[med-svn] [igraph] 28/31: Imported Upstream version 0.7.1

Andreas Tille tille at debian.org
Tue Aug 19 10:16:49 UTC 2014


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

tille pushed a commit to branch master
in repository igraph.

commit b4326a0d661af1e0f5b12ea5dfebc93045e254ba
Author: Andreas Tille <tille at debian.org>
Date:   Tue Aug 19 11:52:19 2014 +0200

    Imported Upstream version 0.7.1
---
 AUTHORS                                            |     2 +
 COPYING                                            |   340 +
 ChangeLog                                          |     0
 INSTALL                                            |   370 +
 Makefile.am                                        |    93 +
 Makefile.in                                        |   973 +
 NEWS                                               |  1435 ++
 README                                             |    13 +
 TODO                                               |    57 +
 VERSION                                            |     1 +
 aclocal.m4                                         |  9754 ++++++++
 compile                                            |   347 +
 config.guess                                       |  1558 ++
 config.h.in                                        |   178 +
 config.sub                                         |  1788 ++
 configure                                          | 20717 ++++++++++++++++
 configure.ac                                       |   334 +
 debian/changelog                                   |    71 -
 debian/compat                                      |     1 -
 debian/control                                     |    46 -
 debian/copyright                                   |    17 -
 debian/libigraph-dev.examples                      |     2 -
 debian/libigraph-dev.info                          |     1 -
 debian/libigraph.manpages                          |     1 -
 debian/libigraph0-dev.install                      |     3 -
 debian/libigraph0.install                          |     1 -
 debian/patches/link_f2c.patch                      |    17 -
 debian/patches/series                              |     1 -
 debian/rules                                       |    23 -
 debian/source/format                               |     1 -
 debian/watch                                       |     5 -
 depcomp                                            |   791 +
 doc/Makefile.in                                    |   690 +
 doc/igraph.3                                       |    46 +
 examples/benchmarks/bench.h                        |    53 +
 examples/benchmarks/igraph_maximal_cliques.c       |    61 +
 examples/benchmarks/igraph_transitivity.c          |    59 +
 examples/simple/2wheap.c                           |   142 +
 examples/simple/LINKS.NET                          |    15 +
 examples/simple/VF2-compat.c                       |   206 +
 examples/simple/adjlist.c                          |    64 +
 examples/simple/ak-4102.max                        | 24623 +++++++++++++++++++
 examples/simple/assortativity.c                    |   212 +
 examples/simple/assortativity.out                  |    10 +
 examples/simple/bellman_ford.c                     |   103 +
 examples/simple/bellman_ford.out                   |    16 +
 examples/simple/biguint.c                          |    87 +
 examples/simple/biguint.out                        |     2 +
 examples/simple/biguint_betweenness.c              |   205 +
 examples/simple/bipartite.net                      |    26 +
 examples/simple/blas.c                             |    49 +
 examples/simple/blas.out                           |     1 +
 examples/simple/bug-1033045.c                      |    50 +
 examples/simple/bug-1033045.out                    |     9 +
 examples/simple/bug-1149658.c                      |    45 +
 examples/simple/cattributes.c                      |   397 +
 examples/simple/cattributes.out                    |    84 +
 examples/simple/cattributes2.c                     |    60 +
 examples/simple/cattributes2.out                   |   283 +
 examples/simple/cattributes3.c                     |   158 +
 examples/simple/cattributes3.out                   |   243 +
 examples/simple/cattributes4.c                     |    90 +
 examples/simple/cattributes4.out                   |    81 +
 examples/simple/celegansneural.gml                 | 15644 ++++++++++++
 examples/simple/centralization.c                   |   173 +
 examples/simple/cohesive_blocks.c                  |   174 +
 examples/simple/cohesive_blocks.out                |    66 +
 examples/simple/d_indheap.c                        |   100 +
 examples/simple/d_indheap.out                      |    12 +
 examples/simple/dijkstra.c                         |    68 +
 examples/simple/dijkstra.out                       |    10 +
 examples/simple/dominator_tree.c                   |   165 +
 examples/simple/dominator_tree.out                 |    49 +
 examples/simple/dot.c                              |    52 +
 examples/simple/dot.out                            |   196 +
 examples/simple/dqueue.c                           |   117 +
 examples/simple/dqueue.out                         |     2 +
 examples/simple/edgelist1.dl                       |    10 +
 examples/simple/edgelist2.dl                       |     9 +
 examples/simple/edgelist3.dl                       |    11 +
 examples/simple/edgelist4.dl                       |    12 +
 examples/simple/edgelist5.dl                       |     9 +
 examples/simple/edgelist6.dl                       |    11 +
 examples/simple/eigenvector_centrality.c           |    85 +
 examples/simple/eigenvector_centrality.out         |     3 +
 examples/simple/even_tarjan.c                      |    66 +
 examples/simple/flow.c                             |   120 +
 examples/simple/flow2.c                            |   240 +
 examples/simple/flow2.out                          |    10 +
 examples/simple/foreign.c                          |    46 +
 examples/simple/foreign.out                        |    11 +
 examples/simple/fullmatrix1.dl                     |     9 +
 examples/simple/fullmatrix2.dl                     |    10 +
 examples/simple/fullmatrix3.dl                     |    12 +
 examples/simple/fullmatrix4.dl                     |    10 +
 examples/simple/gml.c                              |    52 +
 examples/simple/gml.out                            |   612 +
 examples/simple/graphml-hsa05010.xml               |   379 +
 examples/simple/graphml.c                          |    98 +
 examples/simple/graphml.out                        |    24 +
 examples/simple/heap.c                             |    31 +
 examples/simple/igraph_add_edges.c                 |    92 +
 examples/simple/igraph_add_edges.out               |     3 +
 examples/simple/igraph_add_vertices.c              |    63 +
 examples/simple/igraph_adjacency.c                 |    29 +
 examples/simple/igraph_all_st_cuts.c               |   375 +
 examples/simple/igraph_all_st_cuts.out             |    67 +
 examples/simple/igraph_all_st_mincuts.c            |   104 +
 examples/simple/igraph_all_st_mincuts.out          |    24 +
 examples/simple/igraph_are_connected.c             |   108 +
 examples/simple/igraph_arpack_rnsolve.c            |   130 +
 examples/simple/igraph_arpack_rnsolve.out          |    61 +
 examples/simple/igraph_array.c                     |    85 +
 examples/simple/igraph_array.out                   |    37 +
 examples/simple/igraph_atlas.c                     |    58 +
 examples/simple/igraph_atlas.out                   |    31 +
 examples/simple/igraph_average_path_length.c       |    40 +
 examples/simple/igraph_barabasi_game.c             |   118 +
 examples/simple/igraph_barabasi_game2.c            |    92 +
 examples/simple/igraph_betweenness.c               |   140 +
 examples/simple/igraph_bfs.c                       |    61 +
 examples/simple/igraph_bfs.out                     |     6 +
 examples/simple/igraph_bfs2.c                      |   128 +
 examples/simple/igraph_bfs2.out                    |    12 +
 examples/simple/igraph_biconnected_components.c    |    79 +
 examples/simple/igraph_biconnected_components.out  |     6 +
 examples/simple/igraph_bipartite_create.c          |    64 +
 examples/simple/igraph_bipartite_create.out        |     8 +
 examples/simple/igraph_bipartite_projection.c      |   173 +
 examples/simple/igraph_cliques.c                   |    85 +
 examples/simple/igraph_cliques.out                 |    50 +
 examples/simple/igraph_cocitation.c                |    56 +
 examples/simple/igraph_cocitation.out              |     8 +
 .../simple/igraph_community_edge_betweenness.c     |   166 +
 .../simple/igraph_community_edge_betweenness.out   |     3 +
 examples/simple/igraph_community_fastgreedy.c      |   147 +
 examples/simple/igraph_community_fastgreedy.out    |    20 +
 examples/simple/igraph_community_infomap.c         |   258 +
 examples/simple/igraph_community_infomap.out       |    22 +
 .../simple/igraph_community_label_propagation.c    |   100 +
 .../simple/igraph_community_label_propagation.out  |     0
 .../simple/igraph_community_leading_eigenvector.c  |   112 +
 .../igraph_community_leading_eigenvector.out       |     7 +
 .../simple/igraph_community_leading_eigenvector2.c |   116 +
 .../igraph_community_leading_eigenvector2.out      |     7 +
 examples/simple/igraph_community_multilevel.c      |   107 +
 examples/simple/igraph_community_multilevel.out    |    10 +
 .../simple/igraph_community_optimal_modularity.c   |    99 +
 examples/simple/igraph_complementer.c              |   109 +
 examples/simple/igraph_complementer.out            |    87 +
 examples/simple/igraph_complex.c                   |   183 +
 examples/simple/igraph_compose.c                   |   117 +
 examples/simple/igraph_compose.out                 |    11 +
 examples/simple/igraph_convergence_degree.c        |    51 +
 examples/simple/igraph_convergence_degree.out      |     2 +
 examples/simple/igraph_convex_hull.c               |    62 +
 examples/simple/igraph_convex_hull.out             |     2 +
 examples/simple/igraph_copy.c                      |    52 +
 examples/simple/igraph_create.c                    |    84 +
 examples/simple/igraph_decompose.c                 |   103 +
 examples/simple/igraph_decompose.out               |    18 +
 examples/simple/igraph_degree.c                    |   210 +
 examples/simple/igraph_degree.out                  |    13 +
 examples/simple/igraph_degree_sequence_game.c      |    98 +
 examples/simple/igraph_degree_sequence_game.out    |     7 +
 examples/simple/igraph_delete_edges.c              |    84 +
 examples/simple/igraph_delete_vertices.c           |    74 +
 examples/simple/igraph_density.c                   |   133 +
 examples/simple/igraph_density.out                 |    29 +
 .../igraph_deterministic_optimal_imitation.c       |   244 +
 examples/simple/igraph_diameter.c                  |    61 +
 examples/simple/igraph_diameter.out                |     2 +
 examples/simple/igraph_difference.c                |   121 +
 examples/simple/igraph_difference.out              |    16 +
 examples/simple/igraph_disjoint_union.c            |    95 +
 examples/simple/igraph_disjoint_union.out          |     2 +
 examples/simple/igraph_eccentricity.c              |    52 +
 examples/simple/igraph_eccentricity.out            |     3 +
 examples/simple/igraph_edge_betweenness.c          |    84 +
 examples/simple/igraph_edge_betweenness.out        |    97 +
 examples/simple/igraph_eigen_matrix.c              |   124 +
 examples/simple/igraph_eigen_matrix.out            |    11 +
 examples/simple/igraph_eigen_matrix2.c             |   107 +
 examples/simple/igraph_eigen_matrix2.out           |    11 +
 examples/simple/igraph_eigen_matrix3.c             |    89 +
 examples/simple/igraph_eigen_matrix3.out           |     0
 examples/simple/igraph_eigen_matrix4.c             |    92 +
 examples/simple/igraph_eigen_matrix4.out           |     2 +
 examples/simple/igraph_eigen_matrix_symmetric.c    |   122 +
 examples/simple/igraph_eigen_matrix_symmetric.out  |     4 +
 .../simple/igraph_eigen_matrix_symmetric_arpack.c  |   123 +
 .../igraph_eigen_matrix_symmetric_arpack.out       |     4 +
 examples/simple/igraph_empty.c                     |    79 +
 examples/simple/igraph_erdos_renyi_game.c          |   214 +
 examples/simple/igraph_es_adj.c                    |   126 +
 examples/simple/igraph_es_adj.out                  |    38 +
 examples/simple/igraph_es_fromto.c                 |    74 +
 examples/simple/igraph_es_fromto.out               |     3 +
 examples/simple/igraph_es_pairs.c                  |    78 +
 examples/simple/igraph_es_path.c                   |    73 +
 examples/simple/igraph_feedback_arc_set.c          |    74 +
 examples/simple/igraph_feedback_arc_set.out        |     3 +
 examples/simple/igraph_feedback_arc_set_ip.c       |    92 +
 examples/simple/igraph_feedback_arc_set_ip.out     |     4 +
 examples/simple/igraph_fisher_yates_shuffle.c      |   106 +
 examples/simple/igraph_full.c                      |    29 +
 .../igraph_get_all_shortest_paths_dijkstra.c       |   173 +
 .../igraph_get_all_shortest_paths_dijkstra.out     |    19 +
 examples/simple/igraph_get_eid.c                   |   160 +
 examples/simple/igraph_get_eid.out                 |     2 +
 examples/simple/igraph_get_eids.c                  |   216 +
 examples/simple/igraph_get_eids.out                |     3 +
 examples/simple/igraph_get_shortest_paths.c        |   121 +
 examples/simple/igraph_get_shortest_paths.out      |     7 +
 examples/simple/igraph_get_shortest_paths2.c       |    84 +
 examples/simple/igraph_get_shortest_paths2.out     |    16 +
 .../simple/igraph_get_shortest_paths_dijkstra.c    |   214 +
 .../simple/igraph_get_shortest_paths_dijkstra.out  |    15 +
 examples/simple/igraph_girth.c                     |    42 +
 examples/simple/igraph_gomory_hu_tree.c            |   141 +
 examples/simple/igraph_grg_game.c                  |    75 +
 examples/simple/igraph_growing_random_game.c       |    29 +
 examples/simple/igraph_has_multiple.c              |    86 +
 examples/simple/igraph_hashtable.c                 |   131 +
 examples/simple/igraph_hashtable.out               |    14 +
 examples/simple/igraph_hrg.c                       |    73 +
 examples/simple/igraph_hrg2.c                      |    81 +
 examples/simple/igraph_hrg2.out                    |     2 +
 examples/simple/igraph_hrg3.c                      |    81 +
 examples/simple/igraph_hrg3.out                    |     2 +
 examples/simple/igraph_i_cutheap.c                 |    62 +
 examples/simple/igraph_i_cutheap.out               |     1 +
 examples/simple/igraph_i_layout_sphere.c           |    86 +
 examples/simple/igraph_independent_sets.c          |    87 +
 examples/simple/igraph_independent_sets.out        |    36 +
 examples/simple/igraph_induced_subgraph_map.c      |    60 +
 examples/simple/igraph_intersection.c              |   124 +
 examples/simple/igraph_intersection.out            |     7 +
 examples/simple/igraph_intersection2.c             |    59 +
 examples/simple/igraph_intersection2.out           |    21 +
 examples/simple/igraph_is_degree_sequence.c        |   140 +
 examples/simple/igraph_is_directed.c               |    43 +
 examples/simple/igraph_is_loop.c                   |    55 +
 examples/simple/igraph_is_loop.out                 |     2 +
 examples/simple/igraph_is_minimal_separator.c      |    67 +
 examples/simple/igraph_is_multiple.c               |    56 +
 examples/simple/igraph_is_multiple.out             |     2 +
 examples/simple/igraph_is_separator.c              |    67 +
 examples/simple/igraph_isomorphic_vf2.c            |   283 +
 examples/simple/igraph_k_regular_game.c            |   174 +
 examples/simple/igraph_k_regular_game.out          |    16 +
 examples/simple/igraph_knn.c                       |    42 +
 examples/simple/igraph_lapack_dgeev.c              |   234 +
 examples/simple/igraph_lapack_dgeevx.c             |   200 +
 examples/simple/igraph_lapack_dgehrd.c             |    74 +
 examples/simple/igraph_lapack_dgehrd.out           |     0
 examples/simple/igraph_lapack_dgesv.c              |   141 +
 examples/simple/igraph_lapack_dgesv.out            |     1 +
 examples/simple/igraph_lapack_dsyevr.c             |   189 +
 examples/simple/igraph_laplacian.c                 |   236 +
 examples/simple/igraph_laplacian.out               |    80 +
 examples/simple/igraph_lattice.c                   |   180 +
 examples/simple/igraph_layout_grid.c               |    68 +
 examples/simple/igraph_layout_grid.out             |    95 +
 examples/simple/igraph_layout_lgl.c                |    49 +
 examples/simple/igraph_layout_mds.c                |    85 +
 examples/simple/igraph_layout_mds.out              |    10 +
 examples/simple/igraph_layout_merge.c              |    83 +
 examples/simple/igraph_layout_merge2.c             |    78 +
 examples/simple/igraph_layout_merge2.out           |    13 +
 examples/simple/igraph_layout_merge3.c             |    44 +
 examples/simple/igraph_layout_reingold_tilford.c   |    47 +
 examples/simple/igraph_layout_reingold_tilford.in  |    44 +
 examples/simple/igraph_layout_sugiyama.c           |    97 +
 examples/simple/igraph_layout_sugiyama.out         |    87 +
 examples/simple/igraph_lcf.c                       |    47 +
 examples/simple/igraph_local_transitivity.c        |    59 +
 examples/simple/igraph_marked_queue.c              |    62 +
 examples/simple/igraph_maximal_cliques.c           |   153 +
 examples/simple/igraph_maximal_cliques.out         |    22 +
 examples/simple/igraph_maximal_cliques2.c          |    98 +
 examples/simple/igraph_maximal_cliques2.out        |    12 +
 examples/simple/igraph_maximal_cliques3.c          |    79 +
 examples/simple/igraph_maximal_cliques3.out        |    28 +
 examples/simple/igraph_maximal_cliques4.c          |   102 +
 examples/simple/igraph_maximal_cliques4.out        |    30 +
 .../simple/igraph_maximum_bipartite_matching.c     |   249 +
 examples/simple/igraph_mincut.c                    |   109 +
 examples/simple/igraph_mincut.out                  |    12 +
 examples/simple/igraph_minimal_separators.c        |    58 +
 examples/simple/igraph_minimum_size_separators.c   |   166 +
 examples/simple/igraph_minimum_size_separators.out |    30 +
 examples/simple/igraph_minimum_spanning_tree.c     |    70 +
 examples/simple/igraph_minimum_spanning_tree.out   |    34 +
 examples/simple/igraph_moran_process.c             |   221 +
 examples/simple/igraph_motifs_randesu.c            |    69 +
 examples/simple/igraph_motifs_randesu.out          |     9 +
 examples/simple/igraph_neighbors.c                 |    74 +
 examples/simple/igraph_neighbors.out               |     3 +
 examples/simple/igraph_pagerank.c                  |   239 +
 examples/simple/igraph_pagerank.out                |    16 +
 examples/simple/igraph_power_law_fit.c             |   304 +
 examples/simple/igraph_power_law_fit.out           |    42 +
 examples/simple/igraph_preference_game.c           |   131 +
 examples/simple/igraph_psumtree.c                  |   197 +
 examples/simple/igraph_qsort.c                     |    58 +
 examples/simple/igraph_qsort.out                   |     1 +
 examples/simple/igraph_qsort_r.c                   |    68 +
 examples/simple/igraph_qsort_r.out                 |     1 +
 examples/simple/igraph_radius.c                    |    48 +
 examples/simple/igraph_random_sample.c             |   224 +
 examples/simple/igraph_read_graph_dl.c             |    61 +
 examples/simple/igraph_read_graph_dl.out           |   100 +
 examples/simple/igraph_read_graph_graphdb.c        |    41 +
 examples/simple/igraph_read_graph_graphdb.out      |  1500 ++
 examples/simple/igraph_read_graph_lgl-1.lgl        |     7 +
 examples/simple/igraph_read_graph_lgl-2.lgl        |     7 +
 examples/simple/igraph_read_graph_lgl-3.lgl        |     4 +
 examples/simple/igraph_read_graph_lgl.c            |    80 +
 examples/simple/igraph_read_graph_lgl.out          |    12 +
 examples/simple/igraph_reciprocity.c               |    65 +
 examples/simple/igraph_rewire.c                    |    51 +
 examples/simple/igraph_rewire.out                  |     2 +
 examples/simple/igraph_ring.c                      |   169 +
 examples/simple/igraph_rng_get_exp.c               |    36 +
 examples/simple/igraph_rng_get_exp.out             |  1000 +
 examples/simple/igraph_roulette_wheel_imitation.c  |   280 +
 examples/simple/igraph_scg_grouping.c              |    83 +
 examples/simple/igraph_scg_grouping.out            |     1 +
 examples/simple/igraph_scg_grouping2.c             |    79 +
 examples/simple/igraph_scg_grouping2.out           |     4 +
 examples/simple/igraph_scg_grouping3.c             |   120 +
 examples/simple/igraph_scg_grouping3.out           |     5 +
 examples/simple/igraph_scg_grouping4.c             |    99 +
 examples/simple/igraph_scg_grouping4.out           |     4 +
 examples/simple/igraph_scg_semiprojectors.c        |   112 +
 examples/simple/igraph_scg_semiprojectors.out      |    34 +
 examples/simple/igraph_scg_semiprojectors2.c       |   147 +
 examples/simple/igraph_scg_semiprojectors2.out     |    38 +
 examples/simple/igraph_scg_semiprojectors3.c       |   128 +
 examples/simple/igraph_scg_semiprojectors3.out     |    34 +
 examples/simple/igraph_set.c                       |    84 +
 examples/simple/igraph_set.out                     |     1 +
 examples/simple/igraph_similarity.c                |   210 +
 examples/simple/igraph_similarity.out              |    48 +
 examples/simple/igraph_simplify.c                  |    92 +
 examples/simple/igraph_simplify.out                |    10 +
 examples/simple/igraph_small.c                     |    35 +
 examples/simple/igraph_small.out                   |     5 +
 examples/simple/igraph_sparsemat.c                 |   162 +
 examples/simple/igraph_sparsemat.out               |   295 +
 examples/simple/igraph_sparsemat2.c                |   259 +
 examples/simple/igraph_sparsemat2.out              |     0
 examples/simple/igraph_sparsemat3.c                |   309 +
 examples/simple/igraph_sparsemat3.out              |     0
 examples/simple/igraph_sparsemat4.c                |   287 +
 examples/simple/igraph_sparsemat4.out              |     0
 examples/simple/igraph_sparsemat5.c                |   351 +
 examples/simple/igraph_sparsemat5.out              |   117 +
 examples/simple/igraph_sparsemat6.c                |    63 +
 examples/simple/igraph_sparsemat7.c                |    77 +
 examples/simple/igraph_sparsemat8.c                |   183 +
 examples/simple/igraph_sparsemat9.c                |    84 +
 examples/simple/igraph_sparsemat_is_symmetric.c    |    62 +
 examples/simple/igraph_star.c                      |    29 +
 examples/simple/igraph_stochastic_imitation.c      |   240 +
 examples/simple/igraph_strvector.c                 |   190 +
 examples/simple/igraph_strvector.out               |    64 +
 examples/simple/igraph_subisomorphic_lad.c         |   140 +
 examples/simple/igraph_subisomorphic_lad.out       |    30 +
 examples/simple/igraph_to_undirected.c             |    52 +
 examples/simple/igraph_to_undirected.out           |    48 +
 examples/simple/igraph_topological_sorting.c       |    97 +
 examples/simple/igraph_topological_sorting.out     |     4 +
 examples/simple/igraph_transitive_closure_dag.c    |    50 +
 examples/simple/igraph_transitive_closure_dag.out  |     2 +
 examples/simple/igraph_transitivity.c              |    94 +
 examples/simple/igraph_tree.c                      |    29 +
 examples/simple/igraph_trie.c                      |    98 +
 examples/simple/igraph_trie.out                    |    38 +
 examples/simple/igraph_union.c                     |   152 +
 examples/simple/igraph_union.out                   |    69 +
 examples/simple/igraph_version.c                   |    45 +
 examples/simple/igraph_vs_nonadj.c                 |    65 +
 examples/simple/igraph_vs_nonadj.out               |     2 +
 examples/simple/igraph_vs_seq.c                    |    50 +
 examples/simple/igraph_vs_seq.out                  |     1 +
 examples/simple/igraph_vs_vector.c                 |    82 +
 examples/simple/igraph_vs_vector.out               |     1 +
 examples/simple/igraph_weighted_adjacency.c        |   108 +
 examples/simple/igraph_weighted_adjacency.out      |    30 +
 examples/simple/igraph_write_graph_leda.c          |   102 +
 examples/simple/igraph_write_graph_leda.out        |   133 +
 examples/simple/igraph_write_graph_lgl.c           |    48 +
 examples/simple/igraph_write_graph_pajek.c         |    75 +
 examples/simple/igraph_write_graph_pajek.out       |    56 +
 examples/simple/indheap.c                          |    31 +
 examples/simple/input.dl                           |   104 +
 examples/simple/iso_b03_m1000.A00                  |   Bin 0 -> 5002 bytes
 examples/simple/karate.gml                         |   530 +
 examples/simple/levc-stress.c                      |    66 +
 examples/simple/lineendings.c                      |    71 +
 examples/simple/lineendings.out                    |    44 +
 examples/simple/matrix.c                           |   173 +
 examples/simple/matrix.out                         |    37 +
 examples/simple/matrix2.c                          |   316 +
 examples/simple/matrix2.out                        |   167 +
 examples/simple/matrix3.c                          |    43 +
 examples/simple/mt.c                               |    39 +
 examples/simple/nodelist1.dl                       |     9 +
 examples/simple/nodelist2.dl                       |    11 +
 examples/simple/pajek.c                            |    47 +
 examples/simple/pajek1.net                         |    21 +
 examples/simple/pajek2.c                           |    50 +
 examples/simple/pajek2.net                         |     1 +
 examples/simple/pajek2.out                         |     1 +
 examples/simple/pajek3.net                         |    21 +
 examples/simple/pajek4.net                         |    22 +
 examples/simple/pajek5.net                         |    21 +
 examples/simple/pajek6.net                         |    21 +
 examples/simple/pajek_bip.net                      |    27 +
 examples/simple/pajek_bip2.net                     |    27 +
 examples/simple/pajek_bipartite.c                  |    43 +
 examples/simple/pajek_bipartite.out                |    22 +
 examples/simple/pajek_bipartite2.c                 |   120 +
 examples/simple/pajek_bipartite2.out               |    81 +
 examples/simple/pajek_signed.c                     |   100 +
 examples/simple/pajek_signed.net                   |    23 +
 examples/simple/pajek_signed.out                   |    55 +
 examples/simple/random_seed.c                      |    52 +
 examples/simple/scg.c                              |   160 +
 examples/simple/scg.out                            |   300 +
 examples/simple/scg2.c                             |   126 +
 examples/simple/scg2.out                           |   166 +
 examples/simple/scg3.c                             |   124 +
 examples/simple/scg3.out                           |   177 +
 examples/simple/single_target_shortest_path.c      |    78 +
 examples/simple/single_target_shortest_path.out    |    10 +
 examples/simple/spinglass.c                        |    99 +
 examples/simple/spmatrix.c                         |   211 +
 examples/simple/spmatrix.out                       |    52 +
 examples/simple/stack.c                            |    93 +
 examples/simple/test.gxl                           |    50 +
 examples/simple/tls1.c                             |    53 +
 examples/simple/tls2.c                             |   230 +
 examples/simple/tls2.out                           |    23 +
 examples/simple/topology.c                         |    63 +
 examples/simple/topology.out                       |     4 +
 examples/simple/vector.c                           |   341 +
 examples/simple/vector.out                         |    26 +
 examples/simple/vector2.c                          |   125 +
 examples/simple/vector2.out                        |    16 +
 examples/simple/vector3.c                          |    46 +
 examples/simple/vector_ptr.c                       |   277 +
 examples/simple/walktrap.c                         |    70 +
 examples/simple/walktrap.out                       |    10 +
 examples/simple/watts_strogatz_game.c              |   112 +
 examples/simple/wikti_en_V_syn.elist               |  8293 +++++++
 igraph.pc                                          |    12 +
 igraph.pc.in                                       |    12 +
 igraph_Info.plist.in                               |    22 +
 include/igraph.h                                   |    97 +
 include/igraph_adjlist.h                           |   238 +
 include/igraph_arpack.h                            |   341 +
 include/igraph_array.h                             |    69 +
 include/igraph_array_pmt.h                         |    51 +
 include/igraph_attributes.h                        |   878 +
 include/igraph_bipartite.h                         |   106 +
 include/igraph_blas.h                              |    72 +
 include/igraph_centrality.h                        |   221 +
 include/igraph_cliques.h                           |    82 +
 include/igraph_cocitation.h                        |    75 +
 include/igraph_cohesive_blocks.h                   |    37 +
 include/igraph_community.h                         |   241 +
 include/igraph_complex.h                           |   111 +
 include/igraph_components.h                        |    69 +
 include/igraph_constants.h                         |   159 +
 include/igraph_constructors.h                      |    85 +
 include/igraph_conversion.h                        |    74 +
 include/igraph_datatype.h                          |    92 +
 include/igraph_dqueue.h                            |    76 +
 include/igraph_dqueue_pmt.h                        |    49 +
 include/igraph_eigen.h                             |   118 +
 include/igraph_epidemics.h                         |    75 +
 include/igraph_error.h                             |   721 +
 include/igraph_flow.h                              |   178 +
 include/igraph_foreign.h                           |    94 +
 include/igraph_games.h                             |   194 +
 include/igraph_graphlets.h                         |    71 +
 include/igraph_heap.h                              |    91 +
 include/igraph_heap_pmt.h                          |    45 +
 include/igraph_hrg.h                               |   123 +
 include/igraph_interface.h                         |    95 +
 include/igraph_interrupt.h                         |   138 +
 include/igraph_iterators.h                         |   410 +
 include/igraph_lapack.h                            |   118 +
 include/igraph_layout.h                            |   253 +
 include/igraph_matching.h                          |    65 +
 include/igraph_matrix.h                            |   107 +
 include/igraph_matrix_pmt.h                        |   234 +
 include/igraph_memory.h                            |    55 +
 include/igraph_microscopic_update.h                |    69 +
 include/igraph_mixing.h                            |    60 +
 include/igraph_motifs.h                            |   104 +
 include/igraph_neighborhood.h                      |    51 +
 include/igraph_nongraph.h                          |   102 +
 include/igraph_operators.h                         |    72 +
 include/igraph_paths.h                             |   135 +
 include/igraph_pmt.h                               |   142 +
 include/igraph_pmt_off.h                           |   158 +
 include/igraph_progress.h                          |   193 +
 include/igraph_psumtree.h                          |    58 +
 include/igraph_qsort.h                             |    46 +
 include/igraph_random.h                            |   129 +
 include/igraph_revolver.h                          |  1200 +
 include/igraph_scg.h                               |   135 +
 include/igraph_separators.h                        |    62 +
 include/igraph_sparsemat.h                         |   264 +
 include/igraph_spmatrix.h                          |   123 +
 include/igraph_stack.h                             |    82 +
 include/igraph_stack_pmt.h                         |    47 +
 include/igraph_statusbar.h                         |   135 +
 include/igraph_structural.h                        |   157 +
 include/igraph_strvector.h                         |   106 +
 include/igraph_threading.h                         |    51 +
 include/igraph_threading.h.in                      |    51 +
 include/igraph_topology.h                          |   290 +
 include/igraph_transitivity.h                      |    73 +
 include/igraph_types.h                             |    99 +
 include/igraph_vector.h                            |   174 +
 include/igraph_vector_pmt.h                        |   265 +
 include/igraph_vector_ptr.h                        |   109 +
 include/igraph_vector_type.h                       |    34 +
 include/igraph_version.h                           |    36 +
 include/igraph_version.h.in                        |    36 +
 include/igraph_visitor.h                           |   141 +
 install-sh                                         |   527 +
 ltmain.sh                                          |  9655 ++++++++
 missing                                            |   215 +
 optional/glpk/amd/amd.h                            |    67 +
 optional/glpk/amd/amd_1.c                          |   181 +
 optional/glpk/amd/amd_2.c                          |  1844 ++
 optional/glpk/amd/amd_aat.c                        |   187 +
 optional/glpk/amd/amd_control.c                    |    64 +
 optional/glpk/amd/amd_defaults.c                   |    38 +
 optional/glpk/amd/amd_dump.c                       |   180 +
 optional/glpk/amd/amd_info.c                       |   120 +
 optional/glpk/amd/amd_internal.h                   |   117 +
 optional/glpk/amd/amd_order.c                      |   203 +
 optional/glpk/amd/amd_post_tree.c                  |   121 +
 optional/glpk/amd/amd_postorder.c                  |   207 +
 optional/glpk/amd/amd_preprocess.c                 |   119 +
 optional/glpk/amd/amd_valid.c                      |    93 +
 optional/glpk/colamd/colamd.c                      |  3625 +++
 optional/glpk/colamd/colamd.h                      |    69 +
 optional/glpk/glpapi.h                             |   314 +
 optional/glpk/glpapi01.c                           |  1575 ++
 optional/glpk/glpapi02.c                           |   495 +
 optional/glpk/glpapi03.c                           |   166 +
 optional/glpk/glpapi04.c                           |   156 +
 optional/glpk/glpapi05.c                           |   172 +
 optional/glpk/glpapi06.c                           |   810 +
 optional/glpk/glpapi07.c                           |   451 +
 optional/glpk/glpapi08.c                           |   389 +
 optional/glpk/glpapi09.c                           |   741 +
 optional/glpk/glpapi10.c                           |   282 +
 optional/glpk/glpapi11.c                           |  1221 +
 optional/glpk/glpapi12.c                           |  2224 ++
 optional/glpk/glpapi13.c                           |   702 +
 optional/glpk/glpapi14.c                           |   274 +
 optional/glpk/glpapi15.c                           |   614 +
 optional/glpk/glpapi16.c                           |   329 +
 optional/glpk/glpapi17.c                           |  1048 +
 optional/glpk/glpapi18.c                           |   126 +
 optional/glpk/glpapi19.c                           |  1201 +
 optional/glpk/glpavl.c                             |   357 +
 optional/glpk/glpavl.h                             |   123 +
 optional/glpk/glpbfd.c                             |   485 +
 optional/glpk/glpbfd.h                             |    75 +
 optional/glpk/glpbfx.c                             |    91 +
 optional/glpk/glpbfx.h                             |    71 +
 optional/glpk/glpcpx.c                             |  1244 +
 optional/glpk/glpdmp.c                             |   259 +
 optional/glpk/glpdmp.h                             |    80 +
 optional/glpk/glpdmx.c                             |  1472 ++
 optional/glpk/glpenv.h                             |   228 +
 optional/glpk/glpenv01.c                           |   234 +
 optional/glpk/glpenv02.c                           |    73 +
 optional/glpk/glpenv03.c                           |   233 +
 optional/glpk/glpenv04.c                           |   118 +
 optional/glpk/glpenv05.c                           |   229 +
 optional/glpk/glpenv06.c                           |   172 +
 optional/glpk/glpenv07.c                           |   676 +
 optional/glpk/glpenv08.c                           |   156 +
 optional/glpk/glpfhv.c                             |   778 +
 optional/glpk/glpfhv.h                             |   170 +
 optional/glpk/glpgmp.c                             |  1113 +
 optional/glpk/glpgmp.h                             |   190 +
 optional/glpk/glphbm.c                             |   519 +
 optional/glpk/glphbm.h                             |   127 +
 optional/glpk/glpini01.c                           |   581 +
 optional/glpk/glpini02.c                           |   273 +
 optional/glpk/glpios.h                             |   593 +
 optional/glpk/glpios01.c                           |  1618 ++
 optional/glpk/glpios02.c                           |   829 +
 optional/glpk/glpios03.c                           |  1160 +
 optional/glpk/glpios04.c                           |   307 +
 optional/glpk/glpios05.c                           |   285 +
 optional/glpk/glpios06.c                           |  1453 ++
 optional/glpk/glpios07.c                           |   554 +
 optional/glpk/glpios08.c                           |   912 +
 optional/glpk/glpios09.c                           |   665 +
 optional/glpk/glpios10.c                           |   353 +
 optional/glpk/glpios11.c                           |   284 +
 optional/glpk/glpios12.c                           |   180 +
 optional/glpk/glpipm.c                             |  1147 +
 optional/glpk/glpipm.h                             |    36 +
 optional/glpk/glpk.h                               |  1750 ++
 optional/glpk/glpk.inc                             |     1 +
 optional/glpk/glplib.h                             |   135 +
 optional/glpk/glplib01.c                           |   287 +
 optional/glpk/glplib02.c                           |   340 +
 optional/glpk/glplib03.c                           |   696 +
 optional/glpk/glplpf.c                             |   983 +
 optional/glpk/glplpf.h                             |   194 +
 optional/glpk/glplpx01.c                           |  1546 ++
 optional/glpk/glplpx02.c                           |   268 +
 optional/glpk/glplpx03.c                           |   302 +
 optional/glpk/glpluf.c                             |  1851 ++
 optional/glpk/glpluf.h                             |   326 +
 optional/glpk/glplux.c                             |  1028 +
 optional/glpk/glplux.h                             |   221 +
 optional/glpk/glpmat.c                             |   929 +
 optional/glpk/glpmat.h                             |   198 +
 optional/glpk/glpmpl.h                             |  2583 ++
 optional/glpk/glpmpl01.c                           |  4721 ++++
 optional/glpk/glpmpl02.c                           |  1205 +
 optional/glpk/glpmpl03.c                           |  6084 +++++
 optional/glpk/glpmpl04.c                           |  1429 ++
 optional/glpk/glpmpl05.c                           |   566 +
 optional/glpk/glpmpl06.c                           |  1008 +
 optional/glpk/glpmps.c                             |  1407 ++
 optional/glpk/glpnet.h                             |    60 +
 optional/glpk/glpnet01.c                           |   301 +
 optional/glpk/glpnet02.c                           |   314 +
 optional/glpk/glpnet03.c                           |   776 +
 optional/glpk/glpnet04.c                           |   772 +
 optional/glpk/glpnet05.c                           |   367 +
 optional/glpk/glpnet06.c                           |   387 +
 optional/glpk/glpnet07.c                           |   222 +
 optional/glpk/glpnet08.c                           |   245 +
 optional/glpk/glpnet09.c                           |   239 +
 optional/glpk/glpnpp.h                             |   520 +
 optional/glpk/glpnpp01.c                           |   932 +
 optional/glpk/glpnpp02.c                           |  1433 ++
 optional/glpk/glpnpp03.c                           |  2865 +++
 optional/glpk/glpnpp04.c                           |  1419 ++
 optional/glpk/glpnpp05.c                           |   809 +
 optional/glpk/glpqmd.c                             |   584 +
 optional/glpk/glpqmd.h                             |    59 +
 optional/glpk/glprgr.c                             |   165 +
 optional/glpk/glprgr.h                             |    34 +
 optional/glpk/glprng.h                             |    68 +
 optional/glpk/glprng01.c                           |   231 +
 optional/glpk/glprng02.c                           |    76 +
 optional/glpk/glpscf.c                             |   638 +
 optional/glpk/glpscf.h                             |   126 +
 optional/glpk/glpscl.c                             |   476 +
 optional/glpk/glpsdf.c                             |   266 +
 optional/glpk/glpspm.c                             |   846 +
 optional/glpk/glpspm.h                             |   165 +
 optional/glpk/glpspx.h                             |    40 +
 optional/glpk/glpspx01.c                           |  2960 +++
 optional/glpk/glpspx02.c                           |  3084 +++
 optional/glpk/glpsql.c                             |  1631 ++
 optional/glpk/glpsql.h                             |    64 +
 optional/glpk/glpssx.h                             |   418 +
 optional/glpk/glpssx01.c                           |   844 +
 optional/glpk/glpssx02.c                           |   479 +
 optional/glpk/glpstd.h                             |    43 +
 optional/glpk/glptsp.c                             |   672 +
 optional/glpk/glptsp.h                             |   104 +
 src/DensityGrid.cpp                                |   275 +
 src/DensityGrid.h                                  |    88 +
 src/DensityGrid_3d.cpp                             |   296 +
 src/DensityGrid_3d.h                               |    88 +
 src/Makefile.am                                    |   306 +
 src/Makefile.in                                    |  7991 ++++++
 src/NetDataTypes.cpp                               |   225 +
 src/NetDataTypes.h                                 |   821 +
 src/NetRoutines.cpp                                |   278 +
 src/NetRoutines.h                                  |    61 +
 src/adjlist.c                                      |   856 +
 src/arpack.c                                       |  1344 +
 src/array.c                                        |    50 +
 src/array.pmt                                      |    90 +
 src/atlas-edges.h                                  |  1294 +
 src/atlas.c                                        |    82 +
 src/attributes.c                                   |   430 +
 src/basic_query.c                                  |    64 +
 src/bfgs.c                                         |   201 +
 src/bigint.c                                       |   315 +
 src/bigint.h                                       |   105 +
 src/bignum.c                                       |  1953 ++
 src/bignum.h                                       |   120 +
 src/bipartite.c                                    |  1118 +
 src/blas.c                                         |   104 +
 src/bliss.cc                                       |   317 +
 src/bliss_bignum.hh                                |    76 +
 src/bliss_defs.hh                                  |    52 +
 src/bliss_eqrefhash.cc                             |   143 +
 src/bliss_eqrefhash.hh                             |    58 +
 src/bliss_graph.cc                                 |  2495 ++
 src/bliss_graph.hh                                 |   236 +
 src/bliss_heap.cc                                  |    95 +
 src/bliss_heap.hh                                  |    47 +
 src/bliss_kqueue.hh                                |   144 +
 src/bliss_kstack.hh                                |    98 +
 src/bliss_orbit.cc                                 |   153 +
 src/bliss_orbit.hh                                 |    53 +
 src/bliss_partition.cc                             |   917 +
 src/bliss_partition.hh                             |   127 +
 src/bliss_timer.cc                                 |   111 +
 src/bliss_timer.hh                                 |    38 +
 src/bliss_utils.cc                                 |    60 +
 src/bliss_utils.hh                                 |    23 +
 src/cattributes.c                                  |  3718 +++
 src/centrality.c                                   |  3380 +++
 src/cliques.c                                      |  1166 +
 src/clustertool.cpp                                |   657 +
 src/cocitation.c                                   |   764 +
 src/cohesive_blocks.c                              |   567 +
 src/community.c                                    |  3520 +++
 src/complex.c                                      |   390 +
 src/components.c                                   |   838 +
 src/conversion.c                                   |   847 +
 src/cores.c                                        |   159 +
 src/cs/UFconfig.h                                  |   118 +
 src/cs/cs.h                                        |   756 +
 src/cs/cs_add.c                                    |    48 +
 src/cs/cs_amd.c                                    |   387 +
 src/cs/cs_chol.c                                   |    79 +
 src/cs/cs_cholsol.c                                |    46 +
 src/cs/cs_compress.c                               |    42 +
 src/cs/cs_counts.c                                 |    81 +
 src/cs/cs_cumsum.c                                 |    37 +
 src/cs/cs_dfs.c                                    |    56 +
 src/cs/cs_dmperm.c                                 |   164 +
 src/cs/cs_droptol.c                                |    29 +
 src/cs/cs_dropzeros.c                              |    29 +
 src/cs/cs_dupl.c                                   |    54 +
 src/cs/cs_entry.c                                  |    33 +
 src/cs/cs_ereach.c                                 |    43 +
 src/cs/cs_etree.c                                  |    50 +
 src/cs/cs_fkeep.c                                  |    45 +
 src/cs/cs_gaxpy.c                                  |    37 +
 src/cs/cs_happly.c                                 |    39 +
 src/cs/cs_house.c                                  |    50 +
 src/cs/cs_ipvec.c                                  |    29 +
 src/cs/cs_leaf.c                                   |    42 +
 src/cs/cs_load.c                                   |    46 +
 src/cs/cs_lsolve.c                                 |    38 +
 src/cs/cs_ltsolve.c                                |    38 +
 src/cs/cs_lu.c                                     |   109 +
 src/cs/cs_lusol.c                                  |    46 +
 src/cs/cs_malloc.c                                 |    57 +
 src/cs/cs_maxtrans.c                               |   112 +
 src/cs/cs_multiply.c                               |    55 +
 src/cs/cs_norm.c                                   |    36 +
 src/cs/cs_permute.c                                |    45 +
 src/cs/cs_pinv.c                                   |    31 +
 src/cs/cs_post.c                                   |    44 +
 src/cs/cs_print.c                                  |    66 +
 src/cs/cs_pvec.c                                   |    29 +
 src/cs/cs_qr.c                                     |    96 +
 src/cs/cs_qrsol.c                                  |    73 +
 src/cs/cs_randperm.c                               |    44 +
 src/cs/cs_reach.c                                  |    39 +
 src/cs/cs_scatter.c                                |    42 +
 src/cs/cs_scc.c                                    |    61 +
 src/cs/cs_schol.c                                  |    46 +
 src/cs/cs_spsolve.c                                |    48 +
 src/cs/cs_sqr.c                                    |   108 +
 src/cs/cs_symperm.c                                |    59 +
 src/cs/cs_tdfs.c                                   |    44 +
 src/cs/cs_transpose.c                              |    45 +
 src/cs/cs_updown.c                                 |    68 +
 src/cs/cs_usolve.c                                 |    38 +
 src/cs/cs_util.c                                   |   139 +
 src/cs/cs_utsolve.c                                |    38 +
 src/decomposition.c                                |   444 +
 src/distances.c                                    |   211 +
 src/dqueue.c                                       |    49 +
 src/dqueue.pmt                                     |   382 +
 src/drl_Node.h                                     |    66 +
 src/drl_Node_3d.h                                  |    66 +
 src/drl_graph.cpp                                  |  1286 +
 src/drl_graph.h                                    |   128 +
 src/drl_graph_3d.cpp                               |   854 +
 src/drl_graph_3d.h                                 |   120 +
 src/drl_layout.cpp                                 |   472 +
 src/drl_layout.h                                   |    65 +
 src/drl_layout_3d.cpp                              |   123 +
 src/drl_layout_3d.h                                |    65 +
 src/drl_parse.cpp                                  |   205 +
 src/drl_parse.h                                    |    70 +
 src/eigen.c                                        |  1453 ++
 src/evolver_cit.c                                  |   179 +
 src/f2c.h                                          |   230 +
 src/f2c/abort_.c                                   |    22 +
 src/f2c/arithchk.c                                 |   245 +
 src/f2c/backspac.c                                 |    76 +
 src/f2c/c_abs.c                                    |    20 +
 src/f2c/c_cos.c                                    |    23 +
 src/f2c/c_div.c                                    |    53 +
 src/f2c/c_exp.c                                    |    25 +
 src/f2c/c_log.c                                    |    23 +
 src/f2c/c_sin.c                                    |    23 +
 src/f2c/c_sqrt.c                                   |    41 +
 src/f2c/cabs.c                                     |    33 +
 src/f2c/close.c                                    |   101 +
 src/f2c/ctype.c                                    |     2 +
 src/f2c/d_abs.c                                    |    18 +
 src/f2c/d_acos.c                                   |    19 +
 src/f2c/d_asin.c                                   |    19 +
 src/f2c/d_atan.c                                   |    19 +
 src/f2c/d_atn2.c                                   |    19 +
 src/f2c/d_cnjg.c                                   |    19 +
 src/f2c/d_cos.c                                    |    19 +
 src/f2c/d_cosh.c                                   |    19 +
 src/f2c/d_dim.c                                    |    16 +
 src/f2c/d_exp.c                                    |    19 +
 src/f2c/d_imag.c                                   |    16 +
 src/f2c/d_int.c                                    |    19 +
 src/f2c/d_lg10.c                                   |    21 +
 src/f2c/d_log.c                                    |    19 +
 src/f2c/d_mod.c                                    |    46 +
 src/f2c/d_nint.c                                   |    20 +
 src/f2c/d_prod.c                                   |    16 +
 src/f2c/d_sign.c                                   |    18 +
 src/f2c/d_sin.c                                    |    19 +
 src/f2c/d_sinh.c                                   |    19 +
 src/f2c/d_sqrt.c                                   |    19 +
 src/f2c/d_tan.c                                    |    19 +
 src/f2c/d_tanh.c                                   |    19 +
 src/f2c/derf_.c                                    |    18 +
 src/f2c/derfc_.c                                   |    20 +
 src/f2c/dfe.c                                      |   151 +
 src/f2c/dolio.c                                    |    26 +
 src/f2c/dtime_.c                                   |    63 +
 src/f2c/due.c                                      |    77 +
 src/f2c/dummy.c                                    |     2 +
 src/f2c/ef1asc_.c                                  |    25 +
 src/f2c/ef1cmc_.c                                  |    20 +
 src/f2c/endfile.c                                  |   160 +
 src/f2c/erf_.c                                     |    22 +
 src/f2c/erfc_.c                                    |    22 +
 src/f2c/err.c                                      |   293 +
 src/f2c/etime_.c                                   |    57 +
 src/f2c/exit_.c                                    |    43 +
 src/f2c/f77_aloc.c                                 |    44 +
 src/f2c/f77vers.c                                  |    97 +
 src/f2c/fio.h                                      |   141 +
 src/f2c/fmt.c                                      |   530 +
 src/f2c/fmt.h                                      |   105 +
 src/f2c/fmtlib.c                                   |    51 +
 src/f2c/fp.h                                       |    28 +
 src/f2c/ftell_.c                                   |    52 +
 src/f2c/getenv_.c                                  |    62 +
 src/f2c/h_abs.c                                    |    18 +
 src/f2c/h_dim.c                                    |    16 +
 src/f2c/h_dnnt.c                                   |    19 +
 src/f2c/h_indx.c                                   |    32 +
 src/f2c/h_len.c                                    |    16 +
 src/f2c/h_mod.c                                    |    16 +
 src/f2c/h_nint.c                                   |    19 +
 src/f2c/h_sign.c                                   |    18 +
 src/f2c/hl_ge.c                                    |    18 +
 src/f2c/hl_gt.c                                    |    18 +
 src/f2c/hl_le.c                                    |    18 +
 src/f2c/hl_lt.c                                    |    18 +
 src/f2c/i77vers.c                                  |   343 +
 src/f2c/i_abs.c                                    |    18 +
 src/f2c/i_dim.c                                    |    16 +
 src/f2c/i_dnnt.c                                   |    19 +
 src/f2c/i_indx.c                                   |    32 +
 src/f2c/i_len.c                                    |    16 +
 src/f2c/i_mod.c                                    |    16 +
 src/f2c/i_nint.c                                   |    19 +
 src/f2c/i_sign.c                                   |    18 +
 src/f2c/iio.c                                      |   159 +
 src/f2c/ilnw.c                                     |    83 +
 src/f2c/inquire.c                                  |   117 +
 src/f2c/l_ge.c                                     |    18 +
 src/f2c/l_gt.c                                     |    18 +
 src/f2c/l_le.c                                     |    18 +
 src/f2c/l_lt.c                                     |    18 +
 src/f2c/lbitbits.c                                 |    68 +
 src/f2c/lbitshft.c                                 |    17 +
 src/f2c/lio.h                                      |    74 +
 src/f2c/lread.c                                    |   806 +
 src/f2c/lwrite.c                                   |   314 +
 src/f2c/open.c                                     |   301 +
 src/f2c/pow_ci.c                                   |    26 +
 src/f2c/pow_dd.c                                   |    19 +
 src/f2c/pow_di.c                                   |    41 +
 src/f2c/pow_hh.c                                   |    39 +
 src/f2c/pow_ii.c                                   |    39 +
 src/f2c/pow_ri.c                                   |    41 +
 src/f2c/pow_zi.c                                   |    60 +
 src/f2c/pow_zz.c                                   |    29 +
 src/f2c/r_abs.c                                    |    18 +
 src/f2c/r_acos.c                                   |    19 +
 src/f2c/r_asin.c                                   |    19 +
 src/f2c/r_atan.c                                   |    19 +
 src/f2c/r_atn2.c                                   |    19 +
 src/f2c/r_cnjg.c                                   |    18 +
 src/f2c/r_cos.c                                    |    19 +
 src/f2c/r_cosh.c                                   |    19 +
 src/f2c/r_dim.c                                    |    16 +
 src/f2c/r_exp.c                                    |    19 +
 src/f2c/r_imag.c                                   |    16 +
 src/f2c/r_int.c                                    |    19 +
 src/f2c/r_lg10.c                                   |    21 +
 src/f2c/r_log.c                                    |    19 +
 src/f2c/r_mod.c                                    |    46 +
 src/f2c/r_nint.c                                   |    20 +
 src/f2c/r_sign.c                                   |    18 +
 src/f2c/r_sin.c                                    |    19 +
 src/f2c/r_sinh.c                                   |    19 +
 src/f2c/r_sqrt.c                                   |    19 +
 src/f2c/r_tan.c                                    |    19 +
 src/f2c/r_tanh.c                                   |    19 +
 src/f2c/rdfmt.c                                    |   553 +
 src/f2c/rewind.c                                   |    30 +
 src/f2c/rsfe.c                                     |    91 +
 src/f2c/rsli.c                                     |   109 +
 src/f2c/rsne.c                                     |   618 +
 src/f2c/s_cat.c                                    |    86 +
 src/f2c/s_cmp.c                                    |    50 +
 src/f2c/s_copy.c                                   |    57 +
 src/f2c/s_paus.c                                   |    96 +
 src/f2c/s_rnge.c                                   |    32 +
 src/f2c/s_stop.c                                   |    48 +
 src/f2c/sfe.c                                      |    47 +
 src/f2c/sig_die.c                                  |    51 +
 src/f2c/signal1.h                                  |    35 +
 src/f2c/signal1.h0                                 |    35 +
 src/f2c/signal_.c                                  |    21 +
 src/f2c/signbit.c                                  |    24 +
 src/f2c/sue.c                                      |    90 +
 src/f2c/sysdep1.h                                  |    71 +
 src/f2c/sysdep1.h0                                 |    71 +
 src/f2c/system_.c                                  |    42 +
 src/f2c/typesize.c                                 |    18 +
 src/f2c/uio.c                                      |    75 +
 src/f2c/uninit.c                                   |   463 +
 src/f2c/util.c                                     |    57 +
 src/f2c/wref.c                                     |   294 +
 src/f2c/wrtfmt.c                                   |   377 +
 src/f2c/wsfe.c                                     |    78 +
 src/f2c/wsle.c                                     |    42 +
 src/f2c/wsne.c                                     |    32 +
 src/f2c/xwsne.c                                    |    77 +
 src/f2c/z_abs.c                                    |    18 +
 src/f2c/z_cos.c                                    |    21 +
 src/f2c/z_div.c                                    |    50 +
 src/f2c/z_exp.c                                    |    23 +
 src/f2c/z_log.c                                    |   121 +
 src/f2c/z_sin.c                                    |    21 +
 src/f2c/z_sqrt.c                                   |    35 +
 src/fast_community.c                               |   921 +
 src/feedback_arc_set.c                             |   643 +
 src/flow.c                                         |  2476 ++
 src/foreign-dl-header.h                            |    41 +
 src/foreign-dl-lexer.c                             |  2231 ++
 src/foreign-dl-lexer.l                             |   142 +
 src/foreign-dl-parser.c                            |  2148 ++
 src/foreign-dl-parser.h                            |   105 +
 src/foreign-dl-parser.y                            |   313 +
 src/foreign-gml-header.h                           |    30 +
 src/foreign-gml-lexer.c                            |  2054 ++
 src/foreign-gml-lexer.l                            |   102 +
 src/foreign-gml-parser.c                           |  1859 ++
 src/foreign-gml-parser.h                           |    95 +
 src/foreign-gml-parser.y                           |   262 +
 src/foreign-graphml.c                              |  1511 ++
 src/foreign-lgl-header.h                           |    35 +
 src/foreign-lgl-lexer.c                            |  2013 ++
 src/foreign-lgl-lexer.l                            |   102 +
 src/foreign-lgl-parser.c                           |  1698 ++
 src/foreign-lgl-parser.h                           |    85 +
 src/foreign-lgl-parser.y                           |   152 +
 src/foreign-ncol-header.h                          |    34 +
 src/foreign-ncol-lexer.c                           |  2008 ++
 src/foreign-ncol-lexer.l                           |   100 +
 src/foreign-ncol-parser.c                          |  1687 ++
 src/foreign-ncol-parser.h                          |    83 +
 src/foreign-ncol-parser.y                          |   146 +
 src/foreign-pajek-header.h                         |    43 +
 src/foreign-pajek-lexer.c                          |  2469 ++
 src/foreign-pajek-lexer.l                          |   148 +
 src/foreign-pajek-parser.c                         |  2817 +++
 src/foreign-pajek-parser.h                         |   179 +
 src/foreign-pajek-parser.y                         |   758 +
 src/foreign.c                                      |  3334 +++
 src/forestfire.c                                   |   264 +
 src/fortran_intrinsics.c                           |    53 +
 src/games.c                                        |  3866 +++
 src/gengraph_box_list.cpp                          |    87 +
 src/gengraph_box_list.h                            |    75 +
 src/gengraph_definitions.h                         |   191 +
 src/gengraph_degree_sequence.cpp                   |   375 +
 src/gengraph_degree_sequence.h                     |    88 +
 src/gengraph_graph_molloy_hash.cpp                 |  1043 +
 src/gengraph_graph_molloy_hash.h                   |   198 +
 src/gengraph_graph_molloy_optimized.cpp            |  2013 ++
 src/gengraph_graph_molloy_optimized.h              |   263 +
 src/gengraph_hash.h                                |   278 +
 src/gengraph_header.h                              |    86 +
 src/gengraph_mr-connected.cpp                      |   186 +
 src/gengraph_powerlaw.cpp                          |   222 +
 src/gengraph_powerlaw.h                            |    84 +
 src/gengraph_qsort.h                               |   402 +
 src/gengraph_random.cpp                            |   278 +
 src/gengraph_random.h                              |   212 +
 src/gengraph_vertex_cover.h                        |    64 +
 src/glet.c                                         |   860 +
 src/glpk_support.c                                 |    78 +
 src/gml_tree.c                                     |   259 +
 src/hacks.c                                        |    53 +
 src/heap.c                                         |  1061 +
 src/heap.pmt                                       |   345 +
 src/hrg_dendro.h                                   |   302 +
 src/hrg_graph.h                                    |   167 +
 src/hrg_graph_simp.h                               |   162 +
 src/hrg_rbtree.h                                   |   164 +
 src/hrg_splittree_eq.h                             |   185 +
 src/igraph_arpack_internal.h                       |   219 +
 src/igraph_blas_internal.h                         |    55 +
 src/igraph_buckets.c                               |   190 +
 src/igraph_error.c                                 |   285 +
 src/igraph_estack.c                                |    67 +
 src/igraph_estack.h                                |    47 +
 src/igraph_fixed_vectorlist.c                      |    76 +
 src/igraph_flow_internal.h                         |    41 +
 src/igraph_glpk_support.h                          |    48 +
 src/igraph_gml_tree.h                              |    87 +
 src/igraph_grid.c                                  |   541 +
 src/igraph_hacks_internal.h                        |    57 +
 src/igraph_hashtable.c                             |   128 +
 src/igraph_heap.c                                  |    64 +
 src/igraph_hrg.cc                                  |  1025 +
 src/igraph_hrg_types.cc                            |  3470 +++
 src/igraph_interrupt_internal.h                    |    69 +
 src/igraph_lapack_internal.h                       |   178 +
 src/igraph_marked_queue.c                          |   115 +
 src/igraph_marked_queue.h                          |    70 +
 src/igraph_math.h                                  |    82 +
 src/igraph_psumtree.c                              |    98 +
 src/igraph_set.c                                   |   310 +
 src/igraph_stack.c                                 |    83 +
 src/igraph_strvector.c                             |   590 +
 src/igraph_trie.c                                  |   389 +
 src/igraph_types_internal.h                        |   395 +
 src/infomap.cc                                     |   317 +
 src/infomap_FlowGraph.cc                           |   403 +
 src/infomap_FlowGraph.h                            |    78 +
 src/infomap_Greedy.cc                              |   609 +
 src/infomap_Greedy.h                               |    85 +
 src/infomap_Node.cc                                |    69 +
 src/infomap_Node.h                                 |    55 +
 src/interrupt.c                                    |    47 +
 src/iterators.c                                    |  1903 ++
 src/lad.c                                          |  1568 ++
 src/lapack.c                                       |   924 +
 src/lapack/arpack.inc                              |     1 +
 src/lapack/blas.inc                                |     1 +
 src/lapack/dasum.c                                 |    89 +
 src/lapack/daxpy.c                                 |    97 +
 src/lapack/dcopy.c                                 |    97 +
 src/lapack/ddot.c                                  |    99 +
 src/lapack/dgebak.c                                |   223 +
 src/lapack/dgebal.c                                |   399 +
 src/lapack/dgeev.c                                 |   552 +
 src/lapack/dgeevx.c                                |   687 +
 src/lapack/dgehd2.c                                |   180 +
 src/lapack/dgehrd.c                                |   329 +
 src/lapack/dgemm.c                                 |   378 +
 src/lapack/dgemv.c                                 |   302 +
 src/lapack/dgeqr2.c                                |   150 +
 src/lapack/dger.c                                  |   185 +
 src/lapack/dgesv.c                                 |   131 +
 src/lapack/dgetf2.c                                |   179 +
 src/lapack/dgetrf.c                                |   206 +
 src/lapack/dgetrs.c                                |   172 +
 src/lapack/dgetv0.c                                |   480 +
 src/lapack/dhseqr.c                                |   471 +
 src/lapack/disnan.c                                |    48 +
 src/lapack/dlabad.c                                |    68 +
 src/lapack/dlacn2.c                                |   253 +
 src/lapack/dlacpy.c                                |   115 +
 src/lapack/dladiv.c                                |    72 +
 src/lapack/dlae2.c                                 |   134 +
 src/lapack/dlaebz.c                                |   612 +
 src/lapack/dlaev2.c                                |   180 +
 src/lapack/dlaexc.c                                |   443 +
 src/lapack/dlagtf.c                                |   210 +
 src/lapack/dlagts.c                                |   337 +
 src/lapack/dlahqr.c                                |   614 +
 src/lapack/dlahr2.c                                |   310 +
 src/lapack/dlaisnan.c                              |    57 +
 src/lapack/dlaln2.c                                |   556 +
 src/lapack/dlamch.c                                |   169 +
 src/lapack/dlaneg.c                                |   206 +
 src/lapack/dlange.c                                |   185 +
 src/lapack/dlanhs.c                                |   191 +
 src/lapack/dlanst.c                                |   152 +
 src/lapack/dlansy.c                                |   225 +
 src/lapack/dlanv2.c                                |   225 +
 src/lapack/dlapy2.c                                |    65 +
 src/lapack/dlaqr0.c                                |   746 +
 src/lapack/dlaqr1.c                                |   116 +
 src/lapack/dlaqr2.c                                |   683 +
 src/lapack/dlaqr3.c                                |   701 +
 src/lapack/dlaqr4.c                                |   742 +
 src/lapack/dlaqr5.c                                |  1012 +
 src/lapack/dlaqrb.c                                |   602 +
 src/lapack/dlaqtr.c                                |   816 +
 src/lapack/dlar1v.c                                |   429 +
 src/lapack/dlarf.c                                 |   181 +
 src/lapack/dlarfb.c                                |   787 +
 src/lapack/dlarfg.c                                |   156 +
 src/lapack/dlarft.c                                |   345 +
 src/lapack/dlarfx.c                                |   718 +
 src/lapack/dlarnv.c                                |   132 +
 src/lapack/dlarra.c                                |   146 +
 src/lapack/dlarrb.c                                |   338 +
 src/lapack/dlarrc.c                                |   173 +
 src/lapack/dlarrd.c                                |   777 +
 src/lapack/dlarre.c                                |   848 +
 src/lapack/dlarrf.c                                |   419 +
 src/lapack/dlarrj.c                                |   328 +
 src/lapack/dlarrk.c                                |   181 +
 src/lapack/dlarrr.c                                |   164 +
 src/lapack/dlarrv.c                                |   973 +
 src/lapack/dlartg.c                                |   176 +
 src/lapack/dlaruv.c                                |   178 +
 src/lapack/dlascl.c                                |   340 +
 src/lapack/dlaset.c                                |   142 +
 src/lapack/dlasq2.c                                |   588 +
 src/lapack/dlasq3.c                                |   348 +
 src/lapack/dlasq4.c                                |   395 +
 src/lapack/dlasq5.c                                |   229 +
 src/lapack/dlasq6.c                                |   199 +
 src/lapack/dlasr.c                                 |   439 +
 src/lapack/dlasrt.c                                |   272 +
 src/lapack/dlassq.c                                |   106 +
 src/lapack/dlaswp.c                                |   152 +
 src/lapack/dlasy2.c                                |   460 +
 src/lapack/dlatrd.c                                |   341 +
 src/lapack/dmout.c                                 |   393 +
 src/lapack/dnaitr.c                                |   950 +
 src/lapack/dnapps.c                                |   795 +
 src/lapack/dnaup2.c                                |   978 +
 src/lapack/dnaupd.c                                |   794 +
 src/lapack/dnconv.c                                |   178 +
 src/lapack/dneigh.c                                |   377 +
 src/lapack/dneupd.c                                |  1195 +
 src/lapack/dngets.c                                |   275 +
 src/lapack/dnrm2.c                                 |    88 +
 src/lapack/dorg2r.c                                |   163 +
 src/lapack/dorghr.c                                |   203 +
 src/lapack/dorgqr.c                                |   269 +
 src/lapack/dorm2l.c                                |   217 +
 src/lapack/dorm2r.c                                |   221 +
 src/lapack/dormhr.c                                |   247 +
 src/lapack/dormql.c                                |   313 +
 src/lapack/dormqr.c                                |   313 +
 src/lapack/dormtr.c                                |   287 +
 src/lapack/drot.c                                  |    81 +
 src/lapack/dsaitr.c                                |   950 +
 src/lapack/dsapps.c                                |   621 +
 src/lapack/dsaup2.c                                |   976 +
 src/lapack/dsaupd.c                                |   792 +
 src/lapack/dscal.c                                 |    86 +
 src/lapack/dsconv.c                                |   168 +
 src/lapack/dseigt.c                                |   221 +
 src/lapack/dsesrt.c                                |   288 +
 src/lapack/dseupd.c                                |  1046 +
 src/lapack/dsgets.c                                |   259 +
 src/lapack/dsortc.c                                |   406 +
 src/lapack/dsortr.c                                |   268 +
 src/lapack/dstatn.c                                |    83 +
 src/lapack/dstats.c                                |    64 +
 src/lapack/dstebz.c                                |   758 +
 src/lapack/dstein.c                                |   436 +
 src/lapack/dstemr.c                                |   713 +
 src/lapack/dsteqr.c                                |   607 +
 src/lapack/dsterf.c                                |   453 +
 src/lapack/dstqrb.c                                |   691 +
 src/lapack/dswap.c                                 |   104 +
 src/lapack/dsyevr.c                                |   644 +
 src/lapack/dsymv.c                                 |   303 +
 src/lapack/dsyr2.c                                 |   264 +
 src/lapack/dsyr2k.c                                |   396 +
 src/lapack/dsytd2.c                                |   292 +
 src/lapack/dsytrd.c                                |   348 +
 src/lapack/dtrevc.c                                |  1212 +
 src/lapack/dtrexc.c                                |   389 +
 src/lapack/dtrmm.c                                 |   442 +
 src/lapack/dtrmv.c                                 |   335 +
 src/lapack/dtrsen.c                                |   514 +
 src/lapack/dtrsm.c                                 |   479 +
 src/lapack/dtrsna.c                                |   590 +
 src/lapack/dtrsyl.c                                |  1302 +
 src/lapack/dvout.c                                 |   277 +
 src/lapack/idamax.c                                |    82 +
 src/lapack/ieeeck.c                                |   164 +
 src/lapack/iladlc.c                                |    79 +
 src/lapack/iladlr.c                                |    78 +
 src/lapack/ilaenv.c                                |   644 +
 src/lapack/iparmq.c                                |   275 +
 src/lapack/ivout.c                                 |   278 +
 src/lapack/lapack.inc                              |     2 +
 src/lapack/len_trim.c                              |    36 +
 src/lapack/lsame.c                                 |   111 +
 src/lapack/second.c                                |    42 +
 src/lapack/xerbla.c                                |    78 +
 src/layout.c                                       |  3193 +++
 src/matching.c                                     |   991 +
 src/math.c                                         |   248 +
 src/matrix.c                                       |   150 +
 src/matrix.pmt                                     |  1607 ++
 src/maximal_cliques.c                              |   406 +
 src/maximal_cliques_template.h                     |   346 +
 src/memory.c                                       |    75 +
 src/microscopic_update.c                           |  1191 +
 src/mixing.c                                       |   298 +
 src/motifs.c                                       |  1088 +
 src/operators.c                                    |  1215 +
 src/optimal_modularity.c                           |   260 +
 src/other.c                                        |   417 +
 src/plfit/arithmetic_ansi.h                        |   133 +
 src/plfit/arithmetic_sse_double.h                  |   294 +
 src/plfit/arithmetic_sse_float.h                   |   291 +
 src/plfit/error.c                                  |    74 +
 src/plfit/error.h                                  |    86 +
 src/plfit/gss.c                                    |   154 +
 src/plfit/gss.h                                    |   146 +
 src/plfit/kolmogorov.c                             |    66 +
 src/plfit/kolmogorov.h                             |    43 +
 src/plfit/lbfgs.c                                  |  1378 ++
 src/plfit/lbfgs.h                                  |   736 +
 src/plfit/options.c                                |    47 +
 src/plfit/platform.h                               |    54 +
 src/plfit/plfit.c                                  |   778 +
 src/plfit/plfit.h                                  |   109 +
 src/plfit/plfit.inc                                |     9 +
 src/plfit/zeta.c                                   |   154 +
 src/plfit/zeta.h                                   |    53 +
 src/pottsmodel_2.cpp                               |  2302 ++
 src/pottsmodel_2.h                                 |   165 +
 src/progress.c                                     |   152 +
 src/prpack.cpp                                     |    98 +
 src/prpack.h                                       |    54 +
 src/prpack/prpack.h                                |    11 +
 src/prpack/prpack.inc                              |    23 +
 src/prpack/prpack_base_graph.cpp                   |   333 +
 src/prpack/prpack_base_graph.h                     |    42 +
 src/prpack/prpack_csc.h                            |    25 +
 src/prpack/prpack_csr.h                            |    16 +
 src/prpack/prpack_edge_list.h                      |    16 +
 src/prpack/prpack_igraph_graph.cpp                 |   146 +
 src/prpack/prpack_igraph_graph.h                   |    26 +
 src/prpack/prpack_preprocessed_ge_graph.cpp        |    64 +
 src/prpack/prpack_preprocessed_ge_graph.h          |    26 +
 src/prpack/prpack_preprocessed_graph.h             |    17 +
 src/prpack/prpack_preprocessed_gs_graph.cpp        |    81 +
 src/prpack/prpack_preprocessed_gs_graph.h          |    30 +
 src/prpack/prpack_preprocessed_scc_graph.cpp       |   202 +
 src/prpack/prpack_preprocessed_scc_graph.h         |    39 +
 src/prpack/prpack_preprocessed_schur_graph.cpp     |   121 +
 src/prpack/prpack_preprocessed_schur_graph.h       |    33 +
 src/prpack/prpack_result.cpp                       |    12 +
 src/prpack/prpack_result.h                         |    27 +
 src/prpack/prpack_solver.cpp                       |   877 +
 src/prpack/prpack_solver.h                         |   178 +
 src/prpack/prpack_utils.cpp                        |    61 +
 src/prpack/prpack_utils.h                          |    34 +
 src/qsort.c                                        |   212 +
 src/qsort_r.c                                      |     8 +
 src/random.c                                       |  2094 ++
 src/revolver_cit.c                                 |  6479 +++++
 src/revolver_grow.c                                |  1284 +
 src/revolver_ml_cit.c                              |  3548 +++
 src/sbm.c                                          |   214 +
 src/scg.c                                          |  2252 ++
 src/scg_approximate_methods.c                      |   167 +
 src/scg_exact_scg.c                                |    66 +
 src/scg_headers.h                                  |   128 +
 src/scg_kmeans.c                                   |    93 +
 src/scg_optimal_method.c                           |   228 +
 src/scg_utils.c                                    |    92 +
 src/separators.c                                   |   814 +
 src/sir.c                                          |   257 +
 src/spanning_trees.c                               |   368 +
 src/sparsemat.c                                    |  2673 ++
 src/spectral_properties.c                          |   435 +
 src/spmatrix.c                                     |  1004 +
 src/st-cuts.c                                      |  1510 ++
 src/stack.pmt                                      |   291 +
 src/statusbar.c                                    |   130 +
 src/structural_properties.c                        |  6771 +++++
 src/structure_generators.c                         |  2288 ++
 src/sugiyama.c                                     |  1309 +
 src/topology.c                                     |  2955 +++
 src/triangles.c                                    |   925 +
 src/triangles_template.h                           |   110 +
 src/triangles_template1.h                          |    93 +
 src/type_indexededgelist.c                         |  1702 ++
 src/types.c                                        |   146 +
 src/vector.c                                       |   434 +
 src/vector.pmt                                     |  2644 ++
 src/vector_ptr.c                                   |   620 +
 src/version.c                                      |    67 +
 src/visitors.c                                     |   533 +
 src/walktrap.cpp                                   |   173 +
 src/walktrap_communities.cpp                       |   843 +
 src/walktrap_communities.h                         |   175 +
 src/walktrap_graph.cpp                             |   240 +
 src/walktrap_graph.h                               |   107 +
 src/walktrap_heap.cpp                              |   223 +
 src/walktrap_heap.h                                |   133 +
 src/zeroin.c                                       |   203 +
 tests/Makefile.am                                  |    44 +
 tests/Makefile.in                                  |   484 +
 tests/arpack.at                                    |    68 +
 tests/atlocal.in                                   |    11 +
 tests/attributes.at                                |    44 +
 tests/basic.at                                     |    81 +
 tests/bipartite.at                                 |    33 +
 tests/centralization.at                            |    27 +
 tests/cliques.at                                   |    61 +
 tests/community.at                                 |    91 +
 tests/components.at                                |    34 +
 tests/conversion.at                                |    40 +
 tests/eigen.at                                     |    59 +
 tests/flow.at                                      |    66 +
 tests/foreign.at                                   |   114 +
 tests/hrg.at                                       |    37 +
 tests/iterators.at                                 |    57 +
 tests/layout.at                                    |    69 +
 tests/matching.at                                  |    26 +
 tests/microscopic.at                               |    41 +
 tests/motifs.at                                    |    27 +
 tests/mt.at                                        |    33 +
 tests/operators.at                                 |    65 +
 tests/other.at                                     |    32 +
 tests/package.m4                                   |     6 +
 tests/qsort.at                                     |    32 +
 tests/random.at                                    |    48 +
 tests/scg.at                                       |    79 +
 tests/separators.at                                |    53 +
 tests/structural_properties.at                     |   213 +
 tests/structure_generators.at                      |   122 +
 tests/testsuite                                    | 17988 ++++++++++++++
 tests/testsuite.at                                 |    62 +
 tests/topology.at                                  |    48 +
 tests/types.at                                     |   199 +
 tests/version.at                                   |    29 +
 tests/visitors.at                                  |    33 +
 tools/autoconf/ax_tls.m4                           |    76 +
 ylwrap                                             |   247 +
 1374 files changed, 510999 insertions(+), 190 deletions(-)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..cf0b7bf
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Gabor Csardi <csardi.gabor at gmail.com>
+Tamas Nepusz <ntamas at gmail.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/COPYING
@@ -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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..007e939
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
+Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved.  Use GNU `make'
+instead.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf limitation.  Until the limitation is lifted, you can use
+this workaround:
+
+     CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..5dbc9ba
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,93 @@
+
+
+SUBDIRS=src tests
+DOC_FILES = $(top_srcdir)/doc/Makefile.in \
+	$(top_srcdir)/doc/igraph.3
+
+pkgconfigdir = @libdir@/pkgconfig
+pkgconfig_DATA = igraph.pc
+
+EXTRA_DIST = igraph.pc VERSION $(top_srcdir)/include/* $(DOC_FILES) examples \
+	$(wildcard $(top_srcdir)/optional/glpk/*.{inc,c,h})      \
+	$(wildcard $(top_srcdir)/optional/glpk/{README,COPYING}) \
+	$(wildcard $(top_srcdir)/optional/glpk/amd/*.{c,h})      \
+	$(wildcard $(top_srcdir)/optional/glpk/amd/{README,COPYING}) \
+	$(wildcard $(top_srcdir)/optional/glpk/colamd/*.{c,h}) \
+	$(wildcard $(top_srcdir)/optional/glpk/colamd/{README,COPYING}) \
+	tests/testsuite
+
+tests/testsuite:
+	cd tests && make testsuite
+
+install-exec-hook:
+	if test -f $(top_builddir)/src/.libs/cygigraph-0.dll ; \
+		then cp $(top_builddir)/src/.libs/cygigraph-0.dll \
+		$(DESTDIR)$(libdir) ; fi
+
+install-info:
+	if test -f doc/igraph.info; then d="doc"; \
+         else d=$(srcdir); fi; \
+        $(INSTALL_DATA) $$d/igraph.info $(infodir); \
+        if $(SHELL) -c 'install-info --version' \
+           >/dev/null 2>&1; then \
+          install-info --infodir=$(infodir) $$d/igraph.info; \
+        else true; fi
+
+dist-hook:
+	rm -rf `find $(distdir)/examples -type d -name .arch-ids`
+
+MAINTAINERCLEANFILES = Makefile.in
+
+## to make sure make deb will generate Debian packages
+.PHONY: framework msvc parsersources
+
+framework: all
+	rm -rf $(top_builddir)/igraph.framework
+	mkdir -p $(top_builddir)/igraph.framework/Versions/$(VERSION)/Headers
+	mkdir -p $(top_builddir)/igraph.framework/Versions/$(VERSION)/Resources
+	ln -s $(VERSION) $(top_builddir)/igraph.framework/Versions/Current
+	ln -s Versions/Current/Headers $(top_builddir)/igraph.framework/Headers
+	ln -s Versions/Current/Resources $(top_builddir)/igraph.framework/Resources
+	cp $(top_srcdir)/include/* $(top_builddir)/igraph.framework/Headers/
+	if [ $(top_builddir) != $(top_srcdir) ]; then cp $(top_builddir)/include/* $(top_builddir)/igraph.framework/Headers/; fi
+	cp $(top_builddir)/src/.libs/libigraph.dylib $(top_builddir)/igraph.framework/Versions/Current/igraph
+	ln -s Versions/Current/igraph $(top_builddir)/igraph.framework/igraph
+	cp $(top_builddir)/igraph_Info.plist $(top_builddir)/igraph.framework/Versions/Current/Resources/Info.plist
+
+test: all
+	for i in interfaces/*; do \
+		if [ -x $$i/test.sh ]; then \
+		  $$i/test.sh; \
+	 	fi; \
+	done
+
+parsersources:
+	cd src; make parsersources
+
+msvc: parsersources
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc
+	mkdir $(top_builddir)/igraph-$(VERSION)-msvc
+	mkdir $(top_builddir)/igraph-$(VERSION)-msvc/include
+	cp -r $(top_srcdir)/src $(top_builddir)/igraph-$(VERSION)-msvc/
+	cp -r $(top_srcdir)/include/*.h $(top_builddir)/igraph-$(VERSION)-msvc/include
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp -r $(top_builddir)/include $(top_builddir)/src $(top_builddir)/igraph-$(VERSION)-msvc; fi
+	cp -r $(top_srcdir)/msvc/include $(top_builddir)/igraph-$(VERSION)-msvc/winclude
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/{.deps,.libs}
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/config.h
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/*.{o,lo,la}
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/*~
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/include/*~
+	mkdir $(top_builddir)/igraph-$(VERSION)-msvc/winlib
+	$(top_srcdir)/tools/create-msvc-projectfile.py		\
+		$(top_builddir)/igraph-$(VERSION)-msvc 	\
+		$(top_srcdir)/msvc/igraph.vcproj        \
+		$(top_builddir)/src/Makefile
+	cp $(top_srcdir)/msvc/igraph.sln $(top_builddir)/igraph-$(VERSION)-msvc
+	cp -r $(top_srcdir)/msvc/igraphtest .
+	rm -rf igraph-$(VERSION)-msvc.zip
+	zip -r igraph-$(VERSION)-msvc.zip igraph-$(VERSION)-msvc igraphtest
+
+python-msvc: msvc
+	cmd /c "tools\build_python_msvc.cmd"
+    
+CLEANFILES=
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..451b887
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,973 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
+	$(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/configure $(am__configure_deps) \
+	$(srcdir)/config.h.in $(srcdir)/igraph.pc.in \
+	$(srcdir)/igraph_Info.plist.in \
+	$(top_srcdir)/include/igraph_version.h.in \
+	$(top_srcdir)/include/igraph_threading.h.in COPYING TODO \
+	compile config.guess config.sub install-sh missing ltmain.sh
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/tools/autoconf/ax_tls.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = igraph.pc igraph_Info.plist \
+	include/igraph_version.h include/igraph_threading.h
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
+DATA = $(pkgconfig_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	cscope distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOM4TE = @AUTOM4TE@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLOATSTORE = @FLOATSTORE@
+GREP = @GREP@
+HAVE_TLS = @HAVE_TLS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_LIBS_PRIVATE = @PKGCONFIG_LIBS_PRIVATE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WERROR_CFLAGS = @WERROR_CFLAGS@
+XML2CONFIG = @XML2CONFIG@
+XML2_CFLAGS = @XML2_CFLAGS@
+XML2_LIBS = @XML2_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = src tests
+DOC_FILES = $(top_srcdir)/doc/Makefile.in \
+	$(top_srcdir)/doc/igraph.3
+
+pkgconfigdir = @libdir@/pkgconfig
+pkgconfig_DATA = igraph.pc
+EXTRA_DIST = igraph.pc VERSION $(top_srcdir)/include/* $(DOC_FILES) examples \
+	$(wildcard $(top_srcdir)/optional/glpk/*.{inc,c,h})      \
+	$(wildcard $(top_srcdir)/optional/glpk/{README,COPYING}) \
+	$(wildcard $(top_srcdir)/optional/glpk/amd/*.{c,h})      \
+	$(wildcard $(top_srcdir)/optional/glpk/amd/{README,COPYING}) \
+	$(wildcard $(top_srcdir)/optional/glpk/colamd/*.{c,h}) \
+	$(wildcard $(top_srcdir)/optional/glpk/colamd/{README,COPYING}) \
+	tests/testsuite
+
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = 
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+igraph.pc: $(top_builddir)/config.status $(srcdir)/igraph.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+igraph_Info.plist: $(top_builddir)/config.status $(srcdir)/igraph_Info.plist.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+include/igraph_version.h: $(top_builddir)/config.status $(top_srcdir)/include/igraph_version.h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+include/igraph_threading.h: $(top_builddir)/config.status $(top_srcdir)/include/igraph_threading.h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+	@$(NORMAL_INSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+	done
+
+uninstall-pkgconfigDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) \
+	  top_distdir="$(top_distdir)" distdir="$(distdir)" \
+	  dist-hook
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkgconfigDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+	@$(NORMAL_INSTALL)
+	$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-pkgconfigDATA
+
+.MAKE: $(am__recursive_targets) all install-am install-exec-am \
+	install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+	am--refresh check check-am clean clean-cscope clean-generic \
+	clean-libtool cscope cscopelist-am ctags ctags-am dist \
+	dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \
+	dist-tarZ dist-xz dist-zip distcheck distclean \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-tags distcleancheck distdir distuninstallcheck dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-exec-hook install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkgconfigDATA install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-pkgconfigDATA
+
+
+tests/testsuite:
+	cd tests && make testsuite
+
+install-exec-hook:
+	if test -f $(top_builddir)/src/.libs/cygigraph-0.dll ; \
+		then cp $(top_builddir)/src/.libs/cygigraph-0.dll \
+		$(DESTDIR)$(libdir) ; fi
+
+install-info:
+	if test -f doc/igraph.info; then d="doc"; \
+         else d=$(srcdir); fi; \
+        $(INSTALL_DATA) $$d/igraph.info $(infodir); \
+        if $(SHELL) -c 'install-info --version' \
+           >/dev/null 2>&1; then \
+          install-info --infodir=$(infodir) $$d/igraph.info; \
+        else true; fi
+
+dist-hook:
+	rm -rf `find $(distdir)/examples -type d -name .arch-ids`
+
+.PHONY: framework msvc parsersources
+
+framework: all
+	rm -rf $(top_builddir)/igraph.framework
+	mkdir -p $(top_builddir)/igraph.framework/Versions/$(VERSION)/Headers
+	mkdir -p $(top_builddir)/igraph.framework/Versions/$(VERSION)/Resources
+	ln -s $(VERSION) $(top_builddir)/igraph.framework/Versions/Current
+	ln -s Versions/Current/Headers $(top_builddir)/igraph.framework/Headers
+	ln -s Versions/Current/Resources $(top_builddir)/igraph.framework/Resources
+	cp $(top_srcdir)/include/* $(top_builddir)/igraph.framework/Headers/
+	if [ $(top_builddir) != $(top_srcdir) ]; then cp $(top_builddir)/include/* $(top_builddir)/igraph.framework/Headers/; fi
+	cp $(top_builddir)/src/.libs/libigraph.dylib $(top_builddir)/igraph.framework/Versions/Current/igraph
+	ln -s Versions/Current/igraph $(top_builddir)/igraph.framework/igraph
+	cp $(top_builddir)/igraph_Info.plist $(top_builddir)/igraph.framework/Versions/Current/Resources/Info.plist
+
+test: all
+	for i in interfaces/*; do \
+		if [ -x $$i/test.sh ]; then \
+		  $$i/test.sh; \
+	 	fi; \
+	done
+
+parsersources:
+	cd src; make parsersources
+
+msvc: parsersources
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc
+	mkdir $(top_builddir)/igraph-$(VERSION)-msvc
+	mkdir $(top_builddir)/igraph-$(VERSION)-msvc/include
+	cp -r $(top_srcdir)/src $(top_builddir)/igraph-$(VERSION)-msvc/
+	cp -r $(top_srcdir)/include/*.h $(top_builddir)/igraph-$(VERSION)-msvc/include
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp -r $(top_builddir)/include $(top_builddir)/src $(top_builddir)/igraph-$(VERSION)-msvc; fi
+	cp -r $(top_srcdir)/msvc/include $(top_builddir)/igraph-$(VERSION)-msvc/winclude
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/{.deps,.libs}
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/config.h
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/*.{o,lo,la}
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/src/*~
+	rm -rf $(top_builddir)/igraph-$(VERSION)-msvc/include/*~
+	mkdir $(top_builddir)/igraph-$(VERSION)-msvc/winlib
+	$(top_srcdir)/tools/create-msvc-projectfile.py		\
+		$(top_builddir)/igraph-$(VERSION)-msvc 	\
+		$(top_srcdir)/msvc/igraph.vcproj        \
+		$(top_builddir)/src/Makefile
+	cp $(top_srcdir)/msvc/igraph.sln $(top_builddir)/igraph-$(VERSION)-msvc
+	cp -r $(top_srcdir)/msvc/igraphtest .
+	rm -rf igraph-$(VERSION)-msvc.zip
+	zip -r igraph-$(VERSION)-msvc.zip igraph-$(VERSION)-msvc igraphtest
+
+python-msvc: msvc
+	cmd /c "tools\build_python_msvc.cmd"
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..f02fed5
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,1435 @@
+
+igraph 0.6.5
+============
+
+Released February 24, 2013
+
+The version number is not a mistake, we jump to 0.6.5 from 0.6, 
+for technical reasons.
+
+R: 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 some potential crashes in the DrL layout generator.
+- Fixed a bug in the Reingold-Tilford layout when the graph is
+  directed and mode != ALL.
+- Eliminate gap between vertex and edge when plotting an edge without an arrow.
+  Fixes \#1118448.
+- Fixed a bug in has.multiple() that resulted in false negatives for
+  some undirected graphs.
+- Fixed a crash in weighted betweenness calculation.
+- R plotting: fixed a bug that caused misplaced arrows at rectangle
+  vertex shapes.
+
+Python news and fixes
+---------------------
+
+- Added bipartite support to the Pajek reader and writer, closes bug
+  \#1042298.
+- Graph.Degree_Sequence() has a new method now: "no_multiple".
+- Added the is_degree_sequence() and is_graphical_degree_sequence()
+  functions.
+- rewire() has a new mode: "loops", that can create loop edges.
+- Walktrap community detection now handles isolates.
+- Added Graph.K_Regular().
+- power_law_fit() now uses a C implementation.
+- Added support for setting the frame (stroke) width of vertices using the
+  frame_width attribute or the vertex_frame_width keyword argument in plot()
+- Improved Inkscape-friendly SVG output from Graph.write_svg(), thanks to drlog
+- Better handling of named vertices in Graph.delete_vertices()
+- Added experimental Gephi graph streaming support; see igraph.remote.gephi and
+  igraph.drawing.graph.GephiGraphStreamingDrawer
+- Nicer __repr__ output for Flow and Cut instances
+- Arrows are now placed correctly around diamond-shaped nodes on plots
+- Added Graph.TupleList, a function that allows one to create graphs with
+  edge attributes quickly from a list of tuples.
+- plot() now also supports .eps as an extension, not only .ps
+
+- Fixed overflow issues in centralization calculations.
+- 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 Graph.shortest_paths() (Dijkstra's algorithm.) Thanks to 
+  Martin J Reed.
+- Fixed a bug in the NCV setting for ARPACK functions. It cannot be
+  bigger than the matrix size.
+- Fixed a bug in Graph.layout_mds() that resulted vertices on top of each
+  other.
+- Motif finding functions return nan for isomorphism classes that are
+  not motifs (i.e. not connected). Fixes bug \#1050859. 
+- Fixed a bug when calculating the largest cliques of a directed
+  graph. Bug \#1073800.
+- Warn for negative weights when calculating PageRank.
+- Fixed a bug in Graph.eccentricity() and Graph.radius(), the results were often
+  simply wrong.
+- Fixed a bug in Graph.get.all.shortest.paths() when some edges had zero weight.
+- Fixed some potential crashes in the DrL layout generator.
+- Fixed a bug in the Reingold-Tilford layout when the graph is
+  directed and mode != ALL.
+- Fixed a bug in Graph.layout_sugiyama() when the graph had no edges.
+- Fixed a bug in Graph.community_label_propagation() when initial labels
+  contained -1 entries. Issue \#1105460.
+- Repaired the DescartesCoordinateSystem class (which is not used too frequently
+  anyway)
+- Fixed a bug that caused segfaults when an igraph Graph was used in a thread
+  forked from the main Python interpreter thread
+- Fixed a bug that affected file handles created from Python strings in the
+  C layer
+- Fixed a bug in has_multiple() that resulted in false negatives
+  for some undirected graphs.
+- Fixed a crash in weighted betweenness calculation.
+
+C library news and changes
+--------------------------
+
+- Added bipartite support to the Pajek reader and writer, closes bug
+  \#1042298.
+- igraph_layout_mds() uses LAPACK instead of ARPACK.
+- igraph_degree_sequence_game has a new method:
+  IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE.
+- Added the igraph_is_degree_sequence() and
+  igraph_is_graphical_degree_sequence() functions.
+- igraph_rewire() has a new method: IGRAPH_REWIRING_SIMPLE_LOOPS, 
+  that can create loops.
+- Walktrap community detection now handles isolates.
+- Added igraph_k_regular_game().
+- Added igraph_power_law_fit.
+
+- Fixed a bug in igraph_barabasi_game when outseq was an empty vector.
+- Fixed overflow issues in centralization calculations.
+- Fixed an invalid return value of igraph_vector_ptr_pop_back.
+- Fixed a igraph_all_minimal_st_separators() bug, some vertex sets
+  were incorrectly reported as separators. Bug \#1033045.
+- Pajek exporter now always quotes strings, thanks to Elena Tea Russo.
+- Fixed a bug with handling small edge weights in
+  igraph_shortest_paths_dijkstra(), thanks to Martin J Reed.
+- Fixed a bug in the NCV setting for ARPACK functions. It cannot be
+  bigger than the matrix size.
+- igraph_layout_merge_dla uses better default parameter values now.
+- Fixed a bug in igraph_layout_mds() that resulted vertices on top of
+  each other.
+- Attribute handler table is not thread-local any more.
+- Motif finding functions return IGRAPH_NAN for isomorphism classes
+  that are not motifs (i.e. not connected). Fixes bug \#1050859.
+- Fixed a bug when calculating the largest cliques of a directed
+  graph. Bug \#1073800.
+- Fix a bug in degree_sequence_game(), in_seq can be an empty vector as
+  well instead of NULL, for an undirected graph. 
+- Fixed a bug in the maximal clique search, closes \#1074402.
+- Warn for negative weights when calculating PageRank.
+- Fixed a bug in igraph_eccentricity() (and also igraph_radius()), 
+  the results were often simply wrong.
+- Fixed a bug in igraph_get_all_shortest_paths_dijkstra() when edges
+  had zero weight.
+- Fixed some potential crashes in the DrL layout generator.
+- Fixed a bug in the Reingold-Tilford layout when the graph is
+  directed and mode != ALL.
+- Fixed a bug in igraph_has_multiple() that resulted in false negatives
+  for some undirected graphs.
+- Fixed a crash in weighted betweenness calculation.
+
+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().
+
+New in the Python interface
+---------------------------
+
+TODO
+
+Major changes in the Python interface
+-------------------------------------
+
+TODO
+
+New in the C layer
+------------------
+
+- Maximum cardinality search: igraph_maximum_cardinality_search() and 
+  chordality test: igraph_is_chordal().
+- Support the DL file format, igraph_read_graph_dl(). See 
+  http://www.analytictech.com/networks/dataentry.htm.
+- Added generic breadth-first and depth-first search implementations
+  with many callbacks (igraph_bfs(), igraph_dfs()).
+- Centralization scores for degree, closeness, betweenness and
+  eigenvector centrality, see igraph_centralization().
+- Added igraph_sparsemat_t, a type that implements sparse 
+  matrices based on the CXSparse library by Tim Davis.
+  See http://www.cise.ufl.edu/research/sparse/CXSparse/.
+- Personalized Page-Rank scores, igraph_personalized_pagerank() and 
+  igraph_personalized_pagerank_vs().
+- Assortativity coefficient, igraph_assortativity(), 
+  igraph_assortativity_nominal(), and igraph_assortativity_degree().
+- The multi-level modularity optimization community structure detection 
+  algorithm by Blondel et al. was added, see igraph_community_multilevel().
+- Added the igraph_version() function.
+- Star layout: igraph_layout_star().
+- Function to calculate a non-induced subraph: igraph_subgraph_edges().
+- Distance between two community structures: igraph_compare_communities().
+- Community structure via exact modularity optimization,
+  igraph_community_optimal_community().
+- More comprehensive maximum flow and minimum cut calculation, 
+  see functions igraph_maxflow(), igraph_mincut(), 
+  igraph_all_st_cuts(), igraph_all_st_mincuts().
+- Layout based on multidimensional scaling, igraph_layout_mds().
+- It is now possible to access the random number generator(s) via an
+  API. Multiple RNGs can be used, from external sources as well. 
+  The default RNG is MT19937.
+- Added igraph_get_all_shortest_paths_dijkstra, for calculating all
+  non-negatively weighted shortest paths.
+- Check whether a directed graph is a DAG, igraph_is_dag().
+- Cohesive blocking, a'la Moody & White, igraph_cohesive_blocks().
+- Igraph functions can now print status messages, see igraph_status()
+  and related functions.
+- Support writing the LEDA file format, igraph_write_graph_leda().
+- Contract vertices, igraph_contract_vertices().
+- The C reference manual has now a lot of example programs.
+- Hierarchical random graphs and community finding, porting the code
+  from Aaron Clauset. See igraph_hrg_game(), igraph_hrg_fit(), etc.
+- igraph_has_multiple() to decide whether a graph has multiple edges.
+- New layouts igraph_layout_grid() and igraph_layout_grid_3d().
+- igraph_integer_t is really an integer now, it used to be a double.
+- igraph_minimum_spanning_tree(), calls either the weighted or 
+  the unweighted implementation.
+- Eccentricity (igraph_eccentricity()), and radius (igraph_radius())
+  calculations.
+- Several game theory update rules, written by Minh Van Nguyen. See
+  igraph_deterministic_optimal_imitation(),
+  igraph_stochastic_imitation(), igraph_roulette_wheel_imitation(),
+  igraph_moran_process(), 
+- Sugiyama layout algorithm for layered directed acyclic graphs, 
+  igraph_layout_sugiyama().
+- New graph generators: igraph_static_fitness_game(), 
+  igraph_static_power_law_game().
+- Added the InfoMAP community finding method, thanks to Emmanuel
+  Navarro for the code. See igraph_community_infomap().
+- Added the Spectral Coarse Graining algorithm, see igraph_scg(). 
+- Added a function to calculate a diversity score for the vertices,
+  igraph_diversity().
+
+Major changes in the C layer
+----------------------------
+
+- Authority (igraph_authority_score()) and hub (igraph_hub_score()) scores 
+  support edge weights now.
+- Graph Laplacian calculation (igraph_laplacian()) supports edge 
+  weights now.
+- Support edge weights in betweenness (igraph_betweenness()) and closeness
+  (igraph_closeness()) calculations.
+- Support vertex and edge coloring in the VF2 graph isomorphism 
+  algorithm (igraph_isomorphic_vf2(), igraph_count_isomorphisms_vf2(),
+  igraph_get_isomorphisms_vf2(), igraph_subisomorphic_vf2(), 
+  igraph_count_subisomorphisms_vf2(), igraph_get_subisomorphisms_vf2()).
+- Added print operations for the igraph_vector*_t, igraph_matrix*_t and 
+  igraph_strvector_t types.
+- Biconnected component calculation (igraph_biconnected_components())
+  can now return the components themselves.
+- Eigenvector centrality calculation, igraph_eigenvector_centrality() 
+  now works for directed graphs.
+- Shortest path calculations with get_shortest_paths() and 
+  get_shortest_paths_dijkstra() can now return the edges along the paths.
+- Betweenness calculation can now use arbitrarily large integers,
+  this is required for some lattice-like graphs to avoid overflow.
+- igraph_bipartite_projection() calculates multiplicity of edges.
+- igraph_barabasi_game() was rewritten and it supports three 
+  algorithms now, the default algorithm does not generate multiple or
+  loop edges.
+- The Watts-Strogatz graph generator, igraph_watts_strogatz() can 
+  now create graphs without loop edges.
+- igraph should be now thread-safe, on architectures that support 
+  thread-local storage (Linux and Windows: yes, Mac OSX: no).
+
+We also fixed numerous bugs, too many to include them here, sorry.
+You may look at our bug tracker at https://bugs.launchpad.net/igraph
+to check whether a bug was fixed or not. Thanks for all the people
+reporting bugs. Special thanks to Minh Van Nguyen for a lot of bug
+reports, documentation fixes and contributed code!
+
+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
+
+New in the Python interface
+---------------------------
+- Added support for weighted diameter
+- get_eid() considers edge directions by default from now on
+- Fixed a memory leak in the attribute handler
+- 'NaN' and 'inf' are treated correctly now
+
+Bugs corrected in the C layer
+-----------------------------
+- Betweenness and edge betweenness functions work for graphs with
+  many shortest paths now (up to the limit of long long int)
+- The configure script fails if there is no C compiler available
+- Fixed a bug in igraph_community_spinglass, when csize was a NULL
+  pointer, but membership was not
+- Fixed a bug in igraph_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"
+
+New in the Python interface
+---------------------------
+
+- Speeded up betweenness estimation
+- Johnson's shortest paths algorithm added (selected automatically
+  by Graph.shortest_paths() if needed)
+- Weighted degree (also called strength) calculation, Graph.strength()
+- Some new methods to support bipartite graphs: Graph.Bipartite(),
+  Graph.is_bipartite(), Graph.get_indicence(), Graph.Incidence(),
+  Graph.bipartite_projection(), Graph.bipartite_projection_size()
+- Added the label propagation community detection algorithm by
+  Raghavan et al., Graph.community_label_propagation()
+- Added a function to "unfold" a tree, Graph.unfold_tree()
+- setup.py script improvements
+- Graph plotting now supports edge_arrow_size and edge_arrow_width
+- Added Graph.Formula to create small graphs from a simple notation
+- VertexSeq and EdgeSeq objects can now be indexed by slices
+
+New in the C layer
+------------------
+
+- Added progress bar support to igraph_betweenness() and 
+  igraph_betweenness_estimate(), igraph_layout_drl()
+- Speeded up igraph_betweenness_estimate(), igraph_get_eid(), 
+  igraph_are_connected(), igraph_get_eids()
+- Added igraph_get_eid2()
+- Johnson's shortest path algorithm added:
+  igraph_shortest_paths_johnson() 
+- Average nearest neighbor degree calculation,
+  igraph_avg_nearest_neighbor_degree() 
+- Weighted degree (also called strength) calculation,
+  igraph_strength()
+- Some functions to support bipartite graphs: igraph_full_bipartite(),
+  igraph_bipartite_projection(), igraph_create_bipartite(),
+  igraph_incidence(), igraph_get_incidence(),
+  igraph_bipartite_projection_size(), igraph_is_bipartite()
+- Added the label propagation community detection algorithm by
+  Raghavan et al., igraph_community_label_propagation()
+- Added an example that shows how to set the random number generator's
+  seed from C (examples/simple/random_seed.c)
+- Added a function to "unfold" a tree, igraph_unfold_tree()
+- C attribute handler updates: added functions to query many
+  vertices/edges at once
+- Three dimensional DrL layout, igraph_layout_drl_3d()
+
+Bugs corrected in the C layer
+-----------------------------
+
+- Fixed a bug in igraph_isomorphic_function_vf2(), affecting all VF2
+  graph isomorphism functions
+- VL graph generator in igraph_degree_sequence_game() checks now that
+  the sum of the degrees is even
+- Many small corrections to make igraph compile with Microsoft Visual
+  Studio 2003, 2005 and 2008
+- Many fixes for supporting various compilers, e.g. GCC 4.4 and Sun's
+  C compiler
+- Fix a bug when a graph was imported from LGL and exported to NCOL
+  format (\#289596)
+- Fixed memory leaks in igraph_automorphisms(),
+  igraph_shortest_paths_bellman_ford(),
+  igraph_independent_vertex_sets()
+- 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
+  igraph_community_leading_eigenvector()
+- Fixed a bug in igraph_path_length_hist(), 'unconnected' was wrong
+  for unconnected and undirected graphs.
+
+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
+
+New in the Python interface
+---------------------------
+
+- A new layout generator called DrL.
+- Uniform sampling of random connected undirected graphs with a 
+  given degree sequence.
+- Methods parameters accepting igraph.IN, igraph.OUT and igraph.ALL
+  constants now also accept these as strings ("in", "out" and "all").
+  Prefix matches also allowed as long as the prefix match is unique.
+- Graph.shortest_paths() now supports edge weights (Dijkstra's and
+  Bellman-Ford algorithm implemented)
+- Graph.get_shortest_paths() also supports edge weights
+  (only Dijkstra's algorithm yet)
+- Added Graph.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).
+- ARPACK options can now be modified from the Python interface
+  (thanks to Kurt Jacobson)
+- Layout.to_radial() added -- now you can create a top-down tree
+  layout by the Reingold-Tilford algorithm and then turn it to a
+  radial tree layout
+- Added Graph.write_pajek() to save graphs in Pajek format
+- Some vertex and edge related methods can now also be accessed via
+  the methods of VertexSeq and EdgeSeq, restricted to the current
+  vertex/edge sequence of course
+- Visualisations now support triangle shaped vertices
+- Added Graph.mincut()
+- Added Graph.Weighted_Adjacency() to create graphs from weighted
+  adjacency matrices
+- Kamada-Kawai and Fruchterman-Reingold layouts now accept initial
+  vertex positions
+- Graph.Preference() and Graph.Asymmetric_Preference() were 
+  rewritten, they are O(|V|+|E|) now, instead of O(|V|^2).
+
+Bugs corrected in the Python interface
+--------------------------------------
+
+- Graph.constraint() now properly returns floats instead of integers
+  (thanks to Eytan Bakshy)
+- Graphs given by adjacency matrices are now finally loaded and saved
+  properly
+- Graph.Preference() now accepts floats in type distributions
+- A small bug in Graph.community_edge_betweenness() corrected
+- Some bugs in numeric attribute handling resolved
+- VertexSeq and EdgeSeq objects can now be subsetted by lists and
+  tuples as well
+- Fixed a bug when dealing with extremely small layout sizes
+- Eigenvector centality now always return positive values
+- Graph.authority_score() now really returns the authority scores
+  instead of the hub scores (blame copypasting)
+- 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 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
+
+New in the C layer
+------------------
+
+- A new layout generator called DrL.
+- Uniform sampling of random connected undirected graphs with a 
+  given degree sequence.
+- Some stochastic test results are ignored (for spinglass community
+  detection, some Erdos-Renyi generator tests)
+- Weighted shortest paths, Dijkstra's algorithm.
+- The unweigthed shortest path routine returns 'Inf' for unreachable
+  vertices.
+- New function, igraph_adjlist can create igraph graphs from 
+  adjacency lists.
+- New function, igraph_weighted_adjacency can create weighted graphs 
+  from weight matrices.
+- New function, igraph_is_mutual to search for mutual edges.
+- Added inverse log-weighted similarity measure (a.k.a. Adamic/Adar
+  similarity).
+- igraph_preference_game and igraph_asymmetric_preference_game were 
+  rewritten, they are O(|V|+|E|) now, instead of O(|V|^2).
+- The Bellman-Ford shortest path algorithm was added.
+- Added weighted variant of igraph_get_shortest_paths, based on
+  Dijkstra's algorithm.
+- Several small memory leaks were removed, and a big one from the Spinglass
+  community structure detection function
+
+Bugs corrected in the C layer
+-----------------------------
+
+- Several bugs were corrected in the (still experimental) C attribute
+  handler.
+- 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.)
+- Some code polish to make igraph compile with GCC 4.3
+- 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.x
+- Fixed a bug in the Walktrap community detection routine, when applied 
+  to unconnected graphs.
+
+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
+
+New in the Python interface
+---------------------------
+
+- Added shell interface: igraph can now be invoked by calling the script called
+  igraph from the command line. The script launches the Python interpreter and
+  automatically imports igraph functions into the main namespace
+- Pickling (serialization) support for Graph objects
+- Plotting functionality based on the Cairo graphics library (so you need to
+  install python-cairo if you want to use it). Currently the following
+  objects can be plotted: graphs, adjacency matrices and dendrograms. Some
+  crude support for plotting histograms is also implemented. Plots can be
+  saved in PNG, SVG and PDF formats.
+- Unified Graph.layout method for accessing layout algorithms
+- Added interfaces to walktrap community detection and the BLISS isomorphism
+  algorithm
+- Added dyad and triad census functionality and motif counting
+- VertexSeq and EdgeSeq objects can now be restricted to subsets of the
+  whole network (e.g., you can select vertices/edges based on attributes,
+  degree, centrality and so on)
+
+New in the C library
+--------------------
+
+- Many types (stack, matrix, dqueue, etc.) are templates now
+  They were also rewritten to provide a better organized interface
+- 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
+  igraph_canonical_permutation, igraph_isomorphic_bliss
+- We use ARPACK for eigenvalue/eigenvector calculation. This means that the
+  following functions were rewritten: igraph_pagerank,
+  igraph_community_leading_eigenvector_\*. New functions based on
+  ARPACK: igraph_eigenvector_centrality, igraph_hub_score,
+  igraph_authority_score, igraph_arpack_rssolve, igraph_arpack_rnsolve  
+- Experimental C attribute interface added. I.e. it is possible to use
+  graph/vertex/edge attributes from C code now.
+
+- Edge weights for Fruchterman-Reingold layout.
+- Line graph calculation.
+- Kautz and de Bruijn graph generators
+- Support for writing graphs in DOT format
+- Jaccard and Dice similarity coefficients added
+- igraph_count_multiple added
+- igraph_is_loop and igraph_is_multiple "return" boolean vectors
+- The graphopt layout algorithm was added, igraph_layout_graphopt
+- Generation of "famous" graphs, igraph_famous
+- Create graphs from LCF notation, igraph_lcf, igraph_lcf_vector
+- igraph_add_edge adds a single edge to the graph
+- Dyad census and triad cencus functions added
+- igraph_is_simple added
+- progress handlers are allowed to stop calculation
+- igraph_full_citation to create full citation networks
+- igraph_path_length_hist, create a histogram of path lengths
+- forest fire model added
+- DIMACS reader can handle different file types now
+- Adjacency list types made public now (igraph_adjlist_t, igraph_adjedgelist_t)
+- Biconnected components and articulation points can be computed
+- Eigenvector centrality computation
+- Kleinberg's hub and authority scores
+- igraph_to_undirected handles attributes now
+- Geometric random graph generator can return the coordinates of the vertices
+- Function added to convert leading eigenvector community structure result to
+  a membership vector (igraph_le_community_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
+- Weighted modularity calculation
+- igraph_permute_vertices added
+- Betweenness ans closeness calculations are speeded up
+- Startup positions can be supplied to the Kamada-Kawai layout
+  algorithms
+- igraph_read_graph_\* functions 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 a null pointer for edge
+  capacities, implying unit capacities for all edges
+
+Bugs corrected in the C library
+-------------------------------
+
+- Memory leak fixed in adjacency list handling
+- Memory leak fixed in maximal independent vertex set calculation
+- Fixed a bug when rewiring undirected graphs with igraph_rewire
+- Fixed edge betweenness community structure detection for unconnected graphs
+- Make igraph compile with Sun Studio
+- Betweenness bug fixed, when not computing for all vertices
+- memory usage of clique finding reduced
+- Corrected bugs for motif counts when not all motifs were counted,
+  but a 'cut' vector was used
+- Bugs fixed in trait games and cited type game
+- Accept underscore as letter in GML files
+- GML file directedness notation reversed, more logical this way
+
+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 '$'.
+
+New in the C library: 
+- igraph_vector_bool_t data type.
+
+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.
+- MSVC compilation issues were fixed.
+- MinGW compilation fixes.
+
+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.
+- Bug corrected in 'adjacent edges' edge iterator.
+- Python interface: edge and vertex attribute deletion bug corrected.
+- 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.
+- Test suite should run correctly on Cygwin now.
+
+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 C library
+--------------------
+
+- internal representation changed
+- neighbors always returns an ordered list
+- igraph_is_loop and igraph_is_multiple added
+
+- topological sorting
+- VF2 isomorphism algorithm
+- support for reading the file format of the Graph Database for isomorphism
+- igraph_mincut cat 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
+- igraph_community_to_membership supporting function added, creates 
+  a membership vector from a community structure merge tree
+- modularity calculation added
+
+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
+
+- topological sorting
+- VF2 isomorphism algorithm
+- support for reading graphs from the Graph Database for isomorphism
+- 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 denrdograms 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
+------
+
+- proper support for Debian packages (re)added
+- many functions benefit from the new internal representation and are 
+  faster now: transitivity, reciprocity, graph operator functions like 
+  intersection and union, etc.
+- igraph compiles with Microsoft Visual C++ now
+- there were some internal changes to make igraph a real graph algorithm
+  platform in the near future, but these are undocumented now
+
+Bugs corrected
+--------------
+
+- corrected a bug when reading Pajek files: directed graphs were read as undirected
+
+Debian package repository available
+==================================
+
+Debian Linux users can now install and update the C interface
+using the standard package manager. Just add the following two
+lines to /etc/apt/sources.list and install the libigraph and
+libigraph-dev packages. Packages for the Python interface are
+coming soon.
+
+deb http://cneurocvs.rmki.kfki.hu /packages/binary/
+
+deb-src http://cneurocvs.rmki.kfki.hu /packages/source/
+
+igraph 0.3.3
+============
+
+Released February 28, 2007
+
+New in the C library
+--------------------
+
+* igraph_connect_neighborhood, nomen est omen
+* igraph_watts_strogatz_game and igraph_rewire_edges
+* K-core decomposition: igraph_coreness
+* Clique and independent vertex set related functions:
+  igraph_cliques, igraph_independent_vertex_sets,
+  igraph_maximal_cliques, igraph_maximal_independent_vertex_sets,
+  igraph_independence_number, igraph_clique_number,
+  Some of these function were ported from the very_nauty library
+  of Keith Briggs, thanks Keith!
+* The GraphML file format now supports graph attributes
+* Transitivity calculation speeded up
+* Correct transitivity calculation for multigraphs (ie. non-simple graphs)
+
+New in the R interface
+----------------------
+
+* connect.neighborhood
+* watts.strogatz.game and rewire.edges
+* K-core decomposition: graph.coreness
+* added the 'innei' and 'outnei' shorthands for vertex sequence indexing
+  see help(iterators)
+* Clique and independent vertex set related functions:
+  cliques, largest.cliques, maximal.cliques, clique.number,
+  independent.vertex.sets, largest.independent.vertex.sets,
+  maximal.independent.vertex.sets, independence.number
+* The GraphML file format now supports graph attributes
+* edge.lty argument added to plot.igraph and tkplot
+* Transitivity calculation speeded up
+* Correct transitivity calculation for multigraphs (ie. non-simple graphs)
+* alpha.centrality added, calculates Bonacich alpha centrality, see docs.
+
+Bugs corrected
+--------------
+
+* 'make install' installs the library correctly on Cygwin now
+* Pajek parser corrected to read files with MacOS newline characters correctly
+* overflow bug in transitivity calculation for large graphs corrected 
+* an internal memcpy/memmove bug causing some segfaults removed 
+* R interface: tkplot bug with graphs containing a 'name' attribute
+* R interface: attribute handling bug when adding vertices
+* R interface: color selection bug corrected
+* R interface: plot.igraph when plotting loops
+
+Python interface documentation
+====================
+
+Jan 8, 2007
+
+The documentation of the Python interface is available.
+See section 'documentation' in the menu on the left.
+
+igraph 0.3.2
+=========
+
+Released Dec 19, 2006
+
+This is a new major release, it contains many new things:
+
+Changes in the C library
+------------------------
+
+- igraph_maxdegree added, calculates the maximum degree in the graph
+- igraph_grg_game, geometric random graphs
+- igraph_density, graph density calculation
+- push-relabel maximum flow algorithm added, igraph_maxflow_value
+- minimum cut functions added based on maximum flow:
+  igraph_st_mincut_value, igraph_mincut_value, the Stoer-Wagner
+  algorithm is implemented for undirected graphs
+- vertex connectivity functions, usually based on maximum flow:
+  igraph_st_vertex_connectivity, igraph_vertex_connectivity
+- edge connectivity functions, usually based on maximum flow:
+  igraph_st_edge_connectivity, igraph_edge_connectivity
+- other functions based on maximum flow: igraph_edge_disjoint_paths,
+  igraph_vertex_disjoint_paths, igraph_adhesion, igraph_cohesion
+- dimacs file format added
+- igraph_to_directed handles attributes
+- igraph_constraint calculation corrected, it handles weighted graphs
+- spinglass-based community structure detection, the Joerg Reichardt --
+  Stefan Bornholdt algorithm added: igraph_spinglass_community,
+  igraph_spinglass_my_community
+- igraph_extended_chordal_rings, it creates extended chordal rings
+- 'no' argument added to igraph_clusters, it is possible to calculate
+  the number of clusters without calculating the clusters themselves
+- minimum spanning tree functions keep attributes now and also the 
+  direction of the edges is kept in directed graphs
+- there are separate functions to calculate different types of
+  transitivity now
+- igraph_delete_vertices rewritten to allocate less memory for the new
+  graph 
+- neighborhood related functions added: igraph_neighborhood,
+  igraph_neighborhood_size, igraph_neighborhood_graphs
+- two new games added based on different node types:
+  igraph_preference_game and igraph_asymmetric_preference_game
+- Laplacian of a graph can be calculated by the igraph_laplacian function
+
+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 igraph_read_graph_graphml
+- error handling bug corrected in igraph_read_graph_graphml
+- 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:
+- igraph_reciprocity (reciprocity in R) corrected to avoid segfaults
+- some docs updates
+- various R package updated 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)
+- iterators totally rewritten, it is much faster and cleaner now
+- 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 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 mailing lists
+====================
+
+Aug 18, 2006
+
+I've set up two igraph mailing lists: igraph-help for
+general igraph questions and discussion and
+igraph-anonunce for announcements. See 
+http://lists.nongnu.org/mailman/listinfo/igraph-help and
+http://lists.nongnu.org/mailman/listinfo/igraph-announce
+for subscription information, archives, etc.
+
+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/README b/README
new file mode 100644
index 0000000..1fadb05
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+
+The igraph library
+------------------
+
+igraph is a library for creating and manipulating graphs. 
+It is intended to be as powerful (ie. fast) as possible to enable the
+analysis of large graphs. 
+
+It was started as an additional package to the GNU R system, but most
+of its functions can also be used as a separate library.
+
+See the additional HTML files for installation instructions, 
+and documentation. 
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..ced369d
--- /dev/null
+++ b/TODO
@@ -0,0 +1,57 @@
+
+o rewrite igraph_i_eit_create_allfromto, etc., it's just a copy of the
+  index.
+o R interface: curved edges in plots (tkplot and plot)
+o attribute support in to_undirected
+o calculate the actual maximum flow
+o find a way for writing equations in DocBook.
+o read and write non-structural info from/to GraphML files
+  read:
+    - error handling
+    - handle different types of attributes properly (eg. boolean)
+o the number of isomorphism classes for a given graph size
+o index in pdf manual
+o PAJEK import improvements: 
+  - affiliation networks, AFFIL.NET: *Vertices n n1 
+  - multiple edge sets in the same graph (?), Sampson.net, Multi.net, 
+    SampsonL.net
+  - color conversion, see colors in the Pajek manual
+o rewrite add_edges, add_vertices, they're a mess
+o better random number generator handling (init with seed, etc...)
+o uniform graph operators (union, intersection, etc...)
+o attribute handling for operators
+o merging layouts properly, multicompartmental layout functions
+o eccentricity
+o bi-connected components (or k connected component), articulations points
+o connectedness, efficiency, hierarchy, lubness
+
+o igraph.Arrows: better implementation of 'code',
+  it should also handle the case when it is a vector
+o make possible building in separate directory (make check, r package,
+  make dist do not work)
+o write tutorial
+o add some iterators: in-, pre-, post-order, depth-first, breadth-first
+  search, iterators based on attributes etc.
+o add data sets to the R package
+o add automatic tests, add valgrind option to tests (?)
+o make docs look better: index, section tocs
+o make better and faster doxrox engine
+o create man pages
+o implement IGRAPH_STRONG in igraph_decompose
+o top-down and radial layout algorithm for tree graphs
+o Hamilton and Euler circles/paths
+o method to turn the edges to the opposite direction in a graph
+o selective copy: copy only selected edges with attributes
+o method for vertex and edge to return all attrs as a hash
+
+Python interface:
+o Add Python interface to igraph_callaway_traits_game,
+  igraph_barabasi_aging_game, igraph_recent_degree_aging_game
+o Add Python edge/vertex selector support
+o iterator over all components
+o iterator over all circles
+o make del operator work for attributes
+o make in-place addition and subtraction operators NOT copy the graph if
+  a disjoint union or difference is taken
+o igraph_is_loop, igraph_is_multiple
+o igraph_cited_type_game, igraph_citing_cited_type_game, igraph_lastcit_game
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..39e898a
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.7.1
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..2064e08
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,9754 @@
+# generated automatically by aclocal 1.14 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool at gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_REPLACE_SHELLFNS
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Go],			[_LT_LANG(GO)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS="$save_LDFLAGS"
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[  --with-sysroot[=DIR] Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	AC_TRY_EVAL([lt_ar_try])
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t at _DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t at _DLSYM_CONST
+#else
+# define LT@&t at _DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t at _DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	m4_if([$1], [GCJ], [],
+	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+        *Intel*\ [[CF]]*Compiler*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	  ;;
+	*Portland\ Group*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t at m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t at m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX([$1])
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	_LT_TAGVAR(always_export_symbols, $1)=yes
+	_LT_TAGVAR(file_list_spec, $1)='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	# FIXME: Should let the user specify the lib program.
+	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+	  [lt_cv_irix_exported_symbol],
+	  [save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   AC_LINK_IFELSE(
+	     [AC_LANG_SOURCE(
+	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+			      [C++], [[int foo (void) { return 0; }]],
+			      [Fortran 77], [[
+      subroutine foo
+      end]],
+			      [Fortran], [[
+      subroutine foo
+      end]])])],
+	      [lt_cv_irix_exported_symbol=yes],
+	      [lt_cv_irix_exported_symbol=no])
+           LDFLAGS="$save_LDFLAGS"])
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX([$1])
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	    if test "$with_gnu_ld" = yes; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=yes
+	  _LT_TAGVAR(file_list_spec, $1)='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=".dll"
+	  # FIXME: Setting linknames here is a bad hack.
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	    else
+	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	    fi~
+	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	    linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	  # Don't use ranlib
+	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	    lt_tool_outputfile="@TOOL_OUTPUT@"~
+	    case $lt_outputfile in
+	      *.exe|*.EXE) ;;
+	      *)
+		lt_outputfile="$lt_outputfile.exe"
+		lt_tool_outputfile="$lt_tool_outputfile.exe"
+		;;
+	    esac~
+	    func_to_tool_file "$lt_outputfile"~
+	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	      $RM "$lt_outputfile.manifest";
+	    fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=no
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file (1st line
+	    # is EXPORTS), use it as is; otherwise, prepend...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      cp $export_symbols $output_objdir/$soname.def;
+	    else
+	      echo EXPORTS > $output_objdir/$soname.def;
+	      cat $export_symbols >> $output_objdir/$soname.def;
+	    fi~
+	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+		$RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+	      '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+	 case ${prev} in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([	 ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary parameter first.
+    func_stripname_result=${3}
+    func_stripname_result=${func_stripname_result#"${1}"}
+    func_stripname_result=${func_stripname_result%"${2}"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+    func_split_long_opt_name=${1%%=*}
+    func_split_long_opt_arg=${1#*=}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+    func_split_short_opt_arg=${1#??}
+    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+    case ${1} in
+      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+      *)    func_lo2o_result=${1} ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
+
+  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
+
+  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+    func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+  		   [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
+
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
+
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
+
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
+
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.14'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.14], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.14])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake at gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Copyright (C) 1998-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_LEX
+# -----------
+# Autoconf leaves LEX=: if lex or flex can't be found.  Change that to a
+# "missing" invocation, for better error output.
+AC_DEFUN([AM_PROG_LEX],
+[AC_PREREQ([2.50])dnl
+AC_REQUIRE([AM_MISSING_HAS_RUN])dnl
+AC_REQUIRE([AC_PROG_LEX])dnl
+if test "$LEX" = :; then
+  LEX=${am_missing_run}flex
+fi])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/compile b/compile
new file mode 100755
index 0000000..531136b
--- /dev/null
+++ b/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey at cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, 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/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..b79252d
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1558 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-06-10'
+
+# This file 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/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    or1k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel at ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		case $UNAME_PROCESSOR in
+		    i386) UNAME_PROCESSOR=x86_64 ;;
+		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		esac
+	    fi
+	fi
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+esac
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+	"4"
+#else
+	""
+#endif
+	); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..ccc5810
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,178 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `expm1' function. */
+#undef HAVE_EXPM1
+
+/* Define to 1 if you have the `fabsl' function. */
+#undef HAVE_FABSL
+
+/* Define to 1 if you have the `finite' function. */
+#undef HAVE_FINITE
+
+/* Define to 1 if you have the `fmin' function. */
+#undef HAVE_FMIN
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have the GLPK library */
+#undef HAVE_GLPK
+
+/* Define to 1 if you have the GMP library */
+#undef HAVE_GMP
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `isnan' function. */
+#undef HAVE_ISNAN
+
+/* Define to 1 if you have the `arpack' library (-larpack). */
+#undef HAVE_LIBARPACK
+
+/* Define to 1 if you have the `blas' library (-lblas). */
+#undef HAVE_LIBBLAS
+
+/* Define to 1 if you have the `f2c' library (-lf2c). */
+#undef HAVE_LIBF2C
+
+/* Define to 1 if you have the `lapack' library (-llapack). */
+#undef HAVE_LIBLAPACK
+
+/* Define to 1 if you have the libxml2 libraries installed */
+#undef HAVE_LIBXML
+
+/* Define to 1 if you have the `log1p' function. */
+#undef HAVE_LOG1P
+
+/* Define to 1 if you have the `log2' function. */
+#undef HAVE_LOG2
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `rint' function. */
+#undef HAVE_RINT
+
+/* Define to 1 if you have the `rintf' function. */
+#undef HAVE_RINTF
+
+/* Define to 1 if you have the `round' function. */
+#undef HAVE_ROUND
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* 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 `stpcpy' function. */
+#undef HAVE_STPCPY
+
+/* Define to 1 if the stpcpy function has a signature */
+#undef HAVE_STPCPY_SIGNATURE
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* 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/int_types.h> header file. */
+#undef HAVE_SYS_INT_TYPES_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/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the sys/times.h header */
+#undef HAVE_TIMES_H
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you want to use thread-local storage for global igraph
+   structures */
+#undef HAVE_TLS
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `_strdup' function. */
+#undef HAVE__STRDUP
+
+/* Keyword for thread local storage, or just static if not available */
+#undef IGRAPH_F77_SAVE
+
+/* Keyword for thread local storage, or empty if not available */
+#undef IGRAPH_THREAD_LOCAL
+
+/* Define to 1 if you use the internal ARPACK library */
+#undef INTERNAL_ARPACK
+
+/* Define to 1 if you use the internal BLAS library */
+#undef INTERNAL_BLAS
+
+/* Define to 1 if you use the internal F2C library */
+#undef INTERNAL_F2C
+
+/* Define to 1 if you use the internal GLPK library */
+#undef INTERNAL_GLPK
+
+/* Define to 1 if you use the internal LAPACK library */
+#undef INTERNAL_LAPACK
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* 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 home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* If the compiler supports a TLS storage class define it to that here */
+#undef TLS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..8b612ab
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1788 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-04-24'
+
+# This file 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/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze*)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| be32 | be64 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| epiphany \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
+	| ns16k | ns32k \
+	| open8 \
+	| or1k | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pyramid \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pyramid-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16 | cr16-*)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	microblaze*)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i386-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tile*)
+		basic_machine=$basic_machine-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# First match some system type aliases
+	# that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-auroraux)
+		os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	score-*)
+		os=-elf
+		;;
+	spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or1k-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..19f7a96
--- /dev/null
+++ b/configure
@@ -0,0 +1,20717 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for igraph 0.7.1.
+#
+# Report bugs to <csardi.gabor at gmail.com>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf at gnu.org and
+$0: csardi.gabor at gmail.com about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='igraph'
+PACKAGE_TARNAME='igraph'
+PACKAGE_VERSION='0.7.1'
+PACKAGE_STRING='igraph 0.7.1'
+PACKAGE_BUGREPORT='csardi.gabor at gmail.com'
+PACKAGE_URL=''
+
+ac_unique_file="src/games.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+INTERNAL_F2C_FALSE
+INTERNAL_F2C_TRUE
+INTERNAL_BLAS_FALSE
+INTERNAL_BLAS_TRUE
+INTERNAL_LAPACK_FALSE
+INTERNAL_LAPACK_TRUE
+INTERNAL_ARPACK_FALSE
+INTERNAL_ARPACK_TRUE
+INTERNAL_GLPK_FALSE
+INTERNAL_GLPK_TRUE
+HAVE_TLS
+XML2_CFLAGS
+XML2_LIBS
+XML2CONFIG
+WERROR_CFLAGS
+WARNING_CFLAGS
+FLOATSTORE
+AUTOM4TE
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+SED
+LIBTOOL
+OBJDUMP
+DLLTOOL
+AS
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+EGREP
+GREP
+CPP
+YFLAGS
+YACC
+LEXLIB
+LEX_OUTPUT_ROOT
+LEX
+CXXCPP
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+PKGCONFIG_LIBS_PRIVATE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+enable_gcc_warnings
+enable_profiling
+enable_debug
+enable_graphml
+enable_gmp
+enable_tls
+with_external_f2c
+with_external_blas
+with_external_lapack
+with_external_arpack
+with_external_glpk
+enable_glpk
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+CXXCPP
+YACC
+YFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures igraph 0.7.1 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/igraph]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of igraph 0.7.1:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-dependency-tracking
+                          do not reject slow dependency extractors
+  --disable-dependency-tracking
+                          speeds up one-time build
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-gcc-warnings   turn on lots of GCC warnings (not recommended)
+  --enable-profiling      Enable gprof profiling
+  --enable-debug          Enable debug build
+  --disable-graphml       Disable support for GraphML format
+  --disable-gmp           Compile without the GMP library
+  --enable-tls            Compile with thread-local storage
+  --disable-glpk          Compile without the GLPK library
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot=DIR Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).
+  --with-external-f2c     Use external F2C library [default=no]
+  --with-external-blas    Use external BLAS library [default=no]
+  --with-external-lapack  Use external LAPACK library [default=no]
+  --with-external-arpack  Use external ARPACK library [default=no]
+  --with-external-glpk    Use external GLPK library [default=no]
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CXXCPP      C++ preprocessor
+  YACC        The `Yet Another Compiler Compiler' implementation to use.
+              Defaults to the first program found out of: `bison -y', `byacc',
+              `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <csardi.gabor at gmail.com>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+igraph configure 0.7.1
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ------------------------------------- ##
+## Report this to csardi.gabor at gmail.com ##
+## ------------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $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_header_compile
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $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_func
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $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_decl
+
+# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_cxx_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ------------------------------------- ##
+## Report this to csardi.gabor at gmail.com ##
+## ------------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_mongrel
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by igraph $as_me 0.7.1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+am__api_version='1.14'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='igraph'
+ VERSION='0.7.1'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake at gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+ac_config_headers="$ac_config_headers config.h"
+
+
+# ===========================================================================
+#          http://www.gnu.org/software/autoconf-archive/ax_tls.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_TLS([action-if-found], [action-if-not-found])
+#
+# DESCRIPTION
+#
+#   Provides a test for the compiler support of thread local storage (TLS)
+#   extensions. Defines TLS if it is found. Currently knows about GCC/ICC
+#   and MSVC. I think SunPro uses the same as GCC, and Borland apparently
+#   supports either.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Alan Woodland <ajw05 at aber.ac.uk>
+#   Copyright (c) 2010 Diego Elio Petteno` <flameeyes at gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 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/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 10
+
+
+
+
+# Define list of additional libraries that have to be linked to igraph when
+# another app tries to link to the static library of igraph. This is substituted
+# into igraph.pc later on.
+PKGCONFIG_LIBS_PRIVATE="-lxml2 -lz -lm"
+
+
+# Test suite
+ac_config_commands="$ac_config_commands tests/atconfig"
+
+ac_config_files="$ac_config_files tests/Makefile tests/atlocal"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+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
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+# Tricky check for C++ compiler, because Autoconf has a weird bug:
+# http://lists.gnu.org/archive/html/autoconf/2006-03/msg00067.html
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+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
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX"  am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CXX_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CXX_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+  am__fastdepCXX_TRUE=
+  am__fastdepCXX_FALSE='#'
+else
+  am__fastdepCXX_TRUE='#'
+  am__fastdepCXX_FALSE=
+fi
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <iostream>
+const char hw[] = "Hello, World\n";
+int
+main ()
+{
+std::cout << hw;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if ${ac_cv_prog_CXXCPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+        cxx_error=no
+else
+  as_fn_error $? "no C++ compiler found or it cannot create executables" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LEX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LEX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
+$as_echo "$LEX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument.  */
+    yyless ((input () != 0)); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ { ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
+$as_echo_n "checking lex output file root... " >&6; }
+if ${ac_cv_prog_lex_root+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
+$as_echo "$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
+$as_echo_n "checking lex library... " >&6; }
+if ${ac_cv_lib_lex+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_lex=$ac_lib
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
+$as_echo "$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
+$as_echo_n "checking whether yytext is a pointer... " >&6; }
+if ${ac_cv_prog_lex_yytext_pointer+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+  #define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_prog_lex_yytext_pointer=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
+$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = :; then
+  LEX=${am_missing_run}flex
+fi
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_YACC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$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_header_mongrel "$LINENO" "sys/times.h" "ac_cv_header_sys_times_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_times_h" = xyes; then :
+
+$as_echo "#define HAVE_TIMES_H 1" >>confdefs.h
+
+fi
+
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
+set dummy ${ac_tool_prefix}as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AS"; then
+  ac_cv_prog_AS="$AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AS="${ac_tool_prefix}as"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AS"; then
+  ac_ct_AS=$AS
+  # Extract the first word of "as", so it can be a program name with args.
+set dummy as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AS"; then
+  ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AS="as"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AS=$ac_cv_prog_ac_ct_AS
+if test -n "$ac_ct_AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
+$as_echo "$ac_ct_AS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AS" = x; then
+    AS="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AS=$ac_ct_AS
+  fi
+else
+  AS="$ac_cv_prog_AS"
+fi
+
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+  ;;
+esac
+
+test -z "$AS" && AS=as
+
+
+
+
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+enable_dlopen=yes
+
+
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&5
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&5
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[012]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+
+
+
+
+
+# Set options
+
+
+
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl='-Wl,-Wl,,'
+	lt_prog_compiler_pic='-PIC'
+	lt_prog_compiler_static='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fPIC'
+	  lt_prog_compiler_static='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fpic'
+	  lt_prog_compiler_static='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	always_export_symbols=yes
+	file_list_spec='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+	enable_shared_with_static_runtimes=yes
+	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds='chmod 644 $oldlib'
+	postlink_cmds='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+      if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if ${ac_cv_prog_CXXCPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
+  _lt_caught_CXX_error=yes
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+reload_flag_CXX=$reload_flag
+reload_cmds_CXX=$reload_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+  # save warnings/boilerplate of simple test code
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  compiler_CXX=$CC
+  for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+    else
+      lt_prog_compiler_no_builtin_flag_CXX=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+        export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          whole_archive_flag_spec_CXX=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+    ld_shlibs_CXX=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+      aix[4-9]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        archive_cmds_CXX=''
+        hardcode_direct_CXX=yes
+        hardcode_direct_absolute_CXX=yes
+        hardcode_libdir_separator_CXX=':'
+        link_all_deplibs_CXX=yes
+        file_list_spec_CXX='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[012]|aix4.[012].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    hardcode_direct_CXX=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    hardcode_minus_L_CXX=yes
+	    hardcode_libdir_flag_spec_CXX='-L$libdir'
+	    hardcode_libdir_separator_CXX=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        export_dynamic_flag_spec_CXX='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        always_export_symbols_CXX=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          allow_undefined_flag_CXX='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+          hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+	    allow_undefined_flag_CXX="-z nodefs"
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+	    hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    no_undefined_flag_CXX=' ${wl}-bernotok'
+	    allow_undefined_flag_CXX=' ${wl}-berok'
+	    if test "$with_gnu_ld" = yes; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      whole_archive_flag_spec_CXX='$convenience'
+	    fi
+	    archive_cmds_need_lc_CXX=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  allow_undefined_flag_CXX=unsupported
+	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  hardcode_libdir_flag_spec_CXX=' '
+	  allow_undefined_flag_CXX=unsupported
+	  always_export_symbols_CXX=yes
+	  file_list_spec_CXX='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=".dll"
+	  # FIXME: Setting linknames here is a bad hack.
+	  archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	  archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	    else
+	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	    fi~
+	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	    linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true'
+	  enable_shared_with_static_runtimes_CXX=yes
+	  # Don't use ranlib
+	  old_postinstall_cmds_CXX='chmod 644 $oldlib'
+	  postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~
+	    lt_tool_outputfile="@TOOL_OUTPUT@"~
+	    case $lt_outputfile in
+	      *.exe|*.EXE) ;;
+	      *)
+		lt_outputfile="$lt_outputfile.exe"
+		lt_tool_outputfile="$lt_tool_outputfile.exe"
+		;;
+	    esac~
+	    func_to_tool_file "$lt_outputfile"~
+	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	      $RM "$lt_outputfile.manifest";
+	    fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  hardcode_libdir_flag_spec_CXX='-L$libdir'
+	  export_dynamic_flag_spec_CXX='${wl}--export-all-symbols'
+	  allow_undefined_flag_CXX=unsupported
+	  always_export_symbols_CXX=no
+	  enable_shared_with_static_runtimes_CXX=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file (1st line
+	    # is EXPORTS), use it as is; otherwise, prepend...
+	    archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      cp $export_symbols $output_objdir/$soname.def;
+	    else
+	      echo EXPORTS > $output_objdir/$soname.def;
+	      cat $export_symbols >> $output_objdir/$soname.def;
+	    fi~
+	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    ld_shlibs_CXX=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc_CXX=no
+  hardcode_direct_CXX=no
+  hardcode_automatic_CXX=yes
+  hardcode_shlibpath_var_CXX=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec_CXX=''
+  fi
+  link_all_deplibs_CXX=yes
+  allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+       if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+
+  else
+  ld_shlibs_CXX=no
+  fi
+
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        ld_shlibs_CXX=no
+        ;;
+
+      freebsd-elf*)
+        archive_cmds_need_lc_CXX=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        ld_shlibs_CXX=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      haiku*)
+        archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        link_all_deplibs_CXX=yes
+        ;;
+
+      hpux9*)
+        hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+        hardcode_libdir_separator_CXX=:
+        export_dynamic_flag_spec_CXX='${wl}-E'
+        hardcode_direct_CXX=yes
+        hardcode_minus_L_CXX=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            ld_shlibs_CXX=no
+            ;;
+          aCC*)
+            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              ld_shlibs_CXX=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_separator_CXX=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      export_dynamic_flag_spec_CXX='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            hardcode_direct_CXX=no
+            hardcode_shlibpath_var_CXX=no
+            ;;
+          *)
+            hardcode_direct_CXX=yes
+            hardcode_direct_absolute_CXX=yes
+            hardcode_minus_L_CXX=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[3-9]*)
+	hardcode_direct_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	export_dynamic_flag_spec_CXX='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	      fi
+	    fi
+	    link_all_deplibs_CXX=yes
+	    ;;
+        esac
+        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+        hardcode_libdir_separator_CXX=:
+        inherit_rpath_CXX=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    archive_cmds_need_lc_CXX=no
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
+	      prelink_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      old_archive_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+		$RANLIB $oldlib'
+	      archive_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      archive_expsym_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      no_undefined_flag_CXX=' -zdefs'
+	      archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      hardcode_libdir_flag_spec_CXX='-R$libdir'
+	      whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      compiler_needs_object_CXX=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  archive_cmds_CXX='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  hardcode_libdir_flag_spec_CXX='-R$libdir'
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        ld_shlibs_CXX=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	ld_shlibs_CXX=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	  hardcode_direct_absolute_CXX=yes
+	  archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    export_dynamic_flag_spec_CXX='${wl}-E'
+	    whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        allow_undefined_flag_CXX=' -expect_unresolved \*'
+	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+		;;
+	    esac
+
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	      hardcode_libdir_separator_CXX=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            archive_cmds_need_lc_CXX=yes
+	    no_undefined_flag_CXX=' -zdefs'
+	    archive_cmds_CXX='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    hardcode_libdir_flag_spec_CXX='-R$libdir'
+	    hardcode_shlibpath_var_CXX=no
+	    case $host_os in
+	      solaris2.[0-5] | solaris2.[0-5].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    link_all_deplibs_CXX=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[0-5] | solaris2.[0-5].*) ;;
+		*)
+		  whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag_CXX='${wl}-z,text'
+      archive_cmds_need_lc_CXX=no
+      hardcode_shlibpath_var_CXX=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	no_undefined_flag_CXX='${wl}-z,text'
+	allow_undefined_flag_CXX='${wl}-z,nodefs'
+	archive_cmds_need_lc_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+	hardcode_libdir_separator_CXX=':'
+	link_all_deplibs_CXX=yes
+	export_dynamic_flag_spec_CXX='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
+	      '"$old_archive_cmds_CXX"
+	    reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
+	      '"$reload_cmds_CXX"
+	    ;;
+	  *)
+	    archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+    esac
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+    test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+    GCC_CXX="$GXX"
+    LD_CXX="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+	 case ${prev} in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$compiler_lib_search_path_CXX"; then
+	     compiler_lib_search_path_CXX="${prev}${p}"
+	   else
+	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$postdeps_CXX"; then
+	   postdeps_CXX="${prev}${p}"
+	 else
+	   postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$predep_objects_CXX"; then
+	   predep_objects_CXX="$p"
+	 else
+	   predep_objects_CXX="$predep_objects_CXX $p"
+	 fi
+       else
+	 if test -z "$postdep_objects_CXX"; then
+	   postdep_objects_CXX="$p"
+	 else
+	   postdep_objects_CXX="$postdep_objects_CXX $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  predep_objects_CXX=
+  postdep_objects_CXX=
+  postdeps_CXX=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      postdeps_CXX='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      postdeps_CXX='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    lt_prog_compiler_wl_CXX='-Wl,'
+    lt_prog_compiler_static_CXX='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_CXX='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic_CXX='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_CXX='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      lt_prog_compiler_pic_CXX=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static_CXX=
+      ;;
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_CXX=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	lt_prog_compiler_pic_CXX='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_CXX='-fPIC -shared'
+      ;;
+    *)
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[4-9]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  lt_prog_compiler_static_CXX='-Bstatic'
+	else
+	  lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      lt_prog_compiler_pic_CXX='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      lt_prog_compiler_pic_CXX='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fpic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[cC]* | mpixl[cC]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-qpic'
+	    lt_prog_compiler_static_CXX='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      lt_prog_compiler_pic_CXX='-KPIC'
+	      lt_prog_compiler_static_CXX='-Bstatic'
+	      lt_prog_compiler_wl_CXX='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    lt_prog_compiler_pic_CXX='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        lt_prog_compiler_pic_CXX='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    lt_prog_compiler_wl_CXX='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    lt_prog_compiler_pic_CXX='-pic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	lt_prog_compiler_can_build_shared_CXX=no
+	;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_CXX=
+    ;;
+  *)
+    lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; }
+lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works_CXX=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works_CXX=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+    case $lt_prog_compiler_pic_CXX in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+     esac
+else
+    lt_prog_compiler_pic_CXX=
+     lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works_CXX=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works_CXX=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works_CXX=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+    :
+else
+    lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  case $host_os in
+  aix[4-9]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    export_symbols_cmds_CXX="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+      ;;
+    esac
+    ;;
+  *)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_CXX=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_CXX in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl_CXX
+	  pic_flag=$lt_prog_compiler_pic_CXX
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+	  allow_undefined_flag_CXX=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc_CXX=no
+	  else
+	    lt_cv_archive_cmds_need_lc_CXX=yes
+	  fi
+	  allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+      archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+   test -n "$runpath_var_CXX" ||
+   test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct_CXX" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+     test "$hardcode_minus_L_CXX" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_CXX=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_CXX=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test "$hardcode_action_CXX" = relink ||
+   test "$inherit_rpath_CXX" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+AUTOM4TE=${AUTOM4TE-"${am_missing_run}autom4te"}
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+for ac_header in stdarg.h stdlib.h string.h time.h unistd.h stdint.h sys/int_types.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
+
+LIBS_SAVE=$LIBS
+LIBS="$LIBS -lm"
+for ac_func in expm1 rint rintf finite log2 snprintf log1p round fabsl fmin strcasecmp isnan strdup _strdup ftruncate stpcpy
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ac_fn_c_check_decl "$LINENO" "stpcpy" "ac_cv_have_decl_stpcpy" "$ac_includes_default"
+if test "x$ac_cv_have_decl_stpcpy" = xyes; then :
+
+$as_echo "#define HAVE_STPCPY_SIGNATURE 1" >>confdefs.h
+
+fi
+
+LIBS=$LIBS_SAVE
+
+
+
+
+
+## Solaris cc does not support -ffloat-store.
+FLOATSTORE=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -ffloat-store" >&5
+$as_echo_n "checking whether compiler supports -ffloat-store... " >&6; }
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -ffloat-store"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+FLOATSTORE="-ffloat-store"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fstore" >&5
+$as_echo_n "checking whether compiler supports -fstore... " >&6; }
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -fstore"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+FLOATSTORE="$FLOATSTORE -fstore"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+
+
+# Check whether --enable-gcc-warnings was given.
+if test "${enable_gcc_warnings+set}" = set; then :
+  enableval=$enable_gcc_warnings; case "${enableval}" in
+   yes|no) ;;
+   *)      as_fn_error $? "bad value ${enableval} for gcc-warnings option" "$LINENO" 5 ;;
+ esac
+else
+  enableval=no
+fi
+
+if test "${enableval}" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Werror" >&5
+$as_echo_n "checking whether compiler accepts -Werror... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Werror"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  WERROR_CFLAGS=$WARNING_CFLAGS
+
+  WARNING_CFLAGS=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wall" >&5
+$as_echo_n "checking whether compiler accepts -Wall... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wall"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wall"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -W" >&5
+$as_echo_n "checking whether compiler accepts -W... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -W"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -W"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wbad-function-cast" >&5
+$as_echo_n "checking whether compiler accepts -Wbad-function-cast... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wbad-function-cast"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wbad-function-cast"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wcast-align" >&5
+$as_echo_n "checking whether compiler accepts -Wcast-align... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wcast-align"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wcast-align"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wcast-qual" >&5
+$as_echo_n "checking whether compiler accepts -Wcast-qual... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wcast-qual"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wcast-qual"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wformat" >&5
+$as_echo_n "checking whether compiler accepts -Wformat... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wformat"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wformat"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wmissing-declarations" >&5
+$as_echo_n "checking whether compiler accepts -Wmissing-declarations... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wmissing-declarations"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wmissing-declarations"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wmissing-prototypes" >&5
+$as_echo_n "checking whether compiler accepts -Wmissing-prototypes... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wmissing-prototypes"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wmissing-prototypes"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wnested-externs" >&5
+$as_echo_n "checking whether compiler accepts -Wnested-externs... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wnested-externs"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wnested-externs"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wshadow" >&5
+$as_echo_n "checking whether compiler accepts -Wshadow... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wshadow"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wshadow"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wstrict-prototypes" >&5
+$as_echo_n "checking whether compiler accepts -Wstrict-prototypes... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wstrict-prototypes"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wstrict-prototypes"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wwrite-strings" >&5
+$as_echo_n "checking whether compiler accepts -Wwrite-strings... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wwrite-strings"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wwrite-strings"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+else
+  WARNING_CFLAGS=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -Wall" >&5
+$as_echo_n "checking whether compiler accepts -Wall... " >&6; }
+
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Wall"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  WARNING_CFLAGS="$WARNING_CFLAGS -Wall"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$ac_save_CFLAGS"
+fi
+
+use_gprof=no
+# Check whether --enable-profiling was given.
+if test "${enable_profiling+set}" = set; then :
+  enableval=$enable_profiling; use_gprof=$enableval
+else
+  use_gprof=no
+fi
+
+
+debug=no
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug; debug=$enableval
+fi
+
+
+graphml_support=yes
+# Check whether --enable-graphml was given.
+if test "${enable_graphml+set}" = set; then :
+  enableval=$enable_graphml; graphml_support=$enableval
+else
+  graphml_support=yes
+fi
+
+
+HAVE_LIBXML=0
+if test $graphml_support = yes; then
+  # Extract the first word of "xml2-config", so it can be a program name with args.
+set dummy xml2-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_XML2CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $XML2CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_XML2CONFIG="$XML2CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_XML2CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_XML2CONFIG" && ac_cv_path_XML2CONFIG="none"
+  ;;
+esac
+fi
+XML2CONFIG=$ac_cv_path_XML2CONFIG
+if test -n "$XML2CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XML2CONFIG" >&5
+$as_echo "$XML2CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  if test "$XML2CONFIG" = "none"; then
+	# Hmmm, no xml2-config. OS X does not have it while still
+	# having libxml2, so let's try an educated guess
+	XML2_LIBS="-lxml2 -lz -lm"
+	XML2_CFLAGS="-I/usr/include/libxml2"
+  else
+    XML2_LIBS=`$XML2CONFIG --libs`
+    XML2_CFLAGS=`$XML2CONFIG --cflags`
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for xmlSAXUserParseFile in -lxml2" >&5
+$as_echo_n "checking for xmlSAXUserParseFile in -lxml2... " >&6; }
+if ${ac_cv_lib_xml2_xmlSAXUserParseFile+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxml2  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char xmlSAXUserParseFile ();
+int
+main ()
+{
+return xmlSAXUserParseFile ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_xml2_xmlSAXUserParseFile=yes
+else
+  ac_cv_lib_xml2_xmlSAXUserParseFile=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xml2_xmlSAXUserParseFile" >&5
+$as_echo "$ac_cv_lib_xml2_xmlSAXUserParseFile" >&6; }
+if test "x$ac_cv_lib_xml2_xmlSAXUserParseFile" = xyes; then :
+
+    OLDCFLAGS=${CFLAGS}
+    OLDCPPFLAGS=${CPPFLAGS}
+    CFLAGS=${XML2_CFLAGS}
+    CPPFLAGS=${XML2_CFLAGS}
+    ac_fn_c_check_header_mongrel "$LINENO" "libxml/parser.h" "ac_cv_header_libxml_parser_h" "$ac_includes_default"
+if test "x$ac_cv_header_libxml_parser_h" = xyes; then :
+
+      HAVE_LIBXML=1
+
+$as_echo "#define HAVE_LIBXML 1" >>confdefs.h
+
+	  CFLAGS="${OLDCFLAGS} ${XML2_CFLAGS}"
+      CPPFLAGS="${OLDCFLAGS} ${XML2_CFLAGS}"
+
+
+
+else
+
+      graphml_support=no
+      CFLAGS=${OLDCFLAGS}
+	  CPPFLAGS=${OLDCPPFLAGS}
+
+fi
+
+
+
+else
+
+    graphml_support=no
+
+fi
+
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+gmp_support=no
+# Check whether --enable-gmp was given.
+if test "${enable_gmp+set}" = set; then :
+  enableval=$enable_gmp;
+fi
+
+if test "x$enable_gmp" != "xno"; then
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __gmpz_add in -lgmp" >&5
+$as_echo_n "checking for __gmpz_add in -lgmp... " >&6; }
+if ${ac_cv_lib_gmp___gmpz_add+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgmp  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char __gmpz_add ();
+int
+main ()
+{
+return __gmpz_add ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_gmp___gmpz_add=yes
+else
+  ac_cv_lib_gmp___gmpz_add=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmp___gmpz_add" >&5
+$as_echo "$ac_cv_lib_gmp___gmpz_add" >&6; }
+if test "x$ac_cv_lib_gmp___gmpz_add" = xyes; then :
+
+    ac_fn_cxx_check_header_mongrel "$LINENO" "gmp.h" "ac_cv_header_gmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_gmp_h" = xyes; then :
+
+
+$as_echo "#define HAVE_GMP 1" >>confdefs.h
+
+      gmp_support=yes
+      LDFLAGS="${LDFLAGS} -lgmp"
+      PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -lgmp"
+
+fi
+
+
+
+fi
+
+fi
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+tls_support=no
+HAVE_TLS=0
+THREAD_LOCAL=
+# Check whether --enable-tls was given.
+if test "${enable_tls+set}" = set; then :
+  enableval=$enable_tls;
+fi
+
+if test "x$enable_tls" != "xno"; then
+  keywords="__thread __declspec(thread)"
+  for kw in $keywords ; do
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int $kw test;
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_tls=$kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int $kw test;
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_tls=$kw ; break ;
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread local storage (TLS) class" >&5
+$as_echo_n "checking for thread local storage (TLS) class... " >&6; }
+  if ${ac_cv_tls+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ax_tls_keywords="__thread __declspec(thread) none"
+    for ax_tls_keyword in $ax_tls_keywords; do
+       case $ax_tls_keyword in #(
+  none) :
+    ac_cv_tls=none ; break ;; #(
+  *) :
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+               static void
+               foo(void) {
+               static  $ax_tls_keyword  int bar;
+               exit(1);
+               }
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_tls=$ax_tls_keyword ; break
+else
+  ac_cv_tls=none
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;;
+esac
+    done
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_tls" >&5
+$as_echo "$ac_cv_tls" >&6; }
+
+  if test "$ac_cv_tls" != "none"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define TLS $ac_cv_tls
+_ACEOF
+
+
+
+$as_echo "#define HAVE_TLS 1" >>confdefs.h
+
+    tls_support=yes
+    HAVE_TLS=1
+    THREAD_LOCAL=$ac_cv_tls
+
+else
+  true
+
+fi
+
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define IGRAPH_THREAD_LOCAL $THREAD_LOCAL
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define IGRAPH_F77_SAVE static IGRAPH_THREAD_LOCAL
+_ACEOF
+
+
+
+# Check whether --with-external-f2c was given.
+if test "${with_external_f2c+set}" = set; then :
+  withval=$with_external_f2c; internal_f2c=no
+else
+  internal_f2c=yes
+fi
+
+
+# Check whether --with-external-blas was given.
+if test "${with_external_blas+set}" = set; then :
+  withval=$with_external_blas; internal_blas=no
+else
+  internal_blas=yes
+fi
+
+
+# Check whether --with-external-lapack was given.
+if test "${with_external_lapack+set}" = set; then :
+  withval=$with_external_lapack; internal_lapack=no
+else
+  internal_lapack=yes
+fi
+
+
+# Check whether --with-external-arpack was given.
+if test "${with_external_arpack+set}" = set; then :
+  withval=$with_external_arpack; internal_arpack=no
+else
+  internal_arpack=yes
+fi
+
+
+
+# Check whether --with-external-glpk was given.
+if test "${with_external_glpk+set}" = set; then :
+  withval=$with_external_glpk; internal_glpk=no
+else
+  internal_glpk=yes
+fi
+
+
+if test "$internal_f2c" = "no"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for f77_alloc_ in -lf2c" >&5
+$as_echo_n "checking for f77_alloc_ in -lf2c... " >&6; }
+if ${ac_cv_lib_f2c_f77_alloc_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lf2c  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char f77_alloc_ ();
+int
+main ()
+{
+return f77_alloc_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_f2c_f77_alloc_=yes
+else
+  ac_cv_lib_f2c_f77_alloc_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_f2c_f77_alloc_" >&5
+$as_echo "$ac_cv_lib_f2c_f77_alloc_" >&6; }
+if test "x$ac_cv_lib_f2c_f77_alloc_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBF2C 1
+_ACEOF
+
+  LIBS="-lf2c $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for f77_alloc in -lf2c" >&5
+$as_echo_n "checking for f77_alloc in -lf2c... " >&6; }
+if ${ac_cv_lib_f2c_f77_alloc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lf2c  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char f77_alloc ();
+int
+main ()
+{
+return f77_alloc ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_f2c_f77_alloc=yes
+else
+  ac_cv_lib_f2c_f77_alloc=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_f2c_f77_alloc" >&5
+$as_echo "$ac_cv_lib_f2c_f77_alloc" >&6; }
+if test "x$ac_cv_lib_f2c_f77_alloc" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBF2C 1
+_ACEOF
+
+  LIBS="-lf2c $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for F77_ALLOC_ in -lf2c" >&5
+$as_echo_n "checking for F77_ALLOC_ in -lf2c... " >&6; }
+if ${ac_cv_lib_f2c_F77_ALLOC_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lf2c  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char F77_ALLOC_ ();
+int
+main ()
+{
+return F77_ALLOC_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_f2c_F77_ALLOC_=yes
+else
+  ac_cv_lib_f2c_F77_ALLOC_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_f2c_F77_ALLOC_" >&5
+$as_echo "$ac_cv_lib_f2c_F77_ALLOC_" >&6; }
+if test "x$ac_cv_lib_f2c_F77_ALLOC_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBF2C 1
+_ACEOF
+
+  LIBS="-lf2c $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for F77_ALLOC in -lf2c" >&5
+$as_echo_n "checking for F77_ALLOC in -lf2c... " >&6; }
+if ${ac_cv_lib_f2c_F77_ALLOC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lf2c  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char F77_ALLOC ();
+int
+main ()
+{
+return F77_ALLOC ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_f2c_F77_ALLOC=yes
+else
+  ac_cv_lib_f2c_F77_ALLOC=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_f2c_F77_ALLOC" >&5
+$as_echo "$ac_cv_lib_f2c_F77_ALLOC" >&6; }
+if test "x$ac_cv_lib_f2c_F77_ALLOC" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBF2C 1
+_ACEOF
+
+  LIBS="-lf2c $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+fi
+
+fi
+
+fi
+
+fi
+
+  LDFLAGS="${LDFLAGS}"
+else
+
+$as_echo "#define INTERNAL_F2C 1" >>confdefs.h
+
+fi
+
+if test "$internal_blas" = "no"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for daxpy_ in -lblas" >&5
+$as_echo_n "checking for daxpy_ in -lblas... " >&6; }
+if ${ac_cv_lib_blas_daxpy_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblas  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char daxpy_ ();
+int
+main ()
+{
+return daxpy_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_blas_daxpy_=yes
+else
+  ac_cv_lib_blas_daxpy_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_daxpy_" >&5
+$as_echo "$ac_cv_lib_blas_daxpy_" >&6; }
+if test "x$ac_cv_lib_blas_daxpy_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBLAS 1
+_ACEOF
+
+  LIBS="-lblas $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for daxpy in -lblas" >&5
+$as_echo_n "checking for daxpy in -lblas... " >&6; }
+if ${ac_cv_lib_blas_daxpy+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblas  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char daxpy ();
+int
+main ()
+{
+return daxpy ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_blas_daxpy=yes
+else
+  ac_cv_lib_blas_daxpy=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_daxpy" >&5
+$as_echo "$ac_cv_lib_blas_daxpy" >&6; }
+if test "x$ac_cv_lib_blas_daxpy" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBLAS 1
+_ACEOF
+
+  LIBS="-lblas $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DAXPY_ in -lblas" >&5
+$as_echo_n "checking for DAXPY_ in -lblas... " >&6; }
+if ${ac_cv_lib_blas_DAXPY_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblas  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DAXPY_ ();
+int
+main ()
+{
+return DAXPY_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_blas_DAXPY_=yes
+else
+  ac_cv_lib_blas_DAXPY_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_DAXPY_" >&5
+$as_echo "$ac_cv_lib_blas_DAXPY_" >&6; }
+if test "x$ac_cv_lib_blas_DAXPY_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBLAS 1
+_ACEOF
+
+  LIBS="-lblas $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DAXPY in -lblas" >&5
+$as_echo_n "checking for DAXPY in -lblas... " >&6; }
+if ${ac_cv_lib_blas_DAXPY+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblas  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DAXPY ();
+int
+main ()
+{
+return DAXPY ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_blas_DAXPY=yes
+else
+  ac_cv_lib_blas_DAXPY=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_DAXPY" >&5
+$as_echo "$ac_cv_lib_blas_DAXPY" >&6; }
+if test "x$ac_cv_lib_blas_DAXPY" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBLAS 1
+_ACEOF
+
+  LIBS="-lblas $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+fi
+
+fi
+
+fi
+
+fi
+
+  LDFLAGS="${LDFLAGS} -lblas"
+  PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -lblas"
+else
+
+$as_echo "#define INTERNAL_BLAS 1" >>confdefs.h
+
+fi
+
+if test "$internal_lapack" = "no"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlarnv_ in -llapack" >&5
+$as_echo_n "checking for dlarnv_ in -llapack... " >&6; }
+if ${ac_cv_lib_lapack_dlarnv_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llapack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlarnv_ ();
+int
+main ()
+{
+return dlarnv_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_lapack_dlarnv_=yes
+else
+  ac_cv_lib_lapack_dlarnv_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_dlarnv_" >&5
+$as_echo "$ac_cv_lib_lapack_dlarnv_" >&6; }
+if test "x$ac_cv_lib_lapack_dlarnv_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBLAPACK 1
+_ACEOF
+
+  LIBS="-llapack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlarnv in -llapack" >&5
+$as_echo_n "checking for dlarnv in -llapack... " >&6; }
+if ${ac_cv_lib_lapack_dlarnv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llapack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlarnv ();
+int
+main ()
+{
+return dlarnv ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_lapack_dlarnv=yes
+else
+  ac_cv_lib_lapack_dlarnv=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_dlarnv" >&5
+$as_echo "$ac_cv_lib_lapack_dlarnv" >&6; }
+if test "x$ac_cv_lib_lapack_dlarnv" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBLAPACK 1
+_ACEOF
+
+  LIBS="-llapack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DLARNV_ in -llapack" >&5
+$as_echo_n "checking for DLARNV_ in -llapack... " >&6; }
+if ${ac_cv_lib_lapack_DLARNV_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llapack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DLARNV_ ();
+int
+main ()
+{
+return DLARNV_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_lapack_DLARNV_=yes
+else
+  ac_cv_lib_lapack_DLARNV_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_DLARNV_" >&5
+$as_echo "$ac_cv_lib_lapack_DLARNV_" >&6; }
+if test "x$ac_cv_lib_lapack_DLARNV_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBLAPACK 1
+_ACEOF
+
+  LIBS="-llapack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DLARNV in -llapack" >&5
+$as_echo_n "checking for DLARNV in -llapack... " >&6; }
+if ${ac_cv_lib_lapack_DLARNV+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llapack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DLARNV ();
+int
+main ()
+{
+return DLARNV ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_lapack_DLARNV=yes
+else
+  ac_cv_lib_lapack_DLARNV=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_DLARNV" >&5
+$as_echo "$ac_cv_lib_lapack_DLARNV" >&6; }
+if test "x$ac_cv_lib_lapack_DLARNV" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBLAPACK 1
+_ACEOF
+
+  LIBS="-llapack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+fi
+
+fi
+
+fi
+
+fi
+
+  LDFLAGS="${LDFLAGS} -llapack"
+  PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -llapack"
+else
+
+$as_echo "#define INTERNAL_LAPACK 1" >>confdefs.h
+
+fi
+
+if test "$internal_arpack" = "no"; then
+  if test "$tls_support" = "yes"; then
+    as_fn_error $? "Thread-local storage only supported with internal ARPACK library" "$LINENO" 5
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dsaupd_ in -larpack" >&5
+$as_echo_n "checking for dsaupd_ in -larpack... " >&6; }
+if ${ac_cv_lib_arpack_dsaupd_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-larpack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dsaupd_ ();
+int
+main ()
+{
+return dsaupd_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_arpack_dsaupd_=yes
+else
+  ac_cv_lib_arpack_dsaupd_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_arpack_dsaupd_" >&5
+$as_echo "$ac_cv_lib_arpack_dsaupd_" >&6; }
+if test "x$ac_cv_lib_arpack_dsaupd_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBARPACK 1
+_ACEOF
+
+  LIBS="-larpack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dsaupd in -larpack" >&5
+$as_echo_n "checking for dsaupd in -larpack... " >&6; }
+if ${ac_cv_lib_arpack_dsaupd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-larpack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dsaupd ();
+int
+main ()
+{
+return dsaupd ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_arpack_dsaupd=yes
+else
+  ac_cv_lib_arpack_dsaupd=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_arpack_dsaupd" >&5
+$as_echo "$ac_cv_lib_arpack_dsaupd" >&6; }
+if test "x$ac_cv_lib_arpack_dsaupd" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBARPACK 1
+_ACEOF
+
+  LIBS="-larpack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DSAUPD_ in -larpack" >&5
+$as_echo_n "checking for DSAUPD_ in -larpack... " >&6; }
+if ${ac_cv_lib_arpack_DSAUPD_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-larpack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DSAUPD_ ();
+int
+main ()
+{
+return DSAUPD_ ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_arpack_DSAUPD_=yes
+else
+  ac_cv_lib_arpack_DSAUPD_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_arpack_DSAUPD_" >&5
+$as_echo "$ac_cv_lib_arpack_DSAUPD_" >&6; }
+if test "x$ac_cv_lib_arpack_DSAUPD_" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBARPACK 1
+_ACEOF
+
+  LIBS="-larpack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DSAUPD in -larpack" >&5
+$as_echo_n "checking for DSAUPD in -larpack... " >&6; }
+if ${ac_cv_lib_arpack_DSAUPD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-larpack  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DSAUPD ();
+int
+main ()
+{
+return DSAUPD ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_arpack_DSAUPD=yes
+else
+  ac_cv_lib_arpack_DSAUPD=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_arpack_DSAUPD" >&5
+$as_echo "$ac_cv_lib_arpack_DSAUPD" >&6; }
+if test "x$ac_cv_lib_arpack_DSAUPD" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBARPACK 1
+_ACEOF
+
+  LIBS="-larpack $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+fi
+
+fi
+
+fi
+
+fi
+
+  LDFLAGS="${LDFLAGS} -larpack"
+  PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -larpack"
+else
+
+$as_echo "#define INTERNAL_ARPACK 1" >>confdefs.h
+
+fi
+
+glpk_support=no
+# Check whether --enable-glpk was given.
+if test "${enable_glpk+set}" = set; then :
+  enableval=$enable_glpk;
+fi
+
+if test "x$enable_glpk" != "xno"; then
+  if test "$internal_glpk" = "no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for glp_read_mps in -lglpk" >&5
+$as_echo_n "checking for glp_read_mps in -lglpk... " >&6; }
+if ${ac_cv_lib_glpk_glp_read_mps+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lglpk  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char glp_read_mps ();
+int
+main ()
+{
+return glp_read_mps ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_glpk_glp_read_mps=yes
+else
+  ac_cv_lib_glpk_glp_read_mps=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_glpk_glp_read_mps" >&5
+$as_echo "$ac_cv_lib_glpk_glp_read_mps" >&6; }
+if test "x$ac_cv_lib_glpk_glp_read_mps" = xyes; then :
+
+      ac_fn_cxx_check_header_mongrel "$LINENO" "glpk.h" "ac_cv_header_glpk_h" "$ac_includes_default"
+if test "x$ac_cv_header_glpk_h" = xyes; then :
+
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+          #include <glpk.h>
+          #if GLP_MAJOR_VERSION > 4 || (GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 38)
+            yes
+          #endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then :
+
+
+$as_echo "#define HAVE_GLPK 1" >>confdefs.h
+
+          glpk_support=yes
+          LDFLAGS="${LDFLAGS} -lglpk"
+          PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -lglpk"
+
+fi
+rm -f conftest*
+
+
+fi
+
+
+
+fi
+
+  else
+
+$as_echo "#define HAVE_GLPK 1" >>confdefs.h
+
+
+$as_echo "#define INTERNAL_GLPK 1" >>confdefs.h
+
+    glpk_support=yes
+  fi
+else
+  internal_glpk=no
+fi
+
+ if test x$internal_glpk = xyes; then
+  INTERNAL_GLPK_TRUE=
+  INTERNAL_GLPK_FALSE='#'
+else
+  INTERNAL_GLPK_TRUE='#'
+  INTERNAL_GLPK_FALSE=
+fi
+
+ if test x$internal_arpack = xyes; then
+  INTERNAL_ARPACK_TRUE=
+  INTERNAL_ARPACK_FALSE='#'
+else
+  INTERNAL_ARPACK_TRUE='#'
+  INTERNAL_ARPACK_FALSE=
+fi
+
+ if test x$internal_lapack = xyes; then
+  INTERNAL_LAPACK_TRUE=
+  INTERNAL_LAPACK_FALSE='#'
+else
+  INTERNAL_LAPACK_TRUE='#'
+  INTERNAL_LAPACK_FALSE=
+fi
+
+ if test x$internal_blas = xyes; then
+  INTERNAL_BLAS_TRUE=
+  INTERNAL_BLAS_FALSE='#'
+else
+  INTERNAL_BLAS_TRUE='#'
+  INTERNAL_BLAS_FALSE=
+fi
+
+ if test x$internal_f2c = xyes; then
+  INTERNAL_F2C_TRUE=
+  INTERNAL_F2C_FALSE='#'
+else
+  INTERNAL_F2C_TRUE='#'
+  INTERNAL_F2C_FALSE=
+fi
+
+
+if test "$debug" = "yes"; then
+  CFLAGS="${CFLAGS} -ggdb -DRC_DEBUG -O0"
+  CPPFLAGS="${CFLAGS} -ggdb -DRC_DEBUG"
+  CXXFLAGS="${CFLAGS} -ggdb -DRC_DEBUG -O0"
+fi
+
+if test "$use_gprof" = "yes"; then
+  CFLAGS="${CFLAGS} -pg"
+  CPPFLAGS="${CFLAGS} -pg"
+  CXXFLAGS="${CFLAGS} -pg"
+fi
+
+ac_config_files="$ac_config_files Makefile src/Makefile igraph.pc igraph_Info.plist doc/Makefile include/igraph_version.h include/igraph_threading.h"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${INTERNAL_GLPK_TRUE}" && test -z "${INTERNAL_GLPK_FALSE}"; then
+  as_fn_error $? "conditional \"INTERNAL_GLPK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${INTERNAL_ARPACK_TRUE}" && test -z "${INTERNAL_ARPACK_FALSE}"; then
+  as_fn_error $? "conditional \"INTERNAL_ARPACK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${INTERNAL_LAPACK_TRUE}" && test -z "${INTERNAL_LAPACK_FALSE}"; then
+  as_fn_error $? "conditional \"INTERNAL_LAPACK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${INTERNAL_BLAS_TRUE}" && test -z "${INTERNAL_BLAS_FALSE}"; then
+  as_fn_error $? "conditional \"INTERNAL_BLAS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${INTERNAL_F2C_TRUE}" && test -z "${INTERNAL_F2C_FALSE}"; then
+  as_fn_error $? "conditional \"INTERNAL_F2C\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by igraph $as_me 0.7.1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <csardi.gabor at gmail.com>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+igraph config.status 0.7.1
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
+predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
+postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in AS \
+DLLTOOL \
+OBJDUMP \
+SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+reload_flag_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_separator_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+reload_cmds_CXX \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX \
+postlink_cmds_CXX; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "tests/atconfig") CONFIG_COMMANDS="$CONFIG_COMMANDS tests/atconfig" ;;
+    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
+    "tests/atlocal") CONFIG_FILES="$CONFIG_FILES tests/atlocal" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+    "igraph.pc") CONFIG_FILES="$CONFIG_FILES igraph.pc" ;;
+    "igraph_Info.plist") CONFIG_FILES="$CONFIG_FILES igraph_Info.plist" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "include/igraph_version.h") CONFIG_FILES="$CONFIG_FILES include/igraph_version.h" ;;
+    "include/igraph_threading.h") CONFIG_FILES="$CONFIG_FILES include/igraph_threading.h" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "tests/atconfig":C) cat >tests/atconfig <<ATEOF
+# Configurable variable values for building test suites.
+# Generated by $0.
+# Copyright (C) 2012 Free Software Foundation, Inc.
+
+# The test suite will define top_srcdir=$at_top_srcdir/../.. etc.
+at_testdir='tests'
+abs_builddir='$ac_abs_builddir'
+at_srcdir='$ac_srcdir'
+abs_srcdir='$ac_abs_srcdir'
+at_top_srcdir='$ac_top_srcdir'
+abs_top_srcdir='$ac_abs_top_srcdir'
+at_top_build_prefix='$ac_top_build_prefix'
+abs_top_builddir='$ac_abs_top_builddir'
+
+# Backward compatibility with Autotest <= 2.59b:
+at_top_builddir=\$at_top_build_prefix
+
+AUTOTEST_PATH='tests'
+
+SHELL=\${CONFIG_SHELL-'$SHELL'}
+ATEOF
+ ;;
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Assembler program.
+AS=$lt_AS
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Object dumper program.
+OBJDUMP=$lt_OBJDUMP
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  if test x"$xsi_shell" = xyes; then
+  sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\    # positional parameters, so assign one to ordinary parameter first.\
+\    func_stripname_result=${3}\
+\    func_stripname_result=${func_stripname_result#"${1}"}\
+\    func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\    func_split_long_opt_name=${1%%=*}\
+\    func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\    func_split_short_opt_arg=${1#??}\
+\    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\    case ${1} in\
+\      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\      *)    func_lo2o_result=${1} ;;\
+\    esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+    func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+    func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+    func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+    eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\    func_quote_for_eval "${2}"\
+\    eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+
+    cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: igraph successfully configured." >&5
+$as_echo "igraph successfully configured." >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   GraphML format support -- $graphml_support" >&5
+$as_echo "  GraphML format support -- $graphml_support" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   GMP library support    -- $gmp_support" >&5
+$as_echo "  GMP library support    -- $gmp_support" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   GLPK library support   -- $glpk_support" >&5
+$as_echo "  GLPK library support   -- $glpk_support" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Thread-local storage   -- $tls_support" >&5
+$as_echo "  Thread-local storage   -- $tls_support" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Use internal ARPACK    -- $internal_arpack" >&5
+$as_echo "  Use internal ARPACK    -- $internal_arpack" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Use internal LAPACK    -- $internal_lapack" >&5
+$as_echo "  Use internal LAPACK    -- $internal_lapack" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Use internal BLAS      -- $internal_blas" >&5
+$as_echo "  Use internal BLAS      -- $internal_blas" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Use internal F2C       -- $internal_f2c" >&5
+$as_echo "  Use internal F2C       -- $internal_f2c" >&6; }
+if test "$glpk_support" != "no"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result:   Use internal GLPK      -- $internal_glpk" >&5
+$as_echo "  Use internal GLPK      -- $internal_glpk" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Debug build            -- $debug" >&5
+$as_echo "  Debug build            -- $debug" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:   Profiling              -- $use_gprof" >&5
+$as_echo "  Profiling              -- $use_gprof" >&6; }
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..acf76cd
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,334 @@
+AC_INIT(igraph, esyscmd([tr -d '\n' < VERSION]), csardi.gabor at gmail.com)
+AC_CONFIG_SRCDIR(src/games.c)
+AM_INIT_AUTOMAKE([subdir-objects])
+AC_CONFIG_HEADERS([config.h])
+
+m4_include(tools/autoconf/ax_tls.m4)
+
+# Define list of additional libraries that have to be linked to igraph when
+# another app tries to link to the static library of igraph. This is substituted
+# into igraph.pc later on.
+PKGCONFIG_LIBS_PRIVATE="-lxml2 -lz -lm"
+AC_SUBST(PKGCONFIG_LIBS_PRIVATE)
+
+# Test suite
+AC_CONFIG_TESTDIR(tests)
+AC_CONFIG_FILES([tests/Makefile tests/atlocal])
+
+AC_LANG(C)
+AC_PROG_CC
+
+# 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++])
+
+AM_PROG_LEX
+AC_PROG_YACC
+
+AC_CHECK_HEADER([sys/times.h], 
+      [AC_DEFINE([HAVE_TIMES_H], [1], [Define to 1 if you have the sys/times.h header])])
+
+AC_LIBTOOL_WIN32_DLL
+AC_LIBTOOL_DLOPEN
+AC_PROG_LIBTOOL
+AM_MISSING_PROG([AUTOM4TE], [autom4te])
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdarg.h stdlib.h string.h time.h unistd.h stdint.h sys/int_types.h])
+LIBS_SAVE=$LIBS
+LIBS="$LIBS -lm"
+AC_CHECK_FUNCS([expm1 rint rintf finite log2 snprintf log1p round fabsl fmin strcasecmp isnan strdup _strdup ftruncate 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_DEFUN([IGRAPH_WARNING],
+[AC_MSG_CHECKING(whether compiler accepts $1)
+AC_SUBST(WARNING_CFLAGS)
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $1"
+AC_TRY_COMPILE(,
+[int x;],
+WARNING_CFLAGS="$WARNING_CFLAGS $1"
+AC_MSG_RESULT(yes),
+AC_MSG_RESULT(no))
+CFLAGS="$ac_save_CFLAGS"])
+
+AC_DEFUN([IGRAPH_CC_SWITCH],
+[AC_MSG_CHECKING(whether compiler supports $1)
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $1"
+AC_TRY_COMPILE(,
+[int x;],
+AC_MSG_RESULT(yes)
+$2,
+AC_MSG_RESULT(no)
+$3)
+CFLAGS="$ac_save_CFLAGS"])
+
+## Solaris cc does not support -ffloat-store.
+FLOATSTORE=
+IGRAPH_CC_SWITCH([-ffloat-store], [FLOATSTORE="-ffloat-store"], [])
+IGRAPH_CC_SWITCH([-fstore], [FLOATSTORE="$FLOATSTORE -fstore"], [])
+AC_SUBST(FLOATSTORE)
+
+AC_ARG_ENABLE(gcc-warnings,
+              AC_HELP_STRING([--enable-gcc-warnings],
+	                     [turn on lots of GCC warnings (not recommended)]),
+[case "${enableval}" in
+   yes|no) ;;
+   *)      AC_MSG_ERROR([bad value ${enableval} for gcc-warnings option]) ;;
+ esac],
+              [enableval=no])
+if test "${enableval}" = yes; then
+  IGRAPH_WARNING(-Werror)
+  AC_SUBST([WERROR_CFLAGS], [$WARNING_CFLAGS])
+  WARNING_CFLAGS=
+  IGRAPH_WARNING(-Wall)
+  IGRAPH_WARNING(-W)
+  IGRAPH_WARNING(-Wbad-function-cast)
+  IGRAPH_WARNING(-Wcast-align)
+  IGRAPH_WARNING(-Wcast-qual)
+  IGRAPH_WARNING(-Wformat)
+  IGRAPH_WARNING(-Wmissing-declarations)
+  IGRAPH_WARNING(-Wmissing-prototypes)
+  IGRAPH_WARNING(-Wnested-externs)
+  IGRAPH_WARNING(-Wshadow)
+  IGRAPH_WARNING(-Wstrict-prototypes)
+  IGRAPH_WARNING(-Wwrite-strings)
+else
+  WARNING_CFLAGS=                                                              
+  IGRAPH_WARNING(-Wall)
+fi
+
+use_gprof=no
+AC_ARG_ENABLE(profiling,
+              AC_HELP_STRING([--enable-profiling], [Enable gprof profiling]),
+              [use_gprof=$enableval], [use_gprof=no])
+
+debug=no
+AC_ARG_ENABLE(debug,
+              AC_HELP_STRING([--enable-debug], [Enable debug build]),
+	      [debug=$enableval])
+
+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
+	# Hmmm, no xml2-config. OS X does not have it while still
+	# having libxml2, so let's try an educated guess
+	XML2_LIBS="-lxml2 -lz -lm"
+	XML2_CFLAGS="-I/usr/include/libxml2"
+  else
+    XML2_LIBS=`$XML2CONFIG --libs`
+    XML2_CFLAGS=`$XML2CONFIG --cflags`
+  fi
+  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
+
+AC_LANG_PUSH([C++])
+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], [
+      AC_DEFINE([HAVE_GMP], [1], [Define to 1 if you have the GMP library])
+      gmp_support=yes
+      LDFLAGS="${LDFLAGS} -lgmp"
+      PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -lgmp"
+    ])
+  ])
+fi
+AC_LANG_PUSH([C++])
+
+tls_support=no
+HAVE_TLS=0
+THREAD_LOCAL=
+AC_ARG_ENABLE(tls, AC_HELP_STRING([--enable-tls], [Compile with thread-local storage]))
+if test "x$enable_tls" != "xno"; then
+  keywords="__thread __declspec(thread)"
+  for kw in $keywords ; do
+      AC_TRY_COMPILE([int $kw test;], [], ac_cv_tls=$kw)
+      AC_TRY_COMPILE([int $kw test;], [], ac_cv_tls=$kw ; break ;)
+  done
+  AX_TLS([
+    AC_DEFINE([HAVE_TLS], [1], [Define to 1 if you want to use thread-local storage for global igraph structures])
+    tls_support=yes
+    HAVE_TLS=1
+    THREAD_LOCAL=$ac_cv_tls
+  ], [])
+fi
+AC_SUBST(HAVE_TLS)
+AC_DEFINE_UNQUOTED([IGRAPH_THREAD_LOCAL], $THREAD_LOCAL,
+          [Keyword for thread local storage, or empty if not available])
+AC_DEFINE_UNQUOTED([IGRAPH_F77_SAVE], [static IGRAPH_THREAD_LOCAL],
+          [Keyword for thread local storage, or just static if not available])
+
+AC_ARG_WITH([external-f2c], [AS_HELP_STRING([--with-external-f2c],
+		                      [Use external F2C library [default=no]])],
+            [internal_f2c=no],
+	    [internal_f2c=yes])
+AC_ARG_WITH([external-blas], [AS_HELP_STRING([--with-external-blas],
+		                      [Use external BLAS library [default=no]])],
+            [internal_blas=no],
+	    [internal_blas=yes])
+AC_ARG_WITH([external-lapack], [AS_HELP_STRING([--with-external-lapack],
+		                      [Use external LAPACK library [default=no]])],
+            [internal_lapack=no],
+	    [internal_lapack=yes])
+AC_ARG_WITH([external-arpack], [AS_HELP_STRING([--with-external-arpack],
+		                      [Use external ARPACK library [default=no]])],
+            [internal_arpack=no],
+	    [internal_arpack=yes])
+
+AC_ARG_WITH([external-glpk], [AS_HELP_STRING([--with-external-glpk],
+				      [Use external GLPK library [default=no]])],
+            [internal_glpk=no],
+            [internal_glpk=yes])
+
+if test "$internal_f2c" = "no"; then
+  AC_CHECK_LIB([f2c], [f77_alloc_], [],
+     AC_CHECK_LIB([f2c], [f77_alloc], [],
+        AC_CHECK_LIB([f2c], [F77_ALLOC_], [],
+           AC_CHECK_LIB([f2c], [F77_ALLOC], [],
+	      [AC_MSG_RESULT(not found, trying to use -lf2c anyway.)]))))
+  LDFLAGS="${LDFLAGS}"
+else
+  AC_DEFINE([INTERNAL_F2C], [1], [Define to 1 if you use the internal F2C library])
+fi
+
+if test "$internal_blas" = "no"; then
+  AC_CHECK_LIB([blas], [daxpy_], [],
+     AC_CHECK_LIB([blas], [daxpy], [],
+        AC_CHECK_LIB([blas], [DAXPY_], [],
+           AC_CHECK_LIB([blas], [DAXPY], [],
+	      [AC_MSG_RESULT(not found, trying to use -lblas anyway.)]))))
+  LDFLAGS="${LDFLAGS} -lblas"
+  PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -lblas"
+else
+  AC_DEFINE([INTERNAL_BLAS], [1], [Define to 1 if you use the internal BLAS library])
+fi
+
+if test "$internal_lapack" = "no"; then
+  AC_CHECK_LIB([lapack], [dlarnv_], [],
+     AC_CHECK_LIB([lapack], [dlarnv], [],
+        AC_CHECK_LIB([lapack], [DLARNV_], [],
+           AC_CHECK_LIB([lapack], [DLARNV], [],
+	      [AC_MSG_RESULT(not found, trying to use -llapack anyway.)]))))
+  LDFLAGS="${LDFLAGS} -llapack"
+  PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -llapack"
+else
+  AC_DEFINE([INTERNAL_LAPACK], [1], [Define to 1 if you use the internal LAPACK library])
+fi
+
+if test "$internal_arpack" = "no"; then
+  if test "$tls_support" = "yes"; then
+    AC_MSG_ERROR([Thread-local storage only supported with internal ARPACK library])
+  fi
+  AC_CHECK_LIB([arpack], [dsaupd_], [],
+     AC_CHECK_LIB([arpack], [dsaupd], [],
+        AC_CHECK_LIB([arpack], [DSAUPD_], [],
+           AC_CHECK_LIB([arpack], [DSAUPD], [],
+	      [AC_MSG_RESULT(not found, trying to use -larpack anyway.)]))))
+  LDFLAGS="${LDFLAGS} -larpack"
+  PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -larpack"
+else
+  AC_DEFINE([INTERNAL_ARPACK], [1], [Define to 1 if you use the internal ARPACK library])
+fi
+
+glpk_support=no
+AC_ARG_ENABLE(glpk, AC_HELP_STRING([--disable-glpk], [Compile without the GLPK library]))
+if test "x$enable_glpk" != "xno"; then
+  if test "$internal_glpk" = "no"; then
+    AC_CHECK_LIB([glpk], [glp_read_mps], [
+      AC_CHECK_HEADER([glpk.h], [
+        AC_EGREP_CPP(yes, [
+          #include <glpk.h>
+          #if GLP_MAJOR_VERSION > 4 || (GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 38)
+            yes
+          #endif
+        ], [
+          AC_DEFINE([HAVE_GLPK], [1], [Define to 1 if you have the GLPK library])
+          glpk_support=yes
+          LDFLAGS="${LDFLAGS} -lglpk"
+          PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE} -lglpk"
+        ])
+      ])
+    ])
+  else
+    AC_DEFINE([HAVE_GLPK], [1], [Define to 1 if you have the GLPK library])
+    AC_DEFINE([INTERNAL_GLPK], [1], [Define to 1 if you use the internal GLPK library])
+    glpk_support=yes
+  fi
+else
+  internal_glpk=no
+fi
+
+AM_CONDITIONAL(INTERNAL_GLPK, test x$internal_glpk = xyes)
+AM_CONDITIONAL(INTERNAL_ARPACK, test x$internal_arpack = xyes)
+AM_CONDITIONAL(INTERNAL_LAPACK, test x$internal_lapack = xyes)
+AM_CONDITIONAL(INTERNAL_BLAS, test x$internal_blas = xyes)
+AM_CONDITIONAL(INTERNAL_F2C, test x$internal_f2c = xyes)
+
+if test "$debug" = "yes"; then
+  CFLAGS="${CFLAGS} -ggdb -DRC_DEBUG -O0"
+  CPPFLAGS="${CFLAGS} -ggdb -DRC_DEBUG"
+  CXXFLAGS="${CFLAGS} -ggdb -DRC_DEBUG -O0"
+fi
+
+if test "$use_gprof" = "yes"; then
+  CFLAGS="${CFLAGS} -pg"
+  CPPFLAGS="${CFLAGS} -pg"
+  CXXFLAGS="${CFLAGS} -pg"
+fi
+
+AC_CONFIG_FILES([Makefile src/Makefile igraph.pc igraph_Info.plist doc/Makefile include/igraph_version.h include/igraph_threading.h])
+AC_OUTPUT
+
+AC_MSG_RESULT([igraph successfully configured.])
+AC_MSG_RESULT([  GraphML format support -- $graphml_support])
+AC_MSG_RESULT([  GMP library support    -- $gmp_support])
+AC_MSG_RESULT([  GLPK library support   -- $glpk_support])
+AC_MSG_RESULT([  Thread-local storage   -- $tls_support])
+AC_MSG_RESULT([  Use internal ARPACK    -- $internal_arpack])
+AC_MSG_RESULT([  Use internal LAPACK    -- $internal_lapack])
+AC_MSG_RESULT([  Use internal BLAS      -- $internal_blas])
+AC_MSG_RESULT([  Use internal F2C       -- $internal_f2c])
+if test "$glpk_support" != "no"; then
+  AC_MSG_RESULT([  Use internal GLPK      -- $internal_glpk])
+fi
+AC_MSG_RESULT([  Debug build            -- $debug])
+AC_MSG_RESULT([  Profiling              -- $use_gprof])
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index a2ffa3a..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,71 +0,0 @@
-igraph (0.7.1-1) unstable; urgency=medium
-
-  * New upstream version
-
- -- Andreas Tille <tille at debian.org>  Fri, 08 Aug 2014 16:12:35 +0200
-
-igraph (0.6.5-5) unstable; urgency=medium
-
-  * use dh-autoreconf instead of autotools-dev (thanks to Logan Rosen
-    <logan at ubuntu.com> for the patch)
-    Closes: #733712
-
- -- Andreas Tille <tille at debian.org>  Tue, 31 Dec 2013 08:37:18 +0100
-
-igraph (0.6.5-4) unstable; urgency=medium
-
-  * cme fix dpkg-control
-  * debian/patches/link_f2c.patch: Make sure libf2c will be properly linked
-    Closes: #702882
-
- -- Andreas Tille <tille at debian.org>  Thu, 19 Dec 2013 11:23:31 +0100
-
-igraph (0.6.5-3) unstable; urgency=low
-
-  * Team upload.
-  * Rebuild against latest gmp
-  * debian/control:
-     - cme fix dpkg-control
-     - Canonical Vcs-Svn
-
- -- Andreas Tille <tille at debian.org>  Tue, 16 Jul 2013 09:12:52 +0200
-
-igraph (0.6.5-2) unstable; urgency=low
-
-  * Upload to sid
-
- -- Mathieu Malaterre <malat at debian.org>  Mon, 27 May 2013 14:01:54 +0200
-
-igraph (0.6.5-1) experimental; urgency=low
-
-  * New upstream
-  * Bump Std-Vers to 3.9.4. No changes needed
-
- -- Mathieu Malaterre <malat at debian.org>  Tue, 12 Mar 2013 14:34:23 +0100
-
-igraph (0.5.4-2) unstable; urgency=low
-
-  * Use my @d.o alias
-  * Remove DMUA flag
-  * Bump Std-Vers to 3.9.3, no changes needed
-  * Switch to dpkg-source 3.0 (quilt) format
-  * Use dh(9), get hardening for free
-
- -- Mathieu Malaterre <malat at debian.org>  Wed, 11 Apr 2012 13:09:46 +0200
-
-igraph (0.5.4-1) unstable; urgency=low
-
-  * New upstream.
-  
-  * control: Change depends libgmp3-dev --> libgmp-dev.  Update
-    Standards-Version to 3.9.1.
-  
-  * rules: empty out dependency_libs.
-
- -- Steve M. Robbins <smr at debian.org>  Wed, 16 Mar 2011 23:42:10 -0500
-
-igraph (0.5.3-1) unstable; urgency=low
-
-  * Initial upload to Debian. Closes: #546752.
-
- -- Mathieu Malaterre <mathieu.malaterre at gmail.com>  Mon, 16 Nov 2009 18:12:42 +0100
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
deleted file mode 100644
index ffbf412..0000000
--- a/debian/control
+++ /dev/null
@@ -1,46 +0,0 @@
-Source: igraph
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Mathieu Malaterre <malat at debian.org>,
-           Andreas Tille <tille at debian.org>
-Section: libs
-Priority: optional
-Build-Depends: debhelper (>= 9),
-               libtool,
-               libxml2-dev,
-               libgmp-dev,
-               libarpack2-dev,
-               libblas-dev,
-               liblapack-dev,
-               automake,
-               dh-autoreconf,
-               libglpk-dev,
-               libf2c2-dev
-Standards-Version: 3.9.5
-Vcs-Browser: http://anonscm.debian.org/viewvc/debian-med/trunk/packages/igraph/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/igraph/trunk/
-Homepage: http://igraph.org/c/
-
-Package: libigraph0
-Architecture: any
-Depends: ${shlibs:Depends},
-         ${misc:Depends}
-Pre-Depends: ${misc:Pre-Depends}
-Description: library for creating and manipulating graphs
- igraph is a library for creating and manipulating graphs.
- It is intended to be as powerful (ie. fast) as possible to enable the
- analysis of large graphs.
- .
- This is the runtime library package.
-
-Package: libigraph0-dev
-Architecture: any
-Section: libdevel
-Depends: libigraph0 (= ${binary:Version}),
-         ${misc:Depends}
-Provides: libigraph-dev
-Description: library for creating and manipulating graphs - development files
- igraph is a library for creating and manipulating graphs.
- It is intended to be as powerful (ie. fast) as possible to enable the
- analysis of large graphs.
- .
- This package contains the include files and static library for igraph.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 5bd0752..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,17 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: igraph
-Source: https://github.com/igraph/igraph/releases
-
-Files: *
-Copyright:
- Copyright © 2005-2008 Gabor Csardi, Tamas Nepusz
-License: GPL-2+
- The Debian packaging is licensed under the GPL-2 or any later version,
- see `/usr/share/common-licenses/GPL-2'
-
-Files: debian/*
-Copyright:
- Copyright 2009-2012, Mathieu Malaterre <malat at debian.org>
-License: GPL-2+
- The Debian packaging is licensed under the GPL-2 or any later version,
- see `/usr/share/common-licenses/GPL-2'
diff --git a/debian/libigraph-dev.examples b/debian/libigraph-dev.examples
deleted file mode 100644
index 405bf4e..0000000
--- a/debian/libigraph-dev.examples
+++ /dev/null
@@ -1,2 +0,0 @@
-examples/simple/
-
diff --git a/debian/libigraph-dev.info b/debian/libigraph-dev.info
deleted file mode 100644
index 2da6b8c..0000000
--- a/debian/libigraph-dev.info
+++ /dev/null
@@ -1 +0,0 @@
-doc/igraph-docs.info
diff --git a/debian/libigraph.manpages b/debian/libigraph.manpages
deleted file mode 100644
index 8d4d4a4..0000000
--- a/debian/libigraph.manpages
+++ /dev/null
@@ -1 +0,0 @@
-doc/igraph.3
diff --git a/debian/libigraph0-dev.install b/debian/libigraph0-dev.install
deleted file mode 100644
index c5f142f..0000000
--- a/debian/libigraph0-dev.install
+++ /dev/null
@@ -1,3 +0,0 @@
-usr/lib/*/libigraph.so
-usr/include/igraph/*.h
-usr/lib/*/pkgconfig/*.pc
diff --git a/debian/libigraph0.install b/debian/libigraph0.install
deleted file mode 100644
index 2a892c1..0000000
--- a/debian/libigraph0.install
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/*/libigraph.so.*
diff --git a/debian/patches/link_f2c.patch b/debian/patches/link_f2c.patch
deleted file mode 100644
index a1f5e6c..0000000
--- a/debian/patches/link_f2c.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-Last-Changed: Thu, 19 Dec 2013 11:23:31 +0100
-Bug-Debian: http://bugs.debian.org/702882
-Description: Make sure libf2c will be properly linked
-
-
---- a/configure.ac
-+++ b/configure.ac
-@@ -217,7 +217,7 @@ if test "$internal_f2c" = "no"; then
-         AC_CHECK_LIB([f2c], [F77_ALLOC_], [],
-            AC_CHECK_LIB([f2c], [F77_ALLOC], [],
- 	      [AC_MSG_RESULT(not found, trying to use -lf2c anyway.)]))))
--  LDFLAGS="${LDFLAGS}"
-+  LDFLAGS="${LDFLAGS} -lf2c"
- else
-   AC_DEFINE([INTERNAL_F2C], [1], [Define to 1 if you use the internal F2C library])
- fi
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 286f2cb..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-link_f2c.patch
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 6c18edd..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/make -f
-#export DH_VERBOSE=1
-
-%:
-	dh $@ --parallel --with autoreconf
-
-#	--enable-debug
-
-# disable TLS to fix warning with TLS and arpack
-CONF_FLAGS=\
-	--enable-gmp \
-	--disable-tls \
-	--with-external-arpack \
-	--with-external-blas \
-	--with-external-lapack \
-	--with-external-f2c \
-	--with-external-glpk
-
-override_dh_auto_configure:
-	dh_auto_configure -- $(CONF_FLAGS)
-
-get-orig-source:
-	uscan --verbose --force-download --rename
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 2decb01..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,5 +0,0 @@
-version=3
-http://igraph.org/c/ .*/nightly/get/c/igraph-(\d[\d.-]+)\.tar\.gz
-
-# Upstream advises to NOT use Github releases
-# https://github.com/igraph/igraph/releases .*/archive/(\d[\d.-]+)\.(?:tar(?:\.gz|\.bz2)?|tgz)
diff --git a/depcomp b/depcomp
new file mode 100755
index 0000000..4ebd5b3
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+# 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, 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/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva at dcc.unicamp.br>.
+
+case $1 in
+  '')
+    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+    exit 1;
+    ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'.  Note that this directory component will
+# be either empty or ending with a '/' character.  This is deliberate.
+set_dir_from ()
+{
+  case $1 in
+    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+      *) dir=;;
+  esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+  echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+  # If the compiler actually managed to produce a dependency file,
+  # post-process it.
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependency.h'.
+    # Do two passes, one to just change these to
+    #   $object: dependency.h
+    # and one to simply output
+    #   dependency.h:
+    # which is needed to avoid the deleted-header problem.
+    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+    } > "$depfile"
+    rm -f "$tmpdepfile"
+  else
+    make_dummy_depfile
+  fi
+}
+
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+  # This is just like dashmstdout with a different argument.
+  dashmflag=-xM
+  depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+  # This is just like msvisualcpp but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+  # This is just like msvc7 but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+  gccflag=-qmakedep=gcc,-MF
+  depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).  Also, it might not be
+##   supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The second -e expression handles DOS-style file names with drive
+  # letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+      | tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+      >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  set_dir_from "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  aix_post_process_depfile
+  ;;
+
+tcc)
+  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+  # FIXME: That version still under development at the moment of writing.
+  #        Make that this statement remains true also for stable, released
+  #        versions.
+  # It will wrap lines (doesn't matter whether long or short) with a
+  # trailing '\', as in:
+  #
+  #   foo.o : \
+  #    foo.c \
+  #    foo.h \
+  #
+  # It will put a trailing '\' even on the last line, and will use leading
+  # spaces rather than leading tabs (at least since its commit 0394caf7
+  # "Emit spaces for -MD").
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+  # We have to change lines of the first kind to '$object: \'.
+  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+  # And for each line of the second kind, we have to emit a 'dep.h:'
+  # dummy dependency, to avoid the deleted-header problem.
+  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  set_dir_from "$object"
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  set_base_from "$source"
+  tmpdepfile=$base.d
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir=$base.d-lock
+  trap "
+    echo '$0: caught signal, cleaning up...' >&2
+    rmdir '$lockdir'
+    exit 1
+  " 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0; do
+    # mkdir is a portable test-and-set.
+    if mkdir "$lockdir" 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rmdir "$lockdir"
+      break
+    else
+      # If the lock is being held by a different process, wait
+      # until the winning process is done or we timeout.
+      while test -d "$lockdir" && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  set_dir_from  "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+               s/^ *//
+               s/ \\*$//
+               s/$/:/
+               p
+             }' "$tmpdepfile" >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+  # The Tru64 compiler uses -MD to generate dependencies as a side
+  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+  # dependencies in 'foo.d' instead, so we check for that too.
+  # Subdirectories are respected.
+  set_dir_from  "$object"
+  set_base_from "$object"
+
+  if test "$libtool" = yes; then
+    # Libtool generates 2 separate objects for the 2 libraries.  These
+    # two compilations output dependencies in $dir.libs/$base.o.d and
+    # in $dir$base.o.d.  We have to check for both files, because
+    # one of the two compilations can be disabled.  We should prefer
+    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+    # automatically cleaned when .libs/ is deleted, while ignoring
+    # the former would cause a distcleancheck panic.
+    tmpdepfile1=$dir$base.o.d          # libtool 1.5
+    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
+    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
+    "$@" -Wc,-MD
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    tmpdepfile3=$dir$base.d
+    "$@" -MD
+  fi
+
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  # Same post-processing that is required for AIX mode.
+  aix_post_process_depfile
+  ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this sed invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process the last invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed '1,2d' "$tmpdepfile" \
+    | tr ' ' "$nl" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E \
+    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+    | sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+        set fnord "$@"
+        shift
+        shift
+        ;;
+    *)
+        set fnord "$@" "$arg"
+        shift
+        shift
+        ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..f4c5656
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,690 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/tools/autoconf/ax_tls.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOM4TE = @AUTOM4TE@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLOATSTORE = @FLOATSTORE@
+GREP = @GREP@
+HAVE_TLS = @HAVE_TLS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_LIBS_PRIVATE = @PKGCONFIG_LIBS_PRIVATE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WERROR_CFLAGS = @WERROR_CFLAGS@
+XML2CONFIG = @XML2CONFIG@
+XML2_CFLAGS = @XML2_CFLAGS@
+XML2_LIBS = @XML2_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+DOXROX = $(top_srcdir)/doc/doxrox.py
+REGEX = $(top_srcdir)/doc/c-docbook.re
+SRCDIR = $(top_srcdir)/src
+INCLUDEDIR = $(top_srcdir)/include
+BUILD_INCLUDEDIR = $(top_builddir)/include
+REMOVEEXAMPLES = $(top_srcdir)/tools/removeexamples.py
+DOCINCLUDES = vector.xml error.xml matrix.xml basicigraph.xml generators.xml \
+	      structural.xml iterators.xml attributes.xml layout.xml \
+	      foreign.xml nongraph.xml isomorphism.xml motifs.xml \
+	      operators.xml flows.xml community.xml cliques.xml \
+	      sparsematrix.xml stack.xml dqueue.xml heap.xml strvector.xml \
+	      adjlist.xml arpack.xml bipartite.xml visitors.xml random.xml \
+	      separators.xml memory.xml sparsemat.xml hrg.xml \
+	      scg.xml spatialgames.xml threading.xml progress.xml status.xml \
+	      graphlets.xml epi.xml
+
+DOCFIX = fdl.xml gpl.xml installation.xml introduction.xml \
+	 tutorial.xml licenses.xml pmt.xml
+
+DOCFIX2 = $(patsubst %,$(top_srcdir)/doc/%,$(DOCFIX))
+EXAMPLES = $(patsubst $(top_srcdir)/%.c,$(top_builddir)/%.c.xml,$(wildcard $(top_srcdir)/examples/simple/*.c))
+CLEANFILES = $(DOCINCLUDES) html/*.html html/stamp \
+	igraph-docs.{dvi,info,pdf,ps,texi,txml} igraph-docs2.xml 
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu doc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi-am:
+
+html-am:
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf-am:
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags-am uninstall uninstall-am
+
+
+all: doctemplate
+
+html: html/stamp
+
+jekyll: jekyll/stamp
+
+info: igraph.info
+
+dvi: igraph-docs.dvi
+
+pdf: igraph-docs.pdf
+
+ps: igraph-docs.ps
+
+doctemplate: $(DOCINCLUDES)
+
+tags: $(DOCINCLUDES) $(DOCFIX)
+	cat $(DOCINCLUDES) $(DOCFIX)| grep 'id="[^-"]*">' | sed 's/.*id="\([^"]*\)">.*/\1@@/' | tr '@' '\t' | sort > tags
+
+$(top_builddir)/examples/simple/%.c.xml: $(top_srcdir)/examples/simple/%.c tags
+	if [ ! -d "$(top_builddir)/examples/simple" -a "x$(top_srcdir)" != "x$(top_builddir)" ]; then mkdir -p $(top_builddir)/examples/simple; fi
+	source-highlight --src-lang c --out-format docbook --input $< --output $@ --gen-references=inline --ctags="" --outlang-def=$(top_srcdir)/doc/docbook.outlang
+
+igraph-docs.xml: $(DOCINCLUDES) $(EXAMPLES)
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp $(top_srcdir)/doc/igraph-docs.xml . ; fi
+	touch igraph-docs.xml
+
+vector.xml: vector.xxml $(INCLUDEDIR)/igraph_vector_pmt.h $(SRCDIR)/vector.pmt $(SRCDIR)/vector_ptr.c $(SRCDIR)/vector.c $(INCLUDEDIR)/igraph_vector_ptr.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_vector_pmt.h \
+	$(SRCDIR)/vector.pmt $(SRCDIR)/vector_ptr.c $(SRCDIR)/vector.c \
+	$(INCLUDEDIR)/igraph_vector_ptr.h
+
+error.xml: error.xxml $(INCLUDEDIR)/igraph_error.h $(SRCDIR)/igraph_error.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_error.h $(SRCDIR)/igraph_error.c
+
+matrix.xml: matrix.xxml $(INCLUDEDIR)/igraph_matrix.h $(SRCDIR)/matrix.pmt
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_matrix.h $(SRCDIR)/matrix.pmt
+
+sparsematrix.xml: sparsematrix.xxml $(INCLUDEDIR)/igraph_spmatrix.h $(SRCDIR)/spmatrix.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_spmatrix.h $(SRCDIR)/spmatrix.c
+
+sparsemat.xml: sparsemat.xxml $(SRCDIR)/sparsemat.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/sparsemat.c
+
+hrg.xml: hrg.xxml $(SRCDIR)/igraph_hrg.cc $(INCLUDEDIR)/igraph_hrg.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/igraph_hrg.cc $(INCLUDEDIR)/igraph_hrg.h
+
+scg.xml: scg.xxml $(SRCDIR)/scg.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/scg.c
+
+basicigraph.xml: basicigraph.xxml $(SRCDIR)/type_indexededgelist.c $(SRCDIR)/structural_properties.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/type_indexededgelist.c $(SRCDIR)/structural_properties.c
+
+generators.xml: generators.xxml \
+		$(SRCDIR)/atlas.c \
+		$(SRCDIR)/forestfire.c \
+		$(SRCDIR)/games.c \
+		$(SRCDIR)/structure_generators.c \
+		$(SRCDIR)/structural_properties.c \
+		$(SRCDIR)/sbm.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ \
+	$(SRCDIR)/atlas.c \
+	$(SRCDIR)/forestfire.c \
+	$(SRCDIR)/games.c \
+	$(SRCDIR)/structure_generators.c \
+	$(SRCDIR)/structural_properties.c \
+	$(SRCDIR)/sbm.c
+
+structural.xml: structural.xxml $(SRCDIR)/structural_properties.c \
+		$(SRCDIR)/spanning_trees.c \
+		$(SRCDIR)/conversion.c $(SRCDIR)/basic_query.c \
+		$(SRCDIR)/cocitation.c $(SRCDIR)/components.c \
+		$(SRCDIR)/spectral_properties.c $(SRCDIR)/cores.c \
+		$(SRCDIR)/centrality.c $(SRCDIR)/decomposition.c \
+		$(SRCDIR)/mixing.c $(INCLUDEDIR)/igraph_arpack.h \
+		$(SRCDIR)/distances.c $(SRCDIR)/feedback_arc_set.c \
+		$(SRCDIR)/matching.c $(SRCDIR)/triangles.c \
+		$(INCLUDEDIR)/igraph_centrality.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ \
+	$(SRCDIR)/structural_properties.c $(SRCDIR)/spanning_trees.c \
+	$(SRCDIR)/conversion.c $(SRCDIR)/basic_query.c $(SRCDIR)/cocitation.c \
+	$(SRCDIR)/components.c $(SRCDIR)/spectral_properties.c $(SRCDIR)/cores.c \
+	$(SRCDIR)/centrality.c $(SRCDIR)/decomposition.c $(SRCDIR)/mixing.c \
+	$(INCLUDEDIR)/igraph_arpack.h  $(SRCDIR)/distances.c \
+	$(SRCDIR)/feedback_arc_set.c $(SRCDIR)/matching.c $(SRCDIR)/triangles.c \
+	$(INCLUDEDIR)/igraph_centrality.h
+
+iterators.xml: iterators.xxml $(SRCDIR)/iterators.c $(INCLUDEDIR)/igraph_iterators.h
+	$(DOXROX) -c -t $< -e $(REGEX) -o $@ $(SRCDIR)/iterators.c \
+	$(INCLUDEDIR)/igraph_iterators.h
+
+attributes.xml: attributes.xxml $(SRCDIR)/attributes.c $(INCLUDEDIR)/igraph_attributes.h $(SRCDIR)/cattributes.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/attributes.c \
+	$(INCLUDEDIR)/igraph_attributes.h $(SRCDIR)/cattributes.c
+
+layout.xml: layout.xxml $(SRCDIR)/layout.c $(INCLUDEDIR)/igraph_layout.h $(SRCDIR)/drl_layout.cpp $(SRCDIR)/drl_layout_3d.cpp $(SRCDIR)/sugiyama.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/layout.c $(INCLUDEDIR)/igraph_layout.h $(SRCDIR)/drl_layout.cpp $(SRCDIR)/drl_layout_3d.cpp $(SRCDIR)/sugiyama.c
+
+foreign.xml: foreign.xxml $(SRCDIR)/foreign.c $(SRCDIR)/foreign-graphml.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/foreign.c \
+	$(SRCDIR)/foreign-graphml.c
+
+nongraph.xml: nongraph.xxml $(SRCDIR)/other.c $(SRCDIR)/random.c $(SRCDIR)/version.c $(INCLUDEDIR)/igraph_nongraph.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_nongraph.h $(SRCDIR)/other.c $(SRCDIR)/random.c $(SRCDIR)/version.c
+
+isomorphism.xml: isomorphism.xxml $(SRCDIR)/topology.c $(INCLUDEDIR)/igraph_topology.h $(SRCDIR)/bliss.cc $(SRCDIR)/lad.c
+	$(DOXROX) -c -t $< -e $(REGEX) -o $@ $(SRCDIR)/topology.c $(INCLUDEDIR)/igraph_topology.h $(SRCDIR)/bliss.cc $(SRCDIR)/lad.c
+
+motifs.xml: motifs.xxml $(INCLUDEDIR)/igraph_motifs.h $(SRCDIR)/motifs.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_motifs.h $(SRCDIR)/motifs.c
+
+operators.xml: operators.xxml $(SRCDIR)/operators.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/operators.c
+
+flows.xml: flows.xxml $(SRCDIR)/flow.c $(SRCDIR)/st-cuts.c $(SRCDIR)/cohesive_blocks.c $(INCLUDEDIR)/igraph_flow.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/flow.c $(SRCDIR)/st-cuts.c $(SRCDIR)/cohesive_blocks.c $(INCLUDEDIR)/igraph_flow.h
+
+community.xml: community.xxml $(SRCDIR)/community.c $(SRCDIR)/clustertool.cpp $(SRCDIR)/walktrap.cpp $(SRCDIR)/fast_community.c $(SRCDIR)/optimal_modularity.c $(INCLUDEDIR)/igraph_community.h $(SRCDIR)/infomap.cc
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/community.c $(SRCDIR)/clustertool.cpp $(SRCDIR)/walktrap.cpp $(SRCDIR)/fast_community.c $(SRCDIR)/optimal_modularity.c $(INCLUDEDIR)/igraph_community.h $(SRCDIR)/infomap.cc
+
+cliques.xml: cliques.xxml $(SRCDIR)/cliques.c $(SRCDIR)/maximal_cliques.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/cliques.c $(SRCDIR)/maximal_cliques.c
+
+stack.xml: stack.xxml $(SRCDIR)/stack.pmt
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/stack.pmt
+
+dqueue.xml: dqueue.xxml $(SRCDIR)/dqueue.pmt
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/dqueue.pmt
+
+heap.xml: heap.xxml $(SRCDIR)/heap.pmt
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/heap.pmt
+
+strvector.xml: strvector.xxml $(SRCDIR)/igraph_strvector.c $(INCLUDEDIR)/igraph_strvector.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/igraph_strvector.c $(INCLUDEDIR)/igraph_strvector.h
+
+adjlist.xml: adjlist.xxml $(SRCDIR)/adjlist.c $(INCLUDEDIR)/igraph_adjlist.h
+	$(DOXROX) -c -t $< -e $(REGEX) -o $@ $(SRCDIR)/adjlist.c $(INCLUDEDIR)/igraph_adjlist.h
+
+arpack.xml: arpack.xxml $(INCLUDEDIR)/igraph_arpack.h $(SRCDIR)/arpack.c $(INCLUDEDIR)/igraph_blas.h $(SRCDIR)/blas.c $(INCLUDEDIR)/igraph_lapack.h $(SRCDIR)/lapack.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_arpack.h $(SRCDIR)/arpack.c $(INCLUDEDIR)/igraph_blas.h $(SRCDIR)/blas.c $(INCLUDEDIR)/igraph_lapack.h $(SRCDIR)/lapack.c
+
+bipartite.xml: bipartite.xxml $(SRCDIR)/bipartite.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/bipartite.c
+
+visitors.xml: visitors.xxml $(SRCDIR)/visitors.c  $(INCLUDEDIR)/igraph_visitor.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/visitors.c  $(INCLUDEDIR)/igraph_visitor.h
+
+random.xml: random.xxml $(SRCDIR)/random.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/random.c
+
+separators.xml: separators.xxml $(SRCDIR)/separators.c $(SRCDIR)/st-cuts.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/separators.c \
+		$(SRCDIR)/st-cuts.c
+
+memory.xml: memory.xxml $(SRCDIR)/memory.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/memory.c
+
+spatialgames.xml: spatialgames.xxml \
+		   $(SRCDIR)/microscopic_update.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ \
+	$(SRCDIR)/microscopic_update.c
+
+threading.xml: threading.xxml $(BUILD_INCLUDEDIR)/igraph_threading.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(BUILD_INCLUDEDIR)/igraph_threading.h
+
+progress.xml: progress.xxml $(INCLUDEDIR)/igraph_progress.h $(SRCDIR)/progress.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_progress.h $(SRCDIR)/progress.c
+
+status.xml: status.xxml $(INCLUDEDIR)/igraph_statusbar.h $(SRCDIR)/statusbar.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(INCLUDEDIR)/igraph_statusbar.h $(SRCDIR)/statusbar.c
+
+graphlets.xml: graphlets.xxml $(SRCDIR)/glet.c
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/glet.c
+
+epi.xml: epi.xxml $(SRCDIR)/sir.c $(INCLUDEDIR)/igraph_epidemics.h
+	$(DOXROX) -t $< -e $(REGEX) -o $@ $(SRCDIR)/sir.c \
+		$(INCLUDEDIR)/igraph_epidemics.h
+
+html/stamp: igraph-docs.xml $(DOCFIX2) gtk-doc.xsl
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp $(DOCFIX2) . ; fi && \
+	xmlto -x $(top_srcdir)/doc/gtk-doc.xsl -o html xhtml igraph-docs.xml \
+	&& touch html/stamp
+
+jekyll/stamp: html/stamp
+	rm -rf jekyll && mkdir jekyll && cp html/* jekyll/ && rm jekyll/stamp
+	cd html && for i in *.html; do                        \
+	  cat $$i | ../../tools/extract_body.sh               \
+		  | ../../tools/protect_braces.sh             \
+		  | ../../tools/jekyll_header.sh              \
+                  > ../jekyll/$$i; done
+	touch jekyll/stamp
+
+igraph.info: igraph-docs.xml $(DOCFIX2) igraph.info.diff
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp $(DOCFIX2) . ; fi && \
+	cat tutorial.xml | sed '/<link/{N;s/<link\n*[^>]*>//g;}' | \
+	  sed 's/<\/link>//g' >tutorial-info.xml \
+	&& sed 's/tutorial\.xml/tutorial-info.xml/' igraph-docs.xml > igraph-docs-info.xml \
+	&& xmllint --xinclude -o igraph-docs-info2.xml igraph-docs-info.xml \
+	&& $(REMOVEEXAMPLES) igraph-docs-info2.xml igraph-docs-info3.xml \
+	&& sed '/<book/q' igraph-docs-info2.xml | grep -v '<book' >igraph-docs-info4.xml\
+	&& cat igraph-docs-info3.xml >> igraph-docs-info4.xml \
+	&& db2x_xsltproc --xinclude -s texi igraph-docs-info4.xml -o igraph.txml \
+	&& db2x_texixml igraph.txml \
+	&& mv igraph_reference_manual.texi igraph.texi \
+	&& makeinfo --no-split --number-sections igraph.texi \
+	&& mv igraph_reference_manual.info igraph.info \
+	&& patch <$(top_srcdir)/doc/igraph.info.diff
+
+igraph-docs.dvi: igraph-docs.xml $(DOCFIX2)
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp $(DOCFIX2) . ; fi && \
+	xmllint --xinclude -o igraph-docs2.xml igraph-docs.xml \
+	&& $(REMOVEEXAMPLES) igraph-docs2.xml igraph-docs3.xml \
+	&& sed '/<book/q' igraph-docs2.xml | grep -v '<book' >igraph-docs4.xml\
+	&& cat igraph-docs3.xml >> igraph-docs4.xml \
+	&& env < /dev/null hash_extra=650000 docbook2dvi igraph-docs4.xml \
+	&& mv igraph-docs4.dvi igraph-docs.dvi
+
+igraph-docs.ps: igraph-docs.xml $(DOCFIX2)
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp $(DOCFIX2) . ; fi && \
+	xmllint --xinclude -o igraph-docs2.xml igraph-docs.xml \
+	&& $(REMOVEEXAMPLES) igraph-docs2.xml igraph-docs3.xml \
+	&& sed '/<book/q' igraph-docs2.xml | grep -v '<book' >igraph-docs4.xml\
+	&& cat igraph-docs3.xml >> igraph-docs4.xml \
+	&& env < /dev/null hash_extra=65000 docbook2s igraph-docs4.xml \
+	&& mv igraph-docs4.ps igraph-docs.ps
+
+igraph-docs.pdf: igraph-docs.xml $(DOCFIX2)
+	if [ "x$(top_srcdir)" != "x$(top_builddir)" ]; then cp $(DOCFIX2) . ; fi && \
+	xmllint --xinclude -o igraph-docs2.xml igraph-docs.xml \
+	&& $(REMOVEEXAMPLES) igraph-docs2.xml igraph-docs3.xml \
+	&& sed '/<book/q' igraph-docs2.xml | grep -v '<book' >igraph-docs4.xml\
+	&& cat igraph-docs3.xml >> igraph-docs4.xml \
+	&& xsltproc http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl \
+	   igraph-docs4.xml > igraph-docs.fo \
+	&& fop -fo igraph-docs.fo -pdf igraph-docs.pdf
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/igraph.3 b/doc/igraph.3
new file mode 100644
index 0000000..f3f01f8
--- /dev/null
+++ b/doc/igraph.3
@@ -0,0 +1,46 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\"
+.\" Copyright (C) 2006-2012  Tamas Nepusz <ntamas at gmail.com>
+.\" Pázmány Péter sétány 1/a, 1117 Budapest, Hungary
+.\"
+.\" This 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, or (at your option) any later
+.\" version.
+.\" 
+.\" This 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 with
+.\" your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with
+.\" the dpkg source package as the file COPYING.  If not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.TH IGRAPH 3 "March 2007" "igraph library"
+.SH NAME
+igraph \- a library for creating and manipulating graphs
+.SH DESCRIPTION
+.B igraph
+is a library for creating and manipulating graphs.
+It is intended to be as powerful (ie. fast) as possible to enable the
+analysis of large graphs.
+.SH DOCUMENTATION
+The full documentation can be downloaded from the homepage of the
+library:
+.RI < http://igraph.org >
+.PP
+You might also try the info pages of igraph if they are installed:
+
+info igraph-docs
+
+.SH BUGS
+If you think you have found a bug in igraph, feel free to use the
+mailing list at
+.B igraph-help at nongnu.org.
+
+.SH AUTHORS
+Gabor Csardi <csardi.gabor at gmail.com>,
+.br
+Tamas Nepusz <ntamas at gmail.com>
diff --git a/examples/benchmarks/bench.h b/examples/benchmarks/bench.h
new file mode 100644
index 0000000..889c6ab
--- /dev/null
+++ b/examples/benchmarks/bench.h
@@ -0,0 +1,53 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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_BENCH_H
+#define IGRAPH_BENCH_H
+
+inline void igraph_get_cpu_time(igraph_real_t *data) {
+
+	struct rusage self, children;
+	getrusage(RUSAGE_SELF, &self);
+	getrusage(RUSAGE_CHILDREN, &children);
+	data[0] = (double) self.ru_utime.tv_sec +	
+		1e-3 * (self.ru_utime.tv_usec/1000);
+	data[1] = (double) self.ru_stime.tv_sec +
+		1e-3 * (self.ru_stime.tv_usec/1000);
+	data[2] = (double) children.ru_utime.tv_sec +
+		1e-3 * (children.ru_utime.tv_usec/1000);
+	data[3] = (double) children.ru_stime.tv_sec +
+		1e-3 * (children.ru_stime.tv_usec/1000);
+}
+
+#define BENCH(NAME, ...)	do {														 \
+	double start[4], stop[4];																 \
+	igraph_get_cpu_time(start);															 \
+	{ __VA_ARGS__; };																				 \
+	igraph_get_cpu_time(stop);															 \
+	printf("%s %.3gs\n", NAME,															 \
+				 stop[0]+stop[1]+stop[2]+stop[3] -								 \
+				 start[0]-start[1]-start[2]-start[3]);						 \
+	} while (0)
+
+#endif
+
diff --git a/examples/benchmarks/igraph_maximal_cliques.c b/examples/benchmarks/igraph_maximal_cliques.c
new file mode 100644
index 0000000..985587f
--- /dev/null
+++ b/examples/benchmarks/igraph_maximal_cliques.c
@@ -0,0 +1,61 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include "bench.h"
+
+int main() {
+
+  igraph_t g;
+  igraph_real_t toremovev[] = {  2609,  2098, 14517,  7540, 19560,  8855, 
+			         5939, 14947,   441, 16976, 19642,  4188, 
+			        15447, 11837,  2333,  7309, 18539, 14099,
+			        14264,  9240 };
+  igraph_vector_t toremove;
+  igraph_vector_ptr_t res;
+  int i, n;
+
+  igraph_vector_view(&toremove, toremovev, 
+		     sizeof(toremovev) / sizeof(igraph_real_t));
+  igraph_full(&g, 200, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  igraph_delete_edges(&g, igraph_ess_vector(&toremove));
+
+  igraph_vector_ptr_init(&res, 0);
+
+  BENCH("1 Maximal cliques of almost complete graph", 
+	igraph_maximal_cliques(&g, &res, /* min_size= */ 0,
+			       /* max_size= */ 0);
+	);
+
+  igraph_destroy(&g);
+  n=igraph_vector_ptr_size(&res);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(res)[i];
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+  igraph_vector_ptr_destroy(&res);
+  
+  return 0; 
+}
diff --git a/examples/benchmarks/igraph_transitivity.c b/examples/benchmarks/igraph_transitivity.c
new file mode 100644
index 0000000..1c0e12f
--- /dev/null
+++ b/examples/benchmarks/igraph_transitivity.c
@@ -0,0 +1,59 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include "bench.h"
+
+#define N 6000
+#define M 2000000
+
+int main() {
+
+	igraph_t g;
+	igraph_vector_t trans;
+
+	igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, N, M,
+													IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+	igraph_vector_init(&trans, igraph_vcount(&g));	
+
+	BENCH("1 Transitivity GNM   ",
+				igraph_transitivity_local_undirected(&g, &trans, igraph_vss_all(),
+																						 IGRAPH_TRANSITIVITY_NAN);
+				);
+
+	igraph_destroy(&g);
+	igraph_barabasi_game(&g, N, /*power=*/ 1, M/N, /*outseq=*/ 0, 
+											 /*outpref=*/ 0, /*A=*/ 1, IGRAPH_UNDIRECTED, 
+											 IGRAPH_BARABASI_PSUMTREE, /*start_from=*/ 0);
+
+	BENCH("2 Transitivity Skewed",
+				igraph_transitivity_local_undirected(&g, &trans, igraph_vss_all(),
+																						 IGRAPH_TRANSITIVITY_NAN);
+				);
+	
+	igraph_destroy(&g);
+	igraph_vector_destroy(&trans);
+
+	return 0;
+}
diff --git a/examples/simple/2wheap.c b/examples/simple/2wheap.c
new file mode 100644
index 0000000..e9bbc52
--- /dev/null
+++ b/examples/simple/2wheap.c
@@ -0,0 +1,142 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+#include <igraph_types_internal.h>
+#include <time.h>
+#include <stdlib.h>
+
+int main() {
+  
+  igraph_vector_t elems;
+  igraph_2wheap_t Q;
+  long int i;
+  igraph_real_t prev=IGRAPH_INFINITY;
+
+  srand(time(0));
+  
+  igraph_vector_init(&elems, 100);
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    VECTOR(elems)[i] = rand()/(double)RAND_MAX;
+  }
+ 
+  igraph_2wheap_init(&Q, igraph_vector_size(&elems));
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    igraph_2wheap_push_with_index(&Q, i, VECTOR(elems)[i]);
+  }
+
+  /*****/
+
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    if (VECTOR(elems)[i] != igraph_2wheap_get(&Q, i)) { return 1; }
+  }
+
+  /*****/
+  
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    long int j;
+    igraph_real_t tmp=igraph_2wheap_max(&Q);
+    if (tmp > prev) { return 2; }
+    if (tmp != igraph_2wheap_delete_max_index(&Q, &j)) { return 3; }
+    if (VECTOR(elems)[j] != tmp) { return 4; }
+    prev=tmp;
+  }
+
+  /*****/
+
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    igraph_2wheap_push_with_index(&Q, i, VECTOR(elems)[i]);
+  }
+  if (igraph_2wheap_size(&Q) != igraph_vector_size(&elems)) { return 5; }
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    VECTOR(elems)[i] = rand()/(double)RAND_MAX;
+    igraph_2wheap_modify(&Q, i, VECTOR(elems)[i]);
+  }
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    if (VECTOR(elems)[i] != igraph_2wheap_get(&Q, i)) { return 6; }
+  }
+  prev=IGRAPH_INFINITY;
+  for (i=0; i<igraph_vector_size(&elems); i++) {
+    long int j;
+    igraph_real_t tmp=igraph_2wheap_max(&Q);
+    if (tmp > prev) { return 7; }
+    if (tmp != igraph_2wheap_delete_max_index(&Q, &j)) { return 8; }
+    if (VECTOR(elems)[j] != tmp) { return 9; }
+    prev=tmp;
+  }
+  if (!igraph_2wheap_empty(&Q)) { return 10; }
+  if (igraph_2wheap_size(&Q) != 0) { return 11; }
+  
+  igraph_2wheap_destroy(&Q);
+  igraph_vector_destroy(&elems);
+
+  /* Hand-made example */
+    
+#define MAX       do { igraph_2wheap_delete_max(&Q); igraph_2wheap_check(&Q); } while (0)
+#define PUSH(i,e) do { igraph_2wheap_push_with_index(&Q, (i), -(e)); igraph_2wheap_check(&Q); } while (0);
+#define MOD(i, e) do { igraph_2wheap_modify(&Q, (i), -(e)); igraph_2wheap_check(&Q); } while (0)
+
+  igraph_2wheap_init(&Q, 21);
+  /* 0.00 [ 4] */ PUSH(4, 0);
+  /* MAX       */ MAX;
+  /* 0.63 [11] */ PUSH(11, 0.63);
+  /* 0.05 [15] */ PUSH(15, 0.05);
+  /* MAX       */ MAX;
+  /* 0.4  [12] */ PUSH(12, 0.4);
+  /* 0.4  [13] */ PUSH(13, 0.4);
+  /* 0.12 [16] */ PUSH(16, 0.12);
+  /* MAX       */ MAX;
+  /* 1.1  [ 0] */ PUSH(0, 1.1);
+  /* 1.1  [14] */ PUSH(14, 1.1);
+  /* MAX       */ MAX;
+  /* [11]/0.44 */ MOD(11, 0.44);
+  /* MAX       */ MAX;
+  /* MAX       */ MAX;
+  /* 1.1  [20] */ PUSH(20, 1.1);
+  /* MAX       */ MAX;
+  /* 1.3  [ 7] */ PUSH(7, 1.3);
+  /* 1.7  [ 9] */ PUSH(9, 1.7);
+  /* MAX       */ MAX;
+  /* 1.6  [19] */ PUSH(19, 1.6);
+  /* MAX       */ MAX;
+  /* 2.1  [17] */ PUSH(17, 2.1);
+  /* 1.3  [18] */ PUSH(18, 1.3);
+  /* MAX       */ MAX;
+  /* 2.3  [ 1] */ PUSH(1, 2.3);
+  /* 2.2  [ 5] */ PUSH(5, 2.2);
+  /* 2.3  [10] */ PUSH(10, 2.3);
+  /* MAX       */ MAX;
+  /* [17]/1.5  */ MOD(17, 1.5);
+  /* MAX       */ MAX;
+  /* 1.8  [ 6] */ PUSH(6, 1.8);
+  /* MAX       */ MAX;
+  /* 1.3  [ 3] */ PUSH(3, 1.3);
+  /* [ 6]/1.3  */ MOD(6, 1.3);
+  /* MAX       */ MAX;
+  /* 1.6  [ 8] */ PUSH(8, 1.6);
+  /* MAX       */ MAX;
+
+  igraph_2wheap_destroy(&Q);
+  
+  return 0;
+}
diff --git a/examples/simple/LINKS.NET b/examples/simple/LINKS.NET
new file mode 100644
index 0000000..e9e2b14
--- /dev/null
+++ b/examples/simple/LINKS.NET
@@ -0,0 +1,15 @@
+*Network TRALALA
+*vertices 4
+   1 "1"                                           0.0938 0.0896   ellipse x_fact 1 y_fact 1
+   2 "2"                                           0.8188 0.2458   ellipse x_fact 1 y_fact 1
+   3 "3"                                           0.3688 0.7792   ellipse x_fact 1
+   4 "4"                                           0.9583 0.8563   ellipse x_fact 1
+*arcs
+1 1 1  h2 0 w 3 c Blue s 3 a1 -130 k1 0.6 a2 -130 k2 0.6 ap 0.5 l "Bezier loop" lc BlueViolet fos 20 lr 58 lp 0.3 la 360
+2 1 1  h2 0 a1 120 k1 1.3 a2 -120 k2 0.3 ap 25 l "Bezier arc" lphi 270 la 180 lr 19 lp 0.5
+1 2 1  h2 0 a1 40 k1 2.8 a2 30 k2 0.8 ap 25 l "Bezier arc" lphi 90 la 0 lp 0.65
+4 2 -1  h2 0 w 1 k1 -2 k2 250 ap 25 l "Circular arc" c Red lc OrangeRed
+3 4 1  p Dashed h2 0 w 2 c OliveGreen ap 25 l "Straight arc" lc PineGreen
+1 3 1  p Dashed h2 0 w 5 k1 -1 k2 -20 ap 25 l "Oval arc" c Brown lc Black
+3 3 -1  h1 6 w 1 h2 12 k1 -2 k2 -15 ap 0.5 l "Circular loop" c Red lc OrangeRed lphi 270 la 180
+
diff --git a/examples/simple/VF2-compat.c b/examples/simple/VF2-compat.c
new file mode 100644
index 0000000..af42275
--- /dev/null
+++ b/examples/simple/VF2-compat.c
@@ -0,0 +1,206 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+#include <stdlib.h>
+
+/* ----------------------------------------------------------- */
+
+/* Vertices/edges with the same parity match */
+igraph_bool_t compat_parity(const igraph_t *graph1, 
+			    const igraph_t *graph2,
+			    const igraph_integer_t g1_num,
+			    const igraph_integer_t g2_num,
+			    void *arg) {
+  return (g1_num % 2) == (g2_num %2);
+}
+
+/* Nothing vertex/edge 0 in graph1 */
+igraph_bool_t compat_not0(const igraph_t *graph1, 
+			  const igraph_t *graph2,
+			  const igraph_integer_t g1_num,
+			  const igraph_integer_t g2_num,
+			  void *arg) {
+  return g1_num != 0;
+}
+
+int match_rings() {
+
+  igraph_t r1, r2;
+  igraph_bool_t iso;
+  igraph_integer_t count;
+  igraph_ring(&r1, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_ring(&r2, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+
+  igraph_isomorphic_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+			&iso, /*map12=*/ 0, /*map21=*/ 0, 
+			/*node_compat_fn=*/ 0, /*edge_compat_fn=*/ 0, 
+			/*arg=*/ 0);
+  if (!iso) { exit(1); }
+
+  igraph_isomorphic_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+			&iso, /*map12=*/ 0, /*map21=*/ 0, 
+			compat_parity, /*edge_compat_fn=*/ 0, /*arg=*/ 0);
+  if (!iso) { exit(2); }  
+
+  igraph_isomorphic_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+  			&iso, /*map12=*/ 0, /*map21=*/ 0,
+  			compat_not0, /*edge_compat_fn=*/ 0, /*arg=*/ 0);
+  if (iso) { exit(3); }
+
+  /* ------- */
+
+  igraph_isomorphic_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+			&iso, /*map12=*/ 0, /*map21=*/ 0, 
+			/*node_compat_fn=*/ 0, compat_parity, /*arg=*/ 0);
+  if (!iso) { exit(4); }  
+
+  igraph_isomorphic_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+			&iso, /*map12=*/ 0, /*map21=*/ 0, 
+			/*node_compat_fn=*/ 0, compat_not0, /*arg=*/ 0);
+  if (iso) { exit(5); }  
+
+  /* ------- */
+
+  igraph_count_isomorphisms_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+				&count, /*node_compat_fn=*/ 0, 
+				/*edge_compat_fn=*/ 0, /*arg=*/ 0);
+  
+  if (count != 20) { exit(6); }
+
+  igraph_count_isomorphisms_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+				&count, compat_parity, /*edge_compat_fn=*/ 0,
+				/*arg=*/ 0);
+
+  if (count != 10) { exit(7); }
+
+  igraph_count_isomorphisms_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+				&count, compat_not0, /*edge_compat_fn=*/ 0,
+				/*arg=*/ 0);
+
+  if (count != 0) { exit(8); }  
+
+  /* ------- */ 
+
+  igraph_count_isomorphisms_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+				&count, /*node_compat_fn=*/ 0, compat_parity,
+				/*arg=*/ 0);
+
+  if (count != 10) { exit(9); }
+
+  igraph_count_isomorphisms_vf2(&r1, &r2, /*colors(4x)*/ 0, 0, 0, 0,
+				&count, /*node_compat_fn=*/ 0, compat_not0,
+				/*arg=*/ 0);
+
+  if (count != 0) { exit(10); }    
+
+  igraph_destroy(&r1);
+  igraph_destroy(&r2);
+  return 0;
+}
+
+int match_rings_open_closed() {
+  igraph_t ro, rc;
+  igraph_bool_t iso;
+  igraph_integer_t count;
+  igraph_ring(&ro, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 0);
+  igraph_ring(&rc, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);  
+
+  igraph_subisomorphic_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+			   &iso, /*map12=*/ 0, /*map21=*/ 0, 
+			   /*node_compat_fn=*/ 0, /*edge_compat_fn=*/ 0, 
+			   /*arg=*/ 0);
+  if (!iso) { exit(31); }
+
+  igraph_subisomorphic_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+			   &iso, /*map12=*/ 0, /*map21=*/ 0, 
+			   compat_parity, /*edge_compat_fn=*/ 0, 
+			   /*arg=*/ 0);
+  if (!iso) { exit(32); }
+
+  igraph_subisomorphic_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+			   &iso, /*map12=*/ 0, /*map21=*/ 0, 
+			   compat_not0, /*edge_compat_fn=*/ 0, 
+			   /*arg=*/ 0);
+  if (iso) { exit(33); }
+  
+  /* ------- */ 
+
+  igraph_subisomorphic_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+			   &iso, /*map12=*/ 0, /*map21=*/ 0, 
+			   /*node_compat_fn=*/ 0, compat_parity,
+			   /*arg=*/ 0);
+  if (!iso) { exit(34); }
+
+  igraph_subisomorphic_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+			   &iso, /*map12=*/ 0, /*map21=*/ 0, 
+			   /*node_compat_fn=*/ 0, compat_not0,
+			   /*arg=*/ 0);
+  if (!iso) { exit(35); }  
+
+  /* ------- */
+
+  igraph_count_subisomorphisms_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+  				   &count, /*node_compat_fn=*/ 0,
+  				   /*edge_compat_fn=*/ 0, /*arg=*/ 0);
+  
+  if (count != 20) { exit(36); }
+
+  igraph_count_subisomorphisms_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+  				   &count, compat_parity,
+  				   /*edge_compat_fn=*/ 0, /*arg=*/ 0);
+
+  if (count != 10) { exit(37); }
+
+  igraph_count_subisomorphisms_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+  				   &count, compat_not0, /*edge_compat_fn=*/ 0,
+  				   /*arg=*/ 0);
+
+  if (count != 0) { exit(38); }
+
+  /* ------- */ 
+
+  igraph_count_subisomorphisms_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+				   &count, /*node_compat_fn=*/ 0, 
+				   compat_parity, /*arg=*/ 0);
+  
+  if (count != 10) { exit(39); }
+
+  igraph_count_subisomorphisms_vf2(&rc, &ro, /*colors(4x)*/ 0, 0, 0, 0,
+				   &count, /*node_compat_fn=*/ 0, compat_not0,
+				   /*arg=*/ 0);
+
+  if (count != 2) { exit(40); }
+
+  igraph_destroy(&ro);
+  igraph_destroy(&rc);
+  return 0;  
+}
+
+/* ----------------------------------------------------------- */
+
+int main() {
+  match_rings();
+  match_rings_open_closed();
+  return 0;
+}
diff --git a/examples/simple/adjlist.c b/examples/simple/adjlist.c
new file mode 100644
index 0000000..0bc6ee9
--- /dev/null
+++ b/examples/simple/adjlist.c
@@ -0,0 +1,64 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+
+int main() {
+
+  igraph_t g, g2;
+  igraph_adjlist_t adjlist;
+  igraph_bool_t iso;
+  
+  /* Directed, out */
+  igraph_tree(&g, 42, 3, IGRAPH_TREE_OUT);
+  igraph_adjlist_init(&g, &adjlist, IGRAPH_OUT);
+  igraph_adjlist(&g2, &adjlist, IGRAPH_OUT, /*duplicate=*/ 0);
+  igraph_isomorphic_bliss(&g, &g2, &iso, 0, 0, IGRAPH_BLISS_F, IGRAPH_BLISS_F, 0, 0);
+  if (!iso) { return 1; }
+  igraph_adjlist_destroy(&adjlist);
+  igraph_destroy(&g2);
+  igraph_destroy(&g);
+
+  /* Directed, in */
+  igraph_tree(&g, 42, 3, IGRAPH_TREE_OUT);
+  igraph_adjlist_init(&g, &adjlist, IGRAPH_IN);
+  igraph_adjlist(&g2, &adjlist, IGRAPH_IN, /*duplicate=*/ 0);
+  igraph_isomorphic_bliss(&g, &g2, &iso, 0, 0, IGRAPH_BLISS_F, IGRAPH_BLISS_F, 0, 0);
+  if (!iso) { return 1; }
+  igraph_adjlist_destroy(&adjlist);
+  igraph_destroy(&g2);
+  igraph_destroy(&g);
+
+  /* Undirected */
+  igraph_tree(&g, 42, 3, IGRAPH_TREE_UNDIRECTED);
+  igraph_adjlist_init(&g, &adjlist, IGRAPH_OUT);
+  igraph_adjlist(&g2, &adjlist, IGRAPH_ALL, /*duplicate=*/ 1);
+  igraph_isomorphic_bliss(&g, &g2, &iso, 0, 0, IGRAPH_BLISS_F, IGRAPH_BLISS_F, 0, 0);
+  if (!iso) { return 1; }
+  igraph_adjlist_destroy(&adjlist);
+  igraph_destroy(&g2);
+  igraph_destroy(&g);
+			  
+  return 0;
+}
+
diff --git a/examples/simple/ak-4102.max b/examples/simple/ak-4102.max
new file mode 100644
index 0000000..0ff4ab6
--- /dev/null
+++ b/examples/simple/ak-4102.max
@@ -0,0 +1,24623 @@
+c very bad maxflow problem
+p max 16414 24619
+n 1 s
+n 2 t
+a 3 4 4103
+a 3 4106 1
+a 4 5 4102
+a 4 4106 1
+a 5 6 4101
+a 5 4106 1
+a 6 7 4100
+a 6 4106 1
+a 7 8 4099
+a 7 4106 1
+a 8 9 4098
+a 8 4106 1
+a 9 10 4097
+a 9 4106 1
+a 10 11 4096
+a 10 4106 1
+a 11 12 4095
+a 11 4106 1
+a 12 13 4094
+a 12 4106 1
+a 13 14 4093
+a 13 4106 1
+a 14 15 4092
+a 14 4106 1
+a 15 16 4091
+a 15 4106 1
+a 16 17 4090
+a 16 4106 1
+a 17 18 4089
+a 17 4106 1
+a 18 19 4088
+a 18 4106 1
+a 19 20 4087
+a 19 4106 1
+a 20 21 4086
+a 20 4106 1
+a 21 22 4085
+a 21 4106 1
+a 22 23 4084
+a 22 4106 1
+a 23 24 4083
+a 23 4106 1
+a 24 25 4082
+a 24 4106 1
+a 25 26 4081
+a 25 4106 1
+a 26 27 4080
+a 26 4106 1
+a 27 28 4079
+a 27 4106 1
+a 28 29 4078
+a 28 4106 1
+a 29 30 4077
+a 29 4106 1
+a 30 31 4076
+a 30 4106 1
+a 31 32 4075
+a 31 4106 1
+a 32 33 4074
+a 32 4106 1
+a 33 34 4073
+a 33 4106 1
+a 34 35 4072
+a 34 4106 1
+a 35 36 4071
+a 35 4106 1
+a 36 37 4070
+a 36 4106 1
+a 37 38 4069
+a 37 4106 1
+a 38 39 4068
+a 38 4106 1
+a 39 40 4067
+a 39 4106 1
+a 40 41 4066
+a 40 4106 1
+a 41 42 4065
+a 41 4106 1
+a 42 43 4064
+a 42 4106 1
+a 43 44 4063
+a 43 4106 1
+a 44 45 4062
+a 44 4106 1
+a 45 46 4061
+a 45 4106 1
+a 46 47 4060
+a 46 4106 1
+a 47 48 4059
+a 47 4106 1
+a 48 49 4058
+a 48 4106 1
+a 49 50 4057
+a 49 4106 1
+a 50 51 4056
+a 50 4106 1
+a 51 52 4055
+a 51 4106 1
+a 52 53 4054
+a 52 4106 1
+a 53 54 4053
+a 53 4106 1
+a 54 55 4052
+a 54 4106 1
+a 55 56 4051
+a 55 4106 1
+a 56 57 4050
+a 56 4106 1
+a 57 58 4049
+a 57 4106 1
+a 58 59 4048
+a 58 4106 1
+a 59 60 4047
+a 59 4106 1
+a 60 61 4046
+a 60 4106 1
+a 61 62 4045
+a 61 4106 1
+a 62 63 4044
+a 62 4106 1
+a 63 64 4043
+a 63 4106 1
+a 64 65 4042
+a 64 4106 1
+a 65 66 4041
+a 65 4106 1
+a 66 67 4040
+a 66 4106 1
+a 67 68 4039
+a 67 4106 1
+a 68 69 4038
+a 68 4106 1
+a 69 70 4037
+a 69 4106 1
+a 70 71 4036
+a 70 4106 1
+a 71 72 4035
+a 71 4106 1
+a 72 73 4034
+a 72 4106 1
+a 73 74 4033
+a 73 4106 1
+a 74 75 4032
+a 74 4106 1
+a 75 76 4031
+a 75 4106 1
+a 76 77 4030
+a 76 4106 1
+a 77 78 4029
+a 77 4106 1
+a 78 79 4028
+a 78 4106 1
+a 79 80 4027
+a 79 4106 1
+a 80 81 4026
+a 80 4106 1
+a 81 82 4025
+a 81 4106 1
+a 82 83 4024
+a 82 4106 1
+a 83 84 4023
+a 83 4106 1
+a 84 85 4022
+a 84 4106 1
+a 85 86 4021
+a 85 4106 1
+a 86 87 4020
+a 86 4106 1
+a 87 88 4019
+a 87 4106 1
+a 88 89 4018
+a 88 4106 1
+a 89 90 4017
+a 89 4106 1
+a 90 91 4016
+a 90 4106 1
+a 91 92 4015
+a 91 4106 1
+a 92 93 4014
+a 92 4106 1
+a 93 94 4013
+a 93 4106 1
+a 94 95 4012
+a 94 4106 1
+a 95 96 4011
+a 95 4106 1
+a 96 97 4010
+a 96 4106 1
+a 97 98 4009
+a 97 4106 1
+a 98 99 4008
+a 98 4106 1
+a 99 100 4007
+a 99 4106 1
+a 100 101 4006
+a 100 4106 1
+a 101 102 4005
+a 101 4106 1
+a 102 103 4004
+a 102 4106 1
+a 103 104 4003
+a 103 4106 1
+a 104 105 4002
+a 104 4106 1
+a 105 106 4001
+a 105 4106 1
+a 106 107 4000
+a 106 4106 1
+a 107 108 3999
+a 107 4106 1
+a 108 109 3998
+a 108 4106 1
+a 109 110 3997
+a 109 4106 1
+a 110 111 3996
+a 110 4106 1
+a 111 112 3995
+a 111 4106 1
+a 112 113 3994
+a 112 4106 1
+a 113 114 3993
+a 113 4106 1
+a 114 115 3992
+a 114 4106 1
+a 115 116 3991
+a 115 4106 1
+a 116 117 3990
+a 116 4106 1
+a 117 118 3989
+a 117 4106 1
+a 118 119 3988
+a 118 4106 1
+a 119 120 3987
+a 119 4106 1
+a 120 121 3986
+a 120 4106 1
+a 121 122 3985
+a 121 4106 1
+a 122 123 3984
+a 122 4106 1
+a 123 124 3983
+a 123 4106 1
+a 124 125 3982
+a 124 4106 1
+a 125 126 3981
+a 125 4106 1
+a 126 127 3980
+a 126 4106 1
+a 127 128 3979
+a 127 4106 1
+a 128 129 3978
+a 128 4106 1
+a 129 130 3977
+a 129 4106 1
+a 130 131 3976
+a 130 4106 1
+a 131 132 3975
+a 131 4106 1
+a 132 133 3974
+a 132 4106 1
+a 133 134 3973
+a 133 4106 1
+a 134 135 3972
+a 134 4106 1
+a 135 136 3971
+a 135 4106 1
+a 136 137 3970
+a 136 4106 1
+a 137 138 3969
+a 137 4106 1
+a 138 139 3968
+a 138 4106 1
+a 139 140 3967
+a 139 4106 1
+a 140 141 3966
+a 140 4106 1
+a 141 142 3965
+a 141 4106 1
+a 142 143 3964
+a 142 4106 1
+a 143 144 3963
+a 143 4106 1
+a 144 145 3962
+a 144 4106 1
+a 145 146 3961
+a 145 4106 1
+a 146 147 3960
+a 146 4106 1
+a 147 148 3959
+a 147 4106 1
+a 148 149 3958
+a 148 4106 1
+a 149 150 3957
+a 149 4106 1
+a 150 151 3956
+a 150 4106 1
+a 151 152 3955
+a 151 4106 1
+a 152 153 3954
+a 152 4106 1
+a 153 154 3953
+a 153 4106 1
+a 154 155 3952
+a 154 4106 1
+a 155 156 3951
+a 155 4106 1
+a 156 157 3950
+a 156 4106 1
+a 157 158 3949
+a 157 4106 1
+a 158 159 3948
+a 158 4106 1
+a 159 160 3947
+a 159 4106 1
+a 160 161 3946
+a 160 4106 1
+a 161 162 3945
+a 161 4106 1
+a 162 163 3944
+a 162 4106 1
+a 163 164 3943
+a 163 4106 1
+a 164 165 3942
+a 164 4106 1
+a 165 166 3941
+a 165 4106 1
+a 166 167 3940
+a 166 4106 1
+a 167 168 3939
+a 167 4106 1
+a 168 169 3938
+a 168 4106 1
+a 169 170 3937
+a 169 4106 1
+a 170 171 3936
+a 170 4106 1
+a 171 172 3935
+a 171 4106 1
+a 172 173 3934
+a 172 4106 1
+a 173 174 3933
+a 173 4106 1
+a 174 175 3932
+a 174 4106 1
+a 175 176 3931
+a 175 4106 1
+a 176 177 3930
+a 176 4106 1
+a 177 178 3929
+a 177 4106 1
+a 178 179 3928
+a 178 4106 1
+a 179 180 3927
+a 179 4106 1
+a 180 181 3926
+a 180 4106 1
+a 181 182 3925
+a 181 4106 1
+a 182 183 3924
+a 182 4106 1
+a 183 184 3923
+a 183 4106 1
+a 184 185 3922
+a 184 4106 1
+a 185 186 3921
+a 185 4106 1
+a 186 187 3920
+a 186 4106 1
+a 187 188 3919
+a 187 4106 1
+a 188 189 3918
+a 188 4106 1
+a 189 190 3917
+a 189 4106 1
+a 190 191 3916
+a 190 4106 1
+a 191 192 3915
+a 191 4106 1
+a 192 193 3914
+a 192 4106 1
+a 193 194 3913
+a 193 4106 1
+a 194 195 3912
+a 194 4106 1
+a 195 196 3911
+a 195 4106 1
+a 196 197 3910
+a 196 4106 1
+a 197 198 3909
+a 197 4106 1
+a 198 199 3908
+a 198 4106 1
+a 199 200 3907
+a 199 4106 1
+a 200 201 3906
+a 200 4106 1
+a 201 202 3905
+a 201 4106 1
+a 202 203 3904
+a 202 4106 1
+a 203 204 3903
+a 203 4106 1
+a 204 205 3902
+a 204 4106 1
+a 205 206 3901
+a 205 4106 1
+a 206 207 3900
+a 206 4106 1
+a 207 208 3899
+a 207 4106 1
+a 208 209 3898
+a 208 4106 1
+a 209 210 3897
+a 209 4106 1
+a 210 211 3896
+a 210 4106 1
+a 211 212 3895
+a 211 4106 1
+a 212 213 3894
+a 212 4106 1
+a 213 214 3893
+a 213 4106 1
+a 214 215 3892
+a 214 4106 1
+a 215 216 3891
+a 215 4106 1
+a 216 217 3890
+a 216 4106 1
+a 217 218 3889
+a 217 4106 1
+a 218 219 3888
+a 218 4106 1
+a 219 220 3887
+a 219 4106 1
+a 220 221 3886
+a 220 4106 1
+a 221 222 3885
+a 221 4106 1
+a 222 223 3884
+a 222 4106 1
+a 223 224 3883
+a 223 4106 1
+a 224 225 3882
+a 224 4106 1
+a 225 226 3881
+a 225 4106 1
+a 226 227 3880
+a 226 4106 1
+a 227 228 3879
+a 227 4106 1
+a 228 229 3878
+a 228 4106 1
+a 229 230 3877
+a 229 4106 1
+a 230 231 3876
+a 230 4106 1
+a 231 232 3875
+a 231 4106 1
+a 232 233 3874
+a 232 4106 1
+a 233 234 3873
+a 233 4106 1
+a 234 235 3872
+a 234 4106 1
+a 235 236 3871
+a 235 4106 1
+a 236 237 3870
+a 236 4106 1
+a 237 238 3869
+a 237 4106 1
+a 238 239 3868
+a 238 4106 1
+a 239 240 3867
+a 239 4106 1
+a 240 241 3866
+a 240 4106 1
+a 241 242 3865
+a 241 4106 1
+a 242 243 3864
+a 242 4106 1
+a 243 244 3863
+a 243 4106 1
+a 244 245 3862
+a 244 4106 1
+a 245 246 3861
+a 245 4106 1
+a 246 247 3860
+a 246 4106 1
+a 247 248 3859
+a 247 4106 1
+a 248 249 3858
+a 248 4106 1
+a 249 250 3857
+a 249 4106 1
+a 250 251 3856
+a 250 4106 1
+a 251 252 3855
+a 251 4106 1
+a 252 253 3854
+a 252 4106 1
+a 253 254 3853
+a 253 4106 1
+a 254 255 3852
+a 254 4106 1
+a 255 256 3851
+a 255 4106 1
+a 256 257 3850
+a 256 4106 1
+a 257 258 3849
+a 257 4106 1
+a 258 259 3848
+a 258 4106 1
+a 259 260 3847
+a 259 4106 1
+a 260 261 3846
+a 260 4106 1
+a 261 262 3845
+a 261 4106 1
+a 262 263 3844
+a 262 4106 1
+a 263 264 3843
+a 263 4106 1
+a 264 265 3842
+a 264 4106 1
+a 265 266 3841
+a 265 4106 1
+a 266 267 3840
+a 266 4106 1
+a 267 268 3839
+a 267 4106 1
+a 268 269 3838
+a 268 4106 1
+a 269 270 3837
+a 269 4106 1
+a 270 271 3836
+a 270 4106 1
+a 271 272 3835
+a 271 4106 1
+a 272 273 3834
+a 272 4106 1
+a 273 274 3833
+a 273 4106 1
+a 274 275 3832
+a 274 4106 1
+a 275 276 3831
+a 275 4106 1
+a 276 277 3830
+a 276 4106 1
+a 277 278 3829
+a 277 4106 1
+a 278 279 3828
+a 278 4106 1
+a 279 280 3827
+a 279 4106 1
+a 280 281 3826
+a 280 4106 1
+a 281 282 3825
+a 281 4106 1
+a 282 283 3824
+a 282 4106 1
+a 283 284 3823
+a 283 4106 1
+a 284 285 3822
+a 284 4106 1
+a 285 286 3821
+a 285 4106 1
+a 286 287 3820
+a 286 4106 1
+a 287 288 3819
+a 287 4106 1
+a 288 289 3818
+a 288 4106 1
+a 289 290 3817
+a 289 4106 1
+a 290 291 3816
+a 290 4106 1
+a 291 292 3815
+a 291 4106 1
+a 292 293 3814
+a 292 4106 1
+a 293 294 3813
+a 293 4106 1
+a 294 295 3812
+a 294 4106 1
+a 295 296 3811
+a 295 4106 1
+a 296 297 3810
+a 296 4106 1
+a 297 298 3809
+a 297 4106 1
+a 298 299 3808
+a 298 4106 1
+a 299 300 3807
+a 299 4106 1
+a 300 301 3806
+a 300 4106 1
+a 301 302 3805
+a 301 4106 1
+a 302 303 3804
+a 302 4106 1
+a 303 304 3803
+a 303 4106 1
+a 304 305 3802
+a 304 4106 1
+a 305 306 3801
+a 305 4106 1
+a 306 307 3800
+a 306 4106 1
+a 307 308 3799
+a 307 4106 1
+a 308 309 3798
+a 308 4106 1
+a 309 310 3797
+a 309 4106 1
+a 310 311 3796
+a 310 4106 1
+a 311 312 3795
+a 311 4106 1
+a 312 313 3794
+a 312 4106 1
+a 313 314 3793
+a 313 4106 1
+a 314 315 3792
+a 314 4106 1
+a 315 316 3791
+a 315 4106 1
+a 316 317 3790
+a 316 4106 1
+a 317 318 3789
+a 317 4106 1
+a 318 319 3788
+a 318 4106 1
+a 319 320 3787
+a 319 4106 1
+a 320 321 3786
+a 320 4106 1
+a 321 322 3785
+a 321 4106 1
+a 322 323 3784
+a 322 4106 1
+a 323 324 3783
+a 323 4106 1
+a 324 325 3782
+a 324 4106 1
+a 325 326 3781
+a 325 4106 1
+a 326 327 3780
+a 326 4106 1
+a 327 328 3779
+a 327 4106 1
+a 328 329 3778
+a 328 4106 1
+a 329 330 3777
+a 329 4106 1
+a 330 331 3776
+a 330 4106 1
+a 331 332 3775
+a 331 4106 1
+a 332 333 3774
+a 332 4106 1
+a 333 334 3773
+a 333 4106 1
+a 334 335 3772
+a 334 4106 1
+a 335 336 3771
+a 335 4106 1
+a 336 337 3770
+a 336 4106 1
+a 337 338 3769
+a 337 4106 1
+a 338 339 3768
+a 338 4106 1
+a 339 340 3767
+a 339 4106 1
+a 340 341 3766
+a 340 4106 1
+a 341 342 3765
+a 341 4106 1
+a 342 343 3764
+a 342 4106 1
+a 343 344 3763
+a 343 4106 1
+a 344 345 3762
+a 344 4106 1
+a 345 346 3761
+a 345 4106 1
+a 346 347 3760
+a 346 4106 1
+a 347 348 3759
+a 347 4106 1
+a 348 349 3758
+a 348 4106 1
+a 349 350 3757
+a 349 4106 1
+a 350 351 3756
+a 350 4106 1
+a 351 352 3755
+a 351 4106 1
+a 352 353 3754
+a 352 4106 1
+a 353 354 3753
+a 353 4106 1
+a 354 355 3752
+a 354 4106 1
+a 355 356 3751
+a 355 4106 1
+a 356 357 3750
+a 356 4106 1
+a 357 358 3749
+a 357 4106 1
+a 358 359 3748
+a 358 4106 1
+a 359 360 3747
+a 359 4106 1
+a 360 361 3746
+a 360 4106 1
+a 361 362 3745
+a 361 4106 1
+a 362 363 3744
+a 362 4106 1
+a 363 364 3743
+a 363 4106 1
+a 364 365 3742
+a 364 4106 1
+a 365 366 3741
+a 365 4106 1
+a 366 367 3740
+a 366 4106 1
+a 367 368 3739
+a 367 4106 1
+a 368 369 3738
+a 368 4106 1
+a 369 370 3737
+a 369 4106 1
+a 370 371 3736
+a 370 4106 1
+a 371 372 3735
+a 371 4106 1
+a 372 373 3734
+a 372 4106 1
+a 373 374 3733
+a 373 4106 1
+a 374 375 3732
+a 374 4106 1
+a 375 376 3731
+a 375 4106 1
+a 376 377 3730
+a 376 4106 1
+a 377 378 3729
+a 377 4106 1
+a 378 379 3728
+a 378 4106 1
+a 379 380 3727
+a 379 4106 1
+a 380 381 3726
+a 380 4106 1
+a 381 382 3725
+a 381 4106 1
+a 382 383 3724
+a 382 4106 1
+a 383 384 3723
+a 383 4106 1
+a 384 385 3722
+a 384 4106 1
+a 385 386 3721
+a 385 4106 1
+a 386 387 3720
+a 386 4106 1
+a 387 388 3719
+a 387 4106 1
+a 388 389 3718
+a 388 4106 1
+a 389 390 3717
+a 389 4106 1
+a 390 391 3716
+a 390 4106 1
+a 391 392 3715
+a 391 4106 1
+a 392 393 3714
+a 392 4106 1
+a 393 394 3713
+a 393 4106 1
+a 394 395 3712
+a 394 4106 1
+a 395 396 3711
+a 395 4106 1
+a 396 397 3710
+a 396 4106 1
+a 397 398 3709
+a 397 4106 1
+a 398 399 3708
+a 398 4106 1
+a 399 400 3707
+a 399 4106 1
+a 400 401 3706
+a 400 4106 1
+a 401 402 3705
+a 401 4106 1
+a 402 403 3704
+a 402 4106 1
+a 403 404 3703
+a 403 4106 1
+a 404 405 3702
+a 404 4106 1
+a 405 406 3701
+a 405 4106 1
+a 406 407 3700
+a 406 4106 1
+a 407 408 3699
+a 407 4106 1
+a 408 409 3698
+a 408 4106 1
+a 409 410 3697
+a 409 4106 1
+a 410 411 3696
+a 410 4106 1
+a 411 412 3695
+a 411 4106 1
+a 412 413 3694
+a 412 4106 1
+a 413 414 3693
+a 413 4106 1
+a 414 415 3692
+a 414 4106 1
+a 415 416 3691
+a 415 4106 1
+a 416 417 3690
+a 416 4106 1
+a 417 418 3689
+a 417 4106 1
+a 418 419 3688
+a 418 4106 1
+a 419 420 3687
+a 419 4106 1
+a 420 421 3686
+a 420 4106 1
+a 421 422 3685
+a 421 4106 1
+a 422 423 3684
+a 422 4106 1
+a 423 424 3683
+a 423 4106 1
+a 424 425 3682
+a 424 4106 1
+a 425 426 3681
+a 425 4106 1
+a 426 427 3680
+a 426 4106 1
+a 427 428 3679
+a 427 4106 1
+a 428 429 3678
+a 428 4106 1
+a 429 430 3677
+a 429 4106 1
+a 430 431 3676
+a 430 4106 1
+a 431 432 3675
+a 431 4106 1
+a 432 433 3674
+a 432 4106 1
+a 433 434 3673
+a 433 4106 1
+a 434 435 3672
+a 434 4106 1
+a 435 436 3671
+a 435 4106 1
+a 436 437 3670
+a 436 4106 1
+a 437 438 3669
+a 437 4106 1
+a 438 439 3668
+a 438 4106 1
+a 439 440 3667
+a 439 4106 1
+a 440 441 3666
+a 440 4106 1
+a 441 442 3665
+a 441 4106 1
+a 442 443 3664
+a 442 4106 1
+a 443 444 3663
+a 443 4106 1
+a 444 445 3662
+a 444 4106 1
+a 445 446 3661
+a 445 4106 1
+a 446 447 3660
+a 446 4106 1
+a 447 448 3659
+a 447 4106 1
+a 448 449 3658
+a 448 4106 1
+a 449 450 3657
+a 449 4106 1
+a 450 451 3656
+a 450 4106 1
+a 451 452 3655
+a 451 4106 1
+a 452 453 3654
+a 452 4106 1
+a 453 454 3653
+a 453 4106 1
+a 454 455 3652
+a 454 4106 1
+a 455 456 3651
+a 455 4106 1
+a 456 457 3650
+a 456 4106 1
+a 457 458 3649
+a 457 4106 1
+a 458 459 3648
+a 458 4106 1
+a 459 460 3647
+a 459 4106 1
+a 460 461 3646
+a 460 4106 1
+a 461 462 3645
+a 461 4106 1
+a 462 463 3644
+a 462 4106 1
+a 463 464 3643
+a 463 4106 1
+a 464 465 3642
+a 464 4106 1
+a 465 466 3641
+a 465 4106 1
+a 466 467 3640
+a 466 4106 1
+a 467 468 3639
+a 467 4106 1
+a 468 469 3638
+a 468 4106 1
+a 469 470 3637
+a 469 4106 1
+a 470 471 3636
+a 470 4106 1
+a 471 472 3635
+a 471 4106 1
+a 472 473 3634
+a 472 4106 1
+a 473 474 3633
+a 473 4106 1
+a 474 475 3632
+a 474 4106 1
+a 475 476 3631
+a 475 4106 1
+a 476 477 3630
+a 476 4106 1
+a 477 478 3629
+a 477 4106 1
+a 478 479 3628
+a 478 4106 1
+a 479 480 3627
+a 479 4106 1
+a 480 481 3626
+a 480 4106 1
+a 481 482 3625
+a 481 4106 1
+a 482 483 3624
+a 482 4106 1
+a 483 484 3623
+a 483 4106 1
+a 484 485 3622
+a 484 4106 1
+a 485 486 3621
+a 485 4106 1
+a 486 487 3620
+a 486 4106 1
+a 487 488 3619
+a 487 4106 1
+a 488 489 3618
+a 488 4106 1
+a 489 490 3617
+a 489 4106 1
+a 490 491 3616
+a 490 4106 1
+a 491 492 3615
+a 491 4106 1
+a 492 493 3614
+a 492 4106 1
+a 493 494 3613
+a 493 4106 1
+a 494 495 3612
+a 494 4106 1
+a 495 496 3611
+a 495 4106 1
+a 496 497 3610
+a 496 4106 1
+a 497 498 3609
+a 497 4106 1
+a 498 499 3608
+a 498 4106 1
+a 499 500 3607
+a 499 4106 1
+a 500 501 3606
+a 500 4106 1
+a 501 502 3605
+a 501 4106 1
+a 502 503 3604
+a 502 4106 1
+a 503 504 3603
+a 503 4106 1
+a 504 505 3602
+a 504 4106 1
+a 505 506 3601
+a 505 4106 1
+a 506 507 3600
+a 506 4106 1
+a 507 508 3599
+a 507 4106 1
+a 508 509 3598
+a 508 4106 1
+a 509 510 3597
+a 509 4106 1
+a 510 511 3596
+a 510 4106 1
+a 511 512 3595
+a 511 4106 1
+a 512 513 3594
+a 512 4106 1
+a 513 514 3593
+a 513 4106 1
+a 514 515 3592
+a 514 4106 1
+a 515 516 3591
+a 515 4106 1
+a 516 517 3590
+a 516 4106 1
+a 517 518 3589
+a 517 4106 1
+a 518 519 3588
+a 518 4106 1
+a 519 520 3587
+a 519 4106 1
+a 520 521 3586
+a 520 4106 1
+a 521 522 3585
+a 521 4106 1
+a 522 523 3584
+a 522 4106 1
+a 523 524 3583
+a 523 4106 1
+a 524 525 3582
+a 524 4106 1
+a 525 526 3581
+a 525 4106 1
+a 526 527 3580
+a 526 4106 1
+a 527 528 3579
+a 527 4106 1
+a 528 529 3578
+a 528 4106 1
+a 529 530 3577
+a 529 4106 1
+a 530 531 3576
+a 530 4106 1
+a 531 532 3575
+a 531 4106 1
+a 532 533 3574
+a 532 4106 1
+a 533 534 3573
+a 533 4106 1
+a 534 535 3572
+a 534 4106 1
+a 535 536 3571
+a 535 4106 1
+a 536 537 3570
+a 536 4106 1
+a 537 538 3569
+a 537 4106 1
+a 538 539 3568
+a 538 4106 1
+a 539 540 3567
+a 539 4106 1
+a 540 541 3566
+a 540 4106 1
+a 541 542 3565
+a 541 4106 1
+a 542 543 3564
+a 542 4106 1
+a 543 544 3563
+a 543 4106 1
+a 544 545 3562
+a 544 4106 1
+a 545 546 3561
+a 545 4106 1
+a 546 547 3560
+a 546 4106 1
+a 547 548 3559
+a 547 4106 1
+a 548 549 3558
+a 548 4106 1
+a 549 550 3557
+a 549 4106 1
+a 550 551 3556
+a 550 4106 1
+a 551 552 3555
+a 551 4106 1
+a 552 553 3554
+a 552 4106 1
+a 553 554 3553
+a 553 4106 1
+a 554 555 3552
+a 554 4106 1
+a 555 556 3551
+a 555 4106 1
+a 556 557 3550
+a 556 4106 1
+a 557 558 3549
+a 557 4106 1
+a 558 559 3548
+a 558 4106 1
+a 559 560 3547
+a 559 4106 1
+a 560 561 3546
+a 560 4106 1
+a 561 562 3545
+a 561 4106 1
+a 562 563 3544
+a 562 4106 1
+a 563 564 3543
+a 563 4106 1
+a 564 565 3542
+a 564 4106 1
+a 565 566 3541
+a 565 4106 1
+a 566 567 3540
+a 566 4106 1
+a 567 568 3539
+a 567 4106 1
+a 568 569 3538
+a 568 4106 1
+a 569 570 3537
+a 569 4106 1
+a 570 571 3536
+a 570 4106 1
+a 571 572 3535
+a 571 4106 1
+a 572 573 3534
+a 572 4106 1
+a 573 574 3533
+a 573 4106 1
+a 574 575 3532
+a 574 4106 1
+a 575 576 3531
+a 575 4106 1
+a 576 577 3530
+a 576 4106 1
+a 577 578 3529
+a 577 4106 1
+a 578 579 3528
+a 578 4106 1
+a 579 580 3527
+a 579 4106 1
+a 580 581 3526
+a 580 4106 1
+a 581 582 3525
+a 581 4106 1
+a 582 583 3524
+a 582 4106 1
+a 583 584 3523
+a 583 4106 1
+a 584 585 3522
+a 584 4106 1
+a 585 586 3521
+a 585 4106 1
+a 586 587 3520
+a 586 4106 1
+a 587 588 3519
+a 587 4106 1
+a 588 589 3518
+a 588 4106 1
+a 589 590 3517
+a 589 4106 1
+a 590 591 3516
+a 590 4106 1
+a 591 592 3515
+a 591 4106 1
+a 592 593 3514
+a 592 4106 1
+a 593 594 3513
+a 593 4106 1
+a 594 595 3512
+a 594 4106 1
+a 595 596 3511
+a 595 4106 1
+a 596 597 3510
+a 596 4106 1
+a 597 598 3509
+a 597 4106 1
+a 598 599 3508
+a 598 4106 1
+a 599 600 3507
+a 599 4106 1
+a 600 601 3506
+a 600 4106 1
+a 601 602 3505
+a 601 4106 1
+a 602 603 3504
+a 602 4106 1
+a 603 604 3503
+a 603 4106 1
+a 604 605 3502
+a 604 4106 1
+a 605 606 3501
+a 605 4106 1
+a 606 607 3500
+a 606 4106 1
+a 607 608 3499
+a 607 4106 1
+a 608 609 3498
+a 608 4106 1
+a 609 610 3497
+a 609 4106 1
+a 610 611 3496
+a 610 4106 1
+a 611 612 3495
+a 611 4106 1
+a 612 613 3494
+a 612 4106 1
+a 613 614 3493
+a 613 4106 1
+a 614 615 3492
+a 614 4106 1
+a 615 616 3491
+a 615 4106 1
+a 616 617 3490
+a 616 4106 1
+a 617 618 3489
+a 617 4106 1
+a 618 619 3488
+a 618 4106 1
+a 619 620 3487
+a 619 4106 1
+a 620 621 3486
+a 620 4106 1
+a 621 622 3485
+a 621 4106 1
+a 622 623 3484
+a 622 4106 1
+a 623 624 3483
+a 623 4106 1
+a 624 625 3482
+a 624 4106 1
+a 625 626 3481
+a 625 4106 1
+a 626 627 3480
+a 626 4106 1
+a 627 628 3479
+a 627 4106 1
+a 628 629 3478
+a 628 4106 1
+a 629 630 3477
+a 629 4106 1
+a 630 631 3476
+a 630 4106 1
+a 631 632 3475
+a 631 4106 1
+a 632 633 3474
+a 632 4106 1
+a 633 634 3473
+a 633 4106 1
+a 634 635 3472
+a 634 4106 1
+a 635 636 3471
+a 635 4106 1
+a 636 637 3470
+a 636 4106 1
+a 637 638 3469
+a 637 4106 1
+a 638 639 3468
+a 638 4106 1
+a 639 640 3467
+a 639 4106 1
+a 640 641 3466
+a 640 4106 1
+a 641 642 3465
+a 641 4106 1
+a 642 643 3464
+a 642 4106 1
+a 643 644 3463
+a 643 4106 1
+a 644 645 3462
+a 644 4106 1
+a 645 646 3461
+a 645 4106 1
+a 646 647 3460
+a 646 4106 1
+a 647 648 3459
+a 647 4106 1
+a 648 649 3458
+a 648 4106 1
+a 649 650 3457
+a 649 4106 1
+a 650 651 3456
+a 650 4106 1
+a 651 652 3455
+a 651 4106 1
+a 652 653 3454
+a 652 4106 1
+a 653 654 3453
+a 653 4106 1
+a 654 655 3452
+a 654 4106 1
+a 655 656 3451
+a 655 4106 1
+a 656 657 3450
+a 656 4106 1
+a 657 658 3449
+a 657 4106 1
+a 658 659 3448
+a 658 4106 1
+a 659 660 3447
+a 659 4106 1
+a 660 661 3446
+a 660 4106 1
+a 661 662 3445
+a 661 4106 1
+a 662 663 3444
+a 662 4106 1
+a 663 664 3443
+a 663 4106 1
+a 664 665 3442
+a 664 4106 1
+a 665 666 3441
+a 665 4106 1
+a 666 667 3440
+a 666 4106 1
+a 667 668 3439
+a 667 4106 1
+a 668 669 3438
+a 668 4106 1
+a 669 670 3437
+a 669 4106 1
+a 670 671 3436
+a 670 4106 1
+a 671 672 3435
+a 671 4106 1
+a 672 673 3434
+a 672 4106 1
+a 673 674 3433
+a 673 4106 1
+a 674 675 3432
+a 674 4106 1
+a 675 676 3431
+a 675 4106 1
+a 676 677 3430
+a 676 4106 1
+a 677 678 3429
+a 677 4106 1
+a 678 679 3428
+a 678 4106 1
+a 679 680 3427
+a 679 4106 1
+a 680 681 3426
+a 680 4106 1
+a 681 682 3425
+a 681 4106 1
+a 682 683 3424
+a 682 4106 1
+a 683 684 3423
+a 683 4106 1
+a 684 685 3422
+a 684 4106 1
+a 685 686 3421
+a 685 4106 1
+a 686 687 3420
+a 686 4106 1
+a 687 688 3419
+a 687 4106 1
+a 688 689 3418
+a 688 4106 1
+a 689 690 3417
+a 689 4106 1
+a 690 691 3416
+a 690 4106 1
+a 691 692 3415
+a 691 4106 1
+a 692 693 3414
+a 692 4106 1
+a 693 694 3413
+a 693 4106 1
+a 694 695 3412
+a 694 4106 1
+a 695 696 3411
+a 695 4106 1
+a 696 697 3410
+a 696 4106 1
+a 697 698 3409
+a 697 4106 1
+a 698 699 3408
+a 698 4106 1
+a 699 700 3407
+a 699 4106 1
+a 700 701 3406
+a 700 4106 1
+a 701 702 3405
+a 701 4106 1
+a 702 703 3404
+a 702 4106 1
+a 703 704 3403
+a 703 4106 1
+a 704 705 3402
+a 704 4106 1
+a 705 706 3401
+a 705 4106 1
+a 706 707 3400
+a 706 4106 1
+a 707 708 3399
+a 707 4106 1
+a 708 709 3398
+a 708 4106 1
+a 709 710 3397
+a 709 4106 1
+a 710 711 3396
+a 710 4106 1
+a 711 712 3395
+a 711 4106 1
+a 712 713 3394
+a 712 4106 1
+a 713 714 3393
+a 713 4106 1
+a 714 715 3392
+a 714 4106 1
+a 715 716 3391
+a 715 4106 1
+a 716 717 3390
+a 716 4106 1
+a 717 718 3389
+a 717 4106 1
+a 718 719 3388
+a 718 4106 1
+a 719 720 3387
+a 719 4106 1
+a 720 721 3386
+a 720 4106 1
+a 721 722 3385
+a 721 4106 1
+a 722 723 3384
+a 722 4106 1
+a 723 724 3383
+a 723 4106 1
+a 724 725 3382
+a 724 4106 1
+a 725 726 3381
+a 725 4106 1
+a 726 727 3380
+a 726 4106 1
+a 727 728 3379
+a 727 4106 1
+a 728 729 3378
+a 728 4106 1
+a 729 730 3377
+a 729 4106 1
+a 730 731 3376
+a 730 4106 1
+a 731 732 3375
+a 731 4106 1
+a 732 733 3374
+a 732 4106 1
+a 733 734 3373
+a 733 4106 1
+a 734 735 3372
+a 734 4106 1
+a 735 736 3371
+a 735 4106 1
+a 736 737 3370
+a 736 4106 1
+a 737 738 3369
+a 737 4106 1
+a 738 739 3368
+a 738 4106 1
+a 739 740 3367
+a 739 4106 1
+a 740 741 3366
+a 740 4106 1
+a 741 742 3365
+a 741 4106 1
+a 742 743 3364
+a 742 4106 1
+a 743 744 3363
+a 743 4106 1
+a 744 745 3362
+a 744 4106 1
+a 745 746 3361
+a 745 4106 1
+a 746 747 3360
+a 746 4106 1
+a 747 748 3359
+a 747 4106 1
+a 748 749 3358
+a 748 4106 1
+a 749 750 3357
+a 749 4106 1
+a 750 751 3356
+a 750 4106 1
+a 751 752 3355
+a 751 4106 1
+a 752 753 3354
+a 752 4106 1
+a 753 754 3353
+a 753 4106 1
+a 754 755 3352
+a 754 4106 1
+a 755 756 3351
+a 755 4106 1
+a 756 757 3350
+a 756 4106 1
+a 757 758 3349
+a 757 4106 1
+a 758 759 3348
+a 758 4106 1
+a 759 760 3347
+a 759 4106 1
+a 760 761 3346
+a 760 4106 1
+a 761 762 3345
+a 761 4106 1
+a 762 763 3344
+a 762 4106 1
+a 763 764 3343
+a 763 4106 1
+a 764 765 3342
+a 764 4106 1
+a 765 766 3341
+a 765 4106 1
+a 766 767 3340
+a 766 4106 1
+a 767 768 3339
+a 767 4106 1
+a 768 769 3338
+a 768 4106 1
+a 769 770 3337
+a 769 4106 1
+a 770 771 3336
+a 770 4106 1
+a 771 772 3335
+a 771 4106 1
+a 772 773 3334
+a 772 4106 1
+a 773 774 3333
+a 773 4106 1
+a 774 775 3332
+a 774 4106 1
+a 775 776 3331
+a 775 4106 1
+a 776 777 3330
+a 776 4106 1
+a 777 778 3329
+a 777 4106 1
+a 778 779 3328
+a 778 4106 1
+a 779 780 3327
+a 779 4106 1
+a 780 781 3326
+a 780 4106 1
+a 781 782 3325
+a 781 4106 1
+a 782 783 3324
+a 782 4106 1
+a 783 784 3323
+a 783 4106 1
+a 784 785 3322
+a 784 4106 1
+a 785 786 3321
+a 785 4106 1
+a 786 787 3320
+a 786 4106 1
+a 787 788 3319
+a 787 4106 1
+a 788 789 3318
+a 788 4106 1
+a 789 790 3317
+a 789 4106 1
+a 790 791 3316
+a 790 4106 1
+a 791 792 3315
+a 791 4106 1
+a 792 793 3314
+a 792 4106 1
+a 793 794 3313
+a 793 4106 1
+a 794 795 3312
+a 794 4106 1
+a 795 796 3311
+a 795 4106 1
+a 796 797 3310
+a 796 4106 1
+a 797 798 3309
+a 797 4106 1
+a 798 799 3308
+a 798 4106 1
+a 799 800 3307
+a 799 4106 1
+a 800 801 3306
+a 800 4106 1
+a 801 802 3305
+a 801 4106 1
+a 802 803 3304
+a 802 4106 1
+a 803 804 3303
+a 803 4106 1
+a 804 805 3302
+a 804 4106 1
+a 805 806 3301
+a 805 4106 1
+a 806 807 3300
+a 806 4106 1
+a 807 808 3299
+a 807 4106 1
+a 808 809 3298
+a 808 4106 1
+a 809 810 3297
+a 809 4106 1
+a 810 811 3296
+a 810 4106 1
+a 811 812 3295
+a 811 4106 1
+a 812 813 3294
+a 812 4106 1
+a 813 814 3293
+a 813 4106 1
+a 814 815 3292
+a 814 4106 1
+a 815 816 3291
+a 815 4106 1
+a 816 817 3290
+a 816 4106 1
+a 817 818 3289
+a 817 4106 1
+a 818 819 3288
+a 818 4106 1
+a 819 820 3287
+a 819 4106 1
+a 820 821 3286
+a 820 4106 1
+a 821 822 3285
+a 821 4106 1
+a 822 823 3284
+a 822 4106 1
+a 823 824 3283
+a 823 4106 1
+a 824 825 3282
+a 824 4106 1
+a 825 826 3281
+a 825 4106 1
+a 826 827 3280
+a 826 4106 1
+a 827 828 3279
+a 827 4106 1
+a 828 829 3278
+a 828 4106 1
+a 829 830 3277
+a 829 4106 1
+a 830 831 3276
+a 830 4106 1
+a 831 832 3275
+a 831 4106 1
+a 832 833 3274
+a 832 4106 1
+a 833 834 3273
+a 833 4106 1
+a 834 835 3272
+a 834 4106 1
+a 835 836 3271
+a 835 4106 1
+a 836 837 3270
+a 836 4106 1
+a 837 838 3269
+a 837 4106 1
+a 838 839 3268
+a 838 4106 1
+a 839 840 3267
+a 839 4106 1
+a 840 841 3266
+a 840 4106 1
+a 841 842 3265
+a 841 4106 1
+a 842 843 3264
+a 842 4106 1
+a 843 844 3263
+a 843 4106 1
+a 844 845 3262
+a 844 4106 1
+a 845 846 3261
+a 845 4106 1
+a 846 847 3260
+a 846 4106 1
+a 847 848 3259
+a 847 4106 1
+a 848 849 3258
+a 848 4106 1
+a 849 850 3257
+a 849 4106 1
+a 850 851 3256
+a 850 4106 1
+a 851 852 3255
+a 851 4106 1
+a 852 853 3254
+a 852 4106 1
+a 853 854 3253
+a 853 4106 1
+a 854 855 3252
+a 854 4106 1
+a 855 856 3251
+a 855 4106 1
+a 856 857 3250
+a 856 4106 1
+a 857 858 3249
+a 857 4106 1
+a 858 859 3248
+a 858 4106 1
+a 859 860 3247
+a 859 4106 1
+a 860 861 3246
+a 860 4106 1
+a 861 862 3245
+a 861 4106 1
+a 862 863 3244
+a 862 4106 1
+a 863 864 3243
+a 863 4106 1
+a 864 865 3242
+a 864 4106 1
+a 865 866 3241
+a 865 4106 1
+a 866 867 3240
+a 866 4106 1
+a 867 868 3239
+a 867 4106 1
+a 868 869 3238
+a 868 4106 1
+a 869 870 3237
+a 869 4106 1
+a 870 871 3236
+a 870 4106 1
+a 871 872 3235
+a 871 4106 1
+a 872 873 3234
+a 872 4106 1
+a 873 874 3233
+a 873 4106 1
+a 874 875 3232
+a 874 4106 1
+a 875 876 3231
+a 875 4106 1
+a 876 877 3230
+a 876 4106 1
+a 877 878 3229
+a 877 4106 1
+a 878 879 3228
+a 878 4106 1
+a 879 880 3227
+a 879 4106 1
+a 880 881 3226
+a 880 4106 1
+a 881 882 3225
+a 881 4106 1
+a 882 883 3224
+a 882 4106 1
+a 883 884 3223
+a 883 4106 1
+a 884 885 3222
+a 884 4106 1
+a 885 886 3221
+a 885 4106 1
+a 886 887 3220
+a 886 4106 1
+a 887 888 3219
+a 887 4106 1
+a 888 889 3218
+a 888 4106 1
+a 889 890 3217
+a 889 4106 1
+a 890 891 3216
+a 890 4106 1
+a 891 892 3215
+a 891 4106 1
+a 892 893 3214
+a 892 4106 1
+a 893 894 3213
+a 893 4106 1
+a 894 895 3212
+a 894 4106 1
+a 895 896 3211
+a 895 4106 1
+a 896 897 3210
+a 896 4106 1
+a 897 898 3209
+a 897 4106 1
+a 898 899 3208
+a 898 4106 1
+a 899 900 3207
+a 899 4106 1
+a 900 901 3206
+a 900 4106 1
+a 901 902 3205
+a 901 4106 1
+a 902 903 3204
+a 902 4106 1
+a 903 904 3203
+a 903 4106 1
+a 904 905 3202
+a 904 4106 1
+a 905 906 3201
+a 905 4106 1
+a 906 907 3200
+a 906 4106 1
+a 907 908 3199
+a 907 4106 1
+a 908 909 3198
+a 908 4106 1
+a 909 910 3197
+a 909 4106 1
+a 910 911 3196
+a 910 4106 1
+a 911 912 3195
+a 911 4106 1
+a 912 913 3194
+a 912 4106 1
+a 913 914 3193
+a 913 4106 1
+a 914 915 3192
+a 914 4106 1
+a 915 916 3191
+a 915 4106 1
+a 916 917 3190
+a 916 4106 1
+a 917 918 3189
+a 917 4106 1
+a 918 919 3188
+a 918 4106 1
+a 919 920 3187
+a 919 4106 1
+a 920 921 3186
+a 920 4106 1
+a 921 922 3185
+a 921 4106 1
+a 922 923 3184
+a 922 4106 1
+a 923 924 3183
+a 923 4106 1
+a 924 925 3182
+a 924 4106 1
+a 925 926 3181
+a 925 4106 1
+a 926 927 3180
+a 926 4106 1
+a 927 928 3179
+a 927 4106 1
+a 928 929 3178
+a 928 4106 1
+a 929 930 3177
+a 929 4106 1
+a 930 931 3176
+a 930 4106 1
+a 931 932 3175
+a 931 4106 1
+a 932 933 3174
+a 932 4106 1
+a 933 934 3173
+a 933 4106 1
+a 934 935 3172
+a 934 4106 1
+a 935 936 3171
+a 935 4106 1
+a 936 937 3170
+a 936 4106 1
+a 937 938 3169
+a 937 4106 1
+a 938 939 3168
+a 938 4106 1
+a 939 940 3167
+a 939 4106 1
+a 940 941 3166
+a 940 4106 1
+a 941 942 3165
+a 941 4106 1
+a 942 943 3164
+a 942 4106 1
+a 943 944 3163
+a 943 4106 1
+a 944 945 3162
+a 944 4106 1
+a 945 946 3161
+a 945 4106 1
+a 946 947 3160
+a 946 4106 1
+a 947 948 3159
+a 947 4106 1
+a 948 949 3158
+a 948 4106 1
+a 949 950 3157
+a 949 4106 1
+a 950 951 3156
+a 950 4106 1
+a 951 952 3155
+a 951 4106 1
+a 952 953 3154
+a 952 4106 1
+a 953 954 3153
+a 953 4106 1
+a 954 955 3152
+a 954 4106 1
+a 955 956 3151
+a 955 4106 1
+a 956 957 3150
+a 956 4106 1
+a 957 958 3149
+a 957 4106 1
+a 958 959 3148
+a 958 4106 1
+a 959 960 3147
+a 959 4106 1
+a 960 961 3146
+a 960 4106 1
+a 961 962 3145
+a 961 4106 1
+a 962 963 3144
+a 962 4106 1
+a 963 964 3143
+a 963 4106 1
+a 964 965 3142
+a 964 4106 1
+a 965 966 3141
+a 965 4106 1
+a 966 967 3140
+a 966 4106 1
+a 967 968 3139
+a 967 4106 1
+a 968 969 3138
+a 968 4106 1
+a 969 970 3137
+a 969 4106 1
+a 970 971 3136
+a 970 4106 1
+a 971 972 3135
+a 971 4106 1
+a 972 973 3134
+a 972 4106 1
+a 973 974 3133
+a 973 4106 1
+a 974 975 3132
+a 974 4106 1
+a 975 976 3131
+a 975 4106 1
+a 976 977 3130
+a 976 4106 1
+a 977 978 3129
+a 977 4106 1
+a 978 979 3128
+a 978 4106 1
+a 979 980 3127
+a 979 4106 1
+a 980 981 3126
+a 980 4106 1
+a 981 982 3125
+a 981 4106 1
+a 982 983 3124
+a 982 4106 1
+a 983 984 3123
+a 983 4106 1
+a 984 985 3122
+a 984 4106 1
+a 985 986 3121
+a 985 4106 1
+a 986 987 3120
+a 986 4106 1
+a 987 988 3119
+a 987 4106 1
+a 988 989 3118
+a 988 4106 1
+a 989 990 3117
+a 989 4106 1
+a 990 991 3116
+a 990 4106 1
+a 991 992 3115
+a 991 4106 1
+a 992 993 3114
+a 992 4106 1
+a 993 994 3113
+a 993 4106 1
+a 994 995 3112
+a 994 4106 1
+a 995 996 3111
+a 995 4106 1
+a 996 997 3110
+a 996 4106 1
+a 997 998 3109
+a 997 4106 1
+a 998 999 3108
+a 998 4106 1
+a 999 1000 3107
+a 999 4106 1
+a 1000 1001 3106
+a 1000 4106 1
+a 1001 1002 3105
+a 1001 4106 1
+a 1002 1003 3104
+a 1002 4106 1
+a 1003 1004 3103
+a 1003 4106 1
+a 1004 1005 3102
+a 1004 4106 1
+a 1005 1006 3101
+a 1005 4106 1
+a 1006 1007 3100
+a 1006 4106 1
+a 1007 1008 3099
+a 1007 4106 1
+a 1008 1009 3098
+a 1008 4106 1
+a 1009 1010 3097
+a 1009 4106 1
+a 1010 1011 3096
+a 1010 4106 1
+a 1011 1012 3095
+a 1011 4106 1
+a 1012 1013 3094
+a 1012 4106 1
+a 1013 1014 3093
+a 1013 4106 1
+a 1014 1015 3092
+a 1014 4106 1
+a 1015 1016 3091
+a 1015 4106 1
+a 1016 1017 3090
+a 1016 4106 1
+a 1017 1018 3089
+a 1017 4106 1
+a 1018 1019 3088
+a 1018 4106 1
+a 1019 1020 3087
+a 1019 4106 1
+a 1020 1021 3086
+a 1020 4106 1
+a 1021 1022 3085
+a 1021 4106 1
+a 1022 1023 3084
+a 1022 4106 1
+a 1023 1024 3083
+a 1023 4106 1
+a 1024 1025 3082
+a 1024 4106 1
+a 1025 1026 3081
+a 1025 4106 1
+a 1026 1027 3080
+a 1026 4106 1
+a 1027 1028 3079
+a 1027 4106 1
+a 1028 1029 3078
+a 1028 4106 1
+a 1029 1030 3077
+a 1029 4106 1
+a 1030 1031 3076
+a 1030 4106 1
+a 1031 1032 3075
+a 1031 4106 1
+a 1032 1033 3074
+a 1032 4106 1
+a 1033 1034 3073
+a 1033 4106 1
+a 1034 1035 3072
+a 1034 4106 1
+a 1035 1036 3071
+a 1035 4106 1
+a 1036 1037 3070
+a 1036 4106 1
+a 1037 1038 3069
+a 1037 4106 1
+a 1038 1039 3068
+a 1038 4106 1
+a 1039 1040 3067
+a 1039 4106 1
+a 1040 1041 3066
+a 1040 4106 1
+a 1041 1042 3065
+a 1041 4106 1
+a 1042 1043 3064
+a 1042 4106 1
+a 1043 1044 3063
+a 1043 4106 1
+a 1044 1045 3062
+a 1044 4106 1
+a 1045 1046 3061
+a 1045 4106 1
+a 1046 1047 3060
+a 1046 4106 1
+a 1047 1048 3059
+a 1047 4106 1
+a 1048 1049 3058
+a 1048 4106 1
+a 1049 1050 3057
+a 1049 4106 1
+a 1050 1051 3056
+a 1050 4106 1
+a 1051 1052 3055
+a 1051 4106 1
+a 1052 1053 3054
+a 1052 4106 1
+a 1053 1054 3053
+a 1053 4106 1
+a 1054 1055 3052
+a 1054 4106 1
+a 1055 1056 3051
+a 1055 4106 1
+a 1056 1057 3050
+a 1056 4106 1
+a 1057 1058 3049
+a 1057 4106 1
+a 1058 1059 3048
+a 1058 4106 1
+a 1059 1060 3047
+a 1059 4106 1
+a 1060 1061 3046
+a 1060 4106 1
+a 1061 1062 3045
+a 1061 4106 1
+a 1062 1063 3044
+a 1062 4106 1
+a 1063 1064 3043
+a 1063 4106 1
+a 1064 1065 3042
+a 1064 4106 1
+a 1065 1066 3041
+a 1065 4106 1
+a 1066 1067 3040
+a 1066 4106 1
+a 1067 1068 3039
+a 1067 4106 1
+a 1068 1069 3038
+a 1068 4106 1
+a 1069 1070 3037
+a 1069 4106 1
+a 1070 1071 3036
+a 1070 4106 1
+a 1071 1072 3035
+a 1071 4106 1
+a 1072 1073 3034
+a 1072 4106 1
+a 1073 1074 3033
+a 1073 4106 1
+a 1074 1075 3032
+a 1074 4106 1
+a 1075 1076 3031
+a 1075 4106 1
+a 1076 1077 3030
+a 1076 4106 1
+a 1077 1078 3029
+a 1077 4106 1
+a 1078 1079 3028
+a 1078 4106 1
+a 1079 1080 3027
+a 1079 4106 1
+a 1080 1081 3026
+a 1080 4106 1
+a 1081 1082 3025
+a 1081 4106 1
+a 1082 1083 3024
+a 1082 4106 1
+a 1083 1084 3023
+a 1083 4106 1
+a 1084 1085 3022
+a 1084 4106 1
+a 1085 1086 3021
+a 1085 4106 1
+a 1086 1087 3020
+a 1086 4106 1
+a 1087 1088 3019
+a 1087 4106 1
+a 1088 1089 3018
+a 1088 4106 1
+a 1089 1090 3017
+a 1089 4106 1
+a 1090 1091 3016
+a 1090 4106 1
+a 1091 1092 3015
+a 1091 4106 1
+a 1092 1093 3014
+a 1092 4106 1
+a 1093 1094 3013
+a 1093 4106 1
+a 1094 1095 3012
+a 1094 4106 1
+a 1095 1096 3011
+a 1095 4106 1
+a 1096 1097 3010
+a 1096 4106 1
+a 1097 1098 3009
+a 1097 4106 1
+a 1098 1099 3008
+a 1098 4106 1
+a 1099 1100 3007
+a 1099 4106 1
+a 1100 1101 3006
+a 1100 4106 1
+a 1101 1102 3005
+a 1101 4106 1
+a 1102 1103 3004
+a 1102 4106 1
+a 1103 1104 3003
+a 1103 4106 1
+a 1104 1105 3002
+a 1104 4106 1
+a 1105 1106 3001
+a 1105 4106 1
+a 1106 1107 3000
+a 1106 4106 1
+a 1107 1108 2999
+a 1107 4106 1
+a 1108 1109 2998
+a 1108 4106 1
+a 1109 1110 2997
+a 1109 4106 1
+a 1110 1111 2996
+a 1110 4106 1
+a 1111 1112 2995
+a 1111 4106 1
+a 1112 1113 2994
+a 1112 4106 1
+a 1113 1114 2993
+a 1113 4106 1
+a 1114 1115 2992
+a 1114 4106 1
+a 1115 1116 2991
+a 1115 4106 1
+a 1116 1117 2990
+a 1116 4106 1
+a 1117 1118 2989
+a 1117 4106 1
+a 1118 1119 2988
+a 1118 4106 1
+a 1119 1120 2987
+a 1119 4106 1
+a 1120 1121 2986
+a 1120 4106 1
+a 1121 1122 2985
+a 1121 4106 1
+a 1122 1123 2984
+a 1122 4106 1
+a 1123 1124 2983
+a 1123 4106 1
+a 1124 1125 2982
+a 1124 4106 1
+a 1125 1126 2981
+a 1125 4106 1
+a 1126 1127 2980
+a 1126 4106 1
+a 1127 1128 2979
+a 1127 4106 1
+a 1128 1129 2978
+a 1128 4106 1
+a 1129 1130 2977
+a 1129 4106 1
+a 1130 1131 2976
+a 1130 4106 1
+a 1131 1132 2975
+a 1131 4106 1
+a 1132 1133 2974
+a 1132 4106 1
+a 1133 1134 2973
+a 1133 4106 1
+a 1134 1135 2972
+a 1134 4106 1
+a 1135 1136 2971
+a 1135 4106 1
+a 1136 1137 2970
+a 1136 4106 1
+a 1137 1138 2969
+a 1137 4106 1
+a 1138 1139 2968
+a 1138 4106 1
+a 1139 1140 2967
+a 1139 4106 1
+a 1140 1141 2966
+a 1140 4106 1
+a 1141 1142 2965
+a 1141 4106 1
+a 1142 1143 2964
+a 1142 4106 1
+a 1143 1144 2963
+a 1143 4106 1
+a 1144 1145 2962
+a 1144 4106 1
+a 1145 1146 2961
+a 1145 4106 1
+a 1146 1147 2960
+a 1146 4106 1
+a 1147 1148 2959
+a 1147 4106 1
+a 1148 1149 2958
+a 1148 4106 1
+a 1149 1150 2957
+a 1149 4106 1
+a 1150 1151 2956
+a 1150 4106 1
+a 1151 1152 2955
+a 1151 4106 1
+a 1152 1153 2954
+a 1152 4106 1
+a 1153 1154 2953
+a 1153 4106 1
+a 1154 1155 2952
+a 1154 4106 1
+a 1155 1156 2951
+a 1155 4106 1
+a 1156 1157 2950
+a 1156 4106 1
+a 1157 1158 2949
+a 1157 4106 1
+a 1158 1159 2948
+a 1158 4106 1
+a 1159 1160 2947
+a 1159 4106 1
+a 1160 1161 2946
+a 1160 4106 1
+a 1161 1162 2945
+a 1161 4106 1
+a 1162 1163 2944
+a 1162 4106 1
+a 1163 1164 2943
+a 1163 4106 1
+a 1164 1165 2942
+a 1164 4106 1
+a 1165 1166 2941
+a 1165 4106 1
+a 1166 1167 2940
+a 1166 4106 1
+a 1167 1168 2939
+a 1167 4106 1
+a 1168 1169 2938
+a 1168 4106 1
+a 1169 1170 2937
+a 1169 4106 1
+a 1170 1171 2936
+a 1170 4106 1
+a 1171 1172 2935
+a 1171 4106 1
+a 1172 1173 2934
+a 1172 4106 1
+a 1173 1174 2933
+a 1173 4106 1
+a 1174 1175 2932
+a 1174 4106 1
+a 1175 1176 2931
+a 1175 4106 1
+a 1176 1177 2930
+a 1176 4106 1
+a 1177 1178 2929
+a 1177 4106 1
+a 1178 1179 2928
+a 1178 4106 1
+a 1179 1180 2927
+a 1179 4106 1
+a 1180 1181 2926
+a 1180 4106 1
+a 1181 1182 2925
+a 1181 4106 1
+a 1182 1183 2924
+a 1182 4106 1
+a 1183 1184 2923
+a 1183 4106 1
+a 1184 1185 2922
+a 1184 4106 1
+a 1185 1186 2921
+a 1185 4106 1
+a 1186 1187 2920
+a 1186 4106 1
+a 1187 1188 2919
+a 1187 4106 1
+a 1188 1189 2918
+a 1188 4106 1
+a 1189 1190 2917
+a 1189 4106 1
+a 1190 1191 2916
+a 1190 4106 1
+a 1191 1192 2915
+a 1191 4106 1
+a 1192 1193 2914
+a 1192 4106 1
+a 1193 1194 2913
+a 1193 4106 1
+a 1194 1195 2912
+a 1194 4106 1
+a 1195 1196 2911
+a 1195 4106 1
+a 1196 1197 2910
+a 1196 4106 1
+a 1197 1198 2909
+a 1197 4106 1
+a 1198 1199 2908
+a 1198 4106 1
+a 1199 1200 2907
+a 1199 4106 1
+a 1200 1201 2906
+a 1200 4106 1
+a 1201 1202 2905
+a 1201 4106 1
+a 1202 1203 2904
+a 1202 4106 1
+a 1203 1204 2903
+a 1203 4106 1
+a 1204 1205 2902
+a 1204 4106 1
+a 1205 1206 2901
+a 1205 4106 1
+a 1206 1207 2900
+a 1206 4106 1
+a 1207 1208 2899
+a 1207 4106 1
+a 1208 1209 2898
+a 1208 4106 1
+a 1209 1210 2897
+a 1209 4106 1
+a 1210 1211 2896
+a 1210 4106 1
+a 1211 1212 2895
+a 1211 4106 1
+a 1212 1213 2894
+a 1212 4106 1
+a 1213 1214 2893
+a 1213 4106 1
+a 1214 1215 2892
+a 1214 4106 1
+a 1215 1216 2891
+a 1215 4106 1
+a 1216 1217 2890
+a 1216 4106 1
+a 1217 1218 2889
+a 1217 4106 1
+a 1218 1219 2888
+a 1218 4106 1
+a 1219 1220 2887
+a 1219 4106 1
+a 1220 1221 2886
+a 1220 4106 1
+a 1221 1222 2885
+a 1221 4106 1
+a 1222 1223 2884
+a 1222 4106 1
+a 1223 1224 2883
+a 1223 4106 1
+a 1224 1225 2882
+a 1224 4106 1
+a 1225 1226 2881
+a 1225 4106 1
+a 1226 1227 2880
+a 1226 4106 1
+a 1227 1228 2879
+a 1227 4106 1
+a 1228 1229 2878
+a 1228 4106 1
+a 1229 1230 2877
+a 1229 4106 1
+a 1230 1231 2876
+a 1230 4106 1
+a 1231 1232 2875
+a 1231 4106 1
+a 1232 1233 2874
+a 1232 4106 1
+a 1233 1234 2873
+a 1233 4106 1
+a 1234 1235 2872
+a 1234 4106 1
+a 1235 1236 2871
+a 1235 4106 1
+a 1236 1237 2870
+a 1236 4106 1
+a 1237 1238 2869
+a 1237 4106 1
+a 1238 1239 2868
+a 1238 4106 1
+a 1239 1240 2867
+a 1239 4106 1
+a 1240 1241 2866
+a 1240 4106 1
+a 1241 1242 2865
+a 1241 4106 1
+a 1242 1243 2864
+a 1242 4106 1
+a 1243 1244 2863
+a 1243 4106 1
+a 1244 1245 2862
+a 1244 4106 1
+a 1245 1246 2861
+a 1245 4106 1
+a 1246 1247 2860
+a 1246 4106 1
+a 1247 1248 2859
+a 1247 4106 1
+a 1248 1249 2858
+a 1248 4106 1
+a 1249 1250 2857
+a 1249 4106 1
+a 1250 1251 2856
+a 1250 4106 1
+a 1251 1252 2855
+a 1251 4106 1
+a 1252 1253 2854
+a 1252 4106 1
+a 1253 1254 2853
+a 1253 4106 1
+a 1254 1255 2852
+a 1254 4106 1
+a 1255 1256 2851
+a 1255 4106 1
+a 1256 1257 2850
+a 1256 4106 1
+a 1257 1258 2849
+a 1257 4106 1
+a 1258 1259 2848
+a 1258 4106 1
+a 1259 1260 2847
+a 1259 4106 1
+a 1260 1261 2846
+a 1260 4106 1
+a 1261 1262 2845
+a 1261 4106 1
+a 1262 1263 2844
+a 1262 4106 1
+a 1263 1264 2843
+a 1263 4106 1
+a 1264 1265 2842
+a 1264 4106 1
+a 1265 1266 2841
+a 1265 4106 1
+a 1266 1267 2840
+a 1266 4106 1
+a 1267 1268 2839
+a 1267 4106 1
+a 1268 1269 2838
+a 1268 4106 1
+a 1269 1270 2837
+a 1269 4106 1
+a 1270 1271 2836
+a 1270 4106 1
+a 1271 1272 2835
+a 1271 4106 1
+a 1272 1273 2834
+a 1272 4106 1
+a 1273 1274 2833
+a 1273 4106 1
+a 1274 1275 2832
+a 1274 4106 1
+a 1275 1276 2831
+a 1275 4106 1
+a 1276 1277 2830
+a 1276 4106 1
+a 1277 1278 2829
+a 1277 4106 1
+a 1278 1279 2828
+a 1278 4106 1
+a 1279 1280 2827
+a 1279 4106 1
+a 1280 1281 2826
+a 1280 4106 1
+a 1281 1282 2825
+a 1281 4106 1
+a 1282 1283 2824
+a 1282 4106 1
+a 1283 1284 2823
+a 1283 4106 1
+a 1284 1285 2822
+a 1284 4106 1
+a 1285 1286 2821
+a 1285 4106 1
+a 1286 1287 2820
+a 1286 4106 1
+a 1287 1288 2819
+a 1287 4106 1
+a 1288 1289 2818
+a 1288 4106 1
+a 1289 1290 2817
+a 1289 4106 1
+a 1290 1291 2816
+a 1290 4106 1
+a 1291 1292 2815
+a 1291 4106 1
+a 1292 1293 2814
+a 1292 4106 1
+a 1293 1294 2813
+a 1293 4106 1
+a 1294 1295 2812
+a 1294 4106 1
+a 1295 1296 2811
+a 1295 4106 1
+a 1296 1297 2810
+a 1296 4106 1
+a 1297 1298 2809
+a 1297 4106 1
+a 1298 1299 2808
+a 1298 4106 1
+a 1299 1300 2807
+a 1299 4106 1
+a 1300 1301 2806
+a 1300 4106 1
+a 1301 1302 2805
+a 1301 4106 1
+a 1302 1303 2804
+a 1302 4106 1
+a 1303 1304 2803
+a 1303 4106 1
+a 1304 1305 2802
+a 1304 4106 1
+a 1305 1306 2801
+a 1305 4106 1
+a 1306 1307 2800
+a 1306 4106 1
+a 1307 1308 2799
+a 1307 4106 1
+a 1308 1309 2798
+a 1308 4106 1
+a 1309 1310 2797
+a 1309 4106 1
+a 1310 1311 2796
+a 1310 4106 1
+a 1311 1312 2795
+a 1311 4106 1
+a 1312 1313 2794
+a 1312 4106 1
+a 1313 1314 2793
+a 1313 4106 1
+a 1314 1315 2792
+a 1314 4106 1
+a 1315 1316 2791
+a 1315 4106 1
+a 1316 1317 2790
+a 1316 4106 1
+a 1317 1318 2789
+a 1317 4106 1
+a 1318 1319 2788
+a 1318 4106 1
+a 1319 1320 2787
+a 1319 4106 1
+a 1320 1321 2786
+a 1320 4106 1
+a 1321 1322 2785
+a 1321 4106 1
+a 1322 1323 2784
+a 1322 4106 1
+a 1323 1324 2783
+a 1323 4106 1
+a 1324 1325 2782
+a 1324 4106 1
+a 1325 1326 2781
+a 1325 4106 1
+a 1326 1327 2780
+a 1326 4106 1
+a 1327 1328 2779
+a 1327 4106 1
+a 1328 1329 2778
+a 1328 4106 1
+a 1329 1330 2777
+a 1329 4106 1
+a 1330 1331 2776
+a 1330 4106 1
+a 1331 1332 2775
+a 1331 4106 1
+a 1332 1333 2774
+a 1332 4106 1
+a 1333 1334 2773
+a 1333 4106 1
+a 1334 1335 2772
+a 1334 4106 1
+a 1335 1336 2771
+a 1335 4106 1
+a 1336 1337 2770
+a 1336 4106 1
+a 1337 1338 2769
+a 1337 4106 1
+a 1338 1339 2768
+a 1338 4106 1
+a 1339 1340 2767
+a 1339 4106 1
+a 1340 1341 2766
+a 1340 4106 1
+a 1341 1342 2765
+a 1341 4106 1
+a 1342 1343 2764
+a 1342 4106 1
+a 1343 1344 2763
+a 1343 4106 1
+a 1344 1345 2762
+a 1344 4106 1
+a 1345 1346 2761
+a 1345 4106 1
+a 1346 1347 2760
+a 1346 4106 1
+a 1347 1348 2759
+a 1347 4106 1
+a 1348 1349 2758
+a 1348 4106 1
+a 1349 1350 2757
+a 1349 4106 1
+a 1350 1351 2756
+a 1350 4106 1
+a 1351 1352 2755
+a 1351 4106 1
+a 1352 1353 2754
+a 1352 4106 1
+a 1353 1354 2753
+a 1353 4106 1
+a 1354 1355 2752
+a 1354 4106 1
+a 1355 1356 2751
+a 1355 4106 1
+a 1356 1357 2750
+a 1356 4106 1
+a 1357 1358 2749
+a 1357 4106 1
+a 1358 1359 2748
+a 1358 4106 1
+a 1359 1360 2747
+a 1359 4106 1
+a 1360 1361 2746
+a 1360 4106 1
+a 1361 1362 2745
+a 1361 4106 1
+a 1362 1363 2744
+a 1362 4106 1
+a 1363 1364 2743
+a 1363 4106 1
+a 1364 1365 2742
+a 1364 4106 1
+a 1365 1366 2741
+a 1365 4106 1
+a 1366 1367 2740
+a 1366 4106 1
+a 1367 1368 2739
+a 1367 4106 1
+a 1368 1369 2738
+a 1368 4106 1
+a 1369 1370 2737
+a 1369 4106 1
+a 1370 1371 2736
+a 1370 4106 1
+a 1371 1372 2735
+a 1371 4106 1
+a 1372 1373 2734
+a 1372 4106 1
+a 1373 1374 2733
+a 1373 4106 1
+a 1374 1375 2732
+a 1374 4106 1
+a 1375 1376 2731
+a 1375 4106 1
+a 1376 1377 2730
+a 1376 4106 1
+a 1377 1378 2729
+a 1377 4106 1
+a 1378 1379 2728
+a 1378 4106 1
+a 1379 1380 2727
+a 1379 4106 1
+a 1380 1381 2726
+a 1380 4106 1
+a 1381 1382 2725
+a 1381 4106 1
+a 1382 1383 2724
+a 1382 4106 1
+a 1383 1384 2723
+a 1383 4106 1
+a 1384 1385 2722
+a 1384 4106 1
+a 1385 1386 2721
+a 1385 4106 1
+a 1386 1387 2720
+a 1386 4106 1
+a 1387 1388 2719
+a 1387 4106 1
+a 1388 1389 2718
+a 1388 4106 1
+a 1389 1390 2717
+a 1389 4106 1
+a 1390 1391 2716
+a 1390 4106 1
+a 1391 1392 2715
+a 1391 4106 1
+a 1392 1393 2714
+a 1392 4106 1
+a 1393 1394 2713
+a 1393 4106 1
+a 1394 1395 2712
+a 1394 4106 1
+a 1395 1396 2711
+a 1395 4106 1
+a 1396 1397 2710
+a 1396 4106 1
+a 1397 1398 2709
+a 1397 4106 1
+a 1398 1399 2708
+a 1398 4106 1
+a 1399 1400 2707
+a 1399 4106 1
+a 1400 1401 2706
+a 1400 4106 1
+a 1401 1402 2705
+a 1401 4106 1
+a 1402 1403 2704
+a 1402 4106 1
+a 1403 1404 2703
+a 1403 4106 1
+a 1404 1405 2702
+a 1404 4106 1
+a 1405 1406 2701
+a 1405 4106 1
+a 1406 1407 2700
+a 1406 4106 1
+a 1407 1408 2699
+a 1407 4106 1
+a 1408 1409 2698
+a 1408 4106 1
+a 1409 1410 2697
+a 1409 4106 1
+a 1410 1411 2696
+a 1410 4106 1
+a 1411 1412 2695
+a 1411 4106 1
+a 1412 1413 2694
+a 1412 4106 1
+a 1413 1414 2693
+a 1413 4106 1
+a 1414 1415 2692
+a 1414 4106 1
+a 1415 1416 2691
+a 1415 4106 1
+a 1416 1417 2690
+a 1416 4106 1
+a 1417 1418 2689
+a 1417 4106 1
+a 1418 1419 2688
+a 1418 4106 1
+a 1419 1420 2687
+a 1419 4106 1
+a 1420 1421 2686
+a 1420 4106 1
+a 1421 1422 2685
+a 1421 4106 1
+a 1422 1423 2684
+a 1422 4106 1
+a 1423 1424 2683
+a 1423 4106 1
+a 1424 1425 2682
+a 1424 4106 1
+a 1425 1426 2681
+a 1425 4106 1
+a 1426 1427 2680
+a 1426 4106 1
+a 1427 1428 2679
+a 1427 4106 1
+a 1428 1429 2678
+a 1428 4106 1
+a 1429 1430 2677
+a 1429 4106 1
+a 1430 1431 2676
+a 1430 4106 1
+a 1431 1432 2675
+a 1431 4106 1
+a 1432 1433 2674
+a 1432 4106 1
+a 1433 1434 2673
+a 1433 4106 1
+a 1434 1435 2672
+a 1434 4106 1
+a 1435 1436 2671
+a 1435 4106 1
+a 1436 1437 2670
+a 1436 4106 1
+a 1437 1438 2669
+a 1437 4106 1
+a 1438 1439 2668
+a 1438 4106 1
+a 1439 1440 2667
+a 1439 4106 1
+a 1440 1441 2666
+a 1440 4106 1
+a 1441 1442 2665
+a 1441 4106 1
+a 1442 1443 2664
+a 1442 4106 1
+a 1443 1444 2663
+a 1443 4106 1
+a 1444 1445 2662
+a 1444 4106 1
+a 1445 1446 2661
+a 1445 4106 1
+a 1446 1447 2660
+a 1446 4106 1
+a 1447 1448 2659
+a 1447 4106 1
+a 1448 1449 2658
+a 1448 4106 1
+a 1449 1450 2657
+a 1449 4106 1
+a 1450 1451 2656
+a 1450 4106 1
+a 1451 1452 2655
+a 1451 4106 1
+a 1452 1453 2654
+a 1452 4106 1
+a 1453 1454 2653
+a 1453 4106 1
+a 1454 1455 2652
+a 1454 4106 1
+a 1455 1456 2651
+a 1455 4106 1
+a 1456 1457 2650
+a 1456 4106 1
+a 1457 1458 2649
+a 1457 4106 1
+a 1458 1459 2648
+a 1458 4106 1
+a 1459 1460 2647
+a 1459 4106 1
+a 1460 1461 2646
+a 1460 4106 1
+a 1461 1462 2645
+a 1461 4106 1
+a 1462 1463 2644
+a 1462 4106 1
+a 1463 1464 2643
+a 1463 4106 1
+a 1464 1465 2642
+a 1464 4106 1
+a 1465 1466 2641
+a 1465 4106 1
+a 1466 1467 2640
+a 1466 4106 1
+a 1467 1468 2639
+a 1467 4106 1
+a 1468 1469 2638
+a 1468 4106 1
+a 1469 1470 2637
+a 1469 4106 1
+a 1470 1471 2636
+a 1470 4106 1
+a 1471 1472 2635
+a 1471 4106 1
+a 1472 1473 2634
+a 1472 4106 1
+a 1473 1474 2633
+a 1473 4106 1
+a 1474 1475 2632
+a 1474 4106 1
+a 1475 1476 2631
+a 1475 4106 1
+a 1476 1477 2630
+a 1476 4106 1
+a 1477 1478 2629
+a 1477 4106 1
+a 1478 1479 2628
+a 1478 4106 1
+a 1479 1480 2627
+a 1479 4106 1
+a 1480 1481 2626
+a 1480 4106 1
+a 1481 1482 2625
+a 1481 4106 1
+a 1482 1483 2624
+a 1482 4106 1
+a 1483 1484 2623
+a 1483 4106 1
+a 1484 1485 2622
+a 1484 4106 1
+a 1485 1486 2621
+a 1485 4106 1
+a 1486 1487 2620
+a 1486 4106 1
+a 1487 1488 2619
+a 1487 4106 1
+a 1488 1489 2618
+a 1488 4106 1
+a 1489 1490 2617
+a 1489 4106 1
+a 1490 1491 2616
+a 1490 4106 1
+a 1491 1492 2615
+a 1491 4106 1
+a 1492 1493 2614
+a 1492 4106 1
+a 1493 1494 2613
+a 1493 4106 1
+a 1494 1495 2612
+a 1494 4106 1
+a 1495 1496 2611
+a 1495 4106 1
+a 1496 1497 2610
+a 1496 4106 1
+a 1497 1498 2609
+a 1497 4106 1
+a 1498 1499 2608
+a 1498 4106 1
+a 1499 1500 2607
+a 1499 4106 1
+a 1500 1501 2606
+a 1500 4106 1
+a 1501 1502 2605
+a 1501 4106 1
+a 1502 1503 2604
+a 1502 4106 1
+a 1503 1504 2603
+a 1503 4106 1
+a 1504 1505 2602
+a 1504 4106 1
+a 1505 1506 2601
+a 1505 4106 1
+a 1506 1507 2600
+a 1506 4106 1
+a 1507 1508 2599
+a 1507 4106 1
+a 1508 1509 2598
+a 1508 4106 1
+a 1509 1510 2597
+a 1509 4106 1
+a 1510 1511 2596
+a 1510 4106 1
+a 1511 1512 2595
+a 1511 4106 1
+a 1512 1513 2594
+a 1512 4106 1
+a 1513 1514 2593
+a 1513 4106 1
+a 1514 1515 2592
+a 1514 4106 1
+a 1515 1516 2591
+a 1515 4106 1
+a 1516 1517 2590
+a 1516 4106 1
+a 1517 1518 2589
+a 1517 4106 1
+a 1518 1519 2588
+a 1518 4106 1
+a 1519 1520 2587
+a 1519 4106 1
+a 1520 1521 2586
+a 1520 4106 1
+a 1521 1522 2585
+a 1521 4106 1
+a 1522 1523 2584
+a 1522 4106 1
+a 1523 1524 2583
+a 1523 4106 1
+a 1524 1525 2582
+a 1524 4106 1
+a 1525 1526 2581
+a 1525 4106 1
+a 1526 1527 2580
+a 1526 4106 1
+a 1527 1528 2579
+a 1527 4106 1
+a 1528 1529 2578
+a 1528 4106 1
+a 1529 1530 2577
+a 1529 4106 1
+a 1530 1531 2576
+a 1530 4106 1
+a 1531 1532 2575
+a 1531 4106 1
+a 1532 1533 2574
+a 1532 4106 1
+a 1533 1534 2573
+a 1533 4106 1
+a 1534 1535 2572
+a 1534 4106 1
+a 1535 1536 2571
+a 1535 4106 1
+a 1536 1537 2570
+a 1536 4106 1
+a 1537 1538 2569
+a 1537 4106 1
+a 1538 1539 2568
+a 1538 4106 1
+a 1539 1540 2567
+a 1539 4106 1
+a 1540 1541 2566
+a 1540 4106 1
+a 1541 1542 2565
+a 1541 4106 1
+a 1542 1543 2564
+a 1542 4106 1
+a 1543 1544 2563
+a 1543 4106 1
+a 1544 1545 2562
+a 1544 4106 1
+a 1545 1546 2561
+a 1545 4106 1
+a 1546 1547 2560
+a 1546 4106 1
+a 1547 1548 2559
+a 1547 4106 1
+a 1548 1549 2558
+a 1548 4106 1
+a 1549 1550 2557
+a 1549 4106 1
+a 1550 1551 2556
+a 1550 4106 1
+a 1551 1552 2555
+a 1551 4106 1
+a 1552 1553 2554
+a 1552 4106 1
+a 1553 1554 2553
+a 1553 4106 1
+a 1554 1555 2552
+a 1554 4106 1
+a 1555 1556 2551
+a 1555 4106 1
+a 1556 1557 2550
+a 1556 4106 1
+a 1557 1558 2549
+a 1557 4106 1
+a 1558 1559 2548
+a 1558 4106 1
+a 1559 1560 2547
+a 1559 4106 1
+a 1560 1561 2546
+a 1560 4106 1
+a 1561 1562 2545
+a 1561 4106 1
+a 1562 1563 2544
+a 1562 4106 1
+a 1563 1564 2543
+a 1563 4106 1
+a 1564 1565 2542
+a 1564 4106 1
+a 1565 1566 2541
+a 1565 4106 1
+a 1566 1567 2540
+a 1566 4106 1
+a 1567 1568 2539
+a 1567 4106 1
+a 1568 1569 2538
+a 1568 4106 1
+a 1569 1570 2537
+a 1569 4106 1
+a 1570 1571 2536
+a 1570 4106 1
+a 1571 1572 2535
+a 1571 4106 1
+a 1572 1573 2534
+a 1572 4106 1
+a 1573 1574 2533
+a 1573 4106 1
+a 1574 1575 2532
+a 1574 4106 1
+a 1575 1576 2531
+a 1575 4106 1
+a 1576 1577 2530
+a 1576 4106 1
+a 1577 1578 2529
+a 1577 4106 1
+a 1578 1579 2528
+a 1578 4106 1
+a 1579 1580 2527
+a 1579 4106 1
+a 1580 1581 2526
+a 1580 4106 1
+a 1581 1582 2525
+a 1581 4106 1
+a 1582 1583 2524
+a 1582 4106 1
+a 1583 1584 2523
+a 1583 4106 1
+a 1584 1585 2522
+a 1584 4106 1
+a 1585 1586 2521
+a 1585 4106 1
+a 1586 1587 2520
+a 1586 4106 1
+a 1587 1588 2519
+a 1587 4106 1
+a 1588 1589 2518
+a 1588 4106 1
+a 1589 1590 2517
+a 1589 4106 1
+a 1590 1591 2516
+a 1590 4106 1
+a 1591 1592 2515
+a 1591 4106 1
+a 1592 1593 2514
+a 1592 4106 1
+a 1593 1594 2513
+a 1593 4106 1
+a 1594 1595 2512
+a 1594 4106 1
+a 1595 1596 2511
+a 1595 4106 1
+a 1596 1597 2510
+a 1596 4106 1
+a 1597 1598 2509
+a 1597 4106 1
+a 1598 1599 2508
+a 1598 4106 1
+a 1599 1600 2507
+a 1599 4106 1
+a 1600 1601 2506
+a 1600 4106 1
+a 1601 1602 2505
+a 1601 4106 1
+a 1602 1603 2504
+a 1602 4106 1
+a 1603 1604 2503
+a 1603 4106 1
+a 1604 1605 2502
+a 1604 4106 1
+a 1605 1606 2501
+a 1605 4106 1
+a 1606 1607 2500
+a 1606 4106 1
+a 1607 1608 2499
+a 1607 4106 1
+a 1608 1609 2498
+a 1608 4106 1
+a 1609 1610 2497
+a 1609 4106 1
+a 1610 1611 2496
+a 1610 4106 1
+a 1611 1612 2495
+a 1611 4106 1
+a 1612 1613 2494
+a 1612 4106 1
+a 1613 1614 2493
+a 1613 4106 1
+a 1614 1615 2492
+a 1614 4106 1
+a 1615 1616 2491
+a 1615 4106 1
+a 1616 1617 2490
+a 1616 4106 1
+a 1617 1618 2489
+a 1617 4106 1
+a 1618 1619 2488
+a 1618 4106 1
+a 1619 1620 2487
+a 1619 4106 1
+a 1620 1621 2486
+a 1620 4106 1
+a 1621 1622 2485
+a 1621 4106 1
+a 1622 1623 2484
+a 1622 4106 1
+a 1623 1624 2483
+a 1623 4106 1
+a 1624 1625 2482
+a 1624 4106 1
+a 1625 1626 2481
+a 1625 4106 1
+a 1626 1627 2480
+a 1626 4106 1
+a 1627 1628 2479
+a 1627 4106 1
+a 1628 1629 2478
+a 1628 4106 1
+a 1629 1630 2477
+a 1629 4106 1
+a 1630 1631 2476
+a 1630 4106 1
+a 1631 1632 2475
+a 1631 4106 1
+a 1632 1633 2474
+a 1632 4106 1
+a 1633 1634 2473
+a 1633 4106 1
+a 1634 1635 2472
+a 1634 4106 1
+a 1635 1636 2471
+a 1635 4106 1
+a 1636 1637 2470
+a 1636 4106 1
+a 1637 1638 2469
+a 1637 4106 1
+a 1638 1639 2468
+a 1638 4106 1
+a 1639 1640 2467
+a 1639 4106 1
+a 1640 1641 2466
+a 1640 4106 1
+a 1641 1642 2465
+a 1641 4106 1
+a 1642 1643 2464
+a 1642 4106 1
+a 1643 1644 2463
+a 1643 4106 1
+a 1644 1645 2462
+a 1644 4106 1
+a 1645 1646 2461
+a 1645 4106 1
+a 1646 1647 2460
+a 1646 4106 1
+a 1647 1648 2459
+a 1647 4106 1
+a 1648 1649 2458
+a 1648 4106 1
+a 1649 1650 2457
+a 1649 4106 1
+a 1650 1651 2456
+a 1650 4106 1
+a 1651 1652 2455
+a 1651 4106 1
+a 1652 1653 2454
+a 1652 4106 1
+a 1653 1654 2453
+a 1653 4106 1
+a 1654 1655 2452
+a 1654 4106 1
+a 1655 1656 2451
+a 1655 4106 1
+a 1656 1657 2450
+a 1656 4106 1
+a 1657 1658 2449
+a 1657 4106 1
+a 1658 1659 2448
+a 1658 4106 1
+a 1659 1660 2447
+a 1659 4106 1
+a 1660 1661 2446
+a 1660 4106 1
+a 1661 1662 2445
+a 1661 4106 1
+a 1662 1663 2444
+a 1662 4106 1
+a 1663 1664 2443
+a 1663 4106 1
+a 1664 1665 2442
+a 1664 4106 1
+a 1665 1666 2441
+a 1665 4106 1
+a 1666 1667 2440
+a 1666 4106 1
+a 1667 1668 2439
+a 1667 4106 1
+a 1668 1669 2438
+a 1668 4106 1
+a 1669 1670 2437
+a 1669 4106 1
+a 1670 1671 2436
+a 1670 4106 1
+a 1671 1672 2435
+a 1671 4106 1
+a 1672 1673 2434
+a 1672 4106 1
+a 1673 1674 2433
+a 1673 4106 1
+a 1674 1675 2432
+a 1674 4106 1
+a 1675 1676 2431
+a 1675 4106 1
+a 1676 1677 2430
+a 1676 4106 1
+a 1677 1678 2429
+a 1677 4106 1
+a 1678 1679 2428
+a 1678 4106 1
+a 1679 1680 2427
+a 1679 4106 1
+a 1680 1681 2426
+a 1680 4106 1
+a 1681 1682 2425
+a 1681 4106 1
+a 1682 1683 2424
+a 1682 4106 1
+a 1683 1684 2423
+a 1683 4106 1
+a 1684 1685 2422
+a 1684 4106 1
+a 1685 1686 2421
+a 1685 4106 1
+a 1686 1687 2420
+a 1686 4106 1
+a 1687 1688 2419
+a 1687 4106 1
+a 1688 1689 2418
+a 1688 4106 1
+a 1689 1690 2417
+a 1689 4106 1
+a 1690 1691 2416
+a 1690 4106 1
+a 1691 1692 2415
+a 1691 4106 1
+a 1692 1693 2414
+a 1692 4106 1
+a 1693 1694 2413
+a 1693 4106 1
+a 1694 1695 2412
+a 1694 4106 1
+a 1695 1696 2411
+a 1695 4106 1
+a 1696 1697 2410
+a 1696 4106 1
+a 1697 1698 2409
+a 1697 4106 1
+a 1698 1699 2408
+a 1698 4106 1
+a 1699 1700 2407
+a 1699 4106 1
+a 1700 1701 2406
+a 1700 4106 1
+a 1701 1702 2405
+a 1701 4106 1
+a 1702 1703 2404
+a 1702 4106 1
+a 1703 1704 2403
+a 1703 4106 1
+a 1704 1705 2402
+a 1704 4106 1
+a 1705 1706 2401
+a 1705 4106 1
+a 1706 1707 2400
+a 1706 4106 1
+a 1707 1708 2399
+a 1707 4106 1
+a 1708 1709 2398
+a 1708 4106 1
+a 1709 1710 2397
+a 1709 4106 1
+a 1710 1711 2396
+a 1710 4106 1
+a 1711 1712 2395
+a 1711 4106 1
+a 1712 1713 2394
+a 1712 4106 1
+a 1713 1714 2393
+a 1713 4106 1
+a 1714 1715 2392
+a 1714 4106 1
+a 1715 1716 2391
+a 1715 4106 1
+a 1716 1717 2390
+a 1716 4106 1
+a 1717 1718 2389
+a 1717 4106 1
+a 1718 1719 2388
+a 1718 4106 1
+a 1719 1720 2387
+a 1719 4106 1
+a 1720 1721 2386
+a 1720 4106 1
+a 1721 1722 2385
+a 1721 4106 1
+a 1722 1723 2384
+a 1722 4106 1
+a 1723 1724 2383
+a 1723 4106 1
+a 1724 1725 2382
+a 1724 4106 1
+a 1725 1726 2381
+a 1725 4106 1
+a 1726 1727 2380
+a 1726 4106 1
+a 1727 1728 2379
+a 1727 4106 1
+a 1728 1729 2378
+a 1728 4106 1
+a 1729 1730 2377
+a 1729 4106 1
+a 1730 1731 2376
+a 1730 4106 1
+a 1731 1732 2375
+a 1731 4106 1
+a 1732 1733 2374
+a 1732 4106 1
+a 1733 1734 2373
+a 1733 4106 1
+a 1734 1735 2372
+a 1734 4106 1
+a 1735 1736 2371
+a 1735 4106 1
+a 1736 1737 2370
+a 1736 4106 1
+a 1737 1738 2369
+a 1737 4106 1
+a 1738 1739 2368
+a 1738 4106 1
+a 1739 1740 2367
+a 1739 4106 1
+a 1740 1741 2366
+a 1740 4106 1
+a 1741 1742 2365
+a 1741 4106 1
+a 1742 1743 2364
+a 1742 4106 1
+a 1743 1744 2363
+a 1743 4106 1
+a 1744 1745 2362
+a 1744 4106 1
+a 1745 1746 2361
+a 1745 4106 1
+a 1746 1747 2360
+a 1746 4106 1
+a 1747 1748 2359
+a 1747 4106 1
+a 1748 1749 2358
+a 1748 4106 1
+a 1749 1750 2357
+a 1749 4106 1
+a 1750 1751 2356
+a 1750 4106 1
+a 1751 1752 2355
+a 1751 4106 1
+a 1752 1753 2354
+a 1752 4106 1
+a 1753 1754 2353
+a 1753 4106 1
+a 1754 1755 2352
+a 1754 4106 1
+a 1755 1756 2351
+a 1755 4106 1
+a 1756 1757 2350
+a 1756 4106 1
+a 1757 1758 2349
+a 1757 4106 1
+a 1758 1759 2348
+a 1758 4106 1
+a 1759 1760 2347
+a 1759 4106 1
+a 1760 1761 2346
+a 1760 4106 1
+a 1761 1762 2345
+a 1761 4106 1
+a 1762 1763 2344
+a 1762 4106 1
+a 1763 1764 2343
+a 1763 4106 1
+a 1764 1765 2342
+a 1764 4106 1
+a 1765 1766 2341
+a 1765 4106 1
+a 1766 1767 2340
+a 1766 4106 1
+a 1767 1768 2339
+a 1767 4106 1
+a 1768 1769 2338
+a 1768 4106 1
+a 1769 1770 2337
+a 1769 4106 1
+a 1770 1771 2336
+a 1770 4106 1
+a 1771 1772 2335
+a 1771 4106 1
+a 1772 1773 2334
+a 1772 4106 1
+a 1773 1774 2333
+a 1773 4106 1
+a 1774 1775 2332
+a 1774 4106 1
+a 1775 1776 2331
+a 1775 4106 1
+a 1776 1777 2330
+a 1776 4106 1
+a 1777 1778 2329
+a 1777 4106 1
+a 1778 1779 2328
+a 1778 4106 1
+a 1779 1780 2327
+a 1779 4106 1
+a 1780 1781 2326
+a 1780 4106 1
+a 1781 1782 2325
+a 1781 4106 1
+a 1782 1783 2324
+a 1782 4106 1
+a 1783 1784 2323
+a 1783 4106 1
+a 1784 1785 2322
+a 1784 4106 1
+a 1785 1786 2321
+a 1785 4106 1
+a 1786 1787 2320
+a 1786 4106 1
+a 1787 1788 2319
+a 1787 4106 1
+a 1788 1789 2318
+a 1788 4106 1
+a 1789 1790 2317
+a 1789 4106 1
+a 1790 1791 2316
+a 1790 4106 1
+a 1791 1792 2315
+a 1791 4106 1
+a 1792 1793 2314
+a 1792 4106 1
+a 1793 1794 2313
+a 1793 4106 1
+a 1794 1795 2312
+a 1794 4106 1
+a 1795 1796 2311
+a 1795 4106 1
+a 1796 1797 2310
+a 1796 4106 1
+a 1797 1798 2309
+a 1797 4106 1
+a 1798 1799 2308
+a 1798 4106 1
+a 1799 1800 2307
+a 1799 4106 1
+a 1800 1801 2306
+a 1800 4106 1
+a 1801 1802 2305
+a 1801 4106 1
+a 1802 1803 2304
+a 1802 4106 1
+a 1803 1804 2303
+a 1803 4106 1
+a 1804 1805 2302
+a 1804 4106 1
+a 1805 1806 2301
+a 1805 4106 1
+a 1806 1807 2300
+a 1806 4106 1
+a 1807 1808 2299
+a 1807 4106 1
+a 1808 1809 2298
+a 1808 4106 1
+a 1809 1810 2297
+a 1809 4106 1
+a 1810 1811 2296
+a 1810 4106 1
+a 1811 1812 2295
+a 1811 4106 1
+a 1812 1813 2294
+a 1812 4106 1
+a 1813 1814 2293
+a 1813 4106 1
+a 1814 1815 2292
+a 1814 4106 1
+a 1815 1816 2291
+a 1815 4106 1
+a 1816 1817 2290
+a 1816 4106 1
+a 1817 1818 2289
+a 1817 4106 1
+a 1818 1819 2288
+a 1818 4106 1
+a 1819 1820 2287
+a 1819 4106 1
+a 1820 1821 2286
+a 1820 4106 1
+a 1821 1822 2285
+a 1821 4106 1
+a 1822 1823 2284
+a 1822 4106 1
+a 1823 1824 2283
+a 1823 4106 1
+a 1824 1825 2282
+a 1824 4106 1
+a 1825 1826 2281
+a 1825 4106 1
+a 1826 1827 2280
+a 1826 4106 1
+a 1827 1828 2279
+a 1827 4106 1
+a 1828 1829 2278
+a 1828 4106 1
+a 1829 1830 2277
+a 1829 4106 1
+a 1830 1831 2276
+a 1830 4106 1
+a 1831 1832 2275
+a 1831 4106 1
+a 1832 1833 2274
+a 1832 4106 1
+a 1833 1834 2273
+a 1833 4106 1
+a 1834 1835 2272
+a 1834 4106 1
+a 1835 1836 2271
+a 1835 4106 1
+a 1836 1837 2270
+a 1836 4106 1
+a 1837 1838 2269
+a 1837 4106 1
+a 1838 1839 2268
+a 1838 4106 1
+a 1839 1840 2267
+a 1839 4106 1
+a 1840 1841 2266
+a 1840 4106 1
+a 1841 1842 2265
+a 1841 4106 1
+a 1842 1843 2264
+a 1842 4106 1
+a 1843 1844 2263
+a 1843 4106 1
+a 1844 1845 2262
+a 1844 4106 1
+a 1845 1846 2261
+a 1845 4106 1
+a 1846 1847 2260
+a 1846 4106 1
+a 1847 1848 2259
+a 1847 4106 1
+a 1848 1849 2258
+a 1848 4106 1
+a 1849 1850 2257
+a 1849 4106 1
+a 1850 1851 2256
+a 1850 4106 1
+a 1851 1852 2255
+a 1851 4106 1
+a 1852 1853 2254
+a 1852 4106 1
+a 1853 1854 2253
+a 1853 4106 1
+a 1854 1855 2252
+a 1854 4106 1
+a 1855 1856 2251
+a 1855 4106 1
+a 1856 1857 2250
+a 1856 4106 1
+a 1857 1858 2249
+a 1857 4106 1
+a 1858 1859 2248
+a 1858 4106 1
+a 1859 1860 2247
+a 1859 4106 1
+a 1860 1861 2246
+a 1860 4106 1
+a 1861 1862 2245
+a 1861 4106 1
+a 1862 1863 2244
+a 1862 4106 1
+a 1863 1864 2243
+a 1863 4106 1
+a 1864 1865 2242
+a 1864 4106 1
+a 1865 1866 2241
+a 1865 4106 1
+a 1866 1867 2240
+a 1866 4106 1
+a 1867 1868 2239
+a 1867 4106 1
+a 1868 1869 2238
+a 1868 4106 1
+a 1869 1870 2237
+a 1869 4106 1
+a 1870 1871 2236
+a 1870 4106 1
+a 1871 1872 2235
+a 1871 4106 1
+a 1872 1873 2234
+a 1872 4106 1
+a 1873 1874 2233
+a 1873 4106 1
+a 1874 1875 2232
+a 1874 4106 1
+a 1875 1876 2231
+a 1875 4106 1
+a 1876 1877 2230
+a 1876 4106 1
+a 1877 1878 2229
+a 1877 4106 1
+a 1878 1879 2228
+a 1878 4106 1
+a 1879 1880 2227
+a 1879 4106 1
+a 1880 1881 2226
+a 1880 4106 1
+a 1881 1882 2225
+a 1881 4106 1
+a 1882 1883 2224
+a 1882 4106 1
+a 1883 1884 2223
+a 1883 4106 1
+a 1884 1885 2222
+a 1884 4106 1
+a 1885 1886 2221
+a 1885 4106 1
+a 1886 1887 2220
+a 1886 4106 1
+a 1887 1888 2219
+a 1887 4106 1
+a 1888 1889 2218
+a 1888 4106 1
+a 1889 1890 2217
+a 1889 4106 1
+a 1890 1891 2216
+a 1890 4106 1
+a 1891 1892 2215
+a 1891 4106 1
+a 1892 1893 2214
+a 1892 4106 1
+a 1893 1894 2213
+a 1893 4106 1
+a 1894 1895 2212
+a 1894 4106 1
+a 1895 1896 2211
+a 1895 4106 1
+a 1896 1897 2210
+a 1896 4106 1
+a 1897 1898 2209
+a 1897 4106 1
+a 1898 1899 2208
+a 1898 4106 1
+a 1899 1900 2207
+a 1899 4106 1
+a 1900 1901 2206
+a 1900 4106 1
+a 1901 1902 2205
+a 1901 4106 1
+a 1902 1903 2204
+a 1902 4106 1
+a 1903 1904 2203
+a 1903 4106 1
+a 1904 1905 2202
+a 1904 4106 1
+a 1905 1906 2201
+a 1905 4106 1
+a 1906 1907 2200
+a 1906 4106 1
+a 1907 1908 2199
+a 1907 4106 1
+a 1908 1909 2198
+a 1908 4106 1
+a 1909 1910 2197
+a 1909 4106 1
+a 1910 1911 2196
+a 1910 4106 1
+a 1911 1912 2195
+a 1911 4106 1
+a 1912 1913 2194
+a 1912 4106 1
+a 1913 1914 2193
+a 1913 4106 1
+a 1914 1915 2192
+a 1914 4106 1
+a 1915 1916 2191
+a 1915 4106 1
+a 1916 1917 2190
+a 1916 4106 1
+a 1917 1918 2189
+a 1917 4106 1
+a 1918 1919 2188
+a 1918 4106 1
+a 1919 1920 2187
+a 1919 4106 1
+a 1920 1921 2186
+a 1920 4106 1
+a 1921 1922 2185
+a 1921 4106 1
+a 1922 1923 2184
+a 1922 4106 1
+a 1923 1924 2183
+a 1923 4106 1
+a 1924 1925 2182
+a 1924 4106 1
+a 1925 1926 2181
+a 1925 4106 1
+a 1926 1927 2180
+a 1926 4106 1
+a 1927 1928 2179
+a 1927 4106 1
+a 1928 1929 2178
+a 1928 4106 1
+a 1929 1930 2177
+a 1929 4106 1
+a 1930 1931 2176
+a 1930 4106 1
+a 1931 1932 2175
+a 1931 4106 1
+a 1932 1933 2174
+a 1932 4106 1
+a 1933 1934 2173
+a 1933 4106 1
+a 1934 1935 2172
+a 1934 4106 1
+a 1935 1936 2171
+a 1935 4106 1
+a 1936 1937 2170
+a 1936 4106 1
+a 1937 1938 2169
+a 1937 4106 1
+a 1938 1939 2168
+a 1938 4106 1
+a 1939 1940 2167
+a 1939 4106 1
+a 1940 1941 2166
+a 1940 4106 1
+a 1941 1942 2165
+a 1941 4106 1
+a 1942 1943 2164
+a 1942 4106 1
+a 1943 1944 2163
+a 1943 4106 1
+a 1944 1945 2162
+a 1944 4106 1
+a 1945 1946 2161
+a 1945 4106 1
+a 1946 1947 2160
+a 1946 4106 1
+a 1947 1948 2159
+a 1947 4106 1
+a 1948 1949 2158
+a 1948 4106 1
+a 1949 1950 2157
+a 1949 4106 1
+a 1950 1951 2156
+a 1950 4106 1
+a 1951 1952 2155
+a 1951 4106 1
+a 1952 1953 2154
+a 1952 4106 1
+a 1953 1954 2153
+a 1953 4106 1
+a 1954 1955 2152
+a 1954 4106 1
+a 1955 1956 2151
+a 1955 4106 1
+a 1956 1957 2150
+a 1956 4106 1
+a 1957 1958 2149
+a 1957 4106 1
+a 1958 1959 2148
+a 1958 4106 1
+a 1959 1960 2147
+a 1959 4106 1
+a 1960 1961 2146
+a 1960 4106 1
+a 1961 1962 2145
+a 1961 4106 1
+a 1962 1963 2144
+a 1962 4106 1
+a 1963 1964 2143
+a 1963 4106 1
+a 1964 1965 2142
+a 1964 4106 1
+a 1965 1966 2141
+a 1965 4106 1
+a 1966 1967 2140
+a 1966 4106 1
+a 1967 1968 2139
+a 1967 4106 1
+a 1968 1969 2138
+a 1968 4106 1
+a 1969 1970 2137
+a 1969 4106 1
+a 1970 1971 2136
+a 1970 4106 1
+a 1971 1972 2135
+a 1971 4106 1
+a 1972 1973 2134
+a 1972 4106 1
+a 1973 1974 2133
+a 1973 4106 1
+a 1974 1975 2132
+a 1974 4106 1
+a 1975 1976 2131
+a 1975 4106 1
+a 1976 1977 2130
+a 1976 4106 1
+a 1977 1978 2129
+a 1977 4106 1
+a 1978 1979 2128
+a 1978 4106 1
+a 1979 1980 2127
+a 1979 4106 1
+a 1980 1981 2126
+a 1980 4106 1
+a 1981 1982 2125
+a 1981 4106 1
+a 1982 1983 2124
+a 1982 4106 1
+a 1983 1984 2123
+a 1983 4106 1
+a 1984 1985 2122
+a 1984 4106 1
+a 1985 1986 2121
+a 1985 4106 1
+a 1986 1987 2120
+a 1986 4106 1
+a 1987 1988 2119
+a 1987 4106 1
+a 1988 1989 2118
+a 1988 4106 1
+a 1989 1990 2117
+a 1989 4106 1
+a 1990 1991 2116
+a 1990 4106 1
+a 1991 1992 2115
+a 1991 4106 1
+a 1992 1993 2114
+a 1992 4106 1
+a 1993 1994 2113
+a 1993 4106 1
+a 1994 1995 2112
+a 1994 4106 1
+a 1995 1996 2111
+a 1995 4106 1
+a 1996 1997 2110
+a 1996 4106 1
+a 1997 1998 2109
+a 1997 4106 1
+a 1998 1999 2108
+a 1998 4106 1
+a 1999 2000 2107
+a 1999 4106 1
+a 2000 2001 2106
+a 2000 4106 1
+a 2001 2002 2105
+a 2001 4106 1
+a 2002 2003 2104
+a 2002 4106 1
+a 2003 2004 2103
+a 2003 4106 1
+a 2004 2005 2102
+a 2004 4106 1
+a 2005 2006 2101
+a 2005 4106 1
+a 2006 2007 2100
+a 2006 4106 1
+a 2007 2008 2099
+a 2007 4106 1
+a 2008 2009 2098
+a 2008 4106 1
+a 2009 2010 2097
+a 2009 4106 1
+a 2010 2011 2096
+a 2010 4106 1
+a 2011 2012 2095
+a 2011 4106 1
+a 2012 2013 2094
+a 2012 4106 1
+a 2013 2014 2093
+a 2013 4106 1
+a 2014 2015 2092
+a 2014 4106 1
+a 2015 2016 2091
+a 2015 4106 1
+a 2016 2017 2090
+a 2016 4106 1
+a 2017 2018 2089
+a 2017 4106 1
+a 2018 2019 2088
+a 2018 4106 1
+a 2019 2020 2087
+a 2019 4106 1
+a 2020 2021 2086
+a 2020 4106 1
+a 2021 2022 2085
+a 2021 4106 1
+a 2022 2023 2084
+a 2022 4106 1
+a 2023 2024 2083
+a 2023 4106 1
+a 2024 2025 2082
+a 2024 4106 1
+a 2025 2026 2081
+a 2025 4106 1
+a 2026 2027 2080
+a 2026 4106 1
+a 2027 2028 2079
+a 2027 4106 1
+a 2028 2029 2078
+a 2028 4106 1
+a 2029 2030 2077
+a 2029 4106 1
+a 2030 2031 2076
+a 2030 4106 1
+a 2031 2032 2075
+a 2031 4106 1
+a 2032 2033 2074
+a 2032 4106 1
+a 2033 2034 2073
+a 2033 4106 1
+a 2034 2035 2072
+a 2034 4106 1
+a 2035 2036 2071
+a 2035 4106 1
+a 2036 2037 2070
+a 2036 4106 1
+a 2037 2038 2069
+a 2037 4106 1
+a 2038 2039 2068
+a 2038 4106 1
+a 2039 2040 2067
+a 2039 4106 1
+a 2040 2041 2066
+a 2040 4106 1
+a 2041 2042 2065
+a 2041 4106 1
+a 2042 2043 2064
+a 2042 4106 1
+a 2043 2044 2063
+a 2043 4106 1
+a 2044 2045 2062
+a 2044 4106 1
+a 2045 2046 2061
+a 2045 4106 1
+a 2046 2047 2060
+a 2046 4106 1
+a 2047 2048 2059
+a 2047 4106 1
+a 2048 2049 2058
+a 2048 4106 1
+a 2049 2050 2057
+a 2049 4106 1
+a 2050 2051 2056
+a 2050 4106 1
+a 2051 2052 2055
+a 2051 4106 1
+a 2052 2053 2054
+a 2052 4106 1
+a 2053 2054 2053
+a 2053 4106 1
+a 2054 2055 2052
+a 2054 4106 1
+a 2055 2056 2051
+a 2055 4106 1
+a 2056 2057 2050
+a 2056 4106 1
+a 2057 2058 2049
+a 2057 4106 1
+a 2058 2059 2048
+a 2058 4106 1
+a 2059 2060 2047
+a 2059 4106 1
+a 2060 2061 2046
+a 2060 4106 1
+a 2061 2062 2045
+a 2061 4106 1
+a 2062 2063 2044
+a 2062 4106 1
+a 2063 2064 2043
+a 2063 4106 1
+a 2064 2065 2042
+a 2064 4106 1
+a 2065 2066 2041
+a 2065 4106 1
+a 2066 2067 2040
+a 2066 4106 1
+a 2067 2068 2039
+a 2067 4106 1
+a 2068 2069 2038
+a 2068 4106 1
+a 2069 2070 2037
+a 2069 4106 1
+a 2070 2071 2036
+a 2070 4106 1
+a 2071 2072 2035
+a 2071 4106 1
+a 2072 2073 2034
+a 2072 4106 1
+a 2073 2074 2033
+a 2073 4106 1
+a 2074 2075 2032
+a 2074 4106 1
+a 2075 2076 2031
+a 2075 4106 1
+a 2076 2077 2030
+a 2076 4106 1
+a 2077 2078 2029
+a 2077 4106 1
+a 2078 2079 2028
+a 2078 4106 1
+a 2079 2080 2027
+a 2079 4106 1
+a 2080 2081 2026
+a 2080 4106 1
+a 2081 2082 2025
+a 2081 4106 1
+a 2082 2083 2024
+a 2082 4106 1
+a 2083 2084 2023
+a 2083 4106 1
+a 2084 2085 2022
+a 2084 4106 1
+a 2085 2086 2021
+a 2085 4106 1
+a 2086 2087 2020
+a 2086 4106 1
+a 2087 2088 2019
+a 2087 4106 1
+a 2088 2089 2018
+a 2088 4106 1
+a 2089 2090 2017
+a 2089 4106 1
+a 2090 2091 2016
+a 2090 4106 1
+a 2091 2092 2015
+a 2091 4106 1
+a 2092 2093 2014
+a 2092 4106 1
+a 2093 2094 2013
+a 2093 4106 1
+a 2094 2095 2012
+a 2094 4106 1
+a 2095 2096 2011
+a 2095 4106 1
+a 2096 2097 2010
+a 2096 4106 1
+a 2097 2098 2009
+a 2097 4106 1
+a 2098 2099 2008
+a 2098 4106 1
+a 2099 2100 2007
+a 2099 4106 1
+a 2100 2101 2006
+a 2100 4106 1
+a 2101 2102 2005
+a 2101 4106 1
+a 2102 2103 2004
+a 2102 4106 1
+a 2103 2104 2003
+a 2103 4106 1
+a 2104 2105 2002
+a 2104 4106 1
+a 2105 2106 2001
+a 2105 4106 1
+a 2106 2107 2000
+a 2106 4106 1
+a 2107 2108 1999
+a 2107 4106 1
+a 2108 2109 1998
+a 2108 4106 1
+a 2109 2110 1997
+a 2109 4106 1
+a 2110 2111 1996
+a 2110 4106 1
+a 2111 2112 1995
+a 2111 4106 1
+a 2112 2113 1994
+a 2112 4106 1
+a 2113 2114 1993
+a 2113 4106 1
+a 2114 2115 1992
+a 2114 4106 1
+a 2115 2116 1991
+a 2115 4106 1
+a 2116 2117 1990
+a 2116 4106 1
+a 2117 2118 1989
+a 2117 4106 1
+a 2118 2119 1988
+a 2118 4106 1
+a 2119 2120 1987
+a 2119 4106 1
+a 2120 2121 1986
+a 2120 4106 1
+a 2121 2122 1985
+a 2121 4106 1
+a 2122 2123 1984
+a 2122 4106 1
+a 2123 2124 1983
+a 2123 4106 1
+a 2124 2125 1982
+a 2124 4106 1
+a 2125 2126 1981
+a 2125 4106 1
+a 2126 2127 1980
+a 2126 4106 1
+a 2127 2128 1979
+a 2127 4106 1
+a 2128 2129 1978
+a 2128 4106 1
+a 2129 2130 1977
+a 2129 4106 1
+a 2130 2131 1976
+a 2130 4106 1
+a 2131 2132 1975
+a 2131 4106 1
+a 2132 2133 1974
+a 2132 4106 1
+a 2133 2134 1973
+a 2133 4106 1
+a 2134 2135 1972
+a 2134 4106 1
+a 2135 2136 1971
+a 2135 4106 1
+a 2136 2137 1970
+a 2136 4106 1
+a 2137 2138 1969
+a 2137 4106 1
+a 2138 2139 1968
+a 2138 4106 1
+a 2139 2140 1967
+a 2139 4106 1
+a 2140 2141 1966
+a 2140 4106 1
+a 2141 2142 1965
+a 2141 4106 1
+a 2142 2143 1964
+a 2142 4106 1
+a 2143 2144 1963
+a 2143 4106 1
+a 2144 2145 1962
+a 2144 4106 1
+a 2145 2146 1961
+a 2145 4106 1
+a 2146 2147 1960
+a 2146 4106 1
+a 2147 2148 1959
+a 2147 4106 1
+a 2148 2149 1958
+a 2148 4106 1
+a 2149 2150 1957
+a 2149 4106 1
+a 2150 2151 1956
+a 2150 4106 1
+a 2151 2152 1955
+a 2151 4106 1
+a 2152 2153 1954
+a 2152 4106 1
+a 2153 2154 1953
+a 2153 4106 1
+a 2154 2155 1952
+a 2154 4106 1
+a 2155 2156 1951
+a 2155 4106 1
+a 2156 2157 1950
+a 2156 4106 1
+a 2157 2158 1949
+a 2157 4106 1
+a 2158 2159 1948
+a 2158 4106 1
+a 2159 2160 1947
+a 2159 4106 1
+a 2160 2161 1946
+a 2160 4106 1
+a 2161 2162 1945
+a 2161 4106 1
+a 2162 2163 1944
+a 2162 4106 1
+a 2163 2164 1943
+a 2163 4106 1
+a 2164 2165 1942
+a 2164 4106 1
+a 2165 2166 1941
+a 2165 4106 1
+a 2166 2167 1940
+a 2166 4106 1
+a 2167 2168 1939
+a 2167 4106 1
+a 2168 2169 1938
+a 2168 4106 1
+a 2169 2170 1937
+a 2169 4106 1
+a 2170 2171 1936
+a 2170 4106 1
+a 2171 2172 1935
+a 2171 4106 1
+a 2172 2173 1934
+a 2172 4106 1
+a 2173 2174 1933
+a 2173 4106 1
+a 2174 2175 1932
+a 2174 4106 1
+a 2175 2176 1931
+a 2175 4106 1
+a 2176 2177 1930
+a 2176 4106 1
+a 2177 2178 1929
+a 2177 4106 1
+a 2178 2179 1928
+a 2178 4106 1
+a 2179 2180 1927
+a 2179 4106 1
+a 2180 2181 1926
+a 2180 4106 1
+a 2181 2182 1925
+a 2181 4106 1
+a 2182 2183 1924
+a 2182 4106 1
+a 2183 2184 1923
+a 2183 4106 1
+a 2184 2185 1922
+a 2184 4106 1
+a 2185 2186 1921
+a 2185 4106 1
+a 2186 2187 1920
+a 2186 4106 1
+a 2187 2188 1919
+a 2187 4106 1
+a 2188 2189 1918
+a 2188 4106 1
+a 2189 2190 1917
+a 2189 4106 1
+a 2190 2191 1916
+a 2190 4106 1
+a 2191 2192 1915
+a 2191 4106 1
+a 2192 2193 1914
+a 2192 4106 1
+a 2193 2194 1913
+a 2193 4106 1
+a 2194 2195 1912
+a 2194 4106 1
+a 2195 2196 1911
+a 2195 4106 1
+a 2196 2197 1910
+a 2196 4106 1
+a 2197 2198 1909
+a 2197 4106 1
+a 2198 2199 1908
+a 2198 4106 1
+a 2199 2200 1907
+a 2199 4106 1
+a 2200 2201 1906
+a 2200 4106 1
+a 2201 2202 1905
+a 2201 4106 1
+a 2202 2203 1904
+a 2202 4106 1
+a 2203 2204 1903
+a 2203 4106 1
+a 2204 2205 1902
+a 2204 4106 1
+a 2205 2206 1901
+a 2205 4106 1
+a 2206 2207 1900
+a 2206 4106 1
+a 2207 2208 1899
+a 2207 4106 1
+a 2208 2209 1898
+a 2208 4106 1
+a 2209 2210 1897
+a 2209 4106 1
+a 2210 2211 1896
+a 2210 4106 1
+a 2211 2212 1895
+a 2211 4106 1
+a 2212 2213 1894
+a 2212 4106 1
+a 2213 2214 1893
+a 2213 4106 1
+a 2214 2215 1892
+a 2214 4106 1
+a 2215 2216 1891
+a 2215 4106 1
+a 2216 2217 1890
+a 2216 4106 1
+a 2217 2218 1889
+a 2217 4106 1
+a 2218 2219 1888
+a 2218 4106 1
+a 2219 2220 1887
+a 2219 4106 1
+a 2220 2221 1886
+a 2220 4106 1
+a 2221 2222 1885
+a 2221 4106 1
+a 2222 2223 1884
+a 2222 4106 1
+a 2223 2224 1883
+a 2223 4106 1
+a 2224 2225 1882
+a 2224 4106 1
+a 2225 2226 1881
+a 2225 4106 1
+a 2226 2227 1880
+a 2226 4106 1
+a 2227 2228 1879
+a 2227 4106 1
+a 2228 2229 1878
+a 2228 4106 1
+a 2229 2230 1877
+a 2229 4106 1
+a 2230 2231 1876
+a 2230 4106 1
+a 2231 2232 1875
+a 2231 4106 1
+a 2232 2233 1874
+a 2232 4106 1
+a 2233 2234 1873
+a 2233 4106 1
+a 2234 2235 1872
+a 2234 4106 1
+a 2235 2236 1871
+a 2235 4106 1
+a 2236 2237 1870
+a 2236 4106 1
+a 2237 2238 1869
+a 2237 4106 1
+a 2238 2239 1868
+a 2238 4106 1
+a 2239 2240 1867
+a 2239 4106 1
+a 2240 2241 1866
+a 2240 4106 1
+a 2241 2242 1865
+a 2241 4106 1
+a 2242 2243 1864
+a 2242 4106 1
+a 2243 2244 1863
+a 2243 4106 1
+a 2244 2245 1862
+a 2244 4106 1
+a 2245 2246 1861
+a 2245 4106 1
+a 2246 2247 1860
+a 2246 4106 1
+a 2247 2248 1859
+a 2247 4106 1
+a 2248 2249 1858
+a 2248 4106 1
+a 2249 2250 1857
+a 2249 4106 1
+a 2250 2251 1856
+a 2250 4106 1
+a 2251 2252 1855
+a 2251 4106 1
+a 2252 2253 1854
+a 2252 4106 1
+a 2253 2254 1853
+a 2253 4106 1
+a 2254 2255 1852
+a 2254 4106 1
+a 2255 2256 1851
+a 2255 4106 1
+a 2256 2257 1850
+a 2256 4106 1
+a 2257 2258 1849
+a 2257 4106 1
+a 2258 2259 1848
+a 2258 4106 1
+a 2259 2260 1847
+a 2259 4106 1
+a 2260 2261 1846
+a 2260 4106 1
+a 2261 2262 1845
+a 2261 4106 1
+a 2262 2263 1844
+a 2262 4106 1
+a 2263 2264 1843
+a 2263 4106 1
+a 2264 2265 1842
+a 2264 4106 1
+a 2265 2266 1841
+a 2265 4106 1
+a 2266 2267 1840
+a 2266 4106 1
+a 2267 2268 1839
+a 2267 4106 1
+a 2268 2269 1838
+a 2268 4106 1
+a 2269 2270 1837
+a 2269 4106 1
+a 2270 2271 1836
+a 2270 4106 1
+a 2271 2272 1835
+a 2271 4106 1
+a 2272 2273 1834
+a 2272 4106 1
+a 2273 2274 1833
+a 2273 4106 1
+a 2274 2275 1832
+a 2274 4106 1
+a 2275 2276 1831
+a 2275 4106 1
+a 2276 2277 1830
+a 2276 4106 1
+a 2277 2278 1829
+a 2277 4106 1
+a 2278 2279 1828
+a 2278 4106 1
+a 2279 2280 1827
+a 2279 4106 1
+a 2280 2281 1826
+a 2280 4106 1
+a 2281 2282 1825
+a 2281 4106 1
+a 2282 2283 1824
+a 2282 4106 1
+a 2283 2284 1823
+a 2283 4106 1
+a 2284 2285 1822
+a 2284 4106 1
+a 2285 2286 1821
+a 2285 4106 1
+a 2286 2287 1820
+a 2286 4106 1
+a 2287 2288 1819
+a 2287 4106 1
+a 2288 2289 1818
+a 2288 4106 1
+a 2289 2290 1817
+a 2289 4106 1
+a 2290 2291 1816
+a 2290 4106 1
+a 2291 2292 1815
+a 2291 4106 1
+a 2292 2293 1814
+a 2292 4106 1
+a 2293 2294 1813
+a 2293 4106 1
+a 2294 2295 1812
+a 2294 4106 1
+a 2295 2296 1811
+a 2295 4106 1
+a 2296 2297 1810
+a 2296 4106 1
+a 2297 2298 1809
+a 2297 4106 1
+a 2298 2299 1808
+a 2298 4106 1
+a 2299 2300 1807
+a 2299 4106 1
+a 2300 2301 1806
+a 2300 4106 1
+a 2301 2302 1805
+a 2301 4106 1
+a 2302 2303 1804
+a 2302 4106 1
+a 2303 2304 1803
+a 2303 4106 1
+a 2304 2305 1802
+a 2304 4106 1
+a 2305 2306 1801
+a 2305 4106 1
+a 2306 2307 1800
+a 2306 4106 1
+a 2307 2308 1799
+a 2307 4106 1
+a 2308 2309 1798
+a 2308 4106 1
+a 2309 2310 1797
+a 2309 4106 1
+a 2310 2311 1796
+a 2310 4106 1
+a 2311 2312 1795
+a 2311 4106 1
+a 2312 2313 1794
+a 2312 4106 1
+a 2313 2314 1793
+a 2313 4106 1
+a 2314 2315 1792
+a 2314 4106 1
+a 2315 2316 1791
+a 2315 4106 1
+a 2316 2317 1790
+a 2316 4106 1
+a 2317 2318 1789
+a 2317 4106 1
+a 2318 2319 1788
+a 2318 4106 1
+a 2319 2320 1787
+a 2319 4106 1
+a 2320 2321 1786
+a 2320 4106 1
+a 2321 2322 1785
+a 2321 4106 1
+a 2322 2323 1784
+a 2322 4106 1
+a 2323 2324 1783
+a 2323 4106 1
+a 2324 2325 1782
+a 2324 4106 1
+a 2325 2326 1781
+a 2325 4106 1
+a 2326 2327 1780
+a 2326 4106 1
+a 2327 2328 1779
+a 2327 4106 1
+a 2328 2329 1778
+a 2328 4106 1
+a 2329 2330 1777
+a 2329 4106 1
+a 2330 2331 1776
+a 2330 4106 1
+a 2331 2332 1775
+a 2331 4106 1
+a 2332 2333 1774
+a 2332 4106 1
+a 2333 2334 1773
+a 2333 4106 1
+a 2334 2335 1772
+a 2334 4106 1
+a 2335 2336 1771
+a 2335 4106 1
+a 2336 2337 1770
+a 2336 4106 1
+a 2337 2338 1769
+a 2337 4106 1
+a 2338 2339 1768
+a 2338 4106 1
+a 2339 2340 1767
+a 2339 4106 1
+a 2340 2341 1766
+a 2340 4106 1
+a 2341 2342 1765
+a 2341 4106 1
+a 2342 2343 1764
+a 2342 4106 1
+a 2343 2344 1763
+a 2343 4106 1
+a 2344 2345 1762
+a 2344 4106 1
+a 2345 2346 1761
+a 2345 4106 1
+a 2346 2347 1760
+a 2346 4106 1
+a 2347 2348 1759
+a 2347 4106 1
+a 2348 2349 1758
+a 2348 4106 1
+a 2349 2350 1757
+a 2349 4106 1
+a 2350 2351 1756
+a 2350 4106 1
+a 2351 2352 1755
+a 2351 4106 1
+a 2352 2353 1754
+a 2352 4106 1
+a 2353 2354 1753
+a 2353 4106 1
+a 2354 2355 1752
+a 2354 4106 1
+a 2355 2356 1751
+a 2355 4106 1
+a 2356 2357 1750
+a 2356 4106 1
+a 2357 2358 1749
+a 2357 4106 1
+a 2358 2359 1748
+a 2358 4106 1
+a 2359 2360 1747
+a 2359 4106 1
+a 2360 2361 1746
+a 2360 4106 1
+a 2361 2362 1745
+a 2361 4106 1
+a 2362 2363 1744
+a 2362 4106 1
+a 2363 2364 1743
+a 2363 4106 1
+a 2364 2365 1742
+a 2364 4106 1
+a 2365 2366 1741
+a 2365 4106 1
+a 2366 2367 1740
+a 2366 4106 1
+a 2367 2368 1739
+a 2367 4106 1
+a 2368 2369 1738
+a 2368 4106 1
+a 2369 2370 1737
+a 2369 4106 1
+a 2370 2371 1736
+a 2370 4106 1
+a 2371 2372 1735
+a 2371 4106 1
+a 2372 2373 1734
+a 2372 4106 1
+a 2373 2374 1733
+a 2373 4106 1
+a 2374 2375 1732
+a 2374 4106 1
+a 2375 2376 1731
+a 2375 4106 1
+a 2376 2377 1730
+a 2376 4106 1
+a 2377 2378 1729
+a 2377 4106 1
+a 2378 2379 1728
+a 2378 4106 1
+a 2379 2380 1727
+a 2379 4106 1
+a 2380 2381 1726
+a 2380 4106 1
+a 2381 2382 1725
+a 2381 4106 1
+a 2382 2383 1724
+a 2382 4106 1
+a 2383 2384 1723
+a 2383 4106 1
+a 2384 2385 1722
+a 2384 4106 1
+a 2385 2386 1721
+a 2385 4106 1
+a 2386 2387 1720
+a 2386 4106 1
+a 2387 2388 1719
+a 2387 4106 1
+a 2388 2389 1718
+a 2388 4106 1
+a 2389 2390 1717
+a 2389 4106 1
+a 2390 2391 1716
+a 2390 4106 1
+a 2391 2392 1715
+a 2391 4106 1
+a 2392 2393 1714
+a 2392 4106 1
+a 2393 2394 1713
+a 2393 4106 1
+a 2394 2395 1712
+a 2394 4106 1
+a 2395 2396 1711
+a 2395 4106 1
+a 2396 2397 1710
+a 2396 4106 1
+a 2397 2398 1709
+a 2397 4106 1
+a 2398 2399 1708
+a 2398 4106 1
+a 2399 2400 1707
+a 2399 4106 1
+a 2400 2401 1706
+a 2400 4106 1
+a 2401 2402 1705
+a 2401 4106 1
+a 2402 2403 1704
+a 2402 4106 1
+a 2403 2404 1703
+a 2403 4106 1
+a 2404 2405 1702
+a 2404 4106 1
+a 2405 2406 1701
+a 2405 4106 1
+a 2406 2407 1700
+a 2406 4106 1
+a 2407 2408 1699
+a 2407 4106 1
+a 2408 2409 1698
+a 2408 4106 1
+a 2409 2410 1697
+a 2409 4106 1
+a 2410 2411 1696
+a 2410 4106 1
+a 2411 2412 1695
+a 2411 4106 1
+a 2412 2413 1694
+a 2412 4106 1
+a 2413 2414 1693
+a 2413 4106 1
+a 2414 2415 1692
+a 2414 4106 1
+a 2415 2416 1691
+a 2415 4106 1
+a 2416 2417 1690
+a 2416 4106 1
+a 2417 2418 1689
+a 2417 4106 1
+a 2418 2419 1688
+a 2418 4106 1
+a 2419 2420 1687
+a 2419 4106 1
+a 2420 2421 1686
+a 2420 4106 1
+a 2421 2422 1685
+a 2421 4106 1
+a 2422 2423 1684
+a 2422 4106 1
+a 2423 2424 1683
+a 2423 4106 1
+a 2424 2425 1682
+a 2424 4106 1
+a 2425 2426 1681
+a 2425 4106 1
+a 2426 2427 1680
+a 2426 4106 1
+a 2427 2428 1679
+a 2427 4106 1
+a 2428 2429 1678
+a 2428 4106 1
+a 2429 2430 1677
+a 2429 4106 1
+a 2430 2431 1676
+a 2430 4106 1
+a 2431 2432 1675
+a 2431 4106 1
+a 2432 2433 1674
+a 2432 4106 1
+a 2433 2434 1673
+a 2433 4106 1
+a 2434 2435 1672
+a 2434 4106 1
+a 2435 2436 1671
+a 2435 4106 1
+a 2436 2437 1670
+a 2436 4106 1
+a 2437 2438 1669
+a 2437 4106 1
+a 2438 2439 1668
+a 2438 4106 1
+a 2439 2440 1667
+a 2439 4106 1
+a 2440 2441 1666
+a 2440 4106 1
+a 2441 2442 1665
+a 2441 4106 1
+a 2442 2443 1664
+a 2442 4106 1
+a 2443 2444 1663
+a 2443 4106 1
+a 2444 2445 1662
+a 2444 4106 1
+a 2445 2446 1661
+a 2445 4106 1
+a 2446 2447 1660
+a 2446 4106 1
+a 2447 2448 1659
+a 2447 4106 1
+a 2448 2449 1658
+a 2448 4106 1
+a 2449 2450 1657
+a 2449 4106 1
+a 2450 2451 1656
+a 2450 4106 1
+a 2451 2452 1655
+a 2451 4106 1
+a 2452 2453 1654
+a 2452 4106 1
+a 2453 2454 1653
+a 2453 4106 1
+a 2454 2455 1652
+a 2454 4106 1
+a 2455 2456 1651
+a 2455 4106 1
+a 2456 2457 1650
+a 2456 4106 1
+a 2457 2458 1649
+a 2457 4106 1
+a 2458 2459 1648
+a 2458 4106 1
+a 2459 2460 1647
+a 2459 4106 1
+a 2460 2461 1646
+a 2460 4106 1
+a 2461 2462 1645
+a 2461 4106 1
+a 2462 2463 1644
+a 2462 4106 1
+a 2463 2464 1643
+a 2463 4106 1
+a 2464 2465 1642
+a 2464 4106 1
+a 2465 2466 1641
+a 2465 4106 1
+a 2466 2467 1640
+a 2466 4106 1
+a 2467 2468 1639
+a 2467 4106 1
+a 2468 2469 1638
+a 2468 4106 1
+a 2469 2470 1637
+a 2469 4106 1
+a 2470 2471 1636
+a 2470 4106 1
+a 2471 2472 1635
+a 2471 4106 1
+a 2472 2473 1634
+a 2472 4106 1
+a 2473 2474 1633
+a 2473 4106 1
+a 2474 2475 1632
+a 2474 4106 1
+a 2475 2476 1631
+a 2475 4106 1
+a 2476 2477 1630
+a 2476 4106 1
+a 2477 2478 1629
+a 2477 4106 1
+a 2478 2479 1628
+a 2478 4106 1
+a 2479 2480 1627
+a 2479 4106 1
+a 2480 2481 1626
+a 2480 4106 1
+a 2481 2482 1625
+a 2481 4106 1
+a 2482 2483 1624
+a 2482 4106 1
+a 2483 2484 1623
+a 2483 4106 1
+a 2484 2485 1622
+a 2484 4106 1
+a 2485 2486 1621
+a 2485 4106 1
+a 2486 2487 1620
+a 2486 4106 1
+a 2487 2488 1619
+a 2487 4106 1
+a 2488 2489 1618
+a 2488 4106 1
+a 2489 2490 1617
+a 2489 4106 1
+a 2490 2491 1616
+a 2490 4106 1
+a 2491 2492 1615
+a 2491 4106 1
+a 2492 2493 1614
+a 2492 4106 1
+a 2493 2494 1613
+a 2493 4106 1
+a 2494 2495 1612
+a 2494 4106 1
+a 2495 2496 1611
+a 2495 4106 1
+a 2496 2497 1610
+a 2496 4106 1
+a 2497 2498 1609
+a 2497 4106 1
+a 2498 2499 1608
+a 2498 4106 1
+a 2499 2500 1607
+a 2499 4106 1
+a 2500 2501 1606
+a 2500 4106 1
+a 2501 2502 1605
+a 2501 4106 1
+a 2502 2503 1604
+a 2502 4106 1
+a 2503 2504 1603
+a 2503 4106 1
+a 2504 2505 1602
+a 2504 4106 1
+a 2505 2506 1601
+a 2505 4106 1
+a 2506 2507 1600
+a 2506 4106 1
+a 2507 2508 1599
+a 2507 4106 1
+a 2508 2509 1598
+a 2508 4106 1
+a 2509 2510 1597
+a 2509 4106 1
+a 2510 2511 1596
+a 2510 4106 1
+a 2511 2512 1595
+a 2511 4106 1
+a 2512 2513 1594
+a 2512 4106 1
+a 2513 2514 1593
+a 2513 4106 1
+a 2514 2515 1592
+a 2514 4106 1
+a 2515 2516 1591
+a 2515 4106 1
+a 2516 2517 1590
+a 2516 4106 1
+a 2517 2518 1589
+a 2517 4106 1
+a 2518 2519 1588
+a 2518 4106 1
+a 2519 2520 1587
+a 2519 4106 1
+a 2520 2521 1586
+a 2520 4106 1
+a 2521 2522 1585
+a 2521 4106 1
+a 2522 2523 1584
+a 2522 4106 1
+a 2523 2524 1583
+a 2523 4106 1
+a 2524 2525 1582
+a 2524 4106 1
+a 2525 2526 1581
+a 2525 4106 1
+a 2526 2527 1580
+a 2526 4106 1
+a 2527 2528 1579
+a 2527 4106 1
+a 2528 2529 1578
+a 2528 4106 1
+a 2529 2530 1577
+a 2529 4106 1
+a 2530 2531 1576
+a 2530 4106 1
+a 2531 2532 1575
+a 2531 4106 1
+a 2532 2533 1574
+a 2532 4106 1
+a 2533 2534 1573
+a 2533 4106 1
+a 2534 2535 1572
+a 2534 4106 1
+a 2535 2536 1571
+a 2535 4106 1
+a 2536 2537 1570
+a 2536 4106 1
+a 2537 2538 1569
+a 2537 4106 1
+a 2538 2539 1568
+a 2538 4106 1
+a 2539 2540 1567
+a 2539 4106 1
+a 2540 2541 1566
+a 2540 4106 1
+a 2541 2542 1565
+a 2541 4106 1
+a 2542 2543 1564
+a 2542 4106 1
+a 2543 2544 1563
+a 2543 4106 1
+a 2544 2545 1562
+a 2544 4106 1
+a 2545 2546 1561
+a 2545 4106 1
+a 2546 2547 1560
+a 2546 4106 1
+a 2547 2548 1559
+a 2547 4106 1
+a 2548 2549 1558
+a 2548 4106 1
+a 2549 2550 1557
+a 2549 4106 1
+a 2550 2551 1556
+a 2550 4106 1
+a 2551 2552 1555
+a 2551 4106 1
+a 2552 2553 1554
+a 2552 4106 1
+a 2553 2554 1553
+a 2553 4106 1
+a 2554 2555 1552
+a 2554 4106 1
+a 2555 2556 1551
+a 2555 4106 1
+a 2556 2557 1550
+a 2556 4106 1
+a 2557 2558 1549
+a 2557 4106 1
+a 2558 2559 1548
+a 2558 4106 1
+a 2559 2560 1547
+a 2559 4106 1
+a 2560 2561 1546
+a 2560 4106 1
+a 2561 2562 1545
+a 2561 4106 1
+a 2562 2563 1544
+a 2562 4106 1
+a 2563 2564 1543
+a 2563 4106 1
+a 2564 2565 1542
+a 2564 4106 1
+a 2565 2566 1541
+a 2565 4106 1
+a 2566 2567 1540
+a 2566 4106 1
+a 2567 2568 1539
+a 2567 4106 1
+a 2568 2569 1538
+a 2568 4106 1
+a 2569 2570 1537
+a 2569 4106 1
+a 2570 2571 1536
+a 2570 4106 1
+a 2571 2572 1535
+a 2571 4106 1
+a 2572 2573 1534
+a 2572 4106 1
+a 2573 2574 1533
+a 2573 4106 1
+a 2574 2575 1532
+a 2574 4106 1
+a 2575 2576 1531
+a 2575 4106 1
+a 2576 2577 1530
+a 2576 4106 1
+a 2577 2578 1529
+a 2577 4106 1
+a 2578 2579 1528
+a 2578 4106 1
+a 2579 2580 1527
+a 2579 4106 1
+a 2580 2581 1526
+a 2580 4106 1
+a 2581 2582 1525
+a 2581 4106 1
+a 2582 2583 1524
+a 2582 4106 1
+a 2583 2584 1523
+a 2583 4106 1
+a 2584 2585 1522
+a 2584 4106 1
+a 2585 2586 1521
+a 2585 4106 1
+a 2586 2587 1520
+a 2586 4106 1
+a 2587 2588 1519
+a 2587 4106 1
+a 2588 2589 1518
+a 2588 4106 1
+a 2589 2590 1517
+a 2589 4106 1
+a 2590 2591 1516
+a 2590 4106 1
+a 2591 2592 1515
+a 2591 4106 1
+a 2592 2593 1514
+a 2592 4106 1
+a 2593 2594 1513
+a 2593 4106 1
+a 2594 2595 1512
+a 2594 4106 1
+a 2595 2596 1511
+a 2595 4106 1
+a 2596 2597 1510
+a 2596 4106 1
+a 2597 2598 1509
+a 2597 4106 1
+a 2598 2599 1508
+a 2598 4106 1
+a 2599 2600 1507
+a 2599 4106 1
+a 2600 2601 1506
+a 2600 4106 1
+a 2601 2602 1505
+a 2601 4106 1
+a 2602 2603 1504
+a 2602 4106 1
+a 2603 2604 1503
+a 2603 4106 1
+a 2604 2605 1502
+a 2604 4106 1
+a 2605 2606 1501
+a 2605 4106 1
+a 2606 2607 1500
+a 2606 4106 1
+a 2607 2608 1499
+a 2607 4106 1
+a 2608 2609 1498
+a 2608 4106 1
+a 2609 2610 1497
+a 2609 4106 1
+a 2610 2611 1496
+a 2610 4106 1
+a 2611 2612 1495
+a 2611 4106 1
+a 2612 2613 1494
+a 2612 4106 1
+a 2613 2614 1493
+a 2613 4106 1
+a 2614 2615 1492
+a 2614 4106 1
+a 2615 2616 1491
+a 2615 4106 1
+a 2616 2617 1490
+a 2616 4106 1
+a 2617 2618 1489
+a 2617 4106 1
+a 2618 2619 1488
+a 2618 4106 1
+a 2619 2620 1487
+a 2619 4106 1
+a 2620 2621 1486
+a 2620 4106 1
+a 2621 2622 1485
+a 2621 4106 1
+a 2622 2623 1484
+a 2622 4106 1
+a 2623 2624 1483
+a 2623 4106 1
+a 2624 2625 1482
+a 2624 4106 1
+a 2625 2626 1481
+a 2625 4106 1
+a 2626 2627 1480
+a 2626 4106 1
+a 2627 2628 1479
+a 2627 4106 1
+a 2628 2629 1478
+a 2628 4106 1
+a 2629 2630 1477
+a 2629 4106 1
+a 2630 2631 1476
+a 2630 4106 1
+a 2631 2632 1475
+a 2631 4106 1
+a 2632 2633 1474
+a 2632 4106 1
+a 2633 2634 1473
+a 2633 4106 1
+a 2634 2635 1472
+a 2634 4106 1
+a 2635 2636 1471
+a 2635 4106 1
+a 2636 2637 1470
+a 2636 4106 1
+a 2637 2638 1469
+a 2637 4106 1
+a 2638 2639 1468
+a 2638 4106 1
+a 2639 2640 1467
+a 2639 4106 1
+a 2640 2641 1466
+a 2640 4106 1
+a 2641 2642 1465
+a 2641 4106 1
+a 2642 2643 1464
+a 2642 4106 1
+a 2643 2644 1463
+a 2643 4106 1
+a 2644 2645 1462
+a 2644 4106 1
+a 2645 2646 1461
+a 2645 4106 1
+a 2646 2647 1460
+a 2646 4106 1
+a 2647 2648 1459
+a 2647 4106 1
+a 2648 2649 1458
+a 2648 4106 1
+a 2649 2650 1457
+a 2649 4106 1
+a 2650 2651 1456
+a 2650 4106 1
+a 2651 2652 1455
+a 2651 4106 1
+a 2652 2653 1454
+a 2652 4106 1
+a 2653 2654 1453
+a 2653 4106 1
+a 2654 2655 1452
+a 2654 4106 1
+a 2655 2656 1451
+a 2655 4106 1
+a 2656 2657 1450
+a 2656 4106 1
+a 2657 2658 1449
+a 2657 4106 1
+a 2658 2659 1448
+a 2658 4106 1
+a 2659 2660 1447
+a 2659 4106 1
+a 2660 2661 1446
+a 2660 4106 1
+a 2661 2662 1445
+a 2661 4106 1
+a 2662 2663 1444
+a 2662 4106 1
+a 2663 2664 1443
+a 2663 4106 1
+a 2664 2665 1442
+a 2664 4106 1
+a 2665 2666 1441
+a 2665 4106 1
+a 2666 2667 1440
+a 2666 4106 1
+a 2667 2668 1439
+a 2667 4106 1
+a 2668 2669 1438
+a 2668 4106 1
+a 2669 2670 1437
+a 2669 4106 1
+a 2670 2671 1436
+a 2670 4106 1
+a 2671 2672 1435
+a 2671 4106 1
+a 2672 2673 1434
+a 2672 4106 1
+a 2673 2674 1433
+a 2673 4106 1
+a 2674 2675 1432
+a 2674 4106 1
+a 2675 2676 1431
+a 2675 4106 1
+a 2676 2677 1430
+a 2676 4106 1
+a 2677 2678 1429
+a 2677 4106 1
+a 2678 2679 1428
+a 2678 4106 1
+a 2679 2680 1427
+a 2679 4106 1
+a 2680 2681 1426
+a 2680 4106 1
+a 2681 2682 1425
+a 2681 4106 1
+a 2682 2683 1424
+a 2682 4106 1
+a 2683 2684 1423
+a 2683 4106 1
+a 2684 2685 1422
+a 2684 4106 1
+a 2685 2686 1421
+a 2685 4106 1
+a 2686 2687 1420
+a 2686 4106 1
+a 2687 2688 1419
+a 2687 4106 1
+a 2688 2689 1418
+a 2688 4106 1
+a 2689 2690 1417
+a 2689 4106 1
+a 2690 2691 1416
+a 2690 4106 1
+a 2691 2692 1415
+a 2691 4106 1
+a 2692 2693 1414
+a 2692 4106 1
+a 2693 2694 1413
+a 2693 4106 1
+a 2694 2695 1412
+a 2694 4106 1
+a 2695 2696 1411
+a 2695 4106 1
+a 2696 2697 1410
+a 2696 4106 1
+a 2697 2698 1409
+a 2697 4106 1
+a 2698 2699 1408
+a 2698 4106 1
+a 2699 2700 1407
+a 2699 4106 1
+a 2700 2701 1406
+a 2700 4106 1
+a 2701 2702 1405
+a 2701 4106 1
+a 2702 2703 1404
+a 2702 4106 1
+a 2703 2704 1403
+a 2703 4106 1
+a 2704 2705 1402
+a 2704 4106 1
+a 2705 2706 1401
+a 2705 4106 1
+a 2706 2707 1400
+a 2706 4106 1
+a 2707 2708 1399
+a 2707 4106 1
+a 2708 2709 1398
+a 2708 4106 1
+a 2709 2710 1397
+a 2709 4106 1
+a 2710 2711 1396
+a 2710 4106 1
+a 2711 2712 1395
+a 2711 4106 1
+a 2712 2713 1394
+a 2712 4106 1
+a 2713 2714 1393
+a 2713 4106 1
+a 2714 2715 1392
+a 2714 4106 1
+a 2715 2716 1391
+a 2715 4106 1
+a 2716 2717 1390
+a 2716 4106 1
+a 2717 2718 1389
+a 2717 4106 1
+a 2718 2719 1388
+a 2718 4106 1
+a 2719 2720 1387
+a 2719 4106 1
+a 2720 2721 1386
+a 2720 4106 1
+a 2721 2722 1385
+a 2721 4106 1
+a 2722 2723 1384
+a 2722 4106 1
+a 2723 2724 1383
+a 2723 4106 1
+a 2724 2725 1382
+a 2724 4106 1
+a 2725 2726 1381
+a 2725 4106 1
+a 2726 2727 1380
+a 2726 4106 1
+a 2727 2728 1379
+a 2727 4106 1
+a 2728 2729 1378
+a 2728 4106 1
+a 2729 2730 1377
+a 2729 4106 1
+a 2730 2731 1376
+a 2730 4106 1
+a 2731 2732 1375
+a 2731 4106 1
+a 2732 2733 1374
+a 2732 4106 1
+a 2733 2734 1373
+a 2733 4106 1
+a 2734 2735 1372
+a 2734 4106 1
+a 2735 2736 1371
+a 2735 4106 1
+a 2736 2737 1370
+a 2736 4106 1
+a 2737 2738 1369
+a 2737 4106 1
+a 2738 2739 1368
+a 2738 4106 1
+a 2739 2740 1367
+a 2739 4106 1
+a 2740 2741 1366
+a 2740 4106 1
+a 2741 2742 1365
+a 2741 4106 1
+a 2742 2743 1364
+a 2742 4106 1
+a 2743 2744 1363
+a 2743 4106 1
+a 2744 2745 1362
+a 2744 4106 1
+a 2745 2746 1361
+a 2745 4106 1
+a 2746 2747 1360
+a 2746 4106 1
+a 2747 2748 1359
+a 2747 4106 1
+a 2748 2749 1358
+a 2748 4106 1
+a 2749 2750 1357
+a 2749 4106 1
+a 2750 2751 1356
+a 2750 4106 1
+a 2751 2752 1355
+a 2751 4106 1
+a 2752 2753 1354
+a 2752 4106 1
+a 2753 2754 1353
+a 2753 4106 1
+a 2754 2755 1352
+a 2754 4106 1
+a 2755 2756 1351
+a 2755 4106 1
+a 2756 2757 1350
+a 2756 4106 1
+a 2757 2758 1349
+a 2757 4106 1
+a 2758 2759 1348
+a 2758 4106 1
+a 2759 2760 1347
+a 2759 4106 1
+a 2760 2761 1346
+a 2760 4106 1
+a 2761 2762 1345
+a 2761 4106 1
+a 2762 2763 1344
+a 2762 4106 1
+a 2763 2764 1343
+a 2763 4106 1
+a 2764 2765 1342
+a 2764 4106 1
+a 2765 2766 1341
+a 2765 4106 1
+a 2766 2767 1340
+a 2766 4106 1
+a 2767 2768 1339
+a 2767 4106 1
+a 2768 2769 1338
+a 2768 4106 1
+a 2769 2770 1337
+a 2769 4106 1
+a 2770 2771 1336
+a 2770 4106 1
+a 2771 2772 1335
+a 2771 4106 1
+a 2772 2773 1334
+a 2772 4106 1
+a 2773 2774 1333
+a 2773 4106 1
+a 2774 2775 1332
+a 2774 4106 1
+a 2775 2776 1331
+a 2775 4106 1
+a 2776 2777 1330
+a 2776 4106 1
+a 2777 2778 1329
+a 2777 4106 1
+a 2778 2779 1328
+a 2778 4106 1
+a 2779 2780 1327
+a 2779 4106 1
+a 2780 2781 1326
+a 2780 4106 1
+a 2781 2782 1325
+a 2781 4106 1
+a 2782 2783 1324
+a 2782 4106 1
+a 2783 2784 1323
+a 2783 4106 1
+a 2784 2785 1322
+a 2784 4106 1
+a 2785 2786 1321
+a 2785 4106 1
+a 2786 2787 1320
+a 2786 4106 1
+a 2787 2788 1319
+a 2787 4106 1
+a 2788 2789 1318
+a 2788 4106 1
+a 2789 2790 1317
+a 2789 4106 1
+a 2790 2791 1316
+a 2790 4106 1
+a 2791 2792 1315
+a 2791 4106 1
+a 2792 2793 1314
+a 2792 4106 1
+a 2793 2794 1313
+a 2793 4106 1
+a 2794 2795 1312
+a 2794 4106 1
+a 2795 2796 1311
+a 2795 4106 1
+a 2796 2797 1310
+a 2796 4106 1
+a 2797 2798 1309
+a 2797 4106 1
+a 2798 2799 1308
+a 2798 4106 1
+a 2799 2800 1307
+a 2799 4106 1
+a 2800 2801 1306
+a 2800 4106 1
+a 2801 2802 1305
+a 2801 4106 1
+a 2802 2803 1304
+a 2802 4106 1
+a 2803 2804 1303
+a 2803 4106 1
+a 2804 2805 1302
+a 2804 4106 1
+a 2805 2806 1301
+a 2805 4106 1
+a 2806 2807 1300
+a 2806 4106 1
+a 2807 2808 1299
+a 2807 4106 1
+a 2808 2809 1298
+a 2808 4106 1
+a 2809 2810 1297
+a 2809 4106 1
+a 2810 2811 1296
+a 2810 4106 1
+a 2811 2812 1295
+a 2811 4106 1
+a 2812 2813 1294
+a 2812 4106 1
+a 2813 2814 1293
+a 2813 4106 1
+a 2814 2815 1292
+a 2814 4106 1
+a 2815 2816 1291
+a 2815 4106 1
+a 2816 2817 1290
+a 2816 4106 1
+a 2817 2818 1289
+a 2817 4106 1
+a 2818 2819 1288
+a 2818 4106 1
+a 2819 2820 1287
+a 2819 4106 1
+a 2820 2821 1286
+a 2820 4106 1
+a 2821 2822 1285
+a 2821 4106 1
+a 2822 2823 1284
+a 2822 4106 1
+a 2823 2824 1283
+a 2823 4106 1
+a 2824 2825 1282
+a 2824 4106 1
+a 2825 2826 1281
+a 2825 4106 1
+a 2826 2827 1280
+a 2826 4106 1
+a 2827 2828 1279
+a 2827 4106 1
+a 2828 2829 1278
+a 2828 4106 1
+a 2829 2830 1277
+a 2829 4106 1
+a 2830 2831 1276
+a 2830 4106 1
+a 2831 2832 1275
+a 2831 4106 1
+a 2832 2833 1274
+a 2832 4106 1
+a 2833 2834 1273
+a 2833 4106 1
+a 2834 2835 1272
+a 2834 4106 1
+a 2835 2836 1271
+a 2835 4106 1
+a 2836 2837 1270
+a 2836 4106 1
+a 2837 2838 1269
+a 2837 4106 1
+a 2838 2839 1268
+a 2838 4106 1
+a 2839 2840 1267
+a 2839 4106 1
+a 2840 2841 1266
+a 2840 4106 1
+a 2841 2842 1265
+a 2841 4106 1
+a 2842 2843 1264
+a 2842 4106 1
+a 2843 2844 1263
+a 2843 4106 1
+a 2844 2845 1262
+a 2844 4106 1
+a 2845 2846 1261
+a 2845 4106 1
+a 2846 2847 1260
+a 2846 4106 1
+a 2847 2848 1259
+a 2847 4106 1
+a 2848 2849 1258
+a 2848 4106 1
+a 2849 2850 1257
+a 2849 4106 1
+a 2850 2851 1256
+a 2850 4106 1
+a 2851 2852 1255
+a 2851 4106 1
+a 2852 2853 1254
+a 2852 4106 1
+a 2853 2854 1253
+a 2853 4106 1
+a 2854 2855 1252
+a 2854 4106 1
+a 2855 2856 1251
+a 2855 4106 1
+a 2856 2857 1250
+a 2856 4106 1
+a 2857 2858 1249
+a 2857 4106 1
+a 2858 2859 1248
+a 2858 4106 1
+a 2859 2860 1247
+a 2859 4106 1
+a 2860 2861 1246
+a 2860 4106 1
+a 2861 2862 1245
+a 2861 4106 1
+a 2862 2863 1244
+a 2862 4106 1
+a 2863 2864 1243
+a 2863 4106 1
+a 2864 2865 1242
+a 2864 4106 1
+a 2865 2866 1241
+a 2865 4106 1
+a 2866 2867 1240
+a 2866 4106 1
+a 2867 2868 1239
+a 2867 4106 1
+a 2868 2869 1238
+a 2868 4106 1
+a 2869 2870 1237
+a 2869 4106 1
+a 2870 2871 1236
+a 2870 4106 1
+a 2871 2872 1235
+a 2871 4106 1
+a 2872 2873 1234
+a 2872 4106 1
+a 2873 2874 1233
+a 2873 4106 1
+a 2874 2875 1232
+a 2874 4106 1
+a 2875 2876 1231
+a 2875 4106 1
+a 2876 2877 1230
+a 2876 4106 1
+a 2877 2878 1229
+a 2877 4106 1
+a 2878 2879 1228
+a 2878 4106 1
+a 2879 2880 1227
+a 2879 4106 1
+a 2880 2881 1226
+a 2880 4106 1
+a 2881 2882 1225
+a 2881 4106 1
+a 2882 2883 1224
+a 2882 4106 1
+a 2883 2884 1223
+a 2883 4106 1
+a 2884 2885 1222
+a 2884 4106 1
+a 2885 2886 1221
+a 2885 4106 1
+a 2886 2887 1220
+a 2886 4106 1
+a 2887 2888 1219
+a 2887 4106 1
+a 2888 2889 1218
+a 2888 4106 1
+a 2889 2890 1217
+a 2889 4106 1
+a 2890 2891 1216
+a 2890 4106 1
+a 2891 2892 1215
+a 2891 4106 1
+a 2892 2893 1214
+a 2892 4106 1
+a 2893 2894 1213
+a 2893 4106 1
+a 2894 2895 1212
+a 2894 4106 1
+a 2895 2896 1211
+a 2895 4106 1
+a 2896 2897 1210
+a 2896 4106 1
+a 2897 2898 1209
+a 2897 4106 1
+a 2898 2899 1208
+a 2898 4106 1
+a 2899 2900 1207
+a 2899 4106 1
+a 2900 2901 1206
+a 2900 4106 1
+a 2901 2902 1205
+a 2901 4106 1
+a 2902 2903 1204
+a 2902 4106 1
+a 2903 2904 1203
+a 2903 4106 1
+a 2904 2905 1202
+a 2904 4106 1
+a 2905 2906 1201
+a 2905 4106 1
+a 2906 2907 1200
+a 2906 4106 1
+a 2907 2908 1199
+a 2907 4106 1
+a 2908 2909 1198
+a 2908 4106 1
+a 2909 2910 1197
+a 2909 4106 1
+a 2910 2911 1196
+a 2910 4106 1
+a 2911 2912 1195
+a 2911 4106 1
+a 2912 2913 1194
+a 2912 4106 1
+a 2913 2914 1193
+a 2913 4106 1
+a 2914 2915 1192
+a 2914 4106 1
+a 2915 2916 1191
+a 2915 4106 1
+a 2916 2917 1190
+a 2916 4106 1
+a 2917 2918 1189
+a 2917 4106 1
+a 2918 2919 1188
+a 2918 4106 1
+a 2919 2920 1187
+a 2919 4106 1
+a 2920 2921 1186
+a 2920 4106 1
+a 2921 2922 1185
+a 2921 4106 1
+a 2922 2923 1184
+a 2922 4106 1
+a 2923 2924 1183
+a 2923 4106 1
+a 2924 2925 1182
+a 2924 4106 1
+a 2925 2926 1181
+a 2925 4106 1
+a 2926 2927 1180
+a 2926 4106 1
+a 2927 2928 1179
+a 2927 4106 1
+a 2928 2929 1178
+a 2928 4106 1
+a 2929 2930 1177
+a 2929 4106 1
+a 2930 2931 1176
+a 2930 4106 1
+a 2931 2932 1175
+a 2931 4106 1
+a 2932 2933 1174
+a 2932 4106 1
+a 2933 2934 1173
+a 2933 4106 1
+a 2934 2935 1172
+a 2934 4106 1
+a 2935 2936 1171
+a 2935 4106 1
+a 2936 2937 1170
+a 2936 4106 1
+a 2937 2938 1169
+a 2937 4106 1
+a 2938 2939 1168
+a 2938 4106 1
+a 2939 2940 1167
+a 2939 4106 1
+a 2940 2941 1166
+a 2940 4106 1
+a 2941 2942 1165
+a 2941 4106 1
+a 2942 2943 1164
+a 2942 4106 1
+a 2943 2944 1163
+a 2943 4106 1
+a 2944 2945 1162
+a 2944 4106 1
+a 2945 2946 1161
+a 2945 4106 1
+a 2946 2947 1160
+a 2946 4106 1
+a 2947 2948 1159
+a 2947 4106 1
+a 2948 2949 1158
+a 2948 4106 1
+a 2949 2950 1157
+a 2949 4106 1
+a 2950 2951 1156
+a 2950 4106 1
+a 2951 2952 1155
+a 2951 4106 1
+a 2952 2953 1154
+a 2952 4106 1
+a 2953 2954 1153
+a 2953 4106 1
+a 2954 2955 1152
+a 2954 4106 1
+a 2955 2956 1151
+a 2955 4106 1
+a 2956 2957 1150
+a 2956 4106 1
+a 2957 2958 1149
+a 2957 4106 1
+a 2958 2959 1148
+a 2958 4106 1
+a 2959 2960 1147
+a 2959 4106 1
+a 2960 2961 1146
+a 2960 4106 1
+a 2961 2962 1145
+a 2961 4106 1
+a 2962 2963 1144
+a 2962 4106 1
+a 2963 2964 1143
+a 2963 4106 1
+a 2964 2965 1142
+a 2964 4106 1
+a 2965 2966 1141
+a 2965 4106 1
+a 2966 2967 1140
+a 2966 4106 1
+a 2967 2968 1139
+a 2967 4106 1
+a 2968 2969 1138
+a 2968 4106 1
+a 2969 2970 1137
+a 2969 4106 1
+a 2970 2971 1136
+a 2970 4106 1
+a 2971 2972 1135
+a 2971 4106 1
+a 2972 2973 1134
+a 2972 4106 1
+a 2973 2974 1133
+a 2973 4106 1
+a 2974 2975 1132
+a 2974 4106 1
+a 2975 2976 1131
+a 2975 4106 1
+a 2976 2977 1130
+a 2976 4106 1
+a 2977 2978 1129
+a 2977 4106 1
+a 2978 2979 1128
+a 2978 4106 1
+a 2979 2980 1127
+a 2979 4106 1
+a 2980 2981 1126
+a 2980 4106 1
+a 2981 2982 1125
+a 2981 4106 1
+a 2982 2983 1124
+a 2982 4106 1
+a 2983 2984 1123
+a 2983 4106 1
+a 2984 2985 1122
+a 2984 4106 1
+a 2985 2986 1121
+a 2985 4106 1
+a 2986 2987 1120
+a 2986 4106 1
+a 2987 2988 1119
+a 2987 4106 1
+a 2988 2989 1118
+a 2988 4106 1
+a 2989 2990 1117
+a 2989 4106 1
+a 2990 2991 1116
+a 2990 4106 1
+a 2991 2992 1115
+a 2991 4106 1
+a 2992 2993 1114
+a 2992 4106 1
+a 2993 2994 1113
+a 2993 4106 1
+a 2994 2995 1112
+a 2994 4106 1
+a 2995 2996 1111
+a 2995 4106 1
+a 2996 2997 1110
+a 2996 4106 1
+a 2997 2998 1109
+a 2997 4106 1
+a 2998 2999 1108
+a 2998 4106 1
+a 2999 3000 1107
+a 2999 4106 1
+a 3000 3001 1106
+a 3000 4106 1
+a 3001 3002 1105
+a 3001 4106 1
+a 3002 3003 1104
+a 3002 4106 1
+a 3003 3004 1103
+a 3003 4106 1
+a 3004 3005 1102
+a 3004 4106 1
+a 3005 3006 1101
+a 3005 4106 1
+a 3006 3007 1100
+a 3006 4106 1
+a 3007 3008 1099
+a 3007 4106 1
+a 3008 3009 1098
+a 3008 4106 1
+a 3009 3010 1097
+a 3009 4106 1
+a 3010 3011 1096
+a 3010 4106 1
+a 3011 3012 1095
+a 3011 4106 1
+a 3012 3013 1094
+a 3012 4106 1
+a 3013 3014 1093
+a 3013 4106 1
+a 3014 3015 1092
+a 3014 4106 1
+a 3015 3016 1091
+a 3015 4106 1
+a 3016 3017 1090
+a 3016 4106 1
+a 3017 3018 1089
+a 3017 4106 1
+a 3018 3019 1088
+a 3018 4106 1
+a 3019 3020 1087
+a 3019 4106 1
+a 3020 3021 1086
+a 3020 4106 1
+a 3021 3022 1085
+a 3021 4106 1
+a 3022 3023 1084
+a 3022 4106 1
+a 3023 3024 1083
+a 3023 4106 1
+a 3024 3025 1082
+a 3024 4106 1
+a 3025 3026 1081
+a 3025 4106 1
+a 3026 3027 1080
+a 3026 4106 1
+a 3027 3028 1079
+a 3027 4106 1
+a 3028 3029 1078
+a 3028 4106 1
+a 3029 3030 1077
+a 3029 4106 1
+a 3030 3031 1076
+a 3030 4106 1
+a 3031 3032 1075
+a 3031 4106 1
+a 3032 3033 1074
+a 3032 4106 1
+a 3033 3034 1073
+a 3033 4106 1
+a 3034 3035 1072
+a 3034 4106 1
+a 3035 3036 1071
+a 3035 4106 1
+a 3036 3037 1070
+a 3036 4106 1
+a 3037 3038 1069
+a 3037 4106 1
+a 3038 3039 1068
+a 3038 4106 1
+a 3039 3040 1067
+a 3039 4106 1
+a 3040 3041 1066
+a 3040 4106 1
+a 3041 3042 1065
+a 3041 4106 1
+a 3042 3043 1064
+a 3042 4106 1
+a 3043 3044 1063
+a 3043 4106 1
+a 3044 3045 1062
+a 3044 4106 1
+a 3045 3046 1061
+a 3045 4106 1
+a 3046 3047 1060
+a 3046 4106 1
+a 3047 3048 1059
+a 3047 4106 1
+a 3048 3049 1058
+a 3048 4106 1
+a 3049 3050 1057
+a 3049 4106 1
+a 3050 3051 1056
+a 3050 4106 1
+a 3051 3052 1055
+a 3051 4106 1
+a 3052 3053 1054
+a 3052 4106 1
+a 3053 3054 1053
+a 3053 4106 1
+a 3054 3055 1052
+a 3054 4106 1
+a 3055 3056 1051
+a 3055 4106 1
+a 3056 3057 1050
+a 3056 4106 1
+a 3057 3058 1049
+a 3057 4106 1
+a 3058 3059 1048
+a 3058 4106 1
+a 3059 3060 1047
+a 3059 4106 1
+a 3060 3061 1046
+a 3060 4106 1
+a 3061 3062 1045
+a 3061 4106 1
+a 3062 3063 1044
+a 3062 4106 1
+a 3063 3064 1043
+a 3063 4106 1
+a 3064 3065 1042
+a 3064 4106 1
+a 3065 3066 1041
+a 3065 4106 1
+a 3066 3067 1040
+a 3066 4106 1
+a 3067 3068 1039
+a 3067 4106 1
+a 3068 3069 1038
+a 3068 4106 1
+a 3069 3070 1037
+a 3069 4106 1
+a 3070 3071 1036
+a 3070 4106 1
+a 3071 3072 1035
+a 3071 4106 1
+a 3072 3073 1034
+a 3072 4106 1
+a 3073 3074 1033
+a 3073 4106 1
+a 3074 3075 1032
+a 3074 4106 1
+a 3075 3076 1031
+a 3075 4106 1
+a 3076 3077 1030
+a 3076 4106 1
+a 3077 3078 1029
+a 3077 4106 1
+a 3078 3079 1028
+a 3078 4106 1
+a 3079 3080 1027
+a 3079 4106 1
+a 3080 3081 1026
+a 3080 4106 1
+a 3081 3082 1025
+a 3081 4106 1
+a 3082 3083 1024
+a 3082 4106 1
+a 3083 3084 1023
+a 3083 4106 1
+a 3084 3085 1022
+a 3084 4106 1
+a 3085 3086 1021
+a 3085 4106 1
+a 3086 3087 1020
+a 3086 4106 1
+a 3087 3088 1019
+a 3087 4106 1
+a 3088 3089 1018
+a 3088 4106 1
+a 3089 3090 1017
+a 3089 4106 1
+a 3090 3091 1016
+a 3090 4106 1
+a 3091 3092 1015
+a 3091 4106 1
+a 3092 3093 1014
+a 3092 4106 1
+a 3093 3094 1013
+a 3093 4106 1
+a 3094 3095 1012
+a 3094 4106 1
+a 3095 3096 1011
+a 3095 4106 1
+a 3096 3097 1010
+a 3096 4106 1
+a 3097 3098 1009
+a 3097 4106 1
+a 3098 3099 1008
+a 3098 4106 1
+a 3099 3100 1007
+a 3099 4106 1
+a 3100 3101 1006
+a 3100 4106 1
+a 3101 3102 1005
+a 3101 4106 1
+a 3102 3103 1004
+a 3102 4106 1
+a 3103 3104 1003
+a 3103 4106 1
+a 3104 3105 1002
+a 3104 4106 1
+a 3105 3106 1001
+a 3105 4106 1
+a 3106 3107 1000
+a 3106 4106 1
+a 3107 3108 999
+a 3107 4106 1
+a 3108 3109 998
+a 3108 4106 1
+a 3109 3110 997
+a 3109 4106 1
+a 3110 3111 996
+a 3110 4106 1
+a 3111 3112 995
+a 3111 4106 1
+a 3112 3113 994
+a 3112 4106 1
+a 3113 3114 993
+a 3113 4106 1
+a 3114 3115 992
+a 3114 4106 1
+a 3115 3116 991
+a 3115 4106 1
+a 3116 3117 990
+a 3116 4106 1
+a 3117 3118 989
+a 3117 4106 1
+a 3118 3119 988
+a 3118 4106 1
+a 3119 3120 987
+a 3119 4106 1
+a 3120 3121 986
+a 3120 4106 1
+a 3121 3122 985
+a 3121 4106 1
+a 3122 3123 984
+a 3122 4106 1
+a 3123 3124 983
+a 3123 4106 1
+a 3124 3125 982
+a 3124 4106 1
+a 3125 3126 981
+a 3125 4106 1
+a 3126 3127 980
+a 3126 4106 1
+a 3127 3128 979
+a 3127 4106 1
+a 3128 3129 978
+a 3128 4106 1
+a 3129 3130 977
+a 3129 4106 1
+a 3130 3131 976
+a 3130 4106 1
+a 3131 3132 975
+a 3131 4106 1
+a 3132 3133 974
+a 3132 4106 1
+a 3133 3134 973
+a 3133 4106 1
+a 3134 3135 972
+a 3134 4106 1
+a 3135 3136 971
+a 3135 4106 1
+a 3136 3137 970
+a 3136 4106 1
+a 3137 3138 969
+a 3137 4106 1
+a 3138 3139 968
+a 3138 4106 1
+a 3139 3140 967
+a 3139 4106 1
+a 3140 3141 966
+a 3140 4106 1
+a 3141 3142 965
+a 3141 4106 1
+a 3142 3143 964
+a 3142 4106 1
+a 3143 3144 963
+a 3143 4106 1
+a 3144 3145 962
+a 3144 4106 1
+a 3145 3146 961
+a 3145 4106 1
+a 3146 3147 960
+a 3146 4106 1
+a 3147 3148 959
+a 3147 4106 1
+a 3148 3149 958
+a 3148 4106 1
+a 3149 3150 957
+a 3149 4106 1
+a 3150 3151 956
+a 3150 4106 1
+a 3151 3152 955
+a 3151 4106 1
+a 3152 3153 954
+a 3152 4106 1
+a 3153 3154 953
+a 3153 4106 1
+a 3154 3155 952
+a 3154 4106 1
+a 3155 3156 951
+a 3155 4106 1
+a 3156 3157 950
+a 3156 4106 1
+a 3157 3158 949
+a 3157 4106 1
+a 3158 3159 948
+a 3158 4106 1
+a 3159 3160 947
+a 3159 4106 1
+a 3160 3161 946
+a 3160 4106 1
+a 3161 3162 945
+a 3161 4106 1
+a 3162 3163 944
+a 3162 4106 1
+a 3163 3164 943
+a 3163 4106 1
+a 3164 3165 942
+a 3164 4106 1
+a 3165 3166 941
+a 3165 4106 1
+a 3166 3167 940
+a 3166 4106 1
+a 3167 3168 939
+a 3167 4106 1
+a 3168 3169 938
+a 3168 4106 1
+a 3169 3170 937
+a 3169 4106 1
+a 3170 3171 936
+a 3170 4106 1
+a 3171 3172 935
+a 3171 4106 1
+a 3172 3173 934
+a 3172 4106 1
+a 3173 3174 933
+a 3173 4106 1
+a 3174 3175 932
+a 3174 4106 1
+a 3175 3176 931
+a 3175 4106 1
+a 3176 3177 930
+a 3176 4106 1
+a 3177 3178 929
+a 3177 4106 1
+a 3178 3179 928
+a 3178 4106 1
+a 3179 3180 927
+a 3179 4106 1
+a 3180 3181 926
+a 3180 4106 1
+a 3181 3182 925
+a 3181 4106 1
+a 3182 3183 924
+a 3182 4106 1
+a 3183 3184 923
+a 3183 4106 1
+a 3184 3185 922
+a 3184 4106 1
+a 3185 3186 921
+a 3185 4106 1
+a 3186 3187 920
+a 3186 4106 1
+a 3187 3188 919
+a 3187 4106 1
+a 3188 3189 918
+a 3188 4106 1
+a 3189 3190 917
+a 3189 4106 1
+a 3190 3191 916
+a 3190 4106 1
+a 3191 3192 915
+a 3191 4106 1
+a 3192 3193 914
+a 3192 4106 1
+a 3193 3194 913
+a 3193 4106 1
+a 3194 3195 912
+a 3194 4106 1
+a 3195 3196 911
+a 3195 4106 1
+a 3196 3197 910
+a 3196 4106 1
+a 3197 3198 909
+a 3197 4106 1
+a 3198 3199 908
+a 3198 4106 1
+a 3199 3200 907
+a 3199 4106 1
+a 3200 3201 906
+a 3200 4106 1
+a 3201 3202 905
+a 3201 4106 1
+a 3202 3203 904
+a 3202 4106 1
+a 3203 3204 903
+a 3203 4106 1
+a 3204 3205 902
+a 3204 4106 1
+a 3205 3206 901
+a 3205 4106 1
+a 3206 3207 900
+a 3206 4106 1
+a 3207 3208 899
+a 3207 4106 1
+a 3208 3209 898
+a 3208 4106 1
+a 3209 3210 897
+a 3209 4106 1
+a 3210 3211 896
+a 3210 4106 1
+a 3211 3212 895
+a 3211 4106 1
+a 3212 3213 894
+a 3212 4106 1
+a 3213 3214 893
+a 3213 4106 1
+a 3214 3215 892
+a 3214 4106 1
+a 3215 3216 891
+a 3215 4106 1
+a 3216 3217 890
+a 3216 4106 1
+a 3217 3218 889
+a 3217 4106 1
+a 3218 3219 888
+a 3218 4106 1
+a 3219 3220 887
+a 3219 4106 1
+a 3220 3221 886
+a 3220 4106 1
+a 3221 3222 885
+a 3221 4106 1
+a 3222 3223 884
+a 3222 4106 1
+a 3223 3224 883
+a 3223 4106 1
+a 3224 3225 882
+a 3224 4106 1
+a 3225 3226 881
+a 3225 4106 1
+a 3226 3227 880
+a 3226 4106 1
+a 3227 3228 879
+a 3227 4106 1
+a 3228 3229 878
+a 3228 4106 1
+a 3229 3230 877
+a 3229 4106 1
+a 3230 3231 876
+a 3230 4106 1
+a 3231 3232 875
+a 3231 4106 1
+a 3232 3233 874
+a 3232 4106 1
+a 3233 3234 873
+a 3233 4106 1
+a 3234 3235 872
+a 3234 4106 1
+a 3235 3236 871
+a 3235 4106 1
+a 3236 3237 870
+a 3236 4106 1
+a 3237 3238 869
+a 3237 4106 1
+a 3238 3239 868
+a 3238 4106 1
+a 3239 3240 867
+a 3239 4106 1
+a 3240 3241 866
+a 3240 4106 1
+a 3241 3242 865
+a 3241 4106 1
+a 3242 3243 864
+a 3242 4106 1
+a 3243 3244 863
+a 3243 4106 1
+a 3244 3245 862
+a 3244 4106 1
+a 3245 3246 861
+a 3245 4106 1
+a 3246 3247 860
+a 3246 4106 1
+a 3247 3248 859
+a 3247 4106 1
+a 3248 3249 858
+a 3248 4106 1
+a 3249 3250 857
+a 3249 4106 1
+a 3250 3251 856
+a 3250 4106 1
+a 3251 3252 855
+a 3251 4106 1
+a 3252 3253 854
+a 3252 4106 1
+a 3253 3254 853
+a 3253 4106 1
+a 3254 3255 852
+a 3254 4106 1
+a 3255 3256 851
+a 3255 4106 1
+a 3256 3257 850
+a 3256 4106 1
+a 3257 3258 849
+a 3257 4106 1
+a 3258 3259 848
+a 3258 4106 1
+a 3259 3260 847
+a 3259 4106 1
+a 3260 3261 846
+a 3260 4106 1
+a 3261 3262 845
+a 3261 4106 1
+a 3262 3263 844
+a 3262 4106 1
+a 3263 3264 843
+a 3263 4106 1
+a 3264 3265 842
+a 3264 4106 1
+a 3265 3266 841
+a 3265 4106 1
+a 3266 3267 840
+a 3266 4106 1
+a 3267 3268 839
+a 3267 4106 1
+a 3268 3269 838
+a 3268 4106 1
+a 3269 3270 837
+a 3269 4106 1
+a 3270 3271 836
+a 3270 4106 1
+a 3271 3272 835
+a 3271 4106 1
+a 3272 3273 834
+a 3272 4106 1
+a 3273 3274 833
+a 3273 4106 1
+a 3274 3275 832
+a 3274 4106 1
+a 3275 3276 831
+a 3275 4106 1
+a 3276 3277 830
+a 3276 4106 1
+a 3277 3278 829
+a 3277 4106 1
+a 3278 3279 828
+a 3278 4106 1
+a 3279 3280 827
+a 3279 4106 1
+a 3280 3281 826
+a 3280 4106 1
+a 3281 3282 825
+a 3281 4106 1
+a 3282 3283 824
+a 3282 4106 1
+a 3283 3284 823
+a 3283 4106 1
+a 3284 3285 822
+a 3284 4106 1
+a 3285 3286 821
+a 3285 4106 1
+a 3286 3287 820
+a 3286 4106 1
+a 3287 3288 819
+a 3287 4106 1
+a 3288 3289 818
+a 3288 4106 1
+a 3289 3290 817
+a 3289 4106 1
+a 3290 3291 816
+a 3290 4106 1
+a 3291 3292 815
+a 3291 4106 1
+a 3292 3293 814
+a 3292 4106 1
+a 3293 3294 813
+a 3293 4106 1
+a 3294 3295 812
+a 3294 4106 1
+a 3295 3296 811
+a 3295 4106 1
+a 3296 3297 810
+a 3296 4106 1
+a 3297 3298 809
+a 3297 4106 1
+a 3298 3299 808
+a 3298 4106 1
+a 3299 3300 807
+a 3299 4106 1
+a 3300 3301 806
+a 3300 4106 1
+a 3301 3302 805
+a 3301 4106 1
+a 3302 3303 804
+a 3302 4106 1
+a 3303 3304 803
+a 3303 4106 1
+a 3304 3305 802
+a 3304 4106 1
+a 3305 3306 801
+a 3305 4106 1
+a 3306 3307 800
+a 3306 4106 1
+a 3307 3308 799
+a 3307 4106 1
+a 3308 3309 798
+a 3308 4106 1
+a 3309 3310 797
+a 3309 4106 1
+a 3310 3311 796
+a 3310 4106 1
+a 3311 3312 795
+a 3311 4106 1
+a 3312 3313 794
+a 3312 4106 1
+a 3313 3314 793
+a 3313 4106 1
+a 3314 3315 792
+a 3314 4106 1
+a 3315 3316 791
+a 3315 4106 1
+a 3316 3317 790
+a 3316 4106 1
+a 3317 3318 789
+a 3317 4106 1
+a 3318 3319 788
+a 3318 4106 1
+a 3319 3320 787
+a 3319 4106 1
+a 3320 3321 786
+a 3320 4106 1
+a 3321 3322 785
+a 3321 4106 1
+a 3322 3323 784
+a 3322 4106 1
+a 3323 3324 783
+a 3323 4106 1
+a 3324 3325 782
+a 3324 4106 1
+a 3325 3326 781
+a 3325 4106 1
+a 3326 3327 780
+a 3326 4106 1
+a 3327 3328 779
+a 3327 4106 1
+a 3328 3329 778
+a 3328 4106 1
+a 3329 3330 777
+a 3329 4106 1
+a 3330 3331 776
+a 3330 4106 1
+a 3331 3332 775
+a 3331 4106 1
+a 3332 3333 774
+a 3332 4106 1
+a 3333 3334 773
+a 3333 4106 1
+a 3334 3335 772
+a 3334 4106 1
+a 3335 3336 771
+a 3335 4106 1
+a 3336 3337 770
+a 3336 4106 1
+a 3337 3338 769
+a 3337 4106 1
+a 3338 3339 768
+a 3338 4106 1
+a 3339 3340 767
+a 3339 4106 1
+a 3340 3341 766
+a 3340 4106 1
+a 3341 3342 765
+a 3341 4106 1
+a 3342 3343 764
+a 3342 4106 1
+a 3343 3344 763
+a 3343 4106 1
+a 3344 3345 762
+a 3344 4106 1
+a 3345 3346 761
+a 3345 4106 1
+a 3346 3347 760
+a 3346 4106 1
+a 3347 3348 759
+a 3347 4106 1
+a 3348 3349 758
+a 3348 4106 1
+a 3349 3350 757
+a 3349 4106 1
+a 3350 3351 756
+a 3350 4106 1
+a 3351 3352 755
+a 3351 4106 1
+a 3352 3353 754
+a 3352 4106 1
+a 3353 3354 753
+a 3353 4106 1
+a 3354 3355 752
+a 3354 4106 1
+a 3355 3356 751
+a 3355 4106 1
+a 3356 3357 750
+a 3356 4106 1
+a 3357 3358 749
+a 3357 4106 1
+a 3358 3359 748
+a 3358 4106 1
+a 3359 3360 747
+a 3359 4106 1
+a 3360 3361 746
+a 3360 4106 1
+a 3361 3362 745
+a 3361 4106 1
+a 3362 3363 744
+a 3362 4106 1
+a 3363 3364 743
+a 3363 4106 1
+a 3364 3365 742
+a 3364 4106 1
+a 3365 3366 741
+a 3365 4106 1
+a 3366 3367 740
+a 3366 4106 1
+a 3367 3368 739
+a 3367 4106 1
+a 3368 3369 738
+a 3368 4106 1
+a 3369 3370 737
+a 3369 4106 1
+a 3370 3371 736
+a 3370 4106 1
+a 3371 3372 735
+a 3371 4106 1
+a 3372 3373 734
+a 3372 4106 1
+a 3373 3374 733
+a 3373 4106 1
+a 3374 3375 732
+a 3374 4106 1
+a 3375 3376 731
+a 3375 4106 1
+a 3376 3377 730
+a 3376 4106 1
+a 3377 3378 729
+a 3377 4106 1
+a 3378 3379 728
+a 3378 4106 1
+a 3379 3380 727
+a 3379 4106 1
+a 3380 3381 726
+a 3380 4106 1
+a 3381 3382 725
+a 3381 4106 1
+a 3382 3383 724
+a 3382 4106 1
+a 3383 3384 723
+a 3383 4106 1
+a 3384 3385 722
+a 3384 4106 1
+a 3385 3386 721
+a 3385 4106 1
+a 3386 3387 720
+a 3386 4106 1
+a 3387 3388 719
+a 3387 4106 1
+a 3388 3389 718
+a 3388 4106 1
+a 3389 3390 717
+a 3389 4106 1
+a 3390 3391 716
+a 3390 4106 1
+a 3391 3392 715
+a 3391 4106 1
+a 3392 3393 714
+a 3392 4106 1
+a 3393 3394 713
+a 3393 4106 1
+a 3394 3395 712
+a 3394 4106 1
+a 3395 3396 711
+a 3395 4106 1
+a 3396 3397 710
+a 3396 4106 1
+a 3397 3398 709
+a 3397 4106 1
+a 3398 3399 708
+a 3398 4106 1
+a 3399 3400 707
+a 3399 4106 1
+a 3400 3401 706
+a 3400 4106 1
+a 3401 3402 705
+a 3401 4106 1
+a 3402 3403 704
+a 3402 4106 1
+a 3403 3404 703
+a 3403 4106 1
+a 3404 3405 702
+a 3404 4106 1
+a 3405 3406 701
+a 3405 4106 1
+a 3406 3407 700
+a 3406 4106 1
+a 3407 3408 699
+a 3407 4106 1
+a 3408 3409 698
+a 3408 4106 1
+a 3409 3410 697
+a 3409 4106 1
+a 3410 3411 696
+a 3410 4106 1
+a 3411 3412 695
+a 3411 4106 1
+a 3412 3413 694
+a 3412 4106 1
+a 3413 3414 693
+a 3413 4106 1
+a 3414 3415 692
+a 3414 4106 1
+a 3415 3416 691
+a 3415 4106 1
+a 3416 3417 690
+a 3416 4106 1
+a 3417 3418 689
+a 3417 4106 1
+a 3418 3419 688
+a 3418 4106 1
+a 3419 3420 687
+a 3419 4106 1
+a 3420 3421 686
+a 3420 4106 1
+a 3421 3422 685
+a 3421 4106 1
+a 3422 3423 684
+a 3422 4106 1
+a 3423 3424 683
+a 3423 4106 1
+a 3424 3425 682
+a 3424 4106 1
+a 3425 3426 681
+a 3425 4106 1
+a 3426 3427 680
+a 3426 4106 1
+a 3427 3428 679
+a 3427 4106 1
+a 3428 3429 678
+a 3428 4106 1
+a 3429 3430 677
+a 3429 4106 1
+a 3430 3431 676
+a 3430 4106 1
+a 3431 3432 675
+a 3431 4106 1
+a 3432 3433 674
+a 3432 4106 1
+a 3433 3434 673
+a 3433 4106 1
+a 3434 3435 672
+a 3434 4106 1
+a 3435 3436 671
+a 3435 4106 1
+a 3436 3437 670
+a 3436 4106 1
+a 3437 3438 669
+a 3437 4106 1
+a 3438 3439 668
+a 3438 4106 1
+a 3439 3440 667
+a 3439 4106 1
+a 3440 3441 666
+a 3440 4106 1
+a 3441 3442 665
+a 3441 4106 1
+a 3442 3443 664
+a 3442 4106 1
+a 3443 3444 663
+a 3443 4106 1
+a 3444 3445 662
+a 3444 4106 1
+a 3445 3446 661
+a 3445 4106 1
+a 3446 3447 660
+a 3446 4106 1
+a 3447 3448 659
+a 3447 4106 1
+a 3448 3449 658
+a 3448 4106 1
+a 3449 3450 657
+a 3449 4106 1
+a 3450 3451 656
+a 3450 4106 1
+a 3451 3452 655
+a 3451 4106 1
+a 3452 3453 654
+a 3452 4106 1
+a 3453 3454 653
+a 3453 4106 1
+a 3454 3455 652
+a 3454 4106 1
+a 3455 3456 651
+a 3455 4106 1
+a 3456 3457 650
+a 3456 4106 1
+a 3457 3458 649
+a 3457 4106 1
+a 3458 3459 648
+a 3458 4106 1
+a 3459 3460 647
+a 3459 4106 1
+a 3460 3461 646
+a 3460 4106 1
+a 3461 3462 645
+a 3461 4106 1
+a 3462 3463 644
+a 3462 4106 1
+a 3463 3464 643
+a 3463 4106 1
+a 3464 3465 642
+a 3464 4106 1
+a 3465 3466 641
+a 3465 4106 1
+a 3466 3467 640
+a 3466 4106 1
+a 3467 3468 639
+a 3467 4106 1
+a 3468 3469 638
+a 3468 4106 1
+a 3469 3470 637
+a 3469 4106 1
+a 3470 3471 636
+a 3470 4106 1
+a 3471 3472 635
+a 3471 4106 1
+a 3472 3473 634
+a 3472 4106 1
+a 3473 3474 633
+a 3473 4106 1
+a 3474 3475 632
+a 3474 4106 1
+a 3475 3476 631
+a 3475 4106 1
+a 3476 3477 630
+a 3476 4106 1
+a 3477 3478 629
+a 3477 4106 1
+a 3478 3479 628
+a 3478 4106 1
+a 3479 3480 627
+a 3479 4106 1
+a 3480 3481 626
+a 3480 4106 1
+a 3481 3482 625
+a 3481 4106 1
+a 3482 3483 624
+a 3482 4106 1
+a 3483 3484 623
+a 3483 4106 1
+a 3484 3485 622
+a 3484 4106 1
+a 3485 3486 621
+a 3485 4106 1
+a 3486 3487 620
+a 3486 4106 1
+a 3487 3488 619
+a 3487 4106 1
+a 3488 3489 618
+a 3488 4106 1
+a 3489 3490 617
+a 3489 4106 1
+a 3490 3491 616
+a 3490 4106 1
+a 3491 3492 615
+a 3491 4106 1
+a 3492 3493 614
+a 3492 4106 1
+a 3493 3494 613
+a 3493 4106 1
+a 3494 3495 612
+a 3494 4106 1
+a 3495 3496 611
+a 3495 4106 1
+a 3496 3497 610
+a 3496 4106 1
+a 3497 3498 609
+a 3497 4106 1
+a 3498 3499 608
+a 3498 4106 1
+a 3499 3500 607
+a 3499 4106 1
+a 3500 3501 606
+a 3500 4106 1
+a 3501 3502 605
+a 3501 4106 1
+a 3502 3503 604
+a 3502 4106 1
+a 3503 3504 603
+a 3503 4106 1
+a 3504 3505 602
+a 3504 4106 1
+a 3505 3506 601
+a 3505 4106 1
+a 3506 3507 600
+a 3506 4106 1
+a 3507 3508 599
+a 3507 4106 1
+a 3508 3509 598
+a 3508 4106 1
+a 3509 3510 597
+a 3509 4106 1
+a 3510 3511 596
+a 3510 4106 1
+a 3511 3512 595
+a 3511 4106 1
+a 3512 3513 594
+a 3512 4106 1
+a 3513 3514 593
+a 3513 4106 1
+a 3514 3515 592
+a 3514 4106 1
+a 3515 3516 591
+a 3515 4106 1
+a 3516 3517 590
+a 3516 4106 1
+a 3517 3518 589
+a 3517 4106 1
+a 3518 3519 588
+a 3518 4106 1
+a 3519 3520 587
+a 3519 4106 1
+a 3520 3521 586
+a 3520 4106 1
+a 3521 3522 585
+a 3521 4106 1
+a 3522 3523 584
+a 3522 4106 1
+a 3523 3524 583
+a 3523 4106 1
+a 3524 3525 582
+a 3524 4106 1
+a 3525 3526 581
+a 3525 4106 1
+a 3526 3527 580
+a 3526 4106 1
+a 3527 3528 579
+a 3527 4106 1
+a 3528 3529 578
+a 3528 4106 1
+a 3529 3530 577
+a 3529 4106 1
+a 3530 3531 576
+a 3530 4106 1
+a 3531 3532 575
+a 3531 4106 1
+a 3532 3533 574
+a 3532 4106 1
+a 3533 3534 573
+a 3533 4106 1
+a 3534 3535 572
+a 3534 4106 1
+a 3535 3536 571
+a 3535 4106 1
+a 3536 3537 570
+a 3536 4106 1
+a 3537 3538 569
+a 3537 4106 1
+a 3538 3539 568
+a 3538 4106 1
+a 3539 3540 567
+a 3539 4106 1
+a 3540 3541 566
+a 3540 4106 1
+a 3541 3542 565
+a 3541 4106 1
+a 3542 3543 564
+a 3542 4106 1
+a 3543 3544 563
+a 3543 4106 1
+a 3544 3545 562
+a 3544 4106 1
+a 3545 3546 561
+a 3545 4106 1
+a 3546 3547 560
+a 3546 4106 1
+a 3547 3548 559
+a 3547 4106 1
+a 3548 3549 558
+a 3548 4106 1
+a 3549 3550 557
+a 3549 4106 1
+a 3550 3551 556
+a 3550 4106 1
+a 3551 3552 555
+a 3551 4106 1
+a 3552 3553 554
+a 3552 4106 1
+a 3553 3554 553
+a 3553 4106 1
+a 3554 3555 552
+a 3554 4106 1
+a 3555 3556 551
+a 3555 4106 1
+a 3556 3557 550
+a 3556 4106 1
+a 3557 3558 549
+a 3557 4106 1
+a 3558 3559 548
+a 3558 4106 1
+a 3559 3560 547
+a 3559 4106 1
+a 3560 3561 546
+a 3560 4106 1
+a 3561 3562 545
+a 3561 4106 1
+a 3562 3563 544
+a 3562 4106 1
+a 3563 3564 543
+a 3563 4106 1
+a 3564 3565 542
+a 3564 4106 1
+a 3565 3566 541
+a 3565 4106 1
+a 3566 3567 540
+a 3566 4106 1
+a 3567 3568 539
+a 3567 4106 1
+a 3568 3569 538
+a 3568 4106 1
+a 3569 3570 537
+a 3569 4106 1
+a 3570 3571 536
+a 3570 4106 1
+a 3571 3572 535
+a 3571 4106 1
+a 3572 3573 534
+a 3572 4106 1
+a 3573 3574 533
+a 3573 4106 1
+a 3574 3575 532
+a 3574 4106 1
+a 3575 3576 531
+a 3575 4106 1
+a 3576 3577 530
+a 3576 4106 1
+a 3577 3578 529
+a 3577 4106 1
+a 3578 3579 528
+a 3578 4106 1
+a 3579 3580 527
+a 3579 4106 1
+a 3580 3581 526
+a 3580 4106 1
+a 3581 3582 525
+a 3581 4106 1
+a 3582 3583 524
+a 3582 4106 1
+a 3583 3584 523
+a 3583 4106 1
+a 3584 3585 522
+a 3584 4106 1
+a 3585 3586 521
+a 3585 4106 1
+a 3586 3587 520
+a 3586 4106 1
+a 3587 3588 519
+a 3587 4106 1
+a 3588 3589 518
+a 3588 4106 1
+a 3589 3590 517
+a 3589 4106 1
+a 3590 3591 516
+a 3590 4106 1
+a 3591 3592 515
+a 3591 4106 1
+a 3592 3593 514
+a 3592 4106 1
+a 3593 3594 513
+a 3593 4106 1
+a 3594 3595 512
+a 3594 4106 1
+a 3595 3596 511
+a 3595 4106 1
+a 3596 3597 510
+a 3596 4106 1
+a 3597 3598 509
+a 3597 4106 1
+a 3598 3599 508
+a 3598 4106 1
+a 3599 3600 507
+a 3599 4106 1
+a 3600 3601 506
+a 3600 4106 1
+a 3601 3602 505
+a 3601 4106 1
+a 3602 3603 504
+a 3602 4106 1
+a 3603 3604 503
+a 3603 4106 1
+a 3604 3605 502
+a 3604 4106 1
+a 3605 3606 501
+a 3605 4106 1
+a 3606 3607 500
+a 3606 4106 1
+a 3607 3608 499
+a 3607 4106 1
+a 3608 3609 498
+a 3608 4106 1
+a 3609 3610 497
+a 3609 4106 1
+a 3610 3611 496
+a 3610 4106 1
+a 3611 3612 495
+a 3611 4106 1
+a 3612 3613 494
+a 3612 4106 1
+a 3613 3614 493
+a 3613 4106 1
+a 3614 3615 492
+a 3614 4106 1
+a 3615 3616 491
+a 3615 4106 1
+a 3616 3617 490
+a 3616 4106 1
+a 3617 3618 489
+a 3617 4106 1
+a 3618 3619 488
+a 3618 4106 1
+a 3619 3620 487
+a 3619 4106 1
+a 3620 3621 486
+a 3620 4106 1
+a 3621 3622 485
+a 3621 4106 1
+a 3622 3623 484
+a 3622 4106 1
+a 3623 3624 483
+a 3623 4106 1
+a 3624 3625 482
+a 3624 4106 1
+a 3625 3626 481
+a 3625 4106 1
+a 3626 3627 480
+a 3626 4106 1
+a 3627 3628 479
+a 3627 4106 1
+a 3628 3629 478
+a 3628 4106 1
+a 3629 3630 477
+a 3629 4106 1
+a 3630 3631 476
+a 3630 4106 1
+a 3631 3632 475
+a 3631 4106 1
+a 3632 3633 474
+a 3632 4106 1
+a 3633 3634 473
+a 3633 4106 1
+a 3634 3635 472
+a 3634 4106 1
+a 3635 3636 471
+a 3635 4106 1
+a 3636 3637 470
+a 3636 4106 1
+a 3637 3638 469
+a 3637 4106 1
+a 3638 3639 468
+a 3638 4106 1
+a 3639 3640 467
+a 3639 4106 1
+a 3640 3641 466
+a 3640 4106 1
+a 3641 3642 465
+a 3641 4106 1
+a 3642 3643 464
+a 3642 4106 1
+a 3643 3644 463
+a 3643 4106 1
+a 3644 3645 462
+a 3644 4106 1
+a 3645 3646 461
+a 3645 4106 1
+a 3646 3647 460
+a 3646 4106 1
+a 3647 3648 459
+a 3647 4106 1
+a 3648 3649 458
+a 3648 4106 1
+a 3649 3650 457
+a 3649 4106 1
+a 3650 3651 456
+a 3650 4106 1
+a 3651 3652 455
+a 3651 4106 1
+a 3652 3653 454
+a 3652 4106 1
+a 3653 3654 453
+a 3653 4106 1
+a 3654 3655 452
+a 3654 4106 1
+a 3655 3656 451
+a 3655 4106 1
+a 3656 3657 450
+a 3656 4106 1
+a 3657 3658 449
+a 3657 4106 1
+a 3658 3659 448
+a 3658 4106 1
+a 3659 3660 447
+a 3659 4106 1
+a 3660 3661 446
+a 3660 4106 1
+a 3661 3662 445
+a 3661 4106 1
+a 3662 3663 444
+a 3662 4106 1
+a 3663 3664 443
+a 3663 4106 1
+a 3664 3665 442
+a 3664 4106 1
+a 3665 3666 441
+a 3665 4106 1
+a 3666 3667 440
+a 3666 4106 1
+a 3667 3668 439
+a 3667 4106 1
+a 3668 3669 438
+a 3668 4106 1
+a 3669 3670 437
+a 3669 4106 1
+a 3670 3671 436
+a 3670 4106 1
+a 3671 3672 435
+a 3671 4106 1
+a 3672 3673 434
+a 3672 4106 1
+a 3673 3674 433
+a 3673 4106 1
+a 3674 3675 432
+a 3674 4106 1
+a 3675 3676 431
+a 3675 4106 1
+a 3676 3677 430
+a 3676 4106 1
+a 3677 3678 429
+a 3677 4106 1
+a 3678 3679 428
+a 3678 4106 1
+a 3679 3680 427
+a 3679 4106 1
+a 3680 3681 426
+a 3680 4106 1
+a 3681 3682 425
+a 3681 4106 1
+a 3682 3683 424
+a 3682 4106 1
+a 3683 3684 423
+a 3683 4106 1
+a 3684 3685 422
+a 3684 4106 1
+a 3685 3686 421
+a 3685 4106 1
+a 3686 3687 420
+a 3686 4106 1
+a 3687 3688 419
+a 3687 4106 1
+a 3688 3689 418
+a 3688 4106 1
+a 3689 3690 417
+a 3689 4106 1
+a 3690 3691 416
+a 3690 4106 1
+a 3691 3692 415
+a 3691 4106 1
+a 3692 3693 414
+a 3692 4106 1
+a 3693 3694 413
+a 3693 4106 1
+a 3694 3695 412
+a 3694 4106 1
+a 3695 3696 411
+a 3695 4106 1
+a 3696 3697 410
+a 3696 4106 1
+a 3697 3698 409
+a 3697 4106 1
+a 3698 3699 408
+a 3698 4106 1
+a 3699 3700 407
+a 3699 4106 1
+a 3700 3701 406
+a 3700 4106 1
+a 3701 3702 405
+a 3701 4106 1
+a 3702 3703 404
+a 3702 4106 1
+a 3703 3704 403
+a 3703 4106 1
+a 3704 3705 402
+a 3704 4106 1
+a 3705 3706 401
+a 3705 4106 1
+a 3706 3707 400
+a 3706 4106 1
+a 3707 3708 399
+a 3707 4106 1
+a 3708 3709 398
+a 3708 4106 1
+a 3709 3710 397
+a 3709 4106 1
+a 3710 3711 396
+a 3710 4106 1
+a 3711 3712 395
+a 3711 4106 1
+a 3712 3713 394
+a 3712 4106 1
+a 3713 3714 393
+a 3713 4106 1
+a 3714 3715 392
+a 3714 4106 1
+a 3715 3716 391
+a 3715 4106 1
+a 3716 3717 390
+a 3716 4106 1
+a 3717 3718 389
+a 3717 4106 1
+a 3718 3719 388
+a 3718 4106 1
+a 3719 3720 387
+a 3719 4106 1
+a 3720 3721 386
+a 3720 4106 1
+a 3721 3722 385
+a 3721 4106 1
+a 3722 3723 384
+a 3722 4106 1
+a 3723 3724 383
+a 3723 4106 1
+a 3724 3725 382
+a 3724 4106 1
+a 3725 3726 381
+a 3725 4106 1
+a 3726 3727 380
+a 3726 4106 1
+a 3727 3728 379
+a 3727 4106 1
+a 3728 3729 378
+a 3728 4106 1
+a 3729 3730 377
+a 3729 4106 1
+a 3730 3731 376
+a 3730 4106 1
+a 3731 3732 375
+a 3731 4106 1
+a 3732 3733 374
+a 3732 4106 1
+a 3733 3734 373
+a 3733 4106 1
+a 3734 3735 372
+a 3734 4106 1
+a 3735 3736 371
+a 3735 4106 1
+a 3736 3737 370
+a 3736 4106 1
+a 3737 3738 369
+a 3737 4106 1
+a 3738 3739 368
+a 3738 4106 1
+a 3739 3740 367
+a 3739 4106 1
+a 3740 3741 366
+a 3740 4106 1
+a 3741 3742 365
+a 3741 4106 1
+a 3742 3743 364
+a 3742 4106 1
+a 3743 3744 363
+a 3743 4106 1
+a 3744 3745 362
+a 3744 4106 1
+a 3745 3746 361
+a 3745 4106 1
+a 3746 3747 360
+a 3746 4106 1
+a 3747 3748 359
+a 3747 4106 1
+a 3748 3749 358
+a 3748 4106 1
+a 3749 3750 357
+a 3749 4106 1
+a 3750 3751 356
+a 3750 4106 1
+a 3751 3752 355
+a 3751 4106 1
+a 3752 3753 354
+a 3752 4106 1
+a 3753 3754 353
+a 3753 4106 1
+a 3754 3755 352
+a 3754 4106 1
+a 3755 3756 351
+a 3755 4106 1
+a 3756 3757 350
+a 3756 4106 1
+a 3757 3758 349
+a 3757 4106 1
+a 3758 3759 348
+a 3758 4106 1
+a 3759 3760 347
+a 3759 4106 1
+a 3760 3761 346
+a 3760 4106 1
+a 3761 3762 345
+a 3761 4106 1
+a 3762 3763 344
+a 3762 4106 1
+a 3763 3764 343
+a 3763 4106 1
+a 3764 3765 342
+a 3764 4106 1
+a 3765 3766 341
+a 3765 4106 1
+a 3766 3767 340
+a 3766 4106 1
+a 3767 3768 339
+a 3767 4106 1
+a 3768 3769 338
+a 3768 4106 1
+a 3769 3770 337
+a 3769 4106 1
+a 3770 3771 336
+a 3770 4106 1
+a 3771 3772 335
+a 3771 4106 1
+a 3772 3773 334
+a 3772 4106 1
+a 3773 3774 333
+a 3773 4106 1
+a 3774 3775 332
+a 3774 4106 1
+a 3775 3776 331
+a 3775 4106 1
+a 3776 3777 330
+a 3776 4106 1
+a 3777 3778 329
+a 3777 4106 1
+a 3778 3779 328
+a 3778 4106 1
+a 3779 3780 327
+a 3779 4106 1
+a 3780 3781 326
+a 3780 4106 1
+a 3781 3782 325
+a 3781 4106 1
+a 3782 3783 324
+a 3782 4106 1
+a 3783 3784 323
+a 3783 4106 1
+a 3784 3785 322
+a 3784 4106 1
+a 3785 3786 321
+a 3785 4106 1
+a 3786 3787 320
+a 3786 4106 1
+a 3787 3788 319
+a 3787 4106 1
+a 3788 3789 318
+a 3788 4106 1
+a 3789 3790 317
+a 3789 4106 1
+a 3790 3791 316
+a 3790 4106 1
+a 3791 3792 315
+a 3791 4106 1
+a 3792 3793 314
+a 3792 4106 1
+a 3793 3794 313
+a 3793 4106 1
+a 3794 3795 312
+a 3794 4106 1
+a 3795 3796 311
+a 3795 4106 1
+a 3796 3797 310
+a 3796 4106 1
+a 3797 3798 309
+a 3797 4106 1
+a 3798 3799 308
+a 3798 4106 1
+a 3799 3800 307
+a 3799 4106 1
+a 3800 3801 306
+a 3800 4106 1
+a 3801 3802 305
+a 3801 4106 1
+a 3802 3803 304
+a 3802 4106 1
+a 3803 3804 303
+a 3803 4106 1
+a 3804 3805 302
+a 3804 4106 1
+a 3805 3806 301
+a 3805 4106 1
+a 3806 3807 300
+a 3806 4106 1
+a 3807 3808 299
+a 3807 4106 1
+a 3808 3809 298
+a 3808 4106 1
+a 3809 3810 297
+a 3809 4106 1
+a 3810 3811 296
+a 3810 4106 1
+a 3811 3812 295
+a 3811 4106 1
+a 3812 3813 294
+a 3812 4106 1
+a 3813 3814 293
+a 3813 4106 1
+a 3814 3815 292
+a 3814 4106 1
+a 3815 3816 291
+a 3815 4106 1
+a 3816 3817 290
+a 3816 4106 1
+a 3817 3818 289
+a 3817 4106 1
+a 3818 3819 288
+a 3818 4106 1
+a 3819 3820 287
+a 3819 4106 1
+a 3820 3821 286
+a 3820 4106 1
+a 3821 3822 285
+a 3821 4106 1
+a 3822 3823 284
+a 3822 4106 1
+a 3823 3824 283
+a 3823 4106 1
+a 3824 3825 282
+a 3824 4106 1
+a 3825 3826 281
+a 3825 4106 1
+a 3826 3827 280
+a 3826 4106 1
+a 3827 3828 279
+a 3827 4106 1
+a 3828 3829 278
+a 3828 4106 1
+a 3829 3830 277
+a 3829 4106 1
+a 3830 3831 276
+a 3830 4106 1
+a 3831 3832 275
+a 3831 4106 1
+a 3832 3833 274
+a 3832 4106 1
+a 3833 3834 273
+a 3833 4106 1
+a 3834 3835 272
+a 3834 4106 1
+a 3835 3836 271
+a 3835 4106 1
+a 3836 3837 270
+a 3836 4106 1
+a 3837 3838 269
+a 3837 4106 1
+a 3838 3839 268
+a 3838 4106 1
+a 3839 3840 267
+a 3839 4106 1
+a 3840 3841 266
+a 3840 4106 1
+a 3841 3842 265
+a 3841 4106 1
+a 3842 3843 264
+a 3842 4106 1
+a 3843 3844 263
+a 3843 4106 1
+a 3844 3845 262
+a 3844 4106 1
+a 3845 3846 261
+a 3845 4106 1
+a 3846 3847 260
+a 3846 4106 1
+a 3847 3848 259
+a 3847 4106 1
+a 3848 3849 258
+a 3848 4106 1
+a 3849 3850 257
+a 3849 4106 1
+a 3850 3851 256
+a 3850 4106 1
+a 3851 3852 255
+a 3851 4106 1
+a 3852 3853 254
+a 3852 4106 1
+a 3853 3854 253
+a 3853 4106 1
+a 3854 3855 252
+a 3854 4106 1
+a 3855 3856 251
+a 3855 4106 1
+a 3856 3857 250
+a 3856 4106 1
+a 3857 3858 249
+a 3857 4106 1
+a 3858 3859 248
+a 3858 4106 1
+a 3859 3860 247
+a 3859 4106 1
+a 3860 3861 246
+a 3860 4106 1
+a 3861 3862 245
+a 3861 4106 1
+a 3862 3863 244
+a 3862 4106 1
+a 3863 3864 243
+a 3863 4106 1
+a 3864 3865 242
+a 3864 4106 1
+a 3865 3866 241
+a 3865 4106 1
+a 3866 3867 240
+a 3866 4106 1
+a 3867 3868 239
+a 3867 4106 1
+a 3868 3869 238
+a 3868 4106 1
+a 3869 3870 237
+a 3869 4106 1
+a 3870 3871 236
+a 3870 4106 1
+a 3871 3872 235
+a 3871 4106 1
+a 3872 3873 234
+a 3872 4106 1
+a 3873 3874 233
+a 3873 4106 1
+a 3874 3875 232
+a 3874 4106 1
+a 3875 3876 231
+a 3875 4106 1
+a 3876 3877 230
+a 3876 4106 1
+a 3877 3878 229
+a 3877 4106 1
+a 3878 3879 228
+a 3878 4106 1
+a 3879 3880 227
+a 3879 4106 1
+a 3880 3881 226
+a 3880 4106 1
+a 3881 3882 225
+a 3881 4106 1
+a 3882 3883 224
+a 3882 4106 1
+a 3883 3884 223
+a 3883 4106 1
+a 3884 3885 222
+a 3884 4106 1
+a 3885 3886 221
+a 3885 4106 1
+a 3886 3887 220
+a 3886 4106 1
+a 3887 3888 219
+a 3887 4106 1
+a 3888 3889 218
+a 3888 4106 1
+a 3889 3890 217
+a 3889 4106 1
+a 3890 3891 216
+a 3890 4106 1
+a 3891 3892 215
+a 3891 4106 1
+a 3892 3893 214
+a 3892 4106 1
+a 3893 3894 213
+a 3893 4106 1
+a 3894 3895 212
+a 3894 4106 1
+a 3895 3896 211
+a 3895 4106 1
+a 3896 3897 210
+a 3896 4106 1
+a 3897 3898 209
+a 3897 4106 1
+a 3898 3899 208
+a 3898 4106 1
+a 3899 3900 207
+a 3899 4106 1
+a 3900 3901 206
+a 3900 4106 1
+a 3901 3902 205
+a 3901 4106 1
+a 3902 3903 204
+a 3902 4106 1
+a 3903 3904 203
+a 3903 4106 1
+a 3904 3905 202
+a 3904 4106 1
+a 3905 3906 201
+a 3905 4106 1
+a 3906 3907 200
+a 3906 4106 1
+a 3907 3908 199
+a 3907 4106 1
+a 3908 3909 198
+a 3908 4106 1
+a 3909 3910 197
+a 3909 4106 1
+a 3910 3911 196
+a 3910 4106 1
+a 3911 3912 195
+a 3911 4106 1
+a 3912 3913 194
+a 3912 4106 1
+a 3913 3914 193
+a 3913 4106 1
+a 3914 3915 192
+a 3914 4106 1
+a 3915 3916 191
+a 3915 4106 1
+a 3916 3917 190
+a 3916 4106 1
+a 3917 3918 189
+a 3917 4106 1
+a 3918 3919 188
+a 3918 4106 1
+a 3919 3920 187
+a 3919 4106 1
+a 3920 3921 186
+a 3920 4106 1
+a 3921 3922 185
+a 3921 4106 1
+a 3922 3923 184
+a 3922 4106 1
+a 3923 3924 183
+a 3923 4106 1
+a 3924 3925 182
+a 3924 4106 1
+a 3925 3926 181
+a 3925 4106 1
+a 3926 3927 180
+a 3926 4106 1
+a 3927 3928 179
+a 3927 4106 1
+a 3928 3929 178
+a 3928 4106 1
+a 3929 3930 177
+a 3929 4106 1
+a 3930 3931 176
+a 3930 4106 1
+a 3931 3932 175
+a 3931 4106 1
+a 3932 3933 174
+a 3932 4106 1
+a 3933 3934 173
+a 3933 4106 1
+a 3934 3935 172
+a 3934 4106 1
+a 3935 3936 171
+a 3935 4106 1
+a 3936 3937 170
+a 3936 4106 1
+a 3937 3938 169
+a 3937 4106 1
+a 3938 3939 168
+a 3938 4106 1
+a 3939 3940 167
+a 3939 4106 1
+a 3940 3941 166
+a 3940 4106 1
+a 3941 3942 165
+a 3941 4106 1
+a 3942 3943 164
+a 3942 4106 1
+a 3943 3944 163
+a 3943 4106 1
+a 3944 3945 162
+a 3944 4106 1
+a 3945 3946 161
+a 3945 4106 1
+a 3946 3947 160
+a 3946 4106 1
+a 3947 3948 159
+a 3947 4106 1
+a 3948 3949 158
+a 3948 4106 1
+a 3949 3950 157
+a 3949 4106 1
+a 3950 3951 156
+a 3950 4106 1
+a 3951 3952 155
+a 3951 4106 1
+a 3952 3953 154
+a 3952 4106 1
+a 3953 3954 153
+a 3953 4106 1
+a 3954 3955 152
+a 3954 4106 1
+a 3955 3956 151
+a 3955 4106 1
+a 3956 3957 150
+a 3956 4106 1
+a 3957 3958 149
+a 3957 4106 1
+a 3958 3959 148
+a 3958 4106 1
+a 3959 3960 147
+a 3959 4106 1
+a 3960 3961 146
+a 3960 4106 1
+a 3961 3962 145
+a 3961 4106 1
+a 3962 3963 144
+a 3962 4106 1
+a 3963 3964 143
+a 3963 4106 1
+a 3964 3965 142
+a 3964 4106 1
+a 3965 3966 141
+a 3965 4106 1
+a 3966 3967 140
+a 3966 4106 1
+a 3967 3968 139
+a 3967 4106 1
+a 3968 3969 138
+a 3968 4106 1
+a 3969 3970 137
+a 3969 4106 1
+a 3970 3971 136
+a 3970 4106 1
+a 3971 3972 135
+a 3971 4106 1
+a 3972 3973 134
+a 3972 4106 1
+a 3973 3974 133
+a 3973 4106 1
+a 3974 3975 132
+a 3974 4106 1
+a 3975 3976 131
+a 3975 4106 1
+a 3976 3977 130
+a 3976 4106 1
+a 3977 3978 129
+a 3977 4106 1
+a 3978 3979 128
+a 3978 4106 1
+a 3979 3980 127
+a 3979 4106 1
+a 3980 3981 126
+a 3980 4106 1
+a 3981 3982 125
+a 3981 4106 1
+a 3982 3983 124
+a 3982 4106 1
+a 3983 3984 123
+a 3983 4106 1
+a 3984 3985 122
+a 3984 4106 1
+a 3985 3986 121
+a 3985 4106 1
+a 3986 3987 120
+a 3986 4106 1
+a 3987 3988 119
+a 3987 4106 1
+a 3988 3989 118
+a 3988 4106 1
+a 3989 3990 117
+a 3989 4106 1
+a 3990 3991 116
+a 3990 4106 1
+a 3991 3992 115
+a 3991 4106 1
+a 3992 3993 114
+a 3992 4106 1
+a 3993 3994 113
+a 3993 4106 1
+a 3994 3995 112
+a 3994 4106 1
+a 3995 3996 111
+a 3995 4106 1
+a 3996 3997 110
+a 3996 4106 1
+a 3997 3998 109
+a 3997 4106 1
+a 3998 3999 108
+a 3998 4106 1
+a 3999 4000 107
+a 3999 4106 1
+a 4000 4001 106
+a 4000 4106 1
+a 4001 4002 105
+a 4001 4106 1
+a 4002 4003 104
+a 4002 4106 1
+a 4003 4004 103
+a 4003 4106 1
+a 4004 4005 102
+a 4004 4106 1
+a 4005 4006 101
+a 4005 4106 1
+a 4006 4007 100
+a 4006 4106 1
+a 4007 4008 99
+a 4007 4106 1
+a 4008 4009 98
+a 4008 4106 1
+a 4009 4010 97
+a 4009 4106 1
+a 4010 4011 96
+a 4010 4106 1
+a 4011 4012 95
+a 4011 4106 1
+a 4012 4013 94
+a 4012 4106 1
+a 4013 4014 93
+a 4013 4106 1
+a 4014 4015 92
+a 4014 4106 1
+a 4015 4016 91
+a 4015 4106 1
+a 4016 4017 90
+a 4016 4106 1
+a 4017 4018 89
+a 4017 4106 1
+a 4018 4019 88
+a 4018 4106 1
+a 4019 4020 87
+a 4019 4106 1
+a 4020 4021 86
+a 4020 4106 1
+a 4021 4022 85
+a 4021 4106 1
+a 4022 4023 84
+a 4022 4106 1
+a 4023 4024 83
+a 4023 4106 1
+a 4024 4025 82
+a 4024 4106 1
+a 4025 4026 81
+a 4025 4106 1
+a 4026 4027 80
+a 4026 4106 1
+a 4027 4028 79
+a 4027 4106 1
+a 4028 4029 78
+a 4028 4106 1
+a 4029 4030 77
+a 4029 4106 1
+a 4030 4031 76
+a 4030 4106 1
+a 4031 4032 75
+a 4031 4106 1
+a 4032 4033 74
+a 4032 4106 1
+a 4033 4034 73
+a 4033 4106 1
+a 4034 4035 72
+a 4034 4106 1
+a 4035 4036 71
+a 4035 4106 1
+a 4036 4037 70
+a 4036 4106 1
+a 4037 4038 69
+a 4037 4106 1
+a 4038 4039 68
+a 4038 4106 1
+a 4039 4040 67
+a 4039 4106 1
+a 4040 4041 66
+a 4040 4106 1
+a 4041 4042 65
+a 4041 4106 1
+a 4042 4043 64
+a 4042 4106 1
+a 4043 4044 63
+a 4043 4106 1
+a 4044 4045 62
+a 4044 4106 1
+a 4045 4046 61
+a 4045 4106 1
+a 4046 4047 60
+a 4046 4106 1
+a 4047 4048 59
+a 4047 4106 1
+a 4048 4049 58
+a 4048 4106 1
+a 4049 4050 57
+a 4049 4106 1
+a 4050 4051 56
+a 4050 4106 1
+a 4051 4052 55
+a 4051 4106 1
+a 4052 4053 54
+a 4052 4106 1
+a 4053 4054 53
+a 4053 4106 1
+a 4054 4055 52
+a 4054 4106 1
+a 4055 4056 51
+a 4055 4106 1
+a 4056 4057 50
+a 4056 4106 1
+a 4057 4058 49
+a 4057 4106 1
+a 4058 4059 48
+a 4058 4106 1
+a 4059 4060 47
+a 4059 4106 1
+a 4060 4061 46
+a 4060 4106 1
+a 4061 4062 45
+a 4061 4106 1
+a 4062 4063 44
+a 4062 4106 1
+a 4063 4064 43
+a 4063 4106 1
+a 4064 4065 42
+a 4064 4106 1
+a 4065 4066 41
+a 4065 4106 1
+a 4066 4067 40
+a 4066 4106 1
+a 4067 4068 39
+a 4067 4106 1
+a 4068 4069 38
+a 4068 4106 1
+a 4069 4070 37
+a 4069 4106 1
+a 4070 4071 36
+a 4070 4106 1
+a 4071 4072 35
+a 4071 4106 1
+a 4072 4073 34
+a 4072 4106 1
+a 4073 4074 33
+a 4073 4106 1
+a 4074 4075 32
+a 4074 4106 1
+a 4075 4076 31
+a 4075 4106 1
+a 4076 4077 30
+a 4076 4106 1
+a 4077 4078 29
+a 4077 4106 1
+a 4078 4079 28
+a 4078 4106 1
+a 4079 4080 27
+a 4079 4106 1
+a 4080 4081 26
+a 4080 4106 1
+a 4081 4082 25
+a 4081 4106 1
+a 4082 4083 24
+a 4082 4106 1
+a 4083 4084 23
+a 4083 4106 1
+a 4084 4085 22
+a 4084 4106 1
+a 4085 4086 21
+a 4085 4106 1
+a 4086 4087 20
+a 4086 4106 1
+a 4087 4088 19
+a 4087 4106 1
+a 4088 4089 18
+a 4088 4106 1
+a 4089 4090 17
+a 4089 4106 1
+a 4090 4091 16
+a 4090 4106 1
+a 4091 4092 15
+a 4091 4106 1
+a 4092 4093 14
+a 4092 4106 1
+a 4093 4094 13
+a 4093 4106 1
+a 4094 4095 12
+a 4094 4106 1
+a 4095 4096 11
+a 4095 4106 1
+a 4096 4097 10
+a 4096 4106 1
+a 4097 4098 9
+a 4097 4106 1
+a 4098 4099 8
+a 4098 4106 1
+a 4099 4100 7
+a 4099 4106 1
+a 4100 4101 6
+a 4100 4106 1
+a 4101 4102 5
+a 4101 4106 1
+a 4102 4103 4
+a 4102 4106 1
+a 4103 4104 3
+a 4103 4106 1
+a 4104 4105 2
+a 4104 4106 1
+a 4105 8208 1
+a 4105 4106 1
+a 4106 4107 4103
+a 4107 4108 4103
+a 4108 4109 4103
+a 4109 4110 4103
+a 4110 4111 4103
+a 4111 4112 4103
+a 4112 4113 4103
+a 4113 4114 4103
+a 4114 4115 4103
+a 4115 4116 4103
+a 4116 4117 4103
+a 4117 4118 4103
+a 4118 4119 4103
+a 4119 4120 4103
+a 4120 4121 4103
+a 4121 4122 4103
+a 4122 4123 4103
+a 4123 4124 4103
+a 4124 4125 4103
+a 4125 4126 4103
+a 4126 4127 4103
+a 4127 4128 4103
+a 4128 4129 4103
+a 4129 4130 4103
+a 4130 4131 4103
+a 4131 4132 4103
+a 4132 4133 4103
+a 4133 4134 4103
+a 4134 4135 4103
+a 4135 4136 4103
+a 4136 4137 4103
+a 4137 4138 4103
+a 4138 4139 4103
+a 4139 4140 4103
+a 4140 4141 4103
+a 4141 4142 4103
+a 4142 4143 4103
+a 4143 4144 4103
+a 4144 4145 4103
+a 4145 4146 4103
+a 4146 4147 4103
+a 4147 4148 4103
+a 4148 4149 4103
+a 4149 4150 4103
+a 4150 4151 4103
+a 4151 4152 4103
+a 4152 4153 4103
+a 4153 4154 4103
+a 4154 4155 4103
+a 4155 4156 4103
+a 4156 4157 4103
+a 4157 4158 4103
+a 4158 4159 4103
+a 4159 4160 4103
+a 4160 4161 4103
+a 4161 4162 4103
+a 4162 4163 4103
+a 4163 4164 4103
+a 4164 4165 4103
+a 4165 4166 4103
+a 4166 4167 4103
+a 4167 4168 4103
+a 4168 4169 4103
+a 4169 4170 4103
+a 4170 4171 4103
+a 4171 4172 4103
+a 4172 4173 4103
+a 4173 4174 4103
+a 4174 4175 4103
+a 4175 4176 4103
+a 4176 4177 4103
+a 4177 4178 4103
+a 4178 4179 4103
+a 4179 4180 4103
+a 4180 4181 4103
+a 4181 4182 4103
+a 4182 4183 4103
+a 4183 4184 4103
+a 4184 4185 4103
+a 4185 4186 4103
+a 4186 4187 4103
+a 4187 4188 4103
+a 4188 4189 4103
+a 4189 4190 4103
+a 4190 4191 4103
+a 4191 4192 4103
+a 4192 4193 4103
+a 4193 4194 4103
+a 4194 4195 4103
+a 4195 4196 4103
+a 4196 4197 4103
+a 4197 4198 4103
+a 4198 4199 4103
+a 4199 4200 4103
+a 4200 4201 4103
+a 4201 4202 4103
+a 4202 4203 4103
+a 4203 4204 4103
+a 4204 4205 4103
+a 4205 4206 4103
+a 4206 4207 4103
+a 4207 4208 4103
+a 4208 4209 4103
+a 4209 4210 4103
+a 4210 4211 4103
+a 4211 4212 4103
+a 4212 4213 4103
+a 4213 4214 4103
+a 4214 4215 4103
+a 4215 4216 4103
+a 4216 4217 4103
+a 4217 4218 4103
+a 4218 4219 4103
+a 4219 4220 4103
+a 4220 4221 4103
+a 4221 4222 4103
+a 4222 4223 4103
+a 4223 4224 4103
+a 4224 4225 4103
+a 4225 4226 4103
+a 4226 4227 4103
+a 4227 4228 4103
+a 4228 4229 4103
+a 4229 4230 4103
+a 4230 4231 4103
+a 4231 4232 4103
+a 4232 4233 4103
+a 4233 4234 4103
+a 4234 4235 4103
+a 4235 4236 4103
+a 4236 4237 4103
+a 4237 4238 4103
+a 4238 4239 4103
+a 4239 4240 4103
+a 4240 4241 4103
+a 4241 4242 4103
+a 4242 4243 4103
+a 4243 4244 4103
+a 4244 4245 4103
+a 4245 4246 4103
+a 4246 4247 4103
+a 4247 4248 4103
+a 4248 4249 4103
+a 4249 4250 4103
+a 4250 4251 4103
+a 4251 4252 4103
+a 4252 4253 4103
+a 4253 4254 4103
+a 4254 4255 4103
+a 4255 4256 4103
+a 4256 4257 4103
+a 4257 4258 4103
+a 4258 4259 4103
+a 4259 4260 4103
+a 4260 4261 4103
+a 4261 4262 4103
+a 4262 4263 4103
+a 4263 4264 4103
+a 4264 4265 4103
+a 4265 4266 4103
+a 4266 4267 4103
+a 4267 4268 4103
+a 4268 4269 4103
+a 4269 4270 4103
+a 4270 4271 4103
+a 4271 4272 4103
+a 4272 4273 4103
+a 4273 4274 4103
+a 4274 4275 4103
+a 4275 4276 4103
+a 4276 4277 4103
+a 4277 4278 4103
+a 4278 4279 4103
+a 4279 4280 4103
+a 4280 4281 4103
+a 4281 4282 4103
+a 4282 4283 4103
+a 4283 4284 4103
+a 4284 4285 4103
+a 4285 4286 4103
+a 4286 4287 4103
+a 4287 4288 4103
+a 4288 4289 4103
+a 4289 4290 4103
+a 4290 4291 4103
+a 4291 4292 4103
+a 4292 4293 4103
+a 4293 4294 4103
+a 4294 4295 4103
+a 4295 4296 4103
+a 4296 4297 4103
+a 4297 4298 4103
+a 4298 4299 4103
+a 4299 4300 4103
+a 4300 4301 4103
+a 4301 4302 4103
+a 4302 4303 4103
+a 4303 4304 4103
+a 4304 4305 4103
+a 4305 4306 4103
+a 4306 4307 4103
+a 4307 4308 4103
+a 4308 4309 4103
+a 4309 4310 4103
+a 4310 4311 4103
+a 4311 4312 4103
+a 4312 4313 4103
+a 4313 4314 4103
+a 4314 4315 4103
+a 4315 4316 4103
+a 4316 4317 4103
+a 4317 4318 4103
+a 4318 4319 4103
+a 4319 4320 4103
+a 4320 4321 4103
+a 4321 4322 4103
+a 4322 4323 4103
+a 4323 4324 4103
+a 4324 4325 4103
+a 4325 4326 4103
+a 4326 4327 4103
+a 4327 4328 4103
+a 4328 4329 4103
+a 4329 4330 4103
+a 4330 4331 4103
+a 4331 4332 4103
+a 4332 4333 4103
+a 4333 4334 4103
+a 4334 4335 4103
+a 4335 4336 4103
+a 4336 4337 4103
+a 4337 4338 4103
+a 4338 4339 4103
+a 4339 4340 4103
+a 4340 4341 4103
+a 4341 4342 4103
+a 4342 4343 4103
+a 4343 4344 4103
+a 4344 4345 4103
+a 4345 4346 4103
+a 4346 4347 4103
+a 4347 4348 4103
+a 4348 4349 4103
+a 4349 4350 4103
+a 4350 4351 4103
+a 4351 4352 4103
+a 4352 4353 4103
+a 4353 4354 4103
+a 4354 4355 4103
+a 4355 4356 4103
+a 4356 4357 4103
+a 4357 4358 4103
+a 4358 4359 4103
+a 4359 4360 4103
+a 4360 4361 4103
+a 4361 4362 4103
+a 4362 4363 4103
+a 4363 4364 4103
+a 4364 4365 4103
+a 4365 4366 4103
+a 4366 4367 4103
+a 4367 4368 4103
+a 4368 4369 4103
+a 4369 4370 4103
+a 4370 4371 4103
+a 4371 4372 4103
+a 4372 4373 4103
+a 4373 4374 4103
+a 4374 4375 4103
+a 4375 4376 4103
+a 4376 4377 4103
+a 4377 4378 4103
+a 4378 4379 4103
+a 4379 4380 4103
+a 4380 4381 4103
+a 4381 4382 4103
+a 4382 4383 4103
+a 4383 4384 4103
+a 4384 4385 4103
+a 4385 4386 4103
+a 4386 4387 4103
+a 4387 4388 4103
+a 4388 4389 4103
+a 4389 4390 4103
+a 4390 4391 4103
+a 4391 4392 4103
+a 4392 4393 4103
+a 4393 4394 4103
+a 4394 4395 4103
+a 4395 4396 4103
+a 4396 4397 4103
+a 4397 4398 4103
+a 4398 4399 4103
+a 4399 4400 4103
+a 4400 4401 4103
+a 4401 4402 4103
+a 4402 4403 4103
+a 4403 4404 4103
+a 4404 4405 4103
+a 4405 4406 4103
+a 4406 4407 4103
+a 4407 4408 4103
+a 4408 4409 4103
+a 4409 4410 4103
+a 4410 4411 4103
+a 4411 4412 4103
+a 4412 4413 4103
+a 4413 4414 4103
+a 4414 4415 4103
+a 4415 4416 4103
+a 4416 4417 4103
+a 4417 4418 4103
+a 4418 4419 4103
+a 4419 4420 4103
+a 4420 4421 4103
+a 4421 4422 4103
+a 4422 4423 4103
+a 4423 4424 4103
+a 4424 4425 4103
+a 4425 4426 4103
+a 4426 4427 4103
+a 4427 4428 4103
+a 4428 4429 4103
+a 4429 4430 4103
+a 4430 4431 4103
+a 4431 4432 4103
+a 4432 4433 4103
+a 4433 4434 4103
+a 4434 4435 4103
+a 4435 4436 4103
+a 4436 4437 4103
+a 4437 4438 4103
+a 4438 4439 4103
+a 4439 4440 4103
+a 4440 4441 4103
+a 4441 4442 4103
+a 4442 4443 4103
+a 4443 4444 4103
+a 4444 4445 4103
+a 4445 4446 4103
+a 4446 4447 4103
+a 4447 4448 4103
+a 4448 4449 4103
+a 4449 4450 4103
+a 4450 4451 4103
+a 4451 4452 4103
+a 4452 4453 4103
+a 4453 4454 4103
+a 4454 4455 4103
+a 4455 4456 4103
+a 4456 4457 4103
+a 4457 4458 4103
+a 4458 4459 4103
+a 4459 4460 4103
+a 4460 4461 4103
+a 4461 4462 4103
+a 4462 4463 4103
+a 4463 4464 4103
+a 4464 4465 4103
+a 4465 4466 4103
+a 4466 4467 4103
+a 4467 4468 4103
+a 4468 4469 4103
+a 4469 4470 4103
+a 4470 4471 4103
+a 4471 4472 4103
+a 4472 4473 4103
+a 4473 4474 4103
+a 4474 4475 4103
+a 4475 4476 4103
+a 4476 4477 4103
+a 4477 4478 4103
+a 4478 4479 4103
+a 4479 4480 4103
+a 4480 4481 4103
+a 4481 4482 4103
+a 4482 4483 4103
+a 4483 4484 4103
+a 4484 4485 4103
+a 4485 4486 4103
+a 4486 4487 4103
+a 4487 4488 4103
+a 4488 4489 4103
+a 4489 4490 4103
+a 4490 4491 4103
+a 4491 4492 4103
+a 4492 4493 4103
+a 4493 4494 4103
+a 4494 4495 4103
+a 4495 4496 4103
+a 4496 4497 4103
+a 4497 4498 4103
+a 4498 4499 4103
+a 4499 4500 4103
+a 4500 4501 4103
+a 4501 4502 4103
+a 4502 4503 4103
+a 4503 4504 4103
+a 4504 4505 4103
+a 4505 4506 4103
+a 4506 4507 4103
+a 4507 4508 4103
+a 4508 4509 4103
+a 4509 4510 4103
+a 4510 4511 4103
+a 4511 4512 4103
+a 4512 4513 4103
+a 4513 4514 4103
+a 4514 4515 4103
+a 4515 4516 4103
+a 4516 4517 4103
+a 4517 4518 4103
+a 4518 4519 4103
+a 4519 4520 4103
+a 4520 4521 4103
+a 4521 4522 4103
+a 4522 4523 4103
+a 4523 4524 4103
+a 4524 4525 4103
+a 4525 4526 4103
+a 4526 4527 4103
+a 4527 4528 4103
+a 4528 4529 4103
+a 4529 4530 4103
+a 4530 4531 4103
+a 4531 4532 4103
+a 4532 4533 4103
+a 4533 4534 4103
+a 4534 4535 4103
+a 4535 4536 4103
+a 4536 4537 4103
+a 4537 4538 4103
+a 4538 4539 4103
+a 4539 4540 4103
+a 4540 4541 4103
+a 4541 4542 4103
+a 4542 4543 4103
+a 4543 4544 4103
+a 4544 4545 4103
+a 4545 4546 4103
+a 4546 4547 4103
+a 4547 4548 4103
+a 4548 4549 4103
+a 4549 4550 4103
+a 4550 4551 4103
+a 4551 4552 4103
+a 4552 4553 4103
+a 4553 4554 4103
+a 4554 4555 4103
+a 4555 4556 4103
+a 4556 4557 4103
+a 4557 4558 4103
+a 4558 4559 4103
+a 4559 4560 4103
+a 4560 4561 4103
+a 4561 4562 4103
+a 4562 4563 4103
+a 4563 4564 4103
+a 4564 4565 4103
+a 4565 4566 4103
+a 4566 4567 4103
+a 4567 4568 4103
+a 4568 4569 4103
+a 4569 4570 4103
+a 4570 4571 4103
+a 4571 4572 4103
+a 4572 4573 4103
+a 4573 4574 4103
+a 4574 4575 4103
+a 4575 4576 4103
+a 4576 4577 4103
+a 4577 4578 4103
+a 4578 4579 4103
+a 4579 4580 4103
+a 4580 4581 4103
+a 4581 4582 4103
+a 4582 4583 4103
+a 4583 4584 4103
+a 4584 4585 4103
+a 4585 4586 4103
+a 4586 4587 4103
+a 4587 4588 4103
+a 4588 4589 4103
+a 4589 4590 4103
+a 4590 4591 4103
+a 4591 4592 4103
+a 4592 4593 4103
+a 4593 4594 4103
+a 4594 4595 4103
+a 4595 4596 4103
+a 4596 4597 4103
+a 4597 4598 4103
+a 4598 4599 4103
+a 4599 4600 4103
+a 4600 4601 4103
+a 4601 4602 4103
+a 4602 4603 4103
+a 4603 4604 4103
+a 4604 4605 4103
+a 4605 4606 4103
+a 4606 4607 4103
+a 4607 4608 4103
+a 4608 4609 4103
+a 4609 4610 4103
+a 4610 4611 4103
+a 4611 4612 4103
+a 4612 4613 4103
+a 4613 4614 4103
+a 4614 4615 4103
+a 4615 4616 4103
+a 4616 4617 4103
+a 4617 4618 4103
+a 4618 4619 4103
+a 4619 4620 4103
+a 4620 4621 4103
+a 4621 4622 4103
+a 4622 4623 4103
+a 4623 4624 4103
+a 4624 4625 4103
+a 4625 4626 4103
+a 4626 4627 4103
+a 4627 4628 4103
+a 4628 4629 4103
+a 4629 4630 4103
+a 4630 4631 4103
+a 4631 4632 4103
+a 4632 4633 4103
+a 4633 4634 4103
+a 4634 4635 4103
+a 4635 4636 4103
+a 4636 4637 4103
+a 4637 4638 4103
+a 4638 4639 4103
+a 4639 4640 4103
+a 4640 4641 4103
+a 4641 4642 4103
+a 4642 4643 4103
+a 4643 4644 4103
+a 4644 4645 4103
+a 4645 4646 4103
+a 4646 4647 4103
+a 4647 4648 4103
+a 4648 4649 4103
+a 4649 4650 4103
+a 4650 4651 4103
+a 4651 4652 4103
+a 4652 4653 4103
+a 4653 4654 4103
+a 4654 4655 4103
+a 4655 4656 4103
+a 4656 4657 4103
+a 4657 4658 4103
+a 4658 4659 4103
+a 4659 4660 4103
+a 4660 4661 4103
+a 4661 4662 4103
+a 4662 4663 4103
+a 4663 4664 4103
+a 4664 4665 4103
+a 4665 4666 4103
+a 4666 4667 4103
+a 4667 4668 4103
+a 4668 4669 4103
+a 4669 4670 4103
+a 4670 4671 4103
+a 4671 4672 4103
+a 4672 4673 4103
+a 4673 4674 4103
+a 4674 4675 4103
+a 4675 4676 4103
+a 4676 4677 4103
+a 4677 4678 4103
+a 4678 4679 4103
+a 4679 4680 4103
+a 4680 4681 4103
+a 4681 4682 4103
+a 4682 4683 4103
+a 4683 4684 4103
+a 4684 4685 4103
+a 4685 4686 4103
+a 4686 4687 4103
+a 4687 4688 4103
+a 4688 4689 4103
+a 4689 4690 4103
+a 4690 4691 4103
+a 4691 4692 4103
+a 4692 4693 4103
+a 4693 4694 4103
+a 4694 4695 4103
+a 4695 4696 4103
+a 4696 4697 4103
+a 4697 4698 4103
+a 4698 4699 4103
+a 4699 4700 4103
+a 4700 4701 4103
+a 4701 4702 4103
+a 4702 4703 4103
+a 4703 4704 4103
+a 4704 4705 4103
+a 4705 4706 4103
+a 4706 4707 4103
+a 4707 4708 4103
+a 4708 4709 4103
+a 4709 4710 4103
+a 4710 4711 4103
+a 4711 4712 4103
+a 4712 4713 4103
+a 4713 4714 4103
+a 4714 4715 4103
+a 4715 4716 4103
+a 4716 4717 4103
+a 4717 4718 4103
+a 4718 4719 4103
+a 4719 4720 4103
+a 4720 4721 4103
+a 4721 4722 4103
+a 4722 4723 4103
+a 4723 4724 4103
+a 4724 4725 4103
+a 4725 4726 4103
+a 4726 4727 4103
+a 4727 4728 4103
+a 4728 4729 4103
+a 4729 4730 4103
+a 4730 4731 4103
+a 4731 4732 4103
+a 4732 4733 4103
+a 4733 4734 4103
+a 4734 4735 4103
+a 4735 4736 4103
+a 4736 4737 4103
+a 4737 4738 4103
+a 4738 4739 4103
+a 4739 4740 4103
+a 4740 4741 4103
+a 4741 4742 4103
+a 4742 4743 4103
+a 4743 4744 4103
+a 4744 4745 4103
+a 4745 4746 4103
+a 4746 4747 4103
+a 4747 4748 4103
+a 4748 4749 4103
+a 4749 4750 4103
+a 4750 4751 4103
+a 4751 4752 4103
+a 4752 4753 4103
+a 4753 4754 4103
+a 4754 4755 4103
+a 4755 4756 4103
+a 4756 4757 4103
+a 4757 4758 4103
+a 4758 4759 4103
+a 4759 4760 4103
+a 4760 4761 4103
+a 4761 4762 4103
+a 4762 4763 4103
+a 4763 4764 4103
+a 4764 4765 4103
+a 4765 4766 4103
+a 4766 4767 4103
+a 4767 4768 4103
+a 4768 4769 4103
+a 4769 4770 4103
+a 4770 4771 4103
+a 4771 4772 4103
+a 4772 4773 4103
+a 4773 4774 4103
+a 4774 4775 4103
+a 4775 4776 4103
+a 4776 4777 4103
+a 4777 4778 4103
+a 4778 4779 4103
+a 4779 4780 4103
+a 4780 4781 4103
+a 4781 4782 4103
+a 4782 4783 4103
+a 4783 4784 4103
+a 4784 4785 4103
+a 4785 4786 4103
+a 4786 4787 4103
+a 4787 4788 4103
+a 4788 4789 4103
+a 4789 4790 4103
+a 4790 4791 4103
+a 4791 4792 4103
+a 4792 4793 4103
+a 4793 4794 4103
+a 4794 4795 4103
+a 4795 4796 4103
+a 4796 4797 4103
+a 4797 4798 4103
+a 4798 4799 4103
+a 4799 4800 4103
+a 4800 4801 4103
+a 4801 4802 4103
+a 4802 4803 4103
+a 4803 4804 4103
+a 4804 4805 4103
+a 4805 4806 4103
+a 4806 4807 4103
+a 4807 4808 4103
+a 4808 4809 4103
+a 4809 4810 4103
+a 4810 4811 4103
+a 4811 4812 4103
+a 4812 4813 4103
+a 4813 4814 4103
+a 4814 4815 4103
+a 4815 4816 4103
+a 4816 4817 4103
+a 4817 4818 4103
+a 4818 4819 4103
+a 4819 4820 4103
+a 4820 4821 4103
+a 4821 4822 4103
+a 4822 4823 4103
+a 4823 4824 4103
+a 4824 4825 4103
+a 4825 4826 4103
+a 4826 4827 4103
+a 4827 4828 4103
+a 4828 4829 4103
+a 4829 4830 4103
+a 4830 4831 4103
+a 4831 4832 4103
+a 4832 4833 4103
+a 4833 4834 4103
+a 4834 4835 4103
+a 4835 4836 4103
+a 4836 4837 4103
+a 4837 4838 4103
+a 4838 4839 4103
+a 4839 4840 4103
+a 4840 4841 4103
+a 4841 4842 4103
+a 4842 4843 4103
+a 4843 4844 4103
+a 4844 4845 4103
+a 4845 4846 4103
+a 4846 4847 4103
+a 4847 4848 4103
+a 4848 4849 4103
+a 4849 4850 4103
+a 4850 4851 4103
+a 4851 4852 4103
+a 4852 4853 4103
+a 4853 4854 4103
+a 4854 4855 4103
+a 4855 4856 4103
+a 4856 4857 4103
+a 4857 4858 4103
+a 4858 4859 4103
+a 4859 4860 4103
+a 4860 4861 4103
+a 4861 4862 4103
+a 4862 4863 4103
+a 4863 4864 4103
+a 4864 4865 4103
+a 4865 4866 4103
+a 4866 4867 4103
+a 4867 4868 4103
+a 4868 4869 4103
+a 4869 4870 4103
+a 4870 4871 4103
+a 4871 4872 4103
+a 4872 4873 4103
+a 4873 4874 4103
+a 4874 4875 4103
+a 4875 4876 4103
+a 4876 4877 4103
+a 4877 4878 4103
+a 4878 4879 4103
+a 4879 4880 4103
+a 4880 4881 4103
+a 4881 4882 4103
+a 4882 4883 4103
+a 4883 4884 4103
+a 4884 4885 4103
+a 4885 4886 4103
+a 4886 4887 4103
+a 4887 4888 4103
+a 4888 4889 4103
+a 4889 4890 4103
+a 4890 4891 4103
+a 4891 4892 4103
+a 4892 4893 4103
+a 4893 4894 4103
+a 4894 4895 4103
+a 4895 4896 4103
+a 4896 4897 4103
+a 4897 4898 4103
+a 4898 4899 4103
+a 4899 4900 4103
+a 4900 4901 4103
+a 4901 4902 4103
+a 4902 4903 4103
+a 4903 4904 4103
+a 4904 4905 4103
+a 4905 4906 4103
+a 4906 4907 4103
+a 4907 4908 4103
+a 4908 4909 4103
+a 4909 4910 4103
+a 4910 4911 4103
+a 4911 4912 4103
+a 4912 4913 4103
+a 4913 4914 4103
+a 4914 4915 4103
+a 4915 4916 4103
+a 4916 4917 4103
+a 4917 4918 4103
+a 4918 4919 4103
+a 4919 4920 4103
+a 4920 4921 4103
+a 4921 4922 4103
+a 4922 4923 4103
+a 4923 4924 4103
+a 4924 4925 4103
+a 4925 4926 4103
+a 4926 4927 4103
+a 4927 4928 4103
+a 4928 4929 4103
+a 4929 4930 4103
+a 4930 4931 4103
+a 4931 4932 4103
+a 4932 4933 4103
+a 4933 4934 4103
+a 4934 4935 4103
+a 4935 4936 4103
+a 4936 4937 4103
+a 4937 4938 4103
+a 4938 4939 4103
+a 4939 4940 4103
+a 4940 4941 4103
+a 4941 4942 4103
+a 4942 4943 4103
+a 4943 4944 4103
+a 4944 4945 4103
+a 4945 4946 4103
+a 4946 4947 4103
+a 4947 4948 4103
+a 4948 4949 4103
+a 4949 4950 4103
+a 4950 4951 4103
+a 4951 4952 4103
+a 4952 4953 4103
+a 4953 4954 4103
+a 4954 4955 4103
+a 4955 4956 4103
+a 4956 4957 4103
+a 4957 4958 4103
+a 4958 4959 4103
+a 4959 4960 4103
+a 4960 4961 4103
+a 4961 4962 4103
+a 4962 4963 4103
+a 4963 4964 4103
+a 4964 4965 4103
+a 4965 4966 4103
+a 4966 4967 4103
+a 4967 4968 4103
+a 4968 4969 4103
+a 4969 4970 4103
+a 4970 4971 4103
+a 4971 4972 4103
+a 4972 4973 4103
+a 4973 4974 4103
+a 4974 4975 4103
+a 4975 4976 4103
+a 4976 4977 4103
+a 4977 4978 4103
+a 4978 4979 4103
+a 4979 4980 4103
+a 4980 4981 4103
+a 4981 4982 4103
+a 4982 4983 4103
+a 4983 4984 4103
+a 4984 4985 4103
+a 4985 4986 4103
+a 4986 4987 4103
+a 4987 4988 4103
+a 4988 4989 4103
+a 4989 4990 4103
+a 4990 4991 4103
+a 4991 4992 4103
+a 4992 4993 4103
+a 4993 4994 4103
+a 4994 4995 4103
+a 4995 4996 4103
+a 4996 4997 4103
+a 4997 4998 4103
+a 4998 4999 4103
+a 4999 5000 4103
+a 5000 5001 4103
+a 5001 5002 4103
+a 5002 5003 4103
+a 5003 5004 4103
+a 5004 5005 4103
+a 5005 5006 4103
+a 5006 5007 4103
+a 5007 5008 4103
+a 5008 5009 4103
+a 5009 5010 4103
+a 5010 5011 4103
+a 5011 5012 4103
+a 5012 5013 4103
+a 5013 5014 4103
+a 5014 5015 4103
+a 5015 5016 4103
+a 5016 5017 4103
+a 5017 5018 4103
+a 5018 5019 4103
+a 5019 5020 4103
+a 5020 5021 4103
+a 5021 5022 4103
+a 5022 5023 4103
+a 5023 5024 4103
+a 5024 5025 4103
+a 5025 5026 4103
+a 5026 5027 4103
+a 5027 5028 4103
+a 5028 5029 4103
+a 5029 5030 4103
+a 5030 5031 4103
+a 5031 5032 4103
+a 5032 5033 4103
+a 5033 5034 4103
+a 5034 5035 4103
+a 5035 5036 4103
+a 5036 5037 4103
+a 5037 5038 4103
+a 5038 5039 4103
+a 5039 5040 4103
+a 5040 5041 4103
+a 5041 5042 4103
+a 5042 5043 4103
+a 5043 5044 4103
+a 5044 5045 4103
+a 5045 5046 4103
+a 5046 5047 4103
+a 5047 5048 4103
+a 5048 5049 4103
+a 5049 5050 4103
+a 5050 5051 4103
+a 5051 5052 4103
+a 5052 5053 4103
+a 5053 5054 4103
+a 5054 5055 4103
+a 5055 5056 4103
+a 5056 5057 4103
+a 5057 5058 4103
+a 5058 5059 4103
+a 5059 5060 4103
+a 5060 5061 4103
+a 5061 5062 4103
+a 5062 5063 4103
+a 5063 5064 4103
+a 5064 5065 4103
+a 5065 5066 4103
+a 5066 5067 4103
+a 5067 5068 4103
+a 5068 5069 4103
+a 5069 5070 4103
+a 5070 5071 4103
+a 5071 5072 4103
+a 5072 5073 4103
+a 5073 5074 4103
+a 5074 5075 4103
+a 5075 5076 4103
+a 5076 5077 4103
+a 5077 5078 4103
+a 5078 5079 4103
+a 5079 5080 4103
+a 5080 5081 4103
+a 5081 5082 4103
+a 5082 5083 4103
+a 5083 5084 4103
+a 5084 5085 4103
+a 5085 5086 4103
+a 5086 5087 4103
+a 5087 5088 4103
+a 5088 5089 4103
+a 5089 5090 4103
+a 5090 5091 4103
+a 5091 5092 4103
+a 5092 5093 4103
+a 5093 5094 4103
+a 5094 5095 4103
+a 5095 5096 4103
+a 5096 5097 4103
+a 5097 5098 4103
+a 5098 5099 4103
+a 5099 5100 4103
+a 5100 5101 4103
+a 5101 5102 4103
+a 5102 5103 4103
+a 5103 5104 4103
+a 5104 5105 4103
+a 5105 5106 4103
+a 5106 5107 4103
+a 5107 5108 4103
+a 5108 5109 4103
+a 5109 5110 4103
+a 5110 5111 4103
+a 5111 5112 4103
+a 5112 5113 4103
+a 5113 5114 4103
+a 5114 5115 4103
+a 5115 5116 4103
+a 5116 5117 4103
+a 5117 5118 4103
+a 5118 5119 4103
+a 5119 5120 4103
+a 5120 5121 4103
+a 5121 5122 4103
+a 5122 5123 4103
+a 5123 5124 4103
+a 5124 5125 4103
+a 5125 5126 4103
+a 5126 5127 4103
+a 5127 5128 4103
+a 5128 5129 4103
+a 5129 5130 4103
+a 5130 5131 4103
+a 5131 5132 4103
+a 5132 5133 4103
+a 5133 5134 4103
+a 5134 5135 4103
+a 5135 5136 4103
+a 5136 5137 4103
+a 5137 5138 4103
+a 5138 5139 4103
+a 5139 5140 4103
+a 5140 5141 4103
+a 5141 5142 4103
+a 5142 5143 4103
+a 5143 5144 4103
+a 5144 5145 4103
+a 5145 5146 4103
+a 5146 5147 4103
+a 5147 5148 4103
+a 5148 5149 4103
+a 5149 5150 4103
+a 5150 5151 4103
+a 5151 5152 4103
+a 5152 5153 4103
+a 5153 5154 4103
+a 5154 5155 4103
+a 5155 5156 4103
+a 5156 5157 4103
+a 5157 5158 4103
+a 5158 5159 4103
+a 5159 5160 4103
+a 5160 5161 4103
+a 5161 5162 4103
+a 5162 5163 4103
+a 5163 5164 4103
+a 5164 5165 4103
+a 5165 5166 4103
+a 5166 5167 4103
+a 5167 5168 4103
+a 5168 5169 4103
+a 5169 5170 4103
+a 5170 5171 4103
+a 5171 5172 4103
+a 5172 5173 4103
+a 5173 5174 4103
+a 5174 5175 4103
+a 5175 5176 4103
+a 5176 5177 4103
+a 5177 5178 4103
+a 5178 5179 4103
+a 5179 5180 4103
+a 5180 5181 4103
+a 5181 5182 4103
+a 5182 5183 4103
+a 5183 5184 4103
+a 5184 5185 4103
+a 5185 5186 4103
+a 5186 5187 4103
+a 5187 5188 4103
+a 5188 5189 4103
+a 5189 5190 4103
+a 5190 5191 4103
+a 5191 5192 4103
+a 5192 5193 4103
+a 5193 5194 4103
+a 5194 5195 4103
+a 5195 5196 4103
+a 5196 5197 4103
+a 5197 5198 4103
+a 5198 5199 4103
+a 5199 5200 4103
+a 5200 5201 4103
+a 5201 5202 4103
+a 5202 5203 4103
+a 5203 5204 4103
+a 5204 5205 4103
+a 5205 5206 4103
+a 5206 5207 4103
+a 5207 5208 4103
+a 5208 5209 4103
+a 5209 5210 4103
+a 5210 5211 4103
+a 5211 5212 4103
+a 5212 5213 4103
+a 5213 5214 4103
+a 5214 5215 4103
+a 5215 5216 4103
+a 5216 5217 4103
+a 5217 5218 4103
+a 5218 5219 4103
+a 5219 5220 4103
+a 5220 5221 4103
+a 5221 5222 4103
+a 5222 5223 4103
+a 5223 5224 4103
+a 5224 5225 4103
+a 5225 5226 4103
+a 5226 5227 4103
+a 5227 5228 4103
+a 5228 5229 4103
+a 5229 5230 4103
+a 5230 5231 4103
+a 5231 5232 4103
+a 5232 5233 4103
+a 5233 5234 4103
+a 5234 5235 4103
+a 5235 5236 4103
+a 5236 5237 4103
+a 5237 5238 4103
+a 5238 5239 4103
+a 5239 5240 4103
+a 5240 5241 4103
+a 5241 5242 4103
+a 5242 5243 4103
+a 5243 5244 4103
+a 5244 5245 4103
+a 5245 5246 4103
+a 5246 5247 4103
+a 5247 5248 4103
+a 5248 5249 4103
+a 5249 5250 4103
+a 5250 5251 4103
+a 5251 5252 4103
+a 5252 5253 4103
+a 5253 5254 4103
+a 5254 5255 4103
+a 5255 5256 4103
+a 5256 5257 4103
+a 5257 5258 4103
+a 5258 5259 4103
+a 5259 5260 4103
+a 5260 5261 4103
+a 5261 5262 4103
+a 5262 5263 4103
+a 5263 5264 4103
+a 5264 5265 4103
+a 5265 5266 4103
+a 5266 5267 4103
+a 5267 5268 4103
+a 5268 5269 4103
+a 5269 5270 4103
+a 5270 5271 4103
+a 5271 5272 4103
+a 5272 5273 4103
+a 5273 5274 4103
+a 5274 5275 4103
+a 5275 5276 4103
+a 5276 5277 4103
+a 5277 5278 4103
+a 5278 5279 4103
+a 5279 5280 4103
+a 5280 5281 4103
+a 5281 5282 4103
+a 5282 5283 4103
+a 5283 5284 4103
+a 5284 5285 4103
+a 5285 5286 4103
+a 5286 5287 4103
+a 5287 5288 4103
+a 5288 5289 4103
+a 5289 5290 4103
+a 5290 5291 4103
+a 5291 5292 4103
+a 5292 5293 4103
+a 5293 5294 4103
+a 5294 5295 4103
+a 5295 5296 4103
+a 5296 5297 4103
+a 5297 5298 4103
+a 5298 5299 4103
+a 5299 5300 4103
+a 5300 5301 4103
+a 5301 5302 4103
+a 5302 5303 4103
+a 5303 5304 4103
+a 5304 5305 4103
+a 5305 5306 4103
+a 5306 5307 4103
+a 5307 5308 4103
+a 5308 5309 4103
+a 5309 5310 4103
+a 5310 5311 4103
+a 5311 5312 4103
+a 5312 5313 4103
+a 5313 5314 4103
+a 5314 5315 4103
+a 5315 5316 4103
+a 5316 5317 4103
+a 5317 5318 4103
+a 5318 5319 4103
+a 5319 5320 4103
+a 5320 5321 4103
+a 5321 5322 4103
+a 5322 5323 4103
+a 5323 5324 4103
+a 5324 5325 4103
+a 5325 5326 4103
+a 5326 5327 4103
+a 5327 5328 4103
+a 5328 5329 4103
+a 5329 5330 4103
+a 5330 5331 4103
+a 5331 5332 4103
+a 5332 5333 4103
+a 5333 5334 4103
+a 5334 5335 4103
+a 5335 5336 4103
+a 5336 5337 4103
+a 5337 5338 4103
+a 5338 5339 4103
+a 5339 5340 4103
+a 5340 5341 4103
+a 5341 5342 4103
+a 5342 5343 4103
+a 5343 5344 4103
+a 5344 5345 4103
+a 5345 5346 4103
+a 5346 5347 4103
+a 5347 5348 4103
+a 5348 5349 4103
+a 5349 5350 4103
+a 5350 5351 4103
+a 5351 5352 4103
+a 5352 5353 4103
+a 5353 5354 4103
+a 5354 5355 4103
+a 5355 5356 4103
+a 5356 5357 4103
+a 5357 5358 4103
+a 5358 5359 4103
+a 5359 5360 4103
+a 5360 5361 4103
+a 5361 5362 4103
+a 5362 5363 4103
+a 5363 5364 4103
+a 5364 5365 4103
+a 5365 5366 4103
+a 5366 5367 4103
+a 5367 5368 4103
+a 5368 5369 4103
+a 5369 5370 4103
+a 5370 5371 4103
+a 5371 5372 4103
+a 5372 5373 4103
+a 5373 5374 4103
+a 5374 5375 4103
+a 5375 5376 4103
+a 5376 5377 4103
+a 5377 5378 4103
+a 5378 5379 4103
+a 5379 5380 4103
+a 5380 5381 4103
+a 5381 5382 4103
+a 5382 5383 4103
+a 5383 5384 4103
+a 5384 5385 4103
+a 5385 5386 4103
+a 5386 5387 4103
+a 5387 5388 4103
+a 5388 5389 4103
+a 5389 5390 4103
+a 5390 5391 4103
+a 5391 5392 4103
+a 5392 5393 4103
+a 5393 5394 4103
+a 5394 5395 4103
+a 5395 5396 4103
+a 5396 5397 4103
+a 5397 5398 4103
+a 5398 5399 4103
+a 5399 5400 4103
+a 5400 5401 4103
+a 5401 5402 4103
+a 5402 5403 4103
+a 5403 5404 4103
+a 5404 5405 4103
+a 5405 5406 4103
+a 5406 5407 4103
+a 5407 5408 4103
+a 5408 5409 4103
+a 5409 5410 4103
+a 5410 5411 4103
+a 5411 5412 4103
+a 5412 5413 4103
+a 5413 5414 4103
+a 5414 5415 4103
+a 5415 5416 4103
+a 5416 5417 4103
+a 5417 5418 4103
+a 5418 5419 4103
+a 5419 5420 4103
+a 5420 5421 4103
+a 5421 5422 4103
+a 5422 5423 4103
+a 5423 5424 4103
+a 5424 5425 4103
+a 5425 5426 4103
+a 5426 5427 4103
+a 5427 5428 4103
+a 5428 5429 4103
+a 5429 5430 4103
+a 5430 5431 4103
+a 5431 5432 4103
+a 5432 5433 4103
+a 5433 5434 4103
+a 5434 5435 4103
+a 5435 5436 4103
+a 5436 5437 4103
+a 5437 5438 4103
+a 5438 5439 4103
+a 5439 5440 4103
+a 5440 5441 4103
+a 5441 5442 4103
+a 5442 5443 4103
+a 5443 5444 4103
+a 5444 5445 4103
+a 5445 5446 4103
+a 5446 5447 4103
+a 5447 5448 4103
+a 5448 5449 4103
+a 5449 5450 4103
+a 5450 5451 4103
+a 5451 5452 4103
+a 5452 5453 4103
+a 5453 5454 4103
+a 5454 5455 4103
+a 5455 5456 4103
+a 5456 5457 4103
+a 5457 5458 4103
+a 5458 5459 4103
+a 5459 5460 4103
+a 5460 5461 4103
+a 5461 5462 4103
+a 5462 5463 4103
+a 5463 5464 4103
+a 5464 5465 4103
+a 5465 5466 4103
+a 5466 5467 4103
+a 5467 5468 4103
+a 5468 5469 4103
+a 5469 5470 4103
+a 5470 5471 4103
+a 5471 5472 4103
+a 5472 5473 4103
+a 5473 5474 4103
+a 5474 5475 4103
+a 5475 5476 4103
+a 5476 5477 4103
+a 5477 5478 4103
+a 5478 5479 4103
+a 5479 5480 4103
+a 5480 5481 4103
+a 5481 5482 4103
+a 5482 5483 4103
+a 5483 5484 4103
+a 5484 5485 4103
+a 5485 5486 4103
+a 5486 5487 4103
+a 5487 5488 4103
+a 5488 5489 4103
+a 5489 5490 4103
+a 5490 5491 4103
+a 5491 5492 4103
+a 5492 5493 4103
+a 5493 5494 4103
+a 5494 5495 4103
+a 5495 5496 4103
+a 5496 5497 4103
+a 5497 5498 4103
+a 5498 5499 4103
+a 5499 5500 4103
+a 5500 5501 4103
+a 5501 5502 4103
+a 5502 5503 4103
+a 5503 5504 4103
+a 5504 5505 4103
+a 5505 5506 4103
+a 5506 5507 4103
+a 5507 5508 4103
+a 5508 5509 4103
+a 5509 5510 4103
+a 5510 5511 4103
+a 5511 5512 4103
+a 5512 5513 4103
+a 5513 5514 4103
+a 5514 5515 4103
+a 5515 5516 4103
+a 5516 5517 4103
+a 5517 5518 4103
+a 5518 5519 4103
+a 5519 5520 4103
+a 5520 5521 4103
+a 5521 5522 4103
+a 5522 5523 4103
+a 5523 5524 4103
+a 5524 5525 4103
+a 5525 5526 4103
+a 5526 5527 4103
+a 5527 5528 4103
+a 5528 5529 4103
+a 5529 5530 4103
+a 5530 5531 4103
+a 5531 5532 4103
+a 5532 5533 4103
+a 5533 5534 4103
+a 5534 5535 4103
+a 5535 5536 4103
+a 5536 5537 4103
+a 5537 5538 4103
+a 5538 5539 4103
+a 5539 5540 4103
+a 5540 5541 4103
+a 5541 5542 4103
+a 5542 5543 4103
+a 5543 5544 4103
+a 5544 5545 4103
+a 5545 5546 4103
+a 5546 5547 4103
+a 5547 5548 4103
+a 5548 5549 4103
+a 5549 5550 4103
+a 5550 5551 4103
+a 5551 5552 4103
+a 5552 5553 4103
+a 5553 5554 4103
+a 5554 5555 4103
+a 5555 5556 4103
+a 5556 5557 4103
+a 5557 5558 4103
+a 5558 5559 4103
+a 5559 5560 4103
+a 5560 5561 4103
+a 5561 5562 4103
+a 5562 5563 4103
+a 5563 5564 4103
+a 5564 5565 4103
+a 5565 5566 4103
+a 5566 5567 4103
+a 5567 5568 4103
+a 5568 5569 4103
+a 5569 5570 4103
+a 5570 5571 4103
+a 5571 5572 4103
+a 5572 5573 4103
+a 5573 5574 4103
+a 5574 5575 4103
+a 5575 5576 4103
+a 5576 5577 4103
+a 5577 5578 4103
+a 5578 5579 4103
+a 5579 5580 4103
+a 5580 5581 4103
+a 5581 5582 4103
+a 5582 5583 4103
+a 5583 5584 4103
+a 5584 5585 4103
+a 5585 5586 4103
+a 5586 5587 4103
+a 5587 5588 4103
+a 5588 5589 4103
+a 5589 5590 4103
+a 5590 5591 4103
+a 5591 5592 4103
+a 5592 5593 4103
+a 5593 5594 4103
+a 5594 5595 4103
+a 5595 5596 4103
+a 5596 5597 4103
+a 5597 5598 4103
+a 5598 5599 4103
+a 5599 5600 4103
+a 5600 5601 4103
+a 5601 5602 4103
+a 5602 5603 4103
+a 5603 5604 4103
+a 5604 5605 4103
+a 5605 5606 4103
+a 5606 5607 4103
+a 5607 5608 4103
+a 5608 5609 4103
+a 5609 5610 4103
+a 5610 5611 4103
+a 5611 5612 4103
+a 5612 5613 4103
+a 5613 5614 4103
+a 5614 5615 4103
+a 5615 5616 4103
+a 5616 5617 4103
+a 5617 5618 4103
+a 5618 5619 4103
+a 5619 5620 4103
+a 5620 5621 4103
+a 5621 5622 4103
+a 5622 5623 4103
+a 5623 5624 4103
+a 5624 5625 4103
+a 5625 5626 4103
+a 5626 5627 4103
+a 5627 5628 4103
+a 5628 5629 4103
+a 5629 5630 4103
+a 5630 5631 4103
+a 5631 5632 4103
+a 5632 5633 4103
+a 5633 5634 4103
+a 5634 5635 4103
+a 5635 5636 4103
+a 5636 5637 4103
+a 5637 5638 4103
+a 5638 5639 4103
+a 5639 5640 4103
+a 5640 5641 4103
+a 5641 5642 4103
+a 5642 5643 4103
+a 5643 5644 4103
+a 5644 5645 4103
+a 5645 5646 4103
+a 5646 5647 4103
+a 5647 5648 4103
+a 5648 5649 4103
+a 5649 5650 4103
+a 5650 5651 4103
+a 5651 5652 4103
+a 5652 5653 4103
+a 5653 5654 4103
+a 5654 5655 4103
+a 5655 5656 4103
+a 5656 5657 4103
+a 5657 5658 4103
+a 5658 5659 4103
+a 5659 5660 4103
+a 5660 5661 4103
+a 5661 5662 4103
+a 5662 5663 4103
+a 5663 5664 4103
+a 5664 5665 4103
+a 5665 5666 4103
+a 5666 5667 4103
+a 5667 5668 4103
+a 5668 5669 4103
+a 5669 5670 4103
+a 5670 5671 4103
+a 5671 5672 4103
+a 5672 5673 4103
+a 5673 5674 4103
+a 5674 5675 4103
+a 5675 5676 4103
+a 5676 5677 4103
+a 5677 5678 4103
+a 5678 5679 4103
+a 5679 5680 4103
+a 5680 5681 4103
+a 5681 5682 4103
+a 5682 5683 4103
+a 5683 5684 4103
+a 5684 5685 4103
+a 5685 5686 4103
+a 5686 5687 4103
+a 5687 5688 4103
+a 5688 5689 4103
+a 5689 5690 4103
+a 5690 5691 4103
+a 5691 5692 4103
+a 5692 5693 4103
+a 5693 5694 4103
+a 5694 5695 4103
+a 5695 5696 4103
+a 5696 5697 4103
+a 5697 5698 4103
+a 5698 5699 4103
+a 5699 5700 4103
+a 5700 5701 4103
+a 5701 5702 4103
+a 5702 5703 4103
+a 5703 5704 4103
+a 5704 5705 4103
+a 5705 5706 4103
+a 5706 5707 4103
+a 5707 5708 4103
+a 5708 5709 4103
+a 5709 5710 4103
+a 5710 5711 4103
+a 5711 5712 4103
+a 5712 5713 4103
+a 5713 5714 4103
+a 5714 5715 4103
+a 5715 5716 4103
+a 5716 5717 4103
+a 5717 5718 4103
+a 5718 5719 4103
+a 5719 5720 4103
+a 5720 5721 4103
+a 5721 5722 4103
+a 5722 5723 4103
+a 5723 5724 4103
+a 5724 5725 4103
+a 5725 5726 4103
+a 5726 5727 4103
+a 5727 5728 4103
+a 5728 5729 4103
+a 5729 5730 4103
+a 5730 5731 4103
+a 5731 5732 4103
+a 5732 5733 4103
+a 5733 5734 4103
+a 5734 5735 4103
+a 5735 5736 4103
+a 5736 5737 4103
+a 5737 5738 4103
+a 5738 5739 4103
+a 5739 5740 4103
+a 5740 5741 4103
+a 5741 5742 4103
+a 5742 5743 4103
+a 5743 5744 4103
+a 5744 5745 4103
+a 5745 5746 4103
+a 5746 5747 4103
+a 5747 5748 4103
+a 5748 5749 4103
+a 5749 5750 4103
+a 5750 5751 4103
+a 5751 5752 4103
+a 5752 5753 4103
+a 5753 5754 4103
+a 5754 5755 4103
+a 5755 5756 4103
+a 5756 5757 4103
+a 5757 5758 4103
+a 5758 5759 4103
+a 5759 5760 4103
+a 5760 5761 4103
+a 5761 5762 4103
+a 5762 5763 4103
+a 5763 5764 4103
+a 5764 5765 4103
+a 5765 5766 4103
+a 5766 5767 4103
+a 5767 5768 4103
+a 5768 5769 4103
+a 5769 5770 4103
+a 5770 5771 4103
+a 5771 5772 4103
+a 5772 5773 4103
+a 5773 5774 4103
+a 5774 5775 4103
+a 5775 5776 4103
+a 5776 5777 4103
+a 5777 5778 4103
+a 5778 5779 4103
+a 5779 5780 4103
+a 5780 5781 4103
+a 5781 5782 4103
+a 5782 5783 4103
+a 5783 5784 4103
+a 5784 5785 4103
+a 5785 5786 4103
+a 5786 5787 4103
+a 5787 5788 4103
+a 5788 5789 4103
+a 5789 5790 4103
+a 5790 5791 4103
+a 5791 5792 4103
+a 5792 5793 4103
+a 5793 5794 4103
+a 5794 5795 4103
+a 5795 5796 4103
+a 5796 5797 4103
+a 5797 5798 4103
+a 5798 5799 4103
+a 5799 5800 4103
+a 5800 5801 4103
+a 5801 5802 4103
+a 5802 5803 4103
+a 5803 5804 4103
+a 5804 5805 4103
+a 5805 5806 4103
+a 5806 5807 4103
+a 5807 5808 4103
+a 5808 5809 4103
+a 5809 5810 4103
+a 5810 5811 4103
+a 5811 5812 4103
+a 5812 5813 4103
+a 5813 5814 4103
+a 5814 5815 4103
+a 5815 5816 4103
+a 5816 5817 4103
+a 5817 5818 4103
+a 5818 5819 4103
+a 5819 5820 4103
+a 5820 5821 4103
+a 5821 5822 4103
+a 5822 5823 4103
+a 5823 5824 4103
+a 5824 5825 4103
+a 5825 5826 4103
+a 5826 5827 4103
+a 5827 5828 4103
+a 5828 5829 4103
+a 5829 5830 4103
+a 5830 5831 4103
+a 5831 5832 4103
+a 5832 5833 4103
+a 5833 5834 4103
+a 5834 5835 4103
+a 5835 5836 4103
+a 5836 5837 4103
+a 5837 5838 4103
+a 5838 5839 4103
+a 5839 5840 4103
+a 5840 5841 4103
+a 5841 5842 4103
+a 5842 5843 4103
+a 5843 5844 4103
+a 5844 5845 4103
+a 5845 5846 4103
+a 5846 5847 4103
+a 5847 5848 4103
+a 5848 5849 4103
+a 5849 5850 4103
+a 5850 5851 4103
+a 5851 5852 4103
+a 5852 5853 4103
+a 5853 5854 4103
+a 5854 5855 4103
+a 5855 5856 4103
+a 5856 5857 4103
+a 5857 5858 4103
+a 5858 5859 4103
+a 5859 5860 4103
+a 5860 5861 4103
+a 5861 5862 4103
+a 5862 5863 4103
+a 5863 5864 4103
+a 5864 5865 4103
+a 5865 5866 4103
+a 5866 5867 4103
+a 5867 5868 4103
+a 5868 5869 4103
+a 5869 5870 4103
+a 5870 5871 4103
+a 5871 5872 4103
+a 5872 5873 4103
+a 5873 5874 4103
+a 5874 5875 4103
+a 5875 5876 4103
+a 5876 5877 4103
+a 5877 5878 4103
+a 5878 5879 4103
+a 5879 5880 4103
+a 5880 5881 4103
+a 5881 5882 4103
+a 5882 5883 4103
+a 5883 5884 4103
+a 5884 5885 4103
+a 5885 5886 4103
+a 5886 5887 4103
+a 5887 5888 4103
+a 5888 5889 4103
+a 5889 5890 4103
+a 5890 5891 4103
+a 5891 5892 4103
+a 5892 5893 4103
+a 5893 5894 4103
+a 5894 5895 4103
+a 5895 5896 4103
+a 5896 5897 4103
+a 5897 5898 4103
+a 5898 5899 4103
+a 5899 5900 4103
+a 5900 5901 4103
+a 5901 5902 4103
+a 5902 5903 4103
+a 5903 5904 4103
+a 5904 5905 4103
+a 5905 5906 4103
+a 5906 5907 4103
+a 5907 5908 4103
+a 5908 5909 4103
+a 5909 5910 4103
+a 5910 5911 4103
+a 5911 5912 4103
+a 5912 5913 4103
+a 5913 5914 4103
+a 5914 5915 4103
+a 5915 5916 4103
+a 5916 5917 4103
+a 5917 5918 4103
+a 5918 5919 4103
+a 5919 5920 4103
+a 5920 5921 4103
+a 5921 5922 4103
+a 5922 5923 4103
+a 5923 5924 4103
+a 5924 5925 4103
+a 5925 5926 4103
+a 5926 5927 4103
+a 5927 5928 4103
+a 5928 5929 4103
+a 5929 5930 4103
+a 5930 5931 4103
+a 5931 5932 4103
+a 5932 5933 4103
+a 5933 5934 4103
+a 5934 5935 4103
+a 5935 5936 4103
+a 5936 5937 4103
+a 5937 5938 4103
+a 5938 5939 4103
+a 5939 5940 4103
+a 5940 5941 4103
+a 5941 5942 4103
+a 5942 5943 4103
+a 5943 5944 4103
+a 5944 5945 4103
+a 5945 5946 4103
+a 5946 5947 4103
+a 5947 5948 4103
+a 5948 5949 4103
+a 5949 5950 4103
+a 5950 5951 4103
+a 5951 5952 4103
+a 5952 5953 4103
+a 5953 5954 4103
+a 5954 5955 4103
+a 5955 5956 4103
+a 5956 5957 4103
+a 5957 5958 4103
+a 5958 5959 4103
+a 5959 5960 4103
+a 5960 5961 4103
+a 5961 5962 4103
+a 5962 5963 4103
+a 5963 5964 4103
+a 5964 5965 4103
+a 5965 5966 4103
+a 5966 5967 4103
+a 5967 5968 4103
+a 5968 5969 4103
+a 5969 5970 4103
+a 5970 5971 4103
+a 5971 5972 4103
+a 5972 5973 4103
+a 5973 5974 4103
+a 5974 5975 4103
+a 5975 5976 4103
+a 5976 5977 4103
+a 5977 5978 4103
+a 5978 5979 4103
+a 5979 5980 4103
+a 5980 5981 4103
+a 5981 5982 4103
+a 5982 5983 4103
+a 5983 5984 4103
+a 5984 5985 4103
+a 5985 5986 4103
+a 5986 5987 4103
+a 5987 5988 4103
+a 5988 5989 4103
+a 5989 5990 4103
+a 5990 5991 4103
+a 5991 5992 4103
+a 5992 5993 4103
+a 5993 5994 4103
+a 5994 5995 4103
+a 5995 5996 4103
+a 5996 5997 4103
+a 5997 5998 4103
+a 5998 5999 4103
+a 5999 6000 4103
+a 6000 6001 4103
+a 6001 6002 4103
+a 6002 6003 4103
+a 6003 6004 4103
+a 6004 6005 4103
+a 6005 6006 4103
+a 6006 6007 4103
+a 6007 6008 4103
+a 6008 6009 4103
+a 6009 6010 4103
+a 6010 6011 4103
+a 6011 6012 4103
+a 6012 6013 4103
+a 6013 6014 4103
+a 6014 6015 4103
+a 6015 6016 4103
+a 6016 6017 4103
+a 6017 6018 4103
+a 6018 6019 4103
+a 6019 6020 4103
+a 6020 6021 4103
+a 6021 6022 4103
+a 6022 6023 4103
+a 6023 6024 4103
+a 6024 6025 4103
+a 6025 6026 4103
+a 6026 6027 4103
+a 6027 6028 4103
+a 6028 6029 4103
+a 6029 6030 4103
+a 6030 6031 4103
+a 6031 6032 4103
+a 6032 6033 4103
+a 6033 6034 4103
+a 6034 6035 4103
+a 6035 6036 4103
+a 6036 6037 4103
+a 6037 6038 4103
+a 6038 6039 4103
+a 6039 6040 4103
+a 6040 6041 4103
+a 6041 6042 4103
+a 6042 6043 4103
+a 6043 6044 4103
+a 6044 6045 4103
+a 6045 6046 4103
+a 6046 6047 4103
+a 6047 6048 4103
+a 6048 6049 4103
+a 6049 6050 4103
+a 6050 6051 4103
+a 6051 6052 4103
+a 6052 6053 4103
+a 6053 6054 4103
+a 6054 6055 4103
+a 6055 6056 4103
+a 6056 6057 4103
+a 6057 6058 4103
+a 6058 6059 4103
+a 6059 6060 4103
+a 6060 6061 4103
+a 6061 6062 4103
+a 6062 6063 4103
+a 6063 6064 4103
+a 6064 6065 4103
+a 6065 6066 4103
+a 6066 6067 4103
+a 6067 6068 4103
+a 6068 6069 4103
+a 6069 6070 4103
+a 6070 6071 4103
+a 6071 6072 4103
+a 6072 6073 4103
+a 6073 6074 4103
+a 6074 6075 4103
+a 6075 6076 4103
+a 6076 6077 4103
+a 6077 6078 4103
+a 6078 6079 4103
+a 6079 6080 4103
+a 6080 6081 4103
+a 6081 6082 4103
+a 6082 6083 4103
+a 6083 6084 4103
+a 6084 6085 4103
+a 6085 6086 4103
+a 6086 6087 4103
+a 6087 6088 4103
+a 6088 6089 4103
+a 6089 6090 4103
+a 6090 6091 4103
+a 6091 6092 4103
+a 6092 6093 4103
+a 6093 6094 4103
+a 6094 6095 4103
+a 6095 6096 4103
+a 6096 6097 4103
+a 6097 6098 4103
+a 6098 6099 4103
+a 6099 6100 4103
+a 6100 6101 4103
+a 6101 6102 4103
+a 6102 6103 4103
+a 6103 6104 4103
+a 6104 6105 4103
+a 6105 6106 4103
+a 6106 6107 4103
+a 6107 6108 4103
+a 6108 6109 4103
+a 6109 6110 4103
+a 6110 6111 4103
+a 6111 6112 4103
+a 6112 6113 4103
+a 6113 6114 4103
+a 6114 6115 4103
+a 6115 6116 4103
+a 6116 6117 4103
+a 6117 6118 4103
+a 6118 6119 4103
+a 6119 6120 4103
+a 6120 6121 4103
+a 6121 6122 4103
+a 6122 6123 4103
+a 6123 6124 4103
+a 6124 6125 4103
+a 6125 6126 4103
+a 6126 6127 4103
+a 6127 6128 4103
+a 6128 6129 4103
+a 6129 6130 4103
+a 6130 6131 4103
+a 6131 6132 4103
+a 6132 6133 4103
+a 6133 6134 4103
+a 6134 6135 4103
+a 6135 6136 4103
+a 6136 6137 4103
+a 6137 6138 4103
+a 6138 6139 4103
+a 6139 6140 4103
+a 6140 6141 4103
+a 6141 6142 4103
+a 6142 6143 4103
+a 6143 6144 4103
+a 6144 6145 4103
+a 6145 6146 4103
+a 6146 6147 4103
+a 6147 6148 4103
+a 6148 6149 4103
+a 6149 6150 4103
+a 6150 6151 4103
+a 6151 6152 4103
+a 6152 6153 4103
+a 6153 6154 4103
+a 6154 6155 4103
+a 6155 6156 4103
+a 6156 6157 4103
+a 6157 6158 4103
+a 6158 6159 4103
+a 6159 6160 4103
+a 6160 6161 4103
+a 6161 6162 4103
+a 6162 6163 4103
+a 6163 6164 4103
+a 6164 6165 4103
+a 6165 6166 4103
+a 6166 6167 4103
+a 6167 6168 4103
+a 6168 6169 4103
+a 6169 6170 4103
+a 6170 6171 4103
+a 6171 6172 4103
+a 6172 6173 4103
+a 6173 6174 4103
+a 6174 6175 4103
+a 6175 6176 4103
+a 6176 6177 4103
+a 6177 6178 4103
+a 6178 6179 4103
+a 6179 6180 4103
+a 6180 6181 4103
+a 6181 6182 4103
+a 6182 6183 4103
+a 6183 6184 4103
+a 6184 6185 4103
+a 6185 6186 4103
+a 6186 6187 4103
+a 6187 6188 4103
+a 6188 6189 4103
+a 6189 6190 4103
+a 6190 6191 4103
+a 6191 6192 4103
+a 6192 6193 4103
+a 6193 6194 4103
+a 6194 6195 4103
+a 6195 6196 4103
+a 6196 6197 4103
+a 6197 6198 4103
+a 6198 6199 4103
+a 6199 6200 4103
+a 6200 6201 4103
+a 6201 6202 4103
+a 6202 6203 4103
+a 6203 6204 4103
+a 6204 6205 4103
+a 6205 6206 4103
+a 6206 6207 4103
+a 6207 6208 4103
+a 6208 6209 4103
+a 6209 6210 4103
+a 6210 6211 4103
+a 6211 6212 4103
+a 6212 6213 4103
+a 6213 6214 4103
+a 6214 6215 4103
+a 6215 6216 4103
+a 6216 6217 4103
+a 6217 6218 4103
+a 6218 6219 4103
+a 6219 6220 4103
+a 6220 6221 4103
+a 6221 6222 4103
+a 6222 6223 4103
+a 6223 6224 4103
+a 6224 6225 4103
+a 6225 6226 4103
+a 6226 6227 4103
+a 6227 6228 4103
+a 6228 6229 4103
+a 6229 6230 4103
+a 6230 6231 4103
+a 6231 6232 4103
+a 6232 6233 4103
+a 6233 6234 4103
+a 6234 6235 4103
+a 6235 6236 4103
+a 6236 6237 4103
+a 6237 6238 4103
+a 6238 6239 4103
+a 6239 6240 4103
+a 6240 6241 4103
+a 6241 6242 4103
+a 6242 6243 4103
+a 6243 6244 4103
+a 6244 6245 4103
+a 6245 6246 4103
+a 6246 6247 4103
+a 6247 6248 4103
+a 6248 6249 4103
+a 6249 6250 4103
+a 6250 6251 4103
+a 6251 6252 4103
+a 6252 6253 4103
+a 6253 6254 4103
+a 6254 6255 4103
+a 6255 6256 4103
+a 6256 6257 4103
+a 6257 6258 4103
+a 6258 6259 4103
+a 6259 6260 4103
+a 6260 6261 4103
+a 6261 6262 4103
+a 6262 6263 4103
+a 6263 6264 4103
+a 6264 6265 4103
+a 6265 6266 4103
+a 6266 6267 4103
+a 6267 6268 4103
+a 6268 6269 4103
+a 6269 6270 4103
+a 6270 6271 4103
+a 6271 6272 4103
+a 6272 6273 4103
+a 6273 6274 4103
+a 6274 6275 4103
+a 6275 6276 4103
+a 6276 6277 4103
+a 6277 6278 4103
+a 6278 6279 4103
+a 6279 6280 4103
+a 6280 6281 4103
+a 6281 6282 4103
+a 6282 6283 4103
+a 6283 6284 4103
+a 6284 6285 4103
+a 6285 6286 4103
+a 6286 6287 4103
+a 6287 6288 4103
+a 6288 6289 4103
+a 6289 6290 4103
+a 6290 6291 4103
+a 6291 6292 4103
+a 6292 6293 4103
+a 6293 6294 4103
+a 6294 6295 4103
+a 6295 6296 4103
+a 6296 6297 4103
+a 6297 6298 4103
+a 6298 6299 4103
+a 6299 6300 4103
+a 6300 6301 4103
+a 6301 6302 4103
+a 6302 6303 4103
+a 6303 6304 4103
+a 6304 6305 4103
+a 6305 6306 4103
+a 6306 6307 4103
+a 6307 6308 4103
+a 6308 6309 4103
+a 6309 6310 4103
+a 6310 6311 4103
+a 6311 6312 4103
+a 6312 6313 4103
+a 6313 6314 4103
+a 6314 6315 4103
+a 6315 6316 4103
+a 6316 6317 4103
+a 6317 6318 4103
+a 6318 6319 4103
+a 6319 6320 4103
+a 6320 6321 4103
+a 6321 6322 4103
+a 6322 6323 4103
+a 6323 6324 4103
+a 6324 6325 4103
+a 6325 6326 4103
+a 6326 6327 4103
+a 6327 6328 4103
+a 6328 6329 4103
+a 6329 6330 4103
+a 6330 6331 4103
+a 6331 6332 4103
+a 6332 6333 4103
+a 6333 6334 4103
+a 6334 6335 4103
+a 6335 6336 4103
+a 6336 6337 4103
+a 6337 6338 4103
+a 6338 6339 4103
+a 6339 6340 4103
+a 6340 6341 4103
+a 6341 6342 4103
+a 6342 6343 4103
+a 6343 6344 4103
+a 6344 6345 4103
+a 6345 6346 4103
+a 6346 6347 4103
+a 6347 6348 4103
+a 6348 6349 4103
+a 6349 6350 4103
+a 6350 6351 4103
+a 6351 6352 4103
+a 6352 6353 4103
+a 6353 6354 4103
+a 6354 6355 4103
+a 6355 6356 4103
+a 6356 6357 4103
+a 6357 6358 4103
+a 6358 6359 4103
+a 6359 6360 4103
+a 6360 6361 4103
+a 6361 6362 4103
+a 6362 6363 4103
+a 6363 6364 4103
+a 6364 6365 4103
+a 6365 6366 4103
+a 6366 6367 4103
+a 6367 6368 4103
+a 6368 6369 4103
+a 6369 6370 4103
+a 6370 6371 4103
+a 6371 6372 4103
+a 6372 6373 4103
+a 6373 6374 4103
+a 6374 6375 4103
+a 6375 6376 4103
+a 6376 6377 4103
+a 6377 6378 4103
+a 6378 6379 4103
+a 6379 6380 4103
+a 6380 6381 4103
+a 6381 6382 4103
+a 6382 6383 4103
+a 6383 6384 4103
+a 6384 6385 4103
+a 6385 6386 4103
+a 6386 6387 4103
+a 6387 6388 4103
+a 6388 6389 4103
+a 6389 6390 4103
+a 6390 6391 4103
+a 6391 6392 4103
+a 6392 6393 4103
+a 6393 6394 4103
+a 6394 6395 4103
+a 6395 6396 4103
+a 6396 6397 4103
+a 6397 6398 4103
+a 6398 6399 4103
+a 6399 6400 4103
+a 6400 6401 4103
+a 6401 6402 4103
+a 6402 6403 4103
+a 6403 6404 4103
+a 6404 6405 4103
+a 6405 6406 4103
+a 6406 6407 4103
+a 6407 6408 4103
+a 6408 6409 4103
+a 6409 6410 4103
+a 6410 6411 4103
+a 6411 6412 4103
+a 6412 6413 4103
+a 6413 6414 4103
+a 6414 6415 4103
+a 6415 6416 4103
+a 6416 6417 4103
+a 6417 6418 4103
+a 6418 6419 4103
+a 6419 6420 4103
+a 6420 6421 4103
+a 6421 6422 4103
+a 6422 6423 4103
+a 6423 6424 4103
+a 6424 6425 4103
+a 6425 6426 4103
+a 6426 6427 4103
+a 6427 6428 4103
+a 6428 6429 4103
+a 6429 6430 4103
+a 6430 6431 4103
+a 6431 6432 4103
+a 6432 6433 4103
+a 6433 6434 4103
+a 6434 6435 4103
+a 6435 6436 4103
+a 6436 6437 4103
+a 6437 6438 4103
+a 6438 6439 4103
+a 6439 6440 4103
+a 6440 6441 4103
+a 6441 6442 4103
+a 6442 6443 4103
+a 6443 6444 4103
+a 6444 6445 4103
+a 6445 6446 4103
+a 6446 6447 4103
+a 6447 6448 4103
+a 6448 6449 4103
+a 6449 6450 4103
+a 6450 6451 4103
+a 6451 6452 4103
+a 6452 6453 4103
+a 6453 6454 4103
+a 6454 6455 4103
+a 6455 6456 4103
+a 6456 6457 4103
+a 6457 6458 4103
+a 6458 6459 4103
+a 6459 6460 4103
+a 6460 6461 4103
+a 6461 6462 4103
+a 6462 6463 4103
+a 6463 6464 4103
+a 6464 6465 4103
+a 6465 6466 4103
+a 6466 6467 4103
+a 6467 6468 4103
+a 6468 6469 4103
+a 6469 6470 4103
+a 6470 6471 4103
+a 6471 6472 4103
+a 6472 6473 4103
+a 6473 6474 4103
+a 6474 6475 4103
+a 6475 6476 4103
+a 6476 6477 4103
+a 6477 6478 4103
+a 6478 6479 4103
+a 6479 6480 4103
+a 6480 6481 4103
+a 6481 6482 4103
+a 6482 6483 4103
+a 6483 6484 4103
+a 6484 6485 4103
+a 6485 6486 4103
+a 6486 6487 4103
+a 6487 6488 4103
+a 6488 6489 4103
+a 6489 6490 4103
+a 6490 6491 4103
+a 6491 6492 4103
+a 6492 6493 4103
+a 6493 6494 4103
+a 6494 6495 4103
+a 6495 6496 4103
+a 6496 6497 4103
+a 6497 6498 4103
+a 6498 6499 4103
+a 6499 6500 4103
+a 6500 6501 4103
+a 6501 6502 4103
+a 6502 6503 4103
+a 6503 6504 4103
+a 6504 6505 4103
+a 6505 6506 4103
+a 6506 6507 4103
+a 6507 6508 4103
+a 6508 6509 4103
+a 6509 6510 4103
+a 6510 6511 4103
+a 6511 6512 4103
+a 6512 6513 4103
+a 6513 6514 4103
+a 6514 6515 4103
+a 6515 6516 4103
+a 6516 6517 4103
+a 6517 6518 4103
+a 6518 6519 4103
+a 6519 6520 4103
+a 6520 6521 4103
+a 6521 6522 4103
+a 6522 6523 4103
+a 6523 6524 4103
+a 6524 6525 4103
+a 6525 6526 4103
+a 6526 6527 4103
+a 6527 6528 4103
+a 6528 6529 4103
+a 6529 6530 4103
+a 6530 6531 4103
+a 6531 6532 4103
+a 6532 6533 4103
+a 6533 6534 4103
+a 6534 6535 4103
+a 6535 6536 4103
+a 6536 6537 4103
+a 6537 6538 4103
+a 6538 6539 4103
+a 6539 6540 4103
+a 6540 6541 4103
+a 6541 6542 4103
+a 6542 6543 4103
+a 6543 6544 4103
+a 6544 6545 4103
+a 6545 6546 4103
+a 6546 6547 4103
+a 6547 6548 4103
+a 6548 6549 4103
+a 6549 6550 4103
+a 6550 6551 4103
+a 6551 6552 4103
+a 6552 6553 4103
+a 6553 6554 4103
+a 6554 6555 4103
+a 6555 6556 4103
+a 6556 6557 4103
+a 6557 6558 4103
+a 6558 6559 4103
+a 6559 6560 4103
+a 6560 6561 4103
+a 6561 6562 4103
+a 6562 6563 4103
+a 6563 6564 4103
+a 6564 6565 4103
+a 6565 6566 4103
+a 6566 6567 4103
+a 6567 6568 4103
+a 6568 6569 4103
+a 6569 6570 4103
+a 6570 6571 4103
+a 6571 6572 4103
+a 6572 6573 4103
+a 6573 6574 4103
+a 6574 6575 4103
+a 6575 6576 4103
+a 6576 6577 4103
+a 6577 6578 4103
+a 6578 6579 4103
+a 6579 6580 4103
+a 6580 6581 4103
+a 6581 6582 4103
+a 6582 6583 4103
+a 6583 6584 4103
+a 6584 6585 4103
+a 6585 6586 4103
+a 6586 6587 4103
+a 6587 6588 4103
+a 6588 6589 4103
+a 6589 6590 4103
+a 6590 6591 4103
+a 6591 6592 4103
+a 6592 6593 4103
+a 6593 6594 4103
+a 6594 6595 4103
+a 6595 6596 4103
+a 6596 6597 4103
+a 6597 6598 4103
+a 6598 6599 4103
+a 6599 6600 4103
+a 6600 6601 4103
+a 6601 6602 4103
+a 6602 6603 4103
+a 6603 6604 4103
+a 6604 6605 4103
+a 6605 6606 4103
+a 6606 6607 4103
+a 6607 6608 4103
+a 6608 6609 4103
+a 6609 6610 4103
+a 6610 6611 4103
+a 6611 6612 4103
+a 6612 6613 4103
+a 6613 6614 4103
+a 6614 6615 4103
+a 6615 6616 4103
+a 6616 6617 4103
+a 6617 6618 4103
+a 6618 6619 4103
+a 6619 6620 4103
+a 6620 6621 4103
+a 6621 6622 4103
+a 6622 6623 4103
+a 6623 6624 4103
+a 6624 6625 4103
+a 6625 6626 4103
+a 6626 6627 4103
+a 6627 6628 4103
+a 6628 6629 4103
+a 6629 6630 4103
+a 6630 6631 4103
+a 6631 6632 4103
+a 6632 6633 4103
+a 6633 6634 4103
+a 6634 6635 4103
+a 6635 6636 4103
+a 6636 6637 4103
+a 6637 6638 4103
+a 6638 6639 4103
+a 6639 6640 4103
+a 6640 6641 4103
+a 6641 6642 4103
+a 6642 6643 4103
+a 6643 6644 4103
+a 6644 6645 4103
+a 6645 6646 4103
+a 6646 6647 4103
+a 6647 6648 4103
+a 6648 6649 4103
+a 6649 6650 4103
+a 6650 6651 4103
+a 6651 6652 4103
+a 6652 6653 4103
+a 6653 6654 4103
+a 6654 6655 4103
+a 6655 6656 4103
+a 6656 6657 4103
+a 6657 6658 4103
+a 6658 6659 4103
+a 6659 6660 4103
+a 6660 6661 4103
+a 6661 6662 4103
+a 6662 6663 4103
+a 6663 6664 4103
+a 6664 6665 4103
+a 6665 6666 4103
+a 6666 6667 4103
+a 6667 6668 4103
+a 6668 6669 4103
+a 6669 6670 4103
+a 6670 6671 4103
+a 6671 6672 4103
+a 6672 6673 4103
+a 6673 6674 4103
+a 6674 6675 4103
+a 6675 6676 4103
+a 6676 6677 4103
+a 6677 6678 4103
+a 6678 6679 4103
+a 6679 6680 4103
+a 6680 6681 4103
+a 6681 6682 4103
+a 6682 6683 4103
+a 6683 6684 4103
+a 6684 6685 4103
+a 6685 6686 4103
+a 6686 6687 4103
+a 6687 6688 4103
+a 6688 6689 4103
+a 6689 6690 4103
+a 6690 6691 4103
+a 6691 6692 4103
+a 6692 6693 4103
+a 6693 6694 4103
+a 6694 6695 4103
+a 6695 6696 4103
+a 6696 6697 4103
+a 6697 6698 4103
+a 6698 6699 4103
+a 6699 6700 4103
+a 6700 6701 4103
+a 6701 6702 4103
+a 6702 6703 4103
+a 6703 6704 4103
+a 6704 6705 4103
+a 6705 6706 4103
+a 6706 6707 4103
+a 6707 6708 4103
+a 6708 6709 4103
+a 6709 6710 4103
+a 6710 6711 4103
+a 6711 6712 4103
+a 6712 6713 4103
+a 6713 6714 4103
+a 6714 6715 4103
+a 6715 6716 4103
+a 6716 6717 4103
+a 6717 6718 4103
+a 6718 6719 4103
+a 6719 6720 4103
+a 6720 6721 4103
+a 6721 6722 4103
+a 6722 6723 4103
+a 6723 6724 4103
+a 6724 6725 4103
+a 6725 6726 4103
+a 6726 6727 4103
+a 6727 6728 4103
+a 6728 6729 4103
+a 6729 6730 4103
+a 6730 6731 4103
+a 6731 6732 4103
+a 6732 6733 4103
+a 6733 6734 4103
+a 6734 6735 4103
+a 6735 6736 4103
+a 6736 6737 4103
+a 6737 6738 4103
+a 6738 6739 4103
+a 6739 6740 4103
+a 6740 6741 4103
+a 6741 6742 4103
+a 6742 6743 4103
+a 6743 6744 4103
+a 6744 6745 4103
+a 6745 6746 4103
+a 6746 6747 4103
+a 6747 6748 4103
+a 6748 6749 4103
+a 6749 6750 4103
+a 6750 6751 4103
+a 6751 6752 4103
+a 6752 6753 4103
+a 6753 6754 4103
+a 6754 6755 4103
+a 6755 6756 4103
+a 6756 6757 4103
+a 6757 6758 4103
+a 6758 6759 4103
+a 6759 6760 4103
+a 6760 6761 4103
+a 6761 6762 4103
+a 6762 6763 4103
+a 6763 6764 4103
+a 6764 6765 4103
+a 6765 6766 4103
+a 6766 6767 4103
+a 6767 6768 4103
+a 6768 6769 4103
+a 6769 6770 4103
+a 6770 6771 4103
+a 6771 6772 4103
+a 6772 6773 4103
+a 6773 6774 4103
+a 6774 6775 4103
+a 6775 6776 4103
+a 6776 6777 4103
+a 6777 6778 4103
+a 6778 6779 4103
+a 6779 6780 4103
+a 6780 6781 4103
+a 6781 6782 4103
+a 6782 6783 4103
+a 6783 6784 4103
+a 6784 6785 4103
+a 6785 6786 4103
+a 6786 6787 4103
+a 6787 6788 4103
+a 6788 6789 4103
+a 6789 6790 4103
+a 6790 6791 4103
+a 6791 6792 4103
+a 6792 6793 4103
+a 6793 6794 4103
+a 6794 6795 4103
+a 6795 6796 4103
+a 6796 6797 4103
+a 6797 6798 4103
+a 6798 6799 4103
+a 6799 6800 4103
+a 6800 6801 4103
+a 6801 6802 4103
+a 6802 6803 4103
+a 6803 6804 4103
+a 6804 6805 4103
+a 6805 6806 4103
+a 6806 6807 4103
+a 6807 6808 4103
+a 6808 6809 4103
+a 6809 6810 4103
+a 6810 6811 4103
+a 6811 6812 4103
+a 6812 6813 4103
+a 6813 6814 4103
+a 6814 6815 4103
+a 6815 6816 4103
+a 6816 6817 4103
+a 6817 6818 4103
+a 6818 6819 4103
+a 6819 6820 4103
+a 6820 6821 4103
+a 6821 6822 4103
+a 6822 6823 4103
+a 6823 6824 4103
+a 6824 6825 4103
+a 6825 6826 4103
+a 6826 6827 4103
+a 6827 6828 4103
+a 6828 6829 4103
+a 6829 6830 4103
+a 6830 6831 4103
+a 6831 6832 4103
+a 6832 6833 4103
+a 6833 6834 4103
+a 6834 6835 4103
+a 6835 6836 4103
+a 6836 6837 4103
+a 6837 6838 4103
+a 6838 6839 4103
+a 6839 6840 4103
+a 6840 6841 4103
+a 6841 6842 4103
+a 6842 6843 4103
+a 6843 6844 4103
+a 6844 6845 4103
+a 6845 6846 4103
+a 6846 6847 4103
+a 6847 6848 4103
+a 6848 6849 4103
+a 6849 6850 4103
+a 6850 6851 4103
+a 6851 6852 4103
+a 6852 6853 4103
+a 6853 6854 4103
+a 6854 6855 4103
+a 6855 6856 4103
+a 6856 6857 4103
+a 6857 6858 4103
+a 6858 6859 4103
+a 6859 6860 4103
+a 6860 6861 4103
+a 6861 6862 4103
+a 6862 6863 4103
+a 6863 6864 4103
+a 6864 6865 4103
+a 6865 6866 4103
+a 6866 6867 4103
+a 6867 6868 4103
+a 6868 6869 4103
+a 6869 6870 4103
+a 6870 6871 4103
+a 6871 6872 4103
+a 6872 6873 4103
+a 6873 6874 4103
+a 6874 6875 4103
+a 6875 6876 4103
+a 6876 6877 4103
+a 6877 6878 4103
+a 6878 6879 4103
+a 6879 6880 4103
+a 6880 6881 4103
+a 6881 6882 4103
+a 6882 6883 4103
+a 6883 6884 4103
+a 6884 6885 4103
+a 6885 6886 4103
+a 6886 6887 4103
+a 6887 6888 4103
+a 6888 6889 4103
+a 6889 6890 4103
+a 6890 6891 4103
+a 6891 6892 4103
+a 6892 6893 4103
+a 6893 6894 4103
+a 6894 6895 4103
+a 6895 6896 4103
+a 6896 6897 4103
+a 6897 6898 4103
+a 6898 6899 4103
+a 6899 6900 4103
+a 6900 6901 4103
+a 6901 6902 4103
+a 6902 6903 4103
+a 6903 6904 4103
+a 6904 6905 4103
+a 6905 6906 4103
+a 6906 6907 4103
+a 6907 6908 4103
+a 6908 6909 4103
+a 6909 6910 4103
+a 6910 6911 4103
+a 6911 6912 4103
+a 6912 6913 4103
+a 6913 6914 4103
+a 6914 6915 4103
+a 6915 6916 4103
+a 6916 6917 4103
+a 6917 6918 4103
+a 6918 6919 4103
+a 6919 6920 4103
+a 6920 6921 4103
+a 6921 6922 4103
+a 6922 6923 4103
+a 6923 6924 4103
+a 6924 6925 4103
+a 6925 6926 4103
+a 6926 6927 4103
+a 6927 6928 4103
+a 6928 6929 4103
+a 6929 6930 4103
+a 6930 6931 4103
+a 6931 6932 4103
+a 6932 6933 4103
+a 6933 6934 4103
+a 6934 6935 4103
+a 6935 6936 4103
+a 6936 6937 4103
+a 6937 6938 4103
+a 6938 6939 4103
+a 6939 6940 4103
+a 6940 6941 4103
+a 6941 6942 4103
+a 6942 6943 4103
+a 6943 6944 4103
+a 6944 6945 4103
+a 6945 6946 4103
+a 6946 6947 4103
+a 6947 6948 4103
+a 6948 6949 4103
+a 6949 6950 4103
+a 6950 6951 4103
+a 6951 6952 4103
+a 6952 6953 4103
+a 6953 6954 4103
+a 6954 6955 4103
+a 6955 6956 4103
+a 6956 6957 4103
+a 6957 6958 4103
+a 6958 6959 4103
+a 6959 6960 4103
+a 6960 6961 4103
+a 6961 6962 4103
+a 6962 6963 4103
+a 6963 6964 4103
+a 6964 6965 4103
+a 6965 6966 4103
+a 6966 6967 4103
+a 6967 6968 4103
+a 6968 6969 4103
+a 6969 6970 4103
+a 6970 6971 4103
+a 6971 6972 4103
+a 6972 6973 4103
+a 6973 6974 4103
+a 6974 6975 4103
+a 6975 6976 4103
+a 6976 6977 4103
+a 6977 6978 4103
+a 6978 6979 4103
+a 6979 6980 4103
+a 6980 6981 4103
+a 6981 6982 4103
+a 6982 6983 4103
+a 6983 6984 4103
+a 6984 6985 4103
+a 6985 6986 4103
+a 6986 6987 4103
+a 6987 6988 4103
+a 6988 6989 4103
+a 6989 6990 4103
+a 6990 6991 4103
+a 6991 6992 4103
+a 6992 6993 4103
+a 6993 6994 4103
+a 6994 6995 4103
+a 6995 6996 4103
+a 6996 6997 4103
+a 6997 6998 4103
+a 6998 6999 4103
+a 6999 7000 4103
+a 7000 7001 4103
+a 7001 7002 4103
+a 7002 7003 4103
+a 7003 7004 4103
+a 7004 7005 4103
+a 7005 7006 4103
+a 7006 7007 4103
+a 7007 7008 4103
+a 7008 7009 4103
+a 7009 7010 4103
+a 7010 7011 4103
+a 7011 7012 4103
+a 7012 7013 4103
+a 7013 7014 4103
+a 7014 7015 4103
+a 7015 7016 4103
+a 7016 7017 4103
+a 7017 7018 4103
+a 7018 7019 4103
+a 7019 7020 4103
+a 7020 7021 4103
+a 7021 7022 4103
+a 7022 7023 4103
+a 7023 7024 4103
+a 7024 7025 4103
+a 7025 7026 4103
+a 7026 7027 4103
+a 7027 7028 4103
+a 7028 7029 4103
+a 7029 7030 4103
+a 7030 7031 4103
+a 7031 7032 4103
+a 7032 7033 4103
+a 7033 7034 4103
+a 7034 7035 4103
+a 7035 7036 4103
+a 7036 7037 4103
+a 7037 7038 4103
+a 7038 7039 4103
+a 7039 7040 4103
+a 7040 7041 4103
+a 7041 7042 4103
+a 7042 7043 4103
+a 7043 7044 4103
+a 7044 7045 4103
+a 7045 7046 4103
+a 7046 7047 4103
+a 7047 7048 4103
+a 7048 7049 4103
+a 7049 7050 4103
+a 7050 7051 4103
+a 7051 7052 4103
+a 7052 7053 4103
+a 7053 7054 4103
+a 7054 7055 4103
+a 7055 7056 4103
+a 7056 7057 4103
+a 7057 7058 4103
+a 7058 7059 4103
+a 7059 7060 4103
+a 7060 7061 4103
+a 7061 7062 4103
+a 7062 7063 4103
+a 7063 7064 4103
+a 7064 7065 4103
+a 7065 7066 4103
+a 7066 7067 4103
+a 7067 7068 4103
+a 7068 7069 4103
+a 7069 7070 4103
+a 7070 7071 4103
+a 7071 7072 4103
+a 7072 7073 4103
+a 7073 7074 4103
+a 7074 7075 4103
+a 7075 7076 4103
+a 7076 7077 4103
+a 7077 7078 4103
+a 7078 7079 4103
+a 7079 7080 4103
+a 7080 7081 4103
+a 7081 7082 4103
+a 7082 7083 4103
+a 7083 7084 4103
+a 7084 7085 4103
+a 7085 7086 4103
+a 7086 7087 4103
+a 7087 7088 4103
+a 7088 7089 4103
+a 7089 7090 4103
+a 7090 7091 4103
+a 7091 7092 4103
+a 7092 7093 4103
+a 7093 7094 4103
+a 7094 7095 4103
+a 7095 7096 4103
+a 7096 7097 4103
+a 7097 7098 4103
+a 7098 7099 4103
+a 7099 7100 4103
+a 7100 7101 4103
+a 7101 7102 4103
+a 7102 7103 4103
+a 7103 7104 4103
+a 7104 7105 4103
+a 7105 7106 4103
+a 7106 7107 4103
+a 7107 7108 4103
+a 7108 7109 4103
+a 7109 7110 4103
+a 7110 7111 4103
+a 7111 7112 4103
+a 7112 7113 4103
+a 7113 7114 4103
+a 7114 7115 4103
+a 7115 7116 4103
+a 7116 7117 4103
+a 7117 7118 4103
+a 7118 7119 4103
+a 7119 7120 4103
+a 7120 7121 4103
+a 7121 7122 4103
+a 7122 7123 4103
+a 7123 7124 4103
+a 7124 7125 4103
+a 7125 7126 4103
+a 7126 7127 4103
+a 7127 7128 4103
+a 7128 7129 4103
+a 7129 7130 4103
+a 7130 7131 4103
+a 7131 7132 4103
+a 7132 7133 4103
+a 7133 7134 4103
+a 7134 7135 4103
+a 7135 7136 4103
+a 7136 7137 4103
+a 7137 7138 4103
+a 7138 7139 4103
+a 7139 7140 4103
+a 7140 7141 4103
+a 7141 7142 4103
+a 7142 7143 4103
+a 7143 7144 4103
+a 7144 7145 4103
+a 7145 7146 4103
+a 7146 7147 4103
+a 7147 7148 4103
+a 7148 7149 4103
+a 7149 7150 4103
+a 7150 7151 4103
+a 7151 7152 4103
+a 7152 7153 4103
+a 7153 7154 4103
+a 7154 7155 4103
+a 7155 7156 4103
+a 7156 7157 4103
+a 7157 7158 4103
+a 7158 7159 4103
+a 7159 7160 4103
+a 7160 7161 4103
+a 7161 7162 4103
+a 7162 7163 4103
+a 7163 7164 4103
+a 7164 7165 4103
+a 7165 7166 4103
+a 7166 7167 4103
+a 7167 7168 4103
+a 7168 7169 4103
+a 7169 7170 4103
+a 7170 7171 4103
+a 7171 7172 4103
+a 7172 7173 4103
+a 7173 7174 4103
+a 7174 7175 4103
+a 7175 7176 4103
+a 7176 7177 4103
+a 7177 7178 4103
+a 7178 7179 4103
+a 7179 7180 4103
+a 7180 7181 4103
+a 7181 7182 4103
+a 7182 7183 4103
+a 7183 7184 4103
+a 7184 7185 4103
+a 7185 7186 4103
+a 7186 7187 4103
+a 7187 7188 4103
+a 7188 7189 4103
+a 7189 7190 4103
+a 7190 7191 4103
+a 7191 7192 4103
+a 7192 7193 4103
+a 7193 7194 4103
+a 7194 7195 4103
+a 7195 7196 4103
+a 7196 7197 4103
+a 7197 7198 4103
+a 7198 7199 4103
+a 7199 7200 4103
+a 7200 7201 4103
+a 7201 7202 4103
+a 7202 7203 4103
+a 7203 7204 4103
+a 7204 7205 4103
+a 7205 7206 4103
+a 7206 7207 4103
+a 7207 7208 4103
+a 7208 7209 4103
+a 7209 7210 4103
+a 7210 7211 4103
+a 7211 7212 4103
+a 7212 7213 4103
+a 7213 7214 4103
+a 7214 7215 4103
+a 7215 7216 4103
+a 7216 7217 4103
+a 7217 7218 4103
+a 7218 7219 4103
+a 7219 7220 4103
+a 7220 7221 4103
+a 7221 7222 4103
+a 7222 7223 4103
+a 7223 7224 4103
+a 7224 7225 4103
+a 7225 7226 4103
+a 7226 7227 4103
+a 7227 7228 4103
+a 7228 7229 4103
+a 7229 7230 4103
+a 7230 7231 4103
+a 7231 7232 4103
+a 7232 7233 4103
+a 7233 7234 4103
+a 7234 7235 4103
+a 7235 7236 4103
+a 7236 7237 4103
+a 7237 7238 4103
+a 7238 7239 4103
+a 7239 7240 4103
+a 7240 7241 4103
+a 7241 7242 4103
+a 7242 7243 4103
+a 7243 7244 4103
+a 7244 7245 4103
+a 7245 7246 4103
+a 7246 7247 4103
+a 7247 7248 4103
+a 7248 7249 4103
+a 7249 7250 4103
+a 7250 7251 4103
+a 7251 7252 4103
+a 7252 7253 4103
+a 7253 7254 4103
+a 7254 7255 4103
+a 7255 7256 4103
+a 7256 7257 4103
+a 7257 7258 4103
+a 7258 7259 4103
+a 7259 7260 4103
+a 7260 7261 4103
+a 7261 7262 4103
+a 7262 7263 4103
+a 7263 7264 4103
+a 7264 7265 4103
+a 7265 7266 4103
+a 7266 7267 4103
+a 7267 7268 4103
+a 7268 7269 4103
+a 7269 7270 4103
+a 7270 7271 4103
+a 7271 7272 4103
+a 7272 7273 4103
+a 7273 7274 4103
+a 7274 7275 4103
+a 7275 7276 4103
+a 7276 7277 4103
+a 7277 7278 4103
+a 7278 7279 4103
+a 7279 7280 4103
+a 7280 7281 4103
+a 7281 7282 4103
+a 7282 7283 4103
+a 7283 7284 4103
+a 7284 7285 4103
+a 7285 7286 4103
+a 7286 7287 4103
+a 7287 7288 4103
+a 7288 7289 4103
+a 7289 7290 4103
+a 7290 7291 4103
+a 7291 7292 4103
+a 7292 7293 4103
+a 7293 7294 4103
+a 7294 7295 4103
+a 7295 7296 4103
+a 7296 7297 4103
+a 7297 7298 4103
+a 7298 7299 4103
+a 7299 7300 4103
+a 7300 7301 4103
+a 7301 7302 4103
+a 7302 7303 4103
+a 7303 7304 4103
+a 7304 7305 4103
+a 7305 7306 4103
+a 7306 7307 4103
+a 7307 7308 4103
+a 7308 7309 4103
+a 7309 7310 4103
+a 7310 7311 4103
+a 7311 7312 4103
+a 7312 7313 4103
+a 7313 7314 4103
+a 7314 7315 4103
+a 7315 7316 4103
+a 7316 7317 4103
+a 7317 7318 4103
+a 7318 7319 4103
+a 7319 7320 4103
+a 7320 7321 4103
+a 7321 7322 4103
+a 7322 7323 4103
+a 7323 7324 4103
+a 7324 7325 4103
+a 7325 7326 4103
+a 7326 7327 4103
+a 7327 7328 4103
+a 7328 7329 4103
+a 7329 7330 4103
+a 7330 7331 4103
+a 7331 7332 4103
+a 7332 7333 4103
+a 7333 7334 4103
+a 7334 7335 4103
+a 7335 7336 4103
+a 7336 7337 4103
+a 7337 7338 4103
+a 7338 7339 4103
+a 7339 7340 4103
+a 7340 7341 4103
+a 7341 7342 4103
+a 7342 7343 4103
+a 7343 7344 4103
+a 7344 7345 4103
+a 7345 7346 4103
+a 7346 7347 4103
+a 7347 7348 4103
+a 7348 7349 4103
+a 7349 7350 4103
+a 7350 7351 4103
+a 7351 7352 4103
+a 7352 7353 4103
+a 7353 7354 4103
+a 7354 7355 4103
+a 7355 7356 4103
+a 7356 7357 4103
+a 7357 7358 4103
+a 7358 7359 4103
+a 7359 7360 4103
+a 7360 7361 4103
+a 7361 7362 4103
+a 7362 7363 4103
+a 7363 7364 4103
+a 7364 7365 4103
+a 7365 7366 4103
+a 7366 7367 4103
+a 7367 7368 4103
+a 7368 7369 4103
+a 7369 7370 4103
+a 7370 7371 4103
+a 7371 7372 4103
+a 7372 7373 4103
+a 7373 7374 4103
+a 7374 7375 4103
+a 7375 7376 4103
+a 7376 7377 4103
+a 7377 7378 4103
+a 7378 7379 4103
+a 7379 7380 4103
+a 7380 7381 4103
+a 7381 7382 4103
+a 7382 7383 4103
+a 7383 7384 4103
+a 7384 7385 4103
+a 7385 7386 4103
+a 7386 7387 4103
+a 7387 7388 4103
+a 7388 7389 4103
+a 7389 7390 4103
+a 7390 7391 4103
+a 7391 7392 4103
+a 7392 7393 4103
+a 7393 7394 4103
+a 7394 7395 4103
+a 7395 7396 4103
+a 7396 7397 4103
+a 7397 7398 4103
+a 7398 7399 4103
+a 7399 7400 4103
+a 7400 7401 4103
+a 7401 7402 4103
+a 7402 7403 4103
+a 7403 7404 4103
+a 7404 7405 4103
+a 7405 7406 4103
+a 7406 7407 4103
+a 7407 7408 4103
+a 7408 7409 4103
+a 7409 7410 4103
+a 7410 7411 4103
+a 7411 7412 4103
+a 7412 7413 4103
+a 7413 7414 4103
+a 7414 7415 4103
+a 7415 7416 4103
+a 7416 7417 4103
+a 7417 7418 4103
+a 7418 7419 4103
+a 7419 7420 4103
+a 7420 7421 4103
+a 7421 7422 4103
+a 7422 7423 4103
+a 7423 7424 4103
+a 7424 7425 4103
+a 7425 7426 4103
+a 7426 7427 4103
+a 7427 7428 4103
+a 7428 7429 4103
+a 7429 7430 4103
+a 7430 7431 4103
+a 7431 7432 4103
+a 7432 7433 4103
+a 7433 7434 4103
+a 7434 7435 4103
+a 7435 7436 4103
+a 7436 7437 4103
+a 7437 7438 4103
+a 7438 7439 4103
+a 7439 7440 4103
+a 7440 7441 4103
+a 7441 7442 4103
+a 7442 7443 4103
+a 7443 7444 4103
+a 7444 7445 4103
+a 7445 7446 4103
+a 7446 7447 4103
+a 7447 7448 4103
+a 7448 7449 4103
+a 7449 7450 4103
+a 7450 7451 4103
+a 7451 7452 4103
+a 7452 7453 4103
+a 7453 7454 4103
+a 7454 7455 4103
+a 7455 7456 4103
+a 7456 7457 4103
+a 7457 7458 4103
+a 7458 7459 4103
+a 7459 7460 4103
+a 7460 7461 4103
+a 7461 7462 4103
+a 7462 7463 4103
+a 7463 7464 4103
+a 7464 7465 4103
+a 7465 7466 4103
+a 7466 7467 4103
+a 7467 7468 4103
+a 7468 7469 4103
+a 7469 7470 4103
+a 7470 7471 4103
+a 7471 7472 4103
+a 7472 7473 4103
+a 7473 7474 4103
+a 7474 7475 4103
+a 7475 7476 4103
+a 7476 7477 4103
+a 7477 7478 4103
+a 7478 7479 4103
+a 7479 7480 4103
+a 7480 7481 4103
+a 7481 7482 4103
+a 7482 7483 4103
+a 7483 7484 4103
+a 7484 7485 4103
+a 7485 7486 4103
+a 7486 7487 4103
+a 7487 7488 4103
+a 7488 7489 4103
+a 7489 7490 4103
+a 7490 7491 4103
+a 7491 7492 4103
+a 7492 7493 4103
+a 7493 7494 4103
+a 7494 7495 4103
+a 7495 7496 4103
+a 7496 7497 4103
+a 7497 7498 4103
+a 7498 7499 4103
+a 7499 7500 4103
+a 7500 7501 4103
+a 7501 7502 4103
+a 7502 7503 4103
+a 7503 7504 4103
+a 7504 7505 4103
+a 7505 7506 4103
+a 7506 7507 4103
+a 7507 7508 4103
+a 7508 7509 4103
+a 7509 7510 4103
+a 7510 7511 4103
+a 7511 7512 4103
+a 7512 7513 4103
+a 7513 7514 4103
+a 7514 7515 4103
+a 7515 7516 4103
+a 7516 7517 4103
+a 7517 7518 4103
+a 7518 7519 4103
+a 7519 7520 4103
+a 7520 7521 4103
+a 7521 7522 4103
+a 7522 7523 4103
+a 7523 7524 4103
+a 7524 7525 4103
+a 7525 7526 4103
+a 7526 7527 4103
+a 7527 7528 4103
+a 7528 7529 4103
+a 7529 7530 4103
+a 7530 7531 4103
+a 7531 7532 4103
+a 7532 7533 4103
+a 7533 7534 4103
+a 7534 7535 4103
+a 7535 7536 4103
+a 7536 7537 4103
+a 7537 7538 4103
+a 7538 7539 4103
+a 7539 7540 4103
+a 7540 7541 4103
+a 7541 7542 4103
+a 7542 7543 4103
+a 7543 7544 4103
+a 7544 7545 4103
+a 7545 7546 4103
+a 7546 7547 4103
+a 7547 7548 4103
+a 7548 7549 4103
+a 7549 7550 4103
+a 7550 7551 4103
+a 7551 7552 4103
+a 7552 7553 4103
+a 7553 7554 4103
+a 7554 7555 4103
+a 7555 7556 4103
+a 7556 7557 4103
+a 7557 7558 4103
+a 7558 7559 4103
+a 7559 7560 4103
+a 7560 7561 4103
+a 7561 7562 4103
+a 7562 7563 4103
+a 7563 7564 4103
+a 7564 7565 4103
+a 7565 7566 4103
+a 7566 7567 4103
+a 7567 7568 4103
+a 7568 7569 4103
+a 7569 7570 4103
+a 7570 7571 4103
+a 7571 7572 4103
+a 7572 7573 4103
+a 7573 7574 4103
+a 7574 7575 4103
+a 7575 7576 4103
+a 7576 7577 4103
+a 7577 7578 4103
+a 7578 7579 4103
+a 7579 7580 4103
+a 7580 7581 4103
+a 7581 7582 4103
+a 7582 7583 4103
+a 7583 7584 4103
+a 7584 7585 4103
+a 7585 7586 4103
+a 7586 7587 4103
+a 7587 7588 4103
+a 7588 7589 4103
+a 7589 7590 4103
+a 7590 7591 4103
+a 7591 7592 4103
+a 7592 7593 4103
+a 7593 7594 4103
+a 7594 7595 4103
+a 7595 7596 4103
+a 7596 7597 4103
+a 7597 7598 4103
+a 7598 7599 4103
+a 7599 7600 4103
+a 7600 7601 4103
+a 7601 7602 4103
+a 7602 7603 4103
+a 7603 7604 4103
+a 7604 7605 4103
+a 7605 7606 4103
+a 7606 7607 4103
+a 7607 7608 4103
+a 7608 7609 4103
+a 7609 7610 4103
+a 7610 7611 4103
+a 7611 7612 4103
+a 7612 7613 4103
+a 7613 7614 4103
+a 7614 7615 4103
+a 7615 7616 4103
+a 7616 7617 4103
+a 7617 7618 4103
+a 7618 7619 4103
+a 7619 7620 4103
+a 7620 7621 4103
+a 7621 7622 4103
+a 7622 7623 4103
+a 7623 7624 4103
+a 7624 7625 4103
+a 7625 7626 4103
+a 7626 7627 4103
+a 7627 7628 4103
+a 7628 7629 4103
+a 7629 7630 4103
+a 7630 7631 4103
+a 7631 7632 4103
+a 7632 7633 4103
+a 7633 7634 4103
+a 7634 7635 4103
+a 7635 7636 4103
+a 7636 7637 4103
+a 7637 7638 4103
+a 7638 7639 4103
+a 7639 7640 4103
+a 7640 7641 4103
+a 7641 7642 4103
+a 7642 7643 4103
+a 7643 7644 4103
+a 7644 7645 4103
+a 7645 7646 4103
+a 7646 7647 4103
+a 7647 7648 4103
+a 7648 7649 4103
+a 7649 7650 4103
+a 7650 7651 4103
+a 7651 7652 4103
+a 7652 7653 4103
+a 7653 7654 4103
+a 7654 7655 4103
+a 7655 7656 4103
+a 7656 7657 4103
+a 7657 7658 4103
+a 7658 7659 4103
+a 7659 7660 4103
+a 7660 7661 4103
+a 7661 7662 4103
+a 7662 7663 4103
+a 7663 7664 4103
+a 7664 7665 4103
+a 7665 7666 4103
+a 7666 7667 4103
+a 7667 7668 4103
+a 7668 7669 4103
+a 7669 7670 4103
+a 7670 7671 4103
+a 7671 7672 4103
+a 7672 7673 4103
+a 7673 7674 4103
+a 7674 7675 4103
+a 7675 7676 4103
+a 7676 7677 4103
+a 7677 7678 4103
+a 7678 7679 4103
+a 7679 7680 4103
+a 7680 7681 4103
+a 7681 7682 4103
+a 7682 7683 4103
+a 7683 7684 4103
+a 7684 7685 4103
+a 7685 7686 4103
+a 7686 7687 4103
+a 7687 7688 4103
+a 7688 7689 4103
+a 7689 7690 4103
+a 7690 7691 4103
+a 7691 7692 4103
+a 7692 7693 4103
+a 7693 7694 4103
+a 7694 7695 4103
+a 7695 7696 4103
+a 7696 7697 4103
+a 7697 7698 4103
+a 7698 7699 4103
+a 7699 7700 4103
+a 7700 7701 4103
+a 7701 7702 4103
+a 7702 7703 4103
+a 7703 7704 4103
+a 7704 7705 4103
+a 7705 7706 4103
+a 7706 7707 4103
+a 7707 7708 4103
+a 7708 7709 4103
+a 7709 7710 4103
+a 7710 7711 4103
+a 7711 7712 4103
+a 7712 7713 4103
+a 7713 7714 4103
+a 7714 7715 4103
+a 7715 7716 4103
+a 7716 7717 4103
+a 7717 7718 4103
+a 7718 7719 4103
+a 7719 7720 4103
+a 7720 7721 4103
+a 7721 7722 4103
+a 7722 7723 4103
+a 7723 7724 4103
+a 7724 7725 4103
+a 7725 7726 4103
+a 7726 7727 4103
+a 7727 7728 4103
+a 7728 7729 4103
+a 7729 7730 4103
+a 7730 7731 4103
+a 7731 7732 4103
+a 7732 7733 4103
+a 7733 7734 4103
+a 7734 7735 4103
+a 7735 7736 4103
+a 7736 7737 4103
+a 7737 7738 4103
+a 7738 7739 4103
+a 7739 7740 4103
+a 7740 7741 4103
+a 7741 7742 4103
+a 7742 7743 4103
+a 7743 7744 4103
+a 7744 7745 4103
+a 7745 7746 4103
+a 7746 7747 4103
+a 7747 7748 4103
+a 7748 7749 4103
+a 7749 7750 4103
+a 7750 7751 4103
+a 7751 7752 4103
+a 7752 7753 4103
+a 7753 7754 4103
+a 7754 7755 4103
+a 7755 7756 4103
+a 7756 7757 4103
+a 7757 7758 4103
+a 7758 7759 4103
+a 7759 7760 4103
+a 7760 7761 4103
+a 7761 7762 4103
+a 7762 7763 4103
+a 7763 7764 4103
+a 7764 7765 4103
+a 7765 7766 4103
+a 7766 7767 4103
+a 7767 7768 4103
+a 7768 7769 4103
+a 7769 7770 4103
+a 7770 7771 4103
+a 7771 7772 4103
+a 7772 7773 4103
+a 7773 7774 4103
+a 7774 7775 4103
+a 7775 7776 4103
+a 7776 7777 4103
+a 7777 7778 4103
+a 7778 7779 4103
+a 7779 7780 4103
+a 7780 7781 4103
+a 7781 7782 4103
+a 7782 7783 4103
+a 7783 7784 4103
+a 7784 7785 4103
+a 7785 7786 4103
+a 7786 7787 4103
+a 7787 7788 4103
+a 7788 7789 4103
+a 7789 7790 4103
+a 7790 7791 4103
+a 7791 7792 4103
+a 7792 7793 4103
+a 7793 7794 4103
+a 7794 7795 4103
+a 7795 7796 4103
+a 7796 7797 4103
+a 7797 7798 4103
+a 7798 7799 4103
+a 7799 7800 4103
+a 7800 7801 4103
+a 7801 7802 4103
+a 7802 7803 4103
+a 7803 7804 4103
+a 7804 7805 4103
+a 7805 7806 4103
+a 7806 7807 4103
+a 7807 7808 4103
+a 7808 7809 4103
+a 7809 7810 4103
+a 7810 7811 4103
+a 7811 7812 4103
+a 7812 7813 4103
+a 7813 7814 4103
+a 7814 7815 4103
+a 7815 7816 4103
+a 7816 7817 4103
+a 7817 7818 4103
+a 7818 7819 4103
+a 7819 7820 4103
+a 7820 7821 4103
+a 7821 7822 4103
+a 7822 7823 4103
+a 7823 7824 4103
+a 7824 7825 4103
+a 7825 7826 4103
+a 7826 7827 4103
+a 7827 7828 4103
+a 7828 7829 4103
+a 7829 7830 4103
+a 7830 7831 4103
+a 7831 7832 4103
+a 7832 7833 4103
+a 7833 7834 4103
+a 7834 7835 4103
+a 7835 7836 4103
+a 7836 7837 4103
+a 7837 7838 4103
+a 7838 7839 4103
+a 7839 7840 4103
+a 7840 7841 4103
+a 7841 7842 4103
+a 7842 7843 4103
+a 7843 7844 4103
+a 7844 7845 4103
+a 7845 7846 4103
+a 7846 7847 4103
+a 7847 7848 4103
+a 7848 7849 4103
+a 7849 7850 4103
+a 7850 7851 4103
+a 7851 7852 4103
+a 7852 7853 4103
+a 7853 7854 4103
+a 7854 7855 4103
+a 7855 7856 4103
+a 7856 7857 4103
+a 7857 7858 4103
+a 7858 7859 4103
+a 7859 7860 4103
+a 7860 7861 4103
+a 7861 7862 4103
+a 7862 7863 4103
+a 7863 7864 4103
+a 7864 7865 4103
+a 7865 7866 4103
+a 7866 7867 4103
+a 7867 7868 4103
+a 7868 7869 4103
+a 7869 7870 4103
+a 7870 7871 4103
+a 7871 7872 4103
+a 7872 7873 4103
+a 7873 7874 4103
+a 7874 7875 4103
+a 7875 7876 4103
+a 7876 7877 4103
+a 7877 7878 4103
+a 7878 7879 4103
+a 7879 7880 4103
+a 7880 7881 4103
+a 7881 7882 4103
+a 7882 7883 4103
+a 7883 7884 4103
+a 7884 7885 4103
+a 7885 7886 4103
+a 7886 7887 4103
+a 7887 7888 4103
+a 7888 7889 4103
+a 7889 7890 4103
+a 7890 7891 4103
+a 7891 7892 4103
+a 7892 7893 4103
+a 7893 7894 4103
+a 7894 7895 4103
+a 7895 7896 4103
+a 7896 7897 4103
+a 7897 7898 4103
+a 7898 7899 4103
+a 7899 7900 4103
+a 7900 7901 4103
+a 7901 7902 4103
+a 7902 7903 4103
+a 7903 7904 4103
+a 7904 7905 4103
+a 7905 7906 4103
+a 7906 7907 4103
+a 7907 7908 4103
+a 7908 7909 4103
+a 7909 7910 4103
+a 7910 7911 4103
+a 7911 7912 4103
+a 7912 7913 4103
+a 7913 7914 4103
+a 7914 7915 4103
+a 7915 7916 4103
+a 7916 7917 4103
+a 7917 7918 4103
+a 7918 7919 4103
+a 7919 7920 4103
+a 7920 7921 4103
+a 7921 7922 4103
+a 7922 7923 4103
+a 7923 7924 4103
+a 7924 7925 4103
+a 7925 7926 4103
+a 7926 7927 4103
+a 7927 7928 4103
+a 7928 7929 4103
+a 7929 7930 4103
+a 7930 7931 4103
+a 7931 7932 4103
+a 7932 7933 4103
+a 7933 7934 4103
+a 7934 7935 4103
+a 7935 7936 4103
+a 7936 7937 4103
+a 7937 7938 4103
+a 7938 7939 4103
+a 7939 7940 4103
+a 7940 7941 4103
+a 7941 7942 4103
+a 7942 7943 4103
+a 7943 7944 4103
+a 7944 7945 4103
+a 7945 7946 4103
+a 7946 7947 4103
+a 7947 7948 4103
+a 7948 7949 4103
+a 7949 7950 4103
+a 7950 7951 4103
+a 7951 7952 4103
+a 7952 7953 4103
+a 7953 7954 4103
+a 7954 7955 4103
+a 7955 7956 4103
+a 7956 7957 4103
+a 7957 7958 4103
+a 7958 7959 4103
+a 7959 7960 4103
+a 7960 7961 4103
+a 7961 7962 4103
+a 7962 7963 4103
+a 7963 7964 4103
+a 7964 7965 4103
+a 7965 7966 4103
+a 7966 7967 4103
+a 7967 7968 4103
+a 7968 7969 4103
+a 7969 7970 4103
+a 7970 7971 4103
+a 7971 7972 4103
+a 7972 7973 4103
+a 7973 7974 4103
+a 7974 7975 4103
+a 7975 7976 4103
+a 7976 7977 4103
+a 7977 7978 4103
+a 7978 7979 4103
+a 7979 7980 4103
+a 7980 7981 4103
+a 7981 7982 4103
+a 7982 7983 4103
+a 7983 7984 4103
+a 7984 7985 4103
+a 7985 7986 4103
+a 7986 7987 4103
+a 7987 7988 4103
+a 7988 7989 4103
+a 7989 7990 4103
+a 7990 7991 4103
+a 7991 7992 4103
+a 7992 7993 4103
+a 7993 7994 4103
+a 7994 7995 4103
+a 7995 7996 4103
+a 7996 7997 4103
+a 7997 7998 4103
+a 7998 7999 4103
+a 7999 8000 4103
+a 8000 8001 4103
+a 8001 8002 4103
+a 8002 8003 4103
+a 8003 8004 4103
+a 8004 8005 4103
+a 8005 8006 4103
+a 8006 8007 4103
+a 8007 8008 4103
+a 8008 8009 4103
+a 8009 8010 4103
+a 8010 8011 4103
+a 8011 8012 4103
+a 8012 8013 4103
+a 8013 8014 4103
+a 8014 8015 4103
+a 8015 8016 4103
+a 8016 8017 4103
+a 8017 8018 4103
+a 8018 8019 4103
+a 8019 8020 4103
+a 8020 8021 4103
+a 8021 8022 4103
+a 8022 8023 4103
+a 8023 8024 4103
+a 8024 8025 4103
+a 8025 8026 4103
+a 8026 8027 4103
+a 8027 8028 4103
+a 8028 8029 4103
+a 8029 8030 4103
+a 8030 8031 4103
+a 8031 8032 4103
+a 8032 8033 4103
+a 8033 8034 4103
+a 8034 8035 4103
+a 8035 8036 4103
+a 8036 8037 4103
+a 8037 8038 4103
+a 8038 8039 4103
+a 8039 8040 4103
+a 8040 8041 4103
+a 8041 8042 4103
+a 8042 8043 4103
+a 8043 8044 4103
+a 8044 8045 4103
+a 8045 8046 4103
+a 8046 8047 4103
+a 8047 8048 4103
+a 8048 8049 4103
+a 8049 8050 4103
+a 8050 8051 4103
+a 8051 8052 4103
+a 8052 8053 4103
+a 8053 8054 4103
+a 8054 8055 4103
+a 8055 8056 4103
+a 8056 8057 4103
+a 8057 8058 4103
+a 8058 8059 4103
+a 8059 8060 4103
+a 8060 8061 4103
+a 8061 8062 4103
+a 8062 8063 4103
+a 8063 8064 4103
+a 8064 8065 4103
+a 8065 8066 4103
+a 8066 8067 4103
+a 8067 8068 4103
+a 8068 8069 4103
+a 8069 8070 4103
+a 8070 8071 4103
+a 8071 8072 4103
+a 8072 8073 4103
+a 8073 8074 4103
+a 8074 8075 4103
+a 8075 8076 4103
+a 8076 8077 4103
+a 8077 8078 4103
+a 8078 8079 4103
+a 8079 8080 4103
+a 8080 8081 4103
+a 8081 8082 4103
+a 8082 8083 4103
+a 8083 8084 4103
+a 8084 8085 4103
+a 8085 8086 4103
+a 8086 8087 4103
+a 8087 8088 4103
+a 8088 8089 4103
+a 8089 8090 4103
+a 8090 8091 4103
+a 8091 8092 4103
+a 8092 8093 4103
+a 8093 8094 4103
+a 8094 8095 4103
+a 8095 8096 4103
+a 8096 8097 4103
+a 8097 8098 4103
+a 8098 8099 4103
+a 8099 8100 4103
+a 8100 8101 4103
+a 8101 8102 4103
+a 8102 8103 4103
+a 8103 8104 4103
+a 8104 8105 4103
+a 8105 8106 4103
+a 8106 8107 4103
+a 8107 8108 4103
+a 8108 8109 4103
+a 8109 8110 4103
+a 8110 8111 4103
+a 8111 8112 4103
+a 8112 8113 4103
+a 8113 8114 4103
+a 8114 8115 4103
+a 8115 8116 4103
+a 8116 8117 4103
+a 8117 8118 4103
+a 8118 8119 4103
+a 8119 8120 4103
+a 8120 8121 4103
+a 8121 8122 4103
+a 8122 8123 4103
+a 8123 8124 4103
+a 8124 8125 4103
+a 8125 8126 4103
+a 8126 8127 4103
+a 8127 8128 4103
+a 8128 8129 4103
+a 8129 8130 4103
+a 8130 8131 4103
+a 8131 8132 4103
+a 8132 8133 4103
+a 8133 8134 4103
+a 8134 8135 4103
+a 8135 8136 4103
+a 8136 8137 4103
+a 8137 8138 4103
+a 8138 8139 4103
+a 8139 8140 4103
+a 8140 8141 4103
+a 8141 8142 4103
+a 8142 8143 4103
+a 8143 8144 4103
+a 8144 8145 4103
+a 8145 8146 4103
+a 8146 8147 4103
+a 8147 8148 4103
+a 8148 8149 4103
+a 8149 8150 4103
+a 8150 8151 4103
+a 8151 8152 4103
+a 8152 8153 4103
+a 8153 8154 4103
+a 8154 8155 4103
+a 8155 8156 4103
+a 8156 8157 4103
+a 8157 8158 4103
+a 8158 8159 4103
+a 8159 8160 4103
+a 8160 8161 4103
+a 8161 8162 4103
+a 8162 8163 4103
+a 8163 8164 4103
+a 8164 8165 4103
+a 8165 8166 4103
+a 8166 8167 4103
+a 8167 8168 4103
+a 8168 8169 4103
+a 8169 8170 4103
+a 8170 8171 4103
+a 8171 8172 4103
+a 8172 8173 4103
+a 8173 8174 4103
+a 8174 8175 4103
+a 8175 8176 4103
+a 8176 8177 4103
+a 8177 8178 4103
+a 8178 8179 4103
+a 8179 8180 4103
+a 8180 8181 4103
+a 8181 8182 4103
+a 8182 8183 4103
+a 8183 8184 4103
+a 8184 8185 4103
+a 8185 8186 4103
+a 8186 8187 4103
+a 8187 8188 4103
+a 8188 8189 4103
+a 8189 8190 4103
+a 8190 8191 4103
+a 8191 8192 4103
+a 8192 8193 4103
+a 8193 8194 4103
+a 8194 8195 4103
+a 8195 8196 4103
+a 8196 8197 4103
+a 8197 8198 4103
+a 8198 8199 4103
+a 8199 8200 4103
+a 8200 8201 4103
+a 8201 8202 4103
+a 8202 8203 4103
+a 8203 8204 4103
+a 8204 8205 4103
+a 8205 8206 4103
+a 8206 8207 4103
+a 8207 8208 4103
+a 8209 8210 4102
+a 8210 8211 4102
+a 8211 8212 4102
+a 8212 8213 4102
+a 8213 8214 4102
+a 8214 8215 4102
+a 8215 8216 4102
+a 8216 8217 4102
+a 8217 8218 4102
+a 8218 8219 4102
+a 8219 8220 4102
+a 8220 8221 4102
+a 8221 8222 4102
+a 8222 8223 4102
+a 8223 8224 4102
+a 8224 8225 4102
+a 8225 8226 4102
+a 8226 8227 4102
+a 8227 8228 4102
+a 8228 8229 4102
+a 8229 8230 4102
+a 8230 8231 4102
+a 8231 8232 4102
+a 8232 8233 4102
+a 8233 8234 4102
+a 8234 8235 4102
+a 8235 8236 4102
+a 8236 8237 4102
+a 8237 8238 4102
+a 8238 8239 4102
+a 8239 8240 4102
+a 8240 8241 4102
+a 8241 8242 4102
+a 8242 8243 4102
+a 8243 8244 4102
+a 8244 8245 4102
+a 8245 8246 4102
+a 8246 8247 4102
+a 8247 8248 4102
+a 8248 8249 4102
+a 8249 8250 4102
+a 8250 8251 4102
+a 8251 8252 4102
+a 8252 8253 4102
+a 8253 8254 4102
+a 8254 8255 4102
+a 8255 8256 4102
+a 8256 8257 4102
+a 8257 8258 4102
+a 8258 8259 4102
+a 8259 8260 4102
+a 8260 8261 4102
+a 8261 8262 4102
+a 8262 8263 4102
+a 8263 8264 4102
+a 8264 8265 4102
+a 8265 8266 4102
+a 8266 8267 4102
+a 8267 8268 4102
+a 8268 8269 4102
+a 8269 8270 4102
+a 8270 8271 4102
+a 8271 8272 4102
+a 8272 8273 4102
+a 8273 8274 4102
+a 8274 8275 4102
+a 8275 8276 4102
+a 8276 8277 4102
+a 8277 8278 4102
+a 8278 8279 4102
+a 8279 8280 4102
+a 8280 8281 4102
+a 8281 8282 4102
+a 8282 8283 4102
+a 8283 8284 4102
+a 8284 8285 4102
+a 8285 8286 4102
+a 8286 8287 4102
+a 8287 8288 4102
+a 8288 8289 4102
+a 8289 8290 4102
+a 8290 8291 4102
+a 8291 8292 4102
+a 8292 8293 4102
+a 8293 8294 4102
+a 8294 8295 4102
+a 8295 8296 4102
+a 8296 8297 4102
+a 8297 8298 4102
+a 8298 8299 4102
+a 8299 8300 4102
+a 8300 8301 4102
+a 8301 8302 4102
+a 8302 8303 4102
+a 8303 8304 4102
+a 8304 8305 4102
+a 8305 8306 4102
+a 8306 8307 4102
+a 8307 8308 4102
+a 8308 8309 4102
+a 8309 8310 4102
+a 8310 8311 4102
+a 8311 8312 4102
+a 8312 8313 4102
+a 8313 8314 4102
+a 8314 8315 4102
+a 8315 8316 4102
+a 8316 8317 4102
+a 8317 8318 4102
+a 8318 8319 4102
+a 8319 8320 4102
+a 8320 8321 4102
+a 8321 8322 4102
+a 8322 8323 4102
+a 8323 8324 4102
+a 8324 8325 4102
+a 8325 8326 4102
+a 8326 8327 4102
+a 8327 8328 4102
+a 8328 8329 4102
+a 8329 8330 4102
+a 8330 8331 4102
+a 8331 8332 4102
+a 8332 8333 4102
+a 8333 8334 4102
+a 8334 8335 4102
+a 8335 8336 4102
+a 8336 8337 4102
+a 8337 8338 4102
+a 8338 8339 4102
+a 8339 8340 4102
+a 8340 8341 4102
+a 8341 8342 4102
+a 8342 8343 4102
+a 8343 8344 4102
+a 8344 8345 4102
+a 8345 8346 4102
+a 8346 8347 4102
+a 8347 8348 4102
+a 8348 8349 4102
+a 8349 8350 4102
+a 8350 8351 4102
+a 8351 8352 4102
+a 8352 8353 4102
+a 8353 8354 4102
+a 8354 8355 4102
+a 8355 8356 4102
+a 8356 8357 4102
+a 8357 8358 4102
+a 8358 8359 4102
+a 8359 8360 4102
+a 8360 8361 4102
+a 8361 8362 4102
+a 8362 8363 4102
+a 8363 8364 4102
+a 8364 8365 4102
+a 8365 8366 4102
+a 8366 8367 4102
+a 8367 8368 4102
+a 8368 8369 4102
+a 8369 8370 4102
+a 8370 8371 4102
+a 8371 8372 4102
+a 8372 8373 4102
+a 8373 8374 4102
+a 8374 8375 4102
+a 8375 8376 4102
+a 8376 8377 4102
+a 8377 8378 4102
+a 8378 8379 4102
+a 8379 8380 4102
+a 8380 8381 4102
+a 8381 8382 4102
+a 8382 8383 4102
+a 8383 8384 4102
+a 8384 8385 4102
+a 8385 8386 4102
+a 8386 8387 4102
+a 8387 8388 4102
+a 8388 8389 4102
+a 8389 8390 4102
+a 8390 8391 4102
+a 8391 8392 4102
+a 8392 8393 4102
+a 8393 8394 4102
+a 8394 8395 4102
+a 8395 8396 4102
+a 8396 8397 4102
+a 8397 8398 4102
+a 8398 8399 4102
+a 8399 8400 4102
+a 8400 8401 4102
+a 8401 8402 4102
+a 8402 8403 4102
+a 8403 8404 4102
+a 8404 8405 4102
+a 8405 8406 4102
+a 8406 8407 4102
+a 8407 8408 4102
+a 8408 8409 4102
+a 8409 8410 4102
+a 8410 8411 4102
+a 8411 8412 4102
+a 8412 8413 4102
+a 8413 8414 4102
+a 8414 8415 4102
+a 8415 8416 4102
+a 8416 8417 4102
+a 8417 8418 4102
+a 8418 8419 4102
+a 8419 8420 4102
+a 8420 8421 4102
+a 8421 8422 4102
+a 8422 8423 4102
+a 8423 8424 4102
+a 8424 8425 4102
+a 8425 8426 4102
+a 8426 8427 4102
+a 8427 8428 4102
+a 8428 8429 4102
+a 8429 8430 4102
+a 8430 8431 4102
+a 8431 8432 4102
+a 8432 8433 4102
+a 8433 8434 4102
+a 8434 8435 4102
+a 8435 8436 4102
+a 8436 8437 4102
+a 8437 8438 4102
+a 8438 8439 4102
+a 8439 8440 4102
+a 8440 8441 4102
+a 8441 8442 4102
+a 8442 8443 4102
+a 8443 8444 4102
+a 8444 8445 4102
+a 8445 8446 4102
+a 8446 8447 4102
+a 8447 8448 4102
+a 8448 8449 4102
+a 8449 8450 4102
+a 8450 8451 4102
+a 8451 8452 4102
+a 8452 8453 4102
+a 8453 8454 4102
+a 8454 8455 4102
+a 8455 8456 4102
+a 8456 8457 4102
+a 8457 8458 4102
+a 8458 8459 4102
+a 8459 8460 4102
+a 8460 8461 4102
+a 8461 8462 4102
+a 8462 8463 4102
+a 8463 8464 4102
+a 8464 8465 4102
+a 8465 8466 4102
+a 8466 8467 4102
+a 8467 8468 4102
+a 8468 8469 4102
+a 8469 8470 4102
+a 8470 8471 4102
+a 8471 8472 4102
+a 8472 8473 4102
+a 8473 8474 4102
+a 8474 8475 4102
+a 8475 8476 4102
+a 8476 8477 4102
+a 8477 8478 4102
+a 8478 8479 4102
+a 8479 8480 4102
+a 8480 8481 4102
+a 8481 8482 4102
+a 8482 8483 4102
+a 8483 8484 4102
+a 8484 8485 4102
+a 8485 8486 4102
+a 8486 8487 4102
+a 8487 8488 4102
+a 8488 8489 4102
+a 8489 8490 4102
+a 8490 8491 4102
+a 8491 8492 4102
+a 8492 8493 4102
+a 8493 8494 4102
+a 8494 8495 4102
+a 8495 8496 4102
+a 8496 8497 4102
+a 8497 8498 4102
+a 8498 8499 4102
+a 8499 8500 4102
+a 8500 8501 4102
+a 8501 8502 4102
+a 8502 8503 4102
+a 8503 8504 4102
+a 8504 8505 4102
+a 8505 8506 4102
+a 8506 8507 4102
+a 8507 8508 4102
+a 8508 8509 4102
+a 8509 8510 4102
+a 8510 8511 4102
+a 8511 8512 4102
+a 8512 8513 4102
+a 8513 8514 4102
+a 8514 8515 4102
+a 8515 8516 4102
+a 8516 8517 4102
+a 8517 8518 4102
+a 8518 8519 4102
+a 8519 8520 4102
+a 8520 8521 4102
+a 8521 8522 4102
+a 8522 8523 4102
+a 8523 8524 4102
+a 8524 8525 4102
+a 8525 8526 4102
+a 8526 8527 4102
+a 8527 8528 4102
+a 8528 8529 4102
+a 8529 8530 4102
+a 8530 8531 4102
+a 8531 8532 4102
+a 8532 8533 4102
+a 8533 8534 4102
+a 8534 8535 4102
+a 8535 8536 4102
+a 8536 8537 4102
+a 8537 8538 4102
+a 8538 8539 4102
+a 8539 8540 4102
+a 8540 8541 4102
+a 8541 8542 4102
+a 8542 8543 4102
+a 8543 8544 4102
+a 8544 8545 4102
+a 8545 8546 4102
+a 8546 8547 4102
+a 8547 8548 4102
+a 8548 8549 4102
+a 8549 8550 4102
+a 8550 8551 4102
+a 8551 8552 4102
+a 8552 8553 4102
+a 8553 8554 4102
+a 8554 8555 4102
+a 8555 8556 4102
+a 8556 8557 4102
+a 8557 8558 4102
+a 8558 8559 4102
+a 8559 8560 4102
+a 8560 8561 4102
+a 8561 8562 4102
+a 8562 8563 4102
+a 8563 8564 4102
+a 8564 8565 4102
+a 8565 8566 4102
+a 8566 8567 4102
+a 8567 8568 4102
+a 8568 8569 4102
+a 8569 8570 4102
+a 8570 8571 4102
+a 8571 8572 4102
+a 8572 8573 4102
+a 8573 8574 4102
+a 8574 8575 4102
+a 8575 8576 4102
+a 8576 8577 4102
+a 8577 8578 4102
+a 8578 8579 4102
+a 8579 8580 4102
+a 8580 8581 4102
+a 8581 8582 4102
+a 8582 8583 4102
+a 8583 8584 4102
+a 8584 8585 4102
+a 8585 8586 4102
+a 8586 8587 4102
+a 8587 8588 4102
+a 8588 8589 4102
+a 8589 8590 4102
+a 8590 8591 4102
+a 8591 8592 4102
+a 8592 8593 4102
+a 8593 8594 4102
+a 8594 8595 4102
+a 8595 8596 4102
+a 8596 8597 4102
+a 8597 8598 4102
+a 8598 8599 4102
+a 8599 8600 4102
+a 8600 8601 4102
+a 8601 8602 4102
+a 8602 8603 4102
+a 8603 8604 4102
+a 8604 8605 4102
+a 8605 8606 4102
+a 8606 8607 4102
+a 8607 8608 4102
+a 8608 8609 4102
+a 8609 8610 4102
+a 8610 8611 4102
+a 8611 8612 4102
+a 8612 8613 4102
+a 8613 8614 4102
+a 8614 8615 4102
+a 8615 8616 4102
+a 8616 8617 4102
+a 8617 8618 4102
+a 8618 8619 4102
+a 8619 8620 4102
+a 8620 8621 4102
+a 8621 8622 4102
+a 8622 8623 4102
+a 8623 8624 4102
+a 8624 8625 4102
+a 8625 8626 4102
+a 8626 8627 4102
+a 8627 8628 4102
+a 8628 8629 4102
+a 8629 8630 4102
+a 8630 8631 4102
+a 8631 8632 4102
+a 8632 8633 4102
+a 8633 8634 4102
+a 8634 8635 4102
+a 8635 8636 4102
+a 8636 8637 4102
+a 8637 8638 4102
+a 8638 8639 4102
+a 8639 8640 4102
+a 8640 8641 4102
+a 8641 8642 4102
+a 8642 8643 4102
+a 8643 8644 4102
+a 8644 8645 4102
+a 8645 8646 4102
+a 8646 8647 4102
+a 8647 8648 4102
+a 8648 8649 4102
+a 8649 8650 4102
+a 8650 8651 4102
+a 8651 8652 4102
+a 8652 8653 4102
+a 8653 8654 4102
+a 8654 8655 4102
+a 8655 8656 4102
+a 8656 8657 4102
+a 8657 8658 4102
+a 8658 8659 4102
+a 8659 8660 4102
+a 8660 8661 4102
+a 8661 8662 4102
+a 8662 8663 4102
+a 8663 8664 4102
+a 8664 8665 4102
+a 8665 8666 4102
+a 8666 8667 4102
+a 8667 8668 4102
+a 8668 8669 4102
+a 8669 8670 4102
+a 8670 8671 4102
+a 8671 8672 4102
+a 8672 8673 4102
+a 8673 8674 4102
+a 8674 8675 4102
+a 8675 8676 4102
+a 8676 8677 4102
+a 8677 8678 4102
+a 8678 8679 4102
+a 8679 8680 4102
+a 8680 8681 4102
+a 8681 8682 4102
+a 8682 8683 4102
+a 8683 8684 4102
+a 8684 8685 4102
+a 8685 8686 4102
+a 8686 8687 4102
+a 8687 8688 4102
+a 8688 8689 4102
+a 8689 8690 4102
+a 8690 8691 4102
+a 8691 8692 4102
+a 8692 8693 4102
+a 8693 8694 4102
+a 8694 8695 4102
+a 8695 8696 4102
+a 8696 8697 4102
+a 8697 8698 4102
+a 8698 8699 4102
+a 8699 8700 4102
+a 8700 8701 4102
+a 8701 8702 4102
+a 8702 8703 4102
+a 8703 8704 4102
+a 8704 8705 4102
+a 8705 8706 4102
+a 8706 8707 4102
+a 8707 8708 4102
+a 8708 8709 4102
+a 8709 8710 4102
+a 8710 8711 4102
+a 8711 8712 4102
+a 8712 8713 4102
+a 8713 8714 4102
+a 8714 8715 4102
+a 8715 8716 4102
+a 8716 8717 4102
+a 8717 8718 4102
+a 8718 8719 4102
+a 8719 8720 4102
+a 8720 8721 4102
+a 8721 8722 4102
+a 8722 8723 4102
+a 8723 8724 4102
+a 8724 8725 4102
+a 8725 8726 4102
+a 8726 8727 4102
+a 8727 8728 4102
+a 8728 8729 4102
+a 8729 8730 4102
+a 8730 8731 4102
+a 8731 8732 4102
+a 8732 8733 4102
+a 8733 8734 4102
+a 8734 8735 4102
+a 8735 8736 4102
+a 8736 8737 4102
+a 8737 8738 4102
+a 8738 8739 4102
+a 8739 8740 4102
+a 8740 8741 4102
+a 8741 8742 4102
+a 8742 8743 4102
+a 8743 8744 4102
+a 8744 8745 4102
+a 8745 8746 4102
+a 8746 8747 4102
+a 8747 8748 4102
+a 8748 8749 4102
+a 8749 8750 4102
+a 8750 8751 4102
+a 8751 8752 4102
+a 8752 8753 4102
+a 8753 8754 4102
+a 8754 8755 4102
+a 8755 8756 4102
+a 8756 8757 4102
+a 8757 8758 4102
+a 8758 8759 4102
+a 8759 8760 4102
+a 8760 8761 4102
+a 8761 8762 4102
+a 8762 8763 4102
+a 8763 8764 4102
+a 8764 8765 4102
+a 8765 8766 4102
+a 8766 8767 4102
+a 8767 8768 4102
+a 8768 8769 4102
+a 8769 8770 4102
+a 8770 8771 4102
+a 8771 8772 4102
+a 8772 8773 4102
+a 8773 8774 4102
+a 8774 8775 4102
+a 8775 8776 4102
+a 8776 8777 4102
+a 8777 8778 4102
+a 8778 8779 4102
+a 8779 8780 4102
+a 8780 8781 4102
+a 8781 8782 4102
+a 8782 8783 4102
+a 8783 8784 4102
+a 8784 8785 4102
+a 8785 8786 4102
+a 8786 8787 4102
+a 8787 8788 4102
+a 8788 8789 4102
+a 8789 8790 4102
+a 8790 8791 4102
+a 8791 8792 4102
+a 8792 8793 4102
+a 8793 8794 4102
+a 8794 8795 4102
+a 8795 8796 4102
+a 8796 8797 4102
+a 8797 8798 4102
+a 8798 8799 4102
+a 8799 8800 4102
+a 8800 8801 4102
+a 8801 8802 4102
+a 8802 8803 4102
+a 8803 8804 4102
+a 8804 8805 4102
+a 8805 8806 4102
+a 8806 8807 4102
+a 8807 8808 4102
+a 8808 8809 4102
+a 8809 8810 4102
+a 8810 8811 4102
+a 8811 8812 4102
+a 8812 8813 4102
+a 8813 8814 4102
+a 8814 8815 4102
+a 8815 8816 4102
+a 8816 8817 4102
+a 8817 8818 4102
+a 8818 8819 4102
+a 8819 8820 4102
+a 8820 8821 4102
+a 8821 8822 4102
+a 8822 8823 4102
+a 8823 8824 4102
+a 8824 8825 4102
+a 8825 8826 4102
+a 8826 8827 4102
+a 8827 8828 4102
+a 8828 8829 4102
+a 8829 8830 4102
+a 8830 8831 4102
+a 8831 8832 4102
+a 8832 8833 4102
+a 8833 8834 4102
+a 8834 8835 4102
+a 8835 8836 4102
+a 8836 8837 4102
+a 8837 8838 4102
+a 8838 8839 4102
+a 8839 8840 4102
+a 8840 8841 4102
+a 8841 8842 4102
+a 8842 8843 4102
+a 8843 8844 4102
+a 8844 8845 4102
+a 8845 8846 4102
+a 8846 8847 4102
+a 8847 8848 4102
+a 8848 8849 4102
+a 8849 8850 4102
+a 8850 8851 4102
+a 8851 8852 4102
+a 8852 8853 4102
+a 8853 8854 4102
+a 8854 8855 4102
+a 8855 8856 4102
+a 8856 8857 4102
+a 8857 8858 4102
+a 8858 8859 4102
+a 8859 8860 4102
+a 8860 8861 4102
+a 8861 8862 4102
+a 8862 8863 4102
+a 8863 8864 4102
+a 8864 8865 4102
+a 8865 8866 4102
+a 8866 8867 4102
+a 8867 8868 4102
+a 8868 8869 4102
+a 8869 8870 4102
+a 8870 8871 4102
+a 8871 8872 4102
+a 8872 8873 4102
+a 8873 8874 4102
+a 8874 8875 4102
+a 8875 8876 4102
+a 8876 8877 4102
+a 8877 8878 4102
+a 8878 8879 4102
+a 8879 8880 4102
+a 8880 8881 4102
+a 8881 8882 4102
+a 8882 8883 4102
+a 8883 8884 4102
+a 8884 8885 4102
+a 8885 8886 4102
+a 8886 8887 4102
+a 8887 8888 4102
+a 8888 8889 4102
+a 8889 8890 4102
+a 8890 8891 4102
+a 8891 8892 4102
+a 8892 8893 4102
+a 8893 8894 4102
+a 8894 8895 4102
+a 8895 8896 4102
+a 8896 8897 4102
+a 8897 8898 4102
+a 8898 8899 4102
+a 8899 8900 4102
+a 8900 8901 4102
+a 8901 8902 4102
+a 8902 8903 4102
+a 8903 8904 4102
+a 8904 8905 4102
+a 8905 8906 4102
+a 8906 8907 4102
+a 8907 8908 4102
+a 8908 8909 4102
+a 8909 8910 4102
+a 8910 8911 4102
+a 8911 8912 4102
+a 8912 8913 4102
+a 8913 8914 4102
+a 8914 8915 4102
+a 8915 8916 4102
+a 8916 8917 4102
+a 8917 8918 4102
+a 8918 8919 4102
+a 8919 8920 4102
+a 8920 8921 4102
+a 8921 8922 4102
+a 8922 8923 4102
+a 8923 8924 4102
+a 8924 8925 4102
+a 8925 8926 4102
+a 8926 8927 4102
+a 8927 8928 4102
+a 8928 8929 4102
+a 8929 8930 4102
+a 8930 8931 4102
+a 8931 8932 4102
+a 8932 8933 4102
+a 8933 8934 4102
+a 8934 8935 4102
+a 8935 8936 4102
+a 8936 8937 4102
+a 8937 8938 4102
+a 8938 8939 4102
+a 8939 8940 4102
+a 8940 8941 4102
+a 8941 8942 4102
+a 8942 8943 4102
+a 8943 8944 4102
+a 8944 8945 4102
+a 8945 8946 4102
+a 8946 8947 4102
+a 8947 8948 4102
+a 8948 8949 4102
+a 8949 8950 4102
+a 8950 8951 4102
+a 8951 8952 4102
+a 8952 8953 4102
+a 8953 8954 4102
+a 8954 8955 4102
+a 8955 8956 4102
+a 8956 8957 4102
+a 8957 8958 4102
+a 8958 8959 4102
+a 8959 8960 4102
+a 8960 8961 4102
+a 8961 8962 4102
+a 8962 8963 4102
+a 8963 8964 4102
+a 8964 8965 4102
+a 8965 8966 4102
+a 8966 8967 4102
+a 8967 8968 4102
+a 8968 8969 4102
+a 8969 8970 4102
+a 8970 8971 4102
+a 8971 8972 4102
+a 8972 8973 4102
+a 8973 8974 4102
+a 8974 8975 4102
+a 8975 8976 4102
+a 8976 8977 4102
+a 8977 8978 4102
+a 8978 8979 4102
+a 8979 8980 4102
+a 8980 8981 4102
+a 8981 8982 4102
+a 8982 8983 4102
+a 8983 8984 4102
+a 8984 8985 4102
+a 8985 8986 4102
+a 8986 8987 4102
+a 8987 8988 4102
+a 8988 8989 4102
+a 8989 8990 4102
+a 8990 8991 4102
+a 8991 8992 4102
+a 8992 8993 4102
+a 8993 8994 4102
+a 8994 8995 4102
+a 8995 8996 4102
+a 8996 8997 4102
+a 8997 8998 4102
+a 8998 8999 4102
+a 8999 9000 4102
+a 9000 9001 4102
+a 9001 9002 4102
+a 9002 9003 4102
+a 9003 9004 4102
+a 9004 9005 4102
+a 9005 9006 4102
+a 9006 9007 4102
+a 9007 9008 4102
+a 9008 9009 4102
+a 9009 9010 4102
+a 9010 9011 4102
+a 9011 9012 4102
+a 9012 9013 4102
+a 9013 9014 4102
+a 9014 9015 4102
+a 9015 9016 4102
+a 9016 9017 4102
+a 9017 9018 4102
+a 9018 9019 4102
+a 9019 9020 4102
+a 9020 9021 4102
+a 9021 9022 4102
+a 9022 9023 4102
+a 9023 9024 4102
+a 9024 9025 4102
+a 9025 9026 4102
+a 9026 9027 4102
+a 9027 9028 4102
+a 9028 9029 4102
+a 9029 9030 4102
+a 9030 9031 4102
+a 9031 9032 4102
+a 9032 9033 4102
+a 9033 9034 4102
+a 9034 9035 4102
+a 9035 9036 4102
+a 9036 9037 4102
+a 9037 9038 4102
+a 9038 9039 4102
+a 9039 9040 4102
+a 9040 9041 4102
+a 9041 9042 4102
+a 9042 9043 4102
+a 9043 9044 4102
+a 9044 9045 4102
+a 9045 9046 4102
+a 9046 9047 4102
+a 9047 9048 4102
+a 9048 9049 4102
+a 9049 9050 4102
+a 9050 9051 4102
+a 9051 9052 4102
+a 9052 9053 4102
+a 9053 9054 4102
+a 9054 9055 4102
+a 9055 9056 4102
+a 9056 9057 4102
+a 9057 9058 4102
+a 9058 9059 4102
+a 9059 9060 4102
+a 9060 9061 4102
+a 9061 9062 4102
+a 9062 9063 4102
+a 9063 9064 4102
+a 9064 9065 4102
+a 9065 9066 4102
+a 9066 9067 4102
+a 9067 9068 4102
+a 9068 9069 4102
+a 9069 9070 4102
+a 9070 9071 4102
+a 9071 9072 4102
+a 9072 9073 4102
+a 9073 9074 4102
+a 9074 9075 4102
+a 9075 9076 4102
+a 9076 9077 4102
+a 9077 9078 4102
+a 9078 9079 4102
+a 9079 9080 4102
+a 9080 9081 4102
+a 9081 9082 4102
+a 9082 9083 4102
+a 9083 9084 4102
+a 9084 9085 4102
+a 9085 9086 4102
+a 9086 9087 4102
+a 9087 9088 4102
+a 9088 9089 4102
+a 9089 9090 4102
+a 9090 9091 4102
+a 9091 9092 4102
+a 9092 9093 4102
+a 9093 9094 4102
+a 9094 9095 4102
+a 9095 9096 4102
+a 9096 9097 4102
+a 9097 9098 4102
+a 9098 9099 4102
+a 9099 9100 4102
+a 9100 9101 4102
+a 9101 9102 4102
+a 9102 9103 4102
+a 9103 9104 4102
+a 9104 9105 4102
+a 9105 9106 4102
+a 9106 9107 4102
+a 9107 9108 4102
+a 9108 9109 4102
+a 9109 9110 4102
+a 9110 9111 4102
+a 9111 9112 4102
+a 9112 9113 4102
+a 9113 9114 4102
+a 9114 9115 4102
+a 9115 9116 4102
+a 9116 9117 4102
+a 9117 9118 4102
+a 9118 9119 4102
+a 9119 9120 4102
+a 9120 9121 4102
+a 9121 9122 4102
+a 9122 9123 4102
+a 9123 9124 4102
+a 9124 9125 4102
+a 9125 9126 4102
+a 9126 9127 4102
+a 9127 9128 4102
+a 9128 9129 4102
+a 9129 9130 4102
+a 9130 9131 4102
+a 9131 9132 4102
+a 9132 9133 4102
+a 9133 9134 4102
+a 9134 9135 4102
+a 9135 9136 4102
+a 9136 9137 4102
+a 9137 9138 4102
+a 9138 9139 4102
+a 9139 9140 4102
+a 9140 9141 4102
+a 9141 9142 4102
+a 9142 9143 4102
+a 9143 9144 4102
+a 9144 9145 4102
+a 9145 9146 4102
+a 9146 9147 4102
+a 9147 9148 4102
+a 9148 9149 4102
+a 9149 9150 4102
+a 9150 9151 4102
+a 9151 9152 4102
+a 9152 9153 4102
+a 9153 9154 4102
+a 9154 9155 4102
+a 9155 9156 4102
+a 9156 9157 4102
+a 9157 9158 4102
+a 9158 9159 4102
+a 9159 9160 4102
+a 9160 9161 4102
+a 9161 9162 4102
+a 9162 9163 4102
+a 9163 9164 4102
+a 9164 9165 4102
+a 9165 9166 4102
+a 9166 9167 4102
+a 9167 9168 4102
+a 9168 9169 4102
+a 9169 9170 4102
+a 9170 9171 4102
+a 9171 9172 4102
+a 9172 9173 4102
+a 9173 9174 4102
+a 9174 9175 4102
+a 9175 9176 4102
+a 9176 9177 4102
+a 9177 9178 4102
+a 9178 9179 4102
+a 9179 9180 4102
+a 9180 9181 4102
+a 9181 9182 4102
+a 9182 9183 4102
+a 9183 9184 4102
+a 9184 9185 4102
+a 9185 9186 4102
+a 9186 9187 4102
+a 9187 9188 4102
+a 9188 9189 4102
+a 9189 9190 4102
+a 9190 9191 4102
+a 9191 9192 4102
+a 9192 9193 4102
+a 9193 9194 4102
+a 9194 9195 4102
+a 9195 9196 4102
+a 9196 9197 4102
+a 9197 9198 4102
+a 9198 9199 4102
+a 9199 9200 4102
+a 9200 9201 4102
+a 9201 9202 4102
+a 9202 9203 4102
+a 9203 9204 4102
+a 9204 9205 4102
+a 9205 9206 4102
+a 9206 9207 4102
+a 9207 9208 4102
+a 9208 9209 4102
+a 9209 9210 4102
+a 9210 9211 4102
+a 9211 9212 4102
+a 9212 9213 4102
+a 9213 9214 4102
+a 9214 9215 4102
+a 9215 9216 4102
+a 9216 9217 4102
+a 9217 9218 4102
+a 9218 9219 4102
+a 9219 9220 4102
+a 9220 9221 4102
+a 9221 9222 4102
+a 9222 9223 4102
+a 9223 9224 4102
+a 9224 9225 4102
+a 9225 9226 4102
+a 9226 9227 4102
+a 9227 9228 4102
+a 9228 9229 4102
+a 9229 9230 4102
+a 9230 9231 4102
+a 9231 9232 4102
+a 9232 9233 4102
+a 9233 9234 4102
+a 9234 9235 4102
+a 9235 9236 4102
+a 9236 9237 4102
+a 9237 9238 4102
+a 9238 9239 4102
+a 9239 9240 4102
+a 9240 9241 4102
+a 9241 9242 4102
+a 9242 9243 4102
+a 9243 9244 4102
+a 9244 9245 4102
+a 9245 9246 4102
+a 9246 9247 4102
+a 9247 9248 4102
+a 9248 9249 4102
+a 9249 9250 4102
+a 9250 9251 4102
+a 9251 9252 4102
+a 9252 9253 4102
+a 9253 9254 4102
+a 9254 9255 4102
+a 9255 9256 4102
+a 9256 9257 4102
+a 9257 9258 4102
+a 9258 9259 4102
+a 9259 9260 4102
+a 9260 9261 4102
+a 9261 9262 4102
+a 9262 9263 4102
+a 9263 9264 4102
+a 9264 9265 4102
+a 9265 9266 4102
+a 9266 9267 4102
+a 9267 9268 4102
+a 9268 9269 4102
+a 9269 9270 4102
+a 9270 9271 4102
+a 9271 9272 4102
+a 9272 9273 4102
+a 9273 9274 4102
+a 9274 9275 4102
+a 9275 9276 4102
+a 9276 9277 4102
+a 9277 9278 4102
+a 9278 9279 4102
+a 9279 9280 4102
+a 9280 9281 4102
+a 9281 9282 4102
+a 9282 9283 4102
+a 9283 9284 4102
+a 9284 9285 4102
+a 9285 9286 4102
+a 9286 9287 4102
+a 9287 9288 4102
+a 9288 9289 4102
+a 9289 9290 4102
+a 9290 9291 4102
+a 9291 9292 4102
+a 9292 9293 4102
+a 9293 9294 4102
+a 9294 9295 4102
+a 9295 9296 4102
+a 9296 9297 4102
+a 9297 9298 4102
+a 9298 9299 4102
+a 9299 9300 4102
+a 9300 9301 4102
+a 9301 9302 4102
+a 9302 9303 4102
+a 9303 9304 4102
+a 9304 9305 4102
+a 9305 9306 4102
+a 9306 9307 4102
+a 9307 9308 4102
+a 9308 9309 4102
+a 9309 9310 4102
+a 9310 9311 4102
+a 9311 9312 4102
+a 9312 9313 4102
+a 9313 9314 4102
+a 9314 9315 4102
+a 9315 9316 4102
+a 9316 9317 4102
+a 9317 9318 4102
+a 9318 9319 4102
+a 9319 9320 4102
+a 9320 9321 4102
+a 9321 9322 4102
+a 9322 9323 4102
+a 9323 9324 4102
+a 9324 9325 4102
+a 9325 9326 4102
+a 9326 9327 4102
+a 9327 9328 4102
+a 9328 9329 4102
+a 9329 9330 4102
+a 9330 9331 4102
+a 9331 9332 4102
+a 9332 9333 4102
+a 9333 9334 4102
+a 9334 9335 4102
+a 9335 9336 4102
+a 9336 9337 4102
+a 9337 9338 4102
+a 9338 9339 4102
+a 9339 9340 4102
+a 9340 9341 4102
+a 9341 9342 4102
+a 9342 9343 4102
+a 9343 9344 4102
+a 9344 9345 4102
+a 9345 9346 4102
+a 9346 9347 4102
+a 9347 9348 4102
+a 9348 9349 4102
+a 9349 9350 4102
+a 9350 9351 4102
+a 9351 9352 4102
+a 9352 9353 4102
+a 9353 9354 4102
+a 9354 9355 4102
+a 9355 9356 4102
+a 9356 9357 4102
+a 9357 9358 4102
+a 9358 9359 4102
+a 9359 9360 4102
+a 9360 9361 4102
+a 9361 9362 4102
+a 9362 9363 4102
+a 9363 9364 4102
+a 9364 9365 4102
+a 9365 9366 4102
+a 9366 9367 4102
+a 9367 9368 4102
+a 9368 9369 4102
+a 9369 9370 4102
+a 9370 9371 4102
+a 9371 9372 4102
+a 9372 9373 4102
+a 9373 9374 4102
+a 9374 9375 4102
+a 9375 9376 4102
+a 9376 9377 4102
+a 9377 9378 4102
+a 9378 9379 4102
+a 9379 9380 4102
+a 9380 9381 4102
+a 9381 9382 4102
+a 9382 9383 4102
+a 9383 9384 4102
+a 9384 9385 4102
+a 9385 9386 4102
+a 9386 9387 4102
+a 9387 9388 4102
+a 9388 9389 4102
+a 9389 9390 4102
+a 9390 9391 4102
+a 9391 9392 4102
+a 9392 9393 4102
+a 9393 9394 4102
+a 9394 9395 4102
+a 9395 9396 4102
+a 9396 9397 4102
+a 9397 9398 4102
+a 9398 9399 4102
+a 9399 9400 4102
+a 9400 9401 4102
+a 9401 9402 4102
+a 9402 9403 4102
+a 9403 9404 4102
+a 9404 9405 4102
+a 9405 9406 4102
+a 9406 9407 4102
+a 9407 9408 4102
+a 9408 9409 4102
+a 9409 9410 4102
+a 9410 9411 4102
+a 9411 9412 4102
+a 9412 9413 4102
+a 9413 9414 4102
+a 9414 9415 4102
+a 9415 9416 4102
+a 9416 9417 4102
+a 9417 9418 4102
+a 9418 9419 4102
+a 9419 9420 4102
+a 9420 9421 4102
+a 9421 9422 4102
+a 9422 9423 4102
+a 9423 9424 4102
+a 9424 9425 4102
+a 9425 9426 4102
+a 9426 9427 4102
+a 9427 9428 4102
+a 9428 9429 4102
+a 9429 9430 4102
+a 9430 9431 4102
+a 9431 9432 4102
+a 9432 9433 4102
+a 9433 9434 4102
+a 9434 9435 4102
+a 9435 9436 4102
+a 9436 9437 4102
+a 9437 9438 4102
+a 9438 9439 4102
+a 9439 9440 4102
+a 9440 9441 4102
+a 9441 9442 4102
+a 9442 9443 4102
+a 9443 9444 4102
+a 9444 9445 4102
+a 9445 9446 4102
+a 9446 9447 4102
+a 9447 9448 4102
+a 9448 9449 4102
+a 9449 9450 4102
+a 9450 9451 4102
+a 9451 9452 4102
+a 9452 9453 4102
+a 9453 9454 4102
+a 9454 9455 4102
+a 9455 9456 4102
+a 9456 9457 4102
+a 9457 9458 4102
+a 9458 9459 4102
+a 9459 9460 4102
+a 9460 9461 4102
+a 9461 9462 4102
+a 9462 9463 4102
+a 9463 9464 4102
+a 9464 9465 4102
+a 9465 9466 4102
+a 9466 9467 4102
+a 9467 9468 4102
+a 9468 9469 4102
+a 9469 9470 4102
+a 9470 9471 4102
+a 9471 9472 4102
+a 9472 9473 4102
+a 9473 9474 4102
+a 9474 9475 4102
+a 9475 9476 4102
+a 9476 9477 4102
+a 9477 9478 4102
+a 9478 9479 4102
+a 9479 9480 4102
+a 9480 9481 4102
+a 9481 9482 4102
+a 9482 9483 4102
+a 9483 9484 4102
+a 9484 9485 4102
+a 9485 9486 4102
+a 9486 9487 4102
+a 9487 9488 4102
+a 9488 9489 4102
+a 9489 9490 4102
+a 9490 9491 4102
+a 9491 9492 4102
+a 9492 9493 4102
+a 9493 9494 4102
+a 9494 9495 4102
+a 9495 9496 4102
+a 9496 9497 4102
+a 9497 9498 4102
+a 9498 9499 4102
+a 9499 9500 4102
+a 9500 9501 4102
+a 9501 9502 4102
+a 9502 9503 4102
+a 9503 9504 4102
+a 9504 9505 4102
+a 9505 9506 4102
+a 9506 9507 4102
+a 9507 9508 4102
+a 9508 9509 4102
+a 9509 9510 4102
+a 9510 9511 4102
+a 9511 9512 4102
+a 9512 9513 4102
+a 9513 9514 4102
+a 9514 9515 4102
+a 9515 9516 4102
+a 9516 9517 4102
+a 9517 9518 4102
+a 9518 9519 4102
+a 9519 9520 4102
+a 9520 9521 4102
+a 9521 9522 4102
+a 9522 9523 4102
+a 9523 9524 4102
+a 9524 9525 4102
+a 9525 9526 4102
+a 9526 9527 4102
+a 9527 9528 4102
+a 9528 9529 4102
+a 9529 9530 4102
+a 9530 9531 4102
+a 9531 9532 4102
+a 9532 9533 4102
+a 9533 9534 4102
+a 9534 9535 4102
+a 9535 9536 4102
+a 9536 9537 4102
+a 9537 9538 4102
+a 9538 9539 4102
+a 9539 9540 4102
+a 9540 9541 4102
+a 9541 9542 4102
+a 9542 9543 4102
+a 9543 9544 4102
+a 9544 9545 4102
+a 9545 9546 4102
+a 9546 9547 4102
+a 9547 9548 4102
+a 9548 9549 4102
+a 9549 9550 4102
+a 9550 9551 4102
+a 9551 9552 4102
+a 9552 9553 4102
+a 9553 9554 4102
+a 9554 9555 4102
+a 9555 9556 4102
+a 9556 9557 4102
+a 9557 9558 4102
+a 9558 9559 4102
+a 9559 9560 4102
+a 9560 9561 4102
+a 9561 9562 4102
+a 9562 9563 4102
+a 9563 9564 4102
+a 9564 9565 4102
+a 9565 9566 4102
+a 9566 9567 4102
+a 9567 9568 4102
+a 9568 9569 4102
+a 9569 9570 4102
+a 9570 9571 4102
+a 9571 9572 4102
+a 9572 9573 4102
+a 9573 9574 4102
+a 9574 9575 4102
+a 9575 9576 4102
+a 9576 9577 4102
+a 9577 9578 4102
+a 9578 9579 4102
+a 9579 9580 4102
+a 9580 9581 4102
+a 9581 9582 4102
+a 9582 9583 4102
+a 9583 9584 4102
+a 9584 9585 4102
+a 9585 9586 4102
+a 9586 9587 4102
+a 9587 9588 4102
+a 9588 9589 4102
+a 9589 9590 4102
+a 9590 9591 4102
+a 9591 9592 4102
+a 9592 9593 4102
+a 9593 9594 4102
+a 9594 9595 4102
+a 9595 9596 4102
+a 9596 9597 4102
+a 9597 9598 4102
+a 9598 9599 4102
+a 9599 9600 4102
+a 9600 9601 4102
+a 9601 9602 4102
+a 9602 9603 4102
+a 9603 9604 4102
+a 9604 9605 4102
+a 9605 9606 4102
+a 9606 9607 4102
+a 9607 9608 4102
+a 9608 9609 4102
+a 9609 9610 4102
+a 9610 9611 4102
+a 9611 9612 4102
+a 9612 9613 4102
+a 9613 9614 4102
+a 9614 9615 4102
+a 9615 9616 4102
+a 9616 9617 4102
+a 9617 9618 4102
+a 9618 9619 4102
+a 9619 9620 4102
+a 9620 9621 4102
+a 9621 9622 4102
+a 9622 9623 4102
+a 9623 9624 4102
+a 9624 9625 4102
+a 9625 9626 4102
+a 9626 9627 4102
+a 9627 9628 4102
+a 9628 9629 4102
+a 9629 9630 4102
+a 9630 9631 4102
+a 9631 9632 4102
+a 9632 9633 4102
+a 9633 9634 4102
+a 9634 9635 4102
+a 9635 9636 4102
+a 9636 9637 4102
+a 9637 9638 4102
+a 9638 9639 4102
+a 9639 9640 4102
+a 9640 9641 4102
+a 9641 9642 4102
+a 9642 9643 4102
+a 9643 9644 4102
+a 9644 9645 4102
+a 9645 9646 4102
+a 9646 9647 4102
+a 9647 9648 4102
+a 9648 9649 4102
+a 9649 9650 4102
+a 9650 9651 4102
+a 9651 9652 4102
+a 9652 9653 4102
+a 9653 9654 4102
+a 9654 9655 4102
+a 9655 9656 4102
+a 9656 9657 4102
+a 9657 9658 4102
+a 9658 9659 4102
+a 9659 9660 4102
+a 9660 9661 4102
+a 9661 9662 4102
+a 9662 9663 4102
+a 9663 9664 4102
+a 9664 9665 4102
+a 9665 9666 4102
+a 9666 9667 4102
+a 9667 9668 4102
+a 9668 9669 4102
+a 9669 9670 4102
+a 9670 9671 4102
+a 9671 9672 4102
+a 9672 9673 4102
+a 9673 9674 4102
+a 9674 9675 4102
+a 9675 9676 4102
+a 9676 9677 4102
+a 9677 9678 4102
+a 9678 9679 4102
+a 9679 9680 4102
+a 9680 9681 4102
+a 9681 9682 4102
+a 9682 9683 4102
+a 9683 9684 4102
+a 9684 9685 4102
+a 9685 9686 4102
+a 9686 9687 4102
+a 9687 9688 4102
+a 9688 9689 4102
+a 9689 9690 4102
+a 9690 9691 4102
+a 9691 9692 4102
+a 9692 9693 4102
+a 9693 9694 4102
+a 9694 9695 4102
+a 9695 9696 4102
+a 9696 9697 4102
+a 9697 9698 4102
+a 9698 9699 4102
+a 9699 9700 4102
+a 9700 9701 4102
+a 9701 9702 4102
+a 9702 9703 4102
+a 9703 9704 4102
+a 9704 9705 4102
+a 9705 9706 4102
+a 9706 9707 4102
+a 9707 9708 4102
+a 9708 9709 4102
+a 9709 9710 4102
+a 9710 9711 4102
+a 9711 9712 4102
+a 9712 9713 4102
+a 9713 9714 4102
+a 9714 9715 4102
+a 9715 9716 4102
+a 9716 9717 4102
+a 9717 9718 4102
+a 9718 9719 4102
+a 9719 9720 4102
+a 9720 9721 4102
+a 9721 9722 4102
+a 9722 9723 4102
+a 9723 9724 4102
+a 9724 9725 4102
+a 9725 9726 4102
+a 9726 9727 4102
+a 9727 9728 4102
+a 9728 9729 4102
+a 9729 9730 4102
+a 9730 9731 4102
+a 9731 9732 4102
+a 9732 9733 4102
+a 9733 9734 4102
+a 9734 9735 4102
+a 9735 9736 4102
+a 9736 9737 4102
+a 9737 9738 4102
+a 9738 9739 4102
+a 9739 9740 4102
+a 9740 9741 4102
+a 9741 9742 4102
+a 9742 9743 4102
+a 9743 9744 4102
+a 9744 9745 4102
+a 9745 9746 4102
+a 9746 9747 4102
+a 9747 9748 4102
+a 9748 9749 4102
+a 9749 9750 4102
+a 9750 9751 4102
+a 9751 9752 4102
+a 9752 9753 4102
+a 9753 9754 4102
+a 9754 9755 4102
+a 9755 9756 4102
+a 9756 9757 4102
+a 9757 9758 4102
+a 9758 9759 4102
+a 9759 9760 4102
+a 9760 9761 4102
+a 9761 9762 4102
+a 9762 9763 4102
+a 9763 9764 4102
+a 9764 9765 4102
+a 9765 9766 4102
+a 9766 9767 4102
+a 9767 9768 4102
+a 9768 9769 4102
+a 9769 9770 4102
+a 9770 9771 4102
+a 9771 9772 4102
+a 9772 9773 4102
+a 9773 9774 4102
+a 9774 9775 4102
+a 9775 9776 4102
+a 9776 9777 4102
+a 9777 9778 4102
+a 9778 9779 4102
+a 9779 9780 4102
+a 9780 9781 4102
+a 9781 9782 4102
+a 9782 9783 4102
+a 9783 9784 4102
+a 9784 9785 4102
+a 9785 9786 4102
+a 9786 9787 4102
+a 9787 9788 4102
+a 9788 9789 4102
+a 9789 9790 4102
+a 9790 9791 4102
+a 9791 9792 4102
+a 9792 9793 4102
+a 9793 9794 4102
+a 9794 9795 4102
+a 9795 9796 4102
+a 9796 9797 4102
+a 9797 9798 4102
+a 9798 9799 4102
+a 9799 9800 4102
+a 9800 9801 4102
+a 9801 9802 4102
+a 9802 9803 4102
+a 9803 9804 4102
+a 9804 9805 4102
+a 9805 9806 4102
+a 9806 9807 4102
+a 9807 9808 4102
+a 9808 9809 4102
+a 9809 9810 4102
+a 9810 9811 4102
+a 9811 9812 4102
+a 9812 9813 4102
+a 9813 9814 4102
+a 9814 9815 4102
+a 9815 9816 4102
+a 9816 9817 4102
+a 9817 9818 4102
+a 9818 9819 4102
+a 9819 9820 4102
+a 9820 9821 4102
+a 9821 9822 4102
+a 9822 9823 4102
+a 9823 9824 4102
+a 9824 9825 4102
+a 9825 9826 4102
+a 9826 9827 4102
+a 9827 9828 4102
+a 9828 9829 4102
+a 9829 9830 4102
+a 9830 9831 4102
+a 9831 9832 4102
+a 9832 9833 4102
+a 9833 9834 4102
+a 9834 9835 4102
+a 9835 9836 4102
+a 9836 9837 4102
+a 9837 9838 4102
+a 9838 9839 4102
+a 9839 9840 4102
+a 9840 9841 4102
+a 9841 9842 4102
+a 9842 9843 4102
+a 9843 9844 4102
+a 9844 9845 4102
+a 9845 9846 4102
+a 9846 9847 4102
+a 9847 9848 4102
+a 9848 9849 4102
+a 9849 9850 4102
+a 9850 9851 4102
+a 9851 9852 4102
+a 9852 9853 4102
+a 9853 9854 4102
+a 9854 9855 4102
+a 9855 9856 4102
+a 9856 9857 4102
+a 9857 9858 4102
+a 9858 9859 4102
+a 9859 9860 4102
+a 9860 9861 4102
+a 9861 9862 4102
+a 9862 9863 4102
+a 9863 9864 4102
+a 9864 9865 4102
+a 9865 9866 4102
+a 9866 9867 4102
+a 9867 9868 4102
+a 9868 9869 4102
+a 9869 9870 4102
+a 9870 9871 4102
+a 9871 9872 4102
+a 9872 9873 4102
+a 9873 9874 4102
+a 9874 9875 4102
+a 9875 9876 4102
+a 9876 9877 4102
+a 9877 9878 4102
+a 9878 9879 4102
+a 9879 9880 4102
+a 9880 9881 4102
+a 9881 9882 4102
+a 9882 9883 4102
+a 9883 9884 4102
+a 9884 9885 4102
+a 9885 9886 4102
+a 9886 9887 4102
+a 9887 9888 4102
+a 9888 9889 4102
+a 9889 9890 4102
+a 9890 9891 4102
+a 9891 9892 4102
+a 9892 9893 4102
+a 9893 9894 4102
+a 9894 9895 4102
+a 9895 9896 4102
+a 9896 9897 4102
+a 9897 9898 4102
+a 9898 9899 4102
+a 9899 9900 4102
+a 9900 9901 4102
+a 9901 9902 4102
+a 9902 9903 4102
+a 9903 9904 4102
+a 9904 9905 4102
+a 9905 9906 4102
+a 9906 9907 4102
+a 9907 9908 4102
+a 9908 9909 4102
+a 9909 9910 4102
+a 9910 9911 4102
+a 9911 9912 4102
+a 9912 9913 4102
+a 9913 9914 4102
+a 9914 9915 4102
+a 9915 9916 4102
+a 9916 9917 4102
+a 9917 9918 4102
+a 9918 9919 4102
+a 9919 9920 4102
+a 9920 9921 4102
+a 9921 9922 4102
+a 9922 9923 4102
+a 9923 9924 4102
+a 9924 9925 4102
+a 9925 9926 4102
+a 9926 9927 4102
+a 9927 9928 4102
+a 9928 9929 4102
+a 9929 9930 4102
+a 9930 9931 4102
+a 9931 9932 4102
+a 9932 9933 4102
+a 9933 9934 4102
+a 9934 9935 4102
+a 9935 9936 4102
+a 9936 9937 4102
+a 9937 9938 4102
+a 9938 9939 4102
+a 9939 9940 4102
+a 9940 9941 4102
+a 9941 9942 4102
+a 9942 9943 4102
+a 9943 9944 4102
+a 9944 9945 4102
+a 9945 9946 4102
+a 9946 9947 4102
+a 9947 9948 4102
+a 9948 9949 4102
+a 9949 9950 4102
+a 9950 9951 4102
+a 9951 9952 4102
+a 9952 9953 4102
+a 9953 9954 4102
+a 9954 9955 4102
+a 9955 9956 4102
+a 9956 9957 4102
+a 9957 9958 4102
+a 9958 9959 4102
+a 9959 9960 4102
+a 9960 9961 4102
+a 9961 9962 4102
+a 9962 9963 4102
+a 9963 9964 4102
+a 9964 9965 4102
+a 9965 9966 4102
+a 9966 9967 4102
+a 9967 9968 4102
+a 9968 9969 4102
+a 9969 9970 4102
+a 9970 9971 4102
+a 9971 9972 4102
+a 9972 9973 4102
+a 9973 9974 4102
+a 9974 9975 4102
+a 9975 9976 4102
+a 9976 9977 4102
+a 9977 9978 4102
+a 9978 9979 4102
+a 9979 9980 4102
+a 9980 9981 4102
+a 9981 9982 4102
+a 9982 9983 4102
+a 9983 9984 4102
+a 9984 9985 4102
+a 9985 9986 4102
+a 9986 9987 4102
+a 9987 9988 4102
+a 9988 9989 4102
+a 9989 9990 4102
+a 9990 9991 4102
+a 9991 9992 4102
+a 9992 9993 4102
+a 9993 9994 4102
+a 9994 9995 4102
+a 9995 9996 4102
+a 9996 9997 4102
+a 9997 9998 4102
+a 9998 9999 4102
+a 9999 10000 4102
+a 10000 10001 4102
+a 10001 10002 4102
+a 10002 10003 4102
+a 10003 10004 4102
+a 10004 10005 4102
+a 10005 10006 4102
+a 10006 10007 4102
+a 10007 10008 4102
+a 10008 10009 4102
+a 10009 10010 4102
+a 10010 10011 4102
+a 10011 10012 4102
+a 10012 10013 4102
+a 10013 10014 4102
+a 10014 10015 4102
+a 10015 10016 4102
+a 10016 10017 4102
+a 10017 10018 4102
+a 10018 10019 4102
+a 10019 10020 4102
+a 10020 10021 4102
+a 10021 10022 4102
+a 10022 10023 4102
+a 10023 10024 4102
+a 10024 10025 4102
+a 10025 10026 4102
+a 10026 10027 4102
+a 10027 10028 4102
+a 10028 10029 4102
+a 10029 10030 4102
+a 10030 10031 4102
+a 10031 10032 4102
+a 10032 10033 4102
+a 10033 10034 4102
+a 10034 10035 4102
+a 10035 10036 4102
+a 10036 10037 4102
+a 10037 10038 4102
+a 10038 10039 4102
+a 10039 10040 4102
+a 10040 10041 4102
+a 10041 10042 4102
+a 10042 10043 4102
+a 10043 10044 4102
+a 10044 10045 4102
+a 10045 10046 4102
+a 10046 10047 4102
+a 10047 10048 4102
+a 10048 10049 4102
+a 10049 10050 4102
+a 10050 10051 4102
+a 10051 10052 4102
+a 10052 10053 4102
+a 10053 10054 4102
+a 10054 10055 4102
+a 10055 10056 4102
+a 10056 10057 4102
+a 10057 10058 4102
+a 10058 10059 4102
+a 10059 10060 4102
+a 10060 10061 4102
+a 10061 10062 4102
+a 10062 10063 4102
+a 10063 10064 4102
+a 10064 10065 4102
+a 10065 10066 4102
+a 10066 10067 4102
+a 10067 10068 4102
+a 10068 10069 4102
+a 10069 10070 4102
+a 10070 10071 4102
+a 10071 10072 4102
+a 10072 10073 4102
+a 10073 10074 4102
+a 10074 10075 4102
+a 10075 10076 4102
+a 10076 10077 4102
+a 10077 10078 4102
+a 10078 10079 4102
+a 10079 10080 4102
+a 10080 10081 4102
+a 10081 10082 4102
+a 10082 10083 4102
+a 10083 10084 4102
+a 10084 10085 4102
+a 10085 10086 4102
+a 10086 10087 4102
+a 10087 10088 4102
+a 10088 10089 4102
+a 10089 10090 4102
+a 10090 10091 4102
+a 10091 10092 4102
+a 10092 10093 4102
+a 10093 10094 4102
+a 10094 10095 4102
+a 10095 10096 4102
+a 10096 10097 4102
+a 10097 10098 4102
+a 10098 10099 4102
+a 10099 10100 4102
+a 10100 10101 4102
+a 10101 10102 4102
+a 10102 10103 4102
+a 10103 10104 4102
+a 10104 10105 4102
+a 10105 10106 4102
+a 10106 10107 4102
+a 10107 10108 4102
+a 10108 10109 4102
+a 10109 10110 4102
+a 10110 10111 4102
+a 10111 10112 4102
+a 10112 10113 4102
+a 10113 10114 4102
+a 10114 10115 4102
+a 10115 10116 4102
+a 10116 10117 4102
+a 10117 10118 4102
+a 10118 10119 4102
+a 10119 10120 4102
+a 10120 10121 4102
+a 10121 10122 4102
+a 10122 10123 4102
+a 10123 10124 4102
+a 10124 10125 4102
+a 10125 10126 4102
+a 10126 10127 4102
+a 10127 10128 4102
+a 10128 10129 4102
+a 10129 10130 4102
+a 10130 10131 4102
+a 10131 10132 4102
+a 10132 10133 4102
+a 10133 10134 4102
+a 10134 10135 4102
+a 10135 10136 4102
+a 10136 10137 4102
+a 10137 10138 4102
+a 10138 10139 4102
+a 10139 10140 4102
+a 10140 10141 4102
+a 10141 10142 4102
+a 10142 10143 4102
+a 10143 10144 4102
+a 10144 10145 4102
+a 10145 10146 4102
+a 10146 10147 4102
+a 10147 10148 4102
+a 10148 10149 4102
+a 10149 10150 4102
+a 10150 10151 4102
+a 10151 10152 4102
+a 10152 10153 4102
+a 10153 10154 4102
+a 10154 10155 4102
+a 10155 10156 4102
+a 10156 10157 4102
+a 10157 10158 4102
+a 10158 10159 4102
+a 10159 10160 4102
+a 10160 10161 4102
+a 10161 10162 4102
+a 10162 10163 4102
+a 10163 10164 4102
+a 10164 10165 4102
+a 10165 10166 4102
+a 10166 10167 4102
+a 10167 10168 4102
+a 10168 10169 4102
+a 10169 10170 4102
+a 10170 10171 4102
+a 10171 10172 4102
+a 10172 10173 4102
+a 10173 10174 4102
+a 10174 10175 4102
+a 10175 10176 4102
+a 10176 10177 4102
+a 10177 10178 4102
+a 10178 10179 4102
+a 10179 10180 4102
+a 10180 10181 4102
+a 10181 10182 4102
+a 10182 10183 4102
+a 10183 10184 4102
+a 10184 10185 4102
+a 10185 10186 4102
+a 10186 10187 4102
+a 10187 10188 4102
+a 10188 10189 4102
+a 10189 10190 4102
+a 10190 10191 4102
+a 10191 10192 4102
+a 10192 10193 4102
+a 10193 10194 4102
+a 10194 10195 4102
+a 10195 10196 4102
+a 10196 10197 4102
+a 10197 10198 4102
+a 10198 10199 4102
+a 10199 10200 4102
+a 10200 10201 4102
+a 10201 10202 4102
+a 10202 10203 4102
+a 10203 10204 4102
+a 10204 10205 4102
+a 10205 10206 4102
+a 10206 10207 4102
+a 10207 10208 4102
+a 10208 10209 4102
+a 10209 10210 4102
+a 10210 10211 4102
+a 10211 10212 4102
+a 10212 10213 4102
+a 10213 10214 4102
+a 10214 10215 4102
+a 10215 10216 4102
+a 10216 10217 4102
+a 10217 10218 4102
+a 10218 10219 4102
+a 10219 10220 4102
+a 10220 10221 4102
+a 10221 10222 4102
+a 10222 10223 4102
+a 10223 10224 4102
+a 10224 10225 4102
+a 10225 10226 4102
+a 10226 10227 4102
+a 10227 10228 4102
+a 10228 10229 4102
+a 10229 10230 4102
+a 10230 10231 4102
+a 10231 10232 4102
+a 10232 10233 4102
+a 10233 10234 4102
+a 10234 10235 4102
+a 10235 10236 4102
+a 10236 10237 4102
+a 10237 10238 4102
+a 10238 10239 4102
+a 10239 10240 4102
+a 10240 10241 4102
+a 10241 10242 4102
+a 10242 10243 4102
+a 10243 10244 4102
+a 10244 10245 4102
+a 10245 10246 4102
+a 10246 10247 4102
+a 10247 10248 4102
+a 10248 10249 4102
+a 10249 10250 4102
+a 10250 10251 4102
+a 10251 10252 4102
+a 10252 10253 4102
+a 10253 10254 4102
+a 10254 10255 4102
+a 10255 10256 4102
+a 10256 10257 4102
+a 10257 10258 4102
+a 10258 10259 4102
+a 10259 10260 4102
+a 10260 10261 4102
+a 10261 10262 4102
+a 10262 10263 4102
+a 10263 10264 4102
+a 10264 10265 4102
+a 10265 10266 4102
+a 10266 10267 4102
+a 10267 10268 4102
+a 10268 10269 4102
+a 10269 10270 4102
+a 10270 10271 4102
+a 10271 10272 4102
+a 10272 10273 4102
+a 10273 10274 4102
+a 10274 10275 4102
+a 10275 10276 4102
+a 10276 10277 4102
+a 10277 10278 4102
+a 10278 10279 4102
+a 10279 10280 4102
+a 10280 10281 4102
+a 10281 10282 4102
+a 10282 10283 4102
+a 10283 10284 4102
+a 10284 10285 4102
+a 10285 10286 4102
+a 10286 10287 4102
+a 10287 10288 4102
+a 10288 10289 4102
+a 10289 10290 4102
+a 10290 10291 4102
+a 10291 10292 4102
+a 10292 10293 4102
+a 10293 10294 4102
+a 10294 10295 4102
+a 10295 10296 4102
+a 10296 10297 4102
+a 10297 10298 4102
+a 10298 10299 4102
+a 10299 10300 4102
+a 10300 10301 4102
+a 10301 10302 4102
+a 10302 10303 4102
+a 10303 10304 4102
+a 10304 10305 4102
+a 10305 10306 4102
+a 10306 10307 4102
+a 10307 10308 4102
+a 10308 10309 4102
+a 10309 10310 4102
+a 10310 10311 4102
+a 10311 10312 4102
+a 10312 10313 4102
+a 10313 10314 4102
+a 10314 10315 4102
+a 10315 10316 4102
+a 10316 10317 4102
+a 10317 10318 4102
+a 10318 10319 4102
+a 10319 10320 4102
+a 10320 10321 4102
+a 10321 10322 4102
+a 10322 10323 4102
+a 10323 10324 4102
+a 10324 10325 4102
+a 10325 10326 4102
+a 10326 10327 4102
+a 10327 10328 4102
+a 10328 10329 4102
+a 10329 10330 4102
+a 10330 10331 4102
+a 10331 10332 4102
+a 10332 10333 4102
+a 10333 10334 4102
+a 10334 10335 4102
+a 10335 10336 4102
+a 10336 10337 4102
+a 10337 10338 4102
+a 10338 10339 4102
+a 10339 10340 4102
+a 10340 10341 4102
+a 10341 10342 4102
+a 10342 10343 4102
+a 10343 10344 4102
+a 10344 10345 4102
+a 10345 10346 4102
+a 10346 10347 4102
+a 10347 10348 4102
+a 10348 10349 4102
+a 10349 10350 4102
+a 10350 10351 4102
+a 10351 10352 4102
+a 10352 10353 4102
+a 10353 10354 4102
+a 10354 10355 4102
+a 10355 10356 4102
+a 10356 10357 4102
+a 10357 10358 4102
+a 10358 10359 4102
+a 10359 10360 4102
+a 10360 10361 4102
+a 10361 10362 4102
+a 10362 10363 4102
+a 10363 10364 4102
+a 10364 10365 4102
+a 10365 10366 4102
+a 10366 10367 4102
+a 10367 10368 4102
+a 10368 10369 4102
+a 10369 10370 4102
+a 10370 10371 4102
+a 10371 10372 4102
+a 10372 10373 4102
+a 10373 10374 4102
+a 10374 10375 4102
+a 10375 10376 4102
+a 10376 10377 4102
+a 10377 10378 4102
+a 10378 10379 4102
+a 10379 10380 4102
+a 10380 10381 4102
+a 10381 10382 4102
+a 10382 10383 4102
+a 10383 10384 4102
+a 10384 10385 4102
+a 10385 10386 4102
+a 10386 10387 4102
+a 10387 10388 4102
+a 10388 10389 4102
+a 10389 10390 4102
+a 10390 10391 4102
+a 10391 10392 4102
+a 10392 10393 4102
+a 10393 10394 4102
+a 10394 10395 4102
+a 10395 10396 4102
+a 10396 10397 4102
+a 10397 10398 4102
+a 10398 10399 4102
+a 10399 10400 4102
+a 10400 10401 4102
+a 10401 10402 4102
+a 10402 10403 4102
+a 10403 10404 4102
+a 10404 10405 4102
+a 10405 10406 4102
+a 10406 10407 4102
+a 10407 10408 4102
+a 10408 10409 4102
+a 10409 10410 4102
+a 10410 10411 4102
+a 10411 10412 4102
+a 10412 10413 4102
+a 10413 10414 4102
+a 10414 10415 4102
+a 10415 10416 4102
+a 10416 10417 4102
+a 10417 10418 4102
+a 10418 10419 4102
+a 10419 10420 4102
+a 10420 10421 4102
+a 10421 10422 4102
+a 10422 10423 4102
+a 10423 10424 4102
+a 10424 10425 4102
+a 10425 10426 4102
+a 10426 10427 4102
+a 10427 10428 4102
+a 10428 10429 4102
+a 10429 10430 4102
+a 10430 10431 4102
+a 10431 10432 4102
+a 10432 10433 4102
+a 10433 10434 4102
+a 10434 10435 4102
+a 10435 10436 4102
+a 10436 10437 4102
+a 10437 10438 4102
+a 10438 10439 4102
+a 10439 10440 4102
+a 10440 10441 4102
+a 10441 10442 4102
+a 10442 10443 4102
+a 10443 10444 4102
+a 10444 10445 4102
+a 10445 10446 4102
+a 10446 10447 4102
+a 10447 10448 4102
+a 10448 10449 4102
+a 10449 10450 4102
+a 10450 10451 4102
+a 10451 10452 4102
+a 10452 10453 4102
+a 10453 10454 4102
+a 10454 10455 4102
+a 10455 10456 4102
+a 10456 10457 4102
+a 10457 10458 4102
+a 10458 10459 4102
+a 10459 10460 4102
+a 10460 10461 4102
+a 10461 10462 4102
+a 10462 10463 4102
+a 10463 10464 4102
+a 10464 10465 4102
+a 10465 10466 4102
+a 10466 10467 4102
+a 10467 10468 4102
+a 10468 10469 4102
+a 10469 10470 4102
+a 10470 10471 4102
+a 10471 10472 4102
+a 10472 10473 4102
+a 10473 10474 4102
+a 10474 10475 4102
+a 10475 10476 4102
+a 10476 10477 4102
+a 10477 10478 4102
+a 10478 10479 4102
+a 10479 10480 4102
+a 10480 10481 4102
+a 10481 10482 4102
+a 10482 10483 4102
+a 10483 10484 4102
+a 10484 10485 4102
+a 10485 10486 4102
+a 10486 10487 4102
+a 10487 10488 4102
+a 10488 10489 4102
+a 10489 10490 4102
+a 10490 10491 4102
+a 10491 10492 4102
+a 10492 10493 4102
+a 10493 10494 4102
+a 10494 10495 4102
+a 10495 10496 4102
+a 10496 10497 4102
+a 10497 10498 4102
+a 10498 10499 4102
+a 10499 10500 4102
+a 10500 10501 4102
+a 10501 10502 4102
+a 10502 10503 4102
+a 10503 10504 4102
+a 10504 10505 4102
+a 10505 10506 4102
+a 10506 10507 4102
+a 10507 10508 4102
+a 10508 10509 4102
+a 10509 10510 4102
+a 10510 10511 4102
+a 10511 10512 4102
+a 10512 10513 4102
+a 10513 10514 4102
+a 10514 10515 4102
+a 10515 10516 4102
+a 10516 10517 4102
+a 10517 10518 4102
+a 10518 10519 4102
+a 10519 10520 4102
+a 10520 10521 4102
+a 10521 10522 4102
+a 10522 10523 4102
+a 10523 10524 4102
+a 10524 10525 4102
+a 10525 10526 4102
+a 10526 10527 4102
+a 10527 10528 4102
+a 10528 10529 4102
+a 10529 10530 4102
+a 10530 10531 4102
+a 10531 10532 4102
+a 10532 10533 4102
+a 10533 10534 4102
+a 10534 10535 4102
+a 10535 10536 4102
+a 10536 10537 4102
+a 10537 10538 4102
+a 10538 10539 4102
+a 10539 10540 4102
+a 10540 10541 4102
+a 10541 10542 4102
+a 10542 10543 4102
+a 10543 10544 4102
+a 10544 10545 4102
+a 10545 10546 4102
+a 10546 10547 4102
+a 10547 10548 4102
+a 10548 10549 4102
+a 10549 10550 4102
+a 10550 10551 4102
+a 10551 10552 4102
+a 10552 10553 4102
+a 10553 10554 4102
+a 10554 10555 4102
+a 10555 10556 4102
+a 10556 10557 4102
+a 10557 10558 4102
+a 10558 10559 4102
+a 10559 10560 4102
+a 10560 10561 4102
+a 10561 10562 4102
+a 10562 10563 4102
+a 10563 10564 4102
+a 10564 10565 4102
+a 10565 10566 4102
+a 10566 10567 4102
+a 10567 10568 4102
+a 10568 10569 4102
+a 10569 10570 4102
+a 10570 10571 4102
+a 10571 10572 4102
+a 10572 10573 4102
+a 10573 10574 4102
+a 10574 10575 4102
+a 10575 10576 4102
+a 10576 10577 4102
+a 10577 10578 4102
+a 10578 10579 4102
+a 10579 10580 4102
+a 10580 10581 4102
+a 10581 10582 4102
+a 10582 10583 4102
+a 10583 10584 4102
+a 10584 10585 4102
+a 10585 10586 4102
+a 10586 10587 4102
+a 10587 10588 4102
+a 10588 10589 4102
+a 10589 10590 4102
+a 10590 10591 4102
+a 10591 10592 4102
+a 10592 10593 4102
+a 10593 10594 4102
+a 10594 10595 4102
+a 10595 10596 4102
+a 10596 10597 4102
+a 10597 10598 4102
+a 10598 10599 4102
+a 10599 10600 4102
+a 10600 10601 4102
+a 10601 10602 4102
+a 10602 10603 4102
+a 10603 10604 4102
+a 10604 10605 4102
+a 10605 10606 4102
+a 10606 10607 4102
+a 10607 10608 4102
+a 10608 10609 4102
+a 10609 10610 4102
+a 10610 10611 4102
+a 10611 10612 4102
+a 10612 10613 4102
+a 10613 10614 4102
+a 10614 10615 4102
+a 10615 10616 4102
+a 10616 10617 4102
+a 10617 10618 4102
+a 10618 10619 4102
+a 10619 10620 4102
+a 10620 10621 4102
+a 10621 10622 4102
+a 10622 10623 4102
+a 10623 10624 4102
+a 10624 10625 4102
+a 10625 10626 4102
+a 10626 10627 4102
+a 10627 10628 4102
+a 10628 10629 4102
+a 10629 10630 4102
+a 10630 10631 4102
+a 10631 10632 4102
+a 10632 10633 4102
+a 10633 10634 4102
+a 10634 10635 4102
+a 10635 10636 4102
+a 10636 10637 4102
+a 10637 10638 4102
+a 10638 10639 4102
+a 10639 10640 4102
+a 10640 10641 4102
+a 10641 10642 4102
+a 10642 10643 4102
+a 10643 10644 4102
+a 10644 10645 4102
+a 10645 10646 4102
+a 10646 10647 4102
+a 10647 10648 4102
+a 10648 10649 4102
+a 10649 10650 4102
+a 10650 10651 4102
+a 10651 10652 4102
+a 10652 10653 4102
+a 10653 10654 4102
+a 10654 10655 4102
+a 10655 10656 4102
+a 10656 10657 4102
+a 10657 10658 4102
+a 10658 10659 4102
+a 10659 10660 4102
+a 10660 10661 4102
+a 10661 10662 4102
+a 10662 10663 4102
+a 10663 10664 4102
+a 10664 10665 4102
+a 10665 10666 4102
+a 10666 10667 4102
+a 10667 10668 4102
+a 10668 10669 4102
+a 10669 10670 4102
+a 10670 10671 4102
+a 10671 10672 4102
+a 10672 10673 4102
+a 10673 10674 4102
+a 10674 10675 4102
+a 10675 10676 4102
+a 10676 10677 4102
+a 10677 10678 4102
+a 10678 10679 4102
+a 10679 10680 4102
+a 10680 10681 4102
+a 10681 10682 4102
+a 10682 10683 4102
+a 10683 10684 4102
+a 10684 10685 4102
+a 10685 10686 4102
+a 10686 10687 4102
+a 10687 10688 4102
+a 10688 10689 4102
+a 10689 10690 4102
+a 10690 10691 4102
+a 10691 10692 4102
+a 10692 10693 4102
+a 10693 10694 4102
+a 10694 10695 4102
+a 10695 10696 4102
+a 10696 10697 4102
+a 10697 10698 4102
+a 10698 10699 4102
+a 10699 10700 4102
+a 10700 10701 4102
+a 10701 10702 4102
+a 10702 10703 4102
+a 10703 10704 4102
+a 10704 10705 4102
+a 10705 10706 4102
+a 10706 10707 4102
+a 10707 10708 4102
+a 10708 10709 4102
+a 10709 10710 4102
+a 10710 10711 4102
+a 10711 10712 4102
+a 10712 10713 4102
+a 10713 10714 4102
+a 10714 10715 4102
+a 10715 10716 4102
+a 10716 10717 4102
+a 10717 10718 4102
+a 10718 10719 4102
+a 10719 10720 4102
+a 10720 10721 4102
+a 10721 10722 4102
+a 10722 10723 4102
+a 10723 10724 4102
+a 10724 10725 4102
+a 10725 10726 4102
+a 10726 10727 4102
+a 10727 10728 4102
+a 10728 10729 4102
+a 10729 10730 4102
+a 10730 10731 4102
+a 10731 10732 4102
+a 10732 10733 4102
+a 10733 10734 4102
+a 10734 10735 4102
+a 10735 10736 4102
+a 10736 10737 4102
+a 10737 10738 4102
+a 10738 10739 4102
+a 10739 10740 4102
+a 10740 10741 4102
+a 10741 10742 4102
+a 10742 10743 4102
+a 10743 10744 4102
+a 10744 10745 4102
+a 10745 10746 4102
+a 10746 10747 4102
+a 10747 10748 4102
+a 10748 10749 4102
+a 10749 10750 4102
+a 10750 10751 4102
+a 10751 10752 4102
+a 10752 10753 4102
+a 10753 10754 4102
+a 10754 10755 4102
+a 10755 10756 4102
+a 10756 10757 4102
+a 10757 10758 4102
+a 10758 10759 4102
+a 10759 10760 4102
+a 10760 10761 4102
+a 10761 10762 4102
+a 10762 10763 4102
+a 10763 10764 4102
+a 10764 10765 4102
+a 10765 10766 4102
+a 10766 10767 4102
+a 10767 10768 4102
+a 10768 10769 4102
+a 10769 10770 4102
+a 10770 10771 4102
+a 10771 10772 4102
+a 10772 10773 4102
+a 10773 10774 4102
+a 10774 10775 4102
+a 10775 10776 4102
+a 10776 10777 4102
+a 10777 10778 4102
+a 10778 10779 4102
+a 10779 10780 4102
+a 10780 10781 4102
+a 10781 10782 4102
+a 10782 10783 4102
+a 10783 10784 4102
+a 10784 10785 4102
+a 10785 10786 4102
+a 10786 10787 4102
+a 10787 10788 4102
+a 10788 10789 4102
+a 10789 10790 4102
+a 10790 10791 4102
+a 10791 10792 4102
+a 10792 10793 4102
+a 10793 10794 4102
+a 10794 10795 4102
+a 10795 10796 4102
+a 10796 10797 4102
+a 10797 10798 4102
+a 10798 10799 4102
+a 10799 10800 4102
+a 10800 10801 4102
+a 10801 10802 4102
+a 10802 10803 4102
+a 10803 10804 4102
+a 10804 10805 4102
+a 10805 10806 4102
+a 10806 10807 4102
+a 10807 10808 4102
+a 10808 10809 4102
+a 10809 10810 4102
+a 10810 10811 4102
+a 10811 10812 4102
+a 10812 10813 4102
+a 10813 10814 4102
+a 10814 10815 4102
+a 10815 10816 4102
+a 10816 10817 4102
+a 10817 10818 4102
+a 10818 10819 4102
+a 10819 10820 4102
+a 10820 10821 4102
+a 10821 10822 4102
+a 10822 10823 4102
+a 10823 10824 4102
+a 10824 10825 4102
+a 10825 10826 4102
+a 10826 10827 4102
+a 10827 10828 4102
+a 10828 10829 4102
+a 10829 10830 4102
+a 10830 10831 4102
+a 10831 10832 4102
+a 10832 10833 4102
+a 10833 10834 4102
+a 10834 10835 4102
+a 10835 10836 4102
+a 10836 10837 4102
+a 10837 10838 4102
+a 10838 10839 4102
+a 10839 10840 4102
+a 10840 10841 4102
+a 10841 10842 4102
+a 10842 10843 4102
+a 10843 10844 4102
+a 10844 10845 4102
+a 10845 10846 4102
+a 10846 10847 4102
+a 10847 10848 4102
+a 10848 10849 4102
+a 10849 10850 4102
+a 10850 10851 4102
+a 10851 10852 4102
+a 10852 10853 4102
+a 10853 10854 4102
+a 10854 10855 4102
+a 10855 10856 4102
+a 10856 10857 4102
+a 10857 10858 4102
+a 10858 10859 4102
+a 10859 10860 4102
+a 10860 10861 4102
+a 10861 10862 4102
+a 10862 10863 4102
+a 10863 10864 4102
+a 10864 10865 4102
+a 10865 10866 4102
+a 10866 10867 4102
+a 10867 10868 4102
+a 10868 10869 4102
+a 10869 10870 4102
+a 10870 10871 4102
+a 10871 10872 4102
+a 10872 10873 4102
+a 10873 10874 4102
+a 10874 10875 4102
+a 10875 10876 4102
+a 10876 10877 4102
+a 10877 10878 4102
+a 10878 10879 4102
+a 10879 10880 4102
+a 10880 10881 4102
+a 10881 10882 4102
+a 10882 10883 4102
+a 10883 10884 4102
+a 10884 10885 4102
+a 10885 10886 4102
+a 10886 10887 4102
+a 10887 10888 4102
+a 10888 10889 4102
+a 10889 10890 4102
+a 10890 10891 4102
+a 10891 10892 4102
+a 10892 10893 4102
+a 10893 10894 4102
+a 10894 10895 4102
+a 10895 10896 4102
+a 10896 10897 4102
+a 10897 10898 4102
+a 10898 10899 4102
+a 10899 10900 4102
+a 10900 10901 4102
+a 10901 10902 4102
+a 10902 10903 4102
+a 10903 10904 4102
+a 10904 10905 4102
+a 10905 10906 4102
+a 10906 10907 4102
+a 10907 10908 4102
+a 10908 10909 4102
+a 10909 10910 4102
+a 10910 10911 4102
+a 10911 10912 4102
+a 10912 10913 4102
+a 10913 10914 4102
+a 10914 10915 4102
+a 10915 10916 4102
+a 10916 10917 4102
+a 10917 10918 4102
+a 10918 10919 4102
+a 10919 10920 4102
+a 10920 10921 4102
+a 10921 10922 4102
+a 10922 10923 4102
+a 10923 10924 4102
+a 10924 10925 4102
+a 10925 10926 4102
+a 10926 10927 4102
+a 10927 10928 4102
+a 10928 10929 4102
+a 10929 10930 4102
+a 10930 10931 4102
+a 10931 10932 4102
+a 10932 10933 4102
+a 10933 10934 4102
+a 10934 10935 4102
+a 10935 10936 4102
+a 10936 10937 4102
+a 10937 10938 4102
+a 10938 10939 4102
+a 10939 10940 4102
+a 10940 10941 4102
+a 10941 10942 4102
+a 10942 10943 4102
+a 10943 10944 4102
+a 10944 10945 4102
+a 10945 10946 4102
+a 10946 10947 4102
+a 10947 10948 4102
+a 10948 10949 4102
+a 10949 10950 4102
+a 10950 10951 4102
+a 10951 10952 4102
+a 10952 10953 4102
+a 10953 10954 4102
+a 10954 10955 4102
+a 10955 10956 4102
+a 10956 10957 4102
+a 10957 10958 4102
+a 10958 10959 4102
+a 10959 10960 4102
+a 10960 10961 4102
+a 10961 10962 4102
+a 10962 10963 4102
+a 10963 10964 4102
+a 10964 10965 4102
+a 10965 10966 4102
+a 10966 10967 4102
+a 10967 10968 4102
+a 10968 10969 4102
+a 10969 10970 4102
+a 10970 10971 4102
+a 10971 10972 4102
+a 10972 10973 4102
+a 10973 10974 4102
+a 10974 10975 4102
+a 10975 10976 4102
+a 10976 10977 4102
+a 10977 10978 4102
+a 10978 10979 4102
+a 10979 10980 4102
+a 10980 10981 4102
+a 10981 10982 4102
+a 10982 10983 4102
+a 10983 10984 4102
+a 10984 10985 4102
+a 10985 10986 4102
+a 10986 10987 4102
+a 10987 10988 4102
+a 10988 10989 4102
+a 10989 10990 4102
+a 10990 10991 4102
+a 10991 10992 4102
+a 10992 10993 4102
+a 10993 10994 4102
+a 10994 10995 4102
+a 10995 10996 4102
+a 10996 10997 4102
+a 10997 10998 4102
+a 10998 10999 4102
+a 10999 11000 4102
+a 11000 11001 4102
+a 11001 11002 4102
+a 11002 11003 4102
+a 11003 11004 4102
+a 11004 11005 4102
+a 11005 11006 4102
+a 11006 11007 4102
+a 11007 11008 4102
+a 11008 11009 4102
+a 11009 11010 4102
+a 11010 11011 4102
+a 11011 11012 4102
+a 11012 11013 4102
+a 11013 11014 4102
+a 11014 11015 4102
+a 11015 11016 4102
+a 11016 11017 4102
+a 11017 11018 4102
+a 11018 11019 4102
+a 11019 11020 4102
+a 11020 11021 4102
+a 11021 11022 4102
+a 11022 11023 4102
+a 11023 11024 4102
+a 11024 11025 4102
+a 11025 11026 4102
+a 11026 11027 4102
+a 11027 11028 4102
+a 11028 11029 4102
+a 11029 11030 4102
+a 11030 11031 4102
+a 11031 11032 4102
+a 11032 11033 4102
+a 11033 11034 4102
+a 11034 11035 4102
+a 11035 11036 4102
+a 11036 11037 4102
+a 11037 11038 4102
+a 11038 11039 4102
+a 11039 11040 4102
+a 11040 11041 4102
+a 11041 11042 4102
+a 11042 11043 4102
+a 11043 11044 4102
+a 11044 11045 4102
+a 11045 11046 4102
+a 11046 11047 4102
+a 11047 11048 4102
+a 11048 11049 4102
+a 11049 11050 4102
+a 11050 11051 4102
+a 11051 11052 4102
+a 11052 11053 4102
+a 11053 11054 4102
+a 11054 11055 4102
+a 11055 11056 4102
+a 11056 11057 4102
+a 11057 11058 4102
+a 11058 11059 4102
+a 11059 11060 4102
+a 11060 11061 4102
+a 11061 11062 4102
+a 11062 11063 4102
+a 11063 11064 4102
+a 11064 11065 4102
+a 11065 11066 4102
+a 11066 11067 4102
+a 11067 11068 4102
+a 11068 11069 4102
+a 11069 11070 4102
+a 11070 11071 4102
+a 11071 11072 4102
+a 11072 11073 4102
+a 11073 11074 4102
+a 11074 11075 4102
+a 11075 11076 4102
+a 11076 11077 4102
+a 11077 11078 4102
+a 11078 11079 4102
+a 11079 11080 4102
+a 11080 11081 4102
+a 11081 11082 4102
+a 11082 11083 4102
+a 11083 11084 4102
+a 11084 11085 4102
+a 11085 11086 4102
+a 11086 11087 4102
+a 11087 11088 4102
+a 11088 11089 4102
+a 11089 11090 4102
+a 11090 11091 4102
+a 11091 11092 4102
+a 11092 11093 4102
+a 11093 11094 4102
+a 11094 11095 4102
+a 11095 11096 4102
+a 11096 11097 4102
+a 11097 11098 4102
+a 11098 11099 4102
+a 11099 11100 4102
+a 11100 11101 4102
+a 11101 11102 4102
+a 11102 11103 4102
+a 11103 11104 4102
+a 11104 11105 4102
+a 11105 11106 4102
+a 11106 11107 4102
+a 11107 11108 4102
+a 11108 11109 4102
+a 11109 11110 4102
+a 11110 11111 4102
+a 11111 11112 4102
+a 11112 11113 4102
+a 11113 11114 4102
+a 11114 11115 4102
+a 11115 11116 4102
+a 11116 11117 4102
+a 11117 11118 4102
+a 11118 11119 4102
+a 11119 11120 4102
+a 11120 11121 4102
+a 11121 11122 4102
+a 11122 11123 4102
+a 11123 11124 4102
+a 11124 11125 4102
+a 11125 11126 4102
+a 11126 11127 4102
+a 11127 11128 4102
+a 11128 11129 4102
+a 11129 11130 4102
+a 11130 11131 4102
+a 11131 11132 4102
+a 11132 11133 4102
+a 11133 11134 4102
+a 11134 11135 4102
+a 11135 11136 4102
+a 11136 11137 4102
+a 11137 11138 4102
+a 11138 11139 4102
+a 11139 11140 4102
+a 11140 11141 4102
+a 11141 11142 4102
+a 11142 11143 4102
+a 11143 11144 4102
+a 11144 11145 4102
+a 11145 11146 4102
+a 11146 11147 4102
+a 11147 11148 4102
+a 11148 11149 4102
+a 11149 11150 4102
+a 11150 11151 4102
+a 11151 11152 4102
+a 11152 11153 4102
+a 11153 11154 4102
+a 11154 11155 4102
+a 11155 11156 4102
+a 11156 11157 4102
+a 11157 11158 4102
+a 11158 11159 4102
+a 11159 11160 4102
+a 11160 11161 4102
+a 11161 11162 4102
+a 11162 11163 4102
+a 11163 11164 4102
+a 11164 11165 4102
+a 11165 11166 4102
+a 11166 11167 4102
+a 11167 11168 4102
+a 11168 11169 4102
+a 11169 11170 4102
+a 11170 11171 4102
+a 11171 11172 4102
+a 11172 11173 4102
+a 11173 11174 4102
+a 11174 11175 4102
+a 11175 11176 4102
+a 11176 11177 4102
+a 11177 11178 4102
+a 11178 11179 4102
+a 11179 11180 4102
+a 11180 11181 4102
+a 11181 11182 4102
+a 11182 11183 4102
+a 11183 11184 4102
+a 11184 11185 4102
+a 11185 11186 4102
+a 11186 11187 4102
+a 11187 11188 4102
+a 11188 11189 4102
+a 11189 11190 4102
+a 11190 11191 4102
+a 11191 11192 4102
+a 11192 11193 4102
+a 11193 11194 4102
+a 11194 11195 4102
+a 11195 11196 4102
+a 11196 11197 4102
+a 11197 11198 4102
+a 11198 11199 4102
+a 11199 11200 4102
+a 11200 11201 4102
+a 11201 11202 4102
+a 11202 11203 4102
+a 11203 11204 4102
+a 11204 11205 4102
+a 11205 11206 4102
+a 11206 11207 4102
+a 11207 11208 4102
+a 11208 11209 4102
+a 11209 11210 4102
+a 11210 11211 4102
+a 11211 11212 4102
+a 11212 11213 4102
+a 11213 11214 4102
+a 11214 11215 4102
+a 11215 11216 4102
+a 11216 11217 4102
+a 11217 11218 4102
+a 11218 11219 4102
+a 11219 11220 4102
+a 11220 11221 4102
+a 11221 11222 4102
+a 11222 11223 4102
+a 11223 11224 4102
+a 11224 11225 4102
+a 11225 11226 4102
+a 11226 11227 4102
+a 11227 11228 4102
+a 11228 11229 4102
+a 11229 11230 4102
+a 11230 11231 4102
+a 11231 11232 4102
+a 11232 11233 4102
+a 11233 11234 4102
+a 11234 11235 4102
+a 11235 11236 4102
+a 11236 11237 4102
+a 11237 11238 4102
+a 11238 11239 4102
+a 11239 11240 4102
+a 11240 11241 4102
+a 11241 11242 4102
+a 11242 11243 4102
+a 11243 11244 4102
+a 11244 11245 4102
+a 11245 11246 4102
+a 11246 11247 4102
+a 11247 11248 4102
+a 11248 11249 4102
+a 11249 11250 4102
+a 11250 11251 4102
+a 11251 11252 4102
+a 11252 11253 4102
+a 11253 11254 4102
+a 11254 11255 4102
+a 11255 11256 4102
+a 11256 11257 4102
+a 11257 11258 4102
+a 11258 11259 4102
+a 11259 11260 4102
+a 11260 11261 4102
+a 11261 11262 4102
+a 11262 11263 4102
+a 11263 11264 4102
+a 11264 11265 4102
+a 11265 11266 4102
+a 11266 11267 4102
+a 11267 11268 4102
+a 11268 11269 4102
+a 11269 11270 4102
+a 11270 11271 4102
+a 11271 11272 4102
+a 11272 11273 4102
+a 11273 11274 4102
+a 11274 11275 4102
+a 11275 11276 4102
+a 11276 11277 4102
+a 11277 11278 4102
+a 11278 11279 4102
+a 11279 11280 4102
+a 11280 11281 4102
+a 11281 11282 4102
+a 11282 11283 4102
+a 11283 11284 4102
+a 11284 11285 4102
+a 11285 11286 4102
+a 11286 11287 4102
+a 11287 11288 4102
+a 11288 11289 4102
+a 11289 11290 4102
+a 11290 11291 4102
+a 11291 11292 4102
+a 11292 11293 4102
+a 11293 11294 4102
+a 11294 11295 4102
+a 11295 11296 4102
+a 11296 11297 4102
+a 11297 11298 4102
+a 11298 11299 4102
+a 11299 11300 4102
+a 11300 11301 4102
+a 11301 11302 4102
+a 11302 11303 4102
+a 11303 11304 4102
+a 11304 11305 4102
+a 11305 11306 4102
+a 11306 11307 4102
+a 11307 11308 4102
+a 11308 11309 4102
+a 11309 11310 4102
+a 11310 11311 4102
+a 11311 11312 4102
+a 11312 11313 4102
+a 11313 11314 4102
+a 11314 11315 4102
+a 11315 11316 4102
+a 11316 11317 4102
+a 11317 11318 4102
+a 11318 11319 4102
+a 11319 11320 4102
+a 11320 11321 4102
+a 11321 11322 4102
+a 11322 11323 4102
+a 11323 11324 4102
+a 11324 11325 4102
+a 11325 11326 4102
+a 11326 11327 4102
+a 11327 11328 4102
+a 11328 11329 4102
+a 11329 11330 4102
+a 11330 11331 4102
+a 11331 11332 4102
+a 11332 11333 4102
+a 11333 11334 4102
+a 11334 11335 4102
+a 11335 11336 4102
+a 11336 11337 4102
+a 11337 11338 4102
+a 11338 11339 4102
+a 11339 11340 4102
+a 11340 11341 4102
+a 11341 11342 4102
+a 11342 11343 4102
+a 11343 11344 4102
+a 11344 11345 4102
+a 11345 11346 4102
+a 11346 11347 4102
+a 11347 11348 4102
+a 11348 11349 4102
+a 11349 11350 4102
+a 11350 11351 4102
+a 11351 11352 4102
+a 11352 11353 4102
+a 11353 11354 4102
+a 11354 11355 4102
+a 11355 11356 4102
+a 11356 11357 4102
+a 11357 11358 4102
+a 11358 11359 4102
+a 11359 11360 4102
+a 11360 11361 4102
+a 11361 11362 4102
+a 11362 11363 4102
+a 11363 11364 4102
+a 11364 11365 4102
+a 11365 11366 4102
+a 11366 11367 4102
+a 11367 11368 4102
+a 11368 11369 4102
+a 11369 11370 4102
+a 11370 11371 4102
+a 11371 11372 4102
+a 11372 11373 4102
+a 11373 11374 4102
+a 11374 11375 4102
+a 11375 11376 4102
+a 11376 11377 4102
+a 11377 11378 4102
+a 11378 11379 4102
+a 11379 11380 4102
+a 11380 11381 4102
+a 11381 11382 4102
+a 11382 11383 4102
+a 11383 11384 4102
+a 11384 11385 4102
+a 11385 11386 4102
+a 11386 11387 4102
+a 11387 11388 4102
+a 11388 11389 4102
+a 11389 11390 4102
+a 11390 11391 4102
+a 11391 11392 4102
+a 11392 11393 4102
+a 11393 11394 4102
+a 11394 11395 4102
+a 11395 11396 4102
+a 11396 11397 4102
+a 11397 11398 4102
+a 11398 11399 4102
+a 11399 11400 4102
+a 11400 11401 4102
+a 11401 11402 4102
+a 11402 11403 4102
+a 11403 11404 4102
+a 11404 11405 4102
+a 11405 11406 4102
+a 11406 11407 4102
+a 11407 11408 4102
+a 11408 11409 4102
+a 11409 11410 4102
+a 11410 11411 4102
+a 11411 11412 4102
+a 11412 11413 4102
+a 11413 11414 4102
+a 11414 11415 4102
+a 11415 11416 4102
+a 11416 11417 4102
+a 11417 11418 4102
+a 11418 11419 4102
+a 11419 11420 4102
+a 11420 11421 4102
+a 11421 11422 4102
+a 11422 11423 4102
+a 11423 11424 4102
+a 11424 11425 4102
+a 11425 11426 4102
+a 11426 11427 4102
+a 11427 11428 4102
+a 11428 11429 4102
+a 11429 11430 4102
+a 11430 11431 4102
+a 11431 11432 4102
+a 11432 11433 4102
+a 11433 11434 4102
+a 11434 11435 4102
+a 11435 11436 4102
+a 11436 11437 4102
+a 11437 11438 4102
+a 11438 11439 4102
+a 11439 11440 4102
+a 11440 11441 4102
+a 11441 11442 4102
+a 11442 11443 4102
+a 11443 11444 4102
+a 11444 11445 4102
+a 11445 11446 4102
+a 11446 11447 4102
+a 11447 11448 4102
+a 11448 11449 4102
+a 11449 11450 4102
+a 11450 11451 4102
+a 11451 11452 4102
+a 11452 11453 4102
+a 11453 11454 4102
+a 11454 11455 4102
+a 11455 11456 4102
+a 11456 11457 4102
+a 11457 11458 4102
+a 11458 11459 4102
+a 11459 11460 4102
+a 11460 11461 4102
+a 11461 11462 4102
+a 11462 11463 4102
+a 11463 11464 4102
+a 11464 11465 4102
+a 11465 11466 4102
+a 11466 11467 4102
+a 11467 11468 4102
+a 11468 11469 4102
+a 11469 11470 4102
+a 11470 11471 4102
+a 11471 11472 4102
+a 11472 11473 4102
+a 11473 11474 4102
+a 11474 11475 4102
+a 11475 11476 4102
+a 11476 11477 4102
+a 11477 11478 4102
+a 11478 11479 4102
+a 11479 11480 4102
+a 11480 11481 4102
+a 11481 11482 4102
+a 11482 11483 4102
+a 11483 11484 4102
+a 11484 11485 4102
+a 11485 11486 4102
+a 11486 11487 4102
+a 11487 11488 4102
+a 11488 11489 4102
+a 11489 11490 4102
+a 11490 11491 4102
+a 11491 11492 4102
+a 11492 11493 4102
+a 11493 11494 4102
+a 11494 11495 4102
+a 11495 11496 4102
+a 11496 11497 4102
+a 11497 11498 4102
+a 11498 11499 4102
+a 11499 11500 4102
+a 11500 11501 4102
+a 11501 11502 4102
+a 11502 11503 4102
+a 11503 11504 4102
+a 11504 11505 4102
+a 11505 11506 4102
+a 11506 11507 4102
+a 11507 11508 4102
+a 11508 11509 4102
+a 11509 11510 4102
+a 11510 11511 4102
+a 11511 11512 4102
+a 11512 11513 4102
+a 11513 11514 4102
+a 11514 11515 4102
+a 11515 11516 4102
+a 11516 11517 4102
+a 11517 11518 4102
+a 11518 11519 4102
+a 11519 11520 4102
+a 11520 11521 4102
+a 11521 11522 4102
+a 11522 11523 4102
+a 11523 11524 4102
+a 11524 11525 4102
+a 11525 11526 4102
+a 11526 11527 4102
+a 11527 11528 4102
+a 11528 11529 4102
+a 11529 11530 4102
+a 11530 11531 4102
+a 11531 11532 4102
+a 11532 11533 4102
+a 11533 11534 4102
+a 11534 11535 4102
+a 11535 11536 4102
+a 11536 11537 4102
+a 11537 11538 4102
+a 11538 11539 4102
+a 11539 11540 4102
+a 11540 11541 4102
+a 11541 11542 4102
+a 11542 11543 4102
+a 11543 11544 4102
+a 11544 11545 4102
+a 11545 11546 4102
+a 11546 11547 4102
+a 11547 11548 4102
+a 11548 11549 4102
+a 11549 11550 4102
+a 11550 11551 4102
+a 11551 11552 4102
+a 11552 11553 4102
+a 11553 11554 4102
+a 11554 11555 4102
+a 11555 11556 4102
+a 11556 11557 4102
+a 11557 11558 4102
+a 11558 11559 4102
+a 11559 11560 4102
+a 11560 11561 4102
+a 11561 11562 4102
+a 11562 11563 4102
+a 11563 11564 4102
+a 11564 11565 4102
+a 11565 11566 4102
+a 11566 11567 4102
+a 11567 11568 4102
+a 11568 11569 4102
+a 11569 11570 4102
+a 11570 11571 4102
+a 11571 11572 4102
+a 11572 11573 4102
+a 11573 11574 4102
+a 11574 11575 4102
+a 11575 11576 4102
+a 11576 11577 4102
+a 11577 11578 4102
+a 11578 11579 4102
+a 11579 11580 4102
+a 11580 11581 4102
+a 11581 11582 4102
+a 11582 11583 4102
+a 11583 11584 4102
+a 11584 11585 4102
+a 11585 11586 4102
+a 11586 11587 4102
+a 11587 11588 4102
+a 11588 11589 4102
+a 11589 11590 4102
+a 11590 11591 4102
+a 11591 11592 4102
+a 11592 11593 4102
+a 11593 11594 4102
+a 11594 11595 4102
+a 11595 11596 4102
+a 11596 11597 4102
+a 11597 11598 4102
+a 11598 11599 4102
+a 11599 11600 4102
+a 11600 11601 4102
+a 11601 11602 4102
+a 11602 11603 4102
+a 11603 11604 4102
+a 11604 11605 4102
+a 11605 11606 4102
+a 11606 11607 4102
+a 11607 11608 4102
+a 11608 11609 4102
+a 11609 11610 4102
+a 11610 11611 4102
+a 11611 11612 4102
+a 11612 11613 4102
+a 11613 11614 4102
+a 11614 11615 4102
+a 11615 11616 4102
+a 11616 11617 4102
+a 11617 11618 4102
+a 11618 11619 4102
+a 11619 11620 4102
+a 11620 11621 4102
+a 11621 11622 4102
+a 11622 11623 4102
+a 11623 11624 4102
+a 11624 11625 4102
+a 11625 11626 4102
+a 11626 11627 4102
+a 11627 11628 4102
+a 11628 11629 4102
+a 11629 11630 4102
+a 11630 11631 4102
+a 11631 11632 4102
+a 11632 11633 4102
+a 11633 11634 4102
+a 11634 11635 4102
+a 11635 11636 4102
+a 11636 11637 4102
+a 11637 11638 4102
+a 11638 11639 4102
+a 11639 11640 4102
+a 11640 11641 4102
+a 11641 11642 4102
+a 11642 11643 4102
+a 11643 11644 4102
+a 11644 11645 4102
+a 11645 11646 4102
+a 11646 11647 4102
+a 11647 11648 4102
+a 11648 11649 4102
+a 11649 11650 4102
+a 11650 11651 4102
+a 11651 11652 4102
+a 11652 11653 4102
+a 11653 11654 4102
+a 11654 11655 4102
+a 11655 11656 4102
+a 11656 11657 4102
+a 11657 11658 4102
+a 11658 11659 4102
+a 11659 11660 4102
+a 11660 11661 4102
+a 11661 11662 4102
+a 11662 11663 4102
+a 11663 11664 4102
+a 11664 11665 4102
+a 11665 11666 4102
+a 11666 11667 4102
+a 11667 11668 4102
+a 11668 11669 4102
+a 11669 11670 4102
+a 11670 11671 4102
+a 11671 11672 4102
+a 11672 11673 4102
+a 11673 11674 4102
+a 11674 11675 4102
+a 11675 11676 4102
+a 11676 11677 4102
+a 11677 11678 4102
+a 11678 11679 4102
+a 11679 11680 4102
+a 11680 11681 4102
+a 11681 11682 4102
+a 11682 11683 4102
+a 11683 11684 4102
+a 11684 11685 4102
+a 11685 11686 4102
+a 11686 11687 4102
+a 11687 11688 4102
+a 11688 11689 4102
+a 11689 11690 4102
+a 11690 11691 4102
+a 11691 11692 4102
+a 11692 11693 4102
+a 11693 11694 4102
+a 11694 11695 4102
+a 11695 11696 4102
+a 11696 11697 4102
+a 11697 11698 4102
+a 11698 11699 4102
+a 11699 11700 4102
+a 11700 11701 4102
+a 11701 11702 4102
+a 11702 11703 4102
+a 11703 11704 4102
+a 11704 11705 4102
+a 11705 11706 4102
+a 11706 11707 4102
+a 11707 11708 4102
+a 11708 11709 4102
+a 11709 11710 4102
+a 11710 11711 4102
+a 11711 11712 4102
+a 11712 11713 4102
+a 11713 11714 4102
+a 11714 11715 4102
+a 11715 11716 4102
+a 11716 11717 4102
+a 11717 11718 4102
+a 11718 11719 4102
+a 11719 11720 4102
+a 11720 11721 4102
+a 11721 11722 4102
+a 11722 11723 4102
+a 11723 11724 4102
+a 11724 11725 4102
+a 11725 11726 4102
+a 11726 11727 4102
+a 11727 11728 4102
+a 11728 11729 4102
+a 11729 11730 4102
+a 11730 11731 4102
+a 11731 11732 4102
+a 11732 11733 4102
+a 11733 11734 4102
+a 11734 11735 4102
+a 11735 11736 4102
+a 11736 11737 4102
+a 11737 11738 4102
+a 11738 11739 4102
+a 11739 11740 4102
+a 11740 11741 4102
+a 11741 11742 4102
+a 11742 11743 4102
+a 11743 11744 4102
+a 11744 11745 4102
+a 11745 11746 4102
+a 11746 11747 4102
+a 11747 11748 4102
+a 11748 11749 4102
+a 11749 11750 4102
+a 11750 11751 4102
+a 11751 11752 4102
+a 11752 11753 4102
+a 11753 11754 4102
+a 11754 11755 4102
+a 11755 11756 4102
+a 11756 11757 4102
+a 11757 11758 4102
+a 11758 11759 4102
+a 11759 11760 4102
+a 11760 11761 4102
+a 11761 11762 4102
+a 11762 11763 4102
+a 11763 11764 4102
+a 11764 11765 4102
+a 11765 11766 4102
+a 11766 11767 4102
+a 11767 11768 4102
+a 11768 11769 4102
+a 11769 11770 4102
+a 11770 11771 4102
+a 11771 11772 4102
+a 11772 11773 4102
+a 11773 11774 4102
+a 11774 11775 4102
+a 11775 11776 4102
+a 11776 11777 4102
+a 11777 11778 4102
+a 11778 11779 4102
+a 11779 11780 4102
+a 11780 11781 4102
+a 11781 11782 4102
+a 11782 11783 4102
+a 11783 11784 4102
+a 11784 11785 4102
+a 11785 11786 4102
+a 11786 11787 4102
+a 11787 11788 4102
+a 11788 11789 4102
+a 11789 11790 4102
+a 11790 11791 4102
+a 11791 11792 4102
+a 11792 11793 4102
+a 11793 11794 4102
+a 11794 11795 4102
+a 11795 11796 4102
+a 11796 11797 4102
+a 11797 11798 4102
+a 11798 11799 4102
+a 11799 11800 4102
+a 11800 11801 4102
+a 11801 11802 4102
+a 11802 11803 4102
+a 11803 11804 4102
+a 11804 11805 4102
+a 11805 11806 4102
+a 11806 11807 4102
+a 11807 11808 4102
+a 11808 11809 4102
+a 11809 11810 4102
+a 11810 11811 4102
+a 11811 11812 4102
+a 11812 11813 4102
+a 11813 11814 4102
+a 11814 11815 4102
+a 11815 11816 4102
+a 11816 11817 4102
+a 11817 11818 4102
+a 11818 11819 4102
+a 11819 11820 4102
+a 11820 11821 4102
+a 11821 11822 4102
+a 11822 11823 4102
+a 11823 11824 4102
+a 11824 11825 4102
+a 11825 11826 4102
+a 11826 11827 4102
+a 11827 11828 4102
+a 11828 11829 4102
+a 11829 11830 4102
+a 11830 11831 4102
+a 11831 11832 4102
+a 11832 11833 4102
+a 11833 11834 4102
+a 11834 11835 4102
+a 11835 11836 4102
+a 11836 11837 4102
+a 11837 11838 4102
+a 11838 11839 4102
+a 11839 11840 4102
+a 11840 11841 4102
+a 11841 11842 4102
+a 11842 11843 4102
+a 11843 11844 4102
+a 11844 11845 4102
+a 11845 11846 4102
+a 11846 11847 4102
+a 11847 11848 4102
+a 11848 11849 4102
+a 11849 11850 4102
+a 11850 11851 4102
+a 11851 11852 4102
+a 11852 11853 4102
+a 11853 11854 4102
+a 11854 11855 4102
+a 11855 11856 4102
+a 11856 11857 4102
+a 11857 11858 4102
+a 11858 11859 4102
+a 11859 11860 4102
+a 11860 11861 4102
+a 11861 11862 4102
+a 11862 11863 4102
+a 11863 11864 4102
+a 11864 11865 4102
+a 11865 11866 4102
+a 11866 11867 4102
+a 11867 11868 4102
+a 11868 11869 4102
+a 11869 11870 4102
+a 11870 11871 4102
+a 11871 11872 4102
+a 11872 11873 4102
+a 11873 11874 4102
+a 11874 11875 4102
+a 11875 11876 4102
+a 11876 11877 4102
+a 11877 11878 4102
+a 11878 11879 4102
+a 11879 11880 4102
+a 11880 11881 4102
+a 11881 11882 4102
+a 11882 11883 4102
+a 11883 11884 4102
+a 11884 11885 4102
+a 11885 11886 4102
+a 11886 11887 4102
+a 11887 11888 4102
+a 11888 11889 4102
+a 11889 11890 4102
+a 11890 11891 4102
+a 11891 11892 4102
+a 11892 11893 4102
+a 11893 11894 4102
+a 11894 11895 4102
+a 11895 11896 4102
+a 11896 11897 4102
+a 11897 11898 4102
+a 11898 11899 4102
+a 11899 11900 4102
+a 11900 11901 4102
+a 11901 11902 4102
+a 11902 11903 4102
+a 11903 11904 4102
+a 11904 11905 4102
+a 11905 11906 4102
+a 11906 11907 4102
+a 11907 11908 4102
+a 11908 11909 4102
+a 11909 11910 4102
+a 11910 11911 4102
+a 11911 11912 4102
+a 11912 11913 4102
+a 11913 11914 4102
+a 11914 11915 4102
+a 11915 11916 4102
+a 11916 11917 4102
+a 11917 11918 4102
+a 11918 11919 4102
+a 11919 11920 4102
+a 11920 11921 4102
+a 11921 11922 4102
+a 11922 11923 4102
+a 11923 11924 4102
+a 11924 11925 4102
+a 11925 11926 4102
+a 11926 11927 4102
+a 11927 11928 4102
+a 11928 11929 4102
+a 11929 11930 4102
+a 11930 11931 4102
+a 11931 11932 4102
+a 11932 11933 4102
+a 11933 11934 4102
+a 11934 11935 4102
+a 11935 11936 4102
+a 11936 11937 4102
+a 11937 11938 4102
+a 11938 11939 4102
+a 11939 11940 4102
+a 11940 11941 4102
+a 11941 11942 4102
+a 11942 11943 4102
+a 11943 11944 4102
+a 11944 11945 4102
+a 11945 11946 4102
+a 11946 11947 4102
+a 11947 11948 4102
+a 11948 11949 4102
+a 11949 11950 4102
+a 11950 11951 4102
+a 11951 11952 4102
+a 11952 11953 4102
+a 11953 11954 4102
+a 11954 11955 4102
+a 11955 11956 4102
+a 11956 11957 4102
+a 11957 11958 4102
+a 11958 11959 4102
+a 11959 11960 4102
+a 11960 11961 4102
+a 11961 11962 4102
+a 11962 11963 4102
+a 11963 11964 4102
+a 11964 11965 4102
+a 11965 11966 4102
+a 11966 11967 4102
+a 11967 11968 4102
+a 11968 11969 4102
+a 11969 11970 4102
+a 11970 11971 4102
+a 11971 11972 4102
+a 11972 11973 4102
+a 11973 11974 4102
+a 11974 11975 4102
+a 11975 11976 4102
+a 11976 11977 4102
+a 11977 11978 4102
+a 11978 11979 4102
+a 11979 11980 4102
+a 11980 11981 4102
+a 11981 11982 4102
+a 11982 11983 4102
+a 11983 11984 4102
+a 11984 11985 4102
+a 11985 11986 4102
+a 11986 11987 4102
+a 11987 11988 4102
+a 11988 11989 4102
+a 11989 11990 4102
+a 11990 11991 4102
+a 11991 11992 4102
+a 11992 11993 4102
+a 11993 11994 4102
+a 11994 11995 4102
+a 11995 11996 4102
+a 11996 11997 4102
+a 11997 11998 4102
+a 11998 11999 4102
+a 11999 12000 4102
+a 12000 12001 4102
+a 12001 12002 4102
+a 12002 12003 4102
+a 12003 12004 4102
+a 12004 12005 4102
+a 12005 12006 4102
+a 12006 12007 4102
+a 12007 12008 4102
+a 12008 12009 4102
+a 12009 12010 4102
+a 12010 12011 4102
+a 12011 12012 4102
+a 12012 12013 4102
+a 12013 12014 4102
+a 12014 12015 4102
+a 12015 12016 4102
+a 12016 12017 4102
+a 12017 12018 4102
+a 12018 12019 4102
+a 12019 12020 4102
+a 12020 12021 4102
+a 12021 12022 4102
+a 12022 12023 4102
+a 12023 12024 4102
+a 12024 12025 4102
+a 12025 12026 4102
+a 12026 12027 4102
+a 12027 12028 4102
+a 12028 12029 4102
+a 12029 12030 4102
+a 12030 12031 4102
+a 12031 12032 4102
+a 12032 12033 4102
+a 12033 12034 4102
+a 12034 12035 4102
+a 12035 12036 4102
+a 12036 12037 4102
+a 12037 12038 4102
+a 12038 12039 4102
+a 12039 12040 4102
+a 12040 12041 4102
+a 12041 12042 4102
+a 12042 12043 4102
+a 12043 12044 4102
+a 12044 12045 4102
+a 12045 12046 4102
+a 12046 12047 4102
+a 12047 12048 4102
+a 12048 12049 4102
+a 12049 12050 4102
+a 12050 12051 4102
+a 12051 12052 4102
+a 12052 12053 4102
+a 12053 12054 4102
+a 12054 12055 4102
+a 12055 12056 4102
+a 12056 12057 4102
+a 12057 12058 4102
+a 12058 12059 4102
+a 12059 12060 4102
+a 12060 12061 4102
+a 12061 12062 4102
+a 12062 12063 4102
+a 12063 12064 4102
+a 12064 12065 4102
+a 12065 12066 4102
+a 12066 12067 4102
+a 12067 12068 4102
+a 12068 12069 4102
+a 12069 12070 4102
+a 12070 12071 4102
+a 12071 12072 4102
+a 12072 12073 4102
+a 12073 12074 4102
+a 12074 12075 4102
+a 12075 12076 4102
+a 12076 12077 4102
+a 12077 12078 4102
+a 12078 12079 4102
+a 12079 12080 4102
+a 12080 12081 4102
+a 12081 12082 4102
+a 12082 12083 4102
+a 12083 12084 4102
+a 12084 12085 4102
+a 12085 12086 4102
+a 12086 12087 4102
+a 12087 12088 4102
+a 12088 12089 4102
+a 12089 12090 4102
+a 12090 12091 4102
+a 12091 12092 4102
+a 12092 12093 4102
+a 12093 12094 4102
+a 12094 12095 4102
+a 12095 12096 4102
+a 12096 12097 4102
+a 12097 12098 4102
+a 12098 12099 4102
+a 12099 12100 4102
+a 12100 12101 4102
+a 12101 12102 4102
+a 12102 12103 4102
+a 12103 12104 4102
+a 12104 12105 4102
+a 12105 12106 4102
+a 12106 12107 4102
+a 12107 12108 4102
+a 12108 12109 4102
+a 12109 12110 4102
+a 12110 12111 4102
+a 12111 12112 4102
+a 12112 12113 4102
+a 12113 12114 4102
+a 12114 12115 4102
+a 12115 12116 4102
+a 12116 12117 4102
+a 12117 12118 4102
+a 12118 12119 4102
+a 12119 12120 4102
+a 12120 12121 4102
+a 12121 12122 4102
+a 12122 12123 4102
+a 12123 12124 4102
+a 12124 12125 4102
+a 12125 12126 4102
+a 12126 12127 4102
+a 12127 12128 4102
+a 12128 12129 4102
+a 12129 12130 4102
+a 12130 12131 4102
+a 12131 12132 4102
+a 12132 12133 4102
+a 12133 12134 4102
+a 12134 12135 4102
+a 12135 12136 4102
+a 12136 12137 4102
+a 12137 12138 4102
+a 12138 12139 4102
+a 12139 12140 4102
+a 12140 12141 4102
+a 12141 12142 4102
+a 12142 12143 4102
+a 12143 12144 4102
+a 12144 12145 4102
+a 12145 12146 4102
+a 12146 12147 4102
+a 12147 12148 4102
+a 12148 12149 4102
+a 12149 12150 4102
+a 12150 12151 4102
+a 12151 12152 4102
+a 12152 12153 4102
+a 12153 12154 4102
+a 12154 12155 4102
+a 12155 12156 4102
+a 12156 12157 4102
+a 12157 12158 4102
+a 12158 12159 4102
+a 12159 12160 4102
+a 12160 12161 4102
+a 12161 12162 4102
+a 12162 12163 4102
+a 12163 12164 4102
+a 12164 12165 4102
+a 12165 12166 4102
+a 12166 12167 4102
+a 12167 12168 4102
+a 12168 12169 4102
+a 12169 12170 4102
+a 12170 12171 4102
+a 12171 12172 4102
+a 12172 12173 4102
+a 12173 12174 4102
+a 12174 12175 4102
+a 12175 12176 4102
+a 12176 12177 4102
+a 12177 12178 4102
+a 12178 12179 4102
+a 12179 12180 4102
+a 12180 12181 4102
+a 12181 12182 4102
+a 12182 12183 4102
+a 12183 12184 4102
+a 12184 12185 4102
+a 12185 12186 4102
+a 12186 12187 4102
+a 12187 12188 4102
+a 12188 12189 4102
+a 12189 12190 4102
+a 12190 12191 4102
+a 12191 12192 4102
+a 12192 12193 4102
+a 12193 12194 4102
+a 12194 12195 4102
+a 12195 12196 4102
+a 12196 12197 4102
+a 12197 12198 4102
+a 12198 12199 4102
+a 12199 12200 4102
+a 12200 12201 4102
+a 12201 12202 4102
+a 12202 12203 4102
+a 12203 12204 4102
+a 12204 12205 4102
+a 12205 12206 4102
+a 12206 12207 4102
+a 12207 12208 4102
+a 12208 12209 4102
+a 12209 12210 4102
+a 12210 12211 4102
+a 12211 12212 4102
+a 12212 12213 4102
+a 12213 12214 4102
+a 12214 12215 4102
+a 12215 12216 4102
+a 12216 12217 4102
+a 12217 12218 4102
+a 12218 12219 4102
+a 12219 12220 4102
+a 12220 12221 4102
+a 12221 12222 4102
+a 12222 12223 4102
+a 12223 12224 4102
+a 12224 12225 4102
+a 12225 12226 4102
+a 12226 12227 4102
+a 12227 12228 4102
+a 12228 12229 4102
+a 12229 12230 4102
+a 12230 12231 4102
+a 12231 12232 4102
+a 12232 12233 4102
+a 12233 12234 4102
+a 12234 12235 4102
+a 12235 12236 4102
+a 12236 12237 4102
+a 12237 12238 4102
+a 12238 12239 4102
+a 12239 12240 4102
+a 12240 12241 4102
+a 12241 12242 4102
+a 12242 12243 4102
+a 12243 12244 4102
+a 12244 12245 4102
+a 12245 12246 4102
+a 12246 12247 4102
+a 12247 12248 4102
+a 12248 12249 4102
+a 12249 12250 4102
+a 12250 12251 4102
+a 12251 12252 4102
+a 12252 12253 4102
+a 12253 12254 4102
+a 12254 12255 4102
+a 12255 12256 4102
+a 12256 12257 4102
+a 12257 12258 4102
+a 12258 12259 4102
+a 12259 12260 4102
+a 12260 12261 4102
+a 12261 12262 4102
+a 12262 12263 4102
+a 12263 12264 4102
+a 12264 12265 4102
+a 12265 12266 4102
+a 12266 12267 4102
+a 12267 12268 4102
+a 12268 12269 4102
+a 12269 12270 4102
+a 12270 12271 4102
+a 12271 12272 4102
+a 12272 12273 4102
+a 12273 12274 4102
+a 12274 12275 4102
+a 12275 12276 4102
+a 12276 12277 4102
+a 12277 12278 4102
+a 12278 12279 4102
+a 12279 12280 4102
+a 12280 12281 4102
+a 12281 12282 4102
+a 12282 12283 4102
+a 12283 12284 4102
+a 12284 12285 4102
+a 12285 12286 4102
+a 12286 12287 4102
+a 12287 12288 4102
+a 12288 12289 4102
+a 12289 12290 4102
+a 12290 12291 4102
+a 12291 12292 4102
+a 12292 12293 4102
+a 12293 12294 4102
+a 12294 12295 4102
+a 12295 12296 4102
+a 12296 12297 4102
+a 12297 12298 4102
+a 12298 12299 4102
+a 12299 12300 4102
+a 12300 12301 4102
+a 12301 12302 4102
+a 12302 12303 4102
+a 12303 12304 4102
+a 12304 12305 4102
+a 12305 12306 4102
+a 12306 12307 4102
+a 12307 12308 4102
+a 12308 12309 4102
+a 12309 12310 4102
+a 12310 12311 4102
+a 12311 12312 4102
+a 12312 12313 4102
+a 12313 12314 4102
+a 12314 12315 4102
+a 12315 12316 4102
+a 12316 12317 4102
+a 12317 12318 4102
+a 12318 12319 4102
+a 12319 12320 4102
+a 12320 12321 4102
+a 12321 12322 4102
+a 12322 12323 4102
+a 12323 12324 4102
+a 12324 12325 4102
+a 12325 12326 4102
+a 12326 12327 4102
+a 12327 12328 4102
+a 12328 12329 4102
+a 12329 12330 4102
+a 12330 12331 4102
+a 12331 12332 4102
+a 12332 12333 4102
+a 12333 12334 4102
+a 12334 12335 4102
+a 12335 12336 4102
+a 12336 12337 4102
+a 12337 12338 4102
+a 12338 12339 4102
+a 12339 12340 4102
+a 12340 12341 4102
+a 12341 12342 4102
+a 12342 12343 4102
+a 12343 12344 4102
+a 12344 12345 4102
+a 12345 12346 4102
+a 12346 12347 4102
+a 12347 12348 4102
+a 12348 12349 4102
+a 12349 12350 4102
+a 12350 12351 4102
+a 12351 12352 4102
+a 12352 12353 4102
+a 12353 12354 4102
+a 12354 12355 4102
+a 12355 12356 4102
+a 12356 12357 4102
+a 12357 12358 4102
+a 12358 12359 4102
+a 12359 12360 4102
+a 12360 12361 4102
+a 12361 12362 4102
+a 12362 12363 4102
+a 12363 12364 4102
+a 12364 12365 4102
+a 12365 12366 4102
+a 12366 12367 4102
+a 12367 12368 4102
+a 12368 12369 4102
+a 12369 12370 4102
+a 12370 12371 4102
+a 12371 12372 4102
+a 12372 12373 4102
+a 12373 12374 4102
+a 12374 12375 4102
+a 12375 12376 4102
+a 12376 12377 4102
+a 12377 12378 4102
+a 12378 12379 4102
+a 12379 12380 4102
+a 12380 12381 4102
+a 12381 12382 4102
+a 12382 12383 4102
+a 12383 12384 4102
+a 12384 12385 4102
+a 12385 12386 4102
+a 12386 12387 4102
+a 12387 12388 4102
+a 12388 12389 4102
+a 12389 12390 4102
+a 12390 12391 4102
+a 12391 12392 4102
+a 12392 12393 4102
+a 12393 12394 4102
+a 12394 12395 4102
+a 12395 12396 4102
+a 12396 12397 4102
+a 12397 12398 4102
+a 12398 12399 4102
+a 12399 12400 4102
+a 12400 12401 4102
+a 12401 12402 4102
+a 12402 12403 4102
+a 12403 12404 4102
+a 12404 12405 4102
+a 12405 12406 4102
+a 12406 12407 4102
+a 12407 12408 4102
+a 12408 12409 4102
+a 12409 12410 4102
+a 12410 12411 4102
+a 12411 12412 4102
+a 12412 12413 4102
+a 12413 12414 4102
+a 12414 12415 4102
+a 12415 12416 4102
+a 12416 12417 4102
+a 12417 12418 4102
+a 12418 12419 4102
+a 12419 12420 4102
+a 12420 12421 4102
+a 12421 12422 4102
+a 12422 12423 4102
+a 12423 12424 4102
+a 12424 12425 4102
+a 12425 12426 4102
+a 12426 12427 4102
+a 12427 12428 4102
+a 12428 12429 4102
+a 12429 12430 4102
+a 12430 12431 4102
+a 12431 12432 4102
+a 12432 12433 4102
+a 12433 12434 4102
+a 12434 12435 4102
+a 12435 12436 4102
+a 12436 12437 4102
+a 12437 12438 4102
+a 12438 12439 4102
+a 12439 12440 4102
+a 12440 12441 4102
+a 12441 12442 4102
+a 12442 12443 4102
+a 12443 12444 4102
+a 12444 12445 4102
+a 12445 12446 4102
+a 12446 12447 4102
+a 12447 12448 4102
+a 12448 12449 4102
+a 12449 12450 4102
+a 12450 12451 4102
+a 12451 12452 4102
+a 12452 12453 4102
+a 12453 12454 4102
+a 12454 12455 4102
+a 12455 12456 4102
+a 12456 12457 4102
+a 12457 12458 4102
+a 12458 12459 4102
+a 12459 12460 4102
+a 12460 12461 4102
+a 12461 12462 4102
+a 12462 12463 4102
+a 12463 12464 4102
+a 12464 12465 4102
+a 12465 12466 4102
+a 12466 12467 4102
+a 12467 12468 4102
+a 12468 12469 4102
+a 12469 12470 4102
+a 12470 12471 4102
+a 12471 12472 4102
+a 12472 12473 4102
+a 12473 12474 4102
+a 12474 12475 4102
+a 12475 12476 4102
+a 12476 12477 4102
+a 12477 12478 4102
+a 12478 12479 4102
+a 12479 12480 4102
+a 12480 12481 4102
+a 12481 12482 4102
+a 12482 12483 4102
+a 12483 12484 4102
+a 12484 12485 4102
+a 12485 12486 4102
+a 12486 12487 4102
+a 12487 12488 4102
+a 12488 12489 4102
+a 12489 12490 4102
+a 12490 12491 4102
+a 12491 12492 4102
+a 12492 12493 4102
+a 12493 12494 4102
+a 12494 12495 4102
+a 12495 12496 4102
+a 12496 12497 4102
+a 12497 12498 4102
+a 12498 12499 4102
+a 12499 12500 4102
+a 12500 12501 4102
+a 12501 12502 4102
+a 12502 12503 4102
+a 12503 12504 4102
+a 12504 12505 4102
+a 12505 12506 4102
+a 12506 12507 4102
+a 12507 12508 4102
+a 12508 12509 4102
+a 12509 12510 4102
+a 12510 12511 4102
+a 12511 12512 4102
+a 12512 12513 4102
+a 12513 12514 4102
+a 12514 12515 4102
+a 12515 12516 4102
+a 12516 12517 4102
+a 12517 12518 4102
+a 12518 12519 4102
+a 12519 12520 4102
+a 12520 12521 4102
+a 12521 12522 4102
+a 12522 12523 4102
+a 12523 12524 4102
+a 12524 12525 4102
+a 12525 12526 4102
+a 12526 12527 4102
+a 12527 12528 4102
+a 12528 12529 4102
+a 12529 12530 4102
+a 12530 12531 4102
+a 12531 12532 4102
+a 12532 12533 4102
+a 12533 12534 4102
+a 12534 12535 4102
+a 12535 12536 4102
+a 12536 12537 4102
+a 12537 12538 4102
+a 12538 12539 4102
+a 12539 12540 4102
+a 12540 12541 4102
+a 12541 12542 4102
+a 12542 12543 4102
+a 12543 12544 4102
+a 12544 12545 4102
+a 12545 12546 4102
+a 12546 12547 4102
+a 12547 12548 4102
+a 12548 12549 4102
+a 12549 12550 4102
+a 12550 12551 4102
+a 12551 12552 4102
+a 12552 12553 4102
+a 12553 12554 4102
+a 12554 12555 4102
+a 12555 12556 4102
+a 12556 12557 4102
+a 12557 12558 4102
+a 12558 12559 4102
+a 12559 12560 4102
+a 12560 12561 4102
+a 12561 12562 4102
+a 12562 12563 4102
+a 12563 12564 4102
+a 12564 12565 4102
+a 12565 12566 4102
+a 12566 12567 4102
+a 12567 12568 4102
+a 12568 12569 4102
+a 12569 12570 4102
+a 12570 12571 4102
+a 12571 12572 4102
+a 12572 12573 4102
+a 12573 12574 4102
+a 12574 12575 4102
+a 12575 12576 4102
+a 12576 12577 4102
+a 12577 12578 4102
+a 12578 12579 4102
+a 12579 12580 4102
+a 12580 12581 4102
+a 12581 12582 4102
+a 12582 12583 4102
+a 12583 12584 4102
+a 12584 12585 4102
+a 12585 12586 4102
+a 12586 12587 4102
+a 12587 12588 4102
+a 12588 12589 4102
+a 12589 12590 4102
+a 12590 12591 4102
+a 12591 12592 4102
+a 12592 12593 4102
+a 12593 12594 4102
+a 12594 12595 4102
+a 12595 12596 4102
+a 12596 12597 4102
+a 12597 12598 4102
+a 12598 12599 4102
+a 12599 12600 4102
+a 12600 12601 4102
+a 12601 12602 4102
+a 12602 12603 4102
+a 12603 12604 4102
+a 12604 12605 4102
+a 12605 12606 4102
+a 12606 12607 4102
+a 12607 12608 4102
+a 12608 12609 4102
+a 12609 12610 4102
+a 12610 12611 4102
+a 12611 12612 4102
+a 12612 12613 4102
+a 12613 12614 4102
+a 12614 12615 4102
+a 12615 12616 4102
+a 12616 12617 4102
+a 12617 12618 4102
+a 12618 12619 4102
+a 12619 12620 4102
+a 12620 12621 4102
+a 12621 12622 4102
+a 12622 12623 4102
+a 12623 12624 4102
+a 12624 12625 4102
+a 12625 12626 4102
+a 12626 12627 4102
+a 12627 12628 4102
+a 12628 12629 4102
+a 12629 12630 4102
+a 12630 12631 4102
+a 12631 12632 4102
+a 12632 12633 4102
+a 12633 12634 4102
+a 12634 12635 4102
+a 12635 12636 4102
+a 12636 12637 4102
+a 12637 12638 4102
+a 12638 12639 4102
+a 12639 12640 4102
+a 12640 12641 4102
+a 12641 12642 4102
+a 12642 12643 4102
+a 12643 12644 4102
+a 12644 12645 4102
+a 12645 12646 4102
+a 12646 12647 4102
+a 12647 12648 4102
+a 12648 12649 4102
+a 12649 12650 4102
+a 12650 12651 4102
+a 12651 12652 4102
+a 12652 12653 4102
+a 12653 12654 4102
+a 12654 12655 4102
+a 12655 12656 4102
+a 12656 12657 4102
+a 12657 12658 4102
+a 12658 12659 4102
+a 12659 12660 4102
+a 12660 12661 4102
+a 12661 12662 4102
+a 12662 12663 4102
+a 12663 12664 4102
+a 12664 12665 4102
+a 12665 12666 4102
+a 12666 12667 4102
+a 12667 12668 4102
+a 12668 12669 4102
+a 12669 12670 4102
+a 12670 12671 4102
+a 12671 12672 4102
+a 12672 12673 4102
+a 12673 12674 4102
+a 12674 12675 4102
+a 12675 12676 4102
+a 12676 12677 4102
+a 12677 12678 4102
+a 12678 12679 4102
+a 12679 12680 4102
+a 12680 12681 4102
+a 12681 12682 4102
+a 12682 12683 4102
+a 12683 12684 4102
+a 12684 12685 4102
+a 12685 12686 4102
+a 12686 12687 4102
+a 12687 12688 4102
+a 12688 12689 4102
+a 12689 12690 4102
+a 12690 12691 4102
+a 12691 12692 4102
+a 12692 12693 4102
+a 12693 12694 4102
+a 12694 12695 4102
+a 12695 12696 4102
+a 12696 12697 4102
+a 12697 12698 4102
+a 12698 12699 4102
+a 12699 12700 4102
+a 12700 12701 4102
+a 12701 12702 4102
+a 12702 12703 4102
+a 12703 12704 4102
+a 12704 12705 4102
+a 12705 12706 4102
+a 12706 12707 4102
+a 12707 12708 4102
+a 12708 12709 4102
+a 12709 12710 4102
+a 12710 12711 4102
+a 12711 12712 4102
+a 12712 12713 4102
+a 12713 12714 4102
+a 12714 12715 4102
+a 12715 12716 4102
+a 12716 12717 4102
+a 12717 12718 4102
+a 12718 12719 4102
+a 12719 12720 4102
+a 12720 12721 4102
+a 12721 12722 4102
+a 12722 12723 4102
+a 12723 12724 4102
+a 12724 12725 4102
+a 12725 12726 4102
+a 12726 12727 4102
+a 12727 12728 4102
+a 12728 12729 4102
+a 12729 12730 4102
+a 12730 12731 4102
+a 12731 12732 4102
+a 12732 12733 4102
+a 12733 12734 4102
+a 12734 12735 4102
+a 12735 12736 4102
+a 12736 12737 4102
+a 12737 12738 4102
+a 12738 12739 4102
+a 12739 12740 4102
+a 12740 12741 4102
+a 12741 12742 4102
+a 12742 12743 4102
+a 12743 12744 4102
+a 12744 12745 4102
+a 12745 12746 4102
+a 12746 12747 4102
+a 12747 12748 4102
+a 12748 12749 4102
+a 12749 12750 4102
+a 12750 12751 4102
+a 12751 12752 4102
+a 12752 12753 4102
+a 12753 12754 4102
+a 12754 12755 4102
+a 12755 12756 4102
+a 12756 12757 4102
+a 12757 12758 4102
+a 12758 12759 4102
+a 12759 12760 4102
+a 12760 12761 4102
+a 12761 12762 4102
+a 12762 12763 4102
+a 12763 12764 4102
+a 12764 12765 4102
+a 12765 12766 4102
+a 12766 12767 4102
+a 12767 12768 4102
+a 12768 12769 4102
+a 12769 12770 4102
+a 12770 12771 4102
+a 12771 12772 4102
+a 12772 12773 4102
+a 12773 12774 4102
+a 12774 12775 4102
+a 12775 12776 4102
+a 12776 12777 4102
+a 12777 12778 4102
+a 12778 12779 4102
+a 12779 12780 4102
+a 12780 12781 4102
+a 12781 12782 4102
+a 12782 12783 4102
+a 12783 12784 4102
+a 12784 12785 4102
+a 12785 12786 4102
+a 12786 12787 4102
+a 12787 12788 4102
+a 12788 12789 4102
+a 12789 12790 4102
+a 12790 12791 4102
+a 12791 12792 4102
+a 12792 12793 4102
+a 12793 12794 4102
+a 12794 12795 4102
+a 12795 12796 4102
+a 12796 12797 4102
+a 12797 12798 4102
+a 12798 12799 4102
+a 12799 12800 4102
+a 12800 12801 4102
+a 12801 12802 4102
+a 12802 12803 4102
+a 12803 12804 4102
+a 12804 12805 4102
+a 12805 12806 4102
+a 12806 12807 4102
+a 12807 12808 4102
+a 12808 12809 4102
+a 12809 12810 4102
+a 12810 12811 4102
+a 12811 12812 4102
+a 12812 12813 4102
+a 12813 12814 4102
+a 12814 12815 4102
+a 12815 12816 4102
+a 12816 12817 4102
+a 12817 12818 4102
+a 12818 12819 4102
+a 12819 12820 4102
+a 12820 12821 4102
+a 12821 12822 4102
+a 12822 12823 4102
+a 12823 12824 4102
+a 12824 12825 4102
+a 12825 12826 4102
+a 12826 12827 4102
+a 12827 12828 4102
+a 12828 12829 4102
+a 12829 12830 4102
+a 12830 12831 4102
+a 12831 12832 4102
+a 12832 12833 4102
+a 12833 12834 4102
+a 12834 12835 4102
+a 12835 12836 4102
+a 12836 12837 4102
+a 12837 12838 4102
+a 12838 12839 4102
+a 12839 12840 4102
+a 12840 12841 4102
+a 12841 12842 4102
+a 12842 12843 4102
+a 12843 12844 4102
+a 12844 12845 4102
+a 12845 12846 4102
+a 12846 12847 4102
+a 12847 12848 4102
+a 12848 12849 4102
+a 12849 12850 4102
+a 12850 12851 4102
+a 12851 12852 4102
+a 12852 12853 4102
+a 12853 12854 4102
+a 12854 12855 4102
+a 12855 12856 4102
+a 12856 12857 4102
+a 12857 12858 4102
+a 12858 12859 4102
+a 12859 12860 4102
+a 12860 12861 4102
+a 12861 12862 4102
+a 12862 12863 4102
+a 12863 12864 4102
+a 12864 12865 4102
+a 12865 12866 4102
+a 12866 12867 4102
+a 12867 12868 4102
+a 12868 12869 4102
+a 12869 12870 4102
+a 12870 12871 4102
+a 12871 12872 4102
+a 12872 12873 4102
+a 12873 12874 4102
+a 12874 12875 4102
+a 12875 12876 4102
+a 12876 12877 4102
+a 12877 12878 4102
+a 12878 12879 4102
+a 12879 12880 4102
+a 12880 12881 4102
+a 12881 12882 4102
+a 12882 12883 4102
+a 12883 12884 4102
+a 12884 12885 4102
+a 12885 12886 4102
+a 12886 12887 4102
+a 12887 12888 4102
+a 12888 12889 4102
+a 12889 12890 4102
+a 12890 12891 4102
+a 12891 12892 4102
+a 12892 12893 4102
+a 12893 12894 4102
+a 12894 12895 4102
+a 12895 12896 4102
+a 12896 12897 4102
+a 12897 12898 4102
+a 12898 12899 4102
+a 12899 12900 4102
+a 12900 12901 4102
+a 12901 12902 4102
+a 12902 12903 4102
+a 12903 12904 4102
+a 12904 12905 4102
+a 12905 12906 4102
+a 12906 12907 4102
+a 12907 12908 4102
+a 12908 12909 4102
+a 12909 12910 4102
+a 12910 12911 4102
+a 12911 12912 4102
+a 12912 12913 4102
+a 12913 12914 4102
+a 12914 12915 4102
+a 12915 12916 4102
+a 12916 12917 4102
+a 12917 12918 4102
+a 12918 12919 4102
+a 12919 12920 4102
+a 12920 12921 4102
+a 12921 12922 4102
+a 12922 12923 4102
+a 12923 12924 4102
+a 12924 12925 4102
+a 12925 12926 4102
+a 12926 12927 4102
+a 12927 12928 4102
+a 12928 12929 4102
+a 12929 12930 4102
+a 12930 12931 4102
+a 12931 12932 4102
+a 12932 12933 4102
+a 12933 12934 4102
+a 12934 12935 4102
+a 12935 12936 4102
+a 12936 12937 4102
+a 12937 12938 4102
+a 12938 12939 4102
+a 12939 12940 4102
+a 12940 12941 4102
+a 12941 12942 4102
+a 12942 12943 4102
+a 12943 12944 4102
+a 12944 12945 4102
+a 12945 12946 4102
+a 12946 12947 4102
+a 12947 12948 4102
+a 12948 12949 4102
+a 12949 12950 4102
+a 12950 12951 4102
+a 12951 12952 4102
+a 12952 12953 4102
+a 12953 12954 4102
+a 12954 12955 4102
+a 12955 12956 4102
+a 12956 12957 4102
+a 12957 12958 4102
+a 12958 12959 4102
+a 12959 12960 4102
+a 12960 12961 4102
+a 12961 12962 4102
+a 12962 12963 4102
+a 12963 12964 4102
+a 12964 12965 4102
+a 12965 12966 4102
+a 12966 12967 4102
+a 12967 12968 4102
+a 12968 12969 4102
+a 12969 12970 4102
+a 12970 12971 4102
+a 12971 12972 4102
+a 12972 12973 4102
+a 12973 12974 4102
+a 12974 12975 4102
+a 12975 12976 4102
+a 12976 12977 4102
+a 12977 12978 4102
+a 12978 12979 4102
+a 12979 12980 4102
+a 12980 12981 4102
+a 12981 12982 4102
+a 12982 12983 4102
+a 12983 12984 4102
+a 12984 12985 4102
+a 12985 12986 4102
+a 12986 12987 4102
+a 12987 12988 4102
+a 12988 12989 4102
+a 12989 12990 4102
+a 12990 12991 4102
+a 12991 12992 4102
+a 12992 12993 4102
+a 12993 12994 4102
+a 12994 12995 4102
+a 12995 12996 4102
+a 12996 12997 4102
+a 12997 12998 4102
+a 12998 12999 4102
+a 12999 13000 4102
+a 13000 13001 4102
+a 13001 13002 4102
+a 13002 13003 4102
+a 13003 13004 4102
+a 13004 13005 4102
+a 13005 13006 4102
+a 13006 13007 4102
+a 13007 13008 4102
+a 13008 13009 4102
+a 13009 13010 4102
+a 13010 13011 4102
+a 13011 13012 4102
+a 13012 13013 4102
+a 13013 13014 4102
+a 13014 13015 4102
+a 13015 13016 4102
+a 13016 13017 4102
+a 13017 13018 4102
+a 13018 13019 4102
+a 13019 13020 4102
+a 13020 13021 4102
+a 13021 13022 4102
+a 13022 13023 4102
+a 13023 13024 4102
+a 13024 13025 4102
+a 13025 13026 4102
+a 13026 13027 4102
+a 13027 13028 4102
+a 13028 13029 4102
+a 13029 13030 4102
+a 13030 13031 4102
+a 13031 13032 4102
+a 13032 13033 4102
+a 13033 13034 4102
+a 13034 13035 4102
+a 13035 13036 4102
+a 13036 13037 4102
+a 13037 13038 4102
+a 13038 13039 4102
+a 13039 13040 4102
+a 13040 13041 4102
+a 13041 13042 4102
+a 13042 13043 4102
+a 13043 13044 4102
+a 13044 13045 4102
+a 13045 13046 4102
+a 13046 13047 4102
+a 13047 13048 4102
+a 13048 13049 4102
+a 13049 13050 4102
+a 13050 13051 4102
+a 13051 13052 4102
+a 13052 13053 4102
+a 13053 13054 4102
+a 13054 13055 4102
+a 13055 13056 4102
+a 13056 13057 4102
+a 13057 13058 4102
+a 13058 13059 4102
+a 13059 13060 4102
+a 13060 13061 4102
+a 13061 13062 4102
+a 13062 13063 4102
+a 13063 13064 4102
+a 13064 13065 4102
+a 13065 13066 4102
+a 13066 13067 4102
+a 13067 13068 4102
+a 13068 13069 4102
+a 13069 13070 4102
+a 13070 13071 4102
+a 13071 13072 4102
+a 13072 13073 4102
+a 13073 13074 4102
+a 13074 13075 4102
+a 13075 13076 4102
+a 13076 13077 4102
+a 13077 13078 4102
+a 13078 13079 4102
+a 13079 13080 4102
+a 13080 13081 4102
+a 13081 13082 4102
+a 13082 13083 4102
+a 13083 13084 4102
+a 13084 13085 4102
+a 13085 13086 4102
+a 13086 13087 4102
+a 13087 13088 4102
+a 13088 13089 4102
+a 13089 13090 4102
+a 13090 13091 4102
+a 13091 13092 4102
+a 13092 13093 4102
+a 13093 13094 4102
+a 13094 13095 4102
+a 13095 13096 4102
+a 13096 13097 4102
+a 13097 13098 4102
+a 13098 13099 4102
+a 13099 13100 4102
+a 13100 13101 4102
+a 13101 13102 4102
+a 13102 13103 4102
+a 13103 13104 4102
+a 13104 13105 4102
+a 13105 13106 4102
+a 13106 13107 4102
+a 13107 13108 4102
+a 13108 13109 4102
+a 13109 13110 4102
+a 13110 13111 4102
+a 13111 13112 4102
+a 13112 13113 4102
+a 13113 13114 4102
+a 13114 13115 4102
+a 13115 13116 4102
+a 13116 13117 4102
+a 13117 13118 4102
+a 13118 13119 4102
+a 13119 13120 4102
+a 13120 13121 4102
+a 13121 13122 4102
+a 13122 13123 4102
+a 13123 13124 4102
+a 13124 13125 4102
+a 13125 13126 4102
+a 13126 13127 4102
+a 13127 13128 4102
+a 13128 13129 4102
+a 13129 13130 4102
+a 13130 13131 4102
+a 13131 13132 4102
+a 13132 13133 4102
+a 13133 13134 4102
+a 13134 13135 4102
+a 13135 13136 4102
+a 13136 13137 4102
+a 13137 13138 4102
+a 13138 13139 4102
+a 13139 13140 4102
+a 13140 13141 4102
+a 13141 13142 4102
+a 13142 13143 4102
+a 13143 13144 4102
+a 13144 13145 4102
+a 13145 13146 4102
+a 13146 13147 4102
+a 13147 13148 4102
+a 13148 13149 4102
+a 13149 13150 4102
+a 13150 13151 4102
+a 13151 13152 4102
+a 13152 13153 4102
+a 13153 13154 4102
+a 13154 13155 4102
+a 13155 13156 4102
+a 13156 13157 4102
+a 13157 13158 4102
+a 13158 13159 4102
+a 13159 13160 4102
+a 13160 13161 4102
+a 13161 13162 4102
+a 13162 13163 4102
+a 13163 13164 4102
+a 13164 13165 4102
+a 13165 13166 4102
+a 13166 13167 4102
+a 13167 13168 4102
+a 13168 13169 4102
+a 13169 13170 4102
+a 13170 13171 4102
+a 13171 13172 4102
+a 13172 13173 4102
+a 13173 13174 4102
+a 13174 13175 4102
+a 13175 13176 4102
+a 13176 13177 4102
+a 13177 13178 4102
+a 13178 13179 4102
+a 13179 13180 4102
+a 13180 13181 4102
+a 13181 13182 4102
+a 13182 13183 4102
+a 13183 13184 4102
+a 13184 13185 4102
+a 13185 13186 4102
+a 13186 13187 4102
+a 13187 13188 4102
+a 13188 13189 4102
+a 13189 13190 4102
+a 13190 13191 4102
+a 13191 13192 4102
+a 13192 13193 4102
+a 13193 13194 4102
+a 13194 13195 4102
+a 13195 13196 4102
+a 13196 13197 4102
+a 13197 13198 4102
+a 13198 13199 4102
+a 13199 13200 4102
+a 13200 13201 4102
+a 13201 13202 4102
+a 13202 13203 4102
+a 13203 13204 4102
+a 13204 13205 4102
+a 13205 13206 4102
+a 13206 13207 4102
+a 13207 13208 4102
+a 13208 13209 4102
+a 13209 13210 4102
+a 13210 13211 4102
+a 13211 13212 4102
+a 13212 13213 4102
+a 13213 13214 4102
+a 13214 13215 4102
+a 13215 13216 4102
+a 13216 13217 4102
+a 13217 13218 4102
+a 13218 13219 4102
+a 13219 13220 4102
+a 13220 13221 4102
+a 13221 13222 4102
+a 13222 13223 4102
+a 13223 13224 4102
+a 13224 13225 4102
+a 13225 13226 4102
+a 13226 13227 4102
+a 13227 13228 4102
+a 13228 13229 4102
+a 13229 13230 4102
+a 13230 13231 4102
+a 13231 13232 4102
+a 13232 13233 4102
+a 13233 13234 4102
+a 13234 13235 4102
+a 13235 13236 4102
+a 13236 13237 4102
+a 13237 13238 4102
+a 13238 13239 4102
+a 13239 13240 4102
+a 13240 13241 4102
+a 13241 13242 4102
+a 13242 13243 4102
+a 13243 13244 4102
+a 13244 13245 4102
+a 13245 13246 4102
+a 13246 13247 4102
+a 13247 13248 4102
+a 13248 13249 4102
+a 13249 13250 4102
+a 13250 13251 4102
+a 13251 13252 4102
+a 13252 13253 4102
+a 13253 13254 4102
+a 13254 13255 4102
+a 13255 13256 4102
+a 13256 13257 4102
+a 13257 13258 4102
+a 13258 13259 4102
+a 13259 13260 4102
+a 13260 13261 4102
+a 13261 13262 4102
+a 13262 13263 4102
+a 13263 13264 4102
+a 13264 13265 4102
+a 13265 13266 4102
+a 13266 13267 4102
+a 13267 13268 4102
+a 13268 13269 4102
+a 13269 13270 4102
+a 13270 13271 4102
+a 13271 13272 4102
+a 13272 13273 4102
+a 13273 13274 4102
+a 13274 13275 4102
+a 13275 13276 4102
+a 13276 13277 4102
+a 13277 13278 4102
+a 13278 13279 4102
+a 13279 13280 4102
+a 13280 13281 4102
+a 13281 13282 4102
+a 13282 13283 4102
+a 13283 13284 4102
+a 13284 13285 4102
+a 13285 13286 4102
+a 13286 13287 4102
+a 13287 13288 4102
+a 13288 13289 4102
+a 13289 13290 4102
+a 13290 13291 4102
+a 13291 13292 4102
+a 13292 13293 4102
+a 13293 13294 4102
+a 13294 13295 4102
+a 13295 13296 4102
+a 13296 13297 4102
+a 13297 13298 4102
+a 13298 13299 4102
+a 13299 13300 4102
+a 13300 13301 4102
+a 13301 13302 4102
+a 13302 13303 4102
+a 13303 13304 4102
+a 13304 13305 4102
+a 13305 13306 4102
+a 13306 13307 4102
+a 13307 13308 4102
+a 13308 13309 4102
+a 13309 13310 4102
+a 13310 13311 4102
+a 13311 13312 4102
+a 13312 13313 4102
+a 13313 13314 4102
+a 13314 13315 4102
+a 13315 13316 4102
+a 13316 13317 4102
+a 13317 13318 4102
+a 13318 13319 4102
+a 13319 13320 4102
+a 13320 13321 4102
+a 13321 13322 4102
+a 13322 13323 4102
+a 13323 13324 4102
+a 13324 13325 4102
+a 13325 13326 4102
+a 13326 13327 4102
+a 13327 13328 4102
+a 13328 13329 4102
+a 13329 13330 4102
+a 13330 13331 4102
+a 13331 13332 4102
+a 13332 13333 4102
+a 13333 13334 4102
+a 13334 13335 4102
+a 13335 13336 4102
+a 13336 13337 4102
+a 13337 13338 4102
+a 13338 13339 4102
+a 13339 13340 4102
+a 13340 13341 4102
+a 13341 13342 4102
+a 13342 13343 4102
+a 13343 13344 4102
+a 13344 13345 4102
+a 13345 13346 4102
+a 13346 13347 4102
+a 13347 13348 4102
+a 13348 13349 4102
+a 13349 13350 4102
+a 13350 13351 4102
+a 13351 13352 4102
+a 13352 13353 4102
+a 13353 13354 4102
+a 13354 13355 4102
+a 13355 13356 4102
+a 13356 13357 4102
+a 13357 13358 4102
+a 13358 13359 4102
+a 13359 13360 4102
+a 13360 13361 4102
+a 13361 13362 4102
+a 13362 13363 4102
+a 13363 13364 4102
+a 13364 13365 4102
+a 13365 13366 4102
+a 13366 13367 4102
+a 13367 13368 4102
+a 13368 13369 4102
+a 13369 13370 4102
+a 13370 13371 4102
+a 13371 13372 4102
+a 13372 13373 4102
+a 13373 13374 4102
+a 13374 13375 4102
+a 13375 13376 4102
+a 13376 13377 4102
+a 13377 13378 4102
+a 13378 13379 4102
+a 13379 13380 4102
+a 13380 13381 4102
+a 13381 13382 4102
+a 13382 13383 4102
+a 13383 13384 4102
+a 13384 13385 4102
+a 13385 13386 4102
+a 13386 13387 4102
+a 13387 13388 4102
+a 13388 13389 4102
+a 13389 13390 4102
+a 13390 13391 4102
+a 13391 13392 4102
+a 13392 13393 4102
+a 13393 13394 4102
+a 13394 13395 4102
+a 13395 13396 4102
+a 13396 13397 4102
+a 13397 13398 4102
+a 13398 13399 4102
+a 13399 13400 4102
+a 13400 13401 4102
+a 13401 13402 4102
+a 13402 13403 4102
+a 13403 13404 4102
+a 13404 13405 4102
+a 13405 13406 4102
+a 13406 13407 4102
+a 13407 13408 4102
+a 13408 13409 4102
+a 13409 13410 4102
+a 13410 13411 4102
+a 13411 13412 4102
+a 13412 13413 4102
+a 13413 13414 4102
+a 13414 13415 4102
+a 13415 13416 4102
+a 13416 13417 4102
+a 13417 13418 4102
+a 13418 13419 4102
+a 13419 13420 4102
+a 13420 13421 4102
+a 13421 13422 4102
+a 13422 13423 4102
+a 13423 13424 4102
+a 13424 13425 4102
+a 13425 13426 4102
+a 13426 13427 4102
+a 13427 13428 4102
+a 13428 13429 4102
+a 13429 13430 4102
+a 13430 13431 4102
+a 13431 13432 4102
+a 13432 13433 4102
+a 13433 13434 4102
+a 13434 13435 4102
+a 13435 13436 4102
+a 13436 13437 4102
+a 13437 13438 4102
+a 13438 13439 4102
+a 13439 13440 4102
+a 13440 13441 4102
+a 13441 13442 4102
+a 13442 13443 4102
+a 13443 13444 4102
+a 13444 13445 4102
+a 13445 13446 4102
+a 13446 13447 4102
+a 13447 13448 4102
+a 13448 13449 4102
+a 13449 13450 4102
+a 13450 13451 4102
+a 13451 13452 4102
+a 13452 13453 4102
+a 13453 13454 4102
+a 13454 13455 4102
+a 13455 13456 4102
+a 13456 13457 4102
+a 13457 13458 4102
+a 13458 13459 4102
+a 13459 13460 4102
+a 13460 13461 4102
+a 13461 13462 4102
+a 13462 13463 4102
+a 13463 13464 4102
+a 13464 13465 4102
+a 13465 13466 4102
+a 13466 13467 4102
+a 13467 13468 4102
+a 13468 13469 4102
+a 13469 13470 4102
+a 13470 13471 4102
+a 13471 13472 4102
+a 13472 13473 4102
+a 13473 13474 4102
+a 13474 13475 4102
+a 13475 13476 4102
+a 13476 13477 4102
+a 13477 13478 4102
+a 13478 13479 4102
+a 13479 13480 4102
+a 13480 13481 4102
+a 13481 13482 4102
+a 13482 13483 4102
+a 13483 13484 4102
+a 13484 13485 4102
+a 13485 13486 4102
+a 13486 13487 4102
+a 13487 13488 4102
+a 13488 13489 4102
+a 13489 13490 4102
+a 13490 13491 4102
+a 13491 13492 4102
+a 13492 13493 4102
+a 13493 13494 4102
+a 13494 13495 4102
+a 13495 13496 4102
+a 13496 13497 4102
+a 13497 13498 4102
+a 13498 13499 4102
+a 13499 13500 4102
+a 13500 13501 4102
+a 13501 13502 4102
+a 13502 13503 4102
+a 13503 13504 4102
+a 13504 13505 4102
+a 13505 13506 4102
+a 13506 13507 4102
+a 13507 13508 4102
+a 13508 13509 4102
+a 13509 13510 4102
+a 13510 13511 4102
+a 13511 13512 4102
+a 13512 13513 4102
+a 13513 13514 4102
+a 13514 13515 4102
+a 13515 13516 4102
+a 13516 13517 4102
+a 13517 13518 4102
+a 13518 13519 4102
+a 13519 13520 4102
+a 13520 13521 4102
+a 13521 13522 4102
+a 13522 13523 4102
+a 13523 13524 4102
+a 13524 13525 4102
+a 13525 13526 4102
+a 13526 13527 4102
+a 13527 13528 4102
+a 13528 13529 4102
+a 13529 13530 4102
+a 13530 13531 4102
+a 13531 13532 4102
+a 13532 13533 4102
+a 13533 13534 4102
+a 13534 13535 4102
+a 13535 13536 4102
+a 13536 13537 4102
+a 13537 13538 4102
+a 13538 13539 4102
+a 13539 13540 4102
+a 13540 13541 4102
+a 13541 13542 4102
+a 13542 13543 4102
+a 13543 13544 4102
+a 13544 13545 4102
+a 13545 13546 4102
+a 13546 13547 4102
+a 13547 13548 4102
+a 13548 13549 4102
+a 13549 13550 4102
+a 13550 13551 4102
+a 13551 13552 4102
+a 13552 13553 4102
+a 13553 13554 4102
+a 13554 13555 4102
+a 13555 13556 4102
+a 13556 13557 4102
+a 13557 13558 4102
+a 13558 13559 4102
+a 13559 13560 4102
+a 13560 13561 4102
+a 13561 13562 4102
+a 13562 13563 4102
+a 13563 13564 4102
+a 13564 13565 4102
+a 13565 13566 4102
+a 13566 13567 4102
+a 13567 13568 4102
+a 13568 13569 4102
+a 13569 13570 4102
+a 13570 13571 4102
+a 13571 13572 4102
+a 13572 13573 4102
+a 13573 13574 4102
+a 13574 13575 4102
+a 13575 13576 4102
+a 13576 13577 4102
+a 13577 13578 4102
+a 13578 13579 4102
+a 13579 13580 4102
+a 13580 13581 4102
+a 13581 13582 4102
+a 13582 13583 4102
+a 13583 13584 4102
+a 13584 13585 4102
+a 13585 13586 4102
+a 13586 13587 4102
+a 13587 13588 4102
+a 13588 13589 4102
+a 13589 13590 4102
+a 13590 13591 4102
+a 13591 13592 4102
+a 13592 13593 4102
+a 13593 13594 4102
+a 13594 13595 4102
+a 13595 13596 4102
+a 13596 13597 4102
+a 13597 13598 4102
+a 13598 13599 4102
+a 13599 13600 4102
+a 13600 13601 4102
+a 13601 13602 4102
+a 13602 13603 4102
+a 13603 13604 4102
+a 13604 13605 4102
+a 13605 13606 4102
+a 13606 13607 4102
+a 13607 13608 4102
+a 13608 13609 4102
+a 13609 13610 4102
+a 13610 13611 4102
+a 13611 13612 4102
+a 13612 13613 4102
+a 13613 13614 4102
+a 13614 13615 4102
+a 13615 13616 4102
+a 13616 13617 4102
+a 13617 13618 4102
+a 13618 13619 4102
+a 13619 13620 4102
+a 13620 13621 4102
+a 13621 13622 4102
+a 13622 13623 4102
+a 13623 13624 4102
+a 13624 13625 4102
+a 13625 13626 4102
+a 13626 13627 4102
+a 13627 13628 4102
+a 13628 13629 4102
+a 13629 13630 4102
+a 13630 13631 4102
+a 13631 13632 4102
+a 13632 13633 4102
+a 13633 13634 4102
+a 13634 13635 4102
+a 13635 13636 4102
+a 13636 13637 4102
+a 13637 13638 4102
+a 13638 13639 4102
+a 13639 13640 4102
+a 13640 13641 4102
+a 13641 13642 4102
+a 13642 13643 4102
+a 13643 13644 4102
+a 13644 13645 4102
+a 13645 13646 4102
+a 13646 13647 4102
+a 13647 13648 4102
+a 13648 13649 4102
+a 13649 13650 4102
+a 13650 13651 4102
+a 13651 13652 4102
+a 13652 13653 4102
+a 13653 13654 4102
+a 13654 13655 4102
+a 13655 13656 4102
+a 13656 13657 4102
+a 13657 13658 4102
+a 13658 13659 4102
+a 13659 13660 4102
+a 13660 13661 4102
+a 13661 13662 4102
+a 13662 13663 4102
+a 13663 13664 4102
+a 13664 13665 4102
+a 13665 13666 4102
+a 13666 13667 4102
+a 13667 13668 4102
+a 13668 13669 4102
+a 13669 13670 4102
+a 13670 13671 4102
+a 13671 13672 4102
+a 13672 13673 4102
+a 13673 13674 4102
+a 13674 13675 4102
+a 13675 13676 4102
+a 13676 13677 4102
+a 13677 13678 4102
+a 13678 13679 4102
+a 13679 13680 4102
+a 13680 13681 4102
+a 13681 13682 4102
+a 13682 13683 4102
+a 13683 13684 4102
+a 13684 13685 4102
+a 13685 13686 4102
+a 13686 13687 4102
+a 13687 13688 4102
+a 13688 13689 4102
+a 13689 13690 4102
+a 13690 13691 4102
+a 13691 13692 4102
+a 13692 13693 4102
+a 13693 13694 4102
+a 13694 13695 4102
+a 13695 13696 4102
+a 13696 13697 4102
+a 13697 13698 4102
+a 13698 13699 4102
+a 13699 13700 4102
+a 13700 13701 4102
+a 13701 13702 4102
+a 13702 13703 4102
+a 13703 13704 4102
+a 13704 13705 4102
+a 13705 13706 4102
+a 13706 13707 4102
+a 13707 13708 4102
+a 13708 13709 4102
+a 13709 13710 4102
+a 13710 13711 4102
+a 13711 13712 4102
+a 13712 13713 4102
+a 13713 13714 4102
+a 13714 13715 4102
+a 13715 13716 4102
+a 13716 13717 4102
+a 13717 13718 4102
+a 13718 13719 4102
+a 13719 13720 4102
+a 13720 13721 4102
+a 13721 13722 4102
+a 13722 13723 4102
+a 13723 13724 4102
+a 13724 13725 4102
+a 13725 13726 4102
+a 13726 13727 4102
+a 13727 13728 4102
+a 13728 13729 4102
+a 13729 13730 4102
+a 13730 13731 4102
+a 13731 13732 4102
+a 13732 13733 4102
+a 13733 13734 4102
+a 13734 13735 4102
+a 13735 13736 4102
+a 13736 13737 4102
+a 13737 13738 4102
+a 13738 13739 4102
+a 13739 13740 4102
+a 13740 13741 4102
+a 13741 13742 4102
+a 13742 13743 4102
+a 13743 13744 4102
+a 13744 13745 4102
+a 13745 13746 4102
+a 13746 13747 4102
+a 13747 13748 4102
+a 13748 13749 4102
+a 13749 13750 4102
+a 13750 13751 4102
+a 13751 13752 4102
+a 13752 13753 4102
+a 13753 13754 4102
+a 13754 13755 4102
+a 13755 13756 4102
+a 13756 13757 4102
+a 13757 13758 4102
+a 13758 13759 4102
+a 13759 13760 4102
+a 13760 13761 4102
+a 13761 13762 4102
+a 13762 13763 4102
+a 13763 13764 4102
+a 13764 13765 4102
+a 13765 13766 4102
+a 13766 13767 4102
+a 13767 13768 4102
+a 13768 13769 4102
+a 13769 13770 4102
+a 13770 13771 4102
+a 13771 13772 4102
+a 13772 13773 4102
+a 13773 13774 4102
+a 13774 13775 4102
+a 13775 13776 4102
+a 13776 13777 4102
+a 13777 13778 4102
+a 13778 13779 4102
+a 13779 13780 4102
+a 13780 13781 4102
+a 13781 13782 4102
+a 13782 13783 4102
+a 13783 13784 4102
+a 13784 13785 4102
+a 13785 13786 4102
+a 13786 13787 4102
+a 13787 13788 4102
+a 13788 13789 4102
+a 13789 13790 4102
+a 13790 13791 4102
+a 13791 13792 4102
+a 13792 13793 4102
+a 13793 13794 4102
+a 13794 13795 4102
+a 13795 13796 4102
+a 13796 13797 4102
+a 13797 13798 4102
+a 13798 13799 4102
+a 13799 13800 4102
+a 13800 13801 4102
+a 13801 13802 4102
+a 13802 13803 4102
+a 13803 13804 4102
+a 13804 13805 4102
+a 13805 13806 4102
+a 13806 13807 4102
+a 13807 13808 4102
+a 13808 13809 4102
+a 13809 13810 4102
+a 13810 13811 4102
+a 13811 13812 4102
+a 13812 13813 4102
+a 13813 13814 4102
+a 13814 13815 4102
+a 13815 13816 4102
+a 13816 13817 4102
+a 13817 13818 4102
+a 13818 13819 4102
+a 13819 13820 4102
+a 13820 13821 4102
+a 13821 13822 4102
+a 13822 13823 4102
+a 13823 13824 4102
+a 13824 13825 4102
+a 13825 13826 4102
+a 13826 13827 4102
+a 13827 13828 4102
+a 13828 13829 4102
+a 13829 13830 4102
+a 13830 13831 4102
+a 13831 13832 4102
+a 13832 13833 4102
+a 13833 13834 4102
+a 13834 13835 4102
+a 13835 13836 4102
+a 13836 13837 4102
+a 13837 13838 4102
+a 13838 13839 4102
+a 13839 13840 4102
+a 13840 13841 4102
+a 13841 13842 4102
+a 13842 13843 4102
+a 13843 13844 4102
+a 13844 13845 4102
+a 13845 13846 4102
+a 13846 13847 4102
+a 13847 13848 4102
+a 13848 13849 4102
+a 13849 13850 4102
+a 13850 13851 4102
+a 13851 13852 4102
+a 13852 13853 4102
+a 13853 13854 4102
+a 13854 13855 4102
+a 13855 13856 4102
+a 13856 13857 4102
+a 13857 13858 4102
+a 13858 13859 4102
+a 13859 13860 4102
+a 13860 13861 4102
+a 13861 13862 4102
+a 13862 13863 4102
+a 13863 13864 4102
+a 13864 13865 4102
+a 13865 13866 4102
+a 13866 13867 4102
+a 13867 13868 4102
+a 13868 13869 4102
+a 13869 13870 4102
+a 13870 13871 4102
+a 13871 13872 4102
+a 13872 13873 4102
+a 13873 13874 4102
+a 13874 13875 4102
+a 13875 13876 4102
+a 13876 13877 4102
+a 13877 13878 4102
+a 13878 13879 4102
+a 13879 13880 4102
+a 13880 13881 4102
+a 13881 13882 4102
+a 13882 13883 4102
+a 13883 13884 4102
+a 13884 13885 4102
+a 13885 13886 4102
+a 13886 13887 4102
+a 13887 13888 4102
+a 13888 13889 4102
+a 13889 13890 4102
+a 13890 13891 4102
+a 13891 13892 4102
+a 13892 13893 4102
+a 13893 13894 4102
+a 13894 13895 4102
+a 13895 13896 4102
+a 13896 13897 4102
+a 13897 13898 4102
+a 13898 13899 4102
+a 13899 13900 4102
+a 13900 13901 4102
+a 13901 13902 4102
+a 13902 13903 4102
+a 13903 13904 4102
+a 13904 13905 4102
+a 13905 13906 4102
+a 13906 13907 4102
+a 13907 13908 4102
+a 13908 13909 4102
+a 13909 13910 4102
+a 13910 13911 4102
+a 13911 13912 4102
+a 13912 13913 4102
+a 13913 13914 4102
+a 13914 13915 4102
+a 13915 13916 4102
+a 13916 13917 4102
+a 13917 13918 4102
+a 13918 13919 4102
+a 13919 13920 4102
+a 13920 13921 4102
+a 13921 13922 4102
+a 13922 13923 4102
+a 13923 13924 4102
+a 13924 13925 4102
+a 13925 13926 4102
+a 13926 13927 4102
+a 13927 13928 4102
+a 13928 13929 4102
+a 13929 13930 4102
+a 13930 13931 4102
+a 13931 13932 4102
+a 13932 13933 4102
+a 13933 13934 4102
+a 13934 13935 4102
+a 13935 13936 4102
+a 13936 13937 4102
+a 13937 13938 4102
+a 13938 13939 4102
+a 13939 13940 4102
+a 13940 13941 4102
+a 13941 13942 4102
+a 13942 13943 4102
+a 13943 13944 4102
+a 13944 13945 4102
+a 13945 13946 4102
+a 13946 13947 4102
+a 13947 13948 4102
+a 13948 13949 4102
+a 13949 13950 4102
+a 13950 13951 4102
+a 13951 13952 4102
+a 13952 13953 4102
+a 13953 13954 4102
+a 13954 13955 4102
+a 13955 13956 4102
+a 13956 13957 4102
+a 13957 13958 4102
+a 13958 13959 4102
+a 13959 13960 4102
+a 13960 13961 4102
+a 13961 13962 4102
+a 13962 13963 4102
+a 13963 13964 4102
+a 13964 13965 4102
+a 13965 13966 4102
+a 13966 13967 4102
+a 13967 13968 4102
+a 13968 13969 4102
+a 13969 13970 4102
+a 13970 13971 4102
+a 13971 13972 4102
+a 13972 13973 4102
+a 13973 13974 4102
+a 13974 13975 4102
+a 13975 13976 4102
+a 13976 13977 4102
+a 13977 13978 4102
+a 13978 13979 4102
+a 13979 13980 4102
+a 13980 13981 4102
+a 13981 13982 4102
+a 13982 13983 4102
+a 13983 13984 4102
+a 13984 13985 4102
+a 13985 13986 4102
+a 13986 13987 4102
+a 13987 13988 4102
+a 13988 13989 4102
+a 13989 13990 4102
+a 13990 13991 4102
+a 13991 13992 4102
+a 13992 13993 4102
+a 13993 13994 4102
+a 13994 13995 4102
+a 13995 13996 4102
+a 13996 13997 4102
+a 13997 13998 4102
+a 13998 13999 4102
+a 13999 14000 4102
+a 14000 14001 4102
+a 14001 14002 4102
+a 14002 14003 4102
+a 14003 14004 4102
+a 14004 14005 4102
+a 14005 14006 4102
+a 14006 14007 4102
+a 14007 14008 4102
+a 14008 14009 4102
+a 14009 14010 4102
+a 14010 14011 4102
+a 14011 14012 4102
+a 14012 14013 4102
+a 14013 14014 4102
+a 14014 14015 4102
+a 14015 14016 4102
+a 14016 14017 4102
+a 14017 14018 4102
+a 14018 14019 4102
+a 14019 14020 4102
+a 14020 14021 4102
+a 14021 14022 4102
+a 14022 14023 4102
+a 14023 14024 4102
+a 14024 14025 4102
+a 14025 14026 4102
+a 14026 14027 4102
+a 14027 14028 4102
+a 14028 14029 4102
+a 14029 14030 4102
+a 14030 14031 4102
+a 14031 14032 4102
+a 14032 14033 4102
+a 14033 14034 4102
+a 14034 14035 4102
+a 14035 14036 4102
+a 14036 14037 4102
+a 14037 14038 4102
+a 14038 14039 4102
+a 14039 14040 4102
+a 14040 14041 4102
+a 14041 14042 4102
+a 14042 14043 4102
+a 14043 14044 4102
+a 14044 14045 4102
+a 14045 14046 4102
+a 14046 14047 4102
+a 14047 14048 4102
+a 14048 14049 4102
+a 14049 14050 4102
+a 14050 14051 4102
+a 14051 14052 4102
+a 14052 14053 4102
+a 14053 14054 4102
+a 14054 14055 4102
+a 14055 14056 4102
+a 14056 14057 4102
+a 14057 14058 4102
+a 14058 14059 4102
+a 14059 14060 4102
+a 14060 14061 4102
+a 14061 14062 4102
+a 14062 14063 4102
+a 14063 14064 4102
+a 14064 14065 4102
+a 14065 14066 4102
+a 14066 14067 4102
+a 14067 14068 4102
+a 14068 14069 4102
+a 14069 14070 4102
+a 14070 14071 4102
+a 14071 14072 4102
+a 14072 14073 4102
+a 14073 14074 4102
+a 14074 14075 4102
+a 14075 14076 4102
+a 14076 14077 4102
+a 14077 14078 4102
+a 14078 14079 4102
+a 14079 14080 4102
+a 14080 14081 4102
+a 14081 14082 4102
+a 14082 14083 4102
+a 14083 14084 4102
+a 14084 14085 4102
+a 14085 14086 4102
+a 14086 14087 4102
+a 14087 14088 4102
+a 14088 14089 4102
+a 14089 14090 4102
+a 14090 14091 4102
+a 14091 14092 4102
+a 14092 14093 4102
+a 14093 14094 4102
+a 14094 14095 4102
+a 14095 14096 4102
+a 14096 14097 4102
+a 14097 14098 4102
+a 14098 14099 4102
+a 14099 14100 4102
+a 14100 14101 4102
+a 14101 14102 4102
+a 14102 14103 4102
+a 14103 14104 4102
+a 14104 14105 4102
+a 14105 14106 4102
+a 14106 14107 4102
+a 14107 14108 4102
+a 14108 14109 4102
+a 14109 14110 4102
+a 14110 14111 4102
+a 14111 14112 4102
+a 14112 14113 4102
+a 14113 14114 4102
+a 14114 14115 4102
+a 14115 14116 4102
+a 14116 14117 4102
+a 14117 14118 4102
+a 14118 14119 4102
+a 14119 14120 4102
+a 14120 14121 4102
+a 14121 14122 4102
+a 14122 14123 4102
+a 14123 14124 4102
+a 14124 14125 4102
+a 14125 14126 4102
+a 14126 14127 4102
+a 14127 14128 4102
+a 14128 14129 4102
+a 14129 14130 4102
+a 14130 14131 4102
+a 14131 14132 4102
+a 14132 14133 4102
+a 14133 14134 4102
+a 14134 14135 4102
+a 14135 14136 4102
+a 14136 14137 4102
+a 14137 14138 4102
+a 14138 14139 4102
+a 14139 14140 4102
+a 14140 14141 4102
+a 14141 14142 4102
+a 14142 14143 4102
+a 14143 14144 4102
+a 14144 14145 4102
+a 14145 14146 4102
+a 14146 14147 4102
+a 14147 14148 4102
+a 14148 14149 4102
+a 14149 14150 4102
+a 14150 14151 4102
+a 14151 14152 4102
+a 14152 14153 4102
+a 14153 14154 4102
+a 14154 14155 4102
+a 14155 14156 4102
+a 14156 14157 4102
+a 14157 14158 4102
+a 14158 14159 4102
+a 14159 14160 4102
+a 14160 14161 4102
+a 14161 14162 4102
+a 14162 14163 4102
+a 14163 14164 4102
+a 14164 14165 4102
+a 14165 14166 4102
+a 14166 14167 4102
+a 14167 14168 4102
+a 14168 14169 4102
+a 14169 14170 4102
+a 14170 14171 4102
+a 14171 14172 4102
+a 14172 14173 4102
+a 14173 14174 4102
+a 14174 14175 4102
+a 14175 14176 4102
+a 14176 14177 4102
+a 14177 14178 4102
+a 14178 14179 4102
+a 14179 14180 4102
+a 14180 14181 4102
+a 14181 14182 4102
+a 14182 14183 4102
+a 14183 14184 4102
+a 14184 14185 4102
+a 14185 14186 4102
+a 14186 14187 4102
+a 14187 14188 4102
+a 14188 14189 4102
+a 14189 14190 4102
+a 14190 14191 4102
+a 14191 14192 4102
+a 14192 14193 4102
+a 14193 14194 4102
+a 14194 14195 4102
+a 14195 14196 4102
+a 14196 14197 4102
+a 14197 14198 4102
+a 14198 14199 4102
+a 14199 14200 4102
+a 14200 14201 4102
+a 14201 14202 4102
+a 14202 14203 4102
+a 14203 14204 4102
+a 14204 14205 4102
+a 14205 14206 4102
+a 14206 14207 4102
+a 14207 14208 4102
+a 14208 14209 4102
+a 14209 14210 4102
+a 14210 14211 4102
+a 14211 14212 4102
+a 14212 14213 4102
+a 14213 14214 4102
+a 14214 14215 4102
+a 14215 14216 4102
+a 14216 14217 4102
+a 14217 14218 4102
+a 14218 14219 4102
+a 14219 14220 4102
+a 14220 14221 4102
+a 14221 14222 4102
+a 14222 14223 4102
+a 14223 14224 4102
+a 14224 14225 4102
+a 14225 14226 4102
+a 14226 14227 4102
+a 14227 14228 4102
+a 14228 14229 4102
+a 14229 14230 4102
+a 14230 14231 4102
+a 14231 14232 4102
+a 14232 14233 4102
+a 14233 14234 4102
+a 14234 14235 4102
+a 14235 14236 4102
+a 14236 14237 4102
+a 14237 14238 4102
+a 14238 14239 4102
+a 14239 14240 4102
+a 14240 14241 4102
+a 14241 14242 4102
+a 14242 14243 4102
+a 14243 14244 4102
+a 14244 14245 4102
+a 14245 14246 4102
+a 14246 14247 4102
+a 14247 14248 4102
+a 14248 14249 4102
+a 14249 14250 4102
+a 14250 14251 4102
+a 14251 14252 4102
+a 14252 14253 4102
+a 14253 14254 4102
+a 14254 14255 4102
+a 14255 14256 4102
+a 14256 14257 4102
+a 14257 14258 4102
+a 14258 14259 4102
+a 14259 14260 4102
+a 14260 14261 4102
+a 14261 14262 4102
+a 14262 14263 4102
+a 14263 14264 4102
+a 14264 14265 4102
+a 14265 14266 4102
+a 14266 14267 4102
+a 14267 14268 4102
+a 14268 14269 4102
+a 14269 14270 4102
+a 14270 14271 4102
+a 14271 14272 4102
+a 14272 14273 4102
+a 14273 14274 4102
+a 14274 14275 4102
+a 14275 14276 4102
+a 14276 14277 4102
+a 14277 14278 4102
+a 14278 14279 4102
+a 14279 14280 4102
+a 14280 14281 4102
+a 14281 14282 4102
+a 14282 14283 4102
+a 14283 14284 4102
+a 14284 14285 4102
+a 14285 14286 4102
+a 14286 14287 4102
+a 14287 14288 4102
+a 14288 14289 4102
+a 14289 14290 4102
+a 14290 14291 4102
+a 14291 14292 4102
+a 14292 14293 4102
+a 14293 14294 4102
+a 14294 14295 4102
+a 14295 14296 4102
+a 14296 14297 4102
+a 14297 14298 4102
+a 14298 14299 4102
+a 14299 14300 4102
+a 14300 14301 4102
+a 14301 14302 4102
+a 14302 14303 4102
+a 14303 14304 4102
+a 14304 14305 4102
+a 14305 14306 4102
+a 14306 14307 4102
+a 14307 14308 4102
+a 14308 14309 4102
+a 14309 14310 4102
+a 14310 14311 4102
+a 14311 14312 4102
+a 14312 14313 4102
+a 14313 14314 4102
+a 14314 14315 4102
+a 14315 14316 4102
+a 14316 14317 4102
+a 14317 14318 4102
+a 14318 14319 4102
+a 14319 14320 4102
+a 14320 14321 4102
+a 14321 14322 4102
+a 14322 14323 4102
+a 14323 14324 4102
+a 14324 14325 4102
+a 14325 14326 4102
+a 14326 14327 4102
+a 14327 14328 4102
+a 14328 14329 4102
+a 14329 14330 4102
+a 14330 14331 4102
+a 14331 14332 4102
+a 14332 14333 4102
+a 14333 14334 4102
+a 14334 14335 4102
+a 14335 14336 4102
+a 14336 14337 4102
+a 14337 14338 4102
+a 14338 14339 4102
+a 14339 14340 4102
+a 14340 14341 4102
+a 14341 14342 4102
+a 14342 14343 4102
+a 14343 14344 4102
+a 14344 14345 4102
+a 14345 14346 4102
+a 14346 14347 4102
+a 14347 14348 4102
+a 14348 14349 4102
+a 14349 14350 4102
+a 14350 14351 4102
+a 14351 14352 4102
+a 14352 14353 4102
+a 14353 14354 4102
+a 14354 14355 4102
+a 14355 14356 4102
+a 14356 14357 4102
+a 14357 14358 4102
+a 14358 14359 4102
+a 14359 14360 4102
+a 14360 14361 4102
+a 14361 14362 4102
+a 14362 14363 4102
+a 14363 14364 4102
+a 14364 14365 4102
+a 14365 14366 4102
+a 14366 14367 4102
+a 14367 14368 4102
+a 14368 14369 4102
+a 14369 14370 4102
+a 14370 14371 4102
+a 14371 14372 4102
+a 14372 14373 4102
+a 14373 14374 4102
+a 14374 14375 4102
+a 14375 14376 4102
+a 14376 14377 4102
+a 14377 14378 4102
+a 14378 14379 4102
+a 14379 14380 4102
+a 14380 14381 4102
+a 14381 14382 4102
+a 14382 14383 4102
+a 14383 14384 4102
+a 14384 14385 4102
+a 14385 14386 4102
+a 14386 14387 4102
+a 14387 14388 4102
+a 14388 14389 4102
+a 14389 14390 4102
+a 14390 14391 4102
+a 14391 14392 4102
+a 14392 14393 4102
+a 14393 14394 4102
+a 14394 14395 4102
+a 14395 14396 4102
+a 14396 14397 4102
+a 14397 14398 4102
+a 14398 14399 4102
+a 14399 14400 4102
+a 14400 14401 4102
+a 14401 14402 4102
+a 14402 14403 4102
+a 14403 14404 4102
+a 14404 14405 4102
+a 14405 14406 4102
+a 14406 14407 4102
+a 14407 14408 4102
+a 14408 14409 4102
+a 14409 14410 4102
+a 14410 14411 4102
+a 14411 14412 4102
+a 14412 14413 4102
+a 14413 14414 4102
+a 14414 14415 4102
+a 14415 14416 4102
+a 14416 14417 4102
+a 14417 14418 4102
+a 14418 14419 4102
+a 14419 14420 4102
+a 14420 14421 4102
+a 14421 14422 4102
+a 14422 14423 4102
+a 14423 14424 4102
+a 14424 14425 4102
+a 14425 14426 4102
+a 14426 14427 4102
+a 14427 14428 4102
+a 14428 14429 4102
+a 14429 14430 4102
+a 14430 14431 4102
+a 14431 14432 4102
+a 14432 14433 4102
+a 14433 14434 4102
+a 14434 14435 4102
+a 14435 14436 4102
+a 14436 14437 4102
+a 14437 14438 4102
+a 14438 14439 4102
+a 14439 14440 4102
+a 14440 14441 4102
+a 14441 14442 4102
+a 14442 14443 4102
+a 14443 14444 4102
+a 14444 14445 4102
+a 14445 14446 4102
+a 14446 14447 4102
+a 14447 14448 4102
+a 14448 14449 4102
+a 14449 14450 4102
+a 14450 14451 4102
+a 14451 14452 4102
+a 14452 14453 4102
+a 14453 14454 4102
+a 14454 14455 4102
+a 14455 14456 4102
+a 14456 14457 4102
+a 14457 14458 4102
+a 14458 14459 4102
+a 14459 14460 4102
+a 14460 14461 4102
+a 14461 14462 4102
+a 14462 14463 4102
+a 14463 14464 4102
+a 14464 14465 4102
+a 14465 14466 4102
+a 14466 14467 4102
+a 14467 14468 4102
+a 14468 14469 4102
+a 14469 14470 4102
+a 14470 14471 4102
+a 14471 14472 4102
+a 14472 14473 4102
+a 14473 14474 4102
+a 14474 14475 4102
+a 14475 14476 4102
+a 14476 14477 4102
+a 14477 14478 4102
+a 14478 14479 4102
+a 14479 14480 4102
+a 14480 14481 4102
+a 14481 14482 4102
+a 14482 14483 4102
+a 14483 14484 4102
+a 14484 14485 4102
+a 14485 14486 4102
+a 14486 14487 4102
+a 14487 14488 4102
+a 14488 14489 4102
+a 14489 14490 4102
+a 14490 14491 4102
+a 14491 14492 4102
+a 14492 14493 4102
+a 14493 14494 4102
+a 14494 14495 4102
+a 14495 14496 4102
+a 14496 14497 4102
+a 14497 14498 4102
+a 14498 14499 4102
+a 14499 14500 4102
+a 14500 14501 4102
+a 14501 14502 4102
+a 14502 14503 4102
+a 14503 14504 4102
+a 14504 14505 4102
+a 14505 14506 4102
+a 14506 14507 4102
+a 14507 14508 4102
+a 14508 14509 4102
+a 14509 14510 4102
+a 14510 14511 4102
+a 14511 14512 4102
+a 14512 14513 4102
+a 14513 14514 4102
+a 14514 14515 4102
+a 14515 14516 4102
+a 14516 14517 4102
+a 14517 14518 4102
+a 14518 14519 4102
+a 14519 14520 4102
+a 14520 14521 4102
+a 14521 14522 4102
+a 14522 14523 4102
+a 14523 14524 4102
+a 14524 14525 4102
+a 14525 14526 4102
+a 14526 14527 4102
+a 14527 14528 4102
+a 14528 14529 4102
+a 14529 14530 4102
+a 14530 14531 4102
+a 14531 14532 4102
+a 14532 14533 4102
+a 14533 14534 4102
+a 14534 14535 4102
+a 14535 14536 4102
+a 14536 14537 4102
+a 14537 14538 4102
+a 14538 14539 4102
+a 14539 14540 4102
+a 14540 14541 4102
+a 14541 14542 4102
+a 14542 14543 4102
+a 14543 14544 4102
+a 14544 14545 4102
+a 14545 14546 4102
+a 14546 14547 4102
+a 14547 14548 4102
+a 14548 14549 4102
+a 14549 14550 4102
+a 14550 14551 4102
+a 14551 14552 4102
+a 14552 14553 4102
+a 14553 14554 4102
+a 14554 14555 4102
+a 14555 14556 4102
+a 14556 14557 4102
+a 14557 14558 4102
+a 14558 14559 4102
+a 14559 14560 4102
+a 14560 14561 4102
+a 14561 14562 4102
+a 14562 14563 4102
+a 14563 14564 4102
+a 14564 14565 4102
+a 14565 14566 4102
+a 14566 14567 4102
+a 14567 14568 4102
+a 14568 14569 4102
+a 14569 14570 4102
+a 14570 14571 4102
+a 14571 14572 4102
+a 14572 14573 4102
+a 14573 14574 4102
+a 14574 14575 4102
+a 14575 14576 4102
+a 14576 14577 4102
+a 14577 14578 4102
+a 14578 14579 4102
+a 14579 14580 4102
+a 14580 14581 4102
+a 14581 14582 4102
+a 14582 14583 4102
+a 14583 14584 4102
+a 14584 14585 4102
+a 14585 14586 4102
+a 14586 14587 4102
+a 14587 14588 4102
+a 14588 14589 4102
+a 14589 14590 4102
+a 14590 14591 4102
+a 14591 14592 4102
+a 14592 14593 4102
+a 14593 14594 4102
+a 14594 14595 4102
+a 14595 14596 4102
+a 14596 14597 4102
+a 14597 14598 4102
+a 14598 14599 4102
+a 14599 14600 4102
+a 14600 14601 4102
+a 14601 14602 4102
+a 14602 14603 4102
+a 14603 14604 4102
+a 14604 14605 4102
+a 14605 14606 4102
+a 14606 14607 4102
+a 14607 14608 4102
+a 14608 14609 4102
+a 14609 14610 4102
+a 14610 14611 4102
+a 14611 14612 4102
+a 14612 14613 4102
+a 14613 14614 4102
+a 14614 14615 4102
+a 14615 14616 4102
+a 14616 14617 4102
+a 14617 14618 4102
+a 14618 14619 4102
+a 14619 14620 4102
+a 14620 14621 4102
+a 14621 14622 4102
+a 14622 14623 4102
+a 14623 14624 4102
+a 14624 14625 4102
+a 14625 14626 4102
+a 14626 14627 4102
+a 14627 14628 4102
+a 14628 14629 4102
+a 14629 14630 4102
+a 14630 14631 4102
+a 14631 14632 4102
+a 14632 14633 4102
+a 14633 14634 4102
+a 14634 14635 4102
+a 14635 14636 4102
+a 14636 14637 4102
+a 14637 14638 4102
+a 14638 14639 4102
+a 14639 14640 4102
+a 14640 14641 4102
+a 14641 14642 4102
+a 14642 14643 4102
+a 14643 14644 4102
+a 14644 14645 4102
+a 14645 14646 4102
+a 14646 14647 4102
+a 14647 14648 4102
+a 14648 14649 4102
+a 14649 14650 4102
+a 14650 14651 4102
+a 14651 14652 4102
+a 14652 14653 4102
+a 14653 14654 4102
+a 14654 14655 4102
+a 14655 14656 4102
+a 14656 14657 4102
+a 14657 14658 4102
+a 14658 14659 4102
+a 14659 14660 4102
+a 14660 14661 4102
+a 14661 14662 4102
+a 14662 14663 4102
+a 14663 14664 4102
+a 14664 14665 4102
+a 14665 14666 4102
+a 14666 14667 4102
+a 14667 14668 4102
+a 14668 14669 4102
+a 14669 14670 4102
+a 14670 14671 4102
+a 14671 14672 4102
+a 14672 14673 4102
+a 14673 14674 4102
+a 14674 14675 4102
+a 14675 14676 4102
+a 14676 14677 4102
+a 14677 14678 4102
+a 14678 14679 4102
+a 14679 14680 4102
+a 14680 14681 4102
+a 14681 14682 4102
+a 14682 14683 4102
+a 14683 14684 4102
+a 14684 14685 4102
+a 14685 14686 4102
+a 14686 14687 4102
+a 14687 14688 4102
+a 14688 14689 4102
+a 14689 14690 4102
+a 14690 14691 4102
+a 14691 14692 4102
+a 14692 14693 4102
+a 14693 14694 4102
+a 14694 14695 4102
+a 14695 14696 4102
+a 14696 14697 4102
+a 14697 14698 4102
+a 14698 14699 4102
+a 14699 14700 4102
+a 14700 14701 4102
+a 14701 14702 4102
+a 14702 14703 4102
+a 14703 14704 4102
+a 14704 14705 4102
+a 14705 14706 4102
+a 14706 14707 4102
+a 14707 14708 4102
+a 14708 14709 4102
+a 14709 14710 4102
+a 14710 14711 4102
+a 14711 14712 4102
+a 14712 14713 4102
+a 14713 14714 4102
+a 14714 14715 4102
+a 14715 14716 4102
+a 14716 14717 4102
+a 14717 14718 4102
+a 14718 14719 4102
+a 14719 14720 4102
+a 14720 14721 4102
+a 14721 14722 4102
+a 14722 14723 4102
+a 14723 14724 4102
+a 14724 14725 4102
+a 14725 14726 4102
+a 14726 14727 4102
+a 14727 14728 4102
+a 14728 14729 4102
+a 14729 14730 4102
+a 14730 14731 4102
+a 14731 14732 4102
+a 14732 14733 4102
+a 14733 14734 4102
+a 14734 14735 4102
+a 14735 14736 4102
+a 14736 14737 4102
+a 14737 14738 4102
+a 14738 14739 4102
+a 14739 14740 4102
+a 14740 14741 4102
+a 14741 14742 4102
+a 14742 14743 4102
+a 14743 14744 4102
+a 14744 14745 4102
+a 14745 14746 4102
+a 14746 14747 4102
+a 14747 14748 4102
+a 14748 14749 4102
+a 14749 14750 4102
+a 14750 14751 4102
+a 14751 14752 4102
+a 14752 14753 4102
+a 14753 14754 4102
+a 14754 14755 4102
+a 14755 14756 4102
+a 14756 14757 4102
+a 14757 14758 4102
+a 14758 14759 4102
+a 14759 14760 4102
+a 14760 14761 4102
+a 14761 14762 4102
+a 14762 14763 4102
+a 14763 14764 4102
+a 14764 14765 4102
+a 14765 14766 4102
+a 14766 14767 4102
+a 14767 14768 4102
+a 14768 14769 4102
+a 14769 14770 4102
+a 14770 14771 4102
+a 14771 14772 4102
+a 14772 14773 4102
+a 14773 14774 4102
+a 14774 14775 4102
+a 14775 14776 4102
+a 14776 14777 4102
+a 14777 14778 4102
+a 14778 14779 4102
+a 14779 14780 4102
+a 14780 14781 4102
+a 14781 14782 4102
+a 14782 14783 4102
+a 14783 14784 4102
+a 14784 14785 4102
+a 14785 14786 4102
+a 14786 14787 4102
+a 14787 14788 4102
+a 14788 14789 4102
+a 14789 14790 4102
+a 14790 14791 4102
+a 14791 14792 4102
+a 14792 14793 4102
+a 14793 14794 4102
+a 14794 14795 4102
+a 14795 14796 4102
+a 14796 14797 4102
+a 14797 14798 4102
+a 14798 14799 4102
+a 14799 14800 4102
+a 14800 14801 4102
+a 14801 14802 4102
+a 14802 14803 4102
+a 14803 14804 4102
+a 14804 14805 4102
+a 14805 14806 4102
+a 14806 14807 4102
+a 14807 14808 4102
+a 14808 14809 4102
+a 14809 14810 4102
+a 14810 14811 4102
+a 14811 14812 4102
+a 14812 14813 4102
+a 14813 14814 4102
+a 14814 14815 4102
+a 14815 14816 4102
+a 14816 14817 4102
+a 14817 14818 4102
+a 14818 14819 4102
+a 14819 14820 4102
+a 14820 14821 4102
+a 14821 14822 4102
+a 14822 14823 4102
+a 14823 14824 4102
+a 14824 14825 4102
+a 14825 14826 4102
+a 14826 14827 4102
+a 14827 14828 4102
+a 14828 14829 4102
+a 14829 14830 4102
+a 14830 14831 4102
+a 14831 14832 4102
+a 14832 14833 4102
+a 14833 14834 4102
+a 14834 14835 4102
+a 14835 14836 4102
+a 14836 14837 4102
+a 14837 14838 4102
+a 14838 14839 4102
+a 14839 14840 4102
+a 14840 14841 4102
+a 14841 14842 4102
+a 14842 14843 4102
+a 14843 14844 4102
+a 14844 14845 4102
+a 14845 14846 4102
+a 14846 14847 4102
+a 14847 14848 4102
+a 14848 14849 4102
+a 14849 14850 4102
+a 14850 14851 4102
+a 14851 14852 4102
+a 14852 14853 4102
+a 14853 14854 4102
+a 14854 14855 4102
+a 14855 14856 4102
+a 14856 14857 4102
+a 14857 14858 4102
+a 14858 14859 4102
+a 14859 14860 4102
+a 14860 14861 4102
+a 14861 14862 4102
+a 14862 14863 4102
+a 14863 14864 4102
+a 14864 14865 4102
+a 14865 14866 4102
+a 14866 14867 4102
+a 14867 14868 4102
+a 14868 14869 4102
+a 14869 14870 4102
+a 14870 14871 4102
+a 14871 14872 4102
+a 14872 14873 4102
+a 14873 14874 4102
+a 14874 14875 4102
+a 14875 14876 4102
+a 14876 14877 4102
+a 14877 14878 4102
+a 14878 14879 4102
+a 14879 14880 4102
+a 14880 14881 4102
+a 14881 14882 4102
+a 14882 14883 4102
+a 14883 14884 4102
+a 14884 14885 4102
+a 14885 14886 4102
+a 14886 14887 4102
+a 14887 14888 4102
+a 14888 14889 4102
+a 14889 14890 4102
+a 14890 14891 4102
+a 14891 14892 4102
+a 14892 14893 4102
+a 14893 14894 4102
+a 14894 14895 4102
+a 14895 14896 4102
+a 14896 14897 4102
+a 14897 14898 4102
+a 14898 14899 4102
+a 14899 14900 4102
+a 14900 14901 4102
+a 14901 14902 4102
+a 14902 14903 4102
+a 14903 14904 4102
+a 14904 14905 4102
+a 14905 14906 4102
+a 14906 14907 4102
+a 14907 14908 4102
+a 14908 14909 4102
+a 14909 14910 4102
+a 14910 14911 4102
+a 14911 14912 4102
+a 14912 14913 4102
+a 14913 14914 4102
+a 14914 14915 4102
+a 14915 14916 4102
+a 14916 14917 4102
+a 14917 14918 4102
+a 14918 14919 4102
+a 14919 14920 4102
+a 14920 14921 4102
+a 14921 14922 4102
+a 14922 14923 4102
+a 14923 14924 4102
+a 14924 14925 4102
+a 14925 14926 4102
+a 14926 14927 4102
+a 14927 14928 4102
+a 14928 14929 4102
+a 14929 14930 4102
+a 14930 14931 4102
+a 14931 14932 4102
+a 14932 14933 4102
+a 14933 14934 4102
+a 14934 14935 4102
+a 14935 14936 4102
+a 14936 14937 4102
+a 14937 14938 4102
+a 14938 14939 4102
+a 14939 14940 4102
+a 14940 14941 4102
+a 14941 14942 4102
+a 14942 14943 4102
+a 14943 14944 4102
+a 14944 14945 4102
+a 14945 14946 4102
+a 14946 14947 4102
+a 14947 14948 4102
+a 14948 14949 4102
+a 14949 14950 4102
+a 14950 14951 4102
+a 14951 14952 4102
+a 14952 14953 4102
+a 14953 14954 4102
+a 14954 14955 4102
+a 14955 14956 4102
+a 14956 14957 4102
+a 14957 14958 4102
+a 14958 14959 4102
+a 14959 14960 4102
+a 14960 14961 4102
+a 14961 14962 4102
+a 14962 14963 4102
+a 14963 14964 4102
+a 14964 14965 4102
+a 14965 14966 4102
+a 14966 14967 4102
+a 14967 14968 4102
+a 14968 14969 4102
+a 14969 14970 4102
+a 14970 14971 4102
+a 14971 14972 4102
+a 14972 14973 4102
+a 14973 14974 4102
+a 14974 14975 4102
+a 14975 14976 4102
+a 14976 14977 4102
+a 14977 14978 4102
+a 14978 14979 4102
+a 14979 14980 4102
+a 14980 14981 4102
+a 14981 14982 4102
+a 14982 14983 4102
+a 14983 14984 4102
+a 14984 14985 4102
+a 14985 14986 4102
+a 14986 14987 4102
+a 14987 14988 4102
+a 14988 14989 4102
+a 14989 14990 4102
+a 14990 14991 4102
+a 14991 14992 4102
+a 14992 14993 4102
+a 14993 14994 4102
+a 14994 14995 4102
+a 14995 14996 4102
+a 14996 14997 4102
+a 14997 14998 4102
+a 14998 14999 4102
+a 14999 15000 4102
+a 15000 15001 4102
+a 15001 15002 4102
+a 15002 15003 4102
+a 15003 15004 4102
+a 15004 15005 4102
+a 15005 15006 4102
+a 15006 15007 4102
+a 15007 15008 4102
+a 15008 15009 4102
+a 15009 15010 4102
+a 15010 15011 4102
+a 15011 15012 4102
+a 15012 15013 4102
+a 15013 15014 4102
+a 15014 15015 4102
+a 15015 15016 4102
+a 15016 15017 4102
+a 15017 15018 4102
+a 15018 15019 4102
+a 15019 15020 4102
+a 15020 15021 4102
+a 15021 15022 4102
+a 15022 15023 4102
+a 15023 15024 4102
+a 15024 15025 4102
+a 15025 15026 4102
+a 15026 15027 4102
+a 15027 15028 4102
+a 15028 15029 4102
+a 15029 15030 4102
+a 15030 15031 4102
+a 15031 15032 4102
+a 15032 15033 4102
+a 15033 15034 4102
+a 15034 15035 4102
+a 15035 15036 4102
+a 15036 15037 4102
+a 15037 15038 4102
+a 15038 15039 4102
+a 15039 15040 4102
+a 15040 15041 4102
+a 15041 15042 4102
+a 15042 15043 4102
+a 15043 15044 4102
+a 15044 15045 4102
+a 15045 15046 4102
+a 15046 15047 4102
+a 15047 15048 4102
+a 15048 15049 4102
+a 15049 15050 4102
+a 15050 15051 4102
+a 15051 15052 4102
+a 15052 15053 4102
+a 15053 15054 4102
+a 15054 15055 4102
+a 15055 15056 4102
+a 15056 15057 4102
+a 15057 15058 4102
+a 15058 15059 4102
+a 15059 15060 4102
+a 15060 15061 4102
+a 15061 15062 4102
+a 15062 15063 4102
+a 15063 15064 4102
+a 15064 15065 4102
+a 15065 15066 4102
+a 15066 15067 4102
+a 15067 15068 4102
+a 15068 15069 4102
+a 15069 15070 4102
+a 15070 15071 4102
+a 15071 15072 4102
+a 15072 15073 4102
+a 15073 15074 4102
+a 15074 15075 4102
+a 15075 15076 4102
+a 15076 15077 4102
+a 15077 15078 4102
+a 15078 15079 4102
+a 15079 15080 4102
+a 15080 15081 4102
+a 15081 15082 4102
+a 15082 15083 4102
+a 15083 15084 4102
+a 15084 15085 4102
+a 15085 15086 4102
+a 15086 15087 4102
+a 15087 15088 4102
+a 15088 15089 4102
+a 15089 15090 4102
+a 15090 15091 4102
+a 15091 15092 4102
+a 15092 15093 4102
+a 15093 15094 4102
+a 15094 15095 4102
+a 15095 15096 4102
+a 15096 15097 4102
+a 15097 15098 4102
+a 15098 15099 4102
+a 15099 15100 4102
+a 15100 15101 4102
+a 15101 15102 4102
+a 15102 15103 4102
+a 15103 15104 4102
+a 15104 15105 4102
+a 15105 15106 4102
+a 15106 15107 4102
+a 15107 15108 4102
+a 15108 15109 4102
+a 15109 15110 4102
+a 15110 15111 4102
+a 15111 15112 4102
+a 15112 15113 4102
+a 15113 15114 4102
+a 15114 15115 4102
+a 15115 15116 4102
+a 15116 15117 4102
+a 15117 15118 4102
+a 15118 15119 4102
+a 15119 15120 4102
+a 15120 15121 4102
+a 15121 15122 4102
+a 15122 15123 4102
+a 15123 15124 4102
+a 15124 15125 4102
+a 15125 15126 4102
+a 15126 15127 4102
+a 15127 15128 4102
+a 15128 15129 4102
+a 15129 15130 4102
+a 15130 15131 4102
+a 15131 15132 4102
+a 15132 15133 4102
+a 15133 15134 4102
+a 15134 15135 4102
+a 15135 15136 4102
+a 15136 15137 4102
+a 15137 15138 4102
+a 15138 15139 4102
+a 15139 15140 4102
+a 15140 15141 4102
+a 15141 15142 4102
+a 15142 15143 4102
+a 15143 15144 4102
+a 15144 15145 4102
+a 15145 15146 4102
+a 15146 15147 4102
+a 15147 15148 4102
+a 15148 15149 4102
+a 15149 15150 4102
+a 15150 15151 4102
+a 15151 15152 4102
+a 15152 15153 4102
+a 15153 15154 4102
+a 15154 15155 4102
+a 15155 15156 4102
+a 15156 15157 4102
+a 15157 15158 4102
+a 15158 15159 4102
+a 15159 15160 4102
+a 15160 15161 4102
+a 15161 15162 4102
+a 15162 15163 4102
+a 15163 15164 4102
+a 15164 15165 4102
+a 15165 15166 4102
+a 15166 15167 4102
+a 15167 15168 4102
+a 15168 15169 4102
+a 15169 15170 4102
+a 15170 15171 4102
+a 15171 15172 4102
+a 15172 15173 4102
+a 15173 15174 4102
+a 15174 15175 4102
+a 15175 15176 4102
+a 15176 15177 4102
+a 15177 15178 4102
+a 15178 15179 4102
+a 15179 15180 4102
+a 15180 15181 4102
+a 15181 15182 4102
+a 15182 15183 4102
+a 15183 15184 4102
+a 15184 15185 4102
+a 15185 15186 4102
+a 15186 15187 4102
+a 15187 15188 4102
+a 15188 15189 4102
+a 15189 15190 4102
+a 15190 15191 4102
+a 15191 15192 4102
+a 15192 15193 4102
+a 15193 15194 4102
+a 15194 15195 4102
+a 15195 15196 4102
+a 15196 15197 4102
+a 15197 15198 4102
+a 15198 15199 4102
+a 15199 15200 4102
+a 15200 15201 4102
+a 15201 15202 4102
+a 15202 15203 4102
+a 15203 15204 4102
+a 15204 15205 4102
+a 15205 15206 4102
+a 15206 15207 4102
+a 15207 15208 4102
+a 15208 15209 4102
+a 15209 15210 4102
+a 15210 15211 4102
+a 15211 15212 4102
+a 15212 15213 4102
+a 15213 15214 4102
+a 15214 15215 4102
+a 15215 15216 4102
+a 15216 15217 4102
+a 15217 15218 4102
+a 15218 15219 4102
+a 15219 15220 4102
+a 15220 15221 4102
+a 15221 15222 4102
+a 15222 15223 4102
+a 15223 15224 4102
+a 15224 15225 4102
+a 15225 15226 4102
+a 15226 15227 4102
+a 15227 15228 4102
+a 15228 15229 4102
+a 15229 15230 4102
+a 15230 15231 4102
+a 15231 15232 4102
+a 15232 15233 4102
+a 15233 15234 4102
+a 15234 15235 4102
+a 15235 15236 4102
+a 15236 15237 4102
+a 15237 15238 4102
+a 15238 15239 4102
+a 15239 15240 4102
+a 15240 15241 4102
+a 15241 15242 4102
+a 15242 15243 4102
+a 15243 15244 4102
+a 15244 15245 4102
+a 15245 15246 4102
+a 15246 15247 4102
+a 15247 15248 4102
+a 15248 15249 4102
+a 15249 15250 4102
+a 15250 15251 4102
+a 15251 15252 4102
+a 15252 15253 4102
+a 15253 15254 4102
+a 15254 15255 4102
+a 15255 15256 4102
+a 15256 15257 4102
+a 15257 15258 4102
+a 15258 15259 4102
+a 15259 15260 4102
+a 15260 15261 4102
+a 15261 15262 4102
+a 15262 15263 4102
+a 15263 15264 4102
+a 15264 15265 4102
+a 15265 15266 4102
+a 15266 15267 4102
+a 15267 15268 4102
+a 15268 15269 4102
+a 15269 15270 4102
+a 15270 15271 4102
+a 15271 15272 4102
+a 15272 15273 4102
+a 15273 15274 4102
+a 15274 15275 4102
+a 15275 15276 4102
+a 15276 15277 4102
+a 15277 15278 4102
+a 15278 15279 4102
+a 15279 15280 4102
+a 15280 15281 4102
+a 15281 15282 4102
+a 15282 15283 4102
+a 15283 15284 4102
+a 15284 15285 4102
+a 15285 15286 4102
+a 15286 15287 4102
+a 15287 15288 4102
+a 15288 15289 4102
+a 15289 15290 4102
+a 15290 15291 4102
+a 15291 15292 4102
+a 15292 15293 4102
+a 15293 15294 4102
+a 15294 15295 4102
+a 15295 15296 4102
+a 15296 15297 4102
+a 15297 15298 4102
+a 15298 15299 4102
+a 15299 15300 4102
+a 15300 15301 4102
+a 15301 15302 4102
+a 15302 15303 4102
+a 15303 15304 4102
+a 15304 15305 4102
+a 15305 15306 4102
+a 15306 15307 4102
+a 15307 15308 4102
+a 15308 15309 4102
+a 15309 15310 4102
+a 15310 15311 4102
+a 15311 15312 4102
+a 15312 15313 4102
+a 15313 15314 4102
+a 15314 15315 4102
+a 15315 15316 4102
+a 15316 15317 4102
+a 15317 15318 4102
+a 15318 15319 4102
+a 15319 15320 4102
+a 15320 15321 4102
+a 15321 15322 4102
+a 15322 15323 4102
+a 15323 15324 4102
+a 15324 15325 4102
+a 15325 15326 4102
+a 15326 15327 4102
+a 15327 15328 4102
+a 15328 15329 4102
+a 15329 15330 4102
+a 15330 15331 4102
+a 15331 15332 4102
+a 15332 15333 4102
+a 15333 15334 4102
+a 15334 15335 4102
+a 15335 15336 4102
+a 15336 15337 4102
+a 15337 15338 4102
+a 15338 15339 4102
+a 15339 15340 4102
+a 15340 15341 4102
+a 15341 15342 4102
+a 15342 15343 4102
+a 15343 15344 4102
+a 15344 15345 4102
+a 15345 15346 4102
+a 15346 15347 4102
+a 15347 15348 4102
+a 15348 15349 4102
+a 15349 15350 4102
+a 15350 15351 4102
+a 15351 15352 4102
+a 15352 15353 4102
+a 15353 15354 4102
+a 15354 15355 4102
+a 15355 15356 4102
+a 15356 15357 4102
+a 15357 15358 4102
+a 15358 15359 4102
+a 15359 15360 4102
+a 15360 15361 4102
+a 15361 15362 4102
+a 15362 15363 4102
+a 15363 15364 4102
+a 15364 15365 4102
+a 15365 15366 4102
+a 15366 15367 4102
+a 15367 15368 4102
+a 15368 15369 4102
+a 15369 15370 4102
+a 15370 15371 4102
+a 15371 15372 4102
+a 15372 15373 4102
+a 15373 15374 4102
+a 15374 15375 4102
+a 15375 15376 4102
+a 15376 15377 4102
+a 15377 15378 4102
+a 15378 15379 4102
+a 15379 15380 4102
+a 15380 15381 4102
+a 15381 15382 4102
+a 15382 15383 4102
+a 15383 15384 4102
+a 15384 15385 4102
+a 15385 15386 4102
+a 15386 15387 4102
+a 15387 15388 4102
+a 15388 15389 4102
+a 15389 15390 4102
+a 15390 15391 4102
+a 15391 15392 4102
+a 15392 15393 4102
+a 15393 15394 4102
+a 15394 15395 4102
+a 15395 15396 4102
+a 15396 15397 4102
+a 15397 15398 4102
+a 15398 15399 4102
+a 15399 15400 4102
+a 15400 15401 4102
+a 15401 15402 4102
+a 15402 15403 4102
+a 15403 15404 4102
+a 15404 15405 4102
+a 15405 15406 4102
+a 15406 15407 4102
+a 15407 15408 4102
+a 15408 15409 4102
+a 15409 15410 4102
+a 15410 15411 4102
+a 15411 15412 4102
+a 15412 15413 4102
+a 15413 15414 4102
+a 15414 15415 4102
+a 15415 15416 4102
+a 15416 15417 4102
+a 15417 15418 4102
+a 15418 15419 4102
+a 15419 15420 4102
+a 15420 15421 4102
+a 15421 15422 4102
+a 15422 15423 4102
+a 15423 15424 4102
+a 15424 15425 4102
+a 15425 15426 4102
+a 15426 15427 4102
+a 15427 15428 4102
+a 15428 15429 4102
+a 15429 15430 4102
+a 15430 15431 4102
+a 15431 15432 4102
+a 15432 15433 4102
+a 15433 15434 4102
+a 15434 15435 4102
+a 15435 15436 4102
+a 15436 15437 4102
+a 15437 15438 4102
+a 15438 15439 4102
+a 15439 15440 4102
+a 15440 15441 4102
+a 15441 15442 4102
+a 15442 15443 4102
+a 15443 15444 4102
+a 15444 15445 4102
+a 15445 15446 4102
+a 15446 15447 4102
+a 15447 15448 4102
+a 15448 15449 4102
+a 15449 15450 4102
+a 15450 15451 4102
+a 15451 15452 4102
+a 15452 15453 4102
+a 15453 15454 4102
+a 15454 15455 4102
+a 15455 15456 4102
+a 15456 15457 4102
+a 15457 15458 4102
+a 15458 15459 4102
+a 15459 15460 4102
+a 15460 15461 4102
+a 15461 15462 4102
+a 15462 15463 4102
+a 15463 15464 4102
+a 15464 15465 4102
+a 15465 15466 4102
+a 15466 15467 4102
+a 15467 15468 4102
+a 15468 15469 4102
+a 15469 15470 4102
+a 15470 15471 4102
+a 15471 15472 4102
+a 15472 15473 4102
+a 15473 15474 4102
+a 15474 15475 4102
+a 15475 15476 4102
+a 15476 15477 4102
+a 15477 15478 4102
+a 15478 15479 4102
+a 15479 15480 4102
+a 15480 15481 4102
+a 15481 15482 4102
+a 15482 15483 4102
+a 15483 15484 4102
+a 15484 15485 4102
+a 15485 15486 4102
+a 15486 15487 4102
+a 15487 15488 4102
+a 15488 15489 4102
+a 15489 15490 4102
+a 15490 15491 4102
+a 15491 15492 4102
+a 15492 15493 4102
+a 15493 15494 4102
+a 15494 15495 4102
+a 15495 15496 4102
+a 15496 15497 4102
+a 15497 15498 4102
+a 15498 15499 4102
+a 15499 15500 4102
+a 15500 15501 4102
+a 15501 15502 4102
+a 15502 15503 4102
+a 15503 15504 4102
+a 15504 15505 4102
+a 15505 15506 4102
+a 15506 15507 4102
+a 15507 15508 4102
+a 15508 15509 4102
+a 15509 15510 4102
+a 15510 15511 4102
+a 15511 15512 4102
+a 15512 15513 4102
+a 15513 15514 4102
+a 15514 15515 4102
+a 15515 15516 4102
+a 15516 15517 4102
+a 15517 15518 4102
+a 15518 15519 4102
+a 15519 15520 4102
+a 15520 15521 4102
+a 15521 15522 4102
+a 15522 15523 4102
+a 15523 15524 4102
+a 15524 15525 4102
+a 15525 15526 4102
+a 15526 15527 4102
+a 15527 15528 4102
+a 15528 15529 4102
+a 15529 15530 4102
+a 15530 15531 4102
+a 15531 15532 4102
+a 15532 15533 4102
+a 15533 15534 4102
+a 15534 15535 4102
+a 15535 15536 4102
+a 15536 15537 4102
+a 15537 15538 4102
+a 15538 15539 4102
+a 15539 15540 4102
+a 15540 15541 4102
+a 15541 15542 4102
+a 15542 15543 4102
+a 15543 15544 4102
+a 15544 15545 4102
+a 15545 15546 4102
+a 15546 15547 4102
+a 15547 15548 4102
+a 15548 15549 4102
+a 15549 15550 4102
+a 15550 15551 4102
+a 15551 15552 4102
+a 15552 15553 4102
+a 15553 15554 4102
+a 15554 15555 4102
+a 15555 15556 4102
+a 15556 15557 4102
+a 15557 15558 4102
+a 15558 15559 4102
+a 15559 15560 4102
+a 15560 15561 4102
+a 15561 15562 4102
+a 15562 15563 4102
+a 15563 15564 4102
+a 15564 15565 4102
+a 15565 15566 4102
+a 15566 15567 4102
+a 15567 15568 4102
+a 15568 15569 4102
+a 15569 15570 4102
+a 15570 15571 4102
+a 15571 15572 4102
+a 15572 15573 4102
+a 15573 15574 4102
+a 15574 15575 4102
+a 15575 15576 4102
+a 15576 15577 4102
+a 15577 15578 4102
+a 15578 15579 4102
+a 15579 15580 4102
+a 15580 15581 4102
+a 15581 15582 4102
+a 15582 15583 4102
+a 15583 15584 4102
+a 15584 15585 4102
+a 15585 15586 4102
+a 15586 15587 4102
+a 15587 15588 4102
+a 15588 15589 4102
+a 15589 15590 4102
+a 15590 15591 4102
+a 15591 15592 4102
+a 15592 15593 4102
+a 15593 15594 4102
+a 15594 15595 4102
+a 15595 15596 4102
+a 15596 15597 4102
+a 15597 15598 4102
+a 15598 15599 4102
+a 15599 15600 4102
+a 15600 15601 4102
+a 15601 15602 4102
+a 15602 15603 4102
+a 15603 15604 4102
+a 15604 15605 4102
+a 15605 15606 4102
+a 15606 15607 4102
+a 15607 15608 4102
+a 15608 15609 4102
+a 15609 15610 4102
+a 15610 15611 4102
+a 15611 15612 4102
+a 15612 15613 4102
+a 15613 15614 4102
+a 15614 15615 4102
+a 15615 15616 4102
+a 15616 15617 4102
+a 15617 15618 4102
+a 15618 15619 4102
+a 15619 15620 4102
+a 15620 15621 4102
+a 15621 15622 4102
+a 15622 15623 4102
+a 15623 15624 4102
+a 15624 15625 4102
+a 15625 15626 4102
+a 15626 15627 4102
+a 15627 15628 4102
+a 15628 15629 4102
+a 15629 15630 4102
+a 15630 15631 4102
+a 15631 15632 4102
+a 15632 15633 4102
+a 15633 15634 4102
+a 15634 15635 4102
+a 15635 15636 4102
+a 15636 15637 4102
+a 15637 15638 4102
+a 15638 15639 4102
+a 15639 15640 4102
+a 15640 15641 4102
+a 15641 15642 4102
+a 15642 15643 4102
+a 15643 15644 4102
+a 15644 15645 4102
+a 15645 15646 4102
+a 15646 15647 4102
+a 15647 15648 4102
+a 15648 15649 4102
+a 15649 15650 4102
+a 15650 15651 4102
+a 15651 15652 4102
+a 15652 15653 4102
+a 15653 15654 4102
+a 15654 15655 4102
+a 15655 15656 4102
+a 15656 15657 4102
+a 15657 15658 4102
+a 15658 15659 4102
+a 15659 15660 4102
+a 15660 15661 4102
+a 15661 15662 4102
+a 15662 15663 4102
+a 15663 15664 4102
+a 15664 15665 4102
+a 15665 15666 4102
+a 15666 15667 4102
+a 15667 15668 4102
+a 15668 15669 4102
+a 15669 15670 4102
+a 15670 15671 4102
+a 15671 15672 4102
+a 15672 15673 4102
+a 15673 15674 4102
+a 15674 15675 4102
+a 15675 15676 4102
+a 15676 15677 4102
+a 15677 15678 4102
+a 15678 15679 4102
+a 15679 15680 4102
+a 15680 15681 4102
+a 15681 15682 4102
+a 15682 15683 4102
+a 15683 15684 4102
+a 15684 15685 4102
+a 15685 15686 4102
+a 15686 15687 4102
+a 15687 15688 4102
+a 15688 15689 4102
+a 15689 15690 4102
+a 15690 15691 4102
+a 15691 15692 4102
+a 15692 15693 4102
+a 15693 15694 4102
+a 15694 15695 4102
+a 15695 15696 4102
+a 15696 15697 4102
+a 15697 15698 4102
+a 15698 15699 4102
+a 15699 15700 4102
+a 15700 15701 4102
+a 15701 15702 4102
+a 15702 15703 4102
+a 15703 15704 4102
+a 15704 15705 4102
+a 15705 15706 4102
+a 15706 15707 4102
+a 15707 15708 4102
+a 15708 15709 4102
+a 15709 15710 4102
+a 15710 15711 4102
+a 15711 15712 4102
+a 15712 15713 4102
+a 15713 15714 4102
+a 15714 15715 4102
+a 15715 15716 4102
+a 15716 15717 4102
+a 15717 15718 4102
+a 15718 15719 4102
+a 15719 15720 4102
+a 15720 15721 4102
+a 15721 15722 4102
+a 15722 15723 4102
+a 15723 15724 4102
+a 15724 15725 4102
+a 15725 15726 4102
+a 15726 15727 4102
+a 15727 15728 4102
+a 15728 15729 4102
+a 15729 15730 4102
+a 15730 15731 4102
+a 15731 15732 4102
+a 15732 15733 4102
+a 15733 15734 4102
+a 15734 15735 4102
+a 15735 15736 4102
+a 15736 15737 4102
+a 15737 15738 4102
+a 15738 15739 4102
+a 15739 15740 4102
+a 15740 15741 4102
+a 15741 15742 4102
+a 15742 15743 4102
+a 15743 15744 4102
+a 15744 15745 4102
+a 15745 15746 4102
+a 15746 15747 4102
+a 15747 15748 4102
+a 15748 15749 4102
+a 15749 15750 4102
+a 15750 15751 4102
+a 15751 15752 4102
+a 15752 15753 4102
+a 15753 15754 4102
+a 15754 15755 4102
+a 15755 15756 4102
+a 15756 15757 4102
+a 15757 15758 4102
+a 15758 15759 4102
+a 15759 15760 4102
+a 15760 15761 4102
+a 15761 15762 4102
+a 15762 15763 4102
+a 15763 15764 4102
+a 15764 15765 4102
+a 15765 15766 4102
+a 15766 15767 4102
+a 15767 15768 4102
+a 15768 15769 4102
+a 15769 15770 4102
+a 15770 15771 4102
+a 15771 15772 4102
+a 15772 15773 4102
+a 15773 15774 4102
+a 15774 15775 4102
+a 15775 15776 4102
+a 15776 15777 4102
+a 15777 15778 4102
+a 15778 15779 4102
+a 15779 15780 4102
+a 15780 15781 4102
+a 15781 15782 4102
+a 15782 15783 4102
+a 15783 15784 4102
+a 15784 15785 4102
+a 15785 15786 4102
+a 15786 15787 4102
+a 15787 15788 4102
+a 15788 15789 4102
+a 15789 15790 4102
+a 15790 15791 4102
+a 15791 15792 4102
+a 15792 15793 4102
+a 15793 15794 4102
+a 15794 15795 4102
+a 15795 15796 4102
+a 15796 15797 4102
+a 15797 15798 4102
+a 15798 15799 4102
+a 15799 15800 4102
+a 15800 15801 4102
+a 15801 15802 4102
+a 15802 15803 4102
+a 15803 15804 4102
+a 15804 15805 4102
+a 15805 15806 4102
+a 15806 15807 4102
+a 15807 15808 4102
+a 15808 15809 4102
+a 15809 15810 4102
+a 15810 15811 4102
+a 15811 15812 4102
+a 15812 15813 4102
+a 15813 15814 4102
+a 15814 15815 4102
+a 15815 15816 4102
+a 15816 15817 4102
+a 15817 15818 4102
+a 15818 15819 4102
+a 15819 15820 4102
+a 15820 15821 4102
+a 15821 15822 4102
+a 15822 15823 4102
+a 15823 15824 4102
+a 15824 15825 4102
+a 15825 15826 4102
+a 15826 15827 4102
+a 15827 15828 4102
+a 15828 15829 4102
+a 15829 15830 4102
+a 15830 15831 4102
+a 15831 15832 4102
+a 15832 15833 4102
+a 15833 15834 4102
+a 15834 15835 4102
+a 15835 15836 4102
+a 15836 15837 4102
+a 15837 15838 4102
+a 15838 15839 4102
+a 15839 15840 4102
+a 15840 15841 4102
+a 15841 15842 4102
+a 15842 15843 4102
+a 15843 15844 4102
+a 15844 15845 4102
+a 15845 15846 4102
+a 15846 15847 4102
+a 15847 15848 4102
+a 15848 15849 4102
+a 15849 15850 4102
+a 15850 15851 4102
+a 15851 15852 4102
+a 15852 15853 4102
+a 15853 15854 4102
+a 15854 15855 4102
+a 15855 15856 4102
+a 15856 15857 4102
+a 15857 15858 4102
+a 15858 15859 4102
+a 15859 15860 4102
+a 15860 15861 4102
+a 15861 15862 4102
+a 15862 15863 4102
+a 15863 15864 4102
+a 15864 15865 4102
+a 15865 15866 4102
+a 15866 15867 4102
+a 15867 15868 4102
+a 15868 15869 4102
+a 15869 15870 4102
+a 15870 15871 4102
+a 15871 15872 4102
+a 15872 15873 4102
+a 15873 15874 4102
+a 15874 15875 4102
+a 15875 15876 4102
+a 15876 15877 4102
+a 15877 15878 4102
+a 15878 15879 4102
+a 15879 15880 4102
+a 15880 15881 4102
+a 15881 15882 4102
+a 15882 15883 4102
+a 15883 15884 4102
+a 15884 15885 4102
+a 15885 15886 4102
+a 15886 15887 4102
+a 15887 15888 4102
+a 15888 15889 4102
+a 15889 15890 4102
+a 15890 15891 4102
+a 15891 15892 4102
+a 15892 15893 4102
+a 15893 15894 4102
+a 15894 15895 4102
+a 15895 15896 4102
+a 15896 15897 4102
+a 15897 15898 4102
+a 15898 15899 4102
+a 15899 15900 4102
+a 15900 15901 4102
+a 15901 15902 4102
+a 15902 15903 4102
+a 15903 15904 4102
+a 15904 15905 4102
+a 15905 15906 4102
+a 15906 15907 4102
+a 15907 15908 4102
+a 15908 15909 4102
+a 15909 15910 4102
+a 15910 15911 4102
+a 15911 15912 4102
+a 15912 15913 4102
+a 15913 15914 4102
+a 15914 15915 4102
+a 15915 15916 4102
+a 15916 15917 4102
+a 15917 15918 4102
+a 15918 15919 4102
+a 15919 15920 4102
+a 15920 15921 4102
+a 15921 15922 4102
+a 15922 15923 4102
+a 15923 15924 4102
+a 15924 15925 4102
+a 15925 15926 4102
+a 15926 15927 4102
+a 15927 15928 4102
+a 15928 15929 4102
+a 15929 15930 4102
+a 15930 15931 4102
+a 15931 15932 4102
+a 15932 15933 4102
+a 15933 15934 4102
+a 15934 15935 4102
+a 15935 15936 4102
+a 15936 15937 4102
+a 15937 15938 4102
+a 15938 15939 4102
+a 15939 15940 4102
+a 15940 15941 4102
+a 15941 15942 4102
+a 15942 15943 4102
+a 15943 15944 4102
+a 15944 15945 4102
+a 15945 15946 4102
+a 15946 15947 4102
+a 15947 15948 4102
+a 15948 15949 4102
+a 15949 15950 4102
+a 15950 15951 4102
+a 15951 15952 4102
+a 15952 15953 4102
+a 15953 15954 4102
+a 15954 15955 4102
+a 15955 15956 4102
+a 15956 15957 4102
+a 15957 15958 4102
+a 15958 15959 4102
+a 15959 15960 4102
+a 15960 15961 4102
+a 15961 15962 4102
+a 15962 15963 4102
+a 15963 15964 4102
+a 15964 15965 4102
+a 15965 15966 4102
+a 15966 15967 4102
+a 15967 15968 4102
+a 15968 15969 4102
+a 15969 15970 4102
+a 15970 15971 4102
+a 15971 15972 4102
+a 15972 15973 4102
+a 15973 15974 4102
+a 15974 15975 4102
+a 15975 15976 4102
+a 15976 15977 4102
+a 15977 15978 4102
+a 15978 15979 4102
+a 15979 15980 4102
+a 15980 15981 4102
+a 15981 15982 4102
+a 15982 15983 4102
+a 15983 15984 4102
+a 15984 15985 4102
+a 15985 15986 4102
+a 15986 15987 4102
+a 15987 15988 4102
+a 15988 15989 4102
+a 15989 15990 4102
+a 15990 15991 4102
+a 15991 15992 4102
+a 15992 15993 4102
+a 15993 15994 4102
+a 15994 15995 4102
+a 15995 15996 4102
+a 15996 15997 4102
+a 15997 15998 4102
+a 15998 15999 4102
+a 15999 16000 4102
+a 16000 16001 4102
+a 16001 16002 4102
+a 16002 16003 4102
+a 16003 16004 4102
+a 16004 16005 4102
+a 16005 16006 4102
+a 16006 16007 4102
+a 16007 16008 4102
+a 16008 16009 4102
+a 16009 16010 4102
+a 16010 16011 4102
+a 16011 16012 4102
+a 16012 16013 4102
+a 16013 16014 4102
+a 16014 16015 4102
+a 16015 16016 4102
+a 16016 16017 4102
+a 16017 16018 4102
+a 16018 16019 4102
+a 16019 16020 4102
+a 16020 16021 4102
+a 16021 16022 4102
+a 16022 16023 4102
+a 16023 16024 4102
+a 16024 16025 4102
+a 16025 16026 4102
+a 16026 16027 4102
+a 16027 16028 4102
+a 16028 16029 4102
+a 16029 16030 4102
+a 16030 16031 4102
+a 16031 16032 4102
+a 16032 16033 4102
+a 16033 16034 4102
+a 16034 16035 4102
+a 16035 16036 4102
+a 16036 16037 4102
+a 16037 16038 4102
+a 16038 16039 4102
+a 16039 16040 4102
+a 16040 16041 4102
+a 16041 16042 4102
+a 16042 16043 4102
+a 16043 16044 4102
+a 16044 16045 4102
+a 16045 16046 4102
+a 16046 16047 4102
+a 16047 16048 4102
+a 16048 16049 4102
+a 16049 16050 4102
+a 16050 16051 4102
+a 16051 16052 4102
+a 16052 16053 4102
+a 16053 16054 4102
+a 16054 16055 4102
+a 16055 16056 4102
+a 16056 16057 4102
+a 16057 16058 4102
+a 16058 16059 4102
+a 16059 16060 4102
+a 16060 16061 4102
+a 16061 16062 4102
+a 16062 16063 4102
+a 16063 16064 4102
+a 16064 16065 4102
+a 16065 16066 4102
+a 16066 16067 4102
+a 16067 16068 4102
+a 16068 16069 4102
+a 16069 16070 4102
+a 16070 16071 4102
+a 16071 16072 4102
+a 16072 16073 4102
+a 16073 16074 4102
+a 16074 16075 4102
+a 16075 16076 4102
+a 16076 16077 4102
+a 16077 16078 4102
+a 16078 16079 4102
+a 16079 16080 4102
+a 16080 16081 4102
+a 16081 16082 4102
+a 16082 16083 4102
+a 16083 16084 4102
+a 16084 16085 4102
+a 16085 16086 4102
+a 16086 16087 4102
+a 16087 16088 4102
+a 16088 16089 4102
+a 16089 16090 4102
+a 16090 16091 4102
+a 16091 16092 4102
+a 16092 16093 4102
+a 16093 16094 4102
+a 16094 16095 4102
+a 16095 16096 4102
+a 16096 16097 4102
+a 16097 16098 4102
+a 16098 16099 4102
+a 16099 16100 4102
+a 16100 16101 4102
+a 16101 16102 4102
+a 16102 16103 4102
+a 16103 16104 4102
+a 16104 16105 4102
+a 16105 16106 4102
+a 16106 16107 4102
+a 16107 16108 4102
+a 16108 16109 4102
+a 16109 16110 4102
+a 16110 16111 4102
+a 16111 16112 4102
+a 16112 16113 4102
+a 16113 16114 4102
+a 16114 16115 4102
+a 16115 16116 4102
+a 16116 16117 4102
+a 16117 16118 4102
+a 16118 16119 4102
+a 16119 16120 4102
+a 16120 16121 4102
+a 16121 16122 4102
+a 16122 16123 4102
+a 16123 16124 4102
+a 16124 16125 4102
+a 16125 16126 4102
+a 16126 16127 4102
+a 16127 16128 4102
+a 16128 16129 4102
+a 16129 16130 4102
+a 16130 16131 4102
+a 16131 16132 4102
+a 16132 16133 4102
+a 16133 16134 4102
+a 16134 16135 4102
+a 16135 16136 4102
+a 16136 16137 4102
+a 16137 16138 4102
+a 16138 16139 4102
+a 16139 16140 4102
+a 16140 16141 4102
+a 16141 16142 4102
+a 16142 16143 4102
+a 16143 16144 4102
+a 16144 16145 4102
+a 16145 16146 4102
+a 16146 16147 4102
+a 16147 16148 4102
+a 16148 16149 4102
+a 16149 16150 4102
+a 16150 16151 4102
+a 16151 16152 4102
+a 16152 16153 4102
+a 16153 16154 4102
+a 16154 16155 4102
+a 16155 16156 4102
+a 16156 16157 4102
+a 16157 16158 4102
+a 16158 16159 4102
+a 16159 16160 4102
+a 16160 16161 4102
+a 16161 16162 4102
+a 16162 16163 4102
+a 16163 16164 4102
+a 16164 16165 4102
+a 16165 16166 4102
+a 16166 16167 4102
+a 16167 16168 4102
+a 16168 16169 4102
+a 16169 16170 4102
+a 16170 16171 4102
+a 16171 16172 4102
+a 16172 16173 4102
+a 16173 16174 4102
+a 16174 16175 4102
+a 16175 16176 4102
+a 16176 16177 4102
+a 16177 16178 4102
+a 16178 16179 4102
+a 16179 16180 4102
+a 16180 16181 4102
+a 16181 16182 4102
+a 16182 16183 4102
+a 16183 16184 4102
+a 16184 16185 4102
+a 16185 16186 4102
+a 16186 16187 4102
+a 16187 16188 4102
+a 16188 16189 4102
+a 16189 16190 4102
+a 16190 16191 4102
+a 16191 16192 4102
+a 16192 16193 4102
+a 16193 16194 4102
+a 16194 16195 4102
+a 16195 16196 4102
+a 16196 16197 4102
+a 16197 16198 4102
+a 16198 16199 4102
+a 16199 16200 4102
+a 16200 16201 4102
+a 16201 16202 4102
+a 16202 16203 4102
+a 16203 16204 4102
+a 16204 16205 4102
+a 16205 16206 4102
+a 16206 16207 4102
+a 16207 16208 4102
+a 16208 16209 4102
+a 16209 16210 4102
+a 16210 16211 4102
+a 16211 16212 4102
+a 16212 16213 4102
+a 16213 16214 4102
+a 16214 16215 4102
+a 16215 16216 4102
+a 16216 16217 4102
+a 16217 16218 4102
+a 16218 16219 4102
+a 16219 16220 4102
+a 16220 16221 4102
+a 16221 16222 4102
+a 16222 16223 4102
+a 16223 16224 4102
+a 16224 16225 4102
+a 16225 16226 4102
+a 16226 16227 4102
+a 16227 16228 4102
+a 16228 16229 4102
+a 16229 16230 4102
+a 16230 16231 4102
+a 16231 16232 4102
+a 16232 16233 4102
+a 16233 16234 4102
+a 16234 16235 4102
+a 16235 16236 4102
+a 16236 16237 4102
+a 16237 16238 4102
+a 16238 16239 4102
+a 16239 16240 4102
+a 16240 16241 4102
+a 16241 16242 4102
+a 16242 16243 4102
+a 16243 16244 4102
+a 16244 16245 4102
+a 16245 16246 4102
+a 16246 16247 4102
+a 16247 16248 4102
+a 16248 16249 4102
+a 16249 16250 4102
+a 16250 16251 4102
+a 16251 16252 4102
+a 16252 16253 4102
+a 16253 16254 4102
+a 16254 16255 4102
+a 16255 16256 4102
+a 16256 16257 4102
+a 16257 16258 4102
+a 16258 16259 4102
+a 16259 16260 4102
+a 16260 16261 4102
+a 16261 16262 4102
+a 16262 16263 4102
+a 16263 16264 4102
+a 16264 16265 4102
+a 16265 16266 4102
+a 16266 16267 4102
+a 16267 16268 4102
+a 16268 16269 4102
+a 16269 16270 4102
+a 16270 16271 4102
+a 16271 16272 4102
+a 16272 16273 4102
+a 16273 16274 4102
+a 16274 16275 4102
+a 16275 16276 4102
+a 16276 16277 4102
+a 16277 16278 4102
+a 16278 16279 4102
+a 16279 16280 4102
+a 16280 16281 4102
+a 16281 16282 4102
+a 16282 16283 4102
+a 16283 16284 4102
+a 16284 16285 4102
+a 16285 16286 4102
+a 16286 16287 4102
+a 16287 16288 4102
+a 16288 16289 4102
+a 16289 16290 4102
+a 16290 16291 4102
+a 16291 16292 4102
+a 16292 16293 4102
+a 16293 16294 4102
+a 16294 16295 4102
+a 16295 16296 4102
+a 16296 16297 4102
+a 16297 16298 4102
+a 16298 16299 4102
+a 16299 16300 4102
+a 16300 16301 4102
+a 16301 16302 4102
+a 16302 16303 4102
+a 16303 16304 4102
+a 16304 16305 4102
+a 16305 16306 4102
+a 16306 16307 4102
+a 16307 16308 4102
+a 16308 16309 4102
+a 16309 16310 4102
+a 16310 16311 4102
+a 16311 16312 4102
+a 16312 16313 4102
+a 16313 16314 4102
+a 16314 16315 4102
+a 16315 16316 4102
+a 16316 16317 4102
+a 16317 16318 4102
+a 16318 16319 4102
+a 16319 16320 4102
+a 16320 16321 4102
+a 16321 16322 4102
+a 16322 16323 4102
+a 16323 16324 4102
+a 16324 16325 4102
+a 16325 16326 4102
+a 16326 16327 4102
+a 16327 16328 4102
+a 16328 16329 4102
+a 16329 16330 4102
+a 16330 16331 4102
+a 16331 16332 4102
+a 16332 16333 4102
+a 16333 16334 4102
+a 16334 16335 4102
+a 16335 16336 4102
+a 16336 16337 4102
+a 16337 16338 4102
+a 16338 16339 4102
+a 16339 16340 4102
+a 16340 16341 4102
+a 16341 16342 4102
+a 16342 16343 4102
+a 16343 16344 4102
+a 16344 16345 4102
+a 16345 16346 4102
+a 16346 16347 4102
+a 16347 16348 4102
+a 16348 16349 4102
+a 16349 16350 4102
+a 16350 16351 4102
+a 16351 16352 4102
+a 16352 16353 4102
+a 16353 16354 4102
+a 16354 16355 4102
+a 16355 16356 4102
+a 16356 16357 4102
+a 16357 16358 4102
+a 16358 16359 4102
+a 16359 16360 4102
+a 16360 16361 4102
+a 16361 16362 4102
+a 16362 16363 4102
+a 16363 16364 4102
+a 16364 16365 4102
+a 16365 16366 4102
+a 16366 16367 4102
+a 16367 16368 4102
+a 16368 16369 4102
+a 16369 16370 4102
+a 16370 16371 4102
+a 16371 16372 4102
+a 16372 16373 4102
+a 16373 16374 4102
+a 16374 16375 4102
+a 16375 16376 4102
+a 16376 16377 4102
+a 16377 16378 4102
+a 16378 16379 4102
+a 16379 16380 4102
+a 16380 16381 4102
+a 16381 16382 4102
+a 16382 16383 4102
+a 16383 16384 4102
+a 16384 16385 4102
+a 16385 16386 4102
+a 16386 16387 4102
+a 16387 16388 4102
+a 16388 16389 4102
+a 16389 16390 4102
+a 16390 16391 4102
+a 16391 16392 4102
+a 16392 16393 4102
+a 16393 16394 4102
+a 16394 16395 4102
+a 16395 16396 4102
+a 16396 16397 4102
+a 16397 16398 4102
+a 16398 16399 4102
+a 16399 16400 4102
+a 16400 16401 4102
+a 16401 16402 4102
+a 16402 16403 4102
+a 16403 16404 4102
+a 16404 16405 4102
+a 16405 16406 4102
+a 16406 16407 4102
+a 16407 16408 4102
+a 16408 16409 4102
+a 16409 16410 4102
+a 16410 16411 4102
+a 16411 16412 4102
+a 16412 16413 4102
+a 16413 16414 4102
+a 8209 16414 1
+a 8210 16413 1
+a 8211 16412 1
+a 8212 16411 1
+a 8213 16410 1
+a 8214 16409 1
+a 8215 16408 1
+a 8216 16407 1
+a 8217 16406 1
+a 8218 16405 1
+a 8219 16404 1
+a 8220 16403 1
+a 8221 16402 1
+a 8222 16401 1
+a 8223 16400 1
+a 8224 16399 1
+a 8225 16398 1
+a 8226 16397 1
+a 8227 16396 1
+a 8228 16395 1
+a 8229 16394 1
+a 8230 16393 1
+a 8231 16392 1
+a 8232 16391 1
+a 8233 16390 1
+a 8234 16389 1
+a 8235 16388 1
+a 8236 16387 1
+a 8237 16386 1
+a 8238 16385 1
+a 8239 16384 1
+a 8240 16383 1
+a 8241 16382 1
+a 8242 16381 1
+a 8243 16380 1
+a 8244 16379 1
+a 8245 16378 1
+a 8246 16377 1
+a 8247 16376 1
+a 8248 16375 1
+a 8249 16374 1
+a 8250 16373 1
+a 8251 16372 1
+a 8252 16371 1
+a 8253 16370 1
+a 8254 16369 1
+a 8255 16368 1
+a 8256 16367 1
+a 8257 16366 1
+a 8258 16365 1
+a 8259 16364 1
+a 8260 16363 1
+a 8261 16362 1
+a 8262 16361 1
+a 8263 16360 1
+a 8264 16359 1
+a 8265 16358 1
+a 8266 16357 1
+a 8267 16356 1
+a 8268 16355 1
+a 8269 16354 1
+a 8270 16353 1
+a 8271 16352 1
+a 8272 16351 1
+a 8273 16350 1
+a 8274 16349 1
+a 8275 16348 1
+a 8276 16347 1
+a 8277 16346 1
+a 8278 16345 1
+a 8279 16344 1
+a 8280 16343 1
+a 8281 16342 1
+a 8282 16341 1
+a 8283 16340 1
+a 8284 16339 1
+a 8285 16338 1
+a 8286 16337 1
+a 8287 16336 1
+a 8288 16335 1
+a 8289 16334 1
+a 8290 16333 1
+a 8291 16332 1
+a 8292 16331 1
+a 8293 16330 1
+a 8294 16329 1
+a 8295 16328 1
+a 8296 16327 1
+a 8297 16326 1
+a 8298 16325 1
+a 8299 16324 1
+a 8300 16323 1
+a 8301 16322 1
+a 8302 16321 1
+a 8303 16320 1
+a 8304 16319 1
+a 8305 16318 1
+a 8306 16317 1
+a 8307 16316 1
+a 8308 16315 1
+a 8309 16314 1
+a 8310 16313 1
+a 8311 16312 1
+a 8312 16311 1
+a 8313 16310 1
+a 8314 16309 1
+a 8315 16308 1
+a 8316 16307 1
+a 8317 16306 1
+a 8318 16305 1
+a 8319 16304 1
+a 8320 16303 1
+a 8321 16302 1
+a 8322 16301 1
+a 8323 16300 1
+a 8324 16299 1
+a 8325 16298 1
+a 8326 16297 1
+a 8327 16296 1
+a 8328 16295 1
+a 8329 16294 1
+a 8330 16293 1
+a 8331 16292 1
+a 8332 16291 1
+a 8333 16290 1
+a 8334 16289 1
+a 8335 16288 1
+a 8336 16287 1
+a 8337 16286 1
+a 8338 16285 1
+a 8339 16284 1
+a 8340 16283 1
+a 8341 16282 1
+a 8342 16281 1
+a 8343 16280 1
+a 8344 16279 1
+a 8345 16278 1
+a 8346 16277 1
+a 8347 16276 1
+a 8348 16275 1
+a 8349 16274 1
+a 8350 16273 1
+a 8351 16272 1
+a 8352 16271 1
+a 8353 16270 1
+a 8354 16269 1
+a 8355 16268 1
+a 8356 16267 1
+a 8357 16266 1
+a 8358 16265 1
+a 8359 16264 1
+a 8360 16263 1
+a 8361 16262 1
+a 8362 16261 1
+a 8363 16260 1
+a 8364 16259 1
+a 8365 16258 1
+a 8366 16257 1
+a 8367 16256 1
+a 8368 16255 1
+a 8369 16254 1
+a 8370 16253 1
+a 8371 16252 1
+a 8372 16251 1
+a 8373 16250 1
+a 8374 16249 1
+a 8375 16248 1
+a 8376 16247 1
+a 8377 16246 1
+a 8378 16245 1
+a 8379 16244 1
+a 8380 16243 1
+a 8381 16242 1
+a 8382 16241 1
+a 8383 16240 1
+a 8384 16239 1
+a 8385 16238 1
+a 8386 16237 1
+a 8387 16236 1
+a 8388 16235 1
+a 8389 16234 1
+a 8390 16233 1
+a 8391 16232 1
+a 8392 16231 1
+a 8393 16230 1
+a 8394 16229 1
+a 8395 16228 1
+a 8396 16227 1
+a 8397 16226 1
+a 8398 16225 1
+a 8399 16224 1
+a 8400 16223 1
+a 8401 16222 1
+a 8402 16221 1
+a 8403 16220 1
+a 8404 16219 1
+a 8405 16218 1
+a 8406 16217 1
+a 8407 16216 1
+a 8408 16215 1
+a 8409 16214 1
+a 8410 16213 1
+a 8411 16212 1
+a 8412 16211 1
+a 8413 16210 1
+a 8414 16209 1
+a 8415 16208 1
+a 8416 16207 1
+a 8417 16206 1
+a 8418 16205 1
+a 8419 16204 1
+a 8420 16203 1
+a 8421 16202 1
+a 8422 16201 1
+a 8423 16200 1
+a 8424 16199 1
+a 8425 16198 1
+a 8426 16197 1
+a 8427 16196 1
+a 8428 16195 1
+a 8429 16194 1
+a 8430 16193 1
+a 8431 16192 1
+a 8432 16191 1
+a 8433 16190 1
+a 8434 16189 1
+a 8435 16188 1
+a 8436 16187 1
+a 8437 16186 1
+a 8438 16185 1
+a 8439 16184 1
+a 8440 16183 1
+a 8441 16182 1
+a 8442 16181 1
+a 8443 16180 1
+a 8444 16179 1
+a 8445 16178 1
+a 8446 16177 1
+a 8447 16176 1
+a 8448 16175 1
+a 8449 16174 1
+a 8450 16173 1
+a 8451 16172 1
+a 8452 16171 1
+a 8453 16170 1
+a 8454 16169 1
+a 8455 16168 1
+a 8456 16167 1
+a 8457 16166 1
+a 8458 16165 1
+a 8459 16164 1
+a 8460 16163 1
+a 8461 16162 1
+a 8462 16161 1
+a 8463 16160 1
+a 8464 16159 1
+a 8465 16158 1
+a 8466 16157 1
+a 8467 16156 1
+a 8468 16155 1
+a 8469 16154 1
+a 8470 16153 1
+a 8471 16152 1
+a 8472 16151 1
+a 8473 16150 1
+a 8474 16149 1
+a 8475 16148 1
+a 8476 16147 1
+a 8477 16146 1
+a 8478 16145 1
+a 8479 16144 1
+a 8480 16143 1
+a 8481 16142 1
+a 8482 16141 1
+a 8483 16140 1
+a 8484 16139 1
+a 8485 16138 1
+a 8486 16137 1
+a 8487 16136 1
+a 8488 16135 1
+a 8489 16134 1
+a 8490 16133 1
+a 8491 16132 1
+a 8492 16131 1
+a 8493 16130 1
+a 8494 16129 1
+a 8495 16128 1
+a 8496 16127 1
+a 8497 16126 1
+a 8498 16125 1
+a 8499 16124 1
+a 8500 16123 1
+a 8501 16122 1
+a 8502 16121 1
+a 8503 16120 1
+a 8504 16119 1
+a 8505 16118 1
+a 8506 16117 1
+a 8507 16116 1
+a 8508 16115 1
+a 8509 16114 1
+a 8510 16113 1
+a 8511 16112 1
+a 8512 16111 1
+a 8513 16110 1
+a 8514 16109 1
+a 8515 16108 1
+a 8516 16107 1
+a 8517 16106 1
+a 8518 16105 1
+a 8519 16104 1
+a 8520 16103 1
+a 8521 16102 1
+a 8522 16101 1
+a 8523 16100 1
+a 8524 16099 1
+a 8525 16098 1
+a 8526 16097 1
+a 8527 16096 1
+a 8528 16095 1
+a 8529 16094 1
+a 8530 16093 1
+a 8531 16092 1
+a 8532 16091 1
+a 8533 16090 1
+a 8534 16089 1
+a 8535 16088 1
+a 8536 16087 1
+a 8537 16086 1
+a 8538 16085 1
+a 8539 16084 1
+a 8540 16083 1
+a 8541 16082 1
+a 8542 16081 1
+a 8543 16080 1
+a 8544 16079 1
+a 8545 16078 1
+a 8546 16077 1
+a 8547 16076 1
+a 8548 16075 1
+a 8549 16074 1
+a 8550 16073 1
+a 8551 16072 1
+a 8552 16071 1
+a 8553 16070 1
+a 8554 16069 1
+a 8555 16068 1
+a 8556 16067 1
+a 8557 16066 1
+a 8558 16065 1
+a 8559 16064 1
+a 8560 16063 1
+a 8561 16062 1
+a 8562 16061 1
+a 8563 16060 1
+a 8564 16059 1
+a 8565 16058 1
+a 8566 16057 1
+a 8567 16056 1
+a 8568 16055 1
+a 8569 16054 1
+a 8570 16053 1
+a 8571 16052 1
+a 8572 16051 1
+a 8573 16050 1
+a 8574 16049 1
+a 8575 16048 1
+a 8576 16047 1
+a 8577 16046 1
+a 8578 16045 1
+a 8579 16044 1
+a 8580 16043 1
+a 8581 16042 1
+a 8582 16041 1
+a 8583 16040 1
+a 8584 16039 1
+a 8585 16038 1
+a 8586 16037 1
+a 8587 16036 1
+a 8588 16035 1
+a 8589 16034 1
+a 8590 16033 1
+a 8591 16032 1
+a 8592 16031 1
+a 8593 16030 1
+a 8594 16029 1
+a 8595 16028 1
+a 8596 16027 1
+a 8597 16026 1
+a 8598 16025 1
+a 8599 16024 1
+a 8600 16023 1
+a 8601 16022 1
+a 8602 16021 1
+a 8603 16020 1
+a 8604 16019 1
+a 8605 16018 1
+a 8606 16017 1
+a 8607 16016 1
+a 8608 16015 1
+a 8609 16014 1
+a 8610 16013 1
+a 8611 16012 1
+a 8612 16011 1
+a 8613 16010 1
+a 8614 16009 1
+a 8615 16008 1
+a 8616 16007 1
+a 8617 16006 1
+a 8618 16005 1
+a 8619 16004 1
+a 8620 16003 1
+a 8621 16002 1
+a 8622 16001 1
+a 8623 16000 1
+a 8624 15999 1
+a 8625 15998 1
+a 8626 15997 1
+a 8627 15996 1
+a 8628 15995 1
+a 8629 15994 1
+a 8630 15993 1
+a 8631 15992 1
+a 8632 15991 1
+a 8633 15990 1
+a 8634 15989 1
+a 8635 15988 1
+a 8636 15987 1
+a 8637 15986 1
+a 8638 15985 1
+a 8639 15984 1
+a 8640 15983 1
+a 8641 15982 1
+a 8642 15981 1
+a 8643 15980 1
+a 8644 15979 1
+a 8645 15978 1
+a 8646 15977 1
+a 8647 15976 1
+a 8648 15975 1
+a 8649 15974 1
+a 8650 15973 1
+a 8651 15972 1
+a 8652 15971 1
+a 8653 15970 1
+a 8654 15969 1
+a 8655 15968 1
+a 8656 15967 1
+a 8657 15966 1
+a 8658 15965 1
+a 8659 15964 1
+a 8660 15963 1
+a 8661 15962 1
+a 8662 15961 1
+a 8663 15960 1
+a 8664 15959 1
+a 8665 15958 1
+a 8666 15957 1
+a 8667 15956 1
+a 8668 15955 1
+a 8669 15954 1
+a 8670 15953 1
+a 8671 15952 1
+a 8672 15951 1
+a 8673 15950 1
+a 8674 15949 1
+a 8675 15948 1
+a 8676 15947 1
+a 8677 15946 1
+a 8678 15945 1
+a 8679 15944 1
+a 8680 15943 1
+a 8681 15942 1
+a 8682 15941 1
+a 8683 15940 1
+a 8684 15939 1
+a 8685 15938 1
+a 8686 15937 1
+a 8687 15936 1
+a 8688 15935 1
+a 8689 15934 1
+a 8690 15933 1
+a 8691 15932 1
+a 8692 15931 1
+a 8693 15930 1
+a 8694 15929 1
+a 8695 15928 1
+a 8696 15927 1
+a 8697 15926 1
+a 8698 15925 1
+a 8699 15924 1
+a 8700 15923 1
+a 8701 15922 1
+a 8702 15921 1
+a 8703 15920 1
+a 8704 15919 1
+a 8705 15918 1
+a 8706 15917 1
+a 8707 15916 1
+a 8708 15915 1
+a 8709 15914 1
+a 8710 15913 1
+a 8711 15912 1
+a 8712 15911 1
+a 8713 15910 1
+a 8714 15909 1
+a 8715 15908 1
+a 8716 15907 1
+a 8717 15906 1
+a 8718 15905 1
+a 8719 15904 1
+a 8720 15903 1
+a 8721 15902 1
+a 8722 15901 1
+a 8723 15900 1
+a 8724 15899 1
+a 8725 15898 1
+a 8726 15897 1
+a 8727 15896 1
+a 8728 15895 1
+a 8729 15894 1
+a 8730 15893 1
+a 8731 15892 1
+a 8732 15891 1
+a 8733 15890 1
+a 8734 15889 1
+a 8735 15888 1
+a 8736 15887 1
+a 8737 15886 1
+a 8738 15885 1
+a 8739 15884 1
+a 8740 15883 1
+a 8741 15882 1
+a 8742 15881 1
+a 8743 15880 1
+a 8744 15879 1
+a 8745 15878 1
+a 8746 15877 1
+a 8747 15876 1
+a 8748 15875 1
+a 8749 15874 1
+a 8750 15873 1
+a 8751 15872 1
+a 8752 15871 1
+a 8753 15870 1
+a 8754 15869 1
+a 8755 15868 1
+a 8756 15867 1
+a 8757 15866 1
+a 8758 15865 1
+a 8759 15864 1
+a 8760 15863 1
+a 8761 15862 1
+a 8762 15861 1
+a 8763 15860 1
+a 8764 15859 1
+a 8765 15858 1
+a 8766 15857 1
+a 8767 15856 1
+a 8768 15855 1
+a 8769 15854 1
+a 8770 15853 1
+a 8771 15852 1
+a 8772 15851 1
+a 8773 15850 1
+a 8774 15849 1
+a 8775 15848 1
+a 8776 15847 1
+a 8777 15846 1
+a 8778 15845 1
+a 8779 15844 1
+a 8780 15843 1
+a 8781 15842 1
+a 8782 15841 1
+a 8783 15840 1
+a 8784 15839 1
+a 8785 15838 1
+a 8786 15837 1
+a 8787 15836 1
+a 8788 15835 1
+a 8789 15834 1
+a 8790 15833 1
+a 8791 15832 1
+a 8792 15831 1
+a 8793 15830 1
+a 8794 15829 1
+a 8795 15828 1
+a 8796 15827 1
+a 8797 15826 1
+a 8798 15825 1
+a 8799 15824 1
+a 8800 15823 1
+a 8801 15822 1
+a 8802 15821 1
+a 8803 15820 1
+a 8804 15819 1
+a 8805 15818 1
+a 8806 15817 1
+a 8807 15816 1
+a 8808 15815 1
+a 8809 15814 1
+a 8810 15813 1
+a 8811 15812 1
+a 8812 15811 1
+a 8813 15810 1
+a 8814 15809 1
+a 8815 15808 1
+a 8816 15807 1
+a 8817 15806 1
+a 8818 15805 1
+a 8819 15804 1
+a 8820 15803 1
+a 8821 15802 1
+a 8822 15801 1
+a 8823 15800 1
+a 8824 15799 1
+a 8825 15798 1
+a 8826 15797 1
+a 8827 15796 1
+a 8828 15795 1
+a 8829 15794 1
+a 8830 15793 1
+a 8831 15792 1
+a 8832 15791 1
+a 8833 15790 1
+a 8834 15789 1
+a 8835 15788 1
+a 8836 15787 1
+a 8837 15786 1
+a 8838 15785 1
+a 8839 15784 1
+a 8840 15783 1
+a 8841 15782 1
+a 8842 15781 1
+a 8843 15780 1
+a 8844 15779 1
+a 8845 15778 1
+a 8846 15777 1
+a 8847 15776 1
+a 8848 15775 1
+a 8849 15774 1
+a 8850 15773 1
+a 8851 15772 1
+a 8852 15771 1
+a 8853 15770 1
+a 8854 15769 1
+a 8855 15768 1
+a 8856 15767 1
+a 8857 15766 1
+a 8858 15765 1
+a 8859 15764 1
+a 8860 15763 1
+a 8861 15762 1
+a 8862 15761 1
+a 8863 15760 1
+a 8864 15759 1
+a 8865 15758 1
+a 8866 15757 1
+a 8867 15756 1
+a 8868 15755 1
+a 8869 15754 1
+a 8870 15753 1
+a 8871 15752 1
+a 8872 15751 1
+a 8873 15750 1
+a 8874 15749 1
+a 8875 15748 1
+a 8876 15747 1
+a 8877 15746 1
+a 8878 15745 1
+a 8879 15744 1
+a 8880 15743 1
+a 8881 15742 1
+a 8882 15741 1
+a 8883 15740 1
+a 8884 15739 1
+a 8885 15738 1
+a 8886 15737 1
+a 8887 15736 1
+a 8888 15735 1
+a 8889 15734 1
+a 8890 15733 1
+a 8891 15732 1
+a 8892 15731 1
+a 8893 15730 1
+a 8894 15729 1
+a 8895 15728 1
+a 8896 15727 1
+a 8897 15726 1
+a 8898 15725 1
+a 8899 15724 1
+a 8900 15723 1
+a 8901 15722 1
+a 8902 15721 1
+a 8903 15720 1
+a 8904 15719 1
+a 8905 15718 1
+a 8906 15717 1
+a 8907 15716 1
+a 8908 15715 1
+a 8909 15714 1
+a 8910 15713 1
+a 8911 15712 1
+a 8912 15711 1
+a 8913 15710 1
+a 8914 15709 1
+a 8915 15708 1
+a 8916 15707 1
+a 8917 15706 1
+a 8918 15705 1
+a 8919 15704 1
+a 8920 15703 1
+a 8921 15702 1
+a 8922 15701 1
+a 8923 15700 1
+a 8924 15699 1
+a 8925 15698 1
+a 8926 15697 1
+a 8927 15696 1
+a 8928 15695 1
+a 8929 15694 1
+a 8930 15693 1
+a 8931 15692 1
+a 8932 15691 1
+a 8933 15690 1
+a 8934 15689 1
+a 8935 15688 1
+a 8936 15687 1
+a 8937 15686 1
+a 8938 15685 1
+a 8939 15684 1
+a 8940 15683 1
+a 8941 15682 1
+a 8942 15681 1
+a 8943 15680 1
+a 8944 15679 1
+a 8945 15678 1
+a 8946 15677 1
+a 8947 15676 1
+a 8948 15675 1
+a 8949 15674 1
+a 8950 15673 1
+a 8951 15672 1
+a 8952 15671 1
+a 8953 15670 1
+a 8954 15669 1
+a 8955 15668 1
+a 8956 15667 1
+a 8957 15666 1
+a 8958 15665 1
+a 8959 15664 1
+a 8960 15663 1
+a 8961 15662 1
+a 8962 15661 1
+a 8963 15660 1
+a 8964 15659 1
+a 8965 15658 1
+a 8966 15657 1
+a 8967 15656 1
+a 8968 15655 1
+a 8969 15654 1
+a 8970 15653 1
+a 8971 15652 1
+a 8972 15651 1
+a 8973 15650 1
+a 8974 15649 1
+a 8975 15648 1
+a 8976 15647 1
+a 8977 15646 1
+a 8978 15645 1
+a 8979 15644 1
+a 8980 15643 1
+a 8981 15642 1
+a 8982 15641 1
+a 8983 15640 1
+a 8984 15639 1
+a 8985 15638 1
+a 8986 15637 1
+a 8987 15636 1
+a 8988 15635 1
+a 8989 15634 1
+a 8990 15633 1
+a 8991 15632 1
+a 8992 15631 1
+a 8993 15630 1
+a 8994 15629 1
+a 8995 15628 1
+a 8996 15627 1
+a 8997 15626 1
+a 8998 15625 1
+a 8999 15624 1
+a 9000 15623 1
+a 9001 15622 1
+a 9002 15621 1
+a 9003 15620 1
+a 9004 15619 1
+a 9005 15618 1
+a 9006 15617 1
+a 9007 15616 1
+a 9008 15615 1
+a 9009 15614 1
+a 9010 15613 1
+a 9011 15612 1
+a 9012 15611 1
+a 9013 15610 1
+a 9014 15609 1
+a 9015 15608 1
+a 9016 15607 1
+a 9017 15606 1
+a 9018 15605 1
+a 9019 15604 1
+a 9020 15603 1
+a 9021 15602 1
+a 9022 15601 1
+a 9023 15600 1
+a 9024 15599 1
+a 9025 15598 1
+a 9026 15597 1
+a 9027 15596 1
+a 9028 15595 1
+a 9029 15594 1
+a 9030 15593 1
+a 9031 15592 1
+a 9032 15591 1
+a 9033 15590 1
+a 9034 15589 1
+a 9035 15588 1
+a 9036 15587 1
+a 9037 15586 1
+a 9038 15585 1
+a 9039 15584 1
+a 9040 15583 1
+a 9041 15582 1
+a 9042 15581 1
+a 9043 15580 1
+a 9044 15579 1
+a 9045 15578 1
+a 9046 15577 1
+a 9047 15576 1
+a 9048 15575 1
+a 9049 15574 1
+a 9050 15573 1
+a 9051 15572 1
+a 9052 15571 1
+a 9053 15570 1
+a 9054 15569 1
+a 9055 15568 1
+a 9056 15567 1
+a 9057 15566 1
+a 9058 15565 1
+a 9059 15564 1
+a 9060 15563 1
+a 9061 15562 1
+a 9062 15561 1
+a 9063 15560 1
+a 9064 15559 1
+a 9065 15558 1
+a 9066 15557 1
+a 9067 15556 1
+a 9068 15555 1
+a 9069 15554 1
+a 9070 15553 1
+a 9071 15552 1
+a 9072 15551 1
+a 9073 15550 1
+a 9074 15549 1
+a 9075 15548 1
+a 9076 15547 1
+a 9077 15546 1
+a 9078 15545 1
+a 9079 15544 1
+a 9080 15543 1
+a 9081 15542 1
+a 9082 15541 1
+a 9083 15540 1
+a 9084 15539 1
+a 9085 15538 1
+a 9086 15537 1
+a 9087 15536 1
+a 9088 15535 1
+a 9089 15534 1
+a 9090 15533 1
+a 9091 15532 1
+a 9092 15531 1
+a 9093 15530 1
+a 9094 15529 1
+a 9095 15528 1
+a 9096 15527 1
+a 9097 15526 1
+a 9098 15525 1
+a 9099 15524 1
+a 9100 15523 1
+a 9101 15522 1
+a 9102 15521 1
+a 9103 15520 1
+a 9104 15519 1
+a 9105 15518 1
+a 9106 15517 1
+a 9107 15516 1
+a 9108 15515 1
+a 9109 15514 1
+a 9110 15513 1
+a 9111 15512 1
+a 9112 15511 1
+a 9113 15510 1
+a 9114 15509 1
+a 9115 15508 1
+a 9116 15507 1
+a 9117 15506 1
+a 9118 15505 1
+a 9119 15504 1
+a 9120 15503 1
+a 9121 15502 1
+a 9122 15501 1
+a 9123 15500 1
+a 9124 15499 1
+a 9125 15498 1
+a 9126 15497 1
+a 9127 15496 1
+a 9128 15495 1
+a 9129 15494 1
+a 9130 15493 1
+a 9131 15492 1
+a 9132 15491 1
+a 9133 15490 1
+a 9134 15489 1
+a 9135 15488 1
+a 9136 15487 1
+a 9137 15486 1
+a 9138 15485 1
+a 9139 15484 1
+a 9140 15483 1
+a 9141 15482 1
+a 9142 15481 1
+a 9143 15480 1
+a 9144 15479 1
+a 9145 15478 1
+a 9146 15477 1
+a 9147 15476 1
+a 9148 15475 1
+a 9149 15474 1
+a 9150 15473 1
+a 9151 15472 1
+a 9152 15471 1
+a 9153 15470 1
+a 9154 15469 1
+a 9155 15468 1
+a 9156 15467 1
+a 9157 15466 1
+a 9158 15465 1
+a 9159 15464 1
+a 9160 15463 1
+a 9161 15462 1
+a 9162 15461 1
+a 9163 15460 1
+a 9164 15459 1
+a 9165 15458 1
+a 9166 15457 1
+a 9167 15456 1
+a 9168 15455 1
+a 9169 15454 1
+a 9170 15453 1
+a 9171 15452 1
+a 9172 15451 1
+a 9173 15450 1
+a 9174 15449 1
+a 9175 15448 1
+a 9176 15447 1
+a 9177 15446 1
+a 9178 15445 1
+a 9179 15444 1
+a 9180 15443 1
+a 9181 15442 1
+a 9182 15441 1
+a 9183 15440 1
+a 9184 15439 1
+a 9185 15438 1
+a 9186 15437 1
+a 9187 15436 1
+a 9188 15435 1
+a 9189 15434 1
+a 9190 15433 1
+a 9191 15432 1
+a 9192 15431 1
+a 9193 15430 1
+a 9194 15429 1
+a 9195 15428 1
+a 9196 15427 1
+a 9197 15426 1
+a 9198 15425 1
+a 9199 15424 1
+a 9200 15423 1
+a 9201 15422 1
+a 9202 15421 1
+a 9203 15420 1
+a 9204 15419 1
+a 9205 15418 1
+a 9206 15417 1
+a 9207 15416 1
+a 9208 15415 1
+a 9209 15414 1
+a 9210 15413 1
+a 9211 15412 1
+a 9212 15411 1
+a 9213 15410 1
+a 9214 15409 1
+a 9215 15408 1
+a 9216 15407 1
+a 9217 15406 1
+a 9218 15405 1
+a 9219 15404 1
+a 9220 15403 1
+a 9221 15402 1
+a 9222 15401 1
+a 9223 15400 1
+a 9224 15399 1
+a 9225 15398 1
+a 9226 15397 1
+a 9227 15396 1
+a 9228 15395 1
+a 9229 15394 1
+a 9230 15393 1
+a 9231 15392 1
+a 9232 15391 1
+a 9233 15390 1
+a 9234 15389 1
+a 9235 15388 1
+a 9236 15387 1
+a 9237 15386 1
+a 9238 15385 1
+a 9239 15384 1
+a 9240 15383 1
+a 9241 15382 1
+a 9242 15381 1
+a 9243 15380 1
+a 9244 15379 1
+a 9245 15378 1
+a 9246 15377 1
+a 9247 15376 1
+a 9248 15375 1
+a 9249 15374 1
+a 9250 15373 1
+a 9251 15372 1
+a 9252 15371 1
+a 9253 15370 1
+a 9254 15369 1
+a 9255 15368 1
+a 9256 15367 1
+a 9257 15366 1
+a 9258 15365 1
+a 9259 15364 1
+a 9260 15363 1
+a 9261 15362 1
+a 9262 15361 1
+a 9263 15360 1
+a 9264 15359 1
+a 9265 15358 1
+a 9266 15357 1
+a 9267 15356 1
+a 9268 15355 1
+a 9269 15354 1
+a 9270 15353 1
+a 9271 15352 1
+a 9272 15351 1
+a 9273 15350 1
+a 9274 15349 1
+a 9275 15348 1
+a 9276 15347 1
+a 9277 15346 1
+a 9278 15345 1
+a 9279 15344 1
+a 9280 15343 1
+a 9281 15342 1
+a 9282 15341 1
+a 9283 15340 1
+a 9284 15339 1
+a 9285 15338 1
+a 9286 15337 1
+a 9287 15336 1
+a 9288 15335 1
+a 9289 15334 1
+a 9290 15333 1
+a 9291 15332 1
+a 9292 15331 1
+a 9293 15330 1
+a 9294 15329 1
+a 9295 15328 1
+a 9296 15327 1
+a 9297 15326 1
+a 9298 15325 1
+a 9299 15324 1
+a 9300 15323 1
+a 9301 15322 1
+a 9302 15321 1
+a 9303 15320 1
+a 9304 15319 1
+a 9305 15318 1
+a 9306 15317 1
+a 9307 15316 1
+a 9308 15315 1
+a 9309 15314 1
+a 9310 15313 1
+a 9311 15312 1
+a 9312 15311 1
+a 9313 15310 1
+a 9314 15309 1
+a 9315 15308 1
+a 9316 15307 1
+a 9317 15306 1
+a 9318 15305 1
+a 9319 15304 1
+a 9320 15303 1
+a 9321 15302 1
+a 9322 15301 1
+a 9323 15300 1
+a 9324 15299 1
+a 9325 15298 1
+a 9326 15297 1
+a 9327 15296 1
+a 9328 15295 1
+a 9329 15294 1
+a 9330 15293 1
+a 9331 15292 1
+a 9332 15291 1
+a 9333 15290 1
+a 9334 15289 1
+a 9335 15288 1
+a 9336 15287 1
+a 9337 15286 1
+a 9338 15285 1
+a 9339 15284 1
+a 9340 15283 1
+a 9341 15282 1
+a 9342 15281 1
+a 9343 15280 1
+a 9344 15279 1
+a 9345 15278 1
+a 9346 15277 1
+a 9347 15276 1
+a 9348 15275 1
+a 9349 15274 1
+a 9350 15273 1
+a 9351 15272 1
+a 9352 15271 1
+a 9353 15270 1
+a 9354 15269 1
+a 9355 15268 1
+a 9356 15267 1
+a 9357 15266 1
+a 9358 15265 1
+a 9359 15264 1
+a 9360 15263 1
+a 9361 15262 1
+a 9362 15261 1
+a 9363 15260 1
+a 9364 15259 1
+a 9365 15258 1
+a 9366 15257 1
+a 9367 15256 1
+a 9368 15255 1
+a 9369 15254 1
+a 9370 15253 1
+a 9371 15252 1
+a 9372 15251 1
+a 9373 15250 1
+a 9374 15249 1
+a 9375 15248 1
+a 9376 15247 1
+a 9377 15246 1
+a 9378 15245 1
+a 9379 15244 1
+a 9380 15243 1
+a 9381 15242 1
+a 9382 15241 1
+a 9383 15240 1
+a 9384 15239 1
+a 9385 15238 1
+a 9386 15237 1
+a 9387 15236 1
+a 9388 15235 1
+a 9389 15234 1
+a 9390 15233 1
+a 9391 15232 1
+a 9392 15231 1
+a 9393 15230 1
+a 9394 15229 1
+a 9395 15228 1
+a 9396 15227 1
+a 9397 15226 1
+a 9398 15225 1
+a 9399 15224 1
+a 9400 15223 1
+a 9401 15222 1
+a 9402 15221 1
+a 9403 15220 1
+a 9404 15219 1
+a 9405 15218 1
+a 9406 15217 1
+a 9407 15216 1
+a 9408 15215 1
+a 9409 15214 1
+a 9410 15213 1
+a 9411 15212 1
+a 9412 15211 1
+a 9413 15210 1
+a 9414 15209 1
+a 9415 15208 1
+a 9416 15207 1
+a 9417 15206 1
+a 9418 15205 1
+a 9419 15204 1
+a 9420 15203 1
+a 9421 15202 1
+a 9422 15201 1
+a 9423 15200 1
+a 9424 15199 1
+a 9425 15198 1
+a 9426 15197 1
+a 9427 15196 1
+a 9428 15195 1
+a 9429 15194 1
+a 9430 15193 1
+a 9431 15192 1
+a 9432 15191 1
+a 9433 15190 1
+a 9434 15189 1
+a 9435 15188 1
+a 9436 15187 1
+a 9437 15186 1
+a 9438 15185 1
+a 9439 15184 1
+a 9440 15183 1
+a 9441 15182 1
+a 9442 15181 1
+a 9443 15180 1
+a 9444 15179 1
+a 9445 15178 1
+a 9446 15177 1
+a 9447 15176 1
+a 9448 15175 1
+a 9449 15174 1
+a 9450 15173 1
+a 9451 15172 1
+a 9452 15171 1
+a 9453 15170 1
+a 9454 15169 1
+a 9455 15168 1
+a 9456 15167 1
+a 9457 15166 1
+a 9458 15165 1
+a 9459 15164 1
+a 9460 15163 1
+a 9461 15162 1
+a 9462 15161 1
+a 9463 15160 1
+a 9464 15159 1
+a 9465 15158 1
+a 9466 15157 1
+a 9467 15156 1
+a 9468 15155 1
+a 9469 15154 1
+a 9470 15153 1
+a 9471 15152 1
+a 9472 15151 1
+a 9473 15150 1
+a 9474 15149 1
+a 9475 15148 1
+a 9476 15147 1
+a 9477 15146 1
+a 9478 15145 1
+a 9479 15144 1
+a 9480 15143 1
+a 9481 15142 1
+a 9482 15141 1
+a 9483 15140 1
+a 9484 15139 1
+a 9485 15138 1
+a 9486 15137 1
+a 9487 15136 1
+a 9488 15135 1
+a 9489 15134 1
+a 9490 15133 1
+a 9491 15132 1
+a 9492 15131 1
+a 9493 15130 1
+a 9494 15129 1
+a 9495 15128 1
+a 9496 15127 1
+a 9497 15126 1
+a 9498 15125 1
+a 9499 15124 1
+a 9500 15123 1
+a 9501 15122 1
+a 9502 15121 1
+a 9503 15120 1
+a 9504 15119 1
+a 9505 15118 1
+a 9506 15117 1
+a 9507 15116 1
+a 9508 15115 1
+a 9509 15114 1
+a 9510 15113 1
+a 9511 15112 1
+a 9512 15111 1
+a 9513 15110 1
+a 9514 15109 1
+a 9515 15108 1
+a 9516 15107 1
+a 9517 15106 1
+a 9518 15105 1
+a 9519 15104 1
+a 9520 15103 1
+a 9521 15102 1
+a 9522 15101 1
+a 9523 15100 1
+a 9524 15099 1
+a 9525 15098 1
+a 9526 15097 1
+a 9527 15096 1
+a 9528 15095 1
+a 9529 15094 1
+a 9530 15093 1
+a 9531 15092 1
+a 9532 15091 1
+a 9533 15090 1
+a 9534 15089 1
+a 9535 15088 1
+a 9536 15087 1
+a 9537 15086 1
+a 9538 15085 1
+a 9539 15084 1
+a 9540 15083 1
+a 9541 15082 1
+a 9542 15081 1
+a 9543 15080 1
+a 9544 15079 1
+a 9545 15078 1
+a 9546 15077 1
+a 9547 15076 1
+a 9548 15075 1
+a 9549 15074 1
+a 9550 15073 1
+a 9551 15072 1
+a 9552 15071 1
+a 9553 15070 1
+a 9554 15069 1
+a 9555 15068 1
+a 9556 15067 1
+a 9557 15066 1
+a 9558 15065 1
+a 9559 15064 1
+a 9560 15063 1
+a 9561 15062 1
+a 9562 15061 1
+a 9563 15060 1
+a 9564 15059 1
+a 9565 15058 1
+a 9566 15057 1
+a 9567 15056 1
+a 9568 15055 1
+a 9569 15054 1
+a 9570 15053 1
+a 9571 15052 1
+a 9572 15051 1
+a 9573 15050 1
+a 9574 15049 1
+a 9575 15048 1
+a 9576 15047 1
+a 9577 15046 1
+a 9578 15045 1
+a 9579 15044 1
+a 9580 15043 1
+a 9581 15042 1
+a 9582 15041 1
+a 9583 15040 1
+a 9584 15039 1
+a 9585 15038 1
+a 9586 15037 1
+a 9587 15036 1
+a 9588 15035 1
+a 9589 15034 1
+a 9590 15033 1
+a 9591 15032 1
+a 9592 15031 1
+a 9593 15030 1
+a 9594 15029 1
+a 9595 15028 1
+a 9596 15027 1
+a 9597 15026 1
+a 9598 15025 1
+a 9599 15024 1
+a 9600 15023 1
+a 9601 15022 1
+a 9602 15021 1
+a 9603 15020 1
+a 9604 15019 1
+a 9605 15018 1
+a 9606 15017 1
+a 9607 15016 1
+a 9608 15015 1
+a 9609 15014 1
+a 9610 15013 1
+a 9611 15012 1
+a 9612 15011 1
+a 9613 15010 1
+a 9614 15009 1
+a 9615 15008 1
+a 9616 15007 1
+a 9617 15006 1
+a 9618 15005 1
+a 9619 15004 1
+a 9620 15003 1
+a 9621 15002 1
+a 9622 15001 1
+a 9623 15000 1
+a 9624 14999 1
+a 9625 14998 1
+a 9626 14997 1
+a 9627 14996 1
+a 9628 14995 1
+a 9629 14994 1
+a 9630 14993 1
+a 9631 14992 1
+a 9632 14991 1
+a 9633 14990 1
+a 9634 14989 1
+a 9635 14988 1
+a 9636 14987 1
+a 9637 14986 1
+a 9638 14985 1
+a 9639 14984 1
+a 9640 14983 1
+a 9641 14982 1
+a 9642 14981 1
+a 9643 14980 1
+a 9644 14979 1
+a 9645 14978 1
+a 9646 14977 1
+a 9647 14976 1
+a 9648 14975 1
+a 9649 14974 1
+a 9650 14973 1
+a 9651 14972 1
+a 9652 14971 1
+a 9653 14970 1
+a 9654 14969 1
+a 9655 14968 1
+a 9656 14967 1
+a 9657 14966 1
+a 9658 14965 1
+a 9659 14964 1
+a 9660 14963 1
+a 9661 14962 1
+a 9662 14961 1
+a 9663 14960 1
+a 9664 14959 1
+a 9665 14958 1
+a 9666 14957 1
+a 9667 14956 1
+a 9668 14955 1
+a 9669 14954 1
+a 9670 14953 1
+a 9671 14952 1
+a 9672 14951 1
+a 9673 14950 1
+a 9674 14949 1
+a 9675 14948 1
+a 9676 14947 1
+a 9677 14946 1
+a 9678 14945 1
+a 9679 14944 1
+a 9680 14943 1
+a 9681 14942 1
+a 9682 14941 1
+a 9683 14940 1
+a 9684 14939 1
+a 9685 14938 1
+a 9686 14937 1
+a 9687 14936 1
+a 9688 14935 1
+a 9689 14934 1
+a 9690 14933 1
+a 9691 14932 1
+a 9692 14931 1
+a 9693 14930 1
+a 9694 14929 1
+a 9695 14928 1
+a 9696 14927 1
+a 9697 14926 1
+a 9698 14925 1
+a 9699 14924 1
+a 9700 14923 1
+a 9701 14922 1
+a 9702 14921 1
+a 9703 14920 1
+a 9704 14919 1
+a 9705 14918 1
+a 9706 14917 1
+a 9707 14916 1
+a 9708 14915 1
+a 9709 14914 1
+a 9710 14913 1
+a 9711 14912 1
+a 9712 14911 1
+a 9713 14910 1
+a 9714 14909 1
+a 9715 14908 1
+a 9716 14907 1
+a 9717 14906 1
+a 9718 14905 1
+a 9719 14904 1
+a 9720 14903 1
+a 9721 14902 1
+a 9722 14901 1
+a 9723 14900 1
+a 9724 14899 1
+a 9725 14898 1
+a 9726 14897 1
+a 9727 14896 1
+a 9728 14895 1
+a 9729 14894 1
+a 9730 14893 1
+a 9731 14892 1
+a 9732 14891 1
+a 9733 14890 1
+a 9734 14889 1
+a 9735 14888 1
+a 9736 14887 1
+a 9737 14886 1
+a 9738 14885 1
+a 9739 14884 1
+a 9740 14883 1
+a 9741 14882 1
+a 9742 14881 1
+a 9743 14880 1
+a 9744 14879 1
+a 9745 14878 1
+a 9746 14877 1
+a 9747 14876 1
+a 9748 14875 1
+a 9749 14874 1
+a 9750 14873 1
+a 9751 14872 1
+a 9752 14871 1
+a 9753 14870 1
+a 9754 14869 1
+a 9755 14868 1
+a 9756 14867 1
+a 9757 14866 1
+a 9758 14865 1
+a 9759 14864 1
+a 9760 14863 1
+a 9761 14862 1
+a 9762 14861 1
+a 9763 14860 1
+a 9764 14859 1
+a 9765 14858 1
+a 9766 14857 1
+a 9767 14856 1
+a 9768 14855 1
+a 9769 14854 1
+a 9770 14853 1
+a 9771 14852 1
+a 9772 14851 1
+a 9773 14850 1
+a 9774 14849 1
+a 9775 14848 1
+a 9776 14847 1
+a 9777 14846 1
+a 9778 14845 1
+a 9779 14844 1
+a 9780 14843 1
+a 9781 14842 1
+a 9782 14841 1
+a 9783 14840 1
+a 9784 14839 1
+a 9785 14838 1
+a 9786 14837 1
+a 9787 14836 1
+a 9788 14835 1
+a 9789 14834 1
+a 9790 14833 1
+a 9791 14832 1
+a 9792 14831 1
+a 9793 14830 1
+a 9794 14829 1
+a 9795 14828 1
+a 9796 14827 1
+a 9797 14826 1
+a 9798 14825 1
+a 9799 14824 1
+a 9800 14823 1
+a 9801 14822 1
+a 9802 14821 1
+a 9803 14820 1
+a 9804 14819 1
+a 9805 14818 1
+a 9806 14817 1
+a 9807 14816 1
+a 9808 14815 1
+a 9809 14814 1
+a 9810 14813 1
+a 9811 14812 1
+a 9812 14811 1
+a 9813 14810 1
+a 9814 14809 1
+a 9815 14808 1
+a 9816 14807 1
+a 9817 14806 1
+a 9818 14805 1
+a 9819 14804 1
+a 9820 14803 1
+a 9821 14802 1
+a 9822 14801 1
+a 9823 14800 1
+a 9824 14799 1
+a 9825 14798 1
+a 9826 14797 1
+a 9827 14796 1
+a 9828 14795 1
+a 9829 14794 1
+a 9830 14793 1
+a 9831 14792 1
+a 9832 14791 1
+a 9833 14790 1
+a 9834 14789 1
+a 9835 14788 1
+a 9836 14787 1
+a 9837 14786 1
+a 9838 14785 1
+a 9839 14784 1
+a 9840 14783 1
+a 9841 14782 1
+a 9842 14781 1
+a 9843 14780 1
+a 9844 14779 1
+a 9845 14778 1
+a 9846 14777 1
+a 9847 14776 1
+a 9848 14775 1
+a 9849 14774 1
+a 9850 14773 1
+a 9851 14772 1
+a 9852 14771 1
+a 9853 14770 1
+a 9854 14769 1
+a 9855 14768 1
+a 9856 14767 1
+a 9857 14766 1
+a 9858 14765 1
+a 9859 14764 1
+a 9860 14763 1
+a 9861 14762 1
+a 9862 14761 1
+a 9863 14760 1
+a 9864 14759 1
+a 9865 14758 1
+a 9866 14757 1
+a 9867 14756 1
+a 9868 14755 1
+a 9869 14754 1
+a 9870 14753 1
+a 9871 14752 1
+a 9872 14751 1
+a 9873 14750 1
+a 9874 14749 1
+a 9875 14748 1
+a 9876 14747 1
+a 9877 14746 1
+a 9878 14745 1
+a 9879 14744 1
+a 9880 14743 1
+a 9881 14742 1
+a 9882 14741 1
+a 9883 14740 1
+a 9884 14739 1
+a 9885 14738 1
+a 9886 14737 1
+a 9887 14736 1
+a 9888 14735 1
+a 9889 14734 1
+a 9890 14733 1
+a 9891 14732 1
+a 9892 14731 1
+a 9893 14730 1
+a 9894 14729 1
+a 9895 14728 1
+a 9896 14727 1
+a 9897 14726 1
+a 9898 14725 1
+a 9899 14724 1
+a 9900 14723 1
+a 9901 14722 1
+a 9902 14721 1
+a 9903 14720 1
+a 9904 14719 1
+a 9905 14718 1
+a 9906 14717 1
+a 9907 14716 1
+a 9908 14715 1
+a 9909 14714 1
+a 9910 14713 1
+a 9911 14712 1
+a 9912 14711 1
+a 9913 14710 1
+a 9914 14709 1
+a 9915 14708 1
+a 9916 14707 1
+a 9917 14706 1
+a 9918 14705 1
+a 9919 14704 1
+a 9920 14703 1
+a 9921 14702 1
+a 9922 14701 1
+a 9923 14700 1
+a 9924 14699 1
+a 9925 14698 1
+a 9926 14697 1
+a 9927 14696 1
+a 9928 14695 1
+a 9929 14694 1
+a 9930 14693 1
+a 9931 14692 1
+a 9932 14691 1
+a 9933 14690 1
+a 9934 14689 1
+a 9935 14688 1
+a 9936 14687 1
+a 9937 14686 1
+a 9938 14685 1
+a 9939 14684 1
+a 9940 14683 1
+a 9941 14682 1
+a 9942 14681 1
+a 9943 14680 1
+a 9944 14679 1
+a 9945 14678 1
+a 9946 14677 1
+a 9947 14676 1
+a 9948 14675 1
+a 9949 14674 1
+a 9950 14673 1
+a 9951 14672 1
+a 9952 14671 1
+a 9953 14670 1
+a 9954 14669 1
+a 9955 14668 1
+a 9956 14667 1
+a 9957 14666 1
+a 9958 14665 1
+a 9959 14664 1
+a 9960 14663 1
+a 9961 14662 1
+a 9962 14661 1
+a 9963 14660 1
+a 9964 14659 1
+a 9965 14658 1
+a 9966 14657 1
+a 9967 14656 1
+a 9968 14655 1
+a 9969 14654 1
+a 9970 14653 1
+a 9971 14652 1
+a 9972 14651 1
+a 9973 14650 1
+a 9974 14649 1
+a 9975 14648 1
+a 9976 14647 1
+a 9977 14646 1
+a 9978 14645 1
+a 9979 14644 1
+a 9980 14643 1
+a 9981 14642 1
+a 9982 14641 1
+a 9983 14640 1
+a 9984 14639 1
+a 9985 14638 1
+a 9986 14637 1
+a 9987 14636 1
+a 9988 14635 1
+a 9989 14634 1
+a 9990 14633 1
+a 9991 14632 1
+a 9992 14631 1
+a 9993 14630 1
+a 9994 14629 1
+a 9995 14628 1
+a 9996 14627 1
+a 9997 14626 1
+a 9998 14625 1
+a 9999 14624 1
+a 10000 14623 1
+a 10001 14622 1
+a 10002 14621 1
+a 10003 14620 1
+a 10004 14619 1
+a 10005 14618 1
+a 10006 14617 1
+a 10007 14616 1
+a 10008 14615 1
+a 10009 14614 1
+a 10010 14613 1
+a 10011 14612 1
+a 10012 14611 1
+a 10013 14610 1
+a 10014 14609 1
+a 10015 14608 1
+a 10016 14607 1
+a 10017 14606 1
+a 10018 14605 1
+a 10019 14604 1
+a 10020 14603 1
+a 10021 14602 1
+a 10022 14601 1
+a 10023 14600 1
+a 10024 14599 1
+a 10025 14598 1
+a 10026 14597 1
+a 10027 14596 1
+a 10028 14595 1
+a 10029 14594 1
+a 10030 14593 1
+a 10031 14592 1
+a 10032 14591 1
+a 10033 14590 1
+a 10034 14589 1
+a 10035 14588 1
+a 10036 14587 1
+a 10037 14586 1
+a 10038 14585 1
+a 10039 14584 1
+a 10040 14583 1
+a 10041 14582 1
+a 10042 14581 1
+a 10043 14580 1
+a 10044 14579 1
+a 10045 14578 1
+a 10046 14577 1
+a 10047 14576 1
+a 10048 14575 1
+a 10049 14574 1
+a 10050 14573 1
+a 10051 14572 1
+a 10052 14571 1
+a 10053 14570 1
+a 10054 14569 1
+a 10055 14568 1
+a 10056 14567 1
+a 10057 14566 1
+a 10058 14565 1
+a 10059 14564 1
+a 10060 14563 1
+a 10061 14562 1
+a 10062 14561 1
+a 10063 14560 1
+a 10064 14559 1
+a 10065 14558 1
+a 10066 14557 1
+a 10067 14556 1
+a 10068 14555 1
+a 10069 14554 1
+a 10070 14553 1
+a 10071 14552 1
+a 10072 14551 1
+a 10073 14550 1
+a 10074 14549 1
+a 10075 14548 1
+a 10076 14547 1
+a 10077 14546 1
+a 10078 14545 1
+a 10079 14544 1
+a 10080 14543 1
+a 10081 14542 1
+a 10082 14541 1
+a 10083 14540 1
+a 10084 14539 1
+a 10085 14538 1
+a 10086 14537 1
+a 10087 14536 1
+a 10088 14535 1
+a 10089 14534 1
+a 10090 14533 1
+a 10091 14532 1
+a 10092 14531 1
+a 10093 14530 1
+a 10094 14529 1
+a 10095 14528 1
+a 10096 14527 1
+a 10097 14526 1
+a 10098 14525 1
+a 10099 14524 1
+a 10100 14523 1
+a 10101 14522 1
+a 10102 14521 1
+a 10103 14520 1
+a 10104 14519 1
+a 10105 14518 1
+a 10106 14517 1
+a 10107 14516 1
+a 10108 14515 1
+a 10109 14514 1
+a 10110 14513 1
+a 10111 14512 1
+a 10112 14511 1
+a 10113 14510 1
+a 10114 14509 1
+a 10115 14508 1
+a 10116 14507 1
+a 10117 14506 1
+a 10118 14505 1
+a 10119 14504 1
+a 10120 14503 1
+a 10121 14502 1
+a 10122 14501 1
+a 10123 14500 1
+a 10124 14499 1
+a 10125 14498 1
+a 10126 14497 1
+a 10127 14496 1
+a 10128 14495 1
+a 10129 14494 1
+a 10130 14493 1
+a 10131 14492 1
+a 10132 14491 1
+a 10133 14490 1
+a 10134 14489 1
+a 10135 14488 1
+a 10136 14487 1
+a 10137 14486 1
+a 10138 14485 1
+a 10139 14484 1
+a 10140 14483 1
+a 10141 14482 1
+a 10142 14481 1
+a 10143 14480 1
+a 10144 14479 1
+a 10145 14478 1
+a 10146 14477 1
+a 10147 14476 1
+a 10148 14475 1
+a 10149 14474 1
+a 10150 14473 1
+a 10151 14472 1
+a 10152 14471 1
+a 10153 14470 1
+a 10154 14469 1
+a 10155 14468 1
+a 10156 14467 1
+a 10157 14466 1
+a 10158 14465 1
+a 10159 14464 1
+a 10160 14463 1
+a 10161 14462 1
+a 10162 14461 1
+a 10163 14460 1
+a 10164 14459 1
+a 10165 14458 1
+a 10166 14457 1
+a 10167 14456 1
+a 10168 14455 1
+a 10169 14454 1
+a 10170 14453 1
+a 10171 14452 1
+a 10172 14451 1
+a 10173 14450 1
+a 10174 14449 1
+a 10175 14448 1
+a 10176 14447 1
+a 10177 14446 1
+a 10178 14445 1
+a 10179 14444 1
+a 10180 14443 1
+a 10181 14442 1
+a 10182 14441 1
+a 10183 14440 1
+a 10184 14439 1
+a 10185 14438 1
+a 10186 14437 1
+a 10187 14436 1
+a 10188 14435 1
+a 10189 14434 1
+a 10190 14433 1
+a 10191 14432 1
+a 10192 14431 1
+a 10193 14430 1
+a 10194 14429 1
+a 10195 14428 1
+a 10196 14427 1
+a 10197 14426 1
+a 10198 14425 1
+a 10199 14424 1
+a 10200 14423 1
+a 10201 14422 1
+a 10202 14421 1
+a 10203 14420 1
+a 10204 14419 1
+a 10205 14418 1
+a 10206 14417 1
+a 10207 14416 1
+a 10208 14415 1
+a 10209 14414 1
+a 10210 14413 1
+a 10211 14412 1
+a 10212 14411 1
+a 10213 14410 1
+a 10214 14409 1
+a 10215 14408 1
+a 10216 14407 1
+a 10217 14406 1
+a 10218 14405 1
+a 10219 14404 1
+a 10220 14403 1
+a 10221 14402 1
+a 10222 14401 1
+a 10223 14400 1
+a 10224 14399 1
+a 10225 14398 1
+a 10226 14397 1
+a 10227 14396 1
+a 10228 14395 1
+a 10229 14394 1
+a 10230 14393 1
+a 10231 14392 1
+a 10232 14391 1
+a 10233 14390 1
+a 10234 14389 1
+a 10235 14388 1
+a 10236 14387 1
+a 10237 14386 1
+a 10238 14385 1
+a 10239 14384 1
+a 10240 14383 1
+a 10241 14382 1
+a 10242 14381 1
+a 10243 14380 1
+a 10244 14379 1
+a 10245 14378 1
+a 10246 14377 1
+a 10247 14376 1
+a 10248 14375 1
+a 10249 14374 1
+a 10250 14373 1
+a 10251 14372 1
+a 10252 14371 1
+a 10253 14370 1
+a 10254 14369 1
+a 10255 14368 1
+a 10256 14367 1
+a 10257 14366 1
+a 10258 14365 1
+a 10259 14364 1
+a 10260 14363 1
+a 10261 14362 1
+a 10262 14361 1
+a 10263 14360 1
+a 10264 14359 1
+a 10265 14358 1
+a 10266 14357 1
+a 10267 14356 1
+a 10268 14355 1
+a 10269 14354 1
+a 10270 14353 1
+a 10271 14352 1
+a 10272 14351 1
+a 10273 14350 1
+a 10274 14349 1
+a 10275 14348 1
+a 10276 14347 1
+a 10277 14346 1
+a 10278 14345 1
+a 10279 14344 1
+a 10280 14343 1
+a 10281 14342 1
+a 10282 14341 1
+a 10283 14340 1
+a 10284 14339 1
+a 10285 14338 1
+a 10286 14337 1
+a 10287 14336 1
+a 10288 14335 1
+a 10289 14334 1
+a 10290 14333 1
+a 10291 14332 1
+a 10292 14331 1
+a 10293 14330 1
+a 10294 14329 1
+a 10295 14328 1
+a 10296 14327 1
+a 10297 14326 1
+a 10298 14325 1
+a 10299 14324 1
+a 10300 14323 1
+a 10301 14322 1
+a 10302 14321 1
+a 10303 14320 1
+a 10304 14319 1
+a 10305 14318 1
+a 10306 14317 1
+a 10307 14316 1
+a 10308 14315 1
+a 10309 14314 1
+a 10310 14313 1
+a 10311 14312 1
+a 10312 14311 1
+a 10313 14310 1
+a 10314 14309 1
+a 10315 14308 1
+a 10316 14307 1
+a 10317 14306 1
+a 10318 14305 1
+a 10319 14304 1
+a 10320 14303 1
+a 10321 14302 1
+a 10322 14301 1
+a 10323 14300 1
+a 10324 14299 1
+a 10325 14298 1
+a 10326 14297 1
+a 10327 14296 1
+a 10328 14295 1
+a 10329 14294 1
+a 10330 14293 1
+a 10331 14292 1
+a 10332 14291 1
+a 10333 14290 1
+a 10334 14289 1
+a 10335 14288 1
+a 10336 14287 1
+a 10337 14286 1
+a 10338 14285 1
+a 10339 14284 1
+a 10340 14283 1
+a 10341 14282 1
+a 10342 14281 1
+a 10343 14280 1
+a 10344 14279 1
+a 10345 14278 1
+a 10346 14277 1
+a 10347 14276 1
+a 10348 14275 1
+a 10349 14274 1
+a 10350 14273 1
+a 10351 14272 1
+a 10352 14271 1
+a 10353 14270 1
+a 10354 14269 1
+a 10355 14268 1
+a 10356 14267 1
+a 10357 14266 1
+a 10358 14265 1
+a 10359 14264 1
+a 10360 14263 1
+a 10361 14262 1
+a 10362 14261 1
+a 10363 14260 1
+a 10364 14259 1
+a 10365 14258 1
+a 10366 14257 1
+a 10367 14256 1
+a 10368 14255 1
+a 10369 14254 1
+a 10370 14253 1
+a 10371 14252 1
+a 10372 14251 1
+a 10373 14250 1
+a 10374 14249 1
+a 10375 14248 1
+a 10376 14247 1
+a 10377 14246 1
+a 10378 14245 1
+a 10379 14244 1
+a 10380 14243 1
+a 10381 14242 1
+a 10382 14241 1
+a 10383 14240 1
+a 10384 14239 1
+a 10385 14238 1
+a 10386 14237 1
+a 10387 14236 1
+a 10388 14235 1
+a 10389 14234 1
+a 10390 14233 1
+a 10391 14232 1
+a 10392 14231 1
+a 10393 14230 1
+a 10394 14229 1
+a 10395 14228 1
+a 10396 14227 1
+a 10397 14226 1
+a 10398 14225 1
+a 10399 14224 1
+a 10400 14223 1
+a 10401 14222 1
+a 10402 14221 1
+a 10403 14220 1
+a 10404 14219 1
+a 10405 14218 1
+a 10406 14217 1
+a 10407 14216 1
+a 10408 14215 1
+a 10409 14214 1
+a 10410 14213 1
+a 10411 14212 1
+a 10412 14211 1
+a 10413 14210 1
+a 10414 14209 1
+a 10415 14208 1
+a 10416 14207 1
+a 10417 14206 1
+a 10418 14205 1
+a 10419 14204 1
+a 10420 14203 1
+a 10421 14202 1
+a 10422 14201 1
+a 10423 14200 1
+a 10424 14199 1
+a 10425 14198 1
+a 10426 14197 1
+a 10427 14196 1
+a 10428 14195 1
+a 10429 14194 1
+a 10430 14193 1
+a 10431 14192 1
+a 10432 14191 1
+a 10433 14190 1
+a 10434 14189 1
+a 10435 14188 1
+a 10436 14187 1
+a 10437 14186 1
+a 10438 14185 1
+a 10439 14184 1
+a 10440 14183 1
+a 10441 14182 1
+a 10442 14181 1
+a 10443 14180 1
+a 10444 14179 1
+a 10445 14178 1
+a 10446 14177 1
+a 10447 14176 1
+a 10448 14175 1
+a 10449 14174 1
+a 10450 14173 1
+a 10451 14172 1
+a 10452 14171 1
+a 10453 14170 1
+a 10454 14169 1
+a 10455 14168 1
+a 10456 14167 1
+a 10457 14166 1
+a 10458 14165 1
+a 10459 14164 1
+a 10460 14163 1
+a 10461 14162 1
+a 10462 14161 1
+a 10463 14160 1
+a 10464 14159 1
+a 10465 14158 1
+a 10466 14157 1
+a 10467 14156 1
+a 10468 14155 1
+a 10469 14154 1
+a 10470 14153 1
+a 10471 14152 1
+a 10472 14151 1
+a 10473 14150 1
+a 10474 14149 1
+a 10475 14148 1
+a 10476 14147 1
+a 10477 14146 1
+a 10478 14145 1
+a 10479 14144 1
+a 10480 14143 1
+a 10481 14142 1
+a 10482 14141 1
+a 10483 14140 1
+a 10484 14139 1
+a 10485 14138 1
+a 10486 14137 1
+a 10487 14136 1
+a 10488 14135 1
+a 10489 14134 1
+a 10490 14133 1
+a 10491 14132 1
+a 10492 14131 1
+a 10493 14130 1
+a 10494 14129 1
+a 10495 14128 1
+a 10496 14127 1
+a 10497 14126 1
+a 10498 14125 1
+a 10499 14124 1
+a 10500 14123 1
+a 10501 14122 1
+a 10502 14121 1
+a 10503 14120 1
+a 10504 14119 1
+a 10505 14118 1
+a 10506 14117 1
+a 10507 14116 1
+a 10508 14115 1
+a 10509 14114 1
+a 10510 14113 1
+a 10511 14112 1
+a 10512 14111 1
+a 10513 14110 1
+a 10514 14109 1
+a 10515 14108 1
+a 10516 14107 1
+a 10517 14106 1
+a 10518 14105 1
+a 10519 14104 1
+a 10520 14103 1
+a 10521 14102 1
+a 10522 14101 1
+a 10523 14100 1
+a 10524 14099 1
+a 10525 14098 1
+a 10526 14097 1
+a 10527 14096 1
+a 10528 14095 1
+a 10529 14094 1
+a 10530 14093 1
+a 10531 14092 1
+a 10532 14091 1
+a 10533 14090 1
+a 10534 14089 1
+a 10535 14088 1
+a 10536 14087 1
+a 10537 14086 1
+a 10538 14085 1
+a 10539 14084 1
+a 10540 14083 1
+a 10541 14082 1
+a 10542 14081 1
+a 10543 14080 1
+a 10544 14079 1
+a 10545 14078 1
+a 10546 14077 1
+a 10547 14076 1
+a 10548 14075 1
+a 10549 14074 1
+a 10550 14073 1
+a 10551 14072 1
+a 10552 14071 1
+a 10553 14070 1
+a 10554 14069 1
+a 10555 14068 1
+a 10556 14067 1
+a 10557 14066 1
+a 10558 14065 1
+a 10559 14064 1
+a 10560 14063 1
+a 10561 14062 1
+a 10562 14061 1
+a 10563 14060 1
+a 10564 14059 1
+a 10565 14058 1
+a 10566 14057 1
+a 10567 14056 1
+a 10568 14055 1
+a 10569 14054 1
+a 10570 14053 1
+a 10571 14052 1
+a 10572 14051 1
+a 10573 14050 1
+a 10574 14049 1
+a 10575 14048 1
+a 10576 14047 1
+a 10577 14046 1
+a 10578 14045 1
+a 10579 14044 1
+a 10580 14043 1
+a 10581 14042 1
+a 10582 14041 1
+a 10583 14040 1
+a 10584 14039 1
+a 10585 14038 1
+a 10586 14037 1
+a 10587 14036 1
+a 10588 14035 1
+a 10589 14034 1
+a 10590 14033 1
+a 10591 14032 1
+a 10592 14031 1
+a 10593 14030 1
+a 10594 14029 1
+a 10595 14028 1
+a 10596 14027 1
+a 10597 14026 1
+a 10598 14025 1
+a 10599 14024 1
+a 10600 14023 1
+a 10601 14022 1
+a 10602 14021 1
+a 10603 14020 1
+a 10604 14019 1
+a 10605 14018 1
+a 10606 14017 1
+a 10607 14016 1
+a 10608 14015 1
+a 10609 14014 1
+a 10610 14013 1
+a 10611 14012 1
+a 10612 14011 1
+a 10613 14010 1
+a 10614 14009 1
+a 10615 14008 1
+a 10616 14007 1
+a 10617 14006 1
+a 10618 14005 1
+a 10619 14004 1
+a 10620 14003 1
+a 10621 14002 1
+a 10622 14001 1
+a 10623 14000 1
+a 10624 13999 1
+a 10625 13998 1
+a 10626 13997 1
+a 10627 13996 1
+a 10628 13995 1
+a 10629 13994 1
+a 10630 13993 1
+a 10631 13992 1
+a 10632 13991 1
+a 10633 13990 1
+a 10634 13989 1
+a 10635 13988 1
+a 10636 13987 1
+a 10637 13986 1
+a 10638 13985 1
+a 10639 13984 1
+a 10640 13983 1
+a 10641 13982 1
+a 10642 13981 1
+a 10643 13980 1
+a 10644 13979 1
+a 10645 13978 1
+a 10646 13977 1
+a 10647 13976 1
+a 10648 13975 1
+a 10649 13974 1
+a 10650 13973 1
+a 10651 13972 1
+a 10652 13971 1
+a 10653 13970 1
+a 10654 13969 1
+a 10655 13968 1
+a 10656 13967 1
+a 10657 13966 1
+a 10658 13965 1
+a 10659 13964 1
+a 10660 13963 1
+a 10661 13962 1
+a 10662 13961 1
+a 10663 13960 1
+a 10664 13959 1
+a 10665 13958 1
+a 10666 13957 1
+a 10667 13956 1
+a 10668 13955 1
+a 10669 13954 1
+a 10670 13953 1
+a 10671 13952 1
+a 10672 13951 1
+a 10673 13950 1
+a 10674 13949 1
+a 10675 13948 1
+a 10676 13947 1
+a 10677 13946 1
+a 10678 13945 1
+a 10679 13944 1
+a 10680 13943 1
+a 10681 13942 1
+a 10682 13941 1
+a 10683 13940 1
+a 10684 13939 1
+a 10685 13938 1
+a 10686 13937 1
+a 10687 13936 1
+a 10688 13935 1
+a 10689 13934 1
+a 10690 13933 1
+a 10691 13932 1
+a 10692 13931 1
+a 10693 13930 1
+a 10694 13929 1
+a 10695 13928 1
+a 10696 13927 1
+a 10697 13926 1
+a 10698 13925 1
+a 10699 13924 1
+a 10700 13923 1
+a 10701 13922 1
+a 10702 13921 1
+a 10703 13920 1
+a 10704 13919 1
+a 10705 13918 1
+a 10706 13917 1
+a 10707 13916 1
+a 10708 13915 1
+a 10709 13914 1
+a 10710 13913 1
+a 10711 13912 1
+a 10712 13911 1
+a 10713 13910 1
+a 10714 13909 1
+a 10715 13908 1
+a 10716 13907 1
+a 10717 13906 1
+a 10718 13905 1
+a 10719 13904 1
+a 10720 13903 1
+a 10721 13902 1
+a 10722 13901 1
+a 10723 13900 1
+a 10724 13899 1
+a 10725 13898 1
+a 10726 13897 1
+a 10727 13896 1
+a 10728 13895 1
+a 10729 13894 1
+a 10730 13893 1
+a 10731 13892 1
+a 10732 13891 1
+a 10733 13890 1
+a 10734 13889 1
+a 10735 13888 1
+a 10736 13887 1
+a 10737 13886 1
+a 10738 13885 1
+a 10739 13884 1
+a 10740 13883 1
+a 10741 13882 1
+a 10742 13881 1
+a 10743 13880 1
+a 10744 13879 1
+a 10745 13878 1
+a 10746 13877 1
+a 10747 13876 1
+a 10748 13875 1
+a 10749 13874 1
+a 10750 13873 1
+a 10751 13872 1
+a 10752 13871 1
+a 10753 13870 1
+a 10754 13869 1
+a 10755 13868 1
+a 10756 13867 1
+a 10757 13866 1
+a 10758 13865 1
+a 10759 13864 1
+a 10760 13863 1
+a 10761 13862 1
+a 10762 13861 1
+a 10763 13860 1
+a 10764 13859 1
+a 10765 13858 1
+a 10766 13857 1
+a 10767 13856 1
+a 10768 13855 1
+a 10769 13854 1
+a 10770 13853 1
+a 10771 13852 1
+a 10772 13851 1
+a 10773 13850 1
+a 10774 13849 1
+a 10775 13848 1
+a 10776 13847 1
+a 10777 13846 1
+a 10778 13845 1
+a 10779 13844 1
+a 10780 13843 1
+a 10781 13842 1
+a 10782 13841 1
+a 10783 13840 1
+a 10784 13839 1
+a 10785 13838 1
+a 10786 13837 1
+a 10787 13836 1
+a 10788 13835 1
+a 10789 13834 1
+a 10790 13833 1
+a 10791 13832 1
+a 10792 13831 1
+a 10793 13830 1
+a 10794 13829 1
+a 10795 13828 1
+a 10796 13827 1
+a 10797 13826 1
+a 10798 13825 1
+a 10799 13824 1
+a 10800 13823 1
+a 10801 13822 1
+a 10802 13821 1
+a 10803 13820 1
+a 10804 13819 1
+a 10805 13818 1
+a 10806 13817 1
+a 10807 13816 1
+a 10808 13815 1
+a 10809 13814 1
+a 10810 13813 1
+a 10811 13812 1
+a 10812 13811 1
+a 10813 13810 1
+a 10814 13809 1
+a 10815 13808 1
+a 10816 13807 1
+a 10817 13806 1
+a 10818 13805 1
+a 10819 13804 1
+a 10820 13803 1
+a 10821 13802 1
+a 10822 13801 1
+a 10823 13800 1
+a 10824 13799 1
+a 10825 13798 1
+a 10826 13797 1
+a 10827 13796 1
+a 10828 13795 1
+a 10829 13794 1
+a 10830 13793 1
+a 10831 13792 1
+a 10832 13791 1
+a 10833 13790 1
+a 10834 13789 1
+a 10835 13788 1
+a 10836 13787 1
+a 10837 13786 1
+a 10838 13785 1
+a 10839 13784 1
+a 10840 13783 1
+a 10841 13782 1
+a 10842 13781 1
+a 10843 13780 1
+a 10844 13779 1
+a 10845 13778 1
+a 10846 13777 1
+a 10847 13776 1
+a 10848 13775 1
+a 10849 13774 1
+a 10850 13773 1
+a 10851 13772 1
+a 10852 13771 1
+a 10853 13770 1
+a 10854 13769 1
+a 10855 13768 1
+a 10856 13767 1
+a 10857 13766 1
+a 10858 13765 1
+a 10859 13764 1
+a 10860 13763 1
+a 10861 13762 1
+a 10862 13761 1
+a 10863 13760 1
+a 10864 13759 1
+a 10865 13758 1
+a 10866 13757 1
+a 10867 13756 1
+a 10868 13755 1
+a 10869 13754 1
+a 10870 13753 1
+a 10871 13752 1
+a 10872 13751 1
+a 10873 13750 1
+a 10874 13749 1
+a 10875 13748 1
+a 10876 13747 1
+a 10877 13746 1
+a 10878 13745 1
+a 10879 13744 1
+a 10880 13743 1
+a 10881 13742 1
+a 10882 13741 1
+a 10883 13740 1
+a 10884 13739 1
+a 10885 13738 1
+a 10886 13737 1
+a 10887 13736 1
+a 10888 13735 1
+a 10889 13734 1
+a 10890 13733 1
+a 10891 13732 1
+a 10892 13731 1
+a 10893 13730 1
+a 10894 13729 1
+a 10895 13728 1
+a 10896 13727 1
+a 10897 13726 1
+a 10898 13725 1
+a 10899 13724 1
+a 10900 13723 1
+a 10901 13722 1
+a 10902 13721 1
+a 10903 13720 1
+a 10904 13719 1
+a 10905 13718 1
+a 10906 13717 1
+a 10907 13716 1
+a 10908 13715 1
+a 10909 13714 1
+a 10910 13713 1
+a 10911 13712 1
+a 10912 13711 1
+a 10913 13710 1
+a 10914 13709 1
+a 10915 13708 1
+a 10916 13707 1
+a 10917 13706 1
+a 10918 13705 1
+a 10919 13704 1
+a 10920 13703 1
+a 10921 13702 1
+a 10922 13701 1
+a 10923 13700 1
+a 10924 13699 1
+a 10925 13698 1
+a 10926 13697 1
+a 10927 13696 1
+a 10928 13695 1
+a 10929 13694 1
+a 10930 13693 1
+a 10931 13692 1
+a 10932 13691 1
+a 10933 13690 1
+a 10934 13689 1
+a 10935 13688 1
+a 10936 13687 1
+a 10937 13686 1
+a 10938 13685 1
+a 10939 13684 1
+a 10940 13683 1
+a 10941 13682 1
+a 10942 13681 1
+a 10943 13680 1
+a 10944 13679 1
+a 10945 13678 1
+a 10946 13677 1
+a 10947 13676 1
+a 10948 13675 1
+a 10949 13674 1
+a 10950 13673 1
+a 10951 13672 1
+a 10952 13671 1
+a 10953 13670 1
+a 10954 13669 1
+a 10955 13668 1
+a 10956 13667 1
+a 10957 13666 1
+a 10958 13665 1
+a 10959 13664 1
+a 10960 13663 1
+a 10961 13662 1
+a 10962 13661 1
+a 10963 13660 1
+a 10964 13659 1
+a 10965 13658 1
+a 10966 13657 1
+a 10967 13656 1
+a 10968 13655 1
+a 10969 13654 1
+a 10970 13653 1
+a 10971 13652 1
+a 10972 13651 1
+a 10973 13650 1
+a 10974 13649 1
+a 10975 13648 1
+a 10976 13647 1
+a 10977 13646 1
+a 10978 13645 1
+a 10979 13644 1
+a 10980 13643 1
+a 10981 13642 1
+a 10982 13641 1
+a 10983 13640 1
+a 10984 13639 1
+a 10985 13638 1
+a 10986 13637 1
+a 10987 13636 1
+a 10988 13635 1
+a 10989 13634 1
+a 10990 13633 1
+a 10991 13632 1
+a 10992 13631 1
+a 10993 13630 1
+a 10994 13629 1
+a 10995 13628 1
+a 10996 13627 1
+a 10997 13626 1
+a 10998 13625 1
+a 10999 13624 1
+a 11000 13623 1
+a 11001 13622 1
+a 11002 13621 1
+a 11003 13620 1
+a 11004 13619 1
+a 11005 13618 1
+a 11006 13617 1
+a 11007 13616 1
+a 11008 13615 1
+a 11009 13614 1
+a 11010 13613 1
+a 11011 13612 1
+a 11012 13611 1
+a 11013 13610 1
+a 11014 13609 1
+a 11015 13608 1
+a 11016 13607 1
+a 11017 13606 1
+a 11018 13605 1
+a 11019 13604 1
+a 11020 13603 1
+a 11021 13602 1
+a 11022 13601 1
+a 11023 13600 1
+a 11024 13599 1
+a 11025 13598 1
+a 11026 13597 1
+a 11027 13596 1
+a 11028 13595 1
+a 11029 13594 1
+a 11030 13593 1
+a 11031 13592 1
+a 11032 13591 1
+a 11033 13590 1
+a 11034 13589 1
+a 11035 13588 1
+a 11036 13587 1
+a 11037 13586 1
+a 11038 13585 1
+a 11039 13584 1
+a 11040 13583 1
+a 11041 13582 1
+a 11042 13581 1
+a 11043 13580 1
+a 11044 13579 1
+a 11045 13578 1
+a 11046 13577 1
+a 11047 13576 1
+a 11048 13575 1
+a 11049 13574 1
+a 11050 13573 1
+a 11051 13572 1
+a 11052 13571 1
+a 11053 13570 1
+a 11054 13569 1
+a 11055 13568 1
+a 11056 13567 1
+a 11057 13566 1
+a 11058 13565 1
+a 11059 13564 1
+a 11060 13563 1
+a 11061 13562 1
+a 11062 13561 1
+a 11063 13560 1
+a 11064 13559 1
+a 11065 13558 1
+a 11066 13557 1
+a 11067 13556 1
+a 11068 13555 1
+a 11069 13554 1
+a 11070 13553 1
+a 11071 13552 1
+a 11072 13551 1
+a 11073 13550 1
+a 11074 13549 1
+a 11075 13548 1
+a 11076 13547 1
+a 11077 13546 1
+a 11078 13545 1
+a 11079 13544 1
+a 11080 13543 1
+a 11081 13542 1
+a 11082 13541 1
+a 11083 13540 1
+a 11084 13539 1
+a 11085 13538 1
+a 11086 13537 1
+a 11087 13536 1
+a 11088 13535 1
+a 11089 13534 1
+a 11090 13533 1
+a 11091 13532 1
+a 11092 13531 1
+a 11093 13530 1
+a 11094 13529 1
+a 11095 13528 1
+a 11096 13527 1
+a 11097 13526 1
+a 11098 13525 1
+a 11099 13524 1
+a 11100 13523 1
+a 11101 13522 1
+a 11102 13521 1
+a 11103 13520 1
+a 11104 13519 1
+a 11105 13518 1
+a 11106 13517 1
+a 11107 13516 1
+a 11108 13515 1
+a 11109 13514 1
+a 11110 13513 1
+a 11111 13512 1
+a 11112 13511 1
+a 11113 13510 1
+a 11114 13509 1
+a 11115 13508 1
+a 11116 13507 1
+a 11117 13506 1
+a 11118 13505 1
+a 11119 13504 1
+a 11120 13503 1
+a 11121 13502 1
+a 11122 13501 1
+a 11123 13500 1
+a 11124 13499 1
+a 11125 13498 1
+a 11126 13497 1
+a 11127 13496 1
+a 11128 13495 1
+a 11129 13494 1
+a 11130 13493 1
+a 11131 13492 1
+a 11132 13491 1
+a 11133 13490 1
+a 11134 13489 1
+a 11135 13488 1
+a 11136 13487 1
+a 11137 13486 1
+a 11138 13485 1
+a 11139 13484 1
+a 11140 13483 1
+a 11141 13482 1
+a 11142 13481 1
+a 11143 13480 1
+a 11144 13479 1
+a 11145 13478 1
+a 11146 13477 1
+a 11147 13476 1
+a 11148 13475 1
+a 11149 13474 1
+a 11150 13473 1
+a 11151 13472 1
+a 11152 13471 1
+a 11153 13470 1
+a 11154 13469 1
+a 11155 13468 1
+a 11156 13467 1
+a 11157 13466 1
+a 11158 13465 1
+a 11159 13464 1
+a 11160 13463 1
+a 11161 13462 1
+a 11162 13461 1
+a 11163 13460 1
+a 11164 13459 1
+a 11165 13458 1
+a 11166 13457 1
+a 11167 13456 1
+a 11168 13455 1
+a 11169 13454 1
+a 11170 13453 1
+a 11171 13452 1
+a 11172 13451 1
+a 11173 13450 1
+a 11174 13449 1
+a 11175 13448 1
+a 11176 13447 1
+a 11177 13446 1
+a 11178 13445 1
+a 11179 13444 1
+a 11180 13443 1
+a 11181 13442 1
+a 11182 13441 1
+a 11183 13440 1
+a 11184 13439 1
+a 11185 13438 1
+a 11186 13437 1
+a 11187 13436 1
+a 11188 13435 1
+a 11189 13434 1
+a 11190 13433 1
+a 11191 13432 1
+a 11192 13431 1
+a 11193 13430 1
+a 11194 13429 1
+a 11195 13428 1
+a 11196 13427 1
+a 11197 13426 1
+a 11198 13425 1
+a 11199 13424 1
+a 11200 13423 1
+a 11201 13422 1
+a 11202 13421 1
+a 11203 13420 1
+a 11204 13419 1
+a 11205 13418 1
+a 11206 13417 1
+a 11207 13416 1
+a 11208 13415 1
+a 11209 13414 1
+a 11210 13413 1
+a 11211 13412 1
+a 11212 13411 1
+a 11213 13410 1
+a 11214 13409 1
+a 11215 13408 1
+a 11216 13407 1
+a 11217 13406 1
+a 11218 13405 1
+a 11219 13404 1
+a 11220 13403 1
+a 11221 13402 1
+a 11222 13401 1
+a 11223 13400 1
+a 11224 13399 1
+a 11225 13398 1
+a 11226 13397 1
+a 11227 13396 1
+a 11228 13395 1
+a 11229 13394 1
+a 11230 13393 1
+a 11231 13392 1
+a 11232 13391 1
+a 11233 13390 1
+a 11234 13389 1
+a 11235 13388 1
+a 11236 13387 1
+a 11237 13386 1
+a 11238 13385 1
+a 11239 13384 1
+a 11240 13383 1
+a 11241 13382 1
+a 11242 13381 1
+a 11243 13380 1
+a 11244 13379 1
+a 11245 13378 1
+a 11246 13377 1
+a 11247 13376 1
+a 11248 13375 1
+a 11249 13374 1
+a 11250 13373 1
+a 11251 13372 1
+a 11252 13371 1
+a 11253 13370 1
+a 11254 13369 1
+a 11255 13368 1
+a 11256 13367 1
+a 11257 13366 1
+a 11258 13365 1
+a 11259 13364 1
+a 11260 13363 1
+a 11261 13362 1
+a 11262 13361 1
+a 11263 13360 1
+a 11264 13359 1
+a 11265 13358 1
+a 11266 13357 1
+a 11267 13356 1
+a 11268 13355 1
+a 11269 13354 1
+a 11270 13353 1
+a 11271 13352 1
+a 11272 13351 1
+a 11273 13350 1
+a 11274 13349 1
+a 11275 13348 1
+a 11276 13347 1
+a 11277 13346 1
+a 11278 13345 1
+a 11279 13344 1
+a 11280 13343 1
+a 11281 13342 1
+a 11282 13341 1
+a 11283 13340 1
+a 11284 13339 1
+a 11285 13338 1
+a 11286 13337 1
+a 11287 13336 1
+a 11288 13335 1
+a 11289 13334 1
+a 11290 13333 1
+a 11291 13332 1
+a 11292 13331 1
+a 11293 13330 1
+a 11294 13329 1
+a 11295 13328 1
+a 11296 13327 1
+a 11297 13326 1
+a 11298 13325 1
+a 11299 13324 1
+a 11300 13323 1
+a 11301 13322 1
+a 11302 13321 1
+a 11303 13320 1
+a 11304 13319 1
+a 11305 13318 1
+a 11306 13317 1
+a 11307 13316 1
+a 11308 13315 1
+a 11309 13314 1
+a 11310 13313 1
+a 11311 13312 1
+a 11312 13311 1
+a 11313 13310 1
+a 11314 13309 1
+a 11315 13308 1
+a 11316 13307 1
+a 11317 13306 1
+a 11318 13305 1
+a 11319 13304 1
+a 11320 13303 1
+a 11321 13302 1
+a 11322 13301 1
+a 11323 13300 1
+a 11324 13299 1
+a 11325 13298 1
+a 11326 13297 1
+a 11327 13296 1
+a 11328 13295 1
+a 11329 13294 1
+a 11330 13293 1
+a 11331 13292 1
+a 11332 13291 1
+a 11333 13290 1
+a 11334 13289 1
+a 11335 13288 1
+a 11336 13287 1
+a 11337 13286 1
+a 11338 13285 1
+a 11339 13284 1
+a 11340 13283 1
+a 11341 13282 1
+a 11342 13281 1
+a 11343 13280 1
+a 11344 13279 1
+a 11345 13278 1
+a 11346 13277 1
+a 11347 13276 1
+a 11348 13275 1
+a 11349 13274 1
+a 11350 13273 1
+a 11351 13272 1
+a 11352 13271 1
+a 11353 13270 1
+a 11354 13269 1
+a 11355 13268 1
+a 11356 13267 1
+a 11357 13266 1
+a 11358 13265 1
+a 11359 13264 1
+a 11360 13263 1
+a 11361 13262 1
+a 11362 13261 1
+a 11363 13260 1
+a 11364 13259 1
+a 11365 13258 1
+a 11366 13257 1
+a 11367 13256 1
+a 11368 13255 1
+a 11369 13254 1
+a 11370 13253 1
+a 11371 13252 1
+a 11372 13251 1
+a 11373 13250 1
+a 11374 13249 1
+a 11375 13248 1
+a 11376 13247 1
+a 11377 13246 1
+a 11378 13245 1
+a 11379 13244 1
+a 11380 13243 1
+a 11381 13242 1
+a 11382 13241 1
+a 11383 13240 1
+a 11384 13239 1
+a 11385 13238 1
+a 11386 13237 1
+a 11387 13236 1
+a 11388 13235 1
+a 11389 13234 1
+a 11390 13233 1
+a 11391 13232 1
+a 11392 13231 1
+a 11393 13230 1
+a 11394 13229 1
+a 11395 13228 1
+a 11396 13227 1
+a 11397 13226 1
+a 11398 13225 1
+a 11399 13224 1
+a 11400 13223 1
+a 11401 13222 1
+a 11402 13221 1
+a 11403 13220 1
+a 11404 13219 1
+a 11405 13218 1
+a 11406 13217 1
+a 11407 13216 1
+a 11408 13215 1
+a 11409 13214 1
+a 11410 13213 1
+a 11411 13212 1
+a 11412 13211 1
+a 11413 13210 1
+a 11414 13209 1
+a 11415 13208 1
+a 11416 13207 1
+a 11417 13206 1
+a 11418 13205 1
+a 11419 13204 1
+a 11420 13203 1
+a 11421 13202 1
+a 11422 13201 1
+a 11423 13200 1
+a 11424 13199 1
+a 11425 13198 1
+a 11426 13197 1
+a 11427 13196 1
+a 11428 13195 1
+a 11429 13194 1
+a 11430 13193 1
+a 11431 13192 1
+a 11432 13191 1
+a 11433 13190 1
+a 11434 13189 1
+a 11435 13188 1
+a 11436 13187 1
+a 11437 13186 1
+a 11438 13185 1
+a 11439 13184 1
+a 11440 13183 1
+a 11441 13182 1
+a 11442 13181 1
+a 11443 13180 1
+a 11444 13179 1
+a 11445 13178 1
+a 11446 13177 1
+a 11447 13176 1
+a 11448 13175 1
+a 11449 13174 1
+a 11450 13173 1
+a 11451 13172 1
+a 11452 13171 1
+a 11453 13170 1
+a 11454 13169 1
+a 11455 13168 1
+a 11456 13167 1
+a 11457 13166 1
+a 11458 13165 1
+a 11459 13164 1
+a 11460 13163 1
+a 11461 13162 1
+a 11462 13161 1
+a 11463 13160 1
+a 11464 13159 1
+a 11465 13158 1
+a 11466 13157 1
+a 11467 13156 1
+a 11468 13155 1
+a 11469 13154 1
+a 11470 13153 1
+a 11471 13152 1
+a 11472 13151 1
+a 11473 13150 1
+a 11474 13149 1
+a 11475 13148 1
+a 11476 13147 1
+a 11477 13146 1
+a 11478 13145 1
+a 11479 13144 1
+a 11480 13143 1
+a 11481 13142 1
+a 11482 13141 1
+a 11483 13140 1
+a 11484 13139 1
+a 11485 13138 1
+a 11486 13137 1
+a 11487 13136 1
+a 11488 13135 1
+a 11489 13134 1
+a 11490 13133 1
+a 11491 13132 1
+a 11492 13131 1
+a 11493 13130 1
+a 11494 13129 1
+a 11495 13128 1
+a 11496 13127 1
+a 11497 13126 1
+a 11498 13125 1
+a 11499 13124 1
+a 11500 13123 1
+a 11501 13122 1
+a 11502 13121 1
+a 11503 13120 1
+a 11504 13119 1
+a 11505 13118 1
+a 11506 13117 1
+a 11507 13116 1
+a 11508 13115 1
+a 11509 13114 1
+a 11510 13113 1
+a 11511 13112 1
+a 11512 13111 1
+a 11513 13110 1
+a 11514 13109 1
+a 11515 13108 1
+a 11516 13107 1
+a 11517 13106 1
+a 11518 13105 1
+a 11519 13104 1
+a 11520 13103 1
+a 11521 13102 1
+a 11522 13101 1
+a 11523 13100 1
+a 11524 13099 1
+a 11525 13098 1
+a 11526 13097 1
+a 11527 13096 1
+a 11528 13095 1
+a 11529 13094 1
+a 11530 13093 1
+a 11531 13092 1
+a 11532 13091 1
+a 11533 13090 1
+a 11534 13089 1
+a 11535 13088 1
+a 11536 13087 1
+a 11537 13086 1
+a 11538 13085 1
+a 11539 13084 1
+a 11540 13083 1
+a 11541 13082 1
+a 11542 13081 1
+a 11543 13080 1
+a 11544 13079 1
+a 11545 13078 1
+a 11546 13077 1
+a 11547 13076 1
+a 11548 13075 1
+a 11549 13074 1
+a 11550 13073 1
+a 11551 13072 1
+a 11552 13071 1
+a 11553 13070 1
+a 11554 13069 1
+a 11555 13068 1
+a 11556 13067 1
+a 11557 13066 1
+a 11558 13065 1
+a 11559 13064 1
+a 11560 13063 1
+a 11561 13062 1
+a 11562 13061 1
+a 11563 13060 1
+a 11564 13059 1
+a 11565 13058 1
+a 11566 13057 1
+a 11567 13056 1
+a 11568 13055 1
+a 11569 13054 1
+a 11570 13053 1
+a 11571 13052 1
+a 11572 13051 1
+a 11573 13050 1
+a 11574 13049 1
+a 11575 13048 1
+a 11576 13047 1
+a 11577 13046 1
+a 11578 13045 1
+a 11579 13044 1
+a 11580 13043 1
+a 11581 13042 1
+a 11582 13041 1
+a 11583 13040 1
+a 11584 13039 1
+a 11585 13038 1
+a 11586 13037 1
+a 11587 13036 1
+a 11588 13035 1
+a 11589 13034 1
+a 11590 13033 1
+a 11591 13032 1
+a 11592 13031 1
+a 11593 13030 1
+a 11594 13029 1
+a 11595 13028 1
+a 11596 13027 1
+a 11597 13026 1
+a 11598 13025 1
+a 11599 13024 1
+a 11600 13023 1
+a 11601 13022 1
+a 11602 13021 1
+a 11603 13020 1
+a 11604 13019 1
+a 11605 13018 1
+a 11606 13017 1
+a 11607 13016 1
+a 11608 13015 1
+a 11609 13014 1
+a 11610 13013 1
+a 11611 13012 1
+a 11612 13011 1
+a 11613 13010 1
+a 11614 13009 1
+a 11615 13008 1
+a 11616 13007 1
+a 11617 13006 1
+a 11618 13005 1
+a 11619 13004 1
+a 11620 13003 1
+a 11621 13002 1
+a 11622 13001 1
+a 11623 13000 1
+a 11624 12999 1
+a 11625 12998 1
+a 11626 12997 1
+a 11627 12996 1
+a 11628 12995 1
+a 11629 12994 1
+a 11630 12993 1
+a 11631 12992 1
+a 11632 12991 1
+a 11633 12990 1
+a 11634 12989 1
+a 11635 12988 1
+a 11636 12987 1
+a 11637 12986 1
+a 11638 12985 1
+a 11639 12984 1
+a 11640 12983 1
+a 11641 12982 1
+a 11642 12981 1
+a 11643 12980 1
+a 11644 12979 1
+a 11645 12978 1
+a 11646 12977 1
+a 11647 12976 1
+a 11648 12975 1
+a 11649 12974 1
+a 11650 12973 1
+a 11651 12972 1
+a 11652 12971 1
+a 11653 12970 1
+a 11654 12969 1
+a 11655 12968 1
+a 11656 12967 1
+a 11657 12966 1
+a 11658 12965 1
+a 11659 12964 1
+a 11660 12963 1
+a 11661 12962 1
+a 11662 12961 1
+a 11663 12960 1
+a 11664 12959 1
+a 11665 12958 1
+a 11666 12957 1
+a 11667 12956 1
+a 11668 12955 1
+a 11669 12954 1
+a 11670 12953 1
+a 11671 12952 1
+a 11672 12951 1
+a 11673 12950 1
+a 11674 12949 1
+a 11675 12948 1
+a 11676 12947 1
+a 11677 12946 1
+a 11678 12945 1
+a 11679 12944 1
+a 11680 12943 1
+a 11681 12942 1
+a 11682 12941 1
+a 11683 12940 1
+a 11684 12939 1
+a 11685 12938 1
+a 11686 12937 1
+a 11687 12936 1
+a 11688 12935 1
+a 11689 12934 1
+a 11690 12933 1
+a 11691 12932 1
+a 11692 12931 1
+a 11693 12930 1
+a 11694 12929 1
+a 11695 12928 1
+a 11696 12927 1
+a 11697 12926 1
+a 11698 12925 1
+a 11699 12924 1
+a 11700 12923 1
+a 11701 12922 1
+a 11702 12921 1
+a 11703 12920 1
+a 11704 12919 1
+a 11705 12918 1
+a 11706 12917 1
+a 11707 12916 1
+a 11708 12915 1
+a 11709 12914 1
+a 11710 12913 1
+a 11711 12912 1
+a 11712 12911 1
+a 11713 12910 1
+a 11714 12909 1
+a 11715 12908 1
+a 11716 12907 1
+a 11717 12906 1
+a 11718 12905 1
+a 11719 12904 1
+a 11720 12903 1
+a 11721 12902 1
+a 11722 12901 1
+a 11723 12900 1
+a 11724 12899 1
+a 11725 12898 1
+a 11726 12897 1
+a 11727 12896 1
+a 11728 12895 1
+a 11729 12894 1
+a 11730 12893 1
+a 11731 12892 1
+a 11732 12891 1
+a 11733 12890 1
+a 11734 12889 1
+a 11735 12888 1
+a 11736 12887 1
+a 11737 12886 1
+a 11738 12885 1
+a 11739 12884 1
+a 11740 12883 1
+a 11741 12882 1
+a 11742 12881 1
+a 11743 12880 1
+a 11744 12879 1
+a 11745 12878 1
+a 11746 12877 1
+a 11747 12876 1
+a 11748 12875 1
+a 11749 12874 1
+a 11750 12873 1
+a 11751 12872 1
+a 11752 12871 1
+a 11753 12870 1
+a 11754 12869 1
+a 11755 12868 1
+a 11756 12867 1
+a 11757 12866 1
+a 11758 12865 1
+a 11759 12864 1
+a 11760 12863 1
+a 11761 12862 1
+a 11762 12861 1
+a 11763 12860 1
+a 11764 12859 1
+a 11765 12858 1
+a 11766 12857 1
+a 11767 12856 1
+a 11768 12855 1
+a 11769 12854 1
+a 11770 12853 1
+a 11771 12852 1
+a 11772 12851 1
+a 11773 12850 1
+a 11774 12849 1
+a 11775 12848 1
+a 11776 12847 1
+a 11777 12846 1
+a 11778 12845 1
+a 11779 12844 1
+a 11780 12843 1
+a 11781 12842 1
+a 11782 12841 1
+a 11783 12840 1
+a 11784 12839 1
+a 11785 12838 1
+a 11786 12837 1
+a 11787 12836 1
+a 11788 12835 1
+a 11789 12834 1
+a 11790 12833 1
+a 11791 12832 1
+a 11792 12831 1
+a 11793 12830 1
+a 11794 12829 1
+a 11795 12828 1
+a 11796 12827 1
+a 11797 12826 1
+a 11798 12825 1
+a 11799 12824 1
+a 11800 12823 1
+a 11801 12822 1
+a 11802 12821 1
+a 11803 12820 1
+a 11804 12819 1
+a 11805 12818 1
+a 11806 12817 1
+a 11807 12816 1
+a 11808 12815 1
+a 11809 12814 1
+a 11810 12813 1
+a 11811 12812 1
+a 11812 12811 1
+a 11813 12810 1
+a 11814 12809 1
+a 11815 12808 1
+a 11816 12807 1
+a 11817 12806 1
+a 11818 12805 1
+a 11819 12804 1
+a 11820 12803 1
+a 11821 12802 1
+a 11822 12801 1
+a 11823 12800 1
+a 11824 12799 1
+a 11825 12798 1
+a 11826 12797 1
+a 11827 12796 1
+a 11828 12795 1
+a 11829 12794 1
+a 11830 12793 1
+a 11831 12792 1
+a 11832 12791 1
+a 11833 12790 1
+a 11834 12789 1
+a 11835 12788 1
+a 11836 12787 1
+a 11837 12786 1
+a 11838 12785 1
+a 11839 12784 1
+a 11840 12783 1
+a 11841 12782 1
+a 11842 12781 1
+a 11843 12780 1
+a 11844 12779 1
+a 11845 12778 1
+a 11846 12777 1
+a 11847 12776 1
+a 11848 12775 1
+a 11849 12774 1
+a 11850 12773 1
+a 11851 12772 1
+a 11852 12771 1
+a 11853 12770 1
+a 11854 12769 1
+a 11855 12768 1
+a 11856 12767 1
+a 11857 12766 1
+a 11858 12765 1
+a 11859 12764 1
+a 11860 12763 1
+a 11861 12762 1
+a 11862 12761 1
+a 11863 12760 1
+a 11864 12759 1
+a 11865 12758 1
+a 11866 12757 1
+a 11867 12756 1
+a 11868 12755 1
+a 11869 12754 1
+a 11870 12753 1
+a 11871 12752 1
+a 11872 12751 1
+a 11873 12750 1
+a 11874 12749 1
+a 11875 12748 1
+a 11876 12747 1
+a 11877 12746 1
+a 11878 12745 1
+a 11879 12744 1
+a 11880 12743 1
+a 11881 12742 1
+a 11882 12741 1
+a 11883 12740 1
+a 11884 12739 1
+a 11885 12738 1
+a 11886 12737 1
+a 11887 12736 1
+a 11888 12735 1
+a 11889 12734 1
+a 11890 12733 1
+a 11891 12732 1
+a 11892 12731 1
+a 11893 12730 1
+a 11894 12729 1
+a 11895 12728 1
+a 11896 12727 1
+a 11897 12726 1
+a 11898 12725 1
+a 11899 12724 1
+a 11900 12723 1
+a 11901 12722 1
+a 11902 12721 1
+a 11903 12720 1
+a 11904 12719 1
+a 11905 12718 1
+a 11906 12717 1
+a 11907 12716 1
+a 11908 12715 1
+a 11909 12714 1
+a 11910 12713 1
+a 11911 12712 1
+a 11912 12711 1
+a 11913 12710 1
+a 11914 12709 1
+a 11915 12708 1
+a 11916 12707 1
+a 11917 12706 1
+a 11918 12705 1
+a 11919 12704 1
+a 11920 12703 1
+a 11921 12702 1
+a 11922 12701 1
+a 11923 12700 1
+a 11924 12699 1
+a 11925 12698 1
+a 11926 12697 1
+a 11927 12696 1
+a 11928 12695 1
+a 11929 12694 1
+a 11930 12693 1
+a 11931 12692 1
+a 11932 12691 1
+a 11933 12690 1
+a 11934 12689 1
+a 11935 12688 1
+a 11936 12687 1
+a 11937 12686 1
+a 11938 12685 1
+a 11939 12684 1
+a 11940 12683 1
+a 11941 12682 1
+a 11942 12681 1
+a 11943 12680 1
+a 11944 12679 1
+a 11945 12678 1
+a 11946 12677 1
+a 11947 12676 1
+a 11948 12675 1
+a 11949 12674 1
+a 11950 12673 1
+a 11951 12672 1
+a 11952 12671 1
+a 11953 12670 1
+a 11954 12669 1
+a 11955 12668 1
+a 11956 12667 1
+a 11957 12666 1
+a 11958 12665 1
+a 11959 12664 1
+a 11960 12663 1
+a 11961 12662 1
+a 11962 12661 1
+a 11963 12660 1
+a 11964 12659 1
+a 11965 12658 1
+a 11966 12657 1
+a 11967 12656 1
+a 11968 12655 1
+a 11969 12654 1
+a 11970 12653 1
+a 11971 12652 1
+a 11972 12651 1
+a 11973 12650 1
+a 11974 12649 1
+a 11975 12648 1
+a 11976 12647 1
+a 11977 12646 1
+a 11978 12645 1
+a 11979 12644 1
+a 11980 12643 1
+a 11981 12642 1
+a 11982 12641 1
+a 11983 12640 1
+a 11984 12639 1
+a 11985 12638 1
+a 11986 12637 1
+a 11987 12636 1
+a 11988 12635 1
+a 11989 12634 1
+a 11990 12633 1
+a 11991 12632 1
+a 11992 12631 1
+a 11993 12630 1
+a 11994 12629 1
+a 11995 12628 1
+a 11996 12627 1
+a 11997 12626 1
+a 11998 12625 1
+a 11999 12624 1
+a 12000 12623 1
+a 12001 12622 1
+a 12002 12621 1
+a 12003 12620 1
+a 12004 12619 1
+a 12005 12618 1
+a 12006 12617 1
+a 12007 12616 1
+a 12008 12615 1
+a 12009 12614 1
+a 12010 12613 1
+a 12011 12612 1
+a 12012 12611 1
+a 12013 12610 1
+a 12014 12609 1
+a 12015 12608 1
+a 12016 12607 1
+a 12017 12606 1
+a 12018 12605 1
+a 12019 12604 1
+a 12020 12603 1
+a 12021 12602 1
+a 12022 12601 1
+a 12023 12600 1
+a 12024 12599 1
+a 12025 12598 1
+a 12026 12597 1
+a 12027 12596 1
+a 12028 12595 1
+a 12029 12594 1
+a 12030 12593 1
+a 12031 12592 1
+a 12032 12591 1
+a 12033 12590 1
+a 12034 12589 1
+a 12035 12588 1
+a 12036 12587 1
+a 12037 12586 1
+a 12038 12585 1
+a 12039 12584 1
+a 12040 12583 1
+a 12041 12582 1
+a 12042 12581 1
+a 12043 12580 1
+a 12044 12579 1
+a 12045 12578 1
+a 12046 12577 1
+a 12047 12576 1
+a 12048 12575 1
+a 12049 12574 1
+a 12050 12573 1
+a 12051 12572 1
+a 12052 12571 1
+a 12053 12570 1
+a 12054 12569 1
+a 12055 12568 1
+a 12056 12567 1
+a 12057 12566 1
+a 12058 12565 1
+a 12059 12564 1
+a 12060 12563 1
+a 12061 12562 1
+a 12062 12561 1
+a 12063 12560 1
+a 12064 12559 1
+a 12065 12558 1
+a 12066 12557 1
+a 12067 12556 1
+a 12068 12555 1
+a 12069 12554 1
+a 12070 12553 1
+a 12071 12552 1
+a 12072 12551 1
+a 12073 12550 1
+a 12074 12549 1
+a 12075 12548 1
+a 12076 12547 1
+a 12077 12546 1
+a 12078 12545 1
+a 12079 12544 1
+a 12080 12543 1
+a 12081 12542 1
+a 12082 12541 1
+a 12083 12540 1
+a 12084 12539 1
+a 12085 12538 1
+a 12086 12537 1
+a 12087 12536 1
+a 12088 12535 1
+a 12089 12534 1
+a 12090 12533 1
+a 12091 12532 1
+a 12092 12531 1
+a 12093 12530 1
+a 12094 12529 1
+a 12095 12528 1
+a 12096 12527 1
+a 12097 12526 1
+a 12098 12525 1
+a 12099 12524 1
+a 12100 12523 1
+a 12101 12522 1
+a 12102 12521 1
+a 12103 12520 1
+a 12104 12519 1
+a 12105 12518 1
+a 12106 12517 1
+a 12107 12516 1
+a 12108 12515 1
+a 12109 12514 1
+a 12110 12513 1
+a 12111 12512 1
+a 12112 12511 1
+a 12113 12510 1
+a 12114 12509 1
+a 12115 12508 1
+a 12116 12507 1
+a 12117 12506 1
+a 12118 12505 1
+a 12119 12504 1
+a 12120 12503 1
+a 12121 12502 1
+a 12122 12501 1
+a 12123 12500 1
+a 12124 12499 1
+a 12125 12498 1
+a 12126 12497 1
+a 12127 12496 1
+a 12128 12495 1
+a 12129 12494 1
+a 12130 12493 1
+a 12131 12492 1
+a 12132 12491 1
+a 12133 12490 1
+a 12134 12489 1
+a 12135 12488 1
+a 12136 12487 1
+a 12137 12486 1
+a 12138 12485 1
+a 12139 12484 1
+a 12140 12483 1
+a 12141 12482 1
+a 12142 12481 1
+a 12143 12480 1
+a 12144 12479 1
+a 12145 12478 1
+a 12146 12477 1
+a 12147 12476 1
+a 12148 12475 1
+a 12149 12474 1
+a 12150 12473 1
+a 12151 12472 1
+a 12152 12471 1
+a 12153 12470 1
+a 12154 12469 1
+a 12155 12468 1
+a 12156 12467 1
+a 12157 12466 1
+a 12158 12465 1
+a 12159 12464 1
+a 12160 12463 1
+a 12161 12462 1
+a 12162 12461 1
+a 12163 12460 1
+a 12164 12459 1
+a 12165 12458 1
+a 12166 12457 1
+a 12167 12456 1
+a 12168 12455 1
+a 12169 12454 1
+a 12170 12453 1
+a 12171 12452 1
+a 12172 12451 1
+a 12173 12450 1
+a 12174 12449 1
+a 12175 12448 1
+a 12176 12447 1
+a 12177 12446 1
+a 12178 12445 1
+a 12179 12444 1
+a 12180 12443 1
+a 12181 12442 1
+a 12182 12441 1
+a 12183 12440 1
+a 12184 12439 1
+a 12185 12438 1
+a 12186 12437 1
+a 12187 12436 1
+a 12188 12435 1
+a 12189 12434 1
+a 12190 12433 1
+a 12191 12432 1
+a 12192 12431 1
+a 12193 12430 1
+a 12194 12429 1
+a 12195 12428 1
+a 12196 12427 1
+a 12197 12426 1
+a 12198 12425 1
+a 12199 12424 1
+a 12200 12423 1
+a 12201 12422 1
+a 12202 12421 1
+a 12203 12420 1
+a 12204 12419 1
+a 12205 12418 1
+a 12206 12417 1
+a 12207 12416 1
+a 12208 12415 1
+a 12209 12414 1
+a 12210 12413 1
+a 12211 12412 1
+a 12212 12411 1
+a 12213 12410 1
+a 12214 12409 1
+a 12215 12408 1
+a 12216 12407 1
+a 12217 12406 1
+a 12218 12405 1
+a 12219 12404 1
+a 12220 12403 1
+a 12221 12402 1
+a 12222 12401 1
+a 12223 12400 1
+a 12224 12399 1
+a 12225 12398 1
+a 12226 12397 1
+a 12227 12396 1
+a 12228 12395 1
+a 12229 12394 1
+a 12230 12393 1
+a 12231 12392 1
+a 12232 12391 1
+a 12233 12390 1
+a 12234 12389 1
+a 12235 12388 1
+a 12236 12387 1
+a 12237 12386 1
+a 12238 12385 1
+a 12239 12384 1
+a 12240 12383 1
+a 12241 12382 1
+a 12242 12381 1
+a 12243 12380 1
+a 12244 12379 1
+a 12245 12378 1
+a 12246 12377 1
+a 12247 12376 1
+a 12248 12375 1
+a 12249 12374 1
+a 12250 12373 1
+a 12251 12372 1
+a 12252 12371 1
+a 12253 12370 1
+a 12254 12369 1
+a 12255 12368 1
+a 12256 12367 1
+a 12257 12366 1
+a 12258 12365 1
+a 12259 12364 1
+a 12260 12363 1
+a 12261 12362 1
+a 12262 12361 1
+a 12263 12360 1
+a 12264 12359 1
+a 12265 12358 1
+a 12266 12357 1
+a 12267 12356 1
+a 12268 12355 1
+a 12269 12354 1
+a 12270 12353 1
+a 12271 12352 1
+a 12272 12351 1
+a 12273 12350 1
+a 12274 12349 1
+a 12275 12348 1
+a 12276 12347 1
+a 12277 12346 1
+a 12278 12345 1
+a 12279 12344 1
+a 12280 12343 1
+a 12281 12342 1
+a 12282 12341 1
+a 12283 12340 1
+a 12284 12339 1
+a 12285 12338 1
+a 12286 12337 1
+a 12287 12336 1
+a 12288 12335 1
+a 12289 12334 1
+a 12290 12333 1
+a 12291 12332 1
+a 12292 12331 1
+a 12293 12330 1
+a 12294 12329 1
+a 12295 12328 1
+a 12296 12327 1
+a 12297 12326 1
+a 12298 12325 1
+a 12299 12324 1
+a 12300 12323 1
+a 12301 12322 1
+a 12302 12321 1
+a 12303 12320 1
+a 12304 12319 1
+a 12305 12318 1
+a 12306 12317 1
+a 12307 12316 1
+a 12308 12315 1
+a 12309 12314 1
+a 12310 12313 1
+a 1 3 1000000
+a 1 8209 1000000
+a 8208 2 1000000
+a 16414 2 1000000
diff --git a/examples/simple/assortativity.c b/examples/simple/assortativity.c
new file mode 100644
index 0000000..41403b0
--- /dev/null
+++ b/examples/simple/assortativity.c
@@ -0,0 +1,212 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+
+int main() {
+
+  igraph_t g;
+  FILE *karate, *neural;
+  igraph_real_t res;
+  igraph_vector_t types;
+  igraph_vector_t degree, outdegree, indegree;
+
+  igraph_real_t football_types[] = { 
+    7,0,2,3,7,3,2,8,8,7,3,10,6,2,6,2,7,9,6,1,9,8,8,7,10,0,6,9,
+    11,1,1,6,2,0,6,1,5,0,6,2,3,7,5,6,4,0,11,2,4,11,10,8,3,11,6,
+    1,9,4,11,10,2,6,9,10,2,9,4,11,8,10,9,6,3,11,3,4,9,8,8,1,5,3,
+    5,11,3,6,4,9,11,0,5,4,4,7,1,9,9,10,3,6,2,1,3,0,7,0,2,3,8,0,
+    4,8,4,9,11 };
+
+  karate=fopen("karate.gml", "r");
+  igraph_read_graph_gml(&g, karate);
+  fclose(karate);
+  
+  igraph_vector_init(&types, 0);
+  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
+
+  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
+  printf("%.5f\n", res);
+  
+  igraph_destroy(&g);
+
+  /*---------------------*/
+
+  neural=fopen("celegansneural.gml", "r");
+  igraph_read_graph_gml(&g, neural);
+  fclose(neural);
+  
+  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
+
+  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 1);
+  printf("%.5f\n", res);  
+  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
+  printf("%.5f\n", res);  
+
+  igraph_destroy(&g);
+  igraph_vector_destroy(&types);
+
+  /*---------------------*/
+  
+  karate=fopen("karate.gml", "r");
+  igraph_read_graph_gml(&g, karate);
+  fclose(karate);
+  
+  igraph_vector_init(&degree, 0);
+  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
+  igraph_vector_add_constant(&degree, -1);
+
+  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
+  printf("%.5f\n", res);
+  
+  igraph_destroy(&g);
+
+  /*---------------------*/
+
+  neural=fopen("celegansneural.gml", "r");
+  igraph_read_graph_gml(&g, neural);
+  fclose(neural);
+  
+  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
+  igraph_vector_add_constant(&degree, -1);
+
+  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 1);
+  printf("%.5f\n", res);  
+  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
+  printf("%.5f\n", res);  
+
+  igraph_vector_destroy(&degree);
+
+  /*---------------------*/
+  
+  igraph_vector_init(&indegree, 0);
+  igraph_vector_init(&outdegree, 0);
+  igraph_degree(&g, &indegree, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1);
+  igraph_degree(&g, &outdegree, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1);
+  igraph_vector_add_constant(&indegree, -1);
+  igraph_vector_add_constant(&outdegree, -1);
+  
+  igraph_assortativity(&g, &outdegree, &indegree, &res, /*directed=*/ 1);
+  printf("%.5f\n", res);
+
+  igraph_vector_destroy(&indegree);
+  igraph_vector_destroy(&outdegree);
+
+  /*---------------------*/
+  
+  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
+  printf("%.5f\n", res);
+
+  igraph_destroy(&g);  
+
+  /*---------------------*/
+
+  karate=fopen("karate.gml", "r");
+  igraph_read_graph_gml(&g, karate);
+  fclose(karate);
+  
+  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
+  printf("%.5f\n", res);
+  
+  igraph_destroy(&g);
+
+  /*---------------------*/
+  
+  igraph_small(&g, sizeof(football_types)/sizeof(igraph_real_t), 
+	       IGRAPH_UNDIRECTED,
+	       0,1,2,3,0,4,4,5,3,5,2,6,6,7,7,8,8,9,0,9,4,9,5,10,10,11,5,11,
+	       3,11,12,13,2,13,2,14,12,14,14,15,13,15,2,15,4,16,9,16,0,16,
+	       16,17,12,17,12,18,18,19,17,20,20,21,8,21,7,21,9,22,7,22,21,
+	       22,8,22,22,23,9,23,4,23,16,23,0,23,11,24,24,25,1,25,3,26,12,
+	       26,14,26,26,27,17,27,1,27,17,27,4,28,11,28,24,28,19,29,29,
+	       30,19,30,18,31,31,32,21,32,15,32,13,32,6,32,0,33,1,33,25,33,
+	       19,33,31,34,26,34,12,34,18,34,34,35,0,35,29,35,19,35,30,35,
+	       18,36,12,36,20,36,19,36,36,37,1,37,25,37,33,37,18,38,16,38,
+	       28,38,26,38,14,38,12,38,38,39,6,39,32,39,13,39,15,39,7,40,3,
+	       40,40,41,8,41,4,41,23,41,9,41,0,41,16,41,34,42,29,42,18,42,
+	       26,42,42,43,36,43,26,43,31,43,38,43,12,43,14,43,19,44,35,44,
+	       30,44,44,45,13,45,33,45,1,45,37,45,25,45,21,46,46,47,22,47,
+	       6,47,15,47,2,47,39,47,32,47,44,48,48,49,32,49,46,49,30,50,
+	       24,50,11,50,28,50,50,51,40,51,8,51,22,51,21,51,3,52,40,52,5,
+	       52,52,53,25,53,48,53,49,53,46,53,39,54,31,54,38,54,14,54,34,
+	       54,18,54,54,55,31,55,6,55,35,55,29,55,19,55,30,55,27,56,56,
+	       57,1,57,42,57,44,57,48,57,3,58,6,58,17,58,36,58,36,59,58,59,
+	       59,60,10,60,39,60,6,60,47,60,13,60,15,60,2,60,43,61,47,61,
+	       54,61,18,61,26,61,31,61,34,61,61,62,20,62,45,62,17,62,27,62,
+	       56,62,27,63,58,63,59,63,42,63,63,64,9,64,32,64,60,64,2,64,6,
+	       64,47,64,13,64,0,65,27,65,17,65,63,65,56,65,20,65,65,66,59,
+	       66,24,66,44,66,48,66,16,67,41,67,46,67,53,67,49,67,67,68,15,
+	       68,50,68,21,68,51,68,7,68,22,68,8,68,4,69,24,69,28,69,50,69,
+	       11,69,69,70,43,70,65,70,20,70,56,70,62,70,27,70,60,71,18,71,
+	       14,71,34,71,54,71,38,71,61,71,31,71,71,72,2,72,10,72,3,72,
+	       40,72,52,72,7,73,49,73,53,73,67,73,46,73,73,74,2,74,72,74,5,
+	       74,10,74,52,74,3,74,40,74,20,75,66,75,48,75,57,75,44,75,75,
+	       76,27,76,59,76,20,76,70,76,66,76,56,76,62,76,73,77,22,77,7,
+	       77,51,77,21,77,8,77,77,78,23,78,50,78,28,78,22,78,8,78,68,
+	       78,7,78,51,78,31,79,43,79,30,79,19,79,29,79,35,79,55,79,79,
+	       80,37,80,29,80,16,81,5,81,40,81,10,81,72,81,3,81,81,82,74,
+	       82,39,82,77,82,80,82,30,82,29,82,7,82,53,83,81,83,69,83,73,
+	       83,46,83,67,83,49,83,83,84,24,84,49,84,52,84,3,84,74,84,10,
+	       84,81,84,5,84,3,84,6,85,14,85,38,85,43,85,80,85,12,85,26,85,
+	       31,85,44,86,53,86,75,86,57,86,48,86,80,86,66,86,86,87,17,87,
+	       62,87,56,87,24,87,20,87,65,87,49,88,58,88,83,88,69,88,46,88,
+	       53,88,73,88,67,88,88,89,1,89,37,89,25,89,33,89,55,89,45,89,
+	       5,90,8,90,23,90,0,90,11,90,50,90,24,90,69,90,28,90,29,91,48,
+	       91,66,91,69,91,44,91,86,91,57,91,80,91,91,92,35,92,15,92,86,
+	       92,48,92,57,92,61,92,66,92,75,92,0,93,23,93,80,93,16,93,4,
+	       93,82,93,91,93,41,93,9,93,34,94,19,94,55,94,79,94,80,94,29,
+	       94,30,94,82,94,35,94,70,95,69,95,76,95,62,95,56,95,27,95,17,
+	       95,87,95,37,95,48,96,17,96,76,96,27,96,56,96,65,96,20,96,87,
+	       96,5,97,86,97,58,97,11,97,59,97,63,97,97,98,77,98,48,98,84,
+	       98,40,98,10,98,5,98,52,98,81,98,89,99,34,99,14,99,85,99,54,
+	       99,18,99,31,99,61,99,71,99,14,99,99,100,82,100,13,100,2,100,
+	       15,100,32,100,64,100,47,100,39,100,6,100,51,101,30,101,94,
+	       101,1,101,79,101,58,101,19,101,55,101,35,101,29,101,100,102,
+	       74,102,52,102,98,102,72,102,40,102,10,102,3,102,102,103,33,
+	       103,45,103,25,103,89,103,37,103,1,103,70,103,72,104,11,104,
+	       0,104,93,104,67,104,41,104,16,104,87,104,23,104,4,104,9,104,
+	       89,105,103,105,33,105,62,105,37,105,45,105,1,105,80,105,25,
+	       105,25,106,56,106,92,106,2,106,13,106,32,106,60,106,6,106,
+	       64,106,15,106,39,106,88,107,75,107,98,107,102,107,72,107,40,
+	       107,81,107,5,107,10,107,84,107,4,108,9,108,7,108,51,108,77,
+	       108,21,108,78,108,22,108,68,108,79,109,30,109,63,109,1,109,
+	       33,109,103,109,105,109,45,109,25,109,89,109,37,109,67,110,
+	       13,110,24,110,80,110,88,110,49,110,73,110,46,110,83,110,53,
+	       110,23,111,64,111,46,111,78,111,8,111,21,111,51,111,7,111,
+	       108,111,68,111,77,111,52,112,96,112,97,112,57,112,66,112,63,
+	       112,44,112,92,112,75,112,91,112,28,113,20,113,95,113,59,113,
+	       70,113,17,113,87,113,76,113,65,113,96,113,83,114,88,114,110,
+	       114,53,114,49,114,73,114,46,114,67,114,58,114,15,114,104,114,
+	       -1);
+  igraph_simplify(&g, /*multiple=*/ 1, /*loops=*/ 1, /*edge_comb=*/ 0);
+  igraph_vector_view(&types, football_types, 
+		     sizeof(football_types) / sizeof(igraph_real_t));
+  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
+  printf("%.5f\n", res);
+  
+  igraph_destroy(&g);
+  
+  return 0;
+}
+
diff --git a/examples/simple/assortativity.out b/examples/simple/assortativity.out
new file mode 100644
index 0000000..aa71d28
--- /dev/null
+++ b/examples/simple/assortativity.out
@@ -0,0 +1,10 @@
+-0.07775
+0.00303
+0.00147
+-0.47561
+-0.15328
+-0.14996
+-0.22580
+-0.22580
+-0.47561
+0.60794
diff --git a/examples/simple/bellman_ford.c b/examples/simple/bellman_ford.c
new file mode 100644
index 0000000..5063a15
--- /dev/null
+++ b/examples/simple/bellman_ford.c
@@ -0,0 +1,103 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+
+int print_matrix(const igraph_matrix_t *m) {
+  long int nrow=igraph_matrix_nrow(m);
+  long int ncol=igraph_matrix_ncol(m);
+  long int i, j;
+  for (i=0; i<nrow; i++) {
+    printf("%li:", i);
+    for (j=0; j<ncol; j++) {
+      printf(" %3.0F", MATRIX(*m, i, j));
+    }
+    printf("\n");
+  }
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t weights;
+  igraph_real_t weights_data_0[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
+  igraph_real_t weights_data_1[] = { 6,7,8,-4,-2,-3,9,2,7 };
+  igraph_real_t weights_data_2[] = { 6,7,2,-4,-2,-3,9,2,7 };
+  igraph_matrix_t res;
+  
+  /* Graph with only positive weights */
+  igraph_small(&g, 10, IGRAPH_DIRECTED, 
+	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
+	       2,3, 2,6,         3,2, 3,6,
+	       4,5, 4,7,         5,6, 5,8, 5,9,
+	       7,5, 7,8,         8,9,
+	       5,2,
+	       2,1,
+	       -1);
+  
+  igraph_vector_view(&weights, weights_data_0, 
+		     sizeof(weights_data_0)/sizeof(igraph_real_t));
+  
+  igraph_matrix_init(&res, 0, 0);
+  igraph_shortest_paths_bellman_ford(&g, &res, igraph_vss_all(), igraph_vss_all(),
+				     &weights, IGRAPH_OUT);
+  print_matrix(&res);
+  
+  igraph_matrix_destroy(&res);
+  igraph_destroy(&g);
+
+  printf("\n");
+
+  /***************************************/
+
+  /* Graph with negative weights */
+  igraph_small(&g, 5, IGRAPH_DIRECTED, 
+	       0,1, 0,3, 1,3, 1,4, 2,1, 3,2, 3,4, 4,0, 4,2, -1);
+  
+  igraph_vector_view(&weights, weights_data_1, 
+		     sizeof(weights_data_1)/sizeof(igraph_real_t));
+  
+  igraph_matrix_init(&res, 0, 0);
+  igraph_shortest_paths_bellman_ford(&g, &res, igraph_vss_all(), 
+				     igraph_vss_all(), &weights, IGRAPH_OUT);
+  print_matrix(&res);
+  
+  /***************************************/
+
+  /* Same graph with negative loop */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  igraph_vector_view(&weights, weights_data_2, 
+		     sizeof(weights_data_2)/sizeof(igraph_real_t));
+  if (igraph_shortest_paths_bellman_ford(&g, &res, igraph_vss_all(),
+					 igraph_vss_all(),
+                                         &weights, IGRAPH_OUT) != IGRAPH_ENEGLOOP)
+    return 1;
+  
+  igraph_matrix_destroy(&res);
+  igraph_destroy(&g);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+
+  return 0;
+}
diff --git a/examples/simple/bellman_ford.out b/examples/simple/bellman_ford.out
new file mode 100644
index 0000000..ed392f6
--- /dev/null
+++ b/examples/simple/bellman_ford.out
@@ -0,0 +1,16 @@
+0:   0   0   0   1   5   2   1  13   3   5
+1: INF   0   0   1   5   2   1  13   3   5
+2: INF   1   0   1   6   3   1  14   4   6
+3: INF   1   0   0   6   3   1  14   4   6
+4: INF   5   4   5   0   2   3   8   3   5
+5: INF   3   2   3   8   0   1  16   1   3
+6: INF INF INF INF INF INF   0 INF INF INF
+7: INF   4   3   4   9   1   2   0   1   4
+8: INF INF INF INF INF INF INF INF   0   4
+9: INF INF INF INF INF INF INF INF INF   0
+
+0:   0   2   4   7  -2
+1:  -2   0   2   5  -4
+2:  -4  -2   0   3  -6
+3:  -7  -5  -3   0  -9
+4:   2   4   6   9   0
diff --git a/examples/simple/biguint.c b/examples/simple/biguint.c
new file mode 100644
index 0000000..4c4703f
--- /dev/null
+++ b/examples/simple/biguint.c
@@ -0,0 +1,87 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <igraph_types_internal.h>
+#include <bigint.h>
+
+#include <limits.h>
+
+int main() {
+  
+  igraph_biguint_t A, B, C, D, E, zero, one;
+  
+  igraph_biguint_init(&A);
+  igraph_biguint_init(&B);
+  igraph_biguint_init(&C);
+  igraph_biguint_init(&D);
+  igraph_biguint_init(&E);
+  igraph_biguint_init(&zero);
+  igraph_biguint_init(&one);
+
+  /* set & add & sub */
+  igraph_biguint_set_limb(&one, 1);
+  igraph_biguint_set_limb(&A, UINT_MAX);
+  igraph_biguint_set_limb(&B, UINT_MAX);
+  igraph_biguint_add(&A, &A, &B);                      /* A <- A + B */
+
+  igraph_biguint_print(&B);
+  putchar('\n');
+  igraph_biguint_print(&A);
+  putchar('\n');
+  
+  igraph_biguint_sub(&A, &A, &B);                      /* A <- A - B */
+  if (!igraph_biguint_equal(&A, &B)) { return 1; }
+
+  /* inc & dec */
+  igraph_biguint_inc(&A, &A);	                       /* A <- A + 1 */
+  igraph_biguint_dec(&A, &A);	                       /* A <- A - 1 */
+  if (!igraph_biguint_equal(&A, &B)) { return 2; }
+  
+  /* mul & div */
+  igraph_biguint_mul(&C, &A, &B);                      /* C <- A * B */
+  igraph_biguint_div(&E, &D, &C, &B);                  /* E <- C / B */
+				                       /* D <- C % B */
+  if (!igraph_biguint_equal(&E, &A)) { return 3; }
+  if (!igraph_biguint_equal(&D, &zero)) { return 4; }
+
+  igraph_biguint_mul(&C, &A, &A);                      /* C <- A * A */
+  igraph_biguint_mul(&D, &C, &A);		       /* C <- C * A */
+  igraph_biguint_mul(&C, &D, &A);		       /* C <- C * A */
+
+  igraph_biguint_div(&C, &D, &C, &A);                  /* C <- C / A */
+  igraph_biguint_div(&C, &D, &C, &A);		       /* C <- C / A */
+  igraph_biguint_div(&C, &D, &C, &A);		       /* C <- C / A */
+  igraph_biguint_div(&C, &D, &C, &A);		       /* C <- C / A */
+  if (!igraph_biguint_equal(&C, &one)) { return 5; }
+
+  igraph_biguint_destroy(&A);
+  igraph_biguint_destroy(&B);
+  igraph_biguint_destroy(&C);
+  igraph_biguint_destroy(&D);
+  igraph_biguint_destroy(&E);
+  igraph_biguint_destroy(&zero);
+  igraph_biguint_destroy(&one);
+  
+  return 0;
+}
diff --git a/examples/simple/biguint.out b/examples/simple/biguint.out
new file mode 100644
index 0000000..4e850b7
--- /dev/null
+++ b/examples/simple/biguint.out
@@ -0,0 +1,2 @@
+4294967295
+8589934590
diff --git a/examples/simple/biguint_betweenness.c b/examples/simple/biguint_betweenness.c
new file mode 100644
index 0000000..fdf532d
--- /dev/null
+++ b/examples/simple/biguint_betweenness.c
@@ -0,0 +1,205 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+#include <stdlib.h>
+
+int check(const igraph_vector_t *v1, const igraph_vector_t *v2, int code) {
+  igraph_vector_t v;
+  long int i, n=igraph_vector_size(v1);
+  igraph_real_t m;
+
+  igraph_vector_copy(&v, v1);
+  igraph_vector_sub(&v, v2);
+  
+  for (i=0; i<n; i++) {
+    VECTOR(v)[i] = fabs(VECTOR(v)[i]);
+  }
+  
+  if ( (m=igraph_vector_max(&v)) > 0.01) { 
+    printf("Difference: %g\n", m);
+    exit(code); 
+  }
+
+  igraph_vector_destroy(&v);
+
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t bet, bet2, weights, edges;
+  igraph_vector_t bbet, bbet2;
+  
+  igraph_real_t nontriv[] = { 0, 19, 0, 16, 0, 20, 1, 19, 2, 5, 3, 7, 3, 8, 
+			      4, 15, 4, 11, 5, 8, 5, 19, 6, 7, 6, 10, 6, 8, 
+			      6, 9, 7, 20, 9, 10, 9, 20, 10, 19, 
+			      11, 12, 11, 20, 12, 15, 13, 15, 
+			      14, 18, 14, 16, 14, 17, 15, 16, 17, 18 };
+  
+  igraph_real_t nontriv_weights[] = { 0.5249, 1, 0.1934, 0.6274, 0.5249, 
+				      0.0029, 0.3831, 0.05, 0.6274, 0.3831, 
+				      0.5249, 0.0587, 0.0579, 0.0562, 0.0562, 
+				      0.1934, 0.6274, 0.6274, 0.6274, 0.0418, 
+				      0.6274, 0.3511, 0.3511, 0.1486, 1, 1, 
+				      0.0711, 0.2409 };
+
+  igraph_real_t nontriv_res[] = { 20, 0, 0, 0, 0, 19, 80, 85, 32, 0, 10, 
+				  75, 70, 0, 36, 81, 60, 0, 19, 19, 86 };
+
+  /*******************************************************/
+
+  igraph_barabasi_game(/* graph= */    &g,
+		       /* n= */        1000,
+		       /* power= */    1,
+		       /* m= */        3,
+		       /* outseq= */   0,
+		       /* outpref= */  0,
+		       /* A= */        1,
+		       /* directed= */ 0, 
+		       /* algo= */     IGRAPH_BARABASI_BAG,
+		       /* start_from= */ 0);
+  
+  igraph_simplify(&g, /* multiple= */ 1, /* loops= */ 1, /*edge_comb=*/ 0);
+  
+  igraph_vector_init(&bet, 0);
+  igraph_vector_init(&bbet, 0);
+  
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bet,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 2,
+			      /* weights=   */ 0, 
+			      /* nobigint=  */ 1);
+
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bbet,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 2,
+			      /* weights=   */ 0, 
+			      /* nobigint=  */ 0);  
+
+  check(&bet, &bbet, 10);
+
+  igraph_vector_destroy(&bet);
+  igraph_vector_destroy(&bbet);
+  igraph_destroy(&g);
+
+  /*******************************************************/
+
+  igraph_tree(&g, 20000, 10, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_vector_init(&bet, 0);
+  igraph_vector_init(&bbet, 0);
+  
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bet,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 3,
+			      /* weights=   */ 0, 
+			      /* nobigint=  */ 1);
+
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bbet,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 3,
+			      /* weights=   */ 0, 
+			      /* nobigint=  */ 0);
+
+  check(&bet, &bbet, 20);
+
+  igraph_vector_init(&bet2, 0);
+  igraph_vector_init(&bbet2, 0);
+  igraph_vector_init(&weights, igraph_ecount(&g));
+  igraph_vector_fill(&weights, 1.0);
+  
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bet2,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 3,
+			      /* weights=   */ &weights, 
+			      /* nobigint=  */ 1);
+
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bbet2,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 3,
+			      /* weights=   */ &weights, 
+			      /* nobigint=  */ 0);
+
+  if (!igraph_vector_all_e(&bet, &bet2)) {
+    return 1;
+  }
+
+/*   if (!igraph_vector_all_e(&bbet, &bbet2)) { */
+/*     return 2; */
+/*   } */
+
+  check(&bet, &bbet, 30);
+  check(&bet2, &bbet2, 40);
+
+  igraph_vector_destroy(&bet);
+  igraph_vector_destroy(&bet2);
+  igraph_vector_destroy(&bbet);
+  igraph_vector_destroy(&bbet2);
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* Non-trivial weighted graph */
+  igraph_vector_view(&edges, nontriv, sizeof(nontriv)/sizeof(igraph_real_t));
+  igraph_create(&g, &edges, 0, /* directed= */ 0);
+  igraph_vector_view(&weights, nontriv_weights, 
+		     sizeof(nontriv_weights)/sizeof(igraph_real_t));
+  igraph_vector_init(&bet, 0);
+  igraph_vector_init(&bbet, 0);
+
+  igraph_betweenness(/*graph=*/ &g, /*res=*/ &bet, /*vids=*/ igraph_vss_all(), 
+		     /*directed=*/0, /*weights=*/ &weights, /*nobigint=*/ 1);
+
+  igraph_betweenness(/*graph=*/ &g, /*res=*/ &bbet, /*vids=*/ igraph_vss_all(), 
+		     /*directed=*/0, /*weights=*/ &weights, /*nobigint=*/ 0);
+
+  igraph_vector_view(&bet2, nontriv_res, 
+		     sizeof(nontriv_res)/sizeof(igraph_real_t));
+
+  if (!igraph_vector_all_e(&bet, &bet2)) {
+    return 2;
+  }
+
+  check(&bet, &bbet, 50);
+  
+  igraph_vector_destroy(&bet);
+  igraph_vector_destroy(&bbet);
+  igraph_destroy(&g);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 3;
+
+  return 0;
+}
diff --git a/examples/simple/bipartite.net b/examples/simple/bipartite.net
new file mode 100644
index 0000000..2d4f2c9
--- /dev/null
+++ b/examples/simple/bipartite.net
@@ -0,0 +1,26 @@
+*Vertices 13 8
+1 "A"
+2 "B"
+3 "C"
+4 "D"
+5 "E"
+6 "F"
+7 "G"
+8 "H"
+9 "x-1"
+10 "x-2"
+11 "x-3"
+12 "x-4"
+13 "x-5"
+*Edges
+1 10
+1 13
+2 12
+3 10
+3 11
+4 11
+5 12
+5 13
+6 12
+8 11
+8 13
diff --git a/examples/simple/blas.c b/examples/simple/blas.c
new file mode 100644
index 0000000..67ffdaa
--- /dev/null
+++ b/examples/simple/blas.c
@@ -0,0 +1,49 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+
+int main() {
+  igraph_matrix_t m;
+  igraph_vector_t x, y;
+
+  igraph_vector_init_real(&x, 3, 1.0, 2.0, 3.0);
+  igraph_vector_init_real(&y, 4, 4.0, 5.0, 6.0, 7.0);
+
+  igraph_matrix_init(&m, 4, 3);
+  MATRIX(m, 0, 0) = 1; MATRIX(m, 0, 1) = 2; MATRIX(m, 0, 2) = 3;
+  MATRIX(m, 1, 0) = 2; MATRIX(m, 1, 1) = 3; MATRIX(m, 1, 2) = 4;
+  MATRIX(m, 2, 0) = 3; MATRIX(m, 2, 1) = 4; MATRIX(m, 2, 2) = 5;
+  MATRIX(m, 3, 0) = 4; MATRIX(m, 3, 1) = 5; MATRIX(m, 3, 2) = 6;
+
+  igraph_blas_dgemv(0, 2, &m, &x, 3, &y);
+  igraph_vector_print(&y);
+
+  igraph_vector_destroy(&x);
+  igraph_vector_destroy(&y);
+  igraph_matrix_destroy(&m);
+
+  return 0;
+}
+
diff --git a/examples/simple/blas.out b/examples/simple/blas.out
new file mode 100644
index 0000000..ee2112b
--- /dev/null
+++ b/examples/simple/blas.out
@@ -0,0 +1 @@
+40 55 70 85
diff --git a/examples/simple/bug-1033045.c b/examples/simple/bug-1033045.c
new file mode 100644
index 0000000..739f84f
--- /dev/null
+++ b/examples/simple/bug-1033045.c
@@ -0,0 +1,50 @@
+/* -*- 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.h>
+
+int main() {
+
+  igraph_t graph;  
+  igraph_vector_ptr_t separators;
+  int i, n;  
+
+  igraph_small(&graph, 0, /*directed=*/ 0, 
+	       0,1,0,2, 1,3,1,4, 2,3,2,5, 3,4,3,5, 4,6, 5,6, -1);
+  igraph_vector_ptr_init(&separators, 0);
+  
+  igraph_all_minimal_st_separators(&graph, &separators);
+  
+  n=igraph_vector_ptr_size(&separators);  
+  for (i=0; i<n; i++) {
+    igraph_vector_t *sep=VECTOR(separators)[i];
+    igraph_vector_print(sep);
+    igraph_vector_destroy(sep);
+    igraph_free(sep);
+  }
+  
+  igraph_vector_ptr_destroy(&separators);
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/bug-1033045.out b/examples/simple/bug-1033045.out
new file mode 100644
index 0000000..29110ce
--- /dev/null
+++ b/examples/simple/bug-1033045.out
@@ -0,0 +1,9 @@
+1 2
+0 3 4
+0 3 5
+4 5
+1 3 6
+2 3 6
+2 3 4
+1 3 5
+0 3 6
diff --git a/examples/simple/bug-1149658.c b/examples/simple/bug-1149658.c
new file mode 100644
index 0000000..f37e93a
--- /dev/null
+++ b/examples/simple/bug-1149658.c
@@ -0,0 +1,45 @@
+/* -*- 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.h>
+
+int main() {
+
+  igraph_t graph;  
+  igraph_vector_t mod;
+  
+  igraph_empty(&graph, 25, IGRAPH_UNDIRECTED);
+  igraph_vector_init(&mod, 0);
+  igraph_community_multilevel(&graph, /*weights=*/ 0, /*membership=*/ 0,
+			      /*memberships=*/ 0, &mod);
+  
+  if (igraph_vector_size(&mod) != 1 ||
+      VECTOR(mod)[0] != 0) { 
+    return 1;
+  }
+
+  igraph_vector_destroy(&mod);
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/cattributes.c b/examples/simple/cattributes.c
new file mode 100644
index 0000000..eaa3d83
--- /dev/null
+++ b/examples/simple/cattributes.c
@@ -0,0 +1,397 @@
+/* -*- 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.h>
+#include <string.h>
+#include <stdlib.h>
+
+int print_attributes(const igraph_t *g) {
+
+  igraph_vector_t gtypes, vtypes, etypes;
+  igraph_strvector_t gnames, vnames, enames;
+  long int i;
+
+  igraph_vector_t vec;
+  igraph_strvector_t svec;
+  long int j;
+
+  igraph_vector_init(&gtypes, 0);
+  igraph_vector_init(&vtypes, 0);
+  igraph_vector_init(&etypes, 0);
+  igraph_strvector_init(&gnames, 0);
+  igraph_strvector_init(&vnames, 0);
+  igraph_strvector_init(&enames, 0);
+
+  igraph_cattribute_list(g, &gnames, &gtypes, &vnames, &vtypes, 
+			 &enames, &etypes);
+
+  /* Graph attributes */
+  for (i=0; i<igraph_strvector_size(&gnames); i++) {
+    printf("%s=", STR(gnames, i));
+    if (VECTOR(gtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_real_printf(GAN(g, STR(gnames,i)));
+      putchar(' ');
+    } else {
+      printf("\"%s\" ", GAS(g, STR(gnames,i)));
+    }
+  }
+  printf("\n");
+
+  for (i=0; i<igraph_vcount(g); i++) {
+    long int j;
+    printf("Vertex %li: ", i);
+    for (j=0; j<igraph_strvector_size(&vnames); j++) {
+      printf("%s=", STR(vnames, j));
+      if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_real_printf(VAN(g, STR(vnames,j), i));
+	putchar(' ');
+      } else {
+	printf("\"%s\" ", VAS(g, STR(vnames,j), i));
+      }
+    }
+    printf("\n");
+  }
+
+  for (i=0; i<igraph_ecount(g); i++) {
+    long int j;
+    printf("Edge %li (%i-%i): ", i, (int)IGRAPH_FROM(g,i), (int)IGRAPH_TO(g,i));
+    for (j=0; j<igraph_strvector_size(&enames); j++) {
+      printf("%s=", STR(enames, j));
+      if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_real_printf(EAN(g, STR(enames, j), i));
+	putchar(' ');
+      } else {
+	printf("\"%s\" ", EAS(g, STR(enames, j), i));
+      }
+    }
+    printf("\n");
+  }
+
+  /* Check vector-based query functions */
+  igraph_vector_init(&vec, 0);
+  igraph_strvector_init(&svec, 0);
+  
+  for (j=0; j<igraph_strvector_size(&vnames); j++) {
+    if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_cattribute_VANV(g, STR(vnames, j), igraph_vss_all(), &vec);
+      for (i=0; i<igraph_vcount(g); i++) {
+	igraph_real_t num=VAN(g, STR(vnames, j), i);
+	if (num != VECTOR(vec)[i] &&
+	    (!isnan(num) || !isnan(VECTOR(vec)[i]))) {
+	  exit(51);
+	}
+      }
+    } else {
+      igraph_cattribute_VASV(g, STR(vnames, j), igraph_vss_all(), &svec);
+      for (i=0; i<igraph_vcount(g); i++) {
+	const char *str=VAS(g, STR(vnames, j), i);
+	if (strcmp(str,STR(svec, i))) {
+	  exit(52);
+	}
+      }
+    }
+  }
+
+  for (j=0; j<igraph_strvector_size(&enames); j++) {
+    if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_cattribute_EANV(g, STR(enames, j), 
+			     igraph_ess_all(IGRAPH_EDGEORDER_ID), &vec);
+      for (i=0; i<igraph_ecount(g); i++) {
+	igraph_real_t num=EAN(g, STR(enames, j), i);
+	if (num != VECTOR(vec)[i] && 
+	    (!isnan(num) || !isnan(VECTOR(vec)[i]))) {
+	  exit(53);
+	}
+      }
+    } else {
+      igraph_cattribute_EASV(g, STR(enames, j), 
+			     igraph_ess_all(IGRAPH_EDGEORDER_ID), &svec);
+      for (i=0; i<igraph_ecount(g); i++) {
+	const char *str=EAS(g, STR(enames, j), i);
+	if (strcmp(str,STR(svec, i))) {
+	  exit(54);
+	}
+      }
+    }
+  }
+
+  igraph_strvector_destroy(&svec);
+  igraph_vector_destroy(&vec);
+
+  igraph_strvector_destroy(&enames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&gnames);
+  igraph_vector_destroy(&etypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&gtypes);
+
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g, g2;
+  FILE *ifile;
+  igraph_vector_t gtypes, vtypes, etypes;
+  igraph_strvector_t gnames, vnames, enames;
+  long int i;
+  igraph_vector_t y;
+  igraph_strvector_t id;
+  char str[20];
+
+  /* turn on attribute handling */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+  
+  ifile=fopen("LINKS.NET", "r");
+  if (ifile==0) {
+    return 10;
+  }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+
+  igraph_vector_init(&gtypes, 0);
+  igraph_vector_init(&vtypes, 0);
+  igraph_vector_init(&etypes, 0);
+  igraph_strvector_init(&gnames, 0);
+  igraph_strvector_init(&vnames, 0);
+  igraph_strvector_init(&enames, 0);
+  
+  igraph_cattribute_list(&g, &gnames, &gtypes, &vnames, &vtypes, 
+			 &enames, &etypes);
+  
+  /* List attribute names and types */
+  printf("Graph attributes: ");
+  for (i=0; i<igraph_strvector_size(&gnames); i++) {
+    printf("%s (%i) ", STR(gnames, i), (int)VECTOR(gtypes)[i]);
+  }
+  printf("\n");
+  printf("Vertex attributes: ");
+  for (i=0; i<igraph_strvector_size(&vnames); i++) {
+    printf("%s (%i) ", STR(vnames, i), (int)VECTOR(vtypes)[i]);
+  }
+  printf("\n");
+  printf("Edge attributes: ");
+  for (i=0; i<igraph_strvector_size(&enames); i++) {
+    printf("%s (%i) ", STR(enames, i), (int)VECTOR(etypes)[i]);
+  }
+  printf("\n");
+
+  print_attributes(&g);
+
+  /* Copying a graph */
+  igraph_copy(&g2, &g);
+  print_attributes(&g2);
+  igraph_destroy(&g2);
+  
+  /* Adding vertices */
+  igraph_add_vertices(&g, 3, 0);
+  print_attributes(&g);
+
+  /* Adding edges */
+  igraph_add_edge(&g, 1, 1);
+  igraph_add_edge(&g, 2, 5);
+  igraph_add_edge(&g, 3, 6);
+  print_attributes(&g);
+
+  /* Deleting vertices */
+  igraph_delete_vertices(&g, igraph_vss_1(1));
+  igraph_delete_vertices(&g, igraph_vss_1(4));
+  print_attributes(&g);
+
+  /* Deleting edges */
+  igraph_delete_edges(&g, igraph_ess_1(igraph_ecount(&g)-1));
+  igraph_delete_edges(&g, igraph_ess_1(0));
+  print_attributes(&g);
+
+  /* Set graph attributes */
+  SETGAN(&g, "id", 10);
+  if (GAN(&g, "id") != 10) {
+    return 11;
+  }
+  SETGAS(&g, "name", "toy");
+  if (strcmp(GAS(&g, "name"), "toy")) {
+    return 12;
+  }
+  
+  /* Delete graph attributes */
+  DELGA(&g, "id");
+  DELGA(&g, "name");
+  igraph_cattribute_list(&g, &gnames, 0,0,0,0,0);
+  if (igraph_strvector_size(&gnames) != 0) {
+    return 14;
+  }  
+
+  /* Delete vertex attributes */
+  DELVA(&g, "x");
+  DELVA(&g, "shape");
+  DELVA(&g, "xfact");
+  DELVA(&g, "yfact");
+  igraph_cattribute_list(&g, 0,0, &vnames, 0,0,0);  
+  if (igraph_strvector_size(&vnames) != 2) {
+    return 15;
+  }
+  
+  /* Delete edge attributes */
+  igraph_cattribute_list(&g, 0,0,0,0,&enames,0);
+  i=igraph_strvector_size(&enames);
+  DELEA(&g, "hook1");
+  DELEA(&g, "hook2"); 
+  DELEA(&g, "label");
+  igraph_cattribute_list(&g, 0,0,0,0,&enames,0);
+  if (igraph_strvector_size(&enames) != i-3) {
+    return 16;
+  }
+  
+  /* Set vertex attributes */
+  SETVAN(&g, "y", 0, -1);
+  SETVAN(&g, "y", 1, 2.1);
+  if (VAN(&g, "y", 0) != -1 || 
+      VAN(&g, "y", 1) != 2.1) {
+    return 17;
+  }
+  SETVAS(&g, "id", 0, "foo");
+  SETVAS(&g, "id", 1, "bar");
+  if (strcmp(VAS(&g, "id", 0), "foo") ||
+      strcmp(VAS(&g, "id", 1), "bar")) {
+    return 18;
+  }
+
+  /* Set edge attributes */
+  SETEAN(&g, "weight", 2, 100.0);
+  SETEAN(&g, "weight", 0, -100.1);
+  if (EAN(&g, "weight", 2) != 100.0 ||
+      EAN(&g, "weight", 0) != -100.1) {
+    return 19;
+  }
+  SETEAS(&g, "color", 2, "RED");
+  SETEAS(&g, "color", 0, "Blue");
+  if (strcmp(EAS(&g, "color", 2), "RED") ||
+      strcmp(EAS(&g, "color", 0), "Blue")) {
+    return 20;
+  }      
+
+  /* Set vector attributes as vector */
+  igraph_vector_init(&y, igraph_vcount(&g));
+  igraph_vector_fill(&y, 1.23);
+  SETVANV(&g, "y", &y);
+  igraph_vector_destroy(&y);
+  for (i=0; i<igraph_vcount(&g); i++) {    
+    if (VAN(&g, "y", i) != 1.23) {
+      return 21;
+    }
+  }
+  igraph_vector_init_seq(&y, 0, igraph_vcount(&g)-1);
+  SETVANV(&g, "foobar", &y);
+  igraph_vector_destroy(&y);
+  for (i=0; i<igraph_vcount(&g); i++) {
+    if (VAN(&g, "foobar", i) != i) {
+      return 22;
+    }
+  }  
+  
+  igraph_strvector_init(&id, igraph_vcount(&g));
+  for (i=0; i<igraph_vcount(&g); i++) {
+    snprintf(str, sizeof(str)-1, "%li", i);
+    igraph_strvector_set(&id, i, str);
+  }
+  SETVASV(&g, "foo", &id);
+  igraph_strvector_destroy(&id);
+  for (i=0; i<igraph_vcount(&g); i++) {
+    printf("%s ", VAS(&g, "foo", i));
+  }
+  printf("\n");
+  igraph_strvector_init(&id, igraph_vcount(&g));
+  for (i=0; i<igraph_vcount(&g); i++) {
+    snprintf(str, sizeof(str)-1, "%li", i);
+    igraph_strvector_set(&id, i, str);
+  }
+  SETVASV(&g, "id", &id);
+  igraph_strvector_destroy(&id);
+  for (i=0; i<igraph_vcount(&g); i++) {
+    printf("%s ", VAS(&g, "id", i));
+  }
+  printf("\n");  
+  
+  /* Set edge attributes as vector */
+  igraph_vector_init(&y, igraph_ecount(&g));
+  igraph_vector_fill(&y, 12.3);
+  SETEANV(&g, "weight", &y);
+  igraph_vector_destroy(&y);
+  for (i=0; i<igraph_ecount(&g); i++) {    
+    if (EAN(&g, "weight", i) != 12.3) {
+      return 23;
+    }
+  }
+  igraph_vector_init_seq(&y, 0, igraph_ecount(&g)-1);
+  SETEANV(&g, "foobar", &y);
+  igraph_vector_destroy(&y);
+  for (i=0; i<igraph_ecount(&g); i++) {
+    if (VAN(&g, "foobar", i) != i) {
+      return 24;
+    }
+  }  
+  
+  igraph_strvector_init(&id, igraph_ecount(&g));
+  for (i=0; i<igraph_ecount(&g); i++) {
+    snprintf(str, sizeof(str)-1, "%li", i);
+    igraph_strvector_set(&id, i, str);
+  }
+  SETEASV(&g, "foo", &id);
+  igraph_strvector_destroy(&id);
+  for (i=0; i<igraph_ecount(&g); i++) {
+    printf("%s ", EAS(&g, "foo", i));
+  }
+  printf("\n");
+  igraph_strvector_init(&id, igraph_ecount(&g));
+  for (i=0; i<igraph_ecount(&g); i++) {
+    snprintf(str, sizeof(str)-1, "%li", i);
+    igraph_strvector_set(&id, i, str);
+  }
+  SETEASV(&g, "color", &id);
+  igraph_strvector_destroy(&id);
+  for (i=0; i<igraph_ecount(&g); i++) {
+    printf("%s ", EAS(&g, "color", i));
+  }
+  printf("\n");    
+
+  /* Delete all remaining attributes */
+  DELALL(&g);
+  igraph_cattribute_list(&g, &gnames, &gtypes, &vnames, &vtypes, &enames, &etypes);
+  if (igraph_strvector_size(&gnames) != 0 ||
+      igraph_strvector_size(&vnames) != 0 ||
+      igraph_strvector_size(&enames) != 0) {
+    return 25;
+  }
+
+  /* Destroy */
+  igraph_vector_destroy(&gtypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&etypes);  
+  igraph_strvector_destroy(&gnames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&enames);
+
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/cattributes.out b/examples/simple/cattributes.out
new file mode 100644
index 0000000..3bb1d9c
--- /dev/null
+++ b/examples/simple/cattributes.out
@@ -0,0 +1,84 @@
+Graph attributes: 
+Vertex attributes: id (2) x (1) y (1) shape (2) xfact (1) yfact (1) 
+Edge attributes: weight (1) hook2 (1) edgewidth (1) color (2) arrowsize (1) angle1 (1) velocity1 (1) angle2 (1) velocity2 (1) arrowpos (1) label (2) labelcolor (2) fontsize (1) labelangle (1) labelpos (1) labeldegree (1) labelangle2 (1) linepattern (2) hook1 (1) 
+
+Vertex 0: id="1" x=0.0938 y=0.0896 shape="ellipse" xfact=1 yfact=1 
+Vertex 1: id="2" x=0.8188 y=0.2458 shape="ellipse" xfact=1 yfact=1 
+Vertex 2: id="3" x=0.3688 y=0.7792 shape="ellipse" xfact=1 yfact=0 
+Vertex 3: id="4" x=0.9583 y=0.8563 shape="ellipse" xfact=1 yfact=0 
+Edge 0 (0-0): weight=1 hook2=0 edgewidth=3 color="Blue" arrowsize=3 angle1=-130 velocity1=0.6 angle2=-130 velocity2=0.6 arrowpos=0.5 label="Bezier loop" labelcolor="BlueViolet" fontsize=20 labelangle=58 labelpos=0.3 labeldegree=360 labelangle2=0 linepattern="" hook1=0 
+Edge 1 (1-0): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=120 velocity1=1.3 angle2=-120 velocity2=0.3 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=19 labelpos=0.5 labeldegree=180 labelangle2=270 linepattern="" hook1=0 
+Edge 2 (0-1): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=40 velocity1=2.8 angle2=30 velocity2=0.8 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=NaN labelpos=0.65 labeldegree=0 labelangle2=90 linepattern="" hook1=0 
+Edge 3 (3-1): weight=-1 hook2=0 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=250 arrowpos=25 label="Circular arc" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=0 
+Edge 4 (2-3): weight=1 hook2=0 edgewidth=2 color="OliveGreen" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=25 label="Straight arc" labelcolor="PineGreen" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 5 (0-2): weight=1 hook2=0 edgewidth=5 color="Brown" arrowsize=NaN angle1=NaN velocity1=-1 angle2=NaN velocity2=-20 arrowpos=25 label="Oval arc" labelcolor="Black" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 6 (2-2): weight=-1 hook2=12 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=-15 arrowpos=0.5 label="Circular loop" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=180 labelangle2=270 linepattern="" hook1=6 
+
+Vertex 0: id="1" x=0.0938 y=0.0896 shape="ellipse" xfact=1 yfact=1 
+Vertex 1: id="2" x=0.8188 y=0.2458 shape="ellipse" xfact=1 yfact=1 
+Vertex 2: id="3" x=0.3688 y=0.7792 shape="ellipse" xfact=1 yfact=0 
+Vertex 3: id="4" x=0.9583 y=0.8563 shape="ellipse" xfact=1 yfact=0 
+Edge 0 (0-0): weight=1 hook2=0 edgewidth=3 color="Blue" arrowsize=3 angle1=-130 velocity1=0.6 angle2=-130 velocity2=0.6 arrowpos=0.5 label="Bezier loop" labelcolor="BlueViolet" fontsize=20 labelangle=58 labelpos=0.3 labeldegree=360 labelangle2=0 linepattern="" hook1=0 
+Edge 1 (1-0): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=120 velocity1=1.3 angle2=-120 velocity2=0.3 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=19 labelpos=0.5 labeldegree=180 labelangle2=270 linepattern="" hook1=0 
+Edge 2 (0-1): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=40 velocity1=2.8 angle2=30 velocity2=0.8 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=NaN labelpos=0.65 labeldegree=0 labelangle2=90 linepattern="" hook1=0 
+Edge 3 (3-1): weight=-1 hook2=0 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=250 arrowpos=25 label="Circular arc" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=0 
+Edge 4 (2-3): weight=1 hook2=0 edgewidth=2 color="OliveGreen" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=25 label="Straight arc" labelcolor="PineGreen" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 5 (0-2): weight=1 hook2=0 edgewidth=5 color="Brown" arrowsize=NaN angle1=NaN velocity1=-1 angle2=NaN velocity2=-20 arrowpos=25 label="Oval arc" labelcolor="Black" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 6 (2-2): weight=-1 hook2=12 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=-15 arrowpos=0.5 label="Circular loop" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=180 labelangle2=270 linepattern="" hook1=6 
+
+Vertex 0: id="1" x=0.0938 y=0.0896 shape="ellipse" xfact=1 yfact=1 
+Vertex 1: id="2" x=0.8188 y=0.2458 shape="ellipse" xfact=1 yfact=1 
+Vertex 2: id="3" x=0.3688 y=0.7792 shape="ellipse" xfact=1 yfact=0 
+Vertex 3: id="4" x=0.9583 y=0.8563 shape="ellipse" xfact=1 yfact=0 
+Vertex 4: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Vertex 5: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Vertex 6: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Edge 0 (0-0): weight=1 hook2=0 edgewidth=3 color="Blue" arrowsize=3 angle1=-130 velocity1=0.6 angle2=-130 velocity2=0.6 arrowpos=0.5 label="Bezier loop" labelcolor="BlueViolet" fontsize=20 labelangle=58 labelpos=0.3 labeldegree=360 labelangle2=0 linepattern="" hook1=0 
+Edge 1 (1-0): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=120 velocity1=1.3 angle2=-120 velocity2=0.3 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=19 labelpos=0.5 labeldegree=180 labelangle2=270 linepattern="" hook1=0 
+Edge 2 (0-1): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=40 velocity1=2.8 angle2=30 velocity2=0.8 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=NaN labelpos=0.65 labeldegree=0 labelangle2=90 linepattern="" hook1=0 
+Edge 3 (3-1): weight=-1 hook2=0 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=250 arrowpos=25 label="Circular arc" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=0 
+Edge 4 (2-3): weight=1 hook2=0 edgewidth=2 color="OliveGreen" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=25 label="Straight arc" labelcolor="PineGreen" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 5 (0-2): weight=1 hook2=0 edgewidth=5 color="Brown" arrowsize=NaN angle1=NaN velocity1=-1 angle2=NaN velocity2=-20 arrowpos=25 label="Oval arc" labelcolor="Black" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 6 (2-2): weight=-1 hook2=12 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=-15 arrowpos=0.5 label="Circular loop" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=180 labelangle2=270 linepattern="" hook1=6 
+
+Vertex 0: id="1" x=0.0938 y=0.0896 shape="ellipse" xfact=1 yfact=1 
+Vertex 1: id="2" x=0.8188 y=0.2458 shape="ellipse" xfact=1 yfact=1 
+Vertex 2: id="3" x=0.3688 y=0.7792 shape="ellipse" xfact=1 yfact=0 
+Vertex 3: id="4" x=0.9583 y=0.8563 shape="ellipse" xfact=1 yfact=0 
+Vertex 4: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Vertex 5: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Vertex 6: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Edge 0 (0-0): weight=1 hook2=0 edgewidth=3 color="Blue" arrowsize=3 angle1=-130 velocity1=0.6 angle2=-130 velocity2=0.6 arrowpos=0.5 label="Bezier loop" labelcolor="BlueViolet" fontsize=20 labelangle=58 labelpos=0.3 labeldegree=360 labelangle2=0 linepattern="" hook1=0 
+Edge 1 (1-0): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=120 velocity1=1.3 angle2=-120 velocity2=0.3 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=19 labelpos=0.5 labeldegree=180 labelangle2=270 linepattern="" hook1=0 
+Edge 2 (0-1): weight=1 hook2=0 edgewidth=NaN color="" arrowsize=NaN angle1=40 velocity1=2.8 angle2=30 velocity2=0.8 arrowpos=25 label="Bezier arc" labelcolor="" fontsize=NaN labelangle=NaN labelpos=0.65 labeldegree=0 labelangle2=90 linepattern="" hook1=0 
+Edge 3 (3-1): weight=-1 hook2=0 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=250 arrowpos=25 label="Circular arc" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=0 
+Edge 4 (2-3): weight=1 hook2=0 edgewidth=2 color="OliveGreen" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=25 label="Straight arc" labelcolor="PineGreen" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 5 (0-2): weight=1 hook2=0 edgewidth=5 color="Brown" arrowsize=NaN angle1=NaN velocity1=-1 angle2=NaN velocity2=-20 arrowpos=25 label="Oval arc" labelcolor="Black" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 6 (2-2): weight=-1 hook2=12 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=-15 arrowpos=0.5 label="Circular loop" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=180 labelangle2=270 linepattern="" hook1=6 
+Edge 7 (1-1): weight=NaN hook2=NaN edgewidth=NaN color="" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=NaN label="" labelcolor="" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=NaN 
+Edge 8 (2-5): weight=NaN hook2=NaN edgewidth=NaN color="" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=NaN label="" labelcolor="" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=NaN 
+Edge 9 (3-6): weight=NaN hook2=NaN edgewidth=NaN color="" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=NaN label="" labelcolor="" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=NaN 
+
+Vertex 0: id="1" x=0.0938 y=0.0896 shape="ellipse" xfact=1 yfact=1 
+Vertex 1: id="3" x=0.3688 y=0.7792 shape="ellipse" xfact=1 yfact=0 
+Vertex 2: id="4" x=0.9583 y=0.8563 shape="ellipse" xfact=1 yfact=0 
+Vertex 3: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Vertex 4: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Edge 0 (0-0): weight=1 hook2=0 edgewidth=3 color="Blue" arrowsize=3 angle1=-130 velocity1=0.6 angle2=-130 velocity2=0.6 arrowpos=0.5 label="Bezier loop" labelcolor="BlueViolet" fontsize=20 labelangle=58 labelpos=0.3 labeldegree=360 labelangle2=0 linepattern="" hook1=0 
+Edge 1 (1-2): weight=1 hook2=0 edgewidth=2 color="OliveGreen" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=25 label="Straight arc" labelcolor="PineGreen" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 2 (0-1): weight=1 hook2=0 edgewidth=5 color="Brown" arrowsize=NaN angle1=NaN velocity1=-1 angle2=NaN velocity2=-20 arrowpos=25 label="Oval arc" labelcolor="Black" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 3 (1-1): weight=-1 hook2=12 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=-15 arrowpos=0.5 label="Circular loop" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=180 labelangle2=270 linepattern="" hook1=6 
+Edge 4 (2-4): weight=NaN hook2=NaN edgewidth=NaN color="" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=NaN label="" labelcolor="" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="" hook1=NaN 
+
+Vertex 0: id="1" x=0.0938 y=0.0896 shape="ellipse" xfact=1 yfact=1 
+Vertex 1: id="3" x=0.3688 y=0.7792 shape="ellipse" xfact=1 yfact=0 
+Vertex 2: id="4" x=0.9583 y=0.8563 shape="ellipse" xfact=1 yfact=0 
+Vertex 3: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Vertex 4: id="" x=NaN y=NaN shape="" xfact=NaN yfact=NaN 
+Edge 0 (1-2): weight=1 hook2=0 edgewidth=2 color="OliveGreen" arrowsize=NaN angle1=NaN velocity1=NaN angle2=NaN velocity2=NaN arrowpos=25 label="Straight arc" labelcolor="PineGreen" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 1 (0-1): weight=1 hook2=0 edgewidth=5 color="Brown" arrowsize=NaN angle1=NaN velocity1=-1 angle2=NaN velocity2=-20 arrowpos=25 label="Oval arc" labelcolor="Black" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=NaN labelangle2=NaN linepattern="Dashed" hook1=0 
+Edge 2 (1-1): weight=-1 hook2=12 edgewidth=1 color="Red" arrowsize=NaN angle1=NaN velocity1=-2 angle2=NaN velocity2=-15 arrowpos=0.5 label="Circular loop" labelcolor="OrangeRed" fontsize=NaN labelangle=NaN labelpos=NaN labeldegree=180 labelangle2=270 linepattern="" hook1=6 
+0 1 2 3 4 
+0 1 2 3 4 
+0 1 2 
+0 1 2 
diff --git a/examples/simple/cattributes2.c b/examples/simple/cattributes2.c
new file mode 100644
index 0000000..da39c3f
--- /dev/null
+++ b/examples/simple/cattributes2.c
@@ -0,0 +1,60 @@
+/* -*- 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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t y;  
+
+  /* turn on attribute handling */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+
+  /* Create a graph, add some attributes and save it as a GraphML file */
+  igraph_famous(&g, "Petersen");
+  SETGAS(&g, "name", "Petersen's graph");
+  SETGAN(&g, "vertices", igraph_vcount(&g));
+  SETGAN(&g, "edges", igraph_ecount(&g));
+
+  igraph_vector_init_seq(&y, 1, igraph_vcount(&g));
+  SETVANV(&g, "id", &y);
+  igraph_vector_destroy(&y);
+
+  SETVAS(&g, "name", 0, "foo");
+  SETVAS(&g, "name", 1, "foobar");
+  
+  igraph_vector_init_seq(&y, 1, igraph_ecount(&g));
+  SETEANV(&g, "id", &y);
+  igraph_vector_destroy(&y);
+
+  SETEAS(&g, "name", 0, "FOO");
+  SETEAS(&g, "name", 1, "FOOBAR");
+
+  igraph_write_graph_gml(&g, stdout, 0, "");
+  igraph_write_graph_graphml(&g, stdout, /*prefixattr=*/ 1);
+   
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/cattributes2.out b/examples/simple/cattributes2.out
new file mode 100644
index 0000000..88e7157
--- /dev/null
+++ b/examples/simple/cattributes2.out
@@ -0,0 +1,283 @@
+Creator "igraph version @VERSION@ "
+Version 1
+graph
+[
+  directed 0
+  name "Petersen's graph"
+  vertices 10
+  edges 15
+  node
+  [
+    id 1
+    name "foo"
+  ]
+  node
+  [
+    id 2
+    name "foobar"
+  ]
+  node
+  [
+    id 3
+    name ""
+  ]
+  node
+  [
+    id 4
+    name ""
+  ]
+  node
+  [
+    id 5
+    name ""
+  ]
+  node
+  [
+    id 6
+    name ""
+  ]
+  node
+  [
+    id 7
+    name ""
+  ]
+  node
+  [
+    id 8
+    name ""
+  ]
+  node
+  [
+    id 9
+    name ""
+  ]
+  node
+  [
+    id 10
+    name ""
+  ]
+  edge
+  [
+    source 2
+    target 1
+    id 1
+    name "FOO"
+  ]
+  edge
+  [
+    source 5
+    target 1
+    id 2
+    name "FOOBAR"
+  ]
+  edge
+  [
+    source 6
+    target 1
+    id 3
+    name ""
+  ]
+  edge
+  [
+    source 3
+    target 2
+    id 4
+    name ""
+  ]
+  edge
+  [
+    source 7
+    target 2
+    id 5
+    name ""
+  ]
+  edge
+  [
+    source 4
+    target 3
+    id 6
+    name ""
+  ]
+  edge
+  [
+    source 8
+    target 3
+    id 7
+    name ""
+  ]
+  edge
+  [
+    source 5
+    target 4
+    id 8
+    name ""
+  ]
+  edge
+  [
+    source 9
+    target 4
+    id 9
+    name ""
+  ]
+  edge
+  [
+    source 10
+    target 5
+    id 10
+    name ""
+  ]
+  edge
+  [
+    source 8
+    target 6
+    id 11
+    name ""
+  ]
+  edge
+  [
+    source 9
+    target 6
+    id 12
+    name ""
+  ]
+  edge
+  [
+    source 9
+    target 7
+    id 13
+    name ""
+  ]
+  edge
+  [
+    source 10
+    target 7
+    id 14
+    name ""
+  ]
+  edge
+  [
+    source 10
+    target 8
+    id 15
+    name ""
+  ]
+]
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="g_name" for="graph" attr.name="name" attr.type="string"/>
+  <key id="g_vertices" for="graph" attr.name="vertices" attr.type="double"/>
+  <key id="g_edges" for="graph" attr.name="edges" attr.type="double"/>
+  <key id="v_id" for="node" attr.name="id" attr.type="double"/>
+  <key id="v_name" for="node" attr.name="name" attr.type="string"/>
+  <key id="e_id" for="edge" attr.name="id" attr.type="double"/>
+  <key id="e_name" for="edge" attr.name="name" attr.type="string"/>
+  <graph id="G" edgedefault="undirected">
+    <data key="g_name">Petersen's graph</data>
+    <data key="g_vertices">10</data>
+    <data key="g_edges">15</data>
+    <node id="n0">
+      <data key="v_id">1</data>
+      <data key="v_name">foo</data>
+    </node>
+    <node id="n1">
+      <data key="v_id">2</data>
+      <data key="v_name">foobar</data>
+    </node>
+    <node id="n2">
+      <data key="v_id">3</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n3">
+      <data key="v_id">4</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n4">
+      <data key="v_id">5</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n5">
+      <data key="v_id">6</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n6">
+      <data key="v_id">7</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n7">
+      <data key="v_id">8</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n8">
+      <data key="v_id">9</data>
+      <data key="v_name"></data>
+    </node>
+    <node id="n9">
+      <data key="v_id">10</data>
+      <data key="v_name"></data>
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_id">1</data>
+      <data key="e_name">FOO</data>
+    </edge>
+    <edge source="n0" target="n4">
+      <data key="e_id">2</data>
+      <data key="e_name">FOOBAR</data>
+    </edge>
+    <edge source="n0" target="n5">
+      <data key="e_id">3</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_id">4</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n1" target="n6">
+      <data key="e_id">5</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_id">6</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n2" target="n7">
+      <data key="e_id">7</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n3" target="n4">
+      <data key="e_id">8</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n3" target="n8">
+      <data key="e_id">9</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n4" target="n9">
+      <data key="e_id">10</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n5" target="n7">
+      <data key="e_id">11</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n5" target="n8">
+      <data key="e_id">12</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n6" target="n8">
+      <data key="e_id">13</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n6" target="n9">
+      <data key="e_id">14</data>
+      <data key="e_name"></data>
+    </edge>
+    <edge source="n7" target="n9">
+      <data key="e_id">15</data>
+      <data key="e_name"></data>
+    </edge>
+  </graph>
+</graphml>
diff --git a/examples/simple/cattributes3.c b/examples/simple/cattributes3.c
new file mode 100644
index 0000000..5eb1cc4
--- /dev/null
+++ b/examples/simple/cattributes3.c
@@ -0,0 +1,158 @@
+/* -*- 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.h>
+
+int mf(const igraph_vector_t *input, igraph_real_t *output) {
+  *output = 0.0;
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g, g2;
+  igraph_vector_t weight;
+  igraph_attribute_combination_t comb;
+  
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+  
+  igraph_small(&g, 4, IGRAPH_DIRECTED, 
+	       0, 1, 0, 1, 0, 1,
+	       1, 2, 2, 3, 
+	       -1);
+  
+  igraph_vector_init_seq(&weight, 1, igraph_ecount(&g));
+  SETEANV(&g, "weight", &weight);
+  igraph_vector_destroy(&weight);
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_SUM,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_PROD,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_MIN,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_MAX,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_FIRST,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_LAST,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_MEAN,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */  
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_FUNCTION, mf,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */  
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_MEAN,
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */  
+
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/cattributes3.out b/examples/simple/cattributes3.out
new file mode 100644
index 0000000..de970eb
--- /dev/null
+++ b/examples/simple/cattributes3.out
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">6</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">6</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">1</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">3</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">1</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">3</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">2</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">0</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">0</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">0</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_weight" for="edge" attr.name="weight" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_weight">2</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_weight">4</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_weight">5</data>
+    </edge>
+  </graph>
+</graphml>
diff --git a/examples/simple/cattributes4.c b/examples/simple/cattributes4.c
new file mode 100644
index 0000000..68da2a3
--- /dev/null
+++ b/examples/simple/cattributes4.c
@@ -0,0 +1,90 @@
+/* -*- 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.h>
+
+int mf(const igraph_strvector_t *input, char *output) {
+  /* TODO */
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g, g2;
+  igraph_attribute_combination_t comb;
+  
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+  
+  igraph_small(&g, 4, IGRAPH_DIRECTED, 
+	       0, 1, 0, 1, 0, 1,
+	       1, 2, 2, 3, 
+	       -1);
+    
+  SETEAS(&g, "color", 0, "green");
+  SETEAS(&g, "color", 1, "red");
+  SETEAS(&g, "color", 2, "blue");
+  SETEAS(&g, "color", 3, "white");
+  SETEAS(&g, "color", 4, "black");
+  
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "weight", IGRAPH_ATTRIBUTE_COMBINE_SUM,
+			       "color",  IGRAPH_ATTRIBUTE_COMBINE_FIRST,
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_LAST,
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+
+  /* ****************************************************** */
+  igraph_copy(&g2, &g);
+  igraph_attribute_combination(&comb, 
+			       "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE, 
+			       "color",  IGRAPH_ATTRIBUTE_COMBINE_CONCAT,
+			       IGRAPH_NO_MORE_ATTRIBUTES);
+  igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb);
+  igraph_attribute_combination_destroy(&comb);
+  igraph_write_graph_graphml(&g2, stdout, /*prefixattr=*/ 1);
+  igraph_destroy(&g2);
+  /* ****************************************************** */
+  
+  igraph_destroy(&g);
+
+  return 0;
+}
+  
+  
diff --git a/examples/simple/cattributes4.out b/examples/simple/cattributes4.out
new file mode 100644
index 0000000..bc3b76b
--- /dev/null
+++ b/examples/simple/cattributes4.out
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_color" for="edge" attr.name="color" attr.type="string"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_color">green</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_color">white</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_color">black</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_color" for="edge" attr.name="color" attr.type="string"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_color">blue</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_color">white</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_color">black</data>
+    </edge>
+  </graph>
+</graphml>
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="e_color" for="edge" attr.name="color" attr.type="string"/>
+  <graph id="G" edgedefault="directed">
+    <node id="n0">
+    </node>
+    <node id="n1">
+    </node>
+    <node id="n2">
+    </node>
+    <node id="n3">
+    </node>
+    <edge source="n0" target="n1">
+      <data key="e_color">greenredblue</data>
+    </edge>
+    <edge source="n1" target="n2">
+      <data key="e_color">green</data>
+    </edge>
+    <edge source="n2" target="n3">
+      <data key="e_color">green</data>
+    </edge>
+  </graph>
+</graphml>
diff --git a/examples/simple/celegansneural.gml b/examples/simple/celegansneural.gml
new file mode 100644
index 0000000..98697f4
--- /dev/null
+++ b/examples/simple/celegansneural.gml
@@ -0,0 +1,15644 @@
+Creator "Mark Newman on Thu Aug 31 12:59:09 2006"
+graph
+[
+  directed 1
+  node
+  [
+    id 0
+    label "1"
+  ]
+  node
+  [
+    id 1
+    label "51"
+  ]
+  node
+  [
+    id 2
+    label "72"
+  ]
+  node
+  [
+    id 3
+    label "77"
+  ]
+  node
+  [
+    id 4
+    label "78"
+  ]
+  node
+  [
+    id 5
+    label "2"
+  ]
+  node
+  [
+    id 6
+    label "90"
+  ]
+  node
+  [
+    id 7
+    label "92"
+  ]
+  node
+  [
+    id 8
+    label "158"
+  ]
+  node
+  [
+    id 9
+    label "159"
+  ]
+  node
+  [
+    id 10
+    label "113"
+  ]
+  node
+  [
+    id 11
+    label "69"
+  ]
+  node
+  [
+    id 12
+    label "71"
+  ]
+  node
+  [
+    id 13
+    label "89"
+  ]
+  node
+  [
+    id 14
+    label "91"
+  ]
+  node
+  [
+    id 15
+    label "3"
+  ]
+  node
+  [
+    id 16
+    label "47"
+  ]
+  node
+  [
+    id 17
+    label "9"
+  ]
+  node
+  [
+    id 18
+    label "17"
+  ]
+  node
+  [
+    id 19
+    label "21"
+  ]
+  node
+  [
+    id 20
+    label "93"
+  ]
+  node
+  [
+    id 21
+    label "94"
+  ]
+  node
+  [
+    id 22
+    label "23"
+  ]
+  node
+  [
+    id 23
+    label "121"
+  ]
+  node
+  [
+    id 24
+    label "125"
+  ]
+  node
+  [
+    id 25
+    label "131"
+  ]
+  node
+  [
+    id 26
+    label "31"
+  ]
+  node
+  [
+    id 27
+    label "4"
+  ]
+  node
+  [
+    id 28
+    label "60"
+  ]
+  node
+  [
+    id 29
+    label "10"
+  ]
+  node
+  [
+    id 30
+    label "16"
+  ]
+  node
+  [
+    id 31
+    label "18"
+  ]
+  node
+  [
+    id 32
+    label "22"
+  ]
+  node
+  [
+    id 33
+    label "24"
+  ]
+  node
+  [
+    id 34
+    label "97"
+  ]
+  node
+  [
+    id 35
+    label "122"
+  ]
+  node
+  [
+    id 36
+    label "126"
+  ]
+  node
+  [
+    id 37
+    label "132"
+  ]
+  node
+  [
+    id 38
+    label "32"
+  ]
+  node
+  [
+    id 39
+    label "303"
+  ]
+  node
+  [
+    id 40
+    label "5"
+  ]
+  node
+  [
+    id 41
+    label "7"
+  ]
+  node
+  [
+    id 42
+    label "222"
+  ]
+  node
+  [
+    id 43
+    label "101"
+  ]
+  node
+  [
+    id 44
+    label "305"
+  ]
+  node
+  [
+    id 45
+    label "6"
+  ]
+  node
+  [
+    id 46
+    label "102"
+  ]
+  node
+  [
+    id 47
+    label "99"
+  ]
+  node
+  [
+    id 48
+    label "100"
+  ]
+  node
+  [
+    id 49
+    label "27"
+  ]
+  node
+  [
+    id 50
+    label "8"
+  ]
+  node
+  [
+    id 51
+    label "26"
+  ]
+  node
+  [
+    id 52
+    label "44"
+  ]
+  node
+  [
+    id 53
+    label "37"
+  ]
+  node
+  [
+    id 54
+    label "11"
+  ]
+  node
+  [
+    id 55
+    label "19"
+  ]
+  node
+  [
+    id 56
+    label "29"
+  ]
+  node
+  [
+    id 57
+    label "12"
+  ]
+  node
+  [
+    id 58
+    label "41"
+  ]
+  node
+  [
+    id 59
+    label "118"
+  ]
+  node
+  [
+    id 60
+    label "25"
+  ]
+  node
+  [
+    id 61
+    label "30"
+  ]
+  node
+  [
+    id 62
+    label "13"
+  ]
+  node
+  [
+    id 63
+    label "143"
+  ]
+  node
+  [
+    id 64
+    label "28"
+  ]
+  node
+  [
+    id 65
+    label "43"
+  ]
+  node
+  [
+    id 66
+    label "14"
+  ]
+  node
+  [
+    id 67
+    label "144"
+  ]
+  node
+  [
+    id 68
+    label "20"
+  ]
+  node
+  [
+    id 69
+    label "34"
+  ]
+  node
+  [
+    id 70
+    label "15"
+  ]
+  node
+  [
+    id 71
+    label "40"
+  ]
+  node
+  [
+    id 72
+    label "128"
+  ]
+  node
+  [
+    id 73
+    label "139"
+  ]
+  node
+  [
+    id 74
+    label "140"
+  ]
+  node
+  [
+    id 75
+    label "108"
+  ]
+  node
+  [
+    id 76
+    label "35"
+  ]
+  node
+  [
+    id 77
+    label "107"
+  ]
+  node
+  [
+    id 78
+    label "133"
+  ]
+  node
+  [
+    id 79
+    label "134"
+  ]
+  node
+  [
+    id 80
+    label "105"
+  ]
+  node
+  [
+    id 81
+    label "106"
+  ]
+  node
+  [
+    id 82
+    label "36"
+  ]
+  node
+  [
+    id 83
+    label "33"
+  ]
+  node
+  [
+    id 84
+    label "73"
+  ]
+  node
+  [
+    id 85
+    label "136"
+  ]
+  node
+  [
+    id 86
+    label "74"
+  ]
+  node
+  [
+    id 87
+    label "161"
+  ]
+  node
+  [
+    id 88
+    label "129"
+  ]
+  node
+  [
+    id 89
+    label "135"
+  ]
+  node
+  [
+    id 90
+    label "120"
+  ]
+  node
+  [
+    id 91
+    label "38"
+  ]
+  node
+  [
+    id 92
+    label "39"
+  ]
+  node
+  [
+    id 93
+    label "160"
+  ]
+  node
+  [
+    id 94
+    label "130"
+  ]
+  node
+  [
+    id 95
+    label "174"
+  ]
+  node
+  [
+    id 96
+    label "42"
+  ]
+  node
+  [
+    id 97
+    label "189"
+  ]
+  node
+  [
+    id 98
+    label "82"
+  ]
+  node
+  [
+    id 99
+    label "70"
+  ]
+  node
+  [
+    id 100
+    label "45"
+  ]
+  node
+  [
+    id 101
+    label "141"
+  ]
+  node
+  [
+    id 102
+    label "55"
+  ]
+  node
+  [
+    id 103
+    label "119"
+  ]
+  node
+  [
+    id 104
+    label "137"
+  ]
+  node
+  [
+    id 105
+    label "46"
+  ]
+  node
+  [
+    id 106
+    label "142"
+  ]
+  node
+  [
+    id 107
+    label "114"
+  ]
+  node
+  [
+    id 108
+    label "56"
+  ]
+  node
+  [
+    id 109
+    label "62"
+  ]
+  node
+  [
+    id 110
+    label "86"
+  ]
+  node
+  [
+    id 111
+    label "193"
+  ]
+  node
+  [
+    id 112
+    label "138"
+  ]
+  node
+  [
+    id 113
+    label "109"
+  ]
+  node
+  [
+    id 114
+    label "52"
+  ]
+  node
+  [
+    id 115
+    label "58"
+  ]
+  node
+  [
+    id 116
+    label "61"
+  ]
+  node
+  [
+    id 117
+    label "75"
+  ]
+  node
+  [
+    id 118
+    label "76"
+  ]
+  node
+  [
+    id 119
+    label "81"
+  ]
+  node
+  [
+    id 120
+    label "85"
+  ]
+  node
+  [
+    id 121
+    label "48"
+  ]
+  node
+  [
+    id 122
+    label "110"
+  ]
+  node
+  [
+    id 123
+    label "80"
+  ]
+  node
+  [
+    id 124
+    label "88"
+  ]
+  node
+  [
+    id 125
+    label "216"
+  ]
+  node
+  [
+    id 126
+    label "49"
+  ]
+  node
+  [
+    id 127
+    label "54"
+  ]
+  node
+  [
+    id 128
+    label "50"
+  ]
+  node
+  [
+    id 129
+    label "154"
+  ]
+  node
+  [
+    id 130
+    label "96"
+  ]
+  node
+  [
+    id 131
+    label "127"
+  ]
+  node
+  [
+    id 132
+    label "95"
+  ]
+  node
+  [
+    id 133
+    label "166"
+  ]
+  node
+  [
+    id 134
+    label "53"
+  ]
+  node
+  [
+    id 135
+    label "57"
+  ]
+  node
+  [
+    id 136
+    label "63"
+  ]
+  node
+  [
+    id 137
+    label "198"
+  ]
+  node
+  [
+    id 138
+    label "87"
+  ]
+  node
+  [
+    id 139
+    label "84"
+  ]
+  node
+  [
+    id 140
+    label "59"
+  ]
+  node
+  [
+    id 141
+    label "67"
+  ]
+  node
+  [
+    id 142
+    label "178"
+  ]
+  node
+  [
+    id 143
+    label "64"
+  ]
+  node
+  [
+    id 144
+    label "65"
+  ]
+  node
+  [
+    id 145
+    label "220"
+  ]
+  node
+  [
+    id 146
+    label "66"
+  ]
+  node
+  [
+    id 147
+    label "68"
+  ]
+  node
+  [
+    id 148
+    label "221"
+  ]
+  node
+  [
+    id 149
+    label "111"
+  ]
+  node
+  [
+    id 150
+    label "112"
+  ]
+  node
+  [
+    id 151
+    label "146"
+  ]
+  node
+  [
+    id 152
+    label "225"
+  ]
+  node
+  [
+    id 153
+    label "186"
+  ]
+  node
+  [
+    id 154
+    label "226"
+  ]
+  node
+  [
+    id 155
+    label "227"
+  ]
+  node
+  [
+    id 156
+    label "228"
+  ]
+  node
+  [
+    id 157
+    label "229"
+  ]
+  node
+  [
+    id 158
+    label "230"
+  ]
+  node
+  [
+    id 159
+    label "150"
+  ]
+  node
+  [
+    id 160
+    label "234"
+  ]
+  node
+  [
+    id 161
+    label "235"
+  ]
+  node
+  [
+    id 162
+    label "236"
+  ]
+  node
+  [
+    id 163
+    label "237"
+  ]
+  node
+  [
+    id 164
+    label "238"
+  ]
+  node
+  [
+    id 165
+    label "239"
+  ]
+  node
+  [
+    id 166
+    label "187"
+  ]
+  node
+  [
+    id 167
+    label "188"
+  ]
+  node
+  [
+    id 168
+    label "240"
+  ]
+  node
+  [
+    id 169
+    label "242"
+  ]
+  node
+  [
+    id 170
+    label "203"
+  ]
+  node
+  [
+    id 171
+    label "179"
+  ]
+  node
+  [
+    id 172
+    label "217"
+  ]
+  node
+  [
+    id 173
+    label "162"
+  ]
+  node
+  [
+    id 174
+    label "164"
+  ]
+  node
+  [
+    id 175
+    label "249"
+  ]
+  node
+  [
+    id 176
+    label "250"
+  ]
+  node
+  [
+    id 177
+    label "195"
+  ]
+  node
+  [
+    id 178
+    label "251"
+  ]
+  node
+  [
+    id 179
+    label "252"
+  ]
+  node
+  [
+    id 180
+    label "253"
+  ]
+  node
+  [
+    id 181
+    label "254"
+  ]
+  node
+  [
+    id 182
+    label "255"
+  ]
+  node
+  [
+    id 183
+    label "197"
+  ]
+  node
+  [
+    id 184
+    label "204"
+  ]
+  node
+  [
+    id 185
+    label "180"
+  ]
+  node
+  [
+    id 186
+    label "163"
+  ]
+  node
+  [
+    id 187
+    label "117"
+  ]
+  node
+  [
+    id 188
+    label "256"
+  ]
+  node
+  [
+    id 189
+    label "276"
+  ]
+  node
+  [
+    id 190
+    label "306"
+  ]
+  node
+  [
+    id 191
+    label "177"
+  ]
+  node
+  [
+    id 192
+    label "241"
+  ]
+  node
+  [
+    id 193
+    label "200"
+  ]
+  node
+  [
+    id 194
+    label "215"
+  ]
+  node
+  [
+    id 195
+    label "199"
+  ]
+  node
+  [
+    id 196
+    label "165"
+  ]
+  node
+  [
+    id 197
+    label "169"
+  ]
+  node
+  [
+    id 198
+    label "79"
+  ]
+  node
+  [
+    id 199
+    label "148"
+  ]
+  node
+  [
+    id 200
+    label "168"
+  ]
+  node
+  [
+    id 201
+    label "145"
+  ]
+  node
+  [
+    id 202
+    label "147"
+  ]
+  node
+  [
+    id 203
+    label "192"
+  ]
+  node
+  [
+    id 204
+    label "219"
+  ]
+  node
+  [
+    id 205
+    label "157"
+  ]
+  node
+  [
+    id 206
+    label "172"
+  ]
+  node
+  [
+    id 207
+    label "218"
+  ]
+  node
+  [
+    id 208
+    label "83"
+  ]
+  node
+  [
+    id 209
+    label "98"
+  ]
+  node
+  [
+    id 210
+    label "124"
+  ]
+  node
+  [
+    id 211
+    label "103"
+  ]
+  node
+  [
+    id 212
+    label "104"
+  ]
+  node
+  [
+    id 213
+    label "115"
+  ]
+  node
+  [
+    id 214
+    label "123"
+  ]
+  node
+  [
+    id 215
+    label "156"
+  ]
+  node
+  [
+    id 216
+    label "170"
+  ]
+  node
+  [
+    id 217
+    label "183"
+  ]
+  node
+  [
+    id 218
+    label "116"
+  ]
+  node
+  [
+    id 219
+    label "153"
+  ]
+  node
+  [
+    id 220
+    label "224"
+  ]
+  node
+  [
+    id 221
+    label "196"
+  ]
+  node
+  [
+    id 222
+    label "214"
+  ]
+  node
+  [
+    id 223
+    label "213"
+  ]
+  node
+  [
+    id 224
+    label "155"
+  ]
+  node
+  [
+    id 225
+    label "173"
+  ]
+  node
+  [
+    id 226
+    label "149"
+  ]
+  node
+  [
+    id 227
+    label "275"
+  ]
+  node
+  [
+    id 228
+    label "205"
+  ]
+  node
+  [
+    id 229
+    label "206"
+  ]
+  node
+  [
+    id 230
+    label "151"
+  ]
+  node
+  [
+    id 231
+    label "277"
+  ]
+  node
+  [
+    id 232
+    label "152"
+  ]
+  node
+  [
+    id 233
+    label "245"
+  ]
+  node
+  [
+    id 234
+    label "278"
+  ]
+  node
+  [
+    id 235
+    label "201"
+  ]
+  node
+  [
+    id 236
+    label "202"
+  ]
+  node
+  [
+    id 237
+    label "167"
+  ]
+  node
+  [
+    id 238
+    label "269"
+  ]
+  node
+  [
+    id 239
+    label "184"
+  ]
+  node
+  [
+    id 240
+    label "171"
+  ]
+  node
+  [
+    id 241
+    label "185"
+  ]
+  node
+  [
+    id 242
+    label "175"
+  ]
+  node
+  [
+    id 243
+    label "176"
+  ]
+  node
+  [
+    id 244
+    label "272"
+  ]
+  node
+  [
+    id 245
+    label "270"
+  ]
+  node
+  [
+    id 246
+    label "258"
+  ]
+  node
+  [
+    id 247
+    label "181"
+  ]
+  node
+  [
+    id 248
+    label "182"
+  ]
+  node
+  [
+    id 249
+    label "274"
+  ]
+  node
+  [
+    id 250
+    label "190"
+  ]
+  node
+  [
+    id 251
+    label "191"
+  ]
+  node
+  [
+    id 252
+    label "194"
+  ]
+  node
+  [
+    id 253
+    label "244"
+  ]
+  node
+  [
+    id 254
+    label "260"
+  ]
+  node
+  [
+    id 255
+    label "207"
+  ]
+  node
+  [
+    id 256
+    label "223"
+  ]
+  node
+  [
+    id 257
+    label "208"
+  ]
+  node
+  [
+    id 258
+    label "209"
+  ]
+  node
+  [
+    id 259
+    label "210"
+  ]
+  node
+  [
+    id 260
+    label "211"
+  ]
+  node
+  [
+    id 261
+    label "212"
+  ]
+  node
+  [
+    id 262
+    label "261"
+  ]
+  node
+  [
+    id 263
+    label "262"
+  ]
+  node
+  [
+    id 264
+    label "263"
+  ]
+  node
+  [
+    id 265
+    label "264"
+  ]
+  node
+  [
+    id 266
+    label "265"
+  ]
+  node
+  [
+    id 267
+    label "266"
+  ]
+  node
+  [
+    id 268
+    label "282"
+  ]
+  node
+  [
+    id 269
+    label "279"
+  ]
+  node
+  [
+    id 270
+    label "231"
+  ]
+  node
+  [
+    id 271
+    label "280"
+  ]
+  node
+  [
+    id 272
+    label "232"
+  ]
+  node
+  [
+    id 273
+    label "281"
+  ]
+  node
+  [
+    id 274
+    label "233"
+  ]
+  node
+  [
+    id 275
+    label "246"
+  ]
+  node
+  [
+    id 276
+    label "247"
+  ]
+  node
+  [
+    id 277
+    label "248"
+  ]
+  node
+  [
+    id 278
+    label "243"
+  ]
+  node
+  [
+    id 279
+    label "257"
+  ]
+  node
+  [
+    id 280
+    label "259"
+  ]
+  node
+  [
+    id 281
+    label "267"
+  ]
+  node
+  [
+    id 282
+    label "268"
+  ]
+  node
+  [
+    id 283
+    label "271"
+  ]
+  node
+  [
+    id 284
+    label "273"
+  ]
+  node
+  [
+    id 285
+    label "291"
+  ]
+  node
+  [
+    id 286
+    label "292"
+  ]
+  node
+  [
+    id 287
+    label "293"
+  ]
+  node
+  [
+    id 288
+    label "294"
+  ]
+  node
+  [
+    id 289
+    label "295"
+  ]
+  node
+  [
+    id 290
+    label "296"
+  ]
+  node
+  [
+    id 291
+    label "297"
+  ]
+  node
+  [
+    id 292
+    label "298"
+  ]
+  node
+  [
+    id 293
+    label "299"
+  ]
+  node
+  [
+    id 294
+    label "300"
+  ]
+  node
+  [
+    id 295
+    label "301"
+  ]
+  node
+  [
+    id 296
+    label "302"
+  ]
+  edge
+  [
+    source 0
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 0
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 0
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 0
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 0
+    target 5
+    value 1
+  ]
+  edge
+  [
+    source 0
+    target 6
+    value 6
+  ]
+  edge
+  [
+    source 0
+    target 7
+    value 6
+  ]
+  edge
+  [
+    source 0
+    target 8
+    value 1
+  ]
+  edge
+  [
+    source 0
+    target 9
+    value 4
+  ]
+  edge
+  [
+    source 1
+    target 10
+    value 1
+  ]
+  edge
+  [
+    source 1
+    target 115
+    value 1
+  ]
+  edge
+  [
+    source 1
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 1
+    target 84
+    value 3
+  ]
+  edge
+  [
+    source 1
+    target 129
+    value 1
+  ]
+  edge
+  [
+    source 1
+    target 7
+    value 2
+  ]
+  edge
+  [
+    source 1
+    target 130
+    value 12
+  ]
+  edge
+  [
+    source 1
+    target 131
+    value 1
+  ]
+  edge
+  [
+    source 1
+    target 72
+    value 2
+  ]
+  edge
+  [
+    source 1
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 2
+    target 67
+    value 1
+  ]
+  edge
+  [
+    source 2
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 2
+    target 152
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 153
+    value 9
+  ]
+  edge
+  [
+    source 2
+    target 154
+    value 3
+  ]
+  edge
+  [
+    source 2
+    target 155
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 156
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 157
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 158
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 12
+    value 3
+  ]
+  edge
+  [
+    source 2
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 118
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 4
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 159
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 160
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 161
+    value 9
+  ]
+  edge
+  [
+    source 2
+    target 162
+    value 12
+  ]
+  edge
+  [
+    source 2
+    target 163
+    value 9
+  ]
+  edge
+  [
+    source 2
+    target 164
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 165
+    value 7
+  ]
+  edge
+  [
+    source 2
+    target 166
+    value 14
+  ]
+  edge
+  [
+    source 2
+    target 167
+    value 5
+  ]
+  edge
+  [
+    source 2
+    target 168
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 169
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 184
+    value 5
+  ]
+  edge
+  [
+    source 2
+    target 185
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 125
+    value 28
+  ]
+  edge
+  [
+    source 2
+    target 8
+    value 1
+  ]
+  edge
+  [
+    source 2
+    target 173
+    value 1
+  ]
+  edge
+  [
+    source 2
+    target 186
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 175
+    value 10
+  ]
+  edge
+  [
+    source 2
+    target 176
+    value 14
+  ]
+  edge
+  [
+    source 2
+    target 177
+    value 2
+  ]
+  edge
+  [
+    source 2
+    target 178
+    value 3
+  ]
+  edge
+  [
+    source 2
+    target 179
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 180
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 181
+    value 6
+  ]
+  edge
+  [
+    source 2
+    target 182
+    value 4
+  ]
+  edge
+  [
+    source 2
+    target 183
+    value 2
+  ]
+  edge
+  [
+    source 3
+    target 151
+    value 5
+  ]
+  edge
+  [
+    source 3
+    target 154
+    value 2
+  ]
+  edge
+  [
+    source 3
+    target 155
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 12
+    value 44
+  ]
+  edge
+  [
+    source 3
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 159
+    value 12
+  ]
+  edge
+  [
+    source 3
+    target 160
+    value 6
+  ]
+  edge
+  [
+    source 3
+    target 161
+    value 4
+  ]
+  edge
+  [
+    source 3
+    target 162
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 168
+    value 2
+  ]
+  edge
+  [
+    source 3
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 173
+    value 8
+  ]
+  edge
+  [
+    source 3
+    target 186
+    value 17
+  ]
+  edge
+  [
+    source 3
+    target 196
+    value 6
+  ]
+  edge
+  [
+    source 3
+    target 178
+    value 2
+  ]
+  edge
+  [
+    source 3
+    target 179
+    value 5
+  ]
+  edge
+  [
+    source 3
+    target 180
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 182
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 3
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 151
+    value 5
+  ]
+  edge
+  [
+    source 4
+    target 154
+    value 2
+  ]
+  edge
+  [
+    source 4
+    target 155
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 2
+    value 44
+  ]
+  edge
+  [
+    source 4
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 159
+    value 12
+  ]
+  edge
+  [
+    source 4
+    target 160
+    value 6
+  ]
+  edge
+  [
+    source 4
+    target 161
+    value 4
+  ]
+  edge
+  [
+    source 4
+    target 162
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 168
+    value 2
+  ]
+  edge
+  [
+    source 4
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 173
+    value 8
+  ]
+  edge
+  [
+    source 4
+    target 174
+    value 17
+  ]
+  edge
+  [
+    source 4
+    target 196
+    value 6
+  ]
+  edge
+  [
+    source 4
+    target 178
+    value 2
+  ]
+  edge
+  [
+    source 4
+    target 179
+    value 5
+  ]
+  edge
+  [
+    source 4
+    target 180
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 182
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 4
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 5
+    target 10
+    value 1
+  ]
+  edge
+  [
+    source 5
+    target 11
+    value 1
+  ]
+  edge
+  [
+    source 5
+    target 12
+    value 3
+  ]
+  edge
+  [
+    source 5
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 5
+    target 13
+    value 4
+  ]
+  edge
+  [
+    source 5
+    target 14
+    value 4
+  ]
+  edge
+  [
+    source 5
+    target 8
+    value 7
+  ]
+  edge
+  [
+    source 6
+    target 27
+    value 1
+  ]
+  edge
+  [
+    source 6
+    target 50
+    value 1
+  ]
+  edge
+  [
+    source 6
+    target 34
+    value 2
+  ]
+  edge
+  [
+    source 6
+    target 23
+    value 12
+  ]
+  edge
+  [
+    source 6
+    target 35
+    value 8
+  ]
+  edge
+  [
+    source 6
+    target 47
+    value 5
+  ]
+  edge
+  [
+    source 6
+    target 48
+    value 7
+  ]
+  edge
+  [
+    source 6
+    target 43
+    value 4
+  ]
+  edge
+  [
+    source 6
+    target 46
+    value 9
+  ]
+  edge
+  [
+    source 6
+    target 72
+    value 1
+  ]
+  edge
+  [
+    source 6
+    target 88
+    value 1
+  ]
+  edge
+  [
+    source 6
+    target 94
+    value 1
+  ]
+  edge
+  [
+    source 6
+    target 25
+    value 1
+  ]
+  edge
+  [
+    source 6
+    target 73
+    value 6
+  ]
+  edge
+  [
+    source 6
+    target 74
+    value 10
+  ]
+  edge
+  [
+    source 6
+    target 77
+    value 13
+  ]
+  edge
+  [
+    source 6
+    target 75
+    value 7
+  ]
+  edge
+  [
+    source 7
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 7
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 7
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 7
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 7
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 7
+    target 73
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 102
+    value 2
+  ]
+  edge
+  [
+    source 8
+    target 108
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 235
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 8
+    target 213
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 5
+    value 2
+  ]
+  edge
+  [
+    source 8
+    target 193
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 103
+    value 2
+  ]
+  edge
+  [
+    source 8
+    target 214
+    value 1
+  ]
+  edge
+  [
+    source 8
+    target 36
+    value 3
+  ]
+  edge
+  [
+    source 9
+    target 108
+    value 2
+  ]
+  edge
+  [
+    source 9
+    target 236
+    value 1
+  ]
+  edge
+  [
+    source 9
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 9
+    target 213
+    value 4
+  ]
+  edge
+  [
+    source 9
+    target 218
+    value 1
+  ]
+  edge
+  [
+    source 9
+    target 5
+    value 1
+  ]
+  edge
+  [
+    source 9
+    target 7
+    value 1
+  ]
+  edge
+  [
+    source 9
+    target 103
+    value 1
+  ]
+  edge
+  [
+    source 9
+    target 24
+    value 4
+  ]
+  edge
+  [
+    source 10
+    target 102
+    value 13
+  ]
+  edge
+  [
+    source 10
+    target 208
+    value 3
+  ]
+  edge
+  [
+    source 10
+    target 138
+    value 1
+  ]
+  edge
+  [
+    source 10
+    target 124
+    value 1
+  ]
+  edge
+  [
+    source 10
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 10
+    target 13
+    value 5
+  ]
+  edge
+  [
+    source 10
+    target 14
+    value 5
+  ]
+  edge
+  [
+    source 11
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 11
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 11
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 11
+    target 13
+    value 6
+  ]
+  edge
+  [
+    source 11
+    target 14
+    value 9
+  ]
+  edge
+  [
+    source 12
+    target 16
+    value 1
+  ]
+  edge
+  [
+    source 12
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 12
+    target 152
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 153
+    value 9
+  ]
+  edge
+  [
+    source 12
+    target 154
+    value 3
+  ]
+  edge
+  [
+    source 12
+    target 155
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 156
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 157
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 158
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 2
+    value 3
+  ]
+  edge
+  [
+    source 12
+    target 84
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 117
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 159
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 160
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 161
+    value 9
+  ]
+  edge
+  [
+    source 12
+    target 162
+    value 12
+  ]
+  edge
+  [
+    source 12
+    target 163
+    value 9
+  ]
+  edge
+  [
+    source 12
+    target 164
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 165
+    value 7
+  ]
+  edge
+  [
+    source 12
+    target 166
+    value 14
+  ]
+  edge
+  [
+    source 12
+    target 167
+    value 5
+  ]
+  edge
+  [
+    source 12
+    target 168
+    value 1
+  ]
+  edge
+  [
+    source 12
+    target 168
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 169
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 170
+    value 5
+  ]
+  edge
+  [
+    source 12
+    target 171
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 172
+    value 28
+  ]
+  edge
+  [
+    source 12
+    target 173
+    value 1
+  ]
+  edge
+  [
+    source 12
+    target 174
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 175
+    value 10
+  ]
+  edge
+  [
+    source 12
+    target 176
+    value 14
+  ]
+  edge
+  [
+    source 12
+    target 177
+    value 2
+  ]
+  edge
+  [
+    source 12
+    target 178
+    value 3
+  ]
+  edge
+  [
+    source 12
+    target 179
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 180
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 181
+    value 6
+  ]
+  edge
+  [
+    source 12
+    target 182
+    value 4
+  ]
+  edge
+  [
+    source 12
+    target 183
+    value 2
+  ]
+  edge
+  [
+    source 13
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 13
+    target 34
+    value 2
+  ]
+  edge
+  [
+    source 13
+    target 209
+    value 3
+  ]
+  edge
+  [
+    source 13
+    target 23
+    value 10
+  ]
+  edge
+  [
+    source 13
+    target 35
+    value 6
+  ]
+  edge
+  [
+    source 13
+    target 47
+    value 6
+  ]
+  edge
+  [
+    source 13
+    target 48
+    value 5
+  ]
+  edge
+  [
+    source 13
+    target 43
+    value 7
+  ]
+  edge
+  [
+    source 13
+    target 46
+    value 10
+  ]
+  edge
+  [
+    source 13
+    target 88
+    value 1
+  ]
+  edge
+  [
+    source 13
+    target 73
+    value 9
+  ]
+  edge
+  [
+    source 13
+    target 74
+    value 8
+  ]
+  edge
+  [
+    source 13
+    target 77
+    value 3
+  ]
+  edge
+  [
+    source 13
+    target 75
+    value 12
+  ]
+  edge
+  [
+    source 14
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 14
+    target 11
+    value 1
+  ]
+  edge
+  [
+    source 14
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 14
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 14
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 14
+    target 3
+    value 2
+  ]
+  edge
+  [
+    source 14
+    target 4
+    value 5
+  ]
+  edge
+  [
+    source 14
+    target 13
+    value 3
+  ]
+  edge
+  [
+    source 14
+    target 75
+    value 2
+  ]
+  edge
+  [
+    source 15
+    target 16
+    value 1
+  ]
+  edge
+  [
+    source 15
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 15
+    target 17
+    value 2
+  ]
+  edge
+  [
+    source 15
+    target 18
+    value 4
+  ]
+  edge
+  [
+    source 15
+    target 19
+    value 5
+  ]
+  edge
+  [
+    source 15
+    target 20
+    value 6
+  ]
+  edge
+  [
+    source 15
+    target 21
+    value 4
+  ]
+  edge
+  [
+    source 15
+    target 22
+    value 1
+  ]
+  edge
+  [
+    source 15
+    target 23
+    value 3
+  ]
+  edge
+  [
+    source 15
+    target 24
+    value 1
+  ]
+  edge
+  [
+    source 15
+    target 25
+    value 2
+  ]
+  edge
+  [
+    source 15
+    target 26
+    value 2
+  ]
+  edge
+  [
+    source 16
+    target 113
+    value 5
+  ]
+  edge
+  [
+    source 16
+    target 1
+    value 6
+  ]
+  edge
+  [
+    source 16
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 92
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 115
+    value 3
+  ]
+  edge
+  [
+    source 16
+    target 116
+    value 2
+  ]
+  edge
+  [
+    source 16
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 16
+    target 2
+    value 4
+  ]
+  edge
+  [
+    source 16
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 118
+    value 4
+  ]
+  edge
+  [
+    source 16
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 16
+    target 120
+    value 2
+  ]
+  edge
+  [
+    source 16
+    target 19
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 22
+    value 1
+  ]
+  edge
+  [
+    source 16
+    target 73
+    value 2
+  ]
+  edge
+  [
+    source 17
+    target 41
+    value 1
+  ]
+  edge
+  [
+    source 17
+    target 22
+    value 7
+  ]
+  edge
+  [
+    source 17
+    target 23
+    value 11
+  ]
+  edge
+  [
+    source 17
+    target 53
+    value 1
+  ]
+  edge
+  [
+    source 17
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 18
+    target 4
+    value 19
+  ]
+  edge
+  [
+    source 18
+    target 71
+    value 2
+  ]
+  edge
+  [
+    source 18
+    target 15
+    value 2
+  ]
+  edge
+  [
+    source 18
+    target 17
+    value 1
+  ]
+  edge
+  [
+    source 18
+    target 14
+    value 7
+  ]
+  edge
+  [
+    source 18
+    target 23
+    value 7
+  ]
+  edge
+  [
+    source 18
+    target 35
+    value 1
+  ]
+  edge
+  [
+    source 18
+    target 47
+    value 2
+  ]
+  edge
+  [
+    source 18
+    target 43
+    value 1
+  ]
+  edge
+  [
+    source 18
+    target 51
+    value 2
+  ]
+  edge
+  [
+    source 18
+    target 72
+    value 1
+  ]
+  edge
+  [
+    source 18
+    target 73
+    value 3
+  ]
+  edge
+  [
+    source 18
+    target 74
+    value 4
+  ]
+  edge
+  [
+    source 18
+    target 75
+    value 4
+  ]
+  edge
+  [
+    source 18
+    target 76
+    value 1
+  ]
+  edge
+  [
+    source 19
+    target 17
+    value 2
+  ]
+  edge
+  [
+    source 19
+    target 70
+    value 1
+  ]
+  edge
+  [
+    source 19
+    target 20
+    value 1
+  ]
+  edge
+  [
+    source 19
+    target 59
+    value 2
+  ]
+  edge
+  [
+    source 19
+    target 22
+    value 2
+  ]
+  edge
+  [
+    source 19
+    target 46
+    value 4
+  ]
+  edge
+  [
+    source 19
+    target 80
+    value 3
+  ]
+  edge
+  [
+    source 20
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 20
+    target 2
+    value 6
+  ]
+  edge
+  [
+    source 20
+    target 132
+    value 1
+  ]
+  edge
+  [
+    source 20
+    target 130
+    value 2
+  ]
+  edge
+  [
+    source 20
+    target 209
+    value 1
+  ]
+  edge
+  [
+    source 20
+    target 210
+    value 1
+  ]
+  edge
+  [
+    source 20
+    target 89
+    value 2
+  ]
+  edge
+  [
+    source 20
+    target 73
+    value 3
+  ]
+  edge
+  [
+    source 20
+    target 74
+    value 4
+  ]
+  edge
+  [
+    source 20
+    target 75
+    value 1
+  ]
+  edge
+  [
+    source 21
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 21
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 21
+    target 2
+    value 3
+  ]
+  edge
+  [
+    source 21
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 21
+    target 73
+    value 2
+  ]
+  edge
+  [
+    source 21
+    target 74
+    value 3
+  ]
+  edge
+  [
+    source 21
+    target 77
+    value 2
+  ]
+  edge
+  [
+    source 21
+    target 75
+    value 1
+  ]
+  edge
+  [
+    source 22
+    target 55
+    value 2
+  ]
+  edge
+  [
+    source 23
+    target 46
+    value 7
+  ]
+  edge
+  [
+    source 23
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 24
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 24
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 25
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 26
+    target 22
+    value 3
+  ]
+  edge
+  [
+    source 26
+    target 51
+    value 1
+  ]
+  edge
+  [
+    source 26
+    target 49
+    value 1
+  ]
+  edge
+  [
+    source 26
+    target 64
+    value 2
+  ]
+  edge
+  [
+    source 26
+    target 44
+    value 9
+  ]
+  edge
+  [
+    source 27
+    target 28
+    value 1
+  ]
+  edge
+  [
+    source 27
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 27
+    target 29
+    value 2
+  ]
+  edge
+  [
+    source 27
+    target 30
+    value 1
+  ]
+  edge
+  [
+    source 27
+    target 31
+    value 5
+  ]
+  edge
+  [
+    source 27
+    target 32
+    value 3
+  ]
+  edge
+  [
+    source 27
+    target 20
+    value 2
+  ]
+  edge
+  [
+    source 27
+    target 21
+    value 4
+  ]
+  edge
+  [
+    source 27
+    target 33
+    value 1
+  ]
+  edge
+  [
+    source 27
+    target 34
+    value 1
+  ]
+  edge
+  [
+    source 27
+    target 35
+    value 2
+  ]
+  edge
+  [
+    source 27
+    target 36
+    value 2
+  ]
+  edge
+  [
+    source 27
+    target 37
+    value 2
+  ]
+  edge
+  [
+    source 27
+    target 38
+    value 1
+  ]
+  edge
+  [
+    source 27
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 28
+    target 122
+    value 10
+  ]
+  edge
+  [
+    source 28
+    target 114
+    value 2
+  ]
+  edge
+  [
+    source 29
+    target 50
+    value 1
+  ]
+  edge
+  [
+    source 29
+    target 30
+    value 1
+  ]
+  edge
+  [
+    source 29
+    target 33
+    value 8
+  ]
+  edge
+  [
+    source 29
+    target 35
+    value 11
+  ]
+  edge
+  [
+    source 29
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 30
+    target 29
+    value 5
+  ]
+  edge
+  [
+    source 30
+    target 32
+    value 2
+  ]
+  edge
+  [
+    source 30
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 30
+    target 59
+    value 4
+  ]
+  edge
+  [
+    source 30
+    target 33
+    value 14
+  ]
+  edge
+  [
+    source 30
+    target 51
+    value 3
+  ]
+  edge
+  [
+    source 30
+    target 49
+    value 2
+  ]
+  edge
+  [
+    source 30
+    target 64
+    value 3
+  ]
+  edge
+  [
+    source 30
+    target 38
+    value 3
+  ]
+  edge
+  [
+    source 30
+    target 52
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 3
+    value 14
+  ]
+  edge
+  [
+    source 31
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 58
+    value 2
+  ]
+  edge
+  [
+    source 31
+    target 27
+    value 6
+  ]
+  edge
+  [
+    source 31
+    target 45
+    value 3
+  ]
+  edge
+  [
+    source 31
+    target 29
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 66
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 7
+    value 10
+  ]
+  edge
+  [
+    source 31
+    target 35
+    value 10
+  ]
+  edge
+  [
+    source 31
+    target 47
+    value 2
+  ]
+  edge
+  [
+    source 31
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 46
+    value 3
+  ]
+  edge
+  [
+    source 31
+    target 49
+    value 2
+  ]
+  edge
+  [
+    source 31
+    target 73
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 31
+    target 77
+    value 3
+  ]
+  edge
+  [
+    source 31
+    target 75
+    value 3
+  ]
+  edge
+  [
+    source 32
+    target 29
+    value 1
+  ]
+  edge
+  [
+    source 32
+    target 30
+    value 1
+  ]
+  edge
+  [
+    source 32
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 32
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 32
+    target 33
+    value 1
+  ]
+  edge
+  [
+    source 32
+    target 43
+    value 3
+  ]
+  edge
+  [
+    source 32
+    target 49
+    value 1
+  ]
+  edge
+  [
+    source 32
+    target 81
+    value 3
+  ]
+  edge
+  [
+    source 33
+    target 68
+    value 2
+  ]
+  edge
+  [
+    source 34
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 34
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 34
+    target 47
+    value 2
+  ]
+  edge
+  [
+    source 34
+    target 43
+    value 1
+  ]
+  edge
+  [
+    source 34
+    target 72
+    value 3
+  ]
+  edge
+  [
+    source 34
+    target 37
+    value 3
+  ]
+  edge
+  [
+    source 34
+    target 112
+    value 1
+  ]
+  edge
+  [
+    source 34
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 34
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 35
+    target 43
+    value 10
+  ]
+  edge
+  [
+    source 35
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 36
+    target 49
+    value 1
+  ]
+  edge
+  [
+    source 36
+    target 93
+    value 1
+  ]
+  edge
+  [
+    source 36
+    target 44
+    value 7
+  ]
+  edge
+  [
+    source 37
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 38
+    target 50
+    value 1
+  ]
+  edge
+  [
+    source 38
+    target 33
+    value 4
+  ]
+  edge
+  [
+    source 38
+    target 43
+    value 1
+  ]
+  edge
+  [
+    source 38
+    target 49
+    value 2
+  ]
+  edge
+  [
+    source 38
+    target 64
+    value 2
+  ]
+  edge
+  [
+    source 38
+    target 44
+    value 9
+  ]
+  edge
+  [
+    source 40
+    target 41
+    value 1
+  ]
+  edge
+  [
+    source 40
+    target 42
+    value 1
+  ]
+  edge
+  [
+    source 40
+    target 22
+    value 3
+  ]
+  edge
+  [
+    source 40
+    target 43
+    value 6
+  ]
+  edge
+  [
+    source 40
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 41
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 41
+    target 40
+    value 1
+  ]
+  edge
+  [
+    source 41
+    target 23
+    value 3
+  ]
+  edge
+  [
+    source 41
+    target 47
+    value 1
+  ]
+  edge
+  [
+    source 41
+    target 48
+    value 3
+  ]
+  edge
+  [
+    source 41
+    target 43
+    value 4
+  ]
+  edge
+  [
+    source 41
+    target 46
+    value 2
+  ]
+  edge
+  [
+    source 41
+    target 49
+    value 1
+  ]
+  edge
+  [
+    source 41
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 42
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 42
+    target 86
+    value 3
+  ]
+  edge
+  [
+    source 42
+    target 119
+    value 2
+  ]
+  edge
+  [
+    source 42
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 42
+    target 218
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 167
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 232
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 168
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 40
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 45
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 17
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 29
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 185
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 42
+    target 22
+    value 4
+  ]
+  edge
+  [
+    source 42
+    target 33
+    value 3
+  ]
+  edge
+  [
+    source 42
+    target 173
+    value 1
+  ]
+  edge
+  [
+    source 43
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 43
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 43
+    target 35
+    value 6
+  ]
+  edge
+  [
+    source 43
+    target 44
+    value 7
+  ]
+  edge
+  [
+    source 45
+    target 33
+    value 7
+  ]
+  edge
+  [
+    source 45
+    target 46
+    value 8
+  ]
+  edge
+  [
+    source 45
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 46
+    target 23
+    value 10
+  ]
+  edge
+  [
+    source 46
+    target 79
+    value 1
+  ]
+  edge
+  [
+    source 46
+    target 44
+    value 9
+  ]
+  edge
+  [
+    source 47
+    target 31
+    value 1
+  ]
+  edge
+  [
+    source 47
+    target 13
+    value 5
+  ]
+  edge
+  [
+    source 47
+    target 6
+    value 3
+  ]
+  edge
+  [
+    source 47
+    target 35
+    value 1
+  ]
+  edge
+  [
+    source 47
+    target 48
+    value 2
+  ]
+  edge
+  [
+    source 47
+    target 214
+    value 1
+  ]
+  edge
+  [
+    source 47
+    target 44
+    value 11
+  ]
+  edge
+  [
+    source 48
+    target 213
+    value 1
+  ]
+  edge
+  [
+    source 48
+    target 13
+    value 5
+  ]
+  edge
+  [
+    source 48
+    target 6
+    value 7
+  ]
+  edge
+  [
+    source 48
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 48
+    target 47
+    value 1
+  ]
+  edge
+  [
+    source 48
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 49
+    target 44
+    value 14
+  ]
+  edge
+  [
+    source 50
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 50
+    target 45
+    value 1
+  ]
+  edge
+  [
+    source 50
+    target 23
+    value 3
+  ]
+  edge
+  [
+    source 50
+    target 35
+    value 4
+  ]
+  edge
+  [
+    source 50
+    target 47
+    value 4
+  ]
+  edge
+  [
+    source 50
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 50
+    target 43
+    value 1
+  ]
+  edge
+  [
+    source 50
+    target 46
+    value 4
+  ]
+  edge
+  [
+    source 50
+    target 51
+    value 2
+  ]
+  edge
+  [
+    source 50
+    target 52
+    value 1
+  ]
+  edge
+  [
+    source 50
+    target 44
+    value 12
+  ]
+  edge
+  [
+    source 51
+    target 44
+    value 11
+  ]
+  edge
+  [
+    source 52
+    target 99
+    value 4
+  ]
+  edge
+  [
+    source 52
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 52
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 52
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 52
+    target 32
+    value 1
+  ]
+  edge
+  [
+    source 52
+    target 6
+    value 4
+  ]
+  edge
+  [
+    source 52
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 52
+    target 9
+    value 2
+  ]
+  edge
+  [
+    source 52
+    target 33
+    value 3
+  ]
+  edge
+  [
+    source 52
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 52
+    target 37
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 4
+    value 5
+  ]
+  edge
+  [
+    source 53
+    target 17
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 14
+    value 2
+  ]
+  edge
+  [
+    source 53
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 90
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 23
+    value 4
+  ]
+  edge
+  [
+    source 53
+    target 46
+    value 2
+  ]
+  edge
+  [
+    source 53
+    target 78
+    value 1
+  ]
+  edge
+  [
+    source 53
+    target 75
+    value 4
+  ]
+  edge
+  [
+    source 54
+    target 11
+    value 1
+  ]
+  edge
+  [
+    source 54
+    target 40
+    value 7
+  ]
+  edge
+  [
+    source 54
+    target 55
+    value 2
+  ]
+  edge
+  [
+    source 54
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 54
+    target 22
+    value 9
+  ]
+  edge
+  [
+    source 54
+    target 51
+    value 4
+  ]
+  edge
+  [
+    source 54
+    target 49
+    value 4
+  ]
+  edge
+  [
+    source 54
+    target 56
+    value 3
+  ]
+  edge
+  [
+    source 55
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 55
+    target 35
+    value 4
+  ]
+  edge
+  [
+    source 55
+    target 78
+    value 3
+  ]
+  edge
+  [
+    source 56
+    target 40
+    value 2
+  ]
+  edge
+  [
+    source 56
+    target 22
+    value 3
+  ]
+  edge
+  [
+    source 56
+    target 35
+    value 1
+  ]
+  edge
+  [
+    source 56
+    target 51
+    value 1
+  ]
+  edge
+  [
+    source 56
+    target 44
+    value 6
+  ]
+  edge
+  [
+    source 57
+    target 58
+    value 1
+  ]
+  edge
+  [
+    source 57
+    target 45
+    value 7
+  ]
+  edge
+  [
+    source 57
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 57
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 57
+    target 33
+    value 12
+  ]
+  edge
+  [
+    source 57
+    target 60
+    value 1
+  ]
+  edge
+  [
+    source 57
+    target 51
+    value 3
+  ]
+  edge
+  [
+    source 57
+    target 49
+    value 2
+  ]
+  edge
+  [
+    source 57
+    target 61
+    value 3
+  ]
+  edge
+  [
+    source 58
+    target 3
+    value 5
+  ]
+  edge
+  [
+    source 58
+    target 95
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 45
+    value 5
+  ]
+  edge
+  [
+    source 58
+    target 50
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 31
+    value 6
+  ]
+  edge
+  [
+    source 58
+    target 68
+    value 5
+  ]
+  edge
+  [
+    source 58
+    target 7
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 20
+    value 4
+  ]
+  edge
+  [
+    source 58
+    target 21
+    value 2
+  ]
+  edge
+  [
+    source 58
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 46
+    value 2
+  ]
+  edge
+  [
+    source 58
+    target 87
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 24
+    value 4
+  ]
+  edge
+  [
+    source 58
+    target 88
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 61
+    value 1
+  ]
+  edge
+  [
+    source 58
+    target 69
+    value 2
+  ]
+  edge
+  [
+    source 58
+    target 82
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 105
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 102
+    value 5
+  ]
+  edge
+  [
+    source 59
+    target 108
+    value 4
+  ]
+  edge
+  [
+    source 59
+    target 99
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 5
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 71
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 58
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 15
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 27
+    value 2
+  ]
+  edge
+  [
+    source 59
+    target 66
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 55
+    value 3
+  ]
+  edge
+  [
+    source 59
+    target 68
+    value 3
+  ]
+  edge
+  [
+    source 59
+    target 19
+    value 3
+  ]
+  edge
+  [
+    source 59
+    target 32
+    value 7
+  ]
+  edge
+  [
+    source 59
+    target 13
+    value 12
+  ]
+  edge
+  [
+    source 59
+    target 6
+    value 9
+  ]
+  edge
+  [
+    source 59
+    target 14
+    value 5
+  ]
+  edge
+  [
+    source 59
+    target 7
+    value 4
+  ]
+  edge
+  [
+    source 59
+    target 22
+    value 5
+  ]
+  edge
+  [
+    source 59
+    target 33
+    value 5
+  ]
+  edge
+  [
+    source 59
+    target 49
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 64
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 91
+    value 1
+  ]
+  edge
+  [
+    source 59
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 60
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 60
+    target 7
+    value 1
+  ]
+  edge
+  [
+    source 60
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 61
+    target 33
+    value 3
+  ]
+  edge
+  [
+    source 61
+    target 46
+    value 1
+  ]
+  edge
+  [
+    source 61
+    target 60
+    value 1
+  ]
+  edge
+  [
+    source 61
+    target 49
+    value 1
+  ]
+  edge
+  [
+    source 61
+    target 82
+    value 1
+  ]
+  edge
+  [
+    source 61
+    target 44
+    value 6
+  ]
+  edge
+  [
+    source 62
+    target 63
+    value 2
+  ]
+  edge
+  [
+    source 62
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 62
+    target 41
+    value 1
+  ]
+  edge
+  [
+    source 62
+    target 55
+    value 6
+  ]
+  edge
+  [
+    source 62
+    target 19
+    value 8
+  ]
+  edge
+  [
+    source 62
+    target 20
+    value 1
+  ]
+  edge
+  [
+    source 62
+    target 59
+    value 9
+  ]
+  edge
+  [
+    source 62
+    target 47
+    value 3
+  ]
+  edge
+  [
+    source 62
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 62
+    target 49
+    value 2
+  ]
+  edge
+  [
+    source 62
+    target 64
+    value 2
+  ]
+  edge
+  [
+    source 62
+    target 65
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 101
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 2
+    value 3
+  ]
+  edge
+  [
+    source 63
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 225
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 71
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 129
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 41
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 62
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 18
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 215
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 8
+    value 5
+  ]
+  edge
+  [
+    source 63
+    target 9
+    value 6
+  ]
+  edge
+  [
+    source 63
+    target 59
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 34
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 209
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 47
+    value 2
+  ]
+  edge
+  [
+    source 63
+    target 93
+    value 3
+  ]
+  edge
+  [
+    source 63
+    target 24
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 94
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 81
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 63
+    target 83
+    value 1
+  ]
+  edge
+  [
+    source 64
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 64
+    target 44
+    value 5
+  ]
+  edge
+  [
+    source 65
+    target 11
+    value 7
+  ]
+  edge
+  [
+    source 65
+    target 84
+    value 2
+  ]
+  edge
+  [
+    source 65
+    target 3
+    value 3
+  ]
+  edge
+  [
+    source 65
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 65
+    target 13
+    value 8
+  ]
+  edge
+  [
+    source 65
+    target 20
+    value 1
+  ]
+  edge
+  [
+    source 65
+    target 8
+    value 2
+  ]
+  edge
+  [
+    source 66
+    target 67
+    value 2
+  ]
+  edge
+  [
+    source 66
+    target 50
+    value 1
+  ]
+  edge
+  [
+    source 66
+    target 31
+    value 2
+  ]
+  edge
+  [
+    source 66
+    target 68
+    value 1
+  ]
+  edge
+  [
+    source 66
+    target 32
+    value 7
+  ]
+  edge
+  [
+    source 66
+    target 59
+    value 5
+  ]
+  edge
+  [
+    source 66
+    target 47
+    value 1
+  ]
+  edge
+  [
+    source 66
+    target 51
+    value 2
+  ]
+  edge
+  [
+    source 66
+    target 64
+    value 1
+  ]
+  edge
+  [
+    source 66
+    target 38
+    value 1
+  ]
+  edge
+  [
+    source 66
+    target 69
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 63
+    value 2
+  ]
+  edge
+  [
+    source 67
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 67
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 218
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 58
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 129
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 224
+    value 2
+  ]
+  edge
+  [
+    source 67
+    target 31
+    value 2
+  ]
+  edge
+  [
+    source 67
+    target 8
+    value 7
+  ]
+  edge
+  [
+    source 67
+    target 9
+    value 4
+  ]
+  edge
+  [
+    source 67
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 67
+    target 48
+    value 2
+  ]
+  edge
+  [
+    source 67
+    target 87
+    value 2
+  ]
+  edge
+  [
+    source 67
+    target 212
+    value 1
+  ]
+  edge
+  [
+    source 68
+    target 20
+    value 1
+  ]
+  edge
+  [
+    source 68
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 68
+    target 23
+    value 3
+  ]
+  edge
+  [
+    source 68
+    target 36
+    value 1
+  ]
+  edge
+  [
+    source 68
+    target 79
+    value 2
+  ]
+  edge
+  [
+    source 69
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 58
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 50
+    value 3
+  ]
+  edge
+  [
+    source 69
+    target 66
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 47
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 87
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 88
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 37
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 89
+    value 1
+  ]
+  edge
+  [
+    source 69
+    target 52
+    value 7
+  ]
+  edge
+  [
+    source 70
+    target 5
+    value 1
+  ]
+  edge
+  [
+    source 70
+    target 17
+    value 6
+  ]
+  edge
+  [
+    source 70
+    target 19
+    value 1
+  ]
+  edge
+  [
+    source 70
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 70
+    target 59
+    value 2
+  ]
+  edge
+  [
+    source 70
+    target 22
+    value 11
+  ]
+  edge
+  [
+    source 70
+    target 51
+    value 2
+  ]
+  edge
+  [
+    source 70
+    target 49
+    value 5
+  ]
+  edge
+  [
+    source 70
+    target 64
+    value 1
+  ]
+  edge
+  [
+    source 70
+    target 26
+    value 4
+  ]
+  edge
+  [
+    source 71
+    target 4
+    value 5
+  ]
+  edge
+  [
+    source 71
+    target 40
+    value 4
+  ]
+  edge
+  [
+    source 71
+    target 41
+    value 1
+  ]
+  edge
+  [
+    source 71
+    target 18
+    value 2
+  ]
+  edge
+  [
+    source 71
+    target 55
+    value 6
+  ]
+  edge
+  [
+    source 71
+    target 14
+    value 2
+  ]
+  edge
+  [
+    source 71
+    target 20
+    value 1
+  ]
+  edge
+  [
+    source 71
+    target 21
+    value 3
+  ]
+  edge
+  [
+    source 71
+    target 22
+    value 2
+  ]
+  edge
+  [
+    source 71
+    target 90
+    value 1
+  ]
+  edge
+  [
+    source 71
+    target 43
+    value 3
+  ]
+  edge
+  [
+    source 71
+    target 93
+    value 3
+  ]
+  edge
+  [
+    source 71
+    target 36
+    value 4
+  ]
+  edge
+  [
+    source 71
+    target 94
+    value 1
+  ]
+  edge
+  [
+    source 71
+    target 89
+    value 1
+  ]
+  edge
+  [
+    source 71
+    target 56
+    value 2
+  ]
+  edge
+  [
+    source 71
+    target 83
+    value 2
+  ]
+  edge
+  [
+    source 71
+    target 76
+    value 2
+  ]
+  edge
+  [
+    source 72
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 72
+    target 2
+    value 3
+  ]
+  edge
+  [
+    source 72
+    target 18
+    value 1
+  ]
+  edge
+  [
+    source 72
+    target 132
+    value 4
+  ]
+  edge
+  [
+    source 72
+    target 130
+    value 5
+  ]
+  edge
+  [
+    source 72
+    target 214
+    value 1
+  ]
+  edge
+  [
+    source 72
+    target 93
+    value 1
+  ]
+  edge
+  [
+    source 73
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 73
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 73
+    target 75
+    value 1
+  ]
+  edge
+  [
+    source 73
+    target 44
+    value 3
+  ]
+  edge
+  [
+    source 74
+    target 13
+    value 2
+  ]
+  edge
+  [
+    source 74
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 74
+    target 44
+    value 3
+  ]
+  edge
+  [
+    source 75
+    target 13
+    value 8
+  ]
+  edge
+  [
+    source 75
+    target 6
+    value 4
+  ]
+  edge
+  [
+    source 75
+    target 209
+    value 1
+  ]
+  edge
+  [
+    source 75
+    target 23
+    value 2
+  ]
+  edge
+  [
+    source 75
+    target 73
+    value 2
+  ]
+  edge
+  [
+    source 75
+    target 44
+    value 3
+  ]
+  edge
+  [
+    source 76
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 76
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 76
+    target 35
+    value 4
+  ]
+  edge
+  [
+    source 76
+    target 43
+    value 5
+  ]
+  edge
+  [
+    source 76
+    target 73
+    value 1
+  ]
+  edge
+  [
+    source 76
+    target 74
+    value 2
+  ]
+  edge
+  [
+    source 77
+    target 42
+    value 1
+  ]
+  edge
+  [
+    source 77
+    target 13
+    value 3
+  ]
+  edge
+  [
+    source 77
+    target 6
+    value 7
+  ]
+  edge
+  [
+    source 77
+    target 34
+    value 1
+  ]
+  edge
+  [
+    source 77
+    target 35
+    value 1
+  ]
+  edge
+  [
+    source 77
+    target 74
+    value 4
+  ]
+  edge
+  [
+    source 77
+    target 44
+    value 2
+  ]
+  edge
+  [
+    source 78
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 79
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 80
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 81
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 82
+    target 3
+    value 2
+  ]
+  edge
+  [
+    source 82
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 82
+    target 7
+    value 1
+  ]
+  edge
+  [
+    source 82
+    target 23
+    value 2
+  ]
+  edge
+  [
+    source 82
+    target 46
+    value 4
+  ]
+  edge
+  [
+    source 82
+    target 73
+    value 4
+  ]
+  edge
+  [
+    source 82
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 71
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 41
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 35
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 25
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 83
+    target 65
+    value 4
+  ]
+  edge
+  [
+    source 84
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 152
+    value 2
+  ]
+  edge
+  [
+    source 84
+    target 155
+    value 2
+  ]
+  edge
+  [
+    source 84
+    target 156
+    value 2
+  ]
+  edge
+  [
+    source 84
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 158
+    value 2
+  ]
+  edge
+  [
+    source 84
+    target 2
+    value 25
+  ]
+  edge
+  [
+    source 84
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 84
+    target 118
+    value 3
+  ]
+  edge
+  [
+    source 84
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 84
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 163
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 175
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 180
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 188
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 84
+    target 190
+    value 6
+  ]
+  edge
+  [
+    source 85
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 85
+    target 60
+    value 3
+  ]
+  edge
+  [
+    source 85
+    target 211
+    value 2
+  ]
+  edge
+  [
+    source 85
+    target 44
+    value 9
+  ]
+  edge
+  [
+    source 86
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 152
+    value 2
+  ]
+  edge
+  [
+    source 86
+    target 155
+    value 2
+  ]
+  edge
+  [
+    source 86
+    target 156
+    value 2
+  ]
+  edge
+  [
+    source 86
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 158
+    value 2
+  ]
+  edge
+  [
+    source 86
+    target 12
+    value 25
+  ]
+  edge
+  [
+    source 86
+    target 84
+    value 2
+  ]
+  edge
+  [
+    source 86
+    target 117
+    value 3
+  ]
+  edge
+  [
+    source 86
+    target 3
+    value 3
+  ]
+  edge
+  [
+    source 86
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 163
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 175
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 180
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 188
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 86
+    target 190
+    value 6
+  ]
+  edge
+  [
+    source 87
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 236
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 109
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 87
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 103
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 47
+    value 3
+  ]
+  edge
+  [
+    source 87
+    target 48
+    value 3
+  ]
+  edge
+  [
+    source 87
+    target 43
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 46
+    value 4
+  ]
+  edge
+  [
+    source 87
+    target 52
+    value 1
+  ]
+  edge
+  [
+    source 87
+    target 44
+    value 3
+  ]
+  edge
+  [
+    source 88
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 89
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 89
+    target 60
+    value 4
+  ]
+  edge
+  [
+    source 89
+    target 212
+    value 2
+  ]
+  edge
+  [
+    source 89
+    target 44
+    value 9
+  ]
+  edge
+  [
+    source 90
+    target 3
+    value 8
+  ]
+  edge
+  [
+    source 90
+    target 4
+    value 6
+  ]
+  edge
+  [
+    source 90
+    target 213
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 218
+    value 3
+  ]
+  edge
+  [
+    source 90
+    target 187
+    value 2
+  ]
+  edge
+  [
+    source 90
+    target 71
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 58
+    value 2
+  ]
+  edge
+  [
+    source 90
+    target 15
+    value 2
+  ]
+  edge
+  [
+    source 90
+    target 27
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 31
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 14
+    value 3
+  ]
+  edge
+  [
+    source 90
+    target 7
+    value 6
+  ]
+  edge
+  [
+    source 90
+    target 132
+    value 2
+  ]
+  edge
+  [
+    source 90
+    target 130
+    value 4
+  ]
+  edge
+  [
+    source 90
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 47
+    value 2
+  ]
+  edge
+  [
+    source 90
+    target 48
+    value 5
+  ]
+  edge
+  [
+    source 90
+    target 73
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 77
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 75
+    value 1
+  ]
+  edge
+  [
+    source 90
+    target 91
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 3
+    value 6
+  ]
+  edge
+  [
+    source 91
+    target 29
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 7
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 35
+    value 4
+  ]
+  edge
+  [
+    source 91
+    target 43
+    value 3
+  ]
+  edge
+  [
+    source 91
+    target 78
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 79
+    value 1
+  ]
+  edge
+  [
+    source 91
+    target 77
+    value 3
+  ]
+  edge
+  [
+    source 92
+    target 3
+    value 2
+  ]
+  edge
+  [
+    source 92
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 92
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 92
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 92
+    target 39
+    value 2
+  ]
+  edge
+  [
+    source 93
+    target 101
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 216
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 235
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 141
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 93
+    target 3
+    value 2
+  ]
+  edge
+  [
+    source 93
+    target 71
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 47
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 48
+    value 3
+  ]
+  edge
+  [
+    source 93
+    target 43
+    value 4
+  ]
+  edge
+  [
+    source 93
+    target 36
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 25
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 78
+    value 2
+  ]
+  edge
+  [
+    source 93
+    target 104
+    value 2
+  ]
+  edge
+  [
+    source 93
+    target 65
+    value 1
+  ]
+  edge
+  [
+    source 93
+    target 44
+    value 5
+  ]
+  edge
+  [
+    source 94
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 63
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 67
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 240
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 95
+    target 198
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 119
+    value 2
+  ]
+  edge
+  [
+    source 95
+    target 142
+    value 7
+  ]
+  edge
+  [
+    source 95
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 95
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 95
+    target 207
+    value 4
+  ]
+  edge
+  [
+    source 95
+    target 204
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 72
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 241
+    value 1
+  ]
+  edge
+  [
+    source 95
+    target 61
+    value 1
+  ]
+  edge
+  [
+    source 96
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 96
+    target 60
+    value 1
+  ]
+  edge
+  [
+    source 96
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 97
+    target 166
+    value 2
+  ]
+  edge
+  [
+    source 97
+    target 227
+    value 1
+  ]
+  edge
+  [
+    source 97
+    target 221
+    value 1
+  ]
+  edge
+  [
+    source 97
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 98
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 98
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 98
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 118
+    value 4
+  ]
+  edge
+  [
+    source 98
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 98
+    target 202
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 198
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 206
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 98
+    target 172
+    value 4
+  ]
+  edge
+  [
+    source 98
+    target 207
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 98
+    target 186
+    value 1
+  ]
+  edge
+  [
+    source 99
+    target 107
+    value 1
+  ]
+  edge
+  [
+    source 99
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 99
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 99
+    target 6
+    value 10
+  ]
+  edge
+  [
+    source 99
+    target 7
+    value 12
+  ]
+  edge
+  [
+    source 99
+    target 52
+    value 1
+  ]
+  edge
+  [
+    source 100
+    target 101
+    value 1
+  ]
+  edge
+  [
+    source 100
+    target 102
+    value 11
+  ]
+  edge
+  [
+    source 100
+    target 11
+    value 3
+  ]
+  edge
+  [
+    source 100
+    target 19
+    value 1
+  ]
+  edge
+  [
+    source 100
+    target 13
+    value 12
+  ]
+  edge
+  [
+    source 100
+    target 103
+    value 2
+  ]
+  edge
+  [
+    source 100
+    target 104
+    value 2
+  ]
+  edge
+  [
+    source 101
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 101
+    target 114
+    value 2
+  ]
+  edge
+  [
+    source 101
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 101
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 101
+    target 86
+    value 5
+  ]
+  edge
+  [
+    source 101
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 101
+    target 98
+    value 4
+  ]
+  edge
+  [
+    source 101
+    target 224
+    value 1
+  ]
+  edge
+  [
+    source 101
+    target 132
+    value 3
+  ]
+  edge
+  [
+    source 101
+    target 22
+    value 1
+  ]
+  edge
+  [
+    source 101
+    target 22
+    value 1
+  ]
+  edge
+  [
+    source 101
+    target 77
+    value 2
+  ]
+  edge
+  [
+    source 102
+    target 100
+    value 2
+  ]
+  edge
+  [
+    source 102
+    target 113
+    value 2
+  ]
+  edge
+  [
+    source 102
+    target 1
+    value 4
+  ]
+  edge
+  [
+    source 102
+    target 114
+    value 7
+  ]
+  edge
+  [
+    source 102
+    target 135
+    value 1
+  ]
+  edge
+  [
+    source 102
+    target 136
+    value 1
+  ]
+  edge
+  [
+    source 102
+    target 4
+    value 4
+  ]
+  edge
+  [
+    source 102
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 102
+    target 13
+    value 7
+  ]
+  edge
+  [
+    source 102
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 102
+    target 132
+    value 3
+  ]
+  edge
+  [
+    source 102
+    target 89
+    value 4
+  ]
+  edge
+  [
+    source 102
+    target 104
+    value 7
+  ]
+  edge
+  [
+    source 103
+    target 102
+    value 6
+  ]
+  edge
+  [
+    source 103
+    target 108
+    value 5
+  ]
+  edge
+  [
+    source 103
+    target 201
+    value 1
+  ]
+  edge
+  [
+    source 103
+    target 11
+    value 1
+  ]
+  edge
+  [
+    source 103
+    target 5
+    value 1
+  ]
+  edge
+  [
+    source 103
+    target 137
+    value 3
+  ]
+  edge
+  [
+    source 103
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 103
+    target 13
+    value 6
+  ]
+  edge
+  [
+    source 103
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 103
+    target 65
+    value 5
+  ]
+  edge
+  [
+    source 103
+    target 52
+    value 2
+  ]
+  edge
+  [
+    source 104
+    target 222
+    value 1
+  ]
+  edge
+  [
+    source 104
+    target 64
+    value 5
+  ]
+  edge
+  [
+    source 104
+    target 131
+    value 3
+  ]
+  edge
+  [
+    source 104
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 105
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 105
+    target 107
+    value 1
+  ]
+  edge
+  [
+    source 105
+    target 108
+    value 8
+  ]
+  edge
+  [
+    source 105
+    target 109
+    value 1
+  ]
+  edge
+  [
+    source 105
+    target 99
+    value 3
+  ]
+  edge
+  [
+    source 105
+    target 110
+    value 2
+  ]
+  edge
+  [
+    source 105
+    target 111
+    value 1
+  ]
+  edge
+  [
+    source 105
+    target 6
+    value 12
+  ]
+  edge
+  [
+    source 105
+    target 9
+    value 2
+  ]
+  edge
+  [
+    source 105
+    target 103
+    value 3
+  ]
+  edge
+  [
+    source 105
+    target 89
+    value 1
+  ]
+  edge
+  [
+    source 105
+    target 112
+    value 2
+  ]
+  edge
+  [
+    source 105
+    target 52
+    value 1
+  ]
+  edge
+  [
+    source 106
+    target 84
+    value 3
+  ]
+  edge
+  [
+    source 106
+    target 86
+    value 4
+  ]
+  edge
+  [
+    source 106
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 106
+    target 119
+    value 3
+  ]
+  edge
+  [
+    source 106
+    target 130
+    value 4
+  ]
+  edge
+  [
+    source 106
+    target 33
+    value 1
+  ]
+  edge
+  [
+    source 106
+    target 209
+    value 1
+  ]
+  edge
+  [
+    source 106
+    target 75
+    value 2
+  ]
+  edge
+  [
+    source 107
+    target 105
+    value 1
+  ]
+  edge
+  [
+    source 107
+    target 108
+    value 6
+  ]
+  edge
+  [
+    source 107
+    target 139
+    value 1
+  ]
+  edge
+  [
+    source 107
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 107
+    target 6
+    value 4
+  ]
+  edge
+  [
+    source 107
+    target 7
+    value 4
+  ]
+  edge
+  [
+    source 108
+    target 122
+    value 1
+  ]
+  edge
+  [
+    source 108
+    target 1
+    value 9
+  ]
+  edge
+  [
+    source 108
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 108
+    target 3
+    value 4
+  ]
+  edge
+  [
+    source 108
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 108
+    target 137
+    value 2
+  ]
+  edge
+  [
+    source 108
+    target 6
+    value 7
+  ]
+  edge
+  [
+    source 108
+    target 130
+    value 4
+  ]
+  edge
+  [
+    source 108
+    target 85
+    value 5
+  ]
+  edge
+  [
+    source 108
+    target 112
+    value 3
+  ]
+  edge
+  [
+    source 109
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 109
+    target 105
+    value 2
+  ]
+  edge
+  [
+    source 109
+    target 122
+    value 9
+  ]
+  edge
+  [
+    source 109
+    target 114
+    value 3
+  ]
+  edge
+  [
+    source 109
+    target 2
+    value 5
+  ]
+  edge
+  [
+    source 109
+    target 86
+    value 3
+  ]
+  edge
+  [
+    source 109
+    target 117
+    value 5
+  ]
+  edge
+  [
+    source 109
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 109
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 109
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 109
+    target 111
+    value 1
+  ]
+  edge
+  [
+    source 109
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 109
+    target 87
+    value 2
+  ]
+  edge
+  [
+    source 110
+    target 105
+    value 4
+  ]
+  edge
+  [
+    source 110
+    target 108
+    value 4
+  ]
+  edge
+  [
+    source 110
+    target 28
+    value 1
+  ]
+  edge
+  [
+    source 110
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 110
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 110
+    target 103
+    value 2
+  ]
+  edge
+  [
+    source 110
+    target 112
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 105
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 201
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 111
+    target 84
+    value 3
+  ]
+  edge
+  [
+    source 111
+    target 86
+    value 7
+  ]
+  edge
+  [
+    source 111
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 198
+    value 3
+  ]
+  edge
+  [
+    source 111
+    target 187
+    value 4
+  ]
+  edge
+  [
+    source 111
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 193
+    value 2
+  ]
+  edge
+  [
+    source 111
+    target 125
+    value 5
+  ]
+  edge
+  [
+    source 111
+    target 172
+    value 7
+  ]
+  edge
+  [
+    source 111
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 111
+    target 9
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 111
+    target 190
+    value 3
+  ]
+  edge
+  [
+    source 112
+    target 223
+    value 3
+  ]
+  edge
+  [
+    source 112
+    target 64
+    value 3
+  ]
+  edge
+  [
+    source 112
+    target 72
+    value 4
+  ]
+  edge
+  [
+    source 112
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 113
+    target 101
+    value 1
+  ]
+  edge
+  [
+    source 113
+    target 1
+    value 11
+  ]
+  edge
+  [
+    source 113
+    target 149
+    value 2
+  ]
+  edge
+  [
+    source 113
+    target 102
+    value 2
+  ]
+  edge
+  [
+    source 113
+    target 115
+    value 2
+  ]
+  edge
+  [
+    source 113
+    target 140
+    value 1
+  ]
+  edge
+  [
+    source 113
+    target 141
+    value 3
+  ]
+  edge
+  [
+    source 113
+    target 124
+    value 1
+  ]
+  edge
+  [
+    source 113
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 113
+    target 215
+    value 1
+  ]
+  edge
+  [
+    source 114
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 114
+    target 86
+    value 3
+  ]
+  edge
+  [
+    source 114
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 114
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 114
+    target 14
+    value 4
+  ]
+  edge
+  [
+    source 114
+    target 132
+    value 14
+  ]
+  edge
+  [
+    source 114
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 114
+    target 131
+    value 1
+  ]
+  edge
+  [
+    source 114
+    target 73
+    value 3
+  ]
+  edge
+  [
+    source 114
+    target 133
+    value 1
+  ]
+  edge
+  [
+    source 115
+    target 126
+    value 3
+  ]
+  edge
+  [
+    source 115
+    target 128
+    value 1
+  ]
+  edge
+  [
+    source 115
+    target 113
+    value 4
+  ]
+  edge
+  [
+    source 115
+    target 122
+    value 3
+  ]
+  edge
+  [
+    source 115
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 115
+    target 114
+    value 7
+  ]
+  edge
+  [
+    source 115
+    target 10
+    value 4
+  ]
+  edge
+  [
+    source 115
+    target 107
+    value 12
+  ]
+  edge
+  [
+    source 115
+    target 139
+    value 1
+  ]
+  edge
+  [
+    source 115
+    target 138
+    value 1
+  ]
+  edge
+  [
+    source 115
+    target 124
+    value 2
+  ]
+  edge
+  [
+    source 116
+    target 100
+    value 3
+  ]
+  edge
+  [
+    source 116
+    target 113
+    value 7
+  ]
+  edge
+  [
+    source 116
+    target 1
+    value 5
+  ]
+  edge
+  [
+    source 116
+    target 141
+    value 1
+  ]
+  edge
+  [
+    source 116
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 116
+    target 84
+    value 6
+  ]
+  edge
+  [
+    source 116
+    target 117
+    value 2
+  ]
+  edge
+  [
+    source 116
+    target 118
+    value 4
+  ]
+  edge
+  [
+    source 116
+    target 13
+    value 4
+  ]
+  edge
+  [
+    source 116
+    target 132
+    value 1
+  ]
+  edge
+  [
+    source 116
+    target 22
+    value 1
+  ]
+  edge
+  [
+    source 116
+    target 103
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 152
+    value 2
+  ]
+  edge
+  [
+    source 117
+    target 153
+    value 2
+  ]
+  edge
+  [
+    source 117
+    target 156
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 12
+    value 70
+  ]
+  edge
+  [
+    source 117
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 118
+    value 2
+  ]
+  edge
+  [
+    source 117
+    target 159
+    value 3
+  ]
+  edge
+  [
+    source 117
+    target 160
+    value 2
+  ]
+  edge
+  [
+    source 117
+    target 161
+    value 6
+  ]
+  edge
+  [
+    source 117
+    target 162
+    value 4
+  ]
+  edge
+  [
+    source 117
+    target 163
+    value 3
+  ]
+  edge
+  [
+    source 117
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 167
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 192
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 193
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 170
+    value 3
+  ]
+  edge
+  [
+    source 117
+    target 194
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 173
+    value 3
+  ]
+  edge
+  [
+    source 117
+    target 186
+    value 6
+  ]
+  edge
+  [
+    source 117
+    target 176
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 178
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 179
+    value 3
+  ]
+  edge
+  [
+    source 117
+    target 181
+    value 1
+  ]
+  edge
+  [
+    source 117
+    target 182
+    value 2
+  ]
+  edge
+  [
+    source 118
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 152
+    value 2
+  ]
+  edge
+  [
+    source 118
+    target 153
+    value 2
+  ]
+  edge
+  [
+    source 118
+    target 156
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 2
+    value 70
+  ]
+  edge
+  [
+    source 118
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 117
+    value 2
+  ]
+  edge
+  [
+    source 118
+    target 159
+    value 3
+  ]
+  edge
+  [
+    source 118
+    target 160
+    value 2
+  ]
+  edge
+  [
+    source 118
+    target 161
+    value 6
+  ]
+  edge
+  [
+    source 118
+    target 162
+    value 4
+  ]
+  edge
+  [
+    source 118
+    target 163
+    value 3
+  ]
+  edge
+  [
+    source 118
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 167
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 192
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 193
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 184
+    value 3
+  ]
+  edge
+  [
+    source 118
+    target 194
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 173
+    value 3
+  ]
+  edge
+  [
+    source 118
+    target 174
+    value 6
+  ]
+  edge
+  [
+    source 118
+    target 176
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 178
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 179
+    value 3
+  ]
+  edge
+  [
+    source 118
+    target 181
+    value 1
+  ]
+  edge
+  [
+    source 118
+    target 182
+    value 2
+  ]
+  edge
+  [
+    source 119
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 119
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 86
+    value 5
+  ]
+  edge
+  [
+    source 119
+    target 117
+    value 3
+  ]
+  edge
+  [
+    source 119
+    target 4
+    value 4
+  ]
+  edge
+  [
+    source 119
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 123
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 172
+    value 3
+  ]
+  edge
+  [
+    source 119
+    target 204
+    value 2
+  ]
+  edge
+  [
+    source 119
+    target 148
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 205
+    value 1
+  ]
+  edge
+  [
+    source 119
+    target 90
+    value 2
+  ]
+  edge
+  [
+    source 119
+    target 174
+    value 1
+  ]
+  edge
+  [
+    source 120
+    target 100
+    value 8
+  ]
+  edge
+  [
+    source 120
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 120
+    target 102
+    value 7
+  ]
+  edge
+  [
+    source 120
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 120
+    target 13
+    value 3
+  ]
+  edge
+  [
+    source 120
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 121
+    target 122
+    value 10
+  ]
+  edge
+  [
+    source 121
+    target 114
+    value 11
+  ]
+  edge
+  [
+    source 121
+    target 115
+    value 1
+  ]
+  edge
+  [
+    source 121
+    target 109
+    value 3
+  ]
+  edge
+  [
+    source 121
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 121
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 121
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 121
+    target 117
+    value 5
+  ]
+  edge
+  [
+    source 121
+    target 118
+    value 2
+  ]
+  edge
+  [
+    source 121
+    target 123
+    value 1
+  ]
+  edge
+  [
+    source 121
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 121
+    target 124
+    value 3
+  ]
+  edge
+  [
+    source 121
+    target 31
+    value 1
+  ]
+  edge
+  [
+    source 121
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 121
+    target 20
+    value 1
+  ]
+  edge
+  [
+    source 121
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 121
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 114
+    value 12
+  ]
+  edge
+  [
+    source 122
+    target 108
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 115
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 139
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 124
+    value 1
+  ]
+  edge
+  [
+    source 122
+    target 205
+    value 2
+  ]
+  edge
+  [
+    source 123
+    target 121
+    value 2
+  ]
+  edge
+  [
+    source 123
+    target 201
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 202
+    value 5
+  ]
+  edge
+  [
+    source 123
+    target 198
+    value 2
+  ]
+  edge
+  [
+    source 123
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 123
+    target 203
+    value 4
+  ]
+  edge
+  [
+    source 123
+    target 145
+    value 2
+  ]
+  edge
+  [
+    source 123
+    target 8
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 103
+    value 3
+  ]
+  edge
+  [
+    source 123
+    target 89
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 104
+    value 1
+  ]
+  edge
+  [
+    source 123
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 124
+    target 121
+    value 1
+  ]
+  edge
+  [
+    source 124
+    target 122
+    value 2
+  ]
+  edge
+  [
+    source 124
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 124
+    target 114
+    value 3
+  ]
+  edge
+  [
+    source 124
+    target 10
+    value 4
+  ]
+  edge
+  [
+    source 124
+    target 107
+    value 9
+  ]
+  edge
+  [
+    source 124
+    target 138
+    value 2
+  ]
+  edge
+  [
+    source 125
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 154
+    value 2
+  ]
+  edge
+  [
+    source 125
+    target 12
+    value 7
+  ]
+  edge
+  [
+    source 125
+    target 2
+    value 9
+  ]
+  edge
+  [
+    source 125
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 125
+    target 86
+    value 16
+  ]
+  edge
+  [
+    source 125
+    target 117
+    value 3
+  ]
+  edge
+  [
+    source 125
+    target 118
+    value 6
+  ]
+  edge
+  [
+    source 125
+    target 3
+    value 2
+  ]
+  edge
+  [
+    source 125
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 119
+    value 3
+  ]
+  edge
+  [
+    source 125
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 160
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 232
+    value 4
+  ]
+  edge
+  [
+    source 125
+    target 168
+    value 5
+  ]
+  edge
+  [
+    source 125
+    target 192
+    value 7
+  ]
+  edge
+  [
+    source 125
+    target 169
+    value 3
+  ]
+  edge
+  [
+    source 125
+    target 253
+    value 4
+  ]
+  edge
+  [
+    source 125
+    target 137
+    value 4
+  ]
+  edge
+  [
+    source 125
+    target 184
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 171
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 172
+    value 3
+  ]
+  edge
+  [
+    source 125
+    target 42
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 256
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 96
+    value 5
+  ]
+  edge
+  [
+    source 125
+    target 90
+    value 2
+  ]
+  edge
+  [
+    source 125
+    target 78
+    value 2
+  ]
+  edge
+  [
+    source 125
+    target 254
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 262
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 263
+    value 4
+  ]
+  edge
+  [
+    source 125
+    target 264
+    value 1
+  ]
+  edge
+  [
+    source 125
+    target 265
+    value 5
+  ]
+  edge
+  [
+    source 125
+    target 266
+    value 3
+  ]
+  edge
+  [
+    source 125
+    target 267
+    value 2
+  ]
+  edge
+  [
+    source 126
+    target 127
+    value 1
+  ]
+  edge
+  [
+    source 126
+    target 10
+    value 7
+  ]
+  edge
+  [
+    source 127
+    target 126
+    value 5
+  ]
+  edge
+  [
+    source 127
+    target 113
+    value 2
+  ]
+  edge
+  [
+    source 127
+    target 1
+    value 2
+  ]
+  edge
+  [
+    source 127
+    target 115
+    value 3
+  ]
+  edge
+  [
+    source 127
+    target 5
+    value 3
+  ]
+  edge
+  [
+    source 127
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 127
+    target 96
+    value 1
+  ]
+  edge
+  [
+    source 127
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 128
+    target 107
+    value 11
+  ]
+  edge
+  [
+    source 128
+    target 115
+    value 1
+  ]
+  edge
+  [
+    source 129
+    target 63
+    value 1
+  ]
+  edge
+  [
+    source 129
+    target 67
+    value 2
+  ]
+  edge
+  [
+    source 129
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 129
+    target 114
+    value 2
+  ]
+  edge
+  [
+    source 129
+    target 12
+    value 13
+  ]
+  edge
+  [
+    source 129
+    target 2
+    value 18
+  ]
+  edge
+  [
+    source 129
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 129
+    target 86
+    value 5
+  ]
+  edge
+  [
+    source 129
+    target 117
+    value 6
+  ]
+  edge
+  [
+    source 129
+    target 118
+    value 14
+  ]
+  edge
+  [
+    source 129
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 129
+    target 224
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 106
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 1
+    value 4
+  ]
+  edge
+  [
+    source 130
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 130
+    target 84
+    value 2
+  ]
+  edge
+  [
+    source 130
+    target 86
+    value 5
+  ]
+  edge
+  [
+    source 130
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 213
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 7
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 90
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 47
+    value 2
+  ]
+  edge
+  [
+    source 130
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 130
+    target 210
+    value 2
+  ]
+  edge
+  [
+    source 130
+    target 211
+    value 3
+  ]
+  edge
+  [
+    source 130
+    target 212
+    value 3
+  ]
+  edge
+  [
+    source 130
+    target 73
+    value 2
+  ]
+  edge
+  [
+    source 130
+    target 74
+    value 3
+  ]
+  edge
+  [
+    source 130
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 131
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 131
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 131
+    target 132
+    value 3
+  ]
+  edge
+  [
+    source 131
+    target 130
+    value 5
+  ]
+  edge
+  [
+    source 131
+    target 93
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 84
+    value 2
+  ]
+  edge
+  [
+    source 132
+    target 86
+    value 3
+  ]
+  edge
+  [
+    source 132
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 90
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 47
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 48
+    value 3
+  ]
+  edge
+  [
+    source 132
+    target 210
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 72
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 211
+    value 3
+  ]
+  edge
+  [
+    source 132
+    target 212
+    value 2
+  ]
+  edge
+  [
+    source 132
+    target 74
+    value 5
+  ]
+  edge
+  [
+    source 132
+    target 77
+    value 1
+  ]
+  edge
+  [
+    source 132
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 133
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 132
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 214
+    value 2
+  ]
+  edge
+  [
+    source 133
+    target 131
+    value 9
+  ]
+  edge
+  [
+    source 133
+    target 72
+    value 4
+  ]
+  edge
+  [
+    source 133
+    target 173
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 196
+    value 3
+  ]
+  edge
+  [
+    source 133
+    target 178
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 179
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 200
+    value 2
+  ]
+  edge
+  [
+    source 133
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 133
+    target 44
+    value 5
+  ]
+  edge
+  [
+    source 134
+    target 128
+    value 5
+  ]
+  edge
+  [
+    source 134
+    target 135
+    value 2
+  ]
+  edge
+  [
+    source 134
+    target 28
+    value 1
+  ]
+  edge
+  [
+    source 134
+    target 99
+    value 1
+  ]
+  edge
+  [
+    source 134
+    target 0
+    value 3
+  ]
+  edge
+  [
+    source 134
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 134
+    target 7
+    value 2
+  ]
+  edge
+  [
+    source 134
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 135
+    target 105
+    value 1
+  ]
+  edge
+  [
+    source 135
+    target 113
+    value 4
+  ]
+  edge
+  [
+    source 135
+    target 1
+    value 7
+  ]
+  edge
+  [
+    source 135
+    target 114
+    value 3
+  ]
+  edge
+  [
+    source 135
+    target 10
+    value 12
+  ]
+  edge
+  [
+    source 135
+    target 107
+    value 6
+  ]
+  edge
+  [
+    source 135
+    target 138
+    value 4
+  ]
+  edge
+  [
+    source 135
+    target 124
+    value 2
+  ]
+  edge
+  [
+    source 135
+    target 6
+    value 1
+  ]
+  edge
+  [
+    source 136
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 136
+    target 10
+    value 2
+  ]
+  edge
+  [
+    source 136
+    target 102
+    value 1
+  ]
+  edge
+  [
+    source 136
+    target 135
+    value 1
+  ]
+  edge
+  [
+    source 136
+    target 115
+    value 1
+  ]
+  edge
+  [
+    source 136
+    target 141
+    value 2
+  ]
+  edge
+  [
+    source 136
+    target 138
+    value 2
+  ]
+  edge
+  [
+    source 136
+    target 124
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 102
+    value 3
+  ]
+  edge
+  [
+    source 137
+    target 201
+    value 3
+  ]
+  edge
+  [
+    source 137
+    target 11
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 99
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 12
+    value 3
+  ]
+  edge
+  [
+    source 137
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 3
+    value 8
+  ]
+  edge
+  [
+    source 137
+    target 4
+    value 6
+  ]
+  edge
+  [
+    source 137
+    target 232
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 168
+    value 3
+  ]
+  edge
+  [
+    source 137
+    target 192
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 169
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 253
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 185
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 125
+    value 5
+  ]
+  edge
+  [
+    source 137
+    target 42
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 13
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 103
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 72
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 211
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 212
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 89
+    value 3
+  ]
+  edge
+  [
+    source 137
+    target 85
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 104
+    value 3
+  ]
+  edge
+  [
+    source 137
+    target 112
+    value 2
+  ]
+  edge
+  [
+    source 137
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 133
+    value 1
+  ]
+  edge
+  [
+    source 137
+    target 254
+    value 2
+  ]
+  edge
+  [
+    source 138
+    target 113
+    value 2
+  ]
+  edge
+  [
+    source 138
+    target 122
+    value 4
+  ]
+  edge
+  [
+    source 138
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 138
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 138
+    target 10
+    value 13
+  ]
+  edge
+  [
+    source 138
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 138
+    target 13
+    value 2
+  ]
+  edge
+  [
+    source 139
+    target 105
+    value 3
+  ]
+  edge
+  [
+    source 139
+    target 128
+    value 9
+  ]
+  edge
+  [
+    source 139
+    target 107
+    value 2
+  ]
+  edge
+  [
+    source 139
+    target 108
+    value 7
+  ]
+  edge
+  [
+    source 139
+    target 135
+    value 1
+  ]
+  edge
+  [
+    source 139
+    target 115
+    value 2
+  ]
+  edge
+  [
+    source 139
+    target 110
+    value 2
+  ]
+  edge
+  [
+    source 139
+    target 205
+    value 2
+  ]
+  edge
+  [
+    source 139
+    target 103
+    value 1
+  ]
+  edge
+  [
+    source 140
+    target 113
+    value 9
+  ]
+  edge
+  [
+    source 140
+    target 1
+    value 3
+  ]
+  edge
+  [
+    source 140
+    target 127
+    value 1
+  ]
+  edge
+  [
+    source 140
+    target 141
+    value 1
+  ]
+  edge
+  [
+    source 141
+    target 113
+    value 11
+  ]
+  edge
+  [
+    source 141
+    target 1
+    value 3
+  ]
+  edge
+  [
+    source 141
+    target 149
+    value 2
+  ]
+  edge
+  [
+    source 141
+    target 144
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 102
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 108
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 116
+    value 2
+  ]
+  edge
+  [
+    source 142
+    target 117
+    value 3
+  ]
+  edge
+  [
+    source 142
+    target 202
+    value 2
+  ]
+  edge
+  [
+    source 142
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 120
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 95
+    value 2
+  ]
+  edge
+  [
+    source 142
+    target 163
+    value 2
+  ]
+  edge
+  [
+    source 142
+    target 164
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 169
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 204
+    value 2
+  ]
+  edge
+  [
+    source 142
+    target 148
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 205
+    value 3
+  ]
+  edge
+  [
+    source 142
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 87
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 173
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 186
+    value 3
+  ]
+  edge
+  [
+    source 142
+    target 181
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 182
+    value 1
+  ]
+  edge
+  [
+    source 142
+    target 238
+    value 4
+  ]
+  edge
+  [
+    source 142
+    target 245
+    value 2
+  ]
+  edge
+  [
+    source 142
+    target 244
+    value 5
+  ]
+  edge
+  [
+    source 142
+    target 44
+    value 3
+  ]
+  edge
+  [
+    source 142
+    target 44
+    value 21
+  ]
+  edge
+  [
+    source 143
+    target 122
+    value 3
+  ]
+  edge
+  [
+    source 143
+    target 135
+    value 2
+  ]
+  edge
+  [
+    source 143
+    target 109
+    value 1
+  ]
+  edge
+  [
+    source 143
+    target 138
+    value 1
+  ]
+  edge
+  [
+    source 143
+    target 124
+    value 2
+  ]
+  edge
+  [
+    source 144
+    target 141
+    value 4
+  ]
+  edge
+  [
+    source 144
+    target 145
+    value 13
+  ]
+  edge
+  [
+    source 145
+    target 113
+    value 6
+  ]
+  edge
+  [
+    source 145
+    target 144
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 141
+    value 4
+  ]
+  edge
+  [
+    source 145
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 193
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 191
+    value 3
+  ]
+  edge
+  [
+    source 145
+    target 93
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 145
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 146
+    target 147
+    value 4
+  ]
+  edge
+  [
+    source 146
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 146
+    target 148
+    value 13
+  ]
+  edge
+  [
+    source 147
+    target 122
+    value 11
+  ]
+  edge
+  [
+    source 147
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 147
+    target 150
+    value 1
+  ]
+  edge
+  [
+    source 147
+    target 139
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 122
+    value 7
+  ]
+  edge
+  [
+    source 148
+    target 147
+    value 4
+  ]
+  edge
+  [
+    source 148
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 193
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 205
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 148
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 113
+    value 5
+  ]
+  edge
+  [
+    source 149
+    target 216
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 140
+    value 2
+  ]
+  edge
+  [
+    source 149
+    target 141
+    value 2
+  ]
+  edge
+  [
+    source 149
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 149
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 202
+    value 4
+  ]
+  edge
+  [
+    source 149
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 198
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 123
+    value 2
+  ]
+  edge
+  [
+    source 149
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 215
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 104
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 149
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 150
+    target 122
+    value 4
+  ]
+  edge
+  [
+    source 150
+    target 28
+    value 2
+  ]
+  edge
+  [
+    source 150
+    target 146
+    value 2
+  ]
+  edge
+  [
+    source 150
+    target 147
+    value 2
+  ]
+  edge
+  [
+    source 150
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 150
+    target 202
+    value 3
+  ]
+  edge
+  [
+    source 150
+    target 199
+    value 2
+  ]
+  edge
+  [
+    source 150
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 150
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 150
+    target 142
+    value 2
+  ]
+  edge
+  [
+    source 150
+    target 205
+    value 1
+  ]
+  edge
+  [
+    source 150
+    target 87
+    value 2
+  ]
+  edge
+  [
+    source 150
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 151
+    target 159
+    value 1
+  ]
+  edge
+  [
+    source 151
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 151
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 152
+    target 165
+    value 1
+  ]
+  edge
+  [
+    source 152
+    target 249
+    value 16
+  ]
+  edge
+  [
+    source 152
+    target 268
+    value 2
+  ]
+  edge
+  [
+    source 152
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 153
+    target 161
+    value 1
+  ]
+  edge
+  [
+    source 153
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 153
+    target 167
+    value 1
+  ]
+  edge
+  [
+    source 153
+    target 249
+    value 2
+  ]
+  edge
+  [
+    source 153
+    target 227
+    value 16
+  ]
+  edge
+  [
+    source 153
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 154
+    target 160
+    value 1
+  ]
+  edge
+  [
+    source 154
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 154
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 155
+    target 161
+    value 1
+  ]
+  edge
+  [
+    source 155
+    target 197
+    value 2
+  ]
+  edge
+  [
+    source 155
+    target 189
+    value 16
+  ]
+  edge
+  [
+    source 155
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 156
+    target 189
+    value 2
+  ]
+  edge
+  [
+    source 156
+    target 231
+    value 16
+  ]
+  edge
+  [
+    source 156
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 157
+    target 162
+    value 1
+  ]
+  edge
+  [
+    source 157
+    target 231
+    value 2
+  ]
+  edge
+  [
+    source 157
+    target 234
+    value 16
+  ]
+  edge
+  [
+    source 157
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 158
+    target 163
+    value 1
+  ]
+  edge
+  [
+    source 158
+    target 234
+    value 2
+  ]
+  edge
+  [
+    source 158
+    target 269
+    value 16
+  ]
+  edge
+  [
+    source 158
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 159
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 159
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 159
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 160
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 160
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 160
+    target 197
+    value 23
+  ]
+  edge
+  [
+    source 160
+    target 189
+    value 6
+  ]
+  edge
+  [
+    source 160
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 161
+    target 162
+    value 1
+  ]
+  edge
+  [
+    source 161
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 161
+    target 189
+    value 23
+  ]
+  edge
+  [
+    source 161
+    target 231
+    value 6
+  ]
+  edge
+  [
+    source 161
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 162
+    target 163
+    value 1
+  ]
+  edge
+  [
+    source 162
+    target 275
+    value 1
+  ]
+  edge
+  [
+    source 162
+    target 231
+    value 23
+  ]
+  edge
+  [
+    source 162
+    target 234
+    value 6
+  ]
+  edge
+  [
+    source 162
+    target 269
+    value 1
+  ]
+  edge
+  [
+    source 162
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 163
+    target 164
+    value 1
+  ]
+  edge
+  [
+    source 163
+    target 276
+    value 1
+  ]
+  edge
+  [
+    source 163
+    target 269
+    value 23
+  ]
+  edge
+  [
+    source 163
+    target 271
+    value 1
+  ]
+  edge
+  [
+    source 163
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 164
+    target 165
+    value 1
+  ]
+  edge
+  [
+    source 164
+    target 276
+    value 1
+  ]
+  edge
+  [
+    source 164
+    target 273
+    value 23
+  ]
+  edge
+  [
+    source 164
+    target 268
+    value 1
+  ]
+  edge
+  [
+    source 164
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 165
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 165
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 165
+    target 249
+    value 23
+  ]
+  edge
+  [
+    source 165
+    target 227
+    value 1
+  ]
+  edge
+  [
+    source 165
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 166
+    target 167
+    value 1
+  ]
+  edge
+  [
+    source 166
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 166
+    target 227
+    value 23
+  ]
+  edge
+  [
+    source 166
+    target 221
+    value 1
+  ]
+  edge
+  [
+    source 166
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 167
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 167
+    target 227
+    value 23
+  ]
+  edge
+  [
+    source 167
+    target 221
+    value 1
+  ]
+  edge
+  [
+    source 167
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 168
+    target 156
+    value 1
+  ]
+  edge
+  [
+    source 168
+    target 233
+    value 4
+  ]
+  edge
+  [
+    source 168
+    target 275
+    value 9
+  ]
+  edge
+  [
+    source 168
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 168
+    target 231
+    value 9
+  ]
+  edge
+  [
+    source 168
+    target 234
+    value 22
+  ]
+  edge
+  [
+    source 168
+    target 269
+    value 7
+  ]
+  edge
+  [
+    source 168
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 169
+    target 270
+    value 1
+  ]
+  edge
+  [
+    source 169
+    target 272
+    value 1
+  ]
+  edge
+  [
+    source 169
+    target 276
+    value 4
+  ]
+  edge
+  [
+    source 169
+    target 277
+    value 9
+  ]
+  edge
+  [
+    source 169
+    target 234
+    value 1
+  ]
+  edge
+  [
+    source 169
+    target 269
+    value 9
+  ]
+  edge
+  [
+    source 169
+    target 271
+    value 22
+  ]
+  edge
+  [
+    source 169
+    target 273
+    value 7
+  ]
+  edge
+  [
+    source 169
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 170
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 170
+    target 2
+    value 4
+  ]
+  edge
+  [
+    source 170
+    target 117
+    value 4
+  ]
+  edge
+  [
+    source 170
+    target 118
+    value 2
+  ]
+  edge
+  [
+    source 170
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 170
+    target 255
+    value 1
+  ]
+  edge
+  [
+    source 170
+    target 207
+    value 1
+  ]
+  edge
+  [
+    source 170
+    target 256
+    value 1
+  ]
+  edge
+  [
+    source 171
+    target 213
+    value 22
+  ]
+  edge
+  [
+    source 171
+    target 137
+    value 61
+  ]
+  edge
+  [
+    source 171
+    target 185
+    value 1
+  ]
+  edge
+  [
+    source 171
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 171
+    target 217
+    value 1
+  ]
+  edge
+  [
+    source 171
+    target 42
+    value 2
+  ]
+  edge
+  [
+    source 171
+    target 246
+    value 1
+  ]
+  edge
+  [
+    source 171
+    target 190
+    value 4
+  ]
+  edge
+  [
+    source 172
+    target 201
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 154
+    value 2
+  ]
+  edge
+  [
+    source 172
+    target 12
+    value 8
+  ]
+  edge
+  [
+    source 172
+    target 2
+    value 10
+  ]
+  edge
+  [
+    source 172
+    target 84
+    value 9
+  ]
+  edge
+  [
+    source 172
+    target 86
+    value 6
+  ]
+  edge
+  [
+    source 172
+    target 117
+    value 6
+  ]
+  edge
+  [
+    source 172
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 3
+    value 3
+  ]
+  edge
+  [
+    source 172
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 160
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 232
+    value 4
+  ]
+  edge
+  [
+    source 172
+    target 168
+    value 5
+  ]
+  edge
+  [
+    source 172
+    target 192
+    value 7
+  ]
+  edge
+  [
+    source 172
+    target 169
+    value 3
+  ]
+  edge
+  [
+    source 172
+    target 253
+    value 4
+  ]
+  edge
+  [
+    source 172
+    target 137
+    value 4
+  ]
+  edge
+  [
+    source 172
+    target 129
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 170
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 185
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 42
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 220
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 96
+    value 4
+  ]
+  edge
+  [
+    source 172
+    target 79
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 254
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 262
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 263
+    value 4
+  ]
+  edge
+  [
+    source 172
+    target 264
+    value 1
+  ]
+  edge
+  [
+    source 172
+    target 265
+    value 5
+  ]
+  edge
+  [
+    source 172
+    target 266
+    value 3
+  ]
+  edge
+  [
+    source 172
+    target 267
+    value 2
+  ]
+  edge
+  [
+    source 173
+    target 178
+    value 1
+  ]
+  edge
+  [
+    source 174
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 175
+    target 277
+    value 8
+  ]
+  edge
+  [
+    source 175
+    target 176
+    value 1
+  ]
+  edge
+  [
+    source 175
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 176
+    target 97
+    value 8
+  ]
+  edge
+  [
+    source 176
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 176
+    target 249
+    value 3
+  ]
+  edge
+  [
+    source 176
+    target 227
+    value 2
+  ]
+  edge
+  [
+    source 176
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 177
+    target 153
+    value 2
+  ]
+  edge
+  [
+    source 177
+    target 166
+    value 3
+  ]
+  edge
+  [
+    source 177
+    target 167
+    value 5
+  ]
+  edge
+  [
+    source 177
+    target 253
+    value 4
+  ]
+  edge
+  [
+    source 177
+    target 97
+    value 2
+  ]
+  edge
+  [
+    source 177
+    target 170
+    value 2
+  ]
+  edge
+  [
+    source 177
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 177
+    target 172
+    value 3
+  ]
+  edge
+  [
+    source 177
+    target 176
+    value 1
+  ]
+  edge
+  [
+    source 177
+    target 221
+    value 2
+  ]
+  edge
+  [
+    source 177
+    target 183
+    value 11
+  ]
+  edge
+  [
+    source 177
+    target 44
+    value 14
+  ]
+  edge
+  [
+    source 178
+    target 219
+    value 8
+  ]
+  edge
+  [
+    source 178
+    target 179
+    value 1
+  ]
+  edge
+  [
+    source 178
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 178
+    target 197
+    value 3
+  ]
+  edge
+  [
+    source 178
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 179
+    target 219
+    value 18
+  ]
+  edge
+  [
+    source 179
+    target 233
+    value 11
+  ]
+  edge
+  [
+    source 179
+    target 180
+    value 1
+  ]
+  edge
+  [
+    source 179
+    target 197
+    value 3
+  ]
+  edge
+  [
+    source 179
+    target 189
+    value 2
+  ]
+  edge
+  [
+    source 179
+    target 44
+    value 31
+  ]
+  edge
+  [
+    source 180
+    target 233
+    value 8
+  ]
+  edge
+  [
+    source 180
+    target 181
+    value 1
+  ]
+  edge
+  [
+    source 180
+    target 231
+    value 1
+  ]
+  edge
+  [
+    source 180
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 181
+    target 275
+    value 8
+  ]
+  edge
+  [
+    source 181
+    target 182
+    value 1
+  ]
+  edge
+  [
+    source 181
+    target 231
+    value 3
+  ]
+  edge
+  [
+    source 181
+    target 234
+    value 2
+  ]
+  edge
+  [
+    source 181
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 182
+    target 275
+    value 8
+  ]
+  edge
+  [
+    source 182
+    target 188
+    value 1
+  ]
+  edge
+  [
+    source 182
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 183
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 183
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 184
+    target 12
+    value 3
+  ]
+  edge
+  [
+    source 184
+    target 2
+    value 7
+  ]
+  edge
+  [
+    source 184
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 184
+    target 118
+    value 3
+  ]
+  edge
+  [
+    source 184
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 184
+    target 194
+    value 1
+  ]
+  edge
+  [
+    source 184
+    target 172
+    value 3
+  ]
+  edge
+  [
+    source 184
+    target 42
+    value 1
+  ]
+  edge
+  [
+    source 184
+    target 256
+    value 1
+  ]
+  edge
+  [
+    source 185
+    target 218
+    value 22
+  ]
+  edge
+  [
+    source 185
+    target 137
+    value 61
+  ]
+  edge
+  [
+    source 185
+    target 171
+    value 1
+  ]
+  edge
+  [
+    source 185
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 185
+    target 217
+    value 1
+  ]
+  edge
+  [
+    source 185
+    target 42
+    value 2
+  ]
+  edge
+  [
+    source 185
+    target 246
+    value 1
+  ]
+  edge
+  [
+    source 185
+    target 190
+    value 4
+  ]
+  edge
+  [
+    source 186
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 160
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 97
+    value 2
+  ]
+  edge
+  [
+    source 187
+    target 111
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 220
+    value 1
+  ]
+  edge
+  [
+    source 187
+    target 173
+    value 5
+  ]
+  edge
+  [
+    source 187
+    target 174
+    value 7
+  ]
+  edge
+  [
+    source 187
+    target 221
+    value 3
+  ]
+  edge
+  [
+    source 187
+    target 44
+    value 6
+  ]
+  edge
+  [
+    source 188
+    target 276
+    value 8
+  ]
+  edge
+  [
+    source 188
+    target 279
+    value 1
+  ]
+  edge
+  [
+    source 188
+    target 269
+    value 3
+  ]
+  edge
+  [
+    source 188
+    target 271
+    value 2
+  ]
+  edge
+  [
+    source 188
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 189
+    target 155
+    value 2
+  ]
+  edge
+  [
+    source 189
+    target 237
+    value 2
+  ]
+  edge
+  [
+    source 189
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 191
+    target 113
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 102
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 108
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 116
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 109
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 146
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 141
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 117
+    value 3
+  ]
+  edge
+  [
+    source 191
+    target 202
+    value 6
+  ]
+  edge
+  [
+    source 191
+    target 119
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 120
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 110
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 163
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 142
+    value 3
+  ]
+  edge
+  [
+    source 191
+    target 215
+    value 3
+  ]
+  edge
+  [
+    source 191
+    target 132
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 173
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 186
+    value 3
+  ]
+  edge
+  [
+    source 191
+    target 182
+    value 1
+  ]
+  edge
+  [
+    source 191
+    target 238
+    value 2
+  ]
+  edge
+  [
+    source 191
+    target 244
+    value 10
+  ]
+  edge
+  [
+    source 191
+    target 44
+    value 3
+  ]
+  edge
+  [
+    source 191
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 192
+    target 157
+    value 1
+  ]
+  edge
+  [
+    source 192
+    target 158
+    value 1
+  ]
+  edge
+  [
+    source 192
+    target 275
+    value 4
+  ]
+  edge
+  [
+    source 192
+    target 276
+    value 9
+  ]
+  edge
+  [
+    source 192
+    target 231
+    value 1
+  ]
+  edge
+  [
+    source 192
+    target 234
+    value 9
+  ]
+  edge
+  [
+    source 192
+    target 269
+    value 22
+  ]
+  edge
+  [
+    source 192
+    target 271
+    value 7
+  ]
+  edge
+  [
+    source 192
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 193
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 193
+    target 114
+    value 3
+  ]
+  edge
+  [
+    source 193
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 193
+    target 2
+    value 7
+  ]
+  edge
+  [
+    source 193
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 193
+    target 213
+    value 2
+  ]
+  edge
+  [
+    source 193
+    target 218
+    value 1
+  ]
+  edge
+  [
+    source 193
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 193
+    target 14
+    value 1
+  ]
+  edge
+  [
+    source 193
+    target 8
+    value 5
+  ]
+  edge
+  [
+    source 193
+    target 9
+    value 5
+  ]
+  edge
+  [
+    source 193
+    target 214
+    value 2
+  ]
+  edge
+  [
+    source 193
+    target 210
+    value 4
+  ]
+  edge
+  [
+    source 194
+    target 12
+    value 7
+  ]
+  edge
+  [
+    source 194
+    target 2
+    value 7
+  ]
+  edge
+  [
+    source 194
+    target 118
+    value 23
+  ]
+  edge
+  [
+    source 194
+    target 226
+    value 1
+  ]
+  edge
+  [
+    source 194
+    target 170
+    value 1
+  ]
+  edge
+  [
+    source 194
+    target 204
+    value 1
+  ]
+  edge
+  [
+    source 195
+    target 1
+    value 2
+  ]
+  edge
+  [
+    source 195
+    target 114
+    value 5
+  ]
+  edge
+  [
+    source 195
+    target 213
+    value 7
+  ]
+  edge
+  [
+    source 195
+    target 218
+    value 7
+  ]
+  edge
+  [
+    source 195
+    target 187
+    value 2
+  ]
+  edge
+  [
+    source 195
+    target 166
+    value 2
+  ]
+  edge
+  [
+    source 195
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 195
+    target 97
+    value 3
+  ]
+  edge
+  [
+    source 195
+    target 193
+    value 5
+  ]
+  edge
+  [
+    source 195
+    target 250
+    value 1
+  ]
+  edge
+  [
+    source 195
+    target 111
+    value 2
+  ]
+  edge
+  [
+    source 195
+    target 8
+    value 2
+  ]
+  edge
+  [
+    source 195
+    target 9
+    value 3
+  ]
+  edge
+  [
+    source 195
+    target 59
+    value 1
+  ]
+  edge
+  [
+    source 195
+    target 64
+    value 1
+  ]
+  edge
+  [
+    source 195
+    target 214
+    value 2
+  ]
+  edge
+  [
+    source 195
+    target 210
+    value 4
+  ]
+  edge
+  [
+    source 195
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 195
+    target 44
+    value 5
+  ]
+  edge
+  [
+    source 195
+    target 190
+    value 5
+  ]
+  edge
+  [
+    source 196
+    target 219
+    value 8
+  ]
+  edge
+  [
+    source 196
+    target 178
+    value 1
+  ]
+  edge
+  [
+    source 196
+    target 133
+    value 1
+  ]
+  edge
+  [
+    source 196
+    target 200
+    value 3
+  ]
+  edge
+  [
+    source 196
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 197
+    target 155
+    value 2
+  ]
+  edge
+  [
+    source 197
+    target 237
+    value 2
+  ]
+  edge
+  [
+    source 197
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 198
+    target 105
+    value 3
+  ]
+  edge
+  [
+    source 198
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 198
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 198
+    target 199
+    value 5
+  ]
+  edge
+  [
+    source 198
+    target 123
+    value 2
+  ]
+  edge
+  [
+    source 198
+    target 119
+    value 4
+  ]
+  edge
+  [
+    source 198
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 198
+    target 110
+    value 1
+  ]
+  edge
+  [
+    source 198
+    target 111
+    value 1
+  ]
+  edge
+  [
+    source 198
+    target 148
+    value 2
+  ]
+  edge
+  [
+    source 198
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 198
+    target 103
+    value 3
+  ]
+  edge
+  [
+    source 198
+    target 85
+    value 2
+  ]
+  edge
+  [
+    source 198
+    target 112
+    value 2
+  ]
+  edge
+  [
+    source 198
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 199
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 199
+    target 86
+    value 8
+  ]
+  edge
+  [
+    source 199
+    target 202
+    value 4
+  ]
+  edge
+  [
+    source 199
+    target 226
+    value 2
+  ]
+  edge
+  [
+    source 199
+    target 123
+    value 5
+  ]
+  edge
+  [
+    source 199
+    target 119
+    value 4
+  ]
+  edge
+  [
+    source 199
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 199
+    target 142
+    value 2
+  ]
+  edge
+  [
+    source 199
+    target 185
+    value 1
+  ]
+  edge
+  [
+    source 199
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 199
+    target 227
+    value 1
+  ]
+  edge
+  [
+    source 199
+    target 44
+    value 2
+  ]
+  edge
+  [
+    source 200
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 200
+    target 196
+    value 2
+  ]
+  edge
+  [
+    source 200
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 201
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 201
+    target 2
+    value 3
+  ]
+  edge
+  [
+    source 201
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 201
+    target 86
+    value 5
+  ]
+  edge
+  [
+    source 201
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 201
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 201
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 201
+    target 0
+    value 2
+  ]
+  edge
+  [
+    source 201
+    target 5
+    value 2
+  ]
+  edge
+  [
+    source 201
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 201
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 201
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 201
+    target 203
+    value 1
+  ]
+  edge
+  [
+    source 201
+    target 13
+    value 3
+  ]
+  edge
+  [
+    source 201
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 201
+    target 65
+    value 1
+  ]
+  edge
+  [
+    source 202
+    target 84
+    value 5
+  ]
+  edge
+  [
+    source 202
+    target 199
+    value 5
+  ]
+  edge
+  [
+    source 202
+    target 226
+    value 2
+  ]
+  edge
+  [
+    source 202
+    target 123
+    value 6
+  ]
+  edge
+  [
+    source 202
+    target 98
+    value 4
+  ]
+  edge
+  [
+    source 202
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 202
+    target 191
+    value 1
+  ]
+  edge
+  [
+    source 202
+    target 171
+    value 1
+  ]
+  edge
+  [
+    source 202
+    target 145
+    value 2
+  ]
+  edge
+  [
+    source 202
+    target 133
+    value 1
+  ]
+  edge
+  [
+    source 202
+    target 227
+    value 1
+  ]
+  edge
+  [
+    source 202
+    target 44
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 101
+    value 1
+  ]
+  edge
+  [
+    source 203
+    target 201
+    value 1
+  ]
+  edge
+  [
+    source 203
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 84
+    value 5
+  ]
+  edge
+  [
+    source 203
+    target 86
+    value 6
+  ]
+  edge
+  [
+    source 203
+    target 118
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 203
+    target 123
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 187
+    value 4
+  ]
+  edge
+  [
+    source 203
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 203
+    target 193
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 172
+    value 4
+  ]
+  edge
+  [
+    source 203
+    target 148
+    value 1
+  ]
+  edge
+  [
+    source 203
+    target 8
+    value 2
+  ]
+  edge
+  [
+    source 203
+    target 190
+    value 3
+  ]
+  edge
+  [
+    source 204
+    target 2
+    value 6
+  ]
+  edge
+  [
+    source 204
+    target 86
+    value 3
+  ]
+  edge
+  [
+    source 204
+    target 118
+    value 6
+  ]
+  edge
+  [
+    source 204
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 204
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 204
+    target 226
+    value 1
+  ]
+  edge
+  [
+    source 204
+    target 119
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 98
+    value 7
+  ]
+  edge
+  [
+    source 204
+    target 187
+    value 4
+  ]
+  edge
+  [
+    source 204
+    target 225
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 95
+    value 3
+  ]
+  edge
+  [
+    source 204
+    target 219
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 204
+    target 194
+    value 3
+  ]
+  edge
+  [
+    source 204
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 207
+    value 5
+  ]
+  edge
+  [
+    source 204
+    target 252
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 220
+    value 3
+  ]
+  edge
+  [
+    source 204
+    target 205
+    value 1
+  ]
+  edge
+  [
+    source 204
+    target 238
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 245
+    value 1
+  ]
+  edge
+  [
+    source 204
+    target 221
+    value 1
+  ]
+  edge
+  [
+    source 204
+    target 189
+    value 2
+  ]
+  edge
+  [
+    source 204
+    target 231
+    value 4
+  ]
+  edge
+  [
+    source 204
+    target 44
+    value 7
+  ]
+  edge
+  [
+    source 204
+    target 190
+    value 2
+  ]
+  edge
+  [
+    source 205
+    target 109
+    value 2
+  ]
+  edge
+  [
+    source 205
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 86
+    value 16
+  ]
+  edge
+  [
+    source 205
+    target 202
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 198
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 205
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 205
+    target 111
+    value 4
+  ]
+  edge
+  [
+    source 205
+    target 130
+    value 4
+  ]
+  edge
+  [
+    source 205
+    target 33
+    value 1
+  ]
+  edge
+  [
+    source 206
+    target 67
+    value 3
+  ]
+  edge
+  [
+    source 206
+    target 84
+    value 6
+  ]
+  edge
+  [
+    source 206
+    target 86
+    value 5
+  ]
+  edge
+  [
+    source 206
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 206
+    target 225
+    value 3
+  ]
+  edge
+  [
+    source 206
+    target 95
+    value 4
+  ]
+  edge
+  [
+    source 206
+    target 159
+    value 1
+  ]
+  edge
+  [
+    source 206
+    target 159
+    value 1
+  ]
+  edge
+  [
+    source 206
+    target 125
+    value 4
+  ]
+  edge
+  [
+    source 206
+    target 172
+    value 6
+  ]
+  edge
+  [
+    source 206
+    target 42
+    value 3
+  ]
+  edge
+  [
+    source 206
+    target 96
+    value 1
+  ]
+  edge
+  [
+    source 206
+    target 78
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 2
+    value 6
+  ]
+  edge
+  [
+    source 207
+    target 86
+    value 3
+  ]
+  edge
+  [
+    source 207
+    target 118
+    value 6
+  ]
+  edge
+  [
+    source 207
+    target 4
+    value 3
+  ]
+  edge
+  [
+    source 207
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 226
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 119
+    value 3
+  ]
+  edge
+  [
+    source 207
+    target 98
+    value 7
+  ]
+  edge
+  [
+    source 207
+    target 187
+    value 4
+  ]
+  edge
+  [
+    source 207
+    target 95
+    value 3
+  ]
+  edge
+  [
+    source 207
+    target 219
+    value 2
+  ]
+  edge
+  [
+    source 207
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 194
+    value 3
+  ]
+  edge
+  [
+    source 207
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 207
+    target 204
+    value 4
+  ]
+  edge
+  [
+    source 207
+    target 252
+    value 2
+  ]
+  edge
+  [
+    source 207
+    target 256
+    value 3
+  ]
+  edge
+  [
+    source 207
+    target 205
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 238
+    value 2
+  ]
+  edge
+  [
+    source 207
+    target 245
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 221
+    value 1
+  ]
+  edge
+  [
+    source 207
+    target 189
+    value 2
+  ]
+  edge
+  [
+    source 207
+    target 231
+    value 4
+  ]
+  edge
+  [
+    source 207
+    target 44
+    value 7
+  ]
+  edge
+  [
+    source 207
+    target 190
+    value 2
+  ]
+  edge
+  [
+    source 208
+    target 101
+    value 1
+  ]
+  edge
+  [
+    source 208
+    target 126
+    value 5
+  ]
+  edge
+  [
+    source 208
+    target 10
+    value 1
+  ]
+  edge
+  [
+    source 208
+    target 102
+    value 10
+  ]
+  edge
+  [
+    source 208
+    target 135
+    value 4
+  ]
+  edge
+  [
+    source 208
+    target 140
+    value 1
+  ]
+  edge
+  [
+    source 208
+    target 120
+    value 1
+  ]
+  edge
+  [
+    source 209
+    target 13
+    value 2
+  ]
+  edge
+  [
+    source 209
+    target 6
+    value 2
+  ]
+  edge
+  [
+    source 209
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 209
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 209
+    target 46
+    value 1
+  ]
+  edge
+  [
+    source 209
+    target 64
+    value 1
+  ]
+  edge
+  [
+    source 209
+    target 131
+    value 2
+  ]
+  edge
+  [
+    source 209
+    target 25
+    value 2
+  ]
+  edge
+  [
+    source 209
+    target 73
+    value 2
+  ]
+  edge
+  [
+    source 209
+    target 75
+    value 2
+  ]
+  edge
+  [
+    source 209
+    target 44
+    value 5
+  ]
+  edge
+  [
+    source 210
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 210
+    target 213
+    value 1
+  ]
+  edge
+  [
+    source 210
+    target 218
+    value 3
+  ]
+  edge
+  [
+    source 210
+    target 48
+    value 2
+  ]
+  edge
+  [
+    source 210
+    target 44
+    value 4
+  ]
+  edge
+  [
+    source 211
+    target 12
+    value 15
+  ]
+  edge
+  [
+    source 211
+    target 31
+    value 1
+  ]
+  edge
+  [
+    source 211
+    target 132
+    value 2
+  ]
+  edge
+  [
+    source 211
+    target 130
+    value 9
+  ]
+  edge
+  [
+    source 211
+    target 210
+    value 2
+  ]
+  edge
+  [
+    source 211
+    target 74
+    value 6
+  ]
+  edge
+  [
+    source 212
+    target 2
+    value 11
+  ]
+  edge
+  [
+    source 212
+    target 132
+    value 4
+  ]
+  edge
+  [
+    source 212
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 212
+    target 73
+    value 6
+  ]
+  edge
+  [
+    source 213
+    target 84
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 3
+    value 2
+  ]
+  edge
+  [
+    source 213
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 206
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 185
+    value 4
+  ]
+  edge
+  [
+    source 213
+    target 217
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 148
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 132
+    value 2
+  ]
+  edge
+  [
+    source 213
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 72
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 37
+    value 1
+  ]
+  edge
+  [
+    source 213
+    target 190
+    value 5
+  ]
+  edge
+  [
+    source 214
+    target 1
+    value 1
+  ]
+  edge
+  [
+    source 214
+    target 213
+    value 1
+  ]
+  edge
+  [
+    source 214
+    target 218
+    value 4
+  ]
+  edge
+  [
+    source 214
+    target 47
+    value 5
+  ]
+  edge
+  [
+    source 214
+    target 48
+    value 1
+  ]
+  edge
+  [
+    source 214
+    target 87
+    value 1
+  ]
+  edge
+  [
+    source 214
+    target 44
+    value 5
+  ]
+  edge
+  [
+    source 215
+    target 216
+    value 2
+  ]
+  edge
+  [
+    source 215
+    target 84
+    value 10
+  ]
+  edge
+  [
+    source 215
+    target 86
+    value 1
+  ]
+  edge
+  [
+    source 215
+    target 123
+    value 1
+  ]
+  edge
+  [
+    source 215
+    target 98
+    value 2
+  ]
+  edge
+  [
+    source 215
+    target 203
+    value 3
+  ]
+  edge
+  [
+    source 215
+    target 132
+    value 2
+  ]
+  edge
+  [
+    source 215
+    target 130
+    value 1
+  ]
+  edge
+  [
+    source 216
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 216
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 216
+    target 225
+    value 5
+  ]
+  edge
+  [
+    source 216
+    target 71
+    value 3
+  ]
+  edge
+  [
+    source 216
+    target 15
+    value 1
+  ]
+  edge
+  [
+    source 216
+    target 125
+    value 4
+  ]
+  edge
+  [
+    source 216
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 216
+    target 35
+    value 1
+  ]
+  edge
+  [
+    source 216
+    target 93
+    value 1
+  ]
+  edge
+  [
+    source 216
+    target 239
+    value 1
+  ]
+  edge
+  [
+    source 217
+    target 213
+    value 11
+  ]
+  edge
+  [
+    source 217
+    target 206
+    value 1
+  ]
+  edge
+  [
+    source 217
+    target 137
+    value 3
+  ]
+  edge
+  [
+    source 217
+    target 171
+    value 10
+  ]
+  edge
+  [
+    source 217
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 217
+    target 42
+    value 2
+  ]
+  edge
+  [
+    source 217
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 171
+    value 4
+  ]
+  edge
+  [
+    source 218
+    target 217
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 203
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 132
+    value 3
+  ]
+  edge
+  [
+    source 218
+    target 130
+    value 3
+  ]
+  edge
+  [
+    source 218
+    target 131
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 85
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 73
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 74
+    value 2
+  ]
+  edge
+  [
+    source 218
+    target 75
+    value 1
+  ]
+  edge
+  [
+    source 218
+    target 190
+    value 5
+  ]
+  edge
+  [
+    source 219
+    target 159
+    value 2
+  ]
+  edge
+  [
+    source 219
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 219
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 219
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 220
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 220
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 220
+    target 119
+    value 1
+  ]
+  edge
+  [
+    source 220
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 220
+    target 252
+    value 3
+  ]
+  edge
+  [
+    source 220
+    target 256
+    value 1
+  ]
+  edge
+  [
+    source 220
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 221
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 221
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 222
+    target 72
+    value 3
+  ]
+  edge
+  [
+    source 222
+    target 112
+    value 5
+  ]
+  edge
+  [
+    source 223
+    target 131
+    value 5
+  ]
+  edge
+  [
+    source 223
+    target 104
+    value 6
+  ]
+  edge
+  [
+    source 224
+    target 67
+    value 2
+  ]
+  edge
+  [
+    source 224
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 224
+    target 12
+    value 10
+  ]
+  edge
+  [
+    source 224
+    target 2
+    value 4
+  ]
+  edge
+  [
+    source 224
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 224
+    target 86
+    value 2
+  ]
+  edge
+  [
+    source 224
+    target 117
+    value 10
+  ]
+  edge
+  [
+    source 224
+    target 118
+    value 2
+  ]
+  edge
+  [
+    source 224
+    target 3
+    value 3
+  ]
+  edge
+  [
+    source 224
+    target 4
+    value 2
+  ]
+  edge
+  [
+    source 224
+    target 137
+    value 1
+  ]
+  edge
+  [
+    source 224
+    target 129
+    value 1
+  ]
+  edge
+  [
+    source 224
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 224
+    target 133
+    value 1
+  ]
+  edge
+  [
+    source 224
+    target 190
+    value 3
+  ]
+  edge
+  [
+    source 225
+    target 63
+    value 4
+  ]
+  edge
+  [
+    source 225
+    target 2
+    value 2
+  ]
+  edge
+  [
+    source 225
+    target 198
+    value 1
+  ]
+  edge
+  [
+    source 225
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 225
+    target 191
+    value 4
+  ]
+  edge
+  [
+    source 225
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 225
+    target 207
+    value 1
+  ]
+  edge
+  [
+    source 225
+    target 204
+    value 2
+  ]
+  edge
+  [
+    source 225
+    target 131
+    value 2
+  ]
+  edge
+  [
+    source 225
+    target 56
+    value 1
+  ]
+  edge
+  [
+    source 225
+    target 39
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 12
+    value 3
+  ]
+  edge
+  [
+    source 226
+    target 2
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 84
+    value 4
+  ]
+  edge
+  [
+    source 226
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 4
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 202
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 228
+    value 2
+  ]
+  edge
+  [
+    source 226
+    target 229
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 207
+    value 2
+  ]
+  edge
+  [
+    source 226
+    target 204
+    value 2
+  ]
+  edge
+  [
+    source 226
+    target 203
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 111
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 148
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 176
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 176
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 226
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 227
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 228
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 228
+    target 202
+    value 3
+  ]
+  edge
+  [
+    source 228
+    target 226
+    value 5
+  ]
+  edge
+  [
+    source 228
+    target 198
+    value 1
+  ]
+  edge
+  [
+    source 228
+    target 123
+    value 1
+  ]
+  edge
+  [
+    source 228
+    target 166
+    value 1
+  ]
+  edge
+  [
+    source 228
+    target 137
+    value 2
+  ]
+  edge
+  [
+    source 228
+    target 229
+    value 5
+  ]
+  edge
+  [
+    source 228
+    target 255
+    value 5
+  ]
+  edge
+  [
+    source 228
+    target 257
+    value 4
+  ]
+  edge
+  [
+    source 228
+    target 145
+    value 2
+  ]
+  edge
+  [
+    source 229
+    target 226
+    value 3
+  ]
+  edge
+  [
+    source 229
+    target 123
+    value 1
+  ]
+  edge
+  [
+    source 229
+    target 137
+    value 2
+  ]
+  edge
+  [
+    source 229
+    target 228
+    value 6
+  ]
+  edge
+  [
+    source 229
+    target 255
+    value 1
+  ]
+  edge
+  [
+    source 229
+    target 257
+    value 5
+  ]
+  edge
+  [
+    source 229
+    target 145
+    value 2
+  ]
+  edge
+  [
+    source 230
+    target 151
+    value 1
+  ]
+  edge
+  [
+    source 230
+    target 154
+    value 1
+  ]
+  edge
+  [
+    source 230
+    target 219
+    value 4
+  ]
+  edge
+  [
+    source 230
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 230
+    target 197
+    value 9
+  ]
+  edge
+  [
+    source 230
+    target 189
+    value 22
+  ]
+  edge
+  [
+    source 230
+    target 231
+    value 7
+  ]
+  edge
+  [
+    source 230
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 231
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 232
+    target 155
+    value 1
+  ]
+  edge
+  [
+    source 232
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 232
+    target 233
+    value 4
+  ]
+  edge
+  [
+    source 232
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 232
+    target 189
+    value 9
+  ]
+  edge
+  [
+    source 232
+    target 231
+    value 22
+  ]
+  edge
+  [
+    source 232
+    target 234
+    value 7
+  ]
+  edge
+  [
+    source 232
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 233
+    target 161
+    value 2
+  ]
+  edge
+  [
+    source 233
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 233
+    target 231
+    value 1
+  ]
+  edge
+  [
+    source 233
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 234
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 235
+    target 211
+    value 3
+  ]
+  edge
+  [
+    source 235
+    target 85
+    value 2
+  ]
+  edge
+  [
+    source 235
+    target 77
+    value 1
+  ]
+  edge
+  [
+    source 236
+    target 36
+    value 1
+  ]
+  edge
+  [
+    source 236
+    target 212
+    value 3
+  ]
+  edge
+  [
+    source 236
+    target 89
+    value 1
+  ]
+  edge
+  [
+    source 236
+    target 74
+    value 1
+  ]
+  edge
+  [
+    source 236
+    target 77
+    value 1
+  ]
+  edge
+  [
+    source 237
+    target 219
+    value 19
+  ]
+  edge
+  [
+    source 237
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 237
+    target 178
+    value 1
+  ]
+  edge
+  [
+    source 237
+    target 238
+    value 1
+  ]
+  edge
+  [
+    source 237
+    target 197
+    value 6
+  ]
+  edge
+  [
+    source 237
+    target 189
+    value 4
+  ]
+  edge
+  [
+    source 237
+    target 44
+    value 23
+  ]
+  edge
+  [
+    source 238
+    target 233
+    value 4
+  ]
+  edge
+  [
+    source 238
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 238
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 238
+    target 231
+    value 2
+  ]
+  edge
+  [
+    source 238
+    target 44
+    value 2
+  ]
+  edge
+  [
+    source 238
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 239
+    target 114
+    value 1
+  ]
+  edge
+  [
+    source 239
+    target 216
+    value 1
+  ]
+  edge
+  [
+    source 239
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 239
+    target 2
+    value 3
+  ]
+  edge
+  [
+    source 239
+    target 3
+    value 1
+  ]
+  edge
+  [
+    source 239
+    target 129
+    value 1
+  ]
+  edge
+  [
+    source 239
+    target 21
+    value 1
+  ]
+  edge
+  [
+    source 239
+    target 90
+    value 2
+  ]
+  edge
+  [
+    source 239
+    target 214
+    value 1
+  ]
+  edge
+  [
+    source 240
+    target 95
+    value 5
+  ]
+  edge
+  [
+    source 240
+    target 58
+    value 1
+  ]
+  edge
+  [
+    source 240
+    target 27
+    value 1
+  ]
+  edge
+  [
+    source 240
+    target 172
+    value 2
+  ]
+  edge
+  [
+    source 240
+    target 23
+    value 1
+  ]
+  edge
+  [
+    source 240
+    target 88
+    value 1
+  ]
+  edge
+  [
+    source 241
+    target 16
+    value 1
+  ]
+  edge
+  [
+    source 241
+    target 1
+    value 2
+  ]
+  edge
+  [
+    source 241
+    target 12
+    value 2
+  ]
+  edge
+  [
+    source 241
+    target 84
+    value 5
+  ]
+  edge
+  [
+    source 241
+    target 86
+    value 4
+  ]
+  edge
+  [
+    source 241
+    target 137
+    value 3
+  ]
+  edge
+  [
+    source 241
+    target 24
+    value 2
+  ]
+  edge
+  [
+    source 241
+    target 36
+    value 1
+  ]
+  edge
+  [
+    source 242
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 243
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 244
+    target 202
+    value 1
+  ]
+  edge
+  [
+    source 244
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 244
+    target 195
+    value 1
+  ]
+  edge
+  [
+    source 244
+    target 193
+    value 2
+  ]
+  edge
+  [
+    source 244
+    target 245
+    value 1
+  ]
+  edge
+  [
+    source 244
+    target 283
+    value 1
+  ]
+  edge
+  [
+    source 244
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 245
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 219
+    value 2
+  ]
+  edge
+  [
+    source 245
+    target 233
+    value 4
+  ]
+  edge
+  [
+    source 245
+    target 275
+    value 4
+  ]
+  edge
+  [
+    source 245
+    target 276
+    value 10
+  ]
+  edge
+  [
+    source 245
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 148
+    value 3
+  ]
+  edge
+  [
+    source 245
+    target 252
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 282
+    value 2
+  ]
+  edge
+  [
+    source 245
+    target 238
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 283
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 197
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 189
+    value 1
+  ]
+  edge
+  [
+    source 245
+    target 231
+    value 2
+  ]
+  edge
+  [
+    source 245
+    target 234
+    value 4
+  ]
+  edge
+  [
+    source 245
+    target 269
+    value 3
+  ]
+  edge
+  [
+    source 245
+    target 271
+    value 5
+  ]
+  edge
+  [
+    source 245
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 246
+    target 277
+    value 8
+  ]
+  edge
+  [
+    source 246
+    target 175
+    value 1
+  ]
+  edge
+  [
+    source 246
+    target 273
+    value 3
+  ]
+  edge
+  [
+    source 246
+    target 268
+    value 2
+  ]
+  edge
+  [
+    source 246
+    target 44
+    value 30
+  ]
+  edge
+  [
+    source 247
+    target 12
+    value 27
+  ]
+  edge
+  [
+    source 247
+    target 137
+    value 3
+  ]
+  edge
+  [
+    source 247
+    target 172
+    value 28
+  ]
+  edge
+  [
+    source 247
+    target 248
+    value 1
+  ]
+  edge
+  [
+    source 247
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 248
+    target 2
+    value 27
+  ]
+  edge
+  [
+    source 248
+    target 137
+    value 3
+  ]
+  edge
+  [
+    source 248
+    target 125
+    value 28
+  ]
+  edge
+  [
+    source 248
+    target 247
+    value 1
+  ]
+  edge
+  [
+    source 248
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 249
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 250
+    target 167
+    value 1
+  ]
+  edge
+  [
+    source 250
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 250
+    target 204
+    value 1
+  ]
+  edge
+  [
+    source 250
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 251
+    target 97
+    value 1
+  ]
+  edge
+  [
+    source 251
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 252
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 253
+    target 152
+    value 1
+  ]
+  edge
+  [
+    source 253
+    target 153
+    value 1
+  ]
+  edge
+  [
+    source 253
+    target 97
+    value 4
+  ]
+  edge
+  [
+    source 253
+    target 249
+    value 22
+  ]
+  edge
+  [
+    source 253
+    target 227
+    value 7
+  ]
+  edge
+  [
+    source 253
+    target 273
+    value 1
+  ]
+  edge
+  [
+    source 253
+    target 268
+    value 9
+  ]
+  edge
+  [
+    source 253
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 254
+    target 97
+    value 15
+  ]
+  edge
+  [
+    source 254
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 254
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 255
+    target 12
+    value 9
+  ]
+  edge
+  [
+    source 255
+    target 2
+    value 6
+  ]
+  edge
+  [
+    source 255
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 255
+    target 257
+    value 1
+  ]
+  edge
+  [
+    source 255
+    target 125
+    value 13
+  ]
+  edge
+  [
+    source 255
+    target 177
+    value 2
+  ]
+  edge
+  [
+    source 256
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 256
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 256
+    target 98
+    value 1
+  ]
+  edge
+  [
+    source 256
+    target 125
+    value 1
+  ]
+  edge
+  [
+    source 256
+    target 252
+    value 3
+  ]
+  edge
+  [
+    source 256
+    target 220
+    value 1
+  ]
+  edge
+  [
+    source 256
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 257
+    target 12
+    value 7
+  ]
+  edge
+  [
+    source 257
+    target 2
+    value 7
+  ]
+  edge
+  [
+    source 257
+    target 117
+    value 1
+  ]
+  edge
+  [
+    source 257
+    target 118
+    value 1
+  ]
+  edge
+  [
+    source 257
+    target 255
+    value 1
+  ]
+  edge
+  [
+    source 257
+    target 125
+    value 6
+  ]
+  edge
+  [
+    source 257
+    target 172
+    value 3
+  ]
+  edge
+  [
+    source 257
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 258
+    target 12
+    value 1
+  ]
+  edge
+  [
+    source 258
+    target 137
+    value 5
+  ]
+  edge
+  [
+    source 258
+    target 170
+    value 1
+  ]
+  edge
+  [
+    source 258
+    target 125
+    value 2
+  ]
+  edge
+  [
+    source 258
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 259
+    target 123
+    value 1
+  ]
+  edge
+  [
+    source 259
+    target 167
+    value 6
+  ]
+  edge
+  [
+    source 259
+    target 137
+    value 7
+  ]
+  edge
+  [
+    source 259
+    target 184
+    value 1
+  ]
+  edge
+  [
+    source 259
+    target 258
+    value 1
+  ]
+  edge
+  [
+    source 259
+    target 172
+    value 8
+  ]
+  edge
+  [
+    source 259
+    target 177
+    value 1
+  ]
+  edge
+  [
+    source 260
+    target 191
+    value 2
+  ]
+  edge
+  [
+    source 261
+    target 12
+    value 5
+  ]
+  edge
+  [
+    source 261
+    target 117
+    value 4
+  ]
+  edge
+  [
+    source 261
+    target 137
+    value 5
+  ]
+  edge
+  [
+    source 261
+    target 142
+    value 2
+  ]
+  edge
+  [
+    source 261
+    target 185
+    value 5
+  ]
+  edge
+  [
+    source 261
+    target 172
+    value 1
+  ]
+  edge
+  [
+    source 262
+    target 233
+    value 15
+  ]
+  edge
+  [
+    source 262
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 263
+    target 233
+    value 6
+  ]
+  edge
+  [
+    source 263
+    target 275
+    value 15
+  ]
+  edge
+  [
+    source 263
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 264
+    target 275
+    value 15
+  ]
+  edge
+  [
+    source 264
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 265
+    target 275
+    value 6
+  ]
+  edge
+  [
+    source 265
+    target 276
+    value 15
+  ]
+  edge
+  [
+    source 265
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 266
+    target 276
+    value 15
+  ]
+  edge
+  [
+    source 266
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 267
+    target 276
+    value 6
+  ]
+  edge
+  [
+    source 267
+    target 277
+    value 15
+  ]
+  edge
+  [
+    source 267
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 268
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 269
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 270
+    target 269
+    value 2
+  ]
+  edge
+  [
+    source 270
+    target 271
+    value 16
+  ]
+  edge
+  [
+    source 270
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 271
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 272
+    target 164
+    value 1
+  ]
+  edge
+  [
+    source 272
+    target 271
+    value 2
+  ]
+  edge
+  [
+    source 272
+    target 273
+    value 16
+  ]
+  edge
+  [
+    source 272
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 273
+    target 44
+    value 25
+  ]
+  edge
+  [
+    source 274
+    target 273
+    value 2
+  ]
+  edge
+  [
+    source 274
+    target 268
+    value 16
+  ]
+  edge
+  [
+    source 274
+    target 44
+    value 15
+  ]
+  edge
+  [
+    source 275
+    target 162
+    value 2
+  ]
+  edge
+  [
+    source 275
+    target 234
+    value 1
+  ]
+  edge
+  [
+    source 275
+    target 269
+    value 1
+  ]
+  edge
+  [
+    source 275
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 276
+    target 164
+    value 2
+  ]
+  edge
+  [
+    source 276
+    target 271
+    value 1
+  ]
+  edge
+  [
+    source 276
+    target 273
+    value 1
+  ]
+  edge
+  [
+    source 276
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 277
+    target 165
+    value 2
+  ]
+  edge
+  [
+    source 277
+    target 249
+    value 1
+  ]
+  edge
+  [
+    source 277
+    target 268
+    value 1
+  ]
+  edge
+  [
+    source 277
+    target 44
+    value 29
+  ]
+  edge
+  [
+    source 278
+    target 274
+    value 1
+  ]
+  edge
+  [
+    source 278
+    target 277
+    value 4
+  ]
+  edge
+  [
+    source 278
+    target 97
+    value 9
+  ]
+  edge
+  [
+    source 278
+    target 269
+    value 1
+  ]
+  edge
+  [
+    source 278
+    target 271
+    value 9
+  ]
+  edge
+  [
+    source 278
+    target 273
+    value 22
+  ]
+  edge
+  [
+    source 278
+    target 268
+    value 7
+  ]
+  edge
+  [
+    source 278
+    target 44
+    value 22
+  ]
+  edge
+  [
+    source 279
+    target 276
+    value 8
+  ]
+  edge
+  [
+    source 279
+    target 246
+    value 1
+  ]
+  edge
+  [
+    source 279
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 280
+    target 277
+    value 6
+  ]
+  edge
+  [
+    source 280
+    target 97
+    value 15
+  ]
+  edge
+  [
+    source 280
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 281
+    target 277
+    value 15
+  ]
+  edge
+  [
+    source 281
+    target 44
+    value 18
+  ]
+  edge
+  [
+    source 282
+    target 219
+    value 1
+  ]
+  edge
+  [
+    source 282
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 282
+    target 238
+    value 1
+  ]
+  edge
+  [
+    source 282
+    target 200
+    value 1
+  ]
+  edge
+  [
+    source 282
+    target 44
+    value 2
+  ]
+  edge
+  [
+    source 282
+    target 44
+    value 2
+  ]
+  edge
+  [
+    source 283
+    target 202
+    value 1
+  ]
+  edge
+  [
+    source 283
+    target 199
+    value 1
+  ]
+  edge
+  [
+    source 283
+    target 276
+    value 2
+  ]
+  edge
+  [
+    source 283
+    target 195
+    value 2
+  ]
+  edge
+  [
+    source 283
+    target 193
+    value 2
+  ]
+  edge
+  [
+    source 283
+    target 244
+    value 2
+  ]
+  edge
+  [
+    source 283
+    target 44
+    value 8
+  ]
+  edge
+  [
+    source 284
+    target 187
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 233
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 275
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 276
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 277
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 142
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 145
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 244
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 249
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 227
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 221
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 183
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 271
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 273
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 268
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 284
+    target 44
+    value 10
+  ]
+  edge
+  [
+    source 285
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 286
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 287
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 288
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 289
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 290
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 291
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 292
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 293
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 294
+    target 44
+    value 1
+  ]
+  edge
+  [
+    source 295
+    target 190
+    value 1
+  ]
+  edge
+  [
+    source 296
+    target 190
+    value 1
+  ]
+]
diff --git a/examples/simple/centralization.c b/examples/simple/centralization.c
new file mode 100644
index 0000000..de138b5
--- /dev/null
+++ b/examples/simple/centralization.c
@@ -0,0 +1,173 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+#include <math.h>
+
+#define ALMOST_EQUALS(a, b) (fabs((a)-(b)) < 1e-8)
+
+int main() {
+
+  igraph_t g;
+  igraph_real_t cent;
+  igraph_arpack_options_t arpack_options;
+
+  /****************************/
+  /* in-star */
+  igraph_star(&g, 10, IGRAPH_STAR_IN, /*center=*/ 0);
+  
+  igraph_centralization_degree(&g, /*res=*/ 0,
+			       /*mode=*/ IGRAPH_IN, IGRAPH_NO_LOOPS,
+			       &cent, /*theoretical_max=*/ 0, 
+			       /*normalized=*/ 1);
+  if (cent != 1.0) { 
+    fprintf(stderr, "in-star, degree: %g\n", cent); 
+    return 1; 
+  }
+
+  igraph_centralization_betweenness(&g, /*res=*/ 0,
+				    IGRAPH_UNDIRECTED, /*nobigint=*/ 1, &cent, 
+				    /*theoretical_max=*/ 0,
+				    /*normalized=*/ 1);
+  if (cent != 1.0) { 
+    fprintf(stderr, "in-star, betweenness: %g\n", cent); 
+    return 2; 
+  }
+
+  igraph_centralization_closeness(&g, /*res=*/ 0,
+				  IGRAPH_IN, &cent, 
+				  /*theoretical_max=*/ 0,
+				  /*normalization=*/ 1);
+  
+  if (!ALMOST_EQUALS(cent, 1.0)) {
+    fprintf(stderr, "in-star, closeness: %g\n", cent);
+    return 3;
+  }
+
+  igraph_destroy(&g);
+  
+  /****************************/
+  /* out-star */
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, /*center=*/ 0);
+  
+  igraph_centralization_degree(&g, /*res=*/ 0,
+			       /*mode=*/ IGRAPH_OUT, IGRAPH_NO_LOOPS,
+			       &cent, /*theoretical_max=*/ 0,
+			       /*normalized=*/ 1);
+  if (cent != 1.0) { 
+    fprintf(stderr, "out-star, degree: %g\n", cent); 
+    return 11; 
+  }
+
+  igraph_centralization_betweenness(&g, /*res=*/ 0,
+				    IGRAPH_UNDIRECTED, /*nobigint=*/ 1, &cent,
+				    /*theoretical_max=*/ 0,
+				    /*normalized=*/ 1);
+  if (cent != 1.0) { 
+    fprintf(stderr, "out-star, betweenness: %g\n", cent); 
+    return 12; 
+  }
+
+  igraph_centralization_closeness(&g, /*res=*/ 0,
+				  IGRAPH_OUT, &cent, 
+				  /*theoretical_max=*/ 0,
+				  /*normalization=*/ 1);
+  
+  if (!ALMOST_EQUALS(cent, 1.0)) {
+    fprintf(stderr, "out-star, closeness: %g\n", cent);
+    return 13;
+  }
+
+  igraph_destroy(&g);
+  
+  /****************************/
+  /* undricted star */
+  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, /*center=*/ 0);
+  
+  igraph_centralization_degree(&g, /*res=*/ 0,
+			       /*mode=*/ IGRAPH_ALL, IGRAPH_NO_LOOPS,
+			       &cent, /*theoretical_max=*/ 0,
+			       /*normalized=*/ 1);
+  if (cent != 1.0) { 
+    fprintf(stderr, "undirected star, degree: %g\n", cent); 
+    return 21; 
+  }
+
+  igraph_centralization_betweenness(&g, /*res=*/ 0,
+				    IGRAPH_UNDIRECTED, /*nobigint=*/ 1, &cent,
+				    /*theoretical_max=*/ 0,
+				    /*normalized=*/ 1);
+  if (cent != 1.0) { 
+    fprintf(stderr, "undirected star, betweenness: %g\n", cent); 
+    return 22; 
+  }
+
+  igraph_centralization_closeness(&g, /*res=*/ 0,
+				  IGRAPH_ALL, &cent, 
+				  /*theoretical_max=*/ 0,
+				  /*normalization=*/ 1);
+  
+  if (!ALMOST_EQUALS(cent, 1.0)) {
+    fprintf(stderr, "undirected star, closeness: %g\n", cent);
+    return 23;
+  }
+  
+  igraph_destroy(&g);
+
+  /****************************/
+  /* single dyad */
+  
+  igraph_small(&g, /*n=*/ 10, /*directed=*/ 0, 
+	       0,1, -1);
+  
+  igraph_arpack_options_init(&arpack_options);
+  igraph_centralization_eigenvector_centrality(&g, /*vector=*/ 0,
+					       /*value=*/ 0, 
+					       /*directed=*/ 1,
+					       /*scale=*/ 1,
+					       &arpack_options, &cent,
+					       /*theoretical_max=*/ 0,
+					       /*normalization=*/ 1);
+  
+  if (!ALMOST_EQUALS(cent, 1.0)) {
+    fprintf(stderr, "dyad, eigenvector centrality: %g\n", cent);
+    return 24;
+  }
+
+  igraph_centralization_eigenvector_centrality(&g, /*vector=*/ 0,
+					       /*value=*/ 0, 
+					       /*directed=*/ 1,
+					       /*scale=*/ 0,
+					       &arpack_options, &cent,
+					       /*theoretical_max=*/ 0,
+					       /*normalization=*/ 1);
+  
+  if (!ALMOST_EQUALS(cent, 1.0)) {
+    fprintf(stderr, "dyad, eigenvector centrality, not scaled: %g\n", cent);
+    return 25;
+  }
+    
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/cohesive_blocks.c b/examples/simple/cohesive_blocks.c
new file mode 100644
index 0000000..f7e47a2
--- /dev/null
+++ b/examples/simple/cohesive_blocks.c
@@ -0,0 +1,174 @@
+/* -*- 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.h>
+
+int doit(igraph_t *g) {
+
+  igraph_vector_ptr_t blocks;
+  igraph_vector_t cohesion;
+  igraph_vector_t parent;
+  igraph_t block_tree;
+  long int i;
+
+  igraph_vector_ptr_init(&blocks, 0);
+  igraph_vector_init(&cohesion, 0);
+  igraph_vector_init(&parent, 0);
+
+  igraph_cohesive_blocks(g, &blocks, &cohesion, &parent, 
+			 &block_tree);
+  
+  printf("Blocks:\n");
+  for (i=0; i<igraph_vector_ptr_size(&blocks); i++) {
+    igraph_vector_t *sg=VECTOR(blocks)[i];
+    printf("  "); igraph_vector_print(sg);
+    igraph_vector_destroy(sg);
+    igraph_free(sg);
+  }
+  printf("Cohesion:\n  ");  igraph_vector_print(&cohesion);
+  printf("Parents:\n  ");   igraph_vector_print(&parent);
+  printf("Block graph:\n"); igraph_write_graph_edgelist(&block_tree, stdout);
+
+  igraph_vector_ptr_destroy(&blocks);
+  igraph_vector_destroy(&cohesion);
+  igraph_vector_destroy(&parent);
+  igraph_destroy(&block_tree);
+
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  int ret;
+
+  /* --------------------------------------------------------*/
+  /* The graph from the Moody-White paper                    */
+
+  igraph_small(&g, 23, IGRAPH_UNDIRECTED,
+	       0,1, 0,2, 0,3, 0,4, 0,5,
+	       1,2, 1,3, 1,4, 1,6,
+	       2,3, 2,5, 2,6,
+	       3,4, 3,5, 3,6,
+	       4,5, 4,6, 4,20,
+	       5,6, 
+	       6,7, 6,10, 6,13, 6,18,
+	       7,8, 7,10, 7,13,
+	       8,9,
+	       9,11, 9,12,
+	       10,11, 10,13,
+	       11,15,
+	       12,15,
+	       13,14,
+	       14,15,
+	       16,17, 16,18, 16,19,
+	       17,19, 17,20,
+	       18,19, 18,21, 18,22,
+	       19,20,
+	       20,21, 20,22,
+	       21,22,
+	       -1);
+  
+  if ( (ret=doit(&g)) ) { return ret; }
+  igraph_destroy(&g);
+  printf("--\n");
+
+  /* --------------------------------------------------------*/
+  /* A tricky graph, where the separators themselves         */
+  /* form a block. But recently we don't include this        */
+  /* block in the results.                                   */
+
+  igraph_small(&g, 8, IGRAPH_UNDIRECTED,
+	       0,1,0,4,0,5, 1,2,1,4,1,5,1,6, 2,3,2,5,2,6,2,7,
+	       3,6,3,7, 4,5, 5,6, 6,7, 
+	       -1);
+  
+  if ( (ret=doit(&g)) ) { return ret; }
+  igraph_destroy(&g);
+  printf("--\n");  
+
+  /* --------------------------------------------------------*/
+  /* The science camp graph from http://intersci.ss.uci.edu/ */
+  /* wiki/index.php/Cohesive_blocking                        */
+
+  igraph_small(&g, 18, IGRAPH_UNDIRECTED, 
+	       0,1,0,2,0,3, 
+	       1,2,1,3,1,16,1,17, 
+	       2,3, 
+	       3,17, 
+	       4,5,4,6,4,7,4,8,
+	       5,6,5,7, 
+	       6,7,6,8,
+	       7,8,7,16,
+	       8,9,8,10,
+	       9,11,9,12,9,13,9,14,
+	       10,11,10,12,10,13,
+	       11,14,
+	       12,13,12,14,12,15,
+	       15,16,15,17,
+	       16,17,
+	       -1);
+	       
+  if ( (ret=doit(&g)) ) { return ret; }
+  igraph_destroy(&g);
+  printf("--\n");  
+
+  /* --------------------------------------------------------*/
+  /* Zachary karate-club                                     */
+  
+  igraph_small(&g, 34, IGRAPH_UNDIRECTED,
+	       0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,10,0,11,0,12,0,13,
+	       0,17,0,19,0,21,0,31,
+	       1,2,1,3,1,7,1,13,1,17,1,19,1,21,1,30,
+	       2,3,2,7,2,27,2,28,2,32,2,9,2,8,2,13,
+	       3,7,3,12,3,13,
+	       4,6,4,10,
+	       5,6,5,10,5,16,
+	       6,16,
+	       8,30,8,32,8,33,
+	       9,33,
+	       13,33,
+	       14,32,14,33,
+	       15,32,15,33,
+	       18,32,18,33,
+	       19,33,
+	       20,32,20,33,
+	       22,32,22,33,
+	       23,25,23,27,23,32,23,33,23,29,
+	       24,25,24,27,24,31,
+	       25,31,
+	       26,29,26,33,
+	       27,33,
+	       28,31,28,33,
+	       29,32,29,33,
+	       30,32,30,33,
+	       31,32,31,33,
+	       32,33,
+	       -1);
+
+  if ( (ret=doit(&g)) ) { return ret; }
+  igraph_destroy(&g);
+  printf("--\n");  
+  
+  return 0;
+}
diff --git a/examples/simple/cohesive_blocks.out b/examples/simple/cohesive_blocks.out
new file mode 100644
index 0000000..85e0610
--- /dev/null
+++ b/examples/simple/cohesive_blocks.out
@@ -0,0 +1,66 @@
+Blocks:
+  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
+  0 1 2 3 4 5 6 16 17 18 19 20 21 22
+  6 7 8 9 10 11 12 13 14 15
+  0 1 2 3 4 5 6
+  6 7 10 13
+Cohesion:
+  1 2 2 5 3
+Parents:
+  -1 0 0 1 2
+Block graph:
+0 1
+0 2
+1 3
+2 4
+--
+Blocks:
+  0 1 2 3 4 5 6 7
+  0 1 4 5
+  2 3 6 7
+  1 2 5 6
+Cohesion:
+  2 3 3 3
+Parents:
+  -1 0 0 0
+Block graph:
+0 1
+0 2
+0 3
+--
+Blocks:
+  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+  0 1 2 3
+  4 5 6 7 8
+  9 10 11 12 13 14
+Cohesion:
+  2 3 3 3
+Parents:
+  -1 0 0 0
+Block graph:
+0 1
+0 2
+0 3
+--
+Blocks:
+  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
+  0 1 2 3 7 8 9 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
+  0 4 5 6 10 16
+  0 1 2 3 7
+  0 1 2 8 30 32 33
+  0 4 5 6 10
+  0 1 2 3 13
+  2 23 24 25 27 28 29 31 32 33
+Cohesion:
+  1 2 2 4 3 3 4 3
+Parents:
+  -1 0 0 1 1 2 1 1
+Block graph:
+0 1
+0 2
+1 3
+1 4
+1 6
+1 7
+2 5
+--
diff --git a/examples/simple/d_indheap.c b/examples/simple/d_indheap.c
new file mode 100644
index 0000000..e85c73c
--- /dev/null
+++ b/examples/simple/d_indheap.c
@@ -0,0 +1,100 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <igraph_types_internal.h>
+
+int main() {
+  
+  igraph_d_indheap_t h;
+  long int idx1, idx2;
+
+  /* igraph_d_indheap_init, igraph_d_indheap_destroy */
+  igraph_d_indheap_init(&h, 0);
+  igraph_d_indheap_destroy(&h);
+  igraph_d_indheap_init(&h, 100);
+  igraph_d_indheap_destroy(&h);  
+
+  /* igraph_d_indheap_empty, igraph_d_indheap_size */
+  igraph_d_indheap_init(&h, 10);
+  if (!igraph_d_indheap_empty(&h)) {
+    return 1;
+  }
+  if (igraph_d_indheap_size(&h) != 0) {
+    return 2;
+  }
+  igraph_d_indheap_push(&h, 10, 0, 0);
+  if (igraph_d_indheap_empty(&h)) {
+    return 3;
+  }
+  if (igraph_d_indheap_size(&h) != 1) {
+    return 4;
+  }
+  
+  /* igraph_d_indheap_push */
+  igraph_d_indheap_push(&h, 9, 9, 8);  
+  igraph_d_indheap_push(&h, 3, 3, 2);  
+  igraph_d_indheap_push(&h, 2, 2, 1);  
+  igraph_d_indheap_push(&h, 1, 1, 0);  
+  igraph_d_indheap_push(&h, 7, 7, 6);  
+  igraph_d_indheap_push(&h, 4, 4, 3);  
+  igraph_d_indheap_push(&h, 0, 0, 1);  
+  igraph_d_indheap_push(&h, 6, 6, 5);  
+  igraph_d_indheap_push(&h, 5, 5, 4);  
+  igraph_d_indheap_push(&h, 8, 8, 7);  
+
+  /* igraph_d_indheap_max, igraph_d_indheap_delete_max */
+  while (!igraph_d_indheap_empty(&h)) {
+    printf("% li", (long int)igraph_d_indheap_max(&h));
+    printf("% li\n", (long int)igraph_d_indheap_delete_max(&h));
+  }
+
+  /* igraph_d_indheap_reserve */
+  igraph_d_indheap_reserve(&h, 5);
+  igraph_d_indheap_reserve(&h, 20);
+  igraph_d_indheap_reserve(&h, 0);
+  igraph_d_indheap_reserve(&h, 3);
+  
+  /* igraph_d_indheap_max_index */
+  igraph_d_indheap_push(&h, 0, 0, 1);  
+  igraph_d_indheap_push(&h, 8, 8, 7);  
+  igraph_d_indheap_push(&h, 2, 2, 1);  
+  igraph_d_indheap_push(&h, 7, 7, 6);  
+  igraph_d_indheap_push(&h, 9, 9, 8);  
+  igraph_d_indheap_push(&h, 4, 4, 3);  
+  igraph_d_indheap_push(&h, 3, 3, 2);  
+  igraph_d_indheap_push(&h, 5, 5, 4);  
+  igraph_d_indheap_push(&h, 1, 1, 0);  
+  igraph_d_indheap_push(&h, 6, 6, 5);  
+  while (!igraph_d_indheap_empty(&h)) {
+    igraph_d_indheap_max_index(&h, &idx1, &idx2);
+    printf(" %li %li", idx1, idx2);
+    igraph_d_indheap_delete_max(&h);
+  }
+  printf("\n");
+  igraph_d_indheap_destroy(&h);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 5;
+  
+  return 0;
+}
diff --git a/examples/simple/d_indheap.out b/examples/simple/d_indheap.out
new file mode 100644
index 0000000..7b58a46
--- /dev/null
+++ b/examples/simple/d_indheap.out
@@ -0,0 +1,12 @@
+ 10 10
+ 9 9
+ 8 8
+ 7 7
+ 6 6
+ 5 5
+ 4 4
+ 3 3
+ 2 2
+ 1 1
+ 0 0
+ 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 0 0 1
diff --git a/examples/simple/dijkstra.c b/examples/simple/dijkstra.c
new file mode 100644
index 0000000..f754701
--- /dev/null
+++ b/examples/simple/dijkstra.c
@@ -0,0 +1,68 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+
+int print_matrix(const igraph_matrix_t *m) {
+  long int nrow=igraph_matrix_nrow(m);
+  long int ncol=igraph_matrix_ncol(m);
+  long int i, j;
+  for (i=0; i<nrow; i++) {
+    printf("%li:", i);
+    for (j=0; j<ncol; j++) {
+      printf(" %3.0F", MATRIX(*m, i, j));
+    }
+    printf("\n");
+  }
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t weights;
+  igraph_real_t weights_data[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
+  igraph_matrix_t res;
+  
+  igraph_small(&g, 10, IGRAPH_DIRECTED, 
+	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
+	       2,3, 2,6,         3,2, 3,6,
+	       4,5, 4,7,         5,6, 5,8, 5,9,
+	       7,5, 7,8,         8,9,
+	       5,2,
+	       2,1,
+	       -1);
+  
+  igraph_vector_view(&weights, weights_data, 
+		     sizeof(weights_data)/sizeof(igraph_real_t));
+  
+  igraph_matrix_init(&res, 0, 0);
+  igraph_shortest_paths_dijkstra(&g, &res, igraph_vss_all(), igraph_vss_all(),
+				 &weights, IGRAPH_OUT);
+  print_matrix(&res);
+  
+  igraph_matrix_destroy(&res);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/dijkstra.out b/examples/simple/dijkstra.out
new file mode 100644
index 0000000..1c6691c
--- /dev/null
+++ b/examples/simple/dijkstra.out
@@ -0,0 +1,10 @@
+0:   0   0   0   1   5   2   1  13   3   5
+1: INF   0   0   1   5   2   1  13   3   5
+2: INF   1   0   1   6   3   1  14   4   6
+3: INF   1   0   0   6   3   1  14   4   6
+4: INF   5   4   5   0   2   3   8   3   5
+5: INF   3   2   3   8   0   1  16   1   3
+6: INF INF INF INF INF INF   0 INF INF INF
+7: INF   4   3   4   9   1   2   0   1   4
+8: INF INF INF INF INF INF INF INF   0   4
+9: INF INF INF INF INF INF INF INF INF   0
diff --git a/examples/simple/dominator_tree.c b/examples/simple/dominator_tree.c
new file mode 100644
index 0000000..a9206d3
--- /dev/null
+++ b/examples/simple/dominator_tree.c
@@ -0,0 +1,165 @@
+/* -*- 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.h>
+#include <stdio.h>
+
+int main() {
+
+  igraph_t g, domtree;
+  igraph_vector_t dom, leftout;
+
+  igraph_vector_init(&dom, 0);
+  igraph_small(&g, 13, IGRAPH_DIRECTED,
+	       0,1, 0,7, 0,10,
+	       1,2, 1,5,
+	       2,3,
+	       3,4,
+	       4,3, 4,0,
+	       5,3, 5,6,
+	       6,3,
+	       7,8, 7,10, 7,11,
+	       8,9,
+	       9,4, 9,8,
+	       10,11,
+	       11,12,
+	       12,9,
+	       -1);
+
+  /* Check NULL vector arguments */
+  igraph_dominator_tree(&g, /*root=*/ 0, /*dom=*/ 0, /*domtree=*/ 0,
+			/*leftout=*/ 0, /*mode=*/ IGRAPH_OUT);
+
+  /* Proper calculation */
+  igraph_dominator_tree(&g, /*root=*/ 0, &dom, /*domtree=*/ 0,
+			/*leftout=*/ 0, /*mode=*/ IGRAPH_OUT);
+  igraph_vector_print(&dom);
+
+  /* Tree calculation */
+  igraph_dominator_tree(&g, /*root=*/ 0, /*dom=*/ 0, /*domtree=*/ &domtree,
+			/*leftout=*/ 0, /*mode=*/ IGRAPH_OUT);
+  igraph_write_graph_edgelist(&domtree, stdout);
+  
+  igraph_vector_destroy(&dom);
+  igraph_destroy(&domtree);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------------------------------*/
+  
+  igraph_vector_init(&dom, 0);
+  igraph_small(&g, 13, IGRAPH_DIRECTED,
+	       1,0, 2,0, 3,0,
+	       4,1,
+	       1,2, 4,2, 5,2,
+	       6,3, 7,3,
+	       12,4,
+	       8,5, 
+	       9,6,
+	       9,7, 10,7,
+	       5,8, 11,8,
+	       11,9,
+	       9,10,
+	       9,11, 0,11,
+	       8,12,
+	       -1);
+
+  /* Check NULL vector arguments */
+  igraph_dominator_tree(&g, /*root=*/ 0, /*dom=*/ 0, /*domtree=*/ 0,
+			/*leftout=*/ 0, /*mode=*/ IGRAPH_IN);
+
+  /* Proper calculation */
+  igraph_dominator_tree(&g, /*root=*/ 0, &dom, /*domtree=*/ 0,
+			/*leftout=*/ 0, /*mode=*/ IGRAPH_IN);
+  igraph_vector_print(&dom);
+
+  /* Tree calculation */
+  igraph_dominator_tree(&g, /*root=*/ 0, /*dom=*/ 0, /*domtree=*/ &domtree,
+			/*leftout=*/ 0, /*mode=*/ IGRAPH_IN);
+  igraph_write_graph_edgelist(&domtree, stdout);
+  
+  igraph_vector_destroy(&dom);
+  igraph_destroy(&domtree);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------------------------------*/
+
+  igraph_vector_init(&dom, 0);
+  igraph_vector_init(&leftout, 0);
+
+  /* Check a graph with more components */
+  igraph_small(&g, 20, IGRAPH_DIRECTED,
+	       0,1, 0,2, 0,3,
+	       1,4,
+	       2,1, 2,4, 2,8,
+	       3,9, 3,10,
+	       4,15,
+	       8,11, 
+	       9,12,
+	       10,12, 10,13,
+	       11,8, 11,14,
+	       12,14,
+	       13,12,
+	       14,12, 14,0,
+	       15,11,
+	       -1);
+
+  igraph_dominator_tree(&g, /*root=*/ 0, &dom, &domtree,
+			&leftout, /*mode=*/ IGRAPH_OUT);
+  igraph_vector_print(&dom);
+  igraph_vector_print(&leftout);
+  igraph_write_graph_edgelist(&domtree, stdout);
+
+  igraph_vector_destroy(&dom);
+  igraph_vector_destroy(&leftout);
+  igraph_destroy(&domtree);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------------------------------*/
+
+  igraph_vector_init(&dom, 0);
+  igraph_vector_init(&leftout, 0);
+  
+  igraph_small(&g, 10, IGRAPH_DIRECTED, 
+	       0,9,
+	       1,0, 1,2,
+	       2,3, 2,7,
+	       3,1,
+	       4,1, 4,3,
+	       5,2, 5,3, 5,4, 5,8,
+	       6,5, 6,9,
+	       8,7,
+	       -1);
+  
+  igraph_dominator_tree(&g, /*root=*/ 9, &dom, &domtree,
+			&leftout, /*mode=*/ IGRAPH_IN);
+  igraph_vector_print(&dom);
+  igraph_vector_print(&leftout);
+  igraph_write_graph_edgelist(&domtree, stdout);
+   
+  igraph_vector_destroy(&dom);
+  igraph_vector_destroy(&leftout);
+  igraph_destroy(&domtree);
+  igraph_destroy(&g);
+ 
+  return 0;
+}
diff --git a/examples/simple/dominator_tree.out b/examples/simple/dominator_tree.out
new file mode 100644
index 0000000..680151a
--- /dev/null
+++ b/examples/simple/dominator_tree.out
@@ -0,0 +1,49 @@
+-1 0 1 0 0 1 5 0 0 0 0 0 11
+0 1
+0 3
+0 4
+0 7
+0 8
+0 9
+0 10
+0 11
+1 2
+1 5
+5 6
+11 12
+-1 0 0 0 0 0 3 3 0 0 7 0 4
+1 0
+2 0
+3 0
+4 0
+5 0
+6 3
+7 3
+8 0
+9 0
+10 7
+11 0
+12 4
+-1 0 0 0 0 NaN NaN NaN 0 3 3 0 0 10 0 4 NaN NaN NaN NaN
+5 6 7 16 17 18 19
+0 1
+0 2
+0 3
+0 4
+0 8
+0 11
+0 12
+0 14
+3 9
+3 10
+4 15
+10 13
+9 0 3 1 1 1 9 NaN NaN -1
+7 8
+0 9
+1 0
+2 3
+3 1
+4 1
+5 1
+6 9
diff --git a/examples/simple/dot.c b/examples/simple/dot.c
new file mode 100644
index 0000000..d47b7c2
--- /dev/null
+++ b/examples/simple/dot.c
@@ -0,0 +1,52 @@
+/* -*- 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.h>
+#include <stdio.h>
+
+int main() {
+
+  igraph_t g;
+  FILE *ifile;
+  
+  ifile=fopen("karate.gml", "r");
+  if (ifile==0) {
+    return 10;
+  }
+  
+  igraph_read_graph_gml(&g, ifile);
+  fclose(ifile);
+
+  if (igraph_is_directed(&g)) {
+    printf("directed\n");
+  } else {
+    printf("undirected\n");
+  }
+    
+  igraph_write_graph_edgelist(&g, stdout);
+  printf("-----------------\n");
+  igraph_write_graph_dot(&g, stdout);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/dot.out b/examples/simple/dot.out
new file mode 100644
index 0000000..a959aeb
--- /dev/null
+++ b/examples/simple/dot.out
@@ -0,0 +1,196 @@
+undirected
+0 1
+0 2
+0 3
+0 4
+0 5
+0 6
+0 7
+0 8
+0 10
+0 11
+0 12
+0 13
+0 17
+0 19
+0 21
+0 31
+1 2
+1 3
+1 7
+1 13
+1 17
+1 19
+1 21
+1 30
+2 3
+2 7
+2 8
+2 9
+2 13
+2 27
+2 28
+2 32
+3 7
+3 12
+3 13
+4 6
+4 10
+5 6
+5 10
+5 16
+6 16
+8 30
+8 32
+8 33
+9 33
+13 33
+14 32
+14 33
+15 32
+15 33
+18 32
+18 33
+19 33
+20 32
+20 33
+22 32
+22 33
+23 25
+23 27
+23 29
+23 32
+23 33
+24 25
+24 27
+24 31
+25 31
+26 29
+26 33
+27 33
+28 31
+28 33
+29 32
+29 33
+30 32
+30 33
+31 32
+31 33
+32 33
+-----------------
+/* Created by igraph @VERSION@ */
+graph {
+  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;
+
+  1 -- 0;
+  2 -- 0;
+  2 -- 1;
+  3 -- 0;
+  3 -- 1;
+  3 -- 2;
+  4 -- 0;
+  5 -- 0;
+  6 -- 0;
+  6 -- 4;
+  6 -- 5;
+  7 -- 0;
+  7 -- 1;
+  7 -- 2;
+  7 -- 3;
+  8 -- 0;
+  8 -- 2;
+  9 -- 2;
+  10 -- 0;
+  10 -- 4;
+  10 -- 5;
+  11 -- 0;
+  12 -- 0;
+  12 -- 3;
+  13 -- 0;
+  13 -- 1;
+  13 -- 2;
+  13 -- 3;
+  16 -- 5;
+  16 -- 6;
+  17 -- 0;
+  17 -- 1;
+  19 -- 0;
+  19 -- 1;
+  21 -- 0;
+  21 -- 1;
+  25 -- 23;
+  25 -- 24;
+  27 -- 2;
+  27 -- 23;
+  27 -- 24;
+  28 -- 2;
+  29 -- 23;
+  29 -- 26;
+  30 -- 1;
+  30 -- 8;
+  31 -- 0;
+  31 -- 24;
+  31 -- 25;
+  31 -- 28;
+  32 -- 2;
+  32 -- 8;
+  32 -- 14;
+  32 -- 15;
+  32 -- 18;
+  32 -- 20;
+  32 -- 22;
+  32 -- 23;
+  32 -- 29;
+  32 -- 30;
+  32 -- 31;
+  33 -- 8;
+  33 -- 9;
+  33 -- 13;
+  33 -- 14;
+  33 -- 15;
+  33 -- 18;
+  33 -- 19;
+  33 -- 20;
+  33 -- 22;
+  33 -- 23;
+  33 -- 26;
+  33 -- 27;
+  33 -- 28;
+  33 -- 29;
+  33 -- 30;
+  33 -- 31;
+  33 -- 32;
+}
diff --git a/examples/simple/dqueue.c b/examples/simple/dqueue.c
new file mode 100644
index 0000000..6a6ca6c
--- /dev/null
+++ b/examples/simple/dqueue.c
@@ -0,0 +1,117 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <igraph_dqueue.h>
+
+int main() {
+  
+  igraph_dqueue_t q;
+  int i;
+
+  /* igraph_dqueue_init, igraph_dqueue_destroy, igraph_dqueue_empty */
+  igraph_dqueue_init(&q, 5);
+  if (!igraph_dqueue_empty(&q)) {
+    return 1;
+  }
+  igraph_dqueue_destroy(&q);
+
+  /* igraph_dqueue_push, igraph_dqueue_pop */
+  igraph_dqueue_init(&q, 4);
+  igraph_dqueue_push(&q, 1);
+  igraph_dqueue_push(&q, 2);
+  igraph_dqueue_push(&q, 3);
+  igraph_dqueue_push(&q, 4);
+  if (igraph_dqueue_pop(&q) != 1) {
+    return 2;
+  }
+  if (igraph_dqueue_pop(&q) != 2) {
+    return 3;
+  }
+  if (igraph_dqueue_pop(&q) != 3) {
+    return 4;
+  }
+  if (igraph_dqueue_pop(&q) != 4) {
+    return 5;
+  }
+  igraph_dqueue_destroy(&q);
+
+  /* igraph_dqueue_clear, igraph_dqueue_size */
+  igraph_dqueue_init(&q, 0);
+  if (igraph_dqueue_size(&q) != 0) {
+    return 6;
+  }
+  igraph_dqueue_clear(&q);
+  if (igraph_dqueue_size(&q) != 0) {
+    return 7;
+  }
+  for (i=0; i<10; i++) {
+    igraph_dqueue_push(&q, i);
+  }
+  igraph_dqueue_clear(&q);
+  if (igraph_dqueue_size(&q) != 0) {
+    return 8;
+  }
+  igraph_dqueue_destroy(&q);
+
+  /* TODO: igraph_dqueue_full */
+
+  /* igraph_dqueue_head, igraph_dqueue_back, igraph_dqueue_pop_back */
+  igraph_dqueue_init(&q, 0);
+  for (i=0; i<10; i++) {
+    igraph_dqueue_push(&q, i);
+  }
+  for (i=0; i<10; i++) {
+    if (igraph_dqueue_head(&q) != 0) {
+      return 9;
+    }
+    if (igraph_dqueue_back(&q) != 9-i) {
+      return 10;
+    }
+    if (igraph_dqueue_pop_back(&q) != 9-i) {
+      return 11;
+    }
+  }
+  igraph_dqueue_destroy(&q);
+
+  /* print */
+  igraph_dqueue_init(&q, 4);
+  igraph_dqueue_push(&q, 1);
+  igraph_dqueue_push(&q, 2);
+  igraph_dqueue_push(&q, 3);
+  igraph_dqueue_push(&q, 4);
+  igraph_dqueue_pop(&q);
+  igraph_dqueue_pop(&q);
+  igraph_dqueue_push(&q, 5);
+  igraph_dqueue_push(&q, 6);
+  igraph_dqueue_print(&q);
+
+  igraph_dqueue_clear(&q);
+  igraph_dqueue_print(&q);
+  
+  igraph_dqueue_destroy(&q);  
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 12;  
+
+  return 0;
+}
diff --git a/examples/simple/dqueue.out b/examples/simple/dqueue.out
new file mode 100644
index 0000000..02defa8
--- /dev/null
+++ b/examples/simple/dqueue.out
@@ -0,0 +1,2 @@
+3 4 5 6
+
diff --git a/examples/simple/edgelist1.dl b/examples/simple/edgelist1.dl
new file mode 100644
index 0000000..609bc6f
--- /dev/null
+++ b/examples/simple/edgelist1.dl
@@ -0,0 +1,10 @@
+DL n=5
+format = edgelist1
+labels:
+george, sally, jim, billy, jane
+data:
+1 2
+1 3
+2 3
+3 1
+4 3 
diff --git a/examples/simple/edgelist2.dl b/examples/simple/edgelist2.dl
new file mode 100644
index 0000000..091090e
--- /dev/null
+++ b/examples/simple/edgelist2.dl
@@ -0,0 +1,9 @@
+DL n=5
+format = edgelist1
+labels embedded:
+data:
+george sally
+george jim
+sally jim
+billy george
+jane jim 
diff --git a/examples/simple/edgelist3.dl b/examples/simple/edgelist3.dl
new file mode 100644
index 0000000..3bddc4e
--- /dev/null
+++ b/examples/simple/edgelist3.dl
@@ -0,0 +1,11 @@
+DL n=5
+format = edgelist1
+labels:
+george, sally, jim, billy, jane
+labels embedded:
+data:
+george sally
+george jim
+sally jim
+billy george
+jane jim 
diff --git a/examples/simple/edgelist4.dl b/examples/simple/edgelist4.dl
new file mode 100644
index 0000000..3a8a091
--- /dev/null
+++ b/examples/simple/edgelist4.dl
@@ -0,0 +1,12 @@
+DL n=5
+format = edgelist1
+labels:
+george, sally, jim, billy, jane
+data:
+1 2
+1 3 -1
+2 3
+3 1 -1
+4 3 
+
+  
diff --git a/examples/simple/edgelist5.dl b/examples/simple/edgelist5.dl
new file mode 100644
index 0000000..bcd8403
--- /dev/null
+++ b/examples/simple/edgelist5.dl
@@ -0,0 +1,9 @@
+DL n=5
+format = edgelist1
+labels embedded:
+data:
+george sally     0.1
+george jim       0.5
+sally jim
+billy george     1
+jane jim 
diff --git a/examples/simple/edgelist6.dl b/examples/simple/edgelist6.dl
new file mode 100644
index 0000000..df7db54
--- /dev/null
+++ b/examples/simple/edgelist6.dl
@@ -0,0 +1,11 @@
+DL n=5
+format = edgelist1
+labels:
+george, sally, jim, billy, jane
+labels embedded:
+data:
+george sally
+george jim       2
+sally jim
+billy george     1
+jane jim         1e-5
diff --git a/examples/simple/eigenvector_centrality.c b/examples/simple/eigenvector_centrality.c
new file mode 100644
index 0000000..ce8fa53
--- /dev/null
+++ b/examples/simple/eigenvector_centrality.c
@@ -0,0 +1,85 @@
+/* -*- 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.h"
+
+#include <math.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t v, weights;
+  long int i;
+  igraph_real_t value;
+  igraph_arpack_options_t options;
+  
+  igraph_star(&g, 100, IGRAPH_STAR_UNDIRECTED, 0);
+
+  igraph_arpack_options_init(&options);
+  igraph_vector_init(&v, 0);
+  igraph_eigenvector_centrality(&g, &v, &value, /*directed=*/ 0, 
+				/*scale=*/0, /*weights=*/0, 
+				&options);
+
+  if (options.info != 0) {
+    return 1;
+  }
+
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    printf(" %.3f", fabs(VECTOR(v)[i]));
+  }
+  printf("\n");
+  
+  igraph_destroy(&g);
+
+  /* Special cases: check for empty graph */
+  igraph_empty(&g, 10, 0);
+  igraph_eigenvector_centrality(&g, &v, &value, 0, 0, 0, &options);
+  if (value != 0.0) {
+    return 1;
+  }
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    printf(" %.2f", fabs(VECTOR(v)[i]));
+  }
+  printf("\n");
+  igraph_destroy(&g);
+
+  /* Special cases: check for full graph, zero weights */
+  igraph_full(&g, 10, 0, 0);
+  igraph_vector_init(&weights, 45);
+  igraph_vector_fill(&weights, 0);
+  igraph_eigenvector_centrality(&g, &v, &value, 0, 0, &weights, &options);
+  igraph_vector_destroy(&weights);
+  if (value != 0.0) {
+    return 2;
+  }
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    printf(" %.2f", fabs(VECTOR(v)[i]));
+  }
+  printf("\n");
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&v);
+
+  return 0;
+}
diff --git a/examples/simple/eigenvector_centrality.out b/examples/simple/eigenvector_centrality.out
new file mode 100644
index 0000000..2fae1b3
--- /dev/null
+++ b/examples/simple/eigenvector_centrality.out
@@ -0,0 +1,3 @@
+ 0.707 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 0.071 [...]
+ 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00
+ 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00
diff --git a/examples/simple/even_tarjan.c b/examples/simple/even_tarjan.c
new file mode 100644
index 0000000..e745c24
--- /dev/null
+++ b/examples/simple/even_tarjan.c
@@ -0,0 +1,66 @@
+/* -*- 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.h>
+#include <limits.h>
+
+int main() {
+
+  igraph_t g, gbar;
+  igraph_integer_t k1, k2 = (igraph_integer_t) INT_MAX;
+  igraph_real_t tmpk;
+  long int i, j, n;
+  igraph_maxflow_stats_t stats;
+
+  /* --------------------------------------------------- */
+  
+  igraph_famous(&g, "meredith");
+  igraph_even_tarjan_reduction(&g, &gbar, /*capacity=*/ 0);
+  
+  igraph_vertex_connectivity(&g, &k1, /* checks= */ 0);
+
+  n=igraph_vcount(&g);
+  for (i=0; i<n; i++) {
+    for (j=i+1; j<n; j++) {
+      igraph_bool_t conn;
+      igraph_are_connected(&g, i, j, &conn);
+      if (conn) { continue; }
+      igraph_maxflow_value(&gbar, &tmpk, 
+			   /* source= */ i + n, 
+			   /* target= */ j, 
+			   /* capacity= */ 0,
+			   &stats);
+      if (tmpk < k2) { k2=tmpk; }
+    }
+  }
+
+  igraph_destroy(&gbar);
+  igraph_destroy(&g);
+  
+  if (k1 != k2) {
+    printf("k1 = %ld while k2 = %ld\n", (long int) k1, (long int) k2);
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/flow.c b/examples/simple/flow.c
new file mode 100644
index 0000000..b2305dd
--- /dev/null
+++ b/examples/simple/flow.c
@@ -0,0 +1,120 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+float timer ()
+{
+  struct rusage r;
+
+  getrusage(0, &r);
+  return (float)(r.ru_utime.tv_sec+r.ru_utime.tv_usec/(float)1000000);
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_real_t flow;
+  igraph_vector_t capacity;
+  igraph_integer_t source, target;
+  FILE *infile;
+  float t;
+  igraph_maxflow_stats_t stats;
+
+  igraph_vector_init(&capacity, 0);
+
+  /***************/
+  infile=fopen("ak-4102.max", "r");
+  igraph_read_graph_dimacs(&g, infile, 0, 0, &source, &target, &capacity,
+			   IGRAPH_DIRECTED);
+  fclose(infile);
+
+  t=timer();
+  igraph_maxflow_value(&g, &flow, source, target, &capacity, &stats);
+  t=timer()-t;
+/*   printf("4102: %g (time %.10f)\n", flow, t); */
+  if (flow != 8207) {
+    return 1;
+  }
+  igraph_destroy(&g);  
+  /***************/
+
+/*   /\***************\/ */
+/*   infile=fopen("ak-8198.max", "r"); */
+/*   igraph_read_graph_dimacs(&g, infile, 0, 0, &source, &target, &capacity, */
+/* 			   IGRAPH_DIRECTED); */
+/*   fclose(infile); */
+
+/*   t=timer(); */
+/*   igraph_maxflow_value(&g, &flow, source, target, &capacity, &stats); */
+/*   t=timer()-t; */
+/*   printf("8198: %g (time %.10f)\n", flow, t); */
+/*   igraph_destroy(&g); */
+/*   /\***************\/ */
+
+/*   /\***************\/ */
+/*   infile=fopen("ak-16390.max", "r"); */
+/*   igraph_read_graph_dimacs(&g, infile, 0, 0, &source, &target, &capacity, */
+/* 			   IGRAPH_DIRECTED); */
+/*   fclose(infile); */
+
+/*   t=timer(); */
+/*   igraph_maxflow_value(&g, &flow, source, target, &capacity, &stats); */
+/*   t=timer()-t; */
+/*   printf("16390: %g (time %.10f)\n", flow, t); */
+/*   igraph_destroy(&g); */
+/*   /\***************\/ */
+
+/*   /\***************\/ */
+/*   infile=fopen("ak-32774.max", "r"); */
+/*   igraph_read_graph_dimacs(&g, infile, 0, 0, &source, &target, &capacity, */
+/* 			   IGRAPH_DIRECTED); */
+/*   fclose(infile); */
+
+/*   t=timer(); */
+/*   igraph_maxflow_value(&g, &flow, source, target, &capacity, &stats); */
+/*   t=timer()-t; */
+/*   printf("32774: %g (time %.10f)\n", flow, t); */
+/*   igraph_destroy(&g); */
+/*   /\***************\/ */
+
+/*   /\***************\/ */
+/*   infile=fopen("ak-65542.max", "r"); */
+/*   igraph_read_graph_dimacs(&g, infile, 0, 0, &source, &target, &capacity, */
+/* 			   IGRAPH_DIRECTED); */
+/*   fclose(infile); */
+
+/*   t=timer(); */
+/*   igraph_maxflow_value(&g, &flow, source, target, &capacity, &stats); */
+/*   t=timer()-t; */
+/*   printf("65542: %g (time %.10f)\n", flow, t); */
+/*   igraph_destroy(&g); */
+/*   /\***************\/ */
+
+  igraph_vector_destroy(&capacity);
+  
+  return 0;
+}
diff --git a/examples/simple/flow2.c b/examples/simple/flow2.c
new file mode 100644
index 0000000..5e5e068
--- /dev/null
+++ b/examples/simple/flow2.c
@@ -0,0 +1,240 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int check_flow(int errorinc,
+	       const igraph_t *graph, igraph_real_t flow_value, 
+	       const igraph_vector_t *flow, const igraph_vector_t *cut, 
+	       const igraph_vector_t *partition,
+	       const igraph_vector_t *partition2, 
+	       long int source, long int target, 
+	       const igraph_vector_t *capacity, 
+	       igraph_bool_t print) {
+
+  long int i, n=igraph_vcount(graph), m=igraph_ecount(graph);
+  long int nc=igraph_vector_size(cut);
+  igraph_vector_t inedges, outedges;
+  igraph_bool_t directed=igraph_is_directed(graph);
+  igraph_real_t cutsize;
+  igraph_t graph_copy;
+  igraph_matrix_t sp;
+
+  if (print) {
+    printf("flow value: %g\n", (double) flow_value);
+    printf("flow: "); igraph_vector_print(flow);
+    printf("first partition:  "); igraph_vector_print(partition);
+    printf("second partition: "); igraph_vector_print(partition2);
+    printf("edges in the cut: ");
+    for (i=0; i<nc; i++) {
+      long int edge=VECTOR(*cut)[i];
+      long int from=IGRAPH_FROM(graph, edge);
+      long int to  =IGRAPH_TO  (graph, edge);
+      if (!directed && from > to) {
+	igraph_integer_t tmp=from;
+	from=to;
+	to=tmp;
+      }
+      printf("%li-%li (%g), ", from, to, VECTOR(*capacity)[edge]);
+    }
+    printf("\n");
+  }
+  fflush(stdout);
+        
+  /* Always less than the capacity */
+  for (i=0; i<m; i++) {
+    if (VECTOR(*flow)[i] > VECTOR(*capacity)[i]) {
+      return errorinc+3;
+    }
+  }
+  
+  /* What comes in goes out, but only in directed graphs, 
+     there is no in and out in undirected ones...
+   */
+  if (igraph_is_directed(graph)) {
+    igraph_vector_init(&inedges, 0);
+    igraph_vector_init(&outedges, 0);
+
+    for (i=0; i<n; i++) {
+      long int n1, n2, j;
+      igraph_real_t in_flow=0.0, out_flow=0.0;
+      igraph_incident(graph, &inedges,  i, IGRAPH_IN);
+      igraph_incident(graph, &outedges, i, IGRAPH_OUT);
+      n1=igraph_vector_size(&inedges);
+      n2=igraph_vector_size(&outedges);
+      for (j=0; j<n1; j++) {
+	long int e=VECTOR(inedges)[j];
+	in_flow += VECTOR(*flow)[e];
+      }
+      for (j=0; j<n2; j++) {
+	long int e=VECTOR(outedges)[j];
+	out_flow += VECTOR(*flow)[e];
+      }
+      if (i == source) {
+	if (in_flow > 0) { return errorinc+4; }
+	if (out_flow != flow_value) { return errorinc+5; }
+      } else if (i == target) {
+	if (out_flow > 0) { return errorinc+6; }
+	if (in_flow != flow_value) { return errorinc+7; }
+	
+      } else {
+	if (in_flow != out_flow) { return errorinc+8; }
+      }
+    }
+    
+    igraph_vector_destroy(&inedges);
+    igraph_vector_destroy(&outedges);
+  }
+
+  /* Check the minimum cut size*/
+  for (i=0, cutsize=0.0; i<nc; i++) {
+    long int edge=VECTOR(*cut)[i];
+    cutsize += VECTOR(*capacity)[edge];
+  }
+  if (fabs(cutsize-flow_value) > 1e-14) { return errorinc+9; }
+
+  /* Check that the cut indeed cuts */
+  igraph_copy(&graph_copy, graph);
+  igraph_delete_edges(&graph_copy, igraph_ess_vector(cut));
+  igraph_matrix_init(&sp, 1, 1);
+  igraph_shortest_paths(&graph_copy, &sp, /*from=*/ igraph_vss_1(source),
+			/*to=*/ igraph_vss_1(target), IGRAPH_OUT);
+  if (MATRIX(sp, 0, 0) != IGRAPH_INFINITY) { return errorinc+10; }
+  igraph_matrix_destroy(&sp);
+  igraph_destroy(&graph_copy);
+
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_real_t flow_value;
+  igraph_vector_t cut;
+  igraph_vector_t capacity;
+  igraph_vector_t partition, partition2;
+  igraph_vector_t flow;
+  long int i, n;
+  igraph_integer_t source, target;
+  FILE *infile;
+  igraph_real_t flow_value2=0.0;
+  int check;
+  igraph_maxflow_stats_t stats;
+  
+  igraph_vector_init(&capacity, 0);
+
+  /***************/
+  infile=fopen("ak-4102.max", "r");
+  igraph_read_graph_dimacs(&g, infile, 0, 0, &source, &target, &capacity,
+  			   IGRAPH_DIRECTED);
+  fclose(infile);
+
+  igraph_vector_init(&cut, 0);
+  igraph_vector_init(&partition, 0);
+  igraph_vector_init(&partition2, 0);
+  igraph_vector_init(&flow, 0);
+
+  igraph_maxflow(&g, &flow_value, &flow, &cut, &partition,
+		 &partition2, source, target, &capacity, &stats);
+
+  if (flow_value != 8207) {
+    return 1;
+  }
+
+  n=igraph_vector_size(&cut);
+  for (i=0; i<n; i++) {
+    long int e=VECTOR(cut)[i];
+    flow_value2 += VECTOR(capacity)[e];
+  }
+  if (flow_value != flow_value2) {
+    return 2;
+  }
+
+  /* Check the flow */
+  if ( (check=check_flow(0, &g, flow_value, &flow, &cut, &partition,
+			 &partition2, source, target, &capacity, 
+			 /*print=*/ 0))) {
+    return check;
+  }
+
+  igraph_destroy(&g);
+  igraph_vector_destroy(&capacity);
+  igraph_vector_destroy(&cut);
+  igraph_vector_destroy(&partition);
+  igraph_vector_destroy(&partition2);
+  igraph_vector_destroy(&flow);
+
+  /* ------------------------------------- */
+
+  igraph_small(&g, 4, IGRAPH_UNDIRECTED,
+	       0,1,0,2,1,2,1,3,2,3, -1);
+  igraph_vector_init_int_end(&capacity, -1, 4,2,10,2,2, -1);
+  igraph_vector_init(&cut, 0);
+  igraph_vector_init(&partition, 0);
+  igraph_vector_init(&partition2, 0);
+  igraph_vector_init(&flow, 0);
+
+  igraph_maxflow(&g, &flow_value, &flow, &cut, &partition, &partition2, 
+		 /*source=*/ 0, /*target=*/ 3, &capacity, &stats);
+
+  if ( (check=check_flow(20, &g, flow_value, &flow, &cut, &partition,
+			 &partition2, 0, 3, &capacity, 
+			 /*print=*/ 1))) {
+    return check;
+  }
+
+  igraph_vector_destroy(&cut);
+  igraph_vector_destroy(&partition2);
+  igraph_vector_destroy(&partition);
+  igraph_vector_destroy(&capacity);
+  igraph_vector_destroy(&flow);
+  igraph_destroy(&g);
+
+  /* ------------------------------------- */
+
+  igraph_small(&g, 6, IGRAPH_DIRECTED,
+	       0,1,1,2,2,3, 0,5,5,4,4,3, 3,0, -1);
+  igraph_vector_init_int_end(&capacity, -1, 3,1,2, 10,1,3, 2, -1);
+  igraph_vector_init(&cut, 0);
+  igraph_vector_init(&partition, 0);
+  igraph_vector_init(&partition2, 0);
+  igraph_vector_init(&flow, 0);
+
+  igraph_maxflow(&g, &flow_value, &flow, &cut, &partition, &partition2, 
+		 /*source=*/ 0, /*target=*/ 2, &capacity, &stats);
+
+  if ( (check=check_flow(40, &g, flow_value, &flow, &cut, &partition,
+			 &partition2, 0, 2, &capacity, 
+			 /*print=*/ 1))) {
+    return check;
+  }
+
+  igraph_vector_destroy(&cut);
+  igraph_vector_destroy(&partition2);
+  igraph_vector_destroy(&partition);
+  igraph_vector_destroy(&capacity);
+  igraph_vector_destroy(&flow);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/flow2.out b/examples/simple/flow2.out
new file mode 100644
index 0000000..e0d8d58
--- /dev/null
+++ b/examples/simple/flow2.out
@@ -0,0 +1,10 @@
+flow value: 4
+flow: 4 0 2 2 2
+first partition:  0 1 2
+second partition: 3
+edges in the cut: 1-3 (2), 2-3 (2), 
+flow value: 1
+flow: 1 1 0 0 0 0 0
+first partition:  0 1 3 4 5
+second partition: 2
+edges in the cut: 1-2 (1), 
diff --git a/examples/simple/foreign.c b/examples/simple/foreign.c
new file mode 100644
index 0000000..8990c5f
--- /dev/null
+++ b/examples/simple/foreign.c
@@ -0,0 +1,46 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+
+  igraph_t g;
+  FILE *ifile;
+
+  /* PAJEK */
+  ifile=fopen("LINKS.NET", "r");
+  if (ifile==0) {
+    return 10;
+  }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  printf("The graph:\n");
+  printf("Vertices: %li\n", (long int) igraph_vcount(&g));
+  printf("Edges: %li\n", (long int) igraph_ecount(&g));
+  printf("Directed: %i\n", (int) igraph_is_directed(&g));
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/foreign.out b/examples/simple/foreign.out
new file mode 100644
index 0000000..a1244f9
--- /dev/null
+++ b/examples/simple/foreign.out
@@ -0,0 +1,11 @@
+The graph:
+Vertices: 4
+Edges: 7
+Directed: 1
+0 0
+0 1
+0 2
+1 0
+2 2
+2 3
+3 1
diff --git a/examples/simple/fullmatrix1.dl b/examples/simple/fullmatrix1.dl
new file mode 100644
index 0000000..600884b
--- /dev/null
+++ b/examples/simple/fullmatrix1.dl
@@ -0,0 +1,9 @@
+DL N = 5
+Data:
+0 1 1 1 1
+1 0 1 0 0
+1 1 0 0 1
+1 0 0 0 0
+1 0 1 0 0 
+
+  
diff --git a/examples/simple/fullmatrix2.dl b/examples/simple/fullmatrix2.dl
new file mode 100644
index 0000000..2794732
--- /dev/null
+++ b/examples/simple/fullmatrix2.dl
@@ -0,0 +1,10 @@
+dl n=5
+format = fullmatrix
+labels:
+barry,david,lin,pat,russ
+data:
+0 1 1 1 0
+1 0 0 0 1
+1 0 0 1 0
+1 0 1 0 1
+0 1 0 1 0
diff --git a/examples/simple/fullmatrix3.dl b/examples/simple/fullmatrix3.dl
new file mode 100644
index 0000000..7a966bf
--- /dev/null
+++ b/examples/simple/fullmatrix3.dl
@@ -0,0 +1,12 @@
+dl n=5
+format = fullmatrix
+labels:
+barry,david
+lin,pat
+russ
+data:
+0 1 1 1 0
+1 0 0 0 1
+1 0 0 1 0
+1 0 1 0 1
+0 1 0 1 0
diff --git a/examples/simple/fullmatrix4.dl b/examples/simple/fullmatrix4.dl
new file mode 100644
index 0000000..15d21df
--- /dev/null
+++ b/examples/simple/fullmatrix4.dl
@@ -0,0 +1,10 @@
+dl n=5
+format = fullmatrix
+labels embedded
+data:
+larry david lin pat russ
+Larry 0 1 1 1 0
+david 1 0 0 0 1
+Lin 1 0 0 1 0
+Pat 1 0 1 0 1
+Russ 0 1 0 1 0
diff --git a/examples/simple/gml.c b/examples/simple/gml.c
new file mode 100644
index 0000000..35364d1
--- /dev/null
+++ b/examples/simple/gml.c
@@ -0,0 +1,52 @@
+/* -*- 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.h>
+#include <stdio.h>
+
+int main() {
+
+  igraph_t g;
+  FILE *ifile;
+  
+  ifile=fopen("karate.gml", "r");
+  if (ifile==0) {
+    return 10;
+  }
+  
+  igraph_read_graph_gml(&g, ifile);
+  fclose(ifile);
+
+  if (igraph_is_directed(&g)) {
+    printf("directed\n");
+  } else {
+    printf("undirected\n");
+  }
+    
+  igraph_write_graph_edgelist(&g, stdout);
+  printf("-----------------\n");
+  igraph_write_graph_gml(&g, stdout, 0, "test suite");
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/gml.out b/examples/simple/gml.out
new file mode 100644
index 0000000..5216f54
--- /dev/null
+++ b/examples/simple/gml.out
@@ -0,0 +1,612 @@
+undirected
+0 1
+0 2
+0 3
+0 4
+0 5
+0 6
+0 7
+0 8
+0 10
+0 11
+0 12
+0 13
+0 17
+0 19
+0 21
+0 31
+1 2
+1 3
+1 7
+1 13
+1 17
+1 19
+1 21
+1 30
+2 3
+2 7
+2 8
+2 9
+2 13
+2 27
+2 28
+2 32
+3 7
+3 12
+3 13
+4 6
+4 10
+5 6
+5 10
+5 16
+6 16
+8 30
+8 32
+8 33
+9 33
+13 33
+14 32
+14 33
+15 32
+15 33
+18 32
+18 33
+19 33
+20 32
+20 33
+22 32
+22 33
+23 25
+23 27
+23 29
+23 32
+23 33
+24 25
+24 27
+24 31
+25 31
+26 29
+26 33
+27 33
+28 31
+28 33
+29 32
+29 33
+30 32
+30 33
+31 32
+31 33
+32 33
+-----------------
+Creator "igraph version @VERSION@ test suite"
+Version 1
+graph
+[
+  directed 0
+  node
+  [
+    id 0
+  ]
+  node
+  [
+    id 1
+  ]
+  node
+  [
+    id 2
+  ]
+  node
+  [
+    id 3
+  ]
+  node
+  [
+    id 4
+  ]
+  node
+  [
+    id 5
+  ]
+  node
+  [
+    id 6
+  ]
+  node
+  [
+    id 7
+  ]
+  node
+  [
+    id 8
+  ]
+  node
+  [
+    id 9
+  ]
+  node
+  [
+    id 10
+  ]
+  node
+  [
+    id 11
+  ]
+  node
+  [
+    id 12
+  ]
+  node
+  [
+    id 13
+  ]
+  node
+  [
+    id 14
+  ]
+  node
+  [
+    id 15
+  ]
+  node
+  [
+    id 16
+  ]
+  node
+  [
+    id 17
+  ]
+  node
+  [
+    id 18
+  ]
+  node
+  [
+    id 19
+  ]
+  node
+  [
+    id 20
+  ]
+  node
+  [
+    id 21
+  ]
+  node
+  [
+    id 22
+  ]
+  node
+  [
+    id 23
+  ]
+  node
+  [
+    id 24
+  ]
+  node
+  [
+    id 25
+  ]
+  node
+  [
+    id 26
+  ]
+  node
+  [
+    id 27
+  ]
+  node
+  [
+    id 28
+  ]
+  node
+  [
+    id 29
+  ]
+  node
+  [
+    id 30
+  ]
+  node
+  [
+    id 31
+  ]
+  node
+  [
+    id 32
+  ]
+  node
+  [
+    id 33
+  ]
+  edge
+  [
+    source 1
+    target 0
+  ]
+  edge
+  [
+    source 2
+    target 0
+  ]
+  edge
+  [
+    source 2
+    target 1
+  ]
+  edge
+  [
+    source 3
+    target 0
+  ]
+  edge
+  [
+    source 3
+    target 1
+  ]
+  edge
+  [
+    source 3
+    target 2
+  ]
+  edge
+  [
+    source 4
+    target 0
+  ]
+  edge
+  [
+    source 5
+    target 0
+  ]
+  edge
+  [
+    source 6
+    target 0
+  ]
+  edge
+  [
+    source 6
+    target 4
+  ]
+  edge
+  [
+    source 6
+    target 5
+  ]
+  edge
+  [
+    source 7
+    target 0
+  ]
+  edge
+  [
+    source 7
+    target 1
+  ]
+  edge
+  [
+    source 7
+    target 2
+  ]
+  edge
+  [
+    source 7
+    target 3
+  ]
+  edge
+  [
+    source 8
+    target 0
+  ]
+  edge
+  [
+    source 8
+    target 2
+  ]
+  edge
+  [
+    source 9
+    target 2
+  ]
+  edge
+  [
+    source 10
+    target 0
+  ]
+  edge
+  [
+    source 10
+    target 4
+  ]
+  edge
+  [
+    source 10
+    target 5
+  ]
+  edge
+  [
+    source 11
+    target 0
+  ]
+  edge
+  [
+    source 12
+    target 0
+  ]
+  edge
+  [
+    source 12
+    target 3
+  ]
+  edge
+  [
+    source 13
+    target 0
+  ]
+  edge
+  [
+    source 13
+    target 1
+  ]
+  edge
+  [
+    source 13
+    target 2
+  ]
+  edge
+  [
+    source 13
+    target 3
+  ]
+  edge
+  [
+    source 16
+    target 5
+  ]
+  edge
+  [
+    source 16
+    target 6
+  ]
+  edge
+  [
+    source 17
+    target 0
+  ]
+  edge
+  [
+    source 17
+    target 1
+  ]
+  edge
+  [
+    source 19
+    target 0
+  ]
+  edge
+  [
+    source 19
+    target 1
+  ]
+  edge
+  [
+    source 21
+    target 0
+  ]
+  edge
+  [
+    source 21
+    target 1
+  ]
+  edge
+  [
+    source 25
+    target 23
+  ]
+  edge
+  [
+    source 25
+    target 24
+  ]
+  edge
+  [
+    source 27
+    target 2
+  ]
+  edge
+  [
+    source 27
+    target 23
+  ]
+  edge
+  [
+    source 27
+    target 24
+  ]
+  edge
+  [
+    source 28
+    target 2
+  ]
+  edge
+  [
+    source 29
+    target 23
+  ]
+  edge
+  [
+    source 29
+    target 26
+  ]
+  edge
+  [
+    source 30
+    target 1
+  ]
+  edge
+  [
+    source 30
+    target 8
+  ]
+  edge
+  [
+    source 31
+    target 0
+  ]
+  edge
+  [
+    source 31
+    target 24
+  ]
+  edge
+  [
+    source 31
+    target 25
+  ]
+  edge
+  [
+    source 31
+    target 28
+  ]
+  edge
+  [
+    source 32
+    target 2
+  ]
+  edge
+  [
+    source 32
+    target 8
+  ]
+  edge
+  [
+    source 32
+    target 14
+  ]
+  edge
+  [
+    source 32
+    target 15
+  ]
+  edge
+  [
+    source 32
+    target 18
+  ]
+  edge
+  [
+    source 32
+    target 20
+  ]
+  edge
+  [
+    source 32
+    target 22
+  ]
+  edge
+  [
+    source 32
+    target 23
+  ]
+  edge
+  [
+    source 32
+    target 29
+  ]
+  edge
+  [
+    source 32
+    target 30
+  ]
+  edge
+  [
+    source 32
+    target 31
+  ]
+  edge
+  [
+    source 33
+    target 8
+  ]
+  edge
+  [
+    source 33
+    target 9
+  ]
+  edge
+  [
+    source 33
+    target 13
+  ]
+  edge
+  [
+    source 33
+    target 14
+  ]
+  edge
+  [
+    source 33
+    target 15
+  ]
+  edge
+  [
+    source 33
+    target 18
+  ]
+  edge
+  [
+    source 33
+    target 19
+  ]
+  edge
+  [
+    source 33
+    target 20
+  ]
+  edge
+  [
+    source 33
+    target 22
+  ]
+  edge
+  [
+    source 33
+    target 23
+  ]
+  edge
+  [
+    source 33
+    target 26
+  ]
+  edge
+  [
+    source 33
+    target 27
+  ]
+  edge
+  [
+    source 33
+    target 28
+  ]
+  edge
+  [
+    source 33
+    target 29
+  ]
+  edge
+  [
+    source 33
+    target 30
+  ]
+  edge
+  [
+    source 33
+    target 31
+  ]
+  edge
+  [
+    source 33
+    target 32
+  ]
+]
diff --git a/examples/simple/graphml-hsa05010.xml b/examples/simple/graphml-hsa05010.xml
new file mode 100644
index 0000000..507750e
--- /dev/null
+++ b/examples/simple/graphml-hsa05010.xml
@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+<!-- Created by igraph -->
+  <key id="organism" for="graph" attr.name="organism" attr.type="string"/>
+  <key id="pathway_number" for="graph" attr.name="pathway_number" attr.type="string"/>
+  <key id="title" for="graph" attr.name="title" attr.type="string"/>
+  <key id="type" for="node" attr.name="type" attr.type="string"/>
+  <key id="pathway_id" for="node" attr.name="pathway_id" attr.type="string"/>
+  <key id="name" for="node" attr.name="name" attr.type="string"/>
+  <key id="title" for="node" attr.name="title" attr.type="string"/>
+  <key id="uniprot" for="node" attr.name="uniprot" attr.type="string"/>
+  <key id="gene" for="node" attr.name="gene" attr.type="string"/>
+  <key id="GO" for="node" attr.name="GO" attr.type="string"/>
+  <key id="sim_BP_resnik" for="edge" attr.name="sim_BP_resnik" attr.type="double"/>
+  <key id="sim_BP_lin" for="edge" attr.name="sim_BP_lin" attr.type="double"/>
+  <key id="sim_BP_jiang" for="edge" attr.name="sim_BP_jiang" attr.type="double"/>
+  <key id="sim_BP_rel" for="edge" attr.name="sim_BP_rel" attr.type="double"/>
+  <key id="sim_CC_resnik" for="edge" attr.name="sim_CC_resnik" attr.type="double"/>
+  <key id="sim_CC_lin" for="edge" attr.name="sim_CC_lin" attr.type="double"/>
+  <key id="sim_CC_jiang" for="edge" attr.name="sim_CC_jiang" attr.type="double"/>
+  <key id="sim_CC_rel" for="edge" attr.name="sim_CC_rel" attr.type="double"/>
+  <key id="sim_MF_resnik" for="edge" attr.name="sim_MF_resnik" attr.type="double"/>
+  <key id="sim_MF_lin" for="edge" attr.name="sim_MF_lin" attr.type="double"/>
+  <key id="sim_MF_jiang" for="edge" attr.name="sim_MF_jiang" attr.type="double"/>
+  <key id="sim_MF_rel" for="edge" attr.name="sim_MF_rel" attr.type="double"/>
+  <graph id="G" edgedefault="directed">
+    <data key="organism">hsa</data>
+    <data key="pathway_number">05010</data>
+    <node id="n0">
+      <data key="type">compound</data>
+      <data key="pathway_id">1</data>
+      <data key="name">cpd:C00027</data>
+      <data key="title">C00027</data>
+      <data key="uniprot"></data>
+      <data key="gene"></data>
+      <data key="GO"></data>
+    </node>
+    <node id="n1">
+      <data key="type">compound</data>
+      <data key="pathway_id">2</data>
+      <data key="name">cpd:C00070</data>
+      <data key="title">C00070...</data>
+      <data key="uniprot"></data>
+      <data key="gene"></data>
+      <data key="GO"></data>
+    </node>
+    <node id="n2">
+      <data key="type">compound</data>
+      <data key="pathway_id">2</data>
+      <data key="name">cpd:C14818</data>
+      <data key="title">C00070...</data>
+      <data key="uniprot"></data>
+      <data key="gene"></data>
+      <data key="GO"></data>
+    </node>
+    <node id="n3">
+      <data key="type">gene</data>
+      <data key="pathway_id">4</data>
+      <data key="name">hsa:51107</data>
+      <data key="title">APH1A</data>
+      <data key="uniprot">Q96BI3</data>
+      <data key="gene">APH1A</data>
+      <data key="GO">GO:0005515,GO:0016021,GO:0016485,GO:0043085</data>
+    </node>
+    <node id="n4">
+      <data key="type">gene</data>
+      <data key="pathway_id">6</data>
+      <data key="name">hsa:4311</data>
+      <data key="title">MME</data>
+      <data key="uniprot">P08473</data>
+      <data key="gene">MME</data>
+      <data key="GO">GO:0004245,GO:0016021,GO:0016787,GO:0008237,GO:0007267,GO:0006508,GO:0005887,GO:0005886,GO:0016020</data>
+    </node>
+    <node id="n5">
+      <data key="type">gene</data>
+      <data key="pathway_id">7</data>
+      <data key="name">hsa:2932</data>
+      <data key="title">GSK3B</data>
+      <data key="uniprot">P49841</data>
+      <data key="gene">GSK3B</data>
+      <data key="GO">GO:0016301,GO:0016740,GO:0005977,GO:0004696,GO:0005524,GO:0004674,GO:0006468,GO:0004672</data>
+    </node>
+    <node id="n6">
+      <data key="type">gene</data>
+      <data key="pathway_id">8</data>
+      <data key="name">hsa:4137</data>
+      <data key="title">MAPT</data>
+      <data key="uniprot"></data>
+      <data key="gene"></data>
+      <data key="GO"></data>
+    </node>
+    <node id="n7">
+      <data key="type">gene</data>
+      <data key="pathway_id">9</data>
+      <data key="name">hsa:836</data>
+      <data key="title">CASP3</data>
+      <data key="uniprot">P42574</data>
+      <data key="gene">CASP3</data>
+      <data key="GO">GO:0016787,GO:0008233,GO:0006917,GO:0030693,GO:0008234,GO:0006915,GO:0006508</data>
+    </node>
+    <node id="n8">
+      <data key="type">gene</data>
+      <data key="pathway_id">11</data>
+      <data key="name">hsa:840</data>
+      <data key="title">CASP7</data>
+      <data key="uniprot">P55210</data>
+      <data key="gene">CASP7</data>
+      <data key="GO">GO:0008233,GO:0016787,GO:0008632,GO:0008234,GO:0006915,GO:0005737,GO:0006508</data>
+    </node>
+    <node id="n9">
+      <data key="type">gene</data>
+      <data key="pathway_id">12</data>
+      <data key="name">hsa:55851</data>
+      <data key="title">PSENEN</data>
+      <data key="uniprot">Q9NZ42</data>
+      <data key="gene">PEN2</data>
+      <data key="GO"></data>
+    </node>
+    <node id="n10">
+      <data key="type">gene</data>
+      <data key="pathway_id">13</data>
+      <data key="name">hsa:6622</data>
+      <data key="title">SNCA</data>
+      <data key="uniprot">P37840</data>
+      <data key="gene">SNCA</data>
+      <data key="GO">GO:0005737,GO:0007417,GO:0006916</data>
+    </node>
+    <node id="n11">
+      <data key="type">gene</data>
+      <data key="pathway_id">14</data>
+      <data key="name">hsa:5663</data>
+      <data key="title">PSEN1...</data>
+      <data key="uniprot">P49768</data>
+      <data key="gene"></data>
+      <data key="GO">GO:0016021,GO:0007059,GO:0007001,GO:0006916,GO:0000776,GO:0000775,GO:0005639,GO:0005624,GO:0005783,GO:0007242</data>
+    </node>
+    <node id="n12">
+      <data key="type">gene</data>
+      <data key="pathway_id">14</data>
+      <data key="name">hsa:5664</data>
+      <data key="title">PSEN1...</data>
+      <data key="uniprot">P49810</data>
+      <data key="gene">PSEN2</data>
+      <data key="GO">GO:0016021,GO:0008632,GO:0007059,GO:0007001,GO:0000776,GO:0005639,GO:0005783,GO:0007242</data>
+    </node>
+    <node id="n13">
+      <data key="type">gene</data>
+      <data key="pathway_id">15</data>
+      <data key="name">hsa:836</data>
+      <data key="title">CASP3</data>
+      <data key="uniprot">P42574</data>
+      <data key="gene">CASP3</data>
+      <data key="GO">GO:0016787,GO:0008233,GO:0006917,GO:0030693,GO:0008234,GO:0006915,GO:0006508</data>
+    </node>
+    <node id="n14">
+      <data key="type">gene</data>
+      <data key="pathway_id">16</data>
+      <data key="name">hsa:23385</data>
+      <data key="title">NCSTN</data>
+      <data key="uniprot">Q92542</data>
+      <data key="gene">NCSTN</data>
+      <data key="GO">GO:0016021,GO:0016485,GO:0006508</data>
+    </node>
+    <node id="n15">
+      <data key="type">gene</data>
+      <data key="pathway_id">17</data>
+      <data key="name">hsa:2</data>
+      <data key="title">A2M</data>
+      <data key="uniprot">P01023</data>
+      <data key="gene">A2M</data>
+      <data key="GO">GO:0017114,GO:0004866,GO:0051260,GO:0019899,GO:0008320,GO:0006886,GO:0004867</data>
+    </node>
+    <node id="n16">
+      <data key="type">gene</data>
+      <data key="pathway_id">18</data>
+      <data key="name">hsa:3416</data>
+      <data key="title">IDE</data>
+      <data key="uniprot">P14735</data>
+      <data key="gene">IDE</data>
+      <data key="GO">GO:0004231,GO:0016787,GO:0008237,GO:0007548,GO:0007267,GO:0007165,GO:0006508,GO:0005777,GO:0005625,GO:0005615,GO:0004871,GO:0003824,GO:0004222</data>
+    </node>
+    <node id="n17">
+      <data key="type">gene</data>
+      <data key="pathway_id">19</data>
+      <data key="name">hsa:8883</data>
+      <data key="title">APPBP1</data>
+      <data key="uniprot">Q13564</data>
+      <data key="gene">APPBP1</data>
+      <data key="GO">GO:0007165,GO:0005737,GO:0003824</data>
+    </node>
+    <node id="n18">
+      <data key="type">gene</data>
+      <data key="pathway_id">20</data>
+      <data key="name">hsa:23621</data>
+      <data key="title">BACE1...</data>
+      <data key="uniprot">P56817</data>
+      <data key="gene">BACE1</data>
+      <data key="GO">GO:0004190,GO:0008233,GO:0009049,GO:0016021,GO:0016787,GO:0050435,GO:0005768,GO:0006508,GO:0005794,GO:0006509,GO:0008798,GO:0005887,GO:0004194</data>
+    </node>
+    <node id="n19">
+      <data key="type">gene</data>
+      <data key="pathway_id">20</data>
+      <data key="name">hsa:25825</data>
+      <data key="title">BACE1...</data>
+      <data key="uniprot">Q9Y5Z0</data>
+      <data key="gene"></data>
+      <data key="GO">GO:0004190,GO:0009049,GO:0016021,GO:0016787,GO:0009306,GO:0006464,GO:0005624,GO:0006508,GO:0004194</data>
+    </node>
+    <node id="n20">
+      <data key="type">gene</data>
+      <data key="pathway_id">22</data>
+      <data key="name">hsa:351</data>
+      <data key="title">APP, AD1</data>
+      <data key="uniprot">P05067</data>
+      <data key="gene">APP</data>
+      <data key="GO">GO:0008201,GO:0007155,GO:0006915,GO:0005905,GO:0006897,GO:0016021,GO:0005515,GO:0005887,GO:0005576,GO:0004867</data>
+    </node>
+    <node id="n21">
+      <data key="type">gene</data>
+      <data key="pathway_id">23</data>
+      <data key="name">hsa:2597</data>
+      <data key="title">GAPDH, GAPD</data>
+      <data key="uniprot">P04406</data>
+      <data key="gene"></data>
+      <data key="GO"></data>
+    </node>
+    <node id="n22">
+      <data key="type">gene</data>
+      <data key="pathway_id">24</data>
+      <data key="name">hsa:348</data>
+      <data key="title">APOE, AD2</data>
+      <data key="uniprot">P02649</data>
+      <data key="gene">APOE</data>
+      <data key="GO">GO:0001540,GO:0008015,GO:0007271,GO:0005737,GO:0005319,GO:0008201,GO:0006869,GO:0008289</data>
+    </node>
+    <node id="n23">
+      <data key="type">gene</data>
+      <data key="pathway_id">25</data>
+      <data key="name">hsa:322</data>
+      <data key="title">APBB1, RIR</data>
+      <data key="uniprot">O00213</data>
+      <data key="gene">APBB1</data>
+      <data key="GO">GO:0007165,GO:0001540,GO:0008134,GO:0045449,GO:0050821,GO:0005634,GO:0030308,GO:0045749,GO:0035035,GO:0007050,GO:0030048,GO:0045202,GO:0030027,GO:0030426,GO:0007409,GO:0050760</data>
+    </node>
+    <node id="n24">
+      <data key="type">gene</data>
+      <data key="pathway_id">26</data>
+      <data key="name">hsa:4023</data>
+      <data key="title">LPL</data>
+      <data key="uniprot">P06858</data>
+      <data key="gene">LPL</data>
+      <data key="GO">GO:0005319,GO:0004465,GO:0016787,GO:0016042,GO:0008201,GO:0008015,GO:0006631,GO:0005576,GO:0006629,GO:0003824</data>
+    </node>
+    <node id="n25">
+      <data key="type">gene</data>
+      <data key="pathway_id">27</data>
+      <data key="name">hsa:4035</data>
+      <data key="title">LRP1, APR, A2MR</data>
+      <data key="uniprot">Q07954</data>
+      <data key="gene">LRP1</data>
+      <data key="GO">GO:0016021,GO:0004872,GO:0016020,GO:0008283,GO:0008034,GO:0006629,GO:0005887,GO:0005624,GO:0005509,GO:0005319,GO:0006897,GO:0005905</data>
+    </node>
+    <edge source="n20" target="n23">
+      <data key="sim_BP_resnik">4.95265</data>
+      <data key="sim_BP_lin">0.693152</data>
+      <data key="sim_BP_jiang">0.185704</data>
+      <data key="sim_BP_rel">0.670769</data>
+      <data key="sim_CC_resnik">0.145403</data>
+      <data key="sim_CC_lin">0.05698</data>
+      <data key="sim_CC_jiang">0.172033</data>
+      <data key="sim_CC_rel">0.00546283</data>
+      <data key="sim_MF_resnik">2.93737</data>
+      <data key="sim_MF_lin">0.556617</data>
+      <data key="sim_MF_jiang">0.176068</data>
+      <data key="sim_MF_rel">0.483953</data>
+    </edge>
+    <edge source="n17" target="n20">
+      <data key="sim_BP_resnik">0.50493</data>
+      <data key="sim_BP_lin">0.112413</data>
+      <data key="sim_BP_jiang">0.111437</data>
+      <data key="sim_BP_rel">0.033196</data>
+      <data key="sim_CC_resnik">0.145403</data>
+      <data key="sim_CC_lin">0.0605613</data>
+      <data key="sim_CC_jiang">0.181454</data>
+      <data key="sim_CC_rel">0.00580618</data>
+      <data key="sim_MF_resnik">-0</data>
+      <data key="sim_MF_lin">-0</data>
+      <data key="sim_MF_jiang">0.171988</data>
+      <data key="sim_MF_rel">-0</data>
+    </edge>
+    <edge source="n20" target="n25">
+      <data key="sim_BP_resnik">7.8977</data>
+      <data key="sim_BP_lin">1</data>
+      <data key="sim_BP_jiang">1</data>
+      <data key="sim_BP_rel">0.995807</data>
+      <data key="sim_CC_resnik">9.64739</data>
+      <data key="sim_CC_lin">1</data>
+      <data key="sim_CC_jiang">1</data>
+      <data key="sim_CC_rel">0.998753</data>
+      <data key="sim_MF_resnik">2.93737</data>
+      <data key="sim_MF_lin">0.400174</data>
+      <data key="sim_MF_jiang">0.136512</data>
+      <data key="sim_MF_rel">0.347932</data>
+    </edge>
+    <edge source="n15" target="n25">
+      <data key="sim_BP_resnik">3.5307</data>
+      <data key="sim_BP_lin">0.498171</data>
+      <data key="sim_BP_jiang">0.123255</data>
+      <data key="sim_BP_rel">0.455066</data>
+      <data key="sim_MF_resnik">4.0529</data>
+      <data key="sim_MF_lin">0.366988</data>
+      <data key="sim_MF_jiang">0.0822633</data>
+      <data key="sim_MF_rel">0.344877</data>
+    </edge>
+    <edge source="n24" target="n25">
+      <data key="sim_BP_resnik">5.41325</data>
+      <data key="sim_BP_lin">1</data>
+      <data key="sim_BP_jiang">1</data>
+      <data key="sim_BP_rel">0.976533</data>
+      <data key="sim_CC_resnik">-0</data>
+      <data key="sim_CC_lin">-0</data>
+      <data key="sim_CC_jiang">0.151863</data>
+      <data key="sim_CC_rel">-0</data>
+      <data key="sim_MF_resnik">9.56439</data>
+      <data key="sim_MF_lin">1</data>
+      <data key="sim_MF_jiang">1</data>
+      <data key="sim_MF_rel">0.998679</data>
+    </edge>
+    <edge source="n20" target="n22">
+      <data key="sim_BP_resnik">3.20433</data>
+      <data key="sim_BP_lin">0.383125</data>
+      <data key="sim_BP_jiang">0.0883496</data>
+      <data key="sim_BP_rel">0.341558</data>
+      <data key="sim_CC_resnik">0.145403</data>
+      <data key="sim_CC_lin">0.0605613</data>
+      <data key="sim_CC_jiang">0.181454</data>
+      <data key="sim_CC_rel">0.00580618</data>
+      <data key="sim_MF_resnik">10.0077</data>
+      <data key="sim_MF_lin">1</data>
+      <data key="sim_MF_jiang">1</data>
+      <data key="sim_MF_rel">0.999029</data>
+    </edge>
+    <edge source="n20" target="n21">
+    </edge>
+    <edge source="n18" target="n20">
+      <data key="sim_BP_resnik">0.50493</data>
+      <data key="sim_BP_lin">0.0888891</data>
+      <data key="sim_BP_jiang">0.0880977</data>
+      <data key="sim_BP_rel">0.0262494</data>
+      <data key="sim_CC_resnik">5.53428</data>
+      <data key="sim_CC_lin">1</data>
+      <data key="sim_CC_jiang">1</data>
+      <data key="sim_CC_rel">0.978422</data>
+      <data key="sim_MF_resnik">-0</data>
+      <data key="sim_MF_lin">-0</data>
+      <data key="sim_MF_jiang">0.137908</data>
+      <data key="sim_MF_rel">-0</data>
+    </edge>
+    <edge source="n19" target="n20">
+      <data key="sim_BP_resnik">3.17114</data>
+      <data key="sim_BP_lin">0.346041</data>
+      <data key="sim_BP_jiang">0.0972198</data>
+      <data key="sim_BP_rel">0.307624</data>
+      <data key="sim_CC_resnik">2.60224</data>
+      <data key="sim_CC_lin">1</data>
+      <data key="sim_CC_jiang">1</data>
+      <data key="sim_CC_rel">0.835317</data>
+      <data key="sim_MF_resnik">-0</data>
+      <data key="sim_MF_lin">-0</data>
+      <data key="sim_MF_jiang">0.137908</data>
+      <data key="sim_MF_rel">-0</data>
+    </edge>
+    <edge source="n5" target="n6">
+    </edge>
+  </graph>
+</graphml>
diff --git a/examples/simple/graphml.c b/examples/simple/graphml.c
new file mode 100644
index 0000000..ca7b008
--- /dev/null
+++ b/examples/simple/graphml.c
@@ -0,0 +1,98 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdio.h>
+#include <unistd.h>		/* unlink */
+
+void custom_warning_handler (const char *reason, const char *file,
+			     int line, int igraph_errno) {
+  printf("Warning: %s\n", reason);
+}
+
+int main(int argc, char **argv) {
+  igraph_t g;
+  igraph_error_handler_t* oldhandler;
+  igraph_warning_handler_t* oldwarnhandler;
+  int result;
+  FILE *ifile, *ofile;
+
+  /* GraphML */
+  ifile=fopen("test.gxl", "r");
+  if (ifile==0) {
+    return 10;
+  }
+  
+  oldhandler=igraph_set_error_handler(igraph_error_handler_ignore);
+  oldwarnhandler=igraph_set_warning_handler(custom_warning_handler);
+  if ((result=igraph_read_graph_graphml(&g, ifile, 0))) {
+    // maybe it is simply disabled at compile-time
+    if (result == IGRAPH_UNIMPLEMENTED) return 77;
+    return 1;
+  }
+  igraph_set_error_handler(oldhandler);
+
+  fclose(ifile);
+
+  /* Write it back */
+  ofile=fopen("test2.gxl", "w");
+  /* If we can't create the test file, just skip the test */
+  if (ofile) {
+    if ((result=igraph_write_graph_graphml(&g, ofile, /*prefixattr=*/ 1))) {
+      return 1;
+    }
+    fclose(ofile);
+    unlink("test2.gxl");
+  }
+  
+  printf("The directed graph:\n");
+  printf("Vertices: %li\n", (long int) igraph_vcount(&g));
+  printf("Edges: %li\n", (long int) igraph_ecount(&g));
+  printf("Directed: %i\n", (int) igraph_is_directed(&g));
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+ 
+  /* The same with undirected graph */
+  ifile=fopen("test.gxl", "r");
+  if ((result=igraph_read_graph_graphml(&g, ifile, 0))) {
+    return 1;
+  }
+  fclose(ifile);
+  printf("The undirected graph:\n");
+  printf("Vertices: %li\n", (long int) igraph_vcount(&g));
+  printf("Edges: %li\n", (long int) igraph_ecount(&g));
+  printf("Directed: %i\n", (int) igraph_is_directed(&g));
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+  igraph_set_warning_handler(oldwarnhandler);
+
+  /* There were sometimes problems with this file */
+  /* Only if called from R though, and only on random occasions, once in every 
+     ten reads. Do testing here doesn't make much sense, but if we have the file 
+     then let's do it anyway. */
+  ifile=fopen("graphml-hsa05010.xml", "r");  
+  igraph_read_graph_graphml(&g, ifile, 0);
+  fclose(ifile);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/graphml.out b/examples/simple/graphml.out
new file mode 100644
index 0000000..23d9266
--- /dev/null
+++ b/examples/simple/graphml.out
@@ -0,0 +1,24 @@
+Warning: unknown attribute key 'd3' in a <data> tag, ignoring attribute
+The directed graph:
+Vertices: 6
+Edges: 7
+Directed: 0
+0 1
+0 2
+1 3
+2 3
+2 4
+3 5
+4 5
+Warning: unknown attribute key 'd3' in a <data> tag, ignoring attribute
+The undirected graph:
+Vertices: 6
+Edges: 7
+Directed: 0
+0 1
+0 2
+1 3
+2 3
+2 4
+3 5
+4 5
diff --git a/examples/simple/heap.c b/examples/simple/heap.c
new file mode 100644
index 0000000..bfdd7ad
--- /dev/null
+++ b/examples/simple/heap.c
@@ -0,0 +1,31 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  /* This is not used by any functions any more,
+     no need to test it right now */
+  return 0;
+}
diff --git a/examples/simple/igraph_add_edges.c b/examples/simple/igraph_add_edges.c
new file mode 100644
index 0000000..f4124b9
--- /dev/null
+++ b/examples/simple/igraph_add_edges.c
@@ -0,0 +1,92 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v;
+  int ret;
+
+  /* Create graph */
+  igraph_vector_init(&v, 8);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=3;
+  VECTOR(v)[6]=2; VECTOR(v)[7]=2;
+  igraph_create(&g, &v, 0, 1);
+
+  /* Add edges */
+  igraph_vector_resize(&v, 4);
+  VECTOR(v)[0]=2; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=3; VECTOR(v)[3]=3;
+  igraph_add_edges(&g, &v, 0);
+  
+  /* Check result */
+  igraph_get_edgelist(&g, &v, 0);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+
+  /* Error, vector length */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  igraph_vector_resize(&v, 3);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=2;
+  ret=igraph_add_edges(&g, &v, 0);
+  if (ret != IGRAPH_EINVEVECTOR) {
+    return 1;
+  }
+  
+  /* Check result */
+  igraph_get_edgelist(&g, &v, 0);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+
+  /* Error, vector ids */
+  igraph_vector_resize(&v, 4);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=2; VECTOR(v)[3]=4;
+  ret=igraph_add_edges(&g, &v, 0);
+  if (ret != IGRAPH_EINVVID) {
+    return 2;
+  }  
+
+  /* Check result */
+  igraph_get_edgelist(&g, &v, 0);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+
+  igraph_vector_destroy(&v);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_add_edges.out b/examples/simple/igraph_add_edges.out
new file mode 100644
index 0000000..5c08cfa
--- /dev/null
+++ b/examples/simple/igraph_add_edges.out
@@ -0,0 +1,3 @@
+ 0 1 1 1 2 2 2 2 2 3 3 3
+ 0 1 1 1 2 2 2 2 2 3 3 3
+ 0 1 1 1 2 2 2 2 2 3 3 3
diff --git a/examples/simple/igraph_add_vertices.c b/examples/simple/igraph_add_vertices.c
new file mode 100644
index 0000000..0ea8edb
--- /dev/null
+++ b/examples/simple/igraph_add_vertices.c
@@ -0,0 +1,63 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  igraph_t g1;
+  igraph_vector_t v1;
+  int ret;
+
+  /* Create a graph */
+  igraph_vector_init(&v1, 8);
+  VECTOR(v1)[0]=0; VECTOR(v1)[1]=1;
+  VECTOR(v1)[2]=1; VECTOR(v1)[3]=2;
+  VECTOR(v1)[4]=2; VECTOR(v1)[5]=3;
+  VECTOR(v1)[6]=2; VECTOR(v1)[7]=2;
+  igraph_create(&g1, &v1, 0, 0);
+  igraph_vector_destroy(&v1);
+
+  /* Add more vertices */
+  igraph_add_vertices(&g1, 10, 0);
+  if (igraph_vcount(&g1) != 14) {
+    return 1;
+  }
+
+  /* Add more vertices */
+  igraph_add_vertices(&g1, 0, 0);
+  if (igraph_vcount(&g1) != 14) {
+    return 2;
+  }
+  
+  /* Error */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_add_vertices(&g1, -1, 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 3;
+  }
+  
+  igraph_destroy(&g1);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_adjacency.c b/examples/simple/igraph_adjacency.c
new file mode 100644
index 0000000..a657c02
--- /dev/null
+++ b/examples/simple/igraph_adjacency.c
@@ -0,0 +1,29 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  return 0;
+}
diff --git a/examples/simple/igraph_all_st_cuts.c b/examples/simple/igraph_all_st_cuts.c
new file mode 100644
index 0000000..ae20ead
--- /dev/null
+++ b/examples/simple/igraph_all_st_cuts.c
@@ -0,0 +1,375 @@
+/* -*- 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.h>
+#include <igraph_marked_queue.h>
+#include <igraph_estack.h>
+
+int igraph_i_all_st_cuts_pivot(const igraph_t *graph,
+			       const igraph_marked_queue_t *S,
+			       const igraph_estack_t *T,
+			       long int source,
+			       long int target,
+			       long int *v,
+			       igraph_vector_t *Isv);
+
+int main() {
+  igraph_t g;
+  igraph_vector_ptr_t cuts, partition1s;
+  long int i, n;
+
+  igraph_marked_queue_t S;
+  igraph_estack_t T;
+  long int v;
+  igraph_vector_t Isv;
+
+  /* ----------------------------------------------------------- */
+  /* This is the example from the Provan-Shier paper, 
+     for calculating the dominator tree and finding the right pivot 
+     element */
+  
+  igraph_small(&g, 12, IGRAPH_DIRECTED,
+  	       /* a->b */ 0,1,
+  	       /* b->t */ 1,11,
+  	       /* c->b */ 2,1,  /* c->d */ 2,3,
+  	       /* d->e */ 3,4,  /* d->i */ 3,8,
+  	       /* e->c */ 4,2,
+  	       /* f->c */ 5,2,  /* f->e */ 5,4,
+  	       /* g->d */ 6,3,  /* g->e */ 6,4,  /* g->f */ 6,5,
+  	                        /* g->j */ 6,9,
+  	       /* h->g */ 7,6,  /* h->t */ 7,11,
+  	       /* i->a */ 8,0,
+  	       /* j->i */ 9,8,
+  	       /* s->a */ 10,0, /* s->c */ 10,2, /* s->h */ 10,7,
+  	       -1);
+  
+  /* S={s,a} */
+  igraph_marked_queue_init(&S, igraph_vcount(&g));
+  igraph_marked_queue_start_batch(&S);
+  igraph_marked_queue_push(&S, 10);
+  igraph_marked_queue_push(&S, 0);
+  
+  /* T={t} */
+  igraph_estack_init(&T, igraph_vcount(&g), 1);
+  igraph_estack_push(&T, 11);
+
+  igraph_vector_init(&Isv, 0);
+  igraph_i_all_st_cuts_pivot(&g, &S, &T,
+  				/*source=*/ 10, /*target=*/ 11,
+  				&v, &Isv);
+
+  /* Expected result: v=c, Isv={c,d,e,i} */
+  printf("%li; ", v);
+  igraph_vector_print(&Isv);
+  
+  igraph_vector_destroy(&Isv);
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,1, 1,2,
+  	       -1);
+  
+  /* S={}, T={} */
+  igraph_marked_queue_init(&S, igraph_vcount(&g));
+  igraph_estack_init(&T, igraph_vcount(&g), 3);
+
+  igraph_vector_init(&Isv, 0);
+  igraph_i_all_st_cuts_pivot(&g, &S, &T,
+  				/*source=*/ 0, /*target=*/ 2,
+  				&v, &Isv);
+  printf("%li; ", v);
+  igraph_vector_print(&Isv);
+
+  igraph_vector_destroy(&Isv);
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,1, 1,2,
+  	       -1);
+  
+  /* S={}, T={0} */
+  igraph_marked_queue_init(&S, igraph_vcount(&g));
+
+  igraph_estack_init(&T, igraph_vcount(&g), 3);
+  igraph_estack_push(&T, 0);
+
+  igraph_vector_init(&Isv, 0);
+  igraph_i_all_st_cuts_pivot(&g, &S, &T,
+  				/*source=*/ 0, /*target=*/ 2,
+  				&v, &Isv);
+  printf("%li; ", v);
+  igraph_vector_print(&Isv);
+
+  igraph_vector_destroy(&Isv);
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,1, 1,2,
+  	       -1);
+  
+  /* S={0}, T={} */
+  igraph_marked_queue_init(&S, igraph_vcount(&g));
+  igraph_marked_queue_push(&S, 0);
+
+  igraph_estack_init(&T, igraph_vcount(&g), 3);
+
+  igraph_vector_init(&Isv, 0);
+  igraph_i_all_st_cuts_pivot(&g, &S, &T,
+  				/*source=*/ 0, /*target=*/ 2,
+  				&v, &Isv);
+  printf("%li; ", v);
+  igraph_vector_print(&Isv);
+
+  igraph_vector_destroy(&Isv);
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,1, 1,2,
+  	       -1);
+  
+  /* S={0}, T={1} */
+  igraph_marked_queue_init(&S, igraph_vcount(&g));
+  igraph_marked_queue_push(&S, 0);
+
+  igraph_estack_init(&T, igraph_vcount(&g), 3);
+  igraph_estack_push(&T, 1);
+
+  igraph_vector_init(&Isv, 0);
+  igraph_i_all_st_cuts_pivot(&g, &S, &T,
+  				/*source=*/ 0, /*target=*/ 2,
+  				&v, &Isv);
+  printf("%li; ", v);
+  igraph_vector_print(&Isv);
+
+  igraph_vector_destroy(&Isv);
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,1, 1,2,
+  	       -1);
+  
+  /* S={0,1}, T={} */
+  igraph_marked_queue_init(&S, igraph_vcount(&g));
+  igraph_marked_queue_push(&S, 0);
+  igraph_marked_queue_push(&S, 1);
+
+  igraph_estack_init(&T, igraph_vcount(&g), 3);
+
+  igraph_vector_init(&Isv, 0);
+  igraph_i_all_st_cuts_pivot(&g, &S, &T,
+  				/*source=*/ 0, /*target=*/ 2,
+  				&v, &Isv);
+  printf("%li; ", v);
+  igraph_vector_print(&Isv);
+
+  igraph_vector_destroy(&Isv);
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,1, 1,2,
+  	       -1);
+
+  igraph_vector_ptr_init(&partition1s, 0);
+  igraph_all_st_cuts(&g, /*cuts=*/ 0, &partition1s,
+		     /*source=*/ 0, /*target=*/ 2);
+
+  n=igraph_vector_ptr_size(&partition1s);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(partition1s)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+  igraph_vector_ptr_destroy(&partition1s);
+  
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 5, IGRAPH_DIRECTED,
+  	       0,1, 1,2, 1,3, 2,4, 3,4,
+  	       -1);
+
+  igraph_vector_ptr_init(&partition1s, 0);
+  igraph_all_st_cuts(&g, /*cuts=*/ 0, &partition1s,
+		     /*source=*/ 0, /*target=*/ 4);
+
+  n=igraph_vector_ptr_size(&partition1s);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(partition1s)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+  igraph_vector_ptr_destroy(&partition1s);
+  
+  igraph_destroy(&g);  
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 6, IGRAPH_DIRECTED,
+  	       0,1, 1,2, 1,3, 2,4, 3,4, 1,5, 5,4,
+  	       -1);
+
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_vector_ptr_init(&partition1s, 0);
+  igraph_all_st_cuts(&g, &cuts, &partition1s,
+		     /*source=*/ 0, /*target=*/ 4);
+
+  n=igraph_vector_ptr_size(&partition1s);
+  printf("Partitions and cuts:\n");
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(partition1s)[i];
+    igraph_vector_t *v2=VECTOR(cuts)[i];
+    printf("P: ");
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+    printf("C: ");
+    igraph_vector_print(v2);
+    igraph_vector_destroy(v2);
+    igraph_free(v2);
+  }
+  igraph_vector_ptr_destroy(&partition1s);
+  igraph_vector_ptr_destroy(&cuts);
+  
+  igraph_destroy(&g);  
+
+  /* ----------------------------------------------------------- */
+  
+  igraph_small(&g, 3, IGRAPH_DIRECTED,
+  	       0,2, 1,2,
+  	       -1);
+
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_vector_ptr_init(&partition1s, 0);
+  igraph_all_st_cuts(&g, &cuts, &partition1s,
+		     /*source=*/ 1, /*target=*/ 2);
+
+  n=igraph_vector_ptr_size(&partition1s);
+  printf("Partitions and cuts:\n");
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(partition1s)[i];
+    igraph_vector_t *v2=VECTOR(cuts)[i];
+    printf("P: ");
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+    printf("C: ");
+    igraph_vector_print(v2);
+    igraph_vector_destroy(v2);
+    igraph_free(v2);
+  }
+  igraph_vector_ptr_destroy(&partition1s);
+  igraph_vector_ptr_destroy(&cuts);
+  
+  igraph_destroy(&g);  
+
+  /* ----------------------------------------------------------- */
+  
+  igraph_small(&g, 5, IGRAPH_DIRECTED,
+	       0,1, 1,2, 2,3, 3,4, 3,1,
+	       -1);
+
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_vector_ptr_init(&partition1s, 0);
+  igraph_all_st_cuts(&g, &cuts, &partition1s,
+		     /*source=*/ 0, /*target=*/ 4);
+
+  n=igraph_vector_ptr_size(&partition1s);
+  printf("Partitions and cuts:\n");
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(partition1s)[i];
+    igraph_vector_t *v2=VECTOR(cuts)[i];
+    printf("P: ");
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+    printf("C: ");
+    igraph_vector_print(v2);
+    igraph_vector_destroy(v2);
+    igraph_free(v2);
+  }
+  igraph_vector_ptr_destroy(&partition1s);
+  igraph_vector_ptr_destroy(&cuts);
+  
+  igraph_destroy(&g);  
+
+  /* ----------------------------------------------------------- */
+  
+  igraph_small(&g, 7, IGRAPH_DIRECTED,
+	       0,1,0,2, 1,3,2,3,
+	       1,4,1,5,1,6, 
+	       4,2,5,2,6,2,
+	       -1);
+
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_vector_ptr_init(&partition1s, 0);
+  igraph_all_st_cuts(&g, &cuts, &partition1s,
+		     /*source=*/ 0, /*target=*/ 3);
+
+  n=igraph_vector_ptr_size(&partition1s);
+  printf("Partitions and cuts:\n");
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(partition1s)[i];
+    igraph_vector_t *v2=VECTOR(cuts)[i];
+    printf("P: ");
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+    printf("C: ");
+    igraph_vector_print(v2);
+    igraph_vector_destroy(v2);
+    igraph_free(v2);
+  }
+  igraph_vector_ptr_destroy(&partition1s);
+  igraph_vector_ptr_destroy(&cuts);
+  
+  igraph_destroy(&g);  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_all_st_cuts.out b/examples/simple/igraph_all_st_cuts.out
new file mode 100644
index 0000000..e681149
--- /dev/null
+++ b/examples/simple/igraph_all_st_cuts.out
@@ -0,0 +1,67 @@
+2; 2 3 4 8
+0; 0
+0; 
+1; 1
+1; 
+1; 
+0
+0 1
+0
+0 1
+0 1 3
+0 1 2
+0 1 2 3
+Partitions and cuts:
+P: 0
+C: 0
+P: 0 1
+C: 1 2 5
+P: 0 1 5
+C: 1 2 6
+P: 0 1 3
+C: 1 4 5
+P: 0 1 3 5
+C: 1 4 6
+P: 0 1 2
+C: 2 3 5
+P: 0 1 2 5
+C: 2 3 6
+P: 0 1 2 3
+C: 3 4 5
+P: 0 1 2 3 5
+C: 3 4 6
+Partitions and cuts:
+P: 1
+C: 1
+Partitions and cuts:
+P: 0
+C: 0
+P: 0 1
+C: 1
+P: 0 1 2
+C: 2
+P: 0 1 2 3
+C: 3
+Partitions and cuts:
+P: 0
+C: 0 1
+P: 0 2
+C: 0 3
+P: 0 1
+C: 1 2 4 5 6
+P: 0 1 6
+C: 1 2 4 5 9
+P: 0 1 5
+C: 1 2 4 6 8
+P: 0 1 5 6
+C: 1 2 4 8 9
+P: 0 1 4
+C: 1 2 5 6 7
+P: 0 1 4 6
+C: 1 2 5 7 9
+P: 0 1 4 5
+C: 1 2 6 7 8
+P: 0 1 4 5 6
+C: 1 2 7 8 9
+P: 0 1 4 5 6 2
+C: 2 3
diff --git a/examples/simple/igraph_all_st_mincuts.c b/examples/simple/igraph_all_st_mincuts.c
new file mode 100644
index 0000000..46402d1
--- /dev/null
+++ b/examples/simple/igraph_all_st_mincuts.c
@@ -0,0 +1,104 @@
+/* -*- 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.h>
+
+int print_and_destroy(igraph_real_t value, 
+		      igraph_vector_ptr_t *partitions, 
+		      igraph_vector_ptr_t *cuts) {
+  long int i, n=igraph_vector_ptr_size(partitions);
+  printf("Value: %g\n", value);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *vec=VECTOR(*partitions)[i];
+    igraph_vector_t *vec2=cuts ? VECTOR(*cuts)[i] : 0;
+    printf("Partition: "); igraph_vector_print(vec);
+    if (vec2) { printf("Cut: "); igraph_vector_print(vec2); }
+    igraph_vector_destroy(vec);
+    if (vec2) { igraph_vector_destroy(vec2); }
+    igraph_free(vec);
+    if (vec2) { igraph_free(vec2); }
+  }  
+  igraph_vector_ptr_destroy(partitions);
+  if (cuts) { igraph_vector_ptr_destroy(cuts); }
+  
+  return 0;
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_ptr_t partitions;
+  igraph_vector_ptr_t cuts;
+  igraph_real_t value;
+  
+  igraph_small(&g, 5, IGRAPH_DIRECTED,
+  	       0,1, 1,2, 2,3, 3,4,
+  	       -1);
+  
+  igraph_vector_ptr_init(&partitions, 0);
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_all_st_mincuts(&g, &value, &cuts, &partitions,
+  			/*source=*/ 0, /*target=*/ 4,
+  			/*capacity=*/ 0);
+  
+  print_and_destroy(value, &partitions, &cuts);
+  igraph_destroy(&g);
+
+  /* ---------------------------------------------------------------- */
+  
+  igraph_small(&g, 6, IGRAPH_DIRECTED, 0,1, 1,2, 1,3, 2,4, 3,4, 4,5, -1);
+  igraph_vector_ptr_init(&partitions, 0);
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_all_st_mincuts(&g, &value, &cuts, &partitions,
+  			/*source=*/ 0, /*target=*/ 5, /*capacity=*/ 0);
+
+  print_and_destroy(value, &partitions, &cuts);
+  igraph_destroy(&g);
+
+  /* ---------------------------------------------------------------- */
+  
+  igraph_small(&g, 6, IGRAPH_DIRECTED, 0,1, 1,2, 1,3, 2,4, 3,4, 4,5, -1);
+  igraph_vector_ptr_init(&partitions, 0);
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_all_st_mincuts(&g, &value, &cuts, &partitions,
+  			/*source=*/ 0, /*target=*/ 4, /*capacity=*/ 0);
+
+  print_and_destroy(value, &partitions, &cuts);
+  igraph_destroy(&g);
+
+  /* ---------------------------------------------------------------- */
+  
+  igraph_small(&g, 9, IGRAPH_DIRECTED, 0,1, 0,2, 1,3, 2,3,
+	       1,4,4,2, 1,5,5,2, 1,6,6,2, 1,7,7,2, 1,8,8,2,
+	       -1);
+  igraph_vector_ptr_init(&partitions, 0);
+  igraph_vector_ptr_init(&cuts, 0);
+  igraph_all_st_mincuts(&g, &value, &cuts, &partitions,
+  			/*source=*/ 0, /*target=*/ 3, /*capacity=*/ 0);
+
+  print_and_destroy(value, &partitions, &cuts);
+  igraph_destroy(&g);
+
+ 
+  return 0;
+}
diff --git a/examples/simple/igraph_all_st_mincuts.out b/examples/simple/igraph_all_st_mincuts.out
new file mode 100644
index 0000000..2f47d36
--- /dev/null
+++ b/examples/simple/igraph_all_st_mincuts.out
@@ -0,0 +1,24 @@
+Value: 1
+Partition: 0
+Cut: 0
+Partition: 0 1
+Cut: 1
+Partition: 0 1 2
+Cut: 2
+Partition: 0 1 2 3
+Cut: 3
+Value: 1
+Partition: 0
+Cut: 0
+Partition: 0 4 3 2 1
+Cut: 5
+Value: 1
+Partition: 0
+Cut: 0
+Value: 2
+Partition: 0
+Cut: 0 1
+Partition: 0 2
+Cut: 0 3
+Partition: 0 2 1 8 7 6 5 4
+Cut: 2 3
diff --git a/examples/simple/igraph_are_connected.c b/examples/simple/igraph_are_connected.c
new file mode 100644
index 0000000..72e9d61
--- /dev/null
+++ b/examples/simple/igraph_are_connected.c
@@ -0,0 +1,108 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for whether two vertices are connected by an edge.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+#include <time.h>
+
+#define R_INTEGER(a,b) (igraph_rng_get_integer(igraph_rng_default(), (a), (b)))
+
+/* Crash the library function here. We expect error codes to be returned here.
+ */
+int error_test() {
+  igraph_t g;
+  igraph_bool_t connected;
+  igraph_integer_t nvert, u, v;
+  int ret;
+
+  igraph_rng_seed(igraph_rng_default(), time(0));
+  igraph_small(&g, /*nvert*/ 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  nvert = igraph_vcount(&g);
+  u = (igraph_integer_t)R_INTEGER(-100*nvert, 100*nvert);
+  v = (igraph_integer_t)R_INTEGER(nvert, 100*nvert);
+
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret = igraph_are_connected(&g, u, v, &connected);
+  if (ret != IGRAPH_EINVVID) {
+    printf("Error test failed.\n");
+    return IGRAPH_FAILURE;
+  }
+  igraph_destroy(&g);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* Testing for two vertices being connected by an edge in various graphs.
+ */
+int connected_test() {
+  igraph_t gcomplete, gempty;
+  igraph_bool_t connected;
+  igraph_integer_t nvert, u, v;
+
+  igraph_rng_seed(igraph_rng_default(), time(0));
+
+  /* A complete graph on n vertices. Any two distinct vertices are connected */
+  /* by an edge. Hence we expect the test to return true for any given pair */
+  /* of distinct vertices. */
+  nvert = (igraph_integer_t)R_INTEGER(2, 100);
+  igraph_full(&gcomplete, nvert, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  u = (igraph_integer_t)R_INTEGER(0, nvert - 1);
+  do {
+    v = (igraph_integer_t)R_INTEGER(0, nvert - 1);
+  } while (v == u);
+  igraph_are_connected(&gcomplete, u, v, &connected);
+  if (!connected) {
+    printf("Expected connected = true, but received connected = false.\n");
+    return IGRAPH_FAILURE;
+  }
+  igraph_destroy(&gcomplete);
+
+  /* A graph with n vertices, but no edges. Any two distinct vertices are */
+  /* not joined by an edge. Thus we expect the test to return false for any */
+  /* given pair of distinct vertices. */
+  nvert = (igraph_integer_t)R_INTEGER(2, 100);
+  igraph_empty(&gempty, nvert, IGRAPH_DIRECTED);
+  u = (igraph_integer_t)R_INTEGER(0, nvert - 1);
+  do {
+    v = (igraph_integer_t)R_INTEGER(0, nvert - 1);
+  } while (v == u);
+  igraph_are_connected(&gempty, u, v, &connected);
+  if (connected) {
+    printf("Expected connected = false, but received connected = true.\n");
+    return IGRAPH_FAILURE;
+  }
+  igraph_destroy(&gempty);
+
+  return IGRAPH_SUCCESS;
+}
+
+int main() {
+  int ret;
+
+  ret = error_test();
+  if (ret)
+    return IGRAPH_FAILURE;
+  ret = connected_test();
+  if (ret)
+    return IGRAPH_FAILURE;
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/examples/simple/igraph_arpack_rnsolve.c b/examples/simple/igraph_arpack_rnsolve.c
new file mode 100644
index 0000000..4ab65d0
--- /dev/null
+++ b/examples/simple/igraph_arpack_rnsolve.c
@@ -0,0 +1,130 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+typedef struct cb2_data_t {
+  igraph_matrix_t *A;
+} cb2_data_t;
+
+int cb2(igraph_real_t *to, const igraph_real_t *from, int n, void *extra) {
+  cb2_data_t *data=(cb2_data_t*) extra;
+  igraph_blas_dgemv_array(/*transpose=*/ 0, /*alpha=*/ 1.0, 
+			  data->A, from, /*beta=*/ 0.0, to);
+  return 0;
+}
+
+#define DIM 10
+
+int main() {
+  igraph_matrix_t A;
+  igraph_matrix_t values, vectors;
+  igraph_arpack_options_t options;
+  cb2_data_t data = { &A };  
+  int i, j;
+
+  igraph_rng_seed(igraph_rng_default(), 42 * 42);
+
+  igraph_matrix_init(&A, DIM, DIM);
+
+  for (i=0; i<DIM; i++) {
+    for (j=0; j<DIM; j++) {
+      MATRIX(A, i, j) = igraph_rng_get_integer(igraph_rng_default(), -10, 10);
+    }
+  }
+  
+  igraph_arpack_options_init(&options);
+  options.n=DIM;
+  options.start=0;
+  options.nev=4;
+  options.ncv=9;
+  options.which[0]='L' ; options.which[1]='M';
+
+  igraph_matrix_init(&values, 0, 0);
+  igraph_matrix_init(&vectors, options.n, 1);
+
+  igraph_arpack_rnsolve(cb2, /*extra=*/ &data, &options, /*storage=*/ 0, 
+			&values, &vectors);
+
+  if (MATRIX(values, 2, 1) > 0) {
+    MATRIX(values, 2, 1) = -MATRIX(values, 2, 1);
+    MATRIX(values, 3, 1) = -MATRIX(values, 3, 1);    
+  }
+
+  igraph_matrix_print(&values);
+  printf("---\n");
+  igraph_matrix_print(&vectors);
+  printf("---\n");
+
+  /* -------------- */
+
+  options.nev=3;
+  options.which[0]='L' ; options.which[1]='M';
+
+  igraph_arpack_rnsolve(cb2, /*extra=*/ &data, &options, /*storage=*/ 0, 
+			&values, &vectors);
+
+  if (MATRIX(values, 2, 1) > 0) {
+    MATRIX(values, 2, 1) = -MATRIX(values, 2, 1);
+  }
+
+  igraph_matrix_print(&values);
+  printf("---\n");
+  igraph_matrix_print(&vectors);
+  printf("---\n");
+
+  /* -------------- */
+
+  options.nev=3;
+  options.which[0]='S' ; options.which[1]='R';
+
+  igraph_arpack_rnsolve(cb2, /*extra=*/ &data, &options, /*storage=*/ 0, 
+			&values, &vectors);
+
+  igraph_matrix_print(&values);
+  printf("---\n");
+  igraph_matrix_print(&vectors);
+  printf("---\n");
+
+  /* -------------- */
+
+  options.nev=3;
+  options.which[0]='L' ; options.which[1]='I';
+
+  igraph_arpack_rnsolve(cb2, /*extra=*/ &data, &options, /*storage=*/ 0, 
+			&values, &vectors);
+
+  igraph_matrix_print(&values);
+  printf("---\n");
+  igraph_matrix_print(&vectors);
+  printf("---\n");
+
+  /* -------------- */
+
+  igraph_matrix_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+  igraph_matrix_destroy(&A);
+  
+  return 0;
+}
+			
diff --git a/examples/simple/igraph_arpack_rnsolve.out b/examples/simple/igraph_arpack_rnsolve.out
new file mode 100644
index 0000000..ec38497
--- /dev/null
+++ b/examples/simple/igraph_arpack_rnsolve.out
@@ -0,0 +1,61 @@
+22.0483 0
+-21.3281 0
+-3.00735 -19.2957
+-3.00735 19.2957
+---
+-0.373224 0.226696 0.0473383 -0.204213
+0.289145 -0.296079 0.156365 0.0479785
+-0.539167 -0.046114 0.189081 0.152399
+-0.155332 0.358022 -0.364566 0.0248164
+-0.217492 -0.618375 -0.30221 -0.084056
+0.395358 0.276259 -0.0368916 -0.429673
+-0.323702 0.196714 0.132731 -0.336104
+-0.177548 0.177994 0.382879 -0.0409697
+0.348174 0.0512606 -0.305212 0.141094
+0.0335622 0.446014 0.239725 0.0551197
+---
+22.0483 0
+-21.3281 0
+-3.00735 -19.2957
+---
+0.373224 0.226696 0.204213 0.0473383
+-0.289145 -0.296079 -0.0479785 0.156365
+0.539167 -0.046114 -0.152399 0.189081
+0.155332 0.358022 -0.0248164 -0.364566
+0.217492 -0.618375 0.084056 -0.30221
+-0.395358 0.276259 0.429673 -0.0368916
+0.323702 0.196714 0.336104 0.132731
+0.177548 0.177994 0.0409697 0.382879
+-0.348174 0.0512606 -0.141094 -0.305212
+-0.0335622 0.446014 -0.0551197 0.239725
+---
+-21.3281 0
+-12.4527 0
+-3.00735 -19.2957
+---
+-0.226696 0.695866 -0.204213 -0.0473383
+0.296079 0.120213 0.0479785 -0.156365
+0.046114 0.0628274 0.152399 -0.189081
+-0.358022 -0.0817567 0.0248164 0.364566
+0.618375 -0.354011 -0.084056 0.30221
+-0.276259 0.33649 -0.429673 0.0368916
+-0.196714 0.284155 -0.336104 -0.132731
+-0.177994 0.0164834 -0.0409697 -0.382879
+-0.0512606 0.175732 0.141094 0.305212
+-0.446014 0.374487 0.0551197 -0.239725
+---
+-3.00735 19.2957
+-3.00735 -19.2957
+12.1099 6.27293
+---
+0.0768616 -0.195028 -0.152389 0.21912
+0.147607 0.0704569 0.346547 0.125122
+0.164607 0.178554 -0.153007 -0.188931
+-0.364251 -0.0290787 0.0368355 0.21496
+-0.286559 -0.127595 -0.277981 0.264759
+0.0267116 -0.430426 0.246402 0.129704
+0.180726 -0.312925 -0.262001 -0.40777
+0.384741 0.0157948 -0.296988 0.134903
+-0.322646 0.0946649 -0.148076 0.121394
+0.229009 0.089782 -0.271714 0.0980886
+---
diff --git a/examples/simple/igraph_array.c b/examples/simple/igraph_array.c
new file mode 100644
index 0000000..d8f25d8
--- /dev/null
+++ b/examples/simple/igraph_array.c
@@ -0,0 +1,85 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdio.h>
+
+void print_vector(const igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+void print_array(const igraph_array3_t *a, FILE *f) {
+  long int i,j,k;
+  for (k=0; k<igraph_array3_n(a, 3); k++) {
+    for (i=0; i<igraph_array3_n(a, 1); i++) {
+      for (j=0; j<igraph_array3_n(a, 2); j++) {
+	fprintf(f, " %li", (long int) ARRAY3(*a, i, j, k));
+      }
+      fprintf(f, "\n");
+    }
+    fprintf(f, "\n");
+  }
+}
+
+int main() {
+  igraph_array3_t a;
+  long int i,j,k;
+  long int s=1;
+  
+  igraph_array3_init(&a, 5,4,3);
+  igraph_array3_destroy(&a);
+
+  igraph_array3_init(&a, 5,4,3);
+  print_array(&a, stdout);
+  if (igraph_array3_n(&a, 1) != 5) { 
+    return 1;
+  } 
+  if (igraph_array3_n(&a, 2) != 4) { 
+    return 1;
+  } 
+  if (igraph_array3_n(&a, 3) != 3) { 
+    return 1;
+  } 
+  igraph_array3_destroy(&a);
+
+  igraph_array3_init(&a,5,4,3);
+  for (k=0; k<igraph_array3_n(&a,3); k++) {
+    for (j=0; j<igraph_array3_n(&a,2); j++) {
+      for (i=0; i<igraph_array3_n(&a,1); i++) {
+	ARRAY3(a,i,j,k) = s++;
+      }
+    }
+  }
+  print_array(&a,stdout);
+  print_vector(&a.data, stdout);
+  igraph_array3_destroy(&a);
+  
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 2;
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_array.out b/examples/simple/igraph_array.out
new file mode 100644
index 0000000..bf20c02
--- /dev/null
+++ b/examples/simple/igraph_array.out
@@ -0,0 +1,37 @@
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+
+ 1 6 11 16
+ 2 7 12 17
+ 3 8 13 18
+ 4 9 14 19
+ 5 10 15 20
+
+ 21 26 31 36
+ 22 27 32 37
+ 23 28 33 38
+ 24 29 34 39
+ 25 30 35 40
+
+ 41 46 51 56
+ 42 47 52 57
+ 43 48 53 58
+ 44 49 54 59
+ 45 50 55 60
+
+ 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
diff --git a/examples/simple/igraph_atlas.c b/examples/simple/igraph_atlas.c
new file mode 100644
index 0000000..a5ef2a1
--- /dev/null
+++ b/examples/simple/igraph_atlas.c
@@ -0,0 +1,58 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  igraph_t g;
+  int ret;
+
+  igraph_atlas(&g, 45);
+  igraph_write_graph_edgelist(&g, stdout);
+  printf("\n");
+  igraph_destroy(&g);
+
+  igraph_atlas(&g, 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  printf("\n");
+  igraph_destroy(&g);
+
+  igraph_atlas(&g, 1252);
+  igraph_write_graph_edgelist(&g, stdout);
+  printf("\n");
+  igraph_destroy(&g);
+
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_atlas(&g, -1);
+  if (ret != IGRAPH_EINVAL) {
+    return 1;
+  }
+
+  ret=igraph_atlas(&g, 1253);
+  if (ret != IGRAPH_EINVAL) {
+    return 2;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_atlas.out b/examples/simple/igraph_atlas.out
new file mode 100644
index 0000000..38233da
--- /dev/null
+++ b/examples/simple/igraph_atlas.out
@@ -0,0 +1,31 @@
+0 4
+1 2
+1 3
+1 4
+2 3
+2 4
+3 4
+
+
+0 1
+0 2
+0 3
+0 4
+0 5
+0 6
+1 2
+1 3
+1 4
+1 5
+1 6
+2 3
+2 4
+2 5
+2 6
+3 4
+3 5
+3 6
+4 5
+4 6
+5 6
+
diff --git a/examples/simple/igraph_average_path_length.c b/examples/simple/igraph_average_path_length.c
new file mode 100644
index 0000000..73c3e22
--- /dev/null
+++ b/examples/simple/igraph_average_path_length.c
@@ -0,0 +1,40 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_real_t result;
+  
+  igraph_barabasi_game(&g, 30, /*power=*/ 1, 30, 0, 0, /*A=*/ 1, 
+		       IGRAPH_DIRECTED, IGRAPH_BARABASI_BAG,
+		       /*start_from=*/ 0);
+  igraph_average_path_length(&g, &result, IGRAPH_UNDIRECTED, 1);
+  
+/*   printf("Length of the average shortest paths: %f\n", (float) result); */
+  
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/igraph_barabasi_game.c b/examples/simple/igraph_barabasi_game.c
new file mode 100644
index 0000000..0dc31d8
--- /dev/null
+++ b/examples/simple/igraph_barabasi_game.c
@@ -0,0 +1,118 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t v, v2;
+  int i, ret;
+  
+  igraph_barabasi_game(&g, 10, /*power=*/ 1, 2, 0, 0, /*A=*/ 1, 1, 
+		       IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
+  if (igraph_ecount(&g) != 18) {
+    return 1;
+  }
+  if (igraph_vcount(&g) != 10) {
+    return 2;
+  }
+  if (!igraph_is_directed(&g)) {
+    return 3;
+  }
+
+  igraph_vector_init(&v, 0);
+  igraph_get_edgelist(&g, &v, 0);
+  for (i=0; i<igraph_ecount(&g); i++) {
+    if (VECTOR(v)[2*i] <= VECTOR(v)[2*i+1]) {
+      return 4;
+    }
+  }
+  igraph_destroy(&g);
+  
+  /* out degree sequence */
+  igraph_vector_resize(&v, 10);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=3; VECTOR(v)[3]=3;
+  VECTOR(v)[4]=4; VECTOR(v)[5]=5;
+  VECTOR(v)[6]=6; VECTOR(v)[7]=7;
+  VECTOR(v)[8]=8; VECTOR(v)[9]=9;
+  
+  igraph_barabasi_game(&g, 10, /*power=*/ 1, 0, &v, 0, /*A=*/ 1, 1, 
+		       IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
+  if (igraph_ecount(&g) != igraph_vector_sum(&v)) {
+    return 5;
+  }
+  igraph_vector_init(&v2, 0);
+  igraph_degree(&g, &v2, igraph_vss_all(), IGRAPH_OUT, 1);
+  for (i=0; i<igraph_vcount(&g); i++) {
+    if (VECTOR(v)[i] != VECTOR(v2)[i]) {
+      igraph_vector_print(&v);
+      printf("\n");
+      igraph_vector_print(&v2);
+      return 6;
+    }
+  }
+  igraph_vector_destroy(&v);
+  igraph_vector_destroy(&v2);
+  igraph_destroy(&g);
+  
+  /* outpref, we cannot really test this quantitatively,
+     would need to set random seed */
+  igraph_barabasi_game(&g, 10, /*power=*/ 1, 2, 0, 1, /*A=*/ 1, 1,
+		       IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
+  igraph_vector_init(&v, 0);
+  igraph_get_edgelist(&g, &v, 0);
+  for (i=0; i<igraph_ecount(&g); i++) {
+    if (VECTOR(v)[2*i] <= VECTOR(v)[2*i+1]) {
+      return 7;
+    }
+  }
+  if (!igraph_is_directed(&g)) {
+    return 8;
+  }
+  igraph_vector_destroy(&v);
+  igraph_destroy(&g);
+
+  /* Error tests */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_barabasi_game(&g, -10, /*power=*/ 1, 1, 0, 0, /*A=*/ 1, 0, 
+			   IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 9;
+  }
+  ret=igraph_barabasi_game(&g, 10, /*power=*/ 1, -2, 0, 0, /*A=*/ 1, 0,
+			   IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 10;
+  }
+  igraph_vector_init(&v, 9);
+  ret=igraph_barabasi_game(&g, 10, /*power=*/ 1, 0, &v, 0, /*A=*/ 1, 0,
+			   IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 11;
+  }
+  igraph_vector_destroy(&v);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_barabasi_game2.c b/examples/simple/igraph_barabasi_game2.c
new file mode 100644
index 0000000..82e6945
--- /dev/null
+++ b/examples/simple/igraph_barabasi_game2.c
@@ -0,0 +1,92 @@
+/* -*- 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.h>
+#include <stdio.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_bool_t simple;
+
+  igraph_barabasi_game(/* graph=    */ &g, 
+		       /* n=        */ 100,
+		       /* power=    */ 1.0,
+		       /* m=        */ 2,
+		       /* outseq=   */ 0,
+		       /* outpref=  */ 0,
+		       /* A=        */ 1.0,
+		       /* directed= */ IGRAPH_DIRECTED,
+		       /* algo=     */ IGRAPH_BARABASI_PSUMTREE,
+		       /* start_from= */ 0);
+  
+  if (igraph_ecount(&g) != 197) { return 1; }
+  if (igraph_vcount(&g) != 100) { return 2; }
+  igraph_is_simple(&g, &simple);
+  if (!simple) { return 3; }
+  
+  igraph_destroy(&g);
+  
+  /* ============================== */
+
+  igraph_barabasi_game(/* graph=    */ &g, 
+		       /* n=        */ 100,
+		       /* power=    */ 1.0,
+		       /* m=        */ 2,
+		       /* outseq=   */ 0,
+		       /* outpref=  */ 0,
+		       /* A=        */ 1.0,
+		       /* directed= */ IGRAPH_DIRECTED,
+		       /* algo=     */ IGRAPH_BARABASI_PSUMTREE_MULTIPLE,
+		       /* start_from= */ 0);
+
+  if (igraph_ecount(&g) != 198) { return 4; }
+  if (igraph_vcount(&g) != 100) { return 5; }
+  igraph_is_simple(&g, &simple);
+  if (simple) { return 6; }
+  
+  igraph_destroy(&g);
+
+  /* ============================== */
+
+  igraph_barabasi_game(/* graph=    */ &g, 
+		       /* n=        */ 100,
+		       /* power=    */ 1.0,
+		       /* m=        */ 2,
+		       /* outseq=   */ 0,
+		       /* outpref=  */ 0,
+		       /* A=        */ 1.0,
+		       /* directed= */ IGRAPH_DIRECTED,
+		       /* algo=     */ IGRAPH_BARABASI_BAG,
+		       /* start_from= */ 0);
+
+  if (igraph_ecount(&g) != 198) { return 7; }
+  if (igraph_vcount(&g) != 100) { return 8; }
+  igraph_is_simple(&g, &simple);
+  if (simple) { return 9; }
+  
+  igraph_destroy(&g);    
+  
+  return 0;
+}
+
diff --git a/examples/simple/igraph_betweenness.c b/examples/simple/igraph_betweenness.c
new file mode 100644
index 0000000..0e53ff0
--- /dev/null
+++ b/examples/simple/igraph_betweenness.c
@@ -0,0 +1,140 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t bet, bet2, weights, edges;
+  
+  igraph_real_t nontriv[] = { 0, 19, 0, 16, 0, 20, 1, 19, 2, 5, 3, 7, 3, 8, 
+			      4, 15, 4, 11, 5, 8, 5, 19, 6, 7, 6, 10, 6, 8, 
+			      6, 9, 7, 20, 9, 10, 9, 20, 10, 19, 
+			      11, 12, 11, 20, 12, 15, 13, 15, 
+			      14, 18, 14, 16, 14, 17, 15, 16, 17, 18 };
+  
+  igraph_real_t nontriv_weights[] = { 0.5249, 1, 0.1934, 0.6274, 0.5249, 
+				      0.0029, 0.3831, 0.05, 0.6274, 0.3831, 
+				      0.5249, 0.0587, 0.0579, 0.0562, 0.0562, 
+				      0.1934, 0.6274, 0.6274, 0.6274, 0.0418, 
+				      0.6274, 0.3511, 0.3511, 0.1486, 1, 1, 
+				      0.0711, 0.2409 };
+
+  igraph_real_t nontriv_res[] = { 20, 0, 0, 0, 0, 19, 80, 85, 32, 0, 10, 
+				  75, 70, 0, 36, 81, 60, 0, 19, 19, 86 };
+
+  /*******************************************************/
+
+  igraph_barabasi_game(/* graph= */    &g,
+		       /* n= */        1000,
+		       /* power= */    1,
+		       /* m= */        3,
+		       /* outseq= */   0,
+		       /* outpref= */  0,
+		       /* A= */        1,
+		       /* directed= */ 0,
+		       /* algo= */     IGRAPH_BARABASI_BAG,
+		       /* start_from= */ 0);
+  
+  igraph_simplify(&g, /* multiple= */ 1, /* loops= */ 1, /*edge_comb=*/ 0);
+  
+  igraph_vector_init(&bet, 0);
+  
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bet,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 2,
+			      /* weights=   */ 0, 
+			      /* nobigint=  */ 1);
+  
+  igraph_vector_destroy(&bet);
+  igraph_destroy(&g);
+
+  /*******************************************************/
+
+  igraph_tree(&g, 20000, 10, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_vector_init(&bet, 0);
+  
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bet,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 3,
+			      /* weights=   */ 0, 
+			      /* nobigint=  */ 1);
+
+  igraph_vector_init(&bet2, 0);
+  igraph_vector_init(&weights, igraph_ecount(&g));
+  igraph_vector_fill(&weights, 1.0);
+  
+  igraph_betweenness_estimate(/* graph=     */ &g,
+			      /* res=       */ &bet2,
+			      /* vids=      */ igraph_vss_all(),
+			      /* directed = */ 0,
+			      /* cutoff=    */ 3,
+			      /* weights=   */ &weights, 
+			      /* nobigint=  */ 1);
+
+  if (!igraph_vector_all_e(&bet, &bet2)) {
+    return 1;
+  }
+
+  igraph_vector_destroy(&bet);
+  igraph_vector_destroy(&bet2);
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* Non-trivial weighted graph */
+  igraph_vector_view(&edges, nontriv, sizeof(nontriv)/sizeof(igraph_real_t));
+  igraph_create(&g, &edges, 0, /* directed= */ 0);
+  igraph_vector_view(&weights, nontriv_weights, 
+		     sizeof(nontriv_weights)/sizeof(igraph_real_t));
+  igraph_vector_init(&bet, 0);
+
+  igraph_betweenness(/*graph=*/ &g, /*res=*/ &bet, /*vids=*/ igraph_vss_all(), 
+		     /*directed=*/0, /*weights=*/ &weights, /*nobigint=*/ 1);
+
+  igraph_vector_view(&bet2, nontriv_res, 
+		     sizeof(nontriv_res)/sizeof(igraph_real_t));
+
+  if (!igraph_vector_all_e(&bet, &bet2)) {
+    return 2;
+  }
+  
+  igraph_vector_destroy(&bet);
+  igraph_destroy(&g);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_bfs.c b/examples/simple/igraph_bfs.c
new file mode 100644
index 0000000..80e7b23
--- /dev/null
+++ b/examples/simple/igraph_bfs.c
@@ -0,0 +1,61 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void vector_print(igraph_vector_t *v) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t vids, layers, parents;
+
+  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 0);
+  igraph_vector_init(&vids, 0);
+  igraph_vector_init(&layers, 0);
+  igraph_vector_init(&parents, 0);
+  igraph_i_bfs(&g, 0, IGRAPH_ALL, &vids, &layers, &parents);
+  vector_print(&vids);
+  vector_print(&layers);
+  vector_print(&parents);
+  igraph_destroy(&g);  
+
+  igraph_tree(&g, 20, 2, IGRAPH_TREE_UNDIRECTED);
+  igraph_i_bfs(&g, 0, IGRAPH_ALL, &vids, &layers, &parents);
+  vector_print(&vids);
+  vector_print(&layers);
+  vector_print(&parents);
+  igraph_destroy(&g);  
+  
+  igraph_vector_destroy(&vids);
+  igraph_vector_destroy(&layers);
+  igraph_vector_destroy(&parents);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_bfs.out b/examples/simple/igraph_bfs.out
new file mode 100644
index 0000000..0a5924f
--- /dev/null
+++ b/examples/simple/igraph_bfs.out
@@ -0,0 +1,6 @@
+ 0 1 2 3 4 5 6 7 8 9
+ 0 1 2 3 4 5 6 7 8 9 10
+ 0 0 1 2 3 4 5 6 7 8
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 0 1 3 7 15 20
+ 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9
diff --git a/examples/simple/igraph_bfs2.c b/examples/simple/igraph_bfs2.c
new file mode 100644
index 0000000..969eb7e
--- /dev/null
+++ b/examples/simple/igraph_bfs2.c
@@ -0,0 +1,128 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+
+igraph_bool_t bfs_callback(const igraph_t *graph,
+			   igraph_integer_t vid, 
+			   igraph_integer_t pred, 
+			   igraph_integer_t succ,
+			   igraph_integer_t rank,
+			   igraph_integer_t dist,
+			   void *extra) {
+  printf(" %li", (long int) vid);
+  return 0;
+}		   
+
+int main() {
+  
+  igraph_t graph, ring;
+  igraph_vector_t order, rank, father, pred, succ, dist;
+  igraph_vector_t restricted;
+  igraph_vector_t roots;
+  long int i;
+  
+  igraph_ring(&ring, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_disjoint_union(&graph, &ring, &ring);
+  igraph_destroy(&ring);
+  
+  igraph_vector_init(&order, 0);
+  igraph_vector_init(&rank, 0);
+  igraph_vector_init(&father, 0);
+  igraph_vector_init(&pred, 0);
+  igraph_vector_init(&succ, 0);
+  igraph_vector_init(&dist, 0);
+  
+  igraph_bfs(&graph, /*root=*/0, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 1, /*restricted=*/ 0,
+	     &order, &rank, &father, &pred, &succ, &dist, 
+	     /*callback=*/ 0, /*extra=*/ 0);
+  
+  igraph_vector_print(&order);
+  igraph_vector_print(&rank);
+  igraph_vector_print(&father);
+  igraph_vector_print(&pred);
+  igraph_vector_print(&succ);
+  igraph_vector_print(&dist);
+
+  igraph_vector_destroy(&order);
+  igraph_vector_destroy(&rank);
+  igraph_vector_destroy(&father);
+  igraph_vector_destroy(&pred);
+  igraph_vector_destroy(&succ);
+  igraph_vector_destroy(&dist);
+
+  /* Test the callback */
+
+  igraph_bfs(&graph, /*root=*/ 0, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 1, /*restricted=*/ 0,
+	     0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+  printf("\n");
+  
+  /* Test different roots */
+
+  igraph_bfs(&graph, /*root=*/ 2, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 1, /*restricted=*/ 0,
+	     0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+  printf("\n");
+
+  /* Test restricted */
+
+  igraph_vector_init(&restricted, 0);
+  for (i=5; i<igraph_vcount(&graph); i++) {
+    igraph_vector_push_back(&restricted, i);
+  }
+  igraph_bfs(&graph, /*root=*/ 5, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 1, &restricted,
+	     0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+  printf("\n");  
+
+  /* Root not in restricted set */
+
+  igraph_bfs(&graph, /*root=*/ 4, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 1, &restricted,
+	     0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+  printf("\n");  
+
+  igraph_bfs(&graph, /*root=*/ 3, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 0, &restricted,
+	     0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+  printf("\n");  
+
+  /* Multiple root vertices */
+
+  igraph_vector_init(&roots, 3);
+  VECTOR(roots)[0]=3; 
+  VECTOR(roots)[1]=4;
+  VECTOR(roots)[2]=6;
+  igraph_bfs(&graph, /*root=*/ -1, &roots, /*neimode=*/ IGRAPH_OUT, 
+	     /*unreachable=*/ 0, &restricted,
+	     0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+  printf("\n");    
+
+  igraph_vector_destroy(&roots);
+  igraph_vector_destroy(&restricted);
+  igraph_destroy(&graph);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_bfs2.out b/examples/simple/igraph_bfs2.out
new file mode 100644
index 0000000..cec46de
--- /dev/null
+++ b/examples/simple/igraph_bfs2.out
@@ -0,0 +1,12 @@
+0 1 9 2 8 3 7 4 6 5 10 11 19 12 18 13 17 14 16 15
+0 1 3 5 7 9 8 6 4 2 10 11 13 15 17 19 18 16 14 12
+-1 0 1 2 3 4 7 8 9 0 -1 10 11 12 13 14 17 18 19 10
+-1 0 9 8 7 6 4 3 2 1 -1 10 19 18 17 16 14 13 12 11
+1 9 8 7 6 -1 5 4 3 2 11 19 18 17 16 -1 15 14 13 12
+0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 3 2 1
+ 0 1 9 2 8 3 7 4 6 5 10 11 19 12 18 13 17 14 16 15
+ 2 1 3 0 4 9 5 8 6 7 10 11 19 12 18 13 17 14 16 15
+ 5 6 7 8 9 10 11 19 12 18 13 17 14 16 15
+ 5 6 7 8 9 10 11 19 12 18 13 17 14 16 15
+
+ 6 5 7 8 9
diff --git a/examples/simple/igraph_biconnected_components.c b/examples/simple/igraph_biconnected_components.c
new file mode 100644
index 0000000..b7e11c9
--- /dev/null
+++ b/examples/simple/igraph_biconnected_components.c
@@ -0,0 +1,79 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdlib.h>
+
+void sort_and_print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  igraph_vector_sort(v);
+  for (i=0; i<n; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+void warning_handler_ignore(const char* reason,const char* file,int line,int e) {
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_ptr_t result;
+  igraph_integer_t no;
+  long int i;
+ 
+  igraph_set_warning_handler(warning_handler_ignore);
+
+  igraph_vector_ptr_init(&result, 0);
+  igraph_small(&g, 7, 0, 0, 1, 1, 2, 2, 3, 3, 0, 2, 4, 4, 5, 2, 5, -1);
+  
+  igraph_biconnected_components(&g, &no, 0, 0, &result, 0);
+  if (no != 2 || no != igraph_vector_ptr_size(&result)) return 1;
+  for (i = 0; i < no; i++) {
+    sort_and_print_vector((igraph_vector_t*)VECTOR(result)[i]);
+    igraph_vector_destroy((igraph_vector_t*)VECTOR(result)[i]);
+    free((igraph_vector_t*)VECTOR(result)[i]);
+  }
+
+  igraph_biconnected_components(&g, &no, 0, &result, 0, 0);
+  if (no != 2 || no != igraph_vector_ptr_size(&result)) return 2;
+  for (i = 0; i < no; i++) {
+    sort_and_print_vector((igraph_vector_t*)VECTOR(result)[i]);
+    igraph_vector_destroy((igraph_vector_t*)VECTOR(result)[i]);
+    free((igraph_vector_t*)VECTOR(result)[i]);
+  }
+
+  igraph_biconnected_components(&g, &no, &result, 0, 0, 0);
+  if (no != 2 || no != igraph_vector_ptr_size(&result)) return 3;
+  for (i = 0; i < no; i++) {
+    sort_and_print_vector((igraph_vector_t*)VECTOR(result)[i]);
+    igraph_vector_destroy((igraph_vector_t*)VECTOR(result)[i]);
+    free((igraph_vector_t*)VECTOR(result)[i]);
+  }
+
+  igraph_vector_ptr_destroy(&result);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_biconnected_components.out b/examples/simple/igraph_biconnected_components.out
new file mode 100644
index 0000000..1257c65
--- /dev/null
+++ b/examples/simple/igraph_biconnected_components.out
@@ -0,0 +1,6 @@
+ 2 4 5
+ 0 1 2 3
+ 4 5 6
+ 0 1 2 3
+ 4 5
+ 0 1 2
diff --git a/examples/simple/igraph_bipartite_create.c b/examples/simple/igraph_bipartite_create.c
new file mode 100644
index 0000000..2625063
--- /dev/null
+++ b/examples/simple/igraph_bipartite_create.c
@@ -0,0 +1,64 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+
+int main() {
+  
+  igraph_real_t edges2[] = {0,1, 1,2, 3,4, 5,6, 6,5, 1,4, 1,6, 0,3 };
+  igraph_real_t edges3[] = {0,1, 1,2, 3,4, 5,6, 6,5, 2,4, 1,6, 0,3 };
+  igraph_t g;
+  igraph_vector_bool_t types;
+  igraph_vector_t edges;
+  long int i;
+  int ret;
+
+  igraph_vector_view(&edges, edges2, sizeof(edges2)/sizeof(igraph_real_t));
+  igraph_vector_bool_init(&types, igraph_vector_max(&edges)+1);
+  for (i=0; i<igraph_vector_bool_size(&types); i++) {
+    VECTOR(types)[i] = i % 2;
+  }
+  igraph_create_bipartite(&g, &types, &edges, /*directed=*/ 1);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_vector_bool_destroy(&types);
+  igraph_destroy(&g);
+
+  /* Error handling */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  
+  igraph_vector_view(&edges, edges3, sizeof(edges3)/sizeof(igraph_real_t));
+  igraph_vector_bool_init(&types, igraph_vector_max(&edges)+1);
+  for (i=0; i<igraph_vector_bool_size(&types); i++) {
+    VECTOR(types)[i] = i % 2;
+  }
+  ret = igraph_create_bipartite(&g, &types, &edges, /*directed=*/ 1);
+  if (ret != IGRAPH_EINVAL) { return 1; }
+  igraph_vector_bool_destroy(&types);
+  igraph_destroy(&g);
+
+  return 0;
+}
+  
+  
+
+    
diff --git a/examples/simple/igraph_bipartite_create.out b/examples/simple/igraph_bipartite_create.out
new file mode 100644
index 0000000..ef269aa
--- /dev/null
+++ b/examples/simple/igraph_bipartite_create.out
@@ -0,0 +1,8 @@
+0 1
+0 3
+1 2
+1 4
+1 6
+3 4
+5 6
+6 5
diff --git a/examples/simple/igraph_bipartite_projection.c b/examples/simple/igraph_bipartite_projection.c
new file mode 100644
index 0000000..faadd71
--- /dev/null
+++ b/examples/simple/igraph_bipartite_projection.c
@@ -0,0 +1,173 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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.h>
+#include <stdlib.h>
+
+int check_projection(const igraph_t *graph,
+		     const igraph_vector_bool_t *types,
+		     const igraph_t *proj1,
+		     const igraph_t *proj2) {
+  igraph_integer_t vcount1, ecount1, vcount2, ecount2;
+  igraph_bipartite_projection_size(graph, types, &vcount1, &ecount1,
+				   &vcount2, &ecount2);
+  if (proj1 && igraph_vcount(proj1) != vcount1) {
+    exit(10);
+  }
+  if (proj1 && igraph_ecount(proj1) != ecount1) {
+    exit(11);
+  }
+  if (proj2 && igraph_vcount(proj2) != vcount2) {
+    exit(12);
+  }
+  if (proj2 && igraph_ecount(proj2) != ecount2) {
+    exit(13);
+  }
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g, p1, p2, full, ring;
+  igraph_vector_bool_t types;
+  igraph_bool_t iso;
+  long int i, m2=0, w, f, t;
+  igraph_vector_t mult1, mult2;
+  
+  /*******************************************************/
+  /* Full bipartite graph -> full graphs                 */
+  /*******************************************************/
+
+  igraph_vector_bool_init(&types, 0);
+  igraph_full_bipartite(&g, &types, 5, 3, /*directed=*/ 0, 
+			/*mode=*/ IGRAPH_ALL);
+
+  /* Get both projections */
+  igraph_bipartite_projection(&g, &types, &p1, &p2, 0, 0, /*probe1=*/ -1);
+  check_projection(&g, &types, &p1, &p2);
+
+  /* Check first projection */
+  igraph_full(&full, igraph_vcount(&p1), /*directed=*/0, /*loops=*/0);
+  igraph_isomorphic_bliss(&p1, &full, &iso, 0, 0, 
+			  IGRAPH_BLISS_FM, IGRAPH_BLISS_FM, 0, 0);
+  if (!iso) { return 1; }
+  igraph_destroy(&full);
+  
+  /* Check second projection */
+  igraph_full(&full, igraph_vcount(&p2), /*directed=*/0, /*loops=*/0);
+  igraph_isomorphic_bliss(&p2, &full, &iso, 0, 0, 
+			  IGRAPH_BLISS_FM, IGRAPH_BLISS_FM, 0, 0);
+  if (!iso) { return 2; }
+  igraph_destroy(&full);
+  
+  igraph_destroy(&p1);
+  igraph_destroy(&p2);
+  igraph_destroy(&g);
+  igraph_vector_bool_destroy(&types);
+
+  /*******************************************************/
+  /* More sophisticated test                             */
+  /*******************************************************/
+  
+  igraph_ring(&g, 100, /*directed=*/ 1, /*mutual=*/ 1, 
+	      /*circular=*/ 1);
+  igraph_vector_bool_init(&types, igraph_vcount(&g));
+  for (i=0; i<igraph_vector_bool_size(&types); i++) {
+    VECTOR(types)[i] = i%2 ? 0 : 1;
+  }
+  
+  /* Get both projections */
+  igraph_bipartite_projection(&g, &types, &p1, &p2, 0, 0, /*probe1=*/ -1);
+  check_projection(&g, &types, &p1, &p2);
+  
+  /* Check first projection */
+  igraph_ring(&ring, igraph_vcount(&g)/2, /*directed=*/ 0, 
+	      /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_isomorphic_bliss(&p1, &ring, &iso, 0, 0, 
+			  IGRAPH_BLISS_FM, IGRAPH_BLISS_FM, 0, 0);
+  if (!iso) { return 1; }
+  
+  /* Check second projection */
+  igraph_isomorphic_bliss(&p2, &ring, &iso, 0, 0, 
+			  IGRAPH_BLISS_FM, IGRAPH_BLISS_FM, 0, 0);
+  if (!iso) { return 2; }
+  igraph_destroy(&ring);
+  
+  igraph_destroy(&p1);
+  igraph_destroy(&p2);
+  igraph_destroy(&g);
+  igraph_vector_bool_destroy(&types);
+
+  /*******************************************************/
+  /* Multiplicity test                                   */
+  /*******************************************************/
+  
+  igraph_small(&g, 10, IGRAPH_UNDIRECTED, 
+	       0,8, 1,8, 2,8, 3,8, 4,8, 4,9, 5,9, 6,9, 7,9, 0,9, 
+	       -1);
+  igraph_vector_bool_init(&types, igraph_vcount(&g));
+  igraph_vector_bool_fill(&types, 1);
+  VECTOR(types)[8] = VECTOR(types)[9] = 0;
+  
+  igraph_vector_init(&mult1, 0);
+  igraph_vector_init(&mult2, 0);
+  igraph_bipartite_projection(&g, &types, &p1, &p2, &mult1, &mult2, 
+			      /*probe=*/ -1);
+  check_projection(&g, &types, &p1, &p2);
+  
+  if (igraph_vector_size(&mult1) != igraph_ecount(&p1)) {
+    return 21;
+  }
+  if (igraph_vector_size(&mult2) != igraph_ecount(&p2)) {
+    return 22;
+  }
+  if (VECTOR(mult1)[0] != 2) { 
+    return 23;
+  }
+  for (i=0; i<igraph_vector_size(&mult2); i++) {
+    if (VECTOR(mult2)[i] != 1 && VECTOR(mult2)[i] != 2) {
+      return 24;
+    }
+    if (VECTOR(mult2)[i] == 2) {
+      m2++;
+      w=i;
+    }
+  }
+  if (m2 != 1) { 
+    return 25;
+  }
+  f=IGRAPH_FROM(&p2, w);
+  t=IGRAPH_TO(&p2, w);
+  if (fmin(f, t) != 0 || fmax(f, t) != 4) { 
+    return 26;
+  }
+   
+  igraph_vector_destroy(&mult1);
+  igraph_vector_destroy(&mult2);
+  igraph_destroy(&p1);
+  igraph_destroy(&p2);
+  igraph_destroy(&g);
+  igraph_vector_bool_destroy(&types);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_cliques.c b/examples/simple/igraph_cliques.c
new file mode 100644
index 0000000..04ccad1
--- /dev/null
+++ b/examples/simple/igraph_cliques.c
@@ -0,0 +1,85 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+void warning_handler_ignore(const char* reason,const char* file,int line,int e) {
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_ptr_t result;
+  igraph_es_t es;
+  igraph_integer_t omega;
+  long int i, j, n;
+  const int params[] = {4, -1, 2, 2, 0, 0, -1, -1};
+ 
+  igraph_set_warning_handler(warning_handler_ignore);
+
+  igraph_vector_ptr_init(&result, 0);
+  igraph_full(&g, 6, 0, 0);
+  igraph_es_pairs_small(&es, 0, 0, 1, 0, 2, 3, 5, -1);
+  igraph_delete_edges(&g, es);
+  igraph_es_destroy(&es);
+  
+  for (j=0; j<sizeof(params)/(2*sizeof(params[0])); j++) {
+    if (params[2*j+1] != 0) {
+      igraph_cliques(&g, &result, params[2*j], params[2*j+1]);  
+    } else {
+      igraph_largest_cliques(&g, &result);
+    }
+    n = igraph_vector_ptr_size(&result);
+    printf("%ld cliques found\n", (long)n);
+    for (i=0; i<n; i++) {
+      igraph_vector_t* v;
+      v=igraph_vector_ptr_e(&result,i);
+      print_vector((igraph_vector_t*)v);
+      igraph_vector_destroy(v);
+      free(v);
+    }
+  }
+   
+  igraph_clique_number(&g, &omega);
+  printf("omega=%ld\n", (long)omega);
+
+  igraph_destroy(&g);
+
+  igraph_tree(&g, 5, 2, IGRAPH_TREE_OUT);
+  igraph_cliques(&g, &result, 5, 5);
+  if (igraph_vector_ptr_size(&result) != 0) return 1;
+
+  igraph_destroy(&g);
+  igraph_vector_ptr_destroy(&result);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_cliques.out b/examples/simple/igraph_cliques.out
new file mode 100644
index 0000000..63eefa4
--- /dev/null
+++ b/examples/simple/igraph_cliques.out
@@ -0,0 +1,50 @@
+2 cliques found
+ 1 2 3 4
+ 1 2 4 5
+12 cliques found
+ 0 3
+ 0 4
+ 0 5
+ 1 2
+ 1 3
+ 1 4
+ 1 5
+ 2 3
+ 2 4
+ 2 5
+ 3 4
+ 4 5
+2 cliques found
+ 4 1 2 5
+ 4 1 2 3
+29 cliques found
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 0 3
+ 0 4
+ 0 5
+ 1 2
+ 1 3
+ 1 4
+ 1 5
+ 2 3
+ 2 4
+ 2 5
+ 3 4
+ 4 5
+ 0 3 4
+ 0 4 5
+ 1 2 3
+ 1 2 4
+ 1 2 5
+ 1 3 4
+ 1 4 5
+ 2 3 4
+ 2 4 5
+ 1 2 3 4
+ 1 2 4 5
+omega=4
diff --git a/examples/simple/igraph_cocitation.c b/examples/simple/igraph_cocitation.c
new file mode 100644
index 0000000..1165906
--- /dev/null
+++ b/examples/simple/igraph_cocitation.c
@@ -0,0 +1,56 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void print_matrix(igraph_matrix_t *m, FILE *f) {
+  long int i, j;
+  for (i=0; i<igraph_matrix_nrow(m); i++) {
+    for (j=0; j<igraph_matrix_ncol(m); j++) {
+      fprintf(f, " %li", (long int) MATRIX(*m, i, j));
+    }
+    fprintf(f, "\n");
+  }
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_matrix_t m;
+  
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 
+	       0,1, 2,1, 2,0, 3,0, 
+	       -1);
+  
+  igraph_matrix_init(&m, 0, 0);
+  igraph_bibcoupling(&g, &m, igraph_vss_all());
+  print_matrix(&m, stdout);
+  
+  igraph_cocitation(&g, &m, igraph_vss_all());
+  print_matrix(&m, stdout);
+  
+  igraph_matrix_destroy(&m);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_cocitation.out b/examples/simple/igraph_cocitation.out
new file mode 100644
index 0000000..10020c4
--- /dev/null
+++ b/examples/simple/igraph_cocitation.out
@@ -0,0 +1,8 @@
+ 0 0 1 0
+ 0 0 0 0
+ 1 0 0 1
+ 0 0 1 0
+ 0 1 0 0
+ 1 0 0 0
+ 0 0 0 0
+ 0 0 0 0
diff --git a/examples/simple/igraph_community_edge_betweenness.c b/examples/simple/igraph_community_edge_betweenness.c
new file mode 100644
index 0000000..55e9335
--- /dev/null
+++ b/examples/simple/igraph_community_edge_betweenness.c
@@ -0,0 +1,166 @@
+/* -*- 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.h>
+
+int igraph_vector_between(const igraph_vector_t* v, const igraph_vector_t* lo,
+		const igraph_vector_t* hi) {
+	return igraph_vector_all_le(lo, v) && igraph_vector_all_ge(hi, v);
+}
+
+void test_unweighted() {
+  igraph_t g;
+  igraph_vector_t edges, eb;
+  long int i;
+  long int no_of_edges;
+
+  /* Zachary Karate club */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);  
+  
+  igraph_vector_init(&edges, 0);
+  igraph_vector_init(&eb, 0);
+  igraph_community_edge_betweenness(&g, &edges, &eb, 0 /*merges */,
+				    0 /*bridges */, /*modularity=*/ 0,
+				    /*membership=*/ 0,
+				    IGRAPH_UNDIRECTED,
+				    /*weights=*/ 0);
+  
+  no_of_edges=igraph_ecount(&g);
+  for (i=0; i<no_of_edges; i++) {
+    printf("%li ", (long int)VECTOR(edges)[i]);
+  }
+  printf("\n");
+  
+  for (i=0; i<no_of_edges; i++) {
+    printf("%.2f ", VECTOR(eb)[i]);
+  }
+  printf("\n");
+
+  /* Try it once again without storage space for edges */
+  igraph_community_edge_betweenness(&g, 0, &eb, 0 /*merges */,
+				    0 /*bridges */, /*modularity=*/ 0,
+				    /*membership=*/ 0,
+				    IGRAPH_UNDIRECTED,
+				    /*weights=*/ 0);
+  for (i=0; i<no_of_edges; i++) {
+    printf("%.2f ", VECTOR(eb)[i]);
+  }
+  printf("\n");
+
+  igraph_vector_destroy(&eb);
+  igraph_vector_destroy(&edges);
+  igraph_destroy(&g);
+}
+
+#define EPS 1e-4
+
+void test_weighted() {
+  igraph_t g;
+  igraph_vector_t edges, eb, weights;
+  igraph_real_t weights_array[] = { 4, 1, 3, 2, 5, 8, 6, 7 };
+
+  igraph_real_t edges_array1[] = { 2, 3, 0, 1, 4, 7, 5, 6 };
+  igraph_real_t edges_array2[] = { 2, 3, 6, 5, 0, 1, 4, 7 };
+  igraph_real_t eb_array1_lo[] = { 4, 5, 3+1/3.0-EPS, 4, 2.5, 4, 1, 1 };
+  igraph_real_t eb_array1_hi[] = { 4, 5, 3+1/3.0+EPS, 4, 2.5, 4, 1, 1 };
+  igraph_real_t eb_array2_lo[] = { 4, 5, 3+1/3.0-EPS, 6, 1.5, 2, 1, 1 };
+  igraph_real_t eb_array2_hi[] = { 4, 5, 3+1/3.0+EPS, 6, 1.5, 2, 1, 1 };
+
+  igraph_vector_t edges_sol1, edges_sol2, eb_sol1_lo, eb_sol1_hi, eb_sol2_lo, eb_sol2_hi;
+
+  igraph_vector_view(&edges_sol1, edges_array1, 
+		     sizeof(edges_array1)/sizeof(double));
+  igraph_vector_view(&edges_sol2, edges_array2, 
+		     sizeof(edges_array2)/sizeof(double));
+  igraph_vector_view(&eb_sol1_lo, eb_array1_lo, sizeof(eb_array1_lo)/sizeof(double));
+  igraph_vector_view(&eb_sol2_lo, eb_array2_lo, sizeof(eb_array2_lo)/sizeof(double));
+  igraph_vector_view(&eb_sol1_hi, eb_array1_hi, sizeof(eb_array1_hi)/sizeof(double));
+  igraph_vector_view(&eb_sol2_hi, eb_array2_hi, sizeof(eb_array2_hi)/sizeof(double));
+
+  /* Small graph as follows: A--B--C--A, A--D--E--A, B--D, C--E */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+      0, 1, 0, 2, 0, 3, 0, 4, 1, 2, 1, 3, 2, 4, 3, 4, -1);
+  igraph_vector_view(&weights, weights_array, igraph_ecount(&g));
+
+  igraph_vector_init(&edges, 0);
+  igraph_vector_init(&eb, 0);
+  igraph_community_edge_betweenness(&g, &edges, &eb, 0 /*merges */,
+				    0 /*bridges */, /*modularity=*/ 0,
+				    /*membership=*/ 0,
+				    IGRAPH_UNDIRECTED,
+				    &weights);
+  
+  if (!igraph_vector_all_e(&edges_sol1, &edges) && 
+      !igraph_vector_all_e(&edges_sol2, &edges)) {
+    printf("Error, edges vector was: \n");
+	igraph_vector_print(&edges);
+    exit(2);
+  }
+  if (!igraph_vector_between(&eb, &eb_sol1_lo, &eb_sol1_hi) &&
+      !igraph_vector_between(&eb, &eb_sol2_lo, &eb_sol2_hi)) {
+    printf("Error, eb vector was: \n");
+	igraph_vector_print(&eb);
+    exit(2);
+  }
+
+  /* Try it once again without storage space for edges */
+  igraph_community_edge_betweenness(&g, 0, &eb, 0 /*merges */,
+				    0 /*bridges */, /*modularity=*/ 0,
+				    /*membership=*/ 0,
+				    IGRAPH_UNDIRECTED,
+				    &weights);
+
+  if (!igraph_vector_between(&eb, &eb_sol1_lo, &eb_sol1_hi) &&
+      !igraph_vector_between(&eb, &eb_sol2_lo, &eb_sol2_hi)) {
+    printf("Error, eb vector was: \n");
+	igraph_vector_print(&eb);
+    exit(2);
+  }
+
+  igraph_vector_destroy(&eb);
+  igraph_vector_destroy(&edges);
+  igraph_destroy(&g);
+}
+
+int main() {
+  test_unweighted();
+  test_weighted();
+  return 0;
+}
diff --git a/examples/simple/igraph_community_edge_betweenness.out b/examples/simple/igraph_community_edge_betweenness.out
new file mode 100644
index 0000000..c2e1c41
--- /dev/null
+++ b/examples/simple/igraph_community_edge_betweenness.out
@@ -0,0 +1,3 @@
+15 1 7 45 52 31 23 16 24 25 28 44 68 27 4 5 3 8 76 75 70 57 58 26 9 67 66 10 33 46 47 48 49 63 69 50 51 12 20 53 54 13 21 35 38 55 56 14 22 29 42 43 41 73 74 6 18 32 0 2 11 17 19 30 34 36 37 39 40 59 60 61 62 64 65 71 72 77 
+71.39 66.90 77.32 82.00 123.23 100.21 143.63 109.25 107.67 142.75 285.00 16.83 18.18 18.00 15.33 25.33 25.00 50.00 14.50 22.37 25.62 29.65 40.67 72.00 9.00 9.00 11.00 5.50 8.00 5.00 10.00 4.50 9.00 4.50 9.00 4.00 8.00 3.50 7.00 3.50 7.00 3.00 6.00 3.00 6.00 3.00 6.00 2.50 5.00 2.00 2.00 3.50 5.00 2.00 4.00 1.33 2.00 4.00 1.00 1.50 3.00 1.00 2.00 1.00 1.00 1.00 1.00 2.00 1.00 1.00 1.50 3.00 1.00 2.00 1.00 1.00 2.00 1.00 
+71.39 66.90 77.32 82.00 123.23 100.21 143.63 109.25 107.67 142.75 285.00 16.83 18.18 18.00 15.33 25.33 25.00 50.00 14.50 22.37 25.62 29.65 40.67 72.00 9.00 9.00 11.00 5.50 8.00 5.00 10.00 4.50 9.00 4.50 9.00 4.00 8.00 3.50 7.00 3.50 7.00 3.00 6.00 3.00 6.00 3.00 6.00 2.50 5.00 2.00 2.00 3.50 5.00 2.00 4.00 1.33 2.00 4.00 1.00 1.50 3.00 1.00 2.00 1.00 1.00 1.00 1.00 2.00 1.00 1.00 1.50 3.00 1.00 2.00 1.00 1.00 2.00 1.00 
diff --git a/examples/simple/igraph_community_fastgreedy.c b/examples/simple/igraph_community_fastgreedy.c
new file mode 100644
index 0000000..70a0636
--- /dev/null
+++ b/examples/simple/igraph_community_fastgreedy.c
@@ -0,0 +1,147 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void show_results(igraph_t *g, igraph_vector_t *mod, igraph_matrix_t *merges, FILE* f) {
+  long int i;
+  igraph_vector_t membership;
+
+  igraph_vector_init(&membership, 0);
+
+  i=igraph_vector_which_max(mod);
+  fprintf(f, "Modularity:  %f\n", VECTOR(*mod)[i]);
+  igraph_community_to_membership(merges, igraph_vcount(g), i, &membership, 0);
+  printf("Membership: ");
+  for (i=0; i<igraph_vector_size(&membership); i++) {
+    printf("%li ", (long int)VECTOR(membership)[i]);
+  }
+  printf("\n");
+
+  igraph_vector_destroy(&membership);
+}
+
+int main() {
+  igraph_t g;
+  igraph_vector_t modularity, weights;
+  igraph_matrix_t merges;
+
+  igraph_vector_init(&modularity,0);
+  igraph_matrix_init(&merges,0,0);
+  igraph_vector_init(&weights,0);
+
+  /* Simple unweighted graph */
+  igraph_small(&g, 10, IGRAPH_UNDIRECTED, 
+	       0,1,0,2,0,3,0,4, 1,2,1,3,1,4, 2,3,2,4, 3,4,
+	       5,6,5,7,5,8,5,9, 6,7,6,8,6,9, 7,8,7,9, 8,9,
+           0,5, -1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout); 
+
+  /* Same simple graph, with uniform edge weights */
+  igraph_vector_resize(&weights, igraph_ecount(&g));
+  igraph_vector_fill(&weights, 2);
+  igraph_community_fastgreedy(&g, &weights, &merges, &modularity, 
+			      /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout); 
+  igraph_destroy(&g);
+
+  /* Simple nonuniform weighted graph, with and without weights */
+  igraph_small(&g, 6, IGRAPH_UNDIRECTED, 
+	       0,1,1,2,2,3,2,4,2,5,3,4,3,5,4,5, -1);
+  igraph_vector_resize(&weights, 8);
+  igraph_vector_fill(&weights, 1);
+  VECTOR(weights)[0] = 10; VECTOR(weights)[1] = 10;
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout); 
+  igraph_community_fastgreedy(&g, &weights, &merges, &modularity, 
+			      /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout); 
+  igraph_destroy(&g);
+
+  /* Zachary Karate club */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, 
+			      /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout); 
+  igraph_destroy(&g);
+   
+  /* Simple disconnected graph with isolates */
+  igraph_small(&g, 9, IGRAPH_UNDIRECTED,
+	       0,  1,  0,  2,  0,  3,  1,  2,  1,  3,  2,  3,
+	       4,  5,  4,  6,  4,  7,  5,  6,  5,  7,  6,  7,
+	       -1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout); 
+  igraph_destroy(&g);
+
+  /* Disjoint union of two rings */
+  igraph_small(&g, 20, IGRAPH_UNDIRECTED,
+           0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,0,9,
+	   10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,10,19,-1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout);
+  igraph_destroy(&g);
+
+  /* Completely empty graph */
+  igraph_small(&g, 10, IGRAPH_UNDIRECTED, -1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout);
+  igraph_destroy(&g);
+
+  /* Ring graph with loop edges */
+  igraph_small(&g, 6, IGRAPH_UNDIRECTED,
+          0,1,1,2,2,3,3,4,4,5,5,0,0,0,2,2,-1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout);
+  igraph_destroy(&g);
+
+  /* Regression test -- graph with two vertices and two edges */
+  igraph_small(&g, 2, IGRAPH_UNDIRECTED, 0,0,1,1,-1);
+  igraph_community_fastgreedy(&g, 0, &merges, &modularity, /*membership=*/ 0);
+  show_results(&g, &modularity, &merges, stdout);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&modularity);
+  igraph_vector_destroy(&weights);
+  igraph_matrix_destroy(&merges);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_community_fastgreedy.out b/examples/simple/igraph_community_fastgreedy.out
new file mode 100644
index 0000000..0564dc2
--- /dev/null
+++ b/examples/simple/igraph_community_fastgreedy.out
@@ -0,0 +1,20 @@
+Modularity:  0.452381
+Membership: 1 1 1 1 1 0 0 0 0 0 
+Modularity:  0.452381
+Membership: 1 1 1 1 1 0 0 0 0 0 
+Modularity:  0.179688
+Membership: 1 1 0 0 0 0 
+Modularity:  0.170858
+Membership: 1 1 1 0 0 0 
+Modularity:  0.380671
+Membership: 0 2 2 2 0 0 0 2 1 2 0 0 2 2 1 1 0 2 1 0 1 2 1 1 1 1 1 1 1 1 1 1 1 1 
+Modularity:  0.500000
+Membership: 1 1 1 1 0 0 0 0 2 
+Modularity:  0.540000
+Membership: 1 1 1 1 3 3 3 3 1 1 0 0 0 0 0 0 2 2 2 2 
+Modularity:  0.000000
+Membership: 0 1 2 3 4 5 6 7 8 9 
+Modularity:  0.281250
+Membership: 0 1 1 2 2 0 
+Modularity:  0.500000
+Membership: 0 1 
diff --git a/examples/simple/igraph_community_infomap.c b/examples/simple/igraph_community_infomap.c
new file mode 100644
index 0000000..45071f7
--- /dev/null
+++ b/examples/simple/igraph_community_infomap.c
@@ -0,0 +1,258 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include <igraph.h>
+
+
+void gsumary(const igraph_t * g){
+  printf("|V|=%d |E|=%d directed=%d\n", (int)igraph_vcount(g), (int)igraph_ecount(g), (int)igraph_is_directed(g));
+}
+
+void show_results(igraph_vector_t * membership, igraph_real_t codelength) {
+  printf("Codelength: %0.5f (in %d modules)\n", codelength, (int)igraph_vector_max(membership) + 1 );
+  printf("Membership: ");
+  int i;
+  for (i=0; i < igraph_vector_size(membership); i++) {
+    printf("%li ", (long)VECTOR(*membership)[i] );
+  }
+  printf("\n");
+}
+
+void show_results_lite(igraph_vector_t * membership, igraph_real_t codelength) {
+  printf("Codelength: %0.5f (in %d modules)\n", codelength, (int)igraph_vector_max(membership) + 1 );
+  printf("Membership (1/100 of vertices): ");
+  int i;
+  for (i=0; i < igraph_vector_size(membership); i+=100) {
+    printf("%li ", (long)VECTOR(*membership)[i] );
+  }
+  printf("\n");
+}
+
+void infomap_weighted_test(const igraph_t * g, const igraph_vector_t *weights){
+  igraph_vector_t membership;
+  igraph_real_t codelength = 1000;
+  igraph_vector_init(&membership, 0);
+
+  igraph_community_infomap(/*in */ g, /*e_weight=*/ weights, NULL, /*nb_trials=*/5,
+                           /*out*/ &membership, &codelength);
+  if(igraph_vcount(g) > 500)
+      show_results_lite(&membership, codelength);
+  else
+      show_results(&membership, codelength);
+
+  igraph_vector_destroy(&membership);
+}
+
+
+void infomap_test(const igraph_t * g){
+  infomap_weighted_test(g, 0);
+}
+
+
+int main() {
+  igraph_t g;
+  igraph_vector_t weights;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  /* Two triangles connected by one edge */
+  printf("# Two triangles connected by one edge\n");
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
+                      0, 1, 1, 2, 2, 0,
+                      3, 4, 4, 5, 5, 3,
+                      0, 5,
+                      -1);
+  infomap_test(&g);
+  igraph_destroy(&g);
+  //return 0;
+
+  /* Two 4-cliques with one commun vertex (vertex 3) */
+  printf("# Two 4-cliques (0123 and 4567) connected by two edges (0-4 and 1-5)\n");
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
+                      0, 1,  0, 2,  0, 3,  1, 2,  1, 3,  2, 3, // 4-clique 0,1,2,3
+                      7, 4,  7, 5,  7, 6,  4, 5,  4, 6,  5, 6, // 4-clique 4,5,6,7
+                      0, 4,  1, 5, //8, 0, 8, 4,
+                      -1);
+  infomap_test(&g);
+
+  printf("# Two 4-cliques (0123 and 4567) connected by two edges (0-4 and 1-5)\n");
+  igraph_add_edge(&g, 0, 4);
+  igraph_add_edge(&g, 1, 5);
+  infomap_test(&g);
+  igraph_destroy(&g);
+  
+  /* Zachary Karate club -- this is just a quick smoke test */
+  printf("# Zachary Karate club\n");
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
+               0,  1,  0,  2,  0,  3,  0,  4,  0,  5, //0,  5, 0,  5, 0,  5,
+               0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+               0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+               0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+               1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+               2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+               2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+               4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+               6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+               13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+               18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+               22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+               23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+               25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+               28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+               31, 32, 31, 33, 32, 33,
+               -1);
+  infomap_test(&g);
+  igraph_destroy(&g);
+  
+  /* Flow.net that come in infomap_dir.tgz  */
+  printf("# Flow (from infomap_dir.tgz)\n");
+  igraph_small(&g, 0, IGRAPH_DIRECTED,
+              0, 1,     1, 2,    2, 3,    3, 0,    1, 4,
+              4, 5,     5, 6,    6, 7,    7, 4,    5, 8,
+              8, 9,     9, 10,  10, 11,  11, 8,    9, 12,
+              12, 13,  13, 14,  14, 15,  15, 12,  13, 0,
+               -1);
+  infomap_test(&g);
+  igraph_destroy(&g);
+
+  /* MultiphysChemBioEco40W_weighted_dir.net */
+  printf("# MultiphysChemBioEco40W_weighted_dir.net (from infomap_dir.tgz)\n");
+  igraph_small(&g, 0, IGRAPH_DIRECTED,
+          1, 0,  2, 0,  3, 0,  4, 0,  5, 0,  6, 0,  7, 0,
+          8, 0,  9, 0,  16, 0,  18, 0,  0, 1,  2, 1,  3, 1,
+          5, 1,  6, 1,  7, 1,  9, 1,  10, 1,  16, 1,  18, 1,
+          0, 2,  3, 2,  4, 2,  5, 2,  6, 2,  7, 2,  0, 3,
+          1, 3,  2, 3,  4, 3,  5, 3,  6, 3,  7, 3,  8, 3,
+          9, 3,  10, 3,  11, 3,  13, 3,  14, 3,  16, 3,  17, 3,
+          18, 3,  19, 3,  26, 3,  30, 3,  1, 4,  3, 4,  5, 4,
+          6, 4,  13, 4,  18, 4,  0, 5,  1, 5,  2, 5,  3, 5,
+          6, 5,  7, 5,  9, 5,  1, 6,  3, 6,  7, 6,  9, 6,
+          16, 6,  0, 7,  1, 7,  2, 7,  3, 7,  5, 7,  6, 7,
+          9, 7,  3, 8,  5, 8,  3, 9,  7, 9,  12, 10,  13, 10,
+          14, 10,  15, 10,  16, 10,  17, 10,  18, 10,  19, 10,
+          21, 10,  3, 11,  18, 11,  10, 12,  14, 12,  16, 12,
+          17, 12,  18, 12,  3, 13,  10, 13,  14, 13,  16, 13,
+          10, 14,  12, 14,  13, 14,  15, 14,  16, 14,  17, 14,
+          18, 14,  10, 15,  14, 15,  18, 15,  0, 16,  2, 16,
+          3, 16,  6, 16,  10, 16,  12, 16,  13, 16,  14, 16,
+          17, 16,  18, 16,  10, 17,  12, 17,  14, 17,  18, 17,
+          3, 18,  10, 18,  12, 18,  14, 18,  15, 18,  16, 18,
+          17, 18,  19, 18,  21, 18,  11, 19,  16, 19,  17, 19,
+          16, 20,  18, 20,  21, 20,  22, 20,  23, 20,  24, 20,
+          25, 20,  26, 20,  27, 20,  28, 20,  29, 20,  3, 21,
+          14, 21,  18, 21,  20, 21,  22, 21,  23, 21,  24, 21,
+          25, 21,  26, 21,  27, 21,  28, 21,  29, 21,  35, 21,
+          36, 21,  38, 21,  18, 22,  20, 22,  21, 22,  23, 22,
+          24, 22,  25, 22,  26, 22,  27, 22,  29, 22,  3, 23,
+          20, 23,  21, 23,  22, 23,  24, 23,  25, 23,  26, 23,
+          27, 23,  28, 23,  29, 23,  35, 23,  38, 23,  39, 23,
+          20, 24,  21, 24,  23, 24,  25, 24,  26, 24,  27, 24,
+          28, 24,  29, 24,  9, 25,  20, 25,  21, 25,  22, 25,
+          23, 25,  24, 25,  26, 25,  27, 25,  28, 25,  29, 25,
+          18, 26,  20, 26,  21, 26,  22, 26,  23, 26,  25, 26,
+          27, 26,  28, 26,  29, 26,  30, 26,  32, 26,  35, 26,
+          36, 26,  38, 26,  39, 26,  3, 27,  14, 27,  20, 27,
+          21, 27,  22, 27,  23, 27,  24, 27,  25, 27,  26, 27,
+          28, 27,  29, 27,  38, 27,  3, 28,  18, 28,  20, 28,
+          21, 28,  23, 28,  24, 28,  25, 28,  26, 28,  27, 28,
+          29, 28,  35, 28,  14, 29,  16, 29,  18, 29,  20, 29,
+          21, 29,  22, 29,  23, 29,  24, 29,  25, 29,  26, 29,
+          27, 29,  28, 29,  31, 30,  32, 30,  33, 30,  34, 30,
+          35, 30,  36, 30,  38, 30,  39, 30,  30, 31,  32, 31,
+          34, 31,  36, 31,  30, 32,  34, 32,  35, 32,  36, 32,
+          30, 33,  32, 33,  34, 33,  35, 33,  36, 33,  38, 33,
+          30, 34,  31, 34,  32, 34,  33, 34,  35, 34,  36, 34,
+          38, 34,  39, 34,  26, 35,  30, 35,  32, 35,  33, 35,
+          34, 35,  36, 35,  38, 35,  39, 35,  30, 36,  34, 36,
+          35, 36,  38, 36,  39, 36,  34, 37,  26, 38,  30, 38,
+          32, 38,  33, 38,  34, 38,  35, 38,  36, 38,  39, 38,
+          26, 39,  30, 39,  33, 39,  34, 39,  35, 39,  36, 39,
+          38, 39,
+          -1);
+  igraph_vector_init_real(&weights, 306,
+          5.0,  3.0,  130.0,  4.0,  15.0,  9.0,
+          7.0,  1.0,  1.0,  3.0,  1.0,  1.0,
+          1.0,  34.0,  38.0,  2.0,  23.0,  1.0,
+          1.0,  3.0,  2.0,  2.0,  16.0,  1.0,
+          3.0,  1.0,  3.0,  63.0,  92.0,  72.0,
+          25.0,  447.0,  121.0,  65.0,  4.0,  16.0,
+          35.0,  1.0,  19.0,  1.0,  78.0,  1.0,
+          45.0,  1.0,  3.0,  1.0,  1.0,  25.0,
+          1.0,  3.0,  1.0,  1.0,  3.0,  36.0,
+          19.0,  136.0,  41.0,  96.0,  1.0,  7.0,
+          26.0,  1.0,  2.0,  2.0,  3.0,  2.0,  2.0,
+          23.0,  52.0,  4.0,  1.0,  2.0,  1.0,  3.0,
+          1.0,  11.0,  2.0,  17.0,  1.0,  5.0,  18.0,
+          86.0,  5.0,  1.0,  1.0,  1.0,  6.0,  1.0,
+          2.0,  2.0,  20.0,  4.0,  5.0,  1.0,  5.0,
+          12.0,  4.0,  1.0,  1.0,  4.0,  9.0,  40.0,
+          2.0,  1.0,  4.0,  1.0,  1.0,  48.0,  2.0,
+          18.0,  1.0,  7.0,  2.0,  2.0,  53.0,  25.0,
+          9.0,  1.0,  23.0,  8.0,  62.0,  29.0,  35.0,
+          4.0,  34.0,  35.0,  3.0,  1.0,  24.0,  1.0,
+          6.0,  2.0,  2.0,  22.0,  7.0,  2.0,  5.0,
+          14.0,  3.0,  28.0,  14.0,  20.0,  3.0,  1.0,
+          5.0,  77.0,  20.0,  25.0,  35.0,  55.0,  35.0,
+          115.0,  68.0,  105.0,  2.0,  2.0,  2.0,  4.0,
+          2.0,  17.0,  12.0,  3.0,  3.0,  11.0,  10.0,
+          7.0,  2.0,  12.0,  31.0,  11.0,  5.0,  11.0,
+          65.0,  39.0,  17.0,  26.0,  3.0,  4.0,  2.0,
+          3.0,  6.0,  4.0,  8.0,  1.0,  7.0,  7.0,
+          6.0,  1.0,  39.0,  42.0,  9.0,  6.0,  9.0,
+          5.0,  45.0,  43.0,  26.0,  1.0,  2.0,  6.0,
+          2.0,  15.0,  3.0,  9.0,  2.0,  1.0,  1.0,
+          1.0,  4.0,  2.0,  9.0,  2.0,  1.0,  2.0,
+          28.0,  80.0,  10.0,  18.0,  13.0,  17.0,
+          28.0,  40.0,  76.0,  1.0,  2.0,  1.0,  11.0,
+          37.0,  5.0,  11.0,  14.0,  4.0,  14.0,  10.0,
+          1.0,  1.0,  1.0,  1.0,  41.0,  121.0,  6.0,
+          21.0,  12.0,  30.0,  6.0,  141.0,  43.0,  2.0,
+          12.0,  6.0,  35.0,  10.0,  7.0,  2.0,  12.0,
+          6.0,  2.0,  11.0,  1.0,  7.0,  6.0,  5.0,  3.0,
+          1.0,  2.0,  1.0,  1.0,  1.0,  1.0,  67.0,  9.0,
+          9.0,  11.0,  10.0,  21.0,  7.0,  12.0,  9.0,
+          16.0,  7.0,  4.0,  11.0,  17.0,  37.0,  32.0,
+          9.0,  2.0,  2.0,  5.0,  4.0,  2.0,  7.0,  3.0,
+          3.0,  5.0,  8.0,  14.0,  3.0,  38.0,  3.0,  9.0,
+          2.0,  8.0,  21.0,  18.0,  58.0);
+  infomap_weighted_test(&g, &weights);
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+  
+   /* Two triangles connected by one edge */
+  printf("# Wiktionary english verbs (synonymy 2008)\n");
+  FILE *wikt = fopen("wikti_en_V_syn.elist", "r");
+  igraph_read_graph_edgelist(&g, wikt, 0, 0);
+  fclose(wikt);
+  gsumary(&g);
+  infomap_test(&g);
+  igraph_destroy(&g);
+  
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
+
diff --git a/examples/simple/igraph_community_infomap.out b/examples/simple/igraph_community_infomap.out
new file mode 100644
index 0000000..7d4fc63
--- /dev/null
+++ b/examples/simple/igraph_community_infomap.out
@@ -0,0 +1,22 @@
+# Two triangles connected by one edge
+Codelength: 2.51787 (in 2 modules)
+Membership: 1 1 1 0 0 0 
+# Two 4-cliques (0123 and 4567) connected by two edges (0-4 and 1-5)
+Codelength: 2.94884 (in 2 modules)
+Membership: 1 1 1 1 0 0 0 0 
+# Two 4-cliques (0123 and 4567) connected by two edges (0-4 and 1-5)
+Codelength: 2.96655 (in 2 modules)
+Membership: 1 0 1 1 1 0 0 0 
+# Zachary Karate club
+Codelength: 4.60606 (in 3 modules)
+Membership: 1 1 1 1 2 2 2 1 0 1 2 1 1 1 0 0 2 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 
+# Flow (from infomap_dir.tgz)
+Codelength: 3.32773 (in 4 modules)
+Membership: 3 3 3 3 0 0 0 0 1 1 1 1 2 2 2 2 
+# MultiphysChemBioEco40W_weighted_dir.net (from infomap_dir.tgz)
+Codelength: 3.87095 (in 5 modules)
+Membership: 0 0 0 0 0 0 0 0 0 0 3 3 3 0 3 3 0 3 3 3 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 4 2 2 
+# Wiktionary english verbs (synonymy 2008)
+|V|=7339 |E|=8293 directed=0
+Codelength: 5.70863 (in 1444 modules)
+Membership (1/100 of vertices): 392 200 6 14 2 126 106 3 32 95 98 136 86 67 61 159 142 396 607 54 272 194 213 157 794 616 170 866 36 13 205 98 25 280 460 302 87 911 243 804 835 399 807 953 1333 101 73 75 666 0 568 798 175 219 133 49 1080 179 525 199 197 517 109 1194 1218 827 733 214 38 881 522 1356 143 14 
diff --git a/examples/simple/igraph_community_label_propagation.c b/examples/simple/igraph_community_label_propagation.c
new file mode 100644
index 0000000..e95542c
--- /dev/null
+++ b/examples/simple/igraph_community_label_propagation.c
@@ -0,0 +1,100 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t membership, weights, initial;
+  igraph_vector_bool_t fixed;
+  long int i;
+
+  /* Zachary Karate club -- this is just a quick smoke test */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+               0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+               0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+               0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+               0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+               1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+               2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+               2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+               4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+               6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+               13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+               18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+               22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+               23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+               25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+               28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+               31, 32, 31, 33, 32, 33,
+               -1);  
+  
+  igraph_vector_init(&membership, 0);
+  igraph_community_label_propagation(&g, &membership, 0, 0, 0, 
+				     /*modularity=*/ 0);
+  if (igraph_vector_max(&membership) > 3) {
+    printf("Resulting graph had more than four clusters:\n");
+    for (i=0; i<igraph_vcount(&g); i++)
+      printf("%li ", (long)VECTOR(membership)[i]);
+    printf("\n");
+    return 1;
+  }
+
+  igraph_destroy(&g);
+  
+  /* Simple star graph to test weights */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+               0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+               2,  3,  2,  4,  3,  4,  3,  5,  4,  5,  -1);
+  igraph_vector_init_int_end(&weights, -1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1);
+  igraph_vector_init_int_end(&initial, -1, 0, 0, 1, 1, 1, 1, -1);
+  igraph_vector_bool_init(&fixed, 6);
+  VECTOR(fixed)[3] = 1;
+  VECTOR(fixed)[4] = 1;
+  VECTOR(fixed)[5] = 1;
+  igraph_community_label_propagation(&g, &membership, &weights,
+				     &initial, &fixed, /*modularity=*/ 0);
+  for (i=0; i<igraph_vcount(&g); i++)
+    if (VECTOR(membership)[i] != (i < 2 ? 0 : 1)) return 3;
+  igraph_community_label_propagation(&g, &membership, 0,
+				     &initial, &fixed, /*modularity=*/ 0);
+  for (i=0; i<igraph_vcount(&g); i++)
+    if (VECTOR(membership)[i] != 0) return 4;
+
+  /* Check whether it works with no fixed vertices at all
+   * while an initial configuration is given -- see bug
+   * #570902 in Launchpad. This is a simple smoke test only. */
+  igraph_community_label_propagation(&g, &membership, &weights,
+				     &initial, 0, /*modularity=*/ 0);
+
+  igraph_vector_bool_destroy(&fixed);
+  igraph_vector_destroy(&weights);
+  igraph_vector_destroy(&initial);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&membership);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_community_label_propagation.out b/examples/simple/igraph_community_label_propagation.out
new file mode 100644
index 0000000..e69de29
diff --git a/examples/simple/igraph_community_leading_eigenvector.c b/examples/simple/igraph_community_leading_eigenvector.c
new file mode 100644
index 0000000..f3e6bb4
--- /dev/null
+++ b/examples/simple/igraph_community_leading_eigenvector.c
@@ -0,0 +1,112 @@
+/* -*- 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.h>
+
+int print_vector(const igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf("%.2g", (double)VECTOR(*v)[i]);
+    if (i!=n-1) { printf(" "); }
+  }
+  printf("\n");
+  return 0;
+}
+
+int print_matrix(const igraph_matrix_t *m) {
+  long int i, j, nrow=igraph_matrix_nrow(m), ncol=igraph_matrix_ncol(m);
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      printf("%.2g", (double)MATRIX(*m, i, j));
+      if (j!=ncol-1) { printf(" "); }
+    }
+    printf("\n");
+  }
+  return 0;
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_matrix_t merges;
+  igraph_vector_t membership;
+  igraph_vector_t x;
+  igraph_arpack_options_t options;
+  
+  /* Zachary Karate club */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);  
+ 
+  igraph_matrix_init(&merges, 0, 0);
+  igraph_vector_init(&membership, 0);
+  igraph_vector_init(&x, 0);
+  igraph_arpack_options_init(&options);
+
+  igraph_community_leading_eigenvector(&g, /*weights=*/ 0, &merges, 
+				       &membership, 1, 
+				       &options, /*modularity=*/ 0, 
+				       /*start=*/ 0, /*eigenvalues=*/ 0, 
+				       /*eigenvectors=*/ 0, /*history=*/ 0,
+				       /*callback=*/ 0, 
+				       /*callback_extra=*/ 0);
+
+  print_matrix(&merges);
+  print_vector(&membership);
+
+  printf("\n");
+
+  /* Make all the steps */
+  igraph_community_leading_eigenvector(&g, /*weights=*/ 0, &merges, 
+				       &membership, igraph_vcount(&g),
+				       &options, /*modularity=*/ 0, 
+				       /*start=*/ 0, /*eigenvalues=*/ 0,
+				       /*eigenvectors=*/ 0, /*history=*/ 0,
+				       /*callback=*/ 0, 
+				       /*callback_extra=*/ 0);
+
+  print_matrix(&merges);
+  print_vector(&membership);
+
+  igraph_vector_destroy(&x);
+  igraph_vector_destroy(&membership);
+  igraph_matrix_destroy(&merges);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_community_leading_eigenvector.out b/examples/simple/igraph_community_leading_eigenvector.out
new file mode 100644
index 0000000..195196c
--- /dev/null
+++ b/examples/simple/igraph_community_leading_eigenvector.out
@@ -0,0 +1,7 @@
+0 1
+0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+
+1 3
+0 2
+5 4
+0 2 2 2 0 0 0 2 1 1 0 0 2 2 1 1 0 2 1 2 1 2 1 3 3 3 1 3 3 1 1 3 1 1
diff --git a/examples/simple/igraph_community_leading_eigenvector2.c b/examples/simple/igraph_community_leading_eigenvector2.c
new file mode 100644
index 0000000..edd1aed
--- /dev/null
+++ b/examples/simple/igraph_community_leading_eigenvector2.c
@@ -0,0 +1,116 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+
+int print_vector(const igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf("%.2g", (double)VECTOR(*v)[i]);
+    if (i!=n-1) { printf(" "); }
+  }
+  printf("\n");
+  return 0;
+}
+
+int print_matrix(const igraph_matrix_t *m) {
+  long int i, j, nrow=igraph_matrix_nrow(m), ncol=igraph_matrix_ncol(m);
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      printf("%.2g", (double)MATRIX(*m, i, j));
+      if (j!=ncol-1) { printf(" "); }
+    }
+    printf("\n");
+  }
+  return 0;
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_matrix_t merges;
+  igraph_vector_t membership;
+  igraph_vector_t x;
+  igraph_arpack_options_t options;
+  igraph_vector_t weights;
+  
+  /* Zachary Karate club */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);  
+ 
+  igraph_matrix_init(&merges, 0, 0);
+  igraph_vector_init(&membership, 0);
+  igraph_vector_init(&x, 0);
+  igraph_arpack_options_init(&options);
+  igraph_vector_init(&weights, igraph_ecount(&g));
+  igraph_vector_fill(&weights, 1);
+
+  igraph_community_leading_eigenvector(&g, &weights, &merges, 
+				       &membership, 1, 
+				       &options, /*modularity=*/ 0, 
+				       /*start=*/ 0, /*eigenvalues=*/ 0, 
+				       /*eigenvectors=*/ 0, /*history=*/ 0,
+				       /*callback=*/ 0, 
+				       /*callback_extra=*/ 0);
+
+  print_matrix(&merges);
+  print_vector(&membership);
+
+  printf("\n");
+
+  /* Make all the steps */
+  igraph_community_leading_eigenvector(&g, &weights, &merges, 
+				       &membership, igraph_vcount(&g),
+				       &options, /*modularity=*/ 0, 
+				       /*start=*/ 0, /*eigenvalues=*/ 0,
+				       /*eigenvectors=*/ 0, /*history=*/ 0,
+				       /*callback=*/ 0, 
+				       /*callback_extra=*/ 0);
+
+  print_matrix(&merges);
+  print_vector(&membership);
+
+  igraph_vector_destroy(&weights);
+  igraph_vector_destroy(&x);
+  igraph_vector_destroy(&membership);
+  igraph_matrix_destroy(&merges);
+  igraph_destroy(&g);
+  
+  return 0;
+}  
diff --git a/examples/simple/igraph_community_leading_eigenvector2.out b/examples/simple/igraph_community_leading_eigenvector2.out
new file mode 100644
index 0000000..195196c
--- /dev/null
+++ b/examples/simple/igraph_community_leading_eigenvector2.out
@@ -0,0 +1,7 @@
+0 1
+0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+
+1 3
+0 2
+5 4
+0 2 2 2 0 0 0 2 1 1 0 0 2 2 1 1 0 2 1 2 1 2 1 3 3 3 1 3 3 1 1 3 1 1
diff --git a/examples/simple/igraph_community_multilevel.c b/examples/simple/igraph_community_multilevel.c
new file mode 100644
index 0000000..b75dda7
--- /dev/null
+++ b/examples/simple/igraph_community_multilevel.c
@@ -0,0 +1,107 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void show_results(igraph_t *g, igraph_vector_t *membership, igraph_matrix_t *memberships, igraph_vector_t *modularity, FILE* f) {
+  long int i, j, no_of_nodes = igraph_vcount(g);
+
+  j=igraph_vector_which_max(modularity);
+  for (i=0; i<igraph_vector_size(membership); i++) {
+    if (VECTOR(*membership)[i] != MATRIX(*memberships, j, i)) {
+      fprintf(f, "WARNING: best membership vector element %li does not match the best one in the membership matrix\n", i);
+    }
+  }
+
+  fprintf(f, "Modularities:\n");
+  igraph_vector_print(modularity);
+
+  for (i=0; i < igraph_matrix_nrow(memberships); i++) {
+    for (j=0; j < no_of_nodes; j++) {
+      fprintf(f, "%ld ", (long int)MATRIX(*memberships, i, j));
+    }
+    fprintf(f, "\n");
+  }
+
+  fprintf(f, "\n");
+}
+
+int main() {
+  igraph_t g;
+  igraph_vector_t modularity, membership, edges;
+  igraph_matrix_t memberships;
+  int i, j, k;
+
+  igraph_vector_init(&modularity,0);
+  igraph_vector_init(&membership,0);
+  igraph_matrix_init(&memberships,0,0);
+
+  /* Unweighted test graph from the paper of Blondel et al */
+  igraph_small(&g, 16, IGRAPH_UNDIRECTED,
+      0, 2, 0, 3, 0, 4, 0, 5,
+      1, 2, 1, 4, 1, 7,
+      2, 4, 2, 5, 2, 6,
+      3, 7,
+      4, 10,
+      5, 7, 5, 11,
+      6, 7, 6, 11,
+      8, 9, 8, 10, 8, 11, 8, 14, 8, 15,
+      9, 12, 9, 14,
+      10, 11, 10, 12, 10, 13, 10, 14,
+      11, 13,
+      -1);
+  igraph_community_multilevel(&g, 0, &membership, &memberships, &modularity);
+  show_results(&g, &membership, &memberships, &modularity, stdout);
+  igraph_destroy(&g);
+
+  /* Ring of 30 cliques */
+  igraph_vector_init(&edges,0);
+  for (i = 0; i < 30; i++) {
+    for (j = 0; j < 5; j++) {
+      for (k = j+1; k < 5; k++) {
+        igraph_vector_push_back(&edges, i*5+j);
+        igraph_vector_push_back(&edges, i*5+k);
+      }
+    }
+  }
+  for (i = 0; i < 30; i++) {
+    igraph_vector_push_back(&edges, i*5 % 150);
+    igraph_vector_push_back(&edges, (i*5+6) % 150);
+  }
+  igraph_create(&g, &edges, 150, 0);
+  igraph_community_multilevel(&g, 0, &membership, &memberships, &modularity);
+  show_results(&g, &membership, &memberships, &modularity, stdout);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&modularity);
+  igraph_vector_destroy(&membership);
+  igraph_vector_destroy(&edges);
+  igraph_matrix_destroy(&memberships);
+
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
diff --git a/examples/simple/igraph_community_multilevel.out b/examples/simple/igraph_community_multilevel.out
new file mode 100644
index 0000000..81b9362
--- /dev/null
+++ b/examples/simple/igraph_community_multilevel.out
@@ -0,0 +1,10 @@
+Modularities:
+0.346301 0.392219
+0 0 0 1 0 0 1 1 2 2 2 3 2 3 2 2 
+0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 
+
+Modularities:
+0.875758 0.887879
+0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 6 6 6 6 6 7 7 7 7 7 8 8 8 8 8 9 9 9 9 9 10 10 10 10 10 11 11 11 11 11 12 12 12 12 12 13 13 13 13 13 14 14 14 14 14 15 15 15 15 15 16 16 16 16 16 17 17 17 17 17 18 18 18 18 18 19 19 19 19 19 20 20 20 20 20 21 21 21 21 21 22 22 22 22 22 23 23 23 23 23 24 24 24 24 24 25 25 25 25 25 26 26 26 26 26 27 27 27 27 27 28 28 28 28 28 29 29 29 29 29 
+0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9 10 10 10 10 10 10 10 10 10 10 11 11 11 11 11 11 11 11 11 11 12 12 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 
+
diff --git a/examples/simple/igraph_community_optimal_modularity.c b/examples/simple/igraph_community_optimal_modularity.c
new file mode 100644
index 0000000..ef73f95
--- /dev/null
+++ b/examples/simple/igraph_community_optimal_modularity.c
@@ -0,0 +1,99 @@
+/* -*- 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.h>
+
+void prepare_weights_vector(igraph_vector_t* weights, const igraph_t* graph) {
+  int i, n = igraph_ecount(graph);
+  igraph_vector_resize(weights, n);
+  for (i = 0; i < n; i++) {
+    VECTOR(*weights)[i] = i % 5;
+  }
+}
+
+int main() {
+  igraph_t graph;
+
+  igraph_vector_t v;
+  igraph_real_t edges[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
+			    0,10, 0,11, 0,12, 0,13, 0,17, 0,19, 0,21, 0,31,
+			    1, 2, 1, 3, 1, 7, 1,13, 1,17, 1,19, 1,21, 1,30,
+			    2, 3, 2, 7, 2,27, 2,28, 2,32, 2, 9, 2, 8, 2,13,
+			    3, 7, 3,12, 3,13, 4, 6, 4,10, 5, 6, 5,10, 5,16,
+			    6,16, 8,30, 8,32, 8,33, 9,33,13,33,14,32,14,33,
+			    15,32,15,33,18,32,18,33,19,33,20,32,20,33,
+			    22,32,22,33,23,25,23,27,23,32,23,33,23,29,
+			    24,25,24,27,24,31,25,31,26,29,26,33,27,33,
+			    28,31,28,33,29,32,29,33,30,32,30,33,31,32,31,33,
+			    32,33
+  };
+
+  igraph_vector_t membership;
+  igraph_vector_t weights;
+  igraph_real_t modularity;
+  igraph_bool_t simple;
+  int retval;
+
+  igraph_vector_view(&v, edges, sizeof(edges)/sizeof(double));
+  igraph_create(&graph, &v, 0, IGRAPH_UNDIRECTED);
+
+  igraph_vector_init(&weights, 0);
+
+  igraph_is_simple(&graph, &simple);
+  if (!simple) { return 1; }
+
+  igraph_vector_init(&membership, 0);
+
+  igraph_set_error_handler(&igraph_error_handler_printignore);
+
+  /* Zachary karate club, unweighted */
+  retval = igraph_community_optimal_modularity(&graph, &modularity,
+					       &membership, 0);
+  if (retval == IGRAPH_UNIMPLEMENTED) { return 77; }
+  if (fabs(modularity - 0.4197896) > 0.0000001) { return 2; }
+  /* Zachary karate club, weighted */
+  prepare_weights_vector(&weights, &graph);
+  igraph_community_optimal_modularity(&graph, &modularity,
+				      &membership, &weights);
+  if (fabs(modularity - 0.5115767) > 0.0000001) { return 4; }
+  igraph_destroy(&graph);
+
+  /* simple graph with loop edges, unweighted */
+  igraph_small(&graph, 6, IGRAPH_UNDIRECTED,
+          0,1,1,2,2,3,3,4,4,5,5,0,0,0,2,2,-1);
+  igraph_community_optimal_modularity(&graph, &modularity,
+				      &membership, 0);
+  if (fabs(modularity - 0.28125) > 0.00001) { return 3; }
+  /* simple graph with loop edges, weighted */
+  prepare_weights_vector(&weights, &graph);
+  igraph_community_optimal_modularity(&graph, &modularity,
+				      &membership, &weights);
+  if (fabs(modularity - 0.36686) > 0.00001) { return 5; }
+  igraph_destroy(&graph);
+
+  igraph_vector_destroy(&membership);
+  igraph_vector_destroy(&weights);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_complementer.c b/examples/simple/igraph_complementer.c
new file mode 100644
index 0000000..55046e6
--- /dev/null
+++ b/examples/simple/igraph_complementer.c
@@ -0,0 +1,109 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t g1, g2;
+  
+  /* complementer of the empty graph */
+  igraph_empty(&g1, 5, IGRAPH_DIRECTED);
+  igraph_complementer(&g2, &g1, IGRAPH_LOOPS);
+  igraph_write_graph_edgelist(&g2, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+
+  /* the same without loops */
+  igraph_empty(&g1, 5, IGRAPH_DIRECTED);
+  igraph_complementer(&g2, &g1, IGRAPH_NO_LOOPS);
+  igraph_write_graph_edgelist(&g2, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+  
+  /* complementer of the full graph */
+  igraph_full(&g1, 5, IGRAPH_DIRECTED, IGRAPH_LOOPS);
+  igraph_complementer(&g2, &g1, IGRAPH_LOOPS);
+  if (igraph_ecount(&g2) != 0) {
+    return 1;
+  }
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+
+  /* complementer of the full graph, results loops only */
+  igraph_full(&g1, 5, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  igraph_complementer(&g2, &g1, IGRAPH_LOOPS);
+  igraph_write_graph_edgelist(&g2, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+
+  /**************
+   * undirected *
+   *************/
+
+  /* complementer of the empty graph */
+  igraph_empty(&g1, 5, IGRAPH_UNDIRECTED);
+  igraph_complementer(&g2, &g1, IGRAPH_LOOPS);
+  igraph_write_graph_edgelist(&g2, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+
+  /* the same without loops */
+  igraph_empty(&g1, 5, IGRAPH_UNDIRECTED);
+  igraph_complementer(&g2, &g1, IGRAPH_NO_LOOPS);
+  igraph_write_graph_edgelist(&g2, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+  
+  /* complementer of the full graph */
+  igraph_full(&g1, 5, IGRAPH_UNDIRECTED, IGRAPH_LOOPS);
+  igraph_complementer(&g2, &g1, IGRAPH_LOOPS);
+  if (igraph_ecount(&g2) != 0) {
+    return 1;
+  }
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  printf("---\n");
+
+  /* complementer of the full graph, results loops only */
+  igraph_full(&g1, 5, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  igraph_complementer(&g2, &g1, IGRAPH_LOOPS);
+  igraph_write_graph_edgelist(&g2, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_complementer.out b/examples/simple/igraph_complementer.out
new file mode 100644
index 0000000..25f2fdb
--- /dev/null
+++ b/examples/simple/igraph_complementer.out
@@ -0,0 +1,87 @@
+0 0
+0 1
+0 2
+0 3
+0 4
+1 0
+1 1
+1 2
+1 3
+1 4
+2 0
+2 1
+2 2
+2 3
+2 4
+3 0
+3 1
+3 2
+3 3
+3 4
+4 0
+4 1
+4 2
+4 3
+4 4
+---
+0 1
+0 2
+0 3
+0 4
+1 0
+1 2
+1 3
+1 4
+2 0
+2 1
+2 3
+2 4
+3 0
+3 1
+3 2
+3 4
+4 0
+4 1
+4 2
+4 3
+---
+---
+0 0
+1 1
+2 2
+3 3
+4 4
+---
+0 0
+0 1
+0 2
+0 3
+0 4
+1 1
+1 2
+1 3
+1 4
+2 2
+2 3
+2 4
+3 3
+3 4
+4 4
+---
+0 1
+0 2
+0 3
+0 4
+1 2
+1 3
+1 4
+2 3
+2 4
+3 4
+---
+---
+0 0
+1 1
+2 2
+3 3
+4 4
diff --git a/examples/simple/igraph_complex.c b/examples/simple/igraph_complex.c
new file mode 100644
index 0000000..fcb4ee4
--- /dev/null
+++ b/examples/simple/igraph_complex.c
@@ -0,0 +1,183 @@
+/* -*- 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.h>
+#include <math.h>
+
+#define ARE 4
+#define AIM 5
+#define BRE 6
+#define BIM 2
+
+int main() {
+
+  igraph_complex_t a = igraph_complex(ARE, AIM);
+  igraph_complex_t b = igraph_complex(BRE, BIM);
+  igraph_complex_t c, d, e;
+
+  /* polar, mod, arg */
+  c=igraph_complex_polar(igraph_complex_mod(a), igraph_complex_arg(a));
+  if (!igraph_complex_eq_tol(a,c,1e-14)) { return 1; }
+  
+  /* add */
+  c=igraph_complex_add(a,b);
+  if (IGRAPH_REAL(c) != ARE+BRE || IGRAPH_IMAG(c) != AIM+BIM) { return 2; }
+  
+  /* sub */
+  c=igraph_complex_sub(a,b);
+  if (IGRAPH_REAL(c) != ARE-BRE || IGRAPH_IMAG(c) != AIM-BIM) { return 3; }
+
+  /* mul */
+  c=igraph_complex_mul(a,b);
+  if (IGRAPH_REAL(c) != ARE*BRE-AIM*BIM || 
+      IGRAPH_IMAG(c) != ARE*BIM+AIM*BRE) { return 4; }
+  
+  /* div */
+  c=igraph_complex_div(a,b);
+  c=igraph_complex_mul(c,b);
+  if (!igraph_complex_eq_tol(a,c,1e-14)) { return 5; }
+
+  /* add_real */
+  c=igraph_complex_add_real(a,IGRAPH_REAL(b));
+  if (IGRAPH_REAL(c) != IGRAPH_REAL(a) + IGRAPH_REAL(b)) { return 6; }
+  if (IGRAPH_IMAG(c) != IGRAPH_IMAG(a)) { return 7; }
+
+  /* add_imag */
+  c=igraph_complex_add_imag(a,IGRAPH_IMAG(b));
+  if (IGRAPH_REAL(c) != IGRAPH_REAL(a)) { return 8; }
+  if (IGRAPH_IMAG(c) != IGRAPH_IMAG(a) + IGRAPH_IMAG(b)) { return 9; }
+
+  /* sub_real */
+  c=igraph_complex_sub_real(a,IGRAPH_REAL(b));
+  if (IGRAPH_REAL(c) != IGRAPH_REAL(a) - IGRAPH_REAL(b)) { return 10; }
+  if (IGRAPH_IMAG(c) != IGRAPH_IMAG(a)) { return 11; }  
+
+  /* sub_imag */
+  c=igraph_complex_sub_imag(a,IGRAPH_IMAG(b));
+  if (IGRAPH_REAL(c) != IGRAPH_REAL(a)) { return 12; }
+  if (IGRAPH_IMAG(c) != IGRAPH_IMAG(a) - IGRAPH_IMAG(b)) { return 13; }
+
+  /* mul_real */
+  c=igraph_complex_mul_real(a, IGRAPH_REAL(b));
+  if (IGRAPH_REAL(c) != IGRAPH_REAL(a) * IGRAPH_REAL(b)) { return 14; }
+  if (IGRAPH_IMAG(c) != IGRAPH_IMAG(a) * IGRAPH_REAL(b)) { return 15; }
+
+  /* mul_imag */
+  c=igraph_complex_mul_imag(a, IGRAPH_REAL(b));
+  if (IGRAPH_REAL(c) != - IGRAPH_IMAG(a) * IGRAPH_REAL(b)) { return 14; }
+  if (IGRAPH_IMAG(c) != IGRAPH_REAL(a) * IGRAPH_REAL(b)) { return 15; }  
+
+  /* div_real */
+  c=igraph_complex_div_real(a, IGRAPH_REAL(b));
+  if (fabs(IGRAPH_REAL(c) - IGRAPH_REAL(a) / IGRAPH_REAL(b)) > 1e-15) { 
+    return 16; 
+  }
+  if (fabs(IGRAPH_IMAG(c) - IGRAPH_IMAG(a) / IGRAPH_REAL(b)) > 1e-15) { 
+    return 17; 
+  }
+
+  /* div_imag */
+  c=igraph_complex_div_imag(a, IGRAPH_IMAG(b));
+  if (IGRAPH_REAL(c) != IGRAPH_IMAG(a) / IGRAPH_IMAG(b)) { return 18; }
+  if (IGRAPH_IMAG(c) != - IGRAPH_REAL(a) / IGRAPH_IMAG(b)) { return 19; }
+
+  /* conj */
+  c=igraph_complex_conj(a);
+  if (IGRAPH_REAL(c) != ARE || IGRAPH_IMAG(c) != -AIM) { return 20; }
+
+  /* neg */
+  c=igraph_complex_neg(a);
+  if (IGRAPH_REAL(c) != - IGRAPH_REAL(a) ||
+      IGRAPH_IMAG(c) != - IGRAPH_IMAG(a)) { return 21; }
+
+  /* inv */
+  c=igraph_complex_inv(a);
+  d=igraph_complex(1.0, 0.0);
+  e=igraph_complex_div(d, a);
+  if (!igraph_complex_eq_tol(c, e, 1e-14)) { return 22; }
+
+  /* abs */
+  if (igraph_complex_abs(a) != igraph_complex_mod(a)) { return 23; }
+
+  /* logabs */
+
+  /* sqrt */
+  c=igraph_complex_sqrt(a);
+  d=igraph_complex_mul(c,c);
+  if (!igraph_complex_eq_tol(a, d, 1e-14)) { return 24; }
+
+  /* sqrt_real */
+  c=igraph_complex_sqrt(igraph_complex(-1.0, 0.0));
+  d=igraph_complex_sqrt_real(-1.0);
+  if (!igraph_complex_eq_tol(c, d, 1e-14)) { return 25; }
+
+  /* exp */
+  c=igraph_complex_exp(igraph_complex(0.0, M_PI));
+  if (!igraph_complex_eq_tol(c, igraph_complex(-1.0, 0.0), 1e-14)) { 
+    return 26;
+  }
+
+  /* pow */  
+  c=igraph_complex_pow(igraph_complex(M_E, 0.0), igraph_complex(0.0, M_PI));
+  if (!igraph_complex_eq_tol(c, igraph_complex(-1.0, 0.0), 1e-14)) { 
+    return 27;
+  }
+
+  /* pow_real */
+  c=igraph_complex_pow_real(a, 2.0);
+  d=igraph_complex_mul(a,a);
+  if (!igraph_complex_eq_tol(c, d, 1e-12)) { return 28; }  
+
+  /* log */
+  c=igraph_complex_exp(igraph_complex_log(a));
+  if (!igraph_complex_eq_tol(a, c, 1e-14)) { return 29; }
+
+  /* log10 */
+  c=igraph_complex_pow(igraph_complex(10.0, 0), igraph_complex_log10(a));
+  if (!igraph_complex_eq_tol(a, c, 1e-14)) { return 30; }
+  
+  /* log_b */
+  c=igraph_complex_pow(b, igraph_complex_log_b(a, b));
+  if (!igraph_complex_eq_tol(a, c, 1e-14)) { return 31; }
+
+  /* sin, cos */
+  c=igraph_complex_sin(a);
+  d=igraph_complex_cos(a);
+  e=igraph_complex_add(igraph_complex_mul(c,c), igraph_complex_mul(d,d));
+  if (!igraph_complex_eq_tol(e, igraph_complex(1.0, 0.0), 1e-11)) { 
+    return 32;
+  }
+
+  /* tan */
+  c=igraph_complex_tan(a);
+  d=igraph_complex_div(igraph_complex_sin(a), igraph_complex_cos(a));
+  if (!igraph_complex_eq_tol(c, d, 1e-14)) { return 33; }
+
+  /* sec */
+
+  /* csc */
+
+  /* cot */
+
+  return 0;
+}
diff --git a/examples/simple/igraph_compose.c b/examples/simple/igraph_compose.c
new file mode 100644
index 0000000..6bbef5b
--- /dev/null
+++ b/examples/simple/igraph_compose.c
@@ -0,0 +1,117 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  igraph_t g1, g2, res;
+  igraph_vector_t v;
+  igraph_vector_t map1, map2;
+
+  igraph_vector_init(&map1, 0);
+  igraph_vector_init(&map2, 0);
+
+  /* composition with the empty graph */
+  igraph_empty(&g1, 5, IGRAPH_DIRECTED);
+  igraph_full(&g2, 5, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  igraph_compose(&res, &g1, &g2, &map1, &map2);
+  if (igraph_ecount(&res) != 0) { 
+    return 1;
+  }
+  if (igraph_vector_size(&map1) != 0 || igraph_vector_size(&map2) != 0) {
+    return 11;
+  }
+  igraph_destroy(&res);
+  igraph_compose(&res, &g2, &g1, &map1, &map2);
+  if (igraph_ecount(&res) != 0) { 
+    return 2;
+  }
+  if (igraph_vector_size(&map1) != 0 || igraph_vector_size(&map2) != 0) {
+    return 12;
+  }
+  igraph_destroy(&res);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  /* same but undirected */
+  igraph_empty(&g1, 5, IGRAPH_UNDIRECTED);
+  igraph_full(&g2, 5, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  igraph_compose(&res, &g1, &g2, &map1, &map2);
+  if (igraph_ecount(&res) != 0) { 
+    return 1;
+  }
+  if (igraph_vector_size(&map1) != 0 || igraph_vector_size(&map2) != 0) {
+    return 11;
+  }
+  igraph_destroy(&res);
+  igraph_compose(&res, &g2, &g1, &map1, &map2);
+  if (igraph_ecount(&res) != 0) { 
+    return 2;
+  }
+  if (igraph_vector_size(&map1) != 0 || igraph_vector_size(&map2) != 0) {
+    return 12;
+  }
+  igraph_destroy(&res);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  /* proper directed graph */
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 5,6, -1);
+  igraph_create(&g1, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init_int_end(&v, -1, 0,1, 2,4, 5,6, -1);
+  igraph_create(&g2, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_compose(&res, &g1, &g2, &map1, &map2);
+  igraph_write_graph_edgelist(&res, stdout);
+  igraph_vector_print(&map1);
+  igraph_vector_print(&map2);
+  igraph_destroy(&res);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  /* undirected graph */
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 5,6, -1);
+  igraph_create(&g1, &v, 0, IGRAPH_UNDIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init_int_end(&v, -1, 0,1, 0,4, 5,6, -1);
+  igraph_create(&g2, &v, 0, IGRAPH_UNDIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_compose(&res, &g1, &g2, &map1, &map2);
+  igraph_write_graph_edgelist(&res, stdout);
+  igraph_vector_print(&map1);
+  igraph_vector_print(&map2);
+  igraph_destroy(&res);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  igraph_vector_destroy(&map2);
+  igraph_vector_destroy(&map1);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_compose.out b/examples/simple/igraph_compose.out
new file mode 100644
index 0000000..0f37aa3
--- /dev/null
+++ b/examples/simple/igraph_compose.out
@@ -0,0 +1,11 @@
+1 4
+1
+1
+0 0
+0 2
+1 1
+1 4
+5 5
+6 6
+0 0 0 1 2 2
+0 1 0 0 2 2
diff --git a/examples/simple/igraph_convergence_degree.c b/examples/simple/igraph_convergence_degree.c
new file mode 100644
index 0000000..c702f7c
--- /dev/null
+++ b/examples/simple/igraph_convergence_degree.c
@@ -0,0 +1,51 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t result;
+  long i;
+  
+  igraph_vector_init(&result, 0);
+
+  igraph_small(&g, 7, 0, 0,1,0,2,0,3,1,2,1,3,2,3,3,4,4,5,4,6,5,6, -1);
+  igraph_convergence_degree(&g, &result, 0, 0);
+  for (i=0; i<igraph_ecount(&g); i++)
+    printf("%.4f ", (float)igraph_vector_e(&result, i));
+  printf("\n");
+  igraph_destroy(&g);
+
+  igraph_small(&g, 6, 1, 1,0,2,0,3,0,4,0,0,5, -1);
+  igraph_convergence_degree(&g, &result, 0, 0);
+  for (i=0; i<igraph_ecount(&g); i++)
+    printf("%.4f ", (float)igraph_vector_e(&result, i));
+  printf("\n");
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&result);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_convergence_degree.out b/examples/simple/igraph_convergence_degree.out
new file mode 100644
index 0000000..fa1eae6
--- /dev/null
+++ b/examples/simple/igraph_convergence_degree.out
@@ -0,0 +1,2 @@
+0.0000 0.0000 0.6000 0.0000 0.6000 0.6000 0.1429 0.6667 0.6667 0.0000 
+-0.3333 -0.3333 -0.3333 -0.3333 0.6667 
diff --git a/examples/simple/igraph_convex_hull.c b/examples/simple/igraph_convex_hull.c
new file mode 100644
index 0000000..423fab6
--- /dev/null
+++ b/examples/simple/igraph_convex_hull.c
@@ -0,0 +1,62 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  igraph_real_t coords_array[][2] =
+   {{3, 2}, {5, 1}, {4, 4}, {6, 4}, {4, 3},
+    {2, 5}, {1, 3}, {2, 4}, {6, 3}, {9, 2}
+   };
+    
+  igraph_matrix_t coords, resmat;
+  igraph_vector_t result;
+  long i;
+  
+  igraph_matrix_init(&coords, 10, 2);
+  for (i=0; i<20; i++) MATRIX(coords, i/2, i%2) = coords_array[i/2][i%2];
+  
+  /* Testing with index output mode */
+  igraph_vector_init(&result, 1);
+  if (igraph_convex_hull(&coords, &result, 0))
+    return 1;
+
+  for (i=0; i<igraph_vector_size(&result); i++)
+    printf("%ld ", (long)VECTOR(result)[i]);
+  printf("\n");
+  igraph_vector_destroy(&result);
+
+  /* Testing with coordinate output mode */
+  igraph_matrix_init(&resmat, 0, 0);
+  if (igraph_convex_hull(&coords, 0, &resmat))
+    return 1;
+
+  for (i=0; i<igraph_matrix_nrow(&resmat); i++)
+    printf("%ld %ld ", (long)MATRIX(resmat, i, 0), (long)MATRIX(resmat, i, 1));
+  printf("\n");
+  
+  igraph_matrix_destroy(&resmat);
+  igraph_matrix_destroy(&coords);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_convex_hull.out b/examples/simple/igraph_convex_hull.out
new file mode 100644
index 0000000..f6f78fb
--- /dev/null
+++ b/examples/simple/igraph_convex_hull.out
@@ -0,0 +1,2 @@
+1 6 5 3 9 
+5 1 1 3 2 5 6 4 9 2 
diff --git a/examples/simple/igraph_copy.c b/examples/simple/igraph_copy.c
new file mode 100644
index 0000000..8cc79e4
--- /dev/null
+++ b/examples/simple/igraph_copy.c
@@ -0,0 +1,52 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  igraph_t g1, g2;
+  igraph_vector_t v1, v2;
+
+  igraph_vector_init(&v1, 8);
+  VECTOR(v1)[0]=0; VECTOR(v1)[1]=1;
+  VECTOR(v1)[2]=1; VECTOR(v1)[3]=2;
+  VECTOR(v1)[4]=2; VECTOR(v1)[5]=3;
+  VECTOR(v1)[6]=2; VECTOR(v1)[7]=2;
+
+  igraph_create(&g1, &v1, 0, 0);
+  igraph_copy(&g2, &g1);
+
+  igraph_vector_init(&v2, 0);
+  igraph_get_edgelist(&g2, &v2, 0);
+  if (!igraph_vector_all_e(&v1, &v2)) {
+    return 1;
+  }
+
+  igraph_vector_destroy(&v1);
+  igraph_vector_destroy(&v2);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_create.c b/examples/simple/igraph_create.c
new file mode 100644
index 0000000..aa3cb3c
--- /dev/null
+++ b/examples/simple/igraph_create.c
@@ -0,0 +1,84 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t v1, v2;
+  int ret;
+  
+  /* simple use */
+  igraph_vector_init(&v1, 8);
+  VECTOR(v1)[0]=0; VECTOR(v1)[1]=1;
+  VECTOR(v1)[2]=1; VECTOR(v1)[3]=2;
+  VECTOR(v1)[4]=2; VECTOR(v1)[5]=3;
+  VECTOR(v1)[6]=2; VECTOR(v1)[7]=2;
+  igraph_create(&g, &v1, 0, 0);
+  if (igraph_vcount(&g) != 4) {
+    return 1;
+  }
+  igraph_vector_init(&v2, 0);
+  igraph_get_edgelist(&g, &v2, 0);
+  igraph_vector_sort(&v1);
+  igraph_vector_sort(&v2);
+  if (!igraph_vector_all_e(&v1, &v2)) {
+    return 2;
+  }
+  igraph_destroy(&g);
+  
+  /* higher number of vertices */
+  igraph_create(&g, &v1, 10, 0);
+  if (igraph_vcount(&g) != 10) {
+    return 1;
+  }
+  igraph_get_edgelist(&g, &v2, 0);
+  igraph_vector_sort(&v1);
+  igraph_vector_sort(&v2);
+  if (!igraph_vector_all_e(&v1, &v2)) {
+    return 3;
+  }
+  igraph_destroy(&g);
+
+  /* error: IGRAPH_EINVEVECTOR */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  igraph_vector_resize(&v1, 9);
+  VECTOR(v1)[8]=0;
+  ret=igraph_create(&g, &v1, 0, 0);
+  if (ret != IGRAPH_EINVEVECTOR) {
+    return 4;
+  }
+  
+  /* error: IGRAPH_EINVVID */
+  igraph_vector_resize(&v1, 8);
+  VECTOR(v1)[7]=-1;
+  ret=igraph_create(&g, &v1, 10, 1);
+  if (ret != IGRAPH_EINVVID) {
+    return 5;
+  }
+  igraph_vector_destroy(&v1);
+  igraph_vector_destroy(&v2);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_decompose.c b/examples/simple/igraph_decompose.c
new file mode 100644
index 0000000..6cb772c
--- /dev/null
+++ b/examples/simple/igraph_decompose.c
@@ -0,0 +1,103 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdlib.h>
+
+void free_complist(igraph_vector_ptr_t *complist) {
+  long int i;
+  for (i=0; i<igraph_vector_ptr_size(complist); i++) {
+    igraph_destroy(VECTOR(*complist)[i]);
+    free(VECTOR(*complist)[i]);
+  }
+}
+
+int main() {
+  
+  igraph_t ring, g;
+  igraph_vector_ptr_t complist;
+  long int i;
+  igraph_real_t edges[]= { 0,1,1,2,2,0,
+		    3,4,4,5,5,6,
+		    8,9,9,10 };
+  igraph_vector_t v;
+
+  /* A ring, a single component */
+  igraph_ring(&ring, 10, IGRAPH_UNDIRECTED, 0, 1);
+  
+  igraph_vector_ptr_init(&complist, 0);
+  igraph_decompose(&ring, &complist, IGRAPH_WEAK, -1, 0);
+  igraph_write_graph_edgelist(VECTOR(complist)[0], stdout);
+  free_complist(&complist);
+  igraph_destroy(&ring);
+  
+  /* random graph with a giant component */
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100, 4.0/100, 
+			  IGRAPH_UNDIRECTED, 0);
+  igraph_decompose(&g, &complist, IGRAPH_WEAK, -1, 20);
+  if (igraph_vector_ptr_size(&complist) != 1) { 
+    return 1;
+  }
+  free_complist(&complist);
+  igraph_destroy(&g);
+  
+  /* a toy graph, three components maximum, with at least 2 vertices each */
+  igraph_create(&g, 
+		igraph_vector_view(&v, edges, sizeof(edges)/sizeof(igraph_real_t)), 
+		0, IGRAPH_DIRECTED);
+  igraph_decompose(&g, &complist, IGRAPH_WEAK, 3, 2);
+  for (i=0; i<igraph_vector_ptr_size(&complist); i++) {
+    igraph_write_graph_edgelist(VECTOR(complist)[i], stdout);
+  }
+  free_complist(&complist);
+  igraph_destroy(&g);
+
+  /* The same graph, this time with vertex attributes */
+/*   igraph_vector_init_seq(&idvect, 0, igraph_vcount(&g)-1); */
+/*   igraph_add_vertex_attribute(&g, "id", IGRAPH_ATTRIBUTE_NUM); */
+/*   igraph_set_vertex_attributes(&g, "id", IGRAPH_VS_ALL(&g), &idvect); */
+/*   igraph_vector_destroy(&idvect); */
+
+/*   igraph_decompose(&g, &complist, IGRAPH_WEAK, 3, 2); */
+/*   for (i=0; i<igraph_vector_ptr_size(&complist); i++) { */
+/*     igraph_t *comp=VECTOR(complist)[i]; */
+/*     igraph_es_t es; */
+/*     igraph_es_all(comp, &es); */
+/*     while (!igraph_es_end(comp, &es)) { */
+/*       igraph_real_t *from, *to;  */
+/*       igraph_get_vertex_attribute(comp, "id", igraph_es_from(comp, &es), */
+/* 				  (void**) &from, 0); */
+/*       igraph_get_vertex_attribute(comp, "id", igraph_es_to(comp, &es), */
+/* 				  (void**) &to, 0); */
+/*       printf("%li %li\n", (long int) *from, (long int) *to); */
+/*       igraph_es_next(comp, &es); */
+/*     } */
+/*   } */
+  
+/*   free_complist(&complist); */
+/*   igraph_destroy(&g);   */
+  
+  igraph_vector_ptr_destroy(&complist);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_decompose.out b/examples/simple/igraph_decompose.out
new file mode 100644
index 0000000..370b3f7
--- /dev/null
+++ b/examples/simple/igraph_decompose.out
@@ -0,0 +1,18 @@
+0 1
+0 9
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+0 1
+1 2
+2 0
+0 1
+1 2
+2 3
+0 1
+1 2
diff --git a/examples/simple/igraph_degree.c b/examples/simple/igraph_degree.c
new file mode 100644
index 0000000..5241b04
--- /dev/null
+++ b/examples/simple/igraph_degree.c
@@ -0,0 +1,210 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v, seq;
+  int ret;
+  igraph_integer_t mdeg, nedges;
+  long int i;
+  long int ndeg;
+
+  /* Create graph */
+  igraph_vector_init(&v, 8);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=3;
+  VECTOR(v)[6]=2; VECTOR(v)[7]=2;
+  igraph_create(&g, &v, 0, IGRAPH_DIRECTED);
+  
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+  
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+  
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_set_error_handler(igraph_error_handler_ignore);
+
+  /* Consistency check of the handshaking lemma. */
+  /* If d is the sum of all vertex degrees, then d = 2|E|. */
+  ndeg = 0;
+  nedges = igraph_ecount(&g);
+  for (i = 0; i < igraph_vector_size(&v); i++) {
+    ndeg += (long int) VECTOR(v)[i];
+  }
+  if (ndeg != 2*nedges) {
+    return 1;
+  }
+  
+  igraph_destroy(&g);
+  
+  igraph_vector_resize(&v, 8);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=3;
+  VECTOR(v)[6]=2; VECTOR(v)[7]=2;
+  igraph_create(&g, &v, 0, IGRAPH_UNDIRECTED);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+  
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+  
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS);
+  print_vector(&v, stdout);
+
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+
+  /* Consistency check of the handshaking lemma. */
+  /* If d is the sum of all vertex degrees, then d = 2|E|. */
+  ndeg = 0;
+  nedges = igraph_ecount(&g);
+  for (i = 0; i < igraph_vector_size(&v); i++) {
+    ndeg += (long int) VECTOR(v)[i];
+  }
+  if (ndeg != 2*nedges) {
+    return 2;
+  }
+
+  /* Degree of the same vertex multiple times */
+  
+  igraph_vector_init(&seq, 3);
+  VECTOR(seq)[0]=2; VECTOR(seq)[1]=0; VECTOR(seq)[2]=2;
+  igraph_degree(&g, &v, igraph_vss_vector(&seq), IGRAPH_ALL, IGRAPH_LOOPS);
+  print_vector(&v, stdout);
+
+  /* Errors */
+  ret=igraph_degree(&g, &v, igraph_vss_vector(&seq), (igraph_neimode_t)0, 
+		    IGRAPH_LOOPS);
+  if (ret != IGRAPH_EINVMODE) {
+    return 3;
+  }
+
+  VECTOR(seq)[0]=4;
+  ret=igraph_degree(&g, &v, igraph_vss_vector(&seq), IGRAPH_ALL, IGRAPH_LOOPS);
+  if (ret != IGRAPH_EINVVID) {
+    return 4;
+  }  
+
+  igraph_destroy(&g);
+  igraph_vector_destroy(&seq);
+
+  /* Maximum degree */
+  
+  igraph_ring(&g, 10, 0 /*undirected*/, 0 /*undirected*/, 0/*uncircular*/);
+  igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  if (mdeg != 2) { 
+    return 5;
+  }
+  /* Consistency check of the handshaking lemma. */
+  /* If d is the sum of all vertex degrees, then d = 2|E|. */
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  ndeg = 0;
+  nedges = igraph_ecount(&g);
+  for (i = 0; i < igraph_vector_size(&v); i++) {
+    ndeg += (long int) VECTOR(v)[i];
+  }
+  if (ndeg != 2*nedges) {
+    return 6;
+  }
+  igraph_destroy(&g);
+  
+  igraph_full(&g, 10, 0 /*undirected*/, 0/*no loops*/);
+  igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  if (mdeg != 9) {
+    return 7;
+  }
+  /* Consistency check of the handshaking lemma. */
+  /* If d is the sum of all vertex degrees, then d = 2|E|. */
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  ndeg = 0;
+  nedges = igraph_ecount(&g);
+  for (i = 0; i < igraph_vector_size(&v); i++) {
+    ndeg += (long int) VECTOR(v)[i];
+  }
+  if (ndeg != 2*nedges) {
+    return 8;
+  }
+  igraph_destroy(&g);
+
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
+  igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
+  if (mdeg != 9) {
+    return 9;
+  }
+  igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
+  if (mdeg != 1) {
+    return 10;
+  }
+  igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  if (mdeg != 9) {
+    return 11;
+  }
+  /* Consistency check of the handshaking lemma. */
+  /* If d is the sum of all vertex degrees, then d = 2|E|. */
+  igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  ndeg = 0;
+  nedges = igraph_ecount(&g);
+  for (i = 0; i < igraph_vector_size(&v); i++) {
+    ndeg += (long int) VECTOR(v)[i];
+  }
+  if (ndeg != 2*nedges) {
+    return 12;
+  }
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&v);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_degree.out b/examples/simple/igraph_degree.out
new file mode 100644
index 0000000..d3b252f
--- /dev/null
+++ b/examples/simple/igraph_degree.out
@@ -0,0 +1,13 @@
+ 1 1 1 0
+ 1 1 2 0
+ 0 1 1 1
+ 0 1 2 1
+ 1 2 2 1
+ 1 2 4 1
+ 1 2 2 1
+ 1 2 4 1
+ 1 2 2 1
+ 1 2 4 1
+ 1 2 2 1
+ 1 2 4 1
+ 4 1 4
diff --git a/examples/simple/igraph_degree_sequence_game.c b/examples/simple/igraph_degree_sequence_game.c
new file mode 100644
index 0000000..abfc3d5
--- /dev/null
+++ b/examples/simple/igraph_degree_sequence_game.c
@@ -0,0 +1,98 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t outdeg, indeg, vec;
+  igraph_bool_t is_simple;
+
+  igraph_vector_init_real(&outdeg, 10, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0);
+  igraph_vector_init_real(&indeg, 10, 4.0, 4.0, 2.0, 2.0, 4.0, 4.0, 2.0, 2.0, 3.0, 3.0);
+  igraph_vector_init(&vec, 0);
+
+  /* checking the simple method, undirected graphs */
+  igraph_degree_sequence_game(&g, &outdeg, 0, IGRAPH_DEGSEQ_SIMPLE);
+  if (igraph_is_directed(&g) || igraph_vcount(&g) != 10)
+	return 1;
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, 1))
+	return 2;
+  igraph_vector_print(&vec);
+  igraph_destroy(&g);
+
+  /* checking the Viger-Latapy method, undirected graphs */
+  igraph_degree_sequence_game(&g, &outdeg, 0, IGRAPH_DEGSEQ_VL);
+  if (igraph_is_directed(&g) || igraph_vcount(&g) != 10)
+	return 3;
+  if (igraph_is_simple(&g, &is_simple) || !is_simple)
+	return 4;
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, 0))
+	return 5;
+  igraph_vector_print(&vec);
+  igraph_destroy(&g);
+
+  /* checking the simple method, directed graphs */
+  igraph_degree_sequence_game(&g, &outdeg, &indeg, IGRAPH_DEGSEQ_SIMPLE);
+  if (!igraph_is_directed(&g) || igraph_vcount(&g) != 10)
+	return 6;
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, 1))
+	return 7;
+  igraph_vector_print(&vec);
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_IN, 1))
+	return 8;
+  igraph_vector_print(&vec);
+  igraph_destroy(&g);
+
+  /* checking the no multiple edges method, undirected graphs */
+  igraph_degree_sequence_game(&g, &outdeg, 0, IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE);
+  if (igraph_is_directed(&g) || igraph_vcount(&g) != 10)
+	return 9;
+  if (igraph_is_simple(&g, &is_simple) || !is_simple)
+	return 10;
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, 1))
+	return 11;
+  igraph_vector_print(&vec);
+  igraph_destroy(&g);
+
+  /* checking the no multiple edges method, directed graphs */
+  igraph_degree_sequence_game(&g, &outdeg, &indeg, IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE);
+  if (!igraph_is_directed(&g) || igraph_vcount(&g) != 10)
+	return 12;
+  if (igraph_is_simple(&g, &is_simple) || !is_simple)
+	return 13;
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, 1))
+	return 14;
+  igraph_vector_print(&vec);
+  if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_IN, 1))
+	return 15;
+  igraph_vector_print(&vec);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&vec);
+  igraph_vector_destroy(&outdeg);
+  igraph_vector_destroy(&indeg);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_degree_sequence_game.out b/examples/simple/igraph_degree_sequence_game.out
new file mode 100644
index 0000000..d2285c1
--- /dev/null
+++ b/examples/simple/igraph_degree_sequence_game.out
@@ -0,0 +1,7 @@
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3 3
+4 4 2 2 4 4 2 2 3 3
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3 3
+4 4 2 2 4 4 2 2 3 3
diff --git a/examples/simple/igraph_delete_edges.c b/examples/simple/igraph_delete_edges.c
new file mode 100644
index 0000000..29dfa4b
--- /dev/null
+++ b/examples/simple/igraph_delete_edges.c
@@ -0,0 +1,84 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v;
+  int ret;
+  igraph_es_t es;
+
+  igraph_vector_init(&v, 8);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=3;
+  VECTOR(v)[6]=2; VECTOR(v)[7]=2;
+  igraph_create(&g, &v, 0, 0);
+  
+  igraph_es_pairs_small(&es, IGRAPH_DIRECTED, 3,2, -1);
+  igraph_delete_edges(&g, es);
+  if (igraph_ecount(&g) != 3) {
+    return 1;
+  }
+
+  /* error test, no such edge to delete */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_delete_edges(&g, es);
+  if (ret != IGRAPH_EINVAL) {
+    printf("Error code: %i\n", ret);
+    return 2;
+  } 
+  if (igraph_ecount(&g) != 3) {
+    return 3;
+  }
+
+  /* error test, invalid vertex id */
+  igraph_es_destroy(&es);
+  igraph_es_pairs_small(&es, IGRAPH_DIRECTED, 10,2, -1);
+  ret=igraph_delete_edges(&g, es);
+  if (ret != IGRAPH_EINVVID) {
+    return 4;
+  } 
+  if (igraph_ecount(&g) != 3) {
+    return 5;
+  }
+  
+  /* error test, invalid (odd) length */
+  igraph_es_destroy(&es);
+  igraph_es_pairs_small(&es, IGRAPH_DIRECTED, 0,1,2, -1);
+  ret=igraph_delete_edges(&g, es);
+  if (ret != IGRAPH_EINVAL) {
+    return 6;
+  } 
+  if (igraph_ecount(&g) != 3) {
+    return 7;
+  }  
+
+  igraph_es_destroy(&es);
+  igraph_vector_destroy(&v);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_delete_vertices.c b/examples/simple/igraph_delete_vertices.c
new file mode 100644
index 0000000..d71489b
--- /dev/null
+++ b/examples/simple/igraph_delete_vertices.c
@@ -0,0 +1,74 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v;
+  int ret;
+
+  /* without edges */
+  igraph_empty(&g, 5, IGRAPH_DIRECTED);
+  igraph_add_vertices(&g, 2, 0);
+  igraph_add_vertices(&g, 3, 0);
+  igraph_add_vertices(&g, 1, 0);
+  igraph_add_vertices(&g, 4, 0);
+  if (igraph_vcount(&g) != 15)  {
+    return 1;
+  }
+  igraph_delete_vertices(&g, igraph_vss_1(2));
+  if (igraph_vcount(&g) != 14)  {
+    return 2;
+  }
+  igraph_destroy(&g);
+   
+  igraph_vector_init(&v, 8);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=3;
+  VECTOR(v)[6]=2; VECTOR(v)[7]=2;
+  igraph_create(&g, &v, 0, 0);
+  igraph_vector_destroy(&v);
+
+  /* resize vector */
+  igraph_delete_vertices(&g, igraph_vss_1(2));
+  if (igraph_vcount(&g) != 3) {
+    return 3;
+  }
+  if (igraph_ecount(&g) != 1) {
+    return 4;
+  }
+
+  /* error test */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_delete_vertices(&g, igraph_vss_1(3));
+  if (ret != IGRAPH_EINVVID) {
+    return 5;
+  }
+  
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_density.c b/examples/simple/igraph_density.c
new file mode 100644
index 0000000..398e382
--- /dev/null
+++ b/examples/simple/igraph_density.c
@@ -0,0 +1,133 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-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.h>
+
+void test_density(const igraph_t *graph, igraph_bool_t loops) {
+  igraph_real_t density;
+
+  if (igraph_density(graph, &density, loops)) {
+    printf("FAILED!\n");
+    return;
+  }
+
+  if (igraph_is_nan(density)) {
+    printf("nan\n");
+  } else {
+    printf("%.4f\n", density);
+  }
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v;
+
+  igraph_vector_init(&v, 0);
+
+  /* Test graphs with no vertices and no edges */
+  igraph_create(&g, &v, 0, IGRAPH_UNDIRECTED);
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 0, IGRAPH_DIRECTED);
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Test graphs with one vertex and no edges */
+  igraph_create(&g, &v, 1, IGRAPH_UNDIRECTED);
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 1, IGRAPH_DIRECTED);
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Test graphs with one vertex and a loop edge */
+  igraph_vector_resize(&v, 2);
+  VECTOR(v)[0] = 0; VECTOR(v)[1] = 0;
+  igraph_create(&g, &v, 1, IGRAPH_UNDIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 1, IGRAPH_DIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Test graphs with one vertex and two loop edges */
+  igraph_vector_resize(&v, 4);
+  VECTOR(v)[0] = 0; VECTOR(v)[1] = 0;
+  VECTOR(v)[2] = 0; VECTOR(v)[3] = 0;
+  igraph_create(&g, &v, 1, IGRAPH_UNDIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 1, IGRAPH_DIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Test graphs with two vertices and one edge between them */
+  igraph_vector_resize(&v, 2);
+  VECTOR(v)[0] = 0; VECTOR(v)[1] = 1;
+  igraph_create(&g, &v, 2, IGRAPH_UNDIRECTED);
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 1, IGRAPH_DIRECTED);
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Test graphs with two vertices, one edge between them and a loop on one
+   * of them */
+  igraph_vector_resize(&v, 4);
+  VECTOR(v)[0] = 0; VECTOR(v)[1] = 1;
+  VECTOR(v)[2] = 1; VECTOR(v)[3] = 1;
+  igraph_create(&g, &v, 2, IGRAPH_UNDIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 1, IGRAPH_DIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Test graphs with two vertices, one edge between them and a loop on both
+   * of them */
+  igraph_vector_resize(&v, 6);
+  VECTOR(v)[0] = 0; VECTOR(v)[1] = 1;
+  VECTOR(v)[2] = 1; VECTOR(v)[3] = 1;
+  VECTOR(v)[4] = 0; VECTOR(v)[5] = 0;
+  igraph_create(&g, &v, 2, IGRAPH_UNDIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  igraph_create(&g, &v, 1, IGRAPH_DIRECTED);
+  test_density(&g, 1);
+  igraph_destroy(&g);
+  printf("======\n");
+
+  /* Zachary karate club graph */
+  igraph_famous(&g, "zachary");
+  test_density(&g, 0); test_density(&g, 1);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&v);
+}
diff --git a/examples/simple/igraph_density.out b/examples/simple/igraph_density.out
new file mode 100644
index 0000000..cbd7583
--- /dev/null
+++ b/examples/simple/igraph_density.out
@@ -0,0 +1,29 @@
+nan
+nan
+nan
+nan
+======
+nan
+0.0000
+nan
+0.0000
+======
+1.0000
+1.0000
+======
+2.0000
+2.0000
+======
+1.0000
+0.3333
+0.5000
+0.2500
+======
+0.6667
+0.5000
+======
+1.0000
+0.7500
+======
+0.1390
+0.1311
diff --git a/examples/simple/igraph_deterministic_optimal_imitation.c b/examples/simple/igraph_deterministic_optimal_imitation.c
new file mode 100644
index 0000000..55bf565
--- /dev/null
+++ b/examples/simple/igraph_deterministic_optimal_imitation.c
@@ -0,0 +1,244 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for deterministic optimal imitation.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+
+/* test parameters structure */
+typedef struct {
+  igraph_t *graph;
+  igraph_integer_t vertex;
+  igraph_optimal_t optimality;
+  igraph_vector_t *quantities;
+  igraph_vector_t *strategies;
+  igraph_neimode_t mode;
+  int retval;
+} strategy_test_t;
+
+/* Error tests. That is, we expect error codes to be returned from such tests.
+ */
+int error_tests() {
+  igraph_t g, h;
+  igraph_vector_t quant, strat;
+  int i, n, ret;
+  strategy_test_t *test;
+
+  /* nonempty graph */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  igraph_empty(&h, 0, 0);         /* empty graph */
+  igraph_vector_init(&quant, 1);  /* quantities vector */
+  igraph_vector_init(&strat, 2);  /* strategies vector */
+
+  {
+    /* test parameters */
+    /*--graph--vertex--optimality--quantities--strategies--mode--retval--*/
+    /* null pointer for graph */
+    strategy_test_t null_graph = { NULL, 0, 0, NULL, NULL, IGRAPH_ALL, 
+				   IGRAPH_EINVAL };
+    /* null pointer for quantities vector */
+    strategy_test_t null_quant = { &g, 0, 0, NULL, NULL, IGRAPH_ALL, 
+				   IGRAPH_EINVAL };
+    /* null pointer for strategies vector */
+    strategy_test_t null_strat = { &g, 0, 0, &quant, NULL, IGRAPH_ALL, 
+				   IGRAPH_EINVAL };
+    /* empty graph */
+    strategy_test_t empty_graph = {&h, 0, 0, &quant, &strat, IGRAPH_ALL, 
+				   IGRAPH_EINVAL };
+    /* length of quantities vector different from number of vertices */
+    strategy_test_t qdiff_length = {&g, 0, 0, &quant, &strat, IGRAPH_ALL, 
+				    IGRAPH_EINVAL };
+    /* length of strategies vector different from number of vertices */
+    strategy_test_t sdiff_length = {&g, 0, 0, &quant, &strat, IGRAPH_ALL, 
+				    IGRAPH_EINVAL };
+    strategy_test_t *all_checks[] = {/* 1 */ &null_graph,
+				     /* 2 */ &null_quant,
+				     /* 3 */ &null_strat,
+				     /* 4 */ &empty_graph,
+				     /* 5 */ &qdiff_length,
+				     /* 6 */ &sdiff_length};
+    n = 6;
+    /* Run the error tests. We expect an error to be raised for each test. */
+    igraph_set_error_handler(igraph_error_handler_ignore);
+    i = 0;
+    while (i < n) {
+      test = all_checks[i];
+      ret = igraph_deterministic_optimal_imitation(test->graph,
+						   test->vertex,
+						   test->optimality,
+						   test->quantities,
+						   test->strategies,
+						   test->mode);
+      if (ret != test->retval) {
+	printf("Error test no. %d failed.\n", (int)(i + 1));
+	return IGRAPH_FAILURE;
+      }
+      i++;
+    }
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_destroy(&h);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* Updating the strategy of an isolated vertex. In this case, the strategies
+ * vector should not change at all.
+ */
+int isolated_vertex_test() {
+  igraph_t g;
+  igraph_vector_t quant, strat, v;
+  int i, ret;
+
+  /* graph with one isolated vertex */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  igraph_add_vertices(&g, 1, 0);  /* new vertex 3 is isolated */
+  /* quantities vector: all vertices have the same fitness */
+  igraph_vector_init_real(&quant, 4, 0.25, 0.25, 0.25, 0.25);
+  /* strategies vector: 0 means aggressive strategy; 1 means passive */
+  igraph_vector_init_real(&strat, 4, 1., 0., 1., 0.);
+  /* make a copy of the original strategies vector for comparison later on */
+  igraph_vector_copy(&v, &strat);
+  /* Now update strategy of vertex 3. Since this vertex is isolated, no */
+  /* strategy update would take place. The resulting strategies vector */
+  /* would be the same as it was originally. */
+  ret = igraph_deterministic_optimal_imitation(/*graph*/ &g,
+  					       /*vertex*/ 3,
+  					       /*optimality*/ IGRAPH_MAXIMUM,
+  					       /*quantities*/ &quant,
+  					       /*strategies*/ &strat,
+  					       /*mode*/ IGRAPH_ALL);
+  if (ret) {
+    printf("Isolated vertex test failed.\n");
+    return IGRAPH_FAILURE;
+  }
+  for (i = 0; i < igraph_vector_size(&strat); i++) {
+    if (VECTOR(strat)[i] != VECTOR(v)[i]) {
+      printf("Isolated vertex test failed.\n");
+      return IGRAPH_FAILURE;
+    }
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+  igraph_vector_destroy(&v);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* A game on the Petersen graph. This graph has 10 vertices and 15 edges.
+ * The Petersen graph is initialized with a default quantities vector and a
+ * default strategies vector. For each vertex v in the graph, we update the
+ * strategy of v via deterministic optimal imitation. The resulting updated
+ * strategies vector is compared with the known result vector. A mismatch would
+ * raise an error code. If the updated strategies vector matches the known
+ * result vector, we reset the strategies vector to its default state and
+ * repeat the game with another vertex.
+ */
+int petersen_game_test() {
+  igraph_t g;
+  igraph_vector_t known_max_v, known_min_v, quant, strat, stratcopy;
+  int i, nedge, nvert;  
+
+  /* the Petersen graph */
+  igraph_small(&g, /*n=*/ 0, IGRAPH_UNDIRECTED, 
+	       0,1,0,4,0,5, 1,2,1,6, 2,3,2,7, 3,4,3,8, 4,9,
+	       5,7,5,8, 6,8,6,9, 7,9, -1);
+  nedge = igraph_ecount(&g);
+  nvert = igraph_vcount(&g);
+  /* Strategies vector, one strategy for each vertex. Thus vec[i] is the */
+  /* strategy of vertex i. The strategy space is: {0, 1, 2, 3}. */
+  igraph_vector_init_real(&strat, nvert, 
+			  1., 1., 2., 2., 0.,
+			  0., 0., 1., 2., 3.);
+  /* Quantities vector, one quantity per vertex. Thus vec[i] is the */
+  /* quantity for vertex i. */
+  igraph_vector_init_real(&quant, nvert, 
+			  0.3, 1.1, 0.5, 1.0, 0.9, 
+			  0.8, 0.4, 0.1, 0.7, 0.7);
+  /* Known strategies that would be adopted. Thus vec[i] means that in */
+  /* game i where we revise the strategy of vertex i, the strategy */
+  /* vec[i] would be adopted by i. */
+  /*maximum deterministic imitation*/
+  igraph_vector_init_real(&known_max_v, nvert, 
+			  1., 1., 1., 2., 2., 
+			  0., 1., 0., 2., 0.);
+  /*minimum deterministic imitation*/
+  igraph_vector_init_real(&known_min_v, nvert,
+			  1., 1., 1., 2., 1.,
+			  1., 0., 1., 0., 1.);
+  /* play game and compare resulting updated strategies */
+  for (i = 0; i < nvert; i++) {
+    /* maximum deterministic imitation */
+    igraph_vector_copy(&stratcopy, &strat);
+    igraph_deterministic_optimal_imitation(/*graph*/ &g,
+					   /*vertex*/ (igraph_integer_t)i,
+					   /*optimality*/ IGRAPH_MAXIMUM,
+					   /*quantities*/ &quant,
+					   /*strategies*/ &stratcopy,
+					   /*neighbours*/ IGRAPH_ALL);
+    if (VECTOR(stratcopy)[i] != VECTOR(known_max_v)[i]) {
+      printf("Maximum deterministic imitation failed for vertex %d.\n", i);
+      return IGRAPH_FAILURE;
+    }
+    igraph_vector_destroy(&stratcopy);
+    /* minimum deterministic imitation */
+    igraph_vector_copy(&stratcopy, &strat);
+    igraph_deterministic_optimal_imitation(/*graph*/ &g,
+					   /*vertex*/ (igraph_integer_t)i,
+					   /*optimality*/ IGRAPH_MINIMUM,
+					   /*quantities*/ &quant,
+					   /*strategies*/ &stratcopy,
+					   /*neighbours*/ IGRAPH_ALL);
+    if (VECTOR(stratcopy)[i] != VECTOR(known_min_v)[i]) {
+      printf("Minimum deterministic imitation failed for vertex %d.\n", i);
+      return IGRAPH_FAILURE;
+    }
+    igraph_vector_destroy(&stratcopy);
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_vector_destroy(&known_max_v);
+  igraph_vector_destroy(&known_min_v);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+
+  return IGRAPH_SUCCESS;
+}
+
+int main() {
+  int ret;
+
+  ret = error_tests();
+  if (ret)
+    return ret;
+  ret = isolated_vertex_test();
+  if (ret)
+    return ret;
+  ret = petersen_game_test();
+  if (ret)
+    return ret;
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/examples/simple/igraph_diameter.c b/examples/simple/igraph_diameter.c
new file mode 100644
index 0000000..ac6ff6a
--- /dev/null
+++ b/examples/simple/igraph_diameter.c
@@ -0,0 +1,61 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_integer_t result;
+  igraph_integer_t from, to;
+  igraph_vector_t path;
+  
+  igraph_barabasi_game(&g, 30, /*power=*/ 1, 30, 0, 0, /*A=*/ 1, 
+		       IGRAPH_DIRECTED, IGRAPH_BARABASI_BAG, 
+		       /*start_from=*/ 0);
+  igraph_diameter(&g, &result, 0, 0, 0, IGRAPH_UNDIRECTED, 1);
+  
+/*   printf("Diameter: %li\n", (long int) result); */
+  
+  igraph_destroy(&g);
+
+  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0, 0);
+  igraph_vector_init(&path, 0);
+  igraph_diameter(&g, &result, &from, &to, &path, IGRAPH_DIRECTED, 1);
+  printf("diameter: %li, from %li to %li\n", (long int) result,
+	 (long int) from, (long int) to);
+  print_vector(&path);
+  
+  igraph_vector_destroy(&path);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_diameter.out b/examples/simple/igraph_diameter.out
new file mode 100644
index 0000000..1ca9732
--- /dev/null
+++ b/examples/simple/igraph_diameter.out
@@ -0,0 +1,2 @@
+diameter: 9, from 0 to 9
+ 0 1 2 3 4 5 6 7 8 9
diff --git a/examples/simple/igraph_difference.c b/examples/simple/igraph_difference.c
new file mode 100644
index 0000000..e3e640c
--- /dev/null
+++ b/examples/simple/igraph_difference.c
@@ -0,0 +1,121 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t orig, sub, diff;
+  igraph_vector_t v;
+
+  /* Subtract from itself */
+  printf("subtract itself\n");
+  igraph_vector_init_int_end(&v, -1, 0,1,1,2,2,1,4,5, -1);
+  igraph_create(&orig, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_difference(&diff, &orig, &orig);
+  igraph_write_graph_edgelist(&diff, stdout);
+  if (igraph_ecount(&diff) != 0 ||
+      igraph_vcount(&diff) != igraph_vcount(&orig)) {
+    return 1;
+  }
+  
+  igraph_destroy(&orig);
+  igraph_destroy(&diff);
+
+  /* Same for undirected graph */
+  printf("subtract itself, undirected\n");
+  igraph_vector_init_int_end(&v, -1, 0,1,1,2,2,1,4,5, -1);
+  igraph_create(&orig, &v, 0, IGRAPH_UNDIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init_int_end(&v, -1, 1,0,1,2,2,1,4,5, -1);
+  igraph_create(&sub, &v, 0, IGRAPH_UNDIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_difference(&diff, &orig, &sub);
+  igraph_write_graph_edgelist(&diff, stdout);
+  if (igraph_ecount(&diff) != 0 ||
+      igraph_vcount(&diff) != igraph_vcount(&orig)) {
+    return 2;
+  }
+  
+  igraph_destroy(&orig);
+  igraph_destroy(&sub);
+  igraph_destroy(&diff);
+  
+  /* Subtract the empty graph */
+  printf("subtract empty\n");
+  igraph_vector_init_int_end(&v, -1, 0,1,1,2,2,1,4,5, -1);
+  igraph_create(&orig, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_empty(&sub, 3, IGRAPH_DIRECTED);
+  igraph_difference(&diff, &orig, &sub);
+  igraph_write_graph_edgelist(&diff, stdout);
+  if (igraph_ecount(&diff) != igraph_ecount(&orig) ||
+      igraph_vcount(&diff) != igraph_vcount(&orig)) {
+    return 3;
+  }
+
+  igraph_destroy(&orig);
+  igraph_destroy(&sub);
+  igraph_destroy(&diff);
+
+  /* A `real' example */
+  printf("real example\n");
+  igraph_vector_init_int_end(&v, -1, 0,1,1,2,2,1,4,5,8,9, -1);
+  igraph_create(&orig, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init_int_end(&v, -1, 0,1,5,4,2,1,6,7, -1);
+  igraph_create(&sub, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_difference(&diff, &orig, &sub);
+  igraph_write_graph_edgelist(&diff, stdout);
+
+  igraph_destroy(&diff);
+  igraph_destroy(&orig);
+  igraph_destroy(&sub);  
+
+  /* undirected version */
+  printf("real example, undirected\n");
+  igraph_vector_init_int_end(&v, -1, 0,1,1,2,2,1,4,5,8,9,8,10,8,13,8,11,8,12, -1);
+  igraph_create(&orig, &v, 0, IGRAPH_UNDIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init_int_end(&v, -1, 0,1,5,4,2,1,6,7,8,10,8,13, -1);
+  igraph_create(&sub, &v, 0, IGRAPH_UNDIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_difference(&diff, &orig, &sub);
+  igraph_write_graph_edgelist(&diff, stdout);
+
+  igraph_destroy(&diff);
+  igraph_destroy(&orig);
+  igraph_destroy(&sub);  
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_difference.out b/examples/simple/igraph_difference.out
new file mode 100644
index 0000000..3d9c1d4
--- /dev/null
+++ b/examples/simple/igraph_difference.out
@@ -0,0 +1,16 @@
+subtract itself
+subtract itself, undirected
+subtract empty
+0 1
+1 2
+2 1
+4 5
+real example
+1 2
+4 5
+8 9
+real example, undirected
+1 2
+8 9
+8 11
+8 12
diff --git a/examples/simple/igraph_disjoint_union.c b/examples/simple/igraph_disjoint_union.c
new file mode 100644
index 0000000..c375c3b
--- /dev/null
+++ b/examples/simple/igraph_disjoint_union.c
@@ -0,0 +1,95 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, l=igraph_vector_size(v);
+  for (i=0; i<l; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int main() {
+  
+  igraph_t left, right, uni;
+  igraph_vector_t v;
+  igraph_vector_ptr_t glist;
+  long int i;
+
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,2, 2,3, -1);
+  igraph_create(&left, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,2, 2,4, -1); 
+  igraph_create(&right, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_disjoint_union(&uni, &left, &right);
+  igraph_vector_init(&v, 0);
+  igraph_get_edgelist(&uni, &v, 0);
+  igraph_vector_sort(&v);
+  print_vector(&v);
+  
+  igraph_vector_destroy(&v);
+  igraph_destroy(&left);
+  igraph_destroy(&right);
+  igraph_destroy(&uni);
+
+  /* Empty graph list */
+  igraph_vector_ptr_init(&glist, 0);
+  igraph_disjoint_union_many(&uni, &glist);
+  if (!igraph_is_directed(&uni) || igraph_vcount(&uni) != 0) {
+    return 1;
+  }
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&uni);
+
+  /* Non-empty graph list */
+  igraph_vector_ptr_init(&glist, 10); 
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    VECTOR(glist)[i]=calloc(1, sizeof(igraph_t));
+    igraph_vector_init_int_end(&v, -1, 0,1, 1,0, -1);
+    igraph_create(VECTOR(glist)[i], &v, 0, IGRAPH_DIRECTED);    
+    igraph_vector_destroy(&v);
+  }
+
+  igraph_disjoint_union_many(&uni, &glist);
+  igraph_vector_init(&v, 0);
+  igraph_get_edgelist(&uni, &v, 0);
+  igraph_vector_sort(&v);
+  print_vector(&v);
+  igraph_vector_destroy(&v);
+
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    igraph_destroy(VECTOR(glist)[i]);
+    free(VECTOR(glist)[i]);
+  }
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&uni);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_disjoint_union.out b/examples/simple/igraph_disjoint_union.out
new file mode 100644
index 0000000..c4fbf70
--- /dev/null
+++ b/examples/simple/igraph_disjoint_union.out
@@ -0,0 +1,2 @@
+ 0 1 1 2 2 2 2 3 4 5 5 6 6 6 6 8
+ 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19
diff --git a/examples/simple/igraph_eccentricity.c b/examples/simple/igraph_eccentricity.c
new file mode 100644
index 0000000..e55d595
--- /dev/null
+++ b/examples/simple/igraph_eccentricity.c
@@ -0,0 +1,52 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2011-12  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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t ecc;
+
+  igraph_vector_init(&ecc, 0);
+  
+  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
+  igraph_eccentricity(&g, &ecc, igraph_vss_all(), IGRAPH_OUT);
+  igraph_vector_print(&ecc);
+  igraph_destroy(&g);
+  
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
+  igraph_eccentricity(&g, &ecc, igraph_vss_all(), IGRAPH_ALL);
+  igraph_vector_print(&ecc);
+  igraph_destroy(&g);
+
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
+  igraph_eccentricity(&g, &ecc, igraph_vss_all(), IGRAPH_OUT);
+  igraph_vector_print(&ecc);
+  igraph_destroy(&g);  
+
+  igraph_vector_destroy(&ecc);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_eccentricity.out b/examples/simple/igraph_eccentricity.out
new file mode 100644
index 0000000..a92f5e0
--- /dev/null
+++ b/examples/simple/igraph_eccentricity.out
@@ -0,0 +1,3 @@
+1 2 2 2 2 2 2 2 2 2
+1 2 2 2 2 2 2 2 2 2
+1 0 0 0 0 0 0 0 0 0
diff --git a/examples/simple/igraph_edge_betweenness.c b/examples/simple/igraph_edge_betweenness.c
new file mode 100644
index 0000000..a7ad4ce
--- /dev/null
+++ b/examples/simple/igraph_edge_betweenness.c
@@ -0,0 +1,84 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, "%.5f\n", (double) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t eb; 
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);
+  
+  igraph_vector_init(&eb, igraph_ecount(&g));
+  igraph_edge_betweenness(&g, &eb, IGRAPH_UNDIRECTED, /*weights=*/ 0);
+  print_vector(&eb, stdout);
+  igraph_vector_destroy(&eb);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
+    0, 1, 0, 2, 0, 3, 1, 4, -1);
+  igraph_vector_init(&eb, igraph_ecount(&g));
+  igraph_edge_betweenness_estimate(&g, &eb, IGRAPH_UNDIRECTED, 2, 
+				   /*weights=*/ 0);
+  print_vector(&eb, stdout);
+  igraph_vector_destroy(&eb);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
+    0, 1, 0, 3, 1, 2, 1, 4, 2, 5, 3, 4, 3, 6, 4, 5, 4, 7, 5, 8,
+    6, 7, 7, 8, -1);
+  igraph_vector_init(&eb, igraph_ecount(&g));
+  igraph_edge_betweenness_estimate(&g, &eb, IGRAPH_UNDIRECTED, 2,
+				   /*weights=*/ 0);
+  print_vector(&eb, stdout);
+  igraph_vector_destroy(&eb);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_edge_betweenness.out b/examples/simple/igraph_edge_betweenness.out
new file mode 100644
index 0000000..8af5253
--- /dev/null
+++ b/examples/simple/igraph_edge_betweenness.out
@@ -0,0 +1,97 @@
+14.16667
+43.63889
+11.50000
+29.33333
+43.83333
+43.83333
+12.80238
+41.64841
+29.33333
+33.00000
+26.10000
+23.77063
+22.50952
+25.77063
+22.50952
+71.39286
+13.03333
+4.33333
+4.16429
+6.95952
+10.49048
+8.20952
+10.49048
+18.10952
+12.58333
+14.14524
+5.14762
+17.28095
+4.28095
+23.10873
+12.78095
+38.70159
+1.88810
+6.90000
+8.37143
+2.66667
+1.66667
+1.66667
+2.66667
+16.50000
+16.50000
+5.50000
+17.07778
+22.68492
+16.61429
+38.04921
+13.51111
+19.48889
+13.51111
+19.48889
+13.51111
+19.48889
+33.31349
+13.51111
+19.48889
+13.51111
+19.48889
+11.09444
+5.91111
+3.73333
+12.53333
+18.32778
+2.36667
+10.46667
+22.50000
+23.59444
+2.54286
+30.45714
+17.09762
+8.33333
+13.78095
+13.08730
+16.72222
+9.56667
+15.04286
+23.24444
+29.95397
+4.61429
+
+4.00000
+3.00000
+3.00000
+2.00000
+
+3.00000
+3.00000
+3.00000
+4.00000
+3.00000
+4.00000
+3.00000
+4.00000
+4.00000
+3.00000
+3.00000
+3.00000
+
diff --git a/examples/simple/igraph_eigen_matrix.c b/examples/simple/igraph_eigen_matrix.c
new file mode 100644
index 0000000..7829e10
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix.c
@@ -0,0 +1,124 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  int nodes=10;
+  igraph_real_t triplets[] = { 1,0, 1/4.0,       0,1, 1/3.0, 
+			       2,0, 1/4.0,       0,2, 1/3.0,
+			       3,0, 1.0,         0,3, 1/3.0,
+			       4,1, 1.0,         1,4, 1/4.0,
+			       5,1, 1.0,         1,5, 1/4.0,
+			       6,1, 1.0,         1,6, 1/4.0,
+			       7,2, 1.0,         2,7, 1/4.0,
+			       8,2, 1.0,         2,8, 1/4.0,
+			       9,2, 1.0,         2,9, 1/4.0 };
+  
+  igraph_sparsemat_t mat;
+  int i, n=sizeof(triplets) / sizeof(igraph_real_t);
+  igraph_eigen_which_t which;
+  igraph_vector_complex_t values, values2;
+  igraph_matrix_complex_t vectors, vectors2;
+  igraph_matrix_t mat2;
+  
+  igraph_sparsemat_init(&mat, nodes, nodes, n/3);
+  for (i=0; i<n; i+=3) {
+    igraph_sparsemat_entry(&mat, triplets[i], triplets[i+1], triplets[i+2]);
+  }
+
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=1;
+
+  igraph_vector_complex_init(&values, 0);
+  igraph_matrix_complex_init(&vectors, 0, 0);
+
+  igraph_eigen_matrix(/*matrix=*/ 0, /*sparsemat=*/ &mat, /*fun=*/ 0, 
+		      nodes, /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values, &vectors);
+
+  if (IGRAPH_REAL(MATRIX(vectors, 0, 0)) < 0) { 
+    igraph_matrix_complex_scale(&vectors, igraph_complex(-1.0, -0.0 ));
+  }
+
+  igraph_vector_complex_print(&values);
+  igraph_matrix_complex_print(&vectors);
+
+  igraph_sparsemat_destroy(&mat);
+
+  /* Calcualate all eigenvalues, using SM and LM and then check that they 
+     are the same, in opposite order. We use a random matrix this time. */
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_matrix_init(&mat2, nodes, nodes);
+  for (i=0; i<nodes; i++) {
+    int j;
+    for (j=0; j<nodes; j++) {
+      MATRIX(mat2, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=nodes;
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values, &vectors);
+  
+  which.pos=IGRAPH_EIGEN_SM;
+  which.howmany=nodes;
+  igraph_vector_complex_init(&values2, 0);
+  igraph_matrix_complex_init(&vectors2, 0, 0);
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values2, &vectors2);
+
+#define DUMP() do {				\
+    igraph_vector_complex_print(&values);	\
+    igraph_vector_complex_print(&values2);	\
+  } while(0)
+
+  for (i=0; i<nodes; i++) { 
+    int j;
+    igraph_real_t d=
+      igraph_complex_abs(igraph_complex_sub(VECTOR(values)[i],
+					    VECTOR(values2)[nodes-i-1]));
+    if (d > 1e-15) { DUMP(); return 2; }
+    for (j=0; j<nodes; j++) { 
+      igraph_real_t d=
+	igraph_complex_abs(igraph_complex_sub(MATRIX(vectors, j, i), 
+					      MATRIX(vectors2, j,
+						     nodes-i-1)));
+      if (d > 1e-15) { DUMP(); return 3; }
+    }
+  }
+  
+  igraph_vector_complex_destroy(&values);
+  igraph_matrix_complex_destroy(&vectors);  
+  igraph_vector_complex_destroy(&values2);
+  igraph_matrix_complex_destroy(&vectors2);
+
+  igraph_matrix_destroy(&mat2);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_eigen_matrix.out b/examples/simple/igraph_eigen_matrix.out
new file mode 100644
index 0000000..c24fe02
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix.out
@@ -0,0 +1,11 @@
+1+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
+0.316228+0i
diff --git a/examples/simple/igraph_eigen_matrix2.c b/examples/simple/igraph_eigen_matrix2.c
new file mode 100644
index 0000000..bbf4092
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix2.c
@@ -0,0 +1,107 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define DUMP() do {				\
+    igraph_vector_complex_print(&values);	\
+    igraph_vector_complex_print(&values2);	\
+  } while(0)
+
+int main() {
+  
+  const int nodes=10;
+  igraph_matrix_t mat2;
+  igraph_vector_complex_t values, values2;
+  igraph_matrix_complex_t vectors, vectors2;
+  igraph_eigen_which_t which;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_matrix_init(&mat2, nodes, nodes);
+  for (i=0; i<nodes; i++) {
+    int j;
+    for (j=0; j<nodes; j++) {
+      MATRIX(mat2, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+
+  /* Test LR, a single eigenvalue first */
+  
+  igraph_vector_complex_init(&values, 0);
+  igraph_matrix_complex_init(&vectors, 0, 0);
+  which.pos=IGRAPH_EIGEN_LR;
+  which.howmany=1;
+  
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which,
+		      /*options=*/ 0, /*storage=*/ 0, &values, &vectors);
+  
+  igraph_vector_complex_print(&values);
+  igraph_matrix_complex_print(&vectors);  
+  
+  igraph_vector_complex_destroy(&values);
+  igraph_matrix_complex_destroy(&vectors);
+  
+  /* LR, and SR, all eigenvalues */
+  
+  igraph_vector_complex_init(&values, 0);
+  igraph_matrix_complex_init(&vectors, 0, 0);
+  which.pos=IGRAPH_EIGEN_LR;
+  which.howmany=nodes;
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values, &vectors);
+  
+  igraph_vector_complex_init(&values2, 0);
+  igraph_matrix_complex_init(&vectors2, 0, 0);
+  which.pos=IGRAPH_EIGEN_SR;
+  which.howmany=nodes;
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values2, &vectors2);
+
+  for (i=0; i<nodes; i++) { 
+    int j;
+    igraph_real_t d=
+      igraph_complex_abs(igraph_complex_sub(VECTOR(values)[i],
+					    VECTOR(values2)[nodes-i-1]));
+    if (d > 1e-15) { DUMP(); return 2; }
+    for (j=0; j<nodes; j++) { 
+      igraph_real_t d=
+	igraph_complex_abs(igraph_complex_sub(MATRIX(vectors, j, i), 
+					      MATRIX(vectors2, j,
+						     nodes-i-1)));
+      if (d > 1e-15) { DUMP(); return 3; }
+    }
+  }
+
+  igraph_vector_complex_destroy(&values);
+  igraph_matrix_complex_destroy(&vectors);  
+  igraph_vector_complex_destroy(&values2);
+  igraph_matrix_complex_destroy(&vectors2);
+
+  igraph_matrix_destroy(&mat2);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_eigen_matrix2.out b/examples/simple/igraph_eigen_matrix2.out
new file mode 100644
index 0000000..8ca4732
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix2.out
@@ -0,0 +1,11 @@
+49.9655+0i
+0.376489+0i
+0.280558+0i
+0.344153+0i
+0.252112+0i
+0.265478+0i
+0.372991+0i
+0.367542+0i
+0.289639+0i
+0.280074+0i
+0.300868+0i
diff --git a/examples/simple/igraph_eigen_matrix3.c b/examples/simple/igraph_eigen_matrix3.c
new file mode 100644
index 0000000..4d9d5f3
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix3.c
@@ -0,0 +1,89 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define DUMP() do {				\
+    igraph_vector_complex_print(&values);	\
+    igraph_vector_complex_print(&values2);	\
+  } while(0)
+
+int main() {
+  
+  const int nodes=10, skip=3;
+  igraph_matrix_t mat2;
+  igraph_vector_complex_t values, values2;
+  igraph_matrix_complex_t vectors, vectors2;
+  igraph_eigen_which_t which;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_matrix_init(&mat2, nodes, nodes);
+  for (i=0; i<nodes; i++) {
+    int j;
+    for (j=0; j<nodes; j++) {
+      MATRIX(mat2, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+
+  which.pos=IGRAPH_EIGEN_SELECT;
+  which.il=skip; 
+  which.iu=nodes-skip;
+
+  igraph_vector_complex_init(&values, 0);
+  igraph_matrix_complex_init(&vectors, 0, 0);
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values, &vectors);
+  
+  which.pos=IGRAPH_EIGEN_ALL;
+
+  igraph_vector_complex_init(&values2, 0);
+  igraph_matrix_complex_init(&vectors2, 0, 0);
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which,
+		      /*options=*/ 0, /*storage=*/ 0, &values2, &vectors2);
+  
+  for (i=0; i<nodes-skip*2+1; i++) {
+    int j;
+    igraph_real_t d=
+      igraph_complex_abs(igraph_complex_sub(VECTOR(values)[i], 
+					    VECTOR(values2)[i+skip-1]));
+    if (d > 1e-15) { DUMP(); return 2; }
+    for (j=0; j<nodes; j++) {
+      igraph_real_t d=
+	igraph_complex_abs(igraph_complex_sub(MATRIX(vectors, j, i), 
+					      MATRIX(vectors2, j, i+skip-1)));
+      if (d > 1e-15) { DUMP(); return 3; }
+    }
+  }
+  
+  igraph_vector_complex_destroy(&values);
+  igraph_matrix_complex_destroy(&vectors);
+  igraph_vector_complex_destroy(&values2);
+  igraph_matrix_complex_destroy(&vectors2);
+  igraph_matrix_destroy(&mat2);
+  
+  return 0;
+}
+  
diff --git a/examples/simple/igraph_eigen_matrix3.out b/examples/simple/igraph_eigen_matrix3.out
new file mode 100644
index 0000000..e69de29
diff --git a/examples/simple/igraph_eigen_matrix4.c b/examples/simple/igraph_eigen_matrix4.c
new file mode 100644
index 0000000..587d90b
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix4.c
@@ -0,0 +1,92 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define DUMP() do {				\
+    igraph_vector_complex_print(&values);	\
+    igraph_vector_complex_print(&values2);	\
+  } while(0)
+
+int main() {
+  
+  const int nodes=10;
+  igraph_matrix_t mat2;
+  igraph_vector_complex_t values, values2;
+  igraph_matrix_complex_t vectors, vectors2;
+  igraph_eigen_which_t which;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_matrix_init(&mat2, nodes, nodes);
+  for (i=0; i<nodes; i++) {
+    int j;
+    for (j=0; j<nodes; j++) {
+      MATRIX(mat2, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+
+  igraph_vector_complex_init(&values, 0);
+  igraph_matrix_complex_init(&vectors, 0, 0);
+  which.pos=IGRAPH_EIGEN_LI;
+  which.howmany=nodes;
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which,
+		      /*options=*/ 0, /*storage=*/ 0, &values, &vectors);
+  
+  igraph_vector_complex_init(&values2, 0);
+  igraph_matrix_complex_init(&vectors2, 0, 0);
+  which.pos=IGRAPH_EIGEN_SI;
+  which.howmany=nodes;
+  igraph_eigen_matrix(&mat2, /*sparsemat=*/ 0, /*fun=*/ 0, nodes, 
+		      /*extra=*/ 0, IGRAPH_EIGEN_LAPACK, &which, 
+		      /*options=*/ 0, /*storage=*/ 0, &values2, &vectors2);
+
+  igraph_vector_complex_print(&values);
+  igraph_vector_complex_print(&values2);
+
+  for (i=0; i<nodes; i++) { 
+    int j;
+    igraph_real_t d=
+      igraph_complex_abs(igraph_complex_sub(VECTOR(values)[i],
+					    VECTOR(values2)[nodes-i-1]));
+    if (d > 1e-15) { DUMP(); return 2; }
+    for (j=0; j<nodes; j++) { 
+      igraph_real_t d=
+	igraph_complex_abs(igraph_complex_sub(MATRIX(vectors, j, i), 
+					      MATRIX(vectors2, j,
+						     nodes-i-1)));
+      if (d > 1e-15) { DUMP(); return 3; }
+    }
+  }
+
+  igraph_vector_complex_destroy(&values);
+  igraph_matrix_complex_destroy(&vectors);
+  igraph_vector_complex_destroy(&values2);
+  igraph_matrix_complex_destroy(&vectors2);
+  igraph_matrix_destroy(&mat2);
+  
+  return 0;
+}
+  
+  
diff --git a/examples/simple/igraph_eigen_matrix4.out b/examples/simple/igraph_eigen_matrix4.out
new file mode 100644
index 0000000..b97a46c
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix4.out
@@ -0,0 +1,2 @@
+-0.533366+6.22277i 6.77236+3.96835i -5.06056+2.90197i 49.9655+0i 12.0702+0i -3.82636+0i -8.56628+0i -5.06056-2.90197i 6.77236-3.96835i -0.533366-6.22277i
+-0.533366-6.22277i 6.77236-3.96835i -5.06056-2.90197i -8.56628+0i -3.82636+0i 12.0702+0i 49.9655+0i -5.06056+2.90197i 6.77236+3.96835i -0.533366+6.22277i
diff --git a/examples/simple/igraph_eigen_matrix_symmetric.c b/examples/simple/igraph_eigen_matrix_symmetric.c
new file mode 100644
index 0000000..0d450b8
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix_symmetric.c
@@ -0,0 +1,122 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+
+#define DIM 10
+
+int check_ev(const igraph_matrix_t *A, const igraph_vector_t *values,
+	     const igraph_matrix_t *vectors) {
+
+  int i, n=igraph_matrix_nrow(A);
+  int ne=igraph_matrix_ncol(vectors);
+  igraph_vector_t v, lhs, rhs;
+
+  if (ne != igraph_vector_size(values)) {
+    printf("'values' and 'vectors' sizes do not match\n");
+    exit(1);
+  }
+
+  igraph_vector_init(&lhs, n);
+  igraph_vector_init(&rhs, n);
+
+  for (i=0; i<ne; i++) {
+    igraph_vector_view(&v, &MATRIX(*vectors, 0, i), n);
+    igraph_blas_dgemv(/*transpose=*/ 0, /*alpha=*/ 1, A, &v, 
+		      /*beta=*/ 0, &lhs);
+    igraph_vector_update(&rhs, &v);
+    igraph_vector_scale(&rhs, VECTOR(*values)[i]);
+    if (igraph_vector_maxdifference(&lhs, &rhs) > 1e-10) { 
+      printf("LHS: "); igraph_vector_print(&lhs);
+      printf("RHS: "); igraph_vector_print(&rhs);
+      exit(2);
+    }
+  }
+  
+  igraph_vector_destroy(&rhs);
+  igraph_vector_destroy(&lhs);
+  
+  return 0;
+}
+
+int main() {
+  
+  igraph_matrix_t A;
+  igraph_vector_t values;
+  igraph_matrix_t vectors;
+  int i, j;
+  igraph_eigen_which_t which;
+
+  igraph_rng_seed(igraph_rng_default(), 42 * 42);
+  
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&vectors, 0, 0);
+  igraph_vector_init(&values, 0);
+
+  /* All eigenvalues and eigenvectors */
+
+  for (i=0; i<DIM; i++) {
+    for (j=i; j<DIM; j++) {
+      MATRIX(A, i, j) = MATRIX(A, j, i) = 
+	igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=5;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+				IGRAPH_EIGEN_LAPACK, &which, /*options=*/ 0,
+				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors);
+
+  which.howmany=8;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+				IGRAPH_EIGEN_LAPACK, &which, /*options=*/ 0,
+				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors);
+
+  which.pos=IGRAPH_EIGEN_BE;
+  which.howmany=5;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+				IGRAPH_EIGEN_LAPACK, &which, /*options=*/ 0,
+				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors);
+
+  which.pos=IGRAPH_EIGEN_SM;
+  which.howmany=5;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+				IGRAPH_EIGEN_LAPACK, &which, /*options=*/ 0,
+				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors);
+  
+  igraph_vector_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+  igraph_matrix_destroy(&A);  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_eigen_matrix_symmetric.out b/examples/simple/igraph_eigen_matrix_symmetric.out
new file mode 100644
index 0000000..bdb1f17
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix_symmetric.out
@@ -0,0 +1,4 @@
+56.5915 14.2507 -12.9906 11.1434 -10.4525
+56.5915 14.2507 -12.9906 11.1434 -10.4525 -8.0168 7.44269 -4.93995
+56.5915 -12.9906 14.2507 -10.4525 11.1434
+1.36756 4.60399 -4.93995 7.44269 -8.0168
diff --git a/examples/simple/igraph_eigen_matrix_symmetric_arpack.c b/examples/simple/igraph_eigen_matrix_symmetric_arpack.c
new file mode 100644
index 0000000..81a935d
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix_symmetric_arpack.c
@@ -0,0 +1,123 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+#include <time.h>
+
+#define DIM 10
+
+int check_ev(const igraph_matrix_t *A, const igraph_vector_t *values,
+	     const igraph_matrix_t *vectors, int err_off) {
+
+  int i, n=igraph_matrix_nrow(A);
+  int ne=igraph_matrix_ncol(vectors);
+  igraph_vector_t v, lhs, rhs;
+
+  if (ne != igraph_vector_size(values)) {
+    printf("'values' and 'vectors' sizes do not match\n");
+    exit(err_off + 1);
+  }
+
+  igraph_vector_init(&lhs, n);
+  igraph_vector_init(&rhs, n);
+
+  for (i=0; i<ne; i++) {
+    igraph_vector_view(&v, &MATRIX(*vectors, 0, i), n);
+    igraph_blas_dgemv(/*transpose=*/ 0, /*alpha=*/ 1, A, &v, 
+		      /*beta=*/ 0, &lhs);
+    igraph_vector_update(&rhs, &v);
+    igraph_vector_scale(&rhs, VECTOR(*values)[i]);
+    if (igraph_vector_maxdifference(&lhs, &rhs) > 1e-10) { 
+      printf("LHS %i: ", i); igraph_vector_print(&lhs);
+      printf("RHS %i: ", i); igraph_vector_print(&rhs);
+      exit(err_off + 2);
+    }
+  }
+  
+  igraph_vector_destroy(&rhs);
+  igraph_vector_destroy(&lhs);
+  
+  return 0;
+}
+
+int main() {
+
+  igraph_matrix_t A;
+  igraph_vector_t values;
+  igraph_matrix_t vectors;
+  int i, j;
+  igraph_eigen_which_t which;
+  igraph_arpack_options_t options;
+
+  igraph_rng_seed(igraph_rng_default(), 42 * 42);
+  
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&vectors, 0, 0);
+  igraph_vector_init(&values, 0);
+
+  igraph_arpack_options_init(&options);
+
+  for (i=0; i<DIM; i++) {
+    for (j=i; j<DIM; j++) {
+      MATRIX(A, i, j) = MATRIX(A, j, i) = 
+	igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=2;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+  				IGRAPH_EIGEN_ARPACK, &which, &options,
+  				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors, 0);
+
+  which.howmany=8;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+  				IGRAPH_EIGEN_ARPACK, &which, &options,
+  				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors, 10);
+
+  which.pos=IGRAPH_EIGEN_BE;
+  which.howmany=5;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+				IGRAPH_EIGEN_ARPACK, &which, &options,
+				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors, 20);
+
+  which.pos=IGRAPH_EIGEN_SM;
+  which.howmany=5;
+  igraph_eigen_matrix_symmetric(&A, /*sA=*/ 0, /*fun=*/ 0, DIM, /*extra=*/ 0,
+				IGRAPH_EIGEN_ARPACK, &which, &options,
+				/*storage=*/ 0, &values, &vectors);
+  igraph_vector_print(&values);
+  check_ev(&A, &values, &vectors, 30);
+  
+  igraph_vector_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+  igraph_matrix_destroy(&A);  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_eigen_matrix_symmetric_arpack.out b/examples/simple/igraph_eigen_matrix_symmetric_arpack.out
new file mode 100644
index 0000000..892c18e
--- /dev/null
+++ b/examples/simple/igraph_eigen_matrix_symmetric_arpack.out
@@ -0,0 +1,4 @@
+56.5915 14.2507
+56.5915 14.2507 -12.9906 11.1434 -10.4525 -8.0168 7.44269 -4.93995
+56.5915 -12.9906 14.2507 -10.4525 11.1434
+1.36756 4.60399 -4.93995 7.44269 -8.0168
diff --git a/examples/simple/igraph_empty.c b/examples/simple/igraph_empty.c
new file mode 100644
index 0000000..84fca49
--- /dev/null
+++ b/examples/simple/igraph_empty.c
@@ -0,0 +1,79 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  int ret;
+
+  /* empty directed graph, zero vertices */
+  igraph_empty(&g, 0, 1);
+  if (igraph_vcount(&g) != 0) {
+    return 1;
+  }
+  if (igraph_ecount(&g) != 0) {
+    return 2;
+  }
+  igraph_destroy(&g);
+  
+  /* empty undirected graph, zero vertices */
+  igraph_empty(&g, 0, 0);
+  if (igraph_vcount(&g) != 0) {
+    return 3;
+  }
+  if (igraph_ecount(&g) != 0) {
+    return 4;
+  }
+  igraph_destroy(&g);
+
+  /* empty directed graph, 20 vertices */
+  igraph_empty(&g, 20, 1);
+  if (igraph_vcount(&g) != 20) {
+    return 5;
+  }
+  if (igraph_ecount(&g) != 0) {
+    return 6;
+  }
+  igraph_destroy(&g);
+  
+  /* empty undirected graph, 30 vertices */
+  igraph_empty(&g, 30, 0);
+  if (igraph_vcount(&g) != 30) {
+    return 7;
+  }
+  if (igraph_ecount(&g) != 0) {
+    return 8;
+  }
+  igraph_destroy(&g);
+
+  /* error: negative number of vertices */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_empty(&g, -1, 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 9;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_erdos_renyi_game.c b/examples/simple/igraph_erdos_renyi_game.c
new file mode 100644
index 0000000..72c732b
--- /dev/null
+++ b/examples/simple/igraph_erdos_renyi_game.c
@@ -0,0 +1,214 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  int i;
+  igraph_bool_t simple;
+  
+  /* G(n,p) */
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 10, 0.0, 
+			  IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  if (igraph_ecount(&g) != 0) {
+    return 1;
+  }
+  if (igraph_is_directed(&g)) {
+    return 2;
+  }
+  igraph_destroy(&g);
+  
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 10, 1.0,
+			  IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  if (igraph_ecount(&g) != 10*9) {
+    return 3;
+  }
+  if (!igraph_is_directed(&g)) {
+    return 4;
+  }
+  igraph_destroy(&g);
+
+  /* More useful tests */
+/*   printf("directed with loops\n"); */
+  for (i=0; i<100; i++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 10, 0.9999999,
+			    IGRAPH_DIRECTED, IGRAPH_LOOPS);
+    if (igraph_vcount(&g) != 10) { return 5; }
+    if (igraph_ecount(&g) != 10*10) { return 77; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    if (igraph_ecount(&g) != 10*9) { return 77; }
+    igraph_destroy(&g);
+  }
+
+/*   printf("directed without loops\n"); */
+  for (i=0; i<100; i++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 10, 0.9999999,
+			    IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+    if (igraph_vcount(&g) != 10) { return 7; }
+    if (igraph_ecount(&g) != 10*(10-1)) { return 77; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    if (igraph_ecount(&g) != 10*9) { return 77; }
+    igraph_destroy(&g);
+  }
+  
+/*   printf("undirected with loops\n"); */
+  for (i=0; i<100; i++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 10, 0.9999999,
+			    IGRAPH_UNDIRECTED, IGRAPH_LOOPS);
+    if (igraph_vcount(&g) != 10) { return 9; }
+    if (igraph_ecount(&g) != 10*(10+1)/2) { return 77; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    if (igraph_ecount(&g) != 10*(10-1)/2) { return 77; }
+    igraph_destroy(&g);
+  }
+
+/*   printf("undirected without loops\n"); */
+  for (i=0; i<100; i++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 10, 0.9999999,
+			    IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+    if (igraph_vcount(&g) != 10) { return 11; }
+    if (igraph_ecount(&g) != 10*(10-1)/2) { return 77; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    if (igraph_ecount(&g) != 10*(10-1)/2) { return 77; }
+    igraph_destroy(&g);
+  }    
+
+  /* Create a couple of large graphs too */
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100000, 2.0/100000,
+			  IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 25; }
+  igraph_destroy(&g);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100000, 2.0/100000,
+			  IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 25; }
+  igraph_destroy(&g);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100000, 2.0/100000,
+			  IGRAPH_UNDIRECTED, IGRAPH_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 25; }
+  igraph_destroy(&g);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100000, 2.0/100000,
+			  IGRAPH_DIRECTED, IGRAPH_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 25; }
+  igraph_destroy(&g);
+  
+
+  /* --------------------------------------------------------------------- */
+  /* G(n,m) */
+  
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 10, 0.5,
+			  IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  igraph_destroy(&g);
+
+  /* More useful tests */
+/*   printf("directed with loops\n"); */
+  for (i=0; i<100; i++) {
+    long int ec;
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 10, 10*10-1,
+			    IGRAPH_DIRECTED, IGRAPH_LOOPS);
+    if (igraph_vcount(&g) != 10) { return 13; }
+    if (igraph_ecount(&g) != 10*10-1) { return 14; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    igraph_is_simple(&g, &simple);
+    if (!simple) { return 27; }
+    ec=igraph_ecount(&g);
+    if (ec != 10*9 && ec != 10*9-1) { return 15; }
+    igraph_destroy(&g);
+  }
+
+/*   printf("directed without loops\n"); */
+  for (i=0; i<100; i++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 10, 10*9-1,
+			    IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+    igraph_is_simple(&g, &simple);
+    if (!simple) { return 28; }
+    if (igraph_vcount(&g) != 10) { return 16; }
+    if (igraph_ecount(&g) != 10*(10-1)-1) { return 17; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    if (igraph_ecount(&g) != 10*9-1) { return 18; }
+    igraph_destroy(&g);
+  }
+  
+/*   printf("undirected with loops\n"); */
+  for (i=0; i<100; i++) {
+    long int ec;
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 10, 10*11/2-1,
+			    IGRAPH_UNDIRECTED, IGRAPH_LOOPS);
+    if (igraph_vcount(&g) != 10) { return 19; }
+    if (igraph_ecount(&g) != 10*(10+1)/2-1) { return 20; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    igraph_is_simple(&g, &simple);
+    if (!simple) { return 29; }
+    ec=igraph_ecount(&g);
+    if (ec != 10*(10-1)/2 && ec != 10*9/2-1) { return 21; }
+    igraph_destroy(&g);
+  }
+
+/*   printf("undirected without loops\n"); */
+  for (i=0; i<100; i++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 10, 10*9/2-1,
+			    IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+    igraph_is_simple(&g, &simple);
+    if (!simple) { return 30; }
+    if (igraph_vcount(&g) != 10) { return 22; }
+    if (igraph_ecount(&g) != 10*(10-1)/2-1) { return 23; }
+    igraph_simplify(&g, /*multiple=*/0, /*loops=*/1, /*edge_comb=*/ 0);
+    if (igraph_ecount(&g) != 10*(10-1)/2-1) { return 24; }
+    igraph_destroy(&g);
+  }  
+
+  /* Create a couple of large graphs too */
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 100000, 2.0*100000,
+			  IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 26; }
+  if (igraph_ecount(&g) != 200000) { return 26; }
+  igraph_is_simple(&g, &simple);
+  if (!simple) { return 31; }
+  igraph_destroy(&g);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 100000, 2.0*100000,
+			  IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  igraph_is_simple(&g, &simple);
+  if (!simple) { return 32; }
+  if (igraph_vcount(&g) != 100000) { return 26; }
+  if (igraph_ecount(&g) != 200000) { return 26; }
+  igraph_destroy(&g);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 100000, 2.0*100000,
+			  IGRAPH_UNDIRECTED, IGRAPH_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 26; }
+  if (igraph_ecount(&g) != 200000) { return 26; }
+  igraph_simplify(&g, 0, 1, /*edge_comb=*/ 0);	/* only remove loops */
+  igraph_is_simple(&g, &simple);
+  if (!simple) { return 33; }
+  igraph_destroy(&g);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, 100000, 2.0*100000,
+			  IGRAPH_DIRECTED, IGRAPH_LOOPS);
+  if (igraph_vcount(&g) != 100000) { return 26; }
+  if (igraph_ecount(&g) != 200000) { return 26; }
+  igraph_simplify(&g, 0, 1, /*edge_comb=*/ 0);	/* only remove loops */
+  igraph_is_simple(&g, &simple);
+  if (!simple) { return 34; }
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_es_adj.c b/examples/simple/igraph_es_adj.c
new file mode 100644
index 0000000..86ed03f
--- /dev/null
+++ b/examples/simple/igraph_es_adj.c
@@ -0,0 +1,126 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void igraph_vector_print(const igraph_vector_t *v) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    printf("%li ", (long int)VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int main() {
+  
+  igraph_t g;
+  const igraph_vector_t v=IGRAPH_VECTOR_NULL;
+  igraph_real_t edges1[] = { 0,1, 1,2, 2,2, 2,3, 2,4, 3,4 };
+  igraph_vector_t was;
+  igraph_integer_t size;
+  igraph_es_t it;
+  long int i;
+  
+  igraph_vector_view(&v, edges1, sizeof(edges1)/sizeof(igraph_real_t));
+  igraph_vector_init(&was, 0);
+
+  /******************************************/
+  /* Directed graph                         */
+  /******************************************/
+ 
+  igraph_create(&g, &v, 0, IGRAPH_DIRECTED);
+  
+  /* Simple test, all neighbors */
+  for (i=0; i<=igraph_vector_max(&v); i++) {
+    igraph_vector_clear(&was);
+    igraph_es_adj(&g, &it, i, IGRAPH_ALL);
+    igraph_es_size(&g, &it, &size);
+    printf("%ld\n", (long)size);
+    while (!igraph_es_end(&g, &it)) {
+      igraph_vector_push_back(&was, igraph_es_adj_vertex(&g, &it));
+      igraph_es_next(&g, &it);
+    }
+    igraph_es_destroy(&it);
+    igraph_vector_sort(&was);
+    igraph_vector_print(&was);
+  }
+
+  /* Simple test, outgoing neighbors */
+  for (i=0; i<=igraph_vector_max(&v); i++) {
+    igraph_vector_clear(&was);
+    igraph_es_adj(&g, &it, i, IGRAPH_OUT);
+    igraph_es_size(&g, &it, &size);
+    printf("%ld\n", (long)size);
+    while (!igraph_es_end(&g, &it)) {
+      igraph_vector_push_back(&was, igraph_es_adj_vertex(&g, &it));
+      igraph_es_next(&g, &it);
+    }
+    igraph_es_destroy(&it);
+    igraph_vector_sort(&was);
+    igraph_vector_print(&was);
+  }
+
+
+  /* Simple test, incoming neighbors */
+  for (i=0; i<=igraph_vector_max(&v); i++) {
+    igraph_vector_clear(&was);
+    igraph_es_adj(&g, &it, i, IGRAPH_IN);
+    igraph_es_size(&g, &it, &size);
+    printf("%ld\n", (long)size);
+    while (!igraph_es_end(&g, &it)) {
+      igraph_vector_push_back(&was, igraph_es_adj_vertex(&g, &it));
+      igraph_es_next(&g, &it);
+    }
+    igraph_es_destroy(&it);
+    igraph_vector_sort(&was);
+    igraph_vector_print(&was);
+  }
+		       
+  igraph_destroy(&g);
+
+  /******************************************/
+  /* Undirected graph                       */
+  /******************************************/
+
+  igraph_create(&g, &v, 0, IGRAPH_UNDIRECTED);
+
+  /* Simple test, all neighbors */
+  for (i=0; i<=igraph_vector_max(&v); i++) {
+    igraph_vector_clear(&was);
+    igraph_es_adj(&g, &it, i, IGRAPH_ALL);
+    igraph_es_size(&g, &it, &size);
+    printf("%ld\n", (long)size);
+    while (!igraph_es_end(&g, &it)) {
+      igraph_vector_push_back(&was, igraph_es_adj_vertex(&g, &it));
+      igraph_es_next(&g, &it);
+    }
+    igraph_es_destroy(&it);
+    igraph_vector_sort(&was);
+    igraph_vector_print(&was);
+  }
+
+  igraph_destroy(&g);
+  igraph_vector_destroy(&was);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_es_adj.out b/examples/simple/igraph_es_adj.out
new file mode 100644
index 0000000..bfc147b
--- /dev/null
+++ b/examples/simple/igraph_es_adj.out
@@ -0,0 +1,38 @@
+1
+1
+2
+0 2
+5
+1 2 2 3 4 
+2
+2 4 
+2
+2 3 
+1
+1 
+1
+2 
+3
+2 3 4 
+1
+4 
+
+
+1
+0 
+2
+1 2 
+1
+2 
+2
+2 3 
+1
+1 
+2
+0 2 
+5
+1 2 2 3 4 
+2
+2 4 
+2
+2 3 
diff --git a/examples/simple/igraph_es_fromto.c b/examples/simple/igraph_es_fromto.c
new file mode 100644
index 0000000..32a8f73
--- /dev/null
+++ b/examples/simple/igraph_es_fromto.c
@@ -0,0 +1,74 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void igraph_vector_print(const igraph_vector_t *v) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    printf("%li ", (long int)VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int main() {
+  
+  igraph_t g;
+  const igraph_vector_t v=IGRAPH_VECTOR_NULL;
+  igraph_real_t edges1[] = { 0,1, 1,2, 2,2, 2,3, 2,4, 3,4 };
+  igraph_vector_t from, to;  
+  igraph_es_t it;
+  igraph_integer_t size;
+  long int i;
+
+  igraph_vector_view(&v, edges1, sizeof(edges1)/sizeof(igraph_real_t));
+
+  /******************************************/
+  /* Directed graph                         */
+  /******************************************/
+  
+  igraph_create(&g, &v, 0, IGRAPH_DIRECTED);
+  
+  /* {0,1} -> {2,3}, result should be { 1->2 } */
+  igraph_vector_init(&from, 2); VECTOR(from)[0]=0; VECTOR(from)[1]=1;
+  igraph_vector_init(&to, 2);   VECTOR(to)  [0]=2; VECTOR(to)  [1]=3;
+  igraph_es_fromto(&g, &it, IGRAPH_VS_VECTOR(&g, &from), 
+		   IGRAPH_VS_VECTOR(&g, &to), IGRAPH_DIRECTED);
+  igraph_vector_clear(&from); igraph_vector_clear(&to);
+  igraph_es_size(&g, &it, &size);
+  printf("%ld\n", (long)size);
+  while (!igraph_es_end(&g, &it)) {
+    igraph_vector_push_back(&from, igraph_es_from(&g, &it));
+    igraph_vector_push_back(&to, igraph_es_to(&g, &it));
+    igraph_es_next(&g, &it);
+  }
+  igraph_vector_sort(&from); igraph_vector_sort(&to);
+  igraph_vector_print(&from); igraph_vector_print(&to);
+
+  igraph_es_destroy(&it);
+
+  igraph_vector_destroy(&from);
+  igraph_vector_destroy(&to);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_es_fromto.out b/examples/simple/igraph_es_fromto.out
new file mode 100644
index 0000000..d056bbd
--- /dev/null
+++ b/examples/simple/igraph_es_fromto.out
@@ -0,0 +1,3 @@
+1
+1 
+2 
diff --git a/examples/simple/igraph_es_pairs.c b/examples/simple/igraph_es_pairs.c
new file mode 100644
index 0000000..8c2cff6
--- /dev/null
+++ b/examples/simple/igraph_es_pairs.c
@@ -0,0 +1,78 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  long int i;
+  igraph_integer_t size;
+
+  /* DIRECTED */
+  
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);  
+
+  for (i=0; i<100; i++) {
+    igraph_es_t es;
+    igraph_eit_t it;
+    igraph_es_pairs_small(&es, IGRAPH_DIRECTED, 
+			  0,1,0,2,0,5,0,2,0,3,0,4,0,7,0,9, -1);
+    igraph_eit_create(&g, es, &it);
+    igraph_es_size(&g, &es, &size);
+    IGRAPH_EIT_RESET(it);
+    while (!IGRAPH_EIT_END(it)) {
+      (void) IGRAPH_EIT_GET(it);
+      IGRAPH_EIT_NEXT(it);
+      size--;
+    }
+    if (size != 0) return 1;
+    igraph_eit_destroy(&it);
+    igraph_es_destroy(&es);
+  }
+
+  igraph_destroy(&g);
+
+  /* UNDIRECTED */
+  
+  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
+  
+  for (i=0; i<100; i++) {
+    igraph_es_t es;
+    igraph_eit_t it;
+    igraph_es_pairs_small(&es, IGRAPH_DIRECTED,
+			  0,1,2,0,5,0,0,2,3,0,0,4,7,0,0,9, -1);
+    igraph_eit_create(&g, es, &it);
+    IGRAPH_EIT_RESET(it);
+    while (!IGRAPH_EIT_END(it)) {
+      (void) IGRAPH_EIT_GET(it);
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_eit_destroy(&it);
+    igraph_es_destroy(&es);
+  }
+
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_es_path.c b/examples/simple/igraph_es_path.c
new file mode 100644
index 0000000..7913517
--- /dev/null
+++ b/examples/simple/igraph_es_path.c
@@ -0,0 +1,73 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+#include <stdlib.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_es_t es;
+  igraph_eit_t eit;
+  igraph_integer_t size;
+
+  /* DIRECTED */
+  
+  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0, 1);
+  igraph_es_path_small(&es, IGRAPH_DIRECTED, 0,1,2,3,4,5,6,7,8,9,0,1,2,3, -1);
+  igraph_eit_create(&g, es, &eit);
+  igraph_es_size(&g, &es, &size);
+  while (!IGRAPH_EIT_END(eit)) {
+    long int edge=IGRAPH_EIT_GET(eit);
+    igraph_integer_t from, to;
+    igraph_edge(&g, edge, &from, &to);
+    IGRAPH_EIT_NEXT(eit);
+    size--;
+  }
+  if (size != 0) return 1;
+
+  igraph_eit_destroy(&eit);
+  igraph_es_destroy(&es);
+  igraph_destroy(&g);
+
+  /* UNDIRECTED */
+  
+  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 1);
+  igraph_es_path_small(&es, IGRAPH_DIRECTED, 
+		       0,1,2,3,4,3,2,3,4,5,6,5,4,5,6,7,8,9,0,1,0,9, -1);
+  igraph_eit_create(&g, es, &eit);
+  while (!IGRAPH_EIT_END(eit)) {
+    long int edge=IGRAPH_EIT_GET(eit);
+    igraph_integer_t from, to;
+    igraph_edge(&g, edge, &from, &to);
+    IGRAPH_EIT_NEXT(eit);
+  }
+
+  igraph_eit_destroy(&eit);
+  igraph_es_destroy(&es);
+  igraph_destroy(&g);
+  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_feedback_arc_set.c b/examples/simple/igraph_feedback_arc_set.c
new file mode 100644
index 0000000..f6436d6
--- /dev/null
+++ b/examples/simple/igraph_feedback_arc_set.c
@@ -0,0 +1,74 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <string.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t weights, result;
+  igraph_bool_t dag;
+
+  igraph_vector_init(&result, 0);
+
+  /***********************************************************************/
+  /* Approximation with Eades' method                                    */
+  /***********************************************************************/
+
+  /* Simple unweighted graph */
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
+  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_APPROX_EADES);
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 1;
+  igraph_destroy(&g);
+
+  /* Simple weighted graph */
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
+  igraph_vector_init_int_end(&weights, -1, 1, 1, 3, 1, 1, 1, 1, 1, 1, -1);
+  igraph_feedback_arc_set(&g, &result, &weights, IGRAPH_FAS_APPROX_EADES);
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 2;
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* Simple unweighted graph with loops */
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, 1,1, 4,4, -1);
+  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_APPROX_EADES);
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 3;
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&result);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_feedback_arc_set.out b/examples/simple/igraph_feedback_arc_set.out
new file mode 100644
index 0000000..aeb5a03
--- /dev/null
+++ b/examples/simple/igraph_feedback_arc_set.out
@@ -0,0 +1,3 @@
+2
+1
+2 9 10
diff --git a/examples/simple/igraph_feedback_arc_set_ip.c b/examples/simple/igraph_feedback_arc_set_ip.c
new file mode 100644
index 0000000..2f6d4f3
--- /dev/null
+++ b/examples/simple/igraph_feedback_arc_set_ip.c
@@ -0,0 +1,92 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <string.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t weights, result;
+  igraph_bool_t dag;
+  int retval;
+
+  igraph_vector_init(&result, 0);
+
+  igraph_set_error_handler(&igraph_error_handler_printignore);
+
+  /***********************************************************************/
+  /* Exact solution with integer programming                             */
+  /***********************************************************************/
+
+  /* Simple unweighted graph */
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
+  retval = igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_EXACT_IP);
+  if (retval == IGRAPH_UNIMPLEMENTED)
+    return 77;
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 1;
+  igraph_destroy(&g);
+
+  /* Simple weighted graph */
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
+  igraph_vector_init_int_end(&weights, -1, 1, 1, 3, 1, 1, 1, 1, 1, 1, -1);
+  igraph_feedback_arc_set(&g, &result, &weights, IGRAPH_FAS_EXACT_IP);
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 2;
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* Simple unweighted graph with loops */
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, 1,1, 4,4, -1);
+  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_EXACT_IP);
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 3;
+  igraph_destroy(&g);
+
+  /* Disjoint union of two almost identical graphs */
+  igraph_small(&g, 0, IGRAPH_DIRECTED,
+      0,1, 1,2, 2,0, 2,3,  2,4,  0,4,  4,3,    5,0,  6,5, 1,1, 4,4,
+      7,8, 8,9, 9,7, 9,10, 9,11, 7,11, 11,10, 12,7, 13,12,
+      -1);
+  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_EXACT_IP);
+  igraph_vector_print(&result);
+  igraph_delete_edges(&g, igraph_ess_vector(&result));
+  igraph_is_dag(&g, &dag);
+  if (!dag)
+    return 4;
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&result);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_feedback_arc_set_ip.out b/examples/simple/igraph_feedback_arc_set_ip.out
new file mode 100644
index 0000000..9552ea0
--- /dev/null
+++ b/examples/simple/igraph_feedback_arc_set_ip.out
@@ -0,0 +1,4 @@
+1
+1
+1 9 10
+1 9 10 12
diff --git a/examples/simple/igraph_fisher_yates_shuffle.c b/examples/simple/igraph_fisher_yates_shuffle.c
new file mode 100644
index 0000000..0a4b87d
--- /dev/null
+++ b/examples/simple/igraph_fisher_yates_shuffle.c
@@ -0,0 +1,106 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for the Fisher-Yates shuffle.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <igraph.h>
+#include <time.h>
+
+#define R_INTEGER(a,b) (igraph_rng_get_integer(igraph_rng_default(), (a), (b)))
+#define R_UNIF(a,b) (igraph_rng_get_unif(igraph_rng_default(), (a), (b)))
+
+int main() {
+  igraph_real_t d;
+  igraph_vector_t u, v;
+  int ret;
+  long int i, k, n;
+
+  /********************************
+   * Example usage
+   ********************************/
+
+  /* Sequences with one element. Such sequences are trivially permuted.
+   * The result of any Fisher-Yates shuffle on a sequence with one element
+   * must be the original sequence itself.
+   */
+  n = 1;
+  igraph_vector_init(&v, n);
+  igraph_rng_seed(igraph_rng_default(), time(0));
+  k = R_INTEGER(-1000, 1000);
+  VECTOR(v)[0] = k;
+  igraph_vector_shuffle(&v);
+  if (VECTOR(v)[0] != k) {
+    return 1;
+  }
+  d = R_UNIF(-1000.0, 1000.0);
+
+  VECTOR(v)[0] = d;
+  igraph_vector_shuffle(&v);
+  if (VECTOR(v)[0] != d) {
+    return 2;
+  }
+  igraph_vector_destroy(&v);
+
+  /* Sequences with multiple elements. A Fisher-Yates shuffle of a sequence S
+   * is a random permutation \pi(S) of S. Thus \pi(S) must have the same
+   * length and elements as the original sequence S. A major difference between
+   * S and its random permutation \pi(S) is that the order in which elements
+   * appear in \pi(S) is probably different from how elements are ordered in S.
+   * If S has length n = 1, then both \pi(S) and S are equivalent sequences in
+   * that \pi(S) is merely S and no permutation has taken place. If S has
+   * length n > 1, then there are n! possible permutations of S. Assume that
+   * each such permutation is equally likely to appear as a result of the
+   * Fisher-Yates shuffle. As n increases, the probability that S is different
+   * from \pi(S) also increases. We have a probability of 1 / n! that S and
+   * \pi(S) are equivalent sequences.
+   */
+  n = 100;
+  igraph_vector_init(&u, n);
+  igraph_vector_init(&v, n);
+
+  for (i = 0; i < n; i++) {
+    k = R_INTEGER(-1000, 1000);
+    VECTOR(u)[i] = k;
+    VECTOR(v)[i] = k;
+  }
+
+  igraph_vector_shuffle(&v);
+  /* must have same length */
+  if (igraph_vector_size(&v) != n) {
+    return 3;
+  }
+  if (igraph_vector_size(&u) != igraph_vector_size(&v)) {
+    return 4;
+  }
+  /* must have same elements */
+  igraph_vector_sort(&u);
+  igraph_vector_sort(&v);
+  if (!igraph_vector_all_e(&u, &v)) {
+    return 5;
+  }
+  igraph_vector_destroy(&u);
+  igraph_vector_destroy(&v);
+
+  /* empty sequence */
+  igraph_vector_init(&v, 0);
+  ret = igraph_vector_shuffle(&v);
+  igraph_vector_destroy(&v);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_full.c b/examples/simple/igraph_full.c
new file mode 100644
index 0000000..2ec90b1
--- /dev/null
+++ b/examples/simple/igraph_full.c
@@ -0,0 +1,29 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  return 0;
+}
diff --git a/examples/simple/igraph_get_all_shortest_paths_dijkstra.c b/examples/simple/igraph_get_all_shortest_paths_dijkstra.c
new file mode 100644
index 0000000..25e80d3
--- /dev/null
+++ b/examples/simple/igraph_get_all_shortest_paths_dijkstra.c
@@ -0,0 +1,173 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include <stdlib.h>
+
+void check_nrgeo(igraph_t *graph, igraph_vs_t vs,
+                 igraph_vector_ptr_t* paths,
+                 igraph_vector_t* nrgeo) {
+  long int i, n;
+  igraph_vector_t nrgeo2, *path;
+  igraph_vit_t vit;
+
+  n = igraph_vcount(graph);
+  igraph_vector_init(&nrgeo2, n);
+  if (igraph_vector_size(nrgeo) != n) {
+    printf("nrgeo vector length must be %ld, was %ld", n,
+        igraph_vector_size(nrgeo));
+    return;
+  }
+
+  n = igraph_vector_ptr_size(paths);
+  for (i = 0; i < n; i++) {
+    path = VECTOR(*paths)[i];
+    if (path == 0) {
+      printf("Null path found in result vector at index %ld\n", i);
+      return;
+    }
+    if (igraph_vector_size(path) == 0) {
+      printf("Empty path found in result vector at index %ld\n", i);
+      return;
+    }
+    VECTOR(nrgeo2)[(long int)igraph_vector_tail(path)] += 1;
+  }
+
+  igraph_vit_create(graph, vs, &vit);
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    long int node = IGRAPH_VIT_GET(vit);
+    if (VECTOR(*nrgeo)[node] - VECTOR(nrgeo2)[node]) {
+      printf("nrgeo[%ld] invalid, observed = %ld, expected = %ld\n",
+          node, (long int)VECTOR(*nrgeo)[node], (long int)VECTOR(nrgeo2)[node]);
+    }
+  }
+  igraph_vit_destroy(&vit);
+
+  igraph_vector_destroy(&nrgeo2);
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_ptr_t res;
+  long int i;
+  igraph_real_t weights[] = { 1, 2, 3, 4, 5, 1, 1, 1, 1, 1 }; 
+  igraph_real_t weights2[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
+  igraph_real_t dim[] = { 4, 4 };
+
+  igraph_vector_t weights_vec, dim_vec, nrgeo;
+  igraph_vs_t vs;
+
+  igraph_vector_init(&nrgeo, 0);
+
+  /* Simple ring graph without weights */
+
+  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 1);
+  
+  igraph_vector_ptr_init(&res, 5);
+  igraph_vs_vector_small(&vs, 1, 3, 4, 5, 2, 1,  -1);
+  
+  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ &res, 
+				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
+				     /*weights=*/ 0, /*mode=*/ IGRAPH_OUT);
+  check_nrgeo(&g, vs, &res, &nrgeo);
+
+  for (i=0; i<igraph_vector_ptr_size(&res); i++) {
+    igraph_vector_print(VECTOR(res)[i]);
+    igraph_vector_destroy(VECTOR(res)[i]);
+    free(VECTOR(res)[i]);
+    VECTOR(res)[i] = 0;
+  }
+
+  /* Same ring, but with weights */
+
+  igraph_vector_view(&weights_vec, weights, sizeof(weights)/sizeof(igraph_real_t));
+  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ &res, 
+				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
+				     /*weights=*/ &weights_vec, /*mode=*/ IGRAPH_OUT);
+  check_nrgeo(&g, vs, &res, &nrgeo);
+  
+  for (i=0; i<igraph_vector_ptr_size(&res); i++) {
+    igraph_vector_print(VECTOR(res)[i]);
+    igraph_vector_destroy(VECTOR(res)[i]);
+    free(VECTOR(res)[i]);
+    VECTOR(res)[i] = 0;
+  }
+
+  igraph_destroy(&g);
+
+  /* More complicated example */
+
+  igraph_small(&g, 10, IGRAPH_DIRECTED, 
+	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
+	       2,3, 2,6,         3,2, 3,6,
+	       4,5, 4,7,         5,6, 5,8, 5,9,
+	       7,5, 7,8,         8,9,
+	       5,2,
+	       2,1,
+	       -1);
+  
+  igraph_vector_view(&weights_vec, weights2, sizeof(weights2)/sizeof(igraph_real_t));
+  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ &res, 
+				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
+				     /*weights=*/ &weights_vec, /*mode=*/ IGRAPH_OUT);
+
+  check_nrgeo(&g, vs, &res, &nrgeo);
+
+  for (i=0; i<igraph_vector_ptr_size(&res); i++) {
+    igraph_vector_print(VECTOR(res)[i]);
+    igraph_vector_destroy(VECTOR(res)[i]);
+    free(VECTOR(res)[i]);
+    VECTOR(res)[i] = 0;
+  }
+
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+
+  /* Regular lattice with some heavyweight edges */
+  igraph_vector_view(&dim_vec, dim, sizeof(dim)/sizeof(igraph_real_t));
+  igraph_lattice(&g, &dim_vec, 1, 0, 0, 0);
+  igraph_vs_vector_small(&vs, 3, 12, 15, -1);
+  igraph_vector_init(&weights_vec, 24);
+  igraph_vector_fill(&weights_vec, 1);
+  VECTOR(weights_vec)[2] = 100; VECTOR(weights_vec)[8] = 100; /* 1-->2, 4-->8 */
+  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ 0,
+				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
+				     /*weights=*/ &weights_vec, /*mode=*/ IGRAPH_OUT);
+  igraph_vector_destroy(&weights_vec);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+
+  printf("%ld ", (long int)VECTOR(nrgeo)[3]);
+  printf("%ld ", (long int)VECTOR(nrgeo)[12]);
+  printf("%ld\n", (long int)VECTOR(nrgeo)[15]);
+
+  igraph_vector_ptr_destroy(&res);
+  igraph_vector_destroy(&nrgeo);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_get_all_shortest_paths_dijkstra.out b/examples/simple/igraph_get_all_shortest_paths_dijkstra.out
new file mode 100644
index 0000000..afdcdc0
--- /dev/null
+++ b/examples/simple/igraph_get_all_shortest_paths_dijkstra.out
@@ -0,0 +1,19 @@
+0 1
+0 1 2
+0 1 2 3
+0 1 2 3 4
+0 9 8 7 6 5
+0 1 2 3 4 5
+0 1
+0 1 2
+0 1 2 3
+0 9 8 7 6 5 4
+0 1 2 3 4
+0 9 8 7 6 5
+0 1
+0 1 2
+0 3
+0 1 2 3
+0 1 4
+0 1 5
+4 4 12
diff --git a/examples/simple/igraph_get_eid.c b/examples/simple/igraph_get_eid.c
new file mode 100644
index 0000000..a0fa417
--- /dev/null
+++ b/examples/simple/igraph_get_eid.c
@@ -0,0 +1,160 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  igraph_t g;
+  igraph_integer_t eid;
+  igraph_vector_t hist;
+  long int i;
+  int ret;
+
+  /* DIRECTED */
+
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
+
+  igraph_vector_init(&hist, 9);
+
+  for (i=1; i<10; i++) {
+    igraph_get_eid(&g, &eid, 0, i, IGRAPH_DIRECTED, /*error=*/ 1);
+    VECTOR(hist)[ (long int) eid ] = 1;
+  }
+  print_vector(&hist, stdout);
+  
+  igraph_vector_destroy(&hist);
+  igraph_destroy(&g);
+
+  /* UNDIRECTED */
+
+  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
+  
+  igraph_vector_init(&hist, 9);
+
+  for (i=1; i<10; i++) {
+    igraph_get_eid(&g, &eid, 0, i, IGRAPH_UNDIRECTED, /*error=*/ 1);
+    VECTOR(hist)[ (long int) eid ] += 1;
+    igraph_get_eid(&g, &eid, i, 0, IGRAPH_DIRECTED, /*error=*/ 1);
+    VECTOR(hist)[ (long int) eid ] += 1;
+  }
+  print_vector(&hist, stdout);
+  
+  igraph_vector_destroy(&hist);
+  igraph_destroy(&g);
+
+  /* NON-EXISTANT EDGE */
+  
+  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
+
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  
+  ret=igraph_get_eid(&g, &eid, 5, 6, IGRAPH_UNDIRECTED, /*error=*/ 1);
+  if (ret != IGRAPH_EINVAL) {
+    return 1;
+  }
+  
+  igraph_destroy(&g);
+
+  return 0;
+}
+
+/* Stress test */
+
+/* int main() { */
+
+/*   igraph_t g; */
+/*   long int i, n; */
+/*   igraph_integer_t from, to, eid; */
+
+/*   igraph_barabasi_game(&g, 10000, 100, 0, 0, 1); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 1, 1); */
+/*     igraph_get_eid(&g, &eid, to, from, 0, 1); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+
+/*   igraph_barabasi_game(&g, 10000, 100, 0, 0, 0); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*     igraph_get_eid(&g, &eid, to, from, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+
+/*   igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, */
+/* 			  2000, 100.0/2000, 0, 0); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*     igraph_get_eid(&g, &eid, to, from, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+
+/*   igraph_full(&g, 500, 0, 0); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+  
+/*   igraph_star(&g, 20000, IGRAPH_STAR_OUT, 0); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+
+/*   igraph_star(&g, 20000, IGRAPH_STAR_IN, 0); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+
+/*   igraph_star(&g, 2000000, IGRAPH_STAR_UNDIRECTED, 1999999); */
+/*   n=igraph_ecount(&g); */
+/*   for (i=0; i<n; i++) { */
+/*     igraph_edge(&g, i, &from, &to); */
+/*     igraph_get_eid(&g, &eid, from, to, 0, 1); */
+/*     igraph_get_eid(&g, &eid, to, from, 0, 1); */
+/*   } */
+/*   igraph_destroy(&g); */
+    
+/*   return 0; */
+/* } */
diff --git a/examples/simple/igraph_get_eid.out b/examples/simple/igraph_get_eid.out
new file mode 100644
index 0000000..88f234c
--- /dev/null
+++ b/examples/simple/igraph_get_eid.out
@@ -0,0 +1,2 @@
+ 1 1 1 1 1 1 1 1 1
+ 2 2 2 2 2 2 2 2 2
diff --git a/examples/simple/igraph_get_eids.c b/examples/simple/igraph_get_eids.c
new file mode 100644
index 0000000..22024bb
--- /dev/null
+++ b/examples/simple/igraph_get_eids.c
@@ -0,0 +1,216 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int check_simple() {
+
+  igraph_t g;
+  long int nodes=100;
+  long int edges=1000;
+  igraph_real_t p=3.0/nodes;
+  long int runs=10;
+  long int r, e, ecount;
+  igraph_vector_t eids, pairs, path;
+
+  srand(time(0));
+
+  igraph_vector_init(&pairs, edges*2);
+  igraph_vector_init(&path, 0);
+  igraph_vector_init(&eids, 0);
+
+  for (r=0; r<runs; r++) {
+    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, nodes, p, 
+			    /*directed=*/ 0, /*loops=*/ 0);
+    ecount=igraph_ecount(&g);
+    for (e=0; e<edges; e++) {
+      long int edge=RNG_INTEGER(0, ecount-1);
+      VECTOR(pairs)[2*e] = IGRAPH_FROM(&g, edge);
+      VECTOR(pairs)[2*e+1] = IGRAPH_TO(&g, edge);
+    }
+    igraph_get_eids(&g, &eids, &pairs, /*path=*/ 0, 0, /*error=*/ 1);
+    for (e=0; e<edges; e++) {
+      long int edge=VECTOR(eids)[e];
+      long int from1=VECTOR(pairs)[2*e];
+      long int to1=VECTOR(pairs)[2*e+1];
+      long int from2=IGRAPH_FROM(&g, edge);
+      long int to2=IGRAPH_TO(&g, edge);
+      long int min1= from1 < to1 ? from1 : to1;
+      long int max1= from1 < to1 ? to1 : from1;
+      long int min2= from2 < to2 ? from2 : to2;
+      long int max2= from2 < to2 ? to2 : from2;
+      if (min1 != min2 || max1 != max2) {
+	return 11;
+      }
+    }
+    
+    igraph_diameter(&g, /*res=*/ 0, /*from=*/ 0, /*to=*/ 0, &path,
+		    IGRAPH_UNDIRECTED, /*unconn=*/ 1);
+    igraph_get_eids(&g, &eids, /*pairs=*/ 0, &path, 0, /*error=*/ 1);
+    for (e=0; e<igraph_vector_size(&path)-1; e++) {
+      long int edge=VECTOR(eids)[e];
+      long int from1=VECTOR(path)[e];
+      long int to1=VECTOR(path)[e+1];
+      long int from2=IGRAPH_FROM(&g, edge);
+      long int to2=IGRAPH_TO(&g, edge);
+      long int min1= from1 < to1 ? from1 : to1;
+      long int max1= from1 < to1 ? to1 : from1;
+      long int min2= from2 < to2 ? from2 : to2;
+      long int max2= from2 < to2 ? to2 : from2;
+      if (min1 != min2 || max1 != max2) {
+	return 12;
+      }
+    }
+
+    igraph_destroy(&g);
+  }
+
+  igraph_vector_destroy(&path);
+  igraph_vector_destroy(&pairs);
+  igraph_vector_destroy(&eids);
+
+  return 0;
+}
+
+int check_multi() {
+
+  igraph_t g;
+  igraph_vector_t vec;
+  igraph_vector_t eids, eids2;
+  int ret;
+  long int i;
+
+  igraph_real_t q1[] = { 0,1, 0,1 };
+  igraph_real_t q2[] = { 0,1, 0,1, 0,1 };
+  igraph_real_t q3[] = { 1,0, 3,4, 1,0, 0,1, 3,4, 0,1 };
+
+  igraph_vector_init(&eids, 0);
+
+  /*********************************/
+  igraph_small(&g, /*n=*/ 10, /*directed=*/ 1, 
+	       0,1, 0,1, 1,0, 1,2, 3,4, 3,4, 3,4, 3,5, 3,7, 
+	       9,8,
+	       -1);
+
+  igraph_vector_view(&vec, q1, sizeof(q1) / sizeof(igraph_real_t));
+  igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/ 1, /*error=*/ 1);
+  igraph_vector_sort(&eids);
+  print_vector(&eids, stdout);
+
+  igraph_vector_view(&vec, q2, sizeof(q2) / sizeof(igraph_real_t));
+  igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/ 0, /*error=*/ 1);
+  igraph_vector_sort(&eids);
+  print_vector(&eids, stdout);
+
+  igraph_vector_view(&vec, q2, sizeof(q2) / sizeof(igraph_real_t));
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/ 1, /*error=*/1);
+  if (ret != IGRAPH_EINVAL) { return 1; } 
+  igraph_set_error_handler(igraph_error_handler_abort);
+
+  igraph_destroy(&g);
+  /*********************************/
+
+  /*********************************/
+  igraph_small(&g, /*n=*/10, /*directed=*/0, 
+	       0,1, 1,0, 0,1, 3,4, 3,4, 5,4, 9,8, 
+	       -1);
+  
+  igraph_vector_view(&vec, q1, sizeof(q1) / sizeof(igraph_real_t));
+  igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/1, /*error=*/ 1);
+  igraph_vector_sort(&eids);
+  print_vector(&eids, stdout);
+
+  igraph_vector_view(&vec, q3, sizeof(q3) / sizeof(igraph_real_t));
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/0, /*error=*/ 1);
+  if (ret != IGRAPH_EINVAL) { return 2; }
+  igraph_set_error_handler(igraph_error_handler_abort);
+  
+  igraph_destroy(&g);
+
+  /*********************************/
+
+  igraph_vector_destroy(&eids);
+
+  /*********************************/
+  /* Speed tests */
+
+#define NODES 10000
+  igraph_barabasi_game(&g, /*n=*/ NODES, /*power=*/ 1.0, /*m=*/ 3, 
+		       /*outseq=*/ 0, /*outpref=*/ 0, /*A=*/ 1,
+		       /*directed=*/ 1, IGRAPH_BARABASI_BAG,
+		       /*start_from=*/ 0);
+  igraph_simplify(&g, /*multiple=*/ 1, /*loops=*/ 0, /*edge_comb=*/ 0);
+
+  igraph_vector_init(&eids, NODES/2);
+  igraph_random_sample(&eids, 0, igraph_ecount(&g)-1, NODES/2);
+  igraph_vector_init(&vec, NODES);
+  for (i=0; i<NODES/2; i++) {
+    VECTOR(vec)[2*i]   = IGRAPH_FROM(&g, VECTOR(eids)[i]);
+    VECTOR(vec)[2*i+1] = IGRAPH_TO(&g, VECTOR(eids)[i]);
+  }
+  igraph_vector_init(&eids2, 0);
+  igraph_get_eids_multi(&g, &eids2, &vec, 0, /*directed=*/ 1, /*error=*/ 1);
+  if (!igraph_vector_all_e(&eids, &eids2)) {
+    return 3;
+  }
+
+  /**/
+
+  for (i=0; i<NODES/2; i++) {
+    VECTOR(vec)[2*i]   = IGRAPH_TO(&g, VECTOR(eids)[i]);
+    VECTOR(vec)[2*i+1] = IGRAPH_FROM(&g, VECTOR(eids)[i]);
+  }
+  igraph_get_eids_multi(&g, &eids2, &vec, 0, /*directed=*/ 0, /*error=*/ 1);
+  if (!igraph_vector_all_e(&eids, &eids2)) {
+    return 4;
+  }
+
+  igraph_vector_destroy(&eids);
+  igraph_vector_destroy(&eids2);
+  igraph_vector_destroy(&vec);
+  igraph_destroy(&g);
+		  
+  /*********************************/
+
+  return 0;
+}
+
+int main() {
+  int ret;
+
+  if ( (ret=check_simple()) != 0) { return ret; }
+  if ( (ret=check_multi()) != 0)  { return ret; }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_get_eids.out b/examples/simple/igraph_get_eids.out
new file mode 100644
index 0000000..38387c5
--- /dev/null
+++ b/examples/simple/igraph_get_eids.out
@@ -0,0 +1,3 @@
+ 0 1
+ 0 1 2
+ 1 2
diff --git a/examples/simple/igraph_get_shortest_paths.c b/examples/simple/igraph_get_shortest_paths.c
new file mode 100644
index 0000000..e9eaf4c
--- /dev/null
+++ b/examples/simple/igraph_get_shortest_paths.c
@@ -0,0 +1,121 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, l=igraph_vector_size(v);
+  for (i=0; i<l; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int check_evecs(const igraph_t *graph, const igraph_vector_ptr_t *vecs,
+		const igraph_vector_ptr_t *evecs, int error_code) {
+
+  igraph_bool_t directed=igraph_is_directed(graph);
+  long int i, n=igraph_vector_ptr_size(vecs);
+  if (igraph_vector_ptr_size(evecs) != n) { exit(error_code+1); }
+  
+  for (i=0; i<n; i++) {
+    igraph_vector_t *vvec=VECTOR(*vecs)[i];
+    igraph_vector_t *evec=VECTOR(*evecs)[i];
+    long int j, n2=igraph_vector_size(evec);
+    if (igraph_vector_size(vvec) == 0 && n2==0) { continue; }
+    if (igraph_vector_size(vvec) != n2+1) { exit(error_code+2); }
+    for (j=0; j<n2; j++) {
+      long int edge=VECTOR(*evec)[j];
+      long int from=VECTOR(*vvec)[j];
+      long int to=VECTOR(*vvec)[j+1];
+      if (directed) {
+	if (from != IGRAPH_FROM(graph, edge) ||
+	    to   != IGRAPH_TO  (graph, edge)) {
+	  exit(error_code);
+	}
+      } else {
+	long int from2=IGRAPH_FROM(graph, edge);
+	long int to2=IGRAPH_TO(graph, edge);
+	long int min1= from < to ? from : to;
+	long int max1= from < to ? to : from;
+	long int min2= from2 < to2 ? from2 : to2;
+	long int max2= from2 < to2 ? to2 : from2;
+	if (min1 != min2 || max1 != max2) { exit(error_code+3); }
+      }
+    }
+  }
+
+  return 0;
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_ptr_t vecs, evecs;
+  igraph_vector_long_t pred, inbound;
+  long int i;
+  igraph_vs_t vs;
+
+  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0, 1);
+  
+  igraph_vector_ptr_init(&vecs, 5);
+  igraph_vector_ptr_init(&evecs, 5);
+  igraph_vector_long_init(&pred, 0);
+  igraph_vector_long_init(&inbound, 0);
+
+  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
+    VECTOR(vecs)[i] = calloc(1, sizeof(igraph_vector_t));
+    igraph_vector_init(VECTOR(vecs)[i], 0);
+    VECTOR(evecs)[i] = calloc(1, sizeof(igraph_vector_t));
+    igraph_vector_init(VECTOR(evecs)[i], 0);
+  }
+  igraph_vs_vector_small(&vs, 1, 3, 5, 2, 1,  -1);
+  
+  igraph_get_shortest_paths(&g, &vecs, &evecs, 0, vs, IGRAPH_OUT, &pred, &inbound);
+
+  check_evecs(&g, &vecs, &evecs, 10);
+  
+  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
+    print_vector(VECTOR(vecs)[i]);
+    igraph_vector_destroy(VECTOR(vecs)[i]);
+    free(VECTOR(vecs)[i]);
+    igraph_vector_destroy(VECTOR(evecs)[i]);
+    free(VECTOR(evecs)[i]);
+  }
+
+  igraph_vector_long_print(&pred);
+  igraph_vector_long_print(&inbound);
+
+  igraph_vector_ptr_destroy(&vecs);
+  igraph_vector_ptr_destroy(&evecs);
+  igraph_vector_long_destroy(&pred);
+  igraph_vector_long_destroy(&inbound);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_get_shortest_paths.out b/examples/simple/igraph_get_shortest_paths.out
new file mode 100644
index 0000000..a4a8202
--- /dev/null
+++ b/examples/simple/igraph_get_shortest_paths.out
@@ -0,0 +1,7 @@
+ 0 1
+ 0 1 2 3
+ 0 1 2 3 4 5
+ 0 1 2
+ 0 1
+0 0 1 2 3 4 -1 -1 -1 -1
+-1 0 1 2 3 4 -1 -1 -1 -1
diff --git a/examples/simple/igraph_get_shortest_paths2.c b/examples/simple/igraph_get_shortest_paths2.c
new file mode 100644
index 0000000..5de352f
--- /dev/null
+++ b/examples/simple/igraph_get_shortest_paths2.c
@@ -0,0 +1,84 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  const igraph_real_t edges[] = { 0,1, 0,2, 1,6, 2,6, 1,3, 1,4, 1,5,
+				  3,2, 4,2, 5,2 };
+  igraph_t g;
+  igraph_vector_t edgev;
+  igraph_vector_ptr_t resvertices, resedges;
+  igraph_vector_long_t predecessors, inbound_edges;
+  int vcount, i;
+  
+  igraph_vector_view(&edgev, edges, sizeof(edges)/sizeof(igraph_real_t));
+  vcount=igraph_vector_max(&edgev)+1;
+  igraph_create(&g, &edgev, vcount, IGRAPH_DIRECTED);
+  
+  igraph_vector_ptr_init(&resvertices, vcount);
+  igraph_vector_ptr_init(&resedges, vcount);
+  igraph_vector_long_init(&predecessors, 0);
+  igraph_vector_long_init(&inbound_edges, 0);
+  
+  for (i=0; i<vcount; i++) {
+    igraph_vector_t *v1=malloc(sizeof(igraph_vector_t));
+    igraph_vector_t *v2=malloc(sizeof(igraph_vector_t));
+    if (!v1 || !v2) { 
+      exit(2);
+    }
+    igraph_vector_init(v1, 0);
+    igraph_vector_init(v2, 0);
+    VECTOR(resvertices)[i] = v1;
+    VECTOR(resedges)[i] = v2;
+  }
+
+  igraph_get_shortest_paths(&g, &resvertices, &resedges, /*from=*/ 0, 
+			    /*to=*/ igraph_vss_all(), /*mode=*/ IGRAPH_OUT,
+			    &predecessors, &inbound_edges);
+
+  for (i=0; i<vcount; i++) {
+    igraph_vector_t *v1=VECTOR(resvertices)[i];
+    igraph_vector_t *v2=VECTOR(resedges)[i];
+    printf("%i V: ", i); igraph_vector_print(v1);
+    printf("%i E: ", i); igraph_vector_print(v2);
+  }
+  printf("pred: "); igraph_vector_long_print(&predecessors);
+  printf("inbe: "); igraph_vector_long_print(&inbound_edges);
+
+  igraph_vector_long_destroy(&inbound_edges);
+  igraph_vector_long_destroy(&predecessors);
+  for (i=0; i<vcount; i++) {
+    igraph_vector_t *v1=VECTOR(resvertices)[i];
+    igraph_vector_t *v2=VECTOR(resedges)[i];
+    igraph_vector_destroy(v1);
+    igraph_vector_destroy(v2);
+    igraph_free(v1);
+    igraph_free(v2);
+  }
+  igraph_vector_ptr_destroy(&resedges);
+  igraph_vector_ptr_destroy(&resvertices);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_get_shortest_paths2.out b/examples/simple/igraph_get_shortest_paths2.out
new file mode 100644
index 0000000..664cee5
--- /dev/null
+++ b/examples/simple/igraph_get_shortest_paths2.out
@@ -0,0 +1,16 @@
+0 V: 0
+0 E: 
+1 V: 0 1
+1 E: 0
+2 V: 0 2
+2 E: 1
+3 V: 0 1 3
+3 E: 0 4
+4 V: 0 1 4
+4 E: 0 5
+5 V: 0 1 5
+5 E: 0 6
+6 V: 0 1 6
+6 E: 0 2
+pred: 0 0 0 1 1 1 1
+inbe: -1 0 1 4 5 6 2
diff --git a/examples/simple/igraph_get_shortest_paths_dijkstra.c b/examples/simple/igraph_get_shortest_paths_dijkstra.c
new file mode 100644
index 0000000..4f6000b
--- /dev/null
+++ b/examples/simple/igraph_get_shortest_paths_dijkstra.c
@@ -0,0 +1,214 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, l=igraph_vector_size(v);
+  for (i=0; i<l; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int check_evecs(const igraph_t *graph, const igraph_vector_ptr_t *vecs,
+		const igraph_vector_ptr_t *evecs, int error_code) {
+
+  igraph_bool_t directed=igraph_is_directed(graph);
+  long int i, n=igraph_vector_ptr_size(vecs);
+  if (igraph_vector_ptr_size(evecs) != n) { exit(error_code+1); }
+  
+  for (i=0; i<n; i++) {
+    igraph_vector_t *vvec=VECTOR(*vecs)[i];
+    igraph_vector_t *evec=VECTOR(*evecs)[i];
+    long int j, n2=igraph_vector_size(evec);
+    if (igraph_vector_size(vvec) == 0 && n2==0) { continue; }
+    if (igraph_vector_size(vvec) != n2+1) { exit(error_code+2); }
+    for (j=0; j<n2; j++) {
+      long int edge=VECTOR(*evec)[j];
+      long int from=VECTOR(*vvec)[j];
+      long int to=VECTOR(*vvec)[j+1];
+      if (directed) {
+	if (from != IGRAPH_FROM(graph, edge) ||
+	    to   != IGRAPH_TO  (graph, edge)) {
+	  exit(error_code);
+	}
+      } else {
+	long int from2=IGRAPH_FROM(graph, edge);
+	long int to2=IGRAPH_TO(graph, edge);
+	long int min1= from < to ? from : to;
+	long int max1= from < to ? to : from;
+	long int min2= from2 < to2 ? from2 : to2;
+	long int max2= from2 < to2 ? to2 : from2;
+	if (min1 != min2 || max1 != max2) { exit(error_code+3); }
+      }
+    }
+  }
+
+  return 0;
+}
+
+int check_pred_inbound(const igraph_t* graph, const igraph_vector_long_t* pred,
+        const igraph_vector_long_t* inbound, int start, int error_code) {
+  long int i, n = igraph_vcount(graph);
+
+  if (igraph_vector_long_size(pred) != n ||
+      igraph_vector_long_size(inbound) != n) {
+    exit(error_code);
+  }
+
+  if (VECTOR(*pred)[start] != start || VECTOR(*inbound)[start] != -1)
+    exit(error_code+1);
+
+  for (i = 0; i < n; i++) {
+    if (VECTOR(*pred)[i] == -1) {
+      if (VECTOR(*inbound)[i] != -1) {
+        exit(error_code+2);
+      }
+    } else if (VECTOR(*pred)[i] == i) {
+      if (i != start) {
+        exit(error_code+3);
+      }
+      if (VECTOR(*inbound)[i] != -1) {
+        exit(error_code+4);
+      }
+    } else {
+      long int eid = VECTOR(*inbound)[i];
+      long int u = IGRAPH_FROM(graph, eid), v = IGRAPH_TO(graph, eid);
+      if (v != i && !igraph_is_directed(graph)) {
+        long int dummy = u;
+        u = v; v = dummy;
+      }
+      if (v != i) {
+        exit(error_code+5);
+      } else if (u != VECTOR(*pred)[i]) {
+        exit(error_code+6);
+      }
+    }
+  }
+
+  return 0;
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_ptr_t vecs, evecs;
+  igraph_vector_long_t pred, inbound;
+  long int i;
+  igraph_real_t weights[] = { 1, 2, 3, 4, 5, 1, 1, 1, 1, 1 }; 
+  igraph_real_t weights2[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
+  igraph_vector_t weights_vec;
+  igraph_vs_t vs;
+
+  /* Simple ring graph without weights */
+
+  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 1);
+  
+  igraph_vector_ptr_init(&vecs, 5);
+  igraph_vector_ptr_init(&evecs, 5);
+  igraph_vector_long_init(&pred, 0);
+  igraph_vector_long_init(&inbound, 0);
+
+  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
+    VECTOR(vecs)[i] = calloc(1, sizeof(igraph_vector_t));
+    igraph_vector_init(VECTOR(vecs)[i], 0);
+    VECTOR(evecs)[i] = calloc(1, sizeof(igraph_vector_t));
+    igraph_vector_init(VECTOR(evecs)[i], 0);
+  }
+  igraph_vs_vector_small(&vs, 1, 3, 5, 2, 1,  -1);
+  
+  igraph_get_shortest_paths_dijkstra(&g, /*vertices=*/ &vecs, 
+				     /*edges=*/ &evecs, /*from=*/ 0, /*to=*/ vs, 
+				     /*weights=*/ 0, /*mode=*/ IGRAPH_OUT,
+				     /*predecessors=*/ &pred,
+				     /*inbound_edges=*/ &inbound);
+
+  check_evecs(&g, &vecs, &evecs, 10);
+  check_pred_inbound(&g, &pred, &inbound, /* from= */ 0, 40);
+
+  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
+    print_vector(VECTOR(vecs)[i]);
+  }
+
+  /* Same ring, but with weights */
+
+  igraph_vector_view(&weights_vec, weights, sizeof(weights)/sizeof(igraph_real_t));
+  igraph_get_shortest_paths_dijkstra(&g, /*vertices=*/ &vecs, 
+				     /*edges=*/ &evecs, /*from=*/ 0, /*to=*/ vs, 
+				     &weights_vec, IGRAPH_OUT,
+				     /*predecessors=*/ &pred,
+				     /*inbound_edges=*/ &inbound);
+  
+  check_evecs(&g, &vecs, &evecs, 20);
+  check_pred_inbound(&g, &pred, &inbound, /* from= */ 0, 50);
+
+  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
+    print_vector(VECTOR(vecs)[i]);
+  }
+
+  igraph_destroy(&g);
+
+  /* More complicated example */
+
+  igraph_small(&g, 10, IGRAPH_DIRECTED, 
+	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
+	       2,3, 2,6,         3,2, 3,6,
+	       4,5, 4,7,         5,6, 5,8, 5,9,
+	       7,5, 7,8,         8,9,
+	       5,2,
+	       2,1,
+	       -1);
+  
+  igraph_vector_view(&weights_vec, weights2, sizeof(weights2)/sizeof(igraph_real_t));
+  igraph_get_shortest_paths_dijkstra(&g, /*vertices=*/ &vecs, 
+				     /*edges=*/ &evecs, /*from=*/ 0, /*to=*/ vs, 
+				     &weights_vec, IGRAPH_OUT,
+				     /*predecessors=*/ &pred,
+				     /*inbound_edges=*/ &inbound);
+
+  check_evecs(&g, &vecs, &evecs, 30);
+  check_pred_inbound(&g, &pred, &inbound, /* from= */ 0, 60);
+  
+  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
+    print_vector(VECTOR(vecs)[i]);
+    igraph_vector_destroy(VECTOR(vecs)[i]);
+    free(VECTOR(vecs)[i]);
+    igraph_vector_destroy(VECTOR(evecs)[i]);
+    free(VECTOR(evecs)[i]);
+  }
+
+  igraph_vector_ptr_destroy(&vecs);
+  igraph_vector_ptr_destroy(&evecs);
+  igraph_vector_long_destroy(&pred);
+  igraph_vector_long_destroy(&inbound);
+  
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_get_shortest_paths_dijkstra.out b/examples/simple/igraph_get_shortest_paths_dijkstra.out
new file mode 100644
index 0000000..8a138c4
--- /dev/null
+++ b/examples/simple/igraph_get_shortest_paths_dijkstra.out
@@ -0,0 +1,15 @@
+ 0 1
+ 0 1 2 3
+ 0 1 2 3 4 5
+ 0 1 2
+ 0 1
+ 0 1
+ 0 1 2 3
+ 0 9 8 7 6 5
+ 0 1 2
+ 0 1
+ 0 1
+ 0 3
+ 0 1 5
+ 0 1 2
+ 0 1
diff --git a/examples/simple/igraph_girth.c b/examples/simple/igraph_girth.c
new file mode 100644
index 0000000..40f8c5c
--- /dev/null
+++ b/examples/simple/igraph_girth.c
@@ -0,0 +1,42 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() { 
+  
+  igraph_t g;
+  igraph_integer_t girth;
+  igraph_vector_t v;
+  igraph_real_t chord[] = { 0, 50 };
+  igraph_ring(&g, 100, IGRAPH_UNDIRECTED, 0, 1);
+  igraph_vector_view(&v, chord, sizeof(chord)/sizeof(igraph_real_t));
+  igraph_add_edges(&g, &v, 0);
+  igraph_girth(&g, &girth, 0);
+  if (girth != 51) {
+    return 1;
+  }
+  
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/igraph_gomory_hu_tree.c b/examples/simple/igraph_gomory_hu_tree.c
new file mode 100644
index 0000000..3c6ab5d
--- /dev/null
+++ b/examples/simple/igraph_gomory_hu_tree.c
@@ -0,0 +1,141 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int validate_tree(const igraph_t *graph, const igraph_t *tree,
+    const igraph_vector_t *flow, const igraph_vector_t *capacity) {
+  igraph_integer_t n = igraph_vcount(graph);
+  igraph_vector_t edges;
+  igraph_real_t min_weight, flow_value;
+  long int i, j, k, m;
+
+  if (igraph_vcount(tree) != n) {
+    printf("Gomory-Hu tree should have %ld vertices\n", (long int)n);
+    return IGRAPH_EINVAL;
+  }
+
+  if (igraph_ecount(tree) != n-1) {
+    printf("Gomory-Hu tree should have %ld edges\n", (long int)n-1);
+    return IGRAPH_EINVAL;
+  }
+
+  if (igraph_is_directed(tree)) {
+    printf("Gomory-Hu tree should be undirected\n");
+    return IGRAPH_EINVAL;
+  }
+
+  if (n < 2)
+    return IGRAPH_SUCCESS;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  for (i = 0; i < n; i++) {
+    for (j = i+1; j < n; j++) {
+      IGRAPH_CHECK(igraph_get_shortest_path(tree, 0, &edges, i, j, IGRAPH_ALL));
+      m = igraph_vector_size(&edges);
+      if (m == 0)
+	continue;
+
+      min_weight = VECTOR(*flow)[(long int)VECTOR(edges)[0]];
+      for (k = 1; k < m; k++) {
+	if (VECTOR(*flow)[(long int)VECTOR(edges)[k]] < min_weight) {
+	  min_weight = VECTOR(*flow)[(long int)VECTOR(edges)[k]];
+	}
+      }
+
+      IGRAPH_CHECK(igraph_maxflow(graph, &flow_value, 0, 0, 0, 0, i, j, capacity, 0));
+      if (flow_value != min_weight) {
+	printf("Min weight of path %ld --> %ld in Gomory-Hu tree is %.4f, "
+	    "expected %.4f from flow calculation\n", i, j, min_weight, flow_value);
+	return IGRAPH_EINVAL;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_t tree;
+  igraph_vector_t flow;
+  igraph_vector_t capacity;
+
+  /* initialize flow and capacity vectors */
+  igraph_vector_init(&capacity, 0);
+  igraph_vector_init(&flow, 0);
+
+  /* empty undirected graph */
+  igraph_empty(&g, 0, 0);
+  if (igraph_gomory_hu_tree(&g, &tree, &flow, &capacity)) {
+    return 1;
+  }
+  if (igraph_vcount(&tree) != 0) {
+    return 1;
+  }
+  if (igraph_vector_size(&flow) != 0) {
+    return 1;
+  }
+  igraph_destroy(&tree);
+  igraph_destroy(&g);
+
+  /* simple undirected graph */
+  igraph_small(&g, 6, 0, 0, 1, 0, 2, 1, 2, 1, 3, 1, 4, 2, 4, 3, 4, 3, 5, 4, 5, -1);
+  igraph_vector_resize(&capacity, 9);
+  VECTOR(capacity)[0] = 1; VECTOR(capacity)[1] = 7; VECTOR(capacity)[2] = 1;
+  VECTOR(capacity)[3] = 3; VECTOR(capacity)[4] = 2; VECTOR(capacity)[5] = 4;
+  VECTOR(capacity)[6] = 1; VECTOR(capacity)[7] = 6; VECTOR(capacity)[8] = 2;
+  if (igraph_gomory_hu_tree(&g, &tree, &flow, &capacity)) {
+    return 2;
+  }
+  if (validate_tree(&g, &tree, &flow, &capacity)) {
+    return 2;
+  }
+  igraph_destroy(&tree);
+  /* Make sure we don't blow up without an outgoing flow vector */
+  if (igraph_gomory_hu_tree(&g, &tree, 0, &capacity)) {
+    return 2;
+  }
+  igraph_destroy(&tree);
+  igraph_destroy(&g);
+
+  /* simple directed graph - should throw an error */
+  igraph_small(&g, 6, 1, 0, 1, 0, 2, 1, 2, 1, 3, 1, 4, 2, 4, 3, 4, 3, 5, 4, 5, -1);
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  if (!igraph_gomory_hu_tree(&g, &tree, &flow, &capacity)) {
+    return 3;
+  }
+  igraph_set_error_handler(igraph_error_handler_abort);
+  igraph_destroy(&g);
+
+  /* destroy flow and capacity vectors */
+  igraph_vector_destroy(&flow);
+  igraph_vector_destroy(&capacity);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_grg_game.c b/examples/simple/igraph_grg_game.c
new file mode 100644
index 0000000..78d142c
--- /dev/null
+++ b/examples/simple/igraph_grg_game.c
@@ -0,0 +1,75 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include <unistd.h>
+#include <sys/times.h>
+#include <math.h>
+
+int main() {
+  
+  igraph_t g;
+  /* long int i; */
+  /* struct tms time; */
+  /* clock_t current_time,start_time; */
+  /* long int runs=100, n=10000; */
+  /* igraph_real_t r=0.01; */
+  
+  /* Empty graph */
+  igraph_grg_game(&g, 100, 0, 0, 0, 0);
+  if (igraph_ecount(&g) != 0) {
+    return 1;
+  }
+  igraph_destroy(&g);
+  
+  /* Full graph */
+  igraph_grg_game(&g, 10, sqrt(2.0)/2, 1, 0, 0);
+  if (igraph_ecount(&g) != igraph_vcount(&g) * (igraph_vcount(&g)-1)/2) {
+    return 2;
+  }
+  igraph_destroy(&g);
+
+  /* Measure running time */
+/*   tps=sysconf(_SC_CLK_TCK); // clock ticks per second  */
+/*   times(&time); start_time=time.tms_utime; */
+/*   for (i=0; i<runs; i++) { */
+/*     igraph_grg_game2(&g, n, r, 1);  */
+/*     igraph_destroy(&g); */
+/*   } */
+/*   times(&time); current_time=time.tms_utime; */
+/*   fprintf(stdout,"    sorted: time=%.3fs\n",(current_time-start_time)/(double)tps); */
+
+/*   tps=sysconf(_SC_CLK_TCK); // clock ticks per second  */
+/*   times(&time); start_time=time.tms_utime; */
+/*   for (i=0; i<runs; i++) { */
+/*     igraph_grg_game(&g, n, r, 1); */
+/*     igraph_destroy(&g); */
+/*   } */
+/*   times(&time); current_time=time.tms_utime; */
+/*   fprintf(stdout,"non-sorted: time=%.3fs\n", */
+/* 	  (current_time-start_time)/(double)tps); */
+
+
+  return 0;
+}
diff --git a/examples/simple/igraph_growing_random_game.c b/examples/simple/igraph_growing_random_game.c
new file mode 100644
index 0000000..2ec90b1
--- /dev/null
+++ b/examples/simple/igraph_growing_random_game.c
@@ -0,0 +1,29 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  return 0;
+}
diff --git a/examples/simple/igraph_has_multiple.c b/examples/simple/igraph_has_multiple.c
new file mode 100644
index 0000000..6672219
--- /dev/null
+++ b/examples/simple/igraph_has_multiple.c
@@ -0,0 +1,86 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_bool_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_bool_size(v); i++) {
+    fprintf(f, " %i", (int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_t graph;
+  igraph_bool_t res;
+  
+  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 0,1, 1,0, 3,4, 11,10, -1);
+  igraph_has_multiple(&graph, &res);
+  if (!res)
+    return 1;
+  igraph_destroy(&graph);
+  
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
+	       0,0, 1,2, 1,1, 2,2, 2,1, 2,3, 2,4, 
+	       2,5, 2,6, 2,2, 3,2, 0,0, 6,2, 2,2, 0,0, -1);
+  igraph_has_multiple(&graph, &res);
+  if (!res)
+    return 2;
+  igraph_destroy(&graph);
+
+  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 1,0, 3,4, 11,10, -1);
+  igraph_has_multiple(&graph, &res);
+  if (res)
+    return 3;
+  igraph_destroy(&graph);
+  
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
+	       0,0, 1,2, 1,1, 2,2, 2,3, 2,4, 2,5, 2,6, 2,2, -1);
+  igraph_has_multiple(&graph, &res);
+  if (!res)
+    return 4;
+  igraph_destroy(&graph);
+
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
+	       0,0, 1,2, 1,1, 2,2, 2,3, 2,4, 2,5, 2,6, -1);
+  igraph_has_multiple(&graph, &res);
+  if (res)
+    return 5;
+  igraph_destroy(&graph);
+
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED, 0,1, 0,1, 1,2, -1);
+  igraph_has_multiple(&graph, &res);
+  if (!res)
+    return 6;
+  igraph_destroy(&graph);
+
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED, 0,0, 0,0, -1);
+  igraph_has_multiple(&graph, &res);
+  if (!res)
+    return 7;
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_hashtable.c b/examples/simple/igraph_hashtable.c
new file mode 100644
index 0000000..0a482fc
--- /dev/null
+++ b/examples/simple/igraph_hashtable.c
@@ -0,0 +1,131 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_types_internal.h>
+
+int main() {
+
+  igraph_hashtable_t ht;
+  char *str;
+  const igraph_strvector_t *keys;
+  long int i;
+
+  /* init and destroy */
+  igraph_hashtable_init(&ht);
+  igraph_hashtable_destroy(&ht);
+
+  /* init, add some elements and destroy */
+  igraph_hashtable_init(&ht);
+  igraph_hashtable_addset(&ht, "color", "green", "red");
+  igraph_hashtable_addset(&ht, "size", "", "4");
+  igraph_hashtable_addset(&ht, "color", "", "grey");
+  igraph_hashtable_addset(&ht, "shape", "", "circle");
+  igraph_hashtable_addset(&ht, "shape", "", "diamond");
+  igraph_hashtable_destroy(&ht);
+
+  /* reset */
+  igraph_hashtable_init(&ht);
+  igraph_hashtable_addset(&ht, "color", "green", "red");
+  igraph_hashtable_addset(&ht, "size", "", "4");
+  igraph_hashtable_addset(&ht, "color", "", "grey");
+  igraph_hashtable_addset(&ht, "shape", "", "circle");
+  igraph_hashtable_addset(&ht, "shape", "", "diamond");
+  igraph_hashtable_reset(&ht);
+  igraph_hashtable_addset(&ht, "color", "green", "red");
+  igraph_hashtable_addset(&ht, "size", "", "4");
+  igraph_hashtable_addset(&ht, "color", "", "grey");
+  igraph_hashtable_addset(&ht, "shape", "", "circle");
+  igraph_hashtable_addset(&ht, "shape", "", "diamond");
+  igraph_hashtable_destroy(&ht);
+
+  /* Check semantics */
+  igraph_hashtable_init(&ht);
+  igraph_hashtable_addset(&ht, "color", "green", "red");
+  igraph_hashtable_addset(&ht, "size", "", "4");
+  igraph_hashtable_addset(&ht, "color", "", "grey");
+  igraph_hashtable_addset(&ht, "shape", "", "circle");
+  igraph_hashtable_addset(&ht, "shape", "", "diamond");
+  
+  igraph_hashtable_get(&ht, "color", &str);
+  printf("color: %s\n", str);
+  igraph_hashtable_get(&ht, "size", &str);
+  printf("size: %s\n", str);
+  igraph_hashtable_get(&ht, "shape", &str);
+  printf("shape: %s\n", str);
+  
+  igraph_hashtable_reset(&ht);
+
+  igraph_hashtable_get(&ht, "color", &str);
+  printf("color: %s\n", str);
+  igraph_hashtable_get(&ht, "size", &str);
+  printf("size: %s\n", str);
+  igraph_hashtable_get(&ht, "shape", &str);
+  printf("shape: %s\n", str);
+  
+  igraph_hashtable_getkeys(&ht, &keys);
+  for (i=0; i<igraph_strvector_size(keys); i++) {
+    igraph_strvector_get(keys, i, &str);
+    printf("%s ", str);
+  }
+  printf("\n");
+  
+  igraph_hashtable_destroy(&ht);
+
+  /* addset2 */
+  igraph_hashtable_init(&ht);
+  igraph_hashtable_addset2(&ht, "color", "green", "redddd", 3);
+  igraph_hashtable_addset2(&ht, "size", "", "4111", 1);
+  igraph_hashtable_addset2(&ht, "color", "", "greysdsdf", 4);
+  igraph_hashtable_addset2(&ht, "shape", "", "circle", 6);
+  igraph_hashtable_addset(&ht, "shape", "", "diamond");
+  
+  igraph_hashtable_get(&ht, "color", &str);
+  printf("color: %s\n", str);
+  igraph_hashtable_get(&ht, "size", &str);
+  printf("size: %s\n", str);
+  igraph_hashtable_get(&ht, "shape", &str);
+  printf("shape: %s\n", str);
+  
+  igraph_hashtable_reset(&ht);
+
+  igraph_hashtable_get(&ht, "color", &str);
+  printf("color: %s\n", str);
+  igraph_hashtable_get(&ht, "size", &str);
+  printf("size: %s\n", str);
+  igraph_hashtable_get(&ht, "shape", &str);
+  printf("shape: %s\n", str);
+  
+  igraph_hashtable_getkeys(&ht, &keys);
+  for (i=0; i<igraph_strvector_size(keys); i++) {
+    igraph_strvector_get(keys, i, &str);
+    printf("%s ", str);
+  }
+  printf("\n");
+  
+  igraph_hashtable_destroy(&ht);
+  
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_hashtable.out b/examples/simple/igraph_hashtable.out
new file mode 100644
index 0000000..860d505
--- /dev/null
+++ b/examples/simple/igraph_hashtable.out
@@ -0,0 +1,14 @@
+color: grey
+size: 4
+shape: diamond
+color: green
+size: 
+shape: 
+color size shape 
+color: grey
+size: 4
+shape: diamond
+color: green
+size: 
+shape: 
+color size shape 
diff --git a/examples/simple/igraph_hrg.c b/examples/simple/igraph_hrg.c
new file mode 100644
index 0000000..2241b8d
--- /dev/null
+++ b/examples/simple/igraph_hrg.c
@@ -0,0 +1,73 @@
+/* -*- mode: C++ -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main() {
+  igraph_t graph;
+  igraph_t full, tree;
+  igraph_hrg_t hrg;
+  igraph_t dendrogram;
+  // int i, j;
+  // igraph_vector_t neis;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  // We need attributes
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+  
+  igraph_full(&full, 10, /*directed=*/ 0, /*loops=*/ 0);
+  igraph_tree(&tree, 15, /*children=*/ 2, /*type=*/ IGRAPH_TREE_UNDIRECTED);
+  igraph_disjoint_union(&graph, &full, &tree);
+  igraph_add_edge(&graph, 0, 10);
+  
+  igraph_destroy(&full);
+  igraph_destroy(&tree);
+
+  // Fit
+  igraph_hrg_init(&hrg, igraph_vcount(&graph));
+  igraph_hrg_fit(&graph, &hrg, /*start=*/ 0, /*steps=*/ 0);
+
+  // Create a graph from it
+  igraph_hrg_dendrogram(&dendrogram, &hrg);
+
+  // Print the tree, with labels
+  // igraph_vector_init(&neis, 0);
+  // for (i=0; i<igraph_vcount(&graph)-1; i++) {
+  //   printf("Vertex # %2i, ", (int) (i+igraph_vcount(&graph)));
+  //   igraph_neighbors(&dendrogram, &neis, i+igraph_vcount(&graph), IGRAPH_OUT);
+  //   printf("left: # %2i, right: # %2i, ", (int) VECTOR(neis)[0], 
+  // 	   (int) VECTOR(neis)[1]);
+  //   printf("prob: %6.2g\n", 
+  // 	   VAN(&dendrogram, "probability", i+igraph_vcount(&graph)));
+  // }
+  // igraph_vector_destroy(&neis);
+
+  igraph_destroy(&dendrogram);
+  igraph_hrg_destroy(&hrg);
+  igraph_destroy(&graph);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_hrg2.c b/examples/simple/igraph_hrg2.c
new file mode 100644
index 0000000..4871116
--- /dev/null
+++ b/examples/simple/igraph_hrg2.c
@@ -0,0 +1,81 @@
+/* -*- mode: C++ -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main() {
+  igraph_t karate;
+  igraph_vector_t parents, weights;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_small(&karate, 34, IGRAPH_UNDIRECTED,
+               0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,10,0,11,0,12,0,13,
+               0,17,0,19,0,21,0,31,
+               1,2,1,3,1,7,1,13,1,17,1,19,1,21,1,30,
+               2,3,2,7,2,27,2,28,2,32,2,9,2,8,2,13,
+               3,7,3,12,3,13,
+               4,6,4,10,
+               5,6,5,10,5,16,
+               6,16,
+               8,30,8,32,8,33,
+               9,33,
+               13,33,
+               14,32,14,33,
+               15,32,15,33,
+               18,32,18,33,
+               19,33,
+               20,32,20,33,
+               22,32,22,33,
+               23,25,23,27,23,32,23,33,23,29,
+               24,25,24,27,24,31,
+               25,31,
+               26,29,26,33,
+               27,33,
+               28,31,28,33,
+               29,32,29,33,
+               30,32,30,33,
+               31,32,31,33,
+               32,33,
+               -1);
+  
+  igraph_vector_init(&parents, 0);
+  igraph_vector_init(&weights, 0);
+  igraph_hrg_consensus(&karate, &parents, &weights, /* hrg= */ 0, 
+		       /* start= */ 0, /* num_samples= */ 100);
+
+  /* Check */
+  igraph_vector_print(&parents);
+  igraph_vector_print(&weights);
+
+  igraph_vector_destroy(&parents);
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&karate);
+
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
diff --git a/examples/simple/igraph_hrg2.out b/examples/simple/igraph_hrg2.out
new file mode 100644
index 0000000..b066fcf
--- /dev/null
+++ b/examples/simple/igraph_hrg2.out
@@ -0,0 +1,2 @@
+37 37 37 37 36 36 36 37 34 37 36 37 37 37 37 37 36 37 37 37 37 37 37 37 35 35 37 37 37 37 34 37 37 37 37 37 37 -1
+54 59 71 100
diff --git a/examples/simple/igraph_hrg3.c b/examples/simple/igraph_hrg3.c
new file mode 100644
index 0000000..007b351
--- /dev/null
+++ b/examples/simple/igraph_hrg3.c
@@ -0,0 +1,81 @@
+/* -*- mode: C++ -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main() {
+  igraph_t karate;
+  igraph_vector_t edges, prob;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_small(&karate, 34, IGRAPH_UNDIRECTED,
+               0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,10,0,11,0,12,0,13,
+               0,17,0,19,0,21,0,31,
+               1,2,1,3,1,7,1,13,1,17,1,19,1,21,1,30,
+               2,3,2,7,2,27,2,28,2,32,2,9,2,8,2,13,
+               3,7,3,12,3,13,
+               4,6,4,10,
+               5,6,5,10,5,16,
+               6,16,
+               8,30,8,32,8,33,
+               9,33,
+               13,33,
+               14,32,14,33,
+               15,32,15,33,
+               18,32,18,33,
+               19,33,
+               20,32,20,33,
+               22,32,22,33,
+               23,25,23,27,23,32,23,33,23,29,
+               24,25,24,27,24,31,
+               25,31,
+               26,29,26,33,
+               27,33,
+               28,31,28,33,
+               29,32,29,33,
+               30,32,30,33,
+               31,32,31,33,
+               32,33,
+               -1);
+  
+  igraph_vector_init(&edges, 0);
+  igraph_vector_init(&prob, 0);
+  igraph_hrg_predict(&karate, &edges, &prob, /* hrg= */ 0, /* start= */ 0, 
+		     /* num_samples= */ 100, /* num_bins= */ 25);
+
+  /* Check */
+  igraph_vector_print(&edges);
+  igraph_vector_print(&prob);
+
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&prob);
+  igraph_destroy(&karate);
+
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
diff --git a/examples/simple/igraph_hrg3.out b/examples/simple/igraph_hrg3.out
new file mode 100644
index 0000000..79442eb
--- /dev/null
+++ b/examples/simple/igraph_hrg3.out
@@ -0,0 +1,2 @@
+28 32 0 16 27 32 9 32 26 32 4 5 4 16 10 16 6 10 1 12 2 17 2 19 2 21 2 18 2 31 2 30 2 29 2 23 2 20 2 33 2 15 2 22 2 14 2 26 2 12 3 17 3 21 7 13 3 19 2 24 2 25 23 26 24 33 27 29 0 26 25 33 2 11 0 25 2 16 2 4 2 5 2 6 2 10 1 11 26 27 9 24 14 25 25 30 25 29 20 25 18 25 22 25 25 32 15 25 25 28 8 25 0 9 0 27 0 22 0 32 0 33 0 14 0 28 0 15 0 29 0 18 0 30 0 20 0 23 9 25 24 26 14 24 15 24 22 24 24 29 23 24 24 28 18 24 20 24 24 30 24 32 8 24 25 27 25 26 0 24 12 13 7 12 12 21 12 17 12 19 3 11 9 27 7  [...]
+0.719645 0.683752 0.595454 0.506803 0.485989 0.333764 0.322943 0.296878 0.29381 0.210965 0.195612 0.192923 0.192473 0.187386 0.187317 0.187287 0.187271 0.187263 0.187259 0.187257 0.187251 0.187239 0.187207 0.183749 0.180832 0.180023 0.178898 0.172966 0.17008 0.162812 0.161228 0.146531 0.14168 0.14086 0.140079 0.137672 0.136404 0.13489 0.132525 0.129325 0.129274 0.129251 0.129244 0.127252 0.121633 0.118454 0.115711 0.115706 0.115694 0.115683 0.115682 0.115657 0.115611 0.115604 0.115604 0. [...]
diff --git a/examples/simple/igraph_i_cutheap.c b/examples/simple/igraph_i_cutheap.c
new file mode 100644
index 0000000..ce8d85f
--- /dev/null
+++ b/examples/simple/igraph_i_cutheap.c
@@ -0,0 +1,62 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_types_internal.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  igraph_i_cutheap_t ch;
+  long int i;
+  
+  igraph_i_cutheap_init(&ch, 10);
+
+  for (i=0; i<10; i++) {
+    igraph_i_cutheap_update(&ch, i, i);
+  }
+/*   print_vector(&ch.heap, stdout); */
+/*   print_vector(&ch.index, stdout); */
+/*   print_vector(&ch.hptr, stdout); */
+  while (!igraph_i_cutheap_empty(&ch)) {
+    long int idx=igraph_i_cutheap_popmax(&ch);
+    printf("%li ", idx);
+/*     print_vector(&ch.heap, stdout); */
+/*     print_vector(&ch.index, stdout); */
+/*     print_vector(&ch.hptr, stdout); */
+/*     printf("------------\n"); */
+  }
+  printf("\n");
+
+  igraph_i_cutheap_destroy(&ch);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_i_cutheap.out b/examples/simple/igraph_i_cutheap.out
new file mode 100644
index 0000000..b53cb66
--- /dev/null
+++ b/examples/simple/igraph_i_cutheap.out
@@ -0,0 +1 @@
+9 8 7 6 5 4 3 2 1 0 
diff --git a/examples/simple/igraph_i_layout_sphere.c b/examples/simple/igraph_i_layout_sphere.c
new file mode 100644
index 0000000..4c01bdb
--- /dev/null
+++ b/examples/simple/igraph_i_layout_sphere.c
@@ -0,0 +1,86 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+#include <stdlib.h>
+#include <math.h>
+
+int igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y,
+			      igraph_real_t *r);
+int igraph_i_layout_sphere_3d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y,
+			      igraph_real_t *z, igraph_real_t *r);
+
+int main () {
+  long int i; 
+  igraph_matrix_t m;
+  igraph_real_t x, y, z, r;
+
+  srand(time(0));
+
+  /* 2D */
+  igraph_matrix_init(&m, 1000, 2);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    MATRIX(m,i,0)=rand()/(double)RAND_MAX;
+    MATRIX(m,i,1)=rand()/(double)RAND_MAX;
+  }
+  igraph_i_layout_sphere_2d(&m, &x, &y, &r);
+  
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    igraph_real_t dist=sqrt((MATRIX(m,i,0)-x)*(MATRIX(m,i,0)-x) + 
+		     (MATRIX(m,i,1)-y)*(MATRIX(m,i,1)-y));
+    if (dist > r) {
+      printf("x: %f y: %f r: %f\n", x, y, r);
+      printf("x: %f y: %f dist: %f (%li)\n", 
+	     MATRIX(m,i,0), MATRIX(m,i,1), dist, i);
+      return 1;
+    }
+  }
+  igraph_matrix_destroy(&m);
+
+  /* 3D */
+  igraph_matrix_init(&m, 1000, 3);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    MATRIX(m,i,0)=rand()/(double)RAND_MAX;
+    MATRIX(m,i,1)=rand()/(double)RAND_MAX;
+    MATRIX(m,i,2)=rand()/(double)RAND_MAX;
+  }
+  igraph_i_layout_sphere_3d(&m, &x, &y, &z, &r);
+  
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    igraph_real_t dist=sqrt((MATRIX(m,i,0)-x)*(MATRIX(m,i,0)-x) + 
+		     (MATRIX(m,i,1)-y)*(MATRIX(m,i,1)-y) +
+		     (MATRIX(m,i,2)-z)*(MATRIX(m,i,2)-z));
+    if (dist > r) {
+      printf("x: %f y: %f z: %f r: %f\n", x, y, z, r);
+      printf("x: %f y: %f z: %f dist: %f (%li)\n", 
+	     MATRIX(m,i,0), MATRIX(m,i,1), MATRIX(m,i,2), dist, i);
+      return 1;
+    }
+  }
+  igraph_matrix_destroy(&m);
+
+  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_independent_sets.c b/examples/simple/igraph_independent_sets.c
new file mode 100644
index 0000000..ac9f6dd
--- /dev/null
+++ b/examples/simple/igraph_independent_sets.c
@@ -0,0 +1,87 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+void warning_handler_ignore(const char* reason,const char* file,int line,int e) {
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_ptr_t result;
+  long int i, j, n;
+  igraph_integer_t alpha;
+  const int params[] = {4, -1, 2, 2, 0, 0, -1, -1};
+  
+  igraph_set_warning_handler(warning_handler_ignore);
+  igraph_vector_ptr_init(&result, 0);
+
+  igraph_tree(&g, 5, 2, IGRAPH_TREE_OUT);
+  for (j=0; j<sizeof(params)/(2*sizeof(params[0])); j++) {
+    if (params[2*j+1] != 0) {
+      igraph_independent_vertex_sets(&g, &result, params[2*j], params[2*j+1]);
+    } else {
+      igraph_largest_independent_vertex_sets(&g, &result);
+    }
+    n = igraph_vector_ptr_size(&result);
+    printf("%ld independent sets found\n", (long)n);
+    for (i=0; i<n; i++) {
+      igraph_vector_t* v;
+      v=igraph_vector_ptr_e(&result,i);
+      print_vector((igraph_vector_t*)v);
+      igraph_vector_destroy(v);
+      free(v);
+    }
+  }
+  igraph_destroy(&g);
+
+  igraph_tree(&g, 10, 2, IGRAPH_TREE_OUT);
+  igraph_maximal_independent_vertex_sets(&g, &result);
+  n = igraph_vector_ptr_size(&result);
+  printf("%ld maximal independent sets found\n", (long)n);
+  for (i=0; i<n; i++) {
+    igraph_vector_t* v;
+    v=igraph_vector_ptr_e(&result,i);
+    print_vector((igraph_vector_t*)v);
+    igraph_vector_destroy(v);
+    free(v);
+  }
+  igraph_vector_ptr_destroy(&result);
+
+  igraph_independence_number(&g, &alpha);
+  printf("alpha=%ld\n", (long)alpha);
+
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_independent_sets.out b/examples/simple/igraph_independent_sets.out
new file mode 100644
index 0000000..3449915
--- /dev/null
+++ b/examples/simple/igraph_independent_sets.out
@@ -0,0 +1,36 @@
+0 independent sets found
+6 independent sets found
+ 0 3
+ 0 4
+ 1 2
+ 2 3
+ 2 4
+ 3 4
+2 independent sets found
+ 0 3 4
+ 2 3 4
+13 independent sets found
+ 0
+ 1
+ 2
+ 3
+ 4
+ 0 3
+ 0 4
+ 1 2
+ 2 3
+ 2 4
+ 3 4
+ 0 3 4
+ 2 3 4
+9 maximal independent sets found
+ 0 3 4 5 6
+ 0 3 5 6 9
+ 0 4 5 6 7 8
+ 0 5 6 7 8 9
+ 1 2 7 8 9
+ 1 5 6 7 8 9
+ 2 3 4
+ 2 3 9
+ 2 4 7 8
+alpha=6
diff --git a/examples/simple/igraph_induced_subgraph_map.c b/examples/simple/igraph_induced_subgraph_map.c
new file mode 100644
index 0000000..413b1ed
--- /dev/null
+++ b/examples/simple/igraph_induced_subgraph_map.c
@@ -0,0 +1,60 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main() {
+  igraph_t g, sub;
+  igraph_vector_t map, invmap;
+  igraph_vector_t keep;
+  long int i;
+  
+  igraph_small(&g, 9, IGRAPH_DIRECTED, 0,1, 0,2, 1,3, 2,3,
+	       1,4,4,2, 1,5,5,2, 1,6,6,2, 1,7,7,2, 1,8,8,2,
+	       -1);
+  igraph_vector_init(&map, 0);
+  igraph_vector_init(&invmap, 0);
+  igraph_vector_init(&keep, igraph_vcount(&g));
+  for (i=0; i<igraph_vector_size(&keep); i++) {
+    VECTOR(keep)[i] = i;
+  }
+
+  igraph_induced_subgraph_map(&g, &sub, 
+			      igraph_vss_vector(&keep),
+			      IGRAPH_SUBGRAPH_COPY_AND_DELETE,
+			      &map, &invmap);
+  
+  printf("Map:         "); igraph_vector_print(&map);
+  printf("Inverse map: "); igraph_vector_print(&invmap);
+  igraph_write_graph_edgelist(&sub, stdout);
+
+  igraph_vector_destroy(&keep);
+  igraph_vector_destroy(&map);
+  igraph_vector_destroy(&invmap);
+  
+  igraph_destroy(&sub);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_intersection.c b/examples/simple/igraph_intersection.c
new file mode 100644
index 0000000..17cbdad
--- /dev/null
+++ b/examples/simple/igraph_intersection.c
@@ -0,0 +1,124 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, l=igraph_vector_size(v);
+  for (i=0; i<l; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int main() {
+
+  igraph_t left, right, isec;
+  igraph_vector_t v;
+  igraph_vector_ptr_t glist;
+  igraph_t g1, g2, g3;
+  igraph_vector_t edge_map1, edge_map2;
+
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,3, -1);
+  igraph_create(&left, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init_int_end(&v, -1, 1,0, 5,4, 1,2, 3,2, -1);
+  igraph_create(&right, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+
+  igraph_vector_init(&edge_map1, 0);
+  igraph_vector_init(&edge_map2, 0);
+  
+  igraph_intersection(&isec, &left, &right, &edge_map1, &edge_map2);
+  igraph_vector_init(&v, 0);
+  igraph_get_edgelist(&isec, &v, 0);
+  printf("---\n");
+  print_vector(&v);
+  print_vector(&edge_map1);
+  print_vector(&edge_map2);
+  printf("---\n");
+  igraph_vector_destroy(&v);
+  igraph_destroy(&left);
+  igraph_destroy(&right);
+  igraph_destroy(&isec);
+  igraph_vector_destroy(&edge_map1);
+  igraph_vector_destroy(&edge_map2);
+
+  /* empty graph list */
+  igraph_vector_ptr_init(&glist, 0);
+  igraph_intersection_many(&isec, &glist, 0);
+  if (igraph_vcount(&isec) != 0 || !igraph_is_directed(&isec)) {
+    return 1;
+  }
+  igraph_destroy(&isec);
+  igraph_vector_ptr_destroy(&glist);
+
+  /* graph list with an empty graph */
+  igraph_vector_ptr_init(&glist, 3);
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,3, -1);
+  igraph_create(&g1, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,3, -1);
+  igraph_create(&g2, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  igraph_empty(&g3, 10, IGRAPH_DIRECTED);
+
+  VECTOR(glist)[0]=&g1;
+  VECTOR(glist)[1]=&g2;
+  VECTOR(glist)[2]=&g3;
+  igraph_intersection_many(&isec, &glist, 0);
+  if (igraph_ecount(&isec) != 0 || igraph_vcount(&isec) != 10) {
+    return 2;
+  }
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+  igraph_destroy(&g3);
+  igraph_destroy(&isec);
+  igraph_vector_ptr_destroy(&glist);
+  
+  /* "proper" graph list */
+  igraph_vector_ptr_init(&glist, 3);
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,3, -1);
+  igraph_create(&g1, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,3, 3,2, 4,5, 6,5, -1);
+  igraph_create(&g2, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  igraph_vector_init_int_end(&v, -1, 2,3, 1,0, 1,2, 3,2, 4,5, 6,5, 2,3, -1);
+  igraph_create(&g3, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  VECTOR(glist)[0]=&g1;
+  VECTOR(glist)[1]=&g2;
+  VECTOR(glist)[2]=&g3;
+  igraph_intersection_many(&isec, &glist, 0);
+  igraph_write_graph_edgelist(&isec, stdout);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+  igraph_destroy(&g3);
+  igraph_destroy(&isec);
+  igraph_vector_ptr_destroy(&glist);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_intersection.out b/examples/simple/igraph_intersection.out
new file mode 100644
index 0000000..d15f5a3
--- /dev/null
+++ b/examples/simple/igraph_intersection.out
@@ -0,0 +1,7 @@
+---
+ 1 2
+ 1
+ 2
+---
+1 2
+2 3
diff --git a/examples/simple/igraph_intersection2.c b/examples/simple/igraph_intersection2.c
new file mode 100644
index 0000000..a779f25
--- /dev/null
+++ b/examples/simple/igraph_intersection2.c
@@ -0,0 +1,59 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main() {
+
+  igraph_t star, ring, uni, result;
+  igraph_vector_ptr_t glist;
+
+  igraph_star(&star, 11, IGRAPH_STAR_UNDIRECTED, /*center=*/ 10);
+  igraph_ring(&ring, 10, IGRAPH_UNDIRECTED, /*mutual=*/ 0, /*circular=*/ 1);
+  
+  igraph_union(&uni, &star, &ring, /*edge_map1=*/ 0, /*edge_map2=*/ 0);
+  
+  igraph_intersection(&result, &uni, &star, /*edge_map1*/ 0, 
+		      /*edge_map2=*/ 0);
+  igraph_write_graph_edgelist(&result, stdout);
+
+  igraph_destroy(&result);
+
+  /* ---------------------------- */
+  
+  igraph_vector_ptr_init(&glist, 2);
+  VECTOR(glist)[0] = &uni;
+  VECTOR(glist)[1] = ☆
+  
+  igraph_intersection_many(&result, &glist, /*edgemaps=*/ 0);
+  printf("--\n"); igraph_write_graph_edgelist(&result, stdout);
+
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&result);
+  igraph_destroy(&uni);
+  igraph_destroy(&ring);
+  igraph_destroy(&star);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_intersection2.out b/examples/simple/igraph_intersection2.out
new file mode 100644
index 0000000..f435983
--- /dev/null
+++ b/examples/simple/igraph_intersection2.out
@@ -0,0 +1,21 @@
+0 10
+1 10
+2 10
+3 10
+4 10
+5 10
+6 10
+7 10
+8 10
+9 10
+--
+0 10
+1 10
+2 10
+3 10
+4 10
+5 10
+6 10
+7 10
+8 10
+9 10
diff --git a/examples/simple/igraph_is_degree_sequence.c b/examples/simple/igraph_is_degree_sequence.c
new file mode 100644
index 0000000..be5b376
--- /dev/null
+++ b/examples/simple/igraph_is_degree_sequence.c
@@ -0,0 +1,140 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+    igraph_vector_t outseq, inseq;
+    igraph_bool_t result;
+
+    /***** Testing igraph_is_degree_sequence *****/
+    
+    /* Valid undirected degree sequence */
+    igraph_vector_init_int_end(&outseq, -1, 3, 3, 3, 3, 3, 3, 3, 3, -1);
+    igraph_is_degree_sequence(&outseq, 0, &result);
+    if (!result)
+        return 1;
+    igraph_vector_destroy(&outseq);
+
+    /* Undirected degree sequence with negative degree */
+    igraph_vector_init_int_end(&outseq, -1, 3, -2, 3, 3, 3, 3, 3, 3, -1);
+    igraph_is_degree_sequence(&outseq, 0, &result);
+    if (result)
+        return 2;
+    igraph_vector_destroy(&outseq);
+
+    /* Undirected degree sequence with uneven sum */
+    igraph_vector_init_int_end(&outseq, -1, 3, 3, 3, 3, 3, 3, 3, -1);
+    igraph_is_degree_sequence(&outseq, 0, &result);
+    if (result)
+        return 3;
+    igraph_vector_destroy(&outseq);
+
+    /* Valid directed degree sequences */
+    igraph_vector_init_int_end(&outseq, -1, 0, 2, 3, 0, 4, 3, 1, 3, 4, 2, -1);
+    igraph_vector_init_int_end(&inseq, -1, 0, 3, 1, 3, 2, 4, 4, 1, 3, 1, -1);
+    igraph_is_degree_sequence(&outseq, &inseq, &result);
+    if (!result)
+        return 4;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    /* Directed degree sequence with negative degree */
+    igraph_vector_init_int_end(&outseq, -1, 0, 2, 3, 0, 4, 3, 1, 3, 4, 2, -1);
+    igraph_vector_init_int_end(&inseq, -1, 0, 3, 1, -7, 2, 4, 4, 1, 3, 1, -1);
+    igraph_is_degree_sequence(&outseq, &inseq, &result);
+    if (result)
+        return 5;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    /* Directed degree sequence with different lengths */
+    igraph_vector_init_int_end(&outseq, -1, 0, 2, 3, 0, 4, 3, 1, 3, 4, 2, -1);
+    igraph_vector_init_int_end(&inseq, -1, 0, 3, 1, 2, 4, 4, 1, 3, 1, -1);
+    igraph_is_degree_sequence(&outseq, &inseq, &result);
+    if (result)
+        return 5;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    /* Directed degree sequence with different sums */
+    igraph_vector_init_int_end(&outseq, -1, 0, 2, 3, 0, 4, 3, 1, 3, 4, 2, -1);
+    igraph_vector_init_int_end(&inseq, -1, 0, 3, 1, 2, 2, 4, 4, 1, 3, 1, -1);
+    igraph_is_degree_sequence(&outseq, &inseq, &result);
+    if (result)
+        return 6;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    /***** Testing igraph_is_graphical_degree_sequence *****/
+
+    /* Valid undirected graphical degree sequence */
+    igraph_vector_init_int_end(&outseq, -1, 3, 3, 3, 3, 3, 3, 3, 3, -1);
+    igraph_is_graphical_degree_sequence(&outseq, 0, &result);
+    if (!result)
+        return 7;
+    igraph_vector_destroy(&outseq);
+
+    /* Another valid undirected graphical degree sequence */
+    igraph_vector_init_int_end(&outseq, -1, 4, 7, 4, 7, 7, 8, 9, 9, 4, 6, 5, -1);
+    igraph_is_graphical_degree_sequence(&outseq, 0, &result);
+    if (!result)
+        return 8;
+    igraph_vector_destroy(&outseq);
+
+    /* Valid undirected degree sequence but not graphical */
+    igraph_vector_init_int_end(&outseq, -1, 3, 3, -1);
+    igraph_is_graphical_degree_sequence(&outseq, 0, &result);
+    if (result)
+        return 9;
+    igraph_vector_destroy(&outseq);
+
+    /* Valid directed graphical degree sequence */
+    igraph_vector_init_int_end(&inseq, -1, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1);
+    igraph_vector_init_int_end(&outseq, -1, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1);
+    igraph_is_graphical_degree_sequence(&outseq, &inseq, &result);
+    if (!result)
+        return 10;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    /* Another valid directed graphical degree sequence */
+    igraph_vector_init_int_end(&inseq, -1, 1, 3, 2, 1, 3, 4, 3, 3, 1, 3, -1);
+    igraph_vector_init_int_end(&outseq, -1, 4, 1, 2, 3, 2, 3, 2, 3, 2, 2, -1);
+    igraph_is_graphical_degree_sequence(&outseq, &inseq, &result);
+    if (!result)
+        return 11;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    /* Yet another valid directed graphical degree sequence */
+    igraph_vector_init_int_end(&inseq, -1, 7, 4, 6, 4, 7, 8, 8, 8, 7, 4, -1);
+    igraph_vector_init_int_end(&outseq, -1, 8, 5, 6, 8, 6, 6, 5, 7, 5, 7, -1);
+    igraph_is_graphical_degree_sequence(&outseq, &inseq, &result);
+    if (!result)
+        return 12;
+    igraph_vector_destroy(&outseq);
+    igraph_vector_destroy(&inseq);
+
+    return 0;
+}
diff --git a/examples/simple/igraph_is_directed.c b/examples/simple/igraph_is_directed.c
new file mode 100644
index 0000000..6a561cd
--- /dev/null
+++ b/examples/simple/igraph_is_directed.c
@@ -0,0 +1,43 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  
+  igraph_empty(&g, 0, 0);
+  if (igraph_is_directed(&g)) {
+    return 1;
+  }
+  igraph_destroy(&g);
+
+  igraph_empty(&g, 0, 1);
+  if (!igraph_is_directed(&g)) {
+    return 2;
+  }
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_is_loop.c b/examples/simple/igraph_is_loop.c
new file mode 100644
index 0000000..f788703
--- /dev/null
+++ b/examples/simple/igraph_is_loop.c
@@ -0,0 +1,55 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_bool_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_bool_size(v); i++) {
+    fprintf(f, " %i", (int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_t graph;
+  igraph_vector_bool_t v;
+  
+  igraph_vector_bool_init(&v, 0);
+
+  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 0,1, 1,0, 3,4, 11,10, -1);
+  igraph_is_loop(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  print_vector(&v, stdout);
+  igraph_destroy(&graph);
+  
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
+	       0,0, 1,1, 2,2, 2,3, 2,4, 2,5, 2,6, 2,2, 0,0, -1);
+  igraph_is_loop(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  print_vector(&v, stdout);
+  igraph_destroy(&graph);
+
+  igraph_vector_bool_destroy(&v);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_is_loop.out b/examples/simple/igraph_is_loop.out
new file mode 100644
index 0000000..4fadd3c
--- /dev/null
+++ b/examples/simple/igraph_is_loop.out
@@ -0,0 +1,2 @@
+ 0 0 0 0 0 0 0
+ 1 1 1 0 0 0 0 1 1
diff --git a/examples/simple/igraph_is_minimal_separator.c b/examples/simple/igraph_is_minimal_separator.c
new file mode 100644
index 0000000..b5d2638
--- /dev/null
+++ b/examples/simple/igraph_is_minimal_separator.c
@@ -0,0 +1,67 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+#define FAIL(msg, error) do { printf(msg "\n") ; return error; } while (0)
+
+int main() {
+  
+  igraph_t graph;
+  igraph_vector_t sep;
+  igraph_bool_t result;
+
+  /* Simple star graph, remove the center */
+  igraph_star(&graph, 10, IGRAPH_STAR_UNDIRECTED, 0);
+  igraph_is_minimal_separator(&graph, igraph_vss_1(0), &result);
+  if (!result) FAIL("Center of star graph failed.", 1);
+
+  /* Same graph, but another vertex */
+  igraph_is_minimal_separator(&graph, igraph_vss_1(6), &result);
+  if (result) FAIL("Non-center of star graph failed.", 2);
+  igraph_destroy(&graph);
+
+  /* Karate club */
+  igraph_famous(&graph, "zachary");
+  igraph_vector_init(&sep, 0);
+  igraph_vector_push_back(&sep, 32);
+  igraph_vector_push_back(&sep, 33);
+  igraph_is_minimal_separator(&graph, igraph_vss_vector(&sep), &result);
+  if (!result) FAIL("Karate network (32,33) failed", 3);
+
+  igraph_vector_resize(&sep, 5);
+  VECTOR(sep)[0]=8;
+  VECTOR(sep)[1]=9;
+  VECTOR(sep)[2]=19;
+  VECTOR(sep)[3]=30;
+  VECTOR(sep)[4]=31;
+  igraph_is_minimal_separator(&graph, igraph_vss_vector(&sep), &result);
+  if (result) FAIL("Karate network (8,9,19,30,31) failed", 4);
+
+  igraph_destroy(&graph);
+  igraph_vector_destroy(&sep);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_is_multiple.c b/examples/simple/igraph_is_multiple.c
new file mode 100644
index 0000000..1284858
--- /dev/null
+++ b/examples/simple/igraph_is_multiple.c
@@ -0,0 +1,56 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_bool_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_bool_size(v); i++) {
+    fprintf(f, " %i", (int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_t graph;
+  igraph_vector_bool_t v;
+  
+  igraph_vector_bool_init(&v, 0);
+
+  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 0,1, 1,0, 3,4, 11,10, -1);
+  igraph_is_multiple(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  print_vector(&v, stdout);
+  igraph_destroy(&graph);
+  
+  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
+	       0,0, 1,2, 1,1, 2,2, 2,1, 2,3, 2,4, 
+	       2,5, 2,6, 2,2, 3,2, 0,0, 6,2, 2,2, 0,0, -1);
+  igraph_is_multiple(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  print_vector(&v, stdout);
+  igraph_destroy(&graph);
+
+  igraph_vector_bool_destroy(&v);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_is_multiple.out b/examples/simple/igraph_is_multiple.out
new file mode 100644
index 0000000..14ea4e2
--- /dev/null
+++ b/examples/simple/igraph_is_multiple.out
@@ -0,0 +1,2 @@
+ 0 0 0 1 0 0 0
+ 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1
diff --git a/examples/simple/igraph_is_separator.c b/examples/simple/igraph_is_separator.c
new file mode 100644
index 0000000..9fe0536
--- /dev/null
+++ b/examples/simple/igraph_is_separator.c
@@ -0,0 +1,67 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+#define FAIL(msg, error) do { printf(msg "\n") ; return error; } while (0)
+
+int main() {
+  
+  igraph_t graph;
+  igraph_vector_t sep;
+  igraph_bool_t result;
+
+  /* Simple star graph, remove the center */
+  igraph_star(&graph, 10, IGRAPH_STAR_UNDIRECTED, 0);
+  igraph_is_separator(&graph, igraph_vss_1(0), &result);
+  if (!result) FAIL("Center of star graph failed.", 1);
+
+  /* Same graph, but another vertex */
+  igraph_is_separator(&graph, igraph_vss_1(6), &result);
+  if (result) FAIL("Non-center of star graph failed.", 2);
+  igraph_destroy(&graph);
+
+  /* Karate club */
+  igraph_famous(&graph, "zachary");
+  igraph_vector_init(&sep, 0);
+  igraph_vector_push_back(&sep, 32);
+  igraph_vector_push_back(&sep, 33);
+  igraph_is_separator(&graph, igraph_vss_vector(&sep), &result);
+  if (!result) FAIL("Karate network (32,33) failed", 3);
+
+  igraph_vector_resize(&sep, 5);
+  VECTOR(sep)[0]=8;
+  VECTOR(sep)[1]=9;
+  VECTOR(sep)[2]=19;
+  VECTOR(sep)[3]=30;
+  VECTOR(sep)[4]=31;
+  igraph_is_separator(&graph, igraph_vss_vector(&sep), &result);
+  if (result) FAIL("Karate network (8,9,19,30,31) failed", 4);
+
+  igraph_destroy(&graph);
+  igraph_vector_destroy(&sep);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_isomorphic_vf2.c b/examples/simple/igraph_isomorphic_vf2.c
new file mode 100644
index 0000000..31c7523
--- /dev/null
+++ b/examples/simple/igraph_isomorphic_vf2.c
@@ -0,0 +1,283 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int random_permutation(igraph_vector_t *vec) {
+  /* We just do size(vec) * 2 swaps */
+  long int one, two, tmp, i, n=igraph_vector_size(vec);
+  for (i=0; i<2*n; i++) {
+    one= (double)rand() / RAND_MAX * n;
+    two= (double)rand() / RAND_MAX * n;
+    tmp=one; one=two; two=tmp;
+  }
+  return 0;
+}
+
+int main() {
+  
+  igraph_t ring1, ring2;
+  igraph_vector_int_t color1, color2;
+  igraph_vector_t perm;
+  igraph_bool_t iso;
+  igraph_integer_t count;
+  long int i;
+
+  srand(time(0));
+
+  igraph_ring(&ring1, 100, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/1);
+  igraph_vector_init_seq(&perm, 0, igraph_vcount(&ring1)-1);
+  random_permutation(&perm);
+  igraph_permute_vertices(&ring1, &ring2, &perm);
+  
+  /* Without colors */
+  igraph_isomorphic(&ring1, &ring2, &iso);
+  if (!iso) {
+    fprintf(stderr, "Without color failed.\n");
+    return 1;
+  }
+
+  /* Without colors, number of isomorphisms */
+  igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, 0, 0, &count, 0, 0, 0);
+  if (count != 200) {
+    fprintf(stderr, "Count without colors failed, expected %li, got %li.\n",
+	    (long int) 200, (long int) count);
+    return 2;
+  }
+
+  /* Everything has the same colors */
+  igraph_vector_int_init(&color1, igraph_vcount(&ring1));
+  igraph_vector_int_init(&color2, igraph_vcount(&ring2));
+  igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0, 0, 0, 0);
+  if (!iso) {
+    fprintf(stderr, "Single color failed.\n");
+    return 3;
+  }
+  
+  /* Two colors, just counting */
+  for (i=0; i<igraph_vector_int_size(&color1); i+=2) {
+    VECTOR(color1)[i]   = VECTOR(color2)[i] = 0;
+    VECTOR(color1)[i+1] = VECTOR(color2)[i] = 1;
+  }
+  igraph_count_isomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &count, 0, 0, 0);
+  if (count != 100) {
+    fprintf(stderr, "Count with two colors failed, expected %li, got %li.\n",
+	    (long int) 100, (long int) count);
+    return 4;
+  }
+
+  /* Separate colors for each vertex */
+  for (i=0; i<igraph_vector_int_size(&color1); i++) {
+    VECTOR(color1)[i]   = VECTOR(color2)[i] = i;
+  }
+  igraph_count_isomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &count, 0, 0, 0);
+  if (count != 1) {
+    fprintf(stderr, "Count with separate colors failed, expected %li, got %li.\n",
+	    (long int) 1, (long int) count);
+    return 5;
+  }
+
+  /* Try a negative result */
+  igraph_vector_int_fill(&color1, 0);
+  igraph_vector_int_fill(&color2, 0); 
+  VECTOR(color1)[0]=1;
+  igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0, 0, 0, 0);
+  if (iso) {
+    fprintf(stderr, "Negative test failed.\n");
+    return 6;
+  }
+
+  /* Another negative, same color distribution, different topology */
+  igraph_vector_int_fill(&color1, 0);
+  igraph_vector_int_fill(&color2, 0); 
+  VECTOR(color1)[0]=1;  VECTOR(color1)[1]=1;
+  VECTOR(color2)[0]=1;  VECTOR(color2)[2]=1;
+  igraph_isomorphic_vf2(&ring1, &ring2, &color1, &color2, 0, 0, &iso, 0, 0, 0, 0, 0);
+  if (iso) {
+    fprintf(stderr, "Second negative test failed.\n");
+    return 7;
+  }  
+  
+  igraph_vector_int_destroy(&color1);
+  igraph_vector_int_destroy(&color2);
+
+  igraph_vector_destroy(&perm);
+  igraph_destroy(&ring2);
+  igraph_destroy(&ring1);
+
+  /* ---------------------------------------------------------------- */
+  /* SUBGRAPH ISOMORPHISM                                             */
+  /* ---------------------------------------------------------------- */
+
+  igraph_ring(&ring1, 100, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/0);
+  igraph_ring(&ring2, 80 , /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/0);
+
+  /* One color */
+  igraph_vector_int_init(&color1, igraph_vcount(&ring1));
+  igraph_vector_int_init(&color2, igraph_vcount(&ring2));
+  igraph_count_subisomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, 
+				   &count, 0, 0, 0);
+  if (count != 42) {
+    fprintf(stderr, "Count with one color failed, expected %li, got %li.\n",
+	    (long int) 42, (long int) count);
+    return 31;
+  }
+
+  /* Two colors */
+  for (i=0; i<igraph_vector_int_size(&color1); i+=2) {
+    VECTOR(color1)[i]   = 0;
+    VECTOR(color1)[i+1] = 1;
+  }
+  for (i=0; i<igraph_vector_int_size(&color2); i+=2) {  
+    VECTOR(color2)[i]   = 0;
+    VECTOR(color2)[i+1] = 1;
+  }
+  igraph_count_subisomorphisms_vf2(&ring1, &ring2, &color1, &color2, 0, 0, 
+				   &count, 0, 0, 0);
+  if (count != 21) {
+    fprintf(stderr, "Count with two colors failed, expected %li, got %li.\n",
+	    (long int) 21, (long int) count);
+    return 32;
+  }
+
+  igraph_vector_int_destroy(&color1);
+  igraph_vector_int_destroy(&color2);
+
+  igraph_destroy(&ring1);
+  igraph_destroy(&ring2);
+
+  /* ---------------------------------------------------------------- */
+  /* EDGE COLORING, GRAPH ISOMORPHISM                                 */
+  /* ---------------------------------------------------------------- */
+
+  igraph_ring(&ring1, 100, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_vector_init_seq(&perm, 0, igraph_ecount(&ring1)-1);
+  random_permutation(&perm);
+  igraph_permute_vertices(&ring1, &ring2, &perm);
+  igraph_vector_destroy(&perm);
+
+  /* Everything has the same color */
+  igraph_vector_int_init(&color1, igraph_ecount(&ring1));
+  igraph_vector_int_init(&color2, igraph_ecount(&ring2));
+  igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0, 0, 0, 0);
+  if (!iso) {
+    fprintf(stderr, "Single edge-color failed.\n");
+    return 41;
+  }
+
+  /* Two colors, just counting */
+  for (i=0; i<igraph_vector_int_size(&color1); i+=2) {
+    VECTOR(color1)[i]   = VECTOR(color2)[i] = 0;
+    VECTOR(color1)[i+1] = VECTOR(color2)[i] = 1;
+  }
+  igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &count, 0, 0, 0);
+  if (count != 100) {
+    fprintf(stderr, "Count with two edge colors failed, expected %li, got %li.\n",
+	    (long int) 100, (long int) count);
+    return 42;
+  }
+
+  /* Separate colors for each edge */
+  for (i=0; i<igraph_vector_int_size(&color1); i++) {
+    VECTOR(color1)[i]   = VECTOR(color2)[i] = i;
+  }
+  igraph_count_isomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &count, 0, 0, 0);
+  if (count != 1) {
+    fprintf(stderr, "Count with separate edge colors failed, expected %li, got %li.\n",
+	    (long int) 1, (long int) count);
+    return 43;
+  }  
+
+  /* Try a negative result */
+  igraph_vector_int_fill(&color1, 0);
+  igraph_vector_int_fill(&color2, 0); 
+  VECTOR(color1)[0]=1;
+  igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0, 0, 0, 0);
+  if (iso) {
+    fprintf(stderr, "Negative edge test failed.\n");
+    return 44;
+  }
+
+  /* Another negative, same color distribution, different topology */
+  igraph_vector_int_fill(&color1, 0);
+  igraph_vector_int_fill(&color2, 0); 
+  VECTOR(color1)[0]=1;  VECTOR(color1)[1]=1;
+  VECTOR(color2)[0]=1;  VECTOR(color2)[2]=1;
+  igraph_isomorphic_vf2(&ring1, &ring2, 0, 0, &color1, &color2, &iso, 0, 0, 0, 0, 0);
+  if (iso) {
+    fprintf(stderr, "Second negative edge test failed.\n");
+    return 45;
+  }    
+
+  igraph_vector_int_destroy(&color1);
+  igraph_vector_int_destroy(&color2);
+
+  igraph_destroy(&ring1);
+  igraph_destroy(&ring2);
+
+  /* ---------------------------------------------------------------- */
+  /* EDGE COLORED SUBGRAPH ISOMORPHISM                                */
+  /* ---------------------------------------------------------------- */
+
+  igraph_ring(&ring1, 100, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/0);
+  igraph_ring(&ring2, 80 , /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/0);
+
+  /* One color */
+  igraph_vector_int_init(&color1, igraph_ecount(&ring1));
+  igraph_vector_int_init(&color2, igraph_ecount(&ring2));
+  igraph_count_subisomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2,
+				   &count, 0, 0, 0);
+  if (count != 42) {
+    fprintf(stderr, "Count with one edge color failed, expected %li, got %li.\n",
+	    (long int) 42, (long int) count);
+    return 51;
+  }
+
+  /* Two colors */
+  for (i=0; i<igraph_vector_int_size(&color1)-1; i+=2) {
+    VECTOR(color1)[i]   = 0;
+    VECTOR(color1)[i+1] = 1;
+  }
+  for (i=0; i<igraph_vector_int_size(&color2)-1; i+=2) {  
+    VECTOR(color2)[i]   = 0;
+    VECTOR(color2)[i+1] = 1;
+  }
+  igraph_count_subisomorphisms_vf2(&ring1, &ring2, 0, 0, &color1, &color2,
+				   &count, 0, 0, 0);
+  if (count != 22) {
+    fprintf(stderr, "Count with two edge colors failed, expected %li, got %li.\n",
+	    (long int) 22, (long int) count);
+    return 52;
+  }
+
+  igraph_vector_int_destroy(&color1);
+  igraph_vector_int_destroy(&color2);
+
+  igraph_destroy(&ring1);
+  igraph_destroy(&ring2);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_k_regular_game.c b/examples/simple/igraph_k_regular_game.c
new file mode 100644
index 0000000..9cf7a9c
--- /dev/null
+++ b/examples/simple/igraph_k_regular_game.c
@@ -0,0 +1,174 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t deg;
+  igraph_bool_t is_simple;
+
+  igraph_set_error_handler(&igraph_error_handler_ignore);
+
+  igraph_vector_init(&deg, 0);
+
+  /* k-regular undirected graph, even degrees, no multiple edges */
+  igraph_k_regular_game(&g, 10, 4, 0, 0);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_ALL, 1);
+  igraph_vector_print(&deg);
+  igraph_is_simple(&g, &is_simple);
+  if (!is_simple)
+	  return 1;
+  if (igraph_is_directed(&g))
+	  return 1;
+  igraph_destroy(&g);
+
+  /* k-regular undirected graph, odd degrees, even number of vertices, no multiple edges */
+  igraph_k_regular_game(&g, 10, 3, 0, 0);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_ALL, 1);
+  igraph_vector_print(&deg);
+  igraph_is_simple(&g, &is_simple);
+  if (!is_simple)
+	  return 2;
+  if (igraph_is_directed(&g))
+	  return 2;
+  igraph_destroy(&g);
+
+  /* k-regular undirected graph, odd degrees, odd number of vertices, no multiple edges */
+  if (!igraph_k_regular_game(&g, 9, 3, 0, 0))
+	  return 3;
+
+  /* k-regular undirected graph, even degrees, multiple edges */
+  igraph_k_regular_game(&g, 10, 4, 0, 1);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_ALL, 1);
+  igraph_vector_print(&deg);
+  if (igraph_is_directed(&g))
+	  return 14;
+  igraph_destroy(&g);
+
+  /* k-regular undirected graph, odd degrees, even number of vertices, multiple edges */
+  igraph_k_regular_game(&g, 10, 3, 0, 1);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_ALL, 1);
+  igraph_vector_print(&deg);
+  if (igraph_is_directed(&g))
+	  return 15;
+  igraph_destroy(&g);
+
+  /* k-regular undirected graph, odd degrees, odd number of vertices, multiple edges */
+  if (!igraph_k_regular_game(&g, 9, 3, 0, 1))
+	  return 4;
+
+  /* k-regular directed graph, even degrees, no multiple edges */
+  igraph_k_regular_game(&g, 10, 4, 1, 0);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_IN, 1);
+  igraph_vector_print(&deg);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_OUT, 1);
+  igraph_vector_print(&deg);
+  igraph_is_simple(&g, &is_simple);
+  if (!is_simple)
+	  return 5;
+  if (!igraph_is_directed(&g))
+	  return 5;
+  igraph_destroy(&g);
+
+  /* k-regular directed graph, odd degrees, even number of vertices, no multiple edges */
+  igraph_k_regular_game(&g, 10, 3, 1, 0);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_IN, 1);
+  igraph_vector_print(&deg);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_OUT, 1);
+  igraph_vector_print(&deg);
+  igraph_is_simple(&g, &is_simple);
+  if (!is_simple)
+	  return 6;
+  if (!igraph_is_directed(&g))
+	  return 6;
+  igraph_destroy(&g);
+
+  /* k-regular directed graph, odd degrees, odd number of vertices, no multiple edges */
+  igraph_k_regular_game(&g, 9, 3, 1, 0);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_IN, 1);
+  igraph_vector_print(&deg);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_OUT, 1);
+  igraph_vector_print(&deg);
+  igraph_is_simple(&g, &is_simple);
+  if (!is_simple)
+	  return 7;
+  if (!igraph_is_directed(&g))
+	  return 7;
+  igraph_destroy(&g);
+
+  /* k-regular directed graph, even degrees, multiple edges */
+  igraph_k_regular_game(&g, 10, 4, 1, 1);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_IN, 1);
+  igraph_vector_print(&deg);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_OUT, 1);
+  igraph_vector_print(&deg);
+  if (!igraph_is_directed(&g))
+	  return 16;
+  igraph_destroy(&g);
+
+  /* k-regular directed graph, odd degrees, even number of vertices, multiple edges */
+  igraph_k_regular_game(&g, 10, 3, 1, 1);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_IN, 1);
+  igraph_vector_print(&deg);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_OUT, 1);
+  igraph_vector_print(&deg);
+  if (!igraph_is_directed(&g))
+	  return 17;
+  igraph_destroy(&g);
+
+  /* k-regular directed graph, odd degrees, odd number of vertices, multiple edges */
+  igraph_k_regular_game(&g, 9, 3, 1, 1);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_IN, 1);
+  igraph_vector_print(&deg);
+  igraph_degree(&g, &deg, igraph_vss_all(), IGRAPH_OUT, 1);
+  igraph_vector_print(&deg);
+  if (!igraph_is_directed(&g))
+	  return 18;
+  igraph_destroy(&g);
+
+  /* k-regular undirected graph, too large degree, no multiple edges */
+  if (!igraph_k_regular_game(&g, 10, 10, 0, 0))
+	  return 8;
+
+  /* k-regular directed graph, too large degree, no multiple edges */
+  if (!igraph_k_regular_game(&g, 10, 10, 1, 0))
+	  return 9;
+
+  /* empty graph */
+  if (igraph_k_regular_game(&g, 0, 0, 0, 0))
+	  return 10;
+  if (igraph_vcount(&g) != 0 || igraph_ecount(&g) != 0 || igraph_is_directed(&g))
+	  return 11;
+  igraph_destroy(&g);
+  if (igraph_k_regular_game(&g, 0, 0, 1, 0))
+	  return 12;
+  if (igraph_vcount(&g) != 0 || igraph_ecount(&g) != 0 || !igraph_is_directed(&g))
+	  return 13;
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&deg);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_k_regular_game.out b/examples/simple/igraph_k_regular_game.out
new file mode 100644
index 0000000..8b82ce0
--- /dev/null
+++ b/examples/simple/igraph_k_regular_game.out
@@ -0,0 +1,16 @@
+4 4 4 4 4 4 4 4 4 4
+3 3 3 3 3 3 3 3 3 3
+4 4 4 4 4 4 4 4 4 4
+3 3 3 3 3 3 3 3 3 3
+4 4 4 4 4 4 4 4 4 4
+4 4 4 4 4 4 4 4 4 4
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3
+4 4 4 4 4 4 4 4 4 4
+4 4 4 4 4 4 4 4 4 4
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3
+3 3 3 3 3 3 3 3 3
diff --git a/examples/simple/igraph_knn.c b/examples/simple/igraph_knn.c
new file mode 100644
index 0000000..34a59b3
--- /dev/null
+++ b/examples/simple/igraph_knn.c
@@ -0,0 +1,42 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t v, v2;
+  
+  igraph_vector_init(&v, 0);
+  igraph_vector_init(&v2, 0);
+  igraph_ring(&g, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_avg_nearest_neighbor_degree(&g, igraph_vss_all(), &v, &v2, 
+				     /*weights=*/ 0);
+  
+  igraph_destroy(&g);
+  igraph_vector_destroy(&v);
+  igraph_vector_destroy(&v2);
+  
+  return 0;
+}
+
diff --git a/examples/simple/igraph_lapack_dgeev.c b/examples/simple/igraph_lapack_dgeev.c
new file mode 100644
index 0000000..78dee0d
--- /dev/null
+++ b/examples/simple/igraph_lapack_dgeev.c
@@ -0,0 +1,234 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+#include <stdio.h>
+
+#define DIM 10
+
+int real_cplx_mult(const igraph_matrix_t *A,
+		   const igraph_vector_t *v_real,
+		   const igraph_vector_t *v_imag, 
+		   igraph_vector_t *res_real,
+		   igraph_vector_t *res_imag) {
+
+  int n=igraph_vector_size(v_real);
+  int r, c;
+
+  if (igraph_matrix_nrow(A) != n || 
+      igraph_matrix_ncol(A) != n || 
+      igraph_vector_size(v_imag) != n) {
+    printf("Wrong matrix or vector size");
+    return 1;
+  }
+
+  igraph_vector_resize(res_real, n);
+  igraph_vector_resize(res_imag, n);
+
+  for (r=0; r<n; r++) {
+    igraph_real_t s_real=0.0;
+    igraph_real_t s_imag=0.0;
+    for (c=0; c<n; c++) {
+      s_real += MATRIX(*A, r, c) * VECTOR(*v_real)[c];
+      s_imag += MATRIX(*A, r, c) * VECTOR(*v_imag)[c];
+    }
+    VECTOR(*res_real)[r]=s_real;
+    VECTOR(*res_imag)[r]=s_imag;
+  }
+  
+  return 0;
+}
+
+int sc_cplx_cplx_mult(igraph_real_t lambda_real,
+		      igraph_real_t lambda_imag,
+		      const igraph_vector_t *v_real,
+		      const igraph_vector_t *v_imag,
+		      igraph_vector_t *res_real,
+		      igraph_vector_t *res_imag) {
+  
+  int r;
+  int n=igraph_vector_size(v_real);
+  
+  if (igraph_vector_size(v_imag) != n) {
+    printf("Wrong vector sizes");
+    return 1;
+  }
+  
+  igraph_vector_resize(res_real, n);
+  igraph_vector_resize(res_imag, n);
+
+  for (r=0; r<n; r++) {
+    VECTOR(*res_real)[r] = (lambda_real * VECTOR(*v_real)[r] -
+			    lambda_imag * VECTOR(*v_imag)[r]);
+    VECTOR(*res_imag)[r] = (lambda_imag * VECTOR(*v_real)[r] + 
+			    lambda_real * VECTOR(*v_imag)[r]);
+  }
+
+  return 0;
+}
+
+igraph_bool_t check_ev(const igraph_matrix_t *A, 
+		       const igraph_vector_t *values_real,
+		       const igraph_vector_t *values_imag,
+		       const igraph_matrix_t *vectors_left, 
+		       const igraph_matrix_t *vectors_right, 
+		       igraph_real_t tol) {
+
+  int i, n=igraph_matrix_nrow(A);
+  igraph_vector_t v_real, v_imag;
+  igraph_vector_t AV_real, AV_imag, lv_real, lv_imag;
+  igraph_vector_t null;
+  
+  if (igraph_matrix_ncol(A)             != n) { return 1; }
+  if (igraph_vector_size(values_real)   != n) { return 1; }
+  if (igraph_vector_size(values_imag)   != n) { return 1; }
+  if (igraph_matrix_nrow(vectors_left)  != n) { return 1; }
+  if (igraph_matrix_ncol(vectors_left)  != n) { return 1; }
+  if (igraph_matrix_nrow(vectors_right) != n) { return 1; }
+  if (igraph_matrix_ncol(vectors_right) != n) { return 1; }
+
+  igraph_vector_init(&AV_real, n);
+  igraph_vector_init(&AV_imag, n);
+  igraph_vector_init(&lv_real, n);
+  igraph_vector_init(&lv_imag, n);
+  igraph_vector_init(&null, n);
+  igraph_vector_null(&null);
+
+  for (i=0; i<n; i++) {
+    if (VECTOR(*values_imag)[i]==0.0) {
+      igraph_vector_view(&v_real, &MATRIX(*vectors_right, 0, i), n);
+      igraph_vector_view(&v_imag, VECTOR(null), n);
+    } else if (VECTOR(*values_imag)[i] > 0.0) {
+      igraph_vector_view(&v_real, &MATRIX(*vectors_right, 0, i), n);
+      igraph_vector_view(&v_imag, &MATRIX(*vectors_right, 0, i+1), n);
+    } else if (VECTOR(*values_imag)[i] < 0.0) {
+      igraph_vector_view(&v_real, &MATRIX(*vectors_right, 0, i-1), n);
+      igraph_vector_view(&v_imag, &MATRIX(*vectors_right, 0, i), n);
+      igraph_vector_scale(&v_imag, -1.0);
+    }
+    real_cplx_mult(A, &v_real, &v_imag, &AV_real, &AV_imag);
+    sc_cplx_cplx_mult(VECTOR(*values_real)[i], VECTOR(*values_imag)[i],
+		      &v_real, &v_imag, &lv_real, &lv_imag);
+    
+    if (igraph_vector_maxdifference(&AV_real, &lv_real) > tol ||
+	igraph_vector_maxdifference(&AV_imag, &lv_imag) > tol) {
+      printf("ERROR:\n");
+      igraph_vector_print(&AV_real); igraph_vector_print(&AV_imag);
+      igraph_vector_print(&lv_real); igraph_vector_print(&lv_imag);      
+      return 1;
+    }
+  }
+
+  igraph_vector_destroy(&null);
+  igraph_vector_destroy(&AV_imag);
+  igraph_vector_destroy(&AV_real);
+  igraph_vector_destroy(&lv_imag);
+  igraph_vector_destroy(&lv_real);
+  
+  return 0;
+}
+
+int main() {
+  
+  igraph_matrix_t A;
+  igraph_matrix_t vectors_left, vectors_right;
+  igraph_vector_t values_real, values_imag;
+  int i, j;
+  int info=1;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&vectors_left, 0, 0);
+  igraph_matrix_init(&vectors_right, 0, 0);
+  igraph_vector_init(&values_real, 0);
+  igraph_vector_init(&values_imag, 0);
+
+  for (i=0; i<DIM; i++) {
+    for (j=0; j<DIM; j++) {
+      MATRIX(A, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  
+  igraph_lapack_dgeev(&A, &values_real, &values_imag,
+  		      &vectors_left, &vectors_right, &info);
+
+  if (check_ev(&A, &values_real, &values_imag,
+  	       &vectors_left, &vectors_right, /*tol=*/ 1e-8)) {
+    return 1;
+  }
+
+  /* ------------------------------------------------------- */
+
+  /* igraph_matrix_resize(&A, 10, 10); */
+  /* igraph_matrix_null(&A); */
+  /* for (i=0; i<10; i++) { MATRIX(A, i, i) = 1.0; }  */
+  /* MATRIX(A,0,1) = 1.0; */
+
+  /* igraph_lapack_dgeev(&A, &values_real, &values_imag,  */
+  /* 		      &vectors_left, &vectors_right, &info);   */
+
+  /* if (check_ev(&A, &values_real, &values_imag, */
+  /* 	       &vectors_left, &vectors_right, /\*tol=*\/ 1e-8)) { */
+  /*   return 2; */
+  /* } */
+
+  /* ------------------------------------------------------- */
+    
+  igraph_matrix_resize(&A, 10, 10);
+  igraph_matrix_null(&A);
+  MATRIX(A,0,1) = MATRIX(A,0,2) = MATRIX(A,0,3) = 1/3.0;
+  MATRIX(A,1,0) = MATRIX(A,1,4) = MATRIX(A,1,5) = MATRIX(A,1,6) = 1/4.0;
+  MATRIX(A,2,0) = MATRIX(A,2,7) = MATRIX(A,2,8) = MATRIX(A,2,9) = 1/4.0;
+  MATRIX(A,3,0) = 1.0;
+  MATRIX(A,4,1) = 1.0;
+  MATRIX(A,5,1) = 1.0;
+  MATRIX(A,6,1) = 1.0;
+  MATRIX(A,7,2) = 1.0;
+  MATRIX(A,8,2) = 1.0;
+  MATRIX(A,9,2) = 1.0;
+
+  info=0;
+  igraph_lapack_dgeev(&A, &values_real, &values_imag,
+  		      &vectors_left, &vectors_right, &info);
+
+  /* igraph_matrix_print(&A); */
+  /* printf("---\n"); */
+  /* igraph_vector_print(&values_real); */
+  /* igraph_vector_print(&values_imag); */
+  /* igraph_matrix_print(&vectors_left); */
+
+  if (check_ev(&A, &values_real, &values_imag,
+  	       &vectors_left, &vectors_right, /*tol=*/ 1e-8)) {
+    return 3;
+  }
+
+  igraph_vector_destroy(&values_imag);
+  igraph_vector_destroy(&values_real);
+  igraph_matrix_destroy(&vectors_right);
+  igraph_matrix_destroy(&vectors_left);
+  igraph_matrix_destroy(&A);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_lapack_dgeevx.c b/examples/simple/igraph_lapack_dgeevx.c
new file mode 100644
index 0000000..7b9d0e3
--- /dev/null
+++ b/examples/simple/igraph_lapack_dgeevx.c
@@ -0,0 +1,200 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+#include <stdio.h>
+
+#define DIM 10
+
+int real_cplx_mult(const igraph_matrix_t *A,
+		   const igraph_vector_t *v_real,
+		   const igraph_vector_t *v_imag, 
+		   igraph_vector_t *res_real,
+		   igraph_vector_t *res_imag) {
+
+  int n=igraph_vector_size(v_real);
+  int r, c;
+
+  if (igraph_matrix_nrow(A) != n || 
+      igraph_matrix_ncol(A) != n || 
+      igraph_vector_size(v_imag) != n) {
+    printf("Wrong matrix or vector size");
+    return 1;
+  }
+
+  igraph_vector_resize(res_real, n);
+  igraph_vector_resize(res_imag, n);
+
+  for (r=0; r<n; r++) {
+    igraph_real_t s_real=0.0;
+    igraph_real_t s_imag=0.0;
+    for (c=0; c<n; c++) {
+      s_real += MATRIX(*A, r, c) * VECTOR(*v_real)[c];
+      s_imag += MATRIX(*A, r, c) * VECTOR(*v_imag)[c];
+    }
+    VECTOR(*res_real)[r]=s_real;
+    VECTOR(*res_imag)[r]=s_imag;
+  }
+  
+  return 0;
+}
+
+int sc_cplx_cplx_mult(igraph_real_t lambda_real,
+		      igraph_real_t lambda_imag,
+		      const igraph_vector_t *v_real,
+		      const igraph_vector_t *v_imag,
+		      igraph_vector_t *res_real,
+		      igraph_vector_t *res_imag) {
+  
+  int r;
+  int n=igraph_vector_size(v_real);
+  
+  if (igraph_vector_size(v_imag) != n) {
+    printf("Wrong vector sizes");
+    return 1;
+  }
+  
+  igraph_vector_resize(res_real, n);
+  igraph_vector_resize(res_imag, n);
+
+  for (r=0; r<n; r++) {
+    VECTOR(*res_real)[r] = (lambda_real * VECTOR(*v_real)[r] -
+			    lambda_imag * VECTOR(*v_imag)[r]);
+    VECTOR(*res_imag)[r] = (lambda_imag * VECTOR(*v_real)[r] + 
+			    lambda_real * VECTOR(*v_imag)[r]);
+  }
+
+  return 0;
+}
+
+igraph_bool_t check_ev(const igraph_matrix_t *A, 
+		       const igraph_vector_t *values_real,
+		       const igraph_vector_t *values_imag,
+		       const igraph_matrix_t *vectors_left, 
+		       const igraph_matrix_t *vectors_right, 
+		       igraph_real_t tol) {
+
+  int n=igraph_matrix_nrow(A);
+  igraph_vector_t v_real, v_imag;
+  igraph_vector_t AV_real, AV_imag, lv_real, lv_imag;
+  igraph_vector_t null;
+  int i;
+  
+  if (igraph_matrix_ncol(A)             != n) { return 1; }
+  if (igraph_vector_size(values_real)   != n) { return 1; }
+  if (igraph_vector_size(values_imag)   != n) { return 1; }
+  if (igraph_matrix_nrow(vectors_left)  != n) { return 1; }
+  if (igraph_matrix_ncol(vectors_left)  != n) { return 1; }
+  if (igraph_matrix_nrow(vectors_right) != n) { return 1; }
+  if (igraph_matrix_ncol(vectors_right) != n) { return 1; }
+
+  igraph_vector_init(&AV_real, n);
+  igraph_vector_init(&AV_imag, n);
+  igraph_vector_init(&lv_real, n);
+  igraph_vector_init(&lv_imag, n);
+  igraph_vector_init(&null, n);
+  igraph_vector_null(&null);
+
+  for (i=0; i<n; i++) {
+    if (VECTOR(*values_imag)[i]==0.0) {
+      igraph_vector_view(&v_real, &MATRIX(*vectors_right, 0, i), n);
+      igraph_vector_view(&v_imag, VECTOR(null), n);
+    } else if (VECTOR(*values_imag)[i] > 0.0) {
+      igraph_vector_view(&v_real, &MATRIX(*vectors_right, 0, i), n);
+      igraph_vector_view(&v_imag, &MATRIX(*vectors_right, 0, i+1), n);
+    } else if (VECTOR(*values_imag)[i] < 0.0) {
+      igraph_vector_view(&v_real, &MATRIX(*vectors_right, 0, i-1), n);
+      igraph_vector_view(&v_imag, &MATRIX(*vectors_right, 0, i), n);
+      igraph_vector_scale(&v_imag, -1.0);
+    }
+    real_cplx_mult(A, &v_real, &v_imag, &AV_real, &AV_imag);
+    sc_cplx_cplx_mult(VECTOR(*values_real)[i], VECTOR(*values_imag)[i],
+		      &v_real, &v_imag, &lv_real, &lv_imag);
+    
+    if (igraph_vector_maxdifference(&AV_real, &lv_real) > tol ||
+	igraph_vector_maxdifference(&AV_imag, &lv_imag) > tol) {
+      igraph_vector_print(&AV_real); igraph_vector_print(&AV_imag);
+      igraph_vector_print(&lv_real); igraph_vector_print(&lv_imag);      
+      return 1;
+    }
+  }
+
+  igraph_vector_destroy(&null);
+  igraph_vector_destroy(&AV_imag);
+  igraph_vector_destroy(&AV_real);
+  igraph_vector_destroy(&lv_imag);
+  igraph_vector_destroy(&lv_real);
+  
+  return 0;
+}
+
+int main() {
+  
+  igraph_matrix_t A;
+  igraph_matrix_t vectors_left, vectors_right;
+  igraph_vector_t values_real, values_imag;
+  int i, j;
+  int info=1;
+  int ilo, ihi;
+  igraph_real_t abnrm;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&vectors_left, 0, 0);
+  igraph_matrix_init(&vectors_right, 0, 0);
+  igraph_vector_init(&values_real, 0);
+  igraph_vector_init(&values_imag, 0);
+
+  for (i=0; i<DIM; i++) {
+    for (j=0; j<DIM; j++) {
+      MATRIX(A, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  
+  igraph_lapack_dgeevx(IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH,
+		       &A, &values_real, &values_imag, 
+		       &vectors_left, &vectors_right, &ilo, &ihi,
+		       /*scale=*/ 0, &abnrm, /*rconde=*/ 0, 
+		       /*rcondv=*/ 0, &info);
+
+  if (check_ev(&A, &values_real, &values_imag, 
+	       &vectors_left, &vectors_right, /*tol=*/ 1e-8)) {
+    return 1;
+  }
+  
+  /* igraph_matrix_print(&A); */
+  /* igraph_vector_print(&values_real); */
+  /* igraph_vector_print(&values_imag); */
+  /* igraph_matrix_print(&vectors_left); */
+  /* igraph_matrix_print(&vectors_right); */
+  
+  igraph_vector_destroy(&values_imag);
+  igraph_vector_destroy(&values_real);
+  igraph_matrix_destroy(&vectors_right);
+  igraph_matrix_destroy(&vectors_left);
+  igraph_matrix_destroy(&A);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_lapack_dgehrd.c b/examples/simple/igraph_lapack_dgehrd.c
new file mode 100644
index 0000000..9350981
--- /dev/null
+++ b/examples/simple/igraph_lapack_dgehrd.c
@@ -0,0 +1,74 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  int nodes=10;
+  igraph_t tree;
+  igraph_matrix_t sto;
+  igraph_matrix_t hess;
+  igraph_matrix_complex_t evec1, evec2;
+  igraph_vector_complex_t eval1, eval2;
+  igraph_eigen_which_t which;
+  int i;
+
+  igraph_tree(&tree, nodes, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_matrix_init(&sto, nodes, nodes);
+  igraph_get_stochastic(&tree, &sto, /*column_wise=*/ 0);
+  igraph_matrix_transpose(&sto);
+  
+  igraph_matrix_init(&hess, nodes, nodes);
+  igraph_lapack_dgehrd(&sto, 1, nodes, &hess);
+  
+  igraph_matrix_complex_init(&evec1, 0, 0);
+  igraph_vector_complex_init(&eval1, 0);
+  which.pos = IGRAPH_EIGEN_ALL;
+  igraph_eigen_matrix(&sto, 0, 0, nodes, 0, IGRAPH_EIGEN_LAPACK, &which, 0, 0,
+		      &eval1, &evec1);
+
+  igraph_matrix_complex_init(&evec2, 0, 0);
+  igraph_vector_complex_init(&eval2, 0);
+  igraph_eigen_matrix(&hess, 0, 0, nodes, 0, IGRAPH_EIGEN_LAPACK, &which, 0, 
+		      0, &eval2, &evec2);
+
+  for (i=0; i<nodes; i++) { 
+    igraph_real_t d=igraph_complex_abs(igraph_complex_sub(VECTOR(eval1)[i],
+							  VECTOR(eval2)[i]));
+    if (d > 1e-14) { printf("Difference: %g\n", d); return 1; }
+  }
+  
+  igraph_matrix_complex_destroy(&evec2);
+  igraph_vector_complex_destroy(&eval2);
+
+  igraph_matrix_complex_destroy(&evec1);
+  igraph_vector_complex_destroy(&eval1);
+  
+  igraph_matrix_destroy(&hess);
+  igraph_matrix_destroy(&sto);
+  igraph_destroy(&tree);
+    
+  return 0;
+}
diff --git a/examples/simple/igraph_lapack_dgehrd.out b/examples/simple/igraph_lapack_dgehrd.out
new file mode 100644
index 0000000..e69de29
diff --git a/examples/simple/igraph_lapack_dgesv.c b/examples/simple/igraph_lapack_dgesv.c
new file mode 100644
index 0000000..b5eba97
--- /dev/null
+++ b/examples/simple/igraph_lapack_dgesv.c
@@ -0,0 +1,141 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+#include <stdio.h>
+
+#define DIM 10
+
+void igraph_print_warning(const char *reason, const char *file, 
+			  int line, int igraph_errno) {
+  printf("Warning: %s\n", reason);
+}
+
+int main() {
+
+  igraph_matrix_t A, B, RHS;
+  int info;
+  int i;
+
+  /* Identity matrix, you have to start somewhere */
+
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&B, DIM, 1);
+  for (i=0; i<DIM; i++) {
+    MATRIX(A, i, i) = 1.0;
+    MATRIX(B, i, 0) = i+1;
+  }
+
+  igraph_matrix_copy(&RHS, &B);
+  igraph_lapack_dgesv(&A, /*ipiv=*/ 0, &RHS, &info);
+
+  if (info != 0) { return 1;}
+  if (!igraph_matrix_all_e(&B, &RHS)) { return 2; }
+  
+  igraph_matrix_destroy(&A);
+  igraph_matrix_destroy(&B);
+  igraph_matrix_destroy(&RHS);
+
+  /* Diagonal matrix */
+
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&RHS, DIM, 1);
+  for (i=0; i<DIM; i++) {
+    MATRIX(A, i, i) = i+1;
+    MATRIX(RHS, i, 0) = i+1;
+  }
+
+  igraph_lapack_dgesv(&A, /*ipiv=*/ 0, &RHS, &info);
+
+  if (info != 0) { return 3;}
+  for (i=0; i<DIM; i++) {
+    if (MATRIX(RHS, i, 0) != 1.0) { return 4; }
+  }
+  
+  igraph_matrix_destroy(&A);
+  igraph_matrix_destroy(&RHS);  
+
+  /* A general matrix */
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&B, DIM, 1);
+  igraph_matrix_init(&RHS, DIM, 1);
+  for (i=0; i<DIM; i++) {
+    int j;
+    MATRIX(B, i, 0) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    for (j=0; j<DIM; j++) {
+      MATRIX(A, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  igraph_blas_dgemv_array(/*transpose=*/ 0, /*alpha=*/ 1.0, /*a=*/ &A, 
+			  /*x-*/ &MATRIX(B, 0, 0), /*beta=*/ 0,
+			  /*y=*/ &MATRIX(RHS, 0, 0));
+
+  igraph_lapack_dgesv(&A, /*ipiv=*/ 0, &RHS, &info);
+  if (info != 0) { return 5; }
+  for (i=0; i<DIM; i++) {
+    if (fabs(MATRIX(B, i, 0) - MATRIX(RHS, i, 0)) > 1e-13) { return 6; }
+  }
+  
+  igraph_matrix_destroy(&A);
+  igraph_matrix_destroy(&B);
+  igraph_matrix_destroy(&RHS);
+
+  /* A singular matrix */
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&B, DIM, 1);
+  igraph_matrix_init(&RHS, DIM, 1);
+  for (i=0; i<DIM; i++) {
+    int j;
+    MATRIX(B, i, 0) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    for (j=0; j<DIM; j++) {
+      MATRIX(A, i, j) = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  for (i=0; i<DIM; i++) {
+    MATRIX(A, DIM-1, i) = MATRIX(A, 0, i);
+  }
+
+  igraph_blas_dgemv_array(/*transpose=*/ 0, /*alpha=*/ 1.0, /*a=*/ &A, 
+			  /*x-*/ &MATRIX(B, 0, 0), /*beta=*/ 0,
+			  /*y=*/ &MATRIX(RHS, 0, 0));
+
+  igraph_set_warning_handler(igraph_print_warning);
+  igraph_lapack_dgesv(&A, /*ipiv=*/ 0, &RHS, &info);
+  if (info != 10) {
+    printf("LAPACK returned info = %d, should have been 10", info);
+    return 7;
+  }
+  
+  igraph_matrix_destroy(&A);
+  igraph_matrix_destroy(&B);
+  igraph_matrix_destroy(&RHS);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_lapack_dgesv.out b/examples/simple/igraph_lapack_dgesv.out
new file mode 100644
index 0000000..c78aad1
--- /dev/null
+++ b/examples/simple/igraph_lapack_dgesv.out
@@ -0,0 +1 @@
+Warning: LU: factor is exactly singular
diff --git a/examples/simple/igraph_lapack_dsyevr.c b/examples/simple/igraph_lapack_dsyevr.c
new file mode 100644
index 0000000..1325d12
--- /dev/null
+++ b/examples/simple/igraph_lapack_dsyevr.c
@@ -0,0 +1,189 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <time.h>
+
+#define DIM 10
+
+igraph_bool_t check_ev(const igraph_matrix_t *A, 
+		       const igraph_vector_t *values,
+		       const igraph_matrix_t *vectors, igraph_real_t tol) {
+  igraph_vector_t v, y;
+  int i, j;
+  int m=igraph_matrix_ncol(vectors);
+  int n=igraph_matrix_nrow(A);
+  
+  if (igraph_matrix_ncol(A) != n)       { return 1; }
+  if (igraph_vector_size(values) != m)  { return 1; }
+  if (igraph_matrix_nrow(vectors) != n) { return 1; }
+
+  igraph_vector_init(&y, n);
+
+  for (i=0; i<m; i++) {
+    igraph_vector_view(&v, &MATRIX(*vectors, 0, i), n);
+    igraph_vector_update(&y, &v);
+    igraph_blas_dgemv(/*transpose=*/ 0, /*alpha=*/ 1.0, A, &v, 
+		      /*beta=*/ -VECTOR(*values)[i], &y);
+    for (j=0; j<n; j++) {
+      if (fabs(VECTOR(y)[i]) > tol) {
+	printf("Matrix:\n"); igraph_matrix_print(A);
+	printf("lambda= %g\n", VECTOR(*values)[i]);
+	printf("v= "); igraph_vector_print(&v);
+	printf("residual: "); igraph_vector_print(&y);
+	return 1; 
+      }
+    }
+  }
+  
+  igraph_vector_destroy(&y);
+  return 0;
+}
+
+int main() {
+
+  igraph_matrix_t A;
+  igraph_matrix_t vectors, vectors2;
+  igraph_vector_t values, values2;
+  int i, j;
+  int il, iu;
+  igraph_real_t vl, vu;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_matrix_init(&A, DIM, DIM);
+  igraph_matrix_init(&vectors, 0, 0);
+  igraph_vector_init(&values, 0);
+
+  /* All eigenvalues and eigenvectors */
+
+  for (i=0; i<DIM; i++) {
+    for (j=i; j<DIM; j++) {
+      MATRIX(A, i, j) = MATRIX(A, j, i) = 
+	igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    }
+  }
+  
+  igraph_lapack_dsyevr(&A, IGRAPH_LAPACK_DSYEV_ALL, /*vl=*/ 0, /*vu=*/ 0,
+		       /*vestimate=*/ 0, /*il=*/ 0, /*iu=*/ 0, 
+		       /*abstol=*/ 1e-10, &values, &vectors, /*support=*/ 0);
+
+  if (igraph_vector_size(&values) != DIM) { return 1; }
+  if (igraph_matrix_nrow(&vectors) != DIM || 
+      igraph_matrix_ncol(&vectors) != DIM) { return 2; }
+  if (check_ev(&A, &values, &vectors, /*tol=*/ 1e-8)) { return 3; }
+
+  /* Only a subset */
+  
+  igraph_matrix_init(&vectors2, 0, 0);
+  igraph_vector_init(&values2, 0);
+
+  il=2; iu=5;
+  igraph_lapack_dsyevr(&A, IGRAPH_LAPACK_DSYEV_SELECT, /*vl=*/ 0, /*vu=*/ 0,
+		       /*vestimate=*/ 0, /*il=*/ il, /*iu=*/ iu, 
+		       /*abstol=*/ 1e-10, &values2, &vectors2, 
+		       /*support=*/ 0);
+  
+  if (igraph_vector_size(&values2) != iu-il+1) { return 4; }
+  if (igraph_matrix_nrow(&vectors2) != DIM ||
+      igraph_matrix_ncol(&vectors2) != iu-il+1) { return 5; }
+  for (i=0; i<iu-il+1; i++) {
+    igraph_real_t m1=1.0;
+
+    if (fabs(VECTOR(values)[il+i-1] - VECTOR(values2)[i]) > 1e-8) {
+      printf("Full:   "); igraph_vector_print(&values);
+      printf("Subset: "); igraph_vector_print(&values2);
+      return 6;
+    }
+
+    if (MATRIX(vectors, 0, il+i-1) * MATRIX(vectors2, 0, i) < 0) {
+      m1=-1.0;
+    } else { 
+      m1=1.0;
+    }
+
+    for (j=0; j<DIM; j++) {
+      if (fabs(MATRIX(vectors, j, il+i-1) - 
+	       m1 * MATRIX(vectors2, j, i)) > 1e-8) {
+	printf("Full:\n"); igraph_matrix_print(&vectors);
+	printf("Subset:\n"); igraph_matrix_print(&vectors2);
+	return 7;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&values2);
+  igraph_matrix_destroy(&vectors2);
+  
+  /* Subset based on an interval */
+
+  igraph_matrix_init(&vectors2, 0, 0);
+  igraph_vector_init(&values2, 0);
+
+  il=2; iu=5;
+  vl = (VECTOR(values)[il-1] + VECTOR(values)[il-2]) / 2.0;   
+  vu = (VECTOR(values)[iu] + VECTOR(values)[iu-1]) / 2.0;
+
+  igraph_lapack_dsyevr(&A, IGRAPH_LAPACK_DSYEV_INTERVAL, vl, vu, 
+		       /*vestimate=*/ iu-il+1, /*il=*/ 0, /*iu=*/ 0, 
+		       /*abstol=*/ 1e-10, &values2, &vectors2, 
+		       /*support=*/ 0);
+
+  if (igraph_vector_size(&values2) != iu-il+1) { return 4; }
+  if (igraph_matrix_nrow(&vectors2) != DIM ||
+      igraph_matrix_ncol(&vectors2) != iu-il+1) { return 5; }
+  for (i=0; i<iu-il+1; i++) {
+    igraph_real_t m1=1.0;
+
+    if (fabs(VECTOR(values)[il+i-1] - VECTOR(values2)[i]) > 1e-8) {
+      printf("Full:   "); igraph_vector_print(&values);
+      printf("Subset: "); igraph_vector_print(&values2);
+      return 6;
+    }
+
+    if (MATRIX(vectors, 0, il+i-1) * MATRIX(vectors2, 0, i) < 0) {
+      m1=-1.0;
+    } else { 
+      m1=1.0;
+    }
+
+    for (j=0; j<DIM; j++) {
+      if (fabs(MATRIX(vectors, j, il+i-1) - 
+	       m1 * MATRIX(vectors2, j, i)) > 1e-8) {
+	printf("Full:\n"); igraph_matrix_print(&vectors);
+	printf("Subset:\n"); igraph_matrix_print(&vectors2);
+	return 7;
+      }
+    }
+  }  
+
+  igraph_vector_destroy(&values2);
+  igraph_matrix_destroy(&vectors2);
+
+  igraph_vector_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+  igraph_matrix_destroy(&A);
+
+  return 0;
+}
+
diff --git a/examples/simple/igraph_laplacian.c b/examples/simple/igraph_laplacian.c
new file mode 100644
index 0000000..bd5b0c1
--- /dev/null
+++ b/examples/simple/igraph_laplacian.c
@@ -0,0 +1,236 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+igraph_bool_t check_laplacian(igraph_t* graph, igraph_matrix_t* matrix, igraph_vector_t* w) {
+  igraph_vector_t vec, res;
+  long int i, j;
+
+  igraph_vector_init(&vec, 0);
+  igraph_vector_init(&res, igraph_vcount(graph));
+
+  if (w)
+    igraph_strength(graph, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS, w);
+  else
+    igraph_degree(graph, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS);
+
+  for (i = 0; i < igraph_vcount(graph); i++) {
+    VECTOR(vec)[i] = sqrt(VECTOR(vec)[i]);
+  }
+
+  for (i = 0; i < igraph_vcount(graph); i++) {
+    for (j = 0; j < igraph_vcount(graph); j++) {
+      VECTOR(res)[i] += MATRIX(*matrix, i, j) * VECTOR(vec)[j];
+    }
+  }
+
+  if (igraph_vector_min(&res) > 1e-7) {
+    printf("Invalid Laplacian matrix:\n");
+    igraph_matrix_print(matrix);
+    return 0;
+  }
+
+  igraph_vector_destroy(&vec);
+  igraph_vector_destroy(&res);
+
+  return 1;
+}
+
+int test_unnormalized_laplacian(igraph_vector_t* w, igraph_bool_t dir) {
+  igraph_t g;
+  igraph_matrix_t m, m2;
+  igraph_sparsemat_t sm;
+  igraph_vector_t vec, *weights = 0;
+  igraph_matrix_init(&m, 1, 1);
+  igraph_sparsemat_init(&sm, 0, 0, 0);
+
+  if (w) {
+    weights = (igraph_vector_t*)calloc(1, sizeof(igraph_vector_t));
+    igraph_vector_copy(weights, w);
+  }
+
+  /* No loop or multiple edges */
+  igraph_ring(&g, 5, dir, 0, 1);
+  igraph_laplacian(&g, &m, &sm, 0, weights);
+  igraph_matrix_init(&m2, 0, 0);
+  igraph_sparsemat_as_matrix(&m2, &sm);
+  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
+    return 41;
+  }
+  igraph_matrix_destroy(&m2);
+  igraph_matrix_print(&m);
+  printf("===\n");
+
+  /* Add some loop edges */
+  igraph_vector_init_real(&vec, 4, 1.0, 1.0, 2.0, 2.0);
+  igraph_add_edges(&g, &vec, 0);
+  igraph_vector_destroy(&vec);
+  if (weights) {
+    igraph_vector_push_back(weights, 2);
+    igraph_vector_push_back(weights, 2);
+  }
+
+  igraph_laplacian(&g, &m, &sm, 0, weights);
+  igraph_matrix_init(&m2, 0, 0);
+  igraph_sparsemat_as_matrix(&m2, &sm);
+  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
+    return 42;
+  }
+  igraph_matrix_destroy(&m2);
+  igraph_matrix_print(&m);
+  printf("===\n");
+
+  /* Duplicate some edges */
+  igraph_vector_init_real(&vec, 4, 1.0, 2.0, 3.0, 4.0);
+  igraph_add_edges(&g, &vec, 0);
+  igraph_vector_destroy(&vec);
+  if (weights) {
+    igraph_vector_push_back(weights, 3);
+    igraph_vector_push_back(weights, 3);
+  }
+
+  igraph_laplacian(&g, &m, &sm, 0, weights);
+  igraph_matrix_init(&m2, 0, 0);
+  igraph_sparsemat_as_matrix(&m2, &sm);
+  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
+    return 43;
+  }
+  igraph_matrix_destroy(&m2);
+  igraph_matrix_print(&m);
+
+  igraph_destroy(&g);
+
+  igraph_matrix_destroy(&m);
+  if (weights) {
+    igraph_vector_destroy(weights); free(weights);
+  }
+
+  return 0;
+}
+
+int test_normalized_laplacian(igraph_vector_t *w, igraph_bool_t dir) {
+  igraph_t g;
+  igraph_matrix_t m, m2;
+  igraph_sparsemat_t sm;
+  igraph_vector_t vec, *weights = 0;
+  igraph_bool_t ok = 1;
+  igraph_matrix_init(&m, 1, 1);
+  igraph_sparsemat_init(&sm, 0, 0, 0);
+
+  if (w) {
+    weights = (igraph_vector_t*)calloc(1, sizeof(igraph_vector_t));
+    igraph_vector_copy(weights, w);
+  }
+
+  /* Undirected graph, no loop or multiple edges */
+  igraph_ring(&g, 5, dir, 0, 1);
+  igraph_laplacian(&g, &m, &sm, 1, weights);
+  igraph_matrix_init(&m2, 0, 0);
+  igraph_sparsemat_as_matrix(&m2, &sm);
+  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
+    return 44;
+  }
+  igraph_matrix_destroy(&m2);
+  ok = ok && check_laplacian(&g, &m, weights);
+
+  /* Add some loop edges */
+  igraph_vector_init_real(&vec, 4, 1.0, 1.0, 2.0, 2.0);
+  igraph_add_edges(&g, &vec, 0);
+  igraph_vector_destroy(&vec);
+  if (weights) {
+    igraph_vector_push_back(weights, 2);
+    igraph_vector_push_back(weights, 2);
+  }
+
+  igraph_laplacian(&g, &m, &sm, 1, weights);
+  igraph_matrix_init(&m2, 0, 0);
+  igraph_sparsemat_as_matrix(&m2, &sm);
+  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
+    return 45;
+  }
+  igraph_matrix_destroy(&m2);
+  ok = ok && check_laplacian(&g, &m, weights);
+
+  /* Duplicate some edges */
+  igraph_vector_init_real(&vec, 4, 1.0, 2.0, 3.0, 4.0);
+  igraph_add_edges(&g, &vec, 0);
+  igraph_vector_destroy(&vec);
+  if (weights) {
+    igraph_vector_push_back(weights, 3);
+    igraph_vector_push_back(weights, 3);
+  }
+
+  igraph_laplacian(&g, &m, &sm, 1, weights);
+  igraph_matrix_init(&m2, 0, 0);
+  igraph_sparsemat_as_matrix(&m2, &sm);
+  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
+    return 46;
+  }
+  igraph_matrix_destroy(&m2);
+  ok = ok && check_laplacian(&g, &m, weights);
+
+  igraph_destroy(&g);
+
+  igraph_matrix_destroy(&m);
+  if (weights) {
+    igraph_vector_destroy(weights); free(weights);
+  }
+
+  if (ok)
+    printf("OK\n");
+
+  return !ok;
+}
+
+int main() {
+  int res;
+  int i;
+  igraph_vector_t weights;
+
+  igraph_vector_init_real(&weights, 5, 1.0, 2.0, 3.0, 4.0, 5.0);
+
+  for (i = 0; i < 8; i++) {
+    igraph_bool_t is_normalized = i / 4;
+    igraph_vector_t* v = ((i & 2) / 2 ? &weights : 0);
+    igraph_bool_t dir = (i % 2 ? IGRAPH_DIRECTED : IGRAPH_UNDIRECTED);
+
+    printf("=== %sormalized, %sweighted, %sdirected\n",
+      (is_normalized ? "N" : "Unn"),
+      (v != 0 ? "" : "un"),
+      (dir == IGRAPH_DIRECTED ? "" : "un")
+    );
+
+    if (is_normalized)
+      res = test_normalized_laplacian(v, dir);
+    else
+      res = test_unnormalized_laplacian(v, dir);
+
+    if (res)
+      return i+1;
+  }
+
+  igraph_vector_destroy(&weights);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_laplacian.out b/examples/simple/igraph_laplacian.out
new file mode 100644
index 0000000..b8aabc4
--- /dev/null
+++ b/examples/simple/igraph_laplacian.out
@@ -0,0 +1,80 @@
+=== Unnormalized, unweighted, undirected
+2 -1 0 0 -1
+-1 2 -1 0 0
+0 -1 2 -1 0
+0 0 -1 2 -1
+-1 0 0 -1 2
+===
+2 -1 0 0 -1
+-1 2 -1 0 0
+0 -1 2 -1 0
+0 0 -1 2 -1
+-1 0 0 -1 2
+===
+2 -1 0 0 -1
+-1 3 -2 0 0
+0 -2 3 -1 0
+0 0 -1 3 -2
+-1 0 0 -2 3
+=== Unnormalized, unweighted, directed
+1 -1 0 0 0
+0 1 -1 0 0
+0 0 1 -1 0
+0 0 0 1 -1
+-1 0 0 0 1
+===
+1 -1 0 0 0
+0 1 -1 0 0
+0 0 1 -1 0
+0 0 0 1 -1
+-1 0 0 0 1
+===
+1 -1 0 0 0
+0 2 -2 0 0
+0 0 1 -1 0
+0 0 0 2 -2
+-1 0 0 0 1
+=== Unnormalized, weighted, undirected
+6 -1 0 0 -5
+-1 3 -2 0 0
+0 -2 5 -3 0
+0 0 -3 7 -4
+-5 0 0 -4 9
+===
+6 -1 0 0 -5
+-1 3 -2 0 0
+0 -2 5 -3 0
+0 0 -3 7 -4
+-5 0 0 -4 9
+===
+6 -1 0 0 -5
+-1 6 -5 0 0
+0 -5 8 -3 0
+0 0 -3 10 -7
+-5 0 0 -7 12
+=== Unnormalized, weighted, directed
+1 -1 0 0 0
+0 2 -2 0 0
+0 0 3 -3 0
+0 0 0 4 -4
+-5 0 0 0 5
+===
+1 -1 0 0 0
+0 2 -2 0 0
+0 0 3 -3 0
+0 0 0 4 -4
+-5 0 0 0 5
+===
+1 -1 0 0 0
+0 5 -5 0 0
+0 0 3 -3 0
+0 0 0 7 -7
+-5 0 0 0 5
+=== Normalized, unweighted, undirected
+OK
+=== Normalized, unweighted, directed
+OK
+=== Normalized, weighted, undirected
+OK
+=== Normalized, weighted, directed
+OK
diff --git a/examples/simple/igraph_lattice.c b/examples/simple/igraph_lattice.c
new file mode 100644
index 0000000..e2586df
--- /dev/null
+++ b/examples/simple/igraph_lattice.c
@@ -0,0 +1,180 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+typedef struct {
+  int dim;
+  int m;
+  int nei;
+  igraph_bool_t directed, mutual, circular;
+  igraph_real_t *dimedges;
+} lat_test_t;
+
+#define LAT_TEST(id, d, m, ne, di, mu, ci, ...) \
+  igraph_real_t lat_ ## id ## _edges[] = { __VA_ARGS__ } ; \
+  lat_test_t lat_ ## id = { d, m, ne, di, mu, ci, lat_ ## id ## _edges }
+
+/*----------------d--m--ne-di-mu-ci-dimedges------------------------*/
+LAT_TEST(u_0,     0, 0, 1, 0, 0, 0,  -1 );
+LAT_TEST(u_01,    1, 0, 1, 0, 0, 0,  0 );
+LAT_TEST(u_02,    2, 0, 1, 0, 0, 0,  0, 1 );
+LAT_TEST(u_03,    2, 0, 1, 0, 0, 0,  1, 0 );
+
+LAT_TEST(d_0,     0, 0, 1, 1, 0, 0,  -1 );
+LAT_TEST(d_01,    1, 0, 1, 1, 0, 0,  0 );
+LAT_TEST(d_02,    2, 0, 1, 1, 0, 0,  0, 1 );
+LAT_TEST(d_03,    2, 0, 1, 1, 0, 0,  1, 0 );
+
+LAT_TEST(u_1,     1, 0, 1, 0, 0, 0,  1 );
+LAT_TEST(u_1x1,   2, 0, 1, 0, 0, 0,  1, 1 );
+LAT_TEST(u_2,     1, 1, 1, 0, 0, 0,  2, 0,1 );
+LAT_TEST(u_2x1,   2, 1, 1, 0, 0, 0,  2,1, 0,1 );
+LAT_TEST(u_2x2,   2, 4, 1, 0, 0, 0,  2,2, 0,1, 0,2, 1,3, 2,3 );
+
+LAT_TEST(uc_1,    1, 0, 1, 0, 0, 1,  1 );
+LAT_TEST(uc_1x1,  2, 0, 1, 0, 0, 1,  1, 1 );
+LAT_TEST(uc_2,    1, 1, 1, 0, 0, 1,  2, 0,1 );
+LAT_TEST(uc_2x1,  2, 1, 1, 0, 0, 1,  2,1, 0,1 );
+LAT_TEST(uc_2x2,  2, 4, 1, 0, 0, 1,  2,2, 0,1, 0,2, 1,3, 2,3 );
+
+LAT_TEST(dc_1,    1, 0, 1, 1, 0, 1,  1 );
+LAT_TEST(dc_1x1,  2, 0, 1, 1, 0, 1,  1, 1 );
+LAT_TEST(dc_2,    1, 2, 1, 1, 0, 1,  2, 0,1, 1,0 );
+LAT_TEST(dc_2x1,  2, 2, 1, 1, 0, 1,  2,1, 0,1, 1,0 );
+LAT_TEST(dc_2x2,  2, 8, 1, 1, 0, 1,  2,2, 0,1, 0,2, 1,3, 2,3, 
+	                             1,0, 2,0, 3,1, 3,2, );
+
+LAT_TEST(d_1,     1, 0, 1, 1, 0, 0,  1 );
+LAT_TEST(d_1x1,   2, 0, 1, 1, 0, 0,  1, 1 );
+LAT_TEST(d_2,     1, 1, 1, 1, 0, 0,  2, 0,1 );
+LAT_TEST(d_2x1,   2, 1, 1, 1, 0, 0,  2,1, 0,1 );
+LAT_TEST(d_2x2,   2, 4, 1, 1, 0, 0,  2,2, 0,1, 0,2, 1,3, 2,3 );
+
+LAT_TEST(dmc_1,   1, 0, 1, 1, 0, 1,  1 );
+LAT_TEST(dmc_1x1, 2, 0, 1, 1, 0, 1,  1, 1 );
+LAT_TEST(dmc_2,   1, 2, 1, 1, 0, 1,  2, 0,1, 1,0 );
+LAT_TEST(dmc_2x1, 2, 2, 1, 1, 0, 1,  2,1, 0,1, 1,0 );
+LAT_TEST(dmc_2x2, 2, 4, 1, 1, 0, 1,  2,2, 0,1, 0,2, 1,3, 2,3, 
+				     1,0, 3,2, );
+/*----------------d--m--ne-di-mu-ci-dimedges------------------------*/
+
+/* TODO: add more */
+
+lat_test_t *all_checks[] = { /*  1 */ &lat_u_0,   /*  2 */ &lat_u_01,
+			     /*  3 */ &lat_u_02,  /*  4 */ &lat_u_03,
+			     /*  5 */ &lat_d_0,   /*  6 */ &lat_d_01,
+			     /*  7 */ &lat_d_02,  /*  8 */ &lat_d_03,
+			     /*  9 */ &lat_u_1,   /* 10 */ &lat_u_1x1,
+			     /* 11 */ &lat_u_2,   /* 12 */ &lat_u_2x1,
+			     /* 13 */ &lat_u_2x2, /* 14 */ &lat_u_1,
+			     /* 15 */ &lat_u_1x1, /* 16 */ &lat_u_2,
+			     /* 17 */ &lat_u_2x1, /* 18 */ &lat_uc_2x2,
+			     /* 19 */ &lat_dc_1,  /* 20 */ &lat_dc_1x1,
+			     /* 21 */ &lat_dc_2,  /* 22 */ &lat_dc_2x1,
+			     /* 23 */ &lat_dc_2x2,/* 24 */ &lat_d_1,
+			     /* 25 */ &lat_d_1x1, /* 26 */ &lat_d_2,
+			     /* 27 */ &lat_d_2x1, /* 28 */ &lat_d_2x2,
+			     /* 29 */ &lat_dc_2x2,/* 30 */ &lat_d_1,
+			     /* 31 */ &lat_d_1x1, /* 32 */ &lat_d_2,
+			     /* 33 */ &lat_d_2x1, /* 34 */ &lat_d_2x2,
+			     0 };
+
+int check_lattice_properties(const igraph_t *lattice,
+			     const igraph_vector_t *dim, 
+			     igraph_bool_t directed, 
+			     igraph_bool_t mutual, 
+			     igraph_bool_t circular) {
+  igraph_bool_t res;
+
+  /* Connected */
+  igraph_is_connected(lattice, &res, IGRAPH_WEAK); 
+  if (!res) {
+    printf("Not connected\n");
+    return 1;
+  }
+
+  /* Simple */
+  igraph_is_simple(lattice, &res); 
+  if (!res) {
+    printf("Not simple\n");
+    return 2;
+  }
+
+  return 0;
+}
+
+int check_lattice(const lat_test_t *test) {
+  igraph_t graph, othergraph;
+  igraph_vector_t otheredges;
+  igraph_vector_t dimvector;
+  igraph_bool_t iso;
+  int ret;  
+    
+  /* Create lattice */
+  igraph_vector_view(&dimvector, test->dimedges, test->dim);
+  igraph_lattice(&graph, &dimvector, test->nei, test->directed,
+		 test->mutual, test->circular);
+
+  /* Check its properties */
+  if ((ret=check_lattice_properties(&graph, &dimvector, test->directed, 
+				    test->mutual, test->circular))) {
+    igraph_destroy(&graph);
+    printf("Lattice properties are not satisfied\n");
+    return ret;
+  }
+  
+  /* Check that it is isomorphic to the stored graph */
+  igraph_vector_view(&otheredges, test->dimedges+test->dim, test->m * 2);
+  igraph_create(&othergraph, &otheredges, igraph_vector_prod(&dimvector),
+		test->directed);
+  igraph_isomorphic(&graph, &othergraph, &iso);
+  if (!iso) {
+    printf("--\n");
+    igraph_write_graph_edgelist(&graph, stdout);
+    printf("--\n");
+    igraph_write_graph_edgelist(&othergraph, stdout);
+    igraph_destroy(&graph);
+    igraph_destroy(&othergraph);
+    return 50;    
+  }  
+
+  igraph_destroy(&graph);
+  igraph_destroy(&othergraph);
+  return 0;
+}
+
+int main() {
+  int i, ret;
+
+  i=0;
+  while (all_checks[i]) {
+    if ((ret=check_lattice(all_checks[i]))) { 
+      printf("Check no #%d failed.\n", (int) (i+1));
+      return ret;
+    }
+    i++;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_grid.c b/examples/simple/igraph_layout_grid.c
new file mode 100644
index 0000000..64055fe
--- /dev/null
+++ b/examples/simple/igraph_layout_grid.c
@@ -0,0 +1,68 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <math.h>
+#include <stdlib.h>
+
+int main() {
+  igraph_t g;
+  igraph_matrix_t coords;
+
+  igraph_empty(&g, 15, 0);
+  igraph_matrix_init(&coords, 0, 0);
+
+  /* Predefined width, 2D */
+  igraph_layout_grid(&g, &coords, 5);
+  igraph_matrix_print(&coords);
+  printf("===\n");
+
+  /* Automatic width, 2D */
+  igraph_layout_grid(&g, &coords, -1);
+  igraph_matrix_print(&coords);
+  printf("===\n");
+
+  /* Predefined width and height, 3D */
+  igraph_layout_grid_3d(&g, &coords, 4, 2);
+  igraph_matrix_print(&coords);
+  printf("=====\n");
+
+  /* Predefined width, 3D */
+  igraph_layout_grid_3d(&g, &coords, 4, -1);
+  igraph_matrix_print(&coords);
+  printf("=====\n");
+
+  /* Predefined height, 3D */
+  igraph_layout_grid_3d(&g, &coords, -1, 3);
+  igraph_matrix_print(&coords);
+  printf("=====\n");
+
+  /* Automatic width and height, 3D */
+  igraph_layout_grid_3d(&g, &coords, -1, -1);
+  igraph_matrix_print(&coords);
+
+  igraph_matrix_destroy(&coords);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_grid.out b/examples/simple/igraph_layout_grid.out
new file mode 100644
index 0000000..1b8a947
--- /dev/null
+++ b/examples/simple/igraph_layout_grid.out
@@ -0,0 +1,95 @@
+0 0
+1 0
+2 0
+3 0
+4 0
+0 1
+1 1
+2 1
+3 1
+4 1
+0 2
+1 2
+2 2
+3 2
+4 2
+===
+0 0
+1 0
+2 0
+3 0
+0 1
+1 1
+2 1
+3 1
+0 2
+1 2
+2 2
+3 2
+0 3
+1 3
+2 3
+===
+0 0 0
+1 0 0
+2 0 0
+3 0 0
+0 1 0
+1 1 0
+2 1 0
+3 1 0
+0 0 1
+1 0 1
+2 0 1
+3 0 1
+0 1 1
+1 1 1
+2 1 1
+=====
+0 0 0
+1 0 0
+2 0 0
+3 0 0
+0 1 0
+1 1 0
+2 1 0
+3 1 0
+0 0 1
+1 0 1
+2 0 1
+3 0 1
+0 1 1
+1 1 1
+2 1 1
+=====
+0 0 0
+1 0 0
+2 0 0
+0 1 0
+1 1 0
+2 1 0
+0 2 0
+1 2 0
+2 2 0
+0 0 1
+1 0 1
+2 0 1
+0 1 1
+1 1 1
+2 1 1
+=====
+0 0 0
+1 0 0
+2 0 0
+0 1 0
+1 1 0
+2 1 0
+0 2 0
+1 2 0
+2 2 0
+0 0 1
+1 0 1
+2 0 1
+0 1 1
+1 1 1
+2 1 1
diff --git a/examples/simple/igraph_layout_lgl.c b/examples/simple/igraph_layout_lgl.c
new file mode 100644
index 0000000..549bccc
--- /dev/null
+++ b/examples/simple/igraph_layout_lgl.c
@@ -0,0 +1,49 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <math.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_matrix_t coords;
+  igraph_real_t vc;
+  
+  igraph_tree(&g, 100, 3, IGRAPH_TREE_UNDIRECTED);
+/*   igraph_barabasi_game(&g, 1000, 1, 0, 0, IGRAPH_UNDIRECTED); */
+  igraph_matrix_init(&coords, 0, 0);
+  vc=igraph_vcount(&g);
+  igraph_layout_lgl(&g, &coords, 
+		    /* maxiter */    150, 
+		    /* maxdelta */   vc,
+		    /* area */       vc*vc,
+		    /* coolexp */    1.5,
+		    /* repulserad */ vc*vc*vc,
+		    /* cellsize */   sqrt(sqrt(vc)),
+		    /* root */       0);
+  
+  igraph_matrix_destroy(&coords);
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_mds.c b/examples/simple/igraph_layout_mds.c
new file mode 100644
index 0000000..a341645
--- /dev/null
+++ b/examples/simple/igraph_layout_mds.c
@@ -0,0 +1,85 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <math.h>
+#include <stdlib.h>
+
+#define sqr(x) ((x)*(x))
+
+int main() {
+  igraph_t g;
+  igraph_matrix_t coords, dist_mat;
+  igraph_arpack_options_t options;
+  int i, j;
+  srand(time(0));
+
+  igraph_arpack_options_init(&options);
+
+  igraph_tree(&g, 10, 2, IGRAPH_TREE_UNDIRECTED);
+  igraph_matrix_init(&coords, 0, 0);
+  igraph_layout_mds(&g, &coords, 0, 2, &options);
+  if (MATRIX(coords, 0, 0) > 0) {
+    for (i = 0; i < igraph_matrix_nrow(&coords); i++)
+      MATRIX(coords, i, 0) *= -1;
+  }
+  if (MATRIX(coords, 0, 1) < 0) {
+    for (i = 0; i < igraph_matrix_nrow(&coords); i++)
+      MATRIX(coords, i, 1) *= -1;
+  }
+  igraph_matrix_print(&coords);
+  igraph_matrix_destroy(&coords);
+  igraph_destroy(&g);
+
+  igraph_full(&g, 8, IGRAPH_UNDIRECTED, 0);
+  igraph_matrix_init(&coords, 8, 2);
+  igraph_matrix_init(&dist_mat, 8, 8);
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 2; j++)
+      MATRIX(coords, i, j) = rand() % 1000;
+  for (i = 0; i < 8; i++)
+    for (j = i+1; j < 8; j++) {
+      double dist_sq = 0.0;
+      dist_sq += sqr(MATRIX(coords, i, 0)-MATRIX(coords, j, 0));
+      dist_sq += sqr(MATRIX(coords, i, 1)-MATRIX(coords, j, 1));
+      MATRIX(dist_mat, i, j) = sqrt(dist_sq);
+      MATRIX(dist_mat, j, i) = sqrt(dist_sq);
+	}
+  igraph_layout_mds(&g, &coords, &dist_mat, 2, &options);
+  for (i = 0; i < 8; i++)
+    for (j = i+1; j < 8; j++) {
+      double dist_sq = 0.0;
+      dist_sq += sqr(MATRIX(coords, i, 0)-MATRIX(coords, j, 0));
+      dist_sq += sqr(MATRIX(coords, i, 1)-MATRIX(coords, j, 1));
+      if (fabs(sqrt(dist_sq) - MATRIX(dist_mat, i, j)) > 1e-2) {
+        printf("dist(%d,%d) should be %.4f, but it is %.4f\n",
+				i, j, MATRIX(dist_mat, i, j), sqrt(dist_sq));
+        return 1;
+      }
+    }
+  igraph_matrix_destroy(&dist_mat);
+  igraph_matrix_destroy(&coords);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_mds.out b/examples/simple/igraph_layout_mds.out
new file mode 100644
index 0000000..e02cf48
--- /dev/null
+++ b/examples/simple/igraph_layout_mds.out
@@ -0,0 +1,10 @@
+-0.692039 0.0247583
+0.399957 0.178289
+-1.78403 -0.128772
+1.25186 -0.697105
+0.891182 1.32979
+-2.6988 -0.242629
+-2.6988 -0.242629
+1.97413 -1.3515
+1.97413 -1.3515
+1.38241 2.4813
diff --git a/examples/simple/igraph_layout_merge.c b/examples/simple/igraph_layout_merge.c
new file mode 100644
index 0000000..5a18929
--- /dev/null
+++ b/examples/simple/igraph_layout_merge.c
@@ -0,0 +1,83 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_types_internal.h>
+#include <stdlib.h>
+#include <time.h>
+
+int igraph_i_layout_merge_dla(igraph_i_layout_mergegrid_t *grid, 
+			      long int actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r,
+			      igraph_real_t cx, igraph_real_t cy, igraph_real_t startr, 
+			      igraph_real_t killr);
+
+int main() {
+  
+  /*******************/
+  /* Testing the DLA */
+  /*******************/
+  long int nodes=10;
+  igraph_i_layout_mergegrid_t grid;
+  igraph_vector_t x, y, r;
+  long int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_vector_init(&x, nodes);
+  igraph_vector_init(&y, nodes);
+  igraph_vector_init(&r, nodes);  
+  igraph_i_layout_mergegrid_init(&grid, -5, 5, 100, -5, 5, 100);
+
+  /* radius */
+  for (i=0; i<nodes; i++) {
+    VECTOR(r)[i]=rand()/(double)RAND_MAX;
+  }
+  igraph_vector_sort(&r);
+
+  /* place */
+  VECTOR(x)[0]=0;
+  VECTOR(y)[0]=0;
+  igraph_i_layout_merge_place_sphere(&grid, 0, 0, VECTOR(r)[nodes-1], 0);
+
+  for (i=1; i<nodes; i++) {
+/*     fprintf(stderr, "%li ", i); */
+    igraph_i_layout_merge_dla(&grid, i, 
+			      igraph_vector_e_ptr(&x, i),
+			      igraph_vector_e_ptr(&y, i),
+			      VECTOR(r)[nodes-i-1], 0, 0, 4, 7);
+    igraph_i_layout_merge_place_sphere(&grid, VECTOR(x)[i], VECTOR(y)[i], 
+				       VECTOR(r)[nodes-i-1], i);
+  }
+
+/*   for (i=0; i<nodes; i++) {  */
+/*     printf("%f %f\n", VECTOR(x)[i], VECTOR(y)[i]); */
+/*   } */
+
+/*   print_grid(&grid, stdout); */
+  
+  igraph_vector_destroy(&x);
+  igraph_vector_destroy(&y);
+  igraph_vector_destroy(&r);
+  igraph_i_layout_mergegrid_destroy(&grid);
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_merge2.c b/examples/simple/igraph_layout_merge2.c
new file mode 100644
index 0000000..919510c
--- /dev/null
+++ b/examples/simple/igraph_layout_merge2.c
@@ -0,0 +1,78 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  igraph_t small, big;
+  igraph_matrix_t small_coords, big_coords, merged_coords;
+  igraph_vector_ptr_t graph_ptr, coords_ptr;
+  igraph_arpack_options_t arpack_opts;
+
+  /* To make things reproducible */
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_small(&big, 10, IGRAPH_UNDIRECTED, 
+	       0,1, 1,2, 2,3, 3,4, 4,5, 5,6, 6,7, 7,8, 8,9, 9,0,
+	       -1);
+  
+  igraph_small(&small, 3, IGRAPH_UNDIRECTED,
+	       0,1, 1,2, 2,0,
+	       -1);
+
+  igraph_arpack_options_init(&arpack_opts);
+
+  igraph_matrix_init(&big_coords, 0, 0);
+  igraph_layout_mds(&big, &big_coords, /*dist=*/ 0, /*dim=*/ 2,
+		    &arpack_opts);
+  
+  igraph_matrix_init(&small_coords, 0, 0);
+  igraph_layout_mds(&small, &small_coords, /*dist=*/ 0, /*dim=*/ 2,
+		    &arpack_opts);
+  
+  igraph_vector_ptr_init(&graph_ptr, 2);
+  igraph_vector_ptr_init(&coords_ptr, 2);
+  igraph_matrix_init(&merged_coords, 0, 0);
+  VECTOR(graph_ptr)[0] = &big; 
+  VECTOR(graph_ptr)[1] = &small;
+  VECTOR(coords_ptr)[0] = &big_coords;
+  VECTOR(coords_ptr)[1] = &small_coords;
+  
+  igraph_layout_merge_dla(&graph_ptr, &coords_ptr, &merged_coords);
+  
+  igraph_matrix_print(&merged_coords);
+  
+  igraph_matrix_destroy(&merged_coords);
+  igraph_matrix_destroy(&small_coords);
+  igraph_matrix_destroy(&big_coords);
+  igraph_vector_ptr_destroy(&graph_ptr);
+  igraph_vector_ptr_destroy(&coords_ptr);
+  igraph_destroy(&small);
+  igraph_destroy(&big);
+  
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
diff --git a/examples/simple/igraph_layout_merge2.out b/examples/simple/igraph_layout_merge2.out
new file mode 100644
index 0000000..dfe2c22
--- /dev/null
+++ b/examples/simple/igraph_layout_merge2.out
@@ -0,0 +1,13 @@
+-2.73912 -2.95429
+-0.479512 -4.00008
+1.96326 -3.51798
+3.65613 -1.69214
+3.95248 0.780051
+2.73912 2.95429
+0.479512 4.00008
+-1.96326 3.51798
+-3.65613 1.69214
+-3.95248 -0.780051
+-1.6061 6.30088
+-4.92661 5.80435
+-3.69637 8.92826
diff --git a/examples/simple/igraph_layout_merge3.c b/examples/simple/igraph_layout_merge3.c
new file mode 100644
index 0000000..ca0aa01
--- /dev/null
+++ b/examples/simple/igraph_layout_merge3.c
@@ -0,0 +1,44 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  igraph_t graph;
+  igraph_matrix_t coords;
+  int i;
+
+  igraph_matrix_init(&coords, 0, 0);
+
+  for (i=0; i<10; i++) {
+    igraph_erdos_renyi_game(&graph, IGRAPH_ERDOS_RENYI_GNP, /*n=*/ 100, 
+			    /*p=*/ 2.0/100, IGRAPH_UNDIRECTED, /*loops=*/ 0);
+    igraph_layout_mds(&graph, &coords, /*dist=*/ 0, /*dim=*/ 2,
+		      /*options=*/ 0);
+    igraph_destroy(&graph);
+  }
+  
+  igraph_matrix_destroy(&coords);
+	 
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_reingold_tilford.c b/examples/simple/igraph_layout_reingold_tilford.c
new file mode 100644
index 0000000..37081e5
--- /dev/null
+++ b/examples/simple/igraph_layout_reingold_tilford.c
@@ -0,0 +1,47 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <math.h>
+
+int main() {
+
+  igraph_t g;
+  FILE *f;
+  igraph_matrix_t coords;
+  /* long int i, n; */
+
+  f=fopen("igraph_layout_reingold_tilford.in", "r");
+  igraph_read_graph_edgelist(&g, f, 0, 1);
+  igraph_matrix_init(&coords, 0, 0);
+  igraph_layout_reingold_tilford(&g, &coords, IGRAPH_IN, 0, 0); 
+  
+  /*n=igraph_vcount(&g);
+  for (i=0; i<n; i++) {
+    printf("%6.3f %6.3f\n", MATRIX(coords, i, 0), MATRIX(coords, i, 1));
+  }*/
+  
+  igraph_matrix_destroy(&coords);
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_reingold_tilford.in b/examples/simple/igraph_layout_reingold_tilford.in
new file mode 100644
index 0000000..d49aef3
--- /dev/null
+++ b/examples/simple/igraph_layout_reingold_tilford.in
@@ -0,0 +1,44 @@
+1 0
+2 0
+3 0
+4 0
+5 0
+6 1
+7 13
+8 0
+9 5
+10 1
+11 0
+12 2
+13 0
+14 2
+15 13
+16 11
+17 5
+18 4
+19 4
+20 4
+21 4
+22 28
+23 4
+24 10
+25 24
+26 2
+27 4
+28 5
+29 8
+30 14
+31 33
+32 14
+33 14
+34 12
+35 37
+36 14
+37 16
+38 14
+39 12
+40 9
+41 37
+42 36
+43 41
+44 41
diff --git a/examples/simple/igraph_layout_sugiyama.c b/examples/simple/igraph_layout_sugiyama.c
new file mode 100644
index 0000000..11aebb5
--- /dev/null
+++ b/examples/simple/igraph_layout_sugiyama.c
@@ -0,0 +1,97 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <math.h>
+#include <stdlib.h>
+
+int main() {
+  igraph_t g, extd_g;
+  igraph_matrix_t coords;
+  igraph_vector_t edgelist, extd_edgelist, extd_to_orig_eids;
+  igraph_vector_t layers;
+
+  igraph_matrix_init(&coords, 0, 0);
+  igraph_vector_init(&extd_to_orig_eids, 0);
+
+  /* Layout on simple graph with predefined layers */
+  igraph_vector_init_int_end(&layers, -1, 0,1,1,2,3,3,4,4,5, -1);
+  igraph_vector_init_int_end(&edgelist, -1,
+          0,1, 0,2, 0,3, 1,2, 2,2, 1,4, 2,5, 4,6, 5,7, 6,8, 7,8,
+          3,8, 8,1, 8,2, -1);
+  igraph_create(&g, &edgelist, 0, 1);
+
+  igraph_layout_sugiyama(&g, &coords, 0, 0, &layers,
+          /* hgap = */ 1,
+          /* vgap = */ 1,
+          /* maxiter = */ 100,
+          /* weights = */ 0);
+  igraph_matrix_print(&coords);
+  printf("===\n");
+
+  /* Same, but this time also return the extended graph */
+  igraph_layout_sugiyama(&g, &coords, &extd_g, &extd_to_orig_eids, &layers,
+          /* hgap = */ 1,
+          /* vgap = */ 1,
+          /* maxiter = */ 100,
+          /* weights = */ 0);
+  igraph_matrix_print(&coords);
+  printf("===\n");
+  igraph_vector_init(&extd_edgelist, 0);
+  igraph_get_edgelist(&extd_g, &extd_edgelist, 0);
+  igraph_vector_print(&extd_edgelist);
+  igraph_vector_destroy(&extd_edgelist);
+  igraph_destroy(&extd_g);
+  printf("===\n");
+  igraph_vector_print(&extd_to_orig_eids);
+  printf("===\n");
+
+  igraph_vector_destroy(&layers);
+
+  /* Same, but with automatic layering */
+  igraph_layout_sugiyama(&g, &coords, 0, 0, 0,
+          /* hgap = */ 1,
+          /* vgap = */ 1,
+          /* maxiter = */ 100,
+          /* weights = */ 0);
+  igraph_matrix_print(&coords);
+  printf("===\n");
+
+  /* Layering with gaps in it */
+  igraph_vector_init_int_end(&layers, -1, 0,2,2,4,6,6,12,12,15, -1);
+  igraph_layout_sugiyama(&g, &coords, 0, 0, &layers,
+          /* hgap = */ 1,
+          /* vgap = */ 1,
+          /* maxiter = */ 100,
+          /* weights = */ 0);
+  igraph_matrix_print(&coords);
+  igraph_vector_destroy(&layers);
+  printf("===\n");
+
+  igraph_vector_destroy(&edgelist);
+  igraph_matrix_destroy(&coords);
+  igraph_vector_destroy(&extd_to_orig_eids);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_layout_sugiyama.out b/examples/simple/igraph_layout_sugiyama.out
new file mode 100644
index 0000000..2260ad1
--- /dev/null
+++ b/examples/simple/igraph_layout_sugiyama.out
@@ -0,0 +1,87 @@
+2.5 0
+0.5 1
+2.5 1
+4 2
+0 3
+2 3
+0 4
+2 4
+2 5
+4 1
+0 2
+2 2
+4 3
+4 4
+1 2
+1 3
+1 4
+3 2
+3 3
+3 4
+===
+2.5 0
+0.5 1
+2.5 1
+4 2
+0 3
+2 3
+0 4
+2 4
+2 5
+4 1
+0 2
+2 2
+4 3
+4 4
+1 2
+1 3
+1 4
+3 2
+3 3
+3 4
+===
+0 1 0 2 0 9 9 3 1 2 1 10 10 4 2 2 2 11 11 5 3 12 12 13 13 8 4 6 5 7 6 8 7 8 8 16 16 15 15 14 14 1 8 19 19 18 18 17 17 2
+===
+0 1 2 2 3 5 5 4 6 6 11 11 11 7 8 9 10 12 12 12 12 13 13 13 13
+===
+2.5 0
+1 1
+2.5 2
+4 1
+0 2
+2 3
+0 3
+2 4
+2 5
+2.5 1
+4 2
+4 3
+4 4
+0 4
+1 2
+1 3
+1 4
+3 3
+3 4
+===
+2.5 0
+0.5 2
+2.5 2
+4 4
+0 6
+2 6
+0 12
+2 12
+2 15
+4 2
+0 4
+2 4
+4 6
+4 12
+1 4
+1 6
+1 12
+3 4
+3 6
+3 12
+===
diff --git a/examples/simple/igraph_lcf.c b/examples/simple/igraph_lcf.c
new file mode 100644
index 0000000..2c6cfa0
--- /dev/null
+++ b/examples/simple/igraph_lcf.c
@@ -0,0 +1,47 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g, g2;
+  igraph_bool_t iso;
+  
+  igraph_lcf(&g, 12, 5, -5, 6, 0);
+  igraph_famous(&g2, "franklin");
+  
+  igraph_isomorphic_vf2(&g, &g2, 
+			/*vertex.color1=*/ 0, /*vertex.color2=*/ 0, 
+			/*edge.color1=*/ 0, /*edge.color2=*/ 0,
+			&iso, 0, 0, 0, 0, 0);
+  if (!iso) {
+    printf("OOOPS!\n");
+    return 1;
+  }
+  
+  igraph_destroy(&g);
+  igraph_destroy(&g2);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_local_transitivity.c b/examples/simple/igraph_local_transitivity.c
new file mode 100644
index 0000000..1041270
--- /dev/null
+++ b/examples/simple/igraph_local_transitivity.c
@@ -0,0 +1,59 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vs_t vertices;
+  igraph_vector_t result1, result2;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_vector_init(&result1, 0);
+  igraph_vector_init(&result2, 0);
+
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100, .1,
+			  IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+
+  igraph_vs_seq(&vertices, 0, 99);
+
+  igraph_transitivity_local_undirected(&g, &result1, igraph_vss_all(),
+				       IGRAPH_TRANSITIVITY_NAN);
+  igraph_transitivity_local_undirected(&g, &result2, vertices,
+				       IGRAPH_TRANSITIVITY_NAN);
+  
+  if (!igraph_vector_all_e(&result1, &result2)) {
+    igraph_vector_print(&result1);
+    igraph_vector_print(&result2);
+    return 1;
+  }
+
+  igraph_vector_destroy(&result1);
+  igraph_vector_destroy(&result2);
+  igraph_vs_destroy(&vertices);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_marked_queue.c b/examples/simple/igraph_marked_queue.c
new file mode 100644
index 0000000..3ca38e3
--- /dev/null
+++ b/examples/simple/igraph_marked_queue.c
@@ -0,0 +1,62 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include "igraph_marked_queue.h"
+
+int main() {
+  igraph_marked_queue_t Q;
+  long int i;
+  
+  igraph_marked_queue_init(&Q, 100);
+  for (i=0; i<50; i++) {
+    igraph_marked_queue_push(&Q, i);
+    if (!igraph_marked_queue_iselement(&Q, i)) {
+      return 4;
+    }
+    if (! ((i+1) % 5)) {
+      igraph_marked_queue_start_batch(&Q);
+    }
+  }
+
+  for (i=1; i<50; i++) {
+    if (!igraph_marked_queue_iselement(&Q, i)) {
+      printf("Problem with %li.\n", i);
+      return 3;
+    }
+  }
+
+  for (i=0; i<=50/5; i++) {
+    if (igraph_marked_queue_empty(&Q)) {
+      return 1;
+    }
+    igraph_marked_queue_pop_back_batch(&Q);
+  }
+  if (!igraph_marked_queue_empty(&Q)) {
+    return 2;
+  }
+
+  igraph_marked_queue_destroy(&Q);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_maximal_cliques.c b/examples/simple/igraph_maximal_cliques.c
new file mode 100644
index 0000000..255501e
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques.c
@@ -0,0 +1,153 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define NODES 1000
+#define CLIQUE_SIZE 10
+#define NO_CLIQUES 10
+#define INT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))
+
+int permutation(igraph_vector_t *vec) {
+  int i, r, tmp;
+  for (i=0; i<CLIQUE_SIZE; i++) {
+    r=INT(NODES-1);
+    tmp=VECTOR(*vec)[i];
+    VECTOR(*vec)[i]=VECTOR(*vec)[r];
+    VECTOR(*vec)[r]=tmp;
+  }
+  return 0;
+}
+
+int sort_cmp(const void *a, const void *b) {
+  const igraph_vector_t **da = (const igraph_vector_t **) a;
+  const igraph_vector_t **db = (const igraph_vector_t **) b;
+  int i, alen=igraph_vector_size(*da), blen=igraph_vector_size(*db);
+  if (alen != blen) { return (alen < blen) - (alen > blen); }
+  for (i=0; i<alen; i++) {
+    int ea=VECTOR(**da)[i], eb=VECTOR(**db)[i];
+    if (ea != eb) { return (ea > eb) - (ea < eb); }
+  }
+  return 0;
+}
+
+void sort_cliques(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_sort(v);
+  }
+  igraph_qsort(VECTOR(*cliques), (size_t) n,
+	       sizeof(igraph_vector_t *), sort_cmp);
+}
+
+void print_and_destroy_cliques(igraph_vector_ptr_t *cliques) {
+  int i;
+  sort_cliques(cliques);
+  for (i=0; i<igraph_vector_ptr_size(cliques); i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+}
+
+int main() {
+  
+  igraph_t g, g2, cli;
+  igraph_vector_t perm;
+  igraph_vector_ptr_t cliques;
+  igraph_integer_t no;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  /* Create a graph that has a random component, plus a number of 
+     relatively small cliques */
+  
+  igraph_vector_init_seq(&perm, 0, NODES-1);
+  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, NODES, NODES, 
+        /*directed=*/ 0, /*loops=*/ 0);
+  igraph_full(&cli, CLIQUE_SIZE, /*directed=*/ 0, /*loops=*/ 0);
+
+  for (i=0; i<NO_CLIQUES; i++) {
+    /* Permute vertices of g */
+    permutation(&perm);
+    igraph_permute_vertices(&g, &g2, &perm);
+    igraph_destroy(&g);
+    g=g2;
+    
+    /* Add a clique */
+    igraph_union(&g2, &g, &cli, /*edge_map1=*/ 0, /*edge_map2=*/ 0);
+    igraph_destroy(&g);
+    g=g2;
+  }
+  igraph_simplify(&g, /*multiple=*/ 1, /*loop=*/ 0, /*edge_comb=*/ 0);
+  
+  igraph_vector_destroy(&perm);
+  igraph_destroy(&cli);
+  
+  /* Find the maximal cliques */
+  
+  igraph_vector_ptr_init(&cliques, 0);
+  igraph_maximal_cliques(&g, &cliques, /*min_size=*/ 3,
+       /*max_size=*/ 0 /*no limit*/);
+  igraph_maximal_cliques_count(&g, &no, /*min_size=*/ 3, 
+       /*max_size=*/ 0 /*no limit*/);
+
+  if (no != igraph_vector_ptr_size(&cliques)) { return 1; }
+  
+  /* Print and destroy them */
+
+  print_and_destroy_cliques(&cliques);
+  
+  /* Clean up */
+
+  igraph_vector_ptr_destroy(&cliques);
+  igraph_destroy(&g);
+
+  /* Build a triangle with a loop (thanks to Emmanuel Navarro) */
+
+  igraph_small(&g, 3, IGRAPH_UNDIRECTED, 0, 1, 1, 2, 2, 0, 0, 0, -1);
+
+  /* Find the maximal cliques */
+
+  igraph_vector_ptr_init(&cliques, 0);
+  igraph_maximal_cliques(&g, &cliques, /*min_size=*/ 3,
+    /*max_size=*/ 0 /*no limit*/);
+  igraph_maximal_cliques_count(&g, &no, /*min_size=*/ 3, 
+       /*max_size=*/ 0 /*no limit*/);
+
+  if (no != igraph_vector_ptr_size(&cliques)) { return 2; }
+
+  /* Print and destroy them */
+
+  print_and_destroy_cliques(&cliques);
+  
+  /* Clean up */
+
+  igraph_vector_ptr_destroy(&cliques);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_maximal_cliques.out b/examples/simple/igraph_maximal_cliques.out
new file mode 100644
index 0000000..6366872
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques.out
@@ -0,0 +1,22 @@
+0 1 2 3 4 5 6 7 8 9
+0 1 3 4 5 7 270 279 534 606
+0 1 3 4 5 7 270 534 606 919
+9 164 307 416 613 725 749 822 940 949
+13 56 75 273 498 534 691 812 864 999
+13 82 150 392 418 594 691 810 985 987
+13 150 380 418 480 594 749 810 985 987
+22 307 450 476 498 520 671 772 831 852
+129 205 228 241 247 251 274 377 606 954
+129 205 228 247 377 380 392 831 940 954
+13 150 380 392 418 594 810 985 987
+129 205 228 241 247 377 380 940 954
+1 534 999
+9 749 987
+107 609 835
+137 273 691
+193 594 691
+295 307 450
+307 831 940
+338 610 840
+380 749 940
+0 1 2
diff --git a/examples/simple/igraph_maximal_cliques2.c b/examples/simple/igraph_maximal_cliques2.c
new file mode 100644
index 0000000..f7d5b22
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques2.c
@@ -0,0 +1,98 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int sort_cmp(const void *a, const void *b) {
+  const igraph_vector_t **da = (const igraph_vector_t **) a;
+  const igraph_vector_t **db = (const igraph_vector_t **) b;
+  int i, alen=igraph_vector_size(*da), blen=igraph_vector_size(*db);
+  if (alen != blen) { return (alen < blen) - (alen > blen); }
+  for (i=0; i<alen; i++) {
+    int ea=VECTOR(**da)[i], eb=VECTOR(**db)[i];
+    if (ea != eb) { return (ea > eb) - (ea < eb); }
+  }
+  return 0;
+}
+
+void sort_cliques(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_sort(v);
+  }
+  igraph_qsort(VECTOR(*cliques), (size_t) n,
+	       sizeof(igraph_vector_t *), sort_cmp);
+}
+
+int print_and_destroy(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  sort_cliques(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+  }
+  igraph_vector_ptr_destroy(cliques);
+  return 0;
+}
+
+int main() {
+  igraph_t graph;
+  igraph_vector_ptr_t cliques;
+  igraph_integer_t no;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_ring(&graph, /*n=*/ 10, /*directed=*/ 0,
+  	      /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_vector_ptr_init(&cliques, 0);
+
+  igraph_maximal_cliques(&graph, &cliques, /*min_size=*/ 0,
+  			 /*max_size=*/ 0);
+  igraph_maximal_cliques_count(&graph, &no, /*min_size=*/ 0, 
+       /*max_size=*/ 0 /*no limit*/);
+  if (no != igraph_vector_ptr_size(&cliques)) { return 1; }
+
+  print_and_destroy(&cliques);
+  igraph_destroy(&graph);
+
+  printf("---\n");
+  /* ----------------------------------------------------------- */
+
+  igraph_erdos_renyi_game(&graph, IGRAPH_ERDOS_RENYI_GNP, 
+			  /*n=*/ 50, /*p=*/ 0.5, /*directed=*/ 0,
+			  /*loops=*/ 0);
+  igraph_vector_ptr_init(&cliques, 0);
+  
+  igraph_maximal_cliques(&graph, &cliques, /*min_size=*/ 8,
+			 /*max_size=*/ 0);
+  igraph_maximal_cliques_count(&graph, &no, /*min_size=*/ 8, 
+       /*max_size=*/ 0 /*no limit*/);
+  if (no != igraph_vector_ptr_size(&cliques)) { return 2; }
+  
+  print_and_destroy(&cliques);
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_maximal_cliques2.out b/examples/simple/igraph_maximal_cliques2.out
new file mode 100644
index 0000000..d4ae415
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques2.out
@@ -0,0 +1,12 @@
+0 1
+0 9
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+---
+0 7 10 11 13 24 34 42
diff --git a/examples/simple/igraph_maximal_cliques3.c b/examples/simple/igraph_maximal_cliques3.c
new file mode 100644
index 0000000..ce5b6ca
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques3.c
@@ -0,0 +1,79 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <unistd.h>
+
+int sort_cmp(const void *a, const void *b) {
+  const igraph_vector_t **da = (const igraph_vector_t **) a;
+  const igraph_vector_t **db = (const igraph_vector_t **) b;
+  int i, alen=igraph_vector_size(*da), blen=igraph_vector_size(*db);
+  if (alen != blen) { return (alen < blen) - (alen > blen); }
+  for (i=0; i<alen; i++) {
+    int ea=VECTOR(**da)[i], eb=VECTOR(**db)[i];
+    if (ea != eb) { return (ea > eb) - (ea < eb); }
+  }
+  return 0;
+}
+
+void sort_cliques(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_sort(v);
+  }
+  igraph_qsort(VECTOR(*cliques), (size_t) n,
+	       sizeof(igraph_vector_t *), sort_cmp);
+}
+
+int print_and_destroy(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  sort_cliques(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+  }
+  igraph_vector_ptr_destroy(cliques);
+  return 0;
+}
+
+int main() {
+  igraph_t graph;
+  igraph_vector_ptr_t cliques;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_erdos_renyi_game(&graph, IGRAPH_ERDOS_RENYI_GNP,
+  			  /*n=*/ 100, /*p=*/ 0.7, /*directed=*/ 0,
+  			  /*loops=*/ 0);
+
+  igraph_vector_ptr_init(&cliques, 0);
+  
+  igraph_maximal_cliques(&graph, &cliques, /*min_size=*/ 15,
+			 /*max_size=*/ 0);
+  
+  print_and_destroy(&cliques);
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_maximal_cliques3.out b/examples/simple/igraph_maximal_cliques3.out
new file mode 100644
index 0000000..609e5e2
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques3.out
@@ -0,0 +1,28 @@
+0 6 17 19 25 30 33 35 40 73 74 79 90 92 97
+0 6 17 19 25 30 33 35 47 73 74 79 90 92 97
+0 11 12 17 19 30 33 35 47 53 62 79 91 92 97
+0 17 19 25 30 33 35 47 73 74 79 90 91 92 97
+1 3 6 17 25 28 37 40 49 50 69 74 85 86 97
+1 3 6 17 25 28 37 40 49 50 73 74 85 86 97
+1 3 6 17 25 28 37 40 50 54 69 74 85 86 97
+1 3 6 17 25 28 37 40 50 54 73 74 85 86 97
+1 3 6 17 25 37 40 49 50 69 74 85 86 90 97
+1 3 6 17 25 37 40 49 50 73 74 85 86 90 97
+1 3 6 17 25 37 40 50 69 74 85 86 90 95 97
+1 3 6 17 25 37 40 50 73 74 85 86 90 95 97
+1 3 17 25 28 37 40 49 50 69 74 85 86 97 98
+1 3 17 25 28 37 40 49 50 73 74 85 86 97 98
+1 3 17 25 28 37 40 50 54 69 74 85 86 97 98
+1 3 17 25 28 37 40 50 54 73 74 85 86 97 98
+1 6 17 25 28 37 40 49 50 61 69 74 85 86 97
+1 6 17 25 28 37 40 49 50 61 73 74 85 86 97
+1 6 17 25 28 37 40 50 54 61 69 74 85 86 97
+1 6 17 25 28 37 40 50 54 61 73 74 85 86 97
+1 6 17 25 37 40 49 50 61 69 74 85 86 90 97
+1 6 17 25 37 40 49 50 61 73 74 85 86 90 97
+1 6 17 25 37 40 50 61 69 74 85 86 90 95 97
+1 6 17 25 37 40 50 61 73 74 85 86 90 95 97
+1 9 16 25 28 54 57 58 67 78 85 86 87 97 99
+1 9 16 25 28 54 57 58 67 85 86 87 97 98 99
+1 9 25 28 54 57 58 67 69 85 86 87 97 98 99
+8 15 28 39 43 48 55 56 59 61 62 63 76 78 84
diff --git a/examples/simple/igraph_maximal_cliques4.c b/examples/simple/igraph_maximal_cliques4.c
new file mode 100644
index 0000000..fd18eba
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques4.c
@@ -0,0 +1,102 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int sort_cmp(const void *a, const void *b) {
+  const igraph_vector_t **da = (const igraph_vector_t **) a;
+  const igraph_vector_t **db = (const igraph_vector_t **) b;
+  int i, alen=igraph_vector_size(*da), blen=igraph_vector_size(*db);
+  if (alen != blen) { return (alen < blen) - (alen > blen); }
+  for (i=0; i<alen; i++) {
+    int ea=VECTOR(**da)[i], eb=VECTOR(**db)[i];
+    if (ea != eb) { return (ea > eb) - (ea < eb); }
+  }
+  return 0;
+}
+
+void sort_cliques(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_sort(v);
+  }
+  igraph_qsort(VECTOR(*cliques), (size_t) n,
+	       sizeof(igraph_vector_t *), sort_cmp);
+}
+
+int print_and_destroy(igraph_vector_ptr_t *cliques) {
+  int i, n=igraph_vector_ptr_size(cliques);
+  sort_cliques(cliques);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+  }
+  igraph_vector_ptr_destroy(cliques);
+  return 0;
+}
+
+int main() {
+  igraph_t graph;
+  igraph_vector_ptr_t cliques, cl1, cl2;
+  igraph_vector_int_t v1, v2;
+  igraph_integer_t n, n1, n2;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_erdos_renyi_game(&graph, IGRAPH_ERDOS_RENYI_GNP,
+  			  /*n=*/ 100, /*p=*/ 0.5, /*directed=*/ 0,
+  			  /*loops=*/ 0);
+
+  igraph_vector_ptr_init(&cliques, 0);
+  
+  igraph_maximal_cliques_subset(&graph, /*subset=*/ 0, 
+				&cliques, &n, /*outfile=*/ 0, 
+				/*min_size=*/ 9, /*max_size=*/ 0);
+
+  igraph_vector_int_init_seq(&v1,  0, 12);
+  igraph_vector_int_init_seq(&v2, 13, 99);
+  igraph_vector_ptr_init(&cl1, 0);
+  igraph_vector_ptr_init(&cl2, 0);
+  igraph_maximal_cliques_subset(&graph, &v1, &cl1, &n1, /*outfile=*/ 0, 
+				/*min_size=*/ 9, /*max_size=*/ 0);
+  igraph_maximal_cliques_subset(&graph, &v2, &cl2, &n2, /*outfile=*/ 0, 
+				/*min_size=*/ 9, /*max_size=*/ 0);
+
+  igraph_vector_int_destroy(&v1);
+  igraph_vector_int_destroy(&v2);    
+
+  if (n1 + n2 != n) { return 1; }
+  if (n1 != igraph_vector_ptr_size(&cl1)) { return 2; }
+  if (n2 != igraph_vector_ptr_size(&cl2)) { return 3; }
+  
+  print_and_destroy(&cliques);
+  printf("---\n");
+  print_and_destroy(&cl1);
+  printf("+\n");
+  print_and_destroy(&cl2);
+  
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_maximal_cliques4.out b/examples/simple/igraph_maximal_cliques4.out
new file mode 100644
index 0000000..0a486d5
--- /dev/null
+++ b/examples/simple/igraph_maximal_cliques4.out
@@ -0,0 +1,30 @@
+0 10 11 13 24 34 42 79 97
+0 11 13 24 34 42 58 64 97
+2 5 7 34 42 64 67 78 92
+4 24 30 31 47 52 60 87 95
+4 24 30 47 52 60 84 87 95
+6 11 13 26 35 38 54 62 79
+6 11 13 60 66 73 81 82 84
+11 13 16 34 45 58 64 67 82
+13 29 33 49 50 62 63 66 96
+13 29 33 50 62 63 66 86 96
+24 30 31 47 52 60 69 87 95
+24 30 31 52 60 69 79 87 95
+24 30 31 52 60 69 79 88 95
+24 31 32 52 60 69 79 88 95
+---
+0 10 11 13 24 34 42 79 97
+0 11 13 24 34 42 58 64 97
+2 5 7 34 42 64 67 78 92
+4 24 30 31 47 52 60 87 95
+4 24 30 47 52 60 84 87 95
+6 11 13 26 35 38 54 62 79
+6 11 13 60 66 73 81 82 84
+11 13 16 34 45 58 64 67 82
+13 29 33 49 50 62 63 66 96
+13 29 33 50 62 63 66 86 96
++
+24 30 31 47 52 60 69 87 95
+24 30 31 52 60 69 79 87 95
+24 30 31 52 60 69 79 88 95
+24 31 32 52 60 69 79 88 95
diff --git a/examples/simple/igraph_maximum_bipartite_matching.c b/examples/simple/igraph_maximum_bipartite_matching.c
new file mode 100644
index 0000000..f3bc3b1
--- /dev/null
+++ b/examples/simple/igraph_maximum_bipartite_matching.c
@@ -0,0 +1,249 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Tamas Nepusz <ntamas at gmail.com>
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+
+int test_graph_from_leda_tutorial() {
+  /* Test graph from the LEDA tutorial:
+   * http://www.leda-tutorial.org/en/unofficial/ch05s03s05.html
+   */
+  igraph_t graph;
+  igraph_vector_bool_t types;
+  igraph_vector_long_t matching;
+  igraph_integer_t matching_size;
+  igraph_real_t matching_weight;
+  igraph_bool_t is_matching;
+  int i;
+
+  igraph_small(&graph, 0, 0,
+      0, 8, 0, 12, 0, 14,
+      1, 9, 1, 10, 1, 13,
+      2, 8, 2, 9,
+      3, 10, 3, 11, 3, 13,
+      4, 9, 4, 14,
+      5, 14,
+      6, 9, 6, 14,
+      7, 8, 7, 12, 7, 14
+      , -1);
+  igraph_vector_bool_init(&types, 15);
+  for (i = 0; i < 15; i++)
+    VECTOR(types)[i] = (i >= 8);
+  igraph_vector_long_init(&matching, 0);
+
+  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
+      &matching_weight, &matching, 0, 0);
+  if (matching_size != 6) {
+    printf("matching_size is %ld, expected: 6\n", (long)matching_size);
+    return 1;
+  }
+  if (matching_weight != 6) {
+    printf("matching_weight is %ld, expected: 6\n", (long)matching_weight);
+    return 2;
+  }
+  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
+  if (!is_matching) {
+    printf("not a matching: ");
+    igraph_vector_long_print(&matching);
+    return 3;
+  }
+
+  igraph_vector_long_destroy(&matching);
+  igraph_vector_bool_destroy(&types);
+  igraph_destroy(&graph);
+
+  return 0;
+}
+
+int test_weighted_graph_from_mit_notes() {
+  /* Test graph from the following lecture notes:
+   * http://math.mit.edu/~goemans/18433S07/matching-notes.pdf
+   */
+  igraph_t graph;
+  igraph_vector_bool_t types;
+  igraph_vector_long_t matching;
+  igraph_vector_t weights;
+  igraph_integer_t matching_size;
+  igraph_real_t matching_weight;
+  igraph_bool_t is_matching;
+  igraph_real_t weight_array[] = { 2, 7, 2, 3,
+      1, 3, 9, 3, 3,
+      1, 3, 3, 1, 2,
+      4, 1, 2,
+      3 };
+  int i;
+
+  igraph_small(&graph, 0, 0,
+      0, 6, 0, 7, 0, 8, 0, 9,
+      1, 5, 1, 6, 1, 7, 1, 8, 1, 9,
+      2, 5, 2, 6, 2, 7, 2, 8, 2, 9,
+      3, 5, 3, 7, 3, 9,
+      4, 7, -1);
+  igraph_vector_bool_init(&types, 10);
+  for (i = 0; i < 10; i++)
+    VECTOR(types)[i] = (i >= 5);
+  igraph_vector_long_init(&matching, 0);
+  igraph_vector_init_copy(&weights, weight_array,
+      sizeof(weight_array) / sizeof(weight_array[0]));
+
+  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
+      &matching_weight, &matching, &weights, 0);
+  if (matching_size != 4) {
+    printf("matching_size is %ld, expected: 4\n", (long)matching_size);
+    return 1;
+  }
+  if (matching_weight != 19) {
+    printf("matching_weight is %ld, expected: 19\n", (long)matching_weight);
+    return 2;
+  }
+  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
+  if (!is_matching) {
+    printf("not a matching: ");
+    igraph_vector_long_print(&matching);
+    return 3;
+  }
+  
+  igraph_vector_destroy(&weights);
+  igraph_vector_long_destroy(&matching);
+  igraph_vector_bool_destroy(&types);
+  igraph_destroy(&graph);
+
+  return 0;
+}
+
+int test_weighted_graph_generated() {
+  /* Several randomly generated small test graphs */
+  igraph_t graph;
+  igraph_vector_bool_t types;
+  igraph_vector_long_t matching;
+  igraph_vector_t weights;
+  igraph_integer_t matching_size;
+  igraph_real_t matching_weight;
+  igraph_real_t weight_array_1[] = { 8, 5, 9, 18, 20, 13 };
+  igraph_real_t weight_array_2[] = { 20, 4, 20, 3, 13, 1 };
+  int i;
+
+  igraph_vector_bool_init(&types, 10);
+  for (i = 0; i < 10; i++)
+    VECTOR(types)[i] = (i >= 5);
+  igraph_vector_long_init(&matching, 0);
+
+  /* Case 1 */
+
+  igraph_small(&graph, 0, 0, 0, 8, 2, 7, 3, 7, 3, 8, 4, 5, 4, 9, -1);
+  igraph_vector_init_copy(&weights, weight_array_1,
+      sizeof(weight_array_1) / sizeof(weight_array_1[0]));
+  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
+      &matching_weight, &matching, &weights, 0);
+  if (matching_weight != 43) {
+    printf("matching_weight is %ld, expected: 43\n", (long)matching_weight);
+    return 2;
+  }
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&graph);
+
+  /* Case 2 */
+
+  igraph_small(&graph, 0, 0, 0, 5, 0, 6, 1, 7, 2, 5, 3, 5, 3, 9, -1);
+  igraph_vector_init_copy(&weights, weight_array_2,
+      sizeof(weight_array_2) / sizeof(weight_array_2[0]));
+  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
+      &matching_weight, &matching, &weights, 0);
+  if (matching_weight != 41) {
+    printf("matching_weight is %ld, expected: 41\n", (long)matching_weight);
+    return 2;
+  }
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&graph);
+
+  igraph_vector_long_destroy(&matching);
+  igraph_vector_bool_destroy(&types);
+
+  return 0;
+}
+
+int test_weighted_graph_from_file(const char* fname, int type1_count, long exp_weight) {
+  igraph_t graph;
+  igraph_vector_bool_t types;
+  igraph_vector_long_t matching;
+  igraph_vector_t weights;
+  igraph_real_t matching_weight;
+  FILE* f;
+  int i, n;
+
+  f = fopen(fname, "r");
+  if (!f) {
+    fprintf(stderr, "No such file: %s\n", fname);
+    return 1;
+  }
+  igraph_read_graph_ncol(&graph, f, 0, 1, 1, 0);
+  fclose(f);
+
+  n = igraph_vcount(&graph);
+  igraph_vector_bool_init(&types, n);
+  for (i = 0; i < n; i++) {
+    VECTOR(types)[i] = (i >= type1_count);
+  }
+
+  igraph_vector_long_init(&matching, 0);
+
+  igraph_vector_init(&weights, 0);
+  EANV(&graph, "weight", &weights);
+  igraph_maximum_bipartite_matching(&graph, &types, 0, &matching_weight,
+      &matching, &weights, 0);
+  igraph_vector_destroy(&weights);
+
+  igraph_vector_long_print(&matching);
+  if (matching_weight != exp_weight) {
+    printf("matching_weight is %ld, expected: %ld\n", (long)matching_weight,
+        (long)exp_weight);
+    return 2;
+  }
+
+  igraph_vector_destroy(&weights);
+  igraph_vector_long_destroy(&matching);
+  igraph_vector_bool_destroy(&types);
+  igraph_destroy(&graph);
+  
+  return 0;
+}
+
+int main() {
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+
+  if (test_graph_from_leda_tutorial())
+    return 1;
+
+  if (test_weighted_graph_from_mit_notes())
+    return 2;
+
+  if (test_weighted_graph_generated())
+    return 3;
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) {
+    printf("Finally stack still has %d elements.\n", IGRAPH_FINALLY_STACK_SIZE());
+    return 4;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_mincut.c b/examples/simple/igraph_mincut.c
new file mode 100644
index 0000000..296e4cb
--- /dev/null
+++ b/examples/simple/igraph_mincut.c
@@ -0,0 +1,109 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int print_mincut(const igraph_t *graph, igraph_real_t value, 
+		 const igraph_vector_t *partition, 
+		 const igraph_vector_t *partition2, 
+		 const igraph_vector_t *cut, 
+		 const igraph_vector_t *capacity) {
+  
+  long int i, nc=igraph_vector_size(cut);
+  igraph_bool_t directed=igraph_is_directed(graph);
+
+  printf("mincut value: %g\n", (double) value);
+  printf("first partition:  ");  igraph_vector_print(partition);
+  printf("second partition: ");  igraph_vector_print(partition2);
+  printf("edges in the cut: ");
+  for (i=0; i<nc; i++) {
+    long int edge=VECTOR(*cut)[i];
+    long int from=IGRAPH_FROM(graph, edge);
+    long int to  =IGRAPH_TO  (graph, edge);
+    if (!directed && from > to) {
+      igraph_integer_t tmp=from;
+      from=to;
+      to=tmp;
+    }
+    printf("%li-%li (%g), ", from, to, VECTOR(*capacity)[edge]);
+  }
+  printf("\n");
+  
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t weights, partition, partition2, cut;
+  igraph_real_t value;
+
+  igraph_vector_init(&partition, 0);
+  igraph_vector_init(&partition2, 0);
+  igraph_vector_init(&cut, 0);
+
+  /* -------------------------------------------- */
+  
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,1, 0,4, 1,2, 1,4, 1,5, 2,3, 2,6, 3,6, 3,7, 4,5, 5,6, 6,7,
+	       -1);
+  igraph_vector_init_int_end(&weights, -1, 2,3,3,2,2, 4,2,2,2,3, 1,3, -1);
+  
+  igraph_mincut(&g, &value, &partition, &partition2, &cut, &weights);
+  print_mincut(&g, value, &partition, &partition2, &cut, &weights);
+  
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------- */
+
+  igraph_small(&g, 6, IGRAPH_DIRECTED,
+	       0,1,1,2,2,3, 0,5,5,4,4,3, 3,0, -1);
+  igraph_vector_init_int_end(&weights, -1, 3,1,2, 10,1,3, 2, -1);
+
+  igraph_mincut(&g, &value, &partition, &partition2, &cut, &weights);
+  print_mincut(&g, value, &partition, &partition2, &cut, &weights);
+
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------- */
+
+  igraph_small(&g, 5, IGRAPH_DIRECTED,
+	       4,3, 3,2, 2,1, 1,0, 
+	       -1);
+  igraph_vector_init_int_end(&weights, -1, 1,1,1,1, -1);
+  igraph_mincut(&g, &value, &partition, &partition2, &cut, &weights);
+  print_mincut(&g, value, &partition, &partition2, &cut, &weights);
+
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------- */
+
+  igraph_vector_destroy(&cut);
+  igraph_vector_destroy(&partition2);
+  igraph_vector_destroy(&partition);
+ 
+  return 0;
+}
diff --git a/examples/simple/igraph_mincut.out b/examples/simple/igraph_mincut.out
new file mode 100644
index 0000000..4308766
--- /dev/null
+++ b/examples/simple/igraph_mincut.out
@@ -0,0 +1,12 @@
+mincut value: 4
+first partition:  2 3 6 7
+second partition: 0 1 4 5
+edges in the cut: 1-2 (3), 5-6 (1), 
+mincut value: 1
+first partition:  1
+second partition: 0 2 3 4 5
+edges in the cut: 1-2 (1), 
+mincut value: 0
+first partition:  0
+second partition: 1 2 3 4
+edges in the cut: 
diff --git a/examples/simple/igraph_minimal_separators.c b/examples/simple/igraph_minimal_separators.c
new file mode 100644
index 0000000..d94a7bf
--- /dev/null
+++ b/examples/simple/igraph_minimal_separators.c
@@ -0,0 +1,58 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main() {
+  
+  igraph_t graph;
+  igraph_vector_ptr_t separators;
+  long int i, n;
+  
+  igraph_famous(&graph, "zachary");
+  igraph_vector_ptr_init(&separators, 0);
+  igraph_all_minimal_st_separators(&graph, &separators);
+
+  n=igraph_vector_ptr_size(&separators);
+  for (i=0; i<n; i++) {
+    igraph_bool_t res;
+    igraph_vector_t *sep=VECTOR(separators)[i];
+    igraph_is_separator(&graph, igraph_vss_vector(sep), &res);
+    if (!res) { 
+      printf("Vertex set %li is not a separator!\n", i);
+      igraph_vector_print(sep);
+      return 1;
+    }
+  }
+
+  igraph_destroy(&graph);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(separators)[i];
+    igraph_vector_destroy(v);
+    igraph_Free(v);
+  }
+  igraph_vector_ptr_destroy(&separators);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_minimum_size_separators.c b/examples/simple/igraph_minimum_size_separators.c
new file mode 100644
index 0000000..d6fc1c6
--- /dev/null
+++ b/examples/simple/igraph_minimum_size_separators.c
@@ -0,0 +1,166 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int print_and_destroy(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];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+  igraph_vector_ptr_destroy(ptr);
+  return 0;
+}
+
+int main() {
+  igraph_t g, g2;
+  igraph_vector_ptr_t sep;
+  igraph_vs_t vs;
+  
+  igraph_small(&g, 7, IGRAPH_UNDIRECTED,
+	       1,0, 2,0, 3,0, 4,0, 5,0, 6,0,
+	       -1);
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_minimum_size_separators(&g, &sep);
+  print_and_destroy(&sep);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 5, IGRAPH_UNDIRECTED,
+	       0,3, 1,3, 2,3,
+	       0,4, 1,4, 2,4,
+	       -1);
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_minimum_size_separators(&g, &sep);
+  print_and_destroy(&sep);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 5, IGRAPH_UNDIRECTED,
+	       2,0, 3,0, 4,0,
+	       2,1, 3,1, 4,1,
+	       -1);
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_minimum_size_separators(&g, &sep);
+  print_and_destroy(&sep);
+  igraph_destroy(&g);
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 10, IGRAPH_UNDIRECTED,
+	       0,2, 0,3, 1,2, 1,3, 5,2, 5,3, 6,2, 6,3, 
+	       7,2, 7,3, 8,2, 8,3, 9,2, 9,3,
+	       2,4, 4,3,
+	       -1);
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_minimum_size_separators(&g, &sep);
+  print_and_destroy(&sep);
+  igraph_destroy(&g);  
+
+  /* ----------------------------------------------------------- */
+
+  igraph_full(&g, 4, IGRAPH_UNDIRECTED, /*loops=*/ 0);
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_minimum_size_separators(&g, &sep);
+  print_and_destroy(&sep);
+  igraph_destroy(&g);  
+
+  /* ----------------------------------------------------------- */
+
+  igraph_small(&g, 23, IGRAPH_UNDIRECTED,
+	       0,1, 0,2, 0,3, 0,4, 0,5,
+	       1,2, 1,3, 1,4, 1,6,
+	       2,3, 2,5, 2,6,
+	       3,4, 3,5, 3,6,
+	       4,5, 4,6, 4,20,
+	       5,6, 
+	       6,7, 6,10, 6,13, 6,18,
+	       7,8, 7,10, 7,13,
+	       8,9,
+	       9,11, 9,12,
+	       10,11, 10,13,
+	       11,15,
+	       12,15,
+	       13,14,
+	       14,15,
+	       16,17, 16,18, 16,19,
+	       17,19, 17,20,
+	       18,19, 18,21, 18,22,
+	       19,20,
+	       20,21, 20,22,
+	       21,22,
+	       -1);
+
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_minimum_size_separators(&g, &sep);
+  printf("Orig:\n"); print_and_destroy(&sep);
+
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_vs_vector_small(&vs, 0,1,2,3,4,5,6, 16,17,18,19,20,21,22, -1);
+  igraph_induced_subgraph(&g, &g2, vs, IGRAPH_SUBGRAPH_AUTO);
+  igraph_minimum_size_separators(&g2, &sep);
+  printf("1-7,17-23:\n"); print_and_destroy(&sep);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g2);
+  
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_vs_vector_small(&vs, 6,7,8,9,10,11,12,13,14,15, -1);
+  igraph_induced_subgraph(&g, &g2, vs, IGRAPH_SUBGRAPH_AUTO);
+  igraph_minimum_size_separators(&g2, &sep);
+  printf("7-16:\n"); print_and_destroy(&sep);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g2);
+  
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_vs_vector_small(&vs, 16,17,18,19,20,21,22, -1);
+  igraph_induced_subgraph(&g, &g2, vs, IGRAPH_SUBGRAPH_AUTO);
+  igraph_minimum_size_separators(&g2, &sep);
+  printf("17-23:\n"); print_and_destroy(&sep);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g2);
+  
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_vs_vector_small(&vs, 6,7,10,13, -1);
+  igraph_induced_subgraph(&g, &g2, vs, IGRAPH_SUBGRAPH_AUTO);
+  igraph_minimum_size_separators(&g2, &sep);
+  printf("7,8,11,14:\n"); print_and_destroy(&sep);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g2);
+
+  igraph_vector_ptr_init(&sep, 0);
+  igraph_vs_vector_small(&vs, 0,1,2,3,4,5,6, -1);
+  igraph_induced_subgraph(&g, &g2, vs, IGRAPH_SUBGRAPH_AUTO);
+  igraph_minimum_size_separators(&g2, &sep);
+  printf("1-7:\n"); print_and_destroy(&sep);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g2);  
+
+  igraph_destroy(&g);  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_minimum_size_separators.out b/examples/simple/igraph_minimum_size_separators.out
new file mode 100644
index 0000000..ef0e5fb
--- /dev/null
+++ b/examples/simple/igraph_minimum_size_separators.out
@@ -0,0 +1,30 @@
+0
+3 4
+0 1
+2 3
+1 2 3
+0 2 3
+0 1 3
+0 1 2
+Orig:
+6
+1-7,17-23:
+4 6
+6 11
+4 9
+9 11
+7-16:
+3 9
+7 9
+1 3
+17-23:
+2 4
+7,8,11,14:
+1 2 3
+0 2 3
+0 1 3
+0 1 2
+1-7:
+1 2 3 4 5
+0 2 3 4 6
+0 1 3 5 6
diff --git a/examples/simple/igraph_minimum_spanning_tree.c b/examples/simple/igraph_minimum_spanning_tree.c
new file mode 100644
index 0000000..4469765
--- /dev/null
+++ b/examples/simple/igraph_minimum_spanning_tree.c
@@ -0,0 +1,70 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g, tree;
+  igraph_vector_t eb, edges;
+  long int i;
+  
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);
+  
+  igraph_vector_init(&eb, igraph_ecount(&g));
+  igraph_edge_betweenness(&g, &eb, IGRAPH_UNDIRECTED, /*weights=*/ 0);
+  for (i=0; i<igraph_vector_size(&eb); i++) {
+    VECTOR(eb)[i] = -VECTOR(eb)[i];
+  }
+
+  igraph_minimum_spanning_tree_prim(&g, &tree, &eb);
+  igraph_write_graph_edgelist(&tree, stdout);
+
+  igraph_vector_init(&edges, 0);
+  igraph_minimum_spanning_tree(&g, &edges, &eb);
+  igraph_vector_print(&edges);
+  igraph_vector_destroy(&edges);
+
+  igraph_destroy(&tree);
+  igraph_destroy(&g);
+  igraph_vector_destroy(&eb);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_minimum_spanning_tree.out b/examples/simple/igraph_minimum_spanning_tree.out
new file mode 100644
index 0000000..32eebad
--- /dev/null
+++ b/examples/simple/igraph_minimum_spanning_tree.out
@@ -0,0 +1,34 @@
+0 2
+0 4
+0 5
+0 6
+0 8
+0 10
+0 11
+0 12
+0 17
+0 21
+0 31
+1 30
+2 3
+2 7
+2 9
+2 27
+2 32
+6 16
+13 33
+14 33
+15 33
+18 33
+19 33
+20 33
+22 33
+23 33
+24 31
+25 31
+26 33
+28 33
+29 33
+30 33
+31 33
+15 5 4 1 7 31 9 76 45 52 67 8 3 10 65 29 12 14 64 49 47 51 56 54 61 27 72 40 74 23 25 70 24
diff --git a/examples/simple/igraph_moran_process.c b/examples/simple/igraph_moran_process.c
new file mode 100644
index 0000000..42d8f32
--- /dev/null
+++ b/examples/simple/igraph_moran_process.c
@@ -0,0 +1,221 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for the Moran process in a network setting.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <assert.h>
+#include <igraph.h>
+#include <stdio.h>
+
+/* test parameters structure */
+typedef struct {
+  igraph_t *graph;
+  igraph_vector_t *weights;
+  igraph_vector_t *quantities;
+  igraph_vector_t *strategies;
+  igraph_neimode_t mode;
+  int retval;
+} strategy_test_t;
+
+/* Error tests, i.e. we expect errors to be raised for each test.
+ */
+int error_tests() {
+  igraph_t g, gzero, h;
+  igraph_vector_t quant, quantnvert, quantzero;
+  igraph_vector_t strat, stratnvert, stratzero;
+  igraph_vector_t wgt, wgtnedge, wgtzero;
+  int i, n, nvert, ret;
+  strategy_test_t *test;
+
+  igraph_empty(&h, 0, 0);  /* empty graph */
+  /* nonempty graph */
+  igraph_small(&g, /*nvert=*/ 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  nvert = igraph_vcount(&g);
+  /* weights vectors */
+  igraph_vector_init(&wgt, 0);
+  igraph_vector_init(&wgtnedge, igraph_ecount(&g));
+  /* quantities vectors */
+  igraph_vector_init(&quant, 1);
+  igraph_vector_init_real(&quantnvert, nvert, 0.1, 0.2, 0.3);
+  /* strategies vectors */
+  igraph_vector_init(&strat, 2);
+  igraph_vector_init_real(&stratnvert, nvert, 0.0, 1.0, 2.0);
+
+  igraph_small(&gzero, /*nvert=*/ 0, IGRAPH_UNDIRECTED,
+               0,3, 0,4, 1,2, 1,4, 1,5, 2,3, 2,4, 3,4, -1);
+  nvert = igraph_vcount(&gzero);
+  igraph_vector_init(&quantzero, nvert);                /* vector of zeros */
+  igraph_vector_init(&stratzero, nvert);                /* vector of zeros */
+  igraph_vector_init(&wgtzero, igraph_ecount(&gzero));  /* vector of zeros */
+  /* igraph_vector_init_real(&stratzero, nvert, 1.0, 0.0, 1.0, 2.0, 0.0, 3.0); */
+
+  /* test parameters */
+  /*------graph--weights--quantities--strategies--mode--retval------*/
+  /* null pointer for graph */
+  strategy_test_t null_graph = {NULL, NULL, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for weights vector */
+  strategy_test_t null_wgt = {&g, NULL, &quantnvert, &stratnvert, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for quantities vector */
+  strategy_test_t null_quant = {&g, &wgt, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for strategies vector */
+  strategy_test_t null_strat = {&g, &wgt, &quant, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* empty graph */
+  strategy_test_t empty_graph = {&h, &wgt, &quant, &strat, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of quantities vector different from number of vertices */
+  strategy_test_t qdiff_length = {&g, &wgtnedge, &quant, &strat, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of strategies vector different from number of vertices */
+  strategy_test_t sdiff_length = {&g, &wgtnedge, &quantnvert, &strat, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of weights vector different from number of edges */
+  strategy_test_t wdiff_length = {&g, &wgt, &quantnvert, &stratnvert, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* weights vector contains all zeros */
+  strategy_test_t zero_wgt = {&g, &wgtnedge, &quantnvert, &stratnvert, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* quantities vector contains all zeros */
+  strategy_test_t zero_quant = {&gzero, &wgtzero, &quantzero, &stratzero, IGRAPH_ALL, IGRAPH_EINVAL};
+  strategy_test_t *all_checks[] = {/* 1 */  &null_graph,
+                                   /* 2 */  &null_quant,
+                                   /* 3 */  &null_strat,
+                                   /* 4 */  &null_wgt,
+                                   /* 5 */  &empty_graph,
+                                   /* 6 */  &qdiff_length,
+                                   /* 7 */  &sdiff_length,
+                                   /* 8 */  &wdiff_length,
+                                   /* 9 */  &zero_quant,
+                                   /* 10 */ &zero_wgt};
+
+  /* Run the error tests. We expect error to be raised for each test. */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  n = 10;
+  i = 0;
+  while (i < n) {
+    test = all_checks[i];
+    ret = igraph_moran_process(test->graph, test->weights, test->quantities,
+                               test->strategies, test->mode);
+    if (ret != test->retval) {
+      printf("Error test no. %d failed.\n", (int)(i + 1));
+      return IGRAPH_FAILURE;
+    }
+    i++;
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_destroy(&gzero);
+  igraph_destroy(&h);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&quantnvert);
+  igraph_vector_destroy(&quantzero);
+  igraph_vector_destroy(&strat);
+  igraph_vector_destroy(&stratnvert);
+  igraph_vector_destroy(&stratzero);
+  igraph_vector_destroy(&wgt);
+  igraph_vector_destroy(&wgtnedge);
+  igraph_vector_destroy(&wgtzero);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* One iteration of the Moran process on a simple digraph.
+ */
+int moran_one_test() {
+  igraph_t g;
+  igraph_integer_t u = -1;  /* vertex chosen for reproduction */
+  igraph_integer_t v = -1;  /* clone of u */
+  igraph_integer_t nedge, nvert;
+  igraph_real_t q = 0.0;
+  igraph_vector_t quant, quantcp;
+  igraph_vector_t strat, stratcp;
+  igraph_vector_t wgt;
+  long int i;
+
+  /* graph representing the game network; quantities and strategies vectors */
+  igraph_small(&g, /*nvert*/ 0, IGRAPH_DIRECTED,
+               0,1, 0,4, 1,2, 1,4, 2,1, 3,2, 4,0, 4,3, -1);
+  nvert = igraph_vcount(&g);
+  nedge = igraph_ecount(&g);
+  igraph_vector_init_real(&quant, nvert, 0.77, 0.83, 0.64, 0.81, 0.05);
+  igraph_vector_init_real(&strat, nvert, 2.0, 0.0, 0.0, 1.0, 2.0);
+  /* Set the edge weights. Here we assume the following correspondence */
+  /* between edge IDs and directed edges: */
+  /* edge 0: 0 -> 1 */
+  /* edge 1: 0 -> 4 */
+  /* edge 2: 1 -> 2 */
+  /* edge 3: 1 -> 4 */
+  /* edge 4: 2 -> 1 */
+  /* edge 5: 3 -> 2 */
+  /* edge 6: 4 -> 0 */
+  /* edge 7: 4 -> 3 */
+  igraph_vector_init_real(&wgt, nedge, 1.9, 0.8, 6.2, 2.4, 1.1, 5.2, 7.3, 8.8);
+
+  /* play game */
+  igraph_vector_copy(&quantcp, &quant);
+  igraph_vector_copy(&stratcp, &strat);
+  igraph_moran_process(&g, &wgt, &quantcp, &stratcp, IGRAPH_OUT);
+
+  /* Determine which vertex was chosen for death. The original quantities */
+  /* vector contain unique values, i.e. no duplicates. Thus we compare the */
+  /* updated quantities with the original one. */
+  for (i = 0; i < igraph_vector_size(&quant); i++) {
+    if (VECTOR(quant)[i] != VECTOR(quantcp)[i]) {
+      /* found the new clone vertex */
+      v = (igraph_integer_t)i;
+      q = (igraph_real_t)VECTOR(quantcp)[i];
+      break;
+    }
+  }
+  assert(v >= 0);
+  assert(q != 0.0);
+
+  /* Now we know that v is a clone of some vertex. Determine the vertex that */
+  /* v is a clone of. */
+  for (i = 0; i < igraph_vector_size(&quant); i++) {
+    if (VECTOR(quant)[i] == q) {
+      /* found the vertex chosen for reproduction */
+      u = (igraph_integer_t)i;
+      break;
+    }
+  }
+  assert(u >= 0);
+
+  /* check that v is indeed a clone of u */
+  if (VECTOR(quant)[u] != VECTOR(quantcp)[v])
+    return IGRAPH_FAILURE;
+  if (VECTOR(strat)[u] != VECTOR(stratcp)[v])
+    return IGRAPH_FAILURE;
+
+  igraph_destroy(&g);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&quantcp);
+  igraph_vector_destroy(&strat);
+  igraph_vector_destroy(&stratcp);
+  igraph_vector_destroy(&wgt);
+
+  return IGRAPH_SUCCESS;
+}
+
+int main() {
+  int ret;
+
+  ret = error_tests();
+  if (ret)
+    return IGRAPH_FAILURE;
+  ret = moran_one_test();
+  if (ret)
+    return IGRAPH_FAILURE;
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/examples/simple/igraph_motifs_randesu.c b/examples/simple/igraph_motifs_randesu.c
new file mode 100644
index 0000000..41431a8
--- /dev/null
+++ b/examples/simple/igraph_motifs_randesu.c
@@ -0,0 +1,69 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v); 
+  igraph_real_t sum=0.0;
+  for (i=0; i<n; i++) {
+    if (!igraph_is_nan(VECTOR(*v)[i])) { sum += VECTOR(*v)[i]; }
+  }
+  for (i=0; i<n; i++) {
+    igraph_real_printf(VECTOR(*v)[i]/sum);
+    printf(" ");
+  }
+  printf("\n");
+}
+
+igraph_bool_t print_motif(const igraph_t *graph, igraph_vector_t *vids,
+    int isoclass, void* extra) {
+  printf("Class %d: ", isoclass);
+  igraph_vector_print(vids);
+  return 0;
+}
+
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t hist;
+  igraph_vector_t cp;
+
+  igraph_vector_init_real(&cp, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
+  igraph_ring(&g, 1000, IGRAPH_DIRECTED, 1, 1);
+  igraph_vector_init(&hist, 0);
+  igraph_motifs_randesu(&g, &hist, 3, &cp);
+  print_vector(&hist);
+  igraph_destroy(&g);
+  igraph_vector_destroy(&hist);
+
+  igraph_famous(&g, "bull");
+  igraph_motifs_randesu_callback(&g, 3, &cp, &print_motif, 0);
+  igraph_motifs_randesu_callback(&g, 4, &cp, &print_motif, 0);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&cp);
+  return 0;
+}
diff --git a/examples/simple/igraph_motifs_randesu.out b/examples/simple/igraph_motifs_randesu.out
new file mode 100644
index 0000000..c5eaebc
--- /dev/null
+++ b/examples/simple/igraph_motifs_randesu.out
@@ -0,0 +1,9 @@
+NaN NaN 0 NaN 0 0 0 0 0 0 1 0 0 0 0 0 
+Class 3: 0 2 1
+Class 2: 0 2 4
+Class 2: 0 1 3
+Class 2: 1 3 2
+Class 2: 1 2 4
+Class 7: 0 2 4 1
+Class 7: 0 2 1 3
+Class 6: 1 3 2 4
diff --git a/examples/simple/igraph_neighbors.c b/examples/simple/igraph_neighbors.c
new file mode 100644
index 0000000..b405dc6
--- /dev/null
+++ b/examples/simple/igraph_neighbors.c
@@ -0,0 +1,74 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v;
+  int ret;
+
+  igraph_vector_init(&v, 8);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=3;
+  VECTOR(v)[6]=2; VECTOR(v)[7]=2;
+  igraph_create(&g, &v, 0, 1);
+
+  igraph_neighbors(&g, &v, 2, IGRAPH_OUT);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+  
+  igraph_neighbors(&g, &v, 2, IGRAPH_IN);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+
+  igraph_neighbors(&g, &v, 2, IGRAPH_ALL);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+  
+  /* Errors */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  ret=igraph_neighbors(&g, &v, 2, (igraph_neimode_t)0); /* conv for c++ */
+  if (ret != IGRAPH_EINVMODE) {
+    return 1;
+  }
+  
+  ret=igraph_neighbors(&g, &v, 4, IGRAPH_ALL);
+  if (ret != IGRAPH_EINVVID) {
+    return 2;
+  }
+
+  igraph_vector_destroy(&v);
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/igraph_neighbors.out b/examples/simple/igraph_neighbors.out
new file mode 100644
index 0000000..9139118
--- /dev/null
+++ b/examples/simple/igraph_neighbors.out
@@ -0,0 +1,3 @@
+ 2 3
+ 1 2
+ 1 2 2 3
diff --git a/examples/simple/igraph_pagerank.c b/examples/simple/igraph_pagerank.c
new file mode 100644
index 0000000..d2f6b8f
--- /dev/null
+++ b/examples/simple/igraph_pagerank.c
@@ -0,0 +1,239 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <unistd.h>
+#include <libgen.h>
+
+void warning_handler_stdout (const char *reason, const char *file,
+			     int line, int igraph_errno) {
+  IGRAPH_UNUSED(igraph_errno);
+  printf("Warning: %s\n", reason);
+}
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %4.2f", VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+igraph_warning_handler_t *oldwarn;
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v, res, reset, weights;
+  igraph_arpack_options_t arpack_options;
+  igraph_real_t value;
+  int ret;
+  igraph_pagerank_power_options_t power_options;
+
+  /* Test graphs taken from http://www.iprcom.com/papers/pagerank/ */
+  igraph_vector_init(&v, 10);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
+  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
+  VECTOR(v)[4]=2; VECTOR(v)[5]=0;
+  VECTOR(v)[6]=3; VECTOR(v)[7]=2;
+  VECTOR(v)[8]=0; VECTOR(v)[9]=2;
+  igraph_create(&g, &v, 0, 1);
+
+  igraph_vector_init(&res, 0);
+  oldwarn=igraph_set_warning_handler(warning_handler_stdout);
+  igraph_pagerank_old(&g, &res, igraph_vss_all(), 1, 1000, 0.001, 0.85, 0);
+  print_vector(&res, stdout);
+  igraph_vector_destroy(&res);
+  igraph_vector_destroy(&v);
+  
+  igraph_destroy(&g);
+
+  igraph_vector_init(&v, 28);
+  VECTOR(v)[ 0]=0; VECTOR(v)[ 1]=1;
+  VECTOR(v)[ 2]=0; VECTOR(v)[ 3]=2;
+  VECTOR(v)[ 4]=0; VECTOR(v)[ 5]=3;
+  VECTOR(v)[ 6]=1; VECTOR(v)[ 7]=0;
+  VECTOR(v)[ 8]=2; VECTOR(v)[ 9]=0;
+  VECTOR(v)[10]=3; VECTOR(v)[11]=0;
+  VECTOR(v)[12]=3; VECTOR(v)[13]=4;
+  VECTOR(v)[14]=3; VECTOR(v)[15]=5;
+  VECTOR(v)[16]=3; VECTOR(v)[17]=6;
+  VECTOR(v)[18]=3; VECTOR(v)[19]=7;
+  VECTOR(v)[20]=4; VECTOR(v)[21]=0;
+  VECTOR(v)[22]=5; VECTOR(v)[23]=0;
+  VECTOR(v)[24]=6; VECTOR(v)[25]=0;
+  VECTOR(v)[26]=7; VECTOR(v)[27]=0;
+  igraph_create(&g, &v, 0, 1);
+
+  igraph_vector_init(&res, 0);
+  igraph_pagerank_old(&g, &res, igraph_vss_all(), 1, 10000, 0.0001, 0.85, 0);
+  print_vector(&res, stdout);
+  igraph_vector_destroy(&res);
+  igraph_vector_destroy(&v);
+  igraph_destroy(&g);
+
+  igraph_set_warning_handler(oldwarn);
+
+  /* New PageRank */
+  igraph_star(&g, 11, IGRAPH_STAR_UNDIRECTED, 0);
+  igraph_vector_init(&res, 0);
+  igraph_arpack_options_init(&arpack_options);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
+		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
+  print_vector(&res, stdout);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
+		  igraph_vss_all(), 0, 0.85, 0, 0);
+  print_vector(&res, stdout);
+  /* Check twice more for consistency */
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
+		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
+  print_vector(&res, stdout);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
+		  igraph_vss_all(), 0, 0.85, 0, 0);
+  print_vector(&res, stdout);
+
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
+		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
+  print_vector(&res, stdout);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
+		  igraph_vss_all(), 0, 0.85, 0, 0);
+  print_vector(&res, stdout);
+
+  /* Check personalized PageRank */
+  igraph_personalized_pagerank_vs(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
+				  igraph_vss_all(), 0, 0.5,
+				  igraph_vss_1(1), 0, &arpack_options);
+  print_vector(&res, stdout);
+  igraph_personalized_pagerank_vs(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
+				  igraph_vss_all(), 0, 0.5,
+				  igraph_vss_1(1), 0, 0);
+  print_vector(&res, stdout);
+
+  /* Errors */
+  power_options.niter = -1; power_options.eps=0.0001;
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  igraph_set_warning_handler(igraph_warning_handler_ignore);
+  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
+		      /*value=*/ 0, igraph_vss_all(), 1, 0.85,
+		      /*weights=*/ 0, &power_options);
+  if (ret != IGRAPH_EINVAL) {
+    return 1;
+  }
+  
+  power_options.niter=10000; power_options.eps=-1;
+  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
+		      /*value=*/ 0, igraph_vss_all(), 1, 0.85,
+		      /*weights=*/ 0, &power_options);
+  if (ret != IGRAPH_EINVAL) {
+    return 2;
+  }
+
+  power_options.niter=10000; power_options.eps=0.0001;
+  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
+		      /*value=*/ 0, igraph_vss_all(), 1, 1.2,
+		      /*weights=*/ 0, &power_options);
+  if (ret != IGRAPH_EINVAL) {
+    return 3;
+  }
+
+  igraph_vector_init(&reset, 2);
+  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
+				   igraph_vss_all(), 0, 0.85, &reset, 0,
+				   &arpack_options);
+  if (ret != IGRAPH_EINVAL) {
+    return 4;
+  }
+  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
+				   igraph_vss_all(), 0, 0.85, &reset, 0, 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 4;
+  }
+  igraph_vector_resize(&reset, 10);
+  igraph_vector_fill(&reset, 0);
+  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK,
+				   &res, 0, igraph_vss_all(), 0, 0.85,
+				   &reset, 0, &arpack_options);
+  if (ret != IGRAPH_EINVAL) {
+    return 5;
+  }
+  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK,
+				   &res, 0, igraph_vss_all(), 0, 0.85,
+				   &reset, 0, 0);
+  if (ret != IGRAPH_EINVAL) {
+    return 5;
+  }
+  igraph_vector_destroy(&reset);
+  igraph_destroy(&g);
+  igraph_set_error_handler(igraph_error_handler_abort);
+
+  /* Special cases: check for empty graph */
+  igraph_empty(&g, 10, 0);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, &value,
+		  igraph_vss_all(), 1, 0.85, 0, &arpack_options);
+  if (value != 1.0) {
+    return 6;
+  }
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, &value,
+		  igraph_vss_all(), 1, 0.85, 0, 0);
+  if (value != 1.0) {
+    return 6;
+  }
+  print_vector(&res, stdout);
+  igraph_destroy(&g);
+
+  /* Special cases: check for full graph, zero weights */
+  igraph_full(&g, 10, 0, 0);
+  igraph_vector_init(&v, 45);
+  igraph_vector_fill(&v, 0);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, &value,
+		  igraph_vss_all(), 1, 0.85, &v, &arpack_options);
+  if (value != 1.0) {
+    return 7;
+  }
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, &value,
+		  igraph_vss_all(), 1, 0.85, &v, 0);
+  if (value != 1.0) {
+    return 7;
+  }
+  igraph_vector_destroy(&v);
+  print_vector(&res, stdout);
+  igraph_destroy(&g);
+
+  /* Another test case for PageRank (bug #792352) */
+  igraph_small(&g, 9, 1, 0, 5, 1, 5, 2, 0, 3, 1, 5, 4, 5, 7, 6, 0, 8, 0, 8, 1, -1);
+  igraph_vector_init(&weights, 9);
+  VECTOR(weights)[0] = 4; VECTOR(weights)[1] = 5; VECTOR(weights)[2] = 5;
+  VECTOR(weights)[3] = 4; VECTOR(weights)[4] = 4; VECTOR(weights)[5] = 4;
+  VECTOR(weights)[6] = 3; VECTOR(weights)[7] = 4; VECTOR(weights)[8] = 4;
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
+		  igraph_vss_all(), 1, 0.85, &weights, &arpack_options);
+  print_vector(&res, stdout);
+  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
+		  igraph_vss_all(), 1, 0.85, &weights, 0);
+  print_vector(&res, stdout);
+  igraph_vector_destroy(&weights);
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&res);
+  return 0;
+}
diff --git a/examples/simple/igraph_pagerank.out b/examples/simple/igraph_pagerank.out
new file mode 100644
index 0000000..23ee843
--- /dev/null
+++ b/examples/simple/igraph_pagerank.out
@@ -0,0 +1,16 @@
+Warning: igraph_pagerank_old is deprecated from igraph 0.7, use igraph_pagerank instead
+ 0.37 0.20 0.39 0.04
+Warning: igraph_pagerank_old is deprecated from igraph 0.7, use igraph_pagerank instead
+ 0.42 0.14 0.14 0.14 0.04 0.04 0.04 0.04
+ 0.47 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+ 0.47 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+ 0.47 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+ 0.47 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+ 0.47 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+ 0.47 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+ 0.33 0.52 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02
+ 0.33 0.52 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02
+ 0.10 0.10 0.10 0.10 0.10 0.10 0.10 0.10 0.10 0.10
+ 0.10 0.10 0.10 0.10 0.10 0.10 0.10 0.10 0.10 0.10
+ 0.14 0.10 0.05 0.05 0.16 0.26 0.05 0.16 0.05
+ 0.14 0.10 0.05 0.05 0.16 0.26 0.05 0.16 0.05
diff --git a/examples/simple/igraph_power_law_fit.c b/examples/simple/igraph_power_law_fit.c
new file mode 100644
index 0000000..dcbcaab
--- /dev/null
+++ b/examples/simple/igraph_power_law_fit.c
@@ -0,0 +1,304 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+void print_result(const igraph_plfit_result_t* result) {
+  printf("continuous = %s\n", result->continuous ? "true" : "false");
+  printf("alpha = %.5f\n", result->alpha);
+  printf("xmin = %.5f\n", result->xmin);
+  printf("L = %.5f\n", result->L);
+  printf("D = %.5f\n", result->D);
+  printf("p = %.5f\n", result->p);
+  printf("====================\n");
+}
+
+int test_continuous() {
+  igraph_plfit_result_t result;
+  igraph_vector_t vector;
+  double data[] = { 1.52219974, 6.80675663, 1.02798042, 1.31180733, 3.97473174,
+        1.17209342, 1.64889191, 2.47764721, 1.32939375, 3.03762554, 1.62638327,
+        6.08405495, 1.70890382, 1.05294973, 1.17408407, 4.48945532, 1.16777371,
+        2.52502391, 1.09755984, 1.63838051, 1.03811206, 1.47224168, 1.57161431,
+        1.60163451, 2.08280263, 1.04678340, 1.33317526, 1.58588741, 1.26484666,
+        1.02367503, 1.57045702, 3.42374138, 1.23190611, 1.09378228, 1.04959505,
+        1.05818408, 1.43879491, 2.22750459, 1.41027204, 1.81964745, 2.80239939,
+        1.25399323, 1.07479219, 3.94616077, 1.26367914, 1.87367507, 1.35741026,
+        1.14867526, 7.33024762, 1.87957274, 2.79258534, 1.21682159, 1.61194300,
+        2.81885973, 1.21514746, 1.12850917, 51.85245035, 1.21883209, 1.04861029,
+        1.69215609, 2.18429429, 1.59752172, 1.41909984, 3.14393355, 1.18298455,
+        1.67063821, 1.88568524, 1.07445906, 1.45007973, 1.12568920, 1.56806310,
+        1.36996101, 1.19440982, 6.57296980, 1.35860725, 1.06552137, 1.16950701,
+        1.34750790, 1.66977492, 1.22658722, 1.62247444, 1.23458784, 8.55843760,
+        1.70020162, 4.76368831, 1.04846170, 1.13689661, 1.94449567, 1.10584812,
+        1.32525767, 1.26640912, 1.91372972, 1.56185373, 2.37829675, 1.04616674,
+        2.43549177, 1.14961092, 1.82106455, 1.25818298, 1.64763037, 1.43019402,
+        1.50439978, 1.90281251, 1.34827040, 1.57935671, 1.77260751, 1.06976614,
+        1.12236012, 2.19770254, 1.51825533, 1.19027804, 1.08307524, 1.57912902,
+        3.33313888, 2.14005088, 1.38341873, 1.20088138, 1.25870539, 1.03811620,
+        1.86622820, 2.99310953, 1.55615055, 2.12364873, 4.49081000, 1.01274439,
+        1.22373389, 3.79059729, 3.10099275, 2.70218546, 1.03609624, 2.20776919,
+        1.00651347, 1.87344592, 1.04903307, 1.24899747, 1.20377911, 1.12706494,
+        1.01706713, 7.01069306, 1.05363146, 2.50105512, 1.11168552, 1.71133998,
+        1.17714528, 1.37986755, 2.20981534, 1.18179277, 2.07982010, 4.04967099,
+        1.00680257, 1.62850069, 2.58816230, 1.35079027, 1.03382890, 4.54326500,
+        1.62489905, 1.36102570, 1.52349738, 1.06606346, 7.80558026, 1.02602538,
+        1.43330925, 1.36040920, 9.29692547, 15.27015690, 1.75966437, 1.02635409,
+        1.40421505, 2.87296958, 1.46232202, 1.87065204, 3.37278803, 1.82589564,
+        1.06488044, 1.72568108, 1.21062115, 4.39311214, 1.12636227, 2.20820528,
+        1.09826903, 2.58989998, 1.34944949, 1.08654244, 2.38021951, 3.96308780,
+        1.37494639, 1.18245279, 3.72506217, 3.79775023, 1.19018356, 2.86924476,
+        3.40015888, 1.92317855, 1.55203754, 1.34985008, 1.31480190, 1.65899877,
+        4.77446435, 1.41073246, 1.35555456, 2.40543613, 2.72162935, 1.34475982,
+        1.41342115, 5.15278473, 1.69654436, 3.21081899, 1.18822397, 1.40394863,
+        1.06793574, 1.67085563, 1.08125975, 1.11765459, 1.17245045, 1.15711479,
+        1.18656910, 1.61296203, 1.71427634, 1.24017302, 2.05291524, 2.52658791,
+        2.04645295, 34.07541626, 1.32670899, 1.03893757, 1.08957199, 5.55332328,
+        1.17276097, 1.60389480, 2.02098430, 2.92934928, 1.00558653, 1.05830070,
+        1.81440889, 3.85044779, 1.12317456, 1.39547640, 2.93105179, 1.95048788,
+        1.05602445, 1.96855429, 1.60432293, 3.28820202, 1.50117325, 1.19775674,
+        1.28280841, 1.08318646, 1.02098264, 1.24861938, 1.06511473, 1.07549717,
+        3.57739126, 1.07265409, 1.06312441, 1.16296512, 3.83654484, 2.02366951,
+        1.73168875, 1.60443228, 2.30779766, 1.50531775, 1.31925607, 1.87926179,
+        1.86249354, 2.14768716, 2.31583955, 2.15651148, 1.29677318, 1.10110071,
+        1.03383916, 1.50665009, 1.16502917, 1.40055008, 2.80847193, 1.29824634,
+        2.76239920, 1.73123621, 1.15286577, 1.89493526, 1.63112634, 1.17828846,
+        1.01293513, 1.84834048, 4.19026736, 1.82684815, 3.51812301, 1.33499862,
+        2.03087497, 1.32419883, 1.34126954, 1.98250684, 1.00025697, 1.59416883,
+        6.38249787, 2.79055559, 1.57750678, 1.36953983, 1.37513919, 3.63573178,
+        1.15637432, 9.28386344, 1.16947695, 1.54995742, 1.44018755, 1.29332881,
+        1.81274872, 1.14900153, 1.07117403, 1.17035915, 1.39229249, 1.96645872,
+        1.09147706, 1.25211993, 1.07092474, 1.85394206, 1.29807741, 3.41499510,
+        1.22444449, 1.00913782, 3.87431854, 1.01072376, 1.01186727, 3.00175639,
+        2.52183377, 1.23992099, 1.69819010, 1.36850400, 1.14577814, 1.06035078,
+        1.08414298, 1.55920217, 5.07059630, 1.15434572, 1.41873305, 1.24712256,
+        1.10478618, 1.30707247, 1.85719110, 1.89873207, 1.72629431, 1.65171651,
+        7.10864875, 2.31945709, 1.06722361, 1.26696259, 2.23845503, 1.38674196,
+        1.91015397, 1.29590323, 1.10448028, 4.52757499, 2.00258408, 1.38299092,
+        1.01431427, 1.54039270, 1.34880396, 1.08784083, 1.35553378, 1.37307373,
+        1.32320467, 1.50261683, 6.91050685, 1.06083157, 1.20841351, 2.92719840,
+        2.82178183, 2.05765813, 1.84621661, 1.04677388, 2.13801850, 1.39654855,
+        1.13037727, 1.37887598, 1.03221650, 1.15981176, 1.09896163, 1.88624084,
+        1.43459062, 1.54587662, 1.48604380, 2.06197392, 1.97079675, 4.31388672,
+        2.94376994, 3.48708489, 1.09674551, 2.46926816, 1.23705940, 1.57512843,
+        1.15595205, 1.18432818, 1.54298936, 1.60600489, 1.07361787, 1.38666771,
+        1.45533003, 1.78940830, 1.33799752, 1.12955889, 4.59400278, 1.15170228,
+        1.39346636, 1.61408789, 2.21293753, 5.33166143, 1.18147947, 1.54426891,
+        1.32496426, 1.25037632, 3.31244261, 1.36211171, 1.82239599, 1.75235087,
+        1.67044831, 1.24802350, 1.34776327, 1.34740665, 1.30664120, 1.06852680,
+        1.22513631, 1.25310923, 1.36394926, 1.07796356, 3.10823551, 1.46770227,
+        1.40264883, 1.08787681, 1.26460358, 1.10348946, 2.03168839, 1.09435135,
+        1.66991715, 1.19738540, 1.28922229, 2.85704149, 1.33952521, 1.73497688,
+        2.90052876, 5.34596348, 1.36399078, 3.38399264, 1.06089658, 1.09370142,
+        1.37523679, 3.01964907, 1.40684792, 1.11312672, 2.44666372, 1.73953904,
+        1.65569280, 1.05813000, 2.02893022, 1.72877601, 1.55758690, 1.83904301,
+        1.14316984, 1.17792251, 1.44106281, 9.67126482, 1.93207441, 1.08242887,
+        2.87271135, 2.19095115, 2.13195479, 1.02355472, 1.18218470, 1.30907724,
+        1.13291587, 2.85659336, 12.62726889, 1.18818589, 1.02852443, 1.12838670,
+        1.36349361, 1.34817100, 1.30535737, 3.22225028, 1.28680350, 1.83979657,
+        1.11088952, 1.43866586, 8.52587567, 3.73988696, 2.65816056, 1.17373111,
+        2.61567111, 3.24024082, 2.96798864, 1.05335616, 1.31159271, 1.36485918,
+        1.24988767, 7.80609746, 1.54892174, 1.10682809, 1.21728827, 1.20429971,
+        1.72719055, 1.78534831, 1.04414979, 1.25646988, 1.19788383, 1.08854812,
+        1.04859628, 1.04676064, 5.07295341, 3.83595341, 1.61079632, 1.10528426,
+        1.15050241, 2.78129736, 1.25494119, 1.28692155, 1.06812292, 3.29393761,
+        1.37542463, 1.67241953, 1.21698665, 10.57727604, 8.63598976, 1.18886984,
+        1.30609583, 9.47777457, 1.69612900, 2.23002585, 1.58461615, 1.04110023,
+        3.08140806, 1.39599251, 1.06575789, 1.29741002, 1.75253864, 1.82594258,
+        1.15111702, 1.17370053, 1.15254396, 1.94401179, 5.36344596, 4.66322185,
+        1.15073993, 3.21478159, 1.39843306, 1.03961906, 5.72845289, 1.72454161,
+        1.04610704, 1.38975310, 1.77732797, 1.10139931, 2.23656355, 1.89952669,
+        1.72136921, 1.15798212, 1.59545971, 1.08789161, 1.93272206, 2.57480708,
+        1.04977784, 2.00874078, 3.40065861, 1.00978603, 3.97804652, 1.54762586,
+        1.01015493, 1.15148220, 1.15246483, 19.67426012, 1.33290993, 2.33137522,
+        1.12841749, 1.73407057, 2.00469493, 1.27418995, 1.49814918, 1.10398785,
+        1.20063760, 1.05536150, 1.87616599, 1.49305736, 1.60241346, 1.16666060,
+        1.05013736, 1.77929210, 1.00206028, 3.41096863, 1.47499925, 1.14071240,
+        1.65361002, 1.76466424, 8.49298111, 1.41069285, 2.11681605, 4.90260842,
+        1.13029658, 1.20802818, 1.42525579, 1.00310774, 1.08082363, 9.95194247,
+        2.82773946, 2.77420002, 1.82543685, 1.28557906, 1.97711769, 1.19001264,
+        1.95712650, 1.54230291, 1.31625757, 2.36364128, 1.11523099, 1.00343756,
+        1.71299382, 1.44667100, 2.38154868, 1.41174217, 1.80660493, 1.51020853,
+        1.16761479, 1.25898190, 1.18150781, 1.58465451, 2.03560597, 3.48531184,
+        1.21187672, 1.35111036, 1.02954922, 1.90892663, 3.99078548, 5.67385199,
+        4.38055264, 1.17446048, 13.41617858, 1.60241740, 1.14811206, 4.68120263,
+        3.83763710, 2.66095263, 1.83338503, 4.75973082, 1.08982301, 4.04104276,
+        1.34220189, 1.06135891, 2.71185882, 1.46085873, 1.09915614, 10.35178646,
+        2.54402271, 2.65696704, 1.31388649, 1.02942408, 1.57780748, 1.01552697,
+        2.24860361, 2.22011778, 1.13595134, 1.11492512, 2.11966788, 1.20420149,
+        1.11112428, 3.09324603, 2.87240762, 1.50486558, 1.92227231, 4.12480449,
+        1.58244751, 1.69922308, 6.28134904, 2.91944178, 1.85386792, 1.41799519,
+        1.64636127, 2.05837832, 1.07153521, 2.05376943, 2.60053549, 1.09773382,
+        1.54671309, 1.68007415, 3.43941489, 1.41601033, 2.00237256, 1.20830978,
+        1.25582363, 1.10830461, 1.24850906, 1.88035202, 1.70557719, 1.04191110,
+        1.33501003, 1.33554804, 1.36935735, 4.79153510, 1.06566392, 1.14495966,
+        1.90020028, 1.08266994, 1.20588153, 1.40730214, 4.34320304, 1.71762330,
+        1.06620797, 1.39695239, 1.03024563, 3.94971225, 5.02945862, 1.06145571,
+        1.42511911, 2.13889169, 1.04986044, 1.91400616, 5.50708156, 1.52870464,
+        1.11303137, 1.05282759, 1.83793940, 3.05244089, 2.64499634, 1.51688076,
+        2.63350152, 1.31014486, 1.69462474, 1.67792130, 1.34236945, 1.02358460,
+        1.04593509, 1.04007620, 1.87990081, 1.28585413, 1.01636283, 3.55338495,
+        1.19542700, 1.23630628, 1.32321942, 4.03762786, 1.25379147, 1.12330233,
+        1.24966418, 1.26323243, 1.14779989, 1.20378343, 1.01531796, 1.44500318,
+        1.72723672, 15.68799957, 1.37641063, 7.00788166, 3.89674130, 1.68303382,
+        1.10089816, 1.72831362, 2.70479861, 1.75821836, 2.32404215, 2.64165162,
+        1.42441301, 1.83256456, 1.12548819, 4.81273800, 2.52840227, 2.68430190,
+        1.00928919, 1.02438446, 1.33909276, 2.32261242, 1.01299124, 1.07614975,
+        1.66823898, 1.97172786, 1.01707292, 1.68325092, 1.76834032, 1.08952069,
+        1.02265517, 1.96843176, 1.83351706, 1.92704772, 18.44811035, 1.00178046,
+        2.70555953, 1.35839004, 1.04834633, 1.26649072, 2.87152600, 4.12536409,
+        1.25200853, 1.71199647, 1.61175739, 1.26313274, 1.75224120, 2.70412800,
+        1.33998630, 1.61271556, 2.65784769, 10.38771107, 1.33121364, 1.01207979,
+        2.00238212, 2.50195600, 1.96917548, 1.71618169, 1.37050585, 10.11861690,
+        1.18339112, 1.80083386, 2.88582103, 1.21935761, 2.37900131, 1.49449487,
+        4.75106319, 2.33977804, 2.87963540, 1.01807103, 3.74847411, 1.71981276,
+        1.50726964, 1.20723219, 1.37904840, 1.04565533, 1.59877004, 1.11481349,
+        2.17320556, 2.07108468, 1.23274077, 1.75180110, 1.27558910, 1.63240839,
+        1.58760550, 1.01266256, 1.30395323, 1.14618521, 1.02385023, 2.24198100,
+        1.26765471, 1.15855534, 1.83936251, 1.32970987, 1.25844192, 1.31133485,
+        4.74300303, 6.19325623, 1.31832913, 3.97645560, 1.00545340, 1.24431862,
+        1.25855820, 1.15514241, 1.35986865, 1.72446070, 1.13069572, 2.45890932,
+        1.00394684, 1.03533631, 1.87698184, 2.34576160, 1.03997887, 1.02694456,
+        2.52227100, 2.66278467, 1.17002905, 3.42239624, 2.46753038, 1.17103623,
+        1.07832850, 1.42782632, 1.29110546, 1.03435772, 1.33512109, 1.14337058,
+        1.34103634, 1.15155161, 2.59805360, 2.09650343, 1.53399143, 1.02319185,
+        1.32210667, 1.05720671, 1.20882651, 2.34881662, 1.05163662, 3.26219380,
+        10.58124156, 1.07283644, 1.02105339, 1.23268679, 1.81469813, 1.49393533,
+        1.29760853, 5.37676625, 1.02529938, 1.86815537, 1.57961476, 3.77408176,
+        2.79405589, 3.25246617, 1.63913824, 3.12133428, 1.03787574, 4.17232960,
+        1.33406468, 1.57119541, 1.13675102, 3.42874720, 1.13066210, 1.33896458,
+        1.23883935, 1.35272696, 1.15172654, 2.18633755, 1.23251881, 1.59742606,
+        1.08718410, 1.06168544, 1.19926517, 1.00214807, 1.29121086, 3.44575916,
+        1.26524744, 1.16718301, 4.11789988, 1.25375574, 1.35753968, 1.69247751,
+        1.28473150, 2.20669768, 1.53213883, 2.30598771, 1.68420243, 1.37320685,
+        2.08619411, 1.26990265, 1.82215898, 1.10656122, 1.40229835, 1.11896817,
+        1.00127366, 2.88218857, 2.79105702, 1.28699225, 1.15929737, 1.07928363,
+        10.54130128, 8.79261793, 1.15699405, 1.69050500, 2.76586152, 1.22802809,
+        1.38014655, 2.19208585, 1.64409370, 1.46918371, 2.99582898, 1.37759923,
+        1.29776632, 1.82884215, 2.67317357, 1.37063041, 1.26884340, 1.07874723,
+        1.48172681, 1.01771849, 2.40642202, 1.37115433, 1.05954574, 2.12998246,
+        2.34178079, 1.54515623, 1.00179963, 2.12228030, 1.46007334, 1.20664530,
+        1.31417158, 1.03322353, 1.95420119, 1.30541569, 1.15016102, 2.17036908,
+        2.81707947, 1.16173181, 2.01742565, 1.02478594, 1.57428560, 1.21209176,
+        2.20735202, 1.12935761, 2.08850147, 1.05353378, 1.02324910, 1.49636415,
+        1.48061026, 2.25651770, 3.04296168, 1.24380806, 1.07707360, 2.00284318,
+        10.02810932, 3.38695326, 6.82841534, 2.13556915, 1.19152238};
+
+  igraph_vector_view(&vector, data, sizeof(data) / sizeof(data[0]));
+
+  /* determining xmin and alpha */
+  if (igraph_power_law_fit(&vector, &result, -1, 0))
+    return 1;
+  print_result(&result);
+
+  /* determining alpha only */
+  if (igraph_power_law_fit(&vector, &result, 2, 0))
+    return 2;
+  print_result(&result);
+
+  return 0;
+}
+
+int test_discrete() {
+  igraph_plfit_result_t result;
+  igraph_vector_t vector;
+  double data[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+        2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1,
+        1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1,
+        1, 1, 1, 1, 1, 1, 6, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 4, 1, 1, 1,
+        1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1,
+        1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1,
+        1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+        1, 2, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 4, 1, 1, 14, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 2,
+        1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1,
+        1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 4, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 2, 5, 1, 1, 5, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1,
+        2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1,
+        2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1,
+        1, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2,
+        1, 1, 1, 1, 2, 11, 1, 33, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2,
+        2, 1, 1, 1, 2, 2, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1,
+        1, 1, 2, 1, 2, 1, 1, 12, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1,
+        3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
+        1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 2, 2, 2, 2, 1, 1, 1, 4, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+        3, 2, 1, 1, 1, 2 };
+
+  igraph_vector_view(&vector, data, sizeof(data) / sizeof(data[0]));
+
+  /* determining xmin and alpha */
+  if (igraph_power_law_fit(&vector, &result, -1, 0))
+    return 3;
+  print_result(&result);
+
+  /* determining alpha only */
+  if (igraph_power_law_fit(&vector, &result, 2, 0))
+    return 4;
+  print_result(&result);
+
+  /* forcing continuous fitting */
+  if (igraph_power_law_fit(&vector, &result, -1, 1))
+    return 5;
+  print_result(&result);
+
+  /* forcing continuous fitting, xmin given */
+  if (igraph_power_law_fit(&vector, &result, 2, 1))
+    return 6;
+  print_result(&result);
+
+  return 0;
+}
+
+int main() {
+  int retval;
+
+  retval = test_continuous();
+  if (retval)
+    return retval;
+
+  retval = test_discrete();
+  if (retval)
+    return retval;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_power_law_fit.out b/examples/simple/igraph_power_law_fit.out
new file mode 100644
index 0000000..6c95b38
--- /dev/null
+++ b/examples/simple/igraph_power_law_fit.out
@@ -0,0 +1,42 @@
+continuous = true
+alpha = 2.81976
+xmin = 1.00979
+L = -946.14703
+D = 0.01454
+p = 0.98525
+====================
+continuous = true
+alpha = 2.81157
+xmin = 2.00000
+L = -463.92064
+D = 0.05091
+p = 0.46011
+====================
+continuous = false
+alpha = 3.11402
+xmin = 1.00000
+L = -622.60933
+D = 0.00941
+p = 0.99999
+====================
+continuous = false
+alpha = 3.27159
+xmin = 2.00000
+L = -185.83215
+D = 0.04504
+p = 0.90576
+====================
+continuous = true
+alpha = 3.77550
+xmin = 11.00000
+L = -13.68681
+D = 0.15260
+p = 0.99902
+====================
+continuous = true
+alpha = 5.26868
+xmin = 2.00000
+L = -75.22503
+D = 0.70253
+p = 0.00000
+====================
diff --git a/examples/simple/igraph_preference_game.c b/examples/simple/igraph_preference_game.c
new file mode 100644
index 0000000..6ad94f9
--- /dev/null
+++ b/examples/simple/igraph_preference_game.c
@@ -0,0 +1,131 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <assert.h>
+
+int main() {
+  igraph_t g;
+  igraph_vector_t tdist;
+  igraph_matrix_t pmat;
+  igraph_bool_t conn;
+  igraph_vector_bool_t bs;
+  int i;
+  
+  /* Symmetric preference game */
+  igraph_vector_bool_init(&bs, 0);
+
+  igraph_vector_init_real(&tdist, 3, 1.0, 1.0, 1.0);
+
+  igraph_matrix_init(&pmat, 3, 3);
+  for (i=0; i<3; i++) MATRIX(pmat, i, i) = 0.2;
+
+  /* undirected, no loops */
+  IGRAPH_CHECK(igraph_preference_game(&g, 1000, 3, &tdist, /*fixed_sizes=*/ 0,
+				      &pmat, 0, 0, 0));
+  if (igraph_vcount(&g) != 1000) return 18;
+  if (igraph_is_directed(&g)) return 2;
+  igraph_is_connected(&g, &conn, IGRAPH_STRONG);
+  if (conn) return 3;
+  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 4;
+  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 5;
+  igraph_destroy(&g);
+
+  for (i=0; i<2; i++) MATRIX(pmat, i, i+1) = 0.1;
+
+  /* directed, no loops */
+  IGRAPH_CHECK(igraph_preference_game(&g, 1000, 3, &tdist, /*fixed_sizes=*/0, 
+				      &pmat, 0, 1, 0));
+  if (igraph_vcount(&g) != 1000) return 17;
+  if (!igraph_is_directed(&g)) return 6;
+  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 7;
+  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 8;
+  igraph_destroy(&g);
+
+  /* undirected, loops */
+  for (i=0; i<3; i++) MATRIX(pmat, i, i) = 1.0;
+  IGRAPH_CHECK(igraph_preference_game(&g, 100, 3, &tdist, /*fixed_sizes=*/ 0,
+				      &pmat, 0, 0, 1));
+  if (igraph_vcount(&g) != 100) return 16;
+  if (igraph_ecount(&g) < 1395) return 20;
+  if (igraph_is_directed(&g)) return 9;
+  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs) == 0) return 10;
+  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 11;
+  igraph_destroy(&g);
+
+  /* directed, loops */
+  IGRAPH_CHECK(igraph_preference_game(&g, 100, 3, &tdist, /*fixed_sizes=*/ 0,
+				      &pmat, 0, 1, 1));
+  if (igraph_vcount(&g) != 100) return 15;
+  if (igraph_ecount(&g) < 2700) return 19;
+  if (!igraph_is_directed(&g)) return 12;
+  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs) == 0) return 13;
+  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 14;
+  igraph_destroy(&g);
+
+  /* Asymmetric preference game */
+
+  /* directed, no loops */
+  igraph_matrix_resize(&pmat, 2, 2);
+  MATRIX(pmat, 0, 0) = 1; MATRIX(pmat, 0, 1) = 1;
+  MATRIX(pmat, 1, 0) = 1; MATRIX(pmat, 1, 1) = 1;
+  IGRAPH_CHECK(igraph_asymmetric_preference_game(&g, 100, 2, 0, &pmat, 0, 0, 0));
+  if (igraph_vcount(&g) != 100) return 21;
+  if (igraph_ecount(&g) != 9900) return 22;
+  if (!igraph_is_directed(&g)) return 23;
+  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 24;
+  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 25;
+  igraph_destroy(&g);
+
+  /* directed, loops */
+  igraph_matrix_resize(&pmat, 2, 2);
+  MATRIX(pmat, 0, 0) = 1; MATRIX(pmat, 0, 1) = 1;
+  MATRIX(pmat, 1, 0) = 1; MATRIX(pmat, 1, 1) = 1;
+  IGRAPH_CHECK(igraph_asymmetric_preference_game(&g, 100, 2, 0, &pmat, 0, 0, 1));
+  if (igraph_vcount(&g) != 100) return 26;
+  if (igraph_ecount(&g) != 10000) return 27;
+  if (!igraph_is_directed(&g)) return 28;
+  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs) != 100) return 29;
+  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
+  if (igraph_vector_bool_sum(&bs)) return 30;
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&tdist);
+  igraph_matrix_destroy(&pmat);
+  igraph_vector_bool_destroy(&bs);
+
+  assert(IGRAPH_FINALLY_STACK_EMPTY);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_psumtree.c b/examples/simple/igraph_psumtree.c
new file mode 100644
index 0000000..df97b43
--- /dev/null
+++ b/examples/simple/igraph_psumtree.c
@@ -0,0 +1,197 @@
+
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_psumtree.h>
+#include <stdlib.h>
+
+int print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf("%li ", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+  return 0;
+}
+
+int main() {
+  igraph_psumtree_t tree;
+  igraph_vector_t vec;
+  long int i;
+  igraph_real_t sum;
+
+  /* Uniform random numbers */
+  igraph_vector_init(&vec, 16);
+  igraph_psumtree_init(&tree, 16);
+  sum=igraph_psumtree_sum(&tree);
+  if (sum != 0) {
+    printf("Sum: %f instead of 0.\n", sum);
+    return 1;
+  }
+
+  for (i=0; i<16; i++) {
+    igraph_psumtree_update(&tree, i, 1);
+  }
+  if ((sum=igraph_psumtree_sum(&tree)) != 16) {
+    printf("Sum: %f instead of 16.\n", sum);
+    return 2;
+  }
+  
+  for (i=0; i<16000; i++) {
+    igraph_real_t r=((double)rand())/RAND_MAX * sum;
+    long int idx;
+    igraph_psumtree_search(&tree, &idx, r);
+    VECTOR(vec)[idx] += 1;
+  }  
+  for (i=0; i<16; i++) {
+    if (VECTOR(vec)[i] < 800 || VECTOR(vec)[i] > 1200) {
+      return 3;
+    }
+  }
+
+  /* Nonuniform, even indices have twice as much chance */
+  for (i=0; i<16; i+=2) {
+    igraph_psumtree_update(&tree, i, 2);
+  }
+  if ((sum=igraph_psumtree_sum(&tree)) != 24) {
+    printf("Sum: %f instead of 24.\n", sum);
+    return 4;
+  }
+  
+  igraph_vector_null(&vec);
+  for (i=0; i<24000; i++) {
+    igraph_real_t r=((double)rand())/RAND_MAX * sum;
+    long int idx;
+    igraph_psumtree_search(&tree, &idx, r);
+    VECTOR(vec)[idx] += 1;
+  }
+  for (i=0; i<16; i++) {
+    if (i%2 == 0 && (VECTOR(vec)[i] < 1800 || VECTOR(vec)[i] > 2200)) {
+      return 5;
+    }
+    if (i%2 != 0 && (VECTOR(vec)[i] < 800 || VECTOR(vec)[i] > 1200)) {
+      return 6;
+    }
+  }
+  
+  /* Test zero probabilities */
+  igraph_psumtree_update(&tree, 0, 0);
+  igraph_psumtree_update(&tree, 5, 0);
+  igraph_psumtree_update(&tree, 15, 0);
+  sum=igraph_psumtree_sum(&tree);
+  
+  igraph_vector_null(&vec);
+  for (i=0; i<20000; i++) {
+    igraph_real_t r=((double)rand())/RAND_MAX * sum;
+    long int idx;
+    igraph_psumtree_search(&tree, &idx, r);
+    VECTOR(vec)[idx] += 1;
+  }
+  if (VECTOR(vec)[0] != 0 || VECTOR(vec)[5] != 0 || VECTOR(vec)[15] != 0) {
+    return 7;
+  }
+
+  igraph_vector_destroy(&vec);
+  igraph_psumtree_destroy(&tree);
+
+  /****************************************************/
+  /* Non power-of-two vector size                     */
+  /****************************************************/
+
+  igraph_vector_init(&vec, 9);
+  igraph_psumtree_init(&tree, 9);
+
+  for (i=0; i<9; i++) {
+    igraph_psumtree_update(&tree, i, 1);
+  }
+  sum=igraph_psumtree_sum(&tree);
+  
+  for (i=0; i<9000; i++) {
+    igraph_real_t r=((double)rand())/RAND_MAX * sum;
+    long int idx;
+    igraph_psumtree_search(&tree, &idx, r);
+    VECTOR(vec)[idx] += 1;
+  }  
+  for (i=0; i<9; i++) {
+    if (VECTOR(vec)[i] < 800 || VECTOR(vec)[i] > 1200) {
+      return 8;
+    }
+  }
+
+  /* Nonuniform, even indices have twice as much chance */
+  for (i=0; i<9; i+=2) {
+    igraph_psumtree_update(&tree, i, 2);
+  }
+  sum=igraph_psumtree_sum(&tree);
+  
+  igraph_vector_null(&vec);
+  for (i=0; i<14000; i++) {
+    igraph_real_t r=((double)rand())/RAND_MAX * sum;
+    long int idx;
+    igraph_psumtree_search(&tree, &idx, r);
+    VECTOR(vec)[idx] += 1;
+  }
+  for (i=0; i<9; i++) {
+    if (i%2 == 0 && (VECTOR(vec)[i] < 1800 || VECTOR(vec)[i] > 2200)) {
+      return 9;
+    }
+    if (i%2 != 0 && (VECTOR(vec)[i] < 800 || VECTOR(vec)[i] > 1200)) {
+      return 10;
+    }
+  }
+
+  /* Test query */
+  for (i=0; i<igraph_psumtree_size(&tree); i++) {
+    if (i%2==0 && igraph_psumtree_get(&tree, i) != 2) {
+      return 11;
+    }
+    if (i%2!=0 && igraph_psumtree_get(&tree, i) != 1) {
+      return 12;
+    }
+  }
+  
+  /* Test zero probabilities */
+  igraph_psumtree_update(&tree, 0, 0);
+  igraph_psumtree_update(&tree, 5, 0);
+  igraph_psumtree_update(&tree, 8, 0);
+  sum=igraph_psumtree_sum(&tree);
+  
+  igraph_vector_null(&vec);
+  for (i=0; i<9000; i++) {
+    igraph_real_t r=((double)rand())/RAND_MAX * sum;
+    long int idx;
+    igraph_psumtree_search(&tree, &idx, r);
+    VECTOR(vec)[idx] += 1;
+  }
+  if (VECTOR(vec)[0] != 0 || VECTOR(vec)[5] != 0 || VECTOR(vec)[8] != 0) {
+    return 11;
+  }
+
+  igraph_vector_destroy(&vec);
+  igraph_psumtree_destroy(&tree);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 13;
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_qsort.c b/examples/simple/igraph_qsort.c
new file mode 100644
index 0000000..7aef785
--- /dev/null
+++ b/examples/simple/igraph_qsort.c
@@ -0,0 +1,58 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int comp(const void *a, const void *b) {
+  igraph_real_t *aa=(igraph_real_t *) a;
+  igraph_real_t *bb=(igraph_real_t *) b;
+  
+  if (*aa < *bb) { 
+    return -1;
+  } else if (*aa > *bb) { 
+    return 1;
+  }
+
+  return 0;
+}
+
+int main() {  
+  const int len=100;
+  igraph_vector_t v;
+  int i;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_vector_init(&v, len);
+  for (i=0; i<len; i++) {
+    VECTOR(v)[i] = i;
+  }
+  igraph_vector_shuffle(&v);
+  
+  igraph_qsort(VECTOR(v), igraph_vector_size(&v), sizeof(VECTOR(v)[0]), comp);
+  
+  igraph_vector_print(&v);
+  
+  igraph_vector_destroy(&v);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_qsort.out b/examples/simple/igraph_qsort.out
new file mode 100644
index 0000000..580e05a
--- /dev/null
+++ b/examples/simple/igraph_qsort.out
@@ -0,0 +1 @@
+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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
diff --git a/examples/simple/igraph_qsort_r.c b/examples/simple/igraph_qsort_r.c
new file mode 100644
index 0000000..f0700cc
--- /dev/null
+++ b/examples/simple/igraph_qsort_r.c
@@ -0,0 +1,68 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int comp(void *extra, const void *a, const void *b) {
+  igraph_vector_t *v=(igraph_vector_t*) extra;
+  int *aa=(int*) a;
+  int *bb=(int*) b;
+  igraph_real_t aaa=VECTOR(*v)[*aa];
+  igraph_real_t bbb=VECTOR(*v)[*bb];
+  
+  if (aaa < bbb) { 
+    return -1;
+  } else if (aaa > bbb) { 
+    return 1;
+  }
+  
+  return 0;
+}
+
+int main() {
+  const int len=100;
+  igraph_vector_t v;
+  igraph_vector_int_t idx;
+  int i;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+  igraph_vector_init(&v, len);
+  igraph_vector_int_init(&idx, len);
+  for (i=0; i<len; i++) {
+    VECTOR(v)[i] = i;
+    VECTOR(idx)[i] = i;
+  }
+  igraph_vector_shuffle(&v);
+
+  igraph_qsort_r(VECTOR(idx), len, sizeof(VECTOR(idx)[0]), (void*) &v, comp);
+
+  for (i=0; i<len; i++) { 
+    printf("%g ", VECTOR(v)[ VECTOR(idx)[i] ]);
+  }
+  printf("\n");
+  
+  igraph_vector_int_destroy(&idx);
+  igraph_vector_destroy(&v);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_qsort_r.out b/examples/simple/igraph_qsort_r.out
new file mode 100644
index 0000000..246042d
--- /dev/null
+++ b/examples/simple/igraph_qsort_r.out
@@ -0,0 +1 @@
+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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
diff --git a/examples/simple/igraph_radius.c b/examples/simple/igraph_radius.c
new file mode 100644
index 0000000..bcdbc6c
--- /dev/null
+++ b/examples/simple/igraph_radius.c
@@ -0,0 +1,48 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   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
+
+*/
+
+#include <igraph.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_real_t radius;
+
+  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
+  igraph_radius(&g, &radius, IGRAPH_OUT);
+  if (radius != 1) { return 1; }
+  igraph_destroy(&g);
+  
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
+  igraph_radius(&g, &radius, IGRAPH_ALL);
+  if (radius != 1) { return 2; }
+  igraph_destroy(&g);
+
+  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
+  igraph_radius(&g, &radius, IGRAPH_OUT);
+  if (radius != 0) { return 3; }
+  igraph_destroy(&g);  
+
+  return 0;
+}
diff --git a/examples/simple/igraph_random_sample.c b/examples/simple/igraph_random_sample.c
new file mode 100644
index 0000000..3aac314
--- /dev/null
+++ b/examples/simple/igraph_random_sample.c
@@ -0,0 +1,224 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for random sampling.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <assert.h>
+#include <igraph.h>
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+
+#define R_INTEGER(a,b) (igraph_rng_get_integer(igraph_rng_default(), (a), (b)))
+
+/* test parameters */
+typedef struct {
+  igraph_integer_t low;
+  igraph_integer_t high;
+  igraph_integer_t length;
+  int retval;
+} sampling_test_t;
+
+/* Error tests. Don't be afraid to crash the library function.
+ */
+int error_test() {
+  const igraph_integer_t min = -1000;
+  const igraph_integer_t max = 1000;
+  igraph_integer_t low;       /* lower limit */
+  igraph_integer_t high;      /* upper limit */
+  igraph_integer_t length;    /* sample size */
+  igraph_integer_t poolsize;  /* size of candidate pool */
+  igraph_vector_t V;
+  int i, n, ret;
+  sampling_test_t *test;
+
+  igraph_rng_seed(igraph_rng_default(), time(0));
+  igraph_vector_init(&V, /*size*/ 0);
+
+  /* test parameters */
+  /*----------low----high----length----retval----------*/
+  /* lower limit is greater than upper limit */
+  do {
+    high = (igraph_integer_t)R_INTEGER(min, max);
+  } while (high == max);
+  do {
+    low = (igraph_integer_t)R_INTEGER(min, max);
+  } while (low <= high);
+  assert(low > high);
+  length = (igraph_integer_t)R_INTEGER(min, max);
+  sampling_test_t lower_bigger = {low, high, length, IGRAPH_EINVAL};
+  /* sample size is greater than size of candidate pool */
+  do {
+    high = (igraph_integer_t)R_INTEGER(min, max);
+  } while (high == min);
+  do {
+    low = (igraph_integer_t)R_INTEGER(min, max);
+  } while (low >= high);
+  assert(low < high);
+  poolsize = (igraph_integer_t)fabs((double)high - (double)low);
+  length = poolsize * poolsize;
+  sampling_test_t sample_size_bigger = {low, high, length, IGRAPH_EINVAL};
+
+  sampling_test_t *all_checks[] = {/* 1 */ &lower_bigger,
+                                   /* 2 */ &sample_size_bigger};
+
+  /* failure is the mother of success */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  n = 2;
+  for (i = 0; i < n; i++) {
+    test = all_checks[i];
+    ret = igraph_random_sample(&V, test->low, test->high, test->length);
+    if (ret != test->retval) {
+      printf("Error test no. %d failed.\n", (int)(i + 1));
+      return IGRAPH_FAILURE;
+    }
+  }
+  igraph_set_error_handler(igraph_error_handler_abort);
+
+  igraph_vector_destroy(&V);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* Get a few random samples and test their properties.
+ */
+int random_sample_test() {
+  const igraph_integer_t min = -1000;
+  const igraph_integer_t max = 1000;
+  igraph_integer_t low;       /* lower limit */
+  igraph_integer_t high;      /* upper limit */
+  igraph_integer_t length;    /* sample size */
+  igraph_integer_t poolsize;  /* size of candidate pool */
+  igraph_real_t sP;           /* population total sum */
+  igraph_real_t ss;           /* sample total sum */
+  igraph_vector_t V;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), time(0));
+
+  /* The generated sequence of numbers must be in increasing order. */
+  igraph_vector_init(&V, /*size*/ 0);
+  do {
+    high = (igraph_integer_t)R_INTEGER(min, max);
+  } while (high == min);
+  do {
+    low = (igraph_integer_t)R_INTEGER(min, max);
+  } while (low >= high);
+  poolsize = (igraph_integer_t)fabs((double)high - (double)low);
+  do {
+    length = (igraph_integer_t)R_INTEGER(1, max);
+  } while (length > poolsize);
+  igraph_random_sample(&V, low, high, length);
+  if (length != igraph_vector_size(&V)) {
+    printf("Requested vector length and resulting length mismatch.\n");
+    return IGRAPH_FAILURE;
+  }
+  for (i = 0; i < length - 1; i++) {
+    if (VECTOR(V)[i] >= VECTOR(V)[i+1]) {
+      printf("Sample not in increasing order.\n");
+      return IGRAPH_FAILURE;
+    }
+  }
+  igraph_vector_destroy(&V);
+
+  /* Let P be a candidate pool of positive integers with total sum s_P. */
+  /* Let S be a random sample from P and having total sum s_S. Then we */
+  /* have the bound s_s <= s_P. */
+  igraph_vector_init(&V, /*size*/ 0);
+  low = 1;
+  do {
+    high = (igraph_integer_t)R_INTEGER(low, max);
+  } while (high == low);
+  poolsize = (igraph_integer_t)fabs((double)high - (double)low);
+  do {
+    length = (igraph_integer_t)R_INTEGER(low, max);
+  } while (length > poolsize);
+  igraph_random_sample(&V, low, high, length);
+  /* Use Gauss' formula to sum all consecutive positive integers from 1 */
+  /* up to and including an upper limit. In LaTeX, Gauss' formula is */
+  /* \sum_{i=1}^n i = \frac{n(n+1)}{2} where n is the upper limit. */
+  sP = (high * (high + 1)) / 2;
+  ss = igraph_vector_sum(&V);
+  if (ss > sP) {
+    printf("Sum of sampled sequence exceeds sum of whole population.\n");
+    return IGRAPH_FAILURE;
+  }
+  igraph_vector_destroy(&V);
+
+  return IGRAPH_SUCCESS;
+}
+
+int equal_test() {
+  igraph_vector_t V;
+  int i;
+
+  igraph_vector_init(&V, 0);
+
+  igraph_random_sample(&V, 0, 0, 1);
+  if (igraph_vector_size(&V) != 1) { return 1; }
+  if (VECTOR(V)[0] != 0) { return 2; }
+
+  igraph_random_sample(&V, 10, 10, 1);
+  if (igraph_vector_size(&V) != 1) { return 3; }
+  if (VECTOR(V)[0] != 10) { return 4; }
+  
+  igraph_random_sample(&V, 2, 12, 11);
+  if (igraph_vector_size(&V) != 11) { return 5; }
+  for (i = 0; i < 11; i++)
+    if (VECTOR(V)[i] != i+2) { return 6; }
+  
+  igraph_vector_destroy(&V);
+  return 0;
+}
+
+int rare_test() {
+  igraph_vector_t V;
+
+  igraph_vector_init(&V, 0);
+
+  igraph_random_sample(&V, 0, 0, 1);
+  if (igraph_vector_size(&V) != 1) { return 1; }
+  if (VECTOR(V)[0] != 0) { return 2; }
+
+  igraph_random_sample(&V, 10, 10, 1);
+  if (igraph_vector_size(&V) != 1) { return 3; }
+  if (VECTOR(V)[0] != 10) { return 4; }
+  
+  igraph_vector_destroy(&V);
+  return 0;
+}
+
+int main() {
+  int ret;
+
+  ret = error_test();
+  if (ret)
+    return 1;
+  ret = random_sample_test();
+  if (ret)
+    return 2;
+  ret = equal_test();
+  if (ret)
+    return 3;
+  ret = rare_test();
+  if (ret)
+    return 4;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_read_graph_dl.c b/examples/simple/igraph_read_graph_dl.c
new file mode 100644
index 0000000..26949b7
--- /dev/null
+++ b/examples/simple/igraph_read_graph_dl.c
@@ -0,0 +1,61 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  
+  const char *files[] = { "fullmatrix1.dl", "fullmatrix2.dl", 
+			  "fullmatrix3.dl", "fullmatrix4.dl",
+			  "edgelist1.dl", "edgelist2.dl", "edgelist3.dl",
+			  "edgelist4.dl", "edgelist5.dl", "edgelist6.dl",
+			  "nodelist1.dl", "nodelist2.dl" };
+  int no_files=sizeof(files)/sizeof(const char*);
+  int i, ret;
+  igraph_t g;
+  FILE *infile;
+
+  for (i=0; i<no_files; i++) {
+    printf("Doing %s\n", files[i]);
+    infile=fopen(files[i], "r");
+    if (!infile) {
+      printf("Cannot open file: %s\n", files[i]);
+      exit(1+i);
+    }
+    igraph_read_graph_dl(&g, infile, /*directed=*/ 1);
+    ret=fclose(infile);
+    if (ret) {
+      printf("Cannot close file: %s\n", files[i]);
+      exit(11+i);
+    }
+    igraph_write_graph_edgelist(&g, stdout);
+    igraph_destroy(&g);
+  }
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0)
+    return 1;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_read_graph_dl.out b/examples/simple/igraph_read_graph_dl.out
new file mode 100644
index 0000000..c1fc54d
--- /dev/null
+++ b/examples/simple/igraph_read_graph_dl.out
@@ -0,0 +1,100 @@
+Doing fullmatrix1.dl
+0 1
+0 2
+0 3
+0 4
+1 0
+1 2
+2 0
+2 1
+2 4
+3 0
+4 0
+4 2
+Doing fullmatrix2.dl
+0 1
+0 2
+0 3
+1 0
+1 4
+2 0
+2 3
+3 0
+3 2
+3 4
+4 1
+4 3
+Doing fullmatrix3.dl
+0 1
+0 2
+0 3
+1 0
+1 4
+2 0
+2 3
+3 0
+3 2
+3 4
+4 1
+4 3
+Doing fullmatrix4.dl
+0 1
+0 2
+0 3
+1 0
+1 4
+2 0
+2 3
+3 0
+3 2
+3 4
+4 1
+4 3
+Doing edgelist1.dl
+0 1
+0 2
+1 2
+2 0
+3 2
+Doing edgelist2.dl
+0 1
+0 2
+1 2
+3 0
+4 2
+Doing edgelist3.dl
+0 1
+0 2
+1 2
+3 0
+4 2
+Doing edgelist4.dl
+0 1
+0 2
+1 2
+2 0
+3 2
+Doing edgelist5.dl
+0 1
+0 2
+1 2
+3 0
+4 2
+Doing edgelist6.dl
+0 1
+0 2
+1 2
+3 0
+4 2
+Doing nodelist1.dl
+0 1
+0 2
+1 2
+2 0
+3 2
+Doing nodelist2.dl
+0 1
+0 2
+1 2
+3 0
+4 2
diff --git a/examples/simple/igraph_read_graph_graphdb.c b/examples/simple/igraph_read_graph_graphdb.c
new file mode 100644
index 0000000..824a332
--- /dev/null
+++ b/examples/simple/igraph_read_graph_graphdb.c
@@ -0,0 +1,41 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  FILE *input;
+  
+  input=fopen("iso_b03_m1000.A00", "rb");
+  if (!input) {
+    return 1;
+  }
+  igraph_read_graph_graphdb(&g, input, IGRAPH_DIRECTED);
+  fclose(input);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_read_graph_graphdb.out b/examples/simple/igraph_read_graph_graphdb.out
new file mode 100644
index 0000000..ec9aa8e
--- /dev/null
+++ b/examples/simple/igraph_read_graph_graphdb.out
@@ -0,0 +1,1500 @@
+0 723
+1 37
+1 951
+3 310
+3 439
+4 64
+4 873
+6 875
+7 617
+8 0
+8 429
+9 711
+10 181
+10 184
+11 257
+11 262
+11 365
+12 400
+12 781
+13 61
+13 482
+13 963
+15 68
+15 567
+16 649
+17 93
+17 355
+18 32
+18 503
+19 53
+19 360
+19 646
+20 71
+20 220
+21 900
+21 909
+22 552
+22 778
+25 623
+25 731
+27 232
+28 293
+28 378
+29 179
+30 542
+30 713
+31 535
+32 312
+33 246
+33 828
+33 868
+34 230
+35 382
+35 519
+36 321
+37 767
+38 216
+38 658
+39 400
+39 889
+40 352
+40 941
+41 60
+41 540
+42 680
+44 280
+44 734
+45 520
+46 302
+46 940
+46 959
+47 928
+49 149
+50 29
+50 216
+50 658
+52 758
+53 455
+53 514
+54 500
+55 51
+55 506
+56 647
+57 352
+57 821
+58 945
+58 953
+59 320
+59 393
+60 157
+62 200
+62 669
+64 886
+65 69
+65 638
+66 390
+66 537
+67 981
+69 42
+70 7
+70 759
+70 991
+71 244
+72 137
+72 450
+72 932
+73 980
+74 819
+75 508
+75 973
+76 295
+76 573
+76 838
+78 778
+79 290
+79 627
+80 981
+81 712
+82 907
+83 17
+83 109
+83 125
+85 97
+86 239
+86 390
+86 850
+87 185
+87 260
+87 652
+88 24
+88 522
+88 614
+89 682
+90 302
+92 164
+95 465
+95 601
+96 23
+96 822
+97 895
+98 195
+98 241
+98 899
+99 367
+99 392
+99 749
+101 811
+102 696
+103 423
+104 55
+104 147
+104 879
+105 68
+105 161
+105 931
+106 318
+106 379
+107 20
+107 816
+108 240
+108 718
+108 883
+109 355
+110 130
+110 337
+111 89
+111 499
+112 91
+112 236
+112 835
+113 217
+113 668
+113 675
+114 199
+114 453
+114 830
+115 607
+116 854
+117 651
+117 710
+118 100
+118 511
+119 347
+119 812
+120 490
+121 521
+121 632
+121 982
+122 16
+122 130
+124 251
+124 644
+124 986
+126 26
+126 727
+126 918
+127 437
+128 194
+128 327
+129 595
+129 639
+131 488
+131 708
+132 60
+132 538
+133 5
+133 203
+134 179
+134 258
+134 913
+135 271
+135 842
+136 696
+136 858
+136 937
+137 273
+138 930
+139 432
+139 654
+139 959
+140 329
+141 627
+141 923
+144 715
+144 939
+145 513
+145 967
+147 2
+147 51
+148 704
+148 746
+150 944
+151 358
+151 611
+152 460
+154 77
+155 190
+155 953
+156 441
+156 962
+156 997
+157 833
+158 508
+158 973
+159 4
+159 423
+162 495
+162 995
+163 173
+164 146
+165 142
+165 187
+165 928
+166 676
+166 804
+167 177
+167 377
+168 175
+168 410
+170 917
+171 473
+172 898
+173 880
+174 177
+175 579
+175 779
+176 243
+176 500
+178 24
+178 84
+180 201
+180 341
+180 813
+181 876
+182 106
+183 202
+185 417
+185 894
+187 47
+188 263
+188 275
+188 786
+189 460
+189 683
+190 58
+190 576
+191 116
+191 324
+192 424
+192 464
+192 670
+193 614
+193 697
+194 829
+195 370
+196 132
+196 952
+197 49
+197 511
+198 506
+198 633
+200 158
+200 775
+201 433
+201 780
+202 394
+202 632
+203 267
+203 855
+204 214
+204 805
+205 990
+206 577
+206 806
+207 705
+208 804
+209 700
+210 764
+211 210
+212 560
+212 575
+212 899
+213 817
+214 110
+215 62
+215 556
+216 664
+217 471
+219 381
+219 645
+219 653
+221 103
+221 409
+221 873
+222 123
+222 420
+223 838
+224 371
+225 479
+225 840
+226 513
+226 761
+226 967
+228 128
+228 346
+228 489
+229 218
+229 459
+230 218
+230 459
+231 135
+231 845
+232 943
+233 391
+233 446
+234 275
+234 786
+235 384
+235 993
+236 635
+236 882
+237 163
+237 824
+238 138
+238 808
+240 259
+241 350
+241 543
+242 238
+242 272
+243 54
+243 319
+244 220
+244 761
+245 628
+245 872
+246 341
+247 273
+248 263
+248 691
+249 752
+250 161
+251 227
+252 565
+253 97
+253 251
+253 414
+254 225
+254 789
+255 407
+255 451
+256 183
+257 457
+259 590
+260 672
+260 894
+261 623
+262 390
+263 527
+264 684
+265 821
+266 507
+266 815
+267 5
+267 307
+268 111
+268 856
+269 616
+270 261
+270 693
+270 742
+271 845
+272 808
+272 935
+274 45
+274 998
+276 16
+276 130
+277 224
+278 572
+279 608
+279 630
+281 207
+282 440
+283 34
+283 117
+285 674
+286 952
+287 73
+287 358
+288 737
+289 933
+290 174
+291 758
+292 283
+293 434
+293 655
+294 38
+296 300
+297 322
+297 892
+298 154
+299 515
+299 864
+300 960
+301 222
+303 127
+303 288
+303 978
+304 314
+304 557
+305 936
+306 9
+306 94
+307 301
+307 420
+309 997
+310 856
+311 634
+312 921
+313 865
+314 450
+315 186
+315 249
+316 199
+317 659
+318 28
+318 434
+319 578
+319 849
+321 205
+322 142
+322 187
+323 618
+323 774
+324 211
+325 699
+325 753
+325 758
+326 399
+327 489
+328 170
+328 597
+329 621
+330 887
+331 64
+331 167
+332 240
+332 883
+333 122
+333 155
+333 649
+334 329
+335 561
+335 608
+335 985
+336 825
+337 276
+338 51
+338 506
+338 891
+339 446
+339 536
+340 107
+340 630
+342 48
+342 61
+343 84
+343 406
+343 533
+344 696
+345 936
+346 920
+348 502
+348 985
+350 575
+351 559
+351 799
+352 265
+353 677
+353 948
+354 718
+356 653
+356 655
+357 661
+359 138
+359 242
+360 455
+362 82
+362 486
+363 285
+363 345
+363 925
+364 289
+364 686
+364 898
+366 504
+366 866
+366 885
+368 92
+369 211
+370 628
+370 897
+371 868
+372 6
+372 993
+373 357
+373 799
+374 68
+374 161
+375 213
+375 636
+376 977
+377 620
+378 653
+379 277
+380 24
+380 84
+380 533
+382 186
+382 320
+383 341
+383 813
+384 372
+384 875
+385 626
+386 127
+386 288
+386 621
+387 103
+387 409
+388 481
+388 870
+389 153
+389 388
+391 339
+393 151
+393 287
+394 481
+395 280
+396 208
+396 890
+397 408
+398 0
+398 846
+399 264
+399 974
+401 74
+402 898
+403 229
+404 160
+404 412
+405 404
+405 915
+406 321
+407 869
+407 948
+411 518
+411 541
+411 994
+412 818
+413 63
+414 85
+414 227
+415 143
+415 580
+415 764
+416 96
+416 385
+417 347
+417 812
+418 77
+418 298
+418 619
+419 266
+420 5
+421 143
+422 514
+424 633
+426 171
+426 785
+427 40
+427 52
+427 265
+430 512
+431 474
+431 881
+432 90
+434 182
+435 249
+435 487
+436 129
+436 751
+437 334
+437 621
+438 444
+439 466
+439 983
+440 120
+440 146
+441 295
+441 309
+442 419
+442 507
+442 867
+443 848
+444 381
+444 572
+445 324
+445 369
+445 954
+447 397
+447 798
+448 182
+448 224
+448 379
+449 170
+450 273
+452 629
+452 656
+452 933
+453 488
+453 708
+454 80
+454 472
+454 765
+455 730
+456 56
+457 89
+457 499
+458 22
+458 78
+459 839
+461 360
+461 730
+462 137
+462 247
+463 101
+463 368
+464 528
+465 747
+466 391
+466 531
+467 304
+467 693
+468 181
+468 184
+468 826
+469 6
+469 498
+470 523
+470 878
+471 675
+471 995
+472 776
+472 919
+473 740
+474 347
+474 666
+475 397
+475 798
+476 401
+476 518
+477 532
+477 981
+478 172
+478 402
+480 754
+481 153
+482 342
+482 610
+483 152
+483 612
+483 741
+484 18
+484 724
+484 796
+485 892
+485 938
+486 323
+486 907
+487 315
+490 282
+491 61
+491 902
+492 421
+492 550
+493 330
+493 701
+494 827
+495 996
+496 750
+496 904
+497 745
+497 950
+500 629
+501 493
+501 871
+502 239
+503 724
+503 905
+504 308
+504 430
+505 346
+505 489
+507 725
+508 775
+509 331
+509 377
+509 886
+510 91
+510 150
+511 149
+512 308
+512 549
+514 646
+515 94
+515 801
+516 465
+516 601
+517 271
+517 361
+518 906
+519 320
+521 256
+522 193
+523 37
+524 769
+524 809
+524 969
+525 969
+526 23
+526 416
+527 275
+527 691
+528 424
+529 100
+529 428
+529 494
+530 389
+531 233
+531 983
+532 67
+532 485
+533 984
+534 21
+534 460
+534 683
+536 462
+537 262
+537 365
+538 157
+539 27
+540 145
+540 662
+541 866
+542 714
+543 195
+544 220
+544 967
+545 35
+545 186
+545 487
+546 635
+546 732
+547 387
+547 681
+547 900
+548 141
+548 988
+549 359
+549 930
+550 39
+551 208
+551 890
+552 823
+552 939
+553 269
+554 362
+554 478
+555 464
+555 667
+556 928
+557 693
+558 565
+560 349
+560 525
+561 279
+562 298
+562 974
+563 559
+563 799
+564 517
+565 859
+566 648
+567 759
+568 539
+568 660
+569 566
+569 602
+569 659
+570 120
+570 146
+571 7
+571 398
+572 877
+573 223
+574 9
+575 525
+576 848
+578 654
+579 410
+579 908
+580 421
+581 741
+582 739
+582 943
+583 305
+584 539
+584 660
+584 726
+585 206
+586 610
+587 204
+587 687
+588 376
+588 480
+588 859
+589 282
+589 425
+589 690
+590 354
+591 78
+591 330
+592 947
+593 578
+593 849
+593 926
+594 1
+594 523
+595 422
+595 646
+597 449
+597 687
+598 210
+598 369
+599 194
+599 367
+600 231
+600 305
+601 688
+602 317
+603 618
+604 596
+604 927
+605 168
+605 694
+605 745
+606 43
+606 344
+607 698
+607 737
+608 348
+609 336
+610 48
+611 59
+611 519
+612 581
+612 862
+613 173
+613 237
+613 609
+614 178
+615 577
+615 851
+616 306
+616 574
+617 863
+619 562
+619 684
+620 177
+620 290
+622 590
+622 732
+624 902
+624 963
+624 988
+625 82
+625 172
+625 554
+626 596
+627 174
+628 965
+629 976
+630 782
+631 559
+631 837
+632 256
+633 670
+634 827
+635 622
+637 692
+638 42
+639 422
+640 313
+640 832
+640 982
+641 280
+641 505
+642 456
+642 637
+642 647
+643 522
+644 227
+644 698
+645 356
+648 45
+648 966
+649 953
+650 73
+650 250
+651 34
+651 218
+652 443
+652 672
+655 378
+656 289
+656 976
+657 302
+657 395
+659 840
+660 643
+661 910
+662 513
+663 469
+663 875
+663 884
+664 26
+664 294
+665 133
+665 603
+666 119
+666 881
+667 435
+667 752
+668 413
+668 802
+669 47
+669 556
+670 891
+671 470
+671 637
+673 255
+673 677
+673 948
+674 209
+674 345
+675 413
+676 14
+676 831
+678 392
+678 749
+679 311
+679 964
+681 409
+682 268
+682 310
+685 376
+685 480
+685 795
+686 402
+687 695
+688 837
+689 535
+689 847
+690 490
+690 716
+691 75
+692 456
+692 946
+694 410
+694 497
+695 328
+697 568
+697 643
+699 140
+699 334
+700 123
+700 285
+701 591
+702 91
+702 150
+702 835
+703 101
+704 615
+704 999
+705 433
+705 780
+706 400
+706 550
+706 781
+707 10
+707 869
+707 888
+708 797
+709 30
+709 43
+710 292
+710 729
+711 94
+711 299
+712 277
+712 371
+713 43
+714 743
+715 821
+715 922
+716 403
+716 425
+717 553
+718 259
+719 26
+719 294
+719 727
+720 154
+720 510
+721 902
+721 988
+722 340
+722 782
+722 816
+723 429
+723 832
+724 968
+725 647
+725 815
+726 27
+726 793
+727 284
+728 164
+728 570
+728 958
+729 581
+729 862
+730 235
+731 261
+731 742
+732 354
+733 169
+733 281
+733 803
+734 395
+735 171
+735 596
+735 785
+736 118
+736 149
+736 844
+737 978
+738 528
+738 555
+739 196
+739 538
+740 426
+740 746
+742 557
+743 357
+744 542
+744 709
+744 792
+745 160
+747 592
+748 760
+748 784
+748 990
+749 599
+750 586
+751 153
+751 530
+752 738
+753 140
+753 291
+754 677
+754 795
+755 636
+755 678
+755 756
+756 375
+756 392
+757 179
+757 258
+759 617
+760 36
+760 205
+761 544
+762 246
+762 383
+763 566
+763 602
+763 966
+765 23
+766 14
+766 717
+766 971
+769 361
+769 564
+770 63
+770 463
+770 703
+771 214
+771 337
+772 269
+772 574
+772 971
+773 548
+773 721
+774 603
+774 855
+775 215
+776 80
+776 477
+777 317
+777 479
+778 701
+779 197
+780 281
+781 431
+782 561
+783 25
+783 258
+783 913
+784 85
+784 895
+785 604
+787 143
+787 598
+787 764
+788 199
+788 638
+788 957
+789 2
+789 479
+790 606
+790 713
+791 381
+791 438
+791 645
+792 714
+792 910
+793 232
+793 286
+794 223
+794 872
+795 353
+796 968
+797 234
+798 326
+800 473
+800 746
+801 274
+802 63
+802 703
+803 207
+803 871
+804 831
+805 771
+805 807
+807 587
+807 695
+808 125
+809 349
+809 361
+810 131
+810 786
+810 797
+811 368
+811 958
+813 433
+814 152
+814 189
+814 741
+815 56
+816 71
+817 74
+817 906
+818 93
+818 405
+819 213
+819 636
+820 296
+820 975
+822 385
+822 927
+823 144
+823 922
+824 296
+824 975
+825 768
+826 102
+827 934
+828 81
+828 762
+829 327
+829 367
+830 316
+830 488
+831 396
+832 865
+833 41
+833 662
+834 29
+834 658
+834 757
+835 882
+836 31
+836 585
+836 806
+837 95
+839 403
+839 425
+840 777
+841 313
+841 521
+842 583
+842 600
+843 428
+843 494
+843 634
+844 100
+844 428
+845 564
+846 8
+847 332
+847 857
+848 672
+849 54
+850 66
+850 502
+851 148
+851 800
+852 516
+852 747
+852 947
+853 336
+853 768
+854 284
+854 954
+855 665
+856 942
+857 535
+858 102
+860 419
+860 750
+861 408
+861 475
+861 592
+862 292
+863 571
+863 846
+864 801
+864 998
+865 429
+866 994
+867 496
+867 860
+868 81
+869 451
+870 183
+870 394
+871 169
+872 965
+873 423
+874 31
+874 689
+874 806
+876 826
+876 858
+877 438
+877 929
+878 594
+879 2
+879 254
+880 609
+880 825
+881 12
+882 546
+883 857
+884 498
+885 430
+885 541
+886 159
+887 169
+887 501
+888 184
+888 451
+889 492
+889 580
+890 278
+891 198
+892 67
+893 768
+893 956
+893 979
+894 812
+896 257
+896 365
+896 499
+897 543
+899 350
+901 14
+901 166
+901 717
+903 247
+903 446
+903 536
+904 48
+904 586
+905 32
+906 401
+907 618
+908 49
+908 779
+909 683
+909 912
+910 743
+911 123
+911 209
+911 301
+912 681
+912 900
+913 623
+914 162
+914 498
+915 93
+915 355
+916 245
+916 794
+916 838
+917 968
+918 116
+918 284
+919 526
+919 765
+920 44
+920 641
+921 300
+921 820
+922 57
+923 79
+923 773
+924 351
+924 631
+924 688
+925 583
+925 936
+926 432
+926 654
+927 626
+929 278
+929 551
+930 308
+931 15
+931 991
+932 314
+932 467
+933 686
+934 311
+934 964
+935 109
+935 125
+937 344
+937 790
+938 142
+938 297
+939 458
+940 657
+940 734
+941 52
+941 291
+942 3
+943 286
+944 77
+944 720
+945 443
+945 576
+946 671
+946 878
+947 408
+949 217
+949 495
+950 160
+950 412
+951 309
+951 767
+952 582
+954 191
+955 650
+956 252
+956 558
+957 65
+957 316
+958 92
+959 90
+960 312
+960 905
+961 264
+961 326
+961 447
+962 295
+962 573
+963 491
+964 680
+965 897
+966 520
+969 349
+970 69
+970 679
+970 680
+971 553
+972 436
+972 530
+972 639
+973 248
+974 684
+975 163
+976 176
+977 252
+977 859
+978 115
+979 558
+979 853
+980 358
+980 955
+982 841
+983 942
+984 36
+984 406
+985 239
+986 115
+986 698
+987 449
+987 796
+987 917
+989 250
+989 374
+989 955
+990 895
+991 567
+992 373
+992 563
+992 661
+993 461
+994 476
+995 949
+996 884
+996 914
+997 767
+998 520
+999 577
+999 585
diff --git a/examples/simple/igraph_read_graph_lgl-1.lgl b/examples/simple/igraph_read_graph_lgl-1.lgl
new file mode 100644
index 0000000..dfdf359
--- /dev/null
+++ b/examples/simple/igraph_read_graph_lgl-1.lgl
@@ -0,0 +1,7 @@
+# foo
+bar 
+foobar 5
+# foobar
+bat 
+tab
+# tab
diff --git a/examples/simple/igraph_read_graph_lgl-2.lgl b/examples/simple/igraph_read_graph_lgl-2.lgl
new file mode 100644
index 0000000..9834c88
--- /dev/null
+++ b/examples/simple/igraph_read_graph_lgl-2.lgl
@@ -0,0 +1,7 @@
+# foo
+bar 1
+foobar 2
+# foobar
+bat 10
+tab
+# tab
diff --git a/examples/simple/igraph_read_graph_lgl-3.lgl b/examples/simple/igraph_read_graph_lgl-3.lgl
new file mode 100644
index 0000000..f293023
--- /dev/null
+++ b/examples/simple/igraph_read_graph_lgl-3.lgl
@@ -0,0 +1,4 @@
+#
+1
+# 1
+2
diff --git a/examples/simple/igraph_read_graph_lgl.c b/examples/simple/igraph_read_graph_lgl.c
new file mode 100644
index 0000000..eed717a
--- /dev/null
+++ b/examples/simple/igraph_read_graph_lgl.c
@@ -0,0 +1,80 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph R package.
+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  FILE *input;
+
+  /* Without names and weights */
+  input=fopen("igraph_read_graph_lgl-1.lgl", "r");
+  if (!input) { 
+    return 1;
+  }
+  igraph_read_graph_lgl(&g, input, 0, IGRAPH_ADD_WEIGHTS_NO, 1);
+  fclose(input);
+  if (!igraph_is_directed(&g)) {
+    return 2;
+  }
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  /* With names and weights */
+  input=fopen("igraph_read_graph_lgl-2.lgl", "r");
+  if (!input) {
+    return 3;
+  }
+  igraph_read_graph_lgl(&g, input, 0, IGRAPH_ADD_WEIGHTS_NO, 1);
+  fclose(input);
+  if (!igraph_is_directed(&g)) {
+    return 4;
+  }
+  igraph_write_graph_ncol(&g, stdout, 0, 0);
+  igraph_destroy(&g);
+
+  /* Same graph, but forcing undirected mode */
+  input=fopen("igraph_read_graph_lgl-2.lgl", "r");
+  igraph_read_graph_lgl(&g, input, 0, IGRAPH_ADD_WEIGHTS_NO, 0);
+  fclose(input);
+  if (igraph_is_directed(&g)) {
+    return 5;
+  }
+  igraph_write_graph_ncol(&g, stdout, 0, 0);
+  igraph_destroy(&g);
+
+  /* Erroneous LGL file (empty vertex name) */
+  input=fopen("igraph_read_graph_lgl-3.lgl", "r");
+  if (!input) {
+    return 6;
+  }
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  if (igraph_read_graph_lgl(&g, input, 0, IGRAPH_ADD_WEIGHTS_NO, 1) !=
+		  IGRAPH_PARSEERROR) {
+    return 7;
+  }
+  fclose(input);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_read_graph_lgl.out b/examples/simple/igraph_read_graph_lgl.out
new file mode 100644
index 0000000..036899b
--- /dev/null
+++ b/examples/simple/igraph_read_graph_lgl.out
@@ -0,0 +1,12 @@
+0 1
+0 2
+2 3
+2 4
+0 1
+0 2
+2 3
+2 4
+0 1
+0 2
+2 3
+2 4
diff --git a/examples/simple/igraph_reciprocity.c b/examples/simple/igraph_reciprocity.c
new file mode 100644
index 0000000..85299e3
--- /dev/null
+++ b/examples/simple/igraph_reciprocity.c
@@ -0,0 +1,65 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <math.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_real_t res;
+
+  /* Trivial cases */
+
+  igraph_ring(&g, 100, IGRAPH_UNDIRECTED, 0, 0);
+  igraph_reciprocity(&g, &res, 0, IGRAPH_RECIPROCITY_DEFAULT);
+  igraph_destroy(&g);
+
+  if (res != 1) {
+    return 1;
+  }
+
+  /* Small test graph */
+
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 
+	       0,  1,  0,  2,  0,  3,  1,  0,  2,  3,  3,  2, -1);
+  
+  igraph_reciprocity(&g, &res, 0, IGRAPH_RECIPROCITY_RATIO);
+  igraph_destroy(&g);
+
+  if (res != 0.5) {
+    fprintf(stderr, "%f != %f\n", res, 0.5);
+    return 2;
+  }
+
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1,1,2,2,1, -1);
+  igraph_reciprocity(&g, &res, 0, IGRAPH_RECIPROCITY_DEFAULT);
+  igraph_destroy(&g);
+  
+  if (fabs(res - 2.0/3.0) > 1e-15) {
+    fprintf(stderr, "%f != %f\n", res, 2.0/3.0);
+    return 3;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_rewire.c b/examples/simple/igraph_rewire.c
new file mode 100644
index 0000000..388e1c7
--- /dev/null
+++ b/examples/simple/igraph_rewire.c
@@ -0,0 +1,51 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t res;
+  long i, n;
+  
+  igraph_tree(&g, 10, 3, IGRAPH_TREE_OUT);
+  igraph_rewire(&g, 1000, IGRAPH_REWIRING_SIMPLE);
+  
+  n=igraph_vcount(&g);
+  igraph_vector_init(&res, 0);
+  igraph_degree(&g, &res, igraph_vss_all(), IGRAPH_IN, 0);
+  for (i=0; i<n; i++)
+    printf("%ld ", (long)igraph_vector_e(&res, i));
+  printf("\n");
+  
+  igraph_degree(&g, &res, igraph_vss_all(), IGRAPH_OUT, 0);
+  for (i=0; i<n; i++)
+    printf("%ld ", (long)igraph_vector_e(&res, i));
+  printf("\n");
+    
+  igraph_destroy(&g);
+  igraph_vector_destroy(&res);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_rewire.out b/examples/simple/igraph_rewire.out
new file mode 100644
index 0000000..5032a53
--- /dev/null
+++ b/examples/simple/igraph_rewire.out
@@ -0,0 +1,2 @@
+0 1 1 1 1 1 1 1 1 1 
+3 3 3 0 0 0 0 0 0 0 
diff --git a/examples/simple/igraph_ring.c b/examples/simple/igraph_ring.c
new file mode 100644
index 0000000..37b7164
--- /dev/null
+++ b/examples/simple/igraph_ring.c
@@ -0,0 +1,169 @@
+/* -*- mode: C -*-  */
+/*
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge MA, 02139 USA
+
+   Ring test suite
+   Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA
+*/
+
+#include <igraph.h>
+
+typedef struct {
+  int n, m;
+  igraph_bool_t directed, mutual, circular;
+  igraph_real_t *edges;
+} ring_test_t;
+
+#define RING_TEST(id, n, m, di, mu, ci, ...) \
+  igraph_real_t ring_ ## id ## _edges[] = { __VA_ARGS__ };		\
+  ring_test_t ring_ ## id = { n, m, di, mu, ci, ring_ ## id ## _edges }
+
+/*---------------n--m--di-mu-ci--edges-------------------------------------*/
+RING_TEST(uc_6,  6, 6, 0, 0, 1,  0,1, 1,2, 2,3, 3,4, 4,5, 5,0 );
+RING_TEST(uc_0,  0, 0, 0, 0, 1,  -1 );
+RING_TEST(uc_1,  1, 0, 0, 0, 1,  -1 );
+RING_TEST(uc_2,  2, 1, 0, 0, 1,  0,1 );
+
+RING_TEST(u_6,   6, 5, 0, 0, 0,  0,1, 1,2, 2,3, 3,4, 4,5 );
+RING_TEST(u_0,   0, 0, 0, 0, 0,  -1 );
+RING_TEST(u_1,   1, 0, 0, 0, 0,  -1 );
+RING_TEST(u_2,   2, 1, 0, 0, 0,  0,1 );
+
+RING_TEST(umc_6, 6, 6, 0, 1, 1,  0,1, 1,2, 2,3, 3,4, 4,5, 5,0 );
+RING_TEST(umc_0, 0, 0, 0, 1, 1,  -1 );
+RING_TEST(umc_1, 1, 0, 0, 1, 1,  -1 );
+RING_TEST(umc_2, 2, 1, 0, 1, 1,  0,1 );
+
+RING_TEST(um_6,  6, 5, 0, 1, 0,  0,1, 1,2, 2,3, 3,4, 4,5 );
+RING_TEST(um_0,  0, 0, 0, 1, 0,  -1 );
+RING_TEST(um_1,  1, 0, 0, 1, 0,  -1 );
+RING_TEST(um_2,  2, 1, 0, 1, 0,  0,1 );
+
+RING_TEST(dc_6,  6, 6, 1, 0, 1,  0,1, 1,2, 2,3, 3,4, 4,5, 5,0 );
+RING_TEST(dc_0,  0, 0, 1, 0, 1,  -1 );
+RING_TEST(dc_1,  1, 0, 1, 0, 1,  -1 );
+RING_TEST(dc_2,  2, 2, 1, 0, 1,  0,1, 1,0 );
+
+RING_TEST(d_6,   6, 5, 1, 0, 1,  0,1, 1,2, 2,3, 3,4, 4,5 );
+RING_TEST(d_0,   0, 0, 1, 0, 1,  -1 );
+RING_TEST(d_1,   1, 0, 1, 0, 1,  -1 );
+RING_TEST(d_2,   2, 1, 1, 0, 1,  0,1 );
+
+RING_TEST(dmc_6,  6,12, 1, 1, 1, 0,1, 1,2, 2,3, 3,4, 4,5, 5,0,
+                                 1,0, 2,1, 3,2, 4,3, 5,4, 0,5 );
+RING_TEST(dmc_0,  0, 0, 1, 1, 1, -1 );
+RING_TEST(dmc_1,  1, 0, 1, 1, 1, -1 );
+RING_TEST(dmc_2,  2, 2, 1, 1, 1, 0,1, 1,0 );
+
+RING_TEST(dm_6,  6,10, 1, 1, 0,  0,1, 1,2, 2,3, 3,4, 4,5,
+                                 1,0, 2,1, 3,2, 4,3, 5,4 );
+RING_TEST(dm_0,  0, 0, 1, 1, 0,  -1 );
+RING_TEST(dm_1,  1, 0, 1, 1, 0,  -1 );
+RING_TEST(dm_2,  2, 2, 1, 1, 0,  0,1, 1,0 );
+/*---------------n--m--di-mu-ci--edges-------------------------------------*/
+
+ring_test_t *all_checks[] = { /*  1 */ &ring_uc_6,   /*  2 */ &ring_uc_0,
+			      /*  3 */ &ring_uc_1,   /*  4 */ &ring_uc_2,
+			      /*  5 */ &ring_u_6,    /*  6 */ &ring_u_0,
+			      /*  7 */ &ring_u_1,    /*  8 */ &ring_u_2,
+			      /*  9 */ &ring_umc_6,  /* 10 */ &ring_umc_0,
+			      /* 11 */ &ring_umc_1,  /* 12 */ &ring_umc_2,
+			      /* 13 */ &ring_um_6,   /* 14 */ &ring_um_0,
+			      /* 15 */ &ring_um_1,   /* 16 */ &ring_um_2,
+			      /* 17 */ &ring_dc_6,   /* 18 */ &ring_dc_0,
+			      /* 19 */ &ring_dc_1,   /* 20 */ &ring_dc_2,
+			      /* 21 */ &ring_dmc_6,  /* 22 */ &ring_dmc_0,
+			      /* 23 */ &ring_dmc_1,  /* 24 */ &ring_dmc_2,
+			      /* 25 */ &ring_dm_6,   /* 26 */ &ring_dm_0,
+			      /* 27 */ &ring_dm_1,   /* 28 */ &ring_dm_2,
+			      0 };
+
+int check_ring_properties(const igraph_t *ring, igraph_bool_t directed,
+			  igraph_bool_t mutual, igraph_bool_t circular) {
+
+  igraph_bool_t res;
+
+  /* Connected */
+  igraph_is_connected(ring, &res, IGRAPH_WEAK); 
+  if (!res) {
+    printf("Not connected\n");
+    return 1;
+  }
+
+  /* Simple */
+  igraph_is_simple(ring, &res); 
+  if (!res) {
+    printf("Not simple\n");
+    return 2;
+  }
+  
+  /* Girth, for big enough circular graphs */
+  if (circular && igraph_vcount(ring) > 2) { 
+    igraph_integer_t girth;
+    igraph_girth(ring, &girth, NULL);
+    if (girth != igraph_vcount(ring)) { 
+      printf("Wrong girth\n");
+      return 3; 
+    }
+  }
+   
+  return 0;
+}
+
+int check_ring(const ring_test_t *test) {
+  igraph_t graph, othergraph;
+  igraph_vector_t otheredges;
+  igraph_bool_t iso;
+  int ret;
+
+  /* Create ring */
+  igraph_ring(&graph, test->n, test->directed, test->mutual, test->circular);
+
+  /* Check its properties */
+  if ((ret=check_ring_properties(&graph, test->directed, test->mutual, 
+				 test->circular))) { return ret;}
+
+  /* Check that it is isomorphic to the stored graph */
+  igraph_vector_view(&otheredges, test->edges, test->m * 2);
+  igraph_create(&othergraph, &otheredges, test->n, test->directed);
+  igraph_isomorphic(&graph, &othergraph, &iso);
+  if (!iso) { return 50; }
+
+  /* Clean up */
+  igraph_destroy(&graph);
+  igraph_destroy(&othergraph);
+
+  return 0;
+}
+
+int main() {
+  int i, ret;
+
+  i=0;
+  while (all_checks[i]) {
+    if ((ret=check_ring(all_checks[i]))) { 
+      printf("Check no #%d failed.\n", (int) (i+1));
+      return ret;
+    }
+    i++;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_rng_get_exp.c b/examples/simple/igraph_rng_get_exp.c
new file mode 100644
index 0000000..aeb872a
--- /dev/null
+++ b/examples/simple/igraph_rng_get_exp.c
@@ -0,0 +1,36 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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.h>
+
+int main() {
+
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  for (i=0; i<1000; i++) {
+    printf("%g\n", igraph_rng_get_exp(igraph_rng_default(), 2.5));
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_rng_get_exp.out b/examples/simple/igraph_rng_get_exp.out
new file mode 100644
index 0000000..4252984
--- /dev/null
+++ b/examples/simple/igraph_rng_get_exp.out
@@ -0,0 +1,1000 @@
+0.476523
+0.237234
+0.0508589
+0.223753
+0.0789268
+0.0774801
+0.653777
+0.304978
+1.23637
+0.411193
+0.080892
+0.611692
+0.166458
+0.120711
+1.51326
+1.30922
+0.265954
+0.000215919
+0.736358
+0.0508505
+0.0893225
+0.0198051
+1.94721
+0.343225
+0.0198197
+0.0894823
+0.517036
+0.600898
+1.30636
+0.34469
+0.0645379
+1.01166
+0.228141
+0.0947088
+0.793474
+0.489198
+0.0113875
+0.0128788
+0.168447
+0.700195
+0.280937
+0.261234
+0.0506306
+0.246718
+0.493925
+0.364641
+1.39503
+1.05688
+0.621344
+0.311095
+0.0879973
+0.286793
+0.071749
+0.737673
+0.130018
+0.204289
+0.375997
+0.334913
+0.0373682
+0.0541603
+0.746052
+1.10985
+0.124698
+0.109559
+0.165773
+0.0245353
+0.0563552
+0.781663
+0.0166674
+1.28794
+0.0902007
+0.499143
+0.197856
+0.311417
+0.0317537
+0.26299
+0.0694009
+0.448064
+0.0778916
+0.0341569
+0.318858
+0.605475
+0.351296
+0.241758
+0.683372
+0.908901
+1.38659
+0.109484
+0.790408
+0.34684
+2.10628
+1.71868
+0.165486
+0.169074
+0.183206
+0.23214
+0.217016
+0.084768
+0.905662
+0.0993878
+1.07108
+0.124614
+0.406696
+1.0424
+0.83855
+0.470568
+0.374831
+0.135073
+0.397552
+0.132738
+0.183685
+0.0730382
+0.110046
+0.316814
+0.130926
+0.489942
+1.02953
+0.200106
+0.0490218
+0.625515
+0.288469
+0.284307
+0.307173
+1.11133
+0.131801
+0.380228
+0.0506205
+0.00685655
+0.156413
+0.0386309
+0.0835339
+0.533872
+0.0318729
+0.204441
+0.804314
+0.575861
+0.0790924
+0.340861
+0.155828
+0.670426
+0.173108
+0.246496
+0.350273
+0.106723
+1.10694
+0.126578
+0.606246
+0.149537
+0.396211
+0.245952
+0.919946
+0.0305129
+0.672937
+2.79888
+0.254412
+0.441369
+0.00192754
+0.681416
+0.00859784
+0.0272715
+0.545116
+0.310493
+0.308319
+0.417443
+0.601178
+0.698357
+0.162415
+0.523397
+0.459066
+0.847087
+0.0684486
+0.280111
+0.157043
+0.318317
+0.0102272
+0.00214322
+0.534918
+1.36796
+1.13208
+0.323093
+0.429373
+0.0664207
+0.144564
+0.618181
+0.0247477
+0.401411
+0.576935
+0.209296
+0.468706
+0.621659
+0.242512
+0.465712
+0.452571
+0.106824
+0.515378
+0.0286197
+0.253146
+1.00963
+0.238676
+0.268242
+0.636814
+0.390507
+0.00655903
+0.751377
+0.15665
+1.23096
+0.090375
+0.142051
+0.559117
+0.00967444
+0.247601
+0.651188
+1.04731
+0.71249
+0.11023
+0.496035
+0.0142011
+0.0381289
+0.140552
+0.422965
+0.188173
+0.889744
+0.0331584
+0.0715166
+0.603026
+0.253778
+0.143242
+0.294586
+0.580331
+0.154792
+0.0523207
+0.419707
+0.323453
+0.435994
+0.160286
+0.180765
+0.237424
+0.112153
+0.178009
+0.970272
+0.044813
+0.168138
+0.0645493
+1.73444
+0.472911
+1.08119
+0.183962
+2.05912
+0.331532
+0.669104
+0.365841
+0.038987
+0.401588
+0.00501155
+0.644738
+0.72675
+0.197193
+0.463609
+0.119706
+0.195336
+0.182329
+0.370156
+0.0546469
+0.0340322
+1.0313
+0.00705126
+0.465604
+0.109066
+0.301583
+0.277998
+0.718065
+0.506215
+0.452248
+0.374321
+0.00210968
+0.116083
+0.0615231
+0.135139
+0.331392
+0.177962
+0.284001
+0.116378
+1.26716
+0.721272
+0.0775106
+0.10263
+0.198175
+1.75526
+0.430518
+0.057834
+0.236504
+0.913993
+0.348377
+0.366374
+0.493415
+0.765433
+0.074437
+0.324252
+0.508765
+0.19298
+0.0195235
+1.05371
+0.823058
+0.0920058
+0.136915
+0.0388395
+0.0146637
+0.349724
+0.0894301
+0.0378795
+0.161987
+0.167129
+0.452445
+0.042256
+0.347006
+0.351675
+0.247489
+0.548908
+0.248091
+0.28719
+0.169548
+0.953979
+0.00907392
+2.07174
+0.00121304
+0.102316
+0.238636
+0.776194
+0.119971
+0.885798
+0.161574
+0.512113
+0.236634
+1.35887
+0.0937122
+1.49043
+1.03326
+0.437592
+1.1691
+0.402303
+0.320246
+0.0794461
+0.00845647
+1.18709
+1.20612
+0.25808
+0.362484
+0.453564
+0.0296659
+0.561111
+0.399901
+0.0177946
+0.262295
+0.215995
+0.311728
+0.72722
+0.300922
+1.37056
+0.776534
+0.0250837
+0.535425
+0.0325081
+0.15961
+0.109944
+0.597248
+0.180873
+0.579303
+0.143149
+0.393989
+1.2347
+0.236149
+0.515372
+0.31059
+0.398968
+0.933897
+0.278636
+1.63527
+0.744385
+0.0224227
+0.468152
+0.531584
+1.15708
+0.655116
+0.343742
+0.0393813
+1.03257
+0.171677
+0.739689
+0.128158
+0.0776142
+0.143259
+0.125689
+0.0434832
+0.446864
+0.548619
+1.3198
+0.598504
+0.206277
+0.835767
+0.844531
+1.03438
+1.23036
+0.37552
+0.195095
+0.715575
+0.282017
+0.210692
+0.373275
+0.708764
+0.397548
+0.514866
+1.32419
+0.0926801
+0.176085
+1.28893
+0.294689
+0.476639
+1.80305
+0.000831908
+0.149547
+0.147171
+0.675908
+0.0926809
+0.883417
+0.178116
+1.54871
+0.109123
+0.159555
+0.141735
+0.498331
+0.0586936
+0.114631
+0.565719
+0.428536
+0.256512
+0.10705
+0.256341
+0.18063
+0.815908
+0.781049
+0.315597
+0.875689
+0.582459
+1.45277
+1.20776
+1.03621
+0.0946031
+0.146405
+0.415746
+0.887384
+0.124578
+0.38762
+0.493893
+0.2759
+0.145291
+1.58206
+0.422258
+0.251575
+0.29437
+0.328227
+0.310021
+0.434597
+0.103154
+0.0108648
+0.188057
+0.545973
+0.242785
+0.0491967
+0.434886
+0.245468
+0.0607397
+0.0354031
+0.472488
+0.277285
+0.22113
+0.0644352
+0.422545
+0.155783
+0.0661531
+0.143876
+0.200697
+0.191927
+0.203634
+0.58311
+0.140086
+0.365995
+0.353475
+0.0277217
+1.11204
+0.02531
+0.445107
+0.388161
+0.18764
+0.133783
+0.30035
+1.01868
+0.346396
+0.0819527
+0.403122
+0.0429624
+0.138015
+0.76312
+0.233263
+0.225037
+0.231695
+0.857064
+0.293218
+0.0396231
+1.23145
+0.0972943
+0.164665
+0.871422
+0.150424
+0.209209
+0.269571
+0.0945744
+0.0280372
+0.97006
+0.33897
+0.89746
+0.511901
+0.257488
+0.0406475
+0.952409
+0.0106609
+0.974738
+0.71569
+0.476092
+0.102764
+0.25024
+0.806184
+0.0971011
+0.479274
+0.166545
+0.966181
+0.382059
+0.0467234
+0.164067
+0.34622
+0.405663
+0.952232
+0.28315
+1.84486
+0.525582
+0.292869
+0.192779
+0.864362
+0.258232
+0.119368
+0.195369
+0.196836
+0.144832
+0.066695
+0.665483
+0.477052
+0.300241
+0.0619939
+0.499651
+1.88586
+0.0119665
+0.393557
+0.0120333
+0.254833
+0.904075
+0.282043
+0.0430834
+0.156329
+0.0209149
+0.103519
+0.636169
+0.451255
+0.15754
+0.0674515
+0.491982
+0.0126004
+0.0778995
+0.0160433
+0.508494
+0.306858
+0.414315
+0.321069
+0.697493
+0.756505
+0.117479
+0.375229
+0.628251
+0.929278
+0.453811
+0.0720734
+0.158529
+1.12268
+0.0288771
+0.32488
+0.372503
+0.53519
+0.251036
+0.0822255
+0.147785
+0.310791
+0.674892
+0.58071
+0.0211272
+0.115517
+0.180576
+0.0649301
+0.0907322
+0.0229427
+0.240124
+0.0412703
+1.28783
+0.681987
+1.66129
+0.535267
+0.4796
+0.222082
+0.248443
+0.550438
+0.635852
+0.480041
+0.0753046
+0.199663
+0.486684
+0.506042
+0.157783
+0.270663
+0.838252
+0.287468
+0.582845
+0.31471
+1.67918
+0.191784
+0.027477
+0.153998
+0.21519
+0.180897
+0.209907
+0.48182
+0.611368
+0.567828
+0.279567
+0.0761718
+0.817646
+0.740753
+0.205599
+0.0945026
+1.30931
+0.450319
+0.307135
+0.837928
+0.409293
+0.0161308
+0.369702
+0.153021
+0.024512
+0.233454
+0.522831
+0.0719647
+0.583366
+0.285239
+0.20411
+0.227735
+0.0962476
+0.111489
+0.163264
+0.244036
+0.592328
+0.093811
+1.76076
+0.0864703
+0.0719341
+0.109315
+0.504849
+0.0438525
+0.30249
+0.181118
+0.434468
+0.037957
+0.0111916
+0.494534
+0.511727
+0.353994
+0.0976694
+0.0188818
+0.193427
+0.237177
+0.625153
+0.510736
+0.295623
+0.289974
+0.0966445
+0.335242
+0.106721
+0.0637199
+0.575552
+0.0298107
+0.566933
+0.312761
+0.640606
+0.51774
+0.598765
+0.158134
+0.1127
+0.730733
+0.736534
+0.157201
+0.430327
+0.535917
+0.13141
+0.0121888
+0.134046
+0.0477772
+0.565849
+0.69511
+0.429391
+0.323003
+0.43345
+0.720951
+1.11614
+0.999473
+0.0389722
+0.959532
+0.446845
+0.814786
+0.0356966
+0.00273382
+0.405418
+0.152316
+0.391791
+1.21223
+1.02244
+0.239528
+0.45135
+0.955034
+0.00932561
+0.0435235
+0.480916
+1.10975
+0.244961
+0.972685
+0.198608
+0.0778225
+0.744985
+0.058044
+0.0654654
+0.0946038
+0.207964
+0.467521
+0.0250126
+0.477028
+1.11921
+0.17068
+0.149732
+0.141867
+0.199693
+0.0256908
+1.41601
+0.443894
+0.0260938
+0.512721
+0.583594
+0.480914
+0.737826
+1.50012
+0.0511721
+0.392586
+0.272568
+0.831151
+1.00268
+0.401255
+0.0282685
+0.896438
+0.425942
+0.074874
+0.375715
+0.231337
+0.119058
+0.301358
+0.189458
+0.0694729
+0.0461938
+0.196352
+0.0692283
+0.312632
+0.483295
+0.3313
+0.417174
+0.458191
+0.16845
+0.0566226
+0.653249
+0.405816
+0.0846199
+0.00208897
+1.08318
+0.596899
+0.599068
+0.751532
+0.994257
+0.333411
+0.244692
+0.709313
+1.34257
+0.945273
+1.36997
+0.0196091
+1.4533
+0.533894
+0.157569
+0.0310638
+0.513828
+0.0607987
+0.00146947
+0.253658
+0.0473801
+0.178317
+0.134915
+0.256689
+0.154367
+0.0280294
+0.0572902
+0.354886
+0.215594
+0.810766
+0.753058
+0.0897429
+0.79294
+0.0060883
+0.188998
+0.586357
+0.088496
+0.214224
+0.339068
+0.990434
+0.0649906
+0.00488317
+0.648478
+0.0889009
+0.0260715
+0.0751065
+1.37238
+0.468028
+0.415826
+0.314527
+0.837376
+0.0391376
+0.0559316
+0.2479
+0.994133
+0.284684
+0.598757
+0.145202
+2.37326
+0.208182
+0.962966
+0.391445
+0.235432
+0.435448
+1.06765
+0.264496
+0.19678
+0.0344625
+0.202639
+0.0502485
+0.484025
+0.857353
+0.200069
+0.0595785
+1.32465
+0.273463
+0.225212
+0.601789
+0.262353
+0.236214
+0.200402
+0.799725
+0.23963
+0.678217
+0.260106
+0.680168
+0.751014
+0.25166
+0.730233
+0.0184523
+0.0876683
+0.108809
+0.146386
+0.25328
+0.399013
+0.48037
+0.128282
+0.359463
+0.0318248
+0.198088
+0.416643
+0.653045
+0.50363
+0.491485
+0.025486
+0.0348423
+0.858139
+0.0634993
+0.0342794
+0.951422
+0.409764
+0.102166
+0.184439
+0.413108
+0.154974
+0.600188
+0.688056
+0.23522
+0.137361
+0.0267689
+0.193169
+0.158911
+0.0420532
+0.594201
+1.13825
+0.80906
+0.0559117
+0.171251
+0.209967
+0.372104
+1.09044
+0.257006
+0.0291851
+0.936808
+0.312606
+0.512919
+0.00183068
+0.237836
+0.0318885
+0.634254
+0.340821
+0.217506
+0.176029
+1.88835
+0.112918
+0.0787542
+0.155159
+0.0524067
+0.0341796
+0.172943
+0.280137
+0.0792235
+0.430372
+0.261439
+0.73563
+0.0949679
+0.0667134
+0.665657
+0.35709
+0.0919602
+0.645242
+0.0385712
+0.00471095
+1.07686
+0.0891634
+0.286884
+1.44992
+0.180876
+0.164404
+1.08594
+0.0521065
+0.193153
+0.00638322
+0.121094
+0.642643
+0.216997
+0.0610307
+0.476355
+0.085372
+0.872874
+0.298697
+1.09896
+0.233019
+0.0340504
+0.897184
+0.684183
+0.271118
+0.750745
+0.923867
+0.37557
+0.0150704
+0.718454
+0.515663
+0.484148
+1.20197
+0.812373
+0.242283
+0.230232
+2.01513
+0.0829772
+0.410858
+0.942172
+0.0299165
+0.255038
+0.431412
+0.373455
+0.190001
diff --git a/examples/simple/igraph_roulette_wheel_imitation.c b/examples/simple/igraph_roulette_wheel_imitation.c
new file mode 100644
index 0000000..02b821c
--- /dev/null
+++ b/examples/simple/igraph_roulette_wheel_imitation.c
@@ -0,0 +1,280 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for stochastic imitation via roulette wheel selection.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+#include <time.h>
+
+#define R_INTEGER(a,b) (igraph_rng_get_integer(igraph_rng_default(), (a), (b)))
+
+/* test parameters structure */
+typedef struct {
+  igraph_t *graph;
+  igraph_integer_t vertex;
+  igraph_bool_t islocal;
+  igraph_vector_t *quantities;
+  igraph_vector_t *strategies;
+  igraph_vector_t *known_strats;
+  igraph_neimode_t mode;
+  int retval;
+} strategy_test_t;
+
+/* Error tests. That is, we expect error codes to be returned from such tests.
+ */
+int error_tests() {
+  igraph_t g, gzero, h;
+  igraph_vector_t quant, quantzero, strat, stratzero;
+  int i, n, nvert, ret;
+  strategy_test_t *test;
+
+  /* nonempty graph */
+  igraph_small(&g, /*nvert=*/ 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  igraph_empty(&h, 0, 0);         /* empty graph */
+  igraph_vector_init(&quant, 1);  /* quantities vector */
+  igraph_vector_init(&strat, 2);  /* strategies vector */
+  igraph_small(&gzero, /*nvert=*/ 0, IGRAPH_UNDIRECTED,
+               0,3, 0,4, 1,2, 1,4, 1,5, 2,3, 2,4, 3,4, -1);
+  nvert = igraph_vcount(&gzero);
+  igraph_vector_init_real(&stratzero, nvert, 1.0, 0.0, 1.0, 2.0, 0.0, 3.0);
+  igraph_vector_init(&quantzero, nvert);  /* vector of zeros */
+
+  /* test parameters */
+  /*graph--vert--islocal--quantities--strategies--known_strats--mode--retval*/
+  /* null pointer for graph */
+  strategy_test_t null_graph = {NULL, 0, 1, NULL, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for quantities vector */
+  strategy_test_t null_quant = {&g, 0, 1, NULL, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for strategies vector */
+  strategy_test_t null_strat = {&g, 0, 1, &quant, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* empty graph */
+  strategy_test_t empty_graph = {&h, 0, 1, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of quantities vector different from number of vertices */
+  strategy_test_t qdiff_length = {&g, 0, 1, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of strategies vector different from number of vertices */
+  strategy_test_t sdiff_length = {&g, 0, 1, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* quantities vector contains all zeros */
+  strategy_test_t zero_quant = {&gzero, 4, 1, &quantzero, &stratzero, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  strategy_test_t *all_checks[] = {/* 1 */ &null_graph,
+                                   /* 2 */ &null_quant,
+                                   /* 3 */ &null_strat,
+                                   /* 4 */ &empty_graph,
+                                   /* 5 */ &qdiff_length,
+                                   /* 6 */ &sdiff_length,
+                                   /* 7 */ &zero_quant};
+
+  /* Run the error tests. We expect error to be raised for each test. */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  n = 7;
+  i = 0;
+  while (i < n) {
+    test = all_checks[i];
+    ret = igraph_roulette_wheel_imitation(test->graph, test->vertex,
+                                          test->islocal, test->quantities,
+                                          test->strategies, test->mode);
+    if (ret != test->retval) {
+      printf("Error test no. %d failed.\n", (int)(i + 1));
+      return IGRAPH_FAILURE;
+    }
+    i++;
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_destroy(&gzero);
+  igraph_destroy(&h);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&quantzero);
+  igraph_vector_destroy(&strat);
+  igraph_vector_destroy(&stratzero);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* A game on a graph with 5 vertices and 7 edges. Use roulette wheel selection
+ * to update strategies. This example also illustrates how a choice of
+ * perspective (whether local or global) could affect the range of
+ * possible strategies a vertex could adopt.
+ */
+int roulette_test() {
+  igraph_t g;
+  igraph_bool_t success;
+  igraph_vector_t *known, quant, strat, stratcopy;
+  igraph_vector_t known0, known1, known2, known3, known4, known5;
+  int i, k, n, nvert, ret;;
+  strategy_test_t *test;
+
+  /* the game network */
+  igraph_small(&g, /*nvert=*/ 0, IGRAPH_UNDIRECTED,
+               0,3, 0,4, 1,2, 1,4, 1,5, 2,3, 2,4, 3,4, -1);
+  nvert = igraph_vcount(&g);
+  /* strategies vector; the strategy space is {0, 1, 2, 3} */
+  /* V[i] is strategy of vertex i */
+  igraph_vector_init_real(&strat, nvert, 1.0, 0.0, 1.0, 2.0, 0.0, 3.0);
+  /* quantities vector; V[i] is quantity of vertex i */
+  igraph_vector_init_real(&quant, nvert, 0.56, 0.13, 0.26, 0.73, 0.67, 0.82);
+  /* possible strategies each vertex can adopt */
+  igraph_vector_init_real(&known0, /*n=*/ 3, 0.0, 1.0, 2.0);       /* local */
+  igraph_vector_init_real(&known1, /*n=*/ 3, 0.0, 1.0, 3.0);       /* local */
+  igraph_vector_init_real(&known2, /*n=*/ 3, 0.0, 1.0, 2.0);       /* local */
+  igraph_vector_init_real(&known3, /*n=*/ 3, 0.0, 1.0, 2.0);       /* local */
+  igraph_vector_init_real(&known4, /*n=*/ 3, 0.0, 1.0, 2.0);       /* local */
+  igraph_vector_init_real(&known5, /*n=*/ 4, 0.0, 1.0, 2.0, 3.0);  /* global */
+
+  /* test parameters */
+  /*graph--vert--islocal--quantities--strategies--known_strats--mode-retval*/
+  strategy_test_t game0 = {&g, 0, 1, &quant, NULL, &known0, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t game1 = {&g, 1, 1, &quant, NULL, &known1, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t game2 = {&g, 2, 1, &quant, NULL, &known2, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t game3 = {&g, 3, 1, &quant, NULL, &known3, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t game4 = {&g, 4, 1, &quant, NULL, &known4, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t game5 = {&g, 5, 0, &quant, NULL, &known5, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t *all_checks[] = {/* 1 */ &game0,
+                                   /* 2 */ &game1,
+                                   /* 3 */ &game2,
+                                   /* 4 */ &game3,
+                                   /* 5 */ &game4,
+                                   /* 6 */ &game5};
+
+  /* play game */
+  n = 6;
+  i = 0;
+  while (i < n) {
+    test = all_checks[i];
+    igraph_vector_copy(&stratcopy, &strat);
+    ret = igraph_roulette_wheel_imitation(test->graph, test->vertex,
+                                          test->islocal, test->quantities,
+                                          &stratcopy, test->mode);
+    if (ret != test->retval) {
+      printf("Test no. %d failed.\n", i + 1);
+      return IGRAPH_FAILURE;
+    }
+    /* If the revised strategy s matches one of the candidate strategies, */
+    /* then success. If s doesn't match any of the possible strategies, then */
+    /* failure. Default to failure. */
+    success = 0;
+    known = test->known_strats;
+    for (k = 0; k < igraph_vector_size(known); k++) {
+      if (VECTOR(*known)[k] == VECTOR(stratcopy)[test->vertex]) {
+        success = 1;
+        break;
+      }
+    }
+    if (!success) {
+      printf("Roulette wheel imitation failed for vertex %d.\n",
+             (int)test->vertex);
+      return IGRAPH_FAILURE;
+    }
+    igraph_vector_destroy(&stratcopy);
+    i++;
+  }
+  /* game finished; pack up */
+  igraph_destroy(&g);
+  igraph_vector_destroy(&known0);
+  igraph_vector_destroy(&known1);
+  igraph_vector_destroy(&known2);
+  igraph_vector_destroy(&known3);
+  igraph_vector_destroy(&known4);
+  igraph_vector_destroy(&known5);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* It is possible for a vertex to retain its current strategy. This can
+ * happen both in the local and global perspectives.
+ */
+int retain_strategy_test() {
+  igraph_t g;
+  igraph_integer_t max, min, v;
+  igraph_vector_t quant, strat, stratcp;
+  int i, ntry, nvert;
+
+  /* the game network */
+  igraph_small(&g, /*nvert=*/ 0, IGRAPH_UNDIRECTED,
+               0,3, 0,4, 1,2, 1,4, 1,5, 2,3, 2,4, 3,4, -1);
+  nvert = igraph_vcount(&g);
+  /* strategies vector; the strategy space is {0, 1, 2, 3} */
+  /* V[i] is strategy of vertex i */
+  igraph_vector_init_real(&strat, nvert, 1.0, 0.0, 1.0, 2.0, 0.0, 3.0);
+  /* quantities vector; V[i] is quantity of vertex i */
+  igraph_vector_init_real(&quant, nvert, 0.56, 0.13, 0.26, 0.73, 0.67, 0.82);
+
+  /* random vertex */
+  min = 0;
+  max = 5;
+  igraph_rng_seed(igraph_rng_default(), time(0));
+  v = R_INTEGER(min, max);  /* min <= v <= max */
+  /* Ensure that it is possible for v to retain its current strategy. We */
+  /* will try to do this at most ntry times. As there are at most 6 vertices */
+  /* to choose from, it shouldn't take long before we encounter a strategy */
+  /* revision round where v retains its current strategy. */
+  /* With local perspective. */
+  i = 0;
+  ntry = 100;
+  igraph_vector_init(&stratcp, 0);
+  do {
+    i++;
+    if (i > ntry)
+      return IGRAPH_FAILURE;  /* ideally this should never happen */
+    igraph_vector_destroy(&stratcp);
+    igraph_vector_copy(&stratcp, &strat);
+    igraph_roulette_wheel_imitation(&g, v, /*is local?*/ 1, &quant, &stratcp,
+                                    IGRAPH_ALL);
+  }
+  while (VECTOR(stratcp)[v] != VECTOR(strat)[v]);
+  /* If we get to this point, we know that there was an update round */
+  /* i <= ntry as a result of which v retains its current strategy. */
+  /* Now try again, but this time with the global perspective. */
+  i = 0;
+  do {
+    i++;
+    if (i > ntry)
+      return IGRAPH_FAILURE;  /* ideally this should never happen */
+    igraph_vector_destroy(&stratcp);
+    igraph_vector_copy(&stratcp, &strat);
+    igraph_roulette_wheel_imitation(&g, v, /*is local?*/ 0, &quant, &stratcp,
+                                    IGRAPH_ALL);
+  }
+  while (VECTOR(stratcp)[v] != VECTOR(strat)[v]);
+  /* nothing further to do, but housekeeping */
+  igraph_destroy(&g);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+  igraph_vector_destroy(&stratcp);
+
+  return IGRAPH_SUCCESS;
+}
+
+int main() {
+  int ret;
+
+  ret = error_tests();
+  if (ret)
+    return IGRAPH_FAILURE;
+  ret = roulette_test();
+  if (ret)
+    return IGRAPH_FAILURE;
+  ret = retain_strategy_test();
+  if (ret)
+    return IGRAPH_FAILURE;
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/examples/simple/igraph_scg_grouping.c b/examples/simple/igraph_scg_grouping.c
new file mode 100644
index 0000000..432fe42
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping.c
@@ -0,0 +1,83 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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.h>
+
+#define SIZE (1000)
+
+int main() {
+
+  igraph_matrix_t M, M2;
+  igraph_vector_t lambda;
+  igraph_matrix_t V;
+  igraph_vector_t groups;
+  igraph_vector_t ivec;
+  int i, j;
+  int n;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  /* Symmetric matrix, exponentially distributed elements */
+
+  igraph_matrix_init(&M, SIZE, SIZE);
+  n=igraph_matrix_nrow(&M);
+  for (i=0; i<n; i++) {
+    for (j=0; j<n; j++) {
+      MATRIX(M, i, j) = igraph_rng_get_exp(igraph_rng_default(), 1);
+    }
+  }
+  igraph_matrix_init(&M2, n, n);
+  igraph_matrix_update(&M2, &M);
+  igraph_matrix_transpose(&M2);
+  igraph_matrix_add(&M, &M2);
+  igraph_matrix_scale(&M, 0.5);
+  igraph_matrix_destroy(&M2);
+
+  /* Get first (most positive) two eigenvectors */
+
+  igraph_vector_init(&lambda, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_lapack_dsyevr(&M, IGRAPH_LAPACK_DSYEV_SELECT, /*vl=*/ 0, /*vu=*/ 0, 
+		       /*vestimate=*/ 0, /*il=*/ n-1, /*iu=*/ n, 
+		       /*abstol=*/ 0.0, /*values=*/ &lambda, /*vectors=*/ &V, 
+		       /*support=*/ 0);
+  
+  /* Grouping */
+  
+  igraph_vector_init(&groups, 0);
+  igraph_vector_init(&ivec, 2);
+  VECTOR(ivec)[0] = 2; VECTOR(ivec)[1] = 3;  
+  igraph_scg_grouping(&V, &groups, /*invervals=*/ 0, 
+		      /*intervals_vector=*/ &ivec, IGRAPH_SCG_SYMMETRIC, 
+		      IGRAPH_SCG_OPTIMUM, /*p=*/ 0, /*maxiter=*/ 100);
+  
+  igraph_vector_print(&groups);
+
+  igraph_vector_destroy(&ivec);
+  igraph_vector_destroy(&groups);
+  igraph_vector_destroy(&lambda);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_destroy(&M);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_scg_grouping.out b/examples/simple/igraph_scg_grouping.out
new file mode 100644
index 0000000..fde1be9
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping.out
@@ -0,0 +1 @@
+0 1 3 2 4 4 3 5 3 3 5 0 3 0 5 1 1 0 0 4 0 4 4 1 4 4 5 0 4 0 1 1 1 0 4 5 5 3 1 5 3 5 1 4 1 4 5 1 3 0 4 4 4 5 5 4 5 1 0 1 1 4 5 2 2 2 0 1 1 4 4 5 2 4 4 3 1 0 4 2 4 1 2 1 3 0 2 1 4 4 3 2 4 5 1 5 3 4 0 5 4 1 4 0 3 4 0 0 2 4 2 5 1 0 1 3 4 2 1 2 3 5 2 2 5 2 4 4 4 0 1 4 2 3 0 4 4 1 5 4 5 2 3 4 4 4 4 4 4 4 1 3 2 0 4 1 0 4 1 0 4 1 0 5 5 1 4 3 2 4 5 2 2 1 4 0 2 3 4 1 4 0 0 1 2 5 2 1 4 0 0 1 1 5 5 2 2 2 4 2 1 0 1 5 2 2 0 1 3 4 1 5 1 2 5 2 4 2 0 1 0 1 5 4 0 4 0 4 1 4 1 5 1 5 2 4 5 0 4 0 3 4 1 4 1 5  [...]
diff --git a/examples/simple/igraph_scg_grouping2.c b/examples/simple/igraph_scg_grouping2.c
new file mode 100644
index 0000000..12efdc2
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping2.c
@@ -0,0 +1,79 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_matrix_t adj, V;
+  igraph_vector_t groups;
+  igraph_eigen_which_t which;
+
+  igraph_matrix_init(&adj, 0, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_vector_init(&groups, 0);
+    
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+
+  igraph_get_adjacency(&g, &adj, IGRAPH_GET_ADJACENCY_BOTH, /*eids=*/ 0);
+
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=1;
+  igraph_eigen_matrix_symmetric(&adj, /*sparsemat=*/ 0, /*fun=*/ 0, 
+				igraph_vcount(&g), /*extra=*/ 0, 
+				/*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+				&which, /*options=*/ 0, /*storage=*/ 0,
+				/*values=*/ 0, &V);
+  
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_OPTIMUM, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_INTERV_KM, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_INTERV, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  igraph_scg_grouping(&V, &groups, /*(ignored) intervals=*/ 0, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_EXACT, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+  
+
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_destroy(&adj);
+  igraph_destroy(&g);
+  
+  return 0;
+}
+    
diff --git a/examples/simple/igraph_scg_grouping2.out b/examples/simple/igraph_scg_grouping2.out
new file mode 100644
index 0000000..54b0ed2
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping2.out
@@ -0,0 +1,4 @@
+0 1 1 2 2 2 2 2 2 2
+0 0 0 2 2 2 2 2 2 2
+0 0 0 2 2 2 2 2 2 2
+0 1 1 2 3 3 3 3 3 3
diff --git a/examples/simple/igraph_scg_grouping3.c b/examples/simple/igraph_scg_grouping3.c
new file mode 100644
index 0000000..6388fe4
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping3.c
@@ -0,0 +1,120 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  const int nodes=10;
+  igraph_t g;
+  igraph_matrix_t V, V3;
+  igraph_matrix_complex_t V2;
+  igraph_sparsemat_t stochastic, stochasticT;
+  igraph_vector_t groups;
+  igraph_eigen_which_t which;
+  igraph_vector_t p, selcol;
+
+  igraph_tree(&g, nodes, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+
+  igraph_sparsemat_init(&stochastic, nodes, nodes, igraph_ecount(&g)*2);
+  igraph_matrix_complex_init(&V2, 0, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_matrix_init(&V3, 0, 0);
+  igraph_vector_init(&groups, 0);
+  igraph_vector_init(&p, 0);
+  igraph_vector_init(&selcol, 1);  
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_get_stochastic_sparsemat(&g, &stochastic, /*column-wise=*/ 0);
+  igraph_sparsemat_transpose(&stochastic, &stochasticT, /*values=*/ 1);
+
+  which.pos=IGRAPH_EIGEN_LR;
+  which.howmany=1;
+
+  igraph_eigen_matrix(/*matrix=*/ 0, &stochasticT, /*fun=*/ 0, nodes,
+		      /*extra=*/ 0, /*1algorithm=*/ IGRAPH_EIGEN_LAPACK,
+		      &which, /*options=*/ 0, /*storage=*/ 0, 
+		      /*values=*/ 0, &V2);
+  igraph_matrix_complex_real(&V2, &V);
+
+  /* `p' is always the eigenvector corresponding to the 1-eigenvalue */
+  igraph_matrix_get_col(&V, &p, 0);
+  igraph_vector_print(&p);
+
+  which.howmany=3;
+  igraph_eigen_matrix(/*matrix=*/ 0, &stochastic, /*fun=*/ 0, nodes,
+		      /*extra=*/ 0, /*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+		      &which, /*options=*/ 0, /*storage=*/ 0, 
+		      /*values=*/ 0, &V2);
+  igraph_matrix_complex_real(&V2, &V3);
+  VECTOR(selcol)[0]=2;
+  igraph_matrix_select_cols(&V3, &V, &selcol);
+
+  /* ------------ */
+  
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_OPTIMUM, &p, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_INTERV_KM, &p, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_INTERV, &p, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */
+
+  igraph_scg_grouping(&V, &groups, /*(ignored) intervals=*/ 0, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_EXACT, &p, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */  
+
+  igraph_vector_destroy(&p);
+  igraph_vector_destroy(&selcol);
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_destroy(&V3);
+  igraph_matrix_complex_destroy(&V2);
+  igraph_sparsemat_destroy(&stochasticT);
+  igraph_sparsemat_destroy(&stochastic);
+  igraph_destroy(&g);
+  
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
+    
diff --git a/examples/simple/igraph_scg_grouping3.out b/examples/simple/igraph_scg_grouping3.out
new file mode 100644
index 0000000..c6fc100
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping3.out
@@ -0,0 +1,5 @@
+0.433013 0.57735 0.57735 0.144338 0.144338 0.144338 0.144338 0.144338 0.144338 0.144338
+0 1 1 0 2 2 2 2 2 2
+1 2 2 0 2 2 2 2 2 2
+1 2 2 0 2 2 2 2 2 2
+1 2 2 0 3 3 3 3 3 3
diff --git a/examples/simple/igraph_scg_grouping4.c b/examples/simple/igraph_scg_grouping4.c
new file mode 100644
index 0000000..fc81365
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping4.c
@@ -0,0 +1,99 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  const int nodes=10;
+  igraph_t g;
+  igraph_matrix_t V;
+  igraph_matrix_complex_t V2;
+  igraph_sparsemat_t laplacian;
+  igraph_vector_t groups;
+  igraph_eigen_which_t which;
+
+  igraph_tree(&g, nodes, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+
+  igraph_sparsemat_init(&laplacian, nodes, nodes, igraph_ecount(&g)*2);
+  igraph_matrix_complex_init(&V2, 0, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_vector_init(&groups, 0);
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_sparsemat_init(&laplacian, 0, 0, 0);
+  igraph_laplacian(&g, /*res=*/ 0, /*sparseres=*/ &laplacian, 
+		   /*normalized=*/ 0, /*weights=*/ 0);
+
+  which.pos=IGRAPH_EIGEN_LR;
+  which.howmany=1;
+
+  igraph_eigen_matrix(/*matrix=*/ 0, &laplacian, /*fun=*/ 0, nodes,
+		      /*extra=*/ 0, /*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+		      &which, /*options=*/ 0, /*storage=*/ 0, 
+		      /*values=*/ 0, &V2);
+  igraph_matrix_complex_real(&V2, &V);
+
+  /* ------------ */
+  
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_OPTIMUM, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_INTERV_KM, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_INTERV, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */
+
+  igraph_scg_grouping(&V, &groups, /*(ignored) intervals=*/ 0, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_EXACT, /*p=*/ 0, /*maxiter=*/ 10000);
+  igraph_vector_print(&groups);
+
+  /* ------------ */  
+
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_complex_destroy(&V2);
+  igraph_sparsemat_destroy(&laplacian);
+  igraph_destroy(&g);
+
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
diff --git a/examples/simple/igraph_scg_grouping4.out b/examples/simple/igraph_scg_grouping4.out
new file mode 100644
index 0000000..a137ff8
--- /dev/null
+++ b/examples/simple/igraph_scg_grouping4.out
@@ -0,0 +1,4 @@
+0 2 2 1 1 1 1 1 1 1
+0 2 2 1 1 1 1 1 1 1
+0 2 2 1 1 1 1 1 1 1
+0 3 3 2 1 1 1 1 1 1
diff --git a/examples/simple/igraph_scg_semiprojectors.c b/examples/simple/igraph_scg_semiprojectors.c
new file mode 100644
index 0000000..295eea2
--- /dev/null
+++ b/examples/simple/igraph_scg_semiprojectors.c
@@ -0,0 +1,112 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_matrix_t L, R;
+  igraph_sparsemat_t Lsparse, Rsparse;
+  igraph_matrix_t adj, V;
+  igraph_vector_t groups;
+  igraph_eigen_which_t which;
+
+  igraph_matrix_init(&L, 0, 0);
+  igraph_matrix_init(&R, 0, 0);
+  igraph_matrix_init(&adj, 0, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_vector_init(&groups, 0);
+    
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_get_adjacency(&g, &adj, IGRAPH_GET_ADJACENCY_BOTH, /*eids=*/ 0);
+
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=1;
+  igraph_eigen_matrix_symmetric(&adj, /*sparsemat=*/ 0, /*fun=*/ 0,
+				igraph_vcount(&g), /*extra=*/ 0, 
+				/*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+				&which, /*options=*/ 0, /*storage=*/ 0, 
+				/*values=*/ 0, &V);
+
+#define SEMI()								\
+  do {									\
+    igraph_scg_semiprojectors(&groups, IGRAPH_SCG_SYMMETRIC, &L, &R,	\
+			      &Lsparse, &Rsparse, /*p=*/ 0,		\
+			      IGRAPH_SCG_NORM_ROW);			\
+  } while(0)
+
+#define PRINTRES()				\
+  do {						\
+    printf("----------------------\n");		\
+    igraph_matrix_print(&L);			\
+    printf("---\n");				\
+    igraph_matrix_print(&R);			\
+    printf("---\n");				\
+  } while (0)
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_OPTIMUM, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 2, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_INTERV_KM, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 2, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_INTERV, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*(ignored) intervals=*/ 0, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_SYMMETRIC,
+		      IGRAPH_SCG_EXACT, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_destroy(&adj);
+  igraph_destroy(&g);
+  
+  return 0;
+}
+    
diff --git a/examples/simple/igraph_scg_semiprojectors.out b/examples/simple/igraph_scg_semiprojectors.out
new file mode 100644
index 0000000..d1421e6
--- /dev/null
+++ b/examples/simple/igraph_scg_semiprojectors.out
@@ -0,0 +1,34 @@
+----------------------
+1 0 0 0 0 0 0 0 0 0
+0 0.707107 0.707107 0 0 0 0 0 0 0
+0 0 0 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964
+---
+1 0 0 0 0 0 0 0 0 0
+0 0.707107 0.707107 0 0 0 0 0 0 0
+0 0 0 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964
+---
+----------------------
+0.57735 0.57735 0.57735 0 0 0 0 0 0 0
+0 0 0 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964
+---
+0.57735 0.57735 0.57735 0 0 0 0 0 0 0
+0 0 0 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964
+---
+----------------------
+0.57735 0.57735 0.57735 0 0 0 0 0 0 0
+0 0 0 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964
+---
+0.57735 0.57735 0.57735 0 0 0 0 0 0 0
+0 0 0 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964 0.377964
+---
+----------------------
+1 0 0 0 0 0 0 0 0 0
+0 0.707107 0.707107 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 0 0 0
+0 0 0 0 0.408248 0.408248 0.408248 0.408248 0.408248 0.408248
+---
+1 0 0 0 0 0 0 0 0 0
+0 0.707107 0.707107 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 0 0 0
+0 0 0 0 0.408248 0.408248 0.408248 0.408248 0.408248 0.408248
+---
diff --git a/examples/simple/igraph_scg_semiprojectors2.c b/examples/simple/igraph_scg_semiprojectors2.c
new file mode 100644
index 0000000..b0113b8
--- /dev/null
+++ b/examples/simple/igraph_scg_semiprojectors2.c
@@ -0,0 +1,147 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  int nodes=10;
+  igraph_t g;
+  igraph_matrix_t L, R;
+  igraph_sparsemat_t Lsparse, Rsparse;
+  igraph_matrix_t V, V3;
+  igraph_matrix_complex_t V2;
+  igraph_sparsemat_t stochastic, stochasticT;
+  igraph_vector_t groups;
+  igraph_eigen_which_t which;
+  igraph_vector_t p, selcol;
+
+  igraph_matrix_init(&L, 0, 0);
+  igraph_matrix_init(&R, 0, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_matrix_init(&V3, 0, 0);
+  igraph_vector_init(&groups, 0);
+  igraph_vector_init(&selcol, 1);
+    
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_sparsemat_init(&stochastic, nodes, nodes, igraph_ecount(&g)*2);
+  igraph_matrix_complex_init(&V2, 0, 0);
+  igraph_vector_init(&p, 0);
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_get_stochastic_sparsemat(&g, &stochastic, /*column-wise=*/ 0);
+  igraph_sparsemat_transpose(&stochastic, &stochasticT, /*values=*/ 1);
+
+  which.pos=IGRAPH_EIGEN_LR;
+  which.howmany=1;
+
+  igraph_eigen_matrix(/*matrix=*/ 0, &stochasticT, /*fun=*/ 0, 10,
+		      /*extra=*/ 0, /*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+		      &which, /*options=*/ 0, /*storage=*/ 0, 
+		      /*values=*/ 0, &V2);
+  igraph_matrix_complex_real(&V2, &V);
+  /* `p' is always the eigenvector corresponding to the 1-eigenvalue */
+  igraph_matrix_get_col(&V, &p, 0);
+
+  which.howmany=3;
+  igraph_eigen_matrix(/*matrix=*/ 0, &stochastic, /*fun=*/ 0, 10,
+		      /*extra=*/ 0, /*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+		      &which, /*options=*/ 0, /*storage=*/ 0, 
+		      /*values=*/ 0, &V2);
+  igraph_matrix_complex_real(&V2, &V3);
+  VECTOR(selcol)[0]=2;
+  igraph_matrix_select_cols(&V3, &V, &selcol);
+
+#define SEMI()								\
+  do {									\
+    igraph_scg_semiprojectors(&groups, IGRAPH_SCG_STOCHASTIC, &L, &R,	\
+			      &Lsparse, &Rsparse, &p,			\
+			      IGRAPH_SCG_NORM_ROW);			\
+  } while(0)
+
+#define PRINTRES()				\
+  do {						\
+    printf("----------------------\n");		\
+    igraph_matrix_print(&L);			\
+    printf("---\n");				\
+    igraph_matrix_print(&R);			\
+    printf("---\n");				\
+  } while (0)
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_OPTIMUM, &p, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_INTERV_KM, &p, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_INTERV, &p, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*(ignored) intervals=*/ 0, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_STOCHASTIC,
+		      IGRAPH_SCG_EXACT, &p, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_vector_destroy(&p);
+  igraph_vector_destroy(&selcol);
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&L);
+  igraph_matrix_destroy(&R);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_destroy(&V3);
+  igraph_matrix_complex_destroy(&V2);
+  igraph_sparsemat_destroy(&stochasticT);
+  igraph_sparsemat_destroy(&stochastic);
+  igraph_destroy(&g);
+  
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
+    
diff --git a/examples/simple/igraph_scg_semiprojectors2.out b/examples/simple/igraph_scg_semiprojectors2.out
new file mode 100644
index 0000000..9faabe1
--- /dev/null
+++ b/examples/simple/igraph_scg_semiprojectors2.out
@@ -0,0 +1,38 @@
+----------------------
+0.75 0 0 0.25 0 0 0 0 0 0
+0 0.5 0.5 0 0 0 0 0 0 0
+0 0 0 0 0.166667 0.166667 0.166667 0.166667 0.166667 0.166667
+---
+1 0 0 1 0 0 0 0 0 0
+0 1 1 0 0 0 0 0 0 0
+0 0 0 0 1 1 1 1 1 1
+---
+----------------------
+0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0
+0 0.285714 0.285714 0 0.0714286 0.0714286 0.0714286 0.0714286 0.0714286 0.0714286
+---
+0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0
+0 1 1 0 1 1 1 1 1 1
+---
+----------------------
+0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0
+0 0.285714 0.285714 0 0.0714286 0.0714286 0.0714286 0.0714286 0.0714286 0.0714286
+---
+0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0
+0 1 1 0 1 1 1 1 1 1
+---
+----------------------
+0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0
+0 0.5 0.5 0 0 0 0 0 0 0
+0 0 0 0 0.166667 0.166667 0.166667 0.166667 0.166667 0.166667
+---
+0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0
+0 1 1 0 0 0 0 0 0 0
+0 0 0 0 1 1 1 1 1 1
+---
diff --git a/examples/simple/igraph_scg_semiprojectors3.c b/examples/simple/igraph_scg_semiprojectors3.c
new file mode 100644
index 0000000..5722b03
--- /dev/null
+++ b/examples/simple/igraph_scg_semiprojectors3.c
@@ -0,0 +1,128 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  int nodes=10;
+  igraph_t g;
+  igraph_matrix_t L, R;
+  igraph_sparsemat_t Lsparse, Rsparse;
+  igraph_matrix_t V;
+  igraph_matrix_complex_t V2;
+  igraph_sparsemat_t laplacian;
+  igraph_vector_t groups;
+  igraph_eigen_which_t which;
+
+  igraph_matrix_init(&L, 0, 0);
+  igraph_matrix_init(&R, 0, 0);
+  igraph_matrix_init(&V, 0, 0);
+  igraph_matrix_complex_init(&V2, 0, 0);
+  igraph_vector_init(&groups, 0);
+    
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_sparsemat_init(&laplacian, nodes, nodes, igraph_ecount(&g)*2);
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_laplacian(&g, /*res=*/ 0, /*sparseres=*/ &laplacian, 
+		   /*normalized=*/ 0, /*weights=*/ 0);
+
+  which.pos=IGRAPH_EIGEN_LM;
+  which.howmany=1;
+
+  igraph_eigen_matrix(/*matrix=*/ 0, &laplacian, /*fun=*/ 0, 10,
+		      /*extra=*/ 0, /*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+		      &which, /*options=*/ 0, /*storage=*/ 0, 
+		      /*values=*/ 0, &V2);
+  igraph_matrix_complex_real(&V2, &V);
+
+#define SEMI()								\
+  do {									\
+    igraph_scg_semiprojectors(&groups, IGRAPH_SCG_LAPLACIAN, &L, &R,	\
+			      &Lsparse, &Rsparse, /*p=*/ 0,		\
+			      IGRAPH_SCG_NORM_ROW);			\
+  } while(0)
+
+#define PRINTRES()				\
+  do {						\
+    printf("----------------------\n");		\
+    igraph_matrix_print(&L);			\
+    printf("---\n");				\
+    igraph_matrix_print(&R);			\
+    printf("---\n");				\
+  } while (0)
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 3, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_OPTIMUM, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 2, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_INTERV_KM, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*intervals=*/ 2, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_INTERV, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_scg_grouping(&V, &groups, /*(ignored) intervals=*/ 0, 
+		      /*intervals_vector=*/ 0, IGRAPH_SCG_LAPLACIAN,
+		      IGRAPH_SCG_EXACT, /*p=*/ 0, /*maxiter=*/ 10000);
+  SEMI();
+  PRINTRES();
+
+  /* -------------- */
+
+  igraph_matrix_destroy(&L);
+  igraph_matrix_destroy(&R);
+  igraph_matrix_destroy(&V);
+  igraph_matrix_complex_destroy(&V2);
+  igraph_vector_destroy(&groups);
+  igraph_sparsemat_destroy(&laplacian);
+  igraph_destroy(&g);
+  
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
+    
diff --git a/examples/simple/igraph_scg_semiprojectors3.out b/examples/simple/igraph_scg_semiprojectors3.out
new file mode 100644
index 0000000..d3d2b3d
--- /dev/null
+++ b/examples/simple/igraph_scg_semiprojectors3.out
@@ -0,0 +1,34 @@
+----------------------
+1 0 0 0 0 0 0 0 0 0
+0 0 0 0.142857 0.142857 0.142857 0.142857 0.142857 0.142857 0.142857
+0 0.5 0.5 0 0 0 0 0 0 0
+---
+1 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 1 1 1 1
+0 1 1 0 0 0 0 0 0 0
+---
+----------------------
+0.125 0 0 0.125 0.125 0.125 0.125 0.125 0.125 0.125
+0 0.5 0.5 0 0 0 0 0 0 0
+---
+1 0 0 1 1 1 1 1 1 1
+0 1 1 0 0 0 0 0 0 0
+---
+----------------------
+0.142857 0 0 0 0.142857 0.142857 0.142857 0.142857 0.142857 0.142857
+0 0.333333 0.333333 0.333333 0 0 0 0 0 0
+---
+1 0 0 0 1 1 1 1 1 1
+0 1 1 1 0 0 0 0 0 0
+---
+----------------------
+1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0.166667 0.166667 0.166667 0.166667 0.166667 0.166667
+0 0 0 1 0 0 0 0 0 0
+0 0.5 0.5 0 0 0 0 0 0 0
+---
+1 0 0 0 0 0 0 0 0 0
+0 0 0 0 1 1 1 1 1 1
+0 0 0 1 0 0 0 0 0 0
+0 1 1 0 0 0 0 0 0 0
+---
diff --git a/examples/simple/igraph_set.c b/examples/simple/igraph_set.c
new file mode 100644
index 0000000..dea48ca
--- /dev/null
+++ b/examples/simple/igraph_set.c
@@ -0,0 +1,84 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_types_internal.h>
+#include <stdlib.h>
+
+void print_set(igraph_set_t *set, FILE *f) {
+  long int state=0;
+  igraph_integer_t element;
+  while (igraph_set_iterate(set, &state, &element)) {
+    fprintf(f, " %li", (long int) element);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_set_t set;
+  int i;
+
+  /* simple init */
+  igraph_set_init(&set, 0);
+  igraph_set_destroy(&set);
+
+  /* addition, igraph_set_size */
+  igraph_set_init(&set, 10);
+  i=10;
+  while (igraph_set_size(&set) < 10) {
+    igraph_set_add(&set, 2*i);
+    i--;
+  }
+  while (igraph_set_size(&set) < 21) {
+    igraph_set_add(&set, 2*i+1);
+    i++;
+  }
+  print_set(&set, stdout);
+
+  /* adding existing element */
+  igraph_set_add(&set, 8);
+  if (igraph_set_size(&set) != 21) {
+    return 4;
+  }
+
+  /* igraph_set_contains */
+  if (igraph_set_contains(&set, 42) || !igraph_set_contains(&set, 7)) {
+    return 3;
+  }
+
+  /* igraph_set_empty, igraph_set_clear */
+  if (igraph_set_empty(&set)) {
+    return 1;
+  }
+  igraph_set_clear(&set);
+  if (!igraph_set_empty(&set)) {
+    return 2;
+  }
+  igraph_set_destroy(&set);
+  
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 5;
+
+  return 0;
+}
+  
diff --git a/examples/simple/igraph_set.out b/examples/simple/igraph_set.out
new file mode 100644
index 0000000..08c0614
--- /dev/null
+++ b/examples/simple/igraph_set.out
@@ -0,0 +1 @@
+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
diff --git a/examples/simple/igraph_similarity.c b/examples/simple/igraph_similarity.c
new file mode 100644
index 0000000..a956d8d
--- /dev/null
+++ b/examples/simple/igraph_similarity.c
@@ -0,0 +1,210 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_matrix(igraph_matrix_t *m, FILE *f) {
+  long int i, j;
+  for (i=0; i<igraph_matrix_nrow(m); i++) {
+    for (j=0; j<igraph_matrix_ncol(m); j++) {
+      fprintf(f, " %.2f", MATRIX(*m, i, j));
+    }
+    fprintf(f, "\n");
+  }
+  fprintf(f, "==========\n");
+}
+
+int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
+		igraph_neimode_t mode, igraph_bool_t loops) {
+  igraph_vector_t pairs, res;
+  long int i, j, k, n;
+  igraph_eit_t eit;
+
+  igraph_vector_init(&res, 0);
+
+  /* First, query the similarities for all the vertices to a matrix */
+  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);
+
+  /* Second, query the similarities for all pairs using a pair vector */
+  n = igraph_vcount(g);
+  igraph_vector_init(&pairs, 0);
+  for (i = 0; i < n; i++) {
+    for (j = n-1; j >= 0; j--) {
+      igraph_vector_push_back(&pairs, i);
+      igraph_vector_push_back(&pairs, j);
+    }
+  }
+  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
+  for (i = 0, k = 0; i < n; i++) {
+    for (j = n-1; j >= 0; j--, k++) {
+      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
+        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
+            "does not match the value in the full matrix (%.6f vs %.6f)\n",
+            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
+        return 1;
+      }
+    }
+  }
+  igraph_vector_destroy(&pairs);
+
+  /* Third, query the similarities for all edges */
+  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
+  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
+  k = 0;
+  while (!IGRAPH_EIT_END(eit)) {
+    long int eid = IGRAPH_EIT_GET(eit);
+    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
+    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
+      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
+          "does not match the value in the full matrix (%.6f vs %.6f)\n",
+          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
+      return 1;
+    }
+    IGRAPH_EIT_NEXT(eit);
+    k++;
+  }
+
+  igraph_eit_destroy(&eit);
+
+  igraph_vector_destroy(&res);
+
+  return 0;
+}
+
+int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
+		igraph_neimode_t mode, igraph_bool_t loops) {
+  igraph_vector_t pairs, res;
+  long int i, j, k, n;
+  igraph_eit_t eit;
+
+  igraph_vector_init(&res, 0);
+
+  /* First, query the similarities for all the vertices to a matrix */
+  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);
+
+  /* Second, query the similarities for all pairs using a pair vector */
+  n = igraph_vcount(g);
+  igraph_vector_init(&pairs, 0);
+  for (i = 0; i < n; i++) {
+    for (j = n-1; j >= 0; j--) {
+      igraph_vector_push_back(&pairs, i);
+      igraph_vector_push_back(&pairs, j);
+    }
+  }
+  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
+  for (i = 0, k = 0; i < n; i++) {
+    for (j = n-1; j >= 0; j--, k++) {
+      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
+        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
+            "does not match the value in the full matrix (%.6f vs %.6f)\n",
+            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
+        return 1;
+      }
+    }
+  }
+  igraph_vector_destroy(&pairs);
+
+  /* Third, query the similarities for all edges */
+  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
+  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
+  k = 0;
+  while (!IGRAPH_EIT_END(eit)) {
+    long int eid = IGRAPH_EIT_GET(eit);
+    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
+    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
+      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
+          "does not match the value in the full matrix (%.6f vs %.6f)\n",
+          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
+      return 1;
+    }
+    IGRAPH_EIT_NEXT(eit);
+    k++;
+  }
+
+  igraph_eit_destroy(&eit);
+
+  igraph_vector_destroy(&res);
+
+  return 0;
+}
+
+int main() {
+  
+  igraph_t g;
+  igraph_matrix_t m;
+  int ret;
+
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 
+	       0,1, 2,1, 2,0, 3,0, 
+	       -1);
+  
+  igraph_matrix_init(&m, 0, 0);
+
+  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
+  print_matrix(&m, stdout);
+  if (ret)
+    return 1;
+  
+  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
+  print_matrix(&m, stdout);
+  
+  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
+  print_matrix(&m, stdout);
+  if (ret)
+    return 3;
+  
+  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
+  print_matrix(&m, stdout);
+  if (ret)
+    return 4;
+  
+  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
+  print_matrix(&m, stdout);
+  if (ret)
+    return 5;
+  
+  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
+  print_matrix(&m, stdout);
+  if (ret)
+    return 6;
+
+  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
+  print_matrix(&m, stdout);
+  if (ret)
+    return 7;
+
+  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
+  print_matrix(&m, stdout);
+  
+  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
+  print_matrix(&m, stdout);
+  
+  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
+  print_matrix(&m, stdout);
+  
+  igraph_matrix_destroy(&m);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_similarity.out b/examples/simple/igraph_similarity.out
new file mode 100644
index 0000000..726c59c
--- /dev/null
+++ b/examples/simple/igraph_similarity.out
@@ -0,0 +1,48 @@
+ 1.00 0.75 0.75 0.50
+ 0.75 1.00 1.00 0.25
+ 0.75 1.00 1.00 0.25
+ 0.50 0.25 0.25 1.00
+==========
+ 1.00 0.33
+ 0.33 1.00
+==========
+ 1.00 0.50 0.67 0.33
+ 0.50 1.00 0.33 0.00
+ 0.67 0.33 1.00 0.25
+ 0.33 0.00 0.25 1.00
+==========
+ 1.00 0.33 0.00 0.00
+ 0.33 1.00 0.00 0.00
+ 0.00 0.00 1.00 0.00
+ 0.00 0.00 0.00 1.00
+==========
+ 1.00 0.86 0.86 0.67
+ 0.86 1.00 1.00 0.40
+ 0.86 1.00 1.00 0.40
+ 0.67 0.40 0.40 1.00
+==========
+ 1.00 0.67 0.80 0.50
+ 0.67 1.00 0.50 0.00
+ 0.80 0.50 1.00 0.40
+ 0.50 0.00 0.40 1.00
+==========
+ 1.00 0.50 0.00 0.00
+ 0.50 1.00 0.00 0.00
+ 0.00 0.00 1.00 0.00
+ 0.00 0.00 0.00 1.00
+==========
+ 0.00 1.44 1.44 0.00
+ 1.44 0.00 0.91 0.91
+ 1.44 0.91 0.00 0.91
+ 0.00 0.91 0.91 0.00
+==========
+ 0.00 0.00 1.44 0.00
+ 0.00 0.00 0.00 0.00
+ 1.44 0.00 0.00 1.44
+ 0.00 0.00 1.44 0.00
+==========
+ 0.00 1.44 0.00 0.00
+ 1.44 0.00 0.00 0.00
+ 0.00 0.00 0.00 0.00
+ 0.00 0.00 0.00 0.00
+==========
diff --git a/examples/simple/igraph_simplify.c b/examples/simple/igraph_simplify.c
new file mode 100644
index 0000000..1a8ec5d
--- /dev/null
+++ b/examples/simple/igraph_simplify.c
@@ -0,0 +1,92 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+
+  /* Multiple edges */
+
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 0,1, 0,1, 0,1, 0,1, -1);
+  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+  
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 1,0, 0,1, 1,0, 0,1, 0,1, -1);
+  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
+  if (igraph_ecount(&g) != 1) {
+    return 1;
+  }
+  igraph_destroy(&g);
+  
+  /* Loop edges*/
+  
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,0,1,1,2,2, 1,2, -1);
+  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 0,0,1,1,2,2, 1,2, -1); 
+  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  /* Loop & multiple edges */
+  
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,0,0,0,0,0,0,0, 1,2, -1);
+  igraph_simplify(&g, 1 /* multiple */, 0 /* loop */, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 1,1,1,1,1,1,1,1, 2,3, -1); 
+  igraph_simplify(&g, 1 /* multiple */, 0 /* loop */, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 2,2,2,2,2,2, 3,2, -1);
+  igraph_simplify(&g, 0 /* multiple */, 1 /* loop */, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 3,3,3,3, 3,4, -1);
+  igraph_simplify(&g, 0 /* multiple */, 1 /* loop */, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);  
+
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 2,2,2,2,2,2,2,2, 3,2,3,2,3,2,3,2,3,2,-1);
+  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       2,2,2,2,2,2,2,2, 3,2,2,3,3,2,3,2,3,2,-1);
+  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
+  if (igraph_ecount(&g) != 1) { 
+    return 2;
+  }
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_simplify.out b/examples/simple/igraph_simplify.out
new file mode 100644
index 0000000..3ad16e2
--- /dev/null
+++ b/examples/simple/igraph_simplify.out
@@ -0,0 +1,10 @@
+0 1
+1 2
+1 2
+0 0
+1 2
+1 1
+2 3
+3 2
+3 4
+3 2
diff --git a/examples/simple/igraph_small.c b/examples/simple/igraph_small.c
new file mode 100644
index 0000000..eecf50f
--- /dev/null
+++ b/examples/simple/igraph_small.c
@@ -0,0 +1,35 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  
+  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,3, 3,4, 6,1, -1);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_small.out b/examples/simple/igraph_small.out
new file mode 100644
index 0000000..4ed7c99
--- /dev/null
+++ b/examples/simple/igraph_small.out
@@ -0,0 +1,5 @@
+0 1
+1 2
+2 3
+3 4
+6 1
diff --git a/examples/simple/igraph_sparsemat.c b/examples/simple/igraph_sparsemat.c
new file mode 100644
index 0000000..b1bb4cc
--- /dev/null
+++ b/examples/simple/igraph_sparsemat.c
@@ -0,0 +1,162 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_sparsemat.h>
+
+int main() {
+  
+  igraph_sparsemat_t A, B, C, D;
+  igraph_t G, H;
+  igraph_vector_t vect;
+  long int i;
+  
+  /* Create, compress, destroy */
+  igraph_sparsemat_init(&A, 100, 20, 50);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&B);
+  igraph_sparsemat_destroy(&A);
+  
+  /* Convert a ring graph to a matrix, print it, compress, print again */
+#define VC 10
+  igraph_ring(&G, VC, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_get_sparsemat(&G, &A);
+  igraph_destroy(&G);
+
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_print(&A, stdout);
+  igraph_sparsemat_print(&B, stdout);
+
+  /* Basic query, nrow, ncol, type, is_triplet, is_cc */
+  if (igraph_sparsemat_nrow(&A) != VC ||
+      igraph_sparsemat_ncol(&A) != VC ||
+      igraph_sparsemat_nrow(&B) != VC || 
+      igraph_sparsemat_ncol(&B) != VC) {
+    return 1;
+  }
+  if (!igraph_sparsemat_is_triplet(&A)) { return 2; }
+  if (!igraph_sparsemat_is_cc(&B))      { return 3; }
+  if (igraph_sparsemat_type(&A) != IGRAPH_SPARSEMAT_TRIPLET) { return 4; }
+  if (igraph_sparsemat_type(&B) != IGRAPH_SPARSEMAT_CC)      { return 5; }
+
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);
+#undef VC
+
+  printf("------------------------\n");
+
+  /* Create unit matrices */
+  igraph_sparsemat_eye(&A, /*n=*/ 5, /*nzmax=*/ 5, /*value=*/ 1.0, 
+		       /*compress=*/ 0);
+  igraph_sparsemat_eye(&B, /*n=*/ 5, /*nzmax=*/ 5, /*value=*/ 1.0, 
+		       /*compress=*/ 1);
+  igraph_sparsemat_print(&A, stdout);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);  
+
+  printf("------------------------\n");
+
+  /* Create diagonal matrices */
+  igraph_vector_init(&vect, 5);
+  for (i=0; i<5; i++) { VECTOR(vect)[i] = i; }
+  igraph_sparsemat_diag(&A, /*nzmax=*/ 5, /*values=*/ &vect, /*compress=*/ 0);
+  igraph_sparsemat_diag(&B, /*nzmax=*/ 5, /*values=*/ &vect, /*compress=*/ 1);
+  igraph_vector_destroy(&vect);
+  igraph_sparsemat_print(&A, stdout);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);
+
+  printf("------------------------\n");
+  
+  /* Transpose matrices */
+  igraph_tree(&G, 10, /*children=*/ 2, IGRAPH_TREE_OUT);
+  igraph_get_sparsemat(&G, &A);
+  igraph_destroy(&G);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_transpose(&B, &C, /*values=*/ 1);
+  igraph_sparsemat_print(&C, stdout);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);	
+  igraph_sparsemat_destroy(&C);	
+
+  printf("------------------------\n");
+
+  /* Add duplicate elements */
+  igraph_sparsemat_init(&A, 10, 10, /*nzmax=*/ 20);
+  for (i=1; i<10; i++) {
+    igraph_sparsemat_entry(&A, 0, i, 1.0);
+  }
+  for (i=1; i<10; i++) {
+    igraph_sparsemat_entry(&A, 0, i, 1.0);
+  }
+  igraph_sparsemat_print(&A, stdout);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_dupl(&B);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);	
+
+  printf("------------------------\n");
+  
+  /* Drop zero elements */
+  igraph_sparsemat_init(&A, 10, 10, /*nzmax=*/ 20);
+  igraph_sparsemat_entry(&A, 7, 3, 0.0);
+  for (i=1; i<10; i++) {
+    igraph_sparsemat_entry(&A, 0, i, 1.0);
+    igraph_sparsemat_entry(&A, 0, i, 0.0);
+  }
+  igraph_sparsemat_entry(&A, 0, 0, 0.0);
+  igraph_sparsemat_print(&A, stdout);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_dropzeros(&B);
+  igraph_sparsemat_print(&B, stdout);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);	  
+
+  printf("------------------------\n");
+
+  /* Add two matrices */
+  
+  igraph_star(&G, 10, IGRAPH_STAR_OUT, /*center=*/ 0);
+  igraph_ring(&H, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_get_sparsemat(&G, &A);
+  igraph_get_sparsemat(&H, &B);
+  igraph_destroy(&G);
+  igraph_destroy(&H);
+  igraph_sparsemat_compress(&A, &C);
+  igraph_sparsemat_compress(&B, &D);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);
+  igraph_sparsemat_add(&C, &D, /*alpha=*/ 1.0, /*beta=*/ 2.0, &A);
+  igraph_sparsemat_destroy(&C);
+  igraph_sparsemat_destroy(&D);
+  igraph_sparsemat_print(&A, stdout);
+  igraph_sparsemat_destroy(&A);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat.out b/examples/simple/igraph_sparsemat.out
new file mode 100644
index 0000000..33b5e6d
--- /dev/null
+++ b/examples/simple/igraph_sparsemat.out
@@ -0,0 +1,295 @@
+1 0 : 1
+0 1 : 1
+2 1 : 1
+1 2 : 1
+3 2 : 1
+2 3 : 1
+4 3 : 1
+3 4 : 1
+5 4 : 1
+4 5 : 1
+6 5 : 1
+5 6 : 1
+7 6 : 1
+6 7 : 1
+8 7 : 1
+7 8 : 1
+9 8 : 1
+8 9 : 1
+9 0 : 1
+0 9 : 1
+col 0: locations 0 to 1
+1 : 1
+9 : 1
+col 1: locations 2 to 3
+0 : 1
+2 : 1
+col 2: locations 4 to 5
+1 : 1
+3 : 1
+col 3: locations 6 to 7
+2 : 1
+4 : 1
+col 4: locations 8 to 9
+3 : 1
+5 : 1
+col 5: locations 10 to 11
+4 : 1
+6 : 1
+col 6: locations 12 to 13
+5 : 1
+7 : 1
+col 7: locations 14 to 15
+6 : 1
+8 : 1
+col 8: locations 16 to 17
+7 : 1
+9 : 1
+col 9: locations 18 to 19
+8 : 1
+0 : 1
+------------------------
+0 0 : 1
+1 1 : 1
+2 2 : 1
+3 3 : 1
+4 4 : 1
+col 0: locations 0 to 0
+0 : 1
+col 1: locations 1 to 1
+1 : 1
+col 2: locations 2 to 2
+2 : 1
+col 3: locations 3 to 3
+3 : 1
+col 4: locations 4 to 4
+4 : 1
+------------------------
+0 0 : 0
+1 1 : 1
+2 2 : 2
+3 3 : 3
+4 4 : 4
+col 0: locations 0 to 0
+0 : 0
+col 1: locations 1 to 1
+1 : 1
+col 2: locations 2 to 2
+2 : 2
+col 3: locations 3 to 3
+3 : 3
+col 4: locations 4 to 4
+4 : 4
+------------------------
+col 0: locations 0 to -1
+col 1: locations 0 to 0
+0 : 1
+col 2: locations 1 to 1
+0 : 1
+col 3: locations 2 to 2
+1 : 1
+col 4: locations 3 to 3
+1 : 1
+col 5: locations 4 to 4
+2 : 1
+col 6: locations 5 to 5
+2 : 1
+col 7: locations 6 to 6
+3 : 1
+col 8: locations 7 to 7
+3 : 1
+col 9: locations 8 to 8
+4 : 1
+col 0: locations 0 to 1
+1 : 1
+2 : 1
+col 1: locations 2 to 3
+3 : 1
+4 : 1
+col 2: locations 4 to 5
+5 : 1
+6 : 1
+col 3: locations 6 to 7
+7 : 1
+8 : 1
+col 4: locations 8 to 8
+9 : 1
+col 5: locations 9 to 8
+col 6: locations 9 to 8
+col 7: locations 9 to 8
+col 8: locations 9 to 8
+col 9: locations 9 to 8
+------------------------
+0 1 : 1
+0 2 : 1
+0 3 : 1
+0 4 : 1
+0 5 : 1
+0 6 : 1
+0 7 : 1
+0 8 : 1
+0 9 : 1
+0 1 : 1
+0 2 : 1
+0 3 : 1
+0 4 : 1
+0 5 : 1
+0 6 : 1
+0 7 : 1
+0 8 : 1
+0 9 : 1
+col 0: locations 0 to -1
+col 1: locations 0 to 1
+0 : 1
+0 : 1
+col 2: locations 2 to 3
+0 : 1
+0 : 1
+col 3: locations 4 to 5
+0 : 1
+0 : 1
+col 4: locations 6 to 7
+0 : 1
+0 : 1
+col 5: locations 8 to 9
+0 : 1
+0 : 1
+col 6: locations 10 to 11
+0 : 1
+0 : 1
+col 7: locations 12 to 13
+0 : 1
+0 : 1
+col 8: locations 14 to 15
+0 : 1
+0 : 1
+col 9: locations 16 to 17
+0 : 1
+0 : 1
+col 0: locations 0 to -1
+col 1: locations 0 to 0
+0 : 2
+col 2: locations 1 to 1
+0 : 2
+col 3: locations 2 to 2
+0 : 2
+col 4: locations 3 to 3
+0 : 2
+col 5: locations 4 to 4
+0 : 2
+col 6: locations 5 to 5
+0 : 2
+col 7: locations 6 to 6
+0 : 2
+col 8: locations 7 to 7
+0 : 2
+col 9: locations 8 to 8
+0 : 2
+------------------------
+7 3 : 0
+0 1 : 1
+0 1 : 0
+0 2 : 1
+0 2 : 0
+0 3 : 1
+0 3 : 0
+0 4 : 1
+0 4 : 0
+0 5 : 1
+0 5 : 0
+0 6 : 1
+0 6 : 0
+0 7 : 1
+0 7 : 0
+0 8 : 1
+0 8 : 0
+0 9 : 1
+0 9 : 0
+0 0 : 0
+col 0: locations 0 to 0
+0 : 0
+col 1: locations 1 to 2
+0 : 1
+0 : 0
+col 2: locations 3 to 4
+0 : 1
+0 : 0
+col 3: locations 5 to 7
+7 : 0
+0 : 1
+0 : 0
+col 4: locations 8 to 9
+0 : 1
+0 : 0
+col 5: locations 10 to 11
+0 : 1
+0 : 0
+col 6: locations 12 to 13
+0 : 1
+0 : 0
+col 7: locations 14 to 15
+0 : 1
+0 : 0
+col 8: locations 16 to 17
+0 : 1
+0 : 0
+col 9: locations 18 to 19
+0 : 1
+0 : 0
+col 0: locations 0 to -1
+col 1: locations 0 to 0
+0 : 1
+col 2: locations 1 to 1
+0 : 1
+col 3: locations 2 to 2
+0 : 1
+col 4: locations 3 to 3
+0 : 1
+col 5: locations 4 to 4
+0 : 1
+col 6: locations 5 to 5
+0 : 1
+col 7: locations 6 to 6
+0 : 1
+col 8: locations 7 to 7
+0 : 1
+col 9: locations 8 to 8
+0 : 1
+------------------------
+col 0: locations 0 to 1
+1 : 2
+9 : 2
+col 1: locations 2 to 3
+0 : 3
+2 : 2
+col 2: locations 4 to 6
+0 : 1
+1 : 2
+3 : 2
+col 3: locations 7 to 9
+0 : 1
+2 : 2
+4 : 2
+col 4: locations 10 to 12
+0 : 1
+3 : 2
+5 : 2
+col 5: locations 13 to 15
+0 : 1
+4 : 2
+6 : 2
+col 6: locations 16 to 18
+0 : 1
+5 : 2
+7 : 2
+col 7: locations 19 to 21
+0 : 1
+6 : 2
+8 : 2
+col 8: locations 22 to 24
+0 : 1
+7 : 2
+9 : 2
+col 9: locations 25 to 26
+0 : 3
+8 : 2
diff --git a/examples/simple/igraph_sparsemat2.c b/examples/simple/igraph_sparsemat2.c
new file mode 100644
index 0000000..c39d0e5
--- /dev/null
+++ b/examples/simple/igraph_sparsemat2.c
@@ -0,0 +1,259 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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 <cs/cs.h>
+#include <igraph.h>
+#include <igraph_sparsemat.h>
+#include <igraph_blas_internal.h>
+#include <igraph_arpack_internal.h>
+
+int igraph_matrix_dgemv(const igraph_matrix_t *m,
+                        const igraph_vector_t *v,
+                        igraph_vector_t *res,
+                        igraph_real_t alpha,
+                        igraph_real_t beta,
+                        igraph_bool_t transpose_m) {
+  
+  int nrow=igraph_matrix_nrow(m);
+  int ncol=igraph_matrix_ncol(m);
+  long int vlen=igraph_vector_size(v);
+  int one=1;
+  char t = transpose_m ? 't' : 'n';
+  long int input_len  = transpose_m ? nrow : ncol;
+  long int output_len = transpose_m ? ncol : nrow;
+  
+  if (vlen != input_len) {
+    IGRAPH_ERROR("Matrix and vector sizes are incompatible", IGRAPH_EINVAL);
+  }
+  
+  if (beta != 0 && igraph_vector_size(res) != output_len) {
+    IGRAPH_ERROR("Non-zero beta and bad `res' vector size, possible mistake",
+                 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, output_len));
+  
+  igraphdgemv_(&t, &nrow, &ncol, &alpha, &MATRIX(*m,0,0), 
+               &nrow, VECTOR(*v), &one, &beta, VECTOR(*res), &one);
+  
+  return 0;
+}
+
+int igraph_matrix_vector_prod(const igraph_matrix_t *m,
+                              const igraph_vector_t *v,
+                              igraph_vector_t *res) {
+  return igraph_matrix_dgemv(m, v, res, 1.0, 0.0, /*transpose=*/ 0);
+}
+
+int my_dgemv(const igraph_matrix_t *m,
+                       const igraph_vector_t *v,
+                       igraph_vector_t *res,
+                       igraph_real_t alpha,
+                       igraph_real_t beta,
+                       igraph_bool_t transpose_m) {
+  
+  int nrow=igraph_matrix_nrow(m);
+  int ncol=igraph_matrix_ncol(m);
+  long int vlen=igraph_vector_size(v);
+  int one=1;
+  char t = transpose_m ? 't' : 'n';
+  long int input_len  = transpose_m ? nrow : ncol;
+  long int output_len = transpose_m ? ncol : nrow;
+  
+  if (vlen != input_len) {
+    IGRAPH_ERROR("Matrix and vector sizes are incompatible", IGRAPH_EINVAL);
+  }
+  
+  if (beta != 0 && igraph_vector_size(res) != output_len) {
+    IGRAPH_ERROR("Non-zero beta and bad `res' vector size, possible mistake",
+                IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, output_len));
+  
+  igraphdgemv_(&t, &nrow, &ncol, &alpha, &MATRIX(*m,0,0), 
+              &nrow, VECTOR(*v), &one, &beta, VECTOR(*res), &one);
+  
+  return 0;
+}
+
+int my_gaxpy(const igraph_matrix_t *m,
+	     const igraph_vector_t *v,
+	     igraph_vector_t *res) {
+  return my_dgemv(m, v, res, 1.0, 0.0, /*transpose=*/ 0);
+}
+
+int my_dgemm(const igraph_matrix_t *m1,
+	     const igraph_matrix_t *m2,
+	     igraph_matrix_t *res) {
+
+  long int m1_r=igraph_matrix_nrow(m1);
+  long int m1_c=igraph_matrix_ncol(m1);
+  long int m2_r=igraph_matrix_nrow(m2);
+  long int m2_c=igraph_matrix_ncol(m2);
+  long int i, j, k;
+  
+  if (m1_c != m2_r) { 
+    IGRAPH_ERROR("Cannot multiply matrices, invalid dimensions", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, m1_r, m2_c));
+  igraph_matrix_null(res);
+
+  for (i=0; i<m1_r; i++) {
+    for (j=0; j<m2_c; j++) {
+      for (k=0; k<m1_c /* which is also m2_r*/; k++) {
+	MATRIX(*res, i, j) += MATRIX(*m1, i, k) * MATRIX(*m2, k, j);
+      }
+    }
+  }
+
+  return 0;
+}
+
+igraph_bool_t check_same(const igraph_sparsemat_t *A, 
+			 const igraph_matrix_t *M) {
+  
+  long int nrow=igraph_sparsemat_nrow(A);
+  long int ncol=igraph_sparsemat_ncol(A);
+  long int j, p, nzero=0;
+  
+  if (nrow != igraph_matrix_nrow(M) ||
+      ncol != igraph_matrix_ncol(M)) { 
+    return 0; 
+  }
+  
+  for (j=0; j<A->cs->n; j++) {
+    for (p=A->cs->p[j]; p < A->cs->p[j+1]; p++) {
+      long int to=A->cs->i[p];
+      igraph_real_t value=A->cs->x[p];
+      if (value != MATRIX(*M, to, j)) { return 0; }
+      nzero += 1;
+    }
+  }
+
+  for (j=0; j<nrow; j++) {
+    for (p=0; p<ncol; p++) {
+      if (MATRIX(*M, j, p) != 0) { nzero -= 1; }
+    }
+  }
+
+  return nzero == 0;
+}
+
+int main() {
+  
+  igraph_sparsemat_t A, B, C, D;
+  igraph_vector_t v, w, x, y;
+  igraph_matrix_t M, N, O;
+  long int i;
+
+  srand(1);
+
+  /* Matrix-vector product */
+#define NROW 10
+#define NCOL 5
+#define EDGES NROW*NCOL/3
+  igraph_matrix_init(&M, NROW, NCOL);
+  igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, NROW-1);
+    long int c=RNG_INTEGER(0, NCOL-1);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    MATRIX(M, r, c) = MATRIX(M, r, c) + value;
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  
+  igraph_vector_init(&v, NCOL);
+  igraph_vector_init(&w, NCOL);
+  for (i=0; i<NCOL; i++) {
+    VECTOR(v)[i] = VECTOR(w)[i] = RNG_INTEGER(1,5);
+  }
+  
+  igraph_vector_init(&x, NROW);
+  igraph_vector_init(&y, NROW);
+  my_gaxpy(&M, &v, &x);
+  igraph_vector_null(&y);
+  igraph_sparsemat_gaxpy(&B, &w, &y);
+  
+  if (!igraph_vector_all_e(&x, &y)) { return 1; }
+
+  igraph_vector_destroy(&x);
+  igraph_vector_destroy(&y);
+  igraph_vector_destroy(&v);
+  igraph_vector_destroy(&w);
+  igraph_sparsemat_destroy(&B);
+  igraph_matrix_destroy(&M);
+
+#undef NROW
+#undef NCOL
+#undef EDGES
+
+  /* Matrix-matrix product */
+#define NROW_A 10
+#define NCOL_A 7
+#define EDGES_A NROW_A*NCOL_A/3
+#define NROW_B 7
+#define NCOL_B 9
+#define EDGES_B NROW_B*NCOL_B/3
+  igraph_matrix_init(&M, NROW_A, NCOL_A);
+  igraph_sparsemat_init(&A, NROW_A, NCOL_A, EDGES_A);
+  for (i=0; i<EDGES_A; i++) {
+    long int r=RNG_INTEGER(0, NROW_A-1);
+    long int c=RNG_INTEGER(0, NCOL_A-1);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    MATRIX(M, r, c) = MATRIX(M, r, c) + value;
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &C);
+  igraph_sparsemat_destroy(&A);
+
+  igraph_matrix_init(&N, NROW_B, NCOL_B);
+  igraph_sparsemat_init(&B, NROW_B, NCOL_B, EDGES_B);
+  for (i=0; i<EDGES_B; i++) {
+    long int r=RNG_INTEGER(0, NROW_B-1);
+    long int c=RNG_INTEGER(0, NCOL_B-1);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    MATRIX(N, r, c) = MATRIX(N, r, c) + value;
+    igraph_sparsemat_entry(&B, r, c, value);
+  }
+  igraph_sparsemat_compress(&B, &D);
+  igraph_sparsemat_destroy(&B);
+
+  igraph_matrix_init(&O, 0, 0);
+  my_dgemm(&M, &N, &O);
+  igraph_sparsemat_multiply(&C, &D, &A);
+
+  if (! check_same(&A, &O)) { return 2; }
+  
+  igraph_sparsemat_destroy(&C);
+  igraph_sparsemat_destroy(&D);
+  igraph_sparsemat_destroy(&A);
+  igraph_matrix_destroy(&M);
+  igraph_matrix_destroy(&N);
+  igraph_matrix_destroy(&O);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat2.out b/examples/simple/igraph_sparsemat2.out
new file mode 100644
index 0000000..e69de29
diff --git a/examples/simple/igraph_sparsemat3.c b/examples/simple/igraph_sparsemat3.c
new file mode 100644
index 0000000..630bf1a
--- /dev/null
+++ b/examples/simple/igraph_sparsemat3.c
@@ -0,0 +1,309 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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 <cs/cs.h>
+#include <igraph.h>
+#include <igraph_sparsemat.h>
+
+int permute(const igraph_matrix_t *M, 
+	    const igraph_vector_int_t *p,
+	    const igraph_vector_int_t *q,
+	    igraph_matrix_t *res) {
+  
+  long int nrow=igraph_vector_int_size(p);
+  long int ncol=igraph_vector_int_size(q);
+  long int i, j;
+
+  igraph_matrix_resize(res, nrow, ncol);
+
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      int ii=VECTOR(*p)[i];
+      int jj=VECTOR(*q)[j];
+      MATRIX(*res, i, j) = MATRIX(*M, ii, jj);
+    }
+  }
+  
+  return 0;
+}
+
+int permute_rows(const igraph_matrix_t *M,
+		 const igraph_vector_int_t *p,
+		 igraph_matrix_t *res) {
+
+  long int nrow=igraph_vector_int_size(p);
+  long int ncol=igraph_matrix_ncol(M);
+  long int i, j;
+  
+  igraph_matrix_resize(res, nrow, ncol);
+  
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      int ii=VECTOR(*p)[i];
+      MATRIX(*res, i, j) = MATRIX(*M, ii, j);
+    }
+  }
+  
+  return 0;
+}
+
+int permute_cols(const igraph_matrix_t *M,
+		 const igraph_vector_int_t *q,
+		 igraph_matrix_t *res) {
+
+  long int nrow=igraph_matrix_nrow(M);
+  long int ncol=igraph_vector_int_size(q);
+  long int i, j;
+  
+  igraph_matrix_resize(res, nrow, ncol);
+  
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      int jj=VECTOR(*q)[j];
+      MATRIX(*res, i, j) = MATRIX(*M, i, jj);
+    }
+  }
+  
+  return 0;
+}
+
+int random_permutation(igraph_vector_int_t *vec) {
+  /* We just do size(vec) * 2 swaps */
+  long int one, two, i, n=igraph_vector_int_size(vec);
+  int tmp;
+  for (i=0; i<2*n; i++) {
+    one= RNG_INTEGER(0, n-1);
+    two= RNG_INTEGER(0, n-1);
+    tmp=VECTOR(*vec)[one];
+    VECTOR(*vec)[one] = VECTOR(*vec)[two];
+    VECTOR(*vec)[two] = tmp;
+  }
+  return 0;
+}
+
+igraph_bool_t check_same(const igraph_sparsemat_t *A, 
+			 const igraph_matrix_t *M) {
+  
+  long int nrow=igraph_sparsemat_nrow(A);
+  long int ncol=igraph_sparsemat_ncol(A);
+  long int j, p, nzero=0;
+  
+  if (nrow != igraph_matrix_nrow(M) ||
+      ncol != igraph_matrix_ncol(M)) { 
+    return 0; 
+  }
+  
+  for (j=0; j<A->cs->n; j++) {
+    for (p=A->cs->p[j]; p < A->cs->p[j+1]; p++) {
+      long int to=A->cs->i[p];
+      igraph_real_t value=A->cs->x[p];
+      if (value != MATRIX(*M, to, j)) { return 0; }
+      nzero += 1;
+    }
+  }
+
+  for (j=0; j<nrow; j++) {
+    for (p=0; p<ncol; p++) {
+      if (MATRIX(*M, j, p) != 0) { nzero -= 1; }
+    }
+  }
+
+  return nzero == 0;
+}
+
+int main() {
+
+  igraph_sparsemat_t A, B;
+  igraph_matrix_t M, N;
+  igraph_vector_int_t p, q;
+  long int i;
+
+  /* Permutation of a matrix */
+
+#define NROW 10
+#define NCOL 5
+#define EDGES NROW*NCOL/3
+  igraph_matrix_init(&M, NROW, NCOL);
+  igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, NROW-1);
+    long int c=RNG_INTEGER(0, NCOL-1);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    MATRIX(M, r, c) = MATRIX(M, r, c) + value;
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+
+  igraph_vector_int_init_seq(&p, 0, NROW-1);
+  igraph_vector_int_init_seq(&q, 0, NCOL-1);
+
+  /* Identity */
+
+  igraph_matrix_init(&N, 0, 0);
+  permute(&M, &p, &q, &N);
+
+  igraph_sparsemat_permute(&B, &p, &q, &A);
+  igraph_sparsemat_dupl(&A);
+  
+  if (! check_same(&A, &N)) { return 1; }
+
+  /* Random permutation */
+  random_permutation(&p);
+  random_permutation(&q);
+
+  permute(&M, &p, &q, &N);
+
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_permute(&B, &p, &q, &A);
+  igraph_sparsemat_dupl(&A);
+  
+  if (! check_same(&A, &N)) { return 2; }
+  
+  igraph_vector_int_destroy(&p);
+  igraph_vector_int_destroy(&q);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);
+  igraph_matrix_destroy(&M);
+  igraph_matrix_destroy(&N);
+
+#undef NROW
+#undef NCOL
+#undef EDGES
+
+  /* Indexing */
+
+#define NROW 10
+#define NCOL 5
+#define EDGES NROW*NCOL/3
+#define I_NROW 6
+#define I_NCOL 3
+  igraph_matrix_init(&M, NROW, NCOL);
+  igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, NROW-1);
+    long int c=RNG_INTEGER(0, NCOL-1);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    MATRIX(M, r, c) = MATRIX(M, r, c) + value;
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+
+  igraph_vector_int_init(&p, I_NROW);
+  igraph_vector_int_init(&q, I_NCOL);
+  
+  for (i=0; i<I_NROW; i++) {
+    VECTOR(p)[i] = RNG_INTEGER(0, I_NROW-1);
+  }
+  for (i=0; i<I_NCOL; i++) {
+    VECTOR(p)[i] = RNG_INTEGER(0, I_NCOL-1);
+  }
+  
+  igraph_matrix_init(&N, 0, 0);
+  permute(&M, &p, &q, &N);
+  
+  igraph_sparsemat_index(&B, &p, &q, &A, 0);
+  
+  if (! check_same(&A, &N)) { return 3; }
+  
+  /* A single element */
+  
+  igraph_vector_int_resize(&p, 1);
+  igraph_vector_int_resize(&q, 1);
+  
+  for (i=0; i<100; i++) {
+    igraph_real_t value;
+    VECTOR(p)[0] = RNG_INTEGER(0, NROW-1);
+    VECTOR(q)[0] = RNG_INTEGER(0, NCOL-1);
+    igraph_sparsemat_index(&B, &p, &q, /*res=*/ 0, &value);
+    if (value != MATRIX(M, VECTOR(p)[0], VECTOR(q)[0])) { 
+      return 4; 
+    }
+  }
+
+  igraph_sparsemat_destroy(&A);
+
+  for (i=0; i<100; i++) {
+    igraph_real_t value;
+    VECTOR(p)[0] = RNG_INTEGER(0, NROW-1);
+    VECTOR(q)[0] = RNG_INTEGER(0, NCOL-1);
+    igraph_sparsemat_index(&B, &p, &q, /*res=*/ &A, &value);
+    igraph_sparsemat_destroy(&A);
+    if (value != MATRIX(M, VECTOR(p)[0], VECTOR(q)[0])) { 
+      return 4; 
+    }
+  }
+
+  igraph_vector_int_destroy(&p);
+  igraph_vector_int_destroy(&q);
+  igraph_sparsemat_destroy(&B);
+  igraph_matrix_destroy(&M);
+  igraph_matrix_destroy(&N);
+
+  /* Indexing only the rows or the columns */
+  
+  igraph_matrix_init(&M, NROW, NCOL);
+  igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, NROW-1);
+    long int c=RNG_INTEGER(0, NCOL-1);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    MATRIX(M, r, c) = MATRIX(M, r, c) + value;
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  
+  igraph_vector_int_init(&p, I_NROW);
+  igraph_vector_int_init(&q, I_NCOL);
+  
+  for (i=0; i<I_NROW; i++) {
+    VECTOR(p)[i] = RNG_INTEGER(0, I_NROW-1);
+  }
+  for (i=0; i<I_NCOL; i++) {
+    VECTOR(p)[i] = RNG_INTEGER(0, I_NCOL-1);
+  }
+  
+  igraph_matrix_init(&N, 0, 0);
+  permute_rows(&M, &p, &N);
+  
+  igraph_sparsemat_index(&B, &p, 0, &A, 0);
+
+  if (! check_same(&A, &N)) { return 5; }
+  
+  permute_cols(&M, &q, &N);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_index(&B, 0, &q, &A, 0);
+  
+  if (! check_same(&A, &N)) { return 6; }
+  
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);
+  igraph_vector_int_destroy(&p);
+  igraph_vector_int_destroy(&q);
+  igraph_matrix_destroy(&M);
+  igraph_matrix_destroy(&N);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat3.out b/examples/simple/igraph_sparsemat3.out
new file mode 100644
index 0000000..e69de29
diff --git a/examples/simple/igraph_sparsemat4.c b/examples/simple/igraph_sparsemat4.c
new file mode 100644
index 0000000..4d85bde
--- /dev/null
+++ b/examples/simple/igraph_sparsemat4.c
@@ -0,0 +1,287 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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 <cs/cs.h>
+#include <igraph.h>
+#include <igraph_sparsemat.h>
+
+igraph_bool_t check_solution(const igraph_sparsemat_t *A,
+			     const igraph_vector_t *x,
+			     const igraph_vector_t *b) {
+
+  long int dim=igraph_vector_size(x);
+  igraph_vector_t res;
+  int j, p;
+  igraph_real_t min, max;
+
+  igraph_vector_copy(&res, b);
+  
+  for (j=0; j<dim; j++) {
+    for (p=A->cs->p[j]; p < A->cs->p[j+1]; p++) {
+      long int from=A->cs->i[p];
+      igraph_real_t value=A->cs->x[p];
+      VECTOR(res)[from] -= VECTOR(*x)[j] * value;
+    }
+  }
+  
+  igraph_vector_minmax(&res, &min, &max);
+  igraph_vector_destroy(&res);
+
+  return abs(min) < 1e-15 && abs(max) < 1e-15;
+}
+
+int main() {
+
+  igraph_sparsemat_t A, B, C;
+  igraph_vector_t b, x;
+  long int i;
+
+  /* lsolve */
+
+#define DIM 10
+#define EDGES (DIM*DIM/6)
+  igraph_sparsemat_init(&A, DIM, DIM, EDGES+DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1,3));
+  }
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, DIM-1);
+    long int c=RNG_INTEGER(0, r);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_dupl(&B);
+  
+  igraph_vector_init(&b, DIM);
+  for (i=0; i<DIM; i++) {    
+    VECTOR(b)[i] = RNG_INTEGER(1,10);
+  }
+
+  igraph_vector_init(&x, DIM);
+  igraph_sparsemat_lsolve(&B, &b, &x);
+
+  if (! check_solution(&B, &x, &b)) { return 1; }
+
+  igraph_vector_destroy(&b);
+  igraph_vector_destroy(&x);
+  igraph_sparsemat_destroy(&B);
+
+#undef DIM
+#undef EDGES
+
+  /* ltsolve */
+
+#define DIM 10
+#define EDGES (DIM*DIM/6)
+  igraph_sparsemat_init(&A, DIM, DIM, EDGES+DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1,3));
+  }
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, DIM-1);
+    long int c=RNG_INTEGER(0, r);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_dupl(&B);
+  
+  igraph_vector_init(&b, DIM);
+  for (i=0; i<DIM; i++) {    
+    VECTOR(b)[i] = RNG_INTEGER(1,10);
+  }
+
+  igraph_vector_init(&x, DIM);
+  igraph_sparsemat_ltsolve(&B, &b, &x);
+
+  igraph_sparsemat_transpose(&B, &A, /*values=*/ 1);
+  if (! check_solution(&A, &x, &b)) { return 2; }
+
+  igraph_vector_destroy(&b);
+  igraph_vector_destroy(&x);
+  igraph_sparsemat_destroy(&B);
+  igraph_sparsemat_destroy(&A);
+
+#undef DIM
+#undef EDGES
+
+  /* usolve */
+
+#define DIM 10
+#define EDGES (DIM*DIM/6)
+  igraph_sparsemat_init(&A, DIM, DIM, EDGES+DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1,3));
+  }
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, DIM-1);
+    long int c=RNG_INTEGER(0, r);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_dupl(&B);
+  igraph_sparsemat_transpose(&B, &A, /*values=*/ 1);
+  
+  igraph_vector_init(&b, DIM);
+  for (i=0; i<DIM; i++) {    
+    VECTOR(b)[i] = RNG_INTEGER(1,10);
+  }
+
+  igraph_vector_init(&x, DIM);
+  igraph_sparsemat_usolve(&A, &b, &x);
+
+  if (! check_solution(&A, &x, &b)) { return 3; }
+
+  igraph_vector_destroy(&b);
+  igraph_vector_destroy(&x);
+  igraph_sparsemat_destroy(&B);
+  igraph_sparsemat_destroy(&A);
+
+#undef DIM
+#undef EDGES  
+
+  /* utsolve */
+
+#define DIM 10
+#define EDGES (DIM*DIM/6)
+  igraph_sparsemat_init(&A, DIM, DIM, EDGES+DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1,3));
+  }
+  for (i=0; i<EDGES; i++) {
+    long int r=RNG_INTEGER(0, DIM-1);
+    long int c=RNG_INTEGER(0, r);
+    igraph_real_t value=RNG_INTEGER(1,5);
+    igraph_sparsemat_entry(&A, r, c, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_dupl(&B);
+  igraph_sparsemat_transpose(&B, &A, /*values=*/ 1);
+  igraph_sparsemat_destroy(&B);
+  
+  igraph_vector_init(&b, DIM);
+  for (i=0; i<DIM; i++) {    
+    VECTOR(b)[i] = RNG_INTEGER(1,10);
+  }
+
+  igraph_vector_init(&x, DIM);
+  igraph_sparsemat_utsolve(&A, &b, &x);
+
+  igraph_sparsemat_transpose(&A, &B, /*values=*/ 1);
+  if (! check_solution(&B, &x, &b)) { return 4; }
+
+  igraph_vector_destroy(&b);
+  igraph_vector_destroy(&x);
+  igraph_sparsemat_destroy(&B);
+  igraph_sparsemat_destroy(&A);
+
+#undef DIM
+#undef EDGES  
+
+  /* cholsol */
+  /* We need a positive definite matrix, so we create a full-rank
+     matrix first and then calculate A'A, which will be positive
+     definite. */
+
+#define DIM 10
+#define EDGES (DIM*DIM/6)
+  igraph_sparsemat_init(&A, DIM, DIM, EDGES+DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1,3));
+  }
+  for (i=0; i<EDGES; i++) {
+    long int from=RNG_INTEGER(0, DIM-1);
+    long int to=RNG_INTEGER(0, DIM-1);
+    igraph_real_t value=RNG_INTEGER(1, 5);
+    igraph_sparsemat_entry(&A, from, to, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_dupl(&B);
+  igraph_sparsemat_transpose(&B, &A, /*values=*/ 1);
+  igraph_sparsemat_multiply(&A, &B, &C);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_destroy(&B);
+  
+  igraph_vector_init(&b, DIM);
+  for (i=0; i<DIM; i++) {
+    VECTOR(b)[i] = RNG_INTEGER(1,10);
+  }
+
+  igraph_vector_init(&x, DIM);
+  igraph_sparsemat_cholsol(&C, &b, &x, /*order=*/ 0);
+  
+  if (! check_solution(&C, &x, &b)) { return 5; }
+
+  igraph_vector_destroy(&b);
+  igraph_vector_destroy(&x);
+  igraph_sparsemat_destroy(&C);
+
+#undef DIM
+#undef EDGES
+
+  /* lusol */
+
+#define DIM 10
+#define EDGES (DIM*DIM/4)
+  igraph_sparsemat_init(&A, DIM, DIM, EDGES+DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1,3));
+  }
+  for (i=0; i<EDGES; i++) {
+    long int from=RNG_INTEGER(0, DIM-1);
+    long int to=RNG_INTEGER(0, DIM-1);
+    igraph_real_t value=RNG_INTEGER(1, 5);
+    igraph_sparsemat_entry(&A, from, to, value);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  igraph_sparsemat_dupl(&B);
+
+  igraph_vector_init(&b, DIM);
+  for (i=0; i<DIM; i++) {
+    VECTOR(b)[i] = RNG_INTEGER(1,10);
+  }
+
+  igraph_vector_init(&x, DIM);
+  igraph_sparsemat_lusol(&B, &b, &x, /*order=*/ 0, /*tol=*/ 1e-10);
+  
+  if (! check_solution(&B, &x, &b)) { return 6; }
+
+  igraph_vector_destroy(&b);
+  igraph_vector_destroy(&x);
+  igraph_sparsemat_destroy(&B);
+
+#undef DIM
+#undef EDGES
+
+  return 0;
+}
+
+
diff --git a/examples/simple/igraph_sparsemat4.out b/examples/simple/igraph_sparsemat4.out
new file mode 100644
index 0000000..e69de29
diff --git a/examples/simple/igraph_sparsemat5.c b/examples/simple/igraph_sparsemat5.c
new file mode 100644
index 0000000..00ff26b
--- /dev/null
+++ b/examples/simple/igraph_sparsemat5.c
@@ -0,0 +1,351 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_sparsemat.h>
+
+#define EPS 1e-13
+
+
+/* Generic test for 1x1 matrices */
+void test_1x1(igraph_real_t value) {
+  igraph_sparsemat_t A, B;
+  igraph_matrix_t values, vectors;
+  igraph_vector_t values2;
+  igraph_arpack_options_t options;
+
+  igraph_arpack_options_init(&options);
+
+  igraph_sparsemat_init(&A, 1, 1, 1);
+  igraph_sparsemat_entry(&A, 0, 0, value);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+
+  igraph_matrix_init(&values, 0, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+  options.mode=1;  
+  igraph_sparsemat_arpack_rnsolve(&B, &options, /*storage=*/ 0,
+				  &values, &vectors);
+  printf("rnsolve:\n  - eigenvalues:\n    "); igraph_matrix_print(&values);
+  printf("  - eigenvectors:\n    "); igraph_matrix_print(&vectors);
+  igraph_matrix_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+
+  igraph_vector_init(&values2, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+  options.mode=1;  
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values2, &vectors, IGRAPH_SPARSEMAT_SOLVE_LU);
+  printf("rssolve:\n  - eigenvalues:\n    "); igraph_vector_print(&values2);
+  printf("  - eigenvectors:\n    "); igraph_matrix_print(&vectors);
+  igraph_vector_destroy(&values2);
+  igraph_matrix_destroy(&vectors);
+
+  igraph_sparsemat_destroy(&B);
+}
+
+/* Generic test for 2x2 matrices */
+void test_2x2(igraph_real_t a, igraph_real_t b, igraph_real_t c, igraph_real_t d) {
+  igraph_sparsemat_t A, B;
+  igraph_matrix_t values, vectors;
+  igraph_vector_t values2;
+  igraph_arpack_options_t options;
+
+  igraph_arpack_options_init(&options);
+  options.mode=1; options.nev=2;
+
+  igraph_sparsemat_init(&A, 2, 2, 4);
+  igraph_sparsemat_entry(&A, 0, 0, a);
+  igraph_sparsemat_entry(&A, 0, 1, b);
+  igraph_sparsemat_entry(&A, 1, 0, c);
+  igraph_sparsemat_entry(&A, 1, 1, d);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+
+  igraph_matrix_init(&values, 0, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+  igraph_sparsemat_arpack_rnsolve(&B, &options, /*storage=*/ 0,
+				  &values, &vectors);
+  printf("rnsolve:\n  - eigenvalues:\n    "); igraph_matrix_print(&values);
+  printf("  - eigenvectors:\n    "); igraph_matrix_print(&vectors);
+  igraph_matrix_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+
+  if (b == c) {
+    igraph_vector_init(&values2, 0);
+    igraph_matrix_init(&vectors, 0, 0);
+    igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+            &values2, &vectors, IGRAPH_SPARSEMAT_SOLVE_QR);
+    printf("rssolve:\n  - eigenvalues:\n    "); igraph_vector_print(&values2);
+    printf("  - eigenvectors:\n    "); igraph_matrix_print(&vectors);
+    igraph_vector_destroy(&values2);
+    igraph_matrix_destroy(&vectors);
+  }
+
+  igraph_sparsemat_destroy(&B);
+}
+
+int main() {
+
+  igraph_sparsemat_t A, B;
+  igraph_matrix_t vectors, values2;
+  igraph_vector_t values;
+  long int i;
+  igraph_arpack_options_t options;
+  igraph_real_t min, max;
+  igraph_t g1, g2, g3;
+
+  /***********************************************************************/
+
+  /* Identity matrix */
+#define DIM 10
+  igraph_sparsemat_init(&A, DIM, DIM, DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, 1.0);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+
+  igraph_vector_init(&values, 0);
+  igraph_arpack_options_init(&options);
+
+  options.mode=1;
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0, 
+				  &values, /*vectors=*/ 0, /*solvemethod=*/0);
+  if (VECTOR(values)[0] != 1.0) { return 1; }
+
+  options.mode=3;
+  options.sigma=2;
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0, 
+				  &values, /*vectors=*/ 0,
+				  IGRAPH_SPARSEMAT_SOLVE_LU);
+  if (VECTOR(values)[0] != 1.0) { return 21; }
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0, 
+				  &values, /*vectors=*/ 0,
+				  IGRAPH_SPARSEMAT_SOLVE_QR);
+  if (VECTOR(values)[0] != 1.0) { return 31; }
+
+  igraph_vector_destroy(&values);
+  igraph_sparsemat_destroy(&B);  
+
+#undef DIM
+
+  /***********************************************************************/
+
+  /* Diagonal matrix */
+#define DIM 10
+  igraph_sparsemat_init(&A, DIM, DIM, DIM);
+  for (i=0; i<DIM; i++) {
+    igraph_sparsemat_entry(&A, i, i, i+1.0);
+  }
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  
+  igraph_vector_init(&values, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+  
+  options.mode=1;
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values, /*vectors=*/ &vectors, 
+				  /*solvemethod=*/ 0);
+  if ( fabs(VECTOR(values)[0] - DIM) > EPS ) {
+    printf("VECTOR(values)[0] numerical precision is only %g, should be %g",
+			fabs((double)VECTOR(values)[0]-DIM), EPS);
+	return 2;
+  }
+
+  if ( fabs(fabs(MATRIX(vectors, DIM-1, 0)) - 1.0) > EPS) { return 3; }
+  MATRIX(vectors, DIM-1, 0) = 0.0;
+  igraph_matrix_minmax(&vectors, &min, &max);
+  if (fabs(min) > EPS) { return 3; }
+  if (fabs(max) > EPS) { return 3; }
+
+  options.mode=3;
+  options.sigma=11;
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values, /*vectors=*/ &vectors,
+				  IGRAPH_SPARSEMAT_SOLVE_LU);
+  if ( fabs(VECTOR(values)[0] - DIM) > EPS ) {
+    printf("VECTOR(values)[0] numerical precision is only %g, should be %g",
+			fabs((double)VECTOR(values)[0]-DIM), EPS);
+	return 22;
+  }
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values, /*vectors=*/ &vectors,
+				  IGRAPH_SPARSEMAT_SOLVE_QR);
+  if ( fabs(VECTOR(values)[0] - DIM) > EPS ) {
+    printf("VECTOR(values)[0] numerical precision is only %g, should be %g",
+			fabs((double)VECTOR(values)[0]-DIM), EPS);
+    return 32;
+  }
+
+  if ( fabs(fabs(MATRIX(vectors, DIM-1, 0)) - 1.0) > EPS) { return 23; }
+  MATRIX(vectors, DIM-1, 0) = 0.0;
+  igraph_matrix_minmax(&vectors, &min, &max);
+  if (fabs(min) > EPS) { return 23; }
+  if (fabs(max) > EPS) { return 23; }
+  
+  igraph_vector_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+  igraph_sparsemat_destroy(&B);
+#undef DIM
+
+  /***********************************************************************/
+
+  /* A tree, plus a ring */
+#define DIM 10
+  igraph_tree(&g1, DIM, /*children=*/ 2, IGRAPH_TREE_UNDIRECTED);
+  igraph_ring(&g2, DIM, IGRAPH_UNDIRECTED, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_union(&g3, &g1, &g2, /*edge_map1=*/ 0, /*edge_map1=*/ 0);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  igraph_get_sparsemat(&g3, &A);
+  igraph_destroy(&g3);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  
+  igraph_vector_init(&values, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+  
+  options.mode=1;
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values, &vectors, /*solvemethod=*/ 0);
+
+  if (MATRIX(vectors, 0, 0) < 0.0) { 
+    igraph_matrix_scale(&vectors, -1.0);
+  }
+  
+  igraph_vector_print(&values);
+  igraph_matrix_print(&vectors);
+
+  options.mode=3;
+  options.sigma=VECTOR(values)[0] * 1.1;
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values, &vectors, 
+				  IGRAPH_SPARSEMAT_SOLVE_LU);
+
+  if (MATRIX(vectors, 0, 0) < 0.0) { 
+    igraph_matrix_scale(&vectors, -1.0);
+  }  
+  igraph_vector_print(&values);
+  igraph_matrix_print(&vectors);
+
+  igraph_sparsemat_arpack_rssolve(&B, &options, /*storage=*/ 0,
+				  &values, &vectors, 
+				  IGRAPH_SPARSEMAT_SOLVE_QR);
+  if (MATRIX(vectors, 0, 0) < 0.0) { 
+    igraph_matrix_scale(&vectors, -1.0);
+  }  
+  igraph_vector_print(&values);
+  igraph_matrix_print(&vectors);
+  
+  igraph_vector_destroy(&values);
+  igraph_matrix_destroy(&vectors);
+  igraph_sparsemat_destroy(&B);
+#undef DIM
+
+  printf("--\n");
+
+  /***********************************************************************/
+
+  /* A directed tree and a directed, mutual ring */
+#define DIM 10
+  igraph_tree(&g1, DIM, /*children=*/ 2, IGRAPH_TREE_OUT);
+  igraph_ring(&g2, DIM, IGRAPH_DIRECTED, /*mutual=*/ 1, /*circular=*/ 1);
+  igraph_union(&g3, &g1, &g2, /*edge_map1=*/ 0, /*edge_map2=*/ 0);
+  igraph_destroy(&g1);
+  igraph_destroy(&g2);
+
+  igraph_get_sparsemat(&g3, &A);
+  igraph_destroy(&g3);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  
+  igraph_matrix_init(&values2, 0, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+  
+  options.mode=1;
+  igraph_sparsemat_arpack_rnsolve(&B, &options, /*storage=*/ 0,
+				  &values2, &vectors);
+
+  if (MATRIX(vectors, 0, 0) < 0.0) { 
+    igraph_matrix_scale(&vectors, -1.0);
+  }
+  
+  igraph_matrix_print(&values2);
+  igraph_matrix_print(&vectors);
+  
+  igraph_matrix_destroy(&values2);
+  igraph_matrix_destroy(&vectors);
+  igraph_sparsemat_destroy(&B);
+#undef DIM
+
+  /***********************************************************************/
+
+  /* A small test graph */
+
+  igraph_small(&g1, 11, IGRAPH_DIRECTED,
+	       0, 1, 1, 3, 1, 8, 2, 10, 3, 6, 3, 10, 4, 2, 5, 4, 
+	       6, 1, 6, 4, 7, 9, 8, 5, 8, 7, 9, 8, 10, 0,
+	       -1);
+
+  igraph_get_sparsemat(&g1, &A);
+  igraph_destroy(&g1);
+  igraph_sparsemat_compress(&A, &B);
+  igraph_sparsemat_destroy(&A);
+  
+  igraph_matrix_init(&values2, 0, 0);
+  igraph_matrix_init(&vectors, 0, 0);
+
+  options.mode=1;  
+  igraph_sparsemat_arpack_rnsolve(&B, &options, /*storage=*/ 0,
+				  &values2, &vectors);
+
+  if (MATRIX(vectors, 0, 0) < 0.0) { 
+    igraph_matrix_scale(&vectors, -1.0);
+  }
+  
+  igraph_matrix_destroy(&values2);
+  igraph_matrix_destroy(&vectors);
+  igraph_sparsemat_destroy(&B);
+
+  /***********************************************************************/
+
+  /* Testing the special case solver for 1x1 matrices */
+  printf("--\n");
+  test_1x1(2);
+  test_1x1(0);
+  test_1x1(-3);
+
+  /***********************************************************************/
+
+  /* Testing the special case solver for 2x2 matrices */
+  printf("--\n");
+  test_2x2(1, 2, 2, 4);      /* symmetric */
+  test_2x2(1, 2, 3, 4);      /* non-symmetric, real eigenvalues */
+  test_2x2(1, -5, 10, 4);    /* non-symmetric, complex eigenvalues */
+  test_2x2(0, 0, 0, 0);      /* symmetric, pathological */
+
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat5.out b/examples/simple/igraph_sparsemat5.out
new file mode 100644
index 0000000..af98eaa
--- /dev/null
+++ b/examples/simple/igraph_sparsemat5.out
@@ -0,0 +1,117 @@
+3.79369
+0.272513
+0.387127
+0.421856
+0.429479
+0.344793
+0.266584
+0.24469
+0.239837
+0.235697
+0.224848
+3.79369
+0.272513
+0.387127
+0.421856
+0.429479
+0.344793
+0.266584
+0.24469
+0.239837
+0.235697
+0.224848
+3.79369
+0.272513
+0.387127
+0.421856
+0.429479
+0.344793
+0.266584
+0.24469
+0.239837
+0.235697
+0.224848
+--
+2.61264 0
+0.467245
+0.571573
+0.427081
+0.335532
+0.263456
+0.130696
+0.0780048
+0.0731022
+0.112985
+0.222086
+--
+rnsolve:
+  - eigenvalues:
+    2 0
+  - eigenvectors:
+    1
+rssolve:
+  - eigenvalues:
+    2
+  - eigenvectors:
+    1
+rnsolve:
+  - eigenvalues:
+    0 0
+  - eigenvectors:
+    1
+rssolve:
+  - eigenvalues:
+    0
+  - eigenvectors:
+    1
+rnsolve:
+  - eigenvalues:
+    -3 0
+  - eigenvectors:
+    1
+rssolve:
+  - eigenvalues:
+    -3
+  - eigenvectors:
+    1
+--
+rnsolve:
+  - eigenvalues:
+    5 0
+0 0
+  - eigenvectors:
+    1 -4
+2 2
+rssolve:
+  - eigenvalues:
+    5 0
+  - eigenvectors:
+    1 -4
+2 2
+rnsolve:
+  - eigenvalues:
+    5.37228 0
+-0.372281 0
+  - eigenvectors:
+    1.37228 -4.37228
+3 3
+rnsolve:
+  - eigenvalues:
+    2.5 6.91014
+2.5 -6.91014
+  - eigenvectors:
+    -1.5 6.91014
+10 0
+rnsolve:
+  - eigenvalues:
+    0 0
+0 0
+  - eigenvectors:
+    1 0
+0 1
+rssolve:
+  - eigenvalues:
+    0 0
+  - eigenvectors:
+    1 0
+0 1
diff --git a/examples/simple/igraph_sparsemat6.c b/examples/simple/igraph_sparsemat6.c
new file mode 100644
index 0000000..0cd2627
--- /dev/null
+++ b/examples/simple/igraph_sparsemat6.c
@@ -0,0 +1,63 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_sparsemat.h>
+
+int main() {
+  igraph_matrix_t mat, mat2, mat3;
+  igraph_sparsemat_t spmat, spmat2;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+#define NROW 10
+#define NCOL 7  
+#define NZERO 15
+
+  igraph_matrix_init(&mat, NROW, NCOL);
+  for (i=0; i<NZERO; i++) {
+    int r=igraph_rng_get_integer(igraph_rng_default(), 0, NROW-1);
+    int c=igraph_rng_get_integer(igraph_rng_default(), 0, NCOL-1);
+    igraph_real_t val=igraph_rng_get_integer(igraph_rng_default(), 1, 10);
+    MATRIX(mat, r, c) = val;
+  }
+  
+  igraph_matrix_as_sparsemat(&spmat, &mat, /*tol=*/ 1e-14);
+  igraph_matrix_init(&mat2, 0, 0);
+  igraph_sparsemat_as_matrix(&mat2, &spmat);
+  if (!igraph_matrix_all_e(&mat, &mat2)) { return 1; }
+  
+  igraph_sparsemat_compress(&spmat, &spmat2);
+  igraph_matrix_init(&mat3, 0, 0);
+  igraph_sparsemat_as_matrix(&mat3, &spmat2);
+  if (!igraph_matrix_all_e(&mat, &mat3)) { return 2; }
+  
+  igraph_matrix_destroy(&mat);
+  igraph_matrix_destroy(&mat2);
+  igraph_matrix_destroy(&mat3);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat7.c b/examples/simple/igraph_sparsemat7.c
new file mode 100644
index 0000000..ff4cabe
--- /dev/null
+++ b/examples/simple/igraph_sparsemat7.c
@@ -0,0 +1,77 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define DIM1 10
+#define DIM2 5
+
+#define INT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))
+
+int main() {
+  igraph_matrix_t mat;
+  igraph_sparsemat_t spmat, spmat2;
+  int i;
+  igraph_real_t m1, m2;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
+  igraph_sparsemat_entry(&spmat, 1, 2, -1.0);
+  igraph_sparsemat_entry(&spmat, 3, 2, 10.0);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&spmat, INT(DIM1-1), INT(DIM2-1), 1.0);
+  } 
+  igraph_sparsemat_entry(&spmat, 1, 2, -1.0);
+  igraph_sparsemat_entry(&spmat, 3, 2, 10.0);
+  
+  igraph_sparsemat_compress(&spmat, &spmat2);
+  igraph_matrix_init(&mat, 0, 0);
+  igraph_sparsemat_as_matrix(&mat, &spmat2);
+  m1=igraph_sparsemat_min(&spmat2);
+  m2=igraph_matrix_min(&mat);
+  if (m1 != m2) {
+    printf("%f %f\n", m1, m2);
+    return 1; 
+  }
+  m1=igraph_sparsemat_max(&spmat2);
+  m2=igraph_matrix_max(&mat);
+  if (m1 != m2) {
+    printf("%f %f\n", m1, m2);
+    return 2;
+  }
+
+  igraph_sparsemat_minmax(&spmat2, &m1, &m2);
+  if (m1 != igraph_matrix_min(&mat)) { return 3; }
+  if (m2 != igraph_matrix_max(&mat)) { return 4; }
+
+  igraph_matrix_destroy(&mat);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+  
+  return 0;
+}
+  
+  
+  
+
diff --git a/examples/simple/igraph_sparsemat8.c b/examples/simple/igraph_sparsemat8.c
new file mode 100644
index 0000000..c8f43e3
--- /dev/null
+++ b/examples/simple/igraph_sparsemat8.c
@@ -0,0 +1,183 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define DIM1 10
+#define DIM2 5
+
+#define INT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))
+
+int main() {
+  igraph_matrix_t mat, mat2;
+  igraph_sparsemat_t spmat, spmat2;
+  int i, j, nz1, nz2;
+  igraph_vector_t sums1, sums2;
+  
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  /* COPY */
+
+  igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&spmat, INT(DIM1-1), INT(DIM2-1), 1.0);
+  }
+  igraph_sparsemat_copy(&spmat2, &spmat);
+  
+  igraph_matrix_init(&mat, 0, 0);
+  igraph_sparsemat_as_matrix(&mat, &spmat);
+  igraph_matrix_init(&mat2, 0, 0);
+  igraph_sparsemat_as_matrix(&mat2, &spmat2);
+  if (!igraph_matrix_all_e(&mat, &mat2)) { return 1;}
+  
+  igraph_matrix_destroy(&mat2);
+  igraph_sparsemat_destroy(&spmat2);
+  
+  igraph_sparsemat_compress(&spmat, &spmat2);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_copy(&spmat, &spmat2);
+  
+  igraph_matrix_init(&mat2, 0, 0);
+  igraph_sparsemat_as_matrix(&mat2, &spmat);
+  if (!igraph_matrix_all_e(&mat, &mat2)) { return 2; }
+
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+  igraph_matrix_destroy(&mat);
+  igraph_matrix_destroy(&mat2);
+
+  /* COLSUMS, ROWSUMS */
+  
+  igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&spmat, INT(DIM1-1), INT(DIM2-1), 1.0);
+  }
+  igraph_sparsemat_compress(&spmat, &spmat2);
+
+  igraph_matrix_init(&mat, 0, 0);
+  igraph_sparsemat_as_matrix(&mat, &spmat);
+  igraph_vector_init(&sums1, 0);
+  igraph_vector_init(&sums2, 0);
+  igraph_sparsemat_colsums(&spmat, &sums1);
+  igraph_matrix_colsum(&mat, &sums2);
+  if (!igraph_vector_all_e(&sums1, &sums2)) { return 3; }
+  igraph_sparsemat_colsums(&spmat2, &sums1);
+  if (!igraph_vector_all_e(&sums1, &sums2)) { return 4; }
+  
+  igraph_sparsemat_rowsums(&spmat, &sums1);
+  igraph_matrix_rowsum(&mat, &sums2);
+  if (!igraph_vector_all_e(&sums1, &sums2)) { return 5; }
+  igraph_sparsemat_rowsums(&spmat2, &sums1);
+  if (!igraph_vector_all_e(&sums1, &sums2)) { return 6; }
+  
+  igraph_matrix_destroy(&mat);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+  igraph_vector_destroy(&sums1);
+  igraph_vector_destroy(&sums2);
+
+  /* COUNT_NONZERO, COUNT_NONZEROTOL */
+  
+  igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
+  igraph_sparsemat_entry(&spmat, 1, 2, 1.0);
+  igraph_sparsemat_entry(&spmat, 1, 2, 1.0);
+  igraph_sparsemat_entry(&spmat, 1, 3, 1e-12);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&spmat, INT(DIM1-1), INT(DIM2-1), 1.0);
+  }
+  igraph_sparsemat_compress(&spmat, &spmat2);
+
+  igraph_matrix_init(&mat, 0, 0);
+  igraph_sparsemat_as_matrix(&mat, &spmat2);
+
+  nz1=igraph_sparsemat_count_nonzero(&spmat2);
+  for (nz2=0, i=0; i<igraph_matrix_nrow(&mat); i++) {
+    for (j=0; j<igraph_matrix_ncol(&mat); j++) {
+      if (MATRIX(mat, i, j) != 0) { nz2++; }
+    }
+  }
+  if (nz1 != nz2) { printf("%i %i\n", nz1, nz2); return 7; }
+  
+  nz1=igraph_sparsemat_count_nonzerotol(&spmat2, 1e-10);
+  for (nz2=0, i=0; i<igraph_matrix_nrow(&mat); i++) {
+    for (j=0; j<igraph_matrix_ncol(&mat); j++) {
+      if (fabs(MATRIX(mat, i, j)) >= 1e-10) { nz2++; }
+    }
+  }
+  if (nz1 != nz2) { printf("%i %i\n", nz1, nz2); return 8; }
+  
+  igraph_matrix_destroy(&mat);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+
+  /* SCALE */
+
+  igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&spmat, INT(DIM1-1), INT(DIM2-1), 1.0);
+  }
+  igraph_sparsemat_compress(&spmat, &spmat2);
+
+  igraph_sparsemat_scale(&spmat, 2.0);
+  igraph_sparsemat_scale(&spmat2, 2.0);
+  igraph_matrix_init(&mat, 0, 0);
+  igraph_sparsemat_as_matrix(&mat, &spmat);
+  igraph_matrix_init(&mat2, 0, 0);
+  igraph_sparsemat_as_matrix(&mat2, &spmat2);
+  igraph_matrix_scale(&mat, 1.0/2.0);
+  igraph_matrix_scale(&mat2, 1.0/2.0);
+  if (!igraph_matrix_all_e(&mat, &mat2)) { return 9; }
+
+  igraph_matrix_destroy(&mat);
+  igraph_matrix_destroy(&mat2);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+
+  /* ADDROWS, ADDCOLS */
+
+  igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&spmat, INT(DIM1-1), INT(DIM2-1), 1.0);
+  }
+  igraph_sparsemat_compress(&spmat, &spmat2);
+  
+  igraph_sparsemat_add_rows(&spmat, 3); 
+  igraph_sparsemat_add_cols(&spmat, 2);
+  
+  igraph_sparsemat_add_rows(&spmat2, 3);
+  igraph_sparsemat_add_cols(&spmat2, 2);
+  
+  igraph_matrix_init(&mat, 0, 0);
+  igraph_sparsemat_as_matrix(&mat, &spmat);
+  igraph_matrix_init(&mat2, 0, 0);
+  igraph_sparsemat_as_matrix(&mat2, &spmat2);
+  if (!igraph_matrix_all_e(&mat, &mat2)) { return 10; }
+
+  igraph_matrix_destroy(&mat);
+  igraph_matrix_destroy(&mat2);
+  igraph_sparsemat_destroy(&spmat);
+  igraph_sparsemat_destroy(&spmat2);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat9.c b/examples/simple/igraph_sparsemat9.c
new file mode 100644
index 0000000..ad9f3e7
--- /dev/null
+++ b/examples/simple/igraph_sparsemat9.c
@@ -0,0 +1,84 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+
+#define DIM1 10
+#define DIM2 5
+#define DIM3 6
+
+#define INT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))
+#define REAL() (igraph_rng_get_normal(igraph_rng_default(), 0, 1))
+
+int main() {
+  igraph_sparsemat_t sA, sB, sC;
+  igraph_matrix_t A1, A2, A3, B, C;
+  int i;
+  
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  igraph_sparsemat_init(&sA, DIM1, DIM2, 20);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&sA, INT(DIM1-1), INT(DIM2-1), REAL());
+  }
+  igraph_sparsemat_compress(&sA, &sB);
+  igraph_sparsemat_destroy(&sA);
+
+  igraph_sparsemat_init(&sA, DIM2, DIM3, 20);
+  for (i=0; i<10; i++) {
+    igraph_sparsemat_entry(&sA, INT(DIM2-1), INT(DIM3-1), REAL());
+  }
+  igraph_sparsemat_compress(&sA, &sC);
+  igraph_sparsemat_destroy(&sA);
+
+  igraph_matrix_init(&B, 0, 0);
+  igraph_sparsemat_as_matrix(&B, &sB);
+  igraph_matrix_init(&C, 0, 0);
+  igraph_sparsemat_as_matrix(&C, &sC);
+  
+  /* All possible products */
+  igraph_sparsemat_multiply(&sB, &sC, &sA);
+  igraph_matrix_init(&A1, 0, 0);
+  igraph_sparsemat_as_matrix(&A1, &sA);
+  igraph_matrix_init(&A2, 0, 0);
+  igraph_sparsemat_dense_multiply(&B, &sC, &A2);
+  igraph_matrix_init(&A3, 0, 0);
+  igraph_sparsemat_multiply_by_dense(&sB, &C, &A3);
+
+  if (igraph_matrix_maxdifference(&A1, &A2) > 1e-10 ||
+      igraph_matrix_maxdifference(&A2, &A3) > 1e-10) {
+    return 1;
+  }
+
+  igraph_sparsemat_destroy(&sA);
+  igraph_sparsemat_destroy(&sB);
+  igraph_sparsemat_destroy(&sC);
+
+  igraph_matrix_destroy(&A1);
+  igraph_matrix_destroy(&A2);
+  igraph_matrix_destroy(&A3);
+  igraph_matrix_destroy(&B);
+  igraph_matrix_destroy(&C);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_sparsemat_is_symmetric.c b/examples/simple/igraph_sparsemat_is_symmetric.c
new file mode 100644
index 0000000..e899417
--- /dev/null
+++ b/examples/simple/igraph_sparsemat_is_symmetric.c
@@ -0,0 +1,62 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#define DIM 10
+
+#define INT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))
+
+int main() {
+  int runs=100;
+  const int noelements=20;
+  igraph_sparsemat_t A;
+  int i;
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+
+  for (; runs > 0; runs--) {
+
+    igraph_sparsemat_init(&A, DIM, DIM, noelements * 2);    
+    for (i=0; i<noelements; i++) {
+      int row=INT(DIM-1);
+      int col=INT(DIM-1);
+      int val=INT(100);
+      igraph_sparsemat_entry(&A, row, col, val);
+      igraph_sparsemat_entry(&A, col, row, val);
+    }
+    if (!igraph_sparsemat_is_symmetric(&A)) { return 1; }
+    igraph_sparsemat_destroy(&A);
+
+    igraph_sparsemat_init(&A, DIM, DIM, noelements);
+    for (i=0; i<noelements; i++) {
+      igraph_sparsemat_entry(&A, INT(DIM-1), INT(DIM-1), INT(100));
+    }
+    if (igraph_sparsemat_is_symmetric(&A)) { return 2; }
+    igraph_sparsemat_destroy(&A);
+
+  }
+    
+  return 0;
+}
+
diff --git a/examples/simple/igraph_star.c b/examples/simple/igraph_star.c
new file mode 100644
index 0000000..2ec90b1
--- /dev/null
+++ b/examples/simple/igraph_star.c
@@ -0,0 +1,29 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  return 0;
+}
diff --git a/examples/simple/igraph_stochastic_imitation.c b/examples/simple/igraph_stochastic_imitation.c
new file mode 100644
index 0000000..88e8939
--- /dev/null
+++ b/examples/simple/igraph_stochastic_imitation.c
@@ -0,0 +1,240 @@
+/* -*- mode: C -*-  */
+/*
+  Test suite for stochastic imitation via uniform selection.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+
+/* test parameters structure */
+typedef struct {
+  igraph_t *graph;
+  igraph_integer_t vertex;
+  igraph_imitate_algorithm_t algo;
+  igraph_vector_t *quantities;
+  igraph_vector_t *strategies;
+  igraph_vector_t *known_strats;
+  igraph_neimode_t mode;
+  int retval;
+} strategy_test_t;
+
+/* Error tests. That is, we expect error codes to be returned from such tests.
+ */
+int error_tests() {
+  igraph_t g, h;
+  igraph_vector_t quant, strat;
+  int i, n, ret;
+  strategy_test_t *test;
+
+  /* nonempty graph */
+  igraph_small(&g, /*n vertices*/ 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  igraph_empty(&h, 0, 0);         /* empty graph */
+  igraph_vector_init(&quant, 1);  /* quantities vector */
+  igraph_vector_init(&strat, 2);  /* strategies vector */
+
+  /* test parameters */
+  /*graph--vertex--algo--quantities--strategies--known_strats--mode--retval*/
+  /* null pointer for graph */
+  strategy_test_t null_graph = {NULL, 0, IGRAPH_IMITATE_BLIND, NULL, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for quantities vector */
+  strategy_test_t null_quant = {&g, 0, IGRAPH_IMITATE_BLIND, NULL, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* null pointer for strategies vector */
+  strategy_test_t null_strat = {&g, 0, IGRAPH_IMITATE_BLIND, &quant, NULL, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* empty graph */
+  strategy_test_t empty_graph = {&h, 0, IGRAPH_IMITATE_BLIND, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of quantities vector different from number of vertices */
+  strategy_test_t qdiff_length = {&g, 0, IGRAPH_IMITATE_BLIND, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  /* length of strategies vector different from number of vertices */
+  strategy_test_t sdiff_length = {&g, 0, IGRAPH_IMITATE_BLIND, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  strategy_test_t unknown_algo = {&g, 0, -1, &quant, &strat, NULL, IGRAPH_ALL, IGRAPH_EINVAL};
+  strategy_test_t *all_checks[] = {/* 1 */ &null_graph,
+                                   /* 2 */ &null_quant,
+                                   /* 3 */ &null_strat,
+                                   /* 4 */ &empty_graph,
+                                   /* 5 */ &qdiff_length,
+                                   /* 6 */ &sdiff_length,
+                                   /* 7 */ &unknown_algo};
+  /* Run the error tests. We expect error to be raised for each test. */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+  n = 7;
+  i = 0;
+  while (i < n) {
+    test = all_checks[i];
+    ret = igraph_stochastic_imitation(test->graph, test->vertex, test->algo,
+                                      test->quantities, test->strategies,
+                                      test->mode);
+    if (ret != test->retval) {
+      printf("Error test no. %d failed.\n", (int)(i + 1));
+      return IGRAPH_FAILURE;
+    }
+    i++;
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_destroy(&h);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* Updating the strategy of an isolated vertex. In this case, the strategies
+ * vector should not change at all.
+ */
+int isolated_vertex_test() {
+  igraph_t g;
+  igraph_vector_t quant, strat, v;
+  int i, ret;
+
+  /* graph with one isolated vertex */
+  igraph_small(&g, /*n vertices*/ 0, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,0, -1);
+  igraph_add_vertices(&g, 1, 0);  /* new vertex 3 is isolated */
+  /* quantities vector: all vertices have the same fitness */
+  igraph_vector_init_real(&quant, 4, 0.25, 0.25, 0.25, 0.25);
+  /* strategies vector: 0 means aggressive strategy; 1 means passive */
+  igraph_vector_init_real(&strat, 4, 1.0, 0.0, 1.0, 0.0);
+  /* make a copy of the original strategies vector for comparison later on */
+  igraph_vector_copy(&v, &strat);
+  /* Now update strategy of vertex 3. Since this vertex is isolated, no */
+  /* strategy update would take place. The resulting strategies vector */
+  /* would be the same as it was originally. */
+  ret = igraph_stochastic_imitation(/*graph*/ &g,
+                                    /*vertex*/ 3,
+                                    /*algorithm*/ IGRAPH_IMITATE_BLIND,
+                                    /*quantities*/ &quant,
+                                    /*strategies*/ &strat,
+                                    /*mode*/ IGRAPH_ALL);
+  if (ret) {
+    printf("Isolated vertex test failed.\n");
+    return IGRAPH_FAILURE;
+  }
+  for (i = 0; i < igraph_vector_size(&strat); i++) {
+    if (VECTOR(strat)[i] != VECTOR(v)[i]) {
+      printf("Isolated vertex test failed.\n");
+      return IGRAPH_FAILURE;
+    }
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+  igraph_vector_destroy(&v);
+
+  return IGRAPH_SUCCESS;
+}
+
+/* A game on the Petersen graph. This graph has 10 vertices and 15 edges. The
+ * Petersen graph is initialized with a default quantities vector and a
+ * default strategies vector. Some vertices are chosen for strategy revision,
+ * each one via a different stochastic imitation rule.
+ */
+int petersen_game_test() {
+  igraph_t g;
+  igraph_bool_t success;
+  igraph_vector_t quant, strat, stratcopy, *knownstrats;
+  igraph_vector_t known0, known2, known4;
+  int i, k, n, nedge, nvert, ret;
+  strategy_test_t *test;
+
+  /* the Petersen graph */
+  igraph_small(&g, /*n vertices*/ 0, IGRAPH_UNDIRECTED,
+               0,1,0,4,0,5, 1,2,1,6, 2,3,2,7, 3,4,3,8, 4,9,
+               5,7,5,8, 6,8,6,9, 7,9, -1);
+  nedge = igraph_ecount(&g);
+  nvert = igraph_vcount(&g);
+  /* Strategies vector, one strategy for each vertex. Thus vec[i] is the */
+  /* strategy of vertex i. The strategy space is: {0, 1, 2, 3}. */
+  /* Each strategy should be an integer. */
+  igraph_vector_init_real(&strat, nvert,
+                          1.0, 1.0, 2.0, 2.0, 0.0,
+                          0.0, 0.0, 1.0, 2.0, 3.0);
+  /* Quantities vector, one quantity per vertex. Thus vec[i] is the */
+  /* quantity for vertex i. */
+  igraph_vector_init_real(&quant, nvert,
+                          0.3, 1.1, 0.5, 1.0, 0.9,
+                          0.8, 0.4, 0.1, 0.7, 0.7);
+  /* parameter settings and known results */
+  igraph_vector_init_real(&known0, 2, 0.0, 1.0);
+  igraph_vector_init_real(&known2, 2, 1.0, 2.0);
+  igraph_vector_init_real(&known4, 2, 0.0, 2.0);
+  /*graph--vertex--algo--quantities--strategies--known_strats--mode--retval*/
+  strategy_test_t blind0 = {&g, 0, IGRAPH_IMITATE_BLIND, &quant, NULL, &known0, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t augmented4 = {&g, 4, IGRAPH_IMITATE_AUGMENTED, &quant, NULL, &known4, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t contracted2 = {&g, 2, IGRAPH_IMITATE_CONTRACTED, &quant, NULL, &known2, IGRAPH_ALL, IGRAPH_SUCCESS};
+  strategy_test_t *all_checks[] = {/* 1 */ &blind0,
+                                   /* 2 */ &augmented4,
+                                   /* 3 */ &contracted2};
+  /* run the tests */
+  n = 3;
+  i = 0;
+  while (i < n) {
+    test = all_checks[i];
+    igraph_vector_copy(&stratcopy, &strat);
+    ret = igraph_stochastic_imitation(test->graph, test->vertex, test->algo,
+                                      test->quantities, &stratcopy,
+                                      test->mode);
+    if (ret) {
+      printf("Stochastic imitation failed for vertex %d.\n",
+             (int)test->vertex);
+      return IGRAPH_FAILURE;
+    }
+    /* If the updated strategy for the vertex matches one of the known */
+    /* strategies, then success. Default to failure. */
+    success = 0;
+    knownstrats = test->known_strats;
+    for (k = 0; k < igraph_vector_size(knownstrats); k++) {
+      if (VECTOR(*knownstrats)[k] == VECTOR(stratcopy)[test->vertex]) {
+        success = 1;
+        break;
+      }
+    }
+    if (!success) {
+      printf("Stochastic imitation failed for vertex %d.\n",
+             (int)test->vertex);
+      return IGRAPH_FAILURE;
+    }
+    igraph_vector_destroy(&stratcopy);
+    i++;
+  }
+  /* clean up */
+  igraph_destroy(&g);
+  igraph_vector_destroy(&known0);
+  igraph_vector_destroy(&known2);
+  igraph_vector_destroy(&known4);
+  igraph_vector_destroy(&quant);
+  igraph_vector_destroy(&strat);
+
+  return IGRAPH_SUCCESS;
+}
+
+int main() {
+  int ret;
+
+  ret = error_tests();
+  if (ret)
+    return ret;
+  ret = isolated_vertex_test();
+  if (ret)
+    return ret;
+  ret = petersen_game_test();
+  if (ret)
+    return ret;
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/examples/simple/igraph_strvector.c b/examples/simple/igraph_strvector.c
new file mode 100644
index 0000000..b801c3e
--- /dev/null
+++ b/examples/simple/igraph_strvector.c
@@ -0,0 +1,190 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void strvector_print(const igraph_strvector_t *sv) {
+  long int i, s=igraph_strvector_size(sv);
+  for (i=0; i<s; i++) {
+    printf("---%s---\n", STR(*sv, i));
+  }
+}
+
+int main() {
+
+  igraph_strvector_t sv1, sv2;
+  char *str1;
+  int i;
+
+  /* igraph_strvector_init, igraph_strvector_destroy */
+  igraph_strvector_init(&sv1, 10);
+  igraph_strvector_destroy(&sv1);
+  igraph_strvector_init(&sv1, 0);
+  igraph_strvector_destroy(&sv1);
+
+  /* igraph_strvector_get, igraph_strvector_set */
+  igraph_strvector_init(&sv1, 5);
+  for (i=0; i<igraph_strvector_size(&sv1); i++) {
+    igraph_strvector_get(&sv1, i, &str1);
+    printf("---%s---\n", str1);
+  }
+  igraph_strvector_set(&sv1, 0, "zero");
+  igraph_strvector_set(&sv1, 1, "one");
+  igraph_strvector_set(&sv1, 2, "two");
+  igraph_strvector_set(&sv1, 3, "three");
+  igraph_strvector_set(&sv1, 4, "four");
+  for (i=0; i<igraph_strvector_size(&sv1); i++) {
+    igraph_strvector_get(&sv1, i, &str1);
+    printf("---%s---\n", str1);
+  }
+
+  /* igraph_strvector_remove_section, igraph_strvector_remove, 
+     igraph_strvector_resize, igraph_strvector_size */
+  igraph_strvector_remove_section(&sv1, 0, 5);
+  if (igraph_strvector_size(&sv1) != 0) {
+    return 1;
+  }
+  igraph_strvector_resize(&sv1, 10);
+  igraph_strvector_set(&sv1, 0, "zero");
+  igraph_strvector_set(&sv1, 1, "one");
+  igraph_strvector_set(&sv1, 2, "two");
+  igraph_strvector_set(&sv1, 3, "three");
+  igraph_strvector_set(&sv1, 4, "four");
+  igraph_strvector_resize(&sv1, 5);
+  for (i=0; i<igraph_strvector_size(&sv1); i++) {
+    igraph_strvector_get(&sv1, i, &str1);
+    printf("---%s---\n", str1);
+  }
+  igraph_strvector_resize(&sv1, 0);
+  if (igraph_strvector_size(&sv1) != 0) {
+    return 1;
+  }
+  igraph_strvector_resize(&sv1, 10);
+  igraph_strvector_set(&sv1, 0, "zero");
+  igraph_strvector_set(&sv1, 1, "one");
+  igraph_strvector_set(&sv1, 2, "two");
+  igraph_strvector_set(&sv1, 3, "three");
+  igraph_strvector_set(&sv1, 4, "four");
+  igraph_strvector_resize(&sv1, 5);
+  for (i=0; i<igraph_strvector_size(&sv1); i++) {
+    igraph_strvector_get(&sv1, i, &str1);
+    printf("---%s---\n", str1);
+  }  
+
+  /* igraph_strvector_move_interval */
+  igraph_strvector_move_interval(&sv1, 3, 5, 0);
+  for (i=0; i<igraph_strvector_size(&sv1); i++) {
+    igraph_strvector_get(&sv1, i, &str1);
+    printf("---%s---\n", str1);
+  }
+
+  /* igraph_strvector_copy */
+  igraph_strvector_copy(&sv2, &sv1);
+  for (i=0; i<igraph_strvector_size(&sv2); i++) {
+    igraph_strvector_get(&sv2, i, &str1);
+    printf("---%s---\n", str1);
+  }
+  igraph_strvector_resize(&sv1, 0);
+  igraph_strvector_destroy(&sv2);
+  igraph_strvector_copy(&sv2, &sv1);
+  if (igraph_strvector_size(&sv2) != 0) {
+    return 2;
+  }
+  igraph_strvector_destroy(&sv2);
+
+  /* igraph_strvector_add */
+  igraph_strvector_add(&sv1, "zeroth");
+  igraph_strvector_add(&sv1, "first");
+  igraph_strvector_add(&sv1, "second");
+  igraph_strvector_add(&sv1, "third");
+  igraph_strvector_add(&sv1, "fourth");
+  for (i=0; i<igraph_strvector_size(&sv1); i++) {
+    igraph_strvector_get(&sv1, i, &str1);
+    printf("---%s---\n", str1);
+  }
+
+  /* TODO: igraph_strvector_permdelete */
+  /* TODO: igraph_strvector_remove_negidx */
+  
+  igraph_strvector_destroy(&sv1);
+
+  /* append */
+  printf("---\n");
+  igraph_strvector_init(&sv1, 0);
+  igraph_strvector_init(&sv2, 0);
+  igraph_strvector_append(&sv1, &sv2);
+  strvector_print(&sv1);
+  printf("---\n");
+  
+  igraph_strvector_resize(&sv1, 3);
+  igraph_strvector_append(&sv1, &sv2);
+  strvector_print(&sv1);
+  printf("---\n");   
+
+  igraph_strvector_append(&sv2, &sv1);
+  strvector_print(&sv2);
+  printf("---\n");   
+  
+  igraph_strvector_set(&sv1, 0, "0");
+  igraph_strvector_set(&sv1, 1, "1");
+  igraph_strvector_set(&sv1, 2, "2");
+  igraph_strvector_set(&sv2, 0, "3");
+  igraph_strvector_set(&sv2, 1, "4");
+  igraph_strvector_set(&sv2, 2, "5");
+  igraph_strvector_append(&sv1, &sv2);
+  strvector_print(&sv1);
+  
+  igraph_strvector_destroy(&sv1);
+  igraph_strvector_destroy(&sv2);
+  
+  /* clear */
+  igraph_strvector_init(&sv1, 3);
+  igraph_strvector_set(&sv1, 0, "0");
+  igraph_strvector_set(&sv1, 1, "1");
+  igraph_strvector_set(&sv1, 2, "2");
+  igraph_strvector_clear(&sv1);
+  if (igraph_strvector_size(&sv1) != 0) {
+    return 3;
+  }
+  igraph_strvector_resize(&sv1, 4);
+  strvector_print(&sv1);
+  igraph_strvector_set(&sv1, 0, "one");
+  igraph_strvector_set(&sv1, 2, "two");
+  strvector_print(&sv1);
+  igraph_strvector_destroy(&sv1);
+
+  /* STR */
+  
+  igraph_strvector_init(&sv1, 5);
+  igraph_strvector_set(&sv1, 0, "one");
+  igraph_strvector_set(&sv1, 1, "two");
+  igraph_strvector_set(&sv1, 2, "three");
+  igraph_strvector_set(&sv1, 3, "four");
+  igraph_strvector_set(&sv1, 4, "five");
+  strvector_print(&sv1);
+  igraph_strvector_destroy(&sv1);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 4;
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_strvector.out b/examples/simple/igraph_strvector.out
new file mode 100644
index 0000000..3d4b171
--- /dev/null
+++ b/examples/simple/igraph_strvector.out
@@ -0,0 +1,64 @@
+------
+------
+------
+------
+------
+---zero---
+---one---
+---two---
+---three---
+---four---
+---zero---
+---one---
+---two---
+---three---
+---four---
+---zero---
+---one---
+---two---
+---three---
+---four---
+---three---
+---four---
+---two---
+---three---
+---four---
+---three---
+---four---
+---two---
+---three---
+---four---
+---zeroth---
+---first---
+---second---
+---third---
+---fourth---
+---
+---
+------
+------
+------
+---
+------
+------
+------
+---
+---0---
+---1---
+---2---
+---3---
+---4---
+---5---
+------
+------
+------
+------
+---one---
+------
+---two---
+------
+---one---
+---two---
+---three---
+---four---
+---five---
diff --git a/examples/simple/igraph_subisomorphic_lad.c b/examples/simple/igraph_subisomorphic_lad.c
new file mode 100644
index 0000000..e1810d1
--- /dev/null
+++ b/examples/simple/igraph_subisomorphic_lad.c
@@ -0,0 +1,140 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+
+int main() {
+  igraph_t target, pattern;
+  igraph_bool_t iso;
+  igraph_vector_t map;
+  igraph_vector_ptr_t maps;
+  int i, n;
+  int domainsvec[] = { 0, 2, 8, -1,
+		       4, 5, 6, 7, -1, 
+		       1, 3, 5, 6, 7, 8, -1,
+		       0, 2, 8, -1,
+		       1, 3, 7, 8, -1, -2 };
+  igraph_vector_ptr_t domains;
+  igraph_vector_t *v=0;
+
+  igraph_small(&target, 9, IGRAPH_UNDIRECTED, 
+	       0,1,0,4,0,6,
+	       1,0,1,4,1,2,
+	       2,1,2,3,
+	       3,2,3,4,3,5,3,7,3,8,
+	       4,0,4,1,4,3,4,5,4,6,
+	       5,6,5,4,5,3,5,8,
+	       6,0,6,4,6,5,
+	       7,3,7,8,
+	       8,5,8,3,8,7, 
+	       -1);
+  igraph_simplify(&target, /*multiple=*/ 1, /*loops=*/ 0, /*edge_comb=*/ 0);
+
+  igraph_small(&pattern, 5, IGRAPH_UNDIRECTED,
+	       0,1,0,4,
+	       1,0,1,4,1,2,
+	       2,1,2,3,
+	       3,2,3,4,
+	       4,3,4,1,4,0,
+	       -1);
+  igraph_simplify(&pattern, /*multiple=*/ 1, /*loops=*/ 0, /*edge_comb=*/ 0);
+  
+  igraph_vector_init(&map, 0);
+  igraph_vector_ptr_init(&maps, 0);
+  
+  igraph_subisomorphic_lad(&pattern, &target, /*domains=*/ 0, &iso, &map, 
+			   &maps, /*induced=*/ 0, /*time_limit=*/ 0);
+
+  if (!iso) { return 1; }
+  igraph_vector_print(&map);
+  n=igraph_vector_ptr_size(&maps);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(maps)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+ 
+  printf("---------\n");
+
+  igraph_subisomorphic_lad(&pattern, &target, /*domains=*/ 0, &iso, &map, 
+			   &maps, /*induced=*/ 1, /*time_limit=*/ 0);
+
+  if (!iso) { return 2; }
+  igraph_vector_print(&map);
+  n=igraph_vector_ptr_size(&maps);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(maps)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+
+  printf("---------\n");
+
+  igraph_vector_ptr_init(&domains, 0);
+  i=0; while (1) { 
+    if (domainsvec[i] == -2) { 
+      break; 
+    } else if (domainsvec[i] == -1) {
+      igraph_vector_ptr_push_back(&domains, v);
+      v=0;
+    } else {
+      if (!v) { 
+	v=(igraph_vector_t *) malloc(sizeof(igraph_vector_t));
+	igraph_vector_init(v, 0);
+      }
+      igraph_vector_push_back(v, domainsvec[i]);
+    }
+    i++;
+  }
+
+  igraph_subisomorphic_lad(&pattern, &target, &domains, &iso, &map, &maps,
+			   /*induced=*/ 0, /*time_limit=*/ 0);
+  
+  if (!iso) { return 3; }
+  igraph_vector_print(&map);
+  n=igraph_vector_ptr_size(&maps);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(maps)[i];
+    igraph_vector_print(v);
+    igraph_vector_destroy(v);
+    igraph_free(v);
+  }
+
+  n=igraph_vector_ptr_size(&domains);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(domains)[i];
+    igraph_vector_destroy(v);
+    free(v);
+  }
+  
+  igraph_vector_ptr_destroy(&domains);
+  igraph_vector_destroy(&map);
+  igraph_vector_ptr_destroy(&maps);
+
+  igraph_destroy(&pattern);
+  igraph_destroy(&target);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_subisomorphic_lad.out b/examples/simple/igraph_subisomorphic_lad.out
new file mode 100644
index 0000000..215a48f
--- /dev/null
+++ b/examples/simple/igraph_subisomorphic_lad.out
@@ -0,0 +1,30 @@
+1 0 6 5 4
+1 0 6 5 4
+0 1 2 3 4
+5 3 2 1 4
+7 3 4 5 8
+4 3 7 8 5
+8 3 4 6 5
+0 4 3 5 6
+0 4 3 2 1
+3 4 0 6 5
+6 4 3 8 5
+5 4 1 2 3
+5 4 1 0 6
+1 4 5 6 0
+8 5 6 4 3
+4 5 8 7 3
+3 5 6 0 4
+6 5 8 3 4
+0 6 5 3 4
+5 6 0 1 4
+7 8 5 4 3
+---------
+0 1 2 3 4
+0 1 2 3 4
+5 3 2 1 4
+5 4 1 2 3
+0 4 3 2 1
+---------
+0 4 3 2 1
+0 4 3 2 1
diff --git a/examples/simple/igraph_to_undirected.c b/examples/simple/igraph_to_undirected.c
new file mode 100644
index 0000000..7c52126
--- /dev/null
+++ b/examples/simple/igraph_to_undirected.c
@@ -0,0 +1,52 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_vector_t v;
+  igraph_t g;
+  
+  igraph_vector_init_int(&v, 2, 5, 5);
+  igraph_lattice(&g, &v, 1, IGRAPH_DIRECTED, 1 /*mutual*/, 0 /*circular*/);
+  igraph_to_undirected(&g, IGRAPH_TO_UNDIRECTED_COLLAPSE, 
+		       /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+
+  igraph_destroy(&g);
+  igraph_vector_destroy(&v);
+
+  printf("---\n");
+
+  igraph_small(&g, 10, IGRAPH_DIRECTED, 
+	       0,1, 2,1, 2,3, 2,3, 4,3, 4,3,
+	       5,6, 6,5, 6,7, 6,7, 7,6, 7,8, 7,8, 8,7, 8,7, 8,8, 9,9, 9,9,
+	       -1);
+  igraph_to_undirected(&g, IGRAPH_TO_UNDIRECTED_MUTUAL,
+		       /*edge_comb=*/ 0);
+  igraph_write_graph_edgelist(&g, stdout);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_to_undirected.out b/examples/simple/igraph_to_undirected.out
new file mode 100644
index 0000000..4829e26
--- /dev/null
+++ b/examples/simple/igraph_to_undirected.out
@@ -0,0 +1,48 @@
+0 1
+0 5
+1 2
+1 6
+2 3
+2 7
+3 4
+3 8
+4 9
+5 6
+5 10
+6 7
+6 11
+7 8
+7 12
+8 9
+8 13
+9 14
+10 11
+10 15
+11 12
+11 16
+12 13
+12 17
+13 14
+13 18
+14 19
+15 16
+15 20
+16 17
+16 21
+17 18
+17 22
+18 19
+18 23
+19 24
+20 21
+21 22
+22 23
+23 24
+---
+5 6
+6 7
+7 8
+7 8
+8 8
+9 9
+9 9
diff --git a/examples/simple/igraph_topological_sorting.c b/examples/simple/igraph_topological_sorting.c
new file mode 100644
index 0000000..401fc26
--- /dev/null
+++ b/examples/simple/igraph_topological_sorting.c
@@ -0,0 +1,97 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %d", (int)VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+void igraph_warning_handler_print_stdout(const char *reason, const char *file,
+					 int line, int igraph_errno) {
+  fprintf(stdout, "Warning: %s\n", reason);
+}
+
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v, res;
+  igraph_bool_t is_dag;
+  int ret;
+
+  igraph_set_warning_handler(igraph_warning_handler_print_stdout);
+
+  /* Test graph taken from http://en.wikipedia.org/wiki/Topological_sorting
+   * @ 05.03.2006 */
+  igraph_small(&g, 8, 1, 0, 3, 0, 4, 1, 3, 2, 4, 2, 7, \
+	       3, 5, 3, 6, 3, 7, 4, 6, -1);
+
+  igraph_vector_init(&res, 0);
+
+  igraph_is_dag(&g, &is_dag);
+  if (!is_dag)
+    return 2;
+
+  igraph_topological_sorting(&g, &res, IGRAPH_OUT);
+  print_vector(&res, stdout);
+  igraph_topological_sorting(&g, &res, IGRAPH_IN);
+  print_vector(&res, stdout);
+
+  /* Add a circle: 5 -> 0 */
+  igraph_vector_init_int(&v, 2, 5, 0);
+  igraph_add_edges(&g, &v, 0);
+  igraph_is_dag(&g, &is_dag);
+  if (is_dag)
+    return 3;
+  igraph_topological_sorting(&g, &res, IGRAPH_OUT);
+  print_vector(&res, stdout);
+  igraph_vector_destroy(&v);
+  igraph_destroy(&g);
+
+  /* Error handling */
+  igraph_set_error_handler(igraph_error_handler_ignore);
+
+  /* This graph is the same but undirected */
+  igraph_small(&g, 8, 0, 0, 3, 0, 4, 1, 3, 2, 4, 2, 7, \
+	       3, 5, 3, 6, 3, 7, 4, 6, -1);
+  igraph_is_dag(&g, &is_dag);
+  if (is_dag)
+    return 4;
+  ret=igraph_topological_sorting(&g, &res, IGRAPH_ALL);
+  if (ret != IGRAPH_EINVAL) {
+    return 1;
+  }
+  ret=igraph_topological_sorting(&g, &res, IGRAPH_OUT);
+  if (ret != IGRAPH_EINVAL) {
+    return 1;
+  }  
+  igraph_destroy(&g);
+
+  igraph_vector_destroy(&res);  
+  return 0;
+}
diff --git a/examples/simple/igraph_topological_sorting.out b/examples/simple/igraph_topological_sorting.out
new file mode 100644
index 0000000..29df183
--- /dev/null
+++ b/examples/simple/igraph_topological_sorting.out
@@ -0,0 +1,4 @@
+ 0 1 2 3 4 5 7 6
+ 5 6 7 4 3 2 0 1
+Warning: graph contains a cycle, partial result is returned
+ 1 2
diff --git a/examples/simple/igraph_transitive_closure_dag.c b/examples/simple/igraph_transitive_closure_dag.c
new file mode 100644
index 0000000..a18778d
--- /dev/null
+++ b/examples/simple/igraph_transitive_closure_dag.c
@@ -0,0 +1,50 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g, g2;
+  igraph_vector_t deg;
+
+  igraph_small(&g, 9, IGRAPH_DIRECTED,
+	       8,7, 7,6, 6,3, 6,0, 3,2, 3,1, 5,0, 4,1,
+	       -1);
+  igraph_transitive_closure_dag(&g, &g2);
+  
+  if (igraph_vcount(&g2) != igraph_vcount(&g)) { return 1; }
+  if (igraph_ecount(&g2) != 19) { return 1; }
+  
+  igraph_vector_init(&deg, 0);
+  igraph_degree(&g2, &deg, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
+  igraph_vector_print(&deg);
+  igraph_degree(&g2, &deg, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
+  igraph_vector_print(&deg);
+  
+  igraph_vector_destroy(&deg);
+  igraph_destroy(&g2);
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_transitive_closure_dag.out b/examples/simple/igraph_transitive_closure_dag.out
new file mode 100644
index 0000000..051c1a0
--- /dev/null
+++ b/examples/simple/igraph_transitive_closure_dag.out
@@ -0,0 +1,2 @@
+4 5 4 3 0 0 2 1 0
+0 0 0 2 1 1 4 5 6
diff --git a/examples/simple/igraph_transitivity.c b/examples/simple/igraph_transitivity.c
new file mode 100644
index 0000000..b7792a3
--- /dev/null
+++ b/examples/simple/igraph_transitivity.c
@@ -0,0 +1,94 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_real_t res;
+
+  /* Trivial cases */
+
+  igraph_ring(&g, 100, IGRAPH_UNDIRECTED, 0, 0);
+  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
+  igraph_destroy(&g);
+
+  if (res != 0) {
+    return 1;
+  }
+
+  igraph_full(&g, 20, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
+  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
+  igraph_destroy(&g);
+  
+  if (res != 1) {
+    return 2;
+  }
+
+  /* Degenerate cases */
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
+		  0,  1,  2,  3,  4,  5, -1);
+  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
+  /* res should be NaN here, any comparison must return false */
+  if (res == 0 || res > 0 || res < 0) {
+	return 4;
+  }
+  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_ZERO);
+  /* res should be zero here */
+  if (res) {
+	return 5;
+  }
+  igraph_destroy(&g);
+
+  /* Zachary Karate club */
+
+  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
+	       0,  1,  0,  2,  0,  3,  0,  4,  0,  5,
+	       0,  6,  0,  7,  0,  8,  0, 10,  0, 11,
+	       0, 12,  0, 13,  0, 17,  0, 19,  0, 21,
+	       0, 31,  1,  2,  1,  3,  1,  7,  1, 13,
+	       1, 17,  1, 19,  1, 21,  1, 30,  2,  3,
+	       2,  7,  2,  8,  2,  9,  2, 13,  2, 27,
+	       2, 28,  2, 32,  3,  7,  3, 12,  3, 13,
+	       4,  6,  4, 10,  5,  6,  5, 10,  5, 16,
+	       6, 16,  8, 30,  8, 32,  8, 33,  9, 33,
+	       13, 33, 14, 32, 14, 33, 15, 32, 15, 33,
+	       18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
+	       22, 32, 22, 33, 23, 25, 23, 27, 23, 29,
+	       23, 32, 23, 33, 24, 25, 24, 27, 24, 31,
+	       25, 31, 26, 29, 26, 33, 27, 33, 28, 31,
+	       28, 33, 29, 32, 29, 33, 30, 32, 30, 33,
+	       31, 32, 31, 33, 32, 33,
+	       -1);  
+  
+  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
+  igraph_destroy(&g);
+  
+  if (res != 0.2556818181818181767717) {
+    fprintf(stderr, "%f != %f\n", res, 0.2556818181818181767717);
+    return 3;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_tree.c b/examples/simple/igraph_tree.c
new file mode 100644
index 0000000..2ec90b1
--- /dev/null
+++ b/examples/simple/igraph_tree.c
@@ -0,0 +1,29 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  return 0;
+}
diff --git a/examples/simple/igraph_trie.c b/examples/simple/igraph_trie.c
new file mode 100644
index 0000000..700f46b
--- /dev/null
+++ b/examples/simple/igraph_trie.c
@@ -0,0 +1,98 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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 <stdio.h>
+#include <igraph.h>
+#include <igraph_types_internal.h>
+
+int main() {
+  
+  igraph_trie_t trie;
+  long int id;
+  int i;
+  char *str;
+
+  /* init */
+  igraph_trie_init(&trie, 0);
+
+  /* add and get values */
+  igraph_trie_get(&trie, "hello", &id);  printf("hello: %li\n", id);
+  igraph_trie_get(&trie, "hepp", &id);   printf("hepp:  %li\n", id);
+  igraph_trie_get(&trie, "alma", &id);   printf("alma:  %li\n", id);
+  igraph_trie_get(&trie, "also", &id);   printf("also:  %li\n", id);
+
+  igraph_trie_get(&trie, "hello", &id);  printf("hello: %li\n", id);
+  igraph_trie_get(&trie, "hepp", &id);   printf("hepp:  %li\n", id);
+  igraph_trie_get(&trie, "alma", &id);   printf("alma:  %li\n", id);
+  igraph_trie_get(&trie, "also", &id);   printf("also:  %li\n", id);
+
+  igraph_trie_get(&trie, "a", &id);      printf("a:     %li\n", id);
+  igraph_trie_get(&trie, "axon", &id);   printf("axon:  %li\n", id);
+
+  igraph_trie_get(&trie, "hello", &id);  printf("hello: %li\n", id);
+  igraph_trie_get(&trie, "hepp", &id);   printf("hepp:  %li\n", id);
+  igraph_trie_get(&trie, "alma", &id);   printf("alma:  %li\n", id);
+  igraph_trie_get(&trie, "also", &id);   printf("also:  %li\n", id);
+
+  /* check for existence */
+  igraph_trie_check(&trie, "head", &id); printf("head:  %li\n", id);
+  igraph_trie_check(&trie, "alma", &id); printf("alma:  %li\n", id);
+   
+  /* destroy */
+  igraph_trie_destroy(&trie);
+
+  /* the same with index */
+  igraph_trie_init(&trie, 1);
+
+  igraph_trie_get(&trie, "hello", &id);  printf("hello: %li\n", id);
+  igraph_trie_get(&trie, "hepp", &id);   printf("hepp:  %li\n", id);
+  igraph_trie_get(&trie, "alma", &id);   printf("alma:  %li\n", id);
+  igraph_trie_get(&trie, "also", &id);   printf("also:  %li\n", id);
+
+  igraph_trie_get(&trie, "hello", &id);  printf("hello: %li\n", id);
+  igraph_trie_get(&trie, "hepp", &id);   printf("hepp:  %li\n", id);
+  igraph_trie_get(&trie, "alma", &id);   printf("alma:  %li\n", id);
+  igraph_trie_get(&trie, "also", &id);   printf("also:  %li\n", id);
+
+  igraph_trie_get(&trie, "a", &id);      printf("a:     %li\n", id);
+  igraph_trie_get(&trie, "axon", &id);   printf("axon:  %li\n", id);
+
+  igraph_trie_get(&trie, "hello", &id);  printf("hello: %li\n", id);
+  igraph_trie_get(&trie, "hepp", &id);   printf("hepp:  %li\n", id);
+  igraph_trie_get(&trie, "alma", &id);   printf("alma:  %li\n", id);
+  igraph_trie_get(&trie, "also", &id);   printf("also:  %li\n", id);
+
+  /* check for existence */
+  igraph_trie_check(&trie, "head", &id); printf("head:  %li\n", id);
+  igraph_trie_check(&trie, "alma", &id); printf("alma:  %li\n", id);
+
+  for (i=0; i<igraph_trie_size(&trie); i++) {
+    igraph_trie_idx(&trie, i, &str);
+    printf("%d: %s\n", i, str);
+  }
+  igraph_trie_destroy(&trie);
+
+  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_trie.out b/examples/simple/igraph_trie.out
new file mode 100644
index 0000000..7367a56
--- /dev/null
+++ b/examples/simple/igraph_trie.out
@@ -0,0 +1,38 @@
+hello: 0
+hepp:  1
+alma:  2
+also:  3
+hello: 0
+hepp:  1
+alma:  2
+also:  3
+a:     4
+axon:  5
+hello: 0
+hepp:  1
+alma:  2
+also:  3
+head:  -1
+alma:  2
+hello: 0
+hepp:  1
+alma:  2
+also:  3
+hello: 0
+hepp:  1
+alma:  2
+also:  3
+a:     4
+axon:  5
+hello: 0
+hepp:  1
+alma:  2
+also:  3
+head:  -1
+alma:  2
+0: hello
+1: hepp
+2: alma
+3: also
+4: a
+5: axon
diff --git a/examples/simple/igraph_union.c b/examples/simple/igraph_union.c
new file mode 100644
index 0000000..79d2ceb
--- /dev/null
+++ b/examples/simple/igraph_union.c
@@ -0,0 +1,152 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void print_vector(igraph_vector_t *v) {
+  long int i, l=igraph_vector_size(v);
+  for (i=0; i<l; i++) {
+    printf(" %li", (long int) VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+int print_free_vector_ptr(igraph_vector_ptr_t *v) {  
+  long int i, l=igraph_vector_ptr_size(v);
+  printf("---\n");
+  for (i=0; i<l; i++) {
+    print_vector(VECTOR(*v)[i]);
+  }
+  printf("===\n");
+  return 0;
+}
+
+int main() {
+  
+  igraph_t left, right, uni;
+  igraph_vector_t v;
+  igraph_vector_ptr_t glist;
+  igraph_vector_t edge_map1, edge_map2;
+  igraph_vector_ptr_t edgemaps;
+  long int i;  
+
+  igraph_vector_init(&edge_map1, 0);
+  igraph_vector_init(&edge_map2, 0);
+
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,2, 2,3, -1);
+  igraph_create(&left, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_vector_init_int_end(&v, -1, 0,1, 1,2, 2,2, 2,4, -1); 
+  igraph_create(&right, &v, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&v);
+  
+  igraph_union(&uni, &left, &right, &edge_map1, &edge_map2);
+  igraph_write_graph_edgelist(&uni, stdout);
+  igraph_vector_print(&edge_map1);
+  igraph_vector_print(&edge_map2);  
+
+  igraph_destroy(&uni);
+  igraph_destroy(&left);
+  igraph_destroy(&right);
+  igraph_vector_destroy(&edge_map1);
+  igraph_vector_destroy(&edge_map2);
+
+  /* Empty graph list */  
+  igraph_vector_ptr_init(&glist, 0);
+  igraph_vector_ptr_init(&edgemaps, 0);
+  igraph_union_many(&uni, &glist, &edgemaps);
+  if (!igraph_is_directed(&uni) || igraph_vcount(&uni) != 0) {
+    return 1;
+  }
+  print_free_vector_ptr(&edgemaps);
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&uni);  
+
+  /* Non-empty graph list */
+  igraph_vector_ptr_init(&glist, 10); 
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    VECTOR(glist)[i]=calloc(1, sizeof(igraph_t));
+    igraph_vector_init_int_end(&v, -1, 0,1, 1,0, -1);
+    igraph_create(VECTOR(glist)[i], &v, 0, IGRAPH_DIRECTED);    
+    igraph_vector_destroy(&v);
+  }
+
+  igraph_union_many(&uni, &glist, &edgemaps);
+  igraph_write_graph_edgelist(&uni, stdout);
+
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    igraph_destroy(VECTOR(glist)[i]);
+    free(VECTOR(glist)[i]);
+  }
+  print_free_vector_ptr(&edgemaps);
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&uni);  
+
+  /* Another non-empty graph list */
+  igraph_vector_ptr_init(&glist, 10); 
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    VECTOR(glist)[i]=calloc(1, sizeof(igraph_t));
+    igraph_vector_init_int_end(&v, -1, i,i+1, 1,0, -1);
+    igraph_create(VECTOR(glist)[i], &v, 0, IGRAPH_DIRECTED);    
+    igraph_vector_destroy(&v);
+  }
+
+  igraph_union_many(&uni, &glist, &edgemaps);
+  igraph_write_graph_edgelist(&uni, stdout);
+
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    igraph_destroy(VECTOR(glist)[i]);
+    free(VECTOR(glist)[i]);
+  }
+  print_free_vector_ptr(&edgemaps);
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&uni);  
+  
+  /* Undirected graph list*/
+  igraph_vector_ptr_init(&glist, 10); 
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    VECTOR(glist)[i]=calloc(1, sizeof(igraph_t));
+    igraph_vector_init_int_end(&v, -1, i,i+1, 1,0, -1);
+    igraph_create(VECTOR(glist)[i], &v, 0, IGRAPH_UNDIRECTED);    
+    igraph_vector_destroy(&v);
+  }
+
+  igraph_union_many(&uni, &glist, &edgemaps);
+  igraph_write_graph_edgelist(&uni, stdout);
+
+  for (i=0; i<igraph_vector_ptr_size(&glist); i++) {
+    igraph_destroy(VECTOR(glist)[i]);
+    free(VECTOR(glist)[i]);
+  }
+  print_free_vector_ptr(&edgemaps);
+  igraph_vector_ptr_destroy(&glist);
+  igraph_destroy(&uni);  
+
+  igraph_vector_ptr_destroy(&edgemaps);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_union.out b/examples/simple/igraph_union.out
new file mode 100644
index 0000000..4c2b691
--- /dev/null
+++ b/examples/simple/igraph_union.out
@@ -0,0 +1,69 @@
+0 1
+1 2
+2 2
+2 3
+2 4
+0 1 2 3
+0 1 2 4
+---
+===
+0 1
+1 0
+---
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+ 1 0
+===
+0 1
+1 0
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+---
+ 10 9
+ 8 9
+ 7 9
+ 6 9
+ 5 9
+ 4 9
+ 3 9
+ 2 9
+ 1 9
+ 0 9
+===
+0 1
+0 1
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+---
+ 10 9
+ 8 9
+ 7 9
+ 6 9
+ 5 9
+ 4 9
+ 3 9
+ 2 9
+ 1 9
+ 0 9
+===
diff --git a/examples/simple/igraph_version.c b/examples/simple/igraph_version.c
new file mode 100644
index 0000000..3dc1cbf
--- /dev/null
+++ b/examples/simple/igraph_version.c
@@ -0,0 +1,45 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <string.h>
+
+int main() {
+  
+  char tmp[100];
+  const char *string;
+  int major, minor, subminor;  
+  
+  igraph_version(&string, &major, &minor, &subminor);
+  if (subminor != 0) { 
+    sprintf(tmp, "%i.%i.%i", major, minor, subminor);
+  } else {
+    sprintf(tmp, "%i.%i", major, minor);    
+  }
+
+  if (strncmp(string, tmp, strlen(tmp))) {
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/igraph_vs_nonadj.c b/examples/simple/igraph_vs_nonadj.c
new file mode 100644
index 0000000..c891987
--- /dev/null
+++ b/examples/simple/igraph_vs_nonadj.c
@@ -0,0 +1,65 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main () {
+
+  igraph_t g;
+  igraph_vs_t vs;
+  igraph_vit_t vit;  
+  igraph_integer_t size;
+
+  /* empty graph, all vertices */
+  igraph_empty(&g, 10, IGRAPH_DIRECTED);
+  igraph_vs_nonadj(&vs, 0, IGRAPH_ALL);
+  igraph_vs_size(&g, &vs, &size);
+  printf("%li ", (long int) size);
+  igraph_vit_create(&g, vs, &vit);
+  while (!IGRAPH_VIT_END(vit)) {
+    printf("%li ", (long int) IGRAPH_VIT_GET(vit));
+    IGRAPH_VIT_NEXT(vit);
+  }
+  printf("\n");
+  
+  igraph_vit_destroy(&vit);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+
+  /* full graph, no vertices */
+  igraph_full(&g, 10, IGRAPH_UNDIRECTED, IGRAPH_LOOPS);
+  igraph_vs_nonadj(&vs, 0, IGRAPH_ALL);
+  igraph_vit_create(&g, vs, &vit);
+  while (!IGRAPH_VIT_END(vit)) {
+    printf("%li ", (long int) IGRAPH_VIT_GET(vit));
+    IGRAPH_VIT_NEXT(vit);
+  }
+  printf("\n");
+  
+  igraph_vit_destroy(&vit);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+
+
+  return 0;
+}
diff --git a/examples/simple/igraph_vs_nonadj.out b/examples/simple/igraph_vs_nonadj.out
new file mode 100644
index 0000000..bc74074
--- /dev/null
+++ b/examples/simple/igraph_vs_nonadj.out
@@ -0,0 +1,2 @@
+10 0 1 2 3 4 5 6 7 8 9 
+
diff --git a/examples/simple/igraph_vs_seq.c b/examples/simple/igraph_vs_seq.c
new file mode 100644
index 0000000..ee3987f
--- /dev/null
+++ b/examples/simple/igraph_vs_seq.c
@@ -0,0 +1,50 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_vs_t vs;
+  igraph_vit_t vit;
+  igraph_t g;
+  igraph_integer_t size;
+
+  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 1);
+  igraph_vs_seq(&vs, 0, 9);
+  igraph_vit_create(&g, vs, &vit);
+  igraph_vs_size(&g, &vs, &size);
+  printf("%li", (long int) size);
+  
+  while (!IGRAPH_VIT_END(vit)) {
+    printf(" %li", (long int)IGRAPH_VIT_GET(vit));
+    IGRAPH_VIT_NEXT(vit);
+  }
+  printf("\n");
+
+  igraph_vit_destroy(&vit);
+  igraph_vs_destroy(&vs);
+  igraph_destroy(&g);
+  
+  return 0;
+}
diff --git a/examples/simple/igraph_vs_seq.out b/examples/simple/igraph_vs_seq.out
new file mode 100644
index 0000000..1b4b2e8
--- /dev/null
+++ b/examples/simple/igraph_vs_seq.out
@@ -0,0 +1 @@
+10 0 1 2 3 4 5 6 7 8 9
diff --git a/examples/simple/igraph_vs_vector.c b/examples/simple/igraph_vs_vector.c
new file mode 100644
index 0000000..f040fd8
--- /dev/null
+++ b/examples/simple/igraph_vs_vector.c
@@ -0,0 +1,82 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t v=IGRAPH_VECTOR_NULL;
+  igraph_real_t edges[] = { 0,1, 1,2, 2,2, 2,3, 2,4, 3,4 };
+  igraph_vector_t v2;
+  long int i;
+  igraph_vit_t vit;
+  igraph_vs_t vs;
+  igraph_integer_t size;
+
+  igraph_vector_view(&v, edges, sizeof(edges)/sizeof(igraph_real_t));
+  igraph_create(&g, &v, 0, IGRAPH_DIRECTED);
+
+  /* Create iterator based on a vector (view) */
+  igraph_vector_init(&v2, 6);
+  VECTOR(v2)[0]=0;   VECTOR(v2)[1]=2;
+  VECTOR(v2)[2]=4;   VECTOR(v2)[3]=0;
+  VECTOR(v2)[4]=2;   VECTOR(v2)[5]=4;
+
+  igraph_vit_create(&g, igraph_vss_vector(&v2), &vit);
+
+  i=0;
+  while (!IGRAPH_VIT_END(vit)) {
+    if (IGRAPH_VIT_GET(vit) != VECTOR(v2)[i]) {
+      return 1;
+    }
+    IGRAPH_VIT_NEXT(vit);
+    i++;
+  }
+  if (i != igraph_vector_size(&v2)) {
+    return 2;
+  }
+
+  igraph_vit_destroy(&vit);
+  igraph_vector_destroy(&v2);
+
+  /* Create small vector iterator */
+
+  igraph_vs_vector_small(&vs, 0, 2, 4, 0, 2, 4, 2, -1);
+  igraph_vit_create(&g, vs, &vit);
+  igraph_vs_size(&g, &vs, &size);
+  printf("%li ", (long int) size);
+  for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    printf("%li ", (long int) IGRAPH_VIT_GET(vit));
+  }
+  printf("\n");
+  
+  igraph_vit_destroy(&vit);
+  igraph_vs_destroy(&vs);
+
+  /* Clean up */
+
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_vs_vector.out b/examples/simple/igraph_vs_vector.out
new file mode 100644
index 0000000..cb9f83b
--- /dev/null
+++ b/examples/simple/igraph_vs_vector.out
@@ -0,0 +1 @@
+7 0 2 4 0 2 4 2 
diff --git a/examples/simple/igraph_weighted_adjacency.c b/examples/simple/igraph_weighted_adjacency.c
new file mode 100644
index 0000000..5a09ffc
--- /dev/null
+++ b/examples/simple/igraph_weighted_adjacency.c
@@ -0,0 +1,108 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdarg.h>
+
+void print(igraph_t *g) {
+  igraph_vector_t el;
+  long int i, j, n;
+  char ch = igraph_is_directed(g) ? '>' : '-';
+
+  igraph_vector_init(&el, 0);
+  igraph_get_edgelist(g, &el, 0);
+  n = igraph_ecount(g);
+
+  for (i=0, j=0; i<n; i++, j+=2) {
+    printf("%ld --%c %ld: %ld\n",
+      (long)VECTOR(el)[j], ch, (long)VECTOR(el)[j+1], (long)EAN(g, "weight", i)); 
+  }
+  printf("\n");
+
+  igraph_vector_destroy(&el);
+}
+
+int main() {
+  igraph_t g;
+  igraph_matrix_t mat;
+  int m[4][4] = { { 0, 1, 2, 0 }, { 2, 0, 0, 1 }, { 0, 0, 1, 0 }, { 0, 1, 0, 0 } };
+  long int i, j;
+
+  igraph_matrix_init(&mat, 4, 4);
+  for (i=0; i<4; i++) for (j=0; j<4; j++) MATRIX(mat, i, j) = m[i][j];
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+
+  /* [ 0 1 2 0 ]
+     [ 2 0 0 1 ]
+     [ 0 0 1 0 ]
+     [ 0 1 0 0 ] */
+  igraph_weighted_adjacency(&g, &mat, IGRAPH_ADJ_DIRECTED, 0, /*loops=*/ 1);
+  print(&g);
+  igraph_destroy(&g);
+
+  /* [ 0 1 2 0 ]
+     [ - 0 0 1 ]
+     [ - - 1 0 ]
+     [ - - - 0 ] */
+  igraph_weighted_adjacency(&g, &mat, IGRAPH_ADJ_UPPER, 0, /*loops=*/ 1);
+  print(&g);
+  igraph_destroy(&g);
+
+  /* [ 0 - - - ]
+     [ 2 0 - - ]
+     [ 0 0 1 - ]
+     [ 0 1 0 0 ] */
+  igraph_weighted_adjacency(&g, &mat, IGRAPH_ADJ_LOWER, 0, /*loops=*/ 1);
+  print(&g);
+  igraph_destroy(&g);
+
+  /* [ 0 1 0 0 ]
+     [ 1 0 0 1 ]
+     [ 0 0 1 0 ]
+     [ 0 1 0 0 ] */
+  igraph_weighted_adjacency(&g, &mat, IGRAPH_ADJ_MIN, 0, /*loops=*/ 1);
+  print(&g);
+  igraph_destroy(&g);
+
+  /* [ 0 2 2 0 ]
+     [ 2 0 0 1 ]
+     [ 2 0 1 0 ]
+     [ 0 1 0 0 ] */
+  igraph_weighted_adjacency(&g, &mat, IGRAPH_ADJ_MAX, 0, /*loops=*/ 1);
+  print(&g);
+  igraph_destroy(&g);
+
+  /* [ 0 3 2 0 ]
+     [ 3 0 0 2 ]
+     [ 2 0 1 0 ]
+     [ 0 2 0 0 ] */
+  igraph_weighted_adjacency(&g, &mat, IGRAPH_ADJ_PLUS, 0, /*loops=*/ 1);
+  print(&g);
+  igraph_destroy(&g);
+
+  igraph_matrix_destroy(&mat);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 1;
+
+  return 0;
+}
diff --git a/examples/simple/igraph_weighted_adjacency.out b/examples/simple/igraph_weighted_adjacency.out
new file mode 100644
index 0000000..8e7675e
--- /dev/null
+++ b/examples/simple/igraph_weighted_adjacency.out
@@ -0,0 +1,30 @@
+0 --> 1: 1
+0 --> 2: 2
+1 --> 0: 2
+1 --> 3: 1
+2 --> 2: 1
+3 --> 1: 1
+
+0 --- 1: 1
+0 --- 2: 2
+1 --- 3: 1
+2 --- 2: 1
+
+0 --- 1: 2
+2 --- 2: 1
+1 --- 3: 1
+
+0 --- 1: 1
+1 --- 3: 1
+2 --- 2: 1
+
+0 --- 1: 2
+0 --- 2: 2
+1 --- 3: 1
+2 --- 2: 1
+
+0 --- 1: 3
+0 --- 2: 2
+1 --- 3: 2
+2 --- 2: 1
+
diff --git a/examples/simple/igraph_write_graph_leda.c b/examples/simple/igraph_write_graph_leda.c
new file mode 100644
index 0000000..fd22c9b
--- /dev/null
+++ b/examples/simple/igraph_write_graph_leda.c
@@ -0,0 +1,102 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+  int i;
+  igraph_t g;
+  igraph_vector_t values;
+  igraph_strvector_t strvalues;
+  const char* strings[] = {"foo", "bar", "baz", "spam", "eggs", "bacon"};
+
+  /* Setting up attribute handler */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+
+  /* Saving directed graph, no attributes */  
+  igraph_ring(&g, 5, /* directed = */ 1,
+                     /* mutual   = */ 0,
+                     /* circular = */ 1);
+  igraph_write_graph_leda(&g, stdout, 0, 0);
+  printf("===\n");
+  igraph_destroy(&g);
+
+  /* Saving undirected graph, no attributes */
+  igraph_ring(&g, 5, /* directed = */ 0,
+                     /* mutual   = */ 0,
+                     /* circular = */ 1);
+  igraph_write_graph_leda(&g, stdout, 0, 0);
+  printf("===\n");
+  igraph_destroy(&g);
+
+  /* Saving directed graph with vertex attributes */
+  igraph_ring(&g, 5, /* directed = */ 1,
+                     /* mutual   = */ 0,
+                     /* circular = */ 1);
+  igraph_vector_init_seq(&values, 5, 9);
+  SETVANV(&g, "name", &values);
+  igraph_write_graph_leda(&g, stdout, "name", 0);
+  igraph_vector_destroy(&values);
+  printf("===\n");
+  DELVAS(&g);
+  igraph_strvector_init(&strvalues, 5);
+  for (i = 0; i < 5; i++)
+    igraph_strvector_set(&strvalues, i, strings[i]);
+  SETVASV(&g, "name", &strvalues);
+  igraph_write_graph_leda(&g, stdout, "name", 0);
+  igraph_strvector_destroy(&strvalues);
+  printf("===\n");
+  igraph_destroy(&g);
+
+  /* Saving undirected graph with edge attributes */
+  igraph_ring(&g, 5, /* directed = */ 0,
+                     /* mutual   = */ 0,
+                     /* circular = */ 1);
+  igraph_vector_init_seq(&values, 5, 9);
+  SETEANV(&g, "weight", &values);
+  igraph_write_graph_leda(&g, stdout, 0, "weight");
+  igraph_vector_destroy(&values);
+  printf("===\n");
+  DELEAS(&g);
+  igraph_strvector_init(&strvalues, 5);
+  for (i = 0; i < 5; i++)
+    igraph_strvector_set(&strvalues, i, strings[i]);
+  SETEASV(&g, "weight", &strvalues);
+  igraph_write_graph_leda(&g, stdout, 0, "weight");
+  igraph_strvector_destroy(&strvalues);
+  printf("===\n");
+  igraph_destroy(&g);
+
+  /* Saving undirected graph with edge attributes and large weights */
+  igraph_ring(&g, 5, /* directed = */ 0,
+                     /* mutual   = */ 0,
+                     /* circular = */ 1);
+  igraph_vector_init_seq(&values, 123456789, 123456793);
+  SETEANV(&g, "weight", &values);
+  igraph_write_graph_leda(&g, stdout, 0, "weight");
+  igraph_vector_destroy(&values);
+  printf("===\n");
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/igraph_write_graph_leda.out b/examples/simple/igraph_write_graph_leda.out
new file mode 100644
index 0000000..4e9eee4
--- /dev/null
+++ b/examples/simple/igraph_write_graph_leda.out
@@ -0,0 +1,133 @@
+LEDA.GRAPH
+void
+void
+-1
+# Vertices
+5
+|{}|
+|{}|
+|{}|
+|{}|
+|{}|
+# Edges
+5
+1 2 0 |{}|
+2 3 0 |{}|
+3 4 0 |{}|
+4 5 0 |{}|
+5 1 0 |{}|
+===
+LEDA.GRAPH
+void
+void
+-2
+# Vertices
+5
+|{}|
+|{}|
+|{}|
+|{}|
+|{}|
+# Edges
+5
+1 2 0 |{}|
+1 5 0 |{}|
+2 3 0 |{}|
+3 4 0 |{}|
+4 5 0 |{}|
+===
+LEDA.GRAPH
+float
+void
+-1
+# Vertices
+5
+|{5}|
+|{6}|
+|{7}|
+|{8}|
+|{9}|
+# Edges
+5
+1 2 0 |{}|
+2 3 0 |{}|
+3 4 0 |{}|
+4 5 0 |{}|
+5 1 0 |{}|
+===
+LEDA.GRAPH
+string
+void
+-1
+# Vertices
+5
+|{foo}|
+|{bar}|
+|{baz}|
+|{spam}|
+|{eggs}|
+# Edges
+5
+1 2 0 |{}|
+2 3 0 |{}|
+3 4 0 |{}|
+4 5 0 |{}|
+5 1 0 |{}|
+===
+LEDA.GRAPH
+void
+float
+-2
+# Vertices
+5
+|{}|
+|{}|
+|{}|
+|{}|
+|{}|
+# Edges
+5
+1 2 0 |{5}|
+1 5 0 |{9}|
+2 3 0 |{6}|
+3 4 0 |{7}|
+4 5 0 |{8}|
+===
+LEDA.GRAPH
+void
+string
+-2
+# Vertices
+5
+|{}|
+|{}|
+|{}|
+|{}|
+|{}|
+# Edges
+5
+1 2 0 |{foo}|
+1 5 0 |{eggs}|
+2 3 0 |{bar}|
+3 4 0 |{baz}|
+4 5 0 |{spam}|
+===
+LEDA.GRAPH
+void
+float
+-2
+# Vertices
+5
+|{}|
+|{}|
+|{}|
+|{}|
+|{}|
+# Edges
+5
+1 2 0 |{123456789}|
+1 5 0 |{123456793}|
+2 3 0 |{123456790}|
+3 4 0 |{123456791}|
+4 5 0 |{123456792}|
+===
diff --git a/examples/simple/igraph_write_graph_lgl.c b/examples/simple/igraph_write_graph_lgl.c
new file mode 100644
index 0000000..c67dd92
--- /dev/null
+++ b/examples/simple/igraph_write_graph_lgl.c
@@ -0,0 +1,48 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+
+  /* igraph_t g; */
+  /* igraph_error_handler_t *oldhandler; */
+  /* FILE *ofile; */
+  /* int ret; */
+
+  /* This is not used right now, as we don't have attributes */
+  
+  /* Testing error handling */  
+/*   igraph_barabasi_game(&g, 10, 1, 0, 0, IGRAPH_DIRECTED); */
+/*   oldhandler=igraph_set_error_handler(igraph_error_handler_ignore); */
+/*   ofile=fopen("test.txt", "w"); */
+/*   ret=igraph_write_graph_lgl(&g, ofile, "names", "weights", 1); */
+/*   if (ret != IGRAPH_EINVAL) { */
+/*     return 1; */
+/*   } */
+/*   fclose(ofile); */
+/*   igraph_destroy(&g); */
+/*   igraph_set_error_handler(oldhandler); */
+
+  return 0;
+}
diff --git a/examples/simple/igraph_write_graph_pajek.c b/examples/simple/igraph_write_graph_pajek.c
new file mode 100644
index 0000000..3fd9fde
--- /dev/null
+++ b/examples/simple/igraph_write_graph_pajek.c
@@ -0,0 +1,75 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_strvector_t names;
+
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+  
+  /* save a simple ring graph */
+  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0 /* mutual */, 1 /* circular */);
+  igraph_write_graph_pajek(&g, stdout);
+  
+  /* add some vertex attributes */
+  igraph_strvector_init(&names, 0);
+  igraph_strvector_add(&names, "A");
+  igraph_strvector_add(&names, "B");
+  igraph_strvector_add(&names, "C");
+  igraph_strvector_add(&names, "D");
+  igraph_strvector_add(&names, "E");
+  igraph_strvector_add(&names, "F");
+  igraph_strvector_add(&names, "G");
+  igraph_strvector_add(&names, "H");
+  igraph_strvector_add(&names, "I");
+  igraph_strvector_add(&names, "J");
+  SETVASV(&g, "id", &names);
+  igraph_strvector_destroy(&names);
+
+  /* save the graph with vertex names */
+  igraph_write_graph_pajek(&g, stdout);
+
+  igraph_strvector_init(&names, 0);
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "escaping spaces");
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "escaping \\backslashes\\");
+  igraph_strvector_add(&names, "square");
+  igraph_strvector_add(&names, "escaping \"quotes\"");
+  SETVASV(&g, "shape", &names);
+  igraph_strvector_destroy(&names);
+
+  /* save the graph with escaped shapes */
+  igraph_write_graph_pajek(&g, stdout);
+
+  /* destroy the graph */
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/igraph_write_graph_pajek.out b/examples/simple/igraph_write_graph_pajek.out
new file mode 100644
index 0000000..5531703
--- /dev/null
+++ b/examples/simple/igraph_write_graph_pajek.out
@@ -0,0 +1,56 @@
+*Vertices 10
+*Arcs
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+10 1
+*Vertices 10
+1 "A"
+2 "B"
+3 "C"
+4 "D"
+5 "E"
+6 "F"
+7 "G"
+8 "H"
+9 "I"
+10 "J"
+*Arcs
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+10 1
+*Vertices 10
+1 "A" "square"
+2 "B" "square"
+3 "C" "square"
+4 "D" "square"
+5 "E" "escaping spaces"
+6 "F" "square"
+7 "G" "square"
+8 "H" "escaping \\backslashes\\"
+9 "I" "square"
+10 "J" "escaping \"quotes\""
+*Arcs
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+10 1
diff --git a/examples/simple/indheap.c b/examples/simple/indheap.c
new file mode 100644
index 0000000..e361e61
--- /dev/null
+++ b/examples/simple/indheap.c
@@ -0,0 +1,31 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  /* This is not used by any functions any more,
+     no need to test it right now */
+  return 0;
+}
diff --git a/examples/simple/input.dl b/examples/simple/input.dl
new file mode 100644
index 0000000..50d75dd
--- /dev/null
+++ b/examples/simple/input.dl
@@ -0,0 +1,104 @@
+DL n=66
+format = edgelist1
+labels embedded:
+data:
+R1 C1
+R1 C5
+R1 C7
+R1 C9
+R1 C11
+R1 C12
+R1 C13
+R1 C16
+R1 C17
+R1 C23
+R1 C24
+R1 C25
+R1 C28
+R2 C8
+R2 C11
+R2 C12
+R2 C17
+R2 C20
+R2 C24
+R2 C26
+R2 C27
+R2 C28
+R3 C2
+R3 C3
+R4 C17
+R4 C23
+R5 C6
+R5 C13
+R5 C19
+R5 C22
+R5 C24
+R6 C14
+R7 C17
+R7 C22
+R7 C26
+R8 C1
+R8 C17
+R8 C19
+R8 C22
+R9 C19
+R9 C22
+R9 C23
+R10 C6
+R10 C18
+R10 C28
+R11 C25
+R12 C25
+R13 C13
+R13 C19
+R14 C1
+R14 C4
+R14 C21
+R15 C15
+R15 C17
+R16 C17
+R16 C23
+R17 C4
+R18 C28
+R19 C6
+R20 C17
+R21 C28
+R22 C4
+R23 C6
+R23 C17
+R24 C11
+R25 C4
+R26 C16
+R26 C20
+R27 C1
+R27 C2
+R27 C5
+R27 C17
+R28 C13
+R28 C20
+R28 C21
+R29 C12
+R30 C1
+R30 C2
+R30 C22
+R31 C10
+R31 C13
+R31 C15
+R32 C6
+R32 C22
+R32 C28
+R33 C14
+R33 C23
+R34 C3
+R34 C28
+R35 C28
+R36 C13
+R36 C20
+R36 C27
+R36 C28
+R37 C28
+R38 C8
+R38 C10
+R38 C13
+R38 C14
+R38 C23
diff --git a/examples/simple/iso_b03_m1000.A00 b/examples/simple/iso_b03_m1000.A00
new file mode 100644
index 0000000..196b400
Binary files /dev/null and b/examples/simple/iso_b03_m1000.A00 differ
diff --git a/examples/simple/karate.gml b/examples/simple/karate.gml
new file mode 100644
index 0000000..ecafe9c
--- /dev/null
+++ b/examples/simple/karate.gml
@@ -0,0 +1,530 @@
+Creator "Mark Newman on Fri Jul 21 12:39:27 2006"
+graph
+[
+  node
+  [
+    id 1
+  ]
+  node
+  [
+    id 2
+  ]
+  node
+  [
+    id 3
+  ]
+  node
+  [
+    id 4
+  ]
+  node
+  [
+    id 5
+  ]
+  node
+  [
+    id 6
+  ]
+  node
+  [
+    id 7
+  ]
+  node
+  [
+    id 8
+  ]
+  node
+  [
+    id 9
+  ]
+  node
+  [
+    id 10
+  ]
+  node
+  [
+    id 11
+  ]
+  node
+  [
+    id 12
+  ]
+  node
+  [
+    id 13
+  ]
+  node
+  [
+    id 14
+  ]
+  node
+  [
+    id 15
+  ]
+  node
+  [
+    id 16
+  ]
+  node
+  [
+    id 17
+  ]
+  node
+  [
+    id 18
+  ]
+  node
+  [
+    id 19
+  ]
+  node
+  [
+    id 20
+  ]
+  node
+  [
+    id 21
+  ]
+  node
+  [
+    id 22
+  ]
+  node
+  [
+    id 23
+  ]
+  node
+  [
+    id 24
+  ]
+  node
+  [
+    id 25
+  ]
+  node
+  [
+    id 26
+  ]
+  node
+  [
+    id 27
+  ]
+  node
+  [
+    id 28
+  ]
+  node
+  [
+    id 29
+  ]
+  node
+  [
+    id 30
+  ]
+  node
+  [
+    id 31
+  ]
+  node
+  [
+    id 32
+  ]
+  node
+  [
+    id 33
+  ]
+  node
+  [
+    id 34
+  ]
+  edge
+  [
+    source 2
+    target 1
+  ]
+  edge
+  [
+    source 3
+    target 1
+  ]
+  edge
+  [
+    source 3
+    target 2
+  ]
+  edge
+  [
+    source 4
+    target 1
+  ]
+  edge
+  [
+    source 4
+    target 2
+  ]
+  edge
+  [
+    source 4
+    target 3
+  ]
+  edge
+  [
+    source 5
+    target 1
+  ]
+  edge
+  [
+    source 6
+    target 1
+  ]
+  edge
+  [
+    source 7
+    target 1
+  ]
+  edge
+  [
+    source 7
+    target 5
+  ]
+  edge
+  [
+    source 7
+    target 6
+  ]
+  edge
+  [
+    source 8
+    target 1
+  ]
+  edge
+  [
+    source 8
+    target 2
+  ]
+  edge
+  [
+    source 8
+    target 3
+  ]
+  edge
+  [
+    source 8
+    target 4
+  ]
+  edge
+  [
+    source 9
+    target 1
+  ]
+  edge
+  [
+    source 9
+    target 3
+  ]
+  edge
+  [
+    source 10
+    target 3
+  ]
+  edge
+  [
+    source 11
+    target 1
+  ]
+  edge
+  [
+    source 11
+    target 5
+  ]
+  edge
+  [
+    source 11
+    target 6
+  ]
+  edge
+  [
+    source 12
+    target 1
+  ]
+  edge
+  [
+    source 13
+    target 1
+  ]
+  edge
+  [
+    source 13
+    target 4
+  ]
+  edge
+  [
+    source 14
+    target 1
+  ]
+  edge
+  [
+    source 14
+    target 2
+  ]
+  edge
+  [
+    source 14
+    target 3
+  ]
+  edge
+  [
+    source 14
+    target 4
+  ]
+  edge
+  [
+    source 17
+    target 6
+  ]
+  edge
+  [
+    source 17
+    target 7
+  ]
+  edge
+  [
+    source 18
+    target 1
+  ]
+  edge
+  [
+    source 18
+    target 2
+  ]
+  edge
+  [
+    source 20
+    target 1
+  ]
+  edge
+  [
+    source 20
+    target 2
+  ]
+  edge
+  [
+    source 22
+    target 1
+  ]
+  edge
+  [
+    source 22
+    target 2
+  ]
+  edge
+  [
+    source 26
+    target 24
+  ]
+  edge
+  [
+    source 26
+    target 25
+  ]
+  edge
+  [
+    source 28
+    target 3
+  ]
+  edge
+  [
+    source 28
+    target 24
+  ]
+  edge
+  [
+    source 28
+    target 25
+  ]
+  edge
+  [
+    source 29
+    target 3
+  ]
+  edge
+  [
+    source 30
+    target 24
+  ]
+  edge
+  [
+    source 30
+    target 27
+  ]
+  edge
+  [
+    source 31
+    target 2
+  ]
+  edge
+  [
+    source 31
+    target 9
+  ]
+  edge
+  [
+    source 32
+    target 1
+  ]
+  edge
+  [
+    source 32
+    target 25
+  ]
+  edge
+  [
+    source 32
+    target 26
+  ]
+  edge
+  [
+    source 32
+    target 29
+  ]
+  edge
+  [
+    source 33
+    target 3
+  ]
+  edge
+  [
+    source 33
+    target 9
+  ]
+  edge
+  [
+    source 33
+    target 15
+  ]
+  edge
+  [
+    source 33
+    target 16
+  ]
+  edge
+  [
+    source 33
+    target 19
+  ]
+  edge
+  [
+    source 33
+    target 21
+  ]
+  edge
+  [
+    source 33
+    target 23
+  ]
+  edge
+  [
+    source 33
+    target 24
+  ]
+  edge
+  [
+    source 33
+    target 30
+  ]
+  edge
+  [
+    source 33
+    target 31
+  ]
+  edge
+  [
+    source 33
+    target 32
+  ]
+  edge
+  [
+    source 34
+    target 9
+  ]
+  edge
+  [
+    source 34
+    target 10
+  ]
+  edge
+  [
+    source 34
+    target 14
+  ]
+  edge
+  [
+    source 34
+    target 15
+  ]
+  edge
+  [
+    source 34
+    target 16
+  ]
+  edge
+  [
+    source 34
+    target 19
+  ]
+  edge
+  [
+    source 34
+    target 20
+  ]
+  edge
+  [
+    source 34
+    target 21
+  ]
+  edge
+  [
+    source 34
+    target 23
+  ]
+  edge
+  [
+    source 34
+    target 24
+  ]
+  edge
+  [
+    source 34
+    target 27
+  ]
+  edge
+  [
+    source 34
+    target 28
+  ]
+  edge
+  [
+    source 34
+    target 29
+  ]
+  edge
+  [
+    source 34
+    target 30
+  ]
+  edge
+  [
+    source 34
+    target 31
+  ]
+  edge
+  [
+    source 34
+    target 32
+  ]
+  edge
+  [
+    source 34
+    target 33
+  ]
+]
diff --git a/examples/simple/levc-stress.c b/examples/simple/levc-stress.c
new file mode 100644
index 0000000..9b0518a
--- /dev/null
+++ b/examples/simple/levc-stress.c
@@ -0,0 +1,66 @@
+/* -*- mode: C -*-  */
+/* vim:set sw=2 ts=2 sts=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 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
+
+*/
+
+/* This is a test for bug #1002140, reported by Luiz Fernando 
+   Bittencourt: https://bugs.launchpad.net/igraph/+bug/1002140 */
+
+#include <igraph.h>
+
+int main() {
+  
+  int k;	
+  for(k=0; k<20; k++) { 
+    igraph_t g;
+    igraph_matrix_t merges;
+    igraph_vector_t membership;
+    igraph_arpack_options_t options;
+    double modularity;
+    igraph_vector_t history;
+    FILE *DLFile = fopen("input.dl","r");		
+    
+    igraph_read_graph_dl(&g, DLFile, /*directed=*/ 0);
+    fclose(DLFile);
+		
+    igraph_matrix_init(&merges, 0, 0);
+    igraph_vector_init(&membership, 0);
+    igraph_vector_init(&history, 0);
+    igraph_arpack_options_init(&options);
+
+    igraph_community_leading_eigenvector(&g, /*weights=*/ 0, &merges, 
+					 &membership, igraph_vcount(&g), 
+					 &options, &modularity,
+					 /*start=*/ 0, /*eigenvalues=*/ 0, 
+					 /*eigenvectors=*/ 0, &history,
+					 /*callback=*/ 0, 
+					 /*callback_extra=*/ 0);
+
+    igraph_vector_destroy(&history);
+    igraph_vector_destroy(&membership);
+    igraph_matrix_destroy(&merges);
+    igraph_destroy(&g);
+  }
+  
+  return 0;
+}
+  
diff --git a/examples/simple/lineendings.c b/examples/simple/lineendings.c
new file mode 100644
index 0000000..a641d37
--- /dev/null
+++ b/examples/simple/lineendings.c
@@ -0,0 +1,71 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  
+  igraph_t g;
+  FILE *ifile;
+  
+  /* turn on attribute handling */
+/*   igraph_i_set_attribute_table(&igraph_cattribute_table); */
+  
+  ifile=fopen("pajek1.net", "r");
+  if (ifile==0) {
+    return 1;
+  }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  igraph_write_graph_pajek(&g, stdout);
+  igraph_destroy(&g);
+
+  ifile=fopen("pajek2.net", "r");
+  if (ifile==0) {
+    return 2;
+  }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  igraph_write_graph_pajek(&g, stdout);
+  igraph_destroy(&g);
+  
+  ifile=fopen("pajek3.net", "r");
+  if (ifile==0) {
+    return 3;
+  }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  igraph_write_graph_pajek(&g, stdout);
+  igraph_destroy(&g);
+
+  ifile=fopen("pajek4.net", "r");
+  if (ifile==0) {
+    return 4;
+  }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  igraph_write_graph_pajek(&g, stdout);
+  igraph_destroy(&g);
+ 
+  return 0;
+}
diff --git a/examples/simple/lineendings.out b/examples/simple/lineendings.out
new file mode 100644
index 0000000..9d7252a
--- /dev/null
+++ b/examples/simple/lineendings.out
@@ -0,0 +1,44 @@
+*Vertices 10
+*Edges
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+*Vertices 10
+*Edges
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+*Vertices 10
+*Edges
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
+*Vertices 10
+*Edges
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
diff --git a/examples/simple/matrix.c b/examples/simple/matrix.c
new file mode 100644
index 0000000..970a346
--- /dev/null
+++ b/examples/simple/matrix.c
@@ -0,0 +1,173 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_matrix(igraph_matrix_t *m, FILE *f) {
+  long int i, j;
+  for (i=0; i<igraph_matrix_nrow(m); i++) {
+    for (j=0; j<igraph_matrix_ncol(m); j++) {
+      fprintf(f, " %li", (long int)MATRIX(*m, i, j));
+    }
+    fprintf(f, "\n");
+  }  
+}
+
+int main() {
+  igraph_matrix_t m, m1;
+  long int i, j, k;
+  
+  /* igraph_matrix_init, igraph_matrix_destroy */
+  igraph_matrix_init(&m, 10, 10);
+  igraph_matrix_destroy(&m);
+  
+  igraph_matrix_init(&m, 0, 0);
+  igraph_matrix_destroy(&m);
+  
+  /* igraph_matrix_ncol, igraph_matrix_nrow */
+  igraph_matrix_init(&m, 10, 5);
+  if (igraph_matrix_nrow(&m) != 10) {
+    return 1;
+  }
+  if (igraph_matrix_ncol(&m) != 5) {
+    return 2;
+  }
+
+  /* igraph_matrix_size, igraph_matrix_resize */
+  igraph_matrix_resize(&m, 6, 5);
+  if (igraph_matrix_size(&m) != 30) {
+    return 3;
+  }
+  if (igraph_matrix_nrow(&m) != 6) {
+    return 4;
+  }
+  if (igraph_matrix_ncol(&m) != 5) {
+    return 5;
+  }
+  igraph_matrix_resize(&m, 2, 4);
+  if (igraph_matrix_nrow(&m) != 2) {
+    return 6;
+  }
+  if (igraph_matrix_ncol(&m) != 4) {
+    return 7;
+  }
+  igraph_matrix_destroy(&m);
+  
+  /* MATRIX, igraph_matrix_null */
+  igraph_matrix_init(&m, 3, 4);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    for (j=0; j<igraph_matrix_ncol(&m); j++) {
+      MATRIX(m, i, j)= i+1;
+    }
+  }
+  print_matrix(&m, stdout);
+  igraph_matrix_null(&m);
+  print_matrix(&m, stdout);
+  igraph_matrix_destroy(&m);
+  
+  /* igraph_matrix_add_cols, igraph_matrix_add_rows */
+  igraph_matrix_init(&m, 4, 3);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    for (j=0; j<igraph_matrix_ncol(&m); j++) {
+      MATRIX(m, i, j)= (i+1)*(j+1);
+    }
+  }
+  igraph_matrix_add_cols(&m, 2);
+  igraph_matrix_add_rows(&m, 2);
+  if (igraph_matrix_ncol(&m) != 5) {
+    return 8;
+  }
+  if (igraph_matrix_nrow(&m) != 6) {
+    return 9;
+  }
+  igraph_matrix_destroy(&m);
+
+  /* igraph_matrix_remove_col */
+  igraph_matrix_init(&m, 5, 3);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    for (j=0; j<igraph_matrix_ncol(&m); j++) {
+      MATRIX(m, i, j)= (i+1)*(j+1);
+    }
+  }
+  igraph_matrix_remove_col(&m, 0);
+  print_matrix(&m, stdout);
+  igraph_matrix_remove_col(&m, 1);
+  print_matrix(&m, stdout);
+  igraph_matrix_destroy(&m);
+
+  /* TODO: igraph_matrix_permdelete_rows */
+  /* TODO: igraph_matrix_delete_rows_neg */
+
+  /* igraph_matrix_copy */
+  igraph_matrix_init(&m, 2, 3);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    for (j=0; j<igraph_matrix_ncol(&m); j++) {
+      MATRIX(m, i, j)= (i+1)*(j+1);
+    }
+  }
+  igraph_matrix_copy(&m1, &m);
+  print_matrix(&m1, stdout);
+  igraph_matrix_destroy(&m);
+  igraph_matrix_destroy(&m1);
+
+  /* in-place transpose */
+  igraph_matrix_init(&m,5,2);
+  k=0;
+  for (i=0; i<igraph_matrix_ncol(&m); i++) {
+    for (j=0; j<igraph_matrix_nrow(&m); j++) {
+      MATRIX(m, j, i)=k++;
+    }
+  }
+  print_matrix(&m, stdout);
+  igraph_matrix_transpose(&m);
+  print_matrix(&m, stdout);
+  igraph_matrix_destroy(&m);
+
+  igraph_matrix_init(&m,5,1);
+  k=0;
+  for (i=0; i<igraph_matrix_ncol(&m); i++) {
+    for (j=0; j<igraph_matrix_nrow(&m); j++) {
+      MATRIX(m, j, i)=k++;
+    }
+  }
+  print_matrix(&m, stdout);
+  igraph_matrix_transpose(&m);
+  print_matrix(&m, stdout);
+  igraph_matrix_destroy(&m);
+
+  igraph_matrix_init(&m,1,5);
+  k=0;
+  for (i=0; i<igraph_matrix_ncol(&m); i++) {
+    for (j=0; j<igraph_matrix_nrow(&m); j++) {
+      MATRIX(m, j, i)=k++;
+    }
+  }
+  print_matrix(&m, stdout);
+  igraph_matrix_transpose(&m);
+  print_matrix(&m, stdout);
+  igraph_matrix_destroy(&m);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 10;
+
+  return 0;
+}
diff --git a/examples/simple/matrix.out b/examples/simple/matrix.out
new file mode 100644
index 0000000..003c81d
--- /dev/null
+++ b/examples/simple/matrix.out
@@ -0,0 +1,37 @@
+ 1 1 1 1
+ 2 2 2 2
+ 3 3 3 3
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 2 3
+ 4 6
+ 6 9
+ 8 12
+ 10 15
+ 2
+ 4
+ 6
+ 8
+ 10
+ 1 2 3
+ 2 4 6
+ 0 5
+ 1 6
+ 2 7
+ 3 8
+ 4 9
+ 0 1 2 3 4
+ 5 6 7 8 9
+ 0
+ 1
+ 2
+ 3
+ 4
+ 0 1 2 3 4
+ 0 1 2 3 4
+ 0
+ 1
+ 2
+ 3
+ 4
diff --git a/examples/simple/matrix2.c b/examples/simple/matrix2.c
new file mode 100644
index 0000000..b24ae22
--- /dev/null
+++ b/examples/simple/matrix2.c
@@ -0,0 +1,316 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdio.h>
+
+void print_matrix(igraph_matrix_t *m) {
+  long int i, j;
+  for (i=0; i<igraph_matrix_nrow(m); i++) {
+    for (j=0; j<igraph_matrix_ncol(m); j++) {
+      printf(" %g", MATRIX(*m, i, j));
+    }
+    printf("\n");
+  }  
+}
+
+void print_vector(igraph_vector_t *v) {
+  long int i, n=igraph_vector_size(v);
+  for (i=0; i<n; i++) {
+    printf(" %g", VECTOR(*v)[i]);
+  }
+  printf("\n");
+}
+
+void byrow(igraph_matrix_t *m) {
+  long int r=igraph_matrix_nrow(m), c=igraph_matrix_ncol(m);
+  long int n=0, i, j;
+  for (i=0; i<r; i++) {
+    for (j=0; j<c; j++) {
+      MATRIX(*m, i, j) = n++;
+    }
+  }
+}
+
+#define apply(m,a,b) \
+   for (i=0; i<igraph_matrix_nrow(&(m)); i++) { \
+     for (j=0; j<igraph_matrix_ncol(&(m)); j++) { \
+        (a); \
+     } \
+     (b); \
+   }
+
+
+int main() {
+  igraph_matrix_t m, m2;
+  igraph_vector_t v;
+  long int i, j, i2, j2;
+  igraph_real_t r1, r2;
+
+  igraph_matrix_init(&m, 4, 3);
+  byrow(&m);
+  
+  /* igraph_matrix_e */
+  printf("igraph_matrix_e\n");
+  apply(m, printf("%i ", (int)igraph_matrix_e(&m, i, j)), printf("\n"));
+
+  /* igraph_matrix_e_ptr */
+  printf("igraph_matrix_e_ptr\n");
+  apply(m, printf("%i ", (int)igraph_matrix_e_ptr(&m, i, j)[0]), printf("\n"));
+
+  /* igraph_matrix_set */
+  printf("igraph_matrix_set\n");
+  apply(m, igraph_matrix_set(&m, i, j, i), (void) 0 );
+  print_matrix(&m);
+  apply(m, igraph_matrix_set(&m, i, j, j), (void) 0 );
+  print_matrix(&m);
+
+  /* igraph_matrix_fill */
+  printf("igraph_matrix_fill\n");
+  igraph_matrix_fill(&m, 42);
+  print_matrix(&m);
+  igraph_matrix_fill(&m, -42.1);
+  print_matrix(&m);
+  
+  /* igraph_matrix_update */
+  printf("igraph_matrix_update\n");
+  igraph_matrix_init(&m2, 0, 0);
+  byrow(&m);
+  igraph_matrix_update(&m2, &m);
+  print_matrix(&m2);
+
+  /* igraph_matrix_rbind */
+  printf("igraph_matrix_rbind\n");
+  igraph_matrix_rbind(&m2, &m);
+  print_matrix(&m2);
+  printf("\n");
+  igraph_matrix_resize(&m, 0, igraph_matrix_ncol(&m2));
+  igraph_matrix_rbind(&m2, &m);
+  print_matrix(&m2);
+  printf("\n");
+  igraph_matrix_rbind(&m, &m2);
+  print_matrix(&m);
+
+  /* igraph_matrix_cbind */
+  printf("igraph_matrix_cbind\n");
+  igraph_matrix_resize(&m, 4, 3);
+  igraph_matrix_resize(&m2, 4, 2);
+  byrow(&m);
+  byrow(&m2);
+  igraph_matrix_cbind(&m, &m2);
+  print_matrix(&m);
+
+  /* igraph_matrix_swap */
+  printf("igraph_matrix_swap\n");
+  igraph_matrix_update(&m, &m2);
+  igraph_matrix_null(&m);
+  igraph_matrix_swap(&m, &m2);
+  print_matrix(&m);
+  print_matrix(&m2);
+  
+  /* igraph_matrix_get_row */
+  /* igraph_matrix_set_row */
+  printf("igraph_matrix_get_row\n");
+  printf("igraph_matrix_set_row\n");
+  igraph_vector_init(&v, 0);
+  for (i=0; i<igraph_matrix_nrow(&m); i++) {
+    igraph_matrix_get_row(&m, &v, i);
+    igraph_matrix_set_row(&m2, &v, i);
+  }
+  print_matrix(&m2);
+
+  /* igraph_matrix_set_col */
+  printf("igraph_matrix_set_col\n");
+  igraph_matrix_null(&m2);
+  for (i=0; i<igraph_matrix_ncol(&m); i++) {
+    igraph_matrix_get_col(&m, &v, i);
+    igraph_matrix_set_col(&m2, &v, i);
+  }
+  print_matrix(&m2);
+  
+  /* igraph_matrix_swap_rows */
+  printf("igraph_matrix_swap_rows\n");
+  igraph_matrix_swap_rows(&m2, 0, 0);
+  igraph_matrix_swap_rows(&m2, 0, 2);
+  print_matrix(&m2);
+  
+  /* igraph_matrix_swap_cols */
+  printf("igraph_matrix_swap_cols\n");
+  igraph_matrix_swap_cols(&m2, 0, 0);
+  igraph_matrix_swap_cols(&m2, 0, 1);
+  print_matrix(&m2);
+
+  /* igraph_matrix_add_constant */
+  printf("igraph_matrix_add_constant\n");
+  igraph_matrix_add_constant(&m2, 0);
+  print_matrix(&m2);  
+  igraph_matrix_add_constant(&m2, -1);
+  print_matrix(&m2);
+  
+  /* igraph_matrix_add */
+  printf("igraph_matrix_add\n");
+  byrow(&m2);
+  byrow(&m);
+  igraph_matrix_add(&m2, &m);
+  print_matrix(&m2);
+
+  /* igraph_matrix_sub */
+  printf("igraph_matrix_sub\n");
+  igraph_matrix_sub(&m2, &m);
+  print_matrix(&m2);
+
+  /* igraph_matrix_mul_elements */
+  printf("igraph_matrix_mul_elements\n");
+  igraph_matrix_mul_elements(&m2, &m);
+  print_matrix(&m2);
+
+  /* igraph_matrix_div_elements */
+  printf("igraph_matrix_div_elements\n");
+  igraph_matrix_fill(&m, 2);
+  igraph_matrix_div_elements(&m2, &m);
+  print_matrix(&m2);
+
+  /* igraph_matrix_min */
+  printf("igraph_matrix_min\n");
+  if (igraph_matrix_min(&m2) != 0) {
+    return 1;
+  }
+  if (igraph_matrix_min(&m) != 2) {
+    return 1;
+  }
+
+  /* igraph_matrix_which_min */
+  printf("igraph_matrix_which_min\n");
+  igraph_matrix_which_min(&m2, &i, &j);
+  if (i != 0 || j != 0) { return 2; }
+  MATRIX(m2,0,1) = -1;
+  igraph_matrix_which_min(&m2, &i, &j);
+  if (i != 0 || j != 1) { return 2; }
+  MATRIX(m2,3,1) = -2;
+  igraph_matrix_which_min(&m2, &i, &j);
+  if (i != 3 || j != 1) { return 2; }
+
+  /* igraph_matrix_which_max */
+  printf("igraph_matrix_which_max\n");
+  MATRIX(m2,3,0) = 100;
+  igraph_matrix_which_max(&m2, &i, &j);
+  if (i != 3 || j != 0) { return 3; }
+  
+  /* igraph_matrix_minmax */
+  printf("igraph_matrix_minmax\n");
+  igraph_matrix_minmax(&m2, &r1, &r2);
+  printf("%g %g\n", r1, r2);
+  
+  /* igraph_matrix_which_minmax */
+  printf("igraph_matrix_which_minmax\n");
+  igraph_matrix_which_minmax(&m2, &i, &j, &i2, &j2);
+  if (i != 3 || j != 1 || i2 != 3 || j2 != 0) { return 4; }
+
+  /* igraph_matrix_isnull */
+  printf("igraph_matrix_isnull\n");
+  if (igraph_matrix_isnull(&m2)) { return 5; }
+  igraph_matrix_null(&m);
+  if (!igraph_matrix_isnull(&m)) { return 5; }
+  igraph_matrix_resize(&m2, 5, 0);
+  if (!igraph_matrix_isnull(&m2)) { return 5; }  
+  
+  /* igraph_matrix_empty */
+  printf("igraph_matrix_empty\n");
+  if (!igraph_matrix_empty(&m2)) { return 6; }
+  igraph_matrix_resize(&m2, 5, 5);
+  if (igraph_matrix_empty(&m2)) { return 6; }
+
+  /* igraph_matrix_is_symmetric */
+  printf("igraph_matrix_is_symmetric\n");
+  byrow(&m2);
+  if (igraph_matrix_is_symmetric(&m2)) { return 7; }
+  igraph_matrix_update(&m, &m2);
+  igraph_matrix_transpose(&m);
+  igraph_matrix_add(&m, &m2);
+  if (!igraph_matrix_is_symmetric(&m)) { return 7; }
+
+  /* igraph_matrix_prod */
+  printf("igraph_matrix_prod\n");
+  igraph_matrix_resize(&m, 3,2);
+  byrow(&m);
+  igraph_matrix_add_constant(&m, 1);
+  print_matrix(&m);
+  printf("product: %g\n", igraph_matrix_prod(&m));
+
+  /* igraph_matrix_rowsum */
+  printf("igraph_matrix_rowsum\n");
+  igraph_matrix_rowsum(&m, &v);
+  print_vector(&v);
+
+  /* igraph_matrix_colsum */
+  printf("igraph_matrix_colsum\n");
+  igraph_matrix_colsum(&m, &v);
+  print_vector(&v);
+
+  /* igraph_matrix_contains */
+  printf("igraph_matrix_contains\n");
+  if (igraph_matrix_contains(&m, 0)) { return 8; }
+  if (igraph_matrix_contains(&m, 6.0001)) { return 8; }
+  if (igraph_matrix_contains(&m, 7)) { return 8; }
+  if (!igraph_matrix_contains(&m, 1)) { return 8; }
+  if (!igraph_matrix_contains(&m, 6)) { return 8; }
+  
+  /* igraph_matrix_search */
+  printf("igraph_matrix_search\n");
+  if (!igraph_matrix_search(&m, 0, 6.0, &i2, &i, &j)) { return 9; }
+  if (i2 != 5 || i != 2 || j != 1) { return 9; }
+  
+  /* igraph_matrix_remove_row */
+  printf("igraph_matrix_remove_row\n");
+  igraph_matrix_remove_row(&m, 1);
+  print_matrix(&m);
+  igraph_matrix_resize(&m,5,4);
+  byrow(&m);
+  igraph_matrix_remove_row(&m, 4);
+  print_matrix(&m);
+  igraph_matrix_remove_row(&m, 0);
+  print_matrix(&m);
+
+  /* igraph_matrix_select_cols */
+  printf("igraph_matrix_select_cols\n");
+  igraph_matrix_resize(&m, 6, 5);
+  apply(m, igraph_matrix_set(&m, i, j, j), (void) 0 );
+  igraph_vector_resize(&v, 3);
+  VECTOR(v)[0]=0; VECTOR(v)[1]=4; VECTOR(v)[2]=2;
+  igraph_matrix_select_cols(&m, &m2, &v);
+  print_matrix(&m2);
+  igraph_vector_resize(&v, 1);
+  igraph_matrix_select_cols(&m, &m2, &v);
+  print_matrix(&m2);
+  igraph_vector_clear(&v);
+  igraph_matrix_select_cols(&m, &m2, &v);
+  if (!igraph_matrix_empty(&m2)) { return 9; }
+
+  igraph_vector_destroy(&v);
+  igraph_matrix_destroy(&m2);
+  igraph_matrix_destroy(&m);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 10;
+
+  return 0;
+}
diff --git a/examples/simple/matrix2.out b/examples/simple/matrix2.out
new file mode 100644
index 0000000..ac2a8d0
--- /dev/null
+++ b/examples/simple/matrix2.out
@@ -0,0 +1,167 @@
+igraph_matrix_e
+0 1 2 
+3 4 5 
+6 7 8 
+9 10 11 
+igraph_matrix_e_ptr
+0 1 2 
+3 4 5 
+6 7 8 
+9 10 11 
+igraph_matrix_set
+ 0 0 0
+ 1 1 1
+ 2 2 2
+ 3 3 3
+ 0 1 2
+ 0 1 2
+ 0 1 2
+ 0 1 2
+igraph_matrix_fill
+ 42 42 42
+ 42 42 42
+ 42 42 42
+ 42 42 42
+ -42.1 -42.1 -42.1
+ -42.1 -42.1 -42.1
+ -42.1 -42.1 -42.1
+ -42.1 -42.1 -42.1
+igraph_matrix_update
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+igraph_matrix_rbind
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+ 0 1 2
+ 3 4 5
+ 6 7 8
+ 9 10 11
+igraph_matrix_cbind
+ 0 1 2 0 1
+ 3 4 5 2 3
+ 6 7 8 4 5
+ 9 10 11 6 7
+igraph_matrix_swap
+ 0 1
+ 2 3
+ 4 5
+ 6 7
+ 0 0
+ 0 0
+ 0 0
+ 0 0
+igraph_matrix_get_row
+igraph_matrix_set_row
+ 0 1
+ 2 3
+ 4 5
+ 6 7
+igraph_matrix_set_col
+ 0 1
+ 2 3
+ 4 5
+ 6 7
+igraph_matrix_swap_rows
+ 4 5
+ 2 3
+ 0 1
+ 6 7
+igraph_matrix_swap_cols
+ 5 4
+ 3 2
+ 1 0
+ 7 6
+igraph_matrix_add_constant
+ 5 4
+ 3 2
+ 1 0
+ 7 6
+ 4 3
+ 2 1
+ 0 -1
+ 6 5
+igraph_matrix_add
+ 0 2
+ 4 6
+ 8 10
+ 12 14
+igraph_matrix_sub
+ 0 1
+ 2 3
+ 4 5
+ 6 7
+igraph_matrix_mul_elements
+ 0 1
+ 4 9
+ 16 25
+ 36 49
+igraph_matrix_div_elements
+ 0 0.5
+ 2 4.5
+ 8 12.5
+ 18 24.5
+igraph_matrix_min
+igraph_matrix_which_min
+igraph_matrix_which_max
+igraph_matrix_minmax
+-2 100
+igraph_matrix_which_minmax
+igraph_matrix_isnull
+igraph_matrix_empty
+igraph_matrix_is_symmetric
+igraph_matrix_prod
+ 1 2
+ 3 4
+ 5 6
+product: 720
+igraph_matrix_rowsum
+ 3 7 11
+igraph_matrix_colsum
+ 9 12
+igraph_matrix_contains
+igraph_matrix_search
+igraph_matrix_remove_row
+ 1 2
+ 5 6
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+ 4 5 6 7
+ 8 9 10 11
+ 12 13 14 15
+igraph_matrix_select_cols
+ 0 4 2
+ 0 4 2
+ 0 4 2
+ 0 4 2
+ 0 4 2
+ 0 4 2
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
diff --git a/examples/simple/matrix3.c b/examples/simple/matrix3.c
new file mode 100644
index 0000000..45e6cb0
--- /dev/null
+++ b/examples/simple/matrix3.c
@@ -0,0 +1,43 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge MA, USA 02139
+   
+   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.h>
+
+int main() {
+  igraph_matrix_t m;
+  
+  igraph_matrix_init(&m, 10, 10);
+  if (igraph_matrix_capacity(&m) != 100) {
+    return 1;
+  }
+
+  igraph_matrix_add_cols(&m, 5);
+  igraph_matrix_resize(&m, 5, 5);
+  igraph_matrix_resize_min(&m);
+  if (igraph_matrix_capacity(&m) != igraph_matrix_size(&m)) {
+    return 2;
+  }
+
+  igraph_matrix_destroy(&m);
+  return 0;
+}
diff --git a/examples/simple/mt.c b/examples/simple/mt.c
new file mode 100644
index 0000000..4c5091b
--- /dev/null
+++ b/examples/simple/mt.c
@@ -0,0 +1,39 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdlib.h>
+
+int main() {
+  
+  long int i;
+  for (i=0; i<1000; i++) {
+    igraph_real_t r=igraph_rng_get_unif01(igraph_rng_default());
+    if (r<0 || r>1) {
+      return 1;
+    }
+  }
+  
+  return 0;
+}
+
diff --git a/examples/simple/nodelist1.dl b/examples/simple/nodelist1.dl
new file mode 100644
index 0000000..3825cd6
--- /dev/null
+++ b/examples/simple/nodelist1.dl
@@ -0,0 +1,9 @@
+DL n=5
+format = nodelist1
+labels:
+george, sally, jim, billy, jane
+data:
+1 2 3
+2 3
+3 1
+4 3 
diff --git a/examples/simple/nodelist2.dl b/examples/simple/nodelist2.dl
new file mode 100644
index 0000000..860061c
--- /dev/null
+++ b/examples/simple/nodelist2.dl
@@ -0,0 +1,11 @@
+DL n=5
+format = nodelist1
+labels embedded:
+data:
+george sally jim
+sally jim
+billy george
+jane jim 
+
+
+  
diff --git a/examples/simple/pajek.c b/examples/simple/pajek.c
new file mode 100644
index 0000000..1dac065
--- /dev/null
+++ b/examples/simple/pajek.c
@@ -0,0 +1,47 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  igraph_t g;
+  FILE *ifile;
+  
+  ifile=fopen("pajek5.net", "r");
+  if (!ifile) { return 1; }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  if (igraph_vcount(&g) != 10 || igraph_ecount(&g) != 9 ||
+      igraph_is_directed(&g)) { return 2; }
+  igraph_destroy(&g);
+
+  ifile=fopen("pajek6.net", "r");
+  if (!ifile) { return 3; }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  if (igraph_vcount(&g) != 10 || igraph_ecount(&g) != 9 ||
+      !igraph_is_directed(&g)) { return 4; }
+  igraph_destroy(&g);
+
+  return 0;
+}
diff --git a/examples/simple/pajek1.net b/examples/simple/pajek1.net
new file mode 100644
index 0000000..8d8c1fb
--- /dev/null
+++ b/examples/simple/pajek1.net
@@ -0,0 +1,21 @@
+*Vertices 10
+1 "Vert 1" 0 0 box x_fact 1 y_fact 1 ic Green
+2 "Vert 2" 0 0 box x_fact 1 y_fact 1 ic Green
+3 "Vert 3" 0 0 box x_fact 1 y_fact 1 ic Green
+4 "Vert 4" 0 0 box x_fact 1 y_fact 1 ic Green
+5 "Vert 5" 0 0 box x_fact 1 y_fact 1 ic Green
+6 "Vert 6" 0 0 box x_fact 1 y_fact 1 ic Blue
+7 "Vert 7" 0 0 box x_fact 1 y_fact 1 ic Red
+8 "Vert 8" 0 0 box x_fact 1 y_fact 1 ic Green
+9 "Vert 9" 0 0 box x_fact 1 y_fact 1 ic Green
+10 "Vert 10" 0 0 box x_fact 1 y_fact 1 ic Green
+*Edges
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
diff --git a/examples/simple/pajek2.c b/examples/simple/pajek2.c
new file mode 100644
index 0000000..1abe4fe
--- /dev/null
+++ b/examples/simple/pajek2.c
@@ -0,0 +1,50 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  igraph_t g;
+  FILE *ifile;
+  int i, n;
+
+  /* turn on attribute handling */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);  
+
+  ifile=fopen("bipartite.net", "r");
+  if (!ifile) { return 5; }
+  igraph_read_graph_pajek(&g, ifile);
+  fclose(ifile);
+  if (igraph_vcount(&g) != 13 || igraph_ecount(&g) != 11 ||
+      igraph_is_directed(&g)) { return 6; }
+
+  for (i=0, n=igraph_vcount(&g); i<n; i++) {
+    printf("%i ", (int) VAN(&g, "type", i));
+  }
+  printf("\n");
+
+  igraph_destroy(&g);  
+
+
+  return 0;
+}
diff --git a/examples/simple/pajek2.net b/examples/simple/pajek2.net
new file mode 100644
index 0000000..ef98523
--- /dev/null
+++ b/examples/simple/pajek2.net
@@ -0,0 +1 @@
+*Vertices 10
1 "Vert 1" 0 0 box x_fact 1 y_fact 1 ic Green
2 "Vert 2" 0 0 box x_fact 1 y_fact 1 ic Green
3 "Vert 3" 0 0 box x_fact 1 y_fact 1 ic Green
4 "Vert 4" 0 0 box x_fact 1 y_fact 1 ic Green
5 "Vert 5" 0 0 box x_fact 1 y_fact 1 ic Green
6 "Vert 6" 0 0 box x_fact 1 y_fact 1 ic Blue
7 "Vert 7" 0 0 box x_fact 1 y_fact 1 ic Red
8 "Vert 8" 0 0 box x_fact 1 y_fact 1 ic Green
9 "Vert 9" 0 0 box x_fact 1 y_fact 1 ic Green
10 "Vert 10" 0 0 box x_fact 1 y_fact 1 ic Green
*Edges
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
\ No newline at end of file
diff --git a/examples/simple/pajek2.out b/examples/simple/pajek2.out
new file mode 100644
index 0000000..6816138
--- /dev/null
+++ b/examples/simple/pajek2.out
@@ -0,0 +1 @@
+0 0 0 0 0 0 0 0 1 1 1 1 1 
diff --git a/examples/simple/pajek3.net b/examples/simple/pajek3.net
new file mode 100644
index 0000000..4017af3
--- /dev/null
+++ b/examples/simple/pajek3.net
@@ -0,0 +1,21 @@
+*Vertices 10
+1 "Vert 1" 0 0 box x_fact 1 y_fact 1 ic Green
+2 "Vert 2" 0 0 box x_fact 1 y_fact 1 ic Green
+3 "Vert 3" 0 0 box x_fact 1 y_fact 1 ic Green
+4 "Vert 4" 0 0 box x_fact 1 y_fact 1 ic Green
+5 "Vert 5" 0 0 box x_fact 1 y_fact 1 ic Green
+6 "Vert 6" 0 0 box x_fact 1 y_fact 1 ic Blue
+7 "Vert 7" 0 0 box x_fact 1 y_fact 1 ic Red
+8 "Vert 8" 0 0 box x_fact 1 y_fact 1 ic Green
+9 "Vert 9" 0 0 box x_fact 1 y_fact 1 ic Green
+10 "Vert 10" 0 0 box x_fact 1 y_fact 1 ic Green
+*Edges
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
diff --git a/examples/simple/pajek4.net b/examples/simple/pajek4.net
new file mode 100644
index 0000000..5ae63c0
--- /dev/null
+++ b/examples/simple/pajek4.net
@@ -0,0 +1,22 @@
+*Vertices 10
+
1 "Vert 1" 0 0 box x_fact 1 y_fact 1 ic Green
+
2 "Vert 2" 0 0 box x_fact 1 y_fact 1 ic Green
+
3 "Vert 3" 0 0 box x_fact 1 y_fact 1 ic Green
+
4 "Vert 4" 0 0 box x_fact 1 y_fact 1 ic Green
+
5 "Vert 5" 0 0 box x_fact 1 y_fact 1 ic Green
+
6 "Vert 6" 0 0 box x_fact 1 y_fact 1 ic Blue
+
7 "Vert 7" 0 0 box x_fact 1 y_fact 1 ic Red
+
8 "Vert 8" 0 0 box x_fact 1 y_fact 1 ic Green
+
9 "Vert 9" 0 0 box x_fact 1 y_fact 1 ic Green
+
10 "Vert 10" 0 0 box x_fact 1 y_fact 1 ic Green
+
*Edges
+
1 2
+
2 3
+
3 4
+
4 5
+
5 6
+
6 7
+
7 8
+
8 9
+
9 10
+
\ No newline at end of file
diff --git a/examples/simple/pajek5.net b/examples/simple/pajek5.net
new file mode 100644
index 0000000..239e842
--- /dev/null
+++ b/examples/simple/pajek5.net
@@ -0,0 +1,21 @@
+*Vertices 10
+1 "Vert 1" 0 0 box x_fact 1 y_fact 1 ic Green
+2 "Vert 2" 0 0 box x_fact 1 y_fact 1 ic Green
+3 "Vert 3" 0 0 box x_fact 1 y_fact 1 ic Green
+4 "Vert 4" 0 0 box x_fact 1 y_fact 1 ic Green
+5 "Vert 5" 0 0 box x_fact 1 y_fact 1 ic Green
+6 "Vert 6" 0 0 box x_fact 1 y_fact 1 ic Blue
+7 "Vert 7" 0 0 box x_fact 1 y_fact 1 ic Red
+8 "Vert 8" 0 0 box x_fact 1 y_fact 1 ic Green
+9 "Vert 9" 0 0 box x_fact 1 y_fact 1 ic Green
+10 "Vert 10" 0 0 box x_fact 1 y_fact 1 ic Green
+*Edges 9
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
diff --git a/examples/simple/pajek6.net b/examples/simple/pajek6.net
new file mode 100644
index 0000000..9badd2d
--- /dev/null
+++ b/examples/simple/pajek6.net
@@ -0,0 +1,21 @@
+*Vertices 10
+1 "Vert 1" 0 0 box x_fact 1 y_fact 1 ic Green
+2 "Vert 2" 0 0 box x_fact 1 y_fact 1 ic Green
+3 "Vert 3" 0 0 box x_fact 1 y_fact 1 ic Green
+4 "Vert 4" 0 0 box x_fact 1 y_fact 1 ic Green
+5 "Vert 5" 0 0 box x_fact 1 y_fact 1 ic Green
+6 "Vert 6" 0 0 box x_fact 1 y_fact 1 ic Blue
+7 "Vert 7" 0 0 box x_fact 1 y_fact 1 ic Red
+8 "Vert 8" 0 0 box x_fact 1 y_fact 1 ic Green
+9 "Vert 9" 0 0 box x_fact 1 y_fact 1 ic Green
+10 "Vert 10" 0 0 box x_fact 1 y_fact 1 ic Green
+*Arcs 9
+1 2
+2 3
+3 4
+4 5
+5 6
+6 7
+7 8
+8 9
+9 10
diff --git a/examples/simple/pajek_bip.net b/examples/simple/pajek_bip.net
new file mode 100644
index 0000000..4040647
--- /dev/null
+++ b/examples/simple/pajek_bip.net
@@ -0,0 +1,27 @@
+*vertices 15 10
+ 1 "A"
+ 2 "B"
+ 3 "C"
+ 4 "D"
+ 5 "E"
+ 6 "F"
+ 7 "G"
+ 8 "H"
+ 9 "I"
+10 "J"
+11 "1"
+12 "2"
+13 "3"
+14 "4"
+15 "5"
+*matrix
+1 0 0 0 0
+1 1 0 0 0
+1 1 1 0 0
+1 1 1 1 0
+1 1 1 1 1
+0 0 0 0 1
+1 0 0 0 1
+1 1 0 1 1
+0 0 0 0 0
+1 0 1 0 1
diff --git a/examples/simple/pajek_bip2.net b/examples/simple/pajek_bip2.net
new file mode 100644
index 0000000..bb4fc6a
--- /dev/null
+++ b/examples/simple/pajek_bip2.net
@@ -0,0 +1,27 @@
+*vertices 15 10
+ 1 "A"
+ 2 "B"
+ 3 "C"
+ 4 "D"
+ 5 "E"
+ 6 "F"
+ 7 "G"
+ 8 "H"
+ 9 "I"
+10 "J"
+11 "1"
+12 "2"
+13 "3"
+14 "4"
+15 "5"
+*matrix
+1 0 0 0 0 1
+1 1 0 0 0 2
+1 1 1 0 0 3
+1 1 1 1 0 4
+1 1 1 1 1 5
+0 0 0 0 1 1
+1 0 0 0 1 2
+1 1 0 1 1 4
+0 0 0 0 0 0
+1 0 1 0 1 3
diff --git a/examples/simple/pajek_bipartite.c b/examples/simple/pajek_bipartite.c
new file mode 100644
index 0000000..6daf5cf
--- /dev/null
+++ b/examples/simple/pajek_bipartite.c
@@ -0,0 +1,43 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+
+int main() {
+  igraph_t graph;
+  igraph_vector_bool_t type;
+  igraph_bool_t typev[] = { 0,1,0,1,0,1,0,1,0,1 };
+
+  /* turn on attribute handling */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+  
+  igraph_ring(&graph, 10, IGRAPH_UNDIRECTED, /*mutual=*/ 0, /*circular=*/ 1);
+  igraph_vector_bool_view(&type, typev, sizeof(typev)/sizeof(igraph_bool_t));
+  SETVABV(&graph, "type", &type);
+
+  igraph_write_graph_pajek(&graph, stdout);
+  
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/pajek_bipartite.out b/examples/simple/pajek_bipartite.out
new file mode 100644
index 0000000..c351319
--- /dev/null
+++ b/examples/simple/pajek_bipartite.out
@@ -0,0 +1,22 @@
+*Vertices 10 5
+1 "1"
+2 "3"
+3 "5"
+4 "7"
+5 "9"
+6 "2"
+7 "4"
+8 "6"
+9 "8"
+10 "10"
+*Edges
+1 6
+6 2
+2 7
+7 3
+3 8
+8 4
+4 9
+9 5
+5 10
+1 10
diff --git a/examples/simple/pajek_bipartite2.c b/examples/simple/pajek_bipartite2.c
new file mode 100644
index 0000000..4916c3c
--- /dev/null
+++ b/examples/simple/pajek_bipartite2.c
@@ -0,0 +1,120 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+
+int print_attributes(const igraph_t *g) {
+
+  igraph_vector_t gtypes, vtypes, etypes;
+  igraph_strvector_t gnames, vnames, enames;
+  long int i;
+
+  igraph_vector_init(&gtypes, 0);
+  igraph_vector_init(&vtypes, 0);
+  igraph_vector_init(&etypes, 0);
+  igraph_strvector_init(&gnames, 0);
+  igraph_strvector_init(&vnames, 0);
+  igraph_strvector_init(&enames, 0);
+
+  igraph_cattribute_list(g, &gnames, &gtypes, &vnames, &vtypes, 
+			 &enames, &etypes);
+
+  for (i=0; i<igraph_vcount(g); i++) {
+    long int j;
+    printf("Vertex %li: ", i);
+    for (j=0; j<igraph_strvector_size(&vnames); j++) {
+      printf("%s=", STR(vnames, j));
+      if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_real_printf(VAN(g, STR(vnames,j), i));
+	putchar(' ');
+      } else {
+	printf("\"%s\" ", VAS(g, STR(vnames,j), i));
+      }
+    }
+    printf("\n");
+  }
+
+  for (i=0; i<igraph_ecount(g); i++) {
+    long int j;
+    int u = IGRAPH_FROM(g, i), v = IGRAPH_TO(g, i);
+    if (u < v && !igraph_is_directed(g)) {
+      u = IGRAPH_TO(g, i); v = IGRAPH_FROM(g, i);
+    }
+    printf("Edge %li (%i-%i): ", i, u, v);
+    for (j=0; j<igraph_strvector_size(&enames); j++) {
+      printf("%s=", STR(enames, j));
+      if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_real_printf(EAN(g, STR(enames, j), i));
+	putchar(' ');
+      } else {
+	printf("\"%s\" ", EAS(g, STR(enames, j), i));
+      }
+    }
+    printf("\n");
+  }
+
+  igraph_strvector_destroy(&enames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&gnames);
+  igraph_vector_destroy(&etypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&gtypes);
+
+  return 0;
+}
+
+int main() {
+  igraph_t graph;
+  FILE *input;
+
+  /* turn on attribute handling */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+
+  /* first file, without marginals */
+
+  input=fopen("pajek_bip.net", "r");
+  if (input==0) { return 1;}
+
+  igraph_read_graph_pajek(&graph, input);
+  fclose(input);
+
+  print_attributes(&graph);
+
+  igraph_destroy(&graph);
+
+  /* second file, with marginals */
+  
+  printf("---\n");
+
+  input=fopen("pajek_bip2.net", "r");
+  if (input==0) { return 1;}
+
+  igraph_read_graph_pajek(&graph, input);
+  fclose(input);
+
+  print_attributes(&graph);
+
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/pajek_bipartite2.out b/examples/simple/pajek_bipartite2.out
new file mode 100644
index 0000000..dece734
--- /dev/null
+++ b/examples/simple/pajek_bipartite2.out
@@ -0,0 +1,81 @@
+Vertex 0: type=0 id="A" 
+Vertex 1: type=0 id="B" 
+Vertex 2: type=0 id="C" 
+Vertex 3: type=0 id="D" 
+Vertex 4: type=0 id="E" 
+Vertex 5: type=0 id="F" 
+Vertex 6: type=0 id="G" 
+Vertex 7: type=0 id="H" 
+Vertex 8: type=0 id="I" 
+Vertex 9: type=0 id="J" 
+Vertex 10: type=1 id="1" 
+Vertex 11: type=1 id="2" 
+Vertex 12: type=1 id="3" 
+Vertex 13: type=1 id="4" 
+Vertex 14: type=1 id="5" 
+Edge 0 (10-0): weight=1 
+Edge 1 (10-1): weight=1 
+Edge 2 (11-1): weight=1 
+Edge 3 (10-2): weight=1 
+Edge 4 (11-2): weight=1 
+Edge 5 (12-2): weight=1 
+Edge 6 (10-3): weight=1 
+Edge 7 (11-3): weight=1 
+Edge 8 (12-3): weight=1 
+Edge 9 (13-3): weight=1 
+Edge 10 (10-4): weight=1 
+Edge 11 (11-4): weight=1 
+Edge 12 (12-4): weight=1 
+Edge 13 (13-4): weight=1 
+Edge 14 (14-4): weight=1 
+Edge 15 (14-5): weight=1 
+Edge 16 (10-6): weight=1 
+Edge 17 (14-6): weight=1 
+Edge 18 (10-7): weight=1 
+Edge 19 (11-7): weight=1 
+Edge 20 (13-7): weight=1 
+Edge 21 (14-7): weight=1 
+Edge 22 (10-9): weight=1 
+Edge 23 (12-9): weight=1 
+Edge 24 (14-9): weight=1 
+---
+Vertex 0: type=0 id="A" 
+Vertex 1: type=0 id="B" 
+Vertex 2: type=0 id="C" 
+Vertex 3: type=0 id="D" 
+Vertex 4: type=0 id="E" 
+Vertex 5: type=0 id="F" 
+Vertex 6: type=0 id="G" 
+Vertex 7: type=0 id="H" 
+Vertex 8: type=0 id="I" 
+Vertex 9: type=0 id="J" 
+Vertex 10: type=1 id="1" 
+Vertex 11: type=1 id="2" 
+Vertex 12: type=1 id="3" 
+Vertex 13: type=1 id="4" 
+Vertex 14: type=1 id="5" 
+Edge 0 (10-0): weight=1 
+Edge 1 (10-1): weight=1 
+Edge 2 (11-1): weight=1 
+Edge 3 (10-2): weight=1 
+Edge 4 (11-2): weight=1 
+Edge 5 (12-2): weight=1 
+Edge 6 (10-3): weight=1 
+Edge 7 (11-3): weight=1 
+Edge 8 (12-3): weight=1 
+Edge 9 (13-3): weight=1 
+Edge 10 (10-4): weight=1 
+Edge 11 (11-4): weight=1 
+Edge 12 (12-4): weight=1 
+Edge 13 (13-4): weight=1 
+Edge 14 (14-4): weight=1 
+Edge 15 (14-5): weight=1 
+Edge 16 (10-6): weight=1 
+Edge 17 (14-6): weight=1 
+Edge 18 (10-7): weight=1 
+Edge 19 (11-7): weight=1 
+Edge 20 (13-7): weight=1 
+Edge 21 (14-7): weight=1 
+Edge 22 (10-9): weight=1 
+Edge 23 (12-9): weight=1 
+Edge 24 (14-9): weight=1 
diff --git a/examples/simple/pajek_signed.c b/examples/simple/pajek_signed.c
new file mode 100644
index 0000000..ab25ca7
--- /dev/null
+++ b/examples/simple/pajek_signed.c
@@ -0,0 +1,100 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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.h>
+
+int print_attributes(const igraph_t *g) {
+
+  igraph_vector_t gtypes, vtypes, etypes;
+  igraph_strvector_t gnames, vnames, enames;
+  long int i;
+
+  igraph_vector_init(&gtypes, 0);
+  igraph_vector_init(&vtypes, 0);
+  igraph_vector_init(&etypes, 0);
+  igraph_strvector_init(&gnames, 0);
+  igraph_strvector_init(&vnames, 0);
+  igraph_strvector_init(&enames, 0);
+
+  igraph_cattribute_list(g, &gnames, &gtypes, &vnames, &vtypes, 
+			 &enames, &etypes);
+
+  for (i=0; i<igraph_vcount(g); i++) {
+    long int j;
+    printf("Vertex %li: ", i);
+    for (j=0; j<igraph_strvector_size(&vnames); j++) {
+      printf("%s=", STR(vnames, j));
+      if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_real_printf(VAN(g, STR(vnames,j), i));
+	putchar(' ');
+      } else {
+	printf("\"%s\" ", VAS(g, STR(vnames,j), i));
+      }
+    }
+    printf("\n");
+  }
+
+  for (i=0; i<igraph_ecount(g); i++) {
+    long int j;
+    printf("Edge %li (%i-%i): ", i, (int)IGRAPH_FROM(g,i), (int)IGRAPH_TO(g,i));
+    for (j=0; j<igraph_strvector_size(&enames); j++) {
+      printf("%s=", STR(enames, j));
+      if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_real_printf(EAN(g, STR(enames, j), i));
+	putchar(' ');
+      } else {
+	printf("\"%s\" ", EAS(g, STR(enames, j), i));
+      }
+    }
+    printf("\n");
+  }
+
+  igraph_strvector_destroy(&enames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&gnames);
+  igraph_vector_destroy(&etypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&gtypes);
+
+  return 0;
+}
+
+int main() {
+  igraph_t graph;
+  FILE *input;
+
+  /* turn on attribute handling */
+  igraph_i_set_attribute_table(&igraph_cattribute_table);
+
+  input=fopen("pajek_signed.net", "r");
+  if (input==0) { return 1;}
+
+  igraph_read_graph_pajek(&graph, input);
+  fclose(input);
+
+  print_attributes(&graph);
+
+  igraph_destroy(&graph);
+
+  return 0;
+}
diff --git a/examples/simple/pajek_signed.net b/examples/simple/pajek_signed.net
new file mode 100644
index 0000000..9279c7b
--- /dev/null
+++ b/examples/simple/pajek_signed.net
@@ -0,0 +1,23 @@
+*NETWORK First.net; 14.04.2009 / 09:46:56
+*Vertices 10
+1 "S65"
+2 "S29"
+3 "S04"
+4 "S75"
+5 "S24"
+6 "S81"
+7 "S51"
+8 "S78"
+9 "S86"
+10 "S39"
+*Matrix
+ 0 0 0 0 0 1 0 0 0 -1
+ 0 0 1 1 0 1 1 0 1 0
+ -1 0 0 1 0 0 1 0 1 0
+ -1 1 0 0 1 1 1 0 1 0
+ 0 1 0 1 0 0 0 0 -1 -1
+ 1 -1 0 0 0 0 0 1 0 0
+ 0 -1 1 1 0 -1 0 0 1 0
+ 0 0 1 1 0 1 -1 0 1 1
+ 0 0 0 0 0 0 0 0 0 -1
+ 1 1 1 1 1 1 1 1 1 0
diff --git a/examples/simple/pajek_signed.out b/examples/simple/pajek_signed.out
new file mode 100644
index 0000000..b74bef9
--- /dev/null
+++ b/examples/simple/pajek_signed.out
@@ -0,0 +1,55 @@
+Vertex 0: id="S65" 
+Vertex 1: id="S29" 
+Vertex 2: id="S04" 
+Vertex 3: id="S75" 
+Vertex 4: id="S24" 
+Vertex 5: id="S81" 
+Vertex 6: id="S51" 
+Vertex 7: id="S78" 
+Vertex 8: id="S86" 
+Vertex 9: id="S39" 
+Edge 0 (0-5): weight=1 
+Edge 1 (0-9): weight=-1 
+Edge 2 (1-2): weight=1 
+Edge 3 (1-3): weight=1 
+Edge 4 (1-5): weight=1 
+Edge 5 (1-6): weight=1 
+Edge 6 (1-8): weight=1 
+Edge 7 (2-0): weight=-1 
+Edge 8 (2-3): weight=1 
+Edge 9 (2-6): weight=1 
+Edge 10 (2-8): weight=1 
+Edge 11 (3-0): weight=-1 
+Edge 12 (3-1): weight=1 
+Edge 13 (3-4): weight=1 
+Edge 14 (3-5): weight=1 
+Edge 15 (3-6): weight=1 
+Edge 16 (3-8): weight=1 
+Edge 17 (4-1): weight=1 
+Edge 18 (4-3): weight=1 
+Edge 19 (4-8): weight=-1 
+Edge 20 (4-9): weight=-1 
+Edge 21 (5-0): weight=1 
+Edge 22 (5-1): weight=-1 
+Edge 23 (5-7): weight=1 
+Edge 24 (6-1): weight=-1 
+Edge 25 (6-2): weight=1 
+Edge 26 (6-3): weight=1 
+Edge 27 (6-5): weight=-1 
+Edge 28 (6-8): weight=1 
+Edge 29 (7-2): weight=1 
+Edge 30 (7-3): weight=1 
+Edge 31 (7-5): weight=1 
+Edge 32 (7-6): weight=-1 
+Edge 33 (7-8): weight=1 
+Edge 34 (7-9): weight=1 
+Edge 35 (8-9): weight=-1 
+Edge 36 (9-0): weight=1 
+Edge 37 (9-1): weight=1 
+Edge 38 (9-2): weight=1 
+Edge 39 (9-3): weight=1 
+Edge 40 (9-4): weight=1 
+Edge 41 (9-5): weight=1 
+Edge 42 (9-6): weight=1 
+Edge 43 (9-7): weight=1 
+Edge 44 (9-8): weight=1 
diff --git a/examples/simple/random_seed.c b/examples/simple/random_seed.c
new file mode 100644
index 0000000..a20da88
--- /dev/null
+++ b/examples/simple/random_seed.c
@@ -0,0 +1,52 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <stdlib.h>
+
+int main() {
+
+  igraph_t g1, g2;
+  igraph_bool_t iso;
+
+  igraph_rng_seed(igraph_rng_default(), 1122);
+  
+  igraph_erdos_renyi_game(&g1, IGRAPH_ERDOS_RENYI_GNP, 
+			  100, 3.0/100, /*directed=*/ 0, /*loops=*/ 0);
+  
+  igraph_rng_seed(igraph_rng_default(), 1122);
+  
+  igraph_erdos_renyi_game(&g2, IGRAPH_ERDOS_RENYI_GNP, 
+			  100, 3.0/100, /*directed=*/ 0, /*loops=*/ 0);
+
+  igraph_isomorphic(&g1, &g2, &iso);
+  
+  if (!iso) {
+    return 1;
+  }
+
+  igraph_destroy(&g2);
+  igraph_destroy(&g1);
+ 
+  return 0;
+}
diff --git a/examples/simple/scg.c b/examples/simple/scg.c
new file mode 100644
index 0000000..06b9412
--- /dev/null
+++ b/examples/simple/scg.c
@@ -0,0 +1,160 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t ev;
+  igraph_t scg_graph;
+  igraph_matrix_t scg_matrix;
+  igraph_sparsemat_t scg_sparsemat;
+  igraph_matrix_t L, R;
+  igraph_sparsemat_t Lsparse, Rsparse;
+  igraph_matrix_t input_matrix;
+  igraph_vector_t groups;
+  igraph_vector_t eval;
+  igraph_matrix_t evec;
+  
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_vector_init(&ev, 1);
+  igraph_matrix_init(&L, 0, 0);
+  igraph_matrix_init(&R, 0, 0);
+  igraph_matrix_init(&scg_matrix, 0, 0);
+  igraph_vector_init(&groups, 0);
+  igraph_vector_init(&eval, 0);
+  igraph_matrix_init(&evec, 0, 0);
+
+#define CALLSYM(algo) do {						\
+    igraph_vector_clear(&eval);						\
+    igraph_matrix_resize(&evec, 0, 0);					\
+    igraph_scg_adjacency(&g, /*matrix=*/ 0, /*sparsemat=*/ 0, &ev,	\
+			 /* intervals= */ 3, /* intervals_vector= */ 0,	\
+			 /* algorithm= */ algo, &eval, &evec,		\
+			 /* groups= */ &groups, /* use_arpack= */ 0,	\
+			 /* maxiter= */ 0, &scg_graph, &scg_matrix,	\
+			 &scg_sparsemat, &L, &R,			\
+			 &Lsparse, &Rsparse); } while(0)
+
+  
+#define PRINTRES()						\
+  do {								\
+    printf("------------------------------------\n");		\
+    igraph_write_graph_edgelist(&scg_graph, stdout);		\
+    printf("---\n");						\
+    igraph_vector_print(&groups);				\
+    printf("---\n");						\
+    igraph_vector_print(&eval);					\
+    igraph_matrix_print(&evec);					\
+    printf("---\n");						\
+    igraph_sparsemat_print(&scg_sparsemat, stdout);		\
+    printf("---\n");						\
+    igraph_sparsemat_print(&Lsparse, stdout);			\
+    printf("---\n");						\
+    igraph_sparsemat_print(&Rsparse, stdout);			\
+    printf("---\n");						\
+  } while (0)
+
+  VECTOR(ev)[0] = 1;
+  CALLSYM(IGRAPH_SCG_EXACT);
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  VECTOR(ev)[0] = 3;
+  CALLSYM(IGRAPH_SCG_EXACT);
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_vector_resize(&ev, 2);
+  VECTOR(ev)[0] = 1; VECTOR(ev)[1] = 3;
+  CALLSYM(IGRAPH_SCG_EXACT);
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+#define CALLSYM2(algo) do {						\
+    igraph_vector_clear(&eval);						\
+    igraph_matrix_resize(&evec, 0, 0);					\
+    igraph_scg_adjacency(/* graph=*/ 0, &input_matrix, /*sparsemat=*/ 0, \
+			 &ev, /* intervals= */ 3,			\
+			 /* intervals_vector= */ 0,			\
+			 /* algorithm= */ algo, &eval, &evec,		\
+			 /* groups= */ &groups, /* use_arpack= */ 0,	\
+			 /* maxiter= */ 0, &scg_graph, &scg_matrix,	\
+			 &scg_sparsemat, &L, &R,			\
+			 &Lsparse, &Rsparse); } while (0)
+
+  igraph_matrix_init(&input_matrix, 0, 0);
+  igraph_get_adjacency(&g, &input_matrix, IGRAPH_GET_ADJACENCY_BOTH, 
+		       /* eids= */ 0);
+
+  igraph_vector_resize(&ev, 1);
+  VECTOR(ev)[0] = 1;
+  CALLSYM2(IGRAPH_SCG_EXACT);
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  VECTOR(ev)[0] = 3;
+  CALLSYM2(IGRAPH_SCG_EXACT);
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_vector_resize(&ev, 2);
+  VECTOR(ev)[0] = 1; VECTOR(ev)[1] = 3;
+  CALLSYM2(IGRAPH_SCG_EXACT);
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_matrix_destroy(&evec);
+  igraph_vector_destroy(&eval);
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&input_matrix);
+  igraph_matrix_destroy(&scg_matrix);
+  igraph_matrix_destroy(&L);
+  igraph_matrix_destroy(&R);
+  igraph_vector_destroy(&ev);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------------------------------- */
+
+  return 0;
+}
diff --git a/examples/simple/scg.out b/examples/simple/scg.out
new file mode 100644
index 0000000..c091f70
--- /dev/null
+++ b/examples/simple/scg.out
@@ -0,0 +1,300 @@
+------------------------------------
+0 1
+0 2
+1 3
+---
+0 1 1 2 3 3 3 3 3 3
+---
+2.33441
+-0.5
+-0.47651
+-0.47651
+-0.214186
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+---
+col 0: locations 0 to 1
+1 : 1.41421
+2 : 1
+col 1: locations 2 to 3
+0 : 1.41421
+3 : 1.73205
+col 2: locations 4 to 4
+0 : 1
+col 3: locations 5 to 5
+1 : 1.73205
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+------------------------------------
+0 1
+0 2
+1 3
+---
+0 1 1 2 3 3 3 3 3 3
+---
+0.741964
+0.5
+-0.151453
+-0.151453
+0.673887
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+---
+col 0: locations 0 to 1
+1 : 1.41421
+2 : 1
+col 1: locations 2 to 3
+0 : 1.41421
+3 : 1.73205
+col 2: locations 4 to 4
+0 : 1
+col 3: locations 5 to 5
+1 : 1.73205
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+------------------------------------
+0 1
+0 2
+1 3
+---
+0 1 1 2 3 3 3 3 3 3
+---
+2.33441 0.741964
+-0.5 0.5
+-0.47651 -0.151453
+-0.47651 -0.151453
+-0.214186 0.673887
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+---
+col 0: locations 0 to 1
+1 : 1.41421
+2 : 1
+col 1: locations 2 to 3
+0 : 1.41421
+3 : 1.73205
+col 2: locations 4 to 4
+0 : 1
+col 3: locations 5 to 5
+1 : 1.73205
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+------------------------------------
+0 1
+0 2
+1 3
+---
+0 1 1 2 3 3 3 3 3 3
+---
+2.33441
+-0.5
+-0.47651
+-0.47651
+-0.214186
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+---
+0 1 : 1.41421
+0 2 : 1
+1 0 : 1.41421
+1 3 : 1.73205
+2 0 : 1
+3 1 : 1.73205
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+------------------------------------
+0 1
+0 2
+1 3
+---
+0 1 1 2 3 3 3 3 3 3
+---
+0.741964
+0.5
+-0.151453
+-0.151453
+0.673887
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+-0.204124
+---
+0 1 : 1.41421
+0 2 : 1
+1 0 : 1.41421
+1 3 : 1.73205
+2 0 : 1
+3 1 : 1.73205
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+------------------------------------
+0 1
+0 2
+1 3
+---
+0 1 1 2 3 3 3 3 3 3
+---
+2.33441 0.741964
+-0.5 0.5
+-0.47651 -0.151453
+-0.47651 -0.151453
+-0.214186 0.673887
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+-0.204124 -0.204124
+---
+0 1 : 1.41421
+0 2 : 1
+1 0 : 1.41421
+1 3 : 1.73205
+2 0 : 1
+3 1 : 1.73205
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
+0 0 : 1
+1 1 : 0.707107
+1 2 : 0.707107
+2 3 : 1
+3 4 : 0.408248
+3 5 : 0.408248
+3 6 : 0.408248
+3 7 : 0.408248
+3 8 : 0.408248
+3 9 : 0.408248
+---
diff --git a/examples/simple/scg2.c b/examples/simple/scg2.c
new file mode 100644
index 0000000..21e4fa0
--- /dev/null
+++ b/examples/simple/scg2.c
@@ -0,0 +1,126 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t ev;
+  igraph_t scg_graph;
+  igraph_matrix_t scg_matrix;
+  igraph_sparsemat_t scg_sparsemat;
+  igraph_matrix_t L, R;
+  igraph_sparsemat_t Lsparse, Rsparse;
+  igraph_vector_t p;
+  igraph_vector_t groups;
+  igraph_vector_complex_t eval;
+  igraph_matrix_complex_t evec;
+  
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_vector_init(&ev, 1);
+  igraph_matrix_init(&L, 0, 0);
+  igraph_matrix_init(&R, 0, 0);
+  igraph_matrix_init(&scg_matrix, 0, 0);
+  igraph_vector_init(&p, 0);
+  igraph_vector_init(&groups, 0);
+  igraph_vector_complex_init(&eval, 0);
+  igraph_matrix_complex_init(&evec, 0, 0);
+
+#define CALLSTO() do {							 \
+    igraph_vector_resize(&p, 0);					 \
+    igraph_vector_resize(&groups, 0);					 \
+    igraph_vector_complex_resize(&eval, 0);				 \
+    igraph_matrix_complex_resize(&evec, 0, 0);				 \
+    igraph_scg_stochastic(&g, /*matrix=*/ 0, /*sparsemat=*/ 0, &ev,	 \
+			  /* intervals= */ 2, /* intervals_vector= */ 0, \
+			  /* algorithm= */ IGRAPH_SCG_EXACT,		 \
+			  IGRAPH_SCG_NORM_ROW, &eval, &evec, 		 \
+			  &groups, &p, /* use_arpack= */ 0,		 \
+			  /* maxiter= */ 0, &scg_graph, &scg_matrix,	 \
+			  &scg_sparsemat, &L, &R,			 \
+			  &Lsparse, &Rsparse);				 \
+} while (0)
+
+#define PRINTRES()						\
+  do {								\
+    printf("--------------------------------\n");		\
+    igraph_vector_print(&groups);				\
+    printf("---\n");						\
+    igraph_vector_complex_print(&eval);				\
+    igraph_matrix_complex_print(&evec);				\
+    printf("---\n");						\
+    igraph_write_graph_edgelist(&scg_graph, stdout);		\
+    printf("---\n");						\
+    igraph_sparsemat_print(&scg_sparsemat, stdout);		\
+    printf("---\n");						\
+    igraph_sparsemat_print(&Lsparse, stdout);			\
+    printf("---\n");						\
+    igraph_sparsemat_print(&Rsparse, stdout);			\
+    printf("---\n");						\
+  } while (0)
+  
+  VECTOR(ev)[0] = 1;
+  CALLSTO();
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  VECTOR(ev)[0] = 3;
+  CALLSTO();
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_vector_resize(&ev, 2);
+  VECTOR(ev)[0] = 1; VECTOR(ev)[1] = 3;
+  CALLSTO();
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_matrix_complex_destroy(&evec);
+  igraph_vector_complex_destroy(&eval);
+  igraph_vector_destroy(&groups);
+  igraph_vector_destroy(&p);
+  igraph_matrix_destroy(&scg_matrix);
+  igraph_matrix_destroy(&L);
+  igraph_matrix_destroy(&R);
+  igraph_vector_destroy(&ev);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------------------------------- */
+
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
diff --git a/examples/simple/scg2.out b/examples/simple/scg2.out
new file mode 100644
index 0000000..6b83919
--- /dev/null
+++ b/examples/simple/scg2.out
@@ -0,0 +1,166 @@
+--------------------------------
+0 0 0 0 0 0 0 0 0 0
+---
+1+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+-0.316228+0i
+---
+0 0
+---
+col 0: locations 0 to 0
+0 : 1
+---
+0 0 : 0.166667
+0 1 : 0.222222
+0 2 : 0.222222
+0 3 : 0.0555556
+0 4 : 0.0555556
+0 5 : 0.0555556
+0 6 : 0.0555556
+0 7 : 0.0555556
+0 8 : 0.0555556
+0 9 : 0.0555556
+---
+0 0 : 1
+0 1 : 1
+0 2 : 1
+0 3 : 1
+0 4 : 1
+0 5 : 1
+0 6 : 1
+0 7 : 1
+0 8 : 1
+0 9 : 1
+---
+--------------------------------
+2 3 1 2 4 4 4 0 0 0
+---
+0.866025+0i
+-3.14295e-16+0i
+0.316228+0i
+-0.316228+0i
+-3.26134e-16+0i
+0.365148+0i
+0.365148+0i
+0.365148+0i
+-0.365148+0i
+-0.365148+0i
+-0.365148+0i
+---
+0 1
+1 0
+1 2
+2 1
+2 2
+2 3
+3 2
+3 4
+4 3
+---
+col 0: locations 0 to 0
+1 : 0.75
+col 1: locations 1 to 2
+2 : 0.25
+0 : 1
+col 2: locations 3 to 5
+3 : 0.25
+1 : 0.25
+2 : 0.5
+col 3: locations 6 to 7
+2 : 0.25
+4 : 1
+col 4: locations 8 to 8
+3 : 0.75
+---
+2 0 : 0.75
+3 1 : 1
+1 2 : 1
+2 3 : 0.25
+4 4 : 0.333333
+4 5 : 0.333333
+4 6 : 0.333333
+0 7 : 0.333333
+0 8 : 0.333333
+0 9 : 0.333333
+---
+2 0 : 1
+3 1 : 1
+1 2 : 1
+2 3 : 1
+4 4 : 1
+4 5 : 1
+4 6 : 1
+0 7 : 1
+0 8 : 1
+0 9 : 1
+---
+--------------------------------
+2 3 1 2 4 4 4 0 0 0
+---
+1+0i 0.866025+0i
+-0.316228+0i -3.14295e-16+0i
+-0.316228+0i 0.316228+0i
+-0.316228+0i -0.316228+0i
+-0.316228+0i -3.26134e-16+0i
+-0.316228+0i 0.365148+0i
+-0.316228+0i 0.365148+0i
+-0.316228+0i 0.365148+0i
+-0.316228+0i -0.365148+0i
+-0.316228+0i -0.365148+0i
+-0.316228+0i -0.365148+0i
+---
+0 1
+1 0
+1 2
+2 1
+2 2
+2 3
+3 2
+3 4
+4 3
+---
+col 0: locations 0 to 0
+1 : 0.75
+col 1: locations 1 to 2
+2 : 0.25
+0 : 1
+col 2: locations 3 to 5
+3 : 0.25
+1 : 0.25
+2 : 0.5
+col 3: locations 6 to 7
+2 : 0.25
+4 : 1
+col 4: locations 8 to 8
+3 : 0.75
+---
+2 0 : 0.75
+3 1 : 1
+1 2 : 1
+2 3 : 0.25
+4 4 : 0.333333
+4 5 : 0.333333
+4 6 : 0.333333
+0 7 : 0.333333
+0 8 : 0.333333
+0 9 : 0.333333
+---
+2 0 : 1
+3 1 : 1
+1 2 : 1
+2 3 : 1
+4 4 : 1
+4 5 : 1
+4 6 : 1
+0 7 : 1
+0 8 : 1
+0 9 : 1
+---
diff --git a/examples/simple/scg3.c b/examples/simple/scg3.c
new file mode 100644
index 0000000..596d39a
--- /dev/null
+++ b/examples/simple/scg3.c
@@ -0,0 +1,124 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+
+  igraph_t g;
+  igraph_vector_t ev;
+  igraph_t scg_graph;
+  igraph_matrix_t scg_matrix;
+  igraph_sparsemat_t scg_sparsemat;
+  igraph_matrix_t L, R;
+  igraph_sparsemat_t Lsparse, Rsparse;
+  igraph_vector_t groups;
+  igraph_vector_complex_t eval;
+  igraph_matrix_complex_t evec;
+  
+  igraph_tree(&g, 10, /* children= */ 3, IGRAPH_TREE_UNDIRECTED);
+  
+  igraph_vector_init(&ev, 1);
+  igraph_matrix_init(&L, 0, 0);
+  igraph_matrix_init(&R, 0, 0);
+  igraph_matrix_init(&scg_matrix, 0, 0);
+  igraph_vector_init(&groups, 0);
+  igraph_vector_complex_init(&eval, 0);
+  igraph_matrix_complex_init(&evec, 0, 0);
+
+#define CALLLAP() do {							 \
+    igraph_vector_resize(&groups, 0);					 \
+    igraph_vector_complex_resize(&eval, 0);				 \
+    igraph_matrix_complex_resize(&evec, 0, 0);				 \
+    igraph_scg_laplacian(&g, /*matrix=*/ 0, /*sparsemat=*/ 0, &ev,	 \
+			 /* intervals= */ 2, /* intervals_vector= */ 0, \
+			 /* algorithm= */ IGRAPH_SCG_EXACT,		\
+			 IGRAPH_SCG_NORM_ROW,				\
+			 IGRAPH_SCG_DIRECTION_DEFAULT, &eval, &evec,	\
+			 &groups, /* use_arpack= */ 0,			\
+			 /* maxiter= */ 0, &scg_graph, &scg_matrix,	\
+			 &scg_sparsemat, &L, &R,			\
+			 &Lsparse, &Rsparse);				\
+} while (0)
+
+#define PRINTRES()						\
+  do {								\
+    printf("--------------------------------\n");		\
+    igraph_vector_print(&groups);				\
+    printf("---\n");						\
+    igraph_vector_complex_print(&eval);				\
+    igraph_matrix_complex_print(&evec);				\
+    printf("---\n");						\
+    igraph_write_graph_edgelist(&scg_graph, stdout);		\
+    printf("---\n");						\
+    igraph_sparsemat_print(&scg_sparsemat, stdout);		\
+    printf("---\n");						\
+    igraph_sparsemat_print(&Lsparse, stdout);			\
+    printf("---\n");						\
+    igraph_sparsemat_print(&Rsparse, stdout);			\
+    printf("---\n");						\
+  } while (0)
+
+  VECTOR(ev)[0] = 1;
+  CALLLAP();
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  VECTOR(ev)[0] = 3;
+  CALLLAP();
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_vector_resize(&ev, 2);
+  VECTOR(ev)[0] = 1; VECTOR(ev)[1] = 3;
+  CALLLAP();
+  PRINTRES();
+  igraph_destroy(&scg_graph);
+  igraph_sparsemat_destroy(&scg_sparsemat);
+  igraph_sparsemat_destroy(&Lsparse);
+  igraph_sparsemat_destroy(&Rsparse);
+
+  igraph_matrix_complex_destroy(&evec);
+  igraph_vector_complex_destroy(&eval);
+  igraph_vector_destroy(&groups);
+  igraph_matrix_destroy(&scg_matrix);
+  igraph_matrix_destroy(&L);
+  igraph_matrix_destroy(&R);
+  igraph_vector_destroy(&ev);
+  igraph_destroy(&g);
+
+  /* -------------------------------------------------------------------- */
+
+#ifdef __APPLE__
+  return 0;
+#else
+  return 77;
+#endif
+}
+  
diff --git a/examples/simple/scg3.out b/examples/simple/scg3.out
new file mode 100644
index 0000000..93ab8af
--- /dev/null
+++ b/examples/simple/scg3.out
@@ -0,0 +1,177 @@
+--------------------------------
+0 3 3 2 1 1 1 1 1 1
+---
+5.52892+0i
+-0.493741+0i
+0.569806+0i
+0.569806+0i
+0.10902+0i
+-0.125815+0i
+-0.125815+0i
+-0.125815+0i
+-0.125815+0i
+-0.125815+0i
+-0.125815+0i
+---
+0 2
+0 3
+1 3
+2 0
+3 0
+3 1
+---
+col 0: locations 0 to 2
+0 : 3
+3 : -1
+2 : -1
+col 1: locations 3 to 4
+1 : 1
+3 : -3
+col 2: locations 5 to 6
+2 : 1
+0 : -1
+col 3: locations 7 to 9
+3 : 4
+0 : -2
+1 : -1
+---
+0 0 : 1
+3 1 : 0.5
+3 2 : 0.5
+2 3 : 1
+1 4 : 0.166667
+1 5 : 0.166667
+1 6 : 0.166667
+1 7 : 0.166667
+1 8 : 0.166667
+1 9 : 0.166667
+---
+0 0 : 1
+3 1 : 1
+3 2 : 1
+2 3 : 1
+1 4 : 1
+1 5 : 1
+1 6 : 1
+1 7 : 1
+1 8 : 1
+1 9 : 1
+---
+--------------------------------
+3 2 2 0 1 1 1 1 1 1
+---
+2.83255+0i
+0.749697+0i
+0.267318+0i
+0.267318+0i
+-0.4091+0i
+-0.145872+0i
+-0.145872+0i
+-0.145872+0i
+-0.145872+0i
+-0.145872+0i
+-0.145872+0i
+---
+0 3
+1 2
+2 1
+2 3
+3 0
+3 2
+---
+col 0: locations 0 to 1
+0 : 1
+3 : -1
+col 1: locations 2 to 3
+1 : 1
+2 : -3
+col 2: locations 4 to 6
+2 : 4
+3 : -2
+1 : -1
+col 3: locations 7 to 9
+3 : 3
+2 : -1
+0 : -1
+---
+3 0 : 1
+2 1 : 0.5
+2 2 : 0.5
+0 3 : 1
+1 4 : 0.166667
+1 5 : 0.166667
+1 6 : 0.166667
+1 7 : 0.166667
+1 8 : 0.166667
+1 9 : 0.166667
+---
+3 0 : 1
+2 1 : 1
+2 2 : 1
+0 3 : 1
+1 4 : 1
+1 5 : 1
+1 6 : 1
+1 7 : 1
+1 8 : 1
+1 9 : 1
+---
+--------------------------------
+0 3 3 2 1 1 1 1 1 1
+---
+5.52892+0i 2.83255+0i
+-0.493741+0i 0.749697+0i
+0.569806+0i 0.267318+0i
+0.569806+0i 0.267318+0i
+0.10902+0i -0.4091+0i
+-0.125815+0i -0.145872+0i
+-0.125815+0i -0.145872+0i
+-0.125815+0i -0.145872+0i
+-0.125815+0i -0.145872+0i
+-0.125815+0i -0.145872+0i
+-0.125815+0i -0.145872+0i
+---
+0 2
+0 3
+1 3
+2 0
+3 0
+3 1
+---
+col 0: locations 0 to 2
+0 : 3
+3 : -1
+2 : -1
+col 1: locations 3 to 4
+1 : 1
+3 : -3
+col 2: locations 5 to 6
+2 : 1
+0 : -1
+col 3: locations 7 to 9
+3 : 4
+0 : -2
+1 : -1
+---
+0 0 : 1
+3 1 : 0.5
+3 2 : 0.5
+2 3 : 1
+1 4 : 0.166667
+1 5 : 0.166667
+1 6 : 0.166667
+1 7 : 0.166667
+1 8 : 0.166667
+1 9 : 0.166667
+---
+0 0 : 1
+3 1 : 1
+3 2 : 1
+2 3 : 1
+1 4 : 1
+1 5 : 1
+1 6 : 1
+1 7 : 1
+1 8 : 1
+1 9 : 1
+---
diff --git a/examples/simple/single_target_shortest_path.c b/examples/simple/single_target_shortest_path.c
new file mode 100644
index 0000000..262a2b5
--- /dev/null
+++ b/examples/simple/single_target_shortest_path.c
@@ -0,0 +1,78 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void igraph_warnings_ignore(const char *reason, const char *file,
+			    int line, int igraph_errno) {
+  /* Do nothing */
+}
+
+int main() {
+  igraph_t g;
+  igraph_vector_t vpath, epath;
+  igraph_vector_t w;
+  
+  /* Unweighted */
+
+  igraph_small(&g, 5, IGRAPH_DIRECTED,
+	       0,1, 1,2, 2,3, 3,4, 0,3, 
+	       -1);
+  igraph_vector_init(&vpath, 0);
+  igraph_vector_init(&epath, 0);
+  igraph_get_shortest_path(&g, &vpath, &epath, 0, 4, IGRAPH_OUT);
+  igraph_vector_print(&vpath);
+  igraph_vector_print(&epath);
+
+  igraph_get_shortest_path(&g, &vpath, &epath, 0, 0, IGRAPH_OUT);
+  igraph_vector_print(&vpath);
+  igraph_vector_print(&epath);
+
+  igraph_set_warning_handler(igraph_warnings_ignore);
+  igraph_get_shortest_path(&g, &vpath, &epath, 4, 0, IGRAPH_OUT);
+  igraph_vector_print(&vpath);
+  igraph_vector_print(&epath);
+  igraph_set_warning_handler(igraph_warning_handler_print);
+
+  igraph_get_shortest_path(&g, &vpath, &epath, 4, 0, IGRAPH_ALL);
+  igraph_vector_print(&vpath);
+  igraph_vector_print(&epath);
+
+  /* Weighted */
+
+  igraph_vector_init(&w, 5);
+  VECTOR(w)[0]=1; VECTOR(w)[1]=1; VECTOR(w)[2]=1; VECTOR(w)[3]=1;
+  VECTOR(w)[4]=3.1;
+
+  igraph_get_shortest_path_dijkstra(&g, &vpath, &epath, 0, 4, &w, IGRAPH_OUT);
+  igraph_vector_print(&vpath);
+  igraph_vector_print(&epath);
+
+  igraph_vector_destroy(&w);
+  igraph_vector_destroy(&epath);
+  igraph_vector_destroy(&vpath);
+  igraph_destroy(&g);
+  
+  return 0;
+}
+
diff --git a/examples/simple/single_target_shortest_path.out b/examples/simple/single_target_shortest_path.out
new file mode 100644
index 0000000..972ab28
--- /dev/null
+++ b/examples/simple/single_target_shortest_path.out
@@ -0,0 +1,10 @@
+0 3 4
+4 3
+0
+
+
+
+4 3 0
+3 4
+0 1 2 3 4
+0 1 2 3
diff --git a/examples/simple/spinglass.c b/examples/simple/spinglass.c
new file mode 100644
index 0000000..6923978
--- /dev/null
+++ b/examples/simple/spinglass.c
@@ -0,0 +1,99 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+int main() {
+  igraph_t g;
+  igraph_real_t  modularity, temperature;
+  igraph_vector_t membership, csize;
+  /* long int i; */
+  igraph_real_t cohesion, adhesion;
+  igraph_integer_t inner_links;
+  igraph_integer_t outer_links;
+  
+  igraph_small(&g, 5, IGRAPH_UNDIRECTED, 
+	       0,1,0,2,0,3,0,4, 1,2,1,3,1,4, 2,3,2,4, 3,4,
+	       5,6,5,7,5,8,5,9, 6,7,6,8,6,9, 7,8,7,9, 8,9, 0,5, -1);
+  igraph_vector_init(&membership, 0);
+  igraph_vector_init(&csize, 0);
+  igraph_community_spinglass(&g, 
+			     0, /* no weights */
+			     &modularity,
+			     &temperature,
+			     &membership,
+			     &csize,
+			     2,	   /* no of spins */
+			     0,    /* parallel update */
+			     1.0,  /* start temperature */
+			     0.01, /* stop temperature */
+			     0.99, /* cooling factor */
+			     IGRAPH_SPINCOMM_UPDATE_CONFIG,
+			     1.0, /* gamma */
+			     IGRAPH_SPINCOMM_IMP_ORIG,
+			     /*gamma-=*/ 0);
+
+/*   printf("Modularity:  %f\n", modularity); */
+/*   printf("Temperature: %f\n", temperature); */
+/*   printf("Cluster sizes: "); */
+/*   for (i=0; i<igraph_vector_size(&csize); i++) { */
+/*     printf("%li ", (long int)VECTOR(csize)[i]); */
+/*   } */
+/*   printf("\n"); */
+/*   printf("Membership: "); */
+/*   for (i=0; i<igraph_vector_size(&membership); i++) { */
+/*     printf("%li ", (long int)VECTOR(membership)[i]); */
+/*   } */
+/*   printf("\n"); */
+
+  if (igraph_vector_size(&csize) != 2) {
+    igraph_vector_destroy(&membership);
+    igraph_vector_destroy(&csize);  
+    return 77;
+  }
+  if (VECTOR(csize)[0] != 5) {
+    igraph_vector_destroy(&membership);
+    igraph_vector_destroy(&csize);  
+    return 77;
+  }
+
+  /* Try to call this as well, we don't check the results currently.... */
+  
+  igraph_community_spinglass_single(&g, 
+				    /*weights=  */ 0,
+				    /*vertex=   */ 0,
+				    /*community=*/ &membership,
+				    /*cohesion= */ &cohesion,
+				    /*adhesion= */ &adhesion,
+				    /*inner_links= */ &inner_links,
+				    /*outer_links= */ &outer_links,
+				    /*spins=       */ 2,
+				    /*update_rule= */ IGRAPH_SPINCOMM_UPDATE_CONFIG,
+				    /*gamma=       */ 1.0);
+  
+  igraph_destroy(&g);
+  igraph_vector_destroy(&membership);
+  igraph_vector_destroy(&csize);  
+  
+  return 0;
+}
diff --git a/examples/simple/spmatrix.c b/examples/simple/spmatrix.c
new file mode 100644
index 0000000..1139fff
--- /dev/null
+++ b/examples/simple/spmatrix.c
@@ -0,0 +1,211 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+
+void print_matrix(igraph_spmatrix_t *m, FILE *f) {
+  long int i, j;
+  for (i=0; i<igraph_spmatrix_nrow(m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(m); j++) {
+      fprintf(f, " %li", (long int)igraph_spmatrix_e(m, i, j));
+    }
+    fprintf(f, "\n");
+  }  
+  fprintf(f, "=========================\n");
+}
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int)VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n=========================\n");
+}
+
+int main() {
+  igraph_spmatrix_t m, m1;
+  igraph_spmatrix_iter_t mit;
+  igraph_real_t arr[12];
+  igraph_vector_t v;
+  long int i, j;
+  int order[] = { 1, 5, 8, 4, 0, 9, 6, 10, 11, 2, 3, 7 };
+
+  /* igraph_spmatrix_init, igraph_spmatrix_destroy */
+  igraph_spmatrix_init(&m, 10, 10);
+  igraph_spmatrix_destroy(&m);
+  
+  igraph_spmatrix_init(&m, 0, 0);
+  igraph_spmatrix_destroy(&m);
+  
+  /* igraph_spmatrix_ncol, igraph_spmatrix_nrow */
+  igraph_spmatrix_init(&m, 10, 5);
+  if (igraph_spmatrix_nrow(&m) != 10) {
+    return 1;
+  }
+  if (igraph_spmatrix_ncol(&m) != 5) {
+    return 2;
+  }
+
+  /* igraph_spmatrix_size, igraph_spmatrix_resize */
+  igraph_spmatrix_resize(&m, 6, 5);
+  if (igraph_spmatrix_size(&m) != 30) {
+    return 3;
+  }
+  if (igraph_spmatrix_nrow(&m) != 6) {
+    return 4;
+  }
+  if (igraph_spmatrix_ncol(&m) != 5) {
+    return 5;
+  }
+  igraph_spmatrix_resize(&m, 2, 4);
+  if (igraph_spmatrix_nrow(&m) != 2) {
+    return 6;
+  }
+  if (igraph_spmatrix_ncol(&m) != 4) {
+    return 7;
+  }
+  igraph_spmatrix_destroy(&m);
+  
+  /* igraph_spmatrix_get, igraph_spmatrix_set, igraph_spmatrix_null */
+  igraph_spmatrix_init(&m, 3, 4);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      igraph_spmatrix_set(&m, i, j, (i+j) % 3);
+    }
+  }
+  print_matrix(&m, stdout);
+  igraph_spmatrix_null(&m);
+  print_matrix(&m, stdout);
+  /* now fill it in shuffled order */
+  for (i=0; i<12; i++) {
+    igraph_spmatrix_set(&m, order[i]/4, order[i]%4, (order[i]/4+order[i]%4) % 3);
+  }
+  print_matrix(&m, stdout);
+  /* now decrease all elements by two in shuffled order */
+  for (i=0; i<12; i++) {
+    igraph_spmatrix_add_e(&m, order[i]/4, order[i]%4, -2);
+  }
+  print_matrix(&m, stdout);
+  /* now increase all elements by one in shuffled order */
+  for (i=0; i<12; i++) {
+    igraph_spmatrix_add_e(&m, order[i]/4, order[i]%4, 1);
+  }
+  print_matrix(&m, stdout);
+
+  igraph_spmatrix_destroy(&m);
+  
+  /* igraph_matrix_add_cols, igraph_matrix_add_rows */
+  igraph_spmatrix_init(&m, 4, 3);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      igraph_spmatrix_set(&m, i, j, (i+1)*(j+1));
+    }
+  }
+  igraph_spmatrix_add_cols(&m, 2);
+  igraph_spmatrix_add_rows(&m, 2);
+  if (igraph_spmatrix_ncol(&m) != 5) {
+    return 8;
+  }
+  if (igraph_spmatrix_nrow(&m) != 6) {
+    return 9;
+  }
+  print_matrix(&m, stdout);
+  igraph_spmatrix_destroy(&m);
+
+  /* igraph_spmatrix_count_nonzero */
+  igraph_spmatrix_init(&m, 5, 3);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      igraph_spmatrix_set(&m, i, j, i*j);
+    }
+  }
+  print_matrix(&m, stdout);
+  if (igraph_spmatrix_count_nonzero(&m) != 8) {
+    return 10;
+  }
+  igraph_spmatrix_destroy(&m);
+
+  /* igraph_spmatrix_copy */
+  igraph_spmatrix_init(&m, 3, 4);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      igraph_spmatrix_set(&m, i, j, i*j);
+    }
+  }
+  igraph_spmatrix_copy(&m1, &m);
+  print_matrix(&m1, stdout);
+  igraph_spmatrix_destroy(&m);
+  igraph_spmatrix_destroy(&m1);
+
+  /* igraph_spmatrix_copy_to */
+  igraph_spmatrix_init(&m, 3, 4);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      igraph_spmatrix_set(&m, i, j, i*j);
+    }
+  }
+  igraph_spmatrix_copy_to(&m, arr);
+  for (i=0; i<12; i++) { printf(" %ld", (long)arr[i]); }
+  printf("\n=========================\n");
+  
+  /* igraph_spmatrix_max */
+  arr[0] = igraph_spmatrix_max(&m, arr+1, arr+2);
+  for (i=0; i<3; i++) { printf(" %ld", (long)arr[i]); }
+  printf("\n=========================\n");
+ 
+  igraph_spmatrix_destroy(&m);
+
+  /* igraph_spmatrix_colsums */
+  igraph_spmatrix_init(&m, 3, 5);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      igraph_spmatrix_set(&m, i, j, i+j-4);
+    }
+  }
+  igraph_vector_init(&v, 0);
+  igraph_spmatrix_colsums(&m, &v);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+  igraph_spmatrix_destroy(&m);
+
+  /* igraph_spmatrix_iter_t */
+  igraph_spmatrix_init(&m, 5, 5);
+  for (i=0; i<igraph_spmatrix_nrow(&m); i++) {
+    for (j=0; j<igraph_spmatrix_ncol(&m); j++) {
+      if (abs(i-j) == 1)
+        igraph_spmatrix_set(&m, i, j, (i+1)*(j+1));
+    }
+  }
+  igraph_spmatrix_iter_create(&mit, &m);
+  while (!igraph_spmatrix_iter_end(&mit)) {
+    printf("%ld %ld %ld\n", mit.ri, mit.ci, (long int)mit.value);
+    igraph_spmatrix_iter_next(&mit);
+  }
+  igraph_spmatrix_iter_destroy(&mit);
+  igraph_spmatrix_destroy(&m);
+  printf("=========================\n");
+
+  /* TODO: igraph_spmatrix_add_col_values */
+
+  return 0;
+}
diff --git a/examples/simple/spmatrix.out b/examples/simple/spmatrix.out
new file mode 100644
index 0000000..5127a4e
--- /dev/null
+++ b/examples/simple/spmatrix.out
@@ -0,0 +1,52 @@
+ 0 1 2 0
+ 1 2 0 1
+ 2 0 1 2
+=========================
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+=========================
+ 0 1 2 0
+ 1 2 0 1
+ 2 0 1 2
+=========================
+ -2 -1 0 -2
+ -1 0 -2 -1
+ 0 -2 -1 0
+=========================
+ -1 0 1 -1
+ 0 1 -1 0
+ 1 -1 0 1
+=========================
+ 1 2 3 0 0
+ 2 4 6 0 0
+ 3 6 9 0 0
+ 4 8 12 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+=========================
+ 0 0 0
+ 0 1 2
+ 0 2 4
+ 0 3 6
+ 0 4 8
+=========================
+ 0 0 0 0
+ 0 1 2 3
+ 0 2 4 6
+=========================
+ 0 0 0 0 1 2 0 2 4 0 3 6
+=========================
+ 6 2 3
+=========================
+ -9 -6 -3 0 3
+=========================
+1 0 2
+0 1 2
+2 1 6
+1 2 6
+3 2 12
+2 3 12
+4 3 20
+3 4 20
+=========================
diff --git a/examples/simple/stack.c b/examples/simple/stack.c
new file mode 100644
index 0000000..a29053b
--- /dev/null
+++ b/examples/simple/stack.c
@@ -0,0 +1,93 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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.h>
+#include <igraph_stack.h>
+
+int main() {
+
+  igraph_stack_t st;
+  int i;
+
+  /* igraph_stack_init, igraph_stack_destroy */
+  igraph_stack_init(&st, 0);
+  igraph_stack_destroy(&st);
+  igraph_stack_init(&st, 10);
+  igraph_stack_destroy(&st);
+
+  /* igraph_stack_reserve */
+  igraph_stack_init(&st, 0);
+  igraph_stack_reserve(&st, 10);
+  igraph_stack_reserve(&st, 5);
+
+  /* igraph_stack_empty */
+  if (!igraph_stack_empty(&st)) {
+    return 1;
+  }
+  igraph_stack_push(&st, 1);
+  if (igraph_stack_empty(&st)) {
+    return 2;
+  }
+
+  /* igraph_stack_size */
+  if (igraph_stack_size(&st) != 1) {
+    return 3;
+  }
+  for (i=0; i<10; i++) {
+    igraph_stack_push(&st, i);
+  }
+  if (igraph_stack_size(&st) != 11) {
+    return 4;
+  }
+
+  /* igraph_stack_clear */
+  igraph_stack_clear(&st);
+  if (!igraph_stack_empty(&st)) {
+    return 5;
+  }
+  igraph_stack_push(&st, 100);
+  if (igraph_stack_pop(&st) != 100) {
+    return 6;
+  }
+  igraph_stack_clear(&st);
+  igraph_stack_clear(&st);
+
+  /* igraph_stack_push, igraph_stack_pop */
+  for (i=0; i<100; i++) {
+    igraph_stack_push(&st, 100-i);
+  }
+  for (i=0; i<100; i++) {
+    if (igraph_stack_pop(&st) != i+1) {
+      return 7;
+    }
+  }
+  if (!igraph_stack_empty(&st)) {
+    return 8;
+  }
+  
+  igraph_stack_destroy(&st);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 9;
+
+  return 0;
+}
diff --git a/examples/simple/test.gxl b/examples/simple/test.gxl
new file mode 100644
index 0000000..6ba4f8f
--- /dev/null
+++ b/examples/simple/test.gxl
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This file was written by the JAVA GraphML Library.-->
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+  <key id="d0" for="node" attr.name="color" attr.type="string">yellow</key>
+  <key id="d1" for="edge" attr.name="weight" attr.type="double"/>
+  <key id="d2" for="graph" attr.name="date" attr.type="string"></key>
+  <key id="d3" for="graph" attr.name="unused" attr.type="string"></key>
+  <key id="d4" for="node" attr.name="gender" attr.type="boolean">1</key>
+  <graph id="G" edgedefault="undirected">
+    <data key="d2">2006-11-12</data>
+    <node id="n0">
+      <data key="d0">green</data>
+      <data key="d3">incorrect</data>
+      <!-- incorrect attribute key, should issue a warning -->
+      <data key="d4">true</data>
+    </node>
+    <node id="n1"/>
+    <node id="n2">
+      <data key="d0">blue</data>
+      <data key="d4">0</data>
+    </node>
+    <node id="n3">
+      <data key="d0">red "with entities"</data>
+    </node>
+    <node id="n4">
+      <data key="d0"><!-- empty key body --></data>
+      <data key="d4">false</data>
+    </node>
+    <node id="n5">
+      <data key="d0">turquoise</data>
+      <data key="d4">fAlSe</data>
+    </node>
+    <edge id="e0" source="n0" target="n2">
+      <data key="d1">1.0</data>
+    </edge>
+    <edge id="e1" source="n0" target="n1">
+      <data key="d1">1.0</data>
+    </edge>
+    <edge id="e2" source="n1" target="n3">
+      <data key="d1">2.0</data>
+    </edge>
+    <edge id="e3" source="n3" target="n2"/>
+    <edge id="e4" source="n2" target="n4"/>
+    <edge id="e5" source="n3" target="n5"/>
+    <edge id="e6" source="n5" target="n4">
+      <data key="d1">1.1</data>
+    </edge>
+  </graph>
+</graphml>
diff --git a/examples/simple/tls1.c b/examples/simple/tls1.c
new file mode 100644
index 0000000..56d79d3
--- /dev/null
+++ b/examples/simple/tls1.c
@@ -0,0 +1,53 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+#include <pthread.h>
+#include <unistd.h>
+
+void *thread_function(void *arg) {
+  IGRAPH_FINALLY(0, 0);
+  return 0;
+}
+
+int main() {
+  pthread_t thread_id;
+  void *exit_status;
+
+  /* Skip if igraph is not thread-safe */
+  if (!IGRAPH_THREAD_SAFE) { 
+    return 77;
+  }
+  
+  /* Run a thread that leaves some junk in the error stack */
+  pthread_create(&thread_id, NULL, thread_function, 0);
+  pthread_join(thread_id, &exit_status);
+
+  /* Check that the error stack is not common */
+  if (!IGRAPH_FINALLY_STACK_EMPTY) {
+    printf("Foobar\n");
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/examples/simple/tls2.c b/examples/simple/tls2.c
new file mode 100644
index 0000000..8bc62a6
--- /dev/null
+++ b/examples/simple/tls2.c
@@ -0,0 +1,230 @@
+/* -*- 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
+
+*/
+
+#include <igraph.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "igraph_arpack_internal.h"
+
+/* Test whether ARPACK is thread-safe. We will create two threads, 
+   each calling a different ARPACK eigensolver. We will make sure that
+   the ARPACK calls from the two threads overlap */
+
+typedef struct thread_data_t {
+  igraph_matrix_t *m;
+  igraph_vector_t *result;
+  pthread_cond_t *cond;
+  pthread_mutex_t *mutex;
+  int *steps, *othersteps;
+} thread_data_t;
+
+int arpack_mult(igraph_real_t *to, igraph_real_t *from, int n, 
+		igraph_matrix_t *matrix) {
+  /* TODO */
+  igraph_blas_dgemv_array(/*transpose=*/ 0, /*alpha=*/ 1.0, matrix,
+			  from, /*beta=*/ 0.0, to);
+
+  return 0;
+}
+
+/* This is the function performed by each thread. It calles the
+   low-level ARPACK symmetric eigensolver, step by step. After each
+   step, it synchronizes with the other thread.
+   
+   The synchronization ensures that the two threads are using the
+   thread-local variables at the same time. If they are really
+   thread-local, then ARPACK still delivers the correct solution for
+   the two matrices. Otherwise the result is undefined: maybe results
+   will be incorrect, or the program will crash.
+
+   This function is basically a simplified copy of igraph_arpack_rssolve.
+*/
+
+void *thread_function(void *arg) {
+  thread_data_t *data=(thread_data_t*) arg;
+  igraph_matrix_t *M=data->m;
+  igraph_vector_t *result=data->result;
+  pthread_cond_t *cond=data->cond;
+  pthread_mutex_t *mutex=data->mutex;
+  igraph_arpack_options_t options;
+  igraph_real_t *v, *workl, *workd, *d, *resid, *ax;
+  int *select;
+  int ido=0;
+  int rvec=1;
+  char *all="All";
+  int i;
+
+  igraph_arpack_options_init(&options);
+  options.n = igraph_matrix_nrow(M);
+  options.ldv = options.n;
+  options.nev = 1;
+  options.ncv = 3;
+  options.lworkl = options.ncv * (options.ncv+8);
+  options.which[0] = 'L'; options.which[1] = 'M';
+
+  options.iparam[0]=options.ishift;
+  options.iparam[2]=options.mxiter;
+  options.iparam[3]=options.nb;
+  options.iparam[4]=0;
+  options.iparam[6]=options.mode;
+  options.info=options.start;
+
+  v=igraph_Calloc(options.ldv * options.ncv, igraph_real_t);
+  workl=igraph_Calloc(options.lworkl, igraph_real_t);
+  workd=igraph_Calloc(3*options.n, igraph_real_t);
+  d=igraph_Calloc(2*options.ncv, igraph_real_t);
+  resid=igraph_Calloc(options.n, igraph_real_t);
+  ax=igraph_Calloc(options.n, igraph_real_t);
+  select=igraph_Calloc(options.ncv, int);
+  
+  if (!v || !workl || !workd || !d || !resid || !ax || !select) { 
+    printf("Out of memory\n");
+    return 0;
+  }
+  
+  while (1) {
+    igraphdsaupd_(&ido, options.bmat, &options.n, options.which,
+		  &options.nev, &options.tol, resid, &options.ncv, v, 
+		  &options.ldv, options.iparam, options.ipntr, workd,
+		  workl, &options.lworkl, &options.info);
+    
+    if (ido == -1 || ido == 1) {
+      
+      igraph_real_t *from=workd+options.ipntr[0]-1;
+      igraph_real_t *to=workd+options.ipntr[1]-1;
+      arpack_mult(to, from, options.n, M);
+      
+    } else { 
+      break;
+    }
+
+    pthread_mutex_lock(mutex);
+    *(data->steps) += 1;
+    if ( *(data->othersteps) == *(data->steps) ) { 
+      pthread_cond_signal(cond);
+    }
+
+    while ( *(data->othersteps) < *(data->steps) && *(data->othersteps) != -1 ) {
+      pthread_cond_wait(cond, mutex);
+    }
+    pthread_mutex_unlock(mutex);
+  }
+
+  pthread_mutex_lock(mutex);
+  *data->steps = -1;
+  pthread_cond_signal(cond);
+  pthread_mutex_unlock(mutex);
+
+  if (options.info != 0) {
+    printf("ARPACK error\n");
+    return 0;
+  }
+
+  igraphdseupd_(&rvec, all, select, d, v, &options.ldv,
+		&options.sigma, options.bmat, &options.n,
+		options.which, &options.nev, &options.tol,
+		resid, &options.ncv, v, &options.ldv, options.iparam,
+		options.ipntr, workd, workl, &options.lworkl,
+		&options.ierr);
+  
+  if (options.ierr != 0) {
+    printf("ARPACK error\n");
+    return 0;
+  }
+  
+  igraph_vector_resize(result, options.n);
+  for (i=0; i<options.n; i++) {
+    VECTOR(*result)[i] = v[i];
+  }
+
+  free(v);
+  free(workl);
+  free(workd);
+  free(d);
+  free(resid);
+  free(ax);
+  free(select);
+
+  return 0;
+}
+
+int main() {
+  pthread_t thread_id1, thread_id2;
+  void *exit_status1, *exit_status2;
+  igraph_matrix_t m1, m2;
+  igraph_vector_t result1, result2;
+  pthread_cond_t steps_cond = PTHREAD_COND_INITIALIZER;
+  pthread_mutex_t steps_mutex = PTHREAD_MUTEX_INITIALIZER;
+  int steps1=0, steps2=0;
+  thread_data_t 
+    data1 = { &m1, &result1, &steps_cond, &steps_mutex, &steps1, &steps2 },
+    data2 = { &m2, &result2, &steps_cond, &steps_mutex, &steps2, &steps1 };
+  int i, j;
+
+  /* Skip if igraph is not thread safe */
+  if (!IGRAPH_THREAD_SAFE) {
+    return 77;
+  }
+
+  igraph_matrix_init(&m1, 10, 10);
+  igraph_matrix_init(&m2, 10, 10);
+  igraph_vector_init(&result1, igraph_matrix_nrow(&m1));
+  igraph_vector_init(&result2, igraph_matrix_nrow(&m2));  
+
+  igraph_rng_seed(igraph_rng_default(), 42);
+  
+  for (i=0; i<igraph_matrix_nrow(&m1); i++) {
+    for (j=0; j<=i; j++) {
+      MATRIX(m1, i, j) = MATRIX(m1, j, i) = 
+	igraph_rng_get_integer(igraph_rng_default(), 0, 10);
+    }
+  }
+
+  for (i=0; i<igraph_matrix_nrow(&m2); i++) {
+    for (j=0; j<=i; j++) {
+      MATRIX(m2, i, j) = MATRIX(m2, j, i) = 
+	igraph_rng_get_integer(igraph_rng_default(), 0, 10);
+    }
+  }
+
+  pthread_create(&thread_id1, NULL, thread_function, (void *) &data1);
+  pthread_create(&thread_id2, NULL, thread_function, (void *) &data2);
+
+  pthread_join(thread_id1, &exit_status1);
+  pthread_join(thread_id2, &exit_status2);
+
+  igraph_matrix_print(&m1);
+  igraph_vector_print(&result1);
+  printf("---\n");
+  igraph_matrix_print(&m2);
+  igraph_vector_print(&result2);
+  
+  igraph_vector_destroy(&result1);
+  igraph_vector_destroy(&result2);
+  igraph_matrix_destroy(&m1);
+  igraph_matrix_destroy(&m2);  
+
+  return 0;
+}
diff --git a/examples/simple/tls2.out b/examples/simple/tls2.out
new file mode 100644
index 0000000..0ae788b
--- /dev/null
+++ b/examples/simple/tls2.out
@@ -0,0 +1,23 @@
+4 8 2 6 1 3 0 2 4 10
+8 10 8 6 1 6 10 10 0 4
+2 8 8 1 0 1 7 2 3 2
+6 6 1 4 5 7 9 6 5 5
+1 1 0 5 9 7 10 3 6 0
+3 6 1 7 7 0 2 6 4 8
+0 10 7 9 10 2 0 5 1 6
+2 10 2 6 3 6 5 0 0 2
+4 0 3 5 6 4 1 0 3 4
+10 4 2 5 0 8 6 2 4 5
+0.286678 0.451579 0.240944 0.373405 0.279524 0.306442 0.358295 0.280974 0.192354 0.316299
+---
+10 6 0 7 0 8 7 9 8 10
+6 5 9 1 10 4 2 0 3 9
+0 9 6 4 10 3 4 1 4 8
+7 1 4 0 10 0 7 10 5 4
+0 10 10 10 6 1 1 4 2 10
+8 4 3 0 1 2 6 2 6 4
+7 2 4 7 1 6 5 2 6 9
+9 0 1 10 4 2 2 7 2 10
+8 3 4 5 2 6 6 2 0 6
+10 9 8 4 10 4 9 10 6 7
+0.383729 0.301458 0.289645 0.287748 0.324551 0.214976 0.2921 0.298273 0.252215 0.453578
diff --git a/examples/simple/topology.c b/examples/simple/topology.c
new file mode 100644
index 0000000..77ce978
--- /dev/null
+++ b/examples/simple/topology.c
@@ -0,0 +1,63 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+
+int main() {
+  
+  igraph_t g;
+  igraph_vector_t edges;
+  igraph_vector_t vids;
+  igraph_integer_t class;
+  
+  igraph_vector_init_int_end(&edges, -1, 
+			     0,1, 1,3, 1,4, 1,6, 3,1,
+			     4,1, 4,2, 6,4, 6,5, 7,8,
+			     8,7, 7,9, 9,7, 8,9, 9,8,
+			     -1);
+  igraph_create(&g, &edges, 0, IGRAPH_DIRECTED);
+  igraph_vector_destroy(&edges);
+  
+  igraph_vector_init_int_end(&vids, -1, 1,4,6, -1);
+  igraph_isoclass_subgraph(&g, &vids, &class);
+  printf("class: %i\n", (int)class);
+  igraph_vector_destroy(&vids);
+
+  igraph_vector_init_int_end(&vids, -1, 0,1,3, -1);
+  igraph_isoclass_subgraph(&g, &vids, &class);
+  printf("class: %i\n", (int)class);
+  igraph_vector_destroy(&vids);
+
+  igraph_vector_init_int_end(&vids, -1, 7,8,9, -1);
+  igraph_isoclass_subgraph(&g, &vids, &class);
+  printf("class: %i\n", (int)class);
+  igraph_vector_destroy(&vids);
+
+  igraph_vector_init_int_end(&vids, -1, 0,2,5, -1);
+  igraph_isoclass_subgraph(&g, &vids, &class);
+  printf("class: %i\n", (int)class);
+  igraph_vector_destroy(&vids);
+  
+  igraph_destroy(&g);
+  return 0;
+}
diff --git a/examples/simple/topology.out b/examples/simple/topology.out
new file mode 100644
index 0000000..c69226c
--- /dev/null
+++ b/examples/simple/topology.out
@@ -0,0 +1,4 @@
+class: 12
+class: 5
+class: 15
+class: 0
diff --git a/examples/simple/vector.c b/examples/simple/vector.c
new file mode 100644
index 0000000..a18de1c
--- /dev/null
+++ b/examples/simple/vector.c
@@ -0,0 +1,341 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_vector_t v, v2, v3;
+  int i;
+  igraph_real_t *ptr;
+  long int pos;
+
+  /* simple init */
+  igraph_vector_init(&v, 0);
+  igraph_vector_destroy(&v);
+
+  /* vector of zeros */
+  igraph_vector_init(&v, 10);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* VECTOR(), igraph_vector_size */
+  igraph_vector_init(&v, 10);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    VECTOR(v)[i]=10-i;
+  }
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_reserve, igraph_vector_push_back */
+  igraph_vector_init(&v, 0);
+  igraph_vector_reserve(&v, 10);
+  for (i=0; i<10; i++) {
+    igraph_vector_push_back(&v, i);
+  }
+
+  /* igraph_vector_empty, igraph_vector_clear */
+  if (igraph_vector_empty(&v)) {
+    return 1;
+  }
+  igraph_vector_clear(&v);
+  if (!igraph_vector_empty(&v)) {
+    return 2;
+  }
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_e, igraph_vector_e_ptr */
+  igraph_vector_init(&v, 5);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    *igraph_vector_e_ptr(&v, i) = 100*i;
+  }
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    fprintf(stdout, " %li", (long int)igraph_vector_e(&v, i));
+  }
+  fprintf(stdout, "\n");
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_set */
+  igraph_vector_init(&v, 5);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    igraph_vector_set(&v, i, 20*i);
+  }
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_null */
+  igraph_vector_init(&v, 0);
+  igraph_vector_null(&v);
+  igraph_vector_destroy(&v);
+  igraph_vector_init(&v, 10);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    VECTOR(v)[i]=i+1;
+  }
+  igraph_vector_null(&v);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_tail, igraph_vector_pop_back */
+  igraph_vector_init(&v, 10);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    VECTOR(v)[i]=i+1;
+  }
+  while (!igraph_vector_empty(&v)) {
+    fprintf(stdout, " %li", (long int)igraph_vector_tail(&v));
+    fprintf(stdout, " %li", (long int)igraph_vector_pop_back(&v));
+  }
+  fprintf(stdout, "\n");
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_init_seq, igraph_vector_order */
+  igraph_vector_init_seq(&v, 1, 10);
+  igraph_vector_init(&v2, 0);
+  igraph_vector_order1(&v, &v2, 10);
+  print_vector(&v2, stdout);
+  igraph_vector_destroy(&v2);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_resize, igraph_vector_sort */
+  igraph_vector_init(&v, 20);  
+  for (i=0; i<10; i++) {
+    VECTOR(v)[i]=10-i;
+  }
+  igraph_vector_resize(&v, 10);
+  igraph_vector_sort(&v);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_max, igraph_vector_init_copy */
+  igraph_vector_init(&v, 10);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    VECTOR(v)[i]=100-i;    
+  }
+  for (i=0; i<10; i++) {
+    fprintf(stdout, " %li", (long int)VECTOR(v)[i]);
+  }
+  fprintf(stdout, "\n");
+  fprintf(stdout, " %li\n", (long int)igraph_vector_max(&v));
+
+  igraph_vector_destroy(&v);
+  ptr=(igraph_real_t*) malloc(10* sizeof(igraph_real_t));
+  igraph_vector_init_copy(&v, ptr, 10);
+  free(ptr);
+  for (i=0; i<10; i++) {
+    VECTOR(v)[i]=100-i;
+  }
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+  
+  /* igraph_vector_copy_to */
+  ptr=(igraph_real_t*) malloc(10* sizeof(igraph_real_t));
+  igraph_vector_init_seq(&v, 11, 20);
+  igraph_vector_copy_to(&v, ptr);
+  for (i=0; i<10; i++) {
+    fprintf(stdout, " %li", (long int)ptr[i]);
+  }
+  fprintf(stdout, "\n");
+  free(ptr);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_init_seq, igraph_vector_sum, igraph_vector_prod */
+  igraph_vector_init_seq(&v, 1, 5);
+  fprintf(stdout, " %li", (long int)igraph_vector_sum(&v));
+  fprintf(stdout, " %li\n", (long int)igraph_vector_prod(&v));
+  
+  /* igraph_vector_remove_section */
+  igraph_vector_remove_section(&v, 2, 4);
+  fprintf(stdout, " %li", (long int)igraph_vector_sum(&v));
+  fprintf(stdout, " %li\n", (long int)igraph_vector_prod(&v));
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_remove */
+  igraph_vector_init_seq(&v, 1, 10);
+  igraph_vector_remove(&v, 9);
+  igraph_vector_remove(&v, 0);
+  igraph_vector_remove(&v, 4);
+  fprintf(stdout, " %li\n", (long int)igraph_vector_sum(&v));
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_move_interval */
+  igraph_vector_init_seq(&v, 0, 9);
+  igraph_vector_move_interval(&v, 5, 10, 0);
+  if (igraph_vector_sum(&v) != 70) {
+    return 3;
+  }
+  igraph_vector_destroy(&v);
+    
+  /* igraph_vector_isininterval */
+  igraph_vector_init_seq(&v, 1, 10);
+  if (!igraph_vector_isininterval(&v, 1, 10)) {
+    return 4;
+  }
+  if (igraph_vector_isininterval(&v, 2, 10)) {
+    return 5;
+  }
+  if (igraph_vector_isininterval(&v, 1, 9)) {
+    return 6;
+  }
+
+  /* igraph_vector_any_smaller */
+  if (igraph_vector_any_smaller(&v, 1)) {
+    return 7;
+  }
+  if (!igraph_vector_any_smaller(&v, 2)) {
+    return 8;
+  }
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_all_e */
+
+  /* igraph_vector_binsearch */
+  igraph_vector_init_seq(&v, 0, 9);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    if (!igraph_vector_binsearch(&v, 0, 0)) {
+      return 9;
+    }
+  }
+  if (igraph_vector_binsearch(&v, 10, 0)) {
+    return 10;
+  }
+  if (igraph_vector_binsearch(&v, -1, 0)) {
+    return 11;
+  }
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    VECTOR(v)[i]= 2*i;
+  }
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    long int pos;
+    if (!igraph_vector_binsearch(&v, VECTOR(v)[i], &pos)) {
+      fprintf(stderr, "cannot find %i\n", (int)VECTOR(v)[i]);
+      return 12;
+    }
+    if (pos != i) {
+      return 13;
+    }
+    if (igraph_vector_binsearch(&v, VECTOR(v)[i]+1, &pos)) {
+      return 14;
+    }
+  }
+  igraph_vector_destroy(&v);
+
+  /* Binsearch in empty vector */
+  igraph_vector_init(&v, 0);
+  if (igraph_vector_binsearch2(&v, 0)) {
+    return 16;
+  }
+  if (igraph_vector_binsearch(&v, 1, &pos)) {
+    return 17;
+  }
+  if (pos != 0) {
+    return 18;
+  }
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_init_real */
+  igraph_vector_init_real(&v, 10, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_init_int */
+  igraph_vector_init_int(&v, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_init_real */
+  igraph_vector_init_real_end(&v, -1, 1.0, 2.0, 3.0, 4.0, 5.0, 
+		       6.0, 7.0, 8.0, 9.0, 10.0, -1.0);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_init_int */
+  igraph_vector_init_int_end(&v, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* igraph_vector_permdelete */
+  /* igraph_vector_remove_negidx */
+
+  /* order2 */
+  igraph_vector_init_int_end(&v, -1, 10,9,8,7,6,7,8,9,10, -1);
+  igraph_vector_order2(&v);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* filter_smaller, quite special.... */
+  igraph_vector_init_int_end(&v, -1, 0,1,2,3,4,4,4,4,5,6,7,8, -1);
+  igraph_vector_filter_smaller(&v, 4);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+  igraph_vector_init_int_end(&v, -1, 1,2,3,4,4,4,4,5,6,7,8, -1);
+  igraph_vector_filter_smaller(&v, 0);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+  igraph_vector_init_int_end(&v, -1, 0,0,1,2,3,4,4,4,4,5,6,7,8, -1);
+  igraph_vector_filter_smaller(&v, 0);
+  print_vector(&v, stdout);
+  igraph_vector_destroy(&v);
+
+  /* rank */
+  igraph_vector_init_int_end(&v, -1, 0,1,2,6,5,2,1,0, -1);
+  igraph_vector_init(&v2, 0);
+  igraph_vector_rank(&v, &v2, 7);
+  print_vector(&v, stdout);
+  print_vector(&v2, stdout);
+  igraph_vector_destroy(&v);
+  igraph_vector_destroy(&v2);
+
+  /* order */
+  igraph_vector_init_int_end(&v,  -1, 1,1,2,2, -1);
+  igraph_vector_init_int_end(&v2, -1, 2,3,1,3, -1);
+  igraph_vector_init(&v3, 0);
+  igraph_vector_order(&v, &v2, &v3, 3);
+  print_vector(&v3, stdout);
+  igraph_vector_destroy(&v);
+  igraph_vector_destroy(&v2);
+  igraph_vector_destroy(&v3);
+
+  /* fill */
+  
+  igraph_vector_init(&v, 100);
+  igraph_vector_fill(&v, 1.234567);
+  for (i=0; i<igraph_vector_size(&v); i++) {
+    if (VECTOR(v)[i] != 1.234567) { 
+      return 15;
+    }
+  }
+  igraph_vector_destroy(&v);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 16;
+
+  return 0;
+}
+  
diff --git a/examples/simple/vector.out b/examples/simple/vector.out
new file mode 100644
index 0000000..4134f24
--- /dev/null
+++ b/examples/simple/vector.out
@@ -0,0 +1,26 @@
+ 0 0 0 0 0 0 0 0 0 0
+ 10 9 8 7 6 5 4 3 2 1
+ 0 100 200 300 400
+ 0 20 40 60 80
+ 0 0 0 0 0 0 0 0 0 0
+ 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1
+ 0 1 2 3 4 5 6 7 8 9
+ 1 2 3 4 5 6 7 8 9 10
+ 100 99 98 97 96 95 94 93 92 91
+ 100
+ 100 99 98 97 96 95 94 93 92 91
+ 11 12 13 14 15 16 17 18 19 20
+ 15 120
+ 8 10
+ 38
+ 1 2 3 4 5 6 7 8 9 10
+ 1 2 3 4 5 6 7 8 9 10
+ 1 2 3 4 5 6 7 8 9 10
+ 1 2 3 4 5 6 7 8 9 10
+ 0 8 1 7 6 2 3 5 4
+ 4 4 5 6 7 8
+ 1 2 3 4 4 4 4 5 6 7 8
+ 0 1 2 3 4 4 4 4 5 6 7 8
+ 0 1 2 6 5 2 1 0
+ 1 3 5 7 6 4 2 0
+ 0 1 2 3
diff --git a/examples/simple/vector2.c b/examples/simple/vector2.c
new file mode 100644
index 0000000..3ef5687
--- /dev/null
+++ b/examples/simple/vector2.c
@@ -0,0 +1,125 @@
+/* -*- 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.h>
+#include <stdlib.h>
+
+void print_vector(igraph_vector_t *v, FILE *f) {
+  long int i;
+  for (i=0; i<igraph_vector_size(v); i++) {
+    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
+  }
+  fprintf(f, "\n");
+}
+
+int main() {
+  
+  igraph_vector_t v1, v2, v3;
+  igraph_real_t min, max;
+  long int imin, imax;
+  int i;
+  
+  igraph_vector_init_seq(&v1, 1, 10);
+  igraph_vector_init_seq(&v2, 0, 9);
+  
+  igraph_vector_swap(&v1, &v2);
+  print_vector(&v1, stdout);
+  print_vector(&v2, stdout);
+  
+  igraph_vector_swap_elements(&v1, 0, 9);
+  igraph_vector_swap_elements(&v1, 3, 6);
+  print_vector(&v1, stdout);
+  
+  igraph_vector_reverse(&v2);
+  print_vector(&v2, stdout);
+  igraph_vector_reverse(&v2);
+  print_vector(&v2, stdout);
+  
+  igraph_vector_destroy(&v1);
+  igraph_vector_destroy(&v2);
+  
+  igraph_vector_init(&v1, 10);
+  igraph_vector_init(&v2, 10);
+  igraph_vector_fill(&v1, 4);
+  igraph_vector_fill(&v2, 2);
+  
+  igraph_vector_add(&v1, &v2);
+  print_vector(&v1, stdout);
+  igraph_vector_sub(&v1, &v2);
+  print_vector(&v1, stdout);
+  igraph_vector_div(&v1, &v2);
+  print_vector(&v1, stdout);
+  igraph_vector_mul(&v1, &v2);
+  print_vector(&v1, stdout);
+  
+  igraph_vector_minmax(&v1, &min, &max);
+  igraph_vector_which_minmax(&v1, &imin, &imax);
+  printf("%g %g %li %li\n", min, max, imin, imax);
+  
+  igraph_vector_destroy(&v1);
+  igraph_vector_destroy(&v2);
+  
+  igraph_vector_init_seq(&v1, 1, 10);
+  igraph_vector_init(&v2, 10);
+  for (i=0; i<10; i++) { VECTOR(v2)[i] = 10-i; }
+
+  igraph_vector_minmax(&v1, &min, &max);
+  igraph_vector_which_minmax(&v1, &imin, &imax);
+  printf("%g %g %li %li\n", min, max, imin, imax);
+  igraph_vector_minmax(&v2, &min, &max);
+  igraph_vector_which_minmax(&v2, &imin, &imax);
+  printf("%g %g %li %li\n", min, max, imin, imax);
+  
+  if (igraph_vector_isnull(&v1)) {
+    return 1;
+  }
+  igraph_vector_null(&v1);
+  if (!igraph_vector_isnull(&v1)) {
+    return 2;
+  }
+
+  igraph_vector_destroy(&v1);
+  igraph_vector_destroy(&v2);
+
+  igraph_vector_init_int(&v1, 10, 3, 5, 6, 6, 6, 7, 8, 8, 9, 10);
+  igraph_vector_init_int(&v2, 10, 1, 3, 3, 6, 6, 9, 12, 15, 17, 20);
+  igraph_vector_init(&v3, 0);
+
+  igraph_vector_intersect_sorted(&v1, &v2, &v3);
+  print_vector(&v3, stdout);
+
+  igraph_vector_difference_sorted(&v1, &v2, &v3);
+  print_vector(&v3, stdout);
+  igraph_vector_difference_sorted(&v2, &v1, &v3);
+  print_vector(&v3, stdout);
+  igraph_vector_difference_sorted(&v2, &v2, &v3);
+  print_vector(&v3, stdout);
+
+  igraph_vector_destroy(&v1);
+  igraph_vector_destroy(&v2);
+  igraph_vector_destroy(&v3);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 3; 
+
+  return 0;
+}
diff --git a/examples/simple/vector2.out b/examples/simple/vector2.out
new file mode 100644
index 0000000..ec3caff
--- /dev/null
+++ b/examples/simple/vector2.out
@@ -0,0 +1,16 @@
+ 0 1 2 3 4 5 6 7 8 9
+ 1 2 3 4 5 6 7 8 9 10
+ 9 1 2 6 4 5 3 7 8 0
+ 10 9 8 7 6 5 4 3 2 1
+ 1 2 3 4 5 6 7 8 9 10
+ 6 6 6 6 6 6 6 6 6 6
+ 4 4 4 4 4 4 4 4 4 4
+ 2 2 2 2 2 2 2 2 2 2
+ 4 4 4 4 4 4 4 4 4 4
+4 4 0 0
+1 10 0 9
+1 10 9 0
+ 3 6 6 9
+ 5 7 8 8 10
+ 1 12 15 17 20
+
diff --git a/examples/simple/vector3.c b/examples/simple/vector3.c
new file mode 100644
index 0000000..00c6767
--- /dev/null
+++ b/examples/simple/vector3.c
@@ -0,0 +1,46 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge MA, USA 02139
+   
+   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.h>
+
+int main() {
+  igraph_vector_t v;
+  
+  igraph_vector_init_seq(&v, 1, 1000);
+  if (igraph_vector_capacity(&v) != 1000) {
+    return 1;
+  }
+
+  igraph_vector_push_back(&v, 1001);
+  if (igraph_vector_capacity(&v) != 2000) { 
+    return 2;
+  }
+  
+  igraph_vector_resize_min(&v);
+  if (igraph_vector_capacity(&v) != igraph_vector_size(&v)) {
+    return 3;
+  }
+
+  igraph_vector_destroy(&v);
+  return 0;
+}
diff --git a/examples/simple/vector_ptr.c b/examples/simple/vector_ptr.c
new file mode 100644
index 0000000..dd1965a
--- /dev/null
+++ b/examples/simple/vector_ptr.c
@@ -0,0 +1,277 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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.h>
+#include <stdlib.h>
+
+igraph_vector_ptr_t custom_destructor_stack;
+
+void custom_destructor(void* ptr) {
+  igraph_vector_ptr_push_back(&custom_destructor_stack, ptr);
+}
+
+int main() {
+  
+  igraph_vector_ptr_t v1, v2;
+  igraph_vector_ptr_t v3=IGRAPH_VECTOR_PTR_NULL;
+  int i;
+  void ** ptr;
+  int d1=1, d2=2, d3=3, d4=4, d5=5;
+  char *block1=0, *block2=0;
+
+  /* igraph_vector_ptr_init, igraph_vector_ptr_destroy */
+  igraph_vector_ptr_init(&v1, 10);
+  igraph_vector_ptr_destroy(&v1);
+  igraph_vector_ptr_init(&v1, 0);
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_free_all, igraph_vector_ptr_destroy_all */
+  igraph_vector_ptr_init(&v1, 5);
+  for (i=0; i<igraph_vector_ptr_size(&v1); i++) {
+    VECTOR(v1)[i]=(void*)malloc(i*10);
+  }
+  igraph_vector_ptr_free_all(&v1);
+  for (i=0; i<igraph_vector_ptr_size(&v1); i++) {
+    VECTOR(v1)[i]=(void*)malloc(i*10);
+  }
+  igraph_vector_ptr_destroy_all(&v1);     
+  
+  /* igraph_vector_ptr_reserve */
+  igraph_vector_ptr_init(&v1, 0);
+  igraph_vector_ptr_reserve(&v1, 5);
+  igraph_vector_ptr_reserve(&v1, 15);
+  igraph_vector_ptr_reserve(&v1, 1);
+  igraph_vector_ptr_reserve(&v1, 0);
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_empty, igraph_vector_ptr_clear */
+  igraph_vector_ptr_init(&v1, 10);
+  if (igraph_vector_ptr_empty(&v1)) {
+    return 1;
+  }
+  igraph_vector_ptr_clear(&v1);
+  if (!igraph_vector_ptr_empty(&v1)) {
+    return 2;
+  }
+
+  /* igraph_vector_ptr_size */
+  if (igraph_vector_ptr_size(&v1) != 0) {
+    return 3;
+  }
+  igraph_vector_ptr_resize(&v1, 10);
+  if (igraph_vector_ptr_size(&v1) != 10) {
+    return 4;
+  }
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_push_back */
+  igraph_vector_ptr_init(&v1, 0);
+  for (i=0; i<10; i++) {
+    igraph_vector_ptr_push_back(&v1, (void*)malloc(i*10));
+  }
+  igraph_vector_ptr_destroy_all(&v1);
+  
+  /* igraph_vector_ptr_e */
+  igraph_vector_ptr_init(&v1, 5);
+  VECTOR(v1)[0]=&d1;
+  VECTOR(v1)[1]=&d2;
+  VECTOR(v1)[2]=&d3;
+  VECTOR(v1)[3]=&d4;
+  VECTOR(v1)[4]=&d5;
+  if (igraph_vector_ptr_e(&v1, 0) != &d1) {
+    return 5;
+  }
+  if (igraph_vector_ptr_e(&v1, 1) != &d2) {
+    return 6;
+  }
+  if (igraph_vector_ptr_e(&v1, 2) != &d3) {
+    return 7;
+  }
+  if (igraph_vector_ptr_e(&v1, 3) != &d4) {
+    return 8;
+  }
+  if (igraph_vector_ptr_e(&v1, 4) != &d5) {
+    return 9;
+  }
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_set */
+  igraph_vector_ptr_init(&v1, 5);
+  igraph_vector_ptr_set(&v1, 0, &d1);
+  igraph_vector_ptr_set(&v1, 1, &d2);
+  igraph_vector_ptr_set(&v1, 2, &d3);
+  igraph_vector_ptr_set(&v1, 3, &d4);
+  igraph_vector_ptr_set(&v1, 4, &d5);
+  if (igraph_vector_ptr_e(&v1, 0) != &d1) {
+    return 5;
+  }
+  if (igraph_vector_ptr_e(&v1, 1) != &d2) {
+    return 6;
+  }
+  if (igraph_vector_ptr_e(&v1, 2) != &d3) {
+    return 7;
+  }
+  if (igraph_vector_ptr_e(&v1, 3) != &d4) {
+    return 8;
+  }
+  if (igraph_vector_ptr_e(&v1, 4) != &d5) {
+    return 9;
+  }
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_null */
+  igraph_vector_ptr_init(&v1, 5);
+  igraph_vector_ptr_set(&v1, 0, &d1);
+  igraph_vector_ptr_set(&v1, 1, &d2);
+  igraph_vector_ptr_set(&v1, 2, &d3);
+  igraph_vector_ptr_set(&v1, 3, &d4);
+  igraph_vector_ptr_set(&v1, 4, &d5);
+  igraph_vector_ptr_null(&v1);
+  for (i=0; i<igraph_vector_ptr_size(&v1); i++) {
+    if (VECTOR(v1)[i] != 0) {
+      return 10;
+    }
+  }
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_resize */
+  igraph_vector_ptr_init(&v1, 10);
+  igraph_vector_ptr_set(&v1, 0, &d1);
+  igraph_vector_ptr_set(&v1, 1, &d2);
+  igraph_vector_ptr_set(&v1, 2, &d3);
+  igraph_vector_ptr_set(&v1, 3, &d4);
+  igraph_vector_ptr_set(&v1, 4, &d5);
+  igraph_vector_ptr_resize(&v1, 10);
+  igraph_vector_ptr_resize(&v1, 15);
+  igraph_vector_ptr_resize(&v1, 5);
+  if (igraph_vector_ptr_size(&v1) != 5) {
+    return 11;
+  }
+  if (igraph_vector_ptr_e(&v1, 0) != &d1) {
+    return 12;
+  }
+  if (igraph_vector_ptr_e(&v1, 1) != &d2) {
+    return 13;
+  }
+  if (igraph_vector_ptr_e(&v1, 2) != &d3) {
+    return 14;
+  }
+  if (igraph_vector_ptr_e(&v1, 3) != &d4) {
+    return 15;
+  }
+  if (igraph_vector_ptr_e(&v1, 4) != &d5) {
+    return 16;
+  }
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_view */
+  ptr=(void**) malloc(5 * sizeof(void*));
+  igraph_vector_ptr_view(&v3, ptr, 5);
+  ptr[0]=&d1; ptr[1]=&d2; ptr[2]=&d3; ptr[3]=&d4; ptr[4]=&d5;
+  for (i=0; i<igraph_vector_ptr_size(&v3); i++) {
+    if ( *((int*)VECTOR(v3)[i]) != i+1) {
+      return 17;
+    }
+  }
+  
+  /* igraph_vector_ptr_init_copy */
+  igraph_vector_ptr_init_copy(&v1, ptr, 5);
+  for (i=0; i<igraph_vector_ptr_size(&v1); i++) {
+    if ( *((int*)VECTOR(v1)[i]) != i+1) {
+      return 18;
+    }
+  }
+
+  /* igraph_vector_ptr_copy_to */
+  igraph_vector_ptr_copy_to(&v1, ptr);
+  for (i=0; i<igraph_vector_ptr_size(&v1); i++) {
+    if ( *((int*)ptr[i]) != i+1) {
+      return 19;
+    }
+  }
+  free(ptr);
+  igraph_vector_ptr_destroy(&v1);
+
+  /* igraph_vector_ptr_copy */
+  igraph_vector_ptr_init(&v1, 5);
+  igraph_vector_ptr_set(&v1, 0, &d1);
+  igraph_vector_ptr_set(&v1, 1, &d2);
+  igraph_vector_ptr_set(&v1, 2, &d3);
+  igraph_vector_ptr_set(&v1, 3, &d4);
+  igraph_vector_ptr_set(&v1, 4, &d5);
+  igraph_vector_ptr_copy(&v2, &v1);
+  igraph_vector_ptr_destroy(&v1);
+  for (i=0; i<igraph_vector_ptr_size(&v2); i++) {
+    if ( *((int*)VECTOR(v2)[i]) != i+1) {
+      return 20;
+    }
+  }
+
+  /* igraph_vector_ptr_remove */
+  igraph_vector_ptr_remove(&v2, 0);
+  igraph_vector_ptr_remove(&v2, 3);
+  if ( *((int*)VECTOR(v2)[0]) != 2) {
+      return 21;
+  }
+  if ( *((int*)VECTOR(v2)[1]) != 3) {
+      return 22;
+  }
+  if ( *((int*)VECTOR(v2)[2]) != 4) {
+      return 23;
+  }
+
+  igraph_vector_ptr_destroy(&v2);
+
+  /* Testing destructor */
+  igraph_vector_ptr_init(&custom_destructor_stack, 0);
+  igraph_vector_ptr_init(&v1, 2);
+  block1 = igraph_Calloc(32, char);
+  block2 = igraph_Calloc(64, char);
+  VECTOR(v1)[0] = block1; VECTOR(v1)[1] = block2;
+  if (igraph_vector_ptr_get_item_destructor(&v1) != 0) {
+    return 24;
+  }
+  if (igraph_vector_ptr_set_item_destructor(&v1, &custom_destructor) != 0) {
+    return 25;
+  }
+  /* Okay, let's clear the vector. This should push the blocks in the
+   * custom destructor stack */
+  igraph_vector_ptr_clear(&v1);
+  /* Put the blocks back and destroy the vector */
+  igraph_vector_ptr_push_back(&v1, block1);
+  igraph_vector_ptr_push_back(&v1, block2);
+  igraph_vector_ptr_destroy_all(&v1);
+
+  if (VECTOR(custom_destructor_stack)[0] != block1 ||
+      VECTOR(custom_destructor_stack)[1] != block2 ||
+      VECTOR(custom_destructor_stack)[2] != block1 ||
+      VECTOR(custom_destructor_stack)[3] != block2
+     )
+    return 26;
+
+  igraph_vector_ptr_destroy(&custom_destructor_stack);
+
+  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 27;
+
+  return 0;
+}
diff --git a/examples/simple/walktrap.c b/examples/simple/walktrap.c
new file mode 100644
index 0000000..dd83d88
--- /dev/null
+++ b/examples/simple/walktrap.c
@@ -0,0 +1,70 @@
+/* -*- 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.h>
+
+int main() {
+  igraph_t g;
+  igraph_matrix_t merges;
+  igraph_vector_t modularity;
+  long int no_of_nodes;
+  long int i;
+  
+  igraph_small(&g, 5, IGRAPH_UNDIRECTED, 
+	       0,1,0,2,0,3,0,4, 1,2,1,3,1,4, 2,3,2,4, 3,4,
+	       5,6,5,7,5,8,5,9, 6,7,6,8,6,9, 7,8,7,9, 8,9, 0,5, -1);
+  igraph_vector_init(&modularity, 0);
+  igraph_matrix_init(&merges, 0, 0);
+  
+  igraph_community_walktrap(&g, 0 /* no weights */,
+			    4 /* steps */,
+			    &merges, &modularity, 
+			    /* membership=*/ 0);
+  
+  no_of_nodes=igraph_vcount(&g);
+  printf("Merges:\n");
+  for (i=0; i<igraph_matrix_nrow(&merges); i++) {
+    printf("%2.1li + %2.li -> %2.li (modularity %4.2f)\n", 
+	   (long int)MATRIX(merges, i, 0), 
+	   (long int)MATRIX(merges, i, 1), 
+	   no_of_nodes+i,
+	   VECTOR(modularity)[i]);
+  }
+  
+  igraph_destroy(&g);
+
+  /* isolated vertices */
+  igraph_small(&g, 5, IGRAPH_UNDIRECTED, -1);
+  if (igraph_community_walktrap(&g, 0 /* no weights */, 4 /* steps */, &merges,
+      &modularity, /* membership = */ 0)) {
+    return 1;
+  }
+  if (igraph_vector_min(&modularity) != 0 || igraph_vector_max(&modularity) != 0) {
+    return 2;
+  }
+  igraph_destroy(&g);
+
+  igraph_matrix_destroy(&merges);
+  igraph_vector_destroy(&modularity);
+  return 0;
+}
diff --git a/examples/simple/walktrap.out b/examples/simple/walktrap.out
new file mode 100644
index 0000000..4814911
--- /dev/null
+++ b/examples/simple/walktrap.out
@@ -0,0 +1,10 @@
+Merges:
+ 6 +  7 -> 10 (modularity 0.00)
+ 2 +  4 -> 11 (modularity -0.07)
+ 8 + 10 -> 12 (modularity -0.04)
+ 3 + 11 -> 13 (modularity 0.02)
+ 9 + 12 -> 14 (modularity 0.08)
+ 1 + 13 -> 15 (modularity 0.16)
+ 0 + 15 -> 16 (modularity 0.25)
+ 5 + 14 -> 17 (modularity 0.35)
+16 + 17 -> 18 (modularity 0.45)
diff --git a/examples/simple/watts_strogatz_game.c b/examples/simple/watts_strogatz_game.c
new file mode 100644
index 0000000..57541af
--- /dev/null
+++ b/examples/simple/watts_strogatz_game.c
@@ -0,0 +1,112 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph R 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
+
+*/
+
+#include <igraph.h>
+#include <stdio.h>
+
+#define N 1000
+
+igraph_bool_t has_loops(const igraph_t *graph) {
+  int i, n=igraph_ecount(graph);
+  for (i=0; i<n; i++) {
+    if (IGRAPH_FROM(graph, i) == IGRAPH_TO(graph, i)) { return 1; }
+  }
+  return 0;
+}
+
+igraph_bool_t has_multiple(const igraph_t *graph) {
+  igraph_bool_t res;
+  igraph_has_multiple(graph, &res);
+  return res;
+}
+
+#define ERR() do {				\
+  printf("Seed: %d\n", seed);			\
+  igraph_write_graph_edgelist(&ws, stdout);	\
+  } while (0)
+
+#define SEED() do {							\
+    seed=igraph_rng_get_integer(igraph_rng_default(), 1, 10000);		\
+    igraph_rng_seed(igraph_rng_default(), seed);				\
+  } while (0)
+
+int main() {
+  
+  igraph_t ws;
+  igraph_bool_t sim, seen_loops, seen_multiple;
+  int i, seed=1305473657;
+
+  igraph_rng_seed(igraph_rng_default(), seed);
+  
+  /* No loops, no multiple edges */
+  for (i=0; i<N; i++) {
+    SEED();
+    igraph_watts_strogatz_game(&ws, /*dim=*/ 1, /*size=*/ 5, /*nei=*/ 1,
+			       /*p=*/ 0.5, /*loops=*/ 0, /*multiple=*/ 0);
+    igraph_is_simple(&ws, &sim); if (!sim) { ERR(); return 1; }
+    if (has_loops(&ws)) { ERR(); return 1; }
+    if (has_multiple(&ws)) { ERR(); return 2; }
+    igraph_destroy(&ws);
+  }
+
+  /* No loops, multiple edges possible */
+  seen_multiple=0;
+  for (i=0; i<N; i++) {
+    SEED();
+    igraph_watts_strogatz_game(&ws, /*dim=*/ 1, /*size=*/ 5, /*nei=*/ 1,
+			       /*p=*/ 0.5, /*loops=*/ 0, /*multiple=*/ 1);
+    if (has_loops(&ws)) { ERR(); return 3; }
+    seen_multiple = seen_multiple || has_multiple(&ws);
+    igraph_destroy(&ws);
+  }  
+  /* This might actually happen */
+  /* if (!seen_multiple) { return 4; } */
+
+  /* Loops possible, no multiple edges */
+  seen_loops=0;
+  for (i=0; i<N; i++) {
+    SEED();
+    igraph_watts_strogatz_game(&ws, /*dim=*/ 1, /*size=*/ 5, /*nei=*/ 1,
+			       /*p=*/ 0.5, /*loops=*/ 1, /*multiple=*/ 0);
+    if (has_multiple(&ws)) { return 5; }
+    seen_loops = seen_loops || has_loops(&ws);
+    igraph_destroy(&ws);
+  }
+  /* This might actually happen */
+  /* if (!seen_loops) { return 6; } */
+  
+  /* Both loops and multiple edges are possible */
+  for (i=0; i<N; i++) {
+    SEED();
+    igraph_watts_strogatz_game(&ws, /*dim=*/ 1, /*size=*/ 5, /*nei=*/ 1,
+			       /*p=*/ 0.5, /*loops=*/ 1, /*multiple=*/ 1);
+    seen_loops = seen_loops || has_loops(&ws);
+    seen_multiple = seen_multiple || has_multiple(&ws);
+    igraph_destroy(&ws);
+  }
+  /* This might actually happen */
+  /* if (!seen_loops) { return 7; } */
+  /* if (!seen_multiple) { return 8; }   */
+
+  return 0;
+}
diff --git a/examples/simple/wikti_en_V_syn.elist b/examples/simple/wikti_en_V_syn.elist
new file mode 100644
index 0000000..2b0e794
--- /dev/null
+++ b/examples/simple/wikti_en_V_syn.elist
@@ -0,0 +1,8293 @@
+0 1
+0 2
+0 220
+0 229
+0 1010
+1 2
+1 12
+1 3849
+3 4
+3 5
+3 6
+3 7
+3 8
+3 9
+3 10
+3 11
+4 7
+7 671
+8 2285
+9 671
+10 671
+10 939
+10 1355
+10 1844
+10 2546
+10 3054
+11 671
+12 3849
+13 14
+13 15
+13 16
+13 17
+13 2270
+14 1795
+14 2270
+14 2531
+15 2270
+17 1466
+18 19
+18 20
+18 21
+18 22
+18 23
+18 24
+18 25
+18 26
+18 2041
+21 1970
+22 838
+24 5101
+25 2531
+25 5101
+27 1079
+27 2041
+27 2126
+27 3081
+28 29
+28 30
+28 31
+28 32
+28 33
+28 34
+28 35
+28 36
+28 37
+28 38
+29 31
+29 35
+29 881
+29 882
+29 883
+29 884
+29 885
+38 3930
+39 40
+39 41
+39 1251
+42 6340
+43 44
+43 45
+43 46
+44 318
+47 48
+47 49
+47 50
+47 5319
+48 50
+48 51
+48 3380
+50 51
+50 52
+50 53
+50 54
+50 55
+50 79
+51 3380
+52 58
+52 59
+52 60
+52 61
+52 62
+52 63
+52 64
+52 65
+52 66
+52 67
+52 68
+52 69
+52 70
+52 71
+52 72
+52 73
+52 74
+52 75
+52 76
+52 77
+52 78
+52 1697
+53 3380
+56 7312
+57 1376
+58 61
+58 64
+58 67
+58 73
+58 2730
+60 3371
+61 3371
+66 68
+66 70
+66 1949
+66 3641
+66 4869
+66 4870
+66 4871
+66 4872
+74 2543
+74 4679
+75 76
+76 389
+76 665
+76 827
+76 853
+76 883
+76 1017
+76 1152
+76 1416
+76 1468
+76 1469
+76 1470
+76 1471
+76 1472
+76 1473
+76 1474
+76 1475
+76 1476
+76 1477
+76 1478
+76 1479
+76 1480
+76 1481
+76 1482
+76 1483
+76 1484
+76 1485
+76 1486
+77 725
+78 5319
+80 2539
+80 3798
+81 2467
+82 83
+82 84
+82 85
+82 86
+82 87
+82 88
+82 89
+82 90
+82 91
+82 92
+82 93
+82 94
+82 95
+82 96
+82 97
+82 1006
+82 2140
+83 85
+83 87
+83 88
+83 90
+83 91
+83 92
+83 93
+83 95
+83 114
+83 115
+84 612
+85 2140
+85 4577
+88 90
+88 91
+88 95
+88 241
+88 4572
+88 5016
+89 1003
+89 1164
+89 1180
+89 1201
+89 1909
+89 2390
+89 4415
+89 5125
+90 93
+90 1201
+90 1341
+90 2390
+91 241
+91 5016
+92 130
+92 3619
+95 4055
+97 612
+97 2531
+97 2937
+97 3516
+97 4023
+97 4024
+97 4025
+97 4026
+97 4027
+97 4028
+97 4029
+97 4030
+97 4031
+97 5016
+98 99
+98 100
+99 100
+99 106
+99 3481
+99 3616
+99 5874
+100 3616
+100 4755
+101 102
+101 103
+101 104
+101 105
+101 106
+101 107
+101 1095
+101 4777
+102 103
+102 104
+102 312
+102 400
+102 1189
+102 1567
+102 2699
+102 2760
+102 3393
+102 3448
+102 4243
+102 5088
+103 2760
+103 3393
+104 107
+104 1498
+104 1567
+104 1999
+104 3892
+104 4777
+105 106
+105 107
+106 107
+106 3622
+106 3952
+106 4515
+107 3997
+107 4777
+108 6079
+109 110
+109 111
+109 112
+109 113
+109 1679
+109 2263
+116 117
+116 118
+117 355
+118 251
+118 2571
+119 5857
+120 4825
+121 122
+123 124
+123 125
+123 126
+123 127
+124 125
+124 126
+124 127
+124 1398
+125 126
+125 127
+126 127
+128 129
+130 138
+130 2975
+130 3618
+131 132
+132 380
+132 384
+132 385
+132 386
+132 742
+132 1394
+132 1704
+132 2084
+132 2085
+132 2086
+132 3018
+132 3139
+132 3201
+132 3648
+132 3653
+132 3654
+132 3655
+132 4414
+132 4987
+132 5041
+133 2975
+134 135
+134 136
+135 5623
+136 6204
+137 138
+137 139
+137 140
+137 141
+137 142
+137 143
+137 144
+137 145
+137 146
+137 147
+137 148
+137 149
+137 150
+137 151
+137 152
+137 153
+137 154
+137 155
+137 156
+137 157
+137 158
+137 159
+137 160
+137 161
+137 162
+137 163
+137 164
+137 165
+137 166
+137 167
+137 168
+137 169
+137 170
+137 171
+137 172
+137 173
+137 174
+137 175
+137 176
+138 139
+138 140
+138 141
+138 142
+138 143
+138 185
+138 186
+138 187
+138 188
+138 189
+138 190
+138 191
+138 192
+138 193
+138 194
+138 195
+138 196
+138 197
+138 198
+138 199
+138 200
+138 201
+138 202
+138 203
+138 204
+138 205
+138 206
+138 207
+138 208
+138 209
+138 210
+138 211
+139 208
+140 142
+140 205
+140 208
+140 1704
+140 3960
+141 204
+141 3960
+142 143
+142 206
+159 297
+166 422
+166 423
+166 3804
+177 3930
+178 2725
+178 2728
+178 3816
+179 2120
+179 2122
+180 181
+181 4287
+181 6173
+181 6401
+181 6444
+181 7287
+181 7292
+182 445
+182 2260
+183 184
+185 1138
+185 1425
+185 1797
+185 2373
+185 2984
+185 3914
+187 1210
+187 1616
+187 4154
+188 597
+189 567
+189 1904
+189 2390
+189 4906
+190 1882
+190 2027
+190 4158
+191 1138
+191 1425
+191 3960
+194 1498
+195 1884
+198 211
+198 4920
+199 205
+202 621
+202 622
+202 623
+203 385
+203 1223
+203 3270
+204 567
+204 587
+204 1022
+204 1704
+204 1904
+204 2960
+205 1010
+205 1013
+205 1014
+205 1494
+205 1495
+205 1496
+206 2974
+207 354
+208 297
+208 1748
+208 3960
+210 597
+210 1138
+210 1425
+211 445
+211 1653
+211 3421
+212 6259
+213 1590
+214 498
+215 239
+215 240
+215 1153
+215 2672
+216 217
+216 218
+216 219
+216 220
+216 4766
+217 220
+217 2058
+219 220
+219 818
+219 819
+219 820
+219 821
+219 822
+219 823
+219 824
+219 825
+219 1722
+219 4766
+220 232
+220 283
+220 284
+220 285
+220 286
+220 287
+220 6453
+221 222
+221 223
+221 224
+221 225
+221 226
+221 227
+221 784
+221 3940
+222 3940
+223 1558
+224 1653
+224 1925
+224 3098
+225 226
+225 564
+225 1026
+225 1558
+225 2037
+225 2363
+225 3169
+225 6678
+226 227
+226 564
+226 1026
+226 1558
+226 1946
+226 1947
+226 2037
+227 1558
+227 2037
+228 1589
+228 3093
+228 6782
+229 230
+229 231
+229 232
+229 233
+229 234
+229 235
+229 236
+229 237
+229 238
+230 236
+230 1167
+230 3423
+230 3424
+232 233
+232 1010
+233 234
+233 235
+233 1563
+233 2064
+233 3091
+234 236
+234 4496
+236 4833
+239 240
+241 242
+241 243
+241 244
+241 245
+244 2390
+245 1254
+246 3094
+247 248
+249 250
+249 251
+249 252
+249 604
+250 251
+250 400
+250 965
+251 354
+251 393
+251 394
+251 395
+251 396
+251 397
+251 398
+251 399
+251 400
+251 401
+251 402
+251 985
+251 1105
+251 1126
+251 1918
+251 1980
+252 297
+253 254
+253 255
+253 256
+253 257
+253 258
+253 259
+253 260
+253 261
+253 262
+253 263
+253 264
+255 454
+255 1619
+255 1971
+257 523
+262 3571
+265 266
+265 267
+265 268
+265 269
+265 270
+265 271
+265 272
+265 273
+265 274
+265 275
+265 276
+265 277
+265 278
+265 279
+265 1821
+280 281
+280 282
+281 5678
+282 787
+282 1636
+282 2445
+282 6200
+283 6453
+285 6453
+286 2053
+288 839
+288 5033
+289 290
+289 291
+289 292
+289 293
+289 294
+289 295
+289 296
+289 297
+289 298
+289 299
+289 300
+289 301
+289 302
+289 303
+289 304
+289 305
+289 306
+289 307
+289 308
+289 706
+289 1201
+289 1722
+289 2059
+289 3615
+289 3935
+289 4539
+289 4554
+289 5254
+289 6307
+289 7197
+289 7300
+290 306
+290 7300
+291 306
+291 4554
+291 4555
+291 7300
+292 325
+294 3279
+296 4539
+296 4540
+296 7197
+297 298
+297 389
+297 404
+297 408
+297 409
+297 478
+297 581
+297 612
+297 614
+297 617
+297 700
+297 972
+297 1180
+297 1305
+297 1318
+297 1353
+297 1371
+297 1419
+297 1431
+297 1487
+297 1721
+297 1722
+297 1723
+297 1724
+297 1725
+297 1726
+297 1727
+297 1728
+297 1729
+297 1730
+297 1731
+297 1732
+297 1733
+297 1734
+297 1735
+297 1736
+297 1737
+297 1738
+297 1739
+297 1740
+297 1741
+297 1742
+297 1743
+297 1744
+297 1745
+297 1746
+297 1747
+297 1748
+297 1749
+297 1750
+297 1751
+297 1752
+297 1753
+297 1754
+297 1755
+297 1756
+297 1757
+297 2733
+298 1722
+298 2733
+298 3935
+299 498
+299 1722
+306 4554
+306 7300
+309 310
+309 311
+312 313
+312 314
+312 315
+312 316
+312 317
+312 368
+313 625
+313 626
+316 3390
+317 1674
+318 400
+319 320
+319 321
+319 6552
+322 935
+322 6054
+323 324
+325 326
+325 327
+325 328
+325 329
+325 330
+325 331
+325 332
+326 438
+328 2041
+328 2833
+329 1079
+330 587
+330 2200
+333 2495
+333 2531
+334 400
+334 1402
+334 2650
+334 3156
+334 3453
+335 336
+337 338
+337 339
+337 340
+337 341
+337 342
+337 343
+337 344
+337 345
+337 346
+337 347
+337 348
+337 349
+337 350
+337 351
+337 352
+337 353
+338 339
+338 3852
+339 341
+339 342
+339 343
+339 346
+339 347
+339 351
+339 4119
+341 342
+341 346
+341 347
+342 343
+342 347
+342 349
+342 1597
+346 347
+351 3169
+354 355
+354 356
+354 357
+354 358
+356 600
+359 3508
+359 3510
+360 1180
+361 362
+362 2732
+363 672
+364 2488
+365 366
+366 4491
+367 2213
+368 369
+368 370
+369 370
+369 1047
+369 1239
+369 1240
+369 1241
+369 1242
+369 1243
+371 6782
+372 373
+372 374
+372 375
+372 376
+372 377
+372 378
+372 379
+373 374
+373 375
+373 376
+373 377
+373 378
+373 379
+373 4791
+374 375
+374 378
+374 379
+375 1223
+376 1223
+381 3117
+381 5859
+382 3117
+382 5215
+382 5217
+383 1400
+384 385
+384 386
+384 387
+384 388
+384 5641
+385 610
+385 1889
+385 3269
+385 3270
+385 3271
+386 387
+386 1889
+386 3270
+386 5640
+386 7109
+386 7110
+387 5359
+387 5641
+388 1010
+388 2958
+389 390
+389 391
+389 392
+389 496
+389 1126
+391 763
+392 2079
+393 1105
+393 1106
+394 672
+396 453
+396 623
+396 2344
+396 2571
+396 2792
+396 4217
+397 1105
+398 596
+398 1413
+399 400
+399 1188
+399 1925
+399 1980
+399 2213
+400 470
+400 581
+400 617
+400 666
+400 671
+400 672
+400 689
+400 706
+400 722
+400 767
+400 857
+400 905
+400 914
+400 956
+400 968
+400 1090
+400 1105
+400 1114
+400 1118
+400 1171
+400 1172
+400 1173
+400 1174
+400 1175
+400 1176
+400 1177
+400 1178
+400 1179
+400 1180
+400 1181
+400 1182
+400 1183
+400 1184
+400 1185
+400 1186
+400 1187
+400 1188
+400 1189
+400 1190
+400 1191
+400 1192
+400 1193
+400 1194
+400 1195
+400 1219
+400 1653
+400 2263
+400 3963
+401 454
+402 604
+402 1137
+402 1138
+403 861
+405 406
+405 407
+405 408
+405 409
+405 410
+405 4500
+406 407
+406 1037
+406 1038
+406 1040
+406 3643
+407 1038
+407 1039
+407 1040
+407 2515
+407 3877
+407 5069
+407 5070
+407 5071
+408 1253
+408 1755
+408 3687
+408 3978
+408 3979
+408 3980
+408 3981
+408 4590
+409 454
+409 1724
+410 3755
+411 412
+411 413
+411 414
+411 415
+411 416
+411 417
+411 418
+411 832
+411 1096
+411 3062
+411 3488
+411 4018
+412 414
+412 4676
+412 5769
+413 800
+413 2753
+413 4876
+414 1153
+414 1349
+414 1350
+414 1351
+414 1352
+414 2924
+415 1153
+417 1688
+417 4016
+417 4018
+418 2159
+418 4018
+419 420
+421 827
+422 423
+422 701
+422 702
+422 703
+422 704
+422 705
+422 2999
+424 425
+424 426
+424 427
+424 428
+424 429
+424 430
+424 1932
+424 2293
+425 3533
+426 427
+426 428
+426 1766
+426 1767
+426 1768
+427 428
+427 1609
+427 3488
+427 4014
+427 5101
+428 1768
+428 3488
+428 3533
+429 3798
+430 915
+430 5101
+430 5561
+431 432
+431 4226
+432 3762
+432 4226
+433 985
+433 1180
+433 1212
+434 597
+434 3645
+434 3646
+435 436
+435 437
+435 1936
+436 1070
+436 1936
+436 1939
+436 3488
+436 4059
+437 1936
+437 5016
+439 1234
+439 1679
+439 2263
+439 3412
+440 441
+440 6135
+442 3553
+443 535
+444 4580
+444 4583
+445 446
+445 447
+445 448
+445 449
+445 450
+445 451
+445 452
+445 453
+446 954
+446 3436
+447 3371
+447 3428
+448 3624
+448 3625
+448 4036
+448 4908
+449 2296
+452 2607
+453 591
+453 679
+453 1106
+453 1628
+453 1688
+453 1927
+453 2344
+453 2345
+453 2607
+453 3026
+453 3224
+453 3806
+453 5490
+453 5794
+454 455
+454 456
+454 457
+454 458
+454 459
+454 460
+454 461
+454 462
+454 463
+454 464
+454 465
+454 466
+454 467
+454 468
+454 469
+454 470
+454 471
+454 472
+454 473
+454 474
+454 475
+454 476
+454 477
+454 478
+454 479
+454 480
+454 481
+454 482
+457 2054
+459 3997
+460 2531
+462 542
+465 1434
+465 1649
+465 1650
+465 1651
+465 1652
+465 6577
+469 4893
+470 541
+470 604
+470 686
+470 687
+470 1173
+470 1987
+470 2440
+470 2441
+471 835
+471 965
+471 2291
+471 4741
+471 4949
+472 1138
+473 985
+473 1955
+475 3907
+477 1138
+478 1724
+478 2213
+479 1877
+479 2483
+480 4289
+481 936
+481 1248
+483 484
+483 485
+483 486
+483 487
+483 488
+483 489
+483 490
+483 491
+483 492
+483 493
+483 4035
+485 644
+485 645
+485 1424
+485 2060
+485 2061
+485 2062
+485 2063
+486 487
+486 488
+486 489
+486 2597
+487 892
+487 894
+487 2452
+487 2599
+487 3622
+487 4900
+488 2105
+488 2106
+488 2107
+488 2108
+488 2110
+488 2111
+488 2112
+488 2113
+488 2114
+488 5916
+489 1036
+489 2106
+489 2597
+490 2114
+491 2112
+491 2113
+491 2114
+492 2114
+493 644
+493 3546
+493 3729
+493 4001
+493 4035
+494 495
+494 496
+494 497
+494 498
+494 499
+494 500
+494 501
+494 502
+495 3798
+495 4791
+495 5579
+496 587
+496 1425
+496 3211
+496 7179
+498 1331
+498 3152
+498 3205
+498 3206
+498 3207
+498 3208
+498 3209
+500 1356
+500 1489
+503 504
+503 681
+503 826
+503 4652
+505 506
+505 507
+505 508
+505 4015
+506 915
+506 1949
+507 4015
+507 5146
+508 5690
+509 3533
+510 4984
+511 512
+511 513
+511 514
+511 515
+511 516
+511 517
+511 518
+511 519
+512 1848
+513 2516
+513 5501
+514 634
+514 1619
+515 1848
+515 2030
+515 2516
+515 3112
+516 1848
+516 3112
+520 521
+520 522
+520 4085
+520 6529
+524 2405
+525 526
+527 528
+527 529
+527 530
+527 531
+528 2555
+529 1219
+530 3572
+531 1139
+531 1299
+531 1447
+531 2520
+531 2549
+531 2555
+531 2846
+531 3572
+531 3963
+531 6647
+531 7022
+532 1611
+533 534
+533 681
+533 3056
+535 536
+535 537
+535 538
+537 626
+537 900
+538 3075
+539 2827
+540 2228
+540 4160
+542 543
+542 544
+542 545
+542 546
+543 2041
+543 2425
+544 2425
+545 980
+547 1092
+548 549
+548 550
+548 551
+548 552
+548 553
+548 554
+548 555
+548 556
+548 557
+548 558
+548 559
+548 560
+548 561
+548 562
+548 745
+550 551
+550 745
+551 556
+551 558
+551 745
+551 906
+556 745
+558 745
+563 6075
+564 695
+564 696
+564 697
+564 5962
+564 6849
+565 6458
+566 782
+566 1096
+566 3434
+567 568
+567 569
+567 570
+567 571
+567 572
+567 573
+567 574
+567 575
+567 576
+567 577
+567 578
+567 3228
+568 1904
+568 3228
+569 575
+570 681
+570 985
+570 1722
+570 4135
+570 5317
+571 732
+573 826
+573 2816
+574 1904
+574 4906
+575 1904
+575 5507
+578 1180
+578 5125
+579 672
+580 581
+580 582
+580 583
+580 584
+580 585
+580 586
+580 1096
+580 1376
+581 1097
+581 1126
+581 1376
+581 2178
+581 3056
+582 1376
+582 2431
+583 1376
+584 1376
+584 2413
+584 2431
+587 588
+587 589
+587 590
+587 591
+587 592
+587 593
+587 594
+587 595
+587 596
+587 597
+587 598
+587 599
+587 600
+587 601
+587 602
+587 603
+587 1425
+587 3225
+588 593
+588 596
+589 783
+589 2200
+589 5340
+591 783
+591 5340
+593 595
+593 596
+593 597
+593 1633
+593 1843
+593 2373
+593 2374
+593 2375
+593 2376
+595 597
+595 1079
+596 597
+596 1310
+596 1413
+596 1414
+597 651
+597 905
+597 1305
+597 1371
+597 1729
+597 1730
+597 1731
+597 1986
+597 2324
+597 2325
+597 2326
+597 2327
+600 735
+600 813
+600 1075
+600 1076
+600 1077
+600 1078
+600 1079
+600 1080
+600 1081
+600 1082
+600 1083
+600 1084
+600 1085
+600 1086
+600 1087
+600 1088
+600 1089
+600 5016
+600 6387
+603 5772
+604 605
+604 606
+604 607
+604 608
+604 2441
+607 672
+608 985
+608 2213
+609 4962
+610 3270
+610 4204
+611 2362
+611 5380
+612 613
+612 614
+612 615
+612 616
+612 617
+612 618
+612 619
+612 620
+612 1931
+612 2258
+612 2531
+613 1931
+614 617
+614 794
+614 1918
+614 3378
+614 3379
+614 3380
+615 2937
+617 875
+617 876
+617 1035
+617 1126
+617 1130
+617 1180
+617 1446
+617 1769
+617 1918
+617 1999
+617 2213
+617 2214
+617 2234
+617 2587
+617 2588
+617 2589
+617 2590
+617 2591
+617 2592
+617 2593
+617 2594
+617 6980
+618 619
+618 935
+618 2333
+618 3460
+619 928
+619 2241
+619 2242
+620 6692
+621 622
+621 3454
+622 2862
+622 3748
+622 5404
+622 5405
+622 5406
+623 4217
+624 6148
+624 6149
+625 626
+625 627
+625 628
+626 897
+626 900
+626 1395
+626 1587
+626 2114
+626 3608
+626 4084
+627 4121
+628 4121
+629 630
+629 4876
+631 3440
+632 4570
+633 863
+633 864
+633 866
+633 1037
+633 1325
+633 4304
+634 635
+634 636
+634 637
+634 638
+634 639
+634 640
+634 641
+634 642
+634 643
+634 7002
+639 642
+639 1236
+640 642
+640 2228
+640 2495
+640 2531
+640 2653
+640 5561
+641 5561
+642 1223
+642 1236
+642 1339
+642 1399
+642 1400
+642 1401
+642 2329
+642 2531
+644 645
+646 647
+646 648
+646 649
+646 650
+649 650
+649 3788
+649 3789
+650 1385
+650 1832
+650 1909
+652 653
+652 654
+652 655
+652 656
+652 657
+652 658
+652 659
+652 660
+654 655
+656 660
+657 3763
+661 662
+661 663
+661 664
+661 1268
+661 1367
+661 2555
+662 1268
+662 2553
+662 3321
+663 1444
+663 2555
+663 6674
+664 3277
+664 3527
+665 827
+665 1648
+666 667
+666 668
+666 669
+666 670
+666 671
+666 672
+666 1180
+666 3443
+667 1071
+668 3443
+669 937
+671 2606
+671 3706
+672 965
+672 1111
+672 1491
+672 1492
+672 1493
+672 2333
+673 4580
+674 2267
+675 676
+676 4144
+677 678
+680 2531
+681 682
+681 683
+681 684
+681 685
+681 686
+681 687
+681 688
+681 689
+681 690
+681 691
+681 692
+681 5736
+684 2041
+685 1722
+685 5317
+689 1487
+689 3056
+690 4472
+691 692
+691 1923
+691 2604
+691 4472
+692 2604
+692 4472
+693 694
+695 1946
+696 2037
+696 2126
+696 5157
+698 699
+698 2487
+698 2488
+698 5456
+703 5691
+703 6782
+706 707
+706 708
+706 709
+706 710
+706 711
+706 712
+706 713
+706 714
+706 715
+706 716
+706 717
+706 718
+706 719
+706 720
+706 721
+706 722
+706 723
+706 724
+706 725
+706 726
+706 727
+706 1234
+706 1679
+706 6569
+707 708
+707 1002
+707 1008
+707 1223
+707 1234
+707 1679
+707 6569
+708 1119
+708 1679
+711 1681
+711 3516
+721 806
+721 1681
+722 783
+722 1069
+722 1070
+722 1180
+722 1219
+722 2178
+722 4736
+725 726
+725 1425
+725 1680
+725 2420
+725 4862
+728 2531
+728 3867
+729 3581
+730 915
+731 1353
+732 733
+734 1546
+736 737
+736 738
+736 739
+736 740
+736 741
+737 740
+737 741
+737 2858
+737 3346
+737 3347
+737 3348
+738 740
+739 740
+739 6039
+740 741
+740 1687
+740 1712
+740 6405
+741 2858
+741 3346
+741 3347
+742 743
+742 744
+745 746
+745 747
+745 748
+745 749
+745 750
+745 751
+747 4091
+752 753
+752 754
+753 754
+753 1951
+753 4065
+754 1283
+754 1951
+754 2755
+754 3631
+754 4065
+754 5154
+754 6147
+755 756
+757 758
+757 759
+757 760
+757 761
+761 1947
+761 2706
+762 4195
+764 765
+764 766
+764 2725
+764 2728
+764 3816
+764 4597
+765 2725
+765 2728
+765 3816
+765 4597
+767 1070
+767 1690
+767 2347
+767 5529
+768 769
+768 770
+768 771
+768 772
+768 773
+770 6933
+771 6940
+772 5696
+774 775
+776 3553
+777 778
+779 780
+779 781
+780 781
+780 799
+780 800
+780 2753
+780 3855
+781 800
+781 2779
+783 784
+783 5340
+784 986
+784 988
+784 1363
+784 1372
+784 3012
+784 4109
+784 5329
+785 786
+785 4833
+787 788
+787 789
+787 790
+788 1636
+788 2445
+789 2320
+789 2321
+791 1153
+792 4197
+793 794
+793 795
+794 1387
+794 1918
+796 906
+797 1697
+798 799
+798 800
+799 800
+799 2753
+799 2779
+799 4580
+800 2753
+800 2777
+800 2778
+800 2779
+800 4580
+800 4876
+801 802
+801 803
+801 804
+801 805
+802 6270
+806 807
+806 808
+808 1681
+809 810
+809 811
+809 3255
+810 811
+810 3247
+810 3254
+810 3255
+810 3256
+810 3257
+810 4172
+810 5949
+810 5950
+811 3244
+811 3245
+811 3246
+811 3247
+811 3248
+811 3249
+811 3250
+811 3251
+811 3252
+811 3253
+811 3254
+811 3255
+811 3256
+811 3257
+812 813
+812 814
+812 815
+812 5010
+813 3098
+815 7233
+816 3030
+817 906
+817 5926
+817 5981
+821 5548
+822 1657
+826 1219
+826 1653
+826 2816
+826 4782
+827 828
+827 829
+827 830
+827 831
+827 832
+827 833
+827 834
+827 2531
+832 1100
+832 1213
+832 1353
+832 2655
+832 4079
+832 4080
+832 4204
+832 5024
+833 922
+834 5097
+834 6692
+835 965
+836 837
+836 2092
+837 2092
+839 840
+839 841
+839 842
+839 843
+839 870
+839 2581
+840 870
+840 2581
+842 870
+844 4215
+845 846
+846 7056
+847 6895
+847 7117
+848 849
+848 850
+848 851
+849 4830
+852 4623
+854 855
+854 856
+857 1180
+857 1353
+857 2213
+857 5317
+858 3740
+859 7122
+860 6567
+861 862
+861 863
+861 864
+861 865
+861 866
+861 867
+861 868
+861 4304
+863 864
+863 865
+863 866
+863 868
+863 1325
+863 6279
+864 865
+864 866
+864 868
+864 1325
+865 1320
+866 1320
+866 1321
+866 1322
+866 1323
+866 1324
+866 1325
+867 5861
+868 1325
+869 5448
+870 871
+870 872
+870 873
+870 874
+870 875
+870 876
+870 877
+870 5033
+871 2581
+875 876
+875 926
+875 1304
+875 1386
+875 1542
+875 1543
+875 2145
+875 2146
+875 2147
+876 6581
+877 949
+877 1896
+877 2016
+877 2367
+877 3221
+877 3588
+877 5689
+877 7251
+878 1400
+878 2412
+879 3679
+879 5121
+880 3761
+883 1010
+883 1017
+884 1353
+884 2041
+885 1846
+885 4431
+886 887
+887 1877
+888 889
+888 890
+888 891
+889 890
+889 2065
+889 2066
+889 2067
+889 2068
+889 2069
+889 2070
+889 2071
+889 2072
+889 2073
+889 2074
+889 2075
+890 891
+890 2371
+890 2822
+890 3222
+890 3483
+890 3484
+890 3485
+890 3486
+890 3487
+890 3581
+890 4635
+890 4864
+890 5141
+890 5563
+890 6529
+891 2370
+891 3581
+891 4431
+892 893
+892 894
+892 895
+892 896
+895 2452
+896 1995
+896 2105
+896 2108
+896 2120
+896 3756
+896 5916
+897 898
+897 899
+897 900
+897 4134
+900 1583
+900 1584
+900 1585
+900 1586
+900 1587
+901 902
+901 903
+901 904
+901 2084
+902 903
+902 904
+903 904
+903 2084
+905 1980
+905 3836
+906 907
+906 908
+906 909
+906 910
+906 911
+906 912
+906 1314
+906 1821
+906 1822
+907 908
+907 2443
+907 2445
+907 3311
+907 3313
+908 3311
+908 6957
+911 1821
+912 2872
+913 4802
+914 915
+914 965
+915 916
+915 917
+915 918
+915 919
+915 920
+915 921
+915 922
+915 923
+915 924
+915 925
+915 5274
+919 5101
+921 923
+921 924
+921 3051
+922 923
+922 2566
+922 2567
+922 6830
+922 6831
+923 1358
+923 3213
+926 1697
+926 4700
+927 2662
+928 929
+928 930
+928 931
+928 932
+928 933
+928 934
+928 935
+928 936
+928 937
+928 938
+928 939
+928 940
+928 941
+928 4085
+929 930
+930 931
+930 932
+930 2003
+930 2662
+930 2668
+930 3422
+930 3924
+930 3925
+930 5287
+930 5630
+931 1363
+932 2662
+934 2212
+934 4085
+935 1162
+935 1941
+935 2015
+935 2332
+935 2604
+935 2605
+935 3404
+935 4113
+936 4085
+937 938
+937 941
+937 985
+937 2410
+937 2675
+937 3399
+937 4113
+937 5092
+939 1268
+939 2413
+942 972
+942 1598
+942 2602
+942 4683
+942 4690
+943 944
+943 945
+943 6554
+944 1653
+944 1657
+946 4690
+947 948
+947 949
+947 3221
+948 4430
+948 5302
+948 6559
+948 6560
+949 3221
+949 3222
+949 4012
+949 4174
+949 4924
+949 6605
+950 951
+950 952
+950 953
+950 954
+950 955
+950 2662
+951 3712
+952 2662
+954 1151
+954 2423
+954 3397
+956 4590
+957 6773
+958 959
+958 960
+958 961
+958 3169
+959 1387
+959 4465
+962 963
+962 964
+962 3007
+962 5633
+963 4433
+964 4433
+965 966
+965 967
+965 968
+965 969
+965 970
+965 971
+965 972
+965 2531
+965 3098
+966 2531
+966 3098
+966 4765
+967 2401
+972 1296
+972 1297
+973 2661
+974 5215
+974 5217
+975 5380
+976 977
+976 978
+976 979
+976 980
+976 981
+977 1827
+980 3928
+980 5371
+982 4443
+983 984
+983 985
+985 1690
+985 1691
+985 1697
+985 1698
+985 1699
+985 3919
+985 4820
+985 5203
+985 5331
+985 5332
+985 5333
+985 5334
+985 5335
+985 5336
+985 5337
+985 5338
+985 5339
+985 5340
+985 5341
+986 987
+986 988
+986 989
+986 990
+987 989
+987 990
+988 990
+989 990
+989 1729
+989 3291
+989 4284
+989 4373
+989 4736
+989 6378
+991 6458
+992 993
+992 994
+992 995
+995 1434
+995 1435
+996 997
+996 998
+996 999
+1000 2531
+1000 3098
+1001 3539
+1002 1003
+1002 1004
+1002 1005
+1002 1006
+1002 1007
+1002 1008
+1002 1009
+1005 1006
+1005 1008
+1006 1007
+1006 1009
+1006 1820
+1006 2526
+1006 3292
+1007 1009
+1007 1820
+1007 2488
+1007 3292
+1008 1820
+1008 2526
+1008 2527
+1008 2529
+1009 1472
+1009 1481
+1009 1820
+1009 2526
+1009 3223
+1010 1011
+1010 1012
+1010 1013
+1010 1014
+1010 1015
+1010 1016
+1010 1017
+1011 2958
+1013 1014
+1013 1495
+1013 1496
+1015 2956
+1015 2958
+1015 3156
+1015 3234
+1015 3567
+1015 3897
+1016 1022
+1016 5174
+1017 1021
+1017 1022
+1017 1120
+1017 1121
+1017 1122
+1017 1123
+1017 1124
+1017 2555
+1017 3321
+1017 4855
+1017 6654
+1018 1512
+1019 2041
+1020 3440
+1021 1022
+1021 1023
+1022 1023
+1022 2527
+1022 3187
+1022 4849
+1022 4850
+1022 4851
+1022 4852
+1022 4853
+1022 4854
+1022 4855
+1022 4856
+1024 1025
+1024 1026
+1024 1027
+1024 1028
+1024 1029
+1024 1030
+1024 1031
+1024 1032
+1024 3540
+1025 3540
+1026 1947
+1026 3540
+1028 3540
+1029 1423
+1029 1427
+1029 2141
+1029 2142
+1029 3750
+1031 3607
+1031 3702
+1031 3750
+1031 4182
+1031 5252
+1032 3540
+1032 3546
+1033 1126
+1033 1487
+1034 1035
+1037 1038
+1037 1039
+1037 1040
+1038 1039
+1039 1040
+1039 3771
+1040 3771
+1041 3143
+1042 1043
+1044 1054
+1045 2610
+1046 4561
+1047 1048
+1047 1049
+1049 3679
+1050 3546
+1051 5340
+1052 1053
+1053 7023
+1055 1353
+1055 4015
+1056 3706
+1056 6453
+1057 1058
+1057 1059
+1058 1769
+1060 1061
+1061 2449
+1061 2499
+1061 2591
+1061 3024
+1061 3695
+1061 3843
+1061 4273
+1062 1063
+1062 1064
+1065 5091
+1066 6286
+1067 6286
+1068 6887
+1069 3759
+1070 1806
+1072 6774
+1073 1791
+1073 2289
+1074 1434
+1074 4057
+1075 3930
+1075 4556
+1077 1079
+1078 3371
+1079 1473
+1079 2049
+1079 2375
+1080 3371
+1080 3712
+1083 2131
+1084 1679
+1084 1681
+1086 3156
+1090 1932
+1091 6288
+1092 1093
+1092 1094
+1092 1095
+1093 1095
+1093 3652
+1093 4545
+1093 4993
+1093 4994
+1095 3529
+1096 1097
+1096 1098
+1096 1099
+1096 1100
+1096 1101
+1096 1102
+1096 4016
+1097 1379
+1097 1520
+1097 2397
+1098 4016
+1100 2655
+1100 3062
+1101 4115
+1101 4741
+1103 1138
+1103 2553
+1104 6777
+1105 1106
+1105 1107
+1105 1108
+1105 1109
+1105 1110
+1105 1111
+1105 1112
+1105 2017
+1105 2263
+1108 1223
+1113 1716
+1113 3020
+1114 1180
+1114 3510
+1115 1116
+1116 3930
+1117 1234
+1117 1679
+1118 3030
+1118 4706
+1125 2212
+1126 1127
+1126 1128
+1126 1129
+1126 1130
+1126 1131
+1126 1132
+1126 1133
+1126 1134
+1126 1135
+1126 1136
+1126 1479
+1128 1133
+1128 1479
+1128 1565
+1128 1635
+1128 1666
+1128 1667
+1128 1668
+1128 1669
+1128 1670
+1129 1212
+1130 1133
+1130 1479
+1130 2589
+1132 3672
+1133 1444
+1133 1445
+1133 1448
+1133 2587
+1133 2589
+1133 3798
+1134 1487
+1134 4545
+1136 1831
+1137 1138
+1137 1139
+1137 1140
+1137 1141
+1137 1142
+1137 1143
+1137 1144
+1137 1145
+1137 1146
+1138 1310
+1138 1425
+1138 1758
+1138 1955
+1138 2010
+1138 2011
+1138 2012
+1138 2013
+1138 2014
+1139 1140
+1139 1299
+1139 1888
+1139 2520
+1139 2846
+1139 3853
+1139 6647
+1140 1498
+1140 3853
+1141 1964
+1141 3853
+1141 4446
+1143 1838
+1144 4459
+1144 6263
+1147 1697
+1148 1781
+1148 2284
+1148 3490
+1149 1180
+1149 3800
+1149 4082
+1150 5238
+1151 1153
+1151 2774
+1151 3895
+1153 1154
+1153 1155
+1153 1156
+1153 1157
+1153 1158
+1153 1159
+1153 1160
+1154 1223
+1155 6270
+1156 1415
+1156 4116
+1158 1223
+1159 1960
+1161 3089
+1163 1487
+1164 1165
+1164 1166
+1168 5309
+1169 1170
+1169 1223
+1169 6930
+1172 1653
+1173 1653
+1173 2441
+1173 7200
+1180 1199
+1180 1200
+1180 1201
+1180 1202
+1180 1203
+1180 1204
+1180 1205
+1180 1206
+1180 1207
+1180 1208
+1180 1209
+1180 1210
+1180 1211
+1180 1212
+1180 1213
+1180 1214
+1180 1215
+1180 1216
+1180 1217
+1180 1218
+1180 1219
+1180 1220
+1180 1221
+1180 1353
+1180 1846
+1180 4415
+1181 4590
+1182 1201
+1182 1660
+1182 3733
+1182 4590
+1184 1188
+1184 1919
+1184 1925
+1184 4227
+1185 1188
+1185 1280
+1185 1281
+1185 2402
+1185 3148
+1186 1188
+1186 1925
+1186 3148
+1187 1188
+1188 1595
+1188 2402
+1188 3148
+1188 3396
+1188 3397
+1188 3398
+1188 6861
+1193 6820
+1194 2210
+1194 4191
+1194 5329
+1194 5330
+1196 1197
+1198 4961
+1198 5834
+1199 4503
+1199 5168
+1200 1722
+1200 2095
+1200 2096
+1201 1202
+1201 2547
+1201 2747
+1201 2748
+1201 2749
+1201 2750
+1201 2751
+1201 2752
+1201 2753
+1201 2754
+1201 2755
+1201 2756
+1201 2757
+1201 2758
+1201 2759
+1201 4415
+1201 5125
+1202 2771
+1202 2773
+1202 4415
+1202 4416
+1202 5922
+1203 5125
+1204 1205
+1204 3155
+1209 6569
+1210 3507
+1210 4155
+1210 4156
+1210 6387
+1211 2937
+1211 5016
+1212 1353
+1212 1948
+1212 1949
+1213 3574
+1213 5024
+1214 4379
+1214 5785
+1219 1420
+1219 1423
+1219 1475
+1219 1911
+1219 2161
+1219 2162
+1219 2163
+1219 2164
+1219 2165
+1219 2166
+1219 2167
+1219 2168
+1219 2169
+1221 1845
+1221 1846
+1221 2415
+1221 2416
+1221 2417
+1221 2418
+1221 2419
+1221 5163
+1221 6057
+1222 2662
+1223 1224
+1223 1225
+1223 1226
+1223 1227
+1223 1228
+1223 1229
+1223 1230
+1223 1231
+1223 1232
+1223 1233
+1223 1234
+1223 1235
+1223 1236
+1223 1237
+1223 1238
+1223 2306
+1223 2307
+1226 1227
+1229 1997
+1230 1231
+1230 2306
+1230 2307
+1230 3897
+1230 5189
+1231 2306
+1231 2307
+1231 5189
+1231 5198
+1232 5189
+1232 5198
+1233 1904
+1233 2103
+1234 1391
+1234 1679
+1234 1680
+1234 2170
+1234 3318
+1234 3616
+1234 4005
+1234 4006
+1234 4007
+1234 4008
+1234 4009
+1234 4010
+1236 1401
+1236 2160
+1236 2531
+1237 1619
+1237 1932
+1243 6700
+1244 2126
+1244 2200
+1244 3732
+1244 3836
+1245 4144
+1246 1247
+1246 2495
+1246 2499
+1246 2650
+1246 2653
+1246 4113
+1246 4443
+1247 2495
+1247 4113
+1248 1249
+1248 1250
+1249 1250
+1249 4906
+1251 4042
+1252 6373
+1253 1254
+1253 1255
+1253 1256
+1253 2213
+1256 3433
+1257 1258
+1259 1791
+1260 1558
+1260 3056
+1260 3156
+1261 3156
+1262 4963
+1263 1932
+1264 1265
+1264 1266
+1264 3527
+1265 1724
+1265 1980
+1265 3527
+1265 6429
+1266 3527
+1266 6429
+1267 3156
+1268 1269
+1268 1270
+1268 1271
+1268 1272
+1268 1273
+1268 1274
+1268 1275
+1268 1276
+1268 1277
+1270 2457
+1270 2808
+1270 4527
+1273 6573
+1273 6574
+1273 6575
+1278 3440
+1279 3581
+1279 5154
+1280 1281
+1280 1282
+1280 1283
+1280 1284
+1283 1925
+1283 6861
+1285 2196
+1286 1287
+1286 1288
+1286 1289
+1287 1359
+1289 1359
+1290 1828
+1291 1292
+1291 1293
+1291 1294
+1291 2650
+1291 6706
+1293 1877
+1293 2483
+1293 3156
+1293 3317
+1294 2054
+1294 2845
+1295 2265
+1297 4040
+1298 1299
+1298 2798
+1298 5000
+1298 6647
+1299 2477
+1299 2521
+1299 2846
+1299 2848
+1299 3963
+1299 6647
+1299 6674
+1300 6127
+1300 6129
+1300 6130
+1301 1302
+1303 2356
+1304 1487
+1304 2108
+1304 3732
+1304 4766
+1305 1306
+1305 1307
+1308 2919
+1309 5194
+1310 1980
+1310 3689
+1311 1312
+1311 6748
+1312 4716
+1313 2041
+1314 1315
+1314 1316
+1314 1317
+1314 1821
+1319 4431
+1321 1322
+1321 2568
+1321 3419
+1322 2569
+1322 3419
+1322 3698
+1325 1701
+1325 3600
+1325 4304
+1326 4804
+1327 6289
+1328 5181
+1329 1330
+1329 1331
+1330 6129
+1331 1862
+1332 3498
+1333 4135
+1334 2127
+1334 5274
+1335 3054
+1335 4015
+1336 1413
+1336 1980
+1336 4777
+1336 5404
+1337 6366
+1338 4831
+1339 2531
+1340 3156
+1342 1464
+1342 2108
+1343 3156
+1343 5189
+1344 3344
+1345 1346
+1345 7117
+1346 1544
+1346 5329
+1346 7117
+1347 3379
+1348 1896
+1348 2016
+1348 5689
+1348 7251
+1353 1354
+1353 1355
+1353 1356
+1353 1660
+1353 3588
+1353 4015
+1355 4862
+1356 1489
+1357 1358
+1357 1359
+1358 1359
+1360 1361
+1361 3192
+1361 3193
+1361 3194
+1362 1997
+1362 4195
+1362 4197
+1362 7186
+1363 1364
+1363 1365
+1363 1366
+1363 1367
+1363 1368
+1363 1369
+1363 1370
+1363 1371
+1363 1372
+1363 1373
+1363 4109
+1363 4476
+1365 1367
+1366 4063
+1366 4476
+1367 1368
+1367 1720
+1367 3649
+1367 3650
+1367 4476
+1368 1720
+1369 4476
+1370 4476
+1374 3798
+1375 3490
+1376 1377
+1376 1378
+1376 1379
+1376 1447
+1379 3488
+1380 1381
+1380 1382
+1380 1383
+1380 1384
+1380 1385
+1380 3287
+1380 3600
+1380 3601
+1381 1383
+1381 1384
+1381 1842
+1381 2956
+1381 2957
+1381 2958
+1381 2959
+1381 3600
+1381 3963
+1382 4188
+1383 4144
+1384 3287
+1384 3600
+1385 3458
+1385 3540
+1385 3601
+1386 1387
+1387 1574
+1387 2753
+1387 2917
+1387 3669
+1388 1389
+1388 1390
+1388 1391
+1388 1392
+1388 1393
+1388 1394
+1391 2260
+1391 2263
+1391 4051
+1392 2054
+1393 2058
+1393 2818
+1394 2054
+1394 2058
+1394 4493
+1395 4464
+1396 1397
+1396 1398
+1397 1398
+1397 1569
+1397 3459
+1398 3459
+1400 2053
+1400 2258
+1400 2329
+1400 2331
+1400 2411
+1400 2412
+1400 2413
+1401 2531
+1402 1403
+1402 1404
+1402 1405
+1402 1406
+1402 1407
+1402 1408
+1402 1409
+1402 1410
+1402 1411
+1402 1412
+1402 7243
+1404 7243
+1413 1763
+1413 1764
+1413 1980
+1413 5595
+1417 1418
+1419 1758
+1421 1422
+1423 1424
+1423 1425
+1423 1426
+1423 1427
+1423 1428
+1423 3018
+1425 1426
+1425 1797
+1425 2013
+1425 2014
+1425 2235
+1425 2373
+1425 2420
+1425 2984
+1425 3225
+1425 3748
+1425 3914
+1426 1883
+1426 3471
+1426 4656
+1426 4755
+1427 2141
+1427 2142
+1427 3813
+1429 1430
+1429 1431
+1429 1432
+1429 1433
+1429 2655
+1429 4135
+1430 1431
+1430 1432
+1430 1433
+1431 1433
+1434 1435
+1434 1436
+1437 1438
+1437 1439
+1438 2362
+1440 2414
+1440 3490
+1441 1442
+1442 1443
+1444 1445
+1444 1446
+1444 1447
+1444 1448
+1444 1449
+1444 1450
+1444 1451
+1444 1452
+1444 2589
+1445 2589
+1445 4160
+1445 4274
+1445 4741
+1446 1447
+1446 2589
+1446 2591
+1446 3585
+1446 4703
+1447 2322
+1447 2555
+1447 2587
+1447 2589
+1447 2593
+1447 2751
+1447 3585
+1447 3586
+1447 3587
+1447 3588
+1447 3589
+1447 3590
+1447 3854
+1447 4160
+1447 6674
+1448 2589
+1451 2555
+1453 2126
+1453 2960
+1453 4766
+1453 7154
+1454 1455
+1454 1456
+1457 1994
+1458 1781
+1459 3930
+1460 1461
+1460 1462
+1460 4741
+1461 1462
+1462 2524
+1462 4741
+1463 1464
+1463 1465
+1463 1466
+1463 2258
+1465 1466
+1466 2051
+1466 2052
+1466 2053
+1467 5549
+1470 2367
+1470 3929
+1470 4431
+1472 3292
+1474 2460
+1474 4015
+1474 4032
+1475 1481
+1475 1507
+1477 3948
+1478 1660
+1478 1694
+1481 2714
+1481 3292
+1481 7156
+1483 1900
+1483 2064
+1483 2519
+1483 2527
+1483 2837
+1483 2859
+1483 2860
+1483 2861
+1483 2862
+1483 2863
+1483 2864
+1483 2865
+1483 2866
+1483 2867
+1483 2868
+1483 2869
+1483 3510
+1485 4178
+1486 2214
+1486 6980
+1487 1488
+1487 1489
+1487 1490
+1488 1956
+1488 2108
+1488 4113
+1489 3211
+1491 4145
+1497 2956
+1497 3234
+1497 3599
+1497 6165
+1498 1499
+1498 1500
+1498 1501
+1498 1502
+1498 1503
+1498 1504
+1498 1505
+1498 1506
+1498 1507
+1498 1997
+1508 3761
+1509 1510
+1509 2807
+1509 4642
+1510 2807
+1511 3112
+1512 1513
+1512 1514
+1512 1515
+1512 1516
+1512 1517
+1512 1518
+1512 2238
+1512 4487
+1513 3750
+1514 1897
+1516 2238
+1516 4487
+1519 1520
+1519 1521
+1520 5106
+1522 2653
+1523 1524
+1523 1525
+1523 1526
+1523 1527
+1523 1528
+1523 1529
+1523 1530
+1523 1531
+1523 1532
+1523 1533
+1523 1534
+1523 1535
+1523 1536
+1523 1537
+1523 1538
+1523 1539
+1523 1540
+1524 4446
+1526 3299
+1526 3300
+1526 3301
+1526 3302
+1526 3303
+1526 3304
+1526 4446
+1527 2431
+1530 2431
+1530 5106
+1537 2671
+1541 5016
+1542 1543
+1542 1544
+1542 1545
+1543 1544
+1543 1545
+1543 1872
+1544 2447
+1544 3569
+1544 4260
+1544 4284
+1545 1736
+1545 3002
+1545 3026
+1546 1547
+1546 1548
+1546 1549
+1546 1550
+1546 1551
+1546 1552
+1546 1553
+1550 2260
+1550 3074
+1554 1674
+1554 3856
+1555 2454
+1556 4015
+1557 3608
+1559 1704
+1560 1561
+1560 1562
+1563 2808
+1563 5954
+1564 1565
+1565 1795
+1565 2260
+1566 1932
+1566 2258
+1568 1569
+1568 1570
+1568 1571
+1568 1572
+1568 1573
+1568 1574
+1568 1575
+1568 4801
+1569 1570
+1569 1571
+1571 1575
+1571 5586
+1574 2089
+1574 5586
+1576 2974
+1576 2975
+1577 3585
+1577 3706
+1578 6440
+1579 2674
+1579 4085
+1580 1581
+1580 1582
+1588 1869
+1589 1590
+1589 1591
+1589 1592
+1589 1593
+1589 1594
+1590 2645
+1590 3770
+1591 5796
+1593 2513
+1593 3094
+1593 4244
+1593 5056
+1593 5273
+1593 5480
+1593 5865
+1594 3093
+1596 6500
+1597 2798
+1598 1599
+1598 1600
+1598 1601
+1600 2388
+1600 3930
+1600 3976
+1602 1603
+1604 2424
+1605 1606
+1605 3988
+1607 1608
+1608 3972
+1608 3973
+1608 3974
+1608 3975
+1609 3533
+1610 1917
+1611 1612
+1611 1613
+1611 1614
+1611 1615
+1611 3081
+1616 1617
+1616 4797
+1618 2260
+1618 2261
+1618 4797
+1619 1620
+1619 1621
+1619 1622
+1622 2054
+1622 3228
+1623 1624
+1623 1625
+1626 1627
+1626 1628
+1626 1629
+1626 1630
+1626 1631
+1626 1632
+1626 1633
+1626 1634
+1626 2041
+1626 3590
+1626 6340
+1627 1633
+1633 1634
+1633 3836
+1633 4447
+1635 2725
+1635 2728
+1635 3816
+1636 1637
+1638 3258
+1639 1640
+1639 1641
+1639 1642
+1639 1643
+1639 1644
+1639 1645
+1639 1646
+1647 1648
+1647 4556
+1648 2313
+1648 2921
+1648 3111
+1648 3214
+1648 3470
+1648 3707
+1648 4257
+1648 5351
+1648 5841
+1648 6635
+1652 3955
+1652 4057
+1652 4058
+1653 1654
+1653 1655
+1653 1656
+1653 1657
+1653 1658
+1653 1659
+1653 1660
+1653 1661
+1653 1662
+1653 1663
+1653 1664
+1653 1665
+1654 1781
+1656 1657
+1660 3588
+1660 7143
+1662 2531
+1668 1877
+1668 4018
+1671 6054
+1672 1673
+1674 1675
+1674 1676
+1674 1677
+1677 3856
+1677 4134
+1678 2388
+1678 2394
+1679 1680
+1679 1681
+1679 1682
+1679 2263
+1679 3071
+1680 2263
+1680 2958
+1680 4755
+1680 6458
+1681 3907
+1683 1684
+1683 1685
+1683 5805
+1686 1687
+1686 1970
+1686 4284
+1686 4373
+1686 4460
+1687 3088
+1687 3668
+1687 4260
+1687 4284
+1687 4360
+1687 4373
+1687 4374
+1687 4460
+1687 4964
+1687 5585
+1687 6405
+1688 4016
+1688 4018
+1689 3488
+1689 4741
+1690 1691
+1690 1692
+1691 3317
+1693 3127
+1694 1695
+1694 1696
+1697 1698
+1697 1699
+1697 4289
+1698 4015
+1698 4032
+1698 4289
+1700 3555
+1700 5032
+1700 7315
+1700 7325
+1702 1703
+1704 1705
+1704 1706
+1704 1707
+1704 1708
+1704 2390
+1704 5189
+1705 2390
+1709 4000
+1710 4828
+1711 2332
+1712 1713
+1712 1714
+1712 1715
+1712 1716
+1712 1717
+1712 1718
+1712 1719
+1712 3488
+1712 5371
+1712 5477
+1713 7233
+1714 3617
+1715 5106
+1716 1717
+1716 4142
+1716 5477
+1717 4949
+1718 2531
+1718 3992
+1718 4016
+1718 4949
+1718 5106
+1722 1727
+1722 2733
+1722 2821
+1722 3403
+1722 4220
+1722 5293
+1722 5294
+1724 1885
+1724 4802
+1729 4373
+1730 1731
+1735 2531
+1737 4015
+1742 1744
+1742 4421
+1742 4802
+1742 6429
+1743 5106
+1752 3259
+1758 1759
+1758 1760
+1758 1761
+1759 1761
+1760 1761
+1761 2199
+1761 2941
+1761 4396
+1761 5614
+1762 4706
+1763 6340
+1764 1980
+1764 4777
+1765 3690
+1766 1768
+1766 3390
+1767 1768
+1767 3390
+1767 3488
+1768 3901
+1768 4181
+1769 1770
+1771 1772
+1771 2563
+1771 4195
+1772 2563
+1772 6409
+1773 6567
+1774 1775
+1774 3798
+1774 4750
+1775 3798
+1775 7173
+1776 2285
+1777 3056
+1778 2460
+1779 2690
+1780 2260
+1781 1782
+1781 1783
+1781 1784
+1781 1785
+1781 1786
+1781 1787
+1781 1788
+1781 1789
+1781 1790
+1781 1791
+1781 1792
+1781 1793
+1781 1794
+1785 3503
+1787 2284
+1787 2292
+1789 3490
+1789 3621
+1790 3503
+1790 3997
+1791 2144
+1794 2017
+1795 1796
+1795 1797
+1795 1798
+1795 1799
+1797 1888
+1797 3630
+1797 3917
+1800 1801
+1801 4208
+1802 1803
+1802 1804
+1803 4583
+1805 2674
+1805 3837
+1805 4716
+1806 2038
+1807 1808
+1807 1809
+1807 1810
+1811 1812
+1811 1813
+1811 1814
+1811 1815
+1811 1816
+1811 1817
+1811 1818
+1811 1819
+1813 1817
+1813 3191
+1816 5696
+1817 1819
+1817 5533
+1818 5061
+1819 3426
+1819 4811
+1820 1972
+1820 2526
+1820 2557
+1820 3292
+1820 3293
+1821 1822
+1821 1823
+1821 1824
+1821 1825
+1821 1826
+1822 1823
+1822 6796
+1822 6797
+1822 6798
+1822 6799
+1822 6800
+1828 1829
+1828 1830
+1831 1832
+1831 1833
+1831 1834
+1831 1835
+1831 1836
+1831 1837
+1832 3081
+1839 3844
+1839 4690
+1840 1841
+1840 1842
+1840 3600
+1842 1904
+1845 1846
+1845 5163
+1845 6057
+1846 1996
+1846 2417
+1846 2419
+1846 2603
+1846 2612
+1846 2613
+1846 2614
+1846 2615
+1846 2616
+1846 2617
+1846 2618
+1846 2619
+1846 2620
+1846 2621
+1846 2622
+1846 2623
+1846 2624
+1846 2625
+1846 2626
+1846 2627
+1846 2628
+1846 2629
+1846 2630
+1846 2631
+1846 2632
+1846 2633
+1846 2634
+1846 2635
+1846 2636
+1846 2637
+1846 2638
+1846 4513
+1846 6057
+1847 1997
+1848 1849
+1848 1850
+1848 1851
+1848 1852
+1848 1853
+1848 1891
+1848 3911
+1849 1891
+1850 1891
+1850 2312
+1853 3112
+1854 1855
+1854 1856
+1854 1857
+1855 5044
+1855 5377
+1855 5522
+1856 7225
+1856 7331
+1858 1862
+1858 1863
+1858 1864
+1858 1865
+1858 3053
+1858 3818
+1858 4939
+1858 5052
+1858 5094
+1859 3673
+1859 7193
+1860 1861
+1862 1863
+1862 1864
+1862 1865
+1862 1866
+1862 1867
+1862 1868
+1862 1869
+1862 3353
+1863 1864
+1865 3052
+1866 3353
+1866 5285
+1867 3353
+1870 4500
+1871 2523
+1872 1873
+1872 1874
+1875 2531
+1876 1877
+1876 1878
+1876 1879
+1876 1880
+1876 1881
+1876 2483
+1876 4460
+1877 1878
+1877 2482
+1877 2483
+1877 2484
+1878 1932
+1878 2483
+1886 3056
+1886 3879
+1886 4862
+1887 4364
+1887 4707
+1887 4708
+1887 4710
+1889 3270
+1890 1891
+1890 1892
+1891 1892
+1891 1928
+1891 3617
+1893 1894
+1895 2103
+1896 2016
+1896 2367
+1897 1898
+1897 1899
+1900 7179
+1901 1902
+1901 1903
+1901 1904
+1901 1905
+1901 1906
+1901 1907
+1901 3964
+1901 3967
+1901 3969
+1902 3964
+1902 3967
+1902 3969
+1903 3964
+1903 3967
+1903 3969
+1904 2130
+1904 2882
+1904 2883
+1904 2884
+1904 2885
+1904 2886
+1904 2887
+1904 2888
+1904 2889
+1904 2890
+1904 2891
+1904 2892
+1904 2893
+1904 2894
+1904 2895
+1904 2896
+1904 2897
+1904 2898
+1904 2899
+1904 2900
+1904 2901
+1904 2902
+1904 2903
+1904 2904
+1904 2905
+1904 2906
+1904 2907
+1904 3964
+1904 3967
+1904 3969
+1904 5115
+1904 5575
+1908 6503
+1909 1989
+1910 1932
+1911 1912
+1911 1913
+1914 6422
+1915 4061
+1916 2126
+1919 1926
+1920 2696
+1921 5598
+1922 4741
+1923 1924
+1925 1926
+1926 3559
+1926 4809
+1929 2332
+1930 5000
+1931 1932
+1932 2257
+1932 2258
+1932 2259
+1933 1934
+1935 3795
+1936 1937
+1936 1938
+1936 1939
+1936 1940
+1939 4059
+1940 2937
+1941 2332
+1941 2333
+1942 2571
+1942 2574
+1943 3224
+1944 1945
+1946 1947
+1946 3476
+1946 3902
+1946 5447
+1946 5496
+1946 5592
+1946 6366
+1947 2377
+1947 2378
+1947 2379
+1947 2380
+1947 5380
+1949 2881
+1950 1951
+1951 2981
+1952 3219
+1953 3353
+1954 1955
+1955 2193
+1955 2600
+1955 2601
+1955 3176
+1955 3177
+1955 4569
+1956 1957
+1958 1959
+1961 2053
+1961 2329
+1961 2413
+1962 1963
+1962 5404
+1963 2558
+1964 1965
+1964 1966
+1964 1967
+1964 1968
+1964 1969
+1964 3259
+1964 4446
+1965 3259
+1967 2388
+1969 4446
+1969 5156
+1970 2450
+1970 2452
+1970 2599
+1970 3709
+1970 3888
+1972 2301
+1972 3292
+1973 6162
+1973 6814
+1974 1975
+1974 1976
+1977 1978
+1977 1979
+1980 1981
+1980 1982
+1980 1983
+1980 1984
+1980 1985
+1980 1986
+1984 5414
+1986 2361
+1987 2289
+1988 3510
+1989 2258
+1990 1991
+1992 3800
+1992 5357
+1993 6776
+1995 2108
+1995 3447
+1995 5916
+1997 1998
+1997 1999
+1997 2000
+1997 2001
+1997 4195
+1997 5629
+1999 2480
+1999 2520
+1999 3586
+1999 7186
+2001 5629
+2002 5786
+2003 2662
+2004 2041
+2005 2372
+2006 4002
+2007 2008
+2007 2009
+2010 3469
+2010 4200
+2011 2213
+2013 2526
+2013 2529
+2013 2988
+2013 2989
+2013 2990
+2013 2991
+2013 2992
+2013 5093
+2015 6054
+2016 5689
+2016 7251
+2017 2018
+2017 2019
+2017 2020
+2021 2022
+2023 6127
+2023 6129
+2023 6130
+2023 7077
+2024 2214
+2024 7179
+2025 2026
+2025 2027
+2027 4977
+2027 6444
+2027 7287
+2028 2029
+2028 2030
+2031 2032
+2031 2033
+2033 2089
+2034 2035
+2034 2036
+2035 6440
+2038 2039
+2038 2040
+2041 2042
+2041 2043
+2041 2044
+2041 2045
+2041 2046
+2041 2047
+2041 2048
+2041 2049
+2041 2050
+2043 6289
+2044 2144
+2048 6340
+2050 5163
+2050 6057
+2052 2531
+2052 2539
+2053 2258
+2053 2331
+2053 2412
+2053 2413
+2053 3114
+2053 3115
+2053 3116
+2054 2055
+2054 2056
+2054 2057
+2054 2058
+2054 2059
+2055 2916
+2056 2058
+2057 2058
+2058 4545
+2058 4643
+2059 4366
+2061 3960
+2062 3334
+2062 3960
+2064 2115
+2076 4113
+2076 4114
+2077 2078
+2077 3761
+2080 2081
+2080 2082
+2083 6512
+2084 2085
+2084 2086
+2084 2087
+2085 3015
+2085 3228
+2085 3540
+2086 3228
+2088 7179
+2089 2090
+2089 2091
+2093 2094
+2097 2098
+2097 2099
+2097 2100
+2097 2101
+2097 3510
+2097 3632
+2099 2101
+2102 2103
+2102 2104
+2103 2104
+2103 3335
+2103 4179
+2103 4180
+2104 5272
+2105 2106
+2105 2107
+2105 2108
+2105 2109
+2105 2115
+2106 2452
+2106 2922
+2106 3829
+2106 3836
+2106 4862
+2107 2108
+2107 6820
+2108 2111
+2108 2143
+2108 4158
+2108 5170
+2110 6820
+2111 4482
+2111 4921
+2112 2113
+2112 2114
+2113 2114
+2113 4164
+2114 4164
+2114 4259
+2114 4755
+2114 4921
+2114 5318
+2115 2116
+2117 2118
+2117 2119
+2117 2120
+2117 2121
+2117 2122
+2117 2123
+2117 2124
+2117 3682
+2118 2381
+2119 2120
+2119 2122
+2120 2123
+2120 3623
+2120 4494
+2120 4495
+2120 5916
+2120 6488
+2120 6820
+2121 2122
+2122 2269
+2122 4771
+2125 2412
+2125 2558
+2126 2127
+2126 2128
+2126 2129
+2127 5274
+2129 2189
+2131 5817
+2132 2133
+2132 2440
+2133 2440
+2134 2135
+2134 2136
+2134 2137
+2134 2138
+2135 2136
+2135 2137
+2135 5755
+2136 2137
+2136 2138
+2137 4514
+2138 6000
+2139 2140
+2139 4115
+2141 3813
+2142 3813
+2144 2289
+2144 6289
+2148 2149
+2148 2150
+2149 4621
+2150 4621
+2151 2152
+2153 4446
+2154 5353
+2155 4431
+2156 2157
+2158 2159
+2158 2531
+2159 4018
+2160 6379
+2161 4748
+2161 4749
+2163 3075
+2163 4015
+2164 2755
+2166 3546
+2170 2974
+2170 2975
+2171 2172
+2171 2173
+2171 2174
+2171 2175
+2173 3098
+2175 2604
+2175 4949
+2176 3400
+2177 2798
+2177 4801
+2178 2179
+2178 4736
+2179 7252
+2180 2531
+2181 4906
+2182 2183
+2183 5933
+2184 2185
+2186 2924
+2187 3287
+2188 4655
+2189 3440
+2190 2191
+2192 7288
+2193 2194
+2194 2213
+2195 2196
+2195 2197
+2196 4636
+2196 4637
+2196 4638
+2196 4639
+2197 2442
+2198 4984
+2200 2201
+2202 6572
+2203 2206
+2203 2753
+2203 4465
+2204 2960
+2204 6153
+2205 2604
+2205 3027
+2206 2207
+2208 2209
+2210 4976
+2211 2212
+2212 2531
+2212 2537
+2212 3846
+2213 2214
+2213 2215
+2213 2216
+2213 2217
+2213 4015
+2213 4474
+2214 2218
+2214 2219
+2214 2220
+2214 2221
+2214 2222
+2214 2223
+2214 2224
+2214 2225
+2214 2226
+2214 2227
+2215 2531
+2215 4518
+2218 2653
+2218 4015
+2220 5314
+2221 2223
+2221 2862
+2228 2229
+2228 2230
+2228 2231
+2228 2232
+2228 4160
+2228 4162
+2228 4831
+2233 3454
+2233 3457
+2234 2364
+2235 3761
+2236 2251
+2237 2238
+2237 2239
+2238 4288
+2238 4356
+2238 4958
+2238 4959
+2238 4960
+2240 4651
+2243 3829
+2244 2958
+2245 2246
+2247 2248
+2247 2249
+2250 3760
+2250 5156
+2251 2252
+2253 3997
+2253 4145
+2254 2255
+2254 2256
+2258 2412
+2259 2531
+2260 2261
+2260 2262
+2260 2263
+2260 2264
+2263 3318
+2263 3661
+2264 4672
+2266 5248
+2267 2268
+2270 2271
+2270 2272
+2270 2273
+2274 3283
+2274 5020
+2274 5198
+2275 2276
+2275 2277
+2275 2278
+2279 2280
+2281 2282
+2281 2283
+2283 3605
+2283 4306
+2284 5668
+2285 2286
+2285 2287
+2285 2288
+2289 2290
+2292 4291
+2292 4490
+2292 5011
+2292 5668
+2293 2294
+2293 2295
+2293 2296
+2293 2297
+2293 2298
+2293 2299
+2293 2300
+2293 2301
+2293 2302
+2293 2303
+2295 2301
+2296 4915
+2296 4922
+2301 2420
+2301 3442
+2304 3540
+2305 2602
+2305 3490
+2306 2307
+2306 2308
+2306 2309
+2307 2308
+2307 2309
+2308 2309
+2310 2311
+2310 2312
+2314 2315
+2314 2316
+2314 2317
+2314 2318
+2314 2319
+2314 6120
+2321 7092
+2323 6910
+2328 6075
+2329 2330
+2329 2331
+2331 2413
+2331 3625
+2331 3629
+2332 2333
+2332 2334
+2332 2335
+2332 2336
+2333 3702
+2337 2338
+2337 2339
+2337 2340
+2338 2339
+2338 2340
+2339 2340
+2341 2796
+2342 2343
+2342 5438
+2344 2345
+2345 5794
+2346 4704
+2347 2348
+2347 2349
+2347 2350
+2347 2351
+2347 2352
+2347 2353
+2347 2354
+2350 5831
+2354 2531
+2355 3776
+2356 2357
+2356 2358
+2356 2359
+2356 2360
+2359 2360
+2360 6822
+2365 2366
+2365 7018
+2367 5689
+2367 6038
+2368 3498
+2369 2370
+2370 2371
+2373 2984
+2373 3748
+2373 3914
+2373 4347
+2375 3829
+2375 5376
+2379 2704
+2379 2731
+2382 2383
+2382 2384
+2382 2385
+2386 2387
+2388 2389
+2388 2390
+2388 2391
+2388 2392
+2388 2393
+2388 2394
+2388 5317
+2390 3037
+2390 3038
+2390 3039
+2390 3040
+2390 3041
+2390 3042
+2390 3043
+2390 3044
+2390 3045
+2395 2396
+2396 2500
+2397 3488
+2398 3490
+2398 3493
+2398 3494
+2399 2975
+2399 2996
+2399 3618
+2399 3621
+2400 2401
+2403 2404
+2406 2407
+2408 2531
+2409 4344
+2411 3843
+2413 2432
+2413 4949
+2418 6057
+2419 2613
+2419 2776
+2419 5163
+2419 6057
+2421 2422
+2421 2423
+2423 5954
+2424 6333
+2425 2426
+2426 2945
+2427 4876
+2427 6453
+2428 2429
+2430 6133
+2432 6573
+2432 6574
+2432 6575
+2433 2434
+2433 2435
+2433 2436
+2433 2437
+2433 2438
+2434 2437
+2434 2644
+2434 2645
+2434 2646
+2434 2647
+2434 2648
+2435 4763
+2435 4764
+2439 3081
+2441 3693
+2443 2444
+2443 2445
+2443 2446
+2443 6957
+2445 3096
+2446 4815
+2447 3800
+2447 6895
+2448 3443
+2449 2450
+2449 2451
+2449 2452
+2449 2922
+2450 2452
+2450 3829
+2450 4583
+2450 6820
+2451 2452
+2451 3829
+2452 2597
+2452 2598
+2452 2599
+2452 2923
+2452 3839
+2452 3888
+2452 4275
+2452 4530
+2452 5912
+2453 2555
+2454 2455
+2454 2456
+2457 2458
+2457 2808
+2459 2460
+2459 2495
+2460 2495
+2461 2462
+2463 4431
+2464 3477
+2465 3352
+2466 3960
+2467 2468
+2469 2470
+2471 2472
+2471 2473
+2471 2474
+2471 2475
+2471 2476
+2472 6096
+2473 5943
+2473 6096
+2473 6124
+2473 6301
+2473 6960
+2474 6096
+2475 6096
+2476 6096
+2477 2478
+2477 3963
+2479 5752
+2481 2531
+2481 5101
+2482 2494
+2482 3210
+2483 2484
+2484 2704
+2484 4115
+2484 4802
+2484 5911
+2485 3027
+2486 3733
+2487 2488
+2488 3070
+2488 3324
+2488 4060
+2488 4253
+2488 4254
+2488 4255
+2488 4256
+2489 4261
+2490 2491
+2492 3317
+2493 2494
+2495 2496
+2495 2497
+2495 2498
+2495 2499
+2496 2499
+2498 2653
+2499 2592
+2501 4203
+2502 2503
+2502 2504
+2502 2505
+2502 2506
+2502 2507
+2502 2508
+2502 2509
+2502 2510
+2502 2511
+2512 4594
+2513 2514
+2513 2515
+2513 5480
+2513 5677
+2515 3249
+2517 5981
+2518 2862
+2520 2549
+2520 4152
+2520 4153
+2521 3854
+2521 6647
+2522 3094
+2524 4015
+2525 4458
+2526 2527
+2526 2528
+2526 2529
+2526 2530
+2526 3292
+2527 2862
+2527 7179
+2528 2529
+2528 3292
+2528 3294
+2529 2530
+2530 2588
+2531 2532
+2531 2533
+2531 2534
+2531 2535
+2531 2536
+2531 2537
+2531 2538
+2531 2539
+2531 2540
+2531 2541
+2531 2542
+2531 2543
+2531 2544
+2531 2545
+2533 3798
+2535 7174
+2536 2910
+2536 3174
+2539 3341
+2539 4344
+2539 4398
+2539 4399
+2541 3858
+2541 5398
+2543 4564
+2543 4678
+2543 4679
+2548 3540
+2549 2550
+2549 2551
+2549 2552
+2549 2555
+2549 3963
+2549 5422
+2549 6674
+2550 2555
+2550 3267
+2553 2554
+2553 2555
+2553 2556
+2555 3321
+2558 2559
+2558 2560
+2558 2561
+2558 2562
+2558 5827
+2561 3310
+2563 2564
+2563 4195
+2564 7288
+2565 6659
+2566 5093
+2570 5181
+2571 2572
+2571 2573
+2571 2574
+2571 2575
+2571 2576
+2571 2577
+2574 2948
+2574 3298
+2574 6340
+2577 3721
+2578 2579
+2578 2580
+2579 2580
+2581 2582
+2581 2583
+2581 2584
+2581 2585
+2581 2586
+2587 2589
+2587 3585
+2588 4970
+2589 3268
+2589 4942
+2590 3458
+2590 4306
+2590 6581
+2592 2750
+2594 2846
+2594 3853
+2595 2872
+2596 4801
+2597 2598
+2597 2599
+2597 3829
+2597 3836
+2597 3839
+2597 4583
+2599 3829
+2599 6820
+2601 3176
+2604 2605
+2607 2608
+2607 2609
+2610 2611
+2613 6576
+2620 6057
+2639 2640
+2641 2642
+2641 2643
+2643 3198
+2643 3199
+2643 3733
+2643 4988
+2643 5939
+2643 6016
+2644 2646
+2644 2647
+2644 5015
+2648 6907
+2649 4831
+2650 2651
+2650 2652
+2650 2653
+2650 2654
+2651 4443
+2652 2653
+2652 3585
+2653 2654
+2653 3027
+2653 3028
+2653 3585
+2653 6638
+2653 6639
+2654 3585
+2655 2656
+2655 2657
+2655 2658
+2655 2659
+2655 2660
+2655 3062
+2655 4876
+2658 3098
+2659 3103
+2662 2663
+2662 2664
+2662 2665
+2662 2666
+2662 2667
+2662 2668
+2662 2669
+2670 4673
+2672 2673
+2674 2675
+2674 2676
+2674 2677
+2674 2678
+2674 2679
+2676 4195
+2678 2683
+2679 4195
+2680 2681
+2680 2682
+2683 3673
+2684 3344
+2685 2686
+2685 2687
+2685 2688
+2685 2689
+2685 2802
+2685 4126
+2686 7175
+2687 2688
+2687 2801
+2687 2802
+2687 2803
+2687 2804
+2687 2805
+2687 2806
+2687 4126
+2688 2799
+2688 2800
+2688 2801
+2688 2802
+2688 4126
+2690 2691
+2690 2692
+2690 2693
+2690 2694
+2692 2693
+2692 3154
+2695 2696
+2695 2697
+2696 2697
+2696 3142
+2696 3143
+2698 5699
+2700 4689
+2701 4160
+2702 2703
+2704 2705
+2706 2707
+2708 2709
+2708 2710
+2708 2711
+2708 2712
+2708 5874
+2710 2958
+2710 6722
+2713 5880
+2714 2715
+2714 2716
+2714 2717
+2714 2718
+2714 2719
+2715 2716
+2715 2717
+2715 2719
+2715 2925
+2715 2926
+2715 2927
+2715 2928
+2715 2929
+2715 2930
+2715 2931
+2715 2932
+2715 2933
+2715 2934
+2715 2935
+2715 2936
+2715 5631
+2715 5877
+2715 5962
+2715 6817
+2715 7194
+2720 2721
+2720 2722
+2720 2723
+2724 5862
+2725 2726
+2725 2727
+2725 2728
+2725 2729
+2726 2728
+2726 3816
+2727 2728
+2727 3816
+2728 3816
+2729 3816
+2732 3605
+2733 2734
+2733 2735
+2733 2736
+2733 2737
+2734 2737
+2738 2739
+2738 2740
+2741 2742
+2741 2743
+2741 2744
+2742 2774
+2742 7310
+2745 2746
+2750 2752
+2750 5139
+2752 3027
+2753 2774
+2753 2779
+2753 2915
+2753 2916
+2753 2917
+2753 2918
+2753 4415
+2753 6667
+2753 7179
+2755 3077
+2755 3736
+2761 5629
+2762 2763
+2762 2764
+2762 2765
+2762 2766
+2762 2767
+2762 2768
+2762 2769
+2763 2764
+2763 2765
+2763 2766
+2763 2767
+2763 2768
+2763 2769
+2763 5120
+2763 6645
+2763 7036
+2764 2765
+2764 2766
+2764 2767
+2764 2768
+2764 2769
+2765 2766
+2765 2767
+2765 2768
+2765 2769
+2765 4645
+2765 4945
+2766 2767
+2766 2768
+2766 2769
+2767 2768
+2767 2769
+2768 2769
+2768 5421
+2768 6385
+2768 6571
+2770 2771
+2770 2772
+2770 2773
+2770 2774
+2770 2775
+2771 2775
+2772 2775
+2773 2775
+2774 2775
+2774 3575
+2774 3895
+2774 5400
+2775 3807
+2779 4580
+2780 3829
+2781 2782
+2781 2783
+2781 2784
+2781 2785
+2785 5803
+2786 2787
+2786 2788
+2786 2789
+2789 4866
+2790 3493
+2791 6437
+2791 6438
+2792 4730
+2793 4716
+2794 2795
+2796 2797
+2798 2846
+2800 2802
+2800 7106
+2801 2802
+2802 4126
+2807 4642
+2808 2809
+2808 2810
+2808 2811
+2808 2812
+2808 2813
+2812 3617
+2814 2815
+2816 2817
+2819 2820
+2823 2824
+2823 6055
+2825 4991
+2826 2827
+2828 2829
+2828 2830
+2828 5541
+2831 5878
+2832 5879
+2833 2919
+2834 2835
+2836 2837
+2837 5125
+2838 2839
+2838 2840
+2841 2842
+2842 2843
+2842 2844
+2846 2847
+2846 2848
+2846 2849
+2850 3855
+2851 6532
+2852 2853
+2852 3510
+2853 3510
+2853 4146
+2853 4147
+2853 4148
+2854 2855
+2856 3936
+2857 3863
+2862 2975
+2862 3339
+2862 7179
+2863 3292
+2863 3294
+2863 3510
+2870 7100
+2871 4683
+2872 2873
+2872 2874
+2872 2875
+2872 2876
+2872 2877
+2874 5500
+2875 5926
+2876 5691
+2876 5926
+2878 2958
+2878 3317
+2879 2880
+2908 2909
+2910 2911
+2910 2912
+2910 3702
+2911 6036
+2913 4716
+2914 6667
+2915 3624
+2916 5590
+2919 2920
+2919 5477
+2922 2923
+2922 4803
+2923 3829
+2926 7193
+2932 5080
+2937 2938
+2937 2939
+2937 2940
+2937 5416
+2940 5016
+2941 3540
+2942 2943
+2944 3702
+2946 4708
+2947 4364
+2948 3334
+2949 2950
+2950 6913
+2951 2952
+2951 2953
+2951 2954
+2951 2955
+2953 5285
+2953 6962
+2956 3234
+2956 3235
+2956 3236
+2956 4923
+2956 6428
+2956 7054
+2957 6428
+2958 3287
+2958 3316
+2958 3317
+2958 3318
+2958 3319
+2958 4306
+2961 2962
+2963 2964
+2963 2965
+2963 2966
+2967 2968
+2967 2969
+2968 2969
+2970 2971
+2970 2972
+2973 3994
+2973 4145
+2974 2975
+2974 2976
+2974 2977
+2975 2996
+2975 2998
+2975 3618
+2975 3620
+2975 5093
+2975 7018
+2978 4580
+2979 4716
+2979 7154
+2980 2981
+2982 5189
+2983 3612
+2984 3748
+2984 3913
+2984 3914
+2985 3502
+2986 4195
+2987 3390
+2987 3488
+2993 6340
+2994 2995
+2996 2997
+2996 2998
+2997 3618
+2997 4158
+2998 3618
+2998 3619
+2999 3000
+3001 3844
+3003 3004
+3003 3005
+3003 3006
+3003 3311
+3003 3312
+3003 3315
+3003 4130
+3004 3005
+3004 3006
+3004 3315
+3005 3006
+3005 3315
+3005 4130
+3005 5285
+3006 3315
+3006 4130
+3007 3008
+3007 3009
+3007 3010
+3007 3011
+3007 3012
+3007 3013
+3008 5633
+3013 5357
+3014 3498
+3014 5003
+3015 3016
+3015 3017
+3015 3018
+3015 3019
+3016 3017
+3016 3018
+3016 3204
+3016 4777
+3018 3653
+3018 3654
+3018 4777
+3020 3021
+3022 6020
+3023 6020
+3025 4421
+3026 3458
+3027 3028
+3027 3029
+3031 3311
+3032 6900
+3033 3034
+3033 3035
+3033 3036
+3041 6333
+3041 6456
+3046 3047
+3046 3048
+3046 3049
+3046 4415
+3046 6227
+3046 6452
+3046 7022
+3050 5615
+3050 5618
+3052 3053
+3054 3055
+3055 4015
+3056 3057
+3056 3156
+3058 3059
+3060 3061
+3062 3063
+3062 3064
+3062 3065
+3066 3067
+3066 3068
+3069 3661
+3071 3072
+3071 3073
+3075 3076
+3075 3077
+3075 3078
+3075 3079
+3075 3080
+3081 3082
+3081 3083
+3081 3084
+3081 3085
+3081 3086
+3081 3087
+3086 4197
+3089 3090
+3092 3600
+3093 3094
+3093 3095
+3093 3096
+3093 3548
+3094 4171
+3094 4244
+3094 4245
+3094 4246
+3094 4247
+3094 4248
+3094 4249
+3094 4250
+3095 5865
+3096 5480
+3096 5865
+3097 3134
+3098 3099
+3098 3100
+3098 3101
+3098 3102
+3098 3103
+3098 3104
+3098 3105
+3098 3106
+3098 3107
+3098 3108
+3102 3106
+3102 6840
+3103 3467
+3105 3106
+3106 4169
+3106 4170
+3108 6840
+3109 3110
+3112 3113
+3117 3118
+3117 3119
+3120 3121
+3120 3122
+3123 3472
+3124 3472
+3125 3126
+3128 6918
+3129 3130
+3129 3131
+3129 3132
+3133 5198
+3134 3135
+3134 3136
+3134 3137
+3134 6673
+3135 3136
+3135 3137
+3138 3602
+3140 3141
+3143 4760
+3144 3145
+3144 3146
+3144 3147
+3146 5503
+3146 6511
+3149 3150
+3149 3151
+3153 3904
+3153 4461
+3156 3157
+3156 3158
+3156 3159
+3156 3160
+3156 3161
+3156 3162
+3158 6467
+3161 4500
+3163 3164
+3163 3165
+3163 3166
+3164 3165
+3164 3166
+3164 3579
+3164 4692
+3165 3859
+3166 4323
+3167 3168
+3169 3170
+3169 3171
+3169 3172
+3169 3173
+3175 3448
+3176 3177
+3176 4569
+3177 3178
+3179 5909
+3180 3181
+3180 3182
+3183 3184
+3183 3185
+3186 3447
+3187 3188
+3187 3189
+3187 3190
+3187 4855
+3188 5479
+3195 3540
+3196 3197
+3196 3219
+3198 3199
+3198 3733
+3199 4993
+3199 4994
+3200 3201
+3202 6145
+3203 3416
+3207 3208
+3212 7233
+3215 3216
+3215 3605
+3216 3605
+3217 4804
+3218 4804
+3219 3220
+3221 3222
+3223 3292
+3226 3408
+3227 3733
+3228 3229
+3228 3230
+3228 3231
+3232 3233
+3234 3235
+3234 3236
+3234 3237
+3234 3238
+3234 3239
+3235 6165
+3235 6428
+3236 4565
+3236 6428
+3239 4015
+3239 7222
+3240 3241
+3240 3242
+3240 3243
+3241 4460
+3246 3255
+3247 5061
+3248 3252
+3248 3993
+3249 3252
+3249 5480
+3254 3255
+3255 3256
+3255 3426
+3259 3260
+3259 3261
+3259 3262
+3259 3263
+3259 3264
+3265 4970
+3266 4711
+3266 4878
+3269 3270
+3270 3271
+3270 4204
+3272 4489
+3273 4893
+3274 4804
+3275 3276
+3276 5633
+3277 3278
+3279 3280
+3281 5916
+3282 3960
+3283 3284
+3283 3285
+3283 5198
+3284 3285
+3284 5020
+3285 5020
+3286 5477
+3287 3288
+3287 3289
+3287 3290
+3287 3317
+3291 3317
+3291 4284
+3292 3293
+3292 3294
+3295 3296
+3297 4876
+3299 7047
+3305 3306
+3305 3307
+3305 3308
+3305 3309
+3307 5230
+3311 3312
+3311 3313
+3311 3314
+3311 3315
+3311 7235
+3312 3315
+3312 3857
+3312 6468
+3313 6393
+3313 7235
+3315 4130
+3315 5285
+3320 5317
+3321 3322
+3321 3323
+3325 3326
+3325 3327
+3325 3328
+3325 3329
+3325 3330
+3325 3331
+3325 3332
+3325 3333
+3329 3332
+3330 3332
+3331 3332
+3332 3333
+3332 4067
+3332 4068
+3332 4069
+3332 4070
+3332 4071
+3332 4072
+3333 5074
+3336 3337
+3338 5483
+3340 5444
+3342 3343
+3344 3345
+3344 4766
+3346 5884
+3349 3350
+3351 6995
+3353 3354
+3355 3356
+3355 3357
+3355 3358
+3355 3359
+3355 3360
+3355 3361
+3355 3362
+3355 3363
+3358 3363
+3362 3363
+3363 3364
+3363 3365
+3363 3366
+3363 3367
+3363 3368
+3363 3369
+3363 3370
+3371 3372
+3371 3373
+3371 3374
+3371 3375
+3371 3376
+3372 5165
+3373 4155
+3374 3428
+3377 4135
+3380 4149
+3380 4150
+3380 4151
+3381 3382
+3381 3383
+3384 3385
+3384 3386
+3384 3387
+3384 3388
+3384 3389
+3386 3389
+3386 4076
+3386 4077
+3386 4277
+3386 4278
+3390 3391
+3390 3392
+3390 3393
+3390 3394
+3390 3488
+3393 3503
+3395 4741
+3398 3569
+3400 3401
+3400 4262
+3402 5449
+3402 6846
+3405 3406
+3406 7039
+3407 4212
+3409 3410
+3411 3922
+3411 4599
+3412 3413
+3414 3415
+3416 3417
+3416 3418
+3417 4054
+3417 4551
+3420 6250
+3421 6567
+3425 3426
+3427 3701
+3427 4741
+3427 6845
+3428 3429
+3428 3430
+3428 3431
+3428 3432
+3434 3435
+3437 3438
+3439 3440
+3439 4690
+3440 3441
+3440 4562
+3440 5306
+3440 5591
+3443 3444
+3443 3445
+3443 3446
+3449 3450
+3449 3451
+3449 3452
+3454 3455
+3454 3456
+3454 3457
+3458 3482
+3458 4470
+3461 3462
+3461 3463
+3464 3465
+3464 3466
+3468 4655
+3469 3540
+3473 3930
+3474 3475
+3474 3577
+3475 3577
+3475 4592
+3477 3478
+3479 3560
+3480 3761
+3483 3581
+3483 3673
+3488 3489
+3490 3491
+3490 3492
+3490 3493
+3490 3494
+3490 3495
+3493 3578
+3494 3578
+3494 3591
+3494 3592
+3494 3621
+3496 3497
+3498 3499
+3498 3500
+3501 3502
+3502 3906
+3502 3944
+3502 4075
+3502 5265
+3502 5266
+3502 5267
+3502 5268
+3503 3504
+3503 3505
+3503 3997
+3503 6580
+3506 7112
+3507 4061
+3508 3509
+3510 3511
+3510 3512
+3510 3513
+3510 3514
+3510 3515
+3510 4401
+3510 7296
+3514 3576
+3516 3517
+3516 3518
+3516 3519
+3518 3519
+3520 3521
+3520 3522
+3520 3523
+3520 3524
+3525 3526
+3527 4344
+3528 3529
+3528 3530
+3528 3531
+3529 4497
+3532 6952
+3534 4065
+3535 3536
+3535 3537
+3537 3600
+3538 3929
+3539 4108
+3540 3541
+3540 3542
+3540 3543
+3540 3544
+3540 3545
+3540 3546
+3540 3547
+3546 3941
+3546 4294
+3546 4295
+3548 3549
+3548 3550
+3548 6918
+3549 4192
+3551 3552
+3554 4018
+3556 3557
+3556 3558
+3559 3560
+3560 3638
+3560 4975
+3561 3562
+3563 3564
+3563 3565
+3566 4704
+3567 3568
+3568 3850
+3568 6447
+3569 3893
+3570 3621
+3572 3573
+3573 4061
+3580 4840
+3581 3582
+3582 3673
+3582 4690
+3582 5154
+3582 5306
+3583 4740
+3583 5248
+3584 5494
+3586 5116
+3586 5812
+3588 4995
+3590 3848
+3593 3594
+3593 3595
+3593 3596
+3593 3597
+3593 6925
+3597 7178
+3598 3901
+3600 3601
+3602 3603
+3602 3604
+3605 3666
+3606 5249
+3608 3609
+3608 3610
+3608 3611
+3609 3611
+3613 3614
+3615 3935
+3616 4158
+3616 4862
+3616 7330
+3618 3619
+3618 3620
+3618 3621
+3619 3620
+3621 3847
+3621 3860
+3621 4003
+3621 4004
+3622 4158
+3624 3625
+3624 3626
+3624 3627
+3624 3628
+3624 3629
+3624 5404
+3624 6566
+3625 3629
+3625 3682
+3625 4036
+3628 3629
+3629 3682
+3629 4120
+3629 6667
+3632 4366
+3633 3634
+3635 4121
+3636 5197
+3637 4160
+3639 4716
+3640 3641
+3640 3642
+3641 3642
+3641 4824
+3642 4824
+3642 5403
+3644 5911
+3645 3646
+3645 3647
+3646 3647
+3649 3731
+3649 4476
+3650 6053
+3651 3673
+3652 4993
+3652 4994
+3656 3657
+3656 3658
+3656 3659
+3657 3658
+3660 4489
+3661 3662
+3663 5835
+3664 3665
+3667 3764
+3668 4373
+3670 3671
+3670 4426
+3671 4426
+3673 3674
+3673 3675
+3673 3676
+3673 3677
+3676 5154
+3676 6147
+3676 7154
+3678 4336
+3680 3681
+3682 4232
+3683 3684
+3683 3685
+3686 5040
+3687 3688
+3687 4590
+3690 3691
+3690 3692
+3694 3829
+3696 4460
+3697 3991
+3698 6795
+3699 3700
+3701 6845
+3702 3703
+3703 6765
+3704 3705
+3708 4755
+3709 5374
+3710 6916
+3711 5252
+3712 3713
+3714 6270
+3715 5284
+3716 3717
+3718 7002
+3719 3720
+3722 4476
+3723 3747
+3723 4232
+3724 4778
+3725 4207
+3725 4783
+3726 3727
+3728 4447
+3729 4035
+3730 5260
+3733 3734
+3735 5016
+3737 4065
+3738 5101
+3739 4580
+3740 3741
+3740 3742
+3742 5477
+3743 5252
+3743 6379
+3743 7114
+3744 3745
+3744 3746
+3748 3913
+3748 3914
+3749 4489
+3750 3751
+3750 3752
+3750 3753
+3754 4491
+3756 3757
+3757 3758
+3762 4226
+3764 3765
+3764 3766
+3764 3767
+3764 3768
+3765 5732
+3766 4455
+3769 7248
+3769 7249
+3771 3871
+3771 3872
+3771 3873
+3771 3874
+3771 3875
+3771 3876
+3771 3877
+3771 3878
+3772 3773
+3774 4553
+3775 4791
+3777 3778
+3777 3779
+3780 3781
+3780 3782
+3781 3782
+3781 3885
+3782 3885
+3783 3784
+3783 3785
+3783 3786
+3783 3787
+3784 3786
+3786 3787
+3786 5346
+3788 6212
+3790 3791
+3790 3792
+3790 3793
+3790 3794
+3790 3795
+3790 3796
+3790 3797
+3791 3795
+3793 3795
+3794 3795
+3795 4299
+3796 5649
+3798 3799
+3798 7173
+3799 4113
+3800 3801
+3800 3802
+3800 3803
+3802 4730
+3804 3805
+3805 4426
+3805 5018
+3808 3809
+3810 3811
+3811 3812
+3814 4217
+3815 4927
+3817 3818
+3817 3819
+3817 3820
+3817 3821
+3817 3822
+3818 5215
+3818 5216
+3818 5217
+3820 5215
+3820 5217
+3823 3824
+3825 3826
+3825 3827
+3825 3828
+3829 3830
+3829 3831
+3829 3832
+3829 3833
+3829 3834
+3829 3835
+3829 3836
+3829 3837
+3829 3838
+3829 3839
+3830 4167
+3834 6820
+3836 3839
+3837 4716
+3839 4528
+3839 4529
+3839 4530
+3840 3841
+3842 4785
+3843 3844
+3843 3845
+3844 3845
+3844 4081
+3844 4471
+3845 4081
+3845 4790
+3847 4163
+3850 3851
+3850 3852
+3850 5198
+3851 5855
+3853 3854
+3854 3927
+3854 4045
+3854 4175
+3854 4176
+3854 4177
+3854 4803
+3860 4716
+3861 4723
+3861 4724
+3862 6135
+3864 3865
+3864 3866
+3865 3866
+3866 4770
+3867 3868
+3867 3869
+3867 3870
+3872 4021
+3873 4021
+3873 6353
+3873 6655
+3879 3880
+3879 3881
+3879 3883
+3879 5210
+3879 6371
+3880 3882
+3880 3883
+3884 3905
+3884 3906
+3884 6130
+3884 6463
+3886 6353
+3886 6655
+3887 4903
+3889 6818
+3890 3891
+3894 4727
+3895 3896
+3897 4059
+3898 3899
+3900 3901
+3902 4580
+3903 3904
+3905 3906
+3905 6463
+3908 3909
+3910 4479
+3911 3912
+3913 4506
+3914 4504
+3914 4505
+3915 3916
+3918 3919
+3918 3920
+3921 6092
+3921 6342
+3922 3923
+3924 3925
+3926 5434
+3928 5371
+3929 3930
+3929 3931
+3929 3932
+3929 3933
+3929 4431
+3930 3931
+3930 3976
+3930 4117
+3930 4432
+3931 6662
+3934 4197
+3937 3938
+3937 3939
+3942 6757
+3943 4195
+3943 4197
+3945 3946
+3945 3947
+3947 4074
+3947 5253
+3949 3950
+3949 3951
+3953 3954
+3953 4228
+3953 4229
+3953 4230
+3953 4599
+3954 4228
+3954 4229
+3954 4230
+3955 4058
+3956 4330
+3957 3958
+3957 3959
+3960 3961
+3961 5219
+3962 4421
+3964 3965
+3964 3966
+3964 3967
+3964 3968
+3964 3969
+3964 3970
+3964 3971
+3965 3967
+3965 3969
+3966 3967
+3966 3969
+3967 3968
+3967 3969
+3967 3970
+3967 3971
+3968 3969
+3969 3970
+3969 3971
+3973 6932
+3977 7235
+3978 4015
+3981 6384
+3982 3983
+3983 5308
+3984 3985
+3986 5231
+3987 7288
+3989 3990
+3994 3995
+3994 3996
+3997 3998
+3997 3999
+4001 4035
+4005 5404
+4005 6413
+4005 6414
+4005 6647
+4011 5319
+4011 6034
+4013 4791
+4014 4059
+4015 4032
+4016 4017
+4016 4018
+4017 5249
+4018 4791
+4018 4792
+4018 5076
+4018 5077
+4019 4020
+4022 7142
+4033 4034
+4036 4656
+4037 4038
+4037 4039
+4040 4041
+4042 4043
+4044 5550
+4046 4047
+4048 5524
+4049 4050
+4052 4741
+4052 6554
+4053 4804
+4055 4056
+4057 4058
+4062 4518
+4064 4967
+4065 4066
+4070 4071
+4071 4072
+4071 6886
+4073 5085
+4074 4076
+4076 4077
+4076 4078
+4080 6884
+4082 4083
+4085 4086
+4085 4087
+4088 4089
+4088 4090
+4089 4090
+4092 4093
+4092 4094
+4092 4095
+4092 4096
+4092 4097
+4092 4098
+4094 6457
+4098 4230
+4099 4100
+4099 4101
+4099 4102
+4099 4103
+4104 5957
+4105 4106
+4105 4107
+4109 4110
+4109 4111
+4109 4112
+4112 4163
+4113 4114
+4115 4116
+4118 5249
+4120 6566
+4121 4122
+4123 4446
+4124 4217
+4125 6277
+4126 4127
+4126 4128
+4126 4129
+4126 4130
+4126 4131
+4126 4132
+4126 4133
+4128 6282
+4134 4135
+4134 4136
+4134 4137
+4138 4139
+4138 4140
+4141 5300
+4143 5565
+4157 4364
+4158 4159
+4160 4161
+4160 4162
+4163 4164
+4163 4165
+4166 6659
+4167 5100
+4168 7038
+4172 5776
+4173 5513
+4182 5252
+4183 4184
+4185 4186
+4187 4458
+4188 4189
+4190 4191
+4192 4193
+4192 4194
+4195 4196
+4195 4197
+4195 4198
+4195 4199
+4197 4199
+4197 5264
+4201 5442
+4202 4232
+4202 6704
+4204 4205
+4204 4206
+4205 4206
+4207 4783
+4209 4210
+4209 4211
+4213 4214
+4213 4215
+4215 4690
+4215 4830
+4216 7133
+4218 4219
+4218 6087
+4218 6088
+4218 6089
+4219 6087
+4219 6088
+4219 6089
+4220 4221
+4222 4223
+4224 4225
+4228 4229
+4228 4230
+4228 4231
+4229 4230
+4230 4231
+4230 4359
+4232 4233
+4234 4235
+4234 4236
+4234 4237
+4234 4238
+4234 4239
+4237 4238
+4240 4241
+4242 5156
+4244 6782
+4251 4252
+4257 5352
+4258 5319
+4262 4263
+4262 4741
+4264 4265
+4264 4266
+4264 4267
+4264 4268
+4266 4267
+4266 4943
+4266 4944
+4267 4943
+4267 4944
+4267 5852
+4269 4270
+4269 6289
+4270 6289
+4271 4767
+4272 4366
+4273 4274
+4276 4425
+4278 4973
+4278 6281
+4279 4280
+4279 4281
+4280 4281
+4282 4283
+4284 4373
+4285 4286
+4288 4487
+4290 6127
+4290 6129
+4290 6130
+4292 4293
+4296 4297
+4298 4791
+4300 4301
+4302 4303
+4303 4304
+4303 6130
+4304 4305
+4304 6130
+4306 4307
+4308 6508
+4309 4310
+4309 4311
+4309 4312
+4309 4313
+4310 4808
+4310 5731
+4314 4315
+4314 4316
+4314 4317
+4318 4319
+4318 4320
+4319 4320
+4321 6135
+4322 4545
+4324 7149
+4325 4326
+4325 4327
+4325 4328
+4325 4329
+4326 4327
+4326 4328
+4326 4329
+4327 4328
+4328 4329
+4330 4331
+4330 4332
+4330 4333
+4330 4334
+4334 5787
+4335 5194
+4337 4338
+4339 4340
+4339 4341
+4340 4341
+4342 6681
+4342 6751
+4342 6953
+4343 4590
+4344 4345
+4344 4346
+4348 4433
+4348 6200
+4349 6518
+4350 5478
+4351 4352
+4351 4353
+4351 4354
+4351 4355
+4356 4487
+4357 6342
+4358 5207
+4358 5929
+4360 4373
+4360 6405
+4361 4362
+4363 4708
+4364 4365
+4364 5380
+4364 5835
+4366 4367
+4368 5251
+4369 4370
+4371 4372
+4372 4519
+4372 4521
+4373 4374
+4373 4375
+4374 6014
+4376 4377
+4378 4893
+4380 5189
+4380 5198
+4381 4382
+4381 4383
+4381 4384
+4385 4386
+4387 4388
+4387 4389
+4387 4390
+4388 6601
+4391 6653
+4392 5885
+4393 4741
+4394 5056
+4394 6353
+4394 6655
+4395 5357
+4397 5098
+4397 5827
+4400 7011
+4402 5118
+4403 6419
+4404 4405
+4404 4406
+4405 4406
+4405 6015
+4406 6015
+4407 7133
+4408 4409
+4410 4411
+4410 4412
+4411 4412
+4413 4755
+4415 4416
+4415 4417
+4415 4418
+4415 4419
+4415 4420
+4416 7179
+4418 6178
+4421 4422
+4421 4423
+4424 7245
+4427 4428
+4429 4468
+4429 4469
+4433 4434
+4433 4435
+4433 4436
+4433 4437
+4433 4438
+4433 4439
+4433 4440
+4433 4441
+4442 6899
+4444 4445
+4445 6551
+4447 4448
+4449 4450
+4449 4451
+4449 4452
+4449 4453
+4449 5568
+4449 5569
+4450 4451
+4450 5568
+4451 5462
+4451 5568
+4451 5569
+4454 6129
+4455 4456
+4456 6124
+4457 6476
+4458 4459
+4460 6014
+4461 4462
+4461 4463
+4466 6114
+4467 6353
+4467 6655
+4468 4469
+4469 5624
+4472 4473
+4474 4475
+4476 4477
+4476 4478
+4476 4479
+4477 4479
+4477 5390
+4477 5391
+4478 4479
+4480 4481
+4480 6859
+4483 5173
+4484 4485
+4484 4486
+4484 4487
+4487 4958
+4487 4959
+4487 4960
+4488 4655
+4490 5011
+4490 6034
+4491 4492
+4498 4499
+4499 5248
+4501 4502
+4507 6092
+4508 4509
+4510 6123
+4511 4512
+4511 7154
+4515 5326
+4516 4517
+4519 4520
+4519 4521
+4522 7034
+4523 4524
+4525 4526
+4530 6484
+4530 6488
+4531 4532
+4533 4534
+4535 4536
+4537 4550
+4538 7154
+4541 5909
+4542 4543
+4544 4654
+4544 4655
+4546 4547
+4546 4548
+4548 5522
+4548 6296
+4549 4640
+4549 6090
+4552 6853
+4557 6634
+4558 4559
+4560 4626
+4563 6387
+4564 4678
+4565 4566
+4565 4567
+4568 6527
+4571 4572
+4571 4573
+4574 4575
+4574 4576
+4575 4576
+4577 4578
+4578 4655
+4579 4631
+4580 4581
+4580 4582
+4580 4583
+4580 4584
+4580 4585
+4580 4586
+4580 4587
+4580 4588
+4580 4589
+4580 4590
+4583 4893
+4588 5502
+4590 4591
+4592 4593
+4594 4595
+4596 5284
+4597 4598
+4599 4600
+4599 4601
+4599 4602
+4599 4603
+4599 4604
+4599 4605
+4599 4606
+4599 4607
+4599 4608
+4599 4609
+4599 4610
+4599 4611
+4599 4612
+4602 4603
+4613 4614
+4613 4615
+4613 4616
+4613 4617
+4613 4618
+4613 4619
+4613 4620
+4613 4693
+4614 4693
+4615 4673
+4615 4674
+4615 4693
+4622 6427
+4624 4625
+4627 4628
+4628 7329
+4629 4630
+4629 4631
+4629 4632
+4629 4633
+4629 6125
+4631 4632
+4631 4633
+4631 5415
+4632 6208
+4634 5502
+4641 4642
+4644 4791
+4644 4880
+4645 4646
+4646 5657
+4647 4893
+4648 4649
+4650 6211
+4652 4653
+4654 4655
+4657 6127
+4657 6129
+4657 6130
+4658 6232
+4659 4660
+4661 7321
+4662 4663
+4664 4665
+4664 4666
+4664 5578
+4664 6045
+4665 4667
+4665 5578
+4666 6786
+4668 6963
+4669 4670
+4671 5260
+4673 4674
+4673 4675
+4673 4676
+4673 4693
+4674 4676
+4674 5815
+4674 5817
+4677 6838
+4678 4679
+4678 4680
+4678 4681
+4678 4682
+4684 4685
+4684 4686
+4684 4687
+4684 7265
+4685 4686
+4685 4687
+4685 4719
+4685 7265
+4686 4687
+4687 7265
+4688 5118
+4690 4691
+4691 5414
+4694 4695
+4696 4697
+4696 4865
+4698 4699
+4701 4702
+4702 6792
+4705 5561
+4705 5827
+4705 6692
+4707 4708
+4707 4709
+4707 4710
+4708 4710
+4712 4713
+4714 4715
+4716 4717
+4718 5992
+4720 4721
+4720 4722
+4723 4724
+4725 4726
+4725 5716
+4728 4729
+4729 4961
+4729 5768
+4731 4732
+4731 4733
+4731 4734
+4735 4804
+4736 4737
+4736 4738
+4736 4739
+4736 4917
+4736 5875
+4738 5255
+4738 5256
+4738 5257
+4741 4742
+4741 4743
+4744 6906
+4745 4746
+4745 4747
+4750 4751
+4752 7017
+4753 4754
+4756 6075
+4757 4758
+4759 4828
+4761 4762
+4763 4933
+4763 6927
+4768 5443
+4768 5527
+4769 5954
+4772 4773
+4772 4774
+4772 5577
+4772 6505
+4773 4774
+4773 5577
+4773 6505
+4774 5577
+4775 4776
+4775 5961
+4776 5960
+4776 5961
+4778 4779
+4780 7256
+4781 4782
+4784 4785
+4784 4786
+4785 4787
+4785 4788
+4785 4789
+4785 5300
+4789 5589
+4791 4792
+4793 5396
+4794 5004
+4795 5238
+4796 5775
+4798 5305
+4799 4800
+4800 5741
+4804 4805
+4804 4806
+4807 5793
+4810 4811
+4810 4812
+4810 5061
+4813 7291
+4814 5805
+4815 4816
+4815 4817
+4815 4818
+4815 4819
+4817 5896
+4821 6289
+4822 4823
+4826 7116
+4827 7154
+4829 6499
+4831 4832
+4833 4834
+4833 4835
+4833 4836
+4833 4837
+4838 4839
+4839 5582
+4841 4842
+4841 4843
+4841 4844
+4841 4845
+4841 4846
+4841 4847
+4841 4848
+4844 4956
+4847 4848
+4857 4858
+4858 4877
+4858 5279
+4858 5316
+4859 4860
+4861 6801
+4862 4863
+4867 4868
+4873 6289
+4874 6751
+4875 6662
+4878 4879
+4880 4881
+4880 4882
+4880 6186
+4883 4884
+4883 4885
+4883 4886
+4883 4887
+4883 4888
+4889 4890
+4891 5445
+4892 5107
+4893 4894
+4893 4895
+4893 4896
+4893 4897
+4893 4898
+4895 7099
+4896 7099
+4899 5524
+4901 4902
+4904 4905
+4906 4907
+4909 4910
+4911 4912
+4913 4914
+4915 4916
+4915 4922
+4918 4919
+4925 6531
+4926 5397
+4927 4928
+4927 4929
+4927 4930
+4931 4932
+4934 5699
+4935 5914
+4935 6232
+4936 6151
+4937 5691
+4937 6782
+4938 7183
+4939 5300
+4940 5437
+4941 7095
+4946 4947
+4946 4948
+4949 4950
+4951 4952
+4953 7233
+4954 4955
+4956 4957
+4965 4966
+4968 4969
+4970 4971
+4972 4973
+4973 6280
+4974 5736
+4978 4979
+4980 5914
+4981 5012
+4982 4983
+4985 4986
+4988 4993
+4988 4994
+4988 6888
+4989 5887
+4990 5875
+4991 4992
+4991 5372
+4992 5087
+4992 5372
+4996 4997
+4998 4999
+5000 5001
+5000 5002
+5005 5006
+5005 5007
+5005 5008
+5009 5487
+5009 5488
+5011 5668
+5012 5013
+5012 5014
+5016 5017
+5019 5033
+5021 5022
+5021 5023
+5024 5025
+5024 5026
+5024 5027
+5024 5028
+5024 5029
+5024 5030
+5024 5031
+5029 6364
+5033 5034
+5033 5035
+5033 5036
+5033 5037
+5038 5923
+5038 6124
+5039 5040
+5042 6232
+5043 5804
+5044 5045
+5044 6296
+5045 5522
+5045 5648
+5045 5989
+5045 6276
+5045 7260
+5046 5891
+5047 6933
+5047 6934
+5048 5049
+5050 6974
+5051 5513
+5053 5755
+5054 6204
+5055 7299
+5057 6676
+5058 5623
+5059 5228
+5059 5300
+5059 5360
+5059 5943
+5059 6124
+5060 5930
+5061 5062
+5061 5063
+5064 5216
+5065 5066
+5067 5471
+5068 5752
+5072 6010
+5073 5930
+5073 6208
+5074 5075
+5075 5867
+5077 5864
+5078 5079
+5081 5082
+5083 5084
+5085 5086
+5089 5215
+5089 5217
+5090 6145
+5094 5095
+5095 6150
+5096 5280
+5097 5098
+5097 5099
+5098 5561
+5098 5827
+5101 5102
+5101 5103
+5101 5104
+5105 5550
+5108 5109
+5110 5111
+5112 5483
+5113 6554
+5114 6775
+5117 5445
+5118 5119
+5118 5120
+5118 6645
+5120 6645
+5121 5122
+5123 5124
+5126 5127
+5126 7272
+5128 5129
+5128 5130
+5128 5131
+5128 5132
+5128 5133
+5128 5134
+5128 5135
+5128 5136
+5128 5137
+5128 5138
+5129 5136
+5129 5137
+5130 5134
+5131 5136
+5131 5137
+5134 5136
+5134 5137
+5135 5136
+5135 5137
+5136 5137
+5136 5429
+5136 5430
+5136 5431
+5136 7283
+5136 7284
+5137 5429
+5137 5430
+5137 5431
+5140 6062
+5142 5943
+5143 6271
+5144 6791
+5145 5280
+5147 5529
+5148 5149
+5150 5151
+5152 5823
+5153 5235
+5155 6492
+5157 5158
+5159 6387
+5160 6606
+5161 6579
+5162 6669
+5164 6227
+5165 5455
+5166 5595
+5167 5691
+5167 5926
+5169 6379
+5171 5479
+5172 6973
+5175 5176
+5177 5178
+5177 5179
+5177 5180
+5178 5179
+5178 5180
+5179 5180
+5182 5183
+5184 5185
+5184 5186
+5187 7033
+5188 6340
+5189 5190
+5189 5191
+5189 5198
+5189 5855
+5192 6790
+5193 6557
+5194 5195
+5196 6112
+5197 6695
+5198 5199
+5198 5200
+5198 5201
+5198 5202
+5200 6602
+5200 6603
+5200 7248
+5200 7249
+5204 5205
+5204 5206
+5207 5208
+5207 5929
+5208 5929
+5208 6325
+5209 6371
+5211 6039
+5212 5213
+5212 5214
+5215 5216
+5215 5217
+5215 5218
+5216 5217
+5217 5218
+5220 5677
+5221 5222
+5223 5224
+5223 5225
+5223 5226
+5223 5227
+5228 5229
+5230 5231
+5231 5814
+5232 5233
+5232 5234
+5235 5236
+5235 5237
+5239 5240
+5241 5248
+5242 5243
+5242 5244
+5245 5246
+5245 5247
+5249 5250
+5258 5259
+5260 5261
+5260 5262
+5260 5263
+5269 5270
+5269 5271
+5274 5275
+5276 5277
+5278 6829
+5280 5281
+5280 5282
+5283 5579
+5285 5286
+5285 6962
+5285 7203
+5288 5289
+5290 6703
+5291 6208
+5292 6208
+5295 5845
+5295 6562
+5296 5775
+5297 5298
+5299 6000
+5301 6058
+5303 7201
+5304 7273
+5307 6621
+5307 7139
+5309 5310
+5311 5312
+5311 5313
+5315 6383
+5316 6896
+5319 6034
+5320 5321
+5322 5787
+5322 5796
+5322 6929
+5322 6952
+5323 5778
+5324 7098
+5325 6958
+5327 5328
+5339 5340
+5340 5873
+5342 7055
+5343 6769
+5344 5345
+5347 5348
+5349 5350
+5354 5355
+5354 5356
+5357 5358
+5357 6210
+5360 5361
+5360 5362
+5360 6248
+5361 6248
+5363 5471
+5364 5365
+5365 6021
+5366 6578
+5367 6448
+5368 6197
+5369 5370
+5373 7309
+5375 5376
+5378 5662
+5379 7098
+5380 5381
+5380 5382
+5380 5383
+5380 5384
+5385 5386
+5385 5387
+5385 5388
+5385 5389
+5392 5393
+5392 5394
+5392 5399
+5394 5736
+5395 5699
+5401 5402
+5404 7198
+5407 5408
+5409 5987
+5410 5411
+5410 5412
+5413 6208
+5415 5437
+5416 5417
+5416 5418
+5416 5419
+5416 5420
+5421 5802
+5421 5862
+5421 6385
+5423 6340
+5424 5425
+5424 5697
+5424 5698
+5425 5697
+5425 5698
+5426 5427
+5426 5428
+5432 5433
+5435 5988
+5436 6733
+5439 5835
+5440 5441
+5443 5897
+5446 5583
+5450 5451
+5452 5453
+5452 5454
+5456 5457
+5456 5458
+5456 5459
+5456 5460
+5456 5461
+5462 5568
+5462 5569
+5463 6670
+5464 6670
+5465 5466
+5466 6845
+5467 5533
+5468 5469
+5468 5470
+5469 5470
+5471 5472
+5471 5473
+5474 5475
+5476 6768
+5481 5482
+5483 5484
+5483 5485
+5483 5486
+5487 5488
+5487 5489
+5491 5563
+5492 5493
+5495 5751
+5495 6508
+5496 5497
+5496 5498
+5496 5499
+5503 5504
+5505 5506
+5508 5509
+5508 6812
+5509 6812
+5509 6813
+5510 6250
+5511 5512
+5514 5515
+5514 5516
+5517 6324
+5518 6124
+5519 5520
+5521 6296
+5523 6670
+5525 5526
+5527 5528
+5527 5897
+5529 5530
+5529 5531
+5529 5532
+5533 5534
+5535 5536
+5535 5537
+5535 5538
+5535 5539
+5535 5540
+5535 5541
+5536 5541
+5537 5541
+5538 5541
+5539 5541
+5540 5541
+5541 5542
+5543 6087
+5543 6088
+5543 6089
+5543 6447
+5544 5545
+5546 5868
+5547 5548
+5550 5551
+5550 5552
+5550 5553
+5553 5622
+5554 5555
+5554 6907
+5556 5823
+5557 6296
+5558 6301
+5558 6960
+5559 5560
+5562 6910
+5564 6279
+5566 5567
+5568 5569
+5569 5574
+5570 5571
+5570 5572
+5570 5573
+5575 5576
+5580 5581
+5584 5892
+5586 5587
+5586 5588
+5586 6012
+5586 6274
+5593 5752
+5594 6296
+5596 5597
+5599 6303
+5600 5601
+5602 6067
+5603 6535
+5604 5849
+5605 5606
+5605 5607
+5606 5607
+5608 5609
+5608 5610
+5608 5611
+5608 5612
+5611 6502
+5613 5626
+5615 5616
+5615 5617
+5615 5618
+5615 5619
+5616 5618
+5617 5618
+5618 5619
+5620 5621
+5622 5623
+5625 6223
+5627 6645
+5628 7248
+5628 7249
+5631 5632
+5633 5634
+5633 5635
+5633 5636
+5637 5638
+5637 5639
+5640 5641
+5642 5643
+5644 5645
+5644 5646
+5644 5647
+5648 6296
+5649 5650
+5649 5651
+5652 6204
+5653 5654
+5655 5656
+5657 5658
+5659 5660
+5659 6184
+5660 6184
+5661 6770
+5663 5664
+5663 5665
+5663 5666
+5663 5667
+5668 5669
+5670 5699
+5671 6199
+5672 6958
+5673 6127
+5673 6129
+5673 6130
+5674 6771
+5675 5676
+5678 5679
+5678 5680
+5681 5682
+5683 5684
+5683 5685
+5683 5686
+5683 5687
+5683 5688
+5689 5871
+5691 5692
+5691 5693
+5691 5926
+5694 5695
+5697 5698
+5699 5700
+5699 5701
+5699 5702
+5699 5703
+5699 5704
+5705 5706
+5707 6415
+5708 6652
+5709 5710
+5711 5712
+5713 5714
+5713 5715
+5714 5715
+5717 5718
+5719 5720
+5721 5722
+5723 7090
+5724 5725
+5726 5727
+5726 5728
+5726 5729
+5726 5730
+5727 5728
+5727 5729
+5730 7335
+5733 6877
+5734 5735
+5736 5737
+5736 5738
+5739 5740
+5742 5743
+5744 6561
+5745 5987
+5746 5787
+5747 7040
+5747 7041
+5748 6963
+5749 7000
+5750 7301
+5752 5753
+5752 5754
+5752 5755
+5754 5755
+5755 5913
+5756 6206
+5757 6651
+5758 5759
+5760 5936
+5761 5762
+5762 5763
+5764 5765
+5764 5766
+5764 5767
+5770 5771
+5773 5774
+5777 6248
+5779 5780
+5779 5781
+5780 5781
+5782 5783
+5782 5784
+5783 5784
+5787 5788
+5787 5789
+5787 5790
+5787 5791
+5787 5792
+5794 5795
+5796 5797
+5796 5798
+5796 5799
+5798 5904
+5798 6929
+5800 6009
+5801 6091
+5802 5862
+5806 5807
+5808 5809
+5810 5811
+5813 7097
+5815 5816
+5815 5817
+5818 5819
+5818 5820
+5818 5821
+5819 5820
+5819 5821
+5820 5821
+5822 6405
+5823 5824
+5823 5825
+5823 5826
+5828 5829
+5828 5933
+5829 5933
+5830 6232
+5832 5833
+5836 5837
+5838 5880
+5839 5840
+5842 5843
+5842 5844
+5845 7193
+5846 5858
+5847 5848
+5850 5851
+5853 5854
+5855 5856
+5859 5860
+5862 5863
+5865 5866
+5867 5868
+5868 7250
+5869 5870
+5872 6829
+5875 5876
+5876 6426
+5876 6519
+5876 6740
+5876 6741
+5876 6742
+5876 7096
+5880 5881
+5882 5883
+5886 5887
+5886 5888
+5887 6402
+5889 5890
+5889 6066
+5891 5892
+5893 6227
+5894 5895
+5898 6216
+5899 6944
+5900 5901
+5900 5902
+5900 6554
+5903 7186
+5904 5905
+5904 5906
+5907 5908
+5910 7148
+5914 5915
+5917 5918
+5919 6938
+5920 6199
+5921 6427
+5923 5924
+5923 5925
+5927 5928
+5930 5931
+5930 5932
+5934 6420
+5935 6711
+5936 5937
+5936 5938
+5937 7301
+5940 5941
+5942 6991
+5943 5944
+5945 5946
+5947 5948
+5951 7117
+5952 6493
+5953 5954
+5955 6553
+5956 6383
+5957 5958
+5957 5959
+5963 5964
+5965 5966
+5967 5968
+5969 7037
+5970 6910
+5971 5972
+5973 5974
+5975 5976
+5977 5978
+5979 6897
+5980 6068
+5981 5982
+5983 5984
+5985 5986
+5989 6296
+5990 6212
+5991 6296
+5993 6087
+5993 6088
+5993 6089
+5994 5995
+5994 5996
+5997 5998
+5998 6032
+5998 6033
+5999 6897
+6000 6001
+6002 6003
+6004 6839
+6005 6006
+6005 6007
+6008 6031
+6009 6010
+6011 6928
+6012 6013
+6017 6018
+6017 6019
+6022 6153
+6023 6751
+6024 6025
+6026 6027
+6028 6079
+6029 6030
+6034 6035
+6036 6037
+6038 7251
+6040 6041
+6040 6042
+6043 6044
+6043 6045
+6045 6786
+6046 6047
+6048 6049
+6050 6051
+6052 6087
+6052 6088
+6052 6089
+6055 6056
+6058 6059
+6060 6061
+6063 6064
+6065 6621
+6069 6070
+6071 6116
+6072 6073
+6072 6074
+6075 6076
+6075 6077
+6078 7154
+6079 6080
+6081 6082
+6083 6203
+6084 7151
+6085 7273
+6086 6802
+6087 6088
+6087 6089
+6088 6089
+6089 7193
+6092 6093
+6094 6095
+6096 6097
+6098 7093
+6099 6964
+6100 6101
+6100 6102
+6100 6103
+6104 6105
+6104 6106
+6104 6107
+6104 6108
+6105 6106
+6105 6107
+6106 6107
+6106 6108
+6107 6108
+6109 6207
+6110 7201
+6111 6375
+6113 6296
+6115 7150
+6117 6118
+6119 7105
+6120 6121
+6122 6341
+6125 6126
+6127 6128
+6127 6129
+6127 6130
+6127 6131
+6128 6436
+6129 6130
+6129 6131
+6129 6132
+6130 6131
+6133 6134
+6135 6136
+6135 6137
+6135 6138
+6135 6139
+6140 6141
+6140 6142
+6140 6143
+6140 6144
+6145 6146
+6152 6458
+6153 6154
+6155 6156
+6157 7085
+6158 7164
+6159 6669
+6160 6161
+6163 7185
+6164 6705
+6164 6914
+6165 6166
+6167 6168
+6169 6170
+6171 6172
+6173 6174
+6174 6444
+6174 7287
+6175 6176
+6177 6941
+6179 6180
+6179 6181
+6179 6182
+6179 6183
+6185 6224
+6187 6188
+6188 6189
+6190 6191
+6192 6977
+6193 6296
+6194 6396
+6195 6918
+6196 6227
+6198 6940
+6201 6202
+6205 6206
+6208 6209
+6213 6214
+6215 7149
+6216 6217
+6218 6219
+6220 7003
+6221 6959
+6222 6312
+6224 6225
+6226 6428
+6227 7022
+6228 6229
+6230 6231
+6233 6234
+6233 6235
+6234 6781
+6236 6237
+6237 6885
+6238 6948
+6238 6949
+6238 6950
+6239 6985
+6240 6947
+6241 6242
+6241 6243
+6244 6245
+6246 6247
+6249 7040
+6249 7041
+6251 6252
+6251 6253
+6251 6254
+6255 6256
+6255 6257
+6255 6258
+6259 6260
+6259 6261
+6259 6262
+6264 6383
+6265 6266
+6267 6995
+6268 6269
+6272 6273
+6273 7320
+6275 6822
+6278 7301
+6283 6284
+6283 6285
+6287 6289
+6290 6789
+6291 7163
+6292 7037
+6293 6960
+6294 6789
+6295 6942
+6296 6297
+6296 6298
+6299 6300
+6302 6346
+6304 6305
+6304 6306
+6308 7175
+6309 6310
+6309 6311
+6309 6933
+6309 6934
+6310 6311
+6310 7048
+6313 6962
+6314 6315
+6316 6902
+6317 6318
+6319 6320
+6319 6321
+6319 6322
+6319 6323
+6319 6395
+6319 6396
+6320 6321
+6320 6322
+6320 6323
+6320 6395
+6320 6396
+6321 6322
+6321 6323
+6321 6395
+6321 6396
+6321 6441
+6321 6442
+6321 6443
+6323 6396
+6326 7155
+6327 7068
+6328 6329
+6328 6330
+6331 6332
+6332 6903
+6334 7094
+6335 6959
+6336 6946
+6337 6735
+6338 6339
+6343 6344
+6345 6901
+6347 6348
+6349 6350
+6351 6352
+6353 6354
+6353 6355
+6354 6655
+6355 6655
+6356 6357
+6357 7065
+6358 6359
+6360 6361
+6362 6363
+6365 6901
+6367 6368
+6369 6370
+6371 6372
+6374 7038
+6376 6978
+6377 6944
+6379 6380
+6381 6789
+6382 6937
+6385 6386
+6387 6388
+6387 6389
+6387 6390
+6387 6391
+6387 6392
+6393 6394
+6395 6396
+6395 6397
+6396 6441
+6396 7134
+6396 7135
+6396 7136
+6396 7137
+6396 7138
+6398 7233
+6399 6400
+6403 6404
+6406 6407
+6406 6408
+6406 7018
+6409 6410
+6411 6412
+6416 6417
+6418 6852
+6420 6421
+6422 6423
+6424 6425
+6429 6430
+6429 6431
+6432 6433
+6434 6435
+6437 6438
+6439 6772
+6444 6602
+6444 6603
+6444 7248
+6444 7249
+6445 6446
+6449 6450
+6449 6451
+6450 6451
+6453 6454
+6455 6646
+6458 6459
+6458 6460
+6461 6462
+6463 6464
+6465 6466
+6468 6469
+6470 6471
+6472 6473
+6472 6474
+6472 6475
+6473 6474
+6474 6475
+6476 6477
+6476 6478
+6476 6479
+6476 6480
+6476 6481
+6476 6990
+6477 6478
+6478 6990
+6482 6483
+6484 6485
+6484 6486
+6484 6487
+6484 6488
+6484 6489
+6484 6490
+6485 6488
+6486 6488
+6487 6488
+6491 6896
+6494 6495
+6494 6496
+6497 6498
+6501 7267
+6501 7268
+6503 6504
+6506 6507
+6509 6510
+6512 6513
+6514 6519
+6515 6516
+6516 6754
+6517 6518
+6518 6723
+6519 6520
+6519 6521
+6519 6522
+6523 6524
+6525 6526
+6525 6527
+6527 6528
+6529 6530
+6533 6534
+6536 6537
+6536 6538
+6536 6539
+6540 6541
+6542 6543
+6544 6545
+6544 6546
+6544 6547
+6545 6547
+6546 6547
+6548 6787
+6548 6788
+6548 7036
+6549 6550
+6554 6555
+6554 6556
+6558 6942
+6559 6560
+6563 6564
+6565 7193
+6567 6568
+6570 7095
+6573 6574
+6573 6575
+6574 6575
+6582 6583
+6584 6585
+6584 6586
+6587 6588
+6589 6590
+6591 6592
+6593 6594
+6593 6595
+6596 6597
+6598 6599
+6598 6600
+6602 6603
+6603 6604
+6607 6608
+6609 6954
+6610 6611
+6610 6612
+6610 6613
+6610 6614
+6610 6615
+6610 6616
+6612 6613
+6612 6614
+6613 6614
+6613 6734
+6617 6618
+6617 6619
+6620 6812
+6620 6813
+6621 6622
+6621 6623
+6624 7255
+6625 6626
+6625 6627
+6625 6628
+6625 6629
+6625 6630
+6625 6631
+6632 6633
+6636 6637
+6640 6641
+6640 6642
+6643 6644
+6647 6648
+6649 6650
+6656 6657
+6656 6658
+6659 6660
+6659 6661
+6662 6663
+6664 6665
+6664 6666
+6664 6667
+6664 6668
+6665 6666
+6665 6667
+6665 6668
+6666 6667
+6666 6668
+6667 6668
+6671 6951
+6672 6951
+6675 6676
+6676 6677
+6679 6680
+6682 6683
+6684 7114
+6685 6686
+6687 6688
+6687 6689
+6690 6691
+6693 6930
+6694 6821
+6695 6696
+6695 6697
+6698 7244
+6699 7019
+6699 7020
+6699 7021
+6701 6702
+6705 6914
+6707 6708
+6709 6710
+6712 6713
+6712 6714
+6714 6752
+6715 6716
+6715 6717
+6715 6718
+6715 6719
+6715 6720
+6715 6721
+6724 6725
+6724 6726
+6727 6728
+6729 6730
+6731 6732
+6735 6736
+6735 6737
+6738 6739
+6741 7096
+6743 6744
+6745 6746
+6747 6748
+6749 6750
+6752 6753
+6755 6756
+6758 6759
+6758 6760
+6761 6762
+6763 7000
+6763 7001
+6764 7099
+6766 6767
+6778 6779
+6780 6781
+6782 6783
+6784 6785
+6787 6788
+6787 7036
+6793 6794
+6803 6804
+6805 6806
+6806 6807
+6808 6809
+6810 6811
+6812 6813
+6815 6816
+6819 7180
+6823 6824
+6825 6826
+6827 6828
+6830 6831
+6832 6834
+6833 6835
+6836 6837
+6841 6842
+6843 6844
+6847 6848
+6850 7028
+6851 7090
+6854 6855
+6854 6856
+6857 6858
+6859 6860
+6862 6863
+6862 6864
+6862 6865
+6862 6866
+6862 6867
+6862 6868
+6862 6869
+6862 6870
+6862 6871
+6862 6872
+6862 6873
+6862 6874
+6862 6875
+6862 6876
+6878 6879
+6878 6880
+6878 6881
+6878 6882
+6878 6883
+6879 6883
+6880 6882
+6880 6883
+6881 6882
+6889 6890
+6889 6891
+6892 6893
+6892 6894
+6897 6898
+6903 6904
+6903 6905
+6908 6909
+6911 6912
+6915 7033
+6917 6918
+6918 7199
+6919 7033
+6920 6921
+6922 6923
+6924 7192
+6926 6979
+6930 6931
+6933 6934
+6935 6936
+6939 6968
+6942 6943
+6945 7192
+6948 6949
+6948 6950
+6948 6976
+6949 6950
+6949 6976
+6955 6956
+6960 6961
+6965 6966
+6965 6967
+6969 6970
+6971 7201
+6972 7030
+6975 7078
+6981 6982
+6983 6984
+6983 6985
+6986 6987
+6986 6988
+6986 6989
+6991 6992
+6993 6994
+6996 6997
+6998 6999
+7000 7001
+7004 7005
+7006 7007
+7008 7009
+7008 7010
+7012 7013
+7014 7015
+7016 7081
+7019 7020
+7024 7025
+7026 7027
+7028 7029
+7031 7032
+7034 7035
+7040 7041
+7042 7043
+7044 7045
+7046 7111
+7049 7050
+7051 7052
+7051 7053
+7052 7053
+7057 7058
+7059 7060
+7059 7061
+7060 7061
+7062 7063
+7062 7064
+7066 7067
+7069 7070
+7069 7071
+7072 7073
+7074 7144
+7075 7093
+7076 7082
+7079 7080
+7083 7084
+7086 7087
+7088 7089
+7091 7092
+7101 7102
+7103 7104
+7107 7108
+7112 7113
+7114 7115
+7118 7119
+7118 7120
+7121 7257
+7122 7123
+7124 7125
+7126 7127
+7128 7129
+7130 7131
+7130 7132
+7131 7132
+7140 7141
+7145 7273
+7146 7147
+7152 7153
+7157 7158
+7159 7160
+7161 7162
+7165 7166
+7167 7168
+7169 7170
+7171 7172
+7176 7177
+7181 7318
+7182 7203
+7183 7184
+7187 7188
+7187 7189
+7188 7190
+7188 7191
+7189 7190
+7195 7196
+7201 7202
+7204 7205
+7206 7207
+7208 7209
+7210 7211
+7212 7213
+7214 7215
+7216 7217
+7218 7219
+7220 7221
+7223 7224
+7224 7269
+7224 7293
+7224 7319
+7226 7227
+7228 7229
+7230 7231
+7230 7232
+7233 7234
+7235 7236
+7237 7238
+7239 7240
+7240 7328
+7241 7242
+7246 7247
+7248 7249
+7253 7254
+7258 7259
+7261 7262
+7263 7264
+7266 7267
+7266 7268
+7267 7268
+7270 7271
+7273 7274
+7275 7276
+7275 7277
+7276 7277
+7278 7279
+7279 7280
+7281 7282
+7283 7284
+7285 7286
+7289 7290
+7294 7295
+7297 7298
+7302 7303
+7304 7305
+7304 7306
+7307 7308
+7310 7311
+7313 7314
+7316 7317
+7321 7322
+7323 7324
+7326 7327
+7332 7333
+7332 7334
+7335 7336
+7335 7337
+7335 7338
diff --git a/igraph.pc b/igraph.pc
new file mode 100644
index 0000000..ee0aa86
--- /dev/null
+++ b/igraph.pc
@@ -0,0 +1,12 @@
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libigraph
+Description: A library for creating and manipulating graphs
+Version: 0.7.1
+URL: http://igraph.org
+Libs: -L${libdir} -ligraph
+Libs.private: -lxml2 -lz -lm -lgmp
+Cflags: -I${includedir}/igraph
diff --git a/igraph.pc.in b/igraph.pc.in
new file mode 100644
index 0000000..474967d
--- /dev/null
+++ b/igraph.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libigraph
+Description: A library for creating and manipulating graphs
+Version: @VERSION@
+URL: http://igraph.org
+Libs: -L${libdir} -ligraph
+Libs.private: @PKGCONFIG_LIBS_PRIVATE@
+Cflags: -I${includedir}/igraph
diff --git a/igraph_Info.plist.in b/igraph_Info.plist.in
new file mode 100644
index 0000000..d78d9f4
--- /dev/null
+++ b/igraph_Info.plist.in
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>igraph</string>
+	<key>CFBundleIdentifier</key>
+	<string>hu.kfki.rmki.cneuro.igraph</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+	<key>CFBundleShortVersionString</key>
+	<string>@VERSION@</string>
+	<key>CFBundleSignature</key>
+	<string>DARC</string>
+	<key>CFBundleVersion</key>
+	<string>@VERSION@</string>
+</dict>
+</plist>
diff --git a/include/igraph.h b/include/igraph.h
new file mode 100644
index 0000000..f5848d0
--- /dev/null
+++ b/include/igraph.h
@@ -0,0 +1,97 @@
+/* -*- 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/include/igraph_adjlist.h b/include/igraph_adjlist.h
new file mode 100644
index 0000000..2e5caf8
--- /dev/null
+++ b/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_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/include/igraph_arpack.h b/include/igraph_arpack.h
new file mode 100644
index 0000000..b165665
--- /dev/null
+++ b/include/igraph_arpack.h
@@ -0,0 +1,341 @@
+/* -*- 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_types.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.h"
+
+#ifndef ARPACK_H
+#define ARPACK_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_arpack ARPACK interface in igraph
+ *
+ * <para>
+ * 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 \c n by \c n matrix \c A. It is
+ * most appropriate for large sparse or structured matrices \c A where
+ * structured means that a matrix-vector product <code>w <- Av</code> requires
+ * order \c n rather than the usual order <code>n^2</code> floating point
+ * operations. Please see
+ * http://www.caam.rice.edu/software/ARPACK/ for details.
+ * </para>
+ *
+ * <para>
+ * The eigenvalue calculation in ARPACK (in the simplest
+ * case) involves the calculation of the \c Av product where \c A
+ * is the matrix we work with and \c v is an arbitrary vector. A
+ * user-defined function of type \ref igraph_arpack_function_t
+ * is expected to perform this product. If the product can be done
+ * efficiently, e.g. if the matrix is sparse, then ARPACK is usually
+ * able to calculate the eigenvalues very quickly.
+ * </para>
+ *
+ * <para>In igraph, eigenvalue/eigenvector calculations usually
+ * involve the following steps:
+ * \olist
+ *   \oli Initialization of an \ref igraph_arpack_options_t data
+ *        structure using \ref igraph_arpack_options_init.
+ *   \oli Setting some options in the initialized \ref
+ *        igraph_arpack_options_t object.
+ *   \oli Defining a function of type \ref igraph_arpack_function_t.
+ *        The input of this function is a vector, and the output
+ *        should be the output matrix multiplied by the input vector.
+ *   \oli Calling \ref igraph_arpack_rssolve() (is the matrix is
+ *        symmetric), or \ref igraph_arpack_rnsolve().
+ * \endolist
+ * The \ref igraph_arpack_options_t object can be used multiple
+ * times.
+ * </para>
+ *
+ * <para>
+ * If we have many eigenvalue problems to solve, then it might worth
+ * to create an \ref igraph_arpack_storage_t object, and initialize it
+ * via \ref igraph_arpack_storage_init(). This structure contains all
+ * memory needed for ARPACK (with the given upper limit regerding to
+ * the size of the eigenvalue problem). Then many problems can be
+ * solved using the same \ref igraph_arpack_storage_t object, without
+ * always reallocating the required memory.
+ * The \ref igraph_arpack_storage_t object needs to be destroyed by
+ * calling \ref igraph_arpack_storage_destroy() on it, when it is not
+ * needed any more.
+ * </para>
+ *
+ * <para>
+ * igraph does not contain all
+ * ARPACK routines, only the ones dealing with symmetric and
+ * non-symmetric eigenvalue problems using double precision real
+ * numbers.
+ * </para>
+ *
+ */
+
+/**
+ * \struct igraph_arpack_options_t
+ * \brief Options for ARPACK
+ *
+ * This data structure contains the options of thee ARPACK eigenvalue
+ * solver routines. It must be initialized by calling \ref
+ * igraph_arpack_options_init() on it. Then it can be used for
+ * multiple ARPACK calls, as the ARPACK solvers do not modify it.
+ *
+ * Input options:
+ * \member bmat Character. Whether to solve a standard ('I') ot a
+ *    generalized problem ('B').
+ * \member n Dimension of the eigenproblem.
+ * \member which Specifies which eigenvalues/vectors to
+ *    compute. Possible values for symmetric matrices:
+ *    \clist \cli LA
+ *                Compute \c nev largest (algebraic) eigenvalues.
+ *           \cli SA
+ *                Compute \c nev smallest (algebraic) eigenvalues.
+ *           \cli LM
+ *                Compute \c nev largest (in magnitude) eigenvalues.
+ *           \cli SM
+ *                Compute \c nev smallest (in magnitude) eigenvalues.
+ *           \cli BE
+ *                Compute \c nev eigenvalues, half from each end of
+ *                   the spectrum. When \c nev is odd, compute one
+ *                   more from the high en than from the low
+ *                   end. \endclist
+ *    Possible values for non-symmetric matrices:
+ *    \clist \cli LM
+ *                Compute \c nev largest (in magnitude) eigenvalues.
+ *           \cli SM
+ *                Compute \c nev smallest (in magnitude) eigenvalues.
+ *           \cli LR
+ *                Compute \c nev eigenvalues of largest real part.
+ *           \cli SR
+ *                Compute \c nev eigenvalues of smallest real part.
+ *           \cli LI
+ *                Compute \c nev eigenvalues of largest imaginary part.
+ *           \cli SI
+ *                Compute \c nev eigenvalues of smallest imaginary
+ *                    part. \endclist
+ * \member nev The number of eigenvalues to be computed.
+ * \member tol Stopping criterion: the relative accuracy
+ *    of the Ritz value is considered acceptable if its error is less
+ *    than \c tol times its estimated value. If this is set to zero
+ *    then machine precision is used.
+ * \member ncv Number of Lanczos vectors to be generated. Setting this
+ *    to zero means that \ref igraph_arpack_rssolve and \ref igraph_arpack_rnsolve
+ *    will determine a suitable value for \c ncv automatically.
+ * \member ldv Numberic scalar. It should be set to
+ *    zero in the current igraph implementation.
+ * \member 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 \c T.
+ *    Please always set this to one.
+ * \member mxiter Maximum number of Arnoldi update iterations allowed.
+ * \member nb Blocksize to be used in the recurrence. Please always
+ *    leave this on the default value, one.
+ * \member mode The type of the eigenproblem to be solved.
+ *    Possible values if the input matrix is symmetric:
+ *    \olist
+ *      \oli A*x=lambda*x, A is symmetric.
+ *      \oli A*x=lambda*M*x, A is
+ *       symmetric, M is symmetric positive definite.
+ *      \oli K*x=lambda*M*x, K is
+ *        symmetric, M is symmetric positive semi-definite.
+ *      \oli K*x=lambda*KG*x, K is
+ *       symmetric positive semi-definite, KG is symmetric
+ *       indefinite.
+ *     \oli A*x=lambda*M*x, A is
+ *       symmetric, M is symmetric positive
+ *       semi-definite. (Cayley transformed mode.) \endolist
+ *    Please note that only \c mode ==1 was tested and other values
+ *    might not work properly.
+ *    Possible values if the input matrix is not symmetric:
+ *    \olist
+ *     \oli A*x=lambda*x.
+ *     \oli A*x=lambda*M*x, M is
+ *       symmetric positive definite.
+ *     \oli A*x=lambda*M*x, M is
+ *       symmetric semi-definite.
+ *     \oli A*x=lambda*M*x, M is
+ *           symmetric semi-definite. \endolist
+ *     Please note that only \c mode == 1 was tested and other values
+ *     might not work properly.
+ * \member start Whether to use the supplied starting vector (1), or
+ *    use a random starting vector (0). The starting vector must be
+ *    supplied in the first column of the \c vectors argument of the
+ *    \ref igraph_arpack_rssolve() of \ref igraph_arpack_rnsolve() call.
+ *
+ * Output options:
+ * \member info Error flag of ARPACK. Possible values:
+ *    \clist \cli 0
+ *                Normal exit.
+ *           \cli 1
+ *                Maximum number of iterations taken.
+ *           \cli 3
+ *                No shifts could be applied during a cycle of the
+ *         Implicitly restarted Arnoldi iteration. One possibility
+ *         is to increase the size of \c ncv relative to \c
+ *           nev. \endclist
+ *    ARPACK can return other error flags as well, but these are
+ *    converted to igraph errors, see \ref igraph_error_type_t.
+ * \member ierr Error flag of the second ARPACK call (one eigenvalue
+ *     computation usually involves two calls to ARPACK). This is
+ *     always zero, as other error codes are converted to igraph errors.
+ * \member noiter Number of Arnoldi iterations taken.
+ * \member nconv Number of converged Ritz values. This
+ *     represents the number of Ritz values that satisfy the
+ *     convergence critetion.
+ * \member numop Total number of matrix-vector multiplications.
+ * \member numopb Not used currently.
+ * \member numreo Total number of steps of re-orthogonalization.
+ *
+ * Internal options:
+ * \member lworkl Do not modify this option.
+ * \member sigma The shift for the shift-invert mode.
+ * \member sigmai The imaginary part of the shift, for the
+ *    non-symmetric or complex shift-invert mode.
+ * \member iparam Do not modify this option.
+ * \member ipntr Do not modify this option.
+ *
+ */
+
+typedef struct igraph_arpack_options_t {
+  /* INPUT */
+  char bmat[1];			/* I-standard problem, G-generalized */
+  int n; 			/* Dimension of the eigenproblem */
+  char which[2];		/* LA, SA, LM, SM, BE */
+  int nev;                 /* Number of eigenvalues to be computed */
+  igraph_real_t tol;		/* Stopping criterion */
+  int ncv;			/* Number of columns in V */
+  int ldv;			/* Leading dimension of V */
+  int ishift;		/* 0-reverse comm., 1-exact with tridiagonal */
+  int mxiter;              /* Maximum number of update iterations to take */
+  int nb;			/* Block size on the recurrence, only 1 works */
+  int mode;		/* The kind of problem to be solved (1-5)
+				   1: A*x=l*x, A symmetric
+				   2: A*x=l*M*x, A symm. M pos. def.
+				   3: K*x = l*M*x, K symm., M pos. semidef.
+				   4: K*x = l*KG*x, K s. pos. semidef. KG s. indef.
+				   5: A*x = l*M*x, A symm., M symm. pos. semidef. */
+  int start;		/* 0: random, 1: use the supplied vector */
+  int lworkl;		/* Size of temporary storage, default is fine */
+  igraph_real_t sigma;          /* The shift for modes 3,4,5 */
+  igraph_real_t sigmai;		/* The imaginary part of shift for rnsolve */
+  /* OUTPUT */
+  int info;		/* What happened, see docs */
+  int ierr;		/* What happened  in the dseupd call */
+  int noiter;		/* The number of iterations taken */
+  int nconv;
+  int numop;		/* Number of OP*x operations */
+  int numopb;		/* Number of B*x operations if BMAT='G' */
+  int numreo;		/* Number of steps of re-orthogonalizations */
+  /* INTERNAL */
+  int iparam[11];
+  int ipntr[14];
+} igraph_arpack_options_t;
+
+/**
+ * \struct igraph_arpack_storage_t
+ * \brief Storage for ARPACK
+ *
+ * Public members, do not modify them directly, these are considered
+ * to be read-only.
+ * \member maxn Maximum rank of matrix.
+ * \member maxncv Maximum NCV.
+ * \member maxldv Maximum LDV.
+ *
+ * These members are considered to be private:
+ * \member workl Working memory.
+ * \member workd Working memory.
+ * \member d Memory for eigenvalues.
+ * \member resid Memory for residuals.
+ * \member ax Working memory.
+ * \member select Working memory.
+ * \member di Memory for eigenvalues, non-symmetric case only.
+ * \member workev Working memory, non-symmetric case only.
+ */
+
+typedef struct igraph_arpack_storage_t {
+  int maxn, maxncv, maxldv;
+  igraph_real_t *v;
+  igraph_real_t *workl;
+  igraph_real_t *workd;
+  igraph_real_t *d;
+  igraph_real_t *resid;
+  igraph_real_t *ax;
+  int *select;
+  igraph_real_t *di;		/* These two only for non-symmetric problems */
+  igraph_real_t *workev;
+} igraph_arpack_storage_t;
+
+void igraph_arpack_options_init(igraph_arpack_options_t *o);
+
+int igraph_arpack_storage_init(igraph_arpack_storage_t *s, long int maxn,
+			       long int maxncv, long int maxldv, igraph_bool_t symm);
+void igraph_arpack_storage_destroy(igraph_arpack_storage_t *s);
+
+/**
+ * \typedef igraph_arpack_function_t
+ * Type of the ARPACK callback function
+ *
+ * \param to Pointer to an \c igraph_real_t, the result of the
+ *    matrix-vector product is expected to be stored here.
+ * \param from Pointer to an \c igraph_real_t, the input matrix should
+ *    be multiplied by the vector stored here.
+ * \param n The length of the vector (which is the same as the order
+ *    of the input matrix).
+ * \param extra Extra argument to the matrix-vector calculation
+ *    function. This is coming from the \ref igraph_arpack_rssolve()
+ *    or \ref igraph_arpack_rnsolve() function.
+ * \return Error code, if not zero, then the ARPACK solver considers
+ *    this as an error, stops and calls the igraph error handler.
+ */
+
+typedef int igraph_arpack_function_t(igraph_real_t *to, const igraph_real_t *from,
+				     int n, void *extra);
+
+int igraph_arpack_rssolve(igraph_arpack_function_t *fun, void *extra,
+			  igraph_arpack_options_t *options,
+			  igraph_arpack_storage_t *storage,
+			  igraph_vector_t *values, igraph_matrix_t *vectors);
+
+int igraph_arpack_rnsolve(igraph_arpack_function_t *fun, void *extra,
+			  igraph_arpack_options_t *options,
+			  igraph_arpack_storage_t *storage,
+			  igraph_matrix_t *values, igraph_matrix_t *vectors);
+
+int igraph_arpack_unpack_complex(igraph_matrix_t *vectors, igraph_matrix_t *values,
+				 long int nev);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_array.h b/include/igraph_array.h
new file mode 100644
index 0000000..4b8a47e
--- /dev/null
+++ b/include/igraph_array.h
@@ -0,0 +1,69 @@
+/* -*- 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_ARRAY_H
+#define IGRAPH_ARRAY_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
+
+/* -------------------------------------------------- */
+/* 3D array                                           */
+/* -------------------------------------------------- */
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "igraph_array_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "igraph_array_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "igraph_array_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "igraph_array_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_array_pmt.h b/include/igraph_array_pmt.h
new file mode 100644
index 0000000..c262176
--- /dev/null
+++ b/include/igraph_array_pmt.h
@@ -0,0 +1,51 @@
+/* -*- 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_array3) {
+  TYPE(igraph_vector) data;
+  long int n1, n2, n3, n1n2;
+} TYPE(igraph_array3);
+
+#ifndef IGRAPH_ARRAY3_INIT_FINALLY
+#define IGRAPH_ARRAY3_INIT_FINALLY(a, n1, n2, n3) \
+  do { IGRAPH_CHECK(igraph_array3_init(a, n1, n2, n3)); \
+  IGRAPH_FINALLY(igraph_array3_destroy, a); } while (0)
+#endif
+
+#ifndef ARRAY3
+#define ARRAY3(m,i,j,k) ((m).data.stor_begin[(m).n1n2*(k)+(m).n1*(j)+(i)])
+#endif
+
+int FUNCTION(igraph_array3,init)(TYPE(igraph_array3) *a, long int n1, long int n2, 
+				 long int n3);
+void FUNCTION(igraph_array3,destroy)(TYPE(igraph_array3) *a);
+long int FUNCTION(igraph_array3,size)(const TYPE(igraph_array3) *a);
+long int FUNCTION(igraph_array3,n)(const TYPE(igraph_array3) *a, long int idx);
+int FUNCTION(igraph_array3,resize)(TYPE(igraph_array3) *a, long int n1, long int n2, 
+				   long int n3);
+void FUNCTION(igraph_array3,null)(TYPE(igraph_array3) *a);
+BASE FUNCTION(igraph_array3,sum)(const TYPE(igraph_array3) *a);
+void FUNCTION(igraph_array3,scale)(TYPE(igraph_array3) *a, BASE by);
+void FUNCTION(igraph_array3,fill)(TYPE(igraph_array3) *a, BASE e);
+int FUNCTION(igraph_array3,update)(TYPE(igraph_array3) *to, 
+				   const TYPE(igraph_array3) *from);
diff --git a/include/igraph_attributes.h b/include/igraph_attributes.h
new file mode 100644
index 0000000..003bc56
--- /dev/null
+++ b/include/igraph_attributes.h
@@ -0,0 +1,878 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#ifndef REST_ATTRIBUTES_H
+#define REST_ATTRIBUTES_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_types.h"
+#include "igraph_vector.h"
+#include "igraph_strvector.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Attributes                                         */
+/* -------------------------------------------------- */
+
+/**
+ * \section about_attributes
+ * 
+ * <para>Attributes are numbers or strings (or basically any kind
+ * of data) associated with the vertices or edges of a graph, or
+ * with the graph itself. Eg. you may label vertices with symbolic names
+ * or attach numeric weights to the edges of a graph. </para>
+ * 
+ * <para>igraph attributes are designed to be flexible and extensible. 
+ * In igraph attributes are implemented via an interface abstraction:
+ * any type implementing the functions in the interface, can be used
+ * for storing vertex, edge and graph attributes. This means that
+ * different attribute implementations can be used together with
+ * igraph. This is reasonable: if igraph is used from Python attributes can be
+ * of any Python type, from GNU R all R types are allowed. There is an
+ * experimental attribute implementation to be used when programming
+ * in C, but by default it is currently turned off.</para>
+ * 
+ * <para>First we briefly look over how attribute handlers can be
+ * implemented. This is not something a user does every day. It is
+ * rather typically the job of the high level interface writers. (But
+ * it is possible to write an interface without implementing
+ * attributes.) Then we show the experimental C attribute handler.</para>
+ */
+
+/**
+ * \section about_attribute_table
+ * <para>It is possible to attach an attribute handling
+ * interface to \a igraph. This is simply a table of functions, of
+ * type \ref igraph_attribute_table_t. These functions are invoked to
+ * notify the attribute handling code about the structural changes in
+ * a graph. See the documentation of this type for details.</para>
+ *
+ * <para>By default there is no attribute interface attached to \a igraph,
+ * to attach one, call \ref igraph_i_set_attribute_table with your new
+ * table. </para>
+ *
+ */
+
+/**
+ * \typedef igraph_attribute_type_t
+ * The possible types of the attributes. 
+ * 
+ * Note that this is only the
+ * type communicated by the attribute interface towards igraph
+ * functions. Eg. in the GNU R attribute handler, it is safe to say
+ * that all complex R object attributes are strings, as long as this
+ * interface is able to serialize them into strings. See also \ref
+ * igraph_attribute_table_t.
+ * \enumval IGRAPH_ATTRIBUTE_DEFAULT Currently not used for anything.
+ * \enumval IGRAPH_ATTRIBUTE_NUMERIC Numeric attribute.
+ * \enumval IGRAPH_ATTRIBUTE_BOOLEAN Logical values, true or false.
+ * \enumval IGRAPH_ATTRIBUTE_STRING Attribute that can be converted to
+ *   a string.
+ * \enumval IGRAPH_ATTRIBUTE_R_OBJECT An R object. This is usually
+ *   ignored by the igraph functions.
+ * \enumval IGRAPH_ATTRIBUTE_PY_OBJECT A Python object. Usually
+ *   ignored by the igraph functions.
+ * 
+ */
+typedef enum { IGRAPH_ATTRIBUTE_DEFAULT=0,
+	       IGRAPH_ATTRIBUTE_NUMERIC=1,
+	       IGRAPH_ATTRIBUTE_BOOLEAN=5,
+	       IGRAPH_ATTRIBUTE_STRING=2,
+	       IGRAPH_ATTRIBUTE_R_OBJECT=3, 
+	       IGRAPH_ATTRIBUTE_PY_OBJECT=4 } igraph_attribute_type_t;
+
+typedef struct igraph_attribute_record_t {
+  const char *name;
+  igraph_attribute_type_t type;
+  const void *value;
+} igraph_attribute_record_t;
+
+typedef enum { IGRAPH_ATTRIBUTE_GRAPH=0,
+	       IGRAPH_ATTRIBUTE_VERTEX,
+	       IGRAPH_ATTRIBUTE_EDGE } igraph_attribute_elemtype_t;
+
+typedef enum {
+  IGRAPH_ATTRIBUTE_COMBINE_IGNORE=0,
+  IGRAPH_ATTRIBUTE_COMBINE_DEFAULT=1,
+  IGRAPH_ATTRIBUTE_COMBINE_FUNCTION=2,
+  IGRAPH_ATTRIBUTE_COMBINE_SUM=3,
+  IGRAPH_ATTRIBUTE_COMBINE_PROD=4,
+  IGRAPH_ATTRIBUTE_COMBINE_MIN=5,
+  IGRAPH_ATTRIBUTE_COMBINE_MAX=6,
+  IGRAPH_ATTRIBUTE_COMBINE_RANDOM=7,
+  IGRAPH_ATTRIBUTE_COMBINE_FIRST=8,
+  IGRAPH_ATTRIBUTE_COMBINE_LAST=9,
+  IGRAPH_ATTRIBUTE_COMBINE_MEAN=10,
+  IGRAPH_ATTRIBUTE_COMBINE_MEDIAN=11,
+  IGRAPH_ATTRIBUTE_COMBINE_CONCAT=12 } igraph_attribute_combination_type_t;
+
+typedef struct igraph_attribute_combination_record_t {
+  const char *name;		/* can be NULL, meaning: the rest */
+  igraph_attribute_combination_type_t type;
+  void *func;
+} igraph_attribute_combination_record_t;
+
+typedef struct igraph_attribute_combination_t {
+  igraph_vector_ptr_t list;
+} igraph_attribute_combination_t;
+
+#define IGRAPH_NO_MORE_ATTRIBUTES ((const char*)0)
+
+int igraph_attribute_combination_init(igraph_attribute_combination_t *comb);
+int igraph_attribute_combination(igraph_attribute_combination_t *comb, ...);
+void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb);
+int igraph_attribute_combination_add(igraph_attribute_combination_t *comb,
+				     const char *name, 
+				     igraph_attribute_combination_type_t type,
+				     void *func);
+int igraph_attribute_combination_remove(igraph_attribute_combination_t *comb, 
+					const char *name);
+int igraph_attribute_combination_query(const igraph_attribute_combination_t *comb,
+				       const char *name,
+				       igraph_attribute_combination_type_t *type,
+				       void **func);
+
+/**
+ * \struct igraph_attribute_table_t
+ * \brief Table of functions to perform operations on attributes
+ * 
+ * This type collects the functions defining an attribute handler.
+ * It has the following members:
+ * \member init This function is called whenever a new graph object is
+ *    created, right after it is created but before any vertices or
+ *    edges are added. It is supposed to set the \c attr member of the \c
+ *    igraph_t object. It is expected to return an error code.
+ * \member destroy This function is called whenever the graph object
+ *    is destroyed, right before freeing the allocated memory. 
+ * \member copy This function is called when copying a graph with \ref
+ *    igraph_copy, after the structure of the graph has been already
+ *    copied. It is expected to return an error code.
+ * \member add_vertices Called when vertices are added to a
+ *    graph, before adding the vertices themselves.
+ *    The number of vertices to add is supplied as an
+ *    argument. Expected to return an error code. 
+ * \member permute_vertices Typically called when a new graph is
+ *    created based on an existing one, e.g. if vertices are removed
+ *    from a graph. The supplied index vector defines which old vertex
+ *    a new vertex corresponds to. Its length must be the same as the
+ *    number of vertices in the new graph.
+ * \member combine_vertices This function is called when the creation
+ *    of a new graph involves a merge (contraction, etc.) of vertices
+ *    from another graph. The function is after the new graph was created.
+ *    An argument specifies how several vertices from the old graph map to a 
+ *    single vertex in the new graph.
+ * \member add_edges Called when new edges have been added. The number
+ *    of new edges are supplied as well. It is expected to return an
+ *    error code.
+ * \member permute_edges Typically called when a new graph is created and 
+ *    some of the new edges should carry the attributes of some of the
+ *    old edges. The idx vector shows the mapping between the old edges and 
+ *    the new ones. Its length is the same as the number of edges in the new 
+ *    graph, and for each edge it gives the id of the old edge (the edge in
+ *    the old graph).
+ * \member combine_edges This function is called when the creation
+ *    of a new graph involves a merge (contraction, etc.) of edges
+ *    from another graph. The function is after the new graph was created.
+ *    An argument specifies how several edges from the old graph map to a 
+ *    single edge in the new graph.
+ * \member get_info Query the attributes of a graph, the names and
+ *    types should be returned.
+ * \member has_attr Check whether a graph has the named
+ *    graph/vertex/edge attribute.
+ * \member gettype Query the type of a graph/vertex/edge attribute.
+ * \member get_numeric_graph_attr Query a numeric graph attribute. The
+ *    value should be placed as the first element of the \p value
+ *    vector.
+ * \member get_string_graph_attr Query a string graph attribute. The 
+ *    value should be placed as the first element of the \p value
+ *    string vector.
+ * \member get_bool_graph_attr Query a boolean graph attribute. The 
+ *    value should be placed as the first element of the \p value
+ *    boolean vector.
+ * \member get_numeric_vertex_attr Query a numeric vertex attribute,
+ *    for the vertices included in \p vs.
+ * \member get_string_vertex_attr Query a string vertex attribute, 
+ *    for the vertices included in \p vs.
+ * \member get_bool_vertex_attr Query a boolean vertex attribute, 
+ *    for the vertices included in \p vs.
+ * \member get_numeric_edge_attr Query a numeric edge attribute, for
+ *    the edges included in \p es.
+ * \member get_string_edge_attr Query a string edge attribute, for the 
+ *    edges included in \p es.
+ * \member get_bool_edge_attr Query a boolean edge attribute, for the 
+ *    edges included in \p es.
+ *
+ * Note that the <function>get_*_*_attr</function> are allowed to
+ * convert the attributes to numeric or string. E.g. if a vertex attribute
+ * is a GNU R complex data type, then
+ * <function>get_string_vertex_attribute</function> may serialize it
+ * into a string, but this probably makes sense only if
+ * <function>add_vertices</function> is able to deserialize it.
+ */
+
+typedef struct igraph_attribute_table_t {
+  int (*init)(igraph_t *graph, igraph_vector_ptr_t *attr);
+  void (*destroy)(igraph_t *graph);
+  int (*copy)(igraph_t *to, const igraph_t *from, igraph_bool_t ga,
+	      igraph_bool_t va, igraph_bool_t ea);
+  int (*add_vertices)(igraph_t *graph, long int nv, igraph_vector_ptr_t *attr);
+  int (*permute_vertices)(const igraph_t *graph, 
+			  igraph_t *newgraph,
+			  const igraph_vector_t *idx);
+  int (*combine_vertices)(const igraph_t *graph,
+			  igraph_t *newgraph,
+			  const igraph_vector_ptr_t *merges,
+			  const igraph_attribute_combination_t *comb);
+  int (*add_edges)(igraph_t *graph, const igraph_vector_t *edges, 
+		   igraph_vector_ptr_t *attr);
+  int (*permute_edges)(const igraph_t *graph, 
+		       igraph_t *newgraph, const igraph_vector_t *idx);
+  int (*combine_edges)(const igraph_t *graph, 
+		       igraph_t *newgraph,
+		       const igraph_vector_ptr_t *merges,
+		       const igraph_attribute_combination_t *comb);
+  int (*get_info)(const igraph_t *graph,
+		  igraph_strvector_t *gnames, igraph_vector_t *gtypes,
+		  igraph_strvector_t *vnames, igraph_vector_t *vtypes,
+		  igraph_strvector_t *enames, igraph_vector_t *etypes);
+  igraph_bool_t (*has_attr)(const igraph_t *graph, igraph_attribute_elemtype_t type,
+			    const char *name);
+  int (*gettype)(const igraph_t *graph, igraph_attribute_type_t *type,
+		 igraph_attribute_elemtype_t elemtype, const char *name);
+  int (*get_numeric_graph_attr)(const igraph_t *graph, const char *name,
+				igraph_vector_t *value);
+  int (*get_string_graph_attr)(const igraph_t *graph, const char *name,
+			       igraph_strvector_t *value);
+  int (*get_bool_graph_attr)(const igraph_t *igraph, const char *name, 
+			     igraph_vector_bool_t *value);
+  int (*get_numeric_vertex_attr)(const igraph_t *graph, const char *name,
+				 igraph_vs_t vs,
+				 igraph_vector_t *value);
+  int (*get_string_vertex_attr)(const igraph_t *graph, const char *name,
+				igraph_vs_t vs,
+				igraph_strvector_t *value);
+  int (*get_bool_vertex_attr)(const igraph_t *graph, const char *name,
+			      igraph_vs_t vs,
+			      igraph_vector_bool_t *value);
+  int (*get_numeric_edge_attr)(const igraph_t *graph, const char *name,
+			       igraph_es_t es,
+			       igraph_vector_t *value);
+  int (*get_string_edge_attr)(const igraph_t *graph, const char *name,
+			      igraph_es_t es,
+			      igraph_strvector_t *value);
+  int (*get_bool_edge_attr)(const igraph_t *graph, const char *name,
+			    igraph_es_t es,
+			    igraph_vector_bool_t *value);
+} igraph_attribute_table_t;
+
+igraph_attribute_table_t *
+igraph_i_set_attribute_table(const igraph_attribute_table_t * table);
+
+igraph_bool_t igraph_has_attribute_table(void);
+
+#define IGRAPH_I_ATTRIBUTE_DESTROY(graph) \
+        do {if ((graph)->attr) igraph_i_attribute_destroy(graph);} while(0)
+#define IGRAPH_I_ATTRIBUTE_COPY(to,from,ga,va,ea) do { \
+        int igraph_i_ret2=0; \
+        if ((from)->attr) { \
+          IGRAPH_CHECK(igraph_i_ret2=igraph_i_attribute_copy((to),(from),(ga),(va),(ea))); \
+        } else { \
+	  (to)->attr = 0; \
+	} \
+        if (igraph_i_ret2 != 0) { \
+          IGRAPH_ERROR("", igraph_i_ret2); \
+        } \
+   } while(0)        
+
+int igraph_i_attribute_init(igraph_t *graph, void *attr);
+void igraph_i_attribute_destroy(igraph_t *graph);
+int igraph_i_attribute_copy(igraph_t *to, const igraph_t *from, 
+			    igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea);
+int igraph_i_attribute_add_vertices(igraph_t *graph, long int nv, void *attr);
+int igraph_i_attribute_permute_vertices(const igraph_t *graph,
+					igraph_t *newgraph,
+					const igraph_vector_t *idx);
+int igraph_i_attribute_combine_vertices(const igraph_t *graph,
+			igraph_t *newgraph,
+			const igraph_vector_ptr_t *merges,
+			const igraph_attribute_combination_t *comb);
+int igraph_i_attribute_add_edges(igraph_t *graph, 
+				 const igraph_vector_t *edges, void *attr);
+int igraph_i_attribute_permute_edges(const igraph_t *graph,
+				     igraph_t *newgraph,
+				     const igraph_vector_t *idx);
+int igraph_i_attribute_combine_edges(const igraph_t *graph,
+			igraph_t *newgraph,
+		        const igraph_vector_ptr_t *merges,
+			const igraph_attribute_combination_t *comb);
+
+int igraph_i_attribute_get_info(const igraph_t *graph,
+				igraph_strvector_t *gnames, 
+				igraph_vector_t *gtypes,
+				igraph_strvector_t *vnames,
+				igraph_vector_t *vtypes,
+				igraph_strvector_t *enames,
+				igraph_vector_t *etypes);
+igraph_bool_t igraph_i_attribute_has_attr(const igraph_t *graph, 
+					  igraph_attribute_elemtype_t type,
+					  const char *name);
+int igraph_i_attribute_gettype(const igraph_t *graph,
+			       igraph_attribute_type_t *type,
+			       igraph_attribute_elemtype_t elemtype,
+			       const char *name);
+
+int igraph_i_attribute_get_numeric_graph_attr(const igraph_t *graph,
+					      const char *name,
+					      igraph_vector_t *value);
+int igraph_i_attribute_get_numeric_vertex_attr(const igraph_t *graph, 
+					       const char *name,
+					       igraph_vs_t vs,
+					       igraph_vector_t *value);
+int igraph_i_attribute_get_numeric_edge_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_es_t es,
+					     igraph_vector_t *value);
+int igraph_i_attribute_get_string_graph_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_strvector_t *value);
+int igraph_i_attribute_get_string_vertex_attr(const igraph_t *graph, 
+					      const char *name,
+					      igraph_vs_t vs,
+					      igraph_strvector_t *value);
+int igraph_i_attribute_get_string_edge_attr(const igraph_t *graph,
+					    const char *name,
+					    igraph_es_t es,
+					    igraph_strvector_t *value);
+int igraph_i_attribute_get_bool_graph_attr(const igraph_t *graph,
+					   const char *name,
+					   igraph_vector_bool_t *value);
+int igraph_i_attribute_get_bool_vertex_attr(const igraph_t *graph, 
+					    const char *name,
+					    igraph_vs_t vs,
+					    igraph_vector_bool_t *value);
+int igraph_i_attribute_get_bool_edge_attr(const igraph_t *graph,
+					  const char *name,
+					  igraph_es_t es,
+					  igraph_vector_bool_t *value);
+
+/* Experimental attribute handler in C */
+
+extern const igraph_attribute_table_t igraph_cattribute_table;
+
+igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name);
+igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name);
+const char* igraph_cattribute_GAS(const igraph_t *graph, const char *name);
+igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name,
+				      igraph_integer_t vid);
+igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name,
+				    igraph_integer_t vid);
+const char* igraph_cattribute_VAS(const igraph_t *graph, const char *name,
+				    igraph_integer_t vid);
+igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name,
+				      igraph_integer_t eid);
+igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name,
+				    igraph_integer_t eid);
+const char* igraph_cattribute_EAS(const igraph_t *graph, const char *name,
+				    igraph_integer_t eid);
+
+int igraph_cattribute_VANV(const igraph_t *graph, const char *name, 
+			   igraph_vs_t vids, igraph_vector_t *result);
+int igraph_cattribute_EANV(const igraph_t *graph, const char *name,
+			   igraph_es_t eids, igraph_vector_t *result);
+int igraph_cattribute_VASV(const igraph_t *graph, const char *name, 
+			   igraph_vs_t vids, igraph_strvector_t *result);
+int igraph_cattribute_EASV(const igraph_t *graph, const char *name,
+			   igraph_es_t eids, igraph_strvector_t *result);
+int igraph_cattribute_VABV(const igraph_t *graph, const char *name, 
+			   igraph_vs_t vids, igraph_vector_bool_t *result);
+int igraph_cattribute_EABV(const igraph_t *graph, const char *name,
+			   igraph_es_t eids, igraph_vector_bool_t *result);
+
+int igraph_cattribute_list(const igraph_t *graph,
+			   igraph_strvector_t *gnames, igraph_vector_t *gtypes,
+			   igraph_strvector_t *vnames, igraph_vector_t *vtypes,
+			   igraph_strvector_t *enames, igraph_vector_t *etypes);
+igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph,
+					 igraph_attribute_elemtype_t type,
+					 const char *name);
+
+int igraph_cattribute_GAN_set(igraph_t *graph, const char *name, 
+			      igraph_real_t value);
+int igraph_cattribute_GAB_set(igraph_t *graph, const char *name, 
+			      igraph_bool_t value);
+int igraph_cattribute_GAS_set(igraph_t *graph, const char *name, 
+			      const char *value);
+int igraph_cattribute_VAN_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t vid, igraph_real_t value);
+int igraph_cattribute_VAB_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t vid, igraph_bool_t value);
+int igraph_cattribute_VAS_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t vid, const char *value);
+int igraph_cattribute_EAN_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t eid, igraph_real_t value);
+int igraph_cattribute_EAB_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t eid, igraph_bool_t value);
+int igraph_cattribute_EAS_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t eid, const char *value);
+
+int igraph_cattribute_VAN_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_t *v);
+int igraph_cattribute_VAB_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_bool_t *v);
+int igraph_cattribute_VAS_setv(igraph_t *graph, const char *name,
+			       const igraph_strvector_t *sv);
+int igraph_cattribute_EAN_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_t *v);
+int igraph_cattribute_EAB_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_bool_t *v);
+int igraph_cattribute_EAS_setv(igraph_t *graph, const char *name,
+			       const igraph_strvector_t *sv);
+
+void igraph_cattribute_remove_g(igraph_t *graph, const char *name);
+void igraph_cattribute_remove_v(igraph_t *graph, const char *name);
+void igraph_cattribute_remove_e(igraph_t *graph, const char *name);
+void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g,
+				  igraph_bool_t v, igraph_bool_t e);
+
+/**
+ * \define GAN
+ * Query a numeric graph attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_GAN().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \return The value of the attribute.
+ */
+#define GAN(graph,n) (igraph_cattribute_GAN((graph), (n)))
+/**
+ * \define GAB
+ * Query a boolean graph attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_GAB().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \return The value of the attribute.
+ */
+#define GAB(graph,n) (igraph_cattribute_GAB((graph), (n)))
+/**
+ * \define GAS
+ * Query a string graph attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_GAS().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \return The value of the attribute.
+ */
+#define GAS(graph,n) (igraph_cattribute_GAS((graph), (n)))
+/**
+ * \define VAN
+ * Query a numeric vertex attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_VAN().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v The id of the vertex.
+ * \return The value of the attribute.
+ */
+#define VAN(graph,n,v) (igraph_cattribute_VAN((graph), (n), (v)))
+/**
+ * \define VAB
+ * Query a boolean vertex attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_VAB().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v The id of the vertex.
+ * \return The value of the attribute.
+ */
+#define VAB(graph,n,v) (igraph_cattribute_VAB((graph), (n), (v)))
+/**
+ * \define VAS
+ * Query a string vertex attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_VAS().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v The id of the vertex.
+ * \return The value of the attribute.
+ */
+#define VAS(graph,n,v) (igraph_cattribute_VAS((graph), (n), (v)))
+/**
+ * \define VANV
+ * Query a numeric vertex attribute for all vertices.
+ *
+ * This is a shorthand for \ref igraph_cattribute_VANV().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vec Pointer to an initialized vector, the result is
+ *        stored here. It will be resized, if needed.
+ * \return Error code.
+ */
+#define VANV(graph,n,vec) (igraph_cattribute_VANV((graph),(n), \
+						  igraph_vss_all(), (vec)))
+/**
+ * \define VABV
+ * Query a boolean vertex attribute for all vertices.
+ *
+ * This is a shorthand for \ref igraph_cattribute_VABV().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vec Pointer to an initialized boolean vector, the result is
+ *        stored here. It will be resized, if needed.
+ * \return Error code.
+ */
+#define VABV(graph,n,vec) (igraph_cattribute_VABV((graph),(n), \
+						  igraph_vss_all(), (vec)))
+/**
+ * \define VASV
+ * Query a string vertex attribute for all vertices.
+ *
+ * This is a shorthand for \ref igraph_cattribute_VASV().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vec Pointer to an initialized string vector, the result is
+ *        stored here. It will be resized, if needed.
+ * \return Error code.
+ */
+#define VASV(graph,n,vec) (igraph_cattribute_VASV((graph),(n), \
+						  igraph_vss_all(), (vec)))
+/**
+ * \define EAN
+ * Query a numeric edge attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_EAN().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param e The id of the edge.
+ * \return The value of the attribute.
+ */
+#define EAN(graph,n,e) (igraph_cattribute_EAN((graph), (n), (e)))
+/**
+ * \define EAB
+ * Query a boolean edge attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_EAB().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param e The id of the edge.
+ * \return The value of the attribute.
+ */
+#define EAB(graph,n,e) (igraph_cattribute_EAB((graph), (n), (e)))
+/**
+ * \define EAS
+ * Query a string edge attribute.
+ * 
+ * This is shorthand for \ref igraph_cattribute_EAS().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param e The id of the edge.
+ * \return The value of the attribute.
+ */
+#define EAS(graph,n,e) (igraph_cattribute_EAS((graph), (n), (e)))
+/**
+ * \define EANV
+ * Query a numeric edge attribute for all edges.
+ *
+ * This is a shorthand for \ref igraph_cattribute_EANV().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vec Pointer to an initialized vector, the result is
+ *        stored here. It will be resized, if needed.
+ * \return Error code.
+ */
+#define EANV(graph,n,vec) (igraph_cattribute_EANV((graph),(n), \
+						  igraph_ess_all(IGRAPH_EDGEORDER_ID), (vec)))
+/**
+ * \define EABV
+ * Query a boolean edge attribute for all edges.
+ *
+ * This is a shorthand for \ref igraph_cattribute_EABV().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vec Pointer to an initialized vector, the result is
+ *        stored here. It will be resized, if needed.
+ * \return Error code.
+ */
+#define EABV(graph,n,vec) (igraph_cattribute_EABV((graph),(n), \
+						  igraph_ess_all(IGRAPH_EDGEORDER_ID), (vec)))
+
+/**
+ * \define EASV
+ * Query a string edge attribute for all edges.
+ *
+ * This is a shorthand for \ref igraph_cattribute_EASV().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vec Pointer to an initialized string vector, the result is
+ *        stored here. It will be resized, if needed.
+ * \return Error code.
+ */
+#define EASV(graph,n,vec) (igraph_cattribute_EASV((graph),(n), \
+						  igraph_ess_all(IGRAPH_EDGEORDER_ID), (vec)))
+/**
+ * \define SETGAN
+ * Set a numeric graph attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_GAN_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETGAN(graph,n,value) (igraph_cattribute_GAN_set((graph),(n),(value)))
+/**
+ * \define SETGAB
+ * Set a boolean graph attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_GAB_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETGAB(graph,n,value) (igraph_cattribute_GAB_set((graph),(n),(value)))
+/**
+ * \define SETGAS
+ * Set a string graph attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_GAS_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETGAS(graph,n,value) (igraph_cattribute_GAS_set((graph),(n),(value)))
+/**
+ * \define SETVAN
+ * Set a numeric vertex attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_VAN_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vid Ids of the vertices to set.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETVAN(graph,n,vid,value) (igraph_cattribute_VAN_set((graph),(n),(vid),(value)))
+/**
+ * \define SETVAB
+ * Set a boolean vertex attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_VAB_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vid Ids of the vertices to set.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETVAB(graph,n,vid,value) (igraph_cattribute_VAB_set((graph),(n),(vid),(value)))
+/**
+ * \define SETVAS
+ * Set a string vertex attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_VAS_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param vid Ids of the vertices to set.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETVAS(graph,n,vid,value) (igraph_cattribute_VAS_set((graph),(n),(vid),(value)))
+/**
+ * \define SETEAN
+ * Set a numeric edge attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_EAN_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param eid Ids of the edges to set.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETEAN(graph,n,eid,value) (igraph_cattribute_EAN_set((graph),(n),(eid),(value)))
+/**
+ * \define SETEAB
+ * Set a boolean edge attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_EAB_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param eid Ids of the edges to set.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETEAB(graph,n,eid,value) (igraph_cattribute_EAB_set((graph),(n),(eid),(value)))
+/**
+ * \define SETEAS
+ * Set a string edge attribute
+ * 
+ * This is a shorthand for \ref igraph_cattribute_EAS_set().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param eid Ids of the edges to set.
+ * \param value The new value of the attribute.
+ * \return Error code.
+ */
+#define SETEAS(graph,n,eid,value) (igraph_cattribute_EAS_set((graph),(n),(eid),(value)))
+
+/**
+ * \define SETVANV
+ *  Set a numeric vertex attribute for all vertices
+ * 
+ * This is a shorthand for \ref igraph_cattribute_VAN_setv().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v Vector containing the new values of the attributes.
+ * \return Error code.
+ */
+#define SETVANV(graph,n,v) (igraph_cattribute_VAN_setv((graph),(n),(v)))
+/**
+ * \define SETVABV
+ *  Set a boolean vertex attribute for all vertices
+ * 
+ * This is a shorthand for \ref igraph_cattribute_VAB_setv().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v Vector containing the new values of the attributes.
+ * \return Error code.
+ */
+#define SETVABV(graph,n,v) (igraph_cattribute_VAB_setv((graph),(n),(v)))
+/**
+ * \define SETVASV
+ *  Set a string vertex attribute for all vertices
+ * 
+ * This is a shorthand for \ref igraph_cattribute_VAS_setv().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v Vector containing the new values of the attributes.
+ * \return Error code.
+ */
+#define SETVASV(graph,n,v) (igraph_cattribute_VAS_setv((graph),(n),(v)))
+/**
+ * \define SETEANV
+ *  Set a numeric edge attribute for all vertices
+ * 
+ * This is a shorthand for \ref igraph_cattribute_EAN_setv().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v Vector containing the new values of the attributes.
+ */
+#define SETEANV(graph,n,v) (igraph_cattribute_EAN_setv((graph),(n),(v)))
+/**
+ * \define SETEABV
+ *  Set a boolean edge attribute for all vertices
+ * 
+ * This is a shorthand for \ref igraph_cattribute_EAB_setv().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v Vector containing the new values of the attributes.
+ */
+#define SETEABV(graph,n,v) (igraph_cattribute_EAB_setv((graph),(n),(v)))
+/**
+ * \define SETEASV
+ *  Set a string edge attribute for all vertices
+ * 
+ * This is a shorthand for \ref igraph_cattribute_EAS_setv().
+ * \param graph The graph.
+ * \param n The name of the attribute.
+ * \param v Vector containing the new values of the attributes.
+ */
+#define SETEASV(graph,n,v) (igraph_cattribute_EAS_setv((graph),(n),(v)))
+
+/**
+ * \define DELGA
+ * Remove a graph attribute.
+ * 
+ * A shorthand for \ref igraph_cattribute_remove_g().
+ * \param graph The graph.
+ * \param n The name of the attribute to remove.
+ */
+#define DELGA(graph,n) (igraph_cattribute_remove_g((graph),(n)))
+/**
+ * \define DELVA
+ * Remove a vertex attribute.
+ * 
+ * A shorthand for \ref igraph_cattribute_remove_v().
+ * \param graph The graph.
+ * \param n The name of the attribute to remove.
+ */
+#define DELVA(graph,n) (igraph_cattribute_remove_v((graph),(n)))
+/**
+ * \define DELEA
+ * Remove an edge attribute.
+ * 
+ * A shorthand for \ref igraph_cattribute_remove_e().
+ * \param graph The graph.
+ * \param n The name of the attribute to remove.
+ */
+#define DELEA(graph,n) (igraph_cattribute_remove_e((graph),(n)))
+/**
+ * \define DELGAS
+ * Remove all graph attributes.
+ * 
+ * Calls \ref igraph_cattribute_remove_all(). 
+ * \param graph The graph.
+ */
+#define DELGAS(graph) (igraph_cattribute_remove_all((graph),1,0,0))
+/**
+ * \define DELVAS
+ * Remove all vertex attributes.
+ * 
+ * Calls \ref igraph_cattribute_remove_all(). 
+ * \param graph The graph.
+ */
+#define DELVAS(graph) (igraph_cattribute_remove_all((graph),0,1,0))
+/**
+ * \define DELEAS
+ * Remove all edge attributes.
+ * 
+ * Calls \ref igraph_cattribute_remove_all(). 
+ * \param graph The graph.
+ */
+#define DELEAS(graph) (igraph_cattribute_remove_all((graph),0,0,1))
+/**
+ * \define DELALL
+ * Remove all attributes.
+ * 
+ * All graph, vertex and edges attributes will be removed.
+ * Calls \ref igraph_cattribute_remove_all(). 
+ * \param graph The graph.
+ */
+#define DELALL(graph) (igraph_cattribute_remove_all((graph),1,1,1))
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_bipartite.h b/include/igraph_bipartite.h
new file mode 100644
index 0000000..69c2d48
--- /dev/null
+++ b/include/igraph_bipartite.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_BIPARTITE_H
+#define IGRAPH_BIPARTITE_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_matrix.h"
+#include "igraph_datatype.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Bipartite networks                                 */
+/* -------------------------------------------------- */
+
+int igraph_full_bipartite(igraph_t *graph, 
+			  igraph_vector_bool_t *types,
+			  igraph_integer_t n1, igraph_integer_t n2,
+			  igraph_bool_t directed, 
+			  igraph_neimode_t mode);
+
+int igraph_create_bipartite(igraph_t *g, const igraph_vector_bool_t *types,
+			    const igraph_vector_t *edges, 
+			    igraph_bool_t directed);
+
+int igraph_bipartite_projection_size(const igraph_t *graph,
+				     const igraph_vector_bool_t *types,
+				     igraph_integer_t *vcount1,
+				     igraph_integer_t *ecount1,
+				     igraph_integer_t *vcount2,
+				     igraph_integer_t *ecount2);
+
+int igraph_bipartite_projection(const igraph_t *graph, 
+				const igraph_vector_bool_t *types,
+				igraph_t *proj1,
+				igraph_t *proj2,
+				igraph_vector_t *multiplicity1,
+				igraph_vector_t *multiplicity2,
+				igraph_integer_t probe1);
+
+int igraph_incidence(igraph_t *graph, igraph_vector_bool_t *types,
+		     const igraph_matrix_t *incidence,  igraph_bool_t directed,
+		     igraph_neimode_t mode, igraph_bool_t multiple);
+
+int igraph_get_incidence(const igraph_t *graph,
+			 const igraph_vector_bool_t *types,
+			 igraph_matrix_t *res,
+			 igraph_vector_t *row_ids,
+			 igraph_vector_t *col_ids);
+
+int igraph_is_bipartite(const igraph_t *graph,
+			igraph_bool_t *res,
+			igraph_vector_bool_t *type);
+
+int igraph_bipartite_game(igraph_t *graph, igraph_vector_bool_t *types, 
+			  igraph_erdos_renyi_t type, 
+			  igraph_integer_t n1, igraph_integer_t n2, 
+			  igraph_real_t p, igraph_integer_t m, 
+			  igraph_bool_t directed, igraph_neimode_t mode);
+
+int igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t *types,
+			      igraph_integer_t n1, igraph_integer_t n2,
+			      igraph_real_t p, igraph_bool_t directed,
+			      igraph_neimode_t mode);
+
+int igraph_bipartite_game_gnm(igraph_t *graph, igraph_vector_bool_t *types,
+			      igraph_integer_t n1, igraph_integer_t n2,
+			      igraph_integer_t m, igraph_bool_t directed,
+			      igraph_neimode_t mode);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_blas.h b/include/igraph_blas.h
new file mode 100644
index 0000000..7742720
--- /dev/null
+++ b/include/igraph_blas.h
@@ -0,0 +1,72 @@
+/* -*- 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/include/igraph_centrality.h b/include/igraph_centrality.h
new file mode 100644
index 0000000..bd2d88b
--- /dev/null
+++ b/include/igraph_centrality.h
@@ -0,0 +1,221 @@
+/* -*- 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_CENTRALITY_H
+#define IGRAPH_CENTRALITY_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_iterators.h"
+#include "igraph_arpack.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Centrality                                         */
+/* -------------------------------------------------- */
+
+int igraph_closeness(const igraph_t *graph, igraph_vector_t *res, 
+		     const igraph_vs_t vids, igraph_neimode_t mode,
+		     const igraph_vector_t *weights, igraph_bool_t normalized);
+int igraph_closeness_estimate(const igraph_t *graph, igraph_vector_t *res, 
+		              const igraph_vs_t vids, igraph_neimode_t mode,
+                              igraph_real_t cutoff,
+			      const igraph_vector_t *weights,
+			      igraph_bool_t normalized);
+
+int igraph_betweenness(const igraph_t *graph, igraph_vector_t *res, 
+                       const igraph_vs_t vids, igraph_bool_t directed,
+		       const igraph_vector_t *weights, igraph_bool_t nobigint);
+int igraph_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res, 
+			        const igraph_vs_t vids, igraph_bool_t directed,
+                                igraph_real_t cutoff, 
+				const igraph_vector_t *weights, 
+				igraph_bool_t nobigint);
+int igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *result,
+                            igraph_bool_t directed, 
+			    const igraph_vector_t *weigths);
+int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *result,
+				     igraph_bool_t directed, igraph_real_t cutoff,
+				     const igraph_vector_t *weights);
+int igraph_pagerank_old(const igraph_t *graph, igraph_vector_t *res, 
+			const igraph_vs_t vids, igraph_bool_t directed,
+			igraph_integer_t niter, igraph_real_t eps, 
+			igraph_real_t damping, igraph_bool_t old);
+
+/**
+ * \typedef igraph_pagerank_algo_t
+ * \brief PageRank algorithm implementation
+ *
+ * Algorithms to calculate PageRank.
+ * \enumval IGRAPH_PAGERANK_ALGO_POWER Use a simple power iteration,
+ *   as it was implemented before igraph version 0.5.
+ * \enumval IGRAPH_PAGERANK_ALGO_ARPACK Use the ARPACK library, this
+ *   was the PageRank implementation in igraph from version 0.5, until
+ *   version 0.7.
+ * \enumval IGRAPH_PAGERANK_ALGO_PRPACK Use the PRPACK
+ *   library. Currently this implementation is recommended.
+ */
+
+typedef enum {
+  IGRAPH_PAGERANK_ALGO_POWER=0,
+  IGRAPH_PAGERANK_ALGO_ARPACK=1,
+  IGRAPH_PAGERANK_ALGO_PRPACK=2
+} igraph_pagerank_algo_t;
+
+/**
+ * \struct igraph_pagerank_power_options_t
+ * \brief Options for the power method
+ *
+ * \member niter The number of iterations to perform, integer.
+ * \member eps  The algorithm will consider the calculation as complete
+ *        if the difference of values between iterations change
+ *        less than this value for every vertex.
+ */
+
+typedef struct igraph_pagerank_power_options_t {
+  igraph_integer_t niter;
+  igraph_real_t eps;
+} igraph_pagerank_power_options_t;
+
+int igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t algo,
+		    igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    const igraph_vector_t *weights, void *options);
+int igraph_personalized_pagerank(const igraph_t *graph, 
+		    igraph_pagerank_algo_t algo, igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    igraph_vector_t *reset,
+		    const igraph_vector_t *weights, void *options);
+int igraph_personalized_pagerank_vs(const igraph_t *graph, 
+		    igraph_pagerank_algo_t algo,
+		    igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping,
+			igraph_vs_t reset_vids,
+		    const igraph_vector_t *weights, void *options);
+
+int igraph_eigenvector_centrality(const igraph_t *graph, igraph_vector_t *vector,
+				  igraph_real_t *value,
+				  igraph_bool_t directed, igraph_bool_t scale,
+				  const igraph_vector_t *weights,
+				  igraph_arpack_options_t *options);
+
+int igraph_hub_score(const igraph_t *graph, igraph_vector_t *vector,
+		     igraph_real_t *value, igraph_bool_t scale,
+		     const igraph_vector_t *weights,
+		     igraph_arpack_options_t *options);
+int igraph_authority_score(const igraph_t *graph, igraph_vector_t *vector,
+			   igraph_real_t *value, igraph_bool_t scale,
+			   const igraph_vector_t *weights,
+			   igraph_arpack_options_t *options);
+
+int igraph_constraint(const igraph_t *graph, igraph_vector_t *res,
+		      igraph_vs_t vids, const igraph_vector_t *weights);
+
+int igraph_strength(const igraph_t *graph, igraph_vector_t *res,
+		    const igraph_vs_t vids, igraph_neimode_t mode,
+		    igraph_bool_t loops, const igraph_vector_t *weights);
+
+int igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result,
+         igraph_vector_t *ins, igraph_vector_t *outs);
+
+int igraph_sort_vertex_ids_by_degree(const igraph_t *graph, 
+				     igraph_vector_t *outvids, 
+				     igraph_vs_t vids,
+				     igraph_neimode_t mode, 
+				     igraph_bool_t loops,
+                     igraph_order_t order,
+				     igraph_bool_t only_indices);
+
+igraph_real_t igraph_centralization(const igraph_vector_t *scores,
+				    igraph_real_t theoretical_max,
+				    igraph_bool_t normalized);
+
+int igraph_centralization_degree(const igraph_t *graph, igraph_vector_t *res, 
+				 igraph_neimode_t mode, igraph_bool_t loops,
+				 igraph_real_t *centralization,
+				 igraph_real_t *theoretical_max,
+				 igraph_bool_t normalized);
+int igraph_centralization_degree_tmax(const igraph_t *graph, 
+				      igraph_integer_t nodes,
+				      igraph_neimode_t mode,
+				      igraph_bool_t loops,
+				      igraph_real_t *res);
+
+int igraph_centralization_betweenness(const igraph_t *graph, 
+				      igraph_vector_t *res,
+				      igraph_bool_t directed,
+				      igraph_bool_t nobigint,
+				      igraph_real_t *centralization,
+				      igraph_real_t *theoretical_max,
+				      igraph_bool_t normalized);
+int igraph_centralization_betweenness_tmax(const igraph_t *graph, 
+					   igraph_integer_t nodes,
+					   igraph_bool_t directed,
+					   igraph_real_t *res);
+
+int igraph_centralization_closeness(const igraph_t *graph, 
+				    igraph_vector_t *res, 
+				    igraph_neimode_t mode, 
+				    igraph_real_t *centralization,
+				    igraph_real_t *theoretical_max,
+				    igraph_bool_t normalized);
+int igraph_centralization_closeness_tmax(const igraph_t *graph,
+					 igraph_integer_t nodes,
+					 igraph_neimode_t mode,
+					 igraph_real_t *res);
+
+int igraph_centralization_eigenvector_centrality(
+					 const igraph_t *graph,
+					 igraph_vector_t *vector,
+					 igraph_real_t *value,
+					 igraph_bool_t directed,
+					 igraph_bool_t scale,
+					 igraph_arpack_options_t *options,
+					 igraph_real_t *centralization,
+					 igraph_real_t *theoretical_max,
+					 igraph_bool_t normalized);
+int igraph_centralization_eigenvector_centrality_tmax(
+					 const igraph_t *graph,
+					 igraph_integer_t nodes,
+					 igraph_bool_t directed,
+					 igraph_bool_t scale, 
+					 igraph_real_t *res);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_cliques.h b/include/igraph_cliques.h
new file mode 100644
index 0000000..eaffc7e
--- /dev/null
+++ b/include/igraph_cliques.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_CLIQUES_H
+#define IGRAPH_CLIQUES_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_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Cliques, maximal independent vertex sets           */
+/* -------------------------------------------------- */
+
+int igraph_maximal_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
+                   igraph_integer_t min_size, igraph_integer_t max_size);
+int igraph_maximal_cliques_file(const igraph_t *graph,
+				FILE *outfile,
+				igraph_integer_t min_size, 
+				igraph_integer_t max_size);
+int igraph_maximal_cliques_count(const igraph_t *graph,
+				 igraph_integer_t *res, 
+				 igraph_integer_t min_size, 
+				 igraph_integer_t max_size);
+int igraph_maximal_cliques_subset(const igraph_t *graph,
+				  igraph_vector_int_t *subset,
+				  igraph_vector_ptr_t *res,
+				  igraph_integer_t *no,
+				  FILE *outfile,
+				  igraph_integer_t min_size,
+				  igraph_integer_t max_size);
+
+int igraph_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
+                   igraph_integer_t min_size, igraph_integer_t max_size);
+int igraph_largest_cliques(const igraph_t *graph, 
+			   igraph_vector_ptr_t *cliques);
+int igraph_clique_number(const igraph_t *graph, igraph_integer_t *no);
+int igraph_independent_vertex_sets(const igraph_t *graph,
+				   igraph_vector_ptr_t *res,
+				   igraph_integer_t min_size,
+				   igraph_integer_t max_size);
+int igraph_largest_independent_vertex_sets(const igraph_t *graph,
+					   igraph_vector_ptr_t *res);
+int igraph_maximal_independent_vertex_sets(const igraph_t *graph,
+					   igraph_vector_ptr_t *res);
+int igraph_independence_number(const igraph_t *graph, igraph_integer_t *no);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_cocitation.h b/include/igraph_cocitation.h
new file mode 100644
index 0000000..eff0867
--- /dev/null
+++ b/include/igraph_cocitation.h
@@ -0,0 +1,75 @@
+/* -*- 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_COCITATION_H
+#define IGRAPH_COCITATION_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_matrix.h"
+#include "igraph_datatype.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Cocitation and other similarity measures           */
+/* -------------------------------------------------- */
+
+int igraph_cocitation(const igraph_t *graph, igraph_matrix_t *res, 
+		      const igraph_vs_t vids);
+int igraph_bibcoupling(const igraph_t *graph, igraph_matrix_t *res, 
+		       const igraph_vs_t vids);
+
+int igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t *res,
+              const igraph_vs_t vids, igraph_neimode_t mode,
+			  igraph_bool_t loops);
+int igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops);
+int igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops);
+
+int igraph_similarity_dice(const igraph_t *graph, igraph_matrix_t *res,
+              const igraph_vs_t vids, igraph_neimode_t mode,
+			  igraph_bool_t loops);
+int igraph_similarity_dice_pairs(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops);
+int igraph_similarity_dice_es(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops);
+
+int igraph_similarity_inverse_log_weighted(const igraph_t *graph,
+              igraph_matrix_t *res, const igraph_vs_t vids,
+              igraph_neimode_t mode);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_cohesive_blocks.h b/include/igraph_cohesive_blocks.h
new file mode 100644
index 0000000..723706c
--- /dev/null
+++ b/include/igraph_cohesive_blocks.h
@@ -0,0 +1,37 @@
+/* -*- 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_COHESIVE_BLOCKS_H
+#define IGRAPH_COHESIVE_BLOCKS_H
+
+#include "igraph_datatype.h"
+#include "igraph_vector.h"
+#include "igraph_vector_ptr.h"
+
+int igraph_cohesive_blocks(const igraph_t *graph,
+			   igraph_vector_ptr_t *blocks,
+			   igraph_vector_t *cohesion,
+			   igraph_vector_t *parent,
+			   igraph_t *block_tree);
+
+#endif
diff --git a/include/igraph_community.h b/include/igraph_community.h
new file mode 100644
index 0000000..5aa9b16
--- /dev/null
+++ b/include/igraph_community.h
@@ -0,0 +1,241 @@
+/* -*- 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_COMMUNITY_H
+#define IGRAPH_COMMUNITY_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_datatype.h"
+#include "igraph_types.h"
+#include "igraph_arpack.h"
+#include "igraph_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* K-Cores                                            */
+/* -------------------------------------------------- */
+
+int igraph_coreness(const igraph_t *graph, igraph_vector_t *cores,
+		    igraph_neimode_t mode);
+
+/* -------------------------------------------------- */
+/* Community Structure                                */
+/* -------------------------------------------------- */
+
+/* TODO: cut.community */
+/* TODO: edge.type.matrix */
+/* TODO:  */
+
+int igraph_community_optimal_modularity(const igraph_t *graph,
+					igraph_real_t *modularity,
+					igraph_vector_t *membership,
+					const igraph_vector_t *weights);
+
+int igraph_community_spinglass(const igraph_t *graph,
+			       const igraph_vector_t *weights,
+			       igraph_real_t *modularity,
+			       igraph_real_t *temperature,
+			       igraph_vector_t *membership, 
+			       igraph_vector_t *csize, 
+			       igraph_integer_t spins,
+			       igraph_bool_t parupdate,
+			       igraph_real_t starttemp,
+			       igraph_real_t stoptemp,
+			       igraph_real_t coolfact,
+			       igraph_spincomm_update_t update_rule,
+			       igraph_real_t gamma, 
+			       /* the rest is for the NegSpin implementation */
+			       igraph_spinglass_implementation_t implementation,
+/* 			       igraph_matrix_t *adhesion, */
+/* 			       igraph_matrix_t *normalised_adhesion, */
+/* 			       igraph_real_t *polarization, */
+			       igraph_real_t lambda);
+
+int igraph_community_spinglass_single(const igraph_t *graph,
+				      const igraph_vector_t *weights,
+				      igraph_integer_t vertex,
+				      igraph_vector_t *community,
+				      igraph_real_t *cohesion,
+				      igraph_real_t *adhesion,
+				      igraph_integer_t *inner_links,
+				      igraph_integer_t *outer_links,
+				      igraph_integer_t spins,
+				      igraph_spincomm_update_t update_rule,
+				      igraph_real_t gamma);
+				   
+int igraph_community_walktrap(const igraph_t *graph, 
+			      const igraph_vector_t *weights,
+			      int steps,
+			      igraph_matrix_t *merges,
+			      igraph_vector_t *modularity, 
+			      igraph_vector_t *membership);
+
+int igraph_community_infomap(const igraph_t * graph,
+			     const igraph_vector_t *e_weights,
+			     const igraph_vector_t *v_weights,
+			     int nb_trials,
+			     igraph_vector_t *membership,
+			     igraph_real_t *codelength);
+
+int igraph_community_edge_betweenness(const igraph_t *graph, 
+				      igraph_vector_t *result,
+				      igraph_vector_t *edge_betweenness,
+				      igraph_matrix_t *merges,
+				      igraph_vector_t *bridges,
+				      igraph_vector_t *modularity,
+				      igraph_vector_t *membership,
+				      igraph_bool_t directed,
+				      const igraph_vector_t *weights);
+int igraph_community_eb_get_merges(const igraph_t *graph, 
+				   const igraph_vector_t *edges,
+                                   const igraph_vector_t *weights,
+				   igraph_matrix_t *merges,
+				   igraph_vector_t *bridges,
+				   igraph_vector_t *modularity,
+				   igraph_vector_t *membership);
+
+int igraph_community_fastgreedy(const igraph_t *graph,
+				const igraph_vector_t *weights,
+				igraph_matrix_t *merges,
+				igraph_vector_t *modularity, 
+				igraph_vector_t *membership);
+
+int igraph_community_to_membership(const igraph_matrix_t *merges,
+				   igraph_integer_t nodes,
+				   igraph_integer_t steps,
+				   igraph_vector_t *membership,
+				   igraph_vector_t *csize);
+int igraph_le_community_to_membership(const igraph_matrix_t *merges,
+				      igraph_integer_t steps,
+				      igraph_vector_t *membership,
+				      igraph_vector_t *csize);
+
+int igraph_modularity(const igraph_t *graph, 
+		      const igraph_vector_t *membership,
+		      igraph_real_t *modularity,
+              const igraph_vector_t *weights);
+
+int igraph_modularity_matrix(const igraph_t *graph, 
+			     const igraph_vector_t *membership,
+			     igraph_matrix_t *modmat, 
+			     const igraph_vector_t *weights);
+
+int igraph_reindex_membership(igraph_vector_t *membership,
+                              igraph_vector_t *new_to_old);
+
+typedef enum { IGRAPH_LEVC_HIST_SPLIT=1,
+	       IGRAPH_LEVC_HIST_FAILED,
+	       IGRAPH_LEVC_HIST_START_FULL,
+	       IGRAPH_LEVC_HIST_START_GIVEN
+} igraph_leading_eigenvector_community_history_t;
+
+/**
+ * \typedef igraph_community_leading_eigenvector_callback_t
+ * Callback for the leading eigenvector community finding method.
+ *
+ * The leading eigenvector community finding implementation in igraph
+ * is able to call a callback function, after each eigenvalue
+ * calculation. This callback function must be of \c
+ * igraph_community_leading_eigenvector_callback_t type.
+ * The following arguments are passed to the callback:
+ * \param membership The actual membership vector, before recording
+ *    the potential change implied by the newly found eigenvalue.
+ * \param comm The id of the community that the algorithm tried to
+ *    split in the last iteration. The community ids are indexed from
+ *    zero here!
+ * \param eigenvalue The eigenvalue the algorithm has just found.
+ * \param eigenvector The eigenvector corresponding to the eigenvalue
+ *    the algorithm just found.
+ * \param arpack_multiplier A function that was passed to \ref
+ *    igraph_arpack_rssolve() to solve the last eigenproblem.
+ * \param arpack_extra The extra argument that was passed to the
+ *    ARPACK solver.
+ * \param extra Extra argument that as passed to \ref
+ *    igraph_community_leading_eigenvector().
+ *
+ * \sa \ref igraph_community_leading_eigenvector(), \ref
+ * igraph_arpack_function_t, \ref igraph_arpack_rssolve().
+ */
+
+typedef int igraph_community_leading_eigenvector_callback_t(
+	const igraph_vector_t *membership,
+	long int comm, 
+	igraph_real_t eigenvalue,
+	const igraph_vector_t *eigenvector,
+	igraph_arpack_function_t *arpack_multiplier,
+        void *arpack_extra,
+        void *extra);
+
+int igraph_community_leading_eigenvector(const igraph_t *graph,
+	const igraph_vector_t *weights,
+	igraph_matrix_t *merges,
+	igraph_vector_t *membership,
+	igraph_integer_t steps,
+	igraph_arpack_options_t *options, 
+	igraph_real_t *modularity,
+	igraph_bool_t start,
+	igraph_vector_t *eigenvalues,
+	igraph_vector_ptr_t *eigenvectors,
+        igraph_vector_t *history, 
+        igraph_community_leading_eigenvector_callback_t *callback,
+        void *callback_extra);
+
+int igraph_community_label_propagation(const igraph_t *graph,
+                                       igraph_vector_t *membership,
+                                       const igraph_vector_t *weights,
+                                       const igraph_vector_t *initial,
+                                       igraph_vector_bool_t *fixed,
+				       igraph_real_t *modularity);
+int igraph_community_multilevel(const igraph_t *graph,
+                                const igraph_vector_t *weights,
+                                igraph_vector_t *membership,
+                                igraph_matrix_t *memberships,
+                                igraph_vector_t *modularity);
+
+/* -------------------------------------------------- */
+/* Community Structure Comparison                     */
+/* -------------------------------------------------- */
+
+int igraph_compare_communities(const igraph_vector_t *comm1,
+	                       const igraph_vector_t *comm2,
+			       igraph_real_t* result,
+			       igraph_community_comparison_t method);
+int igraph_split_join_distance(const igraph_vector_t *comm1,
+        const igraph_vector_t *comm2,
+        igraph_integer_t* distance12,
+        igraph_integer_t* distance21);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_complex.h b/include/igraph_complex.h
new file mode 100644
index 0000000..9821038
--- /dev/null
+++ b/include/igraph_complex.h
@@ -0,0 +1,111 @@
+/* -*- 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_COMPLEX_H
+#define IGRAPH_COMPLEX_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
+
+typedef struct igraph_complex_t { igraph_real_t dat[2]; } igraph_complex_t;
+
+#define IGRAPH_REAL(x) ((x).dat[0])
+#define IGRAPH_IMAG(x) ((x).dat[1])
+#define IGRAPH_COMPLEX_EQ(x,y) ((x).dat[0]==(y).dat[0] && (x).dat[1]==(y).dat[1])
+
+igraph_complex_t igraph_complex(igraph_real_t x, igraph_real_t y);
+igraph_complex_t igraph_complex_polar(igraph_real_t r, igraph_real_t theta);
+
+igraph_bool_t igraph_complex_eq_tol(igraph_complex_t z1,
+				    igraph_complex_t z2, 
+				    igraph_real_t tol);
+
+igraph_real_t igraph_complex_mod(igraph_complex_t z);
+igraph_real_t igraph_complex_arg(igraph_complex_t z);
+
+igraph_real_t igraph_complex_abs(igraph_complex_t z);
+igraph_real_t igraph_complex_logabs(igraph_complex_t z);
+
+igraph_complex_t igraph_complex_add(igraph_complex_t z1, 
+				    igraph_complex_t z2);
+igraph_complex_t igraph_complex_sub(igraph_complex_t z1, 
+				    igraph_complex_t z2);
+igraph_complex_t igraph_complex_mul(igraph_complex_t z1, 
+				    igraph_complex_t z2);
+igraph_complex_t igraph_complex_div(igraph_complex_t z1, 
+				    igraph_complex_t z2);
+
+igraph_complex_t igraph_complex_add_real(igraph_complex_t z, 
+					 igraph_real_t x);
+igraph_complex_t igraph_complex_add_imag(igraph_complex_t z, 
+					 igraph_real_t y);
+igraph_complex_t igraph_complex_sub_real(igraph_complex_t z, 
+					 igraph_real_t x);
+igraph_complex_t igraph_complex_sub_imag(igraph_complex_t z, 
+					 igraph_real_t y);
+igraph_complex_t igraph_complex_mul_real(igraph_complex_t z, 
+					 igraph_real_t x);
+igraph_complex_t igraph_complex_mul_imag(igraph_complex_t z, 
+					 igraph_real_t y);
+igraph_complex_t igraph_complex_div_real(igraph_complex_t z, 
+					 igraph_real_t x);
+igraph_complex_t igraph_complex_div_imag(igraph_complex_t z, 
+					 igraph_real_t y);
+
+igraph_complex_t igraph_complex_conj(igraph_complex_t z);
+igraph_complex_t igraph_complex_neg(igraph_complex_t z);
+igraph_complex_t igraph_complex_inv(igraph_complex_t z);
+
+igraph_complex_t igraph_complex_sqrt(igraph_complex_t z);
+igraph_complex_t igraph_complex_sqrt_real(igraph_real_t x);
+igraph_complex_t igraph_complex_exp(igraph_complex_t z);
+igraph_complex_t igraph_complex_pow(igraph_complex_t z1,
+				    igraph_complex_t z2);
+igraph_complex_t igraph_complex_pow_real(igraph_complex_t z, 
+					 igraph_real_t x);
+igraph_complex_t igraph_complex_log(igraph_complex_t z);
+igraph_complex_t igraph_complex_log10(igraph_complex_t z);
+igraph_complex_t igraph_complex_log_b(igraph_complex_t z, 
+				      igraph_complex_t b);
+
+igraph_complex_t igraph_complex_sin(igraph_complex_t z);
+igraph_complex_t igraph_complex_cos(igraph_complex_t z);
+igraph_complex_t igraph_complex_tan(igraph_complex_t z);
+igraph_complex_t igraph_complex_sec(igraph_complex_t z);
+igraph_complex_t igraph_complex_csc(igraph_complex_t z);
+igraph_complex_t igraph_complex_cot(igraph_complex_t z);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_components.h b/include/igraph_components.h
new file mode 100644
index 0000000..b243be9
--- /dev/null
+++ b/include/igraph_components.h
@@ -0,0 +1,69 @@
+/* -*- 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_COMPONENTS_H
+#define IGRAPH_COMPONENTS_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_datatype.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Components                                         */
+/* -------------------------------------------------- */
+
+int igraph_clusters(const igraph_t *graph, igraph_vector_t *membership, 
+		    igraph_vector_t *csize, igraph_integer_t *no,
+		    igraph_connectedness_t mode);
+int igraph_is_connected(const igraph_t *graph, igraph_bool_t *res, 
+			igraph_connectedness_t mode);
+void igraph_decompose_destroy(igraph_vector_ptr_t *complist);
+int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components, 
+		     igraph_connectedness_t mode, 
+		     long int maxcompno, long int minelements);
+int igraph_articulation_points(const igraph_t *graph,
+			       igraph_vector_t *res);
+int igraph_biconnected_components(const igraph_t *graph,
+				  igraph_integer_t *no,
+				  igraph_vector_ptr_t *tree_edges,
+				  igraph_vector_ptr_t *component_edges,
+				  igraph_vector_ptr_t *components,
+				  igraph_vector_t *articulation_points);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_constants.h b/include/igraph_constants.h
new file mode 100644
index 0000000..8c1694b
--- /dev/null
+++ b/include/igraph_constants.h
@@ -0,0 +1,159 @@
+/* -*- 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/include/igraph_constructors.h b/include/igraph_constructors.h
new file mode 100644
index 0000000..e2572c1
--- /dev/null
+++ b/include/igraph_constructors.h
@@ -0,0 +1,85 @@
+/* -*- 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_CONSTRUCTORS_H
+#define IGRAPH_CONSTRUCTORS_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_datatype.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Constructors, deterministic                        */
+/* -------------------------------------------------- */
+
+int igraph_create(igraph_t *graph, const igraph_vector_t *edges, igraph_integer_t n, 
+		  igraph_bool_t directed);
+int igraph_small(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, 
+		 ...);
+int igraph_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,
+		     igraph_adjacency_t mode);
+int igraph_weighted_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,
+		              igraph_adjacency_t mode, const char* attr, 
+			      igraph_bool_t loops);
+int igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode_t mode, 
+		igraph_integer_t center);
+int igraph_lattice(igraph_t *graph, const igraph_vector_t *dimvector, igraph_integer_t nei, 
+		   igraph_bool_t directed, igraph_bool_t mutual, igraph_bool_t circular);
+int igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, 
+		igraph_bool_t mutual, igraph_bool_t circular);
+int igraph_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, 
+		igraph_tree_mode_t type);
+int igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, igraph_bool_t loops);
+int igraph_full_citation(igraph_t *graph, igraph_integer_t n, 
+			 igraph_bool_t directed);
+int igraph_atlas(igraph_t *graph, int number);
+int igraph_extended_chordal_ring(igraph_t *graph, igraph_integer_t nodes, 
+				 const igraph_matrix_t *W);
+int igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order,
+				igraph_neimode_t mode);
+int igraph_linegraph(const igraph_t *graph, igraph_t *linegraph);
+
+int igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_integer_t n);
+int igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_t n);
+int igraph_famous(igraph_t *graph, const char *name);
+int igraph_lcf_vector(igraph_t *graph, igraph_integer_t n,
+		      const igraph_vector_t *shifts, 
+		      igraph_integer_t repeats);
+int igraph_lcf(igraph_t *graph, igraph_integer_t n, ...);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_conversion.h b/include/igraph_conversion.h
new file mode 100644
index 0000000..9dce4c0
--- /dev/null
+++ b/include/igraph_conversion.h
@@ -0,0 +1,74 @@
+/* -*- 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_CONVERSION_H
+#define IGRAPH_CONVERSION_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_spmatrix.h"
+#include "igraph_matrix.h"
+#include "igraph_sparsemat.h"
+#include "igraph_attributes.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Conversion                                         */
+/* -------------------------------------------------- */
+
+int igraph_get_adjacency(const igraph_t *graph, igraph_matrix_t *res,
+			 igraph_get_adjacency_t type, igraph_bool_t eids);
+int igraph_get_adjacency_sparse(const igraph_t *graph, igraph_spmatrix_t *res,
+			        igraph_get_adjacency_t type);
+
+int igraph_get_stochastic(const igraph_t *graph, 
+			  igraph_matrix_t *matrix,
+			  igraph_bool_t column_wise);
+
+int igraph_get_stochastic_sparsemat(const igraph_t *graph, 
+				    igraph_sparsemat_t *sparsemat,
+				    igraph_bool_t column_wise);
+
+int igraph_get_edgelist(const igraph_t *graph, igraph_vector_t *res, igraph_bool_t bycol);
+
+int igraph_to_directed(igraph_t *graph, 
+		       igraph_to_directed_t flags);
+int igraph_to_undirected(igraph_t *graph,
+			 igraph_to_undirected_t flags,
+			 const igraph_attribute_combination_t *edge_comb);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_datatype.h b/include/igraph_datatype.h
new file mode 100644
index 0000000..563b8d0
--- /dev/null
+++ b/include/igraph_datatype.h
@@ -0,0 +1,92 @@
+/* -*- 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_DATATYPE_H
+#define IGRAPH_DATATYPE_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_vector.h"
+
+__BEGIN_DECLS
+
+/**
+ * \ingroup internal
+ * \struct igraph_t
+ * \brief The internal data structure for storing graphs.
+ *
+ * It is simple and efficient. It has the following members:
+ * - <b>n</b> The number of vertices, reduntant.
+ * - <b>directed</b> Whether the graph is directed.
+ * - <b>from</b> The first column of the edge list.
+ * - <b>to</b> The second column of the edge list.
+ * - <b>oi</b> The index of the edge list by the first column. Thus
+ *   the first edge according to this order goes from
+ *   \c from[oi[0]] to \c to[oi[0]]. The length of
+ *   this vector is the same as the number of edges in the graph.
+ * - <b>ii</b> The index of the edge list by the second column. 
+ *   The length of this vector is the same as the number of edges.
+ * - <b>os</b> Contains pointers to the edgelist (\c from
+ *   and \c to for every vertex. The first edge \em from
+ *   vertex \c v is edge no. \c from[oi[os[v]]] if 
+ *   \c os[v]<os[v+1]. If \c os[v]==os[v+1] then
+ *   there are no edges \em from node \c v. Its length is
+ *   the number of vertices plus one, the last element is always the 
+ *   same as the number of edges and is contained only to ease the
+ *   queries.
+ * - <b>is</b> This is basically the same as <b>os</b>, but this time
+ *   for the incoming edges.
+ * 
+ * For undirected graph, the same edge list is stored, ie. an
+ * undirected edge is stored only once, and for checking whether there
+ * is an undirected edge from \c v1 to \c v2 one
+ * should search for both \c from=v1, \c to=v2 and 
+ * \c from=v2, \c to=v1.
+ *
+ * The storage requirements for a graph with \c |V| vertices
+ * and \c |E| edges is \c O(|E|+|V|).
+ */
+typedef struct igraph_s {
+  igraph_integer_t n;
+  igraph_bool_t directed;
+  igraph_vector_t from;
+  igraph_vector_t to;
+  igraph_vector_t oi;
+  igraph_vector_t ii;
+  igraph_vector_t os;
+  igraph_vector_t is;
+  void *attr;
+} igraph_t;
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_dqueue.h b/include/igraph_dqueue.h
new file mode 100644
index 0000000..d7146ba
--- /dev/null
+++ b/include/igraph_dqueue.h
@@ -0,0 +1,76 @@
+/* -*- 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/include/igraph_dqueue_pmt.h b/include/igraph_dqueue_pmt.h
new file mode 100644
index 0000000..5646408
--- /dev/null
+++ b/include/igraph_dqueue_pmt.h
@@ -0,0 +1,49 @@
+/* -*- 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
+
+*/
+
+/**
+ * Double ended queue data type.
+ * \ingroup internal
+ */
+
+typedef struct TYPE(igraph_dqueue) {
+  BASE *begin;
+  BASE *end;
+  BASE *stor_begin;
+  BASE *stor_end;
+} TYPE(igraph_dqueue);
+
+int FUNCTION(igraph_dqueue,init)    (TYPE(igraph_dqueue)* q, long int size);
+void FUNCTION(igraph_dqueue,destroy) (TYPE(igraph_dqueue)* q);
+igraph_bool_t FUNCTION(igraph_dqueue,empty)   (const TYPE(igraph_dqueue)* q);
+void FUNCTION(igraph_dqueue,clear)   (TYPE(igraph_dqueue)* q);
+igraph_bool_t FUNCTION(igraph_dqueue,full)    (TYPE(igraph_dqueue)* q);
+long int FUNCTION(igraph_dqueue,size)    (const TYPE(igraph_dqueue)* q);
+BASE FUNCTION(igraph_dqueue,pop)     (TYPE(igraph_dqueue)* q);
+BASE FUNCTION(igraph_dqueue,pop_back)(TYPE(igraph_dqueue)* q);
+BASE FUNCTION(igraph_dqueue,head)    (const TYPE(igraph_dqueue)* q);
+BASE FUNCTION(igraph_dqueue,back)    (const TYPE(igraph_dqueue)* q);
+int FUNCTION(igraph_dqueue,push)    (TYPE(igraph_dqueue)* q, BASE elem);
+int FUNCTION(igraph_dqueue,print)(const TYPE(igraph_dqueue)* q);
+int FUNCTION(igraph_dqueue,fprint)(const TYPE(igraph_dqueue)* q, FILE *file);
+BASE FUNCTION(igraph_dqueue,e)(const TYPE(igraph_dqueue) *q, long int idx);
diff --git a/include/igraph_eigen.h b/include/igraph_eigen.h
new file mode 100644
index 0000000..c3712a2
--- /dev/null
+++ b/include/igraph_eigen.h
@@ -0,0 +1,118 @@
+/* -*- 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/include/igraph_epidemics.h b/include/igraph_epidemics.h
new file mode 100644
index 0000000..9b925a5
--- /dev/null
+++ b/include/igraph_epidemics.h
@@ -0,0 +1,75 @@
+/* -*- 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
+
+*/
+
+#ifndef IGRAPH_EPIDEMICS_H
+#define IGRAPH_EPIDEMICS_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_vector.h"
+#include "igraph_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/**
+ * \struct igraph_sir_t
+ *
+ * Data structure to store the results of one simulation 
+ * of the SIR (susceptible-infected-recovered) model on a graph.
+ *
+ * It has the following members. They are all (real or integer) 
+ * vectors, and they are of the same length.
+ * 
+ * \member times A vector, the times of the events are stored here.
+ * \member no_s An integer vector, the number of susceptibles in
+ *              each time step is stored here.
+ * \member no_i An integer vector, the number of infected individuals
+ *              at each time step, is stored here.
+ * \member no_r An integer vector, the number of recovered individuals
+ *              is stored here at each time step.
+ */
+
+typedef struct igraph_sir_t {
+  igraph_vector_t times;
+  igraph_vector_int_t no_s, no_i, no_r;
+} igraph_sir_t;
+
+int igraph_sir_init(igraph_sir_t *sir);
+void igraph_sir_destroy(igraph_sir_t *sir);
+
+int igraph_sir(const igraph_t *graph, igraph_real_t beta,
+	       igraph_real_t gamma, igraph_integer_t no_sim,
+	       igraph_vector_ptr_t *result);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_error.h b/include/igraph_error.h
new file mode 100644
index 0000000..718084d
--- /dev/null
+++ b/include/igraph_error.h
@@ -0,0 +1,721 @@
+/* -*- 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/include/igraph_flow.h b/include/igraph_flow.h
new file mode 100644
index 0000000..5b94cf3
--- /dev/null
+++ b/include/igraph_flow.h
@@ -0,0 +1,178 @@
+/* -*- 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_FLOW_H
+#define IGRAPH_FLOW_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_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* MAximum flows, minimum cuts & such                 */
+/* -------------------------------------------------- */
+
+/**
+ * \typedef igraph_maxflow_stats_t
+ * A simple data type to return some statistics from the
+ * push-relabel maximum flow solver.
+ *
+ * \param nopush The number of push operations performed.
+ * \param norelabel The number of relabel operarions performed.
+ * \param nogap The number of times the gap heuristics was used.
+ * \param nogapnodes The total number of vertices that were
+ *        omitted form further calculations because of the gap
+ *        heuristics.
+ * \param nobfs The number of times the reverse BFS was run to
+ *        assign good values to the height function. This includes
+ *        an initial run before the whole algorithm, so it is always
+ *        at least one.
+ */
+
+typedef struct {
+  int nopush, norelabel, nogap, nogapnodes, nobfs;
+} igraph_maxflow_stats_t;
+
+int igraph_maxflow(const igraph_t *graph, igraph_real_t *value,
+		   igraph_vector_t *flow, igraph_vector_t *cut,
+		   igraph_vector_t *partition, igraph_vector_t *partition2,
+		   igraph_integer_t source, igraph_integer_t target,
+		   const igraph_vector_t *capacity,
+		   igraph_maxflow_stats_t *stats);
+int igraph_maxflow_value(const igraph_t *graph, igraph_real_t *value,
+			 igraph_integer_t source, igraph_integer_t target,
+			 const igraph_vector_t *capacity,
+			 igraph_maxflow_stats_t *stats);
+
+int igraph_st_mincut(const igraph_t *graph, igraph_real_t *value,
+		     igraph_vector_t *cut, igraph_vector_t *partition,
+		     igraph_vector_t *partition2,
+		     igraph_integer_t source, igraph_integer_t target,
+		     const igraph_vector_t *capacity);
+int igraph_st_mincut_value(const igraph_t *graph, igraph_real_t *res,
+                           igraph_integer_t source, igraph_integer_t target,
+			   const igraph_vector_t *capacity);
+
+int igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, 
+			const igraph_vector_t *capacity);
+int igraph_mincut(const igraph_t *graph,
+		  igraph_real_t *value,
+		  igraph_vector_t *partition,
+		  igraph_vector_t *partition2,
+		  igraph_vector_t *cut,
+		  const igraph_vector_t *capacity);
+
+int igraph_st_vertex_connectivity(const igraph_t *graph, 
+				  igraph_integer_t *res,
+				  igraph_integer_t source,
+				  igraph_integer_t target,
+				  igraph_vconn_nei_t neighbors);
+int igraph_vertex_connectivity(const igraph_t *graph, igraph_integer_t *res,
+			       igraph_bool_t checks);
+
+int igraph_st_edge_connectivity(const igraph_t *graph, igraph_integer_t *res,
+				igraph_integer_t source, 
+				igraph_integer_t target);
+int igraph_edge_connectivity(const igraph_t *graph, igraph_integer_t *res,
+			     igraph_bool_t checks);
+
+int igraph_edge_disjoint_paths(const igraph_t *graph, igraph_integer_t *res,
+			       igraph_integer_t source, 
+			       igraph_integer_t target);
+int igraph_vertex_disjoint_paths(const igraph_t *graph, igraph_integer_t *res,
+				 igraph_integer_t source,
+				 igraph_integer_t target);
+
+int igraph_adhesion(const igraph_t *graph, igraph_integer_t *res,
+		    igraph_bool_t checks);
+int igraph_cohesion(const igraph_t *graph, igraph_integer_t *res,
+		    igraph_bool_t checks);
+
+/* s-t cut listing related stuff */
+
+int igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *graphbar,
+				 igraph_vector_t *capacity);
+
+int igraph_residual_graph(const igraph_t *graph,
+			  const igraph_vector_t *capacity,
+			  igraph_t *residual,
+			  igraph_vector_t *residual_capacity,
+			  const igraph_vector_t *flow);
+int igraph_i_residual_graph(const igraph_t *graph,
+			    const igraph_vector_t *capacity,
+			    igraph_t *residual,
+			    igraph_vector_t *residual_capacity,
+			    const igraph_vector_t *flow, 
+			    igraph_vector_t *tmp);
+
+int igraph_i_reverse_residual_graph(const igraph_t *graph,
+				    const igraph_vector_t *capacity,
+				    igraph_t *residual,
+				    const igraph_vector_t *flow,
+				    igraph_vector_t *tmp);
+int igraph_reverse_residual_graph(const igraph_t *graph,
+				  const igraph_vector_t *capacity,
+				  igraph_t *residual,
+				  const igraph_vector_t *flow);
+
+int igraph_dominator_tree(const igraph_t *graph,
+			  igraph_integer_t root,
+			  igraph_vector_t *dom,
+			  igraph_t *domtree,
+			  igraph_vector_t *leftout,
+			  igraph_neimode_t mode);
+
+int igraph_all_st_cuts(const igraph_t *graph,
+		       igraph_vector_ptr_t *cuts,
+		       igraph_vector_ptr_t *partition1s,
+		       igraph_integer_t source,
+		       igraph_integer_t target);
+
+int igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value,
+			  igraph_vector_ptr_t *cuts,
+			  igraph_vector_ptr_t *partition1s,
+			  igraph_integer_t source,
+			  igraph_integer_t target,
+			  const igraph_vector_t *capacity);
+
+int igraph_gomory_hu_tree(const igraph_t *graph,
+			  igraph_t *tree,
+			  igraph_vector_t *flows,
+			  const igraph_vector_t *capacity);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_foreign.h b/include/igraph_foreign.h
new file mode 100644
index 0000000..3ef9153
--- /dev/null
+++ b/include/igraph_foreign.h
@@ -0,0 +1,94 @@
+/* -*- 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_FOREIGN_H
+#define IGRAPH_FOREIGN_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_datatype.h"
+#include "igraph_types.h"
+#include "igraph_strvector.h"
+
+#include <stdio.h>
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Read and write foreign formats                     */
+/* -------------------------------------------------- */
+
+int igraph_read_graph_edgelist(igraph_t *graph, FILE *instream, 
+			       igraph_integer_t n, igraph_bool_t directed);
+int igraph_read_graph_ncol(igraph_t *graph, FILE *instream,
+			   igraph_strvector_t *predefnames, igraph_bool_t names, 
+			  igraph_add_weights_t weights, igraph_bool_t directed);
+int igraph_read_graph_lgl(igraph_t *graph, FILE *instream,
+			  igraph_bool_t names, igraph_add_weights_t weights,
+			  igraph_bool_t directed);
+int igraph_read_graph_pajek(igraph_t *graph, FILE *instream);
+int igraph_read_graph_graphml(igraph_t *graph, FILE *instream,
+			      int index);
+int igraph_read_graph_dimacs(igraph_t *graph, FILE *instream,
+			     igraph_strvector_t *problem,
+			     igraph_vector_t *label,
+			     igraph_integer_t *source, 
+			     igraph_integer_t *target, 
+			     igraph_vector_t *capacity, 
+			     igraph_bool_t directed);
+int igraph_read_graph_graphdb(igraph_t *graph, FILE *instream, 
+			      igraph_bool_t directed);
+int igraph_read_graph_gml(igraph_t *graph, FILE *instream);
+int igraph_read_graph_dl(igraph_t *graph, FILE *instream, 
+			 igraph_bool_t directed);
+
+int igraph_write_graph_edgelist(const igraph_t *graph, FILE *outstream);
+int igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream,
+			    const char *names, const char *weights);
+int igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream,
+			   const char *names, const char *weights,
+			   igraph_bool_t isolates);
+int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream, 
+			       igraph_bool_t prefixattr);
+int igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream);
+int igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream,
+			      long int source, long int target,
+			      const igraph_vector_t *capacity);
+int igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, 
+			   const igraph_vector_t *id, const char *creator);
+int igraph_write_graph_dot(const igraph_t *graph, FILE *outstream);
+int igraph_write_graph_leda(const igraph_t *graph, FILE *outstream,
+        const char* vertex_attr_name, const char* edge_attr_name);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_games.h b/include/igraph_games.h
new file mode 100644
index 0000000..08bd483
--- /dev/null
+++ b/include/igraph_games.h
@@ -0,0 +1,194 @@
+/* -*- 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/include/igraph_graphlets.h b/include/igraph_graphlets.h
new file mode 100644
index 0000000..e3479fc
--- /dev/null
+++ b/include/igraph_graphlets.h
@@ -0,0 +1,71 @@
+/* -*- 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_GRAPHLETS_H
+#define IGRAPH_GRAPHLETS_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_vector_ptr.h"
+#include "igraph_interface.h"
+
+__BEGIN_DECLS
+
+int igraph_subclique_next(const igraph_t *graph,
+			  const igraph_vector_t *weights,
+			  const igraph_vector_int_t *ids,
+			  const igraph_vector_ptr_t *cliques,
+			  igraph_vector_ptr_t *result,
+			  igraph_vector_ptr_t *resultweights,
+			  igraph_vector_ptr_t *resultids,
+			  igraph_vector_t *clique_thr,
+			  igraph_vector_t *next_thr);
+
+int igraph_graphlets_candidate_basis(const igraph_t *graph,
+				     const igraph_vector_t *weights,
+				     igraph_vector_ptr_t *cliques,
+				     igraph_vector_t *thresholds);
+
+int igraph_graphlets_project(const igraph_t *graph,
+			     const igraph_vector_t *weights,
+			     const igraph_vector_ptr_t *cliques,
+			     igraph_vector_t *Mu, igraph_bool_t startMu,
+			     int niter);
+
+int igraph_graphlets(const igraph_t *graph,
+		     const igraph_vector_t *weights,
+		     igraph_vector_ptr_t *cliques,
+		     igraph_vector_t *Mu, int niter);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_heap.h b/include/igraph_heap.h
new file mode 100644
index 0000000..5e46ed9
--- /dev/null
+++ b/include/igraph_heap.h
@@ -0,0 +1,91 @@
+/* -*- 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_HEAP_H
+#define IGRAPH_HEAP_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
+
+/* -------------------------------------------------- */
+/* Heap                                               */
+/* -------------------------------------------------- */
+
+/**
+ * Heap data type.
+ * \ingroup internal
+ */
+
+#define BASE_IGRAPH_REAL
+#define HEAP_TYPE_MAX
+#include "igraph_pmt.h"
+#include "igraph_heap_pmt.h"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MAX
+#define HEAP_TYPE_MIN
+#include "igraph_pmt.h"
+#include "igraph_heap_pmt.h"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MIN
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#define HEAP_TYPE_MAX
+#include "igraph_pmt.h"
+#include "igraph_heap_pmt.h"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MAX
+#define HEAP_TYPE_MIN
+#include "igraph_pmt.h"
+#include "igraph_heap_pmt.h"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MIN
+#undef BASE_LONG
+
+#define BASE_CHAR
+#define HEAP_TYPE_MAX
+#include "igraph_pmt.h"
+#include "igraph_heap_pmt.h"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MAX
+#define HEAP_TYPE_MIN
+#include "igraph_pmt.h"
+#include "igraph_heap_pmt.h"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MIN
+#undef BASE_CHAR
+
+#define IGRAPH_HEAP_NULL { 0,0,0 }
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_heap_pmt.h b/include/igraph_heap_pmt.h
new file mode 100644
index 0000000..02a704a
--- /dev/null
+++ b/include/igraph_heap_pmt.h
@@ -0,0 +1,45 @@
+/* -*- 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_heap) {
+  BASE* stor_begin;
+  BASE* stor_end;
+  BASE* end;
+  int destroy;
+} TYPE(igraph_heap);
+
+int FUNCTION(igraph_heap,init)(TYPE(igraph_heap)* h, long int size);
+int FUNCTION(igraph_heap,init_array)(TYPE(igraph_heap) *t, BASE* data, long int len);
+void FUNCTION(igraph_heap,destroy)(TYPE(igraph_heap)* h);
+igraph_bool_t FUNCTION(igraph_heap,empty)(TYPE(igraph_heap)* h);
+int FUNCTION(igraph_heap,push)(TYPE(igraph_heap)* h, BASE elem);
+BASE FUNCTION(igraph_heap,top)(TYPE(igraph_heap)* h);
+BASE FUNCTION(igraph_heap,delete_top)(TYPE(igraph_heap)* h);
+long int FUNCTION(igraph_heap,size)(TYPE(igraph_heap)* h);
+int FUNCTION(igraph_heap,reserve)(TYPE(igraph_heap)* h, long int size);
+
+void FUNCTION(igraph_heap,i_build)(BASE* arr, long int size, long int head);
+void FUNCTION(igraph_heap,i_shift_up)(BASE* arr, long int size, long int elem);
+void FUNCTION(igraph_heap,i_sink)(BASE* arr, long int size, long int head);
+void FUNCTION(igraph_heap,i_switch)(BASE* arr, long int e1, long int e2);
+
diff --git a/include/igraph_hrg.h b/include/igraph_hrg.h
new file mode 100644
index 0000000..cb50518
--- /dev/null
+++ b/include/igraph_hrg.h
@@ -0,0 +1,123 @@
+/* -*- 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_HRG_H
+#define IGRAPH_HRG_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"
+#include "igraph_vector_ptr.h"
+#include "igraph_datatype.h"
+
+__BEGIN_DECLS
+
+/**
+ * \struct igraph_hrg_t
+ * Data structure to store a hierarchical random graph
+ * 
+ * A hierarchical random graph (HRG) can be given as a binary tree,
+ * where the internal vertices are labeled with real numbers.
+ * 
+ * </para><para>Note that you don't necessarily have to know this
+ * internal representation for using the HRG functions, just pass the
+ * HRG objects created by one igraph function, to another igraph
+ * function.
+ * 
+ * </para><para>
+ * It has the following members:
+ * \member 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.
+ * \member right Vector that contains the right children of the
+ *    vertices, with the same encoding as the \c left vector.
+ * \member 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.
+ * \member edges The number of edges in the subtree below the given
+ *    internal vertex.
+ * \member vertices The number of vertices in the subtree below the
+ *    given internal vertex, including itself.
+ */
+
+typedef struct igraph_hrg_t {
+  igraph_vector_t left, right, prob, edges, vertices;
+} igraph_hrg_t;
+
+int igraph_hrg_init(igraph_hrg_t *hrg, int n);
+void igraph_hrg_destroy(igraph_hrg_t *hrg);
+int igraph_hrg_size(const igraph_hrg_t *hrg);
+int igraph_hrg_resize(igraph_hrg_t *hrg, int newsize);
+
+int igraph_hrg_fit(const igraph_t *graph, 
+		   igraph_hrg_t *hrg,
+		   igraph_bool_t start,
+		   int steps);
+
+int igraph_hrg_sample(const igraph_t *graph,
+		      igraph_t *sample,
+		      igraph_vector_ptr_t *samples,
+		      igraph_hrg_t *hrg,
+		      igraph_bool_t start);
+
+int igraph_hrg_game(igraph_t *graph,
+		    const igraph_hrg_t *hrg);
+
+int igraph_hrg_dendrogram(igraph_t *graph,
+			  const igraph_hrg_t *hrg);
+
+int igraph_hrg_consensus(const igraph_t *graph,
+			 igraph_vector_t *parents,
+			 igraph_vector_t *weights,
+			 igraph_hrg_t *hrg,
+			 igraph_bool_t start, 
+			 int num_samples);
+
+int igraph_hrg_predict(const igraph_t *graph,
+		       igraph_vector_t *edges,
+		       igraph_vector_t *prob,
+		       igraph_hrg_t *hrg,
+		       igraph_bool_t start, 
+		       int num_samples,
+		       int num_bins);
+
+int igraph_hrg_create(igraph_hrg_t *hrg,
+		      const igraph_t *graph, 
+		      const igraph_vector_t *prob);
+
+__END_DECLS
+
+#endif	/* IGRAPH_HRG_H */
diff --git a/include/igraph_interface.h b/include/igraph_interface.h
new file mode 100644
index 0000000..4031b1f
--- /dev/null
+++ b/include/igraph_interface.h
@@ -0,0 +1,95 @@
+/* -*- 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_INTERFACE_H
+#define IGRAPH_INTERFACE_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
+
+/* -------------------------------------------------- */
+/* Interface                                          */
+/* -------------------------------------------------- */
+
+int igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed);
+int igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, void *attr);
+int igraph_destroy(igraph_t *graph);
+int igraph_copy(igraph_t *to, const igraph_t *from);
+int igraph_add_edges(igraph_t *graph, const igraph_vector_t *edges, 
+		     void *attr);
+int igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, 
+			void *attr);
+int igraph_delete_edges(igraph_t *graph, igraph_es_t edges);
+int igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices);
+int igraph_delete_vertices_idx(igraph_t *graph, const igraph_vs_t vertices, 
+			       igraph_vector_t *idx, 
+			       igraph_vector_t *invidx);
+igraph_integer_t igraph_vcount(const igraph_t *graph);
+igraph_integer_t igraph_ecount(const igraph_t *graph);
+int igraph_neighbors(const igraph_t *graph, igraph_vector_t *neis, igraph_integer_t vid, 
+		     igraph_neimode_t mode); 
+igraph_bool_t igraph_is_directed(const igraph_t *graph);
+int igraph_degree(const igraph_t *graph, igraph_vector_t *res, 
+		  const igraph_vs_t vids, igraph_neimode_t mode, 
+		  igraph_bool_t loops);
+int igraph_edge(const igraph_t *graph, igraph_integer_t eid, 
+		igraph_integer_t *from, igraph_integer_t *to);		
+int igraph_edges(const igraph_t *graph, igraph_es_t eids,
+		 igraph_vector_t *edges);
+int igraph_get_eid(const igraph_t *graph, igraph_integer_t *eid,
+		   igraph_integer_t from, igraph_integer_t to,
+		   igraph_bool_t directed, igraph_bool_t error);
+int igraph_get_eids(const igraph_t *graph, igraph_vector_t *eids,
+                    const igraph_vector_t *pairs,
+		    const igraph_vector_t *path,
+		    igraph_bool_t directed, igraph_bool_t error);
+int igraph_get_eids_multi(const igraph_t *graph, igraph_vector_t *eids,
+			  const igraph_vector_t *pairs, 
+			  const igraph_vector_t *path,
+			  igraph_bool_t directed, igraph_bool_t error);
+int igraph_adjacent(const igraph_t *graph, igraph_vector_t *eids, igraph_integer_t vid,
+		    igraph_neimode_t mode);          /* deprecated */
+int igraph_incident(const igraph_t *graph, igraph_vector_t *eids, igraph_integer_t vid,
+		    igraph_neimode_t mode);
+
+#define IGRAPH_FROM(g,e) ((igraph_integer_t)(VECTOR((g)->from)[(long int)(e)]))
+#define IGRAPH_TO(g,e)   ((igraph_integer_t)(VECTOR((g)->to)  [(long int)(e)]))
+#define IGRAPH_OTHER(g,e,v) \
+    ((igraph_integer_t)(IGRAPH_TO(g,(e))==(v) ? IGRAPH_FROM((g),(e)) : IGRAPH_TO((g),(e))))
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_interrupt.h b/include/igraph_interrupt.h
new file mode 100644
index 0000000..8907401
--- /dev/null
+++ b/include/igraph_interrupt.h
@@ -0,0 +1,138 @@
+/* -*- 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_INTERRUPT_H
+#define IGRAPH_INTERRUPT_H
+
+#include "igraph_error.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 interruption handling. */
+
+/**
+ * \section interrupthandlers Interruption handlers
+ *
+ * <para>
+ * \a igraph is designed to be embeddable into several higher level
+ * languages (R and Python interfaces are included in the original
+ * package). Since most higher level languages consider internal \a igraph
+ * calls as atomic, interruption requests (like Ctrl-C in Python) must
+ * be handled differently depending on the environment \a igraph embeds
+ * into.</para>
+ * <para>
+ * An \emb interruption handler \eme is a function which is called regularly
+ * by \a igraph during long calculations. A typical usage of the interruption
+ * handler is to check whether the user tried to interrupt the calculation
+ * and return an appropriate value to signal this condition. For example,
+ * in R, one must call an internal R function regularly to check for
+ * interruption requests, and the \a igraph interruption handler is the
+ * perfect place to do that.</para>
+ * <para>
+ * If you are using the plain C interface of \a igraph or if you are
+ * allowed to replace the operating system's interruption handler (like
+ * SIGINT in Un*x systems), these calls are not of much use to you.</para>
+ * <para>
+ * The default interruption handler is empty.
+ * The \ref igraph_set_interruption_handler() function can be used to set a
+ * new interruption handler function of type
+ * \ref igraph_interruption_handler_t, see the
+ * documentation of this type for details.
+ * </para>
+ */
+
+/**
+ * \section writing_interruption_handlers Writing interruption handlers
+ *
+ * <para>
+ * You can write and install interruption handlers simply by defining a
+ * function of type \ref igraph_interruption_handler_t and calling
+ * \ref igraph_set_interruption_handler(). This feature is useful for
+ * interface writers, because usually this is the only way to allow handling
+ * of Ctrl-C and similar keypresses properly.
+ * </para>
+ * <para> 
+ * Your interruption handler will be called regularly during long operations
+ * (so it is not guaranteed to be called during operations which tend to be
+ * short, like adding single edges). An interruption handler accepts no
+ * parameters and must return \c IGRAPH_SUCCESS if the calculation should go on. All
+ * other return values are considered to be a request for interruption,
+ * and the caller function would return a special error code, \c IGRAPH_INTERRUPTED.
+ * It is up to your error handler function to handle this error properly.
+ * </para>
+ */
+
+/**
+ * \section writing_functions_interruption_handling Writing \a igraph functions with
+ * proper interruption handling
+ *
+ * <para>
+ * There is practically a simple rule that should be obeyed when writing
+ * \a igraph functions. If the calculation is expected to take a long time
+ * in large graphs (a simple rule of thumb is to assume this for every
+ * function with a time complexity of at least O(n^2)), call
+ * \ref IGRAPH_ALLOW_INTERRUPTION in regular intervals like every 10th
+ * iteration or so.
+ * </para>
+ */
+
+/**
+ * \typedef igraph_interruption_handler_t
+ * 
+ * This is the type of the interruption handler functions.
+ * 
+ * \param data reserved for possible future use
+ * \return \c IGRAPH_SUCCESS if the calculation should go on, anything else otherwise.
+ */
+
+typedef int igraph_interruption_handler_t (void* data);
+
+/**
+ * \function igraph_allow_interruption
+ *
+ * This is the function which is called (usually via the
+ * \ref IGRAPH_INTERRUPTION macro) if \a igraph is checking for interruption
+ * requests.
+ *
+ * \param data reserved for possible future use, now it is always \c NULL
+ * \return \c IGRAPH_SUCCESS if the calculation should go on, anything else otherwise.
+ */
+
+int igraph_allow_interruption(void* data);
+
+igraph_interruption_handler_t *
+igraph_set_interruption_handler (igraph_interruption_handler_t * new_handler);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_iterators.h b/include/igraph_iterators.h
new file mode 100644
index 0000000..224e9cb
--- /dev/null
+++ b/include/igraph_iterators.h
@@ -0,0 +1,410 @@
+/* -*- 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_ITERATORS_H
+#define IGRAPH_ITERATORS_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"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Vertex selectors                                   */
+/* -------------------------------------------------- */
+
+#define IGRAPH_VS_ALL       0
+#define IGRAPH_VS_ADJ       1
+#define IGRAPH_VS_NONE      2
+#define IGRAPH_VS_1         3
+#define IGRAPH_VS_VECTORPTR 4
+#define IGRAPH_VS_VECTOR    5
+#define IGRAPH_VS_SEQ       6
+#define IGRAPH_VS_NONADJ    7
+
+typedef struct igraph_vs_t {
+  int type;
+  union {
+    igraph_integer_t vid;    	        /* single vertex  */
+    const igraph_vector_t *vecptr;      /* vector of vertices  */
+    struct {
+      igraph_integer_t vid;
+      igraph_neimode_t mode;
+    } adj;			        /* adjacent vertices  */
+    struct {                           
+      igraph_integer_t from;
+      igraph_integer_t to;
+    } seq;                              /* sequence of vertices from:to */
+  } data;
+} igraph_vs_t;
+    
+int igraph_vs_all(igraph_vs_t *vs);
+igraph_vs_t igraph_vss_all(void);
+
+int igraph_vs_adj(igraph_vs_t *vs, 
+		  igraph_integer_t vid, igraph_neimode_t mode);
+igraph_vs_t igraph_vss_adj(igraph_integer_t vid, igraph_neimode_t mode);
+
+int igraph_vs_nonadj(igraph_vs_t *vs, igraph_integer_t vid, 
+		     igraph_neimode_t mode);
+
+int igraph_vs_none(igraph_vs_t *vs);
+igraph_vs_t igraph_vss_none(void);
+
+int igraph_vs_1(igraph_vs_t *vs, igraph_integer_t vid);
+igraph_vs_t igraph_vss_1(igraph_integer_t vid);
+
+int igraph_vs_vector(igraph_vs_t *vs,
+		     const igraph_vector_t *v);
+igraph_vs_t igraph_vss_vector(const igraph_vector_t *v);
+
+int igraph_vs_vector_small(igraph_vs_t *vs, ...);			   
+
+int igraph_vs_vector_copy(igraph_vs_t *vs,
+			  const igraph_vector_t *v);
+
+int igraph_vs_seq(igraph_vs_t *vs, igraph_integer_t from, igraph_integer_t to);
+igraph_vs_t igraph_vss_seq(igraph_integer_t from, igraph_integer_t to);
+
+void igraph_vs_destroy(igraph_vs_t *vs);
+
+igraph_bool_t igraph_vs_is_all(const igraph_vs_t *vs);
+
+int igraph_vs_copy(igraph_vs_t* dest, const igraph_vs_t* src);
+
+int igraph_vs_as_vector(const igraph_t *graph, igraph_vs_t vs, 
+			igraph_vector_t *v);
+int igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs,
+  igraph_integer_t *result);
+int igraph_vs_type(const igraph_vs_t *vs);
+
+/* -------------------------------------------------- */
+/* Vertex iterators                                   */
+/* -------------------------------------------------- */
+
+#define IGRAPH_VIT_SEQ       0
+#define IGRAPH_VIT_VECTOR    1
+#define IGRAPH_VIT_VECTORPTR 2
+
+typedef struct igraph_vit_t {
+  int type;
+  long int pos;
+  long int start;
+  long int end;
+  const igraph_vector_t *vec;
+} igraph_vit_t;
+
+/**
+ * \section IGRAPH_VIT Stepping over the vertices
+ *
+ * <para>After creating an iterator with \ref igraph_vit_create(), it
+ * points to the first vertex in the vertex determined by the vertex
+ * selector (if there is any). The \ref IGRAPH_VIT_NEXT() macro steps
+ * to the next vertex, \ref IGRAPH_VIT_END() checks whether there are
+ * more vertices to visit, \ref IGRAPH_VIT_SIZE() gives the total size
+ * of the vertices visited so far and to be visited. \ref
+ * IGRAPH_VIT_RESET() resets the iterator, it will point to the first
+ * vertex again. Finally \ref IGRAPH_VIT_GET() gives the current vertex
+ * pointed to by the iterator (call this only if \ref IGRAPH_VIT_END()
+ * is false).
+ * </para>
+ * <para>
+ * Here is an example on how to step over the neighbors of vertex 0:
+ * <informalexample><programlisting>
+ * igraph_vs_t vs;
+ * igraph_vit_t vit;
+ * ...
+ * igraph_vs_adj(&vs, 0, IGRAPH_ALL);
+ * igraph_vit_create(&graph, vs, &vit);
+ * while (!IGRAPH_VIT_END(vit)) {
+ *   printf(" %li", (long int) IGRAPH_VIT_GET(vit));
+ *   IGRAPH_VIT_NEXT(vit);
+ * }
+ * printf("\n");
+ * ...
+ * igraph_vit_destroy(&vit);
+ * igraph_vs_destroy(&vs);
+ * </programlisting></informalexample>
+ * </para>
+ */
+
+/**
+ * \define IGRAPH_VIT_NEXT
+ * \brief Next vertex.
+ * 
+ * Steps the iterator to the next vertex. Only call this function if
+ * \ref IGRAPH_VIT_END() returns false.
+ * \param vit The vertex iterator to step.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_VIT_NEXT(vit)  (++((vit).pos))
+/**
+ * \define IGRAPH_VIT_END
+ * \brief Are we at the end?
+ * 
+ * Checks whether there are more vertices to step to.
+ * \param vit The vertex iterator to check.
+ * \return Logical value, if true there are no more vertices to step
+ * to.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_VIT_END(vit)   ((vit).pos >= (vit).end)
+/**
+ * \define IGRAPH_VIT_SIZE
+ * \brief Size of a vertex iterator.
+ * 
+ * Gives the number of vertices in a vertex iterator.
+ * \param vit The vertex iterator.
+ * \return The number of vertices.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_VIT_SIZE(vit)  ((vit).end - (vit).start)
+/**
+ * \define IGRAPH_VIT_RESET
+ * \brief Reset a vertex iterator.
+ * 
+ * Resets a vertex iterator. After calling this macro the iterator
+ * will point to the first vertex.
+ * \param vit The vertex iterator.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_VIT_RESET(vit) ((vit).pos = (vit).start)
+/**
+ * \define IGRAPH_VIT_GET
+ * \brief Query the current position.
+ * 
+ * Gives the vertex id of the current vertex pointed to by the
+ * iterator. 
+ * \param vit The vertex iterator.
+ * \return The vertex id of the current vertex.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_VIT_GET(vit)  \
+  ((igraph_integer_t)(((vit).type == IGRAPH_VIT_SEQ) ? (vit).pos : \
+  VECTOR(*(vit).vec)[(vit).pos]))
+
+int igraph_vit_create(const igraph_t *graph, 
+		      igraph_vs_t vs, igraph_vit_t *vit);
+void igraph_vit_destroy(const igraph_vit_t *vit); 
+
+int igraph_vit_as_vector(const igraph_vit_t *vit, igraph_vector_t *v);
+
+/* -------------------------------------------------- */
+/* Edge Selectors                                     */
+/* -------------------------------------------------- */
+
+#define IGRAPH_ES_ALL       0
+#define IGRAPH_ES_ALLFROM   1
+#define IGRAPH_ES_ALLTO     2
+#define IGRAPH_ES_INCIDENT  3
+#define IGRAPH_ES_NONE      4
+#define IGRAPH_ES_1         5
+#define IGRAPH_ES_VECTORPTR 6
+#define IGRAPH_ES_VECTOR    7
+#define IGRAPH_ES_SEQ       8
+#define IGRAPH_ES_PAIRS     9
+#define IGRAPH_ES_PATH      10
+#define IGRAPH_ES_MULTIPAIRS 11
+
+typedef struct igraph_es_t {
+  int type;
+  union {
+    igraph_integer_t vid;
+    igraph_integer_t eid;
+    const igraph_vector_t *vecptr;
+    struct {
+      igraph_integer_t vid;
+      igraph_neimode_t mode;
+    } incident;
+    struct {
+      igraph_integer_t from;
+      igraph_integer_t to;
+    } seq;
+    struct {
+      const igraph_vector_t *ptr;
+      igraph_bool_t mode;
+    } path;
+  } data;
+} igraph_es_t;
+
+int igraph_es_all(igraph_es_t *es, 
+		  igraph_edgeorder_type_t order);
+igraph_es_t igraph_ess_all(igraph_edgeorder_type_t order);
+
+int igraph_es_adj(igraph_es_t *es, 
+		  igraph_integer_t vid, igraph_neimode_t mode);     /* deprecated */
+int igraph_es_incident(igraph_es_t *es, 
+		  igraph_integer_t vid, igraph_neimode_t mode);
+
+int igraph_es_none(igraph_es_t *es);
+igraph_es_t igraph_ess_none(void);
+
+int igraph_es_1(igraph_es_t *es, igraph_integer_t eid);
+igraph_es_t igraph_ess_1(igraph_integer_t eid);
+
+int igraph_es_vector(igraph_es_t *es,
+		     const igraph_vector_t *v);
+igraph_es_t igraph_ess_vector(const igraph_vector_t *v);
+
+int igraph_es_fromto(igraph_es_t *es,
+		     igraph_vs_t from, igraph_vs_t to);
+
+int igraph_es_seq(igraph_es_t *es, igraph_integer_t from, igraph_integer_t to);
+igraph_es_t igraph_ess_seq(igraph_integer_t from, igraph_integer_t to);
+
+int igraph_es_vector_copy(igraph_es_t *es, const igraph_vector_t *v);
+
+int igraph_es_pairs(igraph_es_t *es, const igraph_vector_t *v, 
+		    igraph_bool_t directed);
+int igraph_es_pairs_small(igraph_es_t *es, igraph_bool_t directed, ...);
+
+int igraph_es_multipairs(igraph_es_t *es, const igraph_vector_t *v,
+			 igraph_bool_t directed);
+
+int igraph_es_path(igraph_es_t *es, const igraph_vector_t *v, 
+		   igraph_bool_t directed);
+int igraph_es_path_small(igraph_es_t *es, igraph_bool_t directed, ...);
+
+void igraph_es_destroy(igraph_es_t *es);
+
+igraph_bool_t igraph_es_is_all(const igraph_es_t *es);
+
+int igraph_es_copy(igraph_es_t* dest, const igraph_es_t* src);
+
+int igraph_es_as_vector(const igraph_t *graph, igraph_es_t es, 
+			igraph_vector_t *v);
+int igraph_es_size(const igraph_t *graph, const igraph_es_t *es,
+  igraph_integer_t *result);
+int igraph_es_type(const igraph_es_t *es);
+
+
+/* -------------------------------------------------- */
+/* Edge Iterators                                     */
+/* -------------------------------------------------- */
+
+#define IGRAPH_EIT_SEQ       0
+#define IGRAPH_EIT_VECTOR    1
+#define IGRAPH_EIT_VECTORPTR 2
+
+typedef struct igraph_eit_t {
+  int type;
+  long int pos;
+  long int start;
+  long int end;
+  const igraph_vector_t *vec;
+} igraph_eit_t;
+
+/**
+ * \section IGRAPH_EIT Stepping over the edges
+ * 
+ * <para>Just like for vertex iterators, macros are provided for
+ * stepping over a sequence of edges: \ref IGRAPH_EIT_NEXT() goes to
+ * the next edge, \ref IGRAPH_EIT_END() checks whether there are more
+ * edges to visit, \ref IGRAPH_EIT_SIZE() gives the number of edges in
+ * the edge sequence, \ref IGRAPH_EIT_RESET() resets the iterator to
+ * the first edge and \ref IGRAPH_EIT_GET() returns the id of the
+ * current edge.</para>
+ */
+
+/**
+ * \define IGRAPH_EIT_NEXT
+ * \brief Next edge.
+ * 
+ * Steps the iterator to the next edge. Call this function only if
+ * \ref IGRAPH_EIT_END() returns false.
+ * \param eit The edge iterator to step.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_EIT_NEXT(eit) (++((eit).pos))
+/**
+ * \define IGRAPH_EIT_END
+ * \brief Are we at the end?
+ * 
+ * Checks whether there are more edges to step to.
+ * \param wit The edge iterator to check.
+ * \return Logical value, if true there are no more edges
+ * to step to.
+ *
+ * Time complexity: O(1).
+ */
+#define IGRAPH_EIT_END(eit)   ((eit).pos >= (eit).end)
+/**
+ * \define IGRAPH_EIT_SIZE
+ * \brief Number of edges in the iterator.
+ * 
+ * Gives the number of edges in an edge iterator.
+ * \param eit The edge iterator.
+ * \return The number of edges.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_EIT_SIZE(eit)  ((eit).end - (eit).start)
+/**
+ * \define IGRAPH_EIT_RESET
+ * \brief Reset an edge iterator.
+ * 
+ * Resets an edge iterator. After calling this macro the iterator will
+ * point to the first edge.
+ * \param eit The edge iterator.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_EIT_RESET(eit) ((eit).pos = (eit).start)
+/**
+ * \define IGRAPH_EIT_GET
+ * \brief Query an edge iterator.
+ * 
+ * Gives the edge id of the current edge pointed to by an iterator.
+ * \param eit The edge iterator.
+ * \return The id of the current edge.
+ * 
+ * Time complexity: O(1).
+ */
+#define IGRAPH_EIT_GET(eit)  \
+  (igraph_integer_t)((((eit).type == IGRAPH_EIT_SEQ) ? (eit).pos : \
+  VECTOR(*(eit).vec)[(eit).pos]))
+
+int igraph_eit_create(const igraph_t *graph, 
+		      igraph_es_t es, igraph_eit_t *eit);
+void igraph_eit_destroy(const igraph_eit_t *eit); 
+
+int igraph_eit_as_vector(const igraph_eit_t *eit, igraph_vector_t *v);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_lapack.h b/include/igraph_lapack.h
new file mode 100644
index 0000000..90ea388
--- /dev/null
+++ b/include/igraph_lapack.h
@@ -0,0 +1,118 @@
+/* -*- 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/include/igraph_layout.h b/include/igraph_layout.h
new file mode 100644
index 0000000..aa87e5b
--- /dev/null
+++ b/include/igraph_layout.h
@@ -0,0 +1,253 @@
+/* -*- 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/include/igraph_matching.h b/include/igraph_matching.h
new file mode 100644
index 0000000..46194be
--- /dev/null
+++ b/include/igraph_matching.h
@@ -0,0 +1,65 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Tamas Nepusz <ntamas at gmail.com>
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+#ifndef IGRAPH_MATCHING_H
+#define IGRAPH_MATCHING_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_datatype.h"
+#include "igraph_types.h"
+#include "igraph_vector.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Matchings in graphs                                */
+/* -------------------------------------------------- */
+
+int igraph_is_matching(const igraph_t* graph,
+    const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,
+    igraph_bool_t* result);
+int igraph_is_maximal_matching(const igraph_t* graph,
+    const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,
+    igraph_bool_t* result);
+
+int igraph_maximum_bipartite_matching(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
+    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
+    const igraph_vector_t* weights, igraph_real_t eps);
+
+int igraph_maximum_matching(const igraph_t* graph, igraph_integer_t* matching_size,
+    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
+    const igraph_vector_t* weights);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_matrix.h b/include/igraph_matrix.h
new file mode 100644
index 0000000..a17431a
--- /dev/null
+++ b/include/igraph_matrix.h
@@ -0,0 +1,107 @@
+/* -*- 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/include/igraph_matrix_pmt.h b/include/igraph_matrix_pmt.h
new file mode 100644
index 0000000..e8a4097
--- /dev/null
+++ b/include/igraph_matrix_pmt.h
@@ -0,0 +1,234 @@
+/* -*- 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/include/igraph_memory.h b/include/igraph_memory.h
new file mode 100644
index 0000000..02fbf0a
--- /dev/null
+++ b/include/igraph_memory.h
@@ -0,0 +1,55 @@
+/* -*- 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_MEMORY_H
+#define REST_MEMORY_H
+
+#include <stdlib.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_Calloc(n,t)    (t*) calloc( (size_t)(n), sizeof(t) )
+#define igraph_Realloc(p,n,t) (t*) realloc((void*)(p), (size_t)((n)*sizeof(t)))
+#define igraph_Free(p)        (free( (void *)(p) ), (p) = NULL)
+
+/* #ifndef IGRAPH_NO_CALLOC */
+/* #  define Calloc igraph_Calloc */
+/* #  define Realloc igraph_Realloc */
+/* #  define Free igraph_Free */
+/* #endif */
+
+int igraph_free(void *p);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_microscopic_update.h b/include/igraph_microscopic_update.h
new file mode 100644
index 0000000..5789eb9
--- /dev/null
+++ b/include/igraph_microscopic_update.h
@@ -0,0 +1,69 @@
+/* -*- mode: C -*-  */
+/*
+  Microscopic update rules for dealing with agent-level strategy revision.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#ifndef IGRAPH_MICROSCOPIC_UPDATE_H
+#define IGRAPH_MICROSCOPIC_UPDATE_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_datatype.h"
+#include "igraph_iterators.h"
+#include "igraph_types.h"
+#include "igraph_vector.h"
+
+__BEGIN_DECLS
+
+int igraph_deterministic_optimal_imitation(const igraph_t *graph,
+					   igraph_integer_t vid,
+					   igraph_optimal_t optimality,
+					   const igraph_vector_t *quantities,
+					   igraph_vector_t *strategies,
+					   igraph_neimode_t mode);
+int igraph_moran_process(const igraph_t *graph,
+                         const igraph_vector_t *weights,
+                         igraph_vector_t *quantities,
+                         igraph_vector_t *strategies,
+                         igraph_neimode_t mode);
+int igraph_roulette_wheel_imitation(const igraph_t *graph,
+                                    igraph_integer_t vid,
+                                    igraph_bool_t islocal,
+                                    const igraph_vector_t *quantities,
+                                    igraph_vector_t *strategies,
+                                    igraph_neimode_t mode);
+int igraph_stochastic_imitation(const igraph_t *graph,
+                                igraph_integer_t vid,
+                                igraph_imitate_algorithm_t algo,
+                                const igraph_vector_t *quantities,
+                                igraph_vector_t *strategies,
+                                igraph_neimode_t mode);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_mixing.h b/include/igraph_mixing.h
new file mode 100644
index 0000000..c9d2dc6
--- /dev/null
+++ b/include/igraph_mixing.h
@@ -0,0 +1,60 @@
+/* -*- 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_MIXING_H
+#define IGRAPH_MIXING_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_vector.h"
+
+__BEGIN_DECLS
+
+int igraph_assortativity_nominal(const igraph_t *graph, 
+				 const igraph_vector_t *types,
+				 igraph_real_t *res,
+				 igraph_bool_t directed);
+
+int igraph_assortativity(const igraph_t *graph,
+			 const igraph_vector_t *types1,
+			 const igraph_vector_t *types2,
+			 igraph_real_t *res,
+			 igraph_bool_t directed);
+
+int igraph_assortativity_degree(const igraph_t *graph,
+				igraph_real_t *res, 
+				igraph_bool_t directed);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_motifs.h b/include/igraph_motifs.h
new file mode 100644
index 0000000..8494536
--- /dev/null
+++ b/include/igraph_motifs.h
@@ -0,0 +1,104 @@
+/* -*- 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/include/igraph_neighborhood.h b/include/igraph_neighborhood.h
new file mode 100644
index 0000000..7e2a261
--- /dev/null
+++ b/include/igraph_neighborhood.h
@@ -0,0 +1,51 @@
+/* -*- 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/include/igraph_nongraph.h b/include/igraph_nongraph.h
new file mode 100644
index 0000000..007f275
--- /dev/null
+++ b/include/igraph_nongraph.h
@@ -0,0 +1,102 @@
+/* -*- 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_NONGRAPH_H
+#define IGRAPH_NONGRAPH_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_matrix.h"
+#include "igraph_types.h"
+#include "igraph_vector.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Other, not graph related                           */
+/* -------------------------------------------------- */
+
+/**
+ * \struct igraph_plfit_result_t
+ * \brief Result of fitting a power-law distribution to a vector
+ *
+ * This data structure contains the result of \ref igraph_power_law_fit(),
+ * which tries to fit a power-law distribution to a vector of numbers. The
+ * structure contains the following members:
+ *
+ * \member continuous Whether the fitted power-law distribution was continuous
+ *                    or discrete.
+ * \member alpha The exponent of the fitted power-law distribution.
+ * \member xmin  The minimum value from which the power-law distribution was
+ *               fitted. In other words, only the values larger than \c xmin
+ *               were used from the input vector.
+ * \member L     The log-likelihood of the fitted parameters; in other words,
+ *               the probability of observing the input vector given the
+ *               parameters.
+ * \member D     The test statistic of a Kolmogorov-Smirnov test that compares
+ *               the fitted distribution with the input vector. Smaller scores
+ *               denote better fit.
+ * \member p     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.
+ */
+typedef struct igraph_plfit_result_t {
+  igraph_bool_t continuous;
+  double alpha;
+  double xmin;
+  double L;
+  double D;
+  double p;
+} igraph_plfit_result_t;
+
+int igraph_running_mean(const igraph_vector_t *data, igraph_vector_t *res, 
+			igraph_integer_t binwidth);
+int igraph_fisher_yates_shuffle(igraph_vector_t *seq);
+int igraph_random_sample(igraph_vector_t *res, igraph_real_t l, igraph_real_t h, 
+			 igraph_integer_t length);
+int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts,
+		       igraph_matrix_t *rescoords);
+int igraph_zeroin(igraph_real_t *ax, igraph_real_t *bx,
+		  igraph_real_t (*f)(igraph_real_t x, void *info),
+		  void *info, igraph_real_t *Tol, int *Maxit, igraph_real_t *res);
+int igraph_bfgs(igraph_vector_t *b, igraph_real_t *Fmin, 
+		igraph_scalar_function_t fminfn, igraph_vector_function_t fmingr,
+		int maxit, int trace,
+		igraph_real_t abstol, igraph_real_t reltol, int nREPORT, void *ex,
+		igraph_integer_t *fncount, igraph_integer_t *grcount);
+int igraph_power_law_fit(const igraph_vector_t* vector, igraph_plfit_result_t* result,
+                         igraph_real_t xmin, igraph_bool_t force_continuous);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_operators.h b/include/igraph_operators.h
new file mode 100644
index 0000000..e2343ae
--- /dev/null
+++ b/include/igraph_operators.h
@@ -0,0 +1,72 @@
+/* -*- 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_OPERATORS_H
+#define IGRAPH_OPERATORS_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_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Graph operators                                    */
+/* -------------------------------------------------- */
+
+int igraph_disjoint_union(igraph_t *res, 
+			  const igraph_t *left, const igraph_t *right);
+int igraph_disjoint_union_many(igraph_t *res, 
+			       const igraph_vector_ptr_t *graphs);
+int igraph_union(igraph_t *res, const igraph_t *left, const igraph_t *right,
+		 igraph_vector_t *edge_map1, igraph_vector_t *edge_map2);
+int igraph_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs,
+		      igraph_vector_ptr_t *edgemaps);
+int igraph_intersection(igraph_t *res, 
+			const igraph_t *left, const igraph_t *right, 
+			igraph_vector_t *edge_map1, 
+			igraph_vector_t *edge_map2);
+int igraph_intersection_many(igraph_t *res,
+			     const igraph_vector_ptr_t *graphs,
+			     igraph_vector_ptr_t *edgemaps);
+int igraph_difference(igraph_t *res, 
+		      const igraph_t *orig, const igraph_t *sub);
+int igraph_complementer(igraph_t *res, const igraph_t *graph, 
+			igraph_bool_t loops);
+int igraph_compose(igraph_t *res, const igraph_t *g1, const igraph_t *g2,
+		   igraph_vector_t *edge_map1, igraph_vector_t *edge_map2);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_paths.h b/include/igraph_paths.h
new file mode 100644
index 0000000..41cc310
--- /dev/null
+++ b/include/igraph_paths.h
@@ -0,0 +1,135 @@
+/* -*- 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/include/igraph_pmt.h b/include/igraph_pmt.h
new file mode 100644
index 0000000..b01c7b1
--- /dev/null
+++ b/include/igraph_pmt.h
@@ -0,0 +1,142 @@
+/* -*- 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/include/igraph_pmt_off.h b/include/igraph_pmt_off.h
new file mode 100644
index 0000000..44c1393
--- /dev/null
+++ b/include/igraph_pmt_off.h
@@ -0,0 +1,158 @@
+/* -*- 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
+
+*/
+
+#ifdef ATOMIC
+#undef ATOMIC
+#endif
+
+#ifdef ATOMIC_IO
+#undef ATOMIC_IO
+#endif
+
+#ifdef BASE
+#undef BASE
+#endif
+
+#ifdef BASE_EPSILON
+#undef BASE_EPSILON
+#endif
+
+#ifdef CONCAT2
+#undef CONCAT2
+#endif
+
+#ifdef CONCAT2x
+#undef CONCAT2x
+#endif
+
+#ifdef CONCAT3
+#undef CONCAT3
+#endif
+
+#ifdef CONCAT3x
+#undef CONCAT3x
+#endif
+
+#ifdef CONCAT4
+#undef CONCAT4
+#endif
+
+#ifdef CONCAT4x
+#undef CONCAT4x
+#endif
+
+#ifdef FP
+#undef FP
+#endif
+
+#ifdef FUNCTION
+#undef FUNCTION
+#endif
+
+#ifdef IN_FORMAT
+#undef IN_FORMAT
+#endif
+
+#ifdef MULTIPLICITY
+#undef MULTIPLICITY
+#endif
+
+#ifdef ONE
+#undef ONE
+#endif
+
+#ifdef OUT_FORMAT
+#undef OUT_FORMAT
+#endif
+
+#ifdef SHORT
+#undef SHORT
+#endif
+
+#ifdef TYPE
+#undef TYPE
+#endif
+
+#ifdef ZERO
+#undef ZERO
+#endif
+
+#ifdef HEAPMORE
+#undef HEAPMORE
+#endif
+
+#ifdef HEAPLESS
+#undef HEAPLESS
+#endif
+
+#ifdef HEAPMOREEQ
+#undef HEAPMOREEQ
+#endif
+
+#ifdef HEAPLESSEQ
+#undef HEAPLESSEQ
+#endif
+
+#ifdef SUM
+#undef SUM
+#endif
+
+#ifdef SQ
+#undef SQ
+#endif
+
+#ifdef PROD
+#undef PROD
+#endif
+
+#ifdef NOTORDERED
+#undef NOTORDERED
+#endif
+
+#ifdef EQ
+#undef EQ
+#endif
+
+#ifdef DIFF
+#undef DIFF
+#endif
+
+#ifdef DIV
+#undef DIV
+#endif
+
+#ifdef NOABS
+#undef NOABS
+#endif
+
+#ifdef PRINTFUNC
+#undef PRINTFUNC
+#endif
+
+#ifdef FPRINTFUNC
+#undef PRINTFUNC
+#endif
+
+#ifdef UNSIGNED
+#undef UNSIGNED
+#endif
diff --git a/include/igraph_progress.h b/include/igraph_progress.h
new file mode 100644
index 0000000..be1c424
--- /dev/null
+++ b/include/igraph_progress.h
@@ -0,0 +1,193 @@
+/* -*- 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_PROGRESS_H
+#define IGRAPH_PROGRESS_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
+
+/**
+ * \section about_progress_handlers About progress handlers
+ *
+ * <para>It is often useful to report the progress of some long
+ * calculation, to allow the user to follow the computation and 
+ * guess the total running time. A couple of igraph functions 
+ * support this at the time of writing, hopefully more will support it 
+ * in the future. 
+ * </para>
+ * 
+ * <para>
+ * To see the progress of a computation, the user has to install a 
+ * progress handler, as there is none installed by default. 
+ * If an igraph function supports progress reporting, then it 
+ * calls the installed progress handler periodically, and passes a
+ * percentage value to it, the percentage of computation already
+ * performed. To install a progress handler, you need to call 
+ * \ref igraph_set_progress_handler(). Currently there is a single
+ * pre-defined progress handler, called \ref
+ * igraph_progress_handler_stderr().
+ * </para>
+ */
+
+/**
+ * \section writing_progress_handlers Writing progress handlers
+ * 
+ * <para>
+ * To write a new progress handler, one needs to create a function of 
+ * type \ref igraph_progress_handler_t. The new progress handler 
+ * can then be installed with the \ref igraph_set_progress_handler() 
+ * function.
+ * </para>
+ *
+ * <para>
+ * One can assume that the first progress handler call from a
+ * calculation will be call with zero as the \p percentage argument,
+ * and the last call from a function will have 100 as the \p
+ * percentage argument. Note, however, that if an error happens in the 
+ * middle of a computation, then the 100 percent call might be
+ * omitted.
+ * </para>
+ */
+
+/**
+ * \section igraph_functions_with_progress Writing igraph functions with progress reporting
+ * 
+ * <para> 
+ * If you want to write a function that uses igraph and supports
+ * progress reporting, you need to include \ref igraph_progress()
+ * calls in your function, usually via the \ref IGRAPH_PROGRESS()
+ * macro.
+ * </para>
+ * 
+ * <para>
+ * It is good practice to always include a call to \ref
+ * igraph_progress() with a zero \p percentage argument, before the 
+ * computation; and another call with 100 \p percentage value 
+ * after the computation is completed.
+ * </para>
+ * 
+ * <para>
+ * It is also good practice \em not to call \ref igraph_progress() too
+ * often, as this would slow down the computation. It might not be 
+ * worth to support progress reporting in functions with linear or 
+ * log-linear time complexity, as these are fast, even with a large 
+ * amount of data. For functions with quadratic or higher time 
+ * complexity make sure that the time complexity of the progress
+ * reporting is constant or at least linear. In practice this means
+ * having at most O(n) progress checks and at most 100 \reg
+ * igraph_progress() calls.
+ * </para>
+ */
+
+/**
+ * \section progress_and_threads Multi-threaded programs
+ * 
+ * <para>
+ * In multi-threaded programs, each thread has its own progress 
+ * handler, if thread-local storage is supported and igraph is
+ * thread-safe. See the \ref IGRAPH_THREAD_SAFE macro for checking 
+ * whether an igraph build is thread-safe.
+ * </para>
+ */
+
+/* -------------------------------------------------- */
+/* Progress handlers                                  */
+/* -------------------------------------------------- */
+
+/** 
+ * \typedef igraph_progress_handler_t
+ * \brief Type of progress handler functions
+ * 
+ * This is the type of the igraph progress handler functions.
+ * There is currently one such predefined function, 
+ * \ref igraph_progress_handler_stderr(), but the user can
+ * write and set up more sophisticated ones.
+ * \param message A string describing the function or algorithm 
+ *     that is reporting the progress. Current igraph functions
+ *     always use the name \p message argument if reporting from the 
+ *     same function.
+ * \param percent Numeric, the percentage that was completed by the 
+ *     algorithm or function.
+ * \param data User-defined data. Current igraph functions that 
+ *     report progress pass a null pointer here. Users can 
+ *     write their own progress handlers and functions with progress 
+ *     reporting, and then pass some meaningfull context here.
+ * \return If the return value of the progress handler is not 
+ *     IGRAPH_SUCCESS (=0), then \ref igraph_progress() returns the
+ *     error code \c IGRAPH_INTERRUPTED. The \ref IGRAPH_PROGRESS() 
+ *     macro frees all memory and finishes the igraph function with 
+ *     error code \c IGRAPH_INTERRUPTED in this case.
+ */
+
+typedef int igraph_progress_handler_t(const char *message, igraph_real_t percent,
+				      void *data);
+
+extern igraph_progress_handler_t igraph_progress_handler_stderr;
+
+igraph_progress_handler_t *
+igraph_set_progress_handler(igraph_progress_handler_t new_handler);
+
+int igraph_progress(const char *message, igraph_real_t percent, void *data);
+
+int igraph_progressf(const char *message, igraph_real_t percent, void *data, 
+		     ...);
+
+/**
+ * \define IGRAPH_PROGRESS
+ * \brief Report progress.
+ * 
+ * The standard way to report progress from an igraph function
+ * \param message A string, a textual message that references the
+ *    calculation under progress.
+ * \param percent Numeric scalar, the percentage that is complete.
+ * \param data User-defined data, this can be used in user-defined
+ *    progress handler functions, from user-written igraph functions.
+ * \return If the progress handler returns with \c IGRAPH_INTERRUPTED, 
+ *    then this macro frees up the igraph allocated memory for
+ *    temporary data and returns to the caller with \c
+ *    IGRAPH_INTERRUPTED.
+ */
+
+#define IGRAPH_PROGRESS(message, percent, data) \
+  do { \
+    if (igraph_progress((message), (percent), (data)) != IGRAPH_SUCCESS) { \
+      IGRAPH_FINALLY_FREE(); \
+      return IGRAPH_INTERRUPTED; \
+    } \
+  } while (0)
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_psumtree.h b/include/igraph_psumtree.h
new file mode 100644
index 0000000..9dd8554
--- /dev/null
+++ b/include/igraph_psumtree.h
@@ -0,0 +1,58 @@
+/* -*- 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_PSUMTREE_H
+#define IGRAPH_PSUMTREE_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
+
+typedef struct {
+  igraph_vector_t v;
+  long int size;
+  long int offset;
+} igraph_psumtree_t;
+int igraph_psumtree_init(igraph_psumtree_t *t, long int size);
+void igraph_psumtree_destroy(igraph_psumtree_t *t);
+igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, long int idx);
+long int igraph_psumtree_size(const igraph_psumtree_t *t);
+int igraph_psumtree_search(const igraph_psumtree_t *t, long int *idx,
+			   igraph_real_t elem);
+int igraph_psumtree_update(igraph_psumtree_t *t, long int idx, 
+			   igraph_real_t new_value);
+igraph_real_t igraph_psumtree_sum(const igraph_psumtree_t *t);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_qsort.h b/include/igraph_qsort.h
new file mode 100644
index 0000000..bb347da
--- /dev/null
+++ b/include/igraph_qsort.h
@@ -0,0 +1,46 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, 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_QSORT_H
+#define IGRAPH_QSORT_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
+
+void igraph_qsort(void *base, size_t nel, size_t width,
+		  int (*compar)(const void *, const void *));
+void igraph_qsort_r(void *base, size_t nel, size_t width, void *thunk,
+		    int (*compar)(void *, const void *, const void *));
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_random.h b/include/igraph_random.h
new file mode 100644
index 0000000..2658248
--- /dev/null
+++ b/include/igraph_random.h
@@ -0,0 +1,129 @@
+/* -*- 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/include/igraph_revolver.h b/include/igraph_revolver.h
new file mode 100644
index 0000000..8b069cf
--- /dev/null
+++ b/include/igraph_revolver.h
@@ -0,0 +1,1200 @@
+/* -*- 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/include/igraph_scg.h b/include/igraph_scg.h
new file mode 100644
index 0000000..20e1a4a
--- /dev/null
+++ b/include/igraph_scg.h
@@ -0,0 +1,135 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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_SCG_H
+#define IGRAPH_SCG_H
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.h"
+#include "igraph_sparsemat.h"
+
+typedef enum { IGRAPH_SCG_SYMMETRIC=1, IGRAPH_SCG_LAPLACIAN=2,
+	       IGRAPH_SCG_STOCHASTIC=3 } igraph_scg_matrix_t;
+
+typedef enum { IGRAPH_SCG_OPTIMUM=1, IGRAPH_SCG_INTERV_KM=2,
+	       IGRAPH_SCG_INTERV=3, IGRAPH_SCG_EXACT=4 } 
+  igraph_scg_algorithm_t;
+
+typedef enum { IGRAPH_SCG_NORM_ROW=1, IGRAPH_SCG_NORM_COL=2 }
+  igraph_scg_norm_t;
+
+typedef enum { IGRAPH_SCG_DIRECTION_DEFAULT=1, 
+	       IGRAPH_SCG_DIRECTION_LEFT=2,
+	       IGRAPH_SCG_DIRECTION_RIGHT=3 } igraph_scg_direction_t;
+
+int igraph_scg_grouping(const igraph_matrix_t *V, 
+			igraph_vector_t *groups,
+			igraph_integer_t nt,
+			const igraph_vector_t *nt_vec,
+			igraph_scg_matrix_t mtype,
+			igraph_scg_algorithm_t algo,
+			const igraph_vector_t *p,
+			igraph_integer_t maxiter);
+
+int igraph_scg_semiprojectors(const igraph_vector_t *groups,
+			      igraph_scg_matrix_t mtype,
+			      igraph_matrix_t *L,
+			      igraph_matrix_t *R,
+			      igraph_sparsemat_t *Lsparse,
+			      igraph_sparsemat_t *Rsparse, 
+			      const igraph_vector_t *p,
+			      igraph_scg_norm_t norm);
+
+int igraph_scg_norm_eps(const igraph_matrix_t *V,
+			const igraph_vector_t *groups,
+			igraph_vector_t *eps,
+			igraph_scg_matrix_t mtype,
+			const igraph_vector_t *p,
+			igraph_scg_norm_t norm);
+
+int igraph_scg_adjacency(const igraph_t *graph,
+			 const igraph_matrix_t *matrix,
+			 const igraph_sparsemat_t *sparsemat,
+			 const igraph_vector_t *ev,
+			 igraph_integer_t nt,
+			 const igraph_vector_t *nt_vec,
+			 igraph_scg_algorithm_t algo,
+			 igraph_vector_t *values,
+			 igraph_matrix_t *vectors,
+			 igraph_vector_t *groups,
+			 igraph_bool_t use_arpack,
+			 igraph_integer_t maxiter,
+			 igraph_t *scg_graph,
+			 igraph_matrix_t *scg_matrix,
+			 igraph_sparsemat_t *scg_sparsemat,
+			 igraph_matrix_t *L,
+			 igraph_matrix_t *R,
+			 igraph_sparsemat_t *Lsparse,
+			 igraph_sparsemat_t *Rsparse);
+
+int igraph_scg_stochastic(const igraph_t *graph,
+			  const igraph_matrix_t *matrix,
+			  const igraph_sparsemat_t *sparsemat,
+			  const igraph_vector_t *ev,
+			  igraph_integer_t nt,
+			  const igraph_vector_t *nt_vec,
+			  igraph_scg_algorithm_t algo,
+			  igraph_scg_norm_t norm,
+			  igraph_vector_complex_t *values,
+			  igraph_matrix_complex_t *vectors,
+			  igraph_vector_t *groups,
+			  igraph_vector_t *p,
+			  igraph_bool_t use_arpack,
+			  igraph_integer_t maxiter,
+			  igraph_t *scg_graph,
+			  igraph_matrix_t *scg_matrix,
+			  igraph_sparsemat_t *scg_sparsemat,
+			  igraph_matrix_t *L,
+			  igraph_matrix_t *R,
+			  igraph_sparsemat_t *Lsparse,
+			  igraph_sparsemat_t *Rsparse);
+
+int igraph_scg_laplacian(const igraph_t *graph,
+			 const igraph_matrix_t *matrix,
+			 const igraph_sparsemat_t *sparsemat,
+			 const igraph_vector_t *ev,
+			 igraph_integer_t nt,
+			 const igraph_vector_t *nt_vec,
+			 igraph_scg_algorithm_t algo,
+			 igraph_scg_norm_t norm,
+			 igraph_scg_direction_t direction,
+			 igraph_vector_complex_t *values,
+			 igraph_matrix_complex_t *vectors,
+			 igraph_vector_t *groups,
+			 igraph_bool_t use_arpack,
+			 igraph_integer_t maxiter,
+			 igraph_t *scg_graph,
+			 igraph_matrix_t *scg_matrix,
+			 igraph_sparsemat_t *scg_sparsemat,
+			 igraph_matrix_t *L,
+			 igraph_matrix_t *R,
+			 igraph_sparsemat_t *Lsparse,
+			 igraph_sparsemat_t *Rsparse);
+
+#endif
diff --git a/include/igraph_separators.h b/include/igraph_separators.h
new file mode 100644
index 0000000..19ad531
--- /dev/null
+++ b/include/igraph_separators.h
@@ -0,0 +1,62 @@
+/* -*- 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_SEPARATORS_H
+#define IGRAPH_SEPARATORS_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_datatype.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+int igraph_is_separator(const igraph_t *graph, 
+			const igraph_vs_t candidate,
+			igraph_bool_t *res);
+
+int igraph_all_minimal_st_separators(const igraph_t *graph, 
+				     igraph_vector_ptr_t *separators);
+
+int igraph_is_minimal_separator(const igraph_t *graph,
+				const igraph_vs_t candidate, 
+				igraph_bool_t *res);
+
+int igraph_minimum_size_separators(const igraph_t *graph,
+				   igraph_vector_ptr_t *separators);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_sparsemat.h b/include/igraph_sparsemat.h
new file mode 100644
index 0000000..add7356
--- /dev/null
+++ b/include/igraph_sparsemat.h
@@ -0,0 +1,264 @@
+/* -*- 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/include/igraph_spmatrix.h b/include/igraph_spmatrix.h
new file mode 100644
index 0000000..54c1c86
--- /dev/null
+++ b/include/igraph_spmatrix.h
@@ -0,0 +1,123 @@
+/* -*- 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_SPMATRIX_H
+#define IGRAPH_SPMATRIX_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
+
+/* -------------------------------------------------- */
+/* Sparse matrix                                      */
+/* -------------------------------------------------- */
+
+/** 
+ * \section about_igraph_spmatrix_t_objects About \type igraph_spmatrix_t objects
+ * 
+ * <para>The \type igraph_spmatrix_t type stores a sparse matrix with the
+ * assumption that the number of nonzero elements in the matrix scales
+ * linearly with the row or column count of the matrix (so most of the
+ * elements are zero). Of course it can store an arbitrary real matrix,
+ * but if most of the elements are nonzero, one should use \type igraph_matrix_t
+ * instead.</para>
+ *
+ * <para>The elements are stored in column compressed format, so the elements
+ * in the same column are stored adjacent in the computer's memory. The storage
+ * requirement for a sparse matrix is O(n) where n is the number of nonzero
+ * elements. Actually it can be a bit larger, see the documentation of
+ * the vector type for an explanation.</para>
+ */
+typedef struct s_spmatrix {
+  igraph_vector_t ridx, cidx, data;
+  long int nrow, ncol;
+} igraph_spmatrix_t;
+
+#define IGRAPH_SPMATRIX_INIT_FINALLY(m, nr, nc) \
+  do { IGRAPH_CHECK(igraph_spmatrix_init(m, nr, nc)); \
+  IGRAPH_FINALLY(igraph_spmatrix_destroy, m); } while (0)
+
+int igraph_spmatrix_init(igraph_spmatrix_t *m, long int nrow, long int ncol);
+void igraph_spmatrix_destroy(igraph_spmatrix_t *m);
+int igraph_spmatrix_resize(igraph_spmatrix_t *m, long int nrow, long int ncol);
+igraph_real_t igraph_spmatrix_e(const igraph_spmatrix_t *m, long int row, long int col);
+int igraph_spmatrix_set(igraph_spmatrix_t *m, long int row, long int col,
+                        igraph_real_t value);
+int igraph_spmatrix_add_e(igraph_spmatrix_t *m, long int row, long int col,
+                        igraph_real_t value);
+int igraph_spmatrix_add_col_values(igraph_spmatrix_t *m, long int to, long int from);
+long int igraph_spmatrix_count_nonzero(const igraph_spmatrix_t *m);
+long int igraph_spmatrix_size(const igraph_spmatrix_t *m);
+long int igraph_spmatrix_nrow(const igraph_spmatrix_t *m);
+long int igraph_spmatrix_ncol(const igraph_spmatrix_t *m);
+int igraph_spmatrix_copy_to(const igraph_spmatrix_t *m, igraph_real_t *to);
+int igraph_spmatrix_null(igraph_spmatrix_t *m);
+int igraph_spmatrix_add_cols(igraph_spmatrix_t *m, long int n);
+int igraph_spmatrix_add_rows(igraph_spmatrix_t *m, long int n);
+int igraph_spmatrix_clear_col(igraph_spmatrix_t *m, long int col);
+int igraph_spmatrix_clear_row(igraph_spmatrix_t *m, long int row);
+int igraph_spmatrix_copy(igraph_spmatrix_t *to, const igraph_spmatrix_t *from);
+igraph_real_t igraph_spmatrix_max_nonzero(const igraph_spmatrix_t *m,
+    igraph_real_t *ridx, igraph_real_t *cidx);
+igraph_real_t igraph_spmatrix_max(const igraph_spmatrix_t *m,
+    igraph_real_t *ridx, igraph_real_t *cidx);
+void igraph_spmatrix_scale(igraph_spmatrix_t *m, igraph_real_t by);
+int igraph_spmatrix_colsums(const igraph_spmatrix_t *m, igraph_vector_t *res);
+int igraph_spmatrix_rowsums(const igraph_spmatrix_t *m, igraph_vector_t *res);
+
+int igraph_spmatrix_print(const igraph_spmatrix_t *matrix);
+int igraph_spmatrix_fprint(const igraph_spmatrix_t *matrix, FILE* file);
+
+int igraph_i_spmatrix_get_col_nonzero_indices(const igraph_spmatrix_t *m,
+    igraph_vector_t *res, long int col);
+int igraph_i_spmatrix_clear_row_fast(igraph_spmatrix_t *m, long int row);
+int igraph_i_spmatrix_cleanup(igraph_spmatrix_t *m);
+
+
+typedef struct s_spmatrix_iter {
+  const igraph_spmatrix_t *m; /* pointer to the matrix we are iterating over */
+  long int pos;               /* internal index into the data vector */
+  long int ri;                /* row index */
+  long int ci;                /* column index */
+  igraph_real_t value;        /* value at the given cell */
+} igraph_spmatrix_iter_t;
+
+int igraph_spmatrix_iter_create(igraph_spmatrix_iter_t *mit, const igraph_spmatrix_t *m);
+int igraph_spmatrix_iter_reset(igraph_spmatrix_iter_t *mit);
+int igraph_spmatrix_iter_next(igraph_spmatrix_iter_t *mit);
+igraph_bool_t igraph_spmatrix_iter_end(igraph_spmatrix_iter_t *mit);
+void igraph_spmatrix_iter_destroy(igraph_spmatrix_iter_t *mit);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_stack.h b/include/igraph_stack.h
new file mode 100644
index 0000000..c6a821c
--- /dev/null
+++ b/include/igraph_stack.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_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/include/igraph_stack_pmt.h b/include/igraph_stack_pmt.h
new file mode 100644
index 0000000..2db6aa0
--- /dev/null
+++ b/include/igraph_stack_pmt.h
@@ -0,0 +1,47 @@
+/* -*- 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 <stdio.h>
+
+/**
+ * Stack data type.
+ * \ingroup internal
+ */
+
+typedef struct TYPE(igraph_stack) {
+  BASE* stor_begin;
+  BASE* stor_end;
+  BASE* end;
+} TYPE(igraph_stack);
+
+int FUNCTION(igraph_stack,init)(TYPE(igraph_stack)* s, long int size);
+void FUNCTION(igraph_stack,destroy)(TYPE(igraph_stack)* s);
+int FUNCTION(igraph_stack,reserve)(TYPE(igraph_stack)* s, long int size);
+igraph_bool_t FUNCTION(igraph_stack,empty)(TYPE(igraph_stack)* s);
+long int FUNCTION(igraph_stack,size)(const TYPE(igraph_stack)* s);
+void FUNCTION(igraph_stack,clear)(TYPE(igraph_stack)* s);
+int FUNCTION(igraph_stack,push)(TYPE(igraph_stack)* s, BASE elem);
+BASE FUNCTION(igraph_stack,pop)(TYPE(igraph_stack)* s);
+BASE FUNCTION(igraph_stack,top)(const TYPE(igraph_stack)* s);
+int FUNCTION(igraph_stack,print)(const TYPE(igraph_stack)* s);
+int FUNCTION(igraph_stack,fprint)(const TYPE(igraph_stack)* s, FILE *file);
diff --git a/include/igraph_statusbar.h b/include/igraph_statusbar.h
new file mode 100644
index 0000000..1fc845e
--- /dev/null
+++ b/include/igraph_statusbar.h
@@ -0,0 +1,135 @@
+/* -*- 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_STATUSBAR
+#define IGRAPH_STATUSBAR
+
+#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_status_handlers Status reporting
+ * 
+ * <para>
+ * In addition to the possibility of reporting the progress of an 
+ * igraph computation via \ref igraph_progress(), it is also possible 
+ * to report simple status messages from within igraph functions, 
+ * without having to judge how much of the computation was performed
+ * already. For this one needs to install a status handler function.
+ * </para>
+ * 
+ * <para>
+ * Status handler functions must be of type \ref igraph_status_handler_t 
+ * and they can be install by a call to \ref igraph_set_status_handler().
+ * Currently there is a simple predefined status handler function,
+ * called \ref igraph_status_handler_stderr(), but the user can define
+ * new ones.
+ * </para>
+ * 
+ * <para>
+ * Igraph functions report their status via a call to the 
+ * \ref IGRAPH_STATUS() or the \ref IGRAPH_STATUSF() macro.
+ * </para>
+ */
+ 
+/** 
+ * \typedef igraph_status_handler_t
+ * 
+ * The type of the igraph status handler functions
+ * \param message The status message.
+ * \param data Additional context, with user-defined semantics.
+ *        Existing igraph functions pass a null pointer here.
+ */
+
+typedef int igraph_status_handler_t(const char *message, void *data);
+
+extern igraph_status_handler_t igraph_status_handler_stderr;
+
+igraph_status_handler_t *
+igraph_set_status_handler(igraph_status_handler_t new_handler);
+
+int igraph_status(const char *message, void *data);
+
+/**
+ * \define IGRAPH_STATUS
+ * Report the status of an igraph function.
+ * 
+ * Typically this function is called only a handful of times from
+ * an igraph function. E.g. if an algorithm has three major 
+ * steps, then it is logical to call it three times, to 
+ * signal the three major steps.
+ * \param message The status message.
+ * \param data Additional context, with user-defined semantics.
+ *        Existing igraph functions pass a null pointer here.
+ * \return If the status handler returns with a value other than
+ *        \c IGRAPH_SUCCESS, then the function that called this 
+ *        macro returns as well, with error code 
+ *        \c IGRAPH_INTERRUPTED.
+ */
+
+#define IGRAPH_STATUS(message, data) \
+  do { \
+    if (igraph_status((message), (data)) != IGRAPH_SUCCESS) { \
+      IGRAPH_FINALLY_FREE(); \
+      return IGRAPH_INTERRUPTED; \
+    } \
+  } while (0)
+
+int igraph_statusf(const char *message, void *data, ...);
+
+/** 
+ * \define IGRAPH_STATUSF
+ * Report the status from an igraph function 
+ *
+ * This is the more flexible version of \ref IGRAPH_STATUS(), 
+ * having a printf-like syntax. As this macro takes variable 
+ * number of arguments, they must be all supplied as a single 
+ * argument, enclosed in parentheses. Then \ref igraph_statusf() 
+ * is called with the given arguments.
+ * \param args The arguments to pass to \ref igraph_statusf().
+ * \return If the status handler returns with a value other than
+ *        \c IGRAPH_SUCCESS, then the function that called this 
+ *        macro returns as well, with error code 
+ *        \c IGRAPH_INTERRUPTED.
+ */
+
+#define IGRAPH_STATUSF(args) \
+  do { \
+    if (igraph_statusf args != IGRAPH_SUCCESS) { \
+      IGRAPH_FINALLY_FREE(); \
+      return IGRAPH_INTERRUPTED; \
+    } \
+  } while (0)
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_structural.h b/include/igraph_structural.h
new file mode 100644
index 0000000..67253a7
--- /dev/null
+++ b/include/igraph_structural.h
@@ -0,0 +1,157 @@
+/* -*- 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_STRUCTURAL_H
+#define IGRAPH_STRUCTURAL_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_matrix.h"
+#include "igraph_datatype.h"
+#include "igraph_iterators.h"
+#include "igraph_attributes.h"
+#include "igraph_sparsemat.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Basic query functions                              */
+/* -------------------------------------------------- */
+
+int igraph_are_connected(const igraph_t *graph, igraph_integer_t v1, igraph_integer_t v2, igraph_bool_t *res);
+
+/* -------------------------------------------------- */
+/* Structural properties                              */
+/* -------------------------------------------------- */
+
+int igraph_minimum_spanning_tree(const igraph_t *graph, igraph_vector_t *res,
+        const igraph_vector_t *weights);
+int igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, 
+					    igraph_t *mst);
+int igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst,
+				      const igraph_vector_t *weights);
+
+int igraph_subcomponent(const igraph_t *graph, igraph_vector_t *res, igraph_real_t vid, 
+			igraph_neimode_t mode);	
+int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode);
+int igraph_subgraph(const igraph_t *graph, igraph_t *res, 
+		    const igraph_vs_t vids);
+int igraph_induced_subgraph_map(const igraph_t *graph, igraph_t *res,
+				const igraph_vs_t vids, 
+				igraph_subgraph_implementation_t impl,
+				igraph_vector_t *map, 
+				igraph_vector_t *invmap);
+int igraph_induced_subgraph(const igraph_t *graph, igraph_t *res, 
+		    const igraph_vs_t vids, igraph_subgraph_implementation_t impl);
+int igraph_subgraph_edges(const igraph_t *graph, igraph_t *res, 
+		    const igraph_es_t eids, igraph_bool_t delete_vertices);
+int igraph_simplify(igraph_t *graph, igraph_bool_t multiple, 
+		    igraph_bool_t loops,
+		    const igraph_attribute_combination_t *edge_comb);
+int igraph_reciprocity(const igraph_t *graph, igraph_real_t *res,
+		       igraph_bool_t ignore_loops,
+		       igraph_reciprocity_t mode);
+
+int igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res,
+		     igraph_vs_t vids, igraph_neimode_t mode, 
+		     igraph_bool_t loops);
+int igraph_density(const igraph_t *graph, igraph_real_t *res, 
+		   igraph_bool_t loops);
+
+int igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, 
+		   igraph_es_t es);
+int igraph_is_simple(const igraph_t *graph, igraph_bool_t *res);
+int igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res);
+int igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res, 
+		       igraph_es_t es);
+int igraph_count_multiple(const igraph_t *graph, igraph_vector_t *res, igraph_es_t es);
+int igraph_girth(const igraph_t *graph, igraph_integer_t *girth, 
+		 igraph_vector_t *circle);
+int igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to);
+
+int igraph_unfold_tree(const igraph_t *graph, igraph_t *tree,
+		       igraph_neimode_t mode, const igraph_vector_t *roots,
+		       igraph_vector_t *vertex_index);
+
+int igraph_is_mutual(igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es);
+
+int igraph_maximum_cardinality_search(const igraph_t *graph,
+				      igraph_vector_t *alpha,
+				      igraph_vector_t *alpham1);
+int igraph_is_chordal(const igraph_t *graph,
+		      const igraph_vector_t *alpha,
+		      const igraph_vector_t *alpham1,
+		      igraph_bool_t *chordal,
+		      igraph_vector_t *fill_in,
+		      igraph_t *newgraph);
+int igraph_avg_nearest_neighbor_degree(const igraph_t *graph,
+				       igraph_vs_t vids,
+				       igraph_vector_t *knn,
+				       igraph_vector_t *knnk, 
+				       const igraph_vector_t *weights);
+int igraph_contract_vertices(igraph_t *graph,
+			     const igraph_vector_t *mapping,
+			     const igraph_attribute_combination_t 
+			     *vertex_comb);
+
+int igraph_transitive_closure_dag(const igraph_t *graph,
+				  igraph_t *closure);
+
+int igraph_feedback_arc_set(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights, igraph_fas_algorithm_t algo);
+
+int igraph_diversity(igraph_t *graph, const igraph_vector_t *weights,
+		     igraph_vector_t *res, const igraph_vs_t vs);
+
+/* -------------------------------------------------- */
+/* Spectral Properties                                */
+/* -------------------------------------------------- */
+
+int igraph_laplacian(const igraph_t *graph, igraph_matrix_t *res,
+		     igraph_sparsemat_t *sparseres,
+		     igraph_bool_t normalized, 
+		     const igraph_vector_t *weights);
+
+/* -------------------------------------------------- */
+/* Internal functions, may change any time            */
+/* -------------------------------------------------- */
+
+int igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights, igraph_vector_t *layering);
+int igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights, igraph_vector_t *layering);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_strvector.h b/include/igraph_strvector.h
new file mode 100644
index 0000000..b67d3dd
--- /dev/null
+++ b/include/igraph_strvector.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_STRVECTOR_H
+#define IGRAPH_STRVECTOR_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
+
+/**
+ * Vector of strings
+ * \ingroup internal
+ */
+
+typedef struct s_igraph_strvector {
+  char **data;
+  long int len;
+} igraph_strvector_t;
+
+/**
+ * \define STR
+ * Indexing string vectors
+ * 
+ * This is a macro which allows to query the elements of a string vector in 
+ * simpler way than \ref igraph_strvector_get(). Note this macro cannot be 
+ * used to set an element, for that use \ref igraph_strvector_set().
+ * \param sv The string vector
+ * \param i The the index of the element.
+ * \return The element at position \p i.
+ * 
+ * Time complexity: O(1).
+ */
+#define STR(sv,i) ((const char *)((sv).data[(i)]))
+
+#define IGRAPH_STRVECTOR_NULL { 0,0 }
+#define IGRAPH_STRVECTOR_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_strvector_init(v, size)); \
+  IGRAPH_FINALLY( (igraph_finally_func_t*) igraph_strvector_destroy, v); } while (0)
+
+int igraph_strvector_init(igraph_strvector_t *sv, long int len);
+void igraph_strvector_destroy(igraph_strvector_t *sv);
+long int igraph_strvector_size(const igraph_strvector_t *sv);
+void igraph_strvector_get(const igraph_strvector_t *sv, 
+			  long int idx, char **value);
+int igraph_strvector_set(igraph_strvector_t *sv, long int idx, 
+			 const char *value);
+int igraph_strvector_set2(igraph_strvector_t *sv, long int idx, 
+			  const char *value, int len);
+void igraph_strvector_clear(igraph_strvector_t *sv);
+void igraph_strvector_remove_section(igraph_strvector_t *v, long int from, 
+				     long int to);
+void igraph_strvector_remove(igraph_strvector_t *v, long int elem);
+void igraph_strvector_move_interval(igraph_strvector_t *v, long int begin, 
+				   long int end, long int to);
+int igraph_strvector_copy(igraph_strvector_t *to, 
+			  const igraph_strvector_t *from);
+int igraph_strvector_append(igraph_strvector_t *to, 
+			    const igraph_strvector_t *from);
+int igraph_strvector_resize(igraph_strvector_t* v, long int newsize);
+int igraph_strvector_add(igraph_strvector_t *v, const char *value);
+void igraph_strvector_permdelete(igraph_strvector_t *v, const igraph_vector_t *index,
+				 long int nremove);
+void igraph_strvector_remove_negidx(igraph_strvector_t *v, const igraph_vector_t *neg,
+				    long int nremove);
+int igraph_strvector_print(const igraph_strvector_t *v, FILE *file,
+			   const char *sep);
+
+int igraph_strvector_index(const igraph_strvector_t *v, 
+                           igraph_strvector_t *newv,
+                           const igraph_vector_t *idx);
+
+  
+__END_DECLS
+
+#endif
diff --git a/include/igraph_threading.h b/include/igraph_threading.h
new file mode 100644
index 0000000..1df33d1
--- /dev/null
+++ b/include/igraph_threading.h
@@ -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 1
+
+__END_DECLS
+
+#endif
+
diff --git a/include/igraph_threading.h.in b/include/igraph_threading.h.in
new file mode 100644
index 0000000..928269c
--- /dev/null
+++ b/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/include/igraph_topology.h b/include/igraph_topology.h
new file mode 100644
index 0000000..c23c965
--- /dev/null
+++ b/include/igraph_topology.h
@@ -0,0 +1,290 @@
+/* -*- 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_TOPOLOGY_H
+#define IGRAPH_TOPOLOGY_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_datatype.h"
+#include "igraph_types.h"
+#include "igraph_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Degree sequences                                   */
+/* -------------------------------------------------- */
+
+int igraph_is_degree_sequence(const igraph_vector_t *out_degrees,
+        const igraph_vector_t *in_degrees, igraph_bool_t *res);
+int igraph_is_graphical_degree_sequence(const igraph_vector_t *out_degrees,
+        const igraph_vector_t *in_degrees, igraph_bool_t *res);
+
+/* -------------------------------------------------- */
+/* Directed acyclic graphs                            */
+/* -------------------------------------------------- */
+
+int igraph_topological_sorting(const igraph_t *graph, igraph_vector_t *res,
+			       igraph_neimode_t mode);
+int igraph_is_dag(const igraph_t *graph, igraph_bool_t *res);
+int igraph_transitive_closure_dag(const igraph_t *graph,
+				  igraph_t *closure);
+
+/* -------------------------------------------------- */
+/* Graph isomorphisms                                 */
+/* -------------------------------------------------- */
+
+/* Common functions */
+int igraph_permute_vertices(const igraph_t *graph, igraph_t *res,
+			    const igraph_vector_t *permutation);
+
+/* Generic interface */
+int igraph_isomorphic(const igraph_t *graph1, const igraph_t *graph2,
+		      igraph_bool_t *iso);
+int igraph_subisomorphic(const igraph_t *graph1, const igraph_t *graph2,
+			 igraph_bool_t *iso);
+
+/* LAD */
+int igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t *target,
+			     igraph_vector_ptr_t *domains,
+			     igraph_bool_t *iso, igraph_vector_t *map, 
+			     igraph_vector_ptr_t *maps, 
+			     igraph_bool_t induced, int time_limit);
+
+/* VF2 family*/
+/** 
+ * \typedef igraph_isohandler_t
+ * Callback type, called when an isomorphism was found
+ * 
+ * See the details at the documentation of \ref
+ * igraph_isomorphic_function_vf2().
+ * \param map12 The mapping from the first graph to the second.
+ * \param map21 The mapping from the second graph to the first, the
+ *   inverse of \p map12 basically.
+ * \param arg This extra argument was passed to \ref
+ *   igraph_isomorphic_function_vf2() when it was called.
+ * \return Boolean, whether to continue with the isomorphism search.
+ */
+
+
+typedef igraph_bool_t igraph_isohandler_t(const igraph_vector_t *map12, 
+					  const igraph_vector_t *map21, void *arg);
+
+/** 
+ * \typedef igraph_isocompat_t 
+ * Callback type, called to check whether two vertices or edges are compatible
+ * 
+ * VF2 (subgraph) isomorphism functions can be restricted by defining 
+ * relations on the vertices and/or edges of the graphs, and then checking 
+ * whether the vertices (edges) match according to these relations. 
+ * 
+ * </para><para>This feature is implemented by two callbacks, one for 
+ * vertices, one for edges. Every time igraph tries to match a vertex (edge) 
+ * of the first (sub)graph to a vertex of the second graph, the vertex 
+ * (edge) compatibility callback is called. The callback returns a 
+ * logical value, giving whether the two vertices match.
+ * 
+ * </para><para>Both callback functions are of type \c igraph_isocompat_t.
+ * \param graph1 The first graph.
+ * \param graph2 The second graph.
+ * \param g1_num The id of a vertex or edge in the first graph. 
+ * \param g2_num The id of a vertex or edge in the second graph.
+ * \param arg Extra argument to pass to the callback functions.
+ * \return Logical scalar, whether vertex (or edge) \p g1_num in \p graph1 
+ *    is compatible with vertex (or edge) \p g2_num in \p graph2.
+ */
+
+typedef igraph_bool_t igraph_isocompat_t(const igraph_t *graph1,
+					 const igraph_t *graph2,
+					 const igraph_integer_t g1_num,
+					 const igraph_integer_t g2_num,
+					 void *arg);
+
+int igraph_isomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+			  const igraph_vector_int_t *vertex_color1,
+			  const igraph_vector_int_t *vertex_color2,
+			  const igraph_vector_int_t *edge_color1,
+			  const igraph_vector_int_t *edge_color2,
+			  igraph_bool_t *iso,
+			  igraph_vector_t *map12, 
+			  igraph_vector_t *map21,
+			  igraph_isocompat_t *node_compat_fn,
+			  igraph_isocompat_t *edge_compat_fn,
+			  void *arg);
+int igraph_isomorphic_function_vf2(const igraph_t *graph1, const igraph_t *graph2,
+				   const igraph_vector_int_t *vertex_color1,
+				   const igraph_vector_int_t *vertex_color2,
+				   const igraph_vector_int_t *edge_color1,
+				   const igraph_vector_int_t *edge_color2,
+				   igraph_vector_t *map12, igraph_vector_t *map21,
+				   igraph_isohandler_t *isohandler_fn,
+				   igraph_isocompat_t *node_compat_fn,
+				   igraph_isocompat_t *edge_compat_fn,
+				   void *arg);
+int igraph_count_isomorphisms_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+				  const igraph_vector_int_t *vertex_color1,
+				  const igraph_vector_int_t *vertex_color2,
+				  const igraph_vector_int_t *edge_color1,
+				  const igraph_vector_int_t *edge_color2,
+				  igraph_integer_t *count,
+				  igraph_isocompat_t *node_compat_fn,
+				  igraph_isocompat_t *edge_compat_fn,
+				  void *arg);
+int igraph_get_isomorphisms_vf2(const igraph_t *graph1,
+				const igraph_t *graph2,
+				const igraph_vector_int_t *vertex_color1,
+				const igraph_vector_int_t *vertex_color2,
+				const igraph_vector_int_t *edge_color1,
+				const igraph_vector_int_t *edge_color2,
+				igraph_vector_ptr_t *maps,
+				igraph_isocompat_t *node_compat_fn,
+				igraph_isocompat_t *edge_compat_fn,
+				void *arg);
+
+int igraph_subisomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+			     const igraph_vector_int_t *vertex_color1,
+			     const igraph_vector_int_t *vertex_color2,
+			     const igraph_vector_int_t *edge_color1,
+			     const igraph_vector_int_t *edge_color2,
+			     igraph_bool_t *iso,
+			     igraph_vector_t *map12, 
+			     igraph_vector_t *map21,
+			     igraph_isocompat_t *node_compat_fn,
+			     igraph_isocompat_t *edge_compat_fn,
+			     void *arg);
+int igraph_subisomorphic_function_vf2(const igraph_t *graph1, 
+				      const igraph_t *graph2,
+				      const igraph_vector_int_t *vertex_color1,
+				      const igraph_vector_int_t *vertex_color2,
+				      const igraph_vector_int_t *edge_color1,
+				      const igraph_vector_int_t *edge_color2,
+				      igraph_vector_t *map12,
+				      igraph_vector_t *map21,
+				      igraph_isohandler_t *isohandler_fn,
+				      igraph_isocompat_t *node_compat_fn,
+				      igraph_isocompat_t *edge_compat_fn,
+				      void *arg);
+int igraph_count_subisomorphisms_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+				     const igraph_vector_int_t *vertex_color1,
+				     const igraph_vector_int_t *vertex_color2,
+				     const igraph_vector_int_t *edge_color1,
+				     const igraph_vector_int_t *edge_color2,
+				     igraph_integer_t *count,
+				     igraph_isocompat_t *node_compat_fn,
+				     igraph_isocompat_t *edge_compat_fn,
+				     void *arg);
+int igraph_get_subisomorphisms_vf2(const igraph_t *graph1,
+				   const igraph_t *graph2,
+				   const igraph_vector_int_t *vertex_color1,
+				   const igraph_vector_int_t *vertex_color2,
+				   const igraph_vector_int_t *edge_color1,
+				   const igraph_vector_int_t *edge_color2,
+				   igraph_vector_ptr_t *maps,
+				   igraph_isocompat_t *node_compat_fn,
+				   igraph_isocompat_t *edge_compat_fn,
+				   void *arg);
+
+/* BLISS family */
+/**
+ * \struct igraph_bliss_info_t 
+ * Information about a BLISS run
+ * 
+ * Some secondary information found by the BLISS algorithm is stored
+ * here. It is useful if you wany to study the internal working of the
+ * algorithm.
+ * \member nof_nodes The number of nodes in the search tree.
+ * \member nof_leaf_nodes The number of leaf nodes in the search tree.
+ * \member nof_bad_nodes Number of bad nodes.
+ * \member nof_canupdates Number of canrep updates.
+ * \member max_level Maximum level.
+ * \member group_size The size of the automorphism group of the graph,
+ *    given as a string. It should be deallocated via
+ *    <function>free()</function> if not needed any more.
+ * 
+ * See http://www.tcs.hut.fi/Software/bliss/index.html
+ * for details about the algorithm and these parameters.
+ */
+typedef struct igraph_bliss_info_t {
+  unsigned long nof_nodes;
+  unsigned long nof_leaf_nodes;
+  unsigned long nof_bad_nodes;
+  unsigned long nof_canupdates;
+  unsigned long max_level;
+  char *group_size;
+} igraph_bliss_info_t;
+
+/**
+ * \typedef igraph_bliss_sh_t
+ * Splitting heuristics for BLISS
+ * 
+ * \enumval IGRAPH_BLISS_F First non-singleton cell.
+ * \enumval IGRAPH_BLISS_FL First largest non-singleton cell.
+ * \enumval IGRAPH_BLISS_FS First smallest non-singleton cell.
+ * \enumval IGRAPH_BLISS_FM First maximally non-trivially connected
+ *      non-singleton cell.
+ * \enumval IGRAPH_BLISS_FLM Largest maximally non-trivially connected
+ *      non-singleton cell.
+ * \enumval IGRAPH_BLISS_FSM Smallest maximally non-trivially
+ *      connected non-singletion cell.
+ */
+
+typedef enum { IGRAPH_BLISS_F=0, IGRAPH_BLISS_FL, 
+	       IGRAPH_BLISS_FS, IGRAPH_BLISS_FM, 
+	       IGRAPH_BLISS_FLM, IGRAPH_BLISS_FSM } igraph_bliss_sh_t;
+
+int igraph_canonical_permutation(const igraph_t *graph, igraph_vector_t *labeling, 
+				 igraph_bliss_sh_t sh, igraph_bliss_info_t *info);
+int igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *graph2,
+			    igraph_bool_t *iso, igraph_vector_t *map12, 
+			    igraph_vector_t *map21,
+			    igraph_bliss_sh_t sh1, igraph_bliss_sh_t sh2, 
+			    igraph_bliss_info_t *info1, igraph_bliss_info_t *info2);
+
+int igraph_automorphisms(const igraph_t *graph,
+			 igraph_bliss_sh_t sh, igraph_bliss_info_t *info);
+
+/* Functions for 3-4 graphs */
+int igraph_isomorphic_34(const igraph_t *graph1, const igraph_t *graph2, 
+			 igraph_bool_t *iso);
+int igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass);
+int igraph_isoclass_subgraph(const igraph_t *graph, igraph_vector_t *vids,
+			     igraph_integer_t *isoclass);
+int igraph_isoclass_create(igraph_t *graph, igraph_integer_t size,
+			   igraph_integer_t number, igraph_bool_t directed);
+
+
+
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_transitivity.h b/include/igraph_transitivity.h
new file mode 100644
index 0000000..b691a1b
--- /dev/null
+++ b/include/igraph_transitivity.h
@@ -0,0 +1,73 @@
+/* -*- 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_TRANSITIVITY_H
+#define IGRAPH_TRANSITIVITY_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_constants.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+int igraph_transitivity_undirected(const igraph_t *graph, 
+				   igraph_real_t *res,
+				   igraph_transitivity_mode_t mode);
+int igraph_transitivity_local_undirected(const igraph_t *graph, 
+					 igraph_vector_t *res,
+					 const igraph_vs_t vids,
+					 igraph_transitivity_mode_t mode);
+int igraph_transitivity_local_undirected1(const igraph_t *graph, 
+					  igraph_vector_t *res,
+					  const igraph_vs_t vids,
+					  igraph_transitivity_mode_t mode);
+int igraph_transitivity_local_undirected2(const igraph_t *graph, 
+					  igraph_vector_t *res,
+					  const igraph_vs_t vids,
+					  igraph_transitivity_mode_t mode);
+int igraph_transitivity_local_undirected4(const igraph_t *graph, 
+					  igraph_vector_t *res,
+					  const igraph_vs_t vids,
+					  igraph_transitivity_mode_t mode);
+int igraph_transitivity_avglocal_undirected(const igraph_t *graph,
+					    igraph_real_t *res,
+					    igraph_transitivity_mode_t mode);
+int igraph_transitivity_barrat(const igraph_t *graph,
+			       igraph_vector_t *res,
+			       const igraph_vs_t vids,
+			       const igraph_vector_t *weights,
+			       const igraph_transitivity_mode_t mode);
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_types.h b/include/igraph_types.h
new file mode 100644
index 0000000..8445f71
--- /dev/null
+++ b/include/igraph_types.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 REST_TYPES_H
+#define REST_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
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include "igraph_error.h"
+#include <stddef.h>
+#include <math.h>
+#include <stdio.h>
+
+/* This is to eliminate gcc warnings about unused parameters */
+#define IGRAPH_UNUSED(x) (void)(x)
+
+typedef int    igraph_integer_t;
+typedef double igraph_real_t;
+typedef int    igraph_bool_t;
+
+/* Replacements for printf that print doubles in the same way on all platforms
+ * (even for NaN and infinities) */
+int igraph_real_printf(igraph_real_t val);
+int igraph_real_fprintf(FILE *file, igraph_real_t val);
+int igraph_real_snprintf(char* str, size_t size, igraph_real_t val);
+
+/* Replacements for printf that print doubles in the same way on all platforms
+ * (even for NaN and infinities) with the largest possible precision */
+int igraph_real_printf_precise(igraph_real_t val);
+int igraph_real_fprintf_precise(FILE *file, igraph_real_t val);
+int igraph_real_snprintf_precise(char* str, size_t size, igraph_real_t val);
+
+/* igraph_i_fdiv is needed here instead of in igraph_math.h because
+ * some constants use it */
+double igraph_i_fdiv(const double a, const double b);
+
+#if defined(INFINITY)
+#  define IGRAPH_INFINITY INFINITY
+#  define IGRAPH_POSINFINITY INFINITY
+#  define IGRAPH_NEGINFINITY (-INFINITY)
+#else
+#  define IGRAPH_INFINITY (igraph_i_fdiv(1.0, 0.0))
+#  define IGRAPH_POSINFINITY (igraph_i_fdiv(1.0, 0.0))
+#  define IGRAPH_NEGINFINITY (igraph_i_fdiv(-1.0, 0.0))
+#endif
+
+int igraph_finite(double x);
+#define IGRAPH_FINITE(x) igraph_finite(x)
+
+int igraph_is_nan(double x);
+int igraph_is_inf(double x);
+int igraph_is_posinf(double x);
+int igraph_is_neginf(double x);
+
+#if defined(NAN)
+#  define IGRAPH_NAN NAN
+#elif defined(INFINITY)
+#  define IGRAPH_NAN (INFINITY/INFINITY)
+#else
+#  define IGRAPH_NAN (igraph_i_fdiv(0.0, 0.0))
+#endif
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_vector.h b/include/igraph_vector.h
new file mode 100644
index 0000000..2be3b3c
--- /dev/null
+++ b/include/igraph_vector.h
@@ -0,0 +1,174 @@
+/* -*- 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/include/igraph_vector_pmt.h b/include/igraph_vector_pmt.h
new file mode 100644
index 0000000..acd0a58
--- /dev/null
+++ b/include/igraph_vector_pmt.h
@@ -0,0 +1,265 @@
+/* -*- 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
+
+*/
+
+/*--------------------*/
+/* Allocation         */
+/*--------------------*/
+
+int FUNCTION(igraph_vector,init)(TYPE(igraph_vector)* v, long int size);
+int FUNCTION(igraph_vector,init_copy)(TYPE(igraph_vector)* v, 
+				       BASE* data, long int length);
+int FUNCTION(igraph_vector,init_seq)(TYPE(igraph_vector)*v, BASE from, BASE to);
+int FUNCTION(igraph_vector,copy)(TYPE(igraph_vector) *to, 
+				 const TYPE(igraph_vector) *from);
+void FUNCTION(igraph_vector,destroy)(TYPE(igraph_vector)* v);
+
+long int FUNCTION(igraph_vector,capacity)(const TYPE(igraph_vector)*v);
+
+/*--------------------*/
+/* Accessing elements */
+/*--------------------*/
+
+#ifndef VECTOR
+/**
+ * \ingroup vector
+ * \define VECTOR
+ * \brief Accessing an element of a vector.
+ * 
+ * Usage: 
+ * \verbatim VECTOR(v)[0] \endverbatim 
+ * to access the first element of the vector, you can also use this in
+ * assignments, like: 
+ * \verbatim VECTOR(v)[10]=5; \endverbatim
+ *
+ * Note that there are no range checks right now.
+ * This functionality might be redefined later as a real function
+ * instead of a <code>#define</code>. 
+ * \param v The vector object.
+ * 
+ * Time complexity: O(1).
+ */
+#define VECTOR(v) ((v).stor_begin) 
+#endif
+
+BASE FUNCTION(igraph_vector,e)(const TYPE(igraph_vector)* v, long int pos);
+BASE* FUNCTION(igraph_vector,e_ptr)(const TYPE(igraph_vector)* v, long int pos);
+void FUNCTION(igraph_vector,set)(TYPE(igraph_vector)* v, long int pos, BASE value);
+BASE FUNCTION(igraph_vector,tail)(const TYPE(igraph_vector) *v);
+
+/*-----------------------*/
+/* Initializing elements */
+/*-----------------------*/
+
+void FUNCTION(igraph_vector,null)(TYPE(igraph_vector)* v);
+void FUNCTION(igraph_vector,fill)(TYPE(igraph_vector)* v, BASE e);
+
+/*-----------------------*/
+/* Vector views          */
+/*-----------------------*/
+
+const TYPE(igraph_vector) *FUNCTION(igraph_vector,view)(const TYPE(igraph_vector) *v,
+							const BASE *data, 
+							long int length);
+
+/*-----------------------*/
+/* Copying vectors       */
+/*-----------------------*/
+
+void FUNCTION(igraph_vector,copy_to)(const TYPE(igraph_vector) *v, BASE* to);
+int FUNCTION(igraph_vector,update)(TYPE(igraph_vector) *to, 
+				   const TYPE(igraph_vector) *from);
+int FUNCTION(igraph_vector,append)(TYPE(igraph_vector) *to, 
+				   const TYPE(igraph_vector) *from);
+int FUNCTION(igraph_vector,swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2);
+
+/*-----------------------*/
+/* Exchanging elements   */
+/*-----------------------*/
+
+int FUNCTION(igraph_vector,swap_elements)(TYPE(igraph_vector) *v,
+					  long int i, long int j);
+int FUNCTION(igraph_vector,reverse)(TYPE(igraph_vector) *v);
+int FUNCTION(igraph_vector,shuffle)(TYPE(igraph_vector) *v);
+
+/*-----------------------*/
+/* Vector operations     */
+/*-----------------------*/
+
+void FUNCTION(igraph_vector,add_constant)(TYPE(igraph_vector) *v, BASE plus);
+void FUNCTION(igraph_vector,scale)(TYPE(igraph_vector) *v, BASE by);
+int FUNCTION(igraph_vector,add)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2);
+int FUNCTION(igraph_vector,sub)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2);
+int FUNCTION(igraph_vector,mul)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2);
+int FUNCTION(igraph_vector,div)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2);
+int FUNCTION(igraph_vector,cumsum)(TYPE(igraph_vector) *to,
+                const TYPE(igraph_vector) *from);
+
+#ifndef NOABS
+int FUNCTION(igraph_vector,abs)(TYPE(igraph_vector) *v);
+#endif
+
+/*------------------------------*/
+/* Comparison                   */
+/*------------------------------*/
+
+igraph_bool_t FUNCTION(igraph_vector,all_e)(const TYPE(igraph_vector) *lhs, 
+					    const TYPE(igraph_vector) *rhs);
+igraph_bool_t FUNCTION(igraph_vector,all_l)(const TYPE(igraph_vector) *lhs, 
+					    const TYPE(igraph_vector) *rhs);
+igraph_bool_t FUNCTION(igraph_vector,all_g)(const TYPE(igraph_vector) *lhs, 
+					    const TYPE(igraph_vector) *rhs);
+igraph_bool_t FUNCTION(igraph_vector,all_le)(const TYPE(igraph_vector) *lhs, 
+					     const TYPE(igraph_vector) *rhs);
+igraph_bool_t FUNCTION(igraph_vector,all_ge)(const TYPE(igraph_vector) *lhs, 
+					     const TYPE(igraph_vector) *rhs);
+
+/*------------------------------*/
+/* Finding minimum and maximum  */
+/*------------------------------*/
+
+BASE FUNCTION(igraph_vector,min)(const TYPE(igraph_vector)* v);
+BASE FUNCTION(igraph_vector,max)(const TYPE(igraph_vector)* v);
+long int FUNCTION(igraph_vector,which_min)(const TYPE(igraph_vector)* v);
+long int FUNCTION(igraph_vector,which_max)(const TYPE(igraph_vector)* v);
+int FUNCTION(igraph_vector,minmax)(const TYPE(igraph_vector) *v,
+				   BASE *min, BASE *max);
+int FUNCTION(igraph_vector,which_minmax)(const TYPE(igraph_vector) *v,
+					 long int *which_min, long int *which_max);
+
+/*-------------------*/
+/* Vector properties */
+/*-------------------*/
+
+igraph_bool_t FUNCTION(igraph_vector,empty)     (const TYPE(igraph_vector)* v);
+long int FUNCTION(igraph_vector,size)      (const TYPE(igraph_vector)* v);
+igraph_bool_t FUNCTION(igraph_vector,isnull)(const TYPE(igraph_vector) *v);
+BASE FUNCTION(igraph_vector,sum)(const TYPE(igraph_vector) *v);
+igraph_real_t FUNCTION(igraph_vector,sumsq)(const TYPE(igraph_vector) *v);
+BASE FUNCTION(igraph_vector,prod)(const TYPE(igraph_vector) *v);
+igraph_bool_t FUNCTION(igraph_vector,isininterval)(const TYPE(igraph_vector) *v, 
+						   BASE low, BASE high);
+igraph_bool_t FUNCTION(igraph_vector,any_smaller)(const TYPE(igraph_vector) *v, 
+						  BASE limit);
+igraph_bool_t FUNCTION(igraph_vector,is_equal)(const TYPE(igraph_vector) *lhs, 
+                                              const TYPE(igraph_vector) *rhs);
+BASE FUNCTION(igraph_vector,maxdifference)(const TYPE(igraph_vector) *m1,
+					   const TYPE(igraph_vector) *m2);
+
+/*------------------------*/
+/* Searching for elements */
+/*------------------------*/
+
+igraph_bool_t FUNCTION(igraph_vector,contains)(const TYPE(igraph_vector) *v, BASE e);
+igraph_bool_t FUNCTION(igraph_vector,search)(const TYPE(igraph_vector) *v,
+					     long int from, BASE what, 
+					     long int *pos);
+igraph_bool_t FUNCTION(igraph_vector,binsearch)(const TYPE(igraph_vector) *v, 
+						BASE what, long int *pos);
+igraph_bool_t FUNCTION(igraph_vector,binsearch2)(const TYPE(igraph_vector) *v,
+						 BASE what);
+
+/*------------------------*/
+/* Resizing operations    */
+/*------------------------*/
+
+void FUNCTION(igraph_vector,clear)(TYPE(igraph_vector)* v);
+int FUNCTION(igraph_vector,resize)(TYPE(igraph_vector)* v, long int newsize);
+int FUNCTION(igraph_vector,resize_min)(TYPE(igraph_vector)*v);
+int FUNCTION(igraph_vector,reserve)(TYPE(igraph_vector)* v, long int size);
+int FUNCTION(igraph_vector,push_back)(TYPE(igraph_vector)* v, BASE e);
+BASE FUNCTION(igraph_vector,pop_back)(TYPE(igraph_vector)* v);
+int FUNCTION(igraph_vector,insert)(TYPE(igraph_vector) *v, long int pos, BASE value);
+void FUNCTION(igraph_vector,remove)(TYPE(igraph_vector) *v, long int elem);
+void FUNCTION(igraph_vector,remove_section)(TYPE(igraph_vector) *v, 
+					    long int from, long int to);
+
+/*-----------*/
+/* Sorting   */             
+/*-----------*/
+
+void FUNCTION(igraph_vector,sort)(TYPE(igraph_vector) *v);
+long int FUNCTION(igraph_vector,qsort_ind)(TYPE(igraph_vector) *v, 
+					   igraph_vector_t *inds, igraph_bool_t descending);
+
+/*-----------*/
+/* Printing  */
+/*-----------*/
+
+int FUNCTION(igraph_vector,print)(const TYPE(igraph_vector) *v);
+int FUNCTION(igraph_vector,printf)(const TYPE(igraph_vector) *v,
+																	 const char *format);
+int FUNCTION(igraph_vector,fprint)(const TYPE(igraph_vector) *v, FILE *file);
+
+#ifdef BASE_COMPLEX
+
+int igraph_vector_complex_real(const igraph_vector_complex_t *v, 
+			       igraph_vector_t *real);
+int igraph_vector_complex_imag(const igraph_vector_complex_t *v, 
+			       igraph_vector_t *imag);
+int igraph_vector_complex_realimag(const igraph_vector_complex_t *v, 
+				   igraph_vector_t *real, 
+				   igraph_vector_t *imag);
+int igraph_vector_complex_create(igraph_vector_complex_t *v,
+				 const igraph_vector_t *real,
+				 const igraph_vector_t *imag);
+int igraph_vector_complex_create_polar(igraph_vector_complex_t *v,
+				       const igraph_vector_t *r,
+				       const igraph_vector_t *theta);
+
+#endif
+
+/* ----------------------------------------------------------------------------*/
+/* For internal use only, may be removed, rewritten ... */
+/* ----------------------------------------------------------------------------*/
+
+int FUNCTION(igraph_vector,init_real)(TYPE(igraph_vector)*v, int no, ...);
+int FUNCTION(igraph_vector,init_int)(TYPE(igraph_vector)*v, int no, ...);
+int FUNCTION(igraph_vector,init_real_end)(TYPE(igraph_vector)*v, BASE endmark, ...);
+int FUNCTION(igraph_vector,init_int_end)(TYPE(igraph_vector)*v, int endmark, ...);
+
+int FUNCTION(igraph_vector,move_interval)(TYPE(igraph_vector) *v, 
+					  long int begin, long int end, long int to);
+int FUNCTION(igraph_vector,move_interval2)(TYPE(igraph_vector) *v, 
+					  long int begin, long int end, long int to);
+void FUNCTION(igraph_vector,permdelete)(TYPE(igraph_vector) *v, 
+					const igraph_vector_t *index, 
+					long int nremove);
+int FUNCTION(igraph_vector,filter_smaller)(TYPE(igraph_vector) *v, BASE elem);
+int FUNCTION(igraph_vector,get_interval)(const TYPE(igraph_vector) *v, 
+					 TYPE(igraph_vector) *res,
+					 long int from, long int to);
+int FUNCTION(igraph_vector,difference_sorted)(const TYPE(igraph_vector) *v1,
+  const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result);
+int FUNCTION(igraph_vector,intersect_sorted)(const TYPE(igraph_vector) *v1,
+  const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result);
+
+int FUNCTION(igraph_vector,index)(const TYPE(igraph_vector) *v,
+                                  TYPE(igraph_vector) *newv,
+                                  const igraph_vector_t *idx);
+
+int FUNCTION(igraph_vector,index_int)(TYPE(igraph_vector) *v,
+				      const igraph_vector_int_t *idx);
diff --git a/include/igraph_vector_ptr.h b/include/igraph_vector_ptr.h
new file mode 100644
index 0000000..f606be4
--- /dev/null
+++ b/include/igraph_vector_ptr.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_VECTOR_PTR_H
+#define IGRAPH_VECTOR_PTR_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
+
+/* -------------------------------------------------- */
+/* Flexible vector, storing pointers                  */
+/* -------------------------------------------------- */
+
+/** 
+ * Vector, storing pointers efficiently
+ * \ingroup internal
+ * 
+ */
+typedef struct s_vector_ptr {
+  void** stor_begin;
+  void** stor_end;
+  void** end;
+  igraph_finally_func_t* item_destructor;
+} igraph_vector_ptr_t;
+
+#define IGRAPH_VECTOR_PTR_NULL { 0,0,0,0 }
+#define IGRAPH_VECTOR_PTR_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_vector_ptr_init(v, size)); \
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, v); } while (0)
+
+int igraph_vector_ptr_init      (igraph_vector_ptr_t* v, long int size);
+int igraph_vector_ptr_init_copy (igraph_vector_ptr_t* v, void** data, long int length);
+const igraph_vector_ptr_t *igraph_vector_ptr_view (const igraph_vector_ptr_t *v, 
+				     void *const *data, long int length);
+void igraph_vector_ptr_destroy   (igraph_vector_ptr_t* v);
+void igraph_vector_ptr_free_all   (igraph_vector_ptr_t* v);
+void igraph_vector_ptr_destroy_all   (igraph_vector_ptr_t* v);
+int igraph_vector_ptr_reserve   (igraph_vector_ptr_t* v, long int size);
+igraph_bool_t igraph_vector_ptr_empty     (const igraph_vector_ptr_t* v);
+long int igraph_vector_ptr_size      (const igraph_vector_ptr_t* v);
+void igraph_vector_ptr_clear     (igraph_vector_ptr_t* v);
+void igraph_vector_ptr_null      (igraph_vector_ptr_t* v);
+int igraph_vector_ptr_push_back (igraph_vector_ptr_t* v, void* e);
+int igraph_vector_ptr_append    (igraph_vector_ptr_t *to, 
+				 const igraph_vector_ptr_t *from);
+void *igraph_vector_ptr_pop_back (igraph_vector_ptr_t *v);
+int igraph_vector_ptr_insert(igraph_vector_ptr_t *v, long int pos, void* e);
+void* igraph_vector_ptr_e         (const igraph_vector_ptr_t* v, long int pos);
+void igraph_vector_ptr_set       (igraph_vector_ptr_t* v, long int pos, void* value);
+int igraph_vector_ptr_resize(igraph_vector_ptr_t* v, long int newsize);
+void igraph_vector_ptr_copy_to(const igraph_vector_ptr_t *v, void** to);
+int igraph_vector_ptr_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from);
+void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, long int pos);
+void igraph_vector_ptr_sort(igraph_vector_ptr_t *v, int(*compar)(const void*, const void*));
+int igraph_vector_ptr_index_int(igraph_vector_ptr_t *v,
+				const igraph_vector_int_t *idx);
+
+igraph_finally_func_t* igraph_vector_ptr_get_item_destructor(const igraph_vector_ptr_t *v);
+igraph_finally_func_t* igraph_vector_ptr_set_item_destructor(igraph_vector_ptr_t *v,
+        igraph_finally_func_t *func);
+
+/**
+ * \define IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR
+ * \brief Sets the item destructor for this pointer vector (macro version).
+ *
+ * This macro is expanded to \ref igraph_vector_ptr_set_item_destructor(), the
+ * only difference is that the second argument is automatically cast to an
+ * \c igraph_finally_func_t*. The cast is necessary in most cases as the
+ * destructor functions we use (such as \ref igraph_vector_destroy()) take a
+ * pointer to some concrete igraph data type, while \c igraph_finally_func_t
+ * expects \c void*
+ */
+#define IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(v, func) \
+        igraph_vector_ptr_set_item_destructor((v), (igraph_finally_func_t*)(func))
+
+__END_DECLS
+
+#endif
diff --git a/include/igraph_vector_type.h b/include/igraph_vector_type.h
new file mode 100644
index 0000000..b79015b
--- /dev/null
+++ b/include/igraph_vector_type.h
@@ -0,0 +1,34 @@
+/* -*- 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
+
+*/
+
+/** 
+ * Vector, dealing with arrays efficiently.
+ * \ingroup types
+ */
+
+typedef struct TYPE(igraph_vector) {
+  BASE* stor_begin;
+  BASE* stor_end;
+  BASE* end;
+} TYPE(igraph_vector);
+
diff --git a/include/igraph_version.h b/include/igraph_version.h
new file mode 100644
index 0000000..115951a
--- /dev/null
+++ b/include/igraph_version.h
@@ -0,0 +1,36 @@
+/* -*- 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 "0.7.1"
+
+int igraph_version(const char **version_string,
+		   int *major,
+		   int *minor,
+		   int *subminor);
+
+#endif
+
+
diff --git a/include/igraph_version.h.in b/include/igraph_version.h.in
new file mode 100644
index 0000000..64520a9
--- /dev/null
+++ b/include/igraph_version.h.in
@@ -0,0 +1,36 @@
+/* -*- 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 "@VERSION@"
+
+int igraph_version(const char **version_string,
+		   int *major,
+		   int *minor,
+		   int *subminor);
+
+#endif
+
+
diff --git a/include/igraph_visitor.h b/include/igraph_visitor.h
new file mode 100644
index 0000000..8abdcf7
--- /dev/null
+++ b/include/igraph_visitor.h
@@ -0,0 +1,141 @@
+/* -*- 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_VISITOR_H
+#define IGRAPH_VISITOR_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
+
+/* -------------------------------------------------- */
+/* Visitor-like functions                             */
+/* -------------------------------------------------- */
+
+/**
+ * \typedef igraph_bfshandler_t
+ * Callback type for BFS function
+ * 
+ * \ref igraph_bfs() is able to call a callback function, whenever a
+ * new vertex is found, while doing the breadth-first search. This
+ * callback function must be of type \c igraph_bfshandler_t. It has
+ * the following arguments:
+ * \param graph The graph that that algorithm is working on. Of course
+ *   this must not be modified.
+ * \param vid The id of the vertex just found by the breadth-first
+ *   search.
+ * \param pred The id of the previous vertex visited. It is -1 if
+ *   there is no previous vertex, because the current vertex is the root
+ *   is a search tree.
+ * \param succ The id of the next vertex that will be visited. It is
+ *   -1 if there is no next vertex, because the current vertex is the
+ *   last one in a search tree.
+ * \param rank The rank of the current vertex, it starts with zero.
+ * \param dist The distance (number of hops) of the current vertex
+ *   from the root of the current search tree.
+ * \param extra The extra argument that was passed to \ref
+ *   igraph_bfs().
+ * \return A logical value, if TRUE (=non-zero), that is interpreted
+ *    as a request to stop the BFS and return to the caller. If a BFS
+ *    is terminated like this, then all elements of the result vectors
+ *    that were not yet calculated at the point of the termination
+ *    contain \c IGRAPH_NAN.
+ * 
+ * \sa \ref igraph_bfs()
+ */
+
+typedef igraph_bool_t igraph_bfshandler_t(const igraph_t *graph,
+					  igraph_integer_t vid, 
+					  igraph_integer_t pred, 
+					  igraph_integer_t succ,
+					  igraph_integer_t rank,
+					  igraph_integer_t dist,
+					  void *extra);
+
+int igraph_bfs(const igraph_t *graph, 
+	       igraph_integer_t root, const igraph_vector_t *roots,
+	       igraph_neimode_t mode, igraph_bool_t unreachable,
+	       const igraph_vector_t *restricted,
+	       igraph_vector_t *order, igraph_vector_t *rank,
+	       igraph_vector_t *father,
+	       igraph_vector_t *pred, igraph_vector_t *succ,
+	       igraph_vector_t *dist, igraph_bfshandler_t *callback,
+	       void *extra);
+
+int igraph_i_bfs(igraph_t *graph, igraph_integer_t vid, igraph_neimode_t mode,
+		 igraph_vector_t *vids, igraph_vector_t *layers,
+		 igraph_vector_t *parents);
+
+/**
+ * \function igraph_dfshandler_t
+ * Callback type for the DFS function
+ * 
+ * \ref igraph_dfs() is able to call a callback function, whenever a
+ * new vertex is discovered, and/or whenever a subtree is
+ * completed. These callbacks must be of type \c
+ * igraph_dfshandler_t. They have the following arguments:
+ * \param graph The graph that that algorithm is working on. Of course
+ *   this must not be modified.
+ * \param vid The id of the vertex just found by the depth-first
+ *   search.
+ * \param dist The distance (number of hops) of the current vertex
+ *   from the root of the current search tree.
+ * \param extra The extra argument that was passed to \ref
+ *   igraph_dfs().
+ * \return A logical value, if TRUE (=non-zero), that is interpreted
+ *    as a request to stop the DFS and return to the caller. If a DFS
+ *    is terminated like this, then all elements of the result vectors
+ *    that were not yet calculated at the point of the termination
+ *    contain \c IGRAPH_NAN.
+ * 
+ * \sa \ref igraph_dfs()
+ */
+
+typedef igraph_bool_t igraph_dfshandler_t(const igraph_t *graph,
+					  igraph_integer_t vid, 
+					  igraph_integer_t dist,
+					  void *extra);
+
+int igraph_dfs(const igraph_t *graph, igraph_integer_t root,
+	       igraph_neimode_t mode, igraph_bool_t unreachable,
+	       igraph_vector_t *order,
+	       igraph_vector_t *order_out, igraph_vector_t *father,
+	       igraph_vector_t *dist, igraph_dfshandler_t *in_callback,
+	       igraph_dfshandler_t *out_callback,
+	       void *extra);
+
+__END_DECLS
+
+#endif
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..377bb86
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+	shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+	shift;;
+
+    -o) chowncmd="$chownprog $2"
+	shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+	# Protect names problematic for 'test' and other utilities.
+	case $dst_arg in
+	  -* | [=\(\)!]) dst_arg=./$dst_arg;;
+	esac
+	shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dst_arg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix='/';;
+	[-=\(\)!]*) prefix='./';;
+	*)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test X"$d" = X && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+	# Now remove or move aside any old file at destination location.
+	# We try this two ways since rm can't unlink itself on some
+	# systems and the destination file might be busy for other
+	# reasons.  In this case, the final cleanup might fail but the new
+	# file should still install successfully.
+	{
+	  test ! -f "$dst" ||
+	  $doit $rmcmd -f "$dst" 2>/dev/null ||
+	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+	  } ||
+	  { echo "$0: cannot unlink or rename $dst" >&2
+	    (exit 1); exit 1
+	  }
+	} &&
+
+	# Now rename the file to the real destination.
+	$doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100644
index 0000000..63ae69d
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,9655 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --no-warn            don't display warning messages
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:	$host
+#         shell:		$SHELL
+#         compiler:		$LTCC
+#         compiler flags:		$LTCFLAGS
+#         linker:		$LD (gnu? $with_gnu_ld)
+#         $progname:	(GNU libtool) 2.4.2
+#         automake:	$automake_version
+#         autoconf:	$autoconf_version
+#
+# Report bugs to <bug-libtool at gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.4.2
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+    # Extract subdirectory from the argument.
+    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+    case ${2} in
+      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+    esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+		s@/\./@/@g
+		t dotsl
+		s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "$1" | $SED \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case $1 in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $opt_debug
+
+    $SED -n '/(C)/!b go
+	:more
+	/\./!{
+	  N
+	  s/\n# / /
+	  b more
+	}
+	:go
+	/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+	:print
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+	p
+	d
+     }
+     /^# .* home page:/b print
+     /^# General help using/b print
+     ' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $opt_debug
+
+    func_error "missing argument for $1."
+    exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+    my_sed_long_arg='1s/^--[^=]*=//'
+
+    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+    eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+    func_quote_for_eval "${2}"
+    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+    func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+  shift; set dummy --mode clean ${1+"$@"}; shift
+  ;;
+compile|compil|compi|comp|com|co|c)
+  shift; set dummy --mode compile ${1+"$@"}; shift
+  ;;
+execute|execut|execu|exec|exe|ex|e)
+  shift; set dummy --mode execute ${1+"$@"}; shift
+  ;;
+finish|finis|fini|fin|fi|f)
+  shift; set dummy --mode finish ${1+"$@"}; shift
+  ;;
+install|instal|insta|inst|ins|in|i)
+  shift; set dummy --mode install ${1+"$@"}; shift
+  ;;
+link|lin|li|l)
+  shift; set dummy --mode link ${1+"$@"}; shift
+  ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+  shift; set dummy --mode uninstall ${1+"$@"}; shift
+  ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly.  This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+  # this just eases exit handling
+  while test $# -gt 0; do
+    opt="$1"
+    shift
+    case $opt in
+      --debug|-x)	opt_debug='set -x'
+			func_echo "enabling shell trace mode"
+			$opt_debug
+			;;
+      --dry-run|--dryrun|-n)
+			opt_dry_run=:
+			;;
+      --config)
+			opt_config=:
+func_config
+			;;
+      --dlopen|-dlopen)
+			optarg="$1"
+			opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+			shift
+			;;
+      --preserve-dup-deps)
+			opt_preserve_dup_deps=:
+			;;
+      --features)
+			opt_features=:
+func_features
+			;;
+      --finish)
+			opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+			;;
+      --help)
+			opt_help=:
+			;;
+      --help-all)
+			opt_help_all=:
+opt_help=': help-all'
+			;;
+      --mode)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_mode="$optarg"
+case $optarg in
+  # Valid mode arguments:
+  clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+  # Catch anything else as an error
+  *) func_error "invalid argument for $opt"
+     exit_cmd=exit
+     break
+     ;;
+esac
+			shift
+			;;
+      --no-silent|--no-quiet)
+			opt_silent=false
+func_append preserve_args " $opt"
+			;;
+      --no-warning|--no-warn)
+			opt_warning=false
+func_append preserve_args " $opt"
+			;;
+      --no-verbose)
+			opt_verbose=false
+func_append preserve_args " $opt"
+			;;
+      --silent|--quiet)
+			opt_silent=:
+func_append preserve_args " $opt"
+        opt_verbose=false
+			;;
+      --verbose|-v)
+			opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+			;;
+      --tag)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+			shift
+			;;
+
+      -\?|-h)		func_usage				;;
+      --help)		func_help				;;
+      --version)	func_version				;;
+
+      # Separate optargs to long options:
+      --*=*)
+			func_split_long_opt "$opt"
+			set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      # Separate non-argument short options:
+      -\?*|-h*|-n*|-v*)
+			func_split_short_opt "$opt"
+			set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      --)		break					;;
+      -*)		func_fatal_help "unrecognized option \`$opt'" ;;
+      *)		set dummy "$opt" ${1+"$@"};	shift; break  ;;
+    esac
+  done
+
+  # Validate options:
+
+  # save first non-option argument
+  if test "$#" -gt 0; then
+    nonopt="$opt"
+    shift
+  fi
+
+  # preserve --debug
+  test "$opt_debug" = : || func_append preserve_args " --debug"
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+      ;;
+  esac
+
+  $opt_help || {
+    # Sanity checks first:
+    func_check_version_match
+
+    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+      func_fatal_configuration "not configured to build any kind of library"
+    fi
+
+    # Darwin sucks
+    eval std_shrext=\"$shrext_cmds\"
+
+    # Only execute mode is allowed to have -dlopen flags.
+    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+      func_error "unrecognized option \`-dlopen'"
+      $ECHO "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Change the help message to a mode-specific one.
+    generic_help="$help"
+    help="Try \`$progname --help --mode=$opt_mode' for more information."
+  }
+
+
+  # Bail if the options were screwed
+  $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case "$lt_sysroot:$1" in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result="=$func_stripname_result"
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $opt_debug
+  func_convert_core_file_wine_to_w32_result="$1"
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=""
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $opt_debug
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result="$1"
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result="$3"
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $opt_debug
+  case $4 in
+  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $opt_debug
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $opt_debug
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $opt_debug
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "\`$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument \`$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the \`$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=""
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname" ; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename="$func_basename_result"
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename" ; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      func_to_tool_file "$1" func_convert_file_msys_to_w32
+      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test "$fast_install" = yes; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+	{
+EOF
+	    case "$host" in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (strcmp (argv[i], debug_opt) == 0)
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+		    "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+	    cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+	    cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+		  nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+		      i, nonnull (newargz[i]));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+		      "(main) failed to launch target \"%s\": %s\n",
+		      lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir="$arg"
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps ; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      else
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    deplibs="$deplib $deplibs"
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test "$prefer_static_libs" = yes ||
+	     test "$prefer_static_libs,$installed" = "built,no"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib="$l"
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$lt_sysroot$libdir"
+	    absdir="$lt_sysroot$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  case "$host" in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    echo
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$opt_mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$absdir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$opt_mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|qnx|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_append libobjs " $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$opt_mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    func_append newdeplibs " $i"
+		    i=""
+		    ;;
+		  esac
+		fi
+		if test -n "$i" ; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    func_append newdeplibs " $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      func_append newdeplibs " $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      func_append newdeplibs " $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		if test -n "$file_magic_glob"; then
+		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+		else
+		  libnameglob=$libname
+		fi
+		test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  if test "$want_nocaseglob" = yes; then
+		    shopt -s nocaseglob
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	# Remove ${wl} instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS="$save_ifs"
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test "$try_normal_branch" = yes \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=${output_objdir}/${output_la}.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$opt_mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$opt_mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " ${wl}-bind_at_load"
+	      func_append finalize_command " ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    func_append oldobjs " $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		func_resolve_sysroot "$deplib"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test "x$bindir" != x ;
+	      then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=yes ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	odir="$objdir"
+      else
+	odir="$dir/$objdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$opt_mode" = uninstall && odir="$dir"
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test "$opt_mode" = clean; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case "$opt_mode" in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$opt_mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      func_append rmfiles " $odir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/missing b/missing
new file mode 100755
index 0000000..cdea514
--- /dev/null
+++ b/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2012-06-26.16; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
+
+# 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, 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/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake at gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'automa4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/optional/glpk/amd/amd.h b/optional/glpk/amd/amd.h
new file mode 100644
index 0000000..be662d9
--- /dev/null
+++ b/optional/glpk/amd/amd.h
@@ -0,0 +1,67 @@
+/* amd.h */
+
+/* Written by Andrew Makhorin <mao at gnu.org>. */
+
+#ifndef GLPAMD_H
+#define GLPAMD_H
+
+#define AMD_DATE "May 31, 2007"
+#define AMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
+#define AMD_MAIN_VERSION 2
+#define AMD_SUB_VERSION 2
+#define AMD_SUBSUB_VERSION 0
+#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION, AMD_SUB_VERSION)
+
+#define AMD_CONTROL 5
+#define AMD_INFO 20
+
+#define AMD_DENSE 0
+#define AMD_AGGRESSIVE 1
+
+#define AMD_DEFAULT_DENSE 10.0
+#define AMD_DEFAULT_AGGRESSIVE 1
+
+#define AMD_STATUS         0
+#define AMD_N              1
+#define AMD_NZ             2
+#define AMD_SYMMETRY       3
+#define AMD_NZDIAG         4
+#define AMD_NZ_A_PLUS_AT   5
+#define AMD_NDENSE         6
+#define AMD_MEMORY         7
+#define AMD_NCMPA          8
+#define AMD_LNZ            9
+#define AMD_NDIV           10
+#define AMD_NMULTSUBS_LDL  11
+#define AMD_NMULTSUBS_LU   12
+#define AMD_DMAX           13
+
+#define AMD_OK             0
+#define AMD_OUT_OF_MEMORY  (-1)
+#define AMD_INVALID        (-2)
+#define AMD_OK_BUT_JUMBLED 1
+
+#define amd_order _glp_amd_order
+int amd_order(int n, const int Ap[], const int Ai[], int P[],
+      double Control[], double Info[]);
+
+#define amd_2 _glp_amd_2
+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[]);
+
+#define amd_valid _glp_amd_valid
+int amd_valid(int n_row, int n_col, const int Ap[], const int Ai[]);
+
+#define amd_defaults _glp_amd_defaults
+void amd_defaults(double Control[]);
+
+#define amd_control _glp_amd_control
+void amd_control(double Control[]);
+
+#define amd_info _glp_amd_info
+void amd_info(double Info[]);
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/amd/amd_1.c b/optional/glpk/amd/amd_1.c
new file mode 100644
index 0000000..4f9b07d
--- /dev/null
+++ b/optional/glpk/amd/amd_1.c
@@ -0,0 +1,181 @@
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_2.c b/optional/glpk/amd/amd_2.c
new file mode 100644
index 0000000..490b967
--- /dev/null
+++ b/optional/glpk/amd/amd_2.c
@@ -0,0 +1,1844 @@
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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.
+ */
+
+#pragma clang diagnostic ignored "-Wconversion"
+
+#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 UF_long versions are provided.  In the descriptions below
+ *      and integer is and int or UF_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, UF_long_max - n for the
+ *                  UF_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/optional/glpk/amd/amd_aat.c b/optional/glpk/amd/amd_aat.c
new file mode 100644
index 0000000..1b336c7
--- /dev/null
+++ b/optional/glpk/amd/amd_aat.c
@@ -0,0 +1,187 @@
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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).
+ */
+
+#pragma clang diagnostic ignored "-Wsign-conversion"
+
+#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/optional/glpk/amd/amd_control.c b/optional/glpk/amd/amd_control.c
new file mode 100644
index 0000000..f4d4f0d
--- /dev/null
+++ b/optional/glpk/amd/amd_control.c
@@ -0,0 +1,64 @@
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_defaults.c b/optional/glpk/amd/amd_defaults.c
new file mode 100644
index 0000000..820e894
--- /dev/null
+++ b/optional/glpk/amd/amd_defaults.c
@@ -0,0 +1,38 @@
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_dump.c b/optional/glpk/amd/amd_dump.c
new file mode 100644
index 0000000..39bbe1d
--- /dev/null
+++ b/optional/glpk/amd/amd_dump.c
@@ -0,0 +1,180 @@
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_info.c b/optional/glpk/amd/amd_info.c
new file mode 100644
index 0000000..e7b806a
--- /dev/null
+++ b/optional/glpk/amd/amd_info.c
@@ -0,0 +1,120 @@
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_internal.h b/optional/glpk/amd/amd_internal.h
new file mode 100644
index 0000000..a9951a8
--- /dev/null
+++ b/optional/glpk/amd/amd_internal.h
@@ -0,0 +1,117 @@
+/* amd_internal.h */
+
+/* Written by Andrew Makhorin <mao at gnu.org>. */
+
+#ifndef AMD_INTERNAL_H
+#define AMD_INTERNAL_H
+
+/* AMD will be exceedingly slow when running in debug mode. */
+#if 1
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+#endif
+
+#include "amd.h"
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ((size_t)(-1))
+#endif
+
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define IMPLIES(p, q) (!(p) || (q))
+
+#define GLOBAL
+
+#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
+
+#define amd_malloc xmalloc
+#if 0 /* 24/V-2009 */
+#define amd_free xfree
+#else
+#define amd_free(ptr) { if ((ptr) != NULL) xfree(ptr); } 
+#endif
+#define amd_printf xprintf
+
+#define PRINTF(params) { amd_printf params; }
+
+#ifndef NDEBUG
+#define ASSERT(expr) xassert(expr)
+#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
+#define ASSERT(expression)
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+#endif
+
+#define amd_aat _glp_amd_aat
+size_t AMD_aat(Int n, const Int Ap[], const Int Ai[], Int Len[],
+      Int Tp[], double Info[]);
+
+#define amd_1 _glp_amd_1
+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[]);
+
+#define amd_postorder _glp_amd_postorder
+void AMD_postorder(Int nn, Int Parent[], Int Npiv[], Int Fsize[],
+      Int Order[], Int Child[], Int Sibling[], Int Stack[]);
+
+#define amd_post_tree _glp_amd_post_tree
+#ifndef NDEBUG
+Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
+      Int Order[], Int Stack[], Int nn);
+#else
+Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
+      Int Order[], Int Stack[]);
+#endif
+
+#define amd_preprocess _glp_amd_preprocess
+void AMD_preprocess(Int n, const Int Ap[], const Int Ai[], Int Rp[],
+      Int Ri[], Int W[], Int Flag[]);
+
+#define amd_debug _glp_amd_debug
+extern Int AMD_debug;
+
+#define amd_debug_init _glp_amd_debug_init
+void AMD_debug_init(char *s);
+
+#define amd_dump _glp_amd_dump
+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);
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/amd/amd_order.c b/optional/glpk/amd/amd_order.c
new file mode 100644
index 0000000..53d2e55
--- /dev/null
+++ b/optional/glpk/amd/amd_order.c
@@ -0,0 +1,203 @@
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine.  See amd.h for
+ * documentation.
+ */
+
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+
+#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/optional/glpk/amd/amd_post_tree.c b/optional/glpk/amd/amd_post_tree.c
new file mode 100644
index 0000000..bff0e26
--- /dev/null
+++ b/optional/glpk/amd/amd_post_tree.c
@@ -0,0 +1,121 @@
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_postorder.c b/optional/glpk/amd/amd_postorder.c
new file mode 100644
index 0000000..a3ece91
--- /dev/null
+++ b/optional/glpk/amd/amd_postorder.c
@@ -0,0 +1,207 @@
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_preprocess.c b/optional/glpk/amd/amd_preprocess.c
new file mode 100644
index 0000000..fc223fb
--- /dev/null
+++ b/optional/glpk/amd/amd_preprocess.c
@@ -0,0 +1,119 @@
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/amd/amd_valid.c b/optional/glpk/amd/amd_valid.c
new file mode 100644
index 0000000..e9e2e5a
--- /dev/null
+++ b/optional/glpk/amd/amd_valid.c
@@ -0,0 +1,93 @@
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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/optional/glpk/colamd/colamd.c b/optional/glpk/colamd/colamd.c
new file mode 100644
index 0000000..817bd06
--- /dev/null
+++ b/optional/glpk/colamd/colamd.c
@@ -0,0 +1,3625 @@
+/* ========================================================================== */
+/* === 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 (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.
+
+    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.cise.ufl.edu/research/sparse/colamd/
+
+        This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
+        file.  It requires the colamd.h file.  It is required by the colamdmex.c
+        and symamdmex.c files, for the MATLAB interface to colamd and symamd.
+        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 UF_long versions of all its routines.  The
+ * description below is for the int version.  For UF_long, all int arguments
+ * become UF_long.  UF_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 (UF_long nnz, UF_long n_row,
+                UF_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]) ;
+            UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
+                UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
+                UF_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 http://www.cise.ufl.edu/research/sparse/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 *)) ;
+            UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
+                double knobs [COLAMD_KNOBS], UF_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 (UF_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 (UF_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 ======================================================== */
+/* ========================================================================== */
+
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+
+#include "colamd.h"
+
+#if 0 /* by mao */
+#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
+#endif
+
+/* ========================================================================== */
+/* === int or UF_long ======================================================= */
+/* ========================================================================== */
+
+#if 0 /* by mao */
+/* define UF_long */
+#include "UFconfig.h"
+#endif
+
+#ifdef DLONG
+
+#define Int UF_long
+#define ID  UF_long_id
+#define Int_MAX UF_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
+
+#if 0 /* by mao */
+#include <assert.h>
+#endif
+
+/* 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) ; }
+
+#if 0 /* by mao */
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif /* MATLAB_MEX_FILE */
+#else
+#define ASSERT xassert
+#endif
+
+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/optional/glpk/colamd/colamd.h b/optional/glpk/colamd/colamd.h
new file mode 100644
index 0000000..ced46c7
--- /dev/null
+++ b/optional/glpk/colamd/colamd.h
@@ -0,0 +1,69 @@
+/* colamd.h */
+
+/* Written by Andrew Makhorin <mao at gnu.org>. */
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+
+#define COLAMD_DATE "Nov 1, 2007"
+#define COLAMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
+#define COLAMD_MAIN_VERSION 2
+#define COLAMD_SUB_VERSION 7
+#define COLAMD_SUBSUB_VERSION 1
+#define COLAMD_VERSION \
+        COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION)
+
+#define COLAMD_KNOBS 20
+#define COLAMD_STATS 20
+#define COLAMD_DENSE_ROW 0
+#define COLAMD_DENSE_COL 1
+#define COLAMD_AGGRESSIVE 2
+#define COLAMD_DEFRAG_COUNT 2
+#define COLAMD_STATUS 3
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+#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)
+
+#define colamd_recommended _glp_colamd_recommended
+size_t colamd_recommended(int nnz, int n_row, int n_col);
+
+#define colamd_set_defaults _glp_colamd_set_defaults
+void colamd_set_defaults(double knobs [COLAMD_KNOBS]);
+
+#define colamd _glp_colamd
+int colamd(int n_row, int n_col, int Alen, int A[], int p[],
+      double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS]);
+
+#define symamd _glp_symamd
+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 *));
+
+#define colamd_report _glp_colamd_report
+void colamd_report(int stats[COLAMD_STATS]);
+
+#define symamd_report _glp_symamd_report
+void symamd_report(int stats[COLAMD_STATS]);
+
+#define colamd_printf xprintf
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpapi.h b/optional/glpk/glpapi.h
new file mode 100644
index 0000000..290ecd9
--- /dev/null
+++ b/optional/glpk/glpapi.h
@@ -0,0 +1,314 @@
+/* glpapi.h (application program interface) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPAPI_H
+#define GLPAPI_H
+
+#define GLP_PROB_DEFINED
+typedef struct glp_prob glp_prob;
+
+#include "glpk.h"
+#include "glpavl.h"
+#include "glpbfd.h"
+
+typedef struct GLPROW GLPROW;
+typedef struct GLPCOL GLPCOL;
+typedef struct GLPAIJ GLPAIJ;
+
+#define GLP_PROB_MAGIC 0xD7D9D6C2
+
+struct glp_prob
+{     /* LP/MIP problem object */
+      int magic;
+      /* magic value used for debugging */
+      DMP *pool;
+      /* memory pool to store problem object components */
+      glp_tree *tree;
+      /* pointer to the search tree; set by the MIP solver when this
+         object is used in the tree as a core MIP object */
+      void *parms;
+      /* reserved for backward compatibility */
+      /*--------------------------------------------------------------*/
+      /* LP/MIP data */
+      char *name;
+      /* problem name (1 to 255 chars); NULL means no name is assigned
+         to the problem */
+      char *obj;
+      /* objective function name (1 to 255 chars); NULL means no name
+         is assigned to the objective function */
+      int dir;
+      /* optimization direction flag (objective "sense"):
+         GLP_MIN - minimization
+         GLP_MAX - maximization */
+      double c0;
+      /* constant term of the objective function ("shift") */
+      int m_max;
+      /* length of the array of rows (enlarged automatically) */
+      int n_max;
+      /* length of the array of columns (enlarged automatically) */
+      int m;
+      /* number of rows, 0 <= m <= m_max */
+      int n;
+      /* number of columns, 0 <= n <= n_max */
+      int nnz;
+      /* number of non-zero constraint coefficients, nnz >= 0 */
+      GLPROW **row; /* GLPROW *row[1+m_max]; */
+      /* row[i], 1 <= i <= m, is a pointer to i-th row */
+      GLPCOL **col; /* GLPCOL *col[1+n_max]; */
+      /* col[j], 1 <= j <= n, is a pointer to j-th column */
+      AVL *r_tree;
+      /* row index to find rows by their names; NULL means this index
+         does not exist */
+      AVL *c_tree;
+      /* column index to find columns by their names; NULL means this
+         index does not exist */
+      /*--------------------------------------------------------------*/
+      /* basis factorization (LP) */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      int *head; /* int head[1+m_max]; */
+      /* basis header (valid only if the factorization is valid);
+         head[i] = k is the ordinal number of auxiliary (1 <= k <= m)
+         or structural (m+1 <= k <= m+n) variable which corresponds to
+         i-th basic variable xB[i], 1 <= i <= m */
+      glp_bfcp *bfcp;
+      /* basis factorization control parameters; may be NULL */
+      BFD *bfd; /* BFD bfd[1:m,1:m]; */
+      /* basis factorization driver; may be NULL */
+      /*--------------------------------------------------------------*/
+      /* basic solution (LP) */
+      int pbs_stat;
+      /* primal basic solution status:
+         GLP_UNDEF  - primal solution is undefined
+         GLP_FEAS   - primal solution is feasible
+         GLP_INFEAS - primal solution is infeasible
+         GLP_NOFEAS - no primal feasible solution exists */
+      int dbs_stat;
+      /* dual basic solution status:
+         GLP_UNDEF  - dual solution is undefined
+         GLP_FEAS   - dual solution is feasible
+         GLP_INFEAS - dual solution is infeasible
+         GLP_NOFEAS - no dual feasible solution exists */
+      double obj_val;
+      /* objective function value */
+      int it_cnt;
+      /* simplex method iteration count; increased by one on performing
+         one simplex iteration */
+      int some;
+      /* ordinal number of some auxiliary or structural variable having
+         certain property, 0 <= some <= m+n */
+      /*--------------------------------------------------------------*/
+      /* interior-point solution (LP) */
+      int ipt_stat;
+      /* interior-point solution status:
+         GLP_UNDEF  - interior solution is undefined
+         GLP_OPT    - interior solution is optimal
+         GLP_INFEAS - interior solution is infeasible
+         GLP_NOFEAS - no feasible solution exists */
+      double ipt_obj;
+      /* objective function value */
+      /*--------------------------------------------------------------*/
+      /* integer solution (MIP) */
+      int mip_stat;
+      /* integer solution status:
+         GLP_UNDEF  - integer solution is undefined
+         GLP_OPT    - integer solution is optimal
+         GLP_FEAS   - integer solution is feasible
+         GLP_NOFEAS - no integer solution exists */
+      double mip_obj;
+      /* objective function value */
+};
+
+struct GLPROW
+{     /* LP/MIP row (auxiliary variable) */
+      int i;
+      /* ordinal number (1 to m) assigned to this row */
+      char *name;
+      /* row name (1 to 255 chars); NULL means no name is assigned to
+         this row */
+      AVLNODE *node;
+      /* pointer to corresponding node in the row index; NULL means
+         that either the row index does not exist or this row has no
+         name assigned */
+#if 1 /* 20/IX-2008 */
+      int level;
+      unsigned char origin;
+      unsigned char klass;
+#endif
+      int type;
+      /* type of the auxiliary variable:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double lb; /* non-scaled */
+      /* lower bound; if the row has no lower bound, lb is zero */
+      double ub; /* non-scaled */
+      /* upper bound; if the row has no upper bound, ub is zero */
+      /* if the row type is GLP_FX, ub is equal to lb */
+      GLPAIJ *ptr; /* non-scaled */
+      /* pointer to doubly linked list of constraint coefficients which
+         are placed in this row */
+      double rii;
+      /* diagonal element r[i,i] of scaling matrix R for this row;
+         if the scaling is not used, r[i,i] is 1 */
+      int stat;
+      /* status of the auxiliary variable:
+         GLP_BS - basic variable
+         GLP_NL - non-basic variable on lower bound
+         GLP_NU - non-basic variable on upper bound
+         GLP_NF - non-basic free variable
+         GLP_NS - non-basic fixed variable */
+      int bind;
+      /* if the auxiliary variable is basic, head[bind] refers to this
+         row, otherwise, bind is 0; this attribute is valid only if the
+         basis factorization is valid */
+      double prim; /* non-scaled */
+      /* primal value of the auxiliary variable in basic solution */
+      double dual; /* non-scaled */
+      /* dual value of the auxiliary variable in basic solution */
+      double pval; /* non-scaled */
+      /* primal value of the auxiliary variable in interior solution */
+      double dval; /* non-scaled */
+      /* dual value of the auxiliary variable in interior solution */
+      double mipx; /* non-scaled */
+      /* primal value of the auxiliary variable in integer solution */
+};
+
+struct GLPCOL
+{     /* LP/MIP column (structural variable) */
+      int j;
+      /* ordinal number (1 to n) assigned to this column */
+      char *name;
+      /* column name (1 to 255 chars); NULL means no name is assigned
+         to this column */
+      AVLNODE *node;
+      /* pointer to corresponding node in the column index; NULL means
+         that either the column index does not exist or the column has
+         no name assigned */
+      int kind;
+      /* kind of the structural variable:
+         GLP_CV - continuous variable
+         GLP_IV - integer or binary variable */
+      int type;
+      /* type of the structural variable:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double lb; /* non-scaled */
+      /* lower bound; if the column has no lower bound, lb is zero */
+      double ub; /* non-scaled */
+      /* upper bound; if the column has no upper bound, ub is zero */
+      /* if the column type is GLP_FX, ub is equal to lb */
+      double coef; /* non-scaled */
+      /* objective coefficient at the structural variable */
+      GLPAIJ *ptr; /* non-scaled */
+      /* pointer to doubly linked list of constraint coefficients which
+         are placed in this column */
+      double sjj;
+      /* diagonal element s[j,j] of scaling matrix S for this column;
+         if the scaling is not used, s[j,j] is 1 */
+      int stat;
+      /* status of the structural variable:
+         GLP_BS - basic variable
+         GLP_NL - non-basic variable on lower bound
+         GLP_NU - non-basic variable on upper bound
+         GLP_NF - non-basic free variable
+         GLP_NS - non-basic fixed variable */
+      int bind;
+      /* if the structural variable is basic, head[bind] refers to
+         this column; otherwise, bind is 0; this attribute is valid only
+         if the basis factorization is valid */
+      double prim; /* non-scaled */
+      /* primal value of the structural variable in basic solution */
+      double dual; /* non-scaled */
+      /* dual value of the structural variable in basic solution */
+      double pval; /* non-scaled */
+      /* primal value of the structural variable in interior solution */
+      double dval; /* non-scaled */
+      /* dual value of the structural variable in interior solution */
+      double mipx; /* non-scaled */
+      /* primal value of the structural variable in integer solution */
+};
+
+struct GLPAIJ
+{     /* constraint coefficient a[i,j] */
+      GLPROW *row;
+      /* pointer to row, where this coefficient is placed */
+      GLPCOL *col;
+      /* pointer to column, where this coefficient is placed */
+      double val;
+      /* numeric (non-zero) value of this coefficient */
+      GLPAIJ *r_prev;
+      /* pointer to previous coefficient in the same row */
+      GLPAIJ *r_next;
+      /* pointer to next coefficient in the same row */
+      GLPAIJ *c_prev;
+      /* pointer to previous coefficient in the same column */
+      GLPAIJ *c_next;
+      /* pointer to next coefficient in the same column */
+};
+
+void _glp_check_kkt(glp_prob *P, int sol, int cond, double *ae_max,
+      int *ae_ind, double *re_max, int *re_ind);
+/* check feasibility and optimality conditions */
+
+#define lpx_put_solution _glp_put_solution
+void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
+      const int *d_stat, const double *obj_val, const int r_stat[],
+      const double r_prim[], const double r_dual[], const int c_stat[],
+      const double c_prim[], const double c_dual[]);
+/* store basic solution components */
+
+#define lpx_put_mip_soln _glp_put_mip_soln
+void lpx_put_mip_soln(LPX *lp, int i_stat, double row_mipx[],
+      double col_mipx[]);
+/* store mixed integer solution components */
+
+#if 1 /* 28/XI-2009 */
+int _glp_analyze_row(glp_prob *P, int len, const int ind[],
+      const double val[], int type, double rhs, double eps, int *_piv,
+      double *_x, double *_dx, double *_y, double *_dy, double *_dz);
+/* simulate one iteration of dual simplex method */
+#endif
+
+#if 1 /* 08/XII-2009 */
+void _glp_mpl_init_rand(glp_tran *tran, int seed);
+#endif
+
+#define glp_skpgen _glp_skpgen
+void glp_skpgen(int n, int r, int type, int v, int s, int a[],
+   int *b, int c[]);
+/* Pisinger's 0-1 single knapsack problem generator */
+
+#if 1 /* 28/V-2010 */
+int _glp_intopt1(glp_prob *P, const glp_iocp *parm);
+#endif
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpapi01.c b/optional/glpk/glpapi01.c
new file mode 100644
index 0000000..295cbd4
--- /dev/null
+++ b/optional/glpk/glpapi01.c
@@ -0,0 +1,1575 @@
+/* glpapi01.c (problem creating and modifying routines) */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glpios.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal number of rows in the problem object */
+
+#define N_MAX 100000000 /* = 100*10^6 */
+/* maximal number of columns in the problem object */
+
+#define NNZ_MAX 500000000 /* = 500*10^6 */
+/* maximal number of constraint coefficients in the problem object */
+
+/***********************************************************************
+*  NAME
+*
+*  glp_create_prob - create problem object
+*
+*  SYNOPSIS
+*
+*  glp_prob *glp_create_prob(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_create_prob creates a new problem object, which is
+*  initially "empty", i.e. has no rows and columns.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the object created, which should be
+*  used in any subsequent operations on this object. */
+
+static void create_prob(glp_prob *lp)
+{     lp->magic = GLP_PROB_MAGIC;
+      lp->pool = dmp_create_pool();
+#if 0 /* 17/XI-2009 */
+      lp->cps = xmalloc(sizeof(struct LPXCPS));
+      lpx_reset_parms(lp);
+#else
+      lp->parms = NULL;
+#endif
+      lp->tree = NULL;
+#if 0
+      lp->lwa = 0;
+      lp->cwa = NULL;
+#endif
+      /* LP/MIP data */
+      lp->name = NULL;
+      lp->obj = NULL;
+      lp->dir = GLP_MIN;
+      lp->c0 = 0.0;
+      lp->m_max = 100;
+      lp->n_max = 200;
+      lp->m = lp->n = 0;
+      lp->nnz = 0;
+      lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
+      lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
+      lp->r_tree = lp->c_tree = NULL;
+      /* basis factorization */
+      lp->valid = 0;
+      lp->head = xcalloc(1+lp->m_max, sizeof(int));
+      lp->bfcp = NULL;
+      lp->bfd = NULL;
+      /* basic solution (LP) */
+      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+      lp->obj_val = 0.0;
+      lp->it_cnt = 0;
+      lp->some = 0;
+      /* interior-point solution (LP) */
+      lp->ipt_stat = GLP_UNDEF;
+      lp->ipt_obj = 0.0;
+      /* integer solution (MIP) */
+      lp->mip_stat = GLP_UNDEF;
+      lp->mip_obj = 0.0;
+      return;
+}
+
+glp_prob *glp_create_prob(void)
+{     glp_prob *lp;
+      lp = xmalloc(sizeof(glp_prob));
+      create_prob(lp);
+      return lp;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_prob_name - assign (change) problem name
+*
+*  SYNOPSIS
+*
+*  void glp_set_prob_name(glp_prob *lp, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_prob_name assigns a given symbolic name (1 up to
+*  255 characters) to the specified problem object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing symbolic name of the problem object. */
+
+void glp_set_prob_name(glp_prob *lp, const char *name)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_prob_name: operation not allowed\n");
+      if (lp->name != NULL)
+      {  dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1);
+         lp->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_prob_name: problem name too long\n");
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_prob_name: problem name contains invalid"
+                  " character(s)\n");
+         }
+         lp->name = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(lp->name, name);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_obj_name - assign (change) objective function name
+*
+*  SYNOPSIS
+*
+*  void glp_set_obj_name(glp_prob *lp, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_obj_name assigns a given symbolic name (1 up to
+*  255 characters) to the objective function of the specified problem
+*  object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing name of the objective function. */
+
+void glp_set_obj_name(glp_prob *lp, const char *name)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_obj_name: operation not allowed\n");
+     if (lp->obj != NULL)
+      {  dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1);
+         lp->obj = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_obj_name: objective name too long\n");
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_obj_name: objective name contains invali"
+                  "d character(s)\n");
+         }
+         lp->obj = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(lp->obj, name);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_obj_dir - set (change) optimization direction flag
+*
+*  SYNOPSIS
+*
+*  void glp_set_obj_dir(glp_prob *lp, int dir);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_obj_dir sets (changes) optimization direction
+*  flag (i.e. "sense" of the objective function) as specified by the
+*  parameter dir:
+*
+*  GLP_MIN - minimization;
+*  GLP_MAX - maximization. */
+
+void glp_set_obj_dir(glp_prob *lp, int dir)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_obj_dir: operation not allowed\n");
+     if (!(dir == GLP_MIN || dir == GLP_MAX))
+         xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n",
+            dir);
+      lp->dir = dir;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_rows - add new rows to problem object
+*
+*  SYNOPSIS
+*
+*  int glp_add_rows(glp_prob *lp, int nrs);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_rows adds nrs rows (constraints) to the specified
+*  problem object. New rows are always added to the end of the row list,
+*  so the ordinal numbers of existing rows remain unchanged.
+*
+*  Being added each new row is initially free (unbounded) and has empty
+*  list of the constraint coefficients.
+*
+*  RETURNS
+*
+*  The routine glp_add_rows returns the ordinal number of the first new
+*  row added to the problem object. */
+
+int glp_add_rows(glp_prob *lp, int nrs)
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      int m_new, i;
+      /* determine new number of rows */
+      if (nrs < 1)
+         xerror("glp_add_rows: nrs = %d; invalid number of rows\n",
+            nrs);
+      if (nrs > M_MAX - lp->m)
+         xerror("glp_add_rows: nrs = %d; too many rows\n", nrs);
+      m_new = lp->m + nrs;
+      /* increase the room, if necessary */
+      if (lp->m_max < m_new)
+      {  GLPROW **save = lp->row;
+         while (lp->m_max < m_new)
+         {  lp->m_max += lp->m_max;
+            xassert(lp->m_max > 0);
+         }
+         lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
+         memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *));
+         xfree(save);
+         /* do not forget about the basis header */
+         xfree(lp->head);
+         lp->head = xcalloc(1+lp->m_max, sizeof(int));
+      }
+      /* add new rows to the end of the row list */
+      for (i = lp->m+1; i <= m_new; i++)
+      {  /* create row descriptor */
+         lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW));
+         row->i = i;
+         row->name = NULL;
+         row->node = NULL;
+#if 1 /* 20/IX-2008 */
+         row->level = 0;
+         row->origin = 0;
+         row->klass = 0;
+         if (tree != NULL)
+         {  switch (tree->reason)
+            {  case 0:
+                  break;
+               case GLP_IROWGEN:
+                  xassert(tree->curr != NULL);
+                  row->level = tree->curr->level;
+                  row->origin = GLP_RF_LAZY;
+                  break;
+               case GLP_ICUTGEN:
+                  xassert(tree->curr != NULL);
+                  row->level = tree->curr->level;
+                  row->origin = GLP_RF_CUT;
+                  break;
+               default:
+                  xassert(tree != tree);
+            }
+         }
+#endif
+         row->type = GLP_FR;
+         row->lb = row->ub = 0.0;
+         row->ptr = NULL;
+         row->rii = 1.0;
+         row->stat = GLP_BS;
+#if 0
+         row->bind = -1;
+#else
+         row->bind = 0;
+#endif
+         row->prim = row->dual = 0.0;
+         row->pval = row->dval = 0.0;
+         row->mipx = 0.0;
+      }
+      /* set new number of rows */
+      lp->m = m_new;
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+#if 1
+      if (tree != NULL && tree->reason != 0) tree->reopt = 1;
+#endif
+      /* return the ordinal number of the first row added */
+      return m_new - nrs + 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_cols - add new columns to problem object
+*
+*  SYNOPSIS
+*
+*  int glp_add_cols(glp_prob *lp, int ncs);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_cols adds ncs columns (structural variables) to
+*  the specified problem object. New columns are always added to the end
+*  of the column list, so the ordinal numbers of existing columns remain
+*  unchanged.
+*
+*  Being added each new column is initially fixed at zero and has empty
+*  list of the constraint coefficients.
+*
+*  RETURNS
+*
+*  The routine glp_add_cols returns the ordinal number of the first new
+*  column added to the problem object. */
+
+int glp_add_cols(glp_prob *lp, int ncs)
+{     glp_tree *tree = lp->tree;
+      GLPCOL *col;
+      int n_new, j;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_add_cols: operation not allowed\n");
+      /* determine new number of columns */
+      if (ncs < 1)
+         xerror("glp_add_cols: ncs = %d; invalid number of columns\n",
+            ncs);
+      if (ncs > N_MAX - lp->n)
+         xerror("glp_add_cols: ncs = %d; too many columns\n", ncs);
+      n_new = lp->n + ncs;
+      /* increase the room, if necessary */
+      if (lp->n_max < n_new)
+      {  GLPCOL **save = lp->col;
+         while (lp->n_max < n_new)
+         {  lp->n_max += lp->n_max;
+            xassert(lp->n_max > 0);
+         }
+         lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
+         memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *));
+         xfree(save);
+      }
+      /* add new columns to the end of the column list */
+      for (j = lp->n+1; j <= n_new; j++)
+      {  /* create column descriptor */
+         lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL));
+         col->j = j;
+         col->name = NULL;
+         col->node = NULL;
+         col->kind = GLP_CV;
+         col->type = GLP_FX;
+         col->lb = col->ub = 0.0;
+         col->coef = 0.0;
+         col->ptr = NULL;
+         col->sjj = 1.0;
+         col->stat = GLP_NS;
+#if 0
+         col->bind = -1;
+#else
+         col->bind = 0; /* the basis may remain valid */
+#endif
+         col->prim = col->dual = 0.0;
+         col->pval = col->dval = 0.0;
+         col->mipx = 0.0;
+      }
+      /* set new number of columns */
+      lp->n = n_new;
+      /* return the ordinal number of the first column added */
+      return n_new - ncs + 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_row_name - assign (change) row name
+*
+*  SYNOPSIS
+*
+*  void glp_set_row_name(glp_prob *lp, int i, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_row_name assigns a given symbolic name (1 up to
+*  255 characters) to i-th row (auxiliary variable) of the specified
+*  problem object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing name of i-th row. */
+
+void glp_set_row_name(glp_prob *lp, int i, const char *name)
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_row_name: i = %d; row number out of range\n",
+            i);
+      row = lp->row[i];
+      if (tree != NULL && tree->reason != 0)
+      {  xassert(tree->curr != NULL);
+         xassert(row->level == tree->curr->level);
+      }
+      if (row->name != NULL)
+      {  if (row->node != NULL)
+         {  xassert(lp->r_tree != NULL);
+            avl_delete_node(lp->r_tree, row->node);
+            row->node = NULL;
+         }
+         dmp_free_atom(lp->pool, row->name, strlen(row->name)+1);
+         row->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_row_name: i = %d; row name too long\n",
+                  i);
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_row_name: i = %d: row name contains inva"
+                  "lid character(s)\n", i);
+         }
+         row->name = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(row->name, name);
+         if (lp->r_tree != NULL)
+         {  xassert(row->node == NULL);
+            row->node = avl_insert_node(lp->r_tree, row->name);
+            avl_set_node_link(row->node, row);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_name - assign (change) column name
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_name(glp_prob *lp, int j, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_name assigns a given symbolic name (1 up to
+*  255 characters) to j-th column (structural variable) of the specified
+*  problem object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing name of j-th column. */
+
+void glp_set_col_name(glp_prob *lp, int j, const char *name)
+{     glp_tree *tree = lp->tree;
+      GLPCOL *col;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_col_name: operation not allowed\n");
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_col_name: j = %d; column number out of range\n"
+            , j);
+      col = lp->col[j];
+      if (col->name != NULL)
+      {  if (col->node != NULL)
+         {  xassert(lp->c_tree != NULL);
+            avl_delete_node(lp->c_tree, col->node);
+            col->node = NULL;
+         }
+         dmp_free_atom(lp->pool, col->name, strlen(col->name)+1);
+         col->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_col_name: j = %d; column name too long\n"
+                  , j);
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_col_name: j = %d: column name contains i"
+                  "nvalid character(s)\n", j);
+         }
+         col->name = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(col->name, name);
+         if (lp->c_tree != NULL && col->name != NULL)
+         {  xassert(col->node == NULL);
+            col->node = avl_insert_node(lp->c_tree, col->name);
+            avl_set_node_link(col->node, col);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_row_bnds - set (change) row bounds
+*
+*  SYNOPSIS
+*
+*  void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
+*     double ub);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_row_bnds sets (changes) the type and bounds of
+*  i-th row (auxiliary variable) of the specified problem object.
+*
+*  Parameters type, lb, and ub specify the type, lower bound, and upper
+*  bound, respectively, as follows:
+*
+*     Type           Bounds        Comments
+*     ------------------------------------------------------
+*     GLP_FR   -inf <  x <  +inf   Free variable
+*     GLP_LO     lb <= x <  +inf   Variable with lower bound
+*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
+*     GLP_DB     lb <= x <=  ub    Double-bounded variable
+*     GLP_FX           x  =  lb    Fixed variable
+*
+*  where x is the auxiliary variable associated with i-th row.
+*
+*  If the row has no lower bound, the parameter lb is ignored. If the
+*  row has no upper bound, the parameter ub is ignored. If the row is
+*  an equality constraint (i.e. the corresponding auxiliary variable is
+*  of fixed type), only the parameter lb is used while the parameter ub
+*  is ignored. */
+
+void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
+      double ub)
+{     GLPROW *row;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_row_bnds: i = %d; row number out of range\n",
+            i);
+      row = lp->row[i];
+      row->type = type;
+      switch (type)
+      {  case GLP_FR:
+            row->lb = row->ub = 0.0;
+            if (row->stat != GLP_BS) row->stat = GLP_NF;
+            break;
+         case GLP_LO:
+            row->lb = lb, row->ub = 0.0;
+            if (row->stat != GLP_BS) row->stat = GLP_NL;
+            break;
+         case GLP_UP:
+            row->lb = 0.0, row->ub = ub;
+            if (row->stat != GLP_BS) row->stat = GLP_NU;
+            break;
+         case GLP_DB:
+            row->lb = lb, row->ub = ub;
+            if (!(row->stat == GLP_BS ||
+                  row->stat == GLP_NL || row->stat == GLP_NU))
+               row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
+            break;
+         case GLP_FX:
+            row->lb = row->ub = lb;
+            if (row->stat != GLP_BS) row->stat = GLP_NS;
+            break;
+         default:
+            xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty"
+               "pe\n", i, type);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_bnds - set (change) column bounds
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
+*     double ub);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_bnds sets (changes) the type and bounds of
+*  j-th column (structural variable) of the specified problem object.
+*
+*  Parameters type, lb, and ub specify the type, lower bound, and upper
+*  bound, respectively, as follows:
+*
+*     Type           Bounds        Comments
+*     ------------------------------------------------------
+*     GLP_FR   -inf <  x <  +inf   Free variable
+*     GLP_LO     lb <= x <  +inf   Variable with lower bound
+*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
+*     GLP_DB     lb <= x <=  ub    Double-bounded variable
+*     GLP_FX           x  =  lb    Fixed variable
+*
+*  where x is the structural variable associated with j-th column.
+*
+*  If the column has no lower bound, the parameter lb is ignored. If the
+*  column has no upper bound, the parameter ub is ignored. If the column
+*  is of fixed type, only the parameter lb is used while the parameter
+*  ub is ignored. */
+
+void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
+      double ub)
+{     GLPCOL *col;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_col_bnds: j = %d; column number out of range\n"
+            , j);
+      col = lp->col[j];
+      col->type = type;
+      switch (type)
+      {  case GLP_FR:
+            col->lb = col->ub = 0.0;
+            if (col->stat != GLP_BS) col->stat = GLP_NF;
+            break;
+         case GLP_LO:
+            col->lb = lb, col->ub = 0.0;
+            if (col->stat != GLP_BS) col->stat = GLP_NL;
+            break;
+         case GLP_UP:
+            col->lb = 0.0, col->ub = ub;
+            if (col->stat != GLP_BS) col->stat = GLP_NU;
+            break;
+         case GLP_DB:
+            col->lb = lb, col->ub = ub;
+            if (!(col->stat == GLP_BS ||
+                  col->stat == GLP_NL || col->stat == GLP_NU))
+               col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
+            break;
+         case GLP_FX:
+            col->lb = col->ub = lb;
+            if (col->stat != GLP_BS) col->stat = GLP_NS;
+            break;
+         default:
+            xerror("glp_set_col_bnds: j = %d; type = %d; invalid column"
+               " type\n", j, type);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_obj_coef - set (change) obj. coefficient or constant term
+*
+*  SYNOPSIS
+*
+*  void glp_set_obj_coef(glp_prob *lp, int j, double coef);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_obj_coef sets (changes) objective coefficient at
+*  j-th column (structural variable) of the specified problem object.
+*
+*  If the parameter j is 0, the routine sets (changes) the constant term
+*  ("shift") of the objective function. */
+
+void glp_set_obj_coef(glp_prob *lp, int j, double coef)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_obj_coef: operation not allowed\n");
+      if (!(0 <= j && j <= lp->n))
+         xerror("glp_set_obj_coef: j = %d; column number out of range\n"
+            , j);
+      if (j == 0)
+         lp->c0 = coef;
+      else
+         lp->col[j]->coef = coef;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_mat_row - set (replace) row of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_mat_row stores (replaces) the contents of i-th
+*  row of the constraint matrix of the specified problem object.
+*
+*  Column indices and numeric values of new row elements must be placed
+*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
+*  0 <= len <= n is the new length of i-th row, n is the current number
+*  of columns in the problem object. Elements with identical column
+*  indices are not allowed. Zero elements are allowed, but they are not
+*  stored in the constraint matrix.
+*
+*  If the parameter len is zero, the parameters ind and/or val can be
+*  specified as NULL. */
+
+void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
+      const double val[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij, *next;
+      int j, k;
+      /* obtain pointer to i-th row */
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_mat_row: i = %d; row number out of range\n",
+            i);
+      row = lp->row[i];
+      if (tree != NULL && tree->reason != 0)
+      {  xassert(tree->curr != NULL);
+         xassert(row->level == tree->curr->level);
+      }
+      /* remove all existing elements from i-th row */
+      while (row->ptr != NULL)
+      {  /* take next element in the row */
+         aij = row->ptr;
+         /* remove the element from the row list */
+         row->ptr = aij->r_next;
+         /* obtain pointer to corresponding column */
+         col = aij->col;
+         /* remove the element from the column list */
+         if (aij->c_prev == NULL)
+            col->ptr = aij->c_next;
+         else
+            aij->c_prev->c_next = aij->c_next;
+         if (aij->c_next == NULL)
+            ;
+         else
+            aij->c_next->c_prev = aij->c_prev;
+         /* return the element to the memory pool */
+         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         /* if the corresponding column is basic, invalidate the basis
+            factorization */
+         if (col->stat == GLP_BS) lp->valid = 0;
+      }
+      /* store new contents of i-th row */
+      if (!(0 <= len && len <= lp->n))
+         xerror("glp_set_mat_row: i = %d; len = %d; invalid row length "
+            "\n", i, len);
+      if (len > NNZ_MAX - lp->nnz)
+         xerror("glp_set_mat_row: i = %d; len = %d; too many constraint"
+            " coefficients\n", i, len);
+      for (k = 1; k <= len; k++)
+      {  /* take number j of corresponding column */
+         j = ind[k];
+         /* obtain pointer to j-th column */
+         if (!(1 <= j && j <= lp->n))
+            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index"
+               " out of range\n", i, k, j);
+         col = lp->col[j];
+         /* if there is element with the same column index, it can only
+            be found in the beginning of j-th column list */
+         if (col->ptr != NULL && col->ptr->row->i == i)
+            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co"
+               "lumn indices not allowed\n", i, k, j);
+         /* create new element */
+         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+         aij->row = row;
+         aij->col = col;
+         aij->val = val[k];
+         /* add the new element to the beginning of i-th row and j-th
+            column lists */
+         aij->r_prev = NULL;
+         aij->r_next = row->ptr;
+         aij->c_prev = NULL;
+         aij->c_next = col->ptr;
+         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+         row->ptr = col->ptr = aij;
+         /* if the corresponding column is basic, invalidate the basis
+            factorization */
+         if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0;
+      }
+      /* remove zero elements from i-th row */
+      for (aij = row->ptr; aij != NULL; aij = next)
+      {  next = aij->r_next;
+         if (aij->val == 0.0)
+         {  /* remove the element from the row list */
+            if (aij->r_prev == NULL)
+               row->ptr = next;
+            else
+               aij->r_prev->r_next = next;
+            if (next == NULL)
+               ;
+            else
+               next->r_prev = aij->r_prev;
+            /* remove the element from the column list */
+            xassert(aij->c_prev == NULL);
+            aij->col->ptr = aij->c_next;
+            if (aij->c_next != NULL) aij->c_next->c_prev = NULL;
+            /* return the element to the memory pool */
+            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_mat_col - set (replace) column of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_mat_col stores (replaces) the contents of j-th
+*  column of the constraint matrix of the specified problem object.
+*
+*  Row indices and numeric values of new column elements must be placed
+*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
+*  0 <= len <= m is the new length of j-th column, m is the current
+*  number of rows in the problem object. Elements with identical column
+*  indices are not allowed. Zero elements are allowed, but they are not
+*  stored in the constraint matrix.
+*
+*  If the parameter len is zero, the parameters ind and/or val can be
+*  specified as NULL. */
+
+void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
+      const double val[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij, *next;
+      int i, k;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_mat_col: operation not allowed\n");
+      /* obtain pointer to j-th column */
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_mat_col: j = %d; column number out of range\n",
+            j);
+      col = lp->col[j];
+      /* remove all existing elements from j-th column */
+      while (col->ptr != NULL)
+      {  /* take next element in the column */
+         aij = col->ptr;
+         /* remove the element from the column list */
+         col->ptr = aij->c_next;
+         /* obtain pointer to corresponding row */
+         row = aij->row;
+         /* remove the element from the row list */
+         if (aij->r_prev == NULL)
+            row->ptr = aij->r_next;
+         else
+            aij->r_prev->r_next = aij->r_next;
+         if (aij->r_next == NULL)
+            ;
+         else
+            aij->r_next->r_prev = aij->r_prev;
+         /* return the element to the memory pool */
+         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+      }
+      /* store new contents of j-th column */
+      if (!(0 <= len && len <= lp->m))
+         xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng"
+            "th\n", j, len);
+      if (len > NNZ_MAX - lp->nnz)
+         xerror("glp_set_mat_col: j = %d; len = %d; too many constraint"
+            " coefficients\n", j, len);
+      for (k = 1; k <= len; k++)
+      {  /* take number i of corresponding row */
+         i = ind[k];
+         /* obtain pointer to i-th row */
+         if (!(1 <= i && i <= lp->m))
+            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou"
+               "t of range\n", j, k, i);
+         row = lp->row[i];
+         /* if there is element with the same row index, it can only be
+            found in the beginning of i-th row list */
+         if (row->ptr != NULL && row->ptr->col->j == j)
+            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro"
+               "w indices not allowed\n", j, k, i);
+         /* create new element */
+         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+         aij->row = row;
+         aij->col = col;
+         aij->val = val[k];
+         /* add the new element to the beginning of i-th row and j-th
+            column lists */
+         aij->r_prev = NULL;
+         aij->r_next = row->ptr;
+         aij->c_prev = NULL;
+         aij->c_next = col->ptr;
+         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+         row->ptr = col->ptr = aij;
+      }
+      /* remove zero elements from j-th column */
+      for (aij = col->ptr; aij != NULL; aij = next)
+      {  next = aij->c_next;
+         if (aij->val == 0.0)
+         {  /* remove the element from the row list */
+            xassert(aij->r_prev == NULL);
+            aij->row->ptr = aij->r_next;
+            if (aij->r_next != NULL) aij->r_next->r_prev = NULL;
+            /* remove the element from the column list */
+            if (aij->c_prev == NULL)
+               col->ptr = next;
+            else
+               aij->c_prev->c_next = next;
+            if (next == NULL)
+               ;
+            else
+               next->c_prev = aij->c_prev;
+            /* return the element to the memory pool */
+            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         }
+      }
+      /* if j-th column is basic, invalidate the basis factorization */
+      if (col->stat == GLP_BS) lp->valid = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_load_matrix - load (replace) the whole constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+*     const int ja[], const double ar[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_load_matrix loads the constraint matrix passed in
+*  the arrays ia, ja, and ar into the specified problem object. Before
+*  loading the current contents of the constraint matrix is destroyed.
+*
+*  Constraint coefficients (elements of the constraint matrix) must be
+*  specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne,
+*  where ia[k] is the row index, ja[k] is the column index, ar[k] is a
+*  numeric value of corresponding constraint coefficient. The parameter
+*  ne specifies the total number of (non-zero) elements in the matrix
+*  to be loaded. Coefficients with identical indices are not allowed.
+*  Zero coefficients are allowed, however, they are not stored in the
+*  constraint matrix.
+*
+*  If the parameter ne is zero, the parameters ia, ja, and ar can be
+*  specified as NULL. */
+
+void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+      const int ja[], const double ar[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij, *next;
+      int i, j, k;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_load_matrix: operation not allowed\n");
+      /* clear the constraint matrix */
+      for (i = 1; i <= lp->m; i++)
+      {  row = lp->row[i];
+         while (row->ptr != NULL)
+         {  aij = row->ptr;
+            row->ptr = aij->r_next;
+            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         }
+      }
+      xassert(lp->nnz == 0);
+      for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL;
+      /* load the new contents of the constraint matrix and build its
+         row lists */
+      if (ne < 0)
+         xerror("glp_load_matrix: ne = %d; invalid number of constraint"
+            " coefficients\n", ne);
+      if (ne > NNZ_MAX)
+         xerror("glp_load_matrix: ne = %d; too many constraint coeffici"
+            "ents\n", ne);
+      for (k = 1; k <= ne; k++)
+      {  /* take indices of new element */
+         i = ia[k], j = ja[k];
+         /* obtain pointer to i-th row */
+         if (!(1 <= i && i <= lp->m))
+            xerror("glp_load_matrix: ia[%d] = %d; row index out of rang"
+               "e\n", k, i);
+         row = lp->row[i];
+         /* obtain pointer to j-th column */
+         if (!(1 <= j && j <= lp->n))
+            xerror("glp_load_matrix: ja[%d] = %d; column index out of r"
+               "ange\n", k, j);
+         col = lp->col[j];
+         /* create new element */
+         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+         aij->row = row;
+         aij->col = col;
+         aij->val = ar[k];
+         /* add the new element to the beginning of i-th row list */
+         aij->r_prev = NULL;
+         aij->r_next = row->ptr;
+         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+         row->ptr = aij;
+      }
+      xassert(lp->nnz == ne);
+      /* build column lists of the constraint matrix and check elements
+         with identical indices */
+      for (i = 1; i <= lp->m; i++)
+      {  for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  /* obtain pointer to corresponding column */
+            col = aij->col;
+            /* if there is element with identical indices, it can only
+               be found in the beginning of j-th column list */
+            if (col->ptr != NULL && col->ptr->row->i == i)
+            {  for (k = 1; k <= ne; k++)
+                  if (ia[k] == i && ja[k] == col->j) break;
+               xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat"
+                  "e indices not allowed\n", k, i, k, col->j);
+            }
+            /* add the element to the beginning of j-th column list */
+            aij->c_prev = NULL;
+            aij->c_next = col->ptr;
+            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+            col->ptr = aij;
+         }
+      }
+      /* remove zero elements from the constraint matrix */
+      for (i = 1; i <= lp->m; i++)
+      {  row = lp->row[i];
+         for (aij = row->ptr; aij != NULL; aij = next)
+         {  next = aij->r_next;
+            if (aij->val == 0.0)
+            {  /* remove the element from the row list */
+               if (aij->r_prev == NULL)
+                  row->ptr = next;
+               else
+                  aij->r_prev->r_next = next;
+               if (next == NULL)
+                  ;
+               else
+                  next->r_prev = aij->r_prev;
+               /* remove the element from the column list */
+               if (aij->c_prev == NULL)
+                  aij->col->ptr = aij->c_next;
+               else
+                  aij->c_prev->c_next = aij->c_next;
+               if (aij->c_next == NULL)
+                  ;
+               else
+                  aij->c_next->c_prev = aij->c_prev;
+               /* return the element to the memory pool */
+               dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+            }
+         }
+      }
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_check_dup - check for duplicate elements in sparse matrix
+*
+*  SYNOPSIS
+*
+*  int glp_check_dup(int m, int n, int ne, const int ia[],
+*     const int ja[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_check_dup checks for duplicate elements (that is,
+*  elements with identical indices) in a sparse matrix specified in the
+*  coordinate format.
+*
+*  The parameters m and n specifies, respectively, the number of rows
+*  and columns in the matrix, m >= 0, n >= 0.
+*
+*  The parameter ne specifies the number of (structurally) non-zero
+*  elements in the matrix, ne >= 0.
+*
+*  Elements of the matrix are specified as doublets (ia[k],ja[k]) for
+*  k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index.
+*
+*  The routine glp_check_dup can be used prior to a call to the routine
+*  glp_load_matrix to check that the constraint matrix to be loaded has
+*  no duplicate elements.
+*
+*  RETURNS
+*
+*  The routine glp_check_dup returns one of the following values:
+*
+*   0 - the matrix has no duplicate elements;
+*
+*  -k - indices ia[k] or/and ja[k] are out of range;
+*
+*  +k - element (ia[k],ja[k]) is duplicate. */
+
+int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[])
+{     int i, j, k, *ptr, *next, ret;
+      char *flag;
+      if (m < 0)
+         xerror("glp_check_dup: m = %d; invalid parameter\n");
+      if (n < 0)
+         xerror("glp_check_dup: n = %d; invalid parameter\n");
+      if (ne < 0)
+         xerror("glp_check_dup: ne = %d; invalid parameter\n");
+      if (ne > 0 && ia == NULL)
+         xerror("glp_check_dup: ia = %p; invalid parameter\n", ia);
+      if (ne > 0 && ja == NULL)
+         xerror("glp_check_dup: ja = %p; invalid parameter\n", ja);
+      for (k = 1; k <= ne; k++)
+      {  i = ia[k], j = ja[k];
+         if (!(1 <= i && i <= m && 1 <= j && j <= n))
+         {  ret = -k;
+            goto done;
+         }
+      }
+      if (m == 0 || n == 0)
+      {  ret = 0;
+         goto done;
+      }
+      /* allocate working arrays */
+      ptr = xcalloc(1+m, sizeof(int));
+      next = xcalloc(1+ne, sizeof(int));
+      flag = xcalloc(1+n, sizeof(char));
+      /* build row lists */
+      for (i = 1; i <= m; i++)
+         ptr[i] = 0;
+      for (k = 1; k <= ne; k++)
+      {  i = ia[k];
+         next[k] = ptr[i];
+         ptr[i] = k;
+      }
+      /* clear column flags */
+      for (j = 1; j <= n; j++)
+         flag[j] = 0;
+      /* check for duplicate elements */
+      for (i = 1; i <= m; i++)
+      {  for (k = ptr[i]; k != 0; k = next[k])
+         {  j = ja[k];
+            if (flag[j])
+            {  /* find first element (i,j) */
+               for (k = 1; k <= ne; k++)
+                  if (ia[k] == i && ja[k] == j) break;
+               xassert(k <= ne);
+               /* find next (duplicate) element (i,j) */
+               for (k++; k <= ne; k++)
+                  if (ia[k] == i && ja[k] == j) break;
+               xassert(k <= ne);
+               ret = +k;
+               goto skip;
+            }
+            flag[j] = 1;
+         }
+         /* clear column flags */
+         for (k = ptr[i]; k != 0; k = next[k])
+            flag[ja[k]] = 0;
+      }
+      /* no duplicate element found */
+      ret = 0;
+skip: /* free working arrays */
+      xfree(ptr);
+      xfree(next);
+      xfree(flag);
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_sort_matrix - sort elements of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_sort_matrix(glp_prob *P);
+*
+*  DESCRIPTION
+*
+*  The routine glp_sort_matrix sorts elements of the constraint matrix
+*  rebuilding its row and column linked lists. On exit from the routine
+*  the constraint matrix is not changed, however, elements in the row
+*  linked lists become ordered by ascending column indices, and the
+*  elements in the column linked lists become ordered by ascending row
+*  indices. */
+
+void glp_sort_matrix(glp_prob *P)
+{     GLPAIJ *aij;
+      int i, j;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_sort_matrix: P = %p; invalid problem object\n",
+            P);
+      /* rebuild row linked lists */
+      for (i = P->m; i >= 1; i--)
+         P->row[i]->ptr = NULL;
+      for (j = P->n; j >= 1; j--)
+      {  for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next)
+         {  i = aij->row->i;
+            aij->r_prev = NULL;
+            aij->r_next = P->row[i]->ptr;
+            if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+            P->row[i]->ptr = aij;
+         }
+      }
+      /* rebuild column linked lists */
+      for (j = P->n; j >= 1; j--)
+         P->col[j]->ptr = NULL;
+      for (i = P->m; i >= 1; i--)
+      {  for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  j = aij->col->j;
+            aij->c_prev = NULL;
+            aij->c_next = P->col[j]->ptr;
+            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+            P->col[j]->ptr = aij;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_rows - delete rows from problem object
+*
+*  SYNOPSIS
+*
+*  void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_rows deletes rows from the specified problem
+*  object. Ordinal numbers of rows to be deleted should be placed in
+*  locations num[1], ..., num[nrs], where nrs > 0.
+*
+*  Note that deleting rows involves changing ordinal numbers of other
+*  rows remaining in the problem object. New ordinal numbers of the
+*  remaining rows are assigned under the assumption that the original
+*  order of rows is not changed. */
+
+void glp_del_rows(glp_prob *lp, int nrs, const int num[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      int i, k, m_new;
+      /* mark rows to be deleted */
+      if (!(1 <= nrs && nrs <= lp->m))
+         xerror("glp_del_rows: nrs = %d; invalid number of rows\n",
+            nrs);
+      for (k = 1; k <= nrs; k++)
+      {  /* take the number of row to be deleted */
+         i = num[k];
+         /* obtain pointer to i-th row */
+         if (!(1 <= i && i <= lp->m))
+            xerror("glp_del_rows: num[%d] = %d; row number out of range"
+               "\n", k, i);
+         row = lp->row[i];
+         if (tree != NULL && tree->reason != 0)
+         {  if (!(tree->reason == GLP_IROWGEN ||
+                  tree->reason == GLP_ICUTGEN))
+               xerror("glp_del_rows: operation not allowed\n");
+            xassert(tree->curr != NULL);
+            if (row->level != tree->curr->level)
+               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
+                  "elete row created not in current subproblem\n", k,i);
+            if (row->stat != GLP_BS)
+               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
+                  "elete active row (constraint)\n", k, i);
+            tree->reinv = 1;
+         }
+         /* check that the row is not marked yet */
+         if (row->i == 0)
+            xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n"
+               "ot allowed\n", k, i);
+         /* erase symbolic name assigned to the row */
+         glp_set_row_name(lp, i, NULL);
+         xassert(row->node == NULL);
+         /* erase corresponding row of the constraint matrix */
+         glp_set_mat_row(lp, i, 0, NULL, NULL);
+         xassert(row->ptr == NULL);
+         /* mark the row to be deleted */
+         row->i = 0;
+      }
+      /* delete all marked rows from the row list */
+      m_new = 0;
+      for (i = 1; i <= lp->m; i++)
+      {  /* obtain pointer to i-th row */
+         row = lp->row[i];
+         /* check if the row is marked */
+         if (row->i == 0)
+         {  /* it is marked, delete it */
+            dmp_free_atom(lp->pool, row, sizeof(GLPROW));
+         }
+         else
+         {  /* it is not marked; keep it */
+            row->i = ++m_new;
+            lp->row[row->i] = row;
+         }
+      }
+      /* set new number of rows */
+      lp->m = m_new;
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_cols - delete columns from problem object
+*
+*  SYNOPSIS
+*
+*  void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_cols deletes columns from the specified problem
+*  object. Ordinal numbers of columns to be deleted should be placed in
+*  locations num[1], ..., num[ncs], where ncs > 0.
+*
+*  Note that deleting columns involves changing ordinal numbers of
+*  other columns remaining in the problem object. New ordinal numbers
+*  of the remaining columns are assigned under the assumption that the
+*  original order of columns is not changed. */
+
+void glp_del_cols(glp_prob *lp, int ncs, const int num[])
+{     glp_tree *tree = lp->tree;
+      GLPCOL *col;
+      int j, k, n_new;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_del_cols: operation not allowed\n");
+      /* mark columns to be deleted */
+      if (!(1 <= ncs && ncs <= lp->n))
+         xerror("glp_del_cols: ncs = %d; invalid number of columns\n",
+            ncs);
+      for (k = 1; k <= ncs; k++)
+      {  /* take the number of column to be deleted */
+         j = num[k];
+         /* obtain pointer to j-th column */
+         if (!(1 <= j && j <= lp->n))
+            xerror("glp_del_cols: num[%d] = %d; column number out of ra"
+               "nge", k, j);
+         col = lp->col[j];
+         /* check that the column is not marked yet */
+         if (col->j == 0)
+            xerror("glp_del_cols: num[%d] = %d; duplicate column number"
+               "s not allowed\n", k, j);
+         /* erase symbolic name assigned to the column */
+         glp_set_col_name(lp, j, NULL);
+         xassert(col->node == NULL);
+         /* erase corresponding column of the constraint matrix */
+         glp_set_mat_col(lp, j, 0, NULL, NULL);
+         xassert(col->ptr == NULL);
+         /* mark the column to be deleted */
+         col->j = 0;
+         /* if it is basic, invalidate the basis factorization */
+         if (col->stat == GLP_BS) lp->valid = 0;
+      }
+      /* delete all marked columns from the column list */
+      n_new = 0;
+      for (j = 1; j <= lp->n; j++)
+      {  /* obtain pointer to j-th column */
+         col = lp->col[j];
+         /* check if the column is marked */
+         if (col->j == 0)
+         {  /* it is marked; delete it */
+            dmp_free_atom(lp->pool, col, sizeof(GLPCOL));
+         }
+         else
+         {  /* it is not marked; keep it */
+            col->j = ++n_new;
+            lp->col[col->j] = col;
+         }
+      }
+      /* set new number of columns */
+      lp->n = n_new;
+      /* if the basis header is still valid, adjust it */
+      if (lp->valid)
+      {  int m = lp->m;
+         int *head = lp->head;
+         for (j = 1; j <= n_new; j++)
+         {  k = lp->col[j]->bind;
+            if (k != 0)
+            {  xassert(1 <= k && k <= m);
+               head[k] = m + j;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_copy_prob - copy problem object content
+*
+*  SYNOPSIS
+*
+*  void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+*
+*  DESCRIPTION
+*
+*  The routine glp_copy_prob copies the content of the problem object
+*  prob to the problem object dest.
+*
+*  The parameter names is a flag. If it is non-zero, the routine also
+*  copies all symbolic names; otherwise, if it is zero, symbolic names
+*  are not copied. */
+
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names)
+{     glp_tree *tree = dest->tree;
+      glp_bfcp bfcp;
+      int i, j, len, *ind;
+      double *val;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_copy_prob: operation not allowed\n");
+      if (dest == prob)
+         xerror("glp_copy_prob: copying problem object to itself not al"
+            "lowed\n");
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_copy_prob: names = %d; invalid parameter\n",
+            names);
+      glp_erase_prob(dest);
+      if (names && prob->name != NULL)
+         glp_set_prob_name(dest, prob->name);
+      if (names && prob->obj != NULL)
+         glp_set_obj_name(dest, prob->obj);
+      dest->dir = prob->dir;
+      dest->c0 = prob->c0;
+      if (prob->m > 0)
+         glp_add_rows(dest, prob->m);
+      if (prob->n > 0)
+         glp_add_cols(dest, prob->n);
+      glp_get_bfcp(prob, &bfcp);
+      glp_set_bfcp(dest, &bfcp);
+      dest->pbs_stat = prob->pbs_stat;
+      dest->dbs_stat = prob->dbs_stat;
+      dest->obj_val = prob->obj_val;
+      dest->some = prob->some;
+      dest->ipt_stat = prob->ipt_stat;
+      dest->ipt_obj = prob->ipt_obj;
+      dest->mip_stat = prob->mip_stat;
+      dest->mip_obj = prob->mip_obj;
+      for (i = 1; i <= prob->m; i++)
+      {  GLPROW *to = dest->row[i];
+         GLPROW *from = prob->row[i];
+         if (names && from->name != NULL)
+            glp_set_row_name(dest, i, from->name);
+         to->type = from->type;
+         to->lb = from->lb;
+         to->ub = from->ub;
+         to->rii = from->rii;
+         to->stat = from->stat;
+         to->prim = from->prim;
+         to->dual = from->dual;
+         to->pval = from->pval;
+         to->dval = from->dval;
+         to->mipx = from->mipx;
+      }
+      ind = xcalloc(1+prob->m, sizeof(int));
+      val = xcalloc(1+prob->m, sizeof(double));
+      for (j = 1; j <= prob->n; j++)
+      {  GLPCOL *to = dest->col[j];
+         GLPCOL *from = prob->col[j];
+         if (names && from->name != NULL)
+            glp_set_col_name(dest, j, from->name);
+         to->kind = from->kind;
+         to->type = from->type;
+         to->lb = from->lb;
+         to->ub = from->ub;
+         to->coef = from->coef;
+         len = glp_get_mat_col(prob, j, ind, val);
+         glp_set_mat_col(dest, j, len, ind, val);
+         to->sjj = from->sjj;
+         to->stat = from->stat;
+         to->prim = from->prim;
+         to->dual = from->dual;
+         to->pval = from->pval;
+         to->dval = from->dval;
+         to->mipx = from->mipx;
+      }
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_erase_prob - erase problem object content
+*
+*  SYNOPSIS
+*
+*  void glp_erase_prob(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_erase_prob erases the content of the specified
+*  problem object. The effect of this operation is the same as if the
+*  problem object would be deleted with the routine glp_delete_prob and
+*  then created anew with the routine glp_create_prob, with exception
+*  that the handle (pointer) to the problem object remains valid. */
+
+static void delete_prob(glp_prob *lp);
+
+void glp_erase_prob(glp_prob *lp)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_erase_prob: operation not allowed\n");
+      delete_prob(lp);
+      create_prob(lp);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_delete_prob - delete problem object
+*
+*  SYNOPSIS
+*
+*  void glp_delete_prob(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_delete_prob deletes the specified problem object and
+*  frees all the memory allocated to it. */
+
+static void delete_prob(glp_prob *lp)
+{     lp->magic = 0x3F3F3F3F;
+      dmp_delete_pool(lp->pool);
+#if 0 /* 17/XI-2009 */
+      xfree(lp->cps);
+#else
+      if (lp->parms != NULL) xfree(lp->parms);
+#endif
+      xassert(lp->tree == NULL);
+#if 0
+      if (lp->cwa != NULL) xfree(lp->cwa);
+#endif
+      xfree(lp->row);
+      xfree(lp->col);
+      if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree);
+      if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree);
+      xfree(lp->head);
+      if (lp->bfcp != NULL) xfree(lp->bfcp);
+      if (lp->bfd != NULL) bfd_delete_it(lp->bfd);
+      return;
+}
+
+void glp_delete_prob(glp_prob *lp)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_delete_prob: operation not allowed\n");
+      delete_prob(lp);
+      xfree(lp);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi02.c b/optional/glpk/glpapi02.c
new file mode 100644
index 0000000..2e74f47
--- /dev/null
+++ b/optional/glpk/glpapi02.c
@@ -0,0 +1,495 @@
+/* glpapi02.c (problem retrieving routines) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_prob_name - retrieve problem name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_prob_name(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_prob_name returns a pointer to an internal
+*  buffer, which contains symbolic name of the problem. However, if the
+*  problem has no assigned name, the routine returns NULL. */
+
+const char *glp_get_prob_name(glp_prob *lp)
+{     char *name;
+      name = lp->name;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_name - retrieve objective function name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_obj_name(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_name returns a pointer to an internal
+*  buffer, which contains a symbolic name of the objective function.
+*  However, if the objective function has no assigned name, the routine
+*  returns NULL. */
+
+const char *glp_get_obj_name(glp_prob *lp)
+{     char *name;
+      name = lp->obj;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_dir - retrieve optimization direction flag
+*
+*  SYNOPSIS
+*
+*  int glp_get_obj_dir(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_dir returns the optimization direction flag
+*  (i.e. "sense" of the objective function):
+*
+*  GLP_MIN - minimization;
+*  GLP_MAX - maximization. */
+
+int glp_get_obj_dir(glp_prob *lp)
+{     int dir = lp->dir;
+      return dir;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_rows - retrieve number of rows
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_rows(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_rows returns the current number of rows in
+*  the specified problem object. */
+
+int glp_get_num_rows(glp_prob *lp)
+{     int m = lp->m;
+      return m;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_cols - retrieve number of columns
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_cols(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_cols returns the current number of columns
+*  in the specified problem object. */
+
+int glp_get_num_cols(glp_prob *lp)
+{     int n = lp->n;
+      return n;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_name - retrieve row name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_row_name(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_name returns a pointer to an internal
+*  buffer, which contains symbolic name of i-th row. However, if i-th
+*  row has no assigned name, the routine returns NULL. */
+
+const char *glp_get_row_name(glp_prob *lp, int i)
+{     char *name;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_name: i = %d; row number out of range\n",
+            i);
+      name = lp->row[i]->name;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_name - retrieve column name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_col_name(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_name returns a pointer to an internal
+*  buffer, which contains symbolic name of j-th column. However, if j-th
+*  column has no assigned name, the routine returns NULL. */
+
+const char *glp_get_col_name(glp_prob *lp, int j)
+{     char *name;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_name: j = %d; column number out of range\n"
+            , j);
+      name = lp->col[j]->name;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_type - retrieve row type
+*
+*  SYNOPSIS
+*
+*  int glp_get_row_type(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_type returns the type of i-th row, i.e. the
+*  type of corresponding auxiliary variable, as follows:
+*
+*  GLP_FR - free (unbounded) variable;
+*  GLP_LO - variable with lower bound;
+*  GLP_UP - variable with upper bound;
+*  GLP_DB - double-bounded variable;
+*  GLP_FX - fixed variable. */
+
+int glp_get_row_type(glp_prob *lp, int i)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_type: i = %d; row number out of range\n",
+            i);
+      return lp->row[i]->type;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_lb - retrieve row lower bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_lb(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_lb returns the lower bound of i-th row, i.e.
+*  the lower bound of corresponding auxiliary variable. However, if the
+*  row has no lower bound, the routine returns -DBL_MAX. */
+
+double glp_get_row_lb(glp_prob *lp, int i)
+{     double lb;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_lb: i = %d; row number out of range\n", i);
+      switch (lp->row[i]->type)
+      {  case GLP_FR:
+         case GLP_UP:
+            lb = -DBL_MAX; break;
+         case GLP_LO:
+         case GLP_DB:
+         case GLP_FX:
+            lb = lp->row[i]->lb; break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_ub - retrieve row upper bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_ub(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_ub returns the upper bound of i-th row, i.e.
+*  the upper bound of corresponding auxiliary variable. However, if the
+*  row has no upper bound, the routine returns +DBL_MAX. */
+
+double glp_get_row_ub(glp_prob *lp, int i)
+{     double ub;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_ub: i = %d; row number out of range\n", i);
+      switch (lp->row[i]->type)
+      {  case GLP_FR:
+         case GLP_LO:
+            ub = +DBL_MAX; break;
+         case GLP_UP:
+         case GLP_DB:
+         case GLP_FX:
+            ub = lp->row[i]->ub; break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_type - retrieve column type
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_type(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_type returns the type of j-th column, i.e.
+*  the type of corresponding structural variable, as follows:
+*
+*  GLP_FR - free (unbounded) variable;
+*  GLP_LO - variable with lower bound;
+*  GLP_UP - variable with upper bound;
+*  GLP_DB - double-bounded variable;
+*  GLP_FX - fixed variable. */
+
+int glp_get_col_type(glp_prob *lp, int j)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_type: j = %d; column number out of range\n"
+            , j);
+      return lp->col[j]->type;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_lb - retrieve column lower bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_lb(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_lb returns the lower bound of j-th column,
+*  i.e. the lower bound of corresponding structural variable. However,
+*  if the column has no lower bound, the routine returns -DBL_MAX. */
+
+double glp_get_col_lb(glp_prob *lp, int j)
+{     double lb;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_lb: j = %d; column number out of range\n",
+            j);
+      switch (lp->col[j]->type)
+      {  case GLP_FR:
+         case GLP_UP:
+            lb = -DBL_MAX; break;
+         case GLP_LO:
+         case GLP_DB:
+         case GLP_FX:
+            lb = lp->col[j]->lb; break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_ub - retrieve column upper bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_ub(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_ub returns the upper bound of j-th column,
+*  i.e. the upper bound of corresponding structural variable. However,
+*  if the column has no upper bound, the routine returns +DBL_MAX. */
+
+double glp_get_col_ub(glp_prob *lp, int j)
+{     double ub;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_ub: j = %d; column number out of range\n",
+            j);
+      switch (lp->col[j]->type)
+      {  case GLP_FR:
+         case GLP_LO:
+            ub = +DBL_MAX; break;
+         case GLP_UP:
+         case GLP_DB:
+         case GLP_FX:
+            ub = lp->col[j]->ub; break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_coef - retrieve obj. coefficient or constant term
+*
+*  SYNOPSIS
+*
+*  double glp_get_obj_coef(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_coef returns the objective coefficient at
+*  j-th structural variable (column) of the specified problem object.
+*
+*  If the parameter j is zero, the routine returns the constant term
+*  ("shift") of the objective function. */
+
+double glp_get_obj_coef(glp_prob *lp, int j)
+{     if (!(0 <= j && j <= lp->n))
+         xerror("glp_get_obj_coef: j = %d; column number out of range\n"
+            , j);
+      return j == 0 ? lp->c0 : lp->col[j]->coef;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_nz - retrieve number of constraint coefficients
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_nz(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_nz returns the number of (non-zero) elements
+*  in the constraint matrix of the specified problem object. */
+
+int glp_get_num_nz(glp_prob *lp)
+{     int nnz = lp->nnz;
+      return nnz;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_mat_row - retrieve row of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_mat_row scans (non-zero) elements of i-th row
+*  of the constraint matrix of the specified problem object and stores
+*  their column indices and numeric values to locations ind[1], ...,
+*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
+*  is the number of elements in i-th row, n is the number of columns.
+*
+*  The parameter ind and/or val can be specified as NULL, in which case
+*  corresponding information is not stored.
+*
+*  RETURNS
+*
+*  The routine glp_get_mat_row returns the length len, i.e. the number
+*  of (non-zero) elements in i-th row. */
+
+int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[])
+{     GLPAIJ *aij;
+      int len;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_mat_row: i = %d; row number out of range\n",
+            i);
+      len = 0;
+      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+      {  len++;
+         if (ind != NULL) ind[len] = aij->col->j;
+         if (val != NULL) val[len] = aij->val;
+      }
+      xassert(len <= lp->n);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_mat_col - retrieve column of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_mat_col scans (non-zero) elements of j-th column
+*  of the constraint matrix of the specified problem object and stores
+*  their row indices and numeric values to locations ind[1], ...,
+*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m
+*  is the number of elements in j-th column, m is the number of rows.
+*
+*  The parameter ind or/and val can be specified as NULL, in which case
+*  corresponding information is not stored.
+*
+*  RETURNS
+*
+*  The routine glp_get_mat_col returns the length len, i.e. the number
+*  of (non-zero) elements in j-th column. */
+
+int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[])
+{     GLPAIJ *aij;
+      int len;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_mat_col: j = %d; column number out of range\n",
+            j);
+      len = 0;
+      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+      {  len++;
+         if (ind != NULL) ind[len] = aij->row->i;
+         if (val != NULL) val[len] = aij->val;
+      }
+      xassert(len <= lp->m);
+      return len;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi03.c b/optional/glpk/glpapi03.c
new file mode 100644
index 0000000..981efd4
--- /dev/null
+++ b/optional/glpk/glpapi03.c
@@ -0,0 +1,166 @@
+/* glpapi03.c (row and column searching routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_create_index - create the name index
+*
+*  SYNOPSIS
+*
+*  void glp_create_index(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_create_index creates the name index for the
+*  specified problem object. The name index is an auxiliary data
+*  structure, which is intended to quickly (i.e. for logarithmic time)
+*  find rows and columns by their names.
+*
+*  This routine can be called at any time. If the name index already
+*  exists, the routine does nothing. */
+
+void glp_create_index(glp_prob *lp)
+{     GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      /* create row name index */
+      if (lp->r_tree == NULL)
+      {  lp->r_tree = avl_create_tree(avl_strcmp, NULL);
+         for (i = 1; i <= lp->m; i++)
+         {  row = lp->row[i];
+            xassert(row->node == NULL);
+            if (row->name != NULL)
+            {  row->node = avl_insert_node(lp->r_tree, row->name);
+               avl_set_node_link(row->node, row);
+            }
+         }
+      }
+      /* create column name index */
+      if (lp->c_tree == NULL)
+      {  lp->c_tree = avl_create_tree(avl_strcmp, NULL);
+         for (j = 1; j <= lp->n; j++)
+         {  col = lp->col[j];
+            xassert(col->node == NULL);
+            if (col->name != NULL)
+            {  col->node = avl_insert_node(lp->c_tree, col->name);
+               avl_set_node_link(col->node, col);
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_find_row - find row by its name
+*
+*  SYNOPSIS
+*
+*  int glp_find_row(glp_prob *lp, const char *name);
+*
+*  RETURNS
+*
+*  The routine glp_find_row returns the ordinal number of a row,
+*  which is assigned (by the routine glp_set_row_name) the specified
+*  symbolic name. If no such row exists, the routine returns 0. */
+
+int glp_find_row(glp_prob *lp, const char *name)
+{     AVLNODE *node;
+      int i = 0;
+      if (lp->r_tree == NULL)
+         xerror("glp_find_row: row name index does not exist\n");
+      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+      {  node = avl_find_node(lp->r_tree, name);
+         if (node != NULL)
+            i = ((GLPROW *)avl_get_node_link(node))->i;
+      }
+      return i;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_find_col - find column by its name
+*
+*  SYNOPSIS
+*
+*  int glp_find_col(glp_prob *lp, const char *name);
+*
+*  RETURNS
+*
+*  The routine glp_find_col returns the ordinal number of a column,
+*  which is assigned (by the routine glp_set_col_name) the specified
+*  symbolic name. If no such column exists, the routine returns 0. */
+
+int glp_find_col(glp_prob *lp, const char *name)
+{     AVLNODE *node;
+      int j = 0;
+      if (lp->c_tree == NULL)
+         xerror("glp_find_col: column name index does not exist\n");
+      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+      {  node = avl_find_node(lp->c_tree, name);
+         if (node != NULL)
+            j = ((GLPCOL *)avl_get_node_link(node))->j;
+      }
+      return j;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_delete_index - delete the name index
+*
+*  SYNOPSIS
+*
+*  void glp_delete_index(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_delete_index deletes the name index previously
+*  created by the routine glp_create_index and frees the memory
+*  allocated to this auxiliary data structure.
+*
+*  This routine can be called at any time. If the name index does not
+*  exist, the routine does nothing. */
+
+void glp_delete_index(glp_prob *lp)
+{     int i, j;
+      /* delete row name index */
+      if (lp->r_tree != NULL)
+      {  for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL;
+         avl_delete_tree(lp->r_tree), lp->r_tree = NULL;
+      }
+      /* delete column name index */
+      if (lp->c_tree != NULL)
+      {  for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL;
+         avl_delete_tree(lp->c_tree), lp->c_tree = NULL;
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi04.c b/optional/glpk/glpapi04.c
new file mode 100644
index 0000000..c6af27b
--- /dev/null
+++ b/optional/glpk/glpapi04.c
@@ -0,0 +1,156 @@
+/* glpapi04.c (problem scaling routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_rii - set (change) row scale factor
+*
+*  SYNOPSIS
+*
+*  void glp_set_rii(glp_prob *lp, int i, double rii);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_rii sets (changes) the scale factor r[i,i] for
+*  i-th row of the specified problem object. */
+
+void glp_set_rii(glp_prob *lp, int i, double rii)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_rii: i = %d; row number out of range\n", i);
+      if (rii <= 0.0)
+         xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n",
+            i, rii);
+      if (lp->valid && lp->row[i]->rii != rii)
+      {  GLPAIJ *aij;
+         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  if (aij->col->stat == GLP_BS)
+            {  /* invalidate the basis factorization */
+               lp->valid = 0;
+               break;
+            }
+         }
+      }
+      lp->row[i]->rii = rii;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set sjj - set (change) column scale factor
+*
+*  SYNOPSIS
+*
+*  void glp_set_sjj(glp_prob *lp, int j, double sjj);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_sjj sets (changes) the scale factor s[j,j] for
+*  j-th column of the specified problem object. */
+
+void glp_set_sjj(glp_prob *lp, int j, double sjj)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_sjj: j = %d; column number out of range\n", j);
+      if (sjj <= 0.0)
+         xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n",
+            j, sjj);
+      if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat ==
+         GLP_BS)
+      {  /* invalidate the basis factorization */
+         lp->valid = 0;
+      }
+      lp->col[j]->sjj = sjj;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_rii - retrieve row scale factor
+*
+*  SYNOPSIS
+*
+*  double glp_get_rii(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_rii returns current scale factor r[i,i] for i-th
+*  row of the specified problem object. */
+
+double glp_get_rii(glp_prob *lp, int i)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_rii: i = %d; row number out of range\n", i);
+      return lp->row[i]->rii;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_sjj - retrieve column scale factor
+*
+*  SYNOPSIS
+*
+*  double glp_get_sjj(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_sjj returns current scale factor s[j,j] for j-th
+*  column of the specified problem object. */
+
+double glp_get_sjj(glp_prob *lp, int j)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_sjj: j = %d; column number out of range\n", j);
+      return lp->col[j]->sjj;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_unscale_prob - unscale problem data
+*
+*  SYNOPSIS
+*
+*  void glp_unscale_prob(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_unscale_prob performs unscaling of problem data for
+*  the specified problem object.
+*
+*  "Unscaling" means replacing the current scaling matrices R and S by
+*  unity matrices that cancels the scaling effect. */
+
+void glp_unscale_prob(glp_prob *lp)
+{     int m = glp_get_num_rows(lp);
+      int n = glp_get_num_cols(lp);
+      int i, j;
+      for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0);
+      for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi05.c b/optional/glpk/glpapi05.c
new file mode 100644
index 0000000..de62816
--- /dev/null
+++ b/optional/glpk/glpapi05.c
@@ -0,0 +1,172 @@
+/* glpapi05.c (LP basis constructing routines) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_row_stat - set (change) row status
+*
+*  SYNOPSIS
+*
+*  void glp_set_row_stat(glp_prob *lp, int i, int stat);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_row_stat sets (changes) status of the auxiliary
+*  variable associated with i-th row.
+*
+*  The new status of the auxiliary variable should be specified by the
+*  parameter stat as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable;
+*  GLP_NU - non-basic variable on its upper bound; if the variable is
+*           not double-bounded, this means the same as GLP_NL (only in
+*           case of this routine);
+*  GLP_NF - the same as GLP_NL (only in case of this routine);
+*  GLP_NS - the same as GLP_NL (only in case of this routine). */
+
+void glp_set_row_stat(glp_prob *lp, int i, int stat)
+{     GLPROW *row;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_row_stat: i = %d; row number out of range\n",
+            i);
+      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
+            stat == GLP_NF || stat == GLP_NS))
+         xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n",
+            i, stat);
+      row = lp->row[i];
+      if (stat != GLP_BS)
+      {  switch (row->type)
+         {  case GLP_FR: stat = GLP_NF; break;
+            case GLP_LO: stat = GLP_NL; break;
+            case GLP_UP: stat = GLP_NU; break;
+            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
+            case GLP_FX: stat = GLP_NS; break;
+            default: xassert(row != row);
+         }
+      }
+      if (row->stat == GLP_BS && stat != GLP_BS ||
+          row->stat != GLP_BS && stat == GLP_BS)
+      {  /* invalidate the basis factorization */
+         lp->valid = 0;
+      }
+      row->stat = stat;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_stat - set (change) column status
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_stat(glp_prob *lp, int j, int stat);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_stat sets (changes) status of the structural
+*  variable associated with j-th column.
+*
+*  The new status of the structural variable should be specified by the
+*  parameter stat as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable;
+*  GLP_NU - non-basic variable on its upper bound; if the variable is
+*           not double-bounded, this means the same as GLP_NL (only in
+*           case of this routine);
+*  GLP_NF - the same as GLP_NL (only in case of this routine);
+*  GLP_NS - the same as GLP_NL (only in case of this routine). */
+
+void glp_set_col_stat(glp_prob *lp, int j, int stat)
+{     GLPCOL *col;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_col_stat: j = %d; column number out of range\n"
+            , j);
+      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
+            stat == GLP_NF || stat == GLP_NS))
+         xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n",
+            j, stat);
+      col = lp->col[j];
+      if (stat != GLP_BS)
+      {  switch (col->type)
+         {  case GLP_FR: stat = GLP_NF; break;
+            case GLP_LO: stat = GLP_NL; break;
+            case GLP_UP: stat = GLP_NU; break;
+            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
+            case GLP_FX: stat = GLP_NS; break;
+            default: xassert(col != col);
+         }
+      }
+      if (col->stat == GLP_BS && stat != GLP_BS ||
+          col->stat != GLP_BS && stat == GLP_BS)
+      {  /* invalidate the basis factorization */
+         lp->valid = 0;
+      }
+      col->stat = stat;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_std_basis - construct standard initial LP basis
+*
+*  SYNOPSIS
+*
+*  void glp_std_basis(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_std_basis builds the "standard" (trivial) initial
+*  basis for the specified problem object.
+*
+*  In the "standard" basis all auxiliary variables are basic, and all
+*  structural variables are non-basic. */
+
+void glp_std_basis(glp_prob *lp)
+{     int i, j;
+      /* make all auxiliary variables basic */
+      for (i = 1; i <= lp->m; i++)
+         glp_set_row_stat(lp, i, GLP_BS);
+      /* make all structural variables non-basic */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub))
+            glp_set_col_stat(lp, j, GLP_NU);
+         else
+            glp_set_col_stat(lp, j, GLP_NL);
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi06.c b/optional/glpk/glpapi06.c
new file mode 100644
index 0000000..3c1cb6d
--- /dev/null
+++ b/optional/glpk/glpapi06.c
@@ -0,0 +1,810 @@
+/* glpapi06.c (simplex method routines) */
+
+/***********************************************************************
+*  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 "-Wself-assign"
+#endif
+
+#include "glpios.h"
+#include "glpnpp.h"
+#include "glpspx.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_simplex - solve LP problem with the simplex method
+*
+*  SYNOPSIS
+*
+*  int glp_simplex(glp_prob *P, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_simplex is a driver to the LP solver based on the
+*  simplex method. This routine retrieves problem data from the
+*  specified problem object, calls the solver to solve the problem
+*  instance, and stores results of computations back into the problem
+*  object.
+*
+*  The simplex solver has a set of control parameters. Values of the
+*  control parameters can be passed in a structure glp_smcp, which the
+*  parameter parm points to.
+*
+*  The parameter parm can be specified as NULL, in which case the LP
+*  solver uses default settings.
+*
+*  RETURNS
+*
+*  0  The LP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EBADB
+*     Unable to start the search, because the initial basis specified
+*     in the problem object is invalid--the number of basic (auxiliary
+*     and structural) variables is not the same as the number of rows in
+*     the problem object.
+*
+*  GLP_ESING
+*     Unable to start the search, because the basis matrix correspodning
+*     to the initial basis is singular within the working precision.
+*
+*  GLP_ECOND
+*     Unable to start the search, because the basis matrix correspodning
+*     to the initial basis is ill-conditioned, i.e. its condition number
+*     is too large.
+*
+*  GLP_EBOUND
+*     Unable to start the search, because some double-bounded variables
+*     have incorrect bounds.
+*
+*  GLP_EFAIL
+*     The search was prematurely terminated due to the solver failure.
+*
+*  GLP_EOBJLL
+*     The search was prematurely terminated, because the objective
+*     function being maximized has reached its lower limit and continues
+*     decreasing (dual simplex only).
+*
+*  GLP_EOBJUL
+*     The search was prematurely terminated, because the objective
+*     function being minimized has reached its upper limit and continues
+*     increasing (dual simplex only).
+*
+*  GLP_EITLIM
+*     The search was prematurely terminated, because the simplex
+*     iteration limit has been exceeded.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded.
+*
+*  GLP_ENOPFS
+*     The LP problem instance has no primal feasible solution (only if
+*     the LP presolver is used).
+*
+*  GLP_ENODFS
+*     The LP problem instance has no dual feasible solution (only if the
+*     LP presolver is used). */
+
+static void trivial_lp(glp_prob *P, const glp_smcp *parm)
+{     /* solve trivial LP which has empty constraint matrix */
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      double p_infeas, d_infeas, zeta;
+      P->valid = 0;
+      P->pbs_stat = P->dbs_stat = GLP_FEAS;
+      P->obj_val = P->c0;
+      P->some = 0;
+      p_infeas = d_infeas = 0.0;
+      /* make all auxiliary variables basic */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         row->stat = GLP_BS;
+         row->prim = row->dual = 0.0;
+         /* check primal feasibility */
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+         {  /* row has lower bound */
+            if (row->lb > + parm->tol_bnd)
+            {  P->pbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth != GLP_PRIMAL)
+                  P->some = i;
+            }
+            if (p_infeas < + row->lb)
+               p_infeas = + row->lb;
+         }
+         if (row->type == GLP_UP || row->type == GLP_DB ||
+             row->type == GLP_FX)
+         {  /* row has upper bound */
+            if (row->ub < - parm->tol_bnd)
+            {  P->pbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth != GLP_PRIMAL)
+                  P->some = i;
+            }
+            if (p_infeas < - row->ub)
+               p_infeas = - row->ub;
+         }
+      }
+      /* determine scale factor for the objective row */
+      zeta = 1.0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (zeta < fabs(col->coef)) zeta = fabs(col->coef);
+      }
+      zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta;
+      /* make all structural variables non-basic */
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->type == GLP_FR)
+            col->stat = GLP_NF, col->prim = 0.0;
+         else if (col->type == GLP_LO)
+lo:         col->stat = GLP_NL, col->prim = col->lb;
+         else if (col->type == GLP_UP)
+up:         col->stat = GLP_NU, col->prim = col->ub;
+         else if (col->type == GLP_DB)
+         {  if (zeta * col->coef > 0.0)
+               goto lo;
+            else if (zeta * col->coef < 0.0)
+               goto up;
+            else if (fabs(col->lb) <= fabs(col->ub))
+               goto lo;
+            else
+               goto up;
+         }
+         else if (col->type == GLP_FX)
+            col->stat = GLP_NS, col->prim = col->lb;
+         col->dual = col->coef;
+         P->obj_val += col->coef * col->prim;
+         /* check dual feasibility */
+         if (col->type == GLP_FR || col->type == GLP_LO)
+         {  /* column has no upper bound */
+            if (zeta * col->dual < - parm->tol_dj)
+            {  P->dbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth == GLP_PRIMAL)
+                  P->some = P->m + j;
+            }
+            if (d_infeas < - zeta * col->dual)
+               d_infeas = - zeta * col->dual;
+         }
+         if (col->type == GLP_FR || col->type == GLP_UP)
+         {  /* column has no lower bound */
+            if (zeta * col->dual > + parm->tol_dj)
+            {  P->dbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth == GLP_PRIMAL)
+                  P->some = P->m + j;
+            }
+            if (d_infeas < + zeta * col->dual)
+               d_infeas = + zeta * col->dual;
+         }
+      }
+      /* simulate the simplex solver output */
+      if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
+      {  xprintf("~%6d: obj = %17.9e  infeas = %10.3e\n", P->it_cnt,
+            P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas);
+      }
+      if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0)
+      {  if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)
+            xprintf("OPTIMAL SOLUTION FOUND\n");
+         else if (P->pbs_stat == GLP_NOFEAS)
+            xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+         else if (parm->meth == GLP_PRIMAL)
+            xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+         else
+            xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+      }
+      return;
+}
+
+static int solve_lp(glp_prob *P, const glp_smcp *parm)
+{     /* solve LP directly without using the preprocessor */
+      int ret;
+      if (!glp_bf_exists(P))
+      {  ret = glp_factorize(P);
+         if (ret == 0)
+            ;
+         else if (ret == GLP_EBADB)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: initial basis is invalid\n");
+         }
+         else if (ret == GLP_ESING)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: initial basis is singular\n");
+         }
+         else if (ret == GLP_ECOND)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf(
+                  "glp_simplex: initial basis is ill-conditioned\n");
+         }
+         else
+            xassert(ret != ret);
+         if (ret != 0) goto done;
+      }
+      if (parm->meth == GLP_PRIMAL)
+         ret = spx_primal(P, parm);
+      else if (parm->meth == GLP_DUALP)
+      {  ret = spx_dual(P, parm);
+         if (ret == GLP_EFAIL && P->valid)
+            ret = spx_primal(P, parm);
+      }
+      else if (parm->meth == GLP_DUAL)
+         ret = spx_dual(P, parm);
+      else
+         xassert(parm != parm);
+done: return ret;
+}
+
+static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm)
+{     /* solve LP using the preprocessor */
+      NPP *npp;
+      glp_prob *lp = NULL;
+      glp_bfcp bfcp;
+      int ret;
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Preprocessing...\n");
+      /* create preprocessor workspace */
+      npp = npp_create_wksp();
+      /* load original problem into the preprocessor workspace */
+      npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF);
+      /* process LP prior to applying primal/dual simplex method */
+      ret = npp_simplex(npp, parm);
+      if (ret == 0)
+         ;
+      else if (ret == GLP_ENOPFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
+      }
+      else if (ret == GLP_ENODFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+      }
+      else
+         xassert(ret != ret);
+      if (ret != 0) goto done;
+      /* build transformed LP */
+      lp = glp_create_prob();
+      npp_build_prob(npp, lp);
+      /* if the transformed LP is empty, it has empty solution, which
+         is optimal */
+      if (lp->m == 0 && lp->n == 0)
+      {  lp->pbs_stat = lp->dbs_stat = GLP_FEAS;
+         lp->obj_val = lp->c0;
+         if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
+         {  xprintf("~%6d: obj = %17.9e  infeas = %10.3e\n", P->it_cnt,
+               lp->obj_val, 0.0);
+         }
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n");
+         goto post;
+      }
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s",
+            lp->nnz, lp->nnz == 1 ? "" : "s");
+      }
+      /* inherit basis factorization control parameters */
+      glp_get_bfcp(P, &bfcp);
+      glp_set_bfcp(lp, &bfcp);
+      /* scale the transformed problem */
+      {  ENV *env = get_env_ptr();
+         int term_out = env->term_out;
+         if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+            env->term_out = GLP_OFF;
+         else
+            env->term_out = GLP_ON;
+         glp_scale_prob(lp, GLP_SF_AUTO);
+         env->term_out = term_out;
+      }
+      /* build advanced initial basis */
+      {  ENV *env = get_env_ptr();
+         int term_out = env->term_out;
+         if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+            env->term_out = GLP_OFF;
+         else
+            env->term_out = GLP_ON;
+         glp_adv_basis(lp, 0);
+         env->term_out = term_out;
+      }
+      /* solve the transformed LP */
+      lp->it_cnt = P->it_cnt;
+      ret = solve_lp(lp, parm);
+      P->it_cnt = lp->it_cnt;
+      /* only optimal solution can be postprocessed */
+      if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat ==
+            GLP_FEAS))
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_simplex: unable to recover undefined or non-op"
+               "timal solution\n");
+         if (ret == 0)
+         {  if (lp->pbs_stat == GLP_NOFEAS)
+               ret = GLP_ENOPFS;
+            else if (lp->dbs_stat == GLP_NOFEAS)
+               ret = GLP_ENODFS;
+            else
+               xassert(lp != lp);
+         }
+         goto done;
+      }
+post: /* postprocess solution from the transformed LP */
+      npp_postprocess(npp, lp);
+      /* the transformed LP is no longer needed */
+      glp_delete_prob(lp), lp = NULL;
+      /* store solution to the original problem */
+      npp_unload_sol(npp, P);
+      /* the original LP has been successfully solved */
+      ret = 0;
+done: /* delete the transformed LP, if it exists */
+      if (lp != NULL) glp_delete_prob(lp);
+      /* delete preprocessor workspace */
+      npp_delete_wksp(npp);
+      return ret;
+}
+
+int glp_simplex(glp_prob *P, const glp_smcp *parm)
+{     /* solve LP problem with the simplex method */
+      glp_smcp _parm;
+      int i, j, ret;
+      /* check problem object */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_simplex: P = %p; invalid problem object\n", P);
+      if (P->tree != NULL && P->tree->reason != 0)
+         xerror("glp_simplex: operation not allowed\n");
+      /* check control parameters */
+      if (parm == NULL)
+         parm = &_parm, glp_init_smcp((glp_smcp *)parm);
+      if (!(parm->msg_lev == GLP_MSG_OFF ||
+            parm->msg_lev == GLP_MSG_ERR ||
+            parm->msg_lev == GLP_MSG_ON  ||
+            parm->msg_lev == GLP_MSG_ALL ||
+            parm->msg_lev == GLP_MSG_DBG))
+         xerror("glp_simplex: msg_lev = %d; invalid parameter\n",
+            parm->msg_lev);
+      if (!(parm->meth == GLP_PRIMAL ||
+            parm->meth == GLP_DUALP  ||
+            parm->meth == GLP_DUAL))
+         xerror("glp_simplex: meth = %d; invalid parameter\n",
+            parm->meth);
+      if (!(parm->pricing == GLP_PT_STD ||
+            parm->pricing == GLP_PT_PSE))
+         xerror("glp_simplex: pricing = %d; invalid parameter\n",
+            parm->pricing);
+      if (!(parm->r_test == GLP_RT_STD ||
+            parm->r_test == GLP_RT_HAR))
+         xerror("glp_simplex: r_test = %d; invalid parameter\n",
+            parm->r_test);
+      if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
+         xerror("glp_simplex: tol_bnd = %g; invalid parameter\n",
+            parm->tol_bnd);
+      if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
+         xerror("glp_simplex: tol_dj = %g; invalid parameter\n",
+            parm->tol_dj);
+      if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
+         xerror("glp_simplex: tol_piv = %g; invalid parameter\n",
+            parm->tol_piv);
+      if (parm->it_lim < 0)
+         xerror("glp_simplex: it_lim = %d; invalid parameter\n",
+            parm->it_lim);
+      if (parm->tm_lim < 0)
+         xerror("glp_simplex: tm_lim = %d; invalid parameter\n",
+            parm->tm_lim);
+      if (parm->out_frq < 1)
+         xerror("glp_simplex: out_frq = %d; invalid parameter\n",
+            parm->out_frq);
+      if (parm->out_dly < 0)
+         xerror("glp_simplex: out_dly = %d; invalid parameter\n",
+            parm->out_dly);
+      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
+         xerror("glp_simplex: presolve = %d; invalid parameter\n",
+            parm->presolve);
+      /* basic solution is currently undefined */
+      P->pbs_stat = P->dbs_stat = GLP_UNDEF;
+      P->obj_val = 0.0;
+      P->some = 0;
+      /* check bounds of double-bounded variables */
+      for (i = 1; i <= P->m; i++)
+      {  GLPROW *row = P->row[i];
+         if (row->type == GLP_DB && row->lb >= row->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec"
+                  "t bounds\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+         if (col->type == GLP_DB && col->lb >= col->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor"
+                  "rect bounds\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* solve LP problem */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  xprintf("GLPK Simplex Optimizer, v%s\n", glp_version());
+         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+            P->nnz, P->nnz == 1 ? "" : "s");
+      }
+      if (P->nnz == 0)
+         trivial_lp(P, parm), ret = 0;
+      else if (!parm->presolve)
+         ret = solve_lp(P, parm);
+      else
+         ret = preprocess_and_solve_lp(P, parm);
+done: /* return to the application program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_smcp - initialize simplex method control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_smcp(glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_smcp initializes control parameters, which are
+*  used by the simplex solver, with default values.
+*
+*  Default values of the control parameters are stored in a glp_smcp
+*  structure, which the parameter parm points to. */
+
+void glp_init_smcp(glp_smcp *parm)
+{     parm->msg_lev = GLP_MSG_ALL;
+      parm->meth = GLP_PRIMAL;
+      parm->pricing = GLP_PT_PSE;
+      parm->r_test = GLP_RT_HAR;
+      parm->tol_bnd = 1e-7;
+      parm->tol_dj = 1e-7;
+      parm->tol_piv = 1e-10;
+      parm->obj_ll = -DBL_MAX;
+      parm->obj_ul = +DBL_MAX;
+      parm->it_lim = INT_MAX;
+      parm->tm_lim = INT_MAX;
+      parm->out_frq = 500;
+      parm->out_dly = 0;
+      parm->presolve = GLP_OFF;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_status - retrieve generic status of basic solution
+*
+*  SYNOPSIS
+*
+*  int glp_get_status(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_status reports the generic status of the basic
+*  solution for the specified problem object as follows:
+*
+*  GLP_OPT    - solution is optimal;
+*  GLP_FEAS   - solution is feasible;
+*  GLP_INFEAS - solution is infeasible;
+*  GLP_NOFEAS - problem has no feasible solution;
+*  GLP_UNBND  - problem has unbounded solution;
+*  GLP_UNDEF  - solution is undefined. */
+
+int glp_get_status(glp_prob *lp)
+{     int status;
+      status = glp_get_prim_stat(lp);
+      switch (status)
+      {  case GLP_FEAS:
+            switch (glp_get_dual_stat(lp))
+            {  case GLP_FEAS:
+                  status = GLP_OPT;
+                  break;
+               case GLP_NOFEAS:
+                  status = GLP_UNBND;
+                  break;
+               case GLP_UNDEF:
+               case GLP_INFEAS:
+                  status = status;
+                  break;
+               default:
+                  xassert(lp != lp);
+            }
+            break;
+         case GLP_UNDEF:
+         case GLP_INFEAS:
+         case GLP_NOFEAS:
+            status = status;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return status;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_prim_stat - retrieve status of primal basic solution
+*
+*  SYNOPSIS
+*
+*  int glp_get_prim_stat(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_prim_stat reports the status of the primal basic
+*  solution for the specified problem object as follows:
+*
+*  GLP_UNDEF  - primal solution is undefined;
+*  GLP_FEAS   - primal solution is feasible;
+*  GLP_INFEAS - primal solution is infeasible;
+*  GLP_NOFEAS - no primal feasible solution exists. */
+
+int glp_get_prim_stat(glp_prob *lp)
+{     int pbs_stat = lp->pbs_stat;
+      return pbs_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_dual_stat - retrieve status of dual basic solution
+*
+*  SYNOPSIS
+*
+*  int glp_get_dual_stat(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_dual_stat reports the status of the dual basic
+*  solution for the specified problem object as follows:
+*
+*  GLP_UNDEF  - dual solution is undefined;
+*  GLP_FEAS   - dual solution is feasible;
+*  GLP_INFEAS - dual solution is infeasible;
+*  GLP_NOFEAS - no dual feasible solution exists. */
+
+int glp_get_dual_stat(glp_prob *lp)
+{     int dbs_stat = lp->dbs_stat;
+      return dbs_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_val - retrieve objective value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_obj_val(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_val returns value of the objective function
+*  for basic solution. */
+
+double glp_get_obj_val(glp_prob *lp)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double z;
+      z = lp->obj_val;
+      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+      return z;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_stat - retrieve row status
+*
+*  SYNOPSIS
+*
+*  int glp_get_row_stat(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_stat returns current status assigned to the
+*  auxiliary variable associated with i-th row as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on its lower bound;
+*  GLP_NU - non-basic variable on its upper bound;
+*  GLP_NF - non-basic free (unbounded) variable;
+*  GLP_NS - non-basic fixed variable. */
+
+int glp_get_row_stat(glp_prob *lp, int i)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_stat: i = %d; row number out of range\n",
+            i);
+      return lp->row[i]->stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_prim - retrieve row primal value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_prim(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_prim returns primal value of the auxiliary
+*  variable associated with i-th row. */
+
+double glp_get_row_prim(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double prim;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_prim: i = %d; row number out of range\n",
+            i);
+      prim = lp->row[i]->prim;
+      /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
+      return prim;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_dual - retrieve row dual value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_dual(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_dual returns dual value (i.e. reduced cost)
+*  of the auxiliary variable associated with i-th row. */
+
+double glp_get_row_dual(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dual;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_dual: i = %d; row number out of range\n",
+            i);
+      dual = lp->row[i]->dual;
+      /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
+      return dual;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_stat - retrieve column status
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_stat(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_stat returns current status assigned to the
+*  structural variable associated with j-th column as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on its lower bound;
+*  GLP_NU - non-basic variable on its upper bound;
+*  GLP_NF - non-basic free (unbounded) variable;
+*  GLP_NS - non-basic fixed variable. */
+
+int glp_get_col_stat(glp_prob *lp, int j)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_stat: j = %d; column number out of range\n"
+            , j);
+      return lp->col[j]->stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_prim - retrieve column primal value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_prim(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_prim returns primal value of the structural
+*  variable associated with j-th column. */
+
+double glp_get_col_prim(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double prim;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_prim: j = %d; column number out of range\n"
+            , j);
+      prim = lp->col[j]->prim;
+      /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
+      return prim;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_dual - retrieve column dual value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_dual(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_dual returns dual value (i.e. reduced cost)
+*  of the structural variable associated with j-th column. */
+
+double glp_get_col_dual(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dual;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_dual: j = %d; column number out of range\n"
+            , j);
+      dual = lp->col[j]->dual;
+      /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
+      return dual;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_unbnd_ray - determine variable causing unboundedness
+*
+*  SYNOPSIS
+*
+*  int glp_get_unbnd_ray(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_unbnd_ray returns the number k of a variable,
+*  which causes primal or dual unboundedness. If 1 <= k <= m, it is
+*  k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th
+*  structural variable, where m is the number of rows, n is the number
+*  of columns in the problem object. If such variable is not defined,
+*  the routine returns 0.
+*
+*  COMMENTS
+*
+*  If it is not exactly known which version of the simplex solver
+*  detected unboundedness, i.e. whether the unboundedness is primal or
+*  dual, it is sufficient to check the status of the variable reported
+*  with the routine glp_get_row_stat or glp_get_col_stat. If the
+*  variable is non-basic, the unboundedness is primal, otherwise, if
+*  the variable is basic, the unboundedness is dual (the latter case
+*  means that the problem has no primal feasible dolution). */
+
+int glp_get_unbnd_ray(glp_prob *lp)
+{     int k;
+      k = lp->some;
+      xassert(k >= 0);
+      if (k > lp->m + lp->n) k = 0;
+      return k;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi07.c b/optional/glpk/glpapi07.c
new file mode 100644
index 0000000..094ffd8
--- /dev/null
+++ b/optional/glpk/glpapi07.c
@@ -0,0 +1,451 @@
+/* glpapi07.c (exact simplex solver) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpssx.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_exact - solve LP problem in exact arithmetic
+*
+*  SYNOPSIS
+*
+*  int glp_exact(glp_prob *lp, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_exact is a tentative implementation of the primal
+*  two-phase simplex method based on exact (rational) arithmetic. It is
+*  similar to the routine glp_simplex, however, for all internal
+*  computations it uses arithmetic of rational numbers, which is exact
+*  in mathematical sense, i.e. free of round-off errors unlike floating
+*  point arithmetic.
+*
+*  Note that the routine glp_exact uses inly two control parameters
+*  passed in the structure glp_smcp, namely, it_lim and tm_lim.
+*
+*  RETURNS
+*
+*  0  The LP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EBADB
+*     Unable to start the search, because the initial basis specified
+*     in the problem object is invalid--the number of basic (auxiliary
+*     and structural) variables is not the same as the number of rows in
+*     the problem object.
+*
+*  GLP_ESING
+*     Unable to start the search, because the basis matrix correspodning
+*     to the initial basis is exactly singular.
+*
+*  GLP_EBOUND
+*     Unable to start the search, because some double-bounded variables
+*     have incorrect bounds.
+*
+*  GLP_EFAIL
+*     The problem has no rows/columns.
+*
+*  GLP_EITLIM
+*     The search was prematurely terminated, because the simplex
+*     iteration limit has been exceeded.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded. */
+
+static void set_d_eps(mpq_t x, double val)
+{     /* convert double val to rational x obtaining a more adequate
+         fraction than provided by mpq_set_d due to allowing a small
+         approximation error specified by a given relative tolerance;
+         for example, mpq_set_d would give the following
+         1/3 ~= 0.333333333333333314829616256247391... ->
+             -> 6004799503160661/18014398509481984
+         while this routine gives exactly 1/3 */
+      int s, n, j;
+      double f, p, q, eps = 1e-9;
+      mpq_t temp;
+      xassert(-DBL_MAX <= val && val <= +DBL_MAX);
+#if 1 /* 30/VII-2008 */
+      if (val == floor(val))
+      {  /* if val is integral, do not approximate */
+         mpq_set_d(x, val);
+         goto done;
+      }
+#endif
+      if (val > 0.0)
+         s = +1;
+      else if (val < 0.0)
+         s = -1;
+      else
+      {  mpq_set_si(x, 0, 1);
+         goto done;
+      }
+      f = frexp(fabs(val), &n);
+      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
+      fp2rat(f, 0.1 * eps, &p, &q);
+      /* f ~= p / q, where p and q are integers */
+      mpq_init(temp);
+      mpq_set_d(x, p);
+      mpq_set_d(temp, q);
+      mpq_div(x, x, temp);
+      mpq_set_si(temp, 1, 1);
+      for (j = 1; j <= abs(n); j++)
+         mpq_add(temp, temp, temp);
+      if (n > 0)
+         mpq_mul(x, x, temp);
+      else if (n < 0)
+         mpq_div(x, x, temp);
+      mpq_clear(temp);
+      if (s < 0) mpq_neg(x, x);
+      /* check that the desired tolerance has been attained */
+      xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
+done: return;
+}
+
+static void load_data(SSX *ssx, LPX *lp)
+{     /* load LP problem data into simplex solver workspace */
+      int m = ssx->m;
+      int n = ssx->n;
+      int nnz = ssx->A_ptr[n+1]-1;
+      int j, k, type, loc, len, *ind;
+      double lb, ub, coef, *val;
+      xassert(lpx_get_num_rows(lp) == m);
+      xassert(lpx_get_num_cols(lp) == n);
+      xassert(lpx_get_num_nz(lp) == nnz);
+      /* types and bounds of rows and columns */
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  type = lpx_get_row_type(lp, k);
+            lb = lpx_get_row_lb(lp, k);
+            ub = lpx_get_row_ub(lp, k);
+         }
+         else
+         {  type = lpx_get_col_type(lp, k-m);
+            lb = lpx_get_col_lb(lp, k-m);
+            ub = lpx_get_col_ub(lp, k-m);
+         }
+         switch (type)
+         {  case LPX_FR: type = SSX_FR; break;
+            case LPX_LO: type = SSX_LO; break;
+            case LPX_UP: type = SSX_UP; break;
+            case LPX_DB: type = SSX_DB; break;
+            case LPX_FX: type = SSX_FX; break;
+            default: xassert(type != type);
+         }
+         ssx->type[k] = type;
+         set_d_eps(ssx->lb[k], lb);
+         set_d_eps(ssx->ub[k], ub);
+      }
+      /* optimization direction */
+      switch (lpx_get_obj_dir(lp))
+      {  case LPX_MIN: ssx->dir = SSX_MIN; break;
+         case LPX_MAX: ssx->dir = SSX_MAX; break;
+         default: xassert(lp != lp);
+      }
+      /* objective coefficients */
+      for (k = 0; k <= m+n; k++)
+      {  if (k == 0)
+            coef = lpx_get_obj_coef(lp, 0);
+         else if (k <= m)
+            coef = 0.0;
+         else
+            coef = lpx_get_obj_coef(lp, k-m);
+         set_d_eps(ssx->coef[k], coef);
+      }
+      /* constraint coefficients */
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      loc = 0;
+      for (j = 1; j <= n; j++)
+      {  ssx->A_ptr[j] = loc+1;
+         len = lpx_get_mat_col(lp, j, ind, val);
+         for (k = 1; k <= len; k++)
+         {  loc++;
+            ssx->A_ind[loc] = ind[k];
+            set_d_eps(ssx->A_val[loc], val[k]);
+         }
+      }
+      xassert(loc == nnz);
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+static int load_basis(SSX *ssx, LPX *lp)
+{     /* load current LP basis into simplex solver workspace */
+      int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      int *stat = ssx->stat;
+      int *Q_row = ssx->Q_row;
+      int *Q_col = ssx->Q_col;
+      int i, j, k;
+      xassert(lpx_get_num_rows(lp) == m);
+      xassert(lpx_get_num_cols(lp) == n);
+      /* statuses of rows and columns */
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+            stat[k] = lpx_get_row_stat(lp, k);
+         else
+            stat[k] = lpx_get_col_stat(lp, k-m);
+         switch (stat[k])
+         {  case LPX_BS:
+               stat[k] = SSX_BS;
+               break;
+            case LPX_NL:
+               stat[k] = SSX_NL;
+               xassert(type[k] == SSX_LO || type[k] == SSX_DB);
+               break;
+            case LPX_NU:
+               stat[k] = SSX_NU;
+               xassert(type[k] == SSX_UP || type[k] == SSX_DB);
+               break;
+            case LPX_NF:
+               stat[k] = SSX_NF;
+               xassert(type[k] == SSX_FR);
+               break;
+            case LPX_NS:
+               stat[k] = SSX_NS;
+               xassert(type[k] == SSX_FX);
+               break;
+            default:
+               xassert(stat != stat);
+         }
+      }
+      /* build permutation matix Q */
+      i = j = 0;
+      for (k = 1; k <= m+n; k++)
+      {  if (stat[k] == SSX_BS)
+         {  i++;
+            if (i > m) return 1;
+            Q_row[k] = i, Q_col[i] = k;
+         }
+         else
+         {  j++;
+            if (j > n) return 1;
+            Q_row[k] = m+j, Q_col[m+j] = k;
+         }
+      }
+      xassert(i == m && j == n);
+      return 0;
+}
+
+int glp_exact(glp_prob *lp, const glp_smcp *parm)
+{     glp_smcp _parm;
+      SSX *ssx;
+      int m = lpx_get_num_rows(lp);
+      int n = lpx_get_num_cols(lp);
+      int nnz = lpx_get_num_nz(lp);
+      int i, j, k, type, pst, dst, ret, *stat;
+      double lb, ub, *prim, *dual, sum;
+      if (parm == NULL)
+         parm = &_parm, glp_init_smcp((glp_smcp *)parm);
+      /* check control parameters */
+      if (parm->it_lim < 0)
+         xerror("glp_exact: it_lim = %d; invalid parameter\n",
+            parm->it_lim);
+      if (parm->tm_lim < 0)
+         xerror("glp_exact: tm_lim = %d; invalid parameter\n",
+            parm->tm_lim);
+      /* the problem must have at least one row and one column */
+      if (!(m > 0 && n > 0))
+      {  xprintf("glp_exact: problem has no rows/columns\n");
+         return GLP_EFAIL;
+      }
+#if 1
+      /* basic solution is currently undefined */
+      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+      lp->obj_val = 0.0;
+      lp->some = 0;
+#endif
+      /* check that all double-bounded variables have correct bounds */
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  type = lpx_get_row_type(lp, k);
+            lb = lpx_get_row_lb(lp, k);
+            ub = lpx_get_row_ub(lp, k);
+         }
+         else
+         {  type = lpx_get_col_type(lp, k-m);
+            lb = lpx_get_col_lb(lp, k-m);
+            ub = lpx_get_col_ub(lp, k-m);
+         }
+         if (type == LPX_DB && lb >= ub)
+         {  xprintf("glp_exact: %s %d has invalid bounds\n",
+               k <= m ? "row" : "column", k <= m ? k : k-m);
+            return GLP_EBOUND;
+         }
+      }
+      /* create the simplex solver workspace */
+      xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
+         m, n, nnz);
+#ifdef HAVE_GMP
+      xprintf("GNU MP bignum library is being used\n");
+#else
+      xprintf("GLPK bignum module is being used\n");
+      xprintf("(Consider installing GNU MP to attain a much better perf"
+         "ormance.)\n");
+#endif
+      ssx = ssx_create(m, n, nnz);
+      /* load LP problem data into the workspace */
+      load_data(ssx, lp);
+      /* load current LP basis into the workspace */
+      if (load_basis(ssx, lp))
+      {  xprintf("glp_exact: initial LP basis is invalid\n");
+         ret = GLP_EBADB;
+         goto done;
+      }
+      /* inherit some control parameters from the LP object */
+#if 0
+      ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
+      ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
+      ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
+#else
+      ssx->it_lim = parm->it_lim;
+      ssx->it_cnt = lp->it_cnt;
+      ssx->tm_lim = (double)parm->tm_lim / 1000.0;
+#endif
+      ssx->out_frq = 5.0;
+      ssx->tm_beg = xtime();
+      ssx->tm_lag = xlset(0);
+      /* solve LP */
+      ret = ssx_driver(ssx);
+      /* copy back some statistics to the LP object */
+#if 0
+      lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
+      lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
+      lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
+#else
+      lp->it_cnt = ssx->it_cnt;
+#endif
+      /* analyze the return code */
+      switch (ret)
+      {  case 0:
+            /* optimal solution found */
+            ret = 0;
+            pst = LPX_P_FEAS, dst = LPX_D_FEAS;
+            break;
+         case 1:
+            /* problem has no feasible solution */
+            ret = 0;
+            pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS;
+            break;
+         case 2:
+            /* problem has unbounded solution */
+            ret = 0;
+            pst = LPX_P_FEAS, dst = LPX_D_NOFEAS;
+#if 1
+            xassert(1 <= ssx->q && ssx->q <= n);
+            lp->some = ssx->Q_col[m + ssx->q];
+            xassert(1 <= lp->some && lp->some <= m+n);
+#endif
+            break;
+         case 3:
+            /* iteration limit exceeded (phase I) */
+            ret = GLP_EITLIM;
+            pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
+            break;
+         case 4:
+            /* iteration limit exceeded (phase II) */
+            ret = GLP_EITLIM;
+            pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
+            break;
+         case 5:
+            /* time limit exceeded (phase I) */
+            ret = GLP_ETMLIM;
+            pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
+            break;
+         case 6:
+            /* time limit exceeded (phase II) */
+            ret = GLP_ETMLIM;
+            pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
+            break;
+         case 7:
+            /* initial basis matrix is singular */
+            ret = GLP_ESING;
+            goto done;
+         default:
+            xassert(ret != ret);
+      }
+      /* obtain final basic solution components */
+      stat = xcalloc(1+m+n, sizeof(int));
+      prim = xcalloc(1+m+n, sizeof(double));
+      dual = xcalloc(1+m+n, sizeof(double));
+      for (k = 1; k <= m+n; k++)
+      {  if (ssx->stat[k] == SSX_BS)
+         {  i = ssx->Q_row[k]; /* x[k] = xB[i] */
+            xassert(1 <= i && i <= m);
+            stat[k] = LPX_BS;
+            prim[k] = mpq_get_d(ssx->bbar[i]);
+            dual[k] = 0.0;
+         }
+         else
+         {  j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
+            xassert(1 <= j && j <= n);
+            switch (ssx->stat[k])
+            {  case SSX_NF:
+                  stat[k] = LPX_NF;
+                  prim[k] = 0.0;
+                  break;
+               case SSX_NL:
+                  stat[k] = LPX_NL;
+                  prim[k] = mpq_get_d(ssx->lb[k]);
+                  break;
+               case SSX_NU:
+                  stat[k] = LPX_NU;
+                  prim[k] = mpq_get_d(ssx->ub[k]);
+                  break;
+               case SSX_NS:
+                  stat[k] = LPX_NS;
+                  prim[k] = mpq_get_d(ssx->lb[k]);
+                  break;
+               default:
+                  xassert(ssx != ssx);
+            }
+            dual[k] = mpq_get_d(ssx->cbar[j]);
+         }
+      }
+      /* and store them into the LP object */
+      pst = pst - LPX_P_UNDEF + GLP_UNDEF;
+      dst = dst - LPX_D_UNDEF + GLP_UNDEF;
+      for (k = 1; k <= m+n; k++)
+         stat[k] = stat[k] - LPX_BS + GLP_BS;
+      sum = lpx_get_obj_coef(lp, 0);
+      for (j = 1; j <= n; j++)
+         sum += lpx_get_obj_coef(lp, j) * prim[m+j];
+      lpx_put_solution(lp, 1, &pst, &dst, &sum,
+         &stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]);
+      xfree(stat);
+      xfree(prim);
+      xfree(dual);
+done: /* delete the simplex solver workspace */
+      ssx_delete(ssx);
+      /* return to the application program */
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi08.c b/optional/glpk/glpapi08.c
new file mode 100644
index 0000000..b5cb5f0
--- /dev/null
+++ b/optional/glpk/glpapi08.c
@@ -0,0 +1,389 @@
+/* glpapi08.c (interior-point method routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpipm.h"
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_interior - solve LP problem with the interior-point method
+*
+*  SYNOPSIS
+*
+*  int glp_interior(glp_prob *P, const glp_iptcp *parm);
+*
+*  The routine glp_interior is a driver to the LP solver based on the
+*  interior-point method.
+*
+*  The interior-point solver has a set of control parameters. Values of
+*  the control parameters can be passed in a structure glp_iptcp, which
+*  the parameter parm points to.
+*
+*  Currently this routine implements an easy variant of the primal-dual
+*  interior-point method based on Mehrotra's technique.
+*
+*  This routine transforms the original LP problem to an equivalent LP
+*  problem in the standard formulation (all constraints are equalities,
+*  all variables are non-negative), calls the routine ipm_main to solve
+*  the transformed problem, and then transforms an obtained solution to
+*  the solution of the original problem.
+*
+*  RETURNS
+*
+*  0  The LP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EFAIL
+*     The problem has no rows/columns.
+*
+*  GLP_ENOCVG
+*     Very slow convergence or divergence.
+*
+*  GLP_EITLIM
+*     Iteration limit exceeded.
+*
+*  GLP_EINSTAB
+*     Numerical instability on solving Newtonian system. */
+
+static void transform(NPP *npp)
+{     /* transform LP to the standard formulation */
+      NPPROW *row, *prev_row;
+      NPPCOL *col, *prev_col;
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+            npp_free_row(npp, row);
+         else if (row->lb == -DBL_MAX)
+            npp_leq_row(npp, row);
+         else if (row->ub == +DBL_MAX)
+            npp_geq_row(npp, row);
+         else if (row->lb != row->ub)
+         {  if (fabs(row->lb) < fabs(row->ub))
+               npp_geq_row(npp, row);
+            else
+               npp_leq_row(npp, row);
+         }
+      }
+      for (col = npp->c_tail; col != NULL; col = prev_col)
+      {  prev_col = col->prev;
+         if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+            npp_free_col(npp, col);
+         else if (col->lb == -DBL_MAX)
+            npp_ubnd_col(npp, col);
+         else if (col->ub == +DBL_MAX)
+         {  if (col->lb != 0.0)
+               npp_lbnd_col(npp, col);
+         }
+         else if (col->lb != col->ub)
+         {  if (fabs(col->lb) < fabs(col->ub))
+            {  if (col->lb != 0.0)
+                  npp_lbnd_col(npp, col);
+            }
+            else
+               npp_ubnd_col(npp, col);
+            npp_dbnd_col(npp, col);
+         }
+         else
+            npp_fixed_col(npp, col);
+      }
+      for (row = npp->r_head; row != NULL; row = row->next)
+         xassert(row->lb == row->ub);
+      for (col = npp->c_head; col != NULL; col = col->next)
+         xassert(col->lb == 0.0 && col->ub == +DBL_MAX);
+      return;
+}
+
+int glp_interior(glp_prob *P, const glp_iptcp *parm)
+{     glp_iptcp _parm;
+      GLPROW *row;
+      GLPCOL *col;
+      NPP *npp = NULL;
+      glp_prob *prob = NULL;
+      int i, j, ret;
+      /* check control parameters */
+      if (parm == NULL)
+         glp_init_iptcp(&_parm), parm = &_parm;
+      if (!(parm->msg_lev == GLP_MSG_OFF ||
+            parm->msg_lev == GLP_MSG_ERR ||
+            parm->msg_lev == GLP_MSG_ON  ||
+            parm->msg_lev == GLP_MSG_ALL))
+         xerror("glp_interior: msg_lev = %d; invalid parameter\n",
+            parm->msg_lev);
+      if (!(parm->ord_alg == GLP_ORD_NONE ||
+            parm->ord_alg == GLP_ORD_QMD ||
+            parm->ord_alg == GLP_ORD_AMD ||
+            parm->ord_alg == GLP_ORD_SYMAMD))
+         xerror("glp_interior: ord_alg = %d; invalid parameter\n",
+            parm->ord_alg);
+      /* interior-point solution is currently undefined */
+      P->ipt_stat = GLP_UNDEF;
+      P->ipt_obj = 0.0;
+      /* check bounds of double-bounded variables */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type == GLP_DB && row->lb >= row->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre"
+                  "ct bounds\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->type == GLP_DB && col->lb >= col->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_interior: column %d: lb = %g, ub = %g; inco"
+                  "rrect bounds\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* transform LP to the standard formulation */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Original LP has %d row(s), %d column(s), and %d non-z"
+            "ero(s)\n", P->m, P->n, P->nnz);
+      npp = npp_create_wksp();
+      npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON);
+      transform(npp);
+      prob = glp_create_prob();
+      npp_build_prob(npp, prob);
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Working LP has %d row(s), %d column(s), and %d non-ze"
+            "ro(s)\n", prob->m, prob->n, prob->nnz);
+#if 1
+      /* currently empty problem cannot be solved */
+      if (!(prob->m > 0 && prob->n > 0))
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_interior: unable to solve empty problem\n");
+         ret = GLP_EFAIL;
+         goto done;
+      }
+#endif
+      /* scale the resultant LP */
+      {  ENV *env = get_env_ptr();
+         int term_out = env->term_out;
+         env->term_out = GLP_OFF;
+         glp_scale_prob(prob, GLP_SF_EQ);
+         env->term_out = term_out;
+      }
+      /* warn about dense columns */
+      if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200)
+      {  int len, cnt = 0;
+         for (j = 1; j <= prob->n; j++)
+         {  len = glp_get_mat_col(prob, j, NULL, NULL);
+            if ((double)len >= 0.20 * (double)prob->m) cnt++;
+         }
+         if (cnt == 1)
+            xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n");
+         else if (cnt > 0)
+            xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt);
+      }
+      /* solve the transformed LP */
+      ret = ipm_solve(prob, parm);
+      /* postprocess solution from the transformed LP */
+      npp_postprocess(npp, prob);
+      /* and store solution to the original LP */
+      npp_unload_sol(npp, P);
+done: /* free working program objects */
+      if (npp != NULL) npp_delete_wksp(npp);
+      if (prob != NULL) glp_delete_prob(prob);
+      /* return to the application program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_iptcp - initialize interior-point solver control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_iptcp(glp_iptcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_iptcp initializes control parameters, which are
+*  used by the interior-point solver, with default values.
+*
+*  Default values of the control parameters are stored in the glp_iptcp
+*  structure, which the parameter parm points to. */
+
+void glp_init_iptcp(glp_iptcp *parm)
+{     parm->msg_lev = GLP_MSG_ALL;
+      parm->ord_alg = GLP_ORD_AMD;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_status - retrieve status of interior-point solution
+*
+*  SYNOPSIS
+*
+*  int glp_ipt_status(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_status reports the status of solution found by
+*  the interior-point solver as follows:
+*
+*  GLP_UNDEF  - interior-point solution is undefined;
+*  GLP_OPT    - interior-point solution is optimal;
+*  GLP_INFEAS - interior-point solution is infeasible;
+*  GLP_NOFEAS - no feasible solution exists. */
+
+int glp_ipt_status(glp_prob *lp)
+{     int ipt_stat = lp->ipt_stat;
+      return ipt_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_obj_val - retrieve objective value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_obj_val(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_obj_val returns value of the objective function
+*  for interior-point solution. */
+
+double glp_ipt_obj_val(glp_prob *lp)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double z;
+      z = lp->ipt_obj;
+      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+      return z;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_row_prim - retrieve row primal value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_row_prim(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_row_prim returns primal value of the auxiliary
+*  variable associated with i-th row. */
+
+double glp_ipt_row_prim(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double pval;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_ipt_row_prim: i = %d; row number out of range\n",
+            i);
+      pval = lp->row[i]->pval;
+      /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
+      return pval;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_row_dual - retrieve row dual value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_row_dual(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_row_dual returns dual value (i.e. reduced cost)
+*  of the auxiliary variable associated with i-th row. */
+
+double glp_ipt_row_dual(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dval;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_ipt_row_dual: i = %d; row number out of range\n",
+            i);
+      dval = lp->row[i]->dval;
+      /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
+      return dval;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_col_prim - retrieve column primal value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_col_prim(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_col_prim returns primal value of the structural
+*  variable associated with j-th column. */
+
+double glp_ipt_col_prim(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double pval;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_ipt_col_prim: j = %d; column number out of range\n"
+            , j);
+      pval = lp->col[j]->pval;
+      /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
+      return pval;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_col_dual - retrieve column dual value (interior point)
+*
+*  SYNOPSIS
+*
+*  #include "glplpx.h"
+*  double glp_ipt_col_dual(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_col_dual returns dual value (i.e. reduced cost)
+*  of the structural variable associated with j-th column. */
+
+double glp_ipt_col_dual(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dval;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_ipt_col_dual: j = %d; column number out of range\n"
+            , j);
+      dval = lp->col[j]->dval;
+      /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
+      return dval;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi09.c b/optional/glpk/glpapi09.c
new file mode 100644
index 0000000..1d92985
--- /dev/null
+++ b/optional/glpk/glpapi09.c
@@ -0,0 +1,741 @@
+/* glpapi09.c (mixed integer programming routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpios.h"
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_kind - set (change) column kind
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_kind(glp_prob *mip, int j, int kind);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_kind sets (changes) the kind of j-th column
+*  (structural variable) as specified by the parameter kind:
+*
+*  GLP_CV - continuous variable;
+*  GLP_IV - integer variable;
+*  GLP_BV - binary variable. */
+
+void glp_set_col_kind(glp_prob *mip, int j, int kind)
+{     GLPCOL *col;
+      if (!(1 <= j && j <= mip->n))
+         xerror("glp_set_col_kind: j = %d; column number out of range\n"
+            , j);
+      col = mip->col[j];
+      switch (kind)
+      {  case GLP_CV:
+            col->kind = GLP_CV;
+            break;
+         case GLP_IV:
+            col->kind = GLP_IV;
+            break;
+         case GLP_BV:
+            col->kind = GLP_IV;
+            if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
+               1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
+            break;
+         default:
+            xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
+               " kind\n", j, kind);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_kind - retrieve column kind
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_kind(glp_prob *mip, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_kind returns the kind of j-th column, i.e.
+*  the kind of corresponding structural variable, as follows:
+*
+*  GLP_CV - continuous variable;
+*  GLP_IV - integer variable;
+*  GLP_BV - binary variable */
+
+int glp_get_col_kind(glp_prob *mip, int j)
+{     GLPCOL *col;
+      int kind;
+      if (!(1 <= j && j <= mip->n))
+         xerror("glp_get_col_kind: j = %d; column number out of range\n"
+            , j);
+      col = mip->col[j];
+      kind = col->kind;
+      switch (kind)
+      {  case GLP_CV:
+            break;
+         case GLP_IV:
+            if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
+               kind = GLP_BV;
+            break;
+         default:
+            xassert(kind != kind);
+      }
+      return kind;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_int - retrieve number of integer columns
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_int(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_int returns the current number of columns,
+*  which are marked as integer. */
+
+int glp_get_num_int(glp_prob *mip)
+{     GLPCOL *col;
+      int j, count = 0;
+      for (j = 1; j <= mip->n; j++)
+      {  col = mip->col[j];
+         if (col->kind == GLP_IV) count++;
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_bin - retrieve number of binary columns
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_bin(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_bin returns the current number of columns,
+*  which are marked as binary. */
+
+int glp_get_num_bin(glp_prob *mip)
+{     GLPCOL *col;
+      int j, count = 0;
+      for (j = 1; j <= mip->n; j++)
+      {  col = mip->col[j];
+         if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
+            0.0 && col->ub == 1.0) count++;
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_intopt - solve MIP problem with the branch-and-bound method
+*
+*  SYNOPSIS
+*
+*  int glp_intopt(glp_prob *P, const glp_iocp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_intopt is a driver to the MIP solver based on the
+*  branch-and-bound method.
+*
+*  On entry the problem object should contain optimal solution to LP
+*  relaxation (which can be obtained with the routine glp_simplex).
+*
+*  The MIP solver has a set of control parameters. Values of the control
+*  parameters can be passed in a structure glp_iocp, which the parameter
+*  parm points to.
+*
+*  The parameter parm can be specified as NULL, in which case the MIP
+*  solver uses default settings.
+*
+*  RETURNS
+*
+*  0  The MIP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EBOUND
+*     Unable to start the search, because some double-bounded variables
+*     have incorrect bounds or some integer variables have non-integer
+*     (fractional) bounds.
+*
+*  GLP_EROOT
+*     Unable to start the search, because optimal basis for initial LP
+*     relaxation is not provided.
+*
+*  GLP_EFAIL
+*     The search was prematurely terminated due to the solver failure.
+*
+*  GLP_EMIPGAP
+*     The search was prematurely terminated, because the relative mip
+*     gap tolerance has been reached.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded.
+*
+*  GLP_ENOPFS
+*     The MIP problem instance has no primal feasible solution (only if
+*     the MIP presolver is used).
+*
+*  GLP_ENODFS
+*     LP relaxation of the MIP problem instance has no dual feasible
+*     solution (only if the MIP presolver is used).
+*
+*  GLP_ESTOP
+*     The search was prematurely terminated by application. */
+
+static int solve_mip(glp_prob *P, const glp_iocp *parm)
+{     /* solve MIP directly without using the preprocessor */
+      glp_tree *T;
+      int ret;
+      /* optimal basis to LP relaxation must be provided */
+      if (glp_get_status(P) != GLP_OPT)
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_intopt: optimal basis to initial LP relaxation"
+               " not provided\n");
+         ret = GLP_EROOT;
+         goto done;
+      }
+      /* it seems all is ok */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Integer optimization begins...\n");
+      /* create the branch-and-bound tree */
+      T = ios_create_tree(P, parm);
+      /* solve the problem instance */
+      ret = ios_driver(T);
+      /* delete the branch-and-bound tree */
+      ios_delete_tree(T);
+      /* analyze exit code reported by the mip driver */
+      if (ret == 0)
+      {  if (P->mip_stat == GLP_FEAS)
+         {  if (parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
+            P->mip_stat = GLP_OPT;
+         }
+         else
+         {  if (parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
+            P->mip_stat = GLP_NOFEAS;
+         }
+      }
+      else if (ret == GLP_EMIPGAP)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
+               "TED\n");
+      }
+      else if (ret == GLP_ETMLIM)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+      }
+      else if (ret == GLP_EFAIL)
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_intopt: cannot solve current LP relaxation\n");
+      }
+      else if (ret == GLP_ESTOP)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("SEARCH TERMINATED BY APPLICATION\n");
+      }
+      else
+         xassert(ret != ret);
+done: return ret;
+}
+
+static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
+{     /* solve MIP using the preprocessor */
+      ENV *env = get_env_ptr();
+      int term_out = env->term_out;
+      NPP *npp;
+      glp_prob *mip = NULL;
+      glp_bfcp bfcp;
+      glp_smcp smcp;
+      int ret;
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Preprocessing...\n");
+      /* create preprocessor workspace */
+      npp = npp_create_wksp();
+      /* load original problem into the preprocessor workspace */
+      npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
+      /* process MIP prior to applying the branch-and-bound method */
+      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+         env->term_out = GLP_OFF;
+      else
+         env->term_out = GLP_ON;
+      ret = npp_integer(npp, parm);
+      env->term_out = term_out;
+      if (ret == 0)
+         ;
+      else if (ret == GLP_ENOPFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
+      }
+      else if (ret == GLP_ENODFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
+      }
+      else
+         xassert(ret != ret);
+      if (ret != 0) goto done;
+      /* build transformed MIP */
+      mip = glp_create_prob();
+      npp_build_prob(npp, mip);
+      /* if the transformed MIP is empty, it has empty solution, which
+         is optimal */
+      if (mip->m == 0 && mip->n == 0)
+      {  mip->mip_stat = GLP_OPT;
+         mip->mip_obj = mip->c0;
+         if (parm->msg_lev >= GLP_MSG_ALL)
+         {  xprintf("Objective value = %17.9e\n", mip->mip_obj);
+            xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
+               "\n");
+         }
+         goto post;
+      }
+      /* display some statistics */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  int ni = glp_get_num_int(mip);
+         int nb = glp_get_num_bin(mip);
+         char s[50];
+         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
+            "s", mip->nnz, mip->nnz == 1 ? "" : "s");
+         if (nb == 0)
+            strcpy(s, "none of");
+         else if (ni == 1 && nb == 1)
+            strcpy(s, "");
+         else if (nb == 1)
+            strcpy(s, "one of");
+         else if (nb == ni)
+            strcpy(s, "all of");
+         else
+            sprintf(s, "%d of", nb);
+         xprintf("%d integer variable%s, %s which %s binary\n",
+            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
+      }
+      /* inherit basis factorization control parameters */
+      glp_get_bfcp(P, &bfcp);
+      glp_set_bfcp(mip, &bfcp);
+      /* scale the transformed problem */
+      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+         env->term_out = GLP_OFF;
+      else
+         env->term_out = GLP_ON;
+      glp_scale_prob(mip,
+         GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
+      env->term_out = term_out;
+      /* build advanced initial basis */
+      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+         env->term_out = GLP_OFF;
+      else
+         env->term_out = GLP_ON;
+      glp_adv_basis(mip, 0);
+      env->term_out = term_out;
+      /* solve initial LP relaxation */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Solving LP relaxation...\n");
+      glp_init_smcp(&smcp);
+      smcp.msg_lev = parm->msg_lev;
+      mip->it_cnt = P->it_cnt;
+      ret = glp_simplex(mip, &smcp);
+      P->it_cnt = mip->it_cnt;
+      if (ret != 0)
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_intopt: cannot solve LP relaxation\n");
+         ret = GLP_EFAIL;
+         goto done;
+      }
+      /* check status of the basic solution */
+      ret = glp_get_status(mip);
+      if (ret == GLP_OPT)
+         ret = 0;
+      else if (ret == GLP_NOFEAS)
+         ret = GLP_ENOPFS;
+      else if (ret == GLP_UNBND)
+         ret = GLP_ENODFS;
+      else
+         xassert(ret != ret);
+      if (ret != 0) goto done;
+      /* solve the transformed MIP */
+      mip->it_cnt = P->it_cnt;
+      ret = solve_mip(mip, parm);
+      P->it_cnt = mip->it_cnt;
+      /* only integer feasible solution can be postprocessed */
+      if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
+      {  P->mip_stat = mip->mip_stat;
+         goto done;
+      }
+      /* postprocess solution from the transformed MIP */
+post: npp_postprocess(npp, mip);
+      /* the transformed MIP is no longer needed */
+      glp_delete_prob(mip), mip = NULL;
+      /* store solution to the original problem */
+      npp_unload_sol(npp, P);
+done: /* delete the transformed MIP, if it exists */
+      if (mip != NULL) glp_delete_prob(mip);
+      /* delete preprocessor workspace */
+      npp_delete_wksp(npp);
+      return ret;
+}
+
+#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
+int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
+{     xassert(P == P);
+      xassert(parm == parm);
+      xprintf("glp_intopt: no alien solver is available\n");
+      return GLP_EFAIL;
+}
+#endif
+
+int glp_intopt(glp_prob *P, const glp_iocp *parm)
+{     /* solve MIP problem with the branch-and-bound method */
+      glp_iocp _parm;
+      int i, j, ret;
+      /* check problem object */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_intopt: P = %p; invalid problem object\n", P);
+      if (P->tree != NULL)
+         xerror("glp_intopt: operation not allowed\n");
+      /* check control parameters */
+      if (parm == NULL)
+         parm = &_parm, glp_init_iocp((glp_iocp *)parm);
+      if (!(parm->msg_lev == GLP_MSG_OFF ||
+            parm->msg_lev == GLP_MSG_ERR ||
+            parm->msg_lev == GLP_MSG_ON  ||
+            parm->msg_lev == GLP_MSG_ALL ||
+            parm->msg_lev == GLP_MSG_DBG))
+         xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
+            parm->msg_lev);
+      if (!(parm->br_tech == GLP_BR_FFV ||
+            parm->br_tech == GLP_BR_LFV ||
+            parm->br_tech == GLP_BR_MFV ||
+            parm->br_tech == GLP_BR_DTH ||
+            parm->br_tech == GLP_BR_PCH))
+         xerror("glp_intopt: br_tech = %d; invalid parameter\n",
+            parm->br_tech);
+      if (!(parm->bt_tech == GLP_BT_DFS ||
+            parm->bt_tech == GLP_BT_BFS ||
+            parm->bt_tech == GLP_BT_BLB ||
+            parm->bt_tech == GLP_BT_BPH))
+         xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
+            parm->bt_tech);
+      if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
+         xerror("glp_intopt: tol_int = %g; invalid parameter\n",
+            parm->tol_int);
+      if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
+         xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
+            parm->tol_obj);
+      if (parm->tm_lim < 0)
+         xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
+            parm->tm_lim);
+      if (parm->out_frq < 0)
+         xerror("glp_intopt: out_frq = %d; invalid parameter\n",
+            parm->out_frq);
+      if (parm->out_dly < 0)
+         xerror("glp_intopt: out_dly = %d; invalid parameter\n",
+            parm->out_dly);
+      if (!(0 <= parm->cb_size && parm->cb_size <= 256))
+         xerror("glp_intopt: cb_size = %d; invalid parameter\n",
+            parm->cb_size);
+      if (!(parm->pp_tech == GLP_PP_NONE ||
+            parm->pp_tech == GLP_PP_ROOT ||
+            parm->pp_tech == GLP_PP_ALL))
+         xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
+            parm->pp_tech);
+      if (parm->mip_gap < 0.0)
+         xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
+            parm->mip_gap);
+      if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
+         xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
+            parm->mir_cuts);
+      if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
+         xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
+            parm->gmi_cuts);
+      if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
+         xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
+            parm->cov_cuts);
+      if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
+         xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
+            parm->clq_cuts);
+      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
+         xerror("glp_intopt: presolve = %d; invalid parameter\n",
+            parm->presolve);
+      if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
+         xerror("glp_intopt: binarize = %d; invalid parameter\n",
+            parm->binarize);
+      if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
+         xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
+            parm->fp_heur);
+#if 1 /* 28/V-2010 */
+      if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
+         xerror("glp_intopt: alien = %d; invalid parameter\n",
+            parm->alien);
+#endif
+      /* integer solution is currently undefined */
+      P->mip_stat = GLP_UNDEF;
+      P->mip_obj = 0.0;
+      /* check bounds of double-bounded variables */
+      for (i = 1; i <= P->m; i++)
+      {  GLPROW *row = P->row[i];
+         if (row->type == GLP_DB && row->lb >= row->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
+                  " bounds\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+         if (col->type == GLP_DB && col->lb >= col->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
+                  "ect bounds\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* bounds of all integer variables must be integral */
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+         if (col->kind != GLP_IV) continue;
+         if (col->type == GLP_LO || col->type == GLP_DB)
+         {  if (col->lb != floor(col->lb))
+            {  if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("glp_intopt: integer column %d has non-intege"
+                     "r lower bound %g\n", j, col->lb);
+               ret = GLP_EBOUND;
+               goto done;
+            }
+         }
+         if (col->type == GLP_UP || col->type == GLP_DB)
+         {  if (col->ub != floor(col->ub))
+            {  if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("glp_intopt: integer column %d has non-intege"
+                     "r upper bound %g\n", j, col->ub);
+               ret = GLP_EBOUND;
+               goto done;
+            }
+         }
+         if (col->type == GLP_FX)
+         {  if (col->lb != floor(col->lb))
+            {  if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("glp_intopt: integer column %d has non-intege"
+                     "r fixed value %g\n", j, col->lb);
+               ret = GLP_EBOUND;
+               goto done;
+            }
+         }
+      }
+      /* solve MIP problem */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         char s[50];
+         xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
+         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+            P->nnz, P->nnz == 1 ? "" : "s");
+         if (nb == 0)
+            strcpy(s, "none of");
+         else if (ni == 1 && nb == 1)
+            strcpy(s, "");
+         else if (nb == 1)
+            strcpy(s, "one of");
+         else if (nb == ni)
+            strcpy(s, "all of");
+         else
+            sprintf(s, "%d of", nb);
+         xprintf("%d integer variable%s, %s which %s binary\n",
+            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
+      }
+#if 1 /* 28/V-2010 */
+      if (parm->alien)
+      {  /* use alien integer optimizer */
+         ret = _glp_intopt1(P, parm);
+         goto done;
+      }
+#endif
+      if (!parm->presolve)
+         ret = solve_mip(P, parm);
+      else
+         ret = preprocess_and_solve_mip(P, parm);
+done: /* return to the application program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_iocp - initialize integer optimizer control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_iocp(glp_iocp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_iocp initializes control parameters, which are
+*  used by the integer optimizer, with default values.
+*
+*  Default values of the control parameters are stored in a glp_iocp
+*  structure, which the parameter parm points to. */
+
+void glp_init_iocp(glp_iocp *parm)
+{     parm->msg_lev = GLP_MSG_ALL;
+      parm->br_tech = GLP_BR_DTH;
+      parm->bt_tech = GLP_BT_BLB;
+      parm->tol_int = 1e-5;
+      parm->tol_obj = 1e-7;
+      parm->tm_lim = INT_MAX;
+      parm->out_frq = 5000;
+      parm->out_dly = 10000;
+      parm->cb_func = NULL;
+      parm->cb_info = NULL;
+      parm->cb_size = 0;
+      parm->pp_tech = GLP_PP_ALL;
+      parm->mip_gap = 0.0;
+      parm->mir_cuts = GLP_OFF;
+      parm->gmi_cuts = GLP_OFF;
+      parm->cov_cuts = GLP_OFF;
+      parm->clq_cuts = GLP_OFF;
+      parm->presolve = GLP_OFF;
+      parm->binarize = GLP_OFF;
+      parm->fp_heur = GLP_OFF;
+#if 1 /* 28/V-2010 */
+      parm->alien = GLP_OFF;
+#endif
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_status - retrieve status of MIP solution
+*
+*  SYNOPSIS
+*
+*  int glp_mip_status(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine lpx_mip_status reports the status of MIP solution found
+*  by the branch-and-bound solver as follows:
+*
+*  GLP_UNDEF  - MIP solution is undefined;
+*  GLP_OPT    - MIP solution is integer optimal;
+*  GLP_FEAS   - MIP solution is integer feasible but its optimality
+*               (or non-optimality) has not been proven, perhaps due to
+*               premature termination of the search;
+*  GLP_NOFEAS - problem has no integer feasible solution (proven by the
+*               solver). */
+
+int glp_mip_status(glp_prob *mip)
+{     int mip_stat = mip->mip_stat;
+      return mip_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_obj_val - retrieve objective value (MIP solution)
+*
+*  SYNOPSIS
+*
+*  double glp_mip_obj_val(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine glp_mip_obj_val returns value of the objective function
+*  for MIP solution. */
+
+double glp_mip_obj_val(glp_prob *mip)
+{     /*struct LPXCPS *cps = mip->cps;*/
+      double z;
+      z = mip->mip_obj;
+      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+      return z;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_row_val - retrieve row value (MIP solution)
+*
+*  SYNOPSIS
+*
+*  double glp_mip_row_val(glp_prob *mip, int i);
+*
+*  RETURNS
+*
+*  The routine glp_mip_row_val returns value of the auxiliary variable
+*  associated with i-th row. */
+
+double glp_mip_row_val(glp_prob *mip, int i)
+{     /*struct LPXCPS *cps = mip->cps;*/
+      double mipx;
+      if (!(1 <= i && i <= mip->m))
+         xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
+            ;
+      mipx = mip->row[i]->mipx;
+      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
+      return mipx;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_col_val - retrieve column value (MIP solution)
+*
+*  SYNOPSIS
+*
+*  double glp_mip_col_val(glp_prob *mip, int j);
+*
+*  RETURNS
+*
+*  The routine glp_mip_col_val returns value of the structural variable
+*  associated with j-th column. */
+
+double glp_mip_col_val(glp_prob *mip, int j)
+{     /*struct LPXCPS *cps = mip->cps;*/
+      double mipx;
+      if (!(1 <= j && j <= mip->n))
+         xerror("glp_mip_col_val: j = %d; column number out of range\n",
+            j);
+      mipx = mip->col[j]->mipx;
+      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
+      return mipx;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi10.c b/optional/glpk/glpapi10.c
new file mode 100644
index 0000000..22acf03
--- /dev/null
+++ b/optional/glpk/glpapi10.c
@@ -0,0 +1,282 @@
+/* glpapi10.c (solution checking routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+void _glp_check_kkt(glp_prob *P, int sol, int cond, double *_ae_max,
+      int *_ae_ind, double *_re_max, int *_re_ind)
+{     /* check feasibility and optimality conditions */
+      int m = P->m;
+      int n = P->n;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, ae_ind, re_ind;
+      double e, sp, sn, t, ae_max, re_max;
+      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+         xerror("glp_check_kkt: sol = %d; invalid solution indicator\n",
+            sol);
+      if (!(cond == GLP_KKT_PE || cond == GLP_KKT_PB ||
+            cond == GLP_KKT_DE || cond == GLP_KKT_DB ||
+            cond == GLP_KKT_CS))
+         xerror("glp_check_kkt: cond = %d; invalid condition indicator "
+            "\n", cond);
+      ae_max = re_max = 0.0;
+      ae_ind = re_ind = 0;
+      if (cond == GLP_KKT_PE)
+      {  /* xR - A * xS = 0 */
+         for (i = 1; i <= m; i++)
+         {  row = P->row[i];
+            sp = sn = 0.0;
+            /* t := xR[i] */
+            if (sol == GLP_SOL)
+               t = row->prim;
+            else if (sol == GLP_IPT)
+               t = row->pval;
+            else if (sol == GLP_MIP)
+               t = row->mipx;
+            else
+               xassert(sol != sol);
+            if (t >= 0.0) sp += t; else sn -= t;
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            {  col = aij->col;
+               /* t := - a[i,j] * xS[j] */
+               if (sol == GLP_SOL)
+                  t = - aij->val * col->prim;
+               else if (sol == GLP_IPT)
+                  t = - aij->val * col->pval;
+               else if (sol == GLP_MIP)
+                  t = - aij->val * col->mipx;
+               else
+                  xassert(sol != sol);
+               if (t >= 0.0) sp += t; else sn -= t;
+            }
+            /* absolute error */
+            e = fabs(sp - sn);
+            if (ae_max < e)
+               ae_max = e, ae_ind = i;
+            /* relative error */
+            e /= (1.0 + sp + sn);
+            if (re_max < e)
+               re_max = e, re_ind = i;
+         }
+      }
+      else if (cond == GLP_KKT_PB)
+      {  /* lR <= xR <= uR */
+         for (i = 1; i <= m; i++)
+         {  row = P->row[i];
+            /* t := xR[i] */
+            if (sol == GLP_SOL)
+               t = row->prim;
+            else if (sol == GLP_IPT)
+               t = row->pval;
+            else if (sol == GLP_MIP)
+               t = row->mipx;
+            else
+               xassert(sol != sol);
+            /* check lower bound */
+            if (row->type == GLP_LO || row->type == GLP_DB ||
+                row->type == GLP_FX)
+            {  if (t < row->lb)
+               {  /* absolute error */
+                  e = row->lb - t;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = i;
+                  /* relative error */
+                  e /= (1.0 + fabs(row->lb));
+                  if (re_max < e)
+                     re_max = e, re_ind = i;
+               }
+            }
+            /* check upper bound */
+            if (row->type == GLP_UP || row->type == GLP_DB ||
+                row->type == GLP_FX)
+            {  if (t > row->ub)
+               {  /* absolute error */
+                  e = t - row->ub;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = i;
+                  /* relative error */
+                  e /= (1.0 + fabs(row->ub));
+                  if (re_max < e)
+                     re_max = e, re_ind = i;
+               }
+            }
+         }
+         /* lS <= xS <= uS */
+         for (j = 1; j <= n; j++)
+         {  col = P->col[j];
+            /* t := xS[j] */
+            if (sol == GLP_SOL)
+               t = col->prim;
+            else if (sol == GLP_IPT)
+               t = col->pval;
+            else if (sol == GLP_MIP)
+               t = col->mipx;
+            else
+               xassert(sol != sol);
+            /* check lower bound */
+            if (col->type == GLP_LO || col->type == GLP_DB ||
+                col->type == GLP_FX)
+            {  if (t < col->lb)
+               {  /* absolute error */
+                  e = col->lb - t;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = m+j;
+                  /* relative error */
+                  e /= (1.0 + fabs(col->lb));
+                  if (re_max < e)
+                     re_max = e, re_ind = m+j;
+               }
+            }
+            /* check upper bound */
+            if (col->type == GLP_UP || col->type == GLP_DB ||
+                col->type == GLP_FX)
+            {  if (t > col->ub)
+               {  /* absolute error */
+                  e = t - col->ub;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = m+j;
+                  /* relative error */
+                  e /= (1.0 + fabs(col->ub));
+                  if (re_max < e)
+                     re_max = e, re_ind = m+j;
+               }
+            }
+         }
+      }
+      else if (cond == GLP_KKT_DE)
+      {  /* A' * (lambdaR - cR) + (lambdaS - cS) = 0 */
+         for (j = 1; j <= n; j++)
+         {  col = P->col[j];
+            sp = sn = 0.0;
+            /* t := lambdaS[j] - cS[j] */
+            if (sol == GLP_SOL)
+               t = col->dual - col->coef;
+            else if (sol == GLP_IPT)
+               t = col->dval - col->coef;
+            else
+               xassert(sol != sol);
+            if (t >= 0.0) sp += t; else sn -= t;
+            for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+            {  row = aij->row;
+               /* t := a[i,j] * (lambdaR[i] - cR[i]) */
+               if (sol == GLP_SOL)
+                  t = aij->val * row->dual;
+               else if (sol == GLP_IPT)
+                  t = aij->val * row->dval;
+               else
+                  xassert(sol != sol);
+               if (t >= 0.0) sp += t; else sn -= t;
+            }
+            /* absolute error */
+            e = fabs(sp - sn);
+            if (ae_max < e)
+               ae_max = e, ae_ind = m+j;
+            /* relative error */
+            e /= (1.0 + sp + sn);
+            if (re_max < e)
+               re_max = e, re_ind = m+j;
+         }
+      }
+      else if (cond == GLP_KKT_DB)
+      {  /* check lambdaR */
+         for (i = 1; i <= m; i++)
+         {  row = P->row[i];
+            /* t := lambdaR[i] */
+            if (sol == GLP_SOL)
+               t = row->dual;
+            else if (sol == GLP_IPT)
+               t = row->dval;
+            else
+               xassert(sol != sol);
+            /* correct sign */
+            if (P->dir == GLP_MIN)
+               t = + t;
+            else if (P->dir == GLP_MAX)
+               t = - t;
+            else
+               xassert(P != P);
+            /* check for positivity */
+            if (row->type == GLP_FR || row->type == GLP_LO)
+            {  if (t < 0.0)
+               {  e = - t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = i;
+               }
+            }
+            /* check for negativity */
+            if (row->type == GLP_FR || row->type == GLP_UP)
+            {  if (t > 0.0)
+               {  e = + t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = i;
+               }
+            }
+         }
+         /* check lambdaS */
+         for (j = 1; j <= n; j++)
+         {  col = P->col[j];
+            /* t := lambdaS[j] */
+            if (sol == GLP_SOL)
+               t = col->dual;
+            else if (sol == GLP_IPT)
+               t = col->dval;
+            else
+               xassert(sol != sol);
+            /* correct sign */
+            if (P->dir == GLP_MIN)
+               t = + t;
+            else if (P->dir == GLP_MAX)
+               t = - t;
+            else
+               xassert(P != P);
+            /* check for positivity */
+            if (col->type == GLP_FR || col->type == GLP_LO)
+            {  if (t < 0.0)
+               {  e = - t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = m+j;
+               }
+            }
+            /* check for negativity */
+            if (col->type == GLP_FR || col->type == GLP_UP)
+            {  if (t > 0.0)
+               {  e = + t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = m+j;
+               }
+            }
+         }
+      }
+      else
+         xassert(cond != cond);
+      if (_ae_max != NULL) *_ae_max = ae_max;
+      if (_ae_ind != NULL) *_ae_ind = ae_ind;
+      if (_re_max != NULL) *_re_max = re_max;
+      if (_re_ind != NULL) *_re_ind = re_ind;
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi11.c b/optional/glpk/glpapi11.c
new file mode 100644
index 0000000..ad6d0d1
--- /dev/null
+++ b/optional/glpk/glpapi11.c
@@ -0,0 +1,1221 @@
+/* glpapi11.c (utility routines) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#endif
+
+#include "glpapi.h"
+
+int glp_print_sol(glp_prob *P, const char *fname)
+{     /* write basic solution in printable format */
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j, t, ae_ind, re_ind, ret;
+      double ae_max, re_max;
+      xprintf("Writing basic solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%-12s%s\n", "Problem:",
+         P->name == NULL ? "" : P->name);
+      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
+      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+      t = glp_get_status(P);
+      xfprintf(fp, "%-12s%s\n", "Status:",
+         t == GLP_OPT    ? "OPTIMAL" :
+         t == GLP_FEAS   ? "FEASIBLE" :
+         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
+         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
+         t == GLP_UNBND  ? "UNBOUNDED" :
+         t == GLP_UNDEF  ? "UNDEFINED" : "???");
+      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+         P->obj == NULL ? "" : P->obj,
+         P->obj == NULL ? "" : " = ", P->obj_val,
+         P->dir == GLP_MIN ? "MINimum" :
+         P->dir == GLP_MAX ? "MAXimum" : "???");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No.   Row name   St   Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------ -- ------------- ------------- "
+         "------------- -------------\n");
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         xfprintf(fp, "%6d ", i);
+         if (row->name == NULL || strlen(row->name) <= 12)
+            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+         else
+            xfprintf(fp, "%s\n%20s", row->name, "");
+         xfprintf(fp, "%s ",
+            row->stat == GLP_BS ? "B " :
+            row->stat == GLP_NL ? "NL" :
+            row->stat == GLP_NU ? "NU" :
+            row->stat == GLP_NF ? "NF" :
+            row->stat == GLP_NS ? "NS" : "??");
+         xfprintf(fp, "%13.6g ",
+            fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", row->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (row->type == GLP_UP || row->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", row->ub);
+         else
+            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+         if (row->stat != GLP_BS)
+         {  if (fabs(row->dual) <= 1e-9)
+               xfprintf(fp, "%13s", "< eps");
+            else
+               xfprintf(fp, "%13.6g ", row->dual);
+         }
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No. Column name  St   Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------ -- ------------- ------------- "
+         "------------- -------------\n");
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         xfprintf(fp, "%6d ", j);
+         if (col->name == NULL || strlen(col->name) <= 12)
+            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+         else
+            xfprintf(fp, "%s\n%20s", col->name, "");
+         xfprintf(fp, "%s ",
+            col->stat == GLP_BS ? "B " :
+            col->stat == GLP_NL ? "NL" :
+            col->stat == GLP_NU ? "NU" :
+            col->stat == GLP_NF ? "NF" :
+            col->stat == GLP_NS ? "NS" : "??");
+         xfprintf(fp, "%13.6g ",
+            fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
+         if (col->type == GLP_LO || col->type == GLP_DB ||
+             col->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", col->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (col->type == GLP_UP || col->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", col->ub);
+         else
+            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+         if (col->stat != GLP_BS)
+         {  if (fabs(col->dual) <= 1e-9)
+               xfprintf(fp, "%13s", "< eps");
+            else
+               xfprintf(fp, "%13.6g ", col->dual);
+         }
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+         ae_max, ae_ind);
+      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
+         re_max, re_ind);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
+            "E");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
+         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
+         re_max, re_ind == 0 ? 0 : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
+            ;
+      xfprintf(fp, "\n");
+      xfprintf(fp, "End of output\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_sol - read basic solution from text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_sol(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_sol reads basic solution from a text file whose
+*  name is specified by the parameter fname into the problem object.
+*
+*  For the file format see description of the routine glp_write_sol.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero. */
+
+int glp_read_sol(glp_prob *lp, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int i, j, k, ret = 0;
+      xprintf("Reading basic solution from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* number of rows, number of columns */
+      k = glp_sdf_read_int(data);
+      if (k != lp->m)
+         glp_sdf_error(data, "wrong number of rows\n");
+      k = glp_sdf_read_int(data);
+      if (k != lp->n)
+         glp_sdf_error(data, "wrong number of columns\n");
+      /* primal status, dual status, objective value */
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
+            k == GLP_NOFEAS))
+         glp_sdf_error(data, "invalid primal status\n");
+      lp->pbs_stat = k;
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
+            k == GLP_NOFEAS))
+         glp_sdf_error(data, "invalid dual status\n");
+      lp->dbs_stat = k;
+      lp->obj_val = glp_sdf_read_num(data);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* status, primal value, dual value */
+         k = glp_sdf_read_int(data);
+         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
+               k == GLP_NF || k == GLP_NS))
+            glp_sdf_error(data, "invalid row status\n");
+         glp_set_row_stat(lp, i, k);
+         row->prim = glp_sdf_read_num(data);
+         row->dual = glp_sdf_read_num(data);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* status, primal value, dual value */
+         k = glp_sdf_read_int(data);
+         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
+               k == GLP_NF || k == GLP_NS))
+            glp_sdf_error(data, "invalid column status\n");
+         glp_set_col_stat(lp, j, k);
+         col->prim = glp_sdf_read_num(data);
+         col->dual = glp_sdf_read_num(data);
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_sol - write basic solution to text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_sol(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_sol writes the current basic solution to a
+*  text file whose name is specified by the parameter fname. This file
+*  can be read back with the routine glp_read_sol.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine glp_write_sol is a plain text file,
+*  which contains the following information:
+*
+*     m n
+*     p_stat d_stat obj_val
+*     r_stat[1] r_prim[1] r_dual[1]
+*     . . .
+*     r_stat[m] r_prim[m] r_dual[m]
+*     c_stat[1] c_prim[1] c_dual[1]
+*     . . .
+*     c_stat[n] c_prim[n] c_dual[n]
+*
+*  where:
+*  m is the number of rows (auxiliary variables);
+*  n is the number of columns (structural variables);
+*  p_stat is the primal status of the basic solution (GLP_UNDEF = 1,
+*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
+*  d_stat is the dual status of the basic solution (GLP_UNDEF = 1,
+*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
+*  obj_val is the objective value;
+*  r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1,
+*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
+*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
+*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
+*  c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1,
+*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
+*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
+*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
+
+int glp_write_sol(glp_prob *lp, const char *fname)
+{     XFILE *fp;
+      int i, j, ret = 0;
+      xprintf("Writing basic solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns */
+      xfprintf(fp, "%d %d\n", lp->m, lp->n);
+      /* primal status, dual status, objective value */
+      xfprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG,
+         lp->obj_val);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* status, primal value, dual value */
+         xfprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim,
+            DBL_DIG, row->dual);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* status, primal value, dual value */
+         xfprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim,
+            DBL_DIG, col->dual);
+      }
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+static char *format(char buf[13+1], double x)
+{     /* format floating-point number in MPS/360-like style */
+      if (x == -DBL_MAX)
+         strcpy(buf, "         -Inf");
+      else if (x == +DBL_MAX)
+         strcpy(buf, "         +Inf");
+      else if (fabs(x) <= 999999.99998)
+      {  sprintf(buf, "%13.5f", x);
+#if 1
+         if (strcmp(buf, "      0.00000") == 0 ||
+             strcmp(buf, "     -0.00000") == 0)
+            strcpy(buf, "       .     ");
+         else if (memcmp(buf, "      0.", 8) == 0)
+            memcpy(buf, "       .", 8);
+         else if (memcmp(buf, "     -0.", 8) == 0)
+            memcpy(buf, "      -.", 8);
+#endif
+      }
+      else
+         sprintf(buf, "%13.6g", x);
+      return buf;
+}
+
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+      int flags, const char *fname)
+{     /* print sensitivity analysis report */
+      XFILE *fp = NULL;
+      GLPROW *row;
+      GLPCOL *col;
+      int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
+         ret;
+      double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
+         coef2, obj1, obj2;
+      const char *name, *limit;
+      char buf[13+1];
+      /* sanity checks */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_print_ranges: P = %p; invalid problem object\n",
+            P);
+      m = P->m, n = P->n;
+      if (len < 0)
+         xerror("glp_print_ranges: len = %d; invalid list length\n",
+            len);
+      if (len > 0)
+      {  if (list == NULL)
+            xerror("glp_print_ranges: list = %p: invalid parameter\n",
+               list);
+         for (t = 1; t <= len; t++)
+         {  k = list[t];
+            if (!(1 <= k && k <= m+n))
+               xerror("glp_print_ranges: list[%d] = %d; row/column numb"
+                  "er out of range\n", t, k);
+         }
+      }
+      if (flags != 0)
+         xerror("glp_print_ranges: flags = %d; invalid parameter\n",
+            flags);
+      if (fname == NULL)
+         xerror("glp_print_ranges: fname = %p; invalid parameter\n",
+            fname);
+      if (glp_get_status(P) != GLP_OPT)
+      {  xprintf("glp_print_ranges: optimal basic solution required\n");
+         ret = 1;
+         goto done;
+      }
+      if (!glp_bf_exists(P))
+      {  xprintf("glp_print_ranges: basis factorization required\n");
+         ret = 2;
+         goto done;
+      }
+      /* start reporting */
+      xprintf("Write sensitivity analysis report to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 3;
+         goto done;
+      }
+      page = count = 0;
+      for (pass = 1; pass <= 2; pass++)
+      for (t = 1; t <= (len == 0 ? m+n : len); t++)
+      {  if (t == 1) count = 0;
+         k = (len == 0 ? t : list[t]);
+         if (pass == 1 && k > m || pass == 2 && k <= m)
+            continue;
+         if (count == 0)
+         {  xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
+               "ge%4d\n", glp_version(), "", ++page);
+            xfprintf(fp, "\n");
+            xfprintf(fp, "%-12s%s\n", "Problem:",
+               P->name == NULL ? "" : P->name);
+            xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+               P->obj == NULL ? "" : P->obj,
+               P->obj == NULL ? "" : " = ", P->obj_val,
+               P->dir == GLP_MIN ? "MINimum" :
+               P->dir == GLP_MAX ? "MAXimum" : "???");
+            xfprintf(fp, "\n");
+            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s "
+               "%s\n", "No.", pass == 1 ? "Row name" : "Column name",
+               "St", "Activity", pass == 1 ? "Slack" : "Obj coef",
+               "Lower bound", "Activity", "Obj coef", "Obj value at",
+               "Limiting");
+            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s "
+               "%s\n", "", "", "", "", "Marginal", "Upper bound",
+               "range", "range", "break point", "variable");
+            xfprintf(fp, "------ ------------ -- ------------- --------"
+               "----- -------------  ------------- ------------- ------"
+               "------- ------------\n");
+         }
+         if (pass == 1)
+         {  numb = k;
+            xassert(1 <= numb && numb <= m);
+            row = P->row[numb];
+            name = row->name;
+            type = row->type;
+            lb = glp_get_row_lb(P, numb);
+            ub = glp_get_row_ub(P, numb);
+            coef = 0.0;
+            stat = row->stat;
+            prim = row->prim;
+            if (type == GLP_FR)
+               slack = - prim;
+            else if (type == GLP_LO)
+               slack = lb - prim;
+            else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+               slack = ub - prim;
+            dual = row->dual;
+         }
+         else
+         {  numb = k - m;
+            xassert(1 <= numb && numb <= n);
+            col = P->col[numb];
+            name = col->name;
+            lb = glp_get_col_lb(P, numb);
+            ub = glp_get_col_ub(P, numb);
+            coef = col->coef;
+            stat = col->stat;
+            prim = col->prim;
+            slack = 0.0;
+            dual = col->dual;
+         }
+         if (stat != GLP_BS)
+         {  glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
+            if (stat == GLP_NF)
+               coef1 = coef2 = coef;
+            else if (stat == GLP_NS)
+               coef1 = -DBL_MAX, coef2 = +DBL_MAX;
+            else if (stat == GLP_NL && P->dir == GLP_MIN ||
+                     stat == GLP_NU && P->dir == GLP_MAX)
+               coef1 = coef - dual, coef2 = +DBL_MAX;
+            else
+               coef1 = -DBL_MAX, coef2 = coef - dual;
+            if (value1 == -DBL_MAX)
+            {  if (dual < -1e-9)
+                  obj1 = +DBL_MAX;
+               else if (dual > +1e-9)
+                  obj1 = -DBL_MAX;
+               else
+                  obj1 = P->obj_val;
+            }
+            else
+               obj1 = P->obj_val + dual * (value1 - prim);
+            if (value2 == +DBL_MAX)
+            {  if (dual < -1e-9)
+                  obj2 = -DBL_MAX;
+               else if (dual > +1e-9)
+                  obj2 = +DBL_MAX;
+               else
+                  obj2 = P->obj_val;
+            }
+            else
+               obj2 = P->obj_val + dual * (value2 - prim);
+         }
+         else
+         {  glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
+               &var2, &value2);
+            if (coef1 == -DBL_MAX)
+            {  if (prim < -1e-9)
+                  obj1 = +DBL_MAX;
+               else if (prim > +1e-9)
+                  obj1 = -DBL_MAX;
+               else
+                  obj1 = P->obj_val;
+            }
+            else
+               obj1 = P->obj_val + (coef1 - coef) * prim;
+            if (coef2 == +DBL_MAX)
+            {  if (prim < -1e-9)
+                  obj2 = -DBL_MAX;
+               else if (prim > +1e-9)
+                  obj2 = +DBL_MAX;
+               else
+                  obj2 = P->obj_val;
+            }
+            else
+               obj2 = P->obj_val + (coef2 - coef) * prim;
+         }
+         /*** first line ***/
+         /* row/column number */
+         xfprintf(fp, "%6d", numb);
+         /* row/column name */
+         xfprintf(fp, " %-12.12s", name == NULL ? "" : name);
+         if (name != NULL && strlen(name) > 12)
+            xfprintf(fp, "%s\n%6s %12s", name+12, "", "");
+         /* row/column status */
+         xfprintf(fp, " %2s",
+            stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" :
+            stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" :
+            stat == GLP_NS ? "NS" : "??");
+         /* row/column activity */
+         xfprintf(fp, " %s", format(buf, prim));
+         /* row slack, column objective coefficient */
+         xfprintf(fp, " %s", format(buf, k <= m ? slack : coef));
+         /* row/column lower bound */
+         xfprintf(fp, " %s", format(buf, lb));
+         /* row/column activity range */
+         xfprintf(fp, "  %s", format(buf, value1));
+         /* row/column objective coefficient range */
+         xfprintf(fp, " %s", format(buf, coef1));
+         /* objective value at break point */
+         xfprintf(fp, " %s", format(buf, obj1));
+         /* limiting variable name */
+         if (var1 != 0)
+         {  if (var1 <= m)
+               limit = glp_get_row_name(P, var1);
+            else
+               limit = glp_get_col_name(P, var1 - m);
+            if (limit != NULL)
+               xfprintf(fp, " %s", limit);
+         }
+         xfprintf(fp, "\n");
+         /*** second line ***/
+         xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", "");
+         /* row/column reduced cost */
+         xfprintf(fp, " %s", format(buf, dual));
+         /* row/column upper bound */
+         xfprintf(fp, " %s", format(buf, ub));
+         /* row/column activity range */
+         xfprintf(fp, "  %s", format(buf, value2));
+         /* row/column objective coefficient range */
+         xfprintf(fp, " %s", format(buf, coef2));
+         /* objective value at break point */
+         xfprintf(fp, " %s", format(buf, obj2));
+         /* limiting variable name */
+         if (var2 != 0)
+         {  if (var2 <= m)
+               limit = glp_get_row_name(P, var2);
+            else
+               limit = glp_get_col_name(P, var2 - m);
+            if (limit != NULL)
+               xfprintf(fp, " %s", limit);
+         }
+         xfprintf(fp, "\n");
+         xfprintf(fp, "\n");
+         /* print 10 items per page */
+         count = (count + 1) % 10;
+      }
+      xfprintf(fp, "End of report\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 4;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+int glp_print_ipt(glp_prob *P, const char *fname)
+{     /* write interior-point solution in printable format */
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j, t, ae_ind, re_ind, ret;
+      double ae_max, re_max;
+      xprintf("Writing interior-point solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%-12s%s\n", "Problem:",
+         P->name == NULL ? "" : P->name);
+      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
+      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+      t = glp_ipt_status(P);
+      xfprintf(fp, "%-12s%s\n", "Status:",
+         t == GLP_OPT    ? "OPTIMAL" :
+         t == GLP_UNDEF  ? "UNDEFINED" :
+         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
+         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???");
+      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+         P->obj == NULL ? "" : P->obj,
+         P->obj == NULL ? "" : " = ", P->ipt_obj,
+         P->dir == GLP_MIN ? "MINimum" :
+         P->dir == GLP_MAX ? "MAXimum" : "???");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "------------- -------------\n");
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         xfprintf(fp, "%6d ", i);
+         if (row->name == NULL || strlen(row->name) <= 12)
+            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+         else
+            xfprintf(fp, "%s\n%20s", row->name, "");
+         xfprintf(fp, "%3s", "");
+         xfprintf(fp, "%13.6g ",
+            fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", row->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (row->type == GLP_UP || row->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", row->ub);
+         else
+            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+         if (fabs(row->dval) <= 1e-9)
+            xfprintf(fp, "%13s", "< eps");
+         else
+            xfprintf(fp, "%13.6g ", row->dval);
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "------------- -------------\n");
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         xfprintf(fp, "%6d ", j);
+         if (col->name == NULL || strlen(col->name) <= 12)
+            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+         else
+            xfprintf(fp, "%s\n%20s", col->name, "");
+         xfprintf(fp, "%3s", "");
+         xfprintf(fp, "%13.6g ",
+            fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
+         if (col->type == GLP_LO || col->type == GLP_DB ||
+             col->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", col->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (col->type == GLP_UP || col->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", col->ub);
+         else
+            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+         if (fabs(col->dval) <= 1e-9)
+            xfprintf(fp, "%13s", "< eps");
+         else
+            xfprintf(fp, "%13.6g ", col->dval);
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+         ae_max, ae_ind);
+      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
+         re_max, re_ind);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
+            "E");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
+         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
+         re_max, re_ind == 0 ? 0 : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
+            ;
+      xfprintf(fp, "\n");
+      xfprintf(fp, "End of output\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_ipt - read interior-point solution from text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_ipt(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_ipt reads interior-point solution from a text
+*  file whose name is specified by the parameter fname into the problem
+*  object.
+*
+*  For the file format see description of the routine glp_write_ipt.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero. */
+
+int glp_read_ipt(glp_prob *lp, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int i, j, k, ret = 0;
+      xprintf("Reading interior-point solution from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* number of rows, number of columns */
+      k = glp_sdf_read_int(data);
+      if (k != lp->m)
+         glp_sdf_error(data, "wrong number of rows\n");
+      k = glp_sdf_read_int(data);
+      if (k != lp->n)
+         glp_sdf_error(data, "wrong number of columns\n");
+      /* solution status, objective value */
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_OPT))
+         glp_sdf_error(data, "invalid solution status\n");
+      lp->ipt_stat = k;
+      lp->ipt_obj = glp_sdf_read_num(data);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* primal value, dual value */
+         row->pval = glp_sdf_read_num(data);
+         row->dval = glp_sdf_read_num(data);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* primal value, dual value */
+         col->pval = glp_sdf_read_num(data);
+         col->dval = glp_sdf_read_num(data);
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+done: if (ret) lp->ipt_stat = GLP_UNDEF;
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_ipt - write interior-point solution to text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_ipt(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_ipt writes the current interior-point solution
+*  to a text file whose name is specified by the parameter fname. This
+*  file can be read back with the routine glp_read_ipt.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine glp_write_ipt is a plain text file,
+*  which contains the following information:
+*
+*     m n
+*     stat obj_val
+*     r_prim[1] r_dual[1]
+*     . . .
+*     r_prim[m] r_dual[m]
+*     c_prim[1] c_dual[1]
+*     . . .
+*     c_prim[n] c_dual[n]
+*
+*  where:
+*  m is the number of rows (auxiliary variables);
+*  n is the number of columns (structural variables);
+*  stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5);
+*  obj_val is the objective value;
+*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
+*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
+*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
+*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
+
+int glp_write_ipt(glp_prob *lp, const char *fname)
+{     XFILE *fp;
+      int i, j, ret = 0;
+      xprintf("Writing interior-point solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns */
+      xfprintf(fp, "%d %d\n", lp->m, lp->n);
+      /* solution status, objective value */
+      xfprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* primal value, dual value */
+         xfprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG,
+            row->dval);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* primal value, dual value */
+         xfprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG,
+            col->dval);
+      }
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+int glp_print_mip(glp_prob *P, const char *fname)
+{     /* write MIP solution in printable format */
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j, t, ae_ind, re_ind, ret;
+      double ae_max, re_max;
+      xprintf("Writing MIP solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%-12s%s\n", "Problem:",
+         P->name == NULL ? "" : P->name);
+      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+      xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
+         P->n, glp_get_num_int(P), glp_get_num_bin(P));
+      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+      t = glp_mip_status(P);
+      xfprintf(fp, "%-12s%s\n", "Status:",
+         t == GLP_OPT    ? "INTEGER OPTIMAL" :
+         t == GLP_FEAS   ? "INTEGER NON-OPTIMAL" :
+         t == GLP_NOFEAS ? "INTEGER EMPTY" :
+         t == GLP_UNDEF  ? "INTEGER UNDEFINED" : "???");
+      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+         P->obj == NULL ? "" : P->obj,
+         P->obj == NULL ? "" : " = ", P->mip_obj,
+         P->dir == GLP_MIN ? "MINimum" :
+         P->dir == GLP_MAX ? "MAXimum" : "???");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
+         " Upper bound\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "-------------\n");
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         xfprintf(fp, "%6d ", i);
+         if (row->name == NULL || strlen(row->name) <= 12)
+            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+         else
+            xfprintf(fp, "%s\n%20s", row->name, "");
+         xfprintf(fp, "%3s", "");
+         xfprintf(fp, "%13.6g ",
+            fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", row->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (row->type == GLP_UP || row->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", row->ub);
+         else
+            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
+         " Upper bound\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "-------------\n");
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         xfprintf(fp, "%6d ", j);
+         if (col->name == NULL || strlen(col->name) <= 12)
+            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+         else
+            xfprintf(fp, "%s\n%20s", col->name, "");
+         xfprintf(fp, "%s  ",
+            col->kind == GLP_CV ? " " :
+            col->kind == GLP_IV ? "*" : "?");
+         xfprintf(fp, "%13.6g ",
+            fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
+         if (col->type == GLP_LO || col->type == GLP_DB ||
+             col->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", col->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (col->type == GLP_UP || col->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", col->ub);
+         else
+            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "Integer feasibility conditions:\n");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+         ae_max, ae_ind);
+      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
+         re_max, re_ind);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "End of output\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_mip - read MIP solution from text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_mip(glp_prob *mip, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_mip reads MIP solution from a text file whose
+*  name is specified by the parameter fname into the problem object.
+*
+*  For the file format see description of the routine glp_write_mip.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero. */
+
+int glp_read_mip(glp_prob *mip, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int i, j, k, ret = 0;
+      xprintf("Reading MIP solution from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* number of rows, number of columns */
+      k = glp_sdf_read_int(data);
+      if (k != mip->m)
+         glp_sdf_error(data, "wrong number of rows\n");
+      k = glp_sdf_read_int(data);
+      if (k != mip->n)
+         glp_sdf_error(data, "wrong number of columns\n");
+      /* solution status, objective value */
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS ||
+            k == GLP_NOFEAS))
+         glp_sdf_error(data, "invalid solution status\n");
+      mip->mip_stat = k;
+      mip->mip_obj = glp_sdf_read_num(data);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= mip->m; i++)
+      {  GLPROW *row = mip->row[i];
+         row->mipx = glp_sdf_read_num(data);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         col->mipx = glp_sdf_read_num(data);
+         if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
+            glp_sdf_error(data, "non-integer column value");
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+done: if (ret) mip->mip_stat = GLP_UNDEF;
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_mip - write MIP solution to text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_mip(glp_prob *mip, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_mip writes the current MIP solution to a text
+*  file whose name is specified by the parameter fname. This file can
+*  be read back with the routine glp_read_mip.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine glp_write_sol is a plain text file,
+*  which contains the following information:
+*
+*     m n
+*     stat obj_val
+*     r_val[1]
+*     . . .
+*     r_val[m]
+*     c_val[1]
+*     . . .
+*     c_val[n]
+*
+*  where:
+*  m is the number of rows (auxiliary variables);
+*  n is the number of columns (structural variables);
+*  stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2,
+*     GLP_NOFEAS = 4, or GLP_OPT = 5);
+*  obj_val is the objective value;
+*  r_val[i], i = 1,...,m, is the value of i-th row;
+*  c_val[j], j = 1,...,n, is the value of j-th column. */
+
+int glp_write_mip(glp_prob *mip, const char *fname)
+{     XFILE *fp;
+      int i, j, ret = 0;
+      xprintf("Writing MIP solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns */
+      xfprintf(fp, "%d %d\n", mip->m, mip->n);
+      /* solution status, objective value */
+      xfprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= mip->m; i++)
+         xfprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx);
+      /* columns (structural variables) */
+      for (j = 1; j <= mip->n; j++)
+         xfprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx);
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", 2 + mip->m + mip->n);
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi12.c b/optional/glpk/glpapi12.c
new file mode 100644
index 0000000..e95e48a
--- /dev/null
+++ b/optional/glpk/glpapi12.c
@@ -0,0 +1,2224 @@
+/* glpapi12.c (basis factorization and simplex tableau routines) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_bf_exists - check if the basis factorization exists
+*
+*  SYNOPSIS
+*
+*  int glp_bf_exists(glp_prob *lp);
+*
+*  RETURNS
+*
+*  If the basis factorization for the current basis associated with
+*  the specified problem object exists and therefore is available for
+*  computations, the routine glp_bf_exists returns non-zero. Otherwise
+*  the routine returns zero. */
+
+int glp_bf_exists(glp_prob *lp)
+{     int ret;
+      ret = (lp->m == 0 || lp->valid);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_factorize - compute the basis factorization
+*
+*  SYNOPSIS
+*
+*  int glp_factorize(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_factorize computes the basis factorization for the
+*  current basis associated with the specified problem object.
+*
+*  RETURNS
+*
+*  0  The basis factorization has been successfully computed.
+*
+*  GLP_EBADB
+*     The basis matrix is invalid, i.e. the number of basic (auxiliary
+*     and structural) variables differs from the number of rows in the
+*     problem object.
+*
+*  GLP_ESING
+*     The basis matrix is singular within the working precision.
+*
+*  GLP_ECOND
+*     The basis matrix is ill-conditioned. */
+
+static int b_col(void *info, int j, int ind[], double val[])
+{     glp_prob *lp = info;
+      int m = lp->m;
+      GLPAIJ *aij;
+      int k, len;
+      xassert(1 <= j && j <= m);
+      /* determine the ordinal number of basic auxiliary or structural
+         variable x[k] corresponding to basic variable xB[j] */
+      k = lp->head[j];
+      /* build j-th column of the basic matrix, which is k-th column of
+         the scaled augmented matrix (I | -R*A*S) */
+      if (k <= m)
+      {  /* x[k] is auxiliary variable */
+         len = 1;
+         ind[1] = k;
+         val[1] = 1.0;
+      }
+      else
+      {  /* x[k] is structural variable */
+         len = 0;
+         for (aij = lp->col[k-m]->ptr; aij != NULL; aij = aij->c_next)
+         {  len++;
+            ind[len] = aij->row->i;
+            val[len] = - aij->row->rii * aij->val * aij->col->sjj;
+         }
+      }
+      return len;
+}
+
+static void copy_bfcp(glp_prob *lp);
+
+int glp_factorize(glp_prob *lp)
+{     int m = lp->m;
+      int n = lp->n;
+      GLPROW **row = lp->row;
+      GLPCOL **col = lp->col;
+      int *head = lp->head;
+      int j, k, stat, ret;
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+      /* build the basis header */
+      j = 0;
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  stat = row[k]->stat;
+            row[k]->bind = 0;
+         }
+         else
+         {  stat = col[k-m]->stat;
+            col[k-m]->bind = 0;
+         }
+         if (stat == GLP_BS)
+         {  j++;
+            if (j > m)
+            {  /* too many basic variables */
+               ret = GLP_EBADB;
+               goto fini;
+            }
+            head[j] = k;
+            if (k <= m)
+               row[k]->bind = j;
+            else
+               col[k-m]->bind = j;
+         }
+      }
+      if (j < m)
+      {  /* too few basic variables */
+         ret = GLP_EBADB;
+         goto fini;
+      }
+      /* try to factorize the basis matrix */
+      if (m > 0)
+      {  if (lp->bfd == NULL)
+         {  lp->bfd = bfd_create_it();
+            copy_bfcp(lp);
+         }
+         switch (bfd_factorize(lp->bfd, m, lp->head, b_col, lp))
+         {  case 0:
+               /* ok */
+               break;
+            case BFD_ESING:
+               /* singular matrix */
+               ret = GLP_ESING;
+               goto fini;
+            case BFD_ECOND:
+               /* ill-conditioned matrix */
+               ret = GLP_ECOND;
+               goto fini;
+            default:
+               xassert(lp != lp);
+         }
+         lp->valid = 1;
+      }
+      /* factorization successful */
+      ret = 0;
+fini: /* bring the return code to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_bf_updated - check if the basis factorization has been updated
+*
+*  SYNOPSIS
+*
+*  int glp_bf_updated(glp_prob *lp);
+*
+*  RETURNS
+*
+*  If the basis factorization has been just computed from scratch, the
+*  routine glp_bf_updated returns zero. Otherwise, if the factorization
+*  has been updated one or more times, the routine returns non-zero. */
+
+int glp_bf_updated(glp_prob *lp)
+{     int cnt;
+      if (!(lp->m == 0 || lp->valid))
+         xerror("glp_bf_update: basis factorization does not exist\n");
+#if 0 /* 15/XI-2009 */
+      cnt = (lp->m == 0 ? 0 : lp->bfd->upd_cnt);
+#else
+      cnt = (lp->m == 0 ? 0 : bfd_get_count(lp->bfd));
+#endif
+      return cnt;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_bfcp - retrieve basis factorization control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_bfcp retrieves control parameters, which are
+*  used on computing and updating the basis factorization associated
+*  with the specified problem object.
+*
+*  Current values of control parameters are stored by the routine in
+*  a glp_bfcp structure, which the parameter parm points to. */
+
+void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm)
+{     glp_bfcp *bfcp = lp->bfcp;
+      if (bfcp == NULL)
+      {  parm->type = GLP_BF_FT;
+         parm->lu_size = 0;
+         parm->piv_tol = 0.10;
+         parm->piv_lim = 4;
+         parm->suhl = GLP_ON;
+         parm->eps_tol = 1e-15;
+         parm->max_gro = 1e+10;
+         parm->nfs_max = 100;
+         parm->upd_tol = 1e-6;
+         parm->nrs_max = 100;
+         parm->rs_size = 0;
+      }
+      else
+         memcpy(parm, bfcp, sizeof(glp_bfcp));
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_bfcp - change basis factorization control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_bfcp changes control parameters, which are used
+*  by internal GLPK routines in computing and updating the basis
+*  factorization associated with the specified problem object.
+*
+*  New values of the control parameters should be passed in a structure
+*  glp_bfcp, which the parameter parm points to.
+*
+*  The parameter parm can be specified as NULL, in which case all
+*  control parameters are reset to their default values. */
+
+#if 0 /* 15/XI-2009 */
+static void copy_bfcp(glp_prob *lp)
+{     glp_bfcp _parm, *parm = &_parm;
+      BFD *bfd = lp->bfd;
+      glp_get_bfcp(lp, parm);
+      xassert(bfd != NULL);
+      bfd->type = parm->type;
+      bfd->lu_size = parm->lu_size;
+      bfd->piv_tol = parm->piv_tol;
+      bfd->piv_lim = parm->piv_lim;
+      bfd->suhl = parm->suhl;
+      bfd->eps_tol = parm->eps_tol;
+      bfd->max_gro = parm->max_gro;
+      bfd->nfs_max = parm->nfs_max;
+      bfd->upd_tol = parm->upd_tol;
+      bfd->nrs_max = parm->nrs_max;
+      bfd->rs_size = parm->rs_size;
+      return;
+}
+#else
+static void copy_bfcp(glp_prob *lp)
+{     glp_bfcp _parm, *parm = &_parm;
+      glp_get_bfcp(lp, parm);
+      bfd_set_parm(lp->bfd, parm);
+      return;
+}
+#endif
+
+void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm)
+{     glp_bfcp *bfcp = lp->bfcp;
+      if (parm == NULL)
+      {  /* reset to default values */
+         if (bfcp != NULL)
+            xfree(bfcp), lp->bfcp = NULL;
+      }
+      else
+      {  /* set to specified values */
+         if (bfcp == NULL)
+            bfcp = lp->bfcp = xmalloc(sizeof(glp_bfcp));
+         memcpy(bfcp, parm, sizeof(glp_bfcp));
+         if (!(bfcp->type == GLP_BF_FT || bfcp->type == GLP_BF_BG ||
+               bfcp->type == GLP_BF_GR))
+            xerror("glp_set_bfcp: type = %d; invalid parameter\n",
+               bfcp->type);
+         if (bfcp->lu_size < 0)
+            xerror("glp_set_bfcp: lu_size = %d; invalid parameter\n",
+               bfcp->lu_size);
+         if (!(0.0 < bfcp->piv_tol && bfcp->piv_tol < 1.0))
+            xerror("glp_set_bfcp: piv_tol = %g; invalid parameter\n",
+               bfcp->piv_tol);
+         if (bfcp->piv_lim < 1)
+            xerror("glp_set_bfcp: piv_lim = %d; invalid parameter\n",
+               bfcp->piv_lim);
+         if (!(bfcp->suhl == GLP_ON || bfcp->suhl == GLP_OFF))
+            xerror("glp_set_bfcp: suhl = %d; invalid parameter\n",
+               bfcp->suhl);
+         if (!(0.0 <= bfcp->eps_tol && bfcp->eps_tol <= 1e-6))
+            xerror("glp_set_bfcp: eps_tol = %g; invalid parameter\n",
+               bfcp->eps_tol);
+         if (bfcp->max_gro < 1.0)
+            xerror("glp_set_bfcp: max_gro = %g; invalid parameter\n",
+               bfcp->max_gro);
+         if (!(1 <= bfcp->nfs_max && bfcp->nfs_max <= 32767))
+            xerror("glp_set_bfcp: nfs_max = %d; invalid parameter\n",
+               bfcp->nfs_max);
+         if (!(0.0 < bfcp->upd_tol && bfcp->upd_tol < 1.0))
+            xerror("glp_set_bfcp: upd_tol = %g; invalid parameter\n",
+               bfcp->upd_tol);
+         if (!(1 <= bfcp->nrs_max && bfcp->nrs_max <= 32767))
+            xerror("glp_set_bfcp: nrs_max = %d; invalid parameter\n",
+               bfcp->nrs_max);
+         if (bfcp->rs_size < 0)
+            xerror("glp_set_bfcp: rs_size = %d; invalid parameter\n",
+               bfcp->nrs_max);
+         if (bfcp->rs_size == 0)
+            bfcp->rs_size = 20 * bfcp->nrs_max;
+      }
+      if (lp->bfd != NULL) copy_bfcp(lp);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_bhead - retrieve the basis header information
+*
+*  SYNOPSIS
+*
+*  int glp_get_bhead(glp_prob *lp, int k);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_bhead returns the basis header information for
+*  the current basis associated with the specified problem object.
+*
+*  RETURNS
+*
+*  If xB[k], 1 <= k <= m, is i-th auxiliary variable (1 <= i <= m), the
+*  routine returns i. Otherwise, if xB[k] is j-th structural variable
+*  (1 <= j <= n), the routine returns m+j. Here m is the number of rows
+*  and n is the number of columns in the problem object. */
+
+int glp_get_bhead(glp_prob *lp, int k)
+{     if (!(lp->m == 0 || lp->valid))
+         xerror("glp_get_bhead: basis factorization does not exist\n");
+      if (!(1 <= k && k <= lp->m))
+         xerror("glp_get_bhead: k = %d; index out of range\n", k);
+      return lp->head[k];
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_bind - retrieve row index in the basis header
+*
+*  SYNOPSIS
+*
+*  int glp_get_row_bind(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_bind returns the index k of basic variable
+*  xB[k], 1 <= k <= m, which is i-th auxiliary variable, 1 <= i <= m,
+*  in the current basis associated with the specified problem object,
+*  where m is the number of rows. However, if i-th auxiliary variable
+*  is non-basic, the routine returns zero. */
+
+int glp_get_row_bind(glp_prob *lp, int i)
+{     if (!(lp->m == 0 || lp->valid))
+         xerror("glp_get_row_bind: basis factorization does not exist\n"
+            );
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_bind: i = %d; row number out of range\n",
+            i);
+      return lp->row[i]->bind;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_bind - retrieve column index in the basis header
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_bind(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_bind returns the index k of basic variable
+*  xB[k], 1 <= k <= m, which is j-th structural variable, 1 <= j <= n,
+*  in the current basis associated with the specified problem object,
+*  where m is the number of rows, n is the number of columns. However,
+*  if j-th structural variable is non-basic, the routine returns zero.*/
+
+int glp_get_col_bind(glp_prob *lp, int j)
+{     if (!(lp->m == 0 || lp->valid))
+         xerror("glp_get_col_bind: basis factorization does not exist\n"
+            );
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_bind: j = %d; column number out of range\n"
+            , j);
+      return lp->col[j]->bind;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  void glp_ftran(glp_prob *lp, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix corresponding to the
+*  current basis for the specified problem object, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  SCALING/UNSCALING
+*
+*  Let A~ = (I | -A) is the augmented constraint matrix of the original
+*  (unscaled) problem. In the scaled LP problem instead the matrix A the
+*  scaled matrix A" = R*A*S is actually used, so
+*
+*     A~" = (I | A") = (I | R*A*S) = (R*I*inv(R) | R*A*S) =
+*                                                                    (1)
+*         = R*(I | A)*S~ = R*A~*S~,
+*
+*  is the scaled augmented constraint matrix, where R and S are diagonal
+*  scaling matrices used to scale rows and columns of the matrix A, and
+*
+*     S~ = diag(inv(R) | S)                                          (2)
+*
+*  is an augmented diagonal scaling matrix.
+*
+*  By definition:
+*
+*     A~ = (B | N),                                                  (3)
+*
+*  where B is the basic matrix, which consists of basic columns of the
+*  augmented constraint matrix A~, and N is a matrix, which consists of
+*  non-basic columns of A~. From (1) it follows that:
+*
+*     A~" = (B" | N") = (R*B*SB | R*N*SN),                           (4)
+*
+*  where SB and SN are parts of the augmented scaling matrix S~, which
+*  correspond to basic and non-basic variables, respectively. Therefore
+*
+*     B" = R*B*SB,                                                   (5)
+*
+*  which is the scaled basis matrix. */
+
+void glp_ftran(glp_prob *lp, double x[])
+{     int m = lp->m;
+      GLPROW **row = lp->row;
+      GLPCOL **col = lp->col;
+      int i, k;
+      /* B*x = b ===> (R*B*SB)*(inv(SB)*x) = R*b ===>
+         B"*x" = b", where b" = R*b, x = SB*x" */
+      if (!(m == 0 || lp->valid))
+         xerror("glp_ftran: basis factorization does not exist\n");
+      /* b" := R*b */
+      for (i = 1; i <= m; i++)
+         x[i] *= row[i]->rii;
+      /* x" := inv(B")*b" */
+      if (m > 0) bfd_ftran(lp->bfd, x);
+      /* x := SB*x" */
+      for (i = 1; i <= m; i++)
+      {  k = lp->head[i];
+         if (k <= m)
+            x[i] /= row[k]->rii;
+         else
+            x[i] *= col[k-m]->sjj;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  void glp_btran(glp_prob *lp, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix corresponding to the current basis for the specified problem
+*  problem object, x is the vector of unknowns to be computed, b is the
+*  vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  SCALING/UNSCALING
+*
+*  See comments to the routine glp_ftran. */
+
+void glp_btran(glp_prob *lp, double x[])
+{     int m = lp->m;
+      GLPROW **row = lp->row;
+      GLPCOL **col = lp->col;
+      int i, k;
+      /* B'*x = b ===> (SB*B'*R)*(inv(R)*x) = SB*b ===>
+         (B")'*x" = b", where b" = SB*b, x = R*x" */
+      if (!(m == 0 || lp->valid))
+         xerror("glp_btran: basis factorization does not exist\n");
+      /* b" := SB*b */
+      for (i = 1; i <= m; i++)
+      {  k = lp->head[i];
+         if (k <= m)
+            x[i] /= row[k]->rii;
+         else
+            x[i] *= col[k-m]->sjj;
+      }
+      /* x" := inv[(B")']*b" */
+      if (m > 0) bfd_btran(lp->bfd, x);
+      /* x := R*x" */
+      for (i = 1; i <= m; i++)
+         x[i] *= row[i]->rii;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_warm_up - "warm up" LP basis
+*
+*  SYNOPSIS
+*
+*  int glp_warm_up(glp_prob *P);
+*
+*  DESCRIPTION
+*
+*  The routine glp_warm_up "warms up" the LP basis for the specified
+*  problem object using current statuses assigned to rows and columns
+*  (that is, to auxiliary and structural variables).
+*
+*  This operation includes computing factorization of the basis matrix
+*  (if it does not exist), computing primal and dual components of basic
+*  solution, and determining the solution status.
+*
+*  RETURNS
+*
+*  0  The operation has been successfully performed.
+*
+*  GLP_EBADB
+*     The basis matrix is invalid, i.e. the number of basic (auxiliary
+*     and structural) variables differs from the number of rows in the
+*     problem object.
+*
+*  GLP_ESING
+*     The basis matrix is singular within the working precision.
+*
+*  GLP_ECOND
+*     The basis matrix is ill-conditioned. */
+
+int glp_warm_up(glp_prob *P)
+{     GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, type, ret;
+      double eps, temp, *work;
+      /* invalidate basic solution */
+      P->pbs_stat = P->dbs_stat = GLP_UNDEF;
+      P->obj_val = 0.0;
+      P->some = 0;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         row->prim = row->dual = 0.0;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         col->prim = col->dual = 0.0;
+      }
+      /* compute the basis factorization, if necessary */
+      if (!glp_bf_exists(P))
+      {  ret = glp_factorize(P);
+         if (ret != 0) goto done;
+      }
+      /* allocate working array */
+      work = xcalloc(1+P->m, sizeof(double));
+      /* determine and store values of non-basic variables, compute
+         vector (- N * xN) */
+      for (i = 1; i <= P->m; i++)
+         work[i] = 0.0;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->stat == GLP_BS)
+            continue;
+         else if (row->stat == GLP_NL)
+            row->prim = row->lb;
+         else if (row->stat == GLP_NU)
+            row->prim = row->ub;
+         else if (row->stat == GLP_NF)
+            row->prim = 0.0;
+         else if (row->stat == GLP_NS)
+            row->prim = row->lb;
+         else
+            xassert(row != row);
+         /* N[j] is i-th column of matrix (I|-A) */
+         work[i] -= row->prim;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat == GLP_BS)
+            continue;
+         else if (col->stat == GLP_NL)
+            col->prim = col->lb;
+         else if (col->stat == GLP_NU)
+            col->prim = col->ub;
+         else if (col->stat == GLP_NF)
+            col->prim = 0.0;
+         else if (col->stat == GLP_NS)
+            col->prim = col->lb;
+         else
+            xassert(col != col);
+         /* N[j] is (m+j)-th column of matrix (I|-A) */
+         if (col->prim != 0.0)
+         {  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+               work[aij->row->i] += aij->val * col->prim;
+         }
+      }
+      /* compute vector of basic variables xB = - inv(B) * N * xN */
+      glp_ftran(P, work);
+      /* store values of basic variables, check primal feasibility */
+      P->pbs_stat = GLP_FEAS;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->stat != GLP_BS)
+            continue;
+         row->prim = work[row->bind];
+         type = row->type;
+         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(row->lb);
+            if (row->prim < row->lb - eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(row->ub);
+            if (row->prim > row->ub + eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat != GLP_BS)
+            continue;
+         col->prim = work[col->bind];
+         type = col->type;
+         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(col->lb);
+            if (col->prim < col->lb - eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(col->ub);
+            if (col->prim > col->ub + eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+      }
+      /* compute value of the objective function */
+      P->obj_val = P->c0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         P->obj_val += col->coef * col->prim;
+      }
+      /* build vector cB of objective coefficients at basic variables */
+      for (i = 1; i <= P->m; i++)
+         work[i] = 0.0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat == GLP_BS)
+            work[col->bind] = col->coef;
+      }
+      /* compute vector of simplex multipliers pi = inv(B') * cB */
+      glp_btran(P, work);
+      /* compute and store reduced costs of non-basic variables d[j] =
+         c[j] - N'[j] * pi, check dual feasibility */
+      P->dbs_stat = GLP_FEAS;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->stat == GLP_BS)
+         {  row->dual = 0.0;
+            continue;
+         }
+         /* N[j] is i-th column of matrix (I|-A) */
+         row->dual = - work[i];
+         type = row->type;
+         temp = (P->dir == GLP_MIN ? + row->dual : - row->dual);
+         if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
+             (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
+            P->dbs_stat = GLP_INFEAS;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat == GLP_BS)
+         {  col->dual = 0.0;
+            continue;
+         }
+         /* N[j] is (m+j)-th column of matrix (I|-A) */
+         col->dual = col->coef;
+         for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+            col->dual += aij->val * work[aij->row->i];
+         type = col->type;
+         temp = (P->dir == GLP_MIN ? + col->dual : - col->dual);
+         if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
+             (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
+            P->dbs_stat = GLP_INFEAS;
+      }
+      /* free working array */
+      xfree(work);
+      ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_eval_tab_row - compute row of the simplex tableau
+*
+*  SYNOPSIS
+*
+*  int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_eval_tab_row computes a row of the current simplex
+*  tableau for the basic variable, which is specified by the number k:
+*  if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
+*  x[k] is (k-m)-th structural variable, where m is number of rows, and
+*  n is number of columns. The current basis must be available.
+*
+*  The routine stores column indices and numerical values of non-zero
+*  elements of the computed row using sparse format to the locations
+*  ind[1], ..., ind[len] and val[1], ..., val[len], respectively, where
+*  0 <= len <= n is number of non-zeros returned on exit.
+*
+*  Element indices stored in the array ind have the same sense as the
+*  index k, i.e. indices 1 to m denote auxiliary variables and indices
+*  m+1 to m+n denote structural ones (all these variables are obviously
+*  non-basic by definition).
+*
+*  The computed row shows how the specified basic variable x[k] = xB[i]
+*  depends on non-basic variables:
+*
+*     xB[i] = alfa[i,1]*xN[1] + alfa[i,2]*xN[2] + ... + alfa[i,n]*xN[n],
+*
+*  where alfa[i,j] are elements of the simplex table row, xN[j] are
+*  non-basic (auxiliary and structural) variables.
+*
+*  RETURNS
+*
+*  The routine returns number of non-zero elements in the simplex table
+*  row stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  The system of equality constraints of the LP problem is:
+*
+*     xR = A * xS,                                                   (1)
+*
+*  where xR is the vector of auxliary variables, xS is the vector of
+*  structural variables, A is the matrix of constraint coefficients.
+*
+*  The system (1) can be written in homogenous form as follows:
+*
+*     A~ * x = 0,                                                    (2)
+*
+*  where A~ = (I | -A) is the augmented constraint matrix (has m rows
+*  and m+n columns), x = (xR | xS) is the vector of all (auxiliary and
+*  structural) variables.
+*
+*  By definition for the current basis we have:
+*
+*     A~ = (B | N),                                                  (3)
+*
+*  where B is the basis matrix. Thus, the system (2) can be written as:
+*
+*     B * xB + N * xN = 0.                                           (4)
+*
+*  From (4) it follows that:
+*
+*     xB = A^ * xN,                                                  (5)
+*
+*  where the matrix
+*
+*     A^ = - inv(B) * N                                              (6)
+*
+*  is called the simplex table.
+*
+*  It is understood that i-th row of the simplex table is:
+*
+*     e * A^ = - e * inv(B) * N,                                     (7)
+*
+*  where e is a unity vector with e[i] = 1.
+*
+*  To compute i-th row of the simplex table the routine first computes
+*  i-th row of the inverse:
+*
+*     rho = inv(B') * e,                                             (8)
+*
+*  where B' is a matrix transposed to B, and then computes elements of
+*  i-th row of the simplex table as scalar products:
+*
+*     alfa[i,j] = - rho * N[j]   for all j,                          (9)
+*
+*  where N[j] is a column of the augmented constraint matrix A~, which
+*  corresponds to some non-basic auxiliary or structural variable. */
+
+int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[])
+{     int m = lp->m;
+      int n = lp->n;
+      int i, t, len, lll, *iii;
+      double alfa, *rho, *vvv;
+      if (!(m == 0 || lp->valid))
+         xerror("glp_eval_tab_row: basis factorization does not exist\n"
+            );
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_eval_tab_row: k = %d; variable number out of range"
+            , k);
+      /* determine xB[i] which corresponds to x[k] */
+      if (k <= m)
+         i = glp_get_row_bind(lp, k);
+      else
+         i = glp_get_col_bind(lp, k-m);
+      if (i == 0)
+         xerror("glp_eval_tab_row: k = %d; variable must be basic", k);
+      xassert(1 <= i && i <= m);
+      /* allocate working arrays */
+      rho = xcalloc(1+m, sizeof(double));
+      iii = xcalloc(1+m, sizeof(int));
+      vvv = xcalloc(1+m, sizeof(double));
+      /* compute i-th row of the inverse; see (8) */
+      for (t = 1; t <= m; t++) rho[t] = 0.0;
+      rho[i] = 1.0;
+      glp_btran(lp, rho);
+      /* compute i-th row of the simplex table */
+      len = 0;
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  /* x[k] is auxiliary variable, so N[k] is a unity column */
+            if (glp_get_row_stat(lp, k) == GLP_BS) continue;
+            /* compute alfa[i,j]; see (9) */
+            alfa = - rho[k];
+         }
+         else
+         {  /* x[k] is structural variable, so N[k] is a column of the
+               original constraint matrix A with negative sign */
+            if (glp_get_col_stat(lp, k-m) == GLP_BS) continue;
+            /* compute alfa[i,j]; see (9) */
+            lll = glp_get_mat_col(lp, k-m, iii, vvv);
+            alfa = 0.0;
+            for (t = 1; t <= lll; t++) alfa += rho[iii[t]] * vvv[t];
+         }
+         /* store alfa[i,j] */
+         if (alfa != 0.0) len++, ind[len] = k, val[len] = alfa;
+      }
+      xassert(len <= n);
+      /* free working arrays */
+      xfree(rho);
+      xfree(iii);
+      xfree(vvv);
+      /* return to the calling program */
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_eval_tab_col - compute column of the simplex tableau
+*
+*  SYNOPSIS
+*
+*  int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_eval_tab_col computes a column of the current simplex
+*  table for the non-basic variable, which is specified by the number k:
+*  if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
+*  x[k] is (k-m)-th structural variable, where m is number of rows, and
+*  n is number of columns. The current basis must be available.
+*
+*  The routine stores row indices and numerical values of non-zero
+*  elements of the computed column using sparse format to the locations
+*  ind[1], ..., ind[len] and val[1], ..., val[len] respectively, where
+*  0 <= len <= m is number of non-zeros returned on exit.
+*
+*  Element indices stored in the array ind have the same sense as the
+*  index k, i.e. indices 1 to m denote auxiliary variables and indices
+*  m+1 to m+n denote structural ones (all these variables are obviously
+*  basic by the definition).
+*
+*  The computed column shows how basic variables depend on the specified
+*  non-basic variable x[k] = xN[j]:
+*
+*     xB[1] = ... + alfa[1,j]*xN[j] + ...
+*     xB[2] = ... + alfa[2,j]*xN[j] + ...
+*              . . . . . .
+*     xB[m] = ... + alfa[m,j]*xN[j] + ...
+*
+*  where alfa[i,j] are elements of the simplex table column, xB[i] are
+*  basic (auxiliary and structural) variables.
+*
+*  RETURNS
+*
+*  The routine returns number of non-zero elements in the simplex table
+*  column stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  As it was explained in comments to the routine glp_eval_tab_row (see
+*  above) the simplex table is the following matrix:
+*
+*     A^ = - inv(B) * N.                                             (1)
+*
+*  Therefore j-th column of the simplex table is:
+*
+*     A^ * e = - inv(B) * N * e = - inv(B) * N[j],                   (2)
+*
+*  where e is a unity vector with e[j] = 1, B is the basis matrix, N[j]
+*  is a column of the augmented constraint matrix A~, which corresponds
+*  to the given non-basic auxiliary or structural variable. */
+
+int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[])
+{     int m = lp->m;
+      int n = lp->n;
+      int t, len, stat;
+      double *col;
+      if (!(m == 0 || lp->valid))
+         xerror("glp_eval_tab_col: basis factorization does not exist\n"
+            );
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_eval_tab_col: k = %d; variable number out of range"
+            , k);
+      if (k <= m)
+         stat = glp_get_row_stat(lp, k);
+      else
+         stat = glp_get_col_stat(lp, k-m);
+      if (stat == GLP_BS)
+         xerror("glp_eval_tab_col: k = %d; variable must be non-basic",
+            k);
+      /* obtain column N[k] with negative sign */
+      col = xcalloc(1+m, sizeof(double));
+      for (t = 1; t <= m; t++) col[t] = 0.0;
+      if (k <= m)
+      {  /* x[k] is auxiliary variable, so N[k] is a unity column */
+         col[k] = -1.0;
+      }
+      else
+      {  /* x[k] is structural variable, so N[k] is a column of the
+            original constraint matrix A with negative sign */
+         len = glp_get_mat_col(lp, k-m, ind, val);
+         for (t = 1; t <= len; t++) col[ind[t]] = val[t];
+      }
+      /* compute column of the simplex table, which corresponds to the
+         specified non-basic variable x[k] */
+      glp_ftran(lp, col);
+      len = 0;
+      for (t = 1; t <= m; t++)
+      {  if (col[t] != 0.0)
+         {  len++;
+            ind[len] = glp_get_bhead(lp, t);
+            val[len] = col[t];
+         }
+      }
+      xfree(col);
+      /* return to the calling program */
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_transform_row - transform explicitly specified row
+*
+*  SYNOPSIS
+*
+*  int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_transform_row performs the same operation as the
+*  routine glp_eval_tab_row with exception that the row to be
+*  transformed is specified explicitly as a sparse vector.
+*
+*  The explicitly specified row may be thought as a linear form:
+*
+*     x = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],             (1)
+*
+*  where x is an auxiliary variable for this row, a[j] are coefficients
+*  of the linear form, x[m+j] are structural variables.
+*
+*  On entry column indices and numerical values of non-zero elements of
+*  the row should be stored in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], where len is the number of non-zero elements.
+*
+*  This routine uses the system of equality constraints and the current
+*  basis in order to express the auxiliary variable x in (1) through the
+*  current non-basic variables (as if the transformed row were added to
+*  the problem object and its auxiliary variable were basic), i.e. the
+*  resultant row has the form:
+*
+*     x = alfa[1]*xN[1] + alfa[2]*xN[2] + ... + alfa[n]*xN[n],       (2)
+*
+*  where xN[j] are non-basic (auxiliary or structural) variables, n is
+*  the number of columns in the LP problem object.
+*
+*  On exit the routine stores indices and numerical values of non-zero
+*  elements of the resultant row (2) in locations ind[1], ..., ind[len']
+*  and val[1], ..., val[len'], where 0 <= len' <= n is the number of
+*  non-zero elements in the resultant row returned by the routine. Note
+*  that indices (numbers) of non-basic variables stored in the array ind
+*  correspond to original ordinal numbers of variables: indices 1 to m
+*  mean auxiliary variables and indices m+1 to m+n mean structural ones.
+*
+*  RETURNS
+*
+*  The routine returns len', which is the number of non-zero elements in
+*  the resultant row stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  The explicitly specified row (1) is transformed in the same way as it
+*  were the objective function row.
+*
+*  From (1) it follows that:
+*
+*     x = aB * xB + aN * xN,                                         (3)
+*
+*  where xB is the vector of basic variables, xN is the vector of
+*  non-basic variables.
+*
+*  The simplex table, which corresponds to the current basis, is:
+*
+*     xB = [-inv(B) * N] * xN.                                       (4)
+*
+*  Therefore substituting xB from (4) to (3) we have:
+*
+*     x = aB * [-inv(B) * N] * xN + aN * xN =
+*                                                                    (5)
+*       = rho * (-N) * xN + aN * xN = alfa * xN,
+*
+*  where:
+*
+*     rho = inv(B') * aB,                                            (6)
+*
+*  and
+*
+*     alfa = aN + rho * (-N)                                         (7)
+*
+*  is the resultant row computed by the routine. */
+
+int glp_transform_row(glp_prob *P, int len, int ind[], double val[])
+{     int i, j, k, m, n, t, lll, *iii;
+      double alfa, *a, *aB, *rho, *vvv;
+      if (!glp_bf_exists(P))
+         xerror("glp_transform_row: basis factorization does not exist "
+            "\n");
+      m = glp_get_num_rows(P);
+      n = glp_get_num_cols(P);
+      /* unpack the row to be transformed to the array a */
+      a = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++) a[j] = 0.0;
+      if (!(0 <= len && len <= n))
+         xerror("glp_transform_row: len = %d; invalid row length\n",
+            len);
+      for (t = 1; t <= len; t++)
+      {  j = ind[t];
+         if (!(1 <= j && j <= n))
+            xerror("glp_transform_row: ind[%d] = %d; column index out o"
+               "f range\n", t, j);
+         if (val[t] == 0.0)
+            xerror("glp_transform_row: val[%d] = 0; zero coefficient no"
+               "t allowed\n", t);
+         if (a[j] != 0.0)
+            xerror("glp_transform_row: ind[%d] = %d; duplicate column i"
+               "ndices not allowed\n", t, j);
+         a[j] = val[t];
+      }
+      /* construct the vector aB */
+      aB = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  k = glp_get_bhead(P, i);
+         /* xB[i] is k-th original variable */
+         xassert(1 <= k && k <= m+n);
+         aB[i] = (k <= m ? 0.0 : a[k-m]);
+      }
+      /* solve the system B'*rho = aB to compute the vector rho */
+      rho = aB, glp_btran(P, rho);
+      /* compute coefficients at non-basic auxiliary variables */
+      len = 0;
+      for (i = 1; i <= m; i++)
+      {  if (glp_get_row_stat(P, i) != GLP_BS)
+         {  alfa = - rho[i];
+            if (alfa != 0.0)
+            {  len++;
+               ind[len] = i;
+               val[len] = alfa;
+            }
+         }
+      }
+      /* compute coefficients at non-basic structural variables */
+      iii = xcalloc(1+m, sizeof(int));
+      vvv = xcalloc(1+m, sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  if (glp_get_col_stat(P, j) != GLP_BS)
+         {  alfa = a[j];
+            lll = glp_get_mat_col(P, j, iii, vvv);
+            for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]];
+            if (alfa != 0.0)
+            {  len++;
+               ind[len] = m+j;
+               val[len] = alfa;
+            }
+         }
+      }
+      xassert(len <= n);
+      xfree(iii);
+      xfree(vvv);
+      xfree(aB);
+      xfree(a);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_transform_col - transform explicitly specified column
+*
+*  SYNOPSIS
+*
+*  int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_transform_col performs the same operation as the
+*  routine glp_eval_tab_col with exception that the column to be
+*  transformed is specified explicitly as a sparse vector.
+*
+*  The explicitly specified column may be thought as if it were added
+*  to the original system of equality constraints:
+*
+*     x[1] = a[1,1]*x[m+1] + ... + a[1,n]*x[m+n] + a[1]*x
+*     x[2] = a[2,1]*x[m+1] + ... + a[2,n]*x[m+n] + a[2]*x            (1)
+*        .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+*     x[m] = a[m,1]*x[m+1] + ... + a[m,n]*x[m+n] + a[m]*x
+*
+*  where x[i] are auxiliary variables, x[m+j] are structural variables,
+*  x is a structural variable for the explicitly specified column, a[i]
+*  are constraint coefficients for x.
+*
+*  On entry row indices and numerical values of non-zero elements of
+*  the column should be stored in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], where len is the number of non-zero elements.
+*
+*  This routine uses the system of equality constraints and the current
+*  basis in order to express the current basic variables through the
+*  structural variable x in (1) (as if the transformed column were added
+*  to the problem object and the variable x were non-basic), i.e. the
+*  resultant column has the form:
+*
+*     xB[1] = ... + alfa[1]*x
+*     xB[2] = ... + alfa[2]*x                                        (2)
+*        .  .  .  .  .  .
+*     xB[m] = ... + alfa[m]*x
+*
+*  where xB are basic (auxiliary and structural) variables, m is the
+*  number of rows in the problem object.
+*
+*  On exit the routine stores indices and numerical values of non-zero
+*  elements of the resultant column (2) in locations ind[1], ...,
+*  ind[len'] and val[1], ..., val[len'], where 0 <= len' <= m is the
+*  number of non-zero element in the resultant column returned by the
+*  routine. Note that indices (numbers) of basic variables stored in
+*  the array ind correspond to original ordinal numbers of variables:
+*  indices 1 to m mean auxiliary variables and indices m+1 to m+n mean
+*  structural ones.
+*
+*  RETURNS
+*
+*  The routine returns len', which is the number of non-zero elements
+*  in the resultant column stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  The explicitly specified column (1) is transformed in the same way
+*  as any other column of the constraint matrix using the formula:
+*
+*     alfa = inv(B) * a,                                             (3)
+*
+*  where alfa is the resultant column computed by the routine. */
+
+int glp_transform_col(glp_prob *P, int len, int ind[], double val[])
+{     int i, m, t;
+      double *a, *alfa;
+      if (!glp_bf_exists(P))
+         xerror("glp_transform_col: basis factorization does not exist "
+            "\n");
+      m = glp_get_num_rows(P);
+      /* unpack the column to be transformed to the array a */
+      a = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) a[i] = 0.0;
+      if (!(0 <= len && len <= m))
+         xerror("glp_transform_col: len = %d; invalid column length\n",
+            len);
+      for (t = 1; t <= len; t++)
+      {  i = ind[t];
+         if (!(1 <= i && i <= m))
+            xerror("glp_transform_col: ind[%d] = %d; row index out of r"
+               "ange\n", t, i);
+         if (val[t] == 0.0)
+            xerror("glp_transform_col: val[%d] = 0; zero coefficient no"
+               "t allowed\n", t);
+         if (a[i] != 0.0)
+            xerror("glp_transform_col: ind[%d] = %d; duplicate row indi"
+               "ces not allowed\n", t, i);
+         a[i] = val[t];
+      }
+      /* solve the system B*a = alfa to compute the vector alfa */
+      alfa = a, glp_ftran(P, alfa);
+      /* store resultant coefficients */
+      len = 0;
+      for (i = 1; i <= m; i++)
+      {  if (alfa[i] != 0.0)
+         {  len++;
+            ind[len] = glp_get_bhead(P, i);
+            val[len] = alfa[i];
+         }
+      }
+      xfree(a);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_prim_rtest - perform primal ratio test
+*
+*  SYNOPSIS
+*
+*  int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+*     const double val[], int dir, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine glp_prim_rtest performs the primal ratio test using an
+*  explicitly specified column of the simplex table.
+*
+*  The current basic solution associated with the LP problem object
+*  must be primal feasible.
+*
+*  The explicitly specified column of the simplex table shows how the
+*  basic variables xB depend on some non-basic variable x (which is not
+*  necessarily presented in the problem object):
+*
+*     xB[1] = ... + alfa[1] * x + ...
+*     xB[2] = ... + alfa[2] * x + ...                                (*)
+*         .  .  .  .  .  .  .  .
+*     xB[m] = ... + alfa[m] * x + ...
+*
+*  The column (*) is specifed on entry to the routine using the sparse
+*  format. Ordinal numbers of basic variables xB[i] should be placed in
+*  locations ind[1], ..., ind[len], where ordinal number 1 to m denote
+*  auxiliary variables, and ordinal numbers m+1 to m+n denote structural
+*  variables. The corresponding non-zero coefficients alfa[i] should be
+*  placed in locations val[1], ..., val[len]. The arrays ind and val are
+*  not changed on exit.
+*
+*  The parameter dir specifies direction in which the variable x changes
+*  on entering the basis: +1 means increasing, -1 means decreasing.
+*
+*  The parameter eps is an absolute tolerance (small positive number)
+*  used by the routine to skip small alfa[j] of the row (*).
+*
+*  The routine determines which basic variable (among specified in
+*  ind[1], ..., ind[len]) should leave the basis in order to keep primal
+*  feasibility.
+*
+*  RETURNS
+*
+*  The routine glp_prim_rtest returns the index piv in the arrays ind
+*  and val corresponding to the pivot element chosen, 1 <= piv <= len.
+*  If the adjacent basic solution is primal unbounded and therefore the
+*  choice cannot be made, the routine returns zero.
+*
+*  COMMENTS
+*
+*  If the non-basic variable x is presented in the LP problem object,
+*  the column (*) can be computed with the routine glp_eval_tab_col;
+*  otherwise it can be computed with the routine glp_transform_col. */
+
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps)
+{     int k, m, n, piv, t, type, stat;
+      double alfa, big, beta, lb, ub, temp, teta;
+      if (glp_get_prim_stat(P) != GLP_FEAS)
+         xerror("glp_prim_rtest: basic solution is not primal feasible "
+            "\n");
+      if (!(dir == +1 || dir == -1))
+         xerror("glp_prim_rtest: dir = %d; invalid parameter\n", dir);
+      if (!(0.0 < eps && eps < 1.0))
+         xerror("glp_prim_rtest: eps = %g; invalid parameter\n", eps);
+      m = glp_get_num_rows(P);
+      n = glp_get_num_cols(P);
+      /* initial settings */
+      piv = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through the entries of the specified column */
+      for (t = 1; t <= len; t++)
+      {  /* get the ordinal number of basic variable */
+         k = ind[t];
+         if (!(1 <= k && k <= m+n))
+            xerror("glp_prim_rtest: ind[%d] = %d; variable number out o"
+               "f range\n", t, k);
+         /* determine type, bounds, status and primal value of basic
+            variable xB[i] = x[k] in the current basic solution */
+         if (k <= m)
+         {  type = glp_get_row_type(P, k);
+            lb = glp_get_row_lb(P, k);
+            ub = glp_get_row_ub(P, k);
+            stat = glp_get_row_stat(P, k);
+            beta = glp_get_row_prim(P, k);
+         }
+         else
+         {  type = glp_get_col_type(P, k-m);
+            lb = glp_get_col_lb(P, k-m);
+            ub = glp_get_col_ub(P, k-m);
+            stat = glp_get_col_stat(P, k-m);
+            beta = glp_get_col_prim(P, k-m);
+         }
+         if (stat != GLP_BS)
+            xerror("glp_prim_rtest: ind[%d] = %d; non-basic variable no"
+               "t allowed\n", t, k);
+         /* determine influence coefficient at basic variable xB[i]
+            in the explicitly specified column and turn to the case of
+            increasing the variable x in order to simplify the program
+            logic */
+         alfa = (dir > 0 ? + val[t] : - val[t]);
+         /* analyze main cases */
+         if (type == GLP_FR)
+         {  /* xB[i] is free variable */
+            continue;
+         }
+         else if (type == GLP_LO)
+lo:      {  /* xB[i] has an lower bound */
+            if (alfa > - eps) continue;
+            temp = (lb - beta) / alfa;
+         }
+         else if (type == GLP_UP)
+up:      {  /* xB[i] has an upper bound */
+            if (alfa < + eps) continue;
+            temp = (ub - beta) / alfa;
+         }
+         else if (type == GLP_DB)
+         {  /* xB[i] has both lower and upper bounds */
+            if (alfa < 0.0) goto lo; else goto up;
+         }
+         else if (type == GLP_FX)
+         {  /* xB[i] is fixed variable */
+            if (- eps < alfa && alfa < + eps) continue;
+            temp = 0.0;
+         }
+         else
+            xassert(type != type);
+         /* if the value of the variable xB[i] violates its lower or
+            upper bound (slightly, because the current basis is assumed
+            to be primal feasible), temp is negative; we can think this
+            happens due to round-off errors and the value is exactly on
+            the bound; this allows replacing temp by zero */
+         if (temp < 0.0) temp = 0.0;
+         /* apply the minimal ratio test */
+         if (teta > temp || teta == temp && big < fabs(alfa))
+            piv = t, teta = temp, big = fabs(alfa);
+      }
+      /* return index of the pivot element chosen */
+      return piv;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_dual_rtest - perform dual ratio test
+*
+*  SYNOPSIS
+*
+*  int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+*     const double val[], int dir, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine glp_dual_rtest performs the dual ratio test using an
+*  explicitly specified row of the simplex table.
+*
+*  The current basic solution associated with the LP problem object
+*  must be dual feasible.
+*
+*  The explicitly specified row of the simplex table is a linear form
+*  that shows how some basic variable x (which is not necessarily
+*  presented in the problem object) depends on non-basic variables xN:
+*
+*     x = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n]. (*)
+*
+*  The row (*) is specified on entry to the routine using the sparse
+*  format. Ordinal numbers of non-basic variables xN[j] should be placed
+*  in locations ind[1], ..., ind[len], where ordinal numbers 1 to m
+*  denote auxiliary variables, and ordinal numbers m+1 to m+n denote
+*  structural variables. The corresponding non-zero coefficients alfa[j]
+*  should be placed in locations val[1], ..., val[len]. The arrays ind
+*  and val are not changed on exit.
+*
+*  The parameter dir specifies direction in which the variable x changes
+*  on leaving the basis: +1 means that x goes to its lower bound, and -1
+*  means that x goes to its upper bound.
+*
+*  The parameter eps is an absolute tolerance (small positive number)
+*  used by the routine to skip small alfa[j] of the row (*).
+*
+*  The routine determines which non-basic variable (among specified in
+*  ind[1], ..., ind[len]) should enter the basis in order to keep dual
+*  feasibility.
+*
+*  RETURNS
+*
+*  The routine glp_dual_rtest returns the index piv in the arrays ind
+*  and val corresponding to the pivot element chosen, 1 <= piv <= len.
+*  If the adjacent basic solution is dual unbounded and therefore the
+*  choice cannot be made, the routine returns zero.
+*
+*  COMMENTS
+*
+*  If the basic variable x is presented in the LP problem object, the
+*  row (*) can be computed with the routine glp_eval_tab_row; otherwise
+*  it can be computed with the routine glp_transform_row. */
+
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps)
+{     int k, m, n, piv, t, stat;
+      double alfa, big, cost, obj, temp, teta;
+      if (glp_get_dual_stat(P) != GLP_FEAS)
+         xerror("glp_dual_rtest: basic solution is not dual feasible\n")
+            ;
+      if (!(dir == +1 || dir == -1))
+         xerror("glp_dual_rtest: dir = %d; invalid parameter\n", dir);
+      if (!(0.0 < eps && eps < 1.0))
+         xerror("glp_dual_rtest: eps = %g; invalid parameter\n", eps);
+      m = glp_get_num_rows(P);
+      n = glp_get_num_cols(P);
+      /* take into account optimization direction */
+      obj = (glp_get_obj_dir(P) == GLP_MIN ? +1.0 : -1.0);
+      /* initial settings */
+      piv = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through the entries of the specified row */
+      for (t = 1; t <= len; t++)
+      {  /* get ordinal number of non-basic variable */
+         k = ind[t];
+         if (!(1 <= k && k <= m+n))
+            xerror("glp_dual_rtest: ind[%d] = %d; variable number out o"
+               "f range\n", t, k);
+         /* determine status and reduced cost of non-basic variable
+            x[k] = xN[j] in the current basic solution */
+         if (k <= m)
+         {  stat = glp_get_row_stat(P, k);
+            cost = glp_get_row_dual(P, k);
+         }
+         else
+         {  stat = glp_get_col_stat(P, k-m);
+            cost = glp_get_col_dual(P, k-m);
+         }
+         if (stat == GLP_BS)
+            xerror("glp_dual_rtest: ind[%d] = %d; basic variable not al"
+               "lowed\n", t, k);
+         /* determine influence coefficient at non-basic variable xN[j]
+            in the explicitly specified row and turn to the case of
+            increasing the variable x in order to simplify the program
+            logic */
+         alfa = (dir > 0 ? + val[t] : - val[t]);
+         /* analyze main cases */
+         if (stat == GLP_NL)
+         {  /* xN[j] is on its lower bound */
+            if (alfa < + eps) continue;
+            temp = (obj * cost) / alfa;
+         }
+         else if (stat == GLP_NU)
+         {  /* xN[j] is on its upper bound */
+            if (alfa > - eps) continue;
+            temp = (obj * cost) / alfa;
+         }
+         else if (stat == GLP_NF)
+         {  /* xN[j] is non-basic free variable */
+            if (- eps < alfa && alfa < + eps) continue;
+            temp = 0.0;
+         }
+         else if (stat == GLP_NS)
+         {  /* xN[j] is non-basic fixed variable */
+            continue;
+         }
+         else
+            xassert(stat != stat);
+         /* if the reduced cost of the variable xN[j] violates its zero
+            bound (slightly, because the current basis is assumed to be
+            dual feasible), temp is negative; we can think this happens
+            due to round-off errors and the reduced cost is exact zero;
+            this allows replacing temp by zero */
+         if (temp < 0.0) temp = 0.0;
+         /* apply the minimal ratio test */
+         if (teta > temp || teta == temp && big < fabs(alfa))
+            piv = t, teta = temp, big = fabs(alfa);
+      }
+      /* return index of the pivot element chosen */
+      return piv;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_analyze_row - simulate one iteration of dual simplex method
+*
+*  SYNOPSIS
+*
+*  int glp_analyze_row(glp_prob *P, int len, const int ind[],
+*     const double val[], int type, double rhs, double eps, int *piv,
+*     double *x, double *dx, double *y, double *dy, double *dz);
+*
+*  DESCRIPTION
+*
+*  Let the current basis be optimal or dual feasible, and there be
+*  specified a row (constraint), which is violated by the current basic
+*  solution. The routine glp_analyze_row simulates one iteration of the
+*  dual simplex method to determine some information on the adjacent
+*  basis (see below), where the specified row becomes active constraint
+*  (i.e. its auxiliary variable becomes non-basic).
+*
+*  The current basic solution associated with the problem object passed
+*  to the routine must be dual feasible, and its primal components must
+*  be defined.
+*
+*  The row to be analyzed must be previously transformed either with
+*  the routine glp_eval_tab_row (if the row is in the problem object)
+*  or with the routine glp_transform_row (if the row is external, i.e.
+*  not in the problem object). This is needed to express the row only
+*  through (auxiliary and structural) variables, which are non-basic in
+*  the current basis:
+*
+*     y = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n],
+*
+*  where y is an auxiliary variable of the row, alfa[j] is an influence
+*  coefficient, xN[j] is a non-basic variable.
+*
+*  The row is passed to the routine in sparse format. Ordinal numbers
+*  of non-basic variables are stored in locations ind[1], ..., ind[len],
+*  where numbers 1 to m denote auxiliary variables while numbers m+1 to
+*  m+n denote structural variables. Corresponding non-zero coefficients
+*  alfa[j] are stored in locations val[1], ..., val[len]. The arrays
+*  ind and val are ot changed on exit.
+*
+*  The parameters type and rhs specify the row type and its right-hand
+*  side as follows:
+*
+*     type = GLP_LO: y = sum alfa[j] * xN[j] >= rhs
+*
+*     type = GLP_UP: y = sum alfa[j] * xN[j] <= rhs
+*
+*  The parameter eps is an absolute tolerance (small positive number)
+*  used by the routine to skip small coefficients alfa[j] on performing
+*  the dual ratio test.
+*
+*  If the operation was successful, the routine stores the following
+*  information to corresponding location (if some parameter is NULL,
+*  its value is not stored):
+*
+*  piv   index in the array ind and val, 1 <= piv <= len, determining
+*        the non-basic variable, which would enter the adjacent basis;
+*
+*  x     value of the non-basic variable in the current basis;
+*
+*  dx    difference between values of the non-basic variable in the
+*        adjacent and current bases, dx = x.new - x.old;
+*
+*  y     value of the row (i.e. of its auxiliary variable) in the
+*        current basis;
+*
+*  dy    difference between values of the row in the adjacent and
+*        current bases, dy = y.new - y.old;
+*
+*  dz    difference between values of the objective function in the
+*        adjacent and current bases, dz = z.new - z.old. Note that in
+*        case of minimization dz >= 0, and in case of maximization
+*        dz <= 0, i.e. in the adjacent basis the objective function
+*        always gets worse (degrades). */
+
+int _glp_analyze_row(glp_prob *P, int len, const int ind[],
+      const double val[], int type, double rhs, double eps, int *_piv,
+      double *_x, double *_dx, double *_y, double *_dy, double *_dz)
+{     int t, k, dir, piv, ret = 0;
+      double x, dx, y, dy, dz;
+      if (P->pbs_stat == GLP_UNDEF)
+         xerror("glp_analyze_row: primal basic solution components are "
+            "undefined\n");
+      if (P->dbs_stat != GLP_FEAS)
+         xerror("glp_analyze_row: basic solution is not dual feasible\n"
+            );
+      /* compute the row value y = sum alfa[j] * xN[j] in the current
+         basis */
+      if (!(0 <= len && len <= P->n))
+         xerror("glp_analyze_row: len = %d; invalid row length\n", len);
+      y = 0.0;
+      for (t = 1; t <= len; t++)
+      {  /* determine value of x[k] = xN[j] in the current basis */
+         k = ind[t];
+         if (!(1 <= k && k <= P->m+P->n))
+            xerror("glp_analyze_row: ind[%d] = %d; row/column index out"
+               " of range\n", t, k);
+         if (k <= P->m)
+         {  /* x[k] is auxiliary variable */
+            if (P->row[k]->stat == GLP_BS)
+               xerror("glp_analyze_row: ind[%d] = %d; basic auxiliary v"
+                  "ariable is not allowed\n", t, k);
+            x = P->row[k]->prim;
+         }
+         else
+         {  /* x[k] is structural variable */
+            if (P->col[k-P->m]->stat == GLP_BS)
+               xerror("glp_analyze_row: ind[%d] = %d; basic structural "
+                  "variable is not allowed\n", t, k);
+            x = P->col[k-P->m]->prim;
+         }
+         y += val[t] * x;
+      }
+      /* check if the row is primal infeasible in the current basis,
+         i.e. the constraint is violated at the current point */
+      if (type == GLP_LO)
+      {  if (y >= rhs)
+         {  /* the constraint is not violated */
+            ret = 1;
+            goto done;
+         }
+         /* in the adjacent basis y goes to its lower bound */
+         dir = +1;
+      }
+      else if (type == GLP_UP)
+      {  if (y <= rhs)
+         {  /* the constraint is not violated */
+            ret = 1;
+            goto done;
+         }
+         /* in the adjacent basis y goes to its upper bound */
+         dir = -1;
+      }
+      else
+         xerror("glp_analyze_row: type = %d; invalid parameter\n",
+            type);
+      /* compute dy = y.new - y.old */
+      dy = rhs - y;
+      /* perform dual ratio test to determine which non-basic variable
+         should enter the adjacent basis to keep it dual feasible */
+      piv = glp_dual_rtest(P, len, ind, val, dir, eps);
+      if (piv == 0)
+      {  /* no dual feasible adjacent basis exists */
+         ret = 2;
+         goto done;
+      }
+      /* non-basic variable x[k] = xN[j] should enter the basis */
+      k = ind[piv];
+      xassert(1 <= k && k <= P->m+P->n);
+      /* determine its value in the current basis */
+      if (k <= P->m)
+         x = P->row[k]->prim;
+      else
+         x = P->col[k-P->m]->prim;
+      /* compute dx = x.new - x.old = dy / alfa[j] */
+      xassert(val[piv] != 0.0);
+      dx = dy / val[piv];
+      /* compute dz = z.new - z.old = d[j] * dx, where d[j] is reduced
+         cost of xN[j] in the current basis */
+      if (k <= P->m)
+         dz = P->row[k]->dual * dx;
+      else
+         dz = P->col[k-P->m]->dual * dx;
+      /* store the analysis results */
+      if (_piv != NULL) *_piv = piv;
+      if (_x   != NULL) *_x   = x;
+      if (_dx  != NULL) *_dx  = dx;
+      if (_y   != NULL) *_y   = y;
+      if (_dy  != NULL) *_dy  = dy;
+      if (_dz  != NULL) *_dz  = dz;
+done: return ret;
+}
+
+#if 0
+int main(void)
+{     /* example program for the routine glp_analyze_row */
+      glp_prob *P;
+      glp_smcp parm;
+      int i, k, len, piv, ret, ind[1+100];
+      double rhs, x, dx, y, dy, dz, val[1+100];
+      P = glp_create_prob();
+      /* read plan.mps (see glpk/examples) */
+      ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "plan.mps");
+      glp_assert(ret == 0);
+      /* and solve it to optimality */
+      ret = glp_simplex(P, NULL);
+      glp_assert(ret == 0);
+      glp_assert(glp_get_status(P) == GLP_OPT);
+      /* the optimal objective value is 296.217 */
+      /* we would like to know what happens if we would add a new row
+         (constraint) to plan.mps:
+         .01 * bin1 + .01 * bin2 + .02 * bin4 + .02 * bin5 <= 12 */
+      /* first, we specify this new row */
+      glp_create_index(P);
+      len = 0;
+      ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
+      ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
+      rhs = 12;
+      /* then we can compute value of the row (i.e. of its auxiliary
+         variable) in the current basis to see if the constraint is
+         violated */
+      y = 0.0;
+      for (k = 1; k <= len; k++)
+         y += val[k] * glp_get_col_prim(P, ind[k]);
+      glp_printf("y = %g\n", y);
+      /* this prints y = 15.1372, so the constraint is violated, since
+         we require that y <= rhs = 12 */
+      /* now we transform the row to express it only through non-basic
+         (auxiliary and artificial) variables */
+      len = glp_transform_row(P, len, ind, val);
+      /* finally, we simulate one step of the dual simplex method to
+         obtain necessary information for the adjacent basis */
+      ret = _glp_analyze_row(P, len, ind, val, GLP_UP, rhs, 1e-9, &piv,
+         &x, &dx, &y, &dy, &dz);
+      glp_assert(ret == 0);
+      glp_printf("k = %d, x = %g; dx = %g; y = %g; dy = %g; dz = %g\n",
+         ind[piv], x, dx, y, dy, dz);
+      /* this prints dz = 5.64418 and means that in the adjacent basis
+         the objective function would be 296.217 + 5.64418 = 301.861 */
+      /* now we actually include the row into the problem object; note
+         that the arrays ind and val are clobbered, so we need to build
+         them once again */
+      len = 0;
+      ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
+      ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
+      rhs = 12;
+      i = glp_add_rows(P, 1);
+      glp_set_row_bnds(P, i, GLP_UP, 0, rhs);
+      glp_set_mat_row(P, i, len, ind, val);
+      /* and perform one dual simplex iteration */
+      glp_init_smcp(&parm);
+      parm.meth = GLP_DUAL;
+      parm.it_lim = 1;
+      glp_simplex(P, &parm);
+      /* the current objective value is 301.861 */
+      return 0;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  glp_analyze_bound - analyze active bound of non-basic variable
+*
+*  SYNOPSIS
+*
+*  void glp_analyze_bound(glp_prob *P, int k, double *limit1, int *var1,
+*     double *limit2, int *var2);
+*
+*  DESCRIPTION
+*
+*  The routine glp_analyze_bound analyzes the effect of varying the
+*  active bound of specified non-basic variable.
+*
+*  The non-basic variable is specified by the parameter k, where
+*  1 <= k <= m means auxiliary variable of corresponding row while
+*  m+1 <= k <= m+n means structural variable (column).
+*
+*  Note that the current basic solution must be optimal, and the basis
+*  factorization must exist.
+*
+*  Results of the analysis have the following meaning.
+*
+*  value1 is the minimal value of the active bound, at which the basis
+*  still remains primal feasible and thus optimal. -DBL_MAX means that
+*  the active bound has no lower limit.
+*
+*  var1 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) basic variable, which reaches its bound first and thereby
+*  limits further decreasing the active bound being analyzed.
+*  if value1 = -DBL_MAX, var1 is set to 0.
+*
+*  value2 is the maximal value of the active bound, at which the basis
+*  still remains primal feasible and thus optimal. +DBL_MAX means that
+*  the active bound has no upper limit.
+*
+*  var2 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) basic variable, which reaches its bound first and thereby
+*  limits further increasing the active bound being analyzed.
+*  if value2 = +DBL_MAX, var2 is set to 0. */
+
+void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
+      double *value2, int *var2)
+{     GLPROW *row;
+      GLPCOL *col;
+      int m, n, stat, kase, p, len, piv, *ind;
+      double x, new_x, ll, uu, xx, delta, *val;
+      /* sanity checks */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_analyze_bound: P = %p; invalid problem object\n",
+            P);
+      m = P->m, n = P->n;
+      if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+         xerror("glp_analyze_bound: optimal basic solution required\n");
+      if (!(m == 0 || P->valid))
+         xerror("glp_analyze_bound: basis factorization required\n");
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_analyze_bound: k = %d; variable number out of rang"
+            "e\n", k);
+      /* retrieve information about the specified non-basic variable
+         x[k] whose active bound is to be analyzed */
+      if (k <= m)
+      {  row = P->row[k];
+         stat = row->stat;
+         x = row->prim;
+      }
+      else
+      {  col = P->col[k-m];
+         stat = col->stat;
+         x = col->prim;
+      }
+      if (stat == GLP_BS)
+         xerror("glp_analyze_bound: k = %d; basic variable not allowed "
+            "\n", k);
+      /* allocate working arrays */
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      /* compute column of the simplex table corresponding to the
+         non-basic variable x[k] */
+      len = glp_eval_tab_col(P, k, ind, val);
+      xassert(0 <= len && len <= m);
+      /* perform analysis */
+      for (kase = -1; kase <= +1; kase += 2)
+      {  /* kase < 0 means active bound of x[k] is decreasing;
+            kase > 0 means active bound of x[k] is increasing */
+         /* use the primal ratio test to determine some basic variable
+            x[p] which reaches its bound first */
+         piv = glp_prim_rtest(P, len, ind, val, kase, 1e-9);
+         if (piv == 0)
+         {  /* nothing limits changing the active bound of x[k] */
+            p = 0;
+            new_x = (kase < 0 ? -DBL_MAX : +DBL_MAX);
+            goto store;
+         }
+         /* basic variable x[p] limits changing the active bound of
+            x[k]; determine its value in the current basis */
+         xassert(1 <= piv && piv <= len);
+         p = ind[piv];
+         if (p <= m)
+         {  row = P->row[p];
+            ll = glp_get_row_lb(P, row->i);
+            uu = glp_get_row_ub(P, row->i);
+            stat = row->stat;
+            xx = row->prim;
+         }
+         else
+         {  col = P->col[p-m];
+            ll = glp_get_col_lb(P, col->j);
+            uu = glp_get_col_ub(P, col->j);
+            stat = col->stat;
+            xx = col->prim;
+         }
+         xassert(stat == GLP_BS);
+         /* determine delta x[p] = bound of x[p] - value of x[p] */
+         if (kase < 0 && val[piv] > 0.0 ||
+             kase > 0 && val[piv] < 0.0)
+         {  /* delta x[p] < 0, so x[p] goes toward its lower bound */
+            xassert(ll != -DBL_MAX);
+            delta = ll - xx;
+         }
+         else
+         {  /* delta x[p] > 0, so x[p] goes toward its upper bound */
+            xassert(uu != +DBL_MAX);
+            delta = uu - xx;
+         }
+         /* delta x[p] = alfa[p,k] * delta x[k], so new x[k] = x[k] +
+            delta x[k] = x[k] + delta x[p] / alfa[p,k] is the value of
+            x[k] in the adjacent basis */
+         xassert(val[piv] != 0.0);
+         new_x = x + delta / val[piv];
+store:   /* store analysis results */
+         if (kase < 0)
+         {  if (value1 != NULL) *value1 = new_x;
+            if (var1 != NULL) *var1 = p;
+         }
+         else
+         {  if (value2 != NULL) *value2 = new_x;
+            if (var2 != NULL) *var2 = p;
+         }
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_analyze_coef - analyze objective coefficient at basic variable
+*
+*  SYNOPSIS
+*
+*  void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+*     double *value1, double *coef2, int *var2, double *value2);
+*
+*  DESCRIPTION
+*
+*  The routine glp_analyze_coef analyzes the effect of varying the
+*  objective coefficient at specified basic variable.
+*
+*  The basic variable is specified by the parameter k, where
+*  1 <= k <= m means auxiliary variable of corresponding row while
+*  m+1 <= k <= m+n means structural variable (column).
+*
+*  Note that the current basic solution must be optimal, and the basis
+*  factorization must exist.
+*
+*  Results of the analysis have the following meaning.
+*
+*  coef1 is the minimal value of the objective coefficient, at which
+*  the basis still remains dual feasible and thus optimal. -DBL_MAX
+*  means that the objective coefficient has no lower limit.
+*
+*  var1 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) non-basic variable, whose reduced cost reaches its zero
+*  bound first and thereby limits further decreasing the objective
+*  coefficient being analyzed. If coef1 = -DBL_MAX, var1 is set to 0.
+*
+*  value1 is value of the basic variable being analyzed in an adjacent
+*  basis, which is defined as follows. Let the objective coefficient
+*  reaches its minimal value (coef1) and continues decreasing. Then the
+*  reduced cost of the limiting non-basic variable (var1) becomes dual
+*  infeasible and the current basis becomes non-optimal that forces the
+*  limiting non-basic variable to enter the basis replacing there some
+*  basic variable that leaves the basis to keep primal feasibility.
+*  Should note that on determining the adjacent basis current bounds
+*  of the basic variable being analyzed are ignored as if it were free
+*  (unbounded) variable, so it cannot leave the basis. It may happen
+*  that no dual feasible adjacent basis exists, in which case value1 is
+*  set to -DBL_MAX or +DBL_MAX.
+*
+*  coef2 is the maximal value of the objective coefficient, at which
+*  the basis still remains dual feasible and thus optimal. +DBL_MAX
+*  means that the objective coefficient has no upper limit.
+*
+*  var2 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) non-basic variable, whose reduced cost reaches its zero
+*  bound first and thereby limits further increasing the objective
+*  coefficient being analyzed. If coef2 = +DBL_MAX, var2 is set to 0.
+*
+*  value2 is value of the basic variable being analyzed in an adjacent
+*  basis, which is defined exactly in the same way as value1 above with
+*  exception that now the objective coefficient is increasing. */
+
+void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+      double *value1, double *coef2, int *var2, double *value2)
+{     GLPROW *row; GLPCOL *col;
+      int m, n, type, stat, kase, p, q, dir, clen, cpiv, rlen, rpiv,
+         *cind, *rind;
+      double lb, ub, coef, x, lim_coef, new_x, d, delta, ll, uu, xx,
+         *rval, *cval;
+      /* sanity checks */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_analyze_coef: P = %p; invalid problem object\n",
+            P);
+      m = P->m, n = P->n;
+      if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+         xerror("glp_analyze_coef: optimal basic solution required\n");
+      if (!(m == 0 || P->valid))
+         xerror("glp_analyze_coef: basis factorization required\n");
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_analyze_coef: k = %d; variable number out of range"
+            "\n", k);
+      /* retrieve information about the specified basic variable x[k]
+         whose objective coefficient c[k] is to be analyzed */
+      if (k <= m)
+      {  row = P->row[k];
+         type = row->type;
+         lb = row->lb;
+         ub = row->ub;
+         coef = 0.0;
+         stat = row->stat;
+         x = row->prim;
+      }
+      else
+      {  col = P->col[k-m];
+         type = col->type;
+         lb = col->lb;
+         ub = col->ub;
+         coef = col->coef;
+         stat = col->stat;
+         x = col->prim;
+      }
+      if (stat != GLP_BS)
+         xerror("glp_analyze_coef: k = %d; non-basic variable not allow"
+            "ed\n", k);
+      /* allocate working arrays */
+      cind = xcalloc(1+m, sizeof(int));
+      cval = xcalloc(1+m, sizeof(double));
+      rind = xcalloc(1+n, sizeof(int));
+      rval = xcalloc(1+n, sizeof(double));
+      /* compute row of the simplex table corresponding to the basic
+         variable x[k] */
+      rlen = glp_eval_tab_row(P, k, rind, rval);
+      xassert(0 <= rlen && rlen <= n);
+      /* perform analysis */
+      for (kase = -1; kase <= +1; kase += 2)
+      {  /* kase < 0 means objective coefficient c[k] is decreasing;
+            kase > 0 means objective coefficient c[k] is increasing */
+         /* note that decreasing c[k] is equivalent to increasing dual
+            variable lambda[k] and vice versa; we need to correctly set
+            the dir flag as required by the routine glp_dual_rtest */
+         if (P->dir == GLP_MIN)
+            dir = - kase;
+         else if (P->dir == GLP_MAX)
+            dir = + kase;
+         else
+            xassert(P != P);
+         /* use the dual ratio test to determine non-basic variable
+            x[q] whose reduced cost d[q] reaches zero bound first */
+         rpiv = glp_dual_rtest(P, rlen, rind, rval, dir, 1e-9);
+         if (rpiv == 0)
+         {  /* nothing limits changing c[k] */
+            lim_coef = (kase < 0 ? -DBL_MAX : +DBL_MAX);
+            q = 0;
+            /* x[k] keeps its current value */
+            new_x = x;
+            goto store;
+         }
+         /* non-basic variable x[q] limits changing coefficient c[k];
+            determine its status and reduced cost d[k] in the current
+            basis */
+         xassert(1 <= rpiv && rpiv <= rlen);
+         q = rind[rpiv];
+         xassert(1 <= q && q <= m+n);
+         if (q <= m)
+         {  row = P->row[q];
+            stat = row->stat;
+            d = row->dual;
+         }
+         else
+         {  col = P->col[q-m];
+            stat = col->stat;
+            d = col->dual;
+         }
+         /* note that delta d[q] = new d[q] - d[q] = - d[q], because
+            new d[q] = 0; delta d[q] = alfa[k,q] * delta c[k], so
+            delta c[k] = delta d[q] / alfa[k,q] = - d[q] / alfa[k,q] */
+         xassert(rval[rpiv] != 0.0);
+         delta = - d / rval[rpiv];
+         /* compute new c[k] = c[k] + delta c[k], which is the limiting
+            value of the objective coefficient c[k] */
+         lim_coef = coef + delta;
+         /* let c[k] continue decreasing/increasing that makes d[q]
+            dual infeasible and forces x[q] to enter the basis;
+            to perform the primal ratio test we need to know in which
+            direction x[q] changes on entering the basis; we determine
+            that analyzing the sign of delta d[q] (see above), since
+            d[q] may be close to zero having wrong sign */
+         /* let, for simplicity, the problem is minimization */
+         if (kase < 0 && rval[rpiv] > 0.0 ||
+             kase > 0 && rval[rpiv] < 0.0)
+         {  /* delta d[q] < 0, so d[q] being non-negative will become
+               negative, so x[q] will increase */
+            dir = +1;
+         }
+         else
+         {  /* delta d[q] > 0, so d[q] being non-positive will become
+               positive, so x[q] will decrease */
+            dir = -1;
+         }
+         /* if the problem is maximization, correct the direction */
+         if (P->dir == GLP_MAX) dir = - dir;
+         /* check that we didn't make a silly mistake */
+         if (dir > 0)
+            xassert(stat == GLP_NL || stat == GLP_NF);
+         else
+            xassert(stat == GLP_NU || stat == GLP_NF);
+         /* compute column of the simplex table corresponding to the
+            non-basic variable x[q] */
+         clen = glp_eval_tab_col(P, q, cind, cval);
+         /* make x[k] temporarily free (unbounded) */
+         if (k <= m)
+         {  row = P->row[k];
+            row->type = GLP_FR;
+            row->lb = row->ub = 0.0;
+         }
+         else
+         {  col = P->col[k-m];
+            col->type = GLP_FR;
+            col->lb = col->ub = 0.0;
+         }
+         /* use the primal ratio test to determine some basic variable
+            which leaves the basis */
+         cpiv = glp_prim_rtest(P, clen, cind, cval, dir, 1e-9);
+         /* restore original bounds of the basic variable x[k] */
+         if (k <= m)
+         {  row = P->row[k];
+            row->type = type;
+            row->lb = lb, row->ub = ub;
+         }
+         else
+         {  col = P->col[k-m];
+            col->type = type;
+            col->lb = lb, col->ub = ub;
+         }
+         if (cpiv == 0)
+         {  /* non-basic variable x[q] can change unlimitedly */
+            if (dir < 0 && rval[rpiv] > 0.0 ||
+                dir > 0 && rval[rpiv] < 0.0)
+            {  /* delta x[k] = alfa[k,q] * delta x[q] < 0 */
+               new_x = -DBL_MAX;
+            }
+            else
+            {  /* delta x[k] = alfa[k,q] * delta x[q] > 0 */
+               new_x = +DBL_MAX;
+            }
+            goto store;
+         }
+         /* some basic variable x[p] limits changing non-basic variable
+            x[q] in the adjacent basis */
+         xassert(1 <= cpiv && cpiv <= clen);
+         p = cind[cpiv];
+         xassert(1 <= p && p <= m+n);
+         xassert(p != k);
+         if (p <= m)
+         {  row = P->row[p];
+            xassert(row->stat == GLP_BS);
+            ll = glp_get_row_lb(P, row->i);
+            uu = glp_get_row_ub(P, row->i);
+            xx = row->prim;
+         }
+         else
+         {  col = P->col[p-m];
+            xassert(col->stat == GLP_BS);
+            ll = glp_get_col_lb(P, col->j);
+            uu = glp_get_col_ub(P, col->j);
+            xx = col->prim;
+         }
+         /* determine delta x[p] = new x[p] - x[p] */
+         if (dir < 0 && cval[cpiv] > 0.0 ||
+             dir > 0 && cval[cpiv] < 0.0)
+         {  /* delta x[p] < 0, so x[p] goes toward its lower bound */
+            xassert(ll != -DBL_MAX);
+            delta = ll - xx;
+         }
+         else
+         {  /* delta x[p] > 0, so x[p] goes toward its upper bound */
+            xassert(uu != +DBL_MAX);
+            delta = uu - xx;
+         }
+         /* compute new x[k] = x[k] + alfa[k,q] * delta x[q], where
+            delta x[q] = delta x[p] / alfa[p,q] */
+         xassert(cval[cpiv] != 0.0);
+         new_x = x + (rval[rpiv] / cval[cpiv]) * delta;
+store:   /* store analysis results */
+         if (kase < 0)
+         {  if (coef1 != NULL) *coef1 = lim_coef;
+            if (var1 != NULL) *var1 = q;
+            if (value1 != NULL) *value1 = new_x;
+         }
+         else
+         {  if (coef2 != NULL) *coef2 = lim_coef;
+            if (var2 != NULL) *var2 = q;
+            if (value2 != NULL) *value2 = new_x;
+         }
+      }
+      /* free working arrays */
+      xfree(cind);
+      xfree(cval);
+      xfree(rind);
+      xfree(rval);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi13.c b/optional/glpk/glpapi13.c
new file mode 100644
index 0000000..d59a15e
--- /dev/null
+++ b/optional/glpk/glpapi13.c
@@ -0,0 +1,702 @@
+/* glpapi13.c (branch-and-bound interface routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_reason - determine reason for calling the callback routine
+*
+*  SYNOPSIS
+*
+*  glp_ios_reason(glp_tree *tree);
+*
+*  RETURNS
+*
+*  The routine glp_ios_reason returns a code, which indicates why the
+*  user-defined callback routine is being called. */
+
+int glp_ios_reason(glp_tree *tree)
+{     return
+         tree->reason;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_get_prob - access the problem object
+*
+*  SYNOPSIS
+*
+*  glp_prob *glp_ios_get_prob(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_get_prob can be called from the user-defined
+*  callback routine to access the problem object, which is used by the
+*  MIP solver. It is the original problem object passed to the routine
+*  glp_intopt if the MIP presolver is not used; otherwise it is an
+*  internal problem object built by the presolver. If the current
+*  subproblem exists, LP segment of the problem object corresponds to
+*  its LP relaxation.
+*
+*  RETURNS
+*
+*  The routine glp_ios_get_prob returns a pointer to the problem object
+*  used by the MIP solver. */
+
+glp_prob *glp_ios_get_prob(glp_tree *tree)
+{     return
+         tree->mip;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_tree_size - determine size of the branch-and-bound tree
+*
+*  SYNOPSIS
+*
+*  void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+*     int *t_cnt);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_tree_size stores the following three counts which
+*  characterize the current size of the branch-and-bound tree:
+*
+*  a_cnt is the current number of active nodes, i.e. the current size of
+*        the active list;
+*
+*  n_cnt is the current number of all (active and inactive) nodes;
+*
+*  t_cnt is the total number of nodes including those which have been
+*        already removed from the tree. This count is increased whenever
+*        a new node appears in the tree and never decreased.
+*
+*  If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the
+*  corresponding count is not stored. */
+
+void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+      int *t_cnt)
+{     if (a_cnt != NULL) *a_cnt = tree->a_cnt;
+      if (n_cnt != NULL) *n_cnt = tree->n_cnt;
+      if (t_cnt != NULL) *t_cnt = tree->t_cnt;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_curr_node - determine current active subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_curr_node(glp_tree *tree);
+*
+*  RETURNS
+*
+*  The routine glp_ios_curr_node returns the reference number of the
+*  current active subproblem. However, if the current subproblem does
+*  not exist, the routine returns zero. */
+
+int glp_ios_curr_node(glp_tree *tree)
+{     IOSNPD *node;
+      /* obtain pointer to the current subproblem */
+      node = tree->curr;
+      /* return its reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_next_node - determine next active subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_next_node(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  If the parameter p is zero, the routine glp_ios_next_node returns
+*  the reference number of the first active subproblem. However, if the
+*  tree is empty, zero is returned.
+*
+*  If the parameter p is not zero, it must specify the reference number
+*  of some active subproblem, in which case the routine returns the
+*  reference number of the next active subproblem. However, if there is
+*  no next active subproblem in the list, zero is returned.
+*
+*  All subproblems in the active list are ordered chronologically, i.e.
+*  subproblem A precedes subproblem B if A was created before B. */
+
+int glp_ios_next_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      if (p == 0)
+      {  /* obtain pointer to the first active subproblem */
+         node = tree->head;
+      }
+      else
+      {  /* obtain pointer to the specified subproblem */
+         if (!(1 <= p && p <= tree->nslots))
+err:        xerror("glp_ios_next_node: p = %d; invalid subproblem refer"
+               "ence number\n", p);
+         node = tree->slot[p].node;
+         if (node == NULL) goto err;
+         /* the specified subproblem must be active */
+         if (node->count != 0)
+            xerror("glp_ios_next_node: p = %d; subproblem not in the ac"
+               "tive list\n", p);
+         /* obtain pointer to the next active subproblem */
+         node = node->next;
+      }
+      /* return the reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_prev_node - determine previous active subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_prev_node(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  If the parameter p is zero, the routine glp_ios_prev_node returns
+*  the reference number of the last active subproblem. However, if the
+*  tree is empty, zero is returned.
+*
+*  If the parameter p is not zero, it must specify the reference number
+*  of some active subproblem, in which case the routine returns the
+*  reference number of the previous active subproblem. However, if there
+*  is no previous active subproblem in the list, zero is returned.
+*
+*  All subproblems in the active list are ordered chronologically, i.e.
+*  subproblem A precedes subproblem B if A was created before B. */
+
+int glp_ios_prev_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      if (p == 0)
+      {  /* obtain pointer to the last active subproblem */
+         node = tree->tail;
+      }
+      else
+      {  /* obtain pointer to the specified subproblem */
+         if (!(1 <= p && p <= tree->nslots))
+err:        xerror("glp_ios_prev_node: p = %d; invalid subproblem refer"
+               "ence number\n", p);
+         node = tree->slot[p].node;
+         if (node == NULL) goto err;
+         /* the specified subproblem must be active */
+         if (node->count != 0)
+            xerror("glp_ios_prev_node: p = %d; subproblem not in the ac"
+               "tive list\n", p);
+         /* obtain pointer to the previous active subproblem */
+         node = node->prev;
+      }
+      /* return the reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_up_node - determine parent subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_up_node(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  The parameter p must specify the reference number of some (active or
+*  inactive) subproblem, in which case the routine iet_get_up_node
+*  returns the reference number of its parent subproblem. However, if
+*  the specified subproblem is the root of the tree and, therefore, has
+*  no parent, the routine returns zero. */
+
+int glp_ios_up_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_up_node: p = %d; invalid subproblem reference "
+            "number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* obtain pointer to the parent subproblem */
+      node = node->up;
+      /* return the reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_node_level - determine subproblem level
+*
+*  SYNOPSIS
+*
+*  int glp_ios_node_level(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  The routine glp_ios_node_level returns the level of the subproblem,
+*  whose reference number is p, in the branch-and-bound tree. (The root
+*  subproblem has level 0, and the level of any other subproblem is the
+*  level of its parent plus one.) */
+
+int glp_ios_node_level(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
+            "ce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* return the node level */
+      return node->level;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_node_bound - determine subproblem local bound
+*
+*  SYNOPSIS
+*
+*  double glp_ios_node_bound(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  The routine glp_ios_node_bound returns the local bound for (active or
+*  inactive) subproblem, whose reference number is p.
+*
+*  COMMENTS
+*
+*  The local bound for subproblem p is an lower (minimization) or upper
+*  (maximization) bound for integer optimal solution to this subproblem
+*  (not to the original problem). This bound is local in the sense that
+*  only subproblems in the subtree rooted at node p cannot have better
+*  integer feasible solutions.
+*
+*  On creating a subproblem (due to the branching step) its local bound
+*  is inherited from its parent and then may get only stronger (never
+*  weaker). For the root subproblem its local bound is initially set to
+*  -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved
+*  as the root LP relaxation has been solved.
+*
+*  Note that the local bound is not necessarily the optimal objective
+*  value to corresponding LP relaxation; it may be stronger. */
+
+double glp_ios_node_bound(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_node_bound: p = %d; invalid subproblem referen"
+            "ce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* return the node local bound */
+      return node->bound;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_best_node - find active subproblem with best local bound
+*
+*  SYNOPSIS
+*
+*  int glp_ios_best_node(glp_tree *tree);
+*
+*  RETURNS
+*
+*  The routine glp_ios_best_node returns the reference number of the
+*  active subproblem, whose local bound is best (i.e. smallest in case
+*  of minimization or largest in case of maximization). However, if the
+*  tree is empty, the routine returns zero.
+*
+*  COMMENTS
+*
+*  The best local bound is an lower (minimization) or upper
+*  (maximization) bound for integer optimal solution to the original
+*  MIP problem. */
+
+int glp_ios_best_node(glp_tree *tree)
+{     return
+         ios_best_node(tree);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_mip_gap - compute relative MIP gap
+*
+*  SYNOPSIS
+*
+*  double glp_ios_mip_gap(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_mip_gap computes the relative MIP gap with the
+*  following formula:
+*
+*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
+*
+*  where best_mip is the best integer feasible solution found so far,
+*  best_bnd is the best (global) bound. If no integer feasible solution
+*  has been found yet, gap is set to DBL_MAX.
+*
+*  RETURNS
+*
+*  The routine glp_ios_mip_gap returns the relative MIP gap. */
+
+double glp_ios_mip_gap(glp_tree *tree)
+{     return
+         ios_relative_gap(tree);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_node_data - access subproblem application-specific data
+*
+*  SYNOPSIS
+*
+*  void *glp_ios_node_data(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_node_data allows the application accessing a
+*  memory block allocated for the subproblem (which may be active or
+*  inactive), whose reference number is p.
+*
+*  The size of the block is defined by the control parameter cb_size
+*  passed to the routine glp_intopt. The block is initialized by binary
+*  zeros on creating corresponding subproblem, and its contents is kept
+*  until the subproblem will be removed from the tree.
+*
+*  The application may use these memory blocks to store specific data
+*  for each subproblem.
+*
+*  RETURNS
+*
+*  The routine glp_ios_node_data returns a pointer to the memory block
+*  for the specified subproblem. Note that if cb_size = 0, the routine
+*  returns a null pointer. */
+
+void *glp_ios_node_data(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
+            "ce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* return pointer to the application-specific data */
+      return node->data;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_row_attr - retrieve additional row attributes
+*
+*  SYNOPSIS
+*
+*  void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_row_attr retrieves additional attributes of row
+*  i and stores them in the structure glp_attr. */
+
+void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr)
+{     GLPROW *row;
+      if (!(1 <= i && i <= tree->mip->m))
+         xerror("glp_ios_row_attr: i = %d; row number out of range\n",
+            i);
+      row = tree->mip->row[i];
+      attr->level = row->level;
+      attr->origin = row->origin;
+      attr->klass = row->klass;
+      return;
+}
+
+/**********************************************************************/
+
+int glp_ios_pool_size(glp_tree *tree)
+{     /* determine current size of the cut pool */
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_pool_size: operation not allowed\n");
+      xassert(tree->local != NULL);
+      return tree->local->size;
+}
+
+/**********************************************************************/
+
+int glp_ios_add_row(glp_tree *tree,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs)
+{     /* add row (constraint) to the cut pool */
+      int num;
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_add_row: operation not allowed\n");
+      xassert(tree->local != NULL);
+      num = ios_add_row(tree, tree->local, name, klass, flags, len,
+         ind, val, type, rhs);
+      return num;
+}
+
+/**********************************************************************/
+
+void glp_ios_del_row(glp_tree *tree, int i)
+{     /* remove row (constraint) from the cut pool */
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_del_row: operation not allowed\n");
+      ios_del_row(tree, tree->local, i);
+      return;
+}
+
+/**********************************************************************/
+
+void glp_ios_clear_pool(glp_tree *tree)
+{     /* remove all rows (constraints) from the cut pool */
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_clear_pool: operation not allowed\n");
+      ios_clear_pool(tree, tree->local);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_can_branch - check if can branch upon specified variable
+*
+*  SYNOPSIS
+*
+*  int glp_ios_can_branch(glp_tree *tree, int j);
+*
+*  RETURNS
+*
+*  If j-th variable (column) can be used to branch upon, the routine
+*  glp_ios_can_branch returns non-zero, otherwise zero. */
+
+int glp_ios_can_branch(glp_tree *tree, int j)
+{     if (!(1 <= j && j <= tree->mip->n))
+         xerror("glp_ios_can_branch: j = %d; column number out of range"
+            "\n", j);
+      return tree->non_int[j];
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_branch_upon - choose variable to branch upon
+*
+*  SYNOPSIS
+*
+*  void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_branch_upon can be called from the user-defined
+*  callback routine in response to the reason GLP_IBRANCH to choose a
+*  branching variable, whose ordinal number is j. Should note that only
+*  variables, for which the routine glp_ios_can_branch returns non-zero,
+*  can be used to branch upon.
+*
+*  The parameter sel is a flag that indicates which branch (subproblem)
+*  should be selected next to continue the search:
+*
+*  GLP_DN_BRNCH - select down-branch;
+*  GLP_UP_BRNCH - select up-branch;
+*  GLP_NO_BRNCH - use general selection technique. */
+
+void glp_ios_branch_upon(glp_tree *tree, int j, int sel)
+{     if (!(1 <= j && j <= tree->mip->n))
+         xerror("glp_ios_branch_upon: j = %d; column number out of rang"
+            "e\n", j);
+      if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH ||
+            sel == GLP_NO_BRNCH))
+         xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio"
+            "n flag\n", sel);
+      if (!(tree->non_int[j]))
+         xerror("glp_ios_branch_upon: j = %d; variable cannot be used t"
+            "o branch upon\n", j);
+      if (tree->br_var != 0)
+         xerror("glp_ios_branch_upon: branching variable already chosen"
+            "\n");
+      tree->br_var = j;
+      tree->br_sel = sel;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_select_node - select subproblem to continue the search
+*
+*  SYNOPSIS
+*
+*  void glp_ios_select_node(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_select_node can be called from the user-defined
+*  callback routine in response to the reason GLP_ISELECT to select an
+*  active subproblem, whose reference number is p. The search will be
+*  continued from the subproblem selected. */
+
+void glp_ios_select_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_select_node: p = %d; invalid subproblem refere"
+            "nce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* the specified subproblem must be active */
+      if (node->count != 0)
+         xerror("glp_ios_select_node: p = %d; subproblem not in the act"
+            "ive list\n", p);
+      /* no subproblem must be selected yet */
+      if (tree->next_p != 0)
+         xerror("glp_ios_select_node: subproblem already selected\n");
+      /* select the specified subproblem to continue the search */
+      tree->next_p = p;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_heur_sol - provide solution found by heuristic
+*
+*  SYNOPSIS
+*
+*  int glp_ios_heur_sol(glp_tree *tree, const double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_heur_sol can be called from the user-defined
+*  callback routine in response to the reason GLP_IHEUR to provide an
+*  integer feasible solution found by a primal heuristic.
+*
+*  Primal values of *all* variables (columns) found by the heuristic
+*  should be placed in locations x[1], ..., x[n], where n is the number
+*  of columns in the original problem object. Note that the routine
+*  glp_ios_heur_sol *does not* check primal feasibility of the solution
+*  provided.
+*
+*  Using the solution passed in the array x the routine computes value
+*  of the objective function. If the objective value is better than the
+*  best known integer feasible solution, the routine computes values of
+*  auxiliary variables (rows) and stores all solution components in the
+*  problem object.
+*
+*  RETURNS
+*
+*  If the provided solution is accepted, the routine glp_ios_heur_sol
+*  returns zero. Otherwise, if the provided solution is rejected, the
+*  routine returns non-zero. */
+
+int glp_ios_heur_sol(glp_tree *tree, const double x[])
+{     glp_prob *mip = tree->mip;
+      int m = tree->orig_m;
+      int n = tree->n;
+      int i, j;
+      double obj;
+      xassert(mip->m >= m);
+      xassert(mip->n == n);
+      /* check values of integer variables and compute value of the
+         objective function */
+      obj = mip->c0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         if (col->kind == GLP_IV)
+         {  /* provided value must be integral */
+            if (x[j] != floor(x[j])) return 1;
+         }
+         obj += col->coef * x[j];
+      }
+      /* check if the provided solution is better than the best known
+         integer feasible solution */
+      if (mip->mip_stat == GLP_FEAS)
+      {  switch (mip->dir)
+         {  case GLP_MIN:
+               if (obj >= tree->mip->mip_obj) return 1;
+               break;
+            case GLP_MAX:
+               if (obj <= tree->mip->mip_obj) return 1;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      /* it is better; store it in the problem object */
+      if (tree->parm->msg_lev >= GLP_MSG_ON)
+         xprintf("Solution found by heuristic: %.12g\n", obj);
+      mip->mip_stat = GLP_FEAS;
+      mip->mip_obj = obj;
+      for (j = 1; j <= n; j++)
+         mip->col[j]->mipx = x[j];
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = mip->row[i];
+         GLPAIJ *aij;
+         row->mipx = 0.0;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            row->mipx += aij->val * aij->col->mipx;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_terminate - terminate the solution process.
+*
+*  SYNOPSIS
+*
+*  void glp_ios_terminate(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_terminate sets a flag indicating that the MIP
+*  solver should prematurely terminate the search. */
+
+void glp_ios_terminate(glp_tree *tree)
+{     if (tree->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("The search is prematurely terminated due to applicati"
+            "on request\n");
+      tree->stop = 1;
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi14.c b/optional/glpk/glpapi14.c
new file mode 100644
index 0000000..698362d
--- /dev/null
+++ b/optional/glpk/glpapi14.c
@@ -0,0 +1,274 @@
+/* glpapi14.c (processing models in GNU MathProg language) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#define GLP_TRAN_DEFINED
+typedef struct MPL glp_tran;
+
+#include "glpmpl.h"
+#include "glpapi.h"
+
+glp_tran *glp_mpl_alloc_wksp(void)
+{     /* allocate the MathProg translator workspace */
+      glp_tran *tran;
+      tran = mpl_initialize();
+      return tran;
+}
+
+#if 1 /* 08/XII-2009 */
+void _glp_mpl_init_rand(glp_tran *tran, int seed)
+{     if (tran->phase != 0)
+         xerror("glp_mpl_init_rand: invalid call sequence\n");
+      rng_init_rand(tran->rand, seed);
+      return;
+}
+#endif
+
+int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip)
+{     /* read and translate model section */
+      int ret;
+      if (tran->phase != 0)
+         xerror("glp_mpl_read_model: invalid call sequence\n");
+      ret = mpl_read_model(tran, (char *)fname, skip);
+      if (ret == 1 || ret == 2)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+      else
+         xassert(ret != ret);
+      return ret;
+}
+
+int glp_mpl_read_data(glp_tran *tran, const char *fname)
+{     /* read and translate data section */
+      int ret;
+      if (!(tran->phase == 1 || tran->phase == 2))
+         xerror("glp_mpl_read_data: invalid call sequence\n");
+      ret = mpl_read_data(tran, (char *)fname);
+      if (ret == 2)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+      else
+         xassert(ret != ret);
+      return ret;
+}
+
+int glp_mpl_generate(glp_tran *tran, const char *fname)
+{     /* generate the model */
+      int ret;
+      if (!(tran->phase == 1 || tran->phase == 2))
+         xerror("glp_mpl_generate: invalid call sequence\n");
+      ret = mpl_generate(tran, (char *)fname);
+      if (ret == 3)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+      return ret;
+}
+
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob)
+{     /* build LP/MIP problem instance from the model */
+      int m, n, i, j, t, kind, type, len, *ind;
+      double lb, ub, *val;
+      if (tran->phase != 3)
+         xerror("glp_mpl_build_prob: invalid call sequence\n");
+      /* erase the problem object */
+      glp_erase_prob(prob);
+      /* set problem name */
+      glp_set_prob_name(prob, mpl_get_prob_name(tran));
+      /* build rows (constraints) */
+      m = mpl_get_num_rows(tran);
+      if (m > 0)
+         glp_add_rows(prob, m);
+      for (i = 1; i <= m; i++)
+      {  /* set row name */
+         glp_set_row_name(prob, i, mpl_get_row_name(tran, i));
+         /* set row bounds */
+         type = mpl_get_row_bnds(tran, i, &lb, &ub);
+         switch (type)
+         {  case MPL_FR: type = GLP_FR; break;
+            case MPL_LO: type = GLP_LO; break;
+            case MPL_UP: type = GLP_UP; break;
+            case MPL_DB: type = GLP_DB; break;
+            case MPL_FX: type = GLP_FX; break;
+            default: xassert(type != type);
+         }
+         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
+         {  type = GLP_FX;
+            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
+         }
+         glp_set_row_bnds(prob, i, type, lb, ub);
+         /* warn about non-zero constant term */
+         if (mpl_get_row_c0(tran, i) != 0.0)
+            xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig"
+               "nored\n",
+               mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i));
+      }
+      /* build columns (variables) */
+      n = mpl_get_num_cols(tran);
+      if (n > 0)
+         glp_add_cols(prob, n);
+      for (j = 1; j <= n; j++)
+      {  /* set column name */
+         glp_set_col_name(prob, j, mpl_get_col_name(tran, j));
+         /* set column kind */
+         kind = mpl_get_col_kind(tran, j);
+         switch (kind)
+         {  case MPL_NUM:
+               break;
+            case MPL_INT:
+            case MPL_BIN:
+               glp_set_col_kind(prob, j, GLP_IV);
+               break;
+            default:
+               xassert(kind != kind);
+         }
+         /* set column bounds */
+         type = mpl_get_col_bnds(tran, j, &lb, &ub);
+         switch (type)
+         {  case MPL_FR: type = GLP_FR; break;
+            case MPL_LO: type = GLP_LO; break;
+            case MPL_UP: type = GLP_UP; break;
+            case MPL_DB: type = GLP_DB; break;
+            case MPL_FX: type = GLP_FX; break;
+            default: xassert(type != type);
+         }
+         if (kind == MPL_BIN)
+         {  if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0;
+            if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0;
+            type = GLP_DB;
+         }
+         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
+         {  type = GLP_FX;
+            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
+         }
+         glp_set_col_bnds(prob, j, type, lb, ub);
+      }
+      /* load the constraint matrix */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  len = mpl_get_mat_row(tran, i, ind, val);
+         glp_set_mat_row(prob, i, len, ind, val);
+      }
+      /* build objective function (the first objective is used) */
+      for (i = 1; i <= m; i++)
+      {  kind = mpl_get_row_kind(tran, i);
+         if (kind == MPL_MIN || kind == MPL_MAX)
+         {  /* set objective name */
+            glp_set_obj_name(prob, mpl_get_row_name(tran, i));
+            /* set optimization direction */
+            glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX);
+            /* set constant term */
+            glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i));
+            /* set objective coefficients */
+            len = mpl_get_mat_row(tran, i, ind, val);
+            for (t = 1; t <= len; t++)
+               glp_set_obj_coef(prob, ind[t], val[t]);
+            break;
+         }
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol)
+{     /* postsolve the model */
+      int i, j, m, n, stat, ret;
+      double prim, dual;
+      if (!(tran->phase == 3 && !tran->flag_p))
+         xerror("glp_mpl_postsolve: invalid call sequence\n");
+      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+         xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n",
+            sol);
+      m = mpl_get_num_rows(tran);
+      n = mpl_get_num_cols(tran);
+      if (!(m == glp_get_num_rows(prob) &&
+            n == glp_get_num_cols(prob)))
+         xerror("glp_mpl_postsolve: wrong problem object\n");
+      if (!mpl_has_solve_stmt(tran))
+      {  ret = 0;
+         goto done;
+      }
+      for (i = 1; i <= m; i++)
+      {  if (sol == GLP_SOL)
+         {  stat = glp_get_row_stat(prob, i);
+            prim = glp_get_row_prim(prob, i);
+            dual = glp_get_row_dual(prob, i);
+         }
+         else if (sol == GLP_IPT)
+         {  stat = 0;
+            prim = glp_ipt_row_prim(prob, i);
+            dual = glp_ipt_row_dual(prob, i);
+         }
+         else if (sol == GLP_MIP)
+         {  stat = 0;
+            prim = glp_mip_row_val(prob, i);
+            dual = 0.0;
+         }
+         else
+            xassert(sol != sol);
+         if (fabs(prim) < 1e-9) prim = 0.0;
+         if (fabs(dual) < 1e-9) dual = 0.0;
+         mpl_put_row_soln(tran, i, stat, prim, dual);
+      }
+      for (j = 1; j <= n; j++)
+      {  if (sol == GLP_SOL)
+         {  stat = glp_get_col_stat(prob, j);
+            prim = glp_get_col_prim(prob, j);
+            dual = glp_get_col_dual(prob, j);
+         }
+         else if (sol == GLP_IPT)
+         {  stat = 0;
+            prim = glp_ipt_col_prim(prob, j);
+            dual = glp_ipt_col_dual(prob, j);
+         }
+         else if (sol == GLP_MIP)
+         {  stat = 0;
+            prim = glp_mip_col_val(prob, j);
+            dual = 0.0;
+         }
+         else
+            xassert(sol != sol);
+         if (fabs(prim) < 1e-9) prim = 0.0;
+         if (fabs(dual) < 1e-9) dual = 0.0;
+         mpl_put_col_soln(tran, j, stat, prim, dual);
+      }
+      ret = mpl_postsolve(tran);
+      if (ret == 3)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+done: return ret;
+}
+
+void glp_mpl_free_wksp(glp_tran *tran)
+{     /* free the MathProg translator workspace */
+      mpl_terminate(tran);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi15.c b/optional/glpk/glpapi15.c
new file mode 100644
index 0000000..0f1da47
--- /dev/null
+++ b/optional/glpk/glpapi15.c
@@ -0,0 +1,614 @@
+/* glpapi15.c (basic graph and network routines) */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glpapi.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
+
+#define NV_MAX 100000000 /* = 100*10^6 */
+/* maximal number of vertices in the graph */
+
+#define NA_MAX 500000000 /* = 500*10^6 */
+/* maximal number of arcs in the graph */
+
+/***********************************************************************
+*  NAME
+*
+*  glp_create_graph - create graph
+*
+*  SYNOPSIS
+*
+*  glp_graph *glp_create_graph(int v_size, int a_size);
+*
+*  DESCRIPTION
+*
+*  The routine creates a new graph, which initially is empty, i.e. has
+*  no vertices and arcs.
+*
+*  The parameter v_size specifies the size of data associated with each
+*  vertex of the graph (0 to 256 bytes).
+*
+*  The parameter a_size specifies the size of data associated with each
+*  arc of the graph (0 to 256 bytes).
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the graph created. */
+
+static void create_graph(glp_graph *G, int v_size, int a_size)
+{     G->pool = dmp_create_pool();
+      G->name = NULL;
+      G->nv_max = 50;
+      G->nv = G->na = 0;
+      G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
+      G->index = NULL;
+      G->v_size = v_size;
+      G->a_size = a_size;
+      return;
+}
+
+glp_graph *glp_create_graph(int v_size, int a_size)
+{     glp_graph *G;
+      if (!(0 <= v_size && v_size <= 256))
+         xerror("glp_create_graph: v_size = %d; invalid size of vertex "
+            "data\n", v_size);
+      if (!(0 <= a_size && a_size <= 256))
+         xerror("glp_create_graph: a_size = %d; invalid size of arc dat"
+            "a\n", a_size);
+      G = xmalloc(sizeof(glp_graph));
+      create_graph(G, v_size, a_size);
+      return G;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_graph_name - assign (change) graph name
+*
+*  SYNOPSIS
+*
+*  void glp_set_graph_name(glp_graph *G, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_graph_name assigns a symbolic name specified by
+*  the character string name (1 to 255 chars) to the graph.
+*
+*  If the parameter name is NULL or an empty string, the routine erases
+*  the existing symbolic name of the graph. */
+
+void glp_set_graph_name(glp_graph *G, const char *name)
+{     if (G->name != NULL)
+      {  dmp_free_atom(G->pool, G->name, strlen(G->name)+1);
+         G->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int j;
+         for (j = 0; name[j] != '\0'; j++)
+         {  if (j == 256)
+               xerror("glp_set_graph_name: graph name too long\n");
+            if (iscntrl((unsigned char)name[j]))
+               xerror("glp_set_graph_name: graph name contains invalid "
+                  "character(s)\n");
+         }
+         G->name = dmp_get_atom(G->pool, strlen(name)+1);
+         strcpy(G->name, name);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_vertices - add new vertices to graph
+*
+*  SYNOPSIS
+*
+*  int glp_add_vertices(glp_graph *G, int nadd);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_vertices adds nadd vertices to the specified
+*  graph. New vertices are always added to the end of the vertex list,
+*  so ordinal numbers of existing vertices remain unchanged.
+*
+*  Being added each new vertex is isolated (has no incident arcs).
+*
+*  RETURNS
+*
+*  The routine glp_add_vertices returns an ordinal number of the first
+*  new vertex added to the graph. */
+
+int glp_add_vertices(glp_graph *G, int nadd)
+{     int i, nv_new;
+      if (nadd < 1)
+         xerror("glp_add_vertices: nadd = %d; invalid number of vertice"
+            "s\n", nadd);
+      if (nadd > NV_MAX - G->nv)
+         xerror("glp_add_vertices: nadd = %d; too many vertices\n",
+            nadd);
+      /* determine new number of vertices */
+      nv_new = G->nv + nadd;
+      /* increase the room, if necessary */
+      if (G->nv_max < nv_new)
+      {  glp_vertex **save = G->v;
+         while (G->nv_max < nv_new)
+         {  G->nv_max += G->nv_max;
+            xassert(G->nv_max > 0);
+         }
+         G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
+         memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *));
+         xfree(save);
+      }
+      /* add new vertices to the end of the vertex list */
+      for (i = G->nv+1; i <= nv_new; i++)
+      {  glp_vertex *v;
+         G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex));
+         v->i = i;
+         v->name = NULL;
+         v->entry = NULL;
+         if (G->v_size == 0)
+            v->data = NULL;
+         else
+         {  v->data = dmp_get_atom(G->pool, G->v_size);
+            memset(v->data, 0, G->v_size);
+         }
+         v->temp = NULL;
+         v->in = v->out = NULL;
+      }
+      /* set new number of vertices */
+      G->nv = nv_new;
+      /* return the ordinal number of the first vertex added */
+      return nv_new - nadd + 1;
+}
+
+/**********************************************************************/
+
+void glp_set_vertex_name(glp_graph *G, int i, const char *name)
+{     /* assign (change) vertex name */
+      glp_vertex *v;
+      if (!(1 <= i && i <= G->nv))
+         xerror("glp_set_vertex_name: i = %d; vertex number out of rang"
+            "e\n", i);
+      v = G->v[i];
+      if (v->name != NULL)
+      {  if (v->entry != NULL)
+         {  xassert(G->index != NULL);
+            avl_delete_node(G->index, v->entry);
+            v->entry = NULL;
+         }
+         dmp_free_atom(G->pool, v->name, strlen(v->name)+1);
+         v->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_vertex_name: i = %d; vertex name too lon"
+                  "g\n", i);
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_vertex_name: i = %d; vertex name contain"
+                  "s invalid character(s)\n", i);
+         }
+         v->name = dmp_get_atom(G->pool, strlen(name)+1);
+         strcpy(v->name, name);
+         if (G->index != NULL)
+         {  xassert(v->entry == NULL);
+            v->entry = avl_insert_node(G->index, v->name);
+            avl_set_node_link(v->entry, v);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_arc - add new arc to graph
+*
+*  SYNOPSIS
+*
+*  glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_arc adds a new arc to the specified graph.
+*
+*  The parameters i and j specify the ordinal numbers of, resp., tail
+*  and head vertices of the arc. Note that self-loops and multiple arcs
+*  are allowed.
+*
+*  RETURNS
+*
+*  The routine glp_add_arc returns a pointer to the arc added. */
+
+glp_arc *glp_add_arc(glp_graph *G, int i, int j)
+{     glp_arc *a;
+      if (!(1 <= i && i <= G->nv))
+         xerror("glp_add_arc: i = %d; tail vertex number out of range\n"
+            , i);
+      if (!(1 <= j && j <= G->nv))
+         xerror("glp_add_arc: j = %d; head vertex number out of range\n"
+            , j);
+      if (G->na == NA_MAX)
+         xerror("glp_add_arc: too many arcs\n");
+      a = dmp_get_atom(G->pool, sizeof(glp_arc));
+      a->tail = G->v[i];
+      a->head = G->v[j];
+      if (G->a_size == 0)
+         a->data = NULL;
+      else
+      {  a->data = dmp_get_atom(G->pool, G->a_size);
+         memset(a->data, 0, G->a_size);
+      }
+      a->temp = NULL;
+      a->t_prev = NULL;
+      a->t_next = G->v[i]->out;
+      if (a->t_next != NULL) a->t_next->t_prev = a;
+      a->h_prev = NULL;
+      a->h_next = G->v[j]->in;
+      if (a->h_next != NULL) a->h_next->h_prev = a;
+      G->v[i]->out = G->v[j]->in = a;
+      G->na++;
+      return a;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_vertices - delete vertices from graph
+*
+*  SYNOPSIS
+*
+*  void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_vertices deletes vertices along with all
+*  incident arcs from the specified graph. Ordinal numbers of vertices
+*  to be deleted should be placed in locations num[1], ..., num[ndel],
+*  ndel > 0.
+*
+*  Note that deleting vertices involves changing ordinal numbers of
+*  other vertices remaining in the graph. New ordinal numbers of the
+*  remaining vertices are assigned under the assumption that the
+*  original order of vertices is not changed. */
+
+void glp_del_vertices(glp_graph *G, int ndel, const int num[])
+{     glp_vertex *v;
+      int i, k, nv_new;
+      /* scan the list of vertices to be deleted */
+      if (!(1 <= ndel && ndel <= G->nv))
+         xerror("glp_del_vertices: ndel = %d; invalid number of vertice"
+            "s\n", ndel);
+      for (k = 1; k <= ndel; k++)
+      {  /* take the number of vertex to be deleted */
+         i = num[k];
+         /* obtain pointer to i-th vertex */
+         if (!(1 <= i && i <= G->nv))
+            xerror("glp_del_vertices: num[%d] = %d; vertex number out o"
+               "f range\n", k, i);
+         v = G->v[i];
+         /* check that the vertex is not marked yet */
+         if (v->i == 0)
+            xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu"
+               "mbers not allowed\n", k, i);
+         /* erase symbolic name assigned to the vertex */
+         glp_set_vertex_name(G, i, NULL);
+         xassert(v->name == NULL);
+         xassert(v->entry == NULL);
+         /* free vertex data, if allocated */
+         if (v->data != NULL)
+            dmp_free_atom(G->pool, v->data, G->v_size);
+         /* delete all incoming arcs */
+         while (v->in != NULL)
+            glp_del_arc(G, v->in);
+         /* delete all outgoing arcs */
+         while (v->out != NULL)
+            glp_del_arc(G, v->out);
+         /* mark the vertex to be deleted */
+         v->i = 0;
+      }
+      /* delete all marked vertices from the vertex list */
+      nv_new = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  /* obtain pointer to i-th vertex */
+         v = G->v[i];
+         /* check if the vertex is marked */
+         if (v->i == 0)
+         {  /* it is marked, delete it */
+            dmp_free_atom(G->pool, v, sizeof(glp_vertex));
+         }
+         else
+         {  /* it is not marked, keep it */
+            v->i = ++nv_new;
+            G->v[v->i] = v;
+         }
+      }
+      /* set new number of vertices in the graph */
+      G->nv = nv_new;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_arc - delete arc from graph
+*
+*  SYNOPSIS
+*
+*  void glp_del_arc(glp_graph *G, glp_arc *a);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_arc deletes an arc from the specified graph.
+*  The arc to be deleted must exist. */
+
+void glp_del_arc(glp_graph *G, glp_arc *a)
+{     /* some sanity checks */
+      xassert(G->na > 0);
+      xassert(1 <= a->tail->i && a->tail->i <= G->nv);
+      xassert(a->tail == G->v[a->tail->i]);
+      xassert(1 <= a->head->i && a->head->i <= G->nv);
+      xassert(a->head == G->v[a->head->i]);
+      /* remove the arc from the list of incoming arcs */
+      if (a->h_prev == NULL)
+         a->head->in = a->h_next;
+      else
+         a->h_prev->h_next = a->h_next;
+      if (a->h_next == NULL)
+         ;
+      else
+         a->h_next->h_prev = a->h_prev;
+      /* remove the arc from the list of outgoing arcs */
+      if (a->t_prev == NULL)
+         a->tail->out = a->t_next;
+      else
+         a->t_prev->t_next = a->t_next;
+      if (a->t_next == NULL)
+         ;
+      else
+         a->t_next->t_prev = a->t_prev;
+      /* free arc data, if allocated */
+      if (a->data != NULL)
+         dmp_free_atom(G->pool, a->data, G->a_size);
+      /* delete the arc from the graph */
+      dmp_free_atom(G->pool, a, sizeof(glp_arc));
+      G->na--;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_erase_graph - erase graph content
+*
+*  SYNOPSIS
+*
+*  void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+*
+*  DESCRIPTION
+*
+*  The routine glp_erase_graph erases the content of the specified
+*  graph. The effect of this operation is the same as if the graph
+*  would be deleted with the routine glp_delete_graph and then created
+*  anew with the routine glp_create_graph, with exception that the
+*  handle (pointer) to the graph remains valid. */
+
+static void delete_graph(glp_graph *G)
+{     dmp_delete_pool(G->pool);
+      xfree(G->v);
+      if (G->index != NULL) avl_delete_tree(G->index);
+      return;
+}
+
+void glp_erase_graph(glp_graph *G, int v_size, int a_size)
+{     if (!(0 <= v_size && v_size <= 256))
+         xerror("glp_erase_graph: v_size = %d; invalid size of vertex d"
+            "ata\n", v_size);
+      if (!(0 <= a_size && a_size <= 256))
+         xerror("glp_erase_graph: a_size = %d; invalid size of arc data"
+            "\n", a_size);
+      delete_graph(G);
+      create_graph(G, v_size, a_size);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_delete_graph - delete graph
+*
+*  SYNOPSIS
+*
+*  void glp_delete_graph(glp_graph *G);
+*
+*  DESCRIPTION
+*
+*  The routine glp_delete_graph deletes the specified graph and frees
+*  all the memory allocated to this program object. */
+
+void glp_delete_graph(glp_graph *G)
+{     delete_graph(G);
+      xfree(G);
+      return;
+}
+
+/**********************************************************************/
+
+void glp_create_v_index(glp_graph *G)
+{     /* create vertex name index */
+      glp_vertex *v;
+      int i;
+      if (G->index == NULL)
+      {  G->index = avl_create_tree(avl_strcmp, NULL);
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            xassert(v->entry == NULL);
+            if (v->name != NULL)
+            {  v->entry = avl_insert_node(G->index, v->name);
+               avl_set_node_link(v->entry, v);
+            }
+         }
+      }
+      return;
+}
+
+int glp_find_vertex(glp_graph *G, const char *name)
+{     /* find vertex by its name */
+      AVLNODE *node;
+      int i = 0;
+      if (G->index == NULL)
+         xerror("glp_find_vertex: vertex name index does not exist\n");
+      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+      {  node = avl_find_node(G->index, name);
+         if (node != NULL)
+            i = ((glp_vertex *)avl_get_node_link(node))->i;
+      }
+      return i;
+}
+
+void glp_delete_v_index(glp_graph *G)
+{     /* delete vertex name index */
+      int i;
+      if (G->index != NULL)
+      {  avl_delete_tree(G->index), G->index = NULL;
+         for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_graph - read graph from plain text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_graph(glp_graph *G, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_graph reads a graph from a plain text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_graph(glp_graph *G, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int nv, na, i, j, k, ret;
+      glp_erase_graph(G, G->v_size, G->a_size);
+      xprintf("Reading graph from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      nv = glp_sdf_read_int(data);
+      if (nv < 0)
+         glp_sdf_error(data, "invalid number of vertices\n");
+      na = glp_sdf_read_int(data);
+      if (na < 0)
+         glp_sdf_error(data, "invalid number of arcs\n");
+      xprintf("Graph has %d vert%s and %d arc%s\n",
+         nv, nv == 1 ? "ex" : "ices", na, na == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      for (k = 1; k <= na; k++)
+      {  i = glp_sdf_read_int(data);
+         if (!(1 <= i && i <= nv))
+            glp_sdf_error(data, "tail vertex number out of range\n");
+         j = glp_sdf_read_int(data);
+         if (!(1 <= j && j <= nv))
+            glp_sdf_error(data, "head vertex number out of range\n");
+         glp_add_arc(G, i, j);
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+      ret = 0;
+done: if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_graph - write graph to plain text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_graph(glp_graph *G, const char *fname).
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_graph writes the specified graph to a plain
+*  text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_graph(glp_graph *G, const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, count, ret;
+      xprintf("Writing graph to `%s'...\n", fname);
+      fp = xfopen(fname, "w"), count = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%d %d\n", G->nv, G->na), count++;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+            xfprintf(fp, "%d %d\n", a->tail->i, a->head->i), count++;
+      }
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi16.c b/optional/glpk/glpapi16.c
new file mode 100644
index 0000000..4b5030d
--- /dev/null
+++ b/optional/glpk/glpapi16.c
@@ -0,0 +1,329 @@
+/* glpapi16.c (graph and network analysis routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_weak_comp - find all weakly connected components of graph
+*
+*  SYNOPSIS
+*
+*  int glp_weak_comp(glp_graph *G, int v_num);
+*
+*  DESCRIPTION
+*
+*  The routine glp_weak_comp finds all weakly connected components of
+*  the specified graph.
+*
+*  The parameter v_num specifies an offset of the field of type int
+*  in the vertex data block, to which the routine stores the number of
+*  a (weakly) connected component containing that vertex. If v_num < 0,
+*  no component numbers are stored.
+*
+*  The components are numbered in arbitrary order from 1 to nc, where
+*  nc is the total number of components found, 0 <= nc <= |V|.
+*
+*  RETURNS
+*
+*  The routine returns nc, the total number of components found. */
+
+int glp_weak_comp(glp_graph *G, int v_num)
+{     glp_vertex *v;
+      glp_arc *a;
+      int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
+      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+         xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
+      nv = G->nv;
+      if (nv == 0)
+      {  nc = 0;
+         goto done;
+      }
+      /* allocate working arrays */
+      prev = xcalloc(1+nv, sizeof(int));
+      next = xcalloc(1+nv, sizeof(int));
+      list = xcalloc(1+nv, sizeof(int));
+      /* if vertex i is unlabelled, prev[i] is the index of previous
+         unlabelled vertex, and next[i] is the index of next unlabelled
+         vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
+         is the connected component number */
+      /* initially all vertices are unlabelled */
+      f = 1;
+      for (i = 1; i <= nv; i++)
+         prev[i] = i - 1, next[i] = i + 1;
+      next[nv] = 0;
+      /* main loop (until all vertices have been labelled) */
+      nc = 0;
+      while (f != 0)
+      {  /* take an unlabelled vertex */
+         i = f;
+         /* and remove it from the list of unlabelled vertices */
+         f = next[i];
+         if (f != 0) prev[f] = 0;
+         /* label the vertex; it begins a new component */
+         prev[i] = -1, next[i] = ++nc;
+         /* breadth first search */
+         list[1] = i, pos1 = pos2 = 1;
+         while (pos1 <= pos2)
+         {  /* dequeue vertex i */
+            i = list[pos1++];
+            /* consider all arcs incoming to vertex i */
+            for (a = G->v[i]->in; a != NULL; a = a->h_next)
+            {  /* vertex j is adjacent to vertex i */
+               j = a->tail->i;
+               if (prev[j] >= 0)
+               {  /* vertex j is unlabelled */
+                  /* remove it from the list of unlabelled vertices */
+                  if (prev[j] == 0)
+                     f = next[j];
+                  else
+                     next[prev[j]] = next[j];
+                  if (next[j] == 0)
+                     ;
+                  else
+                     prev[next[j]] = prev[j];
+                  /* label the vertex */
+                  prev[j] = -1, next[j] = nc;
+                  /* and enqueue it for further consideration */
+                  list[++pos2] = j;
+               }
+            }
+            /* consider all arcs outgoing from vertex i */
+            for (a = G->v[i]->out; a != NULL; a = a->t_next)
+            {  /* vertex j is adjacent to vertex i */
+               j = a->head->i;
+               if (prev[j] >= 0)
+               {  /* vertex j is unlabelled */
+                  /* remove it from the list of unlabelled vertices */
+                  if (prev[j] == 0)
+                     f = next[j];
+                  else
+                     next[prev[j]] = next[j];
+                  if (next[j] == 0)
+                     ;
+                  else
+                     prev[next[j]] = prev[j];
+                  /* label the vertex */
+                  prev[j] = -1, next[j] = nc;
+                  /* and enqueue it for further consideration */
+                  list[++pos2] = j;
+               }
+            }
+         }
+      }
+      /* store component numbers */
+      if (v_num >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_num, &next[i], sizeof(int));
+         }
+      }
+      /* free working arrays */
+      xfree(prev);
+      xfree(next);
+      xfree(list);
+done: return nc;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_strong_comp - find all strongly connected components of graph
+*
+*  SYNOPSIS
+*
+*  int glp_strong_comp(glp_graph *G, int v_num);
+*
+*  DESCRIPTION
+*
+*  The routine glp_strong_comp finds all strongly connected components
+*  of the specified graph.
+*
+*  The parameter v_num specifies an offset of the field of type int
+*  in the vertex data block, to which the routine stores the number of
+*  a strongly connected component containing that vertex. If v_num < 0,
+*  no component numbers are stored.
+*
+*  The components are numbered in arbitrary order from 1 to nc, where
+*  nc is the total number of components found, 0 <= nc <= |V|. However,
+*  the component numbering has the property that for every arc (i->j)
+*  in the graph the condition num(i) >= num(j) holds.
+*
+*  RETURNS
+*
+*  The routine returns nc, the total number of components found. */
+
+int glp_strong_comp(glp_graph *G, int v_num)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
+         *numb, *prev;
+      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+         xerror("glp_strong_comp: v_num = %d; invalid offset\n",
+            v_num);
+      n = G->nv;
+      if (n == 0)
+      {  nc = 0;
+         goto done;
+      }
+      na = G->na;
+      icn = xcalloc(1+na, sizeof(int));
+      ip = xcalloc(1+n, sizeof(int));
+      lenr = xcalloc(1+n, sizeof(int));
+      ior = xcalloc(1+n, sizeof(int));
+      ib = xcalloc(1+n, sizeof(int));
+      lowl = xcalloc(1+n, sizeof(int));
+      numb = xcalloc(1+n, sizeof(int));
+      prev = xcalloc(1+n, sizeof(int));
+      k = 1;
+      for (i = 1; i <= n; i++)
+      {  v = G->v[i];
+         ip[i] = k;
+         for (a = v->out; a != NULL; a = a->t_next)
+            icn[k++] = a->head->i;
+         lenr[i] = k - ip[i];
+      }
+      xassert(na == k-1);
+      nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
+      if (v_num >= 0)
+      {  xassert(ib[1] == 1);
+         for (k = 1; k <= nc; k++)
+         {  last = (k < nc ? ib[k+1] : n+1);
+            xassert(ib[k] < last);
+            for (i = ib[k]; i < last; i++)
+            {  v = G->v[ior[i]];
+               memcpy((char *)v->data + v_num, &k, sizeof(int));
+            }
+         }
+      }
+      xfree(icn);
+      xfree(ip);
+      xfree(lenr);
+      xfree(ior);
+      xfree(ib);
+      xfree(lowl);
+      xfree(numb);
+      xfree(prev);
+done: return nc;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_top_sort - topological sorting of acyclic digraph
+*
+*  SYNOPSIS
+*
+*  int glp_top_sort(glp_graph *G, int v_num);
+*
+*  DESCRIPTION
+*
+*  The routine glp_top_sort performs topological sorting of vertices of
+*  the specified acyclic digraph.
+*
+*  The parameter v_num specifies an offset of the field of type int in
+*  the vertex data block, to which the routine stores the vertex number
+*  assigned. If v_num < 0, vertex numbers are not stored.
+*
+*  The vertices are numbered from 1 to n, where n is the total number
+*  of vertices in the graph. The vertex numbering has the property that
+*  for every arc (i->j) in the graph the condition num(i) < num(j)
+*  holds. Special case num(i) = 0 means that vertex i is not assigned a
+*  number, because the graph is *not* acyclic.
+*
+*  RETURNS
+*
+*  If the graph is acyclic and therefore all the vertices have been
+*  assigned numbers, the routine glp_top_sort returns zero. Otherwise,
+*  if the graph is not acyclic, the routine returns the number of
+*  vertices which have not been numbered, i.e. for which num(i) = 0. */
+
+static int top_sort(glp_graph *G, int num[])
+{     glp_arc *a;
+      int i, j, cnt, top, *stack, *indeg;
+      /* allocate working arrays */
+      indeg = xcalloc(1+G->nv, sizeof(int));
+      stack = xcalloc(1+G->nv, sizeof(int));
+      /* determine initial indegree of each vertex; push into the stack
+         the vertices having zero indegree */
+      top = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  num[i] = indeg[i] = 0;
+         for (a = G->v[i]->in; a != NULL; a = a->h_next)
+            indeg[i]++;
+         if (indeg[i] == 0)
+            stack[++top] = i;
+      }
+      /* assign numbers to vertices in the sorted order */
+      cnt = 0;
+      while (top > 0)
+      {  /* pull vertex i from the stack */
+         i = stack[top--];
+         /* it has zero indegree in the current graph */
+         xassert(indeg[i] == 0);
+         /* so assign it a next number */
+         xassert(num[i] == 0);
+         num[i] = ++cnt;
+         /* remove vertex i from the current graph, update indegree of
+            its adjacent vertices, and push into the stack new vertices
+            whose indegree becomes zero */
+         for (a = G->v[i]->out; a != NULL; a = a->t_next)
+         {  j = a->head->i;
+            /* there exists arc (i->j) in the graph */
+            xassert(indeg[j] > 0);
+            indeg[j]--;
+            if (indeg[j] == 0)
+               stack[++top] = j;
+         }
+      }
+      /* free working arrays */
+      xfree(indeg);
+      xfree(stack);
+      return G->nv - cnt;
+}
+
+int glp_top_sort(glp_graph *G, int v_num)
+{     glp_vertex *v;
+      int i, cnt, *num;
+      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+         xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
+      if (G->nv == 0)
+      {  cnt = 0;
+         goto done;
+      }
+      num = xcalloc(1+G->nv, sizeof(int));
+      cnt = top_sort(G, num);
+      if (v_num >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_num, &num[i], sizeof(int));
+         }
+      }
+      xfree(num);
+done: return cnt;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi17.c b/optional/glpk/glpapi17.c
new file mode 100644
index 0000000..d83fb56
--- /dev/null
+++ b/optional/glpk/glpapi17.c
@@ -0,0 +1,1048 @@
+/* glpapi17.c (flow network problems) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mincost_lp - convert minimum cost flow problem to LP
+*
+*  SYNOPSIS
+*
+*  void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
+*     int v_rhs, int a_low, int a_cap, int a_cost);
+*
+*  DESCRIPTION
+*
+*  The routine glp_mincost_lp builds an LP problem, which corresponds
+*  to the minimum cost flow problem on the specified network G. */
+
+void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs,
+      int a_low, int a_cap, int a_cost)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, type, ind[1+2];
+      double rhs, low, cap, cost, val[1+2];
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_mincost_lp: names = %d; invalid parameter\n",
+            names);
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost)
+            ;
+      glp_erase_prob(lp);
+      if (names) glp_set_prob_name(lp, G->name);
+      if (G->nv > 0) glp_add_rows(lp, G->nv);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (names) glp_set_row_name(lp, i, v->name);
+         if (v_rhs >= 0)
+            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+         else
+            rhs = 0.0;
+         glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs);
+      }
+      if (G->na > 0) glp_add_cols(lp, G->na);
+      for (i = 1, j = 0; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  j++;
+            if (names)
+            {  char name[50+1];
+               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+               xassert(strlen(name) < sizeof(name));
+               glp_set_col_name(lp, j, name);
+            }
+            if (a->tail->i != a->head->i)
+            {  ind[1] = a->tail->i, val[1] = +1.0;
+               ind[2] = a->head->i, val[2] = -1.0;
+               glp_set_mat_col(lp, j, 2, ind, val);
+            }
+            if (a_low >= 0)
+               memcpy(&low, (char *)a->data + a_low, sizeof(double));
+            else
+               low = 0.0;
+            if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            if (cap == DBL_MAX)
+               type = GLP_LO;
+            else if (low != cap)
+               type = GLP_DB;
+            else
+               type = GLP_FX;
+            glp_set_col_bnds(lp, j, type, low, cap);
+            if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 0.0;
+            glp_set_obj_coef(lp, j, cost);
+         }
+      }
+      xassert(j == G->na);
+      return;
+}
+
+/**********************************************************************/
+
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, double *sol, int a_x, int v_pi)
+{     /* find minimum-cost flow with out-of-kilter algorithm */
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi,
+         ret;
+      double sum, temp;
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n",
+            v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_low = %d; invalid offset\n",
+            a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n",
+            a_cost);
+      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x);
+      if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi);
+      /* s is artificial source node */
+      s = G->nv + 1;
+      /* t is artificial sink node */
+      t = s + 1;
+      /* nv is the total number of nodes in the resulting network */
+      nv = t;
+      /* na is the total number of arcs in the resulting network */
+      na = G->na + 1;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_rhs >= 0)
+            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
+         else
+            temp = 0.0;
+         if (temp != 0.0) na++;
+      }
+      /* allocate working arrays */
+      tail = xcalloc(1+na, sizeof(int));
+      head = xcalloc(1+na, sizeof(int));
+      low = xcalloc(1+na, sizeof(int));
+      cap = xcalloc(1+na, sizeof(int));
+      cost = xcalloc(1+na, sizeof(int));
+      x = xcalloc(1+na, sizeof(int));
+      pi = xcalloc(1+nv, sizeof(int));
+      /* construct the resulting network */
+      k = 0;
+      /* (original arcs) */
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  k++;
+            tail[k] = a->tail->i;
+            head[k] = a->head->i;
+            if (tail[k] == head[k])
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            if (a_low >= 0)
+               memcpy(&temp, (char *)a->data + a_low, sizeof(double));
+            else
+               temp = 0.0;
+            if (!(0.0 <= temp && temp <= (double)INT_MAX &&
+                  temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            low[k] = (int)temp;
+            if (a_cap >= 0)
+               memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
+            else
+               temp = 1.0;
+            if (!((double)low[k] <= temp && temp <= (double)INT_MAX &&
+                  temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cap[k] = (int)temp;
+            if (a_cost >= 0)
+               memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
+            else
+               temp = 0.0;
+            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cost[k] = (int)temp;
+         }
+      }
+      /* (artificial arcs) */
+      sum = 0.0;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_rhs >= 0)
+            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
+         else
+            temp = 0.0;
+         if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+         {  ret = GLP_EDATA;
+            goto done;
+         }
+         if (temp > 0.0)
+         {  /* artificial arc from s to original source i */
+            k++;
+            tail[k] = s;
+            head[k] = i;
+            low[k] = cap[k] = (int)(+temp); /* supply */
+            cost[k] = 0;
+            sum += (double)temp;
+         }
+         else if (temp < 0.0)
+         {  /* artificial arc from original sink i to t */
+            k++;
+            tail[k] = i;
+            head[k] = t;
+            low[k] = cap[k] = (int)(-temp); /* demand */
+            cost[k] = 0;
+         }
+      }
+      /* (feedback arc from t to s) */
+      k++;
+      xassert(k == na);
+      tail[k] = t;
+      head[k] = s;
+      if (sum > (double)INT_MAX)
+      {  ret = GLP_EDATA;
+         goto done;
+      }
+      low[k] = cap[k] = (int)sum; /* total supply/demand */
+      cost[k] = 0;
+      /* find minimal-cost circulation in the resulting network */
+      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
+      switch (ret)
+      {  case 0:
+            /* optimal circulation found */
+            ret = 0;
+            break;
+         case 1:
+            /* no feasible circulation exists */
+            ret = GLP_ENOPFS;
+            break;
+         case 2:
+            /* integer overflow occured */
+            ret = GLP_ERANGE;
+            goto done;
+         case 3:
+            /* optimality test failed (logic error) */
+            ret = GLP_EFAIL;
+            goto done;
+         default:
+            xassert(ret != ret);
+      }
+      /* store solution components */
+      /* (objective function = the total cost) */
+      if (sol != NULL)
+      {  temp = 0.0;
+         for (k = 1; k <= na; k++)
+            temp += (double)cost[k] * (double)x[k];
+         *sol = temp;
+      }
+      /* (arc flows) */
+      if (a_x >= 0)
+      {  k = 0;
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            for (a = v->out; a != NULL; a = a->t_next)
+            {  temp = (double)x[++k];
+               memcpy((char *)a->data + a_x, &temp, sizeof(double));
+            }
+         }
+      }
+      /* (node potentials = Lagrange multipliers) */
+      if (v_pi >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            temp = - (double)pi[i];
+            memcpy((char *)v->data + v_pi, &temp, sizeof(double));
+         }
+      }
+done: /* free working arrays */
+      xfree(tail);
+      xfree(head);
+      xfree(low);
+      xfree(cap);
+      xfree(cost);
+      xfree(x);
+      xfree(pi);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_maxflow_lp - convert maximum flow problem to LP
+*
+*  SYNOPSIS
+*
+*  void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
+*     int t, int a_cap);
+*
+*  DESCRIPTION
+*
+*  The routine glp_maxflow_lp builds an LP problem, which corresponds
+*  to the maximum flow problem on the specified network G. */
+
+void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
+      int t, int a_cap)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, type, ind[1+2];
+      double cap, val[1+2];
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_maxflow_lp: names = %d; invalid parameter\n",
+            names);
+      if (!(1 <= s && s <= G->nv))
+         xerror("glp_maxflow_lp: s = %d; source node number out of rang"
+            "e\n", s);
+      if (!(1 <= t && t <= G->nv))
+         xerror("glp_maxflow_lp: t = %d: sink node number out of range "
+            "\n", t);
+      if (s == t)
+         xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must"
+            " be distinct\n", s);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap);
+      glp_erase_prob(lp);
+      if (names) glp_set_prob_name(lp, G->name);
+      glp_set_obj_dir(lp, GLP_MAX);
+      glp_add_rows(lp, G->nv);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (names) glp_set_row_name(lp, i, v->name);
+         if (i == s)
+            type = GLP_LO;
+         else if (i == t)
+            type = GLP_UP;
+         else
+            type = GLP_FX;
+         glp_set_row_bnds(lp, i, type, 0.0, 0.0);
+      }
+      if (G->na > 0) glp_add_cols(lp, G->na);
+      for (i = 1, j = 0; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  j++;
+            if (names)
+            {  char name[50+1];
+               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+               xassert(strlen(name) < sizeof(name));
+               glp_set_col_name(lp, j, name);
+            }
+            if (a->tail->i != a->head->i)
+            {  ind[1] = a->tail->i, val[1] = +1.0;
+               ind[2] = a->head->i, val[2] = -1.0;
+               glp_set_mat_col(lp, j, 2, ind, val);
+            }
+            if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            if (cap == DBL_MAX)
+               type = GLP_LO;
+            else if (cap != 0.0)
+               type = GLP_DB;
+            else
+               type = GLP_FX;
+            glp_set_col_bnds(lp, j, type, 0.0, cap);
+            if (a->tail->i == s)
+               glp_set_obj_coef(lp, j, +1.0);
+            else if (a->head->i == s)
+               glp_set_obj_coef(lp, j, -1.0);
+         }
+      }
+      xassert(j == G->na);
+      return;
+}
+
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+      double *sol, int a_x, int v_cut)
+{     /* find maximal flow with Ford-Fulkerson algorithm */
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, i, k, flag, *tail, *head, *cap, *x, ret;
+      char *cut;
+      double temp;
+      if (!(1 <= s && s <= G->nv))
+         xerror("glp_maxflow_ffalg: s = %d; source node number out of r"
+            "ange\n", s);
+      if (!(1 <= t && t <= G->nv))
+         xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran"
+            "ge\n", t);
+      if (s == t)
+         xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m"
+            "ust be distinct\n", s);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int))
+         xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n",
+            v_cut);
+      /* allocate working arrays */
+      nv = G->nv;
+      na = G->na;
+      tail = xcalloc(1+na, sizeof(int));
+      head = xcalloc(1+na, sizeof(int));
+      cap = xcalloc(1+na, sizeof(int));
+      x = xcalloc(1+na, sizeof(int));
+      if (v_cut < 0)
+         cut = NULL;
+      else
+         cut = xcalloc(1+nv, sizeof(char));
+      /* copy the flow network */
+      k = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  k++;
+            tail[k] = a->tail->i;
+            head[k] = a->head->i;
+            if (tail[k] == head[k])
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            if (a_cap >= 0)
+               memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
+            else
+               temp = 1.0;
+            if (!(0.0 <= temp && temp <= (double)INT_MAX &&
+                  temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cap[k] = (int)temp;
+         }
+      }
+      xassert(k == na);
+      /* find maximal flow in the flow network */
+      ffalg(nv, na, tail, head, s, t, cap, x, cut);
+      ret = 0;
+      /* store solution components */
+      /* (objective function = total flow through the network) */
+      if (sol != NULL)
+      {  temp = 0.0;
+         for (k = 1; k <= na; k++)
+         {  if (tail[k] == s)
+               temp += (double)x[k];
+            else if (head[k] == s)
+               temp -= (double)x[k];
+         }
+         *sol = temp;
+      }
+      /* (arc flows) */
+      if (a_x >= 0)
+      {  k = 0;
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            for (a = v->out; a != NULL; a = a->t_next)
+            {  temp = (double)x[++k];
+               memcpy((char *)a->data + a_x, &temp, sizeof(double));
+            }
+         }
+      }
+      /* (node flags) */
+      if (v_cut >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            flag = cut[i];
+            memcpy((char *)v->data + v_cut, &flag, sizeof(int));
+         }
+      }
+done: /* free working arrays */
+      xfree(tail);
+      xfree(head);
+      xfree(cap);
+      xfree(x);
+      if (cut != NULL) xfree(cut);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_check_asnprob - check correctness of assignment problem data
+*
+*  SYNOPSIS
+*
+*  int glp_check_asnprob(glp_graph *G, int v_set);
+*
+*  RETURNS
+*
+*  If the specified assignment problem data are correct, the routine
+*  glp_check_asnprob returns zero, otherwise, non-zero. */
+
+int glp_check_asnprob(glp_graph *G, int v_set)
+{     glp_vertex *v;
+      int i, k, ret = 0;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_check_asnprob: v_set = %d; invalid offset\n",
+            v_set);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_set >= 0)
+         {  memcpy(&k, (char *)v->data + v_set, sizeof(int));
+            if (k == 0)
+            {  if (v->in != NULL)
+               {  ret = 1;
+                  break;
+               }
+            }
+            else if (k == 1)
+            {  if (v->out != NULL)
+               {  ret = 2;
+                  break;
+               }
+            }
+            else
+            {  ret = 3;
+               break;
+            }
+         }
+         else
+         {  if (v->in != NULL && v->out != NULL)
+            {  ret = 4;
+               break;
+            }
+         }
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_asnprob_lp - convert assignment problem to LP
+*
+*  SYNOPSIS
+*
+*  int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+*     int v_set, int a_cost);
+*
+*  DESCRIPTION
+*
+*  The routine glp_asnprob_lp builds an LP problem, which corresponds
+*  to the assignment problem on the specified graph G.
+*
+*  RETURNS
+*
+*  If the LP problem has been successfully built, the routine returns
+*  zero, otherwise, non-zero. */
+
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+      int v_set, int a_cost)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, ret, ind[1+2];
+      double cost, val[1+2];
+      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
+            form == GLP_ASN_MMP))
+         xerror("glp_asnprob_lp: form = %d; invalid parameter\n",
+            form);
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_asnprob_lp: names = %d; invalid parameter\n",
+            names);
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_asnprob_lp: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n",
+            a_cost);
+      ret = glp_check_asnprob(G, v_set);
+      if (ret != 0) goto done;
+      glp_erase_prob(P);
+      if (names) glp_set_prob_name(P, G->name);
+      glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX);
+      if (G->nv > 0) glp_add_rows(P, G->nv);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (names) glp_set_row_name(P, i, v->name);
+         glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX,
+            1.0, 1.0);
+      }
+      if (G->na > 0) glp_add_cols(P, G->na);
+      for (i = 1, j = 0; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  j++;
+            if (names)
+            {  char name[50+1];
+               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+               xassert(strlen(name) < sizeof(name));
+               glp_set_col_name(P, j, name);
+            }
+            ind[1] = a->tail->i, val[1] = +1.0;
+            ind[2] = a->head->i, val[2] = +1.0;
+            glp_set_mat_col(P, j, 2, ind, val);
+            glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0);
+            if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 1.0;
+            glp_set_obj_coef(P, j, cost);
+         }
+      }
+      xassert(j == G->na);
+done: return ret;
+}
+
+/**********************************************************************/
+
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
+      double *sol, int a_x)
+{     /* solve assignment problem with out-of-kilter algorithm */
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
+      double temp;
+      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
+            form == GLP_ASN_MMP))
+         xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
+            form);
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
+            a_cost);
+      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
+         xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
+      if (glp_check_asnprob(G, v_set))
+         return GLP_EDATA;
+      /* nv is the total number of nodes in the resulting network */
+      nv = G->nv + 1;
+      /* na is the total number of arcs in the resulting network */
+      na = G->na + G->nv;
+      /* allocate working arrays */
+      tail = xcalloc(1+na, sizeof(int));
+      head = xcalloc(1+na, sizeof(int));
+      low = xcalloc(1+na, sizeof(int));
+      cap = xcalloc(1+na, sizeof(int));
+      cost = xcalloc(1+na, sizeof(int));
+      x = xcalloc(1+na, sizeof(int));
+      pi = xcalloc(1+nv, sizeof(int));
+      /* construct the resulting network */
+      k = 0;
+      /* (original arcs) */
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  k++;
+            tail[k] = a->tail->i;
+            head[k] = a->head->i;
+            low[k] = 0;
+            cap[k] = 1;
+            if (a_cost >= 0)
+               memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
+            else
+               temp = 1.0;
+            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cost[k] = (int)temp;
+            if (form != GLP_ASN_MIN) cost[k] = - cost[k];
+         }
+      }
+      /* (artificial arcs) */
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         k++;
+         if (v->out == NULL)
+            tail[k] = i, head[k] = nv;
+         else if (v->in == NULL)
+            tail[k] = nv, head[k] = i;
+         else
+            xassert(v != v);
+         low[k] = (form == GLP_ASN_MMP ? 0 : 1);
+         cap[k] = 1;
+         cost[k] = 0;
+      }
+      xassert(k == na);
+      /* find minimal-cost circulation in the resulting network */
+      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
+      switch (ret)
+      {  case 0:
+            /* optimal circulation found */
+            ret = 0;
+            break;
+         case 1:
+            /* no feasible circulation exists */
+            ret = GLP_ENOPFS;
+            break;
+         case 2:
+            /* integer overflow occured */
+            ret = GLP_ERANGE;
+            goto done;
+         case 3:
+            /* optimality test failed (logic error) */
+            ret = GLP_EFAIL;
+            goto done;
+         default:
+            xassert(ret != ret);
+      }
+      /* store solution components */
+      /* (objective function = the total cost) */
+      if (sol != NULL)
+      {  temp = 0.0;
+         for (k = 1; k <= na; k++)
+            temp += (double)cost[k] * (double)x[k];
+         if (form != GLP_ASN_MIN) temp = - temp;
+         *sol = temp;
+      }
+      /* (arc flows) */
+      if (a_x >= 0)
+      {  k = 0;
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            for (a = v->out; a != NULL; a = a->t_next)
+            {  k++;
+               if (ret == 0)
+                  xassert(x[k] == 0 || x[k] == 1);
+               memcpy((char *)a->data + a_x, &x[k], sizeof(int));
+            }
+         }
+      }
+done: /* free working arrays */
+      xfree(tail);
+      xfree(head);
+      xfree(low);
+      xfree(cap);
+      xfree(cost);
+      xfree(x);
+      xfree(pi);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_asnprob_hall - find bipartite matching of maximum cardinality
+*
+*  SYNOPSIS
+*
+*  int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+*
+*  DESCRIPTION
+*
+*  The routine glp_asnprob_hall finds a matching of maximal cardinality
+*  in the specified bipartite graph G. It uses a version of the Fortran
+*  routine MC21A developed by I.S.Duff [1], which implements Hall's
+*  algorithm [2].
+*
+*  RETURNS
+*
+*  The routine glp_asnprob_hall returns the cardinality of the matching
+*  found. However, if the specified graph is incorrect (as detected by
+*  the routine glp_check_asnprob), the routine returns negative value.
+*
+*  REFERENCES
+*
+*  1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
+*     Trans. on Math. Softw. 7 (1981), 387-390.
+*
+*  2. M.Hall, "An Algorithm for distinct representatives," Amer. Math.
+*     Monthly 63 (1956), 716-717. */
+
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x)
+{     glp_vertex *v;
+      glp_arc *a;
+      int card, i, k, loc, n, n1, n2, xij;
+      int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_asnprob_hall: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
+         xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x);
+      if (glp_check_asnprob(G, v_set))
+         return -1;
+      /* determine the number of vertices in sets R and S and renumber
+         vertices in S which correspond to columns of the matrix; skip
+         all isolated vertices */
+      num = xcalloc(1+G->nv, sizeof(int));
+      n1 = n2 = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v->in == NULL && v->out != NULL)
+            n1++, num[i] = 0; /* vertex in R */
+         else if (v->in != NULL && v->out == NULL)
+            n2++, num[i] = n2; /* vertex in S */
+         else
+         {  xassert(v->in == NULL && v->out == NULL);
+            num[i] = -1; /* isolated vertex */
+         }
+      }
+      /* the matrix must be square, thus, if it has more columns than
+         rows, extra rows will be just empty, and vice versa */
+      n = (n1 >= n2 ? n1 : n2);
+      /* allocate working arrays */
+      icn = xcalloc(1+G->na, sizeof(int));
+      ip = xcalloc(1+n, sizeof(int));
+      lenr = xcalloc(1+n, sizeof(int));
+      iperm = xcalloc(1+n, sizeof(int));
+      pr = xcalloc(1+n, sizeof(int));
+      arp = xcalloc(1+n, sizeof(int));
+      cv = xcalloc(1+n, sizeof(int));
+      out = xcalloc(1+n, sizeof(int));
+      /* build the adjacency matrix of the bipartite graph in row-wise
+         format (rows are vertices in R, columns are vertices in S) */
+      k = 0, loc = 1;
+      for (i = 1; i <= G->nv; i++)
+      {  if (num[i] != 0) continue;
+         /* vertex i in R */
+         ip[++k] = loc;
+         v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  xassert(num[a->head->i] != 0);
+            icn[loc++] = num[a->head->i];
+         }
+         lenr[k] = loc - ip[k];
+      }
+      xassert(loc-1 == G->na);
+      /* make all extra rows empty (all extra columns are empty due to
+         the row-wise format used) */
+      for (k++; k <= n; k++)
+         ip[k] = loc, lenr[k] = 0;
+      /* find a row permutation that maximizes the number of non-zeros
+         on the main diagonal */
+      card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out);
+#if 1 /* 18/II-2010 */
+      /* FIXED: if card = n, arp remains clobbered on exit */
+      for (i = 1; i <= n; i++)
+         arp[i] = 0;
+      for (i = 1; i <= card; i++)
+      {  k = iperm[i];
+         xassert(1 <= k && k <= n);
+         xassert(arp[k] == 0);
+         arp[k] = i;
+      }
+#endif
+      /* store solution, if necessary */
+      if (a_x < 0) goto skip;
+      k = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  if (num[i] != 0) continue;
+         /* vertex i in R */
+         k++;
+         v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  /* arp[k] is the number of matched column or zero */
+            if (arp[k] == num[a->head->i])
+            {  xassert(arp[k] != 0);
+               xij = 1;
+            }
+            else
+               xij = 0;
+            memcpy((char *)a->data + a_x, &xij, sizeof(int));
+         }
+      }
+skip: /* free working arrays */
+      xfree(num);
+      xfree(icn);
+      xfree(ip);
+      xfree(lenr);
+      xfree(iperm);
+      xfree(pr);
+      xfree(arp);
+      xfree(cv);
+      xfree(out);
+      return card;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_cpp - solve critical path problem
+*
+*  SYNOPSIS
+*
+*  double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+*
+*  DESCRIPTION
+*
+*  The routine glp_cpp solves the critical path problem represented in
+*  the form of the project network.
+*
+*  The parameter G is a pointer to the graph object, which specifies
+*  the project network. This graph must be acyclic. Multiple arcs are
+*  allowed being considered as single arcs.
+*
+*  The parameter v_t specifies an offset of the field of type double
+*  in the vertex data block, which contains time t[i] >= 0 needed to
+*  perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1
+*  for all jobs.
+*
+*  The parameter v_es specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores earliest start
+*  time for corresponding job. If v_es < 0, this time is not stored.
+*
+*  The parameter v_ls specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores latest start
+*  time for corresponding job. If v_ls < 0, this time is not stored.
+*
+*  RETURNS
+*
+*  The routine glp_cpp returns the minimal project duration, that is,
+*  minimal time needed to perform all jobs in the project. */
+
+static void sorting(glp_graph *G, int list[]);
+
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, k, nv, *list;
+      double temp, total, *t, *es, *ls;
+      if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double))
+         xerror("glp_cpp: v_t = %d; invalid offset\n", v_t);
+      if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double))
+         xerror("glp_cpp: v_es = %d; invalid offset\n", v_es);
+      if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double))
+         xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls);
+      nv = G->nv;
+      if (nv == 0)
+      {  total = 0.0;
+         goto done;
+      }
+      /* allocate working arrays */
+      t = xcalloc(1+nv, sizeof(double));
+      es = xcalloc(1+nv, sizeof(double));
+      ls = xcalloc(1+nv, sizeof(double));
+      list = xcalloc(1+nv, sizeof(int));
+      /* retrieve job times */
+      for (i = 1; i <= nv; i++)
+      {  v = G->v[i];
+         if (v_t >= 0)
+         {  memcpy(&t[i], (char *)v->data + v_t, sizeof(double));
+            if (t[i] < 0.0)
+               xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]);
+         }
+         else
+            t[i] = 1.0;
+      }
+      /* perform topological sorting to determine the list of nodes
+         (jobs) such that if list[k] = i and list[kk] = j and there
+         exists arc (i->j), then k < kk */
+      sorting(G, list);
+      /* FORWARD PASS */
+      /* determine earliest start times */
+      for (k = 1; k <= nv; k++)
+      {  j = list[k];
+         es[j] = 0.0;
+         for (a = G->v[j]->in; a != NULL; a = a->h_next)
+         {  i = a->tail->i;
+            /* there exists arc (i->j) in the project network */
+            temp = es[i] + t[i];
+            if (es[j] < temp) es[j] = temp;
+         }
+      }
+      /* determine the minimal project duration */
+      total = 0.0;
+      for (i = 1; i <= nv; i++)
+      {  temp = es[i] + t[i];
+         if (total < temp) total = temp;
+      }
+      /* BACKWARD PASS */
+      /* determine latest start times */
+      for (k = nv; k >= 1; k--)
+      {  i = list[k];
+         ls[i] = total - t[i];
+         for (a = G->v[i]->out; a != NULL; a = a->t_next)
+         {  j = a->head->i;
+            /* there exists arc (i->j) in the project network */
+            temp = ls[j] - t[i];
+            if (ls[i] > temp) ls[i] = temp;
+         }
+         /* avoid possible round-off errors */
+         if (ls[i] < es[i]) ls[i] = es[i];
+      }
+      /* store results, if necessary */
+      if (v_es >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_es, &es[i], sizeof(double));
+         }
+      }
+      if (v_ls >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_ls, &ls[i], sizeof(double));
+         }
+      }
+      /* free working arrays */
+      xfree(t);
+      xfree(es);
+      xfree(ls);
+      xfree(list);
+done: return total;
+}
+
+static void sorting(glp_graph *G, int list[])
+{     /* perform topological sorting to determine the list of nodes
+         (jobs) such that if list[k] = i and list[kk] = j and there
+         exists arc (i->j), then k < kk */
+      int i, k, nv, v_size, *num;
+      void **save;
+      nv = G->nv;
+      v_size = G->v_size;
+      save = xcalloc(1+nv, sizeof(void *));
+      num = xcalloc(1+nv, sizeof(int));
+      G->v_size = sizeof(int);
+      for (i = 1; i <= nv; i++)
+      {  save[i] = G->v[i]->data;
+         G->v[i]->data = &num[i];
+         list[i] = 0;
+      }
+      if (glp_top_sort(G, 0) != 0)
+         xerror("glp_cpp: project network is not acyclic\n");
+      G->v_size = v_size;
+      for (i = 1; i <= nv; i++)
+      {  G->v[i]->data = save[i];
+         k = num[i];
+         xassert(1 <= k && k <= nv);
+         xassert(list[k] == 0);
+         list[k] = i;
+      }
+      xfree(save);
+      xfree(num);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi18.c b/optional/glpk/glpapi18.c
new file mode 100644
index 0000000..281b429
--- /dev/null
+++ b/optional/glpk/glpapi18.c
@@ -0,0 +1,126 @@
+/* glpapi18.c (maximum clique problem) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+static void set_edge(int nv, unsigned char a[], int i, int j)
+{     int k;
+      xassert(1 <= j && j < i && i <= nv);
+      k = ((i - 1) * (i - 2)) / 2 + (j - 1);
+      a[k / CHAR_BIT] |=
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+      return;
+}
+
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set)
+{     /* find maximum weight clique with exact algorithm */
+      glp_arc *e;
+      int i, j, k, len, x, *w, *ind, ret = 0;
+      unsigned char *a;
+      double s, t;
+      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+         xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n",
+            v_wgt);
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_wclique_exact: v_set = %d; invalid parameter\n",
+            v_set);
+      if (G->nv == 0)
+      {  /* empty graph has only empty clique */
+         if (sol != NULL) *sol = 0.0;
+         return 0;
+      }
+      /* allocate working arrays */
+      w = xcalloc(1+G->nv, sizeof(int));
+      ind = xcalloc(1+G->nv, sizeof(int));
+      len = G->nv; /* # vertices */
+      len = len * (len - 1) / 2; /* # entries in lower triangle */
+      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */
+      a = xcalloc(len, sizeof(char));
+      memset(a, 0, len * sizeof(char));
+      /* determine vertex weights */
+      s = 0.0;
+      for (i = 1; i <= G->nv; i++)
+      {  if (v_wgt >= 0)
+         {  memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double));
+            if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            w[i] = (int)t;
+         }
+         else
+            w[i] = 1;
+         s += (double)w[i];
+      }
+      if (s > (double)INT_MAX)
+      {  ret = GLP_EDATA;
+         goto done;
+      }
+      /* build the adjacency matrix */
+      for (i = 1; i <= G->nv; i++)
+      {  for (e = G->v[i]->in; e != NULL; e = e->h_next)
+         {  j = e->tail->i;
+            /* there exists edge (j,i) in the graph */
+            if (i > j) set_edge(G->nv, a, i, j);
+         }
+         for (e = G->v[i]->out; e != NULL; e = e->t_next)
+         {  j = e->head->i;
+            /* there exists edge (i,j) in the graph */
+            if (i > j) set_edge(G->nv, a, i, j);
+         }
+      }
+      /* find maximum weight clique in the graph */
+      len = wclique(G->nv, w, a, ind);
+      /* compute the clique weight */
+      s = 0.0;
+      for (k = 1; k <= len; k++)
+      {  i = ind[k];
+         xassert(1 <= i && i <= G->nv);
+         s += (double)w[i];
+      }
+      if (sol != NULL) *sol = s;
+      /* mark vertices included in the clique */
+      if (v_set >= 0)
+      {  x = 0;
+         for (i = 1; i <= G->nv; i++)
+            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
+         x = 1;
+         for (k = 1; k <= len; k++)
+         {  i = ind[k];
+            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
+         }
+      }
+done: /* free working arrays */
+      xfree(w);
+      xfree(ind);
+      xfree(a);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpapi19.c b/optional/glpk/glpapi19.c
new file mode 100644
index 0000000..75d2ccf
--- /dev/null
+++ b/optional/glpk/glpapi19.c
@@ -0,0 +1,1201 @@
+/* glpapi19.c (stand-alone LP/MIP solver) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glpapi.h"
+#include "glpgmp.h"
+
+struct csa
+{     /* common storage area */
+      glp_prob *prob;
+      /* LP/MIP problem object */
+      glp_bfcp bfcp;
+      /* basis factorization control parameters */
+      glp_smcp smcp;
+      /* simplex method control parameters */
+      glp_iptcp iptcp;
+      /* interior-point method control parameters */
+      glp_iocp iocp;
+      /* integer optimizer control parameters */
+      glp_tran *tran;
+      /* model translator workspace */
+      glp_graph *graph;
+      /* network problem object */
+      int format;
+      /* problem file format: */
+#define FMT_MPS_DECK    1  /* fixed MPS */
+#define FMT_MPS_FILE    2  /* free MPS */
+#define FMT_LP          3  /* CPLEX LP */
+#define FMT_GLP         4  /* GLPK LP/MIP */
+#define FMT_MATHPROG    5  /* MathProg */
+#define FMT_MIN_COST    6  /* DIMACS min-cost flow */
+#define FMT_MAX_FLOW    7  /* DIMACS maximum flow */
+      const char *in_file;
+      /* name of input problem file */
+#define DATA_MAX 10
+      /* maximal number of input data files */
+      int ndf;
+      /* number of input data files specified */
+      const char *in_data[1+DATA_MAX];
+      /* name(s) of input data file(s) */
+      const char *out_dpy;
+      /* name of output file to send display output; NULL means the
+         display output is sent to the terminal */
+      int seed;
+      /* seed value to be passed to the MathProg translator; initially
+         set to 1; 0x80000000 means the value is omitted */
+      int solution;
+      /* solution type flag: */
+#define SOL_BASIC       1  /* basic */
+#define SOL_INTERIOR    2  /* interior-point */
+#define SOL_INTEGER     3  /* mixed integer */
+      const char *in_res;
+      /* name of input solution file in raw format */
+      int dir;
+      /* optimization direction flag:
+         0       - not specified
+         GLP_MIN - minimization
+         GLP_MAX - maximization */
+      int scale;
+      /* automatic problem scaling flag */
+      const char *out_sol;
+      /* name of output solution file in printable format */
+      const char *out_res;
+      /* name of output solution file in raw format */
+      const char *out_ranges;
+      /* name of output file to write sensitivity analysis report */
+      int check;
+      /* input data checking flag; no solution is performed */
+      const char *new_name;
+      /* new name to be assigned to the problem */
+      const char *out_mps;
+      /* name of output problem file in fixed MPS format */
+      const char *out_freemps;
+      /* name of output problem file in free MPS format */
+      const char *out_cpxlp;
+      /* name of output problem file in CPLEX LP format */
+      const char *out_glp;
+      /* name of output problem file in GLPK format */
+      const char *out_pb;
+      /* name of output problem file in OPB format */
+      const char *out_npb;
+      /* name of output problem file in normalized OPB format */
+      const char *log_file;
+      /* name of output file to hardcopy terminal output */
+      int crash;
+      /* initial basis option: */
+#define USE_STD_BASIS   1  /* use standard basis */
+#define USE_ADV_BASIS   2  /* use advanced basis */
+#define USE_CPX_BASIS   3  /* use Bixby's basis */
+#define USE_INI_BASIS   4  /* use initial basis from ini_file */
+      const char *ini_file;
+      /* name of input file containing initial basis */
+      int exact;
+      /* flag to use glp_exact rather than glp_simplex */
+      int xcheck;
+      /* flag to check final basis with glp_exact */
+      int nomip;
+      /* flag to consider MIP as pure LP */
+};
+
+static void print_help(const char *my_name)
+{     /* print help information */
+      xprintf("Usage: %s [options...] filename\n", my_name);
+      xprintf("\n");
+      xprintf("General options:\n");
+      xprintf("   --mps             read LP/MIP problem in fixed MPS fo"
+         "rmat\n");
+      xprintf("   --freemps         read LP/MIP problem in free MPS for"
+         "mat (default)\n");
+      xprintf("   --lp              read LP/MIP problem in CPLEX LP for"
+         "mat\n");
+      xprintf("   --glp             read LP/MIP problem in GLPK format "
+         "\n");
+      xprintf("   --math            read LP/MIP model written in GNU Ma"
+         "thProg modeling\n");
+      xprintf("                     language\n");
+      xprintf("   -m filename, --model filename\n");
+      xprintf("                     read model section and optional dat"
+         "a section from\n");
+      xprintf("                     filename (same as --math)\n");
+      xprintf("   -d filename, --data filename\n");
+      xprintf("                     read data section from filename (fo"
+         "r --math only);\n");
+      xprintf("                     if model file also has data section"
+         ", it is ignored\n");
+      xprintf("   -y filename, --display filename\n");
+      xprintf("                     send display output to filename (fo"
+         "r --math only);\n");
+      xprintf("                     by default the output is sent to te"
+         "rminal\n");
+      xprintf("   --seed value      initialize pseudo-random number gen"
+         "erator used in\n");
+      xprintf("                     MathProg model with specified seed "
+         "(any integer);\n");
+      xprintf("                     if seed value is ?, some random see"
+         "d will be used\n");
+      xprintf("   --mincost         read min-cost flow problem in DIMAC"
+         "S format\n");
+      xprintf("   --maxflow         read maximum flow problem in DIMACS"
+         " format\n");
+      xprintf("   --simplex         use simplex method (default)\n");
+      xprintf("   --interior        use interior point method (LP only)"
+         "\n");
+      xprintf("   -r filename, --read filename\n");
+      xprintf("                     read solution from filename rather "
+         "to find it with\n");
+      xprintf("                     the solver\n");
+      xprintf("   --min             minimization\n");
+      xprintf("   --max             maximization\n");
+      xprintf("   --scale           scale problem (default)\n");
+      xprintf("   --noscale         do not scale problem\n");
+      xprintf("   -o filename, --output filename\n");
+      xprintf("                     write solution to filename in print"
+         "able format\n");
+      xprintf("   -w filename, --write filename\n");
+      xprintf("                     write solution to filename in plain"
+         " text format\n");
+      xprintf("   --ranges filename\n");
+      xprintf("                     write sensitivity analysis report t"
+         "o filename in\n");
+      xprintf("                     printable format (simplex only)\n");
+      xprintf("   --tmlim nnn       limit solution time to nnn seconds "
+         "\n");
+      xprintf("   --memlim nnn      limit available memory to nnn megab"
+         "ytes\n");
+      xprintf("   --check           do not solve problem, check input d"
+         "ata only\n");
+      xprintf("   --name probname   change problem name to probname\n");
+      xprintf("   --wmps filename   write problem to filename in fixed "
+         "MPS format\n");
+      xprintf("   --wfreemps filename\n");
+      xprintf("                     write problem to filename in free M"
+         "PS format\n");
+      xprintf("   --wlp filename    write problem to filename in CPLEX "
+         "LP format\n");
+      xprintf("   --wglp filename   write problem to filename in GLPK f"
+         "ormat\n");
+#if 0
+      xprintf("   --wpb filename    write problem to filename in OPB fo"
+         "rmat\n");
+      xprintf("   --wnpb filename   write problem to filename in normal"
+         "ized OPB format\n");
+#endif
+      xprintf("   --log filename    write copy of terminal output to fi"
+         "lename\n");
+      xprintf("   -h, --help        display this help information and e"
+         "xit\n");
+      xprintf("   -v, --version     display program version and exit\n")
+         ;
+      xprintf("\n");
+      xprintf("LP basis factorization options:\n");
+      xprintf("   --luf             LU + Forrest-Tomlin update\n");
+      xprintf("                     (faster, less stable; default)\n");
+      xprintf("   --cbg             LU + Schur complement + Bartels-Gol"
+         "ub update\n");
+      xprintf("                     (slower, more stable)\n");
+      xprintf("   --cgr             LU + Schur complement + Givens rota"
+         "tion update\n");
+      xprintf("                     (slower, more stable)\n");
+      xprintf("\n");
+      xprintf("Options specific to simplex solver:\n");
+      xprintf("   --primal          use primal simplex (default)\n");
+      xprintf("   --dual            use dual simplex\n");
+      xprintf("   --std             use standard initial basis of all s"
+         "lacks\n");
+      xprintf("   --adv             use advanced initial basis (default"
+         ")\n");
+      xprintf("   --bib             use Bixby's initial basis\n");
+      xprintf("   --ini filename    use as initial basis previously sav"
+         "ed with -w\n");
+      xprintf("                     (disables LP presolver)\n");
+      xprintf("   --steep           use steepest edge technique (defaul"
+         "t)\n");
+      xprintf("   --nosteep         use standard \"textbook\" pricing\n"
+         );
+      xprintf("   --relax           use Harris' two-pass ratio test (de"
+         "fault)\n");
+      xprintf("   --norelax         use standard \"textbook\" ratio tes"
+         "t\n");
+      xprintf("   --presol          use presolver (default; assumes --s"
+         "cale and --adv)\n");
+      xprintf("   --nopresol        do not use presolver\n");
+      xprintf("   --exact           use simplex method based on exact a"
+         "rithmetic\n");
+      xprintf("   --xcheck          check final basis using exact arith"
+         "metic\n");
+      xprintf("\n");
+      xprintf("Options specific to interior-point solver:\n");
+      xprintf("   --nord            use natural (original) ordering\n");
+      xprintf("   --qmd             use quotient minimum degree orderin"
+         "g\n");
+      xprintf("   --amd             use approximate minimum degree orde"
+         "ring (default)\n");
+      xprintf("   --symamd          use approximate minimum degree orde"
+         "ring\n");
+      xprintf("\n");
+      xprintf("Options specific to MIP solver:\n");
+      xprintf("   --nomip           consider all integer variables as c"
+         "ontinuous\n");
+      xprintf("                     (allows solving MIP as pure LP)\n");
+      xprintf("   --first           branch on first integer variable\n")
+         ;
+      xprintf("   --last            branch on last integer variable\n");
+      xprintf("   --mostf           branch on most fractional variable "
+         "\n");
+      xprintf("   --drtom           branch using heuristic by Driebeck "
+         "and Tomlin\n");
+      xprintf("                     (default)\n");
+      xprintf("   --pcost           branch using hybrid pseudocost heur"
+         "istic (may be\n");
+      xprintf("                     useful for hard instances)\n");
+      xprintf("   --dfs             backtrack using depth first search "
+         "\n");
+      xprintf("   --bfs             backtrack using breadth first searc"
+         "h\n");
+      xprintf("   --bestp           backtrack using the best projection"
+         " heuristic\n");
+      xprintf("   --bestb           backtrack using node with best loca"
+         "l bound\n");
+      xprintf("                     (default)\n");
+      xprintf("   --intopt          use MIP presolver (default)\n");
+      xprintf("   --nointopt        do not use MIP presolver\n");
+      xprintf("   --binarize        replace general integer variables b"
+         "y binary ones\n");
+      xprintf("                     (assumes --intopt)\n");
+      xprintf("   --fpump           apply feasibility pump heuristic\n")
+         ;
+      xprintf("   --gomory          generate Gomory's mixed integer cut"
+         "s\n");
+      xprintf("   --mir             generate MIR (mixed integer roundin"
+         "g) cuts\n");
+      xprintf("   --cover           generate mixed cover cuts\n");
+      xprintf("   --clique          generate clique cuts\n");
+      xprintf("   --cuts            generate all cuts above\n");
+      xprintf("   --mipgap tol      set relative mip gap tolerance to t"
+         "ol\n");
+      xprintf("\n");
+      xprintf("For description of the MPS and CPLEX LP formats see Refe"
+         "rence Manual.\n");
+      xprintf("For description of the modeling language see \"GLPK: Mod"
+         "eling Language\n");
+      xprintf("GNU MathProg\". Both documents are included in the GLPK "
+         "distribution.\n");
+      xprintf("\n");
+      xprintf("See GLPK web page at <http://www.gnu.org/software/glpk/g"
+         "lpk.html>.\n");
+      xprintf("\n");
+      xprintf("Please report bugs to <bug-glpk at gnu.org>.\n");
+      return;
+}
+
+static void print_version(int briefly)
+{     /* print version information */
+      xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version());
+      if (briefly) goto done;
+      xprintf("\n");
+      xprintf("Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, "
+         "2007, 2008,\n");
+      xprintf("2009, 2010 Andrew Makhorin, Department for Applied Infor"
+         "matics, Moscow\n");
+      xprintf("Aviation Institute, Moscow, Russia. All rights reserved."
+         "\n");
+      xprintf("\n");
+      xprintf("This program has ABSOLUTELY NO WARRANTY.\n");
+      xprintf("\n");
+      xprintf("This program is free software; you may re-distribute it "
+         "under the terms\n");
+      xprintf("of the GNU General Public License version 3 or later.\n")
+         ;
+done: return;
+}
+
+static int parse_cmdline(struct csa *csa, int argc, const char *argv[])
+{     /* parse command-line parameters */
+      int k;
+#define p(str) (strcmp(argv[k], str) == 0)
+      for (k = 1; k < argc; k++)
+      {  if (p("--mps"))
+            csa->format = FMT_MPS_DECK;
+         else if (p("--freemps"))
+            csa->format = FMT_MPS_FILE;
+         else if (p("--lp") || p("--cpxlp"))
+            csa->format = FMT_LP;
+         else if (p("--glp"))
+            csa->format = FMT_GLP;
+         else if (p("--math") || p("-m") || p("--model"))
+            csa->format = FMT_MATHPROG;
+         else if (p("-d") || p("--data"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No input data file specified\n");
+               return 1;
+            }
+            if (csa->ndf == DATA_MAX)
+            {  xprintf("Too many input data files\n");
+               return 1;
+            }
+            csa->in_data[++(csa->ndf)] = argv[k];
+         }
+         else if (p("-y") || p("--display"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No display output file specified\n");
+               return 1;
+            }
+            if (csa->out_dpy != NULL)
+            {  xprintf("Only one display output file allowed\n");
+               return 1;
+            }
+            csa->out_dpy = argv[k];
+         }
+         else if (p("--seed"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' ||
+               argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
+            {  xprintf("No seed value specified\n");
+               return 1;
+            }
+            if (strcmp(argv[k], "?") == 0)
+               csa->seed = 0x80000000;
+            else if (str2int(argv[k], &csa->seed))
+            {  xprintf("Invalid seed value `%s'\n", argv[k]);
+               return 1;
+            }
+         }
+         else if (p("--mincost"))
+            csa->format = FMT_MIN_COST;
+         else if (p("--maxflow"))
+            csa->format = FMT_MAX_FLOW;
+         else if (p("--simplex"))
+            csa->solution = SOL_BASIC;
+         else if (p("--interior"))
+            csa->solution = SOL_INTERIOR;
+#if 1 /* 28/V-2010 */
+         else if (p("--alien"))
+            csa->iocp.alien = GLP_ON;
+#endif
+         else if (p("-r") || p("--read"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No input solution file specified\n");
+               return 1;
+            }
+            if (csa->in_res != NULL)
+            {  xprintf("Only one input solution file allowed\n");
+               return 1;
+            }
+            csa->in_res = argv[k];
+         }
+         else if (p("--min"))
+            csa->dir = GLP_MIN;
+         else if (p("--max"))
+            csa->dir = GLP_MAX;
+         else if (p("--scale"))
+            csa->scale = 1;
+         else if (p("--noscale"))
+            csa->scale = 0;
+         else if (p("-o") || p("--output"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No output solution file specified\n");
+               return 1;
+            }
+            if (csa->out_sol != NULL)
+            {  xprintf("Only one output solution file allowed\n");
+               return 1;
+            }
+            csa->out_sol = argv[k];
+         }
+         else if (p("-w") || p("--write"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No output solution file specified\n");
+               return 1;
+            }
+            if (csa->out_res != NULL)
+            {  xprintf("Only one output solution file allowed\n");
+               return 1;
+            }
+            csa->out_res = argv[k];
+         }
+         else if (p("--ranges") || p("--bounds"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No output file specified to write sensitivity a"
+                  "nalysis report\n");
+               return 1;
+            }
+            if (csa->out_ranges != NULL)
+            {  xprintf("Only one output file allowed to write sensitivi"
+                  "ty analysis report\n");
+               return 1;
+            }
+            csa->out_ranges = argv[k];
+         }
+         else if (p("--tmlim"))
+         {  int tm_lim;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No time limit specified\n");
+               return 1;
+            }
+            if (str2int(argv[k], &tm_lim) || tm_lim < 0)
+            {  xprintf("Invalid time limit `%s'\n", argv[k]);
+               return 1;
+            }
+            if (tm_lim <= INT_MAX / 1000)
+               csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim;
+            else
+               csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX;
+         }
+         else if (p("--memlim"))
+         {  int mem_lim;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No memory limit specified\n");
+               return 1;
+            }
+            if (str2int(argv[k], &mem_lim) || mem_lim < 1)
+            {  xprintf("Invalid memory limit `%s'\n", argv[k]);
+               return 1;
+            }
+            glp_mem_limit(mem_lim);
+         }
+         else if (p("--check"))
+            csa->check = 1;
+         else if (p("--name"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem name specified\n");
+               return 1;
+            }
+            if (csa->new_name != NULL)
+            {  xprintf("Only one problem name allowed\n");
+               return 1;
+            }
+            csa->new_name = argv[k];
+         }
+         else if (p("--wmps"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No fixed MPS output file specified\n");
+               return 1;
+            }
+            if (csa->out_mps != NULL)
+            {  xprintf("Only one fixed MPS output file allowed\n");
+               return 1;
+            }
+            csa->out_mps = argv[k];
+         }
+         else if (p("--wfreemps"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No free MPS output file specified\n");
+               return 1;
+            }
+            if (csa->out_freemps != NULL)
+            {  xprintf("Only one free MPS output file allowed\n");
+               return 1;
+            }
+            csa->out_freemps = argv[k];
+         }
+         else if (p("--wlp") || p("--wcpxlp") || p("--wlpt"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No CPLEX LP output file specified\n");
+               return 1;
+            }
+            if (csa->out_cpxlp != NULL)
+            {  xprintf("Only one CPLEX LP output file allowed\n");
+               return 1;
+            }
+            csa->out_cpxlp = argv[k];
+         }
+         else if (p("--wglp"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No GLPK LP/MIP output file specified\n");
+               return 1;
+            }
+            if (csa->out_glp != NULL)
+            {  xprintf("Only one GLPK LP/MIP output file allowed\n");
+               return 1;
+            }
+            csa->out_glp = argv[k];
+         }
+         else if (p("--wpb"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem output file specified\n");
+               return 1;
+            }
+            if (csa->out_pb != NULL)
+            {  xprintf("Only one OPB output file allowed\n");
+               return 1;
+            }
+            csa->out_pb = argv[k];
+         }
+         else if (p("--wnpb"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem output file specified\n");
+               return 1;
+            }
+            if (csa->out_npb != NULL)
+            {  xprintf("Only one normalized OPB output file allowed\n");
+               return 1;
+            }
+            csa->out_npb = argv[k];
+         }
+         else if (p("--log"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No log file specified\n");
+               return 1;
+            }
+            if (csa->log_file != NULL)
+            {  xprintf("Only one log file allowed\n");
+               return 1;
+            }
+            csa->log_file = argv[k];
+         }
+         else if (p("-h") || p("--help"))
+         {  print_help(argv[0]);
+            return -1;
+         }
+         else if (p("-v") || p("--version"))
+         {  print_version(0);
+            return -1;
+         }
+         else if (p("--luf"))
+            csa->bfcp.type = GLP_BF_FT;
+         else if (p("--cbg"))
+            csa->bfcp.type = GLP_BF_BG;
+         else if (p("--cgr"))
+            csa->bfcp.type = GLP_BF_GR;
+         else if (p("--primal"))
+            csa->smcp.meth = GLP_PRIMAL;
+         else if (p("--dual"))
+            csa->smcp.meth = GLP_DUAL;
+         else if (p("--std"))
+            csa->crash = USE_STD_BASIS;
+         else if (p("--adv"))
+            csa->crash = USE_ADV_BASIS;
+         else if (p("--bib"))
+            csa->crash = USE_CPX_BASIS;
+         else if (p("--ini"))
+         {  csa->crash = USE_INI_BASIS;
+            csa->smcp.presolve = GLP_OFF;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No initial basis file specified\n");
+               return 1;
+            }
+            if (csa->ini_file != NULL)
+            {  xprintf("Only one initial basis file allowed\n");
+               return 1;
+            }
+            csa->ini_file = argv[k];
+         }
+         else if (p("--steep"))
+            csa->smcp.pricing = GLP_PT_PSE;
+         else if (p("--nosteep"))
+            csa->smcp.pricing = GLP_PT_STD;
+         else if (p("--relax"))
+            csa->smcp.r_test = GLP_RT_HAR;
+         else if (p("--norelax"))
+            csa->smcp.r_test = GLP_RT_STD;
+         else if (p("--presol"))
+            csa->smcp.presolve = GLP_ON;
+         else if (p("--nopresol"))
+            csa->smcp.presolve = GLP_OFF;
+         else if (p("--exact"))
+            csa->exact = 1;
+         else if (p("--xcheck"))
+            csa->xcheck = 1;
+         else if (p("--nord"))
+            csa->iptcp.ord_alg = GLP_ORD_NONE;
+         else if (p("--qmd"))
+            csa->iptcp.ord_alg = GLP_ORD_QMD;
+         else if (p("--amd"))
+            csa->iptcp.ord_alg = GLP_ORD_AMD;
+         else if (p("--symamd"))
+            csa->iptcp.ord_alg = GLP_ORD_SYMAMD;
+         else if (p("--nomip"))
+            csa->nomip = 1;
+         else if (p("--first"))
+            csa->iocp.br_tech = GLP_BR_FFV;
+         else if (p("--last"))
+            csa->iocp.br_tech = GLP_BR_LFV;
+         else if (p("--drtom"))
+            csa->iocp.br_tech = GLP_BR_DTH;
+         else if (p("--mostf"))
+            csa->iocp.br_tech = GLP_BR_MFV;
+         else if (p("--pcost"))
+            csa->iocp.br_tech = GLP_BR_PCH;
+         else if (p("--dfs"))
+            csa->iocp.bt_tech = GLP_BT_DFS;
+         else if (p("--bfs"))
+            csa->iocp.bt_tech = GLP_BT_BFS;
+         else if (p("--bestp"))
+            csa->iocp.bt_tech = GLP_BT_BPH;
+         else if (p("--bestb"))
+            csa->iocp.bt_tech = GLP_BT_BLB;
+         else if (p("--intopt"))
+            csa->iocp.presolve = GLP_ON;
+         else if (p("--nointopt"))
+            csa->iocp.presolve = GLP_OFF;
+         else if (p("--binarize"))
+            csa->iocp.presolve = csa->iocp.binarize = GLP_ON;
+         else if (p("--fpump"))
+            csa->iocp.fp_heur = GLP_ON;
+         else if (p("--gomory"))
+            csa->iocp.gmi_cuts = GLP_ON;
+         else if (p("--mir"))
+            csa->iocp.mir_cuts = GLP_ON;
+         else if (p("--cover"))
+            csa->iocp.cov_cuts = GLP_ON;
+         else if (p("--clique"))
+            csa->iocp.clq_cuts = GLP_ON;
+         else if (p("--cuts"))
+            csa->iocp.gmi_cuts = csa->iocp.mir_cuts =
+            csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON;
+         else if (p("--mipgap"))
+         {  double mip_gap;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No relative gap tolerance specified\n");
+               return 1;
+            }
+            if (str2num(argv[k], &mip_gap) || mip_gap < 0.0)
+            {  xprintf("Invalid relative mip gap tolerance `%s'\n",
+                  argv[k]);
+               return 1;
+            }
+            csa->iocp.mip_gap = mip_gap;
+         }
+         else if (argv[k][0] == '-' ||
+                 (argv[k][0] == '-' && argv[k][1] == '-'))
+         {  xprintf("Invalid option `%s'; try %s --help\n",
+               argv[k], argv[0]);
+            return 1;
+         }
+         else
+         {  if (csa->in_file != NULL)
+            {  xprintf("Only one input problem file allowed\n");
+               return 1;
+            }
+            csa->in_file = argv[k];
+         }
+      }
+#undef p
+      return 0;
+}
+
+typedef struct { double rhs, pi; } v_data;
+typedef struct { double low, cap, cost, x; } a_data;
+
+int glp_main(int argc, const char *argv[])
+{     /* stand-alone LP/MIP solver */
+      struct csa _csa, *csa = &_csa;
+      int ret;
+      glp_long start;
+      /* perform initialization */
+      csa->prob = glp_create_prob();
+      glp_get_bfcp(csa->prob, &csa->bfcp);
+      glp_init_smcp(&csa->smcp);
+      csa->smcp.presolve = GLP_ON;
+      glp_init_iptcp(&csa->iptcp);
+      glp_init_iocp(&csa->iocp);
+      csa->iocp.presolve = GLP_ON;
+      csa->tran = NULL;
+      csa->graph = NULL;
+      csa->format = FMT_MPS_FILE;
+      csa->in_file = NULL;
+      csa->ndf = 0;
+      csa->out_dpy = NULL;
+      csa->seed = 1;
+      csa->solution = SOL_BASIC;
+      csa->in_res = NULL;
+      csa->dir = 0;
+      csa->scale = 1;
+      csa->out_sol = NULL;
+      csa->out_res = NULL;
+      csa->out_ranges = NULL;
+      csa->check = 0;
+      csa->new_name = NULL;
+      csa->out_mps = NULL;
+      csa->out_freemps = NULL;
+      csa->out_cpxlp = NULL;
+      csa->out_glp = NULL;
+      csa->out_pb = NULL;
+      csa->out_npb = NULL;
+      csa->log_file = NULL;
+      csa->crash = USE_ADV_BASIS;
+      csa->ini_file = NULL;
+      csa->exact = 0;
+      csa->xcheck = 0;
+      csa->nomip = 0;
+      /* parse command-line parameters */
+      ret = parse_cmdline(csa, argc, argv);
+      if (ret < 0)
+      {  ret = EXIT_SUCCESS;
+         goto done;
+      }
+      if (ret > 0)
+      {  ret = EXIT_FAILURE;
+         goto done;
+      }
+      /*--------------------------------------------------------------*/
+      /* remove all output files specified in the command line */
+      if (csa->out_dpy != NULL) remove(csa->out_dpy);
+      if (csa->out_sol != NULL) remove(csa->out_sol);
+      if (csa->out_res != NULL) remove(csa->out_res);
+      if (csa->out_ranges != NULL) remove(csa->out_ranges);
+      if (csa->out_mps != NULL) remove(csa->out_mps);
+      if (csa->out_freemps != NULL) remove(csa->out_freemps);
+      if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
+      if (csa->out_glp != NULL) remove(csa->out_glp);
+      if (csa->out_pb != NULL) remove(csa->out_pb);
+      if (csa->out_npb != NULL) remove(csa->out_npb);
+      if (csa->log_file != NULL) remove(csa->log_file);
+      /*--------------------------------------------------------------*/
+      /* open log file, if required */
+      if (csa->log_file != NULL)
+      {  if (glp_open_tee(csa->log_file))
+         {  xprintf("Unable to create log file\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /*--------------------------------------------------------------*/
+      /* print version information */
+      print_version(1);
+      /*--------------------------------------------------------------*/
+      /* print parameters specified in the command line */
+      if (argc > 1)
+      {  int k, len = INT_MAX;
+         xprintf("Parameter(s) specified in the command line:");
+         for (k = 1; k < argc; k++)
+         {  if (len > 72)
+               xprintf("\n"), len = 0;
+            xprintf(" %s", argv[k]);
+            len += 1 + strlen(argv[k]);
+         }
+         xprintf("\n");
+      }
+      /*--------------------------------------------------------------*/
+      /* read problem data from the input file */
+      if (csa->in_file == NULL)
+      {  xprintf("No input problem file specified; try %s --help\n",
+            argv[0]);
+         ret = EXIT_FAILURE;
+         goto done;
+      }
+      if (csa->format == FMT_MPS_DECK)
+      {  ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
+            csa->in_file);
+         if (ret != 0)
+err1:    {  xprintf("MPS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      else if (csa->format == FMT_MPS_FILE)
+      {  ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
+            csa->in_file);
+         if (ret != 0) goto err1;
+      }
+      else if (csa->format == FMT_LP)
+      {  ret = glp_read_lp(csa->prob, NULL, csa->in_file);
+         if (ret != 0)
+         {  xprintf("CPLEX LP file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      else if (csa->format == FMT_GLP)
+      {  ret = glp_read_prob(csa->prob, 0, csa->in_file);
+         if (ret != 0)
+         {  xprintf("GLPK LP/MIP file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      else if (csa->format == FMT_MATHPROG)
+      {  int k;
+         /* allocate the translator workspace */
+         csa->tran = glp_mpl_alloc_wksp();
+         /* set seed value */
+         if (csa->seed == 0x80000000)
+         {  csa->seed = glp_time().lo;
+            xprintf("Seed value %d will be used\n", csa->seed);
+         }
+         _glp_mpl_init_rand(csa->tran, csa->seed);
+         /* read model section and optional data section */
+         if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
+err2:    {  xprintf("MathProg model processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         /* read optional data section(s), if necessary */
+         for (k = 1; k <= csa->ndf; k++)
+         {  if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
+               goto err2;
+         }
+         /* generate the model */
+         if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
+         /* build the problem instance from the model */
+         glp_mpl_build_prob(csa->tran, csa->prob);
+      }
+      else if (csa->format == FMT_MIN_COST)
+      {  csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
+         ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
+            offsetof(a_data, low), offsetof(a_data, cap),
+            offsetof(a_data, cost), csa->in_file);
+         if (ret != 0)
+         {  xprintf("DIMACS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
+            offsetof(v_data, rhs), offsetof(a_data, low),
+            offsetof(a_data, cap), offsetof(a_data, cost));
+         glp_set_prob_name(csa->prob, csa->in_file);
+      }
+      else if (csa->format == FMT_MAX_FLOW)
+      {  int s, t;
+         csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
+         ret = glp_read_maxflow(csa->graph, &s, &t,
+            offsetof(a_data, cap), csa->in_file);
+         if (ret != 0)
+         {  xprintf("DIMACS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
+            offsetof(a_data, cap));
+         glp_set_prob_name(csa->prob, csa->in_file);
+      }
+      else
+         xassert(csa != csa);
+      /*--------------------------------------------------------------*/
+      /* change problem name, if required */
+      if (csa->new_name != NULL)
+         glp_set_prob_name(csa->prob, csa->new_name);
+      /* change optimization direction, if required */
+      if (csa->dir != 0)
+         glp_set_obj_dir(csa->prob, csa->dir);
+      /* sort elements of the constraint matrix */
+      glp_sort_matrix(csa->prob);
+      /*--------------------------------------------------------------*/
+      /* write problem data in fixed MPS format, if required */
+      if (csa->out_mps != NULL)
+      {  ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
+            csa->out_mps);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in fixed MPS format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in free MPS format, if required */
+      if (csa->out_freemps != NULL)
+      {  ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
+            csa->out_freemps);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in free MPS format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in CPLEX LP format, if required */
+      if (csa->out_cpxlp != NULL)
+      {  ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in CPLEX LP format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in GLPK format, if required */
+      if (csa->out_glp != NULL)
+      {  ret = glp_write_prob(csa->prob, 0, csa->out_glp);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in GLPK format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in OPB format, if required */
+      if (csa->out_pb != NULL)
+      {  ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in OPB format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in normalized OPB format, if required */
+      if (csa->out_npb != NULL)
+      {  ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
+         if (ret != 0)
+         {  xprintf(
+               "Unable to write problem in normalized OPB format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /*--------------------------------------------------------------*/
+      /* if only problem data check is required, skip computations */
+      if (csa->check)
+      {  ret = EXIT_SUCCESS;
+         goto done;
+      }
+      /*--------------------------------------------------------------*/
+      /* determine the solution type */
+      if (!csa->nomip &&
+          glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
+      {  if (csa->solution == SOL_INTERIOR)
+         {  xprintf("Interior-point method is not able to solve MIP pro"
+               "blem; use --simplex\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         csa->solution = SOL_INTEGER;
+      }
+      /*--------------------------------------------------------------*/
+      /* if solution is provided, read it and skip computations */
+      if (csa->in_res != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = glp_read_sol(csa->prob, csa->in_res);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = glp_read_ipt(csa->prob, csa->in_res);
+         else if (csa->solution == SOL_INTEGER)
+            ret = glp_read_mip(csa->prob, csa->in_res);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Unable to read problem solution\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         goto skip;
+      }
+      /*--------------------------------------------------------------*/
+      /* scale the problem data, if required */
+      if (csa->scale)
+      {  if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
+             csa->solution == SOL_INTERIOR ||
+             csa->solution == SOL_INTEGER && !csa->iocp.presolve)
+            glp_scale_prob(csa->prob, GLP_SF_AUTO);
+      }
+      /*--------------------------------------------------------------*/
+      /* construct starting LP basis */
+      if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
+          csa->solution == SOL_INTEGER && !csa->iocp.presolve)
+      {  if (csa->crash == USE_STD_BASIS)
+            glp_std_basis(csa->prob);
+         else if (csa->crash == USE_ADV_BASIS)
+            glp_adv_basis(csa->prob, 0);
+         else if (csa->crash == USE_CPX_BASIS)
+            glp_cpx_basis(csa->prob);
+         else if (csa->crash == USE_INI_BASIS)
+         {  ret = glp_read_sol(csa->prob, csa->ini_file);
+            if (ret != 0)
+            {  xprintf("Unable to read initial basis\n");
+               ret = EXIT_FAILURE;
+               goto done;
+            }
+         }
+         else
+            xassert(csa != csa);
+      }
+      /*--------------------------------------------------------------*/
+      /* solve the problem */
+      start = xtime();
+      if (csa->solution == SOL_BASIC)
+      {  if (!csa->exact)
+         {  glp_set_bfcp(csa->prob, &csa->bfcp);
+            glp_simplex(csa->prob, &csa->smcp);
+            if (csa->xcheck)
+            {  if (csa->smcp.presolve &&
+                   glp_get_status(csa->prob) != GLP_OPT)
+                  xprintf("If you need to check final basis for non-opt"
+                     "imal solution, use --nopresol\n");
+               else
+                  glp_exact(csa->prob, &csa->smcp);
+            }
+            if (csa->out_sol != NULL || csa->out_res != NULL)
+            {  if (csa->smcp.presolve &&
+                   glp_get_status(csa->prob) != GLP_OPT)
+               xprintf("If you need actual output for non-optimal solut"
+                  "ion, use --nopresol\n");
+            }
+         }
+         else
+            glp_exact(csa->prob, &csa->smcp);
+      }
+      else if (csa->solution == SOL_INTERIOR)
+         glp_interior(csa->prob, &csa->iptcp);
+      else if (csa->solution == SOL_INTEGER)
+      {  if (!csa->iocp.presolve)
+         {  glp_set_bfcp(csa->prob, &csa->bfcp);
+            glp_simplex(csa->prob, &csa->smcp);
+         }
+#if 0
+         csa->iocp.msg_lev = GLP_MSG_DBG;
+         csa->iocp.pp_tech = GLP_PP_NONE;
+#endif
+         glp_intopt(csa->prob, &csa->iocp);
+      }
+      else
+         xassert(csa != csa);
+      /*--------------------------------------------------------------*/
+      /* display statistics */
+      xprintf("Time used:   %.1f secs\n", xdifftime(xtime(), start));
+      {  glp_long tpeak;
+         char buf[50];
+         glp_mem_usage(NULL, NULL, NULL, &tpeak);
+         xprintf("Memory used: %.1f Mb (%s bytes)\n",
+            xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
+      }
+      /*--------------------------------------------------------------*/
+skip: /* postsolve the model, if necessary */
+      if (csa->tran != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
+         else if (csa->solution == SOL_INTEGER)
+            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Model postsolving error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /*--------------------------------------------------------------*/
+      /* write problem solution in printable format, if required */
+      if (csa->out_sol != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = lpx_print_sol(csa->prob, csa->out_sol);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = lpx_print_ips(csa->prob, csa->out_sol);
+         else if (csa->solution == SOL_INTEGER)
+            ret = lpx_print_mip(csa->prob, csa->out_sol);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Unable to write problem solution\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem solution in printable format, if required */
+      if (csa->out_res != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = glp_write_sol(csa->prob, csa->out_res);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = glp_write_ipt(csa->prob, csa->out_res);
+         else if (csa->solution == SOL_INTEGER)
+            ret = glp_write_mip(csa->prob, csa->out_res);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Unable to write problem solution\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write sensitivity analysis report, if required */
+      if (csa->out_ranges != NULL)
+      {  if (csa->solution == SOL_BASIC)
+         {  if (glp_get_status(csa->prob) == GLP_OPT)
+            {  if (glp_bf_exists(csa->prob))
+ranges:        {  ret = glp_print_ranges(csa->prob, 0, NULL, 0,
+                     csa->out_ranges);
+                  if (ret != 0)
+                  {  xprintf("Unable to write sensitivity analysis repo"
+                        "rt\n");
+                     ret = EXIT_FAILURE;
+                     goto done;
+                  }
+               }
+               else
+               {  ret = glp_factorize(csa->prob);
+                  if (ret == 0) goto ranges;
+                  xprintf("Cannot produce sensitivity analysis report d"
+                     "ue to error in basis factorization (glp_factorize"
+                     " returned %d); try --nopresol\n", ret);
+               }
+            }
+            else
+               xprintf("Cannot produce sensitivity analysis report for "
+                  "non-optimal basic solution\n");
+         }
+         else
+            xprintf("Cannot produce sensitivity analysis report for int"
+               "erior-point or MIP solution\n");
+      }
+      /*--------------------------------------------------------------*/
+      /* all seems to be ok */
+      ret = EXIT_SUCCESS;
+      /*--------------------------------------------------------------*/
+done: /* delete the LP/MIP problem object */
+      if (csa->prob != NULL)
+         glp_delete_prob(csa->prob);
+      /* free the translator workspace, if necessary */
+      if (csa->tran != NULL)
+         glp_mpl_free_wksp(csa->tran);
+      /* delete the network problem object, if necessary */
+      if (csa->graph != NULL)
+         glp_delete_graph(csa->graph);
+      xassert(gmp_pool_count() == 0);
+      gmp_free_mem();
+      /* close log file, if necessary */
+      if (csa->log_file != NULL) glp_close_tee();
+      /* check that no memory blocks are still allocated */
+      {  int count;
+         glp_long total;
+         glp_mem_usage(&count, NULL, &total, NULL);
+         if (count != 0)
+            xerror("Error: %d memory block(s) were lost\n", count);
+         xassert(count == 0);
+         xassert(total.lo == 0 && total.hi == 0);
+      }
+      /* free the GLPK environment */
+      glp_free_env();
+      /* return to the control program */
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpavl.c b/optional/glpk/glpavl.c
new file mode 100644
index 0000000..334e592
--- /dev/null
+++ b/optional/glpk/glpavl.c
@@ -0,0 +1,357 @@
+/* glpavl.c (binary search tree) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpavl.h"
+
+AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
+      const void *key2), void *info)
+{     /* create AVL tree */
+      AVL *tree;
+      tree = xmalloc(sizeof(AVL));
+      tree->pool = dmp_create_pool();
+      tree->root = NULL;
+      tree->fcmp = fcmp;
+      tree->info = info;
+      tree->size = 0;
+      tree->height = 0;
+      return tree;
+}
+
+int avl_strcmp(void *info, const void *key1, const void *key2)
+{     /* compare character string keys */
+      xassert(info == info);
+      return strcmp(key1, key2);
+}
+
+static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
+
+AVLNODE *avl_insert_node(AVL *tree, const void *key)
+{     /* insert new node into AVL tree */
+      AVLNODE *p, *q, *r;
+      short int flag;
+      /* find an appropriate point for insertion */
+      p = NULL; q = tree->root;
+      while (q != NULL)
+      {  p = q;
+         if (tree->fcmp(tree->info, key, p->key) <= 0)
+         {  flag = 0;
+            q = p->left;
+            p->rank++;
+         }
+         else
+         {  flag = 1;
+            q = p->right;
+         }
+      }
+      /* create new node and insert it into the tree */
+      r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
+      r->key = key; r->type = 0; r->link = NULL;
+      r->rank = 1; r->up = p;
+      r->flag = (short int)(p == NULL ? 0 : flag);
+      r->bal = 0; r->left = NULL; r->right = NULL;
+      tree->size++;
+      if (p == NULL)
+         tree->root = r;
+      else
+         if (flag == 0) p->left = r; else p->right = r;
+      /* go upstairs to the root and correct all subtrees affected by
+         insertion */
+      while (p != NULL)
+      {  if (flag == 0)
+         {  /* the height of the left subtree of [p] is increased */
+            if (p->bal > 0)
+            {  p->bal = 0;
+               break;
+            }
+            if (p->bal < 0)
+            {  rotate_subtree(tree, p);
+               break;
+            }
+            p->bal = -1; flag = p->flag; p = p->up;
+         }
+         else
+         {  /* the height of the right subtree of [p] is increased */
+            if (p->bal < 0)
+            {  p->bal = 0;
+               break;
+            }
+            if (p->bal > 0)
+            {  rotate_subtree(tree, p);
+               break;
+            }
+            p->bal = +1; flag = p->flag; p = p->up;
+         }
+      }
+      /* if the root has been reached, the height of the entire tree is
+         increased */
+      if (p == NULL) tree->height++;
+      return r;
+}
+
+void avl_set_node_type(AVLNODE *node, int type)
+{     /* assign the type field of specified node */
+      node->type = type;
+      return;
+}
+
+void avl_set_node_link(AVLNODE *node, void *link)
+{     /* assign the link field of specified node */
+      node->link = link;
+      return;
+}
+
+AVLNODE *avl_find_node(AVL *tree, const void *key)
+{     /* find node in AVL tree */
+      AVLNODE *p;
+      int c;
+      p = tree->root;
+      while (p != NULL)
+      {  c = tree->fcmp(tree->info, key, p->key);
+         if (c == 0) break;
+         p = (c < 0 ? p->left : p->right);
+      }
+      return p;
+}
+
+int avl_get_node_type(AVLNODE *node)
+{     /* retrieve the type field of specified node */
+      return node->type;
+}
+
+void *avl_get_node_link(AVLNODE *node)
+{     /* retrieve the link field of specified node */
+      return node->link;
+}
+
+static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
+{     /* find next node in AVL tree */
+      AVLNODE *p, *q;
+      if (tree->root == NULL) return NULL;
+      p = node;
+      q = (p == NULL ? tree->root : p->right);
+      if (q == NULL)
+      {  /* go upstairs from the left subtree */
+         for (;;)
+         {  q = p->up;
+            if (q == NULL) break;
+            if (p->flag == 0) break;
+            p = q;
+         }
+      }
+      else
+      {  /* go downstairs into the right subtree */
+         for (;;)
+         {  p = q->left;
+            if (p == NULL) break;
+            q = p;
+         }
+      }
+      return q;
+}
+
+void avl_delete_node(AVL *tree, AVLNODE *node)
+{     /* delete specified node from AVL tree */
+      AVLNODE *f, *p, *q, *r, *s, *x, *y;
+      short int flag;
+      p = node;
+      /* if both subtrees of the specified node are non-empty, the node
+         should be interchanged with the next one, at least one subtree
+         of which is always empty */
+      if (p->left == NULL || p->right == NULL) goto skip;
+      f = p->up; q = p->left;
+      r = find_next_node(tree, p); s = r->right;
+      if (p->right == r)
+      {  if (f == NULL)
+            tree->root = r;
+         else
+            if (p->flag == 0) f->left = r; else f->right = r;
+         r->rank = p->rank; r->up = f;
+         r->flag = p->flag; r->bal = p->bal;
+         r->left = q; r->right = p;
+         q->up = r;
+         p->rank = 1; p->up = r; p->flag = 1;
+         p->bal = (short int)(s == NULL ? 0 : +1);
+         p->left = NULL; p->right = s;
+         if (s != NULL) s->up = p;
+      }
+      else
+      {  x = p->right; y = r->up;
+         if (f == NULL)
+            tree->root = r;
+         else
+            if (p->flag == 0) f->left = r; else f->right = r;
+         r->rank = p->rank; r->up = f;
+         r->flag = p->flag; r->bal = p->bal;
+         r->left = q; r->right = x;
+         q->up = r; x->up = r; y->left = p;
+         p->rank = 1; p->up = y; p->flag = 0;
+         p->bal = (short int)(s == NULL ? 0 : +1);
+         p->left = NULL; p->right = s;
+         if (s != NULL) s->up = p;
+      }
+skip: /* now the specified node [p] has at least one empty subtree;
+         go upstairs to the root and adjust the rank field of all nodes
+         affected by deletion */
+      q = p; f = q->up;
+      while (f != NULL)
+      {  if (q->flag == 0) f->rank--;
+         q = f; f = q->up;
+      }
+      /* delete the specified node from the tree */
+      f = p->up; flag = p->flag;
+      q = p->left != NULL ? p->left : p->right;
+      if (f == NULL)
+         tree->root = q;
+      else
+         if (flag == 0) f->left = q; else f->right = q;
+      if (q != NULL) q->up = f, q->flag = flag;
+      tree->size--;
+      /* go upstairs to the root and correct all subtrees affected by
+         deletion */
+      while (f != NULL)
+      {  if (flag == 0)
+         {  /* the height of the left subtree of [f] is decreased */
+            if (f->bal == 0)
+            {  f->bal = +1;
+               break;
+            }
+            if (f->bal < 0)
+               f->bal = 0;
+            else
+            {  f = rotate_subtree(tree, f);
+               if (f->bal < 0) break;
+            }
+            flag = f->flag; f = f->up;
+         }
+         else
+         {  /* the height of the right subtree of [f] is decreased */
+            if (f->bal == 0)
+            {  f->bal = -1;
+               break;
+            }
+            if (f->bal > 0)
+               f->bal = 0;
+            else
+            {  f = rotate_subtree(tree, f);
+               if (f->bal > 0) break;
+            }
+            flag = f->flag; f = f->up;
+         }
+      }
+      /* if the root has been reached, the height of the entire tree is
+         decreased */
+      if (f == NULL) tree->height--;
+      /* returns the deleted node to the memory pool */
+      dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
+      return;
+}
+
+static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
+{     /* restore balance of AVL subtree */
+      AVLNODE *f, *p, *q, *r, *x, *y;
+      xassert(node != NULL);
+      p = node;
+      if (p->bal < 0)
+      {  /* perform negative (left) rotation */
+         f = p->up; q = p->left; r = q->right;
+         if (q->bal <= 0)
+         {  /* perform single negative rotation */
+            if (f == NULL)
+               tree->root = q;
+            else
+               if (p->flag == 0) f->left = q; else f->right = q;
+            p->rank -= q->rank;
+            q->up = f; q->flag = p->flag; q->bal++; q->right = p;
+            p->up = q; p->flag = 1;
+            p->bal = (short int)(-q->bal); p->left = r;
+            if (r != NULL) r->up = p, r->flag = 0;
+            node = q;
+         }
+         else
+         {  /* perform double negative rotation */
+            x = r->left; y = r->right;
+            if (f == NULL)
+               tree->root = r;
+            else
+               if (p->flag == 0) f->left = r; else f->right = r;
+            p->rank -= (q->rank + r->rank);
+            r->rank += q->rank;
+            p->bal = (short int)(r->bal >= 0 ? 0 : +1);
+            q->bal = (short int)(r->bal <= 0 ? 0 : -1);
+            r->up = f; r->flag = p->flag; r->bal = 0;
+            r->left = q; r->right = p;
+            p->up = r; p->flag = 1; p->left = y;
+            q->up = r; q->flag = 0; q->right = x;
+            if (x != NULL) x->up = q, x->flag = 1;
+            if (y != NULL) y->up = p, y->flag = 0;
+            node = r;
+         }
+      }
+      else
+      {  /* perform positive (right) rotation */
+         f = p->up; q = p->right; r = q->left;
+         if (q->bal >= 0)
+         {  /* perform single positive rotation */
+            if (f == NULL)
+               tree->root = q;
+            else
+               if (p->flag == 0) f->left = q; else f->right = q;
+            q->rank += p->rank;
+            q->up = f; q->flag = p->flag; q->bal--; q->left = p;
+            p->up = q; p->flag = 0;
+            p->bal = (short int)(-q->bal); p->right = r;
+            if (r != NULL) r->up = p, r->flag = 1;
+            node = q;
+         }
+         else
+         {  /* perform double positive rotation */
+            x = r->left; y = r->right;
+            if (f == NULL)
+               tree->root = r;
+            else
+               if (p->flag == 0) f->left = r; else f->right = r;
+            q->rank -= r->rank;
+            r->rank += p->rank;
+            p->bal = (short int)(r->bal <= 0 ? 0 : -1);
+            q->bal = (short int)(r->bal >= 0 ? 0 : +1);
+            r->up = f; r->flag = p->flag; r->bal = 0;
+            r->left = p; r->right = q;
+            p->up = r; p->flag = 0; p->right = x;
+            q->up = r; q->flag = 1; q->left = y;
+            if (x != NULL) x->up = p, x->flag = 1;
+            if (y != NULL) y->up = q, y->flag = 0;
+            node = r;
+         }
+      }
+      return node;
+}
+
+void avl_delete_tree(AVL *tree)
+{     /* delete AVL tree */
+      dmp_delete_pool(tree->pool);
+      xfree(tree);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpavl.h b/optional/glpk/glpavl.h
new file mode 100644
index 0000000..e00900a
--- /dev/null
+++ b/optional/glpk/glpavl.h
@@ -0,0 +1,123 @@
+/* glpavl.h (binary search tree) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPAVL_H
+#define GLPAVL_H
+
+#include "glpdmp.h"
+
+typedef struct AVL AVL;
+typedef struct AVLNODE AVLNODE;
+
+struct AVL
+{     /* AVL tree (Adelson-Velsky & Landis binary search tree) */
+      DMP *pool;
+      /* memory pool for allocating nodes */
+      AVLNODE *root;
+      /* pointer to the root node */
+      int (*fcmp)(void *info, const void *key1, const void *key2);
+      /* application-defined key comparison routine */
+      void *info;
+      /* transit pointer passed to the routine fcmp */
+      int size;
+      /* the tree size (the total number of nodes) */
+      int height;
+      /* the tree height */
+};
+
+struct AVLNODE
+{     /* node of AVL tree */
+      const void *key;
+      /* pointer to the node key (data structure for representing keys
+         is supplied by the application) */
+      int rank;
+      /* node rank = relative position of the node in its own subtree =
+         the number of nodes in the left subtree plus one */
+      int type;
+      /* reserved for the application specific information */
+      void *link;
+      /* reserved for the application specific information */
+      AVLNODE *up;
+      /* pointer to the parent node */
+      short int flag;
+      /* node flag:
+         0 - this node is the left child of its parent (or this node is
+             the root of the tree and has no parent)
+         1 - this node is the right child of its parent */
+      short int bal;
+      /* node balance = the difference between heights of the right and
+         left subtrees:
+         -1 - the left subtree is higher than the right one;
+          0 - the left and right subtrees have the same height;
+         +1 - the left subtree is lower than the right one */
+      AVLNODE *left;
+      /* pointer to the root of the left subtree */
+      AVLNODE *right;
+      /* pointer to the root of the right subtree */
+};
+
+#define avl_create_tree _glp_avl_create_tree
+AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
+      const void *key2), void *info);
+/* create AVL tree */
+
+#define avl_strcmp _glp_avl_strcmp
+int avl_strcmp(void *info, const void *key1, const void *key2);
+/* compare character string keys */
+
+#define avl_insert_node _glp_avl_insert_node
+AVLNODE *avl_insert_node(AVL *tree, const void *key);
+/* insert new node into AVL tree */
+
+#define avl_set_node_type _glp_avl_set_node_type
+void avl_set_node_type(AVLNODE *node, int type);
+/* assign the type field of specified node */
+
+#define avl_set_node_link _glp_avl_set_node_link
+void avl_set_node_link(AVLNODE *node, void *link);
+/* assign the link field of specified node */
+
+#define avl_find_node _glp_avl_find_node
+AVLNODE *avl_find_node(AVL *tree, const void *key);
+/* find node in AVL tree */
+
+#define avl_get_node_type _glp_avl_get_node_type
+int avl_get_node_type(AVLNODE *node);
+/* retrieve the type field of specified node */
+
+#define avl_get_node_link _glp_avl_get_node_link
+void *avl_get_node_link(AVLNODE *node);
+/* retrieve the link field of specified node */
+
+#define avl_delete_node _glp_avl_delete_node
+void avl_delete_node(AVL *tree, AVLNODE *node);
+/* delete specified node from AVL tree */
+
+#define avl_delete_tree _glp_avl_delete_tree
+void avl_delete_tree(AVL *tree);
+/* delete AVL tree */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpbfd.c b/optional/glpk/glpbfd.c
new file mode 100644
index 0000000..4b67a29
--- /dev/null
+++ b/optional/glpk/glpbfd.c
@@ -0,0 +1,485 @@
+/* glpbfd.c (LP basis factorization driver) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#endif
+
+typedef struct BFD BFD;
+
+#define GLPBFD_PRIVATE
+#include "glpapi.h"
+#include "glpfhv.h"
+#include "glplpf.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the basis matrix */
+
+struct BFD
+{     /* LP basis factorization */
+      int valid;
+      /* factorization is valid only if this flag is set */
+      int type;
+      /* factorization type:
+         GLP_BF_FT - LUF + Forrest-Tomlin
+         GLP_BF_BG - LUF + Schur compl. + Bartels-Golub
+         GLP_BF_GR - LUF + Schur compl. + Givens rotation */
+      FHV *fhv;
+      /* LP basis factorization (GLP_BF_FT) */
+      LPF *lpf;
+      /* LP basis factorization (GLP_BF_BG, GLP_BF_GR) */
+      int lu_size;      /* luf.sv_size */
+      double piv_tol;   /* luf.piv_tol */
+      int piv_lim;      /* luf.piv_lim */
+      int suhl;         /* luf.suhl */
+      double eps_tol;   /* luf.eps_tol */
+      double max_gro;   /* luf.max_gro */
+      int nfs_max;      /* fhv.hh_max */
+      double upd_tol;   /* fhv.upd_tol */
+      int nrs_max;      /* lpf.n_max */
+      int rs_size;      /* lpf.v_size */
+      /* internal control parameters */
+      int upd_lim;
+      /* the factorization update limit */
+      int upd_cnt;
+      /* the factorization update count */
+};
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_create_it - create LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  BFD *bfd_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_create_it creates a program object, which represents
+*  a factorization of LP basis.
+*
+*  RETURNS
+*
+*  The routine bfd_create_it returns a pointer to the object created. */
+
+BFD *bfd_create_it(void)
+{     BFD *bfd;
+      bfd = xmalloc(sizeof(BFD));
+      bfd->valid = 0;
+      bfd->type = GLP_BF_FT;
+      bfd->fhv = NULL;
+      bfd->lpf = NULL;
+      bfd->lu_size = 0;
+      bfd->piv_tol = 0.10;
+      bfd->piv_lim = 4;
+      bfd->suhl = 1;
+      bfd->eps_tol = 1e-15;
+      bfd->max_gro = 1e+10;
+      bfd->nfs_max = 100;
+      bfd->upd_tol = 1e-6;
+      bfd->nrs_max = 100;
+      bfd->rs_size = 1000;
+      bfd->upd_lim = -1;
+      bfd->upd_cnt = 0;
+      return bfd;
+}
+
+/**********************************************************************/
+
+void bfd_set_parm(BFD *bfd, const void *_parm)
+{     /* change LP basis factorization control parameters */
+      const glp_bfcp *parm = _parm;
+      xassert(bfd != NULL);
+      bfd->type = parm->type;
+      bfd->lu_size = parm->lu_size;
+      bfd->piv_tol = parm->piv_tol;
+      bfd->piv_lim = parm->piv_lim;
+      bfd->suhl = parm->suhl;
+      bfd->eps_tol = parm->eps_tol;
+      bfd->max_gro = parm->max_gro;
+      bfd->nfs_max = parm->nfs_max;
+      bfd->upd_tol = parm->upd_tol;
+      bfd->nrs_max = parm->nrs_max;
+      bfd->rs_size = parm->rs_size;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_factorize - compute LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  int bfd_factorize(BFD *bfd, int m, int bh[], int (*col)(void *info,
+*     int j, int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_factorize computes the factorization of the basis
+*  matrix B specified by the routine col.
+*
+*  The parameter bfd specified the basis factorization data structure
+*  created with the routine bfd_create_it.
+*
+*  The parameter m specifies the order of B, m > 0.
+*
+*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
+*  number of j-th column of B in some original matrix. The array bh is
+*  optional and can be specified as NULL.
+*
+*  The formal routine col specifies the matrix B to be factorized. To
+*  obtain j-th column of A the routine bfd_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully computed.
+*
+*  BFD_ESING
+*     The specified matrix is singular within the working precision.
+*
+*  BFD_ECOND
+*     The specified matrix is ill-conditioned.
+*
+*  For more details see comments to the routine luf_factorize. */
+
+int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info)
+{     LUF *luf;
+      int nov, ret;
+      xassert(bfd != NULL);
+      xassert(1 <= m && m <= M_MAX);
+      /* invalidate the factorization */
+      bfd->valid = 0;
+      /* create the factorization, if necessary */
+      nov = 0;
+      switch (bfd->type)
+      {  case GLP_BF_FT:
+            if (bfd->lpf != NULL)
+               lpf_delete_it(bfd->lpf), bfd->lpf = NULL;
+            if (bfd->fhv == NULL)
+               bfd->fhv = fhv_create_it(), nov = 1;
+            break;
+         case GLP_BF_BG:
+         case GLP_BF_GR:
+            if (bfd->fhv != NULL)
+               fhv_delete_it(bfd->fhv), bfd->fhv = NULL;
+            if (bfd->lpf == NULL)
+               bfd->lpf = lpf_create_it(), nov = 1;
+            break;
+         default:
+            xassert(bfd != bfd);
+      }
+      /* set control parameters specific to LUF */
+      if (bfd->fhv != NULL)
+         luf = bfd->fhv->luf;
+      else if (bfd->lpf != NULL)
+         luf = bfd->lpf->luf;
+      else
+         xassert(bfd != bfd);
+      if (nov) luf->new_sva = bfd->lu_size;
+      luf->piv_tol = bfd->piv_tol;
+      luf->piv_lim = bfd->piv_lim;
+      luf->suhl = bfd->suhl;
+      luf->eps_tol = bfd->eps_tol;
+      luf->max_gro = bfd->max_gro;
+      /* set control parameters specific to FHV */
+      if (bfd->fhv != NULL)
+      {  if (nov) bfd->fhv->hh_max = bfd->nfs_max;
+         bfd->fhv->upd_tol = bfd->upd_tol;
+      }
+      /* set control parameters specific to LPF */
+      if (bfd->lpf != NULL)
+      {  if (nov) bfd->lpf->n_max = bfd->nrs_max;
+         if (nov) bfd->lpf->v_size = bfd->rs_size;
+      }
+      /* try to factorize the basis matrix */
+      if (bfd->fhv != NULL)
+      {  switch (fhv_factorize(bfd->fhv, m, col, info))
+         {  case 0:
+               break;
+            case FHV_ESING:
+               ret = BFD_ESING;
+               goto done;
+            case FHV_ECOND:
+               ret = BFD_ECOND;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else if (bfd->lpf != NULL)
+      {  switch (lpf_factorize(bfd->lpf, m, bh, col, info))
+         {  case 0:
+               /* set the Schur complement update type */
+               switch (bfd->type)
+               {  case GLP_BF_BG:
+                     /* Bartels-Golub update */
+                     bfd->lpf->scf->t_opt = SCF_TBG;
+                     break;
+                  case GLP_BF_GR:
+                     /* Givens rotation update */
+                     bfd->lpf->scf->t_opt = SCF_TGR;
+                     break;
+                  default:
+                     xassert(bfd != bfd);
+               }
+               break;
+            case LPF_ESING:
+               ret = BFD_ESING;
+               goto done;
+            case LPF_ECOND:
+               ret = BFD_ECOND;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else
+         xassert(bfd != bfd);
+      /* the basis matrix has been successfully factorized */
+      bfd->valid = 1;
+      bfd->upd_cnt = 0;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  void bfd_ftran(BFD *bfd, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void bfd_ftran(BFD *bfd, double x[])
+{     xassert(bfd != NULL);
+      xassert(bfd->valid);
+      if (bfd->fhv != NULL)
+         fhv_ftran(bfd->fhv, x);
+      else if (bfd->lpf != NULL)
+         lpf_ftran(bfd->lpf, x);
+      else
+         xassert(bfd != bfd);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  void bfd_btran(BFD *bfd, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix B, x is the vector of unknowns to be computed, b is the vector
+*  of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void bfd_btran(BFD *bfd, double x[])
+{     xassert(bfd != NULL);
+      xassert(bfd->valid);
+      if (bfd->fhv != NULL)
+         fhv_btran(bfd->fhv, x);
+      else if (bfd->lpf != NULL)
+         lpf_btran(bfd->lpf, x);
+      else
+         xassert(bfd != bfd);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_update_it - update LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_update_it updates the factorization of the basis
+*  matrix B after replacing its j-th column by a new vector.
+*
+*  The parameter j specifies the number of column of B, which has been
+*  replaced, 1 <= j <= m, where m is the order of B.
+*
+*  The parameter bh specifies the basis header entry for the new column
+*  of B, which is the number of the new column in some original matrix.
+*  This parameter is optional and can be specified as 0.
+*
+*  Row indices and numerical values of non-zero elements of the new
+*  column of B should be placed in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], resp., where len is the number of non-zeros
+*  in the column. Neither zero nor duplicate elements are allowed.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  BFD_ESING
+*     New basis matrix is singular within the working precision.
+*
+*  BFD_ECHECK
+*     The factorization is inaccurate.
+*
+*  BFD_ELIMIT
+*     Factorization update limit has been reached.
+*
+*  BFD_EROOM
+*     Overflow of the sparse vector area.
+*
+*  In case of non-zero return code the factorization becomes invalid.
+*  It should not be used until it has been recomputed with the routine
+*  bfd_factorize. */
+
+int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
+      const double val[])
+{     int ret;
+      xassert(bfd != NULL);
+      xassert(bfd->valid);
+      /* try to update the factorization */
+      if (bfd->fhv != NULL)
+      {  switch (fhv_update_it(bfd->fhv, j, len, ind, val))
+         {  case 0:
+               break;
+            case FHV_ESING:
+               bfd->valid = 0;
+               ret = BFD_ESING;
+               goto done;
+            case FHV_ECHECK:
+               bfd->valid = 0;
+               ret = BFD_ECHECK;
+               goto done;
+            case FHV_ELIMIT:
+               bfd->valid = 0;
+               ret = BFD_ELIMIT;
+               goto done;
+            case FHV_EROOM:
+               bfd->valid = 0;
+               ret = BFD_EROOM;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else if (bfd->lpf != NULL)
+      {  switch (lpf_update_it(bfd->lpf, j, bh, len, ind, val))
+         {  case 0:
+               break;
+            case LPF_ESING:
+               bfd->valid = 0;
+               ret = BFD_ESING;
+               goto done;
+            case LPF_ELIMIT:
+               bfd->valid = 0;
+               ret = BFD_ELIMIT;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else
+         xassert(bfd != bfd);
+      /* the factorization has been successfully updated */
+      /* increase the update count */
+      bfd->upd_cnt++;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/**********************************************************************/
+
+int bfd_get_count(BFD *bfd)
+{     /* determine factorization update count */
+      xassert(bfd != NULL);
+      xassert(bfd->valid);
+      return bfd->upd_cnt;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_delete_it - delete LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  void bfd_delete_it(BFD *bfd);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_delete_it deletes LP basis factorization specified
+*  by the parameter fhv and frees all memory allocated to this program
+*  object. */
+
+void bfd_delete_it(BFD *bfd)
+{     xassert(bfd != NULL);
+      if (bfd->fhv != NULL)
+         fhv_delete_it(bfd->fhv);
+      if (bfd->lpf != NULL)
+         lpf_delete_it(bfd->lpf);
+      xfree(bfd);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpbfd.h b/optional/glpk/glpbfd.h
new file mode 100644
index 0000000..47405c1
--- /dev/null
+++ b/optional/glpk/glpbfd.h
@@ -0,0 +1,75 @@
+/* glpbfd.h (LP basis factorization driver) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPBFD_H
+#define GLPBFD_H
+
+#ifndef GLPBFD_PRIVATE
+typedef struct { double _opaque_bfd[100]; } BFD;
+#endif
+
+/* return codes: */
+#define BFD_ESING    1  /* singular matrix */
+#define BFD_ECOND    2  /* ill-conditioned matrix */
+#define BFD_ECHECK   3  /* insufficient accuracy */
+#define BFD_ELIMIT   4  /* update limit reached */
+#define BFD_EROOM    5  /* SVA overflow */
+
+#define bfd_create_it _glp_bfd_create_it
+BFD *bfd_create_it(void);
+/* create LP basis factorization */
+
+#define bfd_set_parm _glp_bfd_set_parm
+void bfd_set_parm(BFD *bfd, const void *parm);
+/* change LP basis factorization control parameters */
+
+#define bfd_factorize _glp_bfd_factorize
+int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#define bfd_ftran _glp_bfd_ftran
+void bfd_ftran(BFD *bfd, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#define bfd_btran _glp_bfd_btran
+void bfd_btran(BFD *bfd, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#define bfd_update_it _glp_bfd_update_it
+int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
+      const double val[]);
+/* update LP basis factorization */
+
+#define bfd_get_count _glp_bfd_get_count
+int bfd_get_count(BFD *bfd);
+/* determine factorization update count */
+
+#define bfd_delete_it _glp_bfd_delete_it
+void bfd_delete_it(BFD *bfd);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpbfx.c b/optional/glpk/glpbfx.c
new file mode 100644
index 0000000..435bf7d
--- /dev/null
+++ b/optional/glpk/glpbfx.c
@@ -0,0 +1,91 @@
+/* glpbfx.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+typedef struct BFX BFX;
+#define GLPBFX_DEFINED
+#include "glpbfx.h"
+#include "glpenv.h"
+#include "glplux.h"
+
+struct BFX
+{     int valid;
+      LUX *lux;
+};
+
+BFX *bfx_create_binv(void)
+{     /* create factorization of the basis matrix */
+      BFX *bfx;
+      bfx = xmalloc(sizeof(BFX));
+      bfx->valid = 0;
+      bfx->lux = NULL;
+      return bfx;
+}
+
+int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
+      int ind[], mpq_t val[]), void *info)
+{     /* compute factorization of the basis matrix */
+      int ret;
+      xassert(m > 0);
+      if (binv->lux != NULL && binv->lux->n != m)
+      {  lux_delete(binv->lux);
+         binv->lux = NULL;
+      }
+      if (binv->lux == NULL)
+         binv->lux = lux_create(m);
+      ret = lux_decomp(binv->lux, col, info);
+      binv->valid = (ret == 0);
+      return ret;
+}
+
+void bfx_ftran(BFX *binv, mpq_t x[], int save)
+{     /* perform forward transformation (FTRAN) */
+      xassert(binv->valid);
+      lux_solve(binv->lux, 0, x);
+      xassert(save == save);
+      return;
+}
+
+void bfx_btran(BFX *binv, mpq_t x[])
+{     /* perform backward transformation (BTRAN) */
+      xassert(binv->valid);
+      lux_solve(binv->lux, 1, x);
+      return;
+}
+
+int bfx_update(BFX *binv, int j)
+{     /* update factorization of the basis matrix */
+      xassert(binv->valid);
+      xassert(1 <= j && j <= binv->lux->n);
+      return 1;
+}
+
+void bfx_delete_binv(BFX *binv)
+{     /* delete factorization of the basis matrix */
+      if (binv->lux != NULL)
+         lux_delete(binv->lux);
+      xfree(binv);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpbfx.h b/optional/glpk/glpbfx.h
new file mode 100644
index 0000000..0890aa9
--- /dev/null
+++ b/optional/glpk/glpbfx.h
@@ -0,0 +1,71 @@
+/* glpbfx.h (basis factorization interface, bignum arithmetic) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPBFX_H
+#define GLPBFX_H
+
+#include "glpgmp.h"
+
+#ifndef GLPBFX_DEFINED
+#define GLPBFX_DEFINED
+typedef struct { double _opaque_bfx; } BFX;
+#endif
+
+#define bfx_create_binv       _glp_bfx_create_binv
+#define bfx_is_valid          _glp_bfx_is_valid
+#define bfx_invalidate        _glp_bfx_invalidate
+#define bfx_factorize         _glp_bfx_factorize
+#define bfx_ftran             _glp_bfx_ftran
+#define bfx_btran             _glp_bfx_btran
+#define bfx_update            _glp_bfx_update
+#define bfx_delete_binv       _glp_bfx_delete_binv
+
+BFX *bfx_create_binv(void);
+/* create factorization of the basis matrix */
+
+int bfx_is_valid(BFX *binv);
+/* check if factorization is valid */
+
+void bfx_invalidate(BFX *binv);
+/* invalidate factorization of the basis matrix */
+
+int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
+      int ind[], mpq_t val[]), void *info);
+/* compute factorization of the basis matrix */
+
+void bfx_ftran(BFX *binv, mpq_t x[], int save);
+/* perform forward transformation (FTRAN) */
+
+void bfx_btran(BFX *binv, mpq_t x[]);
+/* perform backward transformation (BTRAN) */
+
+int bfx_update(BFX *binv, int j);
+/* update factorization of the basis matrix */
+
+void bfx_delete_binv(BFX *binv);
+/* delete factorization of the basis matrix */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpcpx.c b/optional/glpk/glpcpx.c
new file mode 100644
index 0000000..52f55dd
--- /dev/null
+++ b/optional/glpk/glpcpx.c
@@ -0,0 +1,1244 @@
+/* glpcpx.c (CPLEX LP format routines) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_cpxcp - initialize CPLEX LP format control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_cpxcp(glp_cpxcp *parm):
+*
+*  The routine glp_init_cpxcp initializes control parameters used by
+*  the CPLEX LP input/output routines glp_read_lp and glp_write_lp with
+*  default values.
+*
+*  Default values of the control parameters are stored in the glp_cpxcp
+*  structure, which the parameter parm points to. */
+
+void glp_init_cpxcp(glp_cpxcp *parm)
+{     xassert(parm != NULL);
+      return;
+}
+
+static void check_parm(const char *func, const glp_cpxcp *parm)
+{     /* check control parameters */
+      xassert(func != NULL);
+      xassert(parm != NULL);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_lp - read problem data in CPLEX LP format
+*
+*  SYNOPSIS
+*
+*  int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char
+*     *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_lp reads problem data in CPLEX LP format from
+*  a text file.
+*
+*  The parameter parm is a pointer to the structure glp_cpxcp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  read.
+*
+*  Note that before reading data the current content of the problem
+*  object is completely erased with the routine glp_erase_prob.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_read_lp returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* LP/MIP problem object */
+      const glp_cpxcp *parm;
+      /* pointer to control parameters */
+      const char *fname;
+      /* name of input CPLEX LP file */
+      XFILE *fp;
+      /* stream assigned to input CPLEX LP file */
+      jmp_buf jump;
+      /* label for go to in case of error */
+      int count;
+      /* line count */
+      int c;
+      /* current character or XEOF */
+      int token;
+      /* current token: */
+#define T_EOF        0x00  /* end of file */
+#define T_MINIMIZE   0x01  /* keyword 'minimize' */
+#define T_MAXIMIZE   0x02  /* keyword 'maximize' */
+#define T_SUBJECT_TO 0x03  /* keyword 'subject to' */
+#define T_BOUNDS     0x04  /* keyword 'bounds' */
+#define T_GENERAL    0x05  /* keyword 'general' */
+#define T_INTEGER    0x06  /* keyword 'integer' */
+#define T_BINARY     0x07  /* keyword 'binary' */
+#define T_END        0x08  /* keyword 'end' */
+#define T_NAME       0x09  /* symbolic name */
+#define T_NUMBER     0x0A  /* numeric constant */
+#define T_PLUS       0x0B  /* delimiter '+' */
+#define T_MINUS      0x0C  /* delimiter '-' */
+#define T_COLON      0x0D  /* delimiter ':' */
+#define T_LE         0x0E  /* delimiter '<=' */
+#define T_GE         0x0F  /* delimiter '>=' */
+#define T_EQ         0x10  /* delimiter '=' */
+      char image[255+1];
+      /* image of current token */
+      int imlen;
+      /* length of token image */
+      double value;
+      /* value of numeric constant */
+      int n_max;
+      /* length of the following five arrays (enlarged automatically,
+         if necessary) */
+      int *ind; /* int ind[1+n_max]; */
+      double *val; /* double val[1+n_max]; */
+      char *flag; /* char flag[1+n_max]; */
+      /* working arrays used to construct linear forms */
+      double *lb; /* double lb[1+n_max]; */
+      double *ub; /* double ub[1+n_max]; */
+      /* lower and upper bounds of variables (columns) */
+};
+
+#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~"
+/* characters, which may appear in symbolic names */
+
+static void error(struct csa *csa, const char *fmt, ...)
+{     /* print error message and terminate processing */
+      va_list arg;
+      xprintf("%s:%d: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      longjmp(csa->jump, 1);
+      /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{     /* print warning message and continue processing */
+      va_list arg;
+      xprintf("%s:%d: warning: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+static void read_char(struct csa *csa)
+{     /* read next character from input file */
+      int c;
+      xassert(csa->c != XEOF);
+      if (csa->c == '\n') csa->count++;
+      c = xfgetc(csa->fp);
+      if (c < 0)
+      {  if (xferror(csa->fp))
+            error(csa, "read error - %s\n", xerrmsg());
+         else if (csa->c == '\n')
+         {  csa->count--;
+            c = XEOF;
+         }
+         else
+         {  warning(csa, "missing final end of line\n");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+         error(csa, "invalid control character 0x%02X\n", c);
+      csa->c = c;
+      return;
+}
+
+static void add_char(struct csa *csa)
+{     /* append current character to current token */
+      if (csa->imlen == sizeof(csa->image)-1)
+         error(csa, "token `%.15s...' too long\n", csa->image);
+      csa->image[csa->imlen++] = (char)csa->c;
+      csa->image[csa->imlen] = '\0';
+      read_char(csa);
+      return;
+}
+
+static int the_same(char *s1, char *s2)
+{     /* compare two character strings ignoring case sensitivity */
+      for (; *s1 != '\0'; s1++, s2++)
+      {  if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2))
+            return 0;
+      }
+      return 1;
+}
+
+static void scan_token(struct csa *csa)
+{     /* scan next token */
+      int flag;
+      csa->token = -1;
+      csa->image[0] = '\0';
+      csa->imlen = 0;
+      csa->value = 0.0;
+loop: flag = 0;
+      /* skip non-significant characters */
+      while (csa->c == ' ') read_char(csa);
+      /* recognize and scan current token */
+      if (csa->c == XEOF)
+         csa->token = T_EOF;
+      else if (csa->c == '\n')
+      {  read_char(csa);
+         /* if the next character is letter, it may begin a keyword */
+         if (isalpha(csa->c))
+         {  flag = 1;
+            goto name;
+         }
+         goto loop;
+      }
+      else if (csa->c == '\\')
+      {  /* comment; ignore everything until end-of-line */
+         while (csa->c != '\n') read_char(csa);
+         goto loop;
+      }
+      else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET,
+         csa->c) != NULL)
+name: {  /* symbolic name */
+         csa->token = T_NAME;
+         while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL)
+            add_char(csa);
+         if (flag)
+         {  /* check for keyword */
+            if (the_same(csa->image, "minimize"))
+               csa->token = T_MINIMIZE;
+            else if (the_same(csa->image, "minimum"))
+               csa->token = T_MINIMIZE;
+            else if (the_same(csa->image, "min"))
+               csa->token = T_MINIMIZE;
+            else if (the_same(csa->image, "maximize"))
+               csa->token = T_MAXIMIZE;
+            else if (the_same(csa->image, "maximum"))
+               csa->token = T_MAXIMIZE;
+            else if (the_same(csa->image, "max"))
+               csa->token = T_MAXIMIZE;
+            else if (the_same(csa->image, "subject"))
+            {  if (csa->c == ' ')
+               {  read_char(csa);
+                  if (tolower(csa->c) == 't')
+                  {  csa->token = T_SUBJECT_TO;
+                     csa->image[csa->imlen++] = ' ';
+                     csa->image[csa->imlen] = '\0';
+                     add_char(csa);
+                     if (tolower(csa->c) != 'o')
+                        error(csa, "keyword `subject to' incomplete\n");
+                     add_char(csa);
+                     if (isalpha(csa->c))
+                        error(csa, "keyword `%s%c...' not recognized\n",
+                           csa->image, csa->c);
+                  }
+               }
+            }
+            else if (the_same(csa->image, "such"))
+            {  if (csa->c == ' ')
+               {  read_char(csa);
+                  if (tolower(csa->c) == 't')
+                  {  csa->token = T_SUBJECT_TO;
+                     csa->image[csa->imlen++] = ' ';
+                     csa->image[csa->imlen] = '\0';
+                     add_char(csa);
+                     if (tolower(csa->c) != 'h')
+err:                    error(csa, "keyword `such that' incomplete\n");
+                     add_char(csa);
+                     if (tolower(csa->c) != 'a') goto err;
+                     add_char(csa);
+                     if (tolower(csa->c) != 't') goto err;
+                     add_char(csa);
+                     if (isalpha(csa->c))
+                        error(csa, "keyword `%s%c...' not recognized\n",
+                           csa->image, csa->c);
+                  }
+               }
+            }
+            else if (the_same(csa->image, "st"))
+               csa->token = T_SUBJECT_TO;
+            else if (the_same(csa->image, "s.t."))
+               csa->token = T_SUBJECT_TO;
+            else if (the_same(csa->image, "st."))
+               csa->token = T_SUBJECT_TO;
+            else if (the_same(csa->image, "bounds"))
+               csa->token = T_BOUNDS;
+            else if (the_same(csa->image, "bound"))
+               csa->token = T_BOUNDS;
+            else if (the_same(csa->image, "general"))
+               csa->token = T_GENERAL;
+            else if (the_same(csa->image, "generals"))
+               csa->token = T_GENERAL;
+            else if (the_same(csa->image, "gen"))
+               csa->token = T_GENERAL;
+            else if (the_same(csa->image, "integer"))
+               csa->token = T_INTEGER;
+            else if (the_same(csa->image, "integers"))
+               csa->token = T_INTEGER;
+            else if (the_same(csa->image, "int"))
+              csa->token = T_INTEGER;
+            else if (the_same(csa->image, "binary"))
+               csa->token = T_BINARY;
+            else if (the_same(csa->image, "binaries"))
+               csa->token = T_BINARY;
+            else if (the_same(csa->image, "bin"))
+               csa->token = T_BINARY;
+            else if (the_same(csa->image, "end"))
+               csa->token = T_END;
+         }
+      }
+      else if (isdigit(csa->c) || csa->c == '.')
+      {  /* numeric constant */
+         csa->token = T_NUMBER;
+         /* scan integer part */
+         while (isdigit(csa->c)) add_char(csa);
+         /* scan optional fractional part (it is mandatory, if there is
+            no integer part) */
+         if (csa->c == '.')
+         {  add_char(csa);
+            if (csa->imlen == 1 && !isdigit(csa->c))
+               error(csa, "invalid use of decimal point\n");
+            while (isdigit(csa->c)) add_char(csa);
+         }
+         /* scan optional decimal exponent */
+         if (csa->c == 'e' || csa->c == 'E')
+         {  add_char(csa);
+            if (csa->c == '+' || csa->c == '-') add_char(csa);
+            if (!isdigit(csa->c))
+               error(csa, "numeric constant `%s' incomplete\n",
+                  csa->image);
+            while (isdigit(csa->c)) add_char(csa);
+         }
+         /* convert the numeric constant to floating-point */
+         if (str2num(csa->image, &csa->value))
+            error(csa, "numeric constant `%s' out of range\n",
+               csa->image);
+      }
+      else if (csa->c == '+')
+         csa->token = T_PLUS, add_char(csa);
+      else if (csa->c == '-')
+         csa->token = T_MINUS, add_char(csa);
+      else if (csa->c == ':')
+         csa->token = T_COLON, add_char(csa);
+      else if (csa->c == '<')
+      {  csa->token = T_LE, add_char(csa);
+         if (csa->c == '=') add_char(csa);
+      }
+      else if (csa->c == '>')
+      {  csa->token = T_GE, add_char(csa);
+         if (csa->c == '=') add_char(csa);
+      }
+      else if (csa->c == '=')
+      {  csa->token = T_EQ, add_char(csa);
+         if (csa->c == '<')
+            csa->token = T_LE, add_char(csa);
+         else if (csa->c == '>')
+            csa->token = T_GE, add_char(csa);
+      }
+      else
+         error(csa, "character `%c' not recognized\n", csa->c);
+      /* skip non-significant characters */
+      while (csa->c == ' ') read_char(csa);
+      return;
+}
+
+static int find_col(struct csa *csa, char *name)
+{     /* find column by its symbolic name */
+      int j;
+      j = glp_find_col(csa->P, name);
+      if (j == 0)
+      {  /* not found; create new column */
+         j = glp_add_cols(csa->P, 1);
+         glp_set_col_name(csa->P, j, name);
+         /* enlarge working arrays, if necessary */
+         if (csa->n_max < j)
+         {  int n_max = csa->n_max;
+            int *ind = csa->ind;
+            double *val = csa->val;
+            char *flag = csa->flag;
+            double *lb = csa->lb;
+            double *ub = csa->ub;
+            csa->n_max += csa->n_max;
+            csa->ind = xcalloc(1+csa->n_max, sizeof(int));
+            memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int));
+            xfree(ind);
+            csa->val = xcalloc(1+csa->n_max, sizeof(double));
+            memcpy(&csa->val[1], &val[1], n_max * sizeof(double));
+            xfree(val);
+            csa->flag = xcalloc(1+csa->n_max, sizeof(char));
+            memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
+            memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char));
+            xfree(flag);
+            csa->lb = xcalloc(1+csa->n_max, sizeof(double));
+            memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double));
+            xfree(lb);
+            csa->ub = xcalloc(1+csa->n_max, sizeof(double));
+            memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double));
+            xfree(ub);
+         }
+         csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX;
+      }
+      return j;
+}
+
+/***********************************************************************
+*  parse_linear_form - parse linear form
+*
+*  This routine parses the linear form using the following syntax:
+*
+*  <variable> ::= <symbolic name>
+*  <coefficient> ::= <numeric constant>
+*  <term> ::= <variable> | <numeric constant> <variable>
+*  <linear form> ::= <term> | + <term> | - <term> |
+*     <linear form> + <term> | <linear form> - <term>
+*
+*  The routine returns the number of terms in the linear form. */
+
+static int parse_linear_form(struct csa *csa)
+{     int j, k, len = 0, newlen;
+      double s, coef;
+loop: /* parse an optional sign */
+      if (csa->token == T_PLUS)
+         s = +1.0, scan_token(csa);
+      else if (csa->token == T_MINUS)
+         s = -1.0, scan_token(csa);
+      else
+         s = +1.0;
+      /* parse an optional coefficient */
+      if (csa->token == T_NUMBER)
+         coef = csa->value, scan_token(csa);
+      else
+         coef = 1.0;
+      /* parse a variable name */
+      if (csa->token != T_NAME)
+         error(csa, "missing variable name\n");
+      /* find the corresponding column */
+      j = find_col(csa, csa->image);
+      /* check if the variable is already used in the linear form */
+      if (csa->flag[j])
+         error(csa, "multiple use of variable `%s' not allowed\n",
+            csa->image);
+      /* add new term to the linear form */
+      len++, csa->ind[len] = j, csa->val[len] = s * coef;
+      /* and mark that the variable is used in the linear form */
+      csa->flag[j] = 1;
+      scan_token(csa);
+      /* if the next token is a sign, there is another term */
+      if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop;
+      /* clear marks of the variables used in the linear form */
+      for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0;
+      /* remove zero coefficients */
+      newlen = 0;
+      for (k = 1; k <= len; k++)
+      {  if (csa->val[k] != 0.0)
+         {  newlen++;
+            csa->ind[newlen] = csa->ind[k];
+            csa->val[newlen] = csa->val[k];
+         }
+      }
+      return newlen;
+}
+
+/***********************************************************************
+*  parse_objective - parse objective function
+*
+*  This routine parses definition of the objective function using the
+*  following syntax:
+*
+*  <obj sense> ::= minimize | minimum | min | maximize | maximum | max
+*  <obj name> ::= <empty> | <symbolic name> :
+*  <obj function> ::= <obj sense> <obj name> <linear form> */
+
+static void parse_objective(struct csa *csa)
+{     /* parse objective sense */
+      int k, len;
+      /* parse the keyword 'minimize' or 'maximize' */
+      if (csa->token == T_MINIMIZE)
+         glp_set_obj_dir(csa->P, GLP_MIN);
+      else if (csa->token == T_MAXIMIZE)
+         glp_set_obj_dir(csa->P, GLP_MAX);
+      else
+         xassert(csa != csa);
+      scan_token(csa);
+      /* parse objective name */
+      if (csa->token == T_NAME && csa->c == ':')
+      {  /* objective name is followed by a colon */
+         glp_set_obj_name(csa->P, csa->image);
+         scan_token(csa);
+         xassert(csa->token == T_COLON);
+         scan_token(csa);
+      }
+      else
+      {  /* objective name is not specified; use default */
+         glp_set_obj_name(csa->P, "obj");
+      }
+      /* parse linear form */
+      len = parse_linear_form(csa);
+      for (k = 1; k <= len; k++)
+         glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]);
+      return;
+}
+
+/***********************************************************************
+*  parse_constraints - parse constraints section
+*
+*  This routine parses the constraints section using the following
+*  syntax:
+*
+*  <row name> ::= <empty> | <symbolic name> :
+*  <row sense> ::= < | <= | =< | > | >= | => | =
+*  <right-hand side> ::= <numeric constant> | + <numeric constant> |
+*     - <numeric constant>
+*  <constraint> ::= <row name> <linear form> <row sense>
+*     <right-hand side>
+*  <subject to> ::= subject to | such that | st | s.t. | st.
+*  <constraints section> ::= <subject to> <constraint> |
+*     <constraints section> <constraint> */
+
+static void parse_constraints(struct csa *csa)
+{     int i, len, type;
+      double s;
+      /* parse the keyword 'subject to' */
+      xassert(csa->token == T_SUBJECT_TO);
+      scan_token(csa);
+loop: /* create new row (constraint) */
+      i = glp_add_rows(csa->P, 1);
+      /* parse row name */
+      if (csa->token == T_NAME && csa->c == ':')
+      {  /* row name is followed by a colon */
+         if (glp_find_row(csa->P, csa->image) != 0)
+            error(csa, "constraint `%s' multiply defined\n",
+               csa->image);
+         glp_set_row_name(csa->P, i, csa->image);
+         scan_token(csa);
+         xassert(csa->token == T_COLON);
+         scan_token(csa);
+      }
+      else
+      {  /* row name is not specified; use default */
+         char name[50];
+         sprintf(name, "r.%d", csa->count);
+         glp_set_row_name(csa->P, i, name);
+      }
+      /* parse linear form */
+      len = parse_linear_form(csa);
+      glp_set_mat_row(csa->P, i, len, csa->ind, csa->val);
+      /* parse constraint sense */
+      if (csa->token == T_LE)
+         type = GLP_UP, scan_token(csa);
+      else if (csa->token == T_GE)
+         type = GLP_LO, scan_token(csa);
+      else if (csa->token == T_EQ)
+         type = GLP_FX, scan_token(csa);
+      else
+         error(csa, "missing constraint sense\n");
+      /* parse right-hand side */
+      if (csa->token == T_PLUS)
+         s = +1.0, scan_token(csa);
+      else if (csa->token == T_MINUS)
+         s = -1.0, scan_token(csa);
+      else
+         s = +1.0;
+      if (csa->token != T_NUMBER)
+         error(csa, "missing right-hand side\n");
+      glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value);
+      /* the rest of the current line must be empty */
+      if (!(csa->c == '\n' || csa->c == XEOF))
+         error(csa, "invalid symbol(s) beyond right-hand side\n");
+      scan_token(csa);
+      /* if the next token is a sign, numeric constant, or a symbolic
+         name, here is another constraint */
+      if (csa->token == T_PLUS || csa->token == T_MINUS ||
+          csa->token == T_NUMBER || csa->token == T_NAME) goto loop;
+      return;
+}
+
+static void set_lower_bound(struct csa *csa, int j, double lb)
+{     /* set lower bound of j-th variable */
+      if (csa->lb[j] != +DBL_MAX)
+      {  warning(csa, "lower bound of variable `%s' redefined\n",
+            glp_get_col_name(csa->P, j));
+      }
+      csa->lb[j] = lb;
+      return;
+}
+
+static void set_upper_bound(struct csa *csa, int j, double ub)
+{     /* set upper bound of j-th variable */
+      if (csa->ub[j] != -DBL_MAX)
+      {  warning(csa, "upper bound of variable `%s' redefined\n",
+            glp_get_col_name(csa->P, j));
+      }
+      csa->ub[j] = ub;
+      return;
+}
+
+/***********************************************************************
+*  parse_bounds - parse bounds section
+*
+*  This routine parses the bounds section using the following syntax:
+*
+*  <variable> ::= <symbolic name>
+*  <infinity> ::= infinity | inf
+*  <bound> ::= <numeric constant> | + <numeric constant> |
+*     - <numeric constant> | + <infinity> | - <infinity>
+*  <lt> ::= < | <= | =<
+*  <gt> ::= > | >= | =>
+*  <bound definition> ::= <bound> <lt> <variable> <lt> <bound> |
+*     <bound> <lt> <variable> | <variable> <lt> <bound> |
+*     <variable> <gt> <bound> | <variable> = <bound> | <variable> free
+*  <bounds> ::= bounds | bound
+*  <bounds section> ::= <bounds> |
+*     <bounds section> <bound definition> */
+
+static void parse_bounds(struct csa *csa)
+{     int j, lb_flag;
+      double lb, s;
+      /* parse the keyword 'bounds' */
+      xassert(csa->token == T_BOUNDS);
+      scan_token(csa);
+loop: /* bound definition can start with a sign, numeric constant, or
+         a symbolic name */
+      if (!(csa->token == T_PLUS || csa->token == T_MINUS ||
+            csa->token == T_NUMBER || csa->token == T_NAME)) goto done;
+      /* parse bound definition */
+      if (csa->token == T_PLUS || csa->token == T_MINUS)
+      {  /* parse signed lower bound */
+         lb_flag = 1;
+         s = (csa->token == T_PLUS ? +1.0 : -1.0);
+         scan_token(csa);
+         if (csa->token == T_NUMBER)
+            lb = s * csa->value, scan_token(csa);
+         else if (the_same(csa->image, "infinity") ||
+                  the_same(csa->image, "inf"))
+         {  if (s > 0.0)
+               error(csa, "invalid use of `+inf' as lower bound\n");
+            lb = -DBL_MAX, scan_token(csa);
+         }
+         else
+            error(csa, "missing lower bound\n");
+      }
+      else if (csa->token == T_NUMBER)
+      {  /* parse unsigned lower bound */
+         lb_flag = 1;
+         lb = csa->value, scan_token(csa);
+      }
+      else
+      {  /* lower bound is not specified */
+         lb_flag = 0;
+      }
+      /* parse the token that should follow the lower bound */
+      if (lb_flag)
+      {  if (csa->token != T_LE)
+            error(csa, "missing `<', `<=', or `=<' after lower bound\n")
+               ;
+         scan_token(csa);
+      }
+      /* parse variable name */
+      if (csa->token != T_NAME)
+         error(csa, "missing variable name\n");
+      j = find_col(csa, csa->image);
+      /* set lower bound */
+      if (lb_flag) set_lower_bound(csa, j, lb);
+      scan_token(csa);
+      /* parse the context that follows the variable name */
+      if (csa->token == T_LE)
+      {  /* parse upper bound */
+         scan_token(csa);
+         if (csa->token == T_PLUS || csa->token == T_MINUS)
+         {  /* parse signed upper bound */
+            s = (csa->token == T_PLUS ? +1.0 : -1.0);
+            scan_token(csa);
+            if (csa->token == T_NUMBER)
+            {  set_upper_bound(csa, j, s * csa->value);
+               scan_token(csa);
+            }
+            else if (the_same(csa->image, "infinity") ||
+                     the_same(csa->image, "inf"))
+            {  if (s < 0.0)
+                  error(csa, "invalid use of `-inf' as upper bound\n");
+               set_upper_bound(csa, j, +DBL_MAX);
+               scan_token(csa);
+            }
+            else
+               error(csa, "missing upper bound\n");
+         }
+         else if (csa->token == T_NUMBER)
+         {  /* parse unsigned upper bound */
+            set_upper_bound(csa, j, csa->value);
+            scan_token(csa);
+         }
+         else
+            error(csa, "missing upper bound\n");
+      }
+      else if (csa->token == T_GE)
+      {  /* parse lower bound */
+         if (lb_flag)
+         {  /* the context '... <= x >= ...' is invalid */
+            error(csa, "invalid bound definition\n");
+         }
+         scan_token(csa);
+         if (csa->token == T_PLUS || csa->token == T_MINUS)
+         {  /* parse signed lower bound */
+            s = (csa->token == T_PLUS ? +1.0 : -1.0);
+            scan_token(csa);
+            if (csa->token == T_NUMBER)
+            {  set_lower_bound(csa, j, s * csa->value);
+               scan_token(csa);
+            }
+            else if (the_same(csa->image, "infinity") ||
+                     the_same(csa->image, "inf") == 0)
+            {  if (s > 0.0)
+                  error(csa, "invalid use of `+inf' as lower bound\n");
+               set_lower_bound(csa, j, -DBL_MAX);
+               scan_token(csa);
+            }
+            else
+               error(csa, "missing lower bound\n");
+         }
+         else if (csa->token == T_NUMBER)
+         {  /* parse unsigned lower bound */
+            set_lower_bound(csa, j, csa->value);
+            scan_token(csa);
+         }
+         else
+            error(csa, "missing lower bound\n");
+      }
+      else if (csa->token == T_EQ)
+      {  /* parse fixed value */
+         if (lb_flag)
+         {  /* the context '... <= x = ...' is invalid */
+            error(csa, "invalid bound definition\n");
+         }
+         scan_token(csa);
+         if (csa->token == T_PLUS || csa->token == T_MINUS)
+         {  /* parse signed fixed value */
+            s = (csa->token == T_PLUS ? +1.0 : -1.0);
+            scan_token(csa);
+            if (csa->token == T_NUMBER)
+            {  set_lower_bound(csa, j, s * csa->value);
+               set_upper_bound(csa, j, s * csa->value);
+               scan_token(csa);
+            }
+            else
+               error(csa, "missing fixed value\n");
+         }
+         else if (csa->token == T_NUMBER)
+         {  /* parse unsigned fixed value */
+            set_lower_bound(csa, j, csa->value);
+            set_upper_bound(csa, j, csa->value);
+            scan_token(csa);
+         }
+         else
+            error(csa, "missing fixed value\n");
+      }
+      else if (the_same(csa->image, "free"))
+      {  /* parse the keyword 'free' */
+         if (lb_flag)
+         {  /* the context '... <= x free ...' is invalid */
+            error(csa, "invalid bound definition\n");
+         }
+         set_lower_bound(csa, j, -DBL_MAX);
+         set_upper_bound(csa, j, +DBL_MAX);
+         scan_token(csa);
+      }
+      else if (!lb_flag)
+      {  /* neither lower nor upper bounds are specified */
+         error(csa, "invalid bound definition\n");
+      }
+      goto loop;
+done: return;
+}
+
+/***********************************************************************
+*  parse_integer - parse general, integer, or binary section
+*
+*  <variable> ::= <symbolic name>
+*  <general> ::= general | generals | gen
+*  <integer> ::= integer | integers | int
+*  <binary> ::= binary | binaries | bin
+*  <section head> ::= <general> <integer> <binary>
+*  <additional section> ::= <section head> |
+*     <additional section> <variable> */
+
+static void parse_integer(struct csa *csa)
+{     int j, binary;
+      /* parse the keyword 'general', 'integer', or 'binary' */
+      if (csa->token == T_GENERAL)
+         binary = 0, scan_token(csa);
+      else if (csa->token == T_INTEGER)
+         binary = 0, scan_token(csa);
+      else if (csa->token == T_BINARY)
+         binary = 1, scan_token(csa);
+      else
+         xassert(csa != csa);
+      /* parse list of variables (may be empty) */
+      while (csa->token == T_NAME)
+      {  /* find the corresponding column */
+         j = find_col(csa, csa->image);
+         /* change kind of the variable */
+         glp_set_col_kind(csa->P, j, GLP_IV);
+         /* set 0-1 bounds for the binary variable */
+         if (binary)
+         {  set_lower_bound(csa, j, 0.0);
+            set_upper_bound(csa, j, 1.0);
+         }
+         scan_token(csa);
+      }
+      return;
+}
+
+int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
+{     /* read problem data in CPLEX LP format */
+      glp_cpxcp _parm;
+      struct csa _csa, *csa = &_csa;
+      int ret;
+      xprintf("Reading problem data from `%s'...\n", fname);
+      if (parm == NULL)
+         glp_init_cpxcp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_read_lp", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->parm = parm;
+      csa->fname = fname;
+      csa->fp = NULL;
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->count = 0;
+      csa->c = '\n';
+      csa->token = T_EOF;
+      csa->image[0] = '\0';
+      csa->imlen = 0;
+      csa->value = 0.0;
+      csa->n_max = 100;
+      csa->ind = xcalloc(1+csa->n_max, sizeof(int));
+      csa->val = xcalloc(1+csa->n_max, sizeof(double));
+      csa->flag = xcalloc(1+csa->n_max, sizeof(char));
+      memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
+      csa->lb = xcalloc(1+csa->n_max, sizeof(double));
+      csa->ub = xcalloc(1+csa->n_max, sizeof(double));
+      /* erase problem object */
+      glp_erase_prob(P);
+      glp_create_index(P);
+      /* open input CPLEX LP file */
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* scan very first token */
+      scan_token(csa);
+      /* parse definition of the objective function */
+      if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE))
+         error(csa, "`minimize' or `maximize' keyword missing\n");
+      parse_objective(csa);
+      /* parse constraints section */
+      if (csa->token != T_SUBJECT_TO)
+         error(csa, "constraints section missing\n");
+      parse_constraints(csa);
+      /* parse optional bounds section */
+      if (csa->token == T_BOUNDS) parse_bounds(csa);
+      /* parse optional general, integer, and binary sections */
+      while (csa->token == T_GENERAL ||
+             csa->token == T_INTEGER ||
+             csa->token == T_BINARY) parse_integer(csa);
+      /* check for the keyword 'end' */
+      if (csa->token == T_END)
+         scan_token(csa);
+      else if (csa->token == T_EOF)
+         warning(csa, "keyword `end' missing\n");
+      else
+         error(csa, "symbol `%s' in wrong position\n", csa->image);
+      /* nothing must follow the keyword 'end' (except comments) */
+      if (csa->token != T_EOF)
+         error(csa, "extra symbol(s) detected beyond `end'\n");
+      /* set bounds of variables */
+      {  int j, type;
+         double lb, ub;
+         for (j = 1; j <= P->n; j++)
+         {  lb = csa->lb[j];
+            ub = csa->ub[j];
+            if (lb == +DBL_MAX) lb = 0.0;      /* default lb */
+            if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */
+            if (lb == -DBL_MAX && ub == +DBL_MAX)
+               type = GLP_FR;
+            else if (ub == +DBL_MAX)
+               type = GLP_LO;
+            else if (lb == -DBL_MAX)
+               type = GLP_UP;
+            else if (lb != ub)
+               type = GLP_DB;
+            else
+               type = GLP_FX;
+            glp_set_col_bnds(csa->P, j, type, lb, ub);
+         }
+      }
+      /* print some statistics */
+      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+         P->nnz, P->nnz == 1 ? "" : "s");
+      if (glp_get_num_int(P) > 0)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         if (ni == 1)
+         {  if (nb == 0)
+               xprintf("One variable is integer\n");
+            else
+               xprintf("One variable is binary\n");
+         }
+         else
+         {  xprintf("%d integer variables, ", ni);
+            if (nb == 0)
+               xprintf("none");
+            else if (nb == 1)
+               xprintf("one");
+            else if (nb == ni)
+               xprintf("all");
+            else
+               xprintf("%d", nb);
+            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+         }
+      }
+      xprintf("%d lines were read\n", csa->count);
+      /* problem data has been successfully read */
+      glp_delete_index(P);
+      glp_sort_matrix(P);
+      ret = 0;
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      xfree(csa->ind);
+      xfree(csa->val);
+      xfree(csa->flag);
+      xfree(csa->lb);
+      xfree(csa->ub);
+      if (ret != 0) glp_erase_prob(P);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_lp - write problem data in CPLEX LP format
+*
+*  SYNOPSIS
+*
+*  int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char
+*     *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_lp writes problem data in CPLEX LP format to
+*  a text file.
+*
+*  The parameter parm is a pointer to the structure glp_cpxcp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  written.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_write_lp returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+#define csa csa1
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* pointer to problem object */
+      const glp_cpxcp *parm;
+      /* pointer to control parameters */
+};
+
+static int check_name(char *name)
+{     /* check if specified name is valid for CPLEX LP format */
+      if (*name == '.') return 1;
+      if (isdigit((unsigned char)*name)) return 1;
+      for (; *name; name++)
+      {  if (!isalnum((unsigned char)*name) &&
+             strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1;
+      }
+      return 0; /* name is ok */
+}
+
+static void adjust_name(char *name)
+{     /* attempt to adjust specified name to make it valid for CPLEX LP
+         format */
+      for (; *name; name++)
+      {  if (*name == ' ')
+            *name = '_';
+         else if (*name == '-')
+            *name = '~';
+         else if (*name == '[')
+            *name = '(';
+         else if (*name == ']')
+            *name = ')';
+      }
+      return;
+}
+
+static char *row_name(struct csa *csa, int i, char rname[255+1])
+{     /* construct symbolic name of i-th row (constraint) */
+      const char *name;
+      if (i == 0)
+         name = glp_get_obj_name(csa->P);
+      else
+         name = glp_get_row_name(csa->P, i);
+      if (name == NULL) goto fake;
+      strcpy(rname, name);
+      adjust_name(rname);
+      if (check_name(rname)) goto fake;
+      return rname;
+fake: if (i == 0)
+         strcpy(rname, "obj");
+      else
+         sprintf(rname, "r_%d", i);
+      return rname;
+}
+
+static char *col_name(struct csa *csa, int j, char cname[255+1])
+{     /* construct symbolic name of j-th column (variable) */
+      const char *name;
+      name = glp_get_col_name(csa->P, j);
+      if (name == NULL) goto fake;
+      strcpy(cname, name);
+      adjust_name(cname);
+      if (check_name(cname)) goto fake;
+      return cname;
+fake: sprintf(cname, "x_%d", j);
+      return cname;
+}
+
+int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
+{     /* write problem data in CPLEX LP format */
+      glp_cpxcp _parm;
+      struct csa _csa, *csa = &_csa;
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, len, flag, count, ret;
+      char line[1000+1], term[500+1], name[255+1];
+      xprintf("Writing problem data to `%s'...\n", fname);
+      if (parm == NULL)
+         glp_init_cpxcp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_write_lp", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->parm = parm;
+      /* create output CPLEX LP file */
+      fp = xfopen(fname, "w"), count = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* write problem name */
+      xfprintf(fp, "\\* Problem: %s *\\\n",
+         P->name == NULL ? "Unknown" : P->name), count++;
+      xfprintf(fp, "\n"), count++;
+      /* the problem should contain at least one row and one column */
+      if (!(P->m > 0 && P->n > 0))
+      {  xprintf("Warning: problem has no rows/columns\n");
+         xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"),
+            count++;
+         xfprintf(fp, "\n"), count++;
+         goto skip;
+      }
+      /* write the objective function definition */
+      if (P->dir == GLP_MIN)
+         xfprintf(fp, "Minimize\n"), count++;
+      else if (P->dir == GLP_MAX)
+         xfprintf(fp, "Maximize\n"), count++;
+      else
+         xassert(P != P);
+      row_name(csa, 0, name);
+      sprintf(line, " %s:", name);
+      len = 0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->coef != 0.0 || col->ptr == NULL)
+         {  len++;
+            col_name(csa, j, name);
+            if (col->coef == 0.0)
+               sprintf(term, " + 0 %s", name); /* empty column */
+            else if (col->coef == +1.0)
+               sprintf(term, " + %s", name);
+            else if (col->coef == -1.0)
+               sprintf(term, " - %s", name);
+            else if (col->coef > 0.0)
+               sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name);
+            else
+               sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name);
+            if (strlen(line) + strlen(term) > 72)
+               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+            strcat(line, term);
+         }
+      }
+      if (len == 0)
+      {  /* empty objective */
+         sprintf(term, " 0 %s", col_name(csa, 1, name));
+         strcat(line, term);
+      }
+      xfprintf(fp, "%s\n", line), count++;
+      if (P->c0 != 0.0)
+         xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0),
+            count++;
+      xfprintf(fp, "\n"), count++;
+      /* write the constraints section */
+      xfprintf(fp, "Subject To\n"), count++;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type == GLP_FR) continue; /* skip free row */
+         row_name(csa, i, name);
+         sprintf(line, " %s:", name);
+         /* linear form */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  col_name(csa, aij->col->j, name);
+            if (aij->val == +1.0)
+               sprintf(term, " + %s", name);
+            else if (aij->val == -1.0)
+               sprintf(term, " - %s", name);
+            else if (aij->val > 0.0)
+               sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name);
+            else
+               sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name);
+            if (strlen(line) + strlen(term) > 72)
+               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+            strcat(line, term);
+         }
+         if (row->type == GLP_DB)
+         {  /* double-bounded (ranged) constraint */
+            sprintf(term, " - ~r_%d", i);
+            if (strlen(line) + strlen(term) > 72)
+               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+            strcat(line, term);
+         }
+         else if (row->ptr == NULL)
+         {  /* empty constraint */
+            sprintf(term, " 0 %s", col_name(csa, 1, name));
+            strcat(line, term);
+         }
+         /* right hand-side */
+         if (row->type == GLP_LO)
+            sprintf(term, " >= %.*g", DBL_DIG, row->lb);
+         else if (row->type == GLP_UP)
+            sprintf(term, " <= %.*g", DBL_DIG, row->ub);
+         else if (row->type == GLP_DB || row->type == GLP_FX)
+            sprintf(term, " = %.*g", DBL_DIG, row->lb);
+         else
+            xassert(row != row);
+         if (strlen(line) + strlen(term) > 72)
+            xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+         strcat(line, term);
+         xfprintf(fp, "%s\n", line), count++;
+      }
+      xfprintf(fp, "\n"), count++;
+      /* write the bounds section */
+      flag = 0;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type != GLP_DB) continue;
+         if (!flag)
+            xfprintf(fp, "Bounds\n"), flag = 1, count++;
+         xfprintf(fp, " 0 <= ~r_%d <= %.*g\n",
+            i, DBL_DIG, row->ub - row->lb), count++;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->type == GLP_LO && col->lb == 0.0) continue;
+         if (!flag)
+            xfprintf(fp, "Bounds\n"), flag = 1, count++;
+         col_name(csa, j, name);
+         if (col->type == GLP_FR)
+            xfprintf(fp, " %s free\n", name), count++;
+         else if (col->type == GLP_LO)
+            xfprintf(fp, " %s >= %.*g\n",
+               name, DBL_DIG, col->lb), count++;
+         else if (col->type == GLP_UP)
+            xfprintf(fp, " -Inf <= %s <= %.*g\n",
+               name, DBL_DIG, col->ub), count++;
+         else if (col->type == GLP_DB)
+            xfprintf(fp, " %.*g <= %s <= %.*g\n",
+               DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++;
+         else if (col->type == GLP_FX)
+            xfprintf(fp, " %s = %.*g\n",
+               name, DBL_DIG, col->lb), count++;
+         else
+            xassert(col != col);
+      }
+      if (flag) xfprintf(fp, "\n"), count++;
+      /* write the integer section */
+      flag = 0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->kind == GLP_CV) continue;
+         xassert(col->kind == GLP_IV);
+         if (!flag)
+            xfprintf(fp, "Generals\n"), flag = 1, count++;
+         xfprintf(fp, " %s\n", col_name(csa, j, name)), count++;
+      }
+      if (flag) xfprintf(fp, "\n"), count++;
+skip: /* write the end keyword */
+      xfprintf(fp, "End\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* problem data has been successfully written */
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpdmp.c b/optional/glpk/glpdmp.c
new file mode 100644
index 0000000..bcf2498
--- /dev/null
+++ b/optional/glpk/glpdmp.c
@@ -0,0 +1,259 @@
+/* glpdmp.c (dynamic memory pool) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpdmp.h"
+
+#if 1 /* 29/VIII-2008 */
+/* some processors need data to be properly aligned; the macro
+   align_datasize enlarges the specified size of a data item to provide
+   a proper alignment of immediately following data */
+
+#define align_datasize(size) ((((size) + 7) / 8) * 8)
+/* 8 bytes is sufficient in both 32- and 64-bit environments */
+#endif
+
+#ifdef GLP_DEBUG
+struct info
+{     DMP *pool;
+      int size;
+};
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_create_pool - create dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  DMP *dmp_create_pool(void);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_create_pool creates a dynamic memory pool.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the memory pool created. */
+
+DMP *dmp_create_pool(void)
+{     DMP *pool;
+      int k;
+#ifdef GLP_DEBUG
+      xprintf("dmp_create_pool: warning: debug mode enabled\n");
+#endif
+      pool = xmalloc(sizeof(DMP));
+#if 0
+      pool->size = 0;
+#endif
+      for (k = 0; k <= 31; k++) pool->avail[k] = NULL;
+      pool->block = NULL;
+      pool->used = DMP_BLK_SIZE;
+      pool->count.lo = pool->count.hi = 0;
+      return pool;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_get_atom - get free atom from dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  void *dmp_get_atom(DMP *pool, int size);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_get_atom obtains a free atom (memory block) from the
+*  specified memory pool.
+*
+*  The parameter size is the atom size, in bytes, 1 <= size <= 256.
+*
+*  Note that the free atom contains arbitrary data, not binary zeros.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the free atom obtained. */
+
+void *dmp_get_atom(DMP *pool, int size)
+{     void *atom;
+      int k;
+#ifdef GLP_DEBUG
+      int orig_size = size;
+#endif
+      if (!(1 <= size && size <= 256))
+         xerror("dmp_get_atom: size = %d; invalid atom size\n", size);
+#if 0
+      if (!(pool->size == 0 || pool->size == size))
+         xerror("dmp_get_atom: size = %d; wrong atom size\n", size);
+#endif
+      /* adjust the size to provide the proper data alignment */
+      size = align_datasize(size);
+#ifdef GLP_DEBUG
+      size += align_datasize(sizeof(struct info));
+#endif
+      /* adjust the size to make it multiple of 8 bytes, if needed */
+      size = ((size + 7) / 8) * 8;
+      /* determine the corresponding list of free cells */
+      k = size / 8 - 1;
+      xassert(0 <= k && k <= 31);
+      /* obtain a free atom */
+      if (pool->avail[k] == NULL)
+      {  /* the list of free cells is empty */
+         if (pool->used + size > DMP_BLK_SIZE)
+         {  /* allocate a new memory block */
+            void *block = xmalloc(DMP_BLK_SIZE);
+            *(void **)block = pool->block;
+            pool->block = block;
+            pool->used = align_datasize(sizeof(void *));
+         }
+         /* place the atom in the current memory block */
+         atom = (char *)pool->block + pool->used;
+         pool->used += size;
+      }
+      else
+      {  /* obtain the atom from the list of free cells */
+         atom = pool->avail[k];
+         pool->avail[k] = *(void **)atom;
+      }
+      memset(atom, '?', size);
+      /* increase the number of atoms which are currently in use */
+      pool->count.lo++;
+      if (pool->count.lo == 0) pool->count.hi++;
+#ifdef GLP_DEBUG
+      ((struct info *)atom)->pool = pool;
+      ((struct info *)atom)->size = orig_size;
+      atom = (char *)atom + align_datasize(sizeof(struct info));
+#endif
+      return atom;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_free_atom - return atom to dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  void dmp_free_atom(DMP *pool, void *atom, int size);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_free_atom returns the specified atom (memory block)
+*  to the specified memory pool, making it free.
+*
+*  The parameter size is the atom size, in bytes, 1 <= size <= 256.
+*
+*  Note that the atom can be returned only to the pool, from which it
+*  was obtained, and its size must be exactly the same as on obtaining
+*  it from the pool. */
+
+void dmp_free_atom(DMP *pool, void *atom, int size)
+{     int k;
+      if (!(1 <= size && size <= 256))
+         xerror("dmp_free_atom: size = %d; invalid atom size\n", size);
+#if 0
+      if (!(pool->size == 0 || pool->size == size))
+         xerror("dmp_free_atom: size = %d; wrong atom size\n", size);
+#endif
+      if (pool->count.lo == 0 && pool->count.hi == 0)
+         xerror("dmp_free_atom: pool allocation error\n");
+#ifdef GLP_DEBUG
+      atom = (char *)atom - align_datasize(sizeof(struct info));
+      xassert(((struct info *)atom)->pool == pool);
+      xassert(((struct info *)atom)->size == size);
+#endif
+      /* adjust the size to provide the proper data alignment */
+      size = align_datasize(size);
+#ifdef GLP_DEBUG
+      size += align_datasize(sizeof(struct info));
+#endif
+      /* adjust the size to make it multiple of 8 bytes, if needed */
+      size = ((size + 7) / 8) * 8;
+      /* determine the corresponding list of free cells */
+      k = size / 8 - 1;
+      xassert(0 <= k && k <= 31);
+      /* return the atom to the list of free cells */
+      *(void **)atom = pool->avail[k];
+      pool->avail[k] = atom;
+      /* decrease the number of atoms which are currently in use */
+      pool->count.lo--;
+      if (pool->count.lo == 0xFFFFFFFF) pool->count.hi--;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_in_use - determine how many atoms are still in use
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  glp_long dmp_in_use(DMP *pool);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_in_use determines how many atoms allocated from the
+*  specified memory pool with the routine dmp_get_atom are still in use,
+*  i.e. not returned to the pool with the routine dmp_free_atom.
+*
+*  RETURNS
+*
+*  The routine returns the number of atoms which are still in use. */
+
+glp_long dmp_in_use(DMP *pool)
+{     return
+         pool->count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_delete_pool - delete dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  void dmp_delete_pool(DMP *pool);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_delete_pool deletes the specified dynamic memory
+*  pool and frees all the memory allocated to this object. */
+
+void dmp_delete_pool(DMP *pool)
+{     while (pool->block != NULL)
+      {  void *block = pool->block;
+         pool->block = *(void **)block;
+         xfree(block);
+      }
+      xfree(pool);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpdmp.h b/optional/glpk/glpdmp.h
new file mode 100644
index 0000000..547d48a
--- /dev/null
+++ b/optional/glpk/glpdmp.h
@@ -0,0 +1,80 @@
+/* glpdmp.h (dynamic memory pool) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPDMP_H
+#define GLPDMP_H
+
+#include "glpenv.h"
+
+typedef struct DMP DMP;
+
+#define DMP_BLK_SIZE 8000
+/* size of memory blocks, in bytes, allocated for memory pools */
+
+struct DMP
+{     /* dynamic memory pool */
+#if 0
+      int size;
+      /* size of atoms, in bytes, 1 <= size <= 256; if size = 0, atoms
+         may have different sizes */
+#endif
+      void *avail[32];
+      /* avail[k], 0 <= k <= 31, is a pointer to the first available
+         (free) cell of (k+1)*8 bytes long; in the beginning of each
+         free cell there is a pointer to another free cell of the same
+         length */
+      void *block;
+      /* pointer to the most recently allocated memory block; in the
+         beginning of each allocated memory block there is a pointer to
+         the previously allocated memory block */
+      int used;
+      /* number of bytes used in the most recently allocated memory
+         block */
+      glp_long count;
+      /* number of atoms which are currently in use */
+};
+
+#define dmp_create_pool _glp_dmp_create_pool
+DMP *dmp_create_pool(void);
+/* create dynamic memory pool */
+
+#define dmp_get_atom _glp_dmp_get_atom
+void *dmp_get_atom(DMP *pool, int size);
+/* get free atom from dynamic memory pool */
+
+#define dmp_free_atom _glp_dmp_free_atom
+void dmp_free_atom(DMP *pool, void *atom, int size);
+/* return atom to dynamic memory pool */
+
+#define dmp_in_use _glp_dmp_in_use
+glp_long dmp_in_use(DMP *pool);
+/* determine how many atoms are still in use */
+
+#define dmp_delete_pool _glp_dmp_delete_pool
+void dmp_delete_pool(DMP *pool);
+/* delete dynamic memory pool */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpdmx.c b/optional/glpk/glpdmx.c
new file mode 100644
index 0000000..3497d8c
--- /dev/null
+++ b/optional/glpk/glpdmx.c
@@ -0,0 +1,1472 @@
+/* glpdmx.c (reading/writing data in DIMACS format) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#define _GLPSTD_STDIO
+#include "glpapi.h"
+
+struct csa
+{     /* common storage area */
+      jmp_buf jump;
+      /* label for go to in case of error */
+      const char *fname;
+      /* name of input text file */
+      XFILE *fp;
+      /* stream assigned to input text file */
+      int count;
+      /* line count */
+      int c;
+      /* current character */
+      char field[255+1];
+      /* data field */
+      int empty;
+      /* warning 'empty line ignored' was printed */
+      int nonint;
+      /* warning 'non-integer data detected' was printed */
+};
+
+static void error(struct csa *csa, const char *fmt, ...)
+{     /* print error message and terminate processing */
+      va_list arg;
+      xprintf("%s:%d: error: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      xprintf("\n");
+      longjmp(csa->jump, 1);
+      /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{     /* print warning message and continue processing */
+      va_list arg;
+      xprintf("%s:%d: warning: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      xprintf("\n");
+      return;
+}
+
+static void read_char(struct csa *csa)
+{     /* read character from input text file */
+      int c;
+      if (csa->c == '\n') csa->count++;
+      c = xfgetc(csa->fp);
+      if (c < 0)
+      {  if (xferror(csa->fp))
+            error(csa, "read error - %s", xerrmsg());
+         else if (csa->c == '\n')
+            error(csa, "unexpected end of file");
+         else
+         {  warning(csa, "missing final end of line");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+         error(csa, "invalid control character 0x%02X", c);
+      csa->c = c;
+      return;
+}
+
+static void read_designator(struct csa *csa)
+{     /* read one-character line designator */
+      xassert(csa->c == '\n');
+      read_char(csa);
+      for (;;)
+      {  /* skip preceding white-space characters */
+         while (csa->c == ' ')
+            read_char(csa);
+         if (csa->c == '\n')
+         {  /* ignore empty line */
+            if (!csa->empty)
+            {  warning(csa, "empty line ignored");
+               csa->empty = 1;
+            }
+            read_char(csa);
+         }
+         else if (csa->c == 'c')
+         {  /* skip comment line */
+            while (csa->c != '\n')
+               read_char(csa);
+            read_char(csa);
+         }
+         else
+         {  /* hmm... looks like a line designator */
+            csa->field[0] = (char)csa->c, csa->field[1] = '\0';
+            /* check that it is followed by a white-space character */
+            read_char(csa);
+            if (!(csa->c == ' ' || csa->c == '\n'))
+               error(csa, "line designator missing or invalid");
+            break;
+         }
+      }
+      return;
+}
+
+static void read_field(struct csa *csa)
+{     /* read data field */
+      int len = 0;
+      /* skip preceding white-space characters */
+      while (csa->c == ' ')
+         read_char(csa);
+      /* scan data field */
+      if (csa->c == '\n')
+         error(csa, "unexpected end of line");
+      while (!(csa->c == ' ' || csa->c == '\n'))
+      {  if (len == sizeof(csa->field)-1)
+            error(csa, "data field `%.15s...' too long", csa->field);
+         csa->field[len++] = (char)csa->c;
+         read_char(csa);
+      }
+      csa->field[len] = '\0';
+      return;
+}
+
+static void end_of_line(struct csa *csa)
+{     /* skip white-space characters until end of line */
+      while (csa->c == ' ')
+         read_char(csa);
+      if (csa->c != '\n')
+         error(csa, "too many data fields specified");
+      return;
+}
+
+static void check_int(struct csa *csa, double num)
+{     /* print a warning if non-integer data are detected */
+      if (!csa->nonint && num != floor(num))
+      {  warning(csa, "non-integer data detected");
+         csa->nonint = 1;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_mincost - read min-cost flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+*     int a_cost, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_mincost reads minimum cost flow problem data in
+*  DIMACS format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, j, k, nv, na, ret = 0;
+      double rhs, low, cap, cost;
+      char *flag = NULL;
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
+            v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_read_mincost: a_low = %d; invalid offset\n",
+            a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
+            a_cost);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading min-cost flow problem data from `%s'...\n",
+         fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "min") != 0)
+         error(csa, "wrong problem designator; `min' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+         error(csa, "number of nodes missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &na) == 0 && na >= 0))
+         error(csa, "number of arcs missing or invalid");
+      xprintf("Flow network has %d node%s and %d arc%s\n",
+         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      flag = xcalloc(1+nv, sizeof(char));
+      memset(&flag[1], 0, nv * sizeof(char));
+      if (v_rhs >= 0)
+      {  rhs = 0.0;
+         for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
+         }
+      }
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "node number %d out of range", i);
+         if (flag[i])
+            error(csa, "duplicate descriptor of node %d", i);
+         read_field(csa);
+         if (str2num(csa->field, &rhs) != 0)
+            error(csa, "node supply/demand missing or invalid");
+         check_int(csa, rhs);
+         if (v_rhs >= 0)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
+         }
+         flag[i] = 1;
+         end_of_line(csa);
+      }
+      xfree(flag), flag = NULL;
+      /* read arc descriptor lines */
+      for (k = 1; k <= na; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "a") != 0)
+            error(csa, "wrong line designator; `a' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "starting node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "starting node number %d out of range", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "ending node number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "ending node number %d out of range", j);
+         read_field(csa);
+         if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
+            error(csa, "lower bound of arc flow missing or invalid");
+         check_int(csa, low);
+         read_field(csa);
+         if (!(str2num(csa->field, &cap) == 0 && cap >= low))
+            error(csa, "upper bound of arc flow missing or invalid");
+         check_int(csa, cap);
+         read_field(csa);
+         if (str2num(csa->field, &cost) != 0)
+            error(csa, "per-unit cost of arc flow missing or invalid");
+         check_int(csa, cost);
+         a = glp_add_arc(G, i, j);
+         if (a_low >= 0)
+            memcpy((char *)a->data + a_low, &low, sizeof(double));
+         if (a_cap >= 0)
+            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
+         if (a_cost >= 0)
+            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_mincost - write min-cost flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+*     int a_cost, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_mincost writes minimum cost flow problem data
+*  in DIMACS format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, count = 0, ret;
+      double rhs, low, cap, cost;
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
+            v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_low = %d; invalid offset\n",
+            a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
+            a_cost);
+      xprintf("Writing min-cost flow problem data to `%s'...\n",
+         fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
+      if (v_rhs >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+            if (rhs != 0.0)
+               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
+         }
+      }
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  if (a_low >= 0)
+               memcpy(&low, (char *)a->data + a_low, sizeof(double));
+            else
+               low = 0.0;
+            if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 0.0;
+            xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
+               a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
+               DBL_DIG, cost), count++;
+         }
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_maxflow - read maximum flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_maxflow reads maximum flow problem data in
+*  DIMACS format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
+      const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_arc *a;
+      int i, j, k, s, t, nv, na, ret = 0;
+      double cap;
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
+            a_cap);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading maximum flow problem data from `%s'...\n",
+         fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "max") != 0)
+         error(csa, "wrong problem designator; `max' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
+         error(csa, "number of nodes missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &na) == 0 && na >= 0))
+         error(csa, "number of arcs missing or invalid");
+      xprintf("Flow network has %d node%s and %d arc%s\n",
+         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      s = t = 0;
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "node number %d out of range", i);
+         read_field(csa);
+         if (strcmp(csa->field, "s") == 0)
+         {  if (s > 0)
+               error(csa, "only one source node allowed");
+            s = i;
+         }
+         else if (strcmp(csa->field, "t") == 0)
+         {  if (t > 0)
+               error(csa, "only one sink node allowed");
+            t = i;
+         }
+         else
+            error(csa, "wrong node designator; `s' or `t' expected");
+         if (s > 0 && s == t)
+            error(csa, "source and sink nodes must be distinct");
+         end_of_line(csa);
+      }
+      if (s == 0)
+         error(csa, "source node descriptor missing\n");
+      if (t == 0)
+         error(csa, "sink node descriptor missing\n");
+      if (_s != NULL) *_s = s;
+      if (_t != NULL) *_t = t;
+      /* read arc descriptor lines */
+      for (k = 1; k <= na; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "a") != 0)
+            error(csa, "wrong line designator; `a' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "starting node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "starting node number %d out of range", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "ending node number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "ending node number %d out of range", j);
+         read_field(csa);
+         if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
+            error(csa, "arc capacity missing or invalid");
+         check_int(csa, cap);
+         a = glp_add_arc(G, i, j);
+         if (a_cap >= 0)
+            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_maxflow - write maximum flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_maxflow writes maximum flow problem data in
+*  DIMACS format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+      const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, count = 0, ret;
+      double cap;
+      if (!(1 <= s && s <= G->nv))
+         xerror("glp_write_maxflow: s = %d; source node number out of r"
+            "ange\n", s);
+      if (!(1 <= t && t <= G->nv))
+         xerror("glp_write_maxflow: t = %d: sink node number out of ran"
+            "ge\n", t);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
+            a_cap);
+      xprintf("Writing maximum flow problem data to `%s'...\n",
+         fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
+      xfprintf(fp, "n %d s\n", s), count++;
+      xfprintf(fp, "n %d t\n", t), count++;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            xfprintf(fp, "a %d %d %.*g\n",
+               a->tail->i, a->head->i, DBL_DIG, cap), count++;
+         }
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_asnprob - read assignment problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_asnprob reads assignment problem data in DIMACS
+*  format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, n1, i, j, k, ret = 0;
+      double cost;
+      char *flag = NULL;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
+            a_cost);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading assignment problem data from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "asn") != 0)
+         error(csa, "wrong problem designator; `asn' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+         error(csa, "number of nodes missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &na) == 0 && na >= 0))
+         error(csa, "number of arcs missing or invalid");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      flag = xcalloc(1+nv, sizeof(char));
+      memset(&flag[1], 0, nv * sizeof(char));
+      n1 = 0;
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "node number %d out of range", i);
+         if (flag[i])
+            error(csa, "duplicate descriptor of node %d", i);
+         flag[i] = 1, n1++;
+         end_of_line(csa);
+      }
+      xprintf(
+         "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
+         n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+      if (v_set >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            k = (flag[i] ? 0 : 1);
+            memcpy((char *)v->data + v_set, &k, sizeof(int));
+         }
+      }
+      /* read arc descriptor lines */
+      for (k = 1; k <= na; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "a") != 0)
+            error(csa, "wrong line designator; `a' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "starting node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "starting node number %d out of range", i);
+         if (!flag[i])
+            error(csa, "node %d cannot be a starting node", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "ending node number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "ending node number %d out of range", j);
+         if (flag[j])
+            error(csa, "node %d cannot be an ending node", j);
+         read_field(csa);
+         if (str2num(csa->field, &cost) != 0)
+            error(csa, "arc cost missing or invalid");
+         check_int(csa, cost);
+         a = glp_add_arc(G, i, j);
+         if (a_cost >= 0)
+            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_asnprob - write assignment problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_asnprob writes assignment problem data in
+*  DIMACS format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, k, count = 0, ret;
+      double cost;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
+            a_cost);
+      xprintf("Writing assignment problem data to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_set >= 0)
+            memcpy(&k, (char *)v->data + v_set, sizeof(int));
+         else
+            k = (v->out != NULL ? 0 : 1);
+         if (k == 0)
+            xfprintf(fp, "n %d\n", i), count++;
+      }
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 1.0;
+            xfprintf(fp, "a %d %d %.*g\n",
+               a->tail->i, a->head->i, DBL_DIG, cost), count++;
+         }
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_ccdata - read graph in DIMACS clique/coloring format
+*
+*  SYNOPSIS
+*
+*  int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_ccdata reads an (undirected) graph in DIMACS
+*  clique/coloring format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_vertex *v;
+      int i, j, k, nv, ne, ret = 0;
+      double w;
+      char *flag = NULL;
+      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+         xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
+            v_wgt);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading graph from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "edge") != 0)
+         error(csa, "wrong problem designator; `edge' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+         error(csa, "number of vertices missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
+         error(csa, "number of edges missing or invalid");
+      xprintf("Graph has %d vert%s and %d edge%s\n",
+         nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      flag = xcalloc(1+nv, sizeof(char));
+      memset(&flag[1], 0, nv * sizeof(char));
+      if (v_wgt >= 0)
+      {  w = 1.0;
+         for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
+         }
+      }
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "vertex number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "vertex number %d out of range", i);
+         if (flag[i])
+            error(csa, "duplicate descriptor of vertex %d", i);
+         read_field(csa);
+         if (str2num(csa->field, &w) != 0)
+            error(csa, "vertex weight missing or invalid");
+         check_int(csa, w);
+         if (v_wgt >= 0)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
+         }
+         flag[i] = 1;
+         end_of_line(csa);
+      }
+      xfree(flag), flag = NULL;
+      /* read edge descriptor lines */
+      for (k = 1; k <= ne; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "e") != 0)
+            error(csa, "wrong line designator; `e' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "first vertex number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "first vertex number %d out of range", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "second vertex number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "second vertex number %d out of range", j);
+         glp_add_arc(G, i, j);
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_ccdata - write graph in DIMACS clique/coloring format
+*
+*  SYNOPSIS
+*
+*  int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_ccdata writes the specified graph in DIMACS
+*  clique/coloring format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *e;
+      int i, count = 0, ret;
+      double w;
+      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+         xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
+            v_wgt);
+      xprintf("Writing graph to `%s'\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
+      if (v_wgt >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
+            if (w != 1.0)
+               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
+         }
+      }
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (e = v->out; e != NULL; e = e->t_next)
+            xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_prob - read problem data in GLPK format
+*
+*  SYNOPSIS
+*
+*  int glp_read_prob(glp_prob *P, int flags, const char *fname);
+*
+*  The routine glp_read_prob reads problem data in GLPK LP/MIP format
+*  from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_prob(glp_prob *P, int flags, const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
+         *ia = NULL, *ja = NULL;
+      double lb, ub, temp, *ar = NULL;
+      char *rf = NULL, *cf = NULL;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_read_prob: P = %p; invalid problem object\n",
+            P);
+      if (flags != 0)
+         xerror("glp_read_prob: flags = %d; invalid parameter\n",
+            flags);
+      if (fname == NULL)
+         xerror("glp_read_prob: fname = %d; invalid parameter\n",
+            fname);
+      glp_erase_prob(P);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading problem data from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "lp") == 0)
+         mip = 0;
+      else if (strcmp(csa->field, "mip") == 0)
+         mip = 1;
+      else
+         error(csa, "wrong problem designator; `lp' or `mip' expected\n"
+            );
+      read_field(csa);
+      if (strcmp(csa->field, "min") == 0)
+         glp_set_obj_dir(P, GLP_MIN);
+      else if (strcmp(csa->field, "max") == 0)
+         glp_set_obj_dir(P, GLP_MAX);
+      else
+         error(csa, "objective sense missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &m) == 0 && m >= 0))
+         error(csa, "number of rows missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &n) == 0 && n >= 0))
+         error(csa, "number of columns missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
+         error(csa, "number of constraint coefficients missing or inval"
+            "id");
+      if (m > 0)
+      {  glp_add_rows(P, m);
+         for (i = 1; i <= m; i++)
+            glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
+      }
+      if (n > 0)
+      {  glp_add_cols(P, n);
+         for (j = 1; j <= n; j++)
+         {  if (!mip)
+               glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
+            else
+               glp_set_col_kind(P, j, GLP_BV);
+         }
+      }
+      end_of_line(csa);
+      /* allocate working arrays */
+      rf = xcalloc(1+m, sizeof(char));
+      memset(rf, 0, 1+m);
+      cf = xcalloc(1+n, sizeof(char));
+      memset(cf, 0, 1+n);
+      ln = xcalloc(1+nnz, sizeof(int));
+      ia = xcalloc(1+nnz, sizeof(int));
+      ja = xcalloc(1+nnz, sizeof(int));
+      ar = xcalloc(1+nnz, sizeof(double));
+      /* read descriptor lines */
+      ne = 0;
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "i") == 0)
+         {  /* row descriptor */
+            read_field(csa);
+            if (str2int(csa->field, &i) != 0)
+               error(csa, "row number missing or invalid");
+            if (!(1 <= i && i <= m))
+               error(csa, "row number out of range");
+            read_field(csa);
+            if (strcmp(csa->field, "f") == 0)
+               type = GLP_FR;
+            else if (strcmp(csa->field, "l") == 0)
+               type = GLP_LO;
+            else if (strcmp(csa->field, "u") == 0)
+               type = GLP_UP;
+            else if (strcmp(csa->field, "d") == 0)
+               type = GLP_DB;
+            else if (strcmp(csa->field, "s") == 0)
+               type = GLP_FX;
+            else
+               error(csa, "row type missing or invalid");
+            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+            {  read_field(csa);
+               if (str2num(csa->field, &lb) != 0)
+                  error(csa, "row lower bound/fixed value missing or in"
+                     "valid");
+            }
+            else
+               lb = 0.0;
+            if (type == GLP_UP || type == GLP_DB)
+            {  read_field(csa);
+               if (str2num(csa->field, &ub) != 0)
+                  error(csa, "row upper bound missing or invalid");
+            }
+            else
+               ub = 0.0;
+            if (rf[i] & 0x01)
+               error(csa, "duplicate row descriptor");
+            glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
+         }
+         else if (strcmp(csa->field, "j") == 0)
+         {  /* column descriptor */
+            read_field(csa);
+            if (str2int(csa->field, &j) != 0)
+               error(csa, "column number missing or invalid");
+            if (!(1 <= j && j <= n))
+               error(csa, "column number out of range");
+            if (!mip)
+               kind = GLP_CV;
+            else
+            {  read_field(csa);
+               if (strcmp(csa->field, "c") == 0)
+                  kind = GLP_CV;
+               else if (strcmp(csa->field, "i") == 0)
+                  kind = GLP_IV;
+               else if (strcmp(csa->field, "b") == 0)
+               {  kind = GLP_IV;
+                  type = GLP_DB, lb = 0.0, ub = 1.0;
+                  goto skip;
+               }
+               else
+                  error(csa, "column kind missing or invalid");
+            }
+            read_field(csa);
+            if (strcmp(csa->field, "f") == 0)
+               type = GLP_FR;
+            else if (strcmp(csa->field, "l") == 0)
+               type = GLP_LO;
+            else if (strcmp(csa->field, "u") == 0)
+               type = GLP_UP;
+            else if (strcmp(csa->field, "d") == 0)
+               type = GLP_DB;
+            else if (strcmp(csa->field, "s") == 0)
+               type = GLP_FX;
+            else
+               error(csa, "column type missing or invalid");
+            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+            {  read_field(csa);
+               if (str2num(csa->field, &lb) != 0)
+                  error(csa, "column lower bound/fixed value missing or"
+                     " invalid");
+            }
+            else
+               lb = 0.0;
+            if (type == GLP_UP || type == GLP_DB)
+            {  read_field(csa);
+               if (str2num(csa->field, &ub) != 0)
+                  error(csa, "column upper bound missing or invalid");
+            }
+            else
+               ub = 0.0;
+skip:       if (cf[j] & 0x01)
+               error(csa, "duplicate column descriptor");
+            glp_set_col_kind(P, j, kind);
+            glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
+         }
+         else if (strcmp(csa->field, "a") == 0)
+         {  /* coefficient descriptor */
+            read_field(csa);
+            if (str2int(csa->field, &i) != 0)
+               error(csa, "row number missing or invalid");
+            if (!(0 <= i && i <= m))
+               error(csa, "row number out of range");
+            read_field(csa);
+            if (str2int(csa->field, &j) != 0)
+               error(csa, "column number missing or invalid");
+            if (!((i == 0 ? 0 : 1) <= j && j <= n))
+               error(csa, "column number out of range");
+            read_field(csa);
+            if (i == 0)
+            {  if (str2num(csa->field, &temp) != 0)
+                  error(csa, "objective %s missing or invalid",
+                     j == 0 ? "constant term" : "coefficient");
+               if (cf[j] & 0x10)
+                  error(csa, "duplicate objective %s",
+                     j == 0 ? "constant term" : "coefficient");
+               glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
+            }
+            else
+            {  if (str2num(csa->field, &temp) != 0)
+                  error(csa, "constraint coefficient missing or invalid"
+                     );
+               if (ne == nnz)
+                  error(csa, "too many constraint coefficient descripto"
+                     "rs");
+               ln[++ne] = csa->count;
+               ia[ne] = i, ja[ne] = j, ar[ne] = temp;
+            }
+         }
+         else if (strcmp(csa->field, "n") == 0)
+         {  /* symbolic name descriptor */
+            read_field(csa);
+            if (strcmp(csa->field, "p") == 0)
+            {  /* problem name */
+               read_field(csa);
+               if (P->name != NULL)
+                  error(csa, "duplicate problem name");
+               glp_set_prob_name(P, csa->field);
+            }
+            else if (strcmp(csa->field, "z") == 0)
+            {  /* objective name */
+               read_field(csa);
+               if (P->obj != NULL)
+                  error(csa, "duplicate objective name");
+               glp_set_obj_name(P, csa->field);
+            }
+            else if (strcmp(csa->field, "i") == 0)
+            {  /* row name */
+               read_field(csa);
+               if (str2int(csa->field, &i) != 0)
+                  error(csa, "row number missing or invalid");
+               if (!(1 <= i && i <= m))
+                  error(csa, "row number out of range");
+               read_field(csa);
+               if (P->row[i]->name != NULL)
+                  error(csa, "duplicate row name");
+               glp_set_row_name(P, i, csa->field);
+            }
+            else if (strcmp(csa->field, "j") == 0)
+            {  /* column name */
+               read_field(csa);
+               if (str2int(csa->field, &j) != 0)
+                  error(csa, "column number missing or invalid");
+               if (!(1 <= j && j <= n))
+                  error(csa, "column number out of range");
+               read_field(csa);
+               if (P->col[j]->name != NULL)
+                  error(csa, "duplicate column name");
+               glp_set_col_name(P, j, csa->field);
+            }
+            else
+               error(csa, "object designator missing or invalid");
+         }
+         else if (strcmp(csa->field, "e") == 0)
+            break;
+         else
+            error(csa, "line designator missing or invalid");
+         end_of_line(csa);
+      }
+      if (ne < nnz)
+         error(csa, "too few constraint coefficient descriptors");
+      xassert(ne == nnz);
+      k = glp_check_dup(m, n, ne, ia, ja);
+      xassert(0 <= k && k <= nnz);
+      if (k > 0)
+      {  csa->count = ln[k];
+         error(csa, "duplicate constraint coefficient");
+      }
+      glp_load_matrix(P, ne, ia, ja, ar);
+      /* print some statistics */
+      if (P->name != NULL)
+         xprintf("Problem: %s\n", P->name);
+      if (P->obj != NULL)
+         xprintf("Objective: %s\n", P->obj);
+      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+         m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
+         "" : "s");
+      if (glp_get_num_int(P) > 0)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         if (ni == 1)
+         {  if (nb == 0)
+               xprintf("One variable is integer\n");
+            else
+               xprintf("One variable is binary\n");
+         }
+         else
+         {  xprintf("%d integer variables, ", ni);
+            if (nb == 0)
+               xprintf("none");
+            else if (nb == 1)
+               xprintf("one");
+            else if (nb == ni)
+               xprintf("all");
+            else
+               xprintf("%d", nb);
+            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+         }
+      }
+      xprintf("%d lines were read\n", csa->count);
+      /* problem data has been successfully read */
+      glp_sort_matrix(P);
+      ret = 0;
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      if (rf != NULL) xfree(rf);
+      if (cf != NULL) xfree(cf);
+      if (ln != NULL) xfree(ln);
+      if (ia != NULL) xfree(ia);
+      if (ja != NULL) xfree(ja);
+      if (ar != NULL) xfree(ar);
+      if (ret) glp_erase_prob(P);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_prob - write problem data in GLPK format
+*
+*  SYNOPSIS
+*
+*  int glp_write_prob(glp_prob *P, int flags, const char *fname);
+*
+*  The routine glp_write_prob writes problem data in GLPK LP/MIP format
+*  to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_prob(glp_prob *P, int flags, const char *fname)
+{     XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int mip, i, j, count, ret;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_write_prob: P = %p; invalid problem object\n",
+            P);
+      if (flags != 0)
+         xerror("glp_write_prob: flags = %d; invalid parameter\n",
+            flags);
+      if (fname == NULL)
+         xerror("glp_write_prob: fname = %d; invalid parameter\n",
+            fname);
+      xprintf("Writing problem data to `%s'...\n", fname);
+      fp = xfopen(fname, "w"), count = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* write problem line */
+      mip = (glp_get_num_int(P) > 0);
+      xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
+         P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
+         P->m, P->n, P->nnz), count++;
+      if (P->name != NULL)
+         xfprintf(fp, "n p %s\n", P->name), count++;
+      if (P->obj != NULL)
+         xfprintf(fp, "n z %s\n", P->obj), count++;
+      /* write row descriptors */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type == GLP_FX && row->lb == 0.0)
+            goto skip1;
+         xfprintf(fp, "i %d ", i), count++;
+         if (row->type == GLP_FR)
+            xfprintf(fp, "f\n");
+         else if (row->type == GLP_LO)
+            xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
+         else if (row->type == GLP_UP)
+            xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
+         else if (row->type == GLP_DB)
+            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
+                  row->ub);
+         else if (row->type == GLP_FX)
+            xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
+         else
+            xassert(row != row);
+skip1:   if (row->name != NULL)
+            xfprintf(fp, "n i %d %s\n", i, row->name), count++;
+      }
+      /* write column descriptors */
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (!mip && col->type == GLP_LO && col->lb == 0.0)
+            goto skip2;
+         if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
+             col->lb == 0.0 && col->ub == 1.0)
+            goto skip2;
+         xfprintf(fp, "j %d ", j), count++;
+         if (mip)
+         {  if (col->kind == GLP_CV)
+               xfprintf(fp, "c ");
+            else if (col->kind == GLP_IV)
+               xfprintf(fp, "i ");
+            else
+               xassert(col != col);
+         }
+         if (col->type == GLP_FR)
+            xfprintf(fp, "f\n");
+         else if (col->type == GLP_LO)
+            xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
+         else if (col->type == GLP_UP)
+            xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
+         else if (col->type == GLP_DB)
+            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
+                  col->ub);
+         else if (col->type == GLP_FX)
+            xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
+         else
+            xassert(col != col);
+skip2:   if (col->name != NULL)
+            xfprintf(fp, "n j %d %s\n", j, col->name), count++;
+      }
+      /* write objective coefficient descriptors */
+      if (P->c0 != 0.0)
+         xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->coef != 0.0)
+            xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
+               count++;
+      }
+      /* write constraint coefficient descriptors */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
+               aij->val), count++;
+      }
+      /* write end line */
+      xfprintf(fp, "e o f\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpenv.h b/optional/glpk/glpenv.h
new file mode 100644
index 0000000..67d9911
--- /dev/null
+++ b/optional/glpk/glpenv.h
@@ -0,0 +1,228 @@
+/* glpenv.h (GLPK environment) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPENV_H
+#define GLPENV_H
+
+#include "glpstd.h"
+#include "glplib.h"
+
+typedef struct ENV ENV;
+typedef struct MEM MEM;
+typedef struct XFILE XFILE;
+
+#define ENV_MAGIC 0x454E5631
+/* environment block magic value */
+
+#define TERM_BUF_SIZE 4096
+/* terminal output buffer size, in bytes */
+
+#define IOERR_MSG_SIZE 1024
+/* i/o error message buffer size, in bytes */
+
+#define MEM_MAGIC 0x4D454D31
+/* memory block descriptor magic value */
+
+struct ENV
+{     /* environment block */
+      int magic;
+      /* magic value used for debugging */
+      char version[7+1];
+      /* version string returned by the routine glp_version */
+      /*--------------------------------------------------------------*/
+      /* terminal output */
+      char *term_buf; /* char term_buf[TERM_BUF_SIZE]; */
+      /* terminal output buffer */
+      int term_out;
+      /* flag to enable/disable terminal output */
+      int (*term_hook)(void *info, const char *s);
+      /* user-defined routine to intercept terminal output */
+      void *term_info;
+      /* transit pointer (cookie) passed to the routine term_hook */
+      FILE *tee_file;
+      /* output stream used to copy terminal output */
+      /*--------------------------------------------------------------*/
+      /* error handling */
+      const char *err_file;
+      /* value of the __FILE__ macro passed to glp_error */
+      int err_line;
+      /* value of the __LINE__ macro passed to glp_error */
+      void (*err_hook)(void *info);
+      /* user-defined routine to intercept abnormal termination */
+      void *err_info;
+      /* transit pointer (cookie) passed to the routine err_hook */
+      /*--------------------------------------------------------------*/
+      /* memory allocation */
+      glp_long mem_limit;
+      /* maximal amount of memory (in bytes) available for dynamic
+         allocation */
+      MEM *mem_ptr;
+      /* pointer to the linked list of allocated memory blocks */
+      int mem_count;
+      /* total number of currently allocated memory blocks */
+      int mem_cpeak;
+      /* peak value of mem_count */
+      glp_long mem_total;
+      /* total amount of currently allocated memory (in bytes; is the
+         sum of the size field over all memory block descriptors) */
+      glp_long mem_tpeak;
+      /* peak value of mem_total */
+      /*--------------------------------------------------------------*/
+      /* stream input/output */
+      XFILE *file_ptr;
+      /* pointer to the linked list of active stream descriptors */
+      char *ioerr_msg; /* char ioerr_msg[IOERR_MSG_SIZE]; */
+      /* input/output error message buffer */
+      /*--------------------------------------------------------------*/
+      /* shared libraries support */
+      void *h_odbc;
+      /* handle to ODBC shared library */
+      void *h_mysql;
+      /* handle to MySQL shared library */
+};
+
+struct MEM
+{     /* memory block descriptor */
+      int flag;
+      /* descriptor flag */
+      int size;
+      /* size of block (in bytes, including descriptor) */
+      MEM *prev;
+      /* pointer to previous memory block descriptor */
+      MEM *next;
+      /* pointer to next memory block descriptor */
+};
+
+struct XFILE
+{     /* input/output stream descriptor */
+      int type;
+      /* stream handle type: */
+#define FH_FILE   0x11  /* FILE   */
+#define FH_ZLIB   0x22  /* gzFile */
+      void *fh;
+      /* pointer to stream handle */
+      XFILE *prev;
+      /* pointer to previous stream descriptor */
+      XFILE *next;
+      /* pointer to next stream descriptor */
+};
+
+#define XEOF (-1)
+
+#define get_env_ptr _glp_get_env_ptr
+ENV *get_env_ptr(void);
+/* retrieve pointer to environment block */
+
+#define tls_set_ptr _glp_tls_set_ptr
+void tls_set_ptr(void *ptr);
+/* store global pointer in TLS */
+
+#define tls_get_ptr _glp_tls_get_ptr
+void *tls_get_ptr(void);
+/* retrieve global pointer from TLS */
+
+#define xprintf glp_printf
+void glp_printf(const char *fmt, ...);
+/* write formatted output to the terminal */
+
+#define xvprintf glp_vprintf
+void glp_vprintf(const char *fmt, va_list arg);
+/* write formatted output to the terminal */
+
+#ifndef GLP_ERROR_DEFINED
+#define GLP_ERROR_DEFINED
+typedef void (*_glp_error)(const char *fmt, ...);
+#endif
+
+#define xerror glp_error_(__FILE__, __LINE__)
+_glp_error glp_error_(const char *file, int line);
+/* display error message and terminate execution */
+
+#define xassert(expr) \
+      ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
+void glp_assert_(const char *expr, const char *file, int line);
+/* check for logical condition */
+
+#define xmalloc glp_malloc
+void *glp_malloc(int size);
+/* allocate memory block */
+
+#define xcalloc glp_calloc
+void *glp_calloc(int n, int size);
+/* allocate memory block */
+
+#define xfree glp_free
+void glp_free(void *ptr);
+/* free memory block */
+
+#define xtime glp_time
+glp_long glp_time(void);
+/* determine current universal time */
+
+#define xdifftime glp_difftime
+double glp_difftime(glp_long t1, glp_long t0);
+/* compute difference between two time values, in seconds */
+
+#define lib_err_msg _glp_lib_err_msg
+void lib_err_msg(const char *msg);
+
+#define xerrmsg _glp_lib_xerrmsg
+const char *xerrmsg(void);
+
+#define xfopen _glp_lib_xfopen
+XFILE *xfopen(const char *fname, const char *mode);
+
+#define xferror _glp_lib_xferror
+int xferror(XFILE *file);
+
+#define xfeof _glp_lib_xfeof
+int xfeof(XFILE *file);
+
+#define xfgetc _glp_lib_xfgetc
+int xfgetc(XFILE *file);
+
+#define xfputc _glp_lib_xfputc
+int xfputc(int c, XFILE *file);
+
+#define xfflush _glp_lib_xfflush
+int xfflush(XFILE *fp);
+
+#define xfclose _glp_lib_xfclose
+int xfclose(XFILE *file);
+
+#define xfprintf _glp_lib_xfprintf
+int xfprintf(XFILE *file, const char *fmt, ...);
+
+#define xdlopen _glp_xdlopen
+void *xdlopen(const char *module);
+
+#define xdlsym _glp_xdlsym
+void *xdlsym(void *h, const char *symbol);
+
+#define xdlclose _glp_xdlclose
+void xdlclose(void *h);
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpenv01.c b/optional/glpk/glpenv01.c
new file mode 100644
index 0000000..d1afbe4
--- /dev/null
+++ b/optional/glpk/glpenv01.c
@@ -0,0 +1,234 @@
+/* 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/optional/glpk/glpenv02.c b/optional/glpk/glpenv02.c
new file mode 100644
index 0000000..c09ec20
--- /dev/null
+++ b/optional/glpk/glpenv02.c
@@ -0,0 +1,73 @@
+/* glpenv02.c (thread local storage) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpenv.h"
+
+static void *tls = NULL;
+/* in a re-entrant version of the package this variable must be placed
+   in the Thread Local Storage (TLS) */
+
+/***********************************************************************
+*  NAME
+*
+*  tls_set_ptr - store global pointer in TLS
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  void tls_set_ptr(void *ptr);
+*
+*  DESCRIPTION
+*
+*  The routine tls_set_ptr stores a pointer specified by the parameter
+*  ptr in the Thread Local Storage (TLS). */
+
+void tls_set_ptr(void *ptr)
+{     tls = ptr;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  tls_get_ptr - retrieve global pointer from TLS
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  void *tls_get_ptr(void);
+*
+*  RETURNS
+*
+*  The routine tls_get_ptr returns a pointer previously stored by the
+*  routine tls_set_ptr. If the latter has not been called yet, NULL is
+*  returned. */
+
+void *tls_get_ptr(void)
+{     void *ptr;
+      ptr = tls;
+      return ptr;
+}
+
+/* eof */
diff --git a/optional/glpk/glpenv03.c b/optional/glpk/glpenv03.c
new file mode 100644
index 0000000..6249c25
--- /dev/null
+++ b/optional/glpk/glpenv03.c
@@ -0,0 +1,233 @@
+/* glpenv03.c (terminal output) */
+
+/***********************************************************************
+*  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 "-Wunused-label"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_printf - write formatted output to terminal
+*
+*  SYNOPSIS
+*
+*  void glp_printf(const char *fmt, ...);
+*
+*  DESCRIPTION
+*
+*  The routine glp_printf uses the format control string fmt to format
+*  its parameters and writes the formatted output to the terminal. */
+
+void glp_printf(const char *fmt, ...)
+{     va_list arg;
+      /* va_start(arg, fmt); */
+      /* xvprintf(fmt, arg); */
+      /* va_end(arg); */
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_vprintf - write formatted output to terminal
+*
+*  SYNOPSIS
+*
+*  void glp_vprintf(const char *fmt, va_list arg);
+*
+*  DESCRIPTION
+*
+*  The routine glp_vprintf uses the format control string fmt to format
+*  its parameters specified by the list arg and writes the formatted
+*  output to the terminal. */
+
+void glp_vprintf(const char *fmt, va_list arg)
+{     ENV *env = get_env_ptr();
+      /* if terminal output is disabled, do nothing */
+      /* if (!env->term_out) goto skip; */
+      /* /\* format the output *\/ */
+      /* vsprintf(env->term_buf, fmt, arg); */
+      /* /\* pass the output to the user-defined routine *\/ */
+      /* if (env->term_hook != NULL) */
+      /* {  if (env->term_hook(env->term_info, env->term_buf) != 0) */
+      /*       goto skip; */
+      /* } */
+      /* /\* send the output to the terminal *\/ */
+      /* fputs(env->term_buf, stdout); */
+      /* fflush(stdout); */
+      /* /\* copy the output to the text file *\/ */
+      /* if (env->tee_file != NULL) */
+      /* {  fputs(env->term_buf, env->tee_file); */
+      /*    fflush(env->tee_file); */
+      /* } */
+skip: return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_term_out - enable/disable terminal output
+*
+*  SYNOPSIS
+*
+*  int glp_term_out(int flag);
+*
+*  DESCRIPTION
+*
+*  Depending on the parameter flag the routine glp_term_out enables or
+*  disables terminal output performed by glpk routines:
+*
+*  GLP_ON  - enable terminal output;
+*  GLP_OFF - disable terminal output.
+*
+*  RETURNS
+*
+*  The routine glp_term_out returns the previous value of the terminal
+*  output flag. */
+
+int glp_term_out(int flag)
+{     ENV *env = get_env_ptr();
+      int old = env->term_out;
+      if (!(flag == GLP_ON || flag == GLP_OFF))
+         xerror("glp_term_out: flag = %d; invalid value\n", flag);
+      env->term_out = flag;
+      return old;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_term_hook - install hook to intercept terminal output
+*
+*  SYNOPSIS
+*
+*  void glp_term_hook(int (*func)(void *info, const char *s),
+*     void *info);
+*
+*  DESCRIPTION
+*
+*  The routine glp_term_hook installs a user-defined hook routine to
+*  intercept all terminal output performed by glpk routines.
+*
+*  This feature can be used to redirect the terminal output to other
+*  destination, for example to a file or a text window.
+*
+*  The parameter func specifies the user-defined hook routine. It is
+*  called from an internal printing routine, which passes to it two
+*  parameters: info and s. The parameter info is a transit pointer,
+*  specified in the corresponding call to the routine glp_term_hook;
+*  it may be used to pass some information to the hook routine. The
+*  parameter s is a pointer to the null terminated character string,
+*  which is intended to be written to the terminal. If the hook routine
+*  returns zero, the printing routine writes the string s to the
+*  terminal in a usual way; otherwise, if the hook routine returns
+*  non-zero, no terminal output is performed.
+*
+*  To uninstall the hook routine the parameters func and info should be
+*  specified as NULL. */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info)
+{     ENV *env = get_env_ptr();
+      if (func == NULL)
+      {  env->term_hook = NULL;
+         env->term_info = NULL;
+      }
+      else
+      {  env->term_hook = func;
+         env->term_info = info;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_open_tee - start copying terminal output to text file
+*
+*  SYNOPSIS
+*
+*  int glp_open_tee(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_open_tee starts copying all the terminal output to
+*  an output text file, whose name is specified by the character string
+*  fname.
+*
+*  RETURNS
+*
+*  0 - operation successful
+*  1 - copying terminal output is already active
+*  2 - unable to create output file */
+
+int glp_open_tee(const char *fname)
+{     ENV *env = get_env_ptr();
+      if (env->tee_file != NULL)
+      {  /* copying terminal output is already active */
+         return 1;
+      }
+      env->tee_file = fopen(fname, "w");
+      if (env->tee_file == NULL)
+      {  /* unable to create output file */
+         return 2;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_close_tee - stop copying terminal output to text file
+*
+*  SYNOPSIS
+*
+*  int glp_close_tee(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_close_tee stops copying the terminal output to the
+*  output text file previously open by the routine glp_open_tee closing
+*  that file.
+*
+*  RETURNS
+*
+*  0 - operation successful
+*  1 - copying terminal output was not started */
+
+int glp_close_tee(void)
+{     ENV *env = get_env_ptr();
+      if (env->tee_file == NULL)
+      {  /* copying terminal output was not started */
+         return 1;
+      }
+      fclose(env->tee_file);
+      env->tee_file = NULL;
+      return 0;
+}
+
+/* eof */
diff --git a/optional/glpk/glpenv04.c b/optional/glpk/glpenv04.c
new file mode 100644
index 0000000..ca03102
--- /dev/null
+++ b/optional/glpk/glpenv04.c
@@ -0,0 +1,118 @@
+/* glpenv04.c (error handling) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "igraph_error.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_error - display error message and terminate execution
+*
+*  SYNOPSIS
+*
+*  void glp_error(const char *fmt, ...);
+*
+*  DESCRIPTION
+*
+*  The routine glp_error (implemented as a macro) formats its
+*  parameters using the format control string fmt, writes the formatted
+*  message to the terminal, and abnormally terminates the program. */
+
+static void error(const char *fmt, ...)
+{     ENV *env = get_env_ptr();
+      va_list arg;
+      env->term_out = GLP_ON;
+      va_start(arg, fmt);
+      igraph_errorvf(fmt, env->err_file, env->err_line, IGRAPH_EGLP, arg);
+      /* no return */
+}
+
+_glp_error glp_error_(const char *file, int line)
+{     ENV *env = get_env_ptr();
+      env->err_file = file;
+      env->err_line = line;
+      return error;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_assert - check for logical condition
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  void glp_assert(int expr);
+*
+*  DESCRIPTION
+*
+*  The routine glp_assert (implemented as a macro) checks for a logical
+*  condition specified by the parameter expr. If the condition is false
+*  (i.e. the value of expr is zero), the routine writes a message to
+*  the terminal and abnormally terminates the program. */
+
+void glp_assert_(const char *expr, const char *file, int line)
+{     glp_error_(file, line)("Assertion failed: %s\n", expr);
+      /* no return */
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_error_hook - install hook to intercept abnormal termination
+*
+*  SYNOPSIS
+*
+*  void glp_error_hook(void (*func)(void *info), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine glp_error_hook installs a user-defined hook routine to
+*  intercept abnormal termination.
+*
+*  The parameter func specifies the user-defined hook routine. It is
+*  called from the routine glp_error before the latter calls the abort
+*  function to abnormally terminate the application program because of
+*  fatal error. The parameter info is a transit pointer, specified in
+*  the corresponding call to the routine glp_error_hook; it may be used
+*  to pass some information to the hook routine.
+*
+*  To uninstall the hook routine the parameters func and info should be
+*  specified as NULL. */
+
+void glp_error_hook(void (*func)(void *info), void *info)
+{     ENV *env = get_env_ptr();
+      if (func == NULL)
+      {  env->err_hook = NULL;
+         env->err_info = NULL;
+      }
+      else
+      {  env->err_hook = func;
+         env->err_info = info;
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpenv05.c b/optional/glpk/glpenv05.c
new file mode 100644
index 0000000..d4b34fb
--- /dev/null
+++ b/optional/glpk/glpenv05.c
@@ -0,0 +1,229 @@
+/* glpenv05.c (memory allocation) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpapi.h"
+
+/* some processors need data to be properly aligned; the macro
+   align_datasize enlarges the specified size of a data item to provide
+   a proper alignment of immediately following data */
+
+#define align_datasize(size) ((((size) + 15) / 16) * 16)
+/* 16 bytes is sufficient in both 32- and 64-bit environments
+   (8 bytes is not sufficient in 64-bit environment due to jmp_buf) */
+
+/***********************************************************************
+*  NAME
+*
+*  glp_malloc - allocate memory block
+*
+*  SYNOPSIS
+*
+*  void *glp_malloc(int size);
+*
+*  DESCRIPTION
+*
+*  The routine glp_malloc allocates a memory block of size bytes long.
+*
+*  Note that being allocated the memory block contains arbitrary data
+*  (not binary zeros).
+*
+*  RETURNS
+*
+*  The routine glp_malloc returns a pointer to the allocated block.
+*  To free this block the routine glp_free (not free!) must be used. */
+
+void *glp_malloc(int size)
+{     ENV *env = get_env_ptr();
+      MEM *desc;
+      int size_of_desc = align_datasize(sizeof(MEM));
+      if (size < 1 || size > INT_MAX - size_of_desc)
+         xerror("glp_malloc: size = %d; invalid parameter\n", size);
+      size += size_of_desc;
+      if (xlcmp(xlset(size),
+          xlsub(env->mem_limit, env->mem_total)) > 0)
+         xerror("glp_malloc: memory limit exceeded\n");
+      if (env->mem_count == INT_MAX)
+         xerror("glp_malloc: too many memory blocks allocated\n");
+      desc = malloc(size);
+      if (desc == NULL)
+         xerror("glp_malloc: no memory available\n");
+      memset(desc, '?', size);
+      desc->flag = MEM_MAGIC;
+      desc->size = size;
+      desc->prev = NULL;
+      desc->next = env->mem_ptr;
+      if (desc->next != NULL) desc->next->prev = desc;
+      env->mem_ptr = desc;
+      env->mem_count++;
+      if (env->mem_cpeak < env->mem_count)
+         env->mem_cpeak = env->mem_count;
+      env->mem_total = xladd(env->mem_total, xlset(size));
+      if (xlcmp(env->mem_tpeak, env->mem_total) < 0)
+         env->mem_tpeak = env->mem_total;
+      return (void *)((char *)desc + size_of_desc);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_calloc - allocate memory block
+*
+*  SYNOPSIS
+*
+*  void *glp_calloc(int n, int size);
+*
+*  DESCRIPTION
+*
+*  The routine glp_calloc allocates a memory block of (n*size) bytes
+*  long.
+*
+*  Note that being allocated the memory block contains arbitrary data
+*  (not binary zeros).
+*
+*  RETURNS
+*
+*  The routine glp_calloc returns a pointer to the allocated block.
+*  To free this block the routine glp_free (not free!) must be used. */
+
+void *glp_calloc(int n, int size)
+{     if (n < 1)
+         xerror("glp_calloc: n = %d; invalid parameter\n", n);
+      if (size < 1)
+         xerror("glp_calloc: size = %d; invalid parameter\n", size);
+      if (n > INT_MAX / size)
+         xerror("glp_calloc: n = %d; size = %d; array too big\n", n,
+            size);
+      return xmalloc(n * size);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_free - free memory block
+*
+*  SYNOPSIS
+*
+*  void glp_free(void *ptr);
+*
+*  DESCRIPTION
+*
+*  The routine glp_free frees a memory block pointed to by ptr, which
+*  was previuosly allocated by the routine glp_malloc or glp_calloc. */
+
+void glp_free(void *ptr)
+{     ENV *env = get_env_ptr();
+      MEM *desc;
+      int size_of_desc = align_datasize(sizeof(MEM));
+      if (ptr == NULL)
+         xerror("glp_free: ptr = %p; null pointer\n", ptr);
+      desc = (void *)((char *)ptr - size_of_desc);
+      if (desc->flag != MEM_MAGIC)
+         xerror("glp_free: ptr = %p; invalid pointer\n", ptr);
+      if (env->mem_count == 0 ||
+          xlcmp(env->mem_total, xlset(desc->size)) < 0)
+         xerror("glp_free: memory allocation error\n");
+      if (desc->prev == NULL)
+         env->mem_ptr = desc->next;
+      else
+         desc->prev->next = desc->next;
+      if (desc->next == NULL)
+         ;
+      else
+         desc->next->prev = desc->prev;
+      env->mem_count--;
+      env->mem_total = xlsub(env->mem_total, xlset(desc->size));
+      memset(desc, '?', size_of_desc);
+      free(desc);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mem_limit - set memory usage limit
+*
+*  SYNOPSIS
+*
+*  void glp_mem_limit(int limit);
+*
+*  DESCRIPTION
+*
+*  The routine glp_mem_limit limits the amount of memory available for
+*  dynamic allocation (in GLPK routines) to limit megabytes. */
+
+void glp_mem_limit(int limit)
+{     ENV *env = get_env_ptr();
+      if (limit < 0)
+         xerror("glp_mem_limit: limit = %d; invalid parameter\n",
+            limit);
+      env->mem_limit = xlmul(xlset(limit), xlset(1 << 20));
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mem_usage - get memory usage information
+*
+*  SYNOPSIS
+*
+*  void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+*     glp_long *tpeak);
+*
+*  DESCRIPTION
+*
+*  The routine glp_mem_usage reports some information about utilization
+*  of the memory by GLPK routines. Information is stored to locations
+*  specified by corresponding parameters (see below). Any parameter can
+*  be specified as NULL, in which case corresponding information is not
+*  stored.
+*
+*  *count is the number of the memory blocks currently allocated by the
+*  routines xmalloc and xcalloc (one call to xmalloc or xcalloc results
+*  in allocating one memory block).
+*
+*  *cpeak is the peak value of *count reached since the initialization
+*  of the GLPK library environment.
+*
+*  *total is the total amount, in bytes, of the memory blocks currently
+*  allocated by the routines xmalloc and xcalloc.
+*
+*  *tpeak is the peak value of *total reached since the initialization
+*  of the GLPK library envirionment. */
+
+void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+      glp_long *tpeak)
+{     ENV *env = get_env_ptr();
+      if (count != NULL) *count = env->mem_count;
+      if (cpeak != NULL) *cpeak = env->mem_cpeak;
+      if (total != NULL) *total = env->mem_total;
+      if (tpeak != NULL) *tpeak = env->mem_tpeak;
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpenv06.c b/optional/glpk/glpenv06.c
new file mode 100644
index 0000000..1f33262
--- /dev/null
+++ b/optional/glpk/glpenv06.c
@@ -0,0 +1,172 @@
+/* glpenv06.c (standard time) */
+
+/***********************************************************************
+*  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 HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_time - determine current universal time
+*
+*  SYNOPSIS
+*
+*  glp_long glp_time(void);
+*
+*  RETURNS
+*
+*  The routine glp_time returns the current universal time (UTC), in
+*  milliseconds, elapsed since 00:00:00 GMT January 1, 1970. */
+
+static const int epoch = 2440588; /* = jday(1, 1, 1970) */
+
+/* POSIX version ******************************************************/
+
+#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)
+
+#include <sys/time.h>
+#include <time.h>
+
+glp_long glp_time(void)
+{     struct timeval tv;
+      struct tm *tm;
+      glp_long t;
+      int j;
+      gettimeofday(&tv, NULL);
+      tm = gmtime(&tv.tv_sec);
+      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+      xassert(j >= 0);
+      t = xlset(j - epoch);
+      t = xlmul(t, xlset(24));
+      t = xladd(t, xlset(tm->tm_hour));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_min));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_sec));
+      t = xlmul(t, xlset(1000));
+      t = xladd(t, xlset(tv.tv_usec / 1000));
+      return t;
+}
+
+/* Windows version ****************************************************/
+
+#elif defined(__WOE__)
+
+#include <windows.h>
+
+glp_long glp_time(void)
+{     SYSTEMTIME st;
+      glp_long t;
+      int j;
+      GetSystemTime(&st);
+      j = jday(st.wDay, st.wMonth, st.wYear);
+      xassert(j >= 0);
+      t = xlset(j - epoch);
+      t = xlmul(t, xlset(24));
+      t = xladd(t, xlset(st.wHour));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(st.wMinute));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(st.wSecond));
+      t = xlmul(t, xlset(1000));
+      t = xladd(t, xlset(st.wMilliseconds));
+      return t;
+}
+
+/* portable ISO C version *********************************************/
+
+#else
+
+#include <time.h>
+
+glp_long glp_time(void)
+{     time_t timer;
+      struct tm *tm;
+      glp_long t;
+      int j;
+      timer = time(NULL);
+      tm = gmtime(&timer);
+      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+      xassert(j >= 0);
+      t = xlset(j - epoch);
+      t = xlmul(t, xlset(24));
+      t = xladd(t, xlset(tm->tm_hour));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_min));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_sec));
+      t = xlmul(t, xlset(1000));
+      return t;
+}
+
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  glp_difftime - compute difference between two time values
+*
+*  SYNOPSIS
+*
+*  double glp_difftime(glp_long t1, glp_long t0);
+*
+*  RETURNS
+*
+*  The routine glp_difftime returns the difference between two time
+*  values t1 and t0, expressed in seconds. */
+
+double glp_difftime(glp_long t1, glp_long t0)
+{     return
+         xltod(xlsub(t1, t0)) / 1000.0;
+}
+
+/**********************************************************************/
+
+#if 0
+int main(void)
+{     glp_long t;
+      glp_ldiv d;
+      int ttt, ss, mm, hh, day, month, year;
+      char s[50];
+      t = glp_time();
+      xprintf("t = %s\n", xltoa(t, s));
+      d = xldiv(t, xlset(1000));
+      ttt = d.rem.lo, t = d.quot;
+      d = xldiv(t, xlset(60));
+      ss = d.rem.lo, t = d.quot;
+      d = xldiv(t, xlset(60));
+      mm = d.rem.lo, t = d.quot;
+      d = xldiv(t, xlset(24));
+      hh = d.rem.lo, t = d.quot;
+      xassert(jdate(t.lo + epoch, &day, &month, &year) == 0);
+      xprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d\n", year, month, day,
+         hh, mm, ss, ttt);
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpenv07.c b/optional/glpk/glpenv07.c
new file mode 100644
index 0000000..12d5118
--- /dev/null
+++ b/optional/glpk/glpenv07.c
@@ -0,0 +1,676 @@
+/* glpenv07.c (stream input/output) */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpenv.h"
+
+/***********************************************************************
+*  NAME
+*
+*  lib_err_msg - save error message string
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  void lib_err_msg(const char *msg);
+*
+*  DESCRIPTION
+*
+*  The routine lib_err_msg saves an error message string specified by
+*  the parameter msg. The message is obtained by some library routines
+*  with a call to strerror(errno). */
+
+void lib_err_msg(const char *msg)
+{     ENV *env = get_env_ptr();
+      int len = strlen(msg);
+      if (len >= IOERR_MSG_SIZE)
+         len = IOERR_MSG_SIZE - 1;
+      memcpy(env->ioerr_msg, msg, len);
+      if (len > 0 && env->ioerr_msg[len-1] == '\n') len--;
+      env->ioerr_msg[len] = '\0';
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xerrmsg - retrieve error message string
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  const char *xerrmsg(void);
+*
+*  RETURNS
+*
+*  The routine xerrmsg returns a pointer to an error message string
+*  previously set by some library routine to indicate an error. */
+
+const char *xerrmsg(void)
+{     ENV *env = get_env_ptr();
+      return env->ioerr_msg;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfopen - open a stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  XFILE *xfopen(const char *fname, const char *mode);
+*
+*  DESCRIPTION
+*
+*  The routine xfopen opens the file whose name is a string pointed to
+*  by fname and associates a stream with it.
+*
+*  The parameter mode points to a string, which indicates the open mode
+*  and should be one of the following:
+*
+*  "r"   open text file for reading;
+*  "w"   truncate to zero length or create text file for writing;
+*  "rb"  open binary file for reading;
+*  "wb"  truncate to zero length or create binary file for writing.
+*
+*  RETURNS
+*
+*  The routine xfopen returns a pointer to the object controlling the
+*  stream. If the open operation fails, xfopen returns NULL. */
+
+static void *c_fopen(const char *fname, const char *mode);
+static void *z_fopen(const char *fname, const char *mode);
+
+static int is_gz_file(const char *fname)
+{     char *ext = strrchr(fname, '.');
+      return ext != NULL && strcmp(ext, ".gz") == 0;
+}
+
+XFILE *xfopen(const char *fname, const char *mode)
+{     ENV *env = get_env_ptr();
+      XFILE *fp;
+      int type;
+      void *fh;
+      if (!is_gz_file(fname))
+      {  type = FH_FILE;
+         fh = c_fopen(fname, mode);
+      }
+      else
+      {  type = FH_ZLIB;
+         fh = z_fopen(fname, mode);
+      }
+      if (fh == NULL)
+      {  fp = NULL;
+         goto done;
+      }
+      fp = xmalloc(sizeof(XFILE));
+      fp->type = type;
+      fp->fh = fh;
+      fp->prev = NULL;
+      fp->next = env->file_ptr;
+      if (fp->next != NULL) fp->next->prev = fp;
+      env->file_ptr = fp;
+done: return fp;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfgetc - read character from the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfgetc(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  If the end-of-file indicator for the input stream pointed to by fp
+*  is not set and a next character is present, the routine xfgetc
+*  obtains that character as an unsigned char converted to an int and
+*  advances the associated file position indicator for the stream (if
+*  defined).
+*
+*  RETURNS
+*
+*  If the end-of-file indicator for the stream is set, or if the
+*  stream is at end-of-file, the end-of-file indicator for the stream
+*  is set and the routine xfgetc returns XEOF. Otherwise, the routine
+*  xfgetc returns the next character from the input stream pointed to
+*  by fp. If a read error occurs, the error indicator for the stream is
+*  set and the xfgetc routine returns XEOF.
+*
+*  Note: An end-of-file and a read error can be distinguished by use of
+*  the routines xfeof and xferror. */
+
+static int c_fgetc(void *fh);
+static int z_fgetc(void *fh);
+
+int xfgetc(XFILE *fp)
+{     int c;
+      switch (fp->type)
+      {  case FH_FILE:
+            c = c_fgetc(fp->fh);
+            break;
+         case FH_ZLIB:
+            c = z_fgetc(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return c;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfputc - write character to the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfputc(int c, XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xfputc writes the character specified by c (converted
+*  to an unsigned char) to the output stream pointed to by fp, at the
+*  position indicated by the associated file position indicator (if
+*  defined), and advances the indicator appropriately.
+*
+*  RETURNS
+*
+*  The routine xfputc returns the character written. If a write error
+*  occurs, the error indicator for the stream is set and xfputc returns
+*  XEOF. */
+
+static int c_fputc(int c, void *fh);
+static int z_fputc(int c, void *fh);
+
+int xfputc(int c, XFILE *fp)
+{     switch (fp->type)
+      {  case FH_FILE:
+            c = c_fputc(c, fp->fh);
+            break;
+         case FH_ZLIB:
+            c = z_fputc(c, fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return c;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xferror - test error indicator for the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xferror(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xferror tests the error indicator for the stream
+*  pointed to by fp.
+*
+*  RETURNS
+*
+*  The routine xferror returns non-zero if and only if the error
+*  indicator is set for the stream. */
+
+static int c_ferror(void *fh);
+static int z_ferror(void *fh);
+
+int xferror(XFILE *fp)
+{     int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_ferror(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_ferror(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfeof - test end-of-file indicator for the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfeof(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xfeof tests the end-of-file indicator for the stream
+*  pointed to by fp.
+*
+*  RETURNS
+*
+*  The routine xfeof returns non-zero if and only if the end-of-file
+*  indicator is set for the stream. */
+
+static int c_feof(void *fh);
+static int z_feof(void *fh);
+
+int xfeof(XFILE *fp)
+{     int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_feof(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_feof(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return ret;
+}
+
+int xfprintf(XFILE *file, const char *fmt, ...)
+{     ENV *env = get_env_ptr();
+      int cnt, j;
+      va_list arg;
+      va_start(arg, fmt);
+      cnt = vsprintf(env->term_buf, fmt, arg);
+      va_end(arg);
+      for (j = 0; j < cnt; j++)
+      {  if (xfputc(env->term_buf[j], file) < 0)
+         {  cnt = -1;
+            break;
+         }
+      }
+      return cnt;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfflush - flush the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfflush(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xfflush causes any unwritten data for the output stream
+*  pointed to by fp to be written to the associated file.
+*
+*  RETURNS
+*
+*  The routine xfflush returns zero if the stream was successfully
+*  flushed. Otherwise, xfflush sets the error indicator for the stream
+*  and returns XEOF. */
+
+static int c_fflush(void *fh);
+static int z_fflush(void *fh);
+
+int xfflush(XFILE *fp)
+{     int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_fflush(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_fflush(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfclose - close the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfclose(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  A successful call to the routine xfclose causes the stream pointed
+*  to by fp to be flushed and the associated file to be closed. Whether
+*  or not the call succeeds, the stream is disassociated from the file.
+*
+*  RETURNS
+*
+*  The routine xfclose returns zero if the stream was successfully
+*  closed, or XEOF if any errors were detected. */
+
+static int c_fclose(void *fh);
+static int z_fclose(void *fh);
+
+int xfclose(XFILE *fp)
+{     ENV *env = get_env_ptr();
+      int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_fclose(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_fclose(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      fp->type = 0xF00BAD;
+      if (fp->prev == NULL)
+         env->file_ptr = fp->next;
+      else
+         fp->prev->next = fp->next;
+      if (fp->next == NULL)
+         ;
+      else
+         fp->next->prev = fp->prev;
+      xfree(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  The following routines implement stream input/output based on the
+*  standard C streams. */
+
+static void *c_fopen(const char *fname, const char *mode)
+{     FILE *fh;
+      /* if (strcmp(fname, "/dev/stdin") == 0) */
+      /*    fh = stdin; */
+      /* else if (strcmp(fname, "/dev/stdout") == 0) */
+      /*    fh = stdout; */
+      /* else if (strcmp(fname, "/dev/stderr") == 0) */
+      /*    fh = stderr; */
+      /* else */
+         fh = fopen(fname, mode);
+      if (fh == NULL)
+         lib_err_msg(strerror(errno));
+      return fh;
+}
+
+static int c_fgetc(void *_fh)
+{     FILE *fh = _fh;
+      int c;
+      if (ferror(fh) || feof(fh))
+      {  c = XEOF;
+         goto done;
+      }
+      c = fgetc(fh);
+      if (ferror(fh))
+      {  lib_err_msg(strerror(errno));
+         c = XEOF;
+      }
+      else if (feof(fh))
+         c = XEOF;
+      else
+         xassert(0x00 <= c && c <= 0xFF);
+done: return c;
+}
+
+static int c_fputc(int c, void *_fh)
+{     FILE *fh = _fh;
+      if (ferror(fh))
+      {  c = XEOF;
+         goto done;
+      }
+      c = (unsigned char)c;
+      fputc(c, fh);
+      if (ferror(fh))
+      {  lib_err_msg(strerror(errno));
+         c = XEOF;
+      }
+done: return c;
+}
+
+static int c_ferror(void *_fh)
+{     FILE *fh = _fh;
+      return ferror(fh);
+}
+
+static int c_feof(void *_fh)
+{     FILE *fh = _fh;
+      return feof(fh);
+}
+
+static int c_fflush(void *_fh)
+{     FILE *fh = _fh;
+      int ret;
+      ret = fflush(fh);
+      if (ret != 0)
+      {  lib_err_msg(strerror(errno));
+         ret = XEOF;
+      }
+      return ret;
+}
+
+static int c_fclose(void *_fh)
+{     FILE *fh = _fh;
+      int ret;
+      /* if (fh == stdin) */
+      /*    ret = 0; */
+      /* else if (fh == stdout || fh == stderr) */
+      /*    fflush(fh), ret = 0; */
+      /* else */
+         ret = fclose(fh);
+      if (ret != 0)
+      {  lib_err_msg(strerror(errno));
+         ret = XEOF;
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  The following routines implement stream input/output based on the
+*  zlib library, which provides processing .gz files "on the fly". */
+
+#ifndef HAVE_ZLIB
+
+static void *z_fopen(const char *fname, const char *mode)
+{     xassert(fname == fname);
+      xassert(mode == mode);
+      lib_err_msg("Compressed files not supported");
+      return NULL;
+}
+
+static int z_fgetc(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_fputc(int c, void *fh)
+{     xassert(c != c);
+      xassert(fh != fh);
+      return 0;
+}
+
+static int z_ferror(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_feof(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_fflush(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_fclose(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+#else
+
+#include <zlib.h>
+
+struct z_file
+{     /* .gz file handle */
+      gzFile file;
+      /* pointer to .gz stream */
+      int err;
+      /* i/o error indicator */
+      int eof;
+      /* end-of-file indicator */
+};
+
+static void *z_fopen(const char *fname, const char *mode)
+{     struct z_file *fh;
+      gzFile file;
+      if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
+         mode = "rb";
+      else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
+         mode = "wb";
+      else
+      {  lib_err_msg("Invalid open mode");
+         fh = NULL;
+         goto done;
+      }
+      file = gzopen(fname, mode);
+      if (file == NULL)
+      {  lib_err_msg(strerror(errno));
+         fh = NULL;
+         goto done;
+      }
+      fh = xmalloc(sizeof(struct z_file));
+      fh->file = file;
+      fh->err = fh->eof = 0;
+done: return fh;
+}
+
+static int z_fgetc(void *_fh)
+{     struct z_file *fh = _fh;
+      int c;
+      if (fh->err || fh->eof)
+      {  c = XEOF;
+         goto done;
+      }
+      c = gzgetc(fh->file);
+      if (c < 0)
+      {  int errnum;
+         const char *msg;
+         msg = gzerror(fh->file, &errnum);
+         if (errnum == Z_STREAM_END)
+            fh->eof = 1;
+         else if (errnum == Z_ERRNO)
+         {  fh->err = 1;
+            lib_err_msg(strerror(errno));
+         }
+         else
+         {  fh->err = 1;
+            lib_err_msg(msg);
+         }
+         c = XEOF;
+      }
+      else
+         xassert(0x00 <= c && c <= 0xFF);
+done: return c;
+}
+
+static int z_fputc(int c, void *_fh)
+{     struct z_file *fh = _fh;
+      if (fh->err)
+      {  c = XEOF;
+         goto done;
+      }
+      c = (unsigned char)c;
+      if (gzputc(fh->file, c) < 0)
+      {  int errnum;
+         const char *msg;
+         fh->err = 1;
+         msg = gzerror(fh->file, &errnum);
+         if (errnum == Z_ERRNO)
+            lib_err_msg(strerror(errno));
+         else
+            lib_err_msg(msg);
+         c = XEOF;
+      }
+done: return c;
+}
+
+static int z_ferror(void *_fh)
+{     struct z_file *fh = _fh;
+      return fh->err;
+}
+
+static int z_feof(void *_fh)
+{     struct z_file *fh = _fh;
+      return fh->eof;
+}
+
+static int z_fflush(void *_fh)
+{     struct z_file *fh = _fh;
+      int ret;
+      ret = gzflush(fh->file, Z_FINISH);
+      if (ret == Z_OK)
+         ret = 0;
+      else
+      {  int errnum;
+         const char *msg;
+         fh->err = 1;
+         msg = gzerror(fh->file, &errnum);
+         if (errnum == Z_ERRNO)
+            lib_err_msg(strerror(errno));
+         else
+            lib_err_msg(msg);
+         ret = XEOF;
+      }
+      return ret;
+}
+
+static int z_fclose(void *_fh)
+{     struct z_file *fh = _fh;
+      gzclose(fh->file);
+      xfree(fh);
+      return 0;
+}
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpenv08.c b/optional/glpk/glpenv08.c
new file mode 100644
index 0000000..d708fbf
--- /dev/null
+++ b/optional/glpk/glpenv08.c
@@ -0,0 +1,156 @@
+/* glpenv08.c (shared library support) */
+
+/***********************************************************************
+*  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 HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpenv.h"
+
+/* GNU version ********************************************************/
+
+#if defined(HAVE_LTDL)
+
+#include <ltdl.h>
+
+void *xdlopen(const char *module)
+{     void *h = NULL;
+      if (lt_dlinit() != 0)
+      {  lib_err_msg(lt_dlerror());
+         goto done;
+      }
+      h = lt_dlopen(module);
+      if (h == NULL)
+      {  lib_err_msg(lt_dlerror());
+         if (lt_dlexit() != 0)
+            xerror("xdlopen: %s\n", lt_dlerror());
+      }
+done: return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     void *ptr;
+      xassert(h != NULL);
+      ptr = lt_dlsym(h, symbol);
+      if (ptr == NULL)
+         xerror("xdlsym: %s: %s\n", symbol, lt_dlerror());
+      return ptr;
+}
+
+void xdlclose(void *h)
+{     xassert(h != NULL);
+      if (lt_dlclose(h) != 0)
+         xerror("xdlclose: %s\n", lt_dlerror());
+      if (lt_dlexit() != 0)
+         xerror("xdlclose: %s\n", lt_dlerror());
+      return;
+}
+
+/* POSIX version ******************************************************/
+
+#elif defined(HAVE_DLFCN)
+
+#include <dlfcn.h>
+
+void *xdlopen(const char *module)
+{     void *h;
+      h = dlopen(module, RTLD_NOW);
+      if (h == NULL)
+         lib_err_msg(dlerror());
+      return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     void *ptr;
+      xassert(h != NULL);
+      ptr = dlsym(h, symbol);
+      if (ptr == NULL)
+         xerror("xdlsym: %s: %s\n", symbol, dlerror());
+      return ptr;
+}
+
+void xdlclose(void *h)
+{     xassert(h != NULL);
+      if (dlclose(h) != 0)
+         xerror("xdlclose: %s\n", dlerror());
+      return;
+}
+
+/* Windows version ****************************************************/
+
+#elif defined(__WOE__)
+
+#include <windows.h>
+
+void *xdlopen(const char *module)
+{     void *h;
+      h = LoadLibrary(module);
+      if (h == NULL)
+      {  char msg[20];
+         sprintf(msg, "Error %d", GetLastError());
+         lib_err_msg(msg);
+      }
+      return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     void *ptr;
+      xassert(h != NULL);
+      ptr = GetProcAddress(h, symbol);
+      if (ptr == NULL)
+         xerror("xdlsym: %s: Error %d\n", symbol, GetLastError());
+      return ptr;
+}
+
+void xdlclose(void *h)
+{     xassert(h != NULL);
+      if (!FreeLibrary(h))
+         xerror("xdlclose: Error %d\n", GetLastError());
+      return;
+}
+
+/* NULL version *******************************************************/
+
+#else
+
+void *xdlopen(const char *module)
+{     xassert(module == module);
+      lib_err_msg("Shared libraries not supported");
+      return NULL;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     xassert(h != h);
+      xassert(symbol != symbol);
+      return NULL;
+}
+
+void xdlclose(void *h)
+{     xassert(h != h);
+      return;
+}
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpfhv.c b/optional/glpk/glpfhv.c
new file mode 100644
index 0000000..84ef12a
--- /dev/null
+++ b/optional/glpk/glpfhv.c
@@ -0,0 +1,778 @@
+/* glpfhv.c (LP basis factorization, FHV eta file version) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpfhv.h"
+#include "glpenv.h"
+#define xfault xerror
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the basis matrix */
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_create_it - create LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  FHV *fhv_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_create_it creates a program object, which represents
+*  a factorization of LP basis.
+*
+*  RETURNS
+*
+*  The routine fhv_create_it returns a pointer to the object created. */
+
+FHV *fhv_create_it(void)
+{     FHV *fhv;
+      fhv = xmalloc(sizeof(FHV));
+      fhv->m_max = fhv->m = 0;
+      fhv->valid = 0;
+      fhv->luf = luf_create_it();
+      fhv->hh_max = 50;
+      fhv->hh_nfs = 0;
+      fhv->hh_ind = fhv->hh_ptr = fhv->hh_len = NULL;
+      fhv->p0_row = fhv->p0_col = NULL;
+      fhv->cc_ind = NULL;
+      fhv->cc_val = NULL;
+      fhv->upd_tol = 1e-6;
+      fhv->nnz_h = 0;
+      return fhv;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_factorize - compute LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
+*     int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_factorize computes the factorization of the basis
+*  matrix B specified by the routine col.
+*
+*  The parameter fhv specified the basis factorization data structure
+*  created by the routine fhv_create_it.
+*
+*  The parameter m specifies the order of B, m > 0.
+*
+*  The formal routine col specifies the matrix B to be factorized. To
+*  obtain j-th column of A the routine fhv_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully computed.
+*
+*  FHV_ESING
+*     The specified matrix is singular within the working precision.
+*
+*  FHV_ECOND
+*     The specified matrix is ill-conditioned.
+*
+*  For more details see comments to the routine luf_factorize.
+*
+*  ALGORITHM
+*
+*  The routine fhv_factorize calls the routine luf_factorize (see the
+*  module GLPLUF), which actually computes LU-factorization of the basis
+*  matrix B in the form
+*
+*     [B] = (F, V, P, Q),
+*
+*  where F and V are such matrices that
+*
+*     B = F * V,
+*
+*  and P and Q are such permutation matrices that the matrix
+*
+*     L = P * F * inv(P)
+*
+*  is lower triangular with unity diagonal, and the matrix
+*
+*     U = P * V * Q
+*
+*  is upper triangular.
+*
+*  In order to build the complete representation of the factorization
+*  (see formula (1) in the file glpfhv.h) the routine fhv_factorize just
+*  additionally sets H = I and P0 = P. */
+
+int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info)
+{     int ret;
+      if (m < 1)
+         xfault("fhv_factorize: m = %d; invalid parameter\n", m);
+      if (m > M_MAX)
+         xfault("fhv_factorize: m = %d; matrix too big\n", m);
+      fhv->m = m;
+      /* invalidate the factorization */
+      fhv->valid = 0;
+      /* allocate/reallocate arrays, if necessary */
+      if (fhv->hh_ind == NULL)
+         fhv->hh_ind = xcalloc(1+fhv->hh_max, sizeof(int));
+      if (fhv->hh_ptr == NULL)
+         fhv->hh_ptr = xcalloc(1+fhv->hh_max, sizeof(int));
+      if (fhv->hh_len == NULL)
+         fhv->hh_len = xcalloc(1+fhv->hh_max, sizeof(int));
+      if (fhv->m_max < m)
+      {  if (fhv->p0_row != NULL) xfree(fhv->p0_row);
+         if (fhv->p0_col != NULL) xfree(fhv->p0_col);
+         if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
+         if (fhv->cc_val != NULL) xfree(fhv->cc_val);
+         fhv->m_max = m + 100;
+         fhv->p0_row = xcalloc(1+fhv->m_max, sizeof(int));
+         fhv->p0_col = xcalloc(1+fhv->m_max, sizeof(int));
+         fhv->cc_ind = xcalloc(1+fhv->m_max, sizeof(int));
+         fhv->cc_val = xcalloc(1+fhv->m_max, sizeof(double));
+      }
+      /* try to factorize the basis matrix */
+      switch (luf_factorize(fhv->luf, m, col, info))
+      {  case 0:
+            break;
+         case LUF_ESING:
+            ret = FHV_ESING;
+            goto done;
+         case LUF_ECOND:
+            ret = FHV_ECOND;
+            goto done;
+         default:
+            xassert(fhv != fhv);
+      }
+      /* the basis matrix has been successfully factorized */
+      fhv->valid = 1;
+      /* H := I */
+      fhv->hh_nfs = 0;
+      /* P0 := P */
+      memcpy(&fhv->p0_row[1], &fhv->luf->pp_row[1], sizeof(int) * m);
+      memcpy(&fhv->p0_col[1], &fhv->luf->pp_col[1], sizeof(int) * m);
+      /* currently H has no factors */
+      fhv->nnz_h = 0;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_h_solve - solve system H*x = b or H'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_h_solve(FHV *fhv, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_h_solve solves either the system H*x = b (if the
+*  flag tr is zero) or the system H'*x = b (if the flag tr is non-zero),
+*  where the matrix H is a component of the factorization specified by
+*  the parameter fhv, H' is a matrix transposed to H.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[m], where m is the order of the
+*  matrix H. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void fhv_h_solve(FHV *fhv, int tr, double x[])
+{     int nfs = fhv->hh_nfs;
+      int *hh_ind = fhv->hh_ind;
+      int *hh_ptr = fhv->hh_ptr;
+      int *hh_len = fhv->hh_len;
+      int *sv_ind = fhv->luf->sv_ind;
+      double *sv_val = fhv->luf->sv_val;
+      int i, k, beg, end, ptr;
+      double temp;
+      if (!fhv->valid)
+         xfault("fhv_h_solve: the factorization is not valid\n");
+      if (!tr)
+      {  /* solve the system H*x = b */
+         for (k = 1; k <= nfs; k++)
+         {  i = hh_ind[k];
+            temp = x[i];
+            beg = hh_ptr[k];
+            end = beg + hh_len[k] - 1;
+            for (ptr = beg; ptr <= end; ptr++)
+               temp -= sv_val[ptr] * x[sv_ind[ptr]];
+            x[i] = temp;
+         }
+      }
+      else
+      {  /* solve the system H'*x = b */
+         for (k = nfs; k >= 1; k--)
+         {  i = hh_ind[k];
+            temp = x[i];
+            if (temp == 0.0) continue;
+            beg = hh_ptr[k];
+            end = beg + hh_len[k] - 1;
+            for (ptr = beg; ptr <= end; ptr++)
+               x[sv_ind[ptr]] -= sv_val[ptr] * temp;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_ftran(FHV *fhv, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void fhv_ftran(FHV *fhv, double x[])
+{     int *pp_row = fhv->luf->pp_row;
+      int *pp_col = fhv->luf->pp_col;
+      int *p0_row = fhv->p0_row;
+      int *p0_col = fhv->p0_col;
+      if (!fhv->valid)
+         xfault("fhv_ftran: the factorization is not valid\n");
+      /* B = F*H*V, therefore inv(B) = inv(V)*inv(H)*inv(F) */
+      fhv->luf->pp_row = p0_row;
+      fhv->luf->pp_col = p0_col;
+      luf_f_solve(fhv->luf, 0, x);
+      fhv->luf->pp_row = pp_row;
+      fhv->luf->pp_col = pp_col;
+      fhv_h_solve(fhv, 0, x);
+      luf_v_solve(fhv->luf, 0, x);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_btran(FHV *fhv, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix B, x is the vector of unknowns to be computed, b is the vector
+*  of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void fhv_btran(FHV *fhv, double x[])
+{     int *pp_row = fhv->luf->pp_row;
+      int *pp_col = fhv->luf->pp_col;
+      int *p0_row = fhv->p0_row;
+      int *p0_col = fhv->p0_col;
+      if (!fhv->valid)
+         xfault("fhv_btran: the factorization is not valid\n");
+      /* B = F*H*V, therefore inv(B') = inv(F')*inv(H')*inv(V') */
+      luf_v_solve(fhv->luf, 1, x);
+      fhv_h_solve(fhv, 1, x);
+      fhv->luf->pp_row = p0_row;
+      fhv->luf->pp_col = p0_col;
+      luf_f_solve(fhv->luf, 1, x);
+      fhv->luf->pp_row = pp_row;
+      fhv->luf->pp_col = pp_col;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_update_it - update LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_update_it updates the factorization of the basis
+*  matrix B after replacing its j-th column by a new vector.
+*
+*  The parameter j specifies the number of column of B, which has been
+*  replaced, 1 <= j <= m, where m is the order of B.
+*
+*  Row indices and numerical values of non-zero elements of the new
+*  column of B should be placed in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], resp., where len is the number of non-zeros
+*  in the column. Neither zero nor duplicate elements are allowed.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  FHV_ESING
+*     The adjacent basis matrix is structurally singular, since after
+*     changing j-th column of matrix V by the new column (see algorithm
+*     below) the case k1 > k2 occured.
+*
+*  FHV_ECHECK
+*     The factorization is inaccurate, since after transforming k2-th
+*     row of matrix U = P*V*Q, its diagonal element u[k2,k2] is zero or
+*     close to zero,
+*
+*  FHV_ELIMIT
+*     Maximal number of H factors has been reached.
+*
+*  FHV_EROOM
+*     Overflow of the sparse vector area.
+*
+*  In case of non-zero return code the factorization becomes invalid.
+*  It should not be used until it has been recomputed with the routine
+*  fhv_factorize.
+*
+*  ALGORITHM
+*
+*  The routine fhv_update_it is based on the transformation proposed by
+*  Forrest and Tomlin.
+*
+*  Let j-th column of the basis matrix B have been replaced by new
+*  column B[j]. In order to keep the equality B = F*H*V j-th column of
+*  matrix V should be replaced by the column inv(F*H)*B[j].
+*
+*  From the standpoint of matrix U = P*V*Q, replacement of j-th column
+*  of matrix V is equivalent to replacement of k1-th column of matrix U,
+*  where k1 is determined by permutation matrix Q. Thus, matrix U loses
+*  its upper triangular form and becomes the following:
+*
+*         1   k1       k2   m
+*     1   x x * x x x x x x x
+*         . x * x x x x x x x
+*     k1  . . * x x x x x x x
+*         . . * x x x x x x x
+*         . . * . x x x x x x
+*         . . * . . x x x x x
+*         . . * . . . x x x x
+*     k2  . . * . . . . x x x
+*         . . . . . . . . x x
+*     m   . . . . . . . . . x
+*
+*  where row index k2 corresponds to the lowest non-zero element of
+*  k1-th column.
+*
+*  The routine moves rows and columns k1+1, k1+2, ..., k2 of matrix U
+*  by one position to the left and upwards and moves k1-th row and k1-th
+*  column to position k2. As the result of such symmetric permutations
+*  matrix U becomes the following:
+*
+*         1   k1       k2   m
+*     1   x x x x x x x * x x
+*         . x x x x x x * x x
+*     k1  . . x x x x x * x x
+*         . . . x x x x * x x
+*         . . . . x x x * x x
+*         . . . . . x x * x x
+*         . . . . . . x * x x
+*     k2  . . x x x x x * x x
+*         . . . . . . . . x x
+*     m   . . . . . . . . . x
+*
+*  Then the routine performs gaussian elimination to eliminate elements
+*  u[k2,k1], u[k2,k1+1], ..., u[k2,k2-1] using diagonal elements
+*  u[k1,k1], u[k1+1,k1+1], ..., u[k2-1,k2-1] as pivots in the same way
+*  as described in comments to the routine luf_factorize (see the module
+*  GLPLUF). Note that actually all operations are performed on matrix V,
+*  not on matrix U. During the elimination process the routine permutes
+*  neither rows nor columns, so only k2-th row of matrix U is changed.
+*
+*  To keep the main equality B = F*H*V, each time when the routine
+*  applies elementary gaussian transformation to the transformed row of
+*  matrix V (which corresponds to k2-th row of matrix U), it also adds
+*  a new element (gaussian multiplier) to the current row-like factor
+*  of matrix H, which corresponds to the transformed row of matrix V. */
+
+int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
+      const double val[])
+{     int m = fhv->m;
+      LUF *luf = fhv->luf;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      double *vr_piv = luf->vr_piv;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *pp_row = luf->pp_row;
+      int *pp_col = luf->pp_col;
+      int *qq_row = luf->qq_row;
+      int *qq_col = luf->qq_col;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      double *work = luf->work;
+      double eps_tol = luf->eps_tol;
+      int *hh_ind = fhv->hh_ind;
+      int *hh_ptr = fhv->hh_ptr;
+      int *hh_len = fhv->hh_len;
+      int *p0_row = fhv->p0_row;
+      int *p0_col = fhv->p0_col;
+      int *cc_ind = fhv->cc_ind;
+      double *cc_val = fhv->cc_val;
+      double upd_tol = fhv->upd_tol;
+      int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q,
+         p_beg, p_end, p_ptr, ptr, ret;
+      double f, temp;
+      if (!fhv->valid)
+         xfault("fhv_update_it: the factorization is not valid\n");
+      if (!(1 <= j && j <= m))
+         xfault("fhv_update_it: j = %d; column number out of range\n",
+            j);
+      /* check if the new factor of matrix H can be created */
+      if (fhv->hh_nfs == fhv->hh_max)
+      {  /* maximal number of updates has been reached */
+         fhv->valid = 0;
+         ret = FHV_ELIMIT;
+         goto done;
+      }
+      /* convert new j-th column of B to dense format */
+      for (i = 1; i <= m; i++)
+         cc_val[i] = 0.0;
+      for (k = 1; k <= len; k++)
+      {  i = ind[k];
+         if (!(1 <= i && i <= m))
+            xfault("fhv_update_it: ind[%d] = %d; row number out of rang"
+               "e\n", k, i);
+         if (cc_val[i] != 0.0)
+            xfault("fhv_update_it: ind[%d] = %d; duplicate row index no"
+               "t allowed\n", k, i);
+         if (val[k] == 0.0)
+            xfault("fhv_update_it: val[%d] = %g; zero element not allow"
+               "ed\n", k, val[k]);
+         cc_val[i] = val[k];
+      }
+      /* new j-th column of V := inv(F * H) * (new B[j]) */
+      fhv->luf->pp_row = p0_row;
+      fhv->luf->pp_col = p0_col;
+      luf_f_solve(fhv->luf, 0, cc_val);
+      fhv->luf->pp_row = pp_row;
+      fhv->luf->pp_col = pp_col;
+      fhv_h_solve(fhv, 0, cc_val);
+      /* convert new j-th column of V to sparse format */
+      len = 0;
+      for (i = 1; i <= m; i++)
+      {  temp = cc_val[i];
+         if (temp == 0.0 || fabs(temp) < eps_tol) continue;
+         len++, cc_ind[len] = i, cc_val[len] = temp;
+      }
+      /* clear old content of j-th column of matrix V */
+      j_beg = vc_ptr[j];
+      j_end = j_beg + vc_len[j] - 1;
+      for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+      {  /* get row index of v[i,j] */
+         i = sv_ind[j_ptr];
+         /* find v[i,j] in the i-th row */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */;
+         xassert(i_ptr <= i_end);
+         /* remove v[i,j] from the i-th row */
+         sv_ind[i_ptr] = sv_ind[i_end];
+         sv_val[i_ptr] = sv_val[i_end];
+         vr_len[i]--;
+      }
+      /* now j-th column of matrix V is empty */
+      luf->nnz_v -= vc_len[j];
+      vc_len[j] = 0;
+      /* add new elements of j-th column of matrix V to corresponding
+         row lists; determine indices k1 and k2 */
+      k1 = qq_row[j], k2 = 0;
+      for (ptr = 1; ptr <= len; ptr++)
+      {  /* get row index of v[i,j] */
+         i = cc_ind[ptr];
+         /* at least one unused location is needed in i-th row */
+         if (vr_len[i] + 1 > vr_cap[i])
+         {  if (luf_enlarge_row(luf, i, vr_len[i] + 10))
+            {  /* overflow of the sparse vector area */
+               fhv->valid = 0;
+               luf->new_sva = luf->sv_size + luf->sv_size;
+               xassert(luf->new_sva > luf->sv_size);
+               ret = FHV_EROOM;
+               goto done;
+            }
+         }
+         /* add v[i,j] to i-th row */
+         i_ptr = vr_ptr[i] + vr_len[i];
+         sv_ind[i_ptr] = j;
+         sv_val[i_ptr] = cc_val[ptr];
+         vr_len[i]++;
+         /* adjust index k2 */
+         if (k2 < pp_col[i]) k2 = pp_col[i];
+      }
+      /* capacity of j-th column (which is currently empty) should be
+         not less than len locations */
+      if (vc_cap[j] < len)
+      {  if (luf_enlarge_col(luf, j, len))
+         {  /* overflow of the sparse vector area */
+            fhv->valid = 0;
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            ret = FHV_EROOM;
+            goto done;
+         }
+      }
+      /* add new elements of matrix V to j-th column list */
+      j_ptr = vc_ptr[j];
+      memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int));
+      memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double));
+      vc_len[j] = len;
+      luf->nnz_v += len;
+      /* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and
+         therefore the adjacent basis matrix is structurally singular */
+      if (k1 > k2)
+      {  fhv->valid = 0;
+         ret = FHV_ESING;
+         goto done;
+      }
+      /* perform implicit symmetric permutations of rows and columns of
+         matrix U */
+      i = pp_row[k1], j = qq_col[k1];
+      for (k = k1; k < k2; k++)
+      {  pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k;
+         qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k;
+      }
+      pp_row[k2] = i, pp_col[i] = k2;
+      qq_col[k2] = j, qq_row[j] = k2;
+      /* now i-th row of the matrix V is k2-th row of matrix U; since
+         no pivoting is used, only this row will be transformed */
+      /* copy elements of i-th row of matrix V to the working array and
+         remove these elements from matrix V */
+      for (j = 1; j <= m; j++) work[j] = 0.0;
+      i_beg = vr_ptr[i];
+      i_end = i_beg + vr_len[i] - 1;
+      for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+      {  /* get column index of v[i,j] */
+         j = sv_ind[i_ptr];
+         /* store v[i,j] to the working array */
+         work[j] = sv_val[i_ptr];
+         /* find v[i,j] in the j-th column */
+         j_beg = vc_ptr[j];
+         j_end = j_beg + vc_len[j] - 1;
+         for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */;
+         xassert(j_ptr <= j_end);
+         /* remove v[i,j] from the j-th column */
+         sv_ind[j_ptr] = sv_ind[j_end];
+         sv_val[j_ptr] = sv_val[j_end];
+         vc_len[j]--;
+      }
+      /* now i-th row of matrix V is empty */
+      luf->nnz_v -= vr_len[i];
+      vr_len[i] = 0;
+      /* create the next row-like factor of the matrix H; this factor
+         corresponds to i-th (transformed) row */
+      fhv->hh_nfs++;
+      hh_ind[fhv->hh_nfs] = i;
+      /* hh_ptr[] will be set later */
+      hh_len[fhv->hh_nfs] = 0;
+      /* up to (k2 - k1) free locations are needed to add new elements
+         to the non-trivial row of the row-like factor */
+      if (luf->sv_end - luf->sv_beg < k2 - k1)
+      {  luf_defrag_sva(luf);
+         if (luf->sv_end - luf->sv_beg < k2 - k1)
+         {  /* overflow of the sparse vector area */
+            fhv->valid = luf->valid = 0;
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            ret = FHV_EROOM;
+            goto done;
+         }
+      }
+      /* eliminate subdiagonal elements of matrix U */
+      for (k = k1; k < k2; k++)
+      {  /* v[p,q] = u[k,k] */
+         p = pp_row[k], q = qq_col[k];
+         /* this is the crucial point, where even tiny non-zeros should
+            not be dropped */
+         if (work[q] == 0.0) continue;
+         /* compute gaussian multiplier f = v[i,q] / v[p,q] */
+         f = work[q] / vr_piv[p];
+         /* perform gaussian transformation:
+            (i-th row) := (i-th row) - f * (p-th row)
+            in order to eliminate v[i,q] = u[k2,k] */
+         p_beg = vr_ptr[p];
+         p_end = p_beg + vr_len[p] - 1;
+         for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+            work[sv_ind[p_ptr]] -= f * sv_val[p_ptr];
+         /* store new element (gaussian multiplier that corresponds to
+            p-th row) in the current row-like factor */
+         luf->sv_end--;
+         sv_ind[luf->sv_end] = p;
+         sv_val[luf->sv_end] = f;
+         hh_len[fhv->hh_nfs]++;
+      }
+      /* set pointer to the current row-like factor of the matrix H
+         (if no elements were added to this factor, it is unity matrix
+         and therefore can be discarded) */
+      if (hh_len[fhv->hh_nfs] == 0)
+         fhv->hh_nfs--;
+      else
+      {  hh_ptr[fhv->hh_nfs] = luf->sv_end;
+         fhv->nnz_h += hh_len[fhv->hh_nfs];
+      }
+      /* store new pivot which corresponds to u[k2,k2] */
+      vr_piv[i] = work[qq_col[k2]];
+      /* new elements of i-th row of matrix V (which are non-diagonal
+         elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are
+         contained in the working array; add them to matrix V */
+      len = 0;
+      for (k = k2+1; k <= m; k++)
+      {  /* get column index and value of v[i,j] = u[k2,k] */
+         j = qq_col[k];
+         temp = work[j];
+         /* if v[i,j] is close to zero, skip it */
+         if (fabs(temp) < eps_tol) continue;
+         /* at least one unused location is needed in j-th column */
+         if (vc_len[j] + 1 > vc_cap[j])
+         {  if (luf_enlarge_col(luf, j, vc_len[j] + 10))
+            {  /* overflow of the sparse vector area */
+               fhv->valid = 0;
+               luf->new_sva = luf->sv_size + luf->sv_size;
+               xassert(luf->new_sva > luf->sv_size);
+               ret = FHV_EROOM;
+               goto done;
+            }
+         }
+         /* add v[i,j] to j-th column */
+         j_ptr = vc_ptr[j] + vc_len[j];
+         sv_ind[j_ptr] = i;
+         sv_val[j_ptr] = temp;
+         vc_len[j]++;
+         /* also store v[i,j] to the auxiliary array */
+         len++, cc_ind[len] = j, cc_val[len] = temp;
+      }
+      /* capacity of i-th row (which is currently empty) should be not
+         less than len locations */
+      if (vr_cap[i] < len)
+      {  if (luf_enlarge_row(luf, i, len))
+         {  /* overflow of the sparse vector area */
+            fhv->valid = 0;
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            ret = FHV_EROOM;
+            goto done;
+         }
+      }
+      /* add new elements to i-th row list */
+      i_ptr = vr_ptr[i];
+      memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int));
+      memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double));
+      vr_len[i] = len;
+      luf->nnz_v += len;
+      /* updating is finished; check that diagonal element u[k2,k2] is
+         not very small in absolute value among other elements in k2-th
+         row and k2-th column of matrix U = P*V*Q */
+      /* temp = max(|u[k2,*]|, |u[*,k2]|) */
+      temp = 0.0;
+      /* walk through k2-th row of U which is i-th row of V */
+      i = pp_row[k2];
+      i_beg = vr_ptr[i];
+      i_end = i_beg + vr_len[i] - 1;
+      for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]);
+      /* walk through k2-th column of U which is j-th column of V */
+      j = qq_col[k2];
+      j_beg = vc_ptr[j];
+      j_end = j_beg + vc_len[j] - 1;
+      for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+         if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]);
+      /* check that u[k2,k2] is not very small */
+      if (fabs(vr_piv[i]) < upd_tol * temp)
+      {  /* the factorization seems to be inaccurate and therefore must
+            be recomputed */
+         fhv->valid = 0;
+         ret = FHV_ECHECK;
+         goto done;
+      }
+      /* the factorization has been successfully updated */
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_delete_it - delete LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_delete_it(FHV *fhv);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_delete_it deletes LP basis factorization specified
+*  by the parameter fhv and frees all memory allocated to this program
+*  object. */
+
+void fhv_delete_it(FHV *fhv)
+{     luf_delete_it(fhv->luf);
+      if (fhv->hh_ind != NULL) xfree(fhv->hh_ind);
+      if (fhv->hh_ptr != NULL) xfree(fhv->hh_ptr);
+      if (fhv->hh_len != NULL) xfree(fhv->hh_len);
+      if (fhv->p0_row != NULL) xfree(fhv->p0_row);
+      if (fhv->p0_col != NULL) xfree(fhv->p0_col);
+      if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
+      if (fhv->cc_val != NULL) xfree(fhv->cc_val);
+      xfree(fhv);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpfhv.h b/optional/glpk/glpfhv.h
new file mode 100644
index 0000000..3ac942b
--- /dev/null
+++ b/optional/glpk/glpfhv.h
@@ -0,0 +1,170 @@
+/* glpfhv.h (LP basis factorization, FHV eta file version) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPFHV_H
+#define GLPFHV_H
+
+#include "glpluf.h"
+
+/***********************************************************************
+*  The structure FHV defines the factorization of the basis mxm-matrix
+*  B, where m is the number of rows in corresponding problem instance.
+*
+*  This factorization is the following sextet:
+*
+*     [B] = (F, H, V, P0, P, Q),                                     (1)
+*
+*  where F, H, and V are such matrices that
+*
+*     B = F * H * V,                                                 (2)
+*
+*  and P0, P, and Q are such permutation matrices that the matrix
+*
+*     L = P0 * F * inv(P0)                                           (3)
+*
+*  is lower triangular with unity diagonal, and the matrix
+*
+*     U = P * V * Q                                                  (4)
+*
+*  is upper triangular. All the matrices have the same order m, which
+*  is the order of the basis matrix B.
+*
+*  The matrices F, V, P, and Q are stored in the structure LUF (see the
+*  module GLPLUF), which is a member of the structure FHV.
+*
+*  The matrix H is stored in the form of eta file using row-like format
+*  as follows:
+*
+*     H = H[1] * H[2] * ... * H[nfs],                                (5)
+*
+*  where H[k], k = 1, 2, ..., nfs, is a row-like factor, which differs
+*  from the unity matrix only by one row, nfs is current number of row-
+*  like factors. After the factorization has been built for some given
+*  basis matrix B the matrix H has no factors and thus it is the unity
+*  matrix. Then each time when the factorization is recomputed for an
+*  adjacent basis matrix, the next factor H[k], k = 1, 2, ... is built
+*  and added to the end of the eta file H.
+*
+*  Being sparse vectors non-trivial rows of the factors H[k] are stored
+*  in the right part of the sparse vector area (SVA) in the same manner
+*  as rows and columns of the matrix F.
+*
+*  For more details see the program documentation. */
+
+typedef struct FHV FHV;
+
+struct FHV
+{     /* LP basis factorization */
+      int m_max;
+      /* maximal value of m (increased automatically, if necessary) */
+      int m;
+      /* the order of matrices B, F, H, V, P0, P, Q */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      LUF *luf;
+      /* LU-factorization (contains the matrices F, V, P, Q) */
+      /*--------------------------------------------------------------*/
+      /* matrix H in the form of eta file */
+      int hh_max;
+      /* maximal number of row-like factors (which limits the number of
+         updates of the factorization) */
+      int hh_nfs;
+      /* current number of row-like factors (0 <= hh_nfs <= hh_max) */
+      int *hh_ind; /* int hh_ind[1+hh_max]; */
+      /* hh_ind[k], k = 1, ..., nfs, is the number of a non-trivial row
+         of factor H[k] */
+      int *hh_ptr; /* int hh_ptr[1+hh_max]; */
+      /* hh_ptr[k], k = 1, ..., nfs, is a pointer to the first element
+         of the non-trivial row of factor H[k] in the SVA */
+      int *hh_len; /* int hh_len[1+hh_max]; */
+      /* hh_len[k], k = 1, ..., nfs, is the number of non-zero elements
+         in the non-trivial row of factor H[k] */
+      /*--------------------------------------------------------------*/
+      /* matrix P0 */
+      int *p0_row; /* int p0_row[1+m_max]; */
+      /* p0_row[i] = j means that p0[i,j] = 1 */
+      int *p0_col; /* int p0_col[1+m_max]; */
+      /* p0_col[j] = i means that p0[i,j] = 1 */
+      /* if i-th row or column of the matrix F corresponds to i'-th row
+         or column of the matrix L = P0*F*inv(P0), then p0_row[i'] = i
+         and p0_col[i] = i' */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      int *cc_ind; /* int cc_ind[1+m_max]; */
+      /* integer working array */
+      double *cc_val; /* double cc_val[1+m_max]; */
+      /* floating-point working array */
+      /*--------------------------------------------------------------*/
+      /* control parameters */
+      double upd_tol;
+      /* update tolerance; if after updating the factorization absolute
+         value of some diagonal element u[k,k] of matrix U = P*V*Q is
+         less than upd_tol * max(|u[k,*]|, |u[*,k]|), the factorization
+         is considered as inaccurate */
+      /*--------------------------------------------------------------*/
+      /* some statistics */
+      int nnz_h;
+      /* current number of non-zeros in all factors of matrix H */
+};
+
+/* return codes: */
+#define FHV_ESING    1  /* singular matrix */
+#define FHV_ECOND    2  /* ill-conditioned matrix */
+#define FHV_ECHECK   3  /* insufficient accuracy */
+#define FHV_ELIMIT   4  /* update limit reached */
+#define FHV_EROOM    5  /* SVA overflow */
+
+#define fhv_create_it _glp_fhv_create_it
+FHV *fhv_create_it(void);
+/* create LP basis factorization */
+
+#define fhv_factorize _glp_fhv_factorize
+int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#define fhv_h_solve _glp_fhv_h_solve
+void fhv_h_solve(FHV *fhv, int tr, double x[]);
+/* solve system H*x = b or H'*x = b */
+
+#define fhv_ftran _glp_fhv_ftran
+void fhv_ftran(FHV *fhv, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#define fhv_btran _glp_fhv_btran
+void fhv_btran(FHV *fhv, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#define fhv_update_it _glp_fhv_update_it
+int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
+      const double val[]);
+/* update LP basis factorization */
+
+#define fhv_delete_it _glp_fhv_delete_it
+void fhv_delete_it(FHV *fhv);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpgmp.c b/optional/glpk/glpgmp.c
new file mode 100644
index 0000000..cd8b090
--- /dev/null
+++ b/optional/glpk/glpgmp.c
@@ -0,0 +1,1113 @@
+/* glpgmp.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#define _GLPSTD_STDIO
+#include "glpdmp.h"
+#include "glpgmp.h"
+#define xfault xerror
+
+#ifdef HAVE_GMP               /* use GNU MP bignum library */
+
+int gmp_pool_count(void) { return 0; }
+
+void gmp_free_mem(void) { return; }
+
+#else                         /* use GLPK bignum module */
+
+static DMP *gmp_pool = NULL;
+static int gmp_size = 0;
+static unsigned short *gmp_work = NULL;
+
+void *gmp_get_atom(int size)
+{     if (gmp_pool == NULL)
+         gmp_pool = dmp_create_pool();
+      return dmp_get_atom(gmp_pool, size);
+}
+
+void gmp_free_atom(void *ptr, int size)
+{     xassert(gmp_pool != NULL);
+      dmp_free_atom(gmp_pool, ptr, size);
+      return;
+}
+
+int gmp_pool_count(void)
+{     if (gmp_pool == NULL)
+         return 0;
+      else
+         return dmp_in_use(gmp_pool).lo;
+}
+
+unsigned short *gmp_get_work(int size)
+{     xassert(size > 0);
+      if (gmp_size < size)
+      {  if (gmp_size == 0)
+         {  xassert(gmp_work == NULL);
+            gmp_size = 100;
+         }
+         else
+         {  xassert(gmp_work != NULL);
+            xfree(gmp_work);
+         }
+         while (gmp_size < size) gmp_size += gmp_size;
+         gmp_work = xcalloc(gmp_size, sizeof(unsigned short));
+      }
+      return gmp_work;
+}
+
+void gmp_free_mem(void)
+{     if (gmp_pool != NULL) dmp_delete_pool(gmp_pool);
+      if (gmp_work != NULL) xfree(gmp_work);
+      gmp_pool = NULL;
+      gmp_size = 0;
+      gmp_work = NULL;
+      return;
+}
+
+/*====================================================================*/
+
+mpz_t _mpz_init(void)
+{     /* initialize x, and set its value to 0 */
+      mpz_t x;
+      x = gmp_get_atom(sizeof(struct mpz));
+      x->val = 0;
+      x->ptr = NULL;
+      return x;
+}
+
+void mpz_clear(mpz_t x)
+{     /* free the space occupied by x */
+      mpz_set_si(x, 0);
+      xassert(x->ptr == NULL);
+      /* free the number descriptor */
+      gmp_free_atom(x, sizeof(struct mpz));
+      return;
+}
+
+void mpz_set(mpz_t z, mpz_t x)
+{     /* set the value of z from x */
+      struct mpz_seg *e, *ee, *es;
+      if (z != x)
+      {  mpz_set_si(z, 0);
+         z->val = x->val;
+         xassert(z->ptr == NULL);
+         for (e = x->ptr, es = NULL; e != NULL; e = e->next)
+         {  ee = gmp_get_atom(sizeof(struct mpz_seg));
+            memcpy(ee->d, e->d, 12);
+            ee->next = NULL;
+            if (z->ptr == NULL)
+               z->ptr = ee;
+            else
+               es->next = ee;
+            es = ee;
+         }
+      }
+      return;
+}
+
+void mpz_set_si(mpz_t x, int val)
+{     /* set the value of x to val */
+      struct mpz_seg *e;
+      /* free existing segments, if any */
+      while (x->ptr != NULL)
+      {  e = x->ptr;
+         x->ptr = e->next;
+         gmp_free_atom(e, sizeof(struct mpz_seg));
+      }
+      /* assign new value */
+      if (val == 0x80000000)
+      {  /* long format is needed */
+         x->val = -1;
+         x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg));
+         memset(e->d, 0, 12);
+         e->d[1] = 0x8000;
+         e->next = NULL;
+      }
+      else
+      {  /* short format is enough */
+         x->val = val;
+      }
+      return;
+}
+
+double mpz_get_d(mpz_t x)
+{     /* convert x to a double, truncating if necessary */
+      struct mpz_seg *e;
+      int j;
+      double val, deg;
+      if (x->ptr == NULL)
+         val = (double)x->val;
+      else
+      {  xassert(x->val != 0);
+         val = 0.0;
+         deg = 1.0;
+         for (e = x->ptr; e != NULL; e = e->next)
+         {  for (j = 0; j <= 5; j++)
+            {  val += deg * (double)((int)e->d[j]);
+               deg *= 65536.0;
+            }
+         }
+         if (x->val < 0) val = - val;
+      }
+      return val;
+}
+
+double mpz_get_d_2exp(int *exp, mpz_t x)
+{     /* convert x to a double, truncating if necessary (i.e. rounding
+         towards zero), and returning the exponent separately;
+         the return value is in the range 0.5 <= |d| < 1 and the
+         exponent is stored to *exp; d*2^exp is the (truncated) x value;
+         if x is zero, the return is 0.0 and 0 is stored to *exp;
+         this is similar to the standard C frexp function */
+      struct mpz_seg *e;
+      int j, n, n1;
+      double val;
+      if (x->ptr == NULL)
+         val = (double)x->val, n = 0;
+      else
+      {  xassert(x->val != 0);
+         val = 0.0, n = 0;
+         for (e = x->ptr; e != NULL; e = e->next)
+         {  for (j = 0; j <= 5; j++)
+            {  val += (double)((int)e->d[j]);
+               val /= 65536.0, n += 16;
+            }
+         }
+         if (x->val < 0) val = - val;
+      }
+      val = frexp(val, &n1);
+      *exp = n + n1;
+      return val;
+}
+
+void mpz_swap(mpz_t x, mpz_t y)
+{     /* swap the values x and y efficiently */
+      int val;
+      void *ptr;
+      val = x->val, ptr = x->ptr;
+      x->val = y->val, x->ptr = y->ptr;
+      y->val = val, y->ptr = ptr;
+      return;
+}
+
+static void normalize(mpz_t x)
+{     /* normalize integer x that includes removing non-significant
+         (leading) zeros and converting to short format, if possible */
+      struct mpz_seg *es, *e;
+      /* if the integer is in short format, it remains unchanged */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         goto done;
+      }
+      xassert(x->val == +1 || x->val == -1);
+      /* find the last (most significant) non-zero segment */
+      es = NULL;
+      for (e = x->ptr; e != NULL; e = e->next)
+      {  if (e->d[0] || e->d[1] || e->d[2] ||
+             e->d[3] || e->d[4] || e->d[5]) es = e;
+      }
+      /* if all segments contain zeros, the integer is zero */
+      if (es == NULL)
+      {  mpz_set_si(x, 0);
+         goto done;
+      }
+      /* remove non-significant (leading) zero segments */
+      while (es->next != NULL)
+      {  e = es->next;
+         es->next = e->next;
+         gmp_free_atom(e, sizeof(struct mpz_seg));
+      }
+      /* convert the integer to short format, if possible */
+      e = x->ptr;
+      if (e->next == NULL && e->d[1] <= 0x7FFF &&
+         !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5])
+      {  int val;
+         val = (int)e->d[0] + ((int)e->d[1] << 16);
+         if (x->val < 0) val = - val;
+         mpz_set_si(x, val);
+      }
+done: return;
+}
+
+void mpz_add(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to x + y */
+      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
+      struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee;
+      int k, sx, sy, sz;
+      unsigned int t;
+      /* if [x] = 0 then [z] = [y] */
+      if (x->val == 0)
+      {  xassert(x->ptr == NULL);
+         mpz_set(z, y);
+         goto done;
+      }
+      /* if [y] = 0 then [z] = [x] */
+      if (y->val == 0)
+      {  xassert(y->ptr == NULL);
+         mpz_set(z, x);
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val, zval = x->val + y->val;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         if (!(xval > 0 && yval > 0 && zval <= 0 ||
+               xval < 0 && yval < 0 && zval >= 0))
+         {  mpz_set_si(z, zval);
+            goto done;
+         }
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* main fragment */
+      sz = sx;
+      ez = es = NULL;
+      if (sx > 0 && sy > 0 || sx < 0 && sy < 0)
+      {  /* [x] and [y] have identical signs -- addition */
+         t = 0;
+         for (; ex || ey; ex = ex->next, ey = ey->next)
+         {  if (ex == NULL) ex = &zero;
+            if (ey == NULL) ey = &zero;
+            ee = gmp_get_atom(sizeof(struct mpz_seg));
+            for (k = 0; k <= 5; k++)
+            {  t += (unsigned int)ex->d[k];
+               t += (unsigned int)ey->d[k];
+               ee->d[k] = (unsigned short)t;
+               t >>= 16;
+            }
+            ee->next = NULL;
+            if (ez == NULL)
+               ez = ee;
+            else
+               es->next = ee;
+            es = ee;
+         }
+         if (t)
+         {  /* overflow -- one extra digit is needed */
+            ee = gmp_get_atom(sizeof(struct mpz_seg));
+            ee->d[0] = 1;
+            ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0;
+            ee->next = NULL;
+            xassert(es != NULL);
+            es->next = ee;
+         }
+      }
+      else
+      {  /* [x] and [y] have different signs -- subtraction */
+         t = 1;
+         for (; ex || ey; ex = ex->next, ey = ey->next)
+         {  if (ex == NULL) ex = &zero;
+            if (ey == NULL) ey = &zero;
+            ee = gmp_get_atom(sizeof(struct mpz_seg));
+            for (k = 0; k <= 5; k++)
+            {  t += (unsigned int)ex->d[k];
+               t += (0xFFFF - (unsigned int)ey->d[k]);
+               ee->d[k] = (unsigned short)t;
+               t >>= 16;
+            }
+            ee->next = NULL;
+            if (ez == NULL)
+               ez = ee;
+            else
+               es->next = ee;
+            es = ee;
+         }
+         if (!t)
+         {  /* |[x]| < |[y]| -- result in complement coding */
+            sz = - sz;
+            t = 1;
+            for (ee = ez; ee != NULL; ee = ee->next)
+            for (k = 0; k <= 5; k++)
+            {  t += (0xFFFF - (unsigned int)ee->d[k]);
+               ee->d[k] = (unsigned short)t;
+               t >>= 16;
+            }
+         }
+      }
+      /* contruct and normalize result */
+      mpz_set_si(z, 0);
+      z->val = sz;
+      z->ptr = ez;
+      normalize(z);
+done: return;
+}
+
+void mpz_sub(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to x - y */
+      if (x == y)
+         mpz_set_si(z, 0);
+      else
+      {  y->val = - y->val;
+         mpz_add(z, x, y);
+         if (y != z) y->val = - y->val;
+      }
+      return;
+}
+
+void mpz_mul(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to x * y */
+      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
+      int sx, sy, k, nx, ny, n;
+      unsigned int t;
+      unsigned short *work, *wx, *wy;
+      /* if [x] = 0 then [z] = 0 */
+      if (x->val == 0)
+      {  xassert(x->ptr == NULL);
+         mpz_set_si(z, 0);
+         goto done;
+      }
+      /* if [y] = 0 then [z] = 0 */
+      if (y->val == 0)
+      {  xassert(y->ptr == NULL);
+         mpz_set_si(z, 0);
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val, sz = +1;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         if (xval < 0) xval = - xval, sz = - sz;
+         if (yval < 0) yval = - yval, sz = - sz;
+         if (xval <= 0x7FFFFFFF / yval)
+         {  mpz_set_si(z, sz * (xval * yval));
+            goto done;
+         }
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* determine the number of digits of [x] */
+      nx = n = 0;
+      for (e = ex; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) nx = n;
+      }
+      xassert(nx > 0);
+      /* determine the number of digits of [y] */
+      ny = n = 0;
+      for (e = ey; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) ny = n;
+      }
+      xassert(ny > 0);
+      /* we need working array containing at least nx+ny+ny places */
+      work = gmp_get_work(nx+ny+ny);
+      /* load digits of [x] */
+      wx = &work[0];
+      for (n = 0; n < nx; n++) wx[ny+n] = 0;
+      for (n = 0, e = ex; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wx[ny+n] = e->d[k];
+      /* load digits of [y] */
+      wy = &work[nx+ny];
+      for (n = 0; n < ny; n++) wy[n] = 0;
+      for (n = 0, e = ey; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wy[n] = e->d[k];
+      /* compute [x] * [y] */
+      bigmul(nx, ny, wx, wy);
+      /* construct and normalize result */
+      mpz_set_si(z, 0);
+      z->val = sx * sy;
+      es = NULL;
+      k = 6;
+      for (n = 0; n < nx+ny; n++)
+      {  if (k > 5)
+         {  e = gmp_get_atom(sizeof(struct mpz_seg));
+            e->d[0] = e->d[1] = e->d[2] = 0;
+            e->d[3] = e->d[4] = e->d[5] = 0;
+            e->next = NULL;
+            if (z->ptr == NULL)
+               z->ptr = e;
+            else
+               es->next = e;
+            es = e;
+            k = 0;
+         }
+         es->d[k++] = wx[n];
+      }
+      normalize(z);
+done: return;
+}
+
+void mpz_neg(mpz_t z, mpz_t x)
+{     /* set z to 0 - x */
+      mpz_set(z, x);
+      z->val = - z->val;
+      return;
+}
+
+void mpz_abs(mpz_t z, mpz_t x)
+{     /* set z to the absolute value of x */
+      mpz_set(z, x);
+      if (z->val < 0) z->val = - z->val;
+      return;
+}
+
+void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y)
+{     /* divide x by y, forming quotient q and/or remainder r
+         if q = NULL then quotient is not stored; if r = NULL then
+         remainder is not stored
+         the sign of quotient is determined as in algebra while the
+         sign of remainder is the same as the sign of dividend:
+         +26 : +7 = +3, remainder is +5
+         -26 : +7 = -3, remainder is -5
+         +26 : -7 = -3, remainder is +5
+         -26 : -7 = +3, remainder is -5 */
+      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
+      int sx, sy, k, nx, ny, n;
+      unsigned int t;
+      unsigned short *work, *wx, *wy;
+      /* divide by zero is not allowed */
+      if (y->val == 0)
+      {  xassert(y->ptr == NULL);
+         xfault("mpz_div: divide by zero not allowed\n");
+      }
+      /* if [x] = 0 then [q] = [r] = 0 */
+      if (x->val == 0)
+      {  xassert(x->ptr == NULL);
+         if (q != NULL) mpz_set_si(q, 0);
+         if (r != NULL) mpz_set_si(r, 0);
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         if (q != NULL) mpz_set_si(q, xval / yval);
+         if (r != NULL) mpz_set_si(r, xval % yval);
+         goto done;
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* determine the number of digits of [x] */
+      nx = n = 0;
+      for (e = ex; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) nx = n;
+      }
+      xassert(nx > 0);
+      /* determine the number of digits of [y] */
+      ny = n = 0;
+      for (e = ey; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) ny = n;
+      }
+      xassert(ny > 0);
+      /* if nx < ny then [q] = 0 and [r] = [x] */
+      if (nx < ny)
+      {  if (r != NULL) mpz_set(r, x);
+         if (q != NULL) mpz_set_si(q, 0);
+         goto done;
+      }
+      /* we need working array containing at least nx+ny+1 places */
+      work = gmp_get_work(nx+ny+1);
+      /* load digits of [x] */
+      wx = &work[0];
+      for (n = 0; n < nx; n++) wx[n] = 0;
+      for (n = 0, e = ex; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wx[n] = e->d[k];
+      /* load digits of [y] */
+      wy = &work[nx+1];
+      for (n = 0; n < ny; n++) wy[n] = 0;
+      for (n = 0, e = ey; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wy[n] = e->d[k];
+      /* compute quotient and remainder */
+      xassert(wy[ny-1] != 0);
+      bigdiv(nx-ny, ny, wx, wy);
+      /* construct and normalize quotient */
+      if (q != NULL)
+      {  mpz_set_si(q, 0);
+         q->val = sx * sy;
+         es = NULL;
+         k = 6;
+         for (n = ny; n <= nx; n++)
+         {  if (k > 5)
+            {  e = gmp_get_atom(sizeof(struct mpz_seg));
+               e->d[0] = e->d[1] = e->d[2] = 0;
+               e->d[3] = e->d[4] = e->d[5] = 0;
+               e->next = NULL;
+               if (q->ptr == NULL)
+                  q->ptr = e;
+               else
+                  es->next = e;
+               es = e;
+               k = 0;
+            }
+            es->d[k++] = wx[n];
+         }
+         normalize(q);
+      }
+      /* construct and normalize remainder */
+      if (r != NULL)
+      {  mpz_set_si(r, 0);
+         r->val = sx;
+         es = NULL;
+         k = 6;
+         for (n = 0; n < ny; n++)
+         {  if (k > 5)
+            {  e = gmp_get_atom(sizeof(struct mpz_seg));
+               e->d[0] = e->d[1] = e->d[2] = 0;
+               e->d[3] = e->d[4] = e->d[5] = 0;
+               e->next = NULL;
+               if (r->ptr == NULL)
+                  r->ptr = e;
+               else
+                  es->next = e;
+               es = e;
+               k = 0;
+            }
+            es->d[k++] = wx[n];
+         }
+         normalize(r);
+      }
+done: return;
+}
+
+void mpz_gcd(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to the greatest common divisor of x and y */
+      /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and,
+         in particular, GCD(0, 0) = 0 */
+      mpz_t u, v, r;
+      mpz_init(u);
+      mpz_init(v);
+      mpz_init(r);
+      mpz_abs(u, x);
+      mpz_abs(v, y);
+      while (mpz_sgn(v))
+      {  mpz_div(NULL, r, u, v);
+         mpz_set(u, v);
+         mpz_set(v, r);
+      }
+      mpz_set(z, u);
+      mpz_clear(u);
+      mpz_clear(v);
+      mpz_clear(r);
+      return;
+}
+
+int mpz_cmp(mpz_t x, mpz_t y)
+{     /* compare x and y; return a positive value if x > y, zero if
+         x = y, or a nefative value if x < y */
+      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
+      struct mpz_seg dumx, dumy, *ex, *ey;
+      int cc, sx, sy, k;
+      unsigned int t;
+      if (x == y)
+      {  cc = 0;
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         cc = (xval > yval ? +1 : xval < yval ? -1 : 0);
+         goto done;
+      }
+      /* special case when [x] and [y] have different signs */
+      if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0)
+      {  cc = +1;
+         goto done;
+      }
+      if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0)
+      {  cc = -1;
+         goto done;
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* main fragment */
+      xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0);
+      cc = 0;
+      for (; ex || ey; ex = ex->next, ey = ey->next)
+      {  if (ex == NULL) ex = &zero;
+         if (ey == NULL) ey = &zero;
+         for (k = 0; k <= 5; k++)
+         {  if (ex->d[k] > ey->d[k]) cc = +1;
+            if (ex->d[k] < ey->d[k]) cc = -1;
+         }
+      }
+      if (sx < 0) cc = - cc;
+done: return cc;
+}
+
+int mpz_sgn(mpz_t x)
+{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+      int s;
+      s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0);
+      return s;
+}
+
+int mpz_out_str(void *_fp, int base, mpz_t x)
+{     /* output x on stream fp, as a string in given base; the base
+         may vary from 2 to 36;
+         return the number of bytes written, or if an error occurred,
+         return 0 */
+      FILE *fp = _fp;
+      mpz_t b, y, r;
+      int n, j, nwr = 0;
+      unsigned char *d;
+      static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+      if (!(2 <= base && base <= 36))
+         xfault("mpz_out_str: base = %d; invalid base\n", base);
+      mpz_init(b);
+      mpz_set_si(b, base);
+      mpz_init(y);
+      mpz_init(r);
+      /* determine the number of digits */
+      mpz_abs(y, x);
+      for (n = 0; mpz_sgn(y) != 0; n++)
+         mpz_div(y, NULL, y, b);
+      if (n == 0) n = 1;
+      /* compute the digits */
+      d = xmalloc(n);
+      mpz_abs(y, x);
+      for (j = 0; j < n; j++)
+      {  mpz_div(y, r, y, b);
+         xassert(0 <= r->val && r->val < base && r->ptr == NULL);
+         d[j] = (unsigned char)r->val;
+      }
+      /* output the integer to the stream */
+      /* if (fp == NULL) fp = stdout; */
+      if (mpz_sgn(x) < 0)
+         fputc('-', fp), nwr++;
+      for (j = n-1; j >= 0; j--)
+         fputc(set[d[j]], fp), nwr++;
+      if (ferror(fp)) nwr = 0;
+      mpz_clear(b);
+      mpz_clear(y);
+      mpz_clear(r);
+      xfree(d);
+      return nwr;
+}
+
+/*====================================================================*/
+
+mpq_t _mpq_init(void)
+{     /* initialize x, and set its value to 0/1 */
+      mpq_t x;
+      x = gmp_get_atom(sizeof(struct mpq));
+      x->p.val = 0;
+      x->p.ptr = NULL;
+      x->q.val = 1;
+      x->q.ptr = NULL;
+      return x;
+}
+
+void mpq_clear(mpq_t x)
+{     /* free the space occupied by x */
+      mpz_set_si(&x->p, 0);
+      xassert(x->p.ptr == NULL);
+      mpz_set_si(&x->q, 0);
+      xassert(x->q.ptr == NULL);
+      /* free the number descriptor */
+      gmp_free_atom(x, sizeof(struct mpq));
+      return;
+}
+
+void mpq_canonicalize(mpq_t x)
+{     /* remove any factors that are common to the numerator and
+         denominator of x, and make the denominator positive */
+      mpz_t f;
+      xassert(x->q.val != 0);
+      if (x->q.val < 0)
+      {  mpz_neg(&x->p, &x->p);
+         mpz_neg(&x->q, &x->q);
+      }
+      mpz_init(f);
+      mpz_gcd(f, &x->p, &x->q);
+      if (!(f->val == 1 && f->ptr == NULL))
+      {  mpz_div(&x->p, NULL, &x->p, f);
+         mpz_div(&x->q, NULL, &x->q, f);
+      }
+      mpz_clear(f);
+      return;
+}
+
+void mpq_set(mpq_t z, mpq_t x)
+{     /* set the value of z from x */
+      if (z != x)
+      {  mpz_set(&z->p, &x->p);
+         mpz_set(&z->q, &x->q);
+      }
+      return;
+}
+
+void mpq_set_si(mpq_t x, int p, unsigned int q)
+{     /* set the value of x to p/q */
+      if (q == 0)
+         xfault("mpq_set_si: zero denominator not allowed\n");
+      mpz_set_si(&x->p, p);
+      xassert(q <= 0x7FFFFFFF);
+      mpz_set_si(&x->q, q);
+      return;
+}
+
+double mpq_get_d(mpq_t x)
+{     /* convert x to a double, truncating if necessary */
+      int np, nq;
+      double p, q;
+      p = mpz_get_d_2exp(&np, &x->p);
+      q = mpz_get_d_2exp(&nq, &x->q);
+      return ldexp(p / q, np - nq);
+}
+
+void mpq_set_d(mpq_t x, double val)
+{     /* set x to val; there is no rounding, the conversion is exact */
+      int s, n, d, j;
+      double f;
+      mpz_t temp;
+      xassert(-DBL_MAX <= val && val <= +DBL_MAX);
+      mpq_set_si(x, 0, 1);
+      if (val > 0.0)
+         s = +1;
+      else if (val < 0.0)
+         s = -1;
+      else
+         goto done;
+      f = frexp(fabs(val), &n);
+      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
+      mpz_init(temp);
+      while (f != 0.0)
+      {  f *= 16.0, n -= 4;
+         d = (int)f;
+         xassert(0 <= d && d <= 15);
+         f -= (double)d;
+         /* x := 16 * x + d */
+         mpz_set_si(temp, 16);
+         mpz_mul(&x->p, &x->p, temp);
+         mpz_set_si(temp, d);
+         mpz_add(&x->p, &x->p, temp);
+      }
+      mpz_clear(temp);
+      /* x := x * 2^n */
+      if (n > 0)
+      {  for (j = 1; j <= n; j++)
+            mpz_add(&x->p, &x->p, &x->p);
+      }
+      else if (n < 0)
+      {  for (j = 1; j <= -n; j++)
+            mpz_add(&x->q, &x->q, &x->q);
+         mpq_canonicalize(x);
+      }
+      if (s < 0) mpq_neg(x, x);
+done: return;
+}
+
+void mpq_add(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x + y */
+      mpz_t p, q;
+      mpz_init(p);
+      mpz_init(q);
+      mpz_mul(p, &x->p, &y->q);
+      mpz_mul(q, &x->q, &y->p);
+      mpz_add(p, p, q);
+      mpz_mul(q, &x->q, &y->q);
+      mpz_set(&z->p, p);
+      mpz_set(&z->q, q);
+      mpz_clear(p);
+      mpz_clear(q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_sub(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x - y */
+      mpz_t p, q;
+      mpz_init(p);
+      mpz_init(q);
+      mpz_mul(p, &x->p, &y->q);
+      mpz_mul(q, &x->q, &y->p);
+      mpz_sub(p, p, q);
+      mpz_mul(q, &x->q, &y->q);
+      mpz_set(&z->p, p);
+      mpz_set(&z->q, q);
+      mpz_clear(p);
+      mpz_clear(q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_mul(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x * y */
+      mpz_mul(&z->p, &x->p, &y->p);
+      mpz_mul(&z->q, &x->q, &y->q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_div(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x / y */
+      mpz_t p, q;
+      if (mpq_sgn(y) == 0)
+         xfault("mpq_div: zero divisor not allowed\n");
+      mpz_init(p);
+      mpz_init(q);
+      mpz_mul(p, &x->p, &y->q);
+      mpz_mul(q, &x->q, &y->p);
+      mpz_set(&z->p, p);
+      mpz_set(&z->q, q);
+      mpz_clear(p);
+      mpz_clear(q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_neg(mpq_t z, mpq_t x)
+{     /* set z to 0 - x */
+      mpq_set(z, x);
+      mpz_neg(&z->p, &z->p);
+      return;
+}
+
+void mpq_abs(mpq_t z, mpq_t x)
+{     /* set z to the absolute value of x */
+      mpq_set(z, x);
+      mpz_abs(&z->p, &z->p);
+      xassert(mpz_sgn(&x->q) > 0);
+      return;
+}
+
+int mpq_cmp(mpq_t x, mpq_t y)
+{     /* compare x and y; return a positive value if x > y, zero if
+         x = y, or a nefative value if x < y */
+      mpq_t temp;
+      int s;
+      mpq_init(temp);
+      mpq_sub(temp, x, y);
+      s = mpq_sgn(temp);
+      mpq_clear(temp);
+      return s;
+}
+
+int mpq_sgn(mpq_t x)
+{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+      int s;
+      s = mpz_sgn(&x->p);
+      xassert(mpz_sgn(&x->q) > 0);
+      return s;
+}
+
+int mpq_out_str(void *_fp, int base, mpq_t x)
+{     /* output x on stream fp, as a string in given base; the base
+         may vary from 2 to 36; output is in the form 'num/den' or if
+         the denominator is 1 then just 'num';
+         if the parameter fp is a null pointer, stdout is assumed;
+         return the number of bytes written, or if an error occurred,
+         return 0 */
+      FILE *fp = _fp;
+      int nwr;
+      if (!(2 <= base && base <= 36))
+         xfault("mpq_out_str: base = %d; invalid base\n", base);
+      /* if (fp == NULL) fp = stdout; */
+      nwr = mpz_out_str(fp, base, &x->p);
+      if (x->q.val == 1 && x->q.ptr == NULL)
+         ;
+      else
+      {  fputc('/', fp), nwr++;
+         nwr += mpz_out_str(fp, base, &x->q);
+      }
+      if (ferror(fp)) nwr = 0;
+      return nwr;
+}
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpgmp.h b/optional/glpk/glpgmp.h
new file mode 100644
index 0000000..741e3a7
--- /dev/null
+++ b/optional/glpk/glpgmp.h
@@ -0,0 +1,190 @@
+/* glpgmp.h (bignum arithmetic) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPGMP_H
+#define GLPGMP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_GMP               /* use GNU MP bignum library */
+
+#include <gmp.h>
+
+#define gmp_pool_count        _glp_gmp_pool_count
+#define gmp_free_mem          _glp_gmp_free_mem
+
+int gmp_pool_count(void);
+void gmp_free_mem(void);
+
+#else                         /* use GLPK bignum module */
+
+/*----------------------------------------------------------------------
+// INTEGER NUMBERS
+//
+// Depending on its magnitude an integer number of arbitrary precision
+// is represented either in short format or in long format.
+//
+// Short format corresponds to the int type and allows representing
+// integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for
+// the most negative number of int type the short format is not used.
+//
+// In long format integer numbers are represented using the positional
+// system with the base (radix) 2^16 = 65536:
+//
+//    x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j,
+//
+// where x is the integer to be represented, s is its sign (+1 or -1),
+// d[j] are its digits (0 <= d[j] <= 65535).
+//
+// RATIONAL NUMBERS
+//
+// A rational number is represented as an irreducible fraction:
+//
+//    p / q,
+//
+// where p (numerator) and q (denominator) are integer numbers (q > 0)
+// having no common divisors. */
+
+struct mpz
+{     /* integer number */
+      int val;
+      /* if ptr is a null pointer, the number is in short format, and
+         val is its value; otherwise, the number is in long format, and
+         val is its sign (+1 or -1) */
+      struct mpz_seg *ptr;
+      /* pointer to the linked list of the number segments ordered in
+         ascending of powers of the base */
+};
+
+struct mpz_seg
+{     /* integer number segment */
+      unsigned short d[6];
+      /* six digits of the number ordered in ascending of powers of the
+         base */
+      struct mpz_seg *next;
+      /* pointer to the next number segment */
+};
+
+struct mpq
+{     /* rational number (p / q) */
+      struct mpz p;
+      /* numerator */
+      struct mpz q;
+      /* denominator */
+};
+
+typedef struct mpz *mpz_t;
+typedef struct mpq *mpq_t;
+
+#define gmp_get_atom          _glp_gmp_get_atom
+#define gmp_free_atom         _glp_gmp_free_atom
+#define gmp_pool_count        _glp_gmp_pool_count
+#define gmp_get_work          _glp_gmp_get_work
+#define gmp_free_mem          _glp_gmp_free_mem
+
+#define _mpz_init             _glp_mpz_init
+#define mpz_clear             _glp_mpz_clear
+#define mpz_set               _glp_mpz_set
+#define mpz_set_si            _glp_mpz_set_si
+#define mpz_get_d             _glp_mpz_get_d
+#define mpz_get_d_2exp        _glp_mpz_get_d_2exp
+#define mpz_swap              _glp_mpz_swap
+#define mpz_add               _glp_mpz_add
+#define mpz_sub               _glp_mpz_sub
+#define mpz_mul               _glp_mpz_mul
+#define mpz_neg               _glp_mpz_neg
+#define mpz_abs               _glp_mpz_abs
+#define mpz_div               _glp_mpz_div
+#define mpz_gcd               _glp_mpz_gcd
+#define mpz_cmp               _glp_mpz_cmp
+#define mpz_sgn               _glp_mpz_sgn
+#define mpz_out_str           _glp_mpz_out_str
+
+#define _mpq_init             _glp_mpq_init
+#define mpq_clear             _glp_mpq_clear
+#define mpq_canonicalize      _glp_mpq_canonicalize
+#define mpq_set               _glp_mpq_set
+#define mpq_set_si            _glp_mpq_set_si
+#define mpq_get_d             _glp_mpq_get_d
+#define mpq_set_d             _glp_mpq_set_d
+#define mpq_add               _glp_mpq_add
+#define mpq_sub               _glp_mpq_sub
+#define mpq_mul               _glp_mpq_mul
+#define mpq_div               _glp_mpq_div
+#define mpq_neg               _glp_mpq_neg
+#define mpq_abs               _glp_mpq_abs
+#define mpq_cmp               _glp_mpq_cmp
+#define mpq_sgn               _glp_mpq_sgn
+#define mpq_out_str           _glp_mpq_out_str
+
+void *gmp_get_atom(int size);
+void gmp_free_atom(void *ptr, int size);
+int gmp_pool_count(void);
+unsigned short *gmp_get_work(int size);
+void gmp_free_mem(void);
+
+mpz_t _mpz_init(void);
+#define mpz_init(x) (void)((x) = _mpz_init())
+void mpz_clear(mpz_t x);
+void mpz_set(mpz_t z, mpz_t x);
+void mpz_set_si(mpz_t x, int val);
+double mpz_get_d(mpz_t x);
+double mpz_get_d_2exp(int *exp, mpz_t x);
+void mpz_swap(mpz_t x, mpz_t y);
+void mpz_add(mpz_t, mpz_t, mpz_t);
+void mpz_sub(mpz_t, mpz_t, mpz_t);
+void mpz_mul(mpz_t, mpz_t, mpz_t);
+void mpz_neg(mpz_t z, mpz_t x);
+void mpz_abs(mpz_t z, mpz_t x);
+void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y);
+void mpz_gcd(mpz_t z, mpz_t x, mpz_t y);
+int mpz_cmp(mpz_t x, mpz_t y);
+int mpz_sgn(mpz_t x);
+int mpz_out_str(void *fp, int base, mpz_t x);
+
+mpq_t _mpq_init(void);
+#define mpq_init(x) (void)((x) = _mpq_init())
+void mpq_clear(mpq_t x);
+void mpq_canonicalize(mpq_t x);
+void mpq_set(mpq_t z, mpq_t x);
+void mpq_set_si(mpq_t x, int p, unsigned int q);
+double mpq_get_d(mpq_t x);
+void mpq_set_d(mpq_t x, double val);
+void mpq_add(mpq_t z, mpq_t x, mpq_t y);
+void mpq_sub(mpq_t z, mpq_t x, mpq_t y);
+void mpq_mul(mpq_t z, mpq_t x, mpq_t y);
+void mpq_div(mpq_t z, mpq_t x, mpq_t y);
+void mpq_neg(mpq_t z, mpq_t x);
+void mpq_abs(mpq_t z, mpq_t x);
+int mpq_cmp(mpq_t x, mpq_t y);
+int mpq_sgn(mpq_t x);
+int mpq_out_str(void *fp, int base, mpq_t x);
+
+#endif
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glphbm.c b/optional/glpk/glphbm.c
new file mode 100644
index 0000000..aff755a
--- /dev/null
+++ b/optional/glpk/glphbm.c
@@ -0,0 +1,519 @@
+/* glphbm.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glphbm.h"
+#include "glpenv.h"
+
+/***********************************************************************
+*  NAME
+*
+*  hbm_read_mat - read sparse matrix in Harwell-Boeing format
+*
+*  SYNOPSIS
+*
+*  #include "glphbm.h"
+*  HBM *hbm_read_mat(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing
+*  format from a text file whose name is the character string fname.
+*
+*  Detailed description of the Harwell-Boeing format recognised by this
+*  routine is given in the following report:
+*
+*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
+*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
+*
+*  RETURNS
+*
+*  If no error occured, the routine hbm_read_mat returns a pointer to
+*  a data structure containing the matrix. In case of error the routine
+*  prints an appropriate error message and returns NULL. */
+
+struct dsa
+{     /* working area used by routine hbm_read_mat */
+      const char *fname;
+      /* name of input text file */
+      FILE *fp;
+      /* stream assigned to input text file */
+      int seqn;
+      /* card sequential number */
+      char card[80+1];
+      /* card image buffer */
+      int fmt_p;
+      /* scale factor */
+      int fmt_k;
+      /* iterator */
+      int fmt_f;
+      /* format code */
+      int fmt_w;
+      /* field width */
+      int fmt_d;
+      /* number of decimal places after point */
+};
+
+/***********************************************************************
+*  read_card - read next data card
+*
+*  This routine reads the next 80-column card from the input text file
+*  and stores its image into the character string card. If the card was
+*  read successfully, the routine returns zero, otherwise non-zero. */
+
+static int read_card(struct dsa *dsa)
+{     int k, c;
+      dsa->seqn++;
+      memset(dsa->card, ' ', 80), dsa->card[80] = '\0';
+      k = 0;
+      for (;;)
+      {  c = fgetc(dsa->fp);
+         if (ferror(dsa->fp))
+         {  xprintf("%s:%d: read error - %s\n", dsa->fname, dsa->seqn,
+               strerror(errno));
+            return 1;
+         }
+         if (feof(dsa->fp))
+         {  if (k == 0)
+               xprintf("%s:%d: unexpected EOF\n", dsa->fname,
+                  dsa->seqn);
+            else
+               xprintf("%s:%d: missing final LF\n", dsa->fname,
+                  dsa->seqn);
+            return 1;
+         }
+         if (c == '\r') continue;
+         if (c == '\n') break;
+         if (iscntrl(c))
+         {  xprintf("%s:%d: invalid control character 0x%02X\n",
+               dsa->fname, dsa->seqn, c);
+            return 1;
+         }
+         if (k == 80)
+         {  xprintf("%s:%d: card image too long\n", dsa->fname,
+               dsa->seqn);
+            return 1;
+         }
+         dsa->card[k++] = (char)c;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  scan_int - scan integer value from the current card
+*
+*  This routine scans an integer value from the current card, where fld
+*  is the name of the field, pos is the position of the field, width is
+*  the width of the field, val points to a location to which the scanned
+*  value should be stored. If the value was scanned successfully, the
+*  routine returns zero, otherwise non-zero. */
+
+static int scan_int(struct dsa *dsa, char *fld, int pos, int width,
+      int *val)
+{     char str[80+1];
+      xassert(1 <= width && width <= 80);
+      memcpy(str, dsa->card + pos, width), str[width] = '\0';
+      if (str2int(strspx(str), val))
+      {  xprintf("%s:%d: field `%s' contains invalid value `%s'\n",
+            dsa->fname, dsa->seqn, fld, str);
+         return 1;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  parse_fmt - parse Fortran format specification
+*
+*  This routine parses the Fortran format specification represented as
+*  character string which fmt points to and stores format elements into
+*  appropriate static locations. Should note that not all valid Fortran
+*  format specifications may be recognised. If the format specification
+*  was recognised, the routine returns zero, otherwise non-zero. */
+
+static int parse_fmt(struct dsa *dsa, char *fmt)
+{     int k, s, val;
+      char str[80+1];
+      /* first character should be left parenthesis */
+      if (fmt[0] != '(')
+fail: {  xprintf("hbm_read_mat: format `%s' not recognised\n", fmt);
+         return 1;
+      }
+      k = 1;
+      /* optional scale factor */
+      dsa->fmt_p = 0;
+      if (isdigit((unsigned char)fmt[k]))
+      {  s = 0;
+         while (isdigit((unsigned char)fmt[k]))
+         {  if (s == 80) goto fail;
+            str[s++] = fmt[k++];
+         }
+         str[s] = '\0';
+         if (str2int(str, &val)) goto fail;
+         if (toupper((unsigned char)fmt[k]) != 'P') goto iter;
+         dsa->fmt_p = val, k++;
+         if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail;
+         /* optional comma may follow scale factor */
+         if (fmt[k] == ',') k++;
+      }
+      /* optional iterator */
+      dsa->fmt_k = 1;
+      if (isdigit((unsigned char)fmt[k]))
+      {  s = 0;
+         while (isdigit((unsigned char)fmt[k]))
+         {  if (s == 80) goto fail;
+            str[s++] = fmt[k++];
+         }
+         str[s] = '\0';
+         if (str2int(str, &val)) goto fail;
+iter:    dsa->fmt_k = val;
+         if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail;
+      }
+      /* format code */
+      dsa->fmt_f = toupper((unsigned char)fmt[k++]);
+      if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' ||
+            dsa->fmt_f == 'F' || dsa->fmt_f == 'G' ||
+            dsa->fmt_f == 'I')) goto fail;
+      /* field width */
+      if (!isdigit((unsigned char)fmt[k])) goto fail;
+      s = 0;
+      while (isdigit((unsigned char)fmt[k]))
+      {  if (s == 80) goto fail;
+         str[s++] = fmt[k++];
+      }
+      str[s] = '\0';
+      if (str2int(str, &dsa->fmt_w)) goto fail;
+      if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail;
+      /* optional number of decimal places after point */
+      dsa->fmt_d = 0;
+      if (fmt[k] == '.')
+      {  k++;
+         if (!isdigit((unsigned char)fmt[k])) goto fail;
+         s = 0;
+         while (isdigit((unsigned char)fmt[k]))
+         {  if (s == 80) goto fail;
+            str[s++] = fmt[k++];
+         }
+         str[s] = '\0';
+         if (str2int(str, &dsa->fmt_d)) goto fail;
+         if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail;
+      }
+      /* last character should be right parenthesis */
+      if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail;
+      return 0;
+}
+
+/***********************************************************************
+*  read_int_array - read array of integer type
+*
+*  This routine reads an integer array from the input text file, where
+*  name is array name, fmt is Fortran format specification that controls
+*  reading, n is number of array elements, val is array of integer type.
+*  If the array was read successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int read_int_array(struct dsa *dsa, char *name, char *fmt,
+      int n, int val[])
+{     int k, pos;
+      char str[80+1];
+      if (parse_fmt(dsa, fmt)) return 1;
+      if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 &&
+            dsa->fmt_k * dsa->fmt_w <= 80))
+      {  xprintf(
+            "%s:%d: can't read array `%s' - invalid format `%s'\n",
+            dsa->fname, dsa->seqn, name, fmt);
+         return 1;
+      }
+      for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
+      {  if (pos >= dsa->fmt_k)
+         {  if (read_card(dsa)) return 1;
+            pos = 0;
+         }
+         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
+         str[dsa->fmt_w] = '\0';
+         strspx(str);
+         if (str2int(str, &val[k]))
+         {  xprintf(
+               "%s:%d: can't read array `%s' - invalid value `%s'\n",
+               dsa->fname, dsa->seqn, name, str);
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  read_real_array - read array of real type
+*
+*  This routine reads a real array from the input text file, where name
+*  is array name, fmt is Fortran format specification that controls
+*  reading, n is number of array elements, val is array of real type.
+*  If the array was read successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int read_real_array(struct dsa *dsa, char *name, char *fmt,
+      int n, double val[])
+{     int k, pos;
+      char str[80+1], *ptr;
+      if (parse_fmt(dsa, fmt)) return 1;
+      if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 &&
+            dsa->fmt_k * dsa->fmt_w <= 80))
+      {  xprintf(
+            "%s:%d: can't read array `%s' - invalid format `%s'\n",
+            dsa->fname, dsa->seqn, name, fmt);
+         return 1;
+      }
+      for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
+      {  if (pos >= dsa->fmt_k)
+         {  if (read_card(dsa)) return 1;
+            pos = 0;
+         }
+         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
+         str[dsa->fmt_w] = '\0';
+         strspx(str);
+         if (strchr(str, '.') == NULL && strcmp(str, "0"))
+         {  xprintf("%s(%d): can't read array `%s' - value `%s' has no "
+               "decimal point\n", dsa->fname, dsa->seqn, name, str);
+            return 1;
+         }
+         /* sometimes lower case letters appear */
+         for (ptr = str; *ptr; ptr++)
+            *ptr = (char)toupper((unsigned char)*ptr);
+         ptr = strchr(str, 'D');
+         if (ptr != NULL) *ptr = 'E';
+         /* value may appear with decimal exponent but without letters
+            E or D (for example, -123.456-012), so missing letter should
+            be inserted */
+         ptr = strchr(str+1, '+');
+         if (ptr == NULL) ptr = strchr(str+1, '-');
+         if (ptr != NULL && *(ptr-1) != 'E')
+         {  xassert(strlen(str) < 80);
+            memmove(ptr+1, ptr, strlen(ptr)+1);
+            *ptr = 'E';
+         }
+         if (str2num(str, &val[k]))
+         {  xprintf(
+               "%s:%d: can't read array `%s' - invalid value `%s'\n",
+               dsa->fname, dsa->seqn, name, str);
+            return 1;
+         }
+      }
+      return 0;
+}
+
+HBM *hbm_read_mat(const char *fname)
+{     struct dsa _dsa, *dsa = &_dsa;
+      HBM *hbm = NULL;
+      dsa->fname = fname;
+      xprintf("hbm_read_mat: reading matrix from `%s'...\n",
+         dsa->fname);
+      dsa->fp = fopen(dsa->fname, "r");
+      if (dsa->fp == NULL)
+      {  xprintf("hbm_read_mat: unable to open `%s' - %s\n",
+            dsa->fname, strerror(errno));
+         goto fail;
+      }
+      dsa->seqn = 0;
+      hbm = xmalloc(sizeof(HBM));
+      memset(hbm, 0, sizeof(HBM));
+      /* read the first heading card */
+      if (read_card(dsa)) goto fail;
+      memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0';
+      strtrim(hbm->title);
+      xprintf("%s\n", hbm->title);
+      memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0';
+      strspx(hbm->key);
+      xprintf("key = %s\n", hbm->key);
+      /* read the second heading card */
+      if (read_card(dsa)) goto fail;
+      if (scan_int(dsa, "totcrd",  0, 14, &hbm->totcrd)) goto fail;
+      if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail;
+      if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail;
+      if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail;
+      if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail;
+      xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc"
+         "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd,
+         hbm->valcrd, hbm->rhscrd);
+      /* read the third heading card */
+      if (read_card(dsa)) goto fail;
+      memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0';
+      if (strchr("RCP",   hbm->mxtype[0]) == NULL ||
+          strchr("SUHZR", hbm->mxtype[1]) == NULL ||
+          strchr("AE",    hbm->mxtype[2]) == NULL)
+      {  xprintf("%s:%d: matrix type `%s' not recognised\n",
+            dsa->fname, dsa->seqn, hbm->mxtype);
+         goto fail;
+      }
+      if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail;
+      if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail;
+      if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail;
+      if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail;
+      xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl ="
+         " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero,
+         hbm->neltvl);
+      /* read the fourth heading card */
+      if (read_card(dsa)) goto fail;
+      memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0';
+      strspx(hbm->ptrfmt);
+      memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0';
+      strspx(hbm->indfmt);
+      memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0';
+      strspx(hbm->valfmt);
+      memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0';
+      strspx(hbm->rhsfmt);
+      xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n",
+         hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt);
+      /* read the fifth heading card (optional) */
+      if (hbm->rhscrd <= 0)
+      {  strcpy(hbm->rhstyp, "???");
+         hbm->nrhs = 0;
+         hbm->nrhsix = 0;
+      }
+      else
+      {  if (read_card(dsa)) goto fail;
+         memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0';
+         if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail;
+         if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail;
+         xprintf("rhstyp = `%s'; nrhs = %d; nrhsix = %d\n",
+            hbm->rhstyp, hbm->nrhs, hbm->nrhsix);
+      }
+      /* read matrix structure */
+      hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int));
+      if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1,
+         hbm->colptr)) goto fail;
+      hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int));
+      if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero,
+         hbm->rowind)) goto fail;
+      /* read matrix values */
+      if (hbm->valcrd <= 0) goto done;
+      if (hbm->mxtype[2] == 'A')
+      {  /* assembled matrix */
+         hbm->values = xcalloc(1+hbm->nnzero, sizeof(double));
+         if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero,
+            hbm->values)) goto fail;
+      }
+      else
+      {  /* elemental (unassembled) matrix */
+         hbm->values = xcalloc(1+hbm->neltvl, sizeof(double));
+         if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl,
+            hbm->values)) goto fail;
+      }
+      /* read right-hand sides */
+      if (hbm->nrhs <= 0) goto done;
+      if (hbm->rhstyp[0] == 'F')
+      {  /* dense format */
+         hbm->nrhsvl = hbm->nrow * hbm->nrhs;
+         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
+         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
+            hbm->rhsval)) goto fail;
+      }
+      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A')
+      {  /* sparse format */
+         /* read pointers */
+         hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int));
+         if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1,
+            hbm->rhsptr)) goto fail;
+         /* read sparsity pattern */
+         hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int));
+         if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix,
+            hbm->rhsind)) goto fail;
+         /* read values */
+         hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double));
+         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix,
+            hbm->rhsval)) goto fail;
+      }
+      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E')
+      {  /* elemental format */
+         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
+         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
+            hbm->rhsval)) goto fail;
+      }
+      else
+      {  xprintf("%s:%d: right-hand side type `%c' not recognised\n",
+            dsa->fname, dsa->seqn, hbm->rhstyp[0]);
+         goto fail;
+      }
+      /* read starting guesses */
+      if (hbm->rhstyp[1] == 'G')
+      {  hbm->nguess = hbm->nrow * hbm->nrhs;
+         hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double));
+         if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess,
+            hbm->sguess)) goto fail;
+      }
+      /* read solution vectors */
+      if (hbm->rhstyp[2] == 'X')
+      {  hbm->nexact = hbm->nrow * hbm->nrhs;
+         hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double));
+         if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact,
+            hbm->xexact)) goto fail;
+      }
+done: /* reading has been completed */
+      xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn);
+      fclose(dsa->fp);
+      return hbm;
+fail: /* something wrong in Danish kingdom */
+      if (hbm != NULL)
+      {  if (hbm->colptr != NULL) xfree(hbm->colptr);
+         if (hbm->rowind != NULL) xfree(hbm->rowind);
+         if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
+         if (hbm->rhsind != NULL) xfree(hbm->rhsind);
+         if (hbm->values != NULL) xfree(hbm->values);
+         if (hbm->rhsval != NULL) xfree(hbm->rhsval);
+         if (hbm->sguess != NULL) xfree(hbm->sguess);
+         if (hbm->xexact != NULL) xfree(hbm->xexact);
+         xfree(hbm);
+      }
+      if (dsa->fp != NULL) fclose(dsa->fp);
+      return NULL;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  hbm_free_mat - free sparse matrix in Harwell-Boeing format
+*
+*  SYNOPSIS
+*
+*  #include "glphbm.h"
+*  void hbm_free_mat(HBM *hbm);
+*
+*  DESCRIPTION
+*
+*  The hbm_free_mat routine frees all the memory allocated to the data
+*  structure containing a sparse matrix in the Harwell-Boeing format. */
+
+void hbm_free_mat(HBM *hbm)
+{     if (hbm->colptr != NULL) xfree(hbm->colptr);
+      if (hbm->rowind != NULL) xfree(hbm->rowind);
+      if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
+      if (hbm->rhsind != NULL) xfree(hbm->rhsind);
+      if (hbm->values != NULL) xfree(hbm->values);
+      if (hbm->rhsval != NULL) xfree(hbm->rhsval);
+      if (hbm->sguess != NULL) xfree(hbm->sguess);
+      if (hbm->xexact != NULL) xfree(hbm->xexact);
+      xfree(hbm);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glphbm.h b/optional/glpk/glphbm.h
new file mode 100644
index 0000000..fd347c4
--- /dev/null
+++ b/optional/glpk/glphbm.h
@@ -0,0 +1,127 @@
+/* glphbm.h (Harwell-Boeing sparse matrix format) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPHBM_H
+#define GLPHBM_H
+
+typedef struct HBM HBM;
+
+struct HBM
+{     /* sparse matrix in Harwell-Boeing format; for details see the
+         report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the
+         Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */
+      char title[72+1];
+      /* matrix title (informative) */
+      char key[8+1];
+      /* matrix key (informative) */
+      char mxtype[3+1];
+      /* matrix type:
+         R.. real matrix
+         C.. complex matrix
+         P.. pattern only (no numerical values supplied)
+         .S. symmetric (lower triangle + main diagonal)
+         .U. unsymmetric
+         .H. hermitian (lower triangle + main diagonal)
+         .Z. skew symmetric (lower triangle only)
+         .R. rectangular
+         ..A assembled
+         ..E elemental (unassembled) */
+      char rhstyp[3+1];
+      /* optional types:
+         F.. right-hand sides in dense format
+         M.. right-hand sides in same format as matrix
+         .G. starting vector(s) (guess) is supplied
+         ..X exact solution vector(s) is supplied */
+      char ptrfmt[16+1];
+      /* format for pointers */
+      char indfmt[16+1];
+      /* format for row (or variable) indices */
+      char valfmt[20+1];
+      /* format for numerical values of coefficient matrix */
+      char rhsfmt[20+1];
+      /* format for numerical values of right-hand sides */
+      int totcrd;
+      /* total number of cards excluding header */
+      int ptrcrd;
+      /* number of cards for ponters */
+      int indcrd;
+      /* number of cards for row (or variable) indices */
+      int valcrd;
+      /* number of cards for numerical values */
+      int rhscrd;
+      /* number of lines for right-hand sides;
+         including starting guesses and solution vectors if present;
+         zero indicates no right-hand side data is present */
+      int nrow;
+      /* number of rows (or variables) */
+      int ncol;
+      /* number of columns (or elements) */
+      int nnzero;
+      /* number of row (or variable) indices;
+         equal to number of entries for assembled matrix */
+      int neltvl;
+      /* number of elemental matrix entries;
+         zero in case of assembled matrix */
+      int nrhs;
+      /* number of right-hand sides */
+      int nrhsix;
+      /* number of row indices;
+         ignored in case of unassembled matrix */
+      int nrhsvl;
+      /* total number of entries in all right-hand sides */
+      int nguess;
+      /* total number of entries in all starting guesses */
+      int nexact;
+      /* total number of entries in all solution vectors */
+      int *colptr; /* alias: eltptr */
+      /* column pointers (in case of assembled matrix);
+         elemental matrix pointers (in case of unassembled matrix) */
+      int *rowind; /* alias: varind */
+      /* row indices (in case of assembled matrix);
+         variable indices (in case of unassembled matrix) */
+      int *rhsptr;
+      /* right-hand side pointers */
+      int *rhsind;
+      /* right-hand side indices */
+      double *values;
+      /* matrix values */
+      double *rhsval;
+      /* right-hand side values */
+      double *sguess;
+      /* starting guess values */
+      double *xexact;
+      /* solution vector values */
+};
+
+#define hbm_read_mat _glp_hbm_read_mat
+HBM *hbm_read_mat(const char *fname);
+/* read sparse matrix in Harwell-Boeing format */
+
+#define hbm_free_mat _glp_hbm_free_mat
+void hbm_free_mat(HBM *hbm);
+/* free sparse matrix in Harwell-Boeing format */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpini01.c b/optional/glpk/glpini01.c
new file mode 100644
index 0000000..55fde56
--- /dev/null
+++ b/optional/glpk/glpini01.c
@@ -0,0 +1,581 @@
+/* glpini01.c */
+
+/***********************************************************************
+*  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 "-Wself-assign"
+#endif
+
+#include "glpapi.h"
+
+/*----------------------------------------------------------------------
+-- triang - find maximal triangular part of a rectangular matrix.
+--
+-- *Synopsis*
+--
+-- int triang(int m, int n,
+--    void *info, int (*mat)(void *info, int k, int ndx[]),
+--    int rn[], int cn[]);
+--
+-- *Description*
+--
+-- For a given rectangular (sparse) matrix A with m rows and n columns
+-- the routine triang tries to find such permutation matrices P and Q
+-- that the first rows and columns of the matrix B = P*A*Q form a lower
+-- triangular submatrix of as greatest size as possible:
+--
+--                   1                       n
+--                1  * . . . . . . x x x x x x
+--                   * * . . . . . x x x x x x
+--                   * * * . . . . x x x x x x
+--                   * * * * . . . x x x x x x
+--    B = P*A*Q =    * * * * * . . x x x x x x
+--                   * * * * * * . x x x x x x
+--                   * * * * * * * x x x x x x
+--                   x x x x x x x x x x x x x
+--                   x x x x x x x x x x x x x
+--                m  x x x x x x x x x x x x x
+--
+-- where: '*' - elements of the lower triangular part, '.' - structural
+-- zeros, 'x' - other (either non-zero or zero) elements.
+--
+-- The parameter info is a transit pointer passed to the formal routine
+-- mat (see below).
+--
+-- The formal routine mat specifies the given matrix A in both row- and
+-- column-wise formats. In order to obtain an i-th row of the matrix A
+-- the routine triang calls the routine mat with the parameter k = +i,
+-- 1 <= i <= m. In response the routine mat should store column indices
+-- of (non-zero) elements of the i-th row to the locations ndx[1], ...,
+-- ndx[len], where len is number of non-zeros in the i-th row returned
+-- on exit. Analogously, in order to obtain a j-th column of the matrix
+-- A, the routine mat is called with the parameter k = -j, 1 <= j <= n,
+-- and should return pattern of the j-th column in the same way as for
+-- row patterns. Note that the routine mat may be called more than once
+-- for the same rows and columns.
+--
+-- On exit the routine computes two resultant arrays rn and cn, which
+-- define the permutation matrices P and Q, respectively. The array rn
+-- should have at least 1+m locations, where rn[i] = i' (1 <= i <= m)
+-- means that i-th row of the original matrix A corresponds to i'-th row
+-- of the matrix B = P*A*Q. Similarly, the array cn should have at least
+-- 1+n locations, where cn[j] = j' (1 <= j <= n) means that j-th column
+-- of the matrix A corresponds to j'-th column of the matrix B.
+--
+-- *Returns*
+--
+-- The routine triang returns the size of the lower tringular part of
+-- the matrix B = P*A*Q (see the figure above).
+--
+-- *Complexity*
+--
+-- The time complexity of the routine triang is O(nnz), where nnz is
+-- number of non-zeros in the given matrix A.
+--
+-- *Algorithm*
+--
+-- The routine triang starts from the matrix B = P*Q*A, where P and Q
+-- are unity matrices, so initially B = A.
+--
+-- Before the next iteration B = (B1 | B2 | B3), where B1 is partially
+-- built a lower triangular submatrix, B2 is the active submatrix, and
+-- B3 is a submatrix that contains rejected columns. Thus, the current
+-- matrix B looks like follows (initially k1 = 1 and k2 = n):
+--
+--       1         k1         k2         n
+--    1  x . . . . . . . . . . . . . # # #
+--       x x . . . . . . . . . . . . # # #
+--       x x x . . . . . . . . . . # # # #
+--       x x x x . . . . . . . . . # # # #
+--       x x x x x . . . . . . . # # # # #
+--    k1 x x x x x * * * * * * * # # # # #
+--       x x x x x * * * * * * * # # # # #
+--       x x x x x * * * * * * * # # # # #
+--       x x x x x * * * * * * * # # # # #
+--    m  x x x x x * * * * * * * # # # # #
+--       <--B1---> <----B2-----> <---B3-->
+--
+-- On each iteartion the routine looks for a singleton row, i.e. some
+-- row that has the only non-zero in the active submatrix B2. If such
+-- row exists and the corresponding non-zero is b[i,j], where (by the
+-- definition) k1 <= i <= m and k1 <= j <= k2, the routine permutes
+-- k1-th and i-th rows and k1-th and j-th columns of the matrix B (in
+-- order to place the element in the position b[k1,k1]), removes the
+-- k1-th column from the active submatrix B2, and adds this column to
+-- the submatrix B1. If no row singletons exist, but B2 is not empty
+-- yet, the routine chooses a j-th column, which has maximal number of
+-- non-zeros among other columns of B2, removes this column from B2 and
+-- adds it to the submatrix B3 in the hope that new row singletons will
+-- appear in the active submatrix. */
+
+static int triang(int m, int n,
+      void *info, int (*mat)(void *info, int k, int ndx[]),
+      int rn[], int cn[])
+{     int *ndx; /* int ndx[1+max(m,n)]; */
+      /* this array is used for querying row and column patterns of the
+         given matrix A (the third parameter to the routine mat) */
+      int *rs_len; /* int rs_len[1+m]; */
+      /* rs_len[0] is not used;
+         rs_len[i], 1 <= i <= m, is number of non-zeros in the i-th row
+         of the matrix A, which (non-zeros) belong to the current active
+         submatrix */
+      int *rs_head; /* int rs_head[1+n]; */
+      /* rs_head[len], 0 <= len <= n, is the number i of the first row
+         of the matrix A, for which rs_len[i] = len */
+      int *rs_prev; /* int rs_prev[1+m]; */
+      /* rs_prev[0] is not used;
+         rs_prev[i], 1 <= i <= m, is a number i' of the previous row of
+         the matrix A, for which rs_len[i] = rs_len[i'] (zero marks the
+         end of this linked list) */
+      int *rs_next; /* int rs_next[1+m]; */
+      /* rs_next[0] is not used;
+         rs_next[i], 1 <= i <= m, is a number i' of the next row of the
+         matrix A, for which rs_len[i] = rs_len[i'] (zero marks the end
+         this linked list) */
+      int cs_head;
+      /* is a number j of the first column of the matrix A, which has
+         maximal number of non-zeros among other columns */
+      int *cs_prev; /* cs_prev[1+n]; */
+      /* cs_prev[0] is not used;
+         cs_prev[j], 1 <= j <= n, is a number of the previous column of
+         the matrix A with the same or greater number of non-zeros than
+         in the j-th column (zero marks the end of this linked list) */
+      int *cs_next; /* cs_next[1+n]; */
+      /* cs_next[0] is not used;
+         cs_next[j], 1 <= j <= n, is a number of the next column of
+         the matrix A with the same or lesser number of non-zeros than
+         in the j-th column (zero marks the end of this linked list) */
+      int i, j, ii, jj, k1, k2, len, t, size = 0;
+      int *head, *rn_inv, *cn_inv;
+      if (!(m > 0 && n > 0))
+         xerror("triang: m = %d; n = %d; invalid dimension\n", m, n);
+      /* allocate working arrays */
+      ndx = xcalloc(1+(m >= n ? m : n), sizeof(int));
+      rs_len = xcalloc(1+m, sizeof(int));
+      rs_head = xcalloc(1+n, sizeof(int));
+      rs_prev = xcalloc(1+m, sizeof(int));
+      rs_next = xcalloc(1+m, sizeof(int));
+      cs_prev = xcalloc(1+n, sizeof(int));
+      cs_next = xcalloc(1+n, sizeof(int));
+      /* build linked lists of columns of the matrix A with the same
+         number of non-zeros */
+      head = rs_len; /* currently rs_len is used as working array */
+      for (len = 0; len <= m; len ++) head[len] = 0;
+      for (j = 1; j <= n; j++)
+      {  /* obtain length of the j-th column */
+         len = mat(info, -j, ndx);
+         xassert(0 <= len && len <= m);
+         /* include the j-th column in the corresponding linked list */
+         cs_prev[j] = head[len];
+         head[len] = j;
+      }
+      /* merge all linked lists of columns in one linked list, where
+         columns are ordered by descending of their lengths */
+      cs_head = 0;
+      for (len = 0; len <= m; len++)
+      {  for (j = head[len]; j != 0; j = cs_prev[j])
+         {  cs_next[j] = cs_head;
+            cs_head = j;
+         }
+      }
+      jj = 0;
+      for (j = cs_head; j != 0; j = cs_next[j])
+      {  cs_prev[j] = jj;
+         jj = j;
+      }
+      /* build initial doubly linked lists of rows of the matrix A with
+         the same number of non-zeros */
+      for (len = 0; len <= n; len++) rs_head[len] = 0;
+      for (i = 1; i <= m; i++)
+      {  /* obtain length of the i-th row */
+         rs_len[i] = len = mat(info, +i, ndx);
+         xassert(0 <= len && len <= n);
+         /* include the i-th row in the correspondng linked list */
+         rs_prev[i] = 0;
+         rs_next[i] = rs_head[len];
+         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+         rs_head[len] = i;
+      }
+      /* initially all rows and columns of the matrix A are active */
+      for (i = 1; i <= m; i++) rn[i] = 0;
+      for (j = 1; j <= n; j++) cn[j] = 0;
+      /* set initial bounds of the active submatrix */
+      k1 = 1, k2 = n;
+      /* main loop starts here */
+      while (k1 <= k2)
+      {  i = rs_head[1];
+         if (i != 0)
+         {  /* the i-th row of the matrix A is a row singleton, since
+               it has the only non-zero in the active submatrix */
+            xassert(rs_len[i] == 1);
+            /* determine the number j of an active column of the matrix
+               A, in which this non-zero is placed */
+            j = 0;
+            t = mat(info, +i, ndx);
+            xassert(0 <= t && t <= n);
+            for (t = t; t >= 1; t--)
+            {  jj = ndx[t];
+               xassert(1 <= jj && jj <= n);
+               if (cn[jj] == 0)
+               {  xassert(j == 0);
+                  j = jj;
+               }
+            }
+            xassert(j != 0);
+            /* the singleton is a[i,j]; move a[i,j] to the position
+               b[k1,k1] of the matrix B */
+            rn[i] = cn[j] = k1;
+            /* shift the left bound of the active submatrix */
+            k1++;
+            /* increase the size of the lower triangular part */
+            size++;
+         }
+         else
+         {  /* the current active submatrix has no row singletons */
+            /* remove an active column with maximal number of non-zeros
+               from the active submatrix */
+            j = cs_head;
+            xassert(j != 0);
+            cn[j] = k2;
+            /* shift the right bound of the active submatrix */
+            k2--;
+         }
+         /* the j-th column of the matrix A has been removed from the
+            active submatrix */
+         /* remove the j-th column from the linked list */
+         if (cs_prev[j] == 0)
+            cs_head = cs_next[j];
+         else
+            cs_next[cs_prev[j]] = cs_next[j];
+         if (cs_next[j] == 0)
+            /* nop */;
+         else
+            cs_prev[cs_next[j]] = cs_prev[j];
+         /* go through non-zeros of the j-th columns and update active
+            lengths of the corresponding rows */
+         t = mat(info, -j, ndx);
+         xassert(0 <= t && t <= m);
+         for (t = t; t >= 1; t--)
+         {  i = ndx[t];
+            xassert(1 <= i && i <= m);
+            /* the non-zero a[i,j] has left the active submatrix */
+            len = rs_len[i];
+            xassert(len >= 1);
+            /* remove the i-th row from the linked list of rows with
+               active length len */
+            if (rs_prev[i] == 0)
+               rs_head[len] = rs_next[i];
+            else
+               rs_next[rs_prev[i]] = rs_next[i];
+            if (rs_next[i] == 0)
+               /* nop */;
+            else
+               rs_prev[rs_next[i]] = rs_prev[i];
+            /* decrease the active length of the i-th row */
+            rs_len[i] = --len;
+            /* return the i-th row to the corresponding linked list */
+            rs_prev[i] = 0;
+            rs_next[i] = rs_head[len];
+            if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+            rs_head[len] = i;
+         }
+      }
+      /* other rows of the matrix A, which are still active, correspond
+         to rows k1, ..., m of the matrix B (in arbitrary order) */
+      for (i = 1; i <= m; i++) if (rn[i] == 0) rn[i] = k1++;
+      /* but for columns this is not needed, because now the submatrix
+         B2 has no columns */
+      for (j = 1; j <= n; j++) xassert(cn[j] != 0);
+      /* perform some optional checks */
+      /* make sure that rn is a permutation of {1, ..., m} and cn is a
+         permutation of {1, ..., n} */
+      rn_inv = rs_len; /* used as working array */
+      for (ii = 1; ii <= m; ii++) rn_inv[ii] = 0;
+      for (i = 1; i <= m; i++)
+      {  ii = rn[i];
+         xassert(1 <= ii && ii <= m);
+         xassert(rn_inv[ii] == 0);
+         rn_inv[ii] = i;
+      }
+      cn_inv = rs_head; /* used as working array */
+      for (jj = 1; jj <= n; jj++) cn_inv[jj] = 0;
+      for (j = 1; j <= n; j++)
+      {  jj = cn[j];
+         xassert(1 <= jj && jj <= n);
+         xassert(cn_inv[jj] == 0);
+         cn_inv[jj] = j;
+      }
+      /* make sure that the matrix B = P*A*Q really has the form, which
+         was declared */
+      for (ii = 1; ii <= size; ii++)
+      {  int diag = 0;
+         i = rn_inv[ii];
+         t = mat(info, +i, ndx);
+         xassert(0 <= t && t <= n);
+         for (t = t; t >= 1; t--)
+         {  j = ndx[t];
+            xassert(1 <= j && j <= n);
+            jj = cn[j];
+            if (jj <= size) xassert(jj <= ii);
+            if (jj == ii)
+            {  xassert(!diag);
+               diag = 1;
+            }
+         }
+         xassert(diag);
+      }
+      /* free working arrays */
+      xfree(ndx);
+      xfree(rs_len);
+      xfree(rs_head);
+      xfree(rs_prev);
+      xfree(rs_next);
+      xfree(cs_prev);
+      xfree(cs_next);
+      /* return to the calling program */
+      return size;
+}
+
+/*----------------------------------------------------------------------
+-- adv_basis - construct advanced initial LP basis.
+--
+-- *Synopsis*
+--
+-- #include "glpini.h"
+-- void adv_basis(glp_prob *lp);
+--
+-- *Description*
+--
+-- The routine adv_basis constructs an advanced initial basis for an LP
+-- problem object, which the parameter lp points to.
+--
+-- In order to build the initial basis the routine does the following:
+--
+-- 1) includes in the basis all non-fixed auxiliary variables;
+--
+-- 2) includes in the basis as many as possible non-fixed structural
+--    variables preserving triangular form of the basis matrix;
+--
+-- 3) includes in the basis appropriate (fixed) auxiliary variables
+--    in order to complete the basis.
+--
+-- As a result the initial basis has minimum of fixed variables and the
+-- corresponding basis matrix is triangular. */
+
+static int mat(void *info, int k, int ndx[])
+{     /* this auxiliary routine returns the pattern of a given row or
+         a given column of the augmented constraint matrix A~ = (I|-A),
+         in which columns of fixed variables are implicitly cleared */
+      LPX *lp = info;
+      int m = lpx_get_num_rows(lp);
+      int n = lpx_get_num_cols(lp);
+      int typx, i, j, lll, len = 0;
+      if (k > 0)
+      {  /* the pattern of the i-th row is required */
+         i = +k;
+         xassert(1 <= i && i <= m);
+#if 0 /* 22/XII-2003 */
+         /* if the auxiliary variable x[i] is non-fixed, include its
+            element (placed in the i-th column) in the pattern */
+         lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
+         if (typx != LPX_FX) ndx[++len] = i;
+         /* include in the pattern elements placed in columns, which
+            correspond to non-fixed structural varables */
+         i_beg = aa_ptr[i];
+         i_end = i_beg + aa_len[i] - 1;
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         {  j = m + sv_ndx[i_ptr];
+            lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
+            if (typx != LPX_FX) ndx[++len] = j;
+         }
+#else
+         lll = lpx_get_mat_row(lp, i, ndx, NULL);
+         for (k = 1; k <= lll; k++)
+         {  lpx_get_col_bnds(lp, ndx[k], &typx, NULL, NULL);
+            if (typx != LPX_FX) ndx[++len] = m + ndx[k];
+         }
+         lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
+         if (typx != LPX_FX) ndx[++len] = i;
+#endif
+      }
+      else
+      {  /* the pattern of the j-th column is required */
+         j = -k;
+         xassert(1 <= j && j <= m+n);
+         /* if the (auxiliary or structural) variable x[j] is fixed,
+            the pattern of its column is empty */
+         if (j <= m)
+            lpx_get_row_bnds(lp, j, &typx, NULL, NULL);
+         else
+            lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
+         if (typx != LPX_FX)
+         {  if (j <= m)
+            {  /* x[j] is non-fixed auxiliary variable */
+               ndx[++len] = j;
+            }
+            else
+            {  /* x[j] is non-fixed structural variables */
+#if 0 /* 22/XII-2003 */
+               j_beg = aa_ptr[j];
+               j_end = j_beg + aa_len[j] - 1;
+               for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+                  ndx[++len] = sv_ndx[j_ptr];
+#else
+               len = lpx_get_mat_col(lp, j-m, ndx, NULL);
+#endif
+            }
+         }
+      }
+      /* return the length of the row/column pattern */
+      return len;
+}
+
+static void adv_basis(glp_prob *lp)
+{     int m = lpx_get_num_rows(lp);
+      int n = lpx_get_num_cols(lp);
+      int i, j, jj, k, size;
+      int *rn, *cn, *rn_inv, *cn_inv;
+      int typx, *tagx = xcalloc(1+m+n, sizeof(int));
+      double lb, ub;
+      xprintf("Constructing initial basis...\n");
+#if 0 /* 13/V-2009 */
+      if (m == 0)
+         xerror("glp_adv_basis: problem has no rows\n");
+      if (n == 0)
+         xerror("glp_adv_basis: problem has no columns\n");
+#else
+      if (m == 0 || n == 0)
+      {  glp_std_basis(lp);
+         return;
+      }
+#endif
+      /* use the routine triang (see above) to find maximal triangular
+         part of the augmented constraint matrix A~ = (I|-A); in order
+         to prevent columns of fixed variables to be included in the
+         triangular part, such columns are implictly removed from the
+         matrix A~ by the routine adv_mat */
+      rn = xcalloc(1+m, sizeof(int));
+      cn = xcalloc(1+m+n, sizeof(int));
+      size = triang(m, m+n, lp, mat, rn, cn);
+      if (lpx_get_int_parm(lp, LPX_K_MSGLEV) >= 3)
+         xprintf("Size of triangular part = %d\n", size);
+      /* the first size rows and columns of the matrix P*A~*Q (where
+         P and Q are permutation matrices defined by the arrays rn and
+         cn) form a lower triangular matrix; build the arrays (rn_inv
+         and cn_inv), which define the matrices inv(P) and inv(Q) */
+      rn_inv = xcalloc(1+m, sizeof(int));
+      cn_inv = xcalloc(1+m+n, sizeof(int));
+      for (i = 1; i <= m; i++) rn_inv[rn[i]] = i;
+      for (j = 1; j <= m+n; j++) cn_inv[cn[j]] = j;
+      /* include the columns of the matrix A~, which correspond to the
+         first size columns of the matrix P*A~*Q, in the basis */
+      for (k = 1; k <= m+n; k++) tagx[k] = -1;
+      for (jj = 1; jj <= size; jj++)
+      {  j = cn_inv[jj];
+         /* the j-th column of A~ is the jj-th column of P*A~*Q */
+         tagx[j] = LPX_BS;
+      }
+      /* if size < m, we need to add appropriate columns of auxiliary
+         variables to the basis */
+      for (jj = size + 1; jj <= m; jj++)
+      {  /* the jj-th column of P*A~*Q should be replaced by the column
+            of the auxiliary variable, for which the only unity element
+            is placed in the position [jj,jj] */
+         i = rn_inv[jj];
+         /* the jj-th row of P*A~*Q is the i-th row of A~, but in the
+            i-th row of A~ the unity element belongs to the i-th column
+            of A~; therefore the disired column corresponds to the i-th
+            auxiliary variable (note that this column doesn't belong to
+            the triangular part found by the routine triang) */
+         xassert(1 <= i && i <= m);
+         xassert(cn[i] > size);
+         tagx[i] = LPX_BS;
+      }
+      /* free working arrays */
+      xfree(rn);
+      xfree(cn);
+      xfree(rn_inv);
+      xfree(cn_inv);
+      /* build tags of non-basic variables */
+      for (k = 1; k <= m+n; k++)
+      {  if (tagx[k] != LPX_BS)
+         {  if (k <= m)
+               lpx_get_row_bnds(lp, k, &typx, &lb, &ub);
+            else
+               lpx_get_col_bnds(lp, k-m, &typx, &lb, &ub);
+            switch (typx)
+            {  case LPX_FR:
+                  tagx[k] = LPX_NF; break;
+               case LPX_LO:
+                  tagx[k] = LPX_NL; break;
+               case LPX_UP:
+                  tagx[k] = LPX_NU; break;
+               case LPX_DB:
+                  tagx[k] =
+                     (fabs(lb) <= fabs(ub) ? LPX_NL : LPX_NU);
+                  break;
+               case LPX_FX:
+                  tagx[k] = LPX_NS; break;
+               default:
+                  xassert(typx != typx);
+            }
+         }
+      }
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+            lpx_set_row_stat(lp, k, tagx[k]);
+         else
+            lpx_set_col_stat(lp, k-m, tagx[k]);
+      }
+      xfree(tagx);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_adv_basis - construct advanced initial LP basis
+*
+*  SYNOPSIS
+*
+*  void glp_adv_basis(glp_prob *lp, int flags);
+*
+*  DESCRIPTION
+*
+*  The routine glp_adv_basis constructs an advanced initial basis for
+*  the specified problem object.
+*
+*  The parameter flags is reserved for use in the future and must be
+*  specified as zero. */
+
+void glp_adv_basis(glp_prob *lp, int flags)
+{     if (flags != 0)
+         xerror("glp_adv_basis: flags = %d; invalid flags\n", flags);
+      if (lp->m == 0 || lp->n == 0)
+         glp_std_basis(lp);
+      else
+         adv_basis(lp);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpini02.c b/optional/glpk/glpini02.c
new file mode 100644
index 0000000..1efc72c
--- /dev/null
+++ b/optional/glpk/glpini02.c
@@ -0,0 +1,273 @@
+/* glpini02.c */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpapi.h"
+
+struct var
+{     /* structural variable */
+      int j;
+      /* ordinal number */
+      double q;
+      /* penalty value */
+};
+
+static int fcmp(const void *ptr1, const void *ptr2)
+{     /* this routine is passed to the qsort() function */
+      struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2;
+      if (col1->q < col2->q) return -1;
+      if (col1->q > col2->q) return +1;
+      return 0;
+}
+
+static int get_column(glp_prob *lp, int j, int ind[], double val[])
+{     /* Bixby's algorithm assumes that the constraint matrix is scaled
+         such that the maximum absolute value in every non-zero row and
+         column is 1 */
+      int k, len;
+      double big;
+      len = glp_get_mat_col(lp, j, ind, val);
+      big = 0.0;
+      for (k = 1; k <= len; k++)
+         if (big < fabs(val[k])) big = fabs(val[k]);
+      if (big == 0.0) big = 1.0;
+      for (k = 1; k <= len; k++) val[k] /= big;
+      return len;
+}
+
+static void cpx_basis(glp_prob *lp)
+{     /* main routine */
+      struct var *C, *C2, *C3, *C4;
+      int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r,
+         *ind;
+      double alpha, gamma, cmax, temp, *v, *val;
+      xprintf("Constructing initial basis...\n");
+      /* determine the number of rows and columns */
+      m = glp_get_num_rows(lp);
+      n = glp_get_num_cols(lp);
+      /* allocate working arrays */
+      C = xcalloc(1+n, sizeof(struct var));
+      I = xcalloc(1+m, sizeof(int));
+      r = xcalloc(1+m, sizeof(int));
+      v = xcalloc(1+m, sizeof(double));
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      /* make all auxiliary variables non-basic */
+      for (i = 1; i <= m; i++)
+      {  if (glp_get_row_type(lp, i) != GLP_DB)
+            glp_set_row_stat(lp, i, GLP_NS);
+         else if (fabs(glp_get_row_lb(lp, i)) <=
+                  fabs(glp_get_row_ub(lp, i)))
+            glp_set_row_stat(lp, i, GLP_NL);
+         else
+            glp_set_row_stat(lp, i, GLP_NU);
+      }
+      /* make all structural variables non-basic */
+      for (j = 1; j <= n; j++)
+      {  if (glp_get_col_type(lp, j) != GLP_DB)
+            glp_set_col_stat(lp, j, GLP_NS);
+         else if (fabs(glp_get_col_lb(lp, j)) <=
+                  fabs(glp_get_col_ub(lp, j)))
+            glp_set_col_stat(lp, j, GLP_NL);
+         else
+            glp_set_col_stat(lp, j, GLP_NU);
+      }
+      /* C2 is a set of free structural variables */
+      n2 = 0, C2 = C + 0;
+      for (j = 1; j <= n; j++)
+      {  type = glp_get_col_type(lp, j);
+         if (type == GLP_FR)
+         {  n2++;
+            C2[n2].j = j;
+            C2[n2].q = 0.0;
+         }
+      }
+      /* C3 is a set of structural variables having excatly one (lower
+         or upper) bound */
+      n3 = 0, C3 = C2 + n2;
+      for (j = 1; j <= n; j++)
+      {  type = glp_get_col_type(lp, j);
+         if (type == GLP_LO)
+         {  n3++;
+            C3[n3].j = j;
+            C3[n3].q = + glp_get_col_lb(lp, j);
+         }
+         else if (type == GLP_UP)
+         {  n3++;
+            C3[n3].j = j;
+            C3[n3].q = - glp_get_col_ub(lp, j);
+         }
+      }
+      /* C4 is a set of structural variables having both (lower and
+         upper) bounds */
+      n4 = 0, C4 = C3 + n3;
+      for (j = 1; j <= n; j++)
+      {  type = glp_get_col_type(lp, j);
+         if (type == GLP_DB)
+         {  n4++;
+            C4[n4].j = j;
+            C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j);
+         }
+      }
+      /* compute gamma = max{|c[j]|: 1 <= j <= n} */
+      gamma = 0.0;
+      for (j = 1; j <= n; j++)
+      {  temp = fabs(glp_get_obj_coef(lp, j));
+         if (gamma < temp) gamma = temp;
+      }
+      /* compute cmax */
+      cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma);
+      /* compute final penalty for all structural variables within sets
+         C2, C3, and C4 */
+      switch (glp_get_obj_dir(lp))
+      {  case GLP_MIN: temp = +1.0; break;
+         case GLP_MAX: temp = -1.0; break;
+         default: xassert(lp != lp);
+      }
+      for (k = 1; k <= n2+n3+n4; k++)
+      {  j = C[k].j;
+         C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax;
+      }
+      /* sort structural variables within C2, C3, and C4 in ascending
+         order of penalty value */
+      qsort(C2+1, n2, sizeof(struct var), fcmp);
+      for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q);
+      qsort(C3+1, n3, sizeof(struct var), fcmp);
+      for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q);
+      qsort(C4+1, n4, sizeof(struct var), fcmp);
+      for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q);
+      /*** STEP 1 ***/
+      for (i = 1; i <= m; i++)
+      {  type = glp_get_row_type(lp, i);
+         if (type != GLP_FX)
+         {  /* row i is either free or inequality constraint */
+            glp_set_row_stat(lp, i, GLP_BS);
+            I[i] = 1;
+            r[i] = 1;
+         }
+         else
+         {  /* row i is equality constraint */
+            I[i] = 0;
+            r[i] = 0;
+         }
+         v[i] = +DBL_MAX;
+      }
+      /*** STEP 2 ***/
+      for (k = 1; k <= n2+n3+n4; k++)
+      {  jk = C[k].j;
+         len = get_column(lp, jk, ind, val);
+         /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such
+            that alpha = |A[l',jk]| */
+         alpha = 0.0, ll = 0;
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (r[l] == 0 && alpha < fabs(val[t]))
+               alpha = fabs(val[t]), ll = l;
+         }
+         if (alpha >= 0.99)
+         {  /* B := B union {jk} */
+            glp_set_col_stat(lp, jk, GLP_BS);
+            I[ll] = 1;
+            v[ll] = alpha;
+            /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
+            for (t = 1; t <= len; t++)
+            {  l = ind[t];
+               if (val[t] != 0.0) r[l]++;
+            }
+            /* continue to the next k */
+            continue;
+         }
+         /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the
+            next k */
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (fabs(val[t]) > 0.01 * v[l]) break;
+         }
+         if (t <= len) continue;
+         /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l'
+            be such that alpha = |A[l',jk]| */
+         alpha = 0.0, ll = 0;
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (I[l] == 0 && alpha < fabs(val[t]))
+               alpha = fabs(val[t]), ll = l;
+         }
+         /* if alpha = 0, continue to the next k */
+         if (alpha == 0.0) continue;
+         /* B := B union {jk} */
+         glp_set_col_stat(lp, jk, GLP_BS);
+         I[ll] = 1;
+         v[ll] = alpha;
+         /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (val[t] != 0.0) r[l]++;
+         }
+      }
+      /*** STEP 3 ***/
+      /* add an artificial variable (auxiliary variable for equality
+         constraint) to cover each remaining uncovered row */
+      for (i = 1; i <= m; i++)
+         if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS);
+      /* free working arrays */
+      xfree(C);
+      xfree(I);
+      xfree(r);
+      xfree(v);
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_cpx_basis - construct Bixby's initial LP basis
+*
+*  SYNOPSIS
+*
+*  void glp_cpx_basis(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_cpx_basis constructs an advanced initial basis for
+*  the specified problem object.
+*
+*  The routine is based on Bixby's algorithm described in the paper:
+*
+*  Robert E. Bixby. Implementing the Simplex Method: The Initial Basis.
+*  ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */
+
+void glp_cpx_basis(glp_prob *lp)
+{     if (lp->m == 0 || lp->n == 0)
+         glp_std_basis(lp);
+      else
+         cpx_basis(lp);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios.h b/optional/glpk/glpios.h
new file mode 100644
index 0000000..3288faa
--- /dev/null
+++ b/optional/glpk/glpios.h
@@ -0,0 +1,593 @@
+/* glpios.h (integer optimization suite) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPIOS_H
+#define GLPIOS_H
+
+#define GLP_TREE_DEFINED
+typedef struct glp_tree glp_tree;
+
+#include "glpapi.h"
+
+typedef struct IOSLOT IOSLOT;
+typedef struct IOSNPD IOSNPD;
+typedef struct IOSBND IOSBND;
+typedef struct IOSTAT IOSTAT;
+typedef struct IOSROW IOSROW;
+typedef struct IOSAIJ IOSAIJ;
+typedef struct IOSPOOL IOSPOOL;
+typedef struct IOSCUT IOSCUT;
+
+struct glp_tree
+{     /* branch-and-bound tree */
+      int magic;
+      /* magic value used for debugging */
+      DMP *pool;
+      /* memory pool to store all IOS components */
+      int n;
+      /* number of columns (variables) */
+      /*--------------------------------------------------------------*/
+      /* problem components corresponding to the original MIP and its
+         LP relaxation (used to restore the original problem object on
+         exit from the solver) */
+      int orig_m;
+      /* number of rows */
+      unsigned char *orig_type; /* uchar orig_type[1+orig_m+n]; */
+      /* types of all variables */
+      double *orig_lb; /* double orig_lb[1+orig_m+n]; */
+      /* lower bounds of all variables */
+      double *orig_ub; /* double orig_ub[1+orig_m+n]; */
+      /* upper bounds of all variables */
+      unsigned char *orig_stat; /* uchar orig_stat[1+orig_m+n]; */
+      /* statuses of all variables */
+      double *orig_prim; /* double orig_prim[1+orig_m+n]; */
+      /* primal values of all variables */
+      double *orig_dual; /* double orig_dual[1+orig_m+n]; */
+      /* dual values of all variables */
+      double orig_obj;
+      /* optimal objective value for LP relaxation */
+      /*--------------------------------------------------------------*/
+      /* branch-and-bound tree */
+      int nslots;
+      /* length of the array of slots (enlarged automatically) */
+      int avail;
+      /* index of the first free slot; 0 means all slots are in use */
+      IOSLOT *slot; /* IOSLOT slot[1+nslots]; */
+      /* array of slots:
+         slot[0] is not used;
+         slot[p], 1 <= p <= nslots, either contains a pointer to some
+         node of the branch-and-bound tree, in which case p is used on
+         API level as the reference number of corresponding subproblem,
+         or is free; all free slots are linked into single linked list;
+         slot[1] always contains a pointer to the root node (it is free
+         only if the tree is empty) */
+      IOSNPD *head;
+      /* pointer to the head of the active list */
+      IOSNPD *tail;
+      /* pointer to the tail of the active list */
+      /* the active list is a doubly linked list of active subproblems
+         which correspond to leaves of the tree; all subproblems in the
+         active list are ordered chronologically (each a new subproblem
+         is always added to the tail of the list) */
+      int a_cnt;
+      /* current number of active nodes (including the current one) */
+      int n_cnt;
+      /* current number of all (active and inactive) nodes */
+      int t_cnt;
+      /* total number of nodes including those which have been already
+         removed from the tree; this count is increased by one whenever
+         a new node is created and never decreased */
+      /*--------------------------------------------------------------*/
+      /* problem components corresponding to the root subproblem */
+      int root_m;
+      /* number of rows */
+      unsigned char *root_type; /* uchar root_type[1+root_m+n]; */
+      /* types of all variables */
+      double *root_lb; /* double root_lb[1+root_m+n]; */
+      /* lower bounds of all variables */
+      double *root_ub; /* double root_ub[1+root_m+n]; */
+      /* upper bounds of all variables */
+      unsigned char *root_stat; /* uchar root_stat[1+root_m+n]; */
+      /* statuses of all variables */
+      /*--------------------------------------------------------------*/
+      /* current subproblem and its LP relaxation */
+      IOSNPD *curr;
+      /* pointer to the current subproblem (which can be only active);
+         NULL means the current subproblem does not exist */
+      glp_prob *mip;
+      /* original problem object passed to the solver; if the current
+         subproblem exists, its LP segment corresponds to LP relaxation
+         of the current subproblem; if the current subproblem does not
+         exist, its LP segment corresponds to LP relaxation of the root
+         subproblem (note that the root subproblem may differ from the
+         original MIP, because it may be preprocessed and/or may have
+         additional rows) */
+      unsigned char *non_int; /* uchar non_int[1+n]; */
+      /* these column flags are set each time when LP relaxation of the
+         current subproblem has been solved;
+         non_int[0] is not used;
+         non_int[j], 1 <= j <= n, is j-th column flag; if this flag is
+         set, corresponding variable is required to be integer, but its
+         value in basic solution is fractional */
+      /*--------------------------------------------------------------*/
+      /* problem components corresponding to the parent (predecessor)
+         subproblem for the current subproblem; used to inspect changes
+         on freezing the current subproblem */
+      int pred_m;
+      /* number of rows */
+      int pred_max;
+      /* length of the following four arrays (enlarged automatically),
+         pred_max >= pred_m + n */
+      unsigned char *pred_type; /* uchar pred_type[1+pred_m+n]; */
+      /* types of all variables */
+      double *pred_lb; /* double pred_lb[1+pred_m+n]; */
+      /* lower bounds of all variables */
+      double *pred_ub; /* double pred_ub[1+pred_m+n]; */
+      /* upper bounds of all variables */
+      unsigned char *pred_stat; /* uchar pred_stat[1+pred_m+n]; */
+      /* statuses of all variables */
+      /****************************************************************/
+      /* built-in cut generators segment */
+      IOSPOOL *local;
+      /* local cut pool */
+      void *mir_gen;
+      /* pointer to working area used by the MIR cut generator */
+      void *clq_gen;
+      /* pointer to working area used by the clique cut generator */
+      /*--------------------------------------------------------------*/
+      void *pcost;
+      /* pointer to working area used on pseudocost branching */
+      int *iwrk; /* int iwrk[1+n]; */
+      /* working array */
+      double *dwrk; /* double dwrk[1+n]; */
+      /* working array */
+      /*--------------------------------------------------------------*/
+      /* control parameters and statistics */
+      const glp_iocp *parm;
+      /* copy of control parameters passed to the solver */
+      glp_long tm_beg;
+      /* starting time of the search, in seconds; the total time of the
+         search is the difference between xtime() and tm_beg */
+      glp_long tm_lag;
+      /* the most recent time, in seconds, at which the progress of the
+         the search was displayed */
+      int sol_cnt;
+      /* number of integer feasible solutions found */
+      /*--------------------------------------------------------------*/
+      /* advanced solver interface */
+      int reason;
+      /* flag indicating the reason why the callback routine is being
+         called (see glpk.h) */
+      int stop;
+      /* flag indicating that the callback routine requires premature
+         termination of the search */
+      int next_p;
+      /* reference number of active subproblem selected to continue
+         the search; 0 means no subproblem has been selected */
+      int reopt;
+      /* flag indicating that the current LP relaxation needs to be
+         re-optimized */
+      int reinv;
+      /* flag indicating that some (non-active) rows were removed from
+         the current LP relaxation, so if there no new rows appear, the
+         basis must be re-factorized */
+      int br_var;
+      /* the number of variable chosen to branch on */
+      int br_sel;
+      /* flag indicating which branch (subproblem) is suggested to be
+         selected to continue the search:
+         GLP_DN_BRNCH - select down-branch
+         GLP_UP_BRNCH - select up-branch
+         GLP_NO_BRNCH - use general selection technique */
+      int child;
+      /* subproblem reference number corresponding to br_sel */
+};
+
+struct IOSLOT
+{     /* node subproblem slot */
+      IOSNPD *node;
+      /* pointer to subproblem descriptor; NULL means free slot */
+      int next;
+      /* index of another free slot (only if this slot is free) */
+};
+
+struct IOSNPD
+{     /* node subproblem descriptor */
+      int p;
+      /* subproblem reference number (it is the index to corresponding
+         slot, i.e. slot[p] points to this descriptor) */
+      IOSNPD *up;
+      /* pointer to the parent subproblem; NULL means this node is the
+         root of the tree, in which case p = 1 */
+      int level;
+      /* node level (the root node has level 0) */
+      int count;
+      /* if count = 0, this subproblem is active; if count > 0, this
+         subproblem is inactive, in which case count is the number of
+         its child subproblems */
+      /* the following three linked lists are destroyed on reviving and
+         built anew on freezing the subproblem: */
+      IOSBND *b_ptr;
+      /* linked list of rows and columns of the parent subproblem whose
+         types and bounds were changed */
+      IOSTAT *s_ptr;
+      /* linked list of rows and columns of the parent subproblem whose
+         statuses were changed */
+      IOSROW *r_ptr;
+      /* linked list of rows (cuts) added to the parent subproblem */
+      int solved;
+      /* how many times LP relaxation of this subproblem was solved;
+         for inactive subproblem this count is always non-zero;
+         for active subproblem, which is not current, this count may be
+         non-zero, if the subproblem was temporarily suspended */
+      double lp_obj;
+      /* optimal objective value to LP relaxation of this subproblem;
+         on creating a subproblem this value is inherited from its
+         parent; for the root subproblem, which has no parent, this
+         value is initially set to -DBL_MAX (minimization) or +DBL_MAX
+         (maximization); each time the subproblem is re-optimized, this
+         value is appropriately changed */
+      double bound;
+      /* local lower (minimization) or upper (maximization) bound for
+         integer optimal solution to *this* subproblem; this bound is
+         local in the sense that only subproblems in the subtree rooted
+         at this node cannot have better integer feasible solutions;
+         on creating a subproblem its local bound is inherited from its
+         parent and then can be made stronger (never weaker); for the
+         root subproblem its local bound is initially set to -DBL_MAX
+         (minimization) or +DBL_MAX (maximization) and then improved as
+         the root LP relaxation has been solved */
+      /* the following two quantities are defined only if LP relaxation
+         of this subproblem was solved at least once (solved > 0): */
+      int ii_cnt;
+      /* number of integer variables whose value in optimal solution to
+         LP relaxation of this subproblem is fractional */
+      double ii_sum;
+      /* sum of integer infeasibilities */
+#if 1 /* 30/XI-2009 */
+      int changed;
+      /* how many times this subproblem was re-formulated (by adding
+         cutting plane constraints) */
+#endif
+      int br_var;
+      /* ordinal number of branching variable, 1 <= br_var <= n, used
+         to split this subproblem; 0 means that either this subproblem
+         is active or branching was made on a constraint */
+      double br_val;
+      /* (fractional) value of branching variable in optimal solution
+         to final LP relaxation of this subproblem */
+      void *data; /* char data[tree->cb_size]; */
+      /* pointer to the application-specific data */
+      IOSNPD *temp;
+      /* working pointer used by some routines */
+      IOSNPD *prev;
+      /* pointer to previous subproblem in the active list */
+      IOSNPD *next;
+      /* pointer to next subproblem in the active list */
+};
+
+struct IOSBND
+{     /* bounds change entry */
+      int k;
+      /* ordinal number of corresponding row (1 <= k <= m) or column
+         (m+1 <= k <= m+n), where m and n are the number of rows and
+         columns, resp., in the parent subproblem */
+      unsigned char type;
+      /* new type */
+      double lb;
+      /* new lower bound */
+      double ub;
+      /* new upper bound */
+      IOSBND *next;
+      /* pointer to next entry for the same subproblem */
+};
+
+struct IOSTAT
+{     /* status change entry */
+      int k;
+      /* ordinal number of corresponding row (1 <= k <= m) or column
+         (m+1 <= k <= m+n), where m and n are the number of rows and
+         columns, resp., in the parent subproblem */
+      unsigned char stat;
+      /* new status */
+      IOSTAT *next;
+      /* pointer to next entry for the same subproblem */
+};
+
+struct IOSROW
+{     /* row (constraint) addition entry */
+      char *name;
+      /* row name or NULL */
+      unsigned char origin;
+      /* row origin flag (see glp_attr.origin) */
+      unsigned char klass;
+      /* row class descriptor (see glp_attr.klass) */
+      unsigned char type;
+      /* row type (GLP_LO, GLP_UP, etc.) */
+      double lb;
+      /* row lower bound */
+      double ub;
+      /* row upper bound */
+      IOSAIJ *ptr;
+      /* pointer to the row coefficient list */
+      double rii;
+      /* row scale factor */
+      unsigned char stat;
+      /* row status (GLP_BS, GLP_NL, etc.) */
+      IOSROW *next;
+      /* pointer to next entry for the same subproblem */
+};
+
+struct IOSAIJ
+{     /* constraint coefficient */
+      int j;
+      /* variable (column) number, 1 <= j <= n */
+      double val;
+      /* non-zero coefficient value */
+      IOSAIJ *next;
+      /* pointer to next coefficient for the same row */
+};
+
+struct IOSPOOL
+{     /* cut pool */
+      int size;
+      /* pool size = number of cuts in the pool */
+      IOSCUT *head;
+      /* pointer to the first cut */
+      IOSCUT *tail;
+      /* pointer to the last cut */
+      int ord;
+      /* ordinal number of the current cut, 1 <= ord <= size */
+      IOSCUT *curr;
+      /* pointer to the current cut */
+};
+
+struct IOSCUT
+{     /* cut (cutting plane constraint) */
+      char *name;
+      /* cut name or NULL */
+      unsigned char klass;
+      /* cut class descriptor (see glp_attr.klass) */
+      IOSAIJ *ptr;
+      /* pointer to the cut coefficient list */
+      unsigned char type;
+      /* cut type:
+         GLP_LO: sum a[j] * x[j] >= b
+         GLP_UP: sum a[j] * x[j] <= b
+         GLP_FX: sum a[j] * x[j]  = b */
+      double rhs;
+      /* cut right-hand side */
+      IOSCUT *prev;
+      /* pointer to previous cut */
+      IOSCUT *next;
+      /* pointer to next cut */
+};
+
+#define ios_create_tree _glp_ios_create_tree
+glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
+/* create branch-and-bound tree */
+
+#define ios_revive_node _glp_ios_revive_node
+void ios_revive_node(glp_tree *tree, int p);
+/* revive specified subproblem */
+
+#define ios_freeze_node _glp_ios_freeze_node
+void ios_freeze_node(glp_tree *tree);
+/* freeze current subproblem */
+
+#define ios_clone_node _glp_ios_clone_node
+void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
+/* clone specified subproblem */
+
+#define ios_delete_node _glp_ios_delete_node
+void ios_delete_node(glp_tree *tree, int p);
+/* delete specified subproblem */
+
+#define ios_delete_tree _glp_ios_delete_tree
+void ios_delete_tree(glp_tree *tree);
+/* delete branch-and-bound tree */
+
+#define ios_eval_degrad _glp_ios_eval_degrad
+void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
+/* estimate obj. degrad. for down- and up-branches */
+
+#define ios_round_bound _glp_ios_round_bound
+double ios_round_bound(glp_tree *tree, double bound);
+/* improve local bound by rounding */
+
+#define ios_is_hopeful _glp_ios_is_hopeful
+int ios_is_hopeful(glp_tree *tree, double bound);
+/* check if subproblem is hopeful */
+
+#define ios_best_node _glp_ios_best_node
+int ios_best_node(glp_tree *tree);
+/* find active node with best local bound */
+
+#define ios_relative_gap _glp_ios_relative_gap
+double ios_relative_gap(glp_tree *tree);
+/* compute relative mip gap */
+
+#define ios_solve_node _glp_ios_solve_node
+int ios_solve_node(glp_tree *tree);
+/* solve LP relaxation of current subproblem */
+
+#define ios_create_pool _glp_ios_create_pool
+IOSPOOL *ios_create_pool(glp_tree *tree);
+/* create cut pool */
+
+#define ios_add_row _glp_ios_add_row
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs);
+/* add row (constraint) to the cut pool */
+
+#define ios_find_row _glp_ios_find_row
+IOSCUT *ios_find_row(IOSPOOL *pool, int i);
+/* find row (constraint) in the cut pool */
+
+#define ios_del_row _glp_ios_del_row
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i);
+/* remove row (constraint) from the cut pool */
+
+#define ios_clear_pool _glp_ios_clear_pool
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool);
+/* remove all rows (constraints) from the cut pool */
+
+#define ios_delete_pool _glp_ios_delete_pool
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool);
+/* delete cut pool */
+
+#define ios_preprocess_node _glp_ios_preprocess_node
+int ios_preprocess_node(glp_tree *tree, int max_pass);
+/* preprocess current subproblem */
+
+#define ios_driver _glp_ios_driver
+int ios_driver(glp_tree *tree);
+/* branch-and-bound driver */
+
+/**********************************************************************/
+
+typedef struct IOSVEC IOSVEC;
+
+struct IOSVEC
+{     /* sparse vector v = (v[j]) */
+      int n;
+      /* dimension, n >= 0 */
+      int nnz;
+      /* number of non-zero components, 0 <= nnz <= n */
+      int *pos; /* int pos[1+n]; */
+      /* pos[j] = k, 1 <= j <= n, is position of (non-zero) v[j] in the
+         arrays ind and val, where 1 <= k <= nnz; pos[j] = 0 means that
+         v[j] is structural zero */
+      int *ind; /* int ind[1+n]; */
+      /* ind[k] = j, 1 <= k <= nnz, is index of v[j] */
+      double *val; /* double val[1+n]; */
+      /* val[k], 1 <= k <= nnz, is a numeric value of v[j] */
+};
+
+#define ios_create_vec _glp_ios_create_vec
+IOSVEC *ios_create_vec(int n);
+/* create sparse vector */
+
+#define ios_check_vec _glp_ios_check_vec
+void ios_check_vec(IOSVEC *v);
+/* check that sparse vector has correct representation */
+
+#define ios_get_vj _glp_ios_get_vj
+double ios_get_vj(IOSVEC *v, int j);
+/* retrieve component of sparse vector */
+
+#define ios_set_vj _glp_ios_set_vj
+void ios_set_vj(IOSVEC *v, int j, double val);
+/* set/change component of sparse vector */
+
+#define ios_clear_vec _glp_ios_clear_vec
+void ios_clear_vec(IOSVEC *v);
+/* set all components of sparse vector to zero */
+
+#define ios_clean_vec _glp_ios_clean_vec
+void ios_clean_vec(IOSVEC *v, double eps);
+/* remove zero or small components from sparse vector */
+
+#define ios_copy_vec _glp_ios_copy_vec
+void ios_copy_vec(IOSVEC *x, IOSVEC *y);
+/* copy sparse vector (x := y) */
+
+#define ios_linear_comb _glp_ios_linear_comb
+void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
+/* compute linear combination (x := x + a * y) */
+
+#define ios_delete_vec _glp_ios_delete_vec
+void ios_delete_vec(IOSVEC *v);
+/* delete sparse vector */
+
+/**********************************************************************/
+
+#define ios_gmi_gen _glp_ios_gmi_gen
+void ios_gmi_gen(glp_tree *tree);
+/* generate Gomory's mixed integer cuts */
+
+#define ios_mir_init _glp_ios_mir_init
+void *ios_mir_init(glp_tree *tree);
+/* initialize MIR cut generator */
+
+#define ios_mir_gen _glp_ios_mir_gen
+void ios_mir_gen(glp_tree *tree, void *gen);
+/* generate MIR cuts */
+
+#define ios_mir_term _glp_ios_mir_term
+void ios_mir_term(void *gen);
+/* terminate MIR cut generator */
+
+#define ios_cov_gen _glp_ios_cov_gen
+void ios_cov_gen(glp_tree *tree);
+/* generate mixed cover cuts */
+
+#define ios_clq_init _glp_ios_clq_init
+void *ios_clq_init(glp_tree *tree);
+/* initialize clique cut generator */
+
+#define ios_clq_gen _glp_ios_clq_gen
+void ios_clq_gen(glp_tree *tree, void *gen);
+/* generate clique cuts */
+
+#define ios_clq_term _glp_ios_clq_term
+void ios_clq_term(void *gen);
+/* terminate clique cut generator */
+
+#define ios_pcost_init _glp_ios_pcost_init
+void *ios_pcost_init(glp_tree *tree);
+/* initialize working data used on pseudocost branching */
+
+#define ios_pcost_branch _glp_ios_pcost_branch
+int ios_pcost_branch(glp_tree *T, int *next);
+/* choose branching variable with pseudocost branching */
+
+#define ios_pcost_update _glp_ios_pcost_update
+void ios_pcost_update(glp_tree *tree);
+/* update history information for pseudocost branching */
+
+#define ios_pcost_free _glp_ios_pcost_free
+void ios_pcost_free(glp_tree *tree);
+/* free working area used on pseudocost branching */
+
+#define ios_feas_pump _glp_ios_feas_pump
+void ios_feas_pump(glp_tree *T);
+/* feasibility pump heuristic */
+
+#define ios_process_cuts _glp_ios_process_cuts
+void ios_process_cuts(glp_tree *T);
+/* process cuts stored in the local cut pool */
+
+#define ios_choose_node _glp_ios_choose_node
+int ios_choose_node(glp_tree *T);
+/* select subproblem to continue the search */
+
+#define ios_choose_var _glp_ios_choose_var
+int ios_choose_var(glp_tree *T, int *next);
+/* select variable to branch on */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpios01.c b/optional/glpk/glpios01.c
new file mode 100644
index 0000000..3bfacfb
--- /dev/null
+++ b/optional/glpk/glpios01.c
@@ -0,0 +1,1618 @@
+/* glpios01.c */
+
+/***********************************************************************
+*  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 "-Wself-assign"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_create_tree - create branch-and-bound tree
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine ios_create_tree creates the branch-and-bound tree.
+*
+*  Being created the tree consists of the only root subproblem whose
+*  reference number is 1. Note that initially the root subproblem is in
+*  frozen state and therefore needs to be revived.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the tree created. */
+
+static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent);
+
+glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm)
+{     int m = mip->m;
+      int n = mip->n;
+      glp_tree *tree;
+      int i, j;
+      xassert(mip->tree == NULL);
+      mip->tree = tree = xmalloc(sizeof(glp_tree));
+      tree->pool = dmp_create_pool();
+      tree->n = n;
+      /* save original problem components */
+      tree->orig_m = m;
+      tree->orig_type = xcalloc(1+m+n, sizeof(char));
+      tree->orig_lb = xcalloc(1+m+n, sizeof(double));
+      tree->orig_ub = xcalloc(1+m+n, sizeof(double));
+      tree->orig_stat = xcalloc(1+m+n, sizeof(char));
+      tree->orig_prim = xcalloc(1+m+n, sizeof(double));
+      tree->orig_dual = xcalloc(1+m+n, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = mip->row[i];
+         tree->orig_type[i] = (char)row->type;
+         tree->orig_lb[i] = row->lb;
+         tree->orig_ub[i] = row->ub;
+         tree->orig_stat[i] = (char)row->stat;
+         tree->orig_prim[i] = row->prim;
+         tree->orig_dual[i] = row->dual;
+      }
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         tree->orig_type[m+j] = (char)col->type;
+         tree->orig_lb[m+j] = col->lb;
+         tree->orig_ub[m+j] = col->ub;
+         tree->orig_stat[m+j] = (char)col->stat;
+         tree->orig_prim[m+j] = col->prim;
+         tree->orig_dual[m+j] = col->dual;
+      }
+      tree->orig_obj = mip->obj_val;
+      /* initialize the branch-and-bound tree */
+      tree->nslots = 0;
+      tree->avail = 0;
+      tree->slot = NULL;
+      tree->head = tree->tail = NULL;
+      tree->a_cnt = tree->n_cnt = tree->t_cnt = 0;
+      /* the root subproblem is not solved yet, so its final components
+         are unknown so far */
+      tree->root_m = 0;
+      tree->root_type = NULL;
+      tree->root_lb = tree->root_ub = NULL;
+      tree->root_stat = NULL;
+      /* the current subproblem does not exist yet */
+      tree->curr = NULL;
+      tree->mip = mip;
+      /*tree->solved = 0;*/
+      tree->non_int = xcalloc(1+n, sizeof(char));
+      memset(&tree->non_int[1], 0, n);
+      /* arrays to save parent subproblem components will be allocated
+         later */
+      tree->pred_m = tree->pred_max = 0;
+      tree->pred_type = NULL;
+      tree->pred_lb = tree->pred_ub = NULL;
+      tree->pred_stat = NULL;
+      /* cut generator */
+      tree->local = ios_create_pool(tree);
+      /*tree->first_attempt = 1;*/
+      /*tree->max_added_cuts = 0;*/
+      /*tree->min_eff = 0.0;*/
+      /*tree->miss = 0;*/
+      /*tree->just_selected = 0;*/
+      tree->mir_gen = NULL;
+      tree->clq_gen = NULL;
+      /*tree->round = 0;*/
+#if 0
+      /* create the conflict graph */
+      tree->n_ref = xcalloc(1+n, sizeof(int));
+      memset(&tree->n_ref[1], 0, n * sizeof(int));
+      tree->c_ref = xcalloc(1+n, sizeof(int));
+      memset(&tree->c_ref[1], 0, n * sizeof(int));
+      tree->g = scg_create_graph(0);
+      tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int));
+#endif
+      /* pseudocost branching */
+      tree->pcost = NULL;
+      tree->iwrk = xcalloc(1+n, sizeof(int));
+      tree->dwrk = xcalloc(1+n, sizeof(double));
+      /* initialize control parameters */
+      tree->parm = parm;
+      tree->tm_beg = xtime();
+      tree->tm_lag = xlset(0);
+      tree->sol_cnt = 0;
+      /* initialize advanced solver interface */
+      tree->reason = 0;
+      tree->reopt = 0;
+      tree->reinv = 0;
+      tree->br_var = 0;
+      tree->br_sel = 0;
+      tree->child = 0;
+      tree->next_p = 0;
+      /*tree->btrack = NULL;*/
+      tree->stop = 0;
+      /* create the root subproblem, which initially is identical to
+         the original MIP */
+      new_node(tree, NULL);
+      return tree;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_revive_node - revive specified subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_revive_node(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine ios_revive_node revives the specified subproblem, whose
+*  reference number is p, and thereby makes it the current subproblem.
+*  Note that the specified subproblem must be active. Besides, if the
+*  current subproblem already exists, it must be frozen before reviving
+*  another subproblem. */
+
+void ios_revive_node(glp_tree *tree, int p)
+{     glp_prob *mip = tree->mip;
+      IOSNPD *node, *root;
+      /* obtain pointer to the specified subproblem */
+      xassert(1 <= p && p <= tree->nslots);
+      node = tree->slot[p].node;
+      xassert(node != NULL);
+      /* the specified subproblem must be active */
+      xassert(node->count == 0);
+      /* the current subproblem must not exist */
+      xassert(tree->curr == NULL);
+      /* the specified subproblem becomes current */
+      tree->curr = node;
+      /*tree->solved = 0;*/
+      /* obtain pointer to the root subproblem */
+      root = tree->slot[1].node;
+      xassert(root != NULL);
+      /* at this point problem object components correspond to the root
+         subproblem, so if the root subproblem should be revived, there
+         is nothing more to do */
+      if (node == root) goto done;
+      xassert(mip->m == tree->root_m);
+      /* build path from the root to the current node */
+      node->temp = NULL;
+      for (node = node; node != NULL; node = node->up)
+      {  if (node->up == NULL)
+            xassert(node == root);
+         else
+            node->up->temp = node;
+      }
+      /* go down from the root to the current node and make necessary
+         changes to restore components of the current subproblem */
+      for (node = root; node != NULL; node = node->temp)
+      {  int m = mip->m;
+         int n = mip->n;
+         /* if the current node is reached, the problem object at this
+            point corresponds to its parent, so save attributes of rows
+            and columns for the parent subproblem */
+         if (node->temp == NULL)
+         {  int i, j;
+            tree->pred_m = m;
+            /* allocate/reallocate arrays, if necessary */
+            if (tree->pred_max < m + n)
+            {  int new_size = m + n + 100;
+               if (tree->pred_type != NULL) xfree(tree->pred_type);
+               if (tree->pred_lb != NULL) xfree(tree->pred_lb);
+               if (tree->pred_ub != NULL) xfree(tree->pred_ub);
+               if (tree->pred_stat != NULL) xfree(tree->pred_stat);
+               tree->pred_max = new_size;
+               tree->pred_type = xcalloc(1+new_size, sizeof(char));
+               tree->pred_lb = xcalloc(1+new_size, sizeof(double));
+               tree->pred_ub = xcalloc(1+new_size, sizeof(double));
+               tree->pred_stat = xcalloc(1+new_size, sizeof(char));
+            }
+            /* save row attributes */
+            for (i = 1; i <= m; i++)
+            {  GLPROW *row = mip->row[i];
+               tree->pred_type[i] = (char)row->type;
+               tree->pred_lb[i] = row->lb;
+               tree->pred_ub[i] = row->ub;
+               tree->pred_stat[i] = (char)row->stat;
+            }
+            /* save column attributes */
+            for (j = 1; j <= n; j++)
+            {  GLPCOL *col = mip->col[j];
+               tree->pred_type[mip->m+j] = (char)col->type;
+               tree->pred_lb[mip->m+j] = col->lb;
+               tree->pred_ub[mip->m+j] = col->ub;
+               tree->pred_stat[mip->m+j] = (char)col->stat;
+            }
+         }
+         /* change bounds of rows and columns */
+         {  IOSBND *b;
+            for (b = node->b_ptr; b != NULL; b = b->next)
+            {  if (b->k <= m)
+                  glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub);
+               else
+                  glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub);
+            }
+         }
+         /* change statuses of rows and columns */
+         {  IOSTAT *s;
+            for (s = node->s_ptr; s != NULL; s = s->next)
+            {  if (s->k <= m)
+                  glp_set_row_stat(mip, s->k, s->stat);
+               else
+                  glp_set_col_stat(mip, s->k-m, s->stat);
+            }
+         }
+         /* add new rows */
+         if (node->r_ptr != NULL)
+         {  IOSROW *r;
+            IOSAIJ *a;
+            int i, len, *ind;
+            double *val;
+            ind = xcalloc(1+n, sizeof(int));
+            val = xcalloc(1+n, sizeof(double));
+            for (r = node->r_ptr; r != NULL; r = r->next)
+            {  i = glp_add_rows(mip, 1);
+               glp_set_row_name(mip, i, r->name);
+#if 1 /* 20/IX-2008 */
+               xassert(mip->row[i]->level == 0);
+               mip->row[i]->level = node->level;
+               mip->row[i]->origin = r->origin;
+               mip->row[i]->klass = r->klass;
+#endif
+               glp_set_row_bnds(mip, i, r->type, r->lb, r->ub);
+               len = 0;
+               for (a = r->ptr; a != NULL; a = a->next)
+                  len++, ind[len] = a->j, val[len] = a->val;
+               glp_set_mat_row(mip, i, len, ind, val);
+               glp_set_rii(mip, i, r->rii);
+               glp_set_row_stat(mip, i, r->stat);
+            }
+            xfree(ind);
+            xfree(val);
+         }
+#if 0
+         /* add new edges to the conflict graph */
+         /* add new cliques to the conflict graph */
+         /* (not implemented yet) */
+         xassert(node->own_nn == 0);
+         xassert(node->own_nc == 0);
+         xassert(node->e_ptr == NULL);
+#endif
+      }
+      /* the specified subproblem has been revived */
+      node = tree->curr;
+      /* delete its bound change list */
+      while (node->b_ptr != NULL)
+      {  IOSBND *b;
+         b = node->b_ptr;
+         node->b_ptr = b->next;
+         dmp_free_atom(tree->pool, b, sizeof(IOSBND));
+      }
+      /* delete its status change list */
+      while (node->s_ptr != NULL)
+      {  IOSTAT *s;
+         s = node->s_ptr;
+         node->s_ptr = s->next;
+         dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
+      }
+#if 1 /* 20/XI-2009 */
+      /* delete its row addition list (additional rows may appear, for
+         example, due to branching on GUB constraints */
+      while (node->r_ptr != NULL)
+      {  IOSROW *r;
+         r = node->r_ptr;
+         node->r_ptr = r->next;
+         xassert(r->name == NULL);
+         while (r->ptr != NULL)
+         {  IOSAIJ *a;
+            a = r->ptr;
+            r->ptr = a->next;
+            dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
+         }
+         dmp_free_atom(tree->pool, r, sizeof(IOSROW));
+      }
+#endif
+done: return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_freeze_node - freeze current subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_freeze_node(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_freeze_node freezes the current subproblem. */
+
+void ios_freeze_node(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      IOSNPD *node;
+      /* obtain pointer to the current subproblem */
+      node = tree->curr;
+      xassert(node != NULL);
+      if (node->up == NULL)
+      {  /* freeze the root subproblem */
+         int k;
+         xassert(node->p == 1);
+         xassert(tree->root_m == 0);
+         xassert(tree->root_type == NULL);
+         xassert(tree->root_lb == NULL);
+         xassert(tree->root_ub == NULL);
+         xassert(tree->root_stat == NULL);
+         tree->root_m = m;
+         tree->root_type = xcalloc(1+m+n, sizeof(char));
+         tree->root_lb = xcalloc(1+m+n, sizeof(double));
+         tree->root_ub = xcalloc(1+m+n, sizeof(double));
+         tree->root_stat = xcalloc(1+m+n, sizeof(char));
+         for (k = 1; k <= m+n; k++)
+         {  if (k <= m)
+            {  GLPROW *row = mip->row[k];
+               tree->root_type[k] = (char)row->type;
+               tree->root_lb[k] = row->lb;
+               tree->root_ub[k] = row->ub;
+               tree->root_stat[k] = (char)row->stat;
+            }
+            else
+            {  GLPCOL *col = mip->col[k-m];
+               tree->root_type[k] = (char)col->type;
+               tree->root_lb[k] = col->lb;
+               tree->root_ub[k] = col->ub;
+               tree->root_stat[k] = (char)col->stat;
+            }
+         }
+      }
+      else
+      {  /* freeze non-root subproblem */
+         int root_m = tree->root_m;
+         int pred_m = tree->pred_m;
+         int i, j, k;
+         xassert(pred_m <= m);
+         /* build change lists for rows and columns which exist in the
+            parent subproblem */
+         xassert(node->b_ptr == NULL);
+         xassert(node->s_ptr == NULL);
+         for (k = 1; k <= pred_m + n; k++)
+         {  int pred_type, pred_stat, type, stat;
+            double pred_lb, pred_ub, lb, ub;
+            /* determine attributes in the parent subproblem */
+            pred_type = tree->pred_type[k];
+            pred_lb = tree->pred_lb[k];
+            pred_ub = tree->pred_ub[k];
+            pred_stat = tree->pred_stat[k];
+            /* determine attributes in the current subproblem */
+            if (k <= pred_m)
+            {  GLPROW *row = mip->row[k];
+               type = row->type;
+               lb = row->lb;
+               ub = row->ub;
+               stat = row->stat;
+            }
+            else
+            {  GLPCOL *col = mip->col[k - pred_m];
+               type = col->type;
+               lb = col->lb;
+               ub = col->ub;
+               stat = col->stat;
+            }
+            /* save type and bounds of a row/column, if changed */
+            if (!(pred_type == type && pred_lb == lb && pred_ub == ub))
+            {  IOSBND *b;
+               b = dmp_get_atom(tree->pool, sizeof(IOSBND));
+               b->k = k;
+               b->type = (unsigned char)type;
+               b->lb = lb;
+               b->ub = ub;
+               b->next = node->b_ptr;
+               node->b_ptr = b;
+            }
+            /* save status of a row/column, if changed */
+            if (pred_stat != stat)
+            {  IOSTAT *s;
+               s = dmp_get_atom(tree->pool, sizeof(IOSTAT));
+               s->k = k;
+               s->stat = (unsigned char)stat;
+               s->next = node->s_ptr;
+               node->s_ptr = s;
+            }
+         }
+         /* save new rows added to the current subproblem */
+         xassert(node->r_ptr == NULL);
+         if (pred_m < m)
+         {  int i, len, *ind;
+            double *val;
+            ind = xcalloc(1+n, sizeof(int));
+            val = xcalloc(1+n, sizeof(double));
+            for (i = m; i > pred_m; i--)
+            {  GLPROW *row = mip->row[i];
+               IOSROW *r;
+               const char *name;
+               r = dmp_get_atom(tree->pool, sizeof(IOSROW));
+               name = glp_get_row_name(mip, i);
+               if (name == NULL)
+                  r->name = NULL;
+               else
+               {  r->name = dmp_get_atom(tree->pool, strlen(name)+1);
+                  strcpy(r->name, name);
+               }
+#if 1 /* 20/IX-2008 */
+               r->origin = row->origin;
+               r->klass = row->klass;
+#endif
+               r->type = (unsigned char)row->type;
+               r->lb = row->lb;
+               r->ub = row->ub;
+               r->ptr = NULL;
+               len = glp_get_mat_row(mip, i, ind, val);
+               for (k = 1; k <= len; k++)
+               {  IOSAIJ *a;
+                  a = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
+                  a->j = ind[k];
+                  a->val = val[k];
+                  a->next = r->ptr;
+                  r->ptr = a;
+               }
+               r->rii = row->rii;
+               r->stat = (unsigned char)row->stat;
+               r->next = node->r_ptr;
+               node->r_ptr = r;
+            }
+            xfree(ind);
+            xfree(val);
+         }
+         /* remove all rows missing in the root subproblem */
+         if (m != root_m)
+         {  int nrs, *num;
+            nrs = m - root_m;
+            xassert(nrs > 0);
+            num = xcalloc(1+nrs, sizeof(int));
+            for (i = 1; i <= nrs; i++) num[i] = root_m + i;
+            glp_del_rows(mip, nrs, num);
+            xfree(num);
+         }
+         m = mip->m;
+         /* and restore attributes of all rows and columns for the root
+            subproblem */
+         xassert(m == root_m);
+         for (i = 1; i <= m; i++)
+         {  glp_set_row_bnds(mip, i, tree->root_type[i],
+               tree->root_lb[i], tree->root_ub[i]);
+            glp_set_row_stat(mip, i, tree->root_stat[i]);
+         }
+         for (j = 1; j <= n; j++)
+         {  glp_set_col_bnds(mip, j, tree->root_type[m+j],
+               tree->root_lb[m+j], tree->root_ub[m+j]);
+            glp_set_col_stat(mip, j, tree->root_stat[m+j]);
+         }
+#if 1
+         /* remove all edges and cliques missing in the conflict graph
+            for the root subproblem */
+         /* (not implemented yet) */
+#endif
+      }
+      /* the current subproblem has been frozen */
+      tree->curr = NULL;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clone_node - clone specified subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clone_node clones the specified subproblem, whose
+*  reference number is p, creating its nnn exact copies. Note that the
+*  specified subproblem must be active and must be in the frozen state
+*  (i.e. it must not be the current subproblem).
+*
+*  Each clone, an exact copy of the specified subproblem, becomes a new
+*  active subproblem added to the end of the active list. After cloning
+*  the specified subproblem becomes inactive.
+*
+*  The reference numbers of clone subproblems are stored to locations
+*  ref[1], ..., ref[nnn]. */
+
+static int get_slot(glp_tree *tree)
+{     int p;
+      /* if no free slots are available, increase the room */
+      if (tree->avail == 0)
+      {  int nslots = tree->nslots;
+         IOSLOT *save = tree->slot;
+         if (nslots == 0)
+            tree->nslots = 20;
+         else
+         {  tree->nslots = nslots + nslots;
+            xassert(tree->nslots > nslots);
+         }
+         tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT));
+         if (save != NULL)
+         {  memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT));
+            xfree(save);
+         }
+         /* push more free slots into the stack */
+         for (p = tree->nslots; p > nslots; p--)
+         {  tree->slot[p].node = NULL;
+            tree->slot[p].next = tree->avail;
+            tree->avail = p;
+         }
+      }
+      /* pull a free slot from the stack */
+      p = tree->avail;
+      tree->avail = tree->slot[p].next;
+      xassert(tree->slot[p].node == NULL);
+      tree->slot[p].next = 0;
+      return p;
+}
+
+static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent)
+{     IOSNPD *node;
+      int p;
+      /* pull a free slot for the new node */
+      p = get_slot(tree);
+      /* create descriptor of the new subproblem */
+      node = dmp_get_atom(tree->pool, sizeof(IOSNPD));
+      tree->slot[p].node = node;
+      node->p = p;
+      node->up = parent;
+      node->level = (parent == NULL ? 0 : parent->level + 1);
+      node->count = 0;
+      node->b_ptr = NULL;
+      node->s_ptr = NULL;
+      node->r_ptr = NULL;
+      node->solved = 0;
+#if 0
+      node->own_nn = node->own_nc = 0;
+      node->e_ptr = NULL;
+#endif
+#if 1 /* 04/X-2008 */
+      node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
+         -DBL_MAX : +DBL_MAX) : parent->lp_obj);
+#endif
+      node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
+         -DBL_MAX : +DBL_MAX) : parent->bound);
+      node->br_var = 0;
+      node->br_val = 0.0;
+      node->ii_cnt = 0;
+      node->ii_sum = 0.0;
+#if 1 /* 30/XI-2009 */
+      node->changed = 0;
+#endif
+      if (tree->parm->cb_size == 0)
+         node->data = NULL;
+      else
+      {  node->data = dmp_get_atom(tree->pool, tree->parm->cb_size);
+         memset(node->data, 0, tree->parm->cb_size);
+      }
+      node->temp = NULL;
+      node->prev = tree->tail;
+      node->next = NULL;
+      /* add the new subproblem to the end of the active list */
+      if (tree->head == NULL)
+         tree->head = node;
+      else
+         tree->tail->next = node;
+      tree->tail = node;
+      tree->a_cnt++;
+      tree->n_cnt++;
+      tree->t_cnt++;
+      /* increase the number of child subproblems */
+      if (parent == NULL)
+         xassert(p == 1);
+      else
+         parent->count++;
+      return node;
+}
+
+void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[])
+{     IOSNPD *node;
+      int k;
+      /* obtain pointer to the subproblem to be cloned */
+      xassert(1 <= p && p <= tree->nslots);
+      node = tree->slot[p].node;
+      xassert(node != NULL);
+      /* the specified subproblem must be active */
+      xassert(node->count == 0);
+      /* and must be in the frozen state */
+      xassert(tree->curr != node);
+      /* remove the specified subproblem from the active list, because
+         it becomes inactive */
+      if (node->prev == NULL)
+         tree->head = node->next;
+      else
+         node->prev->next = node->next;
+      if (node->next == NULL)
+         tree->tail = node->prev;
+      else
+         node->next->prev = node->prev;
+      node->prev = node->next = NULL;
+      tree->a_cnt--;
+      /* create clone subproblems */
+      xassert(nnn > 0);
+      for (k = 1; k <= nnn; k++)
+         ref[k] = new_node(tree, node)->p;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_delete_node - delete specified subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_delete_node(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine ios_delete_node deletes the specified subproblem, whose
+*  reference number is p. The subproblem must be active and must be in
+*  the frozen state (i.e. it must not be the current subproblem).
+*
+*  Note that deletion is performed recursively, i.e. if a subproblem to
+*  be deleted is the only child of its parent, the parent subproblem is
+*  also deleted, etc. */
+
+void ios_delete_node(glp_tree *tree, int p)
+{     IOSNPD *node, *temp;
+      /* obtain pointer to the subproblem to be deleted */
+      xassert(1 <= p && p <= tree->nslots);
+      node = tree->slot[p].node;
+      xassert(node != NULL);
+      /* the specified subproblem must be active */
+      xassert(node->count == 0);
+      /* and must be in the frozen state */
+      xassert(tree->curr != node);
+      /* remove the specified subproblem from the active list, because
+         it is gone from the tree */
+      if (node->prev == NULL)
+         tree->head = node->next;
+      else
+         node->prev->next = node->next;
+      if (node->next == NULL)
+         tree->tail = node->prev;
+      else
+         node->next->prev = node->prev;
+      node->prev = node->next = NULL;
+      tree->a_cnt--;
+loop: /* recursive deletion starts here */
+      /* delete the bound change list */
+      {  IOSBND *b;
+         while (node->b_ptr != NULL)
+         {  b = node->b_ptr;
+            node->b_ptr = b->next;
+            dmp_free_atom(tree->pool, b, sizeof(IOSBND));
+         }
+      }
+      /* delete the status change list */
+      {  IOSTAT *s;
+         while (node->s_ptr != NULL)
+         {  s = node->s_ptr;
+            node->s_ptr = s->next;
+            dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
+         }
+      }
+      /* delete the row addition list */
+      while (node->r_ptr != NULL)
+      {  IOSROW *r;
+         r = node->r_ptr;
+         if (r->name != NULL)
+            dmp_free_atom(tree->pool, r->name, strlen(r->name)+1);
+         while (r->ptr != NULL)
+         {  IOSAIJ *a;
+            a = r->ptr;
+            r->ptr = a->next;
+            dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
+         }
+         node->r_ptr = r->next;
+         dmp_free_atom(tree->pool, r, sizeof(IOSROW));
+      }
+#if 0
+      /* delete the edge addition list */
+      /* delete the clique addition list */
+      /* (not implemented yet) */
+      xassert(node->own_nn == 0);
+      xassert(node->own_nc == 0);
+      xassert(node->e_ptr == NULL);
+#endif
+      /* free application-specific data */
+      if (tree->parm->cb_size == 0)
+         xassert(node->data == NULL);
+      else
+         dmp_free_atom(tree->pool, node->data, tree->parm->cb_size);
+      /* free the corresponding node slot */
+      p = node->p;
+      xassert(tree->slot[p].node == node);
+      tree->slot[p].node = NULL;
+      tree->slot[p].next = tree->avail;
+      tree->avail = p;
+      /* save pointer to the parent subproblem */
+      temp = node->up;
+      /* delete the subproblem descriptor */
+      dmp_free_atom(tree->pool, node, sizeof(IOSNPD));
+      tree->n_cnt--;
+      /* take pointer to the parent subproblem */
+      node = temp;
+      if (node != NULL)
+      {  /* the parent subproblem exists; decrease the number of its
+            child subproblems */
+         xassert(node->count > 0);
+         node->count--;
+         /* if now the parent subproblem has no childs, it also must be
+            deleted */
+         if (node->count == 0) goto loop;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_delete_tree - delete branch-and-bound tree
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_delete_tree(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_delete_tree deletes the branch-and-bound tree, which
+*  the parameter tree points to, and frees all the memory allocated to
+*  this program object.
+*
+*  On exit components of the problem object are restored to correspond
+*  to the original MIP passed to the routine ios_create_tree. */
+
+void ios_delete_tree(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      int i, j;
+      int m = mip->m;
+      int n = mip->n;
+      xassert(mip->tree == tree);
+      /* remove all additional rows */
+      if (m != tree->orig_m)
+      {  int nrs, *num;
+         nrs = m - tree->orig_m;
+         xassert(nrs > 0);
+         num = xcalloc(1+nrs, sizeof(int));
+         for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i;
+         glp_del_rows(mip, nrs, num);
+         xfree(num);
+      }
+      m = tree->orig_m;
+      /* restore original attributes of rows and columns */
+      xassert(m == tree->orig_m);
+      xassert(n == tree->n);
+      for (i = 1; i <= m; i++)
+      {  glp_set_row_bnds(mip, i, tree->orig_type[i],
+            tree->orig_lb[i], tree->orig_ub[i]);
+         glp_set_row_stat(mip, i, tree->orig_stat[i]);
+         mip->row[i]->prim = tree->orig_prim[i];
+         mip->row[i]->dual = tree->orig_dual[i];
+      }
+      for (j = 1; j <= n; j++)
+      {  glp_set_col_bnds(mip, j, tree->orig_type[m+j],
+            tree->orig_lb[m+j], tree->orig_ub[m+j]);
+         glp_set_col_stat(mip, j, tree->orig_stat[m+j]);
+         mip->col[j]->prim = tree->orig_prim[m+j];
+         mip->col[j]->dual = tree->orig_dual[m+j];
+      }
+      mip->pbs_stat = mip->dbs_stat = GLP_FEAS;
+      mip->obj_val = tree->orig_obj;
+      /* delete the branch-and-bound tree */
+      xassert(tree->local != NULL);
+      ios_delete_pool(tree, tree->local);
+      dmp_delete_pool(tree->pool);
+      xfree(tree->orig_type);
+      xfree(tree->orig_lb);
+      xfree(tree->orig_ub);
+      xfree(tree->orig_stat);
+      xfree(tree->orig_prim);
+      xfree(tree->orig_dual);
+      xfree(tree->slot);
+      if (tree->root_type != NULL) xfree(tree->root_type);
+      if (tree->root_lb != NULL) xfree(tree->root_lb);
+      if (tree->root_ub != NULL) xfree(tree->root_ub);
+      if (tree->root_stat != NULL) xfree(tree->root_stat);
+      xfree(tree->non_int);
+#if 0
+      xfree(tree->n_ref);
+      xfree(tree->c_ref);
+      xfree(tree->j_ref);
+#endif
+      if (tree->pcost != NULL) ios_pcost_free(tree);
+      xfree(tree->iwrk);
+      xfree(tree->dwrk);
+#if 0
+      scg_delete_graph(tree->g);
+#endif
+      if (tree->pred_type != NULL) xfree(tree->pred_type);
+      if (tree->pred_lb != NULL) xfree(tree->pred_lb);
+      if (tree->pred_ub != NULL) xfree(tree->pred_ub);
+      if (tree->pred_stat != NULL) xfree(tree->pred_stat);
+#if 0
+      xassert(tree->cut_gen == NULL);
+#endif
+      xassert(tree->mir_gen == NULL);
+      xassert(tree->clq_gen == NULL);
+      xfree(tree);
+      mip->tree = NULL;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_eval_degrad - estimate obj. degrad. for down- and up-branches
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
+*
+*  DESCRIPTION
+*
+*  Given optimal basis to LP relaxation of the current subproblem the
+*  routine ios_eval_degrad performs the dual ratio test to compute the
+*  objective values in the adjacent basis for down- and up-branches,
+*  which are stored in locations *dn and *up, assuming that x[j] is a
+*  variable chosen to branch upon. */
+
+void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up)
+{     glp_prob *mip = tree->mip;
+      int m = mip->m, n = mip->n;
+      int len, kase, k, t, stat;
+      double alfa, beta, gamma, delta, dz;
+      int *ind = tree->iwrk;
+      double *val = tree->dwrk;
+      /* current basis must be optimal */
+      xassert(glp_get_status(mip) == GLP_OPT);
+      /* basis factorization must exist */
+      xassert(glp_bf_exists(mip));
+      /* obtain (fractional) value of x[j] in optimal basic solution
+         to LP relaxation of the current subproblem */
+      xassert(1 <= j && j <= n);
+      beta = mip->col[j]->prim;
+      /* since the value of x[j] is fractional, it is basic; compute
+         corresponding row of the simplex table */
+      len = lpx_eval_tab_row(mip, m+j, ind, val);
+      /* kase < 0 means down-branch; kase > 0 means up-branch */
+      for (kase = -1; kase <= +1; kase += 2)
+      {  /* for down-branch we introduce new upper bound floor(beta)
+            for x[j]; similarly, for up-branch we introduce new lower
+            bound ceil(beta) for x[j]; in the current basis this new
+            upper/lower bound is violated, so in the adjacent basis
+            x[j] will leave the basis and go to its new upper/lower
+            bound; we need to know which non-basic variable x[k] should
+            enter the basis to keep dual feasibility */
+#if 0 /* 23/XI-2009 */
+         k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7);
+#else
+         k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9);
+#endif
+         /* if no variable has been chosen, current basis being primal
+            infeasible due to the new upper/lower bound of x[j] is dual
+            unbounded, therefore, LP relaxation to corresponding branch
+            has no primal feasible solution */
+         if (k == 0)
+         {  if (mip->dir == GLP_MIN)
+            {  if (kase < 0)
+                  *dn = +DBL_MAX;
+               else
+                  *up = +DBL_MAX;
+            }
+            else if (mip->dir == GLP_MAX)
+            {  if (kase < 0)
+                  *dn = -DBL_MAX;
+               else
+                  *up = -DBL_MAX;
+            }
+            else
+               xassert(mip != mip);
+            continue;
+         }
+         xassert(1 <= k && k <= m+n);
+         /* row of the simplex table corresponding to specified basic
+            variable x[j] is the following:
+               x[j] = ... + alfa * x[k] + ... ;
+            we need to know influence coefficient, alfa, at non-basic
+            variable x[k] chosen with the dual ratio test */
+         for (t = 1; t <= len; t++)
+            if (ind[t] == k) break;
+         xassert(1 <= t && t <= len);
+         alfa = val[t];
+         /* determine status and reduced cost of variable x[k] */
+         if (k <= m)
+         {  stat = mip->row[k]->stat;
+            gamma = mip->row[k]->dual;
+         }
+         else
+         {  stat = mip->col[k-m]->stat;
+            gamma = mip->col[k-m]->dual;
+         }
+         /* x[k] cannot be basic or fixed non-basic */
+         xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF);
+         /* if the current basis is dual degenerative, some reduced
+            costs, which are close to zero, may have wrong sign due to
+            round-off errors, so correct the sign of gamma */
+         if (mip->dir == GLP_MIN)
+         {  if (stat == GLP_NL && gamma < 0.0 ||
+                stat == GLP_NU && gamma > 0.0 ||
+                stat == GLP_NF) gamma = 0.0;
+         }
+         else if (mip->dir == GLP_MAX)
+         {  if (stat == GLP_NL && gamma > 0.0 ||
+                stat == GLP_NU && gamma < 0.0 ||
+                stat == GLP_NF) gamma = 0.0;
+         }
+         else
+            xassert(mip != mip);
+         /* determine the change of x[j] in the adjacent basis:
+            delta x[j] = new x[j] - old x[j] */
+         delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta;
+         /* compute the change of x[k] in the adjacent basis:
+            delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */
+         delta /= alfa;
+         /* compute the change of the objective in the adjacent basis:
+            delta z = new z - old z = gamma * delta x[k] */
+         dz = gamma * delta;
+         if (mip->dir == GLP_MIN)
+            xassert(dz >= 0.0);
+         else if (mip->dir == GLP_MAX)
+            xassert(dz <= 0.0);
+         else
+            xassert(mip != mip);
+         /* compute the new objective value in the adjacent basis:
+            new z = old z + delta z */
+         if (kase < 0)
+            *dn = mip->obj_val + dz;
+         else
+            *up = mip->obj_val + dz;
+      }
+      /*xprintf("obj = %g; dn = %g; up = %g\n",
+         mip->obj_val, *dn, *up);*/
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_round_bound - improve local bound by rounding
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  double ios_round_bound(glp_tree *tree, double bound);
+*
+*  RETURNS
+*
+*  For the given local bound for any integer feasible solution to the
+*  current subproblem the routine ios_round_bound returns an improved
+*  local bound for the same integer feasible solution.
+*
+*  BACKGROUND
+*
+*  Let the current subproblem has the following objective function:
+*
+*     z =   sum  c[j] * x[j] + s >= b,                               (1)
+*         j in J
+*
+*  where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is
+*  the sum of terms corresponding to fixed variables, b is an initial
+*  local bound (minimization).
+*
+*  From (1) it follows that:
+*
+*     d *  sum  (c[j] / d) * x[j] + s >= b,                          (2)
+*        j in J
+*
+*  or, equivalently,
+*
+*     sum  (c[j] / d) * x[j] >= (b - s) / d = h,                     (3)
+*   j in J
+*
+*  where d = gcd(c[j]). Since the left-hand side of (3) is integer,
+*  h = (b - s) / d can be rounded up to the nearest integer:
+*
+*     h' = ceil(h) = (b' - s) / d,                                   (4)
+*
+*  that gives an rounded, improved local bound:
+*
+*     b' = d * h' + s.                                               (5)
+*
+*  In case of maximization '>=' in (1) should be replaced by '<=' that
+*  leads to the following formula:
+*
+*     h' = floor(h) = (b' - s) / d,                                  (6)
+*
+*  which should used in the same way as (4).
+*
+*  NOTE: If b is a valid local bound for a child of the current
+*        subproblem, b' is also valid for that child subproblem. */
+
+double ios_round_bound(glp_tree *tree, double bound)
+{     glp_prob *mip = tree->mip;
+      int n = mip->n;
+      int d, j, nn, *c = tree->iwrk;
+      double s, h;
+      /* determine c[j] and compute s */
+      nn = 0, s = mip->c0, d = 0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         if (col->coef == 0.0) continue;
+         if (col->type == GLP_FX)
+         {  /* fixed variable */
+            s += col->coef * col->prim;
+         }
+         else
+         {  /* non-fixed variable */
+            if (col->kind != GLP_IV) goto skip;
+            if (col->coef != floor(col->coef)) goto skip;
+            if (fabs(col->coef) <= (double)INT_MAX)
+               c[++nn] = (int)fabs(col->coef);
+            else
+               d = 1;
+         }
+      }
+      /* compute d = gcd(c[1],...c[nn]) */
+      if (d == 0)
+      {  if (nn == 0) goto skip;
+         d = gcdn(nn, c);
+      }
+      xassert(d > 0);
+      /* compute new local bound */
+      if (mip->dir == GLP_MIN)
+      {  if (bound != +DBL_MAX)
+         {  h = (bound - s) / (double)d;
+            if (h >= floor(h) + 0.001)
+            {  /* round up */
+               h = ceil(h);
+               /*xprintf("d = %d; old = %g; ", d, bound);*/
+               bound = (double)d * h + s;
+               /*xprintf("new = %g\n", bound);*/
+            }
+         }
+      }
+      else if (mip->dir == GLP_MAX)
+      {  if (bound != -DBL_MAX)
+         {  h = (bound - s) / (double)d;
+            if (h <= ceil(h) - 0.001)
+            {  /* round down */
+               h = floor(h);
+               bound = (double)d * h + s;
+            }
+         }
+      }
+      else
+         xassert(mip != mip);
+skip: return bound;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_is_hopeful - check if subproblem is hopeful
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_is_hopeful(glp_tree *tree, double bound);
+*
+*  DESCRIPTION
+*
+*  Given the local bound of a subproblem the routine ios_is_hopeful
+*  checks if the subproblem can have an integer optimal solution which
+*  is better than the best one currently known.
+*
+*  RETURNS
+*
+*  If the subproblem can have a better integer optimal solution, the
+*  routine returns non-zero; otherwise, if the corresponding branch can
+*  be pruned, the routine returns zero. */
+
+int ios_is_hopeful(glp_tree *tree, double bound)
+{     glp_prob *mip = tree->mip;
+      int ret = 1;
+      double eps;
+      if (mip->mip_stat == GLP_FEAS)
+      {  eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj));
+         switch (mip->dir)
+         {  case GLP_MIN:
+               if (bound >= mip->mip_obj - eps) ret = 0;
+               break;
+            case GLP_MAX:
+               if (bound <= mip->mip_obj + eps) ret = 0;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      else
+      {  switch (mip->dir)
+         {  case GLP_MIN:
+               if (bound == +DBL_MAX) ret = 0;
+               break;
+            case GLP_MAX:
+               if (bound == -DBL_MAX) ret = 0;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_best_node - find active node with best local bound
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_best_node(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_best_node finds an active node whose local bound is
+*  best among other active nodes.
+*
+*  It is understood that the integer optimal solution of the original
+*  mip problem cannot be better than the best bound, so the best bound
+*  is an lower (minimization) or upper (maximization) global bound for
+*  the original problem.
+*
+*  RETURNS
+*
+*  The routine ios_best_node returns the subproblem reference number
+*  for the best node. However, if the tree is empty, it returns zero. */
+
+int ios_best_node(glp_tree *tree)
+{     IOSNPD *node, *best = NULL;
+      switch (tree->mip->dir)
+      {  case GLP_MIN:
+            /* minimization */
+            for (node = tree->head; node != NULL; node = node->next)
+               if (best == NULL || best->bound > node->bound)
+                  best = node;
+            break;
+         case GLP_MAX:
+            /* maximization */
+            for (node = tree->head; node != NULL; node = node->next)
+               if (best == NULL || best->bound < node->bound)
+                  best = node;
+            break;
+         default:
+            xassert(tree != tree);
+      }
+      return best == NULL ? 0 : best->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_relative_gap - compute relative mip gap
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  double ios_relative_gap(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_relative_gap computes the relative mip gap using the
+*  formula:
+*
+*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
+*
+*  where best_mip is the best integer feasible solution found so far,
+*  best_bnd is the best (global) bound. If no integer feasible solution
+*  has been found yet, rel_gap is set to DBL_MAX.
+*
+*  RETURNS
+*
+*  The routine ios_relative_gap returns the relative mip gap. */
+
+double ios_relative_gap(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      int p;
+      double best_mip, best_bnd, gap;
+      if (mip->mip_stat == GLP_FEAS)
+      {  best_mip = mip->mip_obj;
+         p = ios_best_node(tree);
+         if (p == 0)
+         {  /* the tree is empty */
+            gap = 0.0;
+         }
+         else
+         {  best_bnd = tree->slot[p].node->bound;
+            gap = fabs(best_mip - best_bnd) / (fabs(best_mip) +
+               DBL_EPSILON);
+         }
+      }
+      else
+      {  /* no integer feasible solution has been found yet */
+         gap = DBL_MAX;
+      }
+      return gap;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_solve_node - solve LP relaxation of current subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_solve_node(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_solve_node re-optimizes LP relaxation of the current
+*  subproblem using the dual simplex method.
+*
+*  RETURNS
+*
+*  The routine returns the code which is reported by glp_simplex. */
+
+int ios_solve_node(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      glp_smcp parm;
+      int ret;
+      /* the current subproblem must exist */
+      xassert(tree->curr != NULL);
+      /* set some control parameters */
+      glp_init_smcp(&parm);
+      switch (tree->parm->msg_lev)
+      {  case GLP_MSG_OFF:
+            parm.msg_lev = GLP_MSG_OFF; break;
+         case GLP_MSG_ERR:
+            parm.msg_lev = GLP_MSG_ERR; break;
+         case GLP_MSG_ON:
+         case GLP_MSG_ALL:
+            parm.msg_lev = GLP_MSG_ON; break;
+         case GLP_MSG_DBG:
+            parm.msg_lev = GLP_MSG_ALL; break;
+         default:
+            xassert(tree != tree);
+      }
+      parm.meth = GLP_DUALP;
+      if (tree->parm->msg_lev < GLP_MSG_DBG)
+         parm.out_dly = tree->parm->out_dly;
+      else
+         parm.out_dly = 0;
+      /* if the incumbent objective value is already known, use it to
+         prematurely terminate the dual simplex search */
+      if (mip->mip_stat == GLP_FEAS)
+      {  switch (tree->mip->dir)
+         {  case GLP_MIN:
+               parm.obj_ul = mip->mip_obj;
+               break;
+            case GLP_MAX:
+               parm.obj_ll = mip->mip_obj;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      /* try to solve/re-optimize the LP relaxation */
+      ret = glp_simplex(mip, &parm);
+      tree->curr->solved++;
+#if 0
+      xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n",
+         ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat,
+         mip->some);
+      lpx_print_sol(mip, "sol");
+#endif
+      return ret;
+}
+
+/**********************************************************************/
+
+IOSPOOL *ios_create_pool(glp_tree *tree)
+{     /* create cut pool */
+      IOSPOOL *pool;
+#if 0
+      pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL));
+#else
+      xassert(tree == tree);
+      pool = xmalloc(sizeof(IOSPOOL));
+#endif
+      pool->size = 0;
+      pool->head = pool->tail = NULL;
+      pool->ord = 0, pool->curr = NULL;
+      return pool;
+}
+
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs)
+{     /* add row (constraint) to the cut pool */
+      IOSCUT *cut;
+      IOSAIJ *aij;
+      int k;
+      xassert(pool != NULL);
+      cut = dmp_get_atom(tree->pool, sizeof(IOSCUT));
+      if (name == NULL || name[0] == '\0')
+         cut->name = NULL;
+      else
+      {  for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_ios_add_row: cut name too long\n");
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_ios_add_row: cut name contains invalid chara"
+                  "cter(s)\n");
+         }
+         cut->name = dmp_get_atom(tree->pool, strlen(name)+1);
+         strcpy(cut->name, name);
+      }
+      if (!(0 <= klass && klass <= 255))
+         xerror("glp_ios_add_row: klass = %d; invalid cut class\n",
+            klass);
+      cut->klass = (unsigned char)klass;
+      if (flags != 0)
+         xerror("glp_ios_add_row: flags = %d; invalid cut flags\n",
+            flags);
+      cut->ptr = NULL;
+      if (!(0 <= len && len <= tree->n))
+         xerror("glp_ios_add_row: len = %d; invalid cut length\n",
+            len);
+      for (k = 1; k <= len; k++)
+      {  aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
+         if (!(1 <= ind[k] && ind[k] <= tree->n))
+            xerror("glp_ios_add_row: ind[%d] = %d; column index out of "
+               "range\n", k, ind[k]);
+         aij->j = ind[k];
+         aij->val = val[k];
+         aij->next = cut->ptr;
+         cut->ptr = aij;
+      }
+      if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX))
+         xerror("glp_ios_add_row: type = %d; invalid cut type\n",
+            type);
+      cut->type = (unsigned char)type;
+      cut->rhs = rhs;
+      cut->prev = pool->tail;
+      cut->next = NULL;
+      if (cut->prev == NULL)
+         pool->head = cut;
+      else
+         cut->prev->next = cut;
+      pool->tail = cut;
+      pool->size++;
+      return pool->size;
+}
+
+IOSCUT *ios_find_row(IOSPOOL *pool, int i)
+{     /* find row (constraint) in the cut pool */
+      /* (smart linear search) */
+      xassert(pool != NULL);
+      xassert(1 <= i && i <= pool->size);
+      if (pool->ord == 0)
+      {  xassert(pool->curr == NULL);
+         pool->ord = 1;
+         pool->curr = pool->head;
+      }
+      xassert(pool->curr != NULL);
+      if (i < pool->ord)
+      {  if (i < pool->ord - i)
+         {  pool->ord = 1;
+            pool->curr = pool->head;
+            while (pool->ord != i)
+            {  pool->ord++;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->next;
+            }
+         }
+         else
+         {  while (pool->ord != i)
+            {  pool->ord--;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->prev;
+            }
+         }
+      }
+      else if (i > pool->ord)
+      {  if (i - pool->ord < pool->size - i)
+         {  while (pool->ord != i)
+            {  pool->ord++;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->next;
+            }
+         }
+         else
+         {  pool->ord = pool->size;
+            pool->curr = pool->tail;
+            while (pool->ord != i)
+            {  pool->ord--;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->prev;
+            }
+         }
+      }
+      xassert(pool->ord == i);
+      xassert(pool->curr != NULL);
+      return pool->curr;
+}
+
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
+{     /* remove row (constraint) from the cut pool */
+      IOSCUT *cut;
+      IOSAIJ *aij;
+      xassert(pool != NULL);
+      if (!(1 <= i && i <= pool->size))
+         xerror("glp_ios_del_row: i = %d; cut number out of range\n",
+            i);
+      cut = ios_find_row(pool, i);
+      xassert(pool->curr == cut);
+      if (cut->next != NULL)
+         pool->curr = cut->next;
+      else if (cut->prev != NULL)
+         pool->ord--, pool->curr = cut->prev;
+      else
+         pool->ord = 0, pool->curr = NULL;
+      if (cut->name != NULL)
+         dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
+      if (cut->prev == NULL)
+      {  xassert(pool->head == cut);
+         pool->head = cut->next;
+      }
+      else
+      {  xassert(cut->prev->next == cut);
+         cut->prev->next = cut->next;
+      }
+      if (cut->next == NULL)
+      {  xassert(pool->tail == cut);
+         pool->tail = cut->prev;
+      }
+      else
+      {  xassert(cut->next->prev == cut);
+         cut->next->prev = cut->prev;
+      }
+      while (cut->ptr != NULL)
+      {  aij = cut->ptr;
+         cut->ptr = aij->next;
+         dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
+      }
+      dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
+      pool->size--;
+      return;
+}
+
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
+{     /* remove all rows (constraints) from the cut pool */
+      xassert(pool != NULL);
+      while (pool->head != NULL)
+      {  IOSCUT *cut = pool->head;
+         pool->head = cut->next;
+         if (cut->name != NULL)
+            dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
+         while (cut->ptr != NULL)
+         {  IOSAIJ *aij = cut->ptr;
+            cut->ptr = aij->next;
+            dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
+         }
+         dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
+      }
+      pool->size = 0;
+      pool->head = pool->tail = NULL;
+      pool->ord = 0, pool->curr = NULL;
+      return;
+}
+
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
+{     /* delete cut pool */
+      xassert(pool != NULL);
+      ios_clear_pool(tree, pool);
+      xfree(pool);
+      return;
+}
+
+/**********************************************************************/
+
+#if 0
+static int refer_to_node(glp_tree *tree, int j)
+{     /* determine node number corresponding to binary variable x[j] or
+         its complement */
+      glp_prob *mip = tree->mip;
+      int n = mip->n;
+      int *ref;
+      if (j > 0)
+         ref = tree->n_ref;
+      else
+         ref = tree->c_ref, j = - j;
+      xassert(1 <= j && j <= n);
+      if (ref[j] == 0)
+      {  /* new node is needed */
+         SCG *g = tree->g;
+         int n_max = g->n_max;
+         ref[j] = scg_add_nodes(g, 1);
+         if (g->n_max > n_max)
+         {  int *save = tree->j_ref;
+            tree->j_ref = xcalloc(1+g->n_max, sizeof(int));
+            memcpy(&tree->j_ref[1], &save[1], g->n * sizeof(int));
+            xfree(save);
+         }
+         xassert(ref[j] == g->n);
+         tree->j_ref[ref[j]] = j;
+         xassert(tree->curr != NULL);
+         if (tree->curr->level > 0) tree->curr->own_nn++;
+      }
+      return ref[j];
+}
+#endif
+
+#if 0
+void ios_add_edge(glp_tree *tree, int j1, int j2)
+{     /* add new edge to the conflict graph */
+      glp_prob *mip = tree->mip;
+      int n = mip->n;
+      SCGRIB *e;
+      int first, i1, i2;
+      xassert(-n <= j1 && j1 <= +n && j1 != 0);
+      xassert(-n <= j2 && j2 <= +n && j2 != 0);
+      xassert(j1 != j2);
+      /* determine number of the first node, which was added for the
+         current subproblem */
+      xassert(tree->curr != NULL);
+      first = tree->g->n - tree->curr->own_nn + 1;
+      /* determine node numbers for both endpoints */
+      i1 = refer_to_node(tree, j1);
+      i2 = refer_to_node(tree, j2);
+      /* add edge (i1,i2) to the conflict graph */
+      e = scg_add_edge(tree->g, i1, i2);
+      /* if the current subproblem is not the root and both endpoints
+         were created on some previous levels, save the edge */
+      if (tree->curr->level > 0 && i1 < first && i2 < first)
+      {  IOSRIB *rib;
+         rib = dmp_get_atom(tree->pool, sizeof(IOSRIB));
+         rib->j1 = j1;
+         rib->j2 = j2;
+         rib->e = e;
+         rib->next = tree->curr->e_ptr;
+         tree->curr->e_ptr = rib;
+      }
+      return;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpios02.c b/optional/glpk/glpios02.c
new file mode 100644
index 0000000..92b3390
--- /dev/null
+++ b/optional/glpk/glpios02.c
@@ -0,0 +1,829 @@
+/* glpios02.c (preprocess current subproblem) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  prepare_row_info - prepare row info to determine implied bounds
+*
+*  Given a row (linear form)
+*
+*      n
+*     sum a[j] * x[j]                                                (1)
+*     j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]                                           (2)
+*
+*  this routine computes f_min, j_min, f_max, j_max needed to determine
+*  implied bounds.
+*
+*  ALGORITHM
+*
+*  Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
+*
+*  Parameters f_min and j_min are computed as follows:
+*
+*  1) if there is no x[k] such that k in J+ and l[k] = -inf or k in J-
+*     and u[k] = +inf, then
+*
+*     f_min :=   sum   a[j] * l[j] +   sum   a[j] * u[j]
+*              j in J+               j in J-
+*                                                                    (3)
+*     j_min := 0
+*
+*  2) if there is exactly one x[k] such that k in J+ and l[k] = -inf
+*     or k in J- and u[k] = +inf, then
+*
+*     f_min :=   sum       a[j] * l[j] +   sum       a[j] * u[j]
+*              j in J+\{k}               j in J-\{k}
+*                                                                    (4)
+*     j_min := k
+*
+*  3) if there are two or more x[k] such that k in J+ and l[k] = -inf
+*     or k in J- and u[k] = +inf, then
+*
+*     f_min := -inf
+*                                                                    (5)
+*     j_min := 0
+*
+*  Parameters f_max and j_max are computed in a similar way as follows:
+*
+*  1) if there is no x[k] such that k in J+ and u[k] = +inf or k in J-
+*     and l[k] = -inf, then
+*
+*     f_max :=   sum   a[j] * u[j] +   sum   a[j] * l[j]
+*              j in J+               j in J-
+*                                                                    (6)
+*     j_max := 0
+*
+*  2) if there is exactly one x[k] such that k in J+ and u[k] = +inf
+*     or k in J- and l[k] = -inf, then
+*
+*     f_max :=   sum       a[j] * u[j] +   sum       a[j] * l[j]
+*              j in J+\{k}               j in J-\{k}
+*                                                                    (7)
+*     j_max := k
+*
+*  3) if there are two or more x[k] such that k in J+ and u[k] = +inf
+*     or k in J- and l[k] = -inf, then
+*
+*     f_max := +inf
+*                                                                    (8)
+*     j_max := 0                                                      */
+
+struct f_info
+{     int j_min, j_max;
+      double f_min, f_max;
+};
+
+static void prepare_row_info(int n, const double a[], const double l[],
+      const double u[], struct f_info *f)
+{     int j, j_min, j_max;
+      double f_min, f_max;
+      xassert(n >= 0);
+      /* determine f_min and j_min */
+      f_min = 0.0, j_min = 0;
+      for (j = 1; j <= n; j++)
+      {  if (a[j] > 0.0)
+         {  if (l[j] == -DBL_MAX)
+            {  if (j_min == 0)
+                  j_min = j;
+               else
+               {  f_min = -DBL_MAX, j_min = 0;
+                  break;
+               }
+            }
+            else
+               f_min += a[j] * l[j];
+         }
+         else if (a[j] < 0.0)
+         {  if (u[j] == +DBL_MAX)
+            {  if (j_min == 0)
+                  j_min = j;
+               else
+               {  f_min = -DBL_MAX, j_min = 0;
+                  break;
+               }
+            }
+            else
+               f_min += a[j] * u[j];
+         }
+         else
+            xassert(a != a);
+      }
+      f->f_min = f_min, f->j_min = j_min;
+      /* determine f_max and j_max */
+      f_max = 0.0, j_max = 0;
+      for (j = 1; j <= n; j++)
+      {  if (a[j] > 0.0)
+         {  if (u[j] == +DBL_MAX)
+            {  if (j_max == 0)
+                  j_max = j;
+               else
+               {  f_max = +DBL_MAX, j_max = 0;
+                  break;
+               }
+            }
+            else
+               f_max += a[j] * u[j];
+         }
+         else if (a[j] < 0.0)
+         {  if (l[j] == -DBL_MAX)
+            {  if (j_max == 0)
+                  j_max = j;
+               else
+               {  f_max = +DBL_MAX, j_max = 0;
+                  break;
+               }
+            }
+            else
+               f_max += a[j] * l[j];
+         }
+         else
+            xassert(a != a);
+      }
+      f->f_max = f_max, f->j_max = j_max;
+      return;
+}
+
+/***********************************************************************
+*  row_implied_bounds - determine row implied bounds
+*
+*  Given a row (linear form)
+*
+*      n
+*     sum a[j] * x[j]
+*     j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  this routine determines implied bounds of the row.
+*
+*  ALGORITHM
+*
+*  Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
+*
+*  The implied lower bound of the row is computed as follows:
+*
+*     L' :=   sum   a[j] * l[j] +   sum   a[j] * u[j]                (9)
+*           j in J+               j in J-
+*
+*  and as it follows from (3), (4), and (5):
+*
+*     L' := if j_min = 0 then f_min else -inf                       (10)
+*
+*  The implied upper bound of the row is computed as follows:
+*
+*     U' :=   sum   a[j] * u[j] +   sum   a[j] * l[j]               (11)
+*           j in J+               j in J-
+*
+*  and as it follows from (6), (7), and (8):
+*
+*     U' := if j_max = 0 then f_max else +inf                       (12)
+*
+*  The implied bounds are stored in locations LL and UU. */
+
+static void row_implied_bounds(const struct f_info *f, double *LL,
+      double *UU)
+{     *LL = (f->j_min == 0 ? f->f_min : -DBL_MAX);
+      *UU = (f->j_max == 0 ? f->f_max : +DBL_MAX);
+      return;
+}
+
+/***********************************************************************
+*  col_implied_bounds - determine column implied bounds
+*
+*  Given a row (constraint)
+*
+*           n
+*     L <= sum a[j] * x[j] <= U                                     (13)
+*          j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  this routine determines implied bounds of variable x[k].
+*
+*  It is assumed that if L != -inf, the lower bound of the row can be
+*  active, and if U != +inf, the upper bound of the row can be active.
+*
+*  ALGORITHM
+*
+*  From (13) it follows that
+*
+*     L <= sum a[j] * x[j] + a[k] * x[k] <= U
+*          j!=k
+*  or
+*
+*     L - sum a[j] * x[j] <= a[k] * x[k] <= U - sum a[j] * x[j]
+*         j!=k                                  j!=k
+*
+*  Thus, if the row lower bound L can be active, implied lower bound of
+*  term a[k] * x[k] can be determined as follows:
+*
+*     ilb(a[k] * x[k]) = min(L - sum a[j] * x[j]) =
+*                                j!=k
+*                                                                   (14)
+*                      = L - max sum a[j] * x[j]
+*                            j!=k
+*
+*  where, as it follows from (6), (7), and (8)
+*
+*                           / f_max - a[k] * u[k], j_max = 0, a[k] > 0
+*                           |
+*                           | f_max - a[k] * l[k], j_max = 0, a[k] < 0
+*     max sum a[j] * x[j] = {
+*         j!=k              | f_max,               j_max = k
+*                           |
+*                           \ +inf,                j_max != 0
+*
+*  and if the upper bound U can be active, implied upper bound of term
+*  a[k] * x[k] can be determined as follows:
+*
+*     iub(a[k] * x[k]) = max(U - sum a[j] * x[j]) =
+*                                j!=k
+*                                                                   (15)
+*                      = U - min sum a[j] * x[j]
+*                            j!=k
+*
+*  where, as it follows from (3), (4), and (5)
+*
+*                           / f_min - a[k] * l[k], j_min = 0, a[k] > 0
+*                           |
+*                           | f_min - a[k] * u[k], j_min = 0, a[k] < 0
+*     min sum a[j] * x[j] = {
+*         j!=k              | f_min,               j_min = k
+*                           |
+*                           \ -inf,                j_min != 0
+*
+*  Since
+*
+*     ilb(a[k] * x[k]) <= a[k] * x[k] <= iub(a[k] * x[k])
+*
+*  implied lower and upper bounds of x[k] are determined as follows:
+*
+*     l'[k] := if a[k] > 0 then ilb / a[k] else ulb / a[k]          (16)
+*
+*     u'[k] := if a[k] > 0 then ulb / a[k] else ilb / a[k]          (17)
+*
+*  The implied bounds are stored in locations ll and uu. */
+
+static void col_implied_bounds(const struct f_info *f, int n,
+      const double a[], double L, double U, const double l[],
+      const double u[], int k, double *ll, double *uu)
+{     double ilb, iub;
+      xassert(n >= 0);
+      xassert(1 <= k && k <= n);
+      /* determine implied lower bound of term a[k] * x[k] (14) */
+      if (L == -DBL_MAX || f->f_max == +DBL_MAX)
+         ilb = -DBL_MAX;
+      else if (f->j_max == 0)
+      {  if (a[k] > 0.0)
+         {  xassert(u[k] != +DBL_MAX);
+            ilb = L - (f->f_max - a[k] * u[k]);
+         }
+         else if (a[k] < 0.0)
+         {  xassert(l[k] != -DBL_MAX);
+            ilb = L - (f->f_max - a[k] * l[k]);
+         }
+         else
+            xassert(a != a);
+      }
+      else if (f->j_max == k)
+         ilb = L - f->f_max;
+      else
+         ilb = -DBL_MAX;
+      /* determine implied upper bound of term a[k] * x[k] (15) */
+      if (U == +DBL_MAX || f->f_min == -DBL_MAX)
+         iub = +DBL_MAX;
+      else if (f->j_min == 0)
+      {  if (a[k] > 0.0)
+         {  xassert(l[k] != -DBL_MAX);
+            iub = U - (f->f_min - a[k] * l[k]);
+         }
+         else if (a[k] < 0.0)
+         {  xassert(u[k] != +DBL_MAX);
+            iub = U - (f->f_min - a[k] * u[k]);
+         }
+         else
+            xassert(a != a);
+      }
+      else if (f->j_min == k)
+         iub = U - f->f_min;
+      else
+         iub = +DBL_MAX;
+      /* determine implied bounds of x[k] (16) and (17) */
+#if 1
+      /* do not use a[k] if it has small magnitude to prevent wrong
+         implied bounds; for example, 1e-15 * x1 >= x2 + x3, where
+         x1 >= -10, x2, x3 >= 0, would lead to wrong conclusion that
+         x1 >= 0 */
+      if (fabs(a[k]) < 1e-6)
+         *ll = -DBL_MAX, *uu = +DBL_MAX; else
+#endif
+      if (a[k] > 0.0)
+      {  *ll = (ilb == -DBL_MAX ? -DBL_MAX : ilb / a[k]);
+         *uu = (iub == +DBL_MAX ? +DBL_MAX : iub / a[k]);
+      }
+      else if (a[k] < 0.0)
+      {  *ll = (iub == +DBL_MAX ? -DBL_MAX : iub / a[k]);
+         *uu = (ilb == -DBL_MAX ? +DBL_MAX : ilb / a[k]);
+      }
+      else
+         xassert(a != a);
+      return;
+}
+
+/***********************************************************************
+*  check_row_bounds - check and relax original row bounds
+*
+*  Given a row (constraint)
+*
+*           n
+*     L <= sum a[j] * x[j] <= U
+*          j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  this routine checks the original row bounds L and U for feasibility
+*  and redundancy. If the original lower bound L or/and upper bound U
+*  cannot be active due to bounds of variables, the routine remove them
+*  replacing by -inf or/and +inf, respectively.
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+static int check_row_bounds(const struct f_info *f, double *L_,
+      double *U_)
+{     int ret = 0;
+      double L = *L_, U = *U_, LL, UU;
+      /* determine implied bounds of the row */
+      row_implied_bounds(f, &LL, &UU);
+      /* check if the original lower bound is infeasible */
+      if (L != -DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(L));
+         if (UU < L - eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original upper bound is infeasible */
+      if (U != +DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(U));
+         if (LL > U + eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original lower bound is redundant */
+      if (L != -DBL_MAX)
+      {  double eps = 1e-12 * (1.0 + fabs(L));
+         if (LL > L - eps)
+         {  /* it cannot be active, so remove it */
+            *L_ = -DBL_MAX;
+         }
+      }
+      /* check if the original upper bound is redundant */
+      if (U != +DBL_MAX)
+      {  double eps = 1e-12 * (1.0 + fabs(U));
+         if (UU < U + eps)
+         {  /* it cannot be active, so remove it */
+            *U_ = +DBL_MAX;
+         }
+      }
+done: return ret;
+}
+
+/***********************************************************************
+*  check_col_bounds - check and tighten original column bounds
+*
+*  Given a row (constraint)
+*
+*           n
+*     L <= sum a[j] * x[j] <= U
+*          j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  for column (variable) x[j] this routine checks the original column
+*  bounds l[j] and u[j] for feasibility and redundancy. If the original
+*  lower bound l[j] or/and upper bound u[j] cannot be active due to
+*  bounds of the constraint and other variables, the routine tighten
+*  them replacing by corresponding implied bounds, if possible.
+*
+*  NOTE: It is assumed that if L != -inf, the row lower bound can be
+*        active, and if U != +inf, the row upper bound can be active.
+*
+*  The flag means that variable x[j] is required to be integer.
+*
+*  New actual bounds for x[j] are stored in locations lj and uj.
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+static int check_col_bounds(const struct f_info *f, int n,
+      const double a[], double L, double U, const double l[],
+      const double u[], int flag, int j, double *_lj, double *_uj)
+{     int ret = 0;
+      double lj, uj, ll, uu;
+      xassert(n >= 0);
+      xassert(1 <= j && j <= n);
+      lj = l[j], uj = u[j];
+      /* determine implied bounds of the column */
+      col_implied_bounds(f, n, a, L, U, l, u, j, &ll, &uu);
+      /* if x[j] is integral, round its implied bounds */
+      if (flag)
+      {  if (ll != -DBL_MAX)
+            ll = (ll - floor(ll) < 1e-3 ? floor(ll) : ceil(ll));
+         if (uu != +DBL_MAX)
+            uu = (ceil(uu) - uu < 1e-3 ? ceil(uu) : floor(uu));
+      }
+      /* check if the original lower bound is infeasible */
+      if (lj != -DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(lj));
+         if (uu < lj - eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original upper bound is infeasible */
+      if (uj != +DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(uj));
+         if (ll > uj + eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original lower bound is redundant */
+      if (ll != -DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(ll));
+         if (lj < ll - eps)
+         {  /* it cannot be active, so tighten it */
+            lj = ll;
+         }
+      }
+      /* check if the original upper bound is redundant */
+      if (uu != +DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(uu));
+         if (uj > uu + eps)
+         {  /* it cannot be active, so tighten it */
+            uj = uu;
+         }
+      }
+      /* due to round-off errors it may happen that lj > uj (although
+         lj < uj + eps, since no primal infeasibility is detected), so
+         adjuct the new actual bounds to provide lj <= uj */
+      if (!(lj == -DBL_MAX || uj == +DBL_MAX))
+      {  double t1 = fabs(lj), t2 = fabs(uj);
+         double eps = 1e-10 * (1.0 + (t1 <= t2 ? t1 : t2));
+         if (lj > uj - eps)
+         {  if (lj == l[j])
+               uj = lj;
+            else if (uj == u[j])
+               lj = uj;
+            else if (t1 <= t2)
+               uj = lj;
+            else
+               lj = uj;
+         }
+      }
+      *_lj = lj, *_uj = uj;
+done: return ret;
+}
+
+/***********************************************************************
+*  check_efficiency - check if change in column bounds is efficient
+*
+*  Given the original bounds of a column l and u and its new actual
+*  bounds l' and u' (possibly tighten by the routine check_col_bounds)
+*  this routine checks if the change in the column bounds is efficient
+*  enough. If so, the routine returns non-zero, otherwise zero.
+*
+*  The flag means that the variable is required to be integer. */
+
+static int check_efficiency(int flag, double l, double u, double ll,
+      double uu)
+{     int eff = 0;
+      /* check efficiency for lower bound */
+      if (l < ll)
+      {  if (flag || l == -DBL_MAX)
+            eff++;
+         else
+         {  double r;
+            if (u == +DBL_MAX)
+               r = 1.0 + fabs(l);
+            else
+               r = 1.0 + (u - l);
+            if (ll - l >= 0.25 * r)
+               eff++;
+         }
+      }
+      /* check efficiency for upper bound */
+      if (u > uu)
+      {  if (flag || u == +DBL_MAX)
+            eff++;
+         else
+         {  double r;
+            if (l == -DBL_MAX)
+               r = 1.0 + fabs(u);
+            else
+               r = 1.0 + (u - l);
+            if (u - uu >= 0.25 * r)
+               eff++;
+         }
+      }
+      return eff;
+}
+
+/***********************************************************************
+*  basic_preprocessing - perform basic preprocessing
+*
+*  This routine performs basic preprocessing of the specified MIP that
+*  includes relaxing some row bounds and tightening some column bounds.
+*
+*  On entry the arrays L and U contains original row bounds, and the
+*  arrays l and u contains original column bounds:
+*
+*  L[0] is the lower bound of the objective row;
+*  L[i], i = 1,...,m, is the lower bound of i-th row;
+*  U[0] is the upper bound of the objective row;
+*  U[i], i = 1,...,m, is the upper bound of i-th row;
+*  l[0] is not used;
+*  l[j], j = 1,...,n, is the lower bound of j-th column;
+*  u[0] is not used;
+*  u[j], j = 1,...,n, is the upper bound of j-th column.
+*
+*  On exit the arrays L, U, l, and u contain new actual bounds of rows
+*  and column in the same locations.
+*
+*  The parameters nrs and num specify an initial list of rows to be
+*  processed:
+*
+*  nrs is the number of rows in the initial list, 0 <= nrs <= m+1;
+*  num[0] is not used;
+*  num[1,...,nrs] are row numbers (0 means the objective row).
+*
+*  The parameter max_pass specifies the maximal number of times that
+*  each row can be processed, max_pass > 0.
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+static int basic_preprocessing(glp_prob *mip, double L[], double U[],
+      double l[], double u[], int nrs, const int num[], int max_pass)
+{     int m = mip->m;
+      int n = mip->n;
+      struct f_info f;
+      int i, j, k, len, size, ret = 0;
+      int *ind, *list, *mark, *pass;
+      double *val, *lb, *ub;
+      xassert(0 <= nrs && nrs <= m+1);
+      xassert(max_pass > 0);
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      list = xcalloc(1+m+1, sizeof(int));
+      mark = xcalloc(1+m+1, sizeof(int));
+      memset(&mark[0], 0, (m+1) * sizeof(int));
+      pass = xcalloc(1+m+1, sizeof(int));
+      memset(&pass[0], 0, (m+1) * sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      lb = xcalloc(1+n, sizeof(double));
+      ub = xcalloc(1+n, sizeof(double));
+      /* initialize the list of rows to be processed */
+      size = 0;
+      for (k = 1; k <= nrs; k++)
+      {  i = num[k];
+         xassert(0 <= i && i <= m);
+         /* duplicate row numbers are not allowed */
+         xassert(!mark[i]);
+         list[++size] = i, mark[i] = 1;
+      }
+      xassert(size == nrs);
+      /* process rows in the list until it becomes empty */
+      while (size > 0)
+      {  /* get a next row from the list */
+         i = list[size--], mark[i] = 0;
+         /* increase the row processing count */
+         pass[i]++;
+         /* if the row is free, skip it */
+         if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
+         /* obtain coefficients of the row */
+         len = 0;
+         if (i == 0)
+         {  for (j = 1; j <= n; j++)
+            {  GLPCOL *col = mip->col[j];
+               if (col->coef != 0.0)
+                  len++, ind[len] = j, val[len] = col->coef;
+            }
+         }
+         else
+         {  GLPROW *row = mip->row[i];
+            GLPAIJ *aij;
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               len++, ind[len] = aij->col->j, val[len] = aij->val;
+         }
+         /* determine lower and upper bounds of columns corresponding
+            to non-zero row coefficients */
+         for (k = 1; k <= len; k++)
+            j = ind[k], lb[k] = l[j], ub[k] = u[j];
+         /* prepare the row info to determine implied bounds */
+         prepare_row_info(len, val, lb, ub, &f);
+         /* check and relax bounds of the row */
+         if (check_row_bounds(&f, &L[i], &U[i]))
+         {  /* the feasible region is empty */
+            ret = 1;
+            goto done;
+         }
+         /* if the row became free, drop it */
+         if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
+         /* process columns having non-zero coefficients in the row */
+         for (k = 1; k <= len; k++)
+         {  GLPCOL *col;
+            int flag, eff;
+            double ll, uu;
+            /* take a next column in the row */
+            j = ind[k], col = mip->col[j];
+            flag = col->kind != GLP_CV;
+            /* check and tighten bounds of the column */
+            if (check_col_bounds(&f, len, val, L[i], U[i], lb, ub,
+                flag, k, &ll, &uu))
+            {  /* the feasible region is empty */
+               ret = 1;
+               goto done;
+            }
+            /* check if change in the column bounds is efficient */
+            eff = check_efficiency(flag, l[j], u[j], ll, uu);
+            /* set new actual bounds of the column */
+            l[j] = ll, u[j] = uu;
+            /* if the change is efficient, add all rows affected by the
+               corresponding column, to the list */
+            if (eff > 0)
+            {  GLPAIJ *aij;
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+               {  int ii = aij->row->i;
+                  /* if the row was processed maximal number of times,
+                     skip it */
+                  if (pass[ii] >= max_pass) continue;
+                  /* if the row is free, skip it */
+                  if (L[ii] == -DBL_MAX && U[ii] == +DBL_MAX) continue;
+                  /* put the row into the list */
+                  if (mark[ii] == 0)
+                  {  xassert(size <= m);
+                     list[++size] = ii, mark[ii] = 1;
+                  }
+               }
+            }
+         }
+      }
+done: /* free working arrays */
+      xfree(ind);
+      xfree(list);
+      xfree(mark);
+      xfree(pass);
+      xfree(val);
+      xfree(lb);
+      xfree(ub);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_preprocess_node - preprocess current subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_preprocess_node(glp_tree *tree, int max_pass);
+*
+*  DESCRIPTION
+*
+*  The routine ios_preprocess_node performs basic preprocessing of the
+*  current subproblem.
+*
+*  RETURNS
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+int ios_preprocess_node(glp_tree *tree, int max_pass)
+{     glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      int i, j, nrs, *num, ret = 0;
+      double *L, *U, *l, *u;
+      /* the current subproblem must exist */
+      xassert(tree->curr != NULL);
+      /* determine original row bounds */
+      L = xcalloc(1+m, sizeof(double));
+      U = xcalloc(1+m, sizeof(double));
+      switch (mip->mip_stat)
+      {  case GLP_UNDEF:
+            L[0] = -DBL_MAX, U[0] = +DBL_MAX;
+            break;
+         case GLP_FEAS:
+            switch (mip->dir)
+            {  case GLP_MIN:
+                  L[0] = -DBL_MAX, U[0] = mip->mip_obj - mip->c0;
+                  break;
+               case GLP_MAX:
+                  L[0] = mip->mip_obj - mip->c0, U[0] = +DBL_MAX;
+                  break;
+               default:
+                  xassert(mip != mip);
+            }
+            break;
+         default:
+            xassert(mip != mip);
+      }
+      for (i = 1; i <= m; i++)
+      {  L[i] = glp_get_row_lb(mip, i);
+         U[i] = glp_get_row_ub(mip, i);
+      }
+      /* determine original column bounds */
+      l = xcalloc(1+n, sizeof(double));
+      u = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  l[j] = glp_get_col_lb(mip, j);
+         u[j] = glp_get_col_ub(mip, j);
+      }
+      /* build the initial list of rows to be analyzed */
+      nrs = m + 1;
+      num = xcalloc(1+nrs, sizeof(int));
+      for (i = 1; i <= nrs; i++) num[i] = i - 1;
+      /* perform basic preprocessing */
+      if (basic_preprocessing(mip , L, U, l, u, nrs, num, max_pass))
+      {  ret = 1;
+         goto done;
+      }
+      /* set new actual (relaxed) row bounds */
+      for (i = 1; i <= m; i++)
+      {  /* consider only non-active rows to keep dual feasibility */
+         if (glp_get_row_stat(mip, i) == GLP_BS)
+         {  if (L[i] == -DBL_MAX && U[i] == +DBL_MAX)
+               glp_set_row_bnds(mip, i, GLP_FR, 0.0, 0.0);
+            else if (U[i] == +DBL_MAX)
+               glp_set_row_bnds(mip, i, GLP_LO, L[i], 0.0);
+            else if (L[i] == -DBL_MAX)
+               glp_set_row_bnds(mip, i, GLP_UP, 0.0, U[i]);
+         }
+      }
+      /* set new actual (tightened) column bounds */
+      for (j = 1; j <= n; j++)
+      {  int type;
+         if (l[j] == -DBL_MAX && u[j] == +DBL_MAX)
+            type = GLP_FR;
+         else if (u[j] == +DBL_MAX)
+            type = GLP_LO;
+         else if (l[j] == -DBL_MAX)
+            type = GLP_UP;
+         else if (l[j] != u[j])
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(mip, j, type, l[j], u[j]);
+      }
+done: /* free working arrays and return */
+      xfree(L);
+      xfree(U);
+      xfree(l);
+      xfree(u);
+      xfree(num);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios03.c b/optional/glpk/glpios03.c
new file mode 100644
index 0000000..d2ef65c
--- /dev/null
+++ b/optional/glpk/glpios03.c
@@ -0,0 +1,1160 @@
+/* glpios03.c (branch-and-cut driver) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  show_progress - display current progress of the search
+*
+*  This routine displays some information about current progress of the
+*  search.
+*
+*  The information includes:
+*
+*  the current number of iterations performed by the simplex solver;
+*
+*  the objective value for the best known integer feasible solution,
+*  which is upper (minimization) or lower (maximization) global bound
+*  for optimal solution of the original mip problem;
+*
+*  the best local bound for active nodes, which is lower (minimization)
+*  or upper (maximization) global bound for optimal solution of the
+*  original mip problem;
+*
+*  the relative mip gap, in percents;
+*
+*  the number of open (active) subproblems;
+*
+*  the number of completely explored subproblems, i.e. whose nodes have
+*  been removed from the tree. */
+
+static void show_progress(glp_tree *T, int bingo)
+{     int p;
+      double temp;
+      char best_mip[50], best_bound[50], *rho, rel_gap[50];
+      /* format the best known integer feasible solution */
+      if (T->mip->mip_stat == GLP_FEAS)
+         sprintf(best_mip, "%17.9e", T->mip->mip_obj);
+      else
+         sprintf(best_mip, "%17s", "not found yet");
+      /* determine reference number of an active subproblem whose local
+         bound is best */
+      p = ios_best_node(T);
+      /* format the best bound */
+      if (p == 0)
+         sprintf(best_bound, "%17s", "tree is empty");
+      else
+      {  temp = T->slot[p].node->bound;
+         if (temp == -DBL_MAX)
+            sprintf(best_bound, "%17s", "-inf");
+         else if (temp == +DBL_MAX)
+            sprintf(best_bound, "%17s", "+inf");
+         else
+            sprintf(best_bound, "%17.9e", temp);
+      }
+      /* choose the relation sign between global bounds */
+      if (T->mip->dir == GLP_MIN)
+         rho = ">=";
+      else if (T->mip->dir == GLP_MAX)
+         rho = "<=";
+      else
+         xassert(T != T);
+      /* format the relative mip gap */
+      temp = ios_relative_gap(T);
+      if (temp == 0.0)
+         sprintf(rel_gap, "  0.0%%");
+      else if (temp < 0.001)
+         sprintf(rel_gap, "< 0.1%%");
+      else if (temp <= 9.999)
+         sprintf(rel_gap, "%5.1f%%", 100.0 * temp);
+      else
+         sprintf(rel_gap, "%6s", "");
+      /* display progress of the search */
+      xprintf("+%6d: %s %s %s %s %s (%d; %d)\n",
+         T->mip->it_cnt, bingo ? ">>>>>" : "mip =", best_mip, rho,
+         best_bound, rel_gap, T->a_cnt, T->t_cnt - T->n_cnt);
+      T->tm_lag = xtime();
+      return;
+}
+
+/***********************************************************************
+*  is_branch_hopeful - check if specified branch is hopeful
+*
+*  This routine checks if the specified subproblem can have an integer
+*  optimal solution which is better than the best known one.
+*
+*  The check is based on comparison of the local objective bound stored
+*  in the subproblem descriptor and the incumbent objective value which
+*  is the global objective bound.
+*
+*  If there is a chance that the specified subproblem can have a better
+*  integer optimal solution, the routine returns non-zero. Otherwise, if
+*  the corresponding branch can pruned, zero is returned. */
+
+static int is_branch_hopeful(glp_tree *T, int p)
+{     xassert(1 <= p && p <= T->nslots);
+      xassert(T->slot[p].node != NULL);
+      return ios_is_hopeful(T, T->slot[p].node->bound);
+}
+
+/***********************************************************************
+*  check_integrality - check integrality of basic solution
+*
+*  This routine checks if the basic solution of LP relaxation of the
+*  current subproblem satisfies to integrality conditions, i.e. that all
+*  variables of integer kind have integral primal values. (The solution
+*  is assumed to be optimal.)
+*
+*  For each variable of integer kind the routine computes the following
+*  quantity:
+*
+*     ii(x[j]) = min(x[j] - floor(x[j]), ceil(x[j]) - x[j]),         (1)
+*
+*  which is a measure of the integer infeasibility (non-integrality) of
+*  x[j] (for example, ii(2.1) = 0.1, ii(3.7) = 0.3, ii(5.0) = 0). It is
+*  understood that 0 <= ii(x[j]) <= 0.5, and variable x[j] is integer
+*  feasible if ii(x[j]) = 0. However, due to floating-point arithmetic
+*  the routine checks less restrictive condition:
+*
+*     ii(x[j]) <= tol_int,                                           (2)
+*
+*  where tol_int is a given tolerance (small positive number) and marks
+*  each variable which does not satisfy to (2) as integer infeasible by
+*  setting its fractionality flag.
+*
+*  In order to characterize integer infeasibility of the basic solution
+*  in the whole the routine computes two parameters: ii_cnt, which is
+*  the number of variables with the fractionality flag set, and ii_sum,
+*  which is the sum of integer infeasibilities (1). */
+
+static void check_integrality(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int j, type, ii_cnt = 0;
+      double lb, ub, x, temp1, temp2, ii_sum = 0.0;
+      /* walk through the set of columns (structural variables) */
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         T->non_int[j] = 0;
+         /* if the column is not integer, skip it */
+         if (col->kind != GLP_IV) continue;
+         /* if the column is non-basic, it is integer feasible */
+         if (col->stat != GLP_BS) continue;
+         /* obtain the type and bounds of the column */
+         type = col->type, lb = col->lb, ub = col->ub;
+         /* obtain value of the column in optimal basic solution */
+         x = col->prim;
+         /* if the column's primal value is close to the lower bound,
+            the column is integer feasible within given tolerance */
+         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+         {  temp1 = lb - T->parm->tol_int;
+            temp2 = lb + T->parm->tol_int;
+            if (temp1 <= x && x <= temp2) continue;
+#if 0
+            /* the lower bound must not be violated */
+            xassert(x >= lb);
+#else
+            if (x < lb) continue;
+#endif
+         }
+         /* if the column's primal value is close to the upper bound,
+            the column is integer feasible within given tolerance */
+         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+         {  temp1 = ub - T->parm->tol_int;
+            temp2 = ub + T->parm->tol_int;
+            if (temp1 <= x && x <= temp2) continue;
+#if 0
+            /* the upper bound must not be violated */
+            xassert(x <= ub);
+#else
+            if (x > ub) continue;
+#endif
+         }
+         /* if the column's primal value is close to nearest integer,
+            the column is integer feasible within given tolerance */
+         temp1 = floor(x + 0.5) - T->parm->tol_int;
+         temp2 = floor(x + 0.5) + T->parm->tol_int;
+         if (temp1 <= x && x <= temp2) continue;
+         /* otherwise the column is integer infeasible */
+         T->non_int[j] = 1;
+         /* increase the number of fractional-valued columns */
+         ii_cnt++;
+         /* compute the sum of integer infeasibilities */
+         temp1 = x - floor(x);
+         temp2 = ceil(x) - x;
+         xassert(temp1 > 0.0 && temp2 > 0.0);
+         ii_sum += (temp1 <= temp2 ? temp1 : temp2);
+      }
+      /* store ii_cnt and ii_sum to the current problem descriptor */
+      xassert(T->curr != NULL);
+      T->curr->ii_cnt = ii_cnt;
+      T->curr->ii_sum = ii_sum;
+      /* and also display these parameters */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  if (ii_cnt == 0)
+            xprintf("There are no fractional columns\n");
+         else if (ii_cnt == 1)
+            xprintf("There is one fractional column, integer infeasibil"
+               "ity is %.3e\n", ii_sum);
+         else
+            xprintf("There are %d fractional columns, integer infeasibi"
+               "lity is %.3e\n", ii_cnt, ii_sum);
+      }
+      return;
+}
+
+/***********************************************************************
+*  record_solution - record better integer feasible solution
+*
+*  This routine records optimal basic solution of LP relaxation of the
+*  current subproblem, which being integer feasible is better than the
+*  best known integer feasible solution. */
+
+static void record_solution(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int i, j;
+      mip->mip_stat = GLP_FEAS;
+      mip->mip_obj = mip->obj_val;
+      for (i = 1; i <= mip->m; i++)
+      {  GLPROW *row = mip->row[i];
+         row->mipx = row->prim;
+      }
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         if (col->kind == GLP_CV)
+            col->mipx = col->prim;
+         else if (col->kind == GLP_IV)
+         {  /* value of the integer column must be integral */
+            col->mipx = floor(col->prim + 0.5);
+         }
+         else
+            xassert(col != col);
+      }
+      T->sol_cnt++;
+      return;
+}
+
+/***********************************************************************
+*  fix_by_red_cost - fix non-basic integer columns by reduced costs
+*
+*  This routine fixes some non-basic integer columns if their reduced
+*  costs indicate that increasing (decreasing) the column at least by
+*  one involves the objective value becoming worse than the incumbent
+*  objective value. */
+
+static void fix_by_red_cost(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int j, stat, fixed = 0;
+      double obj, lb, ub, dj;
+      /* the global bound must exist */
+      xassert(T->mip->mip_stat == GLP_FEAS);
+      /* basic solution of LP relaxation must be optimal */
+      xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
+      /* determine the objective function value */
+      obj = mip->obj_val;
+      /* walk through the column list */
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         /* if the column is not integer, skip it */
+         if (col->kind != GLP_IV) continue;
+         /* obtain bounds of j-th column */
+         lb = col->lb, ub = col->ub;
+         /* and determine its status and reduced cost */
+         stat = col->stat, dj = col->dual;
+         /* analyze the reduced cost */
+         switch (mip->dir)
+         {  case GLP_MIN:
+               /* minimization */
+               if (stat == GLP_NL)
+               {  /* j-th column is non-basic on its lower bound */
+                  if (dj < 0.0) dj = 0.0;
+                  if (obj + dj >= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
+               }
+               else if (stat == GLP_NU)
+               {  /* j-th column is non-basic on its upper bound */
+                  if (dj > 0.0) dj = 0.0;
+                  if (obj - dj >= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
+               }
+               break;
+            case GLP_MAX:
+               /* maximization */
+               if (stat == GLP_NL)
+               {  /* j-th column is non-basic on its lower bound */
+                  if (dj > 0.0) dj = 0.0;
+                  if (obj + dj <= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
+               }
+               else if (stat == GLP_NU)
+               {  /* j-th column is non-basic on its upper bound */
+                  if (dj < 0.0) dj = 0.0;
+                  if (obj - dj <= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
+               }
+               break;
+            default:
+               xassert(T != T);
+         }
+      }
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  if (fixed == 0)
+            /* nothing to say */;
+         else if (fixed == 1)
+            xprintf("One column has been fixed by reduced cost\n");
+         else
+            xprintf("%d columns have been fixed by reduced costs\n",
+               fixed);
+      }
+      /* fixing non-basic columns on their current bounds does not
+         change the basic solution */
+      xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
+      return;
+}
+
+/***********************************************************************
+*  branch_on - perform branching on specified variable
+*
+*  This routine performs branching on j-th column (structural variable)
+*  of the current subproblem. The specified column must be of integer
+*  kind and must have a fractional value in optimal basic solution of
+*  LP relaxation of the current subproblem (i.e. only columns for which
+*  the flag non_int[j] is set are valid candidates to branch on).
+*
+*  Let x be j-th structural variable, and beta be its primal fractional
+*  value in the current basic solution. Branching on j-th variable is
+*  dividing the current subproblem into two new subproblems, which are
+*  identical to the current subproblem with the following exception: in
+*  the first subproblem that begins the down-branch x has a new upper
+*  bound x <= floor(beta), and in the second subproblem that begins the
+*  up-branch x has a new lower bound x >= ceil(beta).
+*
+*  Depending on estimation of local bounds for down- and up-branches
+*  this routine returns the following:
+*
+*  0 - both branches have been created;
+*  1 - one branch is hopeless and has been pruned, so now the current
+*      subproblem is other branch;
+*  2 - both branches are hopeless and have been pruned; new subproblem
+*      selection is needed to continue the search. */
+
+static int branch_on(glp_tree *T, int j, int next)
+{     glp_prob *mip = T->mip;
+      IOSNPD *node;
+      int m = mip->m;
+      int n = mip->n;
+      int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2];
+      double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd;
+      /* determine bounds and value of x[j] in optimal solution to LP
+         relaxation of the current subproblem */
+      xassert(1 <= j && j <= n);
+      type = mip->col[j]->type;
+      lb = mip->col[j]->lb;
+      ub = mip->col[j]->ub;
+      beta = mip->col[j]->prim;
+      /* determine new bounds of x[j] for down- and up-branches */
+      new_ub = floor(beta);
+      new_lb = ceil(beta);
+      switch (type)
+      {  case GLP_FR:
+            dn_type = GLP_UP;
+            up_type = GLP_LO;
+            break;
+         case GLP_LO:
+            xassert(lb <= new_ub);
+            dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
+            xassert(lb + 1.0 <= new_lb);
+            up_type = GLP_LO;
+            break;
+         case GLP_UP:
+            xassert(new_ub <= ub - 1.0);
+            dn_type = GLP_UP;
+            xassert(new_lb <= ub);
+            up_type = (new_lb == ub ? GLP_FX : GLP_DB);
+            break;
+         case GLP_DB:
+            xassert(lb <= new_ub && new_ub <= ub - 1.0);
+            dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
+            xassert(lb + 1.0 <= new_lb && new_lb <= ub);
+            up_type = (new_lb == ub ? GLP_FX : GLP_DB);
+            break;
+         default:
+            xassert(type != type);
+      }
+      /* compute local bounds to LP relaxation for both branches */
+      ios_eval_degrad(T, j, &dn_lp, &up_lp);
+      /* and improve them by rounding */
+      dn_bnd = ios_round_bound(T, dn_lp);
+      up_bnd = ios_round_bound(T, up_lp);
+      /* check local bounds for down- and up-branches */
+      dn_bad = !ios_is_hopeful(T, dn_bnd);
+      up_bad = !ios_is_hopeful(T, up_bnd);
+      if (dn_bad && up_bad)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Both down- and up-branches are hopeless\n");
+         ret = 2;
+         goto done;
+      }
+      else if (up_bad)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Up-branch is hopeless\n");
+         glp_set_col_bnds(mip, j, dn_type, lb, new_ub);
+         T->curr->lp_obj = dn_lp;
+         if (mip->dir == GLP_MIN)
+         {  if (T->curr->bound < dn_bnd)
+                T->curr->bound = dn_bnd;
+         }
+         else if (mip->dir == GLP_MAX)
+         {  if (T->curr->bound > dn_bnd)
+                T->curr->bound = dn_bnd;
+         }
+         else
+            xassert(mip != mip);
+         ret = 1;
+         goto done;
+      }
+      else if (dn_bad)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Down-branch is hopeless\n");
+         glp_set_col_bnds(mip, j, up_type, new_lb, ub);
+         T->curr->lp_obj = up_lp;
+         if (mip->dir == GLP_MIN)
+         {  if (T->curr->bound < up_bnd)
+                T->curr->bound = up_bnd;
+         }
+         else if (mip->dir == GLP_MAX)
+         {  if (T->curr->bound > up_bnd)
+                T->curr->bound = up_bnd;
+         }
+         else
+            xassert(mip != mip);
+         ret = 1;
+         goto done;
+      }
+      /* both down- and up-branches seem to be hopeful */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Branching on column %d, primal value is %.9e\n",
+            j, beta);
+      /* determine the reference number of the current subproblem */
+      xassert(T->curr != NULL);
+      p = T->curr->p;
+      T->curr->br_var = j;
+      T->curr->br_val = beta;
+      /* freeze the current subproblem */
+      ios_freeze_node(T);
+      /* create two clones of the current subproblem; the first clone
+         begins the down-branch, the second one begins the up-branch */
+      ios_clone_node(T, p, 2, clone);
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Node %d begins down branch, node %d begins up branch "
+            "\n", clone[1], clone[2]);
+      /* set new upper bound of j-th column in the down-branch */
+      node = T->slot[clone[1]].node;
+      xassert(node != NULL);
+      xassert(node->up != NULL);
+      xassert(node->b_ptr == NULL);
+      node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
+      node->b_ptr->k = m + j;
+      node->b_ptr->type = (unsigned char)dn_type;
+      node->b_ptr->lb = lb;
+      node->b_ptr->ub = new_ub;
+      node->b_ptr->next = NULL;
+      node->lp_obj = dn_lp;
+      if (mip->dir == GLP_MIN)
+      {  if (node->bound < dn_bnd)
+             node->bound = dn_bnd;
+      }
+      else if (mip->dir == GLP_MAX)
+      {  if (node->bound > dn_bnd)
+             node->bound = dn_bnd;
+      }
+      else
+         xassert(mip != mip);
+      /* set new lower bound of j-th column in the up-branch */
+      node = T->slot[clone[2]].node;
+      xassert(node != NULL);
+      xassert(node->up != NULL);
+      xassert(node->b_ptr == NULL);
+      node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
+      node->b_ptr->k = m + j;
+      node->b_ptr->type = (unsigned char)up_type;
+      node->b_ptr->lb = new_lb;
+      node->b_ptr->ub = ub;
+      node->b_ptr->next = NULL;
+      node->lp_obj = up_lp;
+      if (mip->dir == GLP_MIN)
+      {  if (node->bound < up_bnd)
+             node->bound = up_bnd;
+      }
+      else if (mip->dir == GLP_MAX)
+      {  if (node->bound > up_bnd)
+             node->bound = up_bnd;
+      }
+      else
+         xassert(mip != mip);
+      /* suggest the subproblem to be solved next */
+      xassert(T->child == 0);
+      if (next == GLP_NO_BRNCH)
+         T->child = 0;
+      else if (next == GLP_DN_BRNCH)
+         T->child = clone[1];
+      else if (next == GLP_UP_BRNCH)
+         T->child = clone[2];
+      else
+         xassert(next != next);
+      ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+*  cleanup_the_tree - prune hopeless branches from the tree
+*
+*  This routine walks through the active list and checks the local
+*  bound for every active subproblem. If the local bound indicates that
+*  the subproblem cannot have integer optimal solution better than the
+*  incumbent objective value, the routine deletes such subproblem that,
+*  in turn, involves pruning the corresponding branch of the tree. */
+
+static void cleanup_the_tree(glp_tree *T)
+{     IOSNPD *node, *next_node;
+      int count = 0;
+      /* the global bound must exist */
+      xassert(T->mip->mip_stat == GLP_FEAS);
+      /* walk through the list of active subproblems */
+      for (node = T->head; node != NULL; node = next_node)
+      {  /* deleting some active problem node may involve deleting its
+            parents recursively; however, all its parents being created
+            *before* it are always *precede* it in the node list, so
+            the next problem node is never affected by such deletion */
+         next_node = node->next;
+         /* if the branch is hopeless, prune it */
+         if (!is_branch_hopeful(T, node->p))
+            ios_delete_node(T, node->p), count++;
+      }
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  if (count == 1)
+            xprintf("One hopeless branch has been pruned\n");
+         else if (count > 1)
+            xprintf("%d hopeless branches have been pruned\n", count);
+      }
+      return;
+}
+
+/**********************************************************************/
+
+static void generate_cuts(glp_tree *T)
+{     /* generate generic cuts with built-in generators */
+      if (!(T->parm->mir_cuts == GLP_ON ||
+            T->parm->gmi_cuts == GLP_ON ||
+            T->parm->cov_cuts == GLP_ON ||
+            T->parm->clq_cuts == GLP_ON)) goto done;
+#if 1 /* 20/IX-2008 */
+      {  int i, max_cuts, added_cuts;
+         max_cuts = T->n;
+         if (max_cuts < 1000) max_cuts = 1000;
+         added_cuts = 0;
+         for (i = T->orig_m+1; i <= T->mip->m; i++)
+         {  if (T->mip->row[i]->origin == GLP_RF_CUT)
+               added_cuts++;
+         }
+         /* xprintf("added_cuts = %d\n", added_cuts); */
+         if (added_cuts >= max_cuts) goto done;
+      }
+#endif
+      /* generate and add to POOL all cuts violated by x* */
+      if (T->parm->gmi_cuts == GLP_ON)
+      {  if (T->curr->changed < 5)
+            ios_gmi_gen(T);
+      }
+      if (T->parm->mir_cuts == GLP_ON)
+      {  xassert(T->mir_gen != NULL);
+         ios_mir_gen(T, T->mir_gen);
+      }
+      if (T->parm->cov_cuts == GLP_ON)
+      {  /* cover cuts works well along with mir cuts */
+         /*if (T->round <= 5)*/
+            ios_cov_gen(T);
+      }
+      if (T->parm->clq_cuts == GLP_ON)
+      {  if (T->clq_gen != NULL)
+         {  if (T->curr->level == 0 && T->curr->changed < 50 ||
+                T->curr->level >  0 && T->curr->changed < 5)
+               ios_clq_gen(T, T->clq_gen);
+         }
+      }
+done: return;
+}
+
+/**********************************************************************/
+
+static void remove_cuts(glp_tree *T)
+{     /* remove inactive cuts (some valueable globally valid cut might
+         be saved in the global cut pool) */
+      int i, cnt = 0, *num = NULL;
+      xassert(T->curr != NULL);
+      for (i = T->orig_m+1; i <= T->mip->m; i++)
+      {  if (T->mip->row[i]->origin == GLP_RF_CUT &&
+             T->mip->row[i]->level == T->curr->level &&
+             T->mip->row[i]->stat == GLP_BS)
+         {  if (num == NULL)
+               num = xcalloc(1+T->mip->m, sizeof(int));
+            num[++cnt] = i;
+         }
+      }
+      if (cnt > 0)
+      {  glp_del_rows(T->mip, cnt, num);
+#if 0
+         xprintf("%d inactive cut(s) removed\n", cnt);
+#endif
+         xfree(num);
+         xassert(glp_factorize(T->mip) == 0);
+      }
+      return;
+}
+
+/**********************************************************************/
+
+static void display_cut_info(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int i, gmi = 0, mir = 0, cov = 0, clq = 0, app = 0;
+      for (i = mip->m; i > 0; i--)
+      {  GLPROW *row;
+         row = mip->row[i];
+         /* if (row->level < T->curr->level) break; */
+         if (row->origin == GLP_RF_CUT)
+         {  if (row->klass == GLP_RF_GMI)
+               gmi++;
+            else if (row->klass == GLP_RF_MIR)
+               mir++;
+            else if (row->klass == GLP_RF_COV)
+               cov++;
+            else if (row->klass == GLP_RF_CLQ)
+               clq++;
+            else
+               app++;
+         }
+      }
+      xassert(T->curr != NULL);
+      if (gmi + mir + cov + clq + app > 0)
+      {  xprintf("Cuts on level %d:", T->curr->level);
+         if (gmi > 0) xprintf(" gmi = %d;", gmi);
+         if (mir > 0) xprintf(" mir = %d;", mir);
+         if (cov > 0) xprintf(" cov = %d;", cov);
+         if (clq > 0) xprintf(" clq = %d;", clq);
+         if (app > 0) xprintf(" app = %d;", app);
+         xprintf("\n");
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_driver - branch-and-cut driver
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_driver(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_driver is a branch-and-cut driver. It controls the
+*  MIP solution process.
+*
+*  RETURNS
+*
+*  0  The MIP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EFAIL
+*     The search was prematurely terminated due to the solver failure.
+*
+*  GLP_EMIPGAP
+*     The search was prematurely terminated, because the relative mip
+*     gap tolerance has been reached.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded.
+*
+*  GLP_ESTOP
+*     The search was prematurely terminated by application. */
+
+int ios_driver(glp_tree *T)
+{     int p, curr_p, p_stat, d_stat, ret;
+#if 1 /* carry out to glp_tree */
+      int pred_p = 0;
+      /* if the current subproblem has been just created due to
+         branching, pred_p is the reference number of its parent
+         subproblem, otherwise pred_p is zero */
+#endif
+      glp_long ttt = T->tm_beg;
+#if 0
+      ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG;
+#endif
+      /* on entry to the B&B driver it is assumed that the active list
+         contains the only active (i.e. root) subproblem, which is the
+         original MIP problem to be solved */
+loop: /* main loop starts here */
+      /* at this point the current subproblem does not exist */
+      xassert(T->curr == NULL);
+      /* if the active list is empty, the search is finished */
+      if (T->head == NULL)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Active list is empty!\n");
+         xassert(dmp_in_use(T->pool).lo == 0);
+         ret = 0;
+         goto done;
+      }
+      /* select some active subproblem to continue the search */
+      xassert(T->next_p == 0);
+      /* let the application program select subproblem */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ISELECT;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      if (T->next_p != 0)
+      {  /* the application program has selected something */
+         ;
+      }
+      else if (T->a_cnt == 1)
+      {  /* the only active subproblem exists, so select it */
+         xassert(T->head->next == NULL);
+         T->next_p = T->head->p;
+      }
+      else if (T->child != 0)
+      {  /* select one of branching childs suggested by the branching
+            heuristic */
+         T->next_p = T->child;
+      }
+      else
+      {  /* select active subproblem as specified by the backtracking
+            technique option */
+         T->next_p = ios_choose_node(T);
+      }
+      /* the active subproblem just selected becomes current */
+      ios_revive_node(T, T->next_p);
+      T->next_p = T->child = 0;
+      /* invalidate pred_p, if it is not the reference number of the
+         parent of the current subproblem */
+      if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0;
+      /* determine the reference number of the current subproblem */
+      p = T->curr->p;
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  xprintf("-----------------------------------------------------"
+            "-------------------\n");
+         xprintf("Processing node %d at level %d\n", p, T->curr->level);
+      }
+      /* if it is the root subproblem, initialize cut generators */
+      if (p == 1)
+      {  if (T->parm->gmi_cuts == GLP_ON)
+         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("Gomory's cuts enabled\n");
+         }
+         if (T->parm->mir_cuts == GLP_ON)
+         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("MIR cuts enabled\n");
+            xassert(T->mir_gen == NULL);
+            T->mir_gen = ios_mir_init(T);
+         }
+         if (T->parm->cov_cuts == GLP_ON)
+         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("Cover cuts enabled\n");
+         }
+         if (T->parm->clq_cuts == GLP_ON)
+         {  xassert(T->clq_gen == NULL);
+            if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("Clique cuts enabled\n");
+            T->clq_gen = ios_clq_init(T);
+         }
+      }
+more: /* minor loop starts here */
+      /* at this point the current subproblem needs either to be solved
+         for the first time or re-optimized due to reformulation */
+      /* display current progress of the search */
+      if (T->parm->msg_lev >= GLP_MSG_DBG ||
+          T->parm->msg_lev >= GLP_MSG_ON &&
+        (double)(T->parm->out_frq - 1) <=
+            1000.0 * xdifftime(xtime(), T->tm_lag))
+         show_progress(T, 0);
+      if (T->parm->msg_lev >= GLP_MSG_ALL &&
+            xdifftime(xtime(), ttt) >= 60.0)
+      {  glp_long total;
+         glp_mem_usage(NULL, NULL, &total, NULL);
+         xprintf("Time used: %.1f secs.  Memory used: %.1f Mb.\n",
+            xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0);
+         ttt = xtime();
+      }
+      /* check the mip gap */
+      if (T->parm->mip_gap > 0.0 &&
+          ios_relative_gap(T) <= T->parm->mip_gap)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Relative gap tolerance reached; search terminated "
+               "\n");
+         ret = GLP_EMIPGAP;
+         goto done;
+      }
+      /* check if the time limit has been exhausted */
+      if (T->parm->tm_lim < INT_MAX &&
+         (double)(T->parm->tm_lim - 1) <=
+         1000.0 * xdifftime(xtime(), T->tm_beg))
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Time limit exhausted; search terminated\n");
+         ret = GLP_ETMLIM;
+         goto done;
+      }
+      /* let the application program preprocess the subproblem */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IPREPRO;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      /* perform basic preprocessing */
+      if (T->parm->pp_tech == GLP_PP_NONE)
+         ;
+      else if (T->parm->pp_tech == GLP_PP_ROOT)
+      {  if (T->curr->level == 0)
+         {  if (ios_preprocess_node(T, 100))
+               goto fath;
+         }
+      }
+      else if (T->parm->pp_tech == GLP_PP_ALL)
+      {  if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10))
+            goto fath;
+      }
+      else
+         xassert(T != T);
+      /* preprocessing may improve the global bound */
+      if (!is_branch_hopeful(T, p))
+      {  xprintf("*** not tested yet ***\n");
+         goto fath;
+      }
+      /* solve LP relaxation of the current subproblem */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Solving LP relaxation...\n");
+      ret = ios_solve_node(T);
+      if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL))
+      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("ios_driver: unable to solve current LP relaxation;"
+               " glp_simplex returned %d\n", ret);
+         ret = GLP_EFAIL;
+         goto done;
+      }
+      /* analyze status of the basic solution to LP relaxation found */
+      p_stat = T->mip->pbs_stat;
+      d_stat = T->mip->dbs_stat;
+      if (p_stat == GLP_FEAS && d_stat == GLP_FEAS)
+      {  /* LP relaxation has optimal solution */
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Found optimal solution to LP relaxation\n");
+      }
+      else if (d_stat == GLP_NOFEAS)
+      {  /* LP relaxation has no dual feasible solution */
+         /* since the current subproblem cannot have a larger feasible
+            region than its parent, there is something wrong */
+         if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("ios_driver: current LP relaxation has no dual feas"
+               "ible solution\n");
+         ret = GLP_EFAIL;
+         goto done;
+      }
+      else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS)
+      {  /* LP relaxation has no primal solution which is better than
+            the incumbent objective value */
+         xassert(T->mip->mip_stat == GLP_FEAS);
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("LP relaxation has no solution better than incumben"
+               "t objective value\n");
+         /* prune the branch */
+         goto fath;
+      }
+      else if (p_stat == GLP_NOFEAS)
+      {  /* LP relaxation has no primal feasible solution */
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("LP relaxation has no feasible solution\n");
+         /* prune the branch */
+         goto fath;
+      }
+      else
+      {  /* other cases cannot appear */
+         xassert(T->mip != T->mip);
+      }
+      /* at this point basic solution to LP relaxation of the current
+         subproblem is optimal */
+      xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS);
+      xassert(T->curr != NULL);
+      T->curr->lp_obj = T->mip->obj_val;
+      /* thus, it defines a local bound to integer optimal solution of
+         the current subproblem */
+      {  double bound = T->mip->obj_val;
+         /* some local bound to the current subproblem could be already
+            set before, so we should only improve it */
+         bound = ios_round_bound(T, bound);
+         if (T->mip->dir == GLP_MIN)
+         {  if (T->curr->bound < bound)
+               T->curr->bound = bound;
+         }
+         else if (T->mip->dir == GLP_MAX)
+         {  if (T->curr->bound > bound)
+               T->curr->bound = bound;
+         }
+         else
+            xassert(T->mip != T->mip);
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Local bound is %.9e\n", bound);
+      }
+      /* if the local bound indicates that integer optimal solution of
+         the current subproblem cannot be better than the global bound,
+         prune the branch */
+      if (!is_branch_hopeful(T, p))
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Current branch is hopeless and can be pruned\n");
+         goto fath;
+      }
+      /* let the application program generate additional rows ("lazy"
+         constraints) */
+      xassert(T->reopt == 0);
+      xassert(T->reinv == 0);
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IROWGEN;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+         if (T->reopt)
+         {  /* some rows were added; re-optimization is needed */
+            T->reopt = T->reinv = 0;
+            goto more;
+         }
+         if (T->reinv)
+         {  /* no rows were added, however, some inactive rows were
+               removed */
+            T->reinv = 0;
+            xassert(glp_factorize(T->mip) == 0);
+         }
+      }
+      /* check if the basic solution is integer feasible */
+      check_integrality(T);
+      /* if the basic solution satisfies to all integrality conditions,
+         it is a new, better integer feasible solution */
+      if (T->curr->ii_cnt == 0)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("New integer feasible solution found\n");
+         if (T->parm->msg_lev >= GLP_MSG_ALL)
+            display_cut_info(T);
+         record_solution(T);
+         if (T->parm->msg_lev >= GLP_MSG_ON)
+            show_progress(T, 1);
+         /* make the application program happy */
+         if (T->parm->cb_func != NULL)
+         {  xassert(T->reason == 0);
+            T->reason = GLP_IBINGO;
+            T->parm->cb_func(T, T->parm->cb_info);
+            T->reason = 0;
+            if (T->stop)
+            {  ret = GLP_ESTOP;
+               goto done;
+            }
+         }
+         /* since the current subproblem has been fathomed, prune its
+            branch */
+         goto fath;
+      }
+      /* at this point basic solution to LP relaxation of the current
+         subproblem is optimal, but integer infeasible */
+      /* try to fix some non-basic structural variables of integer kind
+         on their current bounds due to reduced costs */
+      if (T->mip->mip_stat == GLP_FEAS)
+         fix_by_red_cost(T);
+      /* let the application program try to find some solution to the
+         original MIP with a primal heuristic */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IHEUR;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+         /* check if the current branch became hopeless */
+         if (!is_branch_hopeful(T, p))
+         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("Current branch became hopeless and can be prune"
+                  "d\n");
+            goto fath;
+         }
+      }
+      /* try to find solution with the feasibility pump heuristic */
+      if (T->parm->fp_heur)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IHEUR;
+         ios_feas_pump(T);
+         T->reason = 0;
+         /* check if the current branch became hopeless */
+         if (!is_branch_hopeful(T, p))
+         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("Current branch became hopeless and can be prune"
+                  "d\n");
+            goto fath;
+         }
+      }
+      /* it's time to generate cutting planes */
+      xassert(T->local != NULL);
+      xassert(T->local->size == 0);
+      /* let the application program generate some cuts; note that it
+         can add cuts either to the local cut pool or directly to the
+         current subproblem */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ICUTGEN;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      /* try to generate generic cuts with built-in generators
+         (as suggested by Matteo Fischetti et al. the built-in cuts
+         are not generated at each branching node; an intense attempt
+         of generating new cuts is only made at the root node, and then
+         a moderate effort is spent after each backtracking step) */
+      if (T->curr->level == 0 || pred_p == 0)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ICUTGEN;
+         generate_cuts(T);
+         T->reason = 0;
+      }
+      /* if the local cut pool is not empty, select useful cuts and add
+         them to the current subproblem */
+      if (T->local->size > 0)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ICUTGEN;
+         ios_process_cuts(T);
+         T->reason = 0;
+      }
+      /* clear the local cut pool */
+      ios_clear_pool(T, T->local);
+      /* perform re-optimization, if necessary */
+      if (T->reopt)
+      {  T->reopt = 0;
+         T->curr->changed++;
+         goto more;
+      }
+      /* no cuts were generated; remove inactive cuts */
+      remove_cuts(T);
+      if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0)
+         display_cut_info(T);
+      /* update history information used on pseudocost branching */
+      if (T->pcost != NULL) ios_pcost_update(T);
+      /* it's time to perform branching */
+      xassert(T->br_var == 0);
+      xassert(T->br_sel == 0);
+      /* let the application program choose variable to branch on */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         xassert(T->br_var == 0);
+         xassert(T->br_sel == 0);
+         T->reason = GLP_IBRANCH;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      /* if nothing has been chosen, choose some variable as specified
+         by the branching technique option */
+      if (T->br_var == 0)
+         T->br_var = ios_choose_var(T, &T->br_sel);
+      /* perform actual branching */
+      curr_p = T->curr->p;
+      ret = branch_on(T, T->br_var, T->br_sel);
+      T->br_var = T->br_sel = 0;
+      if (ret == 0)
+      {  /* both branches have been created */
+         pred_p = curr_p;
+         goto loop;
+      }
+      else if (ret == 1)
+      {  /* one branch is hopeless and has been pruned, so now the
+            current subproblem is other branch */
+         /* the current subproblem should be considered as a new one,
+            since one bound of the branching variable was changed */
+         T->curr->solved = T->curr->changed = 0;
+         goto more;
+      }
+      else if (ret == 2)
+      {  /* both branches are hopeless and have been pruned; new
+            subproblem selection is needed to continue the search */
+         goto fath;
+      }
+      else
+         xassert(ret != ret);
+fath: /* the current subproblem has been fathomed */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Node %d fathomed\n", p);
+      /* freeze the current subproblem */
+      ios_freeze_node(T);
+      /* and prune the corresponding branch of the tree */
+      ios_delete_node(T, p);
+      /* if a new integer feasible solution has just been found, other
+         branches may become hopeless and therefore must be pruned */
+      if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T);
+      /* new subproblem selection is needed due to backtracking */
+      pred_p = 0;
+      goto loop;
+done: /* display progress of the search on exit from the solver */
+      if (T->parm->msg_lev >= GLP_MSG_ON)
+         show_progress(T, 0);
+      if (T->mir_gen != NULL)
+         ios_mir_term(T->mir_gen), T->mir_gen = NULL;
+      if (T->clq_gen != NULL)
+         ios_clq_term(T->clq_gen), T->clq_gen = NULL;
+      /* return to the calling program */
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios04.c b/optional/glpk/glpios04.c
new file mode 100644
index 0000000..9590e9d
--- /dev/null
+++ b/optional/glpk/glpios04.c
@@ -0,0 +1,307 @@
+/* glpios04.c (operations on sparse vectors) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_create_vec - create sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  IOSVEC *ios_create_vec(int n);
+*
+*  DESCRIPTION
+*
+*  The routine ios_create_vec creates a sparse vector of dimension n,
+*  which initially is a null vector.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the vector created. */
+
+IOSVEC *ios_create_vec(int n)
+{     IOSVEC *v;
+      xassert(n >= 0);
+      v = xmalloc(sizeof(IOSVEC));
+      v->n = n;
+      v->nnz = 0;
+      v->pos = xcalloc(1+n, sizeof(int));
+      memset(&v->pos[1], 0, n * sizeof(int));
+      v->ind = xcalloc(1+n, sizeof(int));
+      v->val = xcalloc(1+n, sizeof(double));
+      return v;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_check_vec - check that sparse vector has correct representation
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_check_vec(IOSVEC *v);
+*
+*  DESCRIPTION
+*
+*  The routine ios_check_vec checks that a sparse vector specified by
+*  the parameter v has correct representation.
+*
+*  NOTE
+*
+*  Complexity of this operation is O(n). */
+
+void ios_check_vec(IOSVEC *v)
+{     int j, k, nnz;
+      xassert(v->n >= 0);
+      nnz = 0;
+      for (j = v->n; j >= 1; j--)
+      {  k = v->pos[j];
+         xassert(0 <= k && k <= v->nnz);
+         if (k != 0)
+         {  xassert(v->ind[k] == j);
+            nnz++;
+         }
+      }
+      xassert(v->nnz == nnz);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_get_vj - retrieve component of sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  double ios_get_vj(IOSVEC *v, int j);
+*
+*  RETURNS
+*
+*  The routine ios_get_vj returns j-th component of a sparse vector
+*  specified by the parameter v. */
+
+double ios_get_vj(IOSVEC *v, int j)
+{     int k;
+      xassert(1 <= j && j <= v->n);
+      k = v->pos[j];
+      xassert(0 <= k && k <= v->nnz);
+      return (k == 0 ? 0.0 : v->val[k]);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_set_vj - set/change component of sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_set_vj(IOSVEC *v, int j, double val);
+*
+*  DESCRIPTION
+*
+*  The routine ios_set_vj assigns val to j-th component of a sparse
+*  vector specified by the parameter v. */
+
+void ios_set_vj(IOSVEC *v, int j, double val)
+{     int k;
+      xassert(1 <= j && j <= v->n);
+      k = v->pos[j];
+      if (val == 0.0)
+      {  if (k != 0)
+         {  /* remove j-th component */
+            v->pos[j] = 0;
+            if (k < v->nnz)
+            {  v->pos[v->ind[v->nnz]] = k;
+               v->ind[k] = v->ind[v->nnz];
+               v->val[k] = v->val[v->nnz];
+            }
+            v->nnz--;
+         }
+      }
+      else
+      {  if (k == 0)
+         {  /* create j-th component */
+            k = ++(v->nnz);
+            v->pos[j] = k;
+            v->ind[k] = j;
+         }
+         v->val[k] = val;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clear_vec - set all components of sparse vector to zero
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clear_vec(IOSVEC *v);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clear_vec sets all components of a sparse vector
+*  specified by the parameter v to zero. */
+
+void ios_clear_vec(IOSVEC *v)
+{     int k;
+      for (k = 1; k <= v->nnz; k++)
+         v->pos[v->ind[k]] = 0;
+      v->nnz = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clean_vec - remove zero or small components from sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clean_vec(IOSVEC *v, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clean_vec removes zero components and components
+*  whose magnitude is less than eps from a sparse vector specified by
+*  the parameter v. If eps is 0.0, only zero components are removed. */
+
+void ios_clean_vec(IOSVEC *v, double eps)
+{     int k, nnz;
+      nnz = 0;
+      for (k = 1; k <= v->nnz; k++)
+      {  if (fabs(v->val[k]) == 0.0 || fabs(v->val[k]) < eps)
+         {  /* remove component */
+            v->pos[v->ind[k]] = 0;
+         }
+         else
+         {  /* keep component */
+            nnz++;
+            v->pos[v->ind[k]] = nnz;
+            v->ind[nnz] = v->ind[k];
+            v->val[nnz] = v->val[k];
+         }
+      }
+      v->nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_copy_vec - copy sparse vector (x := y)
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_copy_vec(IOSVEC *x, IOSVEC *y);
+*
+*  DESCRIPTION
+*
+*  The routine ios_copy_vec copies a sparse vector specified by the
+*  parameter y to a sparse vector specified by the parameter x. */
+
+void ios_copy_vec(IOSVEC *x, IOSVEC *y)
+{     int j;
+      xassert(x != y);
+      xassert(x->n == y->n);
+      ios_clear_vec(x);
+      x->nnz = y->nnz;
+      memcpy(&x->ind[1], &y->ind[1], x->nnz * sizeof(int));
+      memcpy(&x->val[1], &y->val[1], x->nnz * sizeof(double));
+      for (j = 1; j <= x->nnz; j++)
+         x->pos[x->ind[j]] = j;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_linear_comb - compute linear combination (x := x + a * y)
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
+*
+*  DESCRIPTION
+*
+*  The routine ios_linear_comb computes the linear combination
+*
+*     x := x + a * y,
+*
+*  where x and y are sparse vectors, a is a scalar. */
+
+void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y)
+{     int j, k;
+      double xj, yj;
+      xassert(x != y);
+      xassert(x->n == y->n);
+      for (k = 1; k <= y->nnz; k++)
+      {  j = y->ind[k];
+         xj = ios_get_vj(x, j);
+         yj = y->val[k];
+         ios_set_vj(x, j, xj + a * yj);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_delete_vec - delete sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_delete_vec(IOSVEC *v);
+*
+*  DESCRIPTION
+*
+*  The routine ios_delete_vec deletes a sparse vector specified by the
+*  parameter v freeing all the memory allocated to this object. */
+
+void ios_delete_vec(IOSVEC *v)
+{     /* delete sparse vector */
+      xfree(v->pos);
+      xfree(v->ind);
+      xfree(v->val);
+      xfree(v);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios05.c b/optional/glpk/glpios05.c
new file mode 100644
index 0000000..44c4853
--- /dev/null
+++ b/optional/glpk/glpios05.c
@@ -0,0 +1,285 @@
+/* glpios05.c (Gomory's mixed integer cut generator) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_gmi_gen - generate Gomory's mixed integer cuts.
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_gmi_gen(glp_tree *tree, IOSPOOL *pool);
+*
+*  DESCRIPTION
+*
+*  The routine ios_gmi_gen generates Gomory's mixed integer cuts for
+*  the current point and adds them to the cut pool. */
+
+#define MAXCUTS 50
+/* maximal number of cuts to be generated for one round */
+
+struct worka
+{     /* Gomory's cut generator working area */
+      int *ind; /* int ind[1+n]; */
+      double *val; /* double val[1+n]; */
+      double *phi; /* double phi[1+m+n]; */
+};
+
+#define f(x) ((x) - floor(x))
+/* compute fractional part of x */
+
+static void gen_cut(glp_tree *tree, struct worka *worka, int j)
+{     /* this routine tries to generate Gomory's mixed integer cut for
+         specified structural variable x[m+j] of integer kind, which is
+         basic and has fractional value in optimal solution to current
+         LP relaxation */
+      glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      int *ind = worka->ind;
+      double *val = worka->val;
+      double *phi = worka->phi;
+      int i, k, len, kind, stat;
+      double lb, ub, alfa, beta, ksi, phi1, rhs;
+      /* compute row of the simplex tableau, which (row) corresponds
+         to specified basic variable xB[i] = x[m+j]; see (23) */
+      len = glp_eval_tab_row(mip, m+j, ind, val);
+      /* determine beta[i], which a value of xB[i] in optimal solution
+         to current LP relaxation; note that this value is the same as
+         if it would be computed with formula (27); it is assumed that
+         beta[i] is fractional enough */
+      beta = mip->col[j]->prim;
+      /* compute cut coefficients phi and right-hand side rho, which
+         correspond to formula (30); dense format is used, because rows
+         of the simplex tableau is usually dense */
+      for (k = 1; k <= m+n; k++) phi[k] = 0.0;
+      rhs = f(beta); /* initial value of rho; see (28), (32) */
+      for (j = 1; j <= len; j++)
+      {  /* determine original number of non-basic variable xN[j] */
+         k = ind[j];
+         xassert(1 <= k && k <= m+n);
+         /* determine the kind, bounds and current status of xN[j] in
+            optimal solution to LP relaxation */
+         if (k <= m)
+         {  /* auxiliary variable */
+            GLPROW *row = mip->row[k];
+            kind = GLP_CV;
+            lb = row->lb;
+            ub = row->ub;
+            stat = row->stat;
+         }
+         else
+         {  /* structural variable */
+            GLPCOL *col = mip->col[k-m];
+            kind = col->kind;
+            lb = col->lb;
+            ub = col->ub;
+            stat = col->stat;
+         }
+         /* xN[j] cannot be basic */
+         xassert(stat != GLP_BS);
+         /* determine row coefficient ksi[i,j] at xN[j]; see (23) */
+         ksi = val[j];
+         /* if ksi[i,j] is too large in the magnitude, do not generate
+            the cut */
+         if (fabs(ksi) > 1e+05) goto fini;
+         /* if ksi[i,j] is too small in the magnitude, skip it */
+         if (fabs(ksi) < 1e-10) goto skip;
+         /* compute row coefficient alfa[i,j] at y[j]; see (26) */
+         switch (stat)
+         {  case GLP_NF:
+               /* xN[j] is free (unbounded) having non-zero ksi[i,j];
+                  do not generate the cut */
+               goto fini;
+            case GLP_NL:
+               /* xN[j] has active lower bound */
+               alfa = - ksi;
+               break;
+            case GLP_NU:
+               /* xN[j] has active upper bound */
+               alfa = + ksi;
+               break;
+            case GLP_NS:
+               /* xN[j] is fixed; skip it */
+               goto skip;
+            default:
+               xassert(stat != stat);
+         }
+         /* compute cut coefficient phi'[j] at y[j]; see (21), (28) */
+         switch (kind)
+         {  case GLP_IV:
+               /* y[j] is integer */
+               if (fabs(alfa - floor(alfa + 0.5)) < 1e-10)
+               {  /* alfa[i,j] is close to nearest integer; skip it */
+                  goto skip;
+               }
+               else if (f(alfa) <= f(beta))
+                  phi1 = f(alfa);
+               else
+                  phi1 = (f(beta) / (1.0 - f(beta))) * (1.0 - f(alfa));
+               break;
+            case GLP_CV:
+               /* y[j] is continuous */
+               if (alfa >= 0.0)
+                  phi1 = + alfa;
+               else
+                  phi1 = (f(beta) / (1.0 - f(beta))) * (- alfa);
+               break;
+            default:
+               xassert(kind != kind);
+         }
+         /* compute cut coefficient phi[j] at xN[j] and update right-
+            hand side rho; see (31), (32) */
+         switch (stat)
+         {  case GLP_NL:
+               /* xN[j] has active lower bound */
+               phi[k] = + phi1;
+               rhs += phi1 * lb;
+               break;
+            case GLP_NU:
+               /* xN[j] has active upper bound */
+               phi[k] = - phi1;
+               rhs -= phi1 * ub;
+               break;
+            default:
+               xassert(stat != stat);
+         }
+skip:    ;
+      }
+      /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut
+         coefficients are stored in the array phi in dense format;
+         x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc-
+         tural variables; see (30) */
+      /* eliminate auxiliary variables in order to express the cut only
+         through structural variables; see (33) */
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row;
+         GLPAIJ *aij;
+         if (fabs(phi[i]) < 1e-10) continue;
+         /* auxiliary variable x[i] has non-zero cut coefficient */
+         row = mip->row[i];
+         /* x[i] cannot be fixed */
+         xassert(row->type != GLP_FX);
+         /* substitute x[i] = sum_j a[i,j] * x[m+j] */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            phi[m+aij->col->j] += phi[i] * aij->val;
+      }
+      /* convert the final cut to sparse format and substitute fixed
+         (structural) variables */
+      len = 0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col;
+         if (fabs(phi[m+j]) < 1e-10) continue;
+         /* structural variable x[m+j] has non-zero cut coefficient */
+         col = mip->col[j];
+         if (col->type == GLP_FX)
+         {  /* eliminate x[m+j] */
+            rhs -= phi[m+j] * col->lb;
+         }
+         else
+         {  len++;
+            ind[len] = j;
+            val[len] = phi[m+j];
+         }
+      }
+      if (fabs(rhs) < 1e-12) rhs = 0.0;
+      /* if the cut inequality seems to be badly scaled, reject it to
+         avoid numeric difficulties */
+      for (k = 1; k <= len; k++)
+      {  if (fabs(val[k]) < 1e-03) goto fini;
+         if (fabs(val[k]) > 1e+03) goto fini;
+      }
+      /* add the cut to the cut pool for further consideration */
+#if 0
+      ios_add_cut_row(tree, pool, GLP_RF_GMI, len, ind, val, GLP_LO,
+         rhs);
+#else
+      glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, GLP_LO,
+         rhs);
+#endif
+fini: return;
+}
+
+struct var { int j; double f; };
+
+static int fcmp(const void *p1, const void *p2)
+{     const struct var *v1 = p1, *v2 = p2;
+      if (v1->f > v2->f) return -1;
+      if (v1->f < v2->f) return +1;
+      return 0;
+}
+
+void ios_gmi_gen(glp_tree *tree)
+{     /* main routine to generate Gomory's cuts */
+      glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      struct var *var;
+      int k, nv, j, size;
+      struct worka _worka, *worka = &_worka;
+      /* allocate working arrays */
+      var = xcalloc(1+n, sizeof(struct var));
+      worka->ind = xcalloc(1+n, sizeof(int));
+      worka->val = xcalloc(1+n, sizeof(double));
+      worka->phi = xcalloc(1+m+n, sizeof(double));
+      /* build the list of integer structural variables, which are
+         basic and have fractional value in optimal solution to current
+         LP relaxation */
+      nv = 0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         double frac;
+         if (col->kind != GLP_IV) continue;
+         if (col->type == GLP_FX) continue;
+         if (col->stat != GLP_BS) continue;
+         frac = f(col->prim);
+         if (!(0.05 <= frac && frac <= 0.95)) continue;
+         /* add variable to the list */
+         nv++, var[nv].j = j, var[nv].f = frac;
+      }
+      /* order the list by descending fractionality */
+      qsort(&var[1], nv, sizeof(struct var), fcmp);
+      /* try to generate cuts by one for each variable in the list, but
+         not more than MAXCUTS cuts */
+      size = glp_ios_pool_size(tree);
+      for (k = 1; k <= nv; k++)
+      {  if (glp_ios_pool_size(tree) - size >= MAXCUTS) break;
+         gen_cut(tree, worka, var[k].j);
+      }
+      /* free working arrays */
+      xfree(var);
+      xfree(worka->ind);
+      xfree(worka->val);
+      xfree(worka->phi);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios06.c b/optional/glpk/glpios06.c
new file mode 100644
index 0000000..d582ab6
--- /dev/null
+++ b/optional/glpk/glpios06.c
@@ -0,0 +1,1453 @@
+/* glpios06.c (MIR cut generator) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#include "glpios.h"
+
+#define _MIR_DEBUG 0
+
+#define MAXAGGR 5
+/* maximal number of rows which can be aggregated */
+
+struct MIR
+{     /* MIR cut generator working area */
+      /*--------------------------------------------------------------*/
+      /* global information valid for the root subproblem */
+      int m;
+      /* number of rows (in the root subproblem) */
+      int n;
+      /* number of columns */
+      char *skip; /* char skip[1+m]; */
+      /* skip[i], 1 <= i <= m, is a flag that means that row i should
+         not be used because (1) it is not suitable, or (2) because it
+         has been used in the aggregated constraint */
+      char *isint; /* char isint[1+m+n]; */
+      /* isint[k], 1 <= k <= m+n, is a flag that means that variable
+         x[k] is integer (otherwise, continuous) */
+      double *lb; /* double lb[1+m+n]; */
+      /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
+         that x[k] has no lower bound */
+      int *vlb; /* int vlb[1+m+n]; */
+      /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
+         which defines variable lower bound x[k] >= lb[k] * x[k']; zero
+         means that x[k] has simple lower bound */
+      double *ub; /* double ub[1+m+n]; */
+      /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
+         that x[k] has no upper bound */
+      int *vub; /* int vub[1+m+n]; */
+      /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
+         which defines variable upper bound x[k] <= ub[k] * x[k']; zero
+         means that x[k] has simple upper bound */
+      /*--------------------------------------------------------------*/
+      /* current (fractional) point to be separated */
+      double *x; /* double x[1+m+n]; */
+      /* x[k] is current value of auxiliary (1 <= k <= m) or structural
+         (m+1 <= k <= m+n) variable */
+      /*--------------------------------------------------------------*/
+      /* aggregated constraint sum a[k] * x[k] = b, which is a linear
+         combination of original constraints transformed to equalities
+         by introducing auxiliary variables */
+      int agg_cnt;
+      /* number of rows (original constraints) used to build aggregated
+         constraint, 1 <= agg_cnt <= MAXAGGR */
+      int *agg_row; /* int agg_row[1+MAXAGGR]; */
+      /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
+         aggregated constraint */
+      IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
+      /* sparse vector of aggregated constraint coefficients, a[k] */
+      double agg_rhs;
+      /* right-hand side of the aggregated constraint, b */
+      /*--------------------------------------------------------------*/
+      /* bound substitution flags for modified constraint */
+      char *subst; /* char subst[1+m+n]; */
+      /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
+         variable x[k]:
+         '?' - x[k] is missing in modified constraint
+         'L' - x[k] = (lower bound) + x'[k]
+         'U' - x[k] = (upper bound) - x'[k] */
+      /*--------------------------------------------------------------*/
+      /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
+         derived from aggregated constraint by substituting bounds;
+         note that due to substitution of variable bounds there may be
+         additional terms in the modified constraint */
+      IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
+      /* sparse vector of modified constraint coefficients, a'[k] */
+      double mod_rhs;
+      /* right-hand side of the modified constraint, b' */
+      /*--------------------------------------------------------------*/
+      /* cutting plane sum alpha[k] * x[k] <= beta */
+      IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
+      /* sparse vector of cutting plane coefficients, alpha[k] */
+      double cut_rhs;
+      /* right-hand size of the cutting plane, beta */
+};
+
+/***********************************************************************
+*  NAME
+*
+*  ios_mir_init - initialize MIR cut generator
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void *ios_mir_init(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_mir_init initializes the MIR cut generator assuming
+*  that the current subproblem is the root subproblem.
+*
+*  RETURNS
+*
+*  The routine ios_mir_init returns a pointer to the MIR cut generator
+*  working area. */
+
+static void set_row_attrib(glp_tree *tree, struct MIR *mir)
+{     /* set global row attributes */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int k;
+      for (k = 1; k <= m; k++)
+      {  GLPROW *row = mip->row[k];
+         mir->skip[k] = 0;
+         mir->isint[k] = 0;
+         switch (row->type)
+         {  case GLP_FR:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
+            case GLP_LO:
+               mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
+            case GLP_UP:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
+            case GLP_DB:
+               mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
+            case GLP_FX:
+               mir->lb[k] = mir->ub[k] = row->lb; break;
+            default:
+               xassert(row != row);
+         }
+         mir->vlb[k] = mir->vub[k] = 0;
+      }
+      return;
+}
+
+static void set_col_attrib(glp_tree *tree, struct MIR *mir)
+{     /* set global column attributes */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      int k;
+      for (k = m+1; k <= m+n; k++)
+      {  GLPCOL *col = mip->col[k-m];
+         switch (col->kind)
+         {  case GLP_CV:
+               mir->isint[k] = 0; break;
+            case GLP_IV:
+               mir->isint[k] = 1; break;
+            default:
+               xassert(col != col);
+         }
+         switch (col->type)
+         {  case GLP_FR:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
+            case GLP_LO:
+               mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
+            case GLP_UP:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
+            case GLP_DB:
+               mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
+            case GLP_FX:
+               mir->lb[k] = mir->ub[k] = col->lb; break;
+            default:
+               xassert(col != col);
+         }
+         mir->vlb[k] = mir->vub[k] = 0;
+      }
+      return;
+}
+
+static void set_var_bounds(glp_tree *tree, struct MIR *mir)
+{     /* set variable bounds */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      GLPAIJ *aij;
+      int i, k1, k2;
+      double a1, a2;
+      for (i = 1; i <= m; i++)
+      {  /* we need the row to be '>= 0' or '<= 0' */
+         if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
+               mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
+         /* take first term */
+         aij = mip->row[i]->ptr;
+         if (aij == NULL) continue;
+         k1 = m + aij->col->j, a1 = aij->val;
+         /* take second term */
+         aij = aij->r_next;
+         if (aij == NULL) continue;
+         k2 = m + aij->col->j, a2 = aij->val;
+         /* there must be only two terms */
+         if (aij->r_next != NULL) continue;
+         /* interchange terms, if needed */
+         if (!mir->isint[k1] && mir->isint[k2])
+            ;
+         else if (mir->isint[k1] && !mir->isint[k2])
+         {  k2 = k1, a2 = a1;
+            k1 = m + aij->col->j, a1 = aij->val;
+         }
+         else
+         {  /* both terms are either continuous or integer */
+            continue;
+         }
+         /* x[k2] should be double-bounded */
+         if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
+             mir->lb[k2] == mir->ub[k2]) continue;
+         /* change signs, if necessary */
+         if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
+         /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
+            is continuous, x2 is integer */
+         if (a1 > 0.0)
+         {  /* x1 >= - (a2 / a1) * x2 */
+            if (mir->vlb[k1] == 0)
+            {  /* set variable lower bound for x1 */
+               mir->lb[k1] = - a2 / a1;
+               mir->vlb[k1] = k2;
+               /* the row should not be used */
+               mir->skip[i] = 1;
+            }
+         }
+         else /* a1 < 0.0 */
+         {  /* x1 <= - (a2 / a1) * x2 */
+            if (mir->vub[k1] == 0)
+            {  /* set variable upper bound for x1 */
+               mir->ub[k1] = - a2 / a1;
+               mir->vub[k1] = k2;
+               /* the row should not be used */
+               mir->skip[i] = 1;
+            }
+         }
+      }
+      return;
+}
+
+static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
+{     /* mark rows which should not be used */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      GLPAIJ *aij;
+      int i, k, nv;
+      for (i = 1; i <= m; i++)
+      {  /* free rows should not be used */
+         if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
+         {  mir->skip[i] = 1;
+            continue;
+         }
+         nv = 0;
+         for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  k = m + aij->col->j;
+            /* rows with free variables should not be used */
+            if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
+            {  mir->skip[i] = 1;
+               break;
+            }
+            /* rows with integer variables having infinite (lower or
+               upper) bound should not be used */
+            if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
+                mir->isint[k] && mir->ub[k] == +DBL_MAX)
+            {  mir->skip[i] = 1;
+               break;
+            }
+            /* count non-fixed variables */
+            if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
+                  mir->lb[k] == mir->ub[k])) nv++;
+         }
+         /* rows with all variables fixed should not be used */
+         if (nv == 0)
+         {  mir->skip[i] = 1;
+            continue;
+         }
+      }
+      return;
+}
+
+void *ios_mir_init(glp_tree *tree)
+{     /* initialize MIR cut generator */
+      glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      struct MIR *mir;
+#if _MIR_DEBUG
+      xprintf("ios_mir_init: warning: debug mode enabled\n");
+#endif
+      /* allocate working area */
+      mir = xmalloc(sizeof(struct MIR));
+      mir->m = m;
+      mir->n = n;
+      mir->skip = xcalloc(1+m, sizeof(char));
+      mir->isint = xcalloc(1+m+n, sizeof(char));
+      mir->lb = xcalloc(1+m+n, sizeof(double));
+      mir->vlb = xcalloc(1+m+n, sizeof(int));
+      mir->ub = xcalloc(1+m+n, sizeof(double));
+      mir->vub = xcalloc(1+m+n, sizeof(int));
+      mir->x = xcalloc(1+m+n, sizeof(double));
+      mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
+      mir->agg_vec = ios_create_vec(m+n);
+      mir->subst = xcalloc(1+m+n, sizeof(char));
+      mir->mod_vec = ios_create_vec(m+n);
+      mir->cut_vec = ios_create_vec(m+n);
+      /* set global row attributes */
+      set_row_attrib(tree, mir);
+      /* set global column attributes */
+      set_col_attrib(tree, mir);
+      /* set variable bounds */
+      set_var_bounds(tree, mir);
+      /* mark rows which should not be used */
+      mark_useless_rows(tree, mir);
+      return mir;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_mir_gen - generate MIR cuts
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
+*
+*  DESCRIPTION
+*
+*  The routine ios_mir_gen generates MIR cuts for the current point and
+*  adds them to the cut pool. */
+
+static void get_current_point(glp_tree *tree, struct MIR *mir)
+{     /* obtain current point */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      int k;
+      for (k = 1; k <= m; k++)
+         mir->x[k] = mip->row[k]->prim;
+      for (k = m+1; k <= m+n; k++)
+         mir->x[k] = mip->col[k-m]->prim;
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_current_point(struct MIR *mir)
+{     /* check current point */
+      int m = mir->m;
+      int n = mir->n;
+      int k, kk;
+      double lb, ub, eps;
+      for (k = 1; k <= m+n; k++)
+      {  /* determine lower bound */
+         lb = mir->lb[k];
+         kk = mir->vlb[k];
+         if (kk != 0)
+         {  xassert(lb != -DBL_MAX);
+            xassert(!mir->isint[k]);
+            xassert(mir->isint[kk]);
+            lb *= mir->x[kk];
+         }
+         /* check lower bound */
+         if (lb != -DBL_MAX)
+         {  eps = 1e-6 * (1.0 + fabs(lb));
+            xassert(mir->x[k] >= lb - eps);
+         }
+         /* determine upper bound */
+         ub = mir->ub[k];
+         kk = mir->vub[k];
+         if (kk != 0)
+         {  xassert(ub != +DBL_MAX);
+            xassert(!mir->isint[k]);
+            xassert(mir->isint[kk]);
+            ub *= mir->x[kk];
+         }
+         /* check upper bound */
+         if (ub != +DBL_MAX)
+         {  eps = 1e-6 * (1.0 + fabs(ub));
+            xassert(mir->x[k] <= ub + eps);
+         }
+      }
+      return;
+}
+#endif
+
+static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
+{     /* use original i-th row as initial aggregated constraint */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      GLPAIJ *aij;
+      xassert(1 <= i && i <= m);
+      xassert(!mir->skip[i]);
+      /* mark i-th row in order not to use it in the same aggregated
+         constraint */
+      mir->skip[i] = 2;
+      mir->agg_cnt = 1;
+      mir->agg_row[1] = i;
+      /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
+         variable of row i, x[m+j] are structural variables */
+      ios_clear_vec(mir->agg_vec);
+      ios_set_vj(mir->agg_vec, i, 1.0);
+      for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
+      mir->agg_rhs = 0.0;
+#if _MIR_DEBUG
+      ios_check_vec(mir->agg_vec);
+#endif
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_agg_row(struct MIR *mir)
+{     /* check aggregated constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k;
+      double r, big;
+      /* compute the residual r = sum a[k] * x[k] - b and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         r += mir->agg_vec->val[j] * mir->x[k];
+         if (big < fabs(mir->agg_vec->val[j]))
+            big = fabs(mir->agg_vec->val[j]);
+      }
+      r -= mir->agg_rhs;
+      if (big < fabs(mir->agg_rhs))
+         big = fabs(mir->agg_rhs);
+      /* the residual must be close to zero */
+      xassert(fabs(r) <= 1e-6 * big);
+      return;
+}
+#endif
+
+static void subst_fixed_vars(struct MIR *mir)
+{     /* substitute fixed variables into aggregated constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k;
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
+             mir->lb[k] == mir->ub[k])
+         {  /* x[k] is fixed */
+            mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
+            mir->agg_vec->val[j] = 0.0;
+         }
+      }
+      /* remove terms corresponding to fixed variables */
+      ios_clean_vec(mir->agg_vec, DBL_EPSILON);
+#if _MIR_DEBUG
+      ios_check_vec(mir->agg_vec);
+#endif
+      return;
+}
+
+static void bound_subst_heur(struct MIR *mir)
+{     /* bound substitution heuristic */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk;
+      double d1, d2;
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k]) continue; /* skip integer variable */
+         /* compute distance from x[k] to its lower bound */
+         kk = mir->vlb[k];
+         if (kk == 0)
+         {  if (mir->lb[k] == -DBL_MAX)
+               d1 = DBL_MAX;
+            else
+               d1 = mir->x[k] - mir->lb[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->lb[k] != -DBL_MAX);
+            d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         /* compute distance from x[k] to its upper bound */
+         kk = mir->vub[k];
+         if (kk == 0)
+         {  if (mir->vub[k] == +DBL_MAX)
+               d2 = DBL_MAX;
+            else
+               d2 = mir->ub[k] - mir->x[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->ub[k] != +DBL_MAX);
+            d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         /* x[k] cannot be free */
+         xassert(d1 != DBL_MAX || d2 != DBL_MAX);
+         /* choose the bound which is closer to x[k] */
+         xassert(mir->subst[k] == '?');
+         if (d1 <= d2)
+            mir->subst[k] = 'L';
+         else
+            mir->subst[k] = 'U';
+      }
+      return;
+}
+
+static void build_mod_row(struct MIR *mir)
+{     /* substitute bounds and build modified constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, jj, k, kk;
+      /* initially modified constraint is aggregated constraint */
+      ios_copy_vec(mir->mod_vec, mir->agg_vec);
+      mir->mod_rhs = mir->agg_rhs;
+#if _MIR_DEBUG
+      ios_check_vec(mir->mod_vec);
+#endif
+      /* substitute bounds for continuous variables; note that due to
+         substitution of variable bounds additional terms may appear in
+         modified constraint */
+      for (j = mir->mod_vec->nnz; j >= 1; j--)
+      {  k = mir->mod_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k]) continue; /* skip integer variable */
+         if (mir->subst[k] == 'L')
+         {  /* x[k] = (lower bound) + x'[k] */
+            xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+            {  /* x[k] = lb[k] + x'[k] */
+               mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
+            }
+            else
+            {  /* x[k] = lb[k] * x[kk] + x'[k] */
+               xassert(mir->isint[kk]);
+               jj = mir->mod_vec->pos[kk];
+               if (jj == 0)
+               {  ios_set_vj(mir->mod_vec, kk, 1.0);
+                  jj = mir->mod_vec->pos[kk];
+                  mir->mod_vec->val[jj] = 0.0;
+               }
+               mir->mod_vec->val[jj] +=
+                  mir->mod_vec->val[j] * mir->lb[k];
+            }
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x[k] = (upper bound) - x'[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+            {  /* x[k] = ub[k] - x'[k] */
+               mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
+            }
+            else
+            {  /* x[k] = ub[k] * x[kk] - x'[k] */
+               xassert(mir->isint[kk]);
+               jj = mir->mod_vec->pos[kk];
+               if (jj == 0)
+               {  ios_set_vj(mir->mod_vec, kk, 1.0);
+                  jj = mir->mod_vec->pos[kk];
+                  mir->mod_vec->val[jj] = 0.0;
+               }
+               mir->mod_vec->val[jj] +=
+                  mir->mod_vec->val[j] * mir->ub[k];
+            }
+            mir->mod_vec->val[j] = - mir->mod_vec->val[j];
+         }
+         else
+            xassert(k != k);
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->mod_vec);
+#endif
+      /* substitute bounds for integer variables */
+      for (j = 1; j <= mir->mod_vec->nnz; j++)
+      {  k = mir->mod_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (!mir->isint[k]) continue; /* skip continuous variable */
+         xassert(mir->subst[k] == '?');
+         xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
+         xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
+         if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
+         {  /* x[k] = lb[k] + x'[k] */
+            mir->subst[k] = 'L';
+            mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
+         }
+         else
+         {  /* x[k] = ub[k] - x'[k] */
+            mir->subst[k] = 'U';
+            mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
+            mir->mod_vec->val[j] = - mir->mod_vec->val[j];
+         }
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->mod_vec);
+#endif
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_mod_row(struct MIR *mir)
+{     /* check modified constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk;
+      double r, big, x;
+      /* compute the residual r = sum a'[k] * x'[k] - b' and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->mod_vec->nnz; j++)
+      {  k = mir->mod_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->subst[k] == 'L')
+         {  /* x'[k] = x[k] - (lower bound) */
+            xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+               x = mir->x[k] - mir->lb[k];
+            else
+               x = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x'[k] = (upper bound) - x[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+               x = mir->ub[k] - mir->x[k];
+            else
+               x = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         else
+            xassert(k != k);
+         r += mir->mod_vec->val[j] * x;
+         if (big < fabs(mir->mod_vec->val[j]))
+            big = fabs(mir->mod_vec->val[j]);
+      }
+      r -= mir->mod_rhs;
+      if (big < fabs(mir->mod_rhs))
+         big = fabs(mir->mod_rhs);
+      /* the residual must be close to zero */
+      xassert(fabs(r) <= 1e-6 * big);
+      return;
+}
+#endif
+
+/***********************************************************************
+*  mir_ineq - construct MIR inequality
+*
+*  Given the single constraint mixed integer set
+*
+*                    |N|
+*     X = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s},
+*                    +      +  j in N
+*
+*  this routine constructs the mixed integer rounding (MIR) inequality
+*
+*     sum   alpha[j] * x[j] <= beta + gamma * s,
+*    j in N
+*
+*  which is valid for X.
+*
+*  If the MIR inequality has been successfully constructed, the routine
+*  returns zero. Otherwise, if b is close to nearest integer, there may
+*  be numeric difficulties due to big coefficients; so in this case the
+*  routine returns non-zero. */
+
+static int mir_ineq(const int n, const double a[], const double b,
+      double alpha[], double *beta, double *gamma)
+{     int j;
+      double f, t;
+      if (fabs(b - floor(b + .5)) < 0.01)
+         return 1;
+      f = b - floor(b);
+      for (j = 1; j <= n; j++)
+      {  t = (a[j] - floor(a[j])) - f;
+         if (t <= 0.0)
+            alpha[j] = floor(a[j]);
+         else
+            alpha[j] = floor(a[j]) + t / (1.0 - f);
+      }
+      *beta = floor(b);
+      *gamma = 1.0 / (1.0 - f);
+      return 0;
+}
+
+/***********************************************************************
+*  cmir_ineq - construct c-MIR inequality
+*
+*  Given the mixed knapsack set
+*
+*      MK              |N|
+*     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
+*                      +      +  j in N
+*
+*             x[j] <= u[j]},
+*
+*  a subset C of variables to be complemented, and a divisor delta > 0,
+*  this routine constructs the complemented MIR (c-MIR) inequality
+*
+*     sum   alpha[j] * x[j] <= beta + gamma * s,
+*    j in N
+*                      MK
+*  which is valid for X  .
+*
+*  If the c-MIR inequality has been successfully constructed, the
+*  routine returns zero. Otherwise, if there is a risk of numerical
+*  difficulties due to big coefficients (see comments to the routine
+*  mir_ineq), the routine cmir_ineq returns non-zero. */
+
+static int cmir_ineq(const int n, const double a[], const double b,
+      const double u[], const char cset[], const double delta,
+      double alpha[], double *beta, double *gamma)
+{     int j;
+      double *aa, bb;
+      aa = alpha, bb = b;
+      for (j = 1; j <= n; j++)
+      {  aa[j] = a[j] / delta;
+         if (cset[j])
+            aa[j] = - aa[j], bb -= a[j] * u[j];
+      }
+      bb /= delta;
+      if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
+      for (j = 1; j <= n; j++)
+      {  if (cset[j])
+            alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
+      }
+      *gamma /= delta;
+      return 0;
+}
+
+/***********************************************************************
+*  cmir_sep - c-MIR separation heuristic
+*
+*  Given the mixed knapsack set
+*
+*      MK              |N|
+*     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
+*                      +      +  j in N
+*
+*             x[j] <= u[j]}
+*
+*                           *   *
+*  and a fractional point (x , s ), this routine tries to construct
+*  c-MIR inequality
+*
+*     sum   alpha[j] * x[j] <= beta + gamma * s,
+*    j in N
+*                      MK
+*  which is valid for X   and has (desirably maximal) violation at the
+*  fractional point given. This is attained by choosing an appropriate
+*  set C of variables to be complemented and a divisor delta > 0, which
+*  together define corresponding c-MIR inequality.
+*
+*  If a violated c-MIR inequality has been successfully constructed,
+*  the routine returns its violation:
+*
+*                       *                      *
+*     sum   alpha[j] * x [j] - beta - gamma * s ,
+*    j in N
+*
+*  which is positive. In case of failure the routine returns zero. */
+
+struct vset { int j; double v; };
+
+static int cmir_cmp(const void *p1, const void *p2)
+{     const struct vset *v1 = p1, *v2 = p2;
+      if (v1->v < v2->v) return -1;
+      if (v1->v > v2->v) return +1;
+      return 0;
+}
+
+static double cmir_sep(const int n, const double a[], const double b,
+      const double u[], const double x[], const double s,
+      double alpha[], double *beta, double *gamma)
+{     int fail, j, k, nv, v;
+      double delta, eps, d_try[1+3], r, r_best;
+      char *cset;
+      struct vset *vset;
+      /* allocate working arrays */
+      cset = xcalloc(1+n, sizeof(char));
+      vset = xcalloc(1+n, sizeof(struct vset));
+      /* choose initial C */
+      for (j = 1; j <= n; j++)
+         cset[j] = (char)(x[j] >= 0.5 * u[j]);
+      /* choose initial delta */
+      r_best = delta = 0.0;
+      for (j = 1; j <= n; j++)
+      {  xassert(a[j] != 0.0);
+         /* if x[j] is close to its bounds, skip it */
+         eps = 1e-9 * (1.0 + fabs(u[j]));
+         if (x[j] < eps || x[j] > u[j] - eps) continue;
+         /* try delta = |a[j]| to construct c-MIR inequality */
+         fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
+            gamma);
+         if (fail) continue;
+         /* compute violation */
+         r = - (*beta) - (*gamma) * s;
+         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+         if (r_best < r) r_best = r, delta = fabs(a[j]);
+      }
+      if (r_best < 0.001) r_best = 0.0;
+      if (r_best == 0.0) goto done;
+      xassert(delta > 0.0);
+      /* try to increase violation by dividing delta by 2, 4, and 8,
+         respectively */
+      d_try[1] = delta / 2.0;
+      d_try[2] = delta / 4.0;
+      d_try[3] = delta / 8.0;
+      for (j = 1; j <= 3; j++)
+      {  /* construct c-MIR inequality */
+         fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
+            gamma);
+         if (fail) continue;
+         /* compute violation */
+         r = - (*beta) - (*gamma) * s;
+         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+         if (r_best < r) r_best = r, delta = d_try[j];
+      }
+      /* build subset of variables lying strictly between their bounds
+         and order it by nondecreasing values of |x[j] - u[j]/2| */
+      nv = 0;
+      for (j = 1; j <= n; j++)
+      {  /* if x[j] is close to its bounds, skip it */
+         eps = 1e-9 * (1.0 + fabs(u[j]));
+         if (x[j] < eps || x[j] > u[j] - eps) continue;
+         /* add x[j] to the subset */
+         nv++;
+         vset[nv].j = j;
+         vset[nv].v = fabs(x[j] - 0.5 * u[j]);
+      }
+      qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
+      /* try to increase violation by successively complementing each
+         variable in the subset */
+      for (v = 1; v <= nv; v++)
+      {  j = vset[v].j;
+         /* replace x[j] by its complement or vice versa */
+         cset[j] = (char)!cset[j];
+         /* construct c-MIR inequality */
+         fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
+         /* restore the variable */
+         cset[j] = (char)!cset[j];
+         /* do not replace the variable in case of failure */
+         if (fail) continue;
+         /* compute violation */
+         r = - (*beta) - (*gamma) * s;
+         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+         if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
+      }
+      /* construct the best c-MIR inequality chosen */
+      fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
+      xassert(!fail);
+done: /* free working arrays */
+      xfree(cset);
+      xfree(vset);
+      /* return to the calling routine */
+      return r_best;
+}
+
+static double generate(struct MIR *mir)
+{     /* try to generate violated c-MIR cut for modified constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk, nint;
+      double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
+      ios_copy_vec(mir->cut_vec, mir->mod_vec);
+      mir->cut_rhs = mir->mod_rhs;
+      /* remove small terms, which can appear due to substitution of
+         variable bounds */
+      ios_clean_vec(mir->cut_vec, DBL_EPSILON);
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      /* remove positive continuous terms to obtain MK relaxation */
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
+            mir->cut_vec->val[j] = 0.0;
+      }
+      ios_clean_vec(mir->cut_vec, 0.0);
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      /* move integer terms to the beginning of the sparse vector and
+         determine the number of integer variables */
+      nint = 0;
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k])
+         {  double temp;
+            nint++;
+            /* interchange elements [nint] and [j] */
+            kk = mir->cut_vec->ind[nint];
+            mir->cut_vec->pos[k] = nint;
+            mir->cut_vec->pos[kk] = j;
+            mir->cut_vec->ind[nint] = k;
+            mir->cut_vec->ind[j] = kk;
+            temp = mir->cut_vec->val[nint];
+            mir->cut_vec->val[nint] = mir->cut_vec->val[j];
+            mir->cut_vec->val[j] = temp;
+         }
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      /* if there is no integer variable, nothing to generate */
+      if (nint == 0) goto done;
+      /* allocate working arrays */
+      u = xcalloc(1+nint, sizeof(double));
+      x = xcalloc(1+nint, sizeof(double));
+      alpha = xcalloc(1+nint, sizeof(double));
+      /* determine u and x */
+      for (j = 1; j <= nint; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(m+1 <= k && k <= m+n);
+         xassert(mir->isint[k]);
+         u[j] = mir->ub[k] - mir->lb[k];
+         xassert(u[j] >= 1.0);
+         if (mir->subst[k] == 'L')
+            x[j] = mir->x[k] - mir->lb[k];
+         else if (mir->subst[k] == 'U')
+            x[j] = mir->ub[k] - mir->x[k];
+         else
+            xassert(k != k);
+         xassert(x[j] >= -0.001);
+         if (x[j] < 0.0) x[j] = 0.0;
+      }
+      /* compute s = - sum of continuous terms */
+      s = 0.0;
+      for (j = nint+1; j <= mir->cut_vec->nnz; j++)
+      {  double x;
+         k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         /* must be continuous */
+         xassert(!mir->isint[k]);
+         if (mir->subst[k] == 'L')
+         {  xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+               x = mir->x[k] - mir->lb[k];
+            else
+               x = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         else if (mir->subst[k] == 'U')
+         {  xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+               x = mir->ub[k] - mir->x[k];
+            else
+               x = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         else
+            xassert(k != k);
+         xassert(x >= -0.001);
+         if (x < 0.0) x = 0.0;
+         s -= mir->cut_vec->val[j] * x;
+      }
+      xassert(s >= 0.0);
+      /* apply heuristic to obtain most violated c-MIR inequality */
+      b = mir->cut_rhs;
+      r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
+         &beta, &gamma);
+      if (r_best == 0.0) goto skip;
+      xassert(r_best > 0.0);
+      /* convert to raw cut */
+      /* sum alpha[j] * x[j] <= beta + gamma * s */
+      for (j = 1; j <= nint; j++)
+         mir->cut_vec->val[j] = alpha[j];
+      for (j = nint+1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         if (k <= m+n) mir->cut_vec->val[j] *= gamma;
+      }
+      mir->cut_rhs = beta;
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+skip: /* free working arrays */
+      xfree(u);
+      xfree(x);
+      xfree(alpha);
+done: return r_best;
+}
+
+#if _MIR_DEBUG
+static void check_raw_cut(struct MIR *mir, double r_best)
+{     /* check raw cut before back bound substitution */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk;
+      double r, big, x;
+      /* compute the residual r = sum a[k] * x[k] - b and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->subst[k] == 'L')
+         {  xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+               x = mir->x[k] - mir->lb[k];
+            else
+               x = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         else if (mir->subst[k] == 'U')
+         {  xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+               x = mir->ub[k] - mir->x[k];
+            else
+               x = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         else
+            xassert(k != k);
+         r += mir->cut_vec->val[j] * x;
+         if (big < fabs(mir->cut_vec->val[j]))
+            big = fabs(mir->cut_vec->val[j]);
+      }
+      r -= mir->cut_rhs;
+      if (big < fabs(mir->cut_rhs))
+         big = fabs(mir->cut_rhs);
+      /* the residual must be close to r_best */
+      xassert(fabs(r - r_best) <= 1e-6 * big);
+      return;
+}
+#endif
+
+static void back_subst(struct MIR *mir)
+{     /* back substitution of original bounds */
+      int m = mir->m;
+      int n = mir->n;
+      int j, jj, k, kk;
+      /* at first, restore bounds of integer variables (because on
+         restoring variable bounds of continuous variables we need
+         original, not shifted, bounds of integer variables) */
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (!mir->isint[k]) continue; /* skip continuous */
+         if (mir->subst[k] == 'L')
+         {  /* x'[k] = x[k] - lb[k] */
+            xassert(mir->lb[k] != -DBL_MAX);
+            xassert(mir->vlb[k] == 0);
+            mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x'[k] = ub[k] - x[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            xassert(mir->vub[k] == 0);
+            mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
+            mir->cut_vec->val[j] = - mir->cut_vec->val[j];
+         }
+         else
+            xassert(k != k);
+      }
+      /* now restore bounds of continuous variables */
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k]) continue; /* skip integer */
+         if (mir->subst[k] == 'L')
+         {  /* x'[k] = x[k] - (lower bound) */
+            xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+            {  /* x'[k] = x[k] - lb[k] */
+               mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
+            }
+            else
+            {  /* x'[k] = x[k] - lb[k] * x[kk] */
+               jj = mir->cut_vec->pos[kk];
+#if 0
+               xassert(jj != 0);
+#else
+               if (jj == 0)
+               {  ios_set_vj(mir->cut_vec, kk, 1.0);
+                  jj = mir->cut_vec->pos[kk];
+                  xassert(jj != 0);
+                  mir->cut_vec->val[jj] = 0.0;
+               }
+#endif
+               mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
+                  mir->lb[k];
+            }
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x'[k] = (upper bound) - x[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+            {  /* x'[k] = ub[k] - x[k] */
+               mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
+            }
+            else
+            {  /* x'[k] = ub[k] * x[kk] - x[k] */
+               jj = mir->cut_vec->pos[kk];
+               if (jj == 0)
+               {  ios_set_vj(mir->cut_vec, kk, 1.0);
+                  jj = mir->cut_vec->pos[kk];
+                  xassert(jj != 0);
+                  mir->cut_vec->val[jj] = 0.0;
+               }
+               mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
+                  mir->ub[k];
+            }
+            mir->cut_vec->val[j] = - mir->cut_vec->val[j];
+         }
+         else
+            xassert(k != k);
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_cut_row(struct MIR *mir, double r_best)
+{     /* check the cut after back bound substitution or elimination of
+         auxiliary variables */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k;
+      double r, big;
+      /* compute the residual r = sum a[k] * x[k] - b and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         r += mir->cut_vec->val[j] * mir->x[k];
+         if (big < fabs(mir->cut_vec->val[j]))
+            big = fabs(mir->cut_vec->val[j]);
+      }
+      r -= mir->cut_rhs;
+      if (big < fabs(mir->cut_rhs))
+         big = fabs(mir->cut_rhs);
+      /* the residual must be close to r_best */
+      xassert(fabs(r - r_best) <= 1e-6 * big);
+      return;
+}
+#endif
+
+static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
+{     /* final substitution to eliminate auxiliary variables */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      GLPAIJ *aij;
+      int j, k, kk, jj;
+      for (j = mir->cut_vec->nnz; j >= 1; j--)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (k > m) continue; /* skip structurals */
+         for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
+         {  kk = m + aij->col->j; /* structural */
+            jj = mir->cut_vec->pos[kk];
+            if (jj == 0)
+            {  ios_set_vj(mir->cut_vec, kk, 1.0);
+               jj = mir->cut_vec->pos[kk];
+               mir->cut_vec->val[jj] = 0.0;
+            }
+            mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
+         }
+         mir->cut_vec->val[j] = 0.0;
+      }
+      ios_clean_vec(mir->cut_vec, 0.0);
+      return;
+}
+
+static void add_cut(glp_tree *tree, struct MIR *mir)
+{     /* add constructed cut inequality to the cut pool */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, len;
+      int *ind = xcalloc(1+n, sizeof(int));
+      double *val = xcalloc(1+n, sizeof(double));
+      len = 0;
+      for (j = mir->cut_vec->nnz; j >= 1; j--)
+      {  k = mir->cut_vec->ind[j];
+         xassert(m+1 <= k && k <= m+n);
+         len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
+      }
+#if 0
+      ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
+         mir->cut_rhs);
+#else
+      glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
+         mir->cut_rhs);
+#endif
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+static int aggregate_row(glp_tree *tree, struct MIR *mir)
+{     /* try to aggregate another row */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      GLPAIJ *aij;
+      IOSVEC *v;
+      int ii, j, jj, k, kk, kappa = 0, ret = 0;
+      double d1, d2, d, d_max = 0.0;
+      /* choose appropriate structural variable in the aggregated row
+         to be substituted */
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (k <= m) continue; /* skip auxiliary var */
+         if (mir->isint[k]) continue; /* skip integer var */
+         if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
+         /* compute distance from x[k] to its lower bound */
+         kk = mir->vlb[k];
+         if (kk == 0)
+         {  if (mir->lb[k] == -DBL_MAX)
+               d1 = DBL_MAX;
+            else
+               d1 = mir->x[k] - mir->lb[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->lb[k] != -DBL_MAX);
+            d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         /* compute distance from x[k] to its upper bound */
+         kk = mir->vub[k];
+         if (kk == 0)
+         {  if (mir->vub[k] == +DBL_MAX)
+               d2 = DBL_MAX;
+            else
+               d2 = mir->ub[k] - mir->x[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->ub[k] != +DBL_MAX);
+            d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         /* x[k] cannot be free */
+         xassert(d1 != DBL_MAX || d2 != DBL_MAX);
+         /* d = min(d1, d2) */
+         d = (d1 <= d2 ? d1 : d2);
+         xassert(d != DBL_MAX);
+         /* should not be close to corresponding bound */
+         if (d < 0.001) continue;
+         if (d_max < d) d_max = d, kappa = k;
+      }
+      if (kappa == 0)
+      {  /* nothing chosen */
+         ret = 1;
+         goto done;
+      }
+      /* x[kappa] has been chosen */
+      xassert(m+1 <= kappa && kappa <= m+n);
+      xassert(!mir->isint[kappa]);
+      /* find another row, which have not been used yet, to eliminate
+         x[kappa] from the aggregated row */
+      for (ii = 1; ii <= m; ii++)
+      {  if (mir->skip[ii]) continue;
+         for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
+            if (aij->col->j == kappa - m) break;
+         if (aij != NULL && fabs(aij->val) >= 0.001) break;
+      }
+      if (ii > m)
+      {  /* nothing found */
+         ret = 2;
+         goto done;
+      }
+      /* row ii has been found; include it in the aggregated list */
+      mir->agg_cnt++;
+      xassert(mir->agg_cnt <= MAXAGGR);
+      mir->agg_row[mir->agg_cnt] = ii;
+      mir->skip[ii] = 2;
+      /* v := new row */
+      v = ios_create_vec(m+n);
+      ios_set_vj(v, ii, 1.0);
+      for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
+         ios_set_vj(v, m + aij->col->j, - aij->val);
+#if _MIR_DEBUG
+      ios_check_vec(v);
+#endif
+      /* perform gaussian elimination to remove x[kappa] */
+      j = mir->agg_vec->pos[kappa];
+      xassert(j != 0);
+      jj = v->pos[kappa];
+      xassert(jj != 0);
+      ios_linear_comb(mir->agg_vec,
+         - mir->agg_vec->val[j] / v->val[jj], v);
+      ios_delete_vec(v);
+      ios_set_vj(mir->agg_vec, kappa, 0.0);
+#if _MIR_DEBUG
+      ios_check_vec(mir->agg_vec);
+#endif
+done: return ret;
+}
+
+void ios_mir_gen(glp_tree *tree, void *gen)
+{     /* main routine to generate MIR cuts */
+      glp_prob *mip = tree->mip;
+      struct MIR *mir = gen;
+      int m = mir->m;
+      int n = mir->n;
+      int i;
+      double r_best;
+      xassert(mip->m >= m);
+      xassert(mip->n == n);
+      /* obtain current point */
+      get_current_point(tree, mir);
+#if _MIR_DEBUG
+      /* check current point */
+      check_current_point(mir);
+#endif
+      /* reset bound substitution flags */
+      memset(&mir->subst[1], '?', m+n);
+      /* try to generate a set of violated MIR cuts */
+      for (i = 1; i <= m; i++)
+      {  if (mir->skip[i]) continue;
+         /* use original i-th row as initial aggregated constraint */
+         initial_agg_row(tree, mir, i);
+loop:    ;
+#if _MIR_DEBUG
+         /* check aggregated row */
+         check_agg_row(mir);
+#endif
+         /* substitute fixed variables into aggregated constraint */
+         subst_fixed_vars(mir);
+#if _MIR_DEBUG
+         /* check aggregated row */
+         check_agg_row(mir);
+#endif
+#if _MIR_DEBUG
+         /* check bound substitution flags */
+         {  int k;
+            for (k = 1; k <= m+n; k++)
+               xassert(mir->subst[k] == '?');
+         }
+#endif
+         /* apply bound substitution heuristic */
+         bound_subst_heur(mir);
+         /* substitute bounds and build modified constraint */
+         build_mod_row(mir);
+#if _MIR_DEBUG
+         /* check modified row */
+         check_mod_row(mir);
+#endif
+         /* try to generate violated c-MIR cut for modified row */
+         r_best = generate(mir);
+         if (r_best > 0.0)
+         {  /* success */
+#if _MIR_DEBUG
+            /* check raw cut before back bound substitution */
+            check_raw_cut(mir, r_best);
+#endif
+            /* back substitution of original bounds */
+            back_subst(mir);
+#if _MIR_DEBUG
+            /* check the cut after back bound substitution */
+            check_cut_row(mir, r_best);
+#endif
+            /* final substitution to eliminate auxiliary variables */
+            subst_aux_vars(tree, mir);
+#if _MIR_DEBUG
+            /* check the cut after elimination of auxiliaries */
+            check_cut_row(mir, r_best);
+#endif
+            /* add constructed cut inequality to the cut pool */
+            add_cut(tree, mir);
+         }
+         /* reset bound substitution flags */
+         {  int j, k;
+            for (j = 1; j <= mir->mod_vec->nnz; j++)
+            {  k = mir->mod_vec->ind[j];
+               xassert(1 <= k && k <= m+n);
+               xassert(mir->subst[k] != '?');
+               mir->subst[k] = '?';
+            }
+         }
+         if (r_best == 0.0)
+         {  /* failure */
+            if (mir->agg_cnt < MAXAGGR)
+            {  /* try to aggregate another row */
+               if (aggregate_row(tree, mir) == 0) goto loop;
+            }
+         }
+         /* unmark rows used in the aggregated constraint */
+         {  int k, ii;
+            for (k = 1; k <= mir->agg_cnt; k++)
+            {  ii = mir->agg_row[k];
+               xassert(1 <= ii && ii <= m);
+               xassert(mir->skip[ii] == 2);
+               mir->skip[ii] = 0;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_mir_term - terminate MIR cut generator
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_mir_term(void *gen);
+*
+*  DESCRIPTION
+*
+*  The routine ios_mir_term deletes the MIR cut generator working area
+*  freeing all the memory allocated to it. */
+
+void ios_mir_term(void *gen)
+{     struct MIR *mir = gen;
+      xfree(mir->skip);
+      xfree(mir->isint);
+      xfree(mir->lb);
+      xfree(mir->vlb);
+      xfree(mir->ub);
+      xfree(mir->vub);
+      xfree(mir->x);
+      xfree(mir->agg_row);
+      ios_delete_vec(mir->agg_vec);
+      xfree(mir->subst);
+      ios_delete_vec(mir->mod_vec);
+      ios_delete_vec(mir->cut_vec);
+      xfree(mir);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios07.c b/optional/glpk/glpios07.c
new file mode 100644
index 0000000..b94b0c3
--- /dev/null
+++ b/optional/glpk/glpios07.c
@@ -0,0 +1,554 @@
+/* glpios07.c (mixed cover cut generator) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/*----------------------------------------------------------------------
+-- COVER INEQUALITIES
+--
+-- Consider the set of feasible solutions to 0-1 knapsack problem:
+--
+--    sum a[j]*x[j] <= b,                                            (1)
+--  j in J
+--
+--    x[j] is binary,                                                (2)
+--
+-- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
+-- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
+--
+-- A set C within J is called a cover if
+--
+--    sum a[j] > b.                                                  (3)
+--  j in C
+--
+-- For any cover C the inequality
+--
+--    sum x[j] <= |C| - 1                                            (4)
+--  j in C
+--
+-- is called a cover inequality and is valid for (1)-(2).
+--
+-- MIXED COVER INEQUALITIES
+--
+-- Consider the set of feasible solutions to mixed knapsack problem:
+--
+--    sum a[j]*x[j] + y <= b,                                        (5)
+--  j in J
+--
+--    x[j] is binary,                                                (6)
+--
+--    0 <= y <= u is continuous,                                     (7)
+--
+-- where again we assume that a[j] > 0.
+--
+-- Let C within J be some set. From (1)-(4) it follows that
+--
+--    sum a[j] > b - y                                               (8)
+--  j in C
+--
+-- implies
+--
+--    sum x[j] <= |C| - 1.                                           (9)
+--  j in C
+--
+-- Thus, we need to modify the inequality (9) in such a way that it be
+-- a constraint only if the condition (8) is satisfied.
+--
+-- Consider the following inequality:
+--
+--    sum x[j] <= |C| - t.                                          (10)
+--  j in C
+--
+-- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
+-- binary variables. On the other hand, if t <= 0, (10) being satisfied
+-- for any values of x[j] is not a constraint.
+--
+-- Let
+--
+--    t' = sum a[j] + y - b.                                        (11)
+--       j in C
+--
+-- It is understood that the condition t' > 0 is equivalent to (8).
+-- Besides, from (6)-(7) it follows that t' has an implied upper bound:
+--
+--    t'max = sum a[j] + u - b.                                     (12)
+--          j in C
+--
+-- This allows to express the parameter t having desired properties:
+--
+--    t = t' / t'max.                                               (13)
+--
+-- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
+-- is equivalent to (8).
+--
+-- Thus, the inequality (10), where t is given by formula (13) is valid
+-- for (5)-(7).
+--
+-- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
+-- (10) is transformed to the conditions (3) and (4).
+--
+-- GENERATING MIXED COVER CUTS
+--
+-- To generate a mixed cover cut in the form (10) we need to find such
+-- set C which satisfies to the inequality (8) and for which, in turn,
+-- the inequality (10) is violated in the current point.
+--
+-- Substituting t from (13) to (10) gives:
+--
+--                        1
+--    sum x[j] <= |C| - -----  (sum a[j] + y - b),                  (14)
+--  j in C              t'max j in C
+--
+-- and finally we have the cut inequality in the standard form:
+--
+--    sum x[j] + alfa * y <= beta,                                  (15)
+--  j in C
+--
+-- where:
+--
+--    alfa = 1 / t'max,                                             (16)
+--
+--    beta = |C| - alfa *  (sum a[j] - b).                          (17)
+--                        j in C                                      */
+
+#if 1
+#define MAXTRY 1000
+#else
+#define MAXTRY 10000
+#endif
+
+static int cover2(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *_alfa, double *_beta)
+{     /* try to generate mixed cover cut using two-element cover */
+      int i, j, try = 0, ret = 0;
+      double eps, alfa, beta, temp, rmax = 0.001;
+      eps = 0.001 * (1.0 + fabs(b));
+      for (i = 0+1; i <= n; i++)
+      for (j = i+1; j <= n; j++)
+      {  /* C = {i, j} */
+         try++;
+         if (try > MAXTRY) goto done;
+         /* check if condition (8) is satisfied */
+         if (a[i] + a[j] + y > b + eps)
+         {  /* compute parameters for inequality (15) */
+            temp = a[i] + a[j] - b;
+            alfa = 1.0 / (temp + u);
+            beta = 2.0 - alfa * temp;
+            /* compute violation of inequality (15) */
+            temp = x[i] + x[j] + alfa * y - beta;
+            /* choose C providing maximum violation */
+            if (rmax < temp)
+            {  rmax = temp;
+               cov[1] = i;
+               cov[2] = j;
+               *_alfa = alfa;
+               *_beta = beta;
+               ret = 1;
+            }
+         }
+      }
+done: return ret;
+}
+
+static int cover3(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *_alfa, double *_beta)
+{     /* try to generate mixed cover cut using three-element cover */
+      int i, j, k, try = 0, ret = 0;
+      double eps, alfa, beta, temp, rmax = 0.001;
+      eps = 0.001 * (1.0 + fabs(b));
+      for (i = 0+1; i <= n; i++)
+      for (j = i+1; j <= n; j++)
+      for (k = j+1; k <= n; k++)
+      {  /* C = {i, j, k} */
+         try++;
+         if (try > MAXTRY) goto done;
+         /* check if condition (8) is satisfied */
+         if (a[i] + a[j] + a[k] + y > b + eps)
+         {  /* compute parameters for inequality (15) */
+            temp = a[i] + a[j] + a[k] - b;
+            alfa = 1.0 / (temp + u);
+            beta = 3.0 - alfa * temp;
+            /* compute violation of inequality (15) */
+            temp = x[i] + x[j] + x[k] + alfa * y - beta;
+            /* choose C providing maximum violation */
+            if (rmax < temp)
+            {  rmax = temp;
+               cov[1] = i;
+               cov[2] = j;
+               cov[3] = k;
+               *_alfa = alfa;
+               *_beta = beta;
+               ret = 1;
+            }
+         }
+      }
+done: return ret;
+}
+
+static int cover4(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *_alfa, double *_beta)
+{     /* try to generate mixed cover cut using four-element cover */
+      int i, j, k, l, try = 0, ret = 0;
+      double eps, alfa, beta, temp, rmax = 0.001;
+      eps = 0.001 * (1.0 + fabs(b));
+      for (i = 0+1; i <= n; i++)
+      for (j = i+1; j <= n; j++)
+      for (k = j+1; k <= n; k++)
+      for (l = k+1; l <= n; l++)
+      {  /* C = {i, j, k, l} */
+         try++;
+         if (try > MAXTRY) goto done;
+         /* check if condition (8) is satisfied */
+         if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
+         {  /* compute parameters for inequality (15) */
+            temp = a[i] + a[j] + a[k] + a[l] - b;
+            alfa = 1.0 / (temp + u);
+            beta = 4.0 - alfa * temp;
+            /* compute violation of inequality (15) */
+            temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
+            /* choose C providing maximum violation */
+            if (rmax < temp)
+            {  rmax = temp;
+               cov[1] = i;
+               cov[2] = j;
+               cov[3] = k;
+               cov[4] = l;
+               *_alfa = alfa;
+               *_beta = beta;
+               ret = 1;
+            }
+         }
+      }
+done: return ret;
+}
+
+static int cover(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *alfa, double *beta)
+{     /* try to generate mixed cover cut;
+         input (see (5)):
+         n        is the number of binary variables;
+         a[1:n]   are coefficients at binary variables;
+         b        is the right-hand side;
+         u        is upper bound of continuous variable;
+         x[1:n]   are values of binary variables at current point;
+         y        is value of continuous variable at current point;
+         output (see (15), (16), (17)):
+         cov[1:r] are indices of binary variables included in cover C,
+                  where r is the set cardinality returned on exit;
+         alfa     coefficient at continuous variable;
+         beta     is the right-hand side; */
+      int j;
+      /* perform some sanity checks */
+      xassert(n >= 2);
+      for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
+#if 1 /* ??? */
+      xassert(b > -1e-5);
+#else
+      xassert(b > 0.0);
+#endif
+      xassert(u >= 0.0);
+      for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
+      xassert(0.0 <= y && y <= u);
+      /* try to generate mixed cover cut */
+      if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
+      if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
+      if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
+      return 0;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_cover_cut - generate mixed cover cut.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
+--    double work[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_cover_cut generates a mixed cover cut for a given
+-- row of the MIP problem.
+--
+-- The given row of the MIP problem should be explicitly specified in
+-- the form:
+--
+--    sum{j in J} a[j]*x[j] <= b.                                    (1)
+--
+-- On entry indices (ordinal numbers) of structural variables, which
+-- have non-zero constraint coefficients, should be placed in locations
+-- ind[1], ..., ind[len], and corresponding constraint coefficients
+-- should be placed in locations val[1], ..., val[len]. The right-hand
+-- side b should be stored in location val[0].
+--
+-- The working array work should have at least nb locations, where nb
+-- is the number of binary variables in (1).
+--
+-- The routine generates a mixed cover cut in the same form as (1) and
+-- stores the cut coefficients and right-hand side in the same way as
+-- just described above.
+--
+-- RETURNS
+--
+-- If the cutting plane has been successfully generated, the routine
+-- returns 1 <= len' <= n, which is the number of non-zero coefficients
+-- in the inequality constraint. Otherwise, the routine returns zero. */
+
+static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
+      double work[])
+{     int cov[1+4], j, k, nb, newlen, r;
+      double f_min, f_max, alfa, beta, u, *x = work, y;
+      /* substitute and remove fixed variables */
+      newlen = 0;
+      for (k = 1; k <= len; k++)
+      {  j = ind[k];
+         if (lpx_get_col_type(lp, j) == LPX_FX)
+            val[0] -= val[k] * lpx_get_col_lb(lp, j);
+         else
+         {  newlen++;
+            ind[newlen] = ind[k];
+            val[newlen] = val[k];
+         }
+      }
+      len = newlen;
+      /* move binary variables to the beginning of the list so that
+         elements 1, 2, ..., nb correspond to binary variables, and
+         elements nb+1, nb+2, ..., len correspond to rest variables */
+      nb = 0;
+      for (k = 1; k <= len; k++)
+      {  j = ind[k];
+         if (lpx_get_col_kind(lp, j) == LPX_IV &&
+             lpx_get_col_type(lp, j) == LPX_DB &&
+             lpx_get_col_lb(lp, j) == 0.0 &&
+             lpx_get_col_ub(lp, j) == 1.0)
+         {  /* binary variable */
+            int ind_k;
+            double val_k;
+            nb++;
+            ind_k = ind[nb], val_k = val[nb];
+            ind[nb] = ind[k], val[nb] = val[k];
+            ind[k] = ind_k, val[k] = val_k;
+         }
+      }
+      /* now the specified row has the form:
+         sum a[j]*x[j] + sum a[j]*y[j] <= b,
+         where x[j] are binary variables, y[j] are rest variables */
+      /* at least two binary variables are needed */
+      if (nb < 2) return 0;
+      /* compute implied lower and upper bounds for sum a[j]*y[j] */
+      f_min = f_max = 0.0;
+      for (k = nb+1; k <= len; k++)
+      {  j = ind[k];
+         /* both bounds must be finite */
+         if (lpx_get_col_type(lp, j) != LPX_DB) return 0;
+         if (val[k] > 0.0)
+         {  f_min += val[k] * lpx_get_col_lb(lp, j);
+            f_max += val[k] * lpx_get_col_ub(lp, j);
+         }
+         else
+         {  f_min += val[k] * lpx_get_col_ub(lp, j);
+            f_max += val[k] * lpx_get_col_lb(lp, j);
+         }
+      }
+      /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
+         sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
+         sum a[j]*x[j] + y <= b - f_min,
+         where y = sum a[j]*y[j] - f_min;
+         note that 0 <= y <= u, u = f_max - f_min */
+      /* determine upper bound of y */
+      u = f_max - f_min;
+      /* determine value of y at the current point */
+      y = 0.0;
+      for (k = nb+1; k <= len; k++)
+      {  j = ind[k];
+         y += val[k] * lpx_get_col_prim(lp, j);
+      }
+      y -= f_min;
+      if (y < 0.0) y = 0.0;
+      if (y > u) y = u;
+      /* modify the right-hand side b */
+      val[0] -= f_min;
+      /* now the transformed row has the form:
+         sum a[j]*x[j] + y <= b, where 0 <= y <= u */
+      /* determine values of x[j] at the current point */
+      for (k = 1; k <= nb; k++)
+      {  j = ind[k];
+         x[k] = lpx_get_col_prim(lp, j);
+         if (x[k] < 0.0) x[k] = 0.0;
+         if (x[k] > 1.0) x[k] = 1.0;
+      }
+      /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
+      for (k = 1; k <= nb; k++)
+      {  if (val[k] < 0.0)
+         {  ind[k] = - ind[k];
+            val[k] = - val[k];
+            val[0] += val[k];
+            x[k] = 1.0 - x[k];
+         }
+      }
+      /* try to generate a mixed cover cut for the transformed row */
+      r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
+      if (r == 0) return 0;
+      xassert(2 <= r && r <= 4);
+      /* now the cut is in the form:
+         sum{j in C} x[j] + alfa * y <= beta */
+      /* store the right-hand side beta */
+      ind[0] = 0, val[0] = beta;
+      /* restore the original ordinal numbers of x[j] */
+      for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
+      /* store cut coefficients at binary variables complementing back
+         the variables having negative row coefficients */
+      xassert(r <= nb);
+      for (k = 1; k <= r; k++)
+      {  if (cov[k] > 0)
+         {  ind[k] = +cov[k];
+            val[k] = +1.0;
+         }
+         else
+         {  ind[k] = -cov[k];
+            val[k] = -1.0;
+            val[0] -= 1.0;
+         }
+      }
+      /* substitute y = sum a[j]*y[j] - f_min */
+      for (k = nb+1; k <= len; k++)
+      {  r++;
+         ind[r] = ind[k];
+         val[r] = alfa * val[k];
+      }
+      val[0] += alfa * f_min;
+      xassert(r <= len);
+      len = r;
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_eval_row - compute explictily specified row.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_eval_row computes the primal value of an explicitly
+-- specified row using current values of structural variables.
+--
+-- The explicitly specified row may be thought as a linear form:
+--
+--    y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
+--
+-- where y is an auxiliary variable for this row, a[j] are coefficients
+-- of the linear form, x[m+j] are structural variables.
+--
+-- On entry column indices and numerical values of non-zero elements of
+-- the row should be stored in locations ind[1], ..., ind[len] and
+-- val[1], ..., val[len], where len is the number of non-zero elements.
+-- The array ind and val are not changed on exit.
+--
+-- RETURNS
+--
+-- The routine returns a computed value of y, the auxiliary variable of
+-- the specified row. */
+
+static double lpx_eval_row(LPX *lp, int len, int ind[], double val[])
+{     int n = lpx_get_num_cols(lp);
+      int j, k;
+      double sum = 0.0;
+      if (len < 0)
+         xerror("lpx_eval_row: len = %d; invalid row length\n", len);
+      for (k = 1; k <= len; k++)
+      {  j = ind[k];
+         if (!(1 <= j && j <= n))
+            xerror("lpx_eval_row: j = %d; column number out of range\n",
+               j);
+         sum += val[k] * lpx_get_col_prim(lp, j);
+      }
+      return sum;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_cov_gen - generate mixed cover cuts
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_cov_gen(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_cov_gen generates mixed cover cuts for the current
+*  point and adds them to the cut pool. */
+
+void ios_cov_gen(glp_tree *tree)
+{     glp_prob *prob = tree->mip;
+      int m = lpx_get_num_rows(prob);
+      int n = lpx_get_num_cols(prob);
+      int i, k, type, kase, len, *ind;
+      double r, *val, *work;
+      xassert(lpx_get_status(prob) == LPX_OPT);
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      work = xcalloc(1+n, sizeof(double));
+      /* look through all rows */
+      for (i = 1; i <= m; i++)
+      for (kase = 1; kase <= 2; kase++)
+      {  type = lpx_get_row_type(prob, i);
+         if (kase == 1)
+         {  /* consider rows of '<=' type */
+            if (!(type == LPX_UP || type == LPX_DB)) continue;
+            len = lpx_get_mat_row(prob, i, ind, val);
+            val[0] = lpx_get_row_ub(prob, i);
+         }
+         else
+         {  /* consider rows of '>=' type */
+            if (!(type == LPX_LO || type == LPX_DB)) continue;
+            len = lpx_get_mat_row(prob, i, ind, val);
+            for (k = 1; k <= len; k++) val[k] = - val[k];
+            val[0] = - lpx_get_row_lb(prob, i);
+         }
+         /* generate mixed cover cut:
+            sum{j in J} a[j] * x[j] <= b */
+         len = lpx_cover_cut(prob, len, ind, val, work);
+         if (len == 0) continue;
+         /* at the current point the cut inequality is violated, i.e.
+            sum{j in J} a[j] * x[j] - b > 0 */
+         r = lpx_eval_row(prob, len, ind, val) - val[0];
+         if (r < 1e-3) continue;
+         /* add the cut to the cut pool */
+         glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
+            GLP_UP, val[0]);
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      xfree(work);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios08.c b/optional/glpk/glpios08.c
new file mode 100644
index 0000000..444d908
--- /dev/null
+++ b/optional/glpk/glpios08.c
@@ -0,0 +1,912 @@
+/* glpios08.c (clique cut generator) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+#include "glpios.h"
+
+static double get_row_lb(LPX *lp, int i)
+{     /* this routine returns lower bound of row i or -DBL_MAX if the
+         row has no lower bound */
+      double lb;
+      switch (lpx_get_row_type(lp, i))
+      {  case LPX_FR:
+         case LPX_UP:
+            lb = -DBL_MAX;
+            break;
+         case LPX_LO:
+         case LPX_DB:
+         case LPX_FX:
+            lb = lpx_get_row_lb(lp, i);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+static double get_row_ub(LPX *lp, int i)
+{     /* this routine returns upper bound of row i or +DBL_MAX if the
+         row has no upper bound */
+      double ub;
+      switch (lpx_get_row_type(lp, i))
+      {  case LPX_FR:
+         case LPX_LO:
+            ub = +DBL_MAX;
+            break;
+         case LPX_UP:
+         case LPX_DB:
+         case LPX_FX:
+            ub = lpx_get_row_ub(lp, i);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+static double get_col_lb(LPX *lp, int j)
+{     /* this routine returns lower bound of column j or -DBL_MAX if
+         the column has no lower bound */
+      double lb;
+      switch (lpx_get_col_type(lp, j))
+      {  case LPX_FR:
+         case LPX_UP:
+            lb = -DBL_MAX;
+            break;
+         case LPX_LO:
+         case LPX_DB:
+         case LPX_FX:
+            lb = lpx_get_col_lb(lp, j);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+static double get_col_ub(LPX *lp, int j)
+{     /* this routine returns upper bound of column j or +DBL_MAX if
+         the column has no upper bound */
+      double ub;
+      switch (lpx_get_col_type(lp, j))
+      {  case LPX_FR:
+         case LPX_LO:
+            ub = +DBL_MAX;
+            break;
+         case LPX_UP:
+         case LPX_DB:
+         case LPX_FX:
+            ub = lpx_get_col_ub(lp, j);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+static int is_binary(LPX *lp, int j)
+{     /* this routine checks if variable x[j] is binary */
+      return
+         lpx_get_col_kind(lp, j) == LPX_IV &&
+         lpx_get_col_type(lp, j) == LPX_DB &&
+         lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0;
+}
+
+static double eval_lf_min(LPX *lp, int len, int ind[], double val[])
+{     /* this routine computes the minimum of a specified linear form
+
+            sum a[j]*x[j]
+             j
+
+         using the formula:
+
+            min =   sum   a[j]*lb[j] +   sum   a[j]*ub[j],
+                  j in J+              j in J-
+
+         where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
+         are lower and upper bound of variable x[j], resp. */
+      int j, t;
+      double lb, ub, sum;
+      sum = 0.0;
+      for (t = 1; t <= len; t++)
+      {  j = ind[t];
+         if (val[t] > 0.0)
+         {  lb = get_col_lb(lp, j);
+            if (lb == -DBL_MAX)
+            {  sum = -DBL_MAX;
+               break;
+            }
+            sum += val[t] * lb;
+         }
+         else if (val[t] < 0.0)
+         {  ub = get_col_ub(lp, j);
+            if (ub == +DBL_MAX)
+            {  sum = -DBL_MAX;
+               break;
+            }
+            sum += val[t] * ub;
+         }
+         else
+            xassert(val != val);
+      }
+      return sum;
+}
+
+static double eval_lf_max(LPX *lp, int len, int ind[], double val[])
+{     /* this routine computes the maximum of a specified linear form
+
+            sum a[j]*x[j]
+             j
+
+         using the formula:
+
+            max =   sum   a[j]*ub[j] +   sum   a[j]*lb[j],
+                  j in J+              j in J-
+
+         where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
+         are lower and upper bound of variable x[j], resp. */
+      int j, t;
+      double lb, ub, sum;
+      sum = 0.0;
+      for (t = 1; t <= len; t++)
+      {  j = ind[t];
+         if (val[t] > 0.0)
+         {  ub = get_col_ub(lp, j);
+            if (ub == +DBL_MAX)
+            {  sum = +DBL_MAX;
+               break;
+            }
+            sum += val[t] * ub;
+         }
+         else if (val[t] < 0.0)
+         {  lb = get_col_lb(lp, j);
+            if (lb == -DBL_MAX)
+            {  sum = +DBL_MAX;
+               break;
+            }
+            sum += val[t] * lb;
+         }
+         else
+            xassert(val != val);
+      }
+      return sum;
+}
+
+/*----------------------------------------------------------------------
+-- probing - determine logical relation between binary variables.
+--
+-- This routine tentatively sets a binary variable to 0 and then to 1
+-- and examines whether another binary variable is caused to be fixed.
+--
+-- The examination is based only on one row (constraint), which is the
+-- following:
+--
+--    L <= sum a[j]*x[j] <= U.                                       (1)
+--          j
+--
+-- Let x[p] be a probing variable, x[q] be an examined variable. Then
+-- (1) can be written as:
+--
+--    L <=   sum  a[j]*x[j] + a[p]*x[p] + a[q]*x[q] <= U,            (2)
+--         j in J'
+--
+-- where J' = {j: j != p and j != q}.
+--
+-- Let
+--
+--    L' = L - a[p]*x[p],                                            (3)
+--
+--    U' = U - a[p]*x[p],                                            (4)
+--
+-- where x[p] is assumed to be fixed at 0 or 1. So (2) can be rewritten
+-- as follows:
+--
+--    L' <=   sum  a[j]*x[j] + a[q]*x[q] <= U',                      (5)
+--          j in J'
+--
+-- from where we have:
+--
+--    L' -  sum  a[j]*x[j] <= a[q]*x[q] <= U' -  sum  a[j]*x[j].     (6)
+--        j in J'                              j in J'
+--
+-- Thus,
+--
+--    min a[q]*x[q] = L' - MAX,                                      (7)
+--
+--    max a[q]*x[q] = U' - MIN,                                      (8)
+--
+-- where
+--
+--    MIN = min  sum  a[j]*x[j],                                     (9)
+--             j in J'
+--
+--    MAX = max  sum  a[j]*x[j].                                    (10)
+--             j in J'
+--
+-- Formulae (7) and (8) allows determining implied lower and upper
+-- bounds of x[q].
+--
+-- Parameters len, val, L and U specify the constraint (1).
+--
+-- Parameters lf_min and lf_max specify implied lower and upper bounds
+-- of the linear form (1). It is assumed that these bounds are computed
+-- with the routines eval_lf_min and eval_lf_max (see above).
+--
+-- Parameter p specifies the probing variable x[p], which is set to 0
+-- (if set is 0) or to 1 (if set is 1).
+--
+-- Parameter q specifies the examined variable x[q].
+--
+-- On exit the routine returns one of the following codes:
+--
+-- 0 - there is no logical relation between x[p] and x[q];
+-- 1 - x[q] can take only on value 0;
+-- 2 - x[q] can take only on value 1. */
+
+static int probing(int len, double val[], double L, double U,
+      double lf_min, double lf_max, int p, int set, int q)
+{     double temp;
+      xassert(1 <= p && p < q && q <= len);
+      /* compute L' (3) */
+      if (L != -DBL_MAX && set) L -= val[p];
+      /* compute U' (4) */
+      if (U != +DBL_MAX && set) U -= val[p];
+      /* compute MIN (9) */
+      if (lf_min != -DBL_MAX)
+      {  if (val[p] < 0.0) lf_min -= val[p];
+         if (val[q] < 0.0) lf_min -= val[q];
+      }
+      /* compute MAX (10) */
+      if (lf_max != +DBL_MAX)
+      {  if (val[p] > 0.0) lf_max -= val[p];
+         if (val[q] > 0.0) lf_max -= val[q];
+      }
+      /* compute implied lower bound of x[q]; see (7), (8) */
+      if (val[q] > 0.0)
+      {  if (L == -DBL_MAX || lf_max == +DBL_MAX)
+            temp = -DBL_MAX;
+         else
+            temp = (L - lf_max) / val[q];
+      }
+      else
+      {  if (U == +DBL_MAX || lf_min == -DBL_MAX)
+            temp = -DBL_MAX;
+         else
+            temp = (U - lf_min) / val[q];
+      }
+      if (temp > 0.001) return 2;
+      /* compute implied upper bound of x[q]; see (7), (8) */
+      if (val[q] > 0.0)
+      {  if (U == +DBL_MAX || lf_min == -DBL_MAX)
+            temp = +DBL_MAX;
+         else
+            temp = (U - lf_min) / val[q];
+      }
+      else
+      {  if (L == -DBL_MAX || lf_max == +DBL_MAX)
+            temp = +DBL_MAX;
+         else
+            temp = (L - lf_max) / val[q];
+      }
+      if (temp < 0.999) return 1;
+      /* there is no logical relation between x[p] and x[q] */
+      return 0;
+}
+
+struct COG
+{     /* conflict graph; it represents logical relations between binary
+         variables and has a vertex for each binary variable and its
+         complement, and an edge between two vertices when at most one
+         of the variables represented by the vertices can equal one in
+         an optimal solution */
+      int n;
+      /* number of variables */
+      int nb;
+      /* number of binary variables represented in the graph (note that
+         not all binary variables can be represented); vertices which
+         correspond to binary variables have numbers 1, ..., nb while
+         vertices which correspond to complements of binary variables
+         have numbers nb+1, ..., nb+nb */
+      int ne;
+      /* number of edges in the graph */
+      int *vert; /* int vert[1+n]; */
+      /* if x[j] is a binary variable represented in the graph, vert[j]
+         is the vertex number corresponding to x[j]; otherwise vert[j]
+         is zero */
+      int *orig; /* int list[1:nb]; */
+      /* if vert[j] = k > 0, then orig[k] = j */
+      unsigned char *a;
+      /* adjacency matrix of the graph having 2*nb rows and columns;
+         only strict lower triangle is stored in dense packed form */
+};
+
+/*----------------------------------------------------------------------
+-- lpx_create_cog - create the conflict graph.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- void *lpx_create_cog(LPX *lp);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_create_cog creates the conflict graph for a given
+-- problem instance.
+--
+-- RETURNS
+--
+-- If the graph has been created, the routine returns a pointer to it.
+-- Otherwise the routine returns NULL. */
+
+#define MAX_NB 4000
+#define MAX_ROW_LEN 500
+
+static void lpx_add_cog_edge(void *_cog, int i, int j);
+
+static void *lpx_create_cog(LPX *lp)
+{     struct COG *cog = NULL;
+      int m, n, nb, i, j, p, q, len, *ind, *vert, *orig;
+      double L, U, lf_min, lf_max, *val;
+      xprintf("Creating the conflict graph...\n");
+      m = lpx_get_num_rows(lp);
+      n = lpx_get_num_cols(lp);
+      /* determine which binary variables should be included in the
+         conflict graph */
+      nb = 0;
+      vert = xcalloc(1+n, sizeof(int));
+      for (j = 1; j <= n; j++) vert[j] = 0;
+      orig = xcalloc(1+n, sizeof(int));
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  L = get_row_lb(lp, i);
+         U = get_row_ub(lp, i);
+         if (L == -DBL_MAX && U == +DBL_MAX) continue;
+         len = lpx_get_mat_row(lp, i, ind, val);
+         if (len > MAX_ROW_LEN) continue;
+         lf_min = eval_lf_min(lp, len, ind, val);
+         lf_max = eval_lf_max(lp, len, ind, val);
+         for (p = 1; p <= len; p++)
+         {  if (!is_binary(lp, ind[p])) continue;
+            for (q = p+1; q <= len; q++)
+            {  if (!is_binary(lp, ind[q])) continue;
+               if (probing(len, val, L, U, lf_min, lf_max, p, 0, q) ||
+                   probing(len, val, L, U, lf_min, lf_max, p, 1, q))
+               {  /* there is a logical relation */
+                  /* include the first variable in the graph */
+                  j = ind[p];
+                  if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
+                  /* incude the second variable in the graph */
+                  j = ind[q];
+                  if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
+               }
+            }
+         }
+      }
+      /* if the graph is either empty or has too many vertices, do not
+         create it */
+      if (nb == 0 || nb > MAX_NB)
+      {  xprintf("The conflict graph is either empty or too big\n");
+         xfree(vert);
+         xfree(orig);
+         goto done;
+      }
+      /* create the conflict graph */
+      cog = xmalloc(sizeof(struct COG));
+      cog->n = n;
+      cog->nb = nb;
+      cog->ne = 0;
+      cog->vert = vert;
+      cog->orig = orig;
+      len = nb + nb; /* number of vertices */
+      len = (len * (len - 1)) / 2; /* number of entries in triangle */
+      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* bytes needed */
+      cog->a = xmalloc(len);
+      memset(cog->a, 0, len);
+      for (j = 1; j <= nb; j++)
+      {  /* add edge between variable and its complement */
+         lpx_add_cog_edge(cog, +orig[j], -orig[j]);
+      }
+      for (i = 1; i <= m; i++)
+      {  L = get_row_lb(lp, i);
+         U = get_row_ub(lp, i);
+         if (L == -DBL_MAX && U == +DBL_MAX) continue;
+         len = lpx_get_mat_row(lp, i, ind, val);
+         if (len > MAX_ROW_LEN) continue;
+         lf_min = eval_lf_min(lp, len, ind, val);
+         lf_max = eval_lf_max(lp, len, ind, val);
+         for (p = 1; p <= len; p++)
+         {  if (!is_binary(lp, ind[p])) continue;
+            for (q = p+1; q <= len; q++)
+            {  if (!is_binary(lp, ind[q])) continue;
+               /* set x[p] to 0 and examine x[q] */
+               switch (probing(len, val, L, U, lf_min, lf_max, p, 0, q))
+               {  case 0:
+                     /* no logical relation */
+                     break;
+                  case 1:
+                     /* x[p] = 0 implies x[q] = 0 */
+                     lpx_add_cog_edge(cog, -ind[p], +ind[q]);
+                     break;
+                  case 2:
+                     /* x[p] = 0 implies x[q] = 1 */
+                     lpx_add_cog_edge(cog, -ind[p], -ind[q]);
+                     break;
+                  default:
+                     xassert(lp != lp);
+               }
+               /* set x[p] to 1 and examine x[q] */
+               switch (probing(len, val, L, U, lf_min, lf_max, p, 1, q))
+               {  case 0:
+                     /* no logical relation */
+                     break;
+                  case 1:
+                     /* x[p] = 1 implies x[q] = 0 */
+                     lpx_add_cog_edge(cog, +ind[p], +ind[q]);
+                     break;
+                  case 2:
+                     /* x[p] = 1 implies x[q] = 1 */
+                     lpx_add_cog_edge(cog, +ind[p], -ind[q]);
+                     break;
+                  default:
+                     xassert(lp != lp);
+               }
+            }
+         }
+      }
+      xprintf("The conflict graph has 2*%d vertices and %d edges\n",
+         cog->nb, cog->ne);
+done: xfree(ind);
+      xfree(val);
+      return cog;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_add_cog_edge - add edge to the conflict graph.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- void lpx_add_cog_edge(void *cog, int i, int j);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_add_cog_edge adds an edge to the conflict graph.
+-- The edge connects x[i] (if i > 0) or its complement (if i < 0) and
+-- x[j] (if j > 0) or its complement (if j < 0), where i and j are
+-- original ordinal numbers of corresponding variables. */
+
+static void lpx_add_cog_edge(void *_cog, int i, int j)
+{     struct COG *cog = _cog;
+      int k;
+      xassert(i != j);
+      /* determine indices of corresponding vertices */
+      if (i > 0)
+      {  xassert(1 <= i && i <= cog->n);
+         i = cog->vert[i];
+         xassert(i != 0);
+      }
+      else
+      {  i = -i;
+         xassert(1 <= i && i <= cog->n);
+         i = cog->vert[i];
+         xassert(i != 0);
+         i += cog->nb;
+      }
+      if (j > 0)
+      {  xassert(1 <= j && j <= cog->n);
+         j = cog->vert[j];
+         xassert(j != 0);
+      }
+      else
+      {  j = -j;
+         xassert(1 <= j && j <= cog->n);
+         j = cog->vert[j];
+         xassert(j != 0);
+         j += cog->nb;
+      }
+      /* only lower triangle is stored, so we need i > j */
+      if (i < j) k = i, i = j, j = k;
+      k = ((i - 1) * (i - 2)) / 2 + (j - 1);
+      cog->a[k / CHAR_BIT] |=
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+      cog->ne++;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- MAXIMUM WEIGHT CLIQUE
+--
+-- Two subroutines sub() and wclique() below are intended to find a
+-- maximum weight clique in a given undirected graph. These subroutines
+-- are slightly modified version of the program WCLIQUE developed by
+-- Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
+-- on ideas from the article "P. R. J. Ostergard, A new algorithm for
+-- the maximum-weight clique problem, submitted for publication", which
+-- in turn is a generalization of the algorithm for unweighted graphs
+-- presented in "P. R. J. Ostergard, A fast algorithm for the maximum
+-- clique problem, submitted for publication".
+--
+-- USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. */
+
+struct dsa
+{     /* dynamic storage area */
+      int n;
+      /* number of vertices */
+      int *wt; /* int wt[0:n-1]; */
+      /* weights */
+      unsigned char *a;
+      /* adjacency matrix (packed lower triangle without main diag.) */
+      int record;
+      /* weight of best clique */
+      int rec_level;
+      /* number of vertices in best clique */
+      int *rec; /* int rec[0:n-1]; */
+      /* best clique so far */
+      int *clique; /* int clique[0:n-1]; */
+      /* table for pruning */
+      int *set; /* int set[0:n-1]; */
+      /* current clique */
+};
+
+#define n         (dsa->n)
+#define wt        (dsa->wt)
+#define a         (dsa->a)
+#define record    (dsa->record)
+#define rec_level (dsa->rec_level)
+#define rec       (dsa->rec)
+#define clique    (dsa->clique)
+#define set       (dsa->set)
+
+#if 0
+static int is_edge(struct dsa *dsa, int i, int j)
+{     /* if there is arc (i,j), the routine returns true; otherwise
+         false; 0 <= i, j < n */
+      int k;
+      xassert(0 <= i && i < n);
+      xassert(0 <= j && j < n);
+      if (i == j) return 0;
+      if (i < j) k = i, i = j, j = k;
+      k = (i * (i - 1)) / 2 + j;
+      return a[k / CHAR_BIT] &
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+}
+#else
+#define is_edge(dsa, i, j) ((i) == (j) ? 0 : \
+      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
+#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
+#define is_edge2(k) (a[(k) / CHAR_BIT] & \
+      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
+#endif
+
+static void sub(struct dsa *dsa, int ct, int table[], int level,
+      int weight, int l_weight)
+{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
+      newtable = xcalloc(n, sizeof(int));
+      if (ct <= 0)
+      {  /* 0 or 1 elements left; include these */
+         if (ct == 0)
+         {  set[level++] = table[0];
+            weight += l_weight;
+         }
+         if (weight > record)
+         {  record = weight;
+            rec_level = level;
+            for (i = 0; i < level; i++) rec[i] = set[i];
+         }
+         goto done;
+      }
+      for (i = ct; i >= 0; i--)
+      {  if ((level == 0) && (i < ct)) goto done;
+         k = table[i];
+         if ((level > 0) && (clique[k] <= (record - weight)))
+            goto done; /* prune */
+         set[level] = k;
+         curr_weight = weight + wt[k];
+         l_weight -= wt[k];
+         if (l_weight <= (record - curr_weight))
+            goto done; /* prune */
+         p1 = newtable;
+         p2 = table;
+         left_weight = 0;
+         while (p2 < table + i)
+         {  j = *p2++;
+            if (is_edge(dsa, j, k))
+            {  *p1++ = j;
+               left_weight += wt[j];
+            }
+         }
+         if (left_weight <= (record - curr_weight)) continue;
+         sub(dsa, p1 - newtable - 1, newtable, level + 1, curr_weight,
+            left_weight);
+      }
+done: xfree(newtable);
+      return;
+}
+
+static int wclique(int _n, int w[], unsigned char _a[], int sol[])
+{     struct dsa _dsa, *dsa = &_dsa;
+      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
+      glp_long timer;
+      n = _n;
+      wt = &w[1];
+      a = _a;
+      record = 0;
+      rec_level = 0;
+      rec = &sol[1];
+      clique = xcalloc(n, sizeof(int));
+      set = xcalloc(n, sizeof(int));
+      used = xcalloc(n, sizeof(int));
+      nwt = xcalloc(n, sizeof(int));
+      pos = xcalloc(n, sizeof(int));
+      /* start timer */
+      timer = xtime();
+      /* order vertices */
+      for (i = 0; i < n; i++)
+      {  nwt[i] = 0;
+         for (j = 0; j < n; j++)
+            if (is_edge(dsa, i, j)) nwt[i] += wt[j];
+      }
+      for (i = 0; i < n; i++)
+         used[i] = 0;
+      for (i = n-1; i >= 0; i--)
+      {  max_wt = -1;
+         max_nwt = -1;
+         for (j = 0; j < n; j++)
+         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
+               && nwt[j] > max_nwt)))
+            {  max_wt = wt[j];
+               max_nwt = nwt[j];
+               p = j;
+            }
+         }
+         pos[i] = p;
+         used[p] = 1;
+         for (j = 0; j < n; j++)
+            if ((!used[j]) && (j != p) && (is_edge(dsa, p, j)))
+               nwt[j] -= wt[p];
+      }
+      /* main routine */
+      wth = 0;
+      for (i = 0; i < n; i++)
+      {  wth += wt[pos[i]];
+         sub(dsa, i, pos, 0, 0, wth);
+         clique[pos[i]] = record;
+#if 0
+         if (utime() >= timer + 5.0)
+#else
+         if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
+#endif
+         {  /* print current record and reset timer */
+            xprintf("level = %d (%d); best = %d\n", i+1, n, record);
+#if 0
+            timer = utime();
+#else
+            timer = xtime();
+#endif
+         }
+      }
+      xfree(clique);
+      xfree(set);
+      xfree(used);
+      xfree(nwt);
+      xfree(pos);
+      /* return the solution found */
+      for (i = 1; i <= rec_level; i++) sol[i]++;
+      return rec_level;
+}
+
+#undef n
+#undef wt
+#undef a
+#undef record
+#undef rec_level
+#undef rec
+#undef clique
+#undef set
+
+/*----------------------------------------------------------------------
+-- lpx_clique_cut - generate cluque cut.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- int lpx_clique_cut(LPX *lp, void *cog, int ind[], double val[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_clique_cut generates a clique cut using the conflict
+-- graph specified by the parameter cog.
+--
+-- If a violated clique cut has been found, it has the following form:
+--
+--    sum{j in J} a[j]*x[j] <= b.
+--
+-- Variable indices j in J are stored in elements ind[1], ..., ind[len]
+-- while corresponding constraint coefficients are stored in elements
+-- val[1], ..., val[len], where len is returned on exit. The right-hand
+-- side b is stored in element val[0].
+--
+-- RETURNS
+--
+-- If the cutting plane has been successfully generated, the routine
+-- returns 1 <= len <= n, which is the number of non-zero coefficients
+-- in the inequality constraint. Otherwise, the routine returns zero. */
+
+static int lpx_clique_cut(LPX *lp, void *_cog, int ind[], double val[])
+{     struct COG *cog = _cog;
+      int n = lpx_get_num_cols(lp);
+      int j, t, v, card, temp, len = 0, *w, *sol;
+      double x, sum, b, *vec;
+      /* allocate working arrays */
+      w = xcalloc(1 + 2 * cog->nb, sizeof(int));
+      sol = xcalloc(1 + 2 * cog->nb, sizeof(int));
+      vec = xcalloc(1+n, sizeof(double));
+      /* assign weights to vertices of the conflict graph */
+      for (t = 1; t <= cog->nb; t++)
+      {  j = cog->orig[t];
+         x = lpx_get_col_prim(lp, j);
+         temp = (int)(100.0 * x + 0.5);
+         if (temp < 0) temp = 0;
+         if (temp > 100) temp = 100;
+         w[t] = temp;
+         w[cog->nb + t] = 100 - temp;
+      }
+      /* find a clique of maximum weight */
+      card = wclique(2 * cog->nb, w, cog->a, sol);
+      /* compute the clique weight for unscaled values */
+      sum = 0.0;
+      for ( t = 1; t <= card; t++)
+      {  v = sol[t];
+         xassert(1 <= v && v <= 2 * cog->nb);
+         if (v <= cog->nb)
+         {  /* vertex v corresponds to binary variable x[j] */
+            j = cog->orig[v];
+            x = lpx_get_col_prim(lp, j);
+            sum += x;
+         }
+         else
+         {  /* vertex v corresponds to the complement of x[j] */
+            j = cog->orig[v - cog->nb];
+            x = lpx_get_col_prim(lp, j);
+            sum += 1.0 - x;
+         }
+      }
+      /* if the sum of binary variables and their complements in the
+         clique greater than 1, the clique cut is violated */
+      if (sum >= 1.01)
+      {  /* construct the inquality */
+         for (j = 1; j <= n; j++) vec[j] = 0;
+         b = 1.0;
+         for (t = 1; t <= card; t++)
+         {  v = sol[t];
+            if (v <= cog->nb)
+            {  /* vertex v corresponds to binary variable x[j] */
+               j = cog->orig[v];
+               xassert(1 <= j && j <= n);
+               vec[j] += 1.0;
+            }
+            else
+            {  /* vertex v corresponds to the complement of x[j] */
+               j = cog->orig[v - cog->nb];
+               xassert(1 <= j && j <= n);
+               vec[j] -= 1.0;
+               b -= 1.0;
+            }
+         }
+         xassert(len == 0);
+         for (j = 1; j <= n; j++)
+         {  if (vec[j] != 0.0)
+            {  len++;
+               ind[len] = j, val[len] = vec[j];
+            }
+         }
+         ind[0] = 0, val[0] = b;
+      }
+      /* free working arrays */
+      xfree(w);
+      xfree(sol);
+      xfree(vec);
+      /* return to the calling program */
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_delete_cog - delete the conflict graph.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- void lpx_delete_cog(void *cog);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_delete_cog deletes the conflict graph, which the
+-- parameter cog points to, freeing all the memory allocated to this
+-- object. */
+
+static void lpx_delete_cog(void *_cog)
+{     struct COG *cog = _cog;
+      xfree(cog->vert);
+      xfree(cog->orig);
+      xfree(cog->a);
+      xfree(cog);
+}
+
+/**********************************************************************/
+
+void *ios_clq_init(glp_tree *tree)
+{     /* initialize clique cut generator */
+      glp_prob *mip = tree->mip;
+      xassert(mip != NULL);
+      return lpx_create_cog(mip);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clq_gen - generate clique cuts
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clq_gen(glp_tree *tree, void *gen);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clq_gen generates clique cuts for the current point
+*  and adds them to the clique pool. */
+
+void ios_clq_gen(glp_tree *tree, void *gen)
+{     int n = lpx_get_num_cols(tree->mip);
+      int len, *ind;
+      double *val;
+      xassert(gen != NULL);
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      len = lpx_clique_cut(tree->mip, gen, ind, val);
+      if (len > 0)
+      {  /* xprintf("len = %d\n", len); */
+         glp_ios_add_row(tree, NULL, GLP_RF_CLQ, 0, len, ind, val,
+            GLP_UP, val[0]);
+      }
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/**********************************************************************/
+
+void ios_clq_term(void *gen)
+{     /* terminate clique cut generator */
+      xassert(gen != NULL);
+      lpx_delete_cog(gen);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios09.c b/optional/glpk/glpios09.c
new file mode 100644
index 0000000..7cf0232
--- /dev/null
+++ b/optional/glpk/glpios09.c
@@ -0,0 +1,665 @@
+/* glpios09.c (branching heuristics) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#pragma clang diagnostic ignored "-Wpointer-sign"
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_choose_var - select variable to branch on
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_choose_var(glp_tree *T, int *next);
+*
+*  The routine ios_choose_var chooses a variable from the candidate
+*  list to branch on. Additionally the routine provides a flag stored
+*  in the location next to suggests which of the child subproblems
+*  should be solved next.
+*
+*  RETURNS
+*
+*  The routine ios_choose_var returns the ordinal number of the column
+*  choosen. */
+
+static int branch_first(glp_tree *T, int *next);
+static int branch_last(glp_tree *T, int *next);
+static int branch_mostf(glp_tree *T, int *next);
+static int branch_drtom(glp_tree *T, int *next);
+
+int ios_choose_var(glp_tree *T, int *next)
+{     int j;
+      if (T->parm->br_tech == GLP_BR_FFV)
+      {  /* branch on first fractional variable */
+         j = branch_first(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_LFV)
+      {  /* branch on last fractional variable */
+         j = branch_last(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_MFV)
+      {  /* branch on most fractional variable */
+         j = branch_mostf(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_DTH)
+      {  /* branch using the heuristic by Dreebeck and Tomlin */
+         j = branch_drtom(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_PCH)
+      {  /* hybrid pseudocost heuristic */
+         j = ios_pcost_branch(T, next);
+      }
+      else
+         xassert(T != T);
+      return j;
+}
+
+/***********************************************************************
+*  branch_first - choose first branching variable
+*
+*  This routine looks up the list of structural variables and chooses
+*  the first one, which is of integer kind and has fractional value in
+*  optimal solution to the current LP relaxation.
+*
+*  This routine also selects the branch to be solved next where integer
+*  infeasibility of the chosen variable is less than in other one. */
+
+static int branch_first(glp_tree *T, int *_next)
+{     int j, next;
+      double beta;
+      /* choose the column to branch on */
+      for (j = 1; j <= T->n; j++)
+         if (T->non_int[j]) break;
+      xassert(1 <= j && j <= T->n);
+      /* select the branch to be solved next */
+      beta = glp_get_col_prim(T->mip, j);
+      if (beta - floor(beta) < ceil(beta) - beta)
+         next = GLP_DN_BRNCH;
+      else
+         next = GLP_UP_BRNCH;
+      *_next = next;
+      return j;
+}
+
+/***********************************************************************
+*  branch_last - choose last branching variable
+*
+*  This routine looks up the list of structural variables and chooses
+*  the last one, which is of integer kind and has fractional value in
+*  optimal solution to the current LP relaxation.
+*
+*  This routine also selects the branch to be solved next where integer
+*  infeasibility of the chosen variable is less than in other one. */
+
+static int branch_last(glp_tree *T, int *_next)
+{     int j, next;
+      double beta;
+      /* choose the column to branch on */
+      for (j = T->n; j >= 1; j--)
+         if (T->non_int[j]) break;
+      xassert(1 <= j && j <= T->n);
+      /* select the branch to be solved next */
+      beta = glp_get_col_prim(T->mip, j);
+      if (beta - floor(beta) < ceil(beta) - beta)
+         next = GLP_DN_BRNCH;
+      else
+         next = GLP_UP_BRNCH;
+      *_next = next;
+      return j;
+}
+
+/***********************************************************************
+*  branch_mostf - choose most fractional branching variable
+*
+*  This routine looks up the list of structural variables and chooses
+*  that one, which is of integer kind and has most fractional value in
+*  optimal solution to the current LP relaxation.
+*
+*  This routine also selects the branch to be solved next where integer
+*  infeasibility of the chosen variable is less than in other one.
+*
+*  (Alexander Martin notices that "...most infeasible is as good as
+*  random...".) */
+
+static int branch_mostf(glp_tree *T, int *_next)
+{     int j, jj, next;
+      double beta, most, temp;
+      /* choose the column to branch on */
+      jj = 0, most = DBL_MAX;
+      for (j = 1; j <= T->n; j++)
+      {  if (T->non_int[j])
+         {  beta = glp_get_col_prim(T->mip, j);
+            temp = floor(beta) + 0.5;
+            if (most > fabs(beta - temp))
+            {  jj = j, most = fabs(beta - temp);
+               if (beta < temp)
+                  next = GLP_DN_BRNCH;
+               else
+                  next = GLP_UP_BRNCH;
+            }
+         }
+      }
+      *_next = next;
+      return jj;
+}
+
+/***********************************************************************
+*  branch_drtom - choose branching var using Driebeck-Tomlin heuristic
+*
+*  This routine chooses a structural variable, which is required to be
+*  integral and has fractional value in optimal solution of the current
+*  LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
+*
+*  The routine also selects the branch to be solved next, again due to
+*  Driebeck and Tomlin.
+*
+*  This routine is based on the heuristic proposed in:
+*
+*  Driebeck N.J. An algorithm for the solution of mixed-integer
+*  programming problems, Management Science, 12: 576-87 (1966);
+*
+*  and improved in:
+*
+*  Tomlin J.A. Branch and bound methods for integer and non-convex
+*  programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
+*  North-Holland, Amsterdam, pp. 437-50 (1970).
+*
+*  Must note that this heuristic is time-expensive, because computing
+*  one-step degradation (see the routine below) requires one BTRAN for
+*  each fractional-valued structural variable. */
+
+static int branch_drtom(glp_tree *T, int *_next)
+{     glp_prob *mip = T->mip;
+      int m = mip->m;
+      int n = mip->n;
+      char *non_int = T->non_int;
+      int j, jj, k, t, next, kase, len, stat, *ind;
+      double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
+         dd_dn, dd_up, degrad, *val;
+      /* basic solution of LP relaxation must be optimal */
+      xassert(glp_get_status(mip) == GLP_OPT);
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      /* nothing has been chosen so far */
+      jj = 0, degrad = -1.0;
+      /* walk through the list of columns (structural variables) */
+      for (j = 1; j <= n; j++)
+      {  /* if j-th column is not marked as fractional, skip it */
+         if (!non_int[j]) continue;
+         /* obtain (fractional) value of j-th column in basic solution
+            of LP relaxation */
+         x = glp_get_col_prim(mip, j);
+         /* since the value of j-th column is fractional, the column is
+            basic; compute corresponding row of the simplex table */
+         len = glp_eval_tab_row(mip, m+j, ind, val);
+         /* the following fragment computes a change in the objective
+            function: delta Z = new Z - old Z, where old Z is the
+            objective value in the current optimal basis, and new Z is
+            the objective value in the adjacent basis, for two cases:
+            1) if new upper bound ub' = floor(x[j]) is introduced for
+               j-th column (down branch);
+            2) if new lower bound lb' = ceil(x[j]) is introduced for
+               j-th column (up branch);
+            since in both cases the solution remaining dual feasible
+            becomes primal infeasible, one implicit simplex iteration
+            is performed to determine the change delta Z;
+            it is obvious that new Z, which is never better than old Z,
+            is a lower (minimization) or upper (maximization) bound of
+            the objective function for down- and up-branches. */
+         for (kase = -1; kase <= +1; kase += 2)
+         {  /* if kase < 0, the new upper bound of x[j] is introduced;
+               in this case x[j] should decrease in order to leave the
+               basis and go to its new upper bound */
+            /* if kase > 0, the new lower bound of x[j] is introduced;
+               in this case x[j] should increase in order to leave the
+               basis and go to its new lower bound */
+            /* apply the dual ratio test in order to determine which
+               auxiliary or structural variable should enter the basis
+               to keep dual feasibility */
+            k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
+            if (k != 0) k = ind[k];
+            /* if no non-basic variable has been chosen, LP relaxation
+               of corresponding branch being primal infeasible and dual
+               unbounded has no primal feasible solution; in this case
+               the change delta Z is formally set to infinity */
+            if (k == 0)
+            {  delta_z =
+                  (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
+               goto skip;
+            }
+            /* row of the simplex table that corresponds to non-basic
+               variable x[k] choosen by the dual ratio test is:
+                  x[j] = ... + alfa * x[k] + ...
+               where alfa is the influence coefficient (an element of
+               the simplex table row) */
+            /* determine the coefficient alfa */
+            for (t = 1; t <= len; t++) if (ind[t] == k) break;
+            xassert(1 <= t && t <= len);
+            alfa = val[t];
+            /* since in the adjacent basis the variable x[j] becomes
+               non-basic, knowing its value in the current basis we can
+               determine its change delta x[j] = new x[j] - old x[j] */
+            delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
+            /* and knowing the coefficient alfa we can determine the
+               corresponding change delta x[k] = new x[k] - old x[k],
+               where old x[k] is a value of x[k] in the current basis,
+               and new x[k] is a value of x[k] in the adjacent basis */
+            delta_k = delta_j / alfa;
+            /* Tomlin noticed that if the variable x[k] is of integer
+               kind, its change cannot be less (eventually) than one in
+               the magnitude */
+            if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
+            {  /* x[k] is structural integer variable */
+               if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
+               {  if (delta_k > 0.0)
+                     delta_k = ceil(delta_k);  /* +3.14 -> +4 */
+                  else
+                     delta_k = floor(delta_k); /* -3.14 -> -4 */
+               }
+            }
+            /* now determine the status and reduced cost of x[k] in the
+               current basis */
+            if (k <= m)
+            {  stat = glp_get_row_stat(mip, k);
+               dk = glp_get_row_dual(mip, k);
+            }
+            else
+            {  stat = glp_get_col_stat(mip, k-m);
+               dk = glp_get_col_dual(mip, k-m);
+            }
+            /* if the current basis is dual degenerate, some reduced
+               costs which are close to zero may have wrong sign due to
+               round-off errors, so correct the sign of d[k] */
+            switch (T->mip->dir)
+            {  case GLP_MIN:
+                  if (stat == GLP_NL && dk < 0.0 ||
+                      stat == GLP_NU && dk > 0.0 ||
+                      stat == GLP_NF) dk = 0.0;
+                  break;
+               case GLP_MAX:
+                  if (stat == GLP_NL && dk > 0.0 ||
+                      stat == GLP_NU && dk < 0.0 ||
+                      stat == GLP_NF) dk = 0.0;
+                  break;
+               default:
+                  xassert(T != T);
+            }
+            /* now knowing the change of x[k] and its reduced cost d[k]
+               we can compute the corresponding change in the objective
+               function delta Z = new Z - old Z = d[k] * delta x[k];
+               note that due to Tomlin's modification new Z can be even
+               worse than in the adjacent basis */
+            delta_z = dk * delta_k;
+skip:       /* new Z is never better than old Z, therefore the change
+               delta Z is always non-negative (in case of minimization)
+               or non-positive (in case of maximization) */
+            switch (T->mip->dir)
+            {  case GLP_MIN: xassert(delta_z >= 0.0); break;
+               case GLP_MAX: xassert(delta_z <= 0.0); break;
+               default: xassert(T != T);
+            }
+            /* save the change in the objective fnction for down- and
+               up-branches, respectively */
+            if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
+         }
+         /* thus, in down-branch no integer feasible solution can be
+            better than Z + dz_dn, and in up-branch no integer feasible
+            solution can be better than Z + dz_up, where Z is value of
+            the objective function in the current basis */
+         /* following the heuristic by Driebeck and Tomlin we choose a
+            column (i.e. structural variable) which provides largest
+            degradation of the objective function in some of branches;
+            besides, we select the branch with smaller degradation to
+            be solved next and keep other branch with larger degradation
+            in the active list hoping to minimize the number of further
+            backtrackings */
+         if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
+         {  jj = j;
+            if (fabs(dz_dn) < fabs(dz_up))
+            {  /* select down branch to be solved next */
+               next = GLP_DN_BRNCH;
+               degrad = fabs(dz_up);
+            }
+            else
+            {  /* select up branch to be solved next */
+               next = GLP_UP_BRNCH;
+               degrad = fabs(dz_dn);
+            }
+            /* save the objective changes for printing */
+            dd_dn = dz_dn, dd_up = dz_up;
+            /* if down- or up-branch has no feasible solution, we does
+               not need to consider other candidates (in principle, the
+               corresponding branch could be pruned right now) */
+            if (degrad == DBL_MAX) break;
+         }
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      /* something must be chosen */
+      xassert(1 <= jj && jj <= n);
+#if 1 /* 02/XI-2009 */
+      if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
+      {  jj = branch_mostf(T, &next);
+         goto done;
+      }
+#endif
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  xprintf("branch_drtom: column %d chosen to branch on\n", jj);
+         if (fabs(dd_dn) == DBL_MAX)
+            xprintf("branch_drtom: down-branch is infeasible\n");
+         else
+            xprintf("branch_drtom: down-branch bound is %.9e\n",
+               lpx_get_obj_val(mip) + dd_dn);
+         if (fabs(dd_up) == DBL_MAX)
+            xprintf("branch_drtom: up-branch   is infeasible\n");
+         else
+            xprintf("branch_drtom: up-branch   bound is %.9e\n",
+               lpx_get_obj_val(mip) + dd_up);
+      }
+done: *_next = next;
+      return jj;
+}
+
+/**********************************************************************/
+
+struct csa
+{     /* common storage area */
+      int *dn_cnt; /* int dn_cnt[1+n]; */
+      /* dn_cnt[j] is the number of subproblems, whose LP relaxations
+         have been solved and which are down-branches for variable x[j];
+         dn_cnt[j] = 0 means the down pseudocost is uninitialized */
+      double *dn_sum; /* double dn_sum[1+n]; */
+      /* dn_sum[j] is the sum of per unit degradations of the objective
+         over all dn_cnt[j] subproblems */
+      int *up_cnt; /* int up_cnt[1+n]; */
+      /* up_cnt[j] is the number of subproblems, whose LP relaxations
+         have been solved and which are up-branches for variable x[j];
+         up_cnt[j] = 0 means the up pseudocost is uninitialized */
+      double *up_sum; /* double up_sum[1+n]; */
+      /* up_sum[j] is the sum of per unit degradations of the objective
+         over all up_cnt[j] subproblems */
+};
+
+void *ios_pcost_init(glp_tree *tree)
+{     /* initialize working data used on pseudocost branching */
+      struct csa *csa;
+      int n = tree->n, j;
+      csa = xmalloc(sizeof(struct csa));
+      csa->dn_cnt = xcalloc(1+n, sizeof(int));
+      csa->dn_sum = xcalloc(1+n, sizeof(double));
+      csa->up_cnt = xcalloc(1+n, sizeof(int));
+      csa->up_sum = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  csa->dn_cnt[j] = csa->up_cnt[j] = 0;
+         csa->dn_sum[j] = csa->up_sum[j] = 0.0;
+      }
+      return csa;
+}
+
+static double eval_degrad(glp_prob *P, int j, double bnd)
+{     /* compute degradation of the objective on fixing x[j] at given
+         value with a limited number of dual simplex iterations */
+      /* this routine fixes column x[j] at specified value bnd,
+         solves resulting LP, and returns a lower bound to degradation
+         of the objective, degrad >= 0 */
+      glp_prob *lp;
+      glp_smcp parm;
+      int ret;
+      double degrad;
+      /* the current basis must be optimal */
+      xassert(glp_get_status(P) == GLP_OPT);
+      /* create a copy of P */
+      lp = glp_create_prob();
+      glp_copy_prob(lp, P, 0);
+      /* fix column x[j] at specified value */
+      glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
+      /* try to solve resulting LP */
+      glp_init_smcp(&parm);
+      parm.msg_lev = GLP_MSG_OFF;
+      parm.meth = GLP_DUAL;
+      parm.it_lim = 30;
+      parm.out_dly = 1000;
+      parm.meth = GLP_DUAL;
+      ret = glp_simplex(lp, &parm);
+      if (ret == 0 || ret == GLP_EITLIM)
+      {  if (glp_get_prim_stat(lp) == GLP_NOFEAS)
+         {  /* resulting LP has no primal feasible solution */
+            degrad = DBL_MAX;
+         }
+         else if (glp_get_dual_stat(lp) == GLP_FEAS)
+         {  /* resulting basis is optimal or at least dual feasible,
+               so we have the correct lower bound to degradation */
+            if (P->dir == GLP_MIN)
+               degrad = lp->obj_val - P->obj_val;
+            else if (P->dir == GLP_MAX)
+               degrad = P->obj_val - lp->obj_val;
+            else
+               xassert(P != P);
+            /* degradation cannot be negative by definition */
+            /* note that the lower bound to degradation may be close
+               to zero even if its exact value is zero due to round-off
+               errors on computing the objective value */
+            if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
+               degrad = 0.0;
+         }
+         else
+         {  /* the final basis reported by the simplex solver is dual
+               infeasible, so we cannot determine a non-trivial lower
+               bound to degradation */
+            degrad = 0.0;
+         }
+      }
+      else
+      {  /* the simplex solver failed */
+         degrad = 0.0;
+      }
+      /* delete the copy of P */
+      glp_delete_prob(lp);
+      return degrad;
+}
+
+void ios_pcost_update(glp_tree *tree)
+{     /* update history information for pseudocost branching */
+      /* this routine is called every time when LP relaxation of the
+         current subproblem has been solved to optimality with all lazy
+         and cutting plane constraints included */
+      int j;
+      double dx, dz, psi;
+      struct csa *csa = tree->pcost;
+      xassert(csa != NULL);
+      xassert(tree->curr != NULL);
+      /* if the current subproblem is the root, skip updating */
+      if (tree->curr->up == NULL) goto skip;
+      /* determine branching variable x[j], which was used in the
+         parent subproblem to create the current subproblem */
+      j = tree->curr->up->br_var;
+      xassert(1 <= j && j <= tree->n);
+      /* determine the change dx[j] = new x[j] - old x[j],
+         where new x[j] is a value of x[j] in optimal solution to LP
+         relaxation of the current subproblem, old x[j] is a value of
+         x[j] in optimal solution to LP relaxation of the parent
+         subproblem */
+      dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
+      xassert(dx != 0.0);
+      /* determine corresponding change dz = new dz - old dz in the
+         objective function value */
+      dz = tree->mip->obj_val - tree->curr->up->lp_obj;
+      /* determine per unit degradation of the objective function */
+      psi = fabs(dz / dx);
+      /* update history information */
+      if (dx < 0.0)
+      {  /* the current subproblem is down-branch */
+         csa->dn_cnt[j]++;
+         csa->dn_sum[j] += psi;
+      }
+      else /* dx > 0.0 */
+      {  /* the current subproblem is up-branch */
+         csa->up_cnt[j]++;
+         csa->up_sum[j] += psi;
+      }
+skip: return;
+}
+
+void ios_pcost_free(glp_tree *tree)
+{     /* free working area used on pseudocost branching */
+      struct csa *csa = tree->pcost;
+      xassert(csa != NULL);
+      xfree(csa->dn_cnt);
+      xfree(csa->dn_sum);
+      xfree(csa->up_cnt);
+      xfree(csa->up_sum);
+      xfree(csa);
+      tree->pcost = NULL;
+      return;
+}
+
+static double eval_psi(glp_tree *T, int j, int brnch)
+{     /* compute estimation of pseudocost of variable x[j] for down-
+         or up-branch */
+      struct csa *csa = T->pcost;
+      double beta, degrad, psi;
+      xassert(csa != NULL);
+      xassert(1 <= j && j <= T->n);
+      if (brnch == GLP_DN_BRNCH)
+      {  /* down-branch */
+         if (csa->dn_cnt[j] == 0)
+         {  /* initialize down pseudocost */
+            beta = T->mip->col[j]->prim;
+            degrad = eval_degrad(T->mip, j, floor(beta));
+            if (degrad == DBL_MAX)
+            {  psi = DBL_MAX;
+               goto done;
+            }
+            csa->dn_cnt[j] = 1;
+            csa->dn_sum[j] = degrad / (beta - floor(beta));
+         }
+         psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
+      }
+      else if (brnch == GLP_UP_BRNCH)
+      {  /* up-branch */
+         if (csa->up_cnt[j] == 0)
+         {  /* initialize up pseudocost */
+            beta = T->mip->col[j]->prim;
+            degrad = eval_degrad(T->mip, j, ceil(beta));
+            if (degrad == DBL_MAX)
+            {  psi = DBL_MAX;
+               goto done;
+            }
+            csa->up_cnt[j] = 1;
+            csa->up_sum[j] = degrad / (ceil(beta) - beta);
+         }
+         psi = csa->up_sum[j] / (double)csa->up_cnt[j];
+      }
+      else
+         xassert(brnch != brnch);
+done: return psi;
+}
+
+static void progress(glp_tree *T)
+{     /* display progress of pseudocost initialization */
+      struct csa *csa = T->pcost;
+      int j, nv = 0, ni = 0;
+      for (j = 1; j <= T->n; j++)
+      {  if (glp_ios_can_branch(T, j))
+         {  nv++;
+            if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
+         }
+      }
+      xprintf("Pseudocosts initialized for %d of %d variables\n",
+         ni, nv);
+      return;
+}
+
+int ios_pcost_branch(glp_tree *T, int *_next)
+{     /* choose branching variable with pseudocost branching */
+      glp_long t = xtime();
+      int j, jjj, sel;
+      double beta, psi, d1, d2, d, dmax;
+      /* initialize the working arrays */
+      if (T->pcost == NULL)
+         T->pcost = ios_pcost_init(T);
+      /* nothing has been chosen so far */
+      jjj = 0, dmax = -1.0;
+      /* go through the list of branching candidates */
+      for (j = 1; j <= T->n; j++)
+      {  if (!glp_ios_can_branch(T, j)) continue;
+         /* determine primal value of x[j] in optimal solution to LP
+            relaxation of the current subproblem */
+         beta = T->mip->col[j]->prim;
+         /* estimate pseudocost of x[j] for down-branch */
+         psi = eval_psi(T, j, GLP_DN_BRNCH);
+         if (psi == DBL_MAX)
+         {  /* down-branch has no primal feasible solution */
+            jjj = j, sel = GLP_DN_BRNCH;
+            goto done;
+         }
+         /* estimate degradation of the objective for down-branch */
+         d1 = psi * (beta - floor(beta));
+         /* estimate pseudocost of x[j] for up-branch */
+         psi = eval_psi(T, j, GLP_UP_BRNCH);
+         if (psi == DBL_MAX)
+         {  /* up-branch has no primal feasible solution */
+            jjj = j, sel = GLP_UP_BRNCH;
+            goto done;
+         }
+         /* estimate degradation of the objective for up-branch */
+         d2 = psi * (ceil(beta) - beta);
+         /* determine d = max(d1, d2) */
+         d = (d1 > d2 ? d1 : d2);
+         /* choose x[j] which provides maximal estimated degradation of
+            the objective either in down- or up-branch */
+         if (dmax < d)
+         {  dmax = d;
+            jjj = j;
+            /* continue the search from a subproblem, where degradation
+               is less than in other one */
+            sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
+         }
+         /* display progress of pseudocost initialization */
+         if (T->parm->msg_lev >= GLP_ON)
+         {  if (xdifftime(xtime(), t) >= 10.0)
+            {  progress(T);
+               t = xtime();
+            }
+         }
+      }
+      if (dmax == 0.0)
+      {  /* no degradation is indicated; choose a variable having most
+            fractional value */
+         jjj = branch_mostf(T, &sel);
+      }
+done: *_next = sel;
+      return jjj;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios10.c b/optional/glpk/glpios10.c
new file mode 100644
index 0000000..2b2514a
--- /dev/null
+++ b/optional/glpk/glpios10.c
@@ -0,0 +1,353 @@
+/* glpios10.c (feasibility pump heuristic) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glpios.h"
+#include "glprng.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_feas_pump - feasibility pump heuristic
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_feas_pump(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_feas_pump is a simple implementation of the Feasi-
+*  bility Pump heuristic.
+*
+*  REFERENCES
+*
+*  M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math.
+*  Program., Ser. A 104, pp. 91-104 (2005). */
+
+struct VAR
+{     /* binary variable */
+      int j;
+      /* ordinal number */
+      int x;
+      /* value in the rounded solution (0 or 1) */
+      double d;
+      /* sorting key */
+};
+
+static int fcmp(const void *x, const void *y)
+{     /* comparison routine */
+      const struct VAR *vx = x, *vy = y;
+      if (vx->d > vy->d)
+         return -1;
+      else if (vx->d < vy->d)
+         return +1;
+      else
+         return 0;
+}
+
+void ios_feas_pump(glp_tree *T)
+{     glp_prob *P = T->mip;
+      int n = P->n;
+      glp_prob *lp = NULL;
+      struct VAR *var = NULL;
+      RNG *rand = NULL;
+      GLPCOL *col;
+      glp_smcp parm;
+      int j, k, new_x, nfail, npass, nv, ret, stalling;
+      double dist, tol;
+      xassert(glp_get_status(P) == GLP_OPT);
+      /* this heuristic is applied only once on the root level */
+      if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done;
+      /* determine number of binary variables */
+      nv = 0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         /* if x[j] is continuous, skip it */
+         if (col->kind == GLP_CV) continue;
+         /* if x[j] is fixed, skip it */
+         if (col->type == GLP_FX) continue;
+         /* x[j] is non-fixed integer */
+         xassert(col->kind == GLP_IV);
+         if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
+         {  /* x[j] is binary */
+            nv++;
+         }
+         else
+         {  /* x[j] is general integer */
+            if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("FPUMP heuristic cannot be applied due to genera"
+                  "l integer variables\n");
+            goto done;
+         }
+      }
+      /* there must be at least one binary variable */
+      if (nv == 0) goto done;
+      if (T->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Applying FPUMP heuristic...\n");
+      /* build the list of binary variables */
+      var = xcalloc(1+nv, sizeof(struct VAR));
+      k = 0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         if (col->kind == GLP_IV && col->type == GLP_DB)
+            var[++k].j = j;
+      }
+      xassert(k == nv);
+      /* create working problem object */
+      lp = glp_create_prob();
+more: /* copy the original problem object to keep it intact */
+      glp_copy_prob(lp, P, GLP_OFF);
+      /* we are interested to find an integer feasible solution, which
+         is better than the best known one */
+      if (P->mip_stat == GLP_FEAS)
+      {  int *ind;
+         double *val, bnd;
+         /* add a row and make it identical to the objective row */
+         glp_add_rows(lp, 1);
+         ind = xcalloc(1+n, sizeof(int));
+         val = xcalloc(1+n, sizeof(double));
+         for (j = 1; j <= n; j++)
+         {  ind[j] = j;
+            val[j] = P->col[j]->coef;
+         }
+         glp_set_mat_row(lp, lp->m, n, ind, val);
+         xfree(ind);
+         xfree(val);
+         /* introduce upper (minimization) or lower (maximization)
+            bound to the original objective function; note that this
+            additional constraint is not violated at the optimal point
+            to LP relaxation */
+#if 0 /* modified by xypron <xypron.glpk at gmx.de> */
+         if (P->dir == GLP_MIN)
+         {  bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj));
+            if (bnd < P->obj_val) bnd = P->obj_val;
+            glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
+         }
+         else if (P->dir == GLP_MAX)
+         {  bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj));
+            if (bnd > P->obj_val) bnd = P->obj_val;
+            glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
+         }
+         else
+            xassert(P != P);
+#else
+         bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj;
+         /* xprintf("bnd = %f\n", bnd); */
+         if (P->dir == GLP_MIN)
+            glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
+         else if (P->dir == GLP_MAX)
+            glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
+         else
+            xassert(P != P);
+#endif
+      }
+      /* reset pass count */
+      npass = 0;
+      /* invalidate the rounded point */
+      for (k = 1; k <= nv; k++)
+         var[k].x = -1;
+pass: /* next pass starts here */
+      npass++;
+      if (T->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Pass %d\n", npass);
+      /* initialize minimal distance between the basic point and the
+         rounded one obtained during this pass */
+      dist = DBL_MAX;
+      /* reset failure count (the number of succeeded iterations failed
+         to improve the distance) */
+      nfail = 0;
+      /* if it is not the first pass, perturb the last rounded point
+         rather than construct it from the basic solution */
+      if (npass > 1)
+      {  double rho, temp;
+         if (rand == NULL)
+            rand = rng_create_rand();
+         for (k = 1; k <= nv; k++)
+         {  j = var[k].j;
+            col = lp->col[j];
+            rho = rng_uniform(rand, -0.3, 0.7);
+            if (rho < 0.0) rho = 0.0;
+            temp = fabs((double)var[k].x - col->prim);
+            if (temp + rho > 0.5) var[k].x = 1 - var[k].x;
+         }
+         goto skip;
+      }
+loop: /* innermost loop begins here */
+      /* round basic solution (which is assumed primal feasible) */
+      stalling = 1;
+      for (k = 1; k <= nv; k++)
+      {  col = lp->col[var[k].j];
+         if (col->prim < 0.5)
+         {  /* rounded value is 0 */
+            new_x = 0;
+         }
+         else
+         {  /* rounded value is 1 */
+            new_x = 1;
+         }
+         if (var[k].x != new_x)
+         {  stalling = 0;
+            var[k].x = new_x;
+         }
+      }
+      /* if the rounded point has not changed (stalling), choose and
+         flip some its entries heuristically */
+      if (stalling)
+      {  /* compute d[j] = |x[j] - round(x[j])| */
+         for (k = 1; k <= nv; k++)
+         {  col = lp->col[var[k].j];
+            var[k].d = fabs(col->prim - (double)var[k].x);
+         }
+         /* sort the list of binary variables by descending d[j] */
+         qsort(&var[1], nv, sizeof(struct VAR), fcmp);
+         /* choose and flip some rounded components */
+         for (k = 1; k <= nv; k++)
+         {  if (k >= 5 && var[k].d < 0.35 || k >= 10) break;
+            var[k].x = 1 - var[k].x;
+         }
+      }
+skip: /* check if the time limit has been exhausted */
+      if (T->parm->tm_lim < INT_MAX &&
+         (double)(T->parm->tm_lim - 1) <=
+         1000.0 * xdifftime(xtime(), T->tm_beg)) goto done;
+      /* build the objective, which is the distance between the current
+         (basic) point and the rounded one */
+      lp->dir = GLP_MIN;
+      lp->c0 = 0.0;
+      for (j = 1; j <= n; j++)
+         lp->col[j]->coef = 0.0;
+      for (k = 1; k <= nv; k++)
+      {  j = var[k].j;
+         if (var[k].x == 0)
+            lp->col[j]->coef = +1.0;
+         else
+         {  lp->col[j]->coef = -1.0;
+            lp->c0 += 1.0;
+         }
+      }
+      /* minimize the distance with the simplex method */
+      glp_init_smcp(&parm);
+      if (T->parm->msg_lev <= GLP_MSG_ERR)
+         parm.msg_lev = T->parm->msg_lev;
+      else if (T->parm->msg_lev <= GLP_MSG_ALL)
+      {  parm.msg_lev = GLP_MSG_ON;
+         parm.out_dly = 10000;
+      }
+      ret = glp_simplex(lp, &parm);
+      if (ret != 0)
+      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("Warning: glp_simplex returned %d\n", ret);
+         goto done;
+      }
+      ret = glp_get_status(lp);
+      if (ret != GLP_OPT)
+      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("Warning: glp_get_status returned %d\n", ret);
+         goto done;
+      }
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("delta = %g\n", lp->obj_val);
+      /* check if the basic solution is integer feasible; note that it
+         may be so even if the minimial distance is positive */
+      tol = 0.3 * T->parm->tol_int;
+      for (k = 1; k <= nv; k++)
+      {  col = lp->col[var[k].j];
+         if (tol < col->prim && col->prim < 1.0 - tol) break;
+      }
+      if (k > nv)
+      {  /* okay; the basic solution seems to be integer feasible */
+         double *x = xcalloc(1+n, sizeof(double));
+         for (j = 1; j <= n; j++)
+         {  x[j] = lp->col[j]->prim;
+            if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5);
+         }
+#if 1 /* modified by xypron <xypron.glpk at gmx.de> */
+         /* reset direction and right-hand side of objective */
+         lp->c0  = P->c0;
+         lp->dir = P->dir;
+         /* fix integer variables */
+         for (k = 1; k <= nv; k++)
+         {  lp->col[var[k].j]->lb   = x[var[k].j];
+            lp->col[var[k].j]->ub   = x[var[k].j];
+            lp->col[var[k].j]->type = GLP_FX;
+         }
+         /* copy original objective function */
+         for (j = 1; j <= n; j++)
+            lp->col[j]->coef = P->col[j]->coef;
+         /* solve original LP and copy result */
+         ret = glp_simplex(lp, &parm);
+         if (ret != 0)
+         {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: glp_simplex returned %d\n", ret);
+            goto done;
+         }
+         ret = glp_get_status(lp);
+         if (ret != GLP_OPT)
+         {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: glp_get_status returned %d\n", ret);
+            goto done;
+         }
+         for (j = 1; j <= n; j++)
+            if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim;
+#endif
+         ret = glp_ios_heur_sol(T, x);
+         xfree(x);
+         if (ret == 0)
+         {  /* the integer solution is accepted */
+            if (ios_is_hopeful(T, T->curr->bound))
+            {  /* it is reasonable to apply the heuristic once again */
+               goto more;
+            }
+            else
+            {  /* the best known integer feasible solution just found
+                  is close to optimal solution to LP relaxation */
+               goto done;
+            }
+         }
+      }
+      /* the basic solution is fractional */
+      if (dist == DBL_MAX ||
+          lp->obj_val <= dist - 1e-6 * (1.0 + dist))
+      {  /* the distance is reducing */
+         nfail = 0, dist = lp->obj_val;
+      }
+      else
+      {  /* improving the distance failed */
+         nfail++;
+      }
+      if (nfail < 3) goto loop;
+      if (npass < 5) goto pass;
+done: /* delete working objects */
+      if (lp != NULL) glp_delete_prob(lp);
+      if (var != NULL) xfree(var);
+      if (rand != NULL) rng_delete_rand(rand);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios11.c b/optional/glpk/glpios11.c
new file mode 100644
index 0000000..2a77b4a
--- /dev/null
+++ b/optional/glpk/glpios11.c
@@ -0,0 +1,284 @@
+/* glpios11.c (process cuts stored in the local cut pool) */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_process_cuts - process cuts stored in the local cut pool
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_process_cuts(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_process_cuts analyzes each cut currently stored in
+*  the local cut pool, which must be non-empty, and either adds the cut
+*  to the current subproblem or just discards it. All cuts are assumed
+*  to be locally valid. On exit the local cut pool remains unchanged.
+*
+*  REFERENCES
+*
+*  1. E.Balas, S.Ceria, G.Cornuejols, "Mixed 0-1 Programming by
+*     Lift-and-Project in a Branch-and-Cut Framework", Management Sc.,
+*     42 (1996) 1229-1246.
+*
+*  2. G.Andreello, A.Caprara, and M.Fischetti, "Embedding Cuts in
+*     a Branch&Cut Framework: a Computational Study with {0,1/2}-Cuts",
+*     Preliminary Draft, October 28, 2003, pp.6-8. */
+
+struct info
+{     /* estimated cut efficiency */
+      IOSCUT *cut;
+      /* pointer to cut in the cut pool */
+      char flag;
+      /* if this flag is set, the cut is included into the current
+         subproblem */
+      double eff;
+      /* cut efficacy (normalized residual) */
+      double deg;
+      /* lower bound to objective degradation */
+};
+
+static int fcmp(const void *arg1, const void *arg2)
+{     const struct info *info1 = arg1, *info2 = arg2;
+      if (info1->deg == 0.0 && info2->deg == 0.0)
+      {  if (info1->eff > info2->eff) return -1;
+         if (info1->eff < info2->eff) return +1;
+      }
+      else
+      {  if (info1->deg > info2->deg) return -1;
+         if (info1->deg < info2->deg) return +1;
+      }
+      return 0;
+}
+
+static double parallel(IOSCUT *a, IOSCUT *b, double work[]);
+
+void ios_process_cuts(glp_tree *T)
+{     IOSPOOL *pool;
+      IOSCUT *cut;
+      IOSAIJ *aij;
+      struct info *info;
+      int k, kk, max_cuts, len, ret, *ind;
+      double *val, *work;
+      /* the current subproblem must exist */
+      xassert(T->curr != NULL);
+      /* the pool must exist and be non-empty */
+      pool = T->local;
+      xassert(pool != NULL);
+      xassert(pool->size > 0);
+      /* allocate working arrays */
+      info = xcalloc(1+pool->size, sizeof(struct info));
+      ind = xcalloc(1+T->n, sizeof(int));
+      val = xcalloc(1+T->n, sizeof(double));
+      work = xcalloc(1+T->n, sizeof(double));
+      for (k = 1; k <= T->n; k++) work[k] = 0.0;
+      /* build the list of cuts stored in the cut pool */
+      for (k = 0, cut = pool->head; cut != NULL; cut = cut->next)
+         k++, info[k].cut = cut, info[k].flag = 0;
+      xassert(k == pool->size);
+      /* estimate efficiency of all cuts in the cut pool */
+      for (k = 1; k <= pool->size; k++)
+      {  double temp, dy, dz;
+         cut = info[k].cut;
+         /* build the vector of cut coefficients and compute its
+            Euclidean norm */
+         len = 0; temp = 0.0;
+         for (aij = cut->ptr; aij != NULL; aij = aij->next)
+         {  xassert(1 <= aij->j && aij->j <= T->n);
+            len++, ind[len] = aij->j, val[len] = aij->val;
+            temp += aij->val * aij->val;
+         }
+         if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+         /* transform the cut to express it only through non-basic
+            (auxiliary and structural) variables */
+         len = glp_transform_row(T->mip, len, ind, val);
+         /* determine change in the cut value and in the objective
+            value for the adjacent basis by simulating one step of the
+            dual simplex */
+         ret = _glp_analyze_row(T->mip, len, ind, val, cut->type,
+            cut->rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz);
+         /* determine normalized residual and lower bound to objective
+            degradation */
+         if (ret == 0)
+         {  info[k].eff = fabs(dy) / sqrt(temp);
+            /* if some reduced costs violates (slightly) their zero
+               bounds (i.e. have wrong signs) due to round-off errors,
+               dz also may have wrong sign being close to zero */
+            if (T->mip->dir == GLP_MIN)
+            {  if (dz < 0.0) dz = 0.0;
+               info[k].deg = + dz;
+            }
+            else /* GLP_MAX */
+            {  if (dz > 0.0) dz = 0.0;
+               info[k].deg = - dz;
+            }
+         }
+         else if (ret == 1)
+         {  /* the constraint is not violated at the current point */
+            info[k].eff = info[k].deg = 0.0;
+         }
+         else if (ret == 2)
+         {  /* no dual feasible adjacent basis exists */
+            info[k].eff = 1.0;
+            info[k].deg = DBL_MAX;
+         }
+         else
+            xassert(ret != ret);
+         /* if the degradation is too small, just ignore it */
+         if (info[k].deg < 0.01) info[k].deg = 0.0;
+      }
+      /* sort the list of cuts by decreasing objective degradation and
+         then by decreasing efficacy */
+      qsort(&info[1], pool->size, sizeof(struct info), fcmp);
+      /* only first (most efficient) max_cuts in the list are qualified
+         as candidates to be added to the current subproblem */
+      max_cuts = (T->curr->level == 0 ? 90 : 10);
+      if (max_cuts > pool->size) max_cuts = pool->size;
+      /* add cuts to the current subproblem */
+#if 0
+      xprintf("*** adding cuts ***\n");
+#endif
+      for (k = 1; k <= max_cuts; k++)
+      {  int i, len;
+         /* if this cut seems to be inefficient, skip it */
+         if (info[k].deg < 0.01 && info[k].eff < 0.01) continue;
+         /* if the angle between this cut and every other cut included
+            in the current subproblem is small, skip this cut */
+         for (kk = 1; kk < k; kk++)
+         {  if (info[kk].flag)
+            {  if (parallel(info[k].cut, info[kk].cut, work) > 0.90)
+                  break;
+            }
+         }
+         if (kk < k) continue;
+         /* add this cut to the current subproblem */
+#if 0
+         xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg);
+#endif
+         cut = info[k].cut, info[k].flag = 1;
+         i = glp_add_rows(T->mip, 1);
+         if (cut->name != NULL)
+            glp_set_row_name(T->mip, i, cut->name);
+         xassert(T->mip->row[i]->origin == GLP_RF_CUT);
+         T->mip->row[i]->klass = cut->klass;
+         len = 0;
+         for (aij = cut->ptr; aij != NULL; aij = aij->next)
+            len++, ind[len] = aij->j, val[len] = aij->val;
+         glp_set_mat_row(T->mip, i, len, ind, val);
+         xassert(cut->type == GLP_LO || cut->type == GLP_UP);
+         glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs);
+      }
+      /* free working arrays */
+      xfree(info);
+      xfree(ind);
+      xfree(val);
+      xfree(work);
+      return;
+}
+
+#if 0
+/***********************************************************************
+*  Given a cut a * x >= b (<= b) the routine efficacy computes the cut
+*  efficacy as follows:
+*
+*     eff = d * (a * x~ - b) / ||a||,
+*
+*  where d is -1 (in case of '>= b') or +1 (in case of '<= b'), x~ is
+*  the vector of values of structural variables in optimal solution to
+*  LP relaxation of the current subproblem, ||a|| is the Euclidean norm
+*  of the vector of cut coefficients.
+*
+*  If the cut is violated at point x~, the efficacy eff is positive,
+*  and its value is the Euclidean distance between x~ and the cut plane
+*  a * x = b in the space of structural variables.
+*
+*  Following geometrical intuition, it is quite natural to consider
+*  this distance as a first-order measure of the expected efficacy of
+*  the cut: the larger the distance the better the cut [1]. */
+
+static double efficacy(glp_tree *T, IOSCUT *cut)
+{     glp_prob *mip = T->mip;
+      IOSAIJ *aij;
+      double s = 0.0, t = 0.0, temp;
+      for (aij = cut->ptr; aij != NULL; aij = aij->next)
+      {  xassert(1 <= aij->j && aij->j <= mip->n);
+         s += aij->val * mip->col[aij->j]->prim;
+         t += aij->val * aij->val;
+      }
+      temp = sqrt(t);
+      if (temp < DBL_EPSILON) temp = DBL_EPSILON;
+      if (cut->type == GLP_LO)
+         temp = (s >= cut->rhs ? 0.0 : (cut->rhs - s) / temp);
+      else if (cut->type == GLP_UP)
+         temp = (s <= cut->rhs ? 0.0 : (s - cut->rhs) / temp);
+      else
+         xassert(cut != cut);
+      return temp;
+}
+#endif
+
+/***********************************************************************
+*  Given two cuts a1 * x >= b1 (<= b1) and a2 * x >= b2 (<= b2) the
+*  routine parallel computes the cosine of angle between the cut planes
+*  a1 * x = b1 and a2 * x = b2 (which is the acute angle between two
+*  normals to these planes) in the space of structural variables as
+*  follows:
+*
+*     cos phi = (a1' * a2) / (||a1|| * ||a2||),
+*
+*  where (a1' * a2) is a dot product of vectors of cut coefficients,
+*  ||a1|| and ||a2|| are Euclidean norms of vectors a1 and a2.
+*
+*  Note that requirement cos phi = 0 forces the cuts to be orthogonal,
+*  i.e. with disjoint support, while requirement cos phi <= 0.999 means
+*  only avoiding duplicate (parallel) cuts [1]. */
+
+static double parallel(IOSCUT *a, IOSCUT *b, double work[])
+{     IOSAIJ *aij;
+      double s = 0.0, sa = 0.0, sb = 0.0, temp;
+      for (aij = a->ptr; aij != NULL; aij = aij->next)
+      {  work[aij->j] = aij->val;
+         sa += aij->val * aij->val;
+      }
+      for (aij = b->ptr; aij != NULL; aij = aij->next)
+      {  s += work[aij->j] * aij->val;
+         sb += aij->val * aij->val;
+      }
+      for (aij = a->ptr; aij != NULL; aij = aij->next)
+         work[aij->j] = 0.0;
+      temp = sqrt(sa) * sqrt(sb);
+      if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+      return s / temp;
+}
+
+/* eof */
diff --git a/optional/glpk/glpios12.c b/optional/glpk/glpios12.c
new file mode 100644
index 0000000..128b843
--- /dev/null
+++ b/optional/glpk/glpios12.c
@@ -0,0 +1,180 @@
+/* glpios12.c (node selection heuristics) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#endif
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_choose_node - select subproblem to continue the search
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_choose_node(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_choose_node selects a subproblem from the active
+*  list to continue the search. The choice depends on the backtracking
+*  technique option.
+*
+*  RETURNS
+*
+*  The routine ios_choose_node return the reference number of the
+*  subproblem selected. */
+
+static int most_feas(glp_tree *T);
+static int best_proj(glp_tree *T);
+static int best_node(glp_tree *T);
+
+int ios_choose_node(glp_tree *T)
+{     int p;
+      if (T->parm->bt_tech == GLP_BT_DFS)
+      {  /* depth first search */
+         xassert(T->tail != NULL);
+         p = T->tail->p;
+      }
+      else if (T->parm->bt_tech == GLP_BT_BFS)
+      {  /* breadth first search */
+         xassert(T->head != NULL);
+         p = T->head->p;
+      }
+      else if (T->parm->bt_tech == GLP_BT_BLB)
+      {  /* select node with best local bound */
+         p = best_node(T);
+      }
+      else if (T->parm->bt_tech == GLP_BT_BPH)
+      {  if (T->mip->mip_stat == GLP_UNDEF)
+         {  /* "most integer feasible" subproblem */
+            p = most_feas(T);
+         }
+         else
+         {  /* best projection heuristic */
+            p = best_proj(T);
+         }
+      }
+      else
+         xassert(T != T);
+      return p;
+}
+
+static int most_feas(glp_tree *T)
+{     /* select subproblem whose parent has minimal sum of integer
+         infeasibilities */
+      IOSNPD *node;
+      int p;
+      double best;
+      p = 0, best = DBL_MAX;
+      for (node = T->head; node != NULL; node = node->next)
+      {  xassert(node->up != NULL);
+         if (best > node->up->ii_sum)
+            p = node->p, best = node->up->ii_sum;
+      }
+      return p;
+}
+
+static int best_proj(glp_tree *T)
+{     /* select subproblem using the best projection heuristic */
+      IOSNPD *root, *node;
+      int p;
+      double best, deg, obj;
+      /* the global bound must exist */
+      xassert(T->mip->mip_stat == GLP_FEAS);
+      /* obtain pointer to the root node, which must exist */
+      root = T->slot[1].node;
+      xassert(root != NULL);
+      /* deg estimates degradation of the objective function per unit
+         of the sum of integer infeasibilities */
+      xassert(root->ii_sum > 0.0);
+      deg = (T->mip->mip_obj - root->bound) / root->ii_sum;
+      /* nothing has been selected so far */
+      p = 0, best = DBL_MAX;
+      /* walk through the list of active subproblems */
+      for (node = T->head; node != NULL; node = node->next)
+      {  xassert(node->up != NULL);
+         /* obj estimates optimal objective value if the sum of integer
+            infeasibilities were zero */
+         obj = node->up->bound + deg * node->up->ii_sum;
+         if (T->mip->dir == GLP_MAX) obj = - obj;
+         /* select the subproblem which has the best estimated optimal
+            objective value */
+         if (best > obj) p = node->p, best = obj;
+      }
+      return p;
+}
+
+static int best_node(glp_tree *T)
+{     /* select subproblem with best local bound */
+      IOSNPD *node, *best = NULL;
+      double bound, eps;
+      switch (T->mip->dir)
+      {  case GLP_MIN:
+            bound = +DBL_MAX;
+            for (node = T->head; node != NULL; node = node->next)
+               if (bound > node->bound) bound = node->bound;
+            xassert(bound != +DBL_MAX);
+            eps = 0.001 * (1.0 + fabs(bound));
+            for (node = T->head; node != NULL; node = node->next)
+            {  if (node->bound <= bound + eps)
+               {  xassert(node->up != NULL);
+                  if (best == NULL ||
+#if 1
+                  best->up->ii_sum > node->up->ii_sum) best = node;
+#else
+                  best->lp_obj > node->lp_obj) best = node;
+#endif
+               }
+            }
+            break;
+         case GLP_MAX:
+            bound = -DBL_MAX;
+            for (node = T->head; node != NULL; node = node->next)
+               if (bound < node->bound) bound = node->bound;
+            xassert(bound != -DBL_MAX);
+            eps = 0.001 * (1.0 + fabs(bound));
+            for (node = T->head; node != NULL; node = node->next)
+            {  if (node->bound >= bound - eps)
+               {  xassert(node->up != NULL);
+                  if (best == NULL ||
+#if 1
+                  best->up->ii_sum > node->up->ii_sum) best = node;
+#else
+                  best->lp_obj < node->lp_obj) best = node;
+#endif
+               }
+            }
+            break;
+         default:
+            xassert(T != T);
+      }
+      xassert(best != NULL);
+      return best->p;
+}
+
+/* eof */
diff --git a/optional/glpk/glpipm.c b/optional/glpk/glpipm.c
new file mode 100644
index 0000000..295f86b
--- /dev/null
+++ b/optional/glpk/glpipm.c
@@ -0,0 +1,1147 @@
+/* glpipm.c */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#endif
+
+#include "glpipm.h"
+#include "glpmat.h"
+
+#define ITER_MAX 100
+/* maximal number of iterations */
+
+struct csa
+{     /* common storage area */
+      /*--------------------------------------------------------------*/
+      /* LP data */
+      int m;
+      /* number of rows (equality constraints) */
+      int n;
+      /* number of columns (structural variables) */
+      int *A_ptr; /* int A_ptr[1+m+1]; */
+      int *A_ind; /* int A_ind[A_ptr[m+1]]; */
+      double *A_val; /* double A_val[A_ptr[m+1]]; */
+      /* mxn-matrix A in storage-by-rows format */
+      double *b; /* double b[1+m]; */
+      /* m-vector b of right-hand sides */
+      double *c; /* double c[1+n]; */
+      /* n-vector c of objective coefficients; c[0] is constant term of
+         the objective function */
+      /*--------------------------------------------------------------*/
+      /* LP solution */
+      double *x; /* double x[1+n]; */
+      double *y; /* double y[1+m]; */
+      double *z; /* double z[1+n]; */
+      /* current point in primal-dual space; the best point on exit */
+      /*--------------------------------------------------------------*/
+      /* control parameters */
+      const glp_iptcp *parm;
+      /*--------------------------------------------------------------*/
+      /* working arrays and variables */
+      double *D; /* double D[1+n]; */
+      /* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and
+         Z = diag(z[j]) */
+      int *P; /* int P[1+m+m]; */
+      /* permutation mxm-matrix P used to minimize fill-in in Cholesky
+         factorization */
+      int *S_ptr; /* int S_ptr[1+m+1]; */
+      int *S_ind; /* int S_ind[S_ptr[m+1]]; */
+      double *S_val; /* double S_val[S_ptr[m+1]]; */
+      double *S_diag; /* double S_diag[1+m]; */
+      /* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular
+         part without diagonal elements is stored in S_ptr, S_ind, and
+         S_val in storage-by-rows format, diagonal elements are stored
+         in S_diag */
+      int *U_ptr; /* int U_ptr[1+m+1]; */
+      int *U_ind; /* int U_ind[U_ptr[m+1]]; */
+      double *U_val; /* double U_val[U_ptr[m+1]]; */
+      double *U_diag; /* double U_diag[1+m]; */
+      /* upper triangular mxm-matrix U defining Cholesky factorization
+         S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind,
+         U_val in storage-by-rows format, diagonal elements are stored
+         in U_diag */
+      int iter;
+      /* iteration number (0, 1, 2, ...); iter = 0 corresponds to the
+         initial point */
+      double obj;
+      /* current value of the objective function */
+      double rpi;
+      /* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */
+      double rdi;
+      /* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */
+      double gap;
+      /* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative
+         difference between primal and dual objective functions */
+      double phi;
+      /* merit function phi = ||A*x-b||/max(1,||b||) +
+                            + ||A'*y+z-c||/max(1,||c||) +
+                            + |c'*x-b'*y|/max(1,||b||,||c||) */
+      double mu;
+      /* duality measure mu = x'*z/n (used as barrier parameter) */
+      double rmu;
+      /* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */
+      double rmu0;
+      /* the initial value of rmu on iteration 0 */
+      double *phi_min; /* double phi_min[1+ITER_MAX]; */
+      /* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on
+         k-th iteration, 0 <= k <= iter */
+      int best_iter;
+      /* iteration number, on which the value of phi reached its best
+         (minimal) value */
+      double *best_x; /* double best_x[1+n]; */
+      double *best_y; /* double best_y[1+m]; */
+      double *best_z; /* double best_z[1+n]; */
+      /* best point (in the sense of the merit function phi) which has
+         been reached on iteration iter_best */
+      double best_obj;
+      /* objective value at the best point */
+      double *dx_aff; /* double dx_aff[1+n]; */
+      double *dy_aff; /* double dy_aff[1+m]; */
+      double *dz_aff; /* double dz_aff[1+n]; */
+      /* affine scaling direction */
+      double alfa_aff_p, alfa_aff_d;
+      /* maximal primal and dual stepsizes in affine scaling direction,
+         on which x and z are still non-negative */
+      double mu_aff;
+      /* duality measure mu_aff = x_aff'*z_aff/n in the boundary point
+         x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */
+      double sigma;
+      /* Mehrotra's heuristic parameter (0 <= sigma <= 1) */
+      double *dx_cc; /* double dx_cc[1+n]; */
+      double *dy_cc; /* double dy_cc[1+m]; */
+      double *dz_cc; /* double dz_cc[1+n]; */
+      /* centering corrector direction */
+      double *dx; /* double dx[1+n]; */
+      double *dy; /* double dy[1+m]; */
+      double *dz; /* double dz[1+n]; */
+      /* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc,
+         dz = dz_aff+dz_cc */
+      double alfa_max_p;
+      double alfa_max_d;
+      /* maximal primal and dual stepsizes in combined direction, on
+         which x and z are still non-negative */
+};
+
+/***********************************************************************
+*  initialize - allocate and initialize common storage area
+*
+*  This routine allocates and initializes the common storage area (CSA)
+*  used by interior-point method routines. */
+
+static void initialize(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int i;
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1);
+      csa->D = xcalloc(1+n, sizeof(double));
+      /* P := I */
+      csa->P = xcalloc(1+m+m, sizeof(int));
+      for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i;
+      /* S := A*A', symbolically */
+      csa->S_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
+         csa->S_ptr);
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n",
+            csa->S_ptr[m+1]-1 + m);
+      /* determine P using specified ordering algorithm */
+      if (csa->parm->ord_alg == GLP_ORD_NONE)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Original ordering is being used\n");
+         for (i = 1; i <= m; i++)
+            csa->P[i] = csa->P[m+i] = i;
+      }
+      else if (csa->parm->ord_alg == GLP_ORD_QMD)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Minimum degree ordering (QMD)...\n");
+         min_degree(m, csa->S_ptr, csa->S_ind, csa->P);
+      }
+      else if (csa->parm->ord_alg == GLP_ORD_AMD)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Approximate minimum degree ordering (AMD)...\n");
+         amd_order1(m, csa->S_ptr, csa->S_ind, csa->P);
+      }
+      else if (csa->parm->ord_alg == GLP_ORD_SYMAMD)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Approximate minimum degree ordering (SYMAMD)...\n")
+               ;
+         symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P);
+      }
+      else
+         xassert(csa != csa);
+      /* S := P*A*A'*P', symbolically */
+      xfree(csa->S_ind);
+      csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
+         csa->S_ptr);
+      csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double));
+      csa->S_diag = xcalloc(1+m, sizeof(double));
+      /* compute Cholesky factorization S = U'*U, symbolically */
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Computing Cholesky factorization S = L*L'...\n");
+      csa->U_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr);
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m);
+      csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double));
+      csa->U_diag = xcalloc(1+m, sizeof(double));
+      csa->iter = 0;
+      csa->obj = 0.0;
+      csa->rpi = 0.0;
+      csa->rdi = 0.0;
+      csa->gap = 0.0;
+      csa->phi = 0.0;
+      csa->mu = 0.0;
+      csa->rmu = 0.0;
+      csa->rmu0 = 0.0;
+      csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double));
+      csa->best_iter = 0;
+      csa->best_x = xcalloc(1+n, sizeof(double));
+      csa->best_y = xcalloc(1+m, sizeof(double));
+      csa->best_z = xcalloc(1+n, sizeof(double));
+      csa->best_obj = 0.0;
+      csa->dx_aff = xcalloc(1+n, sizeof(double));
+      csa->dy_aff = xcalloc(1+m, sizeof(double));
+      csa->dz_aff = xcalloc(1+n, sizeof(double));
+      csa->alfa_aff_p = 0.0;
+      csa->alfa_aff_d = 0.0;
+      csa->mu_aff = 0.0;
+      csa->sigma = 0.0;
+      csa->dx_cc = xcalloc(1+n, sizeof(double));
+      csa->dy_cc = xcalloc(1+m, sizeof(double));
+      csa->dz_cc = xcalloc(1+n, sizeof(double));
+      csa->dx = csa->dx_aff;
+      csa->dy = csa->dy_aff;
+      csa->dz = csa->dz_aff;
+      csa->alfa_max_p = 0.0;
+      csa->alfa_max_d = 0.0;
+      return;
+}
+
+/***********************************************************************
+*  A_by_vec - compute y = A*x
+*
+*  This routine computes matrix-vector product y = A*x, where A is the
+*  constraint matrix. */
+
+static void A_by_vec(struct csa *csa, double x[], double y[])
+{     /* compute y = A*x */
+      int m = csa->m;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int i, t, beg, end;
+      double temp;
+      for (i = 1; i <= m; i++)
+      {  temp = 0.0;
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]];
+         y[i] = temp;
+      }
+      return;
+}
+
+/***********************************************************************
+*  AT_by_vec - compute y = A'*x
+*
+*  This routine computes matrix-vector product y = A'*x, where A' is a
+*  matrix transposed to the constraint matrix A. */
+
+static void AT_by_vec(struct csa *csa, double x[], double y[])
+{     /* compute y = A'*x, where A' is transposed to A */
+      int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int i, j, t, beg, end;
+      double temp;
+      for (j = 1; j <= n; j++) y[j] = 0.0;
+      for (i = 1; i <= m; i++)
+      {  temp = x[i];
+         if (temp == 0.0) continue;
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp;
+      }
+      return;
+}
+
+/***********************************************************************
+*  decomp_NE - numeric factorization of matrix S = P*A*D*A'*P'
+*
+*  This routine implements numeric phase of Cholesky factorization of
+*  the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal
+*  equation system. Matrix D is assumed to be already computed. */
+
+static void decomp_NE(struct csa *csa)
+{     adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind,
+         csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val,
+         csa->S_diag);
+      chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val,
+         csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag);
+      return;
+}
+
+/***********************************************************************
+*  solve_NE - solve normal equation system
+*
+*  This routine solves the normal equation system:
+*
+*     A*D*A'*y = h.
+*
+*  It is assumed that the matrix A*D*A' has been previously factorized
+*  by the routine decomp_NE.
+*
+*  On entry the array y contains the vector of right-hand sides h. On
+*  exit this array contains the computed vector of unknowns y.
+*
+*  Once the vector y has been computed the routine checks for numeric
+*  stability. If the residual vector:
+*
+*     r = A*D*A'*y - h
+*
+*  is relatively small, the routine returns zero, otherwise non-zero is
+*  returned. */
+
+static int solve_NE(struct csa *csa, double y[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *P = csa->P;
+      int i, j, ret = 0;
+      double *h, *r, *w;
+      /* save vector of right-hand sides h */
+      h = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) h[i] = y[i];
+      /* solve normal equation system (A*D*A')*y = h */
+      /* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we
+         have inv(A*D*A') = P'*inv(U)*inv(U')*P */
+      /* w := P*h */
+      w = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) w[i] = y[P[i]];
+      /* w := inv(U')*w */
+      ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
+      /* w := inv(U)*w */
+      u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
+      /* y := P'*w */
+      for (i = 1; i <= m; i++) y[i] = w[P[m+i]];
+      xfree(w);
+      /* compute residual vector r = A*D*A'*y - h */
+      r = xcalloc(1+m, sizeof(double));
+      /* w := A'*y */
+      w = xcalloc(1+n, sizeof(double));
+      AT_by_vec(csa, y, w);
+      /* w := D*w */
+      for (j = 1; j <= n; j++) w[j] *= csa->D[j];
+      /* r := A*w */
+      A_by_vec(csa, w, r);
+      xfree(w);
+      /* r := r - h */
+      for (i = 1; i <= m; i++) r[i] -= h[i];
+      /* check for numeric stability */
+      for (i = 1; i <= m; i++)
+      {  if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4)
+         {  ret = 1;
+            break;
+         }
+      }
+      xfree(h);
+      xfree(r);
+      return ret;
+}
+
+/***********************************************************************
+*  solve_NS - solve Newtonian system
+*
+*  This routine solves the Newtonian system:
+*
+*     A*dx               = p
+*
+*           A'*dy +   dz = q
+*
+*     Z*dx        + X*dz = r
+*
+*  where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal
+*  equation system:
+*
+*     (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p
+*
+*  (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by
+*  the routine decomp_NE).
+*
+*  Once vector dy has been computed the routine computes vectors dx and
+*  dz as follows:
+*
+*     dx = inv(Z)*(X*(A'*dy-q)+r)
+*
+*     dz = inv(X)*(r-Z*dx)
+*
+*  The routine solve_NS returns the same code which was reported by the
+*  routine solve_NE (see above). */
+
+static int solve_NS(struct csa *csa, double p[], double q[], double r[],
+      double dx[], double dy[], double dz[])
+{     int m = csa->m;
+      int n = csa->n;
+      double *x = csa->x;
+      double *z = csa->z;
+      int i, j, ret;
+      double *w = dx;
+      /* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for
+         the normal equation system */
+      for (j = 1; j <= n; j++)
+         w[j] = (x[j] * q[j] - r[j]) / z[j];
+      A_by_vec(csa, w, dy);
+      for (i = 1; i <= m; i++) dy[i] += p[i];
+      /* solve the normal equation system to compute vector dy */
+      ret = solve_NE(csa, dy);
+      /* compute vectors dx and dz */
+      AT_by_vec(csa, dy, dx);
+      for (j = 1; j <= n; j++)
+      {  dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j];
+         dz[j] = (r[j] - z[j] * dx[j]) / x[j];
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  initial_point - choose initial point using Mehrotra's heuristic
+*
+*  This routine chooses a starting point using a heuristic proposed in
+*  the paper:
+*
+*  S. Mehrotra. On the implementation of a primal-dual interior point
+*  method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
+*
+*  The starting point x in the primal space is chosen as a solution of
+*  the following least squares problem:
+*
+*     minimize    ||x||
+*
+*     subject to  A*x = b
+*
+*  which can be computed explicitly as follows:
+*
+*     x = A'*inv(A*A')*b
+*
+*  Similarly, the starting point (y, z) in the dual space is chosen as
+*  a solution of the following least squares problem:
+*
+*     minimize    ||z||
+*
+*     subject to  A'*y + z = c
+*
+*  which can be computed explicitly as follows:
+*
+*     y = inv(A*A')*A*c
+*
+*     z = c - A'*y
+*
+*  However, some components of the vectors x and z may be non-positive
+*  or close to zero, so the routine uses a Mehrotra's heuristic to find
+*  a more appropriate starting point. */
+
+static void initial_point(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *b = csa->b;
+      double *c = csa->c;
+      double *x = csa->x;
+      double *y = csa->y;
+      double *z = csa->z;
+      double *D = csa->D;
+      int i, j;
+      double dp, dd, ex, ez, xz;
+      /* factorize A*A' */
+      for (j = 1; j <= n; j++) D[j] = 1.0;
+      decomp_NE(csa);
+      /* x~ = A'*inv(A*A')*b */
+      for (i = 1; i <= m; i++) y[i] = b[i];
+      solve_NE(csa, y);
+      AT_by_vec(csa, y, x);
+      /* y~ = inv(A*A')*A*c */
+      A_by_vec(csa, c, y);
+      solve_NE(csa, y);
+      /* z~ = c - A'*y~ */
+      AT_by_vec(csa, y,z);
+      for (j = 1; j <= n; j++) z[j] = c[j] - z[j];
+      /* use Mehrotra's heuristic in order to choose more appropriate
+         starting point with positive components of vectors x and z */
+      dp = dd = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (dp < -1.5 * x[j]) dp = -1.5 * x[j];
+         if (dd < -1.5 * z[j]) dd = -1.5 * z[j];
+      }
+      /* note that b = 0 involves x = 0, and c = 0 involves y = 0 and
+         z = 0, so we need to be careful */
+      if (dp == 0.0) dp = 1.5;
+      if (dd == 0.0) dd = 1.5;
+      ex = ez = xz = 0.0;
+      for (j = 1; j <= n; j++)
+      {  ex += (x[j] + dp);
+         ez += (z[j] + dd);
+         xz += (x[j] + dp) * (z[j] + dd);
+      }
+      dp += 0.5 * (xz / ez);
+      dd += 0.5 * (xz / ex);
+      for (j = 1; j <= n; j++)
+      {  x[j] += dp;
+         z[j] += dd;
+         xassert(x[j] > 0.0 && z[j] > 0.0);
+      }
+      return;
+}
+
+/***********************************************************************
+*  basic_info - perform basic computations at the current point
+*
+*  This routine computes the following quantities at the current point:
+*
+*  1) value of the objective function:
+*
+*     F = c'*x + c[0]
+*
+*  2) relative primal infeasibility:
+*
+*     rpi = ||A*x-b|| / (1+||b||)
+*
+*  3) relative dual infeasibility:
+*
+*     rdi = ||A'*y+z-c|| / (1+||c||)
+*
+*  4) primal-dual gap (relative difference between the primal and the
+*     dual objective function values):
+*
+*     gap = |c'*x-b'*y| / (1+|c'*x|)
+*
+*  5) merit function:
+*
+*     phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) +
+*
+*         + |c'*x-b'*y| / max(1,||b||,||c||)
+*
+*  6) duality measure:
+*
+*     mu = x'*z / n
+*
+*  7) the ratio of infeasibility to mu:
+*
+*     rmu = max(||A*x-b||,||A'*y+z-c||) / mu
+*
+*  where ||*|| denotes euclidian norm, *' denotes transposition. */
+
+static void basic_info(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *b = csa->b;
+      double *c = csa->c;
+      double *x = csa->x;
+      double *y = csa->y;
+      double *z = csa->z;
+      int i, j;
+      double norm1, bnorm, norm2, cnorm, cx, by, *work, temp;
+      /* compute value of the objective function */
+      temp = c[0];
+      for (j = 1; j <= n; j++) temp += c[j] * x[j];
+      csa->obj = temp;
+      /* norm1 = ||A*x-b|| */
+      work = xcalloc(1+m, sizeof(double));
+      A_by_vec(csa, x, work);
+      norm1 = 0.0;
+      for (i = 1; i <= m; i++)
+         norm1 += (work[i] - b[i]) * (work[i] - b[i]);
+      norm1 = sqrt(norm1);
+      xfree(work);
+      /* bnorm = ||b|| */
+      bnorm = 0.0;
+      for (i = 1; i <= m; i++) bnorm += b[i] * b[i];
+      bnorm = sqrt(bnorm);
+      /* compute relative primal infeasibility */
+      csa->rpi = norm1 / (1.0 + bnorm);
+      /* norm2 = ||A'*y+z-c|| */
+      work = xcalloc(1+n, sizeof(double));
+      AT_by_vec(csa, y, work);
+      norm2 = 0.0;
+      for (j = 1; j <= n; j++)
+         norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]);
+      norm2 = sqrt(norm2);
+      xfree(work);
+      /* cnorm = ||c|| */
+      cnorm = 0.0;
+      for (j = 1; j <= n; j++) cnorm += c[j] * c[j];
+      cnorm = sqrt(cnorm);
+      /* compute relative dual infeasibility */
+      csa->rdi = norm2 / (1.0 + cnorm);
+      /* by = b'*y */
+      by = 0.0;
+      for (i = 1; i <= m; i++) by += b[i] * y[i];
+      /* cx = c'*x */
+      cx = 0.0;
+      for (j = 1; j <= n; j++) cx += c[j] * x[j];
+      /* compute primal-dual gap */
+      csa->gap = fabs(cx - by) / (1.0 + fabs(cx));
+      /* compute merit function */
+      csa->phi = 0.0;
+      csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0);
+      csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0);
+      temp = 1.0;
+      if (temp < bnorm) temp = bnorm;
+      if (temp < cnorm) temp = cnorm;
+      csa->phi += fabs(cx - by) / temp;
+      /* compute duality measure */
+      temp = 0.0;
+      for (j = 1; j <= n; j++) temp += x[j] * z[j];
+      csa->mu = temp / (double)n;
+      /* compute the ratio of infeasibility to mu */
+      csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu;
+      return;
+}
+
+/***********************************************************************
+*  make_step - compute next point using Mehrotra's technique
+*
+*  This routine computes the next point using the predictor-corrector
+*  technique proposed in the paper:
+*
+*  S. Mehrotra. On the implementation of a primal-dual interior point
+*  method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
+*
+*  At first, the routine computes so called affine scaling (predictor)
+*  direction (dx_aff,dy_aff,dz_aff) which is a solution of the system:
+*
+*     A*dx_aff                       = b - A*x
+*
+*               A'*dy_aff +   dz_aff = c - A'*y - z
+*
+*     Z*dx_aff            + X*dz_aff = - X*Z*e
+*
+*  where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]),
+*  e = (1,...,1)'.
+*
+*  Then, the routine computes the centering parameter sigma, using the
+*  following Mehrotra's heuristic:
+*
+*     alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0}
+*
+*     alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0}
+*
+*     mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n
+*
+*     sigma = (mu_aff/mu)^3
+*
+*  where alfa_aff_p is the maximal stepsize along the affine scaling
+*  direction in the primal space, alfa_aff_d is the maximal stepsize
+*  along the same direction in the dual space.
+*
+*  After determining sigma the routine computes so called centering
+*  (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of
+*  the system:
+*
+*     A*dx_cc                     = 0
+*
+*              A'*dy_cc +   dz_cc = 0
+*
+*     Z*dx_cc           + X*dz_cc = sigma*mu*e - X*Z*e
+*
+*  Finally, the routine computes the combined direction
+*
+*     (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc)
+*
+*  and determines maximal primal and dual stepsizes along the combined
+*  direction:
+*
+*     alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0}
+*
+*     alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0}
+*
+*  In order to prevent the next point to be too close to the boundary
+*  of the positive ortant, the routine decreases maximal stepsizes:
+*
+*     alfa_p = gamma_p * alfa_max_p
+*
+*     alfa_d = gamma_d * alfa_max_d
+*
+*  where gamma_p and gamma_d are scaling factors, and computes the next
+*  point:
+*
+*     x_new = x + alfa_p * dx
+*
+*     y_new = y + alfa_d * dy
+*
+*     z_new = z + alfa_d * dz
+*
+*  which becomes the current point on the next iteration. */
+
+static int make_step(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *b = csa->b;
+      double *c = csa->c;
+      double *x = csa->x;
+      double *y = csa->y;
+      double *z = csa->z;
+      double *dx_aff = csa->dx_aff;
+      double *dy_aff = csa->dy_aff;
+      double *dz_aff = csa->dz_aff;
+      double *dx_cc = csa->dx_cc;
+      double *dy_cc = csa->dy_cc;
+      double *dz_cc = csa->dz_cc;
+      double *dx = csa->dx;
+      double *dy = csa->dy;
+      double *dz = csa->dz;
+      int i, j, ret = 0;
+      double temp, gamma_p, gamma_d, *p, *q, *r;
+      /* allocate working arrays */
+      p = xcalloc(1+m, sizeof(double));
+      q = xcalloc(1+n, sizeof(double));
+      r = xcalloc(1+n, sizeof(double));
+      /* p = b - A*x */
+      A_by_vec(csa, x, p);
+      for (i = 1; i <= m; i++) p[i] = b[i] - p[i];
+      /* q = c - A'*y - z */
+      AT_by_vec(csa, y,q);
+      for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j];
+      /* r = - X * Z * e */
+      for (j = 1; j <= n; j++) r[j] = - x[j] * z[j];
+      /* solve the first Newtonian system */
+      if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff))
+      {  ret = 1;
+         goto done;
+      }
+      /* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */
+      /* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */
+      csa->alfa_aff_p = csa->alfa_aff_d = 1.0;
+      for (j = 1; j <= n; j++)
+      {  if (dx_aff[j] < 0.0)
+         {  temp = - x[j] / dx_aff[j];
+            if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp;
+         }
+         if (dz_aff[j] < 0.0)
+         {  temp = - z[j] / dz_aff[j];
+            if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp;
+         }
+      }
+      /* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */
+      temp = 0.0;
+      for (j = 1; j <= n; j++)
+         temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) *
+                 (z[j] + csa->alfa_aff_d * dz_aff[j]);
+      csa->mu_aff = temp / (double)n;
+      /* sigma = (mu_aff/mu)^3 */
+      temp = csa->mu_aff / csa->mu;
+      csa->sigma = temp * temp * temp;
+      /* p = 0 */
+      for (i = 1; i <= m; i++) p[i] = 0.0;
+      /* q = 0 */
+      for (j = 1; j <= n; j++) q[j] = 0.0;
+      /* r = sigma * mu * e - X * Z * e */
+      for (j = 1; j <= n; j++)
+         r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j];
+      /* solve the second Newtonian system with the same coefficients
+         but with altered right-hand sides */
+      if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc))
+      {  ret = 1;
+         goto done;
+      }
+      /* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */
+      for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j];
+      for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i];
+      for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j];
+      /* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */
+      /* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */
+      csa->alfa_max_p = csa->alfa_max_d = 1.0;
+      for (j = 1; j <= n; j++)
+      {  if (dx[j] < 0.0)
+         {  temp = - x[j] / dx[j];
+            if (csa->alfa_max_p > temp) csa->alfa_max_p = temp;
+         }
+         if (dz[j] < 0.0)
+         {  temp = - z[j] / dz[j];
+            if (csa->alfa_max_d > temp) csa->alfa_max_d = temp;
+         }
+      }
+      /* determine scale factors (not implemented yet) */
+      gamma_p = 0.90;
+      gamma_d = 0.90;
+      /* compute the next point */
+      for (j = 1; j <= n; j++)
+      {  x[j] += gamma_p * csa->alfa_max_p * dx[j];
+         xassert(x[j] > 0.0);
+      }
+      for (i = 1; i <= m; i++)
+         y[i] += gamma_d * csa->alfa_max_d * dy[i];
+      for (j = 1; j <= n; j++)
+      {  z[j] += gamma_d * csa->alfa_max_d * dz[j];
+         xassert(z[j] > 0.0);
+      }
+done: /* free working arrays */
+      xfree(p);
+      xfree(q);
+      xfree(r);
+      return ret;
+}
+
+/***********************************************************************
+*  terminate - deallocate common storage area
+*
+*  This routine frees all memory allocated to the common storage area
+*  used by interior-point method routines. */
+
+static void terminate(struct csa *csa)
+{     xfree(csa->D);
+      xfree(csa->P);
+      xfree(csa->S_ptr);
+      xfree(csa->S_ind);
+      xfree(csa->S_val);
+      xfree(csa->S_diag);
+      xfree(csa->U_ptr);
+      xfree(csa->U_ind);
+      xfree(csa->U_val);
+      xfree(csa->U_diag);
+      xfree(csa->phi_min);
+      xfree(csa->best_x);
+      xfree(csa->best_y);
+      xfree(csa->best_z);
+      xfree(csa->dx_aff);
+      xfree(csa->dy_aff);
+      xfree(csa->dz_aff);
+      xfree(csa->dx_cc);
+      xfree(csa->dy_cc);
+      xfree(csa->dz_cc);
+      return;
+}
+
+/***********************************************************************
+*  ipm_main - main interior-point method routine
+*
+*  This is a main routine of the primal-dual interior-point method.
+*
+*  The routine ipm_main returns one of the following codes:
+*
+*  0 - optimal solution found;
+*  1 - problem has no feasible (primal or dual) solution;
+*  2 - no convergence;
+*  3 - iteration limit exceeded;
+*  4 - numeric instability on solving Newtonian system.
+*
+*  In case of non-zero return code the routine returns the best point,
+*  which has been reached during optimization. */
+
+static int ipm_main(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int i, j, status;
+      double temp;
+      /* choose initial point using Mehrotra's heuristic */
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Guessing initial point...\n");
+      initial_point(csa);
+      /* main loop starts here */
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Optimization begins...\n");
+      for (;;)
+      {  /* perform basic computations at the current point */
+         basic_info(csa);
+         /* save initial value of rmu */
+         if (csa->iter == 0) csa->rmu0 = csa->rmu;
+         /* accumulate values of min(phi[k]) and save the best point */
+         xassert(csa->iter <= ITER_MAX);
+         if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi)
+         {  csa->phi_min[csa->iter] = csa->phi;
+            csa->best_iter = csa->iter;
+            for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j];
+            for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i];
+            for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j];
+            csa->best_obj = csa->obj;
+         }
+         else
+            csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1];
+         /* display information at the current point */
+         if (csa->parm->msg_lev >= GLP_MSG_ON)
+            xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap ="
+               " %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi,
+               csa->gap);
+         /* check if the current point is optimal */
+         if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8)
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("OPTIMAL SOLUTION FOUND\n");
+            status = 0;
+            break;
+         }
+         /* check if the problem has no feasible solution */
+         temp = 1e5 * csa->phi_min[csa->iter];
+         if (temp < 1e-8) temp = 1e-8;
+         if (csa->phi >= temp)
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n")
+                  ;
+            status = 1;
+            break;
+         }
+         /* check for very slow convergence or divergence */
+         if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu /
+               csa->rmu0 >= 1e6) ||
+               (csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 *
+               csa->phi_min[csa->iter - 30]))
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("NO CONVERGENCE; SEARCH TERMINATED\n");
+            status = 2;
+            break;
+         }
+         /* check for maximal number of iterations */
+         if (csa->iter == ITER_MAX)
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            status = 3;
+            break;
+         }
+         /* start the next iteration */
+         csa->iter++;
+         /* factorize normal equation system */
+         for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j];
+         decomp_NE(csa);
+         /* compute the next point using Mehrotra's predictor-corrector
+            technique */
+         if (make_step(csa))
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n");
+            status = 4;
+            break;
+         }
+      }
+      /* restore the best point */
+      if (status != 0)
+      {  for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j];
+         for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i];
+         for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j];
+         if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Best point %17.9e was reached on iteration %d\n",
+               csa->best_obj, csa->best_iter);
+      }
+      /* return to the calling program */
+      return status;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ipm_solve - core LP solver based on the interior-point method
+*
+*  SYNOPSIS
+*
+*  #include "glpipm.h"
+*  int ipm_solve(glp_prob *P, const glp_iptcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine ipm_solve is a core LP solver based on the primal-dual
+*  interior-point method.
+*
+*  The routine assumes the following standard formulation of LP problem
+*  to be solved:
+*
+*     minimize
+*
+*        F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n]
+*
+*     subject to linear constraints
+*
+*        a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1]
+*
+*        a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2]
+*
+*              . . . . . .
+*
+*        a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m]
+*
+*     and non-negative variables
+*
+*        x[1] >= 0, x[2] >= 0, ..., x[n] >= 0
+*
+*  where:
+*  F                    is the objective function;
+*  x[1], ..., x[n]      are (structural) variables;
+*  c[0]                 is a constant term of the objective function;
+*  c[1], ..., c[n]      are objective coefficients;
+*  a[1,1], ..., a[m,n]  are constraint coefficients;
+*  b[1], ..., b[n]      are right-hand sides.
+*
+*  The solution is three vectors x, y, and z, which are stored by the
+*  routine in the arrays x, y, and z, respectively. These vectors
+*  correspond to the best primal-dual point found during optimization.
+*  They are approximate solution of the following system (which is the
+*  Karush-Kuhn-Tucker optimality conditions):
+*
+*     A*x      = b      (primal feasibility condition)
+*
+*     A'*y + z = c      (dual feasibility condition)
+*
+*     x'*z     = 0      (primal-dual complementarity condition)
+*
+*     x >= 0, z >= 0    (non-negativity condition)
+*
+*  where:
+*  x[1], ..., x[n]      are primal (structural) variables;
+*  y[1], ..., y[m]      are dual variables (Lagrange multipliers) for
+*                       equality constraints;
+*  z[1], ..., z[n]      are dual variables (Lagrange multipliers) for
+*                       non-negativity constraints.
+*
+*  RETURNS
+*
+*  0  LP has been successfully solved.
+*
+*  GLP_ENOCVG
+*     No convergence.
+*
+*  GLP_EITLIM
+*     Iteration limit exceeded.
+*
+*  GLP_EINSTAB
+*     Numeric instability on solving Newtonian system.
+*
+*  In case of non-zero return code the routine returns the best point,
+*  which has been reached during optimization. */
+
+int ipm_solve(glp_prob *P, const glp_iptcp *parm)
+{     struct csa _dsa, *csa = &_dsa;
+      int m = P->m;
+      int n = P->n;
+      int nnz = P->nnz;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, loc, ret, *A_ind, *A_ptr;
+      double dir, *A_val, *b, *c, *x, *y, *z;
+      xassert(m > 0);
+      xassert(n > 0);
+      /* allocate working arrays */
+      A_ptr = xcalloc(1+m+1, sizeof(int));
+      A_ind = xcalloc(1+nnz, sizeof(int));
+      A_val = xcalloc(1+nnz, sizeof(double));
+      b = xcalloc(1+m, sizeof(double));
+      c = xcalloc(1+n, sizeof(double));
+      x = xcalloc(1+n, sizeof(double));
+      y = xcalloc(1+m, sizeof(double));
+      z = xcalloc(1+n, sizeof(double));
+      /* prepare rows and constraint coefficients */
+      loc = 1;
+      for (i = 1; i <= m; i++)
+      {  row = P->row[i];
+         xassert(row->type == GLP_FX);
+         b[i] = row->lb * row->rii;
+         A_ptr[i] = loc;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  A_ind[loc] = aij->col->j;
+            A_val[loc] = row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      A_ptr[m+1] = loc;
+      xassert(loc-1 == nnz);
+      /* prepare columns and objective coefficients */
+      if (P->dir == GLP_MIN)
+         dir = +1.0;
+      else if (P->dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(P != P);
+      c[0] = dir * P->c0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         xassert(col->type == GLP_LO && col->lb == 0.0);
+         c[j] = dir * col->coef * col->sjj;
+      }
+      /* allocate and initialize the common storage area */
+      csa->m = m;
+      csa->n = n;
+      csa->A_ptr = A_ptr;
+      csa->A_ind = A_ind;
+      csa->A_val = A_val;
+      csa->b = b;
+      csa->c = c;
+      csa->x = x;
+      csa->y = y;
+      csa->z = z;
+      csa->parm = parm;
+      initialize(csa);
+      /* solve LP with the interior-point method */
+      ret = ipm_main(csa);
+      /* deallocate the common storage area */
+      terminate(csa);
+      /* determine solution status */
+      if (ret == 0)
+      {  /* optimal solution found */
+         P->ipt_stat = GLP_OPT;
+         ret = 0;
+      }
+      else if (ret == 1)
+      {  /* problem has no feasible (primal or dual) solution */
+         P->ipt_stat = GLP_NOFEAS;
+         ret = 0;
+      }
+      else if (ret == 2)
+      {  /* no convergence */
+         P->ipt_stat = GLP_INFEAS;
+         ret = GLP_ENOCVG;
+      }
+      else if (ret == 3)
+      {  /* iteration limit exceeded */
+         P->ipt_stat = GLP_INFEAS;
+         ret = GLP_EITLIM;
+      }
+      else if (ret == 4)
+      {  /* numeric instability on solving Newtonian system */
+         P->ipt_stat = GLP_INFEAS;
+         ret = GLP_EINSTAB;
+      }
+      else
+         xassert(ret != ret);
+      /* store row solution components */
+      for (i = 1; i <= m; i++)
+      {  row = P->row[i];
+         row->pval = row->lb;
+         row->dval = dir * y[i] * row->rii;
+      }
+      /* store column solution components */
+      P->ipt_obj = P->c0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         col->pval = x[j] * col->sjj;
+         col->dval = dir * z[j] / col->sjj;
+         P->ipt_obj += col->coef * col->pval;
+      }
+      /* free working arrays */
+      xfree(A_ptr);
+      xfree(A_ind);
+      xfree(A_val);
+      xfree(b);
+      xfree(c);
+      xfree(x);
+      xfree(y);
+      xfree(z);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpipm.h b/optional/glpk/glpipm.h
new file mode 100644
index 0000000..78d99b1
--- /dev/null
+++ b/optional/glpk/glpipm.h
@@ -0,0 +1,36 @@
+/* glpipm.h (primal-dual interior-point method) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPIPM_H
+#define GLPIPM_H
+
+#include "glpapi.h"
+
+#define ipm_solve _glp_ipm_solve
+int ipm_solve(glp_prob *P, const glp_iptcp *parm);
+/* core LP solver based on the interior-point method */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpk.h b/optional/glpk/glpk.h
new file mode 100644
index 0000000..11c2d96
--- /dev/null
+++ b/optional/glpk/glpk.h
@@ -0,0 +1,1750 @@
+/* glpk.h */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPK_H
+#define GLPK_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* library version numbers: */
+#define GLP_MAJOR_VERSION  4
+#define GLP_MINOR_VERSION  45
+
+#ifndef GLP_PROB_DEFINED
+#define GLP_PROB_DEFINED
+typedef struct { double _opaque_prob[100]; } glp_prob;
+/* LP/MIP problem object */
+#endif
+
+/* optimization direction flag: */
+#define GLP_MIN            1  /* minimization */
+#define GLP_MAX            2  /* maximization */
+
+/* kind of structural variable: */
+#define GLP_CV             1  /* continuous variable */
+#define GLP_IV             2  /* integer variable */
+#define GLP_BV             3  /* binary variable */
+
+/* type of auxiliary/structural variable: */
+#define GLP_FR             1  /* free variable */
+#define GLP_LO             2  /* variable with lower bound */
+#define GLP_UP             3  /* variable with upper bound */
+#define GLP_DB             4  /* double-bounded variable */
+#define GLP_FX             5  /* fixed variable */
+
+/* status of auxiliary/structural variable: */
+#define GLP_BS             1  /* basic variable */
+#define GLP_NL             2  /* non-basic variable on lower bound */
+#define GLP_NU             3  /* non-basic variable on upper bound */
+#define GLP_NF             4  /* non-basic free variable */
+#define GLP_NS             5  /* non-basic fixed variable */
+
+/* scaling options: */
+#define GLP_SF_GM       0x01  /* perform geometric mean scaling */
+#define GLP_SF_EQ       0x10  /* perform equilibration scaling */
+#define GLP_SF_2N       0x20  /* round scale factors to power of two */
+#define GLP_SF_SKIP     0x40  /* skip if problem is well scaled */
+#define GLP_SF_AUTO     0x80  /* choose scaling options automatically */
+
+/* solution indicator: */
+#define GLP_SOL            1  /* basic solution */
+#define GLP_IPT            2  /* interior-point solution */
+#define GLP_MIP            3  /* mixed integer solution */
+
+/* solution status: */
+#define GLP_UNDEF          1  /* solution is undefined */
+#define GLP_FEAS           2  /* solution is feasible */
+#define GLP_INFEAS         3  /* solution is infeasible */
+#define GLP_NOFEAS         4  /* no feasible solution exists */
+#define GLP_OPT            5  /* solution is optimal */
+#define GLP_UNBND          6  /* solution is unbounded */
+
+typedef struct
+{     /* basis factorization control parameters */
+      int msg_lev;            /* (reserved) */
+      int type;               /* factorization type: */
+#define GLP_BF_FT          1  /* LUF + Forrest-Tomlin */
+#define GLP_BF_BG          2  /* LUF + Schur compl. + Bartels-Golub */
+#define GLP_BF_GR          3  /* LUF + Schur compl. + Givens rotation */
+      int lu_size;            /* luf.sv_size */
+      double piv_tol;         /* luf.piv_tol */
+      int piv_lim;            /* luf.piv_lim */
+      int suhl;               /* luf.suhl */
+      double eps_tol;         /* luf.eps_tol */
+      double max_gro;         /* luf.max_gro */
+      int nfs_max;            /* fhv.hh_max */
+      double upd_tol;         /* fhv.upd_tol */
+      int nrs_max;            /* lpf.n_max */
+      int rs_size;            /* lpf.v_size */
+      double foo_bar[38];     /* (reserved) */
+} glp_bfcp;
+
+typedef struct
+{     /* simplex method control parameters */
+      int msg_lev;            /* message level: */
+#define GLP_MSG_OFF        0  /* no output */
+#define GLP_MSG_ERR        1  /* warning and error messages only */
+#define GLP_MSG_ON         2  /* normal output */
+#define GLP_MSG_ALL        3  /* full output */
+#define GLP_MSG_DBG        4  /* debug output */
+      int meth;               /* simplex method option: */
+#define GLP_PRIMAL         1  /* use primal simplex */
+#define GLP_DUALP          2  /* use dual; if it fails, use primal */
+#define GLP_DUAL           3  /* use dual simplex */
+      int pricing;            /* pricing technique: */
+#define GLP_PT_STD      0x11  /* standard (Dantzig rule) */
+#define GLP_PT_PSE      0x22  /* projected steepest edge */
+      int r_test;             /* ratio test technique: */
+#define GLP_RT_STD      0x11  /* standard (textbook) */
+#define GLP_RT_HAR      0x22  /* two-pass Harris' ratio test */
+      double tol_bnd;         /* spx.tol_bnd */
+      double tol_dj;          /* spx.tol_dj */
+      double tol_piv;         /* spx.tol_piv */
+      double obj_ll;          /* spx.obj_ll */
+      double obj_ul;          /* spx.obj_ul */
+      int it_lim;             /* spx.it_lim */
+      int tm_lim;             /* spx.tm_lim (milliseconds) */
+      int out_frq;            /* spx.out_frq */
+      int out_dly;            /* spx.out_dly (milliseconds) */
+      int presolve;           /* enable/disable using LP presolver */
+      double foo_bar[36];     /* (reserved) */
+} glp_smcp;
+
+typedef struct
+{     /* interior-point solver control parameters */
+      int msg_lev;            /* message level (see glp_smcp) */
+      int ord_alg;            /* ordering algorithm: */
+#define GLP_ORD_NONE       0  /* natural (original) ordering */
+#define GLP_ORD_QMD        1  /* quotient minimum degree (QMD) */
+#define GLP_ORD_AMD        2  /* approx. minimum degree (AMD) */
+#define GLP_ORD_SYMAMD     3  /* approx. minimum degree (SYMAMD) */
+      double foo_bar[48];     /* (reserved) */
+} glp_iptcp;
+
+#ifndef GLP_TREE_DEFINED
+#define GLP_TREE_DEFINED
+typedef struct { double _opaque_tree[100]; } glp_tree;
+/* branch-and-bound tree */
+#endif
+
+typedef struct
+{     /* integer optimizer control parameters */
+      int msg_lev;            /* message level (see glp_smcp) */
+      int br_tech;            /* branching technique: */
+#define GLP_BR_FFV         1  /* first fractional variable */
+#define GLP_BR_LFV         2  /* last fractional variable */
+#define GLP_BR_MFV         3  /* most fractional variable */
+#define GLP_BR_DTH         4  /* heuristic by Driebeck and Tomlin */
+#define GLP_BR_PCH         5  /* hybrid pseudocost heuristic */
+      int bt_tech;            /* backtracking technique: */
+#define GLP_BT_DFS         1  /* depth first search */
+#define GLP_BT_BFS         2  /* breadth first search */
+#define GLP_BT_BLB         3  /* best local bound */
+#define GLP_BT_BPH         4  /* best projection heuristic */
+      double tol_int;         /* mip.tol_int */
+      double tol_obj;         /* mip.tol_obj */
+      int tm_lim;             /* mip.tm_lim (milliseconds) */
+      int out_frq;            /* mip.out_frq (milliseconds) */
+      int out_dly;            /* mip.out_dly (milliseconds) */
+      void (*cb_func)(glp_tree *T, void *info);
+                              /* mip.cb_func */
+      void *cb_info;          /* mip.cb_info */
+      int cb_size;            /* mip.cb_size */
+      int pp_tech;            /* preprocessing technique: */
+#define GLP_PP_NONE        0  /* disable preprocessing */
+#define GLP_PP_ROOT        1  /* preprocessing only on root level */
+#define GLP_PP_ALL         2  /* preprocessing on all levels */
+      double mip_gap;         /* relative MIP gap tolerance */
+      int mir_cuts;           /* MIR cuts       (GLP_ON/GLP_OFF) */
+      int gmi_cuts;           /* Gomory's cuts  (GLP_ON/GLP_OFF) */
+      int cov_cuts;           /* cover cuts     (GLP_ON/GLP_OFF) */
+      int clq_cuts;           /* clique cuts    (GLP_ON/GLP_OFF) */
+      int presolve;           /* enable/disable using MIP presolver */
+      int binarize;           /* try to binarize integer variables */
+      int fp_heur;            /* feasibility pump heuristic */
+#if 1 /* 28/V-2010 */
+      int alien;              /* use alien solver */
+#endif
+      double foo_bar[29];     /* (reserved) */
+} glp_iocp;
+
+typedef struct
+{     /* additional row attributes */
+      int level;
+      /* subproblem level at which the row was added */
+      int origin;
+      /* row origin flag: */
+#define GLP_RF_REG         0  /* regular constraint */
+#define GLP_RF_LAZY        1  /* "lazy" constraint */
+#define GLP_RF_CUT         2  /* cutting plane constraint */
+      int klass;
+      /* row class descriptor: */
+#define GLP_RF_GMI         1  /* Gomory's mixed integer cut */
+#define GLP_RF_MIR         2  /* mixed integer rounding cut */
+#define GLP_RF_COV         3  /* mixed cover cut */
+#define GLP_RF_CLQ         4  /* clique cut */
+      double foo_bar[7];
+      /* (reserved) */
+} glp_attr;
+
+/* enable/disable flag: */
+#define GLP_ON             1  /* enable something */
+#define GLP_OFF            0  /* disable something */
+
+/* reason codes: */
+#define GLP_IROWGEN     0x01  /* request for row generation */
+#define GLP_IBINGO      0x02  /* better integer solution found */
+#define GLP_IHEUR       0x03  /* request for heuristic solution */
+#define GLP_ICUTGEN     0x04  /* request for cut generation */
+#define GLP_IBRANCH     0x05  /* request for branching */
+#define GLP_ISELECT     0x06  /* request for subproblem selection */
+#define GLP_IPREPRO     0x07  /* request for preprocessing */
+
+/* branch selection indicator: */
+#define GLP_NO_BRNCH       0  /* select no branch */
+#define GLP_DN_BRNCH       1  /* select down-branch */
+#define GLP_UP_BRNCH       2  /* select up-branch */
+
+/* return codes: */
+#define GLP_EBADB       0x01  /* invalid basis */
+#define GLP_ESING       0x02  /* singular matrix */
+#define GLP_ECOND       0x03  /* ill-conditioned matrix */
+#define GLP_EBOUND      0x04  /* invalid bounds */
+#define GLP_EFAIL       0x05  /* solver failed */
+#define GLP_EOBJLL      0x06  /* objective lower limit reached */
+#define GLP_EOBJUL      0x07  /* objective upper limit reached */
+#define GLP_EITLIM      0x08  /* iteration limit exceeded */
+#define GLP_ETMLIM      0x09  /* time limit exceeded */
+#define GLP_ENOPFS      0x0A  /* no primal feasible solution */
+#define GLP_ENODFS      0x0B  /* no dual feasible solution */
+#define GLP_EROOT       0x0C  /* root LP optimum not provided */
+#define GLP_ESTOP       0x0D  /* search terminated by application */
+#define GLP_EMIPGAP     0x0E  /* relative mip gap tolerance reached */
+#define GLP_ENOFEAS     0x0F  /* no primal/dual feasible solution */
+#define GLP_ENOCVG      0x10  /* no convergence */
+#define GLP_EINSTAB     0x11  /* numerical instability */
+#define GLP_EDATA       0x12  /* invalid data */
+#define GLP_ERANGE      0x13  /* result out of range */
+
+/* condition indicator: */
+#define GLP_KKT_PE         1  /* primal equalities */
+#define GLP_KKT_PB         2  /* primal bounds */
+#define GLP_KKT_DE         3  /* dual equalities */
+#define GLP_KKT_DB         4  /* dual bounds */
+#define GLP_KKT_CS         5  /* complementary slackness */
+
+/* MPS file format: */
+#define GLP_MPS_DECK       1  /* fixed (ancient) */
+#define GLP_MPS_FILE       2  /* free (modern) */
+
+typedef struct
+{     /* MPS format control parameters */
+      int blank;
+      /* character code to replace blanks in symbolic names */
+      char *obj_name;
+      /* objective row name */
+      double tol_mps;
+      /* zero tolerance for MPS data */
+      double foo_bar[17];
+      /* (reserved for use in the future) */
+} glp_mpscp;
+
+typedef struct
+{     /* CPLEX LP format control parameters */
+      double foo_bar[20];
+      /* (reserved for use in the future) */
+} glp_cpxcp;
+
+#ifndef GLP_TRAN_DEFINED
+#define GLP_TRAN_DEFINED
+typedef struct { double _opaque_tran[100]; } glp_tran;
+/* MathProg translator workspace */
+#endif
+
+glp_prob *glp_create_prob(void);
+/* create problem object */
+
+void glp_set_prob_name(glp_prob *P, const char *name);
+/* assign (change) problem name */
+
+void glp_set_obj_name(glp_prob *P, const char *name);
+/* assign (change) objective function name */
+
+void glp_set_obj_dir(glp_prob *P, int dir);
+/* set (change) optimization direction flag */
+
+int glp_add_rows(glp_prob *P, int nrs);
+/* add new rows to problem object */
+
+int glp_add_cols(glp_prob *P, int ncs);
+/* add new columns to problem object */
+
+void glp_set_row_name(glp_prob *P, int i, const char *name);
+/* assign (change) row name */
+
+void glp_set_col_name(glp_prob *P, int j, const char *name);
+/* assign (change) column name */
+
+void glp_set_row_bnds(glp_prob *P, int i, int type, double lb,
+      double ub);
+/* set (change) row bounds */
+
+void glp_set_col_bnds(glp_prob *P, int j, int type, double lb,
+      double ub);
+/* set (change) column bounds */
+
+void glp_set_obj_coef(glp_prob *P, int j, double coef);
+/* set (change) obj. coefficient or constant term */
+
+void glp_set_mat_row(glp_prob *P, int i, int len, const int ind[],
+      const double val[]);
+/* set (replace) row of the constraint matrix */
+
+void glp_set_mat_col(glp_prob *P, int j, int len, const int ind[],
+      const double val[]);
+/* set (replace) column of the constraint matrix */
+
+void glp_load_matrix(glp_prob *P, int ne, const int ia[],
+      const int ja[], const double ar[]);
+/* load (replace) the whole constraint matrix */
+
+int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]);
+/* check for duplicate elements in sparse matrix */
+
+void glp_sort_matrix(glp_prob *P);
+/* sort elements of the constraint matrix */
+
+void glp_del_rows(glp_prob *P, int nrs, const int num[]);
+/* delete specified rows from problem object */
+
+void glp_del_cols(glp_prob *P, int ncs, const int num[]);
+/* delete specified columns from problem object */
+
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+/* copy problem object content */
+
+void glp_erase_prob(glp_prob *P);
+/* erase problem object content */
+
+void glp_delete_prob(glp_prob *P);
+/* delete problem object */
+
+const char *glp_get_prob_name(glp_prob *P);
+/* retrieve problem name */
+
+const char *glp_get_obj_name(glp_prob *P);
+/* retrieve objective function name */
+
+int glp_get_obj_dir(glp_prob *P);
+/* retrieve optimization direction flag */
+
+int glp_get_num_rows(glp_prob *P);
+/* retrieve number of rows */
+
+int glp_get_num_cols(glp_prob *P);
+/* retrieve number of columns */
+
+const char *glp_get_row_name(glp_prob *P, int i);
+/* retrieve row name */
+
+const char *glp_get_col_name(glp_prob *P, int j);
+/* retrieve column name */
+
+int glp_get_row_type(glp_prob *P, int i);
+/* retrieve row type */
+
+double glp_get_row_lb(glp_prob *P, int i);
+/* retrieve row lower bound */
+
+double glp_get_row_ub(glp_prob *P, int i);
+/* retrieve row upper bound */
+
+int glp_get_col_type(glp_prob *P, int j);
+/* retrieve column type */
+
+double glp_get_col_lb(glp_prob *P, int j);
+/* retrieve column lower bound */
+
+double glp_get_col_ub(glp_prob *P, int j);
+/* retrieve column upper bound */
+
+double glp_get_obj_coef(glp_prob *P, int j);
+/* retrieve obj. coefficient or constant term */
+
+int glp_get_num_nz(glp_prob *P);
+/* retrieve number of constraint coefficients */
+
+int glp_get_mat_row(glp_prob *P, int i, int ind[], double val[]);
+/* retrieve row of the constraint matrix */
+
+int glp_get_mat_col(glp_prob *P, int j, int ind[], double val[]);
+/* retrieve column of the constraint matrix */
+
+void glp_create_index(glp_prob *P);
+/* create the name index */
+
+int glp_find_row(glp_prob *P, const char *name);
+/* find row by its name */
+
+int glp_find_col(glp_prob *P, const char *name);
+/* find column by its name */
+
+void glp_delete_index(glp_prob *P);
+/* delete the name index */
+
+void glp_set_rii(glp_prob *P, int i, double rii);
+/* set (change) row scale factor */
+
+void glp_set_sjj(glp_prob *P, int j, double sjj);
+/* set (change) column scale factor */
+
+double glp_get_rii(glp_prob *P, int i);
+/* retrieve row scale factor */
+
+double glp_get_sjj(glp_prob *P, int j);
+/* retrieve column scale factor */
+
+void glp_scale_prob(glp_prob *P, int flags);
+/* scale problem data */
+
+void glp_unscale_prob(glp_prob *P);
+/* unscale problem data */
+
+void glp_set_row_stat(glp_prob *P, int i, int stat);
+/* set (change) row status */
+
+void glp_set_col_stat(glp_prob *P, int j, int stat);
+/* set (change) column status */
+
+void glp_std_basis(glp_prob *P);
+/* construct standard initial LP basis */
+
+void glp_adv_basis(glp_prob *P, int flags);
+/* construct advanced initial LP basis */
+
+void glp_cpx_basis(glp_prob *P);
+/* construct Bixby's initial LP basis */
+
+int glp_simplex(glp_prob *P, const glp_smcp *parm);
+/* solve LP problem with the simplex method */
+
+int glp_exact(glp_prob *P, const glp_smcp *parm);
+/* solve LP problem in exact arithmetic */
+
+void glp_init_smcp(glp_smcp *parm);
+/* initialize simplex method control parameters */
+
+int glp_get_status(glp_prob *P);
+/* retrieve generic status of basic solution */
+
+int glp_get_prim_stat(glp_prob *P);
+/* retrieve status of primal basic solution */
+
+int glp_get_dual_stat(glp_prob *P);
+/* retrieve status of dual basic solution */
+
+double glp_get_obj_val(glp_prob *P);
+/* retrieve objective value (basic solution) */
+
+int glp_get_row_stat(glp_prob *P, int i);
+/* retrieve row status */
+
+double glp_get_row_prim(glp_prob *P, int i);
+/* retrieve row primal value (basic solution) */
+
+double glp_get_row_dual(glp_prob *P, int i);
+/* retrieve row dual value (basic solution) */
+
+int glp_get_col_stat(glp_prob *P, int j);
+/* retrieve column status */
+
+double glp_get_col_prim(glp_prob *P, int j);
+/* retrieve column primal value (basic solution) */
+
+double glp_get_col_dual(glp_prob *P, int j);
+/* retrieve column dual value (basic solution) */
+
+int glp_get_unbnd_ray(glp_prob *P);
+/* determine variable causing unboundedness */
+
+int glp_interior(glp_prob *P, const glp_iptcp *parm);
+/* solve LP problem with the interior-point method */
+
+void glp_init_iptcp(glp_iptcp *parm);
+/* initialize interior-point solver control parameters */
+
+int glp_ipt_status(glp_prob *P);
+/* retrieve status of interior-point solution */
+
+double glp_ipt_obj_val(glp_prob *P);
+/* retrieve objective value (interior point) */
+
+double glp_ipt_row_prim(glp_prob *P, int i);
+/* retrieve row primal value (interior point) */
+
+double glp_ipt_row_dual(glp_prob *P, int i);
+/* retrieve row dual value (interior point) */
+
+double glp_ipt_col_prim(glp_prob *P, int j);
+/* retrieve column primal value (interior point) */
+
+double glp_ipt_col_dual(glp_prob *P, int j);
+/* retrieve column dual value (interior point) */
+
+void glp_set_col_kind(glp_prob *P, int j, int kind);
+/* set (change) column kind */
+
+int glp_get_col_kind(glp_prob *P, int j);
+/* retrieve column kind */
+
+int glp_get_num_int(glp_prob *P);
+/* retrieve number of integer columns */
+
+int glp_get_num_bin(glp_prob *P);
+/* retrieve number of binary columns */
+
+int glp_intopt(glp_prob *P, const glp_iocp *parm);
+/* solve MIP problem with the branch-and-bound method */
+
+void glp_init_iocp(glp_iocp *parm);
+/* initialize integer optimizer control parameters */
+
+int glp_mip_status(glp_prob *P);
+/* retrieve status of MIP solution */
+
+double glp_mip_obj_val(glp_prob *P);
+/* retrieve objective value (MIP solution) */
+
+double glp_mip_row_val(glp_prob *P, int i);
+/* retrieve row value (MIP solution) */
+
+double glp_mip_col_val(glp_prob *P, int j);
+/* retrieve column value (MIP solution) */
+
+int glp_print_sol(glp_prob *P, const char *fname);
+/* write basic solution in printable format */
+
+int glp_read_sol(glp_prob *P, const char *fname);
+/* read basic solution from text file */
+
+int glp_write_sol(glp_prob *P, const char *fname);
+/* write basic solution to text file */
+
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+      int flags, const char *fname);
+/* print sensitivity analysis report */
+
+int glp_print_ipt(glp_prob *P, const char *fname);
+/* write interior-point solution in printable format */
+
+int glp_read_ipt(glp_prob *P, const char *fname);
+/* read interior-point solution from text file */
+
+int glp_write_ipt(glp_prob *P, const char *fname);
+/* write interior-point solution to text file */
+
+int glp_print_mip(glp_prob *P, const char *fname);
+/* write MIP solution in printable format */
+
+int glp_read_mip(glp_prob *P, const char *fname);
+/* read MIP solution from text file */
+
+int glp_write_mip(glp_prob *P, const char *fname);
+/* write MIP solution to text file */
+
+int glp_bf_exists(glp_prob *P);
+/* check if the basis factorization exists */
+
+int glp_factorize(glp_prob *P);
+/* compute the basis factorization */
+
+int glp_bf_updated(glp_prob *P);
+/* check if the basis factorization has been updated */
+
+void glp_get_bfcp(glp_prob *P, glp_bfcp *parm);
+/* retrieve basis factorization control parameters */
+
+void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm);
+/* change basis factorization control parameters */
+
+int glp_get_bhead(glp_prob *P, int k);
+/* retrieve the basis header information */
+
+int glp_get_row_bind(glp_prob *P, int i);
+/* retrieve row index in the basis header */
+
+int glp_get_col_bind(glp_prob *P, int j);
+/* retrieve column index in the basis header */
+
+void glp_ftran(glp_prob *P, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+void glp_btran(glp_prob *P, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+int glp_warm_up(glp_prob *P);
+/* "warm up" LP basis */
+
+int glp_eval_tab_row(glp_prob *P, int k, int ind[], double val[]);
+/* compute row of the simplex tableau */
+
+int glp_eval_tab_col(glp_prob *P, int k, int ind[], double val[]);
+/* compute column of the simplex tableau */
+
+int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
+/* transform explicitly specified row */
+
+int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
+/* transform explicitly specified column */
+
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps);
+/* perform primal ratio test */
+
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps);
+/* perform dual ratio test */
+
+void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
+      double *value2, int *var2);
+/* analyze active bound of non-basic variable */
+
+void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+      double *value1, double *coef2, int *var2, double *value2);
+/* analyze objective coefficient at basic variable */
+
+int glp_ios_reason(glp_tree *T);
+/* determine reason for calling the callback routine */
+
+glp_prob *glp_ios_get_prob(glp_tree *T);
+/* access the problem object */
+
+void glp_ios_tree_size(glp_tree *T, int *a_cnt, int *n_cnt,
+      int *t_cnt);
+/* determine size of the branch-and-bound tree */
+
+int glp_ios_curr_node(glp_tree *T);
+/* determine current active subproblem */
+
+int glp_ios_next_node(glp_tree *T, int p);
+/* determine next active subproblem */
+
+int glp_ios_prev_node(glp_tree *T, int p);
+/* determine previous active subproblem */
+
+int glp_ios_up_node(glp_tree *T, int p);
+/* determine parent subproblem */
+
+int glp_ios_node_level(glp_tree *T, int p);
+/* determine subproblem level */
+
+double glp_ios_node_bound(glp_tree *T, int p);
+/* determine subproblem local bound */
+
+int glp_ios_best_node(glp_tree *T);
+/* find active subproblem with best local bound */
+
+double glp_ios_mip_gap(glp_tree *T);
+/* compute relative MIP gap */
+
+void *glp_ios_node_data(glp_tree *T, int p);
+/* access subproblem application-specific data */
+
+void glp_ios_row_attr(glp_tree *T, int i, glp_attr *attr);
+/* retrieve additional row attributes */
+
+int glp_ios_pool_size(glp_tree *T);
+/* determine current size of the cut pool */
+
+int glp_ios_add_row(glp_tree *T,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs);
+/* add row (constraint) to the cut pool */
+
+void glp_ios_del_row(glp_tree *T, int i);
+/* remove row (constraint) from the cut pool */
+
+void glp_ios_clear_pool(glp_tree *T);
+/* remove all rows (constraints) from the cut pool */
+
+int glp_ios_can_branch(glp_tree *T, int j);
+/* check if can branch upon specified variable */
+
+void glp_ios_branch_upon(glp_tree *T, int j, int sel);
+/* choose variable to branch upon */
+
+void glp_ios_select_node(glp_tree *T, int p);
+/* select subproblem to continue the search */
+
+int glp_ios_heur_sol(glp_tree *T, const double x[]);
+/* provide solution found by heuristic */
+
+void glp_ios_terminate(glp_tree *T);
+/* terminate the solution process */
+
+void glp_init_mpscp(glp_mpscp *parm);
+/* initialize MPS format control parameters */
+
+int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname);
+/* read problem data in MPS format */
+
+int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname);
+/* write problem data in MPS format */
+
+void glp_init_cpxcp(glp_cpxcp *parm);
+/* initialize CPLEX LP format control parameters */
+
+int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
+/* read problem data in CPLEX LP format */
+
+int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
+/* write problem data in CPLEX LP format */
+
+int glp_read_prob(glp_prob *P, int flags, const char *fname);
+/* read problem data in GLPK format */
+
+int glp_write_prob(glp_prob *P, int flags, const char *fname);
+/* write problem data in GLPK format */
+
+glp_tran *glp_mpl_alloc_wksp(void);
+/* allocate the MathProg translator workspace */
+
+int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip);
+/* read and translate model section */
+
+int glp_mpl_read_data(glp_tran *tran, const char *fname);
+/* read and translate data section */
+
+int glp_mpl_generate(glp_tran *tran, const char *fname);
+/* generate the model */
+
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
+/* build LP/MIP problem instance from the model */
+
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol);
+/* postsolve the model */
+
+void glp_mpl_free_wksp(glp_tran *tran);
+/* free the MathProg translator workspace */
+
+int glp_main(int argc, const char *argv[]);
+/* stand-alone LP/MIP solver */
+
+/**********************************************************************/
+
+#ifndef GLP_LONG_DEFINED
+#define GLP_LONG_DEFINED
+typedef struct { int lo, hi; } glp_long;
+/* long integer data type */
+#endif
+
+int glp_init_env(void);
+/* initialize GLPK environment */
+
+const char *glp_version(void);
+/* determine library version */
+
+int glp_free_env(void);
+/* free GLPK environment */
+
+void glp_printf(const char *fmt, ...);
+/* write formatted output to terminal */
+
+void glp_vprintf(const char *fmt, va_list arg);
+/* write formatted output to terminal */
+
+int glp_term_out(int flag);
+/* enable/disable terminal output */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info);
+/* install hook to intercept terminal output */
+
+int glp_open_tee(const char *fname);
+/* start copying terminal output to text file */
+
+int glp_close_tee(void);
+/* stop copying terminal output to text file */
+
+#ifndef GLP_ERROR_DEFINED
+#define GLP_ERROR_DEFINED
+typedef void (*_glp_error)(const char *fmt, ...);
+#endif
+
+#define glp_error glp_error_(__FILE__, __LINE__)
+_glp_error glp_error_(const char *file, int line);
+/* display error message and terminate execution */
+
+#define glp_assert(expr) \
+      ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
+void glp_assert_(const char *expr, const char *file, int line);
+/* check for logical condition */
+
+void glp_error_hook(void (*func)(void *info), void *info);
+/* install hook to intercept abnormal termination */
+
+void *glp_malloc(int size);
+/* allocate memory block */
+
+void *glp_calloc(int n, int size);
+/* allocate memory block */
+
+void glp_free(void *ptr);
+/* free memory block */
+
+void glp_mem_limit(int limit);
+/* set memory usage limit */
+
+void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+      glp_long *tpeak);
+/* get memory usage information */
+
+glp_long glp_time(void);
+/* determine current universal time */
+
+double glp_difftime(glp_long t1, glp_long t0);
+/* compute difference between two time values */
+
+/**********************************************************************/
+
+#ifndef GLP_DATA_DEFINED
+#define GLP_DATA_DEFINED
+typedef struct { double _opaque_data[100]; } glp_data;
+/* plain data file */
+#endif
+
+glp_data *glp_sdf_open_file(const char *fname);
+/* open plain data file */
+
+void glp_sdf_set_jump(glp_data *data, void *jump);
+/* set up error handling */
+
+void glp_sdf_error(glp_data *data, const char *fmt, ...);
+/* print error message */
+
+void glp_sdf_warning(glp_data *data, const char *fmt, ...);
+/* print warning message */
+
+int glp_sdf_read_int(glp_data *data);
+/* read integer number */
+
+double glp_sdf_read_num(glp_data *data);
+/* read floating-point number */
+
+const char *glp_sdf_read_item(glp_data *data);
+/* read data item */
+
+const char *glp_sdf_read_text(glp_data *data);
+/* read text until end of line */
+
+int glp_sdf_line(glp_data *data);
+/* determine current line number */
+
+void glp_sdf_close_file(glp_data *data);
+/* close plain data file */
+
+/**********************************************************************/
+
+typedef struct _glp_graph glp_graph;
+typedef struct _glp_vertex glp_vertex;
+typedef struct _glp_arc glp_arc;
+
+struct _glp_graph
+{     /* graph descriptor */
+      void *pool; /* DMP *pool; */
+      /* memory pool to store graph components */
+      char *name;
+      /* graph name (1 to 255 chars); NULL means no name is assigned
+         to the graph */
+      int nv_max;
+      /* length of the vertex list (enlarged automatically) */
+      int nv;
+      /* number of vertices in the graph, 0 <= nv <= nv_max */
+      int na;
+      /* number of arcs in the graph, na >= 0 */
+      glp_vertex **v; /* glp_vertex *v[1+nv_max]; */
+      /* v[i], 1 <= i <= nv, is a pointer to i-th vertex */
+      void *index; /* AVL *index; */
+      /* vertex index to find vertices by their names; NULL means the
+         index does not exist */
+      int v_size;
+      /* size of data associated with each vertex (0 to 256 bytes) */
+      int a_size;
+      /* size of data associated with each arc (0 to 256 bytes) */
+};
+
+struct _glp_vertex
+{     /* vertex descriptor */
+      int i;
+      /* vertex ordinal number, 1 <= i <= nv */
+      char *name;
+      /* vertex name (1 to 255 chars); NULL means no name is assigned
+         to the vertex */
+      void *entry; /* AVLNODE *entry; */
+      /* pointer to corresponding entry in the vertex index; NULL means
+         that either the index does not exist or the vertex has no name
+         assigned */
+      void *data;
+      /* pointer to data associated with the vertex */
+      void *temp;
+      /* working pointer */
+      glp_arc *in;
+      /* pointer to the (unordered) list of incoming arcs */
+      glp_arc *out;
+      /* pointer to the (unordered) list of outgoing arcs */
+};
+
+struct _glp_arc
+{     /* arc descriptor */
+      glp_vertex *tail;
+      /* pointer to the tail endpoint */
+      glp_vertex *head;
+      /* pointer to the head endpoint */
+      void *data;
+      /* pointer to data associated with the arc */
+      void *temp;
+      /* working pointer */
+      glp_arc *t_prev;
+      /* pointer to previous arc having the same tail endpoint */
+      glp_arc *t_next;
+      /* pointer to next arc having the same tail endpoint */
+      glp_arc *h_prev;
+      /* pointer to previous arc having the same head endpoint */
+      glp_arc *h_next;
+      /* pointer to next arc having the same head endpoint */
+};
+
+glp_graph *glp_create_graph(int v_size, int a_size);
+/* create graph */
+
+void glp_set_graph_name(glp_graph *G, const char *name);
+/* assign (change) graph name */
+
+int glp_add_vertices(glp_graph *G, int nadd);
+/* add new vertices to graph */
+
+void glp_set_vertex_name(glp_graph *G, int i, const char *name);
+/* assign (change) vertex name */
+
+glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+/* add new arc to graph */
+
+void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+/* delete vertices from graph */
+
+void glp_del_arc(glp_graph *G, glp_arc *a);
+/* delete arc from graph */
+
+void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+/* erase graph content */
+
+void glp_delete_graph(glp_graph *G);
+/* delete graph */
+
+void glp_create_v_index(glp_graph *G);
+/* create vertex name index */
+
+int glp_find_vertex(glp_graph *G, const char *name);
+/* find vertex by its name */
+
+void glp_delete_v_index(glp_graph *G);
+/* delete vertex name index */
+
+int glp_read_graph(glp_graph *G, const char *fname);
+/* read graph from plain text file */
+
+int glp_write_graph(glp_graph *G, const char *fname);
+/* write graph to plain text file */
+
+void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs,
+      int a_low, int a_cap, int a_cost);
+/* convert minimum cost flow problem to LP */
+
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, double *sol, int a_x, int v_pi);
+/* find minimum-cost flow with out-of-kilter algorithm */
+
+void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s,
+      int t, int a_cap);
+/* convert maximum flow problem to LP */
+
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+      double *sol, int a_x, int v_cut);
+/* find maximal flow with Ford-Fulkerson algorithm */
+
+int glp_check_asnprob(glp_graph *G, int v_set);
+/* check correctness of assignment problem data */
+
+/* assignment problem formulation: */
+#define GLP_ASN_MIN        1  /* perfect matching (minimization) */
+#define GLP_ASN_MAX        2  /* perfect matching (maximization) */
+#define GLP_ASN_MMP        3  /* maximum matching */
+
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+      int v_set, int a_cost);
+/* convert assignment problem to LP */
+
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
+      double *sol, int a_x);
+/* solve assignment problem with out-of-kilter algorithm */
+
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+/* find bipartite matching of maximum cardinality */
+
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+/* solve critical path problem */
+
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname);
+/* read min-cost flow problem data in DIMACS format */
+
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname);
+/* write min-cost flow problem data in DIMACS format */
+
+int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+      const char *fname);
+/* read maximum flow problem data in DIMACS format */
+
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+      const char *fname);
+/* write maximum flow problem data in DIMACS format */
+
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname);
+/* read assignment problem data in DIMACS format */
+
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname);
+/* write assignment problem data in DIMACS format */
+
+int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
+/* read graph in DIMACS clique/coloring format */
+
+int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
+/* write graph in DIMACS clique/coloring format */
+
+int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+      const int parm[1+15]);
+/* Klingman's network problem generator */
+
+int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+      const int parm[1+14]);
+/* grid-like network problem generator */
+
+int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+      const int parm[1+5]);
+/* Goldfarb's maximum flow problem generator */
+
+int glp_weak_comp(glp_graph *G, int v_num);
+/* find all weakly connected components of graph */
+
+int glp_strong_comp(glp_graph *G, int v_num);
+/* find all strongly connected components of graph */
+
+int glp_top_sort(glp_graph *G, int v_num);
+/* topological sorting of acyclic digraph */
+
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set);
+/* find maximum weight clique with exact algorithm */
+
+/***********************************************************************
+*  NOTE: All symbols defined below are obsolete and kept here only for
+*        backward compatibility.
+***********************************************************************/
+
+#define LPX glp_prob
+
+/* problem class: */
+#define LPX_LP          100   /* linear programming (LP) */
+#define LPX_MIP         101   /* mixed integer programming (MIP) */
+
+/* type of auxiliary/structural variable: */
+#define LPX_FR          110   /* free variable */
+#define LPX_LO          111   /* variable with lower bound */
+#define LPX_UP          112   /* variable with upper bound */
+#define LPX_DB          113   /* double-bounded variable */
+#define LPX_FX          114   /* fixed variable */
+
+/* optimization direction flag: */
+#define LPX_MIN         120   /* minimization */
+#define LPX_MAX         121   /* maximization */
+
+/* status of primal basic solution: */
+#define LPX_P_UNDEF     132   /* primal solution is undefined */
+#define LPX_P_FEAS      133   /* solution is primal feasible */
+#define LPX_P_INFEAS    134   /* solution is primal infeasible */
+#define LPX_P_NOFEAS    135   /* no primal feasible solution exists */
+
+/* status of dual basic solution: */
+#define LPX_D_UNDEF     136   /* dual solution is undefined */
+#define LPX_D_FEAS      137   /* solution is dual feasible */
+#define LPX_D_INFEAS    138   /* solution is dual infeasible */
+#define LPX_D_NOFEAS    139   /* no dual feasible solution exists */
+
+/* status of auxiliary/structural variable: */
+#define LPX_BS          140   /* basic variable */
+#define LPX_NL          141   /* non-basic variable on lower bound */
+#define LPX_NU          142   /* non-basic variable on upper bound */
+#define LPX_NF          143   /* non-basic free variable */
+#define LPX_NS          144   /* non-basic fixed variable */
+
+/* status of interior-point solution: */
+#define LPX_T_UNDEF     150   /* interior solution is undefined */
+#define LPX_T_OPT       151   /* interior solution is optimal */
+
+/* kind of structural variable: */
+#define LPX_CV          160   /* continuous variable */
+#define LPX_IV          161   /* integer variable */
+
+/* status of integer solution: */
+#define LPX_I_UNDEF     170   /* integer solution is undefined */
+#define LPX_I_OPT       171   /* integer solution is optimal */
+#define LPX_I_FEAS      172   /* integer solution is feasible */
+#define LPX_I_NOFEAS    173   /* no integer solution exists */
+
+/* status codes reported by the routine lpx_get_status: */
+#define LPX_OPT         180   /* optimal */
+#define LPX_FEAS        181   /* feasible */
+#define LPX_INFEAS      182   /* infeasible */
+#define LPX_NOFEAS      183   /* no feasible */
+#define LPX_UNBND       184   /* unbounded */
+#define LPX_UNDEF       185   /* undefined */
+
+/* exit codes returned by solver routines: */
+#define LPX_E_OK        200   /* success */
+#define LPX_E_EMPTY     201   /* empty problem */
+#define LPX_E_BADB      202   /* invalid initial basis */
+#define LPX_E_INFEAS    203   /* infeasible initial solution */
+#define LPX_E_FAULT     204   /* unable to start the search */
+#define LPX_E_OBJLL     205   /* objective lower limit reached */
+#define LPX_E_OBJUL     206   /* objective upper limit reached */
+#define LPX_E_ITLIM     207   /* iterations limit exhausted */
+#define LPX_E_TMLIM     208   /* time limit exhausted */
+#define LPX_E_NOFEAS    209   /* no feasible solution */
+#define LPX_E_INSTAB    210   /* numerical instability */
+#define LPX_E_SING      211   /* problems with basis matrix */
+#define LPX_E_NOCONV    212   /* no convergence (interior) */
+#define LPX_E_NOPFS     213   /* no primal feas. sol. (LP presolver) */
+#define LPX_E_NODFS     214   /* no dual feas. sol. (LP presolver) */
+#define LPX_E_MIPGAP    215   /* relative mip gap tolerance reached */
+
+/* control parameter identifiers: */
+#define LPX_K_MSGLEV    300   /* lp->msg_lev */
+#define LPX_K_SCALE     301   /* lp->scale */
+#define LPX_K_DUAL      302   /* lp->dual */
+#define LPX_K_PRICE     303   /* lp->price */
+#define LPX_K_RELAX     304   /* lp->relax */
+#define LPX_K_TOLBND    305   /* lp->tol_bnd */
+#define LPX_K_TOLDJ     306   /* lp->tol_dj */
+#define LPX_K_TOLPIV    307   /* lp->tol_piv */
+#define LPX_K_ROUND     308   /* lp->round */
+#define LPX_K_OBJLL     309   /* lp->obj_ll */
+#define LPX_K_OBJUL     310   /* lp->obj_ul */
+#define LPX_K_ITLIM     311   /* lp->it_lim */
+#define LPX_K_ITCNT     312   /* lp->it_cnt */
+#define LPX_K_TMLIM     313   /* lp->tm_lim */
+#define LPX_K_OUTFRQ    314   /* lp->out_frq */
+#define LPX_K_OUTDLY    315   /* lp->out_dly */
+#define LPX_K_BRANCH    316   /* lp->branch */
+#define LPX_K_BTRACK    317   /* lp->btrack */
+#define LPX_K_TOLINT    318   /* lp->tol_int */
+#define LPX_K_TOLOBJ    319   /* lp->tol_obj */
+#define LPX_K_MPSINFO   320   /* lp->mps_info */
+#define LPX_K_MPSOBJ    321   /* lp->mps_obj */
+#define LPX_K_MPSORIG   322   /* lp->mps_orig */
+#define LPX_K_MPSWIDE   323   /* lp->mps_wide */
+#define LPX_K_MPSFREE   324   /* lp->mps_free */
+#define LPX_K_MPSSKIP   325   /* lp->mps_skip */
+#define LPX_K_LPTORIG   326   /* lp->lpt_orig */
+#define LPX_K_PRESOL    327   /* lp->presol */
+#define LPX_K_BINARIZE  328   /* lp->binarize */
+#define LPX_K_USECUTS   329   /* lp->use_cuts */
+#define LPX_K_BFTYPE    330   /* lp->bfcp->type */
+#define LPX_K_MIPGAP    331   /* lp->mip_gap */
+
+#define LPX_C_COVER     0x01  /* mixed cover cuts */
+#define LPX_C_CLIQUE    0x02  /* clique cuts */
+#define LPX_C_GOMORY    0x04  /* Gomory's mixed integer cuts */
+#define LPX_C_MIR       0x08  /* mixed integer rounding cuts */
+#define LPX_C_ALL       0xFF  /* all cuts */
+
+typedef struct
+{     /* this structure contains results reported by the routines which
+         checks Karush-Kuhn-Tucker conditions (for details see comments
+         to those routines) */
+      /*--------------------------------------------------------------*/
+      /* xR - A * xS = 0 (KKT.PE) */
+      double pe_ae_max;
+      /* largest absolute error */
+      int    pe_ae_row;
+      /* number of row with largest absolute error */
+      double pe_re_max;
+      /* largest relative error */
+      int    pe_re_row;
+      /* number of row with largest relative error */
+      int    pe_quality;
+      /* quality of primal solution:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - primal solution is wrong */
+      /*--------------------------------------------------------------*/
+      /* l[k] <= x[k] <= u[k] (KKT.PB) */
+      double pb_ae_max;
+      /* largest absolute error */
+      int    pb_ae_ind;
+      /* number of variable with largest absolute error */
+      double pb_re_max;
+      /* largest relative error */
+      int    pb_re_ind;
+      /* number of variable with largest relative error */
+      int    pb_quality;
+      /* quality of primal feasibility:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - primal solution is infeasible */
+      /*--------------------------------------------------------------*/
+      /* A' * (dR - cR) + (dS - cS) = 0 (KKT.DE) */
+      double de_ae_max;
+      /* largest absolute error */
+      int    de_ae_col;
+      /* number of column with largest absolute error */
+      double de_re_max;
+      /* largest relative error */
+      int    de_re_col;
+      /* number of column with largest relative error */
+      int    de_quality;
+      /* quality of dual solution:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - dual solution is wrong */
+      /*--------------------------------------------------------------*/
+      /* d[k] >= 0 or d[k] <= 0 (KKT.DB) */
+      double db_ae_max;
+      /* largest absolute error */
+      int    db_ae_ind;
+      /* number of variable with largest absolute error */
+      double db_re_max;
+      /* largest relative error */
+      int    db_re_ind;
+      /* number of variable with largest relative error */
+      int    db_quality;
+      /* quality of dual feasibility:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - dual solution is infeasible */
+      /*--------------------------------------------------------------*/
+      /* (x[k] - bound of x[k]) * d[k] = 0 (KKT.CS) */
+      double cs_ae_max;
+      /* largest absolute error */
+      int    cs_ae_ind;
+      /* number of variable with largest absolute error */
+      double cs_re_max;
+      /* largest relative error */
+      int    cs_re_ind;
+      /* number of variable with largest relative error */
+      int    cs_quality;
+      /* quality of complementary slackness:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - primal and dual solutions are not complementary */
+} LPXKKT;
+
+#define lpx_create_prob _glp_lpx_create_prob
+LPX *lpx_create_prob(void);
+/* create problem object */
+
+#define lpx_set_prob_name _glp_lpx_set_prob_name
+void lpx_set_prob_name(LPX *lp, const char *name);
+/* assign (change) problem name */
+
+#define lpx_set_obj_name _glp_lpx_set_obj_name
+void lpx_set_obj_name(LPX *lp, const char *name);
+/* assign (change) objective function name */
+
+#define lpx_set_obj_dir _glp_lpx_set_obj_dir
+void lpx_set_obj_dir(LPX *lp, int dir);
+/* set (change) optimization direction flag */
+
+#define lpx_add_rows _glp_lpx_add_rows
+int lpx_add_rows(LPX *lp, int nrs);
+/* add new rows to problem object */
+
+#define lpx_add_cols _glp_lpx_add_cols
+int lpx_add_cols(LPX *lp, int ncs);
+/* add new columns to problem object */
+
+#define lpx_set_row_name _glp_lpx_set_row_name
+void lpx_set_row_name(LPX *lp, int i, const char *name);
+/* assign (change) row name */
+
+#define lpx_set_col_name _glp_lpx_set_col_name
+void lpx_set_col_name(LPX *lp, int j, const char *name);
+/* assign (change) column name */
+
+#define lpx_set_row_bnds _glp_lpx_set_row_bnds
+void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub);
+/* set (change) row bounds */
+
+#define lpx_set_col_bnds _glp_lpx_set_col_bnds
+void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub);
+/* set (change) column bounds */
+
+#define lpx_set_obj_coef _glp_lpx_set_obj_coef
+void lpx_set_obj_coef(glp_prob *lp, int j, double coef);
+/* set (change) obj. coefficient or constant term */
+
+#define lpx_set_mat_row _glp_lpx_set_mat_row
+void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
+      const double val[]);
+/* set (replace) row of the constraint matrix */
+
+#define lpx_set_mat_col _glp_lpx_set_mat_col
+void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
+      const double val[]);
+/* set (replace) column of the constraint matrix */
+
+#define lpx_load_matrix _glp_lpx_load_matrix
+void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
+      const double ar[]);
+/* load (replace) the whole constraint matrix */
+
+#define lpx_del_rows _glp_lpx_del_rows
+void lpx_del_rows(LPX *lp, int nrs, const int num[]);
+/* delete specified rows from problem object */
+
+#define lpx_del_cols _glp_lpx_del_cols
+void lpx_del_cols(LPX *lp, int ncs, const int num[]);
+/* delete specified columns from problem object */
+
+#define lpx_delete_prob _glp_lpx_delete_prob
+void lpx_delete_prob(LPX *lp);
+/* delete problem object */
+
+#define lpx_get_prob_name _glp_lpx_get_prob_name
+const char *lpx_get_prob_name(LPX *lp);
+/* retrieve problem name */
+
+#define lpx_get_obj_name _glp_lpx_get_obj_name
+const char *lpx_get_obj_name(LPX *lp);
+/* retrieve objective function name */
+
+#define lpx_get_obj_dir _glp_lpx_get_obj_dir
+int lpx_get_obj_dir(LPX *lp);
+/* retrieve optimization direction flag */
+
+#define lpx_get_num_rows _glp_lpx_get_num_rows
+int lpx_get_num_rows(LPX *lp);
+/* retrieve number of rows */
+
+#define lpx_get_num_cols _glp_lpx_get_num_cols
+int lpx_get_num_cols(LPX *lp);
+/* retrieve number of columns */
+
+#define lpx_get_row_name _glp_lpx_get_row_name
+const char *lpx_get_row_name(LPX *lp, int i);
+/* retrieve row name */
+
+#define lpx_get_col_name _glp_lpx_get_col_name
+const char *lpx_get_col_name(LPX *lp, int j);
+/* retrieve column name */
+
+#define lpx_get_row_type _glp_lpx_get_row_type
+int lpx_get_row_type(LPX *lp, int i);
+/* retrieve row type */
+
+#define lpx_get_row_lb _glp_lpx_get_row_lb
+double lpx_get_row_lb(LPX *lp, int i);
+/* retrieve row lower bound */
+
+#define lpx_get_row_ub _glp_lpx_get_row_ub
+double lpx_get_row_ub(LPX *lp, int i);
+/* retrieve row upper bound */
+
+#define lpx_get_row_bnds _glp_lpx_get_row_bnds
+void lpx_get_row_bnds(LPX *lp, int i, int *typx, double *lb,
+      double *ub);
+/* retrieve row bounds */
+
+#define lpx_get_col_type _glp_lpx_get_col_type
+int lpx_get_col_type(LPX *lp, int j);
+/* retrieve column type */
+
+#define lpx_get_col_lb _glp_lpx_get_col_lb
+double lpx_get_col_lb(LPX *lp, int j);
+/* retrieve column lower bound */
+
+#define lpx_get_col_ub _glp_lpx_get_col_ub
+double lpx_get_col_ub(LPX *lp, int j);
+/* retrieve column upper bound */
+
+#define lpx_get_col_bnds _glp_lpx_get_col_bnds
+void lpx_get_col_bnds(LPX *lp, int j, int *typx, double *lb,
+      double *ub);
+/* retrieve column bounds */
+
+#define lpx_get_obj_coef _glp_lpx_get_obj_coef
+double lpx_get_obj_coef(LPX *lp, int j);
+/* retrieve obj. coefficient or constant term */
+
+#define lpx_get_num_nz _glp_lpx_get_num_nz
+int lpx_get_num_nz(LPX *lp);
+/* retrieve number of constraint coefficients */
+
+#define lpx_get_mat_row _glp_lpx_get_mat_row
+int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[]);
+/* retrieve row of the constraint matrix */
+
+#define lpx_get_mat_col _glp_lpx_get_mat_col
+int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[]);
+/* retrieve column of the constraint matrix */
+
+#define lpx_create_index _glp_lpx_create_index
+void lpx_create_index(LPX *lp);
+/* create the name index */
+
+#define lpx_find_row _glp_lpx_find_row
+int lpx_find_row(LPX *lp, const char *name);
+/* find row by its name */
+
+#define lpx_find_col _glp_lpx_find_col
+int lpx_find_col(LPX *lp, const char *name);
+/* find column by its name */
+
+#define lpx_delete_index _glp_lpx_delete_index
+void lpx_delete_index(LPX *lp);
+/* delete the name index */
+
+#define lpx_scale_prob _glp_lpx_scale_prob
+void lpx_scale_prob(LPX *lp);
+/* scale problem data */
+
+#define lpx_unscale_prob _glp_lpx_unscale_prob
+void lpx_unscale_prob(LPX *lp);
+/* unscale problem data */
+
+#define lpx_set_row_stat _glp_lpx_set_row_stat
+void lpx_set_row_stat(LPX *lp, int i, int stat);
+/* set (change) row status */
+
+#define lpx_set_col_stat _glp_lpx_set_col_stat
+void lpx_set_col_stat(LPX *lp, int j, int stat);
+/* set (change) column status */
+
+#define lpx_std_basis _glp_lpx_std_basis
+void lpx_std_basis(LPX *lp);
+/* construct standard initial LP basis */
+
+#define lpx_adv_basis _glp_lpx_adv_basis
+void lpx_adv_basis(LPX *lp);
+/* construct advanced initial LP basis */
+
+#define lpx_cpx_basis _glp_lpx_cpx_basis
+void lpx_cpx_basis(LPX *lp);
+/* construct Bixby's initial LP basis */
+
+#define lpx_simplex _glp_lpx_simplex
+int lpx_simplex(LPX *lp);
+/* easy-to-use driver to the simplex method */
+
+#define lpx_exact _glp_lpx_exact
+int lpx_exact(LPX *lp);
+/* easy-to-use driver to the exact simplex method */
+
+#define lpx_get_status _glp_lpx_get_status
+int lpx_get_status(LPX *lp);
+/* retrieve generic status of basic solution */
+
+#define lpx_get_prim_stat _glp_lpx_get_prim_stat
+int lpx_get_prim_stat(LPX *lp);
+/* retrieve primal status of basic solution */
+
+#define lpx_get_dual_stat _glp_lpx_get_dual_stat
+int lpx_get_dual_stat(LPX *lp);
+/* retrieve dual status of basic solution */
+
+#define lpx_get_obj_val _glp_lpx_get_obj_val
+double lpx_get_obj_val(LPX *lp);
+/* retrieve objective value (basic solution) */
+
+#define lpx_get_row_stat _glp_lpx_get_row_stat
+int lpx_get_row_stat(LPX *lp, int i);
+/* retrieve row status (basic solution) */
+
+#define lpx_get_row_prim _glp_lpx_get_row_prim
+double lpx_get_row_prim(LPX *lp, int i);
+/* retrieve row primal value (basic solution) */
+
+#define lpx_get_row_dual _glp_lpx_get_row_dual
+double lpx_get_row_dual(LPX *lp, int i);
+/* retrieve row dual value (basic solution) */
+
+#define lpx_get_row_info _glp_lpx_get_row_info
+void lpx_get_row_info(LPX *lp, int i, int *tagx, double *vx,
+      double *dx);
+/* obtain row solution information */
+
+#define lpx_get_col_stat _glp_lpx_get_col_stat
+int lpx_get_col_stat(LPX *lp, int j);
+/* retrieve column status (basic solution) */
+
+#define lpx_get_col_prim _glp_lpx_get_col_prim
+double lpx_get_col_prim(LPX *lp, int j);
+/* retrieve column primal value (basic solution) */
+
+#define lpx_get_col_dual _glp_lpx_get_col_dual
+double lpx_get_col_dual(glp_prob *lp, int j);
+/* retrieve column dual value (basic solution) */
+
+#define lpx_get_col_info _glp_lpx_get_col_info
+void lpx_get_col_info(LPX *lp, int j, int *tagx, double *vx,
+      double *dx);
+/* obtain column solution information (obsolete) */
+
+#define lpx_get_ray_info _glp_lpx_get_ray_info
+int lpx_get_ray_info(LPX *lp);
+/* determine what causes primal unboundness */
+
+#define lpx_check_kkt _glp_lpx_check_kkt
+void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt);
+/* check Karush-Kuhn-Tucker conditions */
+
+#define lpx_warm_up _glp_lpx_warm_up
+int lpx_warm_up(LPX *lp);
+/* "warm up" LP basis */
+
+#define lpx_eval_tab_row _glp_lpx_eval_tab_row
+int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[]);
+/* compute row of the simplex table */
+
+#define lpx_eval_tab_col _glp_lpx_eval_tab_col
+int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[]);
+/* compute column of the simplex table */
+
+#define lpx_transform_row _glp_lpx_transform_row
+int lpx_transform_row(LPX *lp, int len, int ind[], double val[]);
+/* transform explicitly specified row */
+
+#define lpx_transform_col _glp_lpx_transform_col
+int lpx_transform_col(LPX *lp, int len, int ind[], double val[]);
+/* transform explicitly specified column */
+
+#define lpx_prim_ratio_test _glp_lpx_prim_ratio_test
+int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol);
+/* perform primal ratio test */
+
+#define lpx_dual_ratio_test _glp_lpx_dual_ratio_test
+int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol);
+/* perform dual ratio test */
+
+#define lpx_interior _glp_lpx_interior
+int lpx_interior(LPX *lp);
+/* easy-to-use driver to the interior point method */
+
+#define lpx_ipt_status _glp_lpx_ipt_status
+int lpx_ipt_status(LPX *lp);
+/* retrieve status of interior-point solution */
+
+#define lpx_ipt_obj_val _glp_lpx_ipt_obj_val
+double lpx_ipt_obj_val(LPX *lp);
+/* retrieve objective value (interior point) */
+
+#define lpx_ipt_row_prim _glp_lpx_ipt_row_prim
+double lpx_ipt_row_prim(LPX *lp, int i);
+/* retrieve row primal value (interior point) */
+
+#define lpx_ipt_row_dual _glp_lpx_ipt_row_dual
+double lpx_ipt_row_dual(LPX *lp, int i);
+/* retrieve row dual value (interior point) */
+
+#define lpx_ipt_col_prim _glp_lpx_ipt_col_prim
+double lpx_ipt_col_prim(LPX *lp, int j);
+/* retrieve column primal value (interior point) */
+
+#define lpx_ipt_col_dual _glp_lpx_ipt_col_dual
+double lpx_ipt_col_dual(LPX *lp, int j);
+/* retrieve column dual value (interior point) */
+
+#define lpx_set_class _glp_lpx_set_class
+void lpx_set_class(LPX *lp, int klass);
+/* set problem class */
+
+#define lpx_get_class _glp_lpx_get_class
+int lpx_get_class(LPX *lp);
+/* determine problem klass */
+
+#define lpx_set_col_kind _glp_lpx_set_col_kind
+void lpx_set_col_kind(LPX *lp, int j, int kind);
+/* set (change) column kind */
+
+#define lpx_get_col_kind _glp_lpx_get_col_kind
+int lpx_get_col_kind(LPX *lp, int j);
+/* retrieve column kind */
+
+#define lpx_get_num_int _glp_lpx_get_num_int
+int lpx_get_num_int(LPX *lp);
+/* retrieve number of integer columns */
+
+#define lpx_get_num_bin _glp_lpx_get_num_bin
+int lpx_get_num_bin(LPX *lp);
+/* retrieve number of binary columns */
+
+#define lpx_integer _glp_lpx_integer
+int lpx_integer(LPX *lp);
+/* easy-to-use driver to the branch-and-bound method */
+
+#define lpx_intopt _glp_lpx_intopt
+int lpx_intopt(LPX *lp);
+/* easy-to-use driver to the branch-and-bound method */
+
+#define lpx_mip_status _glp_lpx_mip_status
+int lpx_mip_status(LPX *lp);
+/* retrieve status of MIP solution */
+
+#define lpx_mip_obj_val _glp_lpx_mip_obj_val
+double lpx_mip_obj_val(LPX *lp);
+/* retrieve objective value (MIP solution) */
+
+#define lpx_mip_row_val _glp_lpx_mip_row_val
+double lpx_mip_row_val(LPX *lp, int i);
+/* retrieve row value (MIP solution) */
+
+#define lpx_mip_col_val _glp_lpx_mip_col_val
+double lpx_mip_col_val(LPX *lp, int j);
+/* retrieve column value (MIP solution) */
+
+#define lpx_check_int _glp_lpx_check_int
+void lpx_check_int(LPX *lp, LPXKKT *kkt);
+/* check integer feasibility conditions */
+
+#define lpx_reset_parms _glp_lpx_reset_parms
+void lpx_reset_parms(LPX *lp);
+/* reset control parameters to default values */
+
+#define lpx_set_int_parm _glp_lpx_set_int_parm
+void lpx_set_int_parm(LPX *lp, int parm, int val);
+/* set (change) integer control parameter */
+
+#define lpx_get_int_parm _glp_lpx_get_int_parm
+int lpx_get_int_parm(LPX *lp, int parm);
+/* query integer control parameter */
+
+#define lpx_set_real_parm _glp_lpx_set_real_parm
+void lpx_set_real_parm(LPX *lp, int parm, double val);
+/* set (change) real control parameter */
+
+#define lpx_get_real_parm _glp_lpx_get_real_parm
+double lpx_get_real_parm(LPX *lp, int parm);
+/* query real control parameter */
+
+#define lpx_read_mps _glp_lpx_read_mps
+LPX *lpx_read_mps(const char *fname);
+/* read problem data in fixed MPS format */
+
+#define lpx_write_mps _glp_lpx_write_mps
+int lpx_write_mps(LPX *lp, const char *fname);
+/* write problem data in fixed MPS format */
+
+#define lpx_read_bas _glp_lpx_read_bas
+int lpx_read_bas(LPX *lp, const char *fname);
+/* read LP basis in fixed MPS format */
+
+#define lpx_write_bas _glp_lpx_write_bas
+int lpx_write_bas(LPX *lp, const char *fname);
+/* write LP basis in fixed MPS format */
+
+#define lpx_read_freemps _glp_lpx_read_freemps
+LPX *lpx_read_freemps(const char *fname);
+/* read problem data in free MPS format */
+
+#define lpx_write_freemps _glp_lpx_write_freemps
+int lpx_write_freemps(LPX *lp, const char *fname);
+/* write problem data in free MPS format */
+
+#define lpx_read_cpxlp _glp_lpx_read_cpxlp
+LPX *lpx_read_cpxlp(const char *fname);
+/* read problem data in CPLEX LP format */
+
+#define lpx_write_cpxlp _glp_lpx_write_cpxlp
+int lpx_write_cpxlp(LPX *lp, const char *fname);
+/* write problem data in CPLEX LP format */
+
+#define lpx_read_model _glp_lpx_read_model
+LPX *lpx_read_model(const char *model, const char *data,
+      const char *output);
+/* read LP/MIP model written in GNU MathProg language */
+
+#define lpx_print_prob _glp_lpx_print_prob
+int lpx_print_prob(LPX *lp, const char *fname);
+/* write problem data in plain text format */
+
+#define lpx_print_sol _glp_lpx_print_sol
+int lpx_print_sol(LPX *lp, const char *fname);
+/* write LP problem solution in printable format */
+
+#define lpx_print_sens_bnds _glp_lpx_print_sens_bnds
+int lpx_print_sens_bnds(LPX *lp, const char *fname);
+/* write bounds sensitivity information */
+
+#define lpx_print_ips _glp_lpx_print_ips
+int lpx_print_ips(LPX *lp, const char *fname);
+/* write interior point solution in printable format */
+
+#define lpx_print_mip _glp_lpx_print_mip
+int lpx_print_mip(LPX *lp, const char *fname);
+/* write MIP problem solution in printable format */
+
+#define lpx_is_b_avail _glp_lpx_is_b_avail
+int lpx_is_b_avail(LPX *lp);
+/* check if LP basis is available */
+
+#define lpx_write_pb _glp_lpx_write_pb
+int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+      int binarize);
+/* write problem data in (normalized) OPB format */
+
+#define lpx_main _glp_lpx_main
+int lpx_main(int argc, const char *argv[]);
+/* stand-alone LP/MIP solver */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpk.inc b/optional/glpk/glpk.inc
new file mode 100644
index 0000000..7a48b81
--- /dev/null
+++ b/optional/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/optional/glpk/glplib.h b/optional/glpk/glplib.h
new file mode 100644
index 0000000..9874f8e
--- /dev/null
+++ b/optional/glpk/glplib.h
@@ -0,0 +1,135 @@
+/* glplib.h (miscellaneous library routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPLIB_H
+#define GLPLIB_H
+
+#define bigmul _glp_lib_bigmul
+void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
+/* multiply unsigned integer numbers of arbitrary precision */
+
+#define bigdiv _glp_lib_bigdiv
+void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
+/* divide unsigned integer numbers of arbitrary precision */
+
+#ifndef GLP_LONG_DEFINED
+#define GLP_LONG_DEFINED
+typedef struct { int lo, hi; } glp_long;
+/* long integer data type */
+#endif
+
+typedef struct { glp_long quot, rem; } glp_ldiv;
+/* result of long integer division */
+
+#define xlset _glp_lib_xlset
+glp_long xlset(int x);
+/* expand integer to long integer */
+
+#define xlneg _glp_lib_xlneg
+glp_long xlneg(glp_long x);
+/* negate long integer */
+
+#define xladd _glp_lib_xladd
+glp_long xladd(glp_long x, glp_long y);
+/* add long integers */
+
+#define xlsub _glp_lib_xlsub
+glp_long xlsub(glp_long x, glp_long y);
+/* subtract long integers */
+
+#define xlcmp _glp_lib_xlcmp
+int xlcmp(glp_long x, glp_long y);
+/* compare long integers */
+
+#define xlmul _glp_lib_xlmul
+glp_long xlmul(glp_long x, glp_long y);
+/* multiply long integers */
+
+#define xldiv _glp_lib_xldiv
+glp_ldiv xldiv(glp_long x, glp_long y);
+/* divide long integers */
+
+#define xltod _glp_lib_xltod
+double xltod(glp_long x);
+/* convert long integer to double */
+
+#define xltoa _glp_lib_xltoa
+char *xltoa(glp_long x, char *s);
+/* convert long integer to character string */
+
+#define str2int _glp_lib_str2int
+int str2int(const char *str, int *val);
+/* convert character string to value of int type */
+
+#define str2num _glp_lib_str2num
+int str2num(const char *str, double *val);
+/* convert character string to value of double type */
+
+#define strspx _glp_lib_strspx
+char *strspx(char *str);
+/* remove all spaces from character string */
+
+#define strtrim _glp_lib_strtrim
+char *strtrim(char *str);
+/* remove trailing spaces from character string */
+
+#define strrev _glp_lib_strrev
+char *strrev(char *s);
+/* reverse character string */
+
+#define gcd _glp_lib_gcd
+int gcd(int x, int y);
+/* find greatest common divisor of two integers */
+
+#define gcdn _glp_lib_gcdn
+int gcdn(int n, int x[]);
+/* find greatest common divisor of n integers */
+
+#define lcm _glp_lib_lcm
+int lcm(int x, int y);
+/* find least common multiple of two integers */
+
+#define lcmn _glp_lib_lcmn
+int lcmn(int n, int x[]);
+/* find least common multiple of n integers */
+
+#define round2n _glp_lib_round2n
+double round2n(double x);
+/* round floating-point number to nearest power of two */
+
+#define fp2rat _glp_lib_fp2rat
+int fp2rat(double x, double eps, double *p, double *q);
+/* convert floating-point number to rational number */
+
+#define jday _glp_lib_jday
+int jday(int d, int m, int y);
+/* convert calendar date to Julian day number */
+
+#define jdate _glp_lib_jdate
+int jdate(int j, int *d, int *m, int *y);
+/* convert Julian day number to calendar date */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glplib01.c b/optional/glpk/glplib01.c
new file mode 100644
index 0000000..8e1884a
--- /dev/null
+++ b/optional/glpk/glplib01.c
@@ -0,0 +1,287 @@
+/* glplib01.c (bignum arithmetic) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glplib.h"
+
+/***********************************************************************
+*  Two routines below are intended to multiply and divide unsigned
+*  integer numbers of arbitrary precision.
+* 
+*  The routines assume that an unsigned integer number is represented in
+*  the positional numeral system with the base 2^16 = 65536, i.e. each
+*  "digit" of the number is in the range [0, 65535] and represented as
+*  a 16-bit value of the unsigned short type. In other words, a number x
+*  has the following representation:
+* 
+*         n-1
+*     x = sum d[j] * 65536^j,
+*         j=0
+* 
+*  where n is the number of places (positions), and d[j] is j-th "digit"
+*  of x, 0 <= d[j] <= 65535.
+***********************************************************************/
+
+/***********************************************************************
+*  NAME
+*
+*  bigmul - multiply unsigned integer numbers of arbitrary precision
+* 
+*  SYNOPSIS
+* 
+*  #include "glplib.h"
+*  void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
+* 
+*  DESCRIPTION
+* 
+*  The routine bigmul multiplies unsigned integer numbers of arbitrary
+*  precision.
+* 
+*  n is the number of digits of multiplicand, n >= 1;
+* 
+*  m is the number of digits of multiplier, m >= 1;
+* 
+*  x is an array containing digits of the multiplicand in elements
+*  x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are
+*  ignored on entry.
+* 
+*  y is an array containing digits of the multiplier in elements y[0],
+*  y[1], ..., y[m-1].
+* 
+*  On exit digits of the product are stored in elements x[0], x[1], ...,
+*  x[n+m-1]. The array y is not changed. */
+
+void bigmul(int n, int m, unsigned short x[], unsigned short y[])
+{     int i, j;
+      unsigned int t;
+      xassert(n >= 1);
+      xassert(m >= 1);
+      for (j = 0; j < m; j++) x[j] = 0;
+      for (i = 0; i < n; i++)
+      {  if (x[i+m])
+         {  t = 0;
+            for (j = 0; j < m; j++)
+            {  t += (unsigned int)x[i+m] * (unsigned int)y[j] +
+                    (unsigned int)x[i+j];
+               x[i+j] = (unsigned short)t;
+               t >>= 16;
+            }
+            x[i+m] = (unsigned short)t;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bigdiv - divide unsigned integer numbers of arbitrary precision
+* 
+*  SYNOPSIS
+* 
+*  #include "glplib.h"
+*  void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
+* 
+*  DESCRIPTION
+* 
+*  The routine bigdiv divides one unsigned integer number of arbitrary
+*  precision by another with the algorithm described in [1].
+* 
+*  n is the difference between the number of digits of dividend and the
+*  number of digits of divisor, n >= 0.
+* 
+*  m is the number of digits of divisor, m >= 1.
+* 
+*  x is an array containing digits of the dividend in elements x[0],
+*  x[1], ..., x[n+m-1].
+* 
+*  y is an array containing digits of the divisor in elements y[0],
+*  y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.
+* 
+*  On exit n+1 digits of the quotient are stored in elements x[m],
+*  x[m+1], ..., x[n+m], and m digits of the remainder are stored in
+*  elements x[0], x[1], ..., x[m-1]. The array y is changed but then
+*  restored.
+*
+*  REFERENCES
+*
+*  1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical
+*  Algorithms. Stanford University, 1969. */
+
+void bigdiv(int n, int m, unsigned short x[], unsigned short y[])
+{     int i, j;
+      unsigned int t;
+      unsigned short d, q, r;
+      xassert(n >= 0);
+      xassert(m >= 1);
+      xassert(y[m-1] != 0);
+      /* special case when divisor has the only digit */
+      if (m == 1)
+      {  d = 0;
+         for (i = n; i >= 0; i--)
+         {  t = ((unsigned int)d << 16) + (unsigned int)x[i];
+            x[i+1] = (unsigned short)(t / y[0]);
+            d = (unsigned short)(t % y[0]);
+         }
+         x[0] = d;
+         goto done;
+      }
+      /* multiply dividend and divisor by a normalizing coefficient in
+         order to provide the condition y[m-1] >= base / 2 */
+      d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));
+      if (d == 1)
+         x[n+m] = 0;
+      else
+      {  t = 0;
+         for (i = 0; i < n+m; i++)
+         {  t += (unsigned int)x[i] * (unsigned int)d;
+            x[i] = (unsigned short)t;
+            t >>= 16;
+         }
+         x[n+m] = (unsigned short)t;
+         t = 0;
+         for (j = 0; j < m; j++)
+         {  t += (unsigned int)y[j] * (unsigned int)d;
+            y[j] = (unsigned short)t;
+            t >>= 16;
+         }
+      }
+      /* main loop */
+      for (i = n; i >= 0; i--)
+      {  /* estimate and correct the current digit of quotient */
+         if (x[i+m] < y[m-1])
+         {  t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];
+            q = (unsigned short)(t / (unsigned int)y[m-1]);
+            r = (unsigned short)(t % (unsigned int)y[m-1]);
+            if (q == 0) goto putq; else goto test;
+         }
+         q = 0;
+         r = x[i+m-1];
+decr:    q--; /* if q = 0 then q-- = 0xFFFF */
+         t = (unsigned int)r + (unsigned int)y[m-1];
+         r = (unsigned short)t;
+         if (t > 0xFFFF) goto msub;
+test:    t = (unsigned int)y[m-2] * (unsigned int)q;
+         if ((unsigned short)(t >> 16) > r) goto decr;
+         if ((unsigned short)(t >> 16) < r) goto msub;
+         if ((unsigned short)t > x[i+m-2]) goto decr;
+msub:    /* now subtract divisor multiplied by the current digit of
+            quotient from the current dividend */
+         if (q == 0) goto putq;
+         t = 0;
+         for (j = 0; j < m; j++)
+         {  t += (unsigned int)y[j] * (unsigned int)q;
+            if (x[i+j] < (unsigned short)t) t += 0x10000;
+            x[i+j] -= (unsigned short)t;
+            t >>= 16;
+         }
+         if (x[i+m] >= (unsigned short)t) goto putq;
+         /* perform correcting addition, because the current digit of
+            quotient is greater by one than its correct value */
+         q--;
+         t = 0;
+         for (j = 0; j < m; j++)
+         {  t += (unsigned int)x[i+j] + (unsigned int)y[j];
+            x[i+j] = (unsigned short)t;
+            t >>= 16;
+         }
+putq:    /* store the current digit of quotient */
+         x[i+m] = q;
+      }
+      /* divide divisor and remainder by the normalizing coefficient in
+         order to restore their original values */
+      if (d > 1)
+      {  t = 0;
+         for (i = m-1; i >= 0; i--)
+         {  t = (t << 16) + (unsigned int)x[i];
+            x[i] = (unsigned short)(t / (unsigned int)d);
+            t %= (unsigned int)d;
+         }
+         t = 0;
+         for (j = m-1; j >= 0; j--)
+         {  t = (t << 16) + (unsigned int)y[j];
+            y[j] = (unsigned short)(t / (unsigned int)d);
+            t %= (unsigned int)d;
+         }
+      }
+done: return;
+}
+
+/**********************************************************************/
+
+#if 0
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "glprng.h"
+
+#define N_MAX 7
+/* maximal number of digits in multiplicand */
+
+#define M_MAX 5
+/* maximal number of digits in multiplier */
+
+#define N_TEST 1000000
+/* number of tests */
+
+int main(void)
+{     RNG *rand;
+      int d, j, n, m, test;
+      unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];
+      rand = rng_create_rand();
+      for (test = 1; test <= N_TEST; test++)
+      {  /* x[0,...,n-1] := multiplicand */
+         n = 1 + rng_unif_rand(rand, N_MAX-1);
+         assert(1 <= n && n <= N_MAX);
+         for (j = 0; j < n; j++)
+         {  d = rng_unif_rand(rand, 65536);
+            assert(0 <= d && d <= 65535);
+            x[j] = (unsigned short)d;
+         }
+         /* y[0,...,m-1] := multiplier */
+         m = 1 + rng_unif_rand(rand, M_MAX-1);
+         assert(1 <= m && m <= M_MAX);
+         for (j = 0; j < m; j++)
+         {  d = rng_unif_rand(rand, 65536);
+            assert(0 <= d && d <= 65535);
+            y[j] = (unsigned short)d;
+         }
+         if (y[m-1] == 0) y[m-1] = 1;
+         /* z[0,...,n+m-1] := x * y */
+         for (j = 0; j < n; j++) z[m+j] = x[j];
+         bigmul(n, m, z, y);
+         /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */
+         bigdiv(n, m, z, y);
+         /* z mod y must be 0 */
+         for (j = 0; j < m; j++) assert(z[j] == 0);
+         /* z div y must be x */
+         for (j = 0; j < n; j++) assert(z[m+j] == x[j]);
+      }
+      fprintf(stderr, "%d tests successfully passed\n", N_TEST);
+      rng_delete_rand(rand);
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glplib02.c b/optional/glpk/glplib02.c
new file mode 100644
index 0000000..ab4e6dd
--- /dev/null
+++ b/optional/glpk/glplib02.c
@@ -0,0 +1,340 @@
+/* glplib02.c (64-bit arithmetic) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#endif
+
+#include "glpenv.h"
+#include "glplib.h"
+
+/***********************************************************************
+*  NAME
+*
+*  xlset - expand integer to long integer
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlset(int x);
+*
+*  RETURNS
+*
+*  The routine xlset returns x expanded to long integer. */
+
+glp_long xlset(int x)
+{     glp_long t;
+      t.lo = x, t.hi = (x >= 0 ? 0 : -1);
+      return t;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlneg - negate long integer
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlneg(glp_long x);
+*
+*  RETURNS
+*
+*  The routine xlneg returns the difference  0 - x. */
+
+glp_long xlneg(glp_long x)
+{     if (x.lo)
+         x.lo = - x.lo, x.hi = ~x.hi;
+      else
+         x.hi = - x.hi;
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xladd - add long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xladd(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xladd returns the sum x + y. */
+
+glp_long xladd(glp_long x, glp_long y)
+{     if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo)
+         x.lo += y.lo, x.hi += y.hi;
+      else
+         x.lo += y.lo, x.hi += y.hi + 1;
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlsub - subtract long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlsub(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xlsub returns the difference x - y. */
+
+glp_long xlsub(glp_long x, glp_long y)
+{     return
+         xladd(x, xlneg(y));
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlcmp - compare long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int xlcmp(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xlcmp returns the sign of the difference x - y. */
+
+int xlcmp(glp_long x, glp_long y)
+{     if (x.hi >= 0 && y.hi <  0) return +1;
+      if (x.hi <  0 && y.hi >= 0) return -1;
+      if ((unsigned int)x.hi < (unsigned int)y.hi) return -1;
+      if ((unsigned int)x.hi > (unsigned int)y.hi) return +1;
+      if ((unsigned int)x.lo < (unsigned int)y.lo) return -1;
+      if ((unsigned int)x.lo > (unsigned int)y.lo) return +1;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlmul - multiply long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlmul(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xlmul returns the product x * y. */
+
+glp_long xlmul(glp_long x, glp_long y)
+{     unsigned short xx[8], yy[4];
+      xx[4] = (unsigned short)x.lo;
+      xx[5] = (unsigned short)(x.lo >> 16);
+      xx[6] = (unsigned short)x.hi;
+      xx[7] = (unsigned short)(x.hi >> 16);
+      yy[0] = (unsigned short)y.lo;
+      yy[1] = (unsigned short)(y.lo >> 16);
+      yy[2] = (unsigned short)y.hi;
+      yy[3] = (unsigned short)(y.hi >> 16);
+      bigmul(4, 4, xx, yy);
+      x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16);
+      x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16);
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xldiv - divide long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_ldiv xldiv(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xldiv returns a structure of type glp_ldiv containing
+*  members quot (the quotient) and rem (the remainder), both of type
+*  glp_long. */
+
+glp_ldiv xldiv(glp_long x, glp_long y)
+{     glp_ldiv t;
+      int m, sx, sy;
+      unsigned short xx[8], yy[4];
+      /* sx := sign(x) */
+      sx = (x.hi < 0);
+      /* sy := sign(y) */
+      sy = (y.hi < 0);
+      /* x := |x| */
+      if (sx) x = xlneg(x);
+      /* y := |y| */
+      if (sy) y = xlneg(y);
+      /* compute x div y and x mod y */
+      xx[0] = (unsigned short)x.lo;
+      xx[1] = (unsigned short)(x.lo >> 16);
+      xx[2] = (unsigned short)x.hi;
+      xx[3] = (unsigned short)(x.hi >> 16);
+      yy[0] = (unsigned short)y.lo;
+      yy[1] = (unsigned short)(y.lo >> 16);
+      yy[2] = (unsigned short)y.hi;
+      yy[3] = (unsigned short)(y.hi >> 16);
+      if (yy[3])
+         m = 4;
+      else if (yy[2])
+         m = 3;
+      else if (yy[1])
+         m = 2;
+      else if (yy[0])
+         m = 1;
+      else
+         xerror("xldiv: divide by zero\n");
+      bigdiv(4 - m, m, xx, yy);
+      /* remainder in x[0], x[1], ..., x[m-1] */
+      t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0;
+      if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16;
+      if (m >= 3) t.rem.hi = (unsigned int)xx[2];
+      if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16;
+      if (sx) t.rem = xlneg(t.rem);
+      /* quotient in x[m], x[m+1], ..., x[4] */
+      t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0;
+      if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16;
+      if (m <= 2) t.quot.hi = (unsigned int)xx[m+2];
+      if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16;
+      if (sx ^ sy) t.quot = xlneg(t.quot);
+      return t;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xltod - convert long integer to double
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  double xltod(glp_long x);
+*
+*  RETURNS
+*
+*  The routine xltod returns x converted to double. */
+
+double xltod(glp_long x)
+{     double s, z;
+      if (x.hi >= 0)
+         s = +1.0;
+      else
+         s = -1.0, x = xlneg(x);
+      if (x.hi >= 0)
+         z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo;
+      else
+      {  xassert(x.hi == 0x80000000 && x.lo == 0x00000000);
+         z = 9223372036854775808.0; /* 2^63 */
+      }
+      return s * z;
+}
+
+char *xltoa(glp_long x, char *s)
+{     /* convert long integer to character string */
+      static const char *d = "0123456789";
+      glp_ldiv t;
+      int neg, len;
+      if (x.hi >= 0)
+         neg = 0;
+      else
+         neg = 1, x = xlneg(x);
+      if (x.hi >= 0)
+      {  len = 0;
+         while (!(x.hi == 0 && x.lo == 0))
+         {  t = xldiv(x, xlset(10));
+            xassert(0 <= t.rem.lo && t.rem.lo <= 9);
+            s[len++] = d[t.rem.lo];
+            x = t.quot;
+         }
+         if (len == 0) s[len++] = d[0];
+         if (neg) s[len++] = '-';
+         s[len] = '\0';
+         strrev(s);
+      }
+      else
+         strcpy(s, "-9223372036854775808"); /* -2^63 */
+      return s;
+}
+
+/**********************************************************************/
+
+#if 0
+#include "glprng.h"
+
+#define N_TEST 1000000
+/* number of tests */
+
+static glp_long myrand(RNG *rand)
+{     glp_long x;
+      int k;
+      k = rng_unif_rand(rand, 4);
+      xassert(0 <= k && k <= 3);
+      x.lo = rng_unif_rand(rand, 65536);
+      if (k == 1 || k == 3)
+      {  x.lo <<= 16;
+         x.lo += rng_unif_rand(rand, 65536);
+      }
+      if (k <= 1)
+         x.hi = 0;
+      else
+         x.hi = rng_unif_rand(rand, 65536);
+      if (k == 3)
+      {  x.hi <<= 16;
+         x.hi += rng_unif_rand(rand, 65536);
+      }
+      if (rng_unif_rand(rand, 2)) x = xlneg(x);
+      return x;
+}
+
+int main(void)
+{     RNG *rand;
+      glp_long x, y;
+      glp_ldiv z;
+      int test;
+      rand = rng_create_rand();
+      for (test = 1; test <= N_TEST; test++)
+      {  x = myrand(rand);
+         y = myrand(rand);
+         if (y.lo == 0 && y.hi == 0) y.lo = 1;
+         /* z.quot := x div y, z.rem := x mod y */
+         z = xldiv(x, y);
+         /* x must be equal to y * z.quot + z.rem */
+         xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0);
+      }
+      xprintf("%d tests successfully passed\n", N_TEST);
+      rng_delete_rand(rand);
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glplib03.c b/optional/glpk/glplib03.c
new file mode 100644
index 0000000..b9480a6
--- /dev/null
+++ b/optional/glpk/glplib03.c
@@ -0,0 +1,696 @@
+/* glplib03.c (miscellaneous library routines) */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#endif
+
+#include "glpenv.h"
+#include "glplib.h"
+
+/***********************************************************************
+*  NAME
+*
+*  str2int - convert character string to value of int type
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int str2int(const char *str, int *val);
+*
+*  DESCRIPTION
+*
+*  The routine str2int converts the character string str to a value of
+*  integer type and stores the value into location, which the parameter
+*  val points to (in the case of error content of this location is not
+*  changed).
+*
+*  RETURNS
+*
+*  The routine returns one of the following error codes:
+*
+*  0 - no error;
+*  1 - value out of range;
+*  2 - character string is syntactically incorrect. */
+
+int str2int(const char *str, int *_val)
+{     int d, k, s, val = 0;
+      /* scan optional sign */
+      if (str[0] == '+')
+         s = +1, k = 1;
+      else if (str[0] == '-')
+         s = -1, k = 1;
+      else
+         s = +1, k = 0;
+      /* check for the first digit */
+      if (!isdigit((unsigned char)str[k])) return 2;
+      /* scan digits */
+      while (isdigit((unsigned char)str[k]))
+      {  d = str[k++] - '0';
+         if (s > 0)
+         {  if (val > INT_MAX / 10) return 1;
+            val *= 10;
+            if (val > INT_MAX - d) return 1;
+            val += d;
+         }
+         else
+         {  if (val < INT_MIN / 10) return 1;
+            val *= 10;
+            if (val < INT_MIN + d) return 1;
+            val -= d;
+         }
+      }
+      /* check for terminator */
+      if (str[k] != '\0') return 2;
+      /* conversion has been done */
+      *_val = val;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  str2num - convert character string to value of double type
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int str2num(const char *str, double *val);
+*
+*  DESCRIPTION
+*
+*  The routine str2num converts the character string str to a value of
+*  double type and stores the value into location, which the parameter
+*  val points to (in the case of error content of this location is not
+*  changed).
+*
+*  RETURNS
+*
+*  The routine returns one of the following error codes:
+*
+*  0 - no error;
+*  1 - value out of range;
+*  2 - character string is syntactically incorrect. */
+
+int str2num(const char *str, double *_val)
+{     int k;
+      double val;
+      /* scan optional sign */
+      k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
+      /* check for decimal point */
+      if (str[k] == '.')
+      {  k++;
+         /* a digit should follow it */
+         if (!isdigit((unsigned char)str[k])) return 2;
+         k++;
+         goto frac;
+      }
+      /* integer part should start with a digit */
+      if (!isdigit((unsigned char)str[k])) return 2;
+      /* scan integer part */
+      while (isdigit((unsigned char)str[k])) k++;
+      /* check for decimal point */
+      if (str[k] == '.') k++;
+frac: /* scan optional fraction part */
+      while (isdigit((unsigned char)str[k])) k++;
+      /* check for decimal exponent */
+      if (str[k] == 'E' || str[k] == 'e')
+      {  k++;
+         /* scan optional sign */
+         if (str[k] == '+' || str[k] == '-') k++;
+         /* a digit should follow E, E+ or E- */
+         if (!isdigit((unsigned char)str[k])) return 2;
+      }
+      /* scan optional exponent part */
+      while (isdigit((unsigned char)str[k])) k++;
+      /* check for terminator */
+      if (str[k] != '\0') return 2;
+      /* perform conversion */
+      {  char *endptr;
+         val = strtod(str, &endptr);
+         if (*endptr != '\0') return 2;
+      }
+      /* check for overflow */
+      if (!(-DBL_MAX <= val && val <= +DBL_MAX)) return 1;
+      /* check for underflow */
+      if (-DBL_MIN < val && val < +DBL_MIN) val = 0.0;
+      /* conversion has been done */
+      *_val = val;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  strspx - remove all spaces from character string
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  char *strspx(char *str);
+*
+*  DESCRIPTION
+*
+*  The routine strspx removes all spaces from the character string str.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the character string.
+*
+*  EXAMPLES
+*
+*  strspx("   Errare   humanum   est   ") => "Errarehumanumest"
+*
+*  strspx("      ")                       => "" */
+
+char *strspx(char *str)
+{     char *s, *t;
+      for (s = t = str; *s; s++) if (*s != ' ') *t++ = *s;
+      *t = '\0';
+      return str;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  strtrim - remove trailing spaces from character string
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  char *strtrim(char *str);
+*
+*  DESCRIPTION
+*
+*  The routine strtrim removes trailing spaces from the character
+*  string str.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the character string.
+*
+*  EXAMPLES
+*
+*  strtrim("Errare humanum est   ") => "Errare humanum est"
+*
+*  strtrim("      ")                => "" */
+
+char *strtrim(char *str)
+{     char *t;
+      for (t = strrchr(str, '\0') - 1; t >= str; t--)
+      {  if (*t != ' ') break;
+         *t = '\0';
+      }
+      return str;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  strrev - reverse character string
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  char *strrev(char *s);
+*
+*  DESCRIPTION
+*
+*  The routine strrev changes characters in a character string s to the
+*  reverse order, except the terminating null character.
+*
+*  RETURNS
+*
+*  The routine returns the pointer s.
+*
+*  EXAMPLES
+*
+*  strrev("")                => ""
+*
+*  strrev("Today is Monday") => "yadnoM si yadoT" */
+
+char *strrev(char *s)
+{     int i, j;
+      char t;
+      for (i = 0, j = strlen(s)-1; i < j; i++, j--)
+         t = s[i], s[i] = s[j], s[j] = t;
+      return s;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  gcd - find greatest common divisor of two integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int gcd(int x, int y);
+*
+*  RETURNS
+*
+*  The routine gcd returns gcd(x, y), the greatest common divisor of
+*  the two positive integers given.
+*
+*  ALGORITHM
+*
+*  The routine gcd is based on Euclid's algorithm.
+*
+*  REFERENCES
+*
+*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
+*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
+*  Greatest Common Divisor, pp. 333-56. */
+
+int gcd(int x, int y)
+{     int r;
+      xassert(x > 0 && y > 0);
+      while (y > 0)
+         r = x % y, x = y, y = r;
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  gcdn - find greatest common divisor of n integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int gcdn(int n, int x[]);
+*
+*  RETURNS
+*
+*  The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest
+*  common divisor of n positive integers given, n > 0.
+*
+*  BACKGROUND
+*
+*  The routine gcdn is based on the following identity:
+*
+*     gcd(x, y, z) = gcd(gcd(x, y), z).
+*
+*  REFERENCES
+*
+*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
+*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
+*  Greatest Common Divisor, pp. 333-56. */
+
+int gcdn(int n, int x[])
+{     int d, j;
+      xassert(n > 0);
+      for (j = 1; j <= n; j++)
+      {  xassert(x[j] > 0);
+         if (j == 1)
+            d = x[1];
+         else
+            d = gcd(d, x[j]);
+         if (d == 1) break;
+      }
+      return d;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lcm - find least common multiple of two integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int lcm(int x, int y);
+*
+*  RETURNS
+*
+*  The routine lcm returns lcm(x, y), the least common multiple of the
+*  two positive integers given. In case of integer overflow the routine
+*  returns zero.
+*
+*  BACKGROUND
+*
+*  The routine lcm is based on the following identity:
+*
+*     lcm(x, y) = (x * y) / gcd(x, y) = x * [y / gcd(x, y)],
+*
+*  where gcd(x, y) is the greatest common divisor of x and y. */
+
+int lcm(int x, int y)
+{     xassert(x > 0);
+      xassert(y > 0);
+      y /= gcd(x, y);
+      if (x > INT_MAX / y) return 0;
+      return x * y;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lcmn - find least common multiple of n integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int lcmn(int n, int x[]);
+*
+*  RETURNS
+*
+*  The routine lcmn returns lcm(x[1], x[2], ..., x[n]), the least
+*  common multiple of n positive integers given, n > 0. In case of
+*  integer overflow the routine returns zero.
+*
+*  BACKGROUND
+*
+*  The routine lcmn is based on the following identity:
+*
+*     lcmn(x, y, z) = lcm(lcm(x, y), z),
+*
+*  where lcm(x, y) is the least common multiple of x and y. */
+
+int lcmn(int n, int x[])
+{     int m, j;
+      xassert(n > 0);
+      for (j = 1; j <= n; j++)
+      {  xassert(x[j] > 0);
+         if (j == 1)
+            m = x[1];
+         else
+            m = lcm(m, x[j]);
+         if (m == 0) break;
+      }
+      return m;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  round2n - round floating-point number to nearest power of two
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  double round2n(double x);
+*
+*  RETURNS
+*
+*  Given a positive floating-point value x the routine round2n returns
+*  2^n such that |x - 2^n| is minimal.
+*
+*  EXAMPLES
+*
+*  round2n(10.1) = 2^3 = 8
+*  round2n(15.3) = 2^4 = 16
+*  round2n(0.01) = 2^(-7) = 0.0078125
+*
+*  BACKGROUND
+*
+*  Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part,
+*  e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so
+*  if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e
+*  otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e
+*  or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */
+
+double round2n(double x)
+{     int e;
+      double f;
+      xassert(x > 0.0);
+      f = frexp(x, &e);
+      return ldexp(1.0, f <= 0.75 ? e-1 : e);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fp2rat - convert floating-point number to rational number
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int fp2rat(double x, double eps, double *p, double *q);
+*
+*  DESCRIPTION
+*
+*  Given a floating-point number 0 <= x < 1 the routine fp2rat finds
+*  its "best" rational approximation p / q, where p >= 0 and q > 0 are
+*  integer numbers, such that |x - p / q| <= eps.
+*
+*  RETURNS
+*
+*  The routine fp2rat returns the number of iterations used to achieve
+*  the specified precision eps.
+*
+*  EXAMPLES
+*
+*  For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine
+*  gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543.
+*
+*  BACKGROUND
+*
+*  It is well known that every positive real number x can be expressed
+*  as the following continued fraction:
+*
+*     x = b[0] + a[1]
+*                ------------------------
+*                b[1] + a[2]
+*                       -----------------
+*                       b[2] + a[3]
+*                              ----------
+*                              b[3] + ...
+*
+*  where:
+*
+*     a[k] = 1,                  k = 0, 1, 2, ...
+*
+*     b[k] = floor(x[k]),        k = 0, 1, 2, ...
+*
+*     x[0] = x,
+*
+*     x[k] = 1 / frac(x[k-1]),   k = 1, 2, 3, ...
+*
+*  To find the "best" rational approximation of x the routine computes
+*  partial fractions f[k] by dropping after k terms as follows:
+*
+*     f[k] = A[k] / B[k],
+*
+*  where:
+*
+*     A[-1] = 1,   A[0] = b[0],   B[-1] = 0,   B[0] = 1,
+*
+*     A[k] = b[k] * A[k-1] + a[k] * A[k-2],
+*
+*     B[k] = b[k] * B[k-1] + a[k] * B[k-2].
+*
+*  Once the condition
+*
+*     |x - f[k]| <= eps
+*
+*  has been satisfied, the routine reports p = A[k] and q = B[k] as the
+*  final answer.
+*
+*  In the table below here is some statistics obtained for one million
+*  random numbers uniformly distributed in the range [0, 1).
+*
+*      eps      max p   mean p      max q    mean q  max k   mean k
+*     -------------------------------------------------------------
+*     1e-1          8      1.6          9       3.2    3      1.4
+*     1e-2         98      6.2         99      12.4    5      2.4
+*     1e-3        997     20.7        998      41.5    8      3.4
+*     1e-4       9959     66.6       9960     133.5   10      4.4
+*     1e-5      97403    211.7      97404     424.2   13      5.3
+*     1e-6     479669    669.9     479670    1342.9   15      6.3
+*     1e-7    1579030   2127.3    3962146    4257.8   16      7.3
+*     1e-8   26188823   6749.4   26188824   13503.4   19      8.2
+*
+*  REFERENCES
+*
+*  W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory
+*  and Applications," Encyclopedia on Mathematics and Its Applications,
+*  Addison-Wesley, 1980. */
+
+int fp2rat(double x, double eps, double *p, double *q)
+{     int k;
+      double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp;
+      if (!(0.0 <= x && x < 1.0))
+         xerror("fp2rat: x = %g; number out of range\n", x);
+      for (k = 0; ; k++)
+      {  xassert(k <= 100);
+         if (k == 0)
+         {  /* x[0] = x */
+            xk = x;
+            /* A[-1] = 1 */
+            Akm1 = 1.0;
+            /* A[0] = b[0] = floor(x[0]) = 0 */
+            Ak = 0.0;
+            /* B[-1] = 0 */
+            Bkm1 = 0.0;
+            /* B[0] = 1 */
+            Bk = 1.0;
+         }
+         else
+         {  /* x[k] = 1 / frac(x[k-1]) */
+            temp = xk - floor(xk);
+            xassert(temp != 0.0);
+            xk = 1.0 / temp;
+            /* a[k] = 1 */
+            ak = 1.0;
+            /* b[k] = floor(x[k]) */
+            bk = floor(xk);
+            /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */
+            temp = bk * Ak + ak * Akm1;
+            Akm1 = Ak, Ak = temp;
+            /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */
+            temp = bk * Bk + ak * Bkm1;
+            Bkm1 = Bk, Bk = temp;
+         }
+         /* f[k] = A[k] / B[k] */
+         fk = Ak / Bk;
+#if 0
+         print("%.*g / %.*g = %.*g", DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG,
+            fk);
+#endif
+         if (fabs(x - fk) <= eps) break;
+      }
+      *p = Ak;
+      *q = Bk;
+      return k;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  jday - convert calendar date to Julian day number
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int jday(int d, int m, int y);
+*
+*  DESCRIPTION
+*
+*  The routine jday converts a calendar date, Gregorian calendar, to
+*  corresponding Julian day number j.
+*
+*  From the given day d, month m, and year y, the Julian day number j
+*  is computed without using tables.
+*
+*  The routine is valid for 1 <= y <= 4000.
+*
+*  RETURNS
+*
+*  The routine jday returns the Julian day number, or negative value if
+*  the specified date is incorrect.
+*
+*  REFERENCES
+*
+*  R. G. Tantzen, Algorithm 199: conversions between calendar date and
+*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
+*  Aug. 1963. */
+
+int jday(int d, int m, int y)
+{     int c, ya, j, dd;
+      if (!(1 <= d && d <= 31 && 1 <= m && m <= 12 && 1 <= y &&
+            y <= 4000))
+      {  j = -1;
+         goto done;
+      }
+      if (m >= 3) m -= 3; else m += 9, y--;
+      c = y / 100;
+      ya = y - 100 * c;
+      j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d +
+         1721119;
+      jdate(j, &dd, NULL, NULL);
+      if (d != dd) j = -1;
+done: return j;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  jdate - convert Julian day number to calendar date
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  void jdate(int j, int *d, int *m, int *y);
+*
+*  DESCRIPTION
+*
+*  The routine jdate converts a Julian day number j to corresponding
+*  calendar date, Gregorian calendar.
+*
+*  The day d, month m, and year y are computed without using tables and
+*  stored in corresponding locations.
+*
+*  The routine is valid for 1721426 <= j <= 3182395.
+*
+*  RETURNS
+*
+*  If the conversion is successful, the routine returns zero, otherwise
+*  non-zero.
+*
+*  REFERENCES
+*
+*  R. G. Tantzen, Algorithm 199: conversions between calendar date and
+*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
+*  Aug. 1963. */
+
+int jdate(int j, int *_d, int *_m, int *_y)
+{     int d, m, y, ret = 0;
+      if (!(1721426 <= j && j <= 3182395))
+      {  ret = 1;
+         goto done;
+      }
+      j -= 1721119;
+      y = (4 * j - 1) / 146097;
+      j = (4 * j - 1) % 146097;
+      d = j / 4;
+      j = (4 * d + 3) / 1461;
+      d = (4 * d + 3) % 1461;
+      d = (d + 4) / 4;
+      m = (5 * d - 3) / 153;
+      d = (5 * d - 3) % 153;
+      d = (d + 5) / 5;
+      y = 100 * y + j;
+      if (m <= 9) m += 3; else m -= 9, y++;
+      if (_d != NULL) *_d = d;
+      if (_m != NULL) *_m = m;
+      if (_y != NULL) *_y = y;
+done: return ret;
+}
+
+#if 0
+int main(void)
+{     int jbeg, jend, j, d, m, y;
+      jbeg = jday(1, 1, 1);
+      jend = jday(31, 12, 4000);
+      for (j = jbeg; j <= jend; j++)
+      {  xassert(jdate(j, &d, &m, &y) == 0);
+         xassert(jday(d, m, y) == j);
+      }
+      xprintf("Routines jday and jdate work correctly.\n");
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glplpf.c b/optional/glpk/glplpf.c
new file mode 100644
index 0000000..c6ad57f
--- /dev/null
+++ b/optional/glpk/glplpf.c
@@ -0,0 +1,983 @@
+/* glplpf.c (LP basis factorization, Schur complement version) */
+
+/***********************************************************************
+*  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 "-Wself-assign"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glplpf.h"
+#include "glpenv.h"
+#define xfault xerror
+
+#define _GLPLPF_DEBUG 0
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the basis matrix */
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_create_it - create LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  LPF *lpf_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_create_it creates a program object, which represents
+*  a factorization of LP basis.
+*
+*  RETURNS
+*
+*  The routine lpf_create_it returns a pointer to the object created. */
+
+LPF *lpf_create_it(void)
+{     LPF *lpf;
+#if _GLPLPF_DEBUG
+      xprintf("lpf_create_it: warning: debug mode enabled\n");
+#endif
+      lpf = xmalloc(sizeof(LPF));
+      lpf->valid = 0;
+      lpf->m0_max = lpf->m0 = 0;
+      lpf->luf = luf_create_it();
+      lpf->m = 0;
+      lpf->B = NULL;
+      lpf->n_max = 50;
+      lpf->n = 0;
+      lpf->R_ptr = lpf->R_len = NULL;
+      lpf->S_ptr = lpf->S_len = NULL;
+      lpf->scf = NULL;
+      lpf->P_row = lpf->P_col = NULL;
+      lpf->Q_row = lpf->Q_col = NULL;
+      lpf->v_size = 1000;
+      lpf->v_ptr = 0;
+      lpf->v_ind = NULL;
+      lpf->v_val = NULL;
+      lpf->work1 = lpf->work2 = NULL;
+      return lpf;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_factorize - compute LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
+*     (void *info, int j, int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_factorize computes the factorization of the basis
+*  matrix B specified by the routine col.
+*
+*  The parameter lpf specified the basis factorization data structure
+*  created with the routine lpf_create_it.
+*
+*  The parameter m specifies the order of B, m > 0.
+*
+*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
+*  number of j-th column of B in some original matrix. The array bh is
+*  optional and can be specified as NULL.
+*
+*  The formal routine col specifies the matrix B to be factorized. To
+*  obtain j-th column of A the routine lpf_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully computed.
+*
+*  LPF_ESING
+*     The specified matrix is singular within the working precision.
+*
+*  LPF_ECOND
+*     The specified matrix is ill-conditioned.
+*
+*  For more details see comments to the routine luf_factorize. */
+
+int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info)
+{     int k, ret;
+#if _GLPLPF_DEBUG
+      int i, j, len, *ind;
+      double *B, *val;
+#endif
+      xassert(bh == bh);
+      if (m < 1)
+         xfault("lpf_factorize: m = %d; invalid parameter\n", m);
+      if (m > M_MAX)
+         xfault("lpf_factorize: m = %d; matrix too big\n", m);
+      lpf->m0 = lpf->m = m;
+      /* invalidate the factorization */
+      lpf->valid = 0;
+      /* allocate/reallocate arrays, if necessary */
+      if (lpf->R_ptr == NULL)
+         lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->R_len == NULL)
+         lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->S_ptr == NULL)
+         lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->S_len == NULL)
+         lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->scf == NULL)
+         lpf->scf = scf_create_it(lpf->n_max);
+      if (lpf->v_ind == NULL)
+         lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int));
+      if (lpf->v_val == NULL)
+         lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double));
+      if (lpf->m0_max < m)
+      {  if (lpf->P_row != NULL) xfree(lpf->P_row);
+         if (lpf->P_col != NULL) xfree(lpf->P_col);
+         if (lpf->Q_row != NULL) xfree(lpf->Q_row);
+         if (lpf->Q_col != NULL) xfree(lpf->Q_col);
+         if (lpf->work1 != NULL) xfree(lpf->work1);
+         if (lpf->work2 != NULL) xfree(lpf->work2);
+         lpf->m0_max = m + 100;
+         lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
+         lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
+      }
+      /* try to factorize the basis matrix */
+      switch (luf_factorize(lpf->luf, m, col, info))
+      {  case 0:
+            break;
+         case LUF_ESING:
+            ret = LPF_ESING;
+            goto done;
+         case LUF_ECOND:
+            ret = LPF_ECOND;
+            goto done;
+         default:
+            xassert(lpf != lpf);
+      }
+      /* the basis matrix has been successfully factorized */
+      lpf->valid = 1;
+#if _GLPLPF_DEBUG
+      /* store the basis matrix for debugging */
+      if (lpf->B != NULL) xfree(lpf->B);
+      xassert(m <= 32767);
+      lpf->B = B = xcalloc(1+m*m, sizeof(double));
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      for (k = 1; k <= m * m; k++)
+         B[k] = 0.0;
+      for (j = 1; j <= m; j++)
+      {  len = col(info, j, ind, val);
+         xassert(0 <= len && len <= m);
+         for (k = 1; k <= len; k++)
+         {  i = ind[k];
+            xassert(1 <= i && i <= m);
+            xassert(B[(i - 1) * m + j] == 0.0);
+            xassert(val[k] != 0.0);
+            B[(i - 1) * m + j] = val[k];
+         }
+      }
+      xfree(ind);
+      xfree(val);
+#endif
+      /* B = B0, so there are no additional rows/columns */
+      lpf->n = 0;
+      /* reset the Schur complement factorization */
+      scf_reset_it(lpf->scf);
+      /* P := Q := I */
+      for (k = 1; k <= m; k++)
+      {  lpf->P_row[k] = lpf->P_col[k] = k;
+         lpf->Q_row[k] = lpf->Q_col[k] = k;
+      }
+      /* make all SVA locations free */
+      lpf->v_ptr = 1;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  The routine r_prod computes the product y := y + alpha * R * x,
+*  where x is a n-vector, alpha is a scalar, y is a m0-vector.
+*
+*  Since matrix R is available by columns, the product is computed as
+*  a linear combination:
+*
+*     y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]),
+*
+*  where R[j] is j-th column of R. */
+
+static void r_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *R_ptr = lpf->R_ptr;
+      int *R_len = lpf->R_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int j, beg, end, ptr;
+      double t;
+      for (j = 1; j <= n; j++)
+      {  if (x[j] == 0.0) continue;
+         /* y := y + alpha * R[j] * x[j] */
+         t = a * x[j];
+         beg = R_ptr[j];
+         end = beg + R_len[j];
+         for (ptr = beg; ptr < end; ptr++)
+            y[v_ind[ptr]] += t * v_val[ptr];
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine rt_prod computes the product y := y + alpha * R' * x,
+*  where R' is a matrix transposed to R, x is a m0-vector, alpha is a
+*  scalar, y is a n-vector.
+*
+*  Since matrix R is available by columns, the product components are
+*  computed as inner products:
+*
+*     y[j] := y[j] + alpha * (j-th column of R) * x
+*
+*  for j = 1, 2, ..., n. */
+
+static void rt_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *R_ptr = lpf->R_ptr;
+      int *R_len = lpf->R_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int j, beg, end, ptr;
+      double t;
+      for (j = 1; j <= n; j++)
+      {  /* t := (j-th column of R) * x */
+         t = 0.0;
+         beg = R_ptr[j];
+         end = beg + R_len[j];
+         for (ptr = beg; ptr < end; ptr++)
+            t += v_val[ptr] * x[v_ind[ptr]];
+         /* y[j] := y[j] + alpha * t */
+         y[j] += a * t;
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine s_prod computes the product y := y + alpha * S * x,
+*  where x is a m0-vector, alpha is a scalar, y is a n-vector.
+*
+*  Since matrix S is available by rows, the product components are
+*  computed as inner products:
+*
+*     y[i] = y[i] + alpha * (i-th row of S) * x
+*
+*  for i = 1, 2, ..., n. */
+
+static void s_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *S_ptr = lpf->S_ptr;
+      int *S_len = lpf->S_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int i, beg, end, ptr;
+      double t;
+      for (i = 1; i <= n; i++)
+      {  /* t := (i-th row of S) * x */
+         t = 0.0;
+         beg = S_ptr[i];
+         end = beg + S_len[i];
+         for (ptr = beg; ptr < end; ptr++)
+            t += v_val[ptr] * x[v_ind[ptr]];
+         /* y[i] := y[i] + alpha * t */
+         y[i] += a * t;
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine st_prod computes the product y := y + alpha * S' * x,
+*  where S' is a matrix transposed to S, x is a n-vector, alpha is a
+*  scalar, y is m0-vector.
+*
+*  Since matrix R is available by rows, the product is computed as a
+*  linear combination:
+*
+*     y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]),
+*
+*  where S'[i] is i-th row of S. */
+
+static void st_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *S_ptr = lpf->S_ptr;
+      int *S_len = lpf->S_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int i, beg, end, ptr;
+      double t;
+      for (i = 1; i <= n; i++)
+      {  if (x[i] == 0.0) continue;
+         /* y := y + alpha * S'[i] * x[i] */
+         t = a * x[i];
+         beg = S_ptr[i];
+         end = beg + S_len[i];
+         for (ptr = beg; ptr < end; ptr++)
+            y[v_ind[ptr]] += t * v_val[ptr];
+      }
+      return;
+}
+
+#if _GLPLPF_DEBUG
+/***********************************************************************
+*  The routine check_error computes the maximal relative error between
+*  left- and right-hand sides for the system B * x = b (if tr is zero)
+*  or B' * x = b (if tr is non-zero), where B' is a matrix transposed
+*  to B. (This routine is intended for debugging only.) */
+
+static void check_error(LPF *lpf, int tr, const double x[],
+      const double b[])
+{     int m = lpf->m;
+      double *B = lpf->B;
+      int i, j;
+      double  d, dmax = 0.0, s, t, tmax;
+      for (i = 1; i <= m; i++)
+      {  s = 0.0;
+         tmax = 1.0;
+         for (j = 1; j <= m; j++)
+         {  if (!tr)
+               t = B[m * (i - 1) + j] * x[j];
+            else
+               t = B[m * (j - 1) + i] * x[j];
+            if (tmax < fabs(t)) tmax = fabs(t);
+            s += t;
+         }
+         d = fabs(s - b[i]) / tmax;
+         if (dmax < d) dmax = d;
+      }
+      if (dmax > 1e-8)
+         xprintf("%s: dmax = %g; relative error too large\n",
+            !tr ? "lpf_ftran" : "lpf_btran", dmax);
+      return;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  void lpf_ftran(LPF *lpf, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  BACKGROUND
+*
+*  Solution of the system B * x = b can be obtained by solving the
+*  following augmented system:
+*
+*     ( B  F^) ( x )   ( b )
+*     (      ) (   ) = (   )
+*     ( G^ H^) ( y )   ( 0 )
+*
+*  which, using the main equality, can be written as follows:
+*
+*       ( L0 0 ) ( U0 R )   ( x )   ( b )
+*     P (      ) (      ) Q (   ) = (   )
+*       ( S  I ) ( 0  C )   ( y )   ( 0 )
+*
+*  therefore,
+*
+*     ( x )      ( U0 R )-1 ( L0 0 )-1    ( b )
+*     (   ) = Q' (      )   (      )   P' (   )
+*     ( y )      ( 0  C )   ( S  I )      ( 0 )
+*
+*  Thus, computing the solution includes the following steps:
+*
+*  1. Compute
+*
+*     ( f )      ( b )
+*     (   ) = P' (   )
+*     ( g )      ( 0 )
+*
+*  2. Solve the system
+*
+*     ( f1 )   ( L0 0 )-1 ( f )      ( L0 0 ) ( f1 )   ( f )
+*     (    ) = (      )   (   )  =>  (      ) (    ) = (   )
+*     ( g1 )   ( S  I )   ( g )      ( S  I ) ( g1 )   ( g )
+*
+*     from which it follows that:
+*
+*     { L0 * f1      = f      f1 = inv(L0) * f
+*     {                   =>
+*     {  S * f1 + g1 = g      g1 = g - S * f1
+*
+*  3. Solve the system
+*
+*     ( f2 )   ( U0 R )-1 ( f1 )      ( U0 R ) ( f2 )   ( f1 )
+*     (    ) = (      )   (    )  =>  (      ) (    ) = (    )
+*     ( g2 )   ( 0  C )   ( g1 )      ( 0  C ) ( g2 )   ( g1 )
+*
+*     from which it follows that:
+*
+*     { U0 * f2 + R * g2 = f1      f2 = inv(U0) * (f1 - R * g2)
+*     {                        =>
+*     {           C * g2 = g1      g2 = inv(C) * g1
+*
+*  4. Compute
+*
+*     ( x )      ( f2 )
+*     (   ) = Q' (    )
+*     ( y )      ( g2 )                                               */
+
+void lpf_ftran(LPF *lpf, double x[])
+{     int m0 = lpf->m0;
+      int m = lpf->m;
+      int n  = lpf->n;
+      int *P_col = lpf->P_col;
+      int *Q_col = lpf->Q_col;
+      double *fg = lpf->work1;
+      double *f = fg;
+      double *g = fg + m0;
+      int i, ii;
+#if _GLPLPF_DEBUG
+      double *b;
+#endif
+      if (!lpf->valid)
+         xfault("lpf_ftran: the factorization is not valid\n");
+      xassert(0 <= m && m <= m0 + n);
+#if _GLPLPF_DEBUG
+      /* save the right-hand side vector */
+      b = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) b[i] = x[i];
+#endif
+      /* (f g) := inv(P) * (b 0) */
+      for (i = 1; i <= m0 + n; i++)
+         fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0);
+      /* f1 := inv(L0) * f */
+      luf_f_solve(lpf->luf, 0, f);
+      /* g1 := g - S * f1 */
+      s_prod(lpf, g, -1.0, f);
+      /* g2 := inv(C) * g1 */
+      scf_solve_it(lpf->scf, 0, g);
+      /* f2 := inv(U0) * (f1 - R * g2) */
+      r_prod(lpf, f, -1.0, g);
+      luf_v_solve(lpf->luf, 0, f);
+      /* (x y) := inv(Q) * (f2 g2) */
+      for (i = 1; i <= m; i++)
+         x[i] = fg[Q_col[i]];
+#if _GLPLPF_DEBUG
+      /* check relative error in solution */
+      check_error(lpf, 0, x, b);
+      xfree(b);
+#endif
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  void lpf_btran(LPF *lpf, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix B, x is the vector of unknowns to be computed, b is the vector
+*  of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  BACKGROUND
+*
+*  Solution of the system B' * x = b, where B' is a matrix transposed
+*  to B, can be obtained by solving the following augmented system:
+*
+*     ( B  F^)T ( x )   ( b )
+*     (      )  (   ) = (   )
+*     ( G^ H^)  ( y )   ( 0 )
+*
+*  which, using the main equality, can be written as follows:
+*
+*      T ( U0 R )T ( L0 0 )T  T ( x )   ( b )
+*     Q  (      )  (      )  P  (   ) = (   )
+*        ( 0  C )  ( S  I )     ( y )   ( 0 )
+*
+*  or, equivalently, as follows:
+*
+*        ( U'0 0 ) ( L'0 S')    ( x )   ( b )
+*     Q' (       ) (       ) P' (   ) = (   )
+*        ( R'  C') ( 0   I )    ( y )   ( 0 )
+*
+*  therefore,
+*
+*     ( x )     ( L'0 S')-1 ( U'0 0 )-1   ( b )
+*     (   ) = P (       )   (       )   Q (   )
+*     ( y )     ( 0   I )   ( R'  C')     ( 0 )
+*
+*  Thus, computing the solution includes the following steps:
+*
+*  1. Compute
+*
+*     ( f )     ( b )
+*     (   ) = Q (   )
+*     ( g )     ( 0 )
+*
+*  2. Solve the system
+*
+*     ( f1 )   ( U'0 0 )-1 ( f )      ( U'0 0 ) ( f1 )   ( f )
+*     (    ) = (       )   (   )  =>  (       ) (    ) = (   )
+*     ( g1 )   ( R'  C')   ( g )      ( R'  C') ( g1 )   ( g )
+*
+*     from which it follows that:
+*
+*     { U'0 * f1           = f      f1 = inv(U'0) * f
+*     {                         =>
+*     { R'  * f1 + C' * g1 = g      g1 = inv(C') * (g - R' * f1)
+*
+*  3. Solve the system
+*
+*     ( f2 )   ( L'0 S')-1 ( f1 )      ( L'0 S') ( f2 )   ( f1 )
+*     (    ) = (       )   (    )  =>  (       ) (    ) = (    )
+*     ( g2 )   ( 0   I )   ( g1 )      ( 0   I ) ( g2 )   ( g1 )
+*
+*     from which it follows that:
+*
+*     { L'0 * f2 + S' * g2 = f1
+*     {                          =>  f2 = inv(L'0) * ( f1 - S' * g2)
+*     {                 g2 = g1
+*
+*  4. Compute
+*
+*     ( x )     ( f2 )
+*     (   ) = P (    )
+*     ( y )     ( g2 )                                                */
+
+void lpf_btran(LPF *lpf, double x[])
+{     int m0 = lpf->m0;
+      int m = lpf->m;
+      int n = lpf->n;
+      int *P_row = lpf->P_row;
+      int *Q_row = lpf->Q_row;
+      double *fg = lpf->work1;
+      double *f = fg;
+      double *g = fg + m0;
+      int i, ii;
+#if _GLPLPF_DEBUG
+      double *b;
+#endif
+      if (!lpf->valid)
+         xfault("lpf_btran: the factorization is not valid\n");
+      xassert(0 <= m && m <= m0 + n);
+#if _GLPLPF_DEBUG
+      /* save the right-hand side vector */
+      b = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) b[i] = x[i];
+#endif
+      /* (f g) := Q * (b 0) */
+      for (i = 1; i <= m0 + n; i++)
+         fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0);
+      /* f1 := inv(U'0) * f */
+      luf_v_solve(lpf->luf, 1, f);
+      /* g1 := inv(C') * (g - R' * f1) */
+      rt_prod(lpf, g, -1.0, f);
+      scf_solve_it(lpf->scf, 1, g);
+      /* g2 := g1 */
+      g = g;
+      /* f2 := inv(L'0) * (f1 - S' * g2) */
+      st_prod(lpf, f, -1.0, g);
+      luf_f_solve(lpf->luf, 1, f);
+      /* (x y) := P * (f2 g2) */
+      for (i = 1; i <= m; i++)
+         x[i] = fg[P_row[i]];
+#if _GLPLPF_DEBUG
+      /* check relative error in solution */
+      check_error(lpf, 1, x, b);
+      xfree(b);
+#endif
+      return;
+}
+
+/***********************************************************************
+*  The routine enlarge_sva enlarges the Sparse Vector Area to new_size
+*  locations by reallocating the arrays v_ind and v_val. */
+
+static void enlarge_sva(LPF *lpf, int new_size)
+{     int v_size = lpf->v_size;
+      int used = lpf->v_ptr - 1;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      xassert(v_size < new_size);
+      while (v_size < new_size) v_size += v_size;
+      lpf->v_size = v_size;
+      lpf->v_ind = xcalloc(1+v_size, sizeof(int));
+      lpf->v_val = xcalloc(1+v_size, sizeof(double));
+      xassert(used >= 0);
+      memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int));
+      memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double));
+      xfree(v_ind);
+      xfree(v_val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_update_it - update LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_update_it updates the factorization of the basis
+*  matrix B after replacing its j-th column by a new vector.
+*
+*  The parameter j specifies the number of column of B, which has been
+*  replaced, 1 <= j <= m, where m is the order of B.
+*
+*  The parameter bh specifies the basis header entry for the new column
+*  of B, which is the number of the new column in some original matrix.
+*  This parameter is optional and can be specified as 0.
+*
+*  Row indices and numerical values of non-zero elements of the new
+*  column of B should be placed in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], resp., where len is the number of non-zeros
+*  in the column. Neither zero nor duplicate elements are allowed.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  LPF_ESING
+*     New basis B is singular within the working precision.
+*
+*  LPF_ELIMIT
+*     Maximal number of additional rows and columns has been reached.
+*
+*  BACKGROUND
+*
+*  Let j-th column of the current basis matrix B have to be replaced by
+*  a new column a. This replacement is equivalent to removing the old
+*  j-th column by fixing it at zero and introducing the new column as
+*  follows:
+*
+*                   ( B   F^| a )
+*     ( B  F^)      (       |   )
+*     (      ) ---> ( G^  H^| 0 )
+*     ( G^ H^)      (-------+---)
+*                   ( e'j 0 | 0 )
+*
+*  where ej is a unit vector with 1 in j-th position which used to fix
+*  the old j-th column of B (at zero). Then using the main equality we
+*  have:
+*
+*     ( B   F^| a )            ( B0  F | f )
+*     (       |   )   ( P  0 ) (       |   ) ( Q  0 )
+*     ( G^  H^| 0 ) = (      ) ( G   H | g ) (      ) =
+*     (-------+---)   ( 0  1 ) (-------+---) ( 0  1 )
+*     ( e'j 0 | 0 )            ( v'  w'| 0 )
+*
+*       [   ( B0  F )|   ( f ) ]            [   ( B0 F )  |   ( f ) ]
+*       [ P (       )| P (   ) ] ( Q  0 )   [ P (      ) Q| P (   ) ]
+*     = [   ( G   H )|   ( g ) ] (      ) = [   ( G  H )  |   ( g ) ]
+*       [------------+-------- ] ( 0  1 )   [-------------+---------]
+*       [   ( v'  w')|     0   ]            [   ( v' w') Q|    0    ]
+*
+*  where:
+*
+*     ( a )     ( f )      ( f )        ( a )
+*     (   ) = P (   )  =>  (   ) = P' * (   )
+*     ( 0 )     ( g )      ( g )        ( 0 )
+*
+*                                 ( ej )      ( v )    ( v )     ( ej )
+*     ( e'j  0 ) = ( v' w' ) Q => (    ) = Q' (   ) => (   ) = Q (    )
+*                                 ( 0  )      ( w )    ( w )     ( 0  )
+*
+*  On the other hand:
+*
+*              ( B0| F  f )
+*     ( P  0 ) (---+------) ( Q  0 )         ( B0    new F )
+*     (      ) ( G | H  g ) (      ) = new P (             ) new Q
+*     ( 0  1 ) (   |      ) ( 0  1 )         ( new G new H )
+*              ( v'| w' 0 )
+*
+*  where:
+*                               ( G )           ( H  g )
+*     new F = ( F  f ), new G = (   ),  new H = (      ),
+*                               ( v')           ( w' 0 )
+*
+*             ( P  0 )           ( Q  0 )
+*     new P = (      ) , new Q = (      ) .
+*             ( 0  1 )           ( 0  1 )
+*
+*  The factorization structure for the new augmented matrix remains the
+*  same, therefore:
+*
+*           ( B0    new F )         ( L0     0 ) ( U0 new R )
+*     new P (             ) new Q = (          ) (          )
+*           ( new G new H )         ( new S  I ) ( 0  new C )
+*
+*  where:
+*
+*     new F = L0 * new R  =>
+*
+*     new R = inv(L0) * new F = inv(L0) * (F  f) = ( R  inv(L0)*f )
+*
+*     new G = new S * U0  =>
+*
+*                               ( G )             (     S      )
+*     new S = new G * inv(U0) = (   ) * inv(U0) = (            )
+*                               ( v')             ( v'*inv(U0) )
+*
+*     new H = new S * new R + new C  =>
+*
+*     new C = new H - new S * new R =
+*
+*             ( H  g )   (     S      )
+*           = (      ) - (            ) * ( R  inv(L0)*f ) =
+*             ( w' 0 )   ( v'*inv(U0) )
+*
+*             ( H - S*R           g - S*inv(L0)*f      )   ( C  x )
+*           = (                                        ) = (      )
+*             ( w'- v'*inv(U0)*R  -v'*inv(U0)*inv(L0)*f)   ( y' z )
+*
+*  Note that new C is resulted by expanding old C with new column x,
+*  row y', and diagonal element z, where:
+*
+*     x = g - S * inv(L0) * f = g - S * (new column of R)
+*
+*     y = w - R'* inv(U'0)* v = w - R'* (new row of S)
+*
+*     z = - (new row of S) * (new column of R)
+*
+*  Finally, to replace old B by new B we have to permute j-th and last
+*  (just added) columns of the matrix
+*
+*     ( B   F^| a )
+*     (       |   )
+*     ( G^  H^| 0 )
+*     (-------+---)
+*     ( e'j 0 | 0 )
+*
+*  and to keep the main equality do the same for matrix Q. */
+
+int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
+      const double val[])
+{     int m0 = lpf->m0;
+      int m = lpf->m;
+#if _GLPLPF_DEBUG
+      double *B = lpf->B;
+#endif
+      int n = lpf->n;
+      int *R_ptr = lpf->R_ptr;
+      int *R_len = lpf->R_len;
+      int *S_ptr = lpf->S_ptr;
+      int *S_len = lpf->S_len;
+      int *P_row = lpf->P_row;
+      int *P_col = lpf->P_col;
+      int *Q_row = lpf->Q_row;
+      int *Q_col = lpf->Q_col;
+      int v_ptr = lpf->v_ptr;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      double *a = lpf->work2; /* new column */
+      double *fg = lpf->work1, *f = fg, *g = fg + m0;
+      double *vw = lpf->work2, *v = vw, *w = vw + m0;
+      double *x = g, *y = w, z;
+      int i, ii, k, ret;
+      xassert(bh == bh);
+      if (!lpf->valid)
+         xfault("lpf_update_it: the factorization is not valid\n");
+      if (!(1 <= j && j <= m))
+         xfault("lpf_update_it: j = %d; column number out of range\n",
+            j);
+      xassert(0 <= m && m <= m0 + n);
+      /* check if the basis factorization can be expanded */
+      if (n == lpf->n_max)
+      {  lpf->valid = 0;
+         ret = LPF_ELIMIT;
+         goto done;
+      }
+      /* convert new j-th column of B to dense format */
+      for (i = 1; i <= m; i++)
+         a[i] = 0.0;
+      for (k = 1; k <= len; k++)
+      {  i = ind[k];
+         if (!(1 <= i && i <= m))
+            xfault("lpf_update_it: ind[%d] = %d; row number out of rang"
+               "e\n", k, i);
+         if (a[i] != 0.0)
+            xfault("lpf_update_it: ind[%d] = %d; duplicate row index no"
+               "t allowed\n", k, i);
+         if (val[k] == 0.0)
+            xfault("lpf_update_it: val[%d] = %g; zero element not allow"
+               "ed\n", k, val[k]);
+         a[i] = val[k];
+      }
+#if _GLPLPF_DEBUG
+      /* change column in the basis matrix for debugging */
+      for (i = 1; i <= m; i++)
+         B[(i - 1) * m + j] = a[i];
+#endif
+      /* (f g) := inv(P) * (a 0) */
+      for (i = 1; i <= m0+n; i++)
+         fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0);
+      /* (v w) := Q * (ej 0) */
+      for (i = 1; i <= m0+n; i++) vw[i] = 0.0;
+      vw[Q_col[j]] = 1.0;
+      /* f1 := inv(L0) * f (new column of R) */
+      luf_f_solve(lpf->luf, 0, f);
+      /* v1 := inv(U'0) * v (new row of S) */
+      luf_v_solve(lpf->luf, 1, v);
+      /* we need at most 2 * m0 available locations in the SVA to store
+         new column of matrix R and new row of matrix S */
+      if (lpf->v_size < v_ptr + m0 + m0)
+      {  enlarge_sva(lpf, v_ptr + m0 + m0);
+         v_ind = lpf->v_ind;
+         v_val = lpf->v_val;
+      }
+      /* store new column of R */
+      R_ptr[n+1] = v_ptr;
+      for (i = 1; i <= m0; i++)
+      {  if (f[i] != 0.0)
+            v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++;
+      }
+      R_len[n+1] = v_ptr - lpf->v_ptr;
+      lpf->v_ptr = v_ptr;
+      /* store new row of S */
+      S_ptr[n+1] = v_ptr;
+      for (i = 1; i <= m0; i++)
+      {  if (v[i] != 0.0)
+            v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++;
+      }
+      S_len[n+1] = v_ptr - lpf->v_ptr;
+      lpf->v_ptr = v_ptr;
+      /* x := g - S * f1 (new column of C) */
+      s_prod(lpf, x, -1.0, f);
+      /* y := w - R' * v1 (new row of C) */
+      rt_prod(lpf, y, -1.0, v);
+      /* z := - v1 * f1 (new diagonal element of C) */
+      z = 0.0;
+      for (i = 1; i <= m0; i++) z -= v[i] * f[i];
+      /* update factorization of new matrix C */
+      switch (scf_update_exp(lpf->scf, x, y, z))
+      {  case 0:
+            break;
+         case SCF_ESING:
+            lpf->valid = 0;
+            ret = LPF_ESING;
+            goto done;
+         case SCF_ELIMIT:
+            xassert(lpf != lpf);
+         default:
+            xassert(lpf != lpf);
+      }
+      /* expand matrix P */
+      P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1;
+      /* expand matrix Q */
+      Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1;
+      /* permute j-th and last (just added) column of matrix Q */
+      i = Q_col[j], ii = Q_col[m0+n+1];
+      Q_row[i] = m0+n+1, Q_col[m0+n+1] = i;
+      Q_row[ii] = j, Q_col[j] = ii;
+      /* increase the number of additional rows and columns */
+      lpf->n++;
+      xassert(lpf->n <= lpf->n_max);
+      /* the factorization has been successfully updated */
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_delete_it - delete LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  void lpf_delete_it(LPF *lpf)
+*
+*  DESCRIPTION
+*
+*  The routine lpf_delete_it deletes LP basis factorization specified
+*  by the parameter lpf and frees all memory allocated to this program
+*  object. */
+
+void lpf_delete_it(LPF *lpf)
+{     luf_delete_it(lpf->luf);
+#if _GLPLPF_DEBUG
+      if (lpf->B != NULL) xfree(lpf->B);
+#else
+      xassert(lpf->B == NULL);
+#endif
+      if (lpf->R_ptr != NULL) xfree(lpf->R_ptr);
+      if (lpf->R_len != NULL) xfree(lpf->R_len);
+      if (lpf->S_ptr != NULL) xfree(lpf->S_ptr);
+      if (lpf->S_len != NULL) xfree(lpf->S_len);
+      if (lpf->scf != NULL) scf_delete_it(lpf->scf);
+      if (lpf->P_row != NULL) xfree(lpf->P_row);
+      if (lpf->P_col != NULL) xfree(lpf->P_col);
+      if (lpf->Q_row != NULL) xfree(lpf->Q_row);
+      if (lpf->Q_col != NULL) xfree(lpf->Q_col);
+      if (lpf->v_ind != NULL) xfree(lpf->v_ind);
+      if (lpf->v_val != NULL) xfree(lpf->v_val);
+      if (lpf->work1 != NULL) xfree(lpf->work1);
+      if (lpf->work2 != NULL) xfree(lpf->work2);
+      xfree(lpf);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glplpf.h b/optional/glpk/glplpf.h
new file mode 100644
index 0000000..7ce6a0d
--- /dev/null
+++ b/optional/glpk/glplpf.h
@@ -0,0 +1,194 @@
+/* glplpf.h (LP basis factorization, Schur complement version) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPLPF_H
+#define GLPLPF_H
+
+#include "glpscf.h"
+#include "glpluf.h"
+
+/***********************************************************************
+*  The structure LPF defines the factorization of the basis mxm matrix
+*  B, where m is the number of rows in corresponding problem instance.
+*
+*  This factorization is the following septet:
+*
+*     [B] = (L0, U0, R, S, C, P, Q),                                 (1)
+*
+*  and is based on the following main equality:
+*
+*     ( B  F^)     ( B0 F )       ( L0 0 ) ( U0 R )
+*     (      ) = P (      ) Q = P (      ) (      ) Q,               (2)
+*     ( G^ H^)     ( G  H )       ( S  I ) ( 0  C )
+*
+*  where:
+*
+*  B is the current basis matrix (not stored);
+*
+*  F^, G^, H^ are some additional matrices (not stored);
+*
+*  B0 is some initial basis matrix (not stored);
+*
+*  F, G, H are some additional matrices (not stored);
+*
+*  P, Q are permutation matrices (stored in both row- and column-like
+*  formats);
+*
+*  L0, U0 are some matrices that defines a factorization of the initial
+*  basis matrix B0 = L0 * U0 (stored in an invertable form);
+*
+*  R is a matrix defined from L0 * R = F, so R = inv(L0) * F (stored in
+*  a column-wise sparse format);
+*
+*  S is a matrix defined from S * U0 = G, so S = G * inv(U0) (stored in
+*  a row-wise sparse format);
+*
+*  C is the Schur complement for matrix (B0 F G H). It is defined from
+*  S * R + C = H, so C = H - S * R = H - G * inv(U0) * inv(L0) * F =
+*  = H - G * inv(B0) * F. Matrix C is stored in an invertable form.
+*
+*  REFERENCES
+*
+*  1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
+*     tion," SCCM, Stanford University, 2006.
+*
+*  2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
+*     sity, Spring 2006.
+*
+*  3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
+*     ibid. */
+
+typedef struct LPF LPF;
+
+struct LPF
+{     /* LP basis factorization */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      /*--------------------------------------------------------------*/
+      /* initial basis matrix B0 */
+      int m0_max;
+      /* maximal value of m0 (increased automatically, if necessary) */
+      int m0;
+      /* the order of B0 */
+      LUF *luf;
+      /* LU-factorization of B0 */
+      /*--------------------------------------------------------------*/
+      /* current basis matrix B */
+      int m;
+      /* the order of B */
+      double *B; /* double B[1+m*m]; */
+      /* B in dense format stored by rows and used only for debugging;
+         normally this array is not allocated */
+      /*--------------------------------------------------------------*/
+      /* augmented matrix (B0 F G H) of the order m0+n */
+      int n_max;
+      /* maximal number of additional rows and columns */
+      int n;
+      /* current number of additional rows and columns */
+      /*--------------------------------------------------------------*/
+      /* m0xn matrix R in column-wise format */
+      int *R_ptr; /* int R_ptr[1+n_max]; */
+      /* R_ptr[j], 1 <= j <= n, is a pointer to j-th column */
+      int *R_len; /* int R_len[1+n_max]; */
+      /* R_len[j], 1 <= j <= n, is the length of j-th column */
+      /*--------------------------------------------------------------*/
+      /* nxm0 matrix S in row-wise format */
+      int *S_ptr; /* int S_ptr[1+n_max]; */
+      /* S_ptr[i], 1 <= i <= n, is a pointer to i-th row */
+      int *S_len; /* int S_len[1+n_max]; */
+      /* S_len[i], 1 <= i <= n, is the length of i-th row */
+      /*--------------------------------------------------------------*/
+      /* Schur complement C of the order n */
+      SCF *scf; /* SCF scf[1:n_max]; */
+      /* factorization of the Schur complement */
+      /*--------------------------------------------------------------*/
+      /* matrix P of the order m0+n */
+      int *P_row; /* int P_row[1+m0_max+n_max]; */
+      /* P_row[i] = j means that P[i,j] = 1 */
+      int *P_col; /* int P_col[1+m0_max+n_max]; */
+      /* P_col[j] = i means that P[i,j] = 1 */
+      /*--------------------------------------------------------------*/
+      /* matrix Q of the order m0+n */
+      int *Q_row; /* int Q_row[1+m0_max+n_max]; */
+      /* Q_row[i] = j means that Q[i,j] = 1 */
+      int *Q_col; /* int Q_col[1+m0_max+n_max]; */
+      /* Q_col[j] = i means that Q[i,j] = 1 */
+      /*--------------------------------------------------------------*/
+      /* Sparse Vector Area (SVA) is a set of locations intended to
+         store sparse vectors which represent columns of matrix R and
+         rows of matrix S; each location is a doublet (ind, val), where
+         ind is an index, val is a numerical value of a sparse vector
+         element; in the whole each sparse vector is a set of adjacent
+         locations defined by a pointer to its first element and its
+         length, i.e. the number of its elements */
+      int v_size;
+      /* the SVA size, in locations; locations are numbered by integers
+         1, 2, ..., v_size, and location 0 is not used */
+      int v_ptr;
+      /* pointer to the first available location */
+      int *v_ind; /* int v_ind[1+v_size]; */
+      /* v_ind[k], 1 <= k <= v_size, is the index field of location k */
+      double *v_val; /* double v_val[1+v_size]; */
+      /* v_val[k], 1 <= k <= v_size, is the value field of location k */
+      /*--------------------------------------------------------------*/
+      double *work1; /* double work1[1+m0+n_max]; */
+      /* working array */
+      double *work2; /* double work2[1+m0+n_max]; */
+      /* working array */
+};
+
+/* return codes: */
+#define LPF_ESING    1  /* singular matrix */
+#define LPF_ECOND    2  /* ill-conditioned matrix */
+#define LPF_ELIMIT   3  /* update limit reached */
+
+#define lpf_create_it _glp_lpf_create_it
+LPF *lpf_create_it(void);
+/* create LP basis factorization */
+
+#define lpf_factorize _glp_lpf_factorize
+int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#define lpf_ftran _glp_lpf_ftran
+void lpf_ftran(LPF *lpf, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#define lpf_btran _glp_lpf_btran
+void lpf_btran(LPF *lpf, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#define lpf_update_it _glp_lpf_update_it
+int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
+      const double val[]);
+/* update LP basis factorization */
+
+#define lpf_delete_it _glp_lpf_delete_it
+void lpf_delete_it(LPF *lpf);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glplpx01.c b/optional/glpk/glplpx01.c
new file mode 100644
index 0000000..d5cbff0
--- /dev/null
+++ b/optional/glpk/glplpx01.c
@@ -0,0 +1,1546 @@
+/* glplpx01.c (obsolete API routines) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#endif
+
+#include "glpapi.h"
+
+struct LPXCPS
+{     /* control parameters and statistics */
+      int msg_lev;
+      /* level of messages output by the solver:
+         0 - no output
+         1 - error messages only
+         2 - normal output
+         3 - full output (includes informational messages) */
+      int scale;
+      /* scaling option:
+         0 - no scaling
+         1 - equilibration scaling
+         2 - geometric mean scaling
+         3 - geometric mean scaling, then equilibration scaling */
+      int dual;
+      /* dual simplex option:
+         0 - use primal simplex
+         1 - use dual simplex */
+      int price;
+      /* pricing option (for both primal and dual simplex):
+         0 - textbook pricing
+         1 - steepest edge pricing */
+      double relax;
+      /* relaxation parameter used in the ratio test; if it is zero,
+         the textbook ratio test is used; if it is non-zero (should be
+         positive), Harris' two-pass ratio test is used; in the latter
+         case on the first pass basic variables (in the case of primal
+         simplex) or reduced costs of non-basic variables (in the case
+         of dual simplex) are allowed to slightly violate their bounds,
+         but not more than (relax * tol_bnd) or (relax * tol_dj) (thus,
+         relax is a percentage of tol_bnd or tol_dj) */
+      double tol_bnd;
+      /* relative tolerance used to check if the current basic solution
+         is primal feasible */
+      double tol_dj;
+      /* absolute tolerance used to check if the current basic solution
+         is dual feasible */
+      double tol_piv;
+      /* relative tolerance used to choose eligible pivotal elements of
+         the simplex table in the ratio test */
+      int round;
+      /* solution rounding option:
+         0 - report all computed values and reduced costs "as is"
+         1 - if possible (allowed by the tolerances), replace computed
+             values and reduced costs which are close to zero by exact
+             zeros */
+      double obj_ll;
+      /* lower limit of the objective function; if on the phase II the
+         objective function reaches this limit and continues decreasing,
+         the solver stops the search */
+      double obj_ul;
+      /* upper limit of the objective function; if on the phase II the
+         objective function reaches this limit and continues increasing,
+         the solver stops the search */
+      int it_lim;
+      /* simplex iterations limit; if this value is positive, it is
+         decreased by one each time when one simplex iteration has been
+         performed, and reaching zero value signals the solver to stop
+         the search; negative value means no iterations limit */
+      double tm_lim;
+      /* searching time limit, in seconds; if this value is positive,
+         it is decreased each time when one simplex iteration has been
+         performed by the amount of time spent for the iteration, and
+         reaching zero value signals the solver to stop the search;
+         negative value means no time limit */
+      int out_frq;
+      /* output frequency, in iterations; this parameter specifies how
+         frequently the solver sends information about the solution to
+         the standard output */
+      double out_dly;
+      /* output delay, in seconds; this parameter specifies how long
+         the solver should delay sending information about the solution
+         to the standard output; zero value means no delay */
+      int branch; /* MIP */
+      /* branching heuristic:
+         0 - branch on first variable
+         1 - branch on last variable
+         2 - branch using heuristic by Driebeck and Tomlin
+         3 - branch on most fractional variable */
+      int btrack; /* MIP */
+      /* backtracking heuristic:
+         0 - select most recent node (depth first search)
+         1 - select earliest node (breadth first search)
+         2 - select node using the best projection heuristic
+         3 - select node with best local bound */
+      double tol_int; /* MIP */
+      /* absolute tolerance used to check if the current basic solution
+         is integer feasible */
+      double tol_obj; /* MIP */
+      /* relative tolerance used to check if the value of the objective
+         function is not better than in the best known integer feasible
+         solution */
+      int mps_info; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps outputs several
+         comment cards that contains some information about the problem;
+         otherwise the routine outputs no comment cards */
+      int mps_obj; /* lpx_write_mps */
+      /* this parameter tells the routine lpx_write_mps how to output
+         the objective function row:
+         0 - never output objective function row
+         1 - always output objective function row
+         2 - output objective function row if and only if the problem
+             has no free rows */
+      int mps_orig; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps uses original
+         row and column symbolic names; otherwise the routine generates
+         plain names using ordinal numbers of rows and columns */
+      int mps_wide; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps uses all data
+         fields; otherwise the routine keeps fields 5 and 6 empty */
+      int mps_free; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps omits column
+         and vector names everytime if possible (free style); otherwise
+         the routine never omits these names (pedantic style) */
+      int mps_skip; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps skips empty
+         columns (i.e. which has no constraint coefficients); otherwise
+         the routine outputs all columns */
+      int lpt_orig; /* lpx_write_lpt */
+      /* if this flag is set, the routine lpx_write_lpt uses original
+         row and column symbolic names; otherwise the routine generates
+         plain names using ordinal numbers of rows and columns */
+      int presol; /* lpx_simplex */
+      /* LP presolver option:
+         0 - do not use LP presolver
+         1 - use LP presolver */
+      int binarize; /* lpx_intopt */
+      /* if this flag is set, the routine lpx_intopt replaces integer
+         columns by binary ones */
+      int use_cuts; /* lpx_intopt */
+      /* if this flag is set, the routine lpx_intopt tries generating
+         cutting planes:
+         LPX_C_COVER  - mixed cover cuts
+         LPX_C_CLIQUE - clique cuts
+         LPX_C_GOMORY - Gomory's mixed integer cuts
+         LPX_C_ALL    - all cuts */
+      double mip_gap; /* MIP */
+      /* relative MIP gap tolerance */
+};
+
+LPX *lpx_create_prob(void)
+{     /* create problem object */
+      return glp_create_prob();
+}
+
+void lpx_set_prob_name(LPX *lp, const char *name)
+{     /* assign (change) problem name */
+      glp_set_prob_name(lp, name);
+      return;
+}
+
+void lpx_set_obj_name(LPX *lp, const char *name)
+{     /* assign (change) objective function name */
+      glp_set_obj_name(lp, name);
+      return;
+}
+
+void lpx_set_obj_dir(LPX *lp, int dir)
+{     /* set (change) optimization direction flag */
+      glp_set_obj_dir(lp, dir - LPX_MIN + GLP_MIN);
+      return;
+}
+
+int lpx_add_rows(LPX *lp, int nrs)
+{     /* add new rows to problem object */
+      return glp_add_rows(lp, nrs);
+}
+
+int lpx_add_cols(LPX *lp, int ncs)
+{     /* add new columns to problem object */
+      return glp_add_cols(lp, ncs);
+}
+
+void lpx_set_row_name(LPX *lp, int i, const char *name)
+{     /* assign (change) row name */
+      glp_set_row_name(lp, i, name);
+      return;
+}
+
+void lpx_set_col_name(LPX *lp, int j, const char *name)
+{     /* assign (change) column name */
+      glp_set_col_name(lp, j, name);
+      return;
+}
+
+void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub)
+{     /* set (change) row bounds */
+      glp_set_row_bnds(lp, i, type - LPX_FR + GLP_FR, lb, ub);
+      return;
+}
+
+void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub)
+{     /* set (change) column bounds */
+      glp_set_col_bnds(lp, j, type - LPX_FR + GLP_FR, lb, ub);
+      return;
+}
+
+void lpx_set_obj_coef(glp_prob *lp, int j, double coef)
+{     /* set (change) obj. coefficient or constant term */
+      glp_set_obj_coef(lp, j, coef);
+      return;
+}
+
+void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
+      const double val[])
+{     /* set (replace) row of the constraint matrix */
+      glp_set_mat_row(lp, i, len, ind, val);
+      return;
+}
+
+void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
+      const double val[])
+{     /* set (replace) column of the constraint matrix */
+      glp_set_mat_col(lp, j, len, ind, val);
+      return;
+}
+
+void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
+      const double ar[])
+{     /* load (replace) the whole constraint matrix */
+      glp_load_matrix(lp, ne, ia, ja, ar);
+      return;
+}
+
+void lpx_del_rows(LPX *lp, int nrs, const int num[])
+{     /* delete specified rows from problem object */
+      glp_del_rows(lp, nrs, num);
+      return;
+}
+
+void lpx_del_cols(LPX *lp, int ncs, const int num[])
+{     /* delete specified columns from problem object */
+      glp_del_cols(lp, ncs, num);
+      return;
+}
+
+void lpx_delete_prob(LPX *lp)
+{     /* delete problem object */
+      glp_delete_prob(lp);
+      return;
+}
+
+const char *lpx_get_prob_name(LPX *lp)
+{     /* retrieve problem name */
+      return glp_get_prob_name(lp);
+}
+
+const char *lpx_get_obj_name(LPX *lp)
+{     /* retrieve objective function name */
+      return glp_get_obj_name(lp);
+}
+
+int lpx_get_obj_dir(LPX *lp)
+{     /* retrieve optimization direction flag */
+      return glp_get_obj_dir(lp) - GLP_MIN + LPX_MIN;
+}
+
+int lpx_get_num_rows(LPX *lp)
+{     /* retrieve number of rows */
+      return glp_get_num_rows(lp);
+}
+
+int lpx_get_num_cols(LPX *lp)
+{     /* retrieve number of columns */
+      return glp_get_num_cols(lp);
+}
+
+const char *lpx_get_row_name(LPX *lp, int i)
+{     /* retrieve row name */
+      return glp_get_row_name(lp, i);
+}
+
+const char *lpx_get_col_name(LPX *lp, int j)
+{     /* retrieve column name */
+      return glp_get_col_name(lp, j);
+}
+
+int lpx_get_row_type(LPX *lp, int i)
+{     /* retrieve row type */
+      return glp_get_row_type(lp, i) - GLP_FR + LPX_FR;
+}
+
+double lpx_get_row_lb(glp_prob *lp, int i)
+{     /* retrieve row lower bound */
+      double lb;
+      lb = glp_get_row_lb(lp, i);
+      if (lb == -DBL_MAX) lb = 0.0;
+      return lb;
+}
+
+double lpx_get_row_ub(glp_prob *lp, int i)
+{     /* retrieve row upper bound */
+      double ub;
+      ub = glp_get_row_ub(lp, i);
+      if (ub == +DBL_MAX) ub = 0.0;
+      return ub;
+}
+
+void lpx_get_row_bnds(glp_prob *lp, int i, int *typx, double *lb,
+      double *ub)
+{     /* retrieve row bounds */
+      if (typx != NULL) *typx = lpx_get_row_type(lp, i);
+      if (lb != NULL) *lb = lpx_get_row_lb(lp, i);
+      if (ub != NULL) *ub = lpx_get_row_ub(lp, i);
+      return;
+}
+
+int lpx_get_col_type(LPX *lp, int j)
+{     /* retrieve column type */
+      return glp_get_col_type(lp, j) - GLP_FR + LPX_FR;
+}
+
+double lpx_get_col_lb(glp_prob *lp, int j)
+{     /* retrieve column lower bound */
+      double lb;
+      lb = glp_get_col_lb(lp, j);
+      if (lb == -DBL_MAX) lb = 0.0;
+      return lb;
+}
+
+double lpx_get_col_ub(glp_prob *lp, int j)
+{     /* retrieve column upper bound */
+      double ub;
+      ub = glp_get_col_ub(lp, j);
+      if (ub == +DBL_MAX) ub = 0.0;
+      return ub;
+}
+
+void lpx_get_col_bnds(glp_prob *lp, int j, int *typx, double *lb,
+      double *ub)
+{     /* retrieve column bounds */
+      if (typx != NULL) *typx = lpx_get_col_type(lp, j);
+      if (lb != NULL) *lb = lpx_get_col_lb(lp, j);
+      if (ub != NULL) *ub = lpx_get_col_ub(lp, j);
+      return;
+}
+
+double lpx_get_obj_coef(LPX *lp, int j)
+{     /* retrieve obj. coefficient or constant term */
+      return glp_get_obj_coef(lp, j);
+}
+
+int lpx_get_num_nz(LPX *lp)
+{     /* retrieve number of constraint coefficients */
+      return glp_get_num_nz(lp);
+}
+
+int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[])
+{     /* retrieve row of the constraint matrix */
+      return glp_get_mat_row(lp, i, ind, val);
+}
+
+int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[])
+{     /* retrieve column of the constraint matrix */
+      return glp_get_mat_col(lp, j, ind, val);
+}
+
+void lpx_create_index(LPX *lp)
+{     /* create the name index */
+      glp_create_index(lp);
+      return;
+}
+
+int lpx_find_row(LPX *lp, const char *name)
+{     /* find row by its name */
+      return glp_find_row(lp, name);
+}
+
+int lpx_find_col(LPX *lp, const char *name)
+{     /* find column by its name */
+      return glp_find_col(lp, name);
+}
+
+void lpx_delete_index(LPX *lp)
+{     /* delete the name index */
+      glp_delete_index(lp);
+      return;
+}
+
+void lpx_scale_prob(LPX *lp)
+{     /* scale problem data */
+      switch (lpx_get_int_parm(lp, LPX_K_SCALE))
+      {  case 0:
+            /* no scaling */
+            glp_unscale_prob(lp);
+            break;
+         case 1:
+            /* equilibration scaling */
+            glp_scale_prob(lp, GLP_SF_EQ);
+            break;
+         case 2:
+            /* geometric mean scaling */
+            glp_scale_prob(lp, GLP_SF_GM);
+            break;
+         case 3:
+            /* geometric mean scaling, then equilibration scaling */
+            glp_scale_prob(lp, GLP_SF_GM | GLP_SF_EQ);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return;
+}
+
+void lpx_unscale_prob(LPX *lp)
+{     /* unscale problem data */
+      glp_unscale_prob(lp);
+      return;
+}
+
+void lpx_set_row_stat(LPX *lp, int i, int stat)
+{     /* set (change) row status */
+      glp_set_row_stat(lp, i, stat - LPX_BS + GLP_BS);
+      return;
+}
+
+void lpx_set_col_stat(LPX *lp, int j, int stat)
+{     /* set (change) column status */
+      glp_set_col_stat(lp, j, stat - LPX_BS + GLP_BS);
+      return;
+}
+
+void lpx_std_basis(LPX *lp)
+{     /* construct standard initial LP basis */
+      glp_std_basis(lp);
+      return;
+}
+
+void lpx_adv_basis(LPX *lp)
+{     /* construct advanced initial LP basis */
+      glp_adv_basis(lp, 0);
+      return;
+}
+
+void lpx_cpx_basis(LPX *lp)
+{     /* construct Bixby's initial LP basis */
+      glp_cpx_basis(lp);
+      return;
+}
+
+static void fill_smcp(LPX *lp, glp_smcp *parm)
+{     glp_init_smcp(parm);
+      switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
+      {  case 0:  parm->msg_lev = GLP_MSG_OFF;   break;
+         case 1:  parm->msg_lev = GLP_MSG_ERR;   break;
+         case 2:  parm->msg_lev = GLP_MSG_ON;    break;
+         case 3:  parm->msg_lev = GLP_MSG_ALL;   break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_DUAL))
+      {  case 0:  parm->meth = GLP_PRIMAL;       break;
+         case 1:  parm->meth = GLP_DUAL;         break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_PRICE))
+      {  case 0:  parm->pricing = GLP_PT_STD;    break;
+         case 1:  parm->pricing = GLP_PT_PSE;    break;
+         default: xassert(lp != lp);
+      }
+      if (lpx_get_real_parm(lp, LPX_K_RELAX) == 0.0)
+         parm->r_test = GLP_RT_STD;
+      else
+         parm->r_test = GLP_RT_HAR;
+      parm->tol_bnd = lpx_get_real_parm(lp, LPX_K_TOLBND);
+      parm->tol_dj  = lpx_get_real_parm(lp, LPX_K_TOLDJ);
+      parm->tol_piv = lpx_get_real_parm(lp, LPX_K_TOLPIV);
+      parm->obj_ll  = lpx_get_real_parm(lp, LPX_K_OBJLL);
+      parm->obj_ul  = lpx_get_real_parm(lp, LPX_K_OBJUL);
+      if (lpx_get_int_parm(lp, LPX_K_ITLIM) < 0)
+         parm->it_lim = INT_MAX;
+      else
+         parm->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
+      if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0)
+         parm->tm_lim = INT_MAX;
+      else
+         parm->tm_lim =
+            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
+      parm->out_frq = lpx_get_int_parm(lp, LPX_K_OUTFRQ);
+      parm->out_dly =
+            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_OUTDLY));
+      switch (lpx_get_int_parm(lp, LPX_K_PRESOL))
+      {  case 0:  parm->presolve = GLP_OFF;      break;
+         case 1:  parm->presolve = GLP_ON;       break;
+         default: xassert(lp != lp);
+      }
+      return;
+}
+
+int lpx_simplex(LPX *lp)
+{     /* easy-to-use driver to the simplex method */
+      glp_smcp parm;
+      int ret;
+      fill_smcp(lp, &parm);
+      ret = glp_simplex(lp, &parm);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_EBADB:
+         case GLP_ESING:
+         case GLP_ECOND:
+         case GLP_EBOUND:  ret = LPX_E_FAULT;   break;
+         case GLP_EFAIL:   ret = LPX_E_SING;    break;
+         case GLP_EOBJLL:  ret = LPX_E_OBJLL;   break;
+         case GLP_EOBJUL:  ret = LPX_E_OBJUL;   break;
+         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
+         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
+         case GLP_ENOPFS:  ret = LPX_E_NOPFS;   break;
+         case GLP_ENODFS:  ret = LPX_E_NODFS;   break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_exact(LPX *lp)
+{     /* easy-to-use driver to the exact simplex method */
+      glp_smcp parm;
+      int ret;
+      fill_smcp(lp, &parm);
+      ret = glp_exact(lp, &parm);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_EBADB:
+         case GLP_ESING:
+         case GLP_EBOUND:
+         case GLP_EFAIL:   ret = LPX_E_FAULT;   break;
+         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
+         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_get_status(glp_prob *lp)
+{     /* retrieve generic status of basic solution */
+      int status;
+      switch (glp_get_status(lp))
+      {  case GLP_OPT:    status = LPX_OPT;    break;
+         case GLP_FEAS:   status = LPX_FEAS;   break;
+         case GLP_INFEAS: status = LPX_INFEAS; break;
+         case GLP_NOFEAS: status = LPX_NOFEAS; break;
+         case GLP_UNBND:  status = LPX_UNBND;  break;
+         case GLP_UNDEF:  status = LPX_UNDEF;  break;
+         default:         xassert(lp != lp);
+      }
+      return status;
+}
+
+int lpx_get_prim_stat(glp_prob *lp)
+{     /* retrieve status of primal basic solution */
+      return glp_get_prim_stat(lp) - GLP_UNDEF + LPX_P_UNDEF;
+}
+
+int lpx_get_dual_stat(glp_prob *lp)
+{     /* retrieve status of dual basic solution */
+      return glp_get_dual_stat(lp) - GLP_UNDEF + LPX_D_UNDEF;
+}
+
+double lpx_get_obj_val(LPX *lp)
+{     /* retrieve objective value (basic solution) */
+      return glp_get_obj_val(lp);
+}
+
+int lpx_get_row_stat(LPX *lp, int i)
+{     /* retrieve row status (basic solution) */
+      return glp_get_row_stat(lp, i) - GLP_BS + LPX_BS;
+}
+
+double lpx_get_row_prim(LPX *lp, int i)
+{     /* retrieve row primal value (basic solution) */
+      return glp_get_row_prim(lp, i);
+}
+
+double lpx_get_row_dual(LPX *lp, int i)
+{     /* retrieve row dual value (basic solution) */
+      return glp_get_row_dual(lp, i);
+}
+
+void lpx_get_row_info(glp_prob *lp, int i, int *tagx, double *vx,
+      double *dx)
+{     /* obtain row solution information */
+      if (tagx != NULL) *tagx = lpx_get_row_stat(lp, i);
+      if (vx != NULL) *vx = lpx_get_row_prim(lp, i);
+      if (dx != NULL) *dx = lpx_get_row_dual(lp, i);
+      return;
+}
+
+int lpx_get_col_stat(LPX *lp, int j)
+{     /* retrieve column status (basic solution) */
+      return glp_get_col_stat(lp, j) - GLP_BS + LPX_BS;
+}
+
+double lpx_get_col_prim(LPX *lp, int j)
+{     /* retrieve column primal value (basic solution) */
+      return glp_get_col_prim(lp, j);
+}
+
+double lpx_get_col_dual(glp_prob *lp, int j)
+{     /* retrieve column dual value (basic solution) */
+      return glp_get_col_dual(lp, j);
+}
+
+void lpx_get_col_info(glp_prob *lp, int j, int *tagx, double *vx,
+      double *dx)
+{     /* obtain column solution information */
+      if (tagx != NULL) *tagx = lpx_get_col_stat(lp, j);
+      if (vx != NULL) *vx = lpx_get_col_prim(lp, j);
+      if (dx != NULL) *dx = lpx_get_col_dual(lp, j);
+      return;
+}
+
+int lpx_get_ray_info(LPX *lp)
+{     /* determine what causes primal unboundness */
+      return glp_get_unbnd_ray(lp);
+}
+
+void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt)
+{     /* check Karush-Kuhn-Tucker conditions */
+      int ae_ind, re_ind;
+      double ae_max, re_max;
+      xassert(scaled == scaled);
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pe_ae_max = ae_max;
+      kkt->pe_ae_row = ae_ind;
+      kkt->pe_re_max = re_max;
+      kkt->pe_re_row = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pe_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pe_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pe_quality = 'L';
+      else
+         kkt->pe_quality = '?';
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pb_ae_max = ae_max;
+      kkt->pb_ae_ind = ae_ind;
+      kkt->pb_re_max = re_max;
+      kkt->pb_re_ind = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pb_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pb_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pb_quality = 'L';
+      else
+         kkt->pb_quality = '?';
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->de_ae_max = ae_max;
+      if (ae_ind == 0)
+         kkt->de_ae_col = 0;
+      else
+         kkt->de_ae_col = ae_ind - lp->m;
+      kkt->de_re_max = re_max;
+      if (re_ind == 0)
+         kkt->de_re_col = 0;
+      else
+         kkt->de_re_col = ae_ind - lp->m;
+      if (re_max <= 1e-9)
+         kkt->de_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->de_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->de_quality = 'L';
+      else
+         kkt->de_quality = '?';
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->db_ae_max = ae_max;
+      kkt->db_ae_ind = ae_ind;
+      kkt->db_re_max = re_max;
+      kkt->db_re_ind = re_ind;
+      if (re_max <= 1e-9)
+         kkt->db_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->db_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->db_quality = 'L';
+      else
+         kkt->db_quality = '?';
+      kkt->cs_ae_max = 0.0, kkt->cs_ae_ind = 0;
+      kkt->cs_re_max = 0.0, kkt->cs_re_ind = 0;
+      kkt->cs_quality = 'H';
+      return;
+}
+
+int lpx_warm_up(LPX *lp)
+{     /* "warm up" LP basis */
+      int ret;
+      ret = glp_warm_up(lp);
+      if (ret == 0)
+         ret = LPX_E_OK;
+      else if (ret == GLP_EBADB)
+         ret = LPX_E_BADB;
+      else if (ret == GLP_ESING)
+         ret = LPX_E_SING;
+      else if (ret == GLP_ECOND)
+         ret = LPX_E_SING;
+      else
+         xassert(ret != ret);
+      return ret;
+}
+
+int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[])
+{     /* compute row of the simplex tableau */
+      return glp_eval_tab_row(lp, k, ind, val);
+}
+
+int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[])
+{     /* compute column of the simplex tableau */
+      return glp_eval_tab_col(lp, k, ind, val);
+}
+
+int lpx_transform_row(LPX *lp, int len, int ind[], double val[])
+{     /* transform explicitly specified row */
+      return glp_transform_row(lp, len, ind, val);
+}
+
+int lpx_transform_col(LPX *lp, int len, int ind[], double val[])
+{     /* transform explicitly specified column */
+      return glp_transform_col(lp, len, ind, val);
+}
+
+int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol)
+{     /* perform primal ratio test */
+      int piv;
+      piv = glp_prim_rtest(lp, len, ind, val, how, tol);
+      xassert(0 <= piv && piv <= len);
+      return piv == 0 ? 0 : ind[piv];
+}
+
+int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol)
+{     /* perform dual ratio test */
+      int piv;
+      piv = glp_dual_rtest(lp, len, ind, val, how, tol);
+      xassert(0 <= piv && piv <= len);
+      return piv == 0 ? 0 : ind[piv];
+}
+
+int lpx_interior(LPX *lp)
+{     /* easy-to-use driver to the interior-point method */
+      int ret;
+      ret = glp_interior(lp, NULL);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_EFAIL:   ret = LPX_E_FAULT;   break;
+         case GLP_ENOFEAS: ret = LPX_E_NOFEAS;  break;
+         case GLP_ENOCVG:  ret = LPX_E_NOCONV;  break;
+         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
+         case GLP_EINSTAB: ret = LPX_E_INSTAB;  break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_ipt_status(glp_prob *lp)
+{     /* retrieve status of interior-point solution */
+      int status;
+      switch (glp_ipt_status(lp))
+      {  case GLP_UNDEF:  status = LPX_T_UNDEF;  break;
+         case GLP_OPT:    status = LPX_T_OPT;    break;
+         default:         xassert(lp != lp);
+      }
+      return status;
+}
+
+double lpx_ipt_obj_val(LPX *lp)
+{     /* retrieve objective value (interior point) */
+      return glp_ipt_obj_val(lp);
+}
+
+double lpx_ipt_row_prim(LPX *lp, int i)
+{     /* retrieve row primal value (interior point) */
+      return glp_ipt_row_prim(lp, i);
+}
+
+double lpx_ipt_row_dual(LPX *lp, int i)
+{     /* retrieve row dual value (interior point) */
+      return glp_ipt_row_dual(lp, i);
+}
+
+double lpx_ipt_col_prim(LPX *lp, int j)
+{     /* retrieve column primal value (interior point) */
+      return glp_ipt_col_prim(lp, j);
+}
+
+double lpx_ipt_col_dual(LPX *lp, int j)
+{     /* retrieve column dual value (interior point) */
+      return glp_ipt_col_dual(lp, j);
+}
+
+void lpx_set_class(LPX *lp, int klass)
+{     /* set problem class */
+      xassert(lp == lp);
+      if (!(klass == LPX_LP || klass == LPX_MIP))
+         xerror("lpx_set_class: invalid problem class\n");
+      return;
+}
+
+int lpx_get_class(LPX *lp)
+{     /* determine problem klass */
+      return glp_get_num_int(lp) == 0 ? LPX_LP : LPX_MIP;
+}
+
+void lpx_set_col_kind(LPX *lp, int j, int kind)
+{     /* set (change) column kind */
+      glp_set_col_kind(lp, j, kind - LPX_CV + GLP_CV);
+      return;
+}
+
+int lpx_get_col_kind(LPX *lp, int j)
+{     /* retrieve column kind */
+      return glp_get_col_kind(lp, j) == GLP_CV ? LPX_CV : LPX_IV;
+}
+
+int lpx_get_num_int(LPX *lp)
+{     /* retrieve number of integer columns */
+      return glp_get_num_int(lp);
+}
+
+int lpx_get_num_bin(LPX *lp)
+{     /* retrieve number of binary columns */
+      return glp_get_num_bin(lp);
+}
+
+static int solve_mip(LPX *lp, int presolve)
+{     glp_iocp parm;
+      int ret;
+      glp_init_iocp(&parm);
+      switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
+      {  case 0:  parm.msg_lev = GLP_MSG_OFF;   break;
+         case 1:  parm.msg_lev = GLP_MSG_ERR;   break;
+         case 2:  parm.msg_lev = GLP_MSG_ON;    break;
+         case 3:  parm.msg_lev = GLP_MSG_ALL;   break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_BRANCH))
+      {  case 0:  parm.br_tech = GLP_BR_FFV;    break;
+         case 1:  parm.br_tech = GLP_BR_LFV;    break;
+         case 2:  parm.br_tech = GLP_BR_DTH;    break;
+         case 3:  parm.br_tech = GLP_BR_MFV;    break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_BTRACK))
+      {  case 0:  parm.bt_tech = GLP_BT_DFS;    break;
+         case 1:  parm.bt_tech = GLP_BT_BFS;    break;
+         case 2:  parm.bt_tech = GLP_BT_BPH;    break;
+         case 3:  parm.bt_tech = GLP_BT_BLB;    break;
+         default: xassert(lp != lp);
+      }
+      parm.tol_int = lpx_get_real_parm(lp, LPX_K_TOLINT);
+      parm.tol_obj = lpx_get_real_parm(lp, LPX_K_TOLOBJ);
+      if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0 ||
+          lpx_get_real_parm(lp, LPX_K_TMLIM) > 1e6)
+         parm.tm_lim = INT_MAX;
+      else
+         parm.tm_lim =
+            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
+      parm.mip_gap = lpx_get_real_parm(lp, LPX_K_MIPGAP);
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_GOMORY)
+         parm.gmi_cuts = GLP_ON;
+      else
+         parm.gmi_cuts = GLP_OFF;
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_MIR)
+         parm.mir_cuts = GLP_ON;
+      else
+         parm.mir_cuts = GLP_OFF;
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_COVER)
+         parm.cov_cuts = GLP_ON;
+      else
+         parm.cov_cuts = GLP_OFF;
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_CLIQUE)
+         parm.clq_cuts = GLP_ON;
+      else
+         parm.clq_cuts = GLP_OFF;
+      parm.presolve = presolve;
+      if (lpx_get_int_parm(lp, LPX_K_BINARIZE))
+         parm.binarize = GLP_ON;
+      ret = glp_intopt(lp, &parm);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_ENOPFS:  ret = LPX_E_NOPFS;   break;
+         case GLP_ENODFS:  ret = LPX_E_NODFS;   break;
+         case GLP_EBOUND:
+         case GLP_EROOT:   ret = LPX_E_FAULT;   break;
+         case GLP_EFAIL:   ret = LPX_E_SING;    break;
+         case GLP_EMIPGAP: ret = LPX_E_MIPGAP;  break;
+         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_integer(LPX *lp)
+{     /* easy-to-use driver to the branch-and-bound method */
+      return solve_mip(lp, GLP_OFF);
+}
+
+int lpx_intopt(LPX *lp)
+{     /* easy-to-use driver to the branch-and-bound method */
+      return solve_mip(lp, GLP_ON);
+}
+
+int lpx_mip_status(glp_prob *lp)
+{     /* retrieve status of MIP solution */
+      int status;
+      switch (glp_mip_status(lp))
+      {  case GLP_UNDEF:  status = LPX_I_UNDEF;  break;
+         case GLP_OPT:    status = LPX_I_OPT;    break;
+         case GLP_FEAS:   status = LPX_I_FEAS;   break;
+         case GLP_NOFEAS: status = LPX_I_NOFEAS; break;
+         default:         xassert(lp != lp);
+      }
+      return status;
+}
+
+double lpx_mip_obj_val(LPX *lp)
+{     /* retrieve objective value (MIP solution) */
+      return glp_mip_obj_val(lp);
+}
+
+double lpx_mip_row_val(LPX *lp, int i)
+{     /* retrieve row value (MIP solution) */
+      return glp_mip_row_val(lp, i);
+}
+
+double lpx_mip_col_val(LPX *lp, int j)
+{     /* retrieve column value (MIP solution) */
+      return glp_mip_col_val(lp, j);
+}
+
+void lpx_check_int(LPX *lp, LPXKKT *kkt)
+{     /* check integer feasibility conditions */
+      int ae_ind, re_ind;
+      double ae_max, re_max;
+      _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pe_ae_max = ae_max;
+      kkt->pe_ae_row = ae_ind;
+      kkt->pe_re_max = re_max;
+      kkt->pe_re_row = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pe_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pe_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pe_quality = 'L';
+      else
+         kkt->pe_quality = '?';
+      _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pb_ae_max = ae_max;
+      kkt->pb_ae_ind = ae_ind;
+      kkt->pb_re_max = re_max;
+      kkt->pb_re_ind = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pb_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pb_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pb_quality = 'L';
+      else
+         kkt->pb_quality = '?';
+      return;
+}
+
+#if 1 /* 17/XI-2009 */
+static void reset_parms(LPX *lp)
+{     /* reset control parameters to default values */
+      struct LPXCPS *cps = lp->parms;
+      xassert(cps != NULL);
+      cps->msg_lev  = 3;
+      cps->scale    = 1;
+      cps->dual     = 0;
+      cps->price    = 1;
+      cps->relax    = 0.07;
+      cps->tol_bnd  = 1e-7;
+      cps->tol_dj   = 1e-7;
+      cps->tol_piv  = 1e-9;
+      cps->round    = 0;
+      cps->obj_ll   = -DBL_MAX;
+      cps->obj_ul   = +DBL_MAX;
+      cps->it_lim   = -1;
+#if 0 /* 02/XII-2010 */
+      lp->it_cnt   = 0;
+#endif
+      cps->tm_lim   = -1.0;
+      cps->out_frq  = 200;
+      cps->out_dly  = 0.0;
+      cps->branch   = 2;
+      cps->btrack   = 3;
+      cps->tol_int  = 1e-5;
+      cps->tol_obj  = 1e-7;
+      cps->mps_info = 1;
+      cps->mps_obj  = 2;
+      cps->mps_orig = 0;
+      cps->mps_wide = 1;
+      cps->mps_free = 0;
+      cps->mps_skip = 0;
+      cps->lpt_orig = 0;
+      cps->presol = 0;
+      cps->binarize = 0;
+      cps->use_cuts = 0;
+      cps->mip_gap = 0.0;
+      return;
+}
+#endif
+
+#if 1 /* 17/XI-2009 */
+static struct LPXCPS *access_parms(LPX *lp)
+{     /* allocate and initialize control parameters, if necessary */
+      if (lp->parms == NULL)
+      {  lp->parms = xmalloc(sizeof(struct LPXCPS));
+         reset_parms(lp);
+      }
+      return lp->parms;
+}
+#endif
+
+#if 1 /* 17/XI-2009 */
+void lpx_reset_parms(LPX *lp)
+{     /* reset control parameters to default values */
+      access_parms(lp);
+      reset_parms(lp);
+      return;
+}
+#endif
+
+void lpx_set_int_parm(LPX *lp, int parm, int val)
+{     /* set (change) integer control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      switch (parm)
+      {  case LPX_K_MSGLEV:
+            if (!(0 <= val && val <= 3))
+               xerror("lpx_set_int_parm: MSGLEV = %d; invalid value\n",
+                  val);
+            cps->msg_lev = val;
+            break;
+         case LPX_K_SCALE:
+            if (!(0 <= val && val <= 3))
+               xerror("lpx_set_int_parm: SCALE = %d; invalid value\n",
+                  val);
+            cps->scale = val;
+            break;
+         case LPX_K_DUAL:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: DUAL = %d; invalid value\n",
+                  val);
+            cps->dual = val;
+            break;
+         case LPX_K_PRICE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: PRICE = %d; invalid value\n",
+                  val);
+            cps->price = val;
+            break;
+         case LPX_K_ROUND:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: ROUND = %d; invalid value\n",
+                  val);
+            cps->round = val;
+            break;
+         case LPX_K_ITLIM:
+            cps->it_lim = val;
+            break;
+         case LPX_K_ITCNT:
+            lp->it_cnt = val;
+            break;
+         case LPX_K_OUTFRQ:
+            if (!(val > 0))
+               xerror("lpx_set_int_parm: OUTFRQ = %d; invalid value\n",
+                  val);
+            cps->out_frq = val;
+            break;
+         case LPX_K_BRANCH:
+            if (!(val == 0 || val == 1 || val == 2 || val == 3))
+               xerror("lpx_set_int_parm: BRANCH = %d; invalid value\n",
+                  val);
+            cps->branch = val;
+            break;
+         case LPX_K_BTRACK:
+            if (!(val == 0 || val == 1 || val == 2 || val == 3))
+               xerror("lpx_set_int_parm: BTRACK = %d; invalid value\n",
+                  val);
+            cps->btrack = val;
+            break;
+         case LPX_K_MPSINFO:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSINFO = %d; invalid value\n",
+                  val);
+            cps->mps_info = val;
+            break;
+         case LPX_K_MPSOBJ:
+            if (!(val == 0 || val == 1 || val == 2))
+               xerror("lpx_set_int_parm: MPSOBJ = %d; invalid value\n",
+                  val);
+            cps->mps_obj = val;
+            break;
+         case LPX_K_MPSORIG:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSORIG = %d; invalid value\n",
+                  val);
+            cps->mps_orig = val;
+            break;
+         case LPX_K_MPSWIDE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSWIDE = %d; invalid value\n",
+                  val);
+            cps->mps_wide = val;
+            break;
+         case LPX_K_MPSFREE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSFREE = %d; invalid value\n",
+                  val);
+            cps->mps_free = val;
+            break;
+         case LPX_K_MPSSKIP:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSSKIP = %d; invalid value\n",
+                  val);
+            cps->mps_skip = val;
+            break;
+         case LPX_K_LPTORIG:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: LPTORIG = %d; invalid value\n",
+                  val);
+            cps->lpt_orig = val;
+            break;
+         case LPX_K_PRESOL:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: PRESOL = %d; invalid value\n",
+                  val);
+            cps->presol = val;
+            break;
+         case LPX_K_BINARIZE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: BINARIZE = %d; invalid value\n"
+                  , val);
+            cps->binarize = val;
+            break;
+         case LPX_K_USECUTS:
+            if (val & ~LPX_C_ALL)
+            xerror("lpx_set_int_parm: USECUTS = 0x%X; invalid value\n",
+                  val);
+            cps->use_cuts = val;
+            break;
+         case LPX_K_BFTYPE:
+#if 0
+            if (!(1 <= val && val <= 3))
+               xerror("lpx_set_int_parm: BFTYPE = %d; invalid value\n",
+                  val);
+            cps->bf_type = val;
+#else
+            {  glp_bfcp parm;
+               glp_get_bfcp(lp, &parm);
+               switch (val)
+               {  case 1:
+                     parm.type = GLP_BF_FT; break;
+                  case 2:
+                     parm.type = GLP_BF_BG; break;
+                  case 3:
+                     parm.type = GLP_BF_GR; break;
+                  default:
+                     xerror("lpx_set_int_parm: BFTYPE = %d; invalid val"
+                        "ue\n", val);
+               }
+               glp_set_bfcp(lp, &parm);
+            }
+#endif
+            break;
+         default:
+            xerror("lpx_set_int_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return;
+}
+
+int lpx_get_int_parm(LPX *lp, int parm)
+{     /* query integer control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      int val = 0;
+      switch (parm)
+      {  case LPX_K_MSGLEV:
+            val = cps->msg_lev; break;
+         case LPX_K_SCALE:
+            val = cps->scale; break;
+         case LPX_K_DUAL:
+            val = cps->dual; break;
+         case LPX_K_PRICE:
+            val = cps->price; break;
+         case LPX_K_ROUND:
+            val = cps->round; break;
+         case LPX_K_ITLIM:
+            val = cps->it_lim; break;
+         case LPX_K_ITCNT:
+            val = lp->it_cnt; break;
+         case LPX_K_OUTFRQ:
+            val = cps->out_frq; break;
+         case LPX_K_BRANCH:
+            val = cps->branch; break;
+         case LPX_K_BTRACK:
+            val = cps->btrack; break;
+         case LPX_K_MPSINFO:
+            val = cps->mps_info; break;
+         case LPX_K_MPSOBJ:
+            val = cps->mps_obj; break;
+         case LPX_K_MPSORIG:
+            val = cps->mps_orig; break;
+         case LPX_K_MPSWIDE:
+            val = cps->mps_wide; break;
+         case LPX_K_MPSFREE:
+            val = cps->mps_free; break;
+         case LPX_K_MPSSKIP:
+            val = cps->mps_skip; break;
+         case LPX_K_LPTORIG:
+            val = cps->lpt_orig; break;
+         case LPX_K_PRESOL:
+            val = cps->presol; break;
+         case LPX_K_BINARIZE:
+            val = cps->binarize; break;
+         case LPX_K_USECUTS:
+            val = cps->use_cuts; break;
+         case LPX_K_BFTYPE:
+#if 0
+            val = cps->bf_type; break;
+#else
+            {  glp_bfcp parm;
+               glp_get_bfcp(lp, &parm);
+               switch (parm.type)
+               {  case GLP_BF_FT:
+                     val = 1; break;
+                  case GLP_BF_BG:
+                     val = 2; break;
+                  case GLP_BF_GR:
+                     val = 3; break;
+                  default:
+                     xassert(lp != lp);
+               }
+            }
+            break;
+#endif
+         default:
+            xerror("lpx_get_int_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return val;
+}
+
+void lpx_set_real_parm(LPX *lp, int parm, double val)
+{     /* set (change) real control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      switch (parm)
+      {  case LPX_K_RELAX:
+            if (!(0.0 <= val && val <= 1.0))
+               xerror("lpx_set_real_parm: RELAX = %g; invalid value\n",
+                  val);
+            cps->relax = val;
+            break;
+         case LPX_K_TOLBND:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLBND = %g; invalid value\n",
+                  val);
+#if 0
+            if (cps->tol_bnd > val)
+            {  /* invalidate the basic solution */
+               lp->p_stat = LPX_P_UNDEF;
+               lp->d_stat = LPX_D_UNDEF;
+            }
+#endif
+            cps->tol_bnd = val;
+            break;
+         case LPX_K_TOLDJ:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLDJ = %g; invalid value\n",
+                  val);
+#if 0
+            if (cps->tol_dj > val)
+            {  /* invalidate the basic solution */
+               lp->p_stat = LPX_P_UNDEF;
+               lp->d_stat = LPX_D_UNDEF;
+            }
+#endif
+            cps->tol_dj = val;
+            break;
+         case LPX_K_TOLPIV:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLPIV = %g; invalid value\n",
+                  val);
+            cps->tol_piv = val;
+            break;
+         case LPX_K_OBJLL:
+            cps->obj_ll = val;
+            break;
+         case LPX_K_OBJUL:
+            cps->obj_ul = val;
+            break;
+         case LPX_K_TMLIM:
+            cps->tm_lim = val;
+            break;
+         case LPX_K_OUTDLY:
+            cps->out_dly = val;
+            break;
+         case LPX_K_TOLINT:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLINT = %g; invalid value\n",
+                  val);
+            cps->tol_int = val;
+            break;
+         case LPX_K_TOLOBJ:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLOBJ = %g; invalid value\n",
+                  val);
+            cps->tol_obj = val;
+            break;
+         case LPX_K_MIPGAP:
+            if (val < 0.0)
+               xerror("lpx_set_real_parm: MIPGAP = %g; invalid value\n",
+                  val);
+            cps->mip_gap = val;
+            break;
+         default:
+            xerror("lpx_set_real_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return;
+}
+
+double lpx_get_real_parm(LPX *lp, int parm)
+{     /* query real control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      double val = 0.0;
+      switch (parm)
+      {  case LPX_K_RELAX:
+            val = cps->relax;
+            break;
+         case LPX_K_TOLBND:
+            val = cps->tol_bnd;
+            break;
+         case LPX_K_TOLDJ:
+            val = cps->tol_dj;
+            break;
+         case LPX_K_TOLPIV:
+            val = cps->tol_piv;
+            break;
+         case LPX_K_OBJLL:
+            val = cps->obj_ll;
+            break;
+         case LPX_K_OBJUL:
+            val = cps->obj_ul;
+            break;
+         case LPX_K_TMLIM:
+            val = cps->tm_lim;
+            break;
+         case LPX_K_OUTDLY:
+            val = cps->out_dly;
+            break;
+         case LPX_K_TOLINT:
+            val = cps->tol_int;
+            break;
+         case LPX_K_TOLOBJ:
+            val = cps->tol_obj;
+            break;
+         case LPX_K_MIPGAP:
+            val = cps->mip_gap;
+            break;
+         default:
+            xerror("lpx_get_real_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return val;
+}
+
+LPX *lpx_read_mps(const char *fname)
+{     /* read problem data in fixed MPS format */
+      LPX *lp = lpx_create_prob();
+      if (glp_read_mps(lp, GLP_MPS_DECK, NULL, fname))
+         lpx_delete_prob(lp), lp = NULL;
+      return lp;
+}
+
+int lpx_write_mps(LPX *lp, const char *fname)
+{     /* write problem data in fixed MPS format */
+      return glp_write_mps(lp, GLP_MPS_DECK, NULL, fname);
+}
+
+int lpx_read_bas(LPX *lp, const char *fname)
+{     /* read LP basis in fixed MPS format */
+#if 0 /* 13/IV-2009 */
+      return read_bas(lp, fname);
+#else
+      xassert(lp == lp);
+      xassert(fname == fname);
+      xerror("lpx_read_bas: operation not supported\n");
+      return 0;
+#endif
+}
+
+int lpx_write_bas(LPX *lp, const char *fname)
+{     /* write LP basis in fixed MPS format */
+#if 0 /* 13/IV-2009 */
+      return write_bas(lp, fname);
+#else
+      xassert(lp == lp);
+      xassert(fname == fname);
+      xerror("lpx_write_bas: operation not supported\n");
+      return 0;
+#endif
+}
+
+LPX *lpx_read_freemps(const char *fname)
+{     /* read problem data in free MPS format */
+      LPX *lp = lpx_create_prob();
+      if (glp_read_mps(lp, GLP_MPS_FILE, NULL, fname))
+         lpx_delete_prob(lp), lp = NULL;
+      return lp;
+}
+
+int lpx_write_freemps(LPX *lp, const char *fname)
+{     /* write problem data in free MPS format */
+      return glp_write_mps(lp, GLP_MPS_FILE, NULL, fname);
+}
+
+LPX *lpx_read_cpxlp(const char *fname)
+{     /* read problem data in CPLEX LP format */
+      LPX *lp;
+      lp = lpx_create_prob();
+      if (glp_read_lp(lp, NULL, fname))
+         lpx_delete_prob(lp), lp = NULL;
+      return lp;
+}
+
+int lpx_write_cpxlp(LPX *lp, const char *fname)
+{     /* write problem data in CPLEX LP format */
+      return glp_write_lp(lp, NULL, fname);
+}
+
+LPX *lpx_read_model(const char *model, const char *data, const char
+      *output)
+{     /* read LP/MIP model written in GNU MathProg language */
+      LPX *lp = NULL;
+      glp_tran *tran;
+      /* allocate the translator workspace */
+      tran = glp_mpl_alloc_wksp();
+      /* read model section and optional data section */
+      if (glp_mpl_read_model(tran, model, data != NULL)) goto done;
+      /* read separate data section, if required */
+      if (data != NULL)
+         if (glp_mpl_read_data(tran, data)) goto done;
+      /* generate the model */
+      if (glp_mpl_generate(tran, output)) goto done;
+      /* build the problem instance from the model */
+      lp = glp_create_prob();
+      glp_mpl_build_prob(tran, lp);
+done: /* free the translator workspace */
+      glp_mpl_free_wksp(tran);
+      /* bring the problem object to the calling program */
+      return lp;
+}
+
+int lpx_print_prob(LPX *lp, const char *fname)
+{     /* write problem data in plain text format */
+      return glp_write_lp(lp, NULL, fname);
+}
+
+int lpx_print_sol(LPX *lp, const char *fname)
+{     /* write LP problem solution in printable format */
+      return glp_print_sol(lp, fname);
+}
+
+int lpx_print_sens_bnds(LPX *lp, const char *fname)
+{     /* write bounds sensitivity information */
+      if (glp_get_status(lp) == GLP_OPT && !glp_bf_exists(lp))
+         glp_factorize(lp);
+      return glp_print_ranges(lp, 0, NULL, 0, fname);
+}
+
+int lpx_print_ips(LPX *lp, const char *fname)
+{     /* write interior point solution in printable format */
+      return glp_print_ipt(lp, fname);
+}
+
+int lpx_print_mip(LPX *lp, const char *fname)
+{     /* write MIP problem solution in printable format */
+      return glp_print_mip(lp, fname);
+}
+
+int lpx_is_b_avail(glp_prob *lp)
+{     /* check if LP basis is available */
+      return glp_bf_exists(lp);
+}
+
+int lpx_main(int argc, const char *argv[])
+{     /* stand-alone LP/MIP solver */
+      return glp_main(argc, argv);
+}
+
+/* eof */
diff --git a/optional/glpk/glplpx02.c b/optional/glpk/glplpx02.c
new file mode 100644
index 0000000..9340137
--- /dev/null
+++ b/optional/glpk/glplpx02.c
@@ -0,0 +1,268 @@
+/* glplpx02.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  lpx_put_solution - store basic solution components
+*
+*  SYNOPSIS
+*
+*  void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
+*     const int *d_stat, const double *obj_val, const int r_stat[],
+*     const double r_prim[], const double r_dual[], const int c_stat[],
+*     const double c_prim[], const double c_dual[])
+*
+*  DESCRIPTION
+*
+*  The routine lpx_put_solution stores basic solution components to the
+*  specified problem object.
+*
+*  The parameter inval is the basis factorization invalidity flag.
+*  If this flag is clear, the current status of the basis factorization
+*  remains unchanged. If this flag is set, the routine invalidates the
+*  basis factorization.
+*
+*  The parameter p_stat is a pointer to the status of primal basic
+*  solution, which should be specified as follows:
+*
+*  GLP_UNDEF  - primal solution is undefined;
+*  GLP_FEAS   - primal solution is feasible;
+*  GLP_INFEAS - primal solution is infeasible;
+*  GLP_NOFEAS - no primal feasible solution exists.
+*
+*  If the parameter p_stat is NULL, the current status of primal basic
+*  solution remains unchanged.
+*
+*  The parameter d_stat is a pointer to the status of dual basic
+*  solution, which should be specified as follows:
+*
+*  GLP_UNDEF  - dual solution is undefined;
+*  GLP_FEAS   - dual solution is feasible;
+*  GLP_INFEAS - dual solution is infeasible;
+*  GLP_NOFEAS - no dual feasible solution exists.
+*
+*  If the parameter d_stat is NULL, the current status of dual basic
+*  solution remains unchanged.
+*
+*  The parameter obj_val is a pointer to the objective function value.
+*  If it is NULL, the current value of the objective function remains
+*  unchanged.
+*
+*  The array element r_stat[i], 1 <= i <= m (where m is the number of
+*  rows in the problem object), specifies the status of i-th auxiliary
+*  variable, which should be specified as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on lower bound;
+*  GLP_NU - non-basic variable on upper bound;
+*  GLP_NF - non-basic free variable;
+*  GLP_NS - non-basic fixed variable.
+*
+*  If the parameter r_stat is NULL, the current statuses of auxiliary
+*  variables remain unchanged.
+*
+*  The array element r_prim[i], 1 <= i <= m (where m is the number of
+*  rows in the problem object), specifies a primal value of i-th
+*  auxiliary variable. If the parameter r_prim is NULL, the current
+*  primal values of auxiliary variables remain unchanged.
+*
+*  The array element r_dual[i], 1 <= i <= m (where m is the number of
+*  rows in the problem object), specifies a dual value (reduced cost)
+*  of i-th auxiliary variable. If the parameter r_dual is NULL, the
+*  current dual values of auxiliary variables remain unchanged.
+*
+*  The array element c_stat[j], 1 <= j <= n (where n is the number of
+*  columns in the problem object), specifies the status of j-th
+*  structural variable, which should be specified as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on lower bound;
+*  GLP_NU - non-basic variable on upper bound;
+*  GLP_NF - non-basic free variable;
+*  GLP_NS - non-basic fixed variable.
+*
+*  If the parameter c_stat is NULL, the current statuses of structural
+*  variables remain unchanged.
+*
+*  The array element c_prim[j], 1 <= j <= n (where n is the number of
+*  columns in the problem object), specifies a primal value of j-th
+*  structural variable. If the parameter c_prim is NULL, the current
+*  primal values of structural variables remain unchanged.
+*
+*  The array element c_dual[j], 1 <= j <= n (where n is the number of
+*  columns in the problem object), specifies a dual value (reduced cost)
+*  of j-th structural variable. If the parameter c_dual is NULL, the
+*  current dual values of structural variables remain unchanged. */
+
+void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
+      const int *d_stat, const double *obj_val, const int r_stat[],
+      const double r_prim[], const double r_dual[], const int c_stat[],
+      const double c_prim[], const double c_dual[])
+{     GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      /* invalidate the basis factorization, if required */
+      if (inval) lp->valid = 0;
+      /* store primal status */
+      if (p_stat != NULL)
+      {  if (!(*p_stat == GLP_UNDEF  || *p_stat == GLP_FEAS ||
+               *p_stat == GLP_INFEAS || *p_stat == GLP_NOFEAS))
+            xerror("lpx_put_solution: p_stat = %d; invalid primal statu"
+               "s\n", *p_stat);
+         lp->pbs_stat = *p_stat;
+      }
+      /* store dual status */
+      if (d_stat != NULL)
+      {  if (!(*d_stat == GLP_UNDEF  || *d_stat == GLP_FEAS ||
+               *d_stat == GLP_INFEAS || *d_stat == GLP_NOFEAS))
+            xerror("lpx_put_solution: d_stat = %d; invalid dual status "
+               "\n", *d_stat);
+         lp->dbs_stat = *d_stat;
+      }
+      /* store objective function value */
+      if (obj_val != NULL) lp->obj_val = *obj_val;
+      /* store row solution components */
+      for (i = 1; i <= lp->m; i++)
+      {  row = lp->row[i];
+         if (r_stat != NULL)
+         {  if (!(r_stat[i] == GLP_BS ||
+                  row->type == GLP_FR && r_stat[i] == GLP_NF ||
+                  row->type == GLP_LO && r_stat[i] == GLP_NL ||
+                  row->type == GLP_UP && r_stat[i] == GLP_NU ||
+                  row->type == GLP_DB && r_stat[i] == GLP_NL ||
+                  row->type == GLP_DB && r_stat[i] == GLP_NU ||
+                  row->type == GLP_FX && r_stat[i] == GLP_NS))
+               xerror("lpx_put_solution: r_stat[%d] = %d; invalid row s"
+                  "tatus\n", i, r_stat[i]);
+            row->stat = r_stat[i];
+         }
+         if (r_prim != NULL) row->prim = r_prim[i];
+         if (r_dual != NULL) row->dual = r_dual[i];
+      }
+      /* store column solution components */
+      for (j = 1; j <= lp->n; j++)
+      {  col = lp->col[j];
+         if (c_stat != NULL)
+         {  if (!(c_stat[j] == GLP_BS ||
+                  col->type == GLP_FR && c_stat[j] == GLP_NF ||
+                  col->type == GLP_LO && c_stat[j] == GLP_NL ||
+                  col->type == GLP_UP && c_stat[j] == GLP_NU ||
+                  col->type == GLP_DB && c_stat[j] == GLP_NL ||
+                  col->type == GLP_DB && c_stat[j] == GLP_NU ||
+                  col->type == GLP_FX && c_stat[j] == GLP_NS))
+               xerror("lpx_put_solution: c_stat[%d] = %d; invalid colum"
+                  "n status\n", j, c_stat[j]);
+            col->stat = c_stat[j];
+         }
+         if (c_prim != NULL) col->prim = c_prim[j];
+         if (c_dual != NULL) col->dual = c_dual[j];
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_put_mip_soln - store mixed integer solution components.
+--
+-- *Synopsis*
+--
+-- #include "glplpx.h"
+-- void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
+--    double col_mipx[]);
+--
+-- *Description*
+--
+-- The routine lpx_put_mip_soln stores solution components obtained by
+-- branch-and-bound solver into the specified problem object.
+--
+-- NOTE: This routine is intended for internal use only. */
+
+void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
+      double col_mipx[])
+{     GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      double sum;
+      /* store mixed integer status */
+#if 0
+      if (!(i_stat == LPX_I_UNDEF || i_stat == LPX_I_OPT ||
+            i_stat == LPX_I_FEAS  || i_stat == LPX_I_NOFEAS))
+         fault("lpx_put_mip_soln: i_stat = %d; invalid mixed integer st"
+            "atus", i_stat);
+      lp->i_stat = i_stat;
+#else
+      switch (i_stat)
+      {  case LPX_I_UNDEF:
+            lp->mip_stat = GLP_UNDEF; break;
+         case LPX_I_OPT:
+            lp->mip_stat = GLP_OPT;  break;
+         case LPX_I_FEAS:
+            lp->mip_stat = GLP_FEAS; break;
+         case LPX_I_NOFEAS:
+            lp->mip_stat = GLP_NOFEAS; break;
+         default:
+            xerror("lpx_put_mip_soln: i_stat = %d; invalid mixed intege"
+               "r status\n", i_stat);
+      }
+#endif
+      /* store row solution components */
+      if (row_mipx != NULL)
+      {  for (i = 1; i <= lp->m; i++)
+         {  row = lp->row[i];
+            row->mipx = row_mipx[i];
+         }
+      }
+      /* store column solution components */
+      if (col_mipx != NULL)
+      {  for (j = 1; j <= lp->n; j++)
+         {  col = lp->col[j];
+            col->mipx = col_mipx[j];
+         }
+      }
+      /* if the solution is claimed to be integer feasible, check it */
+      if (lp->mip_stat == GLP_OPT || lp->mip_stat == GLP_FEAS)
+      {  for (j = 1; j <= lp->n; j++)
+         {  col = lp->col[j];
+            if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
+               xerror("lpx_put_mip_soln: col_mipx[%d] = %.*g; must be i"
+                  "ntegral\n", j, DBL_DIG, col->mipx);
+         }
+      }
+      /* compute the objective function value */
+      sum = lp->c0;
+      for (j = 1; j <= lp->n; j++)
+      {  col = lp->col[j];
+         sum += col->coef * col->mipx;
+      }
+      lp->mip_obj = sum;
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glplpx03.c b/optional/glpk/glplpx03.c
new file mode 100644
index 0000000..b15e64d
--- /dev/null
+++ b/optional/glpk/glplpx03.c
@@ -0,0 +1,302 @@
+/* glplpx03.c (OPB format) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Author: Oscar Gustafsson <oscarg at isy.liu.se>.
+*
+*  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/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpapi.h"
+#if 0 /* 24/XII-2009; by mao */
+#include "glpipp.h"
+#endif
+
+/*----------------------------------------------------------------------
+-- lpx_write_pb - write problem data in (normalized) OPB format.
+--
+-- *Synopsis*
+--
+-- #include "glplpx.h"
+-- int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+--    int binarize);
+--
+-- *Description*
+--
+-- The routine lpx_write_pb writes problem data in OPB format
+-- to an output text file whose name is the character string fname.
+-- If normalized is non-zero the output will be generated in a
+-- normalized form with sequentially numbered variables, x1, x2 etc.
+-- If binarize, any integer variable will be repalzec by binary ones,
+-- see ipp_binarize
+--
+-- *Returns*
+--
+-- If the operation was successful, the routine returns zero. Otherwise
+-- the routine prints an error message and returns non-zero. */
+
+#if 1 /* 24/XII-2009; by mao (disabled, because IPP was removed) */
+int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+      int binarize)
+{     xassert(lp == lp);
+      xassert(fname == fname);
+      xassert(normalized == normalized);
+      xassert(binarize == binarize);
+      xprintf("lpx_write_pb: sorry, currently this operation is not ava"
+         "ilable\n");
+      return 1;
+}
+#else
+int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+      int binarize)
+{
+  FILE* fp;
+  int m,n,i,j,k,o,nonfree=0, obj_dir, dbl, *ndx, row_type, emptylhs=0;
+  double coeff, *val, bound, constant/*=0.0*/;
+  char* objconstname = "dummy_one";
+  char* emptylhsname = "dummy_zero";
+
+  /* Variables needed for possible binarization */
+  /*LPX* tlp;*/
+  IPP *ipp = NULL;
+  /*tlp=lp;*/
+
+  if(binarize) /* Transform integer variables to binary ones */
+    {
+      ipp = ipp_create_wksp();
+      ipp_load_orig(ipp, lp);
+      ipp_binarize(ipp);
+      lp = ipp_build_prob(ipp);
+    }
+  fp = fopen(fname, "w");
+
+  if(fp!= NULL)
+    {
+      xprintf(
+          "lpx_write_pb: writing problem in %sOPB format to `%s'...\n",
+              (normalized?"normalized ":""), fname);
+
+      m = glp_get_num_rows(lp);
+      n = glp_get_num_cols(lp);
+      for(i=1;i<=m;i++)
+        {
+          switch(glp_get_row_type(lp,i))
+            {
+            case GLP_LO:
+            case GLP_UP:
+            case GLP_FX:
+              {
+                nonfree += 1;
+                break;
+              }
+            case GLP_DB:
+              {
+                nonfree += 2;
+                break;
+              }
+            }
+        }
+      constant=glp_get_obj_coef(lp,0);
+      fprintf(fp,"* #variables = %d #constraints = %d\n",
+         n + (constant == 0?1:0), nonfree + (constant == 0?1:0));
+      /* Objective function */
+      obj_dir = glp_get_obj_dir(lp);
+      fprintf(fp,"min: ");
+      for(i=1;i<=n;i++)
+        {
+          coeff = glp_get_obj_coef(lp,i);
+          if(coeff != 0.0)
+            {
+              if(obj_dir == GLP_MAX)
+                coeff=-coeff;
+              if(normalized)
+                fprintf(fp, " %d x%d", (int)coeff, i);
+              else
+                fprintf(fp, " %d*%s", (int)coeff,
+                  glp_get_col_name(lp,i));
+
+            }
+        }
+      if(constant)
+        {
+          if(normalized)
+            fprintf(fp, " %d x%d", (int)constant, n+1);
+          else
+            fprintf(fp, " %d*%s", (int)constant, objconstname);
+        }
+      fprintf(fp,";\n");
+
+      if(normalized && !binarize)  /* Name substitution */
+        {
+          fprintf(fp,"* Variable name substitution:\n");
+          for(j=1;j<=n;j++)
+            {
+              fprintf(fp, "* x%d = %s\n", j, glp_get_col_name(lp,j));
+            }
+          if(constant)
+            fprintf(fp, "* x%d = %s\n", n+1, objconstname);
+        }
+
+      ndx = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+
+      /* Constraints */
+      for(j=1;j<=m;j++)
+        {
+          row_type=glp_get_row_type(lp,j);
+          if(row_type!=GLP_FR)
+            {
+              if(row_type == GLP_DB)
+                {
+                  dbl=2;
+                  row_type = GLP_UP;
+                }
+              else
+                {
+                  dbl=1;
+                }
+              k=glp_get_mat_row(lp, j, ndx, val);
+              for(o=1;o<=dbl;o++)
+                {
+                  if(o==2)
+                    {
+                      row_type = GLP_LO;
+                    }
+                  if(k==0) /* Empty LHS */
+                    {
+                      emptylhs = 1;
+                      if(normalized)
+                        {
+                          fprintf(fp, "0 x%d ", n+2);
+                        }
+                      else
+                        {
+                          fprintf(fp, "0*%s ", emptylhsname);
+                        }
+                    }
+
+                  for(i=1;i<=k;i++)
+                    {
+                      if(val[i] != 0.0)
+                        {
+
+                          if(normalized)
+                            {
+                              fprintf(fp, "%d x%d ",
+              (row_type==GLP_UP)?(-(int)val[i]):((int)val[i]), ndx[i]);
+                            }
+                          else
+                            {
+                              fprintf(fp, "%d*%s ", (int)val[i],
+                                      glp_get_col_name(lp,ndx[i]));
+                            }
+                        }
+                    }
+                  switch(row_type)
+                    {
+                    case GLP_LO:
+                      {
+                        fprintf(fp, ">=");
+                        bound = glp_get_row_lb(lp,j);
+                        break;
+                      }
+                    case GLP_UP:
+                      {
+                        if(normalized)
+                          {
+                            fprintf(fp, ">=");
+                            bound = -glp_get_row_ub(lp,j);
+                          }
+                        else
+                          {
+                            fprintf(fp, "<=");
+                            bound = glp_get_row_ub(lp,j);
+                          }
+
+                        break;
+                      }
+                    case GLP_FX:
+                      {
+                        fprintf(fp, "=");
+                        bound = glp_get_row_lb(lp,j);
+                        break;
+                      }
+                    }
+                  fprintf(fp," %d;\n",(int)bound);
+                }
+            }
+        }
+      xfree(ndx);
+      xfree(val);
+
+      if(constant)
+        {
+          xprintf(
+        "lpx_write_pb: adding constant objective function variable\n");
+
+          if(normalized)
+            fprintf(fp, "1 x%d = 1;\n", n+1);
+          else
+            fprintf(fp, "1*%s = 1;\n", objconstname);
+        }
+      if(emptylhs)
+        {
+          xprintf(
+            "lpx_write_pb: adding dummy variable for empty left-hand si"
+            "de constraint\n");
+
+          if(normalized)
+            fprintf(fp, "1 x%d = 0;\n", n+2);
+          else
+            fprintf(fp, "1*%s = 0;\n", emptylhsname);
+        }
+
+    }
+  else
+    {
+      xprintf("Problems opening file for writing: %s\n", fname);
+      return(1);
+    }
+  fflush(fp);
+  if (ferror(fp))
+    {  xprintf("lpx_write_pb: can't write to `%s' - %s\n", fname,
+               strerror(errno));
+    goto fail;
+    }
+  fclose(fp);
+
+
+  if(binarize)
+    {
+      /* delete the resultant problem object */
+      if (lp != NULL) lpx_delete_prob(lp);
+      /* delete MIP presolver workspace */
+      if (ipp != NULL) ipp_delete_wksp(ipp);
+      /*lp=tlp;*/
+    }
+  return 0;
+ fail: if (fp != NULL) fclose(fp);
+  return 1;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpluf.c b/optional/glpk/glpluf.c
new file mode 100644
index 0000000..1fbd64a
--- /dev/null
+++ b/optional/glpk/glpluf.c
@@ -0,0 +1,1851 @@
+/* glpluf.c (LU-factorization) */
+
+/***********************************************************************
+*  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 "-Wself-assign"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "glpenv.h"
+#include "glpluf.h"
+#define xfault xerror
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define N_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the original matrix */
+
+/***********************************************************************
+*  NAME
+*
+*  luf_create_it - create LU-factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  LUF *luf_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine luf_create_it creates a program object, which represents
+*  LU-factorization of a square matrix.
+*
+*  RETURNS
+*
+*  The routine luf_create_it returns a pointer to the object created. */
+
+LUF *luf_create_it(void)
+{     LUF *luf;
+      luf = xmalloc(sizeof(LUF));
+      luf->n_max = luf->n = 0;
+      luf->valid = 0;
+      luf->fr_ptr = luf->fr_len = NULL;
+      luf->fc_ptr = luf->fc_len = NULL;
+      luf->vr_ptr = luf->vr_len = luf->vr_cap = NULL;
+      luf->vr_piv = NULL;
+      luf->vc_ptr = luf->vc_len = luf->vc_cap = NULL;
+      luf->pp_row = luf->pp_col = NULL;
+      luf->qq_row = luf->qq_col = NULL;
+      luf->sv_size = 0;
+      luf->sv_beg = luf->sv_end = 0;
+      luf->sv_ind = NULL;
+      luf->sv_val = NULL;
+      luf->sv_head = luf->sv_tail = 0;
+      luf->sv_prev = luf->sv_next = NULL;
+      luf->vr_max = NULL;
+      luf->rs_head = luf->rs_prev = luf->rs_next = NULL;
+      luf->cs_head = luf->cs_prev = luf->cs_next = NULL;
+      luf->flag = NULL;
+      luf->work = NULL;
+      luf->new_sva = 0;
+      luf->piv_tol = 0.10;
+      luf->piv_lim = 4;
+      luf->suhl = 1;
+      luf->eps_tol = 1e-15;
+      luf->max_gro = 1e+10;
+      luf->nnz_a = luf->nnz_f = luf->nnz_v = 0;
+      luf->max_a = luf->big_v = 0.0;
+      luf->rank = 0;
+      return luf;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_defrag_sva - defragment the sparse vector area
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_defrag_sva(LUF *luf);
+*
+*  DESCRIPTION
+*
+*  The routine luf_defrag_sva defragments the sparse vector area (SVA)
+*  gathering all unused locations in one continuous extent. In order to
+*  do that the routine moves all unused locations from the left part of
+*  SVA (which contains rows and columns of the matrix V) to the middle
+*  part (which contains free locations). This is attained by relocating
+*  elements of rows and columns of the matrix V toward the beginning of
+*  the left part.
+*
+*  NOTE that this "garbage collection" involves changing row and column
+*  pointers of the matrix V. */
+
+void luf_defrag_sva(LUF *luf)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_next = luf->sv_next;
+      int sv_beg = 1;
+      int i, j, k;
+      /* skip rows and columns, which do not need to be relocated */
+      for (k = luf->sv_head; k != 0; k = sv_next[k])
+      {  if (k <= n)
+         {  /* i-th row of the matrix V */
+            i = k;
+            if (vr_ptr[i] != sv_beg) break;
+            vr_cap[i] = vr_len[i];
+            sv_beg += vr_cap[i];
+         }
+         else
+         {  /* j-th column of the matrix V */
+            j = k - n;
+            if (vc_ptr[j] != sv_beg) break;
+            vc_cap[j] = vc_len[j];
+            sv_beg += vc_cap[j];
+         }
+      }
+      /* relocate other rows and columns in order to gather all unused
+         locations in one continuous extent */
+      for (k = k; k != 0; k = sv_next[k])
+      {  if (k <= n)
+         {  /* i-th row of the matrix V */
+            i = k;
+            memmove(&sv_ind[sv_beg], &sv_ind[vr_ptr[i]],
+               vr_len[i] * sizeof(int));
+            memmove(&sv_val[sv_beg], &sv_val[vr_ptr[i]],
+               vr_len[i] * sizeof(double));
+            vr_ptr[i] = sv_beg;
+            vr_cap[i] = vr_len[i];
+            sv_beg += vr_cap[i];
+         }
+         else
+         {  /* j-th column of the matrix V */
+            j = k - n;
+            memmove(&sv_ind[sv_beg], &sv_ind[vc_ptr[j]],
+               vc_len[j] * sizeof(int));
+            memmove(&sv_val[sv_beg], &sv_val[vc_ptr[j]],
+               vc_len[j] * sizeof(double));
+            vc_ptr[j] = sv_beg;
+            vc_cap[j] = vc_len[j];
+            sv_beg += vc_cap[j];
+         }
+      }
+      /* set new pointer to the beginning of the free part */
+      luf->sv_beg = sv_beg;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_enlarge_row - enlarge row capacity
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  int luf_enlarge_row(LUF *luf, int i, int cap);
+*
+*  DESCRIPTION
+*
+*  The routine luf_enlarge_row enlarges capacity of the i-th row of the
+*  matrix V to cap locations (assuming that its current capacity is less
+*  than cap). In order to do that the routine relocates elements of the
+*  i-th row to the end of the left part of SVA (which contains rows and
+*  columns of the matrix V) and then expands the left part by allocating
+*  cap free locations from the free part. If there are less than cap
+*  free locations, the routine defragments the sparse vector area.
+*
+*  Due to "garbage collection" this operation may change row and column
+*  pointers of the matrix V.
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+int luf_enlarge_row(LUF *luf, int i, int cap)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      int ret = 0;
+      int cur, k, kk;
+      xassert(1 <= i && i <= n);
+      xassert(vr_cap[i] < cap);
+      /* if there are less than cap free locations, defragment SVA */
+      if (luf->sv_end - luf->sv_beg < cap)
+      {  luf_defrag_sva(luf);
+         if (luf->sv_end - luf->sv_beg < cap)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* save current capacity of the i-th row */
+      cur = vr_cap[i];
+      /* copy existing elements to the beginning of the free part */
+      memmove(&sv_ind[luf->sv_beg], &sv_ind[vr_ptr[i]],
+         vr_len[i] * sizeof(int));
+      memmove(&sv_val[luf->sv_beg], &sv_val[vr_ptr[i]],
+         vr_len[i] * sizeof(double));
+      /* set new pointer and new capacity of the i-th row */
+      vr_ptr[i] = luf->sv_beg;
+      vr_cap[i] = cap;
+      /* set new pointer to the beginning of the free part */
+      luf->sv_beg += cap;
+      /* now the i-th row starts in the rightmost location among other
+         rows and columns of the matrix V, so its node should be moved
+         to the end of the row/column linked list */
+      k = i;
+      /* remove the i-th row node from the linked list */
+      if (sv_prev[k] == 0)
+         luf->sv_head = sv_next[k];
+      else
+      {  /* capacity of the previous row/column can be increased at the
+            expense of old locations of the i-th row */
+         kk = sv_prev[k];
+         if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
+         sv_next[sv_prev[k]] = sv_next[k];
+      }
+      if (sv_next[k] == 0)
+         luf->sv_tail = sv_prev[k];
+      else
+         sv_prev[sv_next[k]] = sv_prev[k];
+      /* insert the i-th row node to the end of the linked list */
+      sv_prev[k] = luf->sv_tail;
+      sv_next[k] = 0;
+      if (sv_prev[k] == 0)
+         luf->sv_head = k;
+      else
+         sv_next[sv_prev[k]] = k;
+      luf->sv_tail = k;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_enlarge_col - enlarge column capacity
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  int luf_enlarge_col(LUF *luf, int j, int cap);
+*
+*  DESCRIPTION
+*
+*  The routine luf_enlarge_col enlarges capacity of the j-th column of
+*  the matrix V to cap locations (assuming that its current capacity is
+*  less than cap). In order to do that the routine relocates elements
+*  of the j-th column to the end of the left part of SVA (which contains
+*  rows and columns of the matrix V) and then expands the left part by
+*  allocating cap free locations from the free part. If there are less
+*  than cap free locations, the routine defragments the sparse vector
+*  area.
+*
+*  Due to "garbage collection" this operation may change row and column
+*  pointers of the matrix V.
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+int luf_enlarge_col(LUF *luf, int j, int cap)
+{     int n = luf->n;
+      int *vr_cap = luf->vr_cap;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      int ret = 0;
+      int cur, k, kk;
+      xassert(1 <= j && j <= n);
+      xassert(vc_cap[j] < cap);
+      /* if there are less than cap free locations, defragment SVA */
+      if (luf->sv_end - luf->sv_beg < cap)
+      {  luf_defrag_sva(luf);
+         if (luf->sv_end - luf->sv_beg < cap)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* save current capacity of the j-th column */
+      cur = vc_cap[j];
+      /* copy existing elements to the beginning of the free part */
+      memmove(&sv_ind[luf->sv_beg], &sv_ind[vc_ptr[j]],
+         vc_len[j] * sizeof(int));
+      memmove(&sv_val[luf->sv_beg], &sv_val[vc_ptr[j]],
+         vc_len[j] * sizeof(double));
+      /* set new pointer and new capacity of the j-th column */
+      vc_ptr[j] = luf->sv_beg;
+      vc_cap[j] = cap;
+      /* set new pointer to the beginning of the free part */
+      luf->sv_beg += cap;
+      /* now the j-th column starts in the rightmost location among
+         other rows and columns of the matrix V, so its node should be
+         moved to the end of the row/column linked list */
+      k = n + j;
+      /* remove the j-th column node from the linked list */
+      if (sv_prev[k] == 0)
+         luf->sv_head = sv_next[k];
+      else
+      {  /* capacity of the previous row/column can be increased at the
+            expense of old locations of the j-th column */
+         kk = sv_prev[k];
+         if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
+         sv_next[sv_prev[k]] = sv_next[k];
+      }
+      if (sv_next[k] == 0)
+         luf->sv_tail = sv_prev[k];
+      else
+         sv_prev[sv_next[k]] = sv_prev[k];
+      /* insert the j-th column node to the end of the linked list */
+      sv_prev[k] = luf->sv_tail;
+      sv_next[k] = 0;
+      if (sv_prev[k] == 0)
+         luf->sv_head = k;
+      else
+         sv_next[sv_prev[k]] = k;
+      luf->sv_tail = k;
+done: return ret;
+}
+
+/***********************************************************************
+*  reallocate - reallocate LU-factorization arrays
+*
+*  This routine reallocates arrays, whose size depends of n, the order
+*  of the matrix A to be factorized. */
+
+static void reallocate(LUF *luf, int n)
+{     int n_max = luf->n_max;
+      luf->n = n;
+      if (n <= n_max) goto done;
+      if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
+      if (luf->fr_len != NULL) xfree(luf->fr_len);
+      if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
+      if (luf->fc_len != NULL) xfree(luf->fc_len);
+      if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
+      if (luf->vr_len != NULL) xfree(luf->vr_len);
+      if (luf->vr_cap != NULL) xfree(luf->vr_cap);
+      if (luf->vr_piv != NULL) xfree(luf->vr_piv);
+      if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
+      if (luf->vc_len != NULL) xfree(luf->vc_len);
+      if (luf->vc_cap != NULL) xfree(luf->vc_cap);
+      if (luf->pp_row != NULL) xfree(luf->pp_row);
+      if (luf->pp_col != NULL) xfree(luf->pp_col);
+      if (luf->qq_row != NULL) xfree(luf->qq_row);
+      if (luf->qq_col != NULL) xfree(luf->qq_col);
+      if (luf->sv_prev != NULL) xfree(luf->sv_prev);
+      if (luf->sv_next != NULL) xfree(luf->sv_next);
+      if (luf->vr_max != NULL) xfree(luf->vr_max);
+      if (luf->rs_head != NULL) xfree(luf->rs_head);
+      if (luf->rs_prev != NULL) xfree(luf->rs_prev);
+      if (luf->rs_next != NULL) xfree(luf->rs_next);
+      if (luf->cs_head != NULL) xfree(luf->cs_head);
+      if (luf->cs_prev != NULL) xfree(luf->cs_prev);
+      if (luf->cs_next != NULL) xfree(luf->cs_next);
+      if (luf->flag != NULL) xfree(luf->flag);
+      if (luf->work != NULL) xfree(luf->work);
+      luf->n_max = n_max = n + 100;
+      luf->fr_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->fr_len = xcalloc(1+n_max, sizeof(int));
+      luf->fc_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->fc_len = xcalloc(1+n_max, sizeof(int));
+      luf->vr_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->vr_len = xcalloc(1+n_max, sizeof(int));
+      luf->vr_cap = xcalloc(1+n_max, sizeof(int));
+      luf->vr_piv = xcalloc(1+n_max, sizeof(double));
+      luf->vc_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->vc_len = xcalloc(1+n_max, sizeof(int));
+      luf->vc_cap = xcalloc(1+n_max, sizeof(int));
+      luf->pp_row = xcalloc(1+n_max, sizeof(int));
+      luf->pp_col = xcalloc(1+n_max, sizeof(int));
+      luf->qq_row = xcalloc(1+n_max, sizeof(int));
+      luf->qq_col = xcalloc(1+n_max, sizeof(int));
+      luf->sv_prev = xcalloc(1+n_max+n_max, sizeof(int));
+      luf->sv_next = xcalloc(1+n_max+n_max, sizeof(int));
+      luf->vr_max = xcalloc(1+n_max, sizeof(double));
+      luf->rs_head = xcalloc(1+n_max, sizeof(int));
+      luf->rs_prev = xcalloc(1+n_max, sizeof(int));
+      luf->rs_next = xcalloc(1+n_max, sizeof(int));
+      luf->cs_head = xcalloc(1+n_max, sizeof(int));
+      luf->cs_prev = xcalloc(1+n_max, sizeof(int));
+      luf->cs_next = xcalloc(1+n_max, sizeof(int));
+      luf->flag = xcalloc(1+n_max, sizeof(int));
+      luf->work = xcalloc(1+n_max, sizeof(double));
+done: return;
+}
+
+/***********************************************************************
+*  initialize - initialize LU-factorization data structures
+*
+*  This routine initializes data structures for subsequent computing
+*  the LU-factorization of a given matrix A, which is specified by the
+*  formal routine col. On exit V = A and F = P = Q = I, where I is the
+*  unity matrix. (Row-wise representation of the matrix F is not used
+*  at the factorization stage and therefore is not initialized.)
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int initialize(LUF *luf, int (*col)(void *info, int j, int rn[],
+      double aj[]), void *info)
+{     int n = luf->n;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *pp_row = luf->pp_row;
+      int *pp_col = luf->pp_col;
+      int *qq_row = luf->qq_row;
+      int *qq_col = luf->qq_col;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      double *vr_max = luf->vr_max;
+      int *rs_head = luf->rs_head;
+      int *rs_prev = luf->rs_prev;
+      int *rs_next = luf->rs_next;
+      int *cs_head = luf->cs_head;
+      int *cs_prev = luf->cs_prev;
+      int *cs_next = luf->cs_next;
+      int *flag = luf->flag;
+      double *work = luf->work;
+      int ret = 0;
+      int i, i_ptr, j, j_beg, j_end, k, len, nnz, sv_beg, sv_end, ptr;
+      double big, val;
+      /* free all locations of the sparse vector area */
+      sv_beg = 1;
+      sv_end = luf->sv_size + 1;
+      /* (row-wise representation of the matrix F is not initialized,
+         because it is not used at the factorization stage) */
+      /* build the matrix F in column-wise format (initially F = I) */
+      for (j = 1; j <= n; j++)
+      {  fc_ptr[j] = sv_end;
+         fc_len[j] = 0;
+      }
+      /* clear rows of the matrix V; clear the flag array */
+      for (i = 1; i <= n; i++)
+         vr_len[i] = vr_cap[i] = 0, flag[i] = 0;
+      /* build the matrix V in column-wise format (initially V = A);
+         count non-zeros in rows of this matrix; count total number of
+         non-zeros; compute largest of absolute values of elements */
+      nnz = 0;
+      big = 0.0;
+      for (j = 1; j <= n; j++)
+      {  int *rn = pp_row;
+         double *aj = work;
+         /* obtain j-th column of the matrix A */
+         len = col(info, j, rn, aj);
+         if (!(0 <= len && len <= n))
+            xfault("luf_factorize: j = %d; len = %d; invalid column len"
+               "gth\n", j, len);
+         /* check for free locations */
+         if (sv_end - sv_beg < len)
+         {  /* overflow of the sparse vector area */
+            ret = 1;
+            goto done;
+         }
+         /* set pointer to the j-th column */
+         vc_ptr[j] = sv_beg;
+         /* set length of the j-th column */
+         vc_len[j] = vc_cap[j] = len;
+         /* count total number of non-zeros */
+         nnz += len;
+         /* walk through elements of the j-th column */
+         for (ptr = 1; ptr <= len; ptr++)
+         {  /* get row index and numerical value of a[i,j] */
+            i = rn[ptr];
+            val = aj[ptr];
+            if (!(1 <= i && i <= n))
+               xfault("luf_factorize: i = %d; j = %d; invalid row index"
+                  "\n", i, j);
+            if (flag[i])
+               xfault("luf_factorize: i = %d; j = %d; duplicate element"
+                  " not allowed\n", i, j);
+            if (val == 0.0)
+               xfault("luf_factorize: i = %d; j = %d; zero element not "
+                  "allowed\n", i, j);
+            /* add new element v[i,j] = a[i,j] to j-th column */
+            sv_ind[sv_beg] = i;
+            sv_val[sv_beg] = val;
+            sv_beg++;
+            /* big := max(big, |a[i,j]|) */
+            if (val < 0.0) val = - val;
+            if (big < val) big = val;
+            /* mark non-zero in the i-th position of the j-th column */
+            flag[i] = 1;
+            /* increase length of the i-th row */
+            vr_cap[i]++;
+         }
+         /* reset all non-zero marks */
+         for (ptr = 1; ptr <= len; ptr++) flag[rn[ptr]] = 0;
+      }
+      /* allocate rows of the matrix V */
+      for (i = 1; i <= n; i++)
+      {  /* get length of the i-th row */
+         len = vr_cap[i];
+         /* check for free locations */
+         if (sv_end - sv_beg < len)
+         {  /* overflow of the sparse vector area */
+            ret = 1;
+            goto done;
+         }
+         /* set pointer to the i-th row */
+         vr_ptr[i] = sv_beg;
+         /* reserve locations for the i-th row */
+         sv_beg += len;
+      }
+      /* build the matrix V in row-wise format using representation of
+         this matrix in column-wise format */
+      for (j = 1; j <= n; j++)
+      {  /* walk through elements of the j-th column */
+         j_beg = vc_ptr[j];
+         j_end = j_beg + vc_len[j] - 1;
+         for (k = j_beg; k <= j_end; k++)
+         {  /* get row index and numerical value of v[i,j] */
+            i = sv_ind[k];
+            val = sv_val[k];
+            /* store element in the i-th row */
+            i_ptr = vr_ptr[i] + vr_len[i];
+            sv_ind[i_ptr] = j;
+            sv_val[i_ptr] = val;
+            /* increase count of the i-th row */
+            vr_len[i]++;
+         }
+      }
+      /* initialize the matrices P and Q (initially P = Q = I) */
+      for (k = 1; k <= n; k++)
+         pp_row[k] = pp_col[k] = qq_row[k] = qq_col[k] = k;
+      /* set sva partitioning pointers */
+      luf->sv_beg = sv_beg;
+      luf->sv_end = sv_end;
+      /* the initial physical order of rows and columns of the matrix V
+         is n+1, ..., n+n, 1, ..., n (firstly columns, then rows) */
+      luf->sv_head = n+1;
+      luf->sv_tail = n;
+      for (i = 1; i <= n; i++)
+      {  sv_prev[i] = i-1;
+         sv_next[i] = i+1;
+      }
+      sv_prev[1] = n+n;
+      sv_next[n] = 0;
+      for (j = 1; j <= n; j++)
+      {  sv_prev[n+j] = n+j-1;
+         sv_next[n+j] = n+j+1;
+      }
+      sv_prev[n+1] = 0;
+      sv_next[n+n] = 1;
+      /* clear working arrays */
+      for (k = 1; k <= n; k++)
+      {  flag[k] = 0;
+         work[k] = 0.0;
+      }
+      /* initialize some statistics */
+      luf->nnz_a = nnz;
+      luf->nnz_f = 0;
+      luf->nnz_v = nnz;
+      luf->max_a = big;
+      luf->big_v = big;
+      luf->rank = -1;
+      /* initially the active submatrix is the entire matrix V */
+      /* largest of absolute values of elements in each active row is
+         unknown yet */
+      for (i = 1; i <= n; i++) vr_max[i] = -1.0;
+      /* build linked lists of active rows */
+      for (len = 0; len <= n; len++) rs_head[len] = 0;
+      for (i = 1; i <= n; i++)
+      {  len = vr_len[i];
+         rs_prev[i] = 0;
+         rs_next[i] = rs_head[len];
+         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+         rs_head[len] = i;
+      }
+      /* build linked lists of active columns */
+      for (len = 0; len <= n; len++) cs_head[len] = 0;
+      for (j = 1; j <= n; j++)
+      {  len = vc_len[j];
+         cs_prev[j] = 0;
+         cs_next[j] = cs_head[len];
+         if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
+         cs_head[len] = j;
+      }
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  find_pivot - choose a pivot element
+*
+*  This routine chooses a pivot element in the active submatrix of the
+*  matrix U = P*V*Q.
+*
+*  It is assumed that on entry the matrix U has the following partially
+*  triangularized form:
+* 
+*        1       k         n
+*     1  x x x x x x x x x x
+*        . x x x x x x x x x
+*        . . x x x x x x x x
+*        . . . x x x x x x x
+*     k  . . . . * * * * * *
+*        . . . . * * * * * *
+*        . . . . * * * * * *
+*        . . . . * * * * * *
+*        . . . . * * * * * *
+*     n  . . . . * * * * * *
+* 
+*  where rows and columns k, k+1, ..., n belong to the active submatrix
+*  (elements of the active submatrix are marked by '*').
+*
+*  Since the matrix U = P*V*Q is not stored, the routine works with the
+*  matrix V. It is assumed that the row-wise representation corresponds
+*  to the matrix V, but the column-wise representation corresponds to
+*  the active submatrix of the matrix V, i.e. elements of the matrix V,
+*  which doesn't belong to the active submatrix, are missing from the
+*  column linked lists. It is also assumed that each active row of the
+*  matrix V is in the set R[len], where len is number of non-zeros in
+*  the row, and each active column of the matrix V is in the set C[len],
+*  where len is number of non-zeros in the column (in the latter case
+*  only elements of the active submatrix are counted; such elements are
+*  marked by '*' on the figure above).
+* 
+*  For the reason of numerical stability the routine applies so called
+*  threshold pivoting proposed by J.Reid. It is assumed that an element
+*  v[i,j] can be selected as a pivot candidate if it is not very small
+*  (in absolute value) among other elements in the same row, i.e. if it
+*  satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|,
+*  where 0 < tol < 1 is a given tolerance.
+* 
+*  In order to keep sparsity of the matrix V the routine uses Markowitz
+*  strategy, trying to choose such element v[p,q], which satisfies to
+*  the stability condition (see above) and has smallest Markowitz cost
+*  (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are numbers of non-zero
+*  elements, respectively, in the p-th row and in the q-th column of the
+*  active submatrix.
+* 
+*  In order to reduce the search, i.e. not to walk through all elements
+*  of the active submatrix, the routine exploits a technique proposed by
+*  I.Duff. This technique is based on using the sets R[len] and C[len]
+*  of active rows and columns.
+* 
+*  If the pivot element v[p,q] has been chosen, the routine stores its
+*  indices to the locations *p and *q and returns zero. Otherwise, if
+*  the active submatrix is empty and therefore the pivot element can't
+*  be chosen, the routine returns non-zero. */
+
+static int find_pivot(LUF *luf, int *_p, int *_q)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      double *vr_max = luf->vr_max;
+      int *rs_head = luf->rs_head;
+      int *rs_next = luf->rs_next;
+      int *cs_head = luf->cs_head;
+      int *cs_prev = luf->cs_prev;
+      int *cs_next = luf->cs_next;
+      double piv_tol = luf->piv_tol;
+      int piv_lim = luf->piv_lim;
+      int suhl = luf->suhl;
+      int p, q, len, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr,
+         ncand, next_j, min_p, min_q, min_len;
+      double best, cost, big, temp;
+      /* initially no pivot candidates have been found so far */
+      p = q = 0, best = DBL_MAX, ncand = 0;
+      /* if in the active submatrix there is a column that has the only
+         non-zero (column singleton), choose it as pivot */
+      j = cs_head[1];
+      if (j != 0)
+      {  xassert(vc_len[j] == 1);
+         p = sv_ind[vc_ptr[j]], q = j;
+         goto done;
+      }
+      /* if in the active submatrix there is a row that has the only
+         non-zero (row singleton), choose it as pivot */
+      i = rs_head[1];
+      if (i != 0)
+      {  xassert(vr_len[i] == 1);
+         p = i, q = sv_ind[vr_ptr[i]];
+         goto done;
+      }
+      /* there are no singletons in the active submatrix; walk through
+         other non-empty rows and columns */
+      for (len = 2; len <= n; len++)
+      {  /* consider active columns that have len non-zeros */
+         for (j = cs_head[len]; j != 0; j = next_j)
+         {  /* the j-th column has len non-zeros */
+            j_beg = vc_ptr[j];
+            j_end = j_beg + vc_len[j] - 1;
+            /* save pointer to the next column with the same length */
+            next_j = cs_next[j];
+            /* find an element in the j-th column, which is placed in a
+               row with minimal number of non-zeros and satisfies to the
+               stability condition (such element may not exist) */
+            min_p = min_q = 0, min_len = INT_MAX;
+            for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+            {  /* get row index of v[i,j] */
+               i = sv_ind[j_ptr];
+               i_beg = vr_ptr[i];
+               i_end = i_beg + vr_len[i] - 1;
+               /* if the i-th row is not shorter than that one, where
+                  minimal element is currently placed, skip v[i,j] */
+               if (vr_len[i] >= min_len) continue;
+               /* determine the largest of absolute values of elements
+                  in the i-th row */
+               big = vr_max[i];
+               if (big < 0.0)
+               {  /* the largest value is unknown yet; compute it */
+                  for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+                  {  temp = sv_val[i_ptr];
+                     if (temp < 0.0) temp = - temp;
+                     if (big < temp) big = temp;
+                  }
+                  vr_max[i] = big;
+               }
+               /* find v[i,j] in the i-th row */
+               for (i_ptr = vr_ptr[i]; sv_ind[i_ptr] != j; i_ptr++);
+               xassert(i_ptr <= i_end);
+               /* if v[i,j] doesn't satisfy to the stability condition,
+                  skip it */
+               temp = sv_val[i_ptr];
+               if (temp < 0.0) temp = - temp;
+               if (temp < piv_tol * big) continue;
+               /* v[i,j] is better than the current minimal element */
+               min_p = i, min_q = j, min_len = vr_len[i];
+               /* if Markowitz cost of the current minimal element is
+                  not greater than (len-1)**2, it can be chosen right
+                  now; this heuristic reduces the search and works well
+                  in many cases */
+               if (min_len <= len)
+               {  p = min_p, q = min_q;
+                  goto done;
+               }
+            }
+            /* the j-th column has been scanned */
+            if (min_p != 0)
+            {  /* the minimal element is a next pivot candidate */
+               ncand++;
+               /* compute its Markowitz cost */
+               cost = (double)(min_len - 1) * (double)(len - 1);
+               /* choose between the minimal element and the current
+                  candidate */
+               if (cost < best) p = min_p, q = min_q, best = cost;
+               /* if piv_lim candidates have been considered, there are
+                  doubts that a much better candidate exists; therefore
+                  it's time to terminate the search */
+               if (ncand == piv_lim) goto done;
+            }
+            else
+            {  /* the j-th column has no elements, which satisfy to the
+                  stability condition; Uwe Suhl suggests to exclude such
+                  column from the further consideration until it becomes
+                  a column singleton; in hard cases this significantly
+                  reduces a time needed for pivot searching */
+               if (suhl)
+               {  /* remove the j-th column from the active set */
+                  if (cs_prev[j] == 0)
+                     cs_head[len] = cs_next[j];
+                  else
+                     cs_next[cs_prev[j]] = cs_next[j];
+                  if (cs_next[j] == 0)
+                     /* nop */;
+                  else
+                     cs_prev[cs_next[j]] = cs_prev[j];
+                  /* the following assignment is used to avoid an error
+                     when the routine eliminate (see below) will try to
+                     remove the j-th column from the active set */
+                  cs_prev[j] = cs_next[j] = j;
+               }
+            }
+         }
+         /* consider active rows that have len non-zeros */
+         for (i = rs_head[len]; i != 0; i = rs_next[i])
+         {  /* the i-th row has len non-zeros */
+            i_beg = vr_ptr[i];
+            i_end = i_beg + vr_len[i] - 1;
+            /* determine the largest of absolute values of elements in
+               the i-th row */
+            big = vr_max[i];
+            if (big < 0.0)
+            {  /* the largest value is unknown yet; compute it */
+               for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+               {  temp = sv_val[i_ptr];
+                  if (temp < 0.0) temp = - temp;
+                  if (big < temp) big = temp;
+               }
+               vr_max[i] = big;
+            }
+            /* find an element in the i-th row, which is placed in a
+               column with minimal number of non-zeros and satisfies to
+               the stability condition (such element always exists) */
+            min_p = min_q = 0, min_len = INT_MAX;
+            for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+            {  /* get column index of v[i,j] */
+               j = sv_ind[i_ptr];
+               /* if the j-th column is not shorter than that one, where
+                  minimal element is currently placed, skip v[i,j] */
+               if (vc_len[j] >= min_len) continue;
+               /* if v[i,j] doesn't satisfy to the stability condition,
+                  skip it */
+               temp = sv_val[i_ptr];
+               if (temp < 0.0) temp = - temp;
+               if (temp < piv_tol * big) continue;
+               /* v[i,j] is better than the current minimal element */
+               min_p = i, min_q = j, min_len = vc_len[j];
+               /* if Markowitz cost of the current minimal element is
+                  not greater than (len-1)**2, it can be chosen right
+                  now; this heuristic reduces the search and works well
+                  in many cases */
+               if (min_len <= len)
+               {  p = min_p, q = min_q;
+                  goto done;
+               }
+            }
+            /* the i-th row has been scanned */
+            if (min_p != 0)
+            {  /* the minimal element is a next pivot candidate */
+               ncand++;
+               /* compute its Markowitz cost */
+               cost = (double)(len - 1) * (double)(min_len - 1);
+               /* choose between the minimal element and the current
+                  candidate */
+               if (cost < best) p = min_p, q = min_q, best = cost;
+               /* if piv_lim candidates have been considered, there are
+                  doubts that a much better candidate exists; therefore
+                  it's time to terminate the search */
+               if (ncand == piv_lim) goto done;
+            }
+            else
+            {  /* this can't be because this can never be */
+               xassert(min_p != min_p);
+            }
+         }
+      }
+done: /* bring the pivot to the factorizing routine */
+      *_p = p, *_q = q;
+      return (p == 0);
+}
+
+/***********************************************************************
+*  eliminate - perform gaussian elimination.
+* 
+*  This routine performs elementary gaussian transformations in order
+*  to eliminate subdiagonal elements in the k-th column of the matrix
+*  U = P*V*Q using the pivot element u[k,k], where k is the number of
+*  the current elimination step.
+* 
+*  The parameters p and q are, respectively, row and column indices of
+*  the element v[p,q], which corresponds to the element u[k,k].
+* 
+*  Each time when the routine applies the elementary transformation to
+*  a non-pivot row of the matrix V, it stores the corresponding element
+*  to the matrix F in order to keep the main equality A = F*V.
+* 
+*  The routine assumes that on entry the matrices L = P*F*inv(P) and
+*  U = P*V*Q are the following:
+* 
+*        1       k                  1       k         n
+*     1  1 . . . . . . . . .     1  x x x x x x x x x x
+*        x 1 . . . . . . . .        . x x x x x x x x x
+*        x x 1 . . . . . . .        . . x x x x x x x x
+*        x x x 1 . . . . . .        . . . x x x x x x x
+*     k  x x x x 1 . . . . .     k  . . . . * * * * * *
+*        x x x x _ 1 . . . .        . . . . # * * * * *
+*        x x x x _ . 1 . . .        . . . . # * * * * *
+*        x x x x _ . . 1 . .        . . . . # * * * * *
+*        x x x x _ . . . 1 .        . . . . # * * * * *
+*     n  x x x x _ . . . . 1     n  . . . . # * * * * *
+* 
+*             matrix L                   matrix U
+* 
+*  where rows and columns of the matrix U with numbers k, k+1, ..., n
+*  form the active submatrix (eliminated elements are marked by '#' and
+*  other elements of the active submatrix are marked by '*'). Note that
+*  each eliminated non-zero element u[i,k] of the matrix U gives the
+*  corresponding element l[i,k] of the matrix L (marked by '_').
+* 
+*  Actually all operations are performed on the matrix V. Should note
+*  that the row-wise representation corresponds to the matrix V, but the
+*  column-wise representation corresponds to the active submatrix of the
+*  matrix V, i.e. elements of the matrix V, which doesn't belong to the
+*  active submatrix, are missing from the column linked lists.
+* 
+*  Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
+*  elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
+*  the following elementary gaussian transformations:
+* 
+*     (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
+* 
+*  where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
+*
+*  Additionally, in order to keep the main equality A = F*V, each time
+*  when the routine applies the transformation to i-th row of the matrix
+*  V, it also adds f[i,p] as a new element to the matrix F.
+*
+*  IMPORTANT: On entry the working arrays flag and work should contain
+*  zeros. This status is provided by the routine on exit.
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int eliminate(LUF *luf, int p, int q)
+{     int n = luf->n;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      double *vr_piv = luf->vr_piv;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      double *vr_max = luf->vr_max;
+      int *rs_head = luf->rs_head;
+      int *rs_prev = luf->rs_prev;
+      int *rs_next = luf->rs_next;
+      int *cs_head = luf->cs_head;
+      int *cs_prev = luf->cs_prev;
+      int *cs_next = luf->cs_next;
+      int *flag = luf->flag;
+      double *work = luf->work;
+      double eps_tol = luf->eps_tol;
+      /* at this stage the row-wise representation of the matrix F is
+         not used, so fr_len can be used as a working array */
+      int *ndx = luf->fr_len;
+      int ret = 0;
+      int len, fill, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr, k,
+         p_beg, p_end, p_ptr, q_beg, q_end, q_ptr;
+      double fip, val, vpq, temp;
+      xassert(1 <= p && p <= n);
+      xassert(1 <= q && q <= n);
+      /* remove the p-th (pivot) row from the active set; this row will
+         never return there */
+      if (rs_prev[p] == 0)
+         rs_head[vr_len[p]] = rs_next[p];
+      else
+         rs_next[rs_prev[p]] = rs_next[p];
+      if (rs_next[p] == 0)
+         ;
+      else
+         rs_prev[rs_next[p]] = rs_prev[p];
+      /* remove the q-th (pivot) column from the active set; this column
+         will never return there */
+      if (cs_prev[q] == 0)
+         cs_head[vc_len[q]] = cs_next[q];
+      else
+         cs_next[cs_prev[q]] = cs_next[q];
+      if (cs_next[q] == 0)
+         ;
+      else
+         cs_prev[cs_next[q]] = cs_prev[q];
+      /* find the pivot v[p,q] = u[k,k] in the p-th row */
+      p_beg = vr_ptr[p];
+      p_end = p_beg + vr_len[p] - 1;
+      for (p_ptr = p_beg; sv_ind[p_ptr] != q; p_ptr++) /* nop */;
+      xassert(p_ptr <= p_end);
+      /* store value of the pivot */
+      vpq = (vr_piv[p] = sv_val[p_ptr]);
+      /* remove the pivot from the p-th row */
+      sv_ind[p_ptr] = sv_ind[p_end];
+      sv_val[p_ptr] = sv_val[p_end];
+      vr_len[p]--;
+      p_end--;
+      /* find the pivot v[p,q] = u[k,k] in the q-th column */
+      q_beg = vc_ptr[q];
+      q_end = q_beg + vc_len[q] - 1;
+      for (q_ptr = q_beg; sv_ind[q_ptr] != p; q_ptr++) /* nop */;
+      xassert(q_ptr <= q_end);
+      /* remove the pivot from the q-th column */
+      sv_ind[q_ptr] = sv_ind[q_end];
+      vc_len[q]--;
+      q_end--;
+      /* walk through the p-th (pivot) row, which doesn't contain the
+         pivot v[p,q] already, and do the following... */
+      for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+      {  /* get column index of v[p,j] */
+         j = sv_ind[p_ptr];
+         /* store v[p,j] to the working array */
+         flag[j] = 1;
+         work[j] = sv_val[p_ptr];
+         /* remove the j-th column from the active set; this column will
+            return there later with new length */
+         if (cs_prev[j] == 0)
+            cs_head[vc_len[j]] = cs_next[j];
+         else
+            cs_next[cs_prev[j]] = cs_next[j];
+         if (cs_next[j] == 0)
+            ;
+         else
+            cs_prev[cs_next[j]] = cs_prev[j];
+         /* find v[p,j] in the j-th column */
+         j_beg = vc_ptr[j];
+         j_end = j_beg + vc_len[j] - 1;
+         for (j_ptr = j_beg; sv_ind[j_ptr] != p; j_ptr++) /* nop */;
+         xassert(j_ptr <= j_end);
+         /* since v[p,j] leaves the active submatrix, remove it from the
+            j-th column; however, v[p,j] is kept in the p-th row */
+         sv_ind[j_ptr] = sv_ind[j_end];
+         vc_len[j]--;
+      }
+      /* walk through the q-th (pivot) column, which doesn't contain the
+         pivot v[p,q] already, and perform gaussian elimination */
+      while (q_beg <= q_end)
+      {  /* element v[i,q] should be eliminated */
+         /* get row index of v[i,q] */
+         i = sv_ind[q_beg];
+         /* remove the i-th row from the active set; later this row will
+            return there with new length */
+         if (rs_prev[i] == 0)
+            rs_head[vr_len[i]] = rs_next[i];
+         else
+            rs_next[rs_prev[i]] = rs_next[i];
+         if (rs_next[i] == 0)
+            ;
+         else
+            rs_prev[rs_next[i]] = rs_prev[i];
+         /* find v[i,q] in the i-th row */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; sv_ind[i_ptr] != q; i_ptr++) /* nop */;
+         xassert(i_ptr <= i_end);
+         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */
+         fip = sv_val[i_ptr] / vpq;
+         /* since v[i,q] should be eliminated, remove it from the i-th
+            row */
+         sv_ind[i_ptr] = sv_ind[i_end];
+         sv_val[i_ptr] = sv_val[i_end];
+         vr_len[i]--;
+         i_end--;
+         /* and from the q-th column */
+         sv_ind[q_beg] = sv_ind[q_end];
+         vc_len[q]--;
+         q_end--;
+         /* perform gaussian transformation:
+            (i-th row) := (i-th row) - f[i,p] * (p-th row)
+            note that now the p-th row, which is in the working array,
+            doesn't contain the pivot v[p,q], and the i-th row doesn't
+            contain the eliminated element v[i,q] */
+         /* walk through the i-th row and transform existing non-zero
+            elements */
+         fill = vr_len[p];
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         {  /* get column index of v[i,j] */
+            j = sv_ind[i_ptr];
+            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
+            if (flag[j])
+            {  /* v[p,j] != 0 */
+               temp = (sv_val[i_ptr] -= fip * work[j]);
+               if (temp < 0.0) temp = - temp;
+               flag[j] = 0;
+               fill--; /* since both v[i,j] and v[p,j] exist */
+               if (temp == 0.0 || temp < eps_tol)
+               {  /* new v[i,j] is closer to zero; replace it by exact
+                     zero, i.e. remove it from the active submatrix */
+                  /* remove v[i,j] from the i-th row */
+                  sv_ind[i_ptr] = sv_ind[i_end];
+                  sv_val[i_ptr] = sv_val[i_end];
+                  vr_len[i]--;
+                  i_ptr--;
+                  i_end--;
+                  /* find v[i,j] in the j-th column */
+                  j_beg = vc_ptr[j];
+                  j_end = j_beg + vc_len[j] - 1;
+                  for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++);
+                  xassert(j_ptr <= j_end);
+                  /* remove v[i,j] from the j-th column */
+                  sv_ind[j_ptr] = sv_ind[j_end];
+                  vc_len[j]--;
+               }
+               else
+               {  /* v_big := max(v_big, |v[i,j]|) */
+                  if (luf->big_v < temp) luf->big_v = temp;
+               }
+            }
+         }
+         /* now flag is the pattern of the set v[p,*] \ v[i,*], and fill
+            is number of non-zeros in this set; therefore up to fill new
+            non-zeros may appear in the i-th row */
+         if (vr_len[i] + fill > vr_cap[i])
+         {  /* enlarge the i-th row */
+            if (luf_enlarge_row(luf, i, vr_len[i] + fill))
+            {  /* overflow of the sparse vector area */
+               ret = 1;
+               goto done;
+            }
+            /* defragmentation may change row and column pointers of the
+               matrix V */
+            p_beg = vr_ptr[p];
+            p_end = p_beg + vr_len[p] - 1;
+            q_beg = vc_ptr[q];
+            q_end = q_beg + vc_len[q] - 1;
+         }
+         /* walk through the p-th (pivot) row and create new elements
+            of the i-th row that appear due to fill-in; column indices
+            of these new elements are accumulated in the array ndx */
+         len = 0;
+         for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+         {  /* get column index of v[p,j], which may cause fill-in */
+            j = sv_ind[p_ptr];
+            if (flag[j])
+            {  /* compute new non-zero v[i,j] = 0 - f[i,p] * v[p,j] */
+               temp = (val = - fip * work[j]);
+               if (temp < 0.0) temp = - temp;
+               if (temp == 0.0 || temp < eps_tol)
+                  /* if v[i,j] is closer to zero; just ignore it */;
+               else
+               {  /* add v[i,j] to the i-th row */
+                  i_ptr = vr_ptr[i] + vr_len[i];
+                  sv_ind[i_ptr] = j;
+                  sv_val[i_ptr] = val;
+                  vr_len[i]++;
+                  /* remember column index of v[i,j] */
+                  ndx[++len] = j;
+                  /* big_v := max(big_v, |v[i,j]|) */
+                  if (luf->big_v < temp) luf->big_v = temp;
+               }
+            }
+            else
+            {  /* there is no fill-in, because v[i,j] already exists in
+                  the i-th row; restore the flag of the element v[p,j],
+                  which was reset before */
+               flag[j] = 1;
+            }
+         }
+         /* add new non-zeros v[i,j] to the corresponding columns */
+         for (k = 1; k <= len; k++)
+         {  /* get column index of new non-zero v[i,j] */
+            j = ndx[k];
+            /* one free location is needed in the j-th column */
+            if (vc_len[j] + 1 > vc_cap[j])
+            {  /* enlarge the j-th column */
+               if (luf_enlarge_col(luf, j, vc_len[j] + 10))
+               {  /* overflow of the sparse vector area */
+                  ret = 1;
+                  goto done;
+               }
+               /* defragmentation may change row and column pointers of
+                  the matrix V */
+               p_beg = vr_ptr[p];
+               p_end = p_beg + vr_len[p] - 1;
+               q_beg = vc_ptr[q];
+               q_end = q_beg + vc_len[q] - 1;
+            }
+            /* add new non-zero v[i,j] to the j-th column */
+            j_ptr = vc_ptr[j] + vc_len[j];
+            sv_ind[j_ptr] = i;
+            vc_len[j]++;
+         }
+         /* now the i-th row has been completely transformed, therefore
+            it can return to the active set with new length */
+         rs_prev[i] = 0;
+         rs_next[i] = rs_head[vr_len[i]];
+         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+         rs_head[vr_len[i]] = i;
+         /* the largest of absolute values of elements in the i-th row
+            is currently unknown */
+         vr_max[i] = -1.0;
+         /* at least one free location is needed to store the gaussian
+            multiplier */
+         if (luf->sv_end - luf->sv_beg < 1)
+         {  /* there are no free locations at all; defragment SVA */
+            luf_defrag_sva(luf);
+            if (luf->sv_end - luf->sv_beg < 1)
+            {  /* overflow of the sparse vector area */
+               ret = 1;
+               goto done;
+            }
+            /* defragmentation may change row and column pointers of the
+               matrix V */
+            p_beg = vr_ptr[p];
+            p_end = p_beg + vr_len[p] - 1;
+            q_beg = vc_ptr[q];
+            q_end = q_beg + vc_len[q] - 1;
+         }
+         /* add the element f[i,p], which is the gaussian multiplier,
+            to the matrix F */
+         luf->sv_end--;
+         sv_ind[luf->sv_end] = i;
+         sv_val[luf->sv_end] = fip;
+         fc_len[p]++;
+         /* end of elimination loop */
+      }
+      /* at this point the q-th (pivot) column should be empty */
+      xassert(vc_len[q] == 0);
+      /* reset capacity of the q-th column */
+      vc_cap[q] = 0;
+      /* remove node of the q-th column from the addressing list */
+      k = n + q;
+      if (sv_prev[k] == 0)
+         luf->sv_head = sv_next[k];
+      else
+         sv_next[sv_prev[k]] = sv_next[k];
+      if (sv_next[k] == 0)
+         luf->sv_tail = sv_prev[k];
+      else
+         sv_prev[sv_next[k]] = sv_prev[k];
+      /* the p-th column of the matrix F has been completely built; set
+         its pointer */
+      fc_ptr[p] = luf->sv_end;
+      /* walk through the p-th (pivot) row and do the following... */
+      for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+      {  /* get column index of v[p,j] */
+         j = sv_ind[p_ptr];
+         /* erase v[p,j] from the working array */
+         flag[j] = 0;
+         work[j] = 0.0;
+         /* the j-th column has been completely transformed, therefore
+            it can return to the active set with new length; however
+            the special case c_prev[j] = c_next[j] = j means that the
+            routine find_pivot excluded the j-th column from the active
+            set due to Uwe Suhl's rule, and therefore in this case the
+            column can return to the active set only if it is a column
+            singleton */
+         if (!(vc_len[j] != 1 && cs_prev[j] == j && cs_next[j] == j))
+         {  cs_prev[j] = 0;
+            cs_next[j] = cs_head[vc_len[j]];
+            if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
+            cs_head[vc_len[j]] = j;
+         }
+      }
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  build_v_cols - build the matrix V in column-wise format
+*
+*  This routine builds the column-wise representation of the matrix V
+*  using its row-wise representation.
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int build_v_cols(LUF *luf)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      int ret = 0;
+      int i, i_beg, i_end, i_ptr, j, j_ptr, k, nnz;
+      /* it is assumed that on entry all columns of the matrix V are
+         empty, i.e. vc_len[j] = vc_cap[j] = 0 for all j = 1, ..., n,
+         and have been removed from the addressing list */
+      /* count non-zeros in columns of the matrix V; count total number
+         of non-zeros in this matrix */
+      nnz = 0;
+      for (i = 1; i <= n; i++)
+      {  /* walk through elements of the i-th row and count non-zeros
+            in the corresponding columns */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+            vc_cap[sv_ind[i_ptr]]++;
+         /* count total number of non-zeros */
+         nnz += vr_len[i];
+      }
+      /* store total number of non-zeros */
+      luf->nnz_v = nnz;
+      /* check for free locations */
+      if (luf->sv_end - luf->sv_beg < nnz)
+      {  /* overflow of the sparse vector area */
+         ret = 1;
+         goto done;
+      }
+      /* allocate columns of the matrix V */
+      for (j = 1; j <= n; j++)
+      {  /* set pointer to the j-th column */
+         vc_ptr[j] = luf->sv_beg;
+         /* reserve locations for the j-th column */
+         luf->sv_beg += vc_cap[j];
+      }
+      /* build the matrix V in column-wise format using this matrix in
+         row-wise format */
+      for (i = 1; i <= n; i++)
+      {  /* walk through elements of the i-th row */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         {  /* get column index */
+            j = sv_ind[i_ptr];
+            /* store element in the j-th column */
+            j_ptr = vc_ptr[j] + vc_len[j];
+            sv_ind[j_ptr] = i;
+            sv_val[j_ptr] = sv_val[i_ptr];
+            /* increase length of the j-th column */
+            vc_len[j]++;
+         }
+      }
+      /* now columns are placed in the sparse vector area behind rows
+         in the order n+1, n+2, ..., n+n; so insert column nodes in the
+         addressing list using this order */
+      for (k = n+1; k <= n+n; k++)
+      {  sv_prev[k] = k-1;
+         sv_next[k] = k+1;
+      }
+      sv_prev[n+1] = luf->sv_tail;
+      sv_next[luf->sv_tail] = n+1;
+      sv_next[n+n] = 0;
+      luf->sv_tail = n+n;
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  build_f_rows - build the matrix F in row-wise format
+*
+*  This routine builds the row-wise representation of the matrix F using
+*  its column-wise representation.
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int build_f_rows(LUF *luf)
+{     int n = luf->n;
+      int *fr_ptr = luf->fr_ptr;
+      int *fr_len = luf->fr_len;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int ret = 0;
+      int i, j, j_beg, j_end, j_ptr, ptr, nnz;
+      /* clear rows of the matrix F */
+      for (i = 1; i <= n; i++) fr_len[i] = 0;
+      /* count non-zeros in rows of the matrix F; count total number of
+         non-zeros in this matrix */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  /* walk through elements of the j-th column and count non-zeros
+            in the corresponding rows */
+         j_beg = fc_ptr[j];
+         j_end = j_beg + fc_len[j] - 1;
+         for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+            fr_len[sv_ind[j_ptr]]++;
+         /* increase total number of non-zeros */
+         nnz += fc_len[j];
+      }
+      /* store total number of non-zeros */
+      luf->nnz_f = nnz;
+      /* check for free locations */
+      if (luf->sv_end - luf->sv_beg < nnz)
+      {  /* overflow of the sparse vector area */
+         ret = 1;
+         goto done;
+      }
+      /* allocate rows of the matrix F */
+      for (i = 1; i <= n; i++)
+      {  /* set pointer to the end of the i-th row; later this pointer
+            will be set to the beginning of the i-th row */
+         fr_ptr[i] = luf->sv_end;
+         /* reserve locations for the i-th row */
+         luf->sv_end -= fr_len[i];
+      }
+      /* build the matrix F in row-wise format using this matrix in
+         column-wise format */
+      for (j = 1; j <= n; j++)
+      {  /* walk through elements of the j-th column */
+         j_beg = fc_ptr[j];
+         j_end = j_beg + fc_len[j] - 1;
+         for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+         {  /* get row index */
+            i = sv_ind[j_ptr];
+            /* store element in the i-th row */
+            ptr = --fr_ptr[i];
+            sv_ind[ptr] = j;
+            sv_val[ptr] = sv_val[j_ptr];
+         }
+      }
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_factorize - compute LU-factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
+*     int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine luf_factorize computes LU-factorization of a specified
+*  square matrix A.
+*
+*  The parameter luf specifies LU-factorization program object created
+*  by the routine luf_create_it.
+*
+*  The parameter n specifies the order of A, n > 0.
+*
+*  The formal routine col specifies the matrix A to be factorized. To
+*  obtain j-th column of A the routine luf_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of A to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  LU-factorization has been successfully computed.
+*
+*  LUF_ESING
+*     The specified matrix is singular within the working precision.
+*     (On some elimination step the active submatrix is exactly zero,
+*     so no pivot can be chosen.)
+*
+*  LUF_ECOND
+*     The specified matrix is ill-conditioned.
+*     (On some elimination step too intensive growth of elements of the
+*     active submatix has been detected.)
+*
+*  If matrix A is well scaled, the return code LUF_ECOND may also mean
+*  that the threshold pivoting tolerance piv_tol should be increased.
+*
+*  In case of non-zero return code the factorization becomes invalid.
+*  It should not be used in other operations until the cause of failure
+*  has been eliminated and the factorization has been recomputed again
+*  with the routine luf_factorize.
+*
+*  REPAIRING SINGULAR MATRIX
+*
+*  If the routine luf_factorize returns non-zero code, it provides all
+*  necessary information that can be used for "repairing" the matrix A,
+*  where "repairing" means replacing linearly dependent columns of the
+*  matrix A by appropriate columns of the unity matrix. This feature is
+*  needed when this routine is used for factorizing the basis matrix
+*  within the simplex method procedure.
+*
+*  On exit linearly dependent columns of the (partially transformed)
+*  matrix U have numbers rank+1, rank+2, ..., n, where rank is estimated
+*  rank of the matrix A stored by the routine to the member luf->rank.
+*  The correspondence between columns of A and U is the same as between
+*  columns of V and U. Thus, linearly dependent columns of the matrix A
+*  have numbers qq_col[rank+1], qq_col[rank+2], ..., qq_col[n], where
+*  qq_col is the column-like representation of the permutation matrix Q.
+*  It is understood that each j-th linearly dependent column of the
+*  matrix U should be replaced by the unity vector, where all elements
+*  are zero except the unity diagonal element u[j,j]. On the other hand
+*  j-th row of the matrix U corresponds to the row of the matrix V (and
+*  therefore of the matrix A) with the number pp_row[j], where pp_row is
+*  the row-like representation of the permutation matrix P. Thus, each
+*  j-th linearly dependent column of the matrix U should be replaced by
+*  column of the unity matrix with the number pp_row[j].
+*
+*  The code that repairs the matrix A may look like follows:
+*
+*     for (j = rank+1; j <= n; j++)
+*     {  replace the column qq_col[j] of the matrix A by the column
+*        pp_row[j] of the unity matrix;
+*     }
+*
+*  where rank, pp_row, and qq_col are members of the structure LUF. */
+
+int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info)
+{     int *pp_row, *pp_col, *qq_row, *qq_col;
+      double max_gro = luf->max_gro;
+      int i, j, k, p, q, t, ret;
+      if (n < 1)
+         xfault("luf_factorize: n = %d; invalid parameter\n", n);
+      if (n > N_MAX)
+         xfault("luf_factorize: n = %d; matrix too big\n", n);
+      /* invalidate the factorization */
+      luf->valid = 0;
+      /* reallocate arrays, if necessary */
+      reallocate(luf, n);
+      pp_row = luf->pp_row;
+      pp_col = luf->pp_col;
+      qq_row = luf->qq_row;
+      qq_col = luf->qq_col;
+      /* estimate initial size of the SVA, if not specified */
+      if (luf->sv_size == 0 && luf->new_sva == 0)
+         luf->new_sva = 5 * (n + 10);
+more: /* reallocate the sparse vector area, if required */
+      if (luf->new_sva > 0)
+      {  if (luf->sv_ind != NULL) xfree(luf->sv_ind);
+         if (luf->sv_val != NULL) xfree(luf->sv_val);
+         luf->sv_size = luf->new_sva;
+         luf->sv_ind = xcalloc(1+luf->sv_size, sizeof(int));
+         luf->sv_val = xcalloc(1+luf->sv_size, sizeof(double));
+         luf->new_sva = 0;
+      }
+      /* initialize LU-factorization data structures */
+      if (initialize(luf, col, info))
+      {  /* overflow of the sparse vector area */
+         luf->new_sva = luf->sv_size + luf->sv_size;
+         xassert(luf->new_sva > luf->sv_size);
+         goto more;
+      }
+      /* main elimination loop */
+      for (k = 1; k <= n; k++)
+      {  /* choose a pivot element v[p,q] */
+         if (find_pivot(luf, &p, &q))
+         {  /* no pivot can be chosen, because the active submatrix is
+               exactly zero */
+            luf->rank = k - 1;
+            ret = LUF_ESING;
+            goto done;
+         }
+         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
+            rows and k-th and j'-th columns of the matrix U = P*V*Q to
+            move the element u[i',j'] to the position u[k,k] */
+         i = pp_col[p], j = qq_row[q];
+         xassert(k <= i && i <= n && k <= j && j <= n);
+         /* permute k-th and i-th rows of the matrix U */
+         t = pp_row[k];
+         pp_row[i] = t, pp_col[t] = i;
+         pp_row[k] = p, pp_col[p] = k;
+         /* permute k-th and j-th columns of the matrix U */
+         t = qq_col[k];
+         qq_col[j] = t, qq_row[t] = j;
+         qq_col[k] = q, qq_row[q] = k;
+         /* eliminate subdiagonal elements of k-th column of the matrix
+            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
+         if (eliminate(luf, p, q))
+         {  /* overflow of the sparse vector area */
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            goto more;
+         }
+         /* check relative growth of elements of the matrix V */
+         if (luf->big_v > max_gro * luf->max_a)
+         {  /* the growth is too intensive, therefore most probably the
+               matrix A is ill-conditioned */
+            luf->rank = k - 1;
+            ret = LUF_ECOND;
+            goto done;
+         }
+      }
+      /* now the matrix U = P*V*Q is upper triangular, the matrix V has
+         been built in row-wise format, and the matrix F has been built
+         in column-wise format */
+      /* defragment the sparse vector area in order to merge all free
+         locations in one continuous extent */
+      luf_defrag_sva(luf);
+      /* build the matrix V in column-wise format */
+      if (build_v_cols(luf))
+      {  /* overflow of the sparse vector area */
+         luf->new_sva = luf->sv_size + luf->sv_size;
+         xassert(luf->new_sva > luf->sv_size);
+         goto more;
+      }
+      /* build the matrix F in row-wise format */
+      if (build_f_rows(luf))
+      {  /* overflow of the sparse vector area */
+         luf->new_sva = luf->sv_size + luf->sv_size;
+         xassert(luf->new_sva > luf->sv_size);
+         goto more;
+      }
+      /* the LU-factorization has been successfully computed */
+      luf->valid = 1;
+      luf->rank = n;
+      ret = 0;
+      /* if there are few free locations in the sparse vector area, try
+         increasing its size in the future */
+      t = 3 * (n + luf->nnz_v) + 2 * luf->nnz_f;
+      if (luf->sv_size < t)
+      {  luf->new_sva = luf->sv_size;
+         while (luf->new_sva < t)
+         {  k = luf->new_sva;
+            luf->new_sva = k + k;
+            xassert(luf->new_sva > k);
+         }
+      }
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_f_solve - solve system F*x = b or F'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_f_solve(LUF *luf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine luf_f_solve solves either the system F*x = b (if the
+*  flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
+*  where the matrix F is a component of LU-factorization specified by
+*  the parameter luf, F' is a matrix transposed to F.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[n], where n is the order of the
+*  matrix F. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void luf_f_solve(LUF *luf, int tr, double x[])
+{     int n = luf->n;
+      int *fr_ptr = luf->fr_ptr;
+      int *fr_len = luf->fr_len;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *pp_row = luf->pp_row;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int i, j, k, beg, end, ptr;
+      double xk;
+      if (!luf->valid)
+         xfault("luf_f_solve: LU-factorization is not valid\n");
+      if (!tr)
+      {  /* solve the system F*x = b */
+         for (j = 1; j <= n; j++)
+         {  k = pp_row[j];
+            xk = x[k];
+            if (xk != 0.0)
+            {  beg = fc_ptr[k];
+               end = beg + fc_len[k] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  x[sv_ind[ptr]] -= sv_val[ptr] * xk;
+            }
+         }
+      }
+      else
+      {  /* solve the system F'*x = b */
+         for (i = n; i >= 1; i--)
+         {  k = pp_row[i];
+            xk = x[k];
+            if (xk != 0.0)
+            {  beg = fr_ptr[k];
+               end = beg + fr_len[k] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  x[sv_ind[ptr]] -= sv_val[ptr] * xk;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_v_solve - solve system V*x = b or V'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_v_solve(LUF *luf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine luf_v_solve solves either the system V*x = b (if the
+*  flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
+*  where the matrix V is a component of LU-factorization specified by
+*  the parameter luf, V' is a matrix transposed to V.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[n], where n is the order of the
+*  matrix V. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void luf_v_solve(LUF *luf, int tr, double x[])
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      double *vr_piv = luf->vr_piv;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *pp_row = luf->pp_row;
+      int *qq_col = luf->qq_col;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      double *b = luf->work;
+      int i, j, k, beg, end, ptr;
+      double temp;
+      if (!luf->valid)
+         xfault("luf_v_solve: LU-factorization is not valid\n");
+      for (k = 1; k <= n; k++) b[k] = x[k], x[k] = 0.0;
+      if (!tr)
+      {  /* solve the system V*x = b */
+         for (k = n; k >= 1; k--)
+         {  i = pp_row[k], j = qq_col[k];
+            temp = b[i];
+            if (temp != 0.0)
+            {  x[j] = (temp /= vr_piv[i]);
+               beg = vc_ptr[j];
+               end = beg + vc_len[j] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  b[sv_ind[ptr]] -= sv_val[ptr] * temp;
+            }
+         }
+      }
+      else
+      {  /* solve the system V'*x = b */
+         for (k = 1; k <= n; k++)
+         {  i = pp_row[k], j = qq_col[k];
+            temp = b[j];
+            if (temp != 0.0)
+            {  x[i] = (temp /= vr_piv[i]);
+               beg = vr_ptr[i];
+               end = beg + vr_len[i] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  b[sv_ind[ptr]] -= sv_val[ptr] * temp;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_a_solve - solve system A*x = b or A'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_a_solve(LUF *luf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine luf_a_solve solves either the system A*x = b (if the
+*  flag tr is zero) or the system A'*x = b (if the flag tr is non-zero),
+*  where the parameter luf specifies LU-factorization of the matrix A,
+*  A' is a matrix transposed to A.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[n], where n is the order of the
+*  matrix A. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void luf_a_solve(LUF *luf, int tr, double x[])
+{     if (!luf->valid)
+         xfault("luf_a_solve: LU-factorization is not valid\n");
+      if (!tr)
+      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
+         luf_f_solve(luf, 0, x);
+         luf_v_solve(luf, 0, x);
+      }
+      else
+      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
+         luf_v_solve(luf, 1, x);
+         luf_f_solve(luf, 1, x);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_delete_it - delete LU-factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_delete_it(LUF *luf);
+*
+*  DESCRIPTION
+*
+*  The routine luf_delete deletes LU-factorization specified by the
+*  parameter luf and frees all the memory allocated to this program
+*  object. */
+
+void luf_delete_it(LUF *luf)
+{     if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
+      if (luf->fr_len != NULL) xfree(luf->fr_len);
+      if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
+      if (luf->fc_len != NULL) xfree(luf->fc_len);
+      if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
+      if (luf->vr_len != NULL) xfree(luf->vr_len);
+      if (luf->vr_cap != NULL) xfree(luf->vr_cap);
+      if (luf->vr_piv != NULL) xfree(luf->vr_piv);
+      if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
+      if (luf->vc_len != NULL) xfree(luf->vc_len);
+      if (luf->vc_cap != NULL) xfree(luf->vc_cap);
+      if (luf->pp_row != NULL) xfree(luf->pp_row);
+      if (luf->pp_col != NULL) xfree(luf->pp_col);
+      if (luf->qq_row != NULL) xfree(luf->qq_row);
+      if (luf->qq_col != NULL) xfree(luf->qq_col);
+      if (luf->sv_ind != NULL) xfree(luf->sv_ind);
+      if (luf->sv_val != NULL) xfree(luf->sv_val);
+      if (luf->sv_prev != NULL) xfree(luf->sv_prev);
+      if (luf->sv_next != NULL) xfree(luf->sv_next);
+      if (luf->vr_max != NULL) xfree(luf->vr_max);
+      if (luf->rs_head != NULL) xfree(luf->rs_head);
+      if (luf->rs_prev != NULL) xfree(luf->rs_prev);
+      if (luf->rs_next != NULL) xfree(luf->rs_next);
+      if (luf->cs_head != NULL) xfree(luf->cs_head);
+      if (luf->cs_prev != NULL) xfree(luf->cs_prev);
+      if (luf->cs_next != NULL) xfree(luf->cs_next);
+      if (luf->flag != NULL) xfree(luf->flag);
+      if (luf->work != NULL) xfree(luf->work);
+      xfree(luf);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpluf.h b/optional/glpk/glpluf.h
new file mode 100644
index 0000000..eb2cf88
--- /dev/null
+++ b/optional/glpk/glpluf.h
@@ -0,0 +1,326 @@
+/* glpluf.h (LU-factorization) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPLUF_H
+#define GLPLUF_H
+
+/***********************************************************************
+*  The structure LUF defines LU-factorization of a square matrix A and
+*  is the following quartet:
+*
+*     [A] = (F, V, P, Q),                                            (1)
+*
+*  where F and V are such matrices that
+*
+*     A = F * V,                                                     (2)
+*
+*  and P and Q are such permutation matrices that the matrix
+*
+*     L = P * F * inv(P)                                             (3)
+*
+*  is lower triangular with unity diagonal, and the matrix
+*
+*     U = P * V * Q                                                  (4)
+*
+*  is upper triangular. All the matrices have the order n.
+*
+*  Matrices F and V are stored in row- and column-wise sparse format
+*  as row and column linked lists of non-zero elements. Unity elements
+*  on the main diagonal of matrix F are not stored. Pivot elements of
+*  matrix V (which correspond to diagonal elements of matrix U) are
+*  stored separately in an ordinary array.
+*
+*  Permutation matrices P and Q are stored in ordinary arrays in both
+*  row- and column-like formats.
+*
+*  Matrices L and U are completely defined by matrices F, V, P, and Q
+*  and therefore not stored explicitly.
+*
+*  The factorization (1)-(4) is a version of LU-factorization. Indeed,
+*  from (3) and (4) it follows that:
+*
+*     F = inv(P) * L * P,
+*
+*     U = inv(P) * U * inv(Q),
+*
+*  and substitution into (2) leads to:
+*
+*     A = F * V = inv(P) * L * U * inv(Q).
+*
+*  For more details see the program documentation. */
+
+typedef struct LUF LUF;
+
+struct LUF
+{     /* LU-factorization of a square matrix */
+      int n_max;
+      /* maximal value of n (increased automatically, if necessary) */
+      int n;
+      /* the order of matrices A, F, V, P, Q */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      /*--------------------------------------------------------------*/
+      /* matrix F in row-wise format */
+      int *fr_ptr; /* int fr_ptr[1+n_max]; */
+      /* fr_ptr[i], i = 1,...,n, is a pointer to the first element of
+         i-th row in SVA */
+      int *fr_len; /* int fr_len[1+n_max]; */
+      /* fr_len[i], i = 1,...,n, is the number of elements in i-th row
+         (except unity diagonal element) */
+      /*--------------------------------------------------------------*/
+      /* matrix F in column-wise format */
+      int *fc_ptr; /* int fc_ptr[1+n_max]; */
+      /* fc_ptr[j], j = 1,...,n, is a pointer to the first element of
+         j-th column in SVA */
+      int *fc_len; /* int fc_len[1+n_max]; */
+      /* fc_len[j], j = 1,...,n, is the number of elements in j-th
+         column (except unity diagonal element) */
+      /*--------------------------------------------------------------*/
+      /* matrix V in row-wise format */
+      int *vr_ptr; /* int vr_ptr[1+n_max]; */
+      /* vr_ptr[i], i = 1,...,n, is a pointer to the first element of
+         i-th row in SVA */
+      int *vr_len; /* int vr_len[1+n_max]; */
+      /* vr_len[i], i = 1,...,n, is the number of elements in i-th row
+         (except pivot element) */
+      int *vr_cap; /* int vr_cap[1+n_max]; */
+      /* vr_cap[i], i = 1,...,n, is the capacity of i-th row, i.e.
+         maximal number of elements which can be stored in the row
+         without relocating it, vr_cap[i] >= vr_len[i] */
+      double *vr_piv; /* double vr_piv[1+n_max]; */
+      /* vr_piv[p], p = 1,...,n, is the pivot element v[p,q] which
+         corresponds to a diagonal element of matrix U = P*V*Q */
+      /*--------------------------------------------------------------*/
+      /* matrix V in column-wise format */
+      int *vc_ptr; /* int vc_ptr[1+n_max]; */
+      /* vc_ptr[j], j = 1,...,n, is a pointer to the first element of
+         j-th column in SVA */
+      int *vc_len; /* int vc_len[1+n_max]; */
+      /* vc_len[j], j = 1,...,n, is the number of elements in j-th
+         column (except pivot element) */
+      int *vc_cap; /* int vc_cap[1+n_max]; */
+      /* vc_cap[j], j = 1,...,n, is the capacity of j-th column, i.e.
+         maximal number of elements which can be stored in the column
+         without relocating it, vc_cap[j] >= vc_len[j] */
+      /*--------------------------------------------------------------*/
+      /* matrix P */
+      int *pp_row; /* int pp_row[1+n_max]; */
+      /* pp_row[i] = j means that P[i,j] = 1 */
+      int *pp_col; /* int pp_col[1+n_max]; */
+      /* pp_col[j] = i means that P[i,j] = 1 */
+      /* if i-th row or column of matrix F is i'-th row or column of
+         matrix L, or if i-th row of matrix V is i'-th row of matrix U,
+         then pp_row[i'] = i and pp_col[i] = i' */
+      /*--------------------------------------------------------------*/
+      /* matrix Q */
+      int *qq_row; /* int qq_row[1+n_max]; */
+      /* qq_row[i] = j means that Q[i,j] = 1 */
+      int *qq_col; /* int qq_col[1+n_max]; */
+      /* qq_col[j] = i means that Q[i,j] = 1 */
+      /* if j-th column of matrix V is j'-th column of matrix U, then
+         qq_row[j] = j' and qq_col[j'] = j */
+      /*--------------------------------------------------------------*/
+      /* the Sparse Vector Area (SVA) is a set of locations used to
+         store sparse vectors representing rows and columns of matrices
+         F and V; each location is a doublet (ind, val), where ind is
+         an index, and val is a numerical value of a sparse vector
+         element; in the whole each sparse vector is a set of adjacent
+         locations defined by a pointer to the first element and the
+         number of elements; these pointer and number are stored in the
+         corresponding matrix data structure (see above); the left part
+         of SVA is used to store rows and columns of matrix V, and its
+         right part is used to store rows and columns of matrix F; the
+         middle part of SVA contains free (unused) locations */
+      int sv_size;
+      /* the size of SVA, in locations; all locations are numbered by
+         integers 1, ..., n, and location 0 is not used; if necessary,
+         the SVA size is automatically increased */
+      int sv_beg, sv_end;
+      /* SVA partitioning pointers:
+         locations from 1 to sv_beg-1 belong to the left part
+         locations from sv_beg to sv_end-1 belong to the middle part
+         locations from sv_end to sv_size belong to the right part
+         the size of the middle part is (sv_end - sv_beg) */
+      int *sv_ind; /* sv_ind[1+sv_size]; */
+      /* sv_ind[k], 1 <= k <= sv_size, is the index field of k-th
+         location */
+      double *sv_val; /* sv_val[1+sv_size]; */
+      /* sv_val[k], 1 <= k <= sv_size, is the value field of k-th
+         location */
+      /*--------------------------------------------------------------*/
+      /* in order to efficiently defragment the left part of SVA there
+         is a doubly linked list of rows and columns of matrix V, where
+         rows are numbered by 1, ..., n, while columns are numbered by
+         n+1, ..., n+n, that allows uniquely identifying each row and
+         column of V by only one integer; in this list rows and columns
+         are ordered by ascending their pointers vr_ptr and vc_ptr */
+      int sv_head;
+      /* the number of leftmost row/column */
+      int sv_tail;
+      /* the number of rightmost row/column */
+      int *sv_prev; /* int sv_prev[1+n_max+n_max]; */
+      /* sv_prev[k], k = 1,...,n+n, is the number of a row/column which
+         precedes k-th row/column */
+      int *sv_next; /* int sv_next[1+n_max+n_max]; */
+      /* sv_next[k], k = 1,...,n+n, is the number of a row/column which
+         succedes k-th row/column */
+      /*--------------------------------------------------------------*/
+      /* working segment (used only during factorization) */
+      double *vr_max; /* int vr_max[1+n_max]; */
+      /* vr_max[i], 1 <= i <= n, is used only if i-th row of matrix V
+         is active (i.e. belongs to the active submatrix), and is the
+         largest magnitude of elements in i-th row; if vr_max[i] < 0,
+         the largest magnitude is not known yet and should be computed
+         by the pivoting routine */
+      /*--------------------------------------------------------------*/
+      /* in order to efficiently implement Markowitz strategy and Duff
+         search technique there are two families {R[0], R[1], ..., R[n]}
+         and {C[0], C[1], ..., C[n]}; member R[k] is the set of active
+         rows of matrix V, which have k non-zeros, and member C[k] is
+         the set of active columns of V, which have k non-zeros in the
+         active submatrix (i.e. in the active rows); each set R[k] and
+         C[k] is implemented as a separate doubly linked list */
+      int *rs_head; /* int rs_head[1+n_max]; */
+      /* rs_head[k], 0 <= k <= n, is the number of first active row,
+         which has k non-zeros */
+      int *rs_prev; /* int rs_prev[1+n_max]; */
+      /* rs_prev[i], 1 <= i <= n, is the number of previous row, which
+         has the same number of non-zeros as i-th row */
+      int *rs_next; /* int rs_next[1+n_max]; */
+      /* rs_next[i], 1 <= i <= n, is the number of next row, which has
+         the same number of non-zeros as i-th row */
+      int *cs_head; /* int cs_head[1+n_max]; */
+      /* cs_head[k], 0 <= k <= n, is the number of first active column,
+         which has k non-zeros (in the active rows) */
+      int *cs_prev; /* int cs_prev[1+n_max]; */
+      /* cs_prev[j], 1 <= j <= n, is the number of previous column,
+         which has the same number of non-zeros (in the active rows) as
+         j-th column */
+      int *cs_next; /* int cs_next[1+n_max]; */
+      /* cs_next[j], 1 <= j <= n, is the number of next column, which
+         has the same number of non-zeros (in the active rows) as j-th
+         column */
+      /* (end of working segment) */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      int *flag; /* int flag[1+n_max]; */
+      /* integer working array */
+      double *work; /* double work[1+n_max]; */
+      /* floating-point working array */
+      /*--------------------------------------------------------------*/
+      /* control parameters */
+      int new_sva;
+      /* new required size of the sparse vector area, in locations; set
+         automatically by the factorizing routine */
+      double piv_tol;
+      /* threshold pivoting tolerance, 0 < piv_tol < 1; element v[i,j]
+         of the active submatrix fits to be pivot if it satisfies to the
+         stability criterion |v[i,j]| >= piv_tol * max |v[i,*]|, i.e. if
+         it is not very small in the magnitude among other elements in
+         the same row; decreasing this parameter gives better sparsity
+         at the expense of numerical accuracy and vice versa */
+      int piv_lim;
+      /* maximal allowable number of pivot candidates to be considered;
+         if piv_lim pivot candidates have been considered, the pivoting
+         routine terminates the search with the best candidate found */
+      int suhl;
+      /* if this flag is set, the pivoting routine applies a heuristic
+         proposed by Uwe Suhl: if a column of the active submatrix has
+         no eligible pivot candidates (i.e. all its elements do not
+         satisfy to the stability criterion), the routine excludes it
+         from futher consideration until it becomes column singleton;
+         in many cases this allows reducing the time needed for pivot
+         searching */
+      double eps_tol;
+      /* epsilon tolerance; each element of the active submatrix, whose
+         magnitude is less than eps_tol, is replaced by exact zero */
+      double max_gro;
+      /* maximal allowable growth of elements of matrix V during all
+         the factorization process; if on some eliminaion step the ratio
+         big_v / max_a (see below) becomes greater than max_gro, matrix
+         A is considered as ill-conditioned (assuming that the pivoting
+         tolerance piv_tol has an appropriate value) */
+      /*--------------------------------------------------------------*/
+      /* some statistics */
+      int nnz_a;
+      /* the number of non-zeros in matrix A */
+      int nnz_f;
+      /* the number of non-zeros in matrix F (except diagonal elements,
+         which are not stored) */
+      int nnz_v;
+      /* the number of non-zeros in matrix V (except its pivot elements,
+         which are stored in a separate array) */
+      double max_a;
+      /* the largest magnitude of elements of matrix A */
+      double big_v;
+      /* the largest magnitude of elements of matrix V appeared in the
+         active submatrix during all the factorization process */
+      int rank;
+      /* estimated rank of matrix A */
+};
+
+/* return codes: */
+#define LUF_ESING    1  /* singular matrix */
+#define LUF_ECOND    2  /* ill-conditioned matrix */
+
+#define luf_create_it _glp_luf_create_it
+LUF *luf_create_it(void);
+/* create LU-factorization */
+
+#define luf_defrag_sva _glp_luf_defrag_sva
+void luf_defrag_sva(LUF *luf);
+/* defragment the sparse vector area */
+
+#define luf_enlarge_row _glp_luf_enlarge_row
+int luf_enlarge_row(LUF *luf, int i, int cap);
+/* enlarge row capacity */
+
+#define luf_enlarge_col _glp_luf_enlarge_col
+int luf_enlarge_col(LUF *luf, int j, int cap);
+/* enlarge column capacity */
+
+#define luf_factorize _glp_luf_factorize
+int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info);
+/* compute LU-factorization */
+
+#define luf_f_solve _glp_luf_f_solve
+void luf_f_solve(LUF *luf, int tr, double x[]);
+/* solve system F*x = b or F'*x = b */
+
+#define luf_v_solve _glp_luf_v_solve
+void luf_v_solve(LUF *luf, int tr, double x[]);
+/* solve system V*x = b or V'*x = b */
+
+#define luf_a_solve _glp_luf_a_solve
+void luf_a_solve(LUF *luf, int tr, double x[]);
+/* solve system A*x = b or A'*x = b */
+
+#define luf_delete_it _glp_luf_delete_it
+void luf_delete_it(LUF *luf);
+/* delete LU-factorization */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glplux.c b/optional/glpk/glplux.c
new file mode 100644
index 0000000..32e3e16
--- /dev/null
+++ b/optional/glpk/glplux.c
@@ -0,0 +1,1028 @@
+/* glplux.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glplux.h"
+#define xfault xerror
+#define dmp_create_poolx(size) dmp_create_pool()
+
+/*----------------------------------------------------------------------
+// lux_create - create LU-factorization.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// LUX *lux_create(int n);
+//
+// DESCRIPTION
+//
+// The routine lux_create creates LU-factorization data structure for
+// a matrix of the order n. Initially the factorization corresponds to
+// the unity matrix (F = V = P = Q = I, so A = I).
+//
+// RETURNS
+//
+// The routine returns a pointer to the created LU-factorization data
+// structure, which represents the unity matrix of the order n. */
+
+LUX *lux_create(int n)
+{     LUX *lux;
+      int k;
+      if (n < 1)
+         xfault("lux_create: n = %d; invalid parameter\n", n);
+      lux = xmalloc(sizeof(LUX));
+      lux->n = n;
+      lux->pool = dmp_create_poolx(sizeof(LUXELM));
+      lux->F_row = xcalloc(1+n, sizeof(LUXELM *));
+      lux->F_col = xcalloc(1+n, sizeof(LUXELM *));
+      lux->V_piv = xcalloc(1+n, sizeof(mpq_t));
+      lux->V_row = xcalloc(1+n, sizeof(LUXELM *));
+      lux->V_col = xcalloc(1+n, sizeof(LUXELM *));
+      lux->P_row = xcalloc(1+n, sizeof(int));
+      lux->P_col = xcalloc(1+n, sizeof(int));
+      lux->Q_row = xcalloc(1+n, sizeof(int));
+      lux->Q_col = xcalloc(1+n, sizeof(int));
+      for (k = 1; k <= n; k++)
+      {  lux->F_row[k] = lux->F_col[k] = NULL;
+         mpq_init(lux->V_piv[k]);
+         mpq_set_si(lux->V_piv[k], 1, 1);
+         lux->V_row[k] = lux->V_col[k] = NULL;
+         lux->P_row[k] = lux->P_col[k] = k;
+         lux->Q_row[k] = lux->Q_col[k] = k;
+      }
+      lux->rank = n;
+      return lux;
+}
+
+/*----------------------------------------------------------------------
+// initialize - initialize LU-factorization data structures.
+//
+// This routine initializes data structures for subsequent computing
+// the LU-factorization of a given matrix A, which is specified by the
+// formal routine col. On exit V = A and F = P = Q = I, where I is the
+// unity matrix. */
+
+static void initialize(LUX *lux, int (*col)(void *info, int j,
+      int ind[], mpq_t val[]), void *info, LUXWKA *wka)
+{     int n = lux->n;
+      DMP *pool = lux->pool;
+      LUXELM **F_row = lux->F_row;
+      LUXELM **F_col = lux->F_col;
+      mpq_t *V_piv = lux->V_piv;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *P_row = lux->P_row;
+      int *P_col = lux->P_col;
+      int *Q_row = lux->Q_row;
+      int *Q_col = lux->Q_col;
+      int *R_len = wka->R_len;
+      int *R_head = wka->R_head;
+      int *R_prev = wka->R_prev;
+      int *R_next = wka->R_next;
+      int *C_len = wka->C_len;
+      int *C_head = wka->C_head;
+      int *C_prev = wka->C_prev;
+      int *C_next = wka->C_next;
+      LUXELM *fij, *vij;
+      int i, j, k, len, *ind;
+      mpq_t *val;
+      /* F := I */
+      for (i = 1; i <= n; i++)
+      {  while (F_row[i] != NULL)
+         {  fij = F_row[i], F_row[i] = fij->r_next;
+            mpq_clear(fij->val);
+            dmp_free_atom(pool, fij, sizeof(LUXELM));
+         }
+      }
+      for (j = 1; j <= n; j++) F_col[j] = NULL;
+      /* V := 0 */
+      for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1);
+      for (i = 1; i <= n; i++)
+      {  while (V_row[i] != NULL)
+         {  vij = V_row[i], V_row[i] = vij->r_next;
+            mpq_clear(vij->val);
+            dmp_free_atom(pool, vij, sizeof(LUXELM));
+         }
+      }
+      for (j = 1; j <= n; j++) V_col[j] = NULL;
+      /* V := A */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(mpq_t));
+      for (k = 1; k <= n; k++) mpq_init(val[k]);
+      for (j = 1; j <= n; j++)
+      {  /* obtain j-th column of matrix A */
+         len = col(info, j, ind, val);
+         if (!(0 <= len && len <= n))
+            xfault("lux_decomp: j = %d: len = %d; invalid column length"
+               "\n", j, len);
+         /* copy elements of j-th column to matrix V */
+         for (k = 1; k <= len; k++)
+         {  /* get row index of a[i,j] */
+            i = ind[k];
+            if (!(1 <= i && i <= n))
+               xfault("lux_decomp: j = %d: i = %d; row index out of ran"
+                  "ge\n", j, i);
+            /* check for duplicate indices */
+            if (V_row[i] != NULL && V_row[i]->j == j)
+               xfault("lux_decomp: j = %d: i = %d; duplicate row indice"
+                  "s not allowed\n", j, i);
+            /* check for zero value */
+            if (mpq_sgn(val[k]) == 0)
+               xfault("lux_decomp: j = %d: i = %d; zero elements not al"
+                  "lowed\n", j, i);
+            /* add new element v[i,j] = a[i,j] to V */
+            vij = dmp_get_atom(pool, sizeof(LUXELM));
+            vij->i = i, vij->j = j;
+            mpq_init(vij->val);
+            mpq_set(vij->val, val[k]);
+            vij->r_prev = NULL;
+            vij->r_next = V_row[i];
+            vij->c_prev = NULL;
+            vij->c_next = V_col[j];
+            if (vij->r_next != NULL) vij->r_next->r_prev = vij;
+            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+            V_row[i] = V_col[j] = vij;
+         }
+      }
+      xfree(ind);
+      for (k = 1; k <= n; k++) mpq_clear(val[k]);
+      xfree(val);
+      /* P := Q := I */
+      for (k = 1; k <= n; k++)
+         P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k;
+      /* the rank of A and V is not determined yet */
+      lux->rank = -1;
+      /* initially the entire matrix V is active */
+      /* determine its row lengths */
+      for (i = 1; i <= n; i++)
+      {  len = 0;
+         for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++;
+         R_len[i] = len;
+      }
+      /* build linked lists of active rows */
+      for (len = 0; len <= n; len++) R_head[len] = 0;
+      for (i = 1; i <= n; i++)
+      {  len = R_len[i];
+         R_prev[i] = 0;
+         R_next[i] = R_head[len];
+         if (R_next[i] != 0) R_prev[R_next[i]] = i;
+         R_head[len] = i;
+      }
+      /* determine its column lengths */
+      for (j = 1; j <= n; j++)
+      {  len = 0;
+         for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++;
+         C_len[j] = len;
+      }
+      /* build linked lists of active columns */
+      for (len = 0; len <= n; len++) C_head[len] = 0;
+      for (j = 1; j <= n; j++)
+      {  len = C_len[j];
+         C_prev[j] = 0;
+         C_next[j] = C_head[len];
+         if (C_next[j] != 0) C_prev[C_next[j]] = j;
+         C_head[len] = j;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// find_pivot - choose a pivot element.
+//
+// This routine chooses a pivot element v[p,q] in the active submatrix
+// of matrix U = P*V*Q.
+//
+// It is assumed that on entry the matrix U has the following partially
+// triangularized form:
+//
+//       1       k         n
+//    1  x x x x x x x x x x
+//       . x x x x x x x x x
+//       . . x x x x x x x x
+//       . . . x x x x x x x
+//    k  . . . . * * * * * *
+//       . . . . * * * * * *
+//       . . . . * * * * * *
+//       . . . . * * * * * *
+//       . . . . * * * * * *
+//    n  . . . . * * * * * *
+//
+// where rows and columns k, k+1, ..., n belong to the active submatrix
+// (elements of the active submatrix are marked by '*').
+//
+// Since the matrix U = P*V*Q is not stored, the routine works with the
+// matrix V. It is assumed that the row-wise representation corresponds
+// to the matrix V, but the column-wise representation corresponds to
+// the active submatrix of the matrix V, i.e. elements of the matrix V,
+// which does not belong to the active submatrix, are missing from the
+// column linked lists. It is also assumed that each active row of the
+// matrix V is in the set R[len], where len is number of non-zeros in
+// the row, and each active column of the matrix V is in the set C[len],
+// where len is number of non-zeros in the column (in the latter case
+// only elements of the active submatrix are counted; such elements are
+// marked by '*' on the figure above).
+//
+// Due to exact arithmetic any non-zero element of the active submatrix
+// can be chosen as a pivot. However, to keep sparsity of the matrix V
+// the routine uses Markowitz strategy, trying to choose such element
+// v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1),
+// where nr[p] and nc[q] are the number of non-zero elements, resp., in
+// p-th row and in q-th column of the active submatrix.
+//
+// In order to reduce the search, i.e. not to walk through all elements
+// of the active submatrix, the routine exploits a technique proposed by
+// I.Duff. This technique is based on using the sets R[len] and C[len]
+// of active rows and columns.
+//
+// On exit the routine returns a pointer to a pivot v[p,q] chosen, or
+// NULL, if the active submatrix is empty. */
+
+static LUXELM *find_pivot(LUX *lux, LUXWKA *wka)
+{     int n = lux->n;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *R_len = wka->R_len;
+      int *R_head = wka->R_head;
+      int *R_next = wka->R_next;
+      int *C_len = wka->C_len;
+      int *C_head = wka->C_head;
+      int *C_next = wka->C_next;
+      LUXELM *piv, *some, *vij;
+      int i, j, len, min_len, ncand, piv_lim = 5;
+      double best, cost;
+      /* nothing is chosen so far */
+      piv = NULL, best = DBL_MAX, ncand = 0;
+      /* if in the active submatrix there is a column that has the only
+         non-zero (column singleton), choose it as a pivot */
+      j = C_head[1];
+      if (j != 0)
+      {  xassert(C_len[j] == 1);
+         piv = V_col[j];
+         xassert(piv != NULL && piv->c_next == NULL);
+         goto done;
+      }
+      /* if in the active submatrix there is a row that has the only
+         non-zero (row singleton), choose it as a pivot */
+      i = R_head[1];
+      if (i != 0)
+      {  xassert(R_len[i] == 1);
+         piv = V_row[i];
+         xassert(piv != NULL && piv->r_next == NULL);
+         goto done;
+      }
+      /* there are no singletons in the active submatrix; walk through
+         other non-empty rows and columns */
+      for (len = 2; len <= n; len++)
+      {  /* consider active columns having len non-zeros */
+         for (j = C_head[len]; j != 0; j = C_next[j])
+         {  /* j-th column has len non-zeros */
+            /* find an element in the row of minimal length */
+            some = NULL, min_len = INT_MAX;
+            for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
+            {  if (min_len > R_len[vij->i])
+                  some = vij, min_len = R_len[vij->i];
+               /* if Markowitz cost of this element is not greater than
+                  (len-1)**2, it can be chosen right now; this heuristic
+                  reduces the search and works well in many cases */
+               if (min_len <= len)
+               {  piv = some;
+                  goto done;
+               }
+            }
+            /* j-th column has been scanned */
+            /* the minimal element found is a next pivot candidate */
+            xassert(some != NULL);
+            ncand++;
+            /* compute its Markowitz cost */
+            cost = (double)(min_len - 1) * (double)(len - 1);
+            /* choose between the current candidate and this element */
+            if (cost < best) piv = some, best = cost;
+            /* if piv_lim candidates have been considered, there is a
+               doubt that a much better candidate exists; therefore it
+               is the time to terminate the search */
+            if (ncand == piv_lim) goto done;
+         }
+         /* now consider active rows having len non-zeros */
+         for (i = R_head[len]; i != 0; i = R_next[i])
+         {  /* i-th row has len non-zeros */
+            /* find an element in the column of minimal length */
+            some = NULL, min_len = INT_MAX;
+            for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+            {  if (min_len > C_len[vij->j])
+                  some = vij, min_len = C_len[vij->j];
+               /* if Markowitz cost of this element is not greater than
+                  (len-1)**2, it can be chosen right now; this heuristic
+                  reduces the search and works well in many cases */
+               if (min_len <= len)
+               {  piv = some;
+                  goto done;
+               }
+            }
+            /* i-th row has been scanned */
+            /* the minimal element found is a next pivot candidate */
+            xassert(some != NULL);
+            ncand++;
+            /* compute its Markowitz cost */
+            cost = (double)(len - 1) * (double)(min_len - 1);
+            /* choose between the current candidate and this element */
+            if (cost < best) piv = some, best = cost;
+            /* if piv_lim candidates have been considered, there is a
+               doubt that a much better candidate exists; therefore it
+               is the time to terminate the search */
+            if (ncand == piv_lim) goto done;
+         }
+      }
+done: /* bring the pivot v[p,q] to the factorizing routine */
+      return piv;
+}
+
+/*----------------------------------------------------------------------
+// eliminate - perform gaussian elimination.
+//
+// This routine performs elementary gaussian transformations in order
+// to eliminate subdiagonal elements in the k-th column of the matrix
+// U = P*V*Q using the pivot element u[k,k], where k is the number of
+// the current elimination step.
+//
+// The parameter piv specifies the pivot element v[p,q] = u[k,k].
+//
+// Each time when the routine applies the elementary transformation to
+// a non-pivot row of the matrix V, it stores the corresponding element
+// to the matrix F in order to keep the main equality A = F*V.
+//
+// The routine assumes that on entry the matrices L = P*F*inv(P) and
+// U = P*V*Q are the following:
+//
+//       1       k                  1       k         n
+//    1  1 . . . . . . . . .     1  x x x x x x x x x x
+//       x 1 . . . . . . . .        . x x x x x x x x x
+//       x x 1 . . . . . . .        . . x x x x x x x x
+//       x x x 1 . . . . . .        . . . x x x x x x x
+//    k  x x x x 1 . . . . .     k  . . . . * * * * * *
+//       x x x x _ 1 . . . .        . . . . # * * * * *
+//       x x x x _ . 1 . . .        . . . . # * * * * *
+//       x x x x _ . . 1 . .        . . . . # * * * * *
+//       x x x x _ . . . 1 .        . . . . # * * * * *
+//    n  x x x x _ . . . . 1     n  . . . . # * * * * *
+//
+//            matrix L                   matrix U
+//
+// where rows and columns of the matrix U with numbers k, k+1, ..., n
+// form the active submatrix (eliminated elements are marked by '#' and
+// other elements of the active submatrix are marked by '*'). Note that
+// each eliminated non-zero element u[i,k] of the matrix U gives the
+// corresponding element l[i,k] of the matrix L (marked by '_').
+//
+// Actually all operations are performed on the matrix V. Should note
+// that the row-wise representation corresponds to the matrix V, but the
+// column-wise representation corresponds to the active submatrix of the
+// matrix V, i.e. elements of the matrix V, which doesn't belong to the
+// active submatrix, are missing from the column linked lists.
+//
+// Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
+// elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
+// the following elementary gaussian transformations:
+//
+//    (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
+//
+// where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
+//
+// Additionally, in order to keep the main equality A = F*V, each time
+// when the routine applies the transformation to i-th row of the matrix
+// V, it also adds f[i,p] as a new element to the matrix F.
+//
+// IMPORTANT: On entry the working arrays flag and work should contain
+// zeros. This status is provided by the routine on exit. */
+
+static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[],
+      mpq_t work[])
+{     DMP *pool = lux->pool;
+      LUXELM **F_row = lux->F_row;
+      LUXELM **F_col = lux->F_col;
+      mpq_t *V_piv = lux->V_piv;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *R_len = wka->R_len;
+      int *R_head = wka->R_head;
+      int *R_prev = wka->R_prev;
+      int *R_next = wka->R_next;
+      int *C_len = wka->C_len;
+      int *C_head = wka->C_head;
+      int *C_prev = wka->C_prev;
+      int *C_next = wka->C_next;
+      LUXELM *fip, *vij, *vpj, *viq, *next;
+      mpq_t temp;
+      int i, j, p, q;
+      mpq_init(temp);
+      /* determine row and column indices of the pivot v[p,q] */
+      xassert(piv != NULL);
+      p = piv->i, q = piv->j;
+      /* remove p-th (pivot) row from the active set; it will never
+         return there */
+      if (R_prev[p] == 0)
+         R_head[R_len[p]] = R_next[p];
+      else
+         R_next[R_prev[p]] = R_next[p];
+      if (R_next[p] == 0)
+         ;
+      else
+         R_prev[R_next[p]] = R_prev[p];
+      /* remove q-th (pivot) column from the active set; it will never
+         return there */
+      if (C_prev[q] == 0)
+         C_head[C_len[q]] = C_next[q];
+      else
+         C_next[C_prev[q]] = C_next[q];
+      if (C_next[q] == 0)
+         ;
+      else
+         C_prev[C_next[q]] = C_prev[q];
+      /* store the pivot value in a separate array */
+      mpq_set(V_piv[p], piv->val);
+      /* remove the pivot from p-th row */
+      if (piv->r_prev == NULL)
+         V_row[p] = piv->r_next;
+      else
+         piv->r_prev->r_next = piv->r_next;
+      if (piv->r_next == NULL)
+         ;
+      else
+         piv->r_next->r_prev = piv->r_prev;
+      R_len[p]--;
+      /* remove the pivot from q-th column */
+      if (piv->c_prev == NULL)
+         V_col[q] = piv->c_next;
+      else
+         piv->c_prev->c_next = piv->c_next;
+      if (piv->c_next == NULL)
+         ;
+      else
+         piv->c_next->c_prev = piv->c_prev;
+      C_len[q]--;
+      /* free the space occupied by the pivot */
+      mpq_clear(piv->val);
+      dmp_free_atom(pool, piv, sizeof(LUXELM));
+      /* walk through p-th (pivot) row, which already does not contain
+         the pivot v[p,q], and do the following... */
+      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+      {  /* get column index of v[p,j] */
+         j = vpj->j;
+         /* store v[p,j] in the working array */
+         flag[j] = 1;
+         mpq_set(work[j], vpj->val);
+         /* remove j-th column from the active set; it will return there
+            later with a new length */
+         if (C_prev[j] == 0)
+            C_head[C_len[j]] = C_next[j];
+         else
+            C_next[C_prev[j]] = C_next[j];
+         if (C_next[j] == 0)
+            ;
+         else
+            C_prev[C_next[j]] = C_prev[j];
+         /* v[p,j] leaves the active submatrix, so remove it from j-th
+            column; however, v[p,j] is kept in p-th row */
+         if (vpj->c_prev == NULL)
+            V_col[j] = vpj->c_next;
+         else
+            vpj->c_prev->c_next = vpj->c_next;
+         if (vpj->c_next == NULL)
+            ;
+         else
+            vpj->c_next->c_prev = vpj->c_prev;
+         C_len[j]--;
+      }
+      /* now walk through q-th (pivot) column, which already does not
+         contain the pivot v[p,q], and perform gaussian elimination */
+      while (V_col[q] != NULL)
+      {  /* element v[i,q] has to be eliminated */
+         viq = V_col[q];
+         /* get row index of v[i,q] */
+         i = viq->i;
+         /* remove i-th row from the active set; later it will return
+            there with a new length */
+         if (R_prev[i] == 0)
+            R_head[R_len[i]] = R_next[i];
+         else
+            R_next[R_prev[i]] = R_next[i];
+         if (R_next[i] == 0)
+            ;
+         else
+            R_prev[R_next[i]] = R_prev[i];
+         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and
+            store it in the matrix F */
+         fip = dmp_get_atom(pool, sizeof(LUXELM));
+         fip->i = i, fip->j = p;
+         mpq_init(fip->val);
+         mpq_div(fip->val, viq->val, V_piv[p]);
+         fip->r_prev = NULL;
+         fip->r_next = F_row[i];
+         fip->c_prev = NULL;
+         fip->c_next = F_col[p];
+         if (fip->r_next != NULL) fip->r_next->r_prev = fip;
+         if (fip->c_next != NULL) fip->c_next->c_prev = fip;
+         F_row[i] = F_col[p] = fip;
+         /* v[i,q] has to be eliminated, so remove it from i-th row */
+         if (viq->r_prev == NULL)
+            V_row[i] = viq->r_next;
+         else
+            viq->r_prev->r_next = viq->r_next;
+         if (viq->r_next == NULL)
+            ;
+         else
+            viq->r_next->r_prev = viq->r_prev;
+         R_len[i]--;
+         /* and also from q-th column */
+         V_col[q] = viq->c_next;
+         C_len[q]--;
+         /* free the space occupied by v[i,q] */
+         mpq_clear(viq->val);
+         dmp_free_atom(pool, viq, sizeof(LUXELM));
+         /* perform gaussian transformation:
+            (i-th row) := (i-th row) - f[i,p] * (p-th row)
+            note that now p-th row, which is in the working array,
+            does not contain the pivot v[p,q], and i-th row does not
+            contain the element v[i,q] to be eliminated */
+         /* walk through i-th row and transform existing non-zero
+            elements */
+         for (vij = V_row[i]; vij != NULL; vij = next)
+         {  next = vij->r_next;
+            /* get column index of v[i,j] */
+            j = vij->j;
+            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
+            if (flag[j])
+            {  /* v[p,j] != 0 */
+               flag[j] = 0;
+               mpq_mul(temp, fip->val, work[j]);
+               mpq_sub(vij->val, vij->val, temp);
+               if (mpq_sgn(vij->val) == 0)
+               {  /* new v[i,j] is zero, so remove it from the active
+                     submatrix */
+                  /* remove v[i,j] from i-th row */
+                  if (vij->r_prev == NULL)
+                     V_row[i] = vij->r_next;
+                  else
+                     vij->r_prev->r_next = vij->r_next;
+                  if (vij->r_next == NULL)
+                     ;
+                  else
+                     vij->r_next->r_prev = vij->r_prev;
+                  R_len[i]--;
+                  /* remove v[i,j] from j-th column */
+                  if (vij->c_prev == NULL)
+                     V_col[j] = vij->c_next;
+                  else
+                     vij->c_prev->c_next = vij->c_next;
+                  if (vij->c_next == NULL)
+                     ;
+                  else
+                     vij->c_next->c_prev = vij->c_prev;
+                  C_len[j]--;
+                  /* free the space occupied by v[i,j] */
+                  mpq_clear(vij->val);
+                  dmp_free_atom(pool, vij, sizeof(LUXELM));
+               }
+            }
+         }
+         /* now flag is the pattern of the set v[p,*] \ v[i,*] */
+         /* walk through p-th (pivot) row and create new elements in
+            i-th row, which appear due to fill-in */
+         for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+         {  j = vpj->j;
+            if (flag[j])
+            {  /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and
+                  add it to i-th row and j-th column */
+               vij = dmp_get_atom(pool, sizeof(LUXELM));
+               vij->i = i, vij->j = j;
+               mpq_init(vij->val);
+               mpq_mul(vij->val, fip->val, work[j]);
+               mpq_neg(vij->val, vij->val);
+               vij->r_prev = NULL;
+               vij->r_next = V_row[i];
+               vij->c_prev = NULL;
+               vij->c_next = V_col[j];
+               if (vij->r_next != NULL) vij->r_next->r_prev = vij;
+               if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+               V_row[i] = V_col[j] = vij;
+               R_len[i]++, C_len[j]++;
+            }
+            else
+            {  /* there is no fill-in, because v[i,j] already exists in
+                  i-th row; restore the flag, which was reset before */
+               flag[j] = 1;
+            }
+         }
+         /* now i-th row has been completely transformed and can return
+            to the active set with a new length */
+         R_prev[i] = 0;
+         R_next[i] = R_head[R_len[i]];
+         if (R_next[i] != 0) R_prev[R_next[i]] = i;
+         R_head[R_len[i]] = i;
+      }
+      /* at this point q-th (pivot) column must be empty */
+      xassert(C_len[q] == 0);
+      /* walk through p-th (pivot) row again and do the following... */
+      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+      {  /* get column index of v[p,j] */
+         j = vpj->j;
+         /* erase v[p,j] from the working array */
+         flag[j] = 0;
+         mpq_set_si(work[j], 0, 1);
+         /* now j-th column has been completely transformed, so it can
+            return to the active list with a new length */
+         C_prev[j] = 0;
+         C_next[j] = C_head[C_len[j]];
+         if (C_next[j] != 0) C_prev[C_next[j]] = j;
+         C_head[C_len[j]] = j;
+      }
+      mpq_clear(temp);
+      /* return to the factorizing routine */
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_decomp - compute LU-factorization.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+//    mpq_t val[]), void *info);
+//
+// DESCRIPTION
+//
+// The routine lux_decomp computes LU-factorization of a given square
+// matrix A.
+//
+// The parameter lux specifies LU-factorization data structure built by
+// means of the routine lux_create.
+//
+// The formal routine col specifies the original matrix A. In order to
+// obtain j-th column of the matrix A the routine lux_decomp calls the
+// routine col with the parameter j (1 <= j <= n, where n is the order
+// of A). In response the routine col should store row indices and
+// numerical values of non-zero elements of j-th column of A to the
+// locations ind[1], ..., ind[len] and val[1], ..., val[len], resp.,
+// where len is the number of non-zeros in j-th column, which should be
+// returned on exit. Neiter zero nor duplicate elements are allowed.
+//
+// The parameter info is a transit pointer passed to the formal routine
+// col; it can be used for various purposes.
+//
+// RETURNS
+//
+// The routine lux_decomp returns the singularity flag. Zero flag means
+// that the original matrix A is non-singular while non-zero flag means
+// that A is (exactly!) singular.
+//
+// Note that LU-factorization is valid in both cases, however, in case
+// of singularity some rows of the matrix V (including pivot elements)
+// will be empty.
+//
+// REPAIRING SINGULAR MATRIX
+//
+// If the routine lux_decomp returns non-zero flag, it provides all
+// necessary information that can be used for "repairing" the matrix A,
+// where "repairing" means replacing linearly dependent columns of the
+// matrix A by appropriate columns of the unity matrix. This feature is
+// needed when the routine lux_decomp is used for reinverting the basis
+// matrix within the simplex method procedure.
+//
+// On exit linearly dependent columns of the matrix U have the numbers
+// rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A
+// stored by the routine to the member lux->rank. The correspondence
+// between columns of A and U is the same as between columns of V and U.
+// Thus, linearly dependent columns of the matrix A have the numbers
+// Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array
+// representing the permutation matrix Q in column-like format. It is
+// understood that each j-th linearly dependent column of the matrix U
+// should be replaced by the unity vector, where all elements are zero
+// except the unity diagonal element u[j,j]. On the other hand j-th row
+// of the matrix U corresponds to the row of the matrix V (and therefore
+// of the matrix A) with the number P_row[j], where P_row is an array
+// representing the permutation matrix P in row-like format. Thus, each
+// j-th linearly dependent column of the matrix U should be replaced by
+// a column of the unity matrix with the number P_row[j].
+//
+// The code that repairs the matrix A may look like follows:
+//
+//    for (j = rank+1; j <= n; j++)
+//    {  replace column Q_col[j] of the matrix A by column P_row[j] of
+//       the unity matrix;
+//    }
+//
+// where rank, P_row, and Q_col are members of the structure LUX. */
+
+int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+      mpq_t val[]), void *info)
+{     int n = lux->n;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *P_row = lux->P_row;
+      int *P_col = lux->P_col;
+      int *Q_row = lux->Q_row;
+      int *Q_col = lux->Q_col;
+      LUXELM *piv, *vij;
+      LUXWKA *wka;
+      int i, j, k, p, q, t, *flag;
+      mpq_t *work;
+      /* allocate working area */
+      wka = xmalloc(sizeof(LUXWKA));
+      wka->R_len = xcalloc(1+n, sizeof(int));
+      wka->R_head = xcalloc(1+n, sizeof(int));
+      wka->R_prev = xcalloc(1+n, sizeof(int));
+      wka->R_next = xcalloc(1+n, sizeof(int));
+      wka->C_len = xcalloc(1+n, sizeof(int));
+      wka->C_head = xcalloc(1+n, sizeof(int));
+      wka->C_prev = xcalloc(1+n, sizeof(int));
+      wka->C_next = xcalloc(1+n, sizeof(int));
+      /* initialize LU-factorization data structures */
+      initialize(lux, col, info, wka);
+      /* allocate working arrays */
+      flag = xcalloc(1+n, sizeof(int));
+      work = xcalloc(1+n, sizeof(mpq_t));
+      for (k = 1; k <= n; k++)
+      {  flag[k] = 0;
+         mpq_init(work[k]);
+      }
+      /* main elimination loop */
+      for (k = 1; k <= n; k++)
+      {  /* choose a pivot element v[p,q] */
+         piv = find_pivot(lux, wka);
+         if (piv == NULL)
+         {  /* no pivot can be chosen, because the active submatrix is
+               empty */
+            break;
+         }
+         /* determine row and column indices of the pivot element */
+         p = piv->i, q = piv->j;
+         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
+            rows and k-th and j'-th columns of the matrix U = P*V*Q to
+            move the element u[i',j'] to the position u[k,k] */
+         i = P_col[p], j = Q_row[q];
+         xassert(k <= i && i <= n && k <= j && j <= n);
+         /* permute k-th and i-th rows of the matrix U */
+         t = P_row[k];
+         P_row[i] = t, P_col[t] = i;
+         P_row[k] = p, P_col[p] = k;
+         /* permute k-th and j-th columns of the matrix U */
+         t = Q_col[k];
+         Q_col[j] = t, Q_row[t] = j;
+         Q_col[k] = q, Q_row[q] = k;
+         /* eliminate subdiagonal elements of k-th column of the matrix
+            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
+         eliminate(lux, wka, piv, flag, work);
+      }
+      /* determine the rank of A (and V) */
+      lux->rank = k - 1;
+      /* free working arrays */
+      xfree(flag);
+      for (k = 1; k <= n; k++) mpq_clear(work[k]);
+      xfree(work);
+      /* build column lists of the matrix V using its row lists */
+      for (j = 1; j <= n; j++)
+         xassert(V_col[j] == NULL);
+      for (i = 1; i <= n; i++)
+      {  for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+         {  j = vij->j;
+            vij->c_prev = NULL;
+            vij->c_next = V_col[j];
+            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+            V_col[j] = vij;
+         }
+      }
+      /* free working area */
+      xfree(wka->R_len);
+      xfree(wka->R_head);
+      xfree(wka->R_prev);
+      xfree(wka->R_next);
+      xfree(wka->C_len);
+      xfree(wka->C_head);
+      xfree(wka->C_prev);
+      xfree(wka->C_next);
+      xfree(wka);
+      /* return to the calling program */
+      return (lux->rank < n);
+}
+
+/*----------------------------------------------------------------------
+// lux_f_solve - solve system F*x = b or F'*x = b.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
+//
+// DESCRIPTION
+//
+// The routine lux_f_solve solves either the system F*x = b (if the
+// flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
+// where the matrix F is a component of LU-factorization specified by
+// the parameter lux, F' is a matrix transposed to F.
+//
+// On entry the array x should contain elements of the right-hand side
+// vector b in locations x[1], ..., x[n], where n is the order of the
+// matrix F. On exit this array will contain elements of the solution
+// vector x in the same locations. */
+
+void lux_f_solve(LUX *lux, int tr, mpq_t x[])
+{     int n = lux->n;
+      LUXELM **F_row = lux->F_row;
+      LUXELM **F_col = lux->F_col;
+      int *P_row = lux->P_row;
+      LUXELM *fik, *fkj;
+      int i, j, k;
+      mpq_t temp;
+      mpq_init(temp);
+      if (!tr)
+      {  /* solve the system F*x = b */
+         for (j = 1; j <= n; j++)
+         {  k = P_row[j];
+            if (mpq_sgn(x[k]) != 0)
+            {  for (fik = F_col[k]; fik != NULL; fik = fik->c_next)
+               {  mpq_mul(temp, fik->val, x[k]);
+                  mpq_sub(x[fik->i], x[fik->i], temp);
+               }
+            }
+         }
+      }
+      else
+      {  /* solve the system F'*x = b */
+         for (i = n; i >= 1; i--)
+         {  k = P_row[i];
+            if (mpq_sgn(x[k]) != 0)
+            {  for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next)
+               {  mpq_mul(temp, fkj->val, x[k]);
+                  mpq_sub(x[fkj->j], x[fkj->j], temp);
+               }
+            }
+         }
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_v_solve - solve system V*x = b or V'*x = b.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_v_solve(LUX *lux, int tr, double x[]);
+//
+// DESCRIPTION
+//
+// The routine lux_v_solve solves either the system V*x = b (if the
+// flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
+// where the matrix V is a component of LU-factorization specified by
+// the parameter lux, V' is a matrix transposed to V.
+//
+// On entry the array x should contain elements of the right-hand side
+// vector b in locations x[1], ..., x[n], where n is the order of the
+// matrix V. On exit this array will contain elements of the solution
+// vector x in the same locations. */
+
+void lux_v_solve(LUX *lux, int tr, mpq_t x[])
+{     int n = lux->n;
+      mpq_t *V_piv = lux->V_piv;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *P_row = lux->P_row;
+      int *Q_col = lux->Q_col;
+      LUXELM *vij;
+      int i, j, k;
+      mpq_t *b, temp;
+      b = xcalloc(1+n, sizeof(mpq_t));
+      for (k = 1; k <= n; k++)
+         mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1);
+      mpq_init(temp);
+      if (!tr)
+      {  /* solve the system V*x = b */
+         for (k = n; k >= 1; k--)
+         {  i = P_row[k], j = Q_col[k];
+            if (mpq_sgn(b[i]) != 0)
+            {  mpq_set(x[j], b[i]);
+               mpq_div(x[j], x[j], V_piv[i]);
+               for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
+               {  mpq_mul(temp, vij->val, x[j]);
+                  mpq_sub(b[vij->i], b[vij->i], temp);
+               }
+            }
+         }
+      }
+      else
+      {  /* solve the system V'*x = b */
+         for (k = 1; k <= n; k++)
+         {  i = P_row[k], j = Q_col[k];
+            if (mpq_sgn(b[j]) != 0)
+            {  mpq_set(x[i], b[j]);
+               mpq_div(x[i], x[i], V_piv[i]);
+               for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+               {  mpq_mul(temp, vij->val, x[i]);
+                  mpq_sub(b[vij->j], b[vij->j], temp);
+               }
+            }
+         }
+      }
+      for (k = 1; k <= n; k++) mpq_clear(b[k]);
+      mpq_clear(temp);
+      xfree(b);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_solve - solve system A*x = b or A'*x = b.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_solve(LUX *lux, int tr, mpq_t x[]);
+//
+// DESCRIPTION
+//
+// The routine lux_solve solves either the system A*x = b (if the flag
+// tr is zero) or the system A'*x = b (if the flag tr is non-zero),
+// where the parameter lux specifies LU-factorization of the matrix A,
+// A' is a matrix transposed to A.
+//
+// On entry the array x should contain elements of the right-hand side
+// vector b in locations x[1], ..., x[n], where n is the order of the
+// matrix A. On exit this array will contain elements of the solution
+// vector x in the same locations. */
+
+void lux_solve(LUX *lux, int tr, mpq_t x[])
+{     if (lux->rank < lux->n)
+         xfault("lux_solve: LU-factorization has incomplete rank\n");
+      if (!tr)
+      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
+         lux_f_solve(lux, 0, x);
+         lux_v_solve(lux, 0, x);
+      }
+      else
+      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
+         lux_v_solve(lux, 1, x);
+         lux_f_solve(lux, 1, x);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_delete - delete LU-factorization.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_delete(LUX *lux);
+//
+// DESCRIPTION
+//
+// The routine lux_delete deletes LU-factorization data structure,
+// which the parameter lux points to, freeing all the memory allocated
+// to this object. */
+
+void lux_delete(LUX *lux)
+{     int n = lux->n;
+      LUXELM *fij, *vij;
+      int i;
+      for (i = 1; i <= n; i++)
+      {  for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next)
+            mpq_clear(fij->val);
+         mpq_clear(lux->V_piv[i]);
+         for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next)
+            mpq_clear(vij->val);
+      }
+      dmp_delete_pool(lux->pool);
+      xfree(lux->F_row);
+      xfree(lux->F_col);
+      xfree(lux->V_piv);
+      xfree(lux->V_row);
+      xfree(lux->V_col);
+      xfree(lux->P_row);
+      xfree(lux->P_col);
+      xfree(lux->Q_row);
+      xfree(lux->Q_col);
+      xfree(lux);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glplux.h b/optional/glpk/glplux.h
new file mode 100644
index 0000000..73ee91f
--- /dev/null
+++ b/optional/glpk/glplux.h
@@ -0,0 +1,221 @@
+/* glplux.h (LU-factorization, bignum arithmetic) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPLUX_H
+#define GLPLUX_H
+
+#include "glpdmp.h"
+#include "glpgmp.h"
+
+/*----------------------------------------------------------------------
+// The structure LUX defines LU-factorization of a square matrix A,
+// which is the following quartet:
+//
+//    [A] = (F, V, P, Q),                                            (1)
+//
+// where F and V are such matrices that
+//
+//    A = F * V,                                                     (2)
+//
+// and P and Q are such permutation matrices that the matrix
+//
+//    L = P * F * inv(P)                                             (3)
+//
+// is lower triangular with unity diagonal, and the matrix
+//
+//    U = P * V * Q                                                  (4)
+//
+// is upper triangular. All the matrices have the order n.
+//
+// The matrices F and V are stored in row/column-wise sparse format as
+// row and column linked lists of non-zero elements. Unity elements on
+// the main diagonal of the matrix F are not stored. Pivot elements of
+// the matrix V (that correspond to diagonal elements of the matrix U)
+// are also missing from the row and column lists and stored separately
+// in an ordinary array.
+//
+// The permutation matrices P and Q are stored as ordinary arrays using
+// both row- and column-like formats.
+//
+// The matrices L and U being completely defined by the matrices F, V,
+// P, and Q are not stored explicitly.
+//
+// It is easy to show that the factorization (1)-(3) is some version of
+// LU-factorization. Indeed, from (3) and (4) it follows that:
+//
+//    F = inv(P) * L * P,
+//
+//    V = inv(P) * U * inv(Q),
+//
+// and substitution into (2) gives:
+//
+//    A = F * V = inv(P) * L * U * inv(Q).
+//
+// For more details see the program documentation. */
+
+typedef struct LUX LUX;
+typedef struct LUXELM LUXELM;
+typedef struct LUXWKA LUXWKA;
+
+struct LUX
+{     /* LU-factorization of a square matrix */
+      int n;
+      /* the order of matrices A, F, V, P, Q */
+      DMP *pool;
+      /* memory pool for elements of matrices F and V */
+      LUXELM **F_row; /* LUXELM *F_row[1+n]; */
+      /* F_row[0] is not used;
+         F_row[i], 1 <= i <= n, is a pointer to the list of elements in
+         i-th row of matrix F (diagonal elements are not stored) */
+      LUXELM **F_col; /* LUXELM *F_col[1+n]; */
+      /* F_col[0] is not used;
+         F_col[j], 1 <= j <= n, is a pointer to the list of elements in
+         j-th column of matrix F (diagonal elements are not stored) */
+      mpq_t *V_piv; /* mpq_t V_piv[1+n]; */
+      /* V_piv[0] is not used;
+         V_piv[p], 1 <= p <= n, is a pivot element v[p,q] corresponding
+         to a diagonal element u[k,k] of matrix U = P*V*Q (used on k-th
+         elimination step, k = 1, 2, ..., n) */
+      LUXELM **V_row; /* LUXELM *V_row[1+n]; */
+      /* V_row[0] is not used;
+         V_row[i], 1 <= i <= n, is a pointer to the list of elements in
+         i-th row of matrix V (except pivot elements) */
+      LUXELM **V_col; /* LUXELM *V_col[1+n]; */
+      /* V_col[0] is not used;
+         V_col[j], 1 <= j <= n, is a pointer to the list of elements in
+         j-th column of matrix V (except pivot elements) */
+      int *P_row; /* int P_row[1+n]; */
+      /* P_row[0] is not used;
+         P_row[i] = j means that p[i,j] = 1, where p[i,j] is an element
+         of permutation matrix P */
+      int *P_col; /* int P_col[1+n]; */
+      /* P_col[0] is not used;
+         P_col[j] = i means that p[i,j] = 1, where p[i,j] is an element
+         of permutation matrix P */
+      /* if i-th row or column of matrix F is i'-th row or column of
+         matrix L = P*F*inv(P), or if i-th row of matrix V is i'-th row
+         of matrix U = P*V*Q, then P_row[i'] = i and P_col[i] = i' */
+      int *Q_row; /* int Q_row[1+n]; */
+      /* Q_row[0] is not used;
+         Q_row[i] = j means that q[i,j] = 1, where q[i,j] is an element
+         of permutation matrix Q */
+      int *Q_col; /* int Q_col[1+n]; */
+      /* Q_col[0] is not used;
+         Q_col[j] = i means that q[i,j] = 1, where q[i,j] is an element
+         of permutation matrix Q */
+      /* if j-th column of matrix V is j'-th column of matrix U = P*V*Q,
+         then Q_row[j] = j' and Q_col[j'] = j */
+      int rank;
+      /* the (exact) rank of matrices A and V */
+};
+
+struct LUXELM
+{     /* element of matrix F or V */
+      int i;
+      /* row index, 1 <= i <= m */
+      int j;
+      /* column index, 1 <= j <= n */
+      mpq_t val;
+      /* numeric (non-zero) element value */
+      LUXELM *r_prev;
+      /* pointer to previous element in the same row */
+      LUXELM *r_next;
+      /* pointer to next element in the same row */
+      LUXELM *c_prev;
+      /* pointer to previous element in the same column */
+      LUXELM *c_next;
+      /* pointer to next element in the same column */
+};
+
+struct LUXWKA
+{     /* working area (used only during factorization) */
+      /* in order to efficiently implement Markowitz strategy and Duff
+         search technique there are two families {R[0], R[1], ..., R[n]}
+         and {C[0], C[1], ..., C[n]}; member R[k] is a set of active
+         rows of matrix V having k non-zeros, and member C[k] is a set
+         of active columns of matrix V having k non-zeros (in the active
+         submatrix); each set R[k] and C[k] is implemented as a separate
+         doubly linked list */
+      int *R_len; /* int R_len[1+n]; */
+      /* R_len[0] is not used;
+         R_len[i], 1 <= i <= n, is the number of non-zero elements in
+         i-th row of matrix V (that is the length of i-th row) */
+      int *R_head; /* int R_head[1+n]; */
+      /* R_head[k], 0 <= k <= n, is the number of a first row, which is
+         active and whose length is k */
+      int *R_prev; /* int R_prev[1+n]; */
+      /* R_prev[0] is not used;
+         R_prev[i], 1 <= i <= n, is the number of a previous row, which
+         is active and has the same length as i-th row */
+      int *R_next; /* int R_next[1+n]; */
+      /* R_prev[0] is not used;
+         R_prev[i], 1 <= i <= n, is the number of a next row, which is
+         active and has the same length as i-th row */
+      int *C_len; /* int C_len[1+n]; */
+      /* C_len[0] is not used;
+         C_len[j], 1 <= j <= n, is the number of non-zero elements in
+         j-th column of the active submatrix of matrix V (that is the
+         length of j-th column in the active submatrix) */
+      int *C_head; /* int C_head[1+n]; */
+      /* C_head[k], 0 <= k <= n, is the number of a first column, which
+         is active and whose length is k */
+      int *C_prev; /* int C_prev[1+n]; */
+      /* C_prev[0] is not used;
+         C_prev[j], 1 <= j <= n, is the number of a previous column,
+         which is active and has the same length as j-th column */
+      int *C_next; /* int C_next[1+n]; */
+      /* C_next[0] is not used;
+         C_next[j], 1 <= j <= n, is the number of a next column, which
+         is active and has the same length as j-th column */
+};
+
+#define lux_create            _glp_lux_create
+#define lux_decomp            _glp_lux_decomp
+#define lux_f_solve           _glp_lux_f_solve
+#define lux_v_solve           _glp_lux_v_solve
+#define lux_solve             _glp_lux_solve
+#define lux_delete            _glp_lux_delete
+
+LUX *lux_create(int n);
+/* create LU-factorization */
+
+int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+      mpq_t val[]), void *info);
+/* compute LU-factorization */
+
+void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system F*x = b or F'*x = b */
+
+void lux_v_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system V*x = b or V'*x = b */
+
+void lux_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system A*x = b or A'*x = b */
+
+void lux_delete(LUX *lux);
+/* delete LU-factorization */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpmat.c b/optional/glpk/glpmat.c
new file mode 100644
index 0000000..99bbaa0
--- /dev/null
+++ b/optional/glpk/glpmat.c
@@ -0,0 +1,929 @@
+/* glpmat.c */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#endif
+
+#include "glpenv.h"
+#include "glpmat.h"
+#include "glpqmd.h"
+#include "amd/amd.h"
+#include "colamd/colamd.h"
+
+/*----------------------------------------------------------------------
+-- check_fvs - check sparse vector in full-vector storage format.
+--
+-- SYNOPSIS
+--
+-- #include "glpmat.h"
+-- int check_fvs(int n, int nnz, int ind[], double vec[]);
+--
+-- DESCRIPTION
+--
+-- The routine check_fvs checks if a given vector of dimension n in
+-- full-vector storage format has correct representation.
+--
+-- RETURNS
+--
+-- The routine returns one of the following codes:
+--
+-- 0 - the vector is correct;
+-- 1 - the number of elements (n) is negative;
+-- 2 - the number of non-zero elements (nnz) is negative;
+-- 3 - some element index is out of range;
+-- 4 - some element index is duplicate;
+-- 5 - some non-zero element is out of pattern. */
+
+int check_fvs(int n, int nnz, int ind[], double vec[])
+{     int i, t, ret, *flag = NULL;
+      /* check the number of elements */
+      if (n < 0)
+      {  ret = 1;
+         goto done;
+      }
+      /* check the number of non-zero elements */
+      if (nnz < 0)
+      {  ret = 2;
+         goto done;
+      }
+      /* check vector indices */
+      flag = xcalloc(1+n, sizeof(int));
+      for (i = 1; i <= n; i++) flag[i] = 0;
+      for (t = 1; t <= nnz; t++)
+      {  i = ind[t];
+         if (!(1 <= i && i <= n))
+         {  ret = 3;
+            goto done;
+         }
+         if (flag[i])
+         {  ret = 4;
+            goto done;
+         }
+         flag[i] = 1;
+      }
+      /* check vector elements */
+      for (i = 1; i <= n; i++)
+      {  if (!flag[i] && vec[i] != 0.0)
+         {  ret = 5;
+            goto done;
+         }
+      }
+      /* the vector is ok */
+      ret = 0;
+done: if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+-- check_pattern - check pattern of sparse matrix.
+--
+-- SYNOPSIS
+--
+-- #include "glpmat.h"
+-- int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
+--
+-- DESCRIPTION
+--
+-- The routine check_pattern checks the pattern of a given mxn matrix
+-- in storage-by-rows format.
+--
+-- RETURNS
+--
+-- The routine returns one of the following codes:
+--
+-- 0 - the pattern is correct;
+-- 1 - the number of rows (m) is negative;
+-- 2 - the number of columns (n) is negative;
+-- 3 - A_ptr[1] is not 1;
+-- 4 - some column index is out of range;
+-- 5 - some column indices are duplicate. */
+
+int check_pattern(int m, int n, int A_ptr[], int A_ind[])
+{     int i, j, ptr, ret, *flag = NULL;
+      /* check the number of rows */
+      if (m < 0)
+      {  ret = 1;
+         goto done;
+      }
+      /* check the number of columns */
+      if (n < 0)
+      {  ret = 2;
+         goto done;
+      }
+      /* check location A_ptr[1] */
+      if (A_ptr[1] != 1)
+      {  ret = 3;
+         goto done;
+      }
+      /* check row patterns */
+      flag = xcalloc(1+n, sizeof(int));
+      for (j = 1; j <= n; j++) flag[j] = 0;
+      for (i = 1; i <= m; i++)
+      {  /* check pattern of row i */
+         for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
+         {  j = A_ind[ptr];
+            /* check column index */
+            if (!(1 <= j && j <= n))
+            {  ret = 4;
+               goto done;
+            }
+            /* check for duplication */
+            if (flag[j])
+            {  ret = 5;
+               goto done;
+            }
+            flag[j] = 1;
+         }
+         /* clear flags */
+         for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
+         {  j = A_ind[ptr];
+            flag[j] = 0;
+         }
+      }
+      /* the pattern is ok */
+      ret = 0;
+done: if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+-- transpose - transpose sparse matrix.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void transpose(int m, int n, int A_ptr[], int A_ind[],
+--    double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]);
+--
+-- *Description*
+--
+-- For a given mxn sparse matrix A the routine transpose builds a nxm
+-- sparse matrix A' which is a matrix transposed to A.
+--
+-- The arrays A_ptr, A_ind, and A_val specify a given mxn matrix A to
+-- be transposed in storage-by-rows format. The parameter A_val can be
+-- NULL, in which case numeric values are not copied. The arrays A_ptr,
+-- A_ind, and A_val are not changed on exit.
+--
+-- On entry the arrays AT_ptr, AT_ind, and AT_val must be allocated,
+-- but their content is ignored. On exit the routine stores a resultant
+-- nxm matrix A' in these arrays in storage-by-rows format. Note that
+-- if the parameter A_val is NULL, the array AT_val is not used.
+--
+-- The routine transpose has a side effect that elements in rows of the
+-- resultant matrix A' follow in ascending their column indices. */
+
+void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
+      int AT_ptr[], int AT_ind[], double AT_val[])
+{     int i, j, t, beg, end, pos, len;
+      /* determine row lengths of resultant matrix */
+      for (j = 1; j <= n; j++) AT_ptr[j] = 0;
+      for (i = 1; i <= m; i++)
+      {  beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++) AT_ptr[A_ind[t]]++;
+      }
+      /* set up row pointers of resultant matrix */
+      pos = 1;
+      for (j = 1; j <= n; j++)
+         len = AT_ptr[j], pos += len, AT_ptr[j] = pos;
+      AT_ptr[n+1] = pos;
+      /* build resultant matrix */
+      for (i = m; i >= 1; i--)
+      {  beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+         {  pos = --AT_ptr[A_ind[t]];
+            AT_ind[pos] = i;
+            if (A_val != NULL) AT_val[pos] = A_val[t];
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- adat_symbolic - compute S = P*A*D*A'*P' (symbolic phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int *adat_symbolic(int m, int n, int P_per[], int A_ptr[],
+--    int A_ind[], int S_ptr[]);
+--
+-- *Description*
+--
+-- The routine adat_symbolic implements the symbolic phase to compute
+-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
+-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
+-- transposed to A, P' is an inverse of P.
+--
+-- The parameter m is the number of rows in A and the order of P.
+--
+-- The parameter n is the number of columns in A and the order of D.
+--
+-- The array P_per specifies permutation matrix P. It is not changed on
+-- exit.
+--
+-- The arrays A_ptr and A_ind specify the pattern of matrix A. They are
+-- not changed on exit.
+--
+-- On exit the routine stores the pattern of upper triangular part of
+-- matrix S without diagonal elements in the arrays S_ptr and S_ind in
+-- storage-by-rows format. The array S_ptr should be allocated on entry,
+-- however, its content is ignored. The array S_ind is allocated by the
+-- routine itself which returns a pointer to it.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the array S_ind. */
+
+int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
+      int S_ptr[])
+{     int i, j, t, ii, jj, tt, k, size, len;
+      int *S_ind, *AT_ptr, *AT_ind, *ind, *map, *temp;
+      /* build the pattern of A', which is a matrix transposed to A, to
+         efficiently access A in column-wise manner */
+      AT_ptr = xcalloc(1+n+1, sizeof(int));
+      AT_ind = xcalloc(A_ptr[m+1], sizeof(int));
+      transpose(m, n, A_ptr, A_ind, NULL, AT_ptr, AT_ind, NULL);
+      /* allocate the array S_ind */
+      size = A_ptr[m+1] - 1;
+      if (size < m) size = m;
+      S_ind = xcalloc(1+size, sizeof(int));
+      /* allocate and initialize working arrays */
+      ind = xcalloc(1+m, sizeof(int));
+      map = xcalloc(1+m, sizeof(int));
+      for (jj = 1; jj <= m; jj++) map[jj] = 0;
+      /* compute pattern of S; note that symbolically S = B*B', where
+         B = P*A, B' is matrix transposed to B */
+      S_ptr[1] = 1;
+      for (ii = 1; ii <= m; ii++)
+      {  /* compute pattern of ii-th row of S */
+         len = 0;
+         i = P_per[ii]; /* i-th row of A = ii-th row of B */
+         for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+         {  k = A_ind[t];
+            /* walk through k-th column of A */
+            for (tt = AT_ptr[k]; tt < AT_ptr[k+1]; tt++)
+            {  j = AT_ind[tt];
+               jj = P_per[m+j]; /* j-th row of A = jj-th row of B */
+               /* a[i,k] != 0 and a[j,k] != 0 ergo s[ii,jj] != 0 */
+               if (ii < jj && !map[jj]) ind[++len] = jj, map[jj] = 1;
+            }
+         }
+         /* now (ind) is pattern of ii-th row of S */
+         S_ptr[ii+1] = S_ptr[ii] + len;
+         /* at least (S_ptr[ii+1] - 1) locations should be available in
+            the array S_ind */
+         if (S_ptr[ii+1] - 1 > size)
+         {  temp = S_ind;
+            size += size;
+            S_ind = xcalloc(1+size, sizeof(int));
+            memcpy(&S_ind[1], &temp[1], (S_ptr[ii] - 1) * sizeof(int));
+            xfree(temp);
+         }
+         xassert(S_ptr[ii+1] - 1 <= size);
+         /* (ii-th row of S) := (ind) */
+         memcpy(&S_ind[S_ptr[ii]], &ind[1], len * sizeof(int));
+         /* clear the row pattern map */
+         for (t = 1; t <= len; t++) map[ind[t]] = 0;
+      }
+      /* free working arrays */
+      xfree(AT_ptr);
+      xfree(AT_ind);
+      xfree(ind);
+      xfree(map);
+      /* reallocate the array S_ind to free unused locations */
+      temp = S_ind;
+      size = S_ptr[m+1] - 1;
+      S_ind = xcalloc(1+size, sizeof(int));
+      memcpy(&S_ind[1], &temp[1], size * sizeof(int));
+      xfree(temp);
+      return S_ind;
+}
+
+/*----------------------------------------------------------------------
+-- adat_numeric - compute S = P*A*D*A'*P' (numeric phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void adat_numeric(int m, int n, int P_per[],
+--    int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+--    int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
+--
+-- *Description*
+--
+-- The routine adat_numeric implements the numeric phase to compute
+-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
+-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
+-- transposed to A, P' is an inverse of P.
+--
+-- The parameter m is the number of rows in A and the order of P.
+--
+-- The parameter n is the number of columns in A and the order of D.
+--
+-- The matrix P is specified in the array P_per, which is not changed
+-- on exit.
+--
+-- The matrix A is specified in the arrays A_ptr, A_ind, and A_val in
+-- storage-by-rows format. These arrays are not changed on exit.
+--
+-- Diagonal elements of the matrix D are specified in the array D_diag,
+-- where D_diag[0] is not used, D_diag[i] = d[i,i] for i = 1, ..., n.
+-- The array D_diag is not changed on exit.
+--
+-- The pattern of the upper triangular part of the matrix S without
+-- diagonal elements (previously computed by the routine adat_symbolic)
+-- is specified in the arrays S_ptr and S_ind, which are not changed on
+-- exit. Numeric values of non-diagonal elements of S are stored in
+-- corresponding locations of the array S_val, and values of diagonal
+-- elements of S are stored in locations S_diag[1], ..., S_diag[n]. */
+
+void adat_numeric(int m, int n, int P_per[],
+      int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+      int S_ptr[], int S_ind[], double S_val[], double S_diag[])
+{     int i, j, t, ii, jj, tt, beg, end, beg1, end1, k;
+      double sum, *work;
+      work = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++) work[j] = 0.0;
+      /* compute S = B*D*B', where B = P*A, B' is a matrix transposed
+         to B */
+      for (ii = 1; ii <= m; ii++)
+      {  i = P_per[ii]; /* i-th row of A = ii-th row of B */
+         /* (work) := (i-th row of A) */
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+            work[A_ind[t]] = A_val[t];
+         /* compute ii-th row of S */
+         beg = S_ptr[ii], end = S_ptr[ii+1];
+         for (t = beg; t < end; t++)
+         {  jj = S_ind[t];
+            j = P_per[jj]; /* j-th row of A = jj-th row of B */
+            /* s[ii,jj] := sum a[i,k] * d[k,k] * a[j,k] */
+            sum = 0.0;
+            beg1 = A_ptr[j], end1 = A_ptr[j+1];
+            for (tt = beg1; tt < end1; tt++)
+            {  k = A_ind[tt];
+               sum += work[k] * D_diag[k] * A_val[tt];
+            }
+            S_val[t] = sum;
+         }
+         /* s[ii,ii] := sum a[i,k] * d[k,k] * a[i,k] */
+         sum = 0.0;
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+         {  k = A_ind[t];
+            sum += A_val[t] * D_diag[k] * A_val[t];
+            work[k] = 0.0;
+         }
+         S_diag[ii] = sum;
+      }
+      xfree(work);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- min_degree - minimum degree ordering.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
+--
+-- *Description*
+--
+-- The routine min_degree uses the minimum degree ordering algorithm
+-- to find a permutation matrix P for a given sparse symmetric positive
+-- matrix A which minimizes the number of non-zeros in upper triangular
+-- factor U for Cholesky factorization P*A*P' = U'*U.
+--
+-- The parameter n is the order of matrices A and P.
+--
+-- The pattern of the given matrix A is specified on entry in the arrays
+-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
+-- part without diagonal elements (which all are assumed to be non-zero)
+-- should be specified as if A were upper triangular. The arrays A_ptr
+-- and A_ind are not changed on exit.
+--
+-- The permutation matrix P is stored by the routine in the array P_per
+-- on exit.
+--
+-- *Algorithm*
+--
+-- The routine min_degree is based on some subroutines from the package
+-- SPARSPAK (see comments in the module glpqmd). */
+
+void min_degree(int n, int A_ptr[], int A_ind[], int P_per[])
+{     int i, j, ne, t, pos, len;
+      int *xadj, *adjncy, *deg, *marker, *rchset, *nbrhd, *qsize,
+         *qlink, nofsub;
+      /* determine number of non-zeros in complete pattern */
+      ne = A_ptr[n+1] - 1;
+      ne += ne;
+      /* allocate working arrays */
+      xadj = xcalloc(1+n+1, sizeof(int));
+      adjncy = xcalloc(1+ne, sizeof(int));
+      deg = xcalloc(1+n, sizeof(int));
+      marker = xcalloc(1+n, sizeof(int));
+      rchset = xcalloc(1+n, sizeof(int));
+      nbrhd = xcalloc(1+n, sizeof(int));
+      qsize = xcalloc(1+n, sizeof(int));
+      qlink = xcalloc(1+n, sizeof(int));
+      /* determine row lengths in complete pattern */
+      for (i = 1; i <= n; i++) xadj[i] = 0;
+      for (i = 1; i <= n; i++)
+      {  for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+         {  j = A_ind[t];
+            xassert(i < j && j <= n);
+            xadj[i]++, xadj[j]++;
+         }
+      }
+      /* set up row pointers for complete pattern */
+      pos = 1;
+      for (i = 1; i <= n; i++)
+         len = xadj[i], pos += len, xadj[i] = pos;
+      xadj[n+1] = pos;
+      xassert(pos - 1 == ne);
+      /* construct complete pattern */
+      for (i = 1; i <= n; i++)
+      {  for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+         {  j = A_ind[t];
+            adjncy[--xadj[i]] = j, adjncy[--xadj[j]] = i;
+         }
+      }
+      /* call the main minimimum degree ordering routine */
+      genqmd(&n, xadj, adjncy, P_per, P_per + n, deg, marker, rchset,
+         nbrhd, qsize, qlink, &nofsub);
+      /* make sure that permutation matrix P is correct */
+      for (i = 1; i <= n; i++)
+      {  j = P_per[i];
+         xassert(1 <= j && j <= n);
+         xassert(P_per[n+j] == i);
+      }
+      /* free working arrays */
+      xfree(xadj);
+      xfree(adjncy);
+      xfree(deg);
+      xfree(marker);
+      xfree(rchset);
+      xfree(nbrhd);
+      xfree(qsize);
+      xfree(qlink);
+      return;
+}
+
+/**********************************************************************/
+
+void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[])
+{     /* approximate minimum degree ordering (AMD) */
+      int k, ret;
+      double Control[AMD_CONTROL], Info[AMD_INFO];
+      /* get the default parameters */
+      amd_defaults(Control);
+#if 0
+      /* and print them */
+      amd_control(Control);
+#endif
+      /* make all indices 0-based */
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
+      for (k = 1; k <= n+1; k++) A_ptr[k]--;
+      /* call the ordering routine */
+      ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info)
+         ;
+#if 0
+      amd_info(Info);
+#endif
+      xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED);
+      /* retsore 1-based indices */
+      for (k = 1; k <= n+1; k++) A_ptr[k]++;
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
+      /* patch up permutation matrix */
+      memset(&P_per[n+1], 0, n * sizeof(int));
+      for (k = 1; k <= n; k++)
+      {  P_per[k]++;
+         xassert(1 <= P_per[k] && P_per[k] <= n);
+         xassert(P_per[n+P_per[k]] == 0);
+         P_per[n+P_per[k]] = k;
+      }
+      return;
+}
+
+/**********************************************************************/
+
+static void *allocate(size_t n, size_t size)
+{     void *ptr;
+      ptr = xcalloc(n, size);
+      memset(ptr, 0, n * size);
+      return ptr;
+}
+
+static void release(void *ptr)
+{     xfree(ptr);
+      return;
+}
+
+void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[])
+{     /* approximate minimum degree ordering (SYMAMD) */
+      int k, ok;
+      int stats[COLAMD_STATS];
+      /* make all indices 0-based */
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
+      for (k = 1; k <= n+1; k++) A_ptr[k]--;
+      /* call the ordering routine */
+      ok = symamd(n, &A_ind[1], &A_ptr[1], &P_per[1], NULL, stats,
+         allocate, release);
+#if 0
+      symamd_report(stats);
+#endif
+      xassert(ok);
+      /* restore 1-based indices */
+      for (k = 1; k <= n+1; k++) A_ptr[k]++;
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
+      /* patch up permutation matrix */
+      memset(&P_per[n+1], 0, n * sizeof(int));
+      for (k = 1; k <= n; k++)
+      {  P_per[k]++;
+         xassert(1 <= P_per[k] && P_per[k] <= n);
+         xassert(P_per[n+P_per[k]] == 0);
+         P_per[n+P_per[k]] = k;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- chol_symbolic - compute Cholesky factorization (symbolic phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
+--
+-- *Description*
+--
+-- The routine chol_symbolic implements the symbolic phase of Cholesky
+-- factorization A = U'*U, where A is a given sparse symmetric positive
+-- definite matrix, U is a resultant upper triangular factor, U' is a
+-- matrix transposed to U.
+--
+-- The parameter n is the order of matrices A and U.
+--
+-- The pattern of the given matrix A is specified on entry in the arrays
+-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
+-- part without diagonal elements (which all are assumed to be non-zero)
+-- should be specified as if A were upper triangular. The arrays A_ptr
+-- and A_ind are not changed on exit.
+--
+-- The pattern of the matrix U without diagonal elements (which all are
+-- assumed to be non-zero) is stored on exit from the routine in the
+-- arrays U_ptr and U_ind in storage-by-rows format. The array U_ptr
+-- should be allocated on entry, however, its content is ignored. The
+-- array U_ind is allocated by the routine which returns a pointer to it
+-- on exit.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the array U_ind.
+--
+-- *Method*
+--
+-- The routine chol_symbolic computes the pattern of the matrix U in a
+-- row-wise manner. No pivoting is used.
+--
+-- It is known that to compute the pattern of row k of the matrix U we
+-- need to merge the pattern of row k of the matrix A and the patterns
+-- of each row i of U, where u[i,k] is non-zero (these rows are already
+-- computed and placed above row k).
+--
+-- However, to reduce the number of rows to be merged the routine uses
+-- an advanced algorithm proposed in:
+--
+-- D.J.Rose, R.E.Tarjan, and G.S.Lueker. Algorithmic aspects of vertex
+-- elimination on graphs. SIAM J. Comput. 5, 1976, 266-83.
+--
+-- The authors of the cited paper show that we have the same result if
+-- we merge row k of the matrix A and such rows of the matrix U (among
+-- rows 1, ..., k-1) whose leftmost non-diagonal non-zero element is
+-- placed in k-th column. This feature signficantly reduces the number
+-- of rows to be merged, especially on the final steps, where rows of
+-- the matrix U become quite dense.
+--
+-- To determine rows, which should be merged on k-th step, for a fixed
+-- time the routine uses linked lists of row numbers of the matrix U.
+-- Location head[k] contains the number of a first row, whose leftmost
+-- non-diagonal non-zero element is placed in column k, and location
+-- next[i] contains the number of a next row with the same property as
+-- row i. */
+
+int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[])
+{     int i, j, k, t, len, size, beg, end, min_j, *U_ind, *head, *next,
+         *ind, *map, *temp;
+      /* initially we assume that on computing the pattern of U fill-in
+         will double the number of non-zeros in A */
+      size = A_ptr[n+1] - 1;
+      if (size < n) size = n;
+      size += size;
+      U_ind = xcalloc(1+size, sizeof(int));
+      /* allocate and initialize working arrays */
+      head = xcalloc(1+n, sizeof(int));
+      for (i = 1; i <= n; i++) head[i] = 0;
+      next = xcalloc(1+n, sizeof(int));
+      ind = xcalloc(1+n, sizeof(int));
+      map = xcalloc(1+n, sizeof(int));
+      for (j = 1; j <= n; j++) map[j] = 0;
+      /* compute the pattern of matrix U */
+      U_ptr[1] = 1;
+      for (k = 1; k <= n; k++)
+      {  /* compute the pattern of k-th row of U, which is the union of
+            k-th row of A and those rows of U (among 1, ..., k-1) whose
+            leftmost non-diagonal non-zero is placed in k-th column */
+         /* (ind) := (k-th row of A) */
+         len = A_ptr[k+1] - A_ptr[k];
+         memcpy(&ind[1], &A_ind[A_ptr[k]], len * sizeof(int));
+         for (t = 1; t <= len; t++)
+         {  j = ind[t];
+            xassert(k < j && j <= n);
+            map[j] = 1;
+         }
+         /* walk through rows of U whose leftmost non-diagonal non-zero
+            is placed in k-th column */
+         for (i = head[k]; i != 0; i = next[i])
+         {  /* (ind) := (ind) union (i-th row of U) */
+            beg = U_ptr[i], end = U_ptr[i+1];
+            for (t = beg; t < end; t++)
+            {  j = U_ind[t];
+               if (j > k && !map[j]) ind[++len] = j, map[j] = 1;
+            }
+         }
+         /* now (ind) is the pattern of k-th row of U */
+         U_ptr[k+1] = U_ptr[k] + len;
+         /* at least (U_ptr[k+1] - 1) locations should be available in
+            the array U_ind */
+         if (U_ptr[k+1] - 1 > size)
+         {  temp = U_ind;
+            size += size;
+            U_ind = xcalloc(1+size, sizeof(int));
+            memcpy(&U_ind[1], &temp[1], (U_ptr[k] - 1) * sizeof(int));
+            xfree(temp);
+         }
+         xassert(U_ptr[k+1] - 1 <= size);
+         /* (k-th row of U) := (ind) */
+         memcpy(&U_ind[U_ptr[k]], &ind[1], len * sizeof(int));
+         /* determine column index of leftmost non-diagonal non-zero in
+            k-th row of U and clear the row pattern map */
+         min_j = n + 1;
+         for (t = 1; t <= len; t++)
+         {  j = ind[t], map[j] = 0;
+            if (min_j > j) min_j = j;
+         }
+         /* include k-th row into corresponding linked list */
+         if (min_j <= n) next[k] = head[min_j], head[min_j] = k;
+      }
+      /* free working arrays */
+      xfree(head);
+      xfree(next);
+      xfree(ind);
+      xfree(map);
+      /* reallocate the array U_ind to free unused locations */
+      temp = U_ind;
+      size = U_ptr[n+1] - 1;
+      U_ind = xcalloc(1+size, sizeof(int));
+      memcpy(&U_ind[1], &temp[1], size * sizeof(int));
+      xfree(temp);
+      return U_ind;
+}
+
+/*----------------------------------------------------------------------
+-- chol_numeric - compute Cholesky factorization (numeric phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int chol_numeric(int n,
+--    int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+--    int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
+--
+-- *Description*
+--
+-- The routine chol_symbolic implements the numeric phase of Cholesky
+-- factorization A = U'*U, where A is a given sparse symmetric positive
+-- definite matrix, U is a resultant upper triangular factor, U' is a
+-- matrix transposed to U.
+--
+-- The parameter n is the order of matrices A and U.
+--
+-- Upper triangular part of the matrix A without diagonal elements is
+-- specified in the arrays A_ptr, A_ind, and A_val in storage-by-rows
+-- format. Diagonal elements of A are specified in the array A_diag,
+-- where A_diag[0] is not used, A_diag[i] = a[i,i] for i = 1, ..., n.
+-- The arrays A_ptr, A_ind, A_val, and A_diag are not changed on exit.
+--
+-- The pattern of the matrix U without diagonal elements (previously
+-- computed with the routine chol_symbolic) is specified in the arrays
+-- U_ptr and U_ind, which are not changed on exit. Numeric values of
+-- non-diagonal elements of U are stored in corresponding locations of
+-- the array U_val, and values of diagonal elements of U are stored in
+-- locations U_diag[1], ..., U_diag[n].
+--
+-- *Returns*
+--
+-- The routine returns the number of non-positive diagonal elements of
+-- the matrix U which have been replaced by a huge positive number (see
+-- the method description below). Zero return code means the matrix A
+-- has been successfully factorized.
+--
+-- *Method*
+--
+-- The routine chol_numeric computes the matrix U in a row-wise manner
+-- using standard gaussian elimination technique. No pivoting is used.
+--
+-- Initially the routine sets U = A, and before k-th elimination step
+-- the matrix U is the following:
+--
+--       1       k         n
+--    1  x x x x x x x x x x
+--       . x x x x x x x x x
+--       . . x x x x x x x x
+--       . . . x x x x x x x
+--    k  . . . . * * * * * *
+--       . . . . * * * * * *
+--       . . . . * * * * * *
+--       . . . . * * * * * *
+--       . . . . * * * * * *
+--    n  . . . . * * * * * *
+--
+-- where 'x' are elements of already computed rows, '*' are elements of
+-- the active submatrix. (Note that the lower triangular part of the
+-- active submatrix being symmetric is not stored and diagonal elements
+-- are stored separately in the array U_diag.)
+--
+-- The matrix A is assumed to be positive definite. However, if it is
+-- close to semi-definite, on some elimination step a pivot u[k,k] may
+-- happen to be non-positive due to round-off errors. In this case the
+-- routine uses a technique proposed in:
+--
+-- S.J.Wright. The Cholesky factorization in interior-point and barrier
+-- methods. Preprint MCS-P600-0596, Mathematics and Computer Science
+-- Division, Argonne National Laboratory, Argonne, Ill., May 1996.
+--
+-- The routine just replaces non-positive u[k,k] by a huge positive
+-- number. This involves non-diagonal elements in k-th row of U to be
+-- close to zero that, in turn, involves k-th component of a solution
+-- vector to be close to zero. Note, however, that this technique works
+-- only if the system A*x = b is consistent. */
+
+int chol_numeric(int n,
+      int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+      int U_ptr[], int U_ind[], double U_val[], double U_diag[])
+{     int i, j, k, t, t1, beg, end, beg1, end1, count = 0;
+      double ukk, uki, *work;
+      work = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++) work[j] = 0.0;
+      /* U := (upper triangle of A) */
+      /* note that the upper traingle of A is a subset of U */
+      for (i = 1; i <= n; i++)
+      {  beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+            j = A_ind[t], work[j] = A_val[t];
+         beg = U_ptr[i], end = U_ptr[i+1];
+         for (t = beg; t < end; t++)
+            j = U_ind[t], U_val[t] = work[j], work[j] = 0.0;
+         U_diag[i] = A_diag[i];
+      }
+      /* main elimination loop */
+      for (k = 1; k <= n; k++)
+      {  /* transform k-th row of U */
+         ukk = U_diag[k];
+         if (ukk > 0.0)
+            U_diag[k] = ukk = sqrt(ukk);
+         else
+            U_diag[k] = ukk = DBL_MAX, count++;
+         /* (work) := (transformed k-th row) */
+         beg = U_ptr[k], end = U_ptr[k+1];
+         for (t = beg; t < end; t++)
+            work[U_ind[t]] = (U_val[t] /= ukk);
+         /* transform other rows of U */
+         for (t = beg; t < end; t++)
+         {  i = U_ind[t];
+            xassert(i > k);
+            /* (i-th row) := (i-th row) - u[k,i] * (k-th row) */
+            uki = work[i];
+            beg1 = U_ptr[i], end1 = U_ptr[i+1];
+            for (t1 = beg1; t1 < end1; t1++)
+               U_val[t1] -= uki * work[U_ind[t1]];
+            U_diag[i] -= uki * uki;
+         }
+         /* (work) := 0 */
+         for (t = beg; t < end; t++)
+            work[U_ind[t]] = 0.0;
+      }
+      xfree(work);
+      return count;
+}
+
+/*----------------------------------------------------------------------
+-- u_solve - solve upper triangular system U*x = b.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+--    double U_diag[], double x[]);
+--
+-- *Description*
+--
+-- The routine u_solve solves an linear system U*x = b, where U is an
+-- upper triangular matrix.
+--
+-- The parameter n is the order of matrix U.
+--
+-- The matrix U without diagonal elements is specified in the arrays
+-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
+-- of U are specified in the array U_diag, where U_diag[0] is not used,
+-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
+-- changed on exit.
+--
+-- The right-hand side vector b is specified on entry in the array x,
+-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
+-- the routine stores computed components of the vector of unknowns x
+-- in the array x in the same manner. */
+
+void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[])
+{     int i, t, beg, end;
+      double temp;
+      for (i = n; i >= 1; i--)
+      {  temp = x[i];
+         beg = U_ptr[i], end = U_ptr[i+1];
+         for (t = beg; t < end; t++)
+            temp -= U_val[t] * x[U_ind[t]];
+         xassert(U_diag[i] != 0.0);
+         x[i] = temp / U_diag[i];
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- ut_solve - solve lower triangular system U'*x = b.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+--    double U_diag[], double x[]);
+--
+-- *Description*
+--
+-- The routine ut_solve solves an linear system U'*x = b, where U is a
+-- matrix transposed to an upper triangular matrix.
+--
+-- The parameter n is the order of matrix U.
+--
+-- The matrix U without diagonal elements is specified in the arrays
+-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
+-- of U are specified in the array U_diag, where U_diag[0] is not used,
+-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
+-- changed on exit.
+--
+-- The right-hand side vector b is specified on entry in the array x,
+-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
+-- the routine stores computed components of the vector of unknowns x
+-- in the array x in the same manner. */
+
+void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[])
+{     int i, t, beg, end;
+      double temp;
+      for (i = 1; i <= n; i++)
+      {  xassert(U_diag[i] != 0.0);
+         temp = (x[i] /= U_diag[i]);
+         if (temp == 0.0) continue;
+         beg = U_ptr[i], end = U_ptr[i+1];
+         for (t = beg; t < end; t++)
+            x[U_ind[t]] -= U_val[t] * temp;
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmat.h b/optional/glpk/glpmat.h
new file mode 100644
index 0000000..6e74541
--- /dev/null
+++ b/optional/glpk/glpmat.h
@@ -0,0 +1,198 @@
+/* glpmat.h (linear algebra routines) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPMAT_H
+#define GLPMAT_H
+
+/***********************************************************************
+*  FULL-VECTOR STORAGE
+* 
+*  For a sparse vector x having n elements, ne of which are non-zero,
+*  the full-vector storage format uses two arrays x_ind and x_vec, which
+*  are set up as follows:
+* 
+*  x_ind is an integer array of length [1+ne]. Location x_ind[0] is
+*  not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
+*  non-zero elements in vector x.
+* 
+*  x_vec is a floating-point array of length [1+n]. Location x_vec[0]
+*  is not used, and locations x_vec[1], ..., x_vec[n] contain numeric
+*  values of ALL elements in vector x, including its zero elements.
+* 
+*  Let, for example, the following sparse vector x be given:
+* 
+*     (0, 1, 0, 0, 2, 3, 0, 4)
+* 
+*  Then the arrays are:
+* 
+*     x_ind = { X; 2, 5, 6, 8 }
+* 
+*     x_vec = { X; 0, 1, 0, 0, 2, 3, 0, 4 }
+* 
+*  COMPRESSED-VECTOR STORAGE
+* 
+*  For a sparse vector x having n elements, ne of which are non-zero,
+*  the compressed-vector storage format uses two arrays x_ind and x_vec,
+*  which are set up as follows:
+* 
+*  x_ind is an integer array of length [1+ne]. Location x_ind[0] is
+*  not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
+*  non-zero elements in vector x.
+* 
+*  x_vec is a floating-point array of length [1+ne]. Location x_vec[0]
+*  is not used, and locations x_vec[1], ..., x_vec[ne] contain numeric
+*  values of corresponding non-zero elements in vector x.
+* 
+*  Let, for example, the following sparse vector x be given:
+* 
+*     (0, 1, 0, 0, 2, 3, 0, 4)
+* 
+*  Then the arrays are:
+*
+*     x_ind = { X; 2, 5, 6, 8 }
+* 
+*     x_vec = { X; 1, 2, 3, 4 }
+* 
+*  STORAGE-BY-ROWS
+* 
+*  For a sparse matrix A, which has m rows, n columns, and ne non-zero
+*  elements the storage-by-rows format uses three arrays A_ptr, A_ind,
+*  and A_val, which are set up as follows:
+* 
+*  A_ptr is an integer array of length [1+m+1] also called "row pointer
+*  array". It contains the relative starting positions of each row of A
+*  in the arrays A_ind and A_val, i.e. element A_ptr[i], 1 <= i <= m,
+*  indicates where row i begins in the arrays A_ind and A_val. If all
+*  elements in row i are zero, then A_ptr[i] = A_ptr[i+1]. Location
+*  A_ptr[0] is not used, location A_ptr[1] must contain 1, and location
+*  A_ptr[m+1] must contain ne+1 that indicates the position after the
+*  last element in the arrays A_ind and A_val.
+* 
+*  A_ind is an integer array of length [1+ne]. Location A_ind[0] is not
+*  used, and locations A_ind[1], ..., A_ind[ne] contain column indices
+*  of (non-zero) elements in matrix A.
+*
+*  A_val is a floating-point array of length [1+ne]. Location A_val[0]
+*  is not used, and locations A_val[1], ..., A_val[ne] contain numeric
+*  values of non-zero elements in matrix A.
+* 
+*  Non-zero elements of matrix A are stored contiguously, and the rows
+*  of matrix A are stored consecutively from 1 to m in the arrays A_ind
+*  and A_val. The elements in each row of A may be stored in any order
+*  in A_ind and A_val. Note that elements with duplicate column indices
+*  are not allowed.
+* 
+*  Let, for example, the following sparse matrix A be given:
+* 
+*     | 11  . 13  .  .  . |
+*     | 21 22  . 24  .  . |
+*     |  . 32 33  .  .  . |
+*     |  .  . 43 44  . 46 |
+*     |  .  .  .  .  .  . |
+*     | 61 62  .  .  . 66 |
+* 
+*  Then the arrays are:
+* 
+*     A_ptr = { X; 1, 3, 6, 8, 11, 11; 14 }
+*
+*     A_ind = { X;  1,  3;  4,  2,  1;  2,  3;  4,  3,  6;  1,  2,  6 }
+* 
+*     A_val = { X; 11, 13; 24, 22, 21; 32, 33; 44, 43, 46; 61, 62, 66 }
+* 
+*  PERMUTATION MATRICES
+* 
+*  Let P be a permutation matrix of the order n. It is represented as
+*  an integer array P_per of length [1+n+n] as follows: if p[i,j] = 1,
+*  then P_per[i] = j and P_per[n+j] = i. Location P_per[0] is not used.
+* 
+*  Let A' = P*A. If i-th row of A corresponds to i'-th row of A', then
+*  P_per[i'] = i and P_per[n+i] = i'.
+* 
+*  References:
+* 
+*  1. Gustavson F.G. Some basic techniques for solving sparse systems of
+*     linear equations. In Rose and Willoughby (1972), pp. 41-52.
+* 
+*  2. Basic Linear Algebra Subprograms Technical (BLAST) Forum Standard.
+*     University of Tennessee (2001). */
+
+#define check_fvs _glp_mat_check_fvs
+int check_fvs(int n, int nnz, int ind[], double vec[]);
+/* check sparse vector in full-vector storage format */
+
+#define check_pattern _glp_mat_check_pattern
+int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
+/* check pattern of sparse matrix */
+
+#define transpose _glp_mat_transpose
+void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
+      int AT_ptr[], int AT_ind[], double AT_val[]);
+/* transpose sparse matrix */
+
+#define adat_symbolic _glp_mat_adat_symbolic
+int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
+      int S_ptr[]);
+/* compute S = P*A*D*A'*P' (symbolic phase) */
+
+#define adat_numeric _glp_mat_adat_numeric
+void adat_numeric(int m, int n, int P_per[],
+      int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+      int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
+/* compute S = P*A*D*A'*P' (numeric phase) */
+
+#define min_degree _glp_mat_min_degree
+void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* minimum degree ordering */
+
+#define amd_order1 _glp_mat_amd_order1
+void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* approximate minimum degree ordering (AMD) */
+
+#define symamd_ord _glp_mat_symamd_ord
+void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* approximate minimum degree ordering (SYMAMD) */
+
+#define chol_symbolic _glp_mat_chol_symbolic
+int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
+/* compute Cholesky factorization (symbolic phase) */
+
+#define chol_numeric _glp_mat_chol_numeric
+int chol_numeric(int n,
+      int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+      int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
+/* compute Cholesky factorization (numeric phase) */
+
+#define u_solve _glp_mat_u_solve
+void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[]);
+/* solve upper triangular system U*x = b */
+
+#define ut_solve _glp_mat_ut_solve
+void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[]);
+/* solve lower triangular system U'*x = b */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpmpl.h b/optional/glpk/glpmpl.h
new file mode 100644
index 0000000..4372579
--- /dev/null
+++ b/optional/glpk/glpmpl.h
@@ -0,0 +1,2583 @@
+/* glpmpl.h (GNU MathProg translator) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPMPL_H
+#define GLPMPL_H
+
+#include "glpavl.h"
+#include "glprng.h"
+
+typedef struct MPL MPL;
+typedef char STRING;
+typedef struct SYMBOL SYMBOL;
+typedef struct TUPLE TUPLE;
+typedef struct ARRAY ELEMSET;
+typedef struct ELEMVAR ELEMVAR;
+typedef struct FORMULA FORMULA;
+typedef struct ELEMCON ELEMCON;
+typedef union VALUE VALUE;
+typedef struct ARRAY ARRAY;
+typedef struct MEMBER MEMBER;
+#if 1
+/* many C compilers have DOMAIN declared in <math.h> :( */
+#undef DOMAIN
+#define DOMAIN DOMAIN1
+#endif
+typedef struct DOMAIN DOMAIN;
+typedef struct DOMAIN_BLOCK DOMAIN_BLOCK;
+typedef struct DOMAIN_SLOT DOMAIN_SLOT;
+typedef struct SET SET;
+typedef struct WITHIN WITHIN;
+typedef struct GADGET GADGET;
+typedef struct PARAMETER PARAMETER;
+typedef struct CONDITION CONDITION;
+typedef struct VARIABLE VARIABLE;
+typedef struct CONSTRAINT CONSTRAINT;
+typedef struct TABLE TABLE;
+typedef struct TABARG TABARG;
+typedef struct TABFLD TABFLD;
+typedef struct TABIN TABIN;
+typedef struct TABOUT TABOUT;
+typedef struct TABDCA TABDCA;
+typedef union OPERANDS OPERANDS;
+typedef struct ARG_LIST ARG_LIST;
+typedef struct CODE CODE;
+typedef struct CHECK CHECK;
+typedef struct DISPLAY DISPLAY;
+typedef struct DISPLAY1 DISPLAY1;
+typedef struct PRINTF PRINTF;
+typedef struct PRINTF1 PRINTF1;
+typedef struct FOR FOR;
+typedef struct STATEMENT STATEMENT;
+typedef struct TUPLE SLICE;
+
+/**********************************************************************/
+/* * *                    TRANSLATOR DATABASE                     * * */
+/**********************************************************************/
+
+#define A_BINARY        101   /* something binary */
+#define A_CHECK         102   /* check statement */
+#define A_CONSTRAINT    103   /* model constraint */
+#define A_DISPLAY       104   /* display statement */
+#define A_ELEMCON       105   /* elemental constraint/objective */
+#define A_ELEMSET       106   /* elemental set */
+#define A_ELEMVAR       107   /* elemental variable */
+#define A_EXPRESSION    108   /* expression */
+#define A_FOR           109   /* for statement */
+#define A_FORMULA       110   /* formula */
+#define A_INDEX         111   /* dummy index */
+#define A_INPUT         112   /* input table */
+#define A_INTEGER       113   /* something integer */
+#define A_LOGICAL       114   /* something logical */
+#define A_MAXIMIZE      115   /* objective has to be maximized */
+#define A_MINIMIZE      116   /* objective has to be minimized */
+#define A_NONE          117   /* nothing */
+#define A_NUMERIC       118   /* something numeric */
+#define A_OUTPUT        119   /* output table */
+#define A_PARAMETER     120   /* model parameter */
+#define A_PRINTF        121   /* printf statement */
+#define A_SET           122   /* model set */
+#define A_SOLVE         123   /* solve statement */
+#define A_SYMBOLIC      124   /* something symbolic */
+#define A_TABLE         125   /* data table */
+#define A_TUPLE         126   /* n-tuple */
+#define A_VARIABLE      127   /* model variable */
+
+#define MAX_LENGTH 100
+/* maximal length of any symbolic value (this includes symbolic names,
+   numeric and string literals, and all symbolic values that may appear
+   during the evaluation phase) */
+
+#define CONTEXT_SIZE 60
+/* size of the context queue, in characters */
+
+#define OUTBUF_SIZE 1024
+/* size of the output buffer, in characters */
+
+struct MPL
+{     /* translator database */
+      /*--------------------------------------------------------------*/
+      /* scanning segment */
+      int line;
+      /* number of the current text line */
+      int c;
+      /* the current character or EOF */
+      int token;
+      /* the current token: */
+#define T_EOF           201   /* end of file */
+#define T_NAME          202   /* symbolic name (model section only) */
+#define T_SYMBOL        203   /* symbol (data section only) */
+#define T_NUMBER        204   /* numeric literal */
+#define T_STRING        205   /* string literal */
+#define T_AND           206   /* and && */
+#define T_BY            207   /* by */
+#define T_CROSS         208   /* cross */
+#define T_DIFF          209   /* diff */
+#define T_DIV           210   /* div */
+#define T_ELSE          211   /* else */
+#define T_IF            212   /* if */
+#define T_IN            213   /* in */
+#define T_INFINITY      214   /* Infinity */
+#define T_INTER         215   /* inter */
+#define T_LESS          216   /* less */
+#define T_MOD           217   /* mod */
+#define T_NOT           218   /* not ! */
+#define T_OR            219   /* or || */
+#define T_SPTP          220   /* s.t. */
+#define T_SYMDIFF       221   /* symdiff */
+#define T_THEN          222   /* then */
+#define T_UNION         223   /* union */
+#define T_WITHIN        224   /* within */
+#define T_PLUS          225   /* + */
+#define T_MINUS         226   /* - */
+#define T_ASTERISK      227   /* * */
+#define T_SLASH         228   /* / */
+#define T_POWER         229   /* ^ ** */
+#define T_LT            230   /* <  */
+#define T_LE            231   /* <= */
+#define T_EQ            232   /* = == */
+#define T_GE            233   /* >= */
+#define T_GT            234   /* >  */
+#define T_NE            235   /* <> != */
+#define T_CONCAT        236   /* & */
+#define T_BAR           237   /* | */
+#define T_POINT         238   /* . */
+#define T_COMMA         239   /* , */
+#define T_COLON         240   /* : */
+#define T_SEMICOLON     241   /* ; */
+#define T_ASSIGN        242   /* := */
+#define T_DOTS          243   /* .. */
+#define T_LEFT          244   /* ( */
+#define T_RIGHT         245   /* ) */
+#define T_LBRACKET      246   /* [ */
+#define T_RBRACKET      247   /* ] */
+#define T_LBRACE        248   /* { */
+#define T_RBRACE        249   /* } */
+#define T_APPEND        250   /* >> */
+#define T_TILDE         251   /* ~ */
+#define T_INPUT         252   /* <- */
+      int imlen;
+      /* length of the current token */
+      char *image; /* char image[MAX_LENGTH+1]; */
+      /* image of the current token */
+      double value;
+      /* value of the current token (for T_NUMBER only) */
+      int b_token;
+      /* the previous token */
+      int b_imlen;
+      /* length of the previous token */
+      char *b_image; /* char b_image[MAX_LENGTH+1]; */
+      /* image of the previous token */
+      double b_value;
+      /* value of the previous token (if token is T_NUMBER) */
+      int f_dots;
+      /* if this flag is set, the next token should be recognized as
+         T_DOTS, not as T_POINT */
+      int f_scan;
+      /* if this flag is set, the next token is already scanned */
+      int f_token;
+      /* the next token */
+      int f_imlen;
+      /* length of the next token */
+      char *f_image; /* char f_image[MAX_LENGTH+1]; */
+      /* image of the next token */
+      double f_value;
+      /* value of the next token (if token is T_NUMBER) */
+      char *context; /* char context[CONTEXT_SIZE]; */
+      /* context circular queue (not null-terminated!) */
+      int c_ptr;
+      /* pointer to the current position in the context queue */
+      int flag_d;
+      /* if this flag is set, the data section is being processed */
+      /*--------------------------------------------------------------*/
+      /* translating segment */
+      DMP *pool;
+      /* memory pool used to allocate all data instances created during
+         the translation phase */
+      AVL *tree;
+      /* symbolic name table:
+         node.type = A_INDEX     => node.link -> DOMAIN_SLOT
+         node.type = A_SET       => node.link -> SET
+         node.type = A_PARAMETER => node.link -> PARAMETER
+         node.type = A_VARIABLE  => node.link -> VARIABLE
+         node.type = A_CONSTRANT => node.link -> CONSTRAINT */
+      STATEMENT *model;
+      /* linked list of model statements in the original order */
+      int flag_x;
+      /* if this flag is set, the current token being left parenthesis
+         begins a slice that allows recognizing any undeclared symbolic
+         names as dummy indices; this flag is automatically reset once
+         the next token has been scanned */
+      int as_within;
+      /* the warning "in understood as within" has been issued */
+      int as_in;
+      /* the warning "within understood as in" has been issued */
+      int as_binary;
+      /* the warning "logical understood as binary" has been issued */
+      int flag_s;
+      /* if this flag is set, the solve statement has been parsed */
+      /*--------------------------------------------------------------*/
+      /* common segment */
+      DMP *strings;
+      /* memory pool to allocate STRING data structures */
+      DMP *symbols;
+      /* memory pool to allocate SYMBOL data structures */
+      DMP *tuples;
+      /* memory pool to allocate TUPLE data structures */
+      DMP *arrays;
+      /* memory pool to allocate ARRAY data structures */
+      DMP *members;
+      /* memory pool to allocate MEMBER data structures */
+      DMP *elemvars;
+      /* memory pool to allocate ELEMVAR data structures */
+      DMP *formulae;
+      /* memory pool to allocate FORMULA data structures */
+      DMP *elemcons;
+      /* memory pool to allocate ELEMCON data structures */
+      ARRAY *a_list;
+      /* linked list of all arrays in the database */
+      char *sym_buf; /* char sym_buf[255+1]; */
+      /* working buffer used by the routine format_symbol */
+      char *tup_buf; /* char tup_buf[255+1]; */
+      /* working buffer used by the routine format_tuple */
+      /*--------------------------------------------------------------*/
+      /* generating/postsolving segment */
+      RNG *rand;
+      /* pseudo-random number generator */
+      int flag_p;
+      /* if this flag is set, the postsolving phase is in effect */
+      STATEMENT *stmt;
+      /* model statement being currently executed */
+      TABDCA *dca;
+      /* pointer to table driver communication area for table statement
+         currently executed */
+      int m;
+      /* number of rows in the problem, m >= 0 */
+      int n;
+      /* number of columns in the problem, n >= 0 */
+      ELEMCON **row; /* ELEMCON *row[1+m]; */
+      /* row[0] is not used;
+         row[i] is elemental constraint or objective, which corresponds
+         to i-th row of the problem, 1 <= i <= m */
+      ELEMVAR **col; /* ELEMVAR *col[1+n]; */
+      /* col[0] is not used;
+         col[j] is elemental variable, which corresponds to j-th column
+         of the problem, 1 <= j <= n */
+      /*--------------------------------------------------------------*/
+      /* input/output segment */
+      XFILE *in_fp;
+      /* stream assigned to the input text file */
+      char *in_file;
+      /* name of the input text file */
+      XFILE *out_fp;
+      /* stream assigned to the output text file used to write all data
+         produced by display and printf statements; NULL means the data
+         should be sent to stdout via the routine xprintf */
+      char *out_file;
+      /* name of the output text file */
+#if 0 /* 08/XI-2009 */
+      char *out_buf; /* char out_buf[OUTBUF_SIZE] */
+      /* buffer to accumulate output data */
+      int out_cnt;
+      /* count of data bytes stored in the output buffer */
+#endif
+      XFILE *prt_fp;
+      /* stream assigned to the print text file; may be NULL */
+      char *prt_file;
+      /* name of the output print file */
+      /*--------------------------------------------------------------*/
+      /* solver interface segment */
+      jmp_buf jump;
+      /* jump address for non-local go to in case of error */
+      int phase;
+      /* phase of processing:
+         0 - database is being or has been initialized
+         1 - model section is being or has been read
+         2 - data section is being or has been read
+         3 - model is being or has been generated/postsolved
+         4 - model processing error has occurred */
+      char *mod_file;
+      /* name of the input text file, which contains model section */
+      char *mpl_buf; /* char mpl_buf[255+1]; */
+      /* working buffer used by some interface routines */
+};
+
+/**********************************************************************/
+/* * *                  PROCESSING MODEL SECTION                  * * */
+/**********************************************************************/
+
+#define alloc(type) ((type *)dmp_get_atomv(mpl->pool, sizeof(type)))
+/* allocate atom of given type */
+
+#define enter_context _glp_mpl_enter_context
+void enter_context(MPL *mpl);
+/* enter current token into context queue */
+
+#define print_context _glp_mpl_print_context
+void print_context(MPL *mpl);
+/* print current content of context queue */
+
+#define get_char _glp_mpl_get_char
+void get_char(MPL *mpl);
+/* scan next character from input text file */
+
+#define append_char _glp_mpl_append_char
+void append_char(MPL *mpl);
+/* append character to current token */
+
+#define get_token _glp_mpl_get_token
+void get_token(MPL *mpl);
+/* scan next token from input text file */
+
+#define unget_token _glp_mpl_unget_token
+void unget_token(MPL *mpl);
+/* return current token back to input stream */
+
+#define is_keyword _glp_mpl_is_keyword
+int is_keyword(MPL *mpl, char *keyword);
+/* check if current token is given non-reserved keyword */
+
+#define is_reserved _glp_mpl_is_reserved
+int is_reserved(MPL *mpl);
+/* check if current token is reserved keyword */
+
+#define make_code _glp_mpl_make_code
+CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim);
+/* generate pseudo-code (basic routine) */
+
+#define make_unary _glp_mpl_make_unary
+CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim);
+/* generate pseudo-code for unary operation */
+
+#define make_binary _glp_mpl_make_binary
+CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
+      int dim);
+/* generate pseudo-code for binary operation */
+
+#define make_ternary _glp_mpl_make_ternary
+CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
+      int type, int dim);
+/* generate pseudo-code for ternary operation */
+
+#define numeric_literal _glp_mpl_numeric_literal
+CODE *numeric_literal(MPL *mpl);
+/* parse reference to numeric literal */
+
+#define string_literal _glp_mpl_string_literal
+CODE *string_literal(MPL *mpl);
+/* parse reference to string literal */
+
+#define create_arg_list _glp_mpl_create_arg_list
+ARG_LIST *create_arg_list(MPL *mpl);
+/* create empty operands list */
+
+#define expand_arg_list _glp_mpl_expand_arg_list
+ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x);
+/* append operand to operands list */
+
+#define arg_list_len _glp_mpl_arg_list_len
+int arg_list_len(MPL *mpl, ARG_LIST *list);
+/* determine length of operands list */
+
+#define subscript_list _glp_mpl_subscript_list
+ARG_LIST *subscript_list(MPL *mpl);
+/* parse subscript list */
+
+#define object_reference _glp_mpl_object_reference
+CODE *object_reference(MPL *mpl);
+/* parse reference to named object */
+
+#define numeric_argument _glp_mpl_numeric_argument
+CODE *numeric_argument(MPL *mpl, char *func);
+/* parse argument passed to built-in function */
+
+#define symbolic_argument _glp_mpl_symbolic_argument
+CODE *symbolic_argument(MPL *mpl, char *func);
+
+#define elemset_argument _glp_mpl_elemset_argument
+CODE *elemset_argument(MPL *mpl, char *func);
+
+#define function_reference _glp_mpl_function_reference
+CODE *function_reference(MPL *mpl);
+/* parse reference to built-in function */
+
+#define create_domain _glp_mpl_create_domain
+DOMAIN *create_domain(MPL *mpl);
+/* create empty domain */
+
+#define create_block _glp_mpl_create_block
+DOMAIN_BLOCK *create_block(MPL *mpl);
+/* create empty domain block */
+
+#define append_block _glp_mpl_append_block
+void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block);
+/* append domain block to specified domain */
+
+#define append_slot _glp_mpl_append_slot
+DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
+      CODE *code);
+/* create and append new slot to domain block */
+
+#define expression_list _glp_mpl_expression_list
+CODE *expression_list(MPL *mpl);
+/* parse expression list */
+
+#define literal_set _glp_mpl_literal_set
+CODE *literal_set(MPL *mpl, CODE *code);
+/* parse literal set */
+
+#define indexing_expression _glp_mpl_indexing_expression
+DOMAIN *indexing_expression(MPL *mpl);
+/* parse indexing expression */
+
+#define close_scope _glp_mpl_close_scope
+void close_scope(MPL *mpl, DOMAIN *domain);
+/* close scope of indexing expression */
+
+#define iterated_expression _glp_mpl_iterated_expression
+CODE *iterated_expression(MPL *mpl);
+/* parse iterated expression */
+
+#define domain_arity _glp_mpl_domain_arity
+int domain_arity(MPL *mpl, DOMAIN *domain);
+/* determine arity of domain */
+
+#define set_expression _glp_mpl_set_expression
+CODE *set_expression(MPL *mpl);
+/* parse set expression */
+
+#define branched_expression _glp_mpl_branched_expression
+CODE *branched_expression(MPL *mpl);
+/* parse conditional expression */
+
+#define primary_expression _glp_mpl_primary_expression
+CODE *primary_expression(MPL *mpl);
+/* parse primary expression */
+
+#define error_preceding _glp_mpl_error_preceding
+void error_preceding(MPL *mpl, char *opstr);
+/* raise error if preceding operand has wrong type */
+
+#define error_following _glp_mpl_error_following
+void error_following(MPL *mpl, char *opstr);
+/* raise error if following operand has wrong type */
+
+#define error_dimension _glp_mpl_error_dimension
+void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2);
+/* raise error if operands have different dimension */
+
+#define expression_0 _glp_mpl_expression_0
+CODE *expression_0(MPL *mpl);
+/* parse expression of level 0 */
+
+#define expression_1 _glp_mpl_expression_1
+CODE *expression_1(MPL *mpl);
+/* parse expression of level 1 */
+
+#define expression_2 _glp_mpl_expression_2
+CODE *expression_2(MPL *mpl);
+/* parse expression of level 2 */
+
+#define expression_3 _glp_mpl_expression_3
+CODE *expression_3(MPL *mpl);
+/* parse expression of level 3 */
+
+#define expression_4 _glp_mpl_expression_4
+CODE *expression_4(MPL *mpl);
+/* parse expression of level 4 */
+
+#define expression_5 _glp_mpl_expression_5
+CODE *expression_5(MPL *mpl);
+/* parse expression of level 5 */
+
+#define expression_6 _glp_mpl_expression_6
+CODE *expression_6(MPL *mpl);
+/* parse expression of level 6 */
+
+#define expression_7 _glp_mpl_expression_7
+CODE *expression_7(MPL *mpl);
+/* parse expression of level 7 */
+
+#define expression_8 _glp_mpl_expression_8
+CODE *expression_8(MPL *mpl);
+/* parse expression of level 8 */
+
+#define expression_9 _glp_mpl_expression_9
+CODE *expression_9(MPL *mpl);
+/* parse expression of level 9 */
+
+#define expression_10 _glp_mpl_expression_10
+CODE *expression_10(MPL *mpl);
+/* parse expression of level 10 */
+
+#define expression_11 _glp_mpl_expression_11
+CODE *expression_11(MPL *mpl);
+/* parse expression of level 11 */
+
+#define expression_12 _glp_mpl_expression_12
+CODE *expression_12(MPL *mpl);
+/* parse expression of level 12 */
+
+#define expression_13 _glp_mpl_expression_13
+CODE *expression_13(MPL *mpl);
+/* parse expression of level 13 */
+
+#define set_statement _glp_mpl_set_statement
+SET *set_statement(MPL *mpl);
+/* parse set statement */
+
+#define parameter_statement _glp_mpl_parameter_statement
+PARAMETER *parameter_statement(MPL *mpl);
+/* parse parameter statement */
+
+#define variable_statement _glp_mpl_variable_statement
+VARIABLE *variable_statement(MPL *mpl);
+/* parse variable statement */
+
+#define constraint_statement _glp_mpl_constraint_statement
+CONSTRAINT *constraint_statement(MPL *mpl);
+/* parse constraint statement */
+
+#define objective_statement _glp_mpl_objective_statement
+CONSTRAINT *objective_statement(MPL *mpl);
+/* parse objective statement */
+
+#define table_statement _glp_mpl_table_statement
+TABLE *table_statement(MPL *mpl);
+/* parse table statement */
+
+#define solve_statement _glp_mpl_solve_statement
+void *solve_statement(MPL *mpl);
+/* parse solve statement */
+
+#define check_statement _glp_mpl_check_statement
+CHECK *check_statement(MPL *mpl);
+/* parse check statement */
+
+#define display_statement _glp_mpl_display_statement
+DISPLAY *display_statement(MPL *mpl);
+/* parse display statement */
+
+#define printf_statement _glp_mpl_printf_statement
+PRINTF *printf_statement(MPL *mpl);
+/* parse printf statement */
+
+#define for_statement _glp_mpl_for_statement
+FOR *for_statement(MPL *mpl);
+/* parse for statement */
+
+#define end_statement _glp_mpl_end_statement
+void end_statement(MPL *mpl);
+/* parse end statement */
+
+#define simple_statement _glp_mpl_simple_statement
+STATEMENT *simple_statement(MPL *mpl, int spec);
+/* parse simple statement */
+
+#define model_section _glp_mpl_model_section
+void model_section(MPL *mpl);
+/* parse model section */
+
+/**********************************************************************/
+/* * *                  PROCESSING DATA SECTION                   * * */
+/**********************************************************************/
+
+#if 2 + 2 == 5
+struct SLICE /* see TUPLE */
+{     /* component of slice; the slice itself is associated with its
+         first component; slices are similar to n-tuples with exception
+         that some slice components (which are indicated by asterisks)
+         don't refer to any symbols */
+      SYMBOL *sym;
+      /* symbol, which this component refers to; can be NULL */
+      SLICE *next;
+      /* the next component of slice */
+};
+#endif
+
+#define create_slice _glp_mpl_create_slice
+SLICE *create_slice(MPL *mpl);
+/* create slice */
+
+#define expand_slice _glp_mpl_expand_slice
+SLICE *expand_slice
+(     MPL *mpl,
+      SLICE *slice,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+);
+/* append new component to slice */
+
+#define slice_dimen _glp_mpl_slice_dimen
+int slice_dimen
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+);
+/* determine dimension of slice */
+
+#define slice_arity _glp_mpl_slice_arity
+int slice_arity
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+);
+/* determine arity of slice */
+
+#define fake_slice _glp_mpl_fake_slice
+SLICE *fake_slice(MPL *mpl, int dim);
+/* create fake slice of all asterisks */
+
+#define delete_slice _glp_mpl_delete_slice
+void delete_slice
+(     MPL *mpl,
+      SLICE *slice            /* destroyed */
+);
+/* delete slice */
+
+#define is_number _glp_mpl_is_number
+int is_number(MPL *mpl);
+/* check if current token is number */
+
+#define is_symbol _glp_mpl_is_symbol
+int is_symbol(MPL *mpl);
+/* check if current token is symbol */
+
+#define is_literal _glp_mpl_is_literal
+int is_literal(MPL *mpl, char *literal);
+/* check if current token is given symbolic literal */
+
+#define read_number _glp_mpl_read_number
+double read_number(MPL *mpl);
+/* read number */
+
+#define read_symbol _glp_mpl_read_symbol
+SYMBOL *read_symbol(MPL *mpl);
+/* read symbol */
+
+#define read_slice _glp_mpl_read_slice
+SLICE *read_slice
+(     MPL *mpl,
+      char *name,             /* not changed */
+      int dim
+);
+/* read slice */
+
+#define select_set _glp_mpl_select_set
+SET *select_set
+(     MPL *mpl,
+      char *name              /* not changed */
+);
+/* select set to saturate it with elemental sets */
+
+#define simple_format _glp_mpl_simple_format
+void simple_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice            /* not changed */
+);
+/* read set data block in simple format */
+
+#define matrix_format _glp_mpl_matrix_format
+void matrix_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice,           /* not changed */
+      int tr
+);
+/* read set data block in matrix format */
+
+#define set_data _glp_mpl_set_data
+void set_data(MPL *mpl);
+/* read set data */
+
+#define select_parameter _glp_mpl_select_parameter
+PARAMETER *select_parameter
+(     MPL *mpl,
+      char *name              /* not changed */
+);
+/* select parameter to saturate it with data */
+
+#define set_default _glp_mpl_set_default
+void set_default
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SYMBOL *altval          /* destroyed */
+);
+/* set default parameter value */
+
+#define read_value _glp_mpl_read_value
+MEMBER *read_value
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* destroyed */
+);
+/* read value and assign it to parameter member */
+
+#define plain_format _glp_mpl_plain_format
+void plain_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice            /* not changed */
+);
+/* read parameter data block in plain format */
+
+#define tabular_format _glp_mpl_tabular_format
+void tabular_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice,           /* not changed */
+      int tr
+);
+/* read parameter data block in tabular format */
+
+#define tabbing_format _glp_mpl_tabbing_format
+void tabbing_format
+(     MPL *mpl,
+      SYMBOL *altval          /* not changed */
+);
+/* read parameter data block in tabbing format */
+
+#define parameter_data _glp_mpl_parameter_data
+void parameter_data(MPL *mpl);
+/* read parameter data */
+
+#define data_section _glp_mpl_data_section
+void data_section(MPL *mpl);
+/* read data section */
+
+/**********************************************************************/
+/* * *                   FLOATING-POINT NUMBERS                   * * */
+/**********************************************************************/
+
+#define fp_add _glp_mpl_fp_add
+double fp_add(MPL *mpl, double x, double y);
+/* floating-point addition */
+
+#define fp_sub _glp_mpl_fp_sub
+double fp_sub(MPL *mpl, double x, double y);
+/* floating-point subtraction */
+
+#define fp_less _glp_mpl_fp_less
+double fp_less(MPL *mpl, double x, double y);
+/* floating-point non-negative subtraction */
+
+#define fp_mul _glp_mpl_fp_mul
+double fp_mul(MPL *mpl, double x, double y);
+/* floating-point multiplication */
+
+#define fp_div _glp_mpl_fp_div
+double fp_div(MPL *mpl, double x, double y);
+/* floating-point division */
+
+#define fp_idiv _glp_mpl_fp_idiv
+double fp_idiv(MPL *mpl, double x, double y);
+/* floating-point quotient of exact division */
+
+#define fp_mod _glp_mpl_fp_mod
+double fp_mod(MPL *mpl, double x, double y);
+/* floating-point remainder of exact division */
+
+#define fp_power _glp_mpl_fp_power
+double fp_power(MPL *mpl, double x, double y);
+/* floating-point exponentiation (raise to power) */
+
+#define fp_exp _glp_mpl_fp_exp
+double fp_exp(MPL *mpl, double x);
+/* floating-point base-e exponential */
+
+#define fp_log _glp_mpl_fp_log
+double fp_log(MPL *mpl, double x);
+/* floating-point natural logarithm */
+
+#define fp_log10 _glp_mpl_fp_log10
+double fp_log10(MPL *mpl, double x);
+/* floating-point common (decimal) logarithm */
+
+#define fp_sqrt _glp_mpl_fp_sqrt
+double fp_sqrt(MPL *mpl, double x);
+/* floating-point square root */
+
+#define fp_sin _glp_mpl_fp_sin
+double fp_sin(MPL *mpl, double x);
+/* floating-point trigonometric sine */
+
+#define fp_cos _glp_mpl_fp_cos
+double fp_cos(MPL *mpl, double x);
+/* floating-point trigonometric cosine */
+
+#define fp_atan _glp_mpl_fp_atan
+double fp_atan(MPL *mpl, double x);
+/* floating-point trigonometric arctangent */
+
+#define fp_atan2 _glp_mpl_fp_atan2
+double fp_atan2(MPL *mpl, double y, double x);
+/* floating-point trigonometric arctangent */
+
+#define fp_round _glp_mpl_fp_round
+double fp_round(MPL *mpl, double x, double n);
+/* round floating-point value to n fractional digits */
+
+#define fp_trunc _glp_mpl_fp_trunc
+double fp_trunc(MPL *mpl, double x, double n);
+/* truncate floating-point value to n fractional digits */
+
+/**********************************************************************/
+/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
+/**********************************************************************/
+
+#define fp_irand224 _glp_mpl_fp_irand224
+double fp_irand224(MPL *mpl);
+/* pseudo-random integer in the range [0, 2^24) */
+
+#define fp_uniform01 _glp_mpl_fp_uniform01
+double fp_uniform01(MPL *mpl);
+/* pseudo-random number in the range [0, 1) */
+
+#define fp_uniform _glp_mpl_uniform
+double fp_uniform(MPL *mpl, double a, double b);
+/* pseudo-random number in the range [a, b) */
+
+#define fp_normal01 _glp_mpl_fp_normal01
+double fp_normal01(MPL *mpl);
+/* Gaussian random variate with mu = 0 and sigma = 1 */
+
+#define fp_normal _glp_mpl_fp_normal
+double fp_normal(MPL *mpl, double mu, double sigma);
+/* Gaussian random variate with specified mu and sigma */
+
+/**********************************************************************/
+/* * *                         DATE/TIME                          * * */
+/**********************************************************************/
+
+#define fn_gmtime _glp_mpl_fn_gmtime
+double fn_gmtime(MPL *mpl);
+/* obtain the current calendar time (UTC) */
+
+#define fn_str2time _glp_mpl_fn_str2time
+double fn_str2time(MPL *mpl, const char *str, const char *fmt);
+/* convert character string to the calendar time */
+
+#define fn_time2str _glp_mpl_fn_time2str
+void fn_time2str(MPL *mpl, char *str, double t, const char *fmt);
+/* convert the calendar time to character string */
+
+/**********************************************************************/
+/* * *                     CHARACTER STRINGS                      * * */
+/**********************************************************************/
+
+#define create_string _glp_mpl_create_string
+STRING *create_string
+(     MPL *mpl,
+      char buf[MAX_LENGTH+1]  /* not changed */
+);
+/* create character string */
+
+#define copy_string _glp_mpl_copy_string
+STRING *copy_string
+(     MPL *mpl,
+      STRING *str             /* not changed */
+);
+/* make copy of character string */
+
+#define compare_strings _glp_mpl_compare_strings
+int compare_strings
+(     MPL *mpl,
+      STRING *str1,           /* not changed */
+      STRING *str2            /* not changed */
+);
+/* compare one character string with another */
+
+#define fetch_string _glp_mpl_fetch_string
+char *fetch_string
+(     MPL *mpl,
+      STRING *str,            /* not changed */
+      char buf[MAX_LENGTH+1]  /* modified */
+);
+/* extract content of character string */
+
+#define delete_string _glp_mpl_delete_string
+void delete_string
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+);
+/* delete character string */
+
+/**********************************************************************/
+/* * *                          SYMBOLS                           * * */
+/**********************************************************************/
+
+struct SYMBOL
+{     /* symbol (numeric or abstract quantity) */
+      double num;
+      /* numeric value of symbol (used only if str == NULL) */
+      STRING *str;
+      /* abstract value of symbol (used only if str != NULL) */
+};
+
+#define create_symbol_num _glp_mpl_create_symbol_num
+SYMBOL *create_symbol_num(MPL *mpl, double num);
+/* create symbol of numeric type */
+
+#define create_symbol_str _glp_mpl_create_symbol_str
+SYMBOL *create_symbol_str
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+);
+/* create symbol of abstract type */
+
+#define copy_symbol _glp_mpl_copy_symbol
+SYMBOL *copy_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+);
+/* make copy of symbol */
+
+#define compare_symbols _glp_mpl_compare_symbols
+int compare_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* not changed */
+      SYMBOL *sym2            /* not changed */
+);
+/* compare one symbol with another */
+
+#define delete_symbol _glp_mpl_delete_symbol
+void delete_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* destroyed */
+);
+/* delete symbol */
+
+#define format_symbol _glp_mpl_format_symbol
+char *format_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+);
+/* format symbol for displaying or printing */
+
+#define concat_symbols _glp_mpl_concat_symbols
+SYMBOL *concat_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* destroyed */
+      SYMBOL *sym2            /* destroyed */
+);
+/* concatenate one symbol with another */
+
+/**********************************************************************/
+/* * *                          N-TUPLES                          * * */
+/**********************************************************************/
+
+struct TUPLE
+{     /* component of n-tuple; the n-tuple itself is associated with
+         its first component; (note that 0-tuple has no components) */
+      SYMBOL *sym;
+      /* symbol, which the component refers to; cannot be NULL */
+      TUPLE *next;
+      /* the next component of n-tuple */
+};
+
+#define create_tuple _glp_mpl_create_tuple
+TUPLE *create_tuple(MPL *mpl);
+/* create n-tuple */
+
+#define expand_tuple _glp_mpl_expand_tuple
+TUPLE *expand_tuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+);
+/* append symbol to n-tuple */
+
+#define tuple_dimen _glp_mpl_tuple_dimen
+int tuple_dimen
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+);
+/* determine dimension of n-tuple */
+
+#define copy_tuple _glp_mpl_copy_tuple
+TUPLE *copy_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+);
+/* make copy of n-tuple */
+
+#define compare_tuples _glp_mpl_compare_tuples
+int compare_tuples
+(     MPL *mpl,
+      TUPLE *tuple1,          /* not changed */
+      TUPLE *tuple2           /* not changed */
+);
+/* compare one n-tuple with another */
+
+#define build_subtuple _glp_mpl_build_subtuple
+TUPLE *build_subtuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* not changed */
+      int dim
+);
+/* build subtuple of given n-tuple */
+
+#define delete_tuple _glp_mpl_delete_tuple
+void delete_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* destroyed */
+);
+/* delete n-tuple */
+
+#define format_tuple _glp_mpl_format_tuple
+char *format_tuple
+(     MPL *mpl,
+      int c,
+      TUPLE *tuple            /* not changed */
+);
+/* format n-tuple for displaying or printing */
+
+/**********************************************************************/
+/* * *                       ELEMENTAL SETS                       * * */
+/**********************************************************************/
+
+#if 2 + 2 == 5
+struct ELEMSET /* see ARRAY */
+{     /* elemental set of n-tuples; formally it is a "value" assigned
+         to members of model sets (like numbers and symbols, which are
+         values assigned to members of model parameters); note that a
+         simple model set is not an elemental set, it is 0-dimensional
+         array, the only member of which (if it exists) is assigned an
+         elemental set */
+#endif
+
+#define create_elemset _glp_mpl_create_elemset
+ELEMSET *create_elemset(MPL *mpl, int dim);
+/* create elemental set */
+
+#define find_tuple _glp_mpl_find_tuple
+MEMBER *find_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* check if elemental set contains given n-tuple */
+
+#define add_tuple _glp_mpl_add_tuple
+MEMBER *add_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+);
+/* add new n-tuple to elemental set */
+
+#define check_then_add _glp_mpl_check_then_add
+MEMBER *check_then_add
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+);
+/* check and add new n-tuple to elemental set */
+
+#define copy_elemset _glp_mpl_copy_elemset
+ELEMSET *copy_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* not changed */
+);
+/* make copy of elemental set */
+
+#define delete_elemset _glp_mpl_delete_elemset
+void delete_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* destroyed */
+);
+/* delete elemental set */
+
+#define arelset_size _glp_mpl_arelset_size
+int arelset_size(MPL *mpl, double t0, double tf, double dt);
+/* compute size of "arithmetic" elemental set */
+
+#define arelset_member _glp_mpl_arelset_member
+double arelset_member(MPL *mpl, double t0, double tf, double dt, int j);
+/* compute member of "arithmetic" elemental set */
+
+#define create_arelset _glp_mpl_create_arelset
+ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt);
+/* create "arithmetic" elemental set */
+
+#define set_union _glp_mpl_set_union
+ELEMSET *set_union
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* union of two elemental sets */
+
+#define set_diff _glp_mpl_set_diff
+ELEMSET *set_diff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* difference between two elemental sets */
+
+#define set_symdiff _glp_mpl_set_symdiff
+ELEMSET *set_symdiff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* symmetric difference between two elemental sets */
+
+#define set_inter _glp_mpl_set_inter
+ELEMSET *set_inter
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* intersection of two elemental sets */
+
+#define set_cross _glp_mpl_set_cross
+ELEMSET *set_cross
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* cross (Cartesian) product of two elemental sets */
+
+/**********************************************************************/
+/* * *                    ELEMENTAL VARIABLES                     * * */
+/**********************************************************************/
+
+struct ELEMVAR
+{     /* elemental variable; formally it is a "value" assigned to
+         members of model variables (like numbers and symbols, which
+         are values assigned to members of model parameters) */
+      int j;
+      /* LP column number assigned to this elemental variable */
+      VARIABLE *var;
+      /* model variable, which contains this elemental variable */
+      MEMBER *memb;
+      /* array member, which is assigned this elemental variable */
+      double lbnd;
+      /* lower bound */
+      double ubnd;
+      /* upper bound */
+      double temp;
+      /* working quantity used in operations on linear forms; normally
+         it contains floating-point zero */
+#if 1 /* 15/V-2010 */
+      int stat;
+      double prim, dual;
+      /* solution components provided by the solver */
+#endif
+};
+
+/**********************************************************************/
+/* * *                        LINEAR FORMS                        * * */
+/**********************************************************************/
+
+struct FORMULA
+{     /* term of linear form c * x, where c is a coefficient, x is an
+         elemental variable; the linear form itself is the sum of terms
+         and is associated with its first term; (note that the linear
+         form may be empty that means the sum is equal to zero) */
+      double coef;
+      /* coefficient at elemental variable or constant term */
+      ELEMVAR *var;
+      /* reference to elemental variable; NULL means constant term */
+      FORMULA *next;
+      /* the next term of linear form */
+};
+
+#define constant_term _glp_mpl_constant_term
+FORMULA *constant_term(MPL *mpl, double coef);
+/* create constant term */
+
+#define single_variable _glp_mpl_single_variable
+FORMULA *single_variable
+(     MPL *mpl,
+      ELEMVAR *var            /* referenced */
+);
+/* create single variable */
+
+#define copy_formula _glp_mpl_copy_formula
+FORMULA *copy_formula
+(     MPL *mpl,
+      FORMULA *form           /* not changed */
+);
+/* make copy of linear form */
+
+#define delete_formula _glp_mpl_delete_formula
+void delete_formula
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+);
+/* delete linear form */
+
+#define linear_comb _glp_mpl_linear_comb
+FORMULA *linear_comb
+(     MPL *mpl,
+      double a, FORMULA *fx,  /* destroyed */
+      double b, FORMULA *fy   /* destroyed */
+);
+/* linear combination of two linear forms */
+
+#define remove_constant _glp_mpl_remove_constant
+FORMULA *remove_constant
+(     MPL *mpl,
+      FORMULA *form,          /* destroyed */
+      double *coef            /* modified */
+);
+/* remove constant term from linear form */
+
+#define reduce_terms _glp_mpl_reduce_terms
+FORMULA *reduce_terms
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+);
+/* reduce identical terms in linear form */
+
+/**********************************************************************/
+/* * *                   ELEMENTAL CONSTRAINTS                    * * */
+/**********************************************************************/
+
+struct ELEMCON
+{     /* elemental constraint; formally it is a "value" assigned to
+         members of model constraints (like numbers or symbols, which
+         are values assigned to members of model parameters) */
+      int i;
+      /* LP row number assigned to this elemental constraint */
+      CONSTRAINT *con;
+      /* model constraint, which contains this elemental constraint */
+      MEMBER *memb;
+      /* array member, which is assigned this elemental constraint */
+      FORMULA *form;
+      /* linear form */
+      double lbnd;
+      /* lower bound */
+      double ubnd;
+      /* upper bound */
+#if 1 /* 15/V-2010 */
+      int stat;
+      double prim, dual;
+      /* solution components provided by the solver */
+#endif
+};
+
+/**********************************************************************/
+/* * *                       GENERIC VALUES                       * * */
+/**********************************************************************/
+
+union VALUE
+{     /* generic value, which can be assigned to object member or be a
+         result of evaluation of expression */
+      /* indicator that specifies the particular type of generic value
+         is stored in the corresponding array or pseudo-code descriptor
+         and can be one of the following:
+         A_NONE     - no value
+         A_NUMERIC  - floating-point number
+         A_SYMBOLIC - symbol
+         A_LOGICAL  - logical value
+         A_TUPLE    - n-tuple
+         A_ELEMSET  - elemental set
+         A_ELEMVAR  - elemental variable
+         A_FORMULA  - linear form
+         A_ELEMCON  - elemental constraint */
+      void *none;    /* null */
+      double num;    /* value */
+      SYMBOL *sym;   /* value */
+      int bit;       /* value */
+      TUPLE *tuple;  /* value */
+      ELEMSET *set;  /* value */
+      ELEMVAR *var;  /* reference */
+      FORMULA *form; /* value */
+      ELEMCON *con;  /* reference */
+};
+
+#define delete_value _glp_mpl_delete_value
+void delete_value
+(     MPL *mpl,
+      int type,
+      VALUE *value            /* content destroyed */
+);
+/* delete generic value */
+
+/**********************************************************************/
+/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
+/**********************************************************************/
+
+struct ARRAY
+{     /* multi-dimensional array, a set of members indexed over simple
+         or compound sets of symbols; arrays are used to represent the
+         contents of model objects (i.e. sets, parameters, variables,
+         constraints, and objectives); arrays also are used as "values"
+         that are assigned to members of set objects, in which case the
+         array itself represents an elemental set */
+      int type;
+      /* type of generic values assigned to the array members:
+         A_NONE     - none (members have no assigned values)
+         A_NUMERIC  - floating-point numbers
+         A_SYMBOLIC - symbols
+         A_ELEMSET  - elemental sets
+         A_ELEMVAR  - elemental variables
+         A_ELEMCON  - elemental constraints */
+      int dim;
+      /* dimension of the array that determines number of components in
+         n-tuples for all members of the array, dim >= 0; dim = 0 means
+         the array is 0-dimensional */
+      int size;
+      /* size of the array, i.e. number of its members */
+      MEMBER *head;
+      /* the first array member; NULL means the array is empty */
+      MEMBER *tail;
+      /* the last array member; NULL means the array is empty */
+      AVL *tree;
+      /* the search tree intended to find array members for logarithmic
+         time; NULL means the search tree doesn't exist */
+      ARRAY *prev;
+      /* the previous array in the translator database */
+      ARRAY *next;
+      /* the next array in the translator database */
+};
+
+struct MEMBER
+{     /* array member */
+      TUPLE *tuple;
+      /* n-tuple, which identifies the member; number of its components
+         is the same for all members within the array and determined by
+         the array dimension; duplicate members are not allowed */
+      MEMBER *next;
+      /* the next array member */
+      VALUE value;
+      /* generic value assigned to the member */
+};
+
+#define create_array _glp_mpl_create_array
+ARRAY *create_array(MPL *mpl, int type, int dim);
+/* create array */
+
+#define find_member _glp_mpl_find_member
+MEMBER *find_member
+(     MPL *mpl,
+      ARRAY *array,           /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* find array member with given n-tuple */
+
+#define add_member _glp_mpl_add_member
+MEMBER *add_member
+(     MPL *mpl,
+      ARRAY *array,           /* modified */
+      TUPLE *tuple            /* destroyed */
+);
+/* add new member to array */
+
+#define delete_array _glp_mpl_delete_array
+void delete_array
+(     MPL *mpl,
+      ARRAY *array            /* destroyed */
+);
+/* delete array */
+
+/**********************************************************************/
+/* * *                 DOMAINS AND DUMMY INDICES                  * * */
+/**********************************************************************/
+
+struct DOMAIN
+{     /* domain (a simple or compound set); syntactically domain looks
+         like '{ i in I, (j,k) in S, t in T : <predicate> }'; domains
+         are used to define sets, over which model objects are indexed,
+         and also as constituents of iterated operators */
+      DOMAIN_BLOCK *list;
+      /* linked list of domain blocks (in the example above such blocks
+         are 'i in I', '(j,k) in S', and 't in T'); this list cannot be
+         empty */
+      CODE *code;
+      /* pseudo-code for computing the logical predicate, which follows
+         the colon; NULL means no predicate is specified */
+};
+
+struct DOMAIN_BLOCK
+{     /* domain block; syntactically domain blocks look like 'i in I',
+         '(j,k) in S', and 't in T' in the example above (in the sequel
+         sets like I, S, and T are called basic sets) */
+      DOMAIN_SLOT *list;
+      /* linked list of domain slots (i.e. indexing positions); number
+         of slots in this list is the same as dimension of n-tuples in
+         the basic set; this list cannot be empty */
+      CODE *code;
+      /* pseudo-code for computing basic set; cannot be NULL */
+      TUPLE *backup;
+      /* if this n-tuple is not empty, current values of dummy indices
+         in the domain block are the same as components of this n-tuple
+         (note that this n-tuple may have larger dimension than number
+         of dummy indices in this block, in which case extra components
+         are ignored); this n-tuple is used to restore former values of
+         dummy indices, if they were changed due to recursive calls to
+         the domain block */
+      DOMAIN_BLOCK *next;
+      /* the next block in the same domain */
+};
+
+struct DOMAIN_SLOT
+{     /* domain slot; it specifies an individual indexing position and
+         defines the corresponding dummy index */
+      char *name;
+      /* symbolic name of the dummy index; null pointer means the dummy
+         index is not explicitly specified */
+      CODE *code;
+      /* pseudo-code for computing symbolic value, at which the dummy
+         index is bound; NULL means the dummy index is free within the
+         domain scope */
+      SYMBOL *value;
+      /* current value assigned to the dummy index; NULL means no value
+         is assigned at the moment */
+      CODE *list;
+      /* linked list of pseudo-codes with operation O_INDEX referring
+         to this slot; this linked list is used to invalidate resultant
+         values of the operation, which depend on this dummy index */
+      DOMAIN_SLOT *next;
+      /* the next slot in the same domain block */
+};
+
+#define assign_dummy_index _glp_mpl_assign_dummy_index
+void assign_dummy_index
+(     MPL *mpl,
+      DOMAIN_SLOT *slot,      /* modified */
+      SYMBOL *value           /* not changed */
+);
+/* assign new value to dummy index */
+
+#define update_dummy_indices _glp_mpl_update_dummy_indices
+void update_dummy_indices
+(     MPL *mpl,
+      DOMAIN_BLOCK *block     /* not changed */
+);
+/* update current values of dummy indices */
+
+#define enter_domain_block _glp_mpl_enter_domain_block
+int enter_domain_block
+(     MPL *mpl,
+      DOMAIN_BLOCK *block,    /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+);
+/* enter domain block */
+
+#define eval_within_domain _glp_mpl_eval_within_domain
+int eval_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+);
+/* perform evaluation within domain scope */
+
+#define loop_within_domain _glp_mpl_loop_within_domain
+void loop_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      void *info, int (*func)(MPL *mpl, void *info)
+);
+/* perform iterations within domain scope */
+
+#define out_of_domain _glp_mpl_out_of_domain
+void out_of_domain
+(     MPL *mpl,
+      char *name,             /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* raise domain exception */
+
+#define get_domain_tuple _glp_mpl_get_domain_tuple
+TUPLE *get_domain_tuple
+(     MPL *mpl,
+      DOMAIN *domain          /* not changed */
+);
+/* obtain current n-tuple from domain */
+
+#define clean_domain _glp_mpl_clean_domain
+void clean_domain(MPL *mpl, DOMAIN *domain);
+/* clean domain */
+
+/**********************************************************************/
+/* * *                         MODEL SETS                         * * */
+/**********************************************************************/
+
+struct SET
+{     /* model set */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) set, dim > 0 means set of sets */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional set */
+      int dimen;
+      /* dimension of n-tuples, which members of this set consist of
+         (note that the model set itself is an array of elemental sets,
+         which are its members; so, don't confuse this dimension with
+         dimension of the model set); always non-zero */
+      WITHIN *within;
+      /* list of supersets, which restrict each member of the set to be
+         in every superset from this list; this list can be empty */
+      CODE *assign;
+      /* pseudo-code for computing assigned value; can be NULL */
+      CODE *option;
+      /* pseudo-code for computing default value; can be NULL */
+      GADGET *gadget;
+      /* plain set used to initialize the array of sets; can be NULL */
+      int data;
+      /* data status flag:
+         0 - no data are provided in the data section
+         1 - data are provided, but not checked yet
+         2 - data are provided and have been checked */
+      ARRAY *array;
+      /* array of members, which are assigned elemental sets */
+};
+
+struct WITHIN
+{     /* restricting superset list entry */
+      CODE *code;
+      /* pseudo-code for computing the superset; cannot be NULL */
+      WITHIN *next;
+      /* the next entry for the same set or parameter */
+};
+
+struct GADGET
+{     /* plain set used to initialize the array of sets with data */
+      SET *set;
+      /* pointer to plain set; cannot be NULL */
+      int ind[20]; /* ind[dim+dimen]; */
+      /* permutation of integers 1, 2, ..., dim+dimen */
+};
+
+#define check_elem_set _glp_mpl_check_elem_set
+void check_elem_set
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple,           /* not changed */
+      ELEMSET *refer          /* not changed */
+);
+/* check elemental set assigned to set member */
+
+#define take_member_set _glp_mpl_take_member_set
+ELEMSET *take_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain elemental set assigned to set member */
+
+#define eval_member_set _glp_mpl_eval_member_set
+ELEMSET *eval_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate elemental set assigned to set member */
+
+#define eval_whole_set _glp_mpl_eval_whole_set
+void eval_whole_set(MPL *mpl, SET *set);
+/* evaluate model set over entire domain */
+
+#define clean_set _glp_mpl_clean_set
+void clean_set(MPL *mpl, SET *set);
+/* clean model set */
+
+/**********************************************************************/
+/* * *                      MODEL PARAMETERS                      * * */
+/**********************************************************************/
+
+struct PARAMETER
+{     /* model parameter */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) parameter */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional parameter */
+      int type;
+      /* parameter type:
+         A_NUMERIC  - numeric
+         A_INTEGER  - integer
+         A_BINARY   - binary
+         A_SYMBOLIC - symbolic */
+      CONDITION *cond;
+      /* list of conditions, which restrict each parameter member to
+         satisfy to every condition from this list; this list is used
+         only for numeric parameters and can be empty */
+      WITHIN *in;
+      /* list of supersets, which restrict each parameter member to be
+         in every superset from this list; this list is used only for
+         symbolic parameters and can be empty */
+      CODE *assign;
+      /* pseudo-code for computing assigned value; can be NULL */
+      CODE *option;
+      /* pseudo-code for computing default value; can be NULL */
+      int data;
+      /* data status flag:
+         0 - no data are provided in the data section
+         1 - data are provided, but not checked yet
+         2 - data are provided and have been checked */
+      SYMBOL *defval;
+      /* default value provided in the data section; can be NULL */
+      ARRAY *array;
+      /* array of members, which are assigned numbers or symbols */
+};
+
+struct CONDITION
+{     /* restricting condition list entry */
+      int rho;
+      /* flag that specifies the form of the condition:
+         O_LT - less than
+         O_LE - less than or equal to
+         O_EQ - equal to
+         O_GE - greater than or equal to
+         O_GT - greater than
+         O_NE - not equal to */
+      CODE *code;
+      /* pseudo-code for computing the reference value */
+      CONDITION *next;
+      /* the next entry for the same parameter */
+};
+
+#define check_value_num _glp_mpl_check_value_num
+void check_value_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      double value
+);
+/* check numeric value assigned to parameter member */
+
+#define take_member_num _glp_mpl_take_member_num
+double take_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain numeric value assigned to parameter member */
+
+#define eval_member_num _glp_mpl_eval_member_num
+double eval_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate numeric value assigned to parameter member */
+
+#define check_value_sym _glp_mpl_check_value_sym
+void check_value_sym
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      SYMBOL *value           /* not changed */
+);
+/* check symbolic value assigned to parameter member */
+
+#define take_member_sym _glp_mpl_take_member_sym
+SYMBOL *take_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain symbolic value assigned to parameter member */
+
+#define eval_member_sym _glp_mpl_eval_member_sym
+SYMBOL *eval_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate symbolic value assigned to parameter member */
+
+#define eval_whole_par _glp_mpl_eval_whole_par
+void eval_whole_par(MPL *mpl, PARAMETER *par);
+/* evaluate model parameter over entire domain */
+
+#define clean_parameter _glp_mpl_clean_parameter
+void clean_parameter(MPL *mpl, PARAMETER *par);
+/* clean model parameter */
+
+/**********************************************************************/
+/* * *                      MODEL VARIABLES                       * * */
+/**********************************************************************/
+
+struct VARIABLE
+{     /* model variable */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) variable */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional variable */
+      int type;
+      /* variable type:
+         A_NUMERIC - continuous
+         A_INTEGER - integer
+         A_BINARY  - binary */
+      CODE *lbnd;
+      /* pseudo-code for computing lower bound; NULL means lower bound
+         is not specified */
+      CODE *ubnd;
+      /* pseudo-code for computing upper bound; NULL means upper bound
+         is not specified */
+      /* if both the pointers lbnd and ubnd refer to the same code, the
+         variable is fixed at the corresponding value */
+      ARRAY *array;
+      /* array of members, which are assigned elemental variables */
+};
+
+#define take_member_var _glp_mpl_take_member_var
+ELEMVAR *take_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain reference to elemental variable */
+
+#define eval_member_var _glp_mpl_eval_member_var
+ELEMVAR *eval_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate reference to elemental variable */
+
+#define eval_whole_var _glp_mpl_eval_whole_var
+void eval_whole_var(MPL *mpl, VARIABLE *var);
+/* evaluate model variable over entire domain */
+
+#define clean_variable _glp_mpl_clean_variable
+void clean_variable(MPL *mpl, VARIABLE *var);
+/* clean model variable */
+
+/**********************************************************************/
+/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
+/**********************************************************************/
+
+struct CONSTRAINT
+{     /* model constraint or objective */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) constraint */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional constraint */
+      int type;
+      /* constraint type:
+         A_CONSTRAINT - constraint
+         A_MINIMIZE   - objective (minimization)
+         A_MAXIMIZE   - objective (maximization) */
+      CODE *code;
+      /* pseudo-code for computing main linear form; cannot be NULL */
+      CODE *lbnd;
+      /* pseudo-code for computing lower bound; NULL means lower bound
+         is not specified */
+      CODE *ubnd;
+      /* pseudo-code for computing upper bound; NULL means upper bound
+         is not specified */
+      /* if both the pointers lbnd and ubnd refer to the same code, the
+         constraint has the form of equation */
+      ARRAY *array;
+      /* array of members, which are assigned elemental constraints */
+};
+
+#define take_member_con _glp_mpl_take_member_con
+ELEMCON *take_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain reference to elemental constraint */
+
+#define eval_member_con _glp_mpl_eval_member_con
+ELEMCON *eval_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate reference to elemental constraint */
+
+#define eval_whole_con _glp_mpl_eval_whole_con
+void eval_whole_con(MPL *mpl, CONSTRAINT *con);
+/* evaluate model constraint over entire domain */
+
+#define clean_constraint _glp_mpl_clean_constraint
+void clean_constraint(MPL *mpl, CONSTRAINT *con);
+/* clean model constraint */
+
+/**********************************************************************/
+/* * *                        DATA TABLES                         * * */
+/**********************************************************************/
+
+struct TABLE
+{     /* data table */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int type;
+      /* table type:
+         A_INPUT  - input table
+         A_OUTPUT - output table */
+      TABARG *arg;
+      /* argument list; cannot be empty */
+      union
+      {  struct
+         {  SET *set;
+            /* input set; NULL means the set is not specified */
+            TABFLD *fld;
+            /* field list; cannot be empty */
+            TABIN *list;
+            /* input list; can be empty */
+         } in;
+         struct
+         {  DOMAIN *domain;
+            /* subscript domain; cannot be NULL */
+            TABOUT *list;
+            /* output list; cannot be empty */
+         } out;
+      } u;
+};
+
+struct TABARG
+{     /* table argument list entry */
+      CODE *code;
+      /* pseudo-code for computing the argument */
+      TABARG *next;
+      /* next entry for the same table */
+};
+
+struct TABFLD
+{     /* table field list entry */
+      char *name;
+      /* field name; cannot be NULL */
+      TABFLD *next;
+      /* next entry for the same table */
+};
+
+struct TABIN
+{     /* table input list entry */
+      PARAMETER *par;
+      /* parameter to be read; cannot be NULL */
+      char *name;
+      /* column name; cannot be NULL */
+      TABIN *next;
+      /* next entry for the same table */
+};
+
+struct TABOUT
+{     /* table output list entry */
+      CODE *code;
+      /* pseudo-code for computing the value to be written */
+      char *name;
+      /* column name; cannot be NULL */
+      TABOUT *next;
+      /* next entry for the same table */
+};
+
+struct TABDCA
+{     /* table driver communication area */
+      int id;
+      /* driver identifier (set by mpl_tab_drv_open) */
+      void *link;
+      /* driver link pointer (set by mpl_tab_drv_open) */
+      int na;
+      /* number of arguments */
+      char **arg; /* char *arg[1+ns]; */
+      /* arg[k], 1 <= k <= ns, is pointer to k-th argument */
+      int nf;
+      /* number of fields */
+      char **name; /* char *name[1+nc]; */
+      /* name[k], 1 <= k <= nc, is name of k-th field */
+      int *type; /* int type[1+nc]; */
+      /* type[k], 1 <= k <= nc, is type of k-th field:
+         '?' - value not assigned
+         'N' - number
+         'S' - character string */
+      double *num; /* double num[1+nc]; */
+      /* num[k], 1 <= k <= nc, is numeric value of k-th field */
+      char **str;
+      /* str[k], 1 <= k <= nc, is string value of k-th field */
+};
+
+#define mpl_tab_num_args _glp_mpl_tab_num_args
+int mpl_tab_num_args(TABDCA *dca);
+
+#define mpl_tab_get_arg _glp_mpl_tab_get_arg
+const char *mpl_tab_get_arg(TABDCA *dca, int k);
+
+#define mpl_tab_num_flds _glp_mpl_tab_num_flds
+int mpl_tab_num_flds(TABDCA *dca);
+
+#define mpl_tab_get_name _glp_mpl_tab_get_name
+const char *mpl_tab_get_name(TABDCA *dca, int k);
+
+#define mpl_tab_get_type _glp_mpl_tab_get_type
+int mpl_tab_get_type(TABDCA *dca, int k);
+
+#define mpl_tab_get_num _glp_mpl_tab_get_num
+double mpl_tab_get_num(TABDCA *dca, int k);
+
+#define mpl_tab_get_str _glp_mpl_tab_get_str
+const char *mpl_tab_get_str(TABDCA *dca, int k);
+
+#define mpl_tab_set_num _glp_mpl_tab_set_num
+void mpl_tab_set_num(TABDCA *dca, int k, double num);
+
+#define mpl_tab_set_str _glp_mpl_tab_set_str
+void mpl_tab_set_str(TABDCA *dca, int k, const char *str);
+
+#define mpl_tab_drv_open _glp_mpl_tab_drv_open
+void mpl_tab_drv_open(MPL *mpl, int mode);
+
+#define mpl_tab_drv_read _glp_mpl_tab_drv_read
+int mpl_tab_drv_read(MPL *mpl);
+
+#define mpl_tab_drv_write _glp_mpl_tab_drv_write
+void mpl_tab_drv_write(MPL *mpl);
+
+#define mpl_tab_drv_close _glp_mpl_tab_drv_close
+void mpl_tab_drv_close(MPL *mpl);
+
+/**********************************************************************/
+/* * *                        PSEUDO-CODE                         * * */
+/**********************************************************************/
+
+union OPERANDS
+{     /* operands that participate in pseudo-code operation (choice of
+         particular operands depends on the operation code) */
+      /*--------------------------------------------------------------*/
+      double num;             /* O_NUMBER */
+      /* floaing-point number to be taken */
+      /*--------------------------------------------------------------*/
+      char *str;              /* O_STRING */
+      /* character string to be taken */
+      /*--------------------------------------------------------------*/
+      struct                  /* O_INDEX */
+      {  DOMAIN_SLOT *slot;
+         /* domain slot, which contains dummy index to be taken */
+         CODE *next;
+         /* the next pseudo-code with op = O_INDEX, which refers to the
+            same slot as this one; pointer to the beginning of this list
+            is stored in the corresponding domain slot */
+      } index;
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMNUM, O_MEMSYM */
+      {  PARAMETER *par;
+         /* model parameter, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripts; NULL for 0-dimensional parameter */
+      } par;
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMSET */
+      {  SET *set;
+         /* model set, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripts; NULL for 0-dimensional set */
+      } set;
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMVAR */
+      {  VARIABLE *var;
+         /* model variable, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripts; NULL for 0-dimensional variable */
+#if 1 /* 15/V-2010 */
+         int suff;
+         /* suffix specified: */
+#define DOT_NONE        0x00  /* none     (means variable itself) */
+#define DOT_LB          0x01  /* .lb      (lower bound) */
+#define DOT_UB          0x02  /* .ub      (upper bound) */
+#define DOT_STATUS      0x03  /* .status  (status) */
+#define DOT_VAL         0x04  /* .val     (primal value) */
+#define DOT_DUAL        0x05  /* .dual    (dual value) */
+#endif
+      } var;
+#if 1 /* 15/V-2010 */
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMCON */
+      {  CONSTRAINT *con;
+         /* model constraint, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripys; NULL for 0-dimensional constraint */
+         int suff;
+         /* suffix specified (see O_MEMVAR above) */
+      } con;
+#endif
+      /*--------------------------------------------------------------*/
+      ARG_LIST *list;         /* O_TUPLE, O_MAKE, n-ary operations */
+      /* list of operands */
+      /*--------------------------------------------------------------*/
+      DOMAIN_BLOCK *slice;    /* O_SLICE */
+      /* domain block, which specifies slice (i.e. n-tuple that contains
+         free dummy indices); this operation is never evaluated */
+      /*--------------------------------------------------------------*/
+      struct                  /* unary, binary, ternary operations */
+      {  CODE *x;
+         /* pseudo-code for computing first operand */
+         CODE *y;
+         /* pseudo-code for computing second operand */
+         CODE *z;
+         /* pseudo-code for computing third operand */
+      } arg;
+      /*--------------------------------------------------------------*/
+      struct                  /* iterated operations */
+      {  DOMAIN *domain;
+         /* domain, over which the operation is performed */
+         CODE *x;
+         /* pseudo-code for computing "integrand" */
+      } loop;
+      /*--------------------------------------------------------------*/
+};
+
+struct ARG_LIST
+{     /* operands list entry */
+      CODE *x;
+      /* pseudo-code for computing operand */
+      ARG_LIST *next;
+      /* the next operand of the same operation */
+};
+
+struct CODE
+{     /* pseudo-code (internal form of expressions) */
+      int op;
+      /* operation code: */
+#define O_NUMBER        301   /* take floating-point number */
+#define O_STRING        302   /* take character string */
+#define O_INDEX         303   /* take dummy index */
+#define O_MEMNUM        304   /* take member of numeric parameter */
+#define O_MEMSYM        305   /* take member of symbolic parameter */
+#define O_MEMSET        306   /* take member of set */
+#define O_MEMVAR        307   /* take member of variable */
+#define O_MEMCON        308   /* take member of constraint */
+#define O_TUPLE         309   /* make n-tuple */
+#define O_MAKE          310   /* make elemental set of n-tuples */
+#define O_SLICE         311   /* define domain block (dummy op) */
+                              /* 0-ary operations --------------------*/
+#define O_IRAND224      312   /* pseudo-random in [0, 2^24-1] */
+#define O_UNIFORM01     313   /* pseudo-random in [0, 1) */
+#define O_NORMAL01      314   /* gaussian random, mu = 0, sigma = 1 */
+#define O_GMTIME        315   /* current calendar time (UTC) */
+                              /* unary operations --------------------*/
+#define O_CVTNUM        316   /* conversion to numeric */
+#define O_CVTSYM        317   /* conversion to symbolic */
+#define O_CVTLOG        318   /* conversion to logical */
+#define O_CVTTUP        319   /* conversion to 1-tuple */
+#define O_CVTLFM        320   /* conversion to linear form */
+#define O_PLUS          321   /* unary plus */
+#define O_MINUS         322   /* unary minus */
+#define O_NOT           323   /* negation (logical "not") */
+#define O_ABS           324   /* absolute value */
+#define O_CEIL          325   /* round upward ("ceiling of x") */
+#define O_FLOOR         326   /* round downward ("floor of x") */
+#define O_EXP           327   /* base-e exponential */
+#define O_LOG           328   /* natural logarithm */
+#define O_LOG10         329   /* common (decimal) logarithm */
+#define O_SQRT          330   /* square root */
+#define O_SIN           331   /* trigonometric sine */
+#define O_COS           332   /* trigonometric cosine */
+#define O_ATAN          333   /* trigonometric arctangent */
+#define O_ROUND         334   /* round to nearest integer */
+#define O_TRUNC         335   /* truncate to nearest integer */
+#define O_CARD          336   /* cardinality of set */
+#define O_LENGTH        337   /* length of symbolic value */
+                              /* binary operations -------------------*/
+#define O_ADD           338   /* addition */
+#define O_SUB           339   /* subtraction */
+#define O_LESS          340   /* non-negative subtraction */
+#define O_MUL           341   /* multiplication */
+#define O_DIV           342   /* division */
+#define O_IDIV          343   /* quotient of exact division */
+#define O_MOD           344   /* remainder of exact division */
+#define O_POWER         345   /* exponentiation (raise to power) */
+#define O_ATAN2         346   /* trigonometric arctangent */
+#define O_ROUND2        347   /* round to n fractional digits */
+#define O_TRUNC2        348   /* truncate to n fractional digits */
+#define O_UNIFORM       349   /* pseudo-random in [a, b) */
+#define O_NORMAL        350   /* gaussian random, given mu and sigma */
+#define O_CONCAT        351   /* concatenation */
+#define O_LT            352   /* comparison on 'less than' */
+#define O_LE            353   /* comparison on 'not greater than' */
+#define O_EQ            354   /* comparison on 'equal to' */
+#define O_GE            355   /* comparison on 'not less than' */
+#define O_GT            356   /* comparison on 'greater than' */
+#define O_NE            357   /* comparison on 'not equal to' */
+#define O_AND           358   /* conjunction (logical "and") */
+#define O_OR            359   /* disjunction (logical "or") */
+#define O_UNION         360   /* union */
+#define O_DIFF          361   /* difference */
+#define O_SYMDIFF       362   /* symmetric difference */
+#define O_INTER         363   /* intersection */
+#define O_CROSS         364   /* cross (Cartesian) product */
+#define O_IN            365   /* test on 'x in Y' */
+#define O_NOTIN         366   /* test on 'x not in Y' */
+#define O_WITHIN        367   /* test on 'X within Y' */
+#define O_NOTWITHIN     368   /* test on 'X not within Y' */
+#define O_SUBSTR        369   /* substring */
+#define O_STR2TIME      370   /* convert string to time */
+#define O_TIME2STR      371   /* convert time to string */
+                              /* ternary operations ------------------*/
+#define O_DOTS          372   /* build "arithmetic" set */
+#define O_FORK          373   /* if-then-else */
+#define O_SUBSTR3       374   /* substring */
+                              /* n-ary operations --------------------*/
+#define O_MIN           375   /* minimal value (n-ary) */
+#define O_MAX           376   /* maximal value (n-ary) */
+                              /* iterated operations -----------------*/
+#define O_SUM           377   /* summation */
+#define O_PROD          378   /* multiplication */
+#define O_MINIMUM       379   /* minimum */
+#define O_MAXIMUM       380   /* maximum */
+#define O_FORALL        381   /* conjunction (A-quantification) */
+#define O_EXISTS        382   /* disjunction (E-quantification) */
+#define O_SETOF         383   /* compute elemental set */
+#define O_BUILD         384   /* build elemental set */
+      OPERANDS arg;
+      /* operands that participate in the operation */
+      int type;
+      /* type of the resultant value:
+         A_NUMERIC  - numeric
+         A_SYMBOLIC - symbolic
+         A_LOGICAL  - logical
+         A_TUPLE    - n-tuple
+         A_ELEMSET  - elemental set
+         A_FORMULA  - linear form */
+      int dim;
+      /* dimension of the resultant value; for A_TUPLE and A_ELEMSET it
+         is the dimension of the corresponding n-tuple(s) and cannot be
+         zero; for other resultant types it is always zero */
+      CODE *up;
+      /* parent pseudo-code, which refers to this pseudo-code as to its
+         operand; NULL means this pseudo-code has no parent and defines
+         an expression, which is not contained in another expression */
+      int vflag;
+      /* volatile flag; being set this flag means that this operation
+         has a side effect; for primary expressions this flag is set
+         directly by corresponding parsing routines (for example, if
+         primary expression is a reference to a function that generates
+         pseudo-random numbers); in other cases this flag is inherited
+         from operands */
+      int valid;
+      /* if this flag is set, the resultant value, which is a temporary
+         result of evaluating this operation on particular values of
+         operands, is valid; if this flag is clear, the resultant value
+         doesn't exist and therefore not valid; having been evaluated
+         the resultant value is stored here and not destroyed until the
+         dummy indices, which this value depends on, have been changed
+         (and if it doesn't depend on dummy indices at all, it is never
+         destroyed); thus, if the resultant value is valid, evaluating
+         routine can immediately take its copy not computing the result
+         from scratch; this mechanism is similar to moving invariants
+         out of loops and allows improving efficiency at the expense of
+         some extra memory needed to keep temporary results */
+      /* however, if the volatile flag (see above) is set, even if the
+         resultant value is valid, evaluating routine computes it as if
+         it were not valid, i.e. caching is not used in this case */
+      VALUE value;
+      /* resultant value in generic format */
+};
+
+#define eval_numeric _glp_mpl_eval_numeric
+double eval_numeric(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine numeric value */
+
+#define eval_symbolic _glp_mpl_eval_symbolic
+SYMBOL *eval_symbolic(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine symbolic value */
+
+#define eval_logical _glp_mpl_eval_logical
+int eval_logical(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine logical value */
+
+#define eval_tuple _glp_mpl_eval_tuple
+TUPLE *eval_tuple(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct n-tuple */
+
+#define eval_elemset _glp_mpl_eval_elemset
+ELEMSET *eval_elemset(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct elemental set */
+
+#define is_member _glp_mpl_is_member
+int is_member(MPL *mpl, CODE *code, TUPLE *tuple);
+/* check if n-tuple is in set specified by pseudo-code */
+
+#define eval_formula _glp_mpl_eval_formula
+FORMULA *eval_formula(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct linear form */
+
+#define clean_code _glp_mpl_clean_code
+void clean_code(MPL *mpl, CODE *code);
+/* clean pseudo-code */
+
+/**********************************************************************/
+/* * *                      MODEL STATEMENTS                      * * */
+/**********************************************************************/
+
+struct CHECK
+{     /* check statement */
+      DOMAIN *domain;
+      /* subscript domain; NULL means domain is not used */
+      CODE *code;
+      /* code for computing the predicate to be checked */
+};
+
+struct DISPLAY
+{     /* display statement */
+      DOMAIN *domain;
+      /* subscript domain; NULL means domain is not used */
+      DISPLAY1 *list;
+      /* display list; cannot be empty */
+};
+
+struct DISPLAY1
+{     /* display list entry */
+      int type;
+      /* item type:
+         A_INDEX      - dummy index
+         A_SET        - model set
+         A_PARAMETER  - model parameter
+         A_VARIABLE   - model variable
+         A_CONSTRAINT - model constraint/objective
+         A_EXPRESSION - expression */
+      union
+      {  DOMAIN_SLOT *slot;
+         SET *set;
+         PARAMETER *par;
+         VARIABLE *var;
+         CONSTRAINT *con;
+         CODE *code;
+      } u;
+      /* item to be displayed */
+#if 0 /* 15/V-2010 */
+      ARG_LIST *list;
+      /* optional subscript list (for constraint/objective only) */
+#endif
+      DISPLAY1 *next;
+      /* the next entry for the same statement */
+};
+
+struct PRINTF
+{     /* printf statement */
+      DOMAIN *domain;
+      /* subscript domain; NULL means domain is not used */
+      CODE *fmt;
+      /* pseudo-code for computing format string */
+      PRINTF1 *list;
+      /* printf list; can be empty */
+      CODE *fname;
+      /* pseudo-code for computing filename to redirect the output;
+         NULL means the output goes to stdout */
+      int app;
+      /* if this flag is set, the output is appended */
+};
+
+struct PRINTF1
+{     /* printf list entry */
+      CODE *code;
+      /* pseudo-code for computing value to be printed */
+      PRINTF1 *next;
+      /* the next entry for the same statement */
+};
+
+struct FOR
+{     /* for statement */
+      DOMAIN *domain;
+      /* subscript domain; cannot be NULL */
+      STATEMENT *list;
+      /* linked list of model statements within this for statement in
+         the original order */
+};
+
+struct STATEMENT
+{     /* model statement */
+      int line;
+      /* number of source text line, where statement begins */
+      int type;
+      /* statement type:
+         A_SET        - set statement
+         A_PARAMETER  - parameter statement
+         A_VARIABLE   - variable statement
+         A_CONSTRAINT - constraint/objective statement
+         A_TABLE      - table statement
+         A_SOLVE      - solve statement
+         A_CHECK      - check statement
+         A_DISPLAY    - display statement
+         A_PRINTF     - printf statement
+         A_FOR        - for statement */
+      union
+      {  SET *set;
+         PARAMETER *par;
+         VARIABLE *var;
+         CONSTRAINT *con;
+         TABLE *tab;
+         void *slv; /* currently not used (set to NULL) */
+         CHECK *chk;
+         DISPLAY *dpy;
+         PRINTF *prt;
+         FOR *fur;
+      } u;
+      /* specific part of statement */
+      STATEMENT *next;
+      /* the next statement; in this list statements follow in the same
+         order as they appear in the model section */
+};
+
+#define execute_table _glp_mpl_execute_table
+void execute_table(MPL *mpl, TABLE *tab);
+/* execute table statement */
+
+#define free_dca _glp_mpl_free_dca
+void free_dca(MPL *mpl);
+/* free table driver communucation area */
+
+#define clean_table _glp_mpl_clean_table
+void clean_table(MPL *mpl, TABLE *tab);
+/* clean table statement */
+
+#define execute_check _glp_mpl_execute_check
+void execute_check(MPL *mpl, CHECK *chk);
+/* execute check statement */
+
+#define clean_check _glp_mpl_clean_check
+void clean_check(MPL *mpl, CHECK *chk);
+/* clean check statement */
+
+#define execute_display _glp_mpl_execute_display
+void execute_display(MPL *mpl, DISPLAY *dpy);
+/* execute display statement */
+
+#define clean_display _glp_mpl_clean_display
+void clean_display(MPL *mpl, DISPLAY *dpy);
+/* clean display statement */
+
+#define execute_printf _glp_mpl_execute_printf
+void execute_printf(MPL *mpl, PRINTF *prt);
+/* execute printf statement */
+
+#define clean_printf _glp_mpl_clean_printf
+void clean_printf(MPL *mpl, PRINTF *prt);
+/* clean printf statement */
+
+#define execute_for _glp_mpl_execute_for
+void execute_for(MPL *mpl, FOR *fur);
+/* execute for statement */
+
+#define clean_for _glp_mpl_clean_for
+void clean_for(MPL *mpl, FOR *fur);
+/* clean for statement */
+
+#define execute_statement _glp_mpl_execute_statement
+void execute_statement(MPL *mpl, STATEMENT *stmt);
+/* execute specified model statement */
+
+#define clean_statement _glp_mpl_clean_statement
+void clean_statement(MPL *mpl, STATEMENT *stmt);
+/* clean specified model statement */
+
+/**********************************************************************/
+/* * *              GENERATING AND POSTSOLVING MODEL              * * */
+/**********************************************************************/
+
+#define alloc_content _glp_mpl_alloc_content
+void alloc_content(MPL *mpl);
+/* allocate content arrays for all model objects */
+
+#define generate_model _glp_mpl_generate_model
+void generate_model(MPL *mpl);
+/* generate model */
+
+#define build_problem _glp_mpl_build_problem
+void build_problem(MPL *mpl);
+/* build problem instance */
+
+#define postsolve_model _glp_mpl_postsolve_model
+void postsolve_model(MPL *mpl);
+/* postsolve model */
+
+#define clean_model _glp_mpl_clean_model
+void clean_model(MPL *mpl);
+/* clean model content */
+
+/**********************************************************************/
+/* * *                        INPUT/OUTPUT                        * * */
+/**********************************************************************/
+
+#define open_input _glp_mpl_open_input
+void open_input(MPL *mpl, char *file);
+/* open input text file */
+
+#define read_char _glp_mpl_read_char
+int read_char(MPL *mpl);
+/* read next character from input text file */
+
+#define close_input _glp_mpl_close_input
+void close_input(MPL *mpl);
+/* close input text file */
+
+#define open_output _glp_mpl_open_output
+void open_output(MPL *mpl, char *file);
+/* open output text file */
+
+#define write_char _glp_mpl_write_char
+void write_char(MPL *mpl, int c);
+/* write next character to output text file */
+
+#define write_text _glp_mpl_write_text
+void write_text(MPL *mpl, char *fmt, ...);
+/* format and write text to output text file */
+
+#define flush_output _glp_mpl_flush_output
+void flush_output(MPL *mpl);
+/* finalize writing data to output text file */
+
+/**********************************************************************/
+/* * *                      SOLVER INTERFACE                      * * */
+/**********************************************************************/
+
+#define MPL_FR          401   /* free (unbounded) */
+#define MPL_LO          402   /* lower bound */
+#define MPL_UP          403   /* upper bound */
+#define MPL_DB          404   /* both lower and upper bounds */
+#define MPL_FX          405   /* fixed */
+
+#define MPL_ST          411   /* constraint */
+#define MPL_MIN         412   /* objective (minimization) */
+#define MPL_MAX         413   /* objective (maximization) */
+
+#define MPL_NUM         421   /* continuous */
+#define MPL_INT         422   /* integer */
+#define MPL_BIN         423   /* binary */
+
+#define error _glp_mpl_error
+void error(MPL *mpl, char *fmt, ...);
+/* print error message and terminate model processing */
+
+#define warning _glp_mpl_warning
+void warning(MPL *mpl, char *fmt, ...);
+/* print warning message and continue model processing */
+
+#define mpl_initialize _glp_mpl_initialize
+MPL *mpl_initialize(void);
+/* create and initialize translator database */
+
+#define mpl_read_model _glp_mpl_read_model
+int mpl_read_model(MPL *mpl, char *file, int skip_data);
+/* read model section and optional data section */
+
+#define mpl_read_data _glp_mpl_read_data
+int mpl_read_data(MPL *mpl, char *file);
+/* read data section */
+
+#define mpl_generate _glp_mpl_generate
+int mpl_generate(MPL *mpl, char *file);
+/* generate model */
+
+#define mpl_get_prob_name _glp_mpl_get_prob_name
+char *mpl_get_prob_name(MPL *mpl);
+/* obtain problem (model) name */
+
+#define mpl_get_num_rows _glp_mpl_get_num_rows
+int mpl_get_num_rows(MPL *mpl);
+/* determine number of rows */
+
+#define mpl_get_num_cols _glp_mpl_get_num_cols
+int mpl_get_num_cols(MPL *mpl);
+/* determine number of columns */
+
+#define mpl_get_row_name _glp_mpl_get_row_name
+char *mpl_get_row_name(MPL *mpl, int i);
+/* obtain row name */
+
+#define mpl_get_row_kind _glp_mpl_get_row_kind
+int mpl_get_row_kind(MPL *mpl, int i);
+/* determine row kind */
+
+#define mpl_get_row_bnds _glp_mpl_get_row_bnds
+int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
+/* obtain row bounds */
+
+#define mpl_get_mat_row _glp_mpl_get_mat_row
+int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
+/* obtain row of the constraint matrix */
+
+#define mpl_get_row_c0 _glp_mpl_get_row_c0
+double mpl_get_row_c0(MPL *mpl, int i);
+/* obtain constant term of free row */
+
+#define mpl_get_col_name _glp_mpl_get_col_name
+char *mpl_get_col_name(MPL *mpl, int j);
+/* obtain column name */
+
+#define mpl_get_col_kind _glp_mpl_get_col_kind
+int mpl_get_col_kind(MPL *mpl, int j);
+/* determine column kind */
+
+#define mpl_get_col_bnds _glp_mpl_get_col_bnds
+int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
+/* obtain column bounds */
+
+#define mpl_has_solve_stmt _glp_mpl_has_solve_stmt
+int mpl_has_solve_stmt(MPL *mpl);
+/* check if model has solve statement */
+
+#if 1 /* 15/V-2010 */
+#define mpl_put_row_soln _glp_mpl_put_row_soln
+void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
+      double dual);
+/* store row (constraint/objective) solution components */
+#endif
+
+#if 1 /* 15/V-2010 */
+#define mpl_put_col_soln _glp_mpl_put_col_soln
+void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
+      double dual);
+/* store column (variable) solution components */
+#endif
+
+#if 0 /* 15/V-2010 */
+#define mpl_put_col_value _glp_mpl_put_col_value
+void mpl_put_col_value(MPL *mpl, int j, double val);
+/* store column value */
+#endif
+
+#define mpl_postsolve _glp_mpl_postsolve
+int mpl_postsolve(MPL *mpl);
+/* postsolve model */
+
+#define mpl_terminate _glp_mpl_terminate
+void mpl_terminate(MPL *mpl);
+/* free all resources used by translator */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpmpl01.c b/optional/glpk/glpmpl01.c
new file mode 100644
index 0000000..cb70d65
--- /dev/null
+++ b/optional/glpk/glpmpl01.c
@@ -0,0 +1,4721 @@
+/* glpmpl01.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#define _GLPSTD_STDIO
+#include "glpmpl.h"
+#define dmp_get_atomv dmp_get_atom
+
+/**********************************************************************/
+/* * *                  PROCESSING MODEL SECTION                  * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- enter_context - enter current token into context queue.
+--
+-- This routine enters the current token into the context queue. */
+
+void enter_context(MPL *mpl)
+{     char *image, *s;
+      if (mpl->token == T_EOF)
+         image = "_|_";
+      else if (mpl->token == T_STRING)
+         image = "'...'";
+      else
+         image = mpl->image;
+      xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
+      mpl->context[mpl->c_ptr++] = ' ';
+      if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
+      for (s = image; *s != '\0'; s++)
+      {  mpl->context[mpl->c_ptr++] = *s;
+         if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- print_context - print current content of context queue.
+--
+-- This routine prints current content of the context queue. */
+
+void print_context(MPL *mpl)
+{     int c;
+      while (mpl->c_ptr > 0)
+      {  mpl->c_ptr--;
+         c = mpl->context[0];
+         memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
+         mpl->context[CONTEXT_SIZE-1] = (char)c;
+      }
+      xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
+         CONTEXT_SIZE, mpl->context);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- get_char - scan next character from input text file.
+--
+-- This routine scans a next ASCII character from the input text file.
+-- In case of end-of-file, the character is assigned EOF. */
+
+void get_char(MPL *mpl)
+{     int c;
+      if (mpl->c == EOF) goto done;
+      if (mpl->c == '\n') mpl->line++;
+      c = read_char(mpl);
+      if (c == EOF)
+      {  if (mpl->c == '\n')
+            mpl->line--;
+         else
+            warning(mpl, "final NL missing before end of file");
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+      {  enter_context(mpl);
+         error(mpl, "control character 0x%02X not allowed", c);
+      }
+      mpl->c = c;
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- append_char - append character to current token.
+--
+-- This routine appends the current character to the current token and
+-- then scans a next character. */
+
+void append_char(MPL *mpl)
+{     xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
+      if (mpl->imlen == MAX_LENGTH)
+      {  switch (mpl->token)
+         {  case T_NAME:
+               enter_context(mpl);
+               error(mpl, "symbolic name %s... too long", mpl->image);
+            case T_SYMBOL:
+               enter_context(mpl);
+               error(mpl, "symbol %s... too long", mpl->image);
+            case T_NUMBER:
+               enter_context(mpl);
+               error(mpl, "numeric literal %s... too long", mpl->image);
+            case T_STRING:
+               enter_context(mpl);
+               error(mpl, "string literal too long");
+            default:
+               xassert(mpl != mpl);
+         }
+      }
+      mpl->image[mpl->imlen++] = (char)mpl->c;
+      mpl->image[mpl->imlen] = '\0';
+      get_char(mpl);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- get_token - scan next token from input text file.
+--
+-- This routine scans a next token from the input text file using the
+-- standard finite automation technique. */
+
+void get_token(MPL *mpl)
+{     /* save the current token */
+      mpl->b_token = mpl->token;
+      mpl->b_imlen = mpl->imlen;
+      strcpy(mpl->b_image, mpl->image);
+      mpl->b_value = mpl->value;
+      /* if the next token is already scanned, make it current */
+      if (mpl->f_scan)
+      {  mpl->f_scan = 0;
+         mpl->token = mpl->f_token;
+         mpl->imlen = mpl->f_imlen;
+         strcpy(mpl->image, mpl->f_image);
+         mpl->value = mpl->f_value;
+         goto done;
+      }
+loop: /* nothing has been scanned so far */
+      mpl->token = 0;
+      mpl->imlen = 0;
+      mpl->image[0] = '\0';
+      mpl->value = 0.0;
+      /* skip any uninteresting characters */
+      while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
+      /* recognize and construct the token */
+      if (mpl->c == EOF)
+      {  /* end-of-file reached */
+         mpl->token = T_EOF;
+      }
+      else if (mpl->c == '#')
+      {  /* comment; skip anything until end-of-line */
+         while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
+         goto loop;
+      }
+      else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
+      {  /* symbolic name or reserved keyword */
+         mpl->token = T_NAME;
+         while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
+         if (strcmp(mpl->image, "and") == 0)
+            mpl->token = T_AND;
+         else if (strcmp(mpl->image, "by") == 0)
+            mpl->token = T_BY;
+         else if (strcmp(mpl->image, "cross") == 0)
+            mpl->token = T_CROSS;
+         else if (strcmp(mpl->image, "diff") == 0)
+            mpl->token = T_DIFF;
+         else if (strcmp(mpl->image, "div") == 0)
+            mpl->token = T_DIV;
+         else if (strcmp(mpl->image, "else") == 0)
+            mpl->token = T_ELSE;
+         else if (strcmp(mpl->image, "if") == 0)
+            mpl->token = T_IF;
+         else if (strcmp(mpl->image, "in") == 0)
+            mpl->token = T_IN;
+#if 1 /* 21/VII-2006 */
+         else if (strcmp(mpl->image, "Infinity") == 0)
+            mpl->token = T_INFINITY;
+#endif
+         else if (strcmp(mpl->image, "inter") == 0)
+            mpl->token = T_INTER;
+         else if (strcmp(mpl->image, "less") == 0)
+            mpl->token = T_LESS;
+         else if (strcmp(mpl->image, "mod") == 0)
+            mpl->token = T_MOD;
+         else if (strcmp(mpl->image, "not") == 0)
+            mpl->token = T_NOT;
+         else if (strcmp(mpl->image, "or") == 0)
+            mpl->token = T_OR;
+         else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
+         {  mpl->token = T_SPTP;
+            append_char(mpl);
+            if (mpl->c != 't')
+sptp:       {  enter_context(mpl);
+               error(mpl, "keyword s.t. incomplete");
+            }
+            append_char(mpl);
+            if (mpl->c != '.') goto sptp;
+            append_char(mpl);
+         }
+         else if (strcmp(mpl->image, "symdiff") == 0)
+            mpl->token = T_SYMDIFF;
+         else if (strcmp(mpl->image, "then") == 0)
+            mpl->token = T_THEN;
+         else if (strcmp(mpl->image, "union") == 0)
+            mpl->token = T_UNION;
+         else if (strcmp(mpl->image, "within") == 0)
+            mpl->token = T_WITHIN;
+      }
+      else if (!mpl->flag_d && isdigit(mpl->c))
+      {  /* numeric literal */
+         mpl->token = T_NUMBER;
+         /* scan integer part */
+         while (isdigit(mpl->c)) append_char(mpl);
+         /* scan optional fractional part */
+         if (mpl->c == '.')
+         {  append_char(mpl);
+            if (mpl->c == '.')
+            {  /* hmm, it is not the fractional part, it is dots that
+                  follow the integer part */
+               mpl->imlen--;
+               mpl->image[mpl->imlen] = '\0';
+               mpl->f_dots = 1;
+               goto conv;
+            }
+frac:       while (isdigit(mpl->c)) append_char(mpl);
+         }
+         /* scan optional decimal exponent */
+         if (mpl->c == 'e' || mpl->c == 'E')
+         {  append_char(mpl);
+            if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
+            if (!isdigit(mpl->c))
+            {  enter_context(mpl);
+               error(mpl, "numeric literal %s incomplete", mpl->image);
+            }
+            while (isdigit(mpl->c)) append_char(mpl);
+         }
+         /* there must be no letter following the numeric literal */
+         if (isalpha(mpl->c) || mpl->c == '_')
+         {  enter_context(mpl);
+            error(mpl, "symbol %s%c... should be enclosed in quotes",
+               mpl->image, mpl->c);
+         }
+conv:    /* convert numeric literal to floating-point */
+         if (str2num(mpl->image, &mpl->value))
+err:     {  enter_context(mpl);
+            error(mpl, "cannot convert numeric literal %s to floating-p"
+               "oint number", mpl->image);
+         }
+      }
+      else if (mpl->c == '\'' || mpl->c == '"')
+      {  /* character string */
+         int quote = mpl->c;
+         mpl->token = T_STRING;
+         get_char(mpl);
+         for (;;)
+         {  if (mpl->c == '\n' || mpl->c == EOF)
+            {  enter_context(mpl);
+               error(mpl, "unexpected end of line; string literal incom"
+                  "plete");
+            }
+            if (mpl->c == quote)
+            {  get_char(mpl);
+               if (mpl->c != quote) break;
+            }
+            append_char(mpl);
+         }
+      }
+      else if (!mpl->flag_d && mpl->c == '+')
+         mpl->token = T_PLUS, append_char(mpl);
+      else if (!mpl->flag_d && mpl->c == '-')
+         mpl->token = T_MINUS, append_char(mpl);
+      else if (mpl->c == '*')
+      {  mpl->token = T_ASTERISK, append_char(mpl);
+         if (mpl->c == '*')
+            mpl->token = T_POWER, append_char(mpl);
+      }
+      else if (mpl->c == '/')
+      {  mpl->token = T_SLASH, append_char(mpl);
+         if (mpl->c == '*')
+         {  /* comment sequence */
+            get_char(mpl);
+            for (;;)
+            {  if (mpl->c == EOF)
+               {  /* do not call enter_context at this point */
+                  error(mpl, "unexpected end of file; comment sequence "
+                     "incomplete");
+               }
+               else if (mpl->c == '*')
+               {  get_char(mpl);
+                  if (mpl->c == '/') break;
+               }
+               else
+                  get_char(mpl);
+            }
+            get_char(mpl);
+            goto loop;
+         }
+      }
+      else if (mpl->c == '^')
+         mpl->token = T_POWER, append_char(mpl);
+      else if (mpl->c == '<')
+      {  mpl->token = T_LT, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_LE, append_char(mpl);
+         else if (mpl->c == '>')
+            mpl->token = T_NE, append_char(mpl);
+#if 1 /* 11/II-2008 */
+         else if (mpl->c == '-')
+            mpl->token = T_INPUT, append_char(mpl);
+#endif
+      }
+      else if (mpl->c == '=')
+      {  mpl->token = T_EQ, append_char(mpl);
+         if (mpl->c == '=') append_char(mpl);
+      }
+      else if (mpl->c == '>')
+      {  mpl->token = T_GT, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_GE, append_char(mpl);
+#if 1 /* 14/VII-2006 */
+         else if (mpl->c == '>')
+            mpl->token = T_APPEND, append_char(mpl);
+#endif
+      }
+      else if (mpl->c == '!')
+      {  mpl->token = T_NOT, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_NE, append_char(mpl);
+      }
+      else if (mpl->c == '&')
+      {  mpl->token = T_CONCAT, append_char(mpl);
+         if (mpl->c == '&')
+            mpl->token = T_AND, append_char(mpl);
+      }
+      else if (mpl->c == '|')
+      {  mpl->token = T_BAR, append_char(mpl);
+         if (mpl->c == '|')
+            mpl->token = T_OR, append_char(mpl);
+      }
+      else if (!mpl->flag_d && mpl->c == '.')
+      {  mpl->token = T_POINT, append_char(mpl);
+         if (mpl->f_dots)
+         {  /* dots; the first dot was read on the previous call to the
+               scanner, so the current character is the second dot */
+            mpl->token = T_DOTS;
+            mpl->imlen = 2;
+            strcpy(mpl->image, "..");
+            mpl->f_dots = 0;
+         }
+         else if (mpl->c == '.')
+            mpl->token = T_DOTS, append_char(mpl);
+         else if (isdigit(mpl->c))
+         {  /* numeric literal that begins with the decimal point */
+            mpl->token = T_NUMBER, append_char(mpl);
+            goto frac;
+         }
+      }
+      else if (mpl->c == ',')
+         mpl->token = T_COMMA, append_char(mpl);
+      else if (mpl->c == ':')
+      {  mpl->token = T_COLON, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_ASSIGN, append_char(mpl);
+      }
+      else if (mpl->c == ';')
+         mpl->token = T_SEMICOLON, append_char(mpl);
+      else if (mpl->c == '(')
+         mpl->token = T_LEFT, append_char(mpl);
+      else if (mpl->c == ')')
+         mpl->token = T_RIGHT, append_char(mpl);
+      else if (mpl->c == '[')
+         mpl->token = T_LBRACKET, append_char(mpl);
+      else if (mpl->c == ']')
+         mpl->token = T_RBRACKET, append_char(mpl);
+      else if (mpl->c == '{')
+         mpl->token = T_LBRACE, append_char(mpl);
+      else if (mpl->c == '}')
+         mpl->token = T_RBRACE, append_char(mpl);
+#if 1 /* 11/II-2008 */
+      else if (mpl->c == '~')
+         mpl->token = T_TILDE, append_char(mpl);
+#endif
+      else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
+      {  /* symbol */
+         xassert(mpl->flag_d);
+         mpl->token = T_SYMBOL;
+         while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
+            append_char(mpl);
+         switch (str2num(mpl->image, &mpl->value))
+         {  case 0:
+               mpl->token = T_NUMBER;
+               break;
+            case 1:
+               goto err;
+            case 2:
+               break;
+            default:
+               xassert(mpl != mpl);
+         }
+      }
+      else
+      {  enter_context(mpl);
+         error(mpl, "character %c not allowed", mpl->c);
+      }
+      /* enter the current token into the context queue */
+      enter_context(mpl);
+      /* reset the flag, which may be set by indexing_expression() and
+         is used by expression_list() */
+      mpl->flag_x = 0;
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- unget_token - return current token back to input stream.
+--
+-- This routine returns the current token back to the input stream, so
+-- the previously scanned token becomes the current one. */
+
+void unget_token(MPL *mpl)
+{     /* save the current token, which becomes the next one */
+      xassert(!mpl->f_scan);
+      mpl->f_scan = 1;
+      mpl->f_token = mpl->token;
+      mpl->f_imlen = mpl->imlen;
+      strcpy(mpl->f_image, mpl->image);
+      mpl->f_value = mpl->value;
+      /* restore the previous token, which becomes the current one */
+      mpl->token = mpl->b_token;
+      mpl->imlen = mpl->b_imlen;
+      strcpy(mpl->image, mpl->b_image);
+      mpl->value = mpl->b_value;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- is_keyword - check if current token is given non-reserved keyword.
+--
+-- If the current token is given (non-reserved) keyword, this routine
+-- returns non-zero. Otherwise zero is returned. */
+
+int is_keyword(MPL *mpl, char *keyword)
+{     return
+         mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
+}
+
+/*----------------------------------------------------------------------
+-- is_reserved - check if current token is reserved keyword.
+--
+-- If the current token is a reserved keyword, this routine returns
+-- non-zero. Otherwise zero is returned. */
+
+int is_reserved(MPL *mpl)
+{     return
+         mpl->token == T_AND && mpl->image[0] == 'a' ||
+         mpl->token == T_BY ||
+         mpl->token == T_CROSS ||
+         mpl->token == T_DIFF ||
+         mpl->token == T_DIV ||
+         mpl->token == T_ELSE ||
+         mpl->token == T_IF ||
+         mpl->token == T_IN ||
+         mpl->token == T_INTER ||
+         mpl->token == T_LESS ||
+         mpl->token == T_MOD ||
+         mpl->token == T_NOT && mpl->image[0] == 'n' ||
+         mpl->token == T_OR && mpl->image[0] == 'o' ||
+         mpl->token == T_SYMDIFF ||
+         mpl->token == T_THEN ||
+         mpl->token == T_UNION ||
+         mpl->token == T_WITHIN;
+}
+
+/*----------------------------------------------------------------------
+-- make_code - generate pseudo-code (basic routine).
+--
+-- This routine generates specified pseudo-code. It is assumed that all
+-- other translator routines use this basic routine. */
+
+CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
+{     CODE *code;
+      DOMAIN *domain;
+      DOMAIN_BLOCK *block;
+      ARG_LIST *e;
+      /* generate pseudo-code */
+      code = alloc(CODE);
+      code->op = op;
+      code->vflag = 0; /* is inherited from operand(s) */
+      /* copy operands and also make them referring to the pseudo-code
+         being generated, because the latter becomes the parent for all
+         its operands */
+      memset(&code->arg, '?', sizeof(OPERANDS));
+      switch (op)
+      {  case O_NUMBER:
+            code->arg.num = arg->num;
+            break;
+         case O_STRING:
+            code->arg.str = arg->str;
+            break;
+         case O_INDEX:
+            code->arg.index.slot = arg->index.slot;
+            code->arg.index.next = arg->index.next;
+            break;
+         case O_MEMNUM:
+         case O_MEMSYM:
+            for (e = arg->par.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.par.par = arg->par.par;
+            code->arg.par.list = arg->par.list;
+            break;
+         case O_MEMSET:
+            for (e = arg->set.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.set.set = arg->set.set;
+            code->arg.set.list = arg->set.list;
+            break;
+         case O_MEMVAR:
+            for (e = arg->var.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.var.var = arg->var.var;
+            code->arg.var.list = arg->var.list;
+#if 1 /* 15/V-2010 */
+            code->arg.var.suff = arg->var.suff;
+#endif
+            break;
+#if 1 /* 15/V-2010 */
+         case O_MEMCON:
+            for (e = arg->con.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.con.con = arg->con.con;
+            code->arg.con.list = arg->con.list;
+            code->arg.con.suff = arg->con.suff;
+            break;
+#endif
+         case O_TUPLE:
+         case O_MAKE:
+            for (e = arg->list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.list = arg->list;
+            break;
+         case O_SLICE:
+            xassert(arg->slice != NULL);
+            code->arg.slice = arg->slice;
+            break;
+         case O_IRAND224:
+         case O_UNIFORM01:
+         case O_NORMAL01:
+         case O_GMTIME:
+            code->vflag = 1;
+            break;
+         case O_CVTNUM:
+         case O_CVTSYM:
+         case O_CVTLOG:
+         case O_CVTTUP:
+         case O_CVTLFM:
+         case O_PLUS:
+         case O_MINUS:
+         case O_NOT:
+         case O_ABS:
+         case O_CEIL:
+         case O_FLOOR:
+         case O_EXP:
+         case O_LOG:
+         case O_LOG10:
+         case O_SQRT:
+         case O_SIN:
+         case O_COS:
+         case O_ATAN:
+         case O_ROUND:
+         case O_TRUNC:
+         case O_CARD:
+         case O_LENGTH:
+            /* unary operation */
+            xassert(arg->arg.x != NULL);
+            xassert(arg->arg.x->up == NULL);
+            arg->arg.x->up = code;
+            code->vflag |= arg->arg.x->vflag;
+            code->arg.arg.x = arg->arg.x;
+            break;
+         case O_ADD:
+         case O_SUB:
+         case O_LESS:
+         case O_MUL:
+         case O_DIV:
+         case O_IDIV:
+         case O_MOD:
+         case O_POWER:
+         case O_ATAN2:
+         case O_ROUND2:
+         case O_TRUNC2:
+         case O_UNIFORM:
+            if (op == O_UNIFORM) code->vflag = 1;
+         case O_NORMAL:
+            if (op == O_NORMAL) code->vflag = 1;
+         case O_CONCAT:
+         case O_LT:
+         case O_LE:
+         case O_EQ:
+         case O_GE:
+         case O_GT:
+         case O_NE:
+         case O_AND:
+         case O_OR:
+         case O_UNION:
+         case O_DIFF:
+         case O_SYMDIFF:
+         case O_INTER:
+         case O_CROSS:
+         case O_IN:
+         case O_NOTIN:
+         case O_WITHIN:
+         case O_NOTWITHIN:
+         case O_SUBSTR:
+         case O_STR2TIME:
+         case O_TIME2STR:
+            /* binary operation */
+            xassert(arg->arg.x != NULL);
+            xassert(arg->arg.x->up == NULL);
+            arg->arg.x->up = code;
+            code->vflag |= arg->arg.x->vflag;
+            xassert(arg->arg.y != NULL);
+            xassert(arg->arg.y->up == NULL);
+            arg->arg.y->up = code;
+            code->vflag |= arg->arg.y->vflag;
+            code->arg.arg.x = arg->arg.x;
+            code->arg.arg.y = arg->arg.y;
+            break;
+         case O_DOTS:
+         case O_FORK:
+         case O_SUBSTR3:
+            /* ternary operation */
+            xassert(arg->arg.x != NULL);
+            xassert(arg->arg.x->up == NULL);
+            arg->arg.x->up = code;
+            code->vflag |= arg->arg.x->vflag;
+            xassert(arg->arg.y != NULL);
+            xassert(arg->arg.y->up == NULL);
+            arg->arg.y->up = code;
+            code->vflag |= arg->arg.y->vflag;
+            if (arg->arg.z != NULL)
+            {  xassert(arg->arg.z->up == NULL);
+               arg->arg.z->up = code;
+               code->vflag |= arg->arg.z->vflag;
+            }
+            code->arg.arg.x = arg->arg.x;
+            code->arg.arg.y = arg->arg.y;
+            code->arg.arg.z = arg->arg.z;
+            break;
+         case O_MIN:
+         case O_MAX:
+            /* n-ary operation */
+            for (e = arg->list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.list = arg->list;
+            break;
+         case O_SUM:
+         case O_PROD:
+         case O_MINIMUM:
+         case O_MAXIMUM:
+         case O_FORALL:
+         case O_EXISTS:
+         case O_SETOF:
+         case O_BUILD:
+            /* iterated operation */
+            domain = arg->loop.domain;
+            xassert(domain != NULL);
+            if (domain->code != NULL)
+            {  xassert(domain->code->up == NULL);
+               domain->code->up = code;
+               code->vflag |= domain->code->vflag;
+            }
+            for (block = domain->list; block != NULL; block =
+               block->next)
+            {  xassert(block->code != NULL);
+               xassert(block->code->up == NULL);
+               block->code->up = code;
+               code->vflag |= block->code->vflag;
+            }
+            if (arg->loop.x != NULL)
+            {  xassert(arg->loop.x->up == NULL);
+               arg->loop.x->up = code;
+               code->vflag |= arg->loop.x->vflag;
+            }
+            code->arg.loop.domain = arg->loop.domain;
+            code->arg.loop.x = arg->loop.x;
+            break;
+         default:
+            xassert(op != op);
+      }
+      /* set other attributes of the pseudo-code */
+      code->type = type;
+      code->dim = dim;
+      code->up = NULL;
+      code->valid = 0;
+      memset(&code->value, '?', sizeof(VALUE));
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_unary - generate pseudo-code for unary operation.
+--
+-- This routine generates pseudo-code for unary operation. */
+
+CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(x != NULL);
+      arg.arg.x = x;
+      code = make_code(mpl, op, &arg, type, dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_binary - generate pseudo-code for binary operation.
+--
+-- This routine generates pseudo-code for binary operation. */
+
+CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
+      int dim)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(x != NULL);
+      xassert(y != NULL);
+      arg.arg.x = x;
+      arg.arg.y = y;
+      code = make_code(mpl, op, &arg, type, dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_ternary - generate pseudo-code for ternary operation.
+--
+-- This routine generates pseudo-code for ternary operation. */
+
+CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
+      int type, int dim)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(x != NULL);
+      xassert(y != NULL);
+      /* third operand can be NULL */
+      arg.arg.x = x;
+      arg.arg.y = y;
+      arg.arg.z = z;
+      code = make_code(mpl, op, &arg, type, dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- numeric_literal - parse reference to numeric literal.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <numeric literal> */
+
+CODE *numeric_literal(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(mpl->token == T_NUMBER);
+      arg.num = mpl->value;
+      code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
+      get_token(mpl /* <numeric literal> */);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- string_literal - parse reference to string literal.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <string literal> */
+
+CODE *string_literal(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(mpl->token == T_STRING);
+      arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(arg.str, mpl->image);
+      code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
+      get_token(mpl /* <string literal> */);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- create_arg_list - create empty operands list.
+--
+-- This routine creates operands list, which is initially empty. */
+
+ARG_LIST *create_arg_list(MPL *mpl)
+{     ARG_LIST *list;
+      xassert(mpl == mpl);
+      list = NULL;
+      return list;
+}
+
+/*----------------------------------------------------------------------
+-- expand_arg_list - append operand to operands list.
+--
+-- This routine appends new operand to specified operands list. */
+
+ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
+{     ARG_LIST *tail, *temp;
+      xassert(x != NULL);
+      /* create new operands list entry */
+      tail = alloc(ARG_LIST);
+      tail->x = x;
+      tail->next = NULL;
+      /* and append it to the operands list */
+      if (list == NULL)
+         list = tail;
+      else
+      {  for (temp = list; temp->next != NULL; temp = temp->next);
+         temp->next = tail;
+      }
+      return list;
+}
+
+/*----------------------------------------------------------------------
+-- arg_list_len - determine length of operands list.
+--
+-- This routine returns the number of operands in operands list. */
+
+int arg_list_len(MPL *mpl, ARG_LIST *list)
+{     ARG_LIST *temp;
+      int len;
+      xassert(mpl == mpl);
+      len = 0;
+      for (temp = list; temp != NULL; temp = temp->next) len++;
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- subscript_list - parse subscript list.
+--
+-- This routine parses subscript list using the syntax:
+--
+-- <subscript list> ::= <subscript>
+-- <subscript list> ::= <subscript list> , <subscript>
+-- <subscript> ::= <expression 5> */
+
+ARG_LIST *subscript_list(MPL *mpl)
+{     ARG_LIST *list;
+      CODE *x;
+      list = create_arg_list(mpl);
+      for (;;)
+      {  /* parse subscript expression */
+         x = expression_5(mpl);
+         /* convert it to symbolic type, if necessary */
+         if (x->type == A_NUMERIC)
+            x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+         /* check that now the expression is of symbolic type */
+         if (x->type != A_SYMBOLIC)
+            error(mpl, "subscript expression has invalid type");
+         xassert(x->dim == 0);
+         /* and append it to the subscript list */
+         list = expand_arg_list(mpl, list, x);
+         /* check a token that follows the subscript expression */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RBRACKET)
+            break;
+         else
+            error(mpl, "syntax error in subscript list");
+      }
+      return list;
+}
+
+#if 1 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- object_reference - parse reference to named object.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <dummy index>
+-- <primary expression> ::= <set name>
+-- <primary expression> ::= <set name> [ <subscript list> ]
+-- <primary expression> ::= <parameter name>
+-- <primary expression> ::= <parameter name> [ <subscript list> ]
+-- <primary expression> ::= <variable name> <suffix>
+-- <primary expression> ::= <variable name> [ <subscript list> ]
+--                          <suffix>
+-- <primary expression> ::= <constraint name> <suffix>
+-- <primary expression> ::= <constraint name> [ <subscript list> ]
+--                          <suffix>
+-- <dummy index> ::= <symbolic name>
+-- <set name> ::= <symbolic name>
+-- <parameter name> ::= <symbolic name>
+-- <variable name> ::= <symbolic name>
+-- <constraint name> ::= <symbolic name>
+-- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
+
+CODE *object_reference(MPL *mpl)
+{     AVLNODE *node;
+      DOMAIN_SLOT *slot;
+      SET *set;
+      PARAMETER *par;
+      VARIABLE *var;
+      CONSTRAINT *con;
+      ARG_LIST *list;
+      OPERANDS arg;
+      CODE *code;
+      char *name;
+      int dim, suff;
+      /* find the object in the symbolic name table */
+      xassert(mpl->token == T_NAME);
+      node = avl_find_node(mpl->tree, mpl->image);
+      if (node == NULL)
+         error(mpl, "%s not defined", mpl->image);
+      /* check the object type and obtain its dimension */
+      switch (avl_get_node_type(node))
+      {  case A_INDEX:
+            /* dummy index */
+            slot = (DOMAIN_SLOT *)avl_get_node_link(node);
+            name = slot->name;
+            dim = 0;
+            break;
+         case A_SET:
+            /* model set */
+            set = (SET *)avl_get_node_link(node);
+            name = set->name;
+            dim = set->dim;
+            /* if a set object is referenced in its own declaration and
+               the dimen attribute is not specified yet, use dimen 1 by
+               default */
+            if (set->dimen == 0) set->dimen = 1;
+            break;
+         case A_PARAMETER:
+            /* model parameter */
+            par = (PARAMETER *)avl_get_node_link(node);
+            name = par->name;
+            dim = par->dim;
+            break;
+         case A_VARIABLE:
+            /* model variable */
+            var = (VARIABLE *)avl_get_node_link(node);
+            name = var->name;
+            dim = var->dim;
+            break;
+         case A_CONSTRAINT:
+            /* model constraint or objective */
+            con = (CONSTRAINT *)avl_get_node_link(node);
+            name = con->name;
+            dim = con->dim;
+            break;
+         default:
+            xassert(node != node);
+      }
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional subscript list */
+      if (mpl->token == T_LBRACKET)
+      {  /* subscript list is specified */
+         if (dim == 0)
+            error(mpl, "%s cannot be subscripted", name);
+         get_token(mpl /* [ */);
+         list = subscript_list(mpl);
+         if (dim != arg_list_len(mpl, list))
+            error(mpl, "%s must have %d subscript%s rather than %d",
+               name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
+         xassert(mpl->token == T_RBRACKET);
+         get_token(mpl /* ] */);
+      }
+      else
+      {  /* subscript list is not specified */
+         if (dim != 0)
+            error(mpl, "%s must be subscripted", name);
+         list = create_arg_list(mpl);
+      }
+      /* parse optional suffix */
+      if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
+         suff = DOT_NONE;
+      else
+         suff = DOT_VAL;
+      if (mpl->token == T_POINT)
+      {  get_token(mpl /* . */);
+         if (mpl->token != T_NAME)
+            error(mpl, "invalid use of period");
+         if (!(avl_get_node_type(node) == A_VARIABLE ||
+               avl_get_node_type(node) == A_CONSTRAINT))
+            error(mpl, "%s cannot have a suffix", name);
+         if (strcmp(mpl->image, "lb") == 0)
+            suff = DOT_LB;
+         else if (strcmp(mpl->image, "ub") == 0)
+            suff = DOT_UB;
+         else if (strcmp(mpl->image, "status") == 0)
+            suff = DOT_STATUS;
+         else if (strcmp(mpl->image, "val") == 0)
+            suff = DOT_VAL;
+         else if (strcmp(mpl->image, "dual") == 0)
+            suff = DOT_DUAL;
+         else
+            error(mpl, "suffix .%s invalid", mpl->image);
+         get_token(mpl /* suffix */);
+      }
+      /* generate pseudo-code to take value of the object */
+      switch (avl_get_node_type(node))
+      {  case A_INDEX:
+            arg.index.slot = slot;
+            arg.index.next = slot->list;
+            code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
+            slot->list = code;
+            break;
+         case A_SET:
+            arg.set.set = set;
+            arg.set.list = list;
+            code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
+               set->dimen);
+            break;
+         case A_PARAMETER:
+            arg.par.par = par;
+            arg.par.list = list;
+            if (par->type == A_SYMBOLIC)
+               code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
+            else
+               code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
+            break;
+         case A_VARIABLE:
+            if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
+               || suff == DOT_DUAL))
+               error(mpl, "invalid reference to status, primal value, o"
+                  "r dual value of variable %s above solve statement",
+                  var->name);
+            arg.var.var = var;
+            arg.var.list = list;
+            arg.var.suff = suff;
+            code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
+               A_FORMULA : A_NUMERIC, 0);
+            break;
+         case A_CONSTRAINT:
+            if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
+               || suff == DOT_DUAL))
+               error(mpl, "invalid reference to status, primal value, o"
+                  "r dual value of %s %s above solve statement",
+                  con->type == A_CONSTRAINT ? "constraint" : "objective"
+                  , con->name);
+            arg.con.con = con;
+            arg.con.list = list;
+            arg.con.suff = suff;
+            code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
+            break;
+         default:
+            xassert(node != node);
+      }
+      return code;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- numeric_argument - parse argument passed to built-in function.
+--
+-- This routine parses an argument passed to numeric built-in function
+-- using the syntax:
+--
+-- <arg> ::= <expression 5> */
+
+CODE *numeric_argument(MPL *mpl, char *func)
+{     CODE *x;
+      x = expression_5(mpl);
+      /* convert the argument to numeric type, if necessary */
+      if (x->type == A_SYMBOLIC)
+         x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+      /* check that now the argument is of numeric type */
+      if (x->type != A_NUMERIC)
+         error(mpl, "argument for %s has invalid type", func);
+      xassert(x->dim == 0);
+      return x;
+}
+
+#if 1 /* 15/VII-2006 */
+CODE *symbolic_argument(MPL *mpl, char *func)
+{     CODE *x;
+      x = expression_5(mpl);
+      /* convert the argument to symbolic type, if necessary */
+      if (x->type == A_NUMERIC)
+         x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+      /* check that now the argument is of symbolic type */
+      if (x->type != A_SYMBOLIC)
+         error(mpl, "argument for %s has invalid type", func);
+      xassert(x->dim == 0);
+      return x;
+}
+#endif
+
+#if 1 /* 15/VII-2006 */
+CODE *elemset_argument(MPL *mpl, char *func)
+{     CODE *x;
+      x = expression_9(mpl);
+      if (x->type != A_ELEMSET)
+         error(mpl, "argument for %s has invalid type", func);
+      xassert(x->dim > 0);
+      return x;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- function_reference - parse reference to built-in function.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= abs ( <arg> )
+-- <primary expression> ::= ceil ( <arg> )
+-- <primary expression> ::= floor ( <arg> )
+-- <primary expression> ::= exp ( <arg> )
+-- <primary expression> ::= log ( <arg> )
+-- <primary expression> ::= log10 ( <arg> )
+-- <primary expression> ::= max ( <arg list> )
+-- <primary expression> ::= min ( <arg list> )
+-- <primary expression> ::= sqrt ( <arg> )
+-- <primary expression> ::= sin ( <arg> )
+-- <primary expression> ::= cos ( <arg> )
+-- <primary expression> ::= atan ( <arg> )
+-- <primary expression> ::= atan2 ( <arg> , <arg> )
+-- <primary expression> ::= round ( <arg> )
+-- <primary expression> ::= round ( <arg> , <arg> )
+-- <primary expression> ::= trunc ( <arg> )
+-- <primary expression> ::= trunc ( <arg> , <arg> )
+-- <primary expression> ::= Irand224 ( )
+-- <primary expression> ::= Uniform01 ( )
+-- <primary expression> ::= Uniform ( <arg> , <arg> )
+-- <primary expression> ::= Normal01 ( )
+-- <primary expression> ::= Normal ( <arg> , <arg> )
+-- <primary expression> ::= card ( <arg> )
+-- <primary expression> ::= length ( <arg> )
+-- <primary expression> ::= substr ( <arg> , <arg> )
+-- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
+-- <primary expression> ::= str2time ( <arg> , <arg> )
+-- <primary expression> ::= time2str ( <arg> , <arg> )
+-- <primary expression> ::= gmtime ( )
+-- <arg list> ::= <arg>
+-- <arg list> ::= <arg list> , <arg> */
+
+CODE *function_reference(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      int op;
+      char func[15+1];
+      /* determine operation code */
+      xassert(mpl->token == T_NAME);
+      if (strcmp(mpl->image, "abs") == 0)
+         op = O_ABS;
+      else if (strcmp(mpl->image, "ceil") == 0)
+         op = O_CEIL;
+      else if (strcmp(mpl->image, "floor") == 0)
+         op = O_FLOOR;
+      else if (strcmp(mpl->image, "exp") == 0)
+         op = O_EXP;
+      else if (strcmp(mpl->image, "log") == 0)
+         op = O_LOG;
+      else if (strcmp(mpl->image, "log10") == 0)
+         op = O_LOG10;
+      else if (strcmp(mpl->image, "sqrt") == 0)
+         op = O_SQRT;
+      else if (strcmp(mpl->image, "sin") == 0)
+         op = O_SIN;
+      else if (strcmp(mpl->image, "cos") == 0)
+         op = O_COS;
+      else if (strcmp(mpl->image, "atan") == 0)
+         op = O_ATAN;
+      else if (strcmp(mpl->image, "min") == 0)
+         op = O_MIN;
+      else if (strcmp(mpl->image, "max") == 0)
+         op = O_MAX;
+      else if (strcmp(mpl->image, "round") == 0)
+         op = O_ROUND;
+      else if (strcmp(mpl->image, "trunc") == 0)
+         op = O_TRUNC;
+      else if (strcmp(mpl->image, "Irand224") == 0)
+         op = O_IRAND224;
+      else if (strcmp(mpl->image, "Uniform01") == 0)
+         op = O_UNIFORM01;
+      else if (strcmp(mpl->image, "Uniform") == 0)
+         op = O_UNIFORM;
+      else if (strcmp(mpl->image, "Normal01") == 0)
+         op = O_NORMAL01;
+      else if (strcmp(mpl->image, "Normal") == 0)
+         op = O_NORMAL;
+      else if (strcmp(mpl->image, "card") == 0)
+         op = O_CARD;
+      else if (strcmp(mpl->image, "length") == 0)
+         op = O_LENGTH;
+      else if (strcmp(mpl->image, "substr") == 0)
+         op = O_SUBSTR;
+      else if (strcmp(mpl->image, "str2time") == 0)
+         op = O_STR2TIME;
+      else if (strcmp(mpl->image, "time2str") == 0)
+         op = O_TIME2STR;
+      else if (strcmp(mpl->image, "gmtime") == 0)
+         op = O_GMTIME;
+      else
+         error(mpl, "function %s unknown", mpl->image);
+      /* save symbolic name of the function */
+      strcpy(func, mpl->image);
+      xassert(strlen(func) < sizeof(func));
+      get_token(mpl /* <symbolic name> */);
+      /* check the left parenthesis that follows the function name */
+      xassert(mpl->token == T_LEFT);
+      get_token(mpl /* ( */);
+      /* parse argument list */
+      if (op == O_MIN || op == O_MAX)
+      {  /* min and max allow arbitrary number of arguments */
+         arg.list = create_arg_list(mpl);
+         /* parse argument list */
+         for (;;)
+         {  /* parse argument and append it to the operands list */
+            arg.list = expand_arg_list(mpl, arg.list,
+               numeric_argument(mpl, func));
+            /* check a token that follows the argument */
+            if (mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+            else if (mpl->token == T_RIGHT)
+               break;
+            else
+               error(mpl, "syntax error in argument list for %s", func);
+         }
+      }
+      else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
+         O_NORMAL01 || op == O_GMTIME)
+      {  /* Irand224, Uniform01, Normal01, gmtime need no arguments */
+         if (mpl->token != T_RIGHT)
+            error(mpl, "%s needs no arguments", func);
+      }
+      else if (op == O_UNIFORM || op == O_NORMAL)
+      {  /* Uniform and Normal need two arguments */
+         /* parse the first argument */
+         arg.arg.x = numeric_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = numeric_argument(mpl, func);
+         /* check a token that follows the second argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
+      {  /* atan, round, and trunc need one or two arguments */
+         /* parse the first argument */
+         arg.arg.x = numeric_argument(mpl, func);
+         /* parse the second argument, if specified */
+         if (mpl->token == T_COMMA)
+         {  switch (op)
+            {  case O_ATAN:  op = O_ATAN2;  break;
+               case O_ROUND: op = O_ROUND2; break;
+               case O_TRUNC: op = O_TRUNC2; break;
+               default: xassert(op != op);
+            }
+            get_token(mpl /* , */);
+            arg.arg.y = numeric_argument(mpl, func);
+         }
+         /* check a token that follows the last argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs one or two arguments", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_SUBSTR)
+      {  /* substr needs two or three arguments */
+         /* parse the first argument */
+         arg.arg.x = symbolic_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two or three arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = numeric_argument(mpl, func);
+         /* parse the third argument, if specified */
+         if (mpl->token == T_COMMA)
+         {  op = O_SUBSTR3;
+            get_token(mpl /* , */);
+            arg.arg.z = numeric_argument(mpl, func);
+         }
+         /* check a token that follows the last argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two or three arguments", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_STR2TIME)
+      {  /* str2time needs two arguments, both symbolic */
+         /* parse the first argument */
+         arg.arg.x = symbolic_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = symbolic_argument(mpl, func);
+         /* check a token that follows the second argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_TIME2STR)
+      {  /* time2str needs two arguments, numeric and symbolic */
+         /* parse the first argument */
+         arg.arg.x = numeric_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = symbolic_argument(mpl, func);
+         /* check a token that follows the second argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else
+      {  /* other functions need one argument */
+         if (op == O_CARD)
+            arg.arg.x = elemset_argument(mpl, func);
+         else if (op == O_LENGTH)
+            arg.arg.x = symbolic_argument(mpl, func);
+         else
+            arg.arg.x = numeric_argument(mpl, func);
+         /* check a token that follows the argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs one argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      /* make pseudo-code to call the built-in function */
+      if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
+         code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
+      else
+         code = make_code(mpl, op, &arg, A_NUMERIC, 0);
+      /* the reference ends with the right parenthesis */
+      xassert(mpl->token == T_RIGHT);
+      get_token(mpl /* ) */);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- create_domain - create empty domain.
+--
+-- This routine creates empty domain, which is initially empty, i.e.
+-- has no domain blocks. */
+
+DOMAIN *create_domain(MPL *mpl)
+{     DOMAIN *domain;
+      domain = alloc(DOMAIN);
+      domain->list = NULL;
+      domain->code = NULL;
+      return domain;
+}
+
+/*----------------------------------------------------------------------
+-- create_block - create empty domain block.
+--
+-- This routine creates empty domain block, which is initially empty,
+-- i.e. has no domain slots. */
+
+DOMAIN_BLOCK *create_block(MPL *mpl)
+{     DOMAIN_BLOCK *block;
+      block = alloc(DOMAIN_BLOCK);
+      block->list = NULL;
+      block->code = NULL;
+      block->backup = NULL;
+      block->next = NULL;
+      return block;
+}
+
+/*----------------------------------------------------------------------
+-- append_block - append domain block to specified domain.
+--
+-- This routine adds given domain block to the end of the block list of
+-- specified domain. */
+
+void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
+{     DOMAIN_BLOCK *temp;
+      xassert(mpl == mpl);
+      xassert(domain != NULL);
+      xassert(block != NULL);
+      xassert(block->next == NULL);
+      if (domain->list == NULL)
+         domain->list = block;
+      else
+      {  for (temp = domain->list; temp->next != NULL; temp =
+            temp->next);
+         temp->next = block;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- append_slot - create and append new slot to domain block.
+--
+-- This routine creates new domain slot and adds it to the end of slot
+-- list of specified domain block.
+--
+-- The parameter name is symbolic name of the dummy index associated
+-- with the slot (the character string must be allocated). NULL means
+-- the dummy index is not explicitly specified.
+--
+-- The parameter code is pseudo-code for computing symbolic value, at
+-- which the dummy index is bounded. NULL means the dummy index is free
+-- in the domain scope. */
+
+DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
+      CODE *code)
+{     DOMAIN_SLOT *slot, *temp;
+      xassert(block != NULL);
+      slot = alloc(DOMAIN_SLOT);
+      slot->name = name;
+      slot->code = code;
+      slot->value = NULL;
+      slot->list = NULL;
+      slot->next = NULL;
+      if (block->list == NULL)
+         block->list = slot;
+      else
+      {  for (temp = block->list; temp->next != NULL; temp =
+            temp->next);
+         temp->next = slot;
+      }
+      return slot;
+}
+
+/*----------------------------------------------------------------------
+-- expression_list - parse expression list.
+--
+-- This routine parses a list of one or more expressions enclosed into
+-- the parentheses using the syntax:
+--
+-- <primary expression> ::= ( <expression list> )
+-- <expression list> ::= <expression 13>
+-- <expression list> ::= <expression 13> , <expression list>
+--
+-- Note that this construction may have three different meanings:
+--
+-- 1. If <expression list> consists of only one expression, <primary
+--    expression> is a parenthesized expression, which may be of any
+--    valid type (not necessarily 1-tuple).
+--
+-- 2. If <expression list> consists of several expressions separated by
+--    commae, where no expression is undeclared symbolic name, <primary
+--    expression> is a n-tuple.
+--
+-- 3. If <expression list> consists of several expressions separated by
+--    commae, where at least one expression is undeclared symbolic name
+--    (that denotes a dummy index), <primary expression> is a slice and
+--    can be only used as constituent of indexing expression. */
+
+#define max_dim 20
+/* maximal number of components allowed within parentheses */
+
+CODE *expression_list(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      struct { char *name; CODE *code; } list[1+max_dim];
+      int flag_x, next_token, dim, j, slice = 0;
+      xassert(mpl->token == T_LEFT);
+      /* the flag, which allows recognizing undeclared symbolic names
+         as dummy indices, will be automatically reset by get_token(),
+         so save it before scanning the next token */
+      flag_x = mpl->flag_x;
+      get_token(mpl /* ( */);
+      /* parse <expression list> */
+      for (dim = 1; ; dim++)
+      {  if (dim > max_dim)
+            error(mpl, "too many components within parentheses");
+         /* current component of <expression list> can be either dummy
+            index or expression */
+         if (mpl->token == T_NAME)
+         {  /* symbolic name is recognized as dummy index only if:
+               the flag, which allows that, is set, and
+               the name is followed by comma or right parenthesis, and
+               the name is undeclared */
+            get_token(mpl /* <symbolic name> */);
+            next_token = mpl->token;
+            unget_token(mpl);
+            if (!(flag_x &&
+                  (next_token == T_COMMA || next_token == T_RIGHT) &&
+                  avl_find_node(mpl->tree, mpl->image) == NULL))
+            {  /* this is not dummy index */
+               goto expr;
+            }
+            /* all dummy indices within the same slice must have unique
+               symbolic names */
+            for (j = 1; j < dim; j++)
+            {  if (list[j].name != NULL && strcmp(list[j].name,
+                  mpl->image) == 0)
+                  error(mpl, "duplicate dummy index %s not allowed",
+                     mpl->image);
+            }
+            /* current component of <expression list> is dummy index */
+            list[dim].name
+               = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+            strcpy(list[dim].name, mpl->image);
+            list[dim].code = NULL;
+            get_token(mpl /* <symbolic name> */);
+            /* <expression list> is a slice, because at least one dummy
+               index has appeared */
+            slice = 1;
+            /* note that the context ( <dummy index> ) is not allowed,
+               i.e. in this case <primary expression> is considered as
+               a parenthesized expression */
+            if (dim == 1 && mpl->token == T_RIGHT)
+               error(mpl, "%s not defined", list[dim].name);
+         }
+         else
+expr:    {  /* current component of <expression list> is expression */
+            code = expression_13(mpl);
+            /* if the current expression is followed by comma or it is
+               not the very first expression, entire <expression list>
+               is n-tuple or slice, in which case the current expression
+               should be converted to symbolic type, if necessary */
+            if (mpl->token == T_COMMA || dim > 1)
+            {  if (code->type == A_NUMERIC)
+                  code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
+               /* now the expression must be of symbolic type */
+               if (code->type != A_SYMBOLIC)
+                  error(mpl, "component expression has invalid type");
+               xassert(code->dim == 0);
+            }
+            list[dim].name = NULL;
+            list[dim].code = code;
+         }
+         /* check a token that follows the current component */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RIGHT)
+            break;
+         else
+            error(mpl, "right parenthesis missing where expected");
+      }
+      /* generate pseudo-code for <primary expression> */
+      if (dim == 1 && !slice)
+      {  /* <primary expression> is a parenthesized expression */
+         code = list[1].code;
+      }
+      else if (!slice)
+      {  /* <primary expression> is a n-tuple */
+         arg.list = create_arg_list(mpl);
+         for (j = 1; j <= dim; j++)
+            arg.list = expand_arg_list(mpl, arg.list, list[j].code);
+         code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
+      }
+      else
+      {  /* <primary expression> is a slice */
+         arg.slice = create_block(mpl);
+         for (j = 1; j <= dim; j++)
+            append_slot(mpl, arg.slice, list[j].name, list[j].code);
+         /* note that actually pseudo-codes with op = O_SLICE are never
+            evaluated */
+         code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
+      }
+      get_token(mpl /* ) */);
+      /* if <primary expression> is a slice, there must be the keyword
+         'in', which follows the right parenthesis */
+      if (slice && mpl->token != T_IN)
+         error(mpl, "keyword in missing where expected");
+      /* if the slice flag is set and there is the keyword 'in', which
+         follows <primary expression>, the latter must be a slice */
+      if (flag_x && mpl->token == T_IN && !slice)
+      {  if (dim == 1)
+            error(mpl, "syntax error in indexing expression");
+         else
+            error(mpl, "0-ary slice not allowed");
+      }
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- literal set - parse literal set.
+--
+-- This routine parses literal set using the syntax:
+--
+-- <literal set> ::= { <member list> }
+-- <member list> ::= <member expression>
+-- <member list> ::= <member list> , <member expression>
+-- <member expression> ::= <expression 5>
+--
+-- It is assumed that the left curly brace and the very first member
+-- expression that follows it are already parsed. The right curly brace
+-- remains unscanned on exit. */
+
+CODE *literal_set(MPL *mpl, CODE *code)
+{     OPERANDS arg;
+      int j;
+      xassert(code != NULL);
+      arg.list = create_arg_list(mpl);
+      /* parse <member list> */
+      for (j = 1; ; j++)
+      {  /* all member expressions must be n-tuples; so, if the current
+            expression is not n-tuple, convert it to 1-tuple */
+         if (code->type == A_NUMERIC)
+            code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
+         if (code->type == A_SYMBOLIC)
+            code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
+         /* now the expression must be n-tuple */
+         if (code->type != A_TUPLE)
+            error(mpl, "member expression has invalid type");
+         /* all member expressions must have identical dimension */
+         if (arg.list != NULL && arg.list->x->dim != code->dim)
+            error(mpl, "member %d has %d component%s while member %d ha"
+               "s %d component%s",
+               j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
+               j, code->dim, code->dim == 1 ? "" : "s");
+         /* append the current expression to the member list */
+         arg.list = expand_arg_list(mpl, arg.list, code);
+         /* check a token that follows the current expression */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RBRACE)
+            break;
+         else
+            error(mpl, "syntax error in literal set");
+         /* parse the next expression that follows the comma */
+         code = expression_5(mpl);
+      }
+      /* generate pseudo-code for <literal set> */
+      code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- indexing_expression - parse indexing expression.
+--
+-- This routine parses indexing expression using the syntax:
+--
+-- <indexing expression> ::= <literal set>
+-- <indexing expression> ::= { <indexing list> }
+-- <indexing expression> ::= { <indexing list> : <logical expression> }
+-- <indexing list> ::= <indexing element>
+-- <indexing list> ::= <indexing list> , <indexing element>
+-- <indexing element> ::= <basic expression>
+-- <indexing element> ::= <dummy index> in <basic expression>
+-- <indexing element> ::= <slice> in <basic expression>
+-- <dummy index> ::= <symbolic name>
+-- <slice> ::= ( <expression list> )
+-- <basic expression> ::= <expression 9>
+-- <logical expression> ::= <expression 13>
+--
+-- This routine creates domain for <indexing expression>, where each
+-- domain block corresponds to <indexing element>, and each domain slot
+-- corresponds to individual indexing position. */
+
+DOMAIN *indexing_expression(MPL *mpl)
+{     DOMAIN *domain;
+      DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      CODE *code;
+      xassert(mpl->token == T_LBRACE);
+      get_token(mpl /* { */);
+      if (mpl->token == T_RBRACE)
+         error(mpl, "empty indexing expression not allowed");
+      /* create domain to be constructed */
+      domain = create_domain(mpl);
+      /* parse either <member list> or <indexing list> that follows the
+         left brace */
+      for (;;)
+      {  /* domain block for <indexing element> is not created yet */
+         block = NULL;
+         /* pseudo-code for <basic expression> is not generated yet */
+         code = NULL;
+         /* check a token, which <indexing element> begins with */
+         if (mpl->token == T_NAME)
+         {  /* it is a symbolic name */
+            int next_token;
+            char *name;
+            /* symbolic name is recognized as dummy index only if it is
+               followed by the keyword 'in' and not declared */
+            get_token(mpl /* <symbolic name> */);
+            next_token = mpl->token;
+            unget_token(mpl);
+            if (!(next_token == T_IN &&
+                  avl_find_node(mpl->tree, mpl->image) == NULL))
+            {  /* this is not dummy index; the symbolic name begins an
+                  expression, which is either <basic expression> or the
+                  very first <member expression> in <literal set> */
+               goto expr;
+            }
+            /* create domain block with one slot, which is assigned the
+               dummy index */
+            block = create_block(mpl);
+            name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+            strcpy(name, mpl->image);
+            append_slot(mpl, block, name, NULL);
+            get_token(mpl /* <symbolic name> */);
+            /* the keyword 'in' is already checked above */
+            xassert(mpl->token == T_IN);
+            get_token(mpl /* in */);
+            /* <basic expression> that follows the keyword 'in' will be
+               parsed below */
+         }
+         else if (mpl->token == T_LEFT)
+         {  /* it is the left parenthesis; parse expression that begins
+               with this parenthesis (the flag is set in order to allow
+               recognizing slices; see the routine expression_list) */
+            mpl->flag_x = 1;
+            code = expression_9(mpl);
+            if (code->op != O_SLICE)
+            {  /* this is either <basic expression> or the very first
+                  <member expression> in <literal set> */
+               goto expr;
+            }
+            /* this is a slice; besides the corresponding domain block
+               is already created by expression_list() */
+            block = code->arg.slice;
+            code = NULL; /* <basic expression> is not parsed yet */
+            /* the keyword 'in' following the slice is already checked
+               by expression_list() */
+            xassert(mpl->token == T_IN);
+            get_token(mpl /* in */);
+            /* <basic expression> that follows the keyword 'in' will be
+               parsed below */
+         }
+expr:    /* parse expression that follows either the keyword 'in' (in
+            which case it can be <basic expression) or the left brace
+            (in which case it can be <basic expression> as well as the
+            very first <member expression> in <literal set>); note that
+            this expression can be already parsed above */
+         if (code == NULL) code = expression_9(mpl);
+         /* check the type of the expression just parsed */
+         if (code->type != A_ELEMSET)
+         {  /* it is not <basic expression> and therefore it can only
+               be the very first <member expression> in <literal set>;
+               however, then there must be no dummy index neither slice
+               between the left brace and this expression */
+            if (block != NULL)
+               error(mpl, "domain expression has invalid type");
+            /* parse the rest part of <literal set> and make this set
+               be <basic expression>, i.e. the construction {a, b, c}
+               is parsed as it were written as {A}, where A = {a, b, c}
+               is a temporary elemental set */
+            code = literal_set(mpl, code);
+         }
+         /* now pseudo-code for <basic set> has been built */
+         xassert(code != NULL);
+         xassert(code->type == A_ELEMSET);
+         xassert(code->dim > 0);
+         /* if domain block for the current <indexing element> is still
+            not created, create it for fake slice of the same dimension
+            as <basic set> */
+         if (block == NULL)
+         {  int j;
+            block = create_block(mpl);
+            for (j = 1; j <= code->dim; j++)
+               append_slot(mpl, block, NULL, NULL);
+         }
+         /* number of indexing positions in <indexing element> must be
+            the same as dimension of n-tuples in basic set */
+         {  int dim = 0;
+            for (slot = block->list; slot != NULL; slot = slot->next)
+               dim++;
+            if (dim != code->dim)
+               error(mpl,"%d %s specified for set of dimension %d",
+                  dim, dim == 1 ? "index" : "indices", code->dim);
+         }
+         /* store pseudo-code for <basic set> in the domain block */
+         xassert(block->code == NULL);
+         block->code = code;
+         /* and append the domain block to the domain */
+         append_block(mpl, domain, block);
+         /* the current <indexing element> has been completely parsed;
+            include all its dummy indices into the symbolic name table
+            to make them available for referencing from expressions;
+            implicit declarations of dummy indices remain valid while
+            the corresponding domain scope is valid */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         if (slot->name != NULL)
+         {  AVLNODE *node;
+            xassert(avl_find_node(mpl->tree, slot->name) == NULL);
+            node = avl_insert_node(mpl->tree, slot->name);
+            avl_set_node_type(node, A_INDEX);
+            avl_set_node_link(node, (void *)slot);
+         }
+         /* check a token that follows <indexing element> */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
+            break;
+         else
+            error(mpl, "syntax error in indexing expression");
+      }
+      /* parse <logical expression> that follows the colon */
+      if (mpl->token == T_COLON)
+      {  get_token(mpl /* : */);
+         code = expression_13(mpl);
+         /* convert the expression to logical type, if necessary */
+         if (code->type == A_SYMBOLIC)
+            code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
+         if (code->type == A_NUMERIC)
+            code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
+         /* now the expression must be of logical type */
+         if (code->type != A_LOGICAL)
+            error(mpl, "expression following colon has invalid type");
+         xassert(code->dim == 0);
+         domain->code = code;
+         /* the right brace must follow the logical expression */
+         if (mpl->token != T_RBRACE)
+            error(mpl, "syntax error in indexing expression");
+      }
+      get_token(mpl /* } */);
+      return domain;
+}
+
+/*----------------------------------------------------------------------
+-- close_scope - close scope of indexing expression.
+--
+-- The routine closes the scope of indexing expression specified by its
+-- domain and thereby makes all dummy indices introduced in the indexing
+-- expression no longer available for referencing. */
+
+void close_scope(MPL *mpl, DOMAIN *domain)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      AVLNODE *node;
+      xassert(domain != NULL);
+      /* remove all dummy indices from the symbolic names table */
+      for (block = domain->list; block != NULL; block = block->next)
+      {  for (slot = block->list; slot != NULL; slot = slot->next)
+         {  if (slot->name != NULL)
+            {  node = avl_find_node(mpl->tree, slot->name);
+               xassert(node != NULL);
+               xassert(avl_get_node_type(node) == A_INDEX);
+               avl_delete_node(mpl->tree, node);
+            }
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- iterated_expression - parse iterated expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <iterated expression>
+-- <iterated expression> ::= sum <indexing expression> <expression 3>
+-- <iterated expression> ::= prod <indexing expression> <expression 3>
+-- <iterated expression> ::= min <indexing expression> <expression 3>
+-- <iterated expression> ::= max <indexing expression> <expression 3>
+-- <iterated expression> ::= exists <indexing expression>
+--                           <expression 12>
+-- <iterated expression> ::= forall <indexing expression>
+--                           <expression 12>
+-- <iterated expression> ::= setof <indexing expression> <expression 5>
+--
+-- Note that parsing "integrand" depends on the iterated operator. */
+
+#if 1 /* 07/IX-2008 */
+static void link_up(CODE *code)
+{     /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
+         where i and k are dummy indices defined out of the iterated
+         expression, we should link up pseudo-code for computing i+1
+         and k-1 to pseudo-code for computing the iterated expression;
+         this is needed to invalidate current value of the iterated
+         expression once i or k have been changed */
+      DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      for (block = code->arg.loop.domain->list; block != NULL;
+         block = block->next)
+      {  for (slot = block->list; slot != NULL; slot = slot->next)
+         {  if (slot->code != NULL)
+            {  xassert(slot->code->up == NULL);
+               slot->code->up = code;
+            }
+         }
+      }
+      return;
+}
+#endif
+
+CODE *iterated_expression(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      int op;
+      char opstr[8];
+      /* determine operation code */
+      xassert(mpl->token == T_NAME);
+      if (strcmp(mpl->image, "sum") == 0)
+         op = O_SUM;
+      else if (strcmp(mpl->image, "prod") == 0)
+         op = O_PROD;
+      else if (strcmp(mpl->image, "min") == 0)
+         op = O_MINIMUM;
+      else if (strcmp(mpl->image, "max") == 0)
+         op = O_MAXIMUM;
+      else if (strcmp(mpl->image, "forall") == 0)
+         op = O_FORALL;
+      else if (strcmp(mpl->image, "exists") == 0)
+         op = O_EXISTS;
+      else if (strcmp(mpl->image, "setof") == 0)
+         op = O_SETOF;
+      else
+         error(mpl, "operator %s unknown", mpl->image);
+      strcpy(opstr, mpl->image);
+      xassert(strlen(opstr) < sizeof(opstr));
+      get_token(mpl /* <symbolic name> */);
+      /* check the left brace that follows the operator name */
+      xassert(mpl->token == T_LBRACE);
+      /* parse indexing expression that controls iterating */
+      arg.loop.domain = indexing_expression(mpl);
+      /* parse "integrand" expression and generate pseudo-code */
+      switch (op)
+      {  case O_SUM:
+         case O_PROD:
+         case O_MINIMUM:
+         case O_MAXIMUM:
+            arg.loop.x = expression_3(mpl);
+            /* convert the integrand to numeric type, if necessary */
+            if (arg.loop.x->type == A_SYMBOLIC)
+               arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
+                  A_NUMERIC, 0);
+            /* now the integrand must be of numeric type or linear form
+               (the latter is only allowed for the sum operator) */
+            if (!(arg.loop.x->type == A_NUMERIC ||
+                  op == O_SUM && arg.loop.x->type == A_FORMULA))
+err:           error(mpl, "integrand following %s{...} has invalid type"
+                  , opstr);
+            xassert(arg.loop.x->dim == 0);
+            /* generate pseudo-code */
+            code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
+            break;
+         case O_FORALL:
+         case O_EXISTS:
+            arg.loop.x = expression_12(mpl);
+            /* convert the integrand to logical type, if necessary */
+            if (arg.loop.x->type == A_SYMBOLIC)
+               arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
+                  A_NUMERIC, 0);
+            if (arg.loop.x->type == A_NUMERIC)
+               arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
+                  A_LOGICAL, 0);
+            /* now the integrand must be of logical type */
+            if (arg.loop.x->type != A_LOGICAL) goto err;
+            xassert(arg.loop.x->dim == 0);
+            /* generate pseudo-code */
+            code = make_code(mpl, op, &arg, A_LOGICAL, 0);
+            break;
+         case O_SETOF:
+            arg.loop.x = expression_5(mpl);
+            /* convert the integrand to 1-tuple, if necessary */
+            if (arg.loop.x->type == A_NUMERIC)
+               arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
+                  A_SYMBOLIC, 0);
+            if (arg.loop.x->type == A_SYMBOLIC)
+               arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
+                  A_TUPLE, 1);
+            /* now the integrand must be n-tuple */
+            if (arg.loop.x->type != A_TUPLE) goto err;
+            xassert(arg.loop.x->dim > 0);
+            /* generate pseudo-code */
+            code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
+            break;
+         default:
+            xassert(op != op);
+      }
+      /* close the scope of the indexing expression */
+      close_scope(mpl, arg.loop.domain);
+#if 1 /* 07/IX-2008 */
+      link_up(code);
+#endif
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- domain_arity - determine arity of domain.
+--
+-- This routine returns arity of specified domain, which is number of
+-- its free dummy indices. */
+
+int domain_arity(MPL *mpl, DOMAIN *domain)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      int arity;
+      xassert(mpl == mpl);
+      arity = 0;
+      for (block = domain->list; block != NULL; block = block->next)
+         for (slot = block->list; slot != NULL; slot = slot->next)
+            if (slot->code == NULL) arity++;
+      return arity;
+}
+
+/*----------------------------------------------------------------------
+-- set_expression - parse set expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= { }
+-- <primary expression> ::= <indexing expression> */
+
+CODE *set_expression(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(mpl->token == T_LBRACE);
+      get_token(mpl /* { */);
+      /* check a token that follows the left brace */
+      if (mpl->token == T_RBRACE)
+      {  /* it is the right brace, so the resultant is an empty set of
+            dimension 1 */
+         arg.list = NULL;
+         /* generate pseudo-code to build the resultant set */
+         code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
+         get_token(mpl /* } */);
+      }
+      else
+      {  /* the next token begins an indexing expression */
+         unget_token(mpl);
+         arg.loop.domain = indexing_expression(mpl);
+         arg.loop.x = NULL; /* integrand is not used */
+         /* close the scope of the indexing expression */
+         close_scope(mpl, arg.loop.domain);
+         /* generate pseudo-code to build the resultant set */
+         code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
+            domain_arity(mpl, arg.loop.domain));
+#if 1 /* 07/IX-2008 */
+         link_up(code);
+#endif
+      }
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- branched_expression - parse conditional expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <branched expression>
+-- <branched expression> ::= if <logical expression> then <expression 9>
+-- <branched expression> ::= if <logical expression> then <expression 9>
+--                           else <expression 9>
+-- <logical expression> ::= <expression 13> */
+
+CODE *branched_expression(MPL *mpl)
+{     CODE *code, *x, *y, *z;
+      xassert(mpl->token == T_IF);
+      get_token(mpl /* if */);
+      /* parse <logical expression> that follows 'if' */
+      x = expression_13(mpl);
+      /* convert the expression to logical type, if necessary */
+      if (x->type == A_SYMBOLIC)
+         x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+      if (x->type == A_NUMERIC)
+         x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+      /* now the expression must be of logical type */
+      if (x->type != A_LOGICAL)
+         error(mpl, "expression following if has invalid type");
+      xassert(x->dim == 0);
+      /* the keyword 'then' must follow the logical expression */
+      if (mpl->token != T_THEN)
+         error(mpl, "keyword then missing where expected");
+      get_token(mpl /* then */);
+      /* parse <expression> that follows 'then' and check its type */
+      y = expression_9(mpl);
+      if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
+            y->type == A_ELEMSET || y->type == A_FORMULA))
+         error(mpl, "expression following then has invalid type");
+      /* if the expression that follows the keyword 'then' is elemental
+         set, the keyword 'else' cannot be omitted; otherwise else-part
+         is optional */
+      if (mpl->token != T_ELSE)
+      {  if (y->type == A_ELEMSET)
+            error(mpl, "keyword else missing where expected");
+         z = NULL;
+         goto skip;
+      }
+      get_token(mpl /* else */);
+      /* parse <expression> that follow 'else' and check its type */
+      z = expression_9(mpl);
+      if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
+            z->type == A_ELEMSET || z->type == A_FORMULA))
+         error(mpl, "expression following else has invalid type");
+      /* convert to identical types, if necessary */
+      if (y->type == A_FORMULA || z->type == A_FORMULA)
+      {  if (y->type == A_SYMBOLIC)
+            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+         if (y->type == A_NUMERIC)
+            y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+         if (z->type == A_SYMBOLIC)
+            z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
+         if (z->type == A_NUMERIC)
+            z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
+      }
+      if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
+      {  if (y->type == A_NUMERIC)
+            y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+         if (z->type == A_NUMERIC)
+            z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
+      }
+      /* now both expressions must have identical types */
+      if (y->type != z->type)
+         error(mpl, "expressions following then and else have incompati"
+            "ble types");
+      /* and identical dimensions */
+      if (y->dim != z->dim)
+         error(mpl, "expressions following then and else have different"
+            " dimensions %d and %d, respectively", y->dim, z->dim);
+skip: /* generate pseudo-code to perform branching */
+      code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- primary_expression - parse primary expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <numeric literal>
+-- <primary expression> ::= Infinity
+-- <primary expression> ::= <string literal>
+-- <primary expression> ::= <dummy index>
+-- <primary expression> ::= <set name>
+-- <primary expression> ::= <set name> [ <subscript list> ]
+-- <primary expression> ::= <parameter name>
+-- <primary expression> ::= <parameter name> [ <subscript list> ]
+-- <primary expression> ::= <variable name>
+-- <primary expression> ::= <variable name> [ <subscript list> ]
+-- <primary expression> ::= <built-in function> ( <argument list> )
+-- <primary expression> ::= ( <expression list> )
+-- <primary expression> ::= <iterated expression>
+-- <primary expression> ::= { }
+-- <primary expression> ::= <indexing expression>
+-- <primary expression> ::= <branched expression>
+--
+-- For complete list of syntactic rules for <primary expression> see
+-- comments to the corresponding parsing routines. */
+
+CODE *primary_expression(MPL *mpl)
+{     CODE *code;
+      if (mpl->token == T_NUMBER)
+      {  /* parse numeric literal */
+         code = numeric_literal(mpl);
+      }
+#if 1 /* 21/VII-2006 */
+      else if (mpl->token == T_INFINITY)
+      {  /* parse "infinity" */
+         OPERANDS arg;
+         arg.num = DBL_MAX;
+         code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
+         get_token(mpl /* Infinity */);
+      }
+#endif
+      else if (mpl->token == T_STRING)
+      {  /* parse string literal */
+         code = string_literal(mpl);
+      }
+      else if (mpl->token == T_NAME)
+      {  int next_token;
+         get_token(mpl /* <symbolic name> */);
+         next_token = mpl->token;
+         unget_token(mpl);
+         /* check a token that follows <symbolic name> */
+         switch (next_token)
+         {  case T_LBRACKET:
+               /* parse reference to subscripted object */
+               code = object_reference(mpl);
+               break;
+            case T_LEFT:
+               /* parse reference to built-in function */
+               code = function_reference(mpl);
+               break;
+            case T_LBRACE:
+               /* parse iterated expression */
+               code = iterated_expression(mpl);
+               break;
+            default:
+               /* parse reference to unsubscripted object */
+               code = object_reference(mpl);
+               break;
+         }
+      }
+      else if (mpl->token == T_LEFT)
+      {  /* parse parenthesized expression */
+         code = expression_list(mpl);
+      }
+      else if (mpl->token == T_LBRACE)
+      {  /* parse set expression */
+         code = set_expression(mpl);
+      }
+      else if (mpl->token == T_IF)
+      {  /* parse conditional expression */
+         code = branched_expression(mpl);
+      }
+      else if (is_reserved(mpl))
+      {  /* other reserved keywords cannot be used here */
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      }
+      else
+         error(mpl, "syntax error in expression");
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- error_preceding - raise error if preceding operand has wrong type.
+--
+-- This routine is called to raise error if operand that precedes some
+-- infix operator has invalid type. */
+
+void error_preceding(MPL *mpl, char *opstr)
+{     error(mpl, "operand preceding %s has invalid type", opstr);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- error_following - raise error if following operand has wrong type.
+--
+-- This routine is called to raise error if operand that follows some
+-- infix operator has invalid type. */
+
+void error_following(MPL *mpl, char *opstr)
+{     error(mpl, "operand following %s has invalid type", opstr);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- error_dimension - raise error if operands have different dimension.
+--
+-- This routine is called to raise error if two operands of some infix
+-- operator have different dimension. */
+
+void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
+{     error(mpl, "operands preceding and following %s have different di"
+         "mensions %d and %d, respectively", opstr, dim1, dim2);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- expression_0 - parse expression of level 0.
+--
+-- This routine parses expression of level 0 using the syntax:
+--
+-- <expression 0> ::= <primary expression> */
+
+CODE *expression_0(MPL *mpl)
+{     CODE *code;
+      code = primary_expression(mpl);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- expression_1 - parse expression of level 1.
+--
+-- This routine parses expression of level 1 using the syntax:
+--
+-- <expression 1> ::= <expression 0>
+-- <expression 1> ::= <expression 0> <power> <expression 1>
+-- <expression 1> ::= <expression 0> <power> <expression 2>
+-- <power> ::= ^ | ** */
+
+CODE *expression_1(MPL *mpl)
+{     CODE *x, *y;
+      char opstr[8];
+      x = expression_0(mpl);
+      if (mpl->token == T_POWER)
+      {  strcpy(opstr, mpl->image);
+         xassert(strlen(opstr) < sizeof(opstr));
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (x->type != A_NUMERIC)
+            error_preceding(mpl, opstr);
+         get_token(mpl /* ^ | ** */);
+         if (mpl->token == T_PLUS || mpl->token == T_MINUS)
+            y = expression_2(mpl);
+         else
+            y = expression_1(mpl);
+         if (y->type == A_SYMBOLIC)
+            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+         if (y->type != A_NUMERIC)
+            error_following(mpl, opstr);
+         x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_2 - parse expression of level 2.
+--
+-- This routine parses expression of level 2 using the syntax:
+--
+-- <expression 2> ::= <expression 1>
+-- <expression 2> ::= + <expression 1>
+-- <expression 2> ::= - <expression 1> */
+
+CODE *expression_2(MPL *mpl)
+{     CODE *x;
+      if (mpl->token == T_PLUS)
+      {  get_token(mpl /* + */);
+         x = expression_1(mpl);
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+            error_following(mpl, "+");
+         x = make_unary(mpl, O_PLUS, x, x->type, 0);
+      }
+      else if (mpl->token == T_MINUS)
+      {  get_token(mpl /* - */);
+         x = expression_1(mpl);
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+            error_following(mpl, "-");
+         x = make_unary(mpl, O_MINUS, x, x->type, 0);
+      }
+      else
+         x = expression_1(mpl);
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_3 - parse expression of level 3.
+--
+-- This routine parses expression of level 3 using the syntax:
+--
+-- <expression 3> ::= <expression 2>
+-- <expression 3> ::= <expression 3> * <expression 2>
+-- <expression 3> ::= <expression 3> / <expression 2>
+-- <expression 3> ::= <expression 3> div <expression 2>
+-- <expression 3> ::= <expression 3> mod <expression 2> */
+
+CODE *expression_3(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_2(mpl);
+      for (;;)
+      {  if (mpl->token == T_ASTERISK)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "*");
+            get_token(mpl /* * */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+               error_following(mpl, "*");
+            if (x->type == A_FORMULA && y->type == A_FORMULA)
+               error(mpl, "multiplication of linear forms not allowed");
+            if (x->type == A_NUMERIC && y->type == A_NUMERIC)
+               x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
+            else
+               x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
+         }
+         else if (mpl->token == T_SLASH)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "/");
+            get_token(mpl /* / */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "/");
+            if (x->type == A_NUMERIC)
+               x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
+            else
+               x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
+         }
+         else if (mpl->token == T_DIV)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, "div");
+            get_token(mpl /* div */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "div");
+            x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
+         }
+         else if (mpl->token == T_MOD)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, "mod");
+            get_token(mpl /* mod */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "mod");
+            x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_4 - parse expression of level 4.
+--
+-- This routine parses expression of level 4 using the syntax:
+--
+-- <expression 4> ::= <expression 3>
+-- <expression 4> ::= <expression 4> + <expression 3>
+-- <expression 4> ::= <expression 4> - <expression 3>
+-- <expression 4> ::= <expression 4> less <expression 3> */
+
+CODE *expression_4(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_3(mpl);
+      for (;;)
+      {  if (mpl->token == T_PLUS)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "+");
+            get_token(mpl /* + */);
+            y = expression_3(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+               error_following(mpl, "+");
+            if (x->type == A_NUMERIC && y->type == A_FORMULA)
+               x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
+            if (x->type == A_FORMULA && y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+            x = make_binary(mpl, O_ADD, x, y, x->type, 0);
+         }
+         else if (mpl->token == T_MINUS)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "-");
+            get_token(mpl /* - */);
+            y = expression_3(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+               error_following(mpl, "-");
+            if (x->type == A_NUMERIC && y->type == A_FORMULA)
+               x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
+            if (x->type == A_FORMULA && y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+            x = make_binary(mpl, O_SUB, x, y, x->type, 0);
+         }
+         else if (mpl->token == T_LESS)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, "less");
+            get_token(mpl /* less */);
+            y = expression_3(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "less");
+            x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_5 - parse expression of level 5.
+--
+-- This routine parses expression of level 5 using the syntax:
+--
+-- <expression 5> ::= <expression 4>
+-- <expression 5> ::= <expression 5> & <expression 4> */
+
+CODE *expression_5(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_4(mpl);
+      for (;;)
+      {  if (mpl->token == T_CONCAT)
+         {  if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+            if (x->type != A_SYMBOLIC)
+               error_preceding(mpl, "&");
+            get_token(mpl /* & */);
+            y = expression_4(mpl);
+            if (y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+            if (y->type != A_SYMBOLIC)
+               error_following(mpl, "&");
+            x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_6 - parse expression of level 6.
+--
+-- This routine parses expression of level 6 using the syntax:
+--
+-- <expression 6> ::= <expression 5>
+-- <expression 6> ::= <expression 5> .. <expression 5>
+-- <expression 6> ::= <expression 5> .. <expression 5> by
+--                    <expression 5> */
+
+CODE *expression_6(MPL *mpl)
+{     CODE *x, *y, *z;
+      x = expression_5(mpl);
+      if (mpl->token == T_DOTS)
+      {  if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (x->type != A_NUMERIC)
+            error_preceding(mpl, "..");
+         get_token(mpl /* .. */);
+         y = expression_5(mpl);
+         if (y->type == A_SYMBOLIC)
+            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+         if (y->type != A_NUMERIC)
+            error_following(mpl, "..");
+         if (mpl->token == T_BY)
+         {  get_token(mpl /* by */);
+            z = expression_5(mpl);
+            if (z->type == A_SYMBOLIC)
+               z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
+            if (z->type != A_NUMERIC)
+               error_following(mpl, "by");
+         }
+         else
+            z = NULL;
+         x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_7 - parse expression of level 7.
+--
+-- This routine parses expression of level 7 using the syntax:
+--
+-- <expression 7> ::= <expression 6>
+-- <expression 7> ::= <expression 7> cross <expression 6> */
+
+CODE *expression_7(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_6(mpl);
+      for (;;)
+      {  if (mpl->token == T_CROSS)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "cross");
+            get_token(mpl /* cross */);
+            y = expression_6(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "cross");
+            x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
+               x->dim + y->dim);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_8 - parse expression of level 8.
+--
+-- This routine parses expression of level 8 using the syntax:
+--
+-- <expression 8> ::= <expression 7>
+-- <expression 8> ::= <expression 8> inter <expression 7> */
+
+CODE *expression_8(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_7(mpl);
+      for (;;)
+      {  if (mpl->token == T_INTER)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "inter");
+            get_token(mpl /* inter */);
+            y = expression_7(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "inter");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "inter", x->dim, y->dim);
+            x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_9 - parse expression of level 9.
+--
+-- This routine parses expression of level 9 using the syntax:
+--
+-- <expression 9> ::= <expression 8>
+-- <expression 9> ::= <expression 9> union <expression 8>
+-- <expression 9> ::= <expression 9> diff <expression 8>
+-- <expression 9> ::= <expression 9> symdiff <expression 8> */
+
+CODE *expression_9(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_8(mpl);
+      for (;;)
+      {  if (mpl->token == T_UNION)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "union");
+            get_token(mpl /* union */);
+            y = expression_8(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "union");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "union", x->dim, y->dim);
+            x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
+         }
+         else if (mpl->token == T_DIFF)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "diff");
+            get_token(mpl /* diff */);
+            y = expression_8(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "diff");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "diff", x->dim, y->dim);
+            x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
+         }
+         else if (mpl->token == T_SYMDIFF)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "symdiff");
+            get_token(mpl /* symdiff */);
+            y = expression_8(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "symdiff");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "symdiff", x->dim, y->dim);
+            x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_10 - parse expression of level 10.
+--
+-- This routine parses expression of level 10 using the syntax:
+--
+-- <expression 10> ::= <expression 9>
+-- <expression 10> ::= <expression 9> <rho> <expression 9>
+-- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
+--           within | not within | ! within */
+
+CODE *expression_10(MPL *mpl)
+{     CODE *x, *y;
+      int op = -1;
+      char opstr[16];
+      x = expression_9(mpl);
+      strcpy(opstr, "");
+      switch (mpl->token)
+      {  case T_LT:
+            op = O_LT; break;
+         case T_LE:
+            op = O_LE; break;
+         case T_EQ:
+            op = O_EQ; break;
+         case T_GE:
+            op = O_GE; break;
+         case T_GT:
+            op = O_GT; break;
+         case T_NE:
+            op = O_NE; break;
+         case T_IN:
+            op = O_IN; break;
+         case T_WITHIN:
+            op = O_WITHIN; break;
+         case T_NOT:
+            strcpy(opstr, mpl->image);
+            get_token(mpl /* not | ! */);
+            if (mpl->token == T_IN)
+               op = O_NOTIN;
+            else if (mpl->token == T_WITHIN)
+               op = O_NOTWITHIN;
+            else
+               error(mpl, "invalid use of %s", opstr);
+            strcat(opstr, " ");
+            break;
+         default:
+            goto done;
+      }
+      strcat(opstr, mpl->image);
+      xassert(strlen(opstr) < sizeof(opstr));
+      switch (op)
+      {  case O_EQ:
+         case O_NE:
+#if 1 /* 02/VIII-2008 */
+         case O_LT:
+         case O_LE:
+         case O_GT:
+         case O_GE:
+#endif
+            if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
+               error_following(mpl, opstr);
+            if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+            if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+#if 0 /* 02/VIII-2008 */
+         case O_LT:
+         case O_LE:
+         case O_GT:
+         case O_GE:
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, opstr);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+#endif
+         case O_IN:
+         case O_NOTIN:
+            if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
+            if (x->type != A_TUPLE)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, opstr);
+            if (x->dim != y->dim)
+               error_dimension(mpl, opstr, x->dim, y->dim);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+         case O_WITHIN:
+         case O_NOTWITHIN:
+            if (x->type != A_ELEMSET)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, opstr);
+            if (x->dim != y->dim)
+               error_dimension(mpl, opstr, x->dim, y->dim);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+         default:
+            xassert(op != op);
+      }
+done: return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_11 - parse expression of level 11.
+--
+-- This routine parses expression of level 11 using the syntax:
+--
+-- <expression 11> ::= <expression 10>
+-- <expression 11> ::= not <expression 10>
+-- <expression 11> ::= ! <expression 10> */
+
+CODE *expression_11(MPL *mpl)
+{     CODE *x;
+      char opstr[8];
+      if (mpl->token == T_NOT)
+      {  strcpy(opstr, mpl->image);
+         xassert(strlen(opstr) < sizeof(opstr));
+         get_token(mpl /* not | ! */);
+         x = expression_10(mpl);
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (x->type == A_NUMERIC)
+            x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+         if (x->type != A_LOGICAL)
+            error_following(mpl, opstr);
+         x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
+      }
+      else
+         x = expression_10(mpl);
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_12 - parse expression of level 12.
+--
+-- This routine parses expression of level 12 using the syntax:
+--
+-- <expression 12> ::= <expression 11>
+-- <expression 12> ::= <expression 12> and <expression 11>
+-- <expression 12> ::= <expression 12> && <expression 11> */
+
+CODE *expression_12(MPL *mpl)
+{     CODE *x, *y;
+      char opstr[8];
+      x = expression_11(mpl);
+      for (;;)
+      {  if (mpl->token == T_AND)
+         {  strcpy(opstr, mpl->image);
+            xassert(strlen(opstr) < sizeof(opstr));
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+            if (x->type != A_LOGICAL)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* and | && */);
+            y = expression_11(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
+            if (y->type != A_LOGICAL)
+               error_following(mpl, opstr);
+            x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_13 - parse expression of level 13.
+--
+-- This routine parses expression of level 13 using the syntax:
+--
+-- <expression 13> ::= <expression 12>
+-- <expression 13> ::= <expression 13> or <expression 12>
+-- <expression 13> ::= <expression 13> || <expression 12> */
+
+CODE *expression_13(MPL *mpl)
+{     CODE *x, *y;
+      char opstr[8];
+      x = expression_12(mpl);
+      for (;;)
+      {  if (mpl->token == T_OR)
+         {  strcpy(opstr, mpl->image);
+            xassert(strlen(opstr) < sizeof(opstr));
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+            if (x->type != A_LOGICAL)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* or | || */);
+            y = expression_12(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
+            if (y->type != A_LOGICAL)
+               error_following(mpl, opstr);
+            x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- set_statement - parse set statement.
+--
+-- This routine parses set statement using the syntax:
+--
+-- <set statement> ::= set <symbolic name> <alias> <domain>
+--                     <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , dimen <numeric literal>
+-- <attributes> ::= <attributes> , within <expression 9>
+-- <attributes> ::= <attributes> , := <expression 9>
+-- <attributes> ::= <attributes> , default <expression 9>
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+SET *set_statement(MPL *mpl)
+{     SET *set;
+      int dimen_used = 0;
+      xassert(is_keyword(mpl, "set"));
+      get_token(mpl /* set */);
+      /* symbolic name must follow the keyword 'set' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model set */
+      set = alloc(SET);
+      set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(set->name, mpl->image);
+      set->alias = NULL;
+      set->dim = 0;
+      set->domain = NULL;
+      set->dimen = 0;
+      set->within = NULL;
+      set->assign = NULL;
+      set->option = NULL;
+      set->gadget = NULL;
+      set->data = 0;
+      set->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(set->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  set->domain = indexing_expression(mpl);
+         set->dim = domain_arity(mpl, set->domain);
+      }
+      /* include the set name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, set->name);
+         avl_set_node_type(node, A_SET);
+         avl_set_node_link(node, (void *)set);
+      }
+      /* parse the list of optional attributes */
+      for (;;)
+      {  if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         if (is_keyword(mpl, "dimen"))
+         {  /* dimension of set members */
+            int dimen;
+            get_token(mpl /* dimen */);
+            if (!(mpl->token == T_NUMBER &&
+                  1.0 <= mpl->value && mpl->value <= 20.0 &&
+                  floor(mpl->value) == mpl->value))
+               error(mpl, "dimension must be integer between 1 and 20");
+            dimen = (int)(mpl->value + 0.5);
+            if (dimen_used)
+               error(mpl, "at most one dimension attribute allowed");
+            if (set->dimen > 0)
+               error(mpl, "dimension %d conflicts with dimension %d alr"
+                  "eady determined", dimen, set->dimen);
+            set->dimen = dimen;
+            dimen_used = 1;
+            get_token(mpl /* <numeric literal> */);
+         }
+         else if (mpl->token == T_WITHIN || mpl->token == T_IN)
+         {  /* restricting superset */
+            WITHIN *within, *temp;
+            if (mpl->token == T_IN && !mpl->as_within)
+            {  warning(mpl, "keyword in understood as within");
+               mpl->as_within = 1;
+            }
+            get_token(mpl /* within */);
+            /* create new restricting superset list entry and append it
+               to the within-list */
+            within = alloc(WITHIN);
+            within->code = NULL;
+            within->next = NULL;
+            if (set->within == NULL)
+               set->within = within;
+            else
+            {  for (temp = set->within; temp->next != NULL; temp =
+                  temp->next);
+               temp->next = within;
+            }
+            /* parse an expression that follows 'within' */
+            within->code = expression_9(mpl);
+            if (within->code->type != A_ELEMSET)
+               error(mpl, "expression following within has invalid type"
+                  );
+            xassert(within->code->dim > 0);
+            /* check/set dimension of set members */
+            if (set->dimen == 0) set->dimen = within->code->dim;
+            if (set->dimen != within->code->dim)
+               error(mpl, "set expression following within must have di"
+                  "mension %d rather than %d",
+                  set->dimen, within->code->dim);
+         }
+         else if (mpl->token == T_ASSIGN)
+         {  /* assignment expression */
+            if (!(set->assign == NULL && set->option == NULL &&
+                  set->gadget == NULL))
+err:           error(mpl, "at most one := or default/data allowed");
+            get_token(mpl /* := */);
+            /* parse an expression that follows ':=' */
+            set->assign = expression_9(mpl);
+            if (set->assign->type != A_ELEMSET)
+               error(mpl, "expression following := has invalid type");
+            xassert(set->assign->dim > 0);
+            /* check/set dimension of set members */
+            if (set->dimen == 0) set->dimen = set->assign->dim;
+            if (set->dimen != set->assign->dim)
+               error(mpl, "set expression following := must have dimens"
+                  "ion %d rather than %d",
+                  set->dimen, set->assign->dim);
+         }
+         else if (is_keyword(mpl, "default"))
+         {  /* expression for default value */
+            if (!(set->assign == NULL && set->option == NULL)) goto err;
+            get_token(mpl /* := */);
+            /* parse an expression that follows 'default' */
+            set->option = expression_9(mpl);
+            if (set->option->type != A_ELEMSET)
+               error(mpl, "expression following default has invalid typ"
+                  "e");
+            xassert(set->option->dim > 0);
+            /* check/set dimension of set members */
+            if (set->dimen == 0) set->dimen = set->option->dim;
+            if (set->dimen != set->option->dim)
+               error(mpl, "set expression following default must have d"
+                  "imension %d rather than %d",
+                  set->dimen, set->option->dim);
+         }
+#if 1 /* 12/XII-2008 */
+         else if (is_keyword(mpl, "data"))
+         {  /* gadget to initialize the set by data from plain set */
+            GADGET *gadget;
+            AVLNODE *node;
+            int i, k, fff[20];
+            if (!(set->assign == NULL && set->gadget == NULL)) goto err;
+            get_token(mpl /* data */);
+            set->gadget = gadget = alloc(GADGET);
+            /* set name must follow the keyword 'data' */
+            if (mpl->token == T_NAME)
+               ;
+            else if (is_reserved(mpl))
+               error(mpl, "invalid use of reserved keyword %s",
+                  mpl->image);
+            else
+               error(mpl, "set name missing where expected");
+            /* find the set in the symbolic name table */
+            node = avl_find_node(mpl->tree, mpl->image);
+            if (node == NULL)
+               error(mpl, "%s not defined", mpl->image);
+            if (avl_get_node_type(node) != A_SET)
+err1:          error(mpl, "%s not a plain set", mpl->image);
+            gadget->set = avl_get_node_link(node);
+            if (gadget->set->dim != 0) goto err1;
+            if (gadget->set == set)
+               error(mpl, "set cannot be initialized by itself");
+            /* check and set dimensions */
+            if (set->dim >= gadget->set->dimen)
+err2:          error(mpl, "dimension of %s too small", mpl->image);
+            if (set->dimen == 0)
+               set->dimen = gadget->set->dimen - set->dim;
+            if (set->dim + set->dimen > gadget->set->dimen)
+               goto err2;
+            else if (set->dim + set->dimen < gadget->set->dimen)
+               error(mpl, "dimension of %s too big", mpl->image);
+            get_token(mpl /* set name */);
+            /* left parenthesis must follow the set name */
+            if (mpl->token == T_LEFT)
+               get_token(mpl /* ( */);
+            else
+               error(mpl, "left parenthesis missing where expected");
+            /* parse permutation of component numbers */
+            for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
+            k = 0;
+            for (;;)
+            {  if (mpl->token != T_NUMBER)
+                  error(mpl, "component number missing where expected");
+               if (str2int(mpl->image, &i) != 0)
+err3:             error(mpl, "component number must be integer between "
+                     "1 and %d", gadget->set->dimen);
+               if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
+               if (fff[i-1] != 0)
+                  error(mpl, "component %d multiply specified", i);
+               gadget->ind[k++] = i, fff[i-1] = 1;
+               xassert(k <= gadget->set->dimen);
+               get_token(mpl /* number */);
+               if (mpl->token == T_COMMA)
+                  get_token(mpl /* , */);
+               else if (mpl->token == T_RIGHT)
+                  break;
+               else
+                  error(mpl, "syntax error in data attribute");
+            }
+            if (k < gadget->set->dimen)
+               error(mpl, "there are must be %d components rather than "
+                  "%d", gadget->set->dimen, k);
+            get_token(mpl /* ) */);
+         }
+#endif
+         else
+            error(mpl, "syntax error in set statement");
+      }
+      /* close the domain scope */
+      if (set->domain != NULL) close_scope(mpl, set->domain);
+      /* if dimension of set members is still unknown, set it to 1 */
+      if (set->dimen == 0) set->dimen = 1;
+      /* the set statement has been completely parsed */
+      xassert(mpl->token == T_SEMICOLON);
+      get_token(mpl /* ; */);
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- parameter_statement - parse parameter statement.
+--
+-- This routine parses parameter statement using the syntax:
+--
+-- <parameter statement> ::= param <symbolic name> <alias> <domain>
+--                           <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , integer
+-- <attributes> ::= <attributes> , binary
+-- <attributes> ::= <attributes> , symbolic
+-- <attributes> ::= <attributes> , <rho> <expression 5>
+-- <attributes> ::= <attributes> , in <expression 9>
+-- <attributes> ::= <attributes> , := <expression 5>
+-- <attributes> ::= <attributes> , default <expression 5>
+-- <rho> ::= < | <= | = | == | >= | > | <> | !=
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+PARAMETER *parameter_statement(MPL *mpl)
+{     PARAMETER *par;
+      int integer_used = 0, binary_used = 0, symbolic_used = 0;
+      xassert(is_keyword(mpl, "param"));
+      get_token(mpl /* param */);
+      /* symbolic name must follow the keyword 'param' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model parameter */
+      par = alloc(PARAMETER);
+      par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(par->name, mpl->image);
+      par->alias = NULL;
+      par->dim = 0;
+      par->domain = NULL;
+      par->type = A_NUMERIC;
+      par->cond = NULL;
+      par->in = NULL;
+      par->assign = NULL;
+      par->option = NULL;
+      par->data = 0;
+      par->defval = NULL;
+      par->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(par->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  par->domain = indexing_expression(mpl);
+         par->dim = domain_arity(mpl, par->domain);
+      }
+      /* include the parameter name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, par->name);
+         avl_set_node_type(node, A_PARAMETER);
+         avl_set_node_link(node, (void *)par);
+      }
+      /* parse the list of optional attributes */
+      for (;;)
+      {  if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         if (is_keyword(mpl, "integer"))
+         {  if (integer_used)
+               error(mpl, "at most one integer allowed");
+            if (par->type == A_SYMBOLIC)
+               error(mpl, "symbolic parameter cannot be integer");
+            if (par->type != A_BINARY) par->type = A_INTEGER;
+            integer_used = 1;
+            get_token(mpl /* integer */);
+         }
+         else if (is_keyword(mpl, "binary"))
+bin:     {  if (binary_used)
+               error(mpl, "at most one binary allowed");
+            if (par->type == A_SYMBOLIC)
+               error(mpl, "symbolic parameter cannot be binary");
+            par->type = A_BINARY;
+            binary_used = 1;
+            get_token(mpl /* binary */);
+         }
+         else if (is_keyword(mpl, "logical"))
+         {  if (!mpl->as_binary)
+            {  warning(mpl, "keyword logical understood as binary");
+               mpl->as_binary = 1;
+            }
+            goto bin;
+         }
+         else if (is_keyword(mpl, "symbolic"))
+         {  if (symbolic_used)
+               error(mpl, "at most one symbolic allowed");
+            if (par->type != A_NUMERIC)
+               error(mpl, "integer or binary parameter cannot be symbol"
+                  "ic");
+            /* the parameter may be referenced from expressions given
+               in the same parameter declaration, so its type must be
+               completed before parsing that expressions */
+            if (!(par->cond == NULL && par->in == NULL &&
+                  par->assign == NULL && par->option == NULL))
+               error(mpl, "keyword symbolic must precede any other para"
+                  "meter attributes");
+            par->type = A_SYMBOLIC;
+            symbolic_used = 1;
+            get_token(mpl /* symbolic */);
+         }
+         else if (mpl->token == T_LT || mpl->token == T_LE ||
+                  mpl->token == T_EQ || mpl->token == T_GE ||
+                  mpl->token == T_GT || mpl->token == T_NE)
+         {  /* restricting condition */
+            CONDITION *cond, *temp;
+            char opstr[8];
+            /* create new restricting condition list entry and append
+               it to the conditions list */
+            cond = alloc(CONDITION);
+            switch (mpl->token)
+            {  case T_LT:
+                  cond->rho = O_LT, strcpy(opstr, mpl->image); break;
+               case T_LE:
+                  cond->rho = O_LE, strcpy(opstr, mpl->image); break;
+               case T_EQ:
+                  cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
+               case T_GE:
+                  cond->rho = O_GE, strcpy(opstr, mpl->image); break;
+               case T_GT:
+                  cond->rho = O_GT, strcpy(opstr, mpl->image); break;
+               case T_NE:
+                  cond->rho = O_NE, strcpy(opstr, mpl->image); break;
+               default:
+                  xassert(mpl->token != mpl->token);
+            }
+            xassert(strlen(opstr) < sizeof(opstr));
+            cond->code = NULL;
+            cond->next = NULL;
+            if (par->cond == NULL)
+               par->cond = cond;
+            else
+            {  for (temp = par->cond; temp->next != NULL; temp =
+                  temp->next);
+               temp->next = cond;
+            }
+#if 0 /* 13/VIII-2008 */
+            if (par->type == A_SYMBOLIC &&
+               !(cond->rho == O_EQ || cond->rho == O_NE))
+               error(mpl, "inequality restriction not allowed");
+#endif
+            get_token(mpl /* rho */);
+            /* parse an expression that follows relational operator */
+            cond->code = expression_5(mpl);
+            if (!(cond->code->type == A_NUMERIC ||
+                  cond->code->type == A_SYMBOLIC))
+               error(mpl, "expression following %s has invalid type",
+                  opstr);
+            xassert(cond->code->dim == 0);
+            /* convert to the parameter type, if necessary */
+            if (par->type != A_SYMBOLIC && cond->code->type ==
+               A_SYMBOLIC)
+               cond->code = make_unary(mpl, O_CVTNUM, cond->code,
+                  A_NUMERIC, 0);
+            if (par->type == A_SYMBOLIC && cond->code->type !=
+               A_SYMBOLIC)
+               cond->code = make_unary(mpl, O_CVTSYM, cond->code,
+                  A_SYMBOLIC, 0);
+         }
+         else if (mpl->token == T_IN || mpl->token == T_WITHIN)
+         {  /* restricting superset */
+            WITHIN *in, *temp;
+            if (mpl->token == T_WITHIN && !mpl->as_in)
+            {  warning(mpl, "keyword within understood as in");
+               mpl->as_in = 1;
+            }
+            get_token(mpl /* in */);
+            /* create new restricting superset list entry and append it
+               to the in-list */
+            in = alloc(WITHIN);
+            in->code = NULL;
+            in->next = NULL;
+            if (par->in == NULL)
+               par->in = in;
+            else
+            {  for (temp = par->in; temp->next != NULL; temp =
+                  temp->next);
+               temp->next = in;
+            }
+            /* parse an expression that follows 'in' */
+            in->code = expression_9(mpl);
+            if (in->code->type != A_ELEMSET)
+               error(mpl, "expression following in has invalid type");
+            xassert(in->code->dim > 0);
+            if (in->code->dim != 1)
+               error(mpl, "set expression following in must have dimens"
+                  "ion 1 rather than %d", in->code->dim);
+         }
+         else if (mpl->token == T_ASSIGN)
+         {  /* assignment expression */
+            if (!(par->assign == NULL && par->option == NULL))
+err:           error(mpl, "at most one := or default allowed");
+            get_token(mpl /* := */);
+            /* parse an expression that follows ':=' */
+            par->assign = expression_5(mpl);
+            /* the expression must be of numeric/symbolic type */
+            if (!(par->assign->type == A_NUMERIC ||
+                  par->assign->type == A_SYMBOLIC))
+               error(mpl, "expression following := has invalid type");
+            xassert(par->assign->dim == 0);
+            /* convert to the parameter type, if necessary */
+            if (par->type != A_SYMBOLIC && par->assign->type ==
+               A_SYMBOLIC)
+               par->assign = make_unary(mpl, O_CVTNUM, par->assign,
+                  A_NUMERIC, 0);
+            if (par->type == A_SYMBOLIC && par->assign->type !=
+               A_SYMBOLIC)
+               par->assign = make_unary(mpl, O_CVTSYM, par->assign,
+                  A_SYMBOLIC, 0);
+         }
+         else if (is_keyword(mpl, "default"))
+         {  /* expression for default value */
+            if (!(par->assign == NULL && par->option == NULL)) goto err;
+            get_token(mpl /* default */);
+            /* parse an expression that follows 'default' */
+            par->option = expression_5(mpl);
+            if (!(par->option->type == A_NUMERIC ||
+                  par->option->type == A_SYMBOLIC))
+               error(mpl, "expression following default has invalid typ"
+                  "e");
+            xassert(par->option->dim == 0);
+            /* convert to the parameter type, if necessary */
+            if (par->type != A_SYMBOLIC && par->option->type ==
+               A_SYMBOLIC)
+               par->option = make_unary(mpl, O_CVTNUM, par->option,
+                  A_NUMERIC, 0);
+            if (par->type == A_SYMBOLIC && par->option->type !=
+               A_SYMBOLIC)
+               par->option = make_unary(mpl, O_CVTSYM, par->option,
+                  A_SYMBOLIC, 0);
+         }
+         else
+            error(mpl, "syntax error in parameter statement");
+      }
+      /* close the domain scope */
+      if (par->domain != NULL) close_scope(mpl, par->domain);
+      /* the parameter statement has been completely parsed */
+      xassert(mpl->token == T_SEMICOLON);
+      get_token(mpl /* ; */);
+      return par;
+}
+
+/*----------------------------------------------------------------------
+-- variable_statement - parse variable statement.
+--
+-- This routine parses variable statement using the syntax:
+--
+-- <variable statement> ::= var <symbolic name> <alias> <domain>
+--                          <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , integer
+-- <attributes> ::= <attributes> , binary
+-- <attributes> ::= <attributes> , <rho> <expression 5>
+-- <rho> ::= >= | <= | = | ==
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+VARIABLE *variable_statement(MPL *mpl)
+{     VARIABLE *var;
+      int integer_used = 0, binary_used = 0;
+      xassert(is_keyword(mpl, "var"));
+      if (mpl->flag_s)
+         error(mpl, "variable statement must precede solve statement");
+      get_token(mpl /* var */);
+      /* symbolic name must follow the keyword 'var' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model variable */
+      var = alloc(VARIABLE);
+      var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(var->name, mpl->image);
+      var->alias = NULL;
+      var->dim = 0;
+      var->domain = NULL;
+      var->type = A_NUMERIC;
+      var->lbnd = NULL;
+      var->ubnd = NULL;
+      var->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(var->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  var->domain = indexing_expression(mpl);
+         var->dim = domain_arity(mpl, var->domain);
+      }
+      /* include the variable name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, var->name);
+         avl_set_node_type(node, A_VARIABLE);
+         avl_set_node_link(node, (void *)var);
+      }
+      /* parse the list of optional attributes */
+      for (;;)
+      {  if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         if (is_keyword(mpl, "integer"))
+         {  if (integer_used)
+               error(mpl, "at most one integer allowed");
+            if (var->type != A_BINARY) var->type = A_INTEGER;
+            integer_used = 1;
+            get_token(mpl /* integer */);
+         }
+         else if (is_keyword(mpl, "binary"))
+bin:     {  if (binary_used)
+               error(mpl, "at most one binary allowed");
+            var->type = A_BINARY;
+            binary_used = 1;
+            get_token(mpl /* binary */);
+         }
+         else if (is_keyword(mpl, "logical"))
+         {  if (!mpl->as_binary)
+            {  warning(mpl, "keyword logical understood as binary");
+               mpl->as_binary = 1;
+            }
+            goto bin;
+         }
+         else if (is_keyword(mpl, "symbolic"))
+            error(mpl, "variable cannot be symbolic");
+         else if (mpl->token == T_GE)
+         {  /* lower bound */
+            if (var->lbnd != NULL)
+            {  if (var->lbnd == var->ubnd)
+                  error(mpl, "both fixed value and lower bound not allo"
+                     "wed");
+               else
+                  error(mpl, "at most one lower bound allowed");
+            }
+            get_token(mpl /* >= */);
+            /* parse an expression that specifies the lower bound */
+            var->lbnd = expression_5(mpl);
+            if (var->lbnd->type == A_SYMBOLIC)
+               var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
+                  A_NUMERIC, 0);
+            if (var->lbnd->type != A_NUMERIC)
+               error(mpl, "expression following >= has invalid type");
+            xassert(var->lbnd->dim == 0);
+         }
+         else if (mpl->token == T_LE)
+         {  /* upper bound */
+            if (var->ubnd != NULL)
+            {  if (var->ubnd == var->lbnd)
+                  error(mpl, "both fixed value and upper bound not allo"
+                     "wed");
+               else
+                  error(mpl, "at most one upper bound allowed");
+            }
+            get_token(mpl /* <= */);
+            /* parse an expression that specifies the upper bound */
+            var->ubnd = expression_5(mpl);
+            if (var->ubnd->type == A_SYMBOLIC)
+               var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
+                  A_NUMERIC, 0);
+            if (var->ubnd->type != A_NUMERIC)
+               error(mpl, "expression following <= has invalid type");
+            xassert(var->ubnd->dim == 0);
+         }
+         else if (mpl->token == T_EQ)
+         {  /* fixed value */
+            char opstr[8];
+            if (!(var->lbnd == NULL && var->ubnd == NULL))
+            {  if (var->lbnd == var->ubnd)
+                  error(mpl, "at most one fixed value allowed");
+               else if (var->lbnd != NULL)
+                  error(mpl, "both lower bound and fixed value not allo"
+                     "wed");
+               else
+                  error(mpl, "both upper bound and fixed value not allo"
+                     "wed");
+            }
+            strcpy(opstr, mpl->image);
+            xassert(strlen(opstr) < sizeof(opstr));
+            get_token(mpl /* = | == */);
+            /* parse an expression that specifies the fixed value */
+            var->lbnd = expression_5(mpl);
+            if (var->lbnd->type == A_SYMBOLIC)
+               var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
+                  A_NUMERIC, 0);
+            if (var->lbnd->type != A_NUMERIC)
+               error(mpl, "expression following %s has invalid type",
+                  opstr);
+            xassert(var->lbnd->dim == 0);
+            /* indicate that the variable is fixed, not bounded */
+            var->ubnd = var->lbnd;
+         }
+         else if (mpl->token == T_LT || mpl->token == T_GT ||
+                  mpl->token == T_NE)
+            error(mpl, "strict bound not allowed");
+         else
+            error(mpl, "syntax error in variable statement");
+      }
+      /* close the domain scope */
+      if (var->domain != NULL) close_scope(mpl, var->domain);
+      /* the variable statement has been completely parsed */
+      xassert(mpl->token == T_SEMICOLON);
+      get_token(mpl /* ; */);
+      return var;
+}
+
+/*----------------------------------------------------------------------
+-- constraint_statement - parse constraint statement.
+--
+-- This routine parses constraint statement using the syntax:
+--
+-- <constraint statement> ::= <subject to> <symbolic name> <alias>
+--                            <domain> : <constraint> ;
+-- <subject to> ::= <empty>
+-- <subject to> ::= subject to
+-- <subject to> ::= subj to
+-- <subject to> ::= s.t.
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <constraint> ::= <formula> , >= <formula>
+-- <constraint> ::= <formula> , <= <formula>
+-- <constraint> ::= <formula> , = <formula>
+-- <constraint> ::= <formula> , <= <formula> , <= <formula>
+-- <constraint> ::= <formula> , >= <formula> , >= <formula>
+-- <formula> ::= <expression 5>
+--
+-- Commae in <constraint> are optional and may be omitted anywhere. */
+
+CONSTRAINT *constraint_statement(MPL *mpl)
+{     CONSTRAINT *con;
+      CODE *first, *second, *third;
+      int rho;
+      char opstr[8];
+      if (mpl->flag_s)
+         error(mpl, "constraint statement must precede solve statement")
+            ;
+      if (is_keyword(mpl, "subject"))
+      {  get_token(mpl /* subject */);
+         if (!is_keyword(mpl, "to"))
+            error(mpl, "keyword subject to incomplete");
+         get_token(mpl /* to */);
+      }
+      else if (is_keyword(mpl, "subj"))
+      {  get_token(mpl /* subj */);
+         if (!is_keyword(mpl, "to"))
+            error(mpl, "keyword subj to incomplete");
+         get_token(mpl /* to */);
+      }
+      else if (mpl->token == T_SPTP)
+         get_token(mpl /* s.t. */);
+      /* the current token must be symbolic name of constraint */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model constraint */
+      con = alloc(CONSTRAINT);
+      con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(con->name, mpl->image);
+      con->alias = NULL;
+      con->dim = 0;
+      con->domain = NULL;
+      con->type = A_CONSTRAINT;
+      con->code = NULL;
+      con->lbnd = NULL;
+      con->ubnd = NULL;
+      con->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(con->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  con->domain = indexing_expression(mpl);
+         con->dim = domain_arity(mpl, con->domain);
+      }
+      /* include the constraint name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, con->name);
+         avl_set_node_type(node, A_CONSTRAINT);
+         avl_set_node_link(node, (void *)con);
+      }
+      /* the colon must precede the first expression */
+      if (mpl->token != T_COLON)
+         error(mpl, "colon missing where expected");
+      get_token(mpl /* : */);
+      /* parse the first expression */
+      first = expression_5(mpl);
+      if (first->type == A_SYMBOLIC)
+         first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
+      if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
+         error(mpl, "expression following colon has invalid type");
+      xassert(first->dim == 0);
+      /* relational operator must follow the first expression */
+      if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      switch (mpl->token)
+      {  case T_LE:
+         case T_GE:
+         case T_EQ:
+            break;
+         case T_LT:
+         case T_GT:
+         case T_NE:
+            error(mpl, "strict inequality not allowed");
+         case T_SEMICOLON:
+            error(mpl, "constraint must be equality or inequality");
+         default:
+            goto err;
+      }
+      rho = mpl->token;
+      strcpy(opstr, mpl->image);
+      xassert(strlen(opstr) < sizeof(opstr));
+      get_token(mpl /* rho */);
+      /* parse the second expression */
+      second = expression_5(mpl);
+      if (second->type == A_SYMBOLIC)
+         second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
+      if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
+         error(mpl, "expression following %s has invalid type", opstr);
+      xassert(second->dim == 0);
+      /* check a token that follow the second expression */
+      if (mpl->token == T_COMMA)
+      {  get_token(mpl /* , */);
+         if (mpl->token == T_SEMICOLON) goto err;
+      }
+      if (mpl->token == T_LT || mpl->token == T_LE ||
+          mpl->token == T_EQ || mpl->token == T_GE ||
+          mpl->token == T_GT || mpl->token == T_NE)
+      {  /* it is another relational operator, therefore the constraint
+            is double inequality */
+         if (rho == T_EQ || mpl->token != rho)
+            error(mpl, "double inequality must be ... <= ... <= ... or "
+               "... >= ... >= ...");
+         /* the first expression cannot be linear form */
+         if (first->type == A_FORMULA)
+            error(mpl, "leftmost expression in double inequality cannot"
+               " be linear form");
+         get_token(mpl /* rho */);
+         /* parse the third expression */
+         third = expression_5(mpl);
+         if (third->type == A_SYMBOLIC)
+            third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
+         if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
+            error(mpl, "rightmost expression in double inequality const"
+               "raint has invalid type");
+         xassert(third->dim == 0);
+         /* the third expression also cannot be linear form */
+         if (third->type == A_FORMULA)
+            error(mpl, "rightmost expression in double inequality canno"
+               "t be linear form");
+      }
+      else
+      {  /* the constraint is equality or single inequality */
+         third = NULL;
+      }
+      /* close the domain scope */
+      if (con->domain != NULL) close_scope(mpl, con->domain);
+      /* convert all expressions to linear form, if necessary */
+      if (first->type != A_FORMULA)
+         first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
+      if (second->type != A_FORMULA)
+         second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
+      if (third != NULL)
+         third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
+      /* arrange expressions in the constraint */
+      if (third == NULL)
+      {  /* the constraint is equality or single inequality */
+         switch (rho)
+         {  case T_LE:
+               /* first <= second */
+               con->code = first;
+               con->lbnd = NULL;
+               con->ubnd = second;
+               break;
+            case T_GE:
+               /* first >= second */
+               con->code = first;
+               con->lbnd = second;
+               con->ubnd = NULL;
+               break;
+            case T_EQ:
+               /* first = second */
+               con->code = first;
+               con->lbnd = second;
+               con->ubnd = second;
+               break;
+            default:
+               xassert(rho != rho);
+         }
+      }
+      else
+      {  /* the constraint is double inequality */
+         switch (rho)
+         {  case T_LE:
+               /* first <= second <= third */
+               con->code = second;
+               con->lbnd = first;
+               con->ubnd = third;
+               break;
+            case T_GE:
+               /* first >= second >= third */
+               con->code = second;
+               con->lbnd = third;
+               con->ubnd = first;
+               break;
+            default:
+               xassert(rho != rho);
+         }
+      }
+      /* the constraint statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+err:     error(mpl, "syntax error in constraint statement");
+      get_token(mpl /* ; */);
+      return con;
+}
+
+/*----------------------------------------------------------------------
+-- objective_statement - parse objective statement.
+--
+-- This routine parses objective statement using the syntax:
+--
+-- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
+--                           <formula> ;
+-- <verb> ::= minimize
+-- <verb> ::= maximize
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <formula> ::= <expression 5> */
+
+CONSTRAINT *objective_statement(MPL *mpl)
+{     CONSTRAINT *obj;
+      int type;
+      if (is_keyword(mpl, "minimize"))
+         type = A_MINIMIZE;
+      else if (is_keyword(mpl, "maximize"))
+         type = A_MAXIMIZE;
+      else
+         xassert(mpl != mpl);
+      if (mpl->flag_s)
+         error(mpl, "objective statement must precede solve statement");
+      get_token(mpl /* minimize | maximize */);
+      /* symbolic name must follow the verb 'minimize' or 'maximize' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model objective */
+      obj = alloc(CONSTRAINT);
+      obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(obj->name, mpl->image);
+      obj->alias = NULL;
+      obj->dim = 0;
+      obj->domain = NULL;
+      obj->type = type;
+      obj->code = NULL;
+      obj->lbnd = NULL;
+      obj->ubnd = NULL;
+      obj->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(obj->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  obj->domain = indexing_expression(mpl);
+         obj->dim = domain_arity(mpl, obj->domain);
+      }
+      /* include the constraint name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, obj->name);
+         avl_set_node_type(node, A_CONSTRAINT);
+         avl_set_node_link(node, (void *)obj);
+      }
+      /* the colon must precede the objective expression */
+      if (mpl->token != T_COLON)
+         error(mpl, "colon missing where expected");
+      get_token(mpl /* : */);
+      /* parse the objective expression */
+      obj->code = expression_5(mpl);
+      if (obj->code->type == A_SYMBOLIC)
+         obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
+      if (obj->code->type == A_NUMERIC)
+         obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
+      if (obj->code->type != A_FORMULA)
+         error(mpl, "expression following colon has invalid type");
+      xassert(obj->code->dim == 0);
+      /* close the domain scope */
+      if (obj->domain != NULL) close_scope(mpl, obj->domain);
+      /* the objective statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in objective statement");
+      get_token(mpl /* ; */);
+      return obj;
+}
+
+#if 1 /* 11/II-2008 */
+/***********************************************************************
+*  table_statement - parse table statement
+*
+*  This routine parses table statement using the syntax:
+*
+*  <table statement> ::= <input table statement>
+*  <table statement> ::= <output table statement>
+*
+*  <input table statement> ::=
+*        table <table name> <alias> IN <argument list> :
+*        <input set> [ <field list> ] , <input list> ;
+*  <alias> ::= <empty>
+*  <alias> ::= <string literal>
+*  <argument list> ::= <expression 5>
+*  <argument list> ::= <argument list> <expression 5>
+*  <argument list> ::= <argument list> , <expression 5>
+*  <input set> ::= <empty>
+*  <input set> ::= <set name> <-
+*  <field list> ::= <field name>
+*  <field list> ::= <field list> , <field name>
+*  <input list> ::= <input item>
+*  <input list> ::= <input list> , <input item>
+*  <input item> ::= <parameter name>
+*  <input item> ::= <parameter name> ~ <field name>
+*
+*  <output table statement> ::=
+*        table <table name> <alias> <domain> OUT <argument list> :
+*        <output list> ;
+*  <domain> ::= <indexing expression>
+*  <output list> ::= <output item>
+*  <output list> ::= <output list> , <output item>
+*  <output item> ::= <expression 5>
+*  <output item> ::= <expression 5> ~ <field name> */
+
+TABLE *table_statement(MPL *mpl)
+{     TABLE *tab;
+      TABARG *last_arg, *arg;
+      TABFLD *last_fld, *fld;
+      TABIN *last_in, *in;
+      TABOUT *last_out, *out;
+      AVLNODE *node;
+      int nflds;
+      char name[MAX_LENGTH+1];
+      xassert(is_keyword(mpl, "table"));
+      get_token(mpl /* solve */);
+      /* symbolic name must follow the keyword table */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create data table */
+      tab = alloc(TABLE);
+      tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(tab->name, mpl->image);
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(tab->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      else
+         tab->alias = NULL;
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  /* this is output table */
+         tab->type = A_OUTPUT;
+         tab->u.out.domain = indexing_expression(mpl);
+         if (!is_keyword(mpl, "OUT"))
+            error(mpl, "keyword OUT missing where expected");
+         get_token(mpl /* OUT */);
+      }
+      else
+      {  /* this is input table */
+         tab->type = A_INPUT;
+         if (!is_keyword(mpl, "IN"))
+            error(mpl, "keyword IN missing where expected");
+         get_token(mpl /* IN */);
+      }
+      /* parse argument list */
+      tab->arg = last_arg = NULL;
+      for (;;)
+      {  /* create argument list entry */
+         arg = alloc(TABARG);
+         /* parse argument expression */
+         if (mpl->token == T_COMMA || mpl->token == T_COLON ||
+             mpl->token == T_SEMICOLON)
+            error(mpl, "argument expression missing where expected");
+         arg->code = expression_5(mpl);
+         /* convert the result to symbolic type, if necessary */
+         if (arg->code->type == A_NUMERIC)
+            arg->code =
+               make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
+         /* check that now the result is of symbolic type */
+         if (arg->code->type != A_SYMBOLIC)
+            error(mpl, "argument expression has invalid type");
+         /* add the entry to the end of the list */
+         arg->next = NULL;
+         if (last_arg == NULL)
+            tab->arg = arg;
+         else
+            last_arg->next = arg;
+         last_arg = arg;
+         /* argument expression has been parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
+            break;
+      }
+      xassert(tab->arg != NULL);
+      /* argument list must end with colon */
+      if (mpl->token == T_COLON)
+         get_token(mpl /* : */);
+      else
+         error(mpl, "colon missing where expected");
+      /* parse specific part of the table statement */
+      switch (tab->type)
+      {  case A_INPUT:  goto input_table;
+         case A_OUTPUT: goto output_table;
+         default:       xassert(tab != tab);
+      }
+input_table:
+      /* parse optional set name */
+      if (mpl->token == T_NAME)
+      {  node = avl_find_node(mpl->tree, mpl->image);
+         if (node == NULL)
+            error(mpl, "%s not defined", mpl->image);
+         if (avl_get_node_type(node) != A_SET)
+            error(mpl, "%s not a set", mpl->image);
+         tab->u.in.set = (SET *)avl_get_node_link(node);
+         if (tab->u.in.set->assign != NULL)
+            error(mpl, "%s needs no data", mpl->image);
+         if (tab->u.in.set->dim != 0)
+            error(mpl, "%s must be a simple set", mpl->image);
+         get_token(mpl /* <symbolic name> */);
+         if (mpl->token == T_INPUT)
+            get_token(mpl /* <- */);
+         else
+            error(mpl, "delimiter <- missing where expected");
+      }
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         tab->u.in.set = NULL;
+      /* parse field list */
+      tab->u.in.fld = last_fld = NULL;
+      nflds = 0;
+      if (mpl->token == T_LBRACKET)
+         get_token(mpl /* [ */);
+      else
+         error(mpl, "field list missing where expected");
+      for (;;)
+      {  /* create field list entry */
+         fld = alloc(TABFLD);
+         /* parse field name */
+         if (mpl->token == T_NAME)
+            ;
+         else if (is_reserved(mpl))
+            error(mpl,
+               "invalid use of reserved keyword %s", mpl->image);
+         else
+            error(mpl, "field name missing where expected");
+         fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(fld->name, mpl->image);
+         get_token(mpl /* <symbolic name> */);
+         /* add the entry to the end of the list */
+         fld->next = NULL;
+         if (last_fld == NULL)
+            tab->u.in.fld = fld;
+         else
+            last_fld->next = fld;
+         last_fld = fld;
+         nflds++;
+         /* field name has been parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RBRACKET)
+            break;
+         else
+            error(mpl, "syntax error in field list");
+      }
+      /* check that the set dimen is equal to the number of fields */
+      if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
+         error(mpl, "there must be %d field%s rather than %d",
+            tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
+            nflds);
+      get_token(mpl /* ] */);
+      /* parse optional input list */
+      tab->u.in.list = last_in = NULL;
+      while (mpl->token == T_COMMA)
+      {  get_token(mpl /* , */);
+         /* create input list entry */
+         in = alloc(TABIN);
+         /* parse parameter name */
+         if (mpl->token == T_NAME)
+            ;
+         else if (is_reserved(mpl))
+            error(mpl,
+               "invalid use of reserved keyword %s", mpl->image);
+         else
+            error(mpl, "parameter name missing where expected");
+         node = avl_find_node(mpl->tree, mpl->image);
+         if (node == NULL)
+            error(mpl, "%s not defined", mpl->image);
+         if (avl_get_node_type(node) != A_PARAMETER)
+            error(mpl, "%s not a parameter", mpl->image);
+         in->par = (PARAMETER *)avl_get_node_link(node);
+         if (in->par->dim != nflds)
+            error(mpl, "%s must have %d subscript%s rather than %d",
+               mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
+         if (in->par->assign != NULL)
+            error(mpl, "%s needs no data", mpl->image);
+         get_token(mpl /* <symbolic name> */);
+         /* parse optional field name */
+         if (mpl->token == T_TILDE)
+         {  get_token(mpl /* ~ */);
+            /* parse field name */
+            if (mpl->token == T_NAME)
+               ;
+            else if (is_reserved(mpl))
+               error(mpl,
+                  "invalid use of reserved keyword %s", mpl->image);
+            else
+               error(mpl, "field name missing where expected");
+            xassert(strlen(mpl->image) < sizeof(name));
+            strcpy(name, mpl->image);
+            get_token(mpl /* <symbolic name> */);
+         }
+         else
+         {  /* field name is the same as the parameter name */
+            xassert(strlen(in->par->name) < sizeof(name));
+            strcpy(name, in->par->name);
+         }
+         /* assign field name */
+         in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
+         strcpy(in->name, name);
+         /* add the entry to the end of the list */
+         in->next = NULL;
+         if (last_in == NULL)
+            tab->u.in.list = in;
+         else
+            last_in->next = in;
+         last_in = in;
+      }
+      goto end_of_table;
+output_table:
+      /* parse output list */
+      tab->u.out.list = last_out = NULL;
+      for (;;)
+      {  /* create output list entry */
+         out = alloc(TABOUT);
+         /* parse expression */
+         if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
+            error(mpl, "expression missing where expected");
+         if (mpl->token == T_NAME)
+         {  xassert(strlen(mpl->image) < sizeof(name));
+            strcpy(name, mpl->image);
+         }
+         else
+            name[0] = '\0';
+         out->code = expression_5(mpl);
+         /* parse optional field name */
+         if (mpl->token == T_TILDE)
+         {  get_token(mpl /* ~ */);
+            /* parse field name */
+            if (mpl->token == T_NAME)
+               ;
+            else if (is_reserved(mpl))
+               error(mpl,
+                  "invalid use of reserved keyword %s", mpl->image);
+            else
+               error(mpl, "field name missing where expected");
+            xassert(strlen(mpl->image) < sizeof(name));
+            strcpy(name, mpl->image);
+            get_token(mpl /* <symbolic name> */);
+         }
+         /* assign field name */
+         if (name[0] == '\0')
+            error(mpl, "field name required");
+         out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
+         strcpy(out->name, name);
+         /* add the entry to the end of the list */
+         out->next = NULL;
+         if (last_out == NULL)
+            tab->u.out.list = out;
+         else
+            last_out->next = out;
+         last_out = out;
+         /* output item has been parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         else
+            error(mpl, "syntax error in output list");
+      }
+      /* close the domain scope */
+      close_scope(mpl,tab->u.out.domain);
+end_of_table:
+      /* the table statement must end with semicolon */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in table statement");
+      get_token(mpl /* ; */);
+      return tab;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- solve_statement - parse solve statement.
+--
+-- This routine parses solve statement using the syntax:
+--
+-- <solve statement> ::= solve ;
+--
+-- The solve statement can be used at most once. */
+
+void *solve_statement(MPL *mpl)
+{     xassert(is_keyword(mpl, "solve"));
+      if (mpl->flag_s)
+         error(mpl, "at most one solve statement allowed");
+      mpl->flag_s = 1;
+      get_token(mpl /* solve */);
+      /* semicolon must follow solve statement */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in solve statement");
+      get_token(mpl /* ; */);
+      return NULL;
+}
+
+/*----------------------------------------------------------------------
+-- check_statement - parse check statement.
+--
+-- This routine parses check statement using the syntax:
+--
+-- <check statement> ::= check <domain> : <expression 13> ;
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+--
+-- If <domain> is omitted, colon following it may also be omitted. */
+
+CHECK *check_statement(MPL *mpl)
+{     CHECK *chk;
+      xassert(is_keyword(mpl, "check"));
+      /* create check descriptor */
+      chk = alloc(CHECK);
+      chk->domain = NULL;
+      chk->code = NULL;
+      get_token(mpl /* check */);
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  chk->domain = indexing_expression(mpl);
+#if 0
+         if (mpl->token != T_COLON)
+            error(mpl, "colon missing where expected");
+#endif
+      }
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse logical expression */
+      chk->code = expression_13(mpl);
+      if (chk->code->type != A_LOGICAL)
+         error(mpl, "expression has invalid type");
+      xassert(chk->code->dim == 0);
+      /* close the domain scope */
+      if (chk->domain != NULL) close_scope(mpl, chk->domain);
+      /* the check statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in check statement");
+      get_token(mpl /* ; */);
+      return chk;
+}
+
+#if 1 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- display_statement - parse display statement.
+--
+-- This routine parses display statement using the syntax:
+--
+-- <display statement> ::= display <domain> : <display list> ;
+-- <display statement> ::= display <domain> <display list> ;
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <display list> ::= <display entry>
+-- <display list> ::= <display list> , <display entry>
+-- <display entry> ::= <dummy index>
+-- <display entry> ::= <set name>
+-- <display entry> ::= <set name> [ <subscript list> ]
+-- <display entry> ::= <parameter name>
+-- <display entry> ::= <parameter name> [ <subscript list> ]
+-- <display entry> ::= <variable name>
+-- <display entry> ::= <variable name> [ <subscript list> ]
+-- <display entry> ::= <constraint name>
+-- <display entry> ::= <constraint name> [ <subscript list> ]
+-- <display entry> ::= <expression 13> */
+
+DISPLAY *display_statement(MPL *mpl)
+{     DISPLAY *dpy;
+      DISPLAY1 *entry, *last_entry;
+      xassert(is_keyword(mpl, "display"));
+      /* create display descriptor */
+      dpy = alloc(DISPLAY);
+      dpy->domain = NULL;
+      dpy->list = last_entry = NULL;
+      get_token(mpl /* display */);
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+         dpy->domain = indexing_expression(mpl);
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse display list */
+      for (;;)
+      {  /* create new display entry */
+         entry = alloc(DISPLAY1);
+         entry->type = 0;
+         entry->next = NULL;
+         /* and append it to the display list */
+         if (dpy->list == NULL)
+            dpy->list = entry;
+         else
+            last_entry->next = entry;
+         last_entry = entry;
+         /* parse display entry */
+         if (mpl->token == T_NAME)
+         {  AVLNODE *node;
+            int next_token;
+            get_token(mpl /* <symbolic name> */);
+            next_token = mpl->token;
+            unget_token(mpl);
+            if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
+            {  /* symbolic name begins expression */
+               goto expr;
+            }
+            /* display entry is dummy index or model object */
+            node = avl_find_node(mpl->tree, mpl->image);
+            if (node == NULL)
+               error(mpl, "%s not defined", mpl->image);
+            entry->type = avl_get_node_type(node);
+            switch (avl_get_node_type(node))
+            {  case A_INDEX:
+                  entry->u.slot =
+                     (DOMAIN_SLOT *)avl_get_node_link(node);
+                  break;
+               case A_SET:
+                  entry->u.set = (SET *)avl_get_node_link(node);
+                  break;
+               case A_PARAMETER:
+                  entry->u.par = (PARAMETER *)avl_get_node_link(node);
+                  break;
+               case A_VARIABLE:
+                  entry->u.var = (VARIABLE *)avl_get_node_link(node);
+                  if (!mpl->flag_s)
+                     error(mpl, "invalid reference to variable %s above"
+                        " solve statement", entry->u.var->name);
+                  break;
+               case A_CONSTRAINT:
+                  entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
+                  if (!mpl->flag_s)
+                     error(mpl, "invalid reference to %s %s above solve"
+                        " statement",
+                        entry->u.con->type == A_CONSTRAINT ?
+                        "constraint" : "objective", entry->u.con->name);
+                  break;
+               default:
+                  xassert(node != node);
+            }
+            get_token(mpl /* <symbolic name> */);
+         }
+         else
+expr:    {  /* display entry is expression */
+            entry->type = A_EXPRESSION;
+            entry->u.code = expression_13(mpl);
+         }
+         /* check a token that follows the entry parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else
+            break;
+      }
+      /* close the domain scope */
+      if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
+      /* the display statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in display statement");
+      get_token(mpl /* ; */);
+      return dpy;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- printf_statement - parse printf statement.
+--
+-- This routine parses print statement using the syntax:
+--
+-- <printf statement> ::= <printf clause> ;
+-- <printf statement> ::= <printf clause> > <file name> ;
+-- <printf statement> ::= <printf clause> >> <file name> ;
+-- <printf clause> ::= printf <domain> : <format> <printf list>
+-- <printf clause> ::= printf <domain> <format> <printf list>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <format> ::= <expression 5>
+-- <printf list> ::= <empty>
+-- <printf list> ::= <printf list> , <printf entry>
+-- <printf entry> ::= <expression 9>
+-- <file name> ::= <expression 5> */
+
+PRINTF *printf_statement(MPL *mpl)
+{     PRINTF *prt;
+      PRINTF1 *entry, *last_entry;
+      xassert(is_keyword(mpl, "printf"));
+      /* create printf descriptor */
+      prt = alloc(PRINTF);
+      prt->domain = NULL;
+      prt->fmt = NULL;
+      prt->list = last_entry = NULL;
+      get_token(mpl /* printf */);
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  prt->domain = indexing_expression(mpl);
+#if 0
+         if (mpl->token != T_COLON)
+            error(mpl, "colon missing where expected");
+#endif
+      }
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse expression for format string */
+      prt->fmt = expression_5(mpl);
+      /* convert it to symbolic type, if necessary */
+      if (prt->fmt->type == A_NUMERIC)
+         prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
+      /* check that now the expression is of symbolic type */
+      if (prt->fmt->type != A_SYMBOLIC)
+         error(mpl, "format expression has invalid type");
+      /* parse printf list */
+      while (mpl->token == T_COMMA)
+      {  get_token(mpl /* , */);
+         /* create new printf entry */
+         entry = alloc(PRINTF1);
+         entry->code = NULL;
+         entry->next = NULL;
+         /* and append it to the printf list */
+         if (prt->list == NULL)
+            prt->list = entry;
+         else
+            last_entry->next = entry;
+         last_entry = entry;
+         /* parse printf entry */
+         entry->code = expression_9(mpl);
+         if (!(entry->code->type == A_NUMERIC ||
+               entry->code->type == A_SYMBOLIC ||
+               entry->code->type == A_LOGICAL))
+            error(mpl, "only numeric, symbolic, or logical expression a"
+               "llowed");
+      }
+      /* close the domain scope */
+      if (prt->domain != NULL) close_scope(mpl, prt->domain);
+#if 1 /* 14/VII-2006 */
+      /* parse optional redirection */
+      prt->fname = NULL, prt->app = 0;
+      if (mpl->token == T_GT || mpl->token == T_APPEND)
+      {  prt->app = (mpl->token == T_APPEND);
+         get_token(mpl /* > or >> */);
+         /* parse expression for file name string */
+         prt->fname = expression_5(mpl);
+         /* convert it to symbolic type, if necessary */
+         if (prt->fname->type == A_NUMERIC)
+            prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
+               A_SYMBOLIC, 0);
+         /* check that now the expression is of symbolic type */
+         if (prt->fname->type != A_SYMBOLIC)
+            error(mpl, "file name expression has invalid type");
+      }
+#endif
+      /* the printf statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in printf statement");
+      get_token(mpl /* ; */);
+      return prt;
+}
+
+/*----------------------------------------------------------------------
+-- for_statement - parse for statement.
+--
+-- This routine parses for statement using the syntax:
+--
+-- <for statement> ::= for <domain> <statement>
+-- <for statement> ::= for <domain> { <statement list> }
+-- <domain> ::= <indexing expression>
+-- <statement list> ::= <empty>
+-- <statement list> ::= <statement list> <statement>
+-- <statement> ::= <check statement>
+-- <statement> ::= <display statement>
+-- <statement> ::= <printf statement>
+-- <statement> ::= <for statement> */
+
+FOR *for_statement(MPL *mpl)
+{     FOR *fur;
+      STATEMENT *stmt, *last_stmt;
+      xassert(is_keyword(mpl, "for"));
+      /* create for descriptor */
+      fur = alloc(FOR);
+      fur->domain = NULL;
+      fur->list = last_stmt = NULL;
+      get_token(mpl /* for */);
+      /* parse indexing expression */
+      if (mpl->token != T_LBRACE)
+         error(mpl, "indexing expression missing where expected");
+      fur->domain = indexing_expression(mpl);
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse for statement body */
+      if (mpl->token != T_LBRACE)
+      {  /* parse simple statement */
+         fur->list = simple_statement(mpl, 1);
+      }
+      else
+      {  /* parse compound statement */
+         get_token(mpl /* { */);
+         while (mpl->token != T_RBRACE)
+         {  /* parse statement */
+            stmt = simple_statement(mpl, 1);
+            /* and append it to the end of the statement list */
+            if (last_stmt == NULL)
+               fur->list = stmt;
+            else
+               last_stmt->next = stmt;
+            last_stmt = stmt;
+         }
+         get_token(mpl /* } */);
+      }
+      /* close the domain scope */
+      xassert(fur->domain != NULL);
+      close_scope(mpl, fur->domain);
+      /* the for statement has been completely parsed */
+      return fur;
+}
+
+/*----------------------------------------------------------------------
+-- end_statement - parse end statement.
+--
+-- This routine parses end statement using the syntax:
+--
+-- <end statement> ::= end ; <eof> */
+
+void end_statement(MPL *mpl)
+{     if (!mpl->flag_d && is_keyword(mpl, "end") ||
+           mpl->flag_d && is_literal(mpl, "end"))
+      {  get_token(mpl /* end */);
+         if (mpl->token == T_SEMICOLON)
+            get_token(mpl /* ; */);
+         else
+            warning(mpl, "no semicolon following end statement; missing"
+               " semicolon inserted");
+      }
+      else
+         warning(mpl, "unexpected end of file; missing end statement in"
+            "serted");
+      if (mpl->token != T_EOF)
+         warning(mpl, "some text detected beyond end statement; text ig"
+            "nored");
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- simple_statement - parse simple statement.
+--
+-- This routine parses simple statement using the syntax:
+--
+-- <statement> ::= <set statement>
+-- <statement> ::= <parameter statement>
+-- <statement> ::= <variable statement>
+-- <statement> ::= <constraint statement>
+-- <statement> ::= <objective statement>
+-- <statement> ::= <solve statement>
+-- <statement> ::= <check statement>
+-- <statement> ::= <display statement>
+-- <statement> ::= <printf statement>
+-- <statement> ::= <for statement>
+--
+-- If the flag spec is set, some statements cannot be used. */
+
+STATEMENT *simple_statement(MPL *mpl, int spec)
+{     STATEMENT *stmt;
+      stmt = alloc(STATEMENT);
+      stmt->line = mpl->line;
+      stmt->next = NULL;
+      if (is_keyword(mpl, "set"))
+      {  if (spec)
+            error(mpl, "set statement not allowed here");
+         stmt->type = A_SET;
+         stmt->u.set = set_statement(mpl);
+      }
+      else if (is_keyword(mpl, "param"))
+      {  if (spec)
+            error(mpl, "parameter statement not allowed here");
+         stmt->type = A_PARAMETER;
+         stmt->u.par = parameter_statement(mpl);
+      }
+      else if (is_keyword(mpl, "var"))
+      {  if (spec)
+            error(mpl, "variable statement not allowed here");
+         stmt->type = A_VARIABLE;
+         stmt->u.var = variable_statement(mpl);
+      }
+      else if (is_keyword(mpl, "subject") ||
+               is_keyword(mpl, "subj") ||
+               mpl->token == T_SPTP)
+      {  if (spec)
+            error(mpl, "constraint statement not allowed here");
+         stmt->type = A_CONSTRAINT;
+         stmt->u.con = constraint_statement(mpl);
+      }
+      else if (is_keyword(mpl, "minimize") ||
+               is_keyword(mpl, "maximize"))
+      {  if (spec)
+            error(mpl, "objective statement not allowed here");
+         stmt->type = A_CONSTRAINT;
+         stmt->u.con = objective_statement(mpl);
+      }
+#if 1 /* 11/II-2008 */
+      else if (is_keyword(mpl, "table"))
+      {  if (spec)
+            error(mpl, "table statement not allowed here");
+         stmt->type = A_TABLE;
+         stmt->u.tab = table_statement(mpl);
+      }
+#endif
+      else if (is_keyword(mpl, "solve"))
+      {  if (spec)
+            error(mpl, "solve statement not allowed here");
+         stmt->type = A_SOLVE;
+         stmt->u.slv = solve_statement(mpl);
+      }
+      else if (is_keyword(mpl, "check"))
+      {  stmt->type = A_CHECK;
+         stmt->u.chk = check_statement(mpl);
+      }
+      else if (is_keyword(mpl, "display"))
+      {  stmt->type = A_DISPLAY;
+         stmt->u.dpy = display_statement(mpl);
+      }
+      else if (is_keyword(mpl, "printf"))
+      {  stmt->type = A_PRINTF;
+         stmt->u.prt = printf_statement(mpl);
+      }
+      else if (is_keyword(mpl, "for"))
+      {  stmt->type = A_FOR;
+         stmt->u.fur = for_statement(mpl);
+      }
+      else if (mpl->token == T_NAME)
+      {  if (spec)
+            error(mpl, "constraint statement not allowed here");
+         stmt->type = A_CONSTRAINT;
+         stmt->u.con = constraint_statement(mpl);
+      }
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "syntax error in model section");
+      return stmt;
+}
+
+/*----------------------------------------------------------------------
+-- model_section - parse model section.
+--
+-- This routine parses model section using the syntax:
+--
+-- <model section> ::= <empty>
+-- <model section> ::= <model section> <statement>
+--
+-- Parsing model section is terminated by either the keyword 'data', or
+-- the keyword 'end', or the end of file. */
+
+void model_section(MPL *mpl)
+{     STATEMENT *stmt, *last_stmt;
+      xassert(mpl->model == NULL);
+      last_stmt = NULL;
+      while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
+               is_keyword(mpl, "end")))
+      {  /* parse statement */
+         stmt = simple_statement(mpl, 0);
+         /* and append it to the end of the statement list */
+         if (last_stmt == NULL)
+            mpl->model = stmt;
+         else
+            last_stmt->next = stmt;
+         last_stmt = stmt;
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmpl02.c b/optional/glpk/glpmpl02.c
new file mode 100644
index 0000000..e58b41d
--- /dev/null
+++ b/optional/glpk/glpmpl02.c
@@ -0,0 +1,1205 @@
+/* glpmpl02.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glpmpl.h"
+
+/**********************************************************************/
+/* * *                  PROCESSING DATA SECTION                   * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_slice - create slice.
+--
+-- This routine creates a slice, which initially has no components. */
+
+SLICE *create_slice(MPL *mpl)
+{     SLICE *slice;
+      xassert(mpl == mpl);
+      slice = NULL;
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- expand_slice - append new component to slice.
+--
+-- This routine expands slice appending to it either a given symbol or
+-- null component, which becomes the last component of the slice. */
+
+SLICE *expand_slice
+(     MPL *mpl,
+      SLICE *slice,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+)
+{     SLICE *tail, *temp;
+      /* create a new component */
+      tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
+      tail->sym = sym;
+      tail->next = NULL;
+      /* and append it to the component list */
+      if (slice == NULL)
+         slice = tail;
+      else
+      {  for (temp = slice; temp->next != NULL; temp = temp->next);
+         temp->next = tail;
+      }
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- slice_dimen - determine dimension of slice.
+--
+-- This routine returns dimension of slice, which is number of all its
+-- components including null ones. */
+
+int slice_dimen
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+)
+{     SLICE *temp;
+      int dim;
+      xassert(mpl == mpl);
+      dim = 0;
+      for (temp = slice; temp != NULL; temp = temp->next) dim++;
+      return dim;
+}
+
+/*----------------------------------------------------------------------
+-- slice_arity - determine arity of slice.
+--
+-- This routine returns arity of slice, i.e. number of null components
+-- (indicated by asterisks) in the slice. */
+
+int slice_arity
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+)
+{     SLICE *temp;
+      int arity;
+      xassert(mpl == mpl);
+      arity = 0;
+      for (temp = slice; temp != NULL; temp = temp->next)
+         if (temp->sym == NULL) arity++;
+      return arity;
+}
+
+/*----------------------------------------------------------------------
+-- fake_slice - create fake slice of all asterisks.
+--
+-- This routine creates a fake slice of given dimension, which contains
+-- asterisks in all components. Zero dimension is allowed. */
+
+SLICE *fake_slice(MPL *mpl, int dim)
+{     SLICE *slice;
+      slice = create_slice(mpl);
+      while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- delete_slice - delete slice.
+--
+-- This routine deletes specified slice. */
+
+void delete_slice
+(     MPL *mpl,
+      SLICE *slice            /* destroyed */
+)
+{     SLICE *temp;
+      while (slice != NULL)
+      {  temp = slice;
+         slice = temp->next;
+         if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
+xassert(sizeof(SLICE) == sizeof(TUPLE));
+         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- is_number - check if current token is number.
+--
+-- If the current token is a number, this routine returns non-zero.
+-- Otherwise zero is returned. */
+
+int is_number(MPL *mpl)
+{     return
+         mpl->token == T_NUMBER;
+}
+
+/*----------------------------------------------------------------------
+-- is_symbol - check if current token is symbol.
+--
+-- If the current token is suitable to be a symbol, the routine returns
+-- non-zero. Otherwise zero is returned. */
+
+int is_symbol(MPL *mpl)
+{     return
+         mpl->token == T_NUMBER ||
+         mpl->token == T_SYMBOL ||
+         mpl->token == T_STRING;
+}
+
+/*----------------------------------------------------------------------
+-- is_literal - check if current token is given symbolic literal.
+--
+-- If the current token is given symbolic literal, this routine returns
+-- non-zero. Otherwise zero is returned.
+--
+-- This routine is used on processing the data section in the same way
+-- as the routine is_keyword on processing the model section. */
+
+int is_literal(MPL *mpl, char *literal)
+{     return
+         is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
+}
+
+/*----------------------------------------------------------------------
+-- read_number - read number.
+--
+-- This routine reads the current token, which must be a number, and
+-- returns its numeric value. */
+
+double read_number(MPL *mpl)
+{     double num;
+      xassert(is_number(mpl));
+      num = mpl->value;
+      get_token(mpl /* <number> */);
+      return num;
+}
+
+/*----------------------------------------------------------------------
+-- read_symbol - read symbol.
+--
+-- This routine reads the current token, which must be a symbol, and
+-- returns its symbolic value. */
+
+SYMBOL *read_symbol(MPL *mpl)
+{     SYMBOL *sym;
+      xassert(is_symbol(mpl));
+      if (is_number(mpl))
+         sym = create_symbol_num(mpl, mpl->value);
+      else
+         sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
+      get_token(mpl /* <symbol> */);
+      return sym;
+}
+
+/*----------------------------------------------------------------------
+-- read_slice - read slice.
+--
+-- This routine reads slice using the syntax:
+--
+-- <slice> ::= [ <symbol list> ]
+-- <slice> ::= ( <symbol list> )
+-- <symbol list> ::= <symbol or star>
+-- <symbol list> ::= <symbol list> , <symbol or star>
+-- <symbol or star> ::= <symbol>
+-- <symbol or star> ::= *
+--
+-- The bracketed form of slice is used for members of multi-dimensional
+-- objects while the parenthesized form is used for elemental sets. */
+
+SLICE *read_slice
+(     MPL *mpl,
+      char *name,             /* not changed */
+      int dim
+)
+{     SLICE *slice;
+      int close;
+      xassert(name != NULL);
+      switch (mpl->token)
+      {  case T_LBRACKET:
+            close = T_RBRACKET;
+            break;
+         case T_LEFT:
+            xassert(dim > 0);
+            close = T_RIGHT;
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      if (dim == 0)
+         error(mpl, "%s cannot be subscripted", name);
+      get_token(mpl /* ( | [ */);
+      /* read slice components */
+      slice = create_slice(mpl);
+      for (;;)
+      {  /* the current token must be a symbol or asterisk */
+         if (is_symbol(mpl))
+            slice = expand_slice(mpl, slice, read_symbol(mpl));
+         else if (mpl->token == T_ASTERISK)
+         {  slice = expand_slice(mpl, slice, NULL);
+            get_token(mpl /* * */);
+         }
+         else
+            error(mpl, "number, symbol, or asterisk missing where expec"
+               "ted");
+         /* check a token that follows the symbol */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == close)
+            break;
+         else
+            error(mpl, "syntax error in slice");
+      }
+      /* number of slice components must be the same as the appropriate
+         dimension */
+      if (slice_dimen(mpl, slice) != dim)
+      {  switch (close)
+         {  case T_RBRACKET:
+               error(mpl, "%s must have %d subscript%s, not %d", name,
+                  dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
+               break;
+            case T_RIGHT:
+               error(mpl, "%s has dimension %d, not %d", name, dim,
+                  slice_dimen(mpl, slice));
+               break;
+            default:
+               xassert(close != close);
+         }
+      }
+      get_token(mpl /* ) | ] */);
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- select_set - select set to saturate it with elemental sets.
+--
+-- This routine selects set to saturate it with elemental sets provided
+-- in the data section. */
+
+SET *select_set
+(     MPL *mpl,
+      char *name              /* not changed */
+)
+{     SET *set;
+      AVLNODE *node;
+      xassert(name != NULL);
+      node = avl_find_node(mpl->tree, name);
+      if (node == NULL || avl_get_node_type(node) != A_SET)
+         error(mpl, "%s not a set", name);
+      set = (SET *)avl_get_node_link(node);
+      if (set->assign != NULL || set->gadget != NULL)
+         error(mpl, "%s needs no data", name);
+      set->data = 1;
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- simple_format - read set data block in simple format.
+--
+-- This routine reads set data block using the syntax:
+--
+-- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
+--
+-- where <symbols> are used to construct a complete n-tuple, which is
+-- included in elemental set assigned to the set member. Commae between
+-- symbols are optional and may be omitted anywhere.
+--
+-- Number of components in the slice must be the same as dimension of
+-- n-tuples in elemental sets assigned to the set members. To construct
+-- complete n-tuple the routine replaces null positions in the slice by
+-- corresponding <symbols>.
+--
+-- If the slice contains at least one null position, the current token
+-- must be symbol. Otherwise, the routine reads no symbols to construct
+-- the n-tuple, so the current token is not checked. */
+
+void simple_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice            /* not changed */
+)
+{     TUPLE *tuple;
+      SLICE *temp;
+      SYMBOL *sym, *with = NULL;
+      xassert(set != NULL);
+      xassert(memb != NULL);
+      xassert(slice != NULL);
+      xassert(set->dimen == slice_dimen(mpl, slice));
+      xassert(memb->value.set->dim == set->dimen);
+      if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
+      /* read symbols and construct complete n-tuple */
+      tuple = create_tuple(mpl);
+      for (temp = slice; temp != NULL; temp = temp->next)
+      {  if (temp->sym == NULL)
+         {  /* substitution is needed; read symbol */
+            if (!is_symbol(mpl))
+            {  int lack = slice_arity(mpl, temp);
+               /* with cannot be null due to assertion above */
+               xassert(with != NULL);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, with));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, with));
+            }
+            sym = read_symbol(mpl);
+            if (with == NULL) with = sym;
+         }
+         else
+         {  /* copy symbol from the slice */
+            sym = copy_symbol(mpl, temp->sym);
+         }
+         /* append the symbol to the n-tuple */
+         tuple = expand_tuple(mpl, tuple, sym);
+         /* skip optional comma *between* <symbols> */
+         if (temp->next != NULL && mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+      }
+      /* add constructed n-tuple to elemental set */
+      check_then_add(mpl, memb->value.set, tuple);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- matrix_format - read set data block in matrix format.
+--
+-- This routine reads set data block using the syntax:
+--
+-- <matrix format> ::= <column> <column> ... <column> :=
+--               <row>   +/-      +/-    ...   +/-
+--               <row>   +/-      +/-    ...   +/-
+--                 .  .  .  .  .  .  .  .  .  .  .
+--               <row>   +/-      +/-    ...   +/-
+--
+-- where <rows> are symbols that denote rows of the matrix, <columns>
+-- are symbols that denote columns of the matrix, "+" and "-" indicate
+-- whether corresponding n-tuple needs to be included in the elemental
+-- set or not, respectively.
+--
+-- Number of the slice components must be the same as dimension of the
+-- elemental set. The slice must have two null positions. To construct
+-- complete n-tuple for particular element of the matrix the routine
+-- replaces first null position of the slice by the corresponding <row>
+-- (or <column>, if the flag tr is on) and second null position by the
+-- corresponding <column> (or by <row>, if the flag tr is on). */
+
+void matrix_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice,           /* not changed */
+      int tr
+)
+{     SLICE *list, *col, *temp;
+      TUPLE *tuple;
+      SYMBOL *row;
+      xassert(set != NULL);
+      xassert(memb != NULL);
+      xassert(slice != NULL);
+      xassert(set->dimen == slice_dimen(mpl, slice));
+      xassert(memb->value.set->dim == set->dimen);
+      xassert(slice_arity(mpl, slice) == 2);
+      /* read the matrix heading that contains column symbols (there
+         may be no columns at all) */
+      list = create_slice(mpl);
+      while (mpl->token != T_ASSIGN)
+      {  /* read column symbol and append it to the column list */
+         if (!is_symbol(mpl))
+            error(mpl, "number, symbol, or := missing where expected");
+         list = expand_slice(mpl, list, read_symbol(mpl));
+      }
+      get_token(mpl /* := */);
+      /* read zero or more rows that contain matrix data */
+      while (is_symbol(mpl))
+      {  /* read row symbol (if the matrix has no columns, row symbols
+            are just ignored) */
+         row = read_symbol(mpl);
+         /* read the matrix row accordingly to the column list */
+         for (col = list; col != NULL; col = col->next)
+         {  int which = 0;
+            /* check indicator */
+            if (is_literal(mpl, "+"))
+               ;
+            else if (is_literal(mpl, "-"))
+            {  get_token(mpl /* - */);
+               continue;
+            }
+            else
+            {  int lack = slice_dimen(mpl, col);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, row));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, row));
+            }
+            /* construct complete n-tuple */
+            tuple = create_tuple(mpl);
+            for (temp = slice; temp != NULL; temp = temp->next)
+            {  if (temp->sym == NULL)
+               {  /* substitution is needed */
+                  switch (++which)
+                  {  case 1:
+                        /* substitute in the first null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? col->sym : row));
+                        break;
+                     case 2:
+                        /* substitute in the second null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? row : col->sym));
+                        break;
+                     default:
+                        xassert(which != which);
+                  }
+               }
+               else
+               {  /* copy symbol from the slice */
+                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                     temp->sym));
+               }
+            }
+            xassert(which == 2);
+            /* add constructed n-tuple to elemental set */
+            check_then_add(mpl, memb->value.set, tuple);
+            get_token(mpl /* + */);
+         }
+         /* delete the row symbol */
+         delete_symbol(mpl, row);
+      }
+      /* delete the column list */
+      delete_slice(mpl, list);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- set_data - read set data.
+--
+-- This routine reads set data using the syntax:
+--
+-- <set data> ::= set <set name> <assignments> ;
+-- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
+-- <set name> ::= <symbolic name>
+-- <assignments> ::= <empty>
+-- <assignments> ::= <assignments> , :=
+-- <assignments> ::= <assignments> , ( <symbol list> )
+-- <assignments> ::= <assignments> , <simple format>
+-- <assignments> ::= <assignments> , : <matrix format>
+-- <assignments> ::= <assignments> , (tr) <matrix format>
+-- <assignments> ::= <assignments> , (tr) : <matrix format>
+--
+-- Commae in <assignments> are optional and may be omitted anywhere. */
+
+void set_data(MPL *mpl)
+{     SET *set;
+      TUPLE *tuple;
+      MEMBER *memb;
+      SLICE *slice;
+      int tr = 0;
+      xassert(is_literal(mpl, "set"));
+      get_token(mpl /* set */);
+      /* symbolic name of set must follows the keyword 'set' */
+      if (!is_symbol(mpl))
+         error(mpl, "set name missing where expected");
+      /* select the set to saturate it with data */
+      set = select_set(mpl, mpl->image);
+      get_token(mpl /* <symbolic name> */);
+      /* read optional subscript list, which identifies member of the
+         set to be read */
+      tuple = create_tuple(mpl);
+      if (mpl->token == T_LBRACKET)
+      {  /* subscript list is specified */
+         if (set->dim == 0)
+            error(mpl, "%s cannot be subscripted", set->name);
+         get_token(mpl /* [ */);
+         /* read symbols and construct subscript list */
+         for (;;)
+         {  if (!is_symbol(mpl))
+               error(mpl, "number or symbol missing where expected");
+            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
+            if (mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+            else if (mpl->token == T_RBRACKET)
+               break;
+            else
+               error(mpl, "syntax error in subscript list");
+         }
+         if (set->dim != tuple_dimen(mpl, tuple))
+            error(mpl, "%s must have %d subscript%s rather than %d",
+               set->name, set->dim, set->dim == 1 ? "" : "s",
+               tuple_dimen(mpl, tuple));
+         get_token(mpl /* ] */);
+      }
+      else
+      {  /* subscript list is not specified */
+         if (set->dim != 0)
+            error(mpl, "%s must be subscripted", set->name);
+      }
+      /* there must be no member with the same subscript list */
+      if (find_member(mpl, set->array, tuple) != NULL)
+         error(mpl, "%s%s already defined",
+            set->name, format_tuple(mpl, '[', tuple));
+      /* add new member to the set and assign it empty elemental set */
+      memb = add_member(mpl, set->array, tuple);
+      memb->value.set = create_elemset(mpl, set->dimen);
+      /* create an initial fake slice of all asterisks */
+      slice = fake_slice(mpl, set->dimen);
+      /* read zero or more data assignments */
+      for (;;)
+      {  /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* process assignment element */
+         if (mpl->token == T_ASSIGN)
+         {  /* assignment ligature is non-significant element */
+            get_token(mpl /* := */);
+         }
+         else if (mpl->token == T_LEFT)
+         {  /* left parenthesis begins either new slice or "transpose"
+               indicator */
+            int is_tr;
+            get_token(mpl /* ( */);
+            is_tr = is_literal(mpl, "tr");
+            unget_token(mpl /* ( */);
+            if (is_tr) goto left;
+            /* delete the current slice and read new one */
+            delete_slice(mpl, slice);
+            slice = read_slice(mpl, set->name, set->dimen);
+            /* each new slice resets the "transpose" indicator */
+            tr = 0;
+            /* if the new slice is 0-ary, formally there is one 0-tuple
+               (in the simple format) that follows it */
+            if (slice_arity(mpl, slice) == 0)
+               simple_format(mpl, set, memb, slice);
+         }
+         else if (is_symbol(mpl))
+         {  /* number or symbol begins data in the simple format */
+            simple_format(mpl, set, memb, slice);
+         }
+         else if (mpl->token == T_COLON)
+         {  /* colon begins data in the matrix format */
+            if (slice_arity(mpl, slice) != 2)
+err1:          error(mpl, "slice currently used must specify 2 asterisk"
+                  "s, not %d", slice_arity(mpl, slice));
+            get_token(mpl /* : */);
+            /* read elemental set data in the matrix format */
+            matrix_format(mpl, set, memb, slice, tr);
+         }
+         else if (mpl->token == T_LEFT)
+left:    {  /* left parenthesis begins the "transpose" indicator, which
+               is followed by data in the matrix format */
+            get_token(mpl /* ( */);
+            if (!is_literal(mpl, "tr"))
+err2:          error(mpl, "transpose indicator (tr) incomplete");
+            if (slice_arity(mpl, slice) != 2) goto err1;
+            get_token(mpl /* tr */);
+            if (mpl->token != T_RIGHT) goto err2;
+            get_token(mpl /* ) */);
+            /* in this case the colon is optional */
+            if (mpl->token == T_COLON) get_token(mpl /* : */);
+            /* set the "transpose" indicator */
+            tr = 1;
+            /* read elemental set data in the matrix format */
+            matrix_format(mpl, set, memb, slice, tr);
+         }
+         else if (mpl->token == T_SEMICOLON)
+         {  /* semicolon terminates the data block */
+            get_token(mpl /* ; */);
+            break;
+         }
+         else
+            error(mpl, "syntax error in set data block");
+      }
+      /* delete the current slice */
+      delete_slice(mpl, slice);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- select_parameter - select parameter to saturate it with data.
+--
+-- This routine selects parameter to saturate it with data provided in
+-- the data section. */
+
+PARAMETER *select_parameter
+(     MPL *mpl,
+      char *name              /* not changed */
+)
+{     PARAMETER *par;
+      AVLNODE *node;
+      xassert(name != NULL);
+      node = avl_find_node(mpl->tree, name);
+      if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
+         error(mpl, "%s not a parameter", name);
+      par = (PARAMETER *)avl_get_node_link(node);
+      if (par->assign != NULL)
+         error(mpl, "%s needs no data", name);
+      if (par->data)
+         error(mpl, "%s already provided with data", name);
+      par->data = 1;
+      return par;
+}
+
+/*----------------------------------------------------------------------
+-- set_default - set default parameter value.
+--
+-- This routine sets default value for specified parameter. */
+
+void set_default
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SYMBOL *altval          /* destroyed */
+)
+{     xassert(par != NULL);
+      xassert(altval != NULL);
+      if (par->option != NULL)
+         error(mpl, "default value for %s already specified in model se"
+            "ction", par->name);
+      xassert(par->defval == NULL);
+      par->defval = altval;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- read_value - read value and assign it to parameter member.
+--
+-- This routine reads numeric or symbolic value from the input stream
+-- and assigns to new parameter member specified by its n-tuple, which
+-- (the member) is created and added to the parameter array. */
+
+MEMBER *read_value
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(par != NULL);
+      xassert(is_symbol(mpl));
+      /* there must be no member with the same n-tuple */
+      if (find_member(mpl, par->array, tuple) != NULL)
+         error(mpl, "%s%s already defined",
+            par->name, format_tuple(mpl, '[', tuple));
+      /* create new parameter member with given n-tuple */
+      memb = add_member(mpl, par->array, tuple);
+      /* read value and assigns it to the new parameter member */
+      switch (par->type)
+      {  case A_NUMERIC:
+         case A_INTEGER:
+         case A_BINARY:
+            if (!is_number(mpl))
+               error(mpl, "%s requires numeric data", par->name);
+            memb->value.num = read_number(mpl);
+            break;
+         case A_SYMBOLIC:
+            memb->value.sym = read_symbol(mpl);
+            break;
+         default:
+            xassert(par != par);
+      }
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- plain_format - read parameter data block in plain format.
+--
+-- This routine reads parameter data block using the syntax:
+--
+-- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
+--
+-- where <symbols> are used to determine a complete subscript list for
+-- parameter member, <value> is a numeric or symbolic value assigned to
+-- the parameter member. Commae between data items are optional and may
+-- be omitted anywhere.
+--
+-- Number of components in the slice must be the same as dimension of
+-- the parameter. To construct the complete subscript list the routine
+-- replaces null positions in the slice by corresponding <symbols>. */
+
+void plain_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice            /* not changed */
+)
+{     TUPLE *tuple;
+      SLICE *temp;
+      SYMBOL *sym, *with = NULL;
+      xassert(par != NULL);
+      xassert(par->dim == slice_dimen(mpl, slice));
+      xassert(is_symbol(mpl));
+      /* read symbols and construct complete subscript list */
+      tuple = create_tuple(mpl);
+      for (temp = slice; temp != NULL; temp = temp->next)
+      {  if (temp->sym == NULL)
+         {  /* substitution is needed; read symbol */
+            if (!is_symbol(mpl))
+            {  int lack = slice_arity(mpl, temp) + 1;
+               xassert(with != NULL);
+               xassert(lack > 1);
+               error(mpl, "%d items missing in data group beginning wit"
+                  "h %s", lack, format_symbol(mpl, with));
+            }
+            sym = read_symbol(mpl);
+            if (with == NULL) with = sym;
+         }
+         else
+         {  /* copy symbol from the slice */
+            sym = copy_symbol(mpl, temp->sym);
+         }
+         /* append the symbol to the subscript list */
+         tuple = expand_tuple(mpl, tuple, sym);
+         /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      }
+      /* read value and assign it to new parameter member */
+      if (!is_symbol(mpl))
+      {  xassert(with != NULL);
+         error(mpl, "one item missing in data group beginning with %s",
+            format_symbol(mpl, with));
+      }
+      read_value(mpl, par, tuple);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- tabular_format - read parameter data block in tabular format.
+--
+-- This routine reads parameter data block using the syntax:
+--
+-- <tabular format> ::= <column> <column> ... <column> :=
+--                <row> <value>  <value>  ... <value>
+--                <row> <value>  <value>  ... <value>
+--                  .  .  .  .  .  .  .  .  .  .  .
+--                <row> <value>  <value>  ... <value>
+--
+-- where <rows> are symbols that denote rows of the table, <columns>
+-- are symbols that denote columns of the table, <values> are numeric
+-- or symbolic values assigned to the corresponding parameter members.
+-- If <value> is specified as single point, no value is provided.
+--
+-- Number of components in the slice must be the same as dimension of
+-- the parameter. The slice must have two null positions. To construct
+-- complete subscript list for particular <value> the routine replaces
+-- the first null position of the slice by the corresponding <row> (or
+-- <column>, if the flag tr is on) and the second null position by the
+-- corresponding <column> (or by <row>, if the flag tr is on). */
+
+void tabular_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice,           /* not changed */
+      int tr
+)
+{     SLICE *list, *col, *temp;
+      TUPLE *tuple;
+      SYMBOL *row;
+      xassert(par != NULL);
+      xassert(par->dim == slice_dimen(mpl, slice));
+      xassert(slice_arity(mpl, slice) == 2);
+      /* read the table heading that contains column symbols (the table
+         may have no columns) */
+      list = create_slice(mpl);
+      while (mpl->token != T_ASSIGN)
+      {  /* read column symbol and append it to the column list */
+         if (!is_symbol(mpl))
+            error(mpl, "number, symbol, or := missing where expected");
+         list = expand_slice(mpl, list, read_symbol(mpl));
+      }
+      get_token(mpl /* := */);
+      /* read zero or more rows that contain tabular data */
+      while (is_symbol(mpl))
+      {  /* read row symbol (if the table has no columns, these symbols
+            are just ignored) */
+         row = read_symbol(mpl);
+         /* read values accordingly to the column list */
+         for (col = list; col != NULL; col = col->next)
+         {  int which = 0;
+            /* if the token is single point, no value is provided */
+            if (is_literal(mpl, "."))
+            {  get_token(mpl /* . */);
+               continue;
+            }
+            /* construct complete subscript list */
+            tuple = create_tuple(mpl);
+            for (temp = slice; temp != NULL; temp = temp->next)
+            {  if (temp->sym == NULL)
+               {  /* substitution is needed */
+                  switch (++which)
+                  {  case 1:
+                        /* substitute in the first null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? col->sym : row));
+                        break;
+                     case 2:
+                        /* substitute in the second null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? row : col->sym));
+                        break;
+                     default:
+                        xassert(which != which);
+                  }
+               }
+               else
+               {  /* copy symbol from the slice */
+                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                     temp->sym));
+               }
+            }
+            xassert(which == 2);
+            /* read value and assign it to new parameter member */
+            if (!is_symbol(mpl))
+            {  int lack = slice_dimen(mpl, col);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, row));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, row));
+            }
+            read_value(mpl, par, tuple);
+         }
+         /* delete the row symbol */
+         delete_symbol(mpl, row);
+      }
+      /* delete the column list */
+      delete_slice(mpl, list);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- tabbing_format - read parameter data block in tabbing format.
+--
+-- This routine reads parameter data block using the syntax:
+--
+-- <tabbing format> ::=  <prefix> <name>  , ... , <name>  , := ,
+--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
+--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
+--     .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+--    <symbol> , ... , <symbol> , <value> , ... , <value>
+-- <prefix> ::= <empty>
+-- <prefix> ::= <set name> :
+--
+-- where <names> are names of parameters (all the parameters must be
+-- subscripted and have identical dimensions), <symbols> are symbols
+-- used to define subscripts of parameter members, <values> are numeric
+-- or symbolic values assigned to the corresponding parameter members.
+-- Optional <prefix> may specify a simple set, in which case n-tuples
+-- built of <symbols> for each row of the data table (i.e. subscripts
+-- of parameter members) are added to the specified set. Commae between
+-- data items are optional and may be omitted anywhere.
+--
+-- If the parameter altval is not NULL, it specifies a default value
+-- provided for all the parameters specified in the data block.  */
+
+void tabbing_format
+(     MPL *mpl,
+      SYMBOL *altval          /* not changed */
+)
+{     SET *set = NULL;
+      PARAMETER *par;
+      SLICE *list, *col;
+      TUPLE *tuple;
+      int next_token, j, dim = 0;
+      char *last_name = NULL;
+      /* read the optional <prefix> */
+      if (is_symbol(mpl))
+      {  get_token(mpl /* <symbol> */);
+         next_token = mpl->token;
+         unget_token(mpl /* <symbol> */);
+         if (next_token == T_COLON)
+         {  /* select the set to saturate it with data */
+            set = select_set(mpl, mpl->image);
+            /* the set must be simple (i.e. not set of sets) */
+            if (set->dim != 0)
+               error(mpl, "%s must be a simple set", set->name);
+            /* and must not be defined yet */
+            if (set->array->head != NULL)
+               error(mpl, "%s already defined", set->name);
+            /* add new (the only) member to the set and assign it empty
+               elemental set */
+            add_member(mpl, set->array, NULL)->value.set =
+               create_elemset(mpl, set->dimen);
+            last_name = set->name, dim = set->dimen;
+            get_token(mpl /* <symbol> */);
+            xassert(mpl->token == T_COLON);
+            get_token(mpl /* : */);
+         }
+      }
+      /* read the table heading that contains parameter names */
+      list = create_slice(mpl);
+      while (mpl->token != T_ASSIGN)
+      {  /* there must be symbolic name of parameter */
+         if (!is_symbol(mpl))
+            error(mpl, "parameter name or := missing where expected");
+         /* select the parameter to saturate it with data */
+         par = select_parameter(mpl, mpl->image);
+         /* the parameter must be subscripted */
+         if (par->dim == 0)
+            error(mpl, "%s not a subscripted parameter", mpl->image);
+         /* the set (if specified) and all the parameters in the data
+            block must have identical dimension */
+         if (dim != 0 && par->dim != dim)
+         {  xassert(last_name != NULL);
+            error(mpl, "%s has dimension %d while %s has dimension %d",
+               last_name, dim, par->name, par->dim);
+         }
+         /* set default value for the parameter (if specified) */
+         if (altval != NULL)
+            set_default(mpl, par, copy_symbol(mpl, altval));
+         /* append the parameter to the column list */
+         list = expand_slice(mpl, list, (SYMBOL *)par);
+         last_name = par->name, dim = par->dim;
+         get_token(mpl /* <symbol> */);
+         /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      }
+      if (slice_dimen(mpl, list) == 0)
+         error(mpl, "at least one parameter name required");
+      get_token(mpl /* := */);
+      /* skip optional comma */
+      if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      /* read rows that contain tabbing data */
+      while (is_symbol(mpl))
+      {  /* read subscript list */
+         tuple = create_tuple(mpl);
+         for (j = 1; j <= dim; j++)
+         {  /* read j-th subscript */
+            if (!is_symbol(mpl))
+            {  int lack = slice_dimen(mpl, list) + dim - j + 1;
+               xassert(tuple != NULL);
+               xassert(lack > 1);
+               error(mpl, "%d items missing in data group beginning wit"
+                  "h %s", lack, format_symbol(mpl, tuple->sym));
+            }
+            /* read and append j-th subscript to the n-tuple */
+            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
+            /* skip optional comma *between* <symbols> */
+            if (j < dim && mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+         }
+         /* if the set is specified, add to it new n-tuple, which is a
+            copy of the subscript list just read */
+         if (set != NULL)
+            check_then_add(mpl, set->array->head->value.set,
+               copy_tuple(mpl, tuple));
+         /* skip optional comma between <symbol> and <value> */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* read values accordingly to the column list */
+         for (col = list; col != NULL; col = col->next)
+         {  /* if the token is single point, no value is provided */
+            if (is_literal(mpl, "."))
+            {  get_token(mpl /* . */);
+               continue;
+            }
+            /* read value and assign it to new parameter member */
+            if (!is_symbol(mpl))
+            {  int lack = slice_dimen(mpl, col);
+               xassert(tuple != NULL);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, tuple->sym));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, tuple->sym));
+            }
+            read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
+               tuple));
+            /* skip optional comma preceding the next value */
+            if (col->next != NULL && mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+         }
+         /* delete the original subscript list */
+         delete_tuple(mpl, tuple);
+         /* skip optional comma (only if there is next data group) */
+         if (mpl->token == T_COMMA)
+         {  get_token(mpl /* , */);
+            if (!is_symbol(mpl)) unget_token(mpl /* , */);
+         }
+      }
+      /* delete the column list (it contains parameters, not symbols,
+         so nullify it before) */
+      for (col = list; col != NULL; col = col->next) col->sym = NULL;
+      delete_slice(mpl, list);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- parameter_data - read parameter data.
+--
+-- This routine reads parameter data using the syntax:
+--
+-- <parameter data> ::= param <default value> : <tabbing format> ;
+-- <parameter data> ::= param <parameter name> <default value>
+--                      <assignments> ;
+-- <parameter name> ::= <symbolic name>
+-- <default value> ::= <empty>
+-- <default value> ::= default <symbol>
+-- <assignments> ::= <empty>
+-- <assignments> ::= <assignments> , :=
+-- <assignments> ::= <assignments> , [ <symbol list> ]
+-- <assignments> ::= <assignments> , <plain format>
+-- <assignemnts> ::= <assignments> , : <tabular format>
+-- <assignments> ::= <assignments> , (tr) <tabular format>
+-- <assignments> ::= <assignments> , (tr) : <tabular format>
+--
+-- Commae in <assignments> are optional and may be omitted anywhere. */
+
+void parameter_data(MPL *mpl)
+{     PARAMETER *par;
+      SYMBOL *altval = NULL;
+      SLICE *slice;
+      int tr = 0;
+      xassert(is_literal(mpl, "param"));
+      get_token(mpl /* param */);
+      /* read optional default value */
+      if (is_literal(mpl, "default"))
+      {  get_token(mpl /* default */);
+         if (!is_symbol(mpl))
+            error(mpl, "default value missing where expected");
+         altval = read_symbol(mpl);
+         /* if the default value follows the keyword 'param', the next
+            token must be only the colon */
+         if (mpl->token != T_COLON)
+            error(mpl, "colon missing where expected");
+      }
+      /* being used after the keyword 'param' or the optional default
+         value the colon begins data in the tabbing format */
+      if (mpl->token == T_COLON)
+      {  get_token(mpl /* : */);
+         /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* read parameter data in the tabbing format */
+         tabbing_format(mpl, altval);
+         /* on reading data in the tabbing format the default value is
+            always copied, so delete the original symbol */
+         if (altval != NULL) delete_symbol(mpl, altval);
+         /* the next token must be only semicolon */
+         if (mpl->token != T_SEMICOLON)
+            error(mpl, "symbol, number, or semicolon missing where expe"
+               "cted");
+         get_token(mpl /* ; */);
+         goto done;
+      }
+      /* in other cases there must be symbolic name of parameter, which
+         follows the keyword 'param' */
+      if (!is_symbol(mpl))
+         error(mpl, "parameter name missing where expected");
+      /* select the parameter to saturate it with data */
+      par = select_parameter(mpl, mpl->image);
+      get_token(mpl /* <symbol> */);
+      /* read optional default value */
+      if (is_literal(mpl, "default"))
+      {  get_token(mpl /* default */);
+         if (!is_symbol(mpl))
+            error(mpl, "default value missing where expected");
+         altval = read_symbol(mpl);
+         /* set default value for the parameter */
+         set_default(mpl, par, altval);
+      }
+      /* create initial fake slice of all asterisks */
+      slice = fake_slice(mpl, par->dim);
+      /* read zero or more data assignments */
+      for (;;)
+      {  /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* process current assignment */
+         if (mpl->token == T_ASSIGN)
+         {  /* assignment ligature is non-significant element */
+            get_token(mpl /* := */);
+         }
+         else if (mpl->token == T_LBRACKET)
+         {  /* left bracket begins new slice; delete the current slice
+               and read new one */
+            delete_slice(mpl, slice);
+            slice = read_slice(mpl, par->name, par->dim);
+            /* each new slice resets the "transpose" indicator */
+            tr = 0;
+         }
+         else if (is_symbol(mpl))
+         {  /* number or symbol begins data in the plain format */
+            plain_format(mpl, par, slice);
+         }
+         else if (mpl->token == T_COLON)
+         {  /* colon begins data in the tabular format */
+            if (par->dim == 0)
+err1:          error(mpl, "%s not a subscripted parameter",
+                  par->name);
+            if (slice_arity(mpl, slice) != 2)
+err2:          error(mpl, "slice currently used must specify 2 asterisk"
+                  "s, not %d", slice_arity(mpl, slice));
+            get_token(mpl /* : */);
+            /* read parameter data in the tabular format */
+            tabular_format(mpl, par, slice, tr);
+         }
+         else if (mpl->token == T_LEFT)
+         {  /* left parenthesis begins the "transpose" indicator, which
+               is followed by data in the tabular format */
+            get_token(mpl /* ( */);
+            if (!is_literal(mpl, "tr"))
+err3:          error(mpl, "transpose indicator (tr) incomplete");
+            if (par->dim == 0) goto err1;
+            if (slice_arity(mpl, slice) != 2) goto err2;
+            get_token(mpl /* tr */);
+            if (mpl->token != T_RIGHT) goto err3;
+            get_token(mpl /* ) */);
+            /* in this case the colon is optional */
+            if (mpl->token == T_COLON) get_token(mpl /* : */);
+            /* set the "transpose" indicator */
+            tr = 1;
+            /* read parameter data in the tabular format */
+            tabular_format(mpl, par, slice, tr);
+         }
+         else if (mpl->token == T_SEMICOLON)
+         {  /* semicolon terminates the data block */
+            get_token(mpl /* ; */);
+            break;
+         }
+         else
+            error(mpl, "syntax error in parameter data block");
+      }
+      /* delete the current slice */
+      delete_slice(mpl, slice);
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- data_section - read data section.
+--
+-- This routine reads data section using the syntax:
+--
+-- <data section> ::= <empty>
+-- <data section> ::= <data section> <data block> ;
+-- <data block> ::= <set data>
+-- <data block> ::= <parameter data>
+--
+-- Reading data section is terminated by either the keyword 'end' or
+-- the end of file. */
+
+void data_section(MPL *mpl)
+{     while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
+      {  if (is_literal(mpl, "set"))
+            set_data(mpl);
+         else if (is_literal(mpl, "param"))
+            parameter_data(mpl);
+         else
+            error(mpl, "syntax error in data section");
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmpl03.c b/optional/glpk/glpmpl03.c
new file mode 100644
index 0000000..665e512
--- /dev/null
+++ b/optional/glpk/glpmpl03.c
@@ -0,0 +1,6084 @@
+/* glpmpl03.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glpmpl.h"
+
+/**********************************************************************/
+/* * *                   FLOATING-POINT NUMBERS                   * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- fp_add - floating-point addition.
+--
+-- This routine computes the sum x + y. */
+
+double fp_add(MPL *mpl, double x, double y)
+{     if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
+          x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
+         error(mpl, "%.*g + %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x + y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_sub - floating-point subtraction.
+--
+-- This routine computes the difference x - y. */
+
+double fp_sub(MPL *mpl, double x, double y)
+{     if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
+          x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
+         error(mpl, "%.*g - %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x - y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_less - floating-point non-negative subtraction.
+--
+-- This routine computes the non-negative difference max(0, x - y). */
+
+double fp_less(MPL *mpl, double x, double y)
+{     if (x < y) return 0.0;
+      if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
+         error(mpl, "%.*g less %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x - y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_mul - floating-point multiplication.
+--
+-- This routine computes the product x * y. */
+
+double fp_mul(MPL *mpl, double x, double y)
+{     if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
+         error(mpl, "%.*g * %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x * y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_div - floating-point division.
+--
+-- This routine computes the quotient x / y. */
+
+double fp_div(MPL *mpl, double x, double y)
+{     if (fabs(y) < DBL_MIN)
+         error(mpl, "%.*g / %.*g; floating-point zero divide",
+            DBL_DIG, x, DBL_DIG, y);
+      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
+         error(mpl, "%.*g / %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x / y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_idiv - floating-point quotient of exact division.
+--
+-- This routine computes the quotient of exact division x div y. */
+
+double fp_idiv(MPL *mpl, double x, double y)
+{     if (fabs(y) < DBL_MIN)
+         error(mpl, "%.*g div %.*g; floating-point zero divide",
+            DBL_DIG, x, DBL_DIG, y);
+      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
+         error(mpl, "%.*g div %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      x /= y;
+      return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
+}
+
+/*----------------------------------------------------------------------
+-- fp_mod - floating-point remainder of exact division.
+--
+-- This routine computes the remainder of exact division x mod y.
+--
+-- NOTE: By definition x mod y = x - y * floor(x / y). */
+
+double fp_mod(MPL *mpl, double x, double y)
+{     double r;
+      xassert(mpl == mpl);
+      if (x == 0.0)
+         r = 0.0;
+      else if (y == 0.0)
+         r = x;
+      else
+      {  r = fmod(fabs(x), fabs(y));
+         if (r != 0.0)
+         {  if (x < 0.0) r = - r;
+            if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
+         }
+      }
+      return r;
+}
+
+/*----------------------------------------------------------------------
+-- fp_power - floating-point exponentiation (raise to power).
+--
+-- This routine computes the exponentiation x ** y. */
+
+double fp_power(MPL *mpl, double x, double y)
+{     double r;
+      if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
+         error(mpl, "%.*g ** %.*g; result undefined",
+            DBL_DIG, x, DBL_DIG, y);
+      if (x == 0.0) goto eval;
+      if (fabs(x) > 1.0 && y > +1.0 &&
+            +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
+          fabs(x) < 1.0 && y < -1.0 &&
+            +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
+         error(mpl, "%.*g ** %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      if (fabs(x) > 1.0 && y < -1.0 &&
+            -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
+          fabs(x) < 1.0 && y > +1.0 &&
+            -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
+         r = 0.0;
+      else
+eval:    r = pow(x, y);
+      return r;
+}
+
+/*----------------------------------------------------------------------
+-- fp_exp - floating-point base-e exponential.
+--
+-- This routine computes the base-e exponential e ** x. */
+
+double fp_exp(MPL *mpl, double x)
+{     if (x > 0.999 * log(DBL_MAX))
+         error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
+      return exp(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_log - floating-point natural logarithm.
+--
+-- This routine computes the natural logarithm log x. */
+
+double fp_log(MPL *mpl, double x)
+{     if (x <= 0.0)
+         error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
+      return log(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_log10 - floating-point common (decimal) logarithm.
+--
+-- This routine computes the common (decimal) logarithm lg x. */
+
+double fp_log10(MPL *mpl, double x)
+{     if (x <= 0.0)
+         error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
+      return log10(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_sqrt - floating-point square root.
+--
+-- This routine computes the square root x ** 0.5. */
+
+double fp_sqrt(MPL *mpl, double x)
+{     if (x < 0.0)
+         error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
+      return sqrt(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_sin - floating-point trigonometric sine.
+--
+-- This routine computes the trigonometric sine sin(x). */
+
+double fp_sin(MPL *mpl, double x)
+{     if (!(-1e6 <= x && x <= +1e6))
+         error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
+      return sin(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_cos - floating-point trigonometric cosine.
+--
+-- This routine computes the trigonometric cosine cos(x). */
+
+double fp_cos(MPL *mpl, double x)
+{     if (!(-1e6 <= x && x <= +1e6))
+         error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
+      return cos(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_atan - floating-point trigonometric arctangent.
+--
+-- This routine computes the trigonometric arctangent atan(x). */
+
+double fp_atan(MPL *mpl, double x)
+{     xassert(mpl == mpl);
+      return atan(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_atan2 - floating-point trigonometric arctangent.
+--
+-- This routine computes the trigonometric arctangent atan(y / x). */
+
+double fp_atan2(MPL *mpl, double y, double x)
+{     xassert(mpl == mpl);
+      return atan2(y, x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_round - round floating-point value to n fractional digits.
+--
+-- This routine rounds given floating-point value x to n fractional
+-- digits with the formula:
+--
+--    round(x, n) = floor(x * 10^n + 0.5) / 10^n.
+--
+-- The parameter n is assumed to be integer. */
+
+double fp_round(MPL *mpl, double x, double n)
+{     double ten_to_n;
+      if (n != floor(n))
+         error(mpl, "round(%.*g, %.*g); non-integer second argument",
+            DBL_DIG, x, DBL_DIG, n);
+      if (n <= DBL_DIG + 2)
+      {  ten_to_n = pow(10.0, n);
+         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
+         {  x = floor(x * ten_to_n + 0.5);
+            if (x != 0.0) x /= ten_to_n;
+         }
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- fp_trunc - truncate floating-point value to n fractional digits.
+--
+-- This routine truncates given floating-point value x to n fractional
+-- digits with the formula:
+--
+--                  ( floor(x * 10^n) / 10^n,  if x >= 0
+--    trunc(x, n) = <
+--                  ( ceil(x * 10^n) / 10^n,   if x < 0
+--
+-- The parameter n is assumed to be integer. */
+
+double fp_trunc(MPL *mpl, double x, double n)
+{     double ten_to_n;
+      if (n != floor(n))
+         error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
+            DBL_DIG, x, DBL_DIG, n);
+      if (n <= DBL_DIG + 2)
+      {  ten_to_n = pow(10.0, n);
+         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
+         {  x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
+            if (x != 0.0) x /= ten_to_n;
+         }
+      }
+      return x;
+}
+
+/**********************************************************************/
+/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- fp_irand224 - pseudo-random integer in the range [0, 2^24).
+--
+-- This routine returns a next pseudo-random integer (converted to
+-- floating-point) which is uniformly distributed between 0 and 2^24-1,
+-- inclusive. */
+
+#define two_to_the_24 0x1000000
+
+double fp_irand224(MPL *mpl)
+{     return
+         (double)rng_unif_rand(mpl->rand, two_to_the_24);
+}
+
+/*----------------------------------------------------------------------
+-- fp_uniform01 - pseudo-random number in the range [0, 1).
+--
+-- This routine returns a next pseudo-random number which is uniformly
+-- distributed in the range [0, 1). */
+
+#define two_to_the_31 ((unsigned int)0x80000000)
+
+double fp_uniform01(MPL *mpl)
+{     return
+         (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
+}
+
+/*----------------------------------------------------------------------
+-- fp_uniform - pseudo-random number in the range [a, b).
+--
+-- This routine returns a next pseudo-random number which is uniformly
+-- distributed in the range [a, b). */
+
+double fp_uniform(MPL *mpl, double a, double b)
+{     double x;
+      if (a >= b)
+         error(mpl, "Uniform(%.*g, %.*g); invalid range",
+            DBL_DIG, a, DBL_DIG, b);
+      x = fp_uniform01(mpl);
+#if 0
+      x = a * (1.0 - x) + b * x;
+#else
+      x = fp_add(mpl, a * (1.0 - x), b * x);
+#endif
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
+--
+-- This routine returns a Gaussian random variate with zero mean and
+-- unit standard deviation. The polar (Box-Mueller) method is used.
+--
+-- This code is a modified version of the routine gsl_ran_gaussian from
+-- the GNU Scientific Library Version 1.0. */
+
+double fp_normal01(MPL *mpl)
+{     double x, y, r2;
+      do
+      {  /* choose x, y in uniform square (-1,-1) to (+1,+1) */
+         x = -1.0 + 2.0 * fp_uniform01(mpl);
+         y = -1.0 + 2.0 * fp_uniform01(mpl);
+         /* see if it is in the unit circle */
+         r2 = x * x + y * y;
+      } while (r2 > 1.0 || r2 == 0.0);
+      /* Box-Muller transform */
+      return y * sqrt(-2.0 * log (r2) / r2);
+}
+
+/*----------------------------------------------------------------------
+-- fp_normal - Gaussian random variate with specified mu and sigma.
+--
+-- This routine returns a Gaussian random variate with mean mu and
+-- standard deviation sigma. */
+
+double fp_normal(MPL *mpl, double mu, double sigma)
+{     double x;
+#if 0
+      x = mu + sigma * fp_normal01(mpl);
+#else
+      x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
+#endif
+      return x;
+}
+
+/**********************************************************************/
+/* * *                SEGMENTED CHARACTER STRINGS                 * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_string - create character string.
+--
+-- This routine creates a segmented character string, which is exactly
+-- equivalent to specified character string. */
+
+STRING *create_string
+(     MPL *mpl,
+      char buf[MAX_LENGTH+1]  /* not changed */
+)
+#if 0
+{     STRING *head, *tail;
+      int i, j;
+      xassert(buf != NULL);
+      xassert(strlen(buf) <= MAX_LENGTH);
+      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
+      for (i = j = 0; ; i++)
+      {  if ((tail->seg[j++] = buf[i]) == '\0') break;
+         if (j == STRSEG_SIZE)
+tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
+      }
+      tail->next = NULL;
+      return head;
+}
+#else
+{     STRING *str;
+      xassert(strlen(buf) <= MAX_LENGTH);
+      str = dmp_get_atom(mpl->strings, strlen(buf)+1);
+      strcpy(str, buf);
+      return str;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- copy_string - make copy of character string.
+--
+-- This routine returns an exact copy of segmented character string. */
+
+STRING *copy_string
+(     MPL *mpl,
+      STRING *str             /* not changed */
+)
+#if 0
+{     STRING *head, *tail;
+      xassert(str != NULL);
+      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
+      for (; str != NULL; str = str->next)
+      {  memcpy(tail->seg, str->seg, STRSEG_SIZE);
+         if (str->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
+      }
+      tail->next = NULL;
+      return head;
+}
+#else
+{     xassert(mpl == mpl);
+      return create_string(mpl, str);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- compare_strings - compare one character string with another.
+--
+-- This routine compares one segmented character strings with another
+-- and returns the result of comparison as follows:
+--
+-- = 0 - both strings are identical;
+-- < 0 - the first string precedes the second one;
+-- > 0 - the first string follows the second one. */
+
+int compare_strings
+(     MPL *mpl,
+      STRING *str1,           /* not changed */
+      STRING *str2            /* not changed */
+)
+#if 0
+{     int j, c1, c2;
+      xassert(mpl == mpl);
+      for (;; str1 = str1->next, str2 = str2->next)
+      {  xassert(str1 != NULL);
+         xassert(str2 != NULL);
+         for (j = 0; j < STRSEG_SIZE; j++)
+         {  c1 = (unsigned char)str1->seg[j];
+            c2 = (unsigned char)str2->seg[j];
+            if (c1 < c2) return -1;
+            if (c1 > c2) return +1;
+            if (c1 == '\0') goto done;
+         }
+      }
+done: return 0;
+}
+#else
+{     xassert(mpl == mpl);
+      return strcmp(str1, str2);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- fetch_string - extract content of character string.
+--
+-- This routine returns a character string, which is exactly equivalent
+-- to specified segmented character string. */
+
+char *fetch_string
+(     MPL *mpl,
+      STRING *str,            /* not changed */
+      char buf[MAX_LENGTH+1]  /* modified */
+)
+#if 0
+{     int i, j;
+      xassert(mpl == mpl);
+      xassert(buf != NULL);
+      for (i = 0; ; str = str->next)
+      {  xassert(str != NULL);
+         for (j = 0; j < STRSEG_SIZE; j++)
+            if ((buf[i++] = str->seg[j]) == '\0') goto done;
+      }
+done: xassert(strlen(buf) <= MAX_LENGTH);
+      return buf;
+}
+#else
+{     xassert(mpl == mpl);
+      return strcpy(buf, str);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- delete_string - delete character string.
+--
+-- This routine deletes specified segmented character string. */
+
+void delete_string
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+)
+#if 0
+{     STRING *temp;
+      xassert(str != NULL);
+      while (str != NULL)
+      {  temp = str;
+         str = str->next;
+         dmp_free_atom(mpl->strings, temp, sizeof(STRING));
+      }
+      return;
+}
+#else
+{     dmp_free_atom(mpl->strings, str, strlen(str)+1);
+      return;
+}
+#endif
+
+/**********************************************************************/
+/* * *                          SYMBOLS                           * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_symbol_num - create symbol of numeric type.
+--
+-- This routine creates a symbol, which has a numeric value specified
+-- as floating-point number. */
+
+SYMBOL *create_symbol_num(MPL *mpl, double num)
+{     SYMBOL *sym;
+      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+      sym->num = num;
+      sym->str = NULL;
+      return sym;
+}
+
+/*----------------------------------------------------------------------
+-- create_symbol_str - create symbol of abstract type.
+--
+-- This routine creates a symbol, which has an abstract value specified
+-- as segmented character string. */
+
+SYMBOL *create_symbol_str
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+)
+{     SYMBOL *sym;
+      xassert(str != NULL);
+      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+      sym->num = 0.0;
+      sym->str = str;
+      return sym;
+}
+
+/*----------------------------------------------------------------------
+-- copy_symbol - make copy of symbol.
+--
+-- This routine returns an exact copy of symbol. */
+
+SYMBOL *copy_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+)
+{     SYMBOL *copy;
+      xassert(sym != NULL);
+      copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+      if (sym->str == NULL)
+      {  copy->num = sym->num;
+         copy->str = NULL;
+      }
+      else
+      {  copy->num = 0.0;
+         copy->str = copy_string(mpl, sym->str);
+      }
+      return copy;
+}
+
+/*----------------------------------------------------------------------
+-- compare_symbols - compare one symbol with another.
+--
+-- This routine compares one symbol with another and returns the result
+-- of comparison as follows:
+--
+-- = 0 - both symbols are identical;
+-- < 0 - the first symbol precedes the second one;
+-- > 0 - the first symbol follows the second one.
+--
+-- Note that the linear order, in which symbols follow each other, is
+-- implementation-dependent. It may be not an alphabetical order. */
+
+int compare_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* not changed */
+      SYMBOL *sym2            /* not changed */
+)
+{     xassert(sym1 != NULL);
+      xassert(sym2 != NULL);
+      /* let all numeric quantities precede all symbolic quantities */
+      if (sym1->str == NULL && sym2->str == NULL)
+      {  if (sym1->num < sym2->num) return -1;
+         if (sym1->num > sym2->num) return +1;
+         return 0;
+      }
+      if (sym1->str == NULL) return -1;
+      if (sym2->str == NULL) return +1;
+      return compare_strings(mpl, sym1->str, sym2->str);
+}
+
+/*----------------------------------------------------------------------
+-- delete_symbol - delete symbol.
+--
+-- This routine deletes specified symbol. */
+
+void delete_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* destroyed */
+)
+{     xassert(sym != NULL);
+      if (sym->str != NULL) delete_string(mpl, sym->str);
+      dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- format_symbol - format symbol for displaying or printing.
+--
+-- This routine converts specified symbol to a charater string, which
+-- is suitable for displaying or printing.
+--
+-- The resultant string is never longer than 255 characters. If it gets
+-- longer, it is truncated from the right and appended by dots. */
+
+char *format_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+)
+{     char *buf = mpl->sym_buf;
+      xassert(sym != NULL);
+      if (sym->str == NULL)
+         sprintf(buf, "%.*g", DBL_DIG, sym->num);
+      else
+      {  char str[MAX_LENGTH+1];
+         int quoted, j, len;
+         fetch_string(mpl, sym->str, str);
+         if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
+            quoted = 1;
+         else
+         {  quoted = 0;
+            for (j = 1; str[j] != '\0'; j++)
+            {  if (!(isalnum((unsigned char)str[j]) ||
+                     strchr("+-._", (unsigned char)str[j]) != NULL))
+               {  quoted = 1;
+                  break;
+               }
+            }
+         }
+#        define safe_append(c) \
+            (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
+         buf[0] = '\0', len = 0;
+         if (quoted) safe_append('\'');
+         for (j = 0; str[j] != '\0'; j++)
+         {  if (quoted && str[j] == '\'') safe_append('\'');
+            safe_append(str[j]);
+         }
+         if (quoted) safe_append('\'');
+#        undef safe_append
+         buf[len] = '\0';
+         if (len == 255) strcpy(buf+252, "...");
+      }
+      xassert(strlen(buf) <= 255);
+      return buf;
+}
+
+/*----------------------------------------------------------------------
+-- concat_symbols - concatenate one symbol with another.
+--
+-- This routine concatenates values of two given symbols and assigns
+-- the resultant character string to a new symbol, which is returned on
+-- exit. Both original symbols are destroyed. */
+
+SYMBOL *concat_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* destroyed */
+      SYMBOL *sym2            /* destroyed */
+)
+{     char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
+      xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
+      if (sym1->str == NULL)
+         sprintf(str1, "%.*g", DBL_DIG, sym1->num);
+      else
+         fetch_string(mpl, sym1->str, str1);
+      if (sym2->str == NULL)
+         sprintf(str2, "%.*g", DBL_DIG, sym2->num);
+      else
+         fetch_string(mpl, sym2->str, str2);
+      if (strlen(str1) + strlen(str2) > MAX_LENGTH)
+      {  char buf[255+1];
+         strcpy(buf, format_symbol(mpl, sym1));
+         xassert(strlen(buf) < sizeof(buf));
+         error(mpl, "%s & %s; resultant symbol exceeds %d characters",
+            buf, format_symbol(mpl, sym2), MAX_LENGTH);
+      }
+      delete_symbol(mpl, sym1);
+      delete_symbol(mpl, sym2);
+      return create_symbol_str(mpl, create_string(mpl, strcat(str1,
+         str2)));
+}
+
+/**********************************************************************/
+/* * *                          N-TUPLES                          * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_tuple - create n-tuple.
+--
+-- This routine creates a n-tuple, which initially has no components,
+-- i.e. which is 0-tuple. */
+
+TUPLE *create_tuple(MPL *mpl)
+{     TUPLE *tuple;
+      xassert(mpl == mpl);
+      tuple = NULL;
+      return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- expand_tuple - append symbol to n-tuple.
+--
+-- This routine expands n-tuple appending to it a given symbol, which
+-- becomes its new last component. */
+
+TUPLE *expand_tuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+)
+{     TUPLE *tail, *temp;
+      xassert(sym != NULL);
+      /* create a new component */
+      tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+      tail->sym = sym;
+      tail->next = NULL;
+      /* and append it to the component list */
+      if (tuple == NULL)
+         tuple = tail;
+      else
+      {  for (temp = tuple; temp->next != NULL; temp = temp->next);
+         temp->next = tail;
+      }
+      return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- tuple_dimen - determine dimension of n-tuple.
+--
+-- This routine returns dimension of n-tuple, i.e. number of components
+-- in the n-tuple. */
+
+int tuple_dimen
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+)
+{     TUPLE *temp;
+      int dim = 0;
+      xassert(mpl == mpl);
+      for (temp = tuple; temp != NULL; temp = temp->next) dim++;
+      return dim;
+}
+
+/*----------------------------------------------------------------------
+-- copy_tuple - make copy of n-tuple.
+--
+-- This routine returns an exact copy of n-tuple. */
+
+TUPLE *copy_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+)
+{     TUPLE *head, *tail;
+      if (tuple == NULL)
+         head = NULL;
+      else
+      {  head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+         for (; tuple != NULL; tuple = tuple->next)
+         {  xassert(tuple->sym != NULL);
+            tail->sym = copy_symbol(mpl, tuple->sym);
+            if (tuple->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
+         }
+         tail->next = NULL;
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- compare_tuples - compare one n-tuple with another.
+--
+-- This routine compares two given n-tuples, which must have the same
+-- dimension (not checked for the sake of efficiency), and returns one
+-- of the following codes:
+--
+-- = 0 - both n-tuples are identical;
+-- < 0 - the first n-tuple precedes the second one;
+-- > 0 - the first n-tuple follows the second one.
+--
+-- Note that the linear order, in which n-tuples follow each other, is
+-- implementation-dependent. It may be not an alphabetical order. */
+
+int compare_tuples
+(     MPL *mpl,
+      TUPLE *tuple1,          /* not changed */
+      TUPLE *tuple2           /* not changed */
+)
+{     TUPLE *item1, *item2;
+      int ret;
+      xassert(mpl == mpl);
+      for (item1 = tuple1, item2 = tuple2; item1 != NULL;
+           item1 = item1->next, item2 = item2->next)
+      {  xassert(item2 != NULL);
+         xassert(item1->sym != NULL);
+         xassert(item2->sym != NULL);
+         ret = compare_symbols(mpl, item1->sym, item2->sym);
+         if (ret != 0) return ret;
+      }
+      xassert(item2 == NULL);
+      return 0;
+}
+
+/*----------------------------------------------------------------------
+-- build_subtuple - build subtuple of given n-tuple.
+--
+-- This routine builds subtuple, which consists of first dim components
+-- of given n-tuple. */
+
+TUPLE *build_subtuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* not changed */
+      int dim
+)
+{     TUPLE *head, *temp;
+      int j;
+      head = create_tuple(mpl);
+      for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
+      {  xassert(temp != NULL);
+         head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- delete_tuple - delete n-tuple.
+--
+-- This routine deletes specified n-tuple. */
+
+void delete_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* destroyed */
+)
+{     TUPLE *temp;
+      while (tuple != NULL)
+      {  temp = tuple;
+         tuple = temp->next;
+         xassert(temp->sym != NULL);
+         delete_symbol(mpl, temp->sym);
+         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- format_tuple - format n-tuple for displaying or printing.
+--
+-- This routine converts specified n-tuple to a character string, which
+-- is suitable for displaying or printing.
+--
+-- The resultant string is never longer than 255 characters. If it gets
+-- longer, it is truncated from the right and appended by dots. */
+
+char *format_tuple
+(     MPL *mpl,
+      int c,
+      TUPLE *tuple            /* not changed */
+)
+{     TUPLE *temp;
+      int dim, j, len;
+      char *buf = mpl->tup_buf, str[255+1], *save;
+#     define safe_append(c) \
+         (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
+      buf[0] = '\0', len = 0;
+      dim = tuple_dimen(mpl, tuple);
+      if (c == '[' && dim > 0) safe_append('[');
+      if (c == '(' && dim > 1) safe_append('(');
+      for (temp = tuple; temp != NULL; temp = temp->next)
+      {  if (temp != tuple) safe_append(',');
+         xassert(temp->sym != NULL);
+         save = mpl->sym_buf;
+         mpl->sym_buf = str;
+         format_symbol(mpl, temp->sym);
+         mpl->sym_buf = save;
+         xassert(strlen(str) < sizeof(str));
+         for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
+      }
+      if (c == '[' && dim > 0) safe_append(']');
+      if (c == '(' && dim > 1) safe_append(')');
+#     undef safe_append
+      buf[len] = '\0';
+      if (len == 255) strcpy(buf+252, "...");
+      xassert(strlen(buf) <= 255);
+      return buf;
+}
+
+/**********************************************************************/
+/* * *                       ELEMENTAL SETS                       * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_elemset - create elemental set.
+--
+-- This routine creates an elemental set, whose members are n-tuples of
+-- specified dimension. Being created the set is initially empty. */
+
+ELEMSET *create_elemset(MPL *mpl, int dim)
+{     ELEMSET *set;
+      xassert(dim > 0);
+      set = create_array(mpl, A_NONE, dim);
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- find_tuple - check if elemental set contains given n-tuple.
+--
+-- This routine finds given n-tuple in specified elemental set in order
+-- to check if the set contains that n-tuple. If the n-tuple is found,
+-- the routine returns pointer to corresponding array member. Otherwise
+-- null pointer is returned. */
+
+MEMBER *find_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      xassert(set->dim == tuple_dimen(mpl, tuple));
+      return find_member(mpl, set, tuple);
+}
+
+/*----------------------------------------------------------------------
+-- add_tuple - add new n-tuple to elemental set.
+--
+-- This routine adds given n-tuple to specified elemental set.
+--
+-- For the sake of efficiency this routine doesn't check whether the
+-- set already contains the same n-tuple or not. Therefore the calling
+-- program should use the routine find_tuple (if necessary) in order to
+-- make sure that the given n-tuple is not contained in the set, since
+-- duplicate n-tuples within the same set are not allowed. */
+
+MEMBER *add_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      xassert(set->dim == tuple_dimen(mpl, tuple));
+      memb = add_member(mpl, set, tuple);
+      memb->value.none = NULL;
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- check_then_add - check and add new n-tuple to elemental set.
+--
+-- This routine is equivalent to the routine add_tuple except that it
+-- does check for duplicate n-tuples. */
+
+MEMBER *check_then_add
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+)
+{     if (find_tuple(mpl, set, tuple) != NULL)
+         error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
+            '(', tuple));
+      return add_tuple(mpl, set, tuple);
+}
+
+/*----------------------------------------------------------------------
+-- copy_elemset - make copy of elemental set.
+--
+-- This routine makes an exact copy of elemental set. */
+
+ELEMSET *copy_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* not changed */
+)
+{     ELEMSET *copy;
+      MEMBER *memb;
+      xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      xassert(set->dim > 0);
+      copy = create_elemset(mpl, set->dim);
+      for (memb = set->head; memb != NULL; memb = memb->next)
+         add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
+      return copy;
+}
+
+/*----------------------------------------------------------------------
+-- delete_elemset - delete elemental set.
+--
+-- This routine deletes specified elemental set. */
+
+void delete_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* destroyed */
+)
+{     xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      delete_array(mpl, set);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- arelset_size - compute size of "arithmetic" elemental set.
+--
+-- This routine computes the size of "arithmetic" elemental set, which
+-- is specified in the form of arithmetic progression:
+--
+--    { t0 .. tf by dt }.
+--
+-- The size is computed using the formula:
+--
+--    n = max(0, floor((tf - t0) / dt) + 1). */
+
+int arelset_size(MPL *mpl, double t0, double tf, double dt)
+{     double temp;
+      if (dt == 0.0)
+         error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
+            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
+      if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
+         temp = +DBL_MAX;
+      else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
+         temp = -DBL_MAX;
+      else
+         temp = tf - t0;
+      if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
+      {  if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
+            temp = +DBL_MAX;
+         else
+            temp = 0.0;
+      }
+      else
+      {  temp = floor(temp / dt) + 1.0;
+         if (temp < 0.0) temp = 0.0;
+      }
+      xassert(temp >= 0.0);
+      if (temp > (double)(INT_MAX - 1))
+         error(mpl, "%.*g .. %.*g by %.*g; set too large",
+            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
+      return (int)(temp + 0.5);
+}
+
+/*----------------------------------------------------------------------
+-- arelset_member - compute member of "arithmetic" elemental set.
+--
+-- This routine returns a numeric value of symbol, which is equivalent
+-- to j-th member of given "arithmetic" elemental set specified in the
+-- form of arithmetic progression:
+--
+--    { t0 .. tf by dt }.
+--
+-- The symbol value is computed with the formula:
+--
+--    j-th member = t0 + (j - 1) * dt,
+--
+-- The number j must satisfy to the restriction 1 <= j <= n, where n is
+-- the set size computed by the routine arelset_size. */
+
+double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
+{     xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
+      return t0 + (double)(j - 1) * dt;
+}
+
+/*----------------------------------------------------------------------
+-- create_arelset - create "arithmetic" elemental set.
+--
+-- This routine creates "arithmetic" elemental set, which is specified
+-- in the form of arithmetic progression:
+--
+--    { t0 .. tf by dt }.
+--
+-- Components of this set are 1-tuples. */
+
+ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
+{     ELEMSET *set;
+      int j, n;
+      set = create_elemset(mpl, 1);
+      n = arelset_size(mpl, t0, tf, dt);
+      for (j = 1; j <= n; j++)
+      {  add_tuple
+         (  mpl,
+            set,
+            expand_tuple
+            (  mpl,
+               create_tuple(mpl),
+               create_symbol_num
+               (  mpl,
+                  arelset_member(mpl, t0, tf, dt, j)
+               )
+            )
+         );
+      }
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- set_union - union of two elemental sets.
+--
+-- This routine computes the union:
+--
+--    X U Y = { j | (j in X) or (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_union
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      for (memb = Y->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
+            add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, Y);
+      return X;
+}
+
+/*----------------------------------------------------------------------
+-- set_diff - difference between two elemental sets.
+--
+-- This routine computes the difference:
+--
+--    X \ Y = { j | (j in X) and (j not in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_diff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      Z = create_elemset(mpl, X->dim);
+      for (memb = X->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_symdiff - symmetric difference between two elemental sets.
+--
+-- This routine computes the symmetric difference:
+--
+--    X (+) Y = (X \ Y) U (Y \ X),
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_symdiff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      /* Z := X \ Y */
+      Z = create_elemset(mpl, X->dim);
+      for (memb = X->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      /* Z := Z U (Y \ X) */
+      for (memb = Y->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_inter - intersection of two elemental sets.
+--
+-- This routine computes the intersection:
+--
+--    X ^ Y = { j | (j in X) and (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_inter
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      Z = create_elemset(mpl, X->dim);
+      for (memb = X->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, Y, memb->tuple) != NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_cross - cross (Cartesian) product of two elemental sets.
+--
+-- This routine computes the cross (Cartesian) product:
+--
+--    X x Y = { (i,j) | (i in X) and (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_cross
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memx, *memy;
+      TUPLE *tuple, *temp;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      Z = create_elemset(mpl, X->dim + Y->dim);
+      for (memx = X->head; memx != NULL; memx = memx->next)
+      {  for (memy = Y->head; memy != NULL; memy = memy->next)
+         {  tuple = copy_tuple(mpl, memx->tuple);
+            for (temp = memy->tuple; temp != NULL; temp = temp->next)
+               tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                  temp->sym));
+            add_tuple(mpl, Z, tuple);
+         }
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/**********************************************************************/
+/* * *                    ELEMENTAL VARIABLES                     * * */
+/**********************************************************************/
+
+/* (there are no specific routines for elemental variables) */
+
+/**********************************************************************/
+/* * *                        LINEAR FORMS                        * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- constant_term - create constant term.
+--
+-- This routine creates the linear form, which is a constant term. */
+
+FORMULA *constant_term(MPL *mpl, double coef)
+{     FORMULA *form;
+      if (coef == 0.0)
+         form = NULL;
+      else
+      {  form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+         form->coef = coef;
+         form->var = NULL;
+         form->next = NULL;
+      }
+      return form;
+}
+
+/*----------------------------------------------------------------------
+-- single_variable - create single variable.
+--
+-- This routine creates the linear form, which is a single elemental
+-- variable. */
+
+FORMULA *single_variable
+(     MPL *mpl,
+      ELEMVAR *var            /* referenced */
+)
+{     FORMULA *form;
+      xassert(var != NULL);
+      form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+      form->coef = 1.0;
+      form->var = var;
+      form->next = NULL;
+      return form;
+}
+
+/*----------------------------------------------------------------------
+-- copy_formula - make copy of linear form.
+--
+-- This routine returns an exact copy of linear form. */
+
+FORMULA *copy_formula
+(     MPL *mpl,
+      FORMULA *form           /* not changed */
+)
+{     FORMULA *head, *tail;
+      if (form == NULL)
+         head = NULL;
+      else
+      {  head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+         for (; form != NULL; form = form->next)
+         {  tail->coef = form->coef;
+            tail->var = form->var;
+            if (form->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
+         }
+         tail->next = NULL;
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- delete_formula - delete linear form.
+--
+-- This routine deletes specified linear form. */
+
+void delete_formula
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+)
+{     FORMULA *temp;
+      while (form != NULL)
+      {  temp = form;
+         form = form->next;
+         dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- linear_comb - linear combination of two linear forms.
+--
+-- This routine computes the linear combination:
+--
+--    a * fx + b * fy,
+--
+-- where a and b are numeric coefficients, fx and fy are linear forms
+-- (destroyed on exit). */
+
+FORMULA *linear_comb
+(     MPL *mpl,
+      double a, FORMULA *fx,  /* destroyed */
+      double b, FORMULA *fy   /* destroyed */
+)
+{     FORMULA *form = NULL, *term, *temp;
+      double c0 = 0.0;
+      for (term = fx; term != NULL; term = term->next)
+      {  if (term->var == NULL)
+            c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
+         else
+            term->var->temp =
+               fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
+      }
+      for (term = fy; term != NULL; term = term->next)
+      {  if (term->var == NULL)
+            c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
+         else
+            term->var->temp =
+               fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
+      }
+      for (term = fx; term != NULL; term = term->next)
+      {  if (term->var != NULL && term->var->temp != 0.0)
+         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+            temp->coef = term->var->temp, temp->var = term->var;
+            temp->next = form, form = temp;
+            term->var->temp = 0.0;
+         }
+      }
+      for (term = fy; term != NULL; term = term->next)
+      {  if (term->var != NULL && term->var->temp != 0.0)
+         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+            temp->coef = term->var->temp, temp->var = term->var;
+            temp->next = form, form = temp;
+            term->var->temp = 0.0;
+         }
+      }
+      if (c0 != 0.0)
+      {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+         temp->coef = c0, temp->var = NULL;
+         temp->next = form, form = temp;
+      }
+      delete_formula(mpl, fx);
+      delete_formula(mpl, fy);
+      return form;
+}
+
+/*----------------------------------------------------------------------
+-- remove_constant - remove constant term from linear form.
+--
+-- This routine removes constant term from linear form and stores its
+-- value to given location. */
+
+FORMULA *remove_constant
+(     MPL *mpl,
+      FORMULA *form,          /* destroyed */
+      double *coef            /* modified */
+)
+{     FORMULA *head = NULL, *temp;
+      *coef = 0.0;
+      while (form != NULL)
+      {  temp = form;
+         form = form->next;
+         if (temp->var == NULL)
+         {  /* constant term */
+            *coef = fp_add(mpl, *coef, temp->coef);
+            dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
+         }
+         else
+         {  /* linear term */
+            temp->next = head;
+            head = temp;
+         }
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- reduce_terms - reduce identical terms in linear form.
+--
+-- This routine reduces identical terms in specified linear form. */
+
+FORMULA *reduce_terms
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+)
+{     FORMULA *term, *next_term;
+      double c0 = 0.0;
+      for (term = form; term != NULL; term = term->next)
+      {  if (term->var == NULL)
+            c0 = fp_add(mpl, c0, term->coef);
+         else
+            term->var->temp = fp_add(mpl, term->var->temp, term->coef);
+      }
+      next_term = form, form = NULL;
+      for (term = next_term; term != NULL; term = next_term)
+      {  next_term = term->next;
+         if (term->var == NULL && c0 != 0.0)
+         {  term->coef = c0, c0 = 0.0;
+            term->next = form, form = term;
+         }
+         else if (term->var != NULL && term->var->temp != 0.0)
+         {  term->coef = term->var->temp, term->var->temp = 0.0;
+            term->next = form, form = term;
+         }
+         else
+            dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
+      }
+      return form;
+}
+
+/**********************************************************************/
+/* * *                   ELEMENTAL CONSTRAINTS                    * * */
+/**********************************************************************/
+
+/* (there are no specific routines for elemental constraints) */
+
+/**********************************************************************/
+/* * *                       GENERIC VALUES                       * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- delete_value - delete generic value.
+--
+-- This routine deletes specified generic value.
+--
+-- NOTE: The generic value to be deleted must be valid. */
+
+void delete_value
+(     MPL *mpl,
+      int type,
+      VALUE *value            /* content destroyed */
+)
+{     xassert(value != NULL);
+      switch (type)
+      {  case A_NONE:
+            value->none = NULL;
+            break;
+         case A_NUMERIC:
+            value->num = 0.0;
+            break;
+         case A_SYMBOLIC:
+            delete_symbol(mpl, value->sym), value->sym = NULL;
+            break;
+         case A_LOGICAL:
+            value->bit = 0;
+            break;
+         case A_TUPLE:
+            delete_tuple(mpl, value->tuple), value->tuple = NULL;
+            break;
+         case A_ELEMSET:
+            delete_elemset(mpl, value->set), value->set = NULL;
+            break;
+         case A_ELEMVAR:
+            value->var = NULL;
+            break;
+         case A_FORMULA:
+            delete_formula(mpl, value->form), value->form = NULL;
+            break;
+         case A_ELEMCON:
+            value->con = NULL;
+            break;
+         default:
+            xassert(type != type);
+      }
+      return;
+}
+
+/**********************************************************************/
+/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_array - create array.
+--
+-- This routine creates an array of specified type and dimension. Being
+-- created the array is initially empty.
+--
+-- The type indicator determines generic values, which can be assigned
+-- to the array members:
+--
+-- A_NONE     - none (members have no assigned values)
+-- A_NUMERIC  - floating-point numbers
+-- A_SYMBOLIC - symbols
+-- A_ELEMSET  - elemental sets
+-- A_ELEMVAR  - elemental variables
+-- A_ELEMCON  - elemental constraints
+--
+-- The dimension may be 0, in which case the array consists of the only
+-- member (such arrays represent 0-dimensional objects). */
+
+ARRAY *create_array(MPL *mpl, int type, int dim)
+{     ARRAY *array;
+      xassert(type == A_NONE || type == A_NUMERIC ||
+             type == A_SYMBOLIC || type == A_ELEMSET ||
+             type == A_ELEMVAR || type == A_ELEMCON);
+      xassert(dim >= 0);
+      array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
+      array->type = type;
+      array->dim = dim;
+      array->size = 0;
+      array->head = NULL;
+      array->tail = NULL;
+      array->tree = NULL;
+      array->prev = NULL;
+      array->next = mpl->a_list;
+      /* include the array in the global array list */
+      if (array->next != NULL) array->next->prev = array;
+      mpl->a_list = array;
+      return array;
+}
+
+/*----------------------------------------------------------------------
+-- find_member - find array member with given n-tuple.
+--
+-- This routine finds an array member, which has given n-tuple. If the
+-- array is short, the linear search is used. Otherwise the routine
+-- autimatically creates the search tree (i.e. the array index) to find
+-- members for logarithmic time. */
+
+static int compare_member_tuples(void *info, const void *key1,
+      const void *key2)
+{     /* this is an auxiliary routine used to compare keys, which are
+         n-tuples assigned to array members */
+      return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
+}
+
+MEMBER *find_member
+(     MPL *mpl,
+      ARRAY *array,           /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      xassert(array != NULL);
+      /* the n-tuple must have the same dimension as the array */
+      xassert(tuple_dimen(mpl, tuple) == array->dim);
+      /* if the array is large enough, create the search tree and index
+         all existing members of the array */
+      if (array->size > 30 && array->tree == NULL)
+      {  array->tree = avl_create_tree(compare_member_tuples, mpl);
+         for (memb = array->head; memb != NULL; memb = memb->next)
+avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
+               (void *)memb);
+      }
+      /* find a member, which has the given tuple */
+      if (array->tree == NULL)
+      {  /* the search tree doesn't exist; use the linear search */
+         for (memb = array->head; memb != NULL; memb = memb->next)
+            if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
+      }
+      else
+      {  /* the search tree exists; use the binary search */
+         AVLNODE *node;
+         node = avl_find_node(array->tree, tuple);
+memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
+      }
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- add_member - add new member to array.
+--
+-- This routine creates a new member with given n-tuple and adds it to
+-- specified array.
+--
+-- For the sake of efficiency this routine doesn't check whether the
+-- array already contains a member with the given n-tuple or not. Thus,
+-- if necessary, the calling program should use the routine find_member
+-- in order to be sure that the array contains no member with the same
+-- n-tuple, because members with duplicate n-tuples are not allowed.
+--
+-- This routine assigns no generic value to the new member, because the
+-- calling program must do that. */
+
+MEMBER *add_member
+(     MPL *mpl,
+      ARRAY *array,           /* modified */
+      TUPLE *tuple            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(array != NULL);
+      /* the n-tuple must have the same dimension as the array */
+      xassert(tuple_dimen(mpl, tuple) == array->dim);
+      /* create new member */
+      memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
+      memb->tuple = tuple;
+      memb->next = NULL;
+      memset(&memb->value, '?', sizeof(VALUE));
+      /* and append it to the member list */
+      array->size++;
+      if (array->head == NULL)
+         array->head = memb;
+      else
+         array->tail->next = memb;
+      array->tail = memb;
+      /* if the search tree exists, index the new member */
+      if (array->tree != NULL)
+avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
+            (void *)memb);
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- delete_array - delete array.
+--
+-- This routine deletes specified array.
+--
+-- Generic values assigned to the array members are not deleted by this
+-- routine. The calling program itself must delete all assigned generic
+-- values before deleting the array. */
+
+void delete_array
+(     MPL *mpl,
+      ARRAY *array            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(array != NULL);
+      /* delete all existing array members */
+      while (array->head != NULL)
+      {  memb = array->head;
+         array->head = memb->next;
+         delete_tuple(mpl, memb->tuple);
+         dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
+      }
+      /* if the search tree exists, also delete it */
+      if (array->tree != NULL) avl_delete_tree(array->tree);
+      /* remove the array from the global array list */
+      if (array->prev == NULL)
+         mpl->a_list = array->next;
+      else
+         array->prev->next = array->next;
+      if (array->next == NULL)
+         ;
+      else
+         array->next->prev = array->prev;
+      /* delete the array descriptor */
+      dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
+      return;
+}
+
+/**********************************************************************/
+/* * *                 DOMAINS AND DUMMY INDICES                  * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- assign_dummy_index - assign new value to dummy index.
+--
+-- This routine assigns new value to specified dummy index and, that is
+-- important, invalidates all temporary resultant values, which depends
+-- on that dummy index. */
+
+void assign_dummy_index
+(     MPL *mpl,
+      DOMAIN_SLOT *slot,      /* modified */
+      SYMBOL *value           /* not changed */
+)
+{     CODE *leaf, *code;
+      xassert(slot != NULL);
+      xassert(value != NULL);
+      /* delete the current value assigned to the dummy index */
+      if (slot->value != NULL)
+      {  /* if the current value and the new one are identical, actual
+            assignment is not needed */
+         if (compare_symbols(mpl, slot->value, value) == 0) goto done;
+         /* delete a symbol, which is the current value */
+         delete_symbol(mpl, slot->value), slot->value = NULL;
+      }
+      /* now walk through all the pseudo-codes with op = O_INDEX, which
+         refer to the dummy index to be changed (these pseudo-codes are
+         leaves in the forest of *all* expressions in the database) */
+      for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
+         next)
+      {  xassert(leaf->op == O_INDEX);
+         /* invalidate all resultant values, which depend on the dummy
+            index, walking from the current leaf toward the root of the
+            corresponding expression tree */
+         for (code = leaf; code != NULL; code = code->up)
+         {  if (code->valid)
+            {  /* invalidate and delete resultant value */
+               code->valid = 0;
+               delete_value(mpl, code->type, &code->value);
+            }
+         }
+      }
+      /* assign new value to the dummy index */
+      slot->value = copy_symbol(mpl, value);
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- update_dummy_indices - update current values of dummy indices.
+--
+-- This routine assigns components of "backup" n-tuple to dummy indices
+-- of specified domain block. If no "backup" n-tuple is defined for the
+-- domain block, values of the dummy indices remain untouched. */
+
+void update_dummy_indices
+(     MPL *mpl,
+      DOMAIN_BLOCK *block     /* not changed */
+)
+{     DOMAIN_SLOT *slot;
+      TUPLE *temp;
+      if (block->backup != NULL)
+      {  for (slot = block->list, temp = block->backup; slot != NULL;
+            slot = slot->next, temp = temp->next)
+         {  xassert(temp != NULL);
+            xassert(temp->sym != NULL);
+            assign_dummy_index(mpl, slot, temp->sym);
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- enter_domain_block - enter domain block.
+--
+-- Let specified domain block have the form:
+--
+--    { ..., (j1, j2, ..., jn) in J, ... }
+--
+-- where j1, j2, ..., jn are dummy indices, J is a basic set.
+--
+-- This routine does the following:
+--
+-- 1. Checks if the given n-tuple is a member of the basic set J. Note
+--    that J being *out of the scope* of the domain block cannot depend
+--    on the dummy indices in the same and inner domain blocks, so it
+--    can be computed before the dummy indices are assigned new values.
+--    If this check fails, the routine returns with non-zero code.
+--
+-- 2. Saves current values of the dummy indices j1, j2, ..., jn.
+--
+-- 3. Assigns new values, which are components of the given n-tuple, to
+--    the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
+--    larger than n, its extra components n+1, n+2, ... are not used.
+--
+-- 4. Calls the formal routine func which either enters the next domain
+--    block or evaluates some code within the domain scope.
+--
+-- 5. Restores former values of the dummy indices j1, j2, ..., jn.
+--
+-- Since current values assigned to the dummy indices on entry to this
+-- routine are restored on exit, the formal routine func is allowed to
+-- call this routine recursively. */
+
+int enter_domain_block
+(     MPL *mpl,
+      DOMAIN_BLOCK *block,    /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+)
+{     TUPLE *backup;
+      int ret = 0;
+      /* check if the given n-tuple is a member of the basic set */
+      xassert(block->code != NULL);
+      if (!is_member(mpl, block->code, tuple))
+      {  ret = 1;
+         goto done;
+      }
+      /* save reference to "backup" n-tuple, which was used to assign
+         current values of the dummy indices (it is sufficient to save
+         reference, not value, because that n-tuple is defined in some
+         outer level of recursion and therefore cannot be changed on
+         this and deeper recursive calls) */
+      backup = block->backup;
+      /* set up new "backup" n-tuple, which defines new values of the
+         dummy indices */
+      block->backup = tuple;
+      /* assign new values to the dummy indices */
+      update_dummy_indices(mpl, block);
+      /* call the formal routine that does the rest part of the job */
+      func(mpl, info);
+      /* restore reference to the former "backup" n-tuple */
+      block->backup = backup;
+      /* restore former values of the dummy indices; note that if the
+         domain block just escaped has no other active instances which
+         may exist due to recursion (it is indicated by a null pointer
+         to the former n-tuple), former values of the dummy indices are
+         undefined; therefore in this case the routine keeps currently
+         assigned values of the dummy indices that involves keeping all
+         dependent temporary results and thereby, if this domain block
+         is not used recursively, allows improving efficiency */
+      update_dummy_indices(mpl, block);
+done: return ret;
+}
+
+/*----------------------------------------------------------------------
+-- eval_within_domain - perform evaluation within domain scope.
+--
+-- This routine assigns new values (symbols) to all dummy indices of
+-- specified domain and calls the formal routine func, which is used to
+-- evaluate some code in the domain scope. Each free dummy index in the
+-- domain is assigned a value specified in the corresponding component
+-- of given n-tuple. Non-free dummy indices are assigned values, which
+-- are computed by this routine.
+--
+-- Number of components in the given n-tuple must be the same as number
+-- of free indices in the domain.
+--
+-- If the given n-tuple is not a member of the domain set, the routine
+-- func is not called, and non-zero code is returned.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL
+-- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
+-- routine just calls the routine func and returns zero.
+--
+-- This routine allows recursive calls from the routine func providing
+-- correct values of dummy indices for each instance.
+--
+-- NOTE: The n-tuple passed to this routine must not be changed by any
+--       other routines called from the formal routine func until this
+--       routine has returned. */
+
+struct eval_domain_info
+{     /* working info used by the routine eval_within_domain */
+      DOMAIN *domain;
+      /* domain, which has to be entered */
+      DOMAIN_BLOCK *block;
+      /* domain block, which is currently processed */
+      TUPLE *tuple;
+      /* tail of original n-tuple, whose components have to be assigned
+         to free dummy indices in the current domain block */
+      void *info;
+      /* transit pointer passed to the formal routine func */
+      void (*func)(MPL *mpl, void *info);
+      /* routine, which has to be executed in the domain scope */
+      int failure;
+      /* this flag indicates that given n-tuple is not a member of the
+         domain set */
+};
+
+static void eval_domain_func(MPL *mpl, void *_my_info)
+{     /* this routine recursively enters into the domain scope and then
+         calls the routine func */
+      struct eval_domain_info *my_info = _my_info;
+      if (my_info->block != NULL)
+      {  /* the current domain block to be entered exists */
+         DOMAIN_BLOCK *block;
+         DOMAIN_SLOT *slot;
+         TUPLE *tuple = NULL, *temp = NULL;
+         /* save pointer to the current domain block */
+         block = my_info->block;
+         /* and get ready to enter the next block (if it exists) */
+         my_info->block = block->next;
+         /* construct temporary n-tuple, whose components correspond to
+            dummy indices (slots) of the current domain; components of
+            the temporary n-tuple that correspond to free dummy indices
+            are assigned references (not values!) to symbols specified
+            in the corresponding components of the given n-tuple, while
+            other components that correspond to non-free dummy indices
+            are assigned symbolic values computed here */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  /* create component that corresponds to the current slot */
+            if (tuple == NULL)
+               tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+            else
+temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
+            if (slot->code == NULL)
+            {  /* dummy index is free; take reference to symbol, which
+                  is specified in the corresponding component of given
+                  n-tuple */
+               xassert(my_info->tuple != NULL);
+               temp->sym = my_info->tuple->sym;
+               xassert(temp->sym != NULL);
+               my_info->tuple = my_info->tuple->next;
+            }
+            else
+            {  /* dummy index is non-free; compute symbolic value to be
+                  temporarily assigned to the dummy index */
+               temp->sym = eval_symbolic(mpl, slot->code);
+            }
+         }
+         temp->next = NULL;
+         /* enter the current domain block */
+         if (enter_domain_block(mpl, block, tuple, my_info,
+               eval_domain_func)) my_info->failure = 1;
+         /* delete temporary n-tuple as well as symbols that correspond
+            to non-free dummy indices (they were computed here) */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  xassert(tuple != NULL);
+            temp = tuple;
+            tuple = tuple->next;
+            if (slot->code != NULL)
+            {  /* dummy index is non-free; delete symbolic value */
+               delete_symbol(mpl, temp->sym);
+            }
+            /* delete component that corresponds to the current slot */
+            dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+         }
+      }
+      else
+      {  /* there are no more domain blocks, i.e. we have reached the
+            domain scope */
+         xassert(my_info->tuple == NULL);
+         /* check optional predicate specified for the domain */
+         if (my_info->domain->code != NULL && !eval_logical(mpl,
+            my_info->domain->code))
+         {  /* the predicate is false */
+            my_info->failure = 2;
+         }
+         else
+         {  /* the predicate is true; do the job */
+            my_info->func(mpl, my_info->info);
+         }
+      }
+      return;
+}
+
+int eval_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+)
+{     /* this routine performs evaluation within domain scope */
+      struct eval_domain_info _my_info, *my_info = &_my_info;
+      if (domain == NULL)
+      {  xassert(tuple == NULL);
+         func(mpl, info);
+         my_info->failure = 0;
+      }
+      else
+      {  xassert(tuple != NULL);
+         my_info->domain = domain;
+         my_info->block = domain->list;
+         my_info->tuple = tuple;
+         my_info->info = info;
+         my_info->func = func;
+         my_info->failure = 0;
+         /* enter the very first domain block */
+         eval_domain_func(mpl, my_info);
+      }
+      return my_info->failure;
+}
+
+/*----------------------------------------------------------------------
+-- loop_within_domain - perform iterations within domain scope.
+--
+-- This routine iteratively assigns new values (symbols) to the dummy
+-- indices of specified domain by enumerating all n-tuples, which are
+-- members of the domain set, and for every n-tuple it calls the formal
+-- routine func to evaluate some code within the domain scope.
+--
+-- If the routine func returns non-zero, enumeration within the domain
+-- is prematurely terminated.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL,
+-- in which case this routine just calls the routine func only once and
+-- returns zero.
+--
+-- This routine allows recursive calls from the routine func providing
+-- correct values of dummy indices for each instance. */
+
+struct loop_domain_info
+{     /* working info used by the routine loop_within_domain */
+      DOMAIN *domain;
+      /* domain, which has to be entered */
+      DOMAIN_BLOCK *block;
+      /* domain block, which is currently processed */
+      int looping;
+      /* clearing this flag leads to terminating enumeration */
+      void *info;
+      /* transit pointer passed to the formal routine func */
+      int (*func)(MPL *mpl, void *info);
+      /* routine, which needs to be executed in the domain scope */
+};
+
+static void loop_domain_func(MPL *mpl, void *_my_info)
+{     /* this routine enumerates all n-tuples in the basic set of the
+         current domain block, enters recursively into the domain scope
+         for every n-tuple, and then calls the routine func */
+      struct loop_domain_info *my_info = _my_info;
+      if (my_info->block != NULL)
+      {  /* the current domain block to be entered exists */
+         DOMAIN_BLOCK *block;
+         DOMAIN_SLOT *slot;
+         TUPLE *bound;
+         /* save pointer to the current domain block */
+         block = my_info->block;
+         /* and get ready to enter the next block (if it exists) */
+         my_info->block = block->next;
+         /* compute symbolic values, at which non-free dummy indices of
+            the current domain block are bound; since that values don't
+            depend on free dummy indices of the current block, they can
+            be computed once out of the enumeration loop */
+         bound = create_tuple(mpl);
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  if (slot->code != NULL)
+               bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
+                  slot->code));
+         }
+         /* start enumeration */
+         xassert(block->code != NULL);
+         if (block->code->op == O_DOTS)
+         {  /* the basic set is "arithmetic", in which case it doesn't
+               need to be computed explicitly */
+            TUPLE *tuple;
+            int n, j;
+            double t0, tf, dt;
+            /* compute "parameters" of the basic set */
+            t0 = eval_numeric(mpl, block->code->arg.arg.x);
+            tf = eval_numeric(mpl, block->code->arg.arg.y);
+            if (block->code->arg.arg.z == NULL)
+               dt = 1.0;
+            else
+               dt = eval_numeric(mpl, block->code->arg.arg.z);
+            /* determine cardinality of the basic set */
+            n = arelset_size(mpl, t0, tf, dt);
+            /* create dummy 1-tuple for members of the basic set */
+            tuple = expand_tuple(mpl, create_tuple(mpl),
+               create_symbol_num(mpl, 0.0));
+            /* in case of "arithmetic" set there is exactly one dummy
+               index, which cannot be non-free */
+            xassert(bound == NULL);
+            /* walk through 1-tuples of the basic set */
+            for (j = 1; j <= n && my_info->looping; j++)
+            {  /* construct dummy 1-tuple for the current member */
+               tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
+               /* enter the current domain block */
+               enter_domain_block(mpl, block, tuple, my_info,
+                  loop_domain_func);
+            }
+            /* delete dummy 1-tuple */
+            delete_tuple(mpl, tuple);
+         }
+         else
+         {  /* the basic set is of general kind, in which case it needs
+               to be explicitly computed */
+            ELEMSET *set;
+            MEMBER *memb;
+            TUPLE *temp1, *temp2;
+            /* compute the basic set */
+            set = eval_elemset(mpl, block->code);
+            /* walk through all n-tuples of the basic set */
+            for (memb = set->head; memb != NULL && my_info->looping;
+               memb = memb->next)
+            {  /* all components of the current n-tuple that correspond
+                  to non-free dummy indices must be feasible; otherwise
+                  the n-tuple is not in the basic set */
+               temp1 = memb->tuple;
+               temp2 = bound;
+               for (slot = block->list; slot != NULL; slot = slot->next)
+               {  xassert(temp1 != NULL);
+                  if (slot->code != NULL)
+                  {  /* non-free dummy index */
+                     xassert(temp2 != NULL);
+                     if (compare_symbols(mpl, temp1->sym, temp2->sym)
+                        != 0)
+                     {  /* the n-tuple is not in the basic set */
+                        goto skip;
+                     }
+                     temp2 = temp2->next;
+                  }
+                  temp1 = temp1->next;
+               }
+               xassert(temp1 == NULL);
+               xassert(temp2 == NULL);
+               /* enter the current domain block */
+               enter_domain_block(mpl, block, memb->tuple, my_info,
+                  loop_domain_func);
+skip:          ;
+            }
+            /* delete the basic set */
+            delete_elemset(mpl, set);
+         }
+         /* delete symbolic values binding non-free dummy indices */
+         delete_tuple(mpl, bound);
+         /* restore pointer to the current domain block */
+         my_info->block = block;
+      }
+      else
+      {  /* there are no more domain blocks, i.e. we have reached the
+            domain scope */
+         /* check optional predicate specified for the domain */
+         if (my_info->domain->code != NULL && !eval_logical(mpl,
+            my_info->domain->code))
+         {  /* the predicate is false */
+            /* nop */;
+         }
+         else
+         {  /* the predicate is true; do the job */
+            my_info->looping = !my_info->func(mpl, my_info->info);
+         }
+      }
+      return;
+}
+
+void loop_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      void *info, int (*func)(MPL *mpl, void *info)
+)
+{     /* this routine performs iterations within domain scope */
+      struct loop_domain_info _my_info, *my_info = &_my_info;
+      if (domain == NULL)
+         func(mpl, info);
+      else
+      {  my_info->domain = domain;
+         my_info->block = domain->list;
+         my_info->looping = 1;
+         my_info->info = info;
+         my_info->func = func;
+         /* enter the very first domain block */
+         loop_domain_func(mpl, my_info);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- out_of_domain - raise domain exception.
+--
+-- This routine is called when a reference is made to a member of some
+-- model object, but its n-tuple is out of the object domain. */
+
+void out_of_domain
+(     MPL *mpl,
+      char *name,             /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     xassert(name != NULL);
+      xassert(tuple != NULL);
+      error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
+         tuple));
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- get_domain_tuple - obtain current n-tuple from domain.
+--
+-- This routine constructs n-tuple, whose components are current values
+-- assigned to *free* dummy indices of specified domain.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL,
+-- in which case this routine returns 0-tuple.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+TUPLE *get_domain_tuple
+(     MPL *mpl,
+      DOMAIN *domain          /* not changed */
+)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      TUPLE *tuple;
+      tuple = create_tuple(mpl);
+      if (domain != NULL)
+      {  for (block = domain->list; block != NULL; block = block->next)
+         {  for (slot = block->list; slot != NULL; slot = slot->next)
+            {  if (slot->code == NULL)
+               {  xassert(slot->value != NULL);
+                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                     slot->value));
+               }
+            }
+         }
+      }
+      return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- clean_domain - clean domain.
+--
+-- This routine cleans specified domain that assumes deleting all stuff
+-- dynamically allocated during the generation phase. */
+
+void clean_domain(MPL *mpl, DOMAIN *domain)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      /* if no domain is specified, do nothing */
+      if (domain == NULL) goto done;
+      /* clean all domain blocks */
+      for (block = domain->list; block != NULL; block = block->next)
+      {  /* clean all domain slots */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  /* clean pseudo-code for computing bound value */
+            clean_code(mpl, slot->code);
+            /* delete symbolic value assigned to dummy index */
+            if (slot->value != NULL)
+               delete_symbol(mpl, slot->value), slot->value = NULL;
+         }
+         /* clean pseudo-code for computing basic set */
+         clean_code(mpl, block->code);
+      }
+      /* clean pseudo-code for computing domain predicate */
+      clean_code(mpl, domain->code);
+done: return;
+}
+
+/**********************************************************************/
+/* * *                         MODEL SETS                         * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- check_elem_set - check elemental set assigned to set member.
+--
+-- This routine checks if given elemental set being assigned to member
+-- of specified model set satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_elem_set
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple,           /* not changed */
+      ELEMSET *refer          /* not changed */
+)
+{     WITHIN *within;
+      MEMBER *memb;
+      int eqno;
+      /* elemental set must be within all specified supersets */
+      for (within = set->within, eqno = 1; within != NULL; within =
+         within->next, eqno++)
+      {  xassert(within->code != NULL);
+         for (memb = refer->head; memb != NULL; memb = memb->next)
+         {  if (!is_member(mpl, within->code, memb->tuple))
+            {  char buf[255+1];
+               strcpy(buf, format_tuple(mpl, '(', memb->tuple));
+               xassert(strlen(buf) < sizeof(buf));
+               error(mpl, "%s%s contains %s which not within specified "
+                  "set; see (%d)", set->name, format_tuple(mpl, '[',
+                     tuple), buf, eqno);
+            }
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_set - obtain elemental set assigned to set member.
+--
+-- This routine obtains a reference to elemental set assigned to given
+-- member of specified model set and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMSET *take_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      ELEMSET *refer;
+      /* find member in the set array */
+      memb = find_member(mpl, set->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take the reference */
+         refer = memb->value.set;
+      }
+      else if (set->assign != NULL)
+      {  /* compute value using assignment expression */
+         refer = eval_elemset(mpl, set->assign);
+add:     /* check that the elemental set satisfies to all restrictions,
+            assign it to new member, and add the member to the array */
+         check_elem_set(mpl, set, tuple, refer);
+         memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
+         memb->value.set = refer;
+      }
+      else if (set->option != NULL)
+      {  /* compute default elemental set */
+         refer = eval_elemset(mpl, set->option);
+         goto add;
+      }
+      else
+      {  /* no value (elemental set) is provided */
+         error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
+            '[', tuple));
+      }
+      return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_set - evaluate elemental set assigned to set member.
+--
+-- This routine evaluates a reference to elemental set assigned to given
+-- member of specified model set and returns it on exit. */
+
+struct eval_set_info
+{     /* working info used by the routine eval_member_set */
+      SET *set;
+      /* model set */
+      TUPLE *tuple;
+      /* n-tuple, which defines set member */
+      MEMBER *memb;
+      /* normally this pointer is NULL; the routine uses this pointer
+         to check data provided in the data section, in which case it
+         points to a member currently checked; this check is performed
+         automatically only once when a reference to any member occurs
+         for the first time */
+      ELEMSET *refer;
+      /* evaluated reference to elemental set */
+};
+
+static void eval_set_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_set_info *info = _info;
+      if (info->memb != NULL)
+      {  /* checking call; check elemental set being assigned */
+         check_elem_set(mpl, info->set, info->memb->tuple,
+            info->memb->value.set);
+      }
+      else
+      {  /* normal call; evaluate member, which has given n-tuple */
+         info->refer = take_member_set(mpl, info->set, info->tuple);
+      }
+      return;
+}
+
+#if 1 /* 12/XII-2008 */
+static void saturate_set(MPL *mpl, SET *set)
+{     GADGET *gadget = set->gadget;
+      ELEMSET *data;
+      MEMBER *elem, *memb;
+      TUPLE *tuple, *work[20];
+      int i;
+      xprintf("Generating %s...\n", set->name);
+      eval_whole_set(mpl, gadget->set);
+      /* gadget set must have exactly one member */
+      xassert(gadget->set->array != NULL);
+      xassert(gadget->set->array->head != NULL);
+      xassert(gadget->set->array->head == gadget->set->array->tail);
+      data = gadget->set->array->head->value.set;
+      xassert(data->type == A_NONE);
+      xassert(data->dim == gadget->set->dimen);
+      /* walk thru all elements of the plain set */
+      for (elem = data->head; elem != NULL; elem = elem->next)
+      {  /* create a copy of n-tuple */
+         tuple = copy_tuple(mpl, elem->tuple);
+         /* rearrange component of the n-tuple */
+         for (i = 0; i < gadget->set->dimen; i++)
+            work[i] = NULL;
+         for (i = 0; tuple != NULL; tuple = tuple->next)
+            work[gadget->ind[i++]-1] = tuple;
+         xassert(i == gadget->set->dimen);
+         for (i = 0; i < gadget->set->dimen; i++)
+         {  xassert(work[i] != NULL);
+            work[i]->next = work[i+1];
+         }
+         /* construct subscript list from first set->dim components */
+         if (set->dim == 0)
+            tuple = NULL;
+         else
+            tuple = work[0], work[set->dim-1]->next = NULL;
+         /* find corresponding member of the set to be initialized */
+         memb = find_member(mpl, set->array, tuple);
+         if (memb == NULL)
+         {  /* not found; add new member to the set and assign it empty
+               elemental set */
+            memb = add_member(mpl, set->array, tuple);
+            memb->value.set = create_elemset(mpl, set->dimen);
+         }
+         else
+         {  /* found; free subscript list */
+            delete_tuple(mpl, tuple);
+         }
+         /* construct new n-tuple from rest set->dimen components */
+         tuple = work[set->dim];
+         xassert(set->dim + set->dimen == gadget->set->dimen);
+         work[gadget->set->dimen-1]->next = NULL;
+         /* and add it to the elemental set assigned to the member
+            (no check for duplicates is needed) */
+         add_tuple(mpl, memb->value.set, tuple);
+      }
+      /* the set has been saturated with data */
+      set->data = 1;
+      return;
+}
+#endif
+
+ELEMSET *eval_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates set member */
+      struct eval_set_info _info, *info = &_info;
+      xassert(set->dim == tuple_dimen(mpl, tuple));
+      info->set = set;
+      info->tuple = tuple;
+#if 1 /* 12/XII-2008 */
+      if (set->gadget != NULL && set->data == 0)
+      {  /* initialize the set with data from a plain set */
+         saturate_set(mpl, set);
+      }
+#endif
+      if (set->data == 1)
+      {  /* check data, which are provided in the data section, but not
+            checked yet */
+         /* save pointer to the last array member; note that during the
+            check new members may be added beyond the last member due to
+            references to the same parameter from default expression as
+            well as from expressions that define restricting supersets;
+            however, values assigned to the new members will be checked
+            by other routine, so we don't need to check them here */
+         MEMBER *tail = set->array->tail;
+         /* change the data status to prevent infinite recursive loop
+            due to references to the same set during the check */
+         set->data = 2;
+         /* check elemental sets assigned to array members in the data
+            section until the marked member has been reached */
+         for (info->memb = set->array->head; info->memb != NULL;
+            info->memb = info->memb->next)
+         {  if (eval_within_domain(mpl, set->domain, info->memb->tuple,
+               info, eval_set_func))
+               out_of_domain(mpl, set->name, info->memb->tuple);
+            if (info->memb == tail) break;
+         }
+         /* the check has been finished */
+      }
+      /* evaluate member, which has given n-tuple */
+      info->memb = NULL;
+      if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
+         eval_set_func))
+      out_of_domain(mpl, set->name, info->tuple);
+      /* bring evaluated reference to the calling program */
+      return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_set - evaluate model set over entire domain.
+--
+-- This routine evaluates all members of specified model set over entire
+-- domain. */
+
+static int whole_set_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      SET *set = (SET *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, set->domain);
+      eval_member_set(mpl, set, tuple);
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_set(MPL *mpl, SET *set)
+{     loop_within_domain(mpl, set->domain, set, whole_set_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean set - clean model set.
+--
+-- This routine cleans specified model set that assumes deleting all
+-- stuff dynamically allocated during the generation phase. */
+
+void clean_set(MPL *mpl, SET *set)
+{     WITHIN *within;
+      MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, set->domain);
+      /* clean pseudo-code for computing supersets */
+      for (within = set->within; within != NULL; within = within->next)
+         clean_code(mpl, within->code);
+      /* clean pseudo-code for computing assigned value */
+      clean_code(mpl, set->assign);
+      /* clean pseudo-code for computing default value */
+      clean_code(mpl, set->option);
+      /* reset data status flag */
+      set->data = 0;
+      /* delete content array */
+      for (memb = set->array->head; memb != NULL; memb = memb->next)
+         delete_value(mpl, set->array->type, &memb->value);
+      delete_array(mpl, set->array), set->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *                      MODEL PARAMETERS                      * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- check_value_num - check numeric value assigned to parameter member.
+--
+-- This routine checks if numeric value being assigned to some member
+-- of specified numeric model parameter satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_value_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      double value
+)
+{     CONDITION *cond;
+      WITHIN *in;
+      int eqno;
+      /* the value must satisfy to the parameter type */
+      switch (par->type)
+      {  case A_NUMERIC:
+            break;
+         case A_INTEGER:
+            if (value != floor(value))
+               error(mpl, "%s%s = %.*g not integer", par->name,
+                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
+            break;
+         case A_BINARY:
+            if (!(value == 0.0 || value == 1.0))
+               error(mpl, "%s%s = %.*g not binary", par->name,
+                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
+            break;
+         default:
+            xassert(par != par);
+      }
+      /* the value must satisfy to all specified conditions */
+      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
+         eqno++)
+      {  double bound;
+         char *rho;
+         xassert(cond->code != NULL);
+         bound = eval_numeric(mpl, cond->code);
+         switch (cond->rho)
+         {  case O_LT:
+               if (!(value < bound))
+               {  rho = "<";
+err:              error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
+                     par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
+                     value, rho, DBL_DIG, bound, eqno);
+               }
+               break;
+            case O_LE:
+               if (!(value <= bound)) { rho = "<="; goto err; }
+               break;
+            case O_EQ:
+               if (!(value == bound)) { rho = "="; goto err; }
+               break;
+            case O_GE:
+               if (!(value >= bound)) { rho = ">="; goto err; }
+               break;
+            case O_GT:
+               if (!(value > bound)) { rho = ">"; goto err; }
+               break;
+            case O_NE:
+               if (!(value != bound)) { rho = "<>"; goto err; }
+               break;
+            default:
+               xassert(cond != cond);
+         }
+      }
+      /* the value must be in all specified supersets */
+      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
+      {  TUPLE *dummy;
+         xassert(in->code != NULL);
+         xassert(in->code->dim == 1);
+         dummy = expand_tuple(mpl, create_tuple(mpl),
+            create_symbol_num(mpl, value));
+         if (!is_member(mpl, in->code, dummy))
+            error(mpl, "%s%s = %.*g not in specified set; see (%d)",
+               par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
+               value, eqno);
+         delete_tuple(mpl, dummy);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_num - obtain num. value assigned to parameter member.
+--
+-- This routine obtains a numeric value assigned to member of specified
+-- numeric model parameter and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+double take_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      double value;
+      /* find member in the parameter array */
+      memb = find_member(mpl, par->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take its value */
+         value = memb->value.num;
+      }
+      else if (par->assign != NULL)
+      {  /* compute value using assignment expression */
+         value = eval_numeric(mpl, par->assign);
+add:     /* check that the value satisfies to all restrictions, assign
+            it to new member, and add the member to the array */
+         check_value_num(mpl, par, tuple, value);
+         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
+         memb->value.num = value;
+      }
+      else if (par->option != NULL)
+      {  /* compute default value */
+         value = eval_numeric(mpl, par->option);
+         goto add;
+      }
+      else if (par->defval != NULL)
+      {  /* take default value provided in the data section */
+         if (par->defval->str != NULL)
+            error(mpl, "cannot convert %s to floating-point number",
+               format_symbol(mpl, par->defval));
+         value = par->defval->num;
+         goto add;
+      }
+      else
+      {  /* no value is provided */
+         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
+            '[', tuple));
+      }
+      return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_num - evaluate num. value assigned to parameter member.
+--
+-- This routine evaluates a numeric value assigned to given member of
+-- specified numeric model parameter and returns it on exit. */
+
+struct eval_num_info
+{     /* working info used by the routine eval_member_num */
+      PARAMETER *par;
+      /* model parameter  */
+      TUPLE *tuple;
+      /* n-tuple, which defines parameter member */
+      MEMBER *memb;
+      /* normally this pointer is NULL; the routine uses this pointer
+         to check data provided in the data section, in which case it
+         points to a member currently checked; this check is performed
+         automatically only once when a reference to any member occurs
+         for the first time */
+      double value;
+      /* evaluated numeric value */
+};
+
+static void eval_num_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_num_info *info = _info;
+      if (info->memb != NULL)
+      {  /* checking call; check numeric value being assigned */
+         check_value_num(mpl, info->par, info->memb->tuple,
+            info->memb->value.num);
+      }
+      else
+      {  /* normal call; evaluate member, which has given n-tuple */
+         info->value = take_member_num(mpl, info->par, info->tuple);
+      }
+      return;
+}
+
+double eval_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates numeric parameter member */
+      struct eval_num_info _info, *info = &_info;
+      xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
+             par->type == A_BINARY);
+      xassert(par->dim == tuple_dimen(mpl, tuple));
+      info->par = par;
+      info->tuple = tuple;
+      if (par->data == 1)
+      {  /* check data, which are provided in the data section, but not
+            checked yet */
+         /* save pointer to the last array member; note that during the
+            check new members may be added beyond the last member due to
+            references to the same parameter from default expression as
+            well as from expressions that define restricting conditions;
+            however, values assigned to the new members will be checked
+            by other routine, so we don't need to check them here */
+         MEMBER *tail = par->array->tail;
+         /* change the data status to prevent infinite recursive loop
+            due to references to the same parameter during the check */
+         par->data = 2;
+         /* check values assigned to array members in the data section
+            until the marked member has been reached */
+         for (info->memb = par->array->head; info->memb != NULL;
+            info->memb = info->memb->next)
+         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
+               info, eval_num_func))
+               out_of_domain(mpl, par->name, info->memb->tuple);
+            if (info->memb == tail) break;
+         }
+         /* the check has been finished */
+      }
+      /* evaluate member, which has given n-tuple */
+      info->memb = NULL;
+      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
+         eval_num_func))
+         out_of_domain(mpl, par->name, info->tuple);
+      /* bring evaluated value to the calling program */
+      return info->value;
+}
+
+/*----------------------------------------------------------------------
+-- check_value_sym - check symbolic value assigned to parameter member.
+--
+-- This routine checks if symbolic value being assigned to some member
+-- of specified symbolic model parameter satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_value_sym
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      SYMBOL *value           /* not changed */
+)
+{     CONDITION *cond;
+      WITHIN *in;
+      int eqno;
+      /* the value must satisfy to all specified conditions */
+      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
+         eqno++)
+      {  SYMBOL *bound;
+         char buf[255+1];
+         xassert(cond->code != NULL);
+         bound = eval_symbolic(mpl, cond->code);
+         switch (cond->rho)
+         {
+#if 1 /* 13/VIII-2008 */
+            case O_LT:
+               if (!(compare_symbols(mpl, value, bound) < 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not < %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+            case O_LE:
+               if (!(compare_symbols(mpl, value, bound) <= 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not <= %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+#endif
+            case O_EQ:
+               if (!(compare_symbols(mpl, value, bound) == 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not = %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+#if 1 /* 13/VIII-2008 */
+            case O_GE:
+               if (!(compare_symbols(mpl, value, bound) >= 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not >= %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+            case O_GT:
+               if (!(compare_symbols(mpl, value, bound) > 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not > %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+#endif
+            case O_NE:
+               if (!(compare_symbols(mpl, value, bound) != 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not <> %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+            default:
+               xassert(cond != cond);
+         }
+         delete_symbol(mpl, bound);
+      }
+      /* the value must be in all specified supersets */
+      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
+      {  TUPLE *dummy;
+         xassert(in->code != NULL);
+         xassert(in->code->dim == 1);
+         dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
+            value));
+         if (!is_member(mpl, in->code, dummy))
+            error(mpl, "%s%s = %s not in specified set; see (%d)",
+               par->name, format_tuple(mpl, '[', tuple),
+               format_symbol(mpl, value), eqno);
+         delete_tuple(mpl, dummy);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_sym - obtain symb. value assigned to parameter member.
+--
+-- This routine obtains a symbolic value assigned to member of specified
+-- symbolic model parameter and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+SYMBOL *take_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      SYMBOL *value;
+      /* find member in the parameter array */
+      memb = find_member(mpl, par->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take its value */
+         value = copy_symbol(mpl, memb->value.sym);
+      }
+      else if (par->assign != NULL)
+      {  /* compute value using assignment expression */
+         value = eval_symbolic(mpl, par->assign);
+add:     /* check that the value satisfies to all restrictions, assign
+            it to new member, and add the member to the array */
+         check_value_sym(mpl, par, tuple, value);
+         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
+         memb->value.sym = copy_symbol(mpl, value);
+      }
+      else if (par->option != NULL)
+      {  /* compute default value */
+         value = eval_symbolic(mpl, par->option);
+         goto add;
+      }
+      else if (par->defval != NULL)
+      {  /* take default value provided in the data section */
+         value = copy_symbol(mpl, par->defval);
+         goto add;
+      }
+      else
+      {  /* no value is provided */
+         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
+            '[', tuple));
+      }
+      return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_sym - evaluate symb. value assigned to parameter member.
+--
+-- This routine evaluates a symbolic value assigned to given member of
+-- specified symbolic model parameter and returns it on exit. */
+
+struct eval_sym_info
+{     /* working info used by the routine eval_member_sym */
+      PARAMETER *par;
+      /* model parameter */
+      TUPLE *tuple;
+      /* n-tuple, which defines parameter member */
+      MEMBER *memb;
+      /* normally this pointer is NULL; the routine uses this pointer
+         to check data provided in the data section, in which case it
+         points to a member currently checked; this check is performed
+         automatically only once when a reference to any member occurs
+         for the first time */
+      SYMBOL *value;
+      /* evaluated symbolic value */
+};
+
+static void eval_sym_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_sym_info *info = _info;
+      if (info->memb != NULL)
+      {  /* checking call; check symbolic value being assigned */
+         check_value_sym(mpl, info->par, info->memb->tuple,
+            info->memb->value.sym);
+      }
+      else
+      {  /* normal call; evaluate member, which has given n-tuple */
+         info->value = take_member_sym(mpl, info->par, info->tuple);
+      }
+      return;
+}
+
+SYMBOL *eval_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates symbolic parameter member */
+      struct eval_sym_info _info, *info = &_info;
+      xassert(par->type == A_SYMBOLIC);
+      xassert(par->dim == tuple_dimen(mpl, tuple));
+      info->par = par;
+      info->tuple = tuple;
+      if (par->data == 1)
+      {  /* check data, which are provided in the data section, but not
+            checked yet */
+         /* save pointer to the last array member; note that during the
+            check new members may be added beyond the last member due to
+            references to the same parameter from default expression as
+            well as from expressions that define restricting conditions;
+            however, values assigned to the new members will be checked
+            by other routine, so we don't need to check them here */
+         MEMBER *tail = par->array->tail;
+         /* change the data status to prevent infinite recursive loop
+            due to references to the same parameter during the check */
+         par->data = 2;
+         /* check values assigned to array members in the data section
+            until the marked member has been reached */
+         for (info->memb = par->array->head; info->memb != NULL;
+            info->memb = info->memb->next)
+         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
+               info, eval_sym_func))
+               out_of_domain(mpl, par->name, info->memb->tuple);
+            if (info->memb == tail) break;
+         }
+         /* the check has been finished */
+      }
+      /* evaluate member, which has given n-tuple */
+      info->memb = NULL;
+      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
+         eval_sym_func))
+         out_of_domain(mpl, par->name, info->tuple);
+      /* bring evaluated value to the calling program */
+      return info->value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_par - evaluate model parameter over entire domain.
+--
+-- This routine evaluates all members of specified model parameter over
+-- entire domain. */
+
+static int whole_par_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      PARAMETER *par = (PARAMETER *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, par->domain);
+      switch (par->type)
+      {  case A_NUMERIC:
+         case A_INTEGER:
+         case A_BINARY:
+            eval_member_num(mpl, par, tuple);
+            break;
+         case A_SYMBOLIC:
+            delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
+            break;
+         default:
+            xassert(par != par);
+      }
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_par(MPL *mpl, PARAMETER *par)
+{     loop_within_domain(mpl, par->domain, par, whole_par_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_parameter - clean model parameter.
+--
+-- This routine cleans specified model parameter that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_parameter(MPL *mpl, PARAMETER *par)
+{     CONDITION *cond;
+      WITHIN *in;
+      MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, par->domain);
+      /* clean pseudo-code for computing restricting conditions */
+      for (cond = par->cond; cond != NULL; cond = cond->next)
+         clean_code(mpl, cond->code);
+      /* clean pseudo-code for computing restricting supersets */
+      for (in = par->in; in != NULL; in = in->next)
+         clean_code(mpl, in->code);
+      /* clean pseudo-code for computing assigned value */
+      clean_code(mpl, par->assign);
+      /* clean pseudo-code for computing default value */
+      clean_code(mpl, par->option);
+      /* reset data status flag */
+      par->data = 0;
+      /* delete default symbolic value */
+      if (par->defval != NULL)
+         delete_symbol(mpl, par->defval), par->defval = NULL;
+      /* delete content array */
+      for (memb = par->array->head; memb != NULL; memb = memb->next)
+         delete_value(mpl, par->array->type, &memb->value);
+      delete_array(mpl, par->array), par->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *                      MODEL VARIABLES                       * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- take_member_var - obtain reference to elemental variable.
+--
+-- This routine obtains a reference to elemental variable assigned to
+-- given member of specified model variable and returns it on exit. If
+-- necessary, new elemental variable is created.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMVAR *take_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      ELEMVAR *refer;
+      /* find member in the variable array */
+      memb = find_member(mpl, var->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take the reference */
+         refer = memb->value.var;
+      }
+      else
+      {  /* member is referenced for the first time and therefore does
+            not exist; create new elemental variable, assign it to new
+            member, and add the member to the variable array */
+         memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
+         refer = (memb->value.var =
+            dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
+         refer->j = 0;
+         refer->var = var;
+         refer->memb = memb;
+         /* compute lower bound */
+         if (var->lbnd == NULL)
+            refer->lbnd = 0.0;
+         else
+            refer->lbnd = eval_numeric(mpl, var->lbnd);
+         /* compute upper bound */
+         if (var->ubnd == NULL)
+            refer->ubnd = 0.0;
+         else if (var->ubnd == var->lbnd)
+            refer->ubnd = refer->lbnd;
+         else
+            refer->ubnd = eval_numeric(mpl, var->ubnd);
+         /* nullify working quantity */
+         refer->temp = 0.0;
+#if 1 /* 15/V-2010 */
+         /* solution has not been obtained by the solver yet */
+         refer->stat = 0;
+         refer->prim = refer->dual = 0.0;
+#endif
+      }
+      return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_var - evaluate reference to elemental variable.
+--
+-- This routine evaluates a reference to elemental variable assigned to
+-- member of specified model variable and returns it on exit. */
+
+struct eval_var_info
+{     /* working info used by the routine eval_member_var */
+      VARIABLE *var;
+      /* model variable */
+      TUPLE *tuple;
+      /* n-tuple, which defines variable member */
+      ELEMVAR *refer;
+      /* evaluated reference to elemental variable */
+};
+
+static void eval_var_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_var_info *info = _info;
+      info->refer = take_member_var(mpl, info->var, info->tuple);
+      return;
+}
+
+ELEMVAR *eval_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates variable member */
+      struct eval_var_info _info, *info = &_info;
+      xassert(var->dim == tuple_dimen(mpl, tuple));
+      info->var = var;
+      info->tuple = tuple;
+      /* evaluate member, which has given n-tuple */
+      if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
+         eval_var_func))
+         out_of_domain(mpl, var->name, info->tuple);
+      /* bring evaluated reference to the calling program */
+      return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_var - evaluate model variable over entire domain.
+--
+-- This routine evaluates all members of specified model variable over
+-- entire domain. */
+
+static int whole_var_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      VARIABLE *var = (VARIABLE *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, var->domain);
+      eval_member_var(mpl, var, tuple);
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_var(MPL *mpl, VARIABLE *var)
+{     loop_within_domain(mpl, var->domain, var, whole_var_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_variable - clean model variable.
+--
+-- This routine cleans specified model variable that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_variable(MPL *mpl, VARIABLE *var)
+{     MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, var->domain);
+      /* clean code for computing lower bound */
+      clean_code(mpl, var->lbnd);
+      /* clean code for computing upper bound */
+      if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
+      /* delete content array */
+      for (memb = var->array->head; memb != NULL; memb = memb->next)
+         dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
+      delete_array(mpl, var->array), var->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- take_member_con - obtain reference to elemental constraint.
+--
+-- This routine obtains a reference to elemental constraint assigned
+-- to given member of specified model constraint and returns it on exit.
+-- If necessary, new elemental constraint is created.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMCON *take_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      ELEMCON *refer;
+      /* find member in the constraint array */
+      memb = find_member(mpl, con->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take the reference */
+         refer = memb->value.con;
+      }
+      else
+      {  /* member is referenced for the first time and therefore does
+            not exist; create new elemental constraint, assign it to new
+            member, and add the member to the constraint array */
+         memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
+         refer = (memb->value.con =
+            dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
+         refer->i = 0;
+         refer->con = con;
+         refer->memb = memb;
+         /* compute linear form */
+         xassert(con->code != NULL);
+         refer->form = eval_formula(mpl, con->code);
+         /* compute lower and upper bounds */
+         if (con->lbnd == NULL && con->ubnd == NULL)
+         {  /* objective has no bounds */
+            double temp;
+            xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
+            /* carry the constant term to the right-hand side */
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = refer->ubnd = - temp;
+         }
+         else if (con->lbnd != NULL && con->ubnd == NULL)
+         {  /* constraint a * x + b >= c * y + d is transformed to the
+               standard form a * x - c * y >= d - b */
+            double temp;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = linear_comb(mpl,
+               +1.0, refer->form,
+               -1.0, eval_formula(mpl, con->lbnd));
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = - temp;
+            refer->ubnd = 0.0;
+         }
+         else if (con->lbnd == NULL && con->ubnd != NULL)
+         {  /* constraint a * x + b <= c * y + d is transformed to the
+               standard form a * x - c * y <= d - b */
+            double temp;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = linear_comb(mpl,
+               +1.0, refer->form,
+               -1.0, eval_formula(mpl, con->ubnd));
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = 0.0;
+            refer->ubnd = - temp;
+         }
+         else if (con->lbnd == con->ubnd)
+         {  /* constraint a * x + b = c * y + d is transformed to the
+               standard form a * x - c * y = d - b */
+            double temp;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = linear_comb(mpl,
+               +1.0, refer->form,
+               -1.0, eval_formula(mpl, con->lbnd));
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = refer->ubnd = - temp;
+         }
+         else
+         {  /* ranged constraint c <= a * x + b <= d is transformed to
+               the standard form c - b <= a * x <= d - b */
+            double temp, temp1, temp2;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
+               &temp1) == NULL);
+            xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
+               &temp2) == NULL);
+            refer->lbnd = fp_sub(mpl, temp1, temp);
+            refer->ubnd = fp_sub(mpl, temp2, temp);
+         }
+#if 1 /* 15/V-2010 */
+         /* solution has not been obtained by the solver yet */
+         refer->stat = 0;
+         refer->prim = refer->dual = 0.0;
+#endif
+      }
+      return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_con - evaluate reference to elemental constraint.
+--
+-- This routine evaluates a reference to elemental constraint assigned
+-- to member of specified model constraint and returns it on exit. */
+
+struct eval_con_info
+{     /* working info used by the routine eval_member_con */
+      CONSTRAINT *con;
+      /* model constraint */
+      TUPLE *tuple;
+      /* n-tuple, which defines constraint member */
+      ELEMCON *refer;
+      /* evaluated reference to elemental constraint */
+};
+
+static void eval_con_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_con_info *info = _info;
+      info->refer = take_member_con(mpl, info->con, info->tuple);
+      return;
+}
+
+ELEMCON *eval_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates constraint member */
+      struct eval_con_info _info, *info = &_info;
+      xassert(con->dim == tuple_dimen(mpl, tuple));
+      info->con = con;
+      info->tuple = tuple;
+      /* evaluate member, which has given n-tuple */
+      if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
+         eval_con_func))
+         out_of_domain(mpl, con->name, info->tuple);
+      /* bring evaluated reference to the calling program */
+      return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_con - evaluate model constraint over entire domain.
+--
+-- This routine evaluates all members of specified model constraint over
+-- entire domain. */
+
+static int whole_con_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      CONSTRAINT *con = (CONSTRAINT *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, con->domain);
+      eval_member_con(mpl, con, tuple);
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_con(MPL *mpl, CONSTRAINT *con)
+{     loop_within_domain(mpl, con->domain, con, whole_con_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_constraint - clean model constraint.
+--
+-- This routine cleans specified model constraint that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_constraint(MPL *mpl, CONSTRAINT *con)
+{     MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, con->domain);
+      /* clean code for computing main linear form */
+      clean_code(mpl, con->code);
+      /* clean code for computing lower bound */
+      clean_code(mpl, con->lbnd);
+      /* clean code for computing upper bound */
+      if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
+      /* delete content array */
+      for (memb = con->array->head; memb != NULL; memb = memb->next)
+      {  delete_formula(mpl, memb->value.con->form);
+         dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
+      }
+      delete_array(mpl, con->array), con->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *                        PSEUDO-CODE                         * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- eval_numeric - evaluate pseudo-code to determine numeric value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- numeric value, which is returned on exit. */
+
+struct iter_num_info
+{     /* working info used by the routine iter_num_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      double value;
+      /* resultant value */
+};
+
+static int iter_num_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on numeric "integrand" within domain scope */
+      struct iter_num_info *info = _info;
+      double temp;
+      temp = eval_numeric(mpl, info->code->arg.loop.x);
+      switch (info->code->op)
+      {  case O_SUM:
+            /* summation over domain */
+            info->value = fp_add(mpl, info->value, temp);
+            break;
+         case O_PROD:
+            /* multiplication over domain */
+            info->value = fp_mul(mpl, info->value, temp);
+            break;
+         case O_MINIMUM:
+            /* minimum over domain */
+            if (info->value > temp) info->value = temp;
+            break;
+         case O_MAXIMUM:
+            /* maximum over domain */
+            if (info->value < temp) info->value = temp;
+            break;
+         default:
+            xassert(info != info);
+      }
+      return 0;
+}
+
+double eval_numeric(MPL *mpl, CODE *code)
+{     double value;
+      xassert(code != NULL);
+      xassert(code->type == A_NUMERIC);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = code->value.num;
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_NUMBER:
+            /* take floating-point number */
+            value = code->arg.num;
+            break;
+         case O_MEMNUM:
+            /* take member of numeric parameter */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.par.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               value = eval_member_num(mpl, code->arg.par.par, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_MEMVAR:
+            /* take computed value of elemental variable */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+#if 1 /* 15/V-2010 */
+               ELEMVAR *var;
+#endif
+               tuple = create_tuple(mpl);
+               for (e = code->arg.var.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+#if 0 /* 15/V-2010 */
+               value = eval_member_var(mpl, code->arg.var.var, tuple)
+                  ->value;
+#else
+               var = eval_member_var(mpl, code->arg.var.var, tuple);
+               switch (code->arg.var.suff)
+               {  case DOT_LB:
+                     if (var->var->lbnd == NULL)
+                        value = -DBL_MAX;
+                     else
+                        value = var->lbnd;
+                     break;
+                  case DOT_UB:
+                     if (var->var->ubnd == NULL)
+                        value = +DBL_MAX;
+                     else
+                        value = var->ubnd;
+                     break;
+                  case DOT_STATUS:
+                     value = var->stat;
+                     break;
+                  case DOT_VAL:
+                     value = var->prim;
+                     break;
+                  case DOT_DUAL:
+                     value = var->dual;
+                     break;
+                  default:
+                     xassert(code != code);
+               }
+#endif
+               delete_tuple(mpl, tuple);
+            }
+            break;
+#if 1 /* 15/V-2010 */
+         case O_MEMCON:
+            /* take computed value of elemental constraint */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               ELEMCON *con;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.con.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               con = eval_member_con(mpl, code->arg.con.con, tuple);
+               switch (code->arg.con.suff)
+               {  case DOT_LB:
+                     if (con->con->lbnd == NULL)
+                        value = -DBL_MAX;
+                     else
+                        value = con->lbnd;
+                     break;
+                  case DOT_UB:
+                     if (con->con->ubnd == NULL)
+                        value = +DBL_MAX;
+                     else
+                        value = con->ubnd;
+                     break;
+                  case DOT_STATUS:
+                     value = con->stat;
+                     break;
+                  case DOT_VAL:
+                     value = con->prim;
+                     break;
+                  case DOT_DUAL:
+                     value = con->dual;
+                     break;
+                  default:
+                     xassert(code != code);
+               }
+               delete_tuple(mpl, tuple);
+            }
+            break;
+#endif
+         case O_IRAND224:
+            /* pseudo-random in [0, 2^24-1] */
+            value = fp_irand224(mpl);
+            break;
+         case O_UNIFORM01:
+            /* pseudo-random in [0, 1) */
+            value = fp_uniform01(mpl);
+            break;
+         case O_NORMAL01:
+            /* gaussian random, mu = 0, sigma = 1 */
+            value = fp_normal01(mpl);
+            break;
+         case O_GMTIME:
+            /* current calendar time */
+            value = fn_gmtime(mpl);
+            break;
+         case O_CVTNUM:
+            /* conversion to numeric */
+            {  SYMBOL *sym;
+               sym = eval_symbolic(mpl, code->arg.arg.x);
+#if 0 /* 23/XI-2008 */
+               if (sym->str != NULL)
+                  error(mpl, "cannot convert %s to floating-point numbe"
+                     "r", format_symbol(mpl, sym));
+               value = sym->num;
+#else
+               if (sym->str == NULL)
+                  value = sym->num;
+               else
+               {  if (str2num(sym->str, &value))
+                     error(mpl, "cannot convert %s to floating-point nu"
+                        "mber", format_symbol(mpl, sym));
+               }
+#endif
+               delete_symbol(mpl, sym);
+            }
+            break;
+         case O_PLUS:
+            /* unary plus */
+            value = + eval_numeric(mpl, code->arg.arg.x);
+            break;
+         case O_MINUS:
+            /* unary minus */
+            value = - eval_numeric(mpl, code->arg.arg.x);
+            break;
+         case O_ABS:
+            /* absolute value */
+            value = fabs(eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_CEIL:
+            /* round upward ("ceiling of x") */
+            value = ceil(eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_FLOOR:
+            /* round downward ("floor of x") */
+            value = floor(eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_EXP:
+            /* base-e exponential */
+            value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_LOG:
+            /* natural logarithm */
+            value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_LOG10:
+            /* common (decimal) logarithm */
+            value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_SQRT:
+            /* square root */
+            value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_SIN:
+            /* trigonometric sine */
+            value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_COS:
+            /* trigonometric cosine */
+            value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_ATAN:
+            /* trigonometric arctangent (one argument) */
+            value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_ATAN2:
+            /* trigonometric arctangent (two arguments) */
+            value = fp_atan2(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_ROUND:
+            /* round to nearest integer */
+            value = fp_round(mpl,
+               eval_numeric(mpl, code->arg.arg.x), 0.0);
+            break;
+         case O_ROUND2:
+            /* round to n fractional digits */
+            value = fp_round(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_TRUNC:
+            /* truncate to nearest integer */
+            value = fp_trunc(mpl,
+               eval_numeric(mpl, code->arg.arg.x), 0.0);
+            break;
+         case O_TRUNC2:
+            /* truncate to n fractional digits */
+            value = fp_trunc(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_ADD:
+            /* addition */
+            value = fp_add(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_SUB:
+            /* subtraction */
+            value = fp_sub(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_LESS:
+            /* non-negative subtraction */
+            value = fp_less(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_MUL:
+            /* multiplication */
+            value = fp_mul(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_DIV:
+            /* division */
+            value = fp_div(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_IDIV:
+            /* quotient of exact division */
+            value = fp_idiv(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_MOD:
+            /* remainder of exact division */
+            value = fp_mod(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_POWER:
+            /* exponentiation (raise to power) */
+            value = fp_power(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_UNIFORM:
+            /* pseudo-random in [a, b) */
+            value = fp_uniform(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_NORMAL:
+            /* gaussian random, given mu and sigma */
+            value = fp_normal(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_CARD:
+            {  ELEMSET *set;
+               set = eval_elemset(mpl, code->arg.arg.x);
+               value = set->size;
+               delete_array(mpl, set);
+            }
+            break;
+         case O_LENGTH:
+            {  SYMBOL *sym;
+               char str[MAX_LENGTH+1];
+               sym = eval_symbolic(mpl, code->arg.arg.x);
+               if (sym->str == NULL)
+                  sprintf(str, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, str);
+               delete_symbol(mpl, sym);
+               value = strlen(str);
+            }
+            break;
+         case O_STR2TIME:
+            {  SYMBOL *sym;
+               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
+               sym = eval_symbolic(mpl, code->arg.arg.x);
+               if (sym->str == NULL)
+                  sprintf(str, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, str);
+               delete_symbol(mpl, sym);
+               sym = eval_symbolic(mpl, code->arg.arg.y);
+               if (sym->str == NULL)
+                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, fmt);
+               delete_symbol(mpl, sym);
+               value = fn_str2time(mpl, str, fmt);
+            }
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_numeric(mpl, code->arg.arg.y);
+            else if (code->arg.arg.z == NULL)
+               value = 0.0;
+            else
+               value = eval_numeric(mpl, code->arg.arg.z);
+            break;
+         case O_MIN:
+            /* minimal value (n-ary) */
+            {  ARG_LIST *e;
+               double temp;
+               value = +DBL_MAX;
+               for (e = code->arg.list; e != NULL; e = e->next)
+               {  temp = eval_numeric(mpl, e->x);
+                  if (value > temp) value = temp;
+               }
+            }
+            break;
+         case O_MAX:
+            /* maximal value (n-ary) */
+            {  ARG_LIST *e;
+               double temp;
+               value = -DBL_MAX;
+               for (e = code->arg.list; e != NULL; e = e->next)
+               {  temp = eval_numeric(mpl, e->x);
+                  if (value < temp) value = temp;
+               }
+            }
+            break;
+         case O_SUM:
+            /* summation over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = 0.0;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               value = info->value;
+            }
+            break;
+         case O_PROD:
+            /* multiplication over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = 1.0;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               value = info->value;
+            }
+            break;
+         case O_MINIMUM:
+            /* minimum over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = +DBL_MAX;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               if (info->value == +DBL_MAX)
+                  error(mpl, "min{} over empty set; result undefined");
+               value = info->value;
+            }
+            break;
+         case O_MAXIMUM:
+            /* maximum over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = -DBL_MAX;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               if (info->value == -DBL_MAX)
+                  error(mpl, "max{} over empty set; result undefined");
+               value = info->value;
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.num = value;
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_symbolic - evaluate pseudo-code to determine symbolic value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- symbolic value, which is returned on exit. */
+
+SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
+{     SYMBOL *value;
+      xassert(code != NULL);
+      xassert(code->type == A_SYMBOLIC);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_symbol(mpl, code->value.sym);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_STRING:
+            /* take character string */
+            value = create_symbol_str(mpl, create_string(mpl,
+               code->arg.str));
+            break;
+         case O_INDEX:
+            /* take dummy index */
+            xassert(code->arg.index.slot->value != NULL);
+            value = copy_symbol(mpl, code->arg.index.slot->value);
+            break;
+         case O_MEMSYM:
+            /* take member of symbolic parameter */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.par.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               value = eval_member_sym(mpl, code->arg.par.par, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_CVTSYM:
+            /* conversion to symbolic */
+            value = create_symbol_num(mpl, eval_numeric(mpl,
+               code->arg.arg.x));
+            break;
+         case O_CONCAT:
+            /* concatenation */
+            value = concat_symbols(mpl,
+               eval_symbolic(mpl, code->arg.arg.x),
+               eval_symbolic(mpl, code->arg.arg.y));
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_symbolic(mpl, code->arg.arg.y);
+            else if (code->arg.arg.z == NULL)
+               value = create_symbol_num(mpl, 0.0);
+            else
+               value = eval_symbolic(mpl, code->arg.arg.z);
+            break;
+         case O_SUBSTR:
+         case O_SUBSTR3:
+            {  double pos, len;
+               char str[MAX_LENGTH+1];
+               value = eval_symbolic(mpl, code->arg.arg.x);
+               if (value->str == NULL)
+                  sprintf(str, "%.*g", DBL_DIG, value->num);
+               else
+                  fetch_string(mpl, value->str, str);
+               delete_symbol(mpl, value);
+               if (code->op == O_SUBSTR)
+               {  pos = eval_numeric(mpl, code->arg.arg.y);
+                  if (pos != floor(pos))
+                     error(mpl, "substr('...', %.*g); non-integer secon"
+                        "d argument", DBL_DIG, pos);
+                  if (pos < 1 || pos > strlen(str) + 1)
+                     error(mpl, "substr('...', %.*g); substring out of "
+                        "range", DBL_DIG, pos);
+               }
+               else
+               {  pos = eval_numeric(mpl, code->arg.arg.y);
+                  len = eval_numeric(mpl, code->arg.arg.z);
+                  if (pos != floor(pos) || len != floor(len))
+                     error(mpl, "substr('...', %.*g, %.*g); non-integer"
+                        " second and/or third argument", DBL_DIG, pos,
+                        DBL_DIG, len);
+                  if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
+                     error(mpl, "substr('...', %.*g, %.*g); substring o"
+                        "ut of range", DBL_DIG, pos, DBL_DIG, len);
+                  str[(int)pos + (int)len - 1] = '\0';
+               }
+               value = create_symbol_str(mpl, create_string(mpl, str +
+                  (int)pos - 1));
+            }
+            break;
+         case O_TIME2STR:
+            {  double num;
+               SYMBOL *sym;
+               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
+               num = eval_numeric(mpl, code->arg.arg.x);
+               sym = eval_symbolic(mpl, code->arg.arg.y);
+               if (sym->str == NULL)
+                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, fmt);
+               delete_symbol(mpl, sym);
+               fn_time2str(mpl, str, num, fmt);
+               value = create_symbol_str(mpl, create_string(mpl, str));
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.sym = copy_symbol(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_logical - evaluate pseudo-code to determine logical value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- logical value, which is returned on exit. */
+
+struct iter_log_info
+{     /* working info used by the routine iter_log_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      int value;
+      /* resultant value */
+};
+
+static int iter_log_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on logical "integrand" within domain scope */
+      struct iter_log_info *info = _info;
+      int ret = 0;
+      switch (info->code->op)
+      {  case O_FORALL:
+            /* conjunction over domain */
+            info->value &= eval_logical(mpl, info->code->arg.loop.x);
+            if (!info->value) ret = 1;
+            break;
+         case O_EXISTS:
+            /* disjunction over domain */
+            info->value |= eval_logical(mpl, info->code->arg.loop.x);
+            if (info->value) ret = 1;
+            break;
+         default:
+            xassert(info != info);
+      }
+      return ret;
+}
+
+int eval_logical(MPL *mpl, CODE *code)
+{     int value;
+      xassert(code->type == A_LOGICAL);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = code->value.bit;
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_CVTLOG:
+            /* conversion to logical */
+            value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
+            break;
+         case O_NOT:
+            /* negation (logical "not") */
+            value = !eval_logical(mpl, code->arg.arg.x);
+            break;
+         case O_LT:
+            /* comparison on 'less than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) <
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) <
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) < 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_LE:
+            /* comparison on 'not greater than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) <=
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) <=
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) <= 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_EQ:
+            /* comparison on 'equal to' */
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) ==
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) == 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+            break;
+         case O_GE:
+            /* comparison on 'not less than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) >=
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) >=
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) >= 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_GT:
+            /* comparison on 'greater than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) >
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) >
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) > 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_NE:
+            /* comparison on 'not equal to' */
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) !=
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) != 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+            break;
+         case O_AND:
+            /* conjunction (logical "and") */
+            value = eval_logical(mpl, code->arg.arg.x) &&
+                    eval_logical(mpl, code->arg.arg.y);
+            break;
+         case O_OR:
+            /* disjunction (logical "or") */
+            value = eval_logical(mpl, code->arg.arg.x) ||
+                    eval_logical(mpl, code->arg.arg.y);
+            break;
+         case O_IN:
+            /* test on 'x in Y' */
+            {  TUPLE *tuple;
+               tuple = eval_tuple(mpl, code->arg.arg.x);
+               value = is_member(mpl, code->arg.arg.y, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_NOTIN:
+            /* test on 'x not in Y' */
+            {  TUPLE *tuple;
+               tuple = eval_tuple(mpl, code->arg.arg.x);
+               value = !is_member(mpl, code->arg.arg.y, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_WITHIN:
+            /* test on 'X within Y' */
+            {  ELEMSET *set;
+               MEMBER *memb;
+               set = eval_elemset(mpl, code->arg.arg.x);
+               value = 1;
+               for (memb = set->head; memb != NULL; memb = memb->next)
+               {  if (!is_member(mpl, code->arg.arg.y, memb->tuple))
+                  {  value = 0;
+                     break;
+                  }
+               }
+               delete_elemset(mpl, set);
+            }
+            break;
+         case O_NOTWITHIN:
+            /* test on 'X not within Y' */
+            {  ELEMSET *set;
+               MEMBER *memb;
+               set = eval_elemset(mpl, code->arg.arg.x);
+               value = 1;
+               for (memb = set->head; memb != NULL; memb = memb->next)
+               {  if (is_member(mpl, code->arg.arg.y, memb->tuple))
+                  {  value = 0;
+                     break;
+                  }
+               }
+               delete_elemset(mpl, set);
+            }
+            break;
+         case O_FORALL:
+            /* conjunction (A-quantification) */
+            {  struct iter_log_info _info, *info = &_info;
+               info->code = code;
+               info->value = 1;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_log_func);
+               value = info->value;
+            }
+            break;
+         case O_EXISTS:
+            /* disjunction (E-quantification) */
+            {  struct iter_log_info _info, *info = &_info;
+               info->code = code;
+               info->value = 0;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_log_func);
+               value = info->value;
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.bit = value;
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_tuple - evaluate pseudo-code to construct n-tuple.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- n-tuple, which is returned on exit. */
+
+TUPLE *eval_tuple(MPL *mpl, CODE *code)
+{     TUPLE *value;
+      xassert(code != NULL);
+      xassert(code->type == A_TUPLE);
+      xassert(code->dim > 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_tuple(mpl, code->value.tuple);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_TUPLE:
+            /* make n-tuple */
+            {  ARG_LIST *e;
+               value = create_tuple(mpl);
+               for (e = code->arg.list; e != NULL; e = e->next)
+                  value = expand_tuple(mpl, value, eval_symbolic(mpl,
+                     e->x));
+            }
+            break;
+         case O_CVTTUP:
+            /* convert to 1-tuple */
+            value = expand_tuple(mpl, create_tuple(mpl),
+               eval_symbolic(mpl, code->arg.arg.x));
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.tuple = copy_tuple(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_elemset - evaluate pseudo-code to construct elemental set.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- elemental set, which is returned on exit. */
+
+struct iter_set_info
+{     /* working info used by the routine iter_set_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      ELEMSET *value;
+      /* resultant value */
+};
+
+static int iter_set_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on n-tuple "integrand" within domain scope */
+      struct iter_set_info *info = _info;
+      TUPLE *tuple;
+      switch (info->code->op)
+      {  case O_SETOF:
+            /* compute next n-tuple and add it to the set; in this case
+               duplicate n-tuples are silently ignored */
+            tuple = eval_tuple(mpl, info->code->arg.loop.x);
+            if (find_tuple(mpl, info->value, tuple) == NULL)
+               add_tuple(mpl, info->value, tuple);
+            else
+               delete_tuple(mpl, tuple);
+            break;
+         case O_BUILD:
+            /* construct next n-tuple using current values assigned to
+               *free* dummy indices as its components and add it to the
+               set; in this case duplicate n-tuples cannot appear */
+            add_tuple(mpl, info->value, get_domain_tuple(mpl,
+               info->code->arg.loop.domain));
+            break;
+         default:
+            xassert(info != info);
+      }
+      return 0;
+}
+
+ELEMSET *eval_elemset(MPL *mpl, CODE *code)
+{     ELEMSET *value;
+      xassert(code != NULL);
+      xassert(code->type == A_ELEMSET);
+      xassert(code->dim > 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_elemset(mpl, code->value.set);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_MEMSET:
+            /* take member of set */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.set.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               value = copy_elemset(mpl,
+                  eval_member_set(mpl, code->arg.set.set, tuple));
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_MAKE:
+            /* make elemental set of n-tuples */
+            {  ARG_LIST *e;
+               value = create_elemset(mpl, code->dim);
+               for (e = code->arg.list; e != NULL; e = e->next)
+                  check_then_add(mpl, value, eval_tuple(mpl, e->x));
+            }
+            break;
+         case O_UNION:
+            /* union of two elemental sets */
+            value = set_union(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_DIFF:
+            /* difference between two elemental sets */
+            value = set_diff(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_SYMDIFF:
+            /* symmetric difference between two elemental sets */
+            value = set_symdiff(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_INTER:
+            /* intersection of two elemental sets */
+            value = set_inter(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_CROSS:
+            /* cross (Cartesian) product of two elemental sets */
+            value = set_cross(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_DOTS:
+            /* build "arithmetic" elemental set */
+            value = create_arelset(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y),
+               code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
+                  code->arg.arg.z));
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_elemset(mpl, code->arg.arg.y);
+            else
+               value = eval_elemset(mpl, code->arg.arg.z);
+            break;
+         case O_SETOF:
+            /* compute elemental set */
+            {  struct iter_set_info _info, *info = &_info;
+               info->code = code;
+               info->value = create_elemset(mpl, code->dim);
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_set_func);
+               value = info->value;
+            }
+            break;
+         case O_BUILD:
+            /* build elemental set identical to domain set */
+            {  struct iter_set_info _info, *info = &_info;
+               info->code = code;
+               info->value = create_elemset(mpl, code->dim);
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_set_func);
+               value = info->value;
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.set = copy_elemset(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- is_member - check if n-tuple is in set specified by pseudo-code.
+--
+-- This routine checks if given n-tuple is a member of elemental set
+-- specified in the form of pseudo-code (i.e. by expression).
+--
+-- The n-tuple may have more components that dimension of the elemental
+-- set, in which case the extra components are ignored. */
+
+static void null_func(MPL *mpl, void *info)
+{     /* this is dummy routine used to enter the domain scope */
+      xassert(mpl == mpl);
+      xassert(info == NULL);
+      return;
+}
+
+int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
+{     int value;
+      xassert(code != NULL);
+      xassert(code->type == A_ELEMSET);
+      xassert(code->dim > 0);
+      xassert(tuple != NULL);
+      switch (code->op)
+      {  case O_MEMSET:
+            /* check if given n-tuple is member of elemental set, which
+               is assigned to member of model set */
+            {  ARG_LIST *e;
+               TUPLE *temp;
+               ELEMSET *set;
+               /* evaluate reference to elemental set */
+               temp = create_tuple(mpl);
+               for (e = code->arg.set.list; e != NULL; e = e->next)
+                  temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
+                     e->x));
+               set = eval_member_set(mpl, code->arg.set.set, temp);
+               delete_tuple(mpl, temp);
+               /* check if the n-tuple is contained in the set array */
+               temp = build_subtuple(mpl, tuple, set->dim);
+               value = (find_tuple(mpl, set, temp) != NULL);
+               delete_tuple(mpl, temp);
+            }
+            break;
+         case O_MAKE:
+            /* check if given n-tuple is member of literal set */
+            {  ARG_LIST *e;
+               TUPLE *temp, *that;
+               value = 0;
+               temp = build_subtuple(mpl, tuple, code->dim);
+               for (e = code->arg.list; e != NULL; e = e->next)
+               {  that = eval_tuple(mpl, e->x);
+                  value = (compare_tuples(mpl, temp, that) == 0);
+                  delete_tuple(mpl, that);
+                  if (value) break;
+               }
+               delete_tuple(mpl, temp);
+            }
+            break;
+         case O_UNION:
+            value = is_member(mpl, code->arg.arg.x, tuple) ||
+                    is_member(mpl, code->arg.arg.y, tuple);
+            break;
+         case O_DIFF:
+            value = is_member(mpl, code->arg.arg.x, tuple) &&
+                   !is_member(mpl, code->arg.arg.y, tuple);
+            break;
+         case O_SYMDIFF:
+            {  int in1 = is_member(mpl, code->arg.arg.x, tuple);
+               int in2 = is_member(mpl, code->arg.arg.y, tuple);
+               value = (in1 && !in2) || (!in1 && in2);
+            }
+            break;
+         case O_INTER:
+            value = is_member(mpl, code->arg.arg.x, tuple) &&
+                    is_member(mpl, code->arg.arg.y, tuple);
+            break;
+         case O_CROSS:
+            {  int j;
+               value = is_member(mpl, code->arg.arg.x, tuple);
+               if (value)
+               {  for (j = 1; j <= code->arg.arg.x->dim; j++)
+                  {  xassert(tuple != NULL);
+                     tuple = tuple->next;
+                  }
+                  value = is_member(mpl, code->arg.arg.y, tuple);
+               }
+            }
+            break;
+         case O_DOTS:
+            /* check if given 1-tuple is member of "arithmetic" set */
+            {  int j;
+               double x, t0, tf, dt;
+               xassert(code->dim == 1);
+               /* compute "parameters" of the "arithmetic" set */
+               t0 = eval_numeric(mpl, code->arg.arg.x);
+               tf = eval_numeric(mpl, code->arg.arg.y);
+               if (code->arg.arg.z == NULL)
+                  dt = 1.0;
+               else
+                  dt = eval_numeric(mpl, code->arg.arg.z);
+               /* make sure the parameters are correct */
+               arelset_size(mpl, t0, tf, dt);
+               /* if component of 1-tuple is symbolic, not numeric, the
+                  1-tuple cannot be member of "arithmetic" set */
+               xassert(tuple->sym != NULL);
+               if (tuple->sym->str != NULL)
+               {  value = 0;
+                  break;
+               }
+               /* determine numeric value of the component */
+               x = tuple->sym->num;
+               /* if the component value is out of the set range, the
+                  1-tuple is not in the set */
+               if (dt > 0.0 && !(t0 <= x && x <= tf) ||
+                   dt < 0.0 && !(tf <= x && x <= t0))
+               {  value = 0;
+                  break;
+               }
+               /* estimate ordinal number of the 1-tuple in the set */
+               j = (int)(((x - t0) / dt) + 0.5) + 1;
+               /* perform the main check */
+               value = (arelset_member(mpl, t0, tf, dt, j) == x);
+            }
+            break;
+         case O_FORK:
+            /* check if given n-tuple is member of conditional set */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = is_member(mpl, code->arg.arg.y, tuple);
+            else
+               value = is_member(mpl, code->arg.arg.z, tuple);
+            break;
+         case O_SETOF:
+            /* check if given n-tuple is member of computed set */
+            /* it is not clear how to efficiently perform the check not
+               computing the entire elemental set :+( */
+            error(mpl, "implementation restriction; in/within setof{} n"
+               "ot allowed");
+            break;
+         case O_BUILD:
+            /* check if given n-tuple is member of domain set */
+            {  TUPLE *temp;
+               temp = build_subtuple(mpl, tuple, code->dim);
+               /* try to enter the domain scope; if it is successful,
+                  the n-tuple is in the domain set */
+               value = (eval_within_domain(mpl, code->arg.loop.domain,
+                  temp, NULL, null_func) == 0);
+               delete_tuple(mpl, temp);
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_formula - evaluate pseudo-code to construct linear form.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- linear form, which is returned on exit. */
+
+struct iter_form_info
+{     /* working info used by the routine iter_form_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      FORMULA *value;
+      /* resultant value */
+      FORMULA *tail;
+      /* pointer to the last term */
+};
+
+static int iter_form_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on linear form "integrand" within domain scope */
+      struct iter_form_info *info = _info;
+      switch (info->code->op)
+      {  case O_SUM:
+            /* summation over domain */
+#if 0
+            info->value =
+               linear_comb(mpl,
+                  +1.0, info->value,
+                  +1.0, eval_formula(mpl, info->code->arg.loop.x));
+#else
+            /* the routine linear_comb needs to look through all terms
+               of both linear forms to reduce identical terms, so using
+               it here is not a good idea (for example, evaluation of
+               sum{i in 1..n} x[i] required quadratic time); the better
+               idea is to gather all terms of the integrand in one list
+               and reduce identical terms only once after all terms of
+               the resultant linear form have been evaluated */
+            {  FORMULA *form, *term;
+               form = eval_formula(mpl, info->code->arg.loop.x);
+               if (info->value == NULL)
+               {  xassert(info->tail == NULL);
+                  info->value = form;
+               }
+               else
+               {  xassert(info->tail != NULL);
+                  info->tail->next = form;
+               }
+               for (term = form; term != NULL; term = term->next)
+                  info->tail = term;
+            }
+#endif
+            break;
+         default:
+            xassert(info != info);
+      }
+      return 0;
+}
+
+FORMULA *eval_formula(MPL *mpl, CODE *code)
+{     FORMULA *value;
+      xassert(code != NULL);
+      xassert(code->type == A_FORMULA);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_formula(mpl, code->value.form);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_MEMVAR:
+            /* take member of variable */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.var.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+#if 1 /* 15/V-2010 */
+               xassert(code->arg.var.suff == DOT_NONE);
+#endif
+               value = single_variable(mpl,
+                  eval_member_var(mpl, code->arg.var.var, tuple));
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_CVTLFM:
+            /* convert to linear form */
+            value = constant_term(mpl, eval_numeric(mpl,
+               code->arg.arg.x));
+            break;
+         case O_PLUS:
+            /* unary plus */
+            value = linear_comb(mpl,
+                0.0, constant_term(mpl, 0.0),
+               +1.0, eval_formula(mpl, code->arg.arg.x));
+            break;
+         case O_MINUS:
+            /* unary minus */
+            value = linear_comb(mpl,
+                0.0, constant_term(mpl, 0.0),
+               -1.0, eval_formula(mpl, code->arg.arg.x));
+            break;
+         case O_ADD:
+            /* addition */
+            value = linear_comb(mpl,
+               +1.0, eval_formula(mpl, code->arg.arg.x),
+               +1.0, eval_formula(mpl, code->arg.arg.y));
+            break;
+         case O_SUB:
+            /* subtraction */
+            value = linear_comb(mpl,
+               +1.0, eval_formula(mpl, code->arg.arg.x),
+               -1.0, eval_formula(mpl, code->arg.arg.y));
+            break;
+         case O_MUL:
+            /* multiplication */
+            xassert(code->arg.arg.x != NULL);
+            xassert(code->arg.arg.y != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+            {  xassert(code->arg.arg.y->type == A_FORMULA);
+               value = linear_comb(mpl,
+                  eval_numeric(mpl, code->arg.arg.x),
+                  eval_formula(mpl, code->arg.arg.y),
+                  0.0, constant_term(mpl, 0.0));
+            }
+            else
+            {  xassert(code->arg.arg.x->type == A_FORMULA);
+               xassert(code->arg.arg.y->type == A_NUMERIC);
+               value = linear_comb(mpl,
+                  eval_numeric(mpl, code->arg.arg.y),
+                  eval_formula(mpl, code->arg.arg.x),
+                  0.0, constant_term(mpl, 0.0));
+            }
+            break;
+         case O_DIV:
+            /* division */
+            value = linear_comb(mpl,
+               fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
+               eval_formula(mpl, code->arg.arg.x),
+               0.0, constant_term(mpl, 0.0));
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_formula(mpl, code->arg.arg.y);
+            else if (code->arg.arg.z == NULL)
+               value = constant_term(mpl, 0.0);
+            else
+               value = eval_formula(mpl, code->arg.arg.z);
+            break;
+         case O_SUM:
+            /* summation over domain */
+            {  struct iter_form_info _info, *info = &_info;
+               info->code = code;
+               info->value = constant_term(mpl, 0.0);
+               info->tail = NULL;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_form_func);
+               value = reduce_terms(mpl, info->value);
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.form = copy_formula(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- clean_code - clean pseudo-code.
+--
+-- This routine recursively cleans specified pseudo-code that assumes
+-- deleting all temporary resultant values. */
+
+void clean_code(MPL *mpl, CODE *code)
+{     ARG_LIST *e;
+      /* if no pseudo-code is specified, do nothing */
+      if (code == NULL) goto done;
+      /* if resultant value is valid (exists), delete it */
+      if (code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* recursively clean pseudo-code for operands */
+      switch (code->op)
+      {  case O_NUMBER:
+         case O_STRING:
+         case O_INDEX:
+            break;
+         case O_MEMNUM:
+         case O_MEMSYM:
+            for (e = code->arg.par.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_MEMSET:
+            for (e = code->arg.set.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_MEMVAR:
+            for (e = code->arg.var.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+#if 1 /* 15/V-2010 */
+         case O_MEMCON:
+            for (e = code->arg.con.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+#endif
+         case O_TUPLE:
+         case O_MAKE:
+            for (e = code->arg.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_SLICE:
+            xassert(code != code);
+         case O_IRAND224:
+         case O_UNIFORM01:
+         case O_NORMAL01:
+         case O_GMTIME:
+            break;
+         case O_CVTNUM:
+         case O_CVTSYM:
+         case O_CVTLOG:
+         case O_CVTTUP:
+         case O_CVTLFM:
+         case O_PLUS:
+         case O_MINUS:
+         case O_NOT:
+         case O_ABS:
+         case O_CEIL:
+         case O_FLOOR:
+         case O_EXP:
+         case O_LOG:
+         case O_LOG10:
+         case O_SQRT:
+         case O_SIN:
+         case O_COS:
+         case O_ATAN:
+         case O_ROUND:
+         case O_TRUNC:
+         case O_CARD:
+         case O_LENGTH:
+            /* unary operation */
+            clean_code(mpl, code->arg.arg.x);
+            break;
+         case O_ADD:
+         case O_SUB:
+         case O_LESS:
+         case O_MUL:
+         case O_DIV:
+         case O_IDIV:
+         case O_MOD:
+         case O_POWER:
+         case O_ATAN2:
+         case O_ROUND2:
+         case O_TRUNC2:
+         case O_UNIFORM:
+         case O_NORMAL:
+         case O_CONCAT:
+         case O_LT:
+         case O_LE:
+         case O_EQ:
+         case O_GE:
+         case O_GT:
+         case O_NE:
+         case O_AND:
+         case O_OR:
+         case O_UNION:
+         case O_DIFF:
+         case O_SYMDIFF:
+         case O_INTER:
+         case O_CROSS:
+         case O_IN:
+         case O_NOTIN:
+         case O_WITHIN:
+         case O_NOTWITHIN:
+         case O_SUBSTR:
+         case O_STR2TIME:
+         case O_TIME2STR:
+            /* binary operation */
+            clean_code(mpl, code->arg.arg.x);
+            clean_code(mpl, code->arg.arg.y);
+            break;
+         case O_DOTS:
+         case O_FORK:
+         case O_SUBSTR3:
+            /* ternary operation */
+            clean_code(mpl, code->arg.arg.x);
+            clean_code(mpl, code->arg.arg.y);
+            clean_code(mpl, code->arg.arg.z);
+            break;
+         case O_MIN:
+         case O_MAX:
+            /* n-ary operation */
+            for (e = code->arg.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_SUM:
+         case O_PROD:
+         case O_MINIMUM:
+         case O_MAXIMUM:
+         case O_FORALL:
+         case O_EXISTS:
+         case O_SETOF:
+         case O_BUILD:
+            /* iterated operation */
+            clean_domain(mpl, code->arg.loop.domain);
+            clean_code(mpl, code->arg.loop.x);
+            break;
+         default:
+            xassert(code->op != code->op);
+      }
+done: return;
+}
+
+#if 1 /* 11/II-2008 */
+/**********************************************************************/
+/* * *                        DATA TABLES                         * * */
+/**********************************************************************/
+
+int mpl_tab_num_args(TABDCA *dca)
+{     /* returns the number of arguments */
+      return dca->na;
+}
+
+const char *mpl_tab_get_arg(TABDCA *dca, int k)
+{     /* returns pointer to k-th argument */
+      xassert(1 <= k && k <= dca->na);
+      return dca->arg[k];
+}
+
+int mpl_tab_num_flds(TABDCA *dca)
+{     /* returns the number of fields */
+      return dca->nf;
+}
+
+const char *mpl_tab_get_name(TABDCA *dca, int k)
+{     /* returns pointer to name of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      return dca->name[k];
+}
+
+int mpl_tab_get_type(TABDCA *dca, int k)
+{     /* returns type of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      return dca->type[k];
+}
+
+double mpl_tab_get_num(TABDCA *dca, int k)
+{     /* returns numeric value of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == 'N');
+      return dca->num[k];
+}
+
+const char *mpl_tab_get_str(TABDCA *dca, int k)
+{     /* returns pointer to string value of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == 'S');
+      xassert(dca->str[k] != NULL);
+      return dca->str[k];
+}
+
+void mpl_tab_set_num(TABDCA *dca, int k, double num)
+{     /* assign numeric value to k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == '?');
+      dca->type[k] = 'N';
+      dca->num[k] = num;
+      return;
+}
+
+void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
+{     /* assign string value to k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == '?');
+      xassert(strlen(str) <= MAX_LENGTH);
+      xassert(dca->str[k] != NULL);
+      dca->type[k] = 'S';
+      strcpy(dca->str[k], str);
+      return;
+}
+
+static int write_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      TABLE *tab = info;
+      TABDCA *dca = mpl->dca;
+      TABOUT *out;
+      SYMBOL *sym;
+      int k;
+      char buf[MAX_LENGTH+1];
+      /* evaluate field values */
+      k = 0;
+      for (out = tab->u.out.list; out != NULL; out = out->next)
+      {  k++;
+         switch (out->code->type)
+         {  case A_NUMERIC:
+               dca->type[k] = 'N';
+               dca->num[k] = eval_numeric(mpl, out->code);
+               dca->str[k][0] = '\0';
+               break;
+            case A_SYMBOLIC:
+               sym = eval_symbolic(mpl, out->code);
+               if (sym->str == NULL)
+               {  dca->type[k] = 'N';
+                  dca->num[k] = sym->num;
+                  dca->str[k][0] = '\0';
+               }
+               else
+               {  dca->type[k] = 'S';
+                  dca->num[k] = 0.0;
+                  fetch_string(mpl, sym->str, buf);
+                  strcpy(dca->str[k], buf);
+               }
+               delete_symbol(mpl, sym);
+               break;
+            default:
+               xassert(out != out);
+         }
+      }
+      /* write record to output table */
+      mpl_tab_drv_write(mpl);
+      return 0;
+}
+
+void execute_table(MPL *mpl, TABLE *tab)
+{     /* execute table statement */
+      TABARG *arg;
+      TABFLD *fld;
+      TABIN *in;
+      TABOUT *out;
+      TABDCA *dca;
+      SET *set;
+      int k;
+      char buf[MAX_LENGTH+1];
+      /* allocate table driver communication area */
+      xassert(mpl->dca == NULL);
+      mpl->dca = dca = xmalloc(sizeof(TABDCA));
+      dca->id = 0;
+      dca->link = NULL;
+      dca->na = 0;
+      dca->arg = NULL;
+      dca->nf = 0;
+      dca->name = NULL;
+      dca->type = NULL;
+      dca->num = NULL;
+      dca->str = NULL;
+      /* allocate arguments */
+      xassert(dca->na == 0);
+      for (arg = tab->arg; arg != NULL; arg = arg->next)
+         dca->na++;
+      dca->arg = xcalloc(1+dca->na, sizeof(char *));
+#if 1 /* 28/IX-2008 */
+      for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
+#endif
+      /* evaluate argument values */
+      k = 0;
+      for (arg = tab->arg; arg != NULL; arg = arg->next)
+      {  SYMBOL *sym;
+         k++;
+         xassert(arg->code->type == A_SYMBOLIC);
+         sym = eval_symbolic(mpl, arg->code);
+         if (sym->str == NULL)
+            sprintf(buf, "%.*g", DBL_DIG, sym->num);
+         else
+            fetch_string(mpl, sym->str, buf);
+         delete_symbol(mpl, sym);
+         dca->arg[k] = xmalloc(strlen(buf)+1);
+         strcpy(dca->arg[k], buf);
+      }
+      /* perform table input/output */
+      switch (tab->type)
+      {  case A_INPUT:  goto read_table;
+         case A_OUTPUT: goto write_table;
+         default:       xassert(tab != tab);
+      }
+read_table:
+      /* read data from input table */
+      /* add the only member to the control set and assign it empty
+         elemental set */
+      set = tab->u.in.set;
+      if (set != NULL)
+      {  if (set->data)
+            error(mpl, "%s already provided with data", set->name);
+         xassert(set->array->head == NULL);
+         add_member(mpl, set->array, NULL)->value.set =
+            create_elemset(mpl, set->dimen);
+         set->data = 1;
+      }
+      /* check parameters specified in the input list */
+      for (in = tab->u.in.list; in != NULL; in = in->next)
+      {  if (in->par->data)
+            error(mpl, "%s already provided with data", in->par->name);
+         in->par->data = 1;
+      }
+      /* allocate and initialize fields */
+      xassert(dca->nf == 0);
+      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+         dca->nf++;
+      for (in = tab->u.in.list; in != NULL; in = in->next)
+         dca->nf++;
+      dca->name = xcalloc(1+dca->nf, sizeof(char *));
+      dca->type = xcalloc(1+dca->nf, sizeof(int));
+      dca->num = xcalloc(1+dca->nf, sizeof(double));
+      dca->str = xcalloc(1+dca->nf, sizeof(char *));
+      k = 0;
+      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+      {  k++;
+         dca->name[k] = fld->name;
+         dca->type[k] = '?';
+         dca->num[k] = 0.0;
+         dca->str[k] = xmalloc(MAX_LENGTH+1);
+         dca->str[k][0] = '\0';
+      }
+      for (in = tab->u.in.list; in != NULL; in = in->next)
+      {  k++;
+         dca->name[k] = in->name;
+         dca->type[k] = '?';
+         dca->num[k] = 0.0;
+         dca->str[k] = xmalloc(MAX_LENGTH+1);
+         dca->str[k][0] = '\0';
+      }
+      /* open input table */
+      mpl_tab_drv_open(mpl, 'R');
+      /* read and process records */
+      for (;;)
+      {  TUPLE *tup;
+         /* reset field types */
+         for (k = 1; k <= dca->nf; k++)
+            dca->type[k] = '?';
+         /* read next record */
+         if (mpl_tab_drv_read(mpl)) break;
+         /* all fields must be set by the driver */
+         for (k = 1; k <= dca->nf; k++)
+         {  if (dca->type[k] == '?')
+               error(mpl, "field %s missing in input table",
+                  dca->name[k]);
+         }
+         /* construct n-tuple */
+         tup = create_tuple(mpl);
+         k = 0;
+         for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+         {  k++;
+            xassert(k <= dca->nf);
+            switch (dca->type[k])
+            {  case 'N':
+                  tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
+                     dca->num[k]));
+                  break;
+               case 'S':
+                  xassert(strlen(dca->str[k]) <= MAX_LENGTH);
+                  tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
+                     create_string(mpl, dca->str[k])));
+                  break;
+               default:
+                  xassert(dca != dca);
+            }
+         }
+         /* add n-tuple just read to the control set */
+         if (tab->u.in.set != NULL)
+            check_then_add(mpl, tab->u.in.set->array->head->value.set,
+               copy_tuple(mpl, tup));
+         /* assign values to the parameters in the input list */
+         for (in = tab->u.in.list; in != NULL; in = in->next)
+         {  MEMBER *memb;
+            k++;
+            xassert(k <= dca->nf);
+            /* there must be no member with the same n-tuple */
+            if (find_member(mpl, in->par->array, tup) != NULL)
+               error(mpl, "%s%s already defined", in->par->name,
+               format_tuple(mpl, '[', tup));
+            /* create new parameter member with given n-tuple */
+            memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
+               ;
+            /* assign value to the parameter member */
+            switch (in->par->type)
+            {  case A_NUMERIC:
+               case A_INTEGER:
+               case A_BINARY:
+                  if (dca->type[k] != 'N')
+                     error(mpl, "%s requires numeric data",
+                        in->par->name);
+                  memb->value.num = dca->num[k];
+                  break;
+               case A_SYMBOLIC:
+                  switch (dca->type[k])
+                  {  case 'N':
+                        memb->value.sym = create_symbol_num(mpl,
+                           dca->num[k]);
+                        break;
+                     case 'S':
+                        xassert(strlen(dca->str[k]) <= MAX_LENGTH);
+                        memb->value.sym = create_symbol_str(mpl,
+                           create_string(mpl,dca->str[k]));
+                        break;
+                     default:
+                        xassert(dca != dca);
+                  }
+                  break;
+               default:
+                  xassert(in != in);
+            }
+         }
+         /* n-tuple is no more needed */
+         delete_tuple(mpl, tup);
+      }
+      /* close input table */
+      mpl_tab_drv_close(mpl);
+      goto done;
+write_table:
+      /* write data to output table */
+      /* allocate and initialize fields */
+      xassert(dca->nf == 0);
+      for (out = tab->u.out.list; out != NULL; out = out->next)
+         dca->nf++;
+      dca->name = xcalloc(1+dca->nf, sizeof(char *));
+      dca->type = xcalloc(1+dca->nf, sizeof(int));
+      dca->num = xcalloc(1+dca->nf, sizeof(double));
+      dca->str = xcalloc(1+dca->nf, sizeof(char *));
+      k = 0;
+      for (out = tab->u.out.list; out != NULL; out = out->next)
+      {  k++;
+         dca->name[k] = out->name;
+         dca->type[k] = '?';
+         dca->num[k] = 0.0;
+         dca->str[k] = xmalloc(MAX_LENGTH+1);
+         dca->str[k][0] = '\0';
+      }
+      /* open output table */
+      mpl_tab_drv_open(mpl, 'W');
+      /* evaluate fields and write records */
+      loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
+      /* close output table */
+      mpl_tab_drv_close(mpl);
+done: /* free table driver communication area */
+      free_dca(mpl);
+      return;
+}
+
+void free_dca(MPL *mpl)
+{     /* free table driver communucation area */
+      TABDCA *dca = mpl->dca;
+      int k;
+      if (dca != NULL)
+      {  if (dca->link != NULL)
+            mpl_tab_drv_close(mpl);
+         if (dca->arg != NULL)
+         {  for (k = 1; k <= dca->na; k++)
+#if 1 /* 28/IX-2008 */
+               if (dca->arg[k] != NULL)
+#endif
+               xfree(dca->arg[k]);
+            xfree(dca->arg);
+         }
+         if (dca->name != NULL) xfree(dca->name);
+         if (dca->type != NULL) xfree(dca->type);
+         if (dca->num != NULL) xfree(dca->num);
+         if (dca->str != NULL)
+         {  for (k = 1; k <= dca->nf; k++)
+               xfree(dca->str[k]);
+            xfree(dca->str);
+         }
+         xfree(dca), mpl->dca = NULL;
+      }
+      return;
+}
+
+void clean_table(MPL *mpl, TABLE *tab)
+{     /* clean table statement */
+      TABARG *arg;
+      TABOUT *out;
+      /* clean string list */
+      for (arg = tab->arg; arg != NULL; arg = arg->next)
+         clean_code(mpl, arg->code);
+      switch (tab->type)
+      {  case A_INPUT:
+            break;
+         case A_OUTPUT:
+            /* clean subscript domain */
+            clean_domain(mpl, tab->u.out.domain);
+            /* clean output list */
+            for (out = tab->u.out.list; out != NULL; out = out->next)
+               clean_code(mpl, out->code);
+            break;
+         default:
+            xassert(tab != tab);
+      }
+      return;
+}
+#endif
+
+/**********************************************************************/
+/* * *                      MODEL STATEMENTS                      * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- execute_check - execute check statement.
+--
+-- This routine executes specified check statement. */
+
+static int check_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      CHECK *chk = (CHECK *)info;
+      if (!eval_logical(mpl, chk->code))
+         error(mpl, "check%s failed", format_tuple(mpl, '[',
+            get_domain_tuple(mpl, chk->domain)));
+      return 0;
+}
+
+void execute_check(MPL *mpl, CHECK *chk)
+{     loop_within_domain(mpl, chk->domain, chk, check_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_check - clean check statement.
+--
+-- This routine cleans specified check statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_check(MPL *mpl, CHECK *chk)
+{     /* clean subscript domain */
+      clean_domain(mpl, chk->domain);
+      /* clean pseudo-code for computing predicate */
+      clean_code(mpl, chk->code);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_display - execute display statement.
+--
+-- This routine executes specified display statement. */
+
+static void display_set(MPL *mpl, SET *set, MEMBER *memb)
+{     /* display member of model set */
+      ELEMSET *s = memb->value.set;
+      MEMBER *m;
+      write_text(mpl, "%s%s%s\n", set->name,
+         format_tuple(mpl, '[', memb->tuple),
+         s->head == NULL ? " is empty" : ":");
+      for (m = s->head; m != NULL; m = m->next)
+         write_text(mpl, "   %s\n", format_tuple(mpl, '(', m->tuple));
+      return;
+}
+
+static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
+{     /* display member of model parameter */
+      switch (par->type)
+      {  case A_NUMERIC:
+         case A_INTEGER:
+         case A_BINARY:
+            write_text(mpl, "%s%s = %.*g\n", par->name,
+               format_tuple(mpl, '[', memb->tuple),
+               DBL_DIG, memb->value.num);
+            break;
+         case A_SYMBOLIC:
+            write_text(mpl, "%s%s = %s\n", par->name,
+               format_tuple(mpl, '[', memb->tuple),
+               format_symbol(mpl, memb->value.sym));
+            break;
+         default:
+            xassert(par != par);
+      }
+      return;
+}
+
+#if 1 /* 15/V-2010 */
+static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
+      int suff)
+{     /* display member of model variable */
+      if (suff == DOT_NONE || suff == DOT_VAL)
+         write_text(mpl, "%s%s.val = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->prim);
+      else if (suff == DOT_LB)
+         write_text(mpl, "%s%s.lb = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->var->lbnd == NULL ? -DBL_MAX :
+            memb->value.var->lbnd);
+      else if (suff == DOT_UB)
+         write_text(mpl, "%s%s.ub = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->var->ubnd == NULL ? +DBL_MAX :
+            memb->value.var->ubnd);
+      else if (suff == DOT_STATUS)
+         write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
+            (mpl, '[', memb->tuple), memb->value.var->stat);
+      else if (suff == DOT_DUAL)
+         write_text(mpl, "%s%s.dual = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->dual);
+      else
+         xassert(suff != suff);
+      return;
+}
+#endif
+
+#if 1 /* 15/V-2010 */
+static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
+      int suff)
+{     /* display member of model constraint */
+      if (suff == DOT_NONE || suff == DOT_VAL)
+         write_text(mpl, "%s%s.val = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->prim);
+      else if (suff == DOT_LB)
+         write_text(mpl, "%s%s.lb = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->con->lbnd == NULL ? -DBL_MAX :
+            memb->value.con->lbnd);
+      else if (suff == DOT_UB)
+         write_text(mpl, "%s%s.ub = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->con->ubnd == NULL ? +DBL_MAX :
+            memb->value.con->ubnd);
+      else if (suff == DOT_STATUS)
+         write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
+            (mpl, '[', memb->tuple), memb->value.con->stat);
+      else if (suff == DOT_DUAL)
+         write_text(mpl, "%s%s.dual = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->dual);
+      else
+         xassert(suff != suff);
+      return;
+}
+#endif
+
+static void display_memb(MPL *mpl, CODE *code)
+{     /* display member specified by pseudo-code */
+      MEMBER memb;
+      ARG_LIST *e;
+      xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
+         || code->op == O_MEMSET || code->op == O_MEMVAR
+         || code->op == O_MEMCON);
+      memb.tuple = create_tuple(mpl);
+      for (e = code->arg.par.list; e != NULL; e = e->next)
+         memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
+            e->x));
+      switch (code->op)
+      {  case O_MEMNUM:
+            memb.value.num = eval_member_num(mpl, code->arg.par.par,
+               memb.tuple);
+            display_par(mpl, code->arg.par.par, &memb);
+            break;
+         case O_MEMSYM:
+            memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
+               memb.tuple);
+            display_par(mpl, code->arg.par.par, &memb);
+            delete_symbol(mpl, memb.value.sym);
+            break;
+         case O_MEMSET:
+            memb.value.set = eval_member_set(mpl, code->arg.set.set,
+               memb.tuple);
+            display_set(mpl, code->arg.set.set, &memb);
+            break;
+         case O_MEMVAR:
+            memb.value.var = eval_member_var(mpl, code->arg.var.var,
+               memb.tuple);
+            display_var
+               (mpl, code->arg.var.var, &memb, code->arg.var.suff);
+            break;
+         case O_MEMCON:
+            memb.value.con = eval_member_con(mpl, code->arg.con.con,
+               memb.tuple);
+            display_con
+               (mpl, code->arg.con.con, &memb, code->arg.con.suff);
+            break;
+         default:
+            xassert(code != code);
+      }
+      delete_tuple(mpl, memb.tuple);
+      return;
+}
+
+static void display_code(MPL *mpl, CODE *code)
+{     /* display value of expression */
+      switch (code->type)
+      {  case A_NUMERIC:
+            /* numeric value */
+            {  double num;
+               num = eval_numeric(mpl, code);
+               write_text(mpl, "%.*g\n", DBL_DIG, num);
+            }
+            break;
+         case A_SYMBOLIC:
+            /* symbolic value */
+            {  SYMBOL *sym;
+               sym = eval_symbolic(mpl, code);
+               write_text(mpl, "%s\n", format_symbol(mpl, sym));
+               delete_symbol(mpl, sym);
+            }
+            break;
+         case A_LOGICAL:
+            /* logical value */
+            {  int bit;
+               bit = eval_logical(mpl, code);
+               write_text(mpl, "%s\n", bit ? "true" : "false");
+            }
+            break;
+         case A_TUPLE:
+            /* n-tuple */
+            {  TUPLE *tuple;
+               tuple = eval_tuple(mpl, code);
+               write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case A_ELEMSET:
+            /* elemental set */
+            {  ELEMSET *set;
+               MEMBER *memb;
+               set = eval_elemset(mpl, code);
+               if (set->head == 0)
+                  write_text(mpl, "set is empty\n");
+               for (memb = set->head; memb != NULL; memb = memb->next)
+                  write_text(mpl, "   %s\n", format_tuple(mpl, '(',
+                     memb->tuple));
+               delete_elemset(mpl, set);
+            }
+            break;
+         case A_FORMULA:
+            /* linear form */
+            {  FORMULA *form, *term;
+               form = eval_formula(mpl, code);
+               if (form == NULL)
+                  write_text(mpl, "linear form is empty\n");
+               for (term = form; term != NULL; term = term->next)
+               {  if (term->var == NULL)
+                     write_text(mpl, "   %.*g\n", term->coef);
+                  else
+                     write_text(mpl, "   %.*g %s%s\n", DBL_DIG,
+                        term->coef, term->var->var->name,
+                        format_tuple(mpl, '[', term->var->memb->tuple));
+               }
+               delete_formula(mpl, form);
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      return;
+}
+
+static int display_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      DISPLAY *dpy = (DISPLAY *)info;
+      DISPLAY1 *entry;
+      for (entry = dpy->list; entry != NULL; entry = entry->next)
+      {  if (entry->type == A_INDEX)
+         {  /* dummy index */
+            DOMAIN_SLOT *slot = entry->u.slot;
+            write_text(mpl, "%s = %s\n", slot->name,
+            format_symbol(mpl, slot->value));
+         }
+         else if (entry->type == A_SET)
+         {  /* model set */
+            SET *set = entry->u.set;
+            MEMBER *memb;
+            if (set->assign != NULL)
+            {  /* the set has assignment expression; evaluate all its
+                  members over entire domain */
+               eval_whole_set(mpl, set);
+            }
+            else
+            {  /* the set has no assignment expression; refer to its
+                  any existing member ignoring resultant value to check
+                  the data provided the data section */
+#if 1 /* 12/XII-2008 */
+               if (set->gadget != NULL && set->data == 0)
+               {  /* initialize the set with data from a plain set */
+                  saturate_set(mpl, set);
+               }
+#endif
+               if (set->array->head != NULL)
+                  eval_member_set(mpl, set, set->array->head->tuple);
+            }
+            /* display all members of the set array */
+            if (set->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", set->name);
+            for (memb = set->array->head; memb != NULL; memb =
+               memb->next) display_set(mpl, set, memb);
+         }
+         else if (entry->type == A_PARAMETER)
+         {  /* model parameter */
+            PARAMETER *par = entry->u.par;
+            MEMBER *memb;
+            if (par->assign != NULL)
+            {  /* the parameter has an assignment expression; evaluate
+                  all its member over entire domain */
+               eval_whole_par(mpl, par);
+            }
+            else
+            {  /* the parameter has no assignment expression; refer to
+                  its any existing member ignoring resultant value to
+                  check the data provided in the data section */
+               if (par->array->head != NULL)
+               {  if (par->type != A_SYMBOLIC)
+                     eval_member_num(mpl, par, par->array->head->tuple);
+                  else
+                     delete_symbol(mpl, eval_member_sym(mpl, par,
+                        par->array->head->tuple));
+               }
+            }
+            /* display all members of the parameter array */
+            if (par->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", par->name);
+            for (memb = par->array->head; memb != NULL; memb =
+               memb->next) display_par(mpl, par, memb);
+         }
+         else if (entry->type == A_VARIABLE)
+         {  /* model variable */
+            VARIABLE *var = entry->u.var;
+            MEMBER *memb;
+            xassert(mpl->flag_p);
+            /* display all members of the variable array */
+            if (var->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", var->name);
+            for (memb = var->array->head; memb != NULL; memb =
+               memb->next) display_var(mpl, var, memb, DOT_NONE);
+         }
+         else if (entry->type == A_CONSTRAINT)
+         {  /* model constraint */
+            CONSTRAINT *con = entry->u.con;
+            MEMBER *memb;
+            xassert(mpl->flag_p);
+            /* display all members of the constraint array */
+            if (con->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", con->name);
+            for (memb = con->array->head; memb != NULL; memb =
+               memb->next) display_con(mpl, con, memb, DOT_NONE);
+         }
+         else if (entry->type == A_EXPRESSION)
+         {  /* expression */
+            CODE *code = entry->u.code;
+            if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
+                code->op == O_MEMSET || code->op == O_MEMVAR ||
+                code->op == O_MEMCON)
+               display_memb(mpl, code);
+            else
+               display_code(mpl, code);
+         }
+         else
+            xassert(entry != entry);
+      }
+      return 0;
+}
+
+void execute_display(MPL *mpl, DISPLAY *dpy)
+{     loop_within_domain(mpl, dpy->domain, dpy, display_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_display - clean display statement.
+--
+-- This routine cleans specified display statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_display(MPL *mpl, DISPLAY *dpy)
+{     DISPLAY1 *d;
+#if 0 /* 15/V-2010 */
+      ARG_LIST *e;
+#endif
+      /* clean subscript domain */
+      clean_domain(mpl, dpy->domain);
+      /* clean display list */
+      for (d = dpy->list; d != NULL; d = d->next)
+      {  /* clean pseudo-code for computing expression */
+         if (d->type == A_EXPRESSION)
+            clean_code(mpl, d->u.code);
+#if 0 /* 15/V-2010 */
+         /* clean pseudo-code for computing subscripts */
+         for (e = d->list; e != NULL; e = e->next)
+            clean_code(mpl, e->x);
+#endif
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_printf - execute printf statement.
+--
+-- This routine executes specified printf statement. */
+
+#if 1 /* 14/VII-2006 */
+static void print_char(MPL *mpl, int c)
+{     if (mpl->prt_fp == NULL)
+         write_char(mpl, c);
+      else
+         xfputc(c, mpl->prt_fp);
+      return;
+}
+
+static void print_text(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char buf[OUTBUF_SIZE], *c;
+      va_start(arg, fmt);
+      vsprintf(buf, fmt, arg);
+      xassert(strlen(buf) < sizeof(buf));
+      va_end(arg);
+      for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
+      return;
+}
+#endif
+
+static int printf_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      PRINTF *prt = (PRINTF *)info;
+      PRINTF1 *entry;
+      SYMBOL *sym;
+      char fmt[MAX_LENGTH+1], *c, *from, save;
+      /* evaluate format control string */
+      sym = eval_symbolic(mpl, prt->fmt);
+      if (sym->str == NULL)
+         sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+      else
+         fetch_string(mpl, sym->str, fmt);
+      delete_symbol(mpl, sym);
+      /* scan format control string and perform formatting output */
+      entry = prt->list;
+      for (c = fmt; *c != '\0'; c++)
+      {  if (*c == '%')
+         {  /* scan format specifier */
+            from = c++;
+            if (*c == '%')
+            {  print_char(mpl, '%');
+               continue;
+            }
+            if (entry == NULL) break;
+            /* scan optional flags */
+            while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
+                   *c == '0') c++;
+            /* scan optional minimum field width */
+            while (isdigit((unsigned char)*c)) c++;
+            /* scan optional precision */
+            if (*c == '.')
+            {  c++;
+               while (isdigit((unsigned char)*c)) c++;
+            }
+            /* scan conversion specifier and perform formatting */
+            save = *(c+1), *(c+1) = '\0';
+            if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
+                *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
+            {  /* the specifier requires numeric value */
+               double value;
+               xassert(entry != NULL);
+               switch (entry->code->type)
+               {  case A_NUMERIC:
+                     value = eval_numeric(mpl, entry->code);
+                     break;
+                  case A_SYMBOLIC:
+                     sym = eval_symbolic(mpl, entry->code);
+                     if (sym->str != NULL)
+                        error(mpl, "cannot convert %s to floating-point"
+                           " number", format_symbol(mpl, sym));
+                     value = sym->num;
+                     delete_symbol(mpl, sym);
+                     break;
+                  case A_LOGICAL:
+                     if (eval_logical(mpl, entry->code))
+                        value = 1.0;
+                     else
+                        value = 0.0;
+                     break;
+                  default:
+                     xassert(entry != entry);
+               }
+               if (*c == 'd' || *c == 'i')
+               {  double int_max = (double)INT_MAX;
+                  if (!(-int_max <= value && value <= +int_max))
+                     error(mpl, "cannot convert %.*g to integer",
+                        DBL_DIG, value);
+                  print_text(mpl, from, (int)floor(value + 0.5));
+               }
+               else
+                  print_text(mpl, from, value);
+            }
+            else if (*c == 's')
+            {  /* the specifier requires symbolic value */
+               char value[MAX_LENGTH+1];
+               switch (entry->code->type)
+               {  case A_NUMERIC:
+                     sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
+                        entry->code));
+                     break;
+                  case A_LOGICAL:
+                     if (eval_logical(mpl, entry->code))
+                        strcpy(value, "T");
+                     else
+                        strcpy(value, "F");
+                     break;
+                  case A_SYMBOLIC:
+                     sym = eval_symbolic(mpl, entry->code);
+                     if (sym->str == NULL)
+                        sprintf(value, "%.*g", DBL_DIG, sym->num);
+                     else
+                        fetch_string(mpl, sym->str, value);
+                     delete_symbol(mpl, sym);
+                     break;
+                  default:
+                     xassert(entry != entry);
+               }
+               print_text(mpl, from, value);
+            }
+            else
+               error(mpl, "format specifier missing or invalid");
+            *(c+1) = save;
+            entry = entry->next;
+         }
+         else if (*c == '\\')
+         {  /* write some control character */
+            c++;
+            if (*c == 't')
+               print_char(mpl, '\t');
+            else if (*c == 'n')
+               print_char(mpl, '\n');
+#if 1 /* 28/X-2010 */
+            else if (*c == '\0')
+            {  /* format string ends with backslash */
+               error(mpl, "invalid use of escape character \\ in format"
+                  " control string");
+            }
+#endif
+            else
+               print_char(mpl, *c);
+         }
+         else
+         {  /* write character without formatting */
+            print_char(mpl, *c);
+         }
+      }
+      return 0;
+}
+
+#if 0 /* 14/VII-2006 */
+void execute_printf(MPL *mpl, PRINTF *prt)
+{     loop_within_domain(mpl, prt->domain, prt, printf_func);
+      return;
+}
+#else
+void execute_printf(MPL *mpl, PRINTF *prt)
+{     if (prt->fname == NULL)
+      {  /* switch to the standard output */
+         if (mpl->prt_fp != NULL)
+         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
+            xfree(mpl->prt_file), mpl->prt_file = NULL;
+         }
+      }
+      else
+      {  /* evaluate file name string */
+         SYMBOL *sym;
+         char fname[MAX_LENGTH+1];
+         sym = eval_symbolic(mpl, prt->fname);
+         if (sym->str == NULL)
+            sprintf(fname, "%.*g", DBL_DIG, sym->num);
+         else
+            fetch_string(mpl, sym->str, fname);
+         delete_symbol(mpl, sym);
+         /* close the current print file, if necessary */
+         if (mpl->prt_fp != NULL &&
+            (!prt->app || strcmp(mpl->prt_file, fname) != 0))
+         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
+            xfree(mpl->prt_file), mpl->prt_file = NULL;
+         }
+         /* open the specified print file, if necessary */
+         if (mpl->prt_fp == NULL)
+         {  mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w");
+            if (mpl->prt_fp == NULL)
+               error(mpl, "unable to open `%s' for writing - %s",
+                  fname, xerrmsg());
+            mpl->prt_file = xmalloc(strlen(fname)+1);
+            strcpy(mpl->prt_file, fname);
+         }
+      }
+      loop_within_domain(mpl, prt->domain, prt, printf_func);
+      if (mpl->prt_fp != NULL)
+      {  xfflush(mpl->prt_fp);
+         if (xferror(mpl->prt_fp))
+            error(mpl, "writing error to `%s' - %s", mpl->prt_file,
+               xerrmsg());
+      }
+      return;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- clean_printf - clean printf statement.
+--
+-- This routine cleans specified printf statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_printf(MPL *mpl, PRINTF *prt)
+{     PRINTF1 *p;
+      /* clean subscript domain */
+      clean_domain(mpl, prt->domain);
+      /* clean pseudo-code for computing format string */
+      clean_code(mpl, prt->fmt);
+      /* clean printf list */
+      for (p = prt->list; p != NULL; p = p->next)
+      {  /* clean pseudo-code for computing value to be printed */
+         clean_code(mpl, p->code);
+      }
+#if 1 /* 14/VII-2006 */
+      /* clean pseudo-code for computing file name string */
+      clean_code(mpl, prt->fname);
+#endif
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_for - execute for statement.
+--
+-- This routine executes specified for statement. */
+
+static int for_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      FOR *fur = (FOR *)info;
+      STATEMENT *stmt, *save;
+      save = mpl->stmt;
+      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
+         execute_statement(mpl, stmt);
+      mpl->stmt = save;
+      return 0;
+}
+
+void execute_for(MPL *mpl, FOR *fur)
+{     loop_within_domain(mpl, fur->domain, fur, for_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_for - clean for statement.
+--
+-- This routine cleans specified for statement that assumes deleting all
+-- stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_for(MPL *mpl, FOR *fur)
+{     STATEMENT *stmt;
+      /* clean subscript domain */
+      clean_domain(mpl, fur->domain);
+      /* clean all sub-statements */
+      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
+         clean_statement(mpl, stmt);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_statement - execute specified model statement.
+--
+-- This routine executes specified model statement. */
+
+void execute_statement(MPL *mpl, STATEMENT *stmt)
+{     mpl->stmt = stmt;
+      switch (stmt->type)
+      {  case A_SET:
+         case A_PARAMETER:
+         case A_VARIABLE:
+            break;
+         case A_CONSTRAINT:
+            xprintf("Generating %s...\n", stmt->u.con->name);
+            eval_whole_con(mpl, stmt->u.con);
+            break;
+         case A_TABLE:
+            switch (stmt->u.tab->type)
+            {  case A_INPUT:
+                  xprintf("Reading %s...\n", stmt->u.tab->name);
+                  break;
+               case A_OUTPUT:
+                  xprintf("Writing %s...\n", stmt->u.tab->name);
+                  break;
+               default:
+                  xassert(stmt != stmt);
+            }
+            execute_table(mpl, stmt->u.tab);
+            break;
+         case A_SOLVE:
+            break;
+         case A_CHECK:
+            xprintf("Checking (line %d)...\n", stmt->line);
+            execute_check(mpl, stmt->u.chk);
+            break;
+         case A_DISPLAY:
+            write_text(mpl, "Display statement at line %d\n",
+               stmt->line);
+            execute_display(mpl, stmt->u.dpy);
+            break;
+         case A_PRINTF:
+            execute_printf(mpl, stmt->u.prt);
+            break;
+         case A_FOR:
+            execute_for(mpl, stmt->u.fur);
+            break;
+         default:
+            xassert(stmt != stmt);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_statement - clean specified model statement.
+--
+-- This routine cleans specified model statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_statement(MPL *mpl, STATEMENT *stmt)
+{     switch(stmt->type)
+      {  case A_SET:
+            clean_set(mpl, stmt->u.set); break;
+         case A_PARAMETER:
+            clean_parameter(mpl, stmt->u.par); break;
+         case A_VARIABLE:
+            clean_variable(mpl, stmt->u.var); break;
+         case A_CONSTRAINT:
+            clean_constraint(mpl, stmt->u.con); break;
+#if 1 /* 11/II-2008 */
+         case A_TABLE:
+            clean_table(mpl, stmt->u.tab); break;
+#endif
+         case A_SOLVE:
+            break;
+         case A_CHECK:
+            clean_check(mpl, stmt->u.chk); break;
+         case A_DISPLAY:
+            clean_display(mpl, stmt->u.dpy); break;
+         case A_PRINTF:
+            clean_printf(mpl, stmt->u.prt); break;
+         case A_FOR:
+            clean_for(mpl, stmt->u.fur); break;
+         default:
+            xassert(stmt != stmt);
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmpl04.c b/optional/glpk/glpmpl04.c
new file mode 100644
index 0000000..0925bb7
--- /dev/null
+++ b/optional/glpk/glpmpl04.c
@@ -0,0 +1,1429 @@
+/* glpmpl04.c */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpmpl.h"
+#define xfault xerror
+#define dmp_create_poolx(size) dmp_create_pool()
+
+/**********************************************************************/
+/* * *              GENERATING AND POSTSOLVING MODEL              * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- alloc_content - allocate content arrays for all model objects.
+--
+-- This routine allocates content arrays for all existing model objects
+-- and thereby finalizes creating model.
+--
+-- This routine must be called immediately after reading model section,
+-- i.e. before reading data section or generating model. */
+
+void alloc_content(MPL *mpl)
+{     STATEMENT *stmt;
+      /* walk through all model statements */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  switch (stmt->type)
+         {  case A_SET:
+               /* model set */
+               xassert(stmt->u.set->array == NULL);
+               stmt->u.set->array = create_array(mpl, A_ELEMSET,
+                  stmt->u.set->dim);
+               break;
+            case A_PARAMETER:
+               /* model parameter */
+               xassert(stmt->u.par->array == NULL);
+               switch (stmt->u.par->type)
+               {  case A_NUMERIC:
+                  case A_INTEGER:
+                  case A_BINARY:
+                     stmt->u.par->array = create_array(mpl, A_NUMERIC,
+                        stmt->u.par->dim);
+                     break;
+                  case A_SYMBOLIC:
+                     stmt->u.par->array = create_array(mpl, A_SYMBOLIC,
+                        stmt->u.par->dim);
+                     break;
+                  default:
+                     xassert(stmt != stmt);
+               }
+               break;
+            case A_VARIABLE:
+               /* model variable */
+               xassert(stmt->u.var->array == NULL);
+               stmt->u.var->array = create_array(mpl, A_ELEMVAR,
+                  stmt->u.var->dim);
+               break;
+            case A_CONSTRAINT:
+               /* model constraint/objective */
+               xassert(stmt->u.con->array == NULL);
+               stmt->u.con->array = create_array(mpl, A_ELEMCON,
+                  stmt->u.con->dim);
+               break;
+#if 1 /* 11/II-2008 */
+            case A_TABLE:
+#endif
+            case A_SOLVE:
+            case A_CHECK:
+            case A_DISPLAY:
+            case A_PRINTF:
+            case A_FOR:
+               /* functional statements have no content array */
+               break;
+            default:
+               xassert(stmt != stmt);
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- generate_model - generate model.
+--
+-- This routine executes the model statements which precede the solve
+-- statement. */
+
+void generate_model(MPL *mpl)
+{     STATEMENT *stmt;
+      xassert(!mpl->flag_p);
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  execute_statement(mpl, stmt);
+         if (mpl->stmt->type == A_SOLVE) break;
+      }
+      mpl->stmt = stmt;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- build_problem - build problem instance.
+--
+-- This routine builds lists of rows and columns for problem instance,
+-- which corresponds to the generated model. */
+
+void build_problem(MPL *mpl)
+{     STATEMENT *stmt;
+      MEMBER *memb;
+      VARIABLE *v;
+      CONSTRAINT *c;
+      FORMULA *t;
+      int i, j;
+      xassert(mpl->m == 0);
+      xassert(mpl->n == 0);
+      xassert(mpl->row == NULL);
+      xassert(mpl->col == NULL);
+      /* check that all elemental variables has zero column numbers */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_VARIABLE)
+         {  v = stmt->u.var;
+            for (memb = v->array->head; memb != NULL; memb = memb->next)
+               xassert(memb->value.var->j == 0);
+         }
+      }
+      /* assign row numbers to elemental constraints and objectives */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_CONSTRAINT)
+         {  c = stmt->u.con;
+            for (memb = c->array->head; memb != NULL; memb = memb->next)
+            {  xassert(memb->value.con->i == 0);
+               memb->value.con->i = ++mpl->m;
+               /* walk through linear form and mark elemental variables,
+                  which are referenced at least once */
+               for (t = memb->value.con->form; t != NULL; t = t->next)
+               {  xassert(t->var != NULL);
+                  t->var->memb->value.var->j = -1;
+               }
+            }
+         }
+      }
+      /* assign column numbers to marked elemental variables */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_VARIABLE)
+         {  v = stmt->u.var;
+            for (memb = v->array->head; memb != NULL; memb = memb->next)
+               if (memb->value.var->j != 0) memb->value.var->j =
+                  ++mpl->n;
+         }
+      }
+      /* build list of rows */
+      mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *));
+      for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL;
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_CONSTRAINT)
+         {  c = stmt->u.con;
+            for (memb = c->array->head; memb != NULL; memb = memb->next)
+            {  i = memb->value.con->i;
+               xassert(1 <= i && i <= mpl->m);
+               xassert(mpl->row[i] == NULL);
+               mpl->row[i] = memb->value.con;
+            }
+         }
+      }
+      for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL);
+      /* build list of columns */
+      mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *));
+      for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL;
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_VARIABLE)
+         {  v = stmt->u.var;
+            for (memb = v->array->head; memb != NULL; memb = memb->next)
+            {  j = memb->value.var->j;
+               if (j == 0) continue;
+               xassert(1 <= j && j <= mpl->n);
+               xassert(mpl->col[j] == NULL);
+               mpl->col[j] = memb->value.var;
+            }
+         }
+      }
+      for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- postsolve_model - postsolve model.
+--
+-- This routine executes the model statements which follow the solve
+-- statement. */
+
+void postsolve_model(MPL *mpl)
+{     STATEMENT *stmt;
+      xassert(!mpl->flag_p);
+      mpl->flag_p = 1;
+      for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next)
+         execute_statement(mpl, stmt);
+      mpl->stmt = NULL;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_model - clean model content.
+--
+-- This routine cleans the model content that assumes deleting all stuff
+-- dynamically allocated on generating/postsolving phase.
+--
+-- Actually cleaning model content is not needed. This function is used
+-- mainly to be sure that there were no logical errors on using dynamic
+-- memory pools during the generation phase.
+--
+-- NOTE: This routine must not be called if any errors were detected on
+--       the generation phase. */
+
+void clean_model(MPL *mpl)
+{     STATEMENT *stmt;
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+         clean_statement(mpl, stmt);
+      /* check that all atoms have been returned to their pools */
+      if (dmp_in_use(mpl->strings).lo != 0)
+         error(mpl, "internal logic error: %d string segment(s) were lo"
+            "st", dmp_in_use(mpl->strings).lo);
+      if (dmp_in_use(mpl->symbols).lo != 0)
+         error(mpl, "internal logic error: %d symbol(s) were lost",
+            dmp_in_use(mpl->symbols).lo);
+      if (dmp_in_use(mpl->tuples).lo != 0)
+         error(mpl, "internal logic error: %d n-tuple component(s) were"
+            " lost", dmp_in_use(mpl->tuples).lo);
+      if (dmp_in_use(mpl->arrays).lo != 0)
+         error(mpl, "internal logic error: %d array(s) were lost",
+            dmp_in_use(mpl->arrays).lo);
+      if (dmp_in_use(mpl->members).lo != 0)
+         error(mpl, "internal logic error: %d array member(s) were lost"
+            , dmp_in_use(mpl->members).lo);
+      if (dmp_in_use(mpl->elemvars).lo != 0)
+         error(mpl, "internal logic error: %d elemental variable(s) wer"
+            "e lost", dmp_in_use(mpl->elemvars).lo);
+      if (dmp_in_use(mpl->formulae).lo != 0)
+         error(mpl, "internal logic error: %d linear term(s) were lost",
+            dmp_in_use(mpl->formulae).lo);
+      if (dmp_in_use(mpl->elemcons).lo != 0)
+         error(mpl, "internal logic error: %d elemental constraint(s) w"
+            "ere lost", dmp_in_use(mpl->elemcons).lo);
+      return;
+}
+
+/**********************************************************************/
+/* * *                        INPUT/OUTPUT                        * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- open_input - open input text file.
+--
+-- This routine opens the input text file for scanning. */
+
+void open_input(MPL *mpl, char *file)
+{     mpl->line = 0;
+      mpl->c = '\n';
+      mpl->token = 0;
+      mpl->imlen = 0;
+      mpl->image[0] = '\0';
+      mpl->value = 0.0;
+      mpl->b_token = T_EOF;
+      mpl->b_imlen = 0;
+      mpl->b_image[0] = '\0';
+      mpl->b_value = 0.0;
+      mpl->f_dots = 0;
+      mpl->f_scan = 0;
+      mpl->f_token = 0;
+      mpl->f_imlen = 0;
+      mpl->f_image[0] = '\0';
+      mpl->f_value = 0.0;
+      memset(mpl->context, ' ', CONTEXT_SIZE);
+      mpl->c_ptr = 0;
+      xassert(mpl->in_fp == NULL);
+      mpl->in_fp = xfopen(file, "r");
+      if (mpl->in_fp == NULL)
+         error(mpl, "unable to open %s - %s", file, xerrmsg());
+      mpl->in_file = file;
+      /* scan the very first character */
+      get_char(mpl);
+      /* scan the very first token */
+      get_token(mpl);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- read_char - read next character from input text file.
+--
+-- This routine returns a next ASCII character read from the input text
+-- file. If the end of file has been reached, EOF is returned. */
+
+int read_char(MPL *mpl)
+{     int c;
+      xassert(mpl->in_fp != NULL);
+      c = xfgetc(mpl->in_fp);
+      if (c < 0)
+      {  if (xferror(mpl->in_fp))
+            error(mpl, "read error on %s - %s", mpl->in_file,
+               xerrmsg());
+         c = EOF;
+      }
+      return c;
+}
+
+/*----------------------------------------------------------------------
+-- close_input - close input text file.
+--
+-- This routine closes the input text file. */
+
+void close_input(MPL *mpl)
+{     xassert(mpl->in_fp != NULL);
+      xfclose(mpl->in_fp);
+      mpl->in_fp = NULL;
+      mpl->in_file = NULL;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- open_output - open output text file.
+--
+-- This routine opens the output text file for writing data produced by
+-- display and printf statements. */
+
+void open_output(MPL *mpl, char *file)
+{     xassert(mpl->out_fp == NULL);
+      /* if (file == NULL) */
+      /* {  file = "<stdout>"; */
+      /*    mpl->out_fp = (void *)stdout; */
+      /* } */
+      /* else */
+      {  mpl->out_fp = xfopen(file, "w");
+         if (mpl->out_fp == NULL)
+            error(mpl, "unable to create %s - %s", file, xerrmsg());
+      }
+      mpl->out_file = xmalloc(strlen(file)+1);
+      strcpy(mpl->out_file, file);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- write_char - write next character to output text file.
+--
+-- This routine writes an ASCII character to the output text file. */
+
+void write_char(MPL *mpl, int c)
+{     xassert(mpl->out_fp != NULL);
+      /* if (mpl->out_fp == (void *)stdout) */
+      /*    xprintf("%c", c); */
+      /* else */
+         xfprintf(mpl->out_fp, "%c", c);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- write_text - format and write text to output text file.
+--
+-- This routine formats a text using the format control string and then
+-- writes this text to the output text file. */
+
+void write_text(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char buf[OUTBUF_SIZE], *c;
+      va_start(arg, fmt);
+      vsprintf(buf, fmt, arg);
+      xassert(strlen(buf) < sizeof(buf));
+      va_end(arg);
+      for (c = buf; *c != '\0'; c++) write_char(mpl, *c);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- flush_output - finalize writing data to output text file.
+--
+-- This routine finalizes writing data to the output text file. */
+
+void flush_output(MPL *mpl)
+{     xassert(mpl->out_fp != NULL);
+      /* if (mpl->out_fp != (void *)stdout) */
+      {  xfflush(mpl->out_fp);
+         if (xferror(mpl->out_fp))
+            error(mpl, "write error on %s - %s", mpl->out_file,
+               xerrmsg());
+      }
+      return;
+}
+
+/**********************************************************************/
+/* * *                      SOLVER INTERFACE                      * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- error - print error message and terminate model processing.
+--
+-- This routine formats and prints an error message and then terminates
+-- model processing. */
+
+void error(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char msg[4095+1];
+      va_start(arg, fmt);
+      vsprintf(msg, fmt, arg);
+      xassert(strlen(msg) < sizeof(msg));
+      va_end(arg);
+      switch (mpl->phase)
+      {  case 1:
+         case 2:
+            /* translation phase */
+            xprintf("%s:%d: %s\n",
+               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
+               mpl->line, msg);
+            print_context(mpl);
+            break;
+         case 3:
+            /* generation/postsolve phase */
+            xprintf("%s:%d: %s\n",
+               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
+               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      mpl->phase = 4;
+      longjmp(mpl->jump, 1);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- warning - print warning message and continue model processing.
+--
+-- This routine formats and prints a warning message and returns to the
+-- calling program. */
+
+void warning(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char msg[4095+1];
+      va_start(arg, fmt);
+      vsprintf(msg, fmt, arg);
+      xassert(strlen(msg) < sizeof(msg));
+      va_end(arg);
+      switch (mpl->phase)
+      {  case 1:
+         case 2:
+            /* translation phase */
+            xprintf("%s:%d: warning: %s\n",
+               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
+               mpl->line, msg);
+            break;
+         case 3:
+            /* generation/postsolve phase */
+            xprintf("%s:%d: warning: %s\n",
+               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
+               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_initialize - create and initialize translator database.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- MPL *mpl_initialize(void);
+--
+-- *Description*
+--
+-- The routine mpl_initialize creates and initializes the database used
+-- by the GNU MathProg translator.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the database created. */
+
+MPL *mpl_initialize(void)
+{     MPL *mpl;
+      mpl = xmalloc(sizeof(MPL));
+      /* scanning segment */
+      mpl->line = 0;
+      mpl->c = 0;
+      mpl->token = 0;
+      mpl->imlen = 0;
+      mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char));
+      mpl->image[0] = '\0';
+      mpl->value = 0.0;
+      mpl->b_token = 0;
+      mpl->b_imlen = 0;
+      mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char));
+      mpl->b_image[0] = '\0';
+      mpl->b_value = 0.0;
+      mpl->f_dots = 0;
+      mpl->f_scan = 0;
+      mpl->f_token = 0;
+      mpl->f_imlen = 0;
+      mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char));
+      mpl->f_image[0] = '\0';
+      mpl->f_value = 0.0;
+      mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char));
+      memset(mpl->context, ' ', CONTEXT_SIZE);
+      mpl->c_ptr = 0;
+      mpl->flag_d = 0;
+      /* translating segment */
+      mpl->pool = dmp_create_poolx(0);
+      mpl->tree = avl_create_tree(avl_strcmp, NULL);
+      mpl->model = NULL;
+      mpl->flag_x = 0;
+      mpl->as_within = 0;
+      mpl->as_in = 0;
+      mpl->as_binary = 0;
+      mpl->flag_s = 0;
+      /* common segment */
+      mpl->strings = dmp_create_poolx(sizeof(STRING));
+      mpl->symbols = dmp_create_poolx(sizeof(SYMBOL));
+      mpl->tuples = dmp_create_poolx(sizeof(TUPLE));
+      mpl->arrays = dmp_create_poolx(sizeof(ARRAY));
+      mpl->members = dmp_create_poolx(sizeof(MEMBER));
+      mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR));
+      mpl->formulae = dmp_create_poolx(sizeof(FORMULA));
+      mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON));
+      mpl->a_list = NULL;
+      mpl->sym_buf = xcalloc(255+1, sizeof(char));
+      mpl->sym_buf[0] = '\0';
+      mpl->tup_buf = xcalloc(255+1, sizeof(char));
+      mpl->tup_buf[0] = '\0';
+      /* generating/postsolving segment */
+      mpl->rand = rng_create_rand();
+      mpl->flag_p = 0;
+      mpl->stmt = NULL;
+#if 1 /* 11/II-2008 */
+      mpl->dca = NULL;
+#endif
+      mpl->m = 0;
+      mpl->n = 0;
+      mpl->row = NULL;
+      mpl->col = NULL;
+      /* input/output segment */
+      mpl->in_fp = NULL;
+      mpl->in_file = NULL;
+      mpl->out_fp = NULL;
+      mpl->out_file = NULL;
+      mpl->prt_fp = NULL;
+      mpl->prt_file = NULL;
+      /* solver interface segment */
+      if (setjmp(mpl->jump)) xassert(mpl != mpl);
+      mpl->phase = 0;
+      mpl->mod_file = NULL;
+      mpl->mpl_buf = xcalloc(255+1, sizeof(char));
+      mpl->mpl_buf[0] = '\0';
+      return mpl;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_read_model - read model section and optional data section.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_read_model(MPL *mpl, char *file, int skip_data);
+--
+-- *Description*
+--
+-- The routine mpl_read_model reads model section and optionally data
+-- section, which may follow the model section, from the text file,
+-- whose name is the character string file, performs translating model
+-- statements and data blocks, and stores all the information in the
+-- translator database.
+--
+-- The parameter skip_data is a flag. If the input file contains the
+-- data section and this flag is set, the data section is not read as
+-- if there were no data section and a warning message is issued. This
+-- allows reading the data section from another input file.
+--
+-- This routine should be called once after the routine mpl_initialize
+-- and before other API routines.
+--
+-- *Returns*
+--
+-- The routine mpl_read_model returns one the following codes:
+--
+-- 1 - translation successful. The input text file contains only model
+--     section. In this case the calling program may call the routine
+--     mpl_read_data to read data section from another file.
+-- 2 - translation successful. The input text file contains both model
+--     and data section.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_read_model(MPL *mpl, char *file, int skip_data)
+{     if (mpl->phase != 0)
+         xfault("mpl_read_model: invalid call sequence\n");
+      if (file == NULL)
+         xfault("mpl_read_model: no input filename specified\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* translate model section */
+      mpl->phase = 1;
+      xprintf("Reading model section from %s...\n", file);
+      open_input(mpl, file);
+      model_section(mpl);
+      if (mpl->model == NULL)
+         error(mpl, "empty model section not allowed");
+      /* save name of the input text file containing model section for
+         error diagnostics during the generation phase */
+      mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char));
+      strcpy(mpl->mod_file, mpl->in_file);
+      /* allocate content arrays for all model objects */
+      alloc_content(mpl);
+      /* optional data section may begin with the keyword 'data' */
+      if (is_keyword(mpl, "data"))
+      {  if (skip_data)
+         {  warning(mpl, "data section ignored");
+            goto skip;
+         }
+         mpl->flag_d = 1;
+         get_token(mpl /* data */);
+         if (mpl->token != T_SEMICOLON)
+            error(mpl, "semicolon missing where expected");
+         get_token(mpl /* ; */);
+         /* translate data section */
+         mpl->phase = 2;
+         xprintf("Reading data section from %s...\n", file);
+         data_section(mpl);
+      }
+      /* process end statement */
+      end_statement(mpl);
+skip: xprintf("%d line%s were read\n",
+         mpl->line, mpl->line == 1 ? "" : "s");
+      close_input(mpl);
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_read_data - read data section.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_read_data(MPL *mpl, char *file);
+--
+-- *Description*
+--
+-- The routine mpl_read_data reads data section from the text file,
+-- whose name is the character string file, performs translating data
+-- blocks, and stores the data read in the translator database.
+--
+-- If this routine is used, it should be called once after the routine
+-- mpl_read_model and if the latter returned the code 1.
+--
+-- *Returns*
+--
+-- The routine mpl_read_data returns one of the following codes:
+--
+-- 2 - data section has been successfully processed.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_read_data(MPL *mpl, char *file)
+#if 0 /* 02/X-2008 */
+{     if (mpl->phase != 1)
+#else
+{     if (!(mpl->phase == 1 || mpl->phase == 2))
+#endif
+         xfault("mpl_read_data: invalid call sequence\n");
+      if (file == NULL)
+         xfault("mpl_read_data: no input filename specified\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* process data section */
+      mpl->phase = 2;
+      xprintf("Reading data section from %s...\n", file);
+      mpl->flag_d = 1;
+      open_input(mpl, file);
+      /* in this case the keyword 'data' is optional */
+      if (is_literal(mpl, "data"))
+      {  get_token(mpl /* data */);
+         if (mpl->token != T_SEMICOLON)
+            error(mpl, "semicolon missing where expected");
+         get_token(mpl /* ; */);
+      }
+      data_section(mpl);
+      /* process end statement */
+      end_statement(mpl);
+      xprintf("%d line%s were read\n",
+         mpl->line, mpl->line == 1 ? "" : "s");
+      close_input(mpl);
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_generate - generate model.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_generate(MPL *mpl, char *file);
+--
+-- *Description*
+--
+-- The routine mpl_generate generates the model using its description
+-- stored in the translator database. This phase means generating all
+-- variables, constraints, and objectives, executing check and display
+-- statements, which precede the solve statement (if it is presented),
+-- and building the problem instance.
+--
+-- The character string file specifies the name of output text file, to
+-- which output produced by display statements should be written. It is
+-- allowed to specify NULL, in which case the output goes to stdout via
+-- the routine print.
+--
+-- This routine should be called once after the routine mpl_read_model
+-- or mpl_read_data and if one of the latters returned the code 2.
+--
+-- *Returns*
+--
+-- The routine mpl_generate returns one of the following codes:
+--
+-- 3 - model has been successfully generated. In this case the calling
+--     program may call other api routines to obtain components of the
+--     problem instance from the translator database.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_generate(MPL *mpl, char *file)
+{     if (!(mpl->phase == 1 || mpl->phase == 2))
+         xfault("mpl_generate: invalid call sequence\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* generate model */
+      mpl->phase = 3;
+      open_output(mpl, file);
+      generate_model(mpl);
+      flush_output(mpl);
+      /* build problem instance */
+      build_problem(mpl);
+      /* generation phase has been finished */
+      xprintf("Model has been successfully generated\n");
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_prob_name - obtain problem (model) name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_prob_name(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_prob_name returns a pointer to internal buffer,
+-- which contains symbolic name of the problem (model).
+--
+-- *Note*
+--
+-- Currently MathProg has no feature to assign a symbolic name to the
+-- model. Therefore the routine mpl_get_prob_name tries to construct
+-- such name using the name of input text file containing model section,
+-- although this is not a good idea (due to portability problems). */
+
+char *mpl_get_prob_name(MPL *mpl)
+{     char *name = mpl->mpl_buf;
+      char *file = mpl->mod_file;
+      int k;
+      if (mpl->phase != 3)
+         xfault("mpl_get_prob_name: invalid call sequence\n");
+      for (;;)
+      {  if (strchr(file, '/') != NULL)
+            file = strchr(file, '/') + 1;
+         else if (strchr(file, '\\') != NULL)
+            file = strchr(file, '\\') + 1;
+         else if (strchr(file, ':') != NULL)
+            file = strchr(file, ':') + 1;
+         else
+            break;
+      }
+      for (k = 0; ; k++)
+      {  if (k == 255) break;
+         if (!(isalnum((unsigned char)*file) || *file == '_')) break;
+         name[k] = *file++;
+      }
+      if (k == 0)
+         strcpy(name, "Unknown");
+      else
+         name[k] = '\0';
+      xassert(strlen(name) <= 255);
+      return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_num_rows - determine number of rows.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_num_rows(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_num_rows returns total number of rows in the
+-- problem, where each row is an individual constraint or objective. */
+
+int mpl_get_num_rows(MPL *mpl)
+{     if (mpl->phase != 3)
+         xfault("mpl_get_num_rows: invalid call sequence\n");
+      return mpl->m;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_num_cols - determine number of columns.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_num_cols(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_num_cols returns total number of columns in the
+-- problem, where each column is an individual variable. */
+
+int mpl_get_num_cols(MPL *mpl)
+{     if (mpl->phase != 3)
+         xfault("mpl_get_num_cols: invalid call sequence\n");
+      return mpl->n;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_name - obtain row name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_row_name(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_name returns a pointer to internal buffer,
+-- which contains symbolic name of i-th row of the problem. */
+
+char *mpl_get_row_name(MPL *mpl, int i)
+{     char *name = mpl->mpl_buf, *t;
+      int len;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_name: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_name: i = %d; row number out of range\n",
+            i);
+      strcpy(name, mpl->row[i]->con->name);
+      len = strlen(name);
+      xassert(len <= 255);
+      t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple);
+      while (*t)
+      {  if (len == 255) break;
+         name[len++] = *t++;
+      }
+      name[len] = '\0';
+      if (len == 255) strcpy(name+252, "...");
+      xassert(strlen(name) <= 255);
+      return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_kind - determine row kind.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_row_kind(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_kind returns the kind of i-th row, which can
+-- be one of the following:
+--
+-- MPL_ST  - non-free (constraint) row;
+-- MPL_MIN - free (objective) row to be minimized;
+-- MPL_MAX - free (objective) row to be maximized. */
+
+int mpl_get_row_kind(MPL *mpl, int i)
+{     int kind;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_kind: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_kind: i = %d; row number out of range\n",
+            i);
+      switch (mpl->row[i]->con->type)
+      {  case A_CONSTRAINT:
+            kind = MPL_ST; break;
+         case A_MINIMIZE:
+            kind = MPL_MIN; break;
+         case A_MAXIMIZE:
+            kind = MPL_MAX; break;
+         default:
+            xassert(mpl != mpl);
+      }
+      return kind;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_bnds - obtain row bounds.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
+--
+-- *Description*
+--
+-- The routine mpl_get_row_bnds stores lower and upper bounds of i-th
+-- row of the problem to the locations, which the parameters lb and ub
+-- point to, respectively. Besides the routine returns the type of the
+-- i-th row.
+--
+-- If some of the parameters lb and ub is NULL, the corresponding bound
+-- value is not stored.
+--
+-- Types and bounds have the following meaning:
+--
+--     Type           Bounds          Note
+--    -----------------------------------------------------------
+--    MPL_FR   -inf <  f(x) <  +inf   Free linear form
+--    MPL_LO     lb <= f(x) <  +inf   Inequality f(x) >= lb
+--    MPL_UP   -inf <  f(x) <=  ub    Inequality f(x) <= ub
+--    MPL_DB     lb <= f(x) <=  ub    Inequality lb <= f(x) <= ub
+--    MPL_FX           f(x)  =  lb    Equality f(x) = lb
+--
+-- where f(x) is the corresponding linear form of the i-th row.
+--
+-- If the row has no lower bound, *lb is set to zero; if the row has
+-- no upper bound, *ub is set to zero; and if the row is of fixed type,
+-- both *lb and *ub are set to the same value.
+--
+-- *Returns*
+--
+-- The routine returns the type of the i-th row as it is stated in the
+-- table above. */
+
+int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub)
+{     ELEMCON *con;
+      int type;
+      double lb, ub;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_bnds: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_bnds: i = %d; row number out of range\n",
+            i);
+      con = mpl->row[i];
+#if 0 /* 21/VII-2006 */
+      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (con->con->ubnd == NULL)
+         type = MPL_LO, lb = con->lbnd, ub = 0.0;
+      else if (con->con->lbnd == NULL)
+         type = MPL_UP, lb = 0.0, ub = con->ubnd;
+      else if (con->con->lbnd != con->con->ubnd)
+         type = MPL_DB, lb = con->lbnd, ub = con->ubnd;
+      else
+         type = MPL_FX, lb = ub = con->lbnd;
+#else
+      lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd);
+      ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd);
+      if (lb == -DBL_MAX && ub == +DBL_MAX)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (ub == +DBL_MAX)
+         type = MPL_LO, ub = 0.0;
+      else if (lb == -DBL_MAX)
+         type = MPL_UP, lb = 0.0;
+      else if (con->con->lbnd != con->con->ubnd)
+         type = MPL_DB;
+      else
+         type = MPL_FX;
+#endif
+      if (_lb != NULL) *_lb = lb;
+      if (_ub != NULL) *_ub = ub;
+      return type;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_mat_row - obtain row of the constraint matrix.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
+--
+-- *Description*
+--
+-- The routine mpl_get_mat_row stores column indices and numeric values
+-- of constraint coefficients for the i-th row to locations ndx[1], ...,
+-- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
+-- is number of (structural) non-zero constraint coefficients, and n is
+-- number of columns in the problem.
+--
+-- If the parameter ndx is NULL, column indices are not stored. If the
+-- parameter val is NULL, numeric values are not stored.
+--
+-- Note that free rows may have constant terms, which are not part of
+-- the constraint matrix and therefore not reported by this routine. The
+-- constant term of a particular row can be obtained, if necessary, via
+-- the routine mpl_get_row_c0.
+--
+-- *Returns*
+--
+-- The routine mpl_get_mat_row returns len, which is length of i-th row
+-- of the constraint matrix (i.e. number of non-zero coefficients). */
+
+int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[])
+{     FORMULA *term;
+      int len = 0;
+      if (mpl->phase != 3)
+         xfault("mpl_get_mat_row: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_mat_row: i = %d; row number out of range\n",
+            i);
+      for (term = mpl->row[i]->form; term != NULL; term = term->next)
+      {  xassert(term->var != NULL);
+         len++;
+         xassert(len <= mpl->n);
+         if (ndx != NULL) ndx[len] = term->var->j;
+         if (val != NULL) val[len] = term->coef;
+      }
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_c0 - obtain constant term of free row.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- double mpl_get_row_c0(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_c0 returns numeric value of constant term of
+-- i-th row.
+--
+-- Note that only free rows may have non-zero constant terms. Therefore
+-- if i-th row is not free, the routine returns zero. */
+
+double mpl_get_row_c0(MPL *mpl, int i)
+{     ELEMCON *con;
+      double c0;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_c0: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_c0: i = %d; row number out of range\n",
+            i);
+      con = mpl->row[i];
+      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
+         c0 = - con->lbnd;
+      else
+         c0 = 0.0;
+      return c0;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_name - obtain column name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_col_name(MPL *mpl, int j);
+--
+-- *Returns*
+--
+-- The routine mpl_get_col_name returns a pointer to internal buffer,
+-- which contains symbolic name of j-th column of the problem. */
+
+char *mpl_get_col_name(MPL *mpl, int j)
+{     char *name = mpl->mpl_buf, *t;
+      int len;
+      if (mpl->phase != 3)
+         xfault("mpl_get_col_name: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault("mpl_get_col_name: j = %d; column number out of range\n"
+            , j);
+      strcpy(name, mpl->col[j]->var->name);
+      len = strlen(name);
+      xassert(len <= 255);
+      t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple);
+      while (*t)
+      {  if (len == 255) break;
+         name[len++] = *t++;
+      }
+      name[len] = '\0';
+      if (len == 255) strcpy(name+252, "...");
+      xassert(strlen(name) <= 255);
+      return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_kind - determine column kind.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_col_kind(MPL *mpl, int j);
+--
+-- *Returns*
+--
+-- The routine mpl_get_col_kind returns the kind of j-th column, which
+-- can be one of the following:
+--
+-- MPL_NUM - continuous variable;
+-- MPL_INT - integer variable;
+-- MPL_BIN - binary variable.
+--
+-- Note that column kinds are defined independently on type and bounds
+-- (reported by the routine mpl_get_col_bnds) of corresponding columns.
+-- This means, in particular, that bounds of an integer column may be
+-- fractional, or a binary column may have lower and upper bounds that
+-- are not 0 and 1 (or it may have no lower/upper bound at all). */
+
+int mpl_get_col_kind(MPL *mpl, int j)
+{     int kind;
+      if (mpl->phase != 3)
+         xfault("mpl_get_col_kind: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault("mpl_get_col_kind: j = %d; column number out of range\n"
+            , j);
+      switch (mpl->col[j]->var->type)
+      {  case A_NUMERIC:
+            kind = MPL_NUM; break;
+         case A_INTEGER:
+            kind = MPL_INT; break;
+         case A_BINARY:
+            kind = MPL_BIN; break;
+         default:
+            xassert(mpl != mpl);
+      }
+      return kind;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_bnds - obtain column bounds.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
+--
+-- *Description*
+--
+-- The routine mpl_get_col_bnds stores lower and upper bound of j-th
+-- column of the problem to the locations, which the parameters lb and
+-- ub point to, respectively. Besides the routine returns the type of
+-- the j-th column.
+--
+-- If some of the parameters lb and ub is NULL, the corresponding bound
+-- value is not stored.
+--
+-- Types and bounds have the following meaning:
+--
+--     Type         Bounds         Note
+--    ------------------------------------------------------
+--    MPL_FR   -inf <  x <  +inf   Free (unbounded) variable
+--    MPL_LO     lb <= x <  +inf   Variable with lower bound
+--    MPL_UP   -inf <  x <=  ub    Variable with upper bound
+--    MPL_DB     lb <= x <=  ub    Double-bounded variable
+--    MPL_FX           x  =  lb    Fixed variable
+--
+-- where x is individual variable corresponding to the j-th column.
+--
+-- If the column has no lower bound, *lb is set to zero; if the column
+-- has no upper bound, *ub is set to zero; and if the column is of fixed
+-- type, both *lb and *ub are set to the same value.
+--
+-- *Returns*
+--
+-- The routine returns the type of the j-th column as it is stated in
+-- the table above. */
+
+int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub)
+{     ELEMVAR *var;
+      int type;
+      double lb, ub;
+      if (mpl->phase != 3)
+         xfault("mpl_get_col_bnds: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault("mpl_get_col_bnds: j = %d; column number out of range\n"
+            , j);
+      var = mpl->col[j];
+#if 0 /* 21/VII-2006 */
+      if (var->var->lbnd == NULL && var->var->ubnd == NULL)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (var->var->ubnd == NULL)
+         type = MPL_LO, lb = var->lbnd, ub = 0.0;
+      else if (var->var->lbnd == NULL)
+         type = MPL_UP, lb = 0.0, ub = var->ubnd;
+      else if (var->var->lbnd != var->var->ubnd)
+         type = MPL_DB, lb = var->lbnd, ub = var->ubnd;
+      else
+         type = MPL_FX, lb = ub = var->lbnd;
+#else
+      lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd);
+      ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd);
+      if (lb == -DBL_MAX && ub == +DBL_MAX)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (ub == +DBL_MAX)
+         type = MPL_LO, ub = 0.0;
+      else if (lb == -DBL_MAX)
+         type = MPL_UP, lb = 0.0;
+      else if (var->var->lbnd != var->var->ubnd)
+         type = MPL_DB;
+      else
+         type = MPL_FX;
+#endif
+      if (_lb != NULL) *_lb = lb;
+      if (_ub != NULL) *_ub = ub;
+      return type;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_has_solve_stmt - check if model has solve statement.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_has_solve_stmt(MPL *mpl);
+--
+-- *Returns*
+--
+-- If the model has the solve statement, the routine returns non-zero,
+-- otherwise zero is returned. */
+
+int mpl_has_solve_stmt(MPL *mpl)
+{     if (mpl->phase != 3)
+         xfault("mpl_has_solve_stmt: invalid call sequence\n");
+      return mpl->flag_s;
+}
+
+#if 1 /* 15/V-2010 */
+void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
+      double dual)
+{     /* store row (constraint/objective) solution components */
+      xassert(mpl->phase == 3);
+      xassert(1 <= i && i <= mpl->m);
+      mpl->row[i]->stat = stat;
+      mpl->row[i]->prim = prim;
+      mpl->row[i]->dual = dual;
+      return;
+}
+#endif
+
+#if 1 /* 15/V-2010 */
+void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
+      double dual)
+{     /* store column (variable) solution components */
+      xassert(mpl->phase == 3);
+      xassert(1 <= j && j <= mpl->n);
+      mpl->col[j]->stat = stat;
+      mpl->col[j]->prim = prim;
+      mpl->col[j]->dual = dual;
+      return;
+}
+#endif
+
+#if 0 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- mpl_put_col_value - store column value.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- void mpl_put_col_value(MPL *mpl, int j, double val);
+--
+-- *Description*
+--
+-- The routine mpl_put_col_value stores numeric value of j-th column
+-- into the translator database. It is assumed that the column value is
+-- provided by the solver. */
+
+void mpl_put_col_value(MPL *mpl, int j, double val)
+{     if (mpl->phase != 3)
+         xfault("mpl_put_col_value: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault(
+         "mpl_put_col_value: j = %d; column number out of range\n", j);
+      mpl->col[j]->prim = val;
+      return;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- mpl_postsolve - postsolve model.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_postsolve(MPL *mpl);
+--
+-- *Description*
+--
+-- The routine mpl_postsolve performs postsolving of the model using
+-- its description stored in the translator database. This phase means
+-- executing statements, which follow the solve statement.
+--
+-- If this routine is used, it should be called once after the routine
+-- mpl_generate and if the latter returned the code 3.
+--
+-- *Returns*
+--
+-- The routine mpl_postsolve returns one of the following codes:
+--
+-- 3 - model has been successfully postsolved.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_postsolve(MPL *mpl)
+{     if (!(mpl->phase == 3 && !mpl->flag_p))
+         xfault("mpl_postsolve: invalid call sequence\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* perform postsolving */
+      postsolve_model(mpl);
+      flush_output(mpl);
+      /* postsolving phase has been finished */
+      xprintf("Model has been successfully processed\n");
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_terminate - free all resources used by translator.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- void mpl_terminate(MPL *mpl);
+--
+-- *Description*
+--
+-- The routine mpl_terminate frees all the resources used by the GNU
+-- MathProg translator. */
+
+void mpl_terminate(MPL *mpl)
+{     if (setjmp(mpl->jump)) xassert(mpl != mpl);
+      switch (mpl->phase)
+      {  case 0:
+         case 1:
+         case 2:
+         case 3:
+            /* there were no errors; clean the model content */
+            clean_model(mpl);
+            xassert(mpl->a_list == NULL);
+#if 1 /* 11/II-2008 */
+            xassert(mpl->dca == NULL);
+#endif
+            break;
+         case 4:
+            /* model processing has been finished due to error; delete
+               search trees, which may be created for some arrays */
+            {  ARRAY *a;
+               for (a = mpl->a_list; a != NULL; a = a->next)
+                  if (a->tree != NULL) avl_delete_tree(a->tree);
+            }
+#if 1 /* 11/II-2008 */
+            free_dca(mpl);
+#endif
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      /* delete the translator database */
+      xfree(mpl->image);
+      xfree(mpl->b_image);
+      xfree(mpl->f_image);
+      xfree(mpl->context);
+      dmp_delete_pool(mpl->pool);
+      avl_delete_tree(mpl->tree);
+      dmp_delete_pool(mpl->strings);
+      dmp_delete_pool(mpl->symbols);
+      dmp_delete_pool(mpl->tuples);
+      dmp_delete_pool(mpl->arrays);
+      dmp_delete_pool(mpl->members);
+      dmp_delete_pool(mpl->elemvars);
+      dmp_delete_pool(mpl->formulae);
+      dmp_delete_pool(mpl->elemcons);
+      xfree(mpl->sym_buf);
+      xfree(mpl->tup_buf);
+      rng_delete_rand(mpl->rand);
+      if (mpl->row != NULL) xfree(mpl->row);
+      if (mpl->col != NULL) xfree(mpl->col);
+      if (mpl->in_fp != NULL) xfclose(mpl->in_fp);
+      if (mpl->out_fp != NULL /* && mpl->out_fp != (void *)stdout */)
+         xfclose(mpl->out_fp);
+      if (mpl->out_file != NULL) xfree(mpl->out_file);
+      if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp);
+      if (mpl->prt_file != NULL) xfree(mpl->prt_file);
+      if (mpl->mod_file != NULL) xfree(mpl->mod_file);
+      xfree(mpl->mpl_buf);
+      xfree(mpl);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmpl05.c b/optional/glpk/glpmpl05.c
new file mode 100644
index 0000000..e909429
--- /dev/null
+++ b/optional/glpk/glpmpl05.c
@@ -0,0 +1,566 @@
+/* glpmpl05.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Authors: Andrew Makhorin <mao at gnu.org>
+*           Heinrich Schuchardt <xypron.glpk at gmx.de>
+*
+*  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"
+#endif
+
+#define _GLPSTD_STDIO
+#define _GLPSTD_TIME
+#include "glpmpl.h"
+
+double fn_gmtime(MPL *mpl)
+{     /* obtain the current calendar time (UTC) */
+      time_t timer;
+      struct tm *tm;
+      int j;
+      time(&timer);
+      if (timer == (time_t)(-1))
+err:     error(mpl, "gmtime(); unable to obtain current calendar time");
+      tm = gmtime(&timer);
+      if (tm == NULL) goto err;
+      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+      if (j < 0) goto err;
+      return (((double)(j - jday(1, 1, 1970)) * 24.0 +
+         (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
+         (double)tm->tm_sec;
+}
+
+static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
+      "Friday", "Saturday", "Sunday" };
+
+static char *moon[] = { "January", "February", "March", "April", "May",
+      "June", "July", "August", "September", "October", "November",
+      "December" };
+
+static void error1(MPL *mpl, const char *str, const char *s,
+      const char *fmt, const char *f, const char *msg)
+{     xprintf("Input string passed to str2time:\n");
+      xprintf("%s\n", str);
+      xprintf("%*s\n", (s - str) + 1, "^");
+      xprintf("Format string passed to str2time:\n");
+      xprintf("%s\n", fmt);
+      xprintf("%*s\n", (f - fmt) + 1, "^");
+      error(mpl, "%s", msg);
+      /* no return */
+}
+
+double fn_str2time(MPL *mpl, const char *str, const char *fmt)
+{     /* convert character string to the calendar time */
+      int j, year, month, day, hh, mm, ss, zone;
+      const char *s, *f;
+      year = month = day = hh = mm = ss = -1, zone = INT_MAX;
+      s = str;
+      for (f = fmt; *f != '\0'; f++)
+      {  if (*f == '%')
+         {  f++;
+            if (*f == 'b' || *f == 'h')
+            {  /* the abbreviated month name */
+               int k;
+               char *name;
+               if (month >= 0)
+                  error1(mpl, str, s, fmt, f, "month multiply specified"
+                     );
+               while (*s == ' ') s++;
+               for (month = 1; month <= 12; month++)
+               {  name = moon[month-1];
+                  for (k = 0; k <= 2; k++)
+                  {  if (toupper((unsigned char)s[k]) !=
+                         toupper((unsigned char)name[k])) goto next;
+                  }
+                  s += 3;
+                  for (k = 3; name[k] != '\0'; k++)
+                  {  if (toupper((unsigned char)*s) !=
+                         toupper((unsigned char)name[k])) break;
+                     s++;
+                  }
+                  break;
+next:             ;
+               }
+               if (month > 12)
+                  error1(mpl, str, s, fmt, f, "abbreviated month name m"
+                     "issing or invalid");
+            }
+            else if (*f == 'd')
+            {  /* the day of the month as a decimal number (01..31) */
+               if (day >= 0)
+                  error1(mpl, str, s, fmt, f, "day multiply specified");
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "day missing or invalid");
+               day = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  day = 10 * day + ((*s++) - '0');
+               if (!(1 <= day && day <= 31))
+                  error1(mpl, str, s, fmt, f, "day out of range");
+            }
+            else if (*f == 'H')
+            {  /* the hour as a decimal number, using a 24-hour clock
+                  (00..23) */
+               if (hh >= 0)
+                  error1(mpl, str, s, fmt, f, "hour multiply specified")
+                     ;
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "hour missing or invalid")
+                     ;
+               hh = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  hh = 10 * hh + ((*s++) - '0');
+               if (!(0 <= hh && hh <= 23))
+                  error1(mpl, str, s, fmt, f, "hour out of range");
+            }
+            else if (*f == 'm')
+            {  /* the month as a decimal number (01..12) */
+               if (month >= 0)
+                  error1(mpl, str, s, fmt, f, "month multiply specified"
+                     );
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "month missing or invalid"
+                     );
+               month = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  month = 10 * month + ((*s++) - '0');
+               if (!(1 <= month && month <= 12))
+                  error1(mpl, str, s, fmt, f, "month out of range");
+            }
+            else if (*f == 'M')
+            {  /* the minute as a decimal number (00..59) */
+               if (mm >= 0)
+                  error1(mpl, str, s, fmt, f, "minute multiply specifie"
+                     "d");
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "minute missing or invali"
+                     "d");
+               mm = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  mm = 10 * mm + ((*s++) - '0');
+               if (!(0 <= mm && mm <= 59))
+                  error1(mpl, str, s, fmt, f, "minute out of range");
+            }
+            else if (*f == 'S')
+            {  /* the second as a decimal number (00..60) */
+               if (ss >= 0)
+                  error1(mpl, str, s, fmt, f, "second multiply specifie"
+                     "d");
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "second missing or invali"
+                     "d");
+               ss = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  ss = 10 * ss + ((*s++) - '0');
+               if (!(0 <= ss && ss <= 60))
+                  error1(mpl, str, s, fmt, f, "second out of range");
+            }
+            else if (*f == 'y')
+            {  /* the year without a century as a decimal number
+                  (00..99); the values 00 to 68 mean the years 2000 to
+                  2068 while the values 69 to 99 mean the years 1969 to
+                  1999 */
+               if (year >= 0)
+                  error1(mpl, str, s, fmt, f, "year multiply specified")
+                     ;
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "year missing or invalid")
+                     ;
+               year = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  year = 10 * year + ((*s++) - '0');
+               year += (year >= 69 ? 1900 : 2000);
+            }
+            else if (*f == 'Y')
+            {  /* the year as a decimal number, using the Gregorian
+                  calendar */
+               if (year >= 0)
+                  error1(mpl, str, s, fmt, f, "year multiply specified")
+                     ;
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "year missing or invalid")
+                     ;
+               year = 0;
+               for (j = 1; j <= 4; j++)
+               {  if (!('0' <= *s && *s <= '9')) break;
+                  year = 10 * year + ((*s++) - '0');
+               }
+               if (!(1 <= year && year <= 4000))
+                  error1(mpl, str, s, fmt, f, "year out of range");
+            }
+            else if (*f == 'z')
+            {  /* time zone offset in the form zhhmm */
+               int z, hh, mm;
+               if (zone != INT_MAX)
+                  error1(mpl, str, s, fmt, f, "time zone offset multipl"
+                     "y specified");
+               while (*s == ' ') s++;
+               if (*s == 'Z')
+               {  z = hh = mm = 0, s++;
+                  goto skip;
+               }
+               if (*s == '+')
+                  z = +1, s++;
+               else if (*s == '-')
+                  z = -1, s++;
+               else
+                  error1(mpl, str, s, fmt, f, "time zone offset sign mi"
+                     "ssing");
+               hh = 0;
+               for (j = 1; j <= 2; j++)
+               {  if (!('0' <= *s && *s <= '9'))
+err1:                error1(mpl, str, s, fmt, f, "time zone offset valu"
+                        "e incomplete or invalid");
+                  hh = 10 * hh + ((*s++) - '0');
+               }
+               if (hh > 23)
+err2:             error1(mpl, str, s, fmt, f, "time zone offset value o"
+                     "ut of range");
+               if (*s == ':')
+               {  s++;
+                  if (!('0' <= *s && *s <= '9')) goto err1;
+               }
+               mm = 0;
+               if (!('0' <= *s && *s <= '9')) goto skip;
+               for (j = 1; j <= 2; j++)
+               {  if (!('0' <= *s && *s <= '9')) goto err1;
+                  mm = 10 * mm + ((*s++) - '0');
+               }
+               if (mm > 59) goto err2;
+skip:          zone = z * (60 * hh + mm);
+            }
+            else if (*f == '%')
+            {  /* literal % character */
+               goto test;
+            }
+            else
+               error1(mpl, str, s, fmt, f, "invalid conversion specifie"
+                  "r");
+         }
+         else if (*f == ' ')
+            ;
+         else
+test:    {  /* check a matching character in the input string */
+            if (*s != *f)
+               error1(mpl, str, s, fmt, f, "character mismatch");
+            s++;
+         }
+      }
+      if (year < 0) year = 1970;
+      if (month < 0) month = 1;
+      if (day < 0) day = 1;
+      if (hh < 0) hh = 0;
+      if (mm < 0) mm = 0;
+      if (ss < 0) ss = 0;
+      if (zone == INT_MAX) zone = 0;
+      j = jday(day, month, year);
+      xassert(j >= 0);
+      return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
+         60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
+}
+
+static void error2(MPL *mpl, const char *fmt, const char *f,
+      const char *msg)
+{     xprintf("Format string passed to time2str:\n");
+      xprintf("%s\n", fmt);
+      xprintf("%*s\n", (f - fmt) + 1, "^");
+      error(mpl, "%s", msg);
+      /* no return */
+}
+
+static int weekday(int j)
+{     /* determine weekday number (1 = Mon, ..., 7 = Sun) */
+      return (j + jday(1, 1, 1970)) % 7 + 1;
+}
+
+static int firstday(int year)
+{     /* determine the first day of the first week for a specified year
+         according to ISO 8601 */
+      int j;
+      /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
+         in week 01; if 1 January is Friday, Saturday or Sunday, it is
+         in week 52 or 53 of the previous year */
+      j = jday(1, 1, year) - jday(1, 1, 1970);
+      switch (weekday(j))
+      {  case 1: /* 1 Jan is Mon */ j += 0; break;
+         case 2: /* 1 Jan is Tue */ j -= 1; break;
+         case 3: /* 1 Jan is Wed */ j -= 2; break;
+         case 4: /* 1 Jan is Thu */ j -= 3; break;
+         case 5: /* 1 Jan is Fri */ j += 3; break;
+         case 6: /* 1 Jan is Sat */ j += 2; break;
+         case 7: /* 1 Jan is Sun */ j += 1; break;
+         default: xassert(j != j);
+      }
+      /* the first day of the week must be Monday */
+      xassert(weekday(j) == 1);
+      return j;
+}
+
+void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
+{     /* convert the calendar time to character string */
+      int j, year, month, day, hh, mm, ss, len;
+      double temp;
+      const char *f;
+      char buf[MAX_LENGTH+1];
+      if (!(-62135596800.0 <= t && t <= 64092211199.0))
+         error(mpl, "time2str(%.*g,...); argument out of range",
+            DBL_DIG, t);
+      t = floor(t + 0.5);
+      temp = fabs(t) / 86400.0;
+      j = (int)floor(temp);
+      if (t < 0.0)
+      {  if (temp == floor(temp))
+            j = - j;
+         else
+            j = - (j + 1);
+      }
+      xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
+      ss = (int)(t - 86400.0 * (double)j);
+      xassert(0 <= ss && ss < 86400);
+      mm = ss / 60, ss %= 60;
+      hh = mm / 60, mm %= 60;
+      len = 0;
+      for (f = fmt; *f != '\0'; f++)
+      {  if (*f == '%')
+         {  f++;
+            if (*f == 'a')
+            {  /* the abbreviated weekday name */
+               memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
+            }
+            else if (*f == 'A')
+            {  /* the full weekday name */
+               strcpy(buf, week[weekday(j)-1]);
+            }
+            else if (*f == 'b' || *f == 'h')
+            {  /* the abbreviated month name */
+               memcpy(buf, moon[month-1], 3), buf[3] = '\0';
+            }
+            else if (*f == 'B')
+            {  /* the full month name */
+               strcpy(buf, moon[month-1]);
+            }
+            else if (*f == 'C')
+            {  /* the century of the year */
+               sprintf(buf, "%02d", year / 100);
+            }
+            else if (*f == 'd')
+            {  /* the day of the month as a decimal number (01..31) */
+               sprintf(buf, "%02d", day);
+            }
+            else if (*f == 'D')
+            {  /* the date using the format %m/%d/%y */
+               sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
+            }
+            else if (*f == 'e')
+            {  /* the day of the month like with %d, but padded with
+                  blank (1..31) */
+               sprintf(buf, "%2d", day);
+            }
+            else if (*f == 'F')
+            {  /* the date using the format %Y-%m-%d */
+               sprintf(buf, "%04d-%02d-%02d", year, month, day);
+            }
+            else if (*f == 'g')
+            {  /* the year corresponding to the ISO week number, but
+                  without the century (range 00 through 99); this has
+                  the same format and value as %y, except that if the
+                  ISO week number (see %V) belongs to the previous or
+                  next year, that year is used instead */
+               int iso;
+               if (j < firstday(year))
+                  iso = year - 1;
+               else if (j < firstday(year + 1))
+                  iso = year;
+               else
+                  iso = year + 1;
+               sprintf(buf, "%02d", iso % 100);
+            }
+            else if (*f == 'G')
+            {  /* the year corresponding to the ISO week number; this
+                  has the same format and value as %Y, excepth that if
+                  the ISO week number (see %V) belongs to the previous
+                  or next year, that year is used instead */
+               int iso;
+               if (j < firstday(year))
+                  iso = year - 1;
+               else if (j < firstday(year + 1))
+                  iso = year;
+               else
+                  iso = year + 1;
+               sprintf(buf, "%04d", iso);
+            }
+            else if (*f == 'H')
+            {  /* the hour as a decimal number, using a 24-hour clock
+                  (00..23) */
+               sprintf(buf, "%02d", hh);
+            }
+            else if (*f == 'I')
+            {  /* the hour as a decimal number, using a 12-hour clock
+                  (01..12) */
+               sprintf(buf, "%02d",
+                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
+            }
+            else if (*f == 'j')
+            {  /* the day of the year as a decimal number (001..366) */
+               sprintf(buf, "%03d",
+                  jday(day, month, year) - jday(1, 1, year) + 1);
+            }
+            else if (*f == 'k')
+            {  /* the hour as a decimal number, using a 24-hour clock
+                  like %H, but padded with blank (0..23) */
+               sprintf(buf, "%2d", hh);
+            }
+            else if (*f == 'l')
+            {  /* the hour as a decimal number, using a 12-hour clock
+                  like %I, but padded with blank (1..12) */
+               sprintf(buf, "%2d",
+                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
+            }
+            else if (*f == 'm')
+            {  /* the month as a decimal number (01..12) */
+               sprintf(buf, "%02d", month);
+            }
+            else if (*f == 'M')
+            {  /* the minute as a decimal number (00..59) */
+               sprintf(buf, "%02d", mm);
+            }
+            else if (*f == 'p')
+            {  /* either AM or PM, according to the given time value;
+                  noon is treated as PM and midnight as AM */
+               strcpy(buf, hh <= 11 ? "AM" : "PM");
+            }
+            else if (*f == 'P')
+            {  /* either am or pm, according to the given time value;
+                  noon is treated as pm and midnight as am */
+               strcpy(buf, hh <= 11 ? "am" : "pm");
+            }
+            else if (*f == 'r')
+            {  /* the calendar time using the format %I:%M:%S %p */
+               sprintf(buf, "%02d:%02d:%02d %s",
+                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
+                  mm, ss, hh <= 11 ? "AM" : "PM");
+            }
+            else if (*f == 'R')
+            {  /* the hour and minute using the format %H:%M */
+               sprintf(buf, "%02d:%02d", hh, mm);
+            }
+            else if (*f == 'S')
+            {  /* the second as a decimal number (00..59) */
+               sprintf(buf, "%02d", ss);
+            }
+            else if (*f == 'T')
+            {  /* the time of day using the format %H:%M:%S */
+               sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
+            }
+            else if (*f == 'u')
+            {  /* the day of the week as a decimal number (1..7),
+                  Monday being 1 */
+               sprintf(buf, "%d", weekday(j));
+            }
+            else if (*f == 'U')
+            {  /* the week number of the current year as a decimal
+                  number (range 00 through 53), starting with the first
+                  Sunday as the first day of the first week; days
+                  preceding the first Sunday in the year are considered
+                  to be in week 00 */
+#if 1 /* 09/I-2009 */
+#undef sun
+/* causes compilation error in SunOS */
+#endif
+               int sun;
+               /* sun = the first Sunday of the year */
+               sun = jday(1, 1, year) - jday(1, 1, 1970);
+               sun += (7 - weekday(sun));
+               sprintf(buf, "%02d", (j + 7 - sun) / 7);
+            }
+            else if (*f == 'V')
+            {  /* the ISO week number as a decimal number (range 01
+                  through 53); ISO weeks start with Monday and end with
+                  Sunday; week 01 of a year is the first week which has
+                  the majority of its days in that year; week 01 of
+                  a year can contain days from the previous year; the
+                  week before week 01 of a year is the last week (52 or
+                  53) of the previous year even if it contains days
+                  from the new year */
+               int iso;
+               if (j < firstday(year))
+                  iso = j - firstday(year - 1);
+               else if (j < firstday(year + 1))
+                  iso = j - firstday(year);
+               else
+                  iso = j - firstday(year + 1);
+               sprintf(buf, "%02d", iso / 7 + 1);
+            }
+            else if (*f == 'w')
+            {  /* the day of the week as a decimal number (0..6),
+                  Sunday being 0 */
+               sprintf(buf, "%d", weekday(j) % 7);
+            }
+            else if (*f == 'W')
+            {  /* the week number of the current year as a decimal
+                  number (range 00 through 53), starting with the first
+                  Monday as the first day of the first week; days
+                  preceding the first Monday in the year are considered
+                  to be in week 00 */
+               int mon;
+               /* mon = the first Monday of the year */
+               mon = jday(1, 1, year) - jday(1, 1, 1970);
+               mon += (8 - weekday(mon)) % 7;
+               sprintf(buf, "%02d", (j + 7 - mon) / 7);
+            }
+            else if (*f == 'y')
+            {  /* the year without a century as a decimal number
+                  (00..99) */
+               sprintf(buf, "%02d", year % 100);
+            }
+            else if (*f == 'Y')
+            {  /* the year as a decimal number, using the Gregorian
+                  calendar */
+               sprintf(buf, "%04d", year);
+            }
+            else if (*f == '%')
+            {  /* a literal % character */
+               buf[0] = '%', buf[1] = '\0';
+            }
+            else
+               error2(mpl, fmt, f, "invalid conversion specifier");
+         }
+         else
+            buf[0] = *f, buf[1] = '\0';
+         if (len + strlen(buf) > MAX_LENGTH)
+            error(mpl, "time2str; output string length exceeds %d chara"
+               "cters", MAX_LENGTH);
+         memcpy(str+len, buf, strlen(buf));
+         len += strlen(buf);
+      }
+      str[len] = '\0';
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmpl06.c b/optional/glpk/glpmpl06.c
new file mode 100644
index 0000000..cf8a93b
--- /dev/null
+++ b/optional/glpk/glpmpl06.c
@@ -0,0 +1,1008 @@
+/* glpmpl06.c */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#pragma clang diagnostic ignored "-Wself-assign"
+#endif
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpmpl.h"
+#include "glpsql.h"
+
+/**********************************************************************/
+
+#define CSV_FIELD_MAX 50
+/* maximal number of fields in record */
+
+#define CSV_FDLEN_MAX 100
+/* maximal field length */
+
+struct csv
+{     /* comma-separated values file */
+      int mode;
+      /* 'R' = reading; 'W' = writing */
+      char *fname;
+      /* name of csv file */
+      FILE *fp;
+      /* stream assigned to csv file */
+      jmp_buf jump;
+      /* address for non-local go to in case of error */
+      int count;
+      /* record count */
+      /*--------------------------------------------------------------*/
+      /* used only for input csv file */
+      int c;
+      /* current character or EOF */
+      int what;
+      /* current marker: */
+#define CSV_EOF   0  /* end-of-file */
+#define CSV_EOR   1  /* end-of-record */
+#define CSV_NUM   2  /* floating-point number */
+#define CSV_STR   3  /* character string */
+      char field[CSV_FDLEN_MAX+1];
+      /* current field just read */
+      int nf;
+      /* number of fields in the csv file */
+      int ref[1+CSV_FIELD_MAX];
+      /* ref[k] = k', if k-th field of the csv file corresponds to
+         k'-th field in the table statement; if ref[k] = 0, k-th field
+         of the csv file is ignored */
+#if 1 /* 01/VI-2010 */
+      int nskip;
+      /* number of comment records preceding the header record */
+#endif
+};
+
+#undef read_char
+
+static void read_char(struct csv *csv)
+{     /* read character from csv data file */
+      int c;
+      xassert(csv->c != EOF);
+      if (csv->c == '\n') csv->count++;
+loop: c = fgetc(csv->fp);
+      if (ferror(csv->fp))
+      {  xprintf("%s:%d: read error - %s\n", csv->fname, csv->count,
+            strerror(errno));
+         longjmp(csv->jump, 0);
+      }
+      if (feof(csv->fp))
+      {  if (csv->c == '\n')
+         {  csv->count--;
+            c = EOF;
+         }
+         else
+         {  xprintf("%s:%d: warning: missing final end-of-line\n",
+               csv->fname, csv->count);
+            c = '\n';
+         }
+      }
+      else if (c == '\r')
+         goto loop;
+      else if (c == '\n')
+         ;
+      else if (iscntrl(c))
+      {  xprintf("%s:%d: invalid control character 0x%02X\n",
+            csv->fname, csv->count, c);
+         longjmp(csv->jump, 0);
+      }
+      csv->c = c;
+      return;
+}
+
+static void read_field(struct csv *csv)
+{     /* read field from csv data file */
+      /* check for end of file */
+      if (csv->c == EOF)
+      {  csv->what = CSV_EOF;
+         strcpy(csv->field, "EOF");
+         goto done;
+      }
+      /* check for end of record */
+      if (csv->c == '\n')
+      {  csv->what = CSV_EOR;
+         strcpy(csv->field, "EOR");
+         read_char(csv);
+         if (csv->c == ',')
+err1:    {  xprintf("%s:%d: empty field not allowed\n", csv->fname,
+               csv->count);
+            longjmp(csv->jump, 0);
+         }
+         if (csv->c == '\n')
+         {  xprintf("%s:%d: empty record not allowed\n", csv->fname,
+               csv->count);
+            longjmp(csv->jump, 0);
+         }
+#if 1 /* 01/VI-2010 */
+         /* skip comment records; may appear only before the very first
+            record containing field names */
+         if (csv->c == '#' && csv->count == 1)
+         {  while (csv->c == '#')
+            {  while (csv->c != '\n')
+                  read_char(csv);
+               read_char(csv);
+               csv->nskip++;
+            }
+         }
+#endif
+         goto done;
+      }
+      /* skip comma before next field */
+      if (csv->c == ',')
+         read_char(csv);
+      /* read field */
+      if (csv->c == '\'' || csv->c == '"')
+      {  /* read a field enclosed in quotes */
+         int quote = csv->c, len = 0;
+         csv->what = CSV_STR;
+         /* skip opening quote */
+         read_char(csv);
+         /* read field characters within quotes */
+         for (;;)
+         {  /* check for closing quote and read it */
+            if (csv->c == quote)
+            {  read_char(csv);
+               if (csv->c == quote)
+                  ;
+               else if (csv->c == ',' || csv->c == '\n')
+                  break;
+               else
+               {  xprintf("%s:%d: invalid field\n", csv->fname,
+                     csv->count);
+                  longjmp(csv->jump, 0);
+               }
+            }
+            /* check the current field length */
+            if (len == CSV_FDLEN_MAX)
+err2:       {  xprintf("%s:%d: field too long\n", csv->fname,
+                  csv->count);
+               longjmp(csv->jump, 0);
+            }
+            /* add the current character to the field */
+            csv->field[len++] = (char)csv->c;
+            /* read the next character */
+            read_char(csv);
+         }
+         /* the field has been read */
+         if (len == 0) goto err1;
+         csv->field[len] = '\0';
+      }
+      else
+      {  /* read a field not enclosed in quotes */
+         int len = 0;
+         double temp;
+         csv->what = CSV_NUM;
+         while (!(csv->c == ',' || csv->c == '\n'))
+         {  /* quotes within the field are not allowed */
+            if (csv->c == '\'' || csv->c == '"')
+            {  xprintf("%s:%d: invalid use of single or double quote wi"
+                  "thin field\n", csv->fname, csv->count);
+               longjmp(csv->jump, 0);
+            }
+            /* check the current field length */
+            if (len == CSV_FDLEN_MAX) goto err2;
+            /* add the current character to the field */
+            csv->field[len++] = (char)csv->c;
+            /* read the next character */
+            read_char(csv);
+         }
+         /* the field has been read */
+         if (len == 0) goto err1;
+         csv->field[len] = '\0';
+         /* check the field type */
+         if (str2num(csv->field, &temp)) csv->what = CSV_STR;
+      }
+done: return;
+}
+
+static struct csv *csv_open_file(TABDCA *dca, int mode)
+{     /* open csv data file */
+      struct csv *csv;
+      /* create control structure */
+      csv = xmalloc(sizeof(struct csv));
+      csv->mode = mode;
+      csv->fname = NULL;
+      csv->fp = NULL;
+      if (setjmp(csv->jump)) goto fail;
+      csv->count = 0;
+      csv->c = '\n';
+      csv->what = 0;
+      csv->field[0] = '\0';
+      csv->nf = 0;
+      /* try to open the csv data file */
+      if (mpl_tab_num_args(dca) < 2)
+      {  xprintf("csv_driver: file name not specified\n");
+         longjmp(csv->jump, 0);
+      }
+      csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
+      strcpy(csv->fname, mpl_tab_get_arg(dca, 2));
+      if (mode == 'R')
+      {  /* open the file for reading */
+         int k;
+         csv->fp = fopen(csv->fname, "r");
+         if (csv->fp == NULL)
+         {  xprintf("csv_driver: unable to open %s - %s\n",
+               csv->fname, strerror(errno));
+            longjmp(csv->jump, 0);
+         }
+#if 1 /* 01/VI-2010 */
+         csv->nskip = 0;
+#endif
+         /* skip fake new-line */
+         read_field(csv);
+         xassert(csv->what == CSV_EOR);
+         /* read field names */
+         xassert(csv->nf == 0);
+         for (;;)
+         {  read_field(csv);
+            if (csv->what == CSV_EOR)
+               break;
+            if (csv->what != CSV_STR)
+            {  xprintf("%s:%d: invalid field name\n", csv->fname,
+                  csv->count);
+               longjmp(csv->jump, 0);
+            }
+            if (csv->nf == CSV_FIELD_MAX)
+            {  xprintf("%s:%d: too many fields\n", csv->fname,
+                  csv->count);
+               longjmp(csv->jump, 0);
+            }
+            csv->nf++;
+            /* find corresponding field in the table statement */
+            for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+            {  if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0)
+                  break;
+            }
+            csv->ref[csv->nf] = k;
+         }
+         /* find dummy RECNO field in the table statement */
+         for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+            if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
+         csv->ref[0] = k;
+      }
+      else if (mode == 'W')
+      {  /* open the file for writing */
+         int k, nf;
+         csv->fp = fopen(csv->fname, "w");
+         if (csv->fp == NULL)
+         {  xprintf("csv_driver: unable to create %s - %s\n",
+               csv->fname, strerror(errno));
+            longjmp(csv->jump, 0);
+         }
+         /* write field names */
+         nf = mpl_tab_num_flds(dca);
+         for (k = 1; k <= nf; k++)
+            fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k),
+               k < nf ? ',' : '\n');
+         csv->count++;
+      }
+      else
+         xassert(mode != mode);
+      /* the file has been open */
+      return csv;
+fail: /* the file cannot be open */
+      if (csv->fname != NULL) xfree(csv->fname);
+      if (csv->fp != NULL) fclose(csv->fp);
+      xfree(csv);
+      return NULL;
+}
+
+static int csv_read_record(TABDCA *dca, struct csv *csv)
+{     /* read next record from csv data file */
+      int k, ret = 0;
+      xassert(csv->mode == 'R');
+      if (setjmp(csv->jump))
+      {  ret = 1;
+         goto done;
+      }
+      /* read dummy RECNO field */
+      if (csv->ref[0] > 0)
+#if 0 /* 01/VI-2010 */
+         mpl_tab_set_num(dca, csv->ref[0], csv->count-1);
+#else
+         mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1);
+#endif
+      /* read fields */
+      for (k = 1; k <= csv->nf; k++)
+      {  read_field(csv);
+         if (csv->what == CSV_EOF)
+         {  /* end-of-file reached */
+            xassert(k == 1);
+            ret = -1;
+            goto done;
+         }
+         else if (csv->what == CSV_EOR)
+         {  /* end-of-record reached */
+            int lack = csv->nf - k + 1;
+            if (lack == 1)
+               xprintf("%s:%d: one field missing\n", csv->fname,
+                  csv->count);
+            else
+               xprintf("%s:%d: %d fields missing\n", csv->fname,
+                  csv->count, lack);
+            longjmp(csv->jump, 0);
+         }
+         else if (csv->what == CSV_NUM)
+         {  /* floating-point number */
+            if (csv->ref[k] > 0)
+            {  double num;
+               xassert(str2num(csv->field, &num) == 0);
+               mpl_tab_set_num(dca, csv->ref[k], num);
+            }
+         }
+         else if (csv->what == CSV_STR)
+         {  /* character string */
+            if (csv->ref[k] > 0)
+               mpl_tab_set_str(dca, csv->ref[k], csv->field);
+         }
+         else
+            xassert(csv != csv);
+      }
+      /* now there must be NL */
+      read_field(csv);
+      xassert(csv->what != CSV_EOF);
+      if (csv->what != CSV_EOR)
+      {  xprintf("%s:%d: too many fields\n", csv->fname, csv->count);
+         longjmp(csv->jump, 0);
+      }
+done: return ret;
+}
+
+static int csv_write_record(TABDCA *dca, struct csv *csv)
+{     /* write next record to csv data file */
+      int k, nf, ret = 0;
+      const char *c;
+      xassert(csv->mode == 'W');
+      nf = mpl_tab_num_flds(dca);
+      for (k = 1; k <= nf; k++)
+      {  switch (mpl_tab_get_type(dca, k))
+         {  case 'N':
+               fprintf(csv->fp, "%.*g", DBL_DIG,
+                  mpl_tab_get_num(dca, k));
+               break;
+            case 'S':
+               fputc('"', csv->fp);
+               for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++)
+               {  if (*c == '"')
+                     fputc('"', csv->fp), fputc('"', csv->fp);
+                  else
+                     fputc(*c, csv->fp);
+               }
+               fputc('"', csv->fp);
+               break;
+            default:
+               xassert(dca != dca);
+         }
+         fputc(k < nf ? ',' : '\n', csv->fp);
+      }
+      csv->count++;
+      if (ferror(csv->fp))
+      {  xprintf("%s:%d: write error - %s\n", csv->fname, csv->count,
+            strerror(errno));
+         ret = 1;
+      }
+      return ret;
+}
+
+static int csv_close_file(TABDCA *dca, struct csv *csv)
+{     /* close csv data file */
+      int ret = 0;
+      xassert(dca == dca);
+      if (csv->mode == 'W')
+      {  fflush(csv->fp);
+         if (ferror(csv->fp))
+         {  xprintf("%s:%d: write error - %s\n", csv->fname,
+               csv->count, strerror(errno));
+            ret = 1;
+         }
+      }
+      xfree(csv->fname);
+      fclose(csv->fp);
+      xfree(csv);
+      return ret;
+}
+
+/**********************************************************************/
+
+#define DBF_FIELD_MAX 50
+/* maximal number of fields in record */
+
+#define DBF_FDLEN_MAX 100
+/* maximal field length */
+
+struct dbf
+{     /* xBASE data file */
+      int mode;
+      /* 'R' = reading; 'W' = writing */
+      char *fname;
+      /* name of xBASE file */
+      FILE *fp;
+      /* stream assigned to xBASE file */
+      jmp_buf jump;
+      /* address for non-local go to in case of error */
+      int offset;
+      /* offset of a byte to be read next */
+      int count;
+      /* record count */
+      int nf;
+      /* number of fields */
+      int ref[1+DBF_FIELD_MAX];
+      /* ref[k] = k', if k-th field of the csv file corresponds to
+         k'-th field in the table statement; if ref[k] = 0, k-th field
+         of the csv file is ignored */
+      int type[1+DBF_FIELD_MAX];
+      /* type[k] is type of k-th field */
+      int len[1+DBF_FIELD_MAX];
+      /* len[k] is length of k-th field */
+      int prec[1+DBF_FIELD_MAX];
+      /* prec[k] is precision of k-th field */
+};
+
+static int read_byte(struct dbf *dbf)
+{     /* read byte from xBASE data file */
+      int b;
+      b = fgetc(dbf->fp);
+      if (ferror(dbf->fp))
+      {  xprintf("%s:0x%X: read error - %s\n", dbf->fname,
+            dbf->offset, strerror(errno));
+         longjmp(dbf->jump, 0);
+      }
+      if (feof(dbf->fp))
+      {  xprintf("%s:0x%X: unexpected end of file\n", dbf->fname,
+            dbf->offset);
+         longjmp(dbf->jump, 0);
+      }
+      xassert(0x00 <= b && b <= 0xFF);
+      dbf->offset++;
+      return b;
+}
+
+static void read_header(TABDCA *dca, struct dbf *dbf)
+{     /* read xBASE data file header */
+      int b, j, k, recl;
+      char name[10+1];
+      /* (ignored) */
+      for (j = 1; j <= 10; j++)
+         read_byte(dbf);
+      /* length of each record, in bytes */
+      recl = read_byte(dbf);
+      recl += read_byte(dbf) << 8;
+      /* (ignored) */
+      for (j = 1; j <= 20; j++)
+         read_byte(dbf);
+      /* field descriptor array */
+      xassert(dbf->nf == 0);
+      for (;;)
+      {  /* check for end of array */
+         b = read_byte(dbf);
+         if (b == 0x0D) break;
+         if (dbf->nf == DBF_FIELD_MAX)
+         {  xprintf("%s:0x%X: too many fields\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         dbf->nf++;
+         /* field name */
+         name[0] = (char)b;
+         for (j = 1; j < 10; j++)
+         {  b = read_byte(dbf);
+            name[j] = (char)b;
+         }
+         name[10] = '\0';
+         b = read_byte(dbf);
+         if (b != 0x00)
+         {  xprintf("%s:0x%X: invalid field name\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         /* find corresponding field in the table statement */
+         for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+            if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break;
+         dbf->ref[dbf->nf] = k;
+         /* field type */
+         b = read_byte(dbf);
+         if (!(b == 'C' || b == 'N'))
+         {  xprintf("%s:0x%X: invalid field type\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         dbf->type[dbf->nf] = b;
+         /* (ignored) */
+         for (j = 1; j <= 4; j++)
+            read_byte(dbf);
+         /* field length */
+         b = read_byte(dbf);
+         if (b == 0)
+         {  xprintf("%s:0x%X: invalid field length\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         if (b > DBF_FDLEN_MAX)
+         {  xprintf("%s:0x%X: field too long\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         dbf->len[dbf->nf] = b;
+         recl -= b;
+         /* (ignored) */
+         for (j = 1; j <= 15; j++)
+            read_byte(dbf);
+      }
+      if (recl != 1)
+      {  xprintf("%s:0x%X: invalid file header\n", dbf->fname,
+            dbf->offset);
+         longjmp(dbf->jump, 0);
+      }
+      /* find dummy RECNO field in the table statement */
+      for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+         if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
+      dbf->ref[0] = k;
+      return;
+}
+
+static void parse_third_arg(TABDCA *dca, struct dbf *dbf)
+{     /* parse xBASE file format (third argument) */
+      int j, k, temp;
+      const char *arg;
+      dbf->nf = mpl_tab_num_flds(dca);
+      arg = mpl_tab_get_arg(dca, 3), j = 0;
+      for (k = 1; k <= dbf->nf; k++)
+      {  /* parse specification of k-th field */
+         if (arg[j] == '\0')
+         {  xprintf("xBASE driver: field %s: specification missing\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         /* parse field type */
+         if (arg[j] == 'C' || arg[j] == 'N')
+            dbf->type[k] = arg[j], j++;
+         else
+         {  xprintf("xBASE driver: field %s: invalid field type\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         /* check for left parenthesis */
+         if (arg[j] == '(')
+            j++;
+         else
+err:     {  xprintf("xBASE driver: field %s: invalid field format\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         /* parse field length */
+         temp = 0;
+         while (isdigit(arg[j]))
+         {  if (temp > DBF_FDLEN_MAX) break;
+            temp = 10 * temp + (arg[j] - '0'), j++;
+         }
+         if (!(1 <= temp && temp <= DBF_FDLEN_MAX))
+         {  xprintf("xBASE driver: field %s: invalid field length\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         dbf->len[k] = temp;
+         /* parse optional field precision */
+         if (dbf->type[k] == 'N' && arg[j] == ',')
+         {  j++;
+            temp = 0;
+            while (isdigit(arg[j]))
+            {  if (temp > dbf->len[k]) break;
+               temp = 10 * temp + (arg[j] - '0'), j++;
+            }
+            if (temp > dbf->len[k])
+            {  xprintf("xBASE driver: field %s: invalid field precision"
+                  "\n", mpl_tab_get_name(dca, k));
+               longjmp(dbf->jump, 0);
+            }
+            dbf->prec[k] = temp;
+         }
+         else
+            dbf->prec[k] = 0;
+         /* check for right parenthesis */
+         if (arg[j] == ')')
+            j++;
+         else
+            goto err;
+      }
+      /* ignore other specifications */
+      return;
+}
+
+static void write_byte(struct dbf *dbf, int b)
+{     /* write byte to xBASE data file */
+      fputc(b, dbf->fp);
+      dbf->offset++;
+      return;
+}
+
+static void write_header(TABDCA *dca, struct dbf *dbf)
+{     /* write xBASE data file header */
+      int j, k, temp;
+      const char *name;
+      /* version number */
+      write_byte(dbf, 0x03 /* file without DBT */);
+      /* date of last update (YYMMDD) */
+      write_byte(dbf, 70 /* 1970 */);
+      write_byte(dbf, 1 /* January */);
+      write_byte(dbf, 1 /* 1st */);
+      /* number of records (unknown so far) */
+      for (j = 1; j <= 4; j++)
+         write_byte(dbf, 0xFF);
+      /* length of the header, in bytes */
+      temp = 32 + dbf->nf * 32 + 1;
+      write_byte(dbf, temp);
+      write_byte(dbf, temp >> 8);
+      /* length of each record, in bytes */
+      temp = 1;
+      for (k = 1; k <= dbf->nf; k++)
+         temp += dbf->len[k];
+      write_byte(dbf, temp);
+      write_byte(dbf, temp >> 8);
+      /* (reserved) */
+      for (j = 1; j <= 20; j++)
+         write_byte(dbf, 0x00);
+      /* field descriptor array */
+      for (k = 1; k <= dbf->nf; k++)
+      {  /* field name (terminated by 0x00) */
+         name = mpl_tab_get_name(dca, k);
+         for (j = 0; j < 10 && name[j] != '\0'; j++)
+            write_byte(dbf, name[j]);
+         for (j = j; j < 11; j++)
+            write_byte(dbf, 0x00);
+         /* field type */
+         write_byte(dbf, dbf->type[k]);
+         /* (reserved) */
+         for (j = 1; j <= 4; j++)
+            write_byte(dbf, 0x00);
+         /* field length */
+         write_byte(dbf, dbf->len[k]);
+         /* field precision */
+         write_byte(dbf, dbf->prec[k]);
+         /* (reserved) */
+         for (j = 1; j <= 14; j++)
+            write_byte(dbf, 0x00);
+      }
+      /* end of header */
+      write_byte(dbf, 0x0D);
+      return;
+}
+
+static struct dbf *dbf_open_file(TABDCA *dca, int mode)
+{     /* open xBASE data file */
+      struct dbf *dbf;
+      /* create control structure */
+      dbf = xmalloc(sizeof(struct dbf));
+      dbf->mode = mode;
+      dbf->fname = NULL;
+      dbf->fp = NULL;
+      if (setjmp(dbf->jump)) goto fail;
+      dbf->offset = 0;
+      dbf->count = 0;
+      dbf->nf = 0;
+      /* try to open the xBASE data file */
+      if (mpl_tab_num_args(dca) < 2)
+      {  xprintf("xBASE driver: file name not specified\n");
+         longjmp(dbf->jump, 0);
+      }
+      dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
+      strcpy(dbf->fname, mpl_tab_get_arg(dca, 2));
+      if (mode == 'R')
+      {  /* open the file for reading */
+         dbf->fp = fopen(dbf->fname, "rb");
+         if (dbf->fp == NULL)
+         {  xprintf("xBASE driver: unable to open %s - %s\n",
+               dbf->fname, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+         read_header(dca, dbf);
+      }
+      else if (mode == 'W')
+      {  /* open the file for writing */
+         if (mpl_tab_num_args(dca) < 3)
+         {  xprintf("xBASE driver: file format not specified\n");
+            longjmp(dbf->jump, 0);
+         }
+         parse_third_arg(dca, dbf);
+         dbf->fp = fopen(dbf->fname, "wb");
+         if (dbf->fp == NULL)
+         {  xprintf("xBASE driver: unable to create %s - %s\n",
+               dbf->fname, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+         write_header(dca, dbf);
+      }
+      else
+         xassert(mode != mode);
+      /* the file has been open */
+      return dbf;
+fail: /* the file cannot be open */
+      if (dbf->fname != NULL) xfree(dbf->fname);
+      if (dbf->fp != NULL) fclose(dbf->fp);
+      xfree(dbf);
+      return NULL;
+}
+
+static int dbf_read_record(TABDCA *dca, struct dbf *dbf)
+{     /* read next record from xBASE data file */
+      int b, j, k, ret = 0;
+      char buf[DBF_FDLEN_MAX+1];
+      xassert(dbf->mode == 'R');
+      if (setjmp(dbf->jump))
+      {  ret = 1;
+         goto done;
+      }
+      /* check record flag */
+      b = read_byte(dbf);
+      if (b == 0x1A)
+      {  /* end of data */
+         ret = -1;
+         goto done;
+      }
+      if (b != 0x20)
+      {  xprintf("%s:0x%X: invalid record flag\n", dbf->fname,
+            dbf->offset);
+         longjmp(dbf->jump, 0);
+      }
+      /* read dummy RECNO field */
+      if (dbf->ref[0] > 0)
+         mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1);
+      /* read fields */
+      for (k = 1; k <= dbf->nf; k++)
+      {  /* read k-th field */
+         for (j = 0; j < dbf->len[k]; j++)
+            buf[j] = (char)read_byte(dbf);
+         buf[dbf->len[k]] = '\0';
+         /* set field value */
+         if (dbf->type[k] == 'C')
+         {  /* character field */
+            if (dbf->ref[k] > 0)
+               mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf));
+         }
+         else if (dbf->type[k] == 'N')
+         {  /* numeric field */
+            if (dbf->ref[k] > 0)
+            {  double num;
+               strspx(buf);
+               xassert(str2num(buf, &num) == 0);
+               mpl_tab_set_num(dca, dbf->ref[k], num);
+            }
+         }
+         else
+            xassert(dbf != dbf);
+      }
+      /* increase record count */
+      dbf->count++;
+done: return ret;
+}
+
+static int dbf_write_record(TABDCA *dca, struct dbf *dbf)
+{     /* write next record to xBASE data file */
+      int j, k, ret = 0;
+      char buf[255+1];
+      xassert(dbf->mode == 'W');
+      if (setjmp(dbf->jump))
+      {  ret = 1;
+         goto done;
+      }
+      /* record flag */
+      write_byte(dbf, 0x20);
+      xassert(dbf->nf == mpl_tab_num_flds(dca));
+      for (k = 1; k <= dbf->nf; k++)
+      {  if (dbf->type[k] == 'C')
+         {  /* character field */
+            const char *str;
+            if (mpl_tab_get_type(dca, k) == 'N')
+            {  sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+               str = buf;
+            }
+            else if (mpl_tab_get_type(dca, k) == 'S')
+               str = mpl_tab_get_str(dca, k);
+            else
+               xassert(dca != dca);
+            if ((int)strlen(str) > dbf->len[k])
+            {  xprintf("xBASE driver: field %s: cannot convert %.15s..."
+                  " to field format\n", mpl_tab_get_name(dca, k), str);
+               longjmp(dbf->jump, 0);
+            }
+            for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++)
+                write_byte(dbf, str[j]);
+            for (j = j; j < dbf->len[k]; j++)
+                write_byte(dbf, ' ');
+         }
+         else if (dbf->type[k] == 'N')
+         {  /* numeric field */
+            double num = mpl_tab_get_num(dca, k);
+            if (fabs(num) > 1e20)
+err:        {  xprintf("xBASE driver: field %s: cannot convert %g to fi"
+                  "eld format\n", mpl_tab_get_name(dca, k), num);
+               longjmp(dbf->jump, 0);
+            }
+            sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num);
+            xassert(strlen(buf) < sizeof(buf));
+            if ((int)strlen(buf) != dbf->len[k]) goto err;
+            for (j = 0; j < dbf->len[k]; j++)
+               write_byte(dbf, buf[j]);
+         }
+         else
+            xassert(dbf != dbf);
+      }
+      /* increase record count */
+      dbf->count++;
+done: return ret;
+}
+
+static int dbf_close_file(TABDCA *dca, struct dbf *dbf)
+{     /* close xBASE data file */
+      int ret = 0;
+      xassert(dca == dca);
+      if (dbf->mode == 'W')
+      {  if (setjmp(dbf->jump))
+         {  ret = 1;
+            goto skip;
+         }
+         /* end-of-file flag */
+         write_byte(dbf, 0x1A);
+         /* number of records */
+         dbf->offset = 4;
+         if (fseek(dbf->fp, dbf->offset, SEEK_SET))
+         {  xprintf("%s:0x%X: seek error - %s\n", dbf->fname,
+               dbf->offset, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+         write_byte(dbf, dbf->count);
+         write_byte(dbf, dbf->count >> 8);
+         write_byte(dbf, dbf->count >> 16);
+         write_byte(dbf, dbf->count >> 24);
+         fflush(dbf->fp);
+         if (ferror(dbf->fp))
+         {  xprintf("%s:0x%X: write error - %s\n", dbf->fname,
+               dbf->offset, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+skip:    ;
+      }
+      xfree(dbf->fname);
+      fclose(dbf->fp);
+      xfree(dbf);
+      return ret;
+}
+
+/**********************************************************************/
+
+#define TAB_CSV   1
+#define TAB_XBASE 2
+#define TAB_ODBC  3
+#define TAB_MYSQL 4
+
+void mpl_tab_drv_open(MPL *mpl, int mode)
+{     TABDCA *dca = mpl->dca;
+      xassert(dca->id == 0);
+      xassert(dca->link == NULL);
+      xassert(dca->na >= 1);
+      if (strcmp(dca->arg[1], "CSV") == 0)
+      {  dca->id = TAB_CSV;
+         dca->link = csv_open_file(dca, mode);
+      }
+      else if (strcmp(dca->arg[1], "xBASE") == 0)
+      {  dca->id = TAB_XBASE;
+         dca->link = dbf_open_file(dca, mode);
+      }
+      else if (strcmp(dca->arg[1], "ODBC") == 0 ||
+               strcmp(dca->arg[1], "iODBC") == 0)
+      {  dca->id = TAB_ODBC;
+         dca->link = db_iodbc_open(dca, mode);
+      }
+      else if (strcmp(dca->arg[1], "MySQL") == 0)
+      {  dca->id = TAB_MYSQL;
+         dca->link = db_mysql_open(dca, mode);
+      }
+      else
+         xprintf("Invalid table driver `%s'\n", dca->arg[1]);
+      if (dca->link == NULL)
+         error(mpl, "error on opening table %s",
+            mpl->stmt->u.tab->name);
+      return;
+}
+
+int mpl_tab_drv_read(MPL *mpl)
+{     TABDCA *dca = mpl->dca;
+      int ret;
+      switch (dca->id)
+      {  case TAB_CSV:
+            ret = csv_read_record(dca, dca->link);
+            break;
+         case TAB_XBASE:
+            ret = dbf_read_record(dca, dca->link);
+            break;
+         case TAB_ODBC:
+            ret = db_iodbc_read(dca, dca->link);
+            break;
+         case TAB_MYSQL:
+            ret = db_mysql_read(dca, dca->link);
+            break;
+         default:
+            xassert(dca != dca);
+      }
+      if (ret > 0)
+         error(mpl, "error on reading data from table %s",
+            mpl->stmt->u.tab->name);
+      return ret;
+}
+
+void mpl_tab_drv_write(MPL *mpl)
+{     TABDCA *dca = mpl->dca;
+      int ret;
+      switch (dca->id)
+      {  case TAB_CSV:
+            ret = csv_write_record(dca, dca->link);
+            break;
+         case TAB_XBASE:
+            ret = dbf_write_record(dca, dca->link);
+            break;
+         case TAB_ODBC:
+            ret = db_iodbc_write(dca, dca->link);
+            break;
+         case TAB_MYSQL:
+            ret = db_mysql_write(dca, dca->link);
+            break;
+         default:
+            xassert(dca != dca);
+      }
+      if (ret)
+         error(mpl, "error on writing data to table %s",
+            mpl->stmt->u.tab->name);
+      return;
+}
+
+void mpl_tab_drv_close(MPL *mpl)
+{     TABDCA *dca = mpl->dca;
+      int ret;
+      switch (dca->id)
+      {  case TAB_CSV:
+            ret = csv_close_file(dca, dca->link);
+            break;
+         case TAB_XBASE:
+            ret = dbf_close_file(dca, dca->link);
+            break;
+         case TAB_ODBC:
+            ret = db_iodbc_close(dca, dca->link);
+            break;
+         case TAB_MYSQL:
+            ret = db_mysql_close(dca, dca->link);
+            break;
+         default:
+            xassert(dca != dca);
+      }
+      dca->id = 0;
+      dca->link = NULL;
+      if (ret)
+         error(mpl, "error on closing table %s",
+            mpl->stmt->u.tab->name);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpmps.c b/optional/glpk/glpmps.c
new file mode 100644
index 0000000..07dcbfd
--- /dev/null
+++ b/optional/glpk/glpmps.c
@@ -0,0 +1,1407 @@
+/* glpmps.c (MPS format routines) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wself-assign"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_mpscp - initialize MPS format control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_mpscp(glp_mpscp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_mpscp initializes control parameters, which are
+*  used by the MPS input/output routines glp_read_mps and glp_write_mps,
+*  with default values.
+*
+*  Default values of the control parameters are stored in the glp_mpscp
+*  structure, which the parameter parm points to. */
+
+void glp_init_mpscp(glp_mpscp *parm)
+{     parm->blank = '\0';
+      parm->obj_name = NULL;
+      parm->tol_mps = 1e-12;
+      return;
+}
+
+static void check_parm(const char *func, const glp_mpscp *parm)
+{     /* check control parameters */
+      if (!(0x00 <= parm->blank && parm->blank <= 0xFF) ||
+          !(parm->blank == '\0' || isprint(parm->blank)))
+         xerror("%s: blank = 0x%02X; invalid parameter\n",
+            func, parm->blank);
+      if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255))
+         xerror("%s: obj_name = \"%.12s...\"; parameter too long\n",
+            func, parm->obj_name);
+      if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0))
+         xerror("%s: tol_mps = %g; invalid parameter\n",
+            func, parm->tol_mps);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_mps - read problem data in MPS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_mps reads problem data in MPS format from a
+*  text file.
+*
+*  The parameter fmt specifies the version of MPS format:
+*
+*  GLP_MPS_DECK - fixed (ancient) MPS format;
+*  GLP_MPS_FILE - free (modern) MPS format.
+*
+*  The parameter parm is a pointer to the structure glp_mpscp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  read.
+*
+*  Note that before reading data the current content of the problem
+*  object is completely erased with the routine glp_erase_prob.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_read_mps returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* pointer to problem object */
+      int deck;
+      /* MPS format (0 - free, 1 - fixed) */
+      const glp_mpscp *parm;
+      /* pointer to control parameters */
+      const char *fname;
+      /* name of input MPS file */
+      XFILE *fp;
+      /* stream assigned to input MPS file */
+      jmp_buf jump;
+      /* label for go to in case of error */
+      int recno;
+      /* current record (card) number */
+      int recpos;
+      /* current record (card) position */
+      int c;
+      /* current character */
+      int fldno;
+      /* current field number */
+      char field[255+1];
+      /* current field content */
+      int w80;
+      /* warning 'record must not be longer than 80 chars' issued */
+      int wef;
+      /* warning 'extra fields detected beyond field 6' issued */
+      int obj_row;
+      /* objective row number */
+      void *work1, *work2, *work3;
+      /* working arrays */
+};
+
+static void error(struct csa *csa, const char *fmt, ...)
+{     /* print error message and terminate processing */
+      va_list arg;
+      xprintf("%s:%d: ", csa->fname, csa->recno);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      longjmp(csa->jump, 1);
+      /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{     /* print warning message and continue processing */
+      va_list arg;
+      xprintf("%s:%d: warning: ", csa->fname, csa->recno);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+static void read_char(struct csa *csa)
+{     /* read next character */
+      int c;
+      if (csa->c == '\n')
+         csa->recno++, csa->recpos = 0;
+      csa->recpos++;
+read: c = xfgetc(csa->fp);
+      if (c < 0)
+      {  if (xferror(csa->fp))
+            error(csa, "read error - %s\n", xerrmsg());
+         else if (csa->c == '\n')
+            error(csa, "unexpected end of file\n");
+         else
+         {  warning(csa, "missing final end of line\n");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (csa->c == '\r')
+      {  c = '\r';
+         goto badc;
+      }
+      else if (csa->deck && c == '\r')
+      {  csa->c = '\r';
+         goto read;
+      }
+      else if (c == ' ')
+         ;
+      else if (isspace(c))
+      {  if (csa->deck)
+badc:       error(csa, "in fixed MPS format white-space character 0x%02"
+               "X is not allowed\n", c);
+         c = ' ';
+      }
+      else if (iscntrl(c))
+         error(csa, "invalid control character 0x%02X\n", c);
+      if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1)
+      {  warning(csa, "in fixed MPS format record must not be longer th"
+            "an 80 characters\n");
+         csa->w80++;
+      }
+      csa->c = c;
+      return;
+}
+
+static int indicator(struct csa *csa, int name)
+{     /* skip comment records and read possible indicator record */
+      int ret;
+      /* reset current field number */
+      csa->fldno = 0;
+loop: /* read the very first character of the next record */
+      xassert(csa->c == '\n');
+      read_char(csa);
+      if (csa->c == ' ' || csa->c == '\n')
+      {  /* data record */
+         ret = 0;
+      }
+      else if (csa->c == '*')
+      {  /* comment record */
+         while (csa->c != '\n')
+            read_char(csa);
+         goto loop;
+      }
+      else
+      {  /* indicator record */
+         int len = 0;
+         while (csa->c != ' ' && csa->c != '\n' && len < 12)
+         {  csa->field[len++] = (char)csa->c;
+            read_char(csa);
+         }
+         csa->field[len] = '\0';
+         if (!(strcmp(csa->field, "NAME")    == 0 ||
+               strcmp(csa->field, "ROWS")    == 0 ||
+               strcmp(csa->field, "COLUMNS") == 0 ||
+               strcmp(csa->field, "RHS")     == 0 ||
+               strcmp(csa->field, "RANGES")  == 0 ||
+               strcmp(csa->field, "BOUNDS")  == 0 ||
+               strcmp(csa->field, "ENDATA")  == 0))
+            error(csa, "invalid indicator record\n");
+         if (!name)
+         {  while (csa->c != '\n')
+               read_char(csa);
+         }
+         ret = 1;
+      }
+      return ret;
+}
+
+static void read_field(struct csa *csa)
+{     /* read next field of the current data record */
+      csa->fldno++;
+      if (csa->deck)
+      {  /* fixed MPS format */
+         int beg, end, pos;
+         /* determine predefined field positions */
+         if (csa->fldno == 1)
+            beg = 2, end = 3;
+         else if (csa->fldno == 2)
+            beg = 5, end = 12;
+         else if (csa->fldno == 3)
+            beg = 15, end = 22;
+         else if (csa->fldno == 4)
+            beg = 25, end = 36;
+         else if (csa->fldno == 5)
+            beg = 40, end = 47;
+         else if (csa->fldno == 6)
+            beg = 50, end = 61;
+         else
+            xassert(csa != csa);
+         /* skip blanks preceding the current field */
+         if (csa->c != '\n')
+         {  pos = csa->recpos;
+            while (csa->recpos < beg)
+            {  if (csa->c == ' ')
+                  ;
+               else if (csa->c == '\n')
+                  break;
+               else
+                  error(csa, "in fixed MPS format positions %d-%d must "
+                     "be blank\n", pos, beg-1);
+               read_char(csa);
+            }
+         }
+         /* skip possible comment beginning in the field 3 or 5 */
+         if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$')
+         {  while (csa->c != '\n')
+               read_char(csa);
+         }
+         /* read the current field */
+         for (pos = beg; pos <= end; pos++)
+         {  if (csa->c == '\n') break;
+            csa->field[pos-beg] = (char)csa->c;
+            read_char(csa);
+         }
+         csa->field[pos-beg] = '\0';
+         strtrim(csa->field);
+         /* skip blanks following the last field */
+         if (csa->fldno == 6 && csa->c != '\n')
+         {  while (csa->recpos <= 72)
+            {  if (csa->c == ' ')
+                  ;
+               else if (csa->c == '\n')
+                  break;
+               else
+                  error(csa, "in fixed MPS format positions 62-72 must "
+                     "be blank\n");
+               read_char(csa);
+            }
+            while (csa->c != '\n')
+               read_char(csa);
+         }
+      }
+      else
+      {  /* free MPS format */
+         int len;
+         /* skip blanks preceding the current field */
+         while (csa->c == ' ')
+            read_char(csa);
+         /* skip possible comment */
+         if (csa->c == '$')
+         {  while (csa->c != '\n')
+               read_char(csa);
+         }
+         /* read the current field */
+         len = 0;
+         while (!(csa->c == ' ' || csa->c == '\n'))
+         {  if (len == 255)
+               error(csa, "length of field %d exceeds 255 characters\n",
+                  csa->fldno++);
+            csa->field[len++] = (char)csa->c;
+            read_char(csa);
+         }
+         csa->field[len] = '\0';
+         /* skip anything following the last field (any extra fields
+            are considered to be comments) */
+         if (csa->fldno == 6)
+         {  while (csa->c == ' ')
+               read_char(csa);
+            if (csa->c != '$' && csa->c != '\n' && csa->wef < 1)
+            {  warning(csa, "some extra field(s) detected beyond field "
+                  "6; field(s) ignored\n");
+               csa->wef++;
+            }
+            while (csa->c != '\n')
+               read_char(csa);
+         }
+      }
+      return;
+}
+
+static void patch_name(struct csa *csa, char *name)
+{     /* process embedded blanks in symbolic name */
+      int blank = csa->parm->blank;
+      if (blank == '\0')
+      {  /* remove emedded blanks */
+         strspx(name);
+      }
+      else
+      {  /* replace embedded blanks by specified character */
+         for (; *name != '\0'; name++)
+            if (*name == ' ') *name = (char)blank;
+      }
+      return;
+}
+
+static double read_number(struct csa *csa)
+{     /* read next field and convert it to floating-point number */
+      double x;
+      char *s;
+      /* read next field */
+      read_field(csa);
+      xassert(csa->fldno == 4 || csa->fldno == 6);
+      if (csa->field[0] == '\0')
+         error(csa, "missing numeric value in field %d\n", csa->fldno);
+      /* skip initial spaces of the field */
+      for (s = csa->field; *s == ' '; s++);
+      /* perform conversion */
+      if (str2num(s, &x) != 0)
+         error(csa, "cannot convert `%s' to floating-point number\n",
+            s);
+      return x;
+}
+
+static void skip_field(struct csa *csa)
+{     /* read and skip next field (assumed to be blank) */
+      read_field(csa);
+      if (csa->field[0] != '\0')
+         error(csa, "field %d must be blank\n", csa->fldno);
+      return;
+}
+
+static void read_name(struct csa *csa)
+{     /* read NAME indicator record */
+      if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0))
+         error(csa, "missing NAME indicator record\n");
+      /* this indicator record looks like a data record; simulate that
+         fields 1 and 2 were read */
+      csa->fldno = 2;
+      /* field 3: model name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+         warning(csa, "missing model name in field 3\n");
+      else
+         glp_set_prob_name(csa->P, csa->field);
+      /* skip anything following field 3 */
+      while (csa->c != '\n')
+         read_char(csa);
+      return;
+}
+
+static void read_rows(struct csa *csa)
+{     /* read ROWS section */
+      int i, type;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1: row type */
+      read_field(csa), strspx(csa->field);
+      if (strcmp(csa->field, "N") == 0)
+         type = GLP_FR;
+      else if (strcmp(csa->field, "G") == 0)
+         type = GLP_LO;
+      else if (strcmp(csa->field, "L") == 0)
+         type = GLP_UP;
+      else if (strcmp(csa->field, "E") == 0)
+         type = GLP_FX;
+      else if (csa->field[0] == '\0')
+         error(csa, "missing row type in field 1\n");
+      else
+         error(csa, "invalid row type in field 1\n");
+      /* field 2: row name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+         error(csa, "missing row name in field 2\n");
+      if (glp_find_row(csa->P, csa->field) != 0)
+         error(csa, "row `%s' multiply specified\n", csa->field);
+      i = glp_add_rows(csa->P, 1);
+      glp_set_row_name(csa->P, i, csa->field);
+      glp_set_row_bnds(csa->P, i, type, 0.0, 0.0);
+      /* fields 3, 4, 5, and 6 must be blank */
+      skip_field(csa);
+      skip_field(csa);
+      skip_field(csa);
+      skip_field(csa);
+      goto loop;
+done: return;
+}
+
+static void read_columns(struct csa *csa)
+{     /* read COLUMNS section */
+      int i, j, f, len, kind = GLP_CV, *ind;
+      double aij, *val;
+      char name[255+1], *flag;
+      /* allocate working arrays */
+      csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int));
+      csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double));
+      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+      memset(&flag[1], 0, csa->P->m);
+      /* no current column exists */
+      j = 0, len = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1 must be blank */
+      if (csa->deck)
+      {  read_field(csa);
+         if (csa->field[0] != '\0')
+            error(csa, "field 1 must be blank\n");
+      }
+      else
+         csa->fldno++;
+      /* field 2: column or kind name */
+      read_field(csa), patch_name(csa, csa->field);
+      strcpy(name, csa->field);
+      /* field 3: row name or keyword 'MARKER' */
+      read_field(csa), patch_name(csa, csa->field);
+      if (strcmp(csa->field, "'MARKER'") == 0)
+      {  /* process kind data record */
+         /* field 4 must be blank */
+         if (csa->deck)
+         {  read_field(csa);
+            if (csa->field[0] != '\0')
+               error(csa, "field 4 must be blank\n");
+         }
+         else
+            csa->fldno++;
+         /* field 5: keyword 'INTORG' or 'INTEND' */
+         read_field(csa), patch_name(csa, csa->field);
+         if (strcmp(csa->field, "'INTORG'") == 0)
+            kind = GLP_IV;
+         else if (strcmp(csa->field, "'INTEND'") == 0)
+            kind = GLP_CV;
+         else if (csa->field[0] == '\0')
+            error(csa, "missing keyword in field 5\n");
+         else
+            error(csa, "invalid keyword in field 5\n");
+         /* field 6 must be blank */
+         skip_field(csa);
+         goto loop;
+      }
+      /* process column name specified in field 2 */
+      if (name[0] == '\0')
+      {  /* the same column as in previous data record */
+         if (j == 0)
+            error(csa, "missing column name in field 2\n");
+      }
+      else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0)
+      {  /* the same column as in previous data record */
+         xassert(j != 0);
+      }
+      else
+      {  /* store the current column */
+         if (j != 0)
+         {  glp_set_mat_col(csa->P, j, len, ind, val);
+            while (len > 0) flag[ind[len--]] = 0;
+         }
+         /* create new column */
+         if (glp_find_col(csa->P, name) != 0)
+            error(csa, "column `%s' multiply specified\n", name);
+         j = glp_add_cols(csa->P, 1);
+         glp_set_col_name(csa->P, j, name);
+         glp_set_col_kind(csa->P, j, kind);
+         if (kind == GLP_CV)
+            glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0);
+         else if (kind == GLP_IV)
+            glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0);
+         else
+            xassert(kind != kind);
+      }
+      /* process fields 3-4 and 5-6 */
+      for (f = 3; f <= 5; f += 2)
+      {  /* field 3 or 5: row name */
+         if (f == 3)
+         {  if (csa->field[0] == '\0')
+               error(csa, "missing row name in field 3\n");
+         }
+         else
+         {  read_field(csa), patch_name(csa, csa->field);
+            if (csa->field[0] == '\0')
+            {  /* if field 5 is blank, field 6 also must be blank */
+               skip_field(csa);
+               continue;
+            }
+         }
+         i = glp_find_row(csa->P, csa->field);
+         if (i == 0)
+            error(csa, "row `%s' not found\n", csa->field);
+         if (flag[i])
+            error(csa, "duplicate coefficient in row `%s'\n",
+               csa->field);
+         /* field 4 or 6: coefficient value */
+         aij = read_number(csa);
+         if (fabs(aij) < csa->parm->tol_mps) aij = 0.0;
+         len++, ind[len] = i, val[len] = aij, flag[i] = 1;
+      }
+      goto loop;
+done: /* store the last column */
+      if (j != 0)
+         glp_set_mat_col(csa->P, j, len, ind, val);
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      xfree(flag);
+      csa->work1 = csa->work2 = csa->work3 = NULL;
+      return;
+}
+
+static void read_rhs(struct csa *csa)
+{     /* read RHS section */
+      int i, f, v, type;
+      double rhs;
+      char name[255+1], *flag;
+      /* allocate working array */
+      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+      memset(&flag[1], 0, csa->P->m);
+      /* no current RHS vector exists */
+      v = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1 must be blank */
+      if (csa->deck)
+      {  read_field(csa);
+         if (csa->field[0] != '\0')
+            error(csa, "field 1 must be blank\n");
+      }
+      else
+         csa->fldno++;
+      /* field 2: RHS vector name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+      {  /* the same RHS vector as in previous data record */
+         if (v == 0)
+         {  warning(csa, "missing RHS vector name in field 2\n");
+            goto blnk;
+         }
+      }
+      else if (v != 0 && strcmp(csa->field, name) == 0)
+      {  /* the same RHS vector as in previous data record */
+         xassert(v != 0);
+      }
+      else
+blnk: {  /* new RHS vector */
+         if (v != 0)
+            error(csa, "multiple RHS vectors not supported\n");
+         v++;
+         strcpy(name, csa->field);
+      }
+      /* process fields 3-4 and 5-6 */
+      for (f = 3; f <= 5; f += 2)
+      {  /* field 3 or 5: row name */
+         read_field(csa), patch_name(csa, csa->field);
+         if (csa->field[0] == '\0')
+         {  if (f == 3)
+               error(csa, "missing row name in field 3\n");
+            else
+            {  /* if field 5 is blank, field 6 also must be blank */
+               skip_field(csa);
+               continue;
+            }
+         }
+         i = glp_find_row(csa->P, csa->field);
+         if (i == 0)
+            error(csa, "row `%s' not found\n", csa->field);
+         if (flag[i])
+            error(csa, "duplicate right-hand side for row `%s'\n",
+               csa->field);
+         /* field 4 or 6: right-hand side value */
+         rhs = read_number(csa);
+         if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0;
+         type = csa->P->row[i]->type;
+         if (type == GLP_FR)
+         {  if (i == csa->obj_row)
+               glp_set_obj_coef(csa->P, 0, rhs);
+            else if (rhs != 0.0)
+               warning(csa, "non-zero right-hand side for free row `%s'"
+                  " ignored\n", csa->P->row[i]->name);
+         }
+         else
+            glp_set_row_bnds(csa->P, i, type, rhs, rhs);
+         flag[i] = 1;
+      }
+      goto loop;
+done: /* free working array */
+      xfree(flag);
+      csa->work3 = NULL;
+      return;
+}
+
+static void read_ranges(struct csa *csa)
+{     /* read RANGES section */
+      int i, f, v, type;
+      double rhs, rng;
+      char name[255+1], *flag;
+      /* allocate working array */
+      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+      memset(&flag[1], 0, csa->P->m);
+      /* no current RANGES vector exists */
+      v = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1 must be blank */
+      if (csa->deck)
+      {  read_field(csa);
+         if (csa->field[0] != '\0')
+            error(csa, "field 1 must be blank\n");
+      }
+      else
+         csa->fldno++;
+      /* field 2: RANGES vector name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+      {  /* the same RANGES vector as in previous data record */
+         if (v == 0)
+         {  warning(csa, "missing RANGES vector name in field 2\n");
+            goto blnk;
+         }
+      }
+      else if (v != 0 && strcmp(csa->field, name) == 0)
+      {  /* the same RANGES vector as in previous data record */
+         xassert(v != 0);
+      }
+      else
+blnk: {  /* new RANGES vector */
+         if (v != 0)
+            error(csa, "multiple RANGES vectors not supported\n");
+         v++;
+         strcpy(name, csa->field);
+      }
+      /* process fields 3-4 and 5-6 */
+      for (f = 3; f <= 5; f += 2)
+      {  /* field 3 or 5: row name */
+         read_field(csa), patch_name(csa, csa->field);
+         if (csa->field[0] == '\0')
+         {  if (f == 3)
+               error(csa, "missing row name in field 3\n");
+            else
+            {  /* if field 5 is blank, field 6 also must be blank */
+               skip_field(csa);
+               continue;
+            }
+         }
+         i = glp_find_row(csa->P, csa->field);
+         if (i == 0)
+            error(csa, "row `%s' not found\n", csa->field);
+         if (flag[i])
+            error(csa, "duplicate range for row `%s'\n", csa->field);
+         /* field 4 or 6: range value */
+         rng = read_number(csa);
+         if (fabs(rng) < csa->parm->tol_mps) rng = 0.0;
+         type = csa->P->row[i]->type;
+         if (type == GLP_FR)
+            warning(csa, "range for free row `%s' ignored\n",
+               csa->P->row[i]->name);
+         else if (type == GLP_LO)
+         {  rhs = csa->P->row[i]->lb;
+            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
+               rhs, rhs + fabs(rng));
+         }
+         else if (type == GLP_UP)
+         {  rhs = csa->P->row[i]->ub;
+            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
+               rhs - fabs(rng), rhs);
+         }
+         else if (type == GLP_FX)
+         {  rhs = csa->P->row[i]->lb;
+            if (rng > 0.0)
+               glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng);
+            else if (rng < 0.0)
+               glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs);
+         }
+         else
+            xassert(type != type);
+         flag[i] = 1;
+      }
+      goto loop;
+done: /* free working array */
+      xfree(flag);
+      csa->work3 = NULL;
+      return;
+}
+
+static void read_bounds(struct csa *csa)
+{     /* read BOUNDS section */
+      GLPCOL *col;
+      int j, v, mask, data;
+      double bnd, lb, ub;
+      char type[2+1], name[255+1], *flag;
+      /* allocate working array */
+      csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char));
+      memset(&flag[1], 0, csa->P->n);
+      /* no current BOUNDS vector exists */
+      v = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1: bound type */
+      read_field(csa);
+      if (strcmp(csa->field, "LO") == 0)
+         mask = 0x01, data = 1;
+      else if (strcmp(csa->field, "UP") == 0)
+         mask = 0x10, data = 1;
+      else if (strcmp(csa->field, "FX") == 0)
+         mask = 0x11, data = 1;
+      else if (strcmp(csa->field, "FR") == 0)
+         mask = 0x11, data = 0;
+      else if (strcmp(csa->field, "MI") == 0)
+         mask = 0x01, data = 0;
+      else if (strcmp(csa->field, "PL") == 0)
+         mask = 0x10, data = 0;
+      else if (strcmp(csa->field, "LI") == 0)
+         mask = 0x01, data = 1;
+      else if (strcmp(csa->field, "UI") == 0)
+         mask = 0x10, data = 1;
+      else if (strcmp(csa->field, "BV") == 0)
+         mask = 0x11, data = 0;
+      else if (csa->field[0] == '\0')
+         error(csa, "missing bound type in field 1\n");
+      else
+         error(csa, "invalid bound type in field 1\n");
+      strcpy(type, csa->field);
+      /* field 2: BOUNDS vector name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+      {  /* the same BOUNDS vector as in previous data record */
+         if (v == 0)
+         {  warning(csa, "missing BOUNDS vector name in field 2\n");
+            goto blnk;
+         }
+      }
+      else if (v != 0 && strcmp(csa->field, name) == 0)
+      {  /* the same BOUNDS vector as in previous data record */
+         xassert(v != 0);
+      }
+      else
+blnk: {  /* new BOUNDS vector */
+         if (v != 0)
+            error(csa, "multiple BOUNDS vectors not supported\n");
+         v++;
+         strcpy(name, csa->field);
+      }
+      /* field 3: column name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+         error(csa, "missing column name in field 3\n");
+      j = glp_find_col(csa->P, csa->field);
+      if (j == 0)
+         error(csa, "column `%s' not found\n", csa->field);
+      if ((flag[j] & mask) == 0x01)
+         error(csa, "duplicate lower bound for column `%s'\n",
+            csa->field);
+      if ((flag[j] & mask) == 0x10)
+         error(csa, "duplicate upper bound for column `%s'\n",
+            csa->field);
+      xassert((flag[j] & mask) == 0x00);
+      /* field 4: bound value */
+      if (data)
+      {  bnd = read_number(csa);
+         if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0;
+      }
+      else
+         read_field(csa), bnd = 0.0;
+      /* get current column bounds */
+      col = csa->P->col[j];
+      if (col->type == GLP_FR)
+         lb = -DBL_MAX, ub = +DBL_MAX;
+      else if (col->type == GLP_LO)
+         lb = col->lb, ub = +DBL_MAX;
+      else if (col->type == GLP_UP)
+         lb = -DBL_MAX, ub = col->ub;
+      else if (col->type == GLP_DB)
+         lb = col->lb, ub = col->ub;
+      else if (col->type == GLP_FX)
+         lb = ub = col->lb;
+      else
+         xassert(col != col);
+      /* change column bounds */
+      if (strcmp(type, "LO") == 0)
+         lb = bnd;
+      else if (strcmp(type, "UP") == 0)
+         ub = bnd;
+      else if (strcmp(type, "FX") == 0)
+         lb = ub = bnd;
+      else if (strcmp(type, "FR") == 0)
+         lb = -DBL_MAX, ub = +DBL_MAX;
+      else if (strcmp(type, "MI") == 0)
+         lb = -DBL_MAX;
+      else if (strcmp(type, "PL") == 0)
+         ub = +DBL_MAX;
+      else if (strcmp(type, "LI") == 0)
+      {  glp_set_col_kind(csa->P, j, GLP_IV);
+         lb = ceil(bnd);
+      }
+      else if (strcmp(type, "UI") == 0)
+      {  glp_set_col_kind(csa->P, j, GLP_IV);
+         ub = floor(bnd);
+      }
+      else if (strcmp(type, "BV") == 0)
+      {  glp_set_col_kind(csa->P, j, GLP_IV);
+         lb = 0.0, ub = 1.0;
+      }
+      else
+         xassert(type != type);
+      /* set new column bounds */
+      if (lb == -DBL_MAX && ub == +DBL_MAX)
+         glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub);
+      else if (ub == +DBL_MAX)
+         glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub);
+      else if (lb == -DBL_MAX)
+         glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub);
+      else if (lb != ub)
+         glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub);
+      else
+         glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub);
+      flag[j] |= (char)mask;
+      /* fields 5 and 6 must be blank */
+      skip_field(csa);
+      skip_field(csa);
+      goto loop;
+done: /* free working array */
+      xfree(flag);
+      csa->work3 = NULL;
+      return;
+}
+
+int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname)
+{     /* read problem data in MPS format */
+      glp_mpscp _parm;
+      struct csa _csa, *csa = &_csa;
+      int ret;
+      xprintf("Reading problem data from `%s'...\n", fname);
+      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
+         xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt);
+      if (parm == NULL)
+         glp_init_mpscp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_read_mps", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->deck = (fmt == GLP_MPS_DECK);
+      csa->parm = parm;
+      csa->fname = fname;
+      csa->fp = NULL;
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->recno = csa->recpos = 0;
+      csa->c = '\n';
+      csa->fldno = 0;
+      csa->field[0] = '\0';
+      csa->w80 = csa->wef = 0;
+      csa->obj_row = 0;
+      csa->work1 = csa->work2 = csa->work3 = NULL;
+      /* erase problem object */
+      glp_erase_prob(P);
+      glp_create_index(P);
+      /* open input MPS file */
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* read NAME indicator record */
+      read_name(csa);
+      if (P->name != NULL)
+         xprintf("Problem: %s\n", P->name);
+      /* read ROWS section */
+      if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0))
+         error(csa, "missing ROWS indicator record\n");
+      read_rows(csa);
+      /* determine objective row */
+      if (parm->obj_name == NULL || parm->obj_name[0] == '\0')
+      {  /* use the first row of N type */
+         int i;
+         for (i = 1; i <= P->m; i++)
+         {  if (P->row[i]->type == GLP_FR)
+            {  csa->obj_row = i;
+               break;
+            }
+         }
+         if (csa->obj_row == 0)
+            warning(csa, "unable to determine objective row\n");
+      }
+      else
+      {  /* use a row with specified name */
+         int i;
+         for (i = 1; i <= P->m; i++)
+         {  xassert(P->row[i]->name != NULL);
+            if (strcmp(parm->obj_name, P->row[i]->name) == 0)
+            {  csa->obj_row = i;
+               break;
+            }
+         }
+         if (csa->obj_row == 0)
+            error(csa, "objective row `%s' not found\n",
+               parm->obj_name);
+      }
+      if (csa->obj_row != 0)
+      {  glp_set_obj_name(P, P->row[csa->obj_row]->name);
+         xprintf("Objective: %s\n", P->obj);
+      }
+      /* read COLUMNS section */
+      if (strcmp(csa->field, "COLUMNS") != 0)
+         error(csa, "missing COLUMNS indicator record\n");
+      read_columns(csa);
+      /* set objective coefficients */
+      if (csa->obj_row != 0)
+      {  GLPAIJ *aij;
+         for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij =
+            aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val);
+      }
+      /* read optional RHS section */
+      if (strcmp(csa->field, "RHS") == 0)
+         read_rhs(csa);
+      /* read optional RANGES section */
+      if (strcmp(csa->field, "RANGES") == 0)
+         read_ranges(csa);
+      /* read optional BOUNDS section */
+      if (strcmp(csa->field, "BOUNDS") == 0)
+         read_bounds(csa);
+      /* read ENDATA indicator record */
+      if (strcmp(csa->field, "ENDATA") != 0)
+         error(csa, "invalid use of %s indicator record\n",
+            csa->field);
+      /* print some statistics */
+      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+         P->nnz, P->nnz == 1 ? "" : "s");
+      if (glp_get_num_int(P) > 0)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         if (ni == 1)
+         {  if (nb == 0)
+               xprintf("One variable is integer\n");
+            else
+               xprintf("One variable is binary\n");
+         }
+         else
+         {  xprintf("%d integer variables, ", ni);
+            if (nb == 0)
+               xprintf("none");
+            else if (nb == 1)
+               xprintf("one");
+            else if (nb == ni)
+               xprintf("all");
+            else
+               xprintf("%d", nb);
+            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+         }
+      }
+      xprintf("%d records were read\n", csa->recno);
+      /* problem data has been successfully read */
+      glp_delete_index(P);
+      glp_sort_matrix(P);
+      ret = 0;
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      if (csa->work1 != NULL) xfree(csa->work1);
+      if (csa->work2 != NULL) xfree(csa->work2);
+      if (csa->work3 != NULL) xfree(csa->work3);
+      if (ret != 0) glp_erase_prob(P);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_mps - write problem data in MPS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_mps writes problem data in MPS format to a
+*  text file.
+*
+*  The parameter fmt specifies the version of MPS format:
+*
+*  GLP_MPS_DECK - fixed (ancient) MPS format;
+*  GLP_MPS_FILE - free (modern) MPS format.
+*
+*  The parameter parm is a pointer to the structure glp_mpscp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  written.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_read_mps returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+#define csa csa1
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* pointer to problem object */
+      int deck;
+      /* MPS format (0 - free, 1 - fixed) */
+      const glp_mpscp *parm;
+      /* pointer to control parameters */
+      char field[255+1];
+      /* field buffer */
+};
+
+static char *mps_name(struct csa *csa)
+{     /* make problem name */
+      char *f;
+      if (csa->P->name == NULL)
+         csa->field[0] = '\0';
+      else if (csa->deck)
+      {  strncpy(csa->field, csa->P->name, 8);
+         csa->field[8] = '\0';
+      }
+      else
+         strcpy(csa->field, csa->P->name);
+      for (f = csa->field; *f != '\0'; f++)
+         if (*f == ' ') *f = '_';
+      return csa->field;
+}
+
+static char *row_name(struct csa *csa, int i)
+{     /* make i-th row name */
+      char *f;
+      xassert(0 <= i && i <= csa->P->m);
+      if (i == 0 || csa->P->row[i]->name == NULL ||
+          csa->deck && strlen(csa->P->row[i]->name) > 8)
+         sprintf(csa->field, "R%07d", i);
+      else
+      {  strcpy(csa->field, csa->P->row[i]->name);
+         for (f = csa->field; *f != '\0'; f++)
+            if (*f == ' ') *f = '_';
+      }
+      return csa->field;
+}
+
+static char *col_name(struct csa *csa, int j)
+{     /* make j-th column name */
+      char *f;
+      xassert(1 <= j && j <= csa->P->n);
+      if (csa->P->col[j]->name == NULL ||
+          csa->deck && strlen(csa->P->col[j]->name) > 8)
+         sprintf(csa->field, "C%07d", j);
+      else
+      {  strcpy(csa->field, csa->P->col[j]->name);
+         for (f = csa->field; *f != '\0'; f++)
+            if (*f == ' ') *f = '_';
+      }
+      return csa->field;
+}
+
+static char *mps_numb(struct csa *csa, double val)
+{     /* format floating-point number */
+      int dig;
+      char *exp;
+      for (dig = 12; dig >= 6; dig--)
+      {  if (val != 0.0 && fabs(val) < 0.002)
+            sprintf(csa->field, "%.*E", dig-1, val);
+         else
+            sprintf(csa->field, "%.*G", dig, val);
+         exp = strchr(csa->field, 'E');
+         if (exp != NULL)
+            sprintf(exp+1, "%d", atoi(exp+1));
+         if (strlen(csa->field) <= 12) break;
+      }
+      xassert(strlen(csa->field) <= 12);
+      return csa->field;
+}
+
+int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname)
+{     /* write problem data in MPS format */
+      glp_mpscp _parm;
+      struct csa _csa, *csa = &_csa;
+      XFILE *fp;
+      int out_obj, one_col = 0, empty = 0;
+      int i, j, recno, marker, count, gap, ret;
+      xprintf("Writing problem data to `%s'...\n", fname);
+      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
+         xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt);
+      if (parm == NULL)
+         glp_init_mpscp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_write_mps", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->deck = (fmt == GLP_MPS_DECK);
+      csa->parm = parm;
+      /* create output MPS file */
+      fp = xfopen(fname, "w"), recno = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* write comment records */
+      xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:",
+         P->name == NULL ? "" : P->name), recno++;
+      xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ?
+         "LP" : "MIP"), recno++;
+      xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++;
+      if (glp_get_num_int(P) == 0)
+         xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++;
+      else
+         xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n",
+            "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)),
+            recno++;
+      xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++;
+      xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" :
+         "Free MPS"), recno++;
+      xfprintf(fp, "*\n", recno++);
+      /* write NAME indicator record */
+      xfprintf(fp, "NAME%*s%s\n",
+         P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)),
+         recno++;
+#if 1
+      /* determine whether to write the objective row */
+      out_obj = 1;
+      for (i = 1; i <= P->m; i++)
+      {  if (P->row[i]->type == GLP_FR)
+         {  out_obj = 0;
+            break;
+         }
+      }
+#endif
+      /* write ROWS section */
+      xfprintf(fp, "ROWS\n"), recno++;
+      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
+      {  int type;
+         type = (i == 0 ? GLP_FR : P->row[i]->type);
+         if (type == GLP_FR)
+            type = 'N';
+         else if (type == GLP_LO)
+            type = 'G';
+         else if (type == GLP_UP)
+            type = 'L';
+         else if (type == GLP_DB || type == GLP_FX)
+            type = 'E';
+         else
+            xassert(type != type);
+         xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "",
+            row_name(csa, i)), recno++;
+      }
+      /* write COLUMNS section */
+      xfprintf(fp, "COLUMNS\n"), recno++;
+      marker = 0;
+      for (j = 1; j <= P->n; j++)
+      {  GLPAIJ cj, *aij;
+         int kind;
+         kind = P->col[j]->kind;
+         if (kind == GLP_CV)
+         {  if (marker % 2 == 1)
+            {  /* close current integer block */
+               marker++;
+               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
+                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+                  csa->deck ? 17 : 1, ""), recno++;
+            }
+         }
+         else if (kind == GLP_IV)
+         {  if (marker % 2 == 0)
+            {  /* open new integer block */
+               marker++;
+               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n",
+                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+                  csa->deck ? 17 : 1, ""), recno++;
+            }
+         }
+         else
+            xassert(kind != kind);
+         if (out_obj && P->col[j]->coef != 0.0)
+         {  /* make fake objective coefficient */
+            aij = &cj;
+            aij->row = NULL;
+            aij->val = P->col[j]->coef;
+            aij->c_next = P->col[j]->ptr;
+         }
+         else
+            aij = P->col[j]->ptr;
+#if 1 /* FIXME */
+         if (aij == NULL)
+         {  /* empty column */
+            empty++;
+            xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+               csa->deck ? 8 : 1, col_name(csa, j));
+            /* we need a row */
+            xassert(P->m > 0);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, 1));
+            xfprintf(fp, "%*s0%*s$ empty column\n",
+               csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++;
+         }
+#endif
+         count = 0;
+         for (aij = aij; aij != NULL; aij = aij->c_next)
+         {  if (one_col || count % 2 == 0)
+               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+                  csa->deck ? 8 : 1, col_name(csa, j));
+            gap = (one_col || count % 2 == 0 ? 2 : 3);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, aij->row == NULL ? 0 : aij->row->i));
+            xfprintf(fp, "%*s%*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+               mps_numb(csa, aij->val)), count++;
+            if (one_col || count % 2 == 0)
+               xfprintf(fp, "\n"), recno++;
+         }
+         if (!(one_col || count % 2 == 0))
+            xfprintf(fp, "\n"), recno++;
+      }
+      if (marker % 2 == 1)
+      {  /* close last integer block */
+         marker++;
+         xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
+            csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+            csa->deck ? 17 : 1, ""), recno++;
+      }
+#if 1
+      if (empty > 0)
+         xprintf("Warning: problem has %d empty column(s)\n", empty);
+#endif
+      /* write RHS section */
+      xfprintf(fp, "RHS\n"), recno++;
+      count = 0;
+      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
+      {  int type;
+         double rhs;
+         if (i == 0)
+            rhs = P->c0;
+         else
+         {  type = P->row[i]->type;
+            if (type == GLP_FR)
+               rhs = 0.0;
+            else if (type == GLP_LO)
+               rhs = P->row[i]->lb;
+            else if (type == GLP_UP)
+               rhs = P->row[i]->ub;
+            else if (type == GLP_DB || type == GLP_FX)
+               rhs = P->row[i]->lb;
+            else
+               xassert(type != type);
+         }
+         if (rhs != 0.0)
+         {  if (one_col || count % 2 == 0)
+               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+                  csa->deck ? 8 : 1, "RHS1");
+            gap = (one_col || count % 2 == 0 ? 2 : 3);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, i));
+            xfprintf(fp, "%*s%*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+               mps_numb(csa, rhs)), count++;
+            if (one_col || count % 2 == 0)
+               xfprintf(fp, "\n"), recno++;
+         }
+      }
+      if (!(one_col || count % 2 == 0))
+         xfprintf(fp, "\n"), recno++;
+      /* write RANGES section */
+      for (i = P->m; i >= 1; i--)
+         if (P->row[i]->type == GLP_DB) break;
+      if (i == 0) goto bnds;
+      xfprintf(fp, "RANGES\n"), recno++;
+      count = 0;
+      for (i = 1; i <= P->m; i++)
+      {  if (P->row[i]->type == GLP_DB)
+         {  if (one_col || count % 2 == 0)
+               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+                  csa->deck ? 8 : 1, "RNG1");
+            gap = (one_col || count % 2 == 0 ? 2 : 3);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, i));
+            xfprintf(fp, "%*s%*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+               mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++;
+            if (one_col || count % 2 == 0)
+               xfprintf(fp, "\n"), recno++;
+         }
+      }
+      if (!(one_col || count % 2 == 0))
+         xfprintf(fp, "\n"), recno++;
+bnds: /* write BOUNDS section */
+      for (j = P->n; j >= 1; j--)
+         if (!(P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0))
+            break;
+      if (j == 0) goto endt;
+      xfprintf(fp, "BOUNDS\n"), recno++;
+      for (j = 1; j <= P->n; j++)
+      {  int type, data[2];
+         double bnd[2];
+         char *spec[2];
+         spec[0] = spec[1] = NULL;
+         type = P->col[j]->type;
+         if (type == GLP_FR)
+            spec[0] = "FR", data[0] = 0;
+         else if (type == GLP_LO)
+         {  if (P->col[j]->lb != 0.0)
+               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
+            if (P->col[j]->kind == GLP_IV)
+               spec[1] = "PL", data[1] = 0;
+         }
+         else if (type == GLP_UP)
+         {  spec[0] = "MI", data[0] = 0;
+            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
+         }
+         else if (type == GLP_DB)
+         {  if (P->col[j]->lb != 0.0)
+               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
+            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
+         }
+         else if (type == GLP_FX)
+            spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb;
+         else
+            xassert(type != type);
+         for (i = 0; i <= 1; i++)
+         {  if (spec[i] != NULL)
+            {  xfprintf(fp, " %s %-*s%*s%-*s", spec[i],
+                  csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "",
+                  csa->deck ? 8 : 1, col_name(csa, j));
+               if (data[i])
+                  xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "",
+                     csa->deck ? 12 : 1, mps_numb(csa, bnd[i]));
+               xfprintf(fp, "\n"), recno++;
+            }
+         }
+      }
+endt: /* write ENDATA indicator record */
+      xfprintf(fp, "ENDATA\n"), recno++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* problem data has been successfully written */
+      xprintf("%d records were written\n", recno);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnet.h b/optional/glpk/glpnet.h
new file mode 100644
index 0000000..7633353
--- /dev/null
+++ b/optional/glpk/glpnet.h
@@ -0,0 +1,60 @@
+/* glpnet.h (graph and network algorithms) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPNET_H
+#define GLPNET_H
+
+#define mc21a _glp_mc21a
+int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+      int iperm[], int pr[], int arp[], int cv[], int out[]);
+/* permutations for zero-free diagonal */
+
+#define mc13d _glp_mc13d
+int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+      int ior[], int ib[], int lowl[], int numb[], int prev[]);
+/* permutations to block triangular form */
+
+#define okalg _glp_okalg
+int okalg(int nv, int na, const int tail[], const int head[],
+      const int low[], const int cap[], const int cost[], int x[],
+      int pi[]);
+/* out-of-kilter algorithm */
+
+#define ffalg _glp_ffalg
+void ffalg(int nv, int na, const int tail[], const int head[],
+      int s, int t, const int cap[], int x[], char cut[]);
+/* Ford-Fulkerson algorithm */
+
+#define wclique _glp_wclique
+int wclique(int n, const int w[], const unsigned char a[], int ind[]);
+/* find maximum weight clique with Ostergard's algorithm */
+
+#define kellerman _glp_kellerman
+int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+      void *info, void /* glp_graph */ *H);
+/* cover edges by cliques with Kellerman's heuristic */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnet01.c b/optional/glpk/glpnet01.c
new file mode 100644
index 0000000..34d7e5d
--- /dev/null
+++ b/optional/glpk/glpnet01.c
@@ -0,0 +1,301 @@
+/* glpnet01.c (permutations for zero-free diagonal) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is the result of translation of the Fortran subroutines
+*  MC21A and MC21B associated with the following paper:
+*
+*  I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
+*  Trans. on Math. Softw. 7 (1981), 387-390.
+*
+*  Use of ACM Algorithms is subject to the ACM Software Copyright and
+*  License Agreement. See <http://www.acm.org/publications/policies>.
+*
+*  The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  mc21a - permutations for zero-free diagonal
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+*     int iperm[], int pr[], int arp[], int cv[], int out[]);
+*
+*  DESCRIPTION
+*
+*  Given the pattern of nonzeros of a sparse matrix, the routine mc21a
+*  attempts to find a permutation of its rows that makes the matrix have
+*  no zeros on its diagonal.
+*
+*  INPUT PARAMETERS
+*
+*  n     order of matrix.
+*
+*  icn   array containing the column indices of the non-zeros. Those
+*        belonging to a single row must be contiguous but the ordering
+*        of column indices within each row is unimportant and wasted
+*        space between rows is permitted.
+*
+*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
+*        first column index of a non-zero in row i.
+*
+*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
+*
+*  OUTPUT PARAMETER
+*
+*  iperm contains permutation to make diagonal have the smallest
+*        number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n,
+*        are non-zero at the end of the algorithm unless the matrix is
+*        structurally singular. In this case, (iperm[i], i) will be
+*        zero for n - numnz entries.
+*
+*  WORKING ARRAYS
+*
+*  pr    working array of length [1+n], where pr[0] is not used.
+*        pr[i] is the previous row to i in the depth first search.
+*
+*  arp   working array of length [1+n], where arp[0] is not used.
+*        arp[i] is one less than the number of non-zeros in row i which
+*        have not been scanned when looking for a cheap assignment.
+*
+*  cv    working array of length [1+n], where cv[0] is not used.
+*        cv[i] is the most recent row extension at which column i was
+*        visited.
+*
+*  out   working array of length [1+n], where out[0] is not used.
+*        out[i] is one less than the number of non-zeros in row i
+*        which have not been scanned during one pass through the main
+*        loop.
+*
+*  RETURNS
+*
+*  The routine mc21a returns numnz, the number of non-zeros on diagonal
+*  of permuted matrix. */
+
+int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+      int iperm[], int pr[], int arp[], int cv[], int out[])
+{     int i, ii, in1, in2, j, j1, jord, k, kk, numnz;
+      /* Initialization of arrays. */
+      for (i = 1; i <= n; i++)
+      {  arp[i] = lenr[i] - 1;
+         cv[i] = iperm[i] = 0;
+      }
+      numnz = 0;
+      /* Main loop. */
+      /* Each pass round this loop either results in a new assignment
+         or gives a row with no assignment. */
+      for (jord = 1; jord <= n; jord++)
+      {  j = jord;
+         pr[j] = -1;
+         for (k = 1; k <= jord; k++)
+         {  /* Look for a cheap assignment. */
+            in1 = arp[j];
+            if (in1 >= 0)
+            {  in2 = ip[j] + lenr[j] - 1;
+               in1 = in2 - in1;
+               for (ii = in1; ii <= in2; ii++)
+               {  i = icn[ii];
+                  if (iperm[i] == 0) goto L110;
+               }
+               /* No cheap assignment in row. */
+               arp[j] = -1;
+            }
+            /* Begin looking for assignment chain starting with row j.*/
+            out[j] = lenr[j] - 1;
+            /* Inner loop. Extends chain by one or backtracks. */
+            for (kk = 1; kk <= jord; kk++)
+            {  in1 = out[j];
+               if (in1 >= 0)
+               {  in2 = ip[j] + lenr[j] - 1;
+                  in1 = in2 - in1;
+                  /* Forward scan. */
+                  for (ii = in1; ii <= in2; ii++)
+                  {  i = icn[ii];
+                     if (cv[i] != jord)
+                     {  /* Column i has not yet been accessed during
+                           this pass. */
+                        j1 = j;
+                        j = iperm[i];
+                        cv[i] = jord;
+                        pr[j] = j1;
+                        out[j1] = in2 - ii - 1;
+                        goto L100;
+                     }
+                  }
+               }
+               /* Backtracking step. */
+               j = pr[j];
+               if (j == -1) goto L130;
+            }
+L100:       ;
+         }
+L110:    /* New assignment is made. */
+         iperm[i] = j;
+         arp[j] = in2 - ii - 1;
+         numnz++;
+         for (k = 1; k <= jord; k++)
+         {  j = pr[j];
+            if (j == -1) break;
+            ii = ip[j] + lenr[j] - out[j] - 2;
+            i = icn[ii];
+            iperm[i] = j;
+         }
+L130:    ;
+      }
+      /* If matrix is structurally singular, we now complete the
+         permutation iperm. */
+      if (numnz < n)
+      {  for (i = 1; i <= n; i++)
+            arp[i] = 0;
+         k = 0;
+         for (i = 1; i <= n; i++)
+         {  if (iperm[i] == 0)
+               out[++k] = i;
+            else
+               arp[iperm[i]] = i;
+         }
+         k = 0;
+         for (i = 1; i <= n; i++)
+         {  if (arp[i] == 0)
+               iperm[out[++k]] = i;
+         }
+      }
+      return numnz;
+}
+
+/**********************************************************************/
+
+#if 0
+#include "glplib.h"
+
+int sing;
+
+void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
+      int iw[]);
+
+void fa01bs(int max, int *nrand);
+
+int main(void)
+{     /* test program for the routine mc21a */
+      /* these runs on random matrices cause all possible statements in
+         mc21a to be executed */
+      int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz;
+      int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80];
+      licn = 1000;
+      /* run on random matrices of orders 1 through 20 */
+      for (n = 1; n <= 20; n++)
+      {  nov4 = n / 4;
+         if (nov4 < 1) nov4 = 1;
+L10:     fa01bs(nov4, &l);
+         knum = l * n;
+         /* knum is requested number of non-zeros in random matrix */
+         if (knum > licn) goto L10;
+         /* if sing is false, matrix is guaranteed structurally
+            non-singular */
+         sing = ((n / 2) * 2 == n);
+         /* call to subroutine to generate random matrix */
+         ranmat(n, n, icn, ip, n+1, &knum, iw1);
+         /* knum is now actual number of non-zeros in random matrix */
+         if (knum > licn) goto L10;
+         xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing);
+         /* set up array of row lengths */
+         for (i = 1; i <= n; i++)
+            lenr[i] = ip[i+1] - ip[i];
+         /* call to mc21a */
+         numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n],
+            &iw1[n+n], &iw1[n+n+n]);
+         /* testing to see if there are numnz non-zeros on the diagonal
+            of the permuted matrix. */
+         num = 0;
+         for (i = 1; i <= n; i++)
+         {  iold = iperm[i];
+            j1 = ip[iold];
+            j2 = j1 + lenr[iold] - 1;
+            if (j2 < j1) continue;
+            for (jj = j1; jj <= j2; jj++)
+            {  j = icn[jj];
+               if (j == i)
+               {  num++;
+                  break;
+               }
+            }
+         }
+         if (num != numnz)
+            xprintf("Failure in mc21a, numnz = %d instead of %d\n",
+               numnz, num);
+      }
+      return 0;
+}
+
+void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
+      int iw[])
+{     /* subroutine to generate random matrix */
+      int i, ii, inum, j, lrow, matnum;
+      inum = (*knum / n) * 2;
+      if (inum > n-1) inum = n-1;
+      matnum = 1;
+      /* each pass through this loop generates a row of the matrix */
+      for (j = 1; j <= m; j++)
+      {  iptr[j] = matnum;
+         if (!(sing || j > n))
+            icn[matnum++] = j;
+         if (n == 1) continue;
+         for (i = 1; i <= n; i++) iw[i] = 0;
+         if (!sing) iw[j] = 1;
+         fa01bs(inum, &lrow);
+         lrow--;
+         if (lrow == 0) continue;
+         /* lrow off-diagonal non-zeros in row j of the matrix */
+         for (ii = 1; ii <= lrow; ii++)
+         {  for (;;)
+            {  fa01bs(n, &i);
+               if (iw[i] != 1) break;
+            }
+            iw[i] = 1;
+            icn[matnum++] = i;
+         }
+      }
+      for (i = m+1; i <= nnnp1; i++)
+         iptr[i] = matnum;
+      *knum = matnum - 1;
+      return;
+}
+
+double g = 1431655765.0;
+
+double fa01as(int i)
+{     /* random number generator */
+      g = fmod(g * 9228907.0, 4294967296.0);
+      if (i >= 0)
+         return g / 4294967296.0;
+      else
+         return 2.0 * g / 4294967296.0 - 1.0;
+}
+
+void fa01bs(int max, int *nrand)
+{     *nrand = (int)(fa01as(1) * (double)max) + 1;
+      return;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnet02.c b/optional/glpk/glpnet02.c
new file mode 100644
index 0000000..a1a744f
--- /dev/null
+++ b/optional/glpk/glpnet02.c
@@ -0,0 +1,314 @@
+/* glpnet02.c (permutations to block triangular form) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is the result of translation of the Fortran subroutines
+*  MC13D and MC13E associated with the following paper:
+*
+*  I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
+*  form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
+*
+*  Use of ACM Algorithms is subject to the ACM Software Copyright and
+*  License Agreement. See <http://www.acm.org/publications/policies>.
+*
+*  The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  mc13d - permutations to block triangular form
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+*     int ior[], int ib[], int lowl[], int numb[], int prev[]);
+*
+*  DESCRIPTION
+*
+*  Given the column numbers of the nonzeros in each row of the sparse
+*  matrix, the routine mc13d finds a symmetric permutation that makes
+*  the matrix block lower triangular.
+*
+*  INPUT PARAMETERS
+*
+*  n     order of the matrix.
+*
+*  icn   array containing the column indices of the non-zeros. Those
+*        belonging to a single row must be contiguous but the ordering
+*        of column indices within each row is unimportant and wasted
+*        space between rows is permitted.
+*
+*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
+*        first column index of a non-zero in row i.
+*
+*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
+*
+*  OUTPUT PARAMETERS
+*
+*  ior   ior[i], i = 1,2,...,n, gives the position on the original
+*        ordering of the row or column which is in position i in the
+*        permuted form.
+*
+*  ib    ib[i], i = 1,2,...,num, is the row number in the permuted
+*        matrix of the beginning of block i, 1 <= num <= n.
+*
+*  WORKING ARRAYS
+*
+*  arp   working array of length [1+n], where arp[0] is not used.
+*        arp[i] is one less than the number of unsearched edges leaving
+*        node i. At the end of the algorithm it is set to a permutation
+*        which puts the matrix in block lower triangular form.
+*
+*  ib    working array of length [1+n], where ib[0] is not used.
+*        ib[i] is the position in the ordering of the start of the ith
+*        block. ib[n+1-i] holds the node number of the ith node on the
+*        stack.
+*
+*  lowl  working array of length [1+n], where lowl[0] is not used.
+*        lowl[i] is the smallest stack position of any node to which a
+*        path from node i has been found. It is set to n+1 when node i
+*        is removed from the stack.
+*
+*  numb  working array of length [1+n], where numb[0] is not used.
+*        numb[i] is the position of node i in the stack if it is on it,
+*        is the permuted order of node i for those nodes whose final
+*        position has been found and is otherwise zero.
+*
+*  prev  working array of length [1+n], where prev[0] is not used.
+*        prev[i] is the node at the end of the path when node i was
+*        placed on the stack.
+*
+*  RETURNS
+*
+*  The routine mc13d returns num, the number of blocks found. */
+
+int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+      int ior[], int ib[], int lowl[], int numb[], int prev[])
+{     int *arp = ior;
+      int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
+         nnm1, num, stp;
+      /* icnt is the number of nodes whose positions in final ordering
+         have been found. */
+      icnt = 0;
+      /* num is the number of blocks that have been found. */
+      num = 0;
+      nnm1 = n + n - 1;
+      /* Initialization of arrays. */
+      for (j = 1; j <= n; j++)
+      {  numb[j] = 0;
+         arp[j] = lenr[j] - 1;
+      }
+      for (isn = 1; isn <= n; isn++)
+      {  /* Look for a starting node. */
+         if (numb[isn] != 0) continue;
+         iv = isn;
+         /* ist is the number of nodes on the stack ... it is the stack
+            pointer. */
+         ist = 1;
+         /* Put node iv at beginning of stack. */
+         lowl[iv] = numb[iv] = 1;
+         ib[n] = iv;
+         /* The body of this loop puts a new node on the stack or
+            backtracks. */
+         for (dummy = 1; dummy <= nnm1; dummy++)
+         {  i1 = arp[iv];
+            /* Have all edges leaving node iv been searched? */
+            if (i1 >= 0)
+            {  i2 = ip[iv] + lenr[iv] - 1;
+               i1 = i2 - i1;
+               /* Look at edges leaving node iv until one enters a new
+                  node or all edges are exhausted. */
+               for (ii = i1; ii <= i2; ii++)
+               {  iw = icn[ii];
+                  /* Has node iw been on stack already? */
+                  if (numb[iw] == 0) goto L70;
+                  /* Update value of lowl[iv] if necessary. */
+                  if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
+               }
+               /* There are no more edges leaving node iv. */
+               arp[iv] = -1;
+            }
+            /* Is node iv the root of a block? */
+            if (lowl[iv] < numb[iv]) goto L60;
+            /* Order nodes in a block. */
+            num++;
+            ist1 = n + 1 - ist;
+            lcnt = icnt + 1;
+            /* Peel block off the top of the stack starting at the top
+               and working down to the root of the block. */
+            for (stp = ist1; stp <= n; stp++)
+            {  iw = ib[stp];
+               lowl[iw] = n + 1;
+               numb[iw] = ++icnt;
+               if (iw == iv) break;
+            }
+            ist = n - stp;
+            ib[num] = lcnt;
+            /* Are there any nodes left on the stack? */
+            if (ist != 0) goto L60;
+            /* Have all the nodes been ordered? */
+            if (icnt < n) break;
+            goto L100;
+L60:        /* Backtrack to previous node on path. */
+            iw = iv;
+            iv = prev[iv];
+            /* Update value of lowl[iv] if necessary. */
+            if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
+            continue;
+L70:        /* Put new node on the stack. */
+            arp[iv] = i2 - ii - 1;
+            prev[iw] = iv;
+            iv = iw;
+            lowl[iv] = numb[iv] = ++ist;
+            ib[n+1-ist] = iv;
+         }
+      }
+L100: /* Put permutation in the required form. */
+      for (i = 1; i <= n; i++)
+         arp[numb[i]] = i;
+      return num;
+}
+
+/**********************************************************************/
+
+#if 0
+#include "glplib.h"
+
+void test(int n, int ipp);
+
+int main(void)
+{     /* test program for routine mc13d */
+      test( 1,   0);
+      test( 2,   1);
+      test( 2,   2);
+      test( 3,   3);
+      test( 4,   4);
+      test( 5,  10);
+      test(10,  10);
+      test(10,  20);
+      test(20,  20);
+      test(20,  50);
+      test(50,  50);
+      test(50, 200);
+      return 0;
+}
+
+void fa01bs(int max, int *nrand);
+
+void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
+
+void test(int n, int ipp)
+{     int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
+         lenr[1+50];
+      char a[1+50][1+50], hold[1+100];
+      int i, ii, iblock, ij, index, j, jblock, jj, k9, num;
+      xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-"
+         "zeros\n", n, ipp);
+      for (j = 1; j <= n; j++)
+      {  for (i = 1; i <= n; i++)
+            a[i][j] = 0;
+         a[j][j] = 1;
+      }
+      for (k9 = 1; k9 <= ipp; k9++)
+      {  /* these statements should be replaced by calls to your
+            favorite random number generator to place two pseudo-random
+            numbers between 1 and n in the variables i and j */
+         for (;;)
+         {  fa01bs(n, &i);
+            fa01bs(n, &j);
+            if (!a[i][j]) break;
+         }
+         a[i][j] = 1;
+      }
+      /* setup converts matrix a[i,j] to required sparsity-oriented
+         storage format */
+      setup(n, a, ip, icn, lenr);
+      num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]);
+      /* output reordered matrix with blocking to improve clarity */
+      xprintf("\nThe reordered matrix which has %d block%s is of the fo"
+         "rm\n", num, num == 1 ? "" : "s");
+      ib[num+1] = n + 1;
+      index = 100;
+      iblock = 1;
+      for (i = 1; i <= n; i++)
+      {  for (ij = 1; ij <= index; ij++)
+            hold[ij] = ' ';
+         if (i == ib[iblock])
+         {  xprintf("\n");
+            iblock++;
+         }
+         jblock = 1;
+         index = 0;
+         for (j = 1; j <= n; j++)
+         {  if (j == ib[jblock])
+            {  hold[++index] = ' ';
+               jblock++;
+            }
+            ii = ior[i];
+            jj = ior[j];
+            hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
+         }
+         xprintf("%.*s\n", index, &hold[1]);
+      }
+      xprintf("\nThe starting point for each block is given by\n");
+      for (i = 1; i <= num; i++)
+      {  if ((i - 1) % 12 == 0) xprintf("\n");
+         xprintf(" %4d", ib[i]);
+      }
+      xprintf("\n");
+      return;
+}
+
+void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
+{     int i, j, ind;
+      for (i = 1; i <= n; i++)
+         lenr[i] = 0;
+      ind = 1;
+      for (i = 1; i <= n; i++)
+      {  ip[i] = ind;
+         for (j = 1; j <= n; j++)
+         {  if (a[i][j])
+            {  lenr[i]++;
+               icn[ind++] = j;
+            }
+         }
+      }
+      return;
+}
+
+double g = 1431655765.0;
+
+double fa01as(int i)
+{     /* random number generator */
+      g = fmod(g * 9228907.0, 4294967296.0);
+      if (i >= 0)
+         return g / 4294967296.0;
+      else
+         return 2.0 * g / 4294967296.0 - 1.0;
+}
+
+void fa01bs(int max, int *nrand)
+{     *nrand = (int)(fa01as(1) * (double)max) + 1;
+      return;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnet03.c b/optional/glpk/glpnet03.c
new file mode 100644
index 0000000..dc42344
--- /dev/null
+++ b/optional/glpk/glpnet03.c
@@ -0,0 +1,776 @@
+/* glpnet03.c (Klingman's network problem generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is the result of translation of the Fortran program NETGEN
+*  developed by Dr. Darwin Klingman, which is publically available from
+*  NETLIB at <http://www.netlib.org/lp/generators>.
+*
+*  The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_netgen - Klingman's network problem generator
+*
+*  SYNOPSIS
+*
+*  int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+*     const int parm[1+15]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_netgen is a network problem generator developed by
+*  Dr. Darwin Klingman. It can create capacitated and uncapacitated
+*  minimum cost flow (or transshipment), transportation, and assignment
+*  problems.
+*
+*  The parameter G specifies the graph object, to which the generated
+*  problem data have to be stored. Note that on entry the graph object
+*  is erased with the routine glp_erase_graph.
+*
+*  The parameter v_rhs specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores the supply or
+*  demand value. If v_rhs < 0, the value is not stored.
+*
+*  The parameter a_cap specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the arc capacity.
+*  If a_cap < 0, the capacity is not stored.
+*
+*  The parameter a_cost specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the per-unit cost
+*  if the arc flow. If a_cost < 0, the cost is not stored.
+*
+*  The array parm contains description of the network to be generated:
+*
+*  parm[0]           not used
+*  parm[1]  (iseed)  8-digit positive random number seed
+*  parm[2]  (nprob)  8-digit problem id number
+*  parm[3]  (nodes)  total number of nodes
+*  parm[4]  (nsorc)  total number of source nodes (including
+*                    transshipment nodes)
+*  parm[5]  (nsink)  total number of sink nodes (including
+*                    transshipment nodes)
+*  parm[6]  (iarcs)  number of arcs
+*  parm[7]  (mincst) minimum cost for arcs
+*  parm[8]  (maxcst) maximum cost for arcs
+*  parm[9]  (itsup)  total supply
+*  parm[10] (ntsorc) number of transshipment source nodes
+*  parm[11] (ntsink) number of transshipment sink nodes
+*  parm[12] (iphic)  percentage of skeleton arcs to be given
+*                    the maximum cost
+*  parm[13] (ipcap)  percentage of arcs to be capacitated
+*  parm[14] (mincap) minimum upper bound for capacitated arcs
+*  parm[15] (maxcap) maximum upper bound for capacitated arcs
+*
+*  The routine generates a transportation problem if:
+*
+*     nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0.
+*
+*  The routine generates an assignment problem if the requirements for
+*  a transportation problem are met and:
+*
+*     nsorc = nsink and itsup = nsorc.
+*
+*  RETURNS
+*
+*  If the instance was successfully generated, the routine glp_netgen
+*  returns zero; otherwise, if specified parameters are inconsistent,
+*  the routine returns a non-zero error code.
+*
+*  REFERENCES
+*
+*  D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating
+*  large scale capacitated assignment, transportation, and minimum cost
+*  flow networks. Management Science 20 (1974), 814-20. */
+
+struct csa
+{     /* common storage area */
+      glp_graph *G;
+      int v_rhs, a_cap, a_cost;
+      int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor,
+         nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl,
+         nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult,
+         modul, i15, i16, jran;
+};
+
+#define G      (csa->G)
+#define v_rhs  (csa->v_rhs)
+#define a_cap  (csa->a_cap)
+#define a_cost (csa->a_cost)
+#define nodes  (csa->nodes)
+#define iarcs  (csa->iarcs)
+#define mincst (csa->mincst)
+#define maxcst (csa->maxcst)
+#define itsup  (csa->itsup)
+#define nsorc  (csa->nsorc)
+#define nsink  (csa->nsink)
+#define nonsor (csa->nonsor)
+#define nfsink (csa->nfsink)
+#define narcs  (csa->narcs)
+#define nsort  (csa->nsort)
+#define nftsor (csa->nftsor)
+#define ipcap  (csa->ipcap)
+#define mincap (csa->mincap)
+#define maxcap (csa->maxcap)
+#define ktl    (csa->ktl)
+#define nodlft (csa->nodlft)
+#if 0
+/* spent a day to find out this bug */
+#define ist    (csa->ist)
+#else
+#define ist    (ipred[0])
+#endif
+#define ipred  (csa->ipred)
+#define ihead  (csa->ihead)
+#define itail  (csa->itail)
+#define iflag  (csa->iflag)
+#define isup   (csa->isup)
+#define lsinks (csa->lsinks)
+#define mult   (csa->mult)
+#define modul  (csa->modul)
+#define i15    (csa->i15)
+#define i16    (csa->i16)
+#define jran   (csa->jran)
+
+static void cresup(struct csa *csa);
+static void chain(struct csa *csa, int lpick, int lsorc);
+static void chnarc(struct csa *csa, int lsorc);
+static void sort(struct csa *csa);
+static void pickj(struct csa *csa, int it);
+static void assign(struct csa *csa);
+static void setran(struct csa *csa, int iseed);
+static int iran(struct csa *csa, int ilow, int ihigh);
+
+int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
+      const int parm[1+15])
+{     struct csa _csa, *csa = &_csa;
+      int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink,
+         ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick,
+         nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap,
+         jcap, icost, jcost, ret;
+      G = G_;
+      v_rhs = _v_rhs;
+      a_cap = _a_cap;
+      a_cost = _a_cost;
+      if (G != NULL)
+      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+            xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs);
+         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+            xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap);
+         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+            xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost);
+      }
+      /* Input the user's random number seed and fix it if
+         non-positive. */
+      iseed = parm[1];
+      nprob = parm[2];
+      if (iseed <= 0) iseed = 13502460;
+      setran(csa, iseed);
+      /* Input the user's problem characteristics. */
+      nodes = parm[3];
+      nsorc = parm[4];
+      nsink = parm[5];
+      iarcs = parm[6];
+      mincst = parm[7];
+      maxcst = parm[8];
+      itsup = parm[9];
+      ntsorc = parm[10];
+      ntsink = parm[11];
+      iphic = parm[12];
+      ipcap = parm[13];
+      mincap = parm[14];
+      maxcap = parm[15];
+      /* Check the size of the problem. */
+      if (!(10 <= nodes && nodes <= 100000))
+      {  ret = 1;
+         goto done;
+      }
+      /* Check user supplied parameters for consistency. */
+      if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes))
+      {  ret = 2;
+         goto done;
+      }
+      if (iarcs < 0)
+      {  ret = 3;
+         goto done;
+      }
+      if (mincst > maxcst)
+      {  ret = 4;
+         goto done;
+      }
+      if (itsup < 0)
+      {  ret = 5;
+         goto done;
+      }
+      if (!(0 <= ntsorc && ntsorc <= nsorc))
+      {  ret = 6;
+         goto done;
+      }
+      if (!(0 <= ntsink && ntsink <= nsink))
+      {  ret = 7;
+         goto done;
+      }
+      if (!(0 <= iphic && iphic <= 100))
+      {  ret = 8;
+         goto done;
+      }
+      if (!(0 <= ipcap && ipcap <= 100))
+      {  ret = 9;
+         goto done;
+      }
+      if (mincap > maxcap)
+      {  ret = 10;
+         goto done;
+      }
+      /* Initailize the graph object. */
+      if (G != NULL)
+      {  glp_erase_graph(G, G->v_size, G->a_size);
+         glp_add_vertices(G, nodes);
+         if (v_rhs >= 0)
+         {  double zero = 0.0;
+            for (i = 1; i <= nodes; i++)
+            {  glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
+            }
+         }
+      }
+      /* Allocate working arrays. */
+      ipred = xcalloc(1+nodes, sizeof(int));
+      ihead = xcalloc(1+nodes, sizeof(int));
+      itail = xcalloc(1+nodes, sizeof(int));
+      iflag = xcalloc(1+nodes, sizeof(int));
+      isup = xcalloc(1+nodes, sizeof(int));
+      lsinks = xcalloc(1+nodes, sizeof(int));
+      /* Print the problem documentation records. */
+      if (G == NULL)
+      {  xprintf("BEGIN\n");
+         xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n",
+            nprob, "", nodes, iarcs);
+         xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%"
+            "11d%11d\n", iseed, nsorc, nsink, mincst,
+            maxcst, itsup, ntsorc, ntsink, iphic, ipcap,
+            mincap, maxcap);
+      }
+      else
+         glp_set_graph_name(G, "NETGEN");
+      /* Set various constants used in the program. */
+      narcs = 0;
+      nskel = 0;
+      nltr = nodes - nsink;
+      ltsink = nltr + ntsink;
+      ntrans = nltr - nsorc;
+      nfsink = nltr + 1;
+      nonsor = nodes - nsorc + ntsorc;
+      npsink = nsink - ntsink;
+      nodlft = nodes - nsink + ntsink;
+      nftr = nsorc + 1;
+      nftsor = nsorc - ntsorc + 1;
+      npsorc = nsorc - ntsorc;
+      /* Randomly distribute the supply among the source nodes. */
+      if (npsorc + npsink == nodes && npsorc == npsink &&
+          itsup == nsorc)
+      {  assign(csa);
+         nskel = nsorc;
+         goto L390;
+      }
+      cresup(csa);
+      /* Print the supply records. */
+      if (G == NULL)
+      {  xprintf("SUPPLY\n");
+         for (i = 1; i <= nsorc; i++)
+            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
+         xprintf("ARCS\n");
+      }
+      else
+      {  if (v_rhs >= 0)
+         {  for (i = 1; i <= nsorc; i++)
+            {  double temp = (double)isup[i];
+               glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      /* Make the sources point to themselves in ipred array. */
+      for (i = 1; i <= nsorc; i++)
+         ipred[i] = i;
+      if (ntrans == 0) goto L170;
+      /* Chain the transshipment nodes together in the ipred array. */
+      ist = nftr;
+      ipred[nltr] = 0;
+      for (i = nftr; i < nltr; i++)
+         ipred[i] = i+1;
+      /* Form even length chains for 60 percent of the transshipments.*/
+      ntravl = 6 * ntrans / 10;
+      ntrrem = ntrans - ntravl;
+L140: lsorc = 1;
+      while (ntravl != 0)
+      {  lpick = iran(csa, 1, ntravl + ntrrem);
+         ntravl--;
+         chain(csa, lpick, lsorc);
+         if (lsorc == nsorc) goto L140;
+         lsorc++;
+      }
+      /* Add the remaining transshipments to the chains. */
+      while (ntrrem != 0)
+      {
+         lpick = iran(csa, 1, ntrrem);
+         ntrrem--;
+         lsorc = iran(csa, 1, nsorc);
+         chain(csa, lpick, lsorc);
+      }
+L170: /* Set all demands equal to zero. */
+      for (i = nfsink; i <= nodes; i++)
+         ipred[i] = 0;
+      /* The following loop takes one chain at a time (through the use
+         of logic contained in the loop and calls to other routines) and
+         creates the remaining network arcs. */
+      for (lsorc = 1; lsorc <= nsorc; lsorc++)
+      {  chnarc(csa, lsorc);
+         for (i = nfsink; i <= nodes; i++)
+            iflag[i] = 0;
+         /* Choose the number of sinks to be hooked up to the current
+            chain. */
+         if (ntrans != 0)
+            nsksr = (nsort * 2 * nsink) / ntrans;
+         else
+            nsksr = nsink / nsorc + 1;
+         if (nsksr < 2) nsksr = 2;
+         if (nsksr > nsink) nsksr = nsink;
+         nsrchn = nsort;
+         /* Randomly pick nsksr sinks and put their names in lsinks. */
+         ktl = nsink;
+         for (j = 1; j <= nsksr; j++)
+         {  item = iran(csa, 1, ktl);
+            ktl--;
+            for (l = nfsink; l <= nodes; l++)
+            {  if (iflag[l] != 1)
+               {  item--;
+                  if (item == 0) goto L230;
+               }
+            }
+            break;
+L230:       lsinks[j] = l;
+            iflag[l] = 1;
+         }
+         /* If last source chain, add all sinks with zero demand to
+            lsinks list. */
+         if (lsorc == nsorc)
+         {  for (j = nfsink; j <= nodes; j++)
+            {  if (ipred[j] == 0 && iflag[j] != 1)
+               {  nsksr++;
+                  lsinks[nsksr] = j;
+                  iflag[j] = 1;
+               }
+            }
+         }
+         /* Create demands for group of sinks in lsinks. */
+         ks = isup[lsorc] / nsksr;
+         k = ipred[lsorc];
+         for (i = 1; i <= nsksr; i++)
+         {  nsort++;
+            ksp = iran(csa, 1, ks);
+            j = iran(csa, 1, nsksr);
+            itail[nsort] = k;
+            li = lsinks[i];
+            ihead[nsort] = li;
+            ipred[li] += ksp;
+            li = lsinks[j];
+            ipred[li] += ks - ksp;
+            n = iran(csa, 1, nsrchn);
+            k = lsorc;
+            for (ii = 1; ii <= n; ii++)
+               k = ipred[k];
+         }
+         li = lsinks[1];
+         ipred[li] += isup[lsorc] - ks * nsksr;
+         nskel += nsort;
+         /* Sort the arcs in the chain from source lsorc using itail as
+            sort key. */
+         sort(csa);
+         /* Print this part of skeleton and create the arcs for these
+            nodes. */
+         i = 1;
+         itail[nsort+1] = 0;
+L300:    for (j = nftsor; j <= nodes; j++)
+            iflag[j] = 0;
+         ktl = nonsor - 1;
+         it = itail[i];
+         iflag[it] = 1;
+L320:    ih = ihead[i];
+         iflag[ih] = 1;
+         narcs++;
+         ktl--;
+         /* Determine if this skeleton arc should be capacitated. */
+         icap = itsup;
+         jcap = iran(csa, 1, 100);
+         if (jcap <= ipcap)
+         {  icap = isup[lsorc];
+            if (mincap > icap) icap = mincap;
+         }
+         /* Determine if this skeleton arc should have the maximum
+            cost. */
+         icost = maxcst;
+         jcost = iran(csa, 1, 100);
+         if (jcost > iphic)
+            icost = iran(csa, mincst, maxcst);
+         if (G == NULL)
+            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost,
+               icap);
+         else
+         {  glp_arc *a = glp_add_arc(G, it, ih);
+            if (a_cap >= 0)
+            {  double temp = (double)icap;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)icost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+         i++;
+         if (itail[i] == it) goto L320;
+         pickj(csa, it);
+         if (i <= nsort) goto L300;
+      }
+      /* Create arcs from the transshipment sinks. */
+      if (ntsink != 0)
+      {  for (i = nfsink; i <= ltsink; i++)
+         {  for (j = nftsor; j <= nodes; j++)
+               iflag[j] = 0;
+            ktl = nonsor - 1;
+            iflag[i] = 1;
+            pickj(csa, i);
+         }
+      }
+L390: /* Print the demand records and end record. */
+      if (G == NULL)
+      {  xprintf("DEMAND\n");
+         for (i = nfsink; i <= nodes; i++)
+            xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]);
+         xprintf("END\n");
+      }
+      else
+      {  if (v_rhs >= 0)
+         {  for (i = nfsink; i <= nodes; i++)
+            {  double temp = - (double)ipred[i];
+               glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      /* Free working arrays. */
+      xfree(ipred);
+      xfree(ihead);
+      xfree(itail);
+      xfree(iflag);
+      xfree(isup);
+      xfree(lsinks);
+      /* The instance has been successfully generated. */
+      ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+*  The routine cresup randomly distributes the total supply among the
+*  source nodes. */
+
+static void cresup(struct csa *csa)
+{     int i, j, ks, ksp;
+      xassert(itsup > nsorc);
+      ks = itsup / nsorc;
+      for (i = 1; i <= nsorc; i++)
+         isup[i] = 0;
+      for (i = 1; i <= nsorc; i++)
+      {  ksp = iran(csa, 1, ks);
+         j = iran(csa, 1, nsorc);
+         isup[i] += ksp;
+         isup[j] += ks - ksp;
+      }
+      j = iran(csa, 1, nsorc);
+      isup[j] += itsup - ks * nsorc;
+      return;
+}
+
+/***********************************************************************
+*  The routine chain adds node lpick to the end of the chain with source
+*  node lsorc. */
+
+static void chain(struct csa *csa, int lpick, int lsorc)
+{     int i, j, k, l, m;
+      k = 0;
+      m = ist;
+      for (i = 1; i <= lpick; i++)
+      {  l = k;
+         k = m;
+         m = ipred[k];
+      }
+      ipred[l] = m;
+      j = ipred[lsorc];
+      ipred[k] = j;
+      ipred[lsorc] = k;
+      return;
+}
+
+/***********************************************************************
+*  The routine chnarc puts the arcs in the chain from source lsorc into
+*  the ihead and itail arrays for sorting. */
+
+static void chnarc(struct csa *csa, int lsorc)
+{     int ito, ifrom;
+      nsort = 0;
+      ito = ipred[lsorc];
+L10:  if (ito == lsorc) return;
+      nsort++;
+      ifrom = ipred[ito];
+      ihead[nsort] = ito;
+      itail[nsort] = ifrom;
+      ito = ifrom;
+      goto L10;
+}
+
+/***********************************************************************
+*  The routine sort sorts the nsort arcs in the ihead and itail arrays.
+*  ihead is used as the sort key (i.e. forward star sort order). */
+
+static void sort(struct csa *csa)
+{     int i, j, k, l, m, n, it;
+      n = nsort;
+      m = n;
+L10:  m /= 2;
+      if (m == 0) return;
+      k = n - m;
+      j = 1;
+L20:  i = j;
+L30:  l = i + m;
+      if (itail[i] <= itail[l]) goto L40;
+      it = itail[i];
+      itail[i] = itail[l];
+      itail[l] = it;
+      it = ihead[i];
+      ihead[i] = ihead[l];
+      ihead[l] = it;
+      i -= m;
+      if (i >= 1) goto L30;
+L40:  j++;
+      if (j <= k) goto L20;
+      goto L10;
+}
+
+/***********************************************************************
+*  The routine pickj creates a random number of arcs out of node 'it'.
+*  Various parameters are dynamically adjusted in an attempt to ensure
+*  that the generated network has the correct number of arcs. */
+
+static void pickj(struct csa *csa, int it)
+{     int j, k, l, nn, nupbnd, icap, jcap, icost;
+      if ((nodlft - 1) * 2 > iarcs - narcs - 1)
+      {  nodlft--;
+         return;
+      }
+      if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0)
+         k = nonsor;
+      else
+      {  nupbnd = (iarcs - narcs - nodlft) / nodlft * 2;
+L40:     k = iran(csa, 1, nupbnd);
+         if (nodlft == 1) k = iarcs - narcs;
+         if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40;
+      }
+      nodlft--;
+      for (j = 1; j <= k; j++)
+      {  nn = iran(csa, 1, ktl);
+         ktl--;
+         for (l = nftsor; l <= nodes; l++)
+         {  if (iflag[l] != 1)
+            {  nn--;
+               if (nn == 0) goto L70;
+            }
+         }
+         return;
+L70:     iflag[l] = 1;
+         icap = itsup;
+         jcap = iran(csa, 1, 100);
+         if (jcap <= ipcap)
+            icap = iran(csa, mincap, maxcap);
+         icost = iran(csa, mincst, maxcst);
+         if (G == NULL)
+            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost,
+               icap);
+         else
+         {  glp_arc *a = glp_add_arc(G, it, l);
+            if (a_cap >= 0)
+            {  double temp = (double)icap;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)icost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+         narcs++;
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine assign generate assignment problems. It defines the unit
+*  supplies, builds a skeleton, then calls pickj to create the arcs. */
+
+static void assign(struct csa *csa)
+{     int i, it, nn, l, ll, icost;
+      if (G == NULL)
+         xprintf("SUPPLY\n");
+      for (i = 1; i <= nsorc; i++)
+      {  isup[i] = 1;
+         iflag[i] = 0;
+         if (G == NULL)
+            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
+         else
+         {  if (v_rhs >= 0)
+            {  double temp = (double)isup[i];
+               glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      if (G == NULL)
+         xprintf("ARCS\n");
+      for (i = nfsink; i <= nodes; i++)
+         ipred[i] = 1;
+      for (it = 1; it <= nsorc; it++)
+      {  for (i = nfsink; i <= nodes; i++)
+            iflag[i] = 0;
+         ktl = nsink - 1;
+         nn = iran(csa, 1, nsink - it + 1);
+         for (l = 1; l <= nsorc; l++)
+         {  if (iflag[l] != 1)
+            {  nn--;
+               if (nn == 0) break;
+            }
+         }
+         narcs++;
+         ll = nsorc + l;
+         icost = iran(csa, mincst, maxcst);
+         if (G == NULL)
+            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost,
+               isup[1]);
+         else
+         {  glp_arc *a = glp_add_arc(G, it, ll);
+            if (a_cap >= 0)
+            {  double temp = (double)isup[1];
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)icost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+         iflag[l] = 1;
+         iflag[ll] = 1;
+         pickj(csa, it);
+      }
+      return;
+}
+
+/***********************************************************************
+*  Portable congruential (uniform) random number generator:
+*
+*     next_value = ((7**5) * previous_value) modulo ((2**31)-1)
+*
+*  This generator consists of three routines:
+*
+*  (1) setran - initializes constants and seed
+*  (2) iran   - generates an integer random number
+*  (3) rran   - generates a real random number
+*
+*  The generator requires a machine with at least 32 bits of precision.
+*  The seed (iseed) must be in the range [1,(2**31)-1]. */
+
+static void setran(struct csa *csa, int iseed)
+{     xassert(iseed >= 1);
+      mult = 16807;
+      modul = 2147483647;
+      i15 = 1 << 15;
+      i16 = 1 << 16;
+      jran = iseed;
+      return;
+}
+
+/***********************************************************************
+*  The routine iran generates an integer random number between ilow and
+*  ihigh. If ilow > ihigh then iran returns ihigh. */
+
+static int iran(struct csa *csa, int ilow, int ihigh)
+{     int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover,
+         irthi, j;
+      ixhi = jran / i16;
+      ixlo = jran - ixhi * i16;
+      ixalo = ixlo * mult;
+      leftlo = ixalo / i16;
+      ixahi = ixhi * mult;
+      ifulhi = ixahi + leftlo;
+      irtlo = ixalo - leftlo * i16;
+      iover = ifulhi / i15;
+      irthi = ifulhi - iover * i15;
+      jran = ((irtlo - modul) + irthi * i16) + iover;
+      if (jran < 0) jran += modul;
+      j = ihigh - ilow + 1;
+      if (j > 0)
+         return jran % j + ilow;
+      else
+         return ihigh;
+}
+
+/**********************************************************************/
+
+#if 0
+static int scan(char card[80+1], int pos, int len)
+{     char buf[10+1];
+      memcpy(buf, &card[pos-1], len);
+      buf[len] = '\0';
+      return atoi(buf);
+}
+
+int main(void)
+{     int parm[1+15];
+      char card[80+1];
+      xassert(fgets(card, sizeof(card), stdin) == card);
+      parm[1] = scan(card, 1, 8);
+      parm[2] = scan(card, 9, 8);
+      xassert(fgets(card, sizeof(card), stdin) == card);
+      parm[3] = scan(card, 1, 5);
+      parm[4] = scan(card, 6, 5);
+      parm[5] = scan(card, 11, 5);
+      parm[6] = scan(card, 16, 5);
+      parm[7] = scan(card, 21, 5);
+      parm[8] = scan(card, 26, 5);
+      parm[9] = scan(card, 31, 10);
+      parm[10] = scan(card, 41, 5);
+      parm[11] = scan(card, 46, 5);
+      parm[12] = scan(card, 51, 5);
+      parm[13] = scan(card, 56, 5);
+      parm[14] = scan(card, 61, 10);
+      parm[15] = scan(card, 71, 10);
+      glp_netgen(NULL, 0, 0, 0, parm);
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnet04.c b/optional/glpk/glpnet04.c
new file mode 100644
index 0000000..81cb9e7
--- /dev/null
+++ b/optional/glpk/glpnet04.c
@@ -0,0 +1,772 @@
+/* glpnet04.c (grid-like network problem generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is a modified version of the program GRIDGEN, a grid-like
+*  network problem generator developed by Yusin Lee and Jim Orlin.
+*  The original code is publically available on the DIMACS ftp site at:
+*  <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>.
+*
+*  All changes concern only the program interface, so this modified
+*  version produces exactly the same instances as the original version.
+*
+*  Changes were made by Andrew Makhorin <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 "-Wlogical-op-parentheses"
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_gridgen - grid-like network problem generator
+*
+*  SYNOPSIS
+*
+*  int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+*     const int parm[1+14]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_gridgen is a grid-like network problem generator
+*  developed by Yusin Lee and Jim Orlin.
+*
+*  The parameter G specifies the graph object, to which the generated
+*  problem data have to be stored. Note that on entry the graph object
+*  is erased with the routine glp_erase_graph.
+*
+*  The parameter v_rhs specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores the supply or
+*  demand value. If v_rhs < 0, the value is not stored.
+*
+*  The parameter a_cap specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the arc capacity.
+*  If a_cap < 0, the capacity is not stored.
+*
+*  The parameter a_cost specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the per-unit cost
+*  if the arc flow. If a_cost < 0, the cost is not stored.
+*
+*  The array parm contains description of the network to be generated:
+*
+*  parm[0]  not used
+*  parm[1]  two-ways arcs indicator:
+*           1 - if links in both direction should be generated
+*           0 - otherwise
+*  parm[2]  random number seed (a positive integer)
+*  parm[3]  number of nodes (the number of nodes generated might be
+*           slightly different to make the network a grid)
+*  parm[4]  grid width
+*  parm[5]  number of sources
+*  parm[6]  number of sinks
+*  parm[7]  average degree
+*  parm[8]  total flow
+*  parm[9]  distribution of arc costs:
+*           1 - uniform
+*           2 - exponential
+*  parm[10] lower bound for arc cost (uniform)
+*           100 * lambda (exponential)
+*  parm[11] upper bound for arc cost (uniform)
+*           not used (exponential)
+*  parm[12] distribution of arc capacities:
+*           1 - uniform
+*           2 - exponential
+*  parm[13] lower bound for arc capacity (uniform)
+*           100 * lambda (exponential)
+*  parm[14] upper bound for arc capacity (uniform)
+*           not used (exponential)
+*
+*  RETURNS
+*
+*  If the instance was successfully generated, the routine glp_gridgen
+*  returns zero; otherwise, if specified parameters are inconsistent,
+*  the routine returns a non-zero error code.
+*
+*  COMMENTS
+*
+*  This network generator generates a grid-like network plus a super
+*  node. In additional to the arcs connecting the nodes in the grid,
+*  there is an arc from each supply node to the super node and from the
+*  super node to each demand node to guarantee feasiblity. These arcs
+*  have very high costs and very big capacities.
+*
+*  The idea of this network generator is as follows: First, a grid of
+*  n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as
+*  1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between
+*  adjacent nodes are generated. For these arcs, the user is allowed to
+*  specify either to generate two-way arcs or one-way arcs. If two-way
+*  arcs are to be generated, two arcs, one in each direction, will be
+*  generated between each adjacent node pairs. Otherwise, only one arc
+*  will be generated. If this is the case, the arcs will be generated
+*  in alterntive directions as shown below.
+*
+*      1 ---> 2 ---> 3 ---> 4 ---> 5
+*      |      ^      |      ^      |
+*      |      |      |      |      |
+*      V      |      V      |      V
+*      6 <--- 7 <--- 8 <--- 9 <--- 10
+*      |      ^      |      ^      |
+*      |      |      |      |      |
+*      V      |      V      |      V
+*     11 --->12 --->13 --->14 ---> 15
+*
+*  Then the arcs between the super node and the source/sink nodes are
+*  added as mentioned before. If the number of arcs still doesn't reach
+*  the requirement, additional arcs will be added by uniformly picking
+*  random node pairs. There is no checking to prevent multiple arcs
+*  between any pair of nodes. However, there will be no self-arcs (arcs
+*  that poins back to its tail node) in the network.
+*
+*  The source and sink nodes are selected uniformly in the network, and
+*  the imbalances of each source/sink node are also assigned by uniform
+*  distribution. */
+
+struct stat_para
+{     /* structure for statistical distributions */
+      int distribution;
+      /* the distribution: */
+#define UNIFORM      1  /* uniform distribution */
+#define EXPONENTIAL  2  /* exponential distribution */
+      double parameter[5];
+      /* the parameters of the distribution */
+};
+
+struct arcs
+{     int from;
+      /* the FROM node of that arc */
+      int to;
+      /* the TO node of that arc */
+      int cost;
+      /* original cost of that arc */
+      int u;
+      /* capacity of the arc */
+};
+
+struct imbalance
+{     int node;
+      /* Node ID */
+      int supply;
+      /* Supply of that node */
+};
+
+struct csa
+{     /* common storage area */
+      glp_graph *G;
+      int v_rhs, a_cap, a_cost;
+      int seed;
+      /* random number seed */
+      int seed_original;
+      /* the original seed from input */
+      int two_way;
+      /* 0: generate arcs in both direction for the basic grid, except
+         for the arcs to/from the super node.  1: o/w */
+      int n_node;
+      /* total number of nodes in the network, numbered 1 to n_node,
+         including the super node, which is the last one */
+      int n_arc;
+      /* total number of arcs in the network, counting EVERY arc. */
+      int n_grid_arc;
+      /* number of arcs in the basic grid, including the arcs to/from
+         the super node */
+      int n_source, n_sink;
+      /* number of source and sink nodes */
+      int avg_degree;
+      /* average degree, arcs to and from the super node are counted */
+      int t_supply;
+      /* total supply in the network */
+      int n1, n2;
+      /* the two edges of the network grid.  n1 >= n2 */
+      struct imbalance *source_list, *sink_list;
+      /* head of the array of source/sink nodes */
+      struct stat_para arc_costs;
+      /* the distribution of arc costs */
+      struct stat_para capacities;
+      /* distribution of the capacities of the arcs */
+      struct arcs *arc_list;
+      /* head of the arc list array.  Arcs in this array are in the
+         order of grid_arcs, arcs to/from super node, and other arcs */
+};
+
+#define G (csa->G)
+#define v_rhs (csa->v_rhs)
+#define a_cap (csa->a_cap)
+#define a_cost (csa->a_cost)
+#define seed (csa->seed)
+#define seed_original (csa->seed_original)
+#define two_way (csa->two_way)
+#define n_node (csa->n_node)
+#define n_arc (csa->n_arc)
+#define n_grid_arc (csa->n_grid_arc)
+#define n_source (csa->n_source)
+#define n_sink (csa->n_sink)
+#define avg_degree (csa->avg_degree)
+#define t_supply (csa->t_supply)
+#define n1 (csa->n1)
+#define n2 (csa->n2)
+#define source_list (csa->source_list)
+#define sink_list (csa->sink_list)
+#define arc_costs (csa->arc_costs)
+#define capacities (csa->capacities)
+#define arc_list (csa->arc_list)
+
+static void assign_capacities(struct csa *csa);
+static void assign_costs(struct csa *csa);
+static void assign_imbalance(struct csa *csa);
+static int exponential(struct csa *csa, double lambda[1]);
+static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
+      *arc_ptr);
+static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
+      *arc_ptr);
+static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr);
+static void generate(struct csa *csa);
+static void output(struct csa *csa);
+static double randy(struct csa *csa);
+static void select_source_sinks(struct csa *csa);
+static int uniform(struct csa *csa, double a[2]);
+
+int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
+      const int parm[1+14])
+{     struct csa _csa, *csa = &_csa;
+      int n, ret;
+      G = G_;
+      v_rhs = _v_rhs;
+      a_cap = _a_cap;
+      a_cost = _a_cost;
+      if (G != NULL)
+      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+            xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs);
+         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+            xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap);
+         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+            xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost)
+               ;
+      }
+      /* Check the parameters for consistency. */
+      if (!(parm[1] == 0 || parm[1] == 1))
+      {  ret = 1;
+         goto done;
+      }
+      if (parm[2] < 1)
+      {  ret = 2;
+         goto done;
+      }
+      if (!(10 <= parm[3] && parm[3] <= 40000))
+      {  ret = 3;
+         goto done;
+      }
+      if (!(1 <= parm[4] && parm[4] <= 40000))
+      {  ret = 4;
+         goto done;
+      }
+      if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <=
+         parm[3]))
+      {  ret = 5;
+         goto done;
+      }
+      if (!(1 <= parm[7] && parm[7] <= parm[3]))
+      {  ret = 6;
+         goto done;
+      }
+      if (parm[8] < 0)
+      {  ret = 7;
+         goto done;
+      }
+      if (!(parm[9] == 1 || parm[9] == 2))
+      {  ret = 8;
+         goto done;
+      }
+      if (parm[9] == 1 && parm[10] > parm[11] ||
+          parm[9] == 2 && parm[10] < 1)
+      {  ret = 9;
+         goto done;
+      }
+      if (!(parm[12] == 1 || parm[12] == 2))
+      {  ret = 10;
+         goto done;
+      }
+      if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) ||
+          parm[12] == 2 && parm[13] < 1)
+      {  ret = 11;
+         goto done;
+      }
+      /* Initialize the graph object. */
+      if (G != NULL)
+      {  glp_erase_graph(G, G->v_size, G->a_size);
+         glp_set_graph_name(G, "GRIDGEN");
+      }
+      /* Copy the generator parameters. */
+      two_way = parm[1];
+      seed_original = seed = parm[2];
+      n_node = parm[3];
+      n = parm[4];
+      n_source = parm[5];
+      n_sink = parm[6];
+      avg_degree = parm[7];
+      t_supply = parm[8];
+      arc_costs.distribution = parm[9];
+      if (parm[9] == 1)
+      {  arc_costs.parameter[0] = parm[10];
+         arc_costs.parameter[1] = parm[11];
+      }
+      else
+      {  arc_costs.parameter[0] = (double)parm[10] / 100.0;
+         arc_costs.parameter[1] = 0.0;
+      }
+      capacities.distribution = parm[12];
+      if (parm[12] == 1)
+      {  capacities.parameter[0] = parm[13];
+         capacities.parameter[1] = parm[14];
+      }
+      else
+      {  capacities.parameter[0] = (double)parm[13] / 100.0;
+         capacities.parameter[1] = 0.0;
+      }
+      /* Calculate the edge lengths of the grid according to the
+         input. */
+      if (n * n >= n_node)
+      {  n1 = n;
+         n2 = (int)((double)n_node / (double)n + 0.5);
+      }
+      else
+      {  n2 = n;
+         n1 = (int)((double)n_node / (double)n + 0.5);
+      }
+      /* Recalculate the total number of nodes and plus 1 for the super
+         node. */
+      n_node = n1 * n2 + 1;
+      n_arc = n_node * avg_degree;
+      n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) +
+         n_source + n_sink;
+      if (n_grid_arc > n_arc) n_arc = n_grid_arc;
+      arc_list = xcalloc(n_arc, sizeof(struct arcs));
+      source_list = xcalloc(n_source, sizeof(struct imbalance));
+      sink_list = xcalloc(n_sink, sizeof(struct imbalance));
+      /* Generate a random network. */
+      generate(csa);
+      /* Output the network. */
+      output(csa);
+      /* Free all allocated memory. */
+      xfree(arc_list);
+      xfree(source_list);
+      xfree(sink_list);
+      /* The instance has been successfully generated. */
+      ret = 0;
+done: return ret;
+}
+
+#undef random
+
+static void assign_capacities(struct csa *csa)
+{     /* Assign a capacity to each arc. */
+      struct arcs *arc_ptr = arc_list;
+      int (*random)(struct csa *csa, double *);
+      int i;
+      /* Determine the random number generator to use. */
+      switch (arc_costs.distribution)
+      {  case UNIFORM:
+            random = uniform;
+            break;
+         case EXPONENTIAL:
+            random = exponential;
+            break;
+         default:
+            xassert(csa != csa);
+      }
+      /* Assign capacities to grid arcs. */
+      for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
+         arc_ptr->u = random(csa, capacities.parameter);
+      i = i - n_source - n_sink;
+      /* Assign capacities to arcs to/from supernode. */
+      for (; i < n_grid_arc; i++, arc_ptr++)
+         arc_ptr->u = t_supply;
+      /* Assign capacities to all other arcs. */
+      for (; i < n_arc; i++, arc_ptr++)
+         arc_ptr->u = random(csa, capacities.parameter);
+      return;
+}
+
+static void assign_costs(struct csa *csa)
+{     /* Assign a cost to each arc. */
+      struct arcs *arc_ptr = arc_list;
+      int (*random)(struct csa *csa, double *);
+      int i;
+      /* A high cost assigned to arcs to/from the supernode. */
+      int high_cost;
+      /* The maximum cost assigned to arcs in the base grid. */
+      int max_cost = 0;
+      /* Determine the random number generator to use. */
+      switch (arc_costs.distribution)
+      {  case UNIFORM:
+            random = uniform;
+            break;
+         case EXPONENTIAL:
+            random = exponential;
+            break;
+         default:
+            xassert(csa != csa);
+      }
+      /* Assign costs to arcs in the base grid. */
+      for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
+      {  arc_ptr->cost = random(csa, arc_costs.parameter);
+         if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost;
+      }
+      i = i - n_source - n_sink;
+      /* Assign costs to arcs to/from the super node. */
+      high_cost = max_cost * 2;
+      for (; i < n_grid_arc; i++, arc_ptr++)
+         arc_ptr->cost = high_cost;
+      /* Assign costs to all other arcs. */
+      for (; i < n_arc; i++, arc_ptr++)
+         arc_ptr->cost = random(csa, arc_costs.parameter);
+      return;
+}
+
+static void assign_imbalance(struct csa *csa)
+{     /* Assign an imbalance to each node. */
+      int total, i;
+      double avg;
+      struct imbalance *ptr;
+      /* assign the supply nodes */
+      avg = 2.0 * t_supply / n_source;
+      do
+      {  for (i = 1, total = t_supply, ptr = source_list + 1;
+            i < n_source; i++, ptr++)
+         {  ptr->supply = (int)(randy(csa) * avg + 0.5);
+            total -= ptr->supply;
+         }
+         source_list->supply = total;
+      }
+      /* redo all if the assignment "overshooted" */
+      while (total <= 0);
+      /* assign the demand nodes */
+      avg = -2.0 * t_supply / n_sink;
+      do
+      {  for (i = 1, total = t_supply, ptr = sink_list + 1;
+            i < n_sink; i++, ptr++)
+         {  ptr->supply = (int)(randy(csa) * avg - 0.5);
+            total += ptr->supply;
+         }
+         sink_list->supply = - total;
+      }
+      while (total <= 0);
+      return;
+}
+
+static int exponential(struct csa *csa, double lambda[1])
+{     /* Returns an "exponentially distributed" integer with parameter
+         lambda. */
+      return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5));
+}
+
+static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
+      *arc_ptr)
+{     /* Generate an arc from each source to the supernode and from
+         supernode to each sink. */
+      int i;
+      for (i = 0; i < n_source; i++, arc_ptr++)
+      {  arc_ptr->from = source_list[i].node;
+         arc_ptr->to = n_node;
+      }
+      for (i = 0; i < n_sink; i++, arc_ptr++)
+      {  arc_ptr->to = sink_list[i].node;
+         arc_ptr->from = n_node;
+      }
+      return arc_ptr;
+}
+
+static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
+      *arc_ptr)
+{     /* Generate the basic grid. */
+      int direction = 1, i, j, k;
+      if (two_way)
+      {  /* Generate an arc in each direction. */
+         for (i = 1; i < n_node; i += n1)
+         {  for (j = i, k = j + n1 - 1; j < k; j++)
+            {  arc_ptr->from = j;
+               arc_ptr->to = j + 1;
+               arc_ptr++;
+               arc_ptr->from = j + 1;
+               arc_ptr->to = j;
+               arc_ptr++;
+            }
+         }
+         for (i = 1; i <= n1; i++)
+         {  for (j = i + n1; j < n_node; j += n1)
+            {  arc_ptr->from = j;
+               arc_ptr->to = j - n1;
+               arc_ptr++;
+               arc_ptr->from = j - n1;
+               arc_ptr->to = j;
+               arc_ptr++;
+            }
+         }
+      }
+      else
+      {  /* Generate one arc in each direction. */
+         for (i = 1; i < n_node; i += n1)
+         {  if (direction == 1)
+               j = i;
+            else
+               j = i + 1;
+            for (k = j + n1 - 1; j < k; j++)
+            {  arc_ptr->from = j;
+               arc_ptr->to = j + direction;
+               arc_ptr++;
+            }
+            direction = - direction;
+         }
+         for (i = 1; i <= n1; i++)
+         {  j = i + n1;
+            if (direction == 1)
+            {  for (; j < n_node; j += n1)
+               {  arc_ptr->from = j - n1;
+                  arc_ptr->to = j;
+                  arc_ptr++;
+               }
+            }
+            else
+            {  for (; j < n_node; j += n1)
+               {  arc_ptr->from = j - n1;
+                  arc_ptr->to = j;
+                  arc_ptr++;
+               }
+            }
+            direction = - direction;
+         }
+      }
+      return arc_ptr;
+}
+
+static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr)
+{     /* Generate random arcs to meet the specified density. */
+      int i;
+      double ab[2];
+      ab[0] = 0.9;
+      ab[1] = n_node - 0.99;  /* upper limit is n_node-1 because the
+                                 supernode cannot be selected */
+      for (i = n_grid_arc; i < n_arc; i++, arc_ptr++)
+      {  arc_ptr->from = uniform(csa, ab);
+         arc_ptr->to = uniform(csa, ab);
+         if (arc_ptr->from == arc_ptr->to)
+         {  arc_ptr--;
+            i--;
+         }
+      }
+      return;
+}
+
+static void generate(struct csa *csa)
+{     /* Generate a random network. */
+      struct arcs *arc_ptr = arc_list;
+      arc_ptr = gen_basic_grid(csa, arc_ptr);
+      select_source_sinks(csa);
+      arc_ptr = gen_additional_arcs(csa, arc_ptr);
+      gen_more_arcs(csa, arc_ptr);
+      assign_costs(csa);
+      assign_capacities(csa);
+      assign_imbalance(csa);
+      return;
+}
+
+static void output(struct csa *csa)
+{     /* Output the network in DIMACS format. */
+      struct arcs *arc_ptr;
+      struct imbalance *imb_ptr;
+      int i;
+      if (G != NULL) goto skip;
+      /* Output "c", "p" records. */
+      xprintf("c generated by GRIDGEN\n");
+      xprintf("c seed %d\n", seed_original);
+      xprintf("c nodes %d\n", n_node);
+      xprintf("c grid size %d X %d\n", n1, n2);
+      xprintf("c sources %d sinks %d\n", n_source, n_sink);
+      xprintf("c avg. degree %d\n", avg_degree);
+      xprintf("c supply %d\n", t_supply);
+      switch (arc_costs.distribution)
+      {  case UNIFORM:
+            xprintf("c arc costs: UNIFORM distr. min %d max %d\n",
+               (int)arc_costs.parameter[0],
+               (int)arc_costs.parameter[1]);
+            break;
+         case EXPONENTIAL:
+            xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n",
+               (int)arc_costs.parameter[0]);
+            break;
+         default:
+            xassert(csa != csa);
+      }
+      switch (capacities.distribution)
+      {  case UNIFORM:
+            xprintf("c arc caps :  UNIFORM distr. min %d max %d\n",
+               (int)capacities.parameter[0],
+               (int)capacities.parameter[1]);
+            break;
+         case EXPONENTIAL:
+            xprintf("c arc caps :  EXPONENTIAL distr. %d lambda %d\n",
+               (int)capacities.parameter[0]);
+            break;
+         default:
+            xassert(csa != csa);
+      }
+skip: if (G == NULL)
+         xprintf("p min %d %d\n", n_node, n_arc);
+      else
+      {  glp_add_vertices(G, n_node);
+         if (v_rhs >= 0)
+         {  double zero = 0.0;
+            for (i = 1; i <= n_node; i++)
+            {  glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
+            }
+         }
+      }
+      /* Output "n node supply". */
+      for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++)
+      {  if (G == NULL)
+            xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
+         else
+         {  if (v_rhs >= 0)
+            {  double temp = (double)imb_ptr->supply;
+               glp_vertex *v = G->v[imb_ptr->node];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++)
+      {  if (G == NULL)
+            xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
+         else
+         {  if (v_rhs >= 0)
+            {  double temp = (double)imb_ptr->supply;
+               glp_vertex *v = G->v[imb_ptr->node];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      /* Output "a from to lowcap=0 hicap cost". */
+      for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++)
+      {  if (G == NULL)
+            xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to,
+               arc_ptr->u, arc_ptr->cost);
+         else
+         {  glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to);
+            if (a_cap >= 0)
+            {  double temp = (double)arc_ptr->u;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)arc_ptr->cost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+      }
+      return;
+}
+
+static double randy(struct csa *csa)
+{     /* Returns a random number between 0.0 and 1.0.
+         See Ward Cheney & David Kincaid, "Numerical Mathematics and
+         Computing," 2Ed, pp. 335. */
+      seed = 16807 * seed % 2147483647;
+      if (seed < 0) seed = - seed;
+      return seed * 4.6566128752459e-10;
+}
+
+static void select_source_sinks(struct csa *csa)
+{     /* Randomly select the source nodes and sink nodes. */
+      int i, *int_ptr;
+      int *temp_list;   /* a temporary list of nodes */
+      struct imbalance *ptr;
+      double ab[2];     /* parameter for random number generator */
+      ab[0] = 0.9;
+      ab[1] = n_node - 0.99;  /* upper limit is n_node-1 because the
+                                 supernode cannot be selected */
+      temp_list = xcalloc(n_node, sizeof(int));
+      for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++)
+         *int_ptr = 0;
+      /* Select the source nodes. */
+      for (i = 0, ptr = source_list; i < n_source; i++, ptr++)
+      {  ptr->node = uniform(csa, ab);
+         if (temp_list[ptr->node] == 1) /* check for duplicates */
+         {  ptr--;
+            i--;
+         }
+         else
+            temp_list[ptr->node] = 1;
+      }
+      /* Select the sink nodes. */
+      for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++)
+      {  ptr->node = uniform(csa, ab);
+         if (temp_list[ptr->node] == 1)
+         {  ptr--;
+            i--;
+         }
+         else
+            temp_list[ptr->node] = 1;
+      }
+      xfree(temp_list);
+      return;
+}
+
+int uniform(struct csa *csa, double a[2])
+{     /* Generates an integer uniformly selected from [a[0],a[1]]. */
+      return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5);
+}
+
+/**********************************************************************/
+
+#if 0
+int main(void)
+{     int parm[1+14];
+      double temp;
+      scanf("%d", &parm[1]);
+      scanf("%d", &parm[2]);
+      scanf("%d", &parm[3]);
+      scanf("%d", &parm[4]);
+      scanf("%d", &parm[5]);
+      scanf("%d", &parm[6]);
+      scanf("%d", &parm[7]);
+      scanf("%d", &parm[8]);
+      scanf("%d", &parm[9]);
+      if (parm[9] == 1)
+      {  scanf("%d", &parm[10]);
+         scanf("%d", &parm[11]);
+      }
+      else
+      {  scanf("%le", &temp);
+         parm[10] = (int)(100.0 * temp + .5);
+         parm[11] = 0;
+      }
+      scanf("%d", &parm[12]);
+      if (parm[12] == 1)
+      {  scanf("%d", &parm[13]);
+         scanf("%d", &parm[14]);
+      }
+      else
+      {  scanf("%le", &temp);
+         parm[13] = (int)(100.0 * temp + .5);
+         parm[14] = 0;
+      }
+      glp_gridgen(NULL, 0, 0, 0, parm);
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnet05.c b/optional/glpk/glpnet05.c
new file mode 100644
index 0000000..d745b86
--- /dev/null
+++ b/optional/glpk/glpnet05.c
@@ -0,0 +1,367 @@
+/* glpnet05.c (Goldfarb's maximum flow problem generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is a modified version of the program RMFGEN, a maxflow
+*  problem generator developed by D.Goldfarb and M.Grigoriadis, and
+*  originally implemented by Tamas Badics <badics at rutcor.rutgers.edu>.
+*  The original code is publically available on the DIMACS ftp site at:
+*  <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>.
+*
+*  All changes concern only the program interface, so this modified
+*  version produces exactly the same instances as the original version.
+*
+*  Changes were made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glprng.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_rmfgen - Goldfarb's maximum flow problem generator
+*
+*  SYNOPSIS
+*
+*  int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+*     const int parm[1+5]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_rmfgen is a maximum flow problem generator developed
+*  by D.Goldfarb and M.Grigoriadis.
+*
+*  The parameter G specifies the graph object, to which the generated
+*  problem data have to be stored. Note that on entry the graph object
+*  is erased with the routine glp_erase_graph.
+*
+*  The pointer s specifies a location, to which the routine stores the
+*  source node number. If s is NULL, the node number is not stored.
+*
+*  The pointer t specifies a location, to which the routine stores the
+*  sink node number. If t is NULL, the node number is not stored.
+*
+*  The parameter a_cap specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the arc capacity.
+*  If a_cap < 0, the capacity is not stored.
+*
+*  The array parm contains description of the network to be generated:
+*
+*  parm[0]  not used
+*  parm[1]  (seed)   random number seed (a positive integer)
+*  parm[2]  (a)      frame size
+*  parm[3]  (b)      depth
+*  parm[4]  (c1)     minimal arc capacity
+*  parm[5]  (c2)     maximal arc capacity
+*
+*  RETURNS
+*
+*  If the instance was successfully generated, the routine glp_netgen
+*  returns zero; otherwise, if specified parameters are inconsistent,
+*  the routine returns a non-zero error code.
+*
+*  COMMENTS
+*
+*  The generated network is as follows. It has b pieces of frames of
+*  size a * a. (So alltogether the number of vertices is a * a * b)
+*
+*  In each frame all the vertices are connected with their neighbours
+*  (forth and back). In addition the vertices of a frame are connected
+*  one to one with the vertices of next frame using a random permutation
+*  of those vertices.
+*
+*  The source is the lower left vertex of the first frame, the sink is
+*  the upper right vertex of the b'th frame.
+*
+*                    t
+*           +-------+
+*           |      .|
+*           |     . |
+*        /  |    /  |
+*       +-------+/ -+ b
+*       |    |  |/.
+*     a |   -v- |/
+*       |    |  |/
+*       +-------+ 1
+*      s    a
+*
+*  The capacities are randomly chosen integers from the range of [c1,c2]
+*  in the case of interconnecting edges, and c2 * a * a for the in-frame
+*  edges.
+*
+*  REFERENCES
+*
+*  D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the
+*  Dinic and network simplex methods for maximum flow." Annals of Op.
+*  Res. 13 (1988), pp. 83-123.
+*
+*  U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm:
+*  A computational investigation." Zeitschrift fuer Operations Research
+*  33 (1989), pp. 383-403. */
+
+typedef struct VERTEX
+{     struct EDGE **edgelist;
+      /* Pointer to the list of pointers to the adjacent edges.
+         (No matter that to or from edges) */
+      struct EDGE **current;
+      /* Pointer to the current edge */
+      int degree;
+      /* Number of adjacent edges (both direction) */
+      int index;
+} vertex;
+
+typedef struct EDGE
+{     int from;
+      int to;
+      int cap;
+      /* Capacity */
+} edge;
+
+typedef struct NETWORK
+{     struct NETWORK *next, *prev;
+      int vertnum;
+      int edgenum;
+      vertex *verts;
+      /* Vertex array[1..vertnum] */
+      edge *edges;
+      /* Edge array[1..edgenum] */
+      int source;
+      /* Pointer to the source */
+      int sink;
+      /* Pointer to the sink */
+} network;
+
+struct csa
+{     /* common storage area */
+      glp_graph *G;
+      int *s, *t, a_cap;
+      RNG *rand;
+      network *N;
+      int *Parr;
+      int A, AA, C2AA, Ec;
+};
+
+#define G      (csa->G)
+#define s      (csa->s)
+#define t      (csa->t)
+#define a_cap  (csa->a_cap)
+#define N      (csa->N)
+#define Parr   (csa->Parr)
+#define A      (csa->A)
+#define AA     (csa->AA)
+#define C2AA   (csa->C2AA)
+#define Ec     (csa->Ec)
+
+#undef random
+#define random(A) (int)(rng_unif_01(csa->rand) * (double)(A))
+#define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A))
+#define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1)
+
+static void make_edge(struct csa *csa, int from, int to, int c1, int c2)
+{     Ec++;
+      N->edges[Ec].from = from;
+      N->edges[Ec].to = to;
+      N->edges[Ec].cap = RANDOM(c1, c2);
+      return;
+}
+
+static void permute(struct csa *csa)
+{     int i, j, tmp;
+      for (i = 1; i < AA; i++)
+      {  j = RANDOM(i, AA);
+         tmp = Parr[i];
+         Parr[i] = Parr[j];
+         Parr[j] = tmp;
+      }
+      return;
+}
+
+static void connect(struct csa *csa, int offset, int cv, int x1, int y1)
+{     int cv1;
+      cv1 = offset + (x1 - 1) * A + y1;
+      Ec++;
+      N->edges[Ec].from = cv;
+      N->edges[Ec].to = cv1;
+      N->edges[Ec].cap = C2AA;
+      return;
+}
+
+static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2)
+{     /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges
+         random_frame network:
+         Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */
+      int x, y, z, offset, cv;
+      A = a;
+      AA = a * a;
+      C2AA = c2 * AA;
+      Ec = 0;
+      N = (network *)xmalloc(sizeof(network));
+      N->vertnum = AA * b;
+      N->edgenum = 5 * AA * b - 4 * A * b - AA;
+      N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge));
+      N->source = 1;
+      N->sink = N->vertnum;
+      Parr = (int *)xcalloc(AA + 1, sizeof(int));
+      for (x = 1; x <= AA; x++)
+         Parr[x] = x;
+      for (z = 1; z <= b; z++)
+      {  offset = AA * (z - 1);
+         if (z != b)
+            permute(csa);
+         for (x = 1; x <= A; x++)
+         {  for (y = 1; y <= A; y++)
+            {  cv = offset + (x - 1) * A + y;
+               if (z != b)
+                  make_edge(csa, cv, offset + AA + Parr[cv - offset],
+                     c1, c2); /* the intermediate edges */
+               if (y < A)
+                  connect(csa, offset, cv, x, y + 1);
+               if (y > 1)
+                  connect(csa, offset, cv, x, y - 1);
+               if (x < A)
+                  connect(csa, offset, cv, x + 1, y);
+               if (x > 1)
+                  connect(csa, offset, cv, x - 1, y);
+            }
+         }
+      }
+      xfree(Parr);
+      return N;
+}
+
+static void print_max_format(struct csa *csa, network *n, char *comm[],
+      int dim)
+{     /* prints a network heading with dim lines of comments (no \n
+         needs at the ends) */
+      int i, vnum, e_num;
+      edge *e;
+      vnum = n->vertnum;
+      e_num = n->edgenum;
+      if (G == NULL)
+      {  for (i = 0; i < dim; i++)
+            xprintf("c %s\n", comm[i]);
+         xprintf("p max %7d %10d\n", vnum, e_num);
+         xprintf("n %7d s\n", n->source);
+         xprintf("n %7d t\n", n->sink);
+      }
+      else
+      {  glp_add_vertices(G, vnum);
+         if (s != NULL) *s = n->source;
+         if (t != NULL) *t = n->sink;
+      }
+      for (i = 1; i <= e_num; i++)
+      {  e = &n->edges[i];
+         if (G == NULL)
+            xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap);
+         else
+         {  glp_arc *a = glp_add_arc(G, e->from, e->to);
+            if (a_cap >= 0)
+            {  double temp = (double)e->cap;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+         }
+      }
+      return;
+}
+
+static void gen_free_net(network *n)
+{     xfree(n->edges);
+      xfree(n);
+      return;
+}
+
+int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap,
+      const int parm[1+5])
+{     struct csa _csa, *csa = &_csa;
+      network *n;
+      char comm[10][80], *com1[10];
+      int seed, a, b, c1, c2, ret;
+      G = G_;
+      s = _s;
+      t = _t;
+      a_cap = _a_cap;
+      if (G != NULL)
+      {  if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+           xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap);
+      }
+      seed = parm[1];
+      a = parm[2];
+      b = parm[3];
+      c1 = parm[4];
+      c2 = parm[5];
+      if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 &&
+            0 <= c1 && c1 <= c2 && c2 <= 1000))
+      {  ret = 1;
+         goto done;
+      }
+      if (G != NULL)
+      {  glp_erase_graph(G, G->v_size, G->a_size);
+         glp_set_graph_name(G, "RMFGEN");
+      }
+      csa->rand = rng_create_rand();
+      rng_init_rand(csa->rand, seed);
+      n = gen_rmf(csa, a, b, c1, c2);
+      sprintf(comm[0], "This file was generated by genrmf.");
+      sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d",
+         a, b, c1, c2);
+      com1[0] = comm[0];
+      com1[1] = comm[1];
+      print_max_format(csa, n, com1, 2);
+      gen_free_net(n);
+      rng_delete_rand(csa->rand);
+      ret = 0;
+done: return ret;
+}
+
+/**********************************************************************/
+
+#if 0
+int main(int argc, char *argv[])
+{     int seed, a, b, c1, c2, i, parm[1+5];
+      seed = 123;
+      a = b = c1 = c2 = -1;
+      for (i = 1; i < argc; i++)
+      {  if (strcmp(argv[i], "-seed") == 0)
+            seed = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-a") == 0)
+            a = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-b") == 0)
+            b = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-c1") == 0)
+            c1 = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-c2") == 0)
+            c2 = atoi(argv[++i]);
+      }
+      if (a < 0 || b < 0 || c1 < 0 || c2 < 0)
+      {  xprintf("Usage:\n");
+         xprintf("genrmf [-seed seed] -a frame_size -b depth\n");
+         xprintf("        -c1 cap_range1 -c2 cap_range2\n");
+      }
+      else
+      {  parm[1] = seed;
+         parm[2] = a;
+         parm[3] = b;
+         parm[4] = c1;
+         parm[5] = c2;
+         glp_rmfgen(NULL, NULL, NULL, 0, parm);
+      }
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnet06.c b/optional/glpk/glpnet06.c
new file mode 100644
index 0000000..0ddc218
--- /dev/null
+++ b/optional/glpk/glpnet06.c
@@ -0,0 +1,387 @@
+/* glpnet06.c (out-of-kilter algorithm) */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#endif
+
+#include "glpenv.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  okalg - out-of-kilter algorithm
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int okalg(int nv, int na, const int tail[], const int head[],
+*     const int low[], const int cap[], const int cost[], int x[],
+*     int pi[]);
+*
+*  DESCRIPTION
+*
+*  The routine okalg implements the out-of-kilter algorithm to find a
+*  minimal-cost circulation in the specified flow network.
+*
+*  INPUT PARAMETERS
+*
+*  nv is the number of nodes, nv >= 0.
+*
+*  na is the number of arcs, na >= 0.
+*
+*  tail[a], a = 1,...,na, is the index of tail node of arc a.
+*
+*  head[a], a = 1,...,na, is the index of head node of arc a.
+*
+*  low[a], a = 1,...,na, is an lower bound to the flow through arc a.
+*
+*  cap[a], a = 1,...,na, is an upper bound to the flow through arc a,
+*  which is the capacity of the arc.
+*
+*  cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a.
+*
+*  NOTES
+*
+*  1. Multiple arcs are allowed, but self-loops are not allowed.
+*
+*  2. It is required that 0 <= low[a] <= cap[a] for all arcs.
+*
+*  3. Arc costs may have any sign.
+*
+*  OUTPUT PARAMETERS
+*
+*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
+*
+*  pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation
+*  equality constraint corresponding to node i (the node potential).
+*
+*  RETURNS
+*
+*  0  optimal circulation found;
+*
+*  1  there is no feasible circulation;
+*
+*  2  integer overflow occured;
+*
+*  3  optimality test failed (logic error).
+*
+*  REFERENCES
+*
+*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
+*  Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow
+*  Problems," pp.113-26. */
+
+static int overflow(int u, int v)
+{     /* check for integer overflow on computing u + v */
+      if (u > 0 && v > 0 && u + v < 0) return 1;
+      if (u < 0 && v < 0 && u + v > 0) return 1;
+      return 0;
+}
+
+int okalg(int nv, int na, const int tail[], const int head[],
+      const int low[], const int cap[], const int cost[], int x[],
+      int pi[])
+{     int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret,
+         *ptr, *arc, *link, *list;
+      /* sanity checks */
+      xassert(nv >= 0);
+      xassert(na >= 0);
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         xassert(1 <= i && i <= nv);
+         xassert(1 <= j && j <= nv);
+         xassert(i != j);
+         xassert(0 <= low[a] && low[a] <= cap[a]);
+      }
+      /* allocate working arrays */
+      ptr = xcalloc(1+nv+1, sizeof(int));
+      arc = xcalloc(1+na+na, sizeof(int));
+      link = xcalloc(1+nv, sizeof(int));
+      list = xcalloc(1+nv, sizeof(int));
+      /* ptr[i] := (degree of node i) */
+      for (i = 1; i <= nv; i++)
+         ptr[i] = 0;
+      for (a = 1; a <= na; a++)
+      {  ptr[tail[a]]++;
+         ptr[head[a]]++;
+      }
+      /* initialize arc pointers */
+      ptr[1]++;
+      for (i = 1; i < nv; i++)
+         ptr[i+1] += ptr[i];
+      ptr[nv+1] = ptr[nv];
+      /* build arc lists */
+      for (a = 1; a <= na; a++)
+      {  arc[--ptr[tail[a]]] = a;
+         arc[--ptr[head[a]]] = a;
+      }
+      xassert(ptr[1] == 1);
+      xassert(ptr[nv+1] == na+na+1);
+      /* now the indices of arcs incident to node i are stored in
+         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
+      /* initialize arc flows and node potentials */
+      for (a = 1; a <= na; a++)
+         x[a] = 0;
+      for (i = 1; i <= nv; i++)
+         pi[i] = 0;
+loop: /* main loop starts here */
+      /* find out-of-kilter arc */
+      aok = 0;
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         if (overflow(cost[a], pi[i] - pi[j]))
+         {  ret = 2;
+            goto done;
+         }
+         lambda = cost[a] + (pi[i] - pi[j]);
+         if (x[a] < low[a] || lambda < 0 && x[a] < cap[a])
+         {  /* arc a = i->j is out of kilter, and we need to increase
+               the flow through this arc */
+            aok = a, s = j, t = i;
+            break;
+         }
+         if (x[a] > cap[a] || lambda > 0 && x[a] > low[a])
+         {  /* arc a = i->j is out of kilter, and we need to decrease
+               the flow through this arc */
+            aok = a, s = i, t = j;
+            break;
+         }
+      }
+      if (aok == 0)
+      {  /* all arcs are in kilter */
+         /* check for feasibility */
+         for (a = 1; a <= na; a++)
+         {  if (!(low[a] <= x[a] && x[a] <= cap[a]))
+            {  ret = 3;
+               goto done;
+            }
+         }
+         for (i = 1; i <= nv; i++)
+         {  temp = 0;
+            for (k = ptr[i]; k < ptr[i+1]; k++)
+            {  a = arc[k];
+               if (tail[a] == i)
+               {  /* a is outgoing arc */
+                  temp += x[a];
+               }
+               else if (head[a] == i)
+               {  /* a is incoming arc */
+                  temp -= x[a];
+               }
+               else
+                  xassert(a != a);
+            }
+            if (temp != 0)
+            {  ret = 3;
+               goto done;
+            }
+         }
+         /* check for optimality */
+         for (a = 1; a <= na; a++)
+         {  i = tail[a], j = head[a];
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (lambda > 0 && x[a] != low[a] ||
+                lambda < 0 && x[a] != cap[a])
+            {  ret = 3;
+               goto done;
+            }
+         }
+         /* current circulation is optimal */
+         ret = 0;
+         goto done;
+      }
+      /* now we need to find a cycle (t, a, s, ..., t), which allows
+         increasing the flow along it, where a is the out-of-kilter arc
+         just found */
+      /* link[i] = 0 means that node i is not labelled yet;
+         link[i] = a means that arc a immediately precedes node i */
+      /* initially only node s is labelled */
+      for (i = 1; i <= nv; i++)
+         link[i] = 0;
+      link[s] = aok, list[1] = s, pos1 = pos2 = 1;
+      /* breadth first search */
+      while (pos1 <= pos2)
+      {  /* dequeue node i */
+         i = list[pos1++];
+         /* consider all arcs incident to node i */
+         for (k = ptr[i]; k < ptr[i+1]; k++)
+         {  a = arc[k];
+            if (tail[a] == i)
+            {  /* a = i->j is a forward arc from s to t */
+               j = head[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow increasing the flow through
+                  it, skip the arc */
+               if (x[a] >= cap[a]) continue;
+               if (overflow(cost[a], pi[i] - pi[j]))
+               {  ret = 2;
+                  goto done;
+               }
+               lambda = cost[a] + (pi[i] - pi[j]);
+               if (lambda > 0 && x[a] >= low[a]) continue;
+            }
+            else if (head[a] == i)
+            {  /* a = i<-j is a backward arc from s to t */
+               j = tail[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow decreasing the flow through
+                  it, skip the arc */
+               if (x[a] <= low[a]) continue;
+               if (overflow(cost[a], pi[j] - pi[i]))
+               {  ret = 2;
+                  goto done;
+               }
+               lambda = cost[a] + (pi[j] - pi[i]);
+               if (lambda < 0 && x[a] <= cap[a]) continue;
+            }
+            else
+               xassert(a != a);
+            /* label node j and enqueue it */
+            link[j] = a, list[++pos2] = j;
+            /* check for breakthrough */
+            if (j == t) goto brkt;
+         }
+      }
+      /* NONBREAKTHROUGH */
+      /* consider all arcs, whose one endpoint is labelled and other is
+         not, and determine maximal change of node potentials */
+      delta = 0;
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         if (link[i] != 0 && link[j] == 0)
+         {  /* a = i->j, where node i is labelled, node j is not */
+            if (overflow(cost[a], pi[i] - pi[j]))
+            {  ret = 2;
+               goto done;
+            }
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (x[a] <= cap[a] && lambda > 0)
+               if (delta == 0 || delta > + lambda) delta = + lambda;
+         }
+         else if (link[i] == 0 && link[j] != 0)
+         {  /* a = j<-i, where node j is labelled, node i is not */
+            if (overflow(cost[a], pi[i] - pi[j]))
+            {  ret = 2;
+               goto done;
+            }
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (x[a] >= low[a] && lambda < 0)
+               if (delta == 0 || delta > - lambda) delta = - lambda;
+         }
+      }
+      if (delta == 0)
+      {  /* there is no feasible circulation */
+         ret = 1;
+         goto done;
+      }
+      /* increase potentials of all unlabelled nodes */
+      for (i = 1; i <= nv; i++)
+      {  if (link[i] == 0)
+         {  if (overflow(pi[i], delta))
+            {  ret = 2;
+               goto done;
+            }
+            pi[i] += delta;
+         }
+      }
+      goto loop;
+brkt: /* BREAKTHROUGH */
+      /* walk through arcs of the cycle (t, a, s, ..., t) found in the
+         reverse order and determine maximal change of the flow */
+      delta = 0;
+      for (j = t;; j = i)
+      {  /* arc a immediately precedes node j in the cycle */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (lambda > 0 && x[a] < low[a])
+            {  /* x[a] may be increased until its lower bound */
+               temp = low[a] - x[a];
+            }
+            else if (lambda <= 0 && x[a] < cap[a])
+            {  /* x[a] may be increased until its upper bound */
+               temp = cap[a] - x[a];
+            }
+            else
+               xassert(a != a);
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            lambda = cost[a] + (pi[j] - pi[i]);
+            if (lambda < 0 && x[a] > cap[a])
+            {  /* x[a] may be decreased until its upper bound */
+               temp = x[a] - cap[a];
+            }
+            else if (lambda >= 0 && x[a] > low[a])
+            {  /* x[a] may be decreased until its lower bound */
+               temp = x[a] - low[a];
+            }
+            else
+               xassert(a != a);
+         }
+         else
+            xassert(a != a);
+         if (delta == 0 || delta > temp) delta = temp;
+         /* check for end of the cycle */
+         if (i == t) break;
+      }
+      xassert(delta > 0);
+      /* increase the flow along the cycle */
+      for (j = t;; j = i)
+      {  /* arc a immediately precedes node j in the cycle */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            /* overflow cannot occur */
+            x[a] += delta;
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            /* overflow cannot occur */
+            x[a] -= delta;
+         }
+         else
+            xassert(a != a);
+         /* check for end of the cycle */
+         if (i == t) break;
+      }
+      goto loop;
+done: /* free working arrays */
+      xfree(ptr);
+      xfree(arc);
+      xfree(link);
+      xfree(list);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnet07.c b/optional/glpk/glpnet07.c
new file mode 100644
index 0000000..0430225
--- /dev/null
+++ b/optional/glpk/glpnet07.c
@@ -0,0 +1,222 @@
+/* glpnet07.c (Ford-Fulkerson algorithm) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ffalg - Ford-Fulkerson algorithm
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  void ffalg(int nv, int na, const int tail[], const int head[],
+*     int s, int t, const int cap[], int x[], char cut[]);
+*
+*  DESCRIPTION
+*
+*  The routine ffalg implements the Ford-Fulkerson algorithm to find a
+*  maximal flow in the specified flow network.
+*
+*  INPUT PARAMETERS
+*
+*  nv is the number of nodes, nv >= 2.
+*
+*  na is the number of arcs, na >= 0.
+*
+*  tail[a], a = 1,...,na, is the index of tail node of arc a.
+*
+*  head[a], a = 1,...,na, is the index of head node of arc a.
+*
+*  s is the source node index, 1 <= s <= nv.
+*
+*  t is the sink node index, 1 <= t <= nv, t != s.
+*
+*  cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0.
+*
+*  NOTE: Multiple arcs are allowed, but self-loops are not allowed.
+*
+*  OUTPUT PARAMETERS
+*
+*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
+*
+*  cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise.
+*  The set of arcs, whose one endpoint is labelled and other is not,
+*  defines the minimal cut corresponding to the maximal flow found.
+*  If the parameter cut is NULL, the cut information are not stored.
+*
+*  REFERENCES
+*
+*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
+*  Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow,"
+*  pp.30-33. */
+
+void ffalg(int nv, int na, const int tail[], const int head[],
+      int s, int t, const int cap[], int x[], char cut[])
+{     int a, delta, i, j, k, pos1, pos2, temp,
+         *ptr, *arc, *link, *list;
+      /* sanity checks */
+      xassert(nv >= 2);
+      xassert(na >= 0);
+      xassert(1 <= s && s <= nv);
+      xassert(1 <= t && t <= nv);
+      xassert(s != t);
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         xassert(1 <= i && i <= nv);
+         xassert(1 <= j && j <= nv);
+         xassert(i != j);
+         xassert(cap[a] >= 0);
+      }
+      /* allocate working arrays */
+      ptr = xcalloc(1+nv+1, sizeof(int));
+      arc = xcalloc(1+na+na, sizeof(int));
+      link = xcalloc(1+nv, sizeof(int));
+      list = xcalloc(1+nv, sizeof(int));
+      /* ptr[i] := (degree of node i) */
+      for (i = 1; i <= nv; i++)
+         ptr[i] = 0;
+      for (a = 1; a <= na; a++)
+      {  ptr[tail[a]]++;
+         ptr[head[a]]++;
+      }
+      /* initialize arc pointers */
+      ptr[1]++;
+      for (i = 1; i < nv; i++)
+         ptr[i+1] += ptr[i];
+      ptr[nv+1] = ptr[nv];
+      /* build arc lists */
+      for (a = 1; a <= na; a++)
+      {  arc[--ptr[tail[a]]] = a;
+         arc[--ptr[head[a]]] = a;
+      }
+      xassert(ptr[1] == 1);
+      xassert(ptr[nv+1] == na+na+1);
+      /* now the indices of arcs incident to node i are stored in
+         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
+      /* initialize arc flows */
+      for (a = 1; a <= na; a++)
+         x[a] = 0;
+loop: /* main loop starts here */
+      /* build augmenting tree rooted at s */
+      /* link[i] = 0 means that node i is not labelled yet;
+         link[i] = a means that arc a immediately precedes node i */
+      /* initially node s is labelled as the root */
+      for (i = 1; i <= nv; i++)
+         link[i] = 0;
+      link[s] = -1, list[1] = s, pos1 = pos2 = 1;
+      /* breadth first search */
+      while (pos1 <= pos2)
+      {  /* dequeue node i */
+         i = list[pos1++];
+         /* consider all arcs incident to node i */
+         for (k = ptr[i]; k < ptr[i+1]; k++)
+         {  a = arc[k];
+            if (tail[a] == i)
+            {  /* a = i->j is a forward arc from s to t */
+               j = head[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow increasing the flow through
+                  it, skip the arc */
+               if (x[a] == cap[a]) continue;
+            }
+            else if (head[a] == i)
+            {  /* a = i<-j is a backward arc from s to t */
+               j = tail[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow decreasing the flow through
+                  it, skip the arc */
+               if (x[a] == 0) continue;
+            }
+            else
+               xassert(a != a);
+            /* label node j and enqueue it */
+            link[j] = a, list[++pos2] = j;
+            /* check for breakthrough */
+            if (j == t) goto brkt;
+         }
+      }
+      /* NONBREAKTHROUGH */
+      /* no augmenting path exists; current flow is maximal */
+      /* store minimal cut information, if necessary */
+      if (cut != NULL)
+      {  for (i = 1; i <= nv; i++)
+            cut[i] = (char)(link[i] != 0);
+      }
+      goto done;
+brkt: /* BREAKTHROUGH */
+      /* walk through arcs of the augmenting path (s, ..., t) found in
+         the reverse order and determine maximal change of the flow */
+      delta = 0;
+      for (j = t; j != s; j = i)
+      {  /* arc a immediately precedes node j in the path */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            /* x[a] may be increased until its upper bound */
+            temp = cap[a] - x[a];
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            /* x[a] may be decreased until its lower bound */
+            temp = x[a];
+         }
+         else
+            xassert(a != a);
+         if (delta == 0 || delta > temp) delta = temp;
+      }
+      xassert(delta > 0);
+      /* increase the flow along the path */
+      for (j = t; j != s; j = i)
+      {  /* arc a immediately precedes node j in the path */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            x[a] += delta;
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            x[a] -= delta;
+         }
+         else
+            xassert(a != a);
+      }
+      goto loop;
+done: /* free working arrays */
+      xfree(ptr);
+      xfree(arc);
+      xfree(link);
+      xfree(list);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnet08.c b/optional/glpk/glpnet08.c
new file mode 100644
index 0000000..239665c
--- /dev/null
+++ b/optional/glpk/glpnet08.c
@@ -0,0 +1,245 @@
+/* glpnet08.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Two subroutines sub() and wclique() below are intended to find a
+*  maximum weight clique in a given undirected graph. These subroutines
+*  are slightly modified version of the program WCLIQUE developed by
+*  Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
+*  on ideas from the article "P. R. J. Ostergard, A new algorithm for
+*  the maximum-weight clique problem, submitted for publication", which
+*  in turn is a generalization of the algorithm for unweighted graphs
+*  presented in "P. R. J. Ostergard, A fast algorithm for the maximum
+*  clique problem, submitted for publication".
+*
+*  USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE.
+*
+*  Changes were made by Andrew Makhorin <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 "-Wshorten-64-to-32"
+#endif
+
+#include "glpenv.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  wclique - find maximum weight clique with Ostergard's algorithm
+*
+*  SYNOPSIS
+*
+*  int wclique(int n, const int w[], const unsigned char a[],
+*     int ind[]);
+*
+*  DESCRIPTION
+*
+*  The routine wclique finds a maximum weight clique in an undirected
+*  graph with Ostergard's algorithm.
+*
+*  INPUT PARAMETERS
+*
+*  n is the number of vertices, n > 0.
+*
+*  w[i], i = 1,...,n, is a weight of vertex i.
+*
+*  a[*] is the strict (without main diagonal) lower triangle of the
+*  graph adjacency matrix in packed format.
+*
+*  OUTPUT PARAMETER
+*
+*  ind[k], k = 1,...,size, is the number of a vertex included in the
+*  clique found, 1 <= ind[k] <= n, where size is the number of vertices
+*  in the clique returned on exit.
+*
+*  RETURNS
+*
+*  The routine returns the clique size, i.e. the number of vertices in
+*  the clique. */
+
+struct csa
+{     /* common storage area */
+      int n;
+      /* number of vertices */
+      const int *wt; /* int wt[0:n-1]; */
+      /* weights */
+      const unsigned char *a;
+      /* adjacency matrix (packed lower triangle without main diag.) */
+      int record;
+      /* weight of best clique */
+      int rec_level;
+      /* number of vertices in best clique */
+      int *rec; /* int rec[0:n-1]; */
+      /* best clique so far */
+      int *clique; /* int clique[0:n-1]; */
+      /* table for pruning */
+      int *set; /* int set[0:n-1]; */
+      /* current clique */
+};
+
+#define n         (csa->n)
+#define wt        (csa->wt)
+#define a         (csa->a)
+#define record    (csa->record)
+#define rec_level (csa->rec_level)
+#define rec       (csa->rec)
+#define clique    (csa->clique)
+#define set       (csa->set)
+
+#if 0
+static int is_edge(struct csa *csa, int i, int j)
+{     /* if there is arc (i,j), the routine returns true; otherwise
+         false; 0 <= i, j < n */
+      int k;
+      xassert(0 <= i && i < n);
+      xassert(0 <= j && j < n);
+      if (i == j) return 0;
+      if (i < j) k = i, i = j, j = k;
+      k = (i * (i - 1)) / 2 + j;
+      return a[k / CHAR_BIT] &
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+}
+#else
+#define is_edge(csa, i, j) ((i) == (j) ? 0 : \
+      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
+#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
+#define is_edge2(k) (a[(k) / CHAR_BIT] & \
+      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
+#endif
+
+static void sub(struct csa *csa, int ct, int table[], int level,
+      int weight, int l_weight)
+{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
+      newtable = xcalloc(n, sizeof(int));
+      if (ct <= 0)
+      {  /* 0 or 1 elements left; include these */
+         if (ct == 0)
+         {  set[level++] = table[0];
+            weight += l_weight;
+         }
+         if (weight > record)
+         {  record = weight;
+            rec_level = level;
+            for (i = 0; i < level; i++) rec[i] = set[i];
+         }
+         goto done;
+      }
+      for (i = ct; i >= 0; i--)
+      {  if ((level == 0) && (i < ct)) goto done;
+         k = table[i];
+         if ((level > 0) && (clique[k] <= (record - weight)))
+            goto done; /* prune */
+         set[level] = k;
+         curr_weight = weight + wt[k];
+         l_weight -= wt[k];
+         if (l_weight <= (record - curr_weight))
+            goto done; /* prune */
+         p1 = newtable;
+         p2 = table;
+         left_weight = 0;
+         while (p2 < table + i)
+         {  j = *p2++;
+            if (is_edge(csa, j, k))
+            {  *p1++ = j;
+               left_weight += wt[j];
+            }
+         }
+         if (left_weight <= (record - curr_weight)) continue;
+         sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight,
+            left_weight);
+      }
+done: xfree(newtable);
+      return;
+}
+
+int wclique(int _n, const int w[], const unsigned char _a[], int ind[])
+{     struct csa _csa, *csa = &_csa;
+      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
+      glp_long timer;
+      n = _n;
+      xassert(n > 0);
+      wt = &w[1];
+      a = _a;
+      record = 0;
+      rec_level = 0;
+      rec = &ind[1];
+      clique = xcalloc(n, sizeof(int));
+      set = xcalloc(n, sizeof(int));
+      used = xcalloc(n, sizeof(int));
+      nwt = xcalloc(n, sizeof(int));
+      pos = xcalloc(n, sizeof(int));
+      /* start timer */
+      timer = xtime();
+      /* order vertices */
+      for (i = 0; i < n; i++)
+      {  nwt[i] = 0;
+         for (j = 0; j < n; j++)
+            if (is_edge(csa, i, j)) nwt[i] += wt[j];
+      }
+      for (i = 0; i < n; i++)
+         used[i] = 0;
+      for (i = n-1; i >= 0; i--)
+      {  max_wt = -1;
+         max_nwt = -1;
+         for (j = 0; j < n; j++)
+         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
+               && nwt[j] > max_nwt)))
+            {  max_wt = wt[j];
+               max_nwt = nwt[j];
+               p = j;
+            }
+         }
+         pos[i] = p;
+         used[p] = 1;
+         for (j = 0; j < n; j++)
+            if ((!used[j]) && (j != p) && (is_edge(csa, p, j)))
+               nwt[j] -= wt[p];
+      }
+      /* main routine */
+      wth = 0;
+      for (i = 0; i < n; i++)
+      {  wth += wt[pos[i]];
+         sub(csa, i, pos, 0, 0, wth);
+         clique[pos[i]] = record;
+         if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
+         {  /* print current record and reset timer */
+            xprintf("level = %d (%d); best = %d\n", i+1, n, record);
+            timer = xtime();
+         }
+      }
+      xfree(clique);
+      xfree(set);
+      xfree(used);
+      xfree(nwt);
+      xfree(pos);
+      /* return the solution found */
+      for (i = 1; i <= rec_level; i++) ind[i]++;
+      return rec_level;
+}
+
+#undef n
+#undef wt
+#undef a
+#undef record
+#undef rec_level
+#undef rec
+#undef clique
+#undef set
+
+/* eof */
diff --git a/optional/glpk/glpnet09.c b/optional/glpk/glpnet09.c
new file mode 100644
index 0000000..d549ece
--- /dev/null
+++ b/optional/glpk/glpnet09.c
@@ -0,0 +1,239 @@
+/* glpnet09.c */
+
+/***********************************************************************
+*  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"
+#endif
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  kellerman - cover edges by cliques with Kellerman's heuristic
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+*     void *info, glp_graph *H);
+*
+*  DESCRIPTION
+*
+*  The routine kellerman implements Kellerman's heuristic algorithm
+*  to find a minimal set of cliques which cover all edges of specified
+*  graph G = (V, E).
+*
+*  The parameter n specifies the number of vertices |V|, n >= 0.
+*
+*  Formal routine func specifies the set of edges E in the following
+*  way. Running the routine kellerman calls the routine func and passes
+*  to it parameter i, which is the number of some vertex, 1 <= i <= n.
+*  In response the routine func should store numbers of all vertices
+*  adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and
+*  return the value of len, which is the number of adjacent vertices,
+*  0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges
+*  are not allowed.
+*
+*  The parameter info is a transit pointer (magic cookie) passed to the
+*  formal routine func as its first parameter.
+*
+*  The result provided by the routine kellerman is the bipartite graph
+*  H = (V union C, F), which defines the covering found. (The program
+*  object of type glp_graph specified by the parameter H should be
+*  previously created with the routine glp_create_graph. On entry the
+*  routine kellerman erases the content of this object with the routine
+*  glp_erase_graph.) Vertices of first part V correspond to vertices of
+*  the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices
+*  of second part C correspond to cliques and have ordinal numbers
+*  n+1, n+2, ..., n+k, where k is the total number of cliques in the
+*  edge covering found. Every edge f in F in the program object H is
+*  represented as arc f = (i->j), where i in V and j in C, which means
+*  that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus,
+*  if two vertices of the graph G are in the same clique, these vertices
+*  are adjacent in G, and corresponding edge is covered by that clique.)
+*
+*  RETURNS
+*
+*  The routine Kellerman returns k, the total number of cliques in the
+*  edge covering found.
+*
+*  REFERENCE
+*
+*  For more details see: glpk/doc/notes/keller.pdf (in Russian). */
+
+struct set
+{     /* set of vertices */
+      int size;
+      /* size (cardinality) of the set, 0 <= card <= n */
+      int *list; /* int list[1+n]; */
+      /* the set contains vertices list[1,...,size] */
+      int *pos; /* int pos[1+n]; */
+      /* pos[i] > 0 means that vertex i is in the set and
+         list[pos[i]] = i; pos[i] = 0 means that vertex i is not in
+         the set */
+};
+
+int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+      void *info, void /* glp_graph */ *H_)
+{     glp_graph *H = H_;
+      struct set W_, *W = &W_, V_, *V = &V_;
+      glp_arc *a;
+      int i, j, k, m, t, len, card, best;
+      xassert(n >= 0);
+      /* H := (V, 0; 0), where V is the set of vertices of graph G */
+      glp_erase_graph(H, H->v_size, H->a_size);
+      glp_add_vertices(H, n);
+      /* W := 0 */
+      W->size = 0;
+      W->list = xcalloc(1+n, sizeof(int));
+      W->pos = xcalloc(1+n, sizeof(int));
+      memset(&W->pos[1], 0, sizeof(int) * n);
+      /* V := 0 */
+      V->size = 0;
+      V->list = xcalloc(1+n, sizeof(int));
+      V->pos = xcalloc(1+n, sizeof(int));
+      memset(&V->pos[1], 0, sizeof(int) * n);
+      /* main loop */
+      for (i = 1; i <= n; i++)
+      {  /* W must be empty */
+         xassert(W->size == 0);
+         /* W := { j : i > j and (i,j) in E } */
+         len = func(info, i, W->list);
+         xassert(0 <= len && len <= n);
+         for (t = 1; t <= len; t++)
+         {  j = W->list[t];
+            xassert(1 <= j && j <= n);
+            if (j >= i) continue;
+            xassert(W->pos[j] == 0);
+            W->list[++W->size] = j, W->pos[j] = W->size;
+         }
+         /* on i-th iteration we need to cover edges (i,j) for all
+            j in W */
+         /* if W is empty, it is a special case */
+         if (W->size == 0)
+         {  /* set k := k + 1 and create new clique C[k] = { i } */
+            k = glp_add_vertices(H, 1) - n;
+            glp_add_arc(H, i, n + k);
+            continue;
+         }
+         /* try to include vertex i into existing cliques */
+         /* V must be empty */
+         xassert(V->size == 0);
+         /* k is the number of cliques found so far */
+         k = H->nv - n;
+         for (m = 1; m <= k; m++)
+         {  /* do while V != W; since here V is within W, we can use
+               equivalent condition: do while |V| < |W| */
+            if (V->size == W->size) break;
+            /* check if C[m] is within W */
+            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+            {  j = a->tail->i;
+               if (W->pos[j] == 0) break;
+            }
+            if (a != NULL) continue;
+            /* C[m] is within W, expand clique C[m] with vertex i */
+            /* C[m] := C[m] union {i} */
+            glp_add_arc(H, i, n + m);
+            /* V is a set of vertices whose incident edges are already
+               covered by existing cliques */
+            /* V := V union C[m] */
+            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+            {  j = a->tail->i;
+               if (V->pos[j] == 0)
+                  V->list[++V->size] = j, V->pos[j] = V->size;
+            }
+         }
+         /* remove from set W the vertices whose incident edges are
+            already covered by existing cliques */
+         /* W := W \ V, V := 0 */
+         for (t = 1; t <= V->size; t++)
+         {  j = V->list[t], V->pos[j] = 0;
+            if (W->pos[j] != 0)
+            {  /* remove vertex j from W */
+               if (W->pos[j] != W->size)
+               {  int jj = W->list[W->size];
+                  W->list[W->pos[j]] = jj;
+                  W->pos[jj] = W->pos[j];
+               }
+               W->size--, W->pos[j] = 0;
+            }
+         }
+         V->size = 0;
+         /* now set W contains only vertices whose incident edges are
+            still not covered by existing cliques; create new cliques
+            to cover remaining edges until set W becomes empty */
+         while (W->size > 0)
+         {  /* find clique C[m], 1 <= m <= k, which shares maximal
+               number of vertices with W; to break ties choose clique
+               having smallest number m */
+            m = 0, best = -1;
+            k = H->nv - n;
+            for (t = 1; t <= k; t++)
+            {  /* compute cardinality of intersection of W and C[t] */
+               card = 0;
+               for (a = H->v[n + t]->in; a != NULL; a = a->h_next)
+               {  j = a->tail->i;
+                  if (W->pos[j] != 0) card++;
+               }
+               if (best < card)
+                  m = t, best = card;
+            }
+            xassert(m > 0);
+            /* set k := k + 1 and create new clique:
+               C[k] := (W intersect C[m]) union { i }, which covers all
+               edges incident to vertices from (W intersect C[m]) */
+            k = glp_add_vertices(H, 1) - n;
+            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+            {  j = a->tail->i;
+               if (W->pos[j] != 0)
+               {  /* vertex j is in both W and C[m]; include it in new
+                     clique C[k] */
+                  glp_add_arc(H, j, n + k);
+                  /* remove vertex j from W, since edge (i,j) will be
+                     covered by new clique C[k] */
+                  if (W->pos[j] != W->size)
+                  {  int jj = W->list[W->size];
+                     W->list[W->pos[j]] = jj;
+                     W->pos[jj] = W->pos[j];
+                  }
+                  W->size--, W->pos[j] = 0;
+               }
+            }
+            /* include vertex i to new clique C[k] to cover edges (i,j)
+               incident to all vertices j just removed from W */
+            glp_add_arc(H, i, n + k);
+         }
+      }
+      /* free working arrays */
+      xfree(W->list);
+      xfree(W->pos);
+      xfree(V->list);
+      xfree(V->pos);
+      /* return the number of cliques in the edge covering found */
+      return H->nv - n;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnpp.h b/optional/glpk/glpnpp.h
new file mode 100644
index 0000000..1911d1d
--- /dev/null
+++ b/optional/glpk/glpnpp.h
@@ -0,0 +1,520 @@
+/* glpnpp.h (LP/MIP preprocessor) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPNPP_H
+#define GLPNPP_H
+
+#include "glpapi.h"
+
+typedef struct NPP NPP;
+typedef struct NPPROW NPPROW;
+typedef struct NPPCOL NPPCOL;
+typedef struct NPPAIJ NPPAIJ;
+typedef struct NPPTSE NPPTSE;
+typedef struct NPPLFE NPPLFE;
+
+struct NPP
+{     /* LP/MIP preprocessor workspace */
+      /*--------------------------------------------------------------*/
+      /* original problem segment */
+      int orig_dir;
+      /* optimization direction flag:
+         GLP_MIN - minimization
+         GLP_MAX - maximization */
+      int orig_m;
+      /* number of rows */
+      int orig_n;
+      /* number of columns */
+      int orig_nnz;
+      /* number of non-zero constraint coefficients */
+      /*--------------------------------------------------------------*/
+      /* transformed problem segment (always minimization) */
+      DMP *pool;
+      /* memory pool to store problem components */
+      char *name;
+      /* problem name (1 to 255 chars); NULL means no name is assigned
+         to the problem */
+      char *obj;
+      /* objective function name (1 to 255 chars); NULL means no name
+         is assigned to the objective function */
+      double c0;
+      /* constant term of the objective function */
+      int nrows;
+      /* number of rows introduced into the problem; this count
+         increases by one every time a new row is added and never
+         decreases; thus, actual number of rows may be less than nrows
+         due to row deletions */
+      int ncols;
+      /* number of columns introduced into the problem; this count
+         increases by one every time a new column is added and never
+         decreases; thus, actual number of column may be less than
+         ncols due to column deletions */
+      NPPROW *r_head;
+      /* pointer to the beginning of the row list */
+      NPPROW *r_tail;
+      /* pointer to the end of the row list */
+      NPPCOL *c_head;
+      /* pointer to the beginning of the column list */
+      NPPCOL *c_tail;
+      /* pointer to the end of the column list */
+      /*--------------------------------------------------------------*/
+      /* transformation history */
+      DMP *stack;
+      /* memory pool to store transformation entries */
+      NPPTSE *top;
+      /* pointer to most recent transformation entry */
+#if 0 /* 16/XII-2009 */
+      int count[1+25];
+      /* transformation statistics */
+#endif
+      /*--------------------------------------------------------------*/
+      /* resultant (preprocessed) problem segment */
+      int m;
+      /* number of rows */
+      int n;
+      /* number of columns */
+      int nnz;
+      /* number of non-zero constraint coefficients */
+      int *row_ref; /* int row_ref[1+m]; */
+      /* row_ref[i], 1 <= i <= m, is the reference number assigned to
+         a row, which is i-th row of the resultant problem */
+      int *col_ref; /* int col_ref[1+n]; */
+      /* col_ref[j], 1 <= j <= n, is the reference number assigned to
+         a column, which is j-th column of the resultant problem */
+      /*--------------------------------------------------------------*/
+      /* recovered solution segment */
+      int sol;
+      /* solution indicator:
+         GLP_SOL - basic solution
+         GLP_IPT - interior-point solution
+         GLP_MIP - mixed integer solution */
+      int scaling;
+      /* scaling option:
+         GLP_OFF - scaling is disabled
+         GLP_ON  - scaling is enabled */
+      int p_stat;
+      /* status of primal basic solution:
+         GLP_UNDEF  - primal solution is undefined
+         GLP_FEAS   - primal solution is feasible
+         GLP_INFEAS - primal solution is infeasible
+         GLP_NOFEAS - no primal feasible solution exists */
+      int d_stat;
+      /* status of dual basic solution:
+         GLP_UNDEF  - dual solution is undefined
+         GLP_FEAS   - dual solution is feasible
+         GLP_INFEAS - dual solution is infeasible
+         GLP_NOFEAS - no dual feasible solution exists */
+      int t_stat;
+      /* status of interior-point solution:
+         GLP_UNDEF  - interior solution is undefined
+         GLP_OPT    - interior solution is optimal */
+      int i_stat;
+      /* status of mixed integer solution:
+         GLP_UNDEF  - integer solution is undefined
+         GLP_OPT    - integer solution is optimal
+         GLP_FEAS   - integer solution is feasible
+         GLP_NOFEAS - no integer solution exists */
+      char *r_stat; /* char r_stat[1+nrows]; */
+      /* r_stat[i], 1 <= i <= nrows, is status of i-th row:
+         GLP_BS - inactive constraint
+         GLP_NL - active constraint on lower bound
+         GLP_NU - active constraint on upper bound
+         GLP_NF - active free row
+         GLP_NS - active equality constraint */
+      char *c_stat; /* char c_stat[1+nrows]; */
+      /* c_stat[j], 1 <= j <= nrows, is status of j-th column:
+         GLP_BS - basic variable
+         GLP_NL - non-basic variable on lower bound
+         GLP_NU - non-basic variable on upper bound
+         GLP_NF - non-basic free variable
+         GLP_NS - non-basic fixed variable */
+      double *r_pi; /* double r_pi[1+nrows]; */
+      /* r_pi[i], 1 <= i <= nrows, is Lagrange multiplier (dual value)
+         for i-th row (constraint) */
+      double *c_value; /* double c_value[1+ncols]; */
+      /* c_value[j], 1 <= j <= ncols, is primal value of j-th column
+         (structural variable) */
+};
+
+struct NPPROW
+{     /* row (constraint) */
+      int i;
+      /* reference number assigned to the row, 1 <= i <= nrows */
+      char *name;
+      /* row name (1 to 255 chars); NULL means no name is assigned to
+         the row */
+      double lb;
+      /* lower bound; -DBL_MAX means the row has no lower bound */
+      double ub;
+      /* upper bound; +DBL_MAX means the row has no upper bound */
+      NPPAIJ *ptr;
+      /* pointer to the linked list of constraint coefficients */
+      int temp;
+      /* working field used by preprocessor routines */
+      NPPROW *prev;
+      /* pointer to previous row in the row list */
+      NPPROW *next;
+      /* pointer to next row in the row list */
+};
+
+struct NPPCOL
+{     /* column (variable) */
+      int j;
+      /* reference number assigned to the column, 1 <= j <= ncols */
+      char *name;
+      /* column name (1 to 255 chars); NULL means no name is assigned
+         to the column */
+      char is_int;
+      /* 0 means continuous variable; 1 means integer variable */
+      double lb;
+      /* lower bound; -DBL_MAX means the column has no lower bound */
+      double ub;
+      /* upper bound; +DBL_MAX means the column has no upper bound */
+      double coef;
+      /* objective coefficient */
+      NPPAIJ *ptr;
+      /* pointer to the linked list of constraint coefficients */
+      int temp;
+      /* working field used by preprocessor routines */
+#if 1 /* 28/XII-2009 */
+      union
+      {  double ll;
+         /* implied column lower bound */
+         int pos;
+         /* vertex ordinal number corresponding to this binary column
+            in the conflict graph (0, if the vertex does not exist) */
+      }  ll;
+      union
+      {  double uu;
+         /* implied column upper bound */
+         int neg;
+         /* vertex ordinal number corresponding to complement of this
+            binary column in the conflict graph (0, if the vertex does
+            not exist) */
+      }  uu;
+#endif
+      NPPCOL *prev;
+      /* pointer to previous column in the column list */
+      NPPCOL *next;
+      /* pointer to next column in the column list */
+};
+
+struct NPPAIJ
+{     /* constraint coefficient */
+      NPPROW *row;
+      /* pointer to corresponding row */
+      NPPCOL *col;
+      /* pointer to corresponding column */
+      double val;
+      /* (non-zero) coefficient value */
+      NPPAIJ *r_prev;
+      /* pointer to previous coefficient in the same row */
+      NPPAIJ *r_next;
+      /* pointer to next coefficient in the same row */
+      NPPAIJ *c_prev;
+      /* pointer to previous coefficient in the same column */
+      NPPAIJ *c_next;
+      /* pointer to next coefficient in the same column */
+};
+
+struct NPPTSE
+{     /* transformation stack entry */
+      int (*func)(NPP *npp, void *info);
+      /* pointer to routine performing back transformation */
+      void *info;
+      /* pointer to specific info (depends on the transformation) */
+      NPPTSE *link;
+      /* pointer to another entry created *before* this entry */
+};
+
+struct NPPLFE
+{     /* linear form element */
+      int ref;
+      /* row/column reference number */
+      double val;
+      /* (non-zero) coefficient value */
+      NPPLFE *next;
+      /* pointer to another element */
+};
+
+#define npp_create_wksp _glp_npp_create_wksp
+NPP *npp_create_wksp(void);
+/* create LP/MIP preprocessor workspace */
+
+#define npp_insert_row _glp_npp_insert_row
+void npp_insert_row(NPP *npp, NPPROW *row, int where);
+/* insert row to the row list */
+
+#define npp_remove_row _glp_npp_remove_row
+void npp_remove_row(NPP *npp, NPPROW *row);
+/* remove row from the row list */
+
+#define npp_activate_row _glp_npp_activate_row
+void npp_activate_row(NPP *npp, NPPROW *row);
+/* make row active */
+
+#define npp_deactivate_row _glp_npp_deactivate_row
+void npp_deactivate_row(NPP *npp, NPPROW *row);
+/* make row inactive */
+
+#define npp_insert_col _glp_npp_insert_col
+void npp_insert_col(NPP *npp, NPPCOL *col, int where);
+/* insert column to the column list */
+
+#define npp_remove_col _glp_npp_remove_col
+void npp_remove_col(NPP *npp, NPPCOL *col);
+/* remove column from the column list */
+
+#define npp_activate_col _glp_npp_activate_col
+void npp_activate_col(NPP *npp, NPPCOL *col);
+/* make column active */
+
+#define npp_deactivate_col _glp_npp_deactivate_col
+void npp_deactivate_col(NPP *npp, NPPCOL *col);
+/* make column inactive */
+
+#define npp_add_row _glp_npp_add_row
+NPPROW *npp_add_row(NPP *npp);
+/* add new row to the current problem */
+
+#define npp_add_col _glp_npp_add_col
+NPPCOL *npp_add_col(NPP *npp);
+/* add new column to the current problem */
+
+#define npp_add_aij _glp_npp_add_aij
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val);
+/* add new element to the constraint matrix */
+
+#define npp_row_nnz _glp_npp_row_nnz
+int npp_row_nnz(NPP *npp, NPPROW *row);
+/* count number of non-zero coefficients in row */
+
+#define npp_col_nnz _glp_npp_col_nnz
+int npp_col_nnz(NPP *npp, NPPCOL *col);
+/* count number of non-zero coefficients in column */
+
+#define npp_push_tse _glp_npp_push_tse
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+      int size);
+/* push new entry to the transformation stack */
+
+#define npp_erase_row _glp_npp_erase_row
+void npp_erase_row(NPP *npp, NPPROW *row);
+/* erase row content to make it empty */
+
+#define npp_del_row _glp_npp_del_row
+void npp_del_row(NPP *npp, NPPROW *row);
+/* remove row from the current problem */
+
+#define npp_del_col _glp_npp_del_col
+void npp_del_col(NPP *npp, NPPCOL *col);
+/* remove column from the current problem */
+
+#define npp_del_aij _glp_npp_del_aij
+void npp_del_aij(NPP *npp, NPPAIJ *aij);
+/* remove element from the constraint matrix */
+
+#define npp_load_prob _glp_npp_load_prob
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+      int scaling);
+/* load original problem into the preprocessor workspace */
+
+#define npp_build_prob _glp_npp_build_prob
+void npp_build_prob(NPP *npp, glp_prob *prob);
+/* build resultant (preprocessed) problem */
+
+#define npp_postprocess _glp_npp_postprocess
+void npp_postprocess(NPP *npp, glp_prob *prob);
+/* postprocess solution from the resultant problem */
+
+#define npp_unload_sol _glp_npp_unload_sol
+void npp_unload_sol(NPP *npp, glp_prob *orig);
+/* store solution to the original problem */
+
+#define npp_delete_wksp _glp_npp_delete_wksp
+void npp_delete_wksp(NPP *npp);
+/* delete LP/MIP preprocessor workspace */
+
+#define npp_error()
+
+#define npp_free_row _glp_npp_free_row
+void npp_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_geq_row _glp_npp_geq_row
+void npp_geq_row(NPP *npp, NPPROW *p);
+/* process row of 'not less than' type */
+
+#define npp_leq_row _glp_npp_leq_row
+void npp_leq_row(NPP *npp, NPPROW *p);
+/* process row of 'not greater than' type */
+
+#define npp_free_col _glp_npp_free_col
+void npp_free_col(NPP *npp, NPPCOL *q);
+/* process free (unbounded) column */
+
+#define npp_lbnd_col _glp_npp_lbnd_col
+void npp_lbnd_col(NPP *npp, NPPCOL *q);
+/* process column with (non-zero) lower bound */
+
+#define npp_ubnd_col _glp_npp_ubnd_col
+void npp_ubnd_col(NPP *npp, NPPCOL *q);
+/* process column with upper bound */
+
+#define npp_dbnd_col _glp_npp_dbnd_col
+void npp_dbnd_col(NPP *npp, NPPCOL *q);
+/* process non-negative column with upper bound */
+
+#define npp_fixed_col _glp_npp_fixed_col
+void npp_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_make_equality _glp_npp_make_equality
+int npp_make_equality(NPP *npp, NPPROW *p);
+/* process row with almost identical bounds */
+
+#define npp_make_fixed _glp_npp_make_fixed
+int npp_make_fixed(NPP *npp, NPPCOL *q);
+/* process column with almost identical bounds */
+
+#define npp_empty_row _glp_npp_empty_row
+int npp_empty_row(NPP *npp, NPPROW *p);
+/* process empty row */
+
+#define npp_empty_col _glp_npp_empty_col
+int npp_empty_col(NPP *npp, NPPCOL *q);
+/* process empty column */
+
+#define npp_implied_value _glp_npp_implied_value
+int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+/* process implied column value */
+
+#define npp_eq_singlet _glp_npp_eq_singlet
+int npp_eq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (equality constraint) */
+
+#define npp_implied_lower _glp_npp_implied_lower
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+/* process implied column lower bound */
+
+#define npp_implied_upper _glp_npp_implied_upper
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+/* process implied upper bound of column */
+
+#define npp_ineq_singlet _glp_npp_ineq_singlet
+int npp_ineq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (inequality constraint) */
+
+#define npp_implied_slack _glp_npp_implied_slack
+void npp_implied_slack(NPP *npp, NPPCOL *q);
+/* process column singleton (implied slack variable) */
+
+#define npp_implied_free _glp_npp_implied_free
+int npp_implied_free(NPP *npp, NPPCOL *q);
+/* process column singleton (implied free variable) */
+
+#define npp_eq_doublet _glp_npp_eq_doublet
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+/* process row doubleton (equality constraint) */
+
+#define npp_forcing_row _glp_npp_forcing_row
+int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+/* process forcing row */
+
+#define npp_analyze_row _glp_npp_analyze_row
+int npp_analyze_row(NPP *npp, NPPROW *p);
+/* perform general row analysis */
+
+#define npp_inactive_bound _glp_npp_inactive_bound
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+/* remove row lower/upper inactive bound */
+
+#define npp_implied_bounds _glp_npp_implied_bounds
+void npp_implied_bounds(NPP *npp, NPPROW *p);
+/* determine implied column bounds */
+
+#define npp_binarize_prob _glp_npp_binarize_prob
+int npp_binarize_prob(NPP *npp);
+/* binarize MIP problem */
+
+#define npp_is_packing _glp_npp_is_packing
+int npp_is_packing(NPP *npp, NPPROW *row);
+/* test if constraint is packing inequality */
+
+#define npp_hidden_packing _glp_npp_hidden_packing
+int npp_hidden_packing(NPP *npp, NPPROW *row);
+/* identify hidden packing inequality */
+
+#define npp_implied_packing _glp_npp_implied_packing
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+      NPPCOL *var[], char set[]);
+/* identify implied packing inequality */
+
+#define npp_is_covering _glp_npp_is_covering
+int npp_is_covering(NPP *npp, NPPROW *row);
+/* test if constraint is covering inequality */
+
+#define npp_hidden_covering _glp_npp_hidden_covering
+int npp_hidden_covering(NPP *npp, NPPROW *row);
+/* identify hidden covering inequality */
+
+#define npp_is_partitioning _glp_npp_is_partitioning
+int npp_is_partitioning(NPP *npp, NPPROW *row);
+/* test if constraint is partitioning equality */
+
+#define npp_reduce_ineq_coef _glp_npp_reduce_ineq_coef
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+/* reduce inequality constraint coefficients */
+
+#define npp_clean_prob _glp_npp_clean_prob
+void npp_clean_prob(NPP *npp);
+/* perform initial LP/MIP processing */
+
+#define npp_process_row _glp_npp_process_row
+int npp_process_row(NPP *npp, NPPROW *row, int hard);
+/* perform basic row processing */
+
+#define npp_improve_bounds _glp_npp_improve_bounds
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+/* improve current column bounds */
+
+#define npp_process_col _glp_npp_process_col
+int npp_process_col(NPP *npp, NPPCOL *col);
+/* perform basic column processing */
+
+#define npp_process_prob _glp_npp_process_prob
+int npp_process_prob(NPP *npp, int hard);
+/* perform basic LP/MIP processing */
+
+#define npp_simplex _glp_npp_simplex
+int npp_simplex(NPP *npp, const glp_smcp *parm);
+/* process LP prior to applying primal/dual simplex method */
+
+#define npp_integer _glp_npp_integer
+int npp_integer(NPP *npp, const glp_iocp *parm);
+/* process MIP prior to applying branch-and-bound method */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpnpp01.c b/optional/glpk/glpnpp01.c
new file mode 100644
index 0000000..939b343
--- /dev/null
+++ b/optional/glpk/glpnpp01.c
@@ -0,0 +1,932 @@
+/* glpnpp01.c */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#include "glpnpp.h"
+
+NPP *npp_create_wksp(void)
+{     /* create LP/MIP preprocessor workspace */
+      NPP *npp;
+      npp = xmalloc(sizeof(NPP));
+      npp->orig_dir = 0;
+      npp->orig_m = npp->orig_n = npp->orig_nnz = 0;
+      npp->pool = dmp_create_pool();
+      npp->name = npp->obj = NULL;
+      npp->c0 = 0.0;
+      npp->nrows = npp->ncols = 0;
+      npp->r_head = npp->r_tail = NULL;
+      npp->c_head = npp->c_tail = NULL;
+      npp->stack = dmp_create_pool();
+      npp->top = NULL;
+#if 0 /* 16/XII-2009 */
+      memset(&npp->count, 0, sizeof(npp->count));
+#endif
+      npp->m = npp->n = npp->nnz = 0;
+      npp->row_ref = npp->col_ref = NULL;
+      npp->sol = npp->scaling = 0;
+      npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0;
+      npp->r_stat = NULL;
+      /*npp->r_prim =*/ npp->r_pi = NULL;
+      npp->c_stat = NULL;
+      npp->c_value = /*npp->c_dual =*/ NULL;
+      return npp;
+}
+
+void npp_insert_row(NPP *npp, NPPROW *row, int where)
+{     /* insert row to the row list */
+      if (where == 0)
+      {  /* insert row to the beginning of the row list */
+         row->prev = NULL;
+         row->next = npp->r_head;
+         if (row->next == NULL)
+            npp->r_tail = row;
+         else
+            row->next->prev = row;
+         npp->r_head = row;
+      }
+      else
+      {  /* insert row to the end of the row list */
+         row->prev = npp->r_tail;
+         row->next = NULL;
+         if (row->prev == NULL)
+            npp->r_head = row;
+         else
+            row->prev->next = row;
+         npp->r_tail = row;
+      }
+      return;
+}
+
+void npp_remove_row(NPP *npp, NPPROW *row)
+{     /* remove row from the row list */
+      if (row->prev == NULL)
+         npp->r_head = row->next;
+      else
+         row->prev->next = row->next;
+      if (row->next == NULL)
+         npp->r_tail = row->prev;
+      else
+         row->next->prev = row->prev;
+      return;
+}
+
+void npp_activate_row(NPP *npp, NPPROW *row)
+{     /* make row active */
+      if (!row->temp)
+      {  row->temp = 1;
+         /* move the row to the beginning of the row list */
+         npp_remove_row(npp, row);
+         npp_insert_row(npp, row, 0);
+      }
+      return;
+}
+
+void npp_deactivate_row(NPP *npp, NPPROW *row)
+{     /* make row inactive */
+      if (row->temp)
+      {  row->temp = 0;
+         /* move the row to the end of the row list */
+         npp_remove_row(npp, row);
+         npp_insert_row(npp, row, 1);
+      }
+      return;
+}
+
+void npp_insert_col(NPP *npp, NPPCOL *col, int where)
+{     /* insert column to the column list */
+      if (where == 0)
+      {  /* insert column to the beginning of the column list */
+         col->prev = NULL;
+         col->next = npp->c_head;
+         if (col->next == NULL)
+            npp->c_tail = col;
+         else
+            col->next->prev = col;
+         npp->c_head = col;
+      }
+      else
+      {  /* insert column to the end of the column list */
+         col->prev = npp->c_tail;
+         col->next = NULL;
+         if (col->prev == NULL)
+            npp->c_head = col;
+         else
+            col->prev->next = col;
+         npp->c_tail = col;
+      }
+      return;
+}
+
+void npp_remove_col(NPP *npp, NPPCOL *col)
+{     /* remove column from the column list */
+      if (col->prev == NULL)
+         npp->c_head = col->next;
+      else
+         col->prev->next = col->next;
+      if (col->next == NULL)
+         npp->c_tail = col->prev;
+      else
+         col->next->prev = col->prev;
+      return;
+}
+
+void npp_activate_col(NPP *npp, NPPCOL *col)
+{     /* make column active */
+      if (!col->temp)
+      {  col->temp = 1;
+         /* move the column to the beginning of the column list */
+         npp_remove_col(npp, col);
+         npp_insert_col(npp, col, 0);
+      }
+      return;
+}
+
+void npp_deactivate_col(NPP *npp, NPPCOL *col)
+{     /* make column inactive */
+      if (col->temp)
+      {  col->temp = 0;
+         /* move the column to the end of the column list */
+         npp_remove_col(npp, col);
+         npp_insert_col(npp, col, 1);
+      }
+      return;
+}
+
+NPPROW *npp_add_row(NPP *npp)
+{     /* add new row to the current problem */
+      NPPROW *row;
+      row = dmp_get_atom(npp->pool, sizeof(NPPROW));
+      row->i = ++(npp->nrows);
+      row->name = NULL;
+      row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+      row->ptr = NULL;
+      row->temp = 0;
+      npp_insert_row(npp, row, 1);
+      return row;
+}
+
+NPPCOL *npp_add_col(NPP *npp)
+{     /* add new column to the current problem */
+      NPPCOL *col;
+      col = dmp_get_atom(npp->pool, sizeof(NPPCOL));
+      col->j = ++(npp->ncols);
+      col->name = NULL;
+#if 0
+      col->kind = GLP_CV;
+#else
+      col->is_int = 0;
+#endif
+      col->lb = col->ub = col->coef = 0.0;
+      col->ptr = NULL;
+      col->temp = 0;
+      npp_insert_col(npp, col, 1);
+      return col;
+}
+
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val)
+{     /* add new element to the constraint matrix */
+      NPPAIJ *aij;
+      aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ));
+      aij->row = row;
+      aij->col = col;
+      aij->val = val;
+      aij->r_prev = NULL;
+      aij->r_next = row->ptr;
+      aij->c_prev = NULL;
+      aij->c_next = col->ptr;
+      if (aij->r_next != NULL)
+         aij->r_next->r_prev = aij;
+      if (aij->c_next != NULL)
+         aij->c_next->c_prev = aij;
+      row->ptr = col->ptr = aij;
+      return aij;
+}
+
+int npp_row_nnz(NPP *npp, NPPROW *row)
+{     /* count number of non-zero coefficients in row */
+      NPPAIJ *aij;
+      int nnz;
+      xassert(npp == npp);
+      nnz = 0;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         nnz++;
+      return nnz;
+}
+
+int npp_col_nnz(NPP *npp, NPPCOL *col)
+{     /* count number of non-zero coefficients in column */
+      NPPAIJ *aij;
+      int nnz;
+      xassert(npp == npp);
+      nnz = 0;
+      for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+         nnz++;
+      return nnz;
+}
+
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+      int size)
+{     /* push new entry to the transformation stack */
+      NPPTSE *tse;
+      tse = dmp_get_atom(npp->stack, sizeof(NPPTSE));
+      tse->func = func;
+      tse->info = dmp_get_atom(npp->stack, size);
+      tse->link = npp->top;
+      npp->top = tse;
+      return tse->info;
+}
+
+#if 1 /* 23/XII-2009 */
+void npp_erase_row(NPP *npp, NPPROW *row)
+{     /* erase row content to make it empty */
+      NPPAIJ *aij;
+      while (row->ptr != NULL)
+      {  aij = row->ptr;
+         row->ptr = aij->r_next;
+         if (aij->c_prev == NULL)
+            aij->col->ptr = aij->c_next;
+         else
+            aij->c_prev->c_next = aij->c_next;
+         if (aij->c_next == NULL)
+            ;
+         else
+            aij->c_next->c_prev = aij->c_prev;
+         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      }
+      return;
+}
+#endif
+
+void npp_del_row(NPP *npp, NPPROW *row)
+{     /* remove row from the current problem */
+#if 0 /* 23/XII-2009 */
+      NPPAIJ *aij;
+#endif
+      if (row->name != NULL)
+         dmp_free_atom(npp->pool, row->name, strlen(row->name)+1);
+#if 0 /* 23/XII-2009 */
+      while (row->ptr != NULL)
+      {  aij = row->ptr;
+         row->ptr = aij->r_next;
+         if (aij->c_prev == NULL)
+            aij->col->ptr = aij->c_next;
+         else
+            aij->c_prev->c_next = aij->c_next;
+         if (aij->c_next == NULL)
+            ;
+         else
+            aij->c_next->c_prev = aij->c_prev;
+         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      }
+#else
+      npp_erase_row(npp, row);
+#endif
+      npp_remove_row(npp, row);
+      dmp_free_atom(npp->pool, row, sizeof(NPPROW));
+      return;
+}
+
+void npp_del_col(NPP *npp, NPPCOL *col)
+{     /* remove column from the current problem */
+      NPPAIJ *aij;
+      if (col->name != NULL)
+         dmp_free_atom(npp->pool, col->name, strlen(col->name)+1);
+      while (col->ptr != NULL)
+      {  aij = col->ptr;
+         col->ptr = aij->c_next;
+         if (aij->r_prev == NULL)
+            aij->row->ptr = aij->r_next;
+         else
+            aij->r_prev->r_next = aij->r_next;
+         if (aij->r_next == NULL)
+            ;
+         else
+            aij->r_next->r_prev = aij->r_prev;
+         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      }
+      npp_remove_col(npp, col);
+      dmp_free_atom(npp->pool, col, sizeof(NPPCOL));
+      return;
+}
+
+void npp_del_aij(NPP *npp, NPPAIJ *aij)
+{     /* remove element from the constraint matrix */
+      if (aij->r_prev == NULL)
+         aij->row->ptr = aij->r_next;
+      else
+         aij->r_prev->r_next = aij->r_next;
+      if (aij->r_next == NULL)
+         ;
+      else
+         aij->r_next->r_prev = aij->r_prev;
+      if (aij->c_prev == NULL)
+         aij->col->ptr = aij->c_next;
+      else
+         aij->c_prev->c_next = aij->c_next;
+      if (aij->c_next == NULL)
+         ;
+      else
+         aij->c_next->c_prev = aij->c_prev;
+      dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      return;
+}
+
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+      int scaling)
+{     /* load original problem into the preprocessor workspace */
+      int m = orig->m;
+      int n = orig->n;
+      NPPROW **link;
+      int i, j;
+      double dir;
+      xassert(names == GLP_OFF || names == GLP_ON);
+      xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP);
+      xassert(scaling == GLP_OFF || scaling == GLP_ON);
+      if (sol == GLP_MIP) xassert(!scaling);
+      npp->orig_dir = orig->dir;
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      npp->orig_m = m;
+      npp->orig_n = n;
+      npp->orig_nnz = orig->nnz;
+      if (names && orig->name != NULL)
+      {  npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1);
+         strcpy(npp->name, orig->name);
+      }
+      if (names && orig->obj != NULL)
+      {  npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1);
+         strcpy(npp->obj, orig->obj);
+      }
+      npp->c0 = dir * orig->c0;
+      /* load rows */
+      link = xcalloc(1+m, sizeof(NPPROW *));
+      for (i = 1; i <= m; i++)
+      {  GLPROW *rrr = orig->row[i];
+         NPPROW *row;
+         link[i] = row = npp_add_row(npp);
+         xassert(row->i == i);
+         if (names && rrr->name != NULL)
+         {  row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1);
+            strcpy(row->name, rrr->name);
+         }
+         if (!scaling)
+         {  if (rrr->type == GLP_FR)
+               row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_LO)
+               row->lb = rrr->lb, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_UP)
+               row->lb = -DBL_MAX, row->ub = rrr->ub;
+            else if (rrr->type == GLP_DB)
+               row->lb = rrr->lb, row->ub = rrr->ub;
+            else if (rrr->type == GLP_FX)
+               row->lb = row->ub = rrr->lb;
+            else
+               xassert(rrr != rrr);
+         }
+         else
+         {  double rii = rrr->rii;
+            if (rrr->type == GLP_FR)
+               row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_LO)
+               row->lb = rrr->lb * rii, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_UP)
+               row->lb = -DBL_MAX, row->ub = rrr->ub * rii;
+            else if (rrr->type == GLP_DB)
+               row->lb = rrr->lb * rii, row->ub = rrr->ub * rii;
+            else if (rrr->type == GLP_FX)
+               row->lb = row->ub = rrr->lb * rii;
+            else
+               xassert(rrr != rrr);
+         }
+      }
+      /* load columns and constraint coefficients */
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *ccc = orig->col[j];
+         GLPAIJ *aaa;
+         NPPCOL *col;
+         col = npp_add_col(npp);
+         xassert(col->j == j);
+         if (names && ccc->name != NULL)
+         {  col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1);
+            strcpy(col->name, ccc->name);
+         }
+         if (sol == GLP_MIP)
+#if 0
+            col->kind = ccc->kind;
+#else
+            col->is_int = (char)(ccc->kind == GLP_IV);
+#endif
+         if (!scaling)
+         {  if (ccc->type == GLP_FR)
+               col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_LO)
+               col->lb = ccc->lb, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_UP)
+               col->lb = -DBL_MAX, col->ub = ccc->ub;
+            else if (ccc->type == GLP_DB)
+               col->lb = ccc->lb, col->ub = ccc->ub;
+            else if (ccc->type == GLP_FX)
+               col->lb = col->ub = ccc->lb;
+            else
+               xassert(ccc != ccc);
+            col->coef = dir * ccc->coef;
+            for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+               npp_add_aij(npp, link[aaa->row->i], col, aaa->val);
+         }
+         else
+         {  double sjj = ccc->sjj;
+            if (ccc->type == GLP_FR)
+               col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_LO)
+               col->lb = ccc->lb / sjj, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_UP)
+               col->lb = -DBL_MAX, col->ub = ccc->ub / sjj;
+            else if (ccc->type == GLP_DB)
+               col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj;
+            else if (ccc->type == GLP_FX)
+               col->lb = col->ub = ccc->lb / sjj;
+            else
+               xassert(ccc != ccc);
+            col->coef = dir * ccc->coef * sjj;
+            for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+               npp_add_aij(npp, link[aaa->row->i], col,
+                  aaa->row->rii * aaa->val * sjj);
+         }
+      }
+      xfree(link);
+      /* keep solution indicator and scaling option */
+      npp->sol = sol;
+      npp->scaling = scaling;
+      return;
+}
+
+void npp_build_prob(NPP *npp, glp_prob *prob)
+{     /* build resultant (preprocessed) problem */
+      NPPROW *row;
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int i, j, type, len, *ind;
+      double dir, *val;
+      glp_erase_prob(prob);
+      glp_set_prob_name(prob, npp->name);
+      glp_set_obj_name(prob, npp->obj);
+      glp_set_obj_dir(prob, npp->orig_dir);
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      glp_set_obj_coef(prob, 0, dir * npp->c0);
+      /* build rows */
+      for (row = npp->r_head; row != NULL; row = row->next)
+      {  row->temp = i = glp_add_rows(prob, 1);
+         glp_set_row_name(prob, i, row->name);
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+            type = GLP_FR;
+         else if (row->ub == +DBL_MAX)
+            type = GLP_LO;
+         else if (row->lb == -DBL_MAX)
+            type = GLP_UP;
+         else if (row->lb != row->ub)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_row_bnds(prob, i, type, row->lb, row->ub);
+      }
+      /* build columns and the constraint matrix */
+      ind = xcalloc(1+prob->m, sizeof(int));
+      val = xcalloc(1+prob->m, sizeof(double));
+      for (col = npp->c_head; col != NULL; col = col->next)
+      {  j = glp_add_cols(prob, 1);
+         glp_set_col_name(prob, j, col->name);
+#if 0
+         glp_set_col_kind(prob, j, col->kind);
+#else
+         glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV);
+#endif
+         if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+            type = GLP_FR;
+         else if (col->ub == +DBL_MAX)
+            type = GLP_LO;
+         else if (col->lb == -DBL_MAX)
+            type = GLP_UP;
+         else if (col->lb != col->ub)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(prob, j, type, col->lb, col->ub);
+         glp_set_obj_coef(prob, j, dir * col->coef);
+         len = 0;
+         for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+         {  len++;
+            ind[len] = aij->row->temp;
+            val[len] = aij->val;
+         }
+         glp_set_mat_col(prob, j, len, ind, val);
+      }
+      xfree(ind);
+      xfree(val);
+      /* resultant problem has been built */
+      npp->m = prob->m;
+      npp->n = prob->n;
+      npp->nnz = prob->nnz;
+      npp->row_ref = xcalloc(1+npp->m, sizeof(int));
+      npp->col_ref = xcalloc(1+npp->n, sizeof(int));
+      for (row = npp->r_head, i = 0; row != NULL; row = row->next)
+         npp->row_ref[++i] = row->i;
+      for (col = npp->c_head, j = 0; col != NULL; col = col->next)
+         npp->col_ref[++j] = col->j;
+      /* transformed problem segment is no longer needed */
+      dmp_delete_pool(npp->pool), npp->pool = NULL;
+      npp->name = npp->obj = NULL;
+      npp->c0 = 0.0;
+      npp->r_head = npp->r_tail = NULL;
+      npp->c_head = npp->c_tail = NULL;
+      return;
+}
+
+void npp_postprocess(NPP *npp, glp_prob *prob)
+{     /* postprocess solution from the resultant problem */
+      GLPROW *row;
+      GLPCOL *col;
+      NPPTSE *tse;
+      int i, j, k;
+      double dir;
+      xassert(npp->orig_dir == prob->dir);
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      xassert(npp->m == prob->m);
+      xassert(npp->n == prob->n);
+      xassert(npp->nnz == prob->nnz);
+      /* copy solution status */
+      if (npp->sol == GLP_SOL)
+      {  npp->p_stat = prob->pbs_stat;
+         npp->d_stat = prob->dbs_stat;
+      }
+      else if (npp->sol == GLP_IPT)
+         npp->t_stat = prob->ipt_stat;
+      else if (npp->sol == GLP_MIP)
+         npp->i_stat = prob->mip_stat;
+      else
+         xassert(npp != npp);
+      /* allocate solution arrays */
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat == NULL)
+            npp->r_stat = xcalloc(1+npp->nrows, sizeof(char));
+         for (i = 1; i <= npp->nrows; i++)
+            npp->r_stat[i] = 0;
+         if (npp->c_stat == NULL)
+            npp->c_stat = xcalloc(1+npp->ncols, sizeof(char));
+         for (j = 1; j <= npp->ncols; j++)
+            npp->c_stat[j] = 0;
+      }
+#if 0
+      if (npp->r_prim == NULL)
+         npp->r_prim = xcalloc(1+npp->nrows, sizeof(double));
+      for (i = 1; i <= npp->nrows; i++)
+         npp->r_prim[i] = DBL_MAX;
+#endif
+      if (npp->c_value == NULL)
+         npp->c_value = xcalloc(1+npp->ncols, sizeof(double));
+      for (j = 1; j <= npp->ncols; j++)
+         npp->c_value[j] = DBL_MAX;
+      if (npp->sol != GLP_MIP)
+      {  if (npp->r_pi == NULL)
+            npp->r_pi = xcalloc(1+npp->nrows, sizeof(double));
+         for (i = 1; i <= npp->nrows; i++)
+            npp->r_pi[i] = DBL_MAX;
+#if 0
+         if (npp->c_dual == NULL)
+            npp->c_dual = xcalloc(1+npp->ncols, sizeof(double));
+         for (j = 1; j <= npp->ncols; j++)
+            npp->c_dual[j] = DBL_MAX;
+#endif
+      }
+      /* copy solution components from the resultant problem */
+      if (npp->sol == GLP_SOL)
+      {  for (i = 1; i <= npp->m; i++)
+         {  row = prob->row[i];
+            k = npp->row_ref[i];
+            npp->r_stat[k] = (char)row->stat;
+            /*npp->r_prim[k] = row->prim;*/
+            npp->r_pi[k] = dir * row->dual;
+         }
+         for (j = 1; j <= npp->n; j++)
+         {  col = prob->col[j];
+            k = npp->col_ref[j];
+            npp->c_stat[k] = (char)col->stat;
+            npp->c_value[k] = col->prim;
+            /*npp->c_dual[k] = dir * col->dual;*/
+         }
+      }
+      else if (npp->sol == GLP_IPT)
+      {  for (i = 1; i <= npp->m; i++)
+         {  row = prob->row[i];
+            k = npp->row_ref[i];
+            /*npp->r_prim[k] = row->pval;*/
+            npp->r_pi[k] = dir * row->dval;
+         }
+         for (j = 1; j <= npp->n; j++)
+         {  col = prob->col[j];
+            k = npp->col_ref[j];
+            npp->c_value[k] = col->pval;
+            /*npp->c_dual[k] = dir * col->dval;*/
+         }
+      }
+      else if (npp->sol == GLP_MIP)
+      {
+#if 0
+         for (i = 1; i <= npp->m; i++)
+         {  row = prob->row[i];
+            k = npp->row_ref[i];
+            /*npp->r_prim[k] = row->mipx;*/
+         }
+#endif
+         for (j = 1; j <= npp->n; j++)
+         {  col = prob->col[j];
+            k = npp->col_ref[j];
+            npp->c_value[k] = col->mipx;
+         }
+      }
+      else
+         xassert(npp != npp);
+      /* perform postprocessing to construct solution to the original
+         problem */
+      for (tse = npp->top; tse != NULL; tse = tse->link)
+      {  xassert(tse->func != NULL);
+         xassert(tse->func(npp, tse->info) == 0);
+      }
+      return;
+}
+
+void npp_unload_sol(NPP *npp, glp_prob *orig)
+{     /* store solution to the original problem */
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      double dir;
+      xassert(npp->orig_dir == orig->dir);
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      xassert(npp->orig_m == orig->m);
+      xassert(npp->orig_n == orig->n);
+      xassert(npp->orig_nnz == orig->nnz);
+      if (npp->sol == GLP_SOL)
+      {  /* store basic solution */
+         orig->valid = 0;
+         orig->pbs_stat = npp->p_stat;
+         orig->dbs_stat = npp->d_stat;
+         orig->obj_val = orig->c0;
+         orig->some = 0;
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            row->stat = npp->r_stat[i];
+            if (!npp->scaling)
+            {  /*row->prim = npp->r_prim[i];*/
+               row->dual = dir * npp->r_pi[i];
+            }
+            else
+            {  /*row->prim = npp->r_prim[i] / row->rii;*/
+               row->dual = dir * npp->r_pi[i] * row->rii;
+            }
+            if (row->stat == GLP_BS)
+               row->dual = 0.0;
+            else if (row->stat == GLP_NL)
+            {  xassert(row->type == GLP_LO || row->type == GLP_DB);
+               row->prim = row->lb;
+            }
+            else if (row->stat == GLP_NU)
+            {  xassert(row->type == GLP_UP || row->type == GLP_DB);
+               row->prim = row->ub;
+            }
+            else if (row->stat == GLP_NF)
+            {  xassert(row->type == GLP_FR);
+               row->prim = 0.0;
+            }
+            else if (row->stat == GLP_NS)
+            {  xassert(row->type == GLP_FX);
+               row->prim = row->lb;
+            }
+            else
+               xassert(row != row);
+         }
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            col->stat = npp->c_stat[j];
+            if (!npp->scaling)
+            {  col->prim = npp->c_value[j];
+               /*col->dual = dir * npp->c_dual[j];*/
+            }
+            else
+            {  col->prim = npp->c_value[j] * col->sjj;
+               /*col->dual = dir * npp->c_dual[j] / col->sjj;*/
+            }
+            if (col->stat == GLP_BS)
+               col->dual = 0.0;
+#if 1
+            else if (col->stat == GLP_NL)
+            {  xassert(col->type == GLP_LO || col->type == GLP_DB);
+               col->prim = col->lb;
+            }
+            else if (col->stat == GLP_NU)
+            {  xassert(col->type == GLP_UP || col->type == GLP_DB);
+               col->prim = col->ub;
+            }
+            else if (col->stat == GLP_NF)
+            {  xassert(col->type == GLP_FR);
+               col->prim = 0.0;
+            }
+            else if (col->stat == GLP_NS)
+            {  xassert(col->type == GLP_FX);
+               col->prim = col->lb;
+            }
+            else
+               xassert(col != col);
+#endif
+            orig->obj_val += col->coef * col->prim;
+         }
+#if 1
+         /* compute primal values of inactive rows */
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            if (row->stat == GLP_BS)
+            {  GLPAIJ *aij;
+               double temp;
+               temp = 0.0;
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  temp += aij->val * aij->col->prim;
+               row->prim = temp;
+            }
+         }
+         /* compute reduced costs of active columns */
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            if (col->stat != GLP_BS)
+            {  GLPAIJ *aij;
+               double temp;
+               temp = col->coef;
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                  temp -= aij->val * aij->row->dual;
+               col->dual = temp;
+            }
+         }
+#endif
+      }
+      else if (npp->sol == GLP_IPT)
+      {  /* store interior-point solution */
+         orig->ipt_stat = npp->t_stat;
+         orig->ipt_obj = orig->c0;
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            if (!npp->scaling)
+            {  /*row->pval = npp->r_prim[i];*/
+               row->dval = dir * npp->r_pi[i];
+            }
+            else
+            {  /*row->pval = npp->r_prim[i] / row->rii;*/
+               row->dval = dir * npp->r_pi[i] * row->rii;
+            }
+         }
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            if (!npp->scaling)
+            {  col->pval = npp->c_value[j];
+               /*col->dval = dir * npp->c_dual[j];*/
+            }
+            else
+            {  col->pval = npp->c_value[j] * col->sjj;
+               /*col->dval = dir * npp->c_dual[j] / col->sjj;*/
+            }
+            orig->ipt_obj += col->coef * col->pval;
+         }
+#if 1
+         /* compute row primal values */
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            {  GLPAIJ *aij;
+               double temp;
+               temp = 0.0;
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  temp += aij->val * aij->col->pval;
+               row->pval = temp;
+            }
+         }
+         /* compute column dual values */
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            {  GLPAIJ *aij;
+               double temp;
+               temp = col->coef;
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                  temp -= aij->val * aij->row->dval;
+               col->dval = temp;
+            }
+         }
+#endif
+      }
+      else if (npp->sol == GLP_MIP)
+      {  /* store MIP solution */
+         xassert(!npp->scaling);
+         orig->mip_stat = npp->i_stat;
+         orig->mip_obj = orig->c0;
+#if 0
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            /*row->mipx = npp->r_prim[i];*/
+         }
+#endif
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            col->mipx = npp->c_value[j];
+            if (col->kind == GLP_IV)
+               xassert(col->mipx == floor(col->mipx));
+            orig->mip_obj += col->coef * col->mipx;
+         }
+#if 1
+         /* compute row primal values */
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            {  GLPAIJ *aij;
+               double temp;
+               temp = 0.0;
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  temp += aij->val * aij->col->mipx;
+               row->mipx = temp;
+            }
+         }
+#endif
+      }
+      else
+         xassert(npp != npp);
+      return;
+}
+
+void npp_delete_wksp(NPP *npp)
+{     /* delete LP/MIP preprocessor workspace */
+      if (npp->pool != NULL)
+         dmp_delete_pool(npp->pool);
+      if (npp->stack != NULL)
+         dmp_delete_pool(npp->stack);
+      if (npp->row_ref != NULL)
+         xfree(npp->row_ref);
+      if (npp->col_ref != NULL)
+         xfree(npp->col_ref);
+      if (npp->r_stat != NULL)
+         xfree(npp->r_stat);
+#if 0
+      if (npp->r_prim != NULL)
+         xfree(npp->r_prim);
+#endif
+      if (npp->r_pi != NULL)
+         xfree(npp->r_pi);
+      if (npp->c_stat != NULL)
+         xfree(npp->c_stat);
+      if (npp->c_value != NULL)
+         xfree(npp->c_value);
+#if 0
+      if (npp->c_dual != NULL)
+         xfree(npp->c_dual);
+#endif
+      xfree(npp);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnpp02.c b/optional/glpk/glpnpp02.c
new file mode 100644
index 0000000..70b527d
--- /dev/null
+++ b/optional/glpk/glpnpp02.c
@@ -0,0 +1,1433 @@
+/* glpnpp02.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_free_row - process free (unbounded) row
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_free_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_free_row processes row p, which is free (i.e. has
+*  no finite bounds):
+*
+*     -inf < sum a[p,j] x[j] < +inf.                                 (1)
+*             j
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (1) cannot be active, so it is redundant and can be
+*  removed from the original problem.
+*
+*  Removing row p leads to removing a column of multiplier pi[p] for
+*  this row in the dual system. Since row p has no bounds, pi[p] = 0,
+*  so removing the column does not affect the dual solution.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In solution to the original problem row p is inactive constraint,
+*  so it is assigned status GLP_BS, and multiplier pi[p] is assigned
+*  zero value.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  In solution to the original problem row p is inactive constraint,
+*  so its multiplier pi[p] is assigned zero value.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct free_row
+{     /* free (unbounded) row */
+      int p;
+      /* row reference number */
+};
+
+static int rcv_free_row(NPP *npp, void *info);
+
+void npp_free_row(NPP *npp, NPPROW *p)
+{     /* process free (unbounded) row */
+      struct free_row *info;
+      /* the row must be free */
+      xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_free_row, sizeof(struct free_row));
+      info->p = p->i;
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return;
+}
+
+static int rcv_free_row(NPP *npp, void *_info)
+{     /* recover free (unbounded) row */
+      struct free_row *info = _info;
+      if (npp->sol == GLP_SOL)
+         npp->r_stat[info->p] = GLP_BS;
+      if (npp->sol != GLP_MIP)
+         npp->r_pi[info->p] = 0.0;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_geq_row - process row of 'not less than' type
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_geq_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_geq_row processes row p, which is 'not less than'
+*  inequality constraint:
+*
+*     L[p] <= sum a[p,j] x[j] (<= U[p]),                             (1)
+*              j
+*
+*  where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (1) can be replaced by equality constraint:
+*
+*     sum a[p,j] x[j] - s = L[p],                                    (2)
+*      j
+*
+*  where
+*
+*     0 <= s (<= U[p] - L[p])                                        (3)
+*
+*  is a non-negative surplus variable.
+*
+*  Since in the primal system there appears column s having the only
+*  non-zero coefficient in row p, in the dual system there appears a
+*  new row:
+*
+*     (-1) pi[p] + lambda = 0,                                       (4)
+*
+*  where (-1) is coefficient of column s in row p, pi[p] is multiplier
+*  of row p, lambda is multiplier of column q, 0 is coefficient of
+*  column s in the objective row.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status and status of column q in solution to the transformed
+*  problem as follows:
+*
+*     +--------------------------------------+------------------+
+*     |         Transformed problem          | Original problem |
+*     +-----------------+--------------------+------------------+
+*     | Status of row p | Status of column s | Status of row p  |
+*     +-----------------+--------------------+------------------+
+*     |     GLP_BS      |       GLP_BS       |       N/A        |
+*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
+*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_NL       |      GLP_NL      |
+*     |     GLP_NS      |       GLP_NU       |      GLP_NU      |
+*     +-----------------+--------------------+------------------+
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  1. In solution to the transformed problem row p and column q cannot
+*     be basic at the same time; otherwise the basis matrix would have
+*     two linear dependent columns: unity column of auxiliary variable
+*     of row p and unity column of variable s.
+*
+*  2. Though in the transformed problem row p is equality constraint,
+*     it may be basic due to primal degenerate solution.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct ineq_row
+{     /* inequality constraint row */
+      int p;
+      /* row reference number */
+      int s;
+      /* column reference number for slack/surplus variable */
+};
+
+static int rcv_geq_row(NPP *npp, void *info);
+
+void npp_geq_row(NPP *npp, NPPROW *p)
+{     /* process row of 'not less than' type */
+      struct ineq_row *info;
+      NPPCOL *s;
+      /* the row must have lower bound */
+      xassert(p->lb != -DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* create column for surplus variable */
+      s = npp_add_col(npp);
+      s->lb = 0.0;
+      s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+      /* and add it to the transformed problem */
+      npp_add_aij(npp, p, s, -1.0);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_geq_row, sizeof(struct ineq_row));
+      info->p = p->i;
+      info->s = s->j;
+      /* replace the row by equality constraint */
+      p->ub = p->lb;
+      return;
+}
+
+static int rcv_geq_row(NPP *npp, void *_info)
+{     /* recover row of 'not less than' type */
+      struct ineq_row *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+            {  npp_error();
+               return 1;
+            }
+            else if (npp->c_stat[info->s] == GLP_NL ||
+                     npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_BS;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->r_stat[info->p] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->r_stat[info->p] = GLP_NL;
+            else if (npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_NU;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_leq_row - process row of 'not greater than' type
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_leq_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_leq_row processes row p, which is 'not greater than'
+*  inequality constraint:
+*
+*     (L[p] <=) sum a[p,j] x[j] <= U[p],                             (1)
+*                j
+*
+*  where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (1) can be replaced by equality constraint:
+*
+*     sum a[p,j] x[j] + s = L[p],                                    (2)
+*      j
+*
+*  where
+*
+*     0 <= s (<= U[p] - L[p])                                        (3)
+*
+*  is a non-negative slack variable.
+*
+*  Since in the primal system there appears column s having the only
+*  non-zero coefficient in row p, in the dual system there appears a
+*  new row:
+*
+*     (+1) pi[p] + lambda = 0,                                       (4)
+*
+*  where (+1) is coefficient of column s in row p, pi[p] is multiplier
+*  of row p, lambda is multiplier of column q, 0 is coefficient of
+*  column s in the objective row.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status and status of column q in solution to the transformed
+*  problem as follows:
+*
+*     +--------------------------------------+------------------+
+*     |         Transformed problem          | Original problem |
+*     +-----------------+--------------------+------------------+
+*     | Status of row p | Status of column s | Status of row p  |
+*     +-----------------+--------------------+------------------+
+*     |     GLP_BS      |       GLP_BS       |       N/A        |
+*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
+*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_NL       |      GLP_NU      |
+*     |     GLP_NS      |       GLP_NU       |      GLP_NL      |
+*     +-----------------+--------------------+------------------+
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  1. In solution to the transformed problem row p and column q cannot
+*     be basic at the same time; otherwise the basis matrix would have
+*     two linear dependent columns: unity column of auxiliary variable
+*     of row p and unity column of variable s.
+*
+*  2. Though in the transformed problem row p is equality constraint,
+*     it may be basic due to primal degeneracy.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+static int rcv_leq_row(NPP *npp, void *info);
+
+void npp_leq_row(NPP *npp, NPPROW *p)
+{     /* process row of 'not greater than' type */
+      struct ineq_row *info;
+      NPPCOL *s;
+      /* the row must have upper bound */
+      xassert(p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* create column for slack variable */
+      s = npp_add_col(npp);
+      s->lb = 0.0;
+      s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+      /* and add it to the transformed problem */
+      npp_add_aij(npp, p, s, +1.0);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_leq_row, sizeof(struct ineq_row));
+      info->p = p->i;
+      info->s = s->j;
+      /* replace the row by equality constraint */
+      p->lb = p->ub;
+      return;
+}
+
+static int rcv_leq_row(NPP *npp, void *_info)
+{     /* recover row of 'not greater than' type */
+      struct ineq_row *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+            {  npp_error();
+               return 1;
+            }
+            else if (npp->c_stat[info->s] == GLP_NL ||
+                     npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_BS;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->r_stat[info->p] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->r_stat[info->p] = GLP_NU;
+            else if (npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_NL;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_free_col - process free (unbounded) column
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_free_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_free_col processes column q, which is free (i.e. has
+*  no finite bounds):
+*
+*     -oo < x[q] < +oo.                                              (1)
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Free (unbounded) variable can be replaced by the difference of two
+*  non-negative variables:
+*
+*     x[q] = s' - s'',   s', s'' >= 0.                               (2)
+*
+*  Assuming that in the transformed problem x[q] becomes s',
+*  transformation (2) causes new column s'' to appear, which differs
+*  from column s' only in the sign of coefficients in constraint and
+*  objective rows. Thus, if in the dual system the following row
+*  corresponds to column s':
+*
+*     sum a[i,q] pi[i] + lambda' = c[q],                             (3)
+*      i
+*
+*  the row which corresponds to column s'' is the following:
+*
+*     sum (-a[i,q]) pi[i] + lambda'' = -c[q].                        (4)
+*      i
+*
+*  Then from (3) and (4) it follows that:
+*
+*     lambda' + lambda'' = 0   =>   lambda' = lmabda'' = 0,          (5)
+*
+*  where lambda' and lambda'' are multipliers for columns s' and s'',
+*  resp.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  With respect to (5) status of column q in solution to the original
+*  problem is determined by statuses of columns s' and s'' in solution
+*  to the transformed problem as follows:
+*
+*     +--------------------------------------+------------------+
+*     |         Transformed problem          | Original problem |
+*     +------------------+-------------------+------------------+
+*     | Status of col s' | Status of col s'' | Status of col q  |
+*     +------------------+-------------------+------------------+
+*     |      GLP_BS      |      GLP_BS       |       N/A        |
+*     |      GLP_BS      |      GLP_NL       |      GLP_BS      |
+*     |      GLP_NL      |      GLP_BS       |      GLP_BS      |
+*     |      GLP_NL      |      GLP_NL       |      GLP_NF      |
+*     +------------------+-------------------+------------------+
+*
+*  Value of column q is computed with formula (2).
+*
+*  1. In solution to the transformed problem columns s' and s'' cannot
+*     be basic at the same time, because they differ only in the sign,
+*     hence, are linear dependent.
+*
+*  2. Though column q is free, it can be non-basic due to dual
+*     degeneracy.
+*
+*  3. If column q is integral, columns s' and s'' are also integral.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (2). */
+
+struct free_col
+{     /* free (unbounded) column */
+      int q;
+      /* column reference number for variables x[q] and s' */
+      int s;
+      /* column reference number for variable s'' */
+};
+
+static int rcv_free_col(NPP *npp, void *info);
+
+void npp_free_col(NPP *npp, NPPCOL *q)
+{     /* process free (unbounded) column */
+      struct free_col *info;
+      NPPCOL *s;
+      NPPAIJ *aij;
+      /* the column must be free */
+      xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
+      /* variable x[q] becomes s' */
+      q->lb = 0.0, q->ub = +DBL_MAX;
+      /* create variable s'' */
+      s = npp_add_col(npp);
+      s->is_int = q->is_int;
+      s->lb = 0.0, s->ub = +DBL_MAX;
+      /* duplicate objective coefficient */
+      s->coef = -q->coef;
+      /* duplicate column of the constraint matrix */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         npp_add_aij(npp, aij->row, s, -aij->val);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_free_col, sizeof(struct free_col));
+      info->q = q->j;
+      info->s = s->j;
+      return;
+}
+
+static int rcv_free_col(NPP *npp, void *_info)
+{     /* recover free (unbounded) column */
+      struct free_col *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+            {  npp_error();
+               return 1;
+            }
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_BS;
+            else
+            {  npp_error();
+               return -1;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NL)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->c_stat[info->q] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_NF;
+            else
+            {  npp_error();
+               return -1;
+            }
+         }
+         else
+         {  npp_error();
+            return -1;
+         }
+      }
+      /* compute value of x[q] with formula (2) */
+      npp->c_value[info->q] -= npp->c_value[info->s];
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_lbnd_col - process column with (non-zero) lower bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_lbnd_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_lbnd_col processes column q, which has (non-zero)
+*  lower bound:
+*
+*     l[q] <= x[q] (<= u[q]),                                        (1)
+*
+*  where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Column q can be replaced as follows:
+*
+*     x[q] = l[q] + s,                                               (2)
+*
+*  where
+*
+*     0 <= s (<= u[q] - l[q])                                        (3)
+*
+*  is a non-negative variable.
+*
+*  Substituting x[q] from (2) into the objective row, we have:
+*
+*     z = sum c[j] x[j] + c0 =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] s + c~0,
+*
+*  where
+*
+*     c~0 = c0 + c[q] l[q]                                           (4)
+*
+*  is the constant term of the objective in the transformed problem.
+*  Similarly, substituting x[q] into constraint row i, we have:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i]  ==>
+*             j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+*              j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] l[q],  U~[i] = U[i] - a[i,q] l[q]        (5)
+*
+*  are lower and upper bounds of row i in the transformed problem,
+*  resp.
+*
+*  Transformation (2) does not affect the dual system.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of column q in solution to the original problem is the same
+*  as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (2). */
+
+struct bnd_col
+{     /* bounded column */
+      int q;
+      /* column reference number for variables x[q] and s */
+      double bnd;
+      /* lower/upper bound l[q] or u[q] */
+};
+
+static int rcv_lbnd_col(NPP *npp, void *info);
+
+void npp_lbnd_col(NPP *npp, NPPCOL *q)
+{     /* process column with (non-zero) lower bound */
+      struct bnd_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      /* the column must have non-zero lower bound */
+      xassert(q->lb != 0.0);
+      xassert(q->lb != -DBL_MAX);
+      xassert(q->lb < q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_lbnd_col, sizeof(struct bnd_col));
+      info->q = q->j;
+      info->bnd = q->lb;
+      /* substitute x[q] into objective row */
+      npp->c0 += q->coef * q->lb;
+      /* substitute x[q] into constraint rows */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb == i->ub)
+            i->ub = (i->lb -= aij->val * q->lb);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= aij->val * q->lb;
+            if (i->ub != +DBL_MAX)
+               i->ub -= aij->val * q->lb;
+         }
+      }
+      /* column x[q] becomes column s */
+      if (q->ub != +DBL_MAX)
+         q->ub -= q->lb;
+      q->lb = 0.0;
+      return;
+}
+
+static int rcv_lbnd_col(NPP *npp, void *_info)
+{     /* recover column with (non-zero) lower bound */
+      struct bnd_col *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->c_stat[info->q] == GLP_BS ||
+             npp->c_stat[info->q] == GLP_NL ||
+             npp->c_stat[info->q] == GLP_NU)
+            npp->c_stat[info->q] = npp->c_stat[info->q];
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      /* compute value of x[q] with formula (2) */
+      npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_ubnd_col - process column with upper bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_ubnd_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_ubnd_col processes column q, which has upper bound:
+*
+*     (l[q] <=) x[q] <= u[q],                                        (1)
+*
+*  where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Column q can be replaced as follows:
+*
+*     x[q] = u[q] - s,                                               (2)
+*
+*  where
+*
+*     0 <= s (<= u[q] - l[q])                                        (3)
+*
+*  is a non-negative variable.
+*
+*  Substituting x[q] from (2) into the objective row, we have:
+*
+*     z = sum c[j] x[j] + c0 =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] - c[q] s + c~0,
+*
+*  where
+*
+*     c~0 = c0 + c[q] u[q]                                           (4)
+*
+*  is the constant term of the objective in the transformed problem.
+*  Similarly, substituting x[q] into constraint row i, we have:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i]  ==>
+*             j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
+*              j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] u[q],  U~[i] = U[i] - a[i,q] u[q]        (5)
+*
+*  are lower and upper bounds of row i in the transformed problem,
+*  resp.
+*
+*  Note that in the transformed problem coefficients c[q] and a[i,q]
+*  change their sign. Thus, the row of the dual system corresponding to
+*  column q:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q]                            (6)
+*      i
+*
+*  in the transformed problem becomes the following:
+*
+*     sum (-a[i,q]) pi[i] + lambda[s] = -c[q].                       (7)
+*      i
+*
+*  Therefore:
+*
+*     lambda[q] = - lambda[s],                                       (8)
+*
+*  where lambda[q] is multiplier for column q, lambda[s] is multiplier
+*  for column s.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  With respect to (8) status of column q in solution to the original
+*  problem is determined by status of column s in solution to the
+*  transformed problem as follows:
+*
+*     +-----------------------+--------------------+
+*     |  Status of column s   | Status of column q |
+*     | (transformed problem) | (original problem) |
+*     +-----------------------+--------------------+
+*     |        GLP_BS         |       GLP_BS       |
+*     |        GLP_NL         |       GLP_NU       |
+*     |        GLP_NU         |       GLP_NL       |
+*     +-----------------------+--------------------+
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (2). */
+
+static int rcv_ubnd_col(NPP *npp, void *info);
+
+void npp_ubnd_col(NPP *npp, NPPCOL *q)
+{     /* process column with upper bound */
+      struct bnd_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      /* the column must have upper bound */
+      xassert(q->ub != +DBL_MAX);
+      xassert(q->lb < q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_ubnd_col, sizeof(struct bnd_col));
+      info->q = q->j;
+      info->bnd = q->ub;
+      /* substitute x[q] into objective row */
+      npp->c0 += q->coef * q->ub;
+      q->coef = -q->coef;
+      /* substitute x[q] into constraint rows */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb == i->ub)
+            i->ub = (i->lb -= aij->val * q->ub);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= aij->val * q->ub;
+            if (i->ub != +DBL_MAX)
+               i->ub -= aij->val * q->ub;
+         }
+         aij->val = -aij->val;
+      }
+      /* column x[q] becomes column s */
+      if (q->lb != -DBL_MAX)
+         q->ub -= q->lb;
+      else
+         q->ub = +DBL_MAX;
+      q->lb = 0.0;
+      return;
+}
+
+static int rcv_ubnd_col(NPP *npp, void *_info)
+{     /* recover column with upper bound */
+      struct bnd_col *info = _info;
+      if (npp->sol == GLP_BS)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+            npp->c_stat[info->q] = GLP_BS;
+         else if (npp->c_stat[info->q] == GLP_NL)
+            npp->c_stat[info->q] = GLP_NU;
+         else if (npp->c_stat[info->q] == GLP_NU)
+            npp->c_stat[info->q] = GLP_NL;
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      /* compute value of x[q] with formula (2) */
+      npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_dbnd_col - process non-negative column with upper bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_dbnd_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_dbnd_col processes column q, which is non-negative
+*  and has upper bound:
+*
+*     0 <= x[q] <= u[q],                                             (1)
+*
+*  where u[q] > 0.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Upper bound of column q can be replaced by the following equality
+*  constraint:
+*
+*     x[q] + s = u[q],                                               (2)
+*
+*  where s >= 0 is a non-negative complement variable.
+*
+*  Since in the primal system along with new row (2) there appears a
+*  new column s having the only non-zero coefficient in this row, in
+*  the dual system there appears a new row:
+*
+*     (+1)pi + lambda[s] = 0,                                        (3)
+*
+*  where (+1) is coefficient at column s in row (2), pi is multiplier
+*  for row (2), lambda[s] is multiplier for column s, 0 is coefficient
+*  at column s in the objective row.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of column q in solution to the original problem is determined
+*  by its status and status of column s in solution to the transformed
+*  problem as follows:
+*
+*     +-----------------------------------+------------------+
+*     |         Transformed problem       | Original problem |
+*     +-----------------+-----------------+------------------+
+*     | Status of col q | Status of col s | Status of col q  |
+*     +-----------------+-----------------+------------------+
+*     |     GLP_BS      |     GLP_BS      |      GLP_BS      |
+*     |     GLP_BS      |     GLP_NL      |      GLP_NU      |
+*     |     GLP_NL      |     GLP_BS      |      GLP_NL      |
+*     |     GLP_NL      |     GLP_NL      |      GLP_NL (*)  |
+*     +-----------------+-----------------+------------------+
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  1. Formally, in solution to the transformed problem columns q and s
+*     cannot be non-basic at the same time, since the constraint (2)
+*     would be violated. However, if u[q] is close to zero, violation
+*     may be less than a working precision even if both columns q and s
+*     are non-basic. In this degenerate case row (2) can be only basic,
+*     i.e. non-active constraint (otherwise corresponding row of the
+*     basis matrix would be zero). This allows to pivot out auxiliary
+*     variable and pivot in column s, in which case the row becomes
+*     active while column s becomes basic.
+*
+*  2. If column q is integral, column s is also integral.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem. */
+
+struct dbnd_col
+{     /* double-bounded column */
+      int q;
+      /* column reference number for variable x[q] */
+      int s;
+      /* column reference number for complement variable s */
+};
+
+static int rcv_dbnd_col(NPP *npp, void *info);
+
+void npp_dbnd_col(NPP *npp, NPPCOL *q)
+{     /* process non-negative column with upper bound */
+      struct dbnd_col *info;
+      NPPROW *p;
+      NPPCOL *s;
+      /* the column must be non-negative with upper bound */
+      xassert(q->lb == 0.0);
+      xassert(q->ub > 0.0);
+      xassert(q->ub != +DBL_MAX);
+      /* create variable s */
+      s = npp_add_col(npp);
+      s->is_int = q->is_int;
+      s->lb = 0.0, s->ub = +DBL_MAX;
+      /* create equality constraint (2) */
+      p = npp_add_row(npp);
+      p->lb = p->ub = q->ub;
+      npp_add_aij(npp, p, q, +1.0);
+      npp_add_aij(npp, p, s, +1.0);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_dbnd_col, sizeof(struct dbnd_col));
+      info->q = q->j;
+      info->s = s->j;
+      /* remove upper bound of x[q] */
+      q->ub = +DBL_MAX;
+      return;
+}
+
+static int rcv_dbnd_col(NPP *npp, void *_info)
+{     /* recover non-negative column with upper bound */
+      struct dbnd_col *info = _info;
+      if (npp->sol == GLP_BS)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->c_stat[info->q] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_NU;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NL)
+         {  if (npp->c_stat[info->s] == GLP_BS ||
+                npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_NL;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_fixed_col - process fixed column
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_fixed_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_fixed_col processes column q, which is fixed:
+*
+*     x[q] = s[q],                                                   (1)
+*
+*  where s[q] is a fixed column value.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  The value of a fixed column can be substituted into the objective
+*  and constraint rows that allows removing the column from the problem.
+*
+*  Substituting x[q] = s[q] into the objective row, we have:
+*
+*     z = sum c[j] x[j] + c0 =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] s[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c~0,
+*         j!=q
+*
+*  where
+*
+*     c~0 = c0 + c[q] s[q]                                           (2)
+*
+*  is the constant term of the objective in the transformed problem.
+*  Similarly, substituting x[q] = s[q] into constraint row i, we have:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i]  ==>
+*             j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+*              j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] s[q],  U~[i] = U[i] - a[i,q] s[q]        (3)
+*
+*  are lower and upper bounds of row i in the transformed problem,
+*  resp.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Column q is assigned status GLP_NS and its value is assigned s[q].
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is assigned s[q].
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is assigned s[q]. */
+
+struct fixed_col
+{     /* fixed column */
+      int q;
+      /* column reference number for variable x[q] */
+      double s;
+      /* value, at which x[q] is fixed */
+};
+
+static int rcv_fixed_col(NPP *npp, void *info);
+
+void npp_fixed_col(NPP *npp, NPPCOL *q)
+{     /* process fixed column */
+      struct fixed_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      /* the column must be fixed */
+      xassert(q->lb == q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_fixed_col, sizeof(struct fixed_col));
+      info->q = q->j;
+      info->s = q->lb;
+      /* substitute x[q] = s[q] into objective row */
+      npp->c0 += q->coef * q->lb;
+      /* substitute x[q] = s[q] into constraint rows */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb == i->ub)
+            i->ub = (i->lb -= aij->val * q->lb);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= aij->val * q->lb;
+            if (i->ub != +DBL_MAX)
+               i->ub -= aij->val * q->lb;
+         }
+      }
+      /* remove the column from the problem */
+      npp_del_col(npp, q);
+      return;
+}
+
+static int rcv_fixed_col(NPP *npp, void *_info)
+{     /* recover fixed column */
+      struct fixed_col *info = _info;
+      if (npp->sol == GLP_SOL)
+         npp->c_stat[info->q] = GLP_NS;
+      npp->c_value[info->q] = info->s;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_make_equality - process row with almost identical bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_make_equality(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_make_equality processes row p:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*              j
+*
+*  where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
+*  constraint.
+*
+*  RETURNS
+*
+*  0 - row bounds have not been changed;
+*
+*  1 - row has been replaced by equality constraint.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If bounds of row (1) are very close to each other:
+*
+*     U[p] - L[p] <= eps,                                            (2)
+*
+*  where eps is an absolute tolerance for row value, the row can be
+*  replaced by the following almost equivalent equiality constraint:
+*
+*     sum a[p,j] x[j] = b,                                           (3)
+*      j
+*
+*  where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
+*  to be very close to its nearest integer:
+*
+*     |b - floor(b + 0.5)| <= eps,                                   (4)
+*
+*  it is reasonable to use this nearest integer as the right-hand side.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status and the sign of its multiplier pi[p] in solution to
+*  the transformed problem as follows:
+*
+*     +-----------------------+---------+--------------------+
+*     |    Status of row p    | Sign of |  Status of row p   |
+*     | (transformed problem) |  pi[p]  | (original problem) |
+*     +-----------------------+---------+--------------------+
+*     |        GLP_BS         |  + / -  |       GLP_BS       |
+*     |        GLP_NS         |    +    |       GLP_NL       |
+*     |        GLP_NS         |    -    |       GLP_NU       |
+*     +-----------------------+---------+--------------------+
+*
+*  Value of row multiplier pi[p] in solution to the original problem is
+*  the same as in solution to the transformed problem.
+*
+*  RECOVERING INTERIOR POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem is
+*  the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct make_equality
+{     /* row with almost identical bounds */
+      int p;
+      /* row reference number */
+};
+
+static int rcv_make_equality(NPP *npp, void *info);
+
+int npp_make_equality(NPP *npp, NPPROW *p)
+{     /* process row with almost identical bounds */
+      struct make_equality *info;
+      double b, eps, nint;
+      /* the row must be double-sided inequality */
+      xassert(p->lb != -DBL_MAX);
+      xassert(p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* check row bounds */
+      eps = 1e-9 + 1e-12 * fabs(p->lb);
+      if (p->ub - p->lb > eps) return 0;
+      /* row bounds are very close to each other */
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_make_equality, sizeof(struct make_equality));
+      info->p = p->i;
+      /* compute right-hand side */
+      b = 0.5 * (p->ub + p->lb);
+      nint = floor(b + 0.5);
+      if (fabs(b - nint) <= eps) b = nint;
+      /* replace row p by almost equivalent equality constraint */
+      p->lb = p->ub = b;
+      return 1;
+}
+
+int rcv_make_equality(NPP *npp, void *_info)
+{     /* recover row with almost identical bounds */
+      struct make_equality *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+            npp->r_stat[info->p] = GLP_BS;
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  if (npp->r_pi[info->p] >= 0.0)
+               npp->r_stat[info->p] = GLP_NL;
+            else
+               npp->r_stat[info->p] = GLP_NU;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_make_fixed - process column with almost identical bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_make_fixed(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_make_fixed processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
+*  bounds.
+*
+*  RETURNS
+*
+*  0 - column bounds have not been changed;
+*
+*  1 - column has been fixed.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If bounds of column (1) are very close to each other:
+*
+*     u[q] - l[q] <= eps,                                            (2)
+*
+*  where eps is an absolute tolerance for column value, the column can
+*  be fixed:
+*
+*     x[q] = s[q],                                                   (3)
+*
+*  where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
+*  happens to be very close to its nearest integer:
+*
+*     |s[q] - floor(s[q] + 0.5)| <= eps,                             (4)
+*
+*  it is reasonable to use this nearest integer as the fixed value.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In the dual system of the original (as well as transformed) problem
+*  column q corresponds to the following row:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q].                           (5)
+*      i
+*
+*  Since multipliers pi[i] are known for all rows from solution to the
+*  transformed problem, formula (5) allows computing value of multiplier
+*  (reduced cost) for column q:
+*
+*     lambda[q] = c[q] - sum a[i,q] pi[i].                           (6)
+*                         i
+*
+*  Status of column q in solution to the original problem is determined
+*  by its status and the sign of its multiplier lambda[q] in solution to
+*  the transformed problem as follows:
+*
+*     +-----------------------+-----------+--------------------+
+*     |  Status of column q   |  Sign of  | Status of column q |
+*     | (transformed problem) | lambda[q] | (original problem) |
+*     +-----------------------+-----------+--------------------+
+*     |        GLP_BS         |   + / -   |       GLP_BS       |
+*     |        GLP_NS         |     +     |       GLP_NL       |
+*     |        GLP_NS         |     -     |       GLP_NU       |
+*     +-----------------------+-----------+--------------------+
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  RECOVERING INTERIOR POINT SOLUTION
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct make_fixed
+{     /* column with almost identical bounds */
+      int q;
+      /* column reference number */
+      double c;
+      /* objective coefficient at x[q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q] */
+};
+
+static int rcv_make_fixed(NPP *npp, void *info);
+
+int npp_make_fixed(NPP *npp, NPPCOL *q)
+{     /* process column with almost identical bounds */
+      struct make_fixed *info;
+      NPPAIJ *aij;
+      NPPLFE *lfe;
+      double s, eps, nint;
+      /* the column must be double-bounded */
+      xassert(q->lb != -DBL_MAX);
+      xassert(q->ub != +DBL_MAX);
+      xassert(q->lb < q->ub);
+      /* check column bounds */
+      eps = 1e-9 + 1e-12 * fabs(q->lb);
+      if (q->ub - q->lb > eps) return 0;
+      /* column bounds are very close to each other */
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_make_fixed, sizeof(struct make_fixed));
+      info->q = q->j;
+      info->c = q->coef;
+      info->ptr = NULL;
+      /* save column coefficients a[i,q] (needed for basic solution
+         only) */
+      if (npp->sol == GLP_SOL)
+      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = aij->row->i;
+            lfe->val = aij->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+      }
+      /* compute column fixed value */
+      s = 0.5 * (q->ub + q->lb);
+      nint = floor(s + 0.5);
+      if (fabs(s - nint) <= eps) s = nint;
+      /* make column q fixed */
+      q->lb = q->ub = s;
+      return 1;
+}
+
+static int rcv_make_fixed(NPP *npp, void *_info)
+{     /* recover column with almost identical bounds */
+      struct make_fixed *info = _info;
+      NPPLFE *lfe;
+      double lambda;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+            npp->c_stat[info->q] = GLP_BS;
+         else if (npp->c_stat[info->q] == GLP_NS)
+         {  /* compute multiplier for column q with formula (6) */
+            lambda = info->c;
+            for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+               lambda -= lfe->val * npp->r_pi[lfe->ref];
+            /* assign status to non-basic column */
+            if (lambda >= 0.0)
+               npp->c_stat[info->q] = GLP_NL;
+            else
+               npp->c_stat[info->q] = GLP_NU;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnpp03.c b/optional/glpk/glpnpp03.c
new file mode 100644
index 0000000..5e0ba18
--- /dev/null
+++ b/optional/glpk/glpnpp03.c
@@ -0,0 +1,2865 @@
+/* glpnpp03.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#endif
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_empty_row - process empty row
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_empty_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_empty_row processes row p, which is empty, i.e.
+*  coefficients at all columns in this row are zero:
+*
+*     L[p] <= sum 0 x[j] <= U[p],                                    (1)
+*
+*  where L[p] <= U[p].
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - problem has no primal feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If the following conditions hold:
+*
+*     L[p] <= +eps,  U[p] >= -eps,                                   (2)
+*
+*  where eps is an absolute tolerance for row value, the row p is
+*  redundant. In this case it can be replaced by equivalent redundant
+*  row, which is free (unbounded), and then removed from the problem.
+*  Otherwise, the row p is infeasible and, thus, the problem has no
+*  primal feasible solution.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  See the routine npp_free_row.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  See the routine npp_free_row.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+int npp_empty_row(NPP *npp, NPPROW *p)
+{     /* process empty row */
+      double eps = 1e-3;
+      /* the row must be empty */
+      xassert(p->ptr == NULL);
+      /* check primal feasibility */
+      if (p->lb > +eps || p->ub < -eps)
+         return 1;
+      /* replace the row by equivalent free (unbounded) row */
+      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+      /* and process it */
+      npp_free_row(npp, p);
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_empty_col - process empty column
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_empty_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_empty_col processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] <= u[q], which is empty, i.e. has zero coefficients in
+*  all constraint rows.
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - problem has no dual feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  The row of the dual system corresponding to the empty column is the
+*  following:
+*
+*     sum 0 pi[i] + lambda[q] = c[q],                                (2)
+*      i
+*
+*  from which it follows that:
+*
+*     lambda[q] = c[q].                                              (3)
+*
+*  If the following condition holds:
+*
+*     c[q] < - eps,                                                  (4)
+*
+*  where eps is an absolute tolerance for column multiplier, the lower
+*  column bound l[q] must be active to provide dual feasibility (note
+*  that being preprocessed the problem is always minimization). In this
+*  case the column can be fixed on its lower bound and removed from the
+*  problem (if the column is integral, its bounds are also assumed to
+*  be integral). And if the column has no lower bound (l[q] = -oo), the
+*  problem has no dual feasible solution.
+*
+*  If the following condition holds:
+*
+*     c[q] > + eps,                                                  (5)
+*
+*  the upper column bound u[q] must be active to provide dual
+*  feasibility. In this case the column can be fixed on its upper bound
+*  and removed from the problem. And if the column has no upper bound
+*  (u[q] = +oo), the problem has no dual feasible solution.
+*
+*  Finally, if the following condition holds:
+*
+*     - eps <= c[q] <= +eps,                                         (6)
+*
+*  dual feasibility does not depend on a particular value of column q.
+*  In this case the column can be fixed either on its lower bound (if
+*  l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
+*  column is unbounded) and then removed from the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  See the routine npp_fixed_col. Having been recovered the column
+*  is assigned status GLP_NS. However, if actually it is not fixed
+*  (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
+*  GLP_NF depending on which bound it was fixed on transformation stage.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  See the routine npp_fixed_col.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  See the routine npp_fixed_col. */
+
+struct empty_col
+{     /* empty column */
+      int q;
+      /* column reference number */
+      char stat;
+      /* status in basic solution */
+};
+
+static int rcv_empty_col(NPP *npp, void *info);
+
+int npp_empty_col(NPP *npp, NPPCOL *q)
+{     /* process empty column */
+      struct empty_col *info;
+      double eps = 1e-3;
+      /* the column must be empty */
+      xassert(q->ptr == NULL);
+      /* check dual feasibility */
+      if (q->coef > +eps && q->lb == -DBL_MAX)
+         return 1;
+      if (q->coef < -eps && q->ub == +DBL_MAX)
+         return 1;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_empty_col, sizeof(struct empty_col));
+      info->q = q->j;
+      /* fix the column */
+      if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
+      {  /* free column */
+         info->stat = GLP_NF;
+         q->lb = q->ub = 0.0;
+      }
+      else if (q->ub == +DBL_MAX)
+lo:   {  /* column with lower bound */
+         info->stat = GLP_NL;
+         q->ub = q->lb;
+      }
+      else if (q->lb == -DBL_MAX)
+up:   {  /* column with upper bound */
+         info->stat = GLP_NU;
+         q->lb = q->ub;
+      }
+      else if (q->lb != q->ub)
+      {  /* double-bounded column */
+         if (q->coef >= +DBL_EPSILON) goto lo;
+         if (q->coef <= -DBL_EPSILON) goto up;
+         if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
+      }
+      else
+      {  /* fixed column */
+         info->stat = GLP_NS;
+      }
+      /* process fixed column */
+      npp_fixed_col(npp, q);
+      return 0;
+}
+
+static int rcv_empty_col(NPP *npp, void *_info)
+{     /* recover empty column */
+      struct empty_col *info = _info;
+      if (npp->sol == GLP_SOL)
+         npp->c_stat[info->q] = info->stat;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_value - process implied column value
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+*
+*  DESCRIPTION
+*
+*  For column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], the routine npp_implied_value processes its
+*  implied value s[q]. If this implied value satisfies to the current
+*  column bounds and integrality condition, the routine fixes column q
+*  at the given point. Note that the column is kept in the problem in
+*  any case.
+*
+*  RETURNS
+*
+*  0 - column has been fixed;
+*
+*  1 - implied value violates to current column bounds;
+*
+*  2 - implied value violates integrality condition.
+*
+*  ALGORITHM
+*
+*  Implied column value s[q] satisfies to the current column bounds if
+*  the following condition holds:
+*
+*     l[q] - eps <= s[q] <= u[q] + eps,                              (2)
+*
+*  where eps is an absolute tolerance for column value. If the column
+*  is integral, the following condition also must hold:
+*
+*     |s[q] - floor(s[q]+0.5)| <= eps,                               (3)
+*
+*  where floor(s[q]+0.5) is the nearest integer to s[q].
+*
+*  If both condition (2) and (3) are satisfied, the column can be fixed
+*  at the value s[q], or, if it is integral, at floor(s[q]+0.5).
+*  Otherwise, if s[q] violates (2) or (3), the problem has no feasible
+*  solution.
+*
+*  Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
+*  fix the column at its lower or upper bound, resp. rather than at the
+*  implied value. */
+
+int npp_implied_value(NPP *npp, NPPCOL *q, double s)
+{     /* process implied column value */
+      double eps, nint;
+      xassert(npp == npp);
+      /* column must not be fixed */
+      xassert(q->lb < q->ub);
+      /* check integrality */
+      if (q->is_int)
+      {  nint = floor(s + 0.5);
+         if (fabs(s - nint) <= 1e-5)
+            s = nint;
+         else
+            return 2;
+      }
+      /* check current column lower bound */
+      if (q->lb != -DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+         if (s < q->lb - eps) return 1;
+         /* if s[q] is close to l[q], fix column at its lower bound
+            rather than at the implied value */
+         if (s < q->lb + 1e-3 * eps)
+         {  q->ub = q->lb;
+            return 0;
+         }
+      }
+      /* check current column upper bound */
+      if (q->ub != +DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+         if (s > q->ub + eps) return 1;
+         /* if s[q] is close to u[q], fix column at its upper bound
+            rather than at the implied value */
+         if (s > q->ub - 1e-3 * eps)
+         {  q->lb = q->ub;
+            return 0;
+         }
+      }
+      /* fix column at the implied value */
+      q->lb = q->ub = s;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_eq_singlet - process row singleton (equality constraint)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_eq_singlet(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_eq_singlet processes row p, which is equiality
+*  constraint having the only non-zero coefficient:
+*
+*     a[p,q] x[q] = b.                                               (1)
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - problem has no primal feasible solution;
+*
+*  2 - problem has no integer feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  The equality constraint defines implied value of column q:
+*
+*     x[q] = s[q] = b / a[p,q].                                      (2)
+*
+*  If the implied value s[q] satisfies to the column bounds (see the
+*  routine npp_implied_value), the column can be fixed at s[q] and
+*  removed from the problem. In this case row p becomes redundant, so
+*  it can be replaced by equivalent free row and also removed from the
+*  problem.
+*
+*  Note that the routine removes from the problem only row p. Column q
+*  becomes fixed, however, it is kept in the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In solution to the original problem row p is assigned status GLP_NS
+*  (active equality constraint), and column q is assigned status GLP_BS
+*  (basic column).
+*
+*  Multiplier for row p can be computed as follows. In the dual system
+*  of the original problem column q corresponds to the following row:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
+*      i
+*
+*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
+*     i!=p
+*
+*  Therefore:
+*
+*               1
+*     pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]),          (3)
+*             a[p,q]                     i!=q
+*
+*  where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
+*  i != p are known in solution to the transformed problem.
+*
+*  Value of column q in solution to the original problem is assigned
+*  its implied value s[q].
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Multiplier for row p is computed with formula (3). Value of column
+*  q is assigned its implied value s[q].
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is assigned its implied value s[q]. */
+
+struct eq_singlet
+{     /* row singleton (equality constraint) */
+      int p;
+      /* row reference number */
+      int q;
+      /* column reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      double c;
+      /* objective coefficient at x[q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_singlet(NPP *npp, void *info);
+
+int npp_eq_singlet(NPP *npp, NPPROW *p)
+{     /* process row singleton (equality constraint) */
+      struct eq_singlet *info;
+      NPPCOL *q;
+      NPPAIJ *aij;
+      NPPLFE *lfe;
+      int ret;
+      double s;
+      /* the row must be singleton equality constraint */
+      xassert(p->lb == p->ub);
+      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+      /* compute and process implied column value */
+      aij = p->ptr;
+      q = aij->col;
+      s = p->lb / aij->val;
+      ret = npp_implied_value(npp, q, s);
+      xassert(0 <= ret && ret <= 2);
+      if (ret != 0) return ret;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_eq_singlet, sizeof(struct eq_singlet));
+      info->p = p->i;
+      info->q = q->j;
+      info->apq = aij->val;
+      info->c = q->coef;
+      info->ptr = NULL;
+      /* save column coefficients a[i,q], i != p (not needed for MIP
+         solution) */
+      if (npp->sol != GLP_MIP)
+      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         {  if (aij->row == p) continue; /* skip a[p,q] */
+            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = aij->row->i;
+            lfe->val = aij->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+      }
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return 0;
+}
+
+static int rcv_eq_singlet(NPP *npp, void *_info)
+{     /* recover row singleton (equality constraint) */
+      struct eq_singlet *info = _info;
+      NPPLFE *lfe;
+      double temp;
+      if (npp->sol == GLP_SOL)
+      {  /* column q must be already recovered as GLP_NS */
+         if (npp->c_stat[info->q] != GLP_NS)
+         {  npp_error();
+            return 1;
+         }
+         npp->r_stat[info->p] = GLP_NS;
+         npp->c_stat[info->q] = GLP_BS;
+      }
+      if (npp->sol != GLP_MIP)
+      {  /* compute multiplier for row p with formula (3) */
+         temp = info->c;
+         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+            temp -= lfe->val * npp->r_pi[lfe->ref];
+         npp->r_pi[info->p] = temp / info->apq;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_lower - process implied column lower bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+*
+*  DESCRIPTION
+*
+*  For column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], the routine npp_implied_lower processes its
+*  implied lower bound l'[q]. As the result the current column lower
+*  bound may increase. Note that the column is kept in the problem in
+*  any case.
+*
+*  RETURNS
+*
+*  0 - current column lower bound has not changed;
+*
+*  1 - current column lower bound has changed, but not significantly;
+*
+*  2 - current column lower bound has significantly changed;
+*
+*  3 - column has been fixed on its upper bound;
+*
+*  4 - implied lower bound violates current column upper bound.
+*
+*  ALGORITHM
+*
+*  If column q is integral, before processing its implied lower bound
+*  should be rounded up:
+*
+*              ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
+*     l'[q] := <                                                     (2)
+*              ( ceil(l'[q]),      otherwise
+*
+*  where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
+*  is smallest integer not less than l'[q], and eps is an absolute
+*  tolerance for column value.
+*
+*  Processing implied column lower bound l'[q] includes the following
+*  cases:
+*
+*  1) if l'[q] < l[q] + eps, implied lower bound is redundant;
+*
+*  2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
+*     l[q] can be strengthened by replacing it with l'[q]. If in this
+*     case new column lower bound becomes close to current column upper
+*     bound u[q], the column can be fixed on its upper bound;
+*
+*  3) if l'[q] > u[q] + eps, implied lower bound violates current
+*     column upper bound u[q], in which case the problem has no primal
+*     feasible solution. */
+
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
+{     /* process implied column lower bound */
+      int ret;
+      double eps, nint;
+      xassert(npp == npp);
+      /* column must not be fixed */
+      xassert(q->lb < q->ub);
+      /* implied lower bound must be finite */
+      xassert(l != -DBL_MAX);
+      /* if column is integral, round up l'[q] */
+      if (q->is_int)
+      {  nint = floor(l + 0.5);
+         if (fabs(l - nint) <= 1e-5)
+            l = nint;
+         else
+            l = ceil(l);
+      }
+      /* check current column lower bound */
+      if (q->lb != -DBL_MAX)
+      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
+         if (l < q->lb + eps)
+         {  ret = 0; /* redundant */
+            goto done;
+         }
+      }
+      /* check current column upper bound */
+      if (q->ub != +DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+         if (l > q->ub + eps)
+         {  ret = 4; /* infeasible */
+            goto done;
+         }
+         /* if l'[q] is close to u[q], fix column at its upper bound */
+         if (l > q->ub - 1e-3 * eps)
+         {  q->lb = q->ub;
+            ret = 3; /* fixed */
+            goto done;
+         }
+      }
+      /* check if column lower bound changes significantly */
+      if (q->lb == -DBL_MAX)
+         ret = 2; /* significantly */
+      else if (q->is_int && l > q->lb + 0.5)
+         ret = 2; /* significantly */
+      else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
+         ret = 2; /* significantly */
+      else
+         ret = 1; /* not significantly */
+      /* set new column lower bound */
+      q->lb = l;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_upper - process implied column upper bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+*
+*  DESCRIPTION
+*
+*  For column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], the routine npp_implied_upper processes its
+*  implied upper bound u'[q]. As the result the current column upper
+*  bound may decrease. Note that the column is kept in the problem in
+*  any case.
+*
+*  RETURNS
+*
+*  0 - current column upper bound has not changed;
+*
+*  1 - current column upper bound has changed, but not significantly;
+*
+*  2 - current column upper bound has significantly changed;
+*
+*  3 - column has been fixed on its lower bound;
+*
+*  4 - implied upper bound violates current column lower bound.
+*
+*  ALGORITHM
+*
+*  If column q is integral, before processing its implied upper bound
+*  should be rounded down:
+*
+*              ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
+*     u'[q] := <                                                     (2)
+*              ( floor(l'[q]),     otherwise
+*
+*  where floor(u'[q]+0.5) is the nearest integer to u'[q],
+*  floor(u'[q]) is largest integer not greater than u'[q], and eps is
+*  an absolute tolerance for column value.
+*
+*  Processing implied column upper bound u'[q] includes the following
+*  cases:
+*
+*  1) if u'[q] > u[q] - eps, implied upper bound is redundant;
+*
+*  2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
+*     u[q] can be strengthened by replacing it with u'[q]. If in this
+*     case new column upper bound becomes close to current column lower
+*     bound, the column can be fixed on its lower bound;
+*
+*  3) if u'[q] < l[q] - eps, implied upper bound violates current
+*     column lower bound l[q], in which case the problem has no primal
+*     feasible solution. */
+
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
+{     int ret;
+      double eps, nint;
+      xassert(npp == npp);
+      /* column must not be fixed */
+      xassert(q->lb < q->ub);
+      /* implied upper bound must be finite */
+      xassert(u != +DBL_MAX);
+      /* if column is integral, round down u'[q] */
+      if (q->is_int)
+      {  nint = floor(u + 0.5);
+         if (fabs(u - nint) <= 1e-5)
+            u = nint;
+         else
+            u = floor(u);
+      }
+      /* check current column upper bound */
+      if (q->ub != +DBL_MAX)
+      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
+         if (u > q->ub - eps)
+         {  ret = 0; /* redundant */
+            goto done;
+         }
+      }
+      /* check current column lower bound */
+      if (q->lb != -DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+         if (u < q->lb - eps)
+         {  ret = 4; /* infeasible */
+            goto done;
+         }
+         /* if u'[q] is close to l[q], fix column at its lower bound */
+         if (u < q->lb + 1e-3 * eps)
+         {  q->ub = q->lb;
+            ret = 3; /* fixed */
+            goto done;
+         }
+      }
+      /* check if column upper bound changes significantly */
+      if (q->ub == +DBL_MAX)
+         ret = 2; /* significantly */
+      else if (q->is_int && u < q->ub - 0.5)
+         ret = 2; /* significantly */
+      else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
+         ret = 2; /* significantly */
+      else
+         ret = 1; /* not significantly */
+      /* set new column upper bound */
+      q->ub = u;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_ineq_singlet - process row singleton (inequality constraint)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_ineq_singlet(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_ineq_singlet processes row p, which is inequality
+*  constraint having the only non-zero coefficient:
+*
+*     L[p] <= a[p,q] * x[q] <= U[p],                                 (1)
+*
+*  where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+*  RETURNS
+*
+*  0 - current column bounds have not changed;
+*
+*  1 - current column bounds have changed, but not significantly;
+*
+*  2 - current column bounds have significantly changed;
+*
+*  3 - column has been fixed on its lower or upper bound;
+*
+*  4 - problem has no primal feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Inequality constraint (1) defines implied bounds of column q:
+*
+*             (  L[p] / a[p,q],  if a[p,q] > 0
+*     l'[q] = <                                                      (2)
+*             (  U[p] / a[p,q],  if a[p,q] < 0
+*
+*             (  U[p] / a[p,q],  if a[p,q] > 0
+*     u'[q] = <                                                      (3)
+*             (  L[p] / a[p,q],  if a[p,q] < 0
+*
+*  If these implied bounds do not violate current bounds of column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (4)
+*
+*  they can be used to strengthen the current column bounds:
+*
+*     l[q] := max(l[q], l'[q]),                                      (5)
+*
+*     u[q] := min(u[q], u'[q]).                                      (6)
+*
+*  (See the routines npp_implied_lower and npp_implied_upper.)
+*
+*  Once bounds of row p (1) have been carried over column q, the row
+*  becomes redundant, so it can be replaced by equivalent free row and
+*  removed from the problem.
+*
+*  Note that the routine removes from the problem only row p. Column q,
+*  even it has been fixed, is kept in the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Note that the row in the dual system corresponding to column q is
+*  the following:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
+*      i
+*                                                                    (7)
+*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
+*     i!=p
+*
+*  where pi[i] for all i != p are known in solution to the transformed
+*  problem. Row p does not exist in the transformed problem, so it has
+*  zero multiplier there. This allows computing multiplier for column q
+*  in solution to the transformed problem:
+*
+*     lambda~[q] = c[q] - sum a[i,q] pi[i].                          (8)
+*                         i!=p
+*
+*  Let in solution to the transformed problem column q be non-basic
+*  with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
+*  bound be implied one l'[q]. From the original problem's standpoint
+*  this then means that actually the original column lower bound l[q]
+*  is inactive, and active is that row bound L[p] or U[p] that defines
+*  the implied bound l'[q] (2). In this case in solution to the
+*  original problem column q is assigned status GLP_BS while row p is
+*  assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
+*  Since now column q is basic, its multiplier lambda[q] is zero. This
+*  allows using (7) and (8) to find multiplier for row p in solution to
+*  the original problem:
+*
+*               1
+*     pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
+*             a[p,q]         i!=p
+*
+*  Now let in solution to the transformed problem column q be non-basic
+*  with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
+*  bound be implied one u'[q]. As in the previous case this then means
+*  that from the original problem's standpoint actually the original
+*  column upper bound u[q] is inactive, and active is that row bound
+*  L[p] or U[p] that defines the implied bound u'[q] (3). In this case
+*  in solution to the original problem column q is assigned status
+*  GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
+*  (if a[p,q] < 0), and its multiplier is computed with formula (9).
+*
+*  Strengthening bounds of column q according to (5) and (6) may make
+*  it fixed. Thus, if in solution to the transformed problem column q is
+*  non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
+*  column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
+*  column q has active upper bound (GLP_NU), reducing this case to two
+*  previous ones. If, however, lambda~[q] is close to zero or
+*  corresponding bound of row p does not exist (this may happen if
+*  lambda~[q] has wrong sign due to round-off errors, in which case it
+*  is expected to be close to zero, since solution is assumed to be dual
+*  feasible), column q can be assigned status GLP_BS (basic), and row p
+*  can be made active on its existing bound. In the latter case row
+*  multiplier pi[p] computed with formula (9) will be also close to
+*  zero, and dual feasibility will be kept.
+*
+*  In all other cases, namely, if in solution to the transformed
+*  problem column q is basic (GLP_BS), or non-basic with original lower
+*  bound l[q] active (GLP_NL), or non-basic with original upper bound
+*  u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
+*  the original problem status of column q remains unchanged, row p is
+*  assigned status GLP_BS, and its multiplier pi[p] is assigned zero
+*  value.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  First, value of multiplier for column q in solution to the original
+*  problem is computed with formula (8). If lambda~[q] > 0 and column q
+*  has implied lower bound, or if lambda~[q] < 0 and column q has
+*  implied upper bound, this means that from the original problem's
+*  standpoint actually row p has corresponding active bound, in which
+*  case its multiplier pi[p] is computed with formula (9). In other
+*  cases, when the sign of lambda~[q] corresponds to original bound of
+*  column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
+*  assigned zero value.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct ineq_singlet
+{     /* row singleton (inequality constraint) */
+      int p;
+      /* row reference number */
+      int q;
+      /* column reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      double c;
+      /* objective coefficient at x[q] */
+      double lb;
+      /* row lower bound */
+      double ub;
+      /* row upper bound */
+      char lb_changed;
+      /* this flag is set if column lower bound was changed */
+      char ub_changed;
+      /* this flag is set if column upper bound was changed */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_ineq_singlet(NPP *npp, void *info);
+
+int npp_ineq_singlet(NPP *npp, NPPROW *p)
+{     /* process row singleton (inequality constraint) */
+      struct ineq_singlet *info;
+      NPPCOL *q;
+      NPPAIJ *apq, *aij;
+      NPPLFE *lfe;
+      int lb_changed, ub_changed;
+      double ll, uu;
+      /* the row must be singleton inequality constraint */
+      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+      /* compute implied column bounds */
+      apq = p->ptr;
+      q = apq->col;
+      xassert(q->lb < q->ub);
+      if (apq->val > 0.0)
+      {  ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
+         uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
+      }
+      else
+      {  ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
+         uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
+      }
+      /* process implied column lower bound */
+      if (ll == -DBL_MAX)
+         lb_changed = 0;
+      else
+      {  lb_changed = npp_implied_lower(npp, q, ll);
+         xassert(0 <= lb_changed && lb_changed <= 4);
+         if (lb_changed == 4) return 4; /* infeasible */
+      }
+      /* process implied column upper bound */
+      if (uu == +DBL_MAX)
+         ub_changed = 0;
+      else if (lb_changed == 3)
+      {  /* column was fixed on its upper bound due to l'[q] = u[q] */
+         /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
+         ub_changed = 0;
+      }
+      else
+      {  ub_changed = npp_implied_upper(npp, q, uu);
+         xassert(0 <= ub_changed && ub_changed <= 4);
+         if (ub_changed == 4) return 4; /* infeasible */
+      }
+      /* if neither lower nor upper column bound was changed, the row
+         is originally redundant and can be replaced by free row */
+      if (!lb_changed && !ub_changed)
+      {  p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+         npp_free_row(npp, p);
+         return 0;
+      }
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_ineq_singlet, sizeof(struct ineq_singlet));
+      info->p = p->i;
+      info->q = q->j;
+      info->apq = apq->val;
+      info->c = q->coef;
+      info->lb = p->lb;
+      info->ub = p->ub;
+      info->lb_changed = (char)lb_changed;
+      info->ub_changed = (char)ub_changed;
+      info->ptr = NULL;
+      /* save column coefficients a[i,q], i != p (not needed for MIP
+         solution) */
+      if (npp->sol != GLP_MIP)
+      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         {  if (aij == apq) continue; /* skip a[p,q] */
+            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = aij->row->i;
+            lfe->val = aij->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+      }
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return lb_changed >= ub_changed ? lb_changed : ub_changed;
+}
+
+static int rcv_ineq_singlet(NPP *npp, void *_info)
+{     /* recover row singleton (inequality constraint) */
+      struct ineq_singlet *info = _info;
+      NPPLFE *lfe;
+      double lambda;
+      if (npp->sol == GLP_MIP) goto done;
+      /* compute lambda~[q] in solution to the transformed problem
+         with formula (8) */
+      lambda = info->c;
+      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+         lambda -= lfe->val * npp->r_pi[lfe->ref];
+      if (npp->sol == GLP_SOL)
+      {  /* recover basic solution */
+         if (npp->c_stat[info->q] == GLP_BS)
+         {  /* column q is basic, so row p is inactive */
+            npp->r_stat[info->p] = GLP_BS;
+            npp->r_pi[info->p] = 0.0;
+         }
+         else if (npp->c_stat[info->q] == GLP_NL)
+nl:      {  /* column q is non-basic with lower bound active */
+            if (info->lb_changed)
+            {  /* it is implied bound, so actually row p is active
+                  while column q is basic */
+               npp->r_stat[info->p] =
+                  (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+               npp->c_stat[info->q] = GLP_BS;
+               npp->r_pi[info->p] = lambda / info->apq;
+            }
+            else
+            {  /* it is original bound, so row p is inactive */
+               npp->r_stat[info->p] = GLP_BS;
+               npp->r_pi[info->p] = 0.0;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NU)
+nu:      {  /* column q is non-basic with upper bound active */
+            if (info->ub_changed)
+            {  /* it is implied bound, so actually row p is active
+                  while column q is basic */
+               npp->r_stat[info->p] =
+                  (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+               npp->c_stat[info->q] = GLP_BS;
+               npp->r_pi[info->p] = lambda / info->apq;
+            }
+            else
+            {  /* it is original bound, so row p is inactive */
+               npp->r_stat[info->p] = GLP_BS;
+               npp->r_pi[info->p] = 0.0;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NS)
+         {  /* column q is non-basic and fixed; note, however, that in
+               in the original problem it is non-fixed */
+            if (lambda > +1e-7)
+            {  if (info->apq > 0.0 && info->lb != -DBL_MAX ||
+                   info->apq < 0.0 && info->ub != +DBL_MAX ||
+                  !info->lb_changed)
+               {  /* either corresponding bound of row p exists or
+                     column q remains non-basic with its original lower
+                     bound active */
+                  npp->c_stat[info->q] = GLP_NL;
+                  goto nl;
+               }
+            }
+            if (lambda < -1e-7)
+            {  if (info->apq > 0.0 && info->ub != +DBL_MAX ||
+                   info->apq < 0.0 && info->lb != -DBL_MAX ||
+                  !info->ub_changed)
+               {  /* either corresponding bound of row p exists or
+                     column q remains non-basic with its original upper
+                     bound active */
+                  npp->c_stat[info->q] = GLP_NU;
+                  goto nu;
+               }
+            }
+            /* either lambda~[q] is close to zero, or corresponding
+               bound of row p does not exist, because lambda~[q] has
+               wrong sign due to round-off errors; in the latter case
+               lambda~[q] is also assumed to be close to zero; so, we
+               can make row p active on its existing bound and column q
+               basic; pi[p] will have wrong sign, but it also will be
+               close to zero (rarus casus of dual degeneracy) */
+            if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
+            {  /* row lower bound exists, but upper bound doesn't */
+               npp->r_stat[info->p] = GLP_NL;
+            }
+            else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
+            {  /* row upper bound exists, but lower bound doesn't */
+               npp->r_stat[info->p] = GLP_NU;
+            }
+            else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
+            {  /* both row lower and upper bounds exist */
+               /* to choose proper active row bound we should not use
+                  lambda~[q], because its value being close to zero is
+                  unreliable; so we choose that bound which provides
+                  primal feasibility for original constraint (1) */
+               if (info->apq * npp->c_value[info->q] <=
+                   0.5 * (info->lb + info->ub))
+                  npp->r_stat[info->p] = GLP_NL;
+               else
+                  npp->r_stat[info->p] = GLP_NU;
+            }
+            else
+            {  npp_error();
+               return 1;
+            }
+            npp->c_stat[info->q] = GLP_BS;
+            npp->r_pi[info->p] = lambda / info->apq;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      if (npp->sol == GLP_IPT)
+      {  /* recover interior-point solution */
+         if (lambda > +DBL_EPSILON && info->lb_changed ||
+             lambda < -DBL_EPSILON && info->ub_changed)
+         {  /* actually row p has corresponding active bound */
+            npp->r_pi[info->p] = lambda / info->apq;
+         }
+         else
+         {  /* either bounds of column q are both inactive or its
+               original bound is active */
+            npp->r_pi[info->p] = 0.0;
+         }
+      }
+done: return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_slack - process column singleton (implied slack variable)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_implied_slack(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_slack processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], having the only non-zero coefficient in row p,
+*  which is equality constraint:
+*
+*     sum a[p,j] x[j] + a[p,q] x[q] = b.                             (2)
+*     j!=q
+*
+*  PROBLEM TRANSFORMATION
+*
+*  (If x[q] is integral, this transformation must not be used.)
+*
+*  The term a[p,q] x[q] in constraint (2) can be considered as a slack
+*  variable that allows to carry bounds of column q over row p and then
+*  remove column q from the problem.
+*
+*  Constraint (2) can be written as follows:
+*
+*     sum a[p,j] x[j] = b - a[p,q] x[q].                             (3)
+*     j!=q
+*
+*  According to (1) constraint (3) is equivalent to the following
+*  inequality constraint:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (4)
+*             j!=q
+*
+*  where
+*
+*            ( b - a[p,q] u[q],  if a[p,q] > 0
+*     L[p] = <                                                       (5)
+*            ( b - a[p,q] l[q],  if a[p,q] < 0
+*
+*            ( b - a[p,q] l[q],  if a[p,q] > 0
+*     U[p] = <                                                       (6)
+*            ( b - a[p,q] u[q],  if a[p,q] < 0
+*
+*  From (2) it follows that:
+*
+*              1
+*     x[q] = ------ (b - sum a[p,j] x[j]).                           (7)
+*            a[p,q]      j!=q
+*
+*  In order to eliminate x[q] from the objective row we substitute it
+*  from (6) to that row:
+*
+*     z = sum c[j] x[j] + c[q] x[q] + c[0] =
+*         j!=q
+*                                 1
+*       = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
+*         j!=q                  a[p,q]      j!=q
+*
+*       = sum c~[j] x[j] + c~[0],
+*         j!=q
+*                         a[p,j]                     b
+*     c~[j] = c[j] - c[q] ------,  c~0 = c0 - c[q] ------            (8)
+*                         a[p,q]                   a[p,q]
+*
+*  are values of objective coefficients and constant term, resp., in
+*  the transformed problem.
+*
+*  Note that column q is column singleton, so in the dual system of the
+*  original problem it corresponds to the following row singleton:
+*
+*     a[p,q] pi[p] + lambda[q] = c[q].                               (9)
+*
+*  In the transformed problem row (9) would be the following:
+*
+*     a[p,q] pi~[p] + lambda[q] = c~[q] = 0.                        (10)
+*
+*  Subtracting (10) from (9) we have:
+*
+*     a[p,q] (pi[p] - pi~[p]) = c[q]
+*
+*  that gives the following formula to compute multiplier for row p in
+*  solution to the original problem using its value in solution to the
+*  transformed problem:
+*
+*     pi[p] = pi~[p] + c[q] / a[p,q].                               (11)
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of column q in solution to the original problem is defined
+*  by status of row p in solution to the transformed problem and the
+*  sign of coefficient a[p,q] in the original inequality constraint (2)
+*  as follows:
+*
+*     +-----------------------+---------+--------------------+
+*     |    Status of row p    | Sign of | Status of column q |
+*     | (transformed problem) | a[p,q]  | (original problem) |
+*     +-----------------------+---------+--------------------+
+*     |        GLP_BS         |  + / -  |       GLP_BS       |
+*     |        GLP_NL         |    +    |       GLP_NU       |
+*     |        GLP_NL         |    -    |       GLP_NL       |
+*     |        GLP_NU         |    +    |       GLP_NL       |
+*     |        GLP_NU         |    -    |       GLP_NU       |
+*     |        GLP_NF         |  + / -  |       GLP_NF       |
+*     +-----------------------+---------+--------------------+
+*
+*  Value of column q is computed with formula (7). Since originally row
+*  p is equality constraint, its status is assigned GLP_NS, and value of
+*  its multiplier pi[p] is computed with formula (11).
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (7). Row multiplier value
+*  pi[p] is computed with formula (11).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (7). */
+
+struct implied_slack
+{     /* column singleton (implied slack variable) */
+      int p;
+      /* row reference number */
+      int q;
+      /* column reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      double b;
+      /* right-hand side of original equality constraint */
+      double c;
+      /* original objective coefficient at x[q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[p,j], j != q */
+};
+
+static int rcv_implied_slack(NPP *npp, void *info);
+
+void npp_implied_slack(NPP *npp, NPPCOL *q)
+{     /* process column singleton (implied slack variable) */
+      struct implied_slack *info;
+      NPPROW *p;
+      NPPAIJ *aij;
+      NPPLFE *lfe;
+      /* the column must be non-integral non-fixed singleton */
+      xassert(!q->is_int);
+      xassert(q->lb < q->ub);
+      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+      /* corresponding row must be equality constraint */
+      aij = q->ptr;
+      p = aij->row;
+      xassert(p->lb == p->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_implied_slack, sizeof(struct implied_slack));
+      info->p = p->i;
+      info->q = q->j;
+      info->apq = aij->val;
+      info->b = p->lb;
+      info->c = q->coef;
+      info->ptr = NULL;
+      /* save row coefficients a[p,j], j != q, and substitute x[q]
+         into the objective row */
+      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->col == q) continue; /* skip a[p,q] */
+         lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+         lfe->ref = aij->col->j;
+         lfe->val = aij->val;
+         lfe->next = info->ptr;
+         info->ptr = lfe;
+         aij->col->coef -= info->c * (aij->val / info->apq);
+      }
+      npp->c0 += info->c * (info->b / info->apq);
+      /* compute new row bounds */
+      if (info->apq > 0.0)
+      {  p->lb = (q->ub == +DBL_MAX ?
+            -DBL_MAX : info->b - info->apq * q->ub);
+         p->ub = (q->lb == -DBL_MAX ?
+            +DBL_MAX : info->b - info->apq * q->lb);
+      }
+      else
+      {  p->lb = (q->lb == -DBL_MAX ?
+            -DBL_MAX : info->b - info->apq * q->lb);
+         p->ub = (q->ub == +DBL_MAX ?
+            +DBL_MAX : info->b - info->apq * q->ub);
+      }
+      /* remove the column from the problem */
+      npp_del_col(npp, q);
+      return;
+}
+
+static int rcv_implied_slack(NPP *npp, void *_info)
+{     /* recover column singleton (implied slack variable) */
+      struct implied_slack *info = _info;
+      NPPLFE *lfe;
+      double temp;
+      if (npp->sol == GLP_SOL)
+      {  /* assign statuses to row p and column q */
+         if (npp->r_stat[info->p] == GLP_BS ||
+             npp->r_stat[info->p] == GLP_NF)
+            npp->c_stat[info->q] = npp->r_stat[info->p];
+         else if (npp->r_stat[info->p] == GLP_NL)
+            npp->c_stat[info->q] =
+               (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+         else if (npp->r_stat[info->p] == GLP_NU)
+            npp->c_stat[info->q] =
+               (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+         else
+         {  npp_error();
+            return 1;
+         }
+         npp->r_stat[info->p] = GLP_NS;
+      }
+      if (npp->sol != GLP_MIP)
+      {  /* compute multiplier for row p */
+         npp->r_pi[info->p] += info->c / info->apq;
+      }
+      /* compute value of column q */
+      temp = info->b;
+      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+         temp -= lfe->val * npp->c_value[lfe->ref];
+      npp->c_value[info->q] = temp / info->apq;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_free - process column singleton (implied free variable)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_free(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_free processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  having non-zero coefficient in the only row p, which is inequality
+*  constraint:
+*
+*     L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p],                 (2)
+*             j!=q
+*
+*  where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - column lower and/or upper bound(s) can be active;
+*
+*  2 - problem has no dual feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (2) can be written as follows:
+*
+*     L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
+*            j!=q                                     j!=q
+*
+*  from which it follows that:
+*
+*     alfa <= a[p,q] x[q] <= beta,                                   (3)
+*
+*  where
+*
+*     alfa = inf(L[p] - sum a[p,j] x[j]) =
+*                       j!=q
+*
+*          = L[p] - sup sum a[p,j] x[j] =                            (4)
+*                       j!=q
+*
+*          = L[p] -  sum  a[p,j] u[j] -  sum  a[p,j] l[j],
+*                  j in Jp             j in Jn
+*
+*     beta = sup(L[p] - sum a[p,j] x[j]) =
+*                       j!=q
+*
+*          = L[p] - inf sum a[p,j] x[j] =                            (5)
+*                       j!=q
+*
+*          = L[p] -  sum  a[p,j] l[j] -  sum  a[p,j] u[j],
+*                  j in Jp             j in Jn
+*
+*     Jp = {j != q: a[p,j] > 0},  Jn = {j != q: a[p,j] < 0}.         (6)
+*
+*  Inequality (3) defines implied bounds of variable x[q]:
+*
+*     l'[q] <= x[q] <= u'[q],                                        (7)
+*
+*  where
+*
+*             ( alfa / a[p,q], if a[p,q] > 0
+*     l'[q] = <                                                     (8a)
+*             ( beta / a[p,q], if a[p,q] < 0
+*
+*             ( beta / a[p,q], if a[p,q] > 0
+*     u'[q] = <                                                     (8b)
+*             ( alfa / a[p,q], if a[p,q] < 0
+*
+*  Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
+*  an absolute tolerance for column value, column bounds (1) cannot be
+*  active, in which case column q can be replaced by equivalent free
+*  (unbounded) column.
+*
+*  Note that column q is column singleton, so in the dual system of the
+*  original problem it corresponds to the following row singleton:
+*
+*     a[p,q] pi[p] + lambda[q] = c[q],                               (9)
+*
+*  from which it follows that:
+*
+*     pi[p] = (c[q] - lambda[q]) / a[p,q].                          (10)
+*
+*  Let x[q] be implied free (unbounded) variable. Then column q can be
+*  only basic, so its multiplier lambda[q] is equal to zero, and from
+*  (10) we have:
+*
+*     pi[p] = c[q] / a[p,q].                                        (11)
+*
+*  There are possible three cases:
+*
+*  1) pi[p] < -eps, where eps is an absolute tolerance for row
+*     multiplier. In this case, to provide dual feasibility of the
+*     original problem, row p must be active on its lower bound, and
+*     if its lower bound does not exist (L[p] = -oo), the problem has
+*     no dual feasible solution;
+*
+*  2) pi[p] > +eps. In this case row p must be active on its upper
+*     bound, and if its upper bound does not exist (U[p] = +oo), the
+*     problem has no dual feasible solution;
+*
+*  3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
+*     bound of row p can be active, because this does not affect dual
+*     feasibility.
+*
+*  Thus, in all three cases original inequality constraint (2) can be
+*  replaced by equality constraint, where the right-hand side is either
+*  lower or upper bound of row p, and bounds of column q can be removed
+*  that makes it free (unbounded). (May note that this transformation
+*  can be followed by transformation "Column singleton (implied slack
+*  variable)" performed by the routine npp_implied_slack.)
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status in solution to the transformed problem and its bound,
+*  which was choosen to be active:
+*
+*     +-----------------------+--------+--------------------+
+*     |    Status of row p    | Active | Status of row p    |
+*     | (transformed problem) | bound  | (original problem) |
+*     +-----------------------+--------+--------------------+
+*     |        GLP_BS         |  L[p]  |       GLP_BS       |
+*     |        GLP_BS         |  U[p]  |       GLP_BS       |
+*     |        GLP_NS         |  L[p]  |       GLP_NL       |
+*     |        GLP_NS         |  U[p]  |       GLP_NU       |
+*     +-----------------------+--------+--------------------+
+*
+*  Value of row multiplier pi[p] (as well as value of column q) in
+*  solution to the original problem is the same as in solution to the
+*  transformed problem.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem is
+*  the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct implied_free
+{     /* column singleton (implied free variable) */
+      int p;
+      /* row reference number */
+      char stat;
+      /* row status:
+         GLP_NL - active constraint on lower bound
+         GLP_NU - active constraint on upper bound */
+};
+
+static int rcv_implied_free(NPP *npp, void *info);
+
+int npp_implied_free(NPP *npp, NPPCOL *q)
+{     /* process column singleton (implied free variable) */
+      struct implied_free *info;
+      NPPROW *p;
+      NPPAIJ *apq, *aij;
+      double alfa, beta, l, u, pi, eps;
+      /* the column must be non-fixed singleton */
+      xassert(q->lb < q->ub);
+      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+      /* corresponding row must be inequality constraint */
+      apq = q->ptr;
+      p = apq->row;
+      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* compute alfa */
+      alfa = p->lb;
+      if (alfa != -DBL_MAX)
+      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+         {  if (aij == apq) continue; /* skip a[p,q] */
+            if (aij->val > 0.0)
+            {  if (aij->col->ub == +DBL_MAX)
+               {  alfa = -DBL_MAX;
+                  break;
+               }
+               alfa -= aij->val * aij->col->ub;
+            }
+            else /* < 0.0 */
+            {  if (aij->col->lb == -DBL_MAX)
+               {  alfa = -DBL_MAX;
+                  break;
+               }
+               alfa -= aij->val * aij->col->lb;
+            }
+         }
+      }
+      /* compute beta */
+      beta = p->ub;
+      if (beta != +DBL_MAX)
+      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+         {  if (aij == apq) continue; /* skip a[p,q] */
+            if (aij->val > 0.0)
+            {  if (aij->col->lb == -DBL_MAX)
+               {  beta = +DBL_MAX;
+                  break;
+               }
+               beta -= aij->val * aij->col->lb;
+            }
+            else /* < 0.0 */
+            {  if (aij->col->ub == +DBL_MAX)
+               {  beta = +DBL_MAX;
+                  break;
+               }
+               beta -= aij->val * aij->col->ub;
+            }
+         }
+      }
+      /* compute implied column lower bound l'[q] */
+      if (apq->val > 0.0)
+         l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
+      else /* < 0.0 */
+         l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
+      /* compute implied column upper bound u'[q] */
+      if (apq->val > 0.0)
+         u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
+      else
+         u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
+      /* check if column lower bound l[q] can be active */
+      if (q->lb != -DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(q->lb);
+         if (l < q->lb - eps) return 1; /* yes, it can */
+      }
+      /* check if column upper bound u[q] can be active */
+      if (q->ub != +DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(q->ub);
+         if (u > q->ub + eps) return 1; /* yes, it can */
+      }
+      /* okay; make column q free (unbounded) */
+      q->lb = -DBL_MAX, q->ub = +DBL_MAX;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_implied_free, sizeof(struct implied_free));
+      info->p = p->i;
+      info->stat = -1;
+      /* compute row multiplier pi[p] */
+      pi = q->coef / apq->val;
+      /* check dual feasibility for row p */
+      if (pi > +DBL_EPSILON)
+      {  /* lower bound L[p] must be active */
+         if (p->lb != -DBL_MAX)
+nl:      {  info->stat = GLP_NL;
+            p->ub = p->lb;
+         }
+         else
+         {  if (pi > +1e-5) return 2; /* dual infeasibility */
+            /* take a chance on U[p] */
+            xassert(p->ub != +DBL_MAX);
+            goto nu;
+         }
+      }
+      else if (pi < -DBL_EPSILON)
+      {  /* upper bound U[p] must be active */
+         if (p->ub != +DBL_MAX)
+nu:      {  info->stat = GLP_NU;
+            p->lb = p->ub;
+         }
+         else
+         {  if (pi < -1e-5) return 2; /* dual infeasibility */
+            /* take a chance on L[p] */
+            xassert(p->lb != -DBL_MAX);
+            goto nl;
+         }
+      }
+      else
+      {  /* any bound (either L[p] or U[p]) can be made active  */
+         if (p->ub == +DBL_MAX)
+         {  xassert(p->lb != -DBL_MAX);
+            goto nl;
+         }
+         if (p->lb == -DBL_MAX)
+         {  xassert(p->ub != +DBL_MAX);
+            goto nu;
+         }
+         if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
+      }
+      return 0;
+}
+
+static int rcv_implied_free(NPP *npp, void *_info)
+{     /* recover column singleton (implied free variable) */
+      struct implied_free *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+            npp->r_stat[info->p] = GLP_BS;
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  xassert(info->stat == GLP_NL || info->stat == GLP_NU);
+            npp->r_stat[info->p] = info->stat;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_eq_doublet - process row doubleton (equality constraint)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_eq_doublet processes row p, which is equality
+*  constraint having exactly two non-zero coefficients:
+*
+*     a[p,q] x[q] + a[p,r] x[r] = b.                                 (1)
+*
+*  As the result of processing one of columns q or r is eliminated from
+*  all other rows and, thus, becomes column singleton of type "implied
+*  slack variable". Row p is not changed and along with column q and r
+*  remains in the problem.
+*
+*  RETURNS
+*
+*  The routine npp_eq_doublet returns pointer to the descriptor of that
+*  column q or r which has been eliminated. If, due to some reason, the
+*  elimination was not performed, the routine returns NULL.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  First, we decide which column q or r will be eliminated. Let it be
+*  column q. Consider i-th constraint row, where column q has non-zero
+*  coefficient a[i,q] != 0:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i].                               (2)
+*              j
+*
+*  In order to eliminate column q from row (2) we subtract from it row
+*  (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
+*  transformed problem row (2) by its linear combination with row (1).
+*  This transformation changes only coefficients in columns q and r,
+*  and bounds of row i as follows:
+*
+*     a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0,                        (3)
+*
+*     a~[i,r] = a[i,r] - gamma[i] a[p,r],                            (4)
+*
+*       L~[i] = L[i] - gamma[i] b,                                   (5)
+*
+*       U~[i] = U[i] - gamma[i] b.                                   (6)
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  The transformation of the primal system of the original problem:
+*
+*     L <= A x <= U                                                  (7)
+*
+*  is equivalent to multiplying from the left a transformation matrix F
+*  by components of this primal system, which in the transformed problem
+*  becomes the following:
+*
+*     F L <= F A x <= F U  ==>  L~ <= A~x <= U~.                     (8)
+*
+*  The matrix F has the following structure:
+*
+*         ( 1           -gamma[1]            )
+*         (                                  )
+*         (    1        -gamma[2]            )
+*         (                                  )
+*         (      ...       ...               )
+*         (                                  )
+*     F = (          1  -gamma[p-1]          )                       (9)
+*         (                                  )
+*         (                 1                )
+*         (                                  )
+*         (             -gamma[p+1]  1       )
+*         (                                  )
+*         (                ...          ...  )
+*
+*  where its column containing elements -gamma[i] corresponds to row p
+*  of the primal system.
+*
+*  From (8) it follows that the dual system of the original problem:
+*
+*     A'pi + lambda = c,                                            (10)
+*
+*  in the transformed problem becomes the following:
+*
+*     A'F'inv(F')pi + lambda = c  ==>  (A~)'pi~ + lambda = c,       (11)
+*
+*  where:
+*
+*     pi~ = inv(F')pi                                               (12)
+*
+*  is the vector of row multipliers in the transformed problem. Thus:
+*
+*     pi = F'pi~.                                                   (13)
+*
+*  Therefore, as it follows from (13), value of multiplier for row p in
+*  solution to the original problem can be computed as follows:
+*
+*     pi[p] = pi~[p] - sum gamma[i] pi~[i],                         (14)
+*                       i
+*
+*  where pi~[i] = pi[i] is multiplier for row i (i != p).
+*
+*  Note that the statuses of all rows and columns are not changed.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Multiplier for row p in solution to the original problem is computed
+*  with formula (14).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct eq_doublet
+{     /* row doubleton (equality constraint) */
+      int p;
+      /* row reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_doublet(NPP *npp, void *info);
+
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
+{     /* process row doubleton (equality constraint) */
+      struct eq_doublet *info;
+      NPPROW *i;
+      NPPCOL *q, *r;
+      NPPAIJ *apq, *apr, *aiq, *air, *next;
+      NPPLFE *lfe;
+      double gamma;
+      /* the row must be doubleton equality constraint */
+      xassert(p->lb == p->ub);
+      xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
+              p->ptr->r_next->r_next == NULL);
+      /* choose column to be eliminated */
+      {  NPPAIJ *a1, *a2;
+         a1 = p->ptr, a2 = a1->r_next;
+         if (fabs(a2->val) < 0.001 * fabs(a1->val))
+         {  /* only first column can be eliminated, because second one
+               has too small constraint coefficient */
+            apq = a1, apr = a2;
+         }
+         else if (fabs(a1->val) < 0.001 * fabs(a2->val))
+         {  /* only second column can be eliminated, because first one
+               has too small constraint coefficient */
+            apq = a2, apr = a1;
+         }
+         else
+         {  /* both columns are appropriate; choose that one which is
+               shorter to minimize fill-in */
+            if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
+            {  /* first column is shorter */
+               apq = a1, apr = a2;
+            }
+            else
+            {  /* second column is shorter */
+               apq = a2, apr = a1;
+            }
+         }
+      }
+      /* now columns q and r have been chosen */
+      q = apq->col, r = apr->col;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_eq_doublet, sizeof(struct eq_doublet));
+      info->p = p->i;
+      info->apq = apq->val;
+      info->ptr = NULL;
+      /* transform each row i (i != p), where a[i,q] != 0, to eliminate
+         column q */
+      for (aiq = q->ptr; aiq != NULL; aiq = next)
+      {  next = aiq->c_next;
+         if (aiq == apq) continue; /* skip row p */
+         i = aiq->row; /* row i to be transformed */
+         /* save constraint coefficient a[i,q] */
+         if (npp->sol != GLP_MIP)
+         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = i->i;
+            lfe->val = aiq->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+         /* find coefficient a[i,r] in row i */
+         for (air = i->ptr; air != NULL; air = air->r_next)
+            if (air->col == r) break;
+         /* if a[i,r] does not exist, create a[i,r] = 0 */
+         if (air == NULL)
+            air = npp_add_aij(npp, i, r, 0.0);
+         /* compute gamma[i] = a[i,q] / a[p,q] */
+         gamma = aiq->val / apq->val;
+         /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
+         /* new a[i,q] is exact zero due to elimnation; remove it from
+            row i */
+         npp_del_aij(npp, aiq);
+         /* compute new a[i,r] */
+         air->val -= gamma * apr->val;
+         /* if new a[i,r] is close to zero due to numeric cancelation,
+            remove it from row i */
+         if (fabs(air->val) <= 1e-10)
+            npp_del_aij(npp, air);
+         /* compute new lower and upper bounds of row i */
+         if (i->lb == i->ub)
+            i->lb = i->ub = (i->lb - gamma * p->lb);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= gamma * p->lb;
+            if (i->ub != +DBL_MAX)
+               i->ub -= gamma * p->lb;
+         }
+      }
+      return q;
+}
+
+static int rcv_eq_doublet(NPP *npp, void *_info)
+{     /* recover row doubleton (equality constraint) */
+      struct eq_doublet *info = _info;
+      NPPLFE *lfe;
+      double gamma, temp;
+      /* we assume that processing row p is followed by processing
+         column q as singleton of type "implied slack variable", in
+         which case row p must always be active equality constraint */
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] != GLP_NS)
+         {  npp_error();
+            return 1;
+         }
+      }
+      if (npp->sol != GLP_MIP)
+      {  /* compute value of multiplier for row p; see (14) */
+         temp = npp->r_pi[info->p];
+         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+         {  gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
+            temp -= gamma * npp->r_pi[lfe->ref];
+         }
+         npp->r_pi[info->p] = temp;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_forcing_row - process forcing row
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+*
+*  DESCRIPTION
+*
+*  The routine npp_forcing row processes row p of general format:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*              j
+*
+*     l[j] <= x[j] <= u[j],                                          (2)
+*
+*  where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
+*  assumed that:
+*
+*  1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
+*     row upper bound (see below), eps is an absolute tolerance for row
+*     value;
+*
+*  2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
+*     row lower bound (see below).
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - cannot fix columns due to too small constraint coefficients.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Implied lower and upper bounds of row (1) are determined by bounds
+*  of corresponding columns (variables) as follows:
+*
+*     L'[p] = inf sum a[p,j] x[j] =
+*                  j
+*                                                                    (3)
+*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
+*            j in Jp             j in Jn
+*
+*     U'[p] = sup sum a[p,j] x[j] =
+*                                                                    (4)
+*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
+*            j in Jp             j in Jn
+*
+*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
+*
+*  If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
+*  all variables take their boundary values as defined by (4):
+*
+*            ( u[j], if j in Jp
+*     x[j] = <                                                       (6)
+*            ( l[j], if j in Jn
+*
+*  Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
+*  only when all variables take their boundary values as defined by (3):
+*
+*            ( l[j], if j in Jp
+*     x[j] = <                                                       (7)
+*            ( u[j], if j in Jn
+*
+*  Condition (6) or (7) allows fixing all columns (variables x[j])
+*  in row (1) on their bounds and then removing them from the problem
+*  (see the routine npp_fixed_col). Due to this row p becomes redundant,
+*  so it can be replaced by equivalent free (unbounded) row and also
+*  removed from the problem (see the routine npp_free_row).
+*
+*  1. To apply this transformation row (1) should not have coefficients
+*     whose magnitude is too small, i.e. all a[p,j] should satisfy to
+*     the following condition:
+*
+*        |a[p,j]| >= eps * max(1, |a[p,k]|),                         (8)
+*                           k
+*     where eps is a relative tolerance for constraint coefficients.
+*     Otherwise, fixing columns may be numerically unreliable and may
+*     lead to wrong solution.
+*
+*  2. The routine fixes columns and remove bounds of row p, however,
+*     it does not remove the row and columns from the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In the transformed problem row p being inactive constraint is
+*  assigned status GLP_BS (as the result of transformation of free
+*  row), and all columns in this row are assigned status GLP_NS (as the
+*  result of transformation of fixed columns).
+*
+*  Note that in the dual system of the transformed (as well as original)
+*  problem every column j in row p corresponds to the following row:
+*
+*     sum  a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j],           (9)
+*     i!=p
+*
+*  from which it follows that:
+*
+*     lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p].           (10)
+*                        i!=p
+*
+*  In the transformed problem values of all multipliers pi[i] are known
+*  (including pi[i], whose value is zero, since row p is inactive).
+*  Thus, using formula (10) it is possible to compute values of
+*  multipliers lambda[j] for all columns in row p.
+*
+*  Note also that in the original problem all columns in row p are
+*  bounded, not fixed. So status GLP_NS assigned to every such column
+*  must be changed to GLP_NL or GLP_NU depending on which bound the
+*  corresponding column has been fixed. This status change may lead to
+*  dual feasibility violation for solution of the original problem,
+*  because now column multipliers must satisfy to the following
+*  condition:
+*
+*               ( >= 0, if status of column j is GLP_NL,
+*     lambda[j] <                                                   (11)
+*               ( <= 0, if status of column j is GLP_NU.
+*
+*  If this condition holds, solution to the original problem is the
+*  same as to the transformed problem. Otherwise, we have to perform
+*  one degenerate pivoting step of the primal simplex method to obtain
+*  dual feasible (hence, optimal) solution to the original problem as
+*  follows. If, on problem transformation, row p was made active on its
+*  lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
+*  and start increasing its multiplier pi[p]. Otherwise, if row p was
+*  made active on its upper bound (case at = 1), we change its status
+*  to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
+*  follows that:
+*
+*     delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p].    (12)
+*
+*  Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
+*  specified direction causes increasing lambda[j] for every column j
+*  assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
+*  for every column j assigned status GLP_NU (delta lambda[j] < 0). It
+*  is understood that once the last lambda[q], which violates condition
+*  (11), has reached zero, multipliers lambda[j] for all columns get
+*  valid signs. Such column q can be determined as follows. Let d[j] be
+*  initial value of lambda[j] (i.e. reduced cost of column j) in the
+*  transformed problem computed with formula (10) when pi[p] = 0. Then
+*  lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
+*  lambda[j] becomes zero if:
+*
+*     delta lambda[j] = - a[p,j] pi[p] = - d[j]  ==>
+*                                                                   (13)
+*     pi[p] = d[j] / a[p,j].
+*
+*  Therefore, the last column q, for which lambda[q] becomes zero, can
+*  be determined from the following condition:
+*
+*     |d[q] / a[p,q]| = max  |pi[p]| = max  |d[j] / a[p,j]|,        (14)
+*                      j in D         j in D
+*
+*  where D is a set of columns j whose, reduced costs d[j] have invalid
+*  signs, i.e. violate condition (11). (Thus, if D is empty, solution
+*  to the original problem is the same as solution to the transformed
+*  problem, and no correction is needed as was noticed above.) In
+*  solution to the original problem column q is assigned status GLP_BS,
+*  since it replaces column of auxiliary variable of row p (becoming
+*  active) in the basis, and multiplier for row p is assigned its new
+*  value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
+*  degeneracy values of all columns having non-zero coefficients in row
+*  p remain unchanged.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of multiplier pi[p] in solution to the original problem is
+*  corrected in the same way as for basic solution. Values of all
+*  columns having non-zero coefficients in row p remain unchanged.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct forcing_col
+{     /* column fixed on its bound by forcing row */
+      int j;
+      /* column reference number */
+      char stat;
+      /* original column status:
+         GLP_NL - fixed on lower bound
+         GLP_NU - fixed on upper bound */
+      double a;
+      /* constraint coefficient a[p,j] */
+      double c;
+      /* objective coefficient c[j] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,j], i != p */
+      struct forcing_col *next;
+      /* pointer to another column fixed by forcing row */
+};
+
+struct forcing_row
+{     /* forcing row */
+      int p;
+      /* row reference number */
+      char stat;
+      /* status assigned to the row if it becomes active:
+         GLP_NS - active equality constraint
+         GLP_NL - inequality constraint with lower bound active
+         GLP_NU - inequality constraint with upper bound active */
+      struct forcing_col *ptr;
+      /* list of all columns having non-zero constraint coefficient
+         a[p,j] in the forcing row */
+};
+
+static int rcv_forcing_row(NPP *npp, void *info);
+
+int npp_forcing_row(NPP *npp, NPPROW *p, int at)
+{     /* process forcing row */
+      struct forcing_row *info;
+      struct forcing_col *col = NULL;
+      NPPCOL *j;
+      NPPAIJ *apj, *aij;
+      NPPLFE *lfe;
+      double big;
+      xassert(at == 0 || at == 1);
+      /* determine maximal magnitude of the row coefficients */
+      big = 1.0;
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         if (big < fabs(apj->val)) big = fabs(apj->val);
+      /* if there are too small coefficients in the row, transformation
+         should not be applied */
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         if (fabs(apj->val) < 1e-7 * big) return 1;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_forcing_row, sizeof(struct forcing_row));
+      info->p = p->i;
+      if (p->lb == p->ub)
+      {  /* equality constraint */
+         info->stat = GLP_NS;
+      }
+      else if (at == 0)
+      {  /* inequality constraint; case L[p] = U'[p] */
+         info->stat = GLP_NL;
+         xassert(p->lb != -DBL_MAX);
+      }
+      else /* at == 1 */
+      {  /* inequality constraint; case U[p] = L'[p] */
+         info->stat = GLP_NU;
+         xassert(p->ub != +DBL_MAX);
+      }
+      info->ptr = NULL;
+      /* scan the forcing row, fix columns at corresponding bounds, and
+         save column information (the latter is not needed for MIP) */
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+      {  /* column j has non-zero coefficient in the forcing row */
+         j = apj->col;
+         /* it must be non-fixed */
+         xassert(j->lb < j->ub);
+         /* allocate stack entry to save column information */
+         if (npp->sol != GLP_MIP)
+         {  col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
+            col->j = j->j;
+            col->stat = -1; /* will be set below */
+            col->a = apj->val;
+            col->c = j->coef;
+            col->ptr = NULL;
+            col->next = info->ptr;
+            info->ptr = col;
+         }
+         /* fix column j */
+         if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
+         {  /* at its lower bound */
+            if (npp->sol != GLP_MIP)
+               col->stat = GLP_NL;
+            xassert(j->lb != -DBL_MAX);
+            j->ub = j->lb;
+         }
+         else
+         {  /* at its upper bound */
+            if (npp->sol != GLP_MIP)
+               col->stat = GLP_NU;
+            xassert(j->ub != +DBL_MAX);
+            j->lb = j->ub;
+         }
+         /* save column coefficients a[i,j], i != p */
+         if (npp->sol != GLP_MIP)
+         {  for (aij = j->ptr; aij != NULL; aij = aij->c_next)
+            {  if (aij == apj) continue; /* skip a[p,j] */
+               lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+               lfe->ref = aij->row->i;
+               lfe->val = aij->val;
+               lfe->next = col->ptr;
+               col->ptr = lfe;
+            }
+         }
+      }
+      /* make the row free (unbounded) */
+      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+      return 0;
+}
+
+static int rcv_forcing_row(NPP *npp, void *_info)
+{     /* recover forcing row */
+      struct forcing_row *info = _info;
+      struct forcing_col *col, *piv;
+      NPPLFE *lfe;
+      double d, big, temp;
+      if (npp->sol == GLP_MIP) goto done;
+      /* initially solution to the original problem is the same as
+         to the transformed problem, where row p is inactive constraint
+         with pi[p] = 0, and all columns are non-basic */
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] != GLP_BS)
+         {  npp_error();
+            return 1;
+         }
+         for (col = info->ptr; col != NULL; col = col->next)
+         {  if (npp->c_stat[col->j] != GLP_NS)
+            {  npp_error();
+               return 1;
+            }
+            npp->c_stat[col->j] = col->stat; /* original status */
+         }
+      }
+      /* compute reduced costs d[j] for all columns with formula (10)
+         and store them in col.c instead objective coefficients */
+      for (col = info->ptr; col != NULL; col = col->next)
+      {  d = col->c;
+         for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
+            d -= lfe->val * npp->r_pi[lfe->ref];
+         col->c = d;
+      }
+      /* consider columns j, whose multipliers lambda[j] has wrong
+         sign in solution to the transformed problem (where lambda[j] =
+         d[j]), and choose column q, whose multipler lambda[q] reaches
+         zero last on changing row multiplier pi[p]; see (14) */
+      piv = NULL, big = 0.0;
+      for (col = info->ptr; col != NULL; col = col->next)
+      {  d = col->c; /* d[j] */
+         temp = fabs(d / col->a);
+         if (col->stat == GLP_NL)
+         {  /* column j has active lower bound */
+            if (d < 0.0 && big < temp)
+               piv = col, big = temp;
+         }
+         else if (col->stat == GLP_NU)
+         {  /* column j has active upper bound */
+            if (d > 0.0 && big < temp)
+               piv = col, big = temp;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      /* if column q does not exist, no correction is needed */
+      if (piv != NULL)
+      {  /* correct solution; row p becomes active constraint while
+            column q becomes basic */
+         if (npp->sol == GLP_SOL)
+         {  npp->r_stat[info->p] = info->stat;
+            npp->c_stat[piv->j] = GLP_BS;
+         }
+         /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
+         npp->r_pi[info->p] = piv->c / piv->a;
+      }
+done: return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_analyze_row - perform general row analysis
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_analyze_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_analyze_row performs analysis of row p of general
+*  format:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*              j
+*
+*     l[j] <= x[j] <= u[j],                                          (2)
+*
+*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
+*
+*  RETURNS
+*
+*  0x?0 - row lower bound does not exist or is redundant;
+*
+*  0x?1 - row lower bound can be active;
+*
+*  0x?2 - row lower bound is a forcing bound;
+*
+*  0x0? - row upper bound does not exist or is redundant;
+*
+*  0x1? - row upper bound can be active;
+*
+*  0x2? - row upper bound is a forcing bound;
+*
+*  0x33 - row bounds are inconsistent with column bounds.
+*
+*  ALGORITHM
+*
+*  Analysis of row (1) is based on analysis of its implied lower and
+*  upper bounds, which are determined by bounds of corresponding columns
+*  (variables) as follows:
+*
+*     L'[p] = inf sum a[p,j] x[j] =
+*                  j
+*                                                                    (3)
+*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
+*            j in Jp             j in Jn
+*
+*     U'[p] = sup sum a[p,j] x[j] =
+*                                                                    (4)
+*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
+*            j in Jp             j in Jn
+*
+*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
+*
+*  (Note that bounds of all columns in row p are assumed to be correct,
+*  so L'[p] <= U'[p].)
+*
+*  Analysis of row lower bound L[p] includes the following cases:
+*
+*  1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
+*     value, row lower bound L[p] and implied row upper bound U'[p] are
+*     inconsistent, ergo, the problem has no primal feasible solution;
+*
+*  2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
+*     the row is a forcing row on its lower bound (see description of
+*     the routine npp_forcing_row);
+*
+*  3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
+*     conclusion does not account other rows in the problem);
+*
+*  4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
+*     it is redundant and can be removed (replaced by -oo).
+*
+*  Analysis of row upper bound U[p] is performed in a similar way and
+*  includes the following cases:
+*
+*  1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
+*     bound L'[p] are inconsistent, ergo the problem has no primal
+*     feasible solution;
+*
+*  2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
+*     the row is a forcing row on its upper bound (see description of
+*     the routine npp_forcing_row);
+*
+*  3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
+*     conclusion does not account other rows in the problem);
+*
+*  4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
+*     it is redundant and can be removed (replaced by +oo). */
+
+int npp_analyze_row(NPP *npp, NPPROW *p)
+{     /* perform general row analysis */
+      NPPAIJ *aij;
+      int ret = 0x00;
+      double l, u, eps;
+      xassert(npp == npp);
+      /* compute implied lower bound L'[p]; see (3) */
+      l = 0.0;
+      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val > 0.0)
+         {  if (aij->col->lb == -DBL_MAX)
+            {  l = -DBL_MAX;
+               break;
+            }
+            l += aij->val * aij->col->lb;
+         }
+         else /* aij->val < 0.0 */
+         {  if (aij->col->ub == +DBL_MAX)
+            {  l = -DBL_MAX;
+               break;
+            }
+            l += aij->val * aij->col->ub;
+         }
+      }
+      /* compute implied upper bound U'[p]; see (4) */
+      u = 0.0;
+      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val > 0.0)
+         {  if (aij->col->ub == +DBL_MAX)
+            {  u = +DBL_MAX;
+               break;
+            }
+            u += aij->val * aij->col->ub;
+         }
+         else /* aij->val < 0.0 */
+         {  if (aij->col->lb == -DBL_MAX)
+            {  u = +DBL_MAX;
+               break;
+            }
+            u += aij->val * aij->col->lb;
+         }
+      }
+      /* column bounds are assumed correct, so L'[p] <= U'[p] */
+      /* check if row lower bound is consistent */
+      if (p->lb != -DBL_MAX)
+      {  eps = 1e-3 + 1e-6 * fabs(p->lb);
+         if (p->lb - eps > u)
+         {  ret = 0x33;
+            goto done;
+         }
+      }
+      /* check if row upper bound is consistent */
+      if (p->ub != +DBL_MAX)
+      {  eps = 1e-3 + 1e-6 * fabs(p->ub);
+         if (p->ub + eps < l)
+         {  ret = 0x33;
+            goto done;
+         }
+      }
+      /* check if row lower bound can be active/forcing */
+      if (p->lb != -DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(p->lb);
+         if (p->lb - eps > l)
+         {  if (p->lb + eps <= u)
+               ret |= 0x01;
+            else
+               ret |= 0x02;
+         }
+      }
+      /* check if row upper bound can be active/forcing */
+      if (p->ub != +DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(p->ub);
+         if (p->ub + eps < u)
+         {  /* check if the upper bound is forcing */
+            if (p->ub - eps >= l)
+               ret |= 0x10;
+            else
+               ret |= 0x20;
+         }
+      }
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_inactive_bound - remove row lower/upper inactive bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+*
+*  DESCRIPTION
+*
+*  The routine npp_inactive_bound removes lower (if which = 0) or upper
+*  (if which = 1) bound of row p:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],
+*
+*  which (bound) is assumed to be redundant.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If which = 0, current lower bound L[p] of row p is assigned -oo.
+*  If which = 1, current upper bound U[p] of row p is assigned +oo.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  If in solution to the transformed problem row p is inactive
+*  constraint (GLP_BS), its status is not changed in solution to the
+*  original problem. Otherwise, status of row p in solution to the
+*  original problem is defined by its type before transformation and
+*  its status in solution to the transformed problem as follows:
+*
+*     +---------------------+-------+---------------+---------------+
+*     |        Row          | Flag  | Row status in | Row status in |
+*     |        type         | which | transfmd soln | original soln |
+*     +---------------------+-------+---------------+---------------+
+*     |     sum >= L[p]     |   0   |    GLP_NF     |    GLP_NL     |
+*     |     sum <= U[p]     |   1   |    GLP_NF     |    GLP_NU     |
+*     | L[p] <= sum <= U[p] |   0   |    GLP_NU     |    GLP_NU     |
+*     | L[p] <= sum <= U[p] |   1   |    GLP_NL     |    GLP_NL     |
+*     |  sum = L[p] = U[p]  |   0   |    GLP_NU     |    GLP_NS     |
+*     |  sum = L[p] = U[p]  |   1   |    GLP_NL     |    GLP_NS     |
+*     +---------------------+-------+---------------+---------------+
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  None needed.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct inactive_bound
+{     /* row inactive bound */
+      int p;
+      /* row reference number */
+      char stat;
+      /* row status (if active constraint) */
+};
+
+static int rcv_inactive_bound(NPP *npp, void *info);
+
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
+{     /* remove row lower/upper inactive bound */
+      struct inactive_bound *info;
+      if (npp->sol == GLP_SOL)
+      {  /* create transformation stack entry */
+         info = npp_push_tse(npp,
+            rcv_inactive_bound, sizeof(struct inactive_bound));
+         info->p = p->i;
+         if (p->ub == +DBL_MAX)
+            info->stat = GLP_NL;
+         else if (p->lb == -DBL_MAX)
+            info->stat = GLP_NU;
+         else if (p->lb != p->ub)
+            info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
+         else
+            info->stat = GLP_NS;
+      }
+      /* remove row inactive bound */
+      if (which == 0)
+      {  xassert(p->lb != -DBL_MAX);
+         p->lb = -DBL_MAX;
+      }
+      else if (which == 1)
+      {  xassert(p->ub != +DBL_MAX);
+         p->ub = +DBL_MAX;
+      }
+      else
+         xassert(which != which);
+      return;
+}
+
+static int rcv_inactive_bound(NPP *npp, void *_info)
+{     /* recover row status */
+      struct inactive_bound *info = _info;
+      if (npp->sol != GLP_SOL)
+      {  npp_error();
+         return 1;
+      }
+      if (npp->r_stat[info->p] == GLP_BS)
+         npp->r_stat[info->p] = GLP_BS;
+      else
+         npp->r_stat[info->p] = info->stat;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_bounds - determine implied column bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_implied_bounds(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_bounds inspects general row (constraint) p:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*
+*     l[j] <= x[j] <= u[j],                                          (2)
+*
+*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
+*  implied bounds of columns (variables x[j]) in this row.
+*
+*  The routine stores implied column bounds l'[j] and u'[j] in column
+*  descriptors (NPPCOL); it does not change current column bounds l[j]
+*  and u[j]. (Implied column bounds can be then used to strengthen the
+*  current column bounds; see the routines npp_implied_lower and
+*  npp_implied_upper).
+*
+*  ALGORITHM
+*
+*  Current column bounds (2) define implied lower and upper bounds of
+*  row (1) as follows:
+*
+*     L'[p] = inf sum a[p,j] x[j] =
+*                  j
+*                                                                    (3)
+*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
+*            j in Jp             j in Jn
+*
+*     U'[p] = sup sum a[p,j] x[j] =
+*                                                                    (4)
+*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
+*            j in Jp             j in Jn
+*
+*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
+*
+*  (Note that bounds of all columns in row p are assumed to be correct,
+*  so L'[p] <= U'[p].)
+*
+*  If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
+*  row (1) can be active, in which case such row defines implied bounds
+*  of its variables.
+*
+*  Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
+*  Consider a case when row lower bound can be active (L[p] > L'[p]):
+*
+*     sum a[p,j] x[j] >= L[p]  ==>
+*      j
+*
+*     sum a[p,j] x[j] + a[p,k] x[k] >= L[p]  ==>
+*     j!=k
+*                                                                    (6)
+*     a[p,k] x[k] >= L[p] - sum a[p,j] x[j]  ==>
+*                           j!=k
+*
+*     a[p,k] x[k] >= L[p,k],
+*
+*  where
+*
+*     L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
+*                         j!=k
+*
+*            = L[p] - sup sum a[p,j] x[j] =                          (7)
+*                         j!=k
+*
+*            = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
+*                    j in Jp\{k}       j in Jn\{k}
+*
+*  Thus:
+*
+*     x[k] >= l'[k] = L[p,k] / a[p,k],  if a[p,k] > 0,               (8)
+*
+*     x[k] <= u'[k] = L[p,k] / a[p,k],  if a[p,k] < 0.               (9)
+*
+*  where l'[k] and u'[k] are implied lower and upper bounds of variable
+*  x[k], resp.
+*
+*  Now consider a similar case when row upper bound can be active
+*  (U[p] < U'[p]):
+*
+*     sum a[p,j] x[j] <= U[p]  ==>
+*      j
+*
+*     sum a[p,j] x[j] + a[p,k] x[k] <= U[p]  ==>
+*     j!=k
+*                                                                   (10)
+*     a[p,k] x[k] <= U[p] - sum a[p,j] x[j]  ==>
+*                           j!=k
+*
+*     a[p,k] x[k] <= U[p,k],
+*
+*  where:
+*
+*     U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
+*                         j!=k
+*
+*            = U[p] - inf sum a[p,j] x[j] =                         (11)
+*                         j!=k
+*
+*            = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
+*                    j in Jp\{k}       j in Jn\{k}
+*
+*  Thus:
+*
+*     x[k] <= u'[k] = U[p,k] / a[p,k],  if a[p,k] > 0,              (12)
+*
+*     x[k] >= l'[k] = U[p,k] / a[p,k],  if a[p,k] < 0.              (13)
+*
+*  Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
+*  must not be too small in magnitude relatively to other non-zero
+*  coefficients in row (1), i.e. the following condition must hold:
+*
+*     |a[p,k]| >= eps * max(1, |a[p,j]|),                           (14)
+*                        j
+*
+*  where eps is a relative tolerance for constraint coefficients.
+*  Otherwise the implied column bounds can be numerical inreliable. For
+*  example, using formula (8) for the following inequality constraint:
+*
+*     1e-12 x1 - x2 - x3 >= 0,
+*
+*  where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
+*  conclusion that x1 >= 0.
+*
+*  Using formulae (8), (9), (12), and (13) to compute implied bounds
+*  for one variable requires |J| operations, where J = {j: a[p,j] != 0},
+*  because this needs computing L[p,k] and U[p,k]. Thus, computing
+*  implied bounds for all variables in row (1) would require |J|^2
+*  operations, that is not a good technique. However, the total number
+*  of operations can be reduced to |J| as follows.
+*
+*  Let a[p,k] > 0. Then from (7) and (11) we have:
+*
+*     L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
+*
+*            = L[p] - U'[p] + a[p,k] u[k],
+*
+*     U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
+*
+*            = U[p] - L'[p] + a[p,k] l[k],
+*
+*  where L'[p] and U'[p] are implied row lower and upper bounds defined
+*  by formulae (3) and (4). Substituting these expressions into (8) and
+*  (12) gives:
+*
+*     l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k],     (15)
+*
+*     u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k].     (16)
+*
+*  Similarly, if a[p,k] < 0, according to (7) and (11) we have:
+*
+*     L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
+*
+*            = L[p] - U'[p] + a[p,k] l[k],
+*
+*     U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
+*
+*            = U[p] - L'[p] + a[p,k] u[k],
+*
+*  and substituting these expressions into (8) and (12) gives:
+*
+*     l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k],     (17)
+*
+*     u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k].     (18)
+*
+*  Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
+*  exist. However, if for some variable x[j] it happens that l[j] = -oo
+*  and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
+*  a[p,j] < 0) are undefined. Consider, therefore, the most general
+*  situation, when some column bounds (2) may not exist.
+*
+*  Let:
+*
+*     J' = {j : (a[p,j] > 0 and l[j] = -oo) or
+*                                                                   (19)
+*               (a[p,j] < 0 and u[j] = +oo)}.
+*
+*  Then (assuming that row upper bound U[p] can be active) the following
+*  three cases are possible:
+*
+*  1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
+*     in row (1) we can use formulae (16) and (17);
+*
+*  2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
+*     so for variable x[k] we can use formulae (12) and (13). Note that
+*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
+*     or u'[j] = +oo (if a[p,j] > 0);
+*
+*  3) |J'| > 1. In this case for all variables x[j] in row [1] we have
+*     l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
+*
+*  Similarly, let:
+*
+*     J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
+*                                                                   (20)
+*                (a[p,j] < 0 and l[j] = -oo)}.
+*
+*  Then (assuming that row lower bound L[p] can be active) the following
+*  three cases are possible:
+*
+*  1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
+*     in row (1) we can use formulae (15) and (18);
+*
+*  2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
+*     so for variable x[k] we can use formulae (8) and (9). Note that
+*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
+*     or u'[j] = +oo (if a[p,j] < 0);
+*
+*  3) |J''| > 1. In this case for all variables x[j] in row (1) we have
+*     l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
+
+void npp_implied_bounds(NPP *npp, NPPROW *p)
+{     NPPAIJ *apj, *apk;
+      double big, eps, temp;
+      xassert(npp == npp);
+      /* initialize implied bounds for all variables and determine
+         maximal magnitude of row coefficients a[p,j] */
+      big = 1.0;
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+      {  apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
+         if (big < fabs(apj->val)) big = fabs(apj->val);
+      }
+      eps = 1e-6 * big;
+      /* process row lower bound (assuming that it can be active) */
+      if (p->lb != -DBL_MAX)
+      {  apk = NULL;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
+                apj->val < 0.0 && apj->col->lb == -DBL_MAX)
+            {  if (apk == NULL)
+                  apk = apj;
+               else
+                  goto skip1;
+            }
+         }
+         /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
+         temp = p->lb;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj == apk)
+               /* skip a[p,k] */;
+            else if (apj->val > 0.0)
+               temp -= apj->val * apj->col->ub;
+            else /* apj->val < 0.0 */
+               temp -= apj->val * apj->col->lb;
+         }
+         /* compute column implied bounds */
+         if (apk == NULL)
+         {  /* temp = L[p] - U'[p] */
+            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+            {  if (apj->val >= +eps)
+               {  /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
+                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
+               }
+               else if (apj->val <= -eps)
+               {  /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
+                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
+               }
+            }
+         }
+         else
+         {  /* temp = L[p,k] */
+            if (apk->val >= +eps)
+            {  /* l'[k] := L[p,k] / a[p,k] */
+               apk->col->ll.ll = temp / apk->val;
+            }
+            else if (apk->val <= -eps)
+            {  /* u'[k] := L[p,k] / a[p,k] */
+               apk->col->uu.uu = temp / apk->val;
+            }
+         }
+skip1:   ;
+      }
+      /* process row upper bound (assuming that it can be active) */
+      if (p->ub != +DBL_MAX)
+      {  apk = NULL;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
+                apj->val < 0.0 && apj->col->ub == +DBL_MAX)
+            {  if (apk == NULL)
+                  apk = apj;
+               else
+                  goto skip2;
+            }
+         }
+         /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
+         temp = p->ub;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj == apk)
+               /* skip a[p,k] */;
+            else if (apj->val > 0.0)
+               temp -= apj->val * apj->col->lb;
+            else /* apj->val < 0.0 */
+               temp -= apj->val * apj->col->ub;
+         }
+         /* compute column implied bounds */
+         if (apk == NULL)
+         {  /* temp = U[p] - L'[p] */
+            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+            {  if (apj->val >= +eps)
+               {  /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
+                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
+               }
+               else if (apj->val <= -eps)
+               {  /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
+                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
+               }
+            }
+         }
+         else
+         {  /* temp = U[p,k] */
+            if (apk->val >= +eps)
+            {  /* u'[k] := U[p,k] / a[p,k] */
+               apk->col->uu.uu = temp / apk->val;
+            }
+            else if (apk->val <= -eps)
+            {  /* l'[k] := U[p,k] / a[p,k] */
+               apk->col->ll.ll = temp / apk->val;
+            }
+         }
+skip2:   ;
+      }
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpnpp04.c b/optional/glpk/glpnpp04.c
new file mode 100644
index 0000000..ca9125d
--- /dev/null
+++ b/optional/glpk/glpnpp04.c
@@ -0,0 +1,1419 @@
+/* glpnpp04.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_binarize_prob - binarize MIP problem
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_binarize_prob(NPP *npp);
+*
+*  DESCRIPTION
+*
+*  The routine npp_binarize_prob replaces in the original MIP problem
+*  every integer variable:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], by an equivalent sum of binary variables.
+*
+*  RETURNS
+*
+*  The routine returns the number of integer variables for which the
+*  transformation failed, because u[q] - l[q] > d_max.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If variable x[q] has non-zero lower bound, it is first processed
+*  with the routine npp_lbnd_col. Thus, we can assume that:
+*
+*     0 <= x[q] <= u[q].                                             (2)
+*
+*  If u[q] = 1, variable x[q] is already binary, so further processing
+*  is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
+*  smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
+*  Then variable x[q] can be replaced by the following sum:
+*
+*            n-1
+*     x[q] = sum 2^k x[k],                                           (3)
+*            k=0
+*
+*  where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
+*  following additional inequality constraint must be also included in
+*  the transformed problem:
+*
+*     n-1
+*     sum 2^k x[k] <= u[q].                                          (4)
+*     k=0
+*
+*  Note: Assuming that in the transformed problem x[q] becomes binary
+*  variable x[0], this transformation causes new n-1 binary variables
+*  to appear.
+*
+*  Substituting x[q] from (3) to the objective row gives:
+*
+*     z = sum c[j] x[j] + c[0] =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c[0] =
+*         j!=q
+*                              n-1
+*       = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
+*         j!=q                 k=0
+*                         n-1
+*       = sum c[j] x[j] + sum c[k] x[k] + c[0],
+*         j!=q            k=0
+*
+*  where:
+*
+*     c[k] = 2^k c[q],  k = 0, ..., n-1.                             (5)
+*
+*  And substituting x[q] from (3) to i-th constraint row i gives:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*                                      n-1
+*     L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i]  ==>
+*             j!=q                     k=0
+*                               n-1
+*     L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
+*             j!=q              k=0
+*
+*  where:
+*
+*     a[i,k] = 2^k a[i,q],  k = 0, ..., n-1.                         (6)
+*
+*  RECOVERING SOLUTION
+*
+*  Value of variable x[q] is computed with formula (3). */
+
+struct binarize
+{     int q;
+      /* column reference number for x[q] = x[0] */
+      int j;
+      /* column reference number for x[1]; x[2] has reference number
+         j+1, x[3] - j+2, etc. */
+      int n;
+      /* total number of binary variables, n >= 2 */
+};
+
+static int rcv_binarize_prob(NPP *npp, void *info);
+
+int npp_binarize_prob(NPP *npp)
+{     /* binarize MIP problem */
+      struct binarize *info;
+      NPPROW *row;
+      NPPCOL *col, *bin;
+      NPPAIJ *aij;
+      int u, n, k, temp, nfails, nvars, nbins, nrows;
+      /* new variables will be added to the end of the column list, so
+         we go from the end to beginning of the column list */
+      nfails = nvars = nbins = nrows = 0;
+      for (col = npp->c_tail; col != NULL; col = col->prev)
+      {  /* skip continuous variable */
+         if (!col->is_int) continue;
+         /* skip fixed variable */
+         if (col->lb == col->ub) continue;
+         /* skip binary variable */
+         if (col->lb == 0.0 && col->ub == 1.0) continue;
+         /* check if the transformation is applicable */
+         if (col->lb < -1e6 || col->ub > +1e6 ||
+             col->ub - col->lb > 4095.0)
+         {  /* unfortunately, not */
+            nfails++;
+            continue;
+         }
+         /* process integer non-binary variable x[q] */
+         nvars++;
+         /* make x[q] non-negative, if its lower bound is non-zero */
+         if (col->lb != 0.0)
+            npp_lbnd_col(npp, col);
+         /* now 0 <= x[q] <= u[q] */
+         xassert(col->lb == 0.0);
+         u = (int)col->ub;
+         xassert(col->ub == (double)u);
+         /* if x[q] is binary, further processing is not needed */
+         if (u == 1) continue;
+         /* determine smallest n such that u <= 2^n - 1 (thus, n is the
+            number of binary variables needed) */
+         n = 2, temp = 4;
+         while (u >= temp)
+            n++, temp += temp;
+         nbins += n;
+         /* create transformation stack entry */
+         info = npp_push_tse(npp,
+            rcv_binarize_prob, sizeof(struct binarize));
+         info->q = col->j;
+         info->j = 0; /* will be set below */
+         info->n = n;
+         /* if u < 2^n - 1, we need one additional row for (4) */
+         if (u < temp - 1)
+         {  row = npp_add_row(npp), nrows++;
+            row->lb = -DBL_MAX, row->ub = u;
+         }
+         else
+            row = NULL;
+         /* in the transformed problem variable x[q] becomes binary
+            variable x[0], so its objective and constraint coefficients
+            are not changed */
+         col->ub = 1.0;
+         /* include x[0] into constraint (4) */
+         if (row != NULL)
+            npp_add_aij(npp, row, col, 1.0);
+         /* add other binary variables x[1], ..., x[n-1] */
+         for (k = 1, temp = 2; k < n; k++, temp += temp)
+         {  /* add new binary variable x[k] */
+            bin = npp_add_col(npp);
+            bin->is_int = 1;
+            bin->lb = 0.0, bin->ub = 1.0;
+            bin->coef = (double)temp * col->coef;
+            /* store column reference number for x[1] */
+            if (info->j == 0)
+               info->j = bin->j;
+            else
+               xassert(info->j + (k-1) == bin->j);
+            /* duplicate constraint coefficients for x[k]; this also
+               automatically includes x[k] into constraint (4) */
+            for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+               npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
+         }
+      }
+      if (nvars > 0)
+         xprintf("%d integer variable(s) were replaced by %d binary one"
+            "s\n", nvars, nbins);
+      if (nrows > 0)
+         xprintf("%d row(s) were added due to binarization\n", nrows);
+      if (nfails > 0)
+         xprintf("Binarization failed for %d integer variable(s)\n",
+            nfails);
+      return nfails;
+}
+
+static int rcv_binarize_prob(NPP *npp, void *_info)
+{     /* recovery binarized variable */
+      struct binarize *info = _info;
+      int k, temp;
+      double sum;
+      /* compute value of x[q]; see formula (3) */
+      sum = npp->c_value[info->q];
+      for (k = 1, temp = 2; k < info->n; k++, temp += temp)
+         sum += (double)temp * npp->c_value[info->j + (k-1)];
+      npp->c_value[info->q] = sum;
+      return 0;
+}
+
+/**********************************************************************/
+
+struct elem
+{     /* linear form element a[j] x[j] */
+      double aj;
+      /* non-zero coefficient value */
+      NPPCOL *xj;
+      /* pointer to variable (column) */
+      struct elem *next;
+      /* pointer to another term */
+};
+
+static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
+{     /* copy linear form */
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      ptr = NULL;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  e = dmp_get_atom(npp->pool, sizeof(struct elem));
+         e->aj = s * aij->val;
+         e->xj = aij->col;
+         e->next = ptr;
+         ptr = e;
+      }
+      return ptr;
+}
+
+static void drop_form(NPP *npp, struct elem *ptr)
+{     /* drop linear form */
+      struct elem *e;
+      while (ptr != NULL)
+      {  e = ptr;
+         ptr = e->next;
+         dmp_free_atom(npp->pool, e, sizeof(struct elem));
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_is_packing - test if constraint is packing inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_is_packing(NPP *npp, NPPROW *row);
+*
+*  RETURNS
+*
+*  If the specified row (constraint) is packing inequality (see below),
+*  the routine npp_is_packing returns non-zero. Otherwise, it returns
+*  zero.
+*
+*  PACKING INEQUALITIES
+*
+*  In canonical format the packing inequality is the following:
+*
+*     sum  x[j] <= 1,                                                (1)
+*    j in J
+*
+*  where all variables x[j] are binary. This inequality expresses the
+*  condition that in any integer feasible solution at most one variable
+*  from set J can take non-zero (unity) value while other variables
+*  must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
+*  if J is empty or |J| = 1, the inequality (1) is redundant.
+*
+*  In general case the packing inequality may include original variables
+*  x[j] as well as their complements x~[j]:
+*
+*     sum   x[j] + sum   x~[j] <= 1,                                 (2)
+*    j in Jp      j in Jn
+*
+*  where Jp and Jn are not intersected. Therefore, using substitution
+*  x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+*     sum   x[j] - sum   x[j] <= 1 - |Jn|.                           (3)
+*    j in Jp      j in Jn */
+
+int npp_is_packing(NPP *npp, NPPROW *row)
+{     /* test if constraint is packing inequality */
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int b;
+      xassert(npp == npp);
+      if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
+         return 0;
+      b = 1;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0;
+         if (aij->val == +1.0)
+            ;
+         else if (aij->val == -1.0)
+            b--;
+         else
+            return 0;
+      }
+      if (row->ub != (double)b) return 0;
+      return 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_hidden_packing - identify hidden packing inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_hidden_packing(NPP *npp, NPPROW *row);
+*
+*  DESCRIPTION
+*
+*  The routine npp_hidden_packing processes specified inequality
+*  constraint, which includes only binary variables, and the number of
+*  the variables is not less than two. If the original inequality is
+*  equivalent to a packing inequality, the routine replaces it by this
+*  equivalent inequality. If the original constraint is double-sided
+*  inequality, it is replaced by a pair of single-sided inequalities,
+*  if necessary.
+*
+*  RETURNS
+*
+*  If the original inequality constraint was replaced by equivalent
+*  packing inequality, the routine npp_hidden_packing returns non-zero.
+*  Otherwise, it returns zero.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Consider an inequality constraint:
+*
+*     sum  a[j] x[j] <= b,                                           (1)
+*    j in J
+*
+*  where all variables x[j] are binary, and |J| >= 2. (In case of '>='
+*  inequality it can be transformed to '<=' format by multiplying both
+*  its sides by -1.)
+*
+*  Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+*  x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+*     sum   a[j] x[j] <= b  ==>
+*    j in J
+*
+*     sum   a[j] x[j] + sum   a[j] x[j] <= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum   a[j] x[j] + sum   a[j] (1 - x~[j]) <= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum   a[j] x[j] - sum   a[j] x~[j] <= b - sum   a[j].
+*    j in Jp           j in Jn                 j in Jn
+*
+*  Thus, meaning the transformation above, we can assume that in
+*  inequality (1) all coefficients a[j] are positive. Moreover, we can
+*  assume that a[j] <= b. In fact, let a[j] > b; then the following
+*  three cases are possible:
+*
+*  1) b < 0. In this case inequality (1) is infeasible, so the problem
+*     has no feasible solution (see the routine npp_analyze_row);
+*
+*  2) b = 0. In this case inequality (1) is a forcing inequality on its
+*     upper bound (see the routine npp_forcing row), from which it
+*     follows that all variables x[j] should be fixed at zero;
+*
+*  3) b > 0. In this case inequality (1) defines an implied zero upper
+*     bound for variable x[j] (see the routine npp_implied_bounds), from
+*     which it follows that x[j] should be fixed at zero.
+*
+*  It is assumed that all three cases listed above have been recognized
+*  by the routine npp_process_prob, which performs basic MIP processing
+*  prior to a call the routine npp_hidden_packing. So, if one of these
+*  cases occurs, we should just skip processing such constraint.
+*
+*  Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
+*  equivalent to packing inquality only if:
+*
+*     a[j] + a[k] > b + eps                                          (2)
+*
+*  for all j, k in J, j != k, where eps is an absolute tolerance for
+*  row (linear form) value. Checking the condition (2) for all j and k,
+*  j != k, requires time O(|J|^2). However, this time can be reduced to
+*  O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
+*  to check the condition (2) only once.
+*
+*  Once the original inequality (1) is replaced by equivalent packing
+*  inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+*  all j in Jn (see above).
+*
+*  RECOVERING SOLUTION
+*
+*  None needed. */
+
+static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
+{     /* process inequality constraint: sum a[j] x[j] <= b;
+         0 - specified row is NOT hidden packing inequality;
+         1 - specified row is packing inequality;
+         2 - specified row is hidden packing inequality. */
+      struct elem *e, *ej, *ek;
+      int neg;
+      double b = *_b, eps;
+      xassert(npp == npp);
+      /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+      for (e = ptr; e != NULL; e = e->next)
+      {  xassert(e->aj != 0.0);
+         xassert(e->xj->is_int);
+         xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+      }
+      /* check if the specified inequality constraint already has the
+         form of packing inequality */
+      neg = 0; /* neg is |Jn| */
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj == +1.0)
+            ;
+         else if (e->aj == -1.0)
+            neg++;
+         else
+            break;
+      }
+      if (e == NULL)
+      {  /* all coefficients a[j] are +1 or -1; check rhs b */
+         if (b == (double)(1 - neg))
+         {  /* it is packing inequality; no processing is needed */
+            return 1;
+         }
+      }
+      /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+         positive; the result is a~[j] = |a[j]| and new rhs b */
+      for (e = ptr; e != NULL; e = e->next)
+         if (e->aj < 0) b -= e->aj;
+      /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+      /* if a[j] > b, skip processing--this case must not appear */
+      for (e = ptr; e != NULL; e = e->next)
+         if (fabs(e->aj) > b) return 0;
+      /* now 0 < a[j] <= b for all j in J */
+      /* find two minimal coefficients a[j] and a[k], j != k */
+      ej = NULL;
+      for (e = ptr; e != NULL; e = e->next)
+         if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
+      xassert(ej != NULL);
+      ek = NULL;
+      for (e = ptr; e != NULL; e = e->next)
+         if (e != ej)
+            if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
+      xassert(ek != NULL);
+      /* the specified constraint is equivalent to packing inequality
+         iff a[j] + a[k] > b + eps */
+      eps = 1e-3 + 1e-6 * fabs(b);
+      if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
+      /* perform back substitution x~[j] = 1 - x[j] and construct the
+         final equivalent packing inequality in generalized format */
+      b = 1.0;
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj > 0.0)
+            e->aj = +1.0;
+         else /* e->aj < 0.0 */
+            e->aj = -1.0, b -= 1.0;
+      }
+      *_b = b;
+      return 2;
+}
+
+int npp_hidden_packing(NPP *npp, NPPROW *row)
+{     /* identify hidden packing inequality */
+      NPPROW *copy;
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      int kase, ret, count = 0;
+      double b;
+      /* the row must be inequality constraint */
+      xassert(row->lb < row->ub);
+      for (kase = 0; kase <= 1; kase++)
+      {  if (kase == 0)
+         {  /* process row upper bound */
+            if (row->ub == +DBL_MAX) continue;
+            ptr = copy_form(npp, row, +1.0);
+            b = + row->ub;
+         }
+         else
+         {  /* process row lower bound */
+            if (row->lb == -DBL_MAX) continue;
+            ptr = copy_form(npp, row, -1.0);
+            b = - row->lb;
+         }
+         /* now the inequality has the form "sum a[j] x[j] <= b" */
+         ret = hidden_packing(npp, ptr, &b);
+         xassert(0 <= ret && ret <= 2);
+         if (kase == 1 && ret == 1 || ret == 2)
+         {  /* the original inequality has been identified as hidden
+               packing inequality */
+            count++;
+#ifdef GLP_DEBUG
+            xprintf("Original constraint:\n");
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               xprintf(" %+g x%d", aij->val, aij->col->j);
+            if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+            if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+            xprintf("\n");
+            xprintf("Equivalent packing inequality:\n");
+            for (e = ptr; e != NULL; e = e->next)
+               xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+            xprintf(", <= %g\n", b);
+#endif
+            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+            {  /* the original row is single-sided inequality; no copy
+                  is needed */
+               copy = NULL;
+            }
+            else
+            {  /* the original row is double-sided inequality; we need
+                  to create its copy for other bound before replacing it
+                  with the equivalent inequality */
+               copy = npp_add_row(npp);
+               if (kase == 0)
+               {  /* the copy is for lower bound */
+                  copy->lb = row->lb, copy->ub = +DBL_MAX;
+               }
+               else
+               {  /* the copy is for upper bound */
+                  copy->lb = -DBL_MAX, copy->ub = row->ub;
+               }
+               /* copy original row coefficients */
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  npp_add_aij(npp, copy, aij->col, aij->val);
+            }
+            /* replace the original inequality by equivalent one */
+            npp_erase_row(npp, row);
+            row->lb = -DBL_MAX, row->ub = b;
+            for (e = ptr; e != NULL; e = e->next)
+               npp_add_aij(npp, row, e->xj, e->aj);
+            /* continue processing lower bound for the copy */
+            if (copy != NULL) row = copy;
+         }
+         drop_form(npp, ptr);
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_packing - identify implied packing inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+*     NPPCOL *var[], char set[]);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_packing processes specified row (constraint)
+*  of general format:
+*
+*     L <= sum a[j] x[j] <= U.                                       (1)
+*           j
+*
+*  If which = 0, only lower bound L, which must exist, is considered,
+*  while upper bound U is ignored. Similarly, if which = 1, only upper
+*  bound U, which must exist, is considered, while lower bound L is
+*  ignored. Thus, if the specified row is a double-sided inequality or
+*  equality constraint, this routine should be called twice for both
+*  lower and upper bounds.
+*
+*  The routine npp_implied_packing attempts to find a non-trivial (i.e.
+*  having not less than two binary variables) packing inequality:
+*
+*     sum   x[j] - sum   x[j] <= 1 - |Jn|,                           (2)
+*    j in Jp      j in Jn
+*
+*  which is relaxation of the constraint (1) in the sense that any
+*  solution satisfying to that constraint also satisfies to the packing
+*  inequality (2). If such relaxation exists, the routine stores
+*  pointers to descriptors of corresponding binary variables and their
+*  flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
+*  set[2], ..., set[len], where set[j] = 0 means that j in Jp and
+*  set[j] = 1 means that j in Jn.
+*
+*  RETURNS
+*
+*  The routine npp_implied_packing returns len, which is the total
+*  number of binary variables in the packing inequality found, len >= 2.
+*  However, if the relaxation does not exist, the routine returns zero.
+*
+*  ALGORITHM
+*
+*  If which = 0, the constraint coefficients (1) are multiplied by -1
+*  and b is assigned -L; if which = 1, the constraint coefficients (1)
+*  are not changed and b is assigned +U. In both cases the specified
+*  constraint gets the following format:
+*
+*     sum a[j] x[j] <= b.                                            (3)
+*      j
+*
+*  (Note that (3) is a relaxation of (1), because one of bounds L or U
+*  is ignored.)
+*
+*  Let J be set of binary variables, Kp be set of non-binary (integer
+*  or continuous) variables with a[j] > 0, and Kn be set of non-binary
+*  variables with a[j] < 0. Then the inequality (3) can be written as
+*  follows:
+*
+*     sum  a[j] x[j] <= b - sum   a[j] x[j] - sum   a[j] x[j].       (4)
+*    j in J                j in Kp           j in Kn
+*
+*  To get rid of non-binary variables we can replace the inequality (4)
+*  by the following relaxed inequality:
+*
+*     sum  a[j] x[j] <= b~,                                          (5)
+*    j in J
+*
+*  where:
+*
+*     b~ = sup(b - sum   a[j] x[j] - sum   a[j] x[j]) =
+*                 j in Kp           j in Kn
+*
+*        = b - inf sum   a[j] x[j] - inf sum   a[j] x[j] =           (6)
+*                 j in Kp               j in Kn
+*
+*        = b - sum   a[j] l[j] - sum   a[j] u[j].
+*             j in Kp           j in Kn
+*
+*  Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
+*  (if j in Kn) of some non-binary variable x[j] does not exist, then
+*  formally b = +oo, in which case further analysis is not performed.
+*
+*  Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
+*  the inequality coefficients in (5) positive, we replace all x[j] in
+*  Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
+*  j in Bn, that gives:
+*
+*     sum   a[j] x[j] - sum   a[j] x~[j] <= b~ - sum   a[j].         (7)
+*    j in Bp           j in Bn                  j in Bn
+*
+*  This inequality is a relaxation of the original constraint (1), and
+*  it is a binary knapsack inequality. Writing it in the standard format
+*  we have:
+*
+*     sum  alfa[j] z[j] <= beta,                                     (8)
+*    j in J
+*
+*  where:
+*               ( + a[j],   if j in Bp,
+*     alfa[j] = <                                                    (9)
+*               ( - a[j],   if j in Bn,
+*
+*               ( x[j],     if j in Bp,
+*        z[j] = <                                                   (10)
+*               ( 1 - x[j], if j in Bn,
+*
+*        beta = b~ - sum   a[j].                                    (11)
+*                   j in Bn
+*
+*  In the inequality (8) all coefficients are positive, therefore, the
+*  packing relaxation to be found for this inequality is the following:
+*
+*     sum  z[j] <= 1.                                               (12)
+*    j in P
+*
+*  It is obvious that set P within J, which we would like to find, must
+*  satisfy to the following condition:
+*
+*     alfa[j] + alfa[k] > beta + eps  for all j, k in P, j != k,    (13)
+*
+*  where eps is an absolute tolerance for value of the linear form.
+*  Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
+*  Moreover, if in the equality (8) there exist coefficients alfa[k],
+*  for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
+*  satisfies to the condition (13) for all j in P, *one* corresponding
+*  variable z[k] (having, for example, maximal coefficient alfa[k]) can
+*  be included in set P, that allows increasing the number of binary
+*  variables in (12) by one.
+*
+*  Once the set P has been built, for the inequality (12) we need to
+*  perform back substitution according to (10) in order to express it
+*  through the original binary variables. As the result of such back
+*  substitution the relaxed packing inequality get its final format (2),
+*  where Jp = J intersect Bp, and Jn = J intersect Bn. */
+
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+      NPPCOL *var[], char set[])
+{     struct elem *ptr, *e, *i, *k;
+      int len = 0;
+      double b, eps;
+      /* build inequality (3) */
+      if (which == 0)
+      {  ptr = copy_form(npp, row, -1.0);
+         xassert(row->lb != -DBL_MAX);
+         b = - row->lb;
+      }
+      else if (which == 1)
+      {  ptr = copy_form(npp, row, +1.0);
+         xassert(row->ub != +DBL_MAX);
+         b = + row->ub;
+      }
+      /* remove non-binary variables to build relaxed inequality (5);
+         compute its right-hand side b~ with formula (6) */
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+         {  /* x[j] is non-binary variable */
+            if (e->aj > 0.0)
+            {  if (e->xj->lb == -DBL_MAX) goto done;
+               b -= e->aj * e->xj->lb;
+            }
+            else /* e->aj < 0.0 */
+            {  if (e->xj->ub == +DBL_MAX) goto done;
+               b -= e->aj * e->xj->ub;
+            }
+            /* a[j] = 0 means that variable x[j] is removed */
+            e->aj = 0.0;
+         }
+      }
+      /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
+         compute its right-hand side beta with formula (11) */
+      for (e = ptr; e != NULL; e = e->next)
+         if (e->aj < 0.0) b -= e->aj;
+      /* if beta is close to zero, the knapsack inequality is either
+         infeasible or forcing inequality; this must never happen, so
+         we skip further analysis */
+      if (b < 1e-3) goto done;
+      /* build set P as well as sets Jp and Jn, and determine x[k] as
+         explained above in comments to the routine */
+      eps = 1e-3 + 1e-6 * b;
+      i = k = NULL;
+      for (e = ptr; e != NULL; e = e->next)
+      {  /* note that alfa[j] = |a[j]| */
+         if (fabs(e->aj) > 0.5 * (b + eps))
+         {  /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
+               set Jp or Jn */
+            var[++len] = e->xj;
+            set[len] = (char)(e->aj > 0.0 ? 0 : 1);
+            /* alfa[i] = min alfa[j] over all j included in set P */
+            if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
+         }
+         else if (fabs(e->aj) >= 1e-3)
+         {  /* alfa[k] = max alfa[j] over all j not included in set P;
+               we skip coefficient a[j] if it is close to zero to avoid
+               numerically unreliable results */
+            if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
+         }
+      }
+      /* if alfa[k] satisfies to condition (13) for all j in P, include
+         x[k] in P */
+      if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
+      {  var[++len] = k->xj;
+         set[len] = (char)(k->aj > 0.0 ? 0 : 1);
+      }
+      /* trivial packing inequality being redundant must never appear,
+         so we just ignore it */
+      if (len < 2) len = 0;
+done: drop_form(npp, ptr);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_is_covering - test if constraint is covering inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_is_covering(NPP *npp, NPPROW *row);
+*
+*  RETURNS
+*
+*  If the specified row (constraint) is covering inequality (see below),
+*  the routine npp_is_covering returns non-zero. Otherwise, it returns
+*  zero.
+*
+*  COVERING INEQUALITIES
+*
+*  In canonical format the covering inequality is the following:
+*
+*     sum  x[j] >= 1,                                                (1)
+*    j in J
+*
+*  where all variables x[j] are binary. This inequality expresses the
+*  condition that in any integer feasible solution variables in set J
+*  cannot be all equal to zero at the same time, i.e. at least one
+*  variable must take non-zero (unity) value. W.l.o.g. it is assumed
+*  that |J| >= 2, because if J is empty, the inequality (1) is
+*  infeasible, and if |J| = 1, the inequality (1) is a forcing row.
+*
+*  In general case the covering inequality may include original
+*  variables x[j] as well as their complements x~[j]:
+*
+*     sum   x[j] + sum   x~[j] >= 1,                                 (2)
+*    j in Jp      j in Jn
+*
+*  where Jp and Jn are not intersected. Therefore, using substitution
+*  x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+*     sum   x[j] - sum   x[j] >= 1 - |Jn|.                           (3)
+*    j in Jp      j in Jn
+*
+*  (May note that the inequality (3) cuts off infeasible solutions,
+*  where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
+*
+*  NOTE: If |J| = 2, the inequality (3) is equivalent to packing
+*        inequality (see the routine npp_is_packing). */
+
+int npp_is_covering(NPP *npp, NPPROW *row)
+{     /* test if constraint is covering inequality */
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int b;
+      xassert(npp == npp);
+      if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
+         return 0;
+      b = 1;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0;
+         if (aij->val == +1.0)
+            ;
+         else if (aij->val == -1.0)
+            b--;
+         else
+            return 0;
+      }
+      if (row->lb != (double)b) return 0;
+      return 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_hidden_covering - identify hidden covering inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_hidden_covering(NPP *npp, NPPROW *row);
+*
+*  DESCRIPTION
+*
+*  The routine npp_hidden_covering processes specified inequality
+*  constraint, which includes only binary variables, and the number of
+*  the variables is not less than three. If the original inequality is
+*  equivalent to a covering inequality (see below), the routine
+*  replaces it by the equivalent inequality. If the original constraint
+*  is double-sided inequality, it is replaced by a pair of single-sided
+*  inequalities, if necessary.
+*
+*  RETURNS
+*
+*  If the original inequality constraint was replaced by equivalent
+*  covering inequality, the routine npp_hidden_covering returns
+*  non-zero. Otherwise, it returns zero.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Consider an inequality constraint:
+*
+*     sum  a[j] x[j] >= b,                                           (1)
+*    j in J
+*
+*  where all variables x[j] are binary, and |J| >= 3. (In case of '<='
+*  inequality it can be transformed to '>=' format by multiplying both
+*  its sides by -1.)
+*
+*  Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+*  x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+*     sum   a[j] x[j] >= b  ==>
+*    j in J
+*
+*     sum   a[j] x[j] + sum   a[j] x[j] >= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum   a[j] x[j] + sum   a[j] (1 - x~[j]) >= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum  m   a[j] x[j] - sum   a[j] x~[j] >= b - sum   a[j].
+*    j in Jp              j in Jn                 j in Jn
+*
+*  Thus, meaning the transformation above, we can assume that in
+*  inequality (1) all coefficients a[j] are positive. Moreover, we can
+*  assume that b > 0, because otherwise the inequality (1) would be
+*  redundant (see the routine npp_analyze_row). It is then obvious that
+*  constraint (1) is equivalent to covering inequality only if:
+*
+*     a[j] >= b,                                                     (2)
+*
+*  for all j in J.
+*
+*  Once the original inequality (1) is replaced by equivalent covering
+*  inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+*  all j in Jn (see above).
+*
+*  RECOVERING SOLUTION
+*
+*  None needed. */
+
+static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
+{     /* process inequality constraint: sum a[j] x[j] >= b;
+         0 - specified row is NOT hidden covering inequality;
+         1 - specified row is covering inequality;
+         2 - specified row is hidden covering inequality. */
+      struct elem *e;
+      int neg;
+      double b = *_b, eps;
+      xassert(npp == npp);
+      /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+      for (e = ptr; e != NULL; e = e->next)
+      {  xassert(e->aj != 0.0);
+         xassert(e->xj->is_int);
+         xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+      }
+      /* check if the specified inequality constraint already has the
+         form of covering inequality */
+      neg = 0; /* neg is |Jn| */
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj == +1.0)
+            ;
+         else if (e->aj == -1.0)
+            neg++;
+         else
+            break;
+      }
+      if (e == NULL)
+      {  /* all coefficients a[j] are +1 or -1; check rhs b */
+         if (b == (double)(1 - neg))
+         {  /* it is covering inequality; no processing is needed */
+            return 1;
+         }
+      }
+      /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+         positive; the result is a~[j] = |a[j]| and new rhs b */
+      for (e = ptr; e != NULL; e = e->next)
+         if (e->aj < 0) b -= e->aj;
+      /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+      /* if b <= 0, skip processing--this case must not appear */
+      if (b < 1e-3) return 0;
+      /* now a[j] > 0 for all j in J, and b > 0 */
+      /* the specified constraint is equivalent to covering inequality
+         iff a[j] >= b for all j in J */
+      eps = 1e-9 + 1e-12 * fabs(b);
+      for (e = ptr; e != NULL; e = e->next)
+         if (fabs(e->aj) < b - eps) return 0;
+      /* perform back substitution x~[j] = 1 - x[j] and construct the
+         final equivalent covering inequality in generalized format */
+      b = 1.0;
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj > 0.0)
+            e->aj = +1.0;
+         else /* e->aj < 0.0 */
+            e->aj = -1.0, b -= 1.0;
+      }
+      *_b = b;
+      return 2;
+}
+
+int npp_hidden_covering(NPP *npp, NPPROW *row)
+{     /* identify hidden covering inequality */
+      NPPROW *copy;
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      int kase, ret, count = 0;
+      double b;
+      /* the row must be inequality constraint */
+      xassert(row->lb < row->ub);
+      for (kase = 0; kase <= 1; kase++)
+      {  if (kase == 0)
+         {  /* process row lower bound */
+            if (row->lb == -DBL_MAX) continue;
+            ptr = copy_form(npp, row, +1.0);
+            b = + row->lb;
+         }
+         else
+         {  /* process row upper bound */
+            if (row->ub == +DBL_MAX) continue;
+            ptr = copy_form(npp, row, -1.0);
+            b = - row->ub;
+         }
+         /* now the inequality has the form "sum a[j] x[j] >= b" */
+         ret = hidden_covering(npp, ptr, &b);
+         xassert(0 <= ret && ret <= 2);
+         if (kase == 1 && ret == 1 || ret == 2)
+         {  /* the original inequality has been identified as hidden
+               covering inequality */
+            count++;
+#ifdef GLP_DEBUG
+            xprintf("Original constraint:\n");
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               xprintf(" %+g x%d", aij->val, aij->col->j);
+            if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+            if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+            xprintf("\n");
+            xprintf("Equivalent covering inequality:\n");
+            for (e = ptr; e != NULL; e = e->next)
+               xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+            xprintf(", >= %g\n", b);
+#endif
+            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+            {  /* the original row is single-sided inequality; no copy
+                  is needed */
+               copy = NULL;
+            }
+            else
+            {  /* the original row is double-sided inequality; we need
+                  to create its copy for other bound before replacing it
+                  with the equivalent inequality */
+               copy = npp_add_row(npp);
+               if (kase == 0)
+               {  /* the copy is for upper bound */
+                  copy->lb = -DBL_MAX, copy->ub = row->ub;
+               }
+               else
+               {  /* the copy is for lower bound */
+                  copy->lb = row->lb, copy->ub = +DBL_MAX;
+               }
+               /* copy original row coefficients */
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  npp_add_aij(npp, copy, aij->col, aij->val);
+            }
+            /* replace the original inequality by equivalent one */
+            npp_erase_row(npp, row);
+            row->lb = b, row->ub = +DBL_MAX;
+            for (e = ptr; e != NULL; e = e->next)
+               npp_add_aij(npp, row, e->xj, e->aj);
+            /* continue processing upper bound for the copy */
+            if (copy != NULL) row = copy;
+         }
+         drop_form(npp, ptr);
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_is_partitioning - test if constraint is partitioning equality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_is_partitioning(NPP *npp, NPPROW *row);
+*
+*  RETURNS
+*
+*  If the specified row (constraint) is partitioning equality (see
+*  below), the routine npp_is_partitioning returns non-zero. Otherwise,
+*  it returns zero.
+*
+*  PARTITIONING EQUALITIES
+*
+*  In canonical format the partitioning equality is the following:
+*
+*     sum  x[j] = 1,                                                 (1)
+*    j in J
+*
+*  where all variables x[j] are binary. This equality expresses the
+*  condition that in any integer feasible solution exactly one variable
+*  in set J must take non-zero (unity) value while other variables must
+*  be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
+*  J is empty, the inequality (1) is infeasible, and if |J| = 1, the
+*  inequality (1) is a fixing row.
+*
+*  In general case the partitioning equality may include original
+*  variables x[j] as well as their complements x~[j]:
+*
+*     sum   x[j] + sum   x~[j] = 1,                                  (2)
+*    j in Jp      j in Jn
+*
+*  where Jp and Jn are not intersected. Therefore, using substitution
+*  x~[j] = 1 - x[j] leads to the partitioning equality in generalized
+*  format:
+*
+*     sum   x[j] - sum   x[j] = 1 - |Jn|.                            (3)
+*    j in Jp      j in Jn */
+
+int npp_is_partitioning(NPP *npp, NPPROW *row)
+{     /* test if constraint is partitioning equality */
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int b;
+      xassert(npp == npp);
+      if (row->lb != row->ub) return 0;
+      b = 1;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0;
+         if (aij->val == +1.0)
+            ;
+         else if (aij->val == -1.0)
+            b--;
+         else
+            return 0;
+      }
+      if (row->lb != (double)b) return 0;
+      return 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_reduce_ineq_coef - reduce inequality constraint coefficients
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+*
+*  DESCRIPTION
+*
+*  The routine npp_reduce_ineq_coef processes specified inequality
+*  constraint attempting to replace it by an equivalent constraint,
+*  where magnitude of coefficients at binary variables is smaller than
+*  in the original constraint. If the inequality is double-sided, it is
+*  replaced by a pair of single-sided inequalities, if necessary.
+*
+*  RETURNS
+*
+*  The routine npp_reduce_ineq_coef returns the number of coefficients
+*  reduced.
+*
+*  BACKGROUND
+*
+*  Consider an inequality constraint:
+*
+*     sum  a[j] x[j] >= b.                                           (1)
+*    j in J
+*
+*  (In case of '<=' inequality it can be transformed to '>=' format by
+*  multiplying both its sides by -1.) Let x[k] be a binary variable;
+*  other variables can be integer as well as continuous. We can write
+*  constraint (1) as follows:
+*
+*     a[k] x[k] + t[k] >= b,                                         (2)
+*
+*  where:
+*
+*     t[k] = sum      a[j] x[j].                                     (3)
+*           j in J\{k}
+*
+*  Since x[k] is binary, constraint (2) is equivalent to disjunction of
+*  the following two constraints:
+*
+*     x[k] = 0,  t[k] >= b                                           (4)
+*
+*        OR
+*
+*     x[k] = 1,  t[k] >= b - a[k].                                   (5)
+*
+*  Let also that for the partial sum t[k] be known some its implied
+*  lower bound inf t[k].
+*
+*  Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
+*  (4) and (5) and therefore constraint (2) are redundant.
+*  If inf t[k] > b - a[k], only constraint (5) is redundant, in which
+*  case it can be replaced with the following redundant and therefore
+*  equivalent constraint:
+*
+*     t[k] >= b - a'[k] = inf t[k],                                  (6)
+*
+*  where:
+*
+*     a'[k] = b - inf t[k].                                          (7)
+*
+*  Thus, the original constraint (2) is equivalent to the following
+*  constraint with coefficient at variable x[k] changed:
+*
+*     a'[k] x[k] + t[k] >= b.                                        (8)
+*
+*  From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
+*  at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
+*  a'[k] < a[k], i.e. the coefficient reduces in magnitude.
+*
+*  Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
+*  constraints (4) and (5) and therefore constraint (2) are redundant.
+*  If inf t[k] > b, only constraint (4) is redundant, in which case it
+*  can be replaced with the following redundant and therefore equivalent
+*  constraint:
+*
+*     t[k] >= b' = inf t[k].                                         (9)
+*
+*  Rewriting constraint (5) as follows:
+*
+*     t[k] >= b - a[k] = b' - a'[k],                                (10)
+*
+*  where:
+*
+*     a'[k] = a[k] + b' - b = a[k] + inf t[k] - b,                  (11)
+*
+*  we can see that disjunction of constraint (9) and (10) is equivalent
+*  to disjunction of constraint (4) and (5), from which it follows that
+*  the original constraint (2) is equivalent to the following constraint
+*  with both coefficient at variable x[k] and right-hand side changed:
+*
+*     a'[k] x[k] + t[k] >= b'.                                      (12)
+*
+*  From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
+*  coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
+*  that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  In the routine npp_reduce_ineq_coef the following implied lower
+*  bound of the partial sum (3) is used:
+*
+*     inf t[k] = sum       a[j] l[j] + sum       a[j] u[j],         (13)
+*               j in Jp\{k}           k in Jn\{k}
+*
+*  where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
+*  lower and upper bounds, resp., of variable x[j].
+*
+*  In order to compute inf t[k] more efficiently, the following formula,
+*  which is equivalent to (13), is actually used:
+*
+*                ( h - a[k] l[k] = h,        if a[k] > 0,
+*     inf t[k] = <                                                  (14)
+*                ( h - a[k] u[k] = h - a[k], if a[k] < 0,
+*
+*  where:
+*
+*     h = sum   a[j] l[j] + sum   a[j] u[j]                         (15)
+*        j in Jp           j in Jn
+*
+*  is the implied lower bound of row (1).
+*
+*  Reduction of positive coefficient (a[k] > 0) does not change value
+*  of h, since l[k] = 0. In case of reduction of negative coefficient
+*  (a[k] < 0) from (11) it follows that:
+*
+*     delta a[k] = a'[k] - a[k] = inf t[k] - b  (> 0),              (16)
+*
+*  so new value of h (accounting that u[k] = 1) can be computed as
+*  follows:
+*
+*     h := h + delta a[k] = h + (inf t[k] - b).                     (17)
+*
+*  RECOVERING SOLUTION
+*
+*  None needed. */
+
+static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
+{     /* process inequality constraint: sum a[j] x[j] >= b */
+      /* returns: the number of coefficients reduced */
+      struct elem *e;
+      int count = 0;
+      double h, inf_t, new_a, b = *_b;
+      xassert(npp == npp);
+      /* compute h; see (15) */
+      h = 0.0;
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj > 0.0)
+         {  if (e->xj->lb == -DBL_MAX) goto done;
+            h += e->aj * e->xj->lb;
+         }
+         else /* e->aj < 0.0 */
+         {  if (e->xj->ub == +DBL_MAX) goto done;
+            h += e->aj * e->xj->ub;
+         }
+      }
+      /* perform reduction of coefficients at binary variables */
+      for (e = ptr; e != NULL; e = e->next)
+      {  /* skip non-binary variable */
+         if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+            continue;
+         if (e->aj > 0.0)
+         {  /* compute inf t[k]; see (14) */
+            inf_t = h;
+            if (b - e->aj < inf_t && inf_t < b)
+            {  /* compute reduced coefficient a'[k]; see (7) */
+               new_a = b - inf_t;
+               if (new_a >= +1e-3 &&
+                   e->aj - new_a >= 0.01 * (1.0 + e->aj))
+               {  /* accept a'[k] */
+#ifdef GLP_DEBUG
+                  xprintf("+");
+#endif
+                  e->aj = new_a;
+                  count++;
+               }
+            }
+         }
+         else /* e->aj < 0.0 */
+         {  /* compute inf t[k]; see (14) */
+            inf_t = h - e->aj;
+            if (b < inf_t && inf_t < b - e->aj)
+            {  /* compute reduced coefficient a'[k]; see (11) */
+               new_a = e->aj + (inf_t - b);
+               if (new_a <= -1e-3 &&
+                   new_a - e->aj >= 0.01 * (1.0 - e->aj))
+               {  /* accept a'[k] */
+#ifdef GLP_DEBUG
+                  xprintf("-");
+#endif
+                  e->aj = new_a;
+                  /* update h; see (17) */
+                  h += (inf_t - b);
+                  /* compute b'; see (9) */
+                  b = inf_t;
+                  count++;
+               }
+            }
+         }
+      }
+      *_b = b;
+done: return count;
+}
+
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
+{     /* reduce inequality constraint coefficients */
+      NPPROW *copy;
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      int kase, count[2];
+      double b;
+      /* the row must be inequality constraint */
+      xassert(row->lb < row->ub);
+      count[0] = count[1] = 0;
+      for (kase = 0; kase <= 1; kase++)
+      {  if (kase == 0)
+         {  /* process row lower bound */
+            if (row->lb == -DBL_MAX) continue;
+#ifdef GLP_DEBUG
+            xprintf("L");
+#endif
+            ptr = copy_form(npp, row, +1.0);
+            b = + row->lb;
+         }
+         else
+         {  /* process row upper bound */
+            if (row->ub == +DBL_MAX) continue;
+#ifdef GLP_DEBUG
+            xprintf("U");
+#endif
+            ptr = copy_form(npp, row, -1.0);
+            b = - row->ub;
+         }
+         /* now the inequality has the form "sum a[j] x[j] >= b" */
+         count[kase] = reduce_ineq_coef(npp, ptr, &b);
+         if (count[kase] > 0)
+         {  /* the original inequality has been replaced by equivalent
+               one with coefficients reduced */
+            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+            {  /* the original row is single-sided inequality; no copy
+                  is needed */
+               copy = NULL;
+            }
+            else
+            {  /* the original row is double-sided inequality; we need
+                  to create its copy for other bound before replacing it
+                  with the equivalent inequality */
+#ifdef GLP_DEBUG
+               xprintf("*");
+#endif
+               copy = npp_add_row(npp);
+               if (kase == 0)
+               {  /* the copy is for upper bound */
+                  copy->lb = -DBL_MAX, copy->ub = row->ub;
+               }
+               else
+               {  /* the copy is for lower bound */
+                  copy->lb = row->lb, copy->ub = +DBL_MAX;
+               }
+               /* copy original row coefficients */
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  npp_add_aij(npp, copy, aij->col, aij->val);
+            }
+            /* replace the original inequality by equivalent one */
+            npp_erase_row(npp, row);
+            row->lb = b, row->ub = +DBL_MAX;
+            for (e = ptr; e != NULL; e = e->next)
+               npp_add_aij(npp, row, e->xj, e->aj);
+            /* continue processing upper bound for the copy */
+            if (copy != NULL) row = copy;
+         }
+         drop_form(npp, ptr);
+      }
+      return count[0] + count[1];
+}
+
+/* eof */
diff --git a/optional/glpk/glpnpp05.c b/optional/glpk/glpnpp05.c
new file mode 100644
index 0000000..8b5c6c3
--- /dev/null
+++ b/optional/glpk/glpnpp05.c
@@ -0,0 +1,809 @@
+/* glpnpp05.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_clean_prob - perform initial LP/MIP processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_clean_prob(NPP *npp);
+*
+*  DESCRIPTION
+*
+*  The routine npp_clean_prob performs initial LP/MIP processing that
+*  currently includes:
+*
+*  1) removing free rows;
+*
+*  2) replacing double-sided constraint rows with almost identical
+*     bounds, by equality constraint rows;
+*
+*  3) removing fixed columns;
+*
+*  4) replacing double-bounded columns with almost identical bounds by
+*     fixed columns and removing those columns;
+*
+*  5) initial processing constraint coefficients (not implemented);
+*
+*  6) initial processing objective coefficients (not implemented). */
+
+void npp_clean_prob(NPP *npp)
+{     /* perform initial LP/MIP processing */
+      NPPROW *row, *next_row;
+      NPPCOL *col, *next_col;
+      int ret;
+      xassert(npp == npp);
+      /* process rows which originally are free */
+      for (row = npp->r_head; row != NULL; row = next_row)
+      {  next_row = row->next;
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+         {  /* process free row */
+#ifdef GLP_DEBUG
+            xprintf("1");
+#endif
+            npp_free_row(npp, row);
+            /* row was deleted */
+         }
+      }
+      /* process rows which originally are double-sided inequalities */
+      for (row = npp->r_head; row != NULL; row = next_row)
+      {  next_row = row->next;
+         if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
+             row->lb < row->ub)
+         {  ret = npp_make_equality(npp, row);
+            if (ret == 0)
+               ;
+            else if (ret == 1)
+            {  /* row was replaced by equality constraint */
+#ifdef GLP_DEBUG
+               xprintf("2");
+#endif
+            }
+            else
+               xassert(ret != ret);
+         }
+      }
+      /* process columns which are originally fixed */
+      for (col = npp->c_head; col != NULL; col = next_col)
+      {  next_col = col->next;
+         if (col->lb == col->ub)
+         {  /* process fixed column */
+#ifdef GLP_DEBUG
+            xprintf("3");
+#endif
+            npp_fixed_col(npp, col);
+            /* column was deleted */
+         }
+      }
+      /* process columns which are originally double-bounded */
+      for (col = npp->c_head; col != NULL; col = next_col)
+      {  next_col = col->next;
+         if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
+             col->lb < col->ub)
+         {  ret = npp_make_fixed(npp, col);
+            if (ret == 0)
+               ;
+            else if (ret == 1)
+            {  /* column was replaced by fixed column; process it */
+#ifdef GLP_DEBUG
+               xprintf("4");
+#endif
+               npp_fixed_col(npp, col);
+               /* column was deleted */
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_process_row - perform basic row processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_process_row(NPP *npp, NPPROW *row, int hard);
+*
+*  DESCRIPTION
+*
+*  The routine npp_process_row performs basic row processing that
+*  currently includes:
+*
+*  1) removing empty row;
+*
+*  2) removing equality constraint row singleton and corresponding
+*     column;
+*
+*  3) removing inequality constraint row singleton and corresponding
+*     column if it was fixed;
+*
+*  4) performing general row analysis;
+*
+*  5) removing redundant row bounds;
+*
+*  6) removing forcing row and corresponding columns;
+*
+*  7) removing row which becomes free due to redundant bounds;
+*
+*  8) computing implied bounds for all columns in the row and using
+*     them to strengthen current column bounds (MIP only, optional,
+*     performed if the flag hard is on).
+*
+*  Additionally the routine may activate affected rows and/or columns
+*  for further processing.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ENODFS  dual infeasibility detected. */
+
+int npp_process_row(NPP *npp, NPPROW *row, int hard)
+{     /* perform basic row processing */
+      NPPCOL *col;
+      NPPAIJ *aij, *next_aij, *aaa;
+      int ret;
+      /* row must not be free */
+      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+      /* start processing row */
+      if (row->ptr == NULL)
+      {  /* empty row */
+         ret = npp_empty_row(npp, row);
+         if (ret == 0)
+         {  /* row was deleted */
+#ifdef GLP_DEBUG
+            xprintf("A");
+#endif
+            return 0;
+         }
+         else if (ret == 1)
+         {  /* primal infeasibility */
+            return GLP_ENOPFS;
+         }
+         else
+            xassert(ret != ret);
+      }
+      if (row->ptr->r_next == NULL)
+      {  /* row singleton */
+         col = row->ptr->col;
+         if (row->lb == row->ub)
+         {  /* equality constraint */
+            ret = npp_eq_singlet(npp, row);
+            if (ret == 0)
+            {  /* column was fixed, row was deleted */
+#ifdef GLP_DEBUG
+               xprintf("B");
+#endif
+               /* activate rows affected by column */
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                  npp_activate_row(npp, aij->row);
+               /* process fixed column */
+               npp_fixed_col(npp, col);
+               /* column was deleted */
+               return 0;
+            }
+            else if (ret == 1 || ret == 2)
+            {  /* primal/integer infeasibility */
+               return GLP_ENOPFS;
+            }
+            else
+               xassert(ret != ret);
+         }
+         else
+         {  /* inequality constraint */
+            ret = npp_ineq_singlet(npp, row);
+            if (0 <= ret && ret <= 3)
+            {  /* row was deleted */
+#ifdef GLP_DEBUG
+               xprintf("C");
+#endif
+               /* activate column, since its length was changed due to
+                  row deletion */
+               npp_activate_col(npp, col);
+               if (ret >= 2)
+               {  /* column bounds changed significantly or column was
+                     fixed */
+                  /* activate rows affected by column */
+                  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                     npp_activate_row(npp, aij->row);
+               }
+               if (ret == 3)
+               {  /* column was fixed; process it */
+#ifdef GLP_DEBUG
+                  xprintf("D");
+#endif
+                  npp_fixed_col(npp, col);
+                  /* column was deleted */
+               }
+               return 0;
+            }
+            else if (ret == 4)
+            {  /* primal infeasibility */
+               return GLP_ENOPFS;
+            }
+            else
+               xassert(ret != ret);
+         }
+      }
+#if 0
+      /* sometimes this causes too large round-off errors; probably
+         pivot coefficient should be chosen more carefully */
+      if (row->ptr->r_next->r_next == NULL)
+      {  /* row doubleton */
+         if (row->lb == row->ub)
+         {  /* equality constraint */
+            if (!(row->ptr->col->is_int ||
+                  row->ptr->r_next->col->is_int))
+            {  /* both columns are continuous */
+               NPPCOL *q;
+               q = npp_eq_doublet(npp, row);
+               if (q != NULL)
+               {  /* column q was eliminated */
+#ifdef GLP_DEBUG
+                  xprintf("E");
+#endif
+                  /* now column q is singleton of type "implied slack
+                     variable"; we process it here to make sure that on
+                     recovering basic solution the row is always active
+                     equality constraint (as required by the routine
+                     rcv_eq_doublet) */
+                  xassert(npp_process_col(npp, q) == 0);
+                  /* column q was deleted; note that row p also may be
+                     deleted */
+                  return 0;
+               }
+            }
+         }
+      }
+#endif
+      /* general row analysis */
+      ret = npp_analyze_row(npp, row);
+      xassert(0x00 <= ret && ret <= 0xFF);
+      if (ret == 0x33)
+      {  /* row bounds are inconsistent with column bounds */
+         return GLP_ENOPFS;
+      }
+      if ((ret & 0x0F) == 0x00)
+      {  /* row lower bound does not exist or redundant */
+         if (row->lb != -DBL_MAX)
+         {  /* remove redundant row lower bound */
+#ifdef GLP_DEBUG
+            xprintf("F");
+#endif
+            npp_inactive_bound(npp, row, 0);
+         }
+      }
+      else if ((ret & 0x0F) == 0x01)
+      {  /* row lower bound can be active */
+         /* see below */
+      }
+      else if ((ret & 0x0F) == 0x02)
+      {  /* row lower bound is a forcing bound */
+#ifdef GLP_DEBUG
+         xprintf("G");
+#endif
+         /* process forcing row */
+         if (npp_forcing_row(npp, row, 0) == 0)
+fixup:   {  /* columns were fixed, row was made free */
+            for (aij = row->ptr; aij != NULL; aij = next_aij)
+            {  /* process column fixed by forcing row */
+#ifdef GLP_DEBUG
+               xprintf("H");
+#endif
+               col = aij->col;
+               next_aij = aij->r_next;
+               /* activate rows affected by column */
+               for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+                  npp_activate_row(npp, aaa->row);
+               /* process fixed column */
+               npp_fixed_col(npp, col);
+               /* column was deleted */
+            }
+            /* process free row (which now is empty due to deletion of
+               all its columns) */
+            npp_free_row(npp, row);
+            /* row was deleted */
+            return 0;
+         }
+      }
+      else
+         xassert(ret != ret);
+      if ((ret & 0xF0) == 0x00)
+      {  /* row upper bound does not exist or redundant */
+         if (row->ub != +DBL_MAX)
+         {  /* remove redundant row upper bound */
+#ifdef GLP_DEBUG
+            xprintf("I");
+#endif
+            npp_inactive_bound(npp, row, 1);
+         }
+      }
+      else if ((ret & 0xF0) == 0x10)
+      {  /* row upper bound can be active */
+         /* see below */
+      }
+      else if ((ret & 0xF0) == 0x20)
+      {  /* row upper bound is a forcing bound */
+#ifdef GLP_DEBUG
+         xprintf("J");
+#endif
+         /* process forcing row */
+         if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
+      }
+      else
+         xassert(ret != ret);
+      if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+      {  /* row became free due to redundant bounds removal */
+#ifdef GLP_DEBUG
+         xprintf("K");
+#endif
+         /* activate its columns, since their length will change due
+            to row deletion */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            npp_activate_col(npp, aij->col);
+         /* process free row */
+         npp_free_row(npp, row);
+         /* row was deleted */
+         return 0;
+      }
+#if 1 /* 23/XII-2009 */
+      /* row lower and/or upper bounds can be active */
+      if (npp->sol == GLP_MIP && hard)
+      {  /* improve current column bounds (optional) */
+         if (npp_improve_bounds(npp, row, 1) < 0)
+            return GLP_ENOPFS;
+      }
+#endif
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_improve_bounds - improve current column bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+*
+*  DESCRIPTION
+*
+*  The routine npp_improve_bounds analyzes specified row (inequality
+*  or equality constraint) to determine implied column bounds and then
+*  uses these bounds to improve (strengthen) current column bounds.
+*
+*  If the flag is on and current column bounds changed significantly
+*  or the column was fixed, the routine activate rows affected by the
+*  column for further processing. (This feature is intended to be used
+*  in the main loop of the routine npp_process_row.)
+*
+*  NOTE: This operation can be used for MIP problem only.
+*
+*  RETURNS
+*
+*  The routine npp_improve_bounds returns the number of significantly
+*  changed bounds plus the number of column having been fixed due to
+*  bound improvements. However, if the routine detects primal/integer
+*  infeasibility, it returns a negative value. */
+
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
+{     /* improve current column bounds */
+      NPPCOL *col;
+      NPPAIJ *aij, *next_aij, *aaa;
+      int kase, ret, count = 0;
+      double lb, ub;
+      xassert(npp->sol == GLP_MIP);
+      /* row must not be free */
+      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+      /* determine implied column bounds */
+      npp_implied_bounds(npp, row);
+      /* and use these bounds to strengthen current column bounds */
+      for (aij = row->ptr; aij != NULL; aij = next_aij)
+      {  col = aij->col;
+         next_aij = aij->r_next;
+         for (kase = 0; kase <= 1; kase++)
+         {  /* save current column bounds */
+            lb = col->lb, ub = col->ub;
+            if (kase == 0)
+            {  /* process implied column lower bound */
+               if (col->ll.ll == -DBL_MAX) continue;
+               ret = npp_implied_lower(npp, col, col->ll.ll);
+            }
+            else
+            {  /* process implied column upper bound */
+               if (col->uu.uu == +DBL_MAX) continue;
+               ret = npp_implied_upper(npp, col, col->uu.uu);
+            }
+            if (ret == 0 || ret == 1)
+            {  /* current column bounds did not change or changed, but
+                  not significantly; restore current column bounds */
+               col->lb = lb, col->ub = ub;
+            }
+            else if (ret == 2 || ret == 3)
+            {  /* current column bounds changed significantly or column
+                  was fixed */
+#ifdef GLP_DEBUG
+               xprintf("L");
+#endif
+               count++;
+               /* activate other rows affected by column, if required */
+               if (flag)
+               {  for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+                  {  if (aaa->row != row)
+                        npp_activate_row(npp, aaa->row);
+                  }
+               }
+               if (ret == 3)
+               {  /* process fixed column */
+#ifdef GLP_DEBUG
+                  xprintf("M");
+#endif
+                  npp_fixed_col(npp, col);
+                  /* column was deleted */
+                  break; /* for kase */
+               }
+            }
+            else if (ret == 4)
+            {  /* primal/integer infeasibility */
+               return -1;
+            }
+            else
+               xassert(ret != ret);
+         }
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_process_col - perform basic column processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_process_col(NPP *npp, NPPCOL *col);
+*
+*  DESCRIPTION
+*
+*  The routine npp_process_col performs basic column processing that
+*  currently includes:
+*
+*  1) fixing and removing empty column;
+*
+*  2) removing column singleton, which is implied slack variable, and
+*     corresponding row if it becomes free;
+*
+*  3) removing bounds of column, which is implied free variable, and
+*     replacing corresponding row by equality constraint.
+*
+*  Additionally the routine may activate affected rows and/or columns
+*  for further processing.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ENODFS  dual infeasibility detected. */
+
+int npp_process_col(NPP *npp, NPPCOL *col)
+{     /* perform basic column processing */
+      NPPROW *row;
+      NPPAIJ *aij;
+      int ret;
+      /* column must not be fixed */
+      xassert(col->lb < col->ub);
+      /* start processing column */
+      if (col->ptr == NULL)
+      {  /* empty column */
+         ret = npp_empty_col(npp, col);
+         if (ret == 0)
+         {  /* column was fixed and deleted */
+#ifdef GLP_DEBUG
+            xprintf("N");
+#endif
+            return 0;
+         }
+         else if (ret == 1)
+         {  /* dual infeasibility */
+            return GLP_ENODFS;
+         }
+         else
+            xassert(ret != ret);
+      }
+      if (col->ptr->c_next == NULL)
+      {  /* column singleton */
+         row = col->ptr->row;
+         if (row->lb == row->ub)
+         {  /* equality constraint */
+            if (!col->is_int)
+slack:      {  /* implied slack variable */
+#ifdef GLP_DEBUG
+               xprintf("O");
+#endif
+               npp_implied_slack(npp, col);
+               /* column was deleted */
+               if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+               {  /* row became free due to implied slack variable */
+#ifdef GLP_DEBUG
+                  xprintf("P");
+#endif
+                  /* activate columns affected by row */
+                  for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                     npp_activate_col(npp, aij->col);
+                  /* process free row */
+                  npp_free_row(npp, row);
+                  /* row was deleted */
+               }
+               else
+               {  /* row became inequality constraint; activate it
+                     since its length changed due to column deletion */
+                  npp_activate_row(npp, row);
+               }
+               return 0;
+            }
+         }
+         else
+         {  /* inequality constraint */
+            if (!col->is_int)
+            {  ret = npp_implied_free(npp, col);
+               if (ret == 0)
+               {  /* implied free variable */
+#ifdef GLP_DEBUG
+                  xprintf("Q");
+#endif
+                  /* column bounds were removed, row was replaced by
+                     equality constraint */
+                  goto slack;
+               }
+               else if (ret == 1)
+               {  /* column is not implied free variable, because its
+                     lower and/or upper bounds can be active */
+               }
+               else if (ret == 2)
+               {  /* dual infeasibility */
+                  return GLP_ENODFS;
+               }
+            }
+         }
+      }
+      /* column still exists */
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_process_prob - perform basic LP/MIP processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_process_prob(NPP *npp, int hard);
+*
+*  DESCRIPTION
+*
+*  The routine npp_process_prob performs basic LP/MIP processing that
+*  currently includes:
+*
+*  1) initial LP/MIP processing (see the routine npp_clean_prob),
+*
+*  2) basic row processing (see the routine npp_process_row), and
+*
+*  3) basic column processing (see the routine npp_process_col).
+*
+*  If the flag hard is on, the routine attempts to improve current
+*  column bounds multiple times within the main processing loop, in
+*  which case this feature may take a time. Otherwise, if the flag hard
+*  is off, improving column bounds is performed only once at the end of
+*  the main loop. (Note that this feature is used for MIP only.)
+*
+*  The routine uses two sets: the set of active rows and the set of
+*  active columns. Rows/columns are marked by a flag (the field temp in
+*  NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
+*  in which case it is placed in the beginning of the row/column list;
+*  otherwise, if the flag is zero, the row/column is inactive, in which
+*  case it is placed in the end of the row/column list. If a row/column
+*  being currently processed may affect other rows/columns, the latters
+*  are activated for further processing.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ENODFS  dual infeasibility detected. */
+
+int npp_process_prob(NPP *npp, int hard)
+{     /* perform basic LP/MIP processing */
+      NPPROW *row;
+      NPPCOL *col;
+      int processing, ret;
+      /* perform initial LP/MIP processing */
+      npp_clean_prob(npp);
+      /* activate all remaining rows and columns */
+      for (row = npp->r_head; row != NULL; row = row->next)
+         row->temp = 1;
+      for (col = npp->c_head; col != NULL; col = col->next)
+         col->temp = 1;
+      /* main processing loop */
+      processing = 1;
+      while (processing)
+      {  processing = 0;
+         /* process all active rows */
+         for (;;)
+         {  row = npp->r_head;
+            if (row == NULL || !row->temp) break;
+            npp_deactivate_row(npp, row);
+            ret = npp_process_row(npp, row, hard);
+            if (ret != 0) goto done;
+            processing = 1;
+         }
+         /* process all active columns */
+         for (;;)
+         {  col = npp->c_head;
+            if (col == NULL || !col->temp) break;
+            npp_deactivate_col(npp, col);
+            ret = npp_process_col(npp, col);
+            if (ret != 0) goto done;
+            processing = 1;
+         }
+      }
+#if 1 /* 23/XII-2009 */
+      if (npp->sol == GLP_MIP && !hard)
+      {  /* improve current column bounds (optional) */
+         for (row = npp->r_head; row != NULL; row = row->next)
+         {  if (npp_improve_bounds(npp, row, 0) < 0)
+            {  ret = GLP_ENOPFS;
+               goto done;
+            }
+         }
+      }
+#endif
+      /* all seems ok */
+      ret = 0;
+done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
+#ifdef GLP_DEBUG
+      xprintf("\n");
+#endif
+      return ret;
+}
+
+/**********************************************************************/
+
+int npp_simplex(NPP *npp, const glp_smcp *parm)
+{     /* process LP prior to applying primal/dual simplex method */
+      int ret;
+      xassert(npp->sol == GLP_SOL);
+      xassert(parm == parm);
+      ret = npp_process_prob(npp, 0);
+      return ret;
+}
+
+/**********************************************************************/
+
+int npp_integer(NPP *npp, const glp_iocp *parm)
+{     /* process MIP prior to applying branch-and-bound method */
+      NPPROW *row, *prev_row;
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int count, ret;
+      xassert(npp->sol == GLP_MIP);
+      xassert(parm == parm);
+      /*==============================================================*/
+      /* perform basic MIP processing */
+      ret = npp_process_prob(npp, 1);
+      if (ret != 0) goto done;
+      /*==============================================================*/
+      /* binarize problem, if required */
+      if (parm->binarize)
+         npp_binarize_prob(npp);
+      /*==============================================================*/
+      /* identify hidden packing inequalities */
+      count = 0;
+      /* new rows will be added to the end of the row list, so we go
+         from the end to beginning of the row list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* skip free row */
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+         /* skip equality constraint */
+         if (row->lb == row->ub) continue;
+         /* skip row having less than two variables */
+         if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
+         /* skip row having non-binary variables */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  col = aij->col;
+            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+               break;
+         }
+         if (aij != NULL) continue;
+         count += npp_hidden_packing(npp, row);
+      }
+      if (count > 0)
+         xprintf("%d hidden packing inequaliti(es) were detected\n",
+            count);
+      /*==============================================================*/
+      /* identify hidden covering inequalities */
+      count = 0;
+      /* new rows will be added to the end of the row list, so we go
+         from the end to beginning of the row list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* skip free row */
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+         /* skip equality constraint */
+         if (row->lb == row->ub) continue;
+         /* skip row having less than three variables */
+         if (row->ptr == NULL || row->ptr->r_next == NULL ||
+             row->ptr->r_next->r_next == NULL) continue;
+         /* skip row having non-binary variables */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  col = aij->col;
+            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+               break;
+         }
+         if (aij != NULL) continue;
+         count += npp_hidden_covering(npp, row);
+      }
+      if (count > 0)
+         xprintf("%d hidden covering inequaliti(es) were detected\n",
+            count);
+      /*==============================================================*/
+      /* reduce inequality constraint coefficients */
+      count = 0;
+      /* new rows will be added to the end of the row list, so we go
+         from the end to beginning of the row list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* skip equality constraint */
+         if (row->lb == row->ub) continue;
+         count += npp_reduce_ineq_coef(npp, row);
+      }
+      if (count > 0)
+         xprintf("%d constraint coefficient(s) were reduced\n", count);
+      /*==============================================================*/
+#ifdef GLP_DEBUG
+      routine(npp);
+#endif
+      /*==============================================================*/
+      /* all seems ok */
+      ret = 0;
+done: return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpqmd.c b/optional/glpk/glpqmd.c
new file mode 100644
index 0000000..3d4869d
--- /dev/null
+++ b/optional/glpk/glpqmd.c
@@ -0,0 +1,584 @@
+/* glpqmd.c (quotient minimum degree algorithm) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
+*  GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK:
+*
+*  ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE
+*  POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981.
+*
+*  THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS
+*  OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU,
+*  UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA.
+*
+*  The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "glpqmd.h"
+
+/***********************************************************************
+*  NAME
+*
+*  genqmd - GENeral Quotient Minimum Degree algorithm
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
+*     int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+*     int qsize[], int qlink[], int *nofsub);
+*
+*  PURPOSE
+*
+*  This routine implements the minimum degree algorithm. It makes use
+*  of the implicit representation of the elimination graph by quotient
+*  graphs, and the notion of indistinguishable nodes.
+*
+*  CAUTION
+*
+*  The adjancy vector adjncy will be destroyed.
+*
+*  INPUT PARAMETERS
+*
+*  neqns  - number of equations;
+*  (xadj, adjncy) -
+*           the adjancy structure.
+*
+*  OUTPUT PARAMETERS
+*
+*  perm   - the minimum degree ordering;
+*  invp   - the inverse of perm.
+*
+*  WORKING PARAMETERS
+*
+*  deg    - the degree vector. deg[i] is negative means node i has been
+*           numbered;
+*  marker - a marker vector, where marker[i] is negative means node i
+*           has been merged with another nodeand thus can be ignored;
+*  rchset - vector used for the reachable set;
+*  nbrhd  - vector used for neighborhood set;
+*  qsize  - vector used to store the size of indistinguishable
+*           supernodes;
+*  qlink  - vector used to store indistinguishable nodes, i, qlink[i],
+*           qlink[qlink[i]], ... are the members of the supernode
+*           represented by i.
+*
+*  PROGRAM SUBROUTINES
+*
+*  qmdrch, qmdqt, qmdupd.
+***********************************************************************/
+
+void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[],
+      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+      int qsize[], int qlink[], int *_nofsub)
+{     int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num,
+         nump1, nxnode, rchsze, search, thresh;
+#     define neqns  (*_neqns)
+#     define nofsub (*_nofsub)
+      /* Initialize degree vector and other working variables. */
+      mindeg = neqns;
+      nofsub = 0;
+      for (node = 1; node <= neqns; node++)
+      {  perm[node] = node;
+         invp[node] = node;
+         marker[node] = 0;
+         qsize[node] = 1;
+         qlink[node] = 0;
+         ndeg = xadj[node+1] - xadj[node];
+         deg[node] = ndeg;
+         if (ndeg < mindeg) mindeg = ndeg;
+      }
+      num = 0;
+      /* Perform threshold search to get a node of min degree.
+         Variable search point to where search should start. */
+s200: search = 1;
+      thresh = mindeg;
+      mindeg = neqns;
+s300: nump1 = num + 1;
+      if (nump1 > search) search = nump1;
+      for (j = search; j <= neqns; j++)
+      {  node = perm[j];
+         if (marker[node] >= 0)
+         {  ndeg = deg[node];
+            if (ndeg <= thresh) goto s500;
+            if (ndeg < mindeg) mindeg = ndeg;
+         }
+      }
+      goto s200;
+      /* Node has minimum degree. Find its reachable sets by calling
+         qmdrch. */
+s500: search = j;
+      nofsub += deg[node];
+      marker[node] = 1;
+      qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze,
+         nbrhd);
+      /* Eliminate all nodes indistinguishable from node. They are given
+         by node, qlink[node], ... . */
+      nxnode = node;
+s600: num++;
+      np = invp[nxnode];
+      ip = perm[num];
+      perm[np] = ip;
+      invp[ip] = np;
+      perm[num] = nxnode;
+      invp[nxnode] = num;
+      deg[nxnode] = -1;
+      nxnode = qlink[nxnode];
+      if (nxnode > 0) goto s600;
+      if (rchsze > 0)
+      {  /* Update the degrees of the nodes in the reachable set and
+            identify indistinguishable nodes. */
+         qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink,
+            marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]);
+         /* Reset marker value of nodes in reach set. Update threshold
+            value for cyclic search. Also call qmdqt to form new
+            quotient graph. */
+         marker[node] = 0;
+         for (irch = 1; irch <= rchsze; irch++)
+         {  inode = rchset[irch];
+            if (marker[inode] >= 0)
+            {  marker[inode] = 0;
+               ndeg = deg[inode];
+               if (ndeg < mindeg) mindeg = ndeg;
+               if (ndeg <= thresh)
+               {  mindeg = thresh;
+                  thresh = ndeg;
+                  search = invp[inode];
+               }
+            }
+         }
+         if (nhdsze > 0)
+            qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd);
+      }
+      if (num < neqns) goto s300;
+      return;
+#     undef neqns
+#     undef nofsub
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdrch - Quotient MD ReaCHable set
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
+*     int marker[], int *rchsze, int rchset[], int *nhdsze,
+*     int nbrhd[]);
+*
+*  PURPOSE
+*
+*  This subroutine determines the reachable set of a node through a
+*  given subset. The adjancy structure is assumed to be stored in a
+*  quotient graph format.
+* 
+*  INPUT PARAMETERS
+*
+*  root   - the given node not in the subset;
+*  (xadj, adjncy) -
+*           the adjancy structure pair;
+*  deg    - the degree vector. deg[i] < 0 means the node belongs to the
+*           given subset.
+*
+*  OUTPUT PARAMETERS
+*
+*  (rchsze, rchset) -
+*           the reachable set;
+*  (nhdsze, nbrhd) -
+*           the neighborhood set.
+*
+*  UPDATED PARAMETERS
+*
+*  marker - the marker vector for reach and nbrhd sets. > 0 means the
+*           node is in reach set. < 0 means the node has been merged
+*           with others in the quotient or it is in nbrhd set.
+***********************************************************************/
+
+void qmdrch(int *_root, int xadj[], int adjncy[], int deg[],
+      int marker[], int *_rchsze, int rchset[], int *_nhdsze,
+      int nbrhd[])
+{     int i, istop, istrt, j, jstop, jstrt, nabor, node;
+#     define root   (*_root)
+#     define rchsze (*_rchsze)
+#     define nhdsze (*_nhdsze)
+      /* Loop through the neighbors of root in the quotient graph. */
+      nhdsze = 0;
+      rchsze = 0;
+      istrt = xadj[root];
+      istop = xadj[root+1] - 1;
+      if (istop < istrt) return;
+      for (i = istrt; i <= istop; i++)
+      {  nabor = adjncy[i];
+         if (nabor == 0) return;
+         if (marker[nabor] == 0)
+         {  if (deg[nabor] >= 0)
+            {  /* Include nabor into the reachable set. */
+               rchsze++;
+               rchset[rchsze] = nabor;
+               marker[nabor] = 1;
+               goto s600;
+            }
+            /* nabor has been eliminated. Find nodes reachable from
+               it. */
+            marker[nabor] = -1;
+            nhdsze++;
+            nbrhd[nhdsze] = nabor;
+s300:       jstrt = xadj[nabor];
+            jstop = xadj[nabor+1] - 1;
+            for (j = jstrt; j <= jstop; j++)
+            {  node = adjncy[j];
+               nabor = - node;
+               if (node < 0) goto s300;
+               if (node == 0) goto s600;
+               if (marker[node] == 0)
+               {  rchsze++;
+                  rchset[rchsze] = node;
+                  marker[node] = 1;
+               }
+            }
+         }
+s600:    ;
+      }
+      return;
+#     undef root
+#     undef rchsze
+#     undef nhdsze
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdqt - Quotient MD Quotient graph Transformation
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
+*     int *rchsze, int rchset[], int nbrhd[]);
+*
+*  PURPOSE
+*
+*  This subroutine performs the quotient graph transformation after a
+*  node has been eliminated.
+*
+*  INPUT PARAMETERS
+*
+*  root   - the node just eliminated. It becomes the representative of
+*           the new supernode;
+*  (xadj, adjncy) -
+*           the adjancy structure;
+*  (rchsze, rchset) -
+*           the reachable set of root in the old quotient graph;
+*  nbrhd  - the neighborhood set which will be merged with root to form
+*           the new supernode;
+*  marker - the marker vector.
+*
+*  UPDATED PARAMETERS
+*
+*  adjncy - becomes the adjncy of the quotient graph.
+***********************************************************************/
+
+void qmdqt(int *_root, int xadj[], int adjncy[], int marker[],
+      int *_rchsze, int rchset[], int nbrhd[])
+{     int inhd, irch, j, jstop, jstrt, link, nabor, node;
+#     define root   (*_root)
+#     define rchsze (*_rchsze)
+      irch = 0;
+      inhd = 0;
+      node = root;
+s100: jstrt = xadj[node];
+      jstop = xadj[node+1] - 2;
+      if (jstop >= jstrt)
+      {  /* Place reach nodes into the adjacent list of node. */
+         for (j = jstrt; j <= jstop; j++)
+         {  irch++;
+            adjncy[j] = rchset[irch];
+            if (irch >= rchsze) goto s400;
+         }
+      }
+      /* Link to other space provided by the nbrhd set. */
+      link = adjncy[jstop+1];
+      node = - link;
+      if (link >= 0)
+      {  inhd++;
+         node = nbrhd[inhd];
+         adjncy[jstop+1] = - node;
+      }
+      goto s100;
+      /* All reachable nodes have been saved. End the adjacent list.
+         Add root to the neighborhood list of each node in the reach
+         set. */
+s400: adjncy[j+1] = 0;
+      for (irch = 1; irch <= rchsze; irch++)
+      {  node = rchset[irch];
+         if (marker[node] >= 0)
+         {  jstrt = xadj[node];
+            jstop = xadj[node+1] - 1;
+            for (j = jstrt; j <= jstop; j++)
+            {  nabor = adjncy[j];
+               if (marker[nabor] < 0)
+               {  adjncy[j] = root;
+                  goto s600;
+               }
+            }
+         }
+s600:    ;
+      }
+      return;
+#     undef root
+#     undef rchsze
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdupd - Quotient MD UPDate
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
+*     int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+*     int nbrhd[]);
+*
+*  PURPOSE
+*
+*  This routine performs degree update for a set of nodes in the minimum
+*  degree algorithm.
+*
+*  INPUT PARAMETERS
+*
+*  (xadj, adjncy) -
+*           the adjancy structure;
+*  (nlist, list) -
+*           the list of nodes whose degree has to be updated.
+*
+*  UPDATED PARAMETERS
+*
+*  deg    - the degree vector;
+*  qsize  - size of indistinguishable supernodes;
+*  qlink  - linked list for indistinguishable nodes;
+*  marker - used to mark those nodes in reach/nbrhd sets.
+*
+*  WORKING PARAMETERS
+*
+*  rchset - the reachable set;
+*  nbrhd  - the neighborhood set.
+*
+*  PROGRAM SUBROUTINES
+*
+*  qmdmrg.
+***********************************************************************/
+
+void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[],
+      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+      int nbrhd[])
+{     int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark,
+         nabor, nhdsze, node, rchsze;
+#     define nlist  (*_nlist)
+      /* Find all eliminated supernodes that are adjacent to some nodes
+         in the given list. Put them into (nhdsze, nbrhd). deg0 contains
+         the number of nodes in the list. */
+      if (nlist <= 0) return;
+      deg0 = 0;
+      nhdsze = 0;
+      for (il = 1; il <= nlist; il++)
+      {  node = list[il];
+         deg0 += qsize[node];
+         jstrt = xadj[node];
+         jstop = xadj[node+1] - 1;
+         for (j = jstrt; j <= jstop; j++)
+         {  nabor = adjncy[j];
+            if (marker[nabor] == 0 && deg[nabor] < 0)
+            {  marker[nabor] = -1;
+               nhdsze++;
+               nbrhd[nhdsze] = nabor;
+            }
+         }
+      }
+      /* Merge indistinguishable nodes in the list by calling the
+         subroutine qmdmrg. */
+      if (nhdsze > 0)
+         qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, &deg0, &nhdsze,
+            nbrhd, rchset, &nbrhd[nhdsze+1]);
+      /* Find the new degrees of the nodes that have not been merged. */
+      for (il = 1; il <= nlist; il++)
+      {  node = list[il];
+         mark = marker[node];
+         if (mark == 0 || mark == 1)
+         {  marker[node] = 2;
+            qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset,
+               &nhdsze, nbrhd);
+            deg1 = deg0;
+            if (rchsze > 0)
+            {  for (irch = 1; irch <= rchsze; irch++)
+               {  inode = rchset[irch];
+                  deg1 += qsize[inode];
+                  marker[inode] = 0;
+               }
+            }
+            deg[node] = deg1 - 1;
+            if (nhdsze > 0)
+            {  for (inhd = 1; inhd <= nhdsze; inhd++)
+               {  inode = nbrhd[inhd];
+                  marker[inode] = 0;
+               }
+            }
+         }
+      }
+      return;
+#     undef nlist
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdmrg - Quotient MD MeRGe
+*
+*  SYNOPSIS
+*
+*  #include "qmdmrg.h"
+*  void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+*     int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
+*     int rchset[], int ovrlp[]);
+*
+*  PURPOSE
+*
+*  This routine merges indistinguishable nodes in the minimum degree
+*  ordering algorithm. It also computes the new degrees of these new
+*  supernodes.
+*
+*  INPUT PARAMETERS
+*
+*  (xadj, adjncy) -
+*           the adjancy structure;
+*  deg0   - the number of nodes in the given set;
+*  (nhdsze, nbrhd) -
+*           the set of eliminated supernodes adjacent to some nodes in
+*           the set.
+*
+*  UPDATED PARAMETERS
+*
+*  deg    - the degree vector;
+*  qsize  - size of indistinguishable nodes;
+*  qlink  - linked list for indistinguishable nodes;
+*  marker - the given set is given by those nodes with marker value set
+*           to 1. Those nodes with degree updated will have marker value
+*           set to 2.
+*
+*  WORKING PARAMETERS
+*
+*  rchset - the reachable set;
+*  ovrlp  - temp vector to store the intersection of two reachable sets.
+***********************************************************************/
+
+void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+      int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[],
+      int rchset[], int ovrlp[])
+{     int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode,
+         mark, mrgsze, nabor, node, novrlp, rchsze, root;
+#     define deg0   (*_deg0)
+#     define nhdsze (*_nhdsze)
+      /* Initialization. */
+      if (nhdsze <= 0) return;
+      for (inhd = 1; inhd <= nhdsze; inhd++)
+      {  root = nbrhd[inhd];
+         marker[root] = 0;
+      }
+      /* Loop through each eliminated supernode in the set
+         (nhdsze, nbrhd). */
+      for (inhd = 1; inhd <= nhdsze; inhd++)
+      {  root = nbrhd[inhd];
+         marker[root] = -1;
+         rchsze = 0;
+         novrlp = 0;
+         deg1 = 0;
+s200:    jstrt = xadj[root];
+         jstop = xadj[root+1] - 1;
+         /* Determine the reachable set and its intersection with the
+            input reachable set. */
+         for (j = jstrt; j <= jstop; j++)
+         {  nabor = adjncy[j];
+            root = - nabor;
+            if (nabor < 0) goto s200;
+            if (nabor == 0) break;
+            mark = marker[nabor];
+            if (mark == 0)
+            {  rchsze++;
+               rchset[rchsze] = nabor;
+               deg1 += qsize[nabor];
+               marker[nabor] = 1;
+            }
+            else if (mark == 1)
+            {  novrlp++;
+               ovrlp[novrlp] = nabor;
+               marker[nabor] = 2;
+            }
+         }
+         /* From the overlapped set, determine the nodes that can be
+            merged together. */
+         head = 0;
+         mrgsze = 0;
+         for (iov = 1; iov <= novrlp; iov++)
+         {  node = ovrlp[iov];
+            jstrt = xadj[node];
+            jstop = xadj[node+1] - 1;
+            for (j = jstrt; j <= jstop; j++)
+            {  nabor = adjncy[j];
+               if (marker[nabor] == 0)
+               {  marker[node] = 1;
+                  goto s1100;
+               }
+            }
+            /* Node belongs to the new merged supernode. Update the
+               vectors qlink and qsize. */
+            mrgsze += qsize[node];
+            marker[node] = -1;
+            lnode = node;
+s900:       link = qlink[lnode];
+            if (link > 0)
+            {  lnode = link;
+               goto s900;
+            }
+            qlink[lnode] = head;
+            head = node;
+s1100:      ;
+         }
+         if (head > 0)
+         {  qsize[head] = mrgsze;
+            deg[head] = deg0 + deg1 - 1;
+            marker[head] = 2;
+         }
+         /* Reset marker values. */
+         root = nbrhd[inhd];
+         marker[root] = 0;
+         if (rchsze > 0)
+         {  for (irch = 1; irch <= rchsze; irch++)
+            {  node = rchset[irch];
+               marker[node] = 0;
+            }
+         }
+      }
+      return;
+#     undef deg0
+#     undef nhdsze
+}
+
+/* eof */
diff --git a/optional/glpk/glpqmd.h b/optional/glpk/glpqmd.h
new file mode 100644
index 0000000..40b8cb4
--- /dev/null
+++ b/optional/glpk/glpqmd.h
@@ -0,0 +1,59 @@
+/* glpqmd.h (quotient minimum degree algorithm) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPQMD_H
+#define GLPQMD_H
+
+#define genqmd _glp_qmd_genqmd
+void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
+      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+      int qsize[], int qlink[], int *nofsub);
+/* GENeral Quotient Minimum Degree algorithm */
+
+#define qmdrch _glp_qmd_qmdrch
+void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
+      int marker[], int *rchsze, int rchset[], int *nhdsze,
+      int nbrhd[]);
+/* Quotient MD ReaCHable set */
+
+#define qmdqt _glp_qmd_qmdqt
+void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
+      int *rchsze, int rchset[], int nbrhd[]);
+/* Quotient MD Quotient graph Transformation */
+
+#define qmdupd _glp_qmd_qmdupd
+void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
+      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+      int nbrhd[]);
+/* Quotient MD UPDate */
+
+#define qmdmrg _glp_qmd_qmdmrg
+void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+      int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
+      int rchset[], int ovrlp[]);
+/* Quotient MD MeRGe */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glprgr.c b/optional/glpk/glprgr.c
new file mode 100644
index 0000000..c05b79d
--- /dev/null
+++ b/optional/glpk/glprgr.c
@@ -0,0 +1,165 @@
+/* glprgr.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glprgr.h"
+#define xfault xerror
+
+/***********************************************************************
+*  NAME
+*
+*  rgr_write_bmp16 - write 16-color raster image in BMP file format
+*
+*  SYNOPSIS
+*
+*  #include "glprgr.h"
+*  int rgr_write_bmp16(const char *fname, int m, int n, const char
+*     map[]);
+*
+*  DESCRIPTION
+*
+*  The routine rgr_write_bmp16 writes 16-color raster image in
+*  uncompressed BMP file format (Windows bitmap) to a binary file whose
+*  name is specified by the character string fname.
+*
+*  The parameters m and n specify, respectively, the number of rows and
+*  the numbers of columns (i.e. height and width) of the raster image.
+*
+*  The character array map has m*n elements. Elements map[0, ..., n-1]
+*  correspond to the first (top) scanline, elements map[n, ..., 2*n-1]
+*  correspond to the second scanline, etc.
+*
+*  Each element of the array map specifies a color of the corresponding
+*  pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X)
+*  are ignored, I is high intensity bit, R is red color bit, G is green
+*  color bit, and B is blue color bit. Thus, all 16 possible colors are
+*  coded as following hexadecimal numbers:
+*
+*     0x00 = black         0x08 = dark gray
+*     0x01 = blue          0x09 = bright blue
+*     0x02 = green         0x0A = bright green
+*     0x03 = cyan          0x0B = bright cyan
+*     0x04 = red           0x0C = bright red
+*     0x05 = magenta       0x0D = bright magenta
+*     0x06 = brown         0x0E = yellow
+*     0x07 = light gray    0x0F = white
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero; otherwise, it prints
+*  an appropriate error message and returns non-zero. */
+
+static void put_byte(FILE *fp, int c)
+{     fputc(c, fp);
+      return;
+}
+
+static void put_word(FILE *fp, int w)
+{     /* big endian */
+      put_byte(fp, w);
+      put_byte(fp, w >> 8);
+      return;
+}
+
+static void put_dword(FILE *fp, int d)
+{     /* big endian */
+      put_word(fp, d);
+      put_word(fp, d >> 16);
+      return;
+}
+
+int rgr_write_bmp16(const char *fname, int m, int n, const char map[])
+{     FILE *fp;
+      int offset, bmsize, i, j, b, ret = 0;
+      if (!(1 <= m && m <= 32767))
+         xfault("rgr_write_bmp16: m = %d; invalid height\n", m);
+      if (!(1 <= n && n <= 32767))
+         xfault("rgr_write_bmp16: n = %d; invalid width\n", n);
+      fp = fopen(fname, "wb");
+      if (fp == NULL)
+      {  xprintf("rgr_write_bmp16: unable to create `%s' - %s\n",
+            fname, strerror(errno));
+         ret = 1;
+         goto fini;
+      }
+      offset = 14 + 40 + 16 * 4;
+      bmsize = (4 * n + 31) / 32;
+      /* struct BMPFILEHEADER (14 bytes) */
+      /* UINT bfType */          put_byte(fp, 'B'), put_byte(fp, 'M');
+      /* DWORD bfSize */         put_dword(fp, offset + bmsize * 4);
+      /* UINT bfReserved1 */     put_word(fp, 0);
+      /* UNIT bfReserved2 */     put_word(fp, 0);
+      /* DWORD bfOffBits */      put_dword(fp, offset);
+      /* struct BMPINFOHEADER (40 bytes) */
+      /* DWORD biSize */         put_dword(fp, 40);
+      /* LONG biWidth */         put_dword(fp, n);
+      /* LONG biHeight */        put_dword(fp, m);
+      /* WORD biPlanes */        put_word(fp, 1);
+      /* WORD biBitCount */      put_word(fp, 4);
+      /* DWORD biCompression */  put_dword(fp, 0 /* BI_RGB */);
+      /* DWORD biSizeImage */    put_dword(fp, 0);
+      /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
+      /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
+      /* DWORD biClrUsed */      put_dword(fp, 0);
+      /* DWORD biClrImportant */ put_dword(fp, 0);
+      /* struct RGBQUAD (16 * 4 = 64 bytes) */
+      /* CGA-compatible colors: */
+      /* 0x00 = black */         put_dword(fp, 0x000000);
+      /* 0x01 = blue */          put_dword(fp, 0x000080);
+      /* 0x02 = green */         put_dword(fp, 0x008000);
+      /* 0x03 = cyan */          put_dword(fp, 0x008080);
+      /* 0x04 = red */           put_dword(fp, 0x800000);
+      /* 0x05 = magenta */       put_dword(fp, 0x800080);
+      /* 0x06 = brown */         put_dword(fp, 0x808000);
+      /* 0x07 = light gray */    put_dword(fp, 0xC0C0C0);
+      /* 0x08 = dark gray */     put_dword(fp, 0x808080);
+      /* 0x09 = bright blue */   put_dword(fp, 0x0000FF);
+      /* 0x0A = bright green */  put_dword(fp, 0x00FF00);
+      /* 0x0B = bright cyan */   put_dword(fp, 0x00FFFF);
+      /* 0x0C = bright red */    put_dword(fp, 0xFF0000);
+      /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF);
+      /* 0x0E = yellow */        put_dword(fp, 0xFFFF00);
+      /* 0x0F = white */         put_dword(fp, 0xFFFFFF);
+      /* pixel data bits */
+      b = 0;
+      for (i = m - 1; i >= 0; i--)
+      {  for (j = 0; j < ((n + 7) / 8) * 8; j++)
+         {  b <<= 4;
+            b |= (j < n ? map[i * n + j] & 15 : 0);
+            if (j & 1) put_byte(fp, b);
+         }
+      }
+      fflush(fp);
+      if (ferror(fp))
+      {  xprintf("rgr_write_bmp16: write error on `%s' - %s\n",
+            fname, strerror(errno));
+         ret = 1;
+      }
+fini: if (fp != NULL) fclose(fp);
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glprgr.h b/optional/glpk/glprgr.h
new file mode 100644
index 0000000..bc8e1ca
--- /dev/null
+++ b/optional/glpk/glprgr.h
@@ -0,0 +1,34 @@
+/* glprgr.h (raster graphics) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPRGR_H
+#define GLPRGR_H
+
+#define rgr_write_bmp16 _glp_rgr_write_bmp16
+int rgr_write_bmp16(const char *fname, int m, int n, const char map[]);
+/* write 16-color raster image in BMP file format */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glprng.h b/optional/glpk/glprng.h
new file mode 100644
index 0000000..aa20bf7
--- /dev/null
+++ b/optional/glpk/glprng.h
@@ -0,0 +1,68 @@
+/* glprng.h (pseudo-random number generator) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPRNG_H
+#define GLPRNG_H
+
+typedef struct RNG RNG;
+
+struct RNG
+{     /* Knuth's portable pseudo-random number generator */
+      int A[56];
+      /* pseudo-random values */
+      int *fptr;
+      /* the next A value to be exported */
+};
+
+#define rng_create_rand _glp_rng_create_rand
+RNG *rng_create_rand(void);
+/* create pseudo-random number generator */
+
+#define rng_init_rand _glp_rng_init_rand
+void rng_init_rand(RNG *rand, int seed);
+/* initialize pseudo-random number generator */
+
+#define rng_next_rand _glp_rng_next_rand
+int rng_next_rand(RNG *rand);
+/* obtain pseudo-random integer in the range [0, 2^31-1] */
+
+#define rng_unif_rand _glp_rng_unif_rand
+int rng_unif_rand(RNG *rand, int m);
+/* obtain pseudo-random integer in the range [0, m-1] */
+
+#define rng_delete_rand _glp_rng_delete_rand
+void rng_delete_rand(RNG *rand);
+/* delete pseudo-random number generator */
+
+#define rng_unif_01 _glp_rng_unif_01
+double rng_unif_01(RNG *rand);
+/* obtain pseudo-random number in the range [0, 1] */
+
+#define rng_uniform _glp_rng_uniform
+double rng_uniform(RNG *rand, double a, double b);
+/* obtain pseudo-random number in the range [a, b] */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glprng01.c b/optional/glpk/glprng01.c
new file mode 100644
index 0000000..2050b14
--- /dev/null
+++ b/optional/glpk/glprng01.c
@@ -0,0 +1,231 @@
+/* glprng01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is a modified version of the module GB_FLIP, a portable
+*  pseudo-random number generator. The original version of GB_FLIP is
+*  a part of The Stanford GraphBase developed by Donald E. Knuth (see
+*  http://www-cs-staff.stanford.edu/~knuth/sgb.html).
+*
+*  Note that all changes concern only external names, so this modified
+*  version produces exactly the same results as the original version.
+*
+*  Changes were made by Andrew Makhorin <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"
+#endif
+
+#include "glpenv.h"
+#include "glprng.h"
+
+#if 0
+int A[56] = { -1 };
+#else
+#define A (rand->A)
+#endif
+/* pseudo-random values */
+
+#if 0
+int *fptr = A;
+#else
+#define fptr (rand->fptr)
+#endif
+/* the next A value to be exported */
+
+#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF)
+/* difference modulo 2^31 */
+
+static int flip_cycle(RNG *rand)
+{     /* this is an auxiliary routine to do 55 more steps of the basic
+         recurrence, at high speed, and to reset fptr */
+      int *ii, *jj;
+      for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
+         *ii = mod_diff(*ii, *jj);
+      for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
+         *ii = mod_diff(*ii, *jj);
+      fptr = &A[54];
+      return A[55];
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_create_rand - create pseudo-random number generator
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  RNG *rng_create_rand(void);
+*
+*  DESCRIPTION
+*
+*  The routine rng_create_rand creates and initializes a pseudo-random
+*  number generator.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the generator created. */
+
+RNG *rng_create_rand(void)
+{     RNG *rand;
+      int i;
+      rand = xmalloc(sizeof(RNG));
+      A[0] = -1;
+      for (i = 1; i <= 55; i++) A[i] = 0;
+      fptr = A;
+      rng_init_rand(rand, 1);
+      return rand;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_init_rand - initialize pseudo-random number generator
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  void rng_init_rand(RNG *rand, int seed);
+*
+*  DESCRIPTION
+*
+*  The routine rng_init_rand initializes the pseudo-random number
+*  generator. The parameter seed may be any integer number. Note that
+*  on creating the generator this routine is called with the parameter
+*  seed equal to 1. */
+
+void rng_init_rand(RNG *rand, int seed)
+{     int i;
+      int prev = seed, next = 1;
+      seed = prev = mod_diff(prev, 0);
+      A[55] = prev;
+      for (i = 21; i; i = (i + 21) % 55)
+      {  A[i] = next;
+         next = mod_diff(prev, next);
+         if (seed & 1)
+            seed = 0x40000000 + (seed >> 1);
+         else
+            seed >>= 1;
+         next = mod_diff(next, seed);
+         prev = A[i];
+      }
+      flip_cycle(rand);
+      flip_cycle(rand);
+      flip_cycle(rand);
+      flip_cycle(rand);
+      flip_cycle(rand);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  int rng_next_rand(RNG *rand);
+*
+*  RETURNS
+*
+*  The routine rng_next_rand returns a next pseudo-random integer which
+*  is uniformly distributed between 0 and 2^31-1, inclusive. The period
+*  length of the generated numbers is 2^85 - 2^30. The low order bits of
+*  the generated numbers are just as random as the high-order bits. */
+
+int rng_next_rand(RNG *rand)
+{     return
+         *fptr >= 0 ? *fptr-- : flip_cycle(rand);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_unif_rand - obtain pseudo-random integer in the range [0, m-1]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  int rng_unif_rand(RNG *rand, int m);
+*
+*  RETURNS
+*
+*  The routine rng_unif_rand returns a next pseudo-random integer which
+*  is uniformly distributed between 0 and m-1, inclusive, where m is any
+*  positive integer less than 2^31. */
+
+#define two_to_the_31 ((unsigned int)0x80000000)
+
+int rng_unif_rand(RNG *rand, int m)
+{     unsigned int t = two_to_the_31 - (two_to_the_31 % m);
+      int r;
+      xassert(m > 0);
+      do { r = rng_next_rand(rand); } while (t <= (unsigned int)r);
+      return r % m;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_delete_rand - delete pseudo-random number generator
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  void rng_delete_rand(RNG *rand);
+*
+*  DESCRIPTION
+*
+*  The routine rng_delete_rand frees all the memory allocated to the
+*  specified pseudo-random number generator. */
+
+void rng_delete_rand(RNG *rand)
+{     xfree(rand);
+      return;
+}
+
+/**********************************************************************/
+
+#if 0
+/* To be sure that this modified version produces the same results as
+   the original version, run this validation program. */
+
+int main(void)
+{     RNG *rand;
+      int j;
+      rand = rng_create_rand();
+      rng_init_rand(rand, -314159);
+      if (rng_next_rand(rand) != 119318998)
+      {  fprintf(stderr, "Failure on the first try!\n");
+         return -1;
+      }
+      for (j = 1; j <= 133; j++) rng_next_rand(rand);
+      if (rng_unif_rand(rand, 0x55555555) != 748103812)
+      {  fprintf(stderr, "Failure on the second try!\n");
+         return -2;
+      }
+      fprintf(stderr, "OK, the random-number generator routines seem to"
+         " work!\n");
+      rng_delete_rand(rand);
+      return 0;
+}
+#endif
+
+/* eof */
diff --git a/optional/glpk/glprng02.c b/optional/glpk/glprng02.c
new file mode 100644
index 0000000..40f4a65
--- /dev/null
+++ b/optional/glpk/glprng02.c
@@ -0,0 +1,76 @@
+/* glprng02.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glprng.h"
+#define xfault xerror
+
+/***********************************************************************
+*  NAME
+*
+*  rng_unif_01 - obtain pseudo-random number in the range [0, 1]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  double rng_unif_01(RNG *rand);
+*
+*  RETURNS
+*
+*  The routine rng_unif_01 returns a next pseudo-random number which is
+*  uniformly distributed in the range [0, 1]. */
+
+double rng_unif_01(RNG *rand)
+{     double x;
+      x = (double)rng_next_rand(rand) / 2147483647.0;
+      xassert(0.0 <= x && x <= 1.0);
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_uniform - obtain pseudo-random number in the range [a, b]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  double rng_uniform(RNG *rand, double a, double b);
+*
+*  RETURNS
+*
+*  The routine rng_uniform returns a next pseudo-random number which is
+*  uniformly distributed in the range [a, b]. */
+
+double rng_uniform(RNG *rand, double a, double b)
+{     double x;
+      if (a >= b)
+         xfault("rng_uniform: a = %g, b = %g; invalid range\n", a, b);
+      x = rng_unif_01(rand);
+      x = a * (1.0 - x) + b * x;
+      xassert(a <= x && x <= b);
+      return x;
+}
+
+/* eof */
diff --git a/optional/glpk/glpscf.c b/optional/glpk/glpscf.c
new file mode 100644
index 0000000..7af1508
--- /dev/null
+++ b/optional/glpk/glpscf.c
@@ -0,0 +1,638 @@
+/* glpscf.c (Schur complement factorization) */
+
+/***********************************************************************
+*  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 "-Wself-assign"
+#endif
+
+#include "glpenv.h"
+#include "glpscf.h"
+#define xfault xerror
+
+#define _GLPSCF_DEBUG 0
+
+#define eps 1e-10
+
+/***********************************************************************
+*  NAME
+*
+*  scf_create_it - create Schur complement factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  SCF *scf_create_it(int n_max);
+*
+*  DESCRIPTION
+*
+*  The routine scf_create_it creates the factorization of matrix C,
+*  which initially has no rows and columns.
+*
+*  The parameter n_max specifies the maximal order of matrix C to be
+*  factorized, 1 <= n_max <= 32767.
+*
+*  RETURNS
+*
+*  The routine scf_create_it returns a pointer to the structure SCF,
+*  which defines the factorization. */
+
+SCF *scf_create_it(int n_max)
+{     SCF *scf;
+#if _GLPSCF_DEBUG
+      xprintf("scf_create_it: warning: debug mode enabled\n");
+#endif
+      if (!(1 <= n_max && n_max <= 32767))
+         xfault("scf_create_it: n_max = %d; invalid parameter\n",
+            n_max);
+      scf = xmalloc(sizeof(SCF));
+      scf->n_max = n_max;
+      scf->n = 0;
+      scf->f = xcalloc(1 + n_max * n_max, sizeof(double));
+      scf->u = xcalloc(1 + n_max * (n_max + 1) / 2, sizeof(double));
+      scf->p = xcalloc(1 + n_max, sizeof(int));
+      scf->t_opt = SCF_TBG;
+      scf->rank = 0;
+#if _GLPSCF_DEBUG
+      scf->c = xcalloc(1 + n_max * n_max, sizeof(double));
+#else
+      scf->c = NULL;
+#endif
+      scf->w = xcalloc(1 + n_max, sizeof(double));
+      return scf;
+}
+
+/***********************************************************************
+*  The routine f_loc determines location of matrix element F[i,j] in
+*  the one-dimensional array f. */
+
+static int f_loc(SCF *scf, int i, int j)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      xassert(1 <= i && i <= n);
+      xassert(1 <= j && j <= n);
+      return (i - 1) * n_max + j;
+}
+
+/***********************************************************************
+*  The routine u_loc determines location of matrix element U[i,j] in
+*  the one-dimensional array u. */
+
+static int u_loc(SCF *scf, int i, int j)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      xassert(1 <= i && i <= n);
+      xassert(i <= j && j <= n);
+      return (i - 1) * n_max + j - i * (i - 1) / 2;
+}
+
+/***********************************************************************
+*  The routine bg_transform applies Bartels-Golub version of gaussian
+*  elimination to restore triangular structure of matrix U.
+*
+*  On entry matrix U has the following structure:
+*
+*        1       k         n
+*     1  * * * * * * * * * *
+*        . * * * * * * * * *
+*        . . * * * * * * * *
+*        . . . * * * * * * *
+*     k  . . . . * * * * * *
+*        . . . . . * * * * *
+*        . . . . . . * * * *
+*        . . . . . . . * * *
+*        . . . . . . . . * *
+*     n  . . . . # # # # # #
+*
+*  where '#' is a row spike to be eliminated.
+*
+*  Elements of n-th row are passed separately in locations un[k], ...,
+*  un[n]. On exit the content of the array un is destroyed.
+*
+*  REFERENCES
+*
+*  R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
+*  Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
+
+static void bg_transform(SCF *scf, int k, double un[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int j, k1, kj, kk, n1, nj;
+      double t;
+      xassert(1 <= k && k <= n);
+      /* main elimination loop */
+      for (k = k; k < n; k++)
+      {  /* determine location of U[k,k] */
+         kk = u_loc(scf, k, k);
+         /* determine location of F[k,1] */
+         k1 = f_loc(scf, k, 1);
+         /* determine location of F[n,1] */
+         n1 = f_loc(scf, n, 1);
+         /* if |U[k,k]| < |U[n,k]|, interchange k-th and n-th rows to
+            provide |U[k,k]| >= |U[n,k]| */
+         if (fabs(u[kk]) < fabs(un[k]))
+         {  /* interchange k-th and n-th rows of matrix U */
+            for (j = k, kj = kk; j <= n; j++, kj++)
+               t = u[kj], u[kj] = un[j], un[j] = t;
+            /* interchange k-th and n-th rows of matrix F to keep the
+               main equality F * C = U * P */
+            for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
+               t = f[kj], f[kj] = f[nj], f[nj] = t;
+         }
+         /* now |U[k,k]| >= |U[n,k]| */
+         /* if U[k,k] is too small in the magnitude, replace U[k,k] and
+            U[n,k] by exact zero */
+         if (fabs(u[kk]) < eps) u[kk] = un[k] = 0.0;
+         /* if U[n,k] is already zero, elimination is not needed */
+         if (un[k] == 0.0) continue;
+         /* compute gaussian multiplier t = U[n,k] / U[k,k] */
+         t = un[k] / u[kk];
+         /* apply gaussian elimination to nullify U[n,k] */
+         /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */
+         for (j = k+1, kj = kk+1; j <= n; j++, kj++)
+            un[j] -= t * u[kj];
+         /* (n-th row of F) := (n-th row of F) - t * (k-th row of F)
+            to keep the main equality F * C = U * P */
+         for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
+            f[nj] -= t * f[kj];
+      }
+      /* if U[n,n] is too small in the magnitude, replace it by exact
+         zero */
+      if (fabs(un[n]) < eps) un[n] = 0.0;
+      /* store U[n,n] in a proper location */
+      u[u_loc(scf, n, n)] = un[n];
+      return;
+}
+
+/***********************************************************************
+*  The routine givens computes the parameters of Givens plane rotation
+*  c = cos(teta) and s = sin(teta) such that:
+*
+*     ( c -s ) ( a )   ( r )
+*     (      ) (   ) = (   ) ,
+*     ( s  c ) ( b )   ( 0 )
+*
+*  where a and b are given scalars.
+*
+*  REFERENCES
+*
+*  G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */
+
+static void givens(double a, double b, double *c, double *s)
+{     double t;
+      if (b == 0.0)
+         (*c) = 1.0, (*s) = 0.0;
+      else if (fabs(a) <= fabs(b))
+         t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t;
+      else
+         t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t;
+      return;
+}
+
+/*----------------------------------------------------------------------
+*  The routine gr_transform applies Givens plane rotations to restore
+*  triangular structure of matrix U.
+*
+*  On entry matrix U has the following structure:
+*
+*        1       k         n
+*     1  * * * * * * * * * *
+*        . * * * * * * * * *
+*        . . * * * * * * * *
+*        . . . * * * * * * *
+*     k  . . . . * * * * * *
+*        . . . . . * * * * *
+*        . . . . . . * * * *
+*        . . . . . . . * * *
+*        . . . . . . . . * *
+*     n  . . . . # # # # # #
+*
+*  where '#' is a row spike to be eliminated.
+*
+*  Elements of n-th row are passed separately in locations un[k], ...,
+*  un[n]. On exit the content of the array un is destroyed.
+*
+*  REFERENCES
+*
+*  R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
+*  Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
+
+static void gr_transform(SCF *scf, int k, double un[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int j, k1, kj, kk, n1, nj;
+      double c, s;
+      xassert(1 <= k && k <= n);
+      /* main elimination loop */
+      for (k = k; k < n; k++)
+      {  /* determine location of U[k,k] */
+         kk = u_loc(scf, k, k);
+         /* determine location of F[k,1] */
+         k1 = f_loc(scf, k, 1);
+         /* determine location of F[n,1] */
+         n1 = f_loc(scf, n, 1);
+         /* if both U[k,k] and U[n,k] are too small in the magnitude,
+            replace them by exact zero */
+         if (fabs(u[kk]) < eps && fabs(un[k]) < eps)
+            u[kk] = un[k] = 0.0;
+         /* if U[n,k] is already zero, elimination is not needed */
+         if (un[k] == 0.0) continue;
+         /* compute the parameters of Givens plane rotation */
+         givens(u[kk], un[k], &c, &s);
+         /* apply Givens rotation to k-th and n-th rows of matrix U */
+         for (j = k, kj = kk; j <= n; j++, kj++)
+         {  double ukj = u[kj], unj = un[j];
+            u[kj] = c * ukj - s * unj;
+            un[j] = s * ukj + c * unj;
+         }
+         /* apply Givens rotation to k-th and n-th rows of matrix F
+            to keep the main equality F * C = U * P */
+         for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
+         {  double fkj = f[kj], fnj = f[nj];
+            f[kj] = c * fkj - s * fnj;
+            f[nj] = s * fkj + c * fnj;
+         }
+      }
+      /* if U[n,n] is too small in the magnitude, replace it by exact
+         zero */
+      if (fabs(un[n]) < eps) un[n] = 0.0;
+      /* store U[n,n] in a proper location */
+      u[u_loc(scf, n, n)] = un[n];
+      return;
+}
+
+/***********************************************************************
+*  The routine transform restores triangular structure of matrix U.
+*  It is a driver to the routines bg_transform and gr_transform (see
+*  comments to these routines above). */
+
+static void transform(SCF *scf, int k, double un[])
+{     switch (scf->t_opt)
+      {  case SCF_TBG:
+            bg_transform(scf, k, un);
+            break;
+         case SCF_TGR:
+            gr_transform(scf, k, un);
+            break;
+         default:
+            xassert(scf != scf);
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine estimate_rank estimates the rank of matrix C.
+*
+*  Since all transformations applied to matrix F are non-singular,
+*  and F is assumed to be well conditioned, from the main equaility
+*  F * C = U * P it follows that rank(C) = rank(U), where rank(U) is
+*  estimated as the number of non-zero diagonal elements of U. */
+
+static int estimate_rank(SCF *scf)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      double *u = scf->u;
+      int i, ii, inc, rank = 0;
+      for (i = 1, ii = u_loc(scf, i, i), inc = n_max; i <= n;
+         i++, ii += inc, inc--)
+         if (u[ii] != 0.0) rank++;
+      return rank;
+}
+
+#if _GLPSCF_DEBUG
+/***********************************************************************
+*  The routine check_error computes the maximal relative error between
+*  left- and right-hand sides of the main equality F * C = U * P. (This
+*  routine is intended only for debugging.) */
+
+static void check_error(SCF *scf, const char *func)
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+      double *c = scf->c;
+      int i, j, k;
+      double d, dmax = 0.0, s, t;
+      xassert(c != NULL);
+      for (i = 1; i <= n; i++)
+      {  for (j = 1; j <= n; j++)
+         {  /* compute element (i,j) of product F * C */
+            s = 0.0;
+            for (k = 1; k <= n; k++)
+               s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)];
+            /* compute element (i,j) of product U * P */
+            k = p[j];
+            t = (i <= k ? u[u_loc(scf, i, k)] : 0.0);
+            /* compute the maximal relative error */
+            d = fabs(s - t) / (1.0 + fabs(t));
+            if (dmax < d) dmax = d;
+         }
+      }
+      if (dmax > 1e-8)
+         xprintf("%s: dmax = %g; relative error too large\n", func,
+            dmax);
+      return;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  scf_update_exp - update factorization on expanding C
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  int scf_update_exp(SCF *scf, const double x[], const double y[],
+*     double z);
+*
+*  DESCRIPTION
+*
+*  The routine scf_update_exp updates the factorization of matrix C on
+*  expanding it by adding a new row and column as follows:
+*
+*             ( C  x )
+*     new C = (      )
+*             ( y' z )
+*
+*  where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is
+*  a new diagonal element.
+*
+*  If on entry the factorization is empty, the parameters x and y can
+*  be specified as NULL.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  SCF_ESING
+*     The factorization has been successfully updated, however, new
+*     matrix C is singular within working precision. Note that the new
+*     factorization remains valid.
+*
+*  SCF_ELIMIT
+*     There is not enough room to expand the factorization, because
+*     n = n_max. The factorization remains unchanged.
+*
+*  ALGORITHM
+*
+*  We can see that:
+*
+*     ( F  0 ) ( C  x )   ( FC  Fx )   ( UP  Fx )
+*     (      ) (      ) = (        ) = (        ) =
+*     ( 0  1 ) ( y' z )   ( y'   z )   ( y'   z )
+*
+*        ( U   Fx ) ( P  0 )
+*     =  (        ) (      ),
+*        ( y'P' z ) ( 0  1 )
+*
+*  therefore to keep the main equality F * C = U * P we can take:
+*
+*             ( F  0 )           ( U   Fx )           ( P  0 )
+*     new F = (      ),  new U = (        ),  new P = (      ),
+*             ( 0  1 )           ( y'P' z )           ( 0  1 )
+*
+*  and eliminate the row spike y'P' in the last row of new U to restore
+*  its upper triangular structure. */
+
+int scf_update_exp(SCF *scf, const double x[], const double y[],
+      double z)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+#if _GLPSCF_DEBUG
+      double *c = scf->c;
+#endif
+      double *un = scf->w;
+      int i, ij, in, j, k, nj, ret = 0;
+      double t;
+      /* check if the factorization can be expanded */
+      if (n == n_max)
+      {  /* there is not enough room */
+         ret = SCF_ELIMIT;
+         goto done;
+      }
+      /* increase the order of the factorization */
+      scf->n = ++n;
+      /* fill new zero column of matrix F */
+      for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
+         f[in] = 0.0;
+      /* fill new zero row of matrix F */
+      for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
+         f[nj] = 0.0;
+      /* fill new unity diagonal element of matrix F */
+      f[f_loc(scf, n, n)] = 1.0;
+      /* compute new column of matrix U, which is (old F) * x */
+      for (i = 1; i < n; i++)
+      {  /* u[i,n] := (i-th row of old F) * x */
+         t = 0.0;
+         for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++)
+            t += f[ij] * x[j];
+         u[u_loc(scf, i, n)] = t;
+      }
+      /* compute new (spiked) row of matrix U, which is (old P) * y */
+      for (j = 1; j < n; j++) un[j] = y[p[j]];
+      /* store new diagonal element of matrix U, which is z */
+      un[n] = z;
+      /* expand matrix P */
+      p[n] = n;
+#if _GLPSCF_DEBUG
+      /* expand matrix C */
+      /* fill its new column, which is x */
+      for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
+         c[in] = x[i];
+      /* fill its new row, which is y */
+      for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
+         c[nj] = y[j];
+      /* fill its new diagonal element, which is z */
+      c[f_loc(scf, n, n)] = z;
+#endif
+      /* restore upper triangular structure of matrix U */
+      for (k = 1; k < n; k++)
+         if (un[k] != 0.0) break;
+      transform(scf, k, un);
+      /* estimate the rank of matrices C and U */
+      scf->rank = estimate_rank(scf);
+      if (scf->rank != n) ret = SCF_ESING;
+#if _GLPSCF_DEBUG
+      /* check that the factorization is accurate enough */
+      check_error(scf, "scf_update_exp");
+#endif
+done: return ret;
+}
+
+/***********************************************************************
+*  The routine solve solves the system C * x = b.
+*
+*  From the main equation F * C = U * P it follows that:
+*
+*     C * x = b  =>  F * C * x = F * b  =>  U * P * x = F * b  =>
+*
+*     P * x = inv(U) * F * b  =>  x = P' * inv(U) * F * b.
+*
+*  On entry the array x contains right-hand side vector b. On exit this
+*  array contains solution vector x. */
+
+static void solve(SCF *scf, double x[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+      double *y = scf->w;
+      int i, j, ij;
+      double t;
+      /* y := F * b */
+      for (i = 1; i <= n; i++)
+      {  /* y[i] = (i-th row of F) * b */
+         t = 0.0;
+         for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
+            t += f[ij] * x[j];
+         y[i] = t;
+      }
+      /* y := inv(U) * y */
+      for (i = n; i >= 1; i--)
+      {  t = y[i];
+         for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--)
+            t -= u[ij] * y[j];
+         y[i] = t / u[ij];
+      }
+      /* x := P' * y */
+      for (i = 1; i <= n; i++) x[p[i]] = y[i];
+      return;
+}
+
+/***********************************************************************
+*  The routine tsolve solves the transposed system C' * x = b.
+*
+*  From the main equation F * C = U * P it follows that:
+*
+*     C' * F' = P' * U',
+*
+*  therefore:
+*
+*     C' * x = b  =>  C' * F' * inv(F') * x = b  =>
+*
+*     P' * U' * inv(F') * x = b  =>  U' * inv(F') * x = P * b  =>
+*
+*     inv(F') * x = inv(U') * P * b  =>  x = F' * inv(U') * P * b.
+*
+*  On entry the array x contains right-hand side vector b. On exit this
+*  array contains solution vector x. */
+
+static void tsolve(SCF *scf, double x[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+      double *y = scf->w;
+      int i, j, ij;
+      double t;
+      /* y := P * b */
+      for (i = 1; i <= n; i++) y[i] = x[p[i]];
+      /* y := inv(U') * y */
+      for (i = 1; i <= n; i++)
+      {  /* compute y[i] */
+         ij = u_loc(scf, i, i);
+         t = (y[i] /= u[ij]);
+         /* substitute y[i] in other equations */
+         for (j = i+1, ij++; j <= n; j++, ij++)
+            y[j] -= u[ij] * t;
+      }
+      /* x := F' * y (computed as linear combination of rows of F) */
+      for (j = 1; j <= n; j++) x[j] = 0.0;
+      for (i = 1; i <= n; i++)
+      {  t = y[i]; /* coefficient of linear combination */
+         for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
+            x[j] += f[ij] * t;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  scf_solve_it - solve either system C * x = b or C' * x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  void scf_solve_it(SCF *scf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine scf_solve_it solves either the system C * x = b (if tr
+*  is zero) or the system C' * x = b, where C' is a matrix transposed
+*  to C (if tr is non-zero). C is assumed to be non-singular.
+*
+*  On entry the array x should contain the right-hand side vector b in
+*  locations x[1], ..., x[n], where n is the order of matrix C. On exit
+*  the array x contains the solution vector x in the same locations. */
+
+void scf_solve_it(SCF *scf, int tr, double x[])
+{     if (scf->rank < scf->n)
+         xfault("scf_solve_it: singular matrix\n");
+      if (!tr)
+         solve(scf, x);
+      else
+         tsolve(scf, x);
+      return;
+}
+
+void scf_reset_it(SCF *scf)
+{     /* reset factorization for empty matrix C */
+      scf->n = scf->rank = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  scf_delete_it - delete Schur complement factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  void scf_delete_it(SCF *scf);
+*
+*  DESCRIPTION
+*
+*  The routine scf_delete_it deletes the specified factorization and
+*  frees all the memory allocated to this object. */
+
+void scf_delete_it(SCF *scf)
+{     xfree(scf->f);
+      xfree(scf->u);
+      xfree(scf->p);
+#if _GLPSCF_DEBUG
+      xfree(scf->c);
+#endif
+      xfree(scf->w);
+      xfree(scf);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpscf.h b/optional/glpk/glpscf.h
new file mode 100644
index 0000000..1453b31
--- /dev/null
+++ b/optional/glpk/glpscf.h
@@ -0,0 +1,126 @@
+/* glpscf.h (Schur complement factorization) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPSCF_H
+#define GLPSCF_H
+
+/***********************************************************************
+*  The structure SCF defines the following factorization of a square
+*  nxn matrix C (which is the Schur complement):
+*
+*     F * C = U * P,
+*
+*  where F is a square transforming matrix, U is an upper triangular
+*  matrix, P is a permutation matrix.
+*
+*  It is assumed that matrix C is small and dense, so matrices F and U
+*  are stored in the dense format by rows as follows:
+*
+*        1         n       n_max    1         n       n_max
+*      1 * * * * * * x x x x      1 * * * * * * x x x x
+*        * * * * * * x x x x        . * * * * * x x x x
+*        * * * * * * x x x x        . . * * * * x x x x
+*        * * * * * * x x x x        . . . * * * x x x x
+*        * * * * * * x x x x        . . . . * * x x x x
+*      n * * * * * * x x x x      n . . . . . * x x x x
+*        x x x x x x x x x x        . . . . . . x x x x
+*        x x x x x x x x x x        . . . . . . . x x x
+*        x x x x x x x x x x        . . . . . . . . x x
+*  n_max x x x x x x x x x x  n_max . . . . . . . . . x
+*
+*             matrix F                   matrix U
+*
+*  where '*' are matrix elements, 'x' are reserved locations.
+*
+*  Permutation matrix P is stored in row-like format.
+*
+*  Matrix C normally is not stored.
+*
+*  REFERENCES
+*
+*  1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
+*     tion," SCCM, Stanford University, 2006.
+*
+*  2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
+*     sity, Spring 2006.
+*
+*  3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
+*     ibid. */
+
+typedef struct SCF SCF;
+
+struct SCF
+{     /* Schur complement factorization */
+      int n_max;
+      /* maximal order of matrices C, F, U, P; n_max >= 1 */
+      int n;
+      /* current order of matrices C, F, U, P; n >= 0 */
+      double *f; /* double f[1+n_max*n_max]; */
+      /* matrix F stored by rows */
+      double *u; /* double u[1+n_max*(n_max+1)/2]; */
+      /* upper triangle of matrix U stored by rows */
+      int *p; /* int p[1+n_max]; */
+      /* matrix P; p[i] = j means that P[i,j] = 1 */
+      int t_opt;
+      /* type of transformation used to restore triangular structure of
+         matrix U: */
+#define SCF_TBG      1  /* Bartels-Golub elimination */
+#define SCF_TGR      2  /* Givens plane rotation */
+      int rank;
+      /* estimated rank of matrices C and U */
+      double *c; /* double c[1+n_max*n_max]; */
+      /* matrix C stored in the same format as matrix F and used only
+         for debugging; normally this array is not allocated */
+      double *w; /* double w[1+n_max]; */
+      /* working array */
+};
+
+/* return codes: */
+#define SCF_ESING    1  /* singular matrix */
+#define SCF_ELIMIT   2  /* update limit reached */
+
+#define scf_create_it _glp_scf_create_it
+SCF *scf_create_it(int n_max);
+/* create Schur complement factorization */
+
+#define scf_update_exp _glp_scf_update_exp
+int scf_update_exp(SCF *scf, const double x[], const double y[],
+      double z);
+/* update factorization on expanding C */
+
+#define scf_solve_it _glp_scf_solve_it
+void scf_solve_it(SCF *scf, int tr, double x[]);
+/* solve either system C * x = b or C' * x = b */
+
+#define scf_reset_it _glp_scf_reset_it
+void scf_reset_it(SCF *scf);
+/* reset factorization for empty matrix C */
+
+#define scf_delete_it _glp_scf_delete_it
+void scf_delete_it(SCF *scf);
+/* delete Schur complement factorization */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpscl.c b/optional/glpk/glpscl.c
new file mode 100644
index 0000000..05ce55b
--- /dev/null
+++ b/optional/glpk/glpscl.c
@@ -0,0 +1,476 @@
+/* glpscl.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  min_row_aij - determine minimal |a[i,j]| in i-th row
+*
+*  This routine returns minimal magnitude of (non-zero) constraint
+*  coefficients in i-th row of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If i-th row of the matrix is empty, the routine returns 1. */
+
+static double min_row_aij(glp_prob *lp, int i, int scaled)
+{     GLPAIJ *aij;
+      double min_aij, temp;
+      xassert(1 <= i && i <= lp->m);
+      min_aij = 1.0;
+      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->r_prev == NULL || min_aij > temp)
+            min_aij = temp;
+      }
+      return min_aij;
+}
+
+/***********************************************************************
+*  max_row_aij - determine maximal |a[i,j]| in i-th row
+*
+*  This routine returns maximal magnitude of (non-zero) constraint
+*  coefficients in i-th row of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If i-th row of the matrix is empty, the routine returns 1. */
+
+static double max_row_aij(glp_prob *lp, int i, int scaled)
+{     GLPAIJ *aij;
+      double max_aij, temp;
+      xassert(1 <= i && i <= lp->m);
+      max_aij = 1.0;
+      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->r_prev == NULL || max_aij < temp)
+            max_aij = temp;
+      }
+      return max_aij;
+}
+
+/***********************************************************************
+*  min_col_aij - determine minimal |a[i,j]| in j-th column
+*
+*  This routine returns minimal magnitude of (non-zero) constraint
+*  coefficients in j-th column of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If j-th column of the matrix is empty, the routine returns 1. */
+
+static double min_col_aij(glp_prob *lp, int j, int scaled)
+{     GLPAIJ *aij;
+      double min_aij, temp;
+      xassert(1 <= j && j <= lp->n);
+      min_aij = 1.0;
+      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->c_prev == NULL || min_aij > temp)
+            min_aij = temp;
+      }
+      return min_aij;
+}
+
+/***********************************************************************
+*  max_col_aij - determine maximal |a[i,j]| in j-th column
+*
+*  This routine returns maximal magnitude of (non-zero) constraint
+*  coefficients in j-th column of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If j-th column of the matrix is empty, the routine returns 1. */
+
+static double max_col_aij(glp_prob *lp, int j, int scaled)
+{     GLPAIJ *aij;
+      double max_aij, temp;
+      xassert(1 <= j && j <= lp->n);
+      max_aij = 1.0;
+      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->c_prev == NULL || max_aij < temp)
+            max_aij = temp;
+      }
+      return max_aij;
+}
+
+/***********************************************************************
+*  min_mat_aij - determine minimal |a[i,j]| in constraint matrix
+*
+*  This routine returns minimal magnitude of (non-zero) constraint
+*  coefficients in the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If the matrix is empty, the routine returns 1. */
+
+static double min_mat_aij(glp_prob *lp, int scaled)
+{     int i;
+      double min_aij, temp;
+      min_aij = 1.0;
+      for (i = 1; i <= lp->m; i++)
+      {  temp = min_row_aij(lp, i, scaled);
+         if (i == 1 || min_aij > temp)
+            min_aij = temp;
+      }
+      return min_aij;
+}
+
+/***********************************************************************
+*  max_mat_aij - determine maximal |a[i,j]| in constraint matrix
+*
+*  This routine returns maximal magnitude of (non-zero) constraint
+*  coefficients in the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If the matrix is empty, the routine returns 1. */
+
+static double max_mat_aij(glp_prob *lp, int scaled)
+{     int i;
+      double max_aij, temp;
+      max_aij = 1.0;
+      for (i = 1; i <= lp->m; i++)
+      {  temp = max_row_aij(lp, i, scaled);
+         if (i == 1 || max_aij < temp)
+            max_aij = temp;
+      }
+      return max_aij;
+}
+
+/***********************************************************************
+*  eq_scaling - perform equilibration scaling
+*
+*  This routine performs equilibration scaling of rows and columns of
+*  the constraint matrix.
+*
+*  If the parameter flag is zero, the routine scales rows at first and
+*  then columns. Otherwise, the routine scales columns and then rows.
+*
+*  Rows are scaled as follows:
+*
+*                         n
+*     a'[i,j] = a[i,j] / max |a[i,j]|,  i = 1,...,m.
+*                        j=1
+*
+*  This makes the infinity (maximum) norm of each row of the matrix
+*  equal to 1.
+*
+*  Columns are scaled as follows:
+*
+*                         n
+*     a'[i,j] = a[i,j] / max |a[i,j]|,  j = 1,...,n.
+*                        i=1
+*
+*  This makes the infinity (maximum) norm of each column of the matrix
+*  equal to 1. */
+
+static void eq_scaling(glp_prob *lp, int flag)
+{     int i, j, pass;
+      double temp;
+      xassert(flag == 0 || flag == 1);
+      for (pass = 0; pass <= 1; pass++)
+      {  if (pass == flag)
+         {  /* scale rows */
+            for (i = 1; i <= lp->m; i++)
+            {  temp = max_row_aij(lp, i, 1);
+               glp_set_rii(lp, i, glp_get_rii(lp, i) / temp);
+            }
+         }
+         else
+         {  /* scale columns */
+            for (j = 1; j <= lp->n; j++)
+            {  temp = max_col_aij(lp, j, 1);
+               glp_set_sjj(lp, j, glp_get_sjj(lp, j) / temp);
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  gm_scaling - perform geometric mean scaling
+*
+*  This routine performs geometric mean scaling of rows and columns of
+*  the constraint matrix.
+*
+*  If the parameter flag is zero, the routine scales rows at first and
+*  then columns. Otherwise, the routine scales columns and then rows.
+*
+*  Rows are scaled as follows:
+*
+*     a'[i,j] = a[i,j] / sqrt(alfa[i] * beta[i]),  i = 1,...,m,
+*
+*  where:
+*                n                        n
+*     alfa[i] = min |a[i,j]|,  beta[i] = max |a[i,j]|.
+*               j=1                      j=1
+*
+*  This allows decreasing the ratio beta[i] / alfa[i] for each row of
+*  the matrix.
+*
+*  Columns are scaled as follows:
+*
+*     a'[i,j] = a[i,j] / sqrt(alfa[j] * beta[j]),  j = 1,...,n,
+*
+*  where:
+*                m                        m
+*     alfa[j] = min |a[i,j]|,  beta[j] = max |a[i,j]|.
+*               i=1                      i=1
+*
+*  This allows decreasing the ratio beta[j] / alfa[j] for each column
+*  of the matrix. */
+
+static void gm_scaling(glp_prob *lp, int flag)
+{     int i, j, pass;
+      double temp;
+      xassert(flag == 0 || flag == 1);
+      for (pass = 0; pass <= 1; pass++)
+      {  if (pass == flag)
+         {  /* scale rows */
+            for (i = 1; i <= lp->m; i++)
+            {  temp = min_row_aij(lp, i, 1) * max_row_aij(lp, i, 1);
+               glp_set_rii(lp, i, glp_get_rii(lp, i) / sqrt(temp));
+            }
+         }
+         else
+         {  /* scale columns */
+            for (j = 1; j <= lp->n; j++)
+            {  temp = min_col_aij(lp, j, 1) * max_col_aij(lp, j, 1);
+               glp_set_sjj(lp, j, glp_get_sjj(lp, j) / sqrt(temp));
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  max_row_ratio - determine worst scaling "quality" for rows
+*
+*  This routine returns the worst scaling "quality" for rows of the
+*  currently scaled constraint matrix:
+*
+*              m
+*     ratio = max ratio[i],
+*             i=1
+*  where:
+*                 n              n
+*     ratio[i] = max |a[i,j]| / min |a[i,j]|,  1 <= i <= m,
+*                j=1            j=1
+*
+*  is the scaling "quality" of i-th row. */
+
+static double max_row_ratio(glp_prob *lp)
+{     int i;
+      double ratio, temp;
+      ratio = 1.0;
+      for (i = 1; i <= lp->m; i++)
+      {  temp = max_row_aij(lp, i, 1) / min_row_aij(lp, i, 1);
+         if (i == 1 || ratio < temp) ratio = temp;
+      }
+      return ratio;
+}
+
+/***********************************************************************
+*  max_col_ratio - determine worst scaling "quality" for columns
+*
+*  This routine returns the worst scaling "quality" for columns of the
+*  currently scaled constraint matrix:
+*
+*              n
+*     ratio = max ratio[j],
+*             j=1
+*  where:
+*                 m              m
+*     ratio[j] = max |a[i,j]| / min |a[i,j]|,  1 <= j <= n,
+*                i=1            i=1
+*
+*  is the scaling "quality" of j-th column. */
+
+static double max_col_ratio(glp_prob *lp)
+{     int j;
+      double ratio, temp;
+      ratio = 1.0;
+      for (j = 1; j <= lp->n; j++)
+      {  temp = max_col_aij(lp, j, 1) / min_col_aij(lp, j, 1);
+         if (j == 1 || ratio < temp) ratio = temp;
+      }
+      return ratio;
+}
+
+/***********************************************************************
+*  gm_iterate - perform iterative geometric mean scaling
+*
+*  This routine performs iterative geometric mean scaling of rows and
+*  columns of the constraint matrix.
+*
+*  The parameter it_max specifies the maximal number of iterations.
+*  Recommended value of it_max is 15.
+*
+*  The parameter tau specifies a minimal improvement of the scaling
+*  "quality" on each iteration, 0 < tau < 1. It means than the scaling
+*  process continues while the following condition is satisfied:
+*
+*     ratio[k] <= tau * ratio[k-1],
+*
+*  where ratio = max |a[i,j]| / min |a[i,j]| is the scaling "quality"
+*  to be minimized, k is the iteration number. Recommended value of tau
+*  is 0.90. */
+
+static void gm_iterate(glp_prob *lp, int it_max, double tau)
+{     int k, flag;
+      double ratio = 0.0, r_old;
+      /* if the scaling "quality" for rows is better than for columns,
+         the rows are scaled first; otherwise, the columns are scaled
+         first */
+      flag = (max_row_ratio(lp) > max_col_ratio(lp));
+      for (k = 1; k <= it_max; k++)
+      {  /* save the scaling "quality" from previous iteration */
+         r_old = ratio;
+         /* determine the current scaling "quality" */
+         ratio = max_mat_aij(lp, 1) / min_mat_aij(lp, 1);
+#if 0
+         xprintf("k = %d; ratio = %g\n", k, ratio);
+#endif
+         /* if improvement is not enough, terminate scaling */
+         if (k > 1 && ratio > tau * r_old) break;
+         /* otherwise, perform another iteration */
+         gm_scaling(lp, flag);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  scale_prob - scale problem data
+*
+*  SYNOPSIS
+*
+*  #include "glpscl.h"
+*  void scale_prob(glp_prob *lp, int flags);
+*
+*  DESCRIPTION
+*
+*  The routine scale_prob performs automatic scaling of problem data
+*  for the specified problem object. */
+
+static void scale_prob(glp_prob *lp, int flags)
+{     static const char *fmt =
+         "%s: min|aij| = %10.3e  max|aij| = %10.3e  ratio = %10.3e\n";
+      double min_aij, max_aij, ratio;
+      xprintf("Scaling...\n");
+      /* cancel the current scaling effect */
+      glp_unscale_prob(lp);
+      /* report original scaling "quality" */
+      min_aij = min_mat_aij(lp, 1);
+      max_aij = max_mat_aij(lp, 1);
+      ratio = max_aij / min_aij;
+      xprintf(fmt, " A", min_aij, max_aij, ratio);
+      /* check if the problem is well scaled */
+      if (min_aij >= 0.10 && max_aij <= 10.0)
+      {  xprintf("Problem data seem to be well scaled\n");
+         /* skip scaling, if required */
+         if (flags & GLP_SF_SKIP) goto done;
+      }
+      /* perform iterative geometric mean scaling, if required */
+      if (flags & GLP_SF_GM)
+      {  gm_iterate(lp, 15, 0.90);
+         min_aij = min_mat_aij(lp, 1);
+         max_aij = max_mat_aij(lp, 1);
+         ratio = max_aij / min_aij;
+         xprintf(fmt, "GM", min_aij, max_aij, ratio);
+      }
+      /* perform equilibration scaling, if required */
+      if (flags & GLP_SF_EQ)
+      {  eq_scaling(lp, max_row_ratio(lp) > max_col_ratio(lp));
+         min_aij = min_mat_aij(lp, 1);
+         max_aij = max_mat_aij(lp, 1);
+         ratio = max_aij / min_aij;
+         xprintf(fmt, "EQ", min_aij, max_aij, ratio);
+      }
+      /* round scale factors to nearest power of two, if required */
+      if (flags & GLP_SF_2N)
+      {  int i, j;
+         for (i = 1; i <= lp->m; i++)
+            glp_set_rii(lp, i, round2n(glp_get_rii(lp, i)));
+         for (j = 1; j <= lp->n; j++)
+            glp_set_sjj(lp, j, round2n(glp_get_sjj(lp, j)));
+         min_aij = min_mat_aij(lp, 1);
+         max_aij = max_mat_aij(lp, 1);
+         ratio = max_aij / min_aij;
+         xprintf(fmt, "2N", min_aij, max_aij, ratio);
+      }
+done: return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_scale_prob - scale problem data
+*
+*  SYNOPSIS
+*
+*  void glp_scale_prob(glp_prob *lp, int flags);
+*
+*  DESCRIPTION
+*
+*  The routine glp_scale_prob performs automatic scaling of problem
+*  data for the specified problem object.
+*
+*  The parameter flags specifies scaling options used by the routine.
+*  Options can be combined with the bitwise OR operator and may be the
+*  following:
+*
+*  GLP_SF_GM      perform geometric mean scaling;
+*  GLP_SF_EQ      perform equilibration scaling;
+*  GLP_SF_2N      round scale factors to nearest power of two;
+*  GLP_SF_SKIP    skip scaling, if the problem is well scaled.
+*
+*  The parameter flags may be specified as GLP_SF_AUTO, in which case
+*  the routine chooses scaling options automatically. */
+
+void glp_scale_prob(glp_prob *lp, int flags)
+{     if (flags & ~(GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP |
+                    GLP_SF_AUTO))
+         xerror("glp_scale_prob: flags = 0x%02X; invalid scaling option"
+            "s\n", flags);
+      if (flags & GLP_SF_AUTO)
+         flags = (GLP_SF_GM | GLP_SF_EQ | GLP_SF_SKIP);
+      scale_prob(lp, flags);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpsdf.c b/optional/glpk/glpsdf.c
new file mode 100644
index 0000000..4412656
--- /dev/null
+++ b/optional/glpk/glpsdf.c
@@ -0,0 +1,266 @@
+/* glpsdf.c (plain data file reading routines) */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#endif
+
+#define GLPSDF_H
+
+#define GLP_DATA_DEFINED
+typedef struct glp_data glp_data;
+
+#include "glpapi.h"
+
+struct glp_data
+{     /* plain data file */
+      char *fname;
+      /* name of data file */
+      XFILE *fp;
+      /* stream assigned to data file */
+      void *jump; /* jmp_buf jump; */
+      /* label for go to in case of error */
+      int count;
+      /* line count */
+      int c;
+      /* current character of XEOF */
+      char item[255+1];
+      /* current data item */
+};
+
+static void next_char(glp_data *data);
+
+glp_data *glp_sdf_open_file(const char *fname)
+{     /* open plain data file */
+      glp_data *data = NULL;
+      XFILE *fp;
+      jmp_buf jump;
+      fp = xfopen(fname, "r");
+      if (fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         goto done;
+      }
+      data = xmalloc(sizeof(glp_data));
+      data->fname = xmalloc(strlen(fname)+1);
+      strcpy(data->fname, fname);
+      data->fp = fp;
+      data->jump = NULL;
+      data->count = 0;
+      data->c = '\n';
+      data->item[0] = '\0';
+      /* read the very first character */
+      if (setjmp(jump))
+      {  glp_sdf_close_file(data);
+         data = NULL;
+         goto done;
+      }
+      data->jump = jump;
+      next_char(data);
+      data->jump = NULL;
+done: return data;
+}
+
+void glp_sdf_set_jump(glp_data *data, void *jump)
+{     /* set up error handling */
+      data->jump = jump;
+      return;
+}
+
+void glp_sdf_error(glp_data *data, const char *fmt, ...)
+{     /* print error message */
+      va_list arg;
+      xprintf("%s:%d: ", data->fname, data->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      if (data->jump == NULL)
+         xerror("");
+      else
+         longjmp(data->jump, 1);
+      /* no return */
+}
+
+void glp_sdf_warning(glp_data *data, const char *fmt, ...)
+{     /* print warning message */
+      va_list arg;
+      xprintf("%s:%d: warning: ", data->fname, data->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+static void next_char(glp_data *data)
+{     /* read next character */
+      int c;
+      if (data->c == XEOF)
+         glp_sdf_error(data, "unexpected end of file\n");
+      else if (data->c == '\n')
+         data->count++;
+      c = xfgetc(data->fp);
+      if (c < 0)
+      {  if (xferror(data->fp))
+            glp_sdf_error(data, "read error - %s\n", xerrmsg());
+         else if (data->c == '\n')
+            c = XEOF;
+         else
+         {  glp_sdf_warning(data, "missing final end of line\n");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+         glp_sdf_error(data, "invalid control character 0x%02X\n", c);
+      data->c = c;
+      return;
+}
+
+static void skip_pad(glp_data *data)
+{     /* skip uninteresting characters and comments */
+loop: while (data->c == ' ' || data->c == '\n')
+         next_char(data);
+      if (data->c == '/')
+      {  next_char(data);
+         if (data->c != '*')
+            glp_sdf_error(data, "invalid use of slash\n");
+         next_char(data);
+         for (;;)
+         {  if (data->c == '*')
+            {  next_char(data);
+               if (data->c == '/')
+               {  next_char(data);
+                  break;
+               }
+            }
+            next_char(data);
+         }
+         goto loop;
+      }
+      return;
+}
+
+static void next_item(glp_data *data)
+{     /* read next item */
+      int len;
+      skip_pad(data);
+      len = 0;
+      while (!(data->c == ' ' || data->c == '\n'))
+      {  data->item[len++] = (char)data->c;
+         if (len == sizeof(data->item))
+            glp_sdf_error(data, "data item `%.31s...' too long\n",
+               data->item);
+         next_char(data);
+      }
+      data->item[len] = '\0';
+      return;
+}
+
+int glp_sdf_read_int(glp_data *data)
+{     /* read integer number */
+      int x;
+      next_item(data);
+      switch (str2int(data->item, &x))
+      {  case 0:
+            break;
+         case 1:
+            glp_sdf_error(data, "integer `%s' out of range\n",
+               data->item);
+         case 2:
+            glp_sdf_error(data, "cannot convert `%s' to integer\n",
+               data->item);
+         default:
+            xassert(data != data);
+      }
+      return x;
+}
+
+double glp_sdf_read_num(glp_data *data)
+{     /* read floating-point number */
+      double x;
+      next_item(data);
+      switch (str2num(data->item, &x))
+      {  case 0:
+            break;
+         case 1:
+            glp_sdf_error(data, "number `%s' out of range\n",
+               data->item);
+         case 2:
+            glp_sdf_error(data, "cannot convert `%s' to number\n",
+               data->item);
+         default:
+            xassert(data != data);
+      }
+      return x;
+}
+
+const char *glp_sdf_read_item(glp_data *data)
+{     /* read data item */
+      next_item(data);
+      return data->item;
+}
+
+const char *glp_sdf_read_text(glp_data *data)
+{     /* read text until end of line */
+      int c, len = 0;
+      for (;;)
+      {  c = data->c;
+         next_char(data);
+         if (c == ' ')
+         {  /* ignore initial spaces */
+            if (len == 0) continue;
+            /* and multiple ones */
+            if (data->item[len-1] == ' ') continue;
+         }
+         else if (c == '\n')
+         {  /* remove trailing space */
+            if (len > 0 && data->item[len-1] == ' ') len--;
+            /* and stop reading */
+            break;
+         }
+         /* add current character to the buffer */
+         data->item[len++] = (char)c;
+         if (len == sizeof(data->item))
+            glp_sdf_error(data, "line too long\n", data->item);
+      }
+      data->item[len] = '\0';
+      return data->item;
+}
+
+int glp_sdf_line(glp_data *data)
+{     /* determine current line number */
+      return data->count;
+}
+
+void glp_sdf_close_file(glp_data *data)
+{     /* close plain data file */
+      xfclose(data->fp);
+      xfree(data->fname);
+      xfree(data);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpspm.c b/optional/glpk/glpspm.c
new file mode 100644
index 0000000..5549a00
--- /dev/null
+++ b/optional/glpk/glpspm.c
@@ -0,0 +1,846 @@
+/* glpspm.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glphbm.h"
+#include "glprgr.h"
+#include "glpspm.h"
+
+/***********************************************************************
+*  NAME
+*
+*  spm_create_mat - create general sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_create_mat(int m, int n);
+*
+*  DESCRIPTION
+*
+*  The routine spm_create_mat creates a general sparse matrix having
+*  m rows and n columns. Being created the matrix is zero (empty), i.e.
+*  has no elements.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the matrix created. */
+
+SPM *spm_create_mat(int m, int n)
+{     SPM *A;
+      xassert(0 <= m && m < INT_MAX);
+      xassert(0 <= n && n < INT_MAX);
+      A = xmalloc(sizeof(SPM));
+      A->m = m;
+      A->n = n;
+      if (m == 0 || n == 0)
+      {  A->pool = NULL;
+         A->row = NULL;
+         A->col = NULL;
+      }
+      else
+      {  int i, j;
+         A->pool = dmp_create_pool();
+         A->row = xcalloc(1+m, sizeof(SPME *));
+         for (i = 1; i <= m; i++) A->row[i] = NULL;
+         A->col = xcalloc(1+n, sizeof(SPME *));
+         for (j = 1; j <= n; j++) A->col[j] = NULL;
+      }
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_new_elem - add new element to sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPME *spm_new_elem(SPM *A, int i, int j, double val);
+*
+*  DESCRIPTION
+*
+*  The routine spm_new_elem adds a new element to the specified sparse
+*  matrix. Parameters i, j, and val specify the row number, the column
+*  number, and a numerical value of the element, respectively.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the new element added. */
+
+SPME *spm_new_elem(SPM *A, int i, int j, double val)
+{     SPME *e;
+      xassert(1 <= i && i <= A->m);
+      xassert(1 <= j && j <= A->n);
+      e = dmp_get_atom(A->pool, sizeof(SPME));
+      e->i = i;
+      e->j = j;
+      e->val = val;
+      e->r_prev = NULL;
+      e->r_next = A->row[i];
+      if (e->r_next != NULL) e->r_next->r_prev = e;
+      e->c_prev = NULL;
+      e->c_next = A->col[j];
+      if (e->c_next != NULL) e->c_next->c_prev = e;
+      A->row[i] = A->col[j] = e;
+      return e;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_delete_mat - delete general sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  void spm_delete_mat(SPM *A);
+*
+*  DESCRIPTION
+*
+*  The routine deletes the specified general sparse matrix freeing all
+*  the memory allocated to this object. */
+
+void spm_delete_mat(SPM *A)
+{     /* delete sparse matrix */
+      if (A->pool != NULL) dmp_delete_pool(A->pool);
+      if (A->row != NULL) xfree(A->row);
+      if (A->col != NULL) xfree(A->col);
+      xfree(A);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_test_mat_e - create test sparse matrix of E(n,c) class
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_test_mat_e(int n, int c);
+*
+*  DESCRIPTION
+*
+*  The routine spm_test_mat_e creates a test sparse matrix of E(n,c)
+*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
+*  Methods for Sparse Matrices. Springer-Verlag, 1983.
+*
+*  Matrix of E(n,c) class is a symmetric positive definite matrix of
+*  the order n. It has the number 4 on its main diagonal and the number
+*  -1 on its four co-diagonals, two of which are neighbour to the main
+*  diagonal and two others are shifted from the main diagonal on the
+*  distance c.
+*
+*  It is necessary that n >= 3 and 2 <= c <= n-1.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the matrix created. */
+
+SPM *spm_test_mat_e(int n, int c)
+{     SPM *A;
+      int i;
+      xassert(n >= 3 && 2 <= c && c <= n-1);
+      A = spm_create_mat(n, n);
+      for (i = 1; i <= n; i++)
+         spm_new_elem(A, i, i, 4.0);
+      for (i = 1; i <= n-1; i++)
+      {  spm_new_elem(A, i, i+1, -1.0);
+         spm_new_elem(A, i+1, i, -1.0);
+      }
+      for (i = 1; i <= n-c; i++)
+      {  spm_new_elem(A, i, i+c, -1.0);
+         spm_new_elem(A, i+c, i, -1.0);
+      }
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_test_mat_d - create test sparse matrix of D(n,c) class
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_test_mat_d(int n, int c);
+*
+*  DESCRIPTION
+*
+*  The routine spm_test_mat_d creates a test sparse matrix of D(n,c)
+*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
+*  Methods for Sparse Matrices. Springer-Verlag, 1983.
+*
+*  Matrix of D(n,c) class is a non-singular matrix of the order n. It
+*  has unity main diagonal, three co-diagonals above the main diagonal
+*  on the distance c, which are cyclically continued below the main
+*  diagonal, and a triangle block of the size 10x10 in the upper right
+*  corner.
+*
+*  It is necessary that n >= 14 and 1 <= c <= n-13.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the matrix created. */
+
+SPM *spm_test_mat_d(int n, int c)
+{     SPM *A;
+      int i, j;
+      xassert(n >= 14 && 1 <= c && c <= n-13);
+      A = spm_create_mat(n, n);
+      for (i = 1; i <= n; i++)
+         spm_new_elem(A, i, i, 1.0);
+      for (i = 1; i <= n-c; i++)
+         spm_new_elem(A, i, i+c, (double)(i+1));
+      for (i = n-c+1; i <= n; i++)
+         spm_new_elem(A, i, i-n+c, (double)(i+1));
+      for (i = 1; i <= n-c-1; i++)
+         spm_new_elem(A, i, i+c+1, (double)(-i));
+      for (i = n-c; i <= n; i++)
+         spm_new_elem(A, i, i-n+c+1, (double)(-i));
+      for (i = 1; i <= n-c-2; i++)
+         spm_new_elem(A, i, i+c+2, 16.0);
+      for (i = n-c-1; i <= n; i++)
+         spm_new_elem(A, i, i-n+c+2, 16.0);
+      for (j = 1; j <= 10; j++)
+         for (i = 1; i <= 11-j; i++)
+            spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j);
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_show_mat - write sparse matrix pattern in BMP file format
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_show_mat(const SPM *A, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine spm_show_mat writes pattern of the specified sparse
+*  matrix in uncompressed BMP file format (Windows bitmap) to a binary
+*  file whose name is specified by the character string fname.
+*
+*  Each pixel corresponds to one matrix element. The pixel colors have
+*  the following meaning:
+*
+*  Black    structurally zero element
+*  White    positive element
+*  Cyan     negative element
+*  Green    zero element
+*  Red      duplicate element
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero. Otherwise, it prints
+*  an appropriate error message and returns non-zero. */
+
+int spm_show_mat(const SPM *A, const char *fname)
+{     int m = A->m;
+      int n = A->n;
+      int i, j, k, ret;
+      char *map;
+      xprintf("spm_show_mat: writing matrix pattern to `%s'...\n",
+         fname);
+      xassert(1 <= m && m <= 32767);
+      xassert(1 <= n && n <= 32767);
+      map = xmalloc(m * n);
+      memset(map, 0x08, m * n);
+      for (i = 1; i <= m; i++)
+      {  SPME *e;
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  j = e->j;
+            xassert(1 <= j && j <= n);
+            k = n * (i - 1) + (j - 1);
+            if (map[k] != 0x08)
+               map[k] = 0x0C;
+            else if (e->val > 0.0)
+               map[k] = 0x0F;
+            else if (e->val < 0.0)
+               map[k] = 0x0B;
+            else
+               map[k] = 0x0A;
+         }
+      }
+      ret = rgr_write_bmp16(fname, m, n, map);
+      xfree(map);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_read_hbm - read sparse matrix in Harwell-Boeing format
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_read_hbm(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing
+*  format from a text file whose name is the character string fname.
+*
+*  Detailed description of the Harwell-Boeing format recognised by this
+*  routine can be found in the following report:
+*
+*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
+*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
+*
+*  NOTE
+*
+*  The routine spm_read_hbm reads the matrix "as is", due to which zero
+*  and/or duplicate elements can appear in the matrix.
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns a pointer to the matrix
+*  created. Otherwise, the routine prints an appropriate error message
+*  and returns NULL. */
+
+SPM *spm_read_hbm(const char *fname)
+{     SPM *A = NULL;
+      HBM *hbm;
+      int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind;
+      double val, *values;
+      char *mxtype;
+      hbm = hbm_read_mat(fname);
+      if (hbm == NULL)
+      {  xprintf("spm_read_hbm: unable to read matrix\n");
+         goto fini;
+      }
+      mxtype = hbm->mxtype;
+      nrow = hbm->nrow;
+      ncol = hbm->ncol;
+      nnzero = hbm->nnzero;
+      colptr = hbm->colptr;
+      rowind = hbm->rowind;
+      values = hbm->values;
+      if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 ||
+            strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 ||
+            strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0))
+      {  xprintf("spm_read_hbm: matrix type `%s' not supported\n",
+            mxtype);
+         goto fini;
+      }
+      A = spm_create_mat(nrow, ncol);
+      if (mxtype[1] == 'S' || mxtype[1] == 'U')
+         xassert(nrow == ncol);
+      for (j = 1; j <= ncol; j++)
+      {  beg = colptr[j];
+         end = colptr[j+1];
+         xassert(1 <= beg && beg <= end && end <= nnzero + 1);
+         for (ptr = beg; ptr < end; ptr++)
+         {  i = rowind[ptr];
+            xassert(1 <= i && i <= nrow);
+            if (mxtype[0] == 'R')
+               val = values[ptr];
+            else
+               val = 1.0;
+            spm_new_elem(A, i, j, val);
+            if (mxtype[1] == 'S' && i != j)
+               spm_new_elem(A, j, i, val);
+         }
+      }
+fini: if (hbm != NULL) hbm_free_mat(hbm);
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_count_nnz - determine number of non-zeros in sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_count_nnz(const SPM *A);
+*
+*  RETURNS
+*
+*  The routine spm_count_nnz returns the number of structural non-zero
+*  elements in the specified sparse matrix. */
+
+int spm_count_nnz(const SPM *A)
+{     SPME *e;
+      int i, nnz = 0;
+      for (i = 1; i <= A->m; i++)
+         for (e = A->row[i]; e != NULL; e = e->r_next) nnz++;
+      return nnz;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_drop_zeros - remove zero elements from sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_drop_zeros(SPM *A, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine spm_drop_zeros removes all elements from the specified
+*  sparse matrix, whose absolute value is less than eps.
+*
+*  If the parameter eps is 0, only zero elements are removed from the
+*  matrix.
+*
+*  RETURNS
+*
+*  The routine returns the number of elements removed. */
+
+int spm_drop_zeros(SPM *A, double eps)
+{     SPME *e, *next;
+      int i, count = 0;
+      for (i = 1; i <= A->m; i++)
+      {  for (e = A->row[i]; e != NULL; e = next)
+         {  next = e->r_next;
+            if (e->val == 0.0 || fabs(e->val) < eps)
+            {  /* remove element from the row list */
+               if (e->r_prev == NULL)
+                  A->row[e->i] = e->r_next;
+               else
+                  e->r_prev->r_next = e->r_next;
+               if (e->r_next == NULL)
+                  ;
+               else
+                  e->r_next->r_prev = e->r_prev;
+               /* remove element from the column list */
+               if (e->c_prev == NULL)
+                  A->col[e->j] = e->c_next;
+               else
+                  e->c_prev->c_next = e->c_next;
+               if (e->c_next == NULL)
+                  ;
+               else
+                  e->c_next->c_prev = e->c_prev;
+               /* return element to the memory pool */
+               dmp_free_atom(A->pool, e, sizeof(SPME));
+               count++;
+            }
+         }
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_read_mat - read sparse matrix from text file
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_read_mat(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine reads a sparse matrix from a text file whose name is
+*  specified by the parameter fname.
+*
+*  For the file format see description of the routine spm_write_mat.
+*
+*  RETURNS
+*
+*  On success the routine returns a pointer to the matrix created,
+*  otherwise NULL. */
+
+#if 1
+SPM *spm_read_mat(const char *fname)
+{     xassert(fname != fname);
+      return NULL;
+}
+#else
+SPM *spm_read_mat(const char *fname)
+{     SPM *A = NULL;
+      PDS *pds;
+      jmp_buf jump;
+      int i, j, k, m, n, nnz, fail = 0;
+      double val;
+      xprintf("spm_read_mat: reading matrix from `%s'...\n", fname);
+      pds = pds_open_file(fname);
+      if (pds == NULL)
+      {  xprintf("spm_read_mat: unable to open `%s' - %s\n", fname,
+            strerror(errno));
+         fail = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  fail = 1;
+         goto done;
+      }
+      pds_set_jump(pds, jump);
+      /* number of rows, number of columns, number of non-zeros */
+      m = pds_scan_int(pds);
+      if (m < 0)
+         pds_error(pds, "invalid number of rows\n");
+      n = pds_scan_int(pds);
+      if (n < 0)
+         pds_error(pds, "invalid number of columns\n");
+      nnz = pds_scan_int(pds);
+      if (nnz < 0)
+         pds_error(pds, "invalid number of non-zeros\n");
+      /* create matrix */
+      xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n",
+         m, n, nnz);
+      A = spm_create_mat(m, n);
+      /* read matrix elements */
+      for (k = 1; k <= nnz; k++)
+      {  /* row index, column index, element value */
+         i = pds_scan_int(pds);
+         if (!(1 <= i && i <= m))
+            pds_error(pds, "row index out of range\n");
+         j = pds_scan_int(pds);
+         if (!(1 <= j && j <= n))
+            pds_error(pds, "column index out of range\n");
+         val = pds_scan_num(pds);
+         /* add new element to the matrix */
+         spm_new_elem(A, i, j, val);
+      }
+      xprintf("spm_read_mat: %d lines were read\n", pds->count);
+done: if (pds != NULL) pds_close_file(pds);
+      if (fail && A != NULL) spm_delete_mat(A), A = NULL;
+      return A;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  spm_write_mat - write sparse matrix to text file
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_write_mat(const SPM *A, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine spm_write_mat writes the specified sparse matrix to a
+*  text file whose name is specified by the parameter fname. This file
+*  can be read back with the routine spm_read_mat.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine spm_write_mat is a plain text file,
+*  which contains the following information:
+*
+*     m n nnz
+*     row[1] col[1] val[1]
+*     row[2] col[2] val[2]
+*     . . .
+*     row[nnz] col[nnz] val[nnz]
+*
+*  where:
+*  m is the number of rows;
+*  n is the number of columns;
+*  nnz is the number of non-zeros;
+*  row[k], k = 1,...,nnz, are row indices;
+*  col[k], k = 1,...,nnz, are column indices;
+*  val[k], k = 1,...,nnz, are element values. */
+
+#if 1
+int spm_write_mat(const SPM *A, const char *fname)
+{     xassert(A != A);
+      xassert(fname != fname);
+      return 0;
+}
+#else
+int spm_write_mat(const SPM *A, const char *fname)
+{     FILE *fp;
+      int i, nnz, ret = 0;
+      xprintf("spm_write_mat: writing matrix to `%s'...\n", fname);
+      fp = fopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("spm_write_mat: unable to create `%s' - %s\n", fname,
+            strerror(errno));
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns, number of non-zeros */
+      nnz = spm_count_nnz(A);
+      fprintf(fp, "%d %d %d\n", A->m, A->n, nnz);
+      /* walk through rows of the matrix */
+      for (i = 1; i <= A->m; i++)
+      {  SPME *e;
+         /* walk through elements of i-th row */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  /* row index, column index, element value */
+            fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
+         }
+      }
+      fflush(fp);
+      if (ferror(fp))
+      {  xprintf("spm_write_mat: writing error on `%s' - %s\n", fname,
+            strerror(errno));
+         ret = 1;
+         goto done;
+      }
+      xprintf("spm_write_mat: %d lines were written\n", 1 + nnz);
+done: if (fp != NULL) fclose(fp);
+      return ret;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  spm_transpose - transpose sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_transpose(const SPM *A);
+*
+*  RETURNS
+*
+*  The routine computes and returns sparse matrix B, which is a matrix
+*  transposed to sparse matrix A. */
+
+SPM *spm_transpose(const SPM *A)
+{     SPM *B;
+      int i;
+      B = spm_create_mat(A->n, A->m);
+      for (i = 1; i <= A->m; i++)
+      {  SPME *e;
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            spm_new_elem(B, e->j, i, e->val);
+      }
+      return B;
+}
+
+SPM *spm_add_sym(const SPM *A, const SPM *B)
+{     /* add two sparse matrices (symbolic phase) */
+      SPM *C;
+      int i, j, *flag;
+      xassert(A->m == B->m);
+      xassert(A->n == B->n);
+      /* create resultant matrix */
+      C = spm_create_mat(A->m, A->n);
+      /* allocate and clear the flag array */
+      flag = xcalloc(1+C->n, sizeof(int));
+      for (j = 1; j <= C->n; j++)
+         flag[j] = 0;
+      /* compute pattern of C = A + B */
+      for (i = 1; i <= C->m; i++)
+      {  SPME *e;
+         /* at the beginning i-th row of C is empty */
+         /* (i-th row of C) := (i-th row of C) union (i-th row of A) */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  /* (note that i-th row of A may have duplicate elements) */
+            j = e->j;
+            if (!flag[j])
+            {  spm_new_elem(C, i, j, 0.0);
+               flag[j] = 1;
+            }
+         }
+         /* (i-th row of C) := (i-th row of C) union (i-th row of B) */
+         for (e = B->row[i]; e != NULL; e = e->r_next)
+         {  /* (note that i-th row of B may have duplicate elements) */
+            j = e->j;
+            if (!flag[j])
+            {  spm_new_elem(C, i, j, 0.0);
+               flag[j] = 1;
+            }
+         }
+         /* reset the flag array */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+            flag[e->j] = 0;
+      }
+      /* check and deallocate the flag array */
+      for (j = 1; j <= C->n; j++)
+         xassert(!flag[j]);
+      xfree(flag);
+      return C;
+}
+
+void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
+      const SPM *B)
+{     /* add two sparse matrices (numeric phase) */
+      int i, j;
+      double *work;
+      /* allocate and clear the working array */
+      work = xcalloc(1+C->n, sizeof(double));
+      for (j = 1; j <= C->n; j++)
+         work[j] = 0.0;
+      /* compute matrix C = alfa * A + beta * B */
+      for (i = 1; i <= C->n; i++)
+      {  SPME *e;
+         /* work := alfa * (i-th row of A) + beta * (i-th row of B) */
+         /* (note that A and/or B may have duplicate elements) */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            work[e->j] += alfa * e->val;
+         for (e = B->row[i]; e != NULL; e = e->r_next)
+            work[e->j] += beta * e->val;
+         /* (i-th row of C) := work, work := 0 */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+         {  j = e->j;
+            e->val = work[j];
+            work[j] = 0.0;
+         }
+      }
+      /* check and deallocate the working array */
+      for (j = 1; j <= C->n; j++)
+         xassert(work[j] == 0.0);
+      xfree(work);
+      return;
+}
+
+SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B)
+{     /* add two sparse matrices (driver routine) */
+      SPM *C;
+      C = spm_add_sym(A, B);
+      spm_add_num(C, alfa, A, beta, B);
+      return C;
+}
+
+SPM *spm_mul_sym(const SPM *A, const SPM *B)
+{     /* multiply two sparse matrices (symbolic phase) */
+      int i, j, k, *flag;
+      SPM *C;
+      xassert(A->n == B->m);
+      /* create resultant matrix */
+      C = spm_create_mat(A->m, B->n);
+      /* allocate and clear the flag array */
+      flag = xcalloc(1+C->n, sizeof(int));
+      for (j = 1; j <= C->n; j++)
+         flag[j] = 0;
+      /* compute pattern of C = A * B */
+      for (i = 1; i <= C->m; i++)
+      {  SPME *e, *ee;
+         /* compute pattern of i-th row of C */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  k = e->j;
+            for (ee = B->row[k]; ee != NULL; ee = ee->r_next)
+            {  j = ee->j;
+               /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */
+               if (!flag[j])
+               {  /* c[i,j] does not exist, so create it */
+                  spm_new_elem(C, i, j, 0.0);
+                  flag[j] = 1;
+               }
+            }
+         }
+         /* reset the flag array */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+            flag[e->j] = 0;
+      }
+      /* check and deallocate the flag array */
+      for (j = 1; j <= C->n; j++)
+         xassert(!flag[j]);
+      xfree(flag);
+      return C;
+}
+
+void spm_mul_num(SPM *C, const SPM *A, const SPM *B)
+{     /* multiply two sparse matrices (numeric phase) */
+      int i, j;
+      double *work;
+      /* allocate and clear the working array */
+      work = xcalloc(1+A->n, sizeof(double));
+      for (j = 1; j <= A->n; j++)
+         work[j] = 0.0;
+      /* compute matrix C = A * B */
+      for (i = 1; i <= C->m; i++)
+      {  SPME *e, *ee;
+         double temp;
+         /* work := (i-th row of A) */
+         /* (note that A may have duplicate elements) */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            work[e->j] += e->val;
+         /* compute i-th row of C */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+         {  j = e->j;
+            /* c[i,j] := work * (j-th column of B) */
+            temp = 0.0;
+            for (ee = B->col[j]; ee != NULL; ee = ee->c_next)
+               temp += work[ee->i] * ee->val;
+            e->val = temp;
+         }
+         /* reset the working array */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            work[e->j] = 0.0;
+      }
+      /* check and deallocate the working array */
+      for (j = 1; j <= A->n; j++)
+         xassert(work[j] == 0.0);
+      xfree(work);
+      return;
+}
+
+SPM *spm_mul_mat(const SPM *A, const SPM *B)
+{     /* multiply two sparse matrices (driver routine) */
+      SPM *C;
+      C = spm_mul_sym(A, B);
+      spm_mul_num(C, A, B);
+      return C;
+}
+
+PER *spm_create_per(int n)
+{     /* create permutation matrix */
+      PER *P;
+      int k;
+      xassert(n >= 0);
+      P = xmalloc(sizeof(PER));
+      P->n = n;
+      P->row = xcalloc(1+n, sizeof(int));
+      P->col = xcalloc(1+n, sizeof(int));
+      /* initially it is identity matrix */
+      for (k = 1; k <= n; k++)
+         P->row[k] = P->col[k] = k;
+      return P;
+}
+
+void spm_check_per(PER *P)
+{     /* check permutation matrix for correctness */
+      int i, j;
+      xassert(P->n >= 0);
+      for (i = 1; i <= P->n; i++)
+      {  j = P->row[i];
+         xassert(1 <= j && j <= P->n);
+         xassert(P->col[j] == i);
+      }
+      return;
+}
+
+void spm_delete_per(PER *P)
+{     /* delete permutation matrix */
+      xfree(P->row);
+      xfree(P->col);
+      xfree(P);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpspm.h b/optional/glpk/glpspm.h
new file mode 100644
index 0000000..516b046
--- /dev/null
+++ b/optional/glpk/glpspm.h
@@ -0,0 +1,165 @@
+/* glpspm.h (general sparse matrix) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPSPM_H
+#define GLPSPM_H
+
+#include "glpdmp.h"
+
+typedef struct SPM SPM;
+typedef struct SPME SPME;
+
+struct SPM
+{     /* general sparse matrix */
+      int m;
+      /* number of rows, m >= 0 */
+      int n;
+      /* number of columns, n >= 0 */
+      DMP *pool;
+      /* memory pool to store matrix elements */
+      SPME **row; /* SPME *row[1+m]; */
+      /* row[i], 1 <= i <= m, is a pointer to i-th row list */
+      SPME **col; /* SPME *col[1+n]; */
+      /* col[j], 1 <= j <= n, is a pointer to j-th column list */
+};
+
+struct SPME
+{     /* sparse matrix element */
+      int i;
+      /* row number */
+      int j;
+      /* column number */
+      double val;
+      /* element value */
+      SPME *r_prev;
+      /* pointer to previous element in the same row */
+      SPME *r_next;
+      /* pointer to next element in the same row */
+      SPME *c_prev;
+      /* pointer to previous element in the same column */
+      SPME *c_next;
+      /* pointer to next element in the same column */
+};
+
+typedef struct PER PER;
+
+struct PER
+{     /* permutation matrix */
+      int n;
+      /* matrix order, n >= 0 */
+      int *row; /* int row[1+n]; */
+      /* row[i] = j means p[i,j] = 1 */
+      int *col; /* int col[1+n]; */
+      /* col[j] = i means p[i,j] = 1 */
+};
+
+#define spm_create_mat _glp_spm_create_mat
+SPM *spm_create_mat(int m, int n);
+/* create general sparse matrix */
+
+#define spm_new_elem _glp_spm_new_elem
+SPME *spm_new_elem(SPM *A, int i, int j, double val);
+/* add new element to sparse matrix */
+
+#define spm_delete_mat _glp_spm_delete_mat
+void spm_delete_mat(SPM *A);
+/* delete general sparse matrix */
+
+#define spm_test_mat_e _glp_spm_test_mat_e
+SPM *spm_test_mat_e(int n, int c);
+/* create test sparse matrix of E(n,c) class */
+
+#define spm_test_mat_d _glp_spm_test_mat_d
+SPM *spm_test_mat_d(int n, int c);
+/* create test sparse matrix of D(n,c) class */
+
+#define spm_show_mat _glp_spm_show_mat
+int spm_show_mat(const SPM *A, const char *fname);
+/* write sparse matrix pattern in BMP file format */
+
+#define spm_read_hbm _glp_spm_read_hbm
+SPM *spm_read_hbm(const char *fname);
+/* read sparse matrix in Harwell-Boeing format */
+
+#define spm_count_nnz _glp_spm_count_nnz
+int spm_count_nnz(const SPM *A);
+/* determine number of non-zeros in sparse matrix */
+
+#define spm_drop_zeros _glp_spm_drop_zeros
+int spm_drop_zeros(SPM *A, double eps);
+/* remove zero elements from sparse matrix */
+
+#define spm_read_mat _glp_spm_read_mat
+SPM *spm_read_mat(const char *fname);
+/* read sparse matrix from text file */
+
+#define spm_write_mat _glp_spm_write_mat
+int spm_write_mat(const SPM *A, const char *fname);
+/* write sparse matrix to text file */
+
+#define spm_transpose _glp_spm_transpose
+SPM *spm_transpose(const SPM *A);
+/* transpose sparse matrix */
+
+#define spm_add_sym _glp_spm_add_sym
+SPM *spm_add_sym(const SPM *A, const SPM *B);
+/* add two sparse matrices (symbolic phase) */
+
+#define spm_add_num _glp_spm_add_num
+void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
+      const SPM *B);
+/* add two sparse matrices (numeric phase) */
+
+#define spm_add_mat _glp_spm_add_mat
+SPM *spm_add_mat(double alfa, const SPM *A, double beta,
+      const SPM *B);
+/* add two sparse matrices (driver routine) */
+
+#define spm_mul_sym _glp_spm_mul_sym
+SPM *spm_mul_sym(const SPM *A, const SPM *B);
+/* multiply two sparse matrices (symbolic phase) */
+
+#define spm_mul_num _glp_spm_mul_num
+void spm_mul_num(SPM *C, const SPM *A, const SPM *B);
+/* multiply two sparse matrices (numeric phase) */
+
+#define spm_mul_mat _glp_spm_mul_mat
+SPM *spm_mul_mat(const SPM *A, const SPM *B);
+/* multiply two sparse matrices (driver routine) */
+
+#define spm_create_per _glp_spm_create_per
+PER *spm_create_per(int n);
+/* create permutation matrix */
+
+#define spm_check_per _glp_spm_check_per
+void spm_check_per(PER *P);
+/* check permutation matrix for correctness */
+
+#define spm_delete_per _glp_spm_delete_per
+void spm_delete_per(PER *P);
+/* delete permutation matrix */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpspx.h b/optional/glpk/glpspx.h
new file mode 100644
index 0000000..4bda23c
--- /dev/null
+++ b/optional/glpk/glpspx.h
@@ -0,0 +1,40 @@
+/* glpspx.h (core simplex solvers) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPSPX_H
+#define GLPSPX_H
+
+#include "glpapi.h"
+
+#define spx_primal _glp_spx_primal
+int spx_primal(glp_prob *lp, const glp_smcp *parm);
+/* core LP solver based on the primal simplex method */
+
+#define spx_dual _glp_spx_dual
+int spx_dual(glp_prob *lp, const glp_smcp *parm);
+/* core LP solver based on the dual simplex method */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpspx01.c b/optional/glpk/glpspx01.c
new file mode 100644
index 0000000..3e71352
--- /dev/null
+++ b/optional/glpk/glpspx01.c
@@ -0,0 +1,2960 @@
+/* glpspx01.c (primal simplex method) */
+
+/***********************************************************************
+*  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 "-Wsometimes-uninitialized"
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#endif
+
+#include "glpspx.h"
+
+struct csa
+{     /* common storage area */
+      /*--------------------------------------------------------------*/
+      /* LP data */
+      int m;
+      /* number of rows (auxiliary variables), m > 0 */
+      int n;
+      /* number of columns (structural variables), n > 0 */
+      char *type; /* char type[1+m+n]; */
+      /* type[0] is not used;
+         type[k], 1 <= k <= m+n, is the type of variable x[k]:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double *lb; /* double lb[1+m+n]; */
+      /* lb[0] is not used;
+         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+         if x[k] has no lower bound, lb[k] is zero */
+      double *ub; /* double ub[1+m+n]; */
+      /* ub[0] is not used;
+         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+         if x[k] has no upper bound, ub[k] is zero;
+         if x[k] is of fixed type, ub[k] is the same as lb[k] */
+      double *coef; /* double coef[1+m+n]; */
+      /* coef[0] is not used;
+         coef[k], 1 <= k <= m+n, is an objective coefficient at
+         variable x[k] (note that on phase I auxiliary variables also
+         may have non-zero objective coefficients) */
+      /*--------------------------------------------------------------*/
+      /* original objective function */
+      double *obj; /* double obj[1+n]; */
+      /* obj[0] is a constant term of the original objective function;
+         obj[j], 1 <= j <= n, is an original objective coefficient at
+         structural variable x[m+j] */
+      double zeta;
+      /* factor used to scale original objective coefficients; its
+         sign defines original optimization direction: zeta > 0 means
+         minimization, zeta < 0 means maximization */
+      /*--------------------------------------------------------------*/
+      /* constraint matrix A; it has m rows and n columns and is stored
+         by columns */
+      int *A_ptr; /* int A_ptr[1+n+1]; */
+      /* A_ptr[0] is not used;
+         A_ptr[j], 1 <= j <= n, is starting position of j-th column in
+         arrays A_ind and A_val; note that A_ptr[1] is always 1;
+         A_ptr[n+1] indicates the position after the last element in
+         arrays A_ind and A_val */
+      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+      /* row indices */
+      double *A_val; /* double A_val[A_ptr[n+1]]; */
+      /* non-zero element values */
+      /*--------------------------------------------------------------*/
+      /* basis header */
+      int *head; /* int head[1+m+n]; */
+      /* head[0] is not used;
+         head[i], 1 <= i <= m, is the ordinal number of basic variable
+         xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
+         matrix B is k-th column of matrix (I|-A);
+         head[m+j], 1 <= j <= n, is the ordinal number of non-basic
+         variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
+         column of matrix N is k-th column of matrix (I|-A) */
+      char *stat; /* char stat[1+n]; */
+      /* stat[0] is not used;
+         stat[j], 1 <= j <= n, is the status of non-basic variable
+         xN[j], which defines its active bound:
+         GLP_NL - lower bound is active
+         GLP_NU - upper bound is active
+         GLP_NF - free variable
+         GLP_NS - fixed variable */
+      /*--------------------------------------------------------------*/
+      /* matrix B is the basis matrix; it is composed from columns of
+         the augmented constraint matrix (I|-A) corresponding to basic
+         variables and stored in a factorized (invertable) form */
+      int valid;
+      /* factorization is valid only if this flag is set */
+      BFD *bfd; /* BFD bfd[1:m,1:m]; */
+      /* factorized (invertable) form of the basis matrix */
+      /*--------------------------------------------------------------*/
+      /* matrix N is a matrix composed from columns of the augmented
+         constraint matrix (I|-A) corresponding to non-basic variables
+         except fixed ones; it is stored by rows and changes every time
+         the basis changes */
+      int *N_ptr; /* int N_ptr[1+m+1]; */
+      /* N_ptr[0] is not used;
+         N_ptr[i], 1 <= i <= m, is starting position of i-th row in
+         arrays N_ind and N_val; note that N_ptr[1] is always 1;
+         N_ptr[m+1] indicates the position after the last element in
+         arrays N_ind and N_val */
+      int *N_len; /* int N_len[1+m]; */
+      /* N_len[0] is not used;
+         N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
+      int *N_ind; /* int N_ind[N_ptr[m+1]]; */
+      /* column indices */
+      double *N_val; /* double N_val[N_ptr[m+1]]; */
+      /* non-zero element values */
+      /*--------------------------------------------------------------*/
+      /* working parameters */
+      int phase;
+      /* search phase:
+         0 - not determined yet
+         1 - search for primal feasible solution
+         2 - search for optimal solution */
+      glp_long tm_beg;
+      /* time value at the beginning of the search */
+      int it_beg;
+      /* simplex iteration count at the beginning of the search */
+      int it_cnt;
+      /* simplex iteration count; it increases by one every time the
+         basis changes (including the case when a non-basic variable
+         jumps to its opposite bound) */
+      int it_dpy;
+      /* simplex iteration count at the most recent display output */
+      /*--------------------------------------------------------------*/
+      /* basic solution components */
+      double *bbar; /* double bbar[1+m]; */
+      /* bbar[0] is not used;
+         bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
+         (if xB[i] is free, its primal value is not updated) */
+      double *cbar; /* double cbar[1+n]; */
+      /* cbar[0] is not used;
+         cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
+         xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
+      /*--------------------------------------------------------------*/
+      /* the following pricing technique options may be used:
+         GLP_PT_STD - standard ("textbook") pricing;
+         GLP_PT_PSE - projected steepest edge;
+         GLP_PT_DVX - Devex pricing (not implemented yet);
+         in case of GLP_PT_STD the reference space is not used, and all
+         steepest edge coefficients are set to 1 */
+      int refct;
+      /* this count is set to an initial value when the reference space
+         is defined and decreases by one every time the basis changes;
+         once this count reaches zero, the reference space is redefined
+         again */
+      char *refsp; /* char refsp[1+m+n]; */
+      /* refsp[0] is not used;
+         refsp[k], 1 <= k <= m+n, is the flag which means that variable
+         x[k] belongs to the current reference space */
+      double *gamma; /* double gamma[1+n]; */
+      /* gamma[0] is not used;
+         gamma[j], 1 <= j <= n, is the steepest edge coefficient for
+         non-basic variable xN[j]; if xN[j] is fixed, gamma[j] is not
+         used and just set to 1 */
+      /*--------------------------------------------------------------*/
+      /* non-basic variable xN[q] chosen to enter the basis */
+      int q;
+      /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
+         if the set of eligible non-basic variables is empty and thus
+         no variable has been chosen, q is set to 0 */
+      /*--------------------------------------------------------------*/
+      /* pivot column of the simplex table corresponding to non-basic
+         variable xN[q] chosen is the following vector:
+            T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+         where B is the current basis matrix, N[q] is a column of the
+         matrix (I|-A) corresponding to xN[q] */
+      int tcol_nnz;
+      /* number of non-zero components, 0 <= nnz <= m */
+      int *tcol_ind; /* int tcol_ind[1+m]; */
+      /* tcol_ind[0] is not used;
+         tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
+      double *tcol_vec; /* double tcol_vec[1+m]; */
+      /* tcol_vec[0] is not used;
+         tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
+         of the column */
+      double tcol_max;
+      /* infinity (maximum) norm of the column (max |tcol_vec[i]|) */
+      int tcol_num;
+      /* number of significant non-zero components, which means that:
+         |tcol_vec[i]| >= eps for i in tcol_ind[1,...,num],
+         |tcol_vec[i]| <  eps for i in tcol_ind[num+1,...,nnz],
+         where eps is a pivot tolerance */
+      /*--------------------------------------------------------------*/
+      /* basic variable xB[p] chosen to leave the basis */
+      int p;
+      /* index of the basic variable xB[p] chosen, 1 <= p <= m;
+         p = 0 means that no basic variable reaches its bound;
+         p < 0 means that non-basic variable xN[q] reaches its opposite
+         bound before any basic variable */
+      int p_stat;
+      /* new status (GLP_NL, GLP_NU, or GLP_NS) to be assigned to xB[p]
+         once it has left the basis */
+      double teta;
+      /* change of non-basic variable xN[q] (see above), on which xB[p]
+         (or, if p < 0, xN[q] itself) reaches its bound */
+      /*--------------------------------------------------------------*/
+      /* pivot row of the simplex table corresponding to basic variable
+         xB[p] chosen is the following vector:
+            T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
+         where B' is a matrix transposed to the current basis matrix,
+         N' is a matrix, whose rows are columns of the matrix (I|-A)
+         corresponding to non-basic non-fixed variables */
+      int trow_nnz;
+      /* number of non-zero components, 0 <= nnz <= n */
+      int *trow_ind; /* int trow_ind[1+n]; */
+      /* trow_ind[0] is not used;
+         trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
+      double *trow_vec; /* int trow_vec[1+n]; */
+      /* trow_vec[0] is not used;
+         trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
+         of the row */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      double *work1; /* double work1[1+m]; */
+      double *work2; /* double work2[1+m]; */
+      double *work3; /* double work3[1+m]; */
+      double *work4; /* double work4[1+m]; */
+};
+
+static const double kappa = 0.10;
+
+/***********************************************************************
+*  alloc_csa - allocate common storage area
+*
+*  This routine allocates all arrays in the common storage area (CSA)
+*  and returns a pointer to the CSA. */
+
+static struct csa *alloc_csa(glp_prob *lp)
+{     struct csa *csa;
+      int m = lp->m;
+      int n = lp->n;
+      int nnz = lp->nnz;
+      csa = xmalloc(sizeof(struct csa));
+      xassert(m > 0 && n > 0);
+      csa->m = m;
+      csa->n = n;
+      csa->type = xcalloc(1+m+n, sizeof(char));
+      csa->lb = xcalloc(1+m+n, sizeof(double));
+      csa->ub = xcalloc(1+m+n, sizeof(double));
+      csa->coef = xcalloc(1+m+n, sizeof(double));
+      csa->obj = xcalloc(1+n, sizeof(double));
+      csa->A_ptr = xcalloc(1+n+1, sizeof(int));
+      csa->A_ind = xcalloc(1+nnz, sizeof(int));
+      csa->A_val = xcalloc(1+nnz, sizeof(double));
+      csa->head = xcalloc(1+m+n, sizeof(int));
+      csa->stat = xcalloc(1+n, sizeof(char));
+      csa->N_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->N_len = xcalloc(1+m, sizeof(int));
+      csa->N_ind = NULL; /* will be allocated later */
+      csa->N_val = NULL; /* will be allocated later */
+      csa->bbar = xcalloc(1+m, sizeof(double));
+      csa->cbar = xcalloc(1+n, sizeof(double));
+      csa->refsp = xcalloc(1+m+n, sizeof(char));
+      csa->gamma = xcalloc(1+n, sizeof(double));
+      csa->tcol_ind = xcalloc(1+m, sizeof(int));
+      csa->tcol_vec = xcalloc(1+m, sizeof(double));
+      csa->trow_ind = xcalloc(1+n, sizeof(int));
+      csa->trow_vec = xcalloc(1+n, sizeof(double));
+      csa->work1 = xcalloc(1+m, sizeof(double));
+      csa->work2 = xcalloc(1+m, sizeof(double));
+      csa->work3 = xcalloc(1+m, sizeof(double));
+      csa->work4 = xcalloc(1+m, sizeof(double));
+      return csa;
+}
+
+/***********************************************************************
+*  init_csa - initialize common storage area
+*
+*  This routine initializes all data structures in the common storage
+*  area (CSA). */
+
+static void alloc_N(struct csa *csa);
+static void build_N(struct csa *csa);
+
+static void init_csa(struct csa *csa, glp_prob *lp)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      double *obj = csa->obj;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int i, j, k, loc;
+      double cmax;
+      /* auxiliary variables */
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         type[i] = (char)row->type;
+         lb[i] = row->lb * row->rii;
+         ub[i] = row->ub * row->rii;
+         coef[i] = 0.0;
+      }
+      /* structural variables */
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         type[m+j] = (char)col->type;
+         lb[m+j] = col->lb / col->sjj;
+         ub[m+j] = col->ub / col->sjj;
+         coef[m+j] = col->coef * col->sjj;
+      }
+      /* original objective function */
+      obj[0] = lp->c0;
+      memcpy(&obj[1], &coef[m+1], n * sizeof(double));
+      /* factor used to scale original objective coefficients */
+      cmax = 0.0;
+      for (j = 1; j <= n; j++)
+         if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
+      if (cmax == 0.0) cmax = 1.0;
+      switch (lp->dir)
+      {  case GLP_MIN:
+            csa->zeta = + 1.0 / cmax;
+            break;
+         case GLP_MAX:
+            csa->zeta = - 1.0 / cmax;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+#if 1
+      if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
+#endif
+      /* matrix A (by columns) */
+      loc = 1;
+      for (j = 1; j <= n; j++)
+      {  GLPAIJ *aij;
+         A_ptr[j] = loc;
+         for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+         {  A_ind[loc] = aij->row->i;
+            A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      A_ptr[n+1] = loc;
+      xassert(loc == lp->nnz+1);
+      /* basis header */
+      xassert(lp->valid);
+      memcpy(&head[1], &lp->head[1], m * sizeof(int));
+      k = 0;
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         if (row->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = i;
+            stat[k] = (char)row->stat;
+         }
+      }
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         if (col->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = m + j;
+            stat[k] = (char)col->stat;
+         }
+      }
+      xassert(k == n);
+      /* factorization of matrix B */
+      csa->valid = 1, lp->valid = 0;
+      csa->bfd = lp->bfd, lp->bfd = NULL;
+      /* matrix N (by rows) */
+      alloc_N(csa);
+      build_N(csa);
+      /* working parameters */
+      csa->phase = 0;
+      csa->tm_beg = xtime();
+      csa->it_beg = csa->it_cnt = lp->it_cnt;
+      csa->it_dpy = -1;
+      /* reference space and steepest edge coefficients */
+      csa->refct = 0;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (j = 1; j <= n; j++) gamma[j] = 1.0;
+      return;
+}
+
+/***********************************************************************
+*  invert_B - compute factorization of the basis matrix
+*
+*  This routine computes factorization of the current basis matrix B.
+*
+*  If the operation is successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int inv_col(void *info, int i, int ind[], double val[])
+{     /* this auxiliary routine returns row indices and numeric values
+         of non-zero elements of i-th column of the basis matrix */
+      struct csa *csa = info;
+      int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int k, len, ptr, t;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+#endif
+      k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* B[i] is k-th column of submatrix I */
+         len = 1;
+         ind[1] = k;
+         val[1] = 1.0;
+      }
+      else
+      {  /* B[i] is (k-m)-th column of submatrix (-A) */
+         ptr = A_ptr[k-m];
+         len = A_ptr[k-m+1] - ptr;
+         memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
+         memcpy(&val[1], &A_val[ptr], len * sizeof(double));
+         for (t = 1; t <= len; t++) val[t] = - val[t];
+      }
+      return len;
+}
+
+static int invert_B(struct csa *csa)
+{     int ret;
+      ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
+      csa->valid = (ret == 0);
+      return ret;
+}
+
+/***********************************************************************
+*  update_B - update factorization of the basis matrix
+*
+*  This routine replaces i-th column of the basis matrix B by k-th
+*  column of the augmented constraint matrix (I|-A) and then updates
+*  the factorization of B.
+*
+*  If the factorization has been successfully updated, the routine
+*  returns zero, otherwise non-zero. */
+
+static int update_B(struct csa *csa, int i, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int ret;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* new i-th column of B is k-th column of I */
+         int ind[1+1];
+         double val[1+1];
+         ind[1] = k;
+         val[1] = 1.0;
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
+      }
+      else
+      {  /* new i-th column of B is (k-m)-th column of (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         double *val = csa->work1;
+         int beg, end, ptr, len;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         len = 0;
+         for (ptr = beg; ptr < end; ptr++)
+            val[++len] = - A_val[ptr];
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
+      }
+      csa->valid = (ret == 0);
+      return ret;
+}
+
+/***********************************************************************
+*  error_ftran - compute residual vector r = h - B * x
+*
+*  This routine computes the residual vector r = h - B * x, where B is
+*  the current basis matrix, h is the vector of right-hand sides, x is
+*  the solution vector. */
+
+static void error_ftran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector:
+         r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
+         where B[1], ..., B[m] are columns of matrix B */
+      memcpy(&r[1], &h[1], m * sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  temp = x[i];
+         if (temp == 0.0) continue;
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            r[k] -= temp;
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               r[A_ind[ptr]] += A_val[ptr] * temp;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  refine_ftran - refine solution of B * x = h
+*
+*  This routine performs one iteration to refine the solution of
+*  the system B * x = h, where B is the current basis matrix, h is the
+*  vector of right-hand sides, x is the solution vector. */
+
+static void refine_ftran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B * x */
+      error_ftran(csa, h, x, r);
+      /* compute the correction vector d = inv(B) * r */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+
+/***********************************************************************
+*  error_btran - compute residual vector r = h - B'* x
+*
+*  This routine computes the residual vector r = h - B'* x, where B'
+*  is a matrix transposed to the current basis matrix, h is the vector
+*  of right-hand sides, x is the solution vector. */
+
+static void error_btran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector r = b - B'* x */
+      for (i = 1; i <= m; i++)
+      {  /* r[i] := b[i] - (i-th column of B)'* x */
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         temp = h[i];
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            temp -= x[k];
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               temp += A_val[ptr] * x[A_ind[ptr]];
+         }
+         r[i] = temp;
+      }
+      return;
+}
+
+/***********************************************************************
+*  refine_btran - refine solution of B'* x = h
+*
+*  This routine performs one iteration to refine the solution of the
+*  system B'* x = h, where B' is a matrix transposed to the current
+*  basis matrix, h is the vector of right-hand sides, x is the solution
+*  vector. */
+
+static void refine_btran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B'* x */
+      error_btran(csa, h, x, r);
+      /* compute the correction vector d = inv(B') * r */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+
+/***********************************************************************
+*  alloc_N - allocate matrix N
+*
+*  This routine determines maximal row lengths of matrix N, sets its
+*  row pointers, and then allocates arrays N_ind and N_val.
+*
+*  Note that some fixed structural variables may temporarily become
+*  double-bounded, so corresponding columns of matrix A should not be
+*  ignored on calculating maximal row lengths of matrix N. */
+
+static void alloc_N(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int i, j, beg, end, ptr;
+      /* determine number of non-zeros in each row of the augmented
+         constraint matrix (I|-A) */
+      for (i = 1; i <= m; i++)
+         N_len[i] = 1;
+      for (j = 1; j <= n; j++)
+      {  beg = A_ptr[j];
+         end = A_ptr[j+1];
+         for (ptr = beg; ptr < end; ptr++)
+            N_len[A_ind[ptr]]++;
+      }
+      /* determine maximal row lengths of matrix N and set its row
+         pointers */
+      N_ptr[1] = 1;
+      for (i = 1; i <= m; i++)
+      {  /* row of matrix N cannot have more than n non-zeros */
+         if (N_len[i] > n) N_len[i] = n;
+         N_ptr[i+1] = N_ptr[i] + N_len[i];
+      }
+      /* now maximal number of non-zeros in matrix N is known */
+      csa->N_ind = xcalloc(N_ptr[m+1], sizeof(int));
+      csa->N_val = xcalloc(N_ptr[m+1], sizeof(double));
+      return;
+}
+
+/***********************************************************************
+*  add_N_col - add column of matrix (I|-A) to matrix N
+*
+*  This routine adds j-th column to matrix N which is k-th column of
+*  the augmented constraint matrix (I|-A). (It is assumed that old j-th
+*  column was previously removed from matrix N.) */
+
+static void add_N_col(struct csa *csa, int j, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int *N_ind = csa->N_ind;
+      double *N_val = csa->N_val;
+      int pos;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         pos = N_ptr[k] + (N_len[k]++);
+#ifdef GLP_DEBUG
+         xassert(pos < N_ptr[k+1]);
+#endif
+         N_ind[pos] = j;
+         N_val[pos] = 1.0;
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int i, beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+         {  i = A_ind[ptr]; /* row number */
+            pos = N_ptr[i] + (N_len[i]++);
+#ifdef GLP_DEBUG
+            xassert(pos < N_ptr[i+1]);
+#endif
+            N_ind[pos] = j;
+            N_val[pos] = - A_val[ptr];
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  del_N_col - remove column of matrix (I|-A) from matrix N
+*
+*  This routine removes j-th column from matrix N which is k-th column
+*  of the augmented constraint matrix (I|-A). */
+
+static void del_N_col(struct csa *csa, int j, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int *N_ind = csa->N_ind;
+      double *N_val = csa->N_val;
+      int pos, head, tail;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         /* find element in k-th row of N */
+         head = N_ptr[k];
+         for (pos = head; N_ind[pos] != j; pos++) /* nop */;
+         /* and remove it from the row list */
+         tail = head + (--N_len[k]);
+#ifdef GLP_DEBUG
+         xassert(pos <= tail);
+#endif
+         N_ind[pos] = N_ind[tail];
+         N_val[pos] = N_val[tail];
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         int i, beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+         {  i = A_ind[ptr]; /* row number */
+            /* find element in i-th row of N */
+            head = N_ptr[i];
+            for (pos = head; N_ind[pos] != j; pos++) /* nop */;
+            /* and remove it from the row list */
+            tail = head + (--N_len[i]);
+#ifdef GLP_DEBUG
+            xassert(pos <= tail);
+#endif
+            N_ind[pos] = N_ind[tail];
+            N_val[pos] = N_val[tail];
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  build_N - build matrix N for current basis
+*
+*  This routine builds matrix N for the current basis from columns
+*  of the augmented constraint matrix (I|-A) corresponding to non-basic
+*  non-fixed variables. */
+
+static void build_N(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int *N_len = csa->N_len;
+      int j, k;
+      /* N := empty matrix */
+      memset(&N_len[1], 0, m * sizeof(int));
+      /* go through non-basic columns of matrix (I|-A) */
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] != GLP_NS)
+         {  /* xN[j] is non-fixed; add j-th column to matrix N which is
+               k-th column of matrix (I|-A) */
+            k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+            xassert(1 <= k && k <= m+n);
+#endif
+            add_N_col(csa, j, k);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  get_xN - determine current value of non-basic variable xN[j]
+*
+*  This routine returns the current value of non-basic variable xN[j],
+*  which is a value of its active bound. */
+
+static double get_xN(struct csa *csa, int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int k;
+      double xN;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      switch (stat[j])
+      {  case GLP_NL:
+            /* x[k] is on its lower bound */
+            xN = lb[k]; break;
+         case GLP_NU:
+            /* x[k] is on its upper bound */
+            xN = ub[k]; break;
+         case GLP_NF:
+            /* x[k] is free non-basic variable */
+            xN = 0.0; break;
+         case GLP_NS:
+            /* x[k] is fixed non-basic variable */
+            xN = lb[k]; break;
+         default:
+            xassert(stat != stat);
+      }
+      return xN;
+}
+
+/***********************************************************************
+*  eval_beta - compute primal values of basic variables
+*
+*  This routine computes current primal values of all basic variables:
+*
+*     beta = - inv(B) * N * xN,
+*
+*  where B is the current basis matrix, N is a matrix built of columns
+*  of matrix (I|-A) corresponding to non-basic variables, and xN is the
+*  vector of current values of non-basic variables. */
+
+static void eval_beta(struct csa *csa, double beta[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      double *h = csa->work2;
+      int i, j, k, beg, end, ptr;
+      double xN;
+      /* compute the right-hand side vector:
+         h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
+         where N[1], ..., N[n] are columns of matrix N */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* determine current value of xN[j] */
+         xN = get_xN(csa, j);
+         if (xN == 0.0) continue;
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            h[k] -= xN;
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               h[A_ind[ptr]] += xN * A_val[ptr];
+         }
+      }
+      /* solve system B * beta = h */
+      memcpy(&beta[1], &h[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, beta);
+      /* and refine the solution */
+      refine_ftran(csa, h, beta);
+      return;
+}
+
+/***********************************************************************
+*  eval_pi - compute vector of simplex multipliers
+*
+*  This routine computes the vector of current simplex multipliers:
+*
+*     pi = inv(B') * cB,
+*
+*  where B' is a matrix transposed to the current basis matrix, cB is
+*  a subvector of objective coefficients at basic variables. */
+
+static void eval_pi(struct csa *csa, double pi[])
+{     int m = csa->m;
+      double *c = csa->coef;
+      int *head = csa->head;
+      double *cB = csa->work2;
+      int i;
+      /* construct the right-hand side vector cB */
+      for (i = 1; i <= m; i++)
+         cB[i] = c[head[i]];
+      /* solve system B'* pi = cB */
+      memcpy(&pi[1], &cB[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, pi);
+      /* and refine the solution */
+      refine_btran(csa, cB, pi);
+      return;
+}
+
+/***********************************************************************
+*  eval_cost - compute reduced cost of non-basic variable xN[j]
+*
+*  This routine computes the current reduced cost of non-basic variable
+*  xN[j]:
+*
+*     d[j] = cN[j] - N'[j] * pi,
+*
+*  where cN[j] is the objective coefficient at variable xN[j], N[j] is
+*  a column of the augmented constraint matrix (I|-A) corresponding to
+*  xN[j], pi is the vector of simplex multipliers. */
+
+static double eval_cost(struct csa *csa, double pi[], int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int k;
+      double dj;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      dj = coef[k];
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         dj -= pi[k];
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            dj += A_val[ptr] * pi[A_ind[ptr]];
+      }
+      return dj;
+}
+
+/***********************************************************************
+*  eval_bbar - compute and store primal values of basic variables
+*
+*  This routine computes primal values of all basic variables and then
+*  stores them in the solution array. */
+
+static void eval_bbar(struct csa *csa)
+{     eval_beta(csa, csa->bbar);
+      return;
+}
+
+/***********************************************************************
+*  eval_cbar - compute and store reduced costs of non-basic variables
+*
+*  This routine computes reduced costs of all non-basic variables and
+*  then stores them in the solution array. */
+
+static void eval_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+#endif
+      int n = csa->n;
+#ifdef GLP_DEBUG
+      int *head = csa->head;
+#endif
+      double *cbar = csa->cbar;
+      double *pi = csa->work3;
+      int j;
+#ifdef GLP_DEBUG
+      int k;
+#endif
+      /* compute simplex multipliers */
+      eval_pi(csa, pi);
+      /* compute and store reduced costs */
+      for (j = 1; j <= n; j++)
+      {
+#ifdef GLP_DEBUG
+         k = head[m+j]; /* x[k] = xN[j] */
+         xassert(1 <= k && k <= m+n);
+#endif
+         cbar[j] = eval_cost(csa, pi, j);
+      }
+      return;
+}
+
+/***********************************************************************
+*  reset_refsp - reset the reference space
+*
+*  This routine resets (redefines) the reference space used in the
+*  projected steepest edge pricing algorithm. */
+
+static void reset_refsp(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int j, k;
+      xassert(csa->refct == 0);
+      csa->refct = 1000;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+         refsp[k] = 1;
+         gamma[j] = 1.0;
+      }
+      return;
+}
+
+/***********************************************************************
+*  eval_gamma - compute steepest edge coefficient
+*
+*  This routine computes the steepest edge coefficient for non-basic
+*  variable xN[j] using its direct definition:
+*
+*     gamma[j] = delta[j] +  sum   alfa[i,j]^2,
+*                           i in R
+*
+*  where delta[j] = 1, if xN[j] is in the current reference space,
+*  and 0 otherwise; R is a set of basic variables xB[i], which are in
+*  the current reference space; alfa[i,j] are elements of the current
+*  simplex table.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double eval_gamma(struct csa *csa, int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *alfa = csa->work3;
+      double *h = csa->work3;
+      int i, k;
+      double gamma;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[j] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* solve system B * alfa = h */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, alfa);
+      /* compute gamma */
+      gamma = (refsp[k] ? 1.0 : 0.0);
+      for (i = 1; i <= m; i++)
+      {  k = head[i];
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (refsp[k]) gamma += alfa[i] * alfa[i];
+      }
+      return gamma;
+}
+
+/***********************************************************************
+*  chuzc - choose non-basic variable (column of the simplex table)
+*
+*  This routine chooses non-basic variable xN[q], which has largest
+*  weighted reduced cost:
+*
+*     |d[q]| / sqrt(gamma[q]) = max  |d[j]| / sqrt(gamma[j]),
+*                              j in J
+*
+*  where J is a subset of eligible non-basic variables xN[j], d[j] is
+*  reduced cost of xN[j], gamma[j] is the steepest edge coefficient.
+*
+*  The working objective function is always minimized, so the sign of
+*  d[q] determines direction, in which xN[q] has to change:
+*
+*     if d[q] < 0, xN[q] has to increase;
+*
+*     if d[q] > 0, xN[q] has to decrease.
+*
+*  If |d[j]| <= tol_dj, where tol_dj is a specified tolerance, xN[j]
+*  is not included in J and therefore ignored. (It is assumed that the
+*  working objective row is appropriately scaled, i.e. max|c[k]| = 1.)
+*
+*  If J is empty and no variable has been chosen, q is set to 0. */
+
+static void chuzc(struct csa *csa, double tol_dj)
+{     int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      double *gamma = csa->gamma;
+      int j, q;
+      double dj, best, temp;
+      /* nothing is chosen so far */
+      q = 0, best = 0.0;
+      /* look through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  dj = cbar[j];
+         switch (stat[j])
+         {  case GLP_NL:
+               /* xN[j] can increase */
+               if (dj >= - tol_dj) continue;
+               break;
+            case GLP_NU:
+               /* xN[j] can decrease */
+               if (dj <= + tol_dj) continue;
+               break;
+            case GLP_NF:
+               /* xN[j] can change in any direction */
+               if (- tol_dj <= dj && dj <= + tol_dj) continue;
+               break;
+            case GLP_NS:
+               /* xN[j] cannot change at all */
+               continue;
+            default:
+               xassert(stat != stat);
+         }
+         /* xN[j] is eligible non-basic variable; choose one which has
+            largest weighted reduced cost */
+#ifdef GLP_DEBUG
+         xassert(gamma[j] > 0.0);
+#endif
+         temp = (dj * dj) / gamma[j];
+         if (best < temp)
+            q = j, best = temp;
+      }
+      /* store the index of non-basic variable xN[q] chosen */
+      csa->q = q;
+      return;
+}
+
+/***********************************************************************
+*  eval_tcol - compute pivot column of the simplex table
+*
+*  This routine computes the pivot column of the simplex table, which
+*  corresponds to non-basic variable xN[q] chosen.
+*
+*  The pivot column is the following vector:
+*
+*     tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+*
+*  where B is the current basis matrix, N[q] is a column of the matrix
+*  (I|-A) corresponding to variable xN[q]. */
+
+static void eval_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->tcol_vec;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* solve system B * tcol = h */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  refine_tcol - refine pivot column of the simplex table
+*
+*  This routine refines the pivot column of the simplex table assuming
+*  that it was previously computed by the routine eval_tcol. */
+
+static void refine_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->work3;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* refine solution of B * tcol = h */
+      refine_ftran(csa, h, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  sort_tcol - sort pivot column of the simplex table
+*
+*  This routine reorders the list of non-zero elements of the pivot
+*  column to put significant elements, whose magnitude is not less than
+*  a specified tolerance, in front of the list, and stores the number
+*  of significant elements in tcol_num. */
+
+static void sort_tcol(struct csa *csa, double tol_piv)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+#endif
+      int nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int i, num, pos;
+      double big, eps, temp;
+      /* compute infinity (maximum) norm of the column */
+      big = 0.0;
+      for (pos = 1; pos <= nnz; pos++)
+      {
+#ifdef GLP_DEBUG
+         i = tcol_ind[pos];
+         xassert(1 <= i && i <= m);
+#endif
+         temp = fabs(tcol_vec[tcol_ind[pos]]);
+         if (big < temp) big = temp;
+      }
+      csa->tcol_max = big;
+      /* determine absolute pivot tolerance */
+      eps = tol_piv * (1.0 + 0.01 * big);
+      /* move significant column components to front of the list */
+      for (num = 0; num < nnz; )
+      {  i = tcol_ind[nnz];
+         if (fabs(tcol_vec[i]) < eps)
+            nnz--;
+         else
+         {  num++;
+            tcol_ind[nnz] = tcol_ind[num];
+            tcol_ind[num] = i;
+         }
+      }
+      csa->tcol_num = num;
+      return;
+}
+
+/***********************************************************************
+*  chuzr - choose basic variable (row of the simplex table)
+*
+*  This routine chooses basic variable xB[p], which reaches its bound
+*  first on changing non-basic variable xN[q] in valid direction.
+*
+*  The parameter rtol is a relative tolerance used to relax bounds of
+*  basic variables. If rtol = 0, the routine implements the standard
+*  ratio test. Otherwise, if rtol > 0, the routine implements Harris'
+*  two-pass ratio test. In the latter case rtol should be about three
+*  times less than a tolerance used to check primal feasibility. */
+
+static void chuzr(struct csa *csa, double rtol)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int phase = csa->phase;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int tcol_num = csa->tcol_num;
+      int i, i_stat, k, p, p_stat, pos;
+      double alfa, big, delta, s, t, teta, tmax;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      /* s := - sign(d[q]), where d[q] is reduced cost of xN[q] */
+#ifdef GLP_DEBUG
+      xassert(cbar[q] != 0.0);
+#endif
+      s = (cbar[q] > 0.0 ? -1.0 : +1.0);
+      /*** FIRST PASS ***/
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (type[k] == GLP_DB)
+      {  /* xN[q] has both lower and upper bounds */
+         p = -1, p_stat = 0, teta = ub[k] - lb[k], big = 1.0;
+      }
+      else
+      {  /* xN[q] has no opposite bound */
+         p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
+      }
+      /* walk through significant elements of the pivot column */
+      for (pos = 1; pos <= tcol_num; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         alfa = s * tcol_vec[i];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
+            consider the only case when xN[q] is increasing */
+         if (alfa > 0.0)
+         {  /* xB[i] is increasing */
+            if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               delta = rtol * (1.0 + kappa * fabs(lb[k]));
+               t = ((lb[k] + delta) - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_UP || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an upper bound */
+               delta = rtol * (1.0 + kappa * fabs(ub[k]));
+               t = ((ub[k] + delta) - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no upper bound */
+               continue;
+            }
+         }
+         else
+         {  /* xB[i] is decreasing */
+            if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               delta = rtol * (1.0 + kappa * fabs(ub[k]));
+               t = ((ub[k] - delta) - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_LO || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an lower bound */
+               delta = rtol * (1.0 + kappa * fabs(lb[k]));
+               t = ((lb[k] - delta) - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no lower bound */
+               continue;
+            }
+         }
+         /* t is a change of xN[q], on which xB[i] reaches its bound
+            (possibly relaxed); since the basic solution is assumed to
+            be primal feasible (or pseudo feasible on phase I), t has
+            to be non-negative by definition; however, it may happen
+            that xB[i] slightly (i.e. within a tolerance) violates its
+            bound, that leads to negative t; in the latter case, if
+            xB[i] is chosen, negative t means that xN[q] changes in
+            wrong direction; if pivot alfa[i,q] is close to zero, even
+            small bound violation of xB[i] may lead to a large change
+            of xN[q] in wrong direction; let, for example, xB[i] >= 0
+            and in the current basis its value be -5e-9; let also xN[q]
+            be on its zero bound and should increase; from the ratio
+            test rule it follows that the pivot alfa[i,q] < 0; however,
+            if alfa[i,q] is, say, -1e-9, the change of xN[q] in wrong
+            direction is 5e-9 / (-1e-9) = -5, and using it for updating
+            values of other basic variables will give absolutely wrong
+            results; therefore, if t is negative, we should replace it
+            by exact zero assuming that xB[i] is exactly on its bound,
+            and the violation appears due to round-off errors */
+         if (t < 0.0) t = 0.0;
+         /* apply minimal ratio test */
+         if (teta > t || teta == t && big < fabs(alfa))
+            p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
+      }
+      /* the second pass is skipped in the following cases: */
+      /* if the standard ratio test is used */
+      if (rtol == 0.0) goto done;
+      /* if xN[q] reaches its opposite bound or if no basic variable
+         has been chosen on the first pass */
+      if (p <= 0) goto done;
+      /* if xB[p] is a blocking variable, i.e. if it prevents xN[q]
+         from any change */
+      if (teta == 0.0) goto done;
+      /*** SECOND PASS ***/
+      /* here tmax is a maximal change of xN[q], on which the solution
+         remains primal feasible (or pseudo feasible on phase I) within
+         a tolerance */
+#if 0
+      tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
+#else
+      tmax = teta;
+#endif
+      /* nothing is chosen so far */
+      p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through significant elements of the pivot column */
+      for (pos = 1; pos <= tcol_num; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         alfa = s * tcol_vec[i];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
+            consider the only case when xN[q] is increasing */
+         if (alfa > 0.0)
+         {  /* xB[i] is increasing */
+            if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               t = (lb[k] - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_UP || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an upper bound */
+               t = (ub[k] - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no upper bound */
+               continue;
+            }
+         }
+         else
+         {  /* xB[i] is decreasing */
+            if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               t = (ub[k] - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_LO || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an lower bound */
+               t = (lb[k] - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no lower bound */
+               continue;
+            }
+         }
+         /* (see comments for the first pass) */
+         if (t < 0.0) t = 0.0;
+         /* t is a change of xN[q], on which xB[i] reaches its bound;
+            if t <= tmax, all basic variables can violate their bounds
+            only within relaxation tolerance delta; we can use this
+            freedom and choose basic variable having largest influence
+            coefficient to avoid possible numeric instability */
+         if (t <= tmax && big < fabs(alfa))
+            p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
+      }
+      /* something must be chosen on the second pass */
+      xassert(p != 0);
+done: /* store the index and status of basic variable xB[p] chosen */
+      csa->p = p;
+      if (p > 0 && type[head[p]] == GLP_FX)
+         csa->p_stat = GLP_NS;
+      else
+         csa->p_stat = p_stat;
+      /* store corresponding change of non-basic variable xN[q] */
+#ifdef GLP_DEBUG
+      xassert(teta >= 0.0);
+#endif
+      csa->teta = s * teta;
+      return;
+}
+
+/***********************************************************************
+*  eval_rho - compute pivot row of the inverse
+*
+*  This routine computes the pivot (p-th) row of the inverse inv(B),
+*  which corresponds to basic variable xB[p] chosen:
+*
+*     rho = inv(B') * e[p],
+*
+*  where B' is a matrix transposed to the current basis matrix, e[p]
+*  is unity vector. */
+
+static void eval_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = rho;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* solve system B'* rho = e[p] */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, rho);
+      return;
+}
+
+/***********************************************************************
+*  refine_rho - refine pivot row of the inverse
+*
+*  This routine refines the pivot row of the inverse inv(B) assuming
+*  that it was previously computed by the routine eval_rho. */
+
+static void refine_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = csa->work3;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* refine solution of B'* rho = e[p] */
+      refine_btran(csa, e, rho);
+      return;
+}
+
+/***********************************************************************
+*  eval_trow - compute pivot row of the simplex table
+*
+*  This routine computes the pivot row of the simplex table, which
+*  corresponds to basic variable xB[p] chosen.
+*
+*  The pivot row is the following vector:
+*
+*     trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
+*
+*  where rho is the pivot row of the inverse inv(B) previously computed
+*  by the routine eval_rho.
+*
+*  Note that elements of the pivot row corresponding to fixed non-basic
+*  variables are not computed. */
+
+static void eval_trow(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int n = csa->n;
+#ifdef GLP_DEBUG
+      char *stat = csa->stat;
+#endif
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int *N_ind = csa->N_ind;
+      double *N_val = csa->N_val;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int i, j, beg, end, ptr, nnz;
+      double temp;
+      /* clear the pivot row */
+      for (j = 1; j <= n; j++)
+         trow_vec[j] = 0.0;
+      /* compute the pivot row as a linear combination of rows of the
+         matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
+      for (i = 1; i <= m; i++)
+      {  temp = rho[i];
+         if (temp == 0.0) continue;
+         /* trow := trow - rho[i] * N'[i] */
+         beg = N_ptr[i];
+         end = beg + N_len[i];
+         for (ptr = beg; ptr < end; ptr++)
+         {
+#ifdef GLP_DEBUG
+            j = N_ind[ptr];
+            xassert(1 <= j && j <= n);
+            xassert(stat[j] != GLP_NS);
+#endif
+            trow_vec[N_ind[ptr]] -= temp * N_val[ptr];
+         }
+      }
+      /* construct sparse pattern of the pivot row */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  if (trow_vec[j] != 0.0)
+            trow_ind[++nnz] = j;
+      }
+      csa->trow_nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  update_bbar - update values of basic variables
+*
+*  This routine updates values of all basic variables for the adjacent
+*  basis. */
+
+static void update_bbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+      int n = csa->n;
+#endif
+      double *bbar = csa->bbar;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int p = csa->p;
+      double teta = csa->teta;
+      int i, pos;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+      xassert(p < 0 || 1 <= p && p <= m);
+#endif
+      /* if xN[q] leaves the basis, compute its value in the adjacent
+         basis, where it will replace xB[p] */
+      if (p > 0)
+         bbar[p] = get_xN(csa, q) + teta;
+      /* update values of other basic variables (except xB[p], because
+         it will be replaced by xN[q]) */
+      if (teta == 0.0) goto done;
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+         /* skip xB[p] */
+         if (i == p) continue;
+         /* (change of xB[i]) = alfa[i,q] * (change of xN[q]) */
+         bbar[i] += tcol_vec[i] * teta;
+      }
+done: return;
+}
+
+/***********************************************************************
+*  reeval_cost - recompute reduced cost of non-basic variable xN[q]
+*
+*  This routine recomputes reduced cost of non-basic variable xN[q] for
+*  the current basis more accurately using its direct definition:
+*
+*     d[q] = cN[q] - N'[q] * pi =
+*
+*          = cN[q] - N'[q] * (inv(B') * cB) =
+*
+*          = cN[q] - (cB' * inv(B) * N[q]) =
+*
+*          = cN[q] + cB' * (pivot column).
+*
+*  It is assumed that the pivot column of the simplex table is already
+*  computed. */
+
+static double reeval_cost(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int i, pos;
+      double dq;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      dq = coef[head[m+q]];
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         dq += coef[head[i]] * tcol_vec[i];
+      }
+      return dq;
+}
+
+/***********************************************************************
+*  update_cbar - update reduced costs of non-basic variables
+*
+*  This routine updates reduced costs of all (except fixed) non-basic
+*  variables for the adjacent basis. */
+
+static void update_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *cbar = csa->cbar;
+      int q = csa->q;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int j, pos;
+      double new_dq;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      /* compute reduced cost of xB[p] in the adjacent basis, where it
+         will replace xN[q] */
+#ifdef GLP_DEBUG
+      xassert(trow_vec[q] != 0.0);
+#endif
+      new_dq = (cbar[q] /= trow_vec[q]);
+      /* update reduced costs of other non-basic variables (except
+         xN[q], because it will be replaced by xB[p]) */
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+         /* skip xN[q] */
+         if (j == q) continue;
+         cbar[j] -= trow_vec[j] * new_dq;
+      }
+      return;
+}
+
+/***********************************************************************
+*  update_gamma - update steepest edge coefficients
+*
+*  This routine updates steepest-edge coefficients for the adjacent
+*  basis. */
+
+static void update_gamma(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int p = csa->p;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      double *u = csa->work3;
+      int i, j, k, pos, beg, end, ptr;
+      double gamma_q, delta_q, pivot, s, t, t1, t2;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* the basis changes, so decrease the count */
+      xassert(csa->refct > 0);
+      csa->refct--;
+      /* recompute gamma[q] for the current basis more accurately and
+         compute auxiliary vector u */
+      gamma_q = delta_q = (refsp[head[m+q]] ? 1.0 : 0.0);
+      for (i = 1; i <= m; i++) u[i] = 0.0;
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+         if (refsp[head[i]])
+         {  u[i] = t = tcol_vec[i];
+            gamma_q += t * t;
+         }
+         else
+            u[i] = 0.0;
+      }
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, u);
+      /* update gamma[k] for other non-basic variables (except fixed
+         variables and xN[q], because it will be replaced by xB[p]) */
+      pivot = trow_vec[q];
+#ifdef GLP_DEBUG
+      xassert(pivot != 0.0);
+#endif
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+         /* skip xN[q] */
+         if (j == q) continue;
+         /* compute t */
+         t = trow_vec[j] / pivot;
+         /* compute inner product s = N'[j] * u */
+         k = head[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+            s = u[k];
+         else
+         {  s = 0.0;
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               s -= A_val[ptr] * u[A_ind[ptr]];
+         }
+         /* compute gamma[k] for the adjacent basis */
+         t1 = gamma[j] + t * t * gamma_q + 2.0 * t * s;
+         t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * t * t;
+         gamma[j] = (t1 >= t2 ? t1 : t2);
+         if (gamma[j] < DBL_EPSILON) gamma[j] = DBL_EPSILON;
+      }
+      /* compute gamma[q] for the adjacent basis */
+      if (type[head[p]] == GLP_FX)
+         gamma[q] = 1.0;
+      else
+      {  gamma[q] = gamma_q / (pivot * pivot);
+         if (gamma[q] < DBL_EPSILON) gamma[q] = DBL_EPSILON;
+      }
+      return;
+}
+
+/***********************************************************************
+*  err_in_bbar - compute maximal relative error in primal solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |beta[i] - bbar[i]| / (1 + |beta[i]|),
+*
+*  where beta and bbar are, respectively, directly computed and the
+*  current (updated) values of basic variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_bbar(struct csa *csa)
+{     int m = csa->m;
+      double *bbar = csa->bbar;
+      int i;
+      double e, emax, *beta;
+      beta = xcalloc(1+m, sizeof(double));
+      eval_beta(csa, beta);
+      emax = 0.0;
+      for (i = 1; i <= m; i++)
+      {  e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
+         if (emax < e) emax = e;
+      }
+      xfree(beta);
+      return emax;
+}
+
+/***********************************************************************
+*  err_in_cbar - compute maximal relative error in dual solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |cost[j] - cbar[j]| / (1 + |cost[j]|),
+*
+*  where cost and cbar are, respectively, directly computed and the
+*  current (updated) reduced costs of non-basic non-fixed variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_cbar(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j;
+      double e, emax, cost, *pi;
+      pi = xcalloc(1+m, sizeof(double));
+      eval_pi(csa, pi);
+      emax = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS) continue;
+         cost = eval_cost(csa, pi, j);
+         e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
+         if (emax < e) emax = e;
+      }
+      xfree(pi);
+      return emax;
+}
+
+/***********************************************************************
+*  err_in_gamma - compute maximal relative error in steepest edge cff.
+*
+*  This routine returns maximal relative error:
+*
+*     max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
+*
+*  where gamma'[j] and gamma[j] are, respectively, directly computed
+*  and the current (updated) steepest edge coefficients for non-basic
+*  non-fixed variable x[j].
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_gamma(struct csa *csa)
+{     int n = csa->n;
+      char *stat = csa->stat;
+      double *gamma = csa->gamma;
+      int j;
+      double e, emax, temp;
+      emax = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS)
+         {  xassert(gamma[j] == 1.0);
+            continue;
+         }
+         temp = eval_gamma(csa, j);
+         e = fabs(temp - gamma[j]) / (1.0 + fabs(temp));
+         if (emax < e) emax = e;
+      }
+      return emax;
+}
+
+/***********************************************************************
+*  change_basis - change basis header
+*
+*  This routine changes the basis header to make it corresponding to
+*  the adjacent basis. */
+
+static void change_basis(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+      char *type = csa->type;
+#endif
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int q = csa->q;
+      int p = csa->p;
+      int p_stat = csa->p_stat;
+      int k;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      if (p < 0)
+      {  /* xN[q] goes to its opposite bound */
+#ifdef GLP_DEBUG
+         k = head[m+q]; /* x[k] = xN[q] */
+         xassert(1 <= k && k <= m+n);
+         xassert(type[k] == GLP_DB);
+#endif
+         switch (stat[q])
+         {  case GLP_NL:
+               /* xN[q] increases */
+               stat[q] = GLP_NU;
+               break;
+            case GLP_NU:
+               /* xN[q] decreases */
+               stat[q] = GLP_NL;
+               break;
+            default:
+               xassert(stat != stat);
+         }
+      }
+      else
+      {  /* xB[p] leaves the basis, xN[q] enters the basis */
+#ifdef GLP_DEBUG
+         xassert(1 <= p && p <= m);
+         k = head[p]; /* x[k] = xB[p] */
+         switch (p_stat)
+         {  case GLP_NL:
+               /* xB[p] goes to its lower bound */
+               xassert(type[k] == GLP_LO || type[k] == GLP_DB);
+               break;
+            case GLP_NU:
+               /* xB[p] goes to its upper bound */
+               xassert(type[k] == GLP_UP || type[k] == GLP_DB);
+               break;
+            case GLP_NS:
+               /* xB[p] goes to its fixed value */
+               xassert(type[k] == GLP_NS);
+               break;
+            default:
+               xassert(p_stat != p_stat);
+         }
+#endif
+         /* xB[p] <-> xN[q] */
+         k = head[p], head[p] = head[m+q], head[m+q] = k;
+         stat[q] = (char)p_stat;
+      }
+      return;
+}
+
+/***********************************************************************
+*  set_aux_obj - construct auxiliary objective function
+*
+*  The auxiliary objective function is a separable piecewise linear
+*  convex function, which is the sum of primal infeasibilities:
+*
+*     z = t[1] + ... + t[m+n] -> minimize,
+*
+*  where:
+*
+*            / lb[k] - x[k], if x[k] < lb[k]
+*            |
+*     t[k] = <  0, if lb[k] <= x[k] <= ub[k]
+*            |
+*            \ x[k] - ub[k], if x[k] > ub[k]
+*
+*  This routine computes objective coefficients for the current basis
+*  and returns the number of non-zero terms t[k]. */
+
+static int set_aux_obj(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, k, cnt = 0;
+      double eps;
+      /* use a bit more restrictive tolerance */
+      tol_bnd *= 0.90;
+      /* clear all objective coefficients */
+      for (k = 1; k <= m+n; k++)
+         coef[k] = 0.0;
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+         if (type[k] == GLP_LO || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has lower bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] < lb[k] - eps)
+            {  /* and violates it */
+               coef[k] = -1.0;
+               cnt++;
+            }
+         }
+         if (type[k] == GLP_UP || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has upper bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] > ub[k] + eps)
+            {  /* and violates it */
+               coef[k] = +1.0;
+               cnt++;
+            }
+         }
+      }
+      return cnt;
+}
+
+/***********************************************************************
+*  set_orig_obj - restore original objective function
+*
+*  This routine assigns scaled original objective coefficients to the
+*  working objective function. */
+
+static void set_orig_obj(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *coef = csa->coef;
+      double *obj = csa->obj;
+      double zeta = csa->zeta;
+      int i, j;
+      for (i = 1; i <= m; i++)
+         coef[i] = 0.0;
+      for (j = 1; j <= n; j++)
+         coef[m+j] = zeta * obj[j];
+      return;
+}
+
+/***********************************************************************
+*  check_stab - check numerical stability of basic solution
+*
+*  If the current basic solution is primal feasible (or pseudo feasible
+*  on phase I) within a tolerance, this routine returns zero, otherwise
+*  it returns non-zero. */
+
+static int check_stab(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int phase = csa->phase;
+      double *bbar = csa->bbar;
+      int i, k;
+      double eps;
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (phase == 1 && coef[k] < 0.0)
+         {  /* x[k] must not be greater than its lower bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] > lb[k] + eps) return 1;
+         }
+         else if (phase == 1 && coef[k] > 0.0)
+         {  /* x[k] must not be less than its upper bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] < ub[k] - eps) return 1;
+         }
+         else
+         {  /* either phase = 1 and coef[k] = 0, or phase = 2 */
+            if (type[k] == GLP_LO || type[k] == GLP_DB ||
+                type[k] == GLP_FX)
+            {  /* x[k] must not be less than its lower bound */
+               eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+               if (bbar[i] < lb[k] - eps) return 1;
+            }
+            if (type[k] == GLP_UP || type[k] == GLP_DB ||
+                type[k] == GLP_FX)
+            {  /* x[k] must not be greater then its upper bound */
+               eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+               if (bbar[i] > ub[k] + eps) return 1;
+            }
+         }
+      }
+      /* basic solution is primal feasible within a tolerance */
+      return 0;
+}
+
+/***********************************************************************
+*  check_feas - check primal feasibility of basic solution
+*
+*  If the current basic solution is primal feasible within a tolerance,
+*  this routine returns zero, otherwise it returns non-zero. */
+
+static int check_feas(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+      char *type = csa->type;
+#endif
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, k;
+      double eps;
+      xassert(csa->phase == 1);
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (coef[k] < 0.0)
+         {  /* check if x[k] still violates its lower bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] < lb[k] - eps) return 1;
+         }
+         else if (coef[k] > 0.0)
+         {  /* check if x[k] still violates its upper bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] > ub[k] + eps) return 1;
+         }
+      }
+      /* basic solution is primal feasible within a tolerance */
+      return 0;
+}
+
+/***********************************************************************
+*  eval_obj - compute original objective function
+*
+*  This routine computes the current value of the original objective
+*  function. */
+
+static double eval_obj(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *obj = csa->obj;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, j, k;
+      double sum;
+      sum = obj[0];
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * bbar[i];
+      }
+      /* walk through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * get_xN(csa, j);
+      }
+      return sum;
+}
+
+/***********************************************************************
+*  display - display the search progress
+*
+*  This routine displays some information about the search progress
+*  that includes:
+*
+*  the search phase;
+*
+*  the number of simplex iterations performed by the solver;
+*
+*  the original objective value;
+*
+*  the sum of (scaled) primal infeasibilities;
+*
+*  the number of basic fixed variables. */
+
+static void display(struct csa *csa, const glp_smcp *parm, int spec)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int phase = csa->phase;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, k, cnt;
+      double sum;
+      if (parm->msg_lev < GLP_MSG_ON) goto skip;
+      if (parm->out_dly > 0 &&
+         1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
+         goto skip;
+      if (csa->it_cnt == csa->it_dpy) goto skip;
+      if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
+      /* compute the sum of primal infeasibilities and determine the
+         number of basic fixed variables */
+      sum = 0.0, cnt = 0;
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (type[k] == GLP_LO || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has lower bound */
+            if (bbar[i] < lb[k])
+               sum += (lb[k] - bbar[i]);
+         }
+         if (type[k] == GLP_UP || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has upper bound */
+            if (bbar[i] > ub[k])
+               sum += (bbar[i] - ub[k]);
+         }
+         if (type[k] == GLP_FX) cnt++;
+      }
+      xprintf("%c%6d: obj = %17.9e  infeas = %10.3e (%d)\n",
+         phase == 1 ? ' ' : '*', csa->it_cnt, eval_obj(csa), sum, cnt);
+      csa->it_dpy = csa->it_cnt;
+skip: return;
+}
+
+/***********************************************************************
+*  store_sol - store basic solution back to the problem object
+*
+*  This routine stores basic solution components back to the problem
+*  object. */
+
+static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
+      int d_stat, int ray)
+{     int m = csa->m;
+      int n = csa->n;
+      double zeta = csa->zeta;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int i, j, k;
+#ifdef GLP_DEBUG
+      xassert(lp->m == m);
+      xassert(lp->n == n);
+#endif
+      /* basis factorization */
+#ifdef GLP_DEBUG
+      xassert(!lp->valid && lp->bfd == NULL);
+      xassert(csa->valid && csa->bfd != NULL);
+#endif
+      lp->valid = 1, csa->valid = 0;
+      lp->bfd = csa->bfd, csa->bfd = NULL;
+      memcpy(&lp->head[1], &head[1], m * sizeof(int));
+      /* basic solution status */
+      lp->pbs_stat = p_stat;
+      lp->dbs_stat = d_stat;
+      /* objective function value */
+      lp->obj_val = eval_obj(csa);
+      /* simplex iteration count */
+      lp->it_cnt = csa->it_cnt;
+      /* unbounded ray */
+      lp->some = ray;
+      /* basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = GLP_BS;
+            row->bind = i;
+            row->prim = bbar[i] / row->rii;
+            row->dual = 0.0;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = GLP_BS;
+            col->bind = i;
+            col->prim = bbar[i] * col->sjj;
+            col->dual = 0.0;
+         }
+      }
+      /* non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = stat[j];
+            row->bind = 0;
+#if 0
+            row->prim = get_xN(csa, j) / row->rii;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  row->prim = row->lb; break;
+               case GLP_NU:
+                  row->prim = row->ub; break;
+               case GLP_NF:
+                  row->prim = 0.0; break;
+               case GLP_NS:
+                  row->prim = row->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            row->dual = (cbar[j] * row->rii) / zeta;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = stat[j];
+            col->bind = 0;
+#if 0
+            col->prim = get_xN(csa, j) * col->sjj;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  col->prim = col->lb; break;
+               case GLP_NU:
+                  col->prim = col->ub; break;
+               case GLP_NF:
+                  col->prim = 0.0; break;
+               case GLP_NS:
+                  col->prim = col->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            col->dual = (cbar[j] / col->sjj) / zeta;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  free_csa - deallocate common storage area
+*
+*  This routine frees all the memory allocated to arrays in the common
+*  storage area (CSA). */
+
+static void free_csa(struct csa *csa)
+{     xfree(csa->type);
+      xfree(csa->lb);
+      xfree(csa->ub);
+      xfree(csa->coef);
+      xfree(csa->obj);
+      xfree(csa->A_ptr);
+      xfree(csa->A_ind);
+      xfree(csa->A_val);
+      xfree(csa->head);
+      xfree(csa->stat);
+      xfree(csa->N_ptr);
+      xfree(csa->N_len);
+      xfree(csa->N_ind);
+      xfree(csa->N_val);
+      xfree(csa->bbar);
+      xfree(csa->cbar);
+      xfree(csa->refsp);
+      xfree(csa->gamma);
+      xfree(csa->tcol_ind);
+      xfree(csa->tcol_vec);
+      xfree(csa->trow_ind);
+      xfree(csa->trow_vec);
+      xfree(csa->work1);
+      xfree(csa->work2);
+      xfree(csa->work3);
+      xfree(csa->work4);
+      xfree(csa);
+      return;
+}
+
+/***********************************************************************
+*  spx_primal - core LP solver based on the primal simplex method
+*
+*  SYNOPSIS
+*
+*  #include "glpspx.h"
+*  int spx_primal(glp_prob *lp, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine spx_primal is a core LP solver based on the two-phase
+*  primal simplex method.
+*
+*  RETURNS
+*
+*  0  LP instance has been successfully solved.
+*
+*  GLP_EITLIM
+*     Iteration limit has been exhausted.
+*
+*  GLP_ETMLIM
+*     Time limit has been exhausted.
+*
+*  GLP_EFAIL
+*     The solver failed to solve LP instance. */
+
+int spx_primal(glp_prob *lp, const glp_smcp *parm)
+{     struct csa *csa;
+      int binv_st = 2;
+      /* status of basis matrix factorization:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int bbar_st = 0;
+      /* status of primal values of basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int cbar_st = 0;
+      /* status of reduced costs of non-basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int rigorous = 0;
+      /* rigorous mode flag; this flag is used to enable iterative
+         refinement on computing pivot rows and columns of the simplex
+         table */
+      int check = 0;
+      int p_stat, d_stat, ret;
+      /* allocate and initialize the common storage area */
+      csa = alloc_csa(lp);
+      init_csa(csa, lp);
+      if (parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Objective scale factor = %g\n", csa->zeta);
+loop: /* main loop starts here */
+      /* compute factorization of the basis matrix */
+      if (binv_st == 0)
+      {  ret = invert_B(csa);
+         if (ret != 0)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+            {  xprintf("Error: unable to factorize the basis matrix (%d"
+                  ")\n", ret);
+               xprintf("Sorry, basis recovery procedure not implemented"
+                  " yet\n");
+            }
+            xassert(!lp->valid && lp->bfd == NULL);
+            lp->bfd = csa->bfd, csa->bfd = NULL;
+            lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+            lp->obj_val = 0.0;
+            lp->it_cnt = csa->it_cnt;
+            lp->some = 0;
+            ret = GLP_EFAIL;
+            goto done;
+         }
+         csa->valid = 1;
+         binv_st = 1; /* just computed */
+         /* invalidate basic solution components */
+         bbar_st = cbar_st = 0;
+      }
+      /* compute primal values of basic variables */
+      if (bbar_st == 0)
+      {  eval_bbar(csa);
+         bbar_st = 1; /* just computed */
+         /* determine the search phase, if not determined yet */
+         if (csa->phase == 0)
+         {  if (set_aux_obj(csa, parm->tol_bnd) > 0)
+            {  /* current basic solution is primal infeasible */
+               /* start to minimize the sum of infeasibilities */
+               csa->phase = 1;
+            }
+            else
+            {  /* current basic solution is primal feasible */
+               /* start to minimize the original objective function */
+               set_orig_obj(csa);
+               csa->phase = 2;
+            }
+            xassert(check_stab(csa, parm->tol_bnd) == 0);
+            /* working objective coefficients have been changed, so
+               invalidate reduced costs */
+            cbar_st = 0;
+            display(csa, parm, 1);
+         }
+         /* make sure that the current basic solution remains primal
+            feasible (or pseudo feasible on phase I) */
+         if (check_stab(csa, parm->tol_bnd))
+         {  /* there are excessive bound violations due to round-off
+               errors */
+            if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: numerical instability (primal simplex,"
+                  " phase %s)\n", csa->phase == 1 ? "I" : "II");
+            /* restart the search */
+            csa->phase = 0;
+            binv_st = 0;
+            rigorous = 5;
+            goto loop;
+         }
+      }
+      xassert(csa->phase == 1 || csa->phase == 2);
+      /* on phase I we do not need to wait until the current basic
+         solution becomes dual feasible; it is sufficient to make sure
+         that no basic variable violates its bounds */
+      if (csa->phase == 1 && !check_feas(csa, parm->tol_bnd))
+      {  /* the current basis is primal feasible; switch to phase II */
+         csa->phase = 2;
+         set_orig_obj(csa);
+         cbar_st = 0;
+         display(csa, parm, 1);
+      }
+      /* compute reduced costs of non-basic variables */
+      if (cbar_st == 0)
+      {  eval_cbar(csa);
+         cbar_st = 1; /* just computed */
+      }
+      /* redefine the reference space, if required */
+      switch (parm->pricing)
+      {  case GLP_PT_STD:
+            break;
+         case GLP_PT_PSE:
+            if (csa->refct == 0) reset_refsp(csa);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      /* at this point the basis factorization and all basic solution
+         components are valid */
+      xassert(binv_st && bbar_st && cbar_st);
+      /* check accuracy of current basic solution components (only for
+         debugging) */
+      if (check)
+      {  double e_bbar = err_in_bbar(csa);
+         double e_cbar = err_in_cbar(csa);
+         double e_gamma =
+            (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
+         xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
+            e_bbar, e_cbar, e_gamma);
+         xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
+      }
+      /* check if the iteration limit has been exhausted */
+      if (parm->it_lim < INT_MAX &&
+          csa->it_cnt - csa->it_beg >= parm->it_lim)
+      {  if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               p_stat = GLP_INFEAS;
+               set_orig_obj(csa);
+               eval_cbar(csa);
+               break;
+            case 2:
+               p_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         chuzc(csa, parm->tol_dj);
+         d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = GLP_EITLIM;
+         goto done;
+      }
+      /* check if the time limit has been exhausted */
+      if (parm->tm_lim < INT_MAX &&
+          1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
+      {  if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               p_stat = GLP_INFEAS;
+               set_orig_obj(csa);
+               eval_cbar(csa);
+               break;
+            case 2:
+               p_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         chuzc(csa, parm->tol_dj);
+         d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = GLP_ETMLIM;
+         goto done;
+      }
+      /* display the search progress */
+      display(csa, parm, 0);
+      /* choose non-basic variable xN[q] */
+      chuzc(csa, parm->tol_dj);
+      if (csa->q == 0)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+               p_stat = GLP_NOFEAS;
+               set_orig_obj(csa);
+               eval_cbar(csa);
+               chuzc(csa, parm->tol_dj);
+               d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("OPTIMAL SOLUTION FOUND\n");
+               p_stat = d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = 0;
+         goto done;
+      }
+      /* compute pivot column of the simplex table */
+      eval_tcol(csa);
+      if (rigorous) refine_tcol(csa);
+      sort_tcol(csa, parm->tol_piv);
+      /* check accuracy of the reduced cost of xN[q] */
+      {  double d1 = csa->cbar[csa->q]; /* less accurate */
+         double d2 = reeval_cost(csa);  /* more accurate */
+         xassert(d1 != 0.0);
+         if (fabs(d1 - d2) > 1e-5 * (1.0 + fabs(d2)) ||
+             !(d1 < 0.0 && d2 < 0.0 || d1 > 0.0 && d2 > 0.0))
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("d1 = %.12g; d2 = %.12g\n", d1, d2);
+            if (cbar_st != 1 || !rigorous)
+            {  if (cbar_st != 1) cbar_st = 0;
+               rigorous = 5;
+               goto loop;
+            }
+         }
+         /* replace cbar[q] by more accurate value keeping its sign */
+         if (d1 > 0.0)
+            csa->cbar[csa->q] = (d2 > 0.0 ? d2 : +DBL_EPSILON);
+         else
+            csa->cbar[csa->q] = (d2 < 0.0 ? d2 : -DBL_EPSILON);
+      }
+      /* choose basic variable xB[p] */
+      switch (parm->r_test)
+      {  case GLP_RT_STD:
+            chuzr(csa, 0.0);
+            break;
+         case GLP_RT_HAR:
+            chuzr(csa, 0.30 * parm->tol_bnd);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      if (csa->p == 0)
+      {  if (bbar_st != 1 || cbar_st != 1 || !rigorous)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            rigorous = 1;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("Error: unable to choose basic variable on ph"
+                     "ase I\n");
+               xassert(!lp->valid && lp->bfd == NULL);
+               lp->bfd = csa->bfd, csa->bfd = NULL;
+               lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+               lp->obj_val = 0.0;
+               lp->it_cnt = csa->it_cnt;
+               lp->some = 0;
+               ret = GLP_EFAIL;
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+               store_sol(csa, lp, GLP_FEAS, GLP_NOFEAS,
+                  csa->head[csa->m+csa->q]);
+               ret = 0;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         goto done;
+      }
+      /* check if the pivot element is acceptable */
+      if (csa->p > 0)
+      {  double piv = csa->tcol_vec[csa->p];
+         double eps = 1e-5 * (1.0 + 0.01 * csa->tcol_max);
+         if (fabs(piv) < eps)
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv = %.12g; eps = %g\n", piv, eps);
+            if (!rigorous)
+            {  rigorous = 5;
+               goto loop;
+            }
+         }
+      }
+      /* now xN[q] and xB[p] have been chosen anyhow */
+      /* compute pivot row of the simplex table */
+      if (csa->p > 0)
+      {  double *rho = csa->work4;
+         eval_rho(csa, rho);
+         if (rigorous) refine_rho(csa, rho);
+         eval_trow(csa, rho);
+      }
+      /* accuracy check based on the pivot element */
+      if (csa->p > 0)
+      {  double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
+         double piv2 = csa->trow_vec[csa->q]; /* less accurate */
+         xassert(piv1 != 0.0);
+         if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
+             !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
+            if (binv_st != 1 || !rigorous)
+            {  if (binv_st != 1) binv_st = 0;
+               rigorous = 5;
+               goto loop;
+            }
+            /* use more accurate version in the pivot row */
+            if (csa->trow_vec[csa->q] == 0.0)
+            {  csa->trow_nnz++;
+               xassert(csa->trow_nnz <= csa->n);
+               csa->trow_ind[csa->trow_nnz] = csa->q;
+            }
+            csa->trow_vec[csa->q] = piv1;
+         }
+      }
+      /* update primal values of basic variables */
+      update_bbar(csa);
+      bbar_st = 2; /* updated */
+      /* update reduced costs of non-basic variables */
+      if (csa->p > 0)
+      {  update_cbar(csa);
+         cbar_st = 2; /* updated */
+         /* on phase I objective coefficient of xB[p] in the adjacent
+            basis becomes zero */
+         if (csa->phase == 1)
+         {  int k = csa->head[csa->p]; /* x[k] = xB[p] -> xN[q] */
+            csa->cbar[csa->q] -= csa->coef[k];
+            csa->coef[k] = 0.0;
+         }
+      }
+      /* update steepest edge coefficients */
+      if (csa->p > 0)
+      {  switch (parm->pricing)
+         {  case GLP_PT_STD:
+               break;
+            case GLP_PT_PSE:
+               if (csa->refct > 0) update_gamma(csa);
+               break;
+            default:
+               xassert(parm != parm);
+         }
+      }
+      /* update factorization of the basis matrix */
+      if (csa->p > 0)
+      {  ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
+         if (ret == 0)
+            binv_st = 2; /* updated */
+         else
+         {  csa->valid = 0;
+            binv_st = 0; /* invalid */
+         }
+      }
+      /* update matrix N */
+      if (csa->p > 0)
+      {  del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
+         if (csa->type[csa->head[csa->p]] != GLP_FX)
+            add_N_col(csa, csa->q, csa->head[csa->p]);
+      }
+      /* change the basis header */
+      change_basis(csa);
+      /* iteration complete */
+      csa->it_cnt++;
+      if (rigorous > 0) rigorous--;
+      goto loop;
+done: /* deallocate the common storage area */
+      free_csa(csa);
+      /* return to the calling program */
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpspx02.c b/optional/glpk/glpspx02.c
new file mode 100644
index 0000000..7e30e3c
--- /dev/null
+++ b/optional/glpk/glpspx02.c
@@ -0,0 +1,3084 @@
+/* glpspx02.c (dual simplex method) */
+
+/***********************************************************************
+*  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 "-Wcomment"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#endif
+
+#include "glpspx.h"
+
+#define GLP_DEBUG 1
+
+#if 0
+#define GLP_LONG_STEP 1
+#endif
+
+struct csa
+{     /* common storage area */
+      /*--------------------------------------------------------------*/
+      /* LP data */
+      int m;
+      /* number of rows (auxiliary variables), m > 0 */
+      int n;
+      /* number of columns (structural variables), n > 0 */
+      char *type; /* char type[1+m+n]; */
+      /* type[0] is not used;
+         type[k], 1 <= k <= m+n, is the type of variable x[k]:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double *lb; /* double lb[1+m+n]; */
+      /* lb[0] is not used;
+         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+         if x[k] has no lower bound, lb[k] is zero */
+      double *ub; /* double ub[1+m+n]; */
+      /* ub[0] is not used;
+         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+         if x[k] has no upper bound, ub[k] is zero;
+         if x[k] is of fixed type, ub[k] is the same as lb[k] */
+      double *coef; /* double coef[1+m+n]; */
+      /* coef[0] is not used;
+         coef[k], 1 <= k <= m+n, is an objective coefficient at
+         variable x[k] */
+      /*--------------------------------------------------------------*/
+      /* original bounds of variables */
+      char *orig_type; /* char orig_type[1+m+n]; */
+      double *orig_lb; /* double orig_lb[1+m+n]; */
+      double *orig_ub; /* double orig_ub[1+m+n]; */
+      /*--------------------------------------------------------------*/
+      /* original objective function */
+      double *obj; /* double obj[1+n]; */
+      /* obj[0] is a constant term of the original objective function;
+         obj[j], 1 <= j <= n, is an original objective coefficient at
+         structural variable x[m+j] */
+      double zeta;
+      /* factor used to scale original objective coefficients; its
+         sign defines original optimization direction: zeta > 0 means
+         minimization, zeta < 0 means maximization */
+      /*--------------------------------------------------------------*/
+      /* constraint matrix A; it has m rows and n columns and is stored
+         by columns */
+      int *A_ptr; /* int A_ptr[1+n+1]; */
+      /* A_ptr[0] is not used;
+         A_ptr[j], 1 <= j <= n, is starting position of j-th column in
+         arrays A_ind and A_val; note that A_ptr[1] is always 1;
+         A_ptr[n+1] indicates the position after the last element in
+         arrays A_ind and A_val */
+      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+      /* row indices */
+      double *A_val; /* double A_val[A_ptr[n+1]]; */
+      /* non-zero element values */
+#if 1 /* 06/IV-2009 */
+      /* constraint matrix A stored by rows */
+      int *AT_ptr; /* int AT_ptr[1+m+1];
+      /* AT_ptr[0] is not used;
+         AT_ptr[i], 1 <= i <= m, is starting position of i-th row in
+         arrays AT_ind and AT_val; note that AT_ptr[1] is always 1;
+         AT_ptr[m+1] indicates the position after the last element in
+         arrays AT_ind and AT_val */
+      int *AT_ind; /* int AT_ind[AT_ptr[m+1]]; */
+      /* column indices */
+      double *AT_val; /* double AT_val[AT_ptr[m+1]]; */
+      /* non-zero element values */
+#endif
+      /*--------------------------------------------------------------*/
+      /* basis header */
+      int *head; /* int head[1+m+n]; */
+      /* head[0] is not used;
+         head[i], 1 <= i <= m, is the ordinal number of basic variable
+         xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
+         matrix B is k-th column of matrix (I|-A);
+         head[m+j], 1 <= j <= n, is the ordinal number of non-basic
+         variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
+         column of matrix N is k-th column of matrix (I|-A) */
+#if 1 /* 06/IV-2009 */
+      int *bind; /* int bind[1+m+n]; */
+      /* bind[0] is not used;
+         bind[k], 1 <= k <= m+n, is the position of k-th column of the
+         matrix (I|-A) in the matrix (B|N); that is, bind[k] = k' means
+         that head[k'] = k */
+#endif
+      char *stat; /* char stat[1+n]; */
+      /* stat[0] is not used;
+         stat[j], 1 <= j <= n, is the status of non-basic variable
+         xN[j], which defines its active bound:
+         GLP_NL - lower bound is active
+         GLP_NU - upper bound is active
+         GLP_NF - free variable
+         GLP_NS - fixed variable */
+      /*--------------------------------------------------------------*/
+      /* matrix B is the basis matrix; it is composed from columns of
+         the augmented constraint matrix (I|-A) corresponding to basic
+         variables and stored in a factorized (invertable) form */
+      int valid;
+      /* factorization is valid only if this flag is set */
+      BFD *bfd; /* BFD bfd[1:m,1:m]; */
+      /* factorized (invertable) form of the basis matrix */
+#if 0 /* 06/IV-2009 */
+      /*--------------------------------------------------------------*/
+      /* matrix N is a matrix composed from columns of the augmented
+         constraint matrix (I|-A) corresponding to non-basic variables
+         except fixed ones; it is stored by rows and changes every time
+         the basis changes */
+      int *N_ptr; /* int N_ptr[1+m+1]; */
+      /* N_ptr[0] is not used;
+         N_ptr[i], 1 <= i <= m, is starting position of i-th row in
+         arrays N_ind and N_val; note that N_ptr[1] is always 1;
+         N_ptr[m+1] indicates the position after the last element in
+         arrays N_ind and N_val */
+      int *N_len; /* int N_len[1+m]; */
+      /* N_len[0] is not used;
+         N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
+      int *N_ind; /* int N_ind[N_ptr[m+1]]; */
+      /* column indices */
+      double *N_val; /* double N_val[N_ptr[m+1]]; */
+      /* non-zero element values */
+#endif
+      /*--------------------------------------------------------------*/
+      /* working parameters */
+      int phase;
+      /* search phase:
+         0 - not determined yet
+         1 - search for dual feasible solution
+         2 - search for optimal solution */
+      glp_long tm_beg;
+      /* time value at the beginning of the search */
+      int it_beg;
+      /* simplex iteration count at the beginning of the search */
+      int it_cnt;
+      /* simplex iteration count; it increases by one every time the
+         basis changes */
+      int it_dpy;
+      /* simplex iteration count at the most recent display output */
+      /*--------------------------------------------------------------*/
+      /* basic solution components */
+      double *bbar; /* double bbar[1+m]; */
+      /* bbar[0] is not used on phase I; on phase II it is the current
+         value of the original objective function;
+         bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
+         (if xB[i] is free, its primal value is not updated) */
+      double *cbar; /* double cbar[1+n]; */
+      /* cbar[0] is not used;
+         cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
+         xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
+      /*--------------------------------------------------------------*/
+      /* the following pricing technique options may be used:
+         GLP_PT_STD - standard ("textbook") pricing;
+         GLP_PT_PSE - projected steepest edge;
+         GLP_PT_DVX - Devex pricing (not implemented yet);
+         in case of GLP_PT_STD the reference space is not used, and all
+         steepest edge coefficients are set to 1 */
+      int refct;
+      /* this count is set to an initial value when the reference space
+         is defined and decreases by one every time the basis changes;
+         once this count reaches zero, the reference space is redefined
+         again */
+      char *refsp; /* char refsp[1+m+n]; */
+      /* refsp[0] is not used;
+         refsp[k], 1 <= k <= m+n, is the flag which means that variable
+         x[k] belongs to the current reference space */
+      double *gamma; /* double gamma[1+m]; */
+      /* gamma[0] is not used;
+         gamma[i], 1 <= i <= n, is the steepest edge coefficient for
+         basic variable xB[i]; if xB[i] is free, gamma[i] is not used
+         and just set to 1 */
+      /*--------------------------------------------------------------*/
+      /* basic variable xB[p] chosen to leave the basis */
+      int p;
+      /* index of the basic variable xB[p] chosen, 1 <= p <= m;
+         if the set of eligible basic variables is empty (i.e. if the
+         current basic solution is primal feasible within a tolerance)
+         and thus no variable has been chosen, p is set to 0 */
+      double delta;
+      /* change of xB[p] in the adjacent basis;
+         delta > 0 means that xB[p] violates its lower bound and will
+         increase to achieve it in the adjacent basis;
+         delta < 0 means that xB[p] violates its upper bound and will
+         decrease to achieve it in the adjacent basis */
+      /*--------------------------------------------------------------*/
+      /* pivot row of the simplex table corresponding to basic variable
+         xB[p] chosen is the following vector:
+            T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
+         where B' is a matrix transposed to the current basis matrix,
+         N' is a matrix, whose rows are columns of the matrix (I|-A)
+         corresponding to non-basic non-fixed variables */
+      int trow_nnz;
+      /* number of non-zero components, 0 <= nnz <= n */
+      int *trow_ind; /* int trow_ind[1+n]; */
+      /* trow_ind[0] is not used;
+         trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
+      double *trow_vec; /* int trow_vec[1+n]; */
+      /* trow_vec[0] is not used;
+         trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
+         of the row */
+      double trow_max;
+      /* infinity (maximum) norm of the row (max |trow_vec[j]|) */
+      int trow_num;
+      /* number of significant non-zero components, which means that:
+         |trow_vec[j]| >= eps for j in trow_ind[1,...,num],
+         |tcol_vec[j]| <  eps for j in trow_ind[num+1,...,nnz],
+         where eps is a pivot tolerance */
+      /*--------------------------------------------------------------*/
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      int nbps;
+      /* number of breakpoints, 0 <= nbps <= n */
+      struct bkpt
+      {     int j;
+            /* index of non-basic variable xN[j], 1 <= j <= n */
+            double t;
+            /* value of dual ray parameter at breakpoint, t >= 0 */
+            double dz;
+            /* dz = zeta(t = t[k]) - zeta(t = 0) */
+      } *bkpt; /* struct bkpt bkpt[1+n]; */
+      /* bkpt[0] is not used;
+         bkpt[k], 1 <= k <= nbps, is k-th breakpoint of the dual
+         objective */
+#endif
+      /*--------------------------------------------------------------*/
+      /* non-basic variable xN[q] chosen to enter the basis */
+      int q;
+      /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
+         if no variable has been chosen, q is set to 0 */
+      double new_dq;
+      /* reduced cost of xN[q] in the adjacent basis (it is the change
+         of lambdaB[p]) */
+      /*--------------------------------------------------------------*/
+      /* pivot column of the simplex table corresponding to non-basic
+         variable xN[q] chosen is the following vector:
+            T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+         where B is the current basis matrix, N[q] is a column of the
+         matrix (I|-A) corresponding to xN[q] */
+      int tcol_nnz;
+      /* number of non-zero components, 0 <= nnz <= m */
+      int *tcol_ind; /* int tcol_ind[1+m]; */
+      /* tcol_ind[0] is not used;
+         tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
+      double *tcol_vec; /* double tcol_vec[1+m]; */
+      /* tcol_vec[0] is not used;
+         tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
+         of the column */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      double *work1; /* double work1[1+m]; */
+      double *work2; /* double work2[1+m]; */
+      double *work3; /* double work3[1+m]; */
+      double *work4; /* double work4[1+m]; */
+};
+
+static const double kappa = 0.10;
+
+/***********************************************************************
+*  alloc_csa - allocate common storage area
+*
+*  This routine allocates all arrays in the common storage area (CSA)
+*  and returns a pointer to the CSA. */
+
+static struct csa *alloc_csa(glp_prob *lp)
+{     struct csa *csa;
+      int m = lp->m;
+      int n = lp->n;
+      int nnz = lp->nnz;
+      csa = xmalloc(sizeof(struct csa));
+      xassert(m > 0 && n > 0);
+      csa->m = m;
+      csa->n = n;
+      csa->type = xcalloc(1+m+n, sizeof(char));
+      csa->lb = xcalloc(1+m+n, sizeof(double));
+      csa->ub = xcalloc(1+m+n, sizeof(double));
+      csa->coef = xcalloc(1+m+n, sizeof(double));
+      csa->orig_type = xcalloc(1+m+n, sizeof(char));
+      csa->orig_lb = xcalloc(1+m+n, sizeof(double));
+      csa->orig_ub = xcalloc(1+m+n, sizeof(double));
+      csa->obj = xcalloc(1+n, sizeof(double));
+      csa->A_ptr = xcalloc(1+n+1, sizeof(int));
+      csa->A_ind = xcalloc(1+nnz, sizeof(int));
+      csa->A_val = xcalloc(1+nnz, sizeof(double));
+#if 1 /* 06/IV-2009 */
+      csa->AT_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->AT_ind = xcalloc(1+nnz, sizeof(int));
+      csa->AT_val = xcalloc(1+nnz, sizeof(double));
+#endif
+      csa->head = xcalloc(1+m+n, sizeof(int));
+#if 1 /* 06/IV-2009 */
+      csa->bind = xcalloc(1+m+n, sizeof(int));
+#endif
+      csa->stat = xcalloc(1+n, sizeof(char));
+#if 0 /* 06/IV-2009 */
+      csa->N_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->N_len = xcalloc(1+m, sizeof(int));
+      csa->N_ind = NULL; /* will be allocated later */
+      csa->N_val = NULL; /* will be allocated later */
+#endif
+      csa->bbar = xcalloc(1+m, sizeof(double));
+      csa->cbar = xcalloc(1+n, sizeof(double));
+      csa->refsp = xcalloc(1+m+n, sizeof(char));
+      csa->gamma = xcalloc(1+m, sizeof(double));
+      csa->trow_ind = xcalloc(1+n, sizeof(int));
+      csa->trow_vec = xcalloc(1+n, sizeof(double));
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      csa->bkpt = xcalloc(1+n, sizeof(struct bkpt));
+#endif
+      csa->tcol_ind = xcalloc(1+m, sizeof(int));
+      csa->tcol_vec = xcalloc(1+m, sizeof(double));
+      csa->work1 = xcalloc(1+m, sizeof(double));
+      csa->work2 = xcalloc(1+m, sizeof(double));
+      csa->work3 = xcalloc(1+m, sizeof(double));
+      csa->work4 = xcalloc(1+m, sizeof(double));
+      return csa;
+}
+
+/***********************************************************************
+*  init_csa - initialize common storage area
+*
+*  This routine initializes all data structures in the common storage
+*  area (CSA). */
+
+static void init_csa(struct csa *csa, glp_prob *lp)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      char *orig_type = csa->orig_type;
+      double *orig_lb = csa->orig_lb;
+      double *orig_ub = csa->orig_ub;
+      double *obj = csa->obj;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+#if 1 /* 06/IV-2009 */
+      int *AT_ptr = csa->AT_ptr;
+      int *AT_ind = csa->AT_ind;
+      double *AT_val = csa->AT_val;
+#endif
+      int *head = csa->head;
+#if 1 /* 06/IV-2009 */
+      int *bind = csa->bind;
+#endif
+      char *stat = csa->stat;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int i, j, k, loc;
+      double cmax;
+      /* auxiliary variables */
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         type[i] = (char)row->type;
+         lb[i] = row->lb * row->rii;
+         ub[i] = row->ub * row->rii;
+         coef[i] = 0.0;
+      }
+      /* structural variables */
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         type[m+j] = (char)col->type;
+         lb[m+j] = col->lb / col->sjj;
+         ub[m+j] = col->ub / col->sjj;
+         coef[m+j] = col->coef * col->sjj;
+      }
+      /* original bounds of variables */
+      memcpy(&orig_type[1], &type[1], (m+n) * sizeof(char));
+      memcpy(&orig_lb[1], &lb[1], (m+n) * sizeof(double));
+      memcpy(&orig_ub[1], &ub[1], (m+n) * sizeof(double));
+      /* original objective function */
+      obj[0] = lp->c0;
+      memcpy(&obj[1], &coef[m+1], n * sizeof(double));
+      /* factor used to scale original objective coefficients */
+      cmax = 0.0;
+      for (j = 1; j <= n; j++)
+         if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
+      if (cmax == 0.0) cmax = 1.0;
+      switch (lp->dir)
+      {  case GLP_MIN:
+            csa->zeta = + 1.0 / cmax;
+            break;
+         case GLP_MAX:
+            csa->zeta = - 1.0 / cmax;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+#if 1
+      if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
+#endif
+      /* scale working objective coefficients */
+      for (j = 1; j <= n; j++) coef[m+j] *= csa->zeta;
+      /* matrix A (by columns) */
+      loc = 1;
+      for (j = 1; j <= n; j++)
+      {  GLPAIJ *aij;
+         A_ptr[j] = loc;
+         for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+         {  A_ind[loc] = aij->row->i;
+            A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      A_ptr[n+1] = loc;
+      xassert(loc-1 == lp->nnz);
+#if 1 /* 06/IV-2009 */
+      /* matrix A (by rows) */
+      loc = 1;
+      for (i = 1; i <= m; i++)
+      {  GLPAIJ *aij;
+         AT_ptr[i] = loc;
+         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  AT_ind[loc] = aij->col->j;
+            AT_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      AT_ptr[m+1] = loc;
+      xassert(loc-1 == lp->nnz);
+#endif
+      /* basis header */
+      xassert(lp->valid);
+      memcpy(&head[1], &lp->head[1], m * sizeof(int));
+      k = 0;
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         if (row->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = i;
+            stat[k] = (char)row->stat;
+         }
+      }
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         if (col->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = m + j;
+            stat[k] = (char)col->stat;
+         }
+      }
+      xassert(k == n);
+#if 1 /* 06/IV-2009 */
+      for (k = 1; k <= m+n; k++)
+         bind[head[k]] = k;
+#endif
+      /* factorization of matrix B */
+      csa->valid = 1, lp->valid = 0;
+      csa->bfd = lp->bfd, lp->bfd = NULL;
+#if 0 /* 06/IV-2009 */
+      /* matrix N (by rows) */
+      alloc_N(csa);
+      build_N(csa);
+#endif
+      /* working parameters */
+      csa->phase = 0;
+      csa->tm_beg = xtime();
+      csa->it_beg = csa->it_cnt = lp->it_cnt;
+      csa->it_dpy = -1;
+      /* reference space and steepest edge coefficients */
+      csa->refct = 0;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (i = 1; i <= m; i++) gamma[i] = 1.0;
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  invert_B - compute factorization of the basis matrix
+*
+*  This routine computes factorization of the current basis matrix B.
+*
+*  If the operation is successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int inv_col(void *info, int i, int ind[], double val[])
+{     /* this auxiliary routine returns row indices and numeric values
+         of non-zero elements of i-th column of the basis matrix */
+      struct csa *csa = info;
+      int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int k, len, ptr, t;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+#endif
+      k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* B[i] is k-th column of submatrix I */
+         len = 1;
+         ind[1] = k;
+         val[1] = 1.0;
+      }
+      else
+      {  /* B[i] is (k-m)-th column of submatrix (-A) */
+         ptr = A_ptr[k-m];
+         len = A_ptr[k-m+1] - ptr;
+         memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
+         memcpy(&val[1], &A_val[ptr], len * sizeof(double));
+         for (t = 1; t <= len; t++) val[t] = - val[t];
+      }
+      return len;
+}
+
+static int invert_B(struct csa *csa)
+{     int ret;
+      ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
+      csa->valid = (ret == 0);
+      return ret;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  update_B - update factorization of the basis matrix
+*
+*  This routine replaces i-th column of the basis matrix B by k-th
+*  column of the augmented constraint matrix (I|-A) and then updates
+*  the factorization of B.
+*
+*  If the factorization has been successfully updated, the routine
+*  returns zero, otherwise non-zero. */
+
+static int update_B(struct csa *csa, int i, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int ret;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* new i-th column of B is k-th column of I */
+         int ind[1+1];
+         double val[1+1];
+         ind[1] = k;
+         val[1] = 1.0;
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
+      }
+      else
+      {  /* new i-th column of B is (k-m)-th column of (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         double *val = csa->work1;
+         int beg, end, ptr, len;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         len = 0;
+         for (ptr = beg; ptr < end; ptr++)
+            val[++len] = - A_val[ptr];
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
+      }
+      csa->valid = (ret == 0);
+      return ret;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  error_ftran - compute residual vector r = h - B * x
+*
+*  This routine computes the residual vector r = h - B * x, where B is
+*  the current basis matrix, h is the vector of right-hand sides, x is
+*  the solution vector. */
+
+static void error_ftran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector:
+         r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
+         where B[1], ..., B[m] are columns of matrix B */
+      memcpy(&r[1], &h[1], m * sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  temp = x[i];
+         if (temp == 0.0) continue;
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            r[k] -= temp;
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               r[A_ind[ptr]] += A_val[ptr] * temp;
+         }
+      }
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_ftran - refine solution of B * x = h
+*
+*  This routine performs one iteration to refine the solution of
+*  the system B * x = h, where B is the current basis matrix, h is the
+*  vector of right-hand sides, x is the solution vector. */
+
+static void refine_ftran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B * x */
+      error_ftran(csa, h, x, r);
+      /* compute the correction vector d = inv(B) * r */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  error_btran - compute residual vector r = h - B'* x
+*
+*  This routine computes the residual vector r = h - B'* x, where B'
+*  is a matrix transposed to the current basis matrix, h is the vector
+*  of right-hand sides, x is the solution vector. */
+
+static void error_btran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector r = b - B'* x */
+      for (i = 1; i <= m; i++)
+      {  /* r[i] := b[i] - (i-th column of B)'* x */
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         temp = h[i];
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            temp -= x[k];
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               temp += A_val[ptr] * x[A_ind[ptr]];
+         }
+         r[i] = temp;
+      }
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_btran - refine solution of B'* x = h
+*
+*  This routine performs one iteration to refine the solution of the
+*  system B'* x = h, where B' is a matrix transposed to the current
+*  basis matrix, h is the vector of right-hand sides, x is the solution
+*  vector. */
+
+static void refine_btran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B'* x */
+      error_btran(csa, h, x, r);
+      /* compute the correction vector d = inv(B') * r */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  get_xN - determine current value of non-basic variable xN[j]
+*
+*  This routine returns the current value of non-basic variable xN[j],
+*  which is a value of its active bound. */
+
+static double get_xN(struct csa *csa, int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int k;
+      double xN;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      switch (stat[j])
+      {  case GLP_NL:
+            /* x[k] is on its lower bound */
+            xN = lb[k]; break;
+         case GLP_NU:
+            /* x[k] is on its upper bound */
+            xN = ub[k]; break;
+         case GLP_NF:
+            /* x[k] is free non-basic variable */
+            xN = 0.0; break;
+         case GLP_NS:
+            /* x[k] is fixed non-basic variable */
+            xN = lb[k]; break;
+         default:
+            xassert(stat != stat);
+      }
+      return xN;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_beta - compute primal values of basic variables
+*
+*  This routine computes current primal values of all basic variables:
+*
+*     beta = - inv(B) * N * xN,
+*
+*  where B is the current basis matrix, N is a matrix built of columns
+*  of matrix (I|-A) corresponding to non-basic variables, and xN is the
+*  vector of current values of non-basic variables. */
+
+static void eval_beta(struct csa *csa, double beta[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      double *h = csa->work2;
+      int i, j, k, beg, end, ptr;
+      double xN;
+      /* compute the right-hand side vector:
+         h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
+         where N[1], ..., N[n] are columns of matrix N */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* determine current value of xN[j] */
+         xN = get_xN(csa, j);
+         if (xN == 0.0) continue;
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            h[k] -= xN;
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               h[A_ind[ptr]] += xN * A_val[ptr];
+         }
+      }
+      /* solve system B * beta = h */
+      memcpy(&beta[1], &h[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, beta);
+      /* and refine the solution */
+      refine_ftran(csa, h, beta);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_pi - compute vector of simplex multipliers
+*
+*  This routine computes the vector of current simplex multipliers:
+*
+*     pi = inv(B') * cB,
+*
+*  where B' is a matrix transposed to the current basis matrix, cB is
+*  a subvector of objective coefficients at basic variables. */
+
+static void eval_pi(struct csa *csa, double pi[])
+{     int m = csa->m;
+      double *c = csa->coef;
+      int *head = csa->head;
+      double *cB = csa->work2;
+      int i;
+      /* construct the right-hand side vector cB */
+      for (i = 1; i <= m; i++)
+         cB[i] = c[head[i]];
+      /* solve system B'* pi = cB */
+      memcpy(&pi[1], &cB[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, pi);
+      /* and refine the solution */
+      refine_btran(csa, cB, pi);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_cost - compute reduced cost of non-basic variable xN[j]
+*
+*  This routine computes the current reduced cost of non-basic variable
+*  xN[j]:
+*
+*     d[j] = cN[j] - N'[j] * pi,
+*
+*  where cN[j] is the objective coefficient at variable xN[j], N[j] is
+*  a column of the augmented constraint matrix (I|-A) corresponding to
+*  xN[j], pi is the vector of simplex multipliers. */
+
+static double eval_cost(struct csa *csa, double pi[], int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int k;
+      double dj;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      dj = coef[k];
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         dj -= pi[k];
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            dj += A_val[ptr] * pi[A_ind[ptr]];
+      }
+      return dj;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_bbar - compute and store primal values of basic variables
+*
+*  This routine computes primal values of all basic variables and then
+*  stores them in the solution array. */
+
+static void eval_bbar(struct csa *csa)
+{     eval_beta(csa, csa->bbar);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_cbar - compute and store reduced costs of non-basic variables
+*
+*  This routine computes reduced costs of all non-basic variables and
+*  then stores them in the solution array. */
+
+static void eval_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+#endif
+      int n = csa->n;
+#ifdef GLP_DEBUG
+      int *head = csa->head;
+#endif
+      double *cbar = csa->cbar;
+      double *pi = csa->work3;
+      int j;
+#ifdef GLP_DEBUG
+      int k;
+#endif
+      /* compute simplex multipliers */
+      eval_pi(csa, pi);
+      /* compute and store reduced costs */
+      for (j = 1; j <= n; j++)
+      {
+#ifdef GLP_DEBUG
+         k = head[m+j]; /* x[k] = xN[j] */
+         xassert(1 <= k && k <= m+n);
+#endif
+         cbar[j] = eval_cost(csa, pi, j);
+      }
+      return;
+}
+#endif
+
+/***********************************************************************
+*  reset_refsp - reset the reference space
+*
+*  This routine resets (redefines) the reference space used in the
+*  projected steepest edge pricing algorithm. */
+
+static void reset_refsp(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int i, k;
+      xassert(csa->refct == 0);
+      csa->refct = 1000;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+         refsp[k] = 1;
+         gamma[i] = 1.0;
+      }
+      return;
+}
+
+/***********************************************************************
+*  eval_gamma - compute steepest edge coefficients
+*
+*  This routine computes the vector of steepest edge coefficients for
+*  all basic variables (except free ones) using its direct definition:
+*
+*     gamma[i] = eta[i] +  sum   alfa[i,j]^2,  i = 1,...,m,
+*                         j in C
+*
+*  where eta[i] = 1 means that xB[i] is in the current reference space,
+*  and 0 otherwise; C is a set of non-basic non-fixed variables xN[j],
+*  which are in the current reference space; alfa[i,j] are elements of
+*  the current simplex table.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static void eval_gamma(struct csa *csa, double gamma[])
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *alfa = csa->work3;
+      double *h = csa->work3;
+      int i, j, k;
+      /* gamma[i] := eta[i] (or 1, if xB[i] is free) */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (type[k] == GLP_FR)
+            gamma[i] = 1.0;
+         else
+            gamma[i] = (refsp[k] ? 1.0 : 0.0);
+      }
+      /* compute columns of the current simplex table */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* skip column, if xN[j] is not in C */
+         if (!refsp[k]) continue;
+#ifdef GLP_DEBUG
+         /* set C must not contain fixed variables */
+         xassert(type[k] != GLP_FX);
+#endif
+         /* construct the right-hand side vector h = - N[j] */
+         for (i = 1; i <= m; i++)
+            h[i] = 0.0;
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            h[k] = -1.0;
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            int *A_ptr = csa->A_ptr;
+            int *A_ind = csa->A_ind;
+            double *A_val = csa->A_val;
+            int beg, end, ptr;
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               h[A_ind[ptr]] = A_val[ptr];
+         }
+         /* solve system B * alfa = h */
+         xassert(csa->valid);
+         bfd_ftran(csa->bfd, alfa);
+         /* gamma[i] := gamma[i] + alfa[i,j]^2 */
+         for (i = 1; i <= m; i++)
+         {  k = head[i]; /* x[k] = xB[i] */
+            if (type[k] != GLP_FR)
+               gamma[i] += alfa[i] * alfa[i];
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  chuzr - choose basic variable (row of the simplex table)
+*
+*  This routine chooses basic variable xB[p] having largest weighted
+*  bound violation:
+*
+*     |r[p]| / sqrt(gamma[p]) = max  |r[i]| / sqrt(gamma[i]),
+*                              i in I
+*
+*            / lB[i] - beta[i], if beta[i] < lB[i]
+*            |
+*     r[i] = < 0,               if lB[i] <= beta[i] <= uB[i]
+*            |
+*            \ uB[i] - beta[i], if beta[i] > uB[i]
+*
+*  where beta[i] is primal value of xB[i] in the current basis, lB[i]
+*  and uB[i] are lower and upper bounds of xB[i], I is a subset of
+*  eligible basic variables, which significantly violates their bounds,
+*  gamma[i] is the steepest edge coefficient.
+*
+*  If |r[i]| is less than a specified tolerance, xB[i] is not included
+*  in I and therefore ignored.
+*
+*  If I is empty and no variable has been chosen, p is set to 0. */
+
+static void chuzr(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      double *gamma = csa->gamma;
+      int i, k, p;
+      double delta, best, eps, ri, temp;
+      /* nothing is chosen so far */
+      p = 0, delta = 0.0, best = 0.0;
+      /* look through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* determine bound violation ri[i] */
+         ri = 0.0;
+         if (type[k] == GLP_LO || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* xB[i] has lower bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] < lb[k] - eps)
+            {  /* and significantly violates it */
+               ri = lb[k] - bbar[i];
+            }
+         }
+         if (type[k] == GLP_UP || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* xB[i] has upper bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] > ub[k] + eps)
+            {  /* and significantly violates it */
+               ri = ub[k] - bbar[i];
+            }
+         }
+         /* if xB[i] is not eligible, skip it */
+         if (ri == 0.0) continue;
+         /* xB[i] is eligible basic variable; choose one with largest
+            weighted bound violation */
+#ifdef GLP_DEBUG
+         xassert(gamma[i] >= 0.0);
+#endif
+         temp = gamma[i];
+         if (temp < DBL_EPSILON) temp = DBL_EPSILON;
+         temp = (ri * ri) / temp;
+         if (best < temp)
+            p = i, delta = ri, best = temp;
+      }
+      /* store the index of basic variable xB[p] chosen and its change
+         in the adjacent basis */
+      csa->p = p;
+      csa->delta = delta;
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_rho - compute pivot row of the inverse
+*
+*  This routine computes the pivot (p-th) row of the inverse inv(B),
+*  which corresponds to basic variable xB[p] chosen:
+*
+*     rho = inv(B') * e[p],
+*
+*  where B' is a matrix transposed to the current basis matrix, e[p]
+*  is unity vector. */
+
+static void eval_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = rho;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* solve system B'* rho = e[p] */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, rho);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_rho - refine pivot row of the inverse
+*
+*  This routine refines the pivot row of the inverse inv(B) assuming
+*  that it was previously computed by the routine eval_rho. */
+
+static void refine_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = csa->work3;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* refine solution of B'* rho = e[p] */
+      refine_btran(csa, e, rho);
+      return;
+}
+#endif
+
+#if 1 /* 06/IV-2009 */
+/***********************************************************************
+*  eval_trow - compute pivot row of the simplex table
+*
+*  This routine computes the pivot row of the simplex table, which
+*  corresponds to basic variable xB[p] chosen.
+*
+*  The pivot row is the following vector:
+*
+*     trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
+*
+*  where rho is the pivot row of the inverse inv(B) previously computed
+*  by the routine eval_rho.
+*
+*  Note that elements of the pivot row corresponding to fixed non-basic
+*  variables are not computed.
+*
+*  NOTES
+*
+*  Computing pivot row of the simplex table is one of the most time
+*  consuming operations, and for some instances it may take more than
+*  50% of the total solution time.
+*
+*  In the current implementation there are two routines to compute the
+*  pivot row. The routine eval_trow1 computes elements of the pivot row
+*  as inner products of columns of the matrix N and the vector rho; it
+*  is used when the vector rho is relatively dense. The routine
+*  eval_trow2 computes the pivot row as a linear combination of rows of
+*  the matrix N; it is used when the vector rho is relatively sparse. */
+
+static void eval_trow1(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int j, k, beg, end, ptr, nnz;
+      double temp;
+      /* compute the pivot row as inner products of columns of the
+         matrix N and vector rho: trow[j] = - rho * N[j] */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS)
+         {  /* xN[j] is fixed */
+            trow_vec[j] = 0.0;
+            continue;
+         }
+         k = head[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            temp = - rho[k];
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m], end = A_ptr[k-m+1];
+            temp = 0.0;
+            for (ptr = beg; ptr < end; ptr++)
+               temp += rho[A_ind[ptr]] * A_val[ptr];
+         }
+         if (temp != 0.0)
+            trow_ind[++nnz] = j;
+         trow_vec[j] = temp;
+      }
+      csa->trow_nnz = nnz;
+      return;
+}
+
+static void eval_trow2(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *AT_ptr = csa->AT_ptr;
+      int *AT_ind = csa->AT_ind;
+      double *AT_val = csa->AT_val;
+      int *bind = csa->bind;
+      char *stat = csa->stat;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int i, j, beg, end, ptr, nnz;
+      double temp;
+      /* clear the pivot row */
+      for (j = 1; j <= n; j++)
+         trow_vec[j] = 0.0;
+      /* compute the pivot row as a linear combination of rows of the
+         matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
+      for (i = 1; i <= m; i++)
+      {  temp = rho[i];
+         if (temp == 0.0) continue;
+         /* trow := trow - rho[i] * N'[i] */
+         j = bind[i] - m; /* x[i] = xN[j] */
+         if (j >= 1 && stat[j] != GLP_NS)
+            trow_vec[j] -= temp;
+         beg = AT_ptr[i], end = AT_ptr[i+1];
+         for (ptr = beg; ptr < end; ptr++)
+         {  j = bind[m + AT_ind[ptr]] - m; /* x[k] = xN[j] */
+            if (j >= 1 && stat[j] != GLP_NS)
+               trow_vec[j] += temp * AT_val[ptr];
+         }
+      }
+      /* construct sparse pattern of the pivot row */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  if (trow_vec[j] != 0.0)
+            trow_ind[++nnz] = j;
+      }
+      csa->trow_nnz = nnz;
+      return;
+}
+
+static void eval_trow(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int i, nnz;
+      double dens;
+      /* determine the density of the vector rho */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+         if (rho[i] != 0.0) nnz++;
+      dens = (double)nnz / (double)m;
+      if (dens >= 0.20)
+      {  /* rho is relatively dense */
+         eval_trow1(csa, rho);
+      }
+      else
+      {  /* rho is relatively sparse */
+         eval_trow2(csa, rho);
+      }
+      return;
+}
+#endif
+
+/***********************************************************************
+*  sort_trow - sort pivot row of the simplex table
+*
+*  This routine reorders the list of non-zero elements of the pivot
+*  row to put significant elements, whose magnitude is not less than
+*  a specified tolerance, in front of the list, and stores the number
+*  of significant elements in trow_num. */
+
+static void sort_trow(struct csa *csa, double tol_piv)
+{
+#ifdef GLP_DEBUG
+      int n = csa->n;
+      char *stat = csa->stat;
+#endif
+      int nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int j, num, pos;
+      double big, eps, temp;
+      /* compute infinity (maximum) norm of the row */
+      big = 0.0;
+      for (pos = 1; pos <= nnz; pos++)
+      {
+#ifdef GLP_DEBUG
+         j = trow_ind[pos];
+         xassert(1 <= j && j <= n);
+         xassert(stat[j] != GLP_NS);
+#endif
+         temp = fabs(trow_vec[trow_ind[pos]]);
+         if (big < temp) big = temp;
+      }
+      csa->trow_max = big;
+      /* determine absolute pivot tolerance */
+      eps = tol_piv * (1.0 + 0.01 * big);
+      /* move significant row components to the front of the list */
+      for (num = 0; num < nnz; )
+      {  j = trow_ind[nnz];
+         if (fabs(trow_vec[j]) < eps)
+            nnz--;
+         else
+         {  num++;
+            trow_ind[nnz] = trow_ind[num];
+            trow_ind[num] = j;
+         }
+      }
+      csa->trow_num = num;
+      return;
+}
+
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+static int ls_func(const void *p1_, const void *p2_)
+{     const struct bkpt *p1 = p1_, *p2 = p2_;
+      if (p1->t < p2->t) return -1;
+      if (p1->t > p2->t) return +1;
+      return 0;
+}
+
+static int ls_func1(const void *p1_, const void *p2_)
+{     const struct bkpt *p1 = p1_, *p2 = p2_;
+      if (p1->dz < p2->dz) return -1;
+      if (p1->dz > p2->dz) return +1;
+      return 0;
+}
+
+static void long_step(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      double delta = csa->delta;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int trow_num = csa->trow_num;
+      struct bkpt *bkpt = csa->bkpt;
+      int j, k, kk, nbps, pos;
+      double alfa, s, slope, dzmax;
+      /* delta > 0 means that xB[p] violates its lower bound, so to
+         increase the dual objective lambdaB[p] must increase;
+         delta < 0 means that xB[p] violates its upper bound, so to
+         increase the dual objective lambdaB[p] must decrease */
+      /* s := sign(delta) */
+      s = (delta > 0.0 ? +1.0 : -1.0);
+      /* determine breakpoints of the dual objective */
+      nbps = 0;
+      for (pos = 1; pos <= trow_num; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+         xassert(stat[j] != GLP_NS);
+#endif
+         /* if there is free non-basic variable, switch to the standard
+            ratio test */
+         if (stat[j] == GLP_NF)
+         {  nbps = 0;
+            goto done;
+         }
+         /* lambdaN[j] = ... - alfa * t - ..., where t = s * lambdaB[i]
+            is the dual ray parameter, t >= 0 */
+         alfa = s * trow_vec[j];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+         xassert(stat[j] == GLP_NL || stat[j] == GLP_NU);
+#endif
+         if (alfa > 0.0 && stat[j] == GLP_NL ||
+             alfa < 0.0 && stat[j] == GLP_NU)
+         {  /* either lambdaN[j] >= 0 (if stat = GLP_NL) and decreases
+               or lambdaN[j] <= 0 (if stat = GLP_NU) and increases; in
+               both cases we have a breakpoint */
+            nbps++;
+#ifdef GLP_DEBUG
+            xassert(nbps <= n);
+#endif
+            bkpt[nbps].j = j;
+            bkpt[nbps].t = cbar[j] / alfa;
+/*
+if (stat[j] == GLP_NL && cbar[j] < 0.0 ||
+    stat[j] == GLP_NU && cbar[j] > 0.0)
+xprintf("%d %g\n", stat[j], cbar[j]);
+*/
+            /* if t is negative, replace it by exact zero (see comments
+               in the routine chuzc) */
+            if (bkpt[nbps].t < 0.0) bkpt[nbps].t = 0.0;
+         }
+      }
+      /* if there are less than two breakpoints, switch to the standard
+         ratio test */
+      if (nbps < 2)
+      {  nbps = 0;
+         goto done;
+      }
+      /* sort breakpoints by ascending the dual ray parameter, t */
+      qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func);
+      /* determine last breakpoint, at which the dual objective still
+         greater than at t = 0 */
+      dzmax = 0.0;
+      slope = fabs(delta); /* initial slope */
+      for (kk = 1; kk <= nbps; kk++)
+      {  if (kk == 1)
+            bkpt[kk].dz =
+               0.0 + slope * (bkpt[kk].t - 0.0);
+         else
+            bkpt[kk].dz =
+               bkpt[kk-1].dz + slope * (bkpt[kk].t - bkpt[kk-1].t);
+         if (dzmax < bkpt[kk].dz)
+            dzmax = bkpt[kk].dz;
+         else if (bkpt[kk].dz < 0.05 * (1.0 + dzmax))
+         {  nbps = kk - 1;
+            break;
+         }
+         j = bkpt[kk].j;
+         k = head[m+j]; /* x[k] = xN[j] */
+         if (type[k] == GLP_DB)
+            slope -= fabs(trow_vec[j]) * (ub[k] - lb[k]);
+         else
+         {  nbps = kk;
+            break;
+         }
+      }
+      /* if there are less than two breakpoints, switch to the standard
+         ratio test */
+      if (nbps < 2)
+      {  nbps = 0;
+         goto done;
+      }
+      /* sort breakpoints by ascending the dual change, dz */
+      qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func1);
+/*
+for (kk = 1; kk <= nbps; kk++)
+xprintf("%d; t = %g; dz = %g\n", kk, bkpt[kk].t, bkpt[kk].dz);
+*/
+done: csa->nbps = nbps;
+      return;
+}
+#endif
+
+/***********************************************************************
+*  chuzc - choose non-basic variable (column of the simplex table)
+*
+*  This routine chooses non-basic variable xN[q], which being entered
+*  in the basis keeps dual feasibility of the basic solution.
+*
+*  The parameter rtol is a relative tolerance used to relax zero bounds
+*  of reduced costs of non-basic variables. If rtol = 0, the routine
+*  implements the standard ratio test. Otherwise, if rtol > 0, the
+*  routine implements Harris' two-pass ratio test. In the latter case
+*  rtol should be about three times less than a tolerance used to check
+*  dual feasibility. */
+
+static void chuzc(struct csa *csa, double rtol)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+      int n = csa->n;
+#endif
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+#ifdef GLP_DEBUG
+      int p = csa->p;
+#endif
+      double delta = csa->delta;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int trow_num = csa->trow_num;
+      int j, pos, q;
+      double alfa, big, s, t, teta, tmax;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* delta > 0 means that xB[p] violates its lower bound and goes
+         to it in the adjacent basis, so lambdaB[p] is increasing from
+         its lower zero bound;
+         delta < 0 means that xB[p] violates its upper bound and goes
+         to it in the adjacent basis, so lambdaB[p] is decreasing from
+         its upper zero bound */
+#ifdef GLP_DEBUG
+      xassert(delta != 0.0);
+#endif
+      /* s := sign(delta) */
+      s = (delta > 0.0 ? +1.0 : -1.0);
+      /*** FIRST PASS ***/
+      /* nothing is chosen so far */
+      q = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through significant elements of the pivot row */
+      for (pos = 1; pos <= trow_num; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         alfa = s * trow_vec[j];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
+            need to consider only increasing lambdaB[p] */
+         if (alfa > 0.0)
+         {  /* lambdaN[j] is decreasing */
+            if (stat[j] == GLP_NL || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero lower bound */
+               t = (cbar[j] + rtol) / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no lower bound */
+               continue;
+            }
+         }
+         else
+         {  /* lambdaN[j] is increasing */
+            if (stat[j] == GLP_NU || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero upper bound */
+               t = (cbar[j] - rtol) / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no upper bound */
+               continue;
+            }
+         }
+         /* t is a change of lambdaB[p], on which lambdaN[j] reaches
+            its zero bound (possibly relaxed); since the basic solution
+            is assumed to be dual feasible, t has to be non-negative by
+            definition; however, it may happen that lambdaN[j] slightly
+            (i.e. within a tolerance) violates its zero bound, that
+            leads to negative t; in the latter case, if xN[j] is chosen,
+            negative t means that lambdaB[p] changes in wrong direction
+            that may cause wrong results on updating reduced costs;
+            thus, if t is negative, we should replace it by exact zero
+            assuming that lambdaN[j] is exactly on its zero bound, and
+            violation appears due to round-off errors */
+         if (t < 0.0) t = 0.0;
+         /* apply minimal ratio test */
+         if (teta > t || teta == t && big < fabs(alfa))
+            q = j, teta = t, big = fabs(alfa);
+      }
+      /* the second pass is skipped in the following cases: */
+      /* if the standard ratio test is used */
+      if (rtol == 0.0) goto done;
+      /* if no non-basic variable has been chosen on the first pass */
+      if (q == 0) goto done;
+      /* if lambdaN[q] prevents lambdaB[p] from any change */
+      if (teta == 0.0) goto done;
+      /*** SECOND PASS ***/
+      /* here tmax is a maximal change of lambdaB[p], on which the
+         solution remains dual feasible within a tolerance */
+#if 0
+      tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
+#else
+      tmax = teta;
+#endif
+      /* nothing is chosen so far */
+      q = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through significant elements of the pivot row */
+      for (pos = 1; pos <= trow_num; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         alfa = s * trow_vec[j];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
+            need to consider only increasing lambdaB[p] */
+         if (alfa > 0.0)
+         {  /* lambdaN[j] is decreasing */
+            if (stat[j] == GLP_NL || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero lower bound */
+               t = cbar[j] / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no lower bound */
+               continue;
+            }
+         }
+         else
+         {  /* lambdaN[j] is increasing */
+            if (stat[j] == GLP_NU || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero upper bound */
+               t = cbar[j] / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no upper bound */
+               continue;
+            }
+         }
+         /* (see comments for the first pass) */
+         if (t < 0.0) t = 0.0;
+         /* t is a change of lambdaB[p], on which lambdaN[j] reaches
+            its zero (lower or upper) bound; if t <= tmax, all reduced
+            costs can violate their zero bounds only within relaxation
+            tolerance rtol, so we can choose non-basic variable having
+            largest influence coefficient to avoid possible numerical
+            instability */
+         if (t <= tmax && big < fabs(alfa))
+            q = j, teta = t, big = fabs(alfa);
+      }
+      /* something must be chosen on the second pass */
+      xassert(q != 0);
+done: /* store the index of non-basic variable xN[q] chosen */
+      csa->q = q;
+      /* store reduced cost of xN[q] in the adjacent basis */
+      csa->new_dq = s * teta;
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_tcol - compute pivot column of the simplex table
+*
+*  This routine computes the pivot column of the simplex table, which
+*  corresponds to non-basic variable xN[q] chosen.
+*
+*  The pivot column is the following vector:
+*
+*     tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+*
+*  where B is the current basis matrix, N[q] is a column of the matrix
+*  (I|-A) corresponding to variable xN[q]. */
+
+static void eval_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->tcol_vec;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* solve system B * tcol = h */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_tcol - refine pivot column of the simplex table
+*
+*  This routine refines the pivot column of the simplex table assuming
+*  that it was previously computed by the routine eval_tcol. */
+
+static void refine_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->work3;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* refine solution of B * tcol = h */
+      refine_ftran(csa, h, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+#endif
+
+/***********************************************************************
+*  update_cbar - update reduced costs of non-basic variables
+*
+*  This routine updates reduced costs of all (except fixed) non-basic
+*  variables for the adjacent basis. */
+
+static void update_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *cbar = csa->cbar;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int q = csa->q;
+      double new_dq = csa->new_dq;
+      int j, pos;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      /* set new reduced cost of xN[q] */
+      cbar[q] = new_dq;
+      /* update reduced costs of other non-basic variables */
+      if (new_dq == 0.0) goto done;
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         if (j != q)
+            cbar[j] -= trow_vec[j] * new_dq;
+      }
+done: return;
+}
+
+/***********************************************************************
+*  update_bbar - update values of basic variables
+*
+*  This routine updates values of all basic variables for the adjacent
+*  basis. */
+
+static void update_bbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+      int n = csa->n;
+#endif
+      double *bbar = csa->bbar;
+      int p = csa->p;
+      double delta = csa->delta;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int i, pos;
+      double teta;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* determine the change of xN[q] in the adjacent basis */
+#ifdef GLP_DEBUG
+      xassert(tcol_vec[p] != 0.0);
+#endif
+      teta = delta / tcol_vec[p];
+      /* set new primal value of xN[q] */
+      bbar[p] = get_xN(csa, q) + teta;
+      /* update primal values of other basic variables */
+      if (teta == 0.0) goto done;
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         if (i != p)
+            bbar[i] += tcol_vec[i] * teta;
+      }
+done: return;
+}
+
+/***********************************************************************
+*  update_gamma - update steepest edge coefficients
+*
+*  This routine updates steepest-edge coefficients for the adjacent
+*  basis. */
+
+static void update_gamma(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int p = csa->p;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *u = csa->work3;
+      int i, j, k,pos;
+      double gamma_p, eta_p, pivot, t, t1, t2;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* the basis changes, so decrease the count */
+      xassert(csa->refct > 0);
+      csa->refct--;
+      /* recompute gamma[p] for the current basis more accurately and
+         compute auxiliary vector u */
+#ifdef GLP_DEBUG
+      xassert(type[head[p]] != GLP_FR);
+#endif
+      gamma_p = eta_p = (refsp[head[p]] ? 1.0 : 0.0);
+      for (i = 1; i <= m; i++) u[i] = 0.0;
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+         xassert(type[k] != GLP_FX);
+#endif
+         if (!refsp[k]) continue;
+         t = trow_vec[j];
+         gamma_p += t * t;
+         /* u := u + N[j] * delta[j] * trow[j] */
+         if (k <= m)
+         {  /* N[k] = k-j stolbec submatrix I */
+            u[k] += t;
+         }
+         else
+         {  /* N[k] = k-m-k stolbec (-A) */
+            int *A_ptr = csa->A_ptr;
+            int *A_ind = csa->A_ind;
+            double *A_val = csa->A_val;
+            int beg, end, ptr;
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               u[A_ind[ptr]] -= t * A_val[ptr];
+         }
+      }
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, u);
+      /* update gamma[i] for other basic variables (except xB[p] and
+         free variables) */
+      pivot = tcol_vec[p];
+#ifdef GLP_DEBUG
+      xassert(pivot != 0.0);
+#endif
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         k = head[i];
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* skip xB[p] */
+         if (i == p) continue;
+         /* skip free basic variable */
+         if (type[head[i]] == GLP_FR)
+         {
+#ifdef GLP_DEBUG
+            xassert(gamma[i] == 1.0);
+#endif
+            continue;
+         }
+         /* compute gamma[i] for the adjacent basis */
+         t = tcol_vec[i] / pivot;
+         t1 = gamma[i] + t * t * gamma_p + 2.0 * t * u[i];
+         t2 = (refsp[k] ? 1.0 : 0.0) + eta_p * t * t;
+         gamma[i] = (t1 >= t2 ? t1 : t2);
+         /* (though gamma[i] can be exact zero, because the reference
+            space does not include non-basic fixed variables) */
+         if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
+      }
+      /* compute gamma[p] for the adjacent basis */
+      if (type[head[m+q]] == GLP_FR)
+         gamma[p] = 1.0;
+      else
+      {  gamma[p] = gamma_p / (pivot * pivot);
+         if (gamma[p] < DBL_EPSILON) gamma[p] = DBL_EPSILON;
+      }
+      /* if xB[p], which becomes xN[q] in the adjacent basis, is fixed
+         and belongs to the reference space, remove it from there, and
+         change all gamma's appropriately */
+      k = head[p];
+      if (type[k] == GLP_FX && refsp[k])
+      {  refsp[k] = 0;
+         for (pos = 1; pos <= tcol_nnz; pos++)
+         {  i = tcol_ind[pos];
+            if (i == p)
+            {  if (type[head[m+q]] == GLP_FR) continue;
+               t = 1.0 / tcol_vec[p];
+            }
+            else
+            {  if (type[head[i]] == GLP_FR) continue;
+               t = tcol_vec[i] / tcol_vec[p];
+            }
+            gamma[i] -= t * t;
+            if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
+         }
+      }
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  err_in_bbar - compute maximal relative error in primal solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |beta[i] - bbar[i]| / (1 + |beta[i]|),
+*
+*  where beta and bbar are, respectively, directly computed and the
+*  current (updated) values of basic variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_bbar(struct csa *csa)
+{     int m = csa->m;
+      double *bbar = csa->bbar;
+      int i;
+      double e, emax, *beta;
+      beta = xcalloc(1+m, sizeof(double));
+      eval_beta(csa, beta);
+      emax = 0.0;
+      for (i = 1; i <= m; i++)
+      {  e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
+         if (emax < e) emax = e;
+      }
+      xfree(beta);
+      return emax;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  err_in_cbar - compute maximal relative error in dual solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |cost[j] - cbar[j]| / (1 + |cost[j]|),
+*
+*  where cost and cbar are, respectively, directly computed and the
+*  current (updated) reduced costs of non-basic non-fixed variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_cbar(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j;
+      double e, emax, cost, *pi;
+      pi = xcalloc(1+m, sizeof(double));
+      eval_pi(csa, pi);
+      emax = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS) continue;
+         cost = eval_cost(csa, pi, j);
+         e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
+         if (emax < e) emax = e;
+      }
+      xfree(pi);
+      return emax;
+}
+#endif
+
+/***********************************************************************
+*  err_in_gamma - compute maximal relative error in steepest edge cff.
+*
+*  This routine returns maximal relative error:
+*
+*     max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
+*
+*  where gamma'[j] and gamma[j] are, respectively, directly computed
+*  and the current (updated) steepest edge coefficients for non-basic
+*  non-fixed variable x[j].
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_gamma(struct csa *csa)
+{     int m = csa->m;
+      char *type = csa->type;
+      int *head = csa->head;
+      double *gamma = csa->gamma;
+      double *exact = csa->work4;
+      int i;
+      double e, emax, temp;
+      eval_gamma(csa, exact);
+      emax = 0.0;
+      for (i = 1; i <= m; i++)
+      {  if (type[head[i]] == GLP_FR)
+         {  xassert(gamma[i] == 1.0);
+            xassert(exact[i] == 1.0);
+            continue;
+         }
+         temp = exact[i];
+         e = fabs(temp - gamma[i]) / (1.0 + fabs(temp));
+         if (emax < e) emax = e;
+      }
+      return emax;
+}
+
+/***********************************************************************
+*  change_basis - change basis header
+*
+*  This routine changes the basis header to make it corresponding to
+*  the adjacent basis. */
+
+static void change_basis(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      int *head = csa->head;
+#if 1 /* 06/IV-2009 */
+      int *bind = csa->bind;
+#endif
+      char *stat = csa->stat;
+      int p = csa->p;
+      double delta = csa->delta;
+      int q = csa->q;
+      int k;
+      /* xB[p] leaves the basis, xN[q] enters the basis */
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* xB[p] <-> xN[q] */
+      k = head[p], head[p] = head[m+q], head[m+q] = k;
+#if 1 /* 06/IV-2009 */
+      bind[head[p]] = p, bind[head[m+q]] = m + q;
+#endif
+      if (type[k] == GLP_FX)
+         stat[q] = GLP_NS;
+      else if (delta > 0.0)
+      {
+#ifdef GLP_DEBUG
+         xassert(type[k] == GLP_LO || type[k] == GLP_DB);
+#endif
+         stat[q] = GLP_NL;
+      }
+      else /* delta < 0.0 */
+      {
+#ifdef GLP_DEBUG
+         xassert(type[k] == GLP_UP || type[k] == GLP_DB);
+#endif
+         stat[q] = GLP_NU;
+      }
+      return;
+}
+
+/***********************************************************************
+*  check_feas - check dual feasibility of basic solution
+*
+*  If the current basic solution is dual feasible within a tolerance,
+*  this routine returns zero, otherwise it returns non-zero. */
+
+static int check_feas(struct csa *csa, double tol_dj)
+{     int m = csa->m;
+      int n = csa->n;
+      char *orig_type = csa->orig_type;
+      int *head = csa->head;
+      double *cbar = csa->cbar;
+      int j, k;
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (cbar[j] < - tol_dj)
+            if (orig_type[k] == GLP_LO || orig_type[k] == GLP_FR)
+               return 1;
+         if (cbar[j] > + tol_dj)
+            if (orig_type[k] == GLP_UP || orig_type[k] == GLP_FR)
+               return 1;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  set_aux_bnds - assign auxiliary bounds to variables
+*
+*  This routine assigns auxiliary bounds to variables to construct an
+*  LP problem solved on phase I. */
+
+static void set_aux_bnds(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      char *orig_type = csa->orig_type;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j, k;
+      for (k = 1; k <= m+n; k++)
+      {  switch (orig_type[k])
+         {  case GLP_FR:
+#if 0
+               type[k] = GLP_DB, lb[k] = -1.0, ub[k] = +1.0;
+#else
+               /* to force free variables to enter the basis */
+               type[k] = GLP_DB, lb[k] = -1e3, ub[k] = +1e3;
+#endif
+               break;
+            case GLP_LO:
+               type[k] = GLP_DB, lb[k] = 0.0, ub[k] = +1.0;
+               break;
+            case GLP_UP:
+               type[k] = GLP_DB, lb[k] = -1.0, ub[k] = 0.0;
+               break;
+            case GLP_DB:
+            case GLP_FX:
+               type[k] = GLP_FX, lb[k] = ub[k] = 0.0;
+               break;
+            default:
+               xassert(orig_type != orig_type);
+         }
+      }
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (type[k] == GLP_FX)
+            stat[j] = GLP_NS;
+         else if (cbar[j] >= 0.0)
+            stat[j] = GLP_NL;
+         else
+            stat[j] = GLP_NU;
+      }
+      return;
+}
+
+/***********************************************************************
+*  set_orig_bnds - restore original bounds of variables
+*
+*  This routine restores original types and bounds of variables and
+*  determines statuses of non-basic variables assuming that the current
+*  basis is dual feasible. */
+
+static void set_orig_bnds(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      char *orig_type = csa->orig_type;
+      double *orig_lb = csa->orig_lb;
+      double *orig_ub = csa->orig_ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j, k;
+      memcpy(&type[1], &orig_type[1], (m+n) * sizeof(char));
+      memcpy(&lb[1], &orig_lb[1], (m+n) * sizeof(double));
+      memcpy(&ub[1], &orig_ub[1], (m+n) * sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         switch (type[k])
+         {  case GLP_FR:
+               stat[j] = GLP_NF;
+               break;
+            case GLP_LO:
+               stat[j] = GLP_NL;
+               break;
+            case GLP_UP:
+               stat[j] = GLP_NU;
+               break;
+            case GLP_DB:
+               if (cbar[j] >= +DBL_EPSILON)
+                  stat[j] = GLP_NL;
+               else if (cbar[j] <= -DBL_EPSILON)
+                  stat[j] = GLP_NU;
+               else if (fabs(lb[k]) <= fabs(ub[k]))
+                  stat[j] = GLP_NL;
+               else
+                  stat[j] = GLP_NU;
+               break;
+            case GLP_FX:
+               stat[j] = GLP_NS;
+               break;
+            default:
+               xassert(type != type);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  check_stab - check numerical stability of basic solution
+*
+*  If the current basic solution is dual feasible within a tolerance,
+*  this routine returns zero, otherwise it returns non-zero. */
+
+static int check_stab(struct csa *csa, double tol_dj)
+{     int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j;
+      for (j = 1; j <= n; j++)
+      {  if (cbar[j] < - tol_dj)
+            if (stat[j] == GLP_NL || stat[j] == GLP_NF) return 1;
+         if (cbar[j] > + tol_dj)
+            if (stat[j] == GLP_NU || stat[j] == GLP_NF) return 1;
+      }
+      return 0;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_obj - compute original objective function
+*
+*  This routine computes the current value of the original objective
+*  function. */
+
+static double eval_obj(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *obj = csa->obj;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, j, k;
+      double sum;
+      sum = obj[0];
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * bbar[i];
+      }
+      /* walk through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * get_xN(csa, j);
+      }
+      return sum;
+}
+#endif
+
+/***********************************************************************
+*  display - display the search progress
+*
+*  This routine displays some information about the search progress. */
+
+static void display(struct csa *csa, const glp_smcp *parm, int spec)
+{     int m = csa->m;
+      int n = csa->n;
+      double *coef = csa->coef;
+      char *orig_type = csa->orig_type;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int phase = csa->phase;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int i, j, cnt;
+      double sum;
+      if (parm->msg_lev < GLP_MSG_ON) goto skip;
+      if (parm->out_dly > 0 &&
+         1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
+         goto skip;
+      if (csa->it_cnt == csa->it_dpy) goto skip;
+      if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
+      /* compute the sum of dual infeasibilities */
+      sum = 0.0;
+      if (phase == 1)
+      {  for (i = 1; i <= m; i++)
+            sum -= coef[head[i]] * bbar[i];
+         for (j = 1; j <= n; j++)
+            sum -= coef[head[m+j]] * get_xN(csa, j);
+      }
+      else
+      {  for (j = 1; j <= n; j++)
+         {  if (cbar[j] < 0.0)
+               if (stat[j] == GLP_NL || stat[j] == GLP_NF)
+                  sum -= cbar[j];
+            if (cbar[j] > 0.0)
+               if (stat[j] == GLP_NU || stat[j] == GLP_NF)
+                  sum += cbar[j];
+         }
+      }
+      /* determine the number of basic fixed variables */
+      cnt = 0;
+      for (i = 1; i <= m; i++)
+         if (orig_type[head[i]] == GLP_FX) cnt++;
+      if (csa->phase == 1)
+         xprintf(" %6d: %24s infeas = %10.3e (%d)\n",
+            csa->it_cnt, "", sum, cnt);
+      else
+         xprintf("|%6d: obj = %17.9e  infeas = %10.3e (%d)\n",
+            csa->it_cnt, eval_obj(csa), sum, cnt);
+      csa->it_dpy = csa->it_cnt;
+skip: return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  store_sol - store basic solution back to the problem object
+*
+*  This routine stores basic solution components back to the problem
+*  object. */
+
+static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
+      int d_stat, int ray)
+{     int m = csa->m;
+      int n = csa->n;
+      double zeta = csa->zeta;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int i, j, k;
+#ifdef GLP_DEBUG
+      xassert(lp->m == m);
+      xassert(lp->n == n);
+#endif
+      /* basis factorization */
+#ifdef GLP_DEBUG
+      xassert(!lp->valid && lp->bfd == NULL);
+      xassert(csa->valid && csa->bfd != NULL);
+#endif
+      lp->valid = 1, csa->valid = 0;
+      lp->bfd = csa->bfd, csa->bfd = NULL;
+      memcpy(&lp->head[1], &head[1], m * sizeof(int));
+      /* basic solution status */
+      lp->pbs_stat = p_stat;
+      lp->dbs_stat = d_stat;
+      /* objective function value */
+      lp->obj_val = eval_obj(csa);
+      /* simplex iteration count */
+      lp->it_cnt = csa->it_cnt;
+      /* unbounded ray */
+      lp->some = ray;
+      /* basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = GLP_BS;
+            row->bind = i;
+            row->prim = bbar[i] / row->rii;
+            row->dual = 0.0;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = GLP_BS;
+            col->bind = i;
+            col->prim = bbar[i] * col->sjj;
+            col->dual = 0.0;
+         }
+      }
+      /* non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = stat[j];
+            row->bind = 0;
+#if 0
+            row->prim = get_xN(csa, j) / row->rii;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  row->prim = row->lb; break;
+               case GLP_NU:
+                  row->prim = row->ub; break;
+               case GLP_NF:
+                  row->prim = 0.0; break;
+               case GLP_NS:
+                  row->prim = row->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            row->dual = (cbar[j] * row->rii) / zeta;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = stat[j];
+            col->bind = 0;
+#if 0
+            col->prim = get_xN(csa, j) * col->sjj;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  col->prim = col->lb; break;
+               case GLP_NU:
+                  col->prim = col->ub; break;
+               case GLP_NF:
+                  col->prim = 0.0; break;
+               case GLP_NS:
+                  col->prim = col->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            col->dual = (cbar[j] / col->sjj) / zeta;
+         }
+      }
+      return;
+}
+#endif
+
+/***********************************************************************
+*  free_csa - deallocate common storage area
+*
+*  This routine frees all the memory allocated to arrays in the common
+*  storage area (CSA). */
+
+static void free_csa(struct csa *csa)
+{     xfree(csa->type);
+      xfree(csa->lb);
+      xfree(csa->ub);
+      xfree(csa->coef);
+      xfree(csa->orig_type);
+      xfree(csa->orig_lb);
+      xfree(csa->orig_ub);
+      xfree(csa->obj);
+      xfree(csa->A_ptr);
+      xfree(csa->A_ind);
+      xfree(csa->A_val);
+#if 1 /* 06/IV-2009 */
+      xfree(csa->AT_ptr);
+      xfree(csa->AT_ind);
+      xfree(csa->AT_val);
+#endif
+      xfree(csa->head);
+#if 1 /* 06/IV-2009 */
+      xfree(csa->bind);
+#endif
+      xfree(csa->stat);
+#if 0 /* 06/IV-2009 */
+      xfree(csa->N_ptr);
+      xfree(csa->N_len);
+      xfree(csa->N_ind);
+      xfree(csa->N_val);
+#endif
+      xfree(csa->bbar);
+      xfree(csa->cbar);
+      xfree(csa->refsp);
+      xfree(csa->gamma);
+      xfree(csa->trow_ind);
+      xfree(csa->trow_vec);
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      xfree(csa->bkpt);
+#endif
+      xfree(csa->tcol_ind);
+      xfree(csa->tcol_vec);
+      xfree(csa->work1);
+      xfree(csa->work2);
+      xfree(csa->work3);
+      xfree(csa->work4);
+      xfree(csa);
+      return;
+}
+
+/***********************************************************************
+*  spx_dual - core LP solver based on the dual simplex method
+*
+*  SYNOPSIS
+*
+*  #include "glpspx.h"
+*  int spx_dual(glp_prob *lp, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine spx_dual is a core LP solver based on the two-phase dual
+*  simplex method.
+*
+*  RETURNS
+*
+*  0  LP instance has been successfully solved.
+*
+*  GLP_EOBJLL
+*     Objective lower limit has been reached (maximization).
+*
+*  GLP_EOBJUL
+*     Objective upper limit has been reached (minimization).
+*
+*  GLP_EITLIM
+*     Iteration limit has been exhausted.
+*
+*  GLP_ETMLIM
+*     Time limit has been exhausted.
+*
+*  GLP_EFAIL
+*     The solver failed to solve LP instance. */
+
+int spx_dual(glp_prob *lp, const glp_smcp *parm)
+{     struct csa *csa;
+      int binv_st = 2;
+      /* status of basis matrix factorization:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int bbar_st = 0;
+      /* status of primal values of basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int cbar_st = 0;
+      /* status of reduced costs of non-basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int rigorous = 0;
+      /* rigorous mode flag; this flag is used to enable iterative
+         refinement on computing pivot rows and columns of the simplex
+         table */
+      int check = 0;
+      int p_stat, d_stat, ret;
+      /* allocate and initialize the common storage area */
+      csa = alloc_csa(lp);
+      init_csa(csa, lp);
+      if (parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Objective scale factor = %g\n", csa->zeta);
+loop: /* main loop starts here */
+      /* compute factorization of the basis matrix */
+      if (binv_st == 0)
+      {  ret = invert_B(csa);
+         if (ret != 0)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+            {  xprintf("Error: unable to factorize the basis matrix (%d"
+                  ")\n", ret);
+               xprintf("Sorry, basis recovery procedure not implemented"
+                  " yet\n");
+            }
+            xassert(!lp->valid && lp->bfd == NULL);
+            lp->bfd = csa->bfd, csa->bfd = NULL;
+            lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+            lp->obj_val = 0.0;
+            lp->it_cnt = csa->it_cnt;
+            lp->some = 0;
+            ret = GLP_EFAIL;
+            goto done;
+         }
+         csa->valid = 1;
+         binv_st = 1; /* just computed */
+         /* invalidate basic solution components */
+         bbar_st = cbar_st = 0;
+      }
+      /* compute reduced costs of non-basic variables */
+      if (cbar_st == 0)
+      {  eval_cbar(csa);
+         cbar_st = 1; /* just computed */
+         /* determine the search phase, if not determined yet */
+         if (csa->phase == 0)
+         {  if (check_feas(csa, 0.90 * parm->tol_dj) != 0)
+            {  /* current basic solution is dual infeasible */
+               /* start searching for dual feasible solution */
+               csa->phase = 1;
+               set_aux_bnds(csa);
+            }
+            else
+            {  /* current basic solution is dual feasible */
+               /* start searching for optimal solution */
+               csa->phase = 2;
+               set_orig_bnds(csa);
+            }
+            xassert(check_stab(csa, parm->tol_dj) == 0);
+            /* some non-basic double-bounded variables might become
+               fixed (on phase I) or vice versa (on phase II) */
+#if 0 /* 06/IV-2009 */
+            build_N(csa);
+#endif
+            csa->refct = 0;
+            /* bounds of non-basic variables have been changed, so
+               invalidate primal values */
+            bbar_st = 0;
+         }
+         /* make sure that the current basic solution remains dual
+            feasible */
+         if (check_stab(csa, parm->tol_dj) != 0)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: numerical instability (dual simplex, p"
+                  "hase %s)\n", csa->phase == 1 ? "I" : "II");
+#if 1
+            if (parm->meth == GLP_DUALP)
+            {  store_sol(csa, lp, GLP_UNDEF, GLP_UNDEF, 0);
+               ret = GLP_EFAIL;
+               goto done;
+            }
+#endif
+            /* restart the search */
+            csa->phase = 0;
+            binv_st = 0;
+            rigorous = 5;
+            goto loop;
+         }
+      }
+      xassert(csa->phase == 1 || csa->phase == 2);
+      /* on phase I we do not need to wait until the current basic
+         solution becomes primal feasible; it is sufficient to make
+         sure that all reduced costs have correct signs */
+      if (csa->phase == 1 && check_feas(csa, parm->tol_dj) == 0)
+      {  /* the current basis is dual feasible; switch to phase II */
+         display(csa, parm, 1);
+         csa->phase = 2;
+         if (cbar_st != 1)
+         {  eval_cbar(csa);
+            cbar_st = 1;
+         }
+         set_orig_bnds(csa);
+#if 0 /* 06/IV-2009 */
+         build_N(csa);
+#endif
+         csa->refct = 0;
+         bbar_st = 0;
+      }
+      /* compute primal values of basic variables */
+      if (bbar_st == 0)
+      {  eval_bbar(csa);
+         if (csa->phase == 2)
+            csa->bbar[0] = eval_obj(csa);
+         bbar_st = 1; /* just computed */
+      }
+      /* redefine the reference space, if required */
+      switch (parm->pricing)
+      {  case GLP_PT_STD:
+            break;
+         case GLP_PT_PSE:
+            if (csa->refct == 0) reset_refsp(csa);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      /* at this point the basis factorization and all basic solution
+         components are valid */
+      xassert(binv_st && bbar_st && cbar_st);
+      /* check accuracy of current basic solution components (only for
+         debugging) */
+      if (check)
+      {  double e_bbar = err_in_bbar(csa);
+         double e_cbar = err_in_cbar(csa);
+         double e_gamma =
+            (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
+         xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
+            e_bbar, e_cbar, e_gamma);
+         xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
+      }
+      /* if the objective has to be maximized, check if it has reached
+         its lower limit */
+      if (csa->phase == 2 && csa->zeta < 0.0 &&
+          parm->obj_ll > -DBL_MAX && csa->bbar[0] <= parm->obj_ll)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("OBJECTIVE LOWER LIMIT REACHED; SEARCH TERMINATED\n"
+               );
+         store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
+         ret = GLP_EOBJLL;
+         goto done;
+      }
+      /* if the objective has to be minimized, check if it has reached
+         its upper limit */
+      if (csa->phase == 2 && csa->zeta > 0.0 &&
+          parm->obj_ul < +DBL_MAX && csa->bbar[0] >= parm->obj_ul)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("OBJECTIVE UPPER LIMIT REACHED; SEARCH TERMINATED\n"
+               );
+         store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
+         ret = GLP_EOBJUL;
+         goto done;
+      }
+      /* check if the iteration limit has been exhausted */
+      if (parm->it_lim < INT_MAX &&
+          csa->it_cnt - csa->it_beg >= parm->it_lim)
+      {  if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
+         {  if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               d_stat = GLP_INFEAS;
+               set_orig_bnds(csa);
+               eval_bbar(csa);
+               break;
+            case 2:
+               d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
+         ret = GLP_EITLIM;
+         goto done;
+      }
+      /* check if the time limit has been exhausted */
+      if (parm->tm_lim < INT_MAX &&
+          1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
+      {  if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
+         {  if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               d_stat = GLP_INFEAS;
+               set_orig_bnds(csa);
+               eval_bbar(csa);
+               break;
+            case 2:
+               d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
+         ret = GLP_ETMLIM;
+         goto done;
+      }
+      /* display the search progress */
+      display(csa, parm, 0);
+      /* choose basic variable xB[p] */
+      chuzr(csa, parm->tol_bnd);
+      if (csa->p == 0)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+               set_orig_bnds(csa);
+               eval_bbar(csa);
+               p_stat = GLP_INFEAS, d_stat = GLP_NOFEAS;
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("OPTIMAL SOLUTION FOUND\n");
+               p_stat = d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = 0;
+         goto done;
+      }
+      /* compute pivot row of the simplex table */
+      {  double *rho = csa->work4;
+         eval_rho(csa, rho);
+         if (rigorous) refine_rho(csa, rho);
+         eval_trow(csa, rho);
+         sort_trow(csa, parm->tol_bnd);
+      }
+      /* unlike primal simplex there is no need to check accuracy of
+         the primal value of xB[p] (which might be computed using the
+         pivot row), since bbar is a result of FTRAN */
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      long_step(csa);
+      if (csa->nbps > 0)
+      {  csa->q = csa->bkpt[csa->nbps].j;
+         if (csa->delta > 0.0)
+            csa->new_dq = + csa->bkpt[csa->nbps].t;
+         else
+            csa->new_dq = - csa->bkpt[csa->nbps].t;
+      }
+      else
+#endif
+      /* choose non-basic variable xN[q] */
+      switch (parm->r_test)
+      {  case GLP_RT_STD:
+            chuzc(csa, 0.0);
+            break;
+         case GLP_RT_HAR:
+            chuzc(csa, 0.30 * parm->tol_dj);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      if (csa->q == 0)
+      {  if (bbar_st != 1 || cbar_st != 1 || !rigorous)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            rigorous = 1;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("Error: unable to choose basic variable on ph"
+                     "ase I\n");
+               xassert(!lp->valid && lp->bfd == NULL);
+               lp->bfd = csa->bfd, csa->bfd = NULL;
+               lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+               lp->obj_val = 0.0;
+               lp->it_cnt = csa->it_cnt;
+               lp->some = 0;
+               ret = GLP_EFAIL;
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+               store_sol(csa, lp, GLP_NOFEAS, GLP_FEAS,
+                  csa->head[csa->p]);
+               ret = 0;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         goto done;
+      }
+      /* check if the pivot element is acceptable */
+      {  double piv = csa->trow_vec[csa->q];
+         double eps = 1e-5 * (1.0 + 0.01 * csa->trow_max);
+         if (fabs(piv) < eps)
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv = %.12g; eps = %g\n", piv, eps);
+            if (!rigorous)
+            {  rigorous = 5;
+               goto loop;
+            }
+         }
+      }
+      /* now xN[q] and xB[p] have been chosen anyhow */
+      /* compute pivot column of the simplex table */
+      eval_tcol(csa);
+      if (rigorous) refine_tcol(csa);
+      /* accuracy check based on the pivot element */
+      {  double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
+         double piv2 = csa->trow_vec[csa->q]; /* less accurate */
+         xassert(piv1 != 0.0);
+         if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
+             !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
+            if (binv_st != 1 || !rigorous)
+            {  if (binv_st != 1) binv_st = 0;
+               rigorous = 5;
+               goto loop;
+            }
+            /* (not a good idea; should be revised later) */
+            if (csa->tcol_vec[csa->p] == 0.0)
+            {  csa->tcol_nnz++;
+               xassert(csa->tcol_nnz <= csa->m);
+               csa->tcol_ind[csa->tcol_nnz] = csa->p;
+            }
+            csa->tcol_vec[csa->p] = piv2;
+         }
+      }
+      /* update primal values of basic variables */
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      if (csa->nbps > 0)
+      {  int kk, j, k;
+         for (kk = 1; kk < csa->nbps; kk++)
+         {  if (csa->bkpt[kk].t >= csa->bkpt[csa->nbps].t) continue;
+            j = csa->bkpt[kk].j;
+            k = csa->head[csa->m + j];
+            xassert(csa->type[k] == GLP_DB);
+            if (csa->stat[j] == GLP_NL)
+               csa->stat[j] = GLP_NU;
+            else
+               csa->stat[j] = GLP_NL;
+         }
+      }
+      bbar_st = 0;
+#else
+      update_bbar(csa);
+      if (csa->phase == 2)
+         csa->bbar[0] += (csa->cbar[csa->q] / csa->zeta) *
+            (csa->delta / csa->tcol_vec[csa->p]);
+      bbar_st = 2; /* updated */
+#endif
+      /* update reduced costs of non-basic variables */
+      update_cbar(csa);
+      cbar_st = 2; /* updated */
+      /* update steepest edge coefficients */
+      switch (parm->pricing)
+      {  case GLP_PT_STD:
+            break;
+         case GLP_PT_PSE:
+            if (csa->refct > 0) update_gamma(csa);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      /* update factorization of the basis matrix */
+      ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
+      if (ret == 0)
+         binv_st = 2; /* updated */
+      else
+      {  csa->valid = 0;
+         binv_st = 0; /* invalid */
+      }
+#if 0 /* 06/IV-2009 */
+      /* update matrix N */
+      del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
+      if (csa->type[csa->head[csa->p]] != GLP_FX)
+         add_N_col(csa, csa->q, csa->head[csa->p]);
+#endif
+      /* change the basis header */
+      change_basis(csa);
+      /* iteration complete */
+      csa->it_cnt++;
+      if (rigorous > 0) rigorous--;
+      goto loop;
+done: /* deallocate the common storage area */
+      free_csa(csa);
+      /* return to the calling program */
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpsql.c b/optional/glpk/glpsql.c
new file mode 100644
index 0000000..0e937ca
--- /dev/null
+++ b/optional/glpk/glpsql.c
@@ -0,0 +1,1631 @@
+/* glpsql.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Author: Heinrich Schuchardt <xypron.glpk at gmx.de>.
+*
+*  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 "-Wunused-function"
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpmpl.h"
+#include "glpsql.h"
+
+#ifdef ODBC_DLNAME
+#define HAVE_ODBC
+#define libodbc ODBC_DLNAME
+#define h_odbc (get_env_ptr()->h_odbc)
+#endif
+
+#ifdef MYSQL_DLNAME
+#define HAVE_MYSQL
+#define libmysql MYSQL_DLNAME
+#define h_mysql (get_env_ptr()->h_mysql)
+#endif
+
+static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
+      **sqllines);
+static void *db_mysql_open_int(TABDCA *dca, int mode, const char
+      **sqllines);
+
+/**********************************************************************/
+
+#if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
+
+#define SQL_FIELD_MAX 100
+/* maximal field count */
+
+#define SQL_FDLEN_MAX 255
+/* maximal field length */
+
+/***********************************************************************
+*  NAME
+*
+*  args_concat - concatenate arguments
+*
+*  SYNOPSIS
+*
+*  static char **args_concat(TABDCA *dca);
+*
+*  DESCRIPTION
+*
+*  The arguments passed in dca are SQL statements. A SQL statement may
+*  be split over multiple arguments. The last argument of a SQL
+*  statement will be terminated with a semilocon. Each SQL statement is
+*  merged into a single zero terminated string. Boundaries between
+*  arguments are replaced by space.
+*
+*  RETURNS
+*
+*  Buffer with SQL statements */
+
+static char **args_concat(TABDCA *dca)
+{
+   const char  *arg;
+   int          i;
+   int          j;
+   int          j0;
+   int          j1;
+   int          len;
+   int          lentot;
+   int          narg;
+   int          nline = 0;
+   void        *ret;
+   char       **sqllines = NULL;
+
+   narg = mpl_tab_num_args(dca);
+   /* The SQL statements start with argument 3. */
+   if (narg < 3)
+      return NULL;
+   /* Count the SQL statements */
+   for (j = 3; j <= narg; j++)
+   {
+      arg = mpl_tab_get_arg(dca, j);
+      len = strlen(arg);
+      if (arg[len-1] == ';' || j == narg)
+        nline ++;
+   }
+   /* Allocate string buffer. */
+   sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
+   /* Join arguments */
+   sqllines[0] = NULL;
+   j0     = 3;
+   i      = 0;
+   lentot = 0;
+   for (j = 3; j <= narg; j++)
+   {
+      arg = mpl_tab_get_arg(dca, j);
+      len = strlen(arg);
+      lentot += len;
+      if (arg[len-1] == ';' || j == narg)
+      {  /* Join arguments for a single SQL statement */
+         sqllines[i] = xmalloc(lentot+1);
+         sqllines[i+1] = NULL;
+         sqllines[i][0] = 0x00;
+         for (j1 = j0; j1 <= j; j1++)
+         {  if(j1>j0)
+               strcat(sqllines[i], " ");
+            strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
+         }
+         len = strlen(sqllines[i]);
+         if (sqllines[i][len-1] == ';')
+            sqllines[i][len-1] = 0x00;
+         j0 = j+1;
+         i++;
+         lentot = 0;
+      }
+   }
+   return sqllines;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  free_buffer - free multiline string buffer
+*
+*  SYNOPSIS
+*
+*  static void free_buffer(char **buf);
+*
+*  DESCRIPTION
+*
+*  buf is a list of strings terminated by NULL.
+*  The memory for the strings and for the list is released. */
+
+static void free_buffer(char **buf)
+{  int i;
+
+   for(i = 0; buf[i] != NULL; i++)
+      xfree(buf[i]);
+   xfree(buf);
+}
+
+static int db_escaped_string_length(const char* from)
+/* length of escaped string */
+{
+   int         count;
+   const char *pointer;
+
+    for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
+         count++)
+    {
+      switch (*pointer)
+      {
+         case '\'':
+            count++;
+            break;
+      }
+    }
+
+    return count;
+}
+
+static int db_escape_string (char *to, const char *from)
+/* escape string*/
+{
+   const char *source = from;
+   char *target = to;
+   unsigned int remaining;
+
+   remaining = strlen(from);
+
+   if (to == NULL)
+     to = (char *) (from + remaining);
+
+   while (remaining > 0)
+   {
+      switch (*source)
+      {
+         case '\'':
+            *target = '\'';
+            target++;
+            *target = '\'';
+            break;
+
+         default:
+            *target = *source;
+            }
+      source++;
+      target++;
+      remaining--;
+      }
+
+   /* Write the terminating NUL character. */
+   *target = '\0';
+
+   return target - to;
+}
+
+static char *db_generate_select_stmt(TABDCA *dca)
+/* generate select statement */
+{
+   char        *arg;
+   char const  *field;
+   char        *query;
+   int          j;
+   int          narg;
+   int          nf;
+   int          total;
+
+   total = 50;
+   nf = mpl_tab_num_flds(dca);
+   narg = mpl_tab_num_args(dca);
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      total += strlen(field);
+      total += 2;
+   }
+   arg = (char *) mpl_tab_get_arg(dca, narg);
+   total += strlen(arg);
+   query = xmalloc( total * sizeof(char));
+   strcpy (query, "SELECT ");
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      strcat(query, field);
+      if ( j < nf )
+         strcat(query, ", ");
+   }
+   strcat(query, " FROM ");
+   strcat(query, arg);
+   return query;
+}
+
+static char *db_generate_insert_stmt(TABDCA *dca)
+/* generate insert statement */
+{
+   char        *arg;
+   char const  *field;
+   char        *query;
+   int          j;
+   int          narg;
+   int          nf;
+   int          total;
+
+   total = 50;
+   nf = mpl_tab_num_flds(dca);
+   narg = mpl_tab_num_args(dca);
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      total += strlen(field);
+      total += 5;
+   }
+   arg = (char *) mpl_tab_get_arg(dca, narg);
+   total += strlen(arg);
+   query = xmalloc( (total+1) * sizeof(char));
+   strcpy (query, "INSERT INTO ");
+   strcat(query, arg);
+   strcat(query, " ( ");
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      strcat(query, field);
+      if ( j < nf )
+         strcat(query, ", ");
+   }
+   strcat(query, " ) VALUES ( ");
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      strcat(query, "?");
+      if ( j < nf )
+         strcat(query, ", ");
+   }
+   strcat(query, " )");
+   return query;
+}
+
+#endif
+
+/**********************************************************************/
+
+#ifndef HAVE_ODBC
+
+void *db_iodbc_open(TABDCA *dca, int mode)
+{     xassert(dca == dca);
+      xassert(mode == mode);
+      xprintf("iODBC table driver not supported\n");
+      return NULL;
+}
+
+int db_iodbc_read(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_iodbc_write(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_iodbc_close(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+#else
+
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
+#include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+struct db_odbc
+{
+   int              mode;         /*'R' = Read, 'W' = Write*/
+   SQLHDBC          hdbc;         /*connection handle*/
+   SQLHENV          henv;         /*environment handle*/
+   SQLHSTMT         hstmt;        /*statement handle*/
+   SQLSMALLINT      nresultcols;  /* columns in result*/
+   SQLULEN          collen[SQL_FIELD_MAX+1];
+   SQLLEN           outlen[SQL_FIELD_MAX+1];
+   SQLSMALLINT      coltype[SQL_FIELD_MAX+1];
+   SQLCHAR          data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
+   SQLCHAR          colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
+   int              isnumeric[SQL_FIELD_MAX+1];
+   int              nf;
+   /* number of fields in the csv file */
+   int              ref[1+SQL_FIELD_MAX];
+   /* ref[k] = k', if k-th field of the csv file corresponds to
+      k'-th field in the table statement; if ref[k] = 0, k-th field
+      of the csv file is ignored */
+   SQLCHAR         *query;
+   /* query generated by db_iodbc_open */
+};
+
+SQLRETURN SQL_API dl_SQLAllocHandle (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             InputHandle,
+   SQLHANDLE            *OutputHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLAllocHandle(
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             InputHandle,
+         SQLHANDLE            *OutputHandle);
+
+      ep_SQLAllocHandle *fn;
+      fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, InputHandle, OutputHandle);
+}
+
+SQLRETURN SQL_API dl_SQLBindCol (
+   SQLHSTMT              StatementHandle,
+   SQLUSMALLINT          ColumnNumber,
+   SQLSMALLINT           TargetType,
+   SQLPOINTER            TargetValue,
+   SQLLEN                BufferLength,
+   SQLLEN               *StrLen_or_Ind)
+{
+      typedef SQLRETURN SQL_API ep_SQLBindCol(
+         SQLHSTMT              StatementHandle,
+         SQLUSMALLINT          ColumnNumber,
+         SQLSMALLINT           TargetType,
+         SQLPOINTER            TargetValue,
+         SQLLEN                BufferLength,
+         SQLLEN               *StrLen_or_Ind);
+      ep_SQLBindCol *fn;
+      fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, ColumnNumber, TargetType,
+         TargetValue, BufferLength, StrLen_or_Ind);
+}
+
+SQLRETURN SQL_API dl_SQLCloseCursor (
+   SQLHSTMT              StatementHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLCloseCursor (
+         SQLHSTMT              StatementHandle);
+
+      ep_SQLCloseCursor *fn;
+      fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle);
+}
+
+
+SQLRETURN SQL_API dl_SQLDisconnect (
+   SQLHDBC               ConnectionHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLDisconnect(
+         SQLHDBC               ConnectionHandle);
+
+      ep_SQLDisconnect *fn;
+      fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
+      xassert(fn != NULL);
+      return (*fn)(ConnectionHandle);
+}
+
+SQLRETURN SQL_API dl_SQLDriverConnect (
+   SQLHDBC               hdbc,
+   SQLHWND               hwnd,
+   SQLCHAR              *szConnStrIn,
+   SQLSMALLINT           cbConnStrIn,
+   SQLCHAR              *szConnStrOut,
+   SQLSMALLINT           cbConnStrOutMax,
+   SQLSMALLINT          *pcbConnStrOut,
+   SQLUSMALLINT          fDriverCompletion)
+{
+      typedef SQLRETURN SQL_API ep_SQLDriverConnect(
+         SQLHDBC               hdbc,
+         SQLHWND               hwnd,
+         SQLCHAR             * szConnStrIn,
+         SQLSMALLINT           cbConnStrIn,
+         SQLCHAR             * szConnStrOut,
+         SQLSMALLINT           cbConnStrOutMax,
+         SQLSMALLINT         * pcbConnStrOut,
+         SQLUSMALLINT          fDriverCompletion);
+
+      ep_SQLDriverConnect *fn;
+      fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
+      xassert(fn != NULL);
+      return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
+         cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
+}
+
+SQLRETURN SQL_API dl_SQLEndTran (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             Handle,
+   SQLSMALLINT           CompletionType)
+{
+      typedef SQLRETURN SQL_API ep_SQLEndTran (
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             Handle,
+         SQLSMALLINT           CompletionType);
+
+      ep_SQLEndTran *fn;
+      fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, Handle, CompletionType);
+}
+
+SQLRETURN SQL_API dl_SQLExecDirect (
+   SQLHSTMT              StatementHandle,
+   SQLCHAR             * StatementText,
+   SQLINTEGER            TextLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLExecDirect (
+         SQLHSTMT              StatementHandle,
+         SQLCHAR             * StatementText,
+         SQLINTEGER            TextLength);
+
+      ep_SQLExecDirect *fn;
+      fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, StatementText, TextLength);
+}
+
+SQLRETURN SQL_API dl_SQLFetch (
+   SQLHSTMT              StatementHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLFetch (
+         SQLHSTMT              StatementHandle);
+
+      ep_SQLFetch *fn;
+      fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle);
+}
+
+SQLRETURN SQL_API dl_SQLFreeHandle (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             Handle)
+{
+      typedef SQLRETURN SQL_API ep_SQLFreeHandle (
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             Handle);
+
+      ep_SQLFreeHandle *fn;
+      fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, Handle);
+}
+
+SQLRETURN SQL_API dl_SQLDescribeCol (
+   SQLHSTMT              StatementHandle,
+   SQLUSMALLINT          ColumnNumber,
+   SQLCHAR             * ColumnName,
+   SQLSMALLINT           BufferLength,
+   SQLSMALLINT         * NameLength,
+   SQLSMALLINT         * DataType,
+   SQLULEN             * ColumnSize,
+   SQLSMALLINT         * DecimalDigits,
+   SQLSMALLINT         * Nullable)
+{
+      typedef SQLRETURN SQL_API ep_SQLDescribeCol (
+         SQLHSTMT              StatementHandle,
+         SQLUSMALLINT          ColumnNumber,
+         SQLCHAR              *ColumnName,
+         SQLSMALLINT           BufferLength,
+         SQLSMALLINT          *NameLength,
+         SQLSMALLINT          *DataType,
+         SQLULEN              *ColumnSize,
+         SQLSMALLINT          *DecimalDigits,
+         SQLSMALLINT          *Nullable);
+
+      ep_SQLDescribeCol *fn;
+      fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, ColumnNumber, ColumnName,
+         BufferLength, NameLength,
+         DataType, ColumnSize, DecimalDigits, Nullable);
+}
+
+SQLRETURN SQL_API dl_SQLGetDiagRec (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             Handle,
+   SQLSMALLINT           RecNumber,
+   SQLCHAR              *Sqlstate,
+   SQLINTEGER           *NativeError,
+   SQLCHAR              *MessageText,
+   SQLSMALLINT           BufferLength,
+   SQLSMALLINT          *TextLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             Handle,
+         SQLSMALLINT           RecNumber,
+         SQLCHAR              *Sqlstate,
+         SQLINTEGER           *NativeError,
+         SQLCHAR              *MessageText,
+         SQLSMALLINT           BufferLength,
+         SQLSMALLINT          *TextLength);
+
+      ep_SQLGetDiagRec *fn;
+      fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
+         NativeError, MessageText, BufferLength, TextLength);
+}
+
+SQLRETURN SQL_API dl_SQLGetInfo (
+   SQLHDBC               ConnectionHandle,
+   SQLUSMALLINT          InfoType,
+   SQLPOINTER            InfoValue,
+   SQLSMALLINT           BufferLength,
+   SQLSMALLINT          *StringLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLGetInfo (
+         SQLHDBC               ConnectionHandle,
+         SQLUSMALLINT          InfoType,
+         SQLPOINTER            InfoValue,
+         SQLSMALLINT           BufferLength,
+         SQLSMALLINT          *StringLength);
+
+      ep_SQLGetInfo *fn;
+      fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
+      xassert(fn != NULL);
+      return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
+         StringLength);
+}
+
+SQLRETURN SQL_API dl_SQLNumResultCols (
+   SQLHSTMT              StatementHandle,
+   SQLSMALLINT          *ColumnCount)
+{
+      typedef SQLRETURN SQL_API ep_SQLNumResultCols (
+         SQLHSTMT              StatementHandle,
+         SQLSMALLINT          *ColumnCount);
+
+      ep_SQLNumResultCols *fn;
+      fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, ColumnCount);
+}
+
+SQLRETURN SQL_API dl_SQLSetConnectAttr (
+   SQLHDBC               ConnectionHandle,
+   SQLINTEGER            Attribute,
+   SQLPOINTER            Value,
+   SQLINTEGER            StringLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
+         SQLHDBC               ConnectionHandle,
+         SQLINTEGER            Attribute,
+         SQLPOINTER            Value,
+         SQLINTEGER            StringLength);
+
+      ep_SQLSetConnectAttr *fn;
+     fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
+      xassert(fn != NULL);
+      return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
+}
+
+SQLRETURN SQL_API dl_SQLSetEnvAttr (
+   SQLHENV               EnvironmentHandle,
+   SQLINTEGER            Attribute,
+   SQLPOINTER            Value,
+   SQLINTEGER            StringLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
+         SQLHENV               EnvironmentHandle,
+         SQLINTEGER            Attribute,
+         SQLPOINTER            Value,
+         SQLINTEGER            StringLength);
+
+      ep_SQLSetEnvAttr *fn;
+      fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
+      xassert(fn != NULL);
+      return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
+}
+
+static void extract_error(
+   char *fn,
+   SQLHANDLE handle,
+   SQLSMALLINT type);
+
+static int is_numeric(
+    SQLSMALLINT coltype);
+
+/***********************************************************************
+*  NAME
+*
+*  db_iodbc_open - open connection to ODBC data base
+*
+*  SYNOPSIS
+*
+*  #include "glpsql.h"
+*  void *db_iodbc_open(TABDCA *dca, int mode);
+*
+*  DESCRIPTION
+*
+*  The routine db_iodbc_open opens a connection to an ODBC data base.
+*  It then executes the sql statements passed.
+*
+*  In the case of table read the SELECT statement is executed.
+*
+*  In the case of table write the INSERT statement is prepared.
+*  RETURNS
+*
+*  The routine returns a pointer to data storage area created. */
+void *db_iodbc_open(TABDCA *dca, int mode)
+{  void  *ret;
+   char **sqllines;
+
+   sqllines = args_concat(dca);
+   if (sqllines == NULL)
+   {  xprintf("Missing arguments in table statement.\n"
+              "Please, supply table driver, dsn, and query.\n");
+      return NULL;
+   }
+   ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
+   free_buffer(sqllines);
+   return ret;
+}
+
+static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
+   **sqllines)
+{
+   struct db_odbc    *sql;
+   SQLRETURN          ret;
+   SQLCHAR FAR       *dsn;
+   SQLCHAR            info[256];
+   SQLSMALLINT        colnamelen;
+   SQLSMALLINT        nullable;
+   SQLSMALLINT        scale;
+   const char        *arg;
+   int                narg;
+   int                i, j;
+   int                total;
+
+   if (libodbc == NULL)
+   {
+      xprintf("No loader for shared ODBC library available\n");
+      return NULL;
+   }
+
+   if (h_odbc == NULL)
+   {
+      h_odbc = xdlopen(libodbc);
+      if (h_odbc == NULL)
+      {  xprintf("unable to open library %s\n", libodbc);
+         xprintf("%s\n", xerrmsg());
+         return NULL;
+      }
+   }
+
+   sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
+   if (sql == NULL)
+         return NULL;
+
+   sql->mode  = mode;
+   sql->hdbc  = NULL;
+   sql->henv  = NULL;
+   sql->hstmt = NULL;
+   sql->query = NULL;
+   narg = mpl_tab_num_args(dca);
+
+   dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
+   /* allocate an environment handle */
+   ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
+      &(sql->henv));
+   /* set attribute to enable application to run as ODBC 3.0
+      application */
+   ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
+      (void *) SQL_OV_ODBC3, 0);
+   /* allocate a connection handle */
+   ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
+   /* connect */
+   ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
+      NULL, SQL_DRIVER_COMPLETE);
+   if (SQL_SUCCEEDED(ret))
+   {  /* output information about data base connection */
+      xprintf("Connected to ");
+      dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
+         sizeof(info), NULL);
+      xprintf("%s ", info);
+      dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
+         sizeof(info), NULL);
+      xprintf("%s - ", info);
+      dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
+         sizeof(info), NULL);
+      xprintf("%s\n", info);
+   }
+   else
+   {  /* describe error */
+      xprintf("Failed to connect\n");
+      extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
+      dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+      dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+      xfree(sql);
+      return NULL;
+   }
+   /* set AUTOCOMMIT on*/
+   ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
+      (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
+   /* allocate a statement handle */
+   ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
+
+   /* initialization queries */
+   for(j = 0; sqllines[j+1] != NULL; j++)
+   {
+      sql->query = (SQLCHAR *) sqllines[j];
+      xprintf("%s\n", sql->query);
+      ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
+      switch (ret)
+      {
+         case SQL_SUCCESS:
+         case SQL_SUCCESS_WITH_INFO:
+         case SQL_NO_DATA_FOUND:
+            break;
+         default:
+            xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
+               sql->query);
+            extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
+            dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+            dl_SQLDisconnect(sql->hdbc);
+            dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+            dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+            xfree(sql);
+            return NULL;
+      }
+      /* commit statement */
+      dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
+   }
+
+   if ( sql->mode == 'R' )
+   {  sql->nf = mpl_tab_num_flds(dca);
+      for(j = 0; sqllines[j] != NULL; j++)
+         arg = sqllines[j];
+      total = strlen(arg);
+      if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
+      {
+         total = strlen(arg);
+         sql->query = xmalloc( (total+1) * sizeof(char));
+         strcpy (sql->query, arg);
+      }
+      else
+      {
+         sql->query = db_generate_select_stmt(dca);
+      }
+      xprintf("%s\n", sql->query);
+      if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
+         SQL_SUCCESS)
+      {
+         xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
+         extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
+         dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+         dl_SQLDisconnect(sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+         xfree(sql->query);
+            xfree(sql);
+         return NULL;
+      }
+      xfree(sql->query);
+      /* determine number of result columns */
+      ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
+      total = sql->nresultcols;
+      if (total > SQL_FIELD_MAX)
+      {  xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
+            "\"%s\"\n", SQL_FIELD_MAX, sql->query);
+         dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+         dl_SQLDisconnect(sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+         xfree(sql->query);
+         return NULL;
+      }
+      for (i = 1; i <= total; i++)
+      {  /* return a set of attributes for a column */
+         ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
+            sql->colname[i], SQL_FDLEN_MAX,
+            &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
+            &nullable);
+         sql->isnumeric[i] = is_numeric(sql->coltype[i]);
+         /* bind columns to program vars, converting all types to CHAR*/
+         dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
+            SQL_FDLEN_MAX, &(sql->outlen[i]));
+         for (j = sql->nf; j >= 1; j--)
+         {  if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
+            break;
+         }
+         sql->ref[i] = j;
+      }
+   }
+   else if ( sql->mode == 'W' )
+   {  for(j = 0; sqllines[j] != NULL; j++)
+         arg = sqllines[j];
+      if (  NULL != strchr(arg, '?') )
+      {
+         total = strlen(arg);
+         sql->query = xmalloc( (total+1) * sizeof(char));
+         strcpy (sql->query, arg);
+         }
+      else
+      {
+         sql->query = db_generate_insert_stmt(dca);
+      }
+      xprintf("%s\n", sql->query);
+   }
+   return sql;
+}
+
+int db_iodbc_read(TABDCA *dca, void *link)
+{
+   struct db_odbc  *sql;
+   SQLRETURN        ret;
+   char             buf[SQL_FDLEN_MAX+1];
+   int              i;
+   int              len;
+   double           num;
+
+   sql = (struct db_odbc *) link;
+
+   xassert(sql != NULL);
+   xassert(sql->mode == 'R');
+
+   ret=dl_SQLFetch(sql->hstmt);
+   if (ret== SQL_ERROR)
+      return -1;
+   if (ret== SQL_NO_DATA_FOUND)
+      return -1; /*EOF*/
+   for (i=1; i <= sql->nresultcols; i++)
+   {
+      if (sql->ref[i] > 0)
+      {
+         len = sql->outlen[i];
+         if (len != SQL_NULL_DATA)
+         {
+            if (len > SQL_FDLEN_MAX)
+               len = SQL_FDLEN_MAX;
+            else if (len < 0)
+               len = 0;
+            strncpy(buf, (const char *) sql->data[i], len);
+            buf[len] = 0x00;
+            if (0 != (sql->isnumeric[i]))
+            {  strspx(buf); /* remove spaces*/
+               if (str2num(buf, &num) != 0)
+               {  xprintf("'%s' cannot be converted to a number.\n",
+                     buf);
+                  return 1;
+               }
+               mpl_tab_set_num(dca, sql->ref[i], num);
+            }
+            else
+            {  mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
+            }
+         }
+      }
+   }
+   return 0;
+}
+
+int db_iodbc_write(TABDCA *dca, void *link)
+{
+   struct db_odbc  *sql;
+   char            *part;
+   char            *query;
+   char            *template;
+   char             num[50];
+   int              k;
+   int              len;
+   int              nf;
+
+   sql = (struct db_odbc *) link;
+   xassert(sql != NULL);
+   xassert(sql->mode == 'W');
+
+   len      = strlen(sql->query);
+   template = (char *) xmalloc( (len + 1) * sizeof(char) );
+   strcpy(template, sql->query);
+
+   nf = mpl_tab_num_flds(dca);
+   for (k = 1; k <= nf; k++)
+   {     switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+            len += 20;
+            break;
+         case 'S':
+            len += db_escaped_string_length(mpl_tab_get_str(dca, k));
+            len += 2;
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   query = xmalloc( (len + 1 ) * sizeof(char) );
+   query[0] = 0x00;
+   for (k = 1, part = strtok (template, "?"); (part != NULL);
+      part = strtok (NULL, "?"), k++)
+   {
+      if (k > nf) break;
+      strcat( query, part );
+      switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+#if 0 /* 02/XI-2010 by xypron */
+            sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
+#else
+            sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+#endif
+            strcat( query, num );
+            break;
+         case 'S':
+            strcat( query, "'");
+            db_escape_string( query + strlen(query),
+               mpl_tab_get_str(dca, k) );
+            strcat( query, "'");
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   if (part != NULL)
+      strcat(query, part);
+   if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
+      != SQL_SUCCESS)
+   {
+      xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
+      extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
+      xfree(query);
+      xfree(template);
+      return 1;
+      }
+
+   xfree(query);
+   xfree(template);
+   return 0;
+}
+
+int db_iodbc_close(TABDCA *dca, void *link)
+{
+   struct db_odbc *sql;
+
+   sql = (struct db_odbc *) link;
+   xassert(sql != NULL);
+   /* Commit */
+   if ( sql->mode == 'W' )
+      dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
+   if ( sql->mode == 'R' )
+      dl_SQLCloseCursor(sql->hstmt);
+
+   dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+   dl_SQLDisconnect(sql->hdbc);
+   dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+   dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+   if ( sql->mode == 'W' )
+      xfree(sql->query);
+   xfree(sql);
+   dca->link = NULL;
+   return 0;
+}
+
+static void extract_error(
+   char *fn,
+   SQLHANDLE handle,
+   SQLSMALLINT type)
+{
+   SQLINTEGER   i = 0;
+   SQLINTEGER   native;
+   SQLCHAR   state[ 7 ];
+   SQLCHAR   text[256];
+   SQLSMALLINT  len;
+   SQLRETURN    ret;
+
+   xprintf("\nThe driver reported the following diagnostics whilst "
+      "running %s\n", fn);
+
+   do
+   {
+      ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
+         sizeof(text), &len );
+      if (SQL_SUCCEEDED(ret))
+         xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
+   }
+   while( ret == SQL_SUCCESS );
+}
+
+static int is_numeric(SQLSMALLINT coltype)
+{
+   int ret = 0;
+   switch (coltype)
+   {
+      case SQL_DECIMAL:
+      case SQL_NUMERIC:
+      case SQL_SMALLINT:
+      case SQL_INTEGER:
+      case SQL_REAL:
+      case SQL_FLOAT:
+      case SQL_DOUBLE:
+      case SQL_TINYINT:
+      case SQL_BIGINT:
+         ret = 1;
+         break;
+   }
+   return ret;
+}
+
+#endif
+
+/**********************************************************************/
+
+#ifndef HAVE_MYSQL
+
+void *db_mysql_open(TABDCA *dca, int mode)
+{     xassert(dca == dca);
+      xassert(mode == mode);
+      xprintf("MySQL table driver not supported\n");
+      return NULL;
+}
+
+int db_mysql_read(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_mysql_write(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_mysql_close(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+#else
+
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
+#include <windows.h>
+#endif
+
+#ifdef __CYGWIN__
+#define byte_defined 1
+#endif
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <mysql.h>
+
+struct db_mysql
+{
+   int              mode;  /*'R' = Read, 'W' = Write*/
+   MYSQL           *con;   /*connection*/
+   MYSQL_RES       *res;    /*result*/
+   int              nf;
+   /* number of fields in the csv file */
+   int              ref[1+SQL_FIELD_MAX];
+   /* ref[k] = k', if k-th field of the csv file corresponds to
+      k'-th field in the table statement; if ref[k] = 0, k-th field
+      of the csv file is ignored */
+   char            *query;
+   /* query generated by db_mysql_open */
+};
+
+void STDCALL dl_mysql_close(MYSQL *sock)
+{
+      typedef void STDCALL ep_mysql_close(MYSQL *sock);
+
+      ep_mysql_close *fn;
+      fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
+      xassert(fn != NULL);
+      return (*fn)(sock);
+}
+
+const char * STDCALL dl_mysql_error(MYSQL *mysql)
+{
+      typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
+
+      ep_mysql_error *fn;
+      fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
+{
+      typedef MYSQL_FIELD * STDCALL
+         ep_mysql_fetch_fields(MYSQL_RES *res);
+
+      ep_mysql_fetch_fields *fn;
+   fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
+      xassert(fn != NULL);
+      return (*fn)(res);
+}
+
+unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
+{
+      typedef unsigned long * STDCALL
+         ep_mysql_fetch_lengths(MYSQL_RES *result);
+
+      ep_mysql_fetch_lengths *fn;
+      fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
+         "mysql_fetch_lengths");
+      xassert(fn != NULL);
+      return (*fn)(result);
+}
+
+MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
+{
+      typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
+
+      ep_mysql_fetch_row *fn;
+      fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
+      xassert(fn != NULL);
+      return (*fn)(result);
+}
+
+unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
+{
+      typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
+
+      ep_mysql_field_count *fn;
+     fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
+{
+      typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
+
+      ep_mysql_init *fn;
+      fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
+{
+      typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
+
+      ep_mysql_num_fields *fn;
+      fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
+      xassert(fn != NULL);
+      return (*fn)(res);
+}
+
+int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
+{
+      typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
+
+      ep_mysql_query *fn;
+      fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
+      xassert(fn != NULL);
+      return (*fn)(mysql, q);
+}
+
+MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
+                                           const char *user,
+                                           const char *passwd,
+                                           const char *db,
+                                           unsigned int port,
+                                           const char *unix_socket,
+                                           unsigned long clientflag)
+{
+      typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
+            const char *host,
+            const char *user,
+            const char *passwd,
+            const char *db,
+            unsigned int port,
+            const char *unix_socket,
+            unsigned long clientflag);
+
+      ep_mysql_real_connect *fn;
+      fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
+         "mysql_real_connect");
+      xassert(fn != NULL);
+      return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
+         clientflag);
+}
+
+MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
+{
+      typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
+      ep_mysql_use_result *fn;
+      fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  db_mysql_open - open connection to ODBC data base
+*
+*  SYNOPSIS
+*
+*  #include "glpsql.h"
+*  void *db_mysql_open(TABDCA *dca, int mode);
+*
+*  DESCRIPTION
+*
+*  The routine db_mysql_open opens a connection to a MySQL data base.
+*  It then executes the sql statements passed.
+*
+*  In the case of table read the SELECT statement is executed.
+*
+*  In the case of table write the INSERT statement is prepared.
+*  RETURNS
+*
+*  The routine returns a pointer to data storage area created. */
+
+void *db_mysql_open(TABDCA *dca, int mode)
+{  void  *ret;
+   char **sqllines;
+
+   sqllines = args_concat(dca);
+   if (sqllines == NULL)
+   {  xprintf("Missing arguments in table statement.\n"
+              "Please, supply table driver, dsn, and query.\n");
+      return NULL;
+   }
+   ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
+   free_buffer(sqllines);
+   return ret;
+}
+
+static void *db_mysql_open_int(TABDCA *dca, int mode, const char
+   **sqllines)
+{
+   struct db_mysql *sql = NULL;
+   char            *arg = NULL;
+   const char      *field;
+   MYSQL_FIELD     *fields;
+   char            *keyword;
+   char            *value;
+   char            *query;
+   char            *dsn;
+/* "Server=[server_name];Database=[database_name];UID=[username];*/
+/* PWD=[password];Port=[port]"*/
+   char            *server   = NULL;        /* Server */
+   char            *user     = NULL;        /* UID */
+   char            *password = NULL;        /* PWD */
+   char            *database = NULL;        /* Database */
+   unsigned int     port = 0;               /* Port */
+   int              narg;
+   int              i, j, total;
+
+   if (libmysql == NULL)
+   {
+      xprintf("No loader for shared MySQL library available\n");
+      return NULL;
+   }
+
+   if (h_mysql == NULL)
+   {
+      h_mysql = xdlopen(libmysql);
+      if (h_mysql == NULL)
+      {  xprintf("unable to open library %s\n", libmysql);
+         xprintf("%s\n", xerrmsg());
+         return NULL;
+      }
+   }
+
+   sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
+   if (sql == NULL)
+         return NULL;
+   sql->mode = mode;
+   sql->res = NULL;
+   sql->query = NULL;
+   sql->nf = mpl_tab_num_flds(dca);
+
+   narg = mpl_tab_num_args(dca);
+   if (narg < 3 )
+      xprintf("MySQL driver: string list too short \n");
+
+   /* get connection string*/
+   dsn = (char *) mpl_tab_get_arg(dca, 2);
+      /* copy connection string*/
+   i = strlen(dsn);
+   i++;
+   arg = xmalloc(i * sizeof(char));
+   strcpy(arg, dsn);
+   /*tokenize connection string*/
+   for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
+      keyword = strtok (NULL, "="), i++)
+   {
+         value = strtok (NULL, ";");
+      if (value==NULL)
+         {
+            xprintf("db_mysql_open: Missing value for keyword %s\n",
+               keyword);
+            xfree(arg);
+            xfree(sql);
+            return NULL;
+      }
+      if (0 == strcmp(keyword, "Server"))
+            server = value;
+      else if (0 == strcmp(keyword, "Database"))
+             database = value;
+      else if (0 == strcmp(keyword, "UID"))
+             user = value;
+      else if (0 == strcmp(keyword, "PWD"))
+             password = value;
+      else if (0 == strcmp(keyword, "Port"))
+             port = (unsigned int) atol(value);
+   }
+   /* Connect to database */
+   sql->con = dl_mysql_init(NULL);
+  if (!dl_mysql_real_connect(sql->con, server, user, password, database,
+      port, NULL, 0))
+   {
+      xprintf("db_mysql_open: Connect failed\n");
+      xprintf("%s\n", dl_mysql_error(sql->con));
+      xfree(arg);
+      xfree(sql);
+      return NULL;
+   }
+   xfree(arg);
+
+   for(j = 0; sqllines[j+1] != NULL; j++)
+   {  query = (char *) sqllines[j];
+      xprintf("%s\n", query);
+      if (dl_mysql_query(sql->con, query))
+      {
+         xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+         xprintf("%s\n",dl_mysql_error(sql->con));
+         dl_mysql_close(sql->con);
+         xfree(sql);
+         return NULL;
+      }
+   }
+
+   if ( sql->mode == 'R' )
+   {  sql->nf = mpl_tab_num_flds(dca);
+      for(j = 0; sqllines[j] != NULL; j++)
+         arg = (char *) sqllines[j];
+      total = strlen(arg);
+      if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
+      {
+         total = strlen(arg);
+         query = xmalloc( (total+1) * sizeof(char));
+         strcpy (query, arg);
+      }
+      else
+      {
+         query = db_generate_select_stmt(dca);
+      }
+      xprintf("%s\n", query);
+      if (dl_mysql_query(sql->con, query))
+      {
+         xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+         xprintf("%s\n",dl_mysql_error(sql->con));
+         dl_mysql_close(sql->con);
+         xfree(query);
+         xfree(sql);
+         return NULL;
+      }
+      xfree(query);
+      sql->res = dl_mysql_use_result(sql->con);
+      if (sql->res)
+      {
+         /* create references between query results and table fields*/
+         total = dl_mysql_num_fields(sql->res);
+         if (total > SQL_FIELD_MAX)
+         {  xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
+               "\"%s\"\n", SQL_FIELD_MAX, query);
+            xprintf("%s\n",dl_mysql_error(sql->con));
+            dl_mysql_close(sql->con);
+            xfree(query);
+                 xfree(sql);
+            return NULL;
+         }
+         fields = dl_mysql_fetch_fields(sql->res);
+         for (i = 1; i <= total; i++)
+         {
+               for (j = sql->nf; j >= 1; j--)
+            {
+               if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
+                  == 0)
+               break;
+            }
+            sql->ref[i] = j;
+         }
+      }
+      else
+      {
+         if(dl_mysql_field_count(sql->con) == 0)
+            {
+            xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
+               query);
+            xprintf("%s\n",dl_mysql_error(sql->con));
+            xfree(query);
+            xfree(sql);
+            return NULL;
+         }
+         else
+         {
+            xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+            xprintf("%s\n",dl_mysql_error(sql->con));
+            xfree(query);
+            xfree(sql);
+            return NULL;
+         }
+      }
+   }
+   else if ( sql->mode == 'W' )
+   {  for(j = 0; sqllines[j] != NULL; j++)
+         arg = (char *) sqllines[j];
+      if (  NULL != strchr(arg, '?') )
+      {
+         total = strlen(arg);
+         query = xmalloc( (total+1) * sizeof(char));
+         strcpy (query, arg);
+         }
+      else
+         query = db_generate_insert_stmt(dca);
+      sql->query = query;
+      xprintf("%s\n", query);
+   }
+   return sql;
+}
+
+int db_mysql_read(TABDCA *dca, void *link)
+{  struct db_mysql *sql;
+   char            buf[255+1];
+   char            **row;
+   unsigned long   *lengths;
+   MYSQL_FIELD     *fields;
+   double          num;
+   int             len;
+   unsigned long   num_fields;
+   int             i;
+
+   sql = (struct db_mysql *) link;
+
+   xassert(sql != NULL);
+   xassert(sql->mode == 'R');
+   if (NULL == sql->res)
+   {
+      xprintf("db_mysql_read: no result set available");
+      return 1;
+   }
+   if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
+       return -1; /*EOF*/
+   }
+   lengths = dl_mysql_fetch_lengths(sql->res);
+   fields = dl_mysql_fetch_fields(sql->res);
+   num_fields = dl_mysql_num_fields(sql->res);
+   for (i=1; i <= num_fields; i++)
+   {
+      if (row[i-1] != NULL)
+      {  len = (size_t) lengths[i-1];
+         if (len > 255)
+            len = 255;
+         strncpy(buf, (const char *) row[i-1], len);
+         buf[len] = 0x00;
+         if (0 != (fields[i-1].flags & NUM_FLAG))
+         {  strspx(buf); /* remove spaces*/
+            if (str2num(buf, &num) != 0)
+            {  xprintf("'%s' cannot be converted to a number.\n", buf);
+               return 1;
+            }
+            if (sql->ref[i] > 0)
+               mpl_tab_set_num(dca, sql->ref[i], num);
+         }
+         else
+         {  if (sql->ref[i] > 0)
+               mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
+         }
+      }
+   }
+   return 0;
+}
+
+int db_mysql_write(TABDCA *dca, void *link)
+{
+   struct db_mysql *sql;
+   char            *part;
+   char            *query;
+   char            *template;
+   char             num[50];
+   int              k;
+   int              len;
+   int              nf;
+
+   sql = (struct db_mysql *) link;
+   xassert(sql != NULL);
+   xassert(sql->mode == 'W');
+
+   len      = strlen(sql->query);
+   template = (char *) xmalloc( (len + 1) * sizeof(char) );
+   strcpy(template, sql->query);
+
+   nf = mpl_tab_num_flds(dca);
+   for (k = 1; k <= nf; k++)
+   {     switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+            len += 20;
+            break;
+         case 'S':
+            len += db_escaped_string_length(mpl_tab_get_str(dca, k));
+            len += 2;
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   query = xmalloc( (len + 1 ) * sizeof(char) );
+   query[0] = 0x00;
+   for (k = 1, part = strtok (template, "?"); (part != NULL);
+      part = strtok (NULL, "?"), k++)
+   {
+      if (k > nf) break;
+      strcat( query, part );
+      switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+#if 0 /* 02/XI-2010 by xypron */
+            sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
+#else
+            sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+#endif
+            strcat( query, num );
+            break;
+         case 'S':
+            strcat( query, "'");
+            db_escape_string( query + strlen(query),
+               mpl_tab_get_str(dca, k) );
+            strcat( query, "'");
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   if (part != NULL)
+      strcat(query, part);
+   if (dl_mysql_query(sql->con, query))
+   {
+      xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
+      xprintf("%s\n",dl_mysql_error(sql->con));
+      xfree(query);
+      xfree(template);
+      return 1;
+      }
+
+   xfree(query);
+   xfree(template);
+   return 0;
+   }
+
+int db_mysql_close(TABDCA *dca, void *link)
+{
+   struct db_mysql *sql;
+
+   sql = (struct db_mysql *) link;
+   xassert(sql != NULL);
+   dl_mysql_close(sql->con);
+   if ( sql->mode == 'W' )
+      xfree(sql->query);
+   xfree(sql);
+   dca->link = NULL;
+   return 0;
+}
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpsql.h b/optional/glpk/glpsql.h
new file mode 100644
index 0000000..db79b78
--- /dev/null
+++ b/optional/glpk/glpsql.h
@@ -0,0 +1,64 @@
+/* glpsql.h */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Author: Heinrich Schuchardt <heinrich.schuchardt at gmx.de>.
+*
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPSQL_H
+#define GLPSQL_H
+
+#define db_iodbc_open _glp_db_iodbc_open
+void *db_iodbc_open(TABDCA *dca, int mode);
+/* open iODBC database connection */
+
+#define db_iodbc_read _glp_db_iodbc_read
+int db_iodbc_read(TABDCA *dca, void *link);
+/* read data from iODBC */
+
+#define db_iodbc_write _glp_db_iodbc_write
+int db_iodbc_write(TABDCA *dca, void *link);
+/* write data to iODBC */
+
+#define db_iodbc_close _glp_db_iodbc_close
+int db_iodbc_close(TABDCA *dca, void *link);
+/* close iODBC database connection */
+
+#define db_mysql_open _glp_db_mysql_open
+void *db_mysql_open(TABDCA *dca, int mode);
+/* open MySQL database connection */
+
+#define db_mysql_read _glp_db_mysql_read
+int db_mysql_read(TABDCA *dca, void *link);
+/* read data from MySQL */
+
+#define db_mysql_write _glp_db_mysql_write
+int db_mysql_write(TABDCA *dca, void *link);
+/* write data to MySQL */
+
+#define db_mysql_close _glp_db_mysql_close
+int db_mysql_close(TABDCA *dca, void *link);
+/* close MySQL database connection */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpssx.h b/optional/glpk/glpssx.h
new file mode 100644
index 0000000..50413eb
--- /dev/null
+++ b/optional/glpk/glpssx.h
@@ -0,0 +1,418 @@
+/* glpssx.h (simplex method, bignum arithmetic) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPSSX_H
+#define GLPSSX_H
+
+#include "glpbfx.h"
+#include "glpenv.h"
+
+typedef struct SSX SSX;
+
+struct SSX
+{     /* simplex solver workspace */
+/*----------------------------------------------------------------------
+// LP PROBLEM DATA
+//
+// It is assumed that LP problem has the following statement:
+//
+//    minimize (or maximize)
+//
+//       z = c[1]*x[1] + ... + c[m+n]*x[m+n] + c[0]                  (1)
+//
+//    subject to equality constraints
+//
+//       x[1] - a[1,1]*x[m+1] - ... - a[1,n]*x[m+n] = 0
+//
+//          .  .  .  .  .  .  .                                      (2)
+//
+//       x[m] - a[m,1]*x[m+1] + ... - a[m,n]*x[m+n] = 0
+//
+//    and bounds of variables
+//
+//         l[1] <= x[1]   <= u[1]
+//
+//          .  .  .  .  .  .  .                                      (3)
+//
+//       l[m+n] <= x[m+n] <= u[m+n]
+//
+// where:
+// x[1], ..., x[m]      - auxiliary variables;
+// x[m+1], ..., x[m+n]  - structural variables;
+// z                    - objective function;
+// c[1], ..., c[m+n]    - coefficients of the objective function;
+// c[0]                 - constant term of the objective function;
+// a[1,1], ..., a[m,n]  - constraint coefficients;
+// l[1], ..., l[m+n]    - lower bounds of variables;
+// u[1], ..., u[m+n]    - upper bounds of variables.
+//
+// Bounds of variables can be finite as well as inifinite. Besides,
+// lower and upper bounds can be equal to each other. So the following
+// five types of variables are possible:
+//
+//    Bounds of variable      Type of variable
+//    -------------------------------------------------
+//    -inf <  x[k] <  +inf    Free (unbounded) variable
+//    l[k] <= x[k] <  +inf    Variable with lower bound
+//    -inf <  x[k] <= u[k]    Variable with upper bound
+//    l[k] <= x[k] <= u[k]    Double-bounded variable
+//    l[k] =  x[k] =  u[k]    Fixed variable
+//
+// Using vector-matrix notations the LP problem (1)-(3) can be written
+// as follows:
+//
+//    minimize (or maximize)
+//
+//       z = c * x + c[0]                                            (4)
+//
+//    subject to equality constraints
+//
+//       xR - A * xS = 0                                             (5)
+//
+//    and bounds of variables
+//
+//       l <= x <= u                                                 (6)
+//
+// where:
+// xR                   - vector of auxiliary variables;
+// xS                   - vector of structural variables;
+// x = (xR, xS)         - vector of all variables;
+// z                    - objective function;
+// c                    - vector of objective coefficients;
+// c[0]                 - constant term of the objective function;
+// A                    - matrix of constraint coefficients (has m rows
+//                        and n columns);
+// l                    - vector of lower bounds of variables;
+// u                    - vector of upper bounds of variables.
+//
+// The simplex method makes no difference between auxiliary and
+// structural variables, so it is convenient to think the system of
+// equality constraints (5) written in a homogeneous form:
+//
+//    (I | -A) * x = 0,                                              (7)
+//
+// where (I | -A) is an augmented (m+n)xm constraint matrix, I is mxm
+// unity matrix whose columns correspond to auxiliary variables, and A
+// is the original mxn constraint matrix whose columns correspond to
+// structural variables. Note that only the matrix A is stored.
+----------------------------------------------------------------------*/
+      int m;
+      /* number of rows (auxiliary variables), m > 0 */
+      int n;
+      /* number of columns (structural variables), n > 0 */
+      int *type; /* int type[1+m+n]; */
+      /* type[0] is not used;
+         type[k], 1 <= k <= m+n, is the type of variable x[k]: */
+#define SSX_FR          0     /* free (unbounded) variable */
+#define SSX_LO          1     /* variable with lower bound */
+#define SSX_UP          2     /* variable with upper bound */
+#define SSX_DB          3     /* double-bounded variable */
+#define SSX_FX          4     /* fixed variable */
+      mpq_t *lb; /* mpq_t lb[1+m+n]; alias: l */
+      /* lb[0] is not used;
+         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+         if x[k] has no lower bound, lb[k] is zero */
+      mpq_t *ub; /* mpq_t ub[1+m+n]; alias: u */
+      /* ub[0] is not used;
+         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+         if x[k] has no upper bound, ub[k] is zero;
+         if x[k] is of fixed type, ub[k] is equal to lb[k] */
+      int dir;
+      /* optimization direction (sense of the objective function): */
+#define SSX_MIN         0     /* minimization */
+#define SSX_MAX         1     /* maximization */
+      mpq_t *coef; /* mpq_t coef[1+m+n]; alias: c */
+      /* coef[0] is a constant term of the objective function;
+         coef[k], 1 <= k <= m+n, is a coefficient of the objective
+         function at variable x[k];
+         note that auxiliary variables also may have non-zero objective
+         coefficients */
+      int *A_ptr; /* int A_ptr[1+n+1]; */
+      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+      mpq_t *A_val; /* mpq_t A_val[A_ptr[n+1]]; */
+      /* constraint matrix A (see (5)) in storage-by-columns format */
+/*----------------------------------------------------------------------
+// LP BASIS AND CURRENT BASIC SOLUTION
+//
+// The LP basis is defined by the following partition of the augmented
+// constraint matrix (7):
+//
+//    (B | N) = (I | -A) * Q,                                        (8)
+//
+// where B is a mxm non-singular basis matrix whose columns correspond
+// to basic variables xB, N is a mxn matrix whose columns correspond to
+// non-basic variables xN, and Q is a permutation (m+n)x(m+n) matrix.
+//
+// From (7) and (8) it follows that
+//
+//    (I | -A) * x = (I | -A) * Q * Q' * x = (B | N) * (xB, xN),
+//
+// therefore
+//
+//    (xB, xN) = Q' * x,                                             (9)
+//
+// where x is the vector of all variables in the original order, xB is
+// a vector of basic variables, xN is a vector of non-basic variables,
+// Q' = inv(Q) is a matrix transposed to Q.
+//
+// Current values of non-basic variables xN[j], j = 1, ..., n, are not
+// stored; they are defined implicitly by their statuses as follows:
+//
+//    0,             if xN[j] is free variable
+//    lN[j],         if xN[j] is on its lower bound                 (10)
+//    uN[j],         if xN[j] is on its upper bound
+//    lN[j] = uN[j], if xN[j] is fixed variable
+//
+// where lN[j] and uN[j] are lower and upper bounds of xN[j].
+//
+// Current values of basic variables xB[i], i = 1, ..., m, are computed
+// as follows:
+//
+//    beta = - inv(B) * N * xN,                                     (11)
+//
+// where current values of xN are defined by (10).
+//
+// Current values of simplex multipliers pi[i], i = 1, ..., m (which
+// are values of Lagrange multipliers for equality constraints (7) also
+// called shadow prices) are computed as follows:
+//
+//    pi = inv(B') * cB,                                            (12)
+//
+// where B' is a matrix transposed to B, cB is a vector of objective
+// coefficients at basic variables xB.
+//
+// Current values of reduced costs d[j], j = 1, ..., n, (which are
+// values of Langrange multipliers for active inequality constraints
+// corresponding to non-basic variables) are computed as follows:
+//
+//    d = cN - N' * pi,                                             (13)
+//
+// where N' is a matrix transposed to N, cN is a vector of objective
+// coefficients at non-basic variables xN.
+----------------------------------------------------------------------*/
+      int *stat; /* int stat[1+m+n]; */
+      /* stat[0] is not used;
+         stat[k], 1 <= k <= m+n, is the status of variable x[k]: */
+#define SSX_BS          0     /* basic variable */
+#define SSX_NL          1     /* non-basic variable on lower bound */
+#define SSX_NU          2     /* non-basic variable on upper bound */
+#define SSX_NF          3     /* non-basic free variable */
+#define SSX_NS          4     /* non-basic fixed variable */
+      int *Q_row; /* int Q_row[1+m+n]; */
+      /* matrix Q in row-like format;
+         Q_row[0] is not used;
+         Q_row[i] = j means that q[i,j] = 1 */
+      int *Q_col; /* int Q_col[1+m+n]; */
+      /* matrix Q in column-like format;
+         Q_col[0] is not used;
+         Q_col[j] = i means that q[i,j] = 1 */
+      /* if k-th column of the matrix (I | A) is k'-th column of the
+         matrix (B | N), then Q_row[k] = k' and Q_col[k'] = k;
+         if x[k] is xB[i], then Q_row[k] = i and Q_col[i] = k;
+         if x[k] is xN[j], then Q_row[k] = m+j and Q_col[m+j] = k */
+      BFX *binv;
+      /* invertable form of the basis matrix B */
+      mpq_t *bbar; /* mpq_t bbar[1+m]; alias: beta */
+      /* bbar[0] is a value of the objective function;
+         bbar[i], 1 <= i <= m, is a value of basic variable xB[i] */
+      mpq_t *pi; /* mpq_t pi[1+m]; */
+      /* pi[0] is not used;
+         pi[i], 1 <= i <= m, is a simplex multiplier corresponding to
+         i-th row (equality constraint) */
+      mpq_t *cbar; /* mpq_t cbar[1+n]; alias: d */
+      /* cbar[0] is not used;
+         cbar[j], 1 <= j <= n, is a reduced cost of non-basic variable
+         xN[j] */
+/*----------------------------------------------------------------------
+// SIMPLEX TABLE
+//
+// Due to (8) and (9) the system of equality constraints (7) for the
+// current basis can be written as follows:
+//
+//    xB = A~ * xN,                                                 (14)
+//
+// where
+//
+//    A~ = - inv(B) * N                                             (15)
+//
+// is a mxn matrix called the simplex table.
+//
+// The revised simplex method uses only two components of A~, namely,
+// pivot column corresponding to non-basic variable xN[q] chosen to
+// enter the basis, and pivot row corresponding to basic variable xB[p]
+// chosen to leave the basis.
+//
+// Pivot column alfa_q is q-th column of A~, so
+//
+//    alfa_q = A~ * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],   (16)
+//
+// where N[q] is q-th column of the matrix N.
+//
+// Pivot row alfa_p is p-th row of A~ or, equivalently, p-th column of
+// A~', a matrix transposed to A~, so
+//
+//    alfa_p = A~' * e[p] = - N' * inv(B') * e[p] = - N' * rho_p,   (17)
+//
+// where (*)' means transposition, and
+//
+//    rho_p = inv(B') * e[p],                                       (18)
+//
+// is p-th column of inv(B') or, that is the same, p-th row of inv(B).
+----------------------------------------------------------------------*/
+      int p;
+      /* number of basic variable xB[p], 1 <= p <= m, chosen to leave
+         the basis */
+      mpq_t *rho; /* mpq_t rho[1+m]; */
+      /* p-th row of the inverse inv(B); see (18) */
+      mpq_t *ap; /* mpq_t ap[1+n]; */
+      /* p-th row of the simplex table; see (17) */
+      int q;
+      /* number of non-basic variable xN[q], 1 <= q <= n, chosen to
+         enter the basis */
+      mpq_t *aq; /* mpq_t aq[1+m]; */
+      /* q-th column of the simplex table; see (16) */
+/*--------------------------------------------------------------------*/
+      int q_dir;
+      /* direction in which non-basic variable xN[q] should change on
+         moving to the adjacent vertex of the polyhedron:
+         +1 means that xN[q] increases
+         -1 means that xN[q] decreases */
+      int p_stat;
+      /* non-basic status which should be assigned to basic variable
+         xB[p] when it has left the basis and become xN[q] */
+      mpq_t delta;
+      /* actual change of xN[q] in the adjacent basis (it has the same
+         sign as q_dir) */
+/*--------------------------------------------------------------------*/
+      int it_lim;
+      /* simplex iterations limit; if this value is positive, it is
+         decreased by one each time when one simplex iteration has been
+         performed, and reaching zero value signals the solver to stop
+         the search; negative value means no iterations limit */
+      int it_cnt;
+      /* simplex iterations count; this count is increased by one each
+         time when one simplex iteration has been performed */
+      double tm_lim;
+      /* searching time limit, in seconds; if this value is positive,
+         it is decreased each time when one simplex iteration has been
+         performed by the amount of time spent for the iteration, and
+         reaching zero value signals the solver to stop the search;
+         negative value means no time limit */
+      double out_frq;
+      /* output frequency, in seconds; this parameter specifies how
+         frequently the solver sends information about the progress of
+         the search to the standard output */
+      glp_long tm_beg;
+      /* starting time of the search, in seconds; the total time of the
+         search is the difference between xtime() and tm_beg */
+      glp_long tm_lag;
+      /* the most recent time, in seconds, at which the progress of the
+         the search was displayed */
+};
+
+#define ssx_create            _glp_ssx_create
+#define ssx_factorize         _glp_ssx_factorize
+#define ssx_get_xNj           _glp_ssx_get_xNj
+#define ssx_eval_bbar         _glp_ssx_eval_bbar
+#define ssx_eval_pi           _glp_ssx_eval_pi
+#define ssx_eval_dj           _glp_ssx_eval_dj
+#define ssx_eval_cbar         _glp_ssx_eval_cbar
+#define ssx_eval_rho          _glp_ssx_eval_rho
+#define ssx_eval_row          _glp_ssx_eval_row
+#define ssx_eval_col          _glp_ssx_eval_col
+#define ssx_chuzc             _glp_ssx_chuzc
+#define ssx_chuzr             _glp_ssx_chuzr
+#define ssx_update_bbar       _glp_ssx_update_bbar
+#define ssx_update_pi         _glp_ssx_update_pi
+#define ssx_update_cbar       _glp_ssx_update_cbar
+#define ssx_change_basis      _glp_ssx_change_basis
+#define ssx_delete            _glp_ssx_delete
+
+#define ssx_phase_I           _glp_ssx_phase_I
+#define ssx_phase_II          _glp_ssx_phase_II
+#define ssx_driver            _glp_ssx_driver
+
+SSX *ssx_create(int m, int n, int nnz);
+/* create simplex solver workspace */
+
+int ssx_factorize(SSX *ssx);
+/* factorize the current basis matrix */
+
+void ssx_get_xNj(SSX *ssx, int j, mpq_t x);
+/* determine value of non-basic variable */
+
+void ssx_eval_bbar(SSX *ssx);
+/* compute values of basic variables */
+
+void ssx_eval_pi(SSX *ssx);
+/* compute values of simplex multipliers */
+
+void ssx_eval_dj(SSX *ssx, int j, mpq_t dj);
+/* compute reduced cost of non-basic variable */
+
+void ssx_eval_cbar(SSX *ssx);
+/* compute reduced costs of all non-basic variables */
+
+void ssx_eval_rho(SSX *ssx);
+/* compute p-th row of the inverse */
+
+void ssx_eval_row(SSX *ssx);
+/* compute pivot row of the simplex table */
+
+void ssx_eval_col(SSX *ssx);
+/* compute pivot column of the simplex table */
+
+void ssx_chuzc(SSX *ssx);
+/* choose pivot column */
+
+void ssx_chuzr(SSX *ssx);
+/* choose pivot row */
+
+void ssx_update_bbar(SSX *ssx);
+/* update values of basic variables */
+
+void ssx_update_pi(SSX *ssx);
+/* update simplex multipliers */
+
+void ssx_update_cbar(SSX *ssx);
+/* update reduced costs of non-basic variables */
+
+void ssx_change_basis(SSX *ssx);
+/* change current basis to adjacent one */
+
+void ssx_delete(SSX *ssx);
+/* delete simplex solver workspace */
+
+int ssx_phase_I(SSX *ssx);
+/* find primal feasible solution */
+
+int ssx_phase_II(SSX *ssx);
+/* find optimal solution */
+
+int ssx_driver(SSX *ssx);
+/* base driver to exact simplex method */
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glpssx01.c b/optional/glpk/glpssx01.c
new file mode 100644
index 0000000..02ff3b4
--- /dev/null
+++ b/optional/glpk/glpssx01.c
@@ -0,0 +1,844 @@
+/* glpssx01.c */
+
+/***********************************************************************
+*  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 "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wunused-value"
+#endif
+
+#include "glpenv.h"
+#include "glpssx.h"
+#define xfault xerror
+
+/*----------------------------------------------------------------------
+// ssx_create - create simplex solver workspace.
+//
+// This routine creates the workspace used by simplex solver routines,
+// and returns a pointer to it.
+//
+// Parameters m, n, and nnz specify, respectively, the number of rows,
+// columns, and non-zero constraint coefficients.
+//
+// This routine only allocates the memory for the workspace components,
+// so the workspace needs to be saturated by data. */
+
+SSX *ssx_create(int m, int n, int nnz)
+{     SSX *ssx;
+      int i, j, k;
+      if (m < 1)
+         xfault("ssx_create: m = %d; invalid number of rows\n", m);
+      if (n < 1)
+         xfault("ssx_create: n = %d; invalid number of columns\n", n);
+      if (nnz < 0)
+         xfault("ssx_create: nnz = %d; invalid number of non-zero const"
+            "raint coefficients\n", nnz);
+      ssx = xmalloc(sizeof(SSX));
+      ssx->m = m;
+      ssx->n = n;
+      ssx->type = xcalloc(1+m+n, sizeof(int));
+      ssx->lb = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]);
+      ssx->ub = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]);
+      ssx->coef = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]);
+      ssx->A_ptr = xcalloc(1+n+1, sizeof(int));
+      ssx->A_ptr[n+1] = nnz+1;
+      ssx->A_ind = xcalloc(1+nnz, sizeof(int));
+      ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t));
+      for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]);
+      ssx->stat = xcalloc(1+m+n, sizeof(int));
+      ssx->Q_row = xcalloc(1+m+n, sizeof(int));
+      ssx->Q_col = xcalloc(1+m+n, sizeof(int));
+      ssx->binv = bfx_create_binv();
+      ssx->bbar = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]);
+      ssx->pi = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]);
+      ssx->cbar = xcalloc(1+n, sizeof(mpq_t));
+      for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]);
+      ssx->rho = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]);
+      ssx->ap = xcalloc(1+n, sizeof(mpq_t));
+      for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]);
+      ssx->aq = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]);
+      mpq_init(ssx->delta);
+      return ssx;
+}
+
+/*----------------------------------------------------------------------
+// ssx_factorize - factorize the current basis matrix.
+//
+// This routine computes factorization of the current basis matrix B
+// and returns the singularity flag. If the matrix B is non-singular,
+// the flag is zero, otherwise non-zero. */
+
+static int basis_col(void *info, int j, int ind[], mpq_t val[])
+{     /* this auxiliary routine provides row indices and numeric values
+         of non-zero elements in j-th column of the matrix B */
+      SSX *ssx = info;
+      int m = ssx->m;
+      int n = ssx->n;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      int k, len, ptr;
+      xassert(1 <= j && j <= m);
+      k = Q_col[j]; /* x[k] = xB[j] */
+      xassert(1 <= k && k <= m+n);
+      /* j-th column of the matrix B is k-th column of the augmented
+         constraint matrix (I | -A) */
+      if (k <= m)
+      {  /* it is a column of the unity matrix I */
+         len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1);
+      }
+      else
+      {  /* it is a column of the original constraint matrix -A */
+         len = 0;
+         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+         {  len++;
+            ind[len] = A_ind[ptr];
+            mpq_neg(val[len], A_val[ptr]);
+         }
+      }
+      return len;
+}
+
+int ssx_factorize(SSX *ssx)
+{     int ret;
+      ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx);
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_get_xNj - determine value of non-basic variable.
+//
+// This routine determines the value of non-basic variable xN[j] in the
+// current basic solution defined as follows:
+//
+//    0,             if xN[j] is free variable
+//    lN[j],         if xN[j] is on its lower bound
+//    uN[j],         if xN[j] is on its upper bound
+//    lN[j] = uN[j], if xN[j] is fixed variable
+//
+// where lN[j] and uN[j] are lower and upper bounds of xN[j]. */
+
+void ssx_get_xNj(SSX *ssx, int j, mpq_t x)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      int *stat = ssx->stat;
+      int *Q_col = ssx->Q_col;
+      int k;
+      xassert(1 <= j && j <= n);
+      k = Q_col[m+j]; /* x[k] = xN[j] */
+      xassert(1 <= k && k <= m+n);
+      switch (stat[k])
+      {  case SSX_NL:
+            /* xN[j] is on its lower bound */
+            mpq_set(x, lb[k]); break;
+         case SSX_NU:
+            /* xN[j] is on its upper bound */
+            mpq_set(x, ub[k]); break;
+         case SSX_NF:
+            /* xN[j] is free variable */
+            mpq_set_si(x, 0, 1); break;
+         case SSX_NS:
+            /* xN[j] is fixed variable */
+            mpq_set(x, lb[k]); break;
+         default:
+            xassert(stat != stat);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_bbar - compute values of basic variables.
+//
+// This routine computes values of basic variables xB in the current
+// basic solution as follows:
+//
+//    beta = - inv(B) * N * xN,
+//
+// where B is the basis matrix, N is the matrix of non-basic columns,
+// xN is a vector of current values of non-basic variables. */
+
+void ssx_eval_bbar(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *coef = ssx->coef;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      int i, j, k, ptr;
+      mpq_t x, temp;
+      mpq_init(x);
+      mpq_init(temp);
+      /* bbar := 0 */
+      for (i = 1; i <= m; i++)
+         mpq_set_si(bbar[i], 0, 1);
+      /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */
+      for (j = 1; j <= n; j++)
+      {  ssx_get_xNj(ssx, j, x);
+         if (mpq_sgn(x) == 0) continue;
+         k = Q_col[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+         {  /* N[j] is a column of the unity matrix I */
+            mpq_sub(bbar[k], bbar[k], x);
+         }
+         else
+         {  /* N[j] is a column of the original constraint matrix -A */
+            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+            {  mpq_mul(temp, A_val[ptr], x);
+               mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp);
+            }
+         }
+      }
+      /* bbar := inv(B) * bbar */
+      bfx_ftran(ssx->binv, bbar, 0);
+#if 1
+      /* compute value of the objective function */
+      /* bbar[0] := c[0] */
+      mpq_set(bbar[0], coef[0]);
+      /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */
+      for (i = 1; i <= m; i++)
+      {  k = Q_col[i]; /* x[k] = xB[i] */
+         if (mpq_sgn(coef[k]) == 0) continue;
+         mpq_mul(temp, coef[k], bbar[i]);
+         mpq_add(bbar[0], bbar[0], temp);
+      }
+      /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */
+      for (j = 1; j <= n; j++)
+      {  k = Q_col[m+j]; /* x[k] = xN[j] */
+         if (mpq_sgn(coef[k]) == 0) continue;
+         ssx_get_xNj(ssx, j, x);
+         mpq_mul(temp, coef[k], x);
+         mpq_add(bbar[0], bbar[0], temp);
+      }
+#endif
+      mpq_clear(x);
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_pi - compute values of simplex multipliers.
+//
+// This routine computes values of simplex multipliers (shadow prices)
+// pi in the current basic solution as follows:
+//
+//    pi = inv(B') * cB,
+//
+// where B' is a matrix transposed to the basis matrix B, cB is a vector
+// of objective coefficients at basic variables xB. */
+
+void ssx_eval_pi(SSX *ssx)
+{     int m = ssx->m;
+      mpq_t *coef = ssx->coef;
+      int *Q_col = ssx->Q_col;
+      mpq_t *pi = ssx->pi;
+      int i;
+      /* pi := cB */
+      for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]);
+      /* pi := inv(B') * cB */
+      bfx_btran(ssx->binv, pi);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_dj - compute reduced cost of non-basic variable.
+//
+// This routine computes reduced cost d[j] of non-basic variable xN[j]
+// in the current basic solution as follows:
+//
+//    d[j] = cN[j] - N[j] * pi,
+//
+// where cN[j] is an objective coefficient at xN[j], N[j] is a column
+// of the augmented constraint matrix (I | -A) corresponding to xN[j],
+// pi is the vector of simplex multipliers (shadow prices). */
+
+void ssx_eval_dj(SSX *ssx, int j, mpq_t dj)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *coef = ssx->coef;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *pi = ssx->pi;
+      int k, ptr, end;
+      mpq_t temp;
+      mpq_init(temp);
+      xassert(1 <= j && j <= n);
+      k = Q_col[m+j]; /* x[k] = xN[j] */
+      xassert(1 <= k && k <= m+n);
+      /* j-th column of the matrix N is k-th column of the augmented
+         constraint matrix (I | -A) */
+      if (k <= m)
+      {  /* it is a column of the unity matrix I */
+         mpq_sub(dj, coef[k], pi[k]);
+      }
+      else
+      {  /* it is a column of the original constraint matrix -A */
+         mpq_set(dj, coef[k]);
+         for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++)
+         {  mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]);
+            mpq_add(dj, dj, temp);
+         }
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_cbar - compute reduced costs of all non-basic variables.
+//
+// This routine computes the vector of reduced costs pi in the current
+// basic solution for all non-basic variables, including fixed ones. */
+
+void ssx_eval_cbar(SSX *ssx)
+{     int n = ssx->n;
+      mpq_t *cbar = ssx->cbar;
+      int j;
+      for (j = 1; j <= n; j++)
+         ssx_eval_dj(ssx, j, cbar[j]);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_rho - compute p-th row of the inverse.
+//
+// This routine computes p-th row of the matrix inv(B), where B is the
+// current basis matrix.
+//
+// p-th row of the inverse is computed using the following formula:
+//
+//    rho = inv(B') * e[p],
+//
+// where B' is a matrix transposed to B, e[p] is a unity vector, which
+// contains one in p-th position. */
+
+void ssx_eval_rho(SSX *ssx)
+{     int m = ssx->m;
+      int p = ssx->p;
+      mpq_t *rho = ssx->rho;
+      int i;
+      xassert(1 <= p && p <= m);
+      /* rho := 0 */
+      for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1);
+      /* rho := e[p] */
+      mpq_set_si(rho[p], 1, 1);
+      /* rho := inv(B') * rho */
+      bfx_btran(ssx->binv, rho);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_row - compute pivot row of the simplex table.
+//
+// This routine computes p-th (pivot) row of the current simplex table
+// A~ = - inv(B) * N using the following formula:
+//
+//    A~[p] = - N' * inv(B') * e[p] = - N' * rho[p],
+//
+// where N' is a matrix transposed to the matrix N, rho[p] is p-th row
+// of the inverse inv(B). */
+
+void ssx_eval_row(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *rho = ssx->rho;
+      mpq_t *ap = ssx->ap;
+      int j, k, ptr;
+      mpq_t temp;
+      mpq_init(temp);
+      for (j = 1; j <= n; j++)
+      {  /* ap[j] := - N'[j] * rho (inner product) */
+         k = Q_col[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+            mpq_neg(ap[j], rho[k]);
+         else
+         {  mpq_set_si(ap[j], 0, 1);
+            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+            {  mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]);
+               mpq_add(ap[j], ap[j], temp);
+            }
+         }
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_col - compute pivot column of the simplex table.
+//
+// This routine computes q-th (pivot) column of the current simplex
+// table A~ = - inv(B) * N using the following formula:
+//
+//    A~[q] = - inv(B) * N[q],
+//
+// where N[q] is q-th column of the matrix N corresponding to chosen
+// non-basic variable xN[q]. */
+
+void ssx_eval_col(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      int i, k, ptr;
+      xassert(1 <= q && q <= n);
+      /* aq := 0 */
+      for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1);
+      /* aq := N[q] */
+      k = Q_col[m+q]; /* x[k] = xN[q] */
+      if (k <= m)
+      {  /* N[q] is a column of the unity matrix I */
+         mpq_set_si(aq[k], 1, 1);
+      }
+      else
+      {  /* N[q] is a column of the original constraint matrix -A */
+         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+            mpq_neg(aq[A_ind[ptr]], A_val[ptr]);
+      }
+      /* aq := inv(B) * aq */
+      bfx_ftran(ssx->binv, aq, 1);
+      /* aq := - aq */
+      for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_chuzc - choose pivot column.
+//
+// This routine chooses non-basic variable xN[q] whose reduced cost
+// indicates possible improving of the objective function to enter it
+// in the basis.
+//
+// Currently the standard (textbook) pricing is used, i.e. that
+// non-basic variable is preferred which has greatest reduced cost (in
+// magnitude).
+//
+// If xN[q] has been chosen, the routine stores its number q and also
+// sets the flag q_dir that indicates direction in which xN[q] has to
+// change (+1 means increasing, -1 means decreasing).
+//
+// If the choice cannot be made, because the current basic solution is
+// dual feasible, the routine sets the number q to 0. */
+
+void ssx_chuzc(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int dir = (ssx->dir == SSX_MIN ? +1 : -1);
+      int *Q_col = ssx->Q_col;
+      int *stat = ssx->stat;
+      mpq_t *cbar = ssx->cbar;
+      int j, k, s, q, q_dir;
+      double best, temp;
+      /* nothing is chosen so far */
+      q = 0, q_dir = 0, best = 0.0;
+      /* look through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = Q_col[m+j]; /* x[k] = xN[j] */
+         s = dir * mpq_sgn(cbar[j]);
+         if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 ||
+             (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0)
+         {  /* reduced cost of xN[j] indicates possible improving of
+               the objective function */
+            temp = fabs(mpq_get_d(cbar[j]));
+            xassert(temp != 0.0);
+            if (q == 0 || best < temp)
+               q = j, q_dir = - s, best = temp;
+         }
+      }
+      ssx->q = q, ssx->q_dir = q_dir;
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_chuzr - choose pivot row.
+//
+// This routine looks through elements of q-th column of the simplex
+// table and chooses basic variable xB[p] which should leave the basis.
+//
+// The choice is based on the standard (textbook) ratio test.
+//
+// If xB[p] has been chosen, the routine stores its number p and also
+// sets its non-basic status p_stat which should be assigned to xB[p]
+// when it has left the basis and become xN[q].
+//
+// Special case p < 0 means that xN[q] is double-bounded variable and
+// it reaches its opposite bound before any basic variable does that,
+// so the current basis remains unchanged.
+//
+// If the choice cannot be made, because xN[q] can infinitely change in
+// the feasible direction, the routine sets the number p to 0. */
+
+void ssx_chuzr(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      int q_dir = ssx->q_dir;
+      int i, k, s, t, p, p_stat;
+      mpq_t teta, temp;
+      mpq_init(teta);
+      mpq_init(temp);
+      xassert(1 <= q && q <= n);
+      xassert(q_dir == +1 || q_dir == -1);
+      /* nothing is chosen so far */
+      p = 0, p_stat = 0;
+      /* look through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  s = q_dir * mpq_sgn(aq[i]);
+         if (s < 0)
+         {  /* xB[i] decreases */
+            k = Q_col[i]; /* x[k] = xB[i] */
+            t = type[k];
+            if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+            {  /* xB[i] has finite lower bound */
+               mpq_sub(temp, bbar[i], lb[k]);
+               mpq_div(temp, temp, aq[i]);
+               mpq_abs(temp, temp);
+               if (p == 0 || mpq_cmp(teta, temp) > 0)
+               {  p = i;
+                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NL);
+                  mpq_set(teta, temp);
+               }
+            }
+         }
+         else if (s > 0)
+         {  /* xB[i] increases */
+            k = Q_col[i]; /* x[k] = xB[i] */
+            t = type[k];
+            if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+            {  /* xB[i] has finite upper bound */
+               mpq_sub(temp, bbar[i], ub[k]);
+               mpq_div(temp, temp, aq[i]);
+               mpq_abs(temp, temp);
+               if (p == 0 || mpq_cmp(teta, temp) > 0)
+               {  p = i;
+                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NU);
+                  mpq_set(teta, temp);
+               }
+            }
+         }
+         /* if something has been chosen and the ratio test indicates
+            exact degeneracy, the search can be finished */
+         if (p != 0 && mpq_sgn(teta) == 0) break;
+      }
+      /* if xN[q] is double-bounded, check if it can reach its opposite
+         bound before any basic variable */
+      k = Q_col[m+q]; /* x[k] = xN[q] */
+      if (type[k] == SSX_DB)
+      {  mpq_sub(temp, ub[k], lb[k]);
+         if (p == 0 || mpq_cmp(teta, temp) > 0)
+         {  p = -1;
+            p_stat = -1;
+            mpq_set(teta, temp);
+         }
+      }
+      ssx->p = p;
+      ssx->p_stat = p_stat;
+      /* if xB[p] has been chosen, determine its actual change in the
+         adjacent basis (it has the same sign as q_dir) */
+      if (p != 0)
+      {  xassert(mpq_sgn(teta) >= 0);
+         if (q_dir > 0)
+            mpq_set(ssx->delta, teta);
+         else
+            mpq_neg(ssx->delta, teta);
+      }
+      mpq_clear(teta);
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_update_bbar - update values of basic variables.
+//
+// This routine recomputes the current values of basic variables for
+// the adjacent basis.
+//
+// The simplex table for the current basis is the following:
+//
+//    xB[i] = sum{j in 1..n} alfa[i,j] * xN[q],  i = 1,...,m
+//
+// therefore
+//
+//    delta xB[i] = alfa[i,q] * delta xN[q],  i = 1,...,m
+//
+// where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the
+// adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of
+// xB[i]. This gives formulae for recomputing values of xB[i]:
+//
+//    xB.new[p] = xN[q] + delta xN[q]
+//
+// (because xN[q] becomes xB[p] in the adjacent basis), and
+//
+//    xB.new[i] = xB[i] + alfa[i,q] * delta xN[q],  i != p
+//
+// for other basic variables. */
+
+void ssx_update_bbar(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *bbar = ssx->bbar;
+      mpq_t *cbar = ssx->cbar;
+      int p = ssx->p;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      int i;
+      mpq_t temp;
+      mpq_init(temp);
+      xassert(1 <= q && q <= n);
+      if (p < 0)
+      {  /* xN[q] is double-bounded and goes to its opposite bound */
+         /* nop */;
+      }
+      else
+      {  /* xN[q] becomes xB[p] in the adjacent basis */
+         /* xB.new[p] = xN[q] + delta xN[q] */
+         xassert(1 <= p && p <= m);
+         ssx_get_xNj(ssx, q, temp);
+         mpq_add(bbar[p], temp, ssx->delta);
+      }
+      /* update values of other basic variables depending on xN[q] */
+      for (i = 1; i <= m; i++)
+      {  if (i == p) continue;
+         /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */
+         if (mpq_sgn(aq[i]) == 0) continue;
+         mpq_mul(temp, aq[i], ssx->delta);
+         mpq_add(bbar[i], bbar[i], temp);
+      }
+#if 1
+      /* update value of the objective function */
+      /* z.new = z + d[q] * delta xN[q] */
+      mpq_mul(temp, cbar[q], ssx->delta);
+      mpq_add(bbar[0], bbar[0], temp);
+#endif
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- ssx_update_pi - update simplex multipliers.
+--
+-- This routine recomputes the vector of simplex multipliers for the
+-- adjacent basis. */
+
+void ssx_update_pi(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *pi = ssx->pi;
+      mpq_t *cbar = ssx->cbar;
+      int p = ssx->p;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      mpq_t *rho = ssx->rho;
+      int i;
+      mpq_t new_dq, temp;
+      mpq_init(new_dq);
+      mpq_init(temp);
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+      /* compute d[q] in the adjacent basis */
+      mpq_div(new_dq, cbar[q], aq[p]);
+      /* update the vector of simplex multipliers */
+      for (i = 1; i <= m; i++)
+      {  if (mpq_sgn(rho[i]) == 0) continue;
+         mpq_mul(temp, new_dq, rho[i]);
+         mpq_sub(pi[i], pi[i], temp);
+      }
+      mpq_clear(new_dq);
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_update_cbar - update reduced costs of non-basic variables.
+//
+// This routine recomputes the vector of reduced costs of non-basic
+// variables for the adjacent basis. */
+
+void ssx_update_cbar(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *cbar = ssx->cbar;
+      int p = ssx->p;
+      int q = ssx->q;
+      mpq_t *ap = ssx->ap;
+      int j;
+      mpq_t temp;
+      mpq_init(temp);
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+      /* compute d[q] in the adjacent basis */
+      /* d.new[q] = d[q] / alfa[p,q] */
+      mpq_div(cbar[q], cbar[q], ap[q]);
+      /* update reduced costs of other non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  if (j == q) continue;
+         /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */
+         if (mpq_sgn(ap[j]) == 0) continue;
+         mpq_mul(temp, ap[j], cbar[q]);
+         mpq_sub(cbar[j], cbar[j], temp);
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_change_basis - change current basis to adjacent one.
+//
+// This routine changes the current basis to the adjacent one swapping
+// basic variable xB[p] and non-basic variable xN[q]. */
+
+void ssx_change_basis(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      int *stat = ssx->stat;
+      int *Q_row = ssx->Q_row;
+      int *Q_col = ssx->Q_col;
+      int p = ssx->p;
+      int q = ssx->q;
+      int p_stat = ssx->p_stat;
+      int k, kp, kq;
+      if (p < 0)
+      {  /* special case: xN[q] goes to its opposite bound */
+         xassert(1 <= q && q <= n);
+         k = Q_col[m+q]; /* x[k] = xN[q] */
+         xassert(type[k] == SSX_DB);
+         switch (stat[k])
+         {  case SSX_NL:
+               stat[k] = SSX_NU;
+               break;
+            case SSX_NU:
+               stat[k] = SSX_NL;
+               break;
+            default:
+               xassert(stat != stat);
+         }
+      }
+      else
+      {  /* xB[p] leaves the basis, xN[q] enters the basis */
+         xassert(1 <= p && p <= m);
+         xassert(1 <= q && q <= n);
+         kp = Q_col[p];   /* x[kp] = xB[p] */
+         kq = Q_col[m+q]; /* x[kq] = xN[q] */
+         /* check non-basic status of xB[p] which becomes xN[q] */
+         switch (type[kp])
+         {  case SSX_FR:
+               xassert(p_stat == SSX_NF);
+               break;
+            case SSX_LO:
+               xassert(p_stat == SSX_NL);
+               break;
+            case SSX_UP:
+               xassert(p_stat == SSX_NU);
+               break;
+            case SSX_DB:
+               xassert(p_stat == SSX_NL || p_stat == SSX_NU);
+               break;
+            case SSX_FX:
+               xassert(p_stat == SSX_NS);
+               break;
+            default:
+               xassert(type != type);
+         }
+         /* swap xB[p] and xN[q] */
+         stat[kp] = (char)p_stat, stat[kq] = SSX_BS;
+         Q_row[kp] = m+q, Q_row[kq] = p;
+         Q_col[p] = kq, Q_col[m+q] = kp;
+         /* update factorization of the basis matrix */
+         if (bfx_update(ssx->binv, p))
+         {  if (ssx_factorize(ssx))
+               xassert(("Internal error: basis matrix is singular", 0));
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_delete - delete simplex solver workspace.
+//
+// This routine deletes the simplex solver workspace freeing all the
+// memory allocated to this object. */
+
+void ssx_delete(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int nnz = ssx->A_ptr[n+1]-1;
+      int i, j, k;
+      xfree(ssx->type);
+      for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]);
+      xfree(ssx->lb);
+      for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]);
+      xfree(ssx->ub);
+      for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]);
+      xfree(ssx->coef);
+      xfree(ssx->A_ptr);
+      xfree(ssx->A_ind);
+      for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]);
+      xfree(ssx->A_val);
+      xfree(ssx->stat);
+      xfree(ssx->Q_row);
+      xfree(ssx->Q_col);
+      bfx_delete_binv(ssx->binv);
+      for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]);
+      xfree(ssx->bbar);
+      for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]);
+      xfree(ssx->pi);
+      for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]);
+      xfree(ssx->cbar);
+      for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]);
+      xfree(ssx->rho);
+      for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]);
+      xfree(ssx->ap);
+      for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]);
+      xfree(ssx->aq);
+      mpq_clear(ssx->delta);
+      xfree(ssx);
+      return;
+}
+
+/* eof */
diff --git a/optional/glpk/glpssx02.c b/optional/glpk/glpssx02.c
new file mode 100644
index 0000000..c6fbc71
--- /dev/null
+++ b/optional/glpk/glpssx02.c
@@ -0,0 +1,479 @@
+/* glpssx02.c */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpssx.h"
+
+static void show_progress(SSX *ssx, int phase)
+{     /* this auxiliary routine displays information about progress of
+         the search */
+      int i, def = 0;
+      for (i = 1; i <= ssx->m; i++)
+         if (ssx->type[ssx->Q_col[i]] == SSX_FX) def++;
+      xprintf("%s%6d:   %s = %22.15g   (%d)\n", phase == 1 ? " " : "*",
+         ssx->it_cnt, phase == 1 ? "infsum" : "objval",
+         mpq_get_d(ssx->bbar[0]), def);
+#if 0
+      ssx->tm_lag = utime();
+#else
+      ssx->tm_lag = xtime();
+#endif
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_phase_I - find primal feasible solution.
+//
+// This routine implements phase I of the primal simplex method.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - feasible solution found;
+// 1 - problem has no feasible solution;
+// 2 - iterations limit exceeded;
+// 3 - time limit exceeded.
+----------------------------------------------------------------------*/
+
+int ssx_phase_I(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      mpq_t *coef = ssx->coef;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      mpq_t *pi = ssx->pi;
+      mpq_t *cbar = ssx->cbar;
+      int *orig_type, orig_dir;
+      mpq_t *orig_lb, *orig_ub, *orig_coef;
+      int i, k, ret;
+      /* save components of the original LP problem, which are changed
+         by the routine */
+      orig_type = xcalloc(1+m+n, sizeof(int));
+      orig_lb = xcalloc(1+m+n, sizeof(mpq_t));
+      orig_ub = xcalloc(1+m+n, sizeof(mpq_t));
+      orig_coef = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 1; k <= m+n; k++)
+      {  orig_type[k] = type[k];
+         mpq_init(orig_lb[k]);
+         mpq_set(orig_lb[k], lb[k]);
+         mpq_init(orig_ub[k]);
+         mpq_set(orig_ub[k], ub[k]);
+      }
+      orig_dir = ssx->dir;
+      for (k = 0; k <= m+n; k++)
+      {  mpq_init(orig_coef[k]);
+         mpq_set(orig_coef[k], coef[k]);
+      }
+      /* build an artificial basic solution, which is primal feasible,
+         and also build an auxiliary objective function to minimize the
+         sum of infeasibilities for the original problem */
+      ssx->dir = SSX_MIN;
+      for (k = 0; k <= m+n; k++) mpq_set_si(coef[k], 0, 1);
+      mpq_set_si(bbar[0], 0, 1);
+      for (i = 1; i <= m; i++)
+      {  int t;
+         k = Q_col[i]; /* x[k] = xB[i] */
+         t = type[k];
+         if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+         {  /* in the original problem x[k] has lower bound */
+            if (mpq_cmp(bbar[i], lb[k]) < 0)
+            {  /* which is violated */
+               type[k] = SSX_UP;
+               mpq_set(ub[k], lb[k]);
+               mpq_set_si(lb[k], 0, 1);
+               mpq_set_si(coef[k], -1, 1);
+               mpq_add(bbar[0], bbar[0], ub[k]);
+               mpq_sub(bbar[0], bbar[0], bbar[i]);
+            }
+         }
+         if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+         {  /* in the original problem x[k] has upper bound */
+            if (mpq_cmp(bbar[i], ub[k]) > 0)
+            {  /* which is violated */
+               type[k] = SSX_LO;
+               mpq_set(lb[k], ub[k]);
+               mpq_set_si(ub[k], 0, 1);
+               mpq_set_si(coef[k], +1, 1);
+               mpq_add(bbar[0], bbar[0], bbar[i]);
+               mpq_sub(bbar[0], bbar[0], lb[k]);
+            }
+         }
+      }
+      /* now the initial basic solution should be primal feasible due
+         to changes of bounds of some basic variables, which turned to
+         implicit artifical variables */
+      /* compute simplex multipliers and reduced costs */
+      ssx_eval_pi(ssx);
+      ssx_eval_cbar(ssx);
+      /* display initial progress of the search */
+      show_progress(ssx, 1);
+      /* main loop starts here */
+      for (;;)
+      {  /* display current progress of the search */
+#if 0
+         if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
+#else
+         if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
+#endif
+            show_progress(ssx, 1);
+         /* we do not need to wait until all artificial variables have
+            left the basis */
+         if (mpq_sgn(bbar[0]) == 0)
+         {  /* the sum of infeasibilities is zero, therefore the current
+               solution is primal feasible for the original problem */
+            ret = 0;
+            break;
+         }
+         /* check if the iterations limit has been exhausted */
+         if (ssx->it_lim == 0)
+         {  ret = 2;
+            break;
+         }
+         /* check if the time limit has been exhausted */
+#if 0
+         if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
+#else
+         if (ssx->tm_lim >= 0.0 &&
+             ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
+#endif
+         {  ret = 3;
+            break;
+         }
+         /* choose non-basic variable xN[q] */
+         ssx_chuzc(ssx);
+         /* if xN[q] cannot be chosen, the sum of infeasibilities is
+            minimal but non-zero; therefore the original problem has no
+            primal feasible solution */
+         if (ssx->q == 0)
+         {  ret = 1;
+            break;
+         }
+         /* compute q-th column of the simplex table */
+         ssx_eval_col(ssx);
+         /* choose basic variable xB[p] */
+         ssx_chuzr(ssx);
+         /* the sum of infeasibilities cannot be negative, therefore
+            the auxiliary lp problem cannot have unbounded solution */
+         xassert(ssx->p != 0);
+         /* update values of basic variables */
+         ssx_update_bbar(ssx);
+         if (ssx->p > 0)
+         {  /* compute p-th row of the inverse inv(B) */
+            ssx_eval_rho(ssx);
+            /* compute p-th row of the simplex table */
+            ssx_eval_row(ssx);
+            xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
+            /* update simplex multipliers */
+            ssx_update_pi(ssx);
+            /* update reduced costs of non-basic variables */
+            ssx_update_cbar(ssx);
+         }
+         /* xB[p] is leaving the basis; if it is implicit artificial
+            variable, the corresponding residual vanishes; therefore
+            bounds of this variable should be restored to the original
+            values */
+         if (ssx->p > 0)
+         {  k = Q_col[ssx->p]; /* x[k] = xB[p] */
+            if (type[k] != orig_type[k])
+            {  /* x[k] is implicit artificial variable */
+               type[k] = orig_type[k];
+               mpq_set(lb[k], orig_lb[k]);
+               mpq_set(ub[k], orig_ub[k]);
+               xassert(ssx->p_stat == SSX_NL || ssx->p_stat == SSX_NU);
+               ssx->p_stat = (ssx->p_stat == SSX_NL ? SSX_NU : SSX_NL);
+               if (type[k] == SSX_FX) ssx->p_stat = SSX_NS;
+               /* nullify the objective coefficient at x[k] */
+               mpq_set_si(coef[k], 0, 1);
+               /* since coef[k] has been changed, we need to compute
+                  new reduced cost of x[k], which it will have in the
+                  adjacent basis */
+               /* the formula d[j] = cN[j] - pi' * N[j] is used (note
+                  that the vector pi is not changed, because it depends
+                  on objective coefficients at basic variables, but in
+                  the adjacent basis, for which the vector pi has been
+                  just recomputed, x[k] is non-basic) */
+               if (k <= m)
+               {  /* x[k] is auxiliary variable */
+                  mpq_neg(cbar[ssx->q], pi[k]);
+               }
+               else
+               {  /* x[k] is structural variable */
+                  int ptr;
+                  mpq_t temp;
+                  mpq_init(temp);
+                  mpq_set_si(cbar[ssx->q], 0, 1);
+                  for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+                  {  mpq_mul(temp, pi[A_ind[ptr]], A_val[ptr]);
+                     mpq_add(cbar[ssx->q], cbar[ssx->q], temp);
+                  }
+                  mpq_clear(temp);
+               }
+            }
+         }
+         /* jump to the adjacent vertex of the polyhedron */
+         ssx_change_basis(ssx);
+         /* one simplex iteration has been performed */
+         if (ssx->it_lim > 0) ssx->it_lim--;
+         ssx->it_cnt++;
+      }
+      /* display final progress of the search */
+      show_progress(ssx, 1);
+      /* restore components of the original problem, which were changed
+         by the routine */
+      for (k = 1; k <= m+n; k++)
+      {  type[k] = orig_type[k];
+         mpq_set(lb[k], orig_lb[k]);
+         mpq_clear(orig_lb[k]);
+         mpq_set(ub[k], orig_ub[k]);
+         mpq_clear(orig_ub[k]);
+      }
+      ssx->dir = orig_dir;
+      for (k = 0; k <= m+n; k++)
+      {  mpq_set(coef[k], orig_coef[k]);
+         mpq_clear(orig_coef[k]);
+      }
+      xfree(orig_type);
+      xfree(orig_lb);
+      xfree(orig_ub);
+      xfree(orig_coef);
+      /* return to the calling program */
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_phase_II - find optimal solution.
+//
+// This routine implements phase II of the primal simplex method.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - optimal solution found;
+// 1 - problem has unbounded solution;
+// 2 - iterations limit exceeded;
+// 3 - time limit exceeded.
+----------------------------------------------------------------------*/
+
+int ssx_phase_II(SSX *ssx)
+{     int ret;
+      /* display initial progress of the search */
+      show_progress(ssx, 2);
+      /* main loop starts here */
+      for (;;)
+      {  /* display current progress of the search */
+#if 0
+         if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
+#else
+         if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
+#endif
+            show_progress(ssx, 2);
+         /* check if the iterations limit has been exhausted */
+         if (ssx->it_lim == 0)
+         {  ret = 2;
+            break;
+         }
+         /* check if the time limit has been exhausted */
+#if 0
+         if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
+#else
+         if (ssx->tm_lim >= 0.0 &&
+             ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
+#endif
+         {  ret = 3;
+            break;
+         }
+         /* choose non-basic variable xN[q] */
+         ssx_chuzc(ssx);
+         /* if xN[q] cannot be chosen, the current basic solution is
+            dual feasible and therefore optimal */
+         if (ssx->q == 0)
+         {  ret = 0;
+            break;
+         }
+         /* compute q-th column of the simplex table */
+         ssx_eval_col(ssx);
+         /* choose basic variable xB[p] */
+         ssx_chuzr(ssx);
+         /* if xB[p] cannot be chosen, the problem has no dual feasible
+            solution (i.e. unbounded) */
+         if (ssx->p == 0)
+         {  ret = 1;
+            break;
+         }
+         /* update values of basic variables */
+         ssx_update_bbar(ssx);
+         if (ssx->p > 0)
+         {  /* compute p-th row of the inverse inv(B) */
+            ssx_eval_rho(ssx);
+            /* compute p-th row of the simplex table */
+            ssx_eval_row(ssx);
+            xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
+#if 0
+            /* update simplex multipliers */
+            ssx_update_pi(ssx);
+#endif
+            /* update reduced costs of non-basic variables */
+            ssx_update_cbar(ssx);
+         }
+         /* jump to the adjacent vertex of the polyhedron */
+         ssx_change_basis(ssx);
+         /* one simplex iteration has been performed */
+         if (ssx->it_lim > 0) ssx->it_lim--;
+         ssx->it_cnt++;
+      }
+      /* display final progress of the search */
+      show_progress(ssx, 2);
+      /* return to the calling program */
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_driver - base driver to exact simplex method.
+//
+// This routine is a base driver to a version of the primal simplex
+// method using exact (bignum) arithmetic.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - optimal solution found;
+// 1 - problem has no feasible solution;
+// 2 - problem has unbounded solution;
+// 3 - iterations limit exceeded (phase I);
+// 4 - iterations limit exceeded (phase II);
+// 5 - time limit exceeded (phase I);
+// 6 - time limit exceeded (phase II);
+// 7 - initial basis matrix is exactly singular.
+----------------------------------------------------------------------*/
+
+int ssx_driver(SSX *ssx)
+{     int m = ssx->m;
+      int *type = ssx->type;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      int i, k, ret;
+      ssx->tm_beg = xtime();
+      /* factorize the initial basis matrix */
+      if (ssx_factorize(ssx))
+      {  xprintf("Initial basis matrix is singular\n");
+         ret = 7;
+         goto done;
+      }
+      /* compute values of basic variables */
+      ssx_eval_bbar(ssx);
+      /* check if the initial basic solution is primal feasible */
+      for (i = 1; i <= m; i++)
+      {  int t;
+         k = Q_col[i]; /* x[k] = xB[i] */
+         t = type[k];
+         if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+         {  /* x[k] has lower bound */
+            if (mpq_cmp(bbar[i], lb[k]) < 0)
+            {  /* which is violated */
+               break;
+            }
+         }
+         if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+         {  /* x[k] has upper bound */
+            if (mpq_cmp(bbar[i], ub[k]) > 0)
+            {  /* which is violated */
+               break;
+            }
+         }
+      }
+      if (i > m)
+      {  /* no basic variable violates its bounds */
+         ret = 0;
+         goto skip;
+      }
+      /* phase I: find primal feasible solution */
+      ret = ssx_phase_I(ssx);
+      switch (ret)
+      {  case 0:
+            ret = 0;
+            break;
+         case 1:
+            xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+            ret = 1;
+            break;
+         case 2:
+            xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 3;
+            break;
+         case 3:
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 5;
+            break;
+         default:
+            xassert(ret != ret);
+      }
+      /* compute values of basic variables (actually only the objective
+         value needs to be computed) */
+      ssx_eval_bbar(ssx);
+skip: /* compute simplex multipliers */
+      ssx_eval_pi(ssx);
+      /* compute reduced costs of non-basic variables */
+      ssx_eval_cbar(ssx);
+      /* if phase I failed, do not start phase II */
+      if (ret != 0) goto done;
+      /* phase II: find optimal solution */
+      ret = ssx_phase_II(ssx);
+      switch (ret)
+      {  case 0:
+            xprintf("OPTIMAL SOLUTION FOUND\n");
+            ret = 0;
+            break;
+         case 1:
+            xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+            ret = 2;
+            break;
+         case 2:
+            xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 4;
+            break;
+         case 3:
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 6;
+            break;
+         default:
+            xassert(ret != ret);
+      }
+done: /* decrease the time limit by the spent amount of time */
+      if (ssx->tm_lim >= 0.0)
+#if 0
+      {  ssx->tm_lim -= utime() - ssx->tm_beg;
+#else
+      {  ssx->tm_lim -= xdifftime(xtime(), ssx->tm_beg);
+#endif
+         if (ssx->tm_lim < 0.0) ssx->tm_lim = 0.0;
+      }
+      return ret;
+}
+
+/* eof */
diff --git a/optional/glpk/glpstd.h b/optional/glpk/glpstd.h
new file mode 100644
index 0000000..7e2c58b
--- /dev/null
+++ b/optional/glpk/glpstd.h
@@ -0,0 +1,43 @@
+/* glpstd.h (standard C headers) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPSTD_H
+#define GLPSTD_H
+
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#endif
+
+/* eof */
diff --git a/optional/glpk/glptsp.c b/optional/glpk/glptsp.c
new file mode 100644
index 0000000..0fe439d
--- /dev/null
+++ b/optional/glpk/glptsp.c
@@ -0,0 +1,672 @@
+/* glptsp.c */
+
+/***********************************************************************
+*  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 "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wsometimes-uninitialized"
+#endif
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glptsp.h"
+#define xfault xerror
+
+/*----------------------------------------------------------------------
+-- tsp_read_data - read TSP instance data.
+--
+-- *Synopsis*
+--
+-- #include "glptsp.h"
+-- TSP *tsp_read_data(char *fname);
+--
+-- *Description*
+--
+-- The routine tsp_read_data reads a TSP (or related problem) instance
+-- data from the text file, whose name is the character string fname.
+--
+-- For detailed description of the format recognized by the routine see
+-- the report: G.Reinelt, TSPLIB 95.
+--
+-- *Returns*
+--
+-- If no error occurred, the routine tsp_read_data returns a pointer to
+-- the TSP instance data block, which contains loaded data. In the case
+-- of error the routine prints an error message and returns NULL. */
+
+struct dsa
+{     /* dynamic storage area used by the routine tsp_read_data */
+      char *fname;
+      /* name of the input text file */
+      FILE *fp;
+      /* stream assigned to the input text file */
+      int seqn;
+      /* line sequential number */
+      int c;
+      /* current character */
+      char token[255+1];
+      /* current token */
+};
+
+static int get_char(struct dsa *dsa)
+{     dsa->c = fgetc(dsa->fp);
+      if (ferror(dsa->fp))
+      {  xprintf("%s:%d: read error - %s\n",
+            dsa->fname, dsa->seqn, strerror(errno));
+         return 1;
+      }
+      if (feof(dsa->fp))
+         dsa->c = EOF;
+      else if (dsa->c == '\n')
+         dsa->seqn++;
+      else if (isspace(dsa->c))
+         dsa->c = ' ';
+      else if (iscntrl(dsa->c))
+      {  xprintf("%s:%d: invalid control character 0x%02X\n",
+            dsa->fname, dsa->seqn, dsa->c);
+         return 1;
+      }
+      return 0;
+}
+
+static int skip_spaces(struct dsa *dsa, int across)
+{     while (dsa->c == ' ' || (across && dsa->c == '\n'))
+         if (get_char(dsa)) return 1;
+      return 0;
+}
+
+static int scan_keyword(struct dsa *dsa)
+{     int len = 0;
+      if (skip_spaces(dsa, 0)) return 1;
+      dsa->token[0] = '\0';
+      while (isalnum(dsa->c) || dsa->c == '_')
+      {  if (len == 31)
+         {  xprintf("%s:%d: keyword `%s...' too long\n", dsa->fname,
+               dsa->seqn, dsa->token);
+            return 1;
+         }
+         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
+         if (get_char(dsa)) return 1;
+      }
+      if (len == 0)
+      {  xprintf("%s:%d: missing keyword\n", dsa->fname, dsa->seqn);
+         return 1;
+      }
+      return 0;
+}
+
+static int check_colon(struct dsa *dsa)
+{     if (skip_spaces(dsa, 0)) return 1;
+      if (dsa->c != ':')
+      {  xprintf("%s:%d: missing colon after `%s'\n", dsa->fname,
+            dsa->seqn, dsa->token);
+         return 1;
+      }
+      if (get_char(dsa)) return 1;
+      return 0;
+}
+
+static int scan_token(struct dsa *dsa, int across)
+{     int len = 0;
+      if (skip_spaces(dsa, across)) return 1;
+      dsa->token[0] = '\0';
+      while (!(dsa->c == EOF || dsa->c == '\n' || dsa->c == ' '))
+      {  if (len == 255)
+         {  dsa->token[31] = '\0';
+            xprintf("%s:%d: token `%s...' too long\n", dsa->fname,
+               dsa->seqn, dsa->token);
+            return 1;
+         }
+         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
+         if (get_char(dsa)) return 1;
+      }
+      return 0;
+}
+
+static int check_newline(struct dsa *dsa)
+{     if (skip_spaces(dsa, 0)) return 1;
+      if (!(dsa->c == EOF || dsa->c == '\n'))
+      {  xprintf("%s:%d: extra symbols detected\n", dsa->fname,
+            dsa->seqn);
+         return 1;
+      }
+      if (get_char(dsa)) return 1;
+      return 0;
+}
+
+static int scan_comment(struct dsa *dsa)
+{     int len = 0;
+      if (skip_spaces(dsa, 0)) return 1;
+      dsa->token[0] = '\0';
+      while (!(dsa->c == EOF || dsa->c == '\n'))
+      {  if (len == 255)
+         {  xprintf("%s:%d: comment too long\n", dsa->fname, dsa->seqn)
+               ;
+            return 1;
+         }
+         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
+         if (get_char(dsa)) return 1;
+      }
+      return 0;
+}
+
+static int scan_integer(struct dsa *dsa, int across, int *val)
+{     if (scan_token(dsa, across)) return 1;
+      if (strlen(dsa->token) == 0)
+      {  xprintf("%s:%d: missing integer\n", dsa->fname, dsa->seqn);
+         return 1;
+      }
+      if (str2int(dsa->token, val))
+      {  xprintf("%s:%d: integer `%s' invalid\n", dsa->fname, dsa->seqn
+            , dsa->token);
+         return 1;
+      }
+      return 0;
+}
+
+static int scan_number(struct dsa *dsa, int across, double *val)
+{     if (scan_token(dsa, across)) return 1;
+      if (strlen(dsa->token) == 0)
+      {  xprintf("%s:%d: missing number\n", dsa->fname, dsa->seqn);
+         return 1;
+      }
+      if (str2num(dsa->token, val))
+      {  xprintf("%s:%d: number `%s' invalid\n", dsa->fname, dsa->seqn,
+            dsa->token);
+         return 1;
+      }
+      return 0;
+}
+
+TSP *tsp_read_data(char *fname)
+{     struct dsa _dsa, *dsa = &_dsa;
+      TSP *tsp = NULL;
+      dsa->fname = fname;
+      xprintf("tsp_read_data: reading TSP data from `%s'...\n",
+         dsa->fname);
+      dsa->fp = fopen(dsa->fname, "r");
+      if (dsa->fp == NULL)
+      {  xprintf("tsp_read_data: unable to open `%s' - %s\n",
+            dsa->fname, strerror(errno));
+         goto fail;
+      }
+      tsp = xmalloc(sizeof(TSP));
+      tsp->name = NULL;
+      tsp->type = TSP_UNDEF;
+      tsp->comment = NULL;
+      tsp->dimension = 0;
+      tsp->edge_weight_type = TSP_UNDEF;
+      tsp->edge_weight_format = TSP_UNDEF;
+      tsp->display_data_type = TSP_UNDEF;
+      tsp->node_x_coord = NULL;
+      tsp->node_y_coord = NULL;
+      tsp->dply_x_coord = NULL;
+      tsp->dply_y_coord = NULL;
+      tsp->tour = NULL;
+      tsp->edge_weight = NULL;
+      dsa->seqn = 1;
+      if (get_char(dsa)) goto fail;
+loop: if (scan_keyword(dsa)) goto fail;
+      if (strcmp(dsa->token, "NAME") == 0)
+      {  if (tsp->name != NULL)
+         {  xprintf("%s:%d: NAME entry multiply defined\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_token(dsa, 0)) goto fail;
+         if (strlen(dsa->token) == 0)
+         {  xprintf("%s:%d: NAME entry incomplete\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         tsp->name = xmalloc(strlen(dsa->token) + 1);
+         strcpy(tsp->name, dsa->token);
+         xprintf("tsp_read_data: NAME: %s\n", tsp->name);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "TYPE") == 0)
+      {  if (tsp->type != TSP_UNDEF)
+         {  xprintf("%s:%d: TYPE entry multiply defined\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "TSP") == 0)
+            tsp->type = TSP_TSP;
+         else if (strcmp(dsa->token, "ATSP") == 0)
+            tsp->type = TSP_ATSP;
+         else if (strcmp(dsa->token, "TOUR") == 0)
+            tsp->type = TSP_TOUR;
+         else
+         {  xprintf("%s:%d: data type `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: TYPE: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "COMMENT") == 0)
+      {  if (tsp->comment != NULL)
+         {  xprintf("%s:%d: COMMENT entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_comment(dsa)) goto fail;
+         tsp->comment = xmalloc(strlen(dsa->token) + 1);
+         strcpy(tsp->comment, dsa->token);
+         xprintf("tsp_read_data: COMMENT: %s\n", tsp->comment);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "DIMENSION") == 0)
+      {  if (tsp->dimension != 0)
+         {  xprintf("%s:%d: DIMENSION entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_integer(dsa, 0, &tsp->dimension)) goto fail;
+         if (tsp->dimension < 1)
+         {  xprintf("%s:%d: invalid dimension\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         xprintf("tsp_read_data: DIMENSION: %d\n", tsp->dimension);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EDGE_WEIGHT_TYPE") == 0)
+      {  if (tsp->edge_weight_type != TSP_UNDEF)
+         {  xprintf("%s:%d: EDGE_WEIGHT_TYPE entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "GEO") == 0)
+            tsp->edge_weight_type = TSP_GEO;
+         else if (strcmp(dsa->token, "EUC_2D") == 0)
+            tsp->edge_weight_type = TSP_EUC_2D;
+         else if (strcmp(dsa->token, "ATT") == 0)
+            tsp->edge_weight_type = TSP_ATT;
+         else if (strcmp(dsa->token, "EXPLICIT") == 0)
+            tsp->edge_weight_type = TSP_EXPLICIT;
+         else if (strcmp(dsa->token, "CEIL_2D") == 0)
+            tsp->edge_weight_type = TSP_CEIL_2D;
+         else
+         {  xprintf("%s:%d: edge weight type `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: EDGE_WEIGHT_TYPE: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EDGE_WEIGHT_FORMAT") == 0)
+      {  if (tsp->edge_weight_format != TSP_UNDEF)
+         {  xprintf(
+               "%s:%d: EDGE_WEIGHT_FORMAT entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "UPPER_ROW") == 0)
+            tsp->edge_weight_format = TSP_UPPER_ROW;
+         else if (strcmp(dsa->token, "FULL_MATRIX") == 0)
+            tsp->edge_weight_format = TSP_FULL_MATRIX;
+         else if (strcmp(dsa->token, "FUNCTION") == 0)
+            tsp->edge_weight_format = TSP_FUNCTION;
+         else if (strcmp(dsa->token, "LOWER_DIAG_ROW") == 0)
+            tsp->edge_weight_format = TSP_LOWER_DIAG_ROW;
+         else
+         {  xprintf("%s:%d: edge weight format `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: EDGE_WEIGHT_FORMAT: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "DISPLAY_DATA_TYPE") == 0)
+      {  if (tsp->display_data_type != TSP_UNDEF)
+         {  xprintf("%s:%d: DISPLAY_DATA_TYPE entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "COORD_DISPLAY") == 0)
+            tsp->display_data_type = TSP_COORD_DISPLAY;
+         else if (strcmp(dsa->token, "TWOD_DISPLAY") == 0)
+            tsp->display_data_type = TSP_TWOD_DISPLAY;
+         else
+         {  xprintf("%s:%d: display data type `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: DISPLAY_DATA_TYPE: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "NODE_COORD_SECTION") == 0)
+      {  int n = tsp->dimension, k, node;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->node_x_coord != NULL)
+         {  xprintf("%s:%d: NODE_COORD_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->node_x_coord = xcalloc(1+n, sizeof(double));
+         tsp->node_y_coord = xcalloc(1+n, sizeof(double));
+         for (node = 1; node <= n; node++)
+            tsp->node_x_coord[node] = tsp->node_y_coord[node] = DBL_MAX;
+         for (k = 1; k <= n; k++)
+         {  if (scan_integer(dsa, 0, &node)) goto fail;
+            if (!(1 <= node && node <= n))
+            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
+                  dsa->seqn, node);
+               goto fail;
+            }
+            if (tsp->node_x_coord[node] != DBL_MAX)
+            {  xprintf("%s:%d: node number %d multiply specified\n",
+                  dsa->fname, dsa->seqn, node);
+               goto fail;
+            }
+            if (scan_number(dsa, 0, &tsp->node_x_coord[node]))
+               goto fail;
+            if (scan_number(dsa, 0, &tsp->node_y_coord[node]))
+               goto fail;
+            if (check_newline(dsa)) goto fail;
+         }
+      }
+      else if (strcmp(dsa->token, "DISPLAY_DATA_SECTION") == 0)
+      {  int n = tsp->dimension, k, node;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->dply_x_coord != NULL)
+         {  xprintf("%s:%d: DISPLAY_DATA_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->dply_x_coord = xcalloc(1+n, sizeof(double));
+         tsp->dply_y_coord = xcalloc(1+n, sizeof(double));
+         for (node = 1; node <= n; node++)
+            tsp->dply_x_coord[node] = tsp->dply_y_coord[node] = DBL_MAX;
+         for (k = 1; k <= n; k++)
+         {  if (scan_integer(dsa, 0, &node)) goto fail;
+            if (!(1 <= node && node <= n))
+            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
+                  dsa->seqn, node);
+               goto fail;
+            }
+            if (tsp->dply_x_coord[node] != DBL_MAX)
+            {  xprintf("%s:%d: node number %d multiply specified\n",
+                  dsa->fname, dsa->seqn, node);
+               goto fail;
+            }
+            if (scan_number(dsa, 0, &tsp->dply_x_coord[node]))
+               goto fail;
+            if (scan_number(dsa, 0, &tsp->dply_y_coord[node]))
+               goto fail;
+            if (check_newline(dsa)) goto fail;
+         }
+      }
+      else if (strcmp(dsa->token, "TOUR_SECTION") == 0)
+      {  int n = tsp->dimension, k, node;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->tour != NULL)
+         {  xprintf("%s:%d: TOUR_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->tour = xcalloc(1+n, sizeof(int));
+         for (k = 1; k <= n; k++)
+         {  if (scan_integer(dsa, 1, &node)) goto fail;
+            if (!(1 <= node && node <= n))
+            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
+                  dsa->seqn, node);
+               goto fail;
+            }
+            tsp->tour[k] = node;
+         }
+         if (scan_integer(dsa, 1, &node)) goto fail;
+         if (node != -1)
+         {  xprintf("%s:%d: extra node(s) detected\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EDGE_WEIGHT_SECTION") == 0)
+      {  int n = tsp->dimension, i, j, temp;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->edge_weight_format == TSP_UNDEF)
+         {  xprintf("%s:%d: EDGE_WEIGHT_FORMAT entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->edge_weight != NULL)
+         {  xprintf("%s:%d: EDGE_WEIGHT_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->edge_weight = xcalloc(1+n*n, sizeof(int));
+         switch (tsp->edge_weight_format)
+         {  case TSP_FULL_MATRIX:
+               for (i = 1; i <= n; i++)
+               {  for (j = 1; j <= n; j++)
+                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
+                     tsp->edge_weight[(i - 1) * n + j] = temp;
+                  }
+               }
+               break;
+            case TSP_UPPER_ROW:
+               for (i = 1; i <= n; i++)
+               {  tsp->edge_weight[(i - 1) * n + i] = 0;
+                  for (j = i + 1; j <= n; j++)
+                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
+                     tsp->edge_weight[(i - 1) * n + j] = temp;
+                     tsp->edge_weight[(j - 1) * n + i] = temp;
+                  }
+               }
+               break;
+            case TSP_LOWER_DIAG_ROW:
+               for (i = 1; i <= n; i++)
+               {  for (j = 1; j <= i; j++)
+                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
+                     tsp->edge_weight[(i - 1) * n + j] = temp;
+                     tsp->edge_weight[(j - 1) * n + i] = temp;
+                  }
+               }
+               break;
+            default:
+               goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EOF") == 0)
+      {  if (check_newline(dsa)) goto fail;
+         goto done;
+      }
+      else
+      {  xprintf("%s:%d: keyword `%s' not recognized\n", dsa->fname,
+            dsa->seqn, dsa->token);
+         goto fail;
+      }
+      goto loop;
+done: xprintf("tsp_read_data: %d lines were read\n", dsa->seqn-1);
+      fclose(dsa->fp);
+      return tsp;
+fail: if (tsp != NULL)
+      {  if (tsp->name != NULL) xfree(tsp->name);
+         if (tsp->comment != NULL) xfree(tsp->comment);
+         if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
+         if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
+         if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
+         if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
+         if (tsp->tour != NULL) xfree(tsp->tour);
+         if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
+         xfree(tsp);
+      }
+      if (dsa->fp != NULL) fclose(dsa->fp);
+      return NULL;
+}
+
+/*----------------------------------------------------------------------
+-- tsp_free_data - free TSP instance data.
+--
+-- *Synopsis*
+--
+-- #include "glptsp.h"
+-- void tsp_free_data(TSP *tsp);
+--
+-- *Description*
+--
+-- The routine tsp_free_data frees all the memory allocated to the TSP
+-- instance data block, which the parameter tsp points to. */
+
+void tsp_free_data(TSP *tsp)
+{     if (tsp->name != NULL) xfree(tsp->name);
+      if (tsp->comment != NULL) xfree(tsp->comment);
+      if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
+      if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
+      if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
+      if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
+      if (tsp->tour != NULL) xfree(tsp->tour);
+      if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
+      xfree(tsp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- tsp_distance - compute distance between two nodes.
+--
+-- *Synopsis*
+--
+-- #include "glptsp.h"
+-- int tsp_distance(TSP *tsp, int i, int j);
+--
+-- *Description*
+--
+-- The routine tsp_distance computes the distance between i-th and j-th
+-- nodes for the TSP instance, which tsp points to.
+--
+-- *Returns*
+--
+-- The routine tsp_distance returns the computed distance. */
+
+#define nint(x) ((int)((x) + 0.5))
+
+static double rad(double x)
+{     /* convert input coordinate to longitude/latitude, in radians */
+      double pi = 3.141592, deg, min;
+      deg = (int)x;
+      min = x - deg;
+      return pi * (deg + 5.0 * min / 3.0) / 180.0;
+}
+
+int tsp_distance(TSP *tsp, int i, int j)
+{     int n = tsp->dimension, dij;
+      if (!(tsp->type == TSP_TSP || tsp->type == TSP_ATSP))
+         xfault("tsp_distance: invalid TSP instance\n");
+      if (!(1 <= i && i <= n && 1 <= j && j <= n))
+         xfault("tsp_distance: node number out of range\n");
+      switch (tsp->edge_weight_type)
+      {  case TSP_UNDEF:
+            xfault("tsp_distance: edge weight type not specified\n");
+         case TSP_EXPLICIT:
+            if (tsp->edge_weight == NULL)
+               xfault("tsp_distance: edge weights not specified\n");
+            dij = tsp->edge_weight[(i - 1) * n + j];
+            break;
+         case TSP_EUC_2D:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  double xd, yd;
+               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
+               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
+               dij = nint(sqrt(xd * xd + yd * yd));
+            }
+            break;
+         case TSP_CEIL_2D:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  double xd, yd;
+               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
+               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
+               dij = (int)ceil(sqrt(xd * xd + yd * yd));
+            }
+            break;
+         case TSP_GEO:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  double rrr = 6378.388;
+               double latitude_i = rad(tsp->node_x_coord[i]);
+               double latitude_j = rad(tsp->node_x_coord[j]);
+               double longitude_i = rad(tsp->node_y_coord[i]);
+               double longitude_j = rad(tsp->node_y_coord[j]);
+               double q1 = cos(longitude_i - longitude_j);
+               double q2 = cos(latitude_i - latitude_j);
+               double q3 = cos(latitude_i + latitude_j);
+               dij = (int)(rrr * acos(0.5 * ((1.0 + q1) * q2 -
+                  (1.0 - q1) *q3)) + 1.0);
+            }
+            break;
+         case TSP_ATT:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  int tij;
+               double xd, yd, rij;
+               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
+               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
+               rij = sqrt((xd * xd + yd * yd) / 10.0);
+               tij = nint(rij);
+               if (tij < rij) dij = tij + 1; else dij = tij;
+            }
+            break;
+         default:
+            xassert(tsp->edge_weight_type != tsp->edge_weight_type);
+      }
+      return dij;
+}
+
+/* eof */
diff --git a/optional/glpk/glptsp.h b/optional/glpk/glptsp.h
new file mode 100644
index 0000000..22eeb25
--- /dev/null
+++ b/optional/glpk/glptsp.h
@@ -0,0 +1,104 @@
+/* glptsp.h (TSP format) */
+
+/***********************************************************************
+*  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/>.
+***********************************************************************/
+
+#ifndef GLPTSP_H
+#define GLPTSP_H
+
+typedef struct TSP TSP;
+
+struct TSP
+{     /* TSP (or related problem) instance in the format described in
+         the report [G.Reinelt, TSPLIB 95] */
+      /*--------------------------------------------------------------*/
+      /* the specification part */
+      char *name;
+      /* identifies the data file */
+      int type;
+      /* specifies the type of data: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_TSP               1  /* symmetric TSP */
+#define TSP_ATSP              2  /* asymmetric TSP */
+#define TSP_TOUR              3  /* collection of tours */
+      char *comment;
+      /* additional comments (usually the name of the contributor or
+         creator of the problem instance is given here) */
+      int dimension;
+      /* for a TSP or ATSP, the dimension is the number of its nodes
+         for a TOUR it is the dimension of the corresponding problem */
+      int edge_weight_type;
+      /* specifies how the edge weights (or distances) are given: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_EXPLICIT          1  /* listed explicitly */
+#define TSP_EUC_2D            2  /* Eucl. distances in 2-D */
+#define TSP_CEIL_2D           3  /* Eucl. distances in 2-D rounded up */
+#define TSP_GEO               4  /* geographical distances */
+#define TSP_ATT               5  /* special distance function */
+      int edge_weight_format;
+      /* describes the format of the edge weights if they are given
+         explicitly: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_FUNCTION          1  /* given by a function */
+#define TSP_FULL_MATRIX       2  /* given by a full matrix */
+#define TSP_UPPER_ROW         3  /* upper triangulat matrix (row-wise
+                                    without diagonal entries) */
+#define TSP_LOWER_DIAG_ROW    4  /* lower triangular matrix (row-wise
+                                    including diagonal entries) */
+      int display_data_type;
+      /* specifies how a graphical display of the nodes can be
+         obtained: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_COORD_DISPLAY     1  /* display is generated from the node
+                                    coordinates */
+#define TSP_TWOD_DISPLAY      2  /* explicit coordinates in 2-D are
+                                    given */
+      /*--------------------------------------------------------------*/
+      /* data part */
+      /* NODE_COORD_SECTION: */
+      double *node_x_coord; /* double node_x_coord[1+dimension]; */
+      double *node_y_coord; /* double node_y_coord[1+dimension]; */
+      /* DISPLAY_DATA_SECTION: */
+      double *dply_x_coord; /* double dply_x_coord[1+dimension]; */
+      double *dply_y_coord; /* double dply_y_coord[1+dimension]; */
+      /* TOUR_SECTION: */
+      int *tour; /* int tour[1+dimension]; */
+      /* EDGE_WEIGHT_SECTION: */
+      int *edge_weight; /* int edge_weight[1+dimension*dimension]; */
+};
+
+#define tsp_read_data         _glp_tsp_read_data
+#define tsp_free_data         _glp_tsp_free_data
+#define tsp_distance          _glp_tsp_distance
+
+TSP *tsp_read_data(char *fname);
+/* read TSP instance data */
+
+void tsp_free_data(TSP *tsp);
+/* free TSP instance data */
+
+int tsp_distance(TSP *tsp, int i, int j);
+/* compute distance between two nodes */
+
+#endif
+
+/* eof */
diff --git a/src/DensityGrid.cpp b/src/DensityGrid.cpp
new file mode 100644
index 0000000..af6022c
--- /dev/null
+++ b/src/DensityGrid.cpp
@@ -0,0 +1,275 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains the member definitions of the DensityGrid.h class
+// This code is modified from the original code by B.N. Wylie
+
+#include <string>
+#include <deque>
+#include <iostream>
+#include <cmath>
+#include <cstdlib>
+
+using namespace std;
+
+#include "drl_Node.h"
+#include "DensityGrid.h"
+#include "igraph_error.h"
+
+#define GET_BIN(y, x) (Bins[y*GRID_SIZE+x])
+
+namespace drl {
+
+//*******************************************************
+// Density Grid Destructor -- deallocates memory used
+// for Density matrix, fall_off matrix, and node deque.
+
+DensityGrid::~DensityGrid ()
+{
+	delete[] Density;
+	delete[] fall_off;
+	delete[] Bins;
+}
+
+/*********************************************
+* Function: Density_Grid::Reset		         *
+* Description: Reset the density grid		 *
+*********************************************/
+// changed from reset to init since we will only
+// call this once in the parallel version of layout
+
+void DensityGrid::Init() 
+{
+  
+  try
+    {
+      Density = new float[GRID_SIZE][GRID_SIZE];
+      fall_off = new float[RADIUS*2+1][RADIUS*2+1];
+      Bins = new deque<Node>[GRID_SIZE*GRID_SIZE];
+    }
+  catch (bad_alloc errora)
+    {
+      // cout << "Error: Out of memory! Program stopped." << endl;
+	  #ifdef MUSE_MPI
+        MPI_Abort ( MPI_COMM_WORLD, 1 );
+	  #else
+	    igraph_error("DrL is out of memory", __FILE__, __LINE__,
+			 IGRAPH_ENOMEM);
+	  #endif
+    }
+	
+  // Clear Grid
+  int i;
+  for (i=0; i< GRID_SIZE; i++) 
+    for (int j=0; j< GRID_SIZE; j++) {
+      Density[i][j] = 0;
+      GET_BIN(i, j).erase(GET_BIN(i, j).begin(), GET_BIN(i, j).end());
+    }
+  
+  // Compute fall off
+  for(i=-RADIUS; i<=RADIUS; i++)
+    for(int j=-RADIUS; j<=RADIUS; j++) {
+      fall_off[i+RADIUS][j+RADIUS] = (float)((RADIUS-fabs((float)i))/RADIUS) * 
+	(float)((RADIUS-fabs((float)j))/RADIUS);
+    }
+	
+}
+
+/***************************************************
+ * Function: DensityGrid::GetDensity               *
+ * Description: Get_Density from density grid      *
+ **************************************************/
+float DensityGrid::GetDensity(float Nx, float Ny, bool fineDensity) 
+{
+	deque<Node>::iterator BI;
+	int x_grid, y_grid;
+	float x_dist, y_dist, distance, density=0;
+	int boundary=10;	// boundary around plane
+
+
+	/* Where to look */
+	x_grid = (int)((Nx+HALF_VIEW+.5)*VIEW_TO_GRID);
+	y_grid = (int)((Ny+HALF_VIEW+.5)*VIEW_TO_GRID);
+
+	// Check for edges of density grid (10000 is arbitrary high density)
+	if (x_grid > GRID_SIZE-boundary || x_grid < boundary) return 10000;
+	if (y_grid > GRID_SIZE-boundary || y_grid < boundary) return 10000;
+
+	// Fine density?
+	if (fineDensity) {
+
+		// Go through nearest bins
+		for(int i=y_grid-1; i<=y_grid+1; i++)
+			for(int j=x_grid-1; j<=x_grid+1; j++) {
+
+			// Look through bin and add fine repulsions
+			for(BI = GET_BIN(i, j).begin(); BI != GET_BIN(i, j).end(); ++BI) {
+				x_dist =  Nx-(BI->x);
+				y_dist =  Ny-(BI->y);
+				distance = x_dist*x_dist+y_dist*y_dist;
+				density += 1e-4/(distance + 1e-50);
+		 }
+		}
+	// Course density
+	} else {
+
+		// Add rough estimate
+		density = Density[y_grid][x_grid];
+		density *= density;
+	}
+
+	return density;
+}
+
+/// Wrapper functions for the Add and subtract methods
+/// Nodes should all be passed by constant ref
+
+void DensityGrid::Add(Node &n, bool fineDensity)
+{
+  if(fineDensity)
+    fineAdd(n);
+  else
+    Add(n);
+}
+
+void DensityGrid::Subtract( Node &n, bool first_add,
+							bool fine_first_add, bool fineDensity)
+{
+  if ( fineDensity && !fine_first_add ) fineSubtract (n);
+  else if ( !first_add ) Subtract(n);
+}
+
+			
+/***************************************************
+ * Function: DensityGrid::Subtract                *
+ * Description: Subtract a node from density grid  *
+ **************************************************/
+void DensityGrid::Subtract(Node &N) 
+{
+  int x_grid, y_grid, diam;
+  float *den_ptr, *fall_ptr;
+	
+  /* Where to subtract */
+  x_grid = (int)((N.sub_x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.sub_y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  x_grid -= RADIUS;
+  y_grid -= RADIUS;
+  diam = 2*RADIUS;
+
+  /* Subtract density values */
+  den_ptr = &Density[y_grid][x_grid];
+  fall_ptr = &fall_off[0][0];
+  for(int i = 0; i <= diam; i++) {
+    for(int j = 0; j <= diam; j++)
+	 *den_ptr++ -= *fall_ptr++;
+    den_ptr += GRID_SIZE - (diam+1);
+  }
+}
+
+/***************************************************
+ * Function: DensityGrid::Add                     *
+ * Description: Add a node to the density grid     *
+ **************************************************/
+void DensityGrid::Add(Node &N) 
+{
+
+  int x_grid, y_grid, diam;
+  float *den_ptr, *fall_ptr;
+
+
+  /* Where to add */
+  x_grid = (int)((N.x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.y+HALF_VIEW+.5)*VIEW_TO_GRID);
+ 
+  N.sub_x = N.x;
+  N.sub_y = N.y;
+  
+  x_grid -= RADIUS;
+  y_grid -= RADIUS;
+  diam = 2*RADIUS;
+
+  // check to see that we are inside grid
+  if ( (x_grid >= GRID_SIZE) || (x_grid < 0) ||
+       (y_grid >= GRID_SIZE) || (y_grid < 0) )
+    {
+      // cout << endl << "Error: Exceeded density grid with x_grid = " << x_grid 
+      // 	       << " and y_grid = " << y_grid << ".  Program stopped." << endl;
+      #ifdef MUSE_MPI
+ 	    MPI_Abort ( MPI_COMM_WORLD, 1 );
+	  #else
+	    igraph_error("Exceeded density grid in DrL", __FILE__, 
+			 __LINE__, IGRAPH_EDRL);
+	  #endif
+    }    
+
+  /* Add density values */
+  den_ptr = &Density[y_grid][x_grid];
+  fall_ptr = &fall_off[0][0];
+  for(int i = 0; i <= diam; i++) {
+    for(int j = 0; j <= diam; j++)
+	 *den_ptr++ += *fall_ptr++;
+    den_ptr += GRID_SIZE - (diam+1);
+  }
+  
+}
+
+/***************************************************
+ * Function: DensityGrid::fineSubtract             *
+ * Description: Subtract a node from bins		   *
+ **************************************************/
+void DensityGrid::fineSubtract(Node &N) 
+{
+  int x_grid, y_grid;
+
+  /* Where to subtract */
+  x_grid = (int)((N.sub_x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.sub_y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  GET_BIN(y_grid, x_grid).pop_front();
+}
+
+/***************************************************
+ * Function: DensityGrid::fineAdd                  *
+ * Description: Add a node to the bins			   *
+ **************************************************/
+void DensityGrid::fineAdd(Node &N) 
+{
+  int x_grid, y_grid;
+
+  /* Where to add */
+  x_grid = (int)((N.x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  N.sub_x = N.x;
+  N.sub_y = N.y;
+  GET_BIN(y_grid, x_grid).push_back(N);
+}
+
+} // namespace drl
diff --git a/src/DensityGrid.h b/src/DensityGrid.h
new file mode 100644
index 0000000..a80925c
--- /dev/null
+++ b/src/DensityGrid.h
@@ -0,0 +1,88 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __DENSITY_GRID_H__
+#define __DENSITY_GRID_H__
+
+
+// Compile time adjustable parameters
+
+
+#include <deque>
+
+using namespace std;
+
+#include "drl_layout.h"
+#include "drl_Node.h"
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+namespace drl {
+
+class DensityGrid {
+
+public:
+  
+	  // Methods
+	  void Init();
+	  void Subtract(Node &n, bool first_add, bool fine_first_add, bool fineDensity);
+	  void Add(Node &n, bool fineDensity );
+	  float GetDensity(float Nx, float Ny, bool fineDensity);
+
+	  // Contructor/Destructor
+	  DensityGrid() {};
+	  ~DensityGrid();
+
+private:
+
+	  // Private Members
+	  void Subtract( Node &N );
+	  void Add( Node &N );
+	  void fineSubtract( Node &N );
+	  void fineAdd( Node &N );
+
+	  // new dynamic variables -- SBM
+	  float (*fall_off)[RADIUS*2+1];
+	  float (*Density)[GRID_SIZE];
+	  deque<Node>* Bins;
+
+	  // old static variables
+	  //float fall_off[RADIUS*2+1][RADIUS*2+1];
+	  //float Density[GRID_SIZE][GRID_SIZE];
+	  //deque<Node *> Bins[GRID_SIZE][GRID_SIZE];
+};
+
+} // namespace drl
+
+#endif // __DENSITY_GRID_H__
+
diff --git a/src/DensityGrid_3d.cpp b/src/DensityGrid_3d.cpp
new file mode 100644
index 0000000..125c375
--- /dev/null
+++ b/src/DensityGrid_3d.cpp
@@ -0,0 +1,296 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains the member definitions of the DensityGrid.h class
+// This code is modified from the original code by B.N. Wylie
+
+#include <string>
+#include <deque>
+#include <iostream>
+#include <cmath>
+#include <cstdlib>
+
+using namespace std;
+
+#include "drl_Node_3d.h"
+#include "DensityGrid_3d.h"
+#include "igraph_error.h"
+
+#define GET_BIN(z, y, x) (Bins[(z*GRID_SIZE+y)*GRID_SIZE+x])
+
+namespace drl3d {
+
+//*******************************************************
+// Density Grid Destructor -- deallocates memory used
+// for Density matrix, fall_off matrix, and node deque.
+
+DensityGrid::~DensityGrid ()
+{
+	delete[] Density;
+	delete[] fall_off;
+	delete[] Bins;
+}
+
+/*********************************************
+* Function: Density_Grid::Reset		         *
+* Description: Reset the density grid		 *
+*********************************************/
+// changed from reset to init since we will only
+// call this once in the parallel version of layout
+
+void DensityGrid::Init() 
+{
+  
+  try
+    {
+      Density = new float[GRID_SIZE][GRID_SIZE][GRID_SIZE];
+      fall_off = new float[RADIUS*2+1][RADIUS*2+1][RADIUS*2+1];
+      Bins = new deque<Node>[GRID_SIZE*GRID_SIZE*GRID_SIZE];
+    }
+  catch (bad_alloc errora)
+    {
+      // cout << "Error: Out of memory! Program stopped." << endl;
+	  #ifdef MUSE_MPI
+        MPI_Abort ( MPI_COMM_WORLD, 1 );
+	  #else
+	    igraph_error("DrL is out of memory", __FILE__, __LINE__,
+			 IGRAPH_ENOMEM);
+	  #endif
+    }
+	
+  // Clear Grid
+  int i;
+  for (i=0; i< GRID_SIZE; i++) 
+    for (int j=0; j< GRID_SIZE; j++) 
+      for (int k=0; k < GRID_SIZE; k++) {
+	Density[i][j][k] = 0;
+	GET_BIN(i,j,k).erase(GET_BIN(i,j,k).begin(),GET_BIN(i,j,k).end());
+      }
+  
+  // Compute fall off
+  for(i=-RADIUS; i<=RADIUS; i++)
+    for(int j=-RADIUS; j<=RADIUS; j++) 
+      for (int k=-RADIUS; k<=RADIUS; k++) {
+	fall_off[i+RADIUS][j+RADIUS][k+RADIUS] = 
+	  (float)((RADIUS-fabs((float)i))/RADIUS) * 
+	  (float)((RADIUS-fabs((float)j))/RADIUS) *
+	  (float)((RADIUS-fabs((float)k))/RADIUS);
+      }
+  
+}
+
+
+/***************************************************
+ * Function: DensityGrid::GetDensity               *
+ * Description: Get_Density from density grid      *
+ **************************************************/
+float DensityGrid::GetDensity(float Nx, float Ny, float Nz,bool fineDensity) 
+{
+	deque<Node>::iterator BI;
+	int x_grid, y_grid, z_grid;
+	float x_dist, y_dist, z_dist, distance, density=0;
+	int boundary=10;	// boundary around plane
+
+
+	/* Where to look */
+	x_grid = (int)((Nx+HALF_VIEW+.5)*VIEW_TO_GRID);
+	y_grid = (int)((Ny+HALF_VIEW+.5)*VIEW_TO_GRID);
+	z_grid = (int)((Nz+HALF_VIEW+.5)*VIEW_TO_GRID);
+
+	// Check for edges of density grid (10000 is arbitrary high density)
+	if (x_grid > GRID_SIZE-boundary || x_grid < boundary) return 10000;
+	if (y_grid > GRID_SIZE-boundary || y_grid < boundary) return 10000;
+	if (z_grid > GRID_SIZE-boundary || z_grid < boundary) return 10000;
+
+	// Fine density?
+	if (fineDensity) {
+
+		// Go through nearest bins
+	  for (int k=z_grid-1; k<=z_grid+1; k++)
+	    for(int i=y_grid-1; i<=y_grid+1; i++)
+	      for(int j=x_grid-1; j<=x_grid+1; j++) {
+		      
+		// Look through bin and add fine repulsions
+		for(BI = GET_BIN(k,i,j).begin(); BI < GET_BIN(k,i,j).end(); ++BI) {
+		  x_dist =  Nx-(BI->x);
+		  y_dist =  Ny-(BI->y);
+		  z_dist =  Nz-(BI->z);
+		  distance = x_dist*x_dist+y_dist*y_dist+z_dist*z_dist;
+		  density += 1e-4/(distance + 1e-50);
+		}
+	      }
+	  
+	// Course density
+	} else {
+
+		// Add rough estimate
+		density = Density[z_grid][y_grid][x_grid];
+		density *= density;
+	}
+
+	return density;
+}
+
+/// Wrapper functions for the Add and subtract methods
+/// Nodes should all be passed by constant ref
+
+void DensityGrid::Add(Node &n, bool fineDensity)
+{
+  if(fineDensity)
+    fineAdd(n);
+  else
+    Add(n);
+}
+
+void DensityGrid::Subtract( Node &n, bool first_add,
+			    bool fine_first_add, bool fineDensity)
+{
+  if ( fineDensity && !fine_first_add ) fineSubtract (n);
+  else if ( !first_add ) Subtract(n);
+}
+
+			
+/***************************************************
+ * Function: DensityGrid::Subtract                *
+ * Description: Subtract a node from density grid  *
+ **************************************************/
+void DensityGrid::Subtract(Node &N) 
+{
+  int x_grid, y_grid, z_grid, diam;
+  float *den_ptr, *fall_ptr;
+	
+  /* Where to subtract */
+  x_grid = (int)((N.sub_x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.sub_y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  z_grid = (int)((N.sub_z+HALF_VIEW+.5)*VIEW_TO_GRID);
+  x_grid -= RADIUS;
+  y_grid -= RADIUS;
+  z_grid -= RADIUS;
+  diam = 2*RADIUS;
+
+  /* Subtract density values */
+  den_ptr = &Density[z_grid][y_grid][x_grid];
+  fall_ptr = &fall_off[0][0][0];
+  for(int i = 0; i <= diam; i++) {
+    for(int j = 0; j <= diam; j++)
+      for (int k=0; k <= diam; k++)
+	 *den_ptr++ -= *fall_ptr++;
+    den_ptr += GRID_SIZE - (diam+1);
+  }
+}
+
+/***************************************************
+ * Function: DensityGrid::Add                     *
+ * Description: Add a node to the density grid     *
+ **************************************************/
+void DensityGrid::Add(Node &N) 
+{
+
+  int x_grid, y_grid, z_grid, diam;
+  float *den_ptr, *fall_ptr;
+
+
+  /* Where to add */
+  x_grid = (int)((N.x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  z_grid = (int)((N.z+HALF_VIEW+.5)*VIEW_TO_GRID);
+ 
+  N.sub_x = N.x;
+  N.sub_y = N.y;
+  N.sub_z = N.z;
+  
+  x_grid -= RADIUS;
+  y_grid -= RADIUS;
+  z_grid -= RADIUS;
+  diam = 2*RADIUS;
+
+  // check to see that we are inside grid
+  if ( (x_grid >= GRID_SIZE) || (x_grid < 0) ||
+       (y_grid >= GRID_SIZE) || (y_grid < 0) ||
+       (z_grid >= GRID_SIZE) || (z_grid < 0) )
+    {
+      // cout << endl << "Error: Exceeded density grid with x_grid = " << x_grid 
+      // 	       << " and y_grid = " << y_grid << ".  Program stopped." << endl;
+      #ifdef MUSE_MPI
+ 	    MPI_Abort ( MPI_COMM_WORLD, 1 );
+	  #else
+	    igraph_error("Exceeded density grid in DrL", __FILE__, 
+			 __LINE__, IGRAPH_EDRL);
+	  #endif
+    }    
+
+  /* Add density values */
+  den_ptr = &Density[z_grid][y_grid][x_grid];
+  fall_ptr = &fall_off[0][0][0];
+  for(int i = 0; i <= diam; i++) {
+    for(int j = 0; j <= diam; j++)
+      for (int k = 0; k <= diam; k++) 
+	 *den_ptr++ += *fall_ptr++;
+    den_ptr += GRID_SIZE - (diam+1);
+  }
+  
+}
+
+/***************************************************
+ * Function: DensityGrid::fineSubtract             *
+ * Description: Subtract a node from bins		   *
+ **************************************************/
+void DensityGrid::fineSubtract(Node &N) 
+{
+  int x_grid, y_grid, z_grid;
+
+  /* Where to subtract */
+  x_grid = (int)((N.sub_x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.sub_y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  z_grid = (int)((N.sub_z+HALF_VIEW+.5)*VIEW_TO_GRID);
+  GET_BIN(z_grid,y_grid,x_grid).pop_front();
+}
+
+/***************************************************
+ * Function: DensityGrid::fineAdd                  *
+ * Description: Add a node to the bins			   *
+ **************************************************/
+void DensityGrid::fineAdd(Node &N) 
+{
+  int x_grid, y_grid, z_grid;
+
+  /* Where to add */
+  x_grid = (int)((N.x+HALF_VIEW+.5)*VIEW_TO_GRID);
+  y_grid = (int)((N.y+HALF_VIEW+.5)*VIEW_TO_GRID);
+  z_grid = (int)((N.z+HALF_VIEW+.5)*VIEW_TO_GRID);
+  N.sub_x = N.x;
+  N.sub_y = N.y;
+  N.sub_z = N.z;
+  GET_BIN(z_grid,y_grid,x_grid).push_back(N);
+}
+
+} // namespace drl3d
diff --git a/src/DensityGrid_3d.h b/src/DensityGrid_3d.h
new file mode 100644
index 0000000..c2ef4b0
--- /dev/null
+++ b/src/DensityGrid_3d.h
@@ -0,0 +1,88 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __DENSITY_GRID_H__
+#define __DENSITY_GRID_H__
+
+
+// Compile time adjustable parameters
+
+
+#include <deque>
+
+using namespace std;
+
+#include "drl_layout_3d.h"
+#include "drl_Node_3d.h"
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+namespace drl3d {
+
+class DensityGrid {
+
+public:
+  
+	  // Methods
+	  void Init();
+	  void Subtract(Node &n, bool first_add, bool fine_first_add, bool fineDensity);
+	  void Add(Node &n, bool fineDensity );
+	  float GetDensity(float Nx, float Ny, float Nz, bool fineDensity);
+
+	  // Contructor/Destructor
+	  DensityGrid() {};
+	  ~DensityGrid();
+
+private:
+
+	  // Private Members
+	  void Subtract( Node &N );
+	  void Add( Node &N );
+	  void fineSubtract( Node &N );
+	  void fineAdd( Node &N );
+
+	  // new dynamic variables -- SBM
+	  float (*fall_off)[RADIUS*2+1][RADIUS*2+1];
+	  float (*Density)[GRID_SIZE][GRID_SIZE];
+	  deque<Node>* Bins;
+
+	  // old static variables
+	  //float fall_off[RADIUS*2+1][RADIUS*2+1];
+	  //float Density[GRID_SIZE][GRID_SIZE];
+	  //deque<Node *> Bins[GRID_SIZE][GRID_SIZE];
+};
+
+} // namespace drl3d
+
+#endif // __DENSITY_GRID_H__
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..e7085c5
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,306 @@
+# This is to make sure that the headers get built before they are included
+BUILT_SOURCES = foreign-ncol-parser.h foreign-lgl-parser.h \
+		foreign-dl-parser.h foreign-gml-parser.h \
+		foreign-pajek-parser.h
+
+# This is needed to ensure that yacc (or bison) builds the header files
+# Unfortunately this is not the default behaviour in MinGW/MSYS
+AM_YFLAGS = -d
+
+lib_LTLIBRARIES         = libigraph.la
+
+include lapack/blas.inc
+include lapack/lapack.inc
+include lapack/arpack.inc
+include plfit/plfit.inc
+
+F2C =	f2c/abort_.c	  f2c/dolio.c	    f2c/r_sin.c\
+	f2c/dummy.c	  f2c/dtime_.c	    f2c/iio.c	      f2c/r_sinh.c\
+	f2c/backspac.c	  f2c/due.c	    f2c/ilnw.c	      f2c/r_sqrt.c\
+	f2c/c_abs.c	  f2c/ef1asc_.c	    f2c/inquire.c     f2c/r_tan.c\
+	f2c/c_cos.c	  f2c/ef1cmc_.c	    f2c/l_ge.c	      f2c/r_tanh.c\
+	f2c/c_div.c	  f2c/endfile.c	    f2c/l_gt.c	      f2c/rdfmt.c\
+	f2c/c_exp.c	  f2c/erf_.c	    f2c/l_le.c	      f2c/rewind.c\
+	f2c/c_log.c	  f2c/erfc_.c	    f2c/l_lt.c	      f2c/rsfe.c\
+	f2c/c_sin.c	  f2c/err.c	    f2c/lbitbits.c    f2c/rsli.c\
+	f2c/c_sqrt.c	  f2c/etime_.c	    f2c/lbitshft.c    f2c/rsne.c\
+	f2c/cabs.c	  f2c/exit_.c	    f2c/lread.c	      f2c/s_cat.c\
+	f2c/close.c	  f2c/f77_aloc.c    f2c/lwrite.c      f2c/s_cmp.c\
+	f2c/ctype.c	  f2c/f77vers.c	    f2c/s_copy.c\
+	f2c/d_abs.c	  f2c/fmt.c	    f2c/open.c	      f2c/s_paus.c\
+	f2c/d_acos.c	  f2c/fmtlib.c	    f2c/pow_ci.c      f2c/s_rnge.c\
+	f2c/d_asin.c	  f2c/ftell_.c	    f2c/pow_dd.c      f2c/s_stop.c\
+	f2c/d_atan.c	  f2c/pow_di.c      f2c/sfe.c\
+	f2c/d_atn2.c	  f2c/getenv_.c	    f2c/pow_hh.c      f2c/sig_die.c\
+	f2c/d_cnjg.c	  f2c/h_abs.c	    f2c/pow_ii.c      f2c/signal_.c\
+	f2c/d_cos.c	  f2c/h_dim.c	    f2c/pow_ri.c      f2c/signbit.c\
+	f2c/d_cosh.c	  f2c/h_dnnt.c	    f2c/pow_zi.c      f2c/sue.c\
+	f2c/d_dim.c	  f2c/h_indx.c	    f2c/pow_zz.c      f2c/system_.c\
+	f2c/d_exp.c	  f2c/h_len.c	    f2c/r_abs.c	      f2c/typesize.c\
+	f2c/d_imag.c	  f2c/h_mod.c	    f2c/r_acos.c      f2c/uio.c\
+	f2c/d_int.c	  f2c/h_nint.c	    f2c/r_asin.c      f2c/uninit.c\
+	f2c/d_lg10.c	  f2c/h_sign.c	    f2c/r_atan.c      f2c/util.c\
+	f2c/d_log.c	  f2c/hl_ge.c	    f2c/r_atn2.c      f2c/wref.c\
+	f2c/d_mod.c	  f2c/hl_gt.c	    f2c/r_cnjg.c      f2c/wrtfmt.c\
+	f2c/d_nint.c	  f2c/hl_le.c	    f2c/r_cos.c	      f2c/wsfe.c\
+	f2c/d_prod.c	  f2c/hl_lt.c	    f2c/r_cosh.c      f2c/wsle.c\
+	f2c/d_sign.c	  f2c/i77vers.c	    f2c/r_dim.c	      f2c/wsne.c\
+	f2c/d_sin.c	  f2c/i_abs.c	    f2c/r_exp.c	      f2c/xwsne.c\
+	f2c/d_sinh.c	  f2c/i_dim.c	    f2c/r_imag.c      f2c/z_abs.c\
+	f2c/d_sqrt.c	  f2c/i_dnnt.c	    f2c/r_int.c	      f2c/z_cos.c\
+	f2c/d_tan.c	  f2c/i_indx.c	    f2c/r_lg10.c      f2c/z_div.c\
+	f2c/d_tanh.c	  f2c/i_len.c	    f2c/r_log.c	      f2c/z_exp.c\
+	f2c/derf_.c	  f2c/i_mod.c	    f2c/r_mod.c	      f2c/z_log.c\
+	f2c/derfc_.c	  f2c/i_nint.c	    f2c/r_nint.c      f2c/z_sin.c\
+	f2c/dfe.c	  f2c/i_sign.c	    f2c/r_sign.c      f2c/z_sqrt.c
+
+# We also have to pack f2c/arithchk.c in the distribution in case the
+# user wants to compile it using the internal f2c. f2c/arithchk.c is
+# not linked into libf2c.la (hence we cannot add it to libf2c_la_SOURCES)
+# but is needed to build f2c/arith.h
+EXTRA_DIST      = f2c/arithchk.c
+
+if INTERNAL_F2C
+  libf2c_la_SOURCES = f2c.h f2c/fio.h f2c/fmt.h f2c/sysdep1.h\
+					  f2c/sysdep1.h0 f2c/lio.h f2c/fp.h f2c/signal1.h\
+					  f2c/signal1.h0 $(F2C)
+  libf2c_la_CFLAGS = -DSkip_f2c_Undefs -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+  f2c/arith.h: f2c/arithchk.c
+	$(CC) $(CFLAGS) -DNO_FPINIT f2c/arithchk.c -lm -o f2c/arith || \
+	$(CC) -DNO_LONG_LONG $(CFLAGS) -DNO_FPINIT f2c/arithchk.c \
+		$(WARNING_CFLAGS) -lm -o f2c/arith
+	f2c/arith > f2c/arith.h
+  f2c/sysdep1.h: f2c/sysdep1.h0
+	cp f2c/sysdep1.h0 f2c/sysdep1.h
+  f2c/signal1.h: f2c/signal1.h0
+	cp f2c/signal1.h0 f2c/signal1.h
+  F2C_LIB = libf2c.la
+
+  BUILT_SOURCES += f2c/arith.h
+endif
+
+if INTERNAL_BLAS
+  libblas_la_SOURCES = f2c.h $(BLAS)
+  libblas_la_CFLAGS = -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+  BLAS_LIB = libblas.la
+endif
+
+if INTERNAL_LAPACK
+  liblapack_la_SOURCES = f2c.h $(LAPACK)
+  liblapack_la_CFLAGS = -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+  libdlamch_la_SOURCES = lapack/dlamch.c
+  libdlamch_la_CFLAGS = $(FLOATSTORE) -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+  LAPACK_LIB = liblapack.la libdlamch.la
+endif
+
+if INTERNAL_ARPACK
+  libarpack_la_SOURCES = f2c.h $(ARPACK)
+  libarpack_la_CFLAGS = -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+  ARPACK_LIB = libarpack.la
+endif
+
+include ../optional/glpk/glpk.inc
+
+if INTERNAL_GLPK
+  libglpk_la_SOURCES = 	$(GLPK)
+  libglpk_la_CFLAGS = -I$(top_srcdir)/optional/glpk
+  libglpk_la_CPPFLAGS = -I$(top_srcdir)/include
+  GLPK_LIB = libglpk.la
+endif
+
+include prpack/prpack.inc
+
+libprpack_la_SOURCES = $(PRPACK)
+libprpack_la_CFLAGS = -I$(top_srcdir)/include -DPRPACK_IGRAPH_SUPPORT
+libprpack_la_CPPFLAGS = -I$(top_srcdir)/include -DPRPACK_IGRAPH_SUPPORT
+PRPACK_LIB = libprpack.la
+
+libplfit_la_SOURCES = $(PLFIT)
+PLFIT_LIB = libplfit.la
+
+noinst_LTLIBRARIES = $(F2C_LIB) $(BLAS_LIB) $(LAPACK_LIB) $(ARPACK_LIB) \
+					 $(GLPK_LIB) $(PLFIT_LIB) $(PRPACK_LIB)
+
+CS = cs/cs_add.c       cs/cs_happly.c    cs/cs_pvec.c         \
+	cs/cs_amd.c       cs/cs_house.c     cs/cs_qr.c        \
+	cs/cs_chol.c      cs/cs_ipvec.c     cs/cs_qrsol.c     \
+	cs/cs_cholsol.c   cs/cs_leaf.c      cs/cs_randperm.c  \
+	cs/cs_compress.c  cs/cs_load.c      cs/cs_reach.c     \
+	cs/cs_counts.c    cs/cs_lsolve.c    cs/cs_scatter.c   \
+	cs/cs_cumsum.c    cs/cs_ltsolve.c   cs/cs_scc.c       \
+	cs/cs_dfs.c       cs/cs_lu.c        cs/cs_schol.c     \
+	cs/cs_dmperm.c    cs/cs_lusol.c     cs/cs_spsolve.c   \
+	cs/cs_droptol.c   cs/cs_malloc.c    cs/cs_sqr.c       \
+	cs/cs_dropzeros.c cs/cs_maxtrans.c  cs/cs_symperm.c   \
+	cs/cs_dupl.c      cs/cs_multiply.c  cs/cs_tdfs.c      \
+	cs/cs_entry.c     cs/cs_norm.c      cs/cs_transpose.c \
+	cs/cs_ereach.c    cs/cs_permute.c   cs/cs_updown.c    \
+	cs/cs_etree.c     cs/cs_pinv.c      cs/cs_usolve.c    \
+	cs/cs_fkeep.c     cs/cs_post.c      cs/cs_util.c      \
+	cs/cs_gaxpy.c     cs/cs_print.c     cs/cs_utsolve.c   \
+	cs/cs.h	    cs/UFconfig.h
+
+HEADERS_PRIVATE = atlas-edges.h \
+		bliss_bignum.hh		bliss_defs.hh \
+		bliss_eqrefhash.hh	bliss_graph.hh \
+		bliss_heap.hh		bliss_kqueue.hh \
+		bliss_kstack.hh		bliss_orbit.hh \
+		bliss_partition.hh	bliss_timer.hh \
+		bliss_utils.hh \
+		NetDataTypes.h		NetRoutines.h \
+		pottsmodel_2.h \
+		igraph_gml_tree.h \
+		walktrap_graph.h	walktrap_communities.h \
+		walktrap_heap.h \
+		infomap_Greedy.h infomap_Node.h infomap_Greedy.h infomap_FlowGraph.h \
+		igraph_math.h \
+		drl_layout.h drl_parse.h drl_graph.h \
+		drl_graph_3d.h		drl_layout_3d.h \
+		drl_Node.h	drl_Node_3d.h \
+		DensityGrid.h	DensityGrid_3d.h \
+		igraph_flow_internal.h \
+		vector.pmt matrix.pmt stack.pmt dqueue.pmt heap.pmt array.pmt \
+		igraph_types_internal.h \
+		foreign-dl-header.h bignum.h bigint.h \
+		gengraph_box_list.h gengraph_definitions.h \
+		gengraph_degree_sequence.h gengraph_graph_molloy_hash.h \
+		gengraph_graph_molloy_optimized.h \
+		gengraph_hash.h gengraph_header.h gengraph_powerlaw.h \
+		gengraph_qsort.h gengraph_random.h gengraph_vertex_cover.h \
+		igraph_blas_internal.h igraph_arpack_internal.h \
+		igraph_lapack_internal.h igraph_glpk_support.h \
+		igraph_marked_queue.h igraph_estack.h \
+		hrg_dendro.h hrg_graph.h hrg_rbtree.h hrg_splittree_eq.h \
+		hrg_graph_simp.h foreign-gml-header.h \
+		foreign-ncol-header.h foreign-lgl-header.h \
+		foreign-pajek-header.h igraph_interrupt_internal.h \
+		scg_headers.h igraph_hacks_internal.h triangles_template.h \
+		triangles_template1.h maximal_cliques_template.h prpack.h
+
+HEADERS_PUBLIC =../include/igraph.h 		../include/igraph_memory.h    \
+		../include/igraph_random.h 	../include/igraph_types.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_arpack.h 	\
+		../include/igraph_attributes.h 	../include/igraph_error.h     \
+		../include/igraph_pmt.h 	../include/igraph_pmt_off.h   \
+		../include/igraph_adjlist.h	../include/igraph_iterators.h \
+		../include/igraph_bipartite.h	../include/igraph_layout.h    \
+		../include/igraph_centrality.h	../include/igraph_motifs.h    \
+		../include/igraph_cliques.h	../include/igraph_neighborhood.h \
+		../include/igraph_cocitation.h	../include/igraph_nongraph.h  \
+		../include/igraph_community.h	../include/igraph_operators.h \
+		../include/igraph_components.h	../include/igraph_paths.h     \
+		../include/igraph_constructors.h ../include/igraph_progress.h \
+		../include/igraph_conversion.h	../include/igraph_revolver.h  \
+		../include/igraph_datatype.h	../include/igraph_structural.h\
+		../include/igraph_flow.h	../include/igraph_topology.h  \
+		../include/igraph_foreign.h	../include/igraph_transitivity.h \
+		../include/igraph_games.h	../include/igraph_visitor.h   \
+		../include/igraph_interface.h	../include/igraph_constants.h \
+		../include/igraph_vector_pmt.h	../include/igraph_matrix_pmt.h\
+		../include/igraph_array_pmt.h	../include/igraph_dqueue_pmt.h\
+		../include/igraph_stack_pmt.h	../include/igraph_heap_pmt.h  \
+		../include/igraph_vector_ptr.h	../include/igraph_spmatrix.h  \
+		../include/igraph_strvector.h	../include/igraph_psumtree.h  \
+		../include/igraph_sparsemat.h   ../include/igraph_mixing.h    \
+		../include/igraph_version.h     ../include/igraph_blas.h      \
+		../include/igraph_separators.h  ../include/igraph_cohesive_blocks.h \
+		../include/igraph_lapack.h	../include/igraph_complex.h   \
+		../include/igraph_eigen.h	../include/igraph_statusbar.h \
+		../include/igraph_hrg.h         ../include/igraph_microscopic_update.h \
+		../include/igraph_interrupt.h   ../include/igraph_threading.h \
+		../include/igraph_scg.h		../include/igraph_qsort.h \
+		../include/igraph_matching.h	../include/igraph_graphlets.h \
+		../include/igraph_vector_type.h ../include/igraph_epidemics.h
+
+SOURCES = 		     basic_query.c games.c cocitation.c iterators.c \
+			     structural_properties.c components.c layout.c \
+			     structure_generators.c conversion.c \
+			     type_indexededgelist.c spanning_trees.c \
+			     igraph_error.c interrupt.c other.c foreign.c random.c \
+			     attributes.c \
+			     foreign-ncol-parser.y foreign-ncol-lexer.l \
+			     foreign-lgl-parser.y foreign-lgl-lexer.l \
+			     foreign-pajek-parser.y foreign-pajek-lexer.l \
+			     foreign-gml-parser.y foreign-gml-lexer.l \
+			     dqueue.c heap.c igraph_heap.c igraph_stack.c \
+			     igraph_strvector.c igraph_trie.c matrix.c \
+			     vector.c vector_ptr.c memory.c adjlist.c \
+			     visitors.c igraph_grid.c atlas.c topology.c \
+			     motifs.c progress.c operators.c \
+			     igraph_psumtree.c array.c igraph_hashtable.c \
+			     foreign-graphml.c flow.c igraph_buckets.c \
+			     NetDataTypes.cpp NetRoutines.cpp clustertool.cpp \
+			     pottsmodel_2.cpp spectral_properties.c cores.c \
+			     igraph_set.c cliques.c revolver_cit.c revolver_grow.c\
+			     walktrap.cpp walktrap_heap.cpp \
+			     walktrap_graph.cpp walktrap_communities.cpp \
+			     infomap.cc infomap_Greedy.cc infomap_Node.cc infomap_FlowGraph.cc \
+			     spmatrix.c community.c fast_community.c \
+			     evolver_cit.c gml_tree.c \
+			     bliss_orbit.cc bliss_eqrefhash.cc \
+			     bliss_partition.cc bliss_graph.cc bliss_timer.cc \
+			     bliss_heap.cc bliss_utils.cc bliss.cc \
+			     cattributes.c revolver_ml_cit.c zeroin.c bfgs.c math.c \
+			     forestfire.c microscopic_update.c \
+			     blas.c arpack.c centrality.c drl_layout.cpp drl_parse.cpp \
+			     drl_graph.cpp DensityGrid.cpp \
+			     gengraph_box_list.cpp gengraph_degree_sequence.cpp \
+			     gengraph_graph_molloy_hash.cpp \
+			     gengraph_graph_molloy_optimized.cpp \
+			     gengraph_mr-connected.cpp gengraph_powerlaw.cpp \
+			     gengraph_random.cpp decomposition.c bipartite.c \
+			     drl_layout_3d.cpp drl_graph_3d.cpp \
+			     DensityGrid_3d.cpp \
+			     foreign-dl-parser.y foreign-dl-lexer.l \
+			     $(CS) sparsemat.c mixing.c bigint.c bignum.c \
+			     version.c optimal_modularity.c \
+			     igraph_fixed_vectorlist.c separators.c \
+			     igraph_marked_queue.c igraph_estack.c st-cuts.c \
+			     cohesive_blocks.c statusbar.c \
+			     lapack.c complex.c eigen.c feedback_arc_set.c \
+			     sugiyama.c glpk_support.c \
+				 igraph_hrg_types.cc igraph_hrg.cc \
+			     distances.c fortran_intrinsics.c matching.c \
+			     scg.c scg_approximate_methods.c scg_exact_scg.c \
+			     scg_kmeans.c scg_utils.c scg_optimal_method.c \
+			     qsort.c qsort_r.c types.c lad.c hacks.c \
+			     triangles.c glet.c maximal_cliques.c sbm.c \
+			     sir.c  prpack.cpp
+
+libigraph_la_SOURCES       = $(SOURCES) $(HEADERS_PRIVATE)
+libigraph_la_CFLAGS        = -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+libigraph_la_CXXFLAGS	   = -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+libigraph_la_LDFLAGS       = -no-undefined
+libigraph_la_LIBADD        = -lm $(XML2_LIBS) $(F2C_LIB) $(BLAS_LIB) \
+				 $(LAPACK_LIB) $(ARPACK_LIB) $(GLPK_LIB) $(PRPACK_LIB) \
+				 $(PLFIT_LIB)
+
+if INTERNAL_GLPK
+  libigraph_la_CFLAGS   += -I$(top_srcdir)/optional/glpk
+  libigraph_la_CXXFLAGS += -I$(top_srcdir)/optional/glpk
+endif
+
+libigraph_la_CFLAGS += -I$(top_srcdir)/src/prpack -DPRPACK_IGRAPH_SUPPORT
+libigraph_la_CXXFLAGS += -I$(top_srcdir)/src/prpack -DPRPACK_IGRAPH_SUPPORT
+
+includedir = $(prefix)/include/igraph
+include_HEADERS = $(HEADERS_PUBLIC)
+
+MAINTAINERCLEANFILES = Makefile.in foreign-lgl-parser.h foreign-ncol-parser.h
+
+echosources:
+	$(info $(SOURCES) $(LAPACK) $(ARPACK) $(BLAS) $(libf2c_la_SOURCES) \
+	$(libdlamch_la_SOURCES) $(libplfit_la_SOURCES))
+
+echoheaders:
+	$(info $(HEADERS_PUBLIC))
+
+echoheadersprivate:
+	$(info $(HEADERS_PRIVATE))
+
+.PHONY: sources
+
+parsersources: $(DIST_COMMON)
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..777eb28
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,7991 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(srcdir)/lapack/blas.inc $(srcdir)/lapack/lapack.inc \
+	$(srcdir)/lapack/arpack.inc $(srcdir)/plfit/plfit.inc \
+	$(srcdir)/../optional/glpk/glpk.inc \
+	$(srcdir)/prpack/prpack.inc $(srcdir)/Makefile.in \
+	$(srcdir)/Makefile.am foreign-ncol-parser.h \
+	foreign-ncol-parser.c foreign-ncol-lexer.c \
+	foreign-lgl-parser.h foreign-lgl-parser.c foreign-lgl-lexer.c \
+	foreign-pajek-parser.h foreign-pajek-parser.c \
+	foreign-pajek-lexer.c foreign-gml-parser.h \
+	foreign-gml-parser.c foreign-gml-lexer.c foreign-dl-parser.h \
+	foreign-dl-parser.c foreign-dl-lexer.c $(top_srcdir)/depcomp \
+	$(top_srcdir)/ylwrap $(include_HEADERS)
+ at INTERNAL_F2C_TRUE@am__append_1 = f2c/arith.h
+ at INTERNAL_GLPK_TRUE@am__append_2 = -I$(top_srcdir)/optional/glpk
+ at INTERNAL_GLPK_TRUE@am__append_3 = -I$(top_srcdir)/optional/glpk
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/tools/autoconf/ax_tls.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libarpack_la_LIBADD =
+am__libarpack_la_SOURCES_DIST = f2c.h lapack/dnaupd.c lapack/dnaup2.c \
+	lapack/dgetv0.c lapack/dvout.c lapack/second.c lapack/dmout.c \
+	lapack/dnaitr.c lapack/ivout.c lapack/dnapps.c lapack/dnconv.c \
+	lapack/dneigh.c lapack/dlaqrb.c lapack/dngets.c \
+	lapack/dsortc.c lapack/dstatn.c lapack/dneupd.c \
+	lapack/dsaupd.c lapack/dsaup2.c lapack/dsaitr.c \
+	lapack/dsapps.c lapack/dsconv.c lapack/dseigt.c \
+	lapack/dstqrb.c lapack/dsgets.c lapack/dsortr.c \
+	lapack/dstats.c lapack/dseupd.c lapack/dsesrt.c
+am__dirstamp = $(am__leading_dot)dirstamp
+am__objects_1 = lapack/libarpack_la-dnaupd.lo \
+	lapack/libarpack_la-dnaup2.lo lapack/libarpack_la-dgetv0.lo \
+	lapack/libarpack_la-dvout.lo lapack/libarpack_la-second.lo \
+	lapack/libarpack_la-dmout.lo lapack/libarpack_la-dnaitr.lo \
+	lapack/libarpack_la-ivout.lo lapack/libarpack_la-dnapps.lo \
+	lapack/libarpack_la-dnconv.lo lapack/libarpack_la-dneigh.lo \
+	lapack/libarpack_la-dlaqrb.lo lapack/libarpack_la-dngets.lo \
+	lapack/libarpack_la-dsortc.lo lapack/libarpack_la-dstatn.lo \
+	lapack/libarpack_la-dneupd.lo lapack/libarpack_la-dsaupd.lo \
+	lapack/libarpack_la-dsaup2.lo lapack/libarpack_la-dsaitr.lo \
+	lapack/libarpack_la-dsapps.lo lapack/libarpack_la-dsconv.lo \
+	lapack/libarpack_la-dseigt.lo lapack/libarpack_la-dstqrb.lo \
+	lapack/libarpack_la-dsgets.lo lapack/libarpack_la-dsortr.lo \
+	lapack/libarpack_la-dstats.lo lapack/libarpack_la-dseupd.lo \
+	lapack/libarpack_la-dsesrt.lo
+ at INTERNAL_ARPACK_TRUE@am_libarpack_la_OBJECTS = $(am__objects_1)
+libarpack_la_OBJECTS = $(am_libarpack_la_OBJECTS)
+AM_V_lt = $(am__v_lt_ at AM_V@)
+am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libarpack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libarpack_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+ at INTERNAL_ARPACK_TRUE@am_libarpack_la_rpath =
+libblas_la_LIBADD =
+am__libblas_la_SOURCES_DIST = f2c.h lapack/dscal.c lapack/dswap.c \
+	lapack/lsame.c lapack/idamax.c lapack/daxpy.c lapack/dgemv.c \
+	lapack/dger.c lapack/dnrm2.c lapack/dgemm.c lapack/dcopy.c \
+	lapack/dtrmm.c lapack/dtrmv.c lapack/drot.c lapack/ddot.c \
+	lapack/dasum.c lapack/dsymv.c lapack/dsyr2k.c lapack/dsyr2.c \
+	lapack/dtrsm.c
+am__objects_2 = lapack/libblas_la-dscal.lo lapack/libblas_la-dswap.lo \
+	lapack/libblas_la-lsame.lo lapack/libblas_la-idamax.lo \
+	lapack/libblas_la-daxpy.lo lapack/libblas_la-dgemv.lo \
+	lapack/libblas_la-dger.lo lapack/libblas_la-dnrm2.lo \
+	lapack/libblas_la-dgemm.lo lapack/libblas_la-dcopy.lo \
+	lapack/libblas_la-dtrmm.lo lapack/libblas_la-dtrmv.lo \
+	lapack/libblas_la-drot.lo lapack/libblas_la-ddot.lo \
+	lapack/libblas_la-dasum.lo lapack/libblas_la-dsymv.lo \
+	lapack/libblas_la-dsyr2k.lo lapack/libblas_la-dsyr2.lo \
+	lapack/libblas_la-dtrsm.lo
+ at INTERNAL_BLAS_TRUE@am_libblas_la_OBJECTS = $(am__objects_2)
+libblas_la_OBJECTS = $(am_libblas_la_OBJECTS)
+libblas_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libblas_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+ at INTERNAL_BLAS_TRUE@am_libblas_la_rpath =
+libdlamch_la_LIBADD =
+am__libdlamch_la_SOURCES_DIST = lapack/dlamch.c
+ at INTERNAL_LAPACK_TRUE@am_libdlamch_la_OBJECTS =  \
+ at INTERNAL_LAPACK_TRUE@	lapack/libdlamch_la-dlamch.lo
+libdlamch_la_OBJECTS = $(am_libdlamch_la_OBJECTS)
+libdlamch_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libdlamch_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+ at INTERNAL_LAPACK_TRUE@am_libdlamch_la_rpath =
+libf2c_la_LIBADD =
+am__libf2c_la_SOURCES_DIST = f2c.h f2c/fio.h f2c/fmt.h f2c/sysdep1.h \
+	f2c/sysdep1.h0 f2c/lio.h f2c/fp.h f2c/signal1.h f2c/signal1.h0 \
+	f2c/abort_.c f2c/dolio.c f2c/r_sin.c f2c/dummy.c f2c/dtime_.c \
+	f2c/iio.c f2c/r_sinh.c f2c/backspac.c f2c/due.c f2c/ilnw.c \
+	f2c/r_sqrt.c f2c/c_abs.c f2c/ef1asc_.c f2c/inquire.c \
+	f2c/r_tan.c f2c/c_cos.c f2c/ef1cmc_.c f2c/l_ge.c f2c/r_tanh.c \
+	f2c/c_div.c f2c/endfile.c f2c/l_gt.c f2c/rdfmt.c f2c/c_exp.c \
+	f2c/erf_.c f2c/l_le.c f2c/rewind.c f2c/c_log.c f2c/erfc_.c \
+	f2c/l_lt.c f2c/rsfe.c f2c/c_sin.c f2c/err.c f2c/lbitbits.c \
+	f2c/rsli.c f2c/c_sqrt.c f2c/etime_.c f2c/lbitshft.c f2c/rsne.c \
+	f2c/cabs.c f2c/exit_.c f2c/lread.c f2c/s_cat.c f2c/close.c \
+	f2c/f77_aloc.c f2c/lwrite.c f2c/s_cmp.c f2c/ctype.c \
+	f2c/f77vers.c f2c/s_copy.c f2c/d_abs.c f2c/fmt.c f2c/open.c \
+	f2c/s_paus.c f2c/d_acos.c f2c/fmtlib.c f2c/pow_ci.c \
+	f2c/s_rnge.c f2c/d_asin.c f2c/ftell_.c f2c/pow_dd.c \
+	f2c/s_stop.c f2c/d_atan.c f2c/pow_di.c f2c/sfe.c f2c/d_atn2.c \
+	f2c/getenv_.c f2c/pow_hh.c f2c/sig_die.c f2c/d_cnjg.c \
+	f2c/h_abs.c f2c/pow_ii.c f2c/signal_.c f2c/d_cos.c f2c/h_dim.c \
+	f2c/pow_ri.c f2c/signbit.c f2c/d_cosh.c f2c/h_dnnt.c \
+	f2c/pow_zi.c f2c/sue.c f2c/d_dim.c f2c/h_indx.c f2c/pow_zz.c \
+	f2c/system_.c f2c/d_exp.c f2c/h_len.c f2c/r_abs.c \
+	f2c/typesize.c f2c/d_imag.c f2c/h_mod.c f2c/r_acos.c f2c/uio.c \
+	f2c/d_int.c f2c/h_nint.c f2c/r_asin.c f2c/uninit.c \
+	f2c/d_lg10.c f2c/h_sign.c f2c/r_atan.c f2c/util.c f2c/d_log.c \
+	f2c/hl_ge.c f2c/r_atn2.c f2c/wref.c f2c/d_mod.c f2c/hl_gt.c \
+	f2c/r_cnjg.c f2c/wrtfmt.c f2c/d_nint.c f2c/hl_le.c f2c/r_cos.c \
+	f2c/wsfe.c f2c/d_prod.c f2c/hl_lt.c f2c/r_cosh.c f2c/wsle.c \
+	f2c/d_sign.c f2c/i77vers.c f2c/r_dim.c f2c/wsne.c f2c/d_sin.c \
+	f2c/i_abs.c f2c/r_exp.c f2c/xwsne.c f2c/d_sinh.c f2c/i_dim.c \
+	f2c/r_imag.c f2c/z_abs.c f2c/d_sqrt.c f2c/i_dnnt.c f2c/r_int.c \
+	f2c/z_cos.c f2c/d_tan.c f2c/i_indx.c f2c/r_lg10.c f2c/z_div.c \
+	f2c/d_tanh.c f2c/i_len.c f2c/r_log.c f2c/z_exp.c f2c/derf_.c \
+	f2c/i_mod.c f2c/r_mod.c f2c/z_log.c f2c/derfc_.c f2c/i_nint.c \
+	f2c/r_nint.c f2c/z_sin.c f2c/dfe.c f2c/i_sign.c f2c/r_sign.c \
+	f2c/z_sqrt.c
+am__objects_3 = f2c/libf2c_la-abort_.lo f2c/libf2c_la-dolio.lo \
+	f2c/libf2c_la-r_sin.lo f2c/libf2c_la-dummy.lo \
+	f2c/libf2c_la-dtime_.lo f2c/libf2c_la-iio.lo \
+	f2c/libf2c_la-r_sinh.lo f2c/libf2c_la-backspac.lo \
+	f2c/libf2c_la-due.lo f2c/libf2c_la-ilnw.lo \
+	f2c/libf2c_la-r_sqrt.lo f2c/libf2c_la-c_abs.lo \
+	f2c/libf2c_la-ef1asc_.lo f2c/libf2c_la-inquire.lo \
+	f2c/libf2c_la-r_tan.lo f2c/libf2c_la-c_cos.lo \
+	f2c/libf2c_la-ef1cmc_.lo f2c/libf2c_la-l_ge.lo \
+	f2c/libf2c_la-r_tanh.lo f2c/libf2c_la-c_div.lo \
+	f2c/libf2c_la-endfile.lo f2c/libf2c_la-l_gt.lo \
+	f2c/libf2c_la-rdfmt.lo f2c/libf2c_la-c_exp.lo \
+	f2c/libf2c_la-erf_.lo f2c/libf2c_la-l_le.lo \
+	f2c/libf2c_la-rewind.lo f2c/libf2c_la-c_log.lo \
+	f2c/libf2c_la-erfc_.lo f2c/libf2c_la-l_lt.lo \
+	f2c/libf2c_la-rsfe.lo f2c/libf2c_la-c_sin.lo \
+	f2c/libf2c_la-err.lo f2c/libf2c_la-lbitbits.lo \
+	f2c/libf2c_la-rsli.lo f2c/libf2c_la-c_sqrt.lo \
+	f2c/libf2c_la-etime_.lo f2c/libf2c_la-lbitshft.lo \
+	f2c/libf2c_la-rsne.lo f2c/libf2c_la-cabs.lo \
+	f2c/libf2c_la-exit_.lo f2c/libf2c_la-lread.lo \
+	f2c/libf2c_la-s_cat.lo f2c/libf2c_la-close.lo \
+	f2c/libf2c_la-f77_aloc.lo f2c/libf2c_la-lwrite.lo \
+	f2c/libf2c_la-s_cmp.lo f2c/libf2c_la-ctype.lo \
+	f2c/libf2c_la-f77vers.lo f2c/libf2c_la-s_copy.lo \
+	f2c/libf2c_la-d_abs.lo f2c/libf2c_la-fmt.lo \
+	f2c/libf2c_la-open.lo f2c/libf2c_la-s_paus.lo \
+	f2c/libf2c_la-d_acos.lo f2c/libf2c_la-fmtlib.lo \
+	f2c/libf2c_la-pow_ci.lo f2c/libf2c_la-s_rnge.lo \
+	f2c/libf2c_la-d_asin.lo f2c/libf2c_la-ftell_.lo \
+	f2c/libf2c_la-pow_dd.lo f2c/libf2c_la-s_stop.lo \
+	f2c/libf2c_la-d_atan.lo f2c/libf2c_la-pow_di.lo \
+	f2c/libf2c_la-sfe.lo f2c/libf2c_la-d_atn2.lo \
+	f2c/libf2c_la-getenv_.lo f2c/libf2c_la-pow_hh.lo \
+	f2c/libf2c_la-sig_die.lo f2c/libf2c_la-d_cnjg.lo \
+	f2c/libf2c_la-h_abs.lo f2c/libf2c_la-pow_ii.lo \
+	f2c/libf2c_la-signal_.lo f2c/libf2c_la-d_cos.lo \
+	f2c/libf2c_la-h_dim.lo f2c/libf2c_la-pow_ri.lo \
+	f2c/libf2c_la-signbit.lo f2c/libf2c_la-d_cosh.lo \
+	f2c/libf2c_la-h_dnnt.lo f2c/libf2c_la-pow_zi.lo \
+	f2c/libf2c_la-sue.lo f2c/libf2c_la-d_dim.lo \
+	f2c/libf2c_la-h_indx.lo f2c/libf2c_la-pow_zz.lo \
+	f2c/libf2c_la-system_.lo f2c/libf2c_la-d_exp.lo \
+	f2c/libf2c_la-h_len.lo f2c/libf2c_la-r_abs.lo \
+	f2c/libf2c_la-typesize.lo f2c/libf2c_la-d_imag.lo \
+	f2c/libf2c_la-h_mod.lo f2c/libf2c_la-r_acos.lo \
+	f2c/libf2c_la-uio.lo f2c/libf2c_la-d_int.lo \
+	f2c/libf2c_la-h_nint.lo f2c/libf2c_la-r_asin.lo \
+	f2c/libf2c_la-uninit.lo f2c/libf2c_la-d_lg10.lo \
+	f2c/libf2c_la-h_sign.lo f2c/libf2c_la-r_atan.lo \
+	f2c/libf2c_la-util.lo f2c/libf2c_la-d_log.lo \
+	f2c/libf2c_la-hl_ge.lo f2c/libf2c_la-r_atn2.lo \
+	f2c/libf2c_la-wref.lo f2c/libf2c_la-d_mod.lo \
+	f2c/libf2c_la-hl_gt.lo f2c/libf2c_la-r_cnjg.lo \
+	f2c/libf2c_la-wrtfmt.lo f2c/libf2c_la-d_nint.lo \
+	f2c/libf2c_la-hl_le.lo f2c/libf2c_la-r_cos.lo \
+	f2c/libf2c_la-wsfe.lo f2c/libf2c_la-d_prod.lo \
+	f2c/libf2c_la-hl_lt.lo f2c/libf2c_la-r_cosh.lo \
+	f2c/libf2c_la-wsle.lo f2c/libf2c_la-d_sign.lo \
+	f2c/libf2c_la-i77vers.lo f2c/libf2c_la-r_dim.lo \
+	f2c/libf2c_la-wsne.lo f2c/libf2c_la-d_sin.lo \
+	f2c/libf2c_la-i_abs.lo f2c/libf2c_la-r_exp.lo \
+	f2c/libf2c_la-xwsne.lo f2c/libf2c_la-d_sinh.lo \
+	f2c/libf2c_la-i_dim.lo f2c/libf2c_la-r_imag.lo \
+	f2c/libf2c_la-z_abs.lo f2c/libf2c_la-d_sqrt.lo \
+	f2c/libf2c_la-i_dnnt.lo f2c/libf2c_la-r_int.lo \
+	f2c/libf2c_la-z_cos.lo f2c/libf2c_la-d_tan.lo \
+	f2c/libf2c_la-i_indx.lo f2c/libf2c_la-r_lg10.lo \
+	f2c/libf2c_la-z_div.lo f2c/libf2c_la-d_tanh.lo \
+	f2c/libf2c_la-i_len.lo f2c/libf2c_la-r_log.lo \
+	f2c/libf2c_la-z_exp.lo f2c/libf2c_la-derf_.lo \
+	f2c/libf2c_la-i_mod.lo f2c/libf2c_la-r_mod.lo \
+	f2c/libf2c_la-z_log.lo f2c/libf2c_la-derfc_.lo \
+	f2c/libf2c_la-i_nint.lo f2c/libf2c_la-r_nint.lo \
+	f2c/libf2c_la-z_sin.lo f2c/libf2c_la-dfe.lo \
+	f2c/libf2c_la-i_sign.lo f2c/libf2c_la-r_sign.lo \
+	f2c/libf2c_la-z_sqrt.lo
+ at INTERNAL_F2C_TRUE@am_libf2c_la_OBJECTS = $(am__objects_3)
+libf2c_la_OBJECTS = $(am_libf2c_la_OBJECTS)
+libf2c_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libf2c_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+ at INTERNAL_F2C_TRUE@am_libf2c_la_rpath =
+libglpk_la_LIBADD =
+am__libglpk_la_SOURCES_DIST = ../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/glpk/glpapi17.c ../optional/glpk/glpapi18.c \
+	../optional/glpk/glpapi19.c ../optional/glpk/glpavl.c \
+	../optional/glpk/glpavl.h ../optional/glpk/glpbfd.c \
+	../optional/glpk/glpbfd.h ../optional/glpk/glpbfx.c \
+	../optional/glpk/glpbfx.h ../optional/glpk/glpcpx.c \
+	../optional/glpk/glpdmp.c ../optional/glpk/glpdmp.h \
+	../optional/glpk/glpdmx.c ../optional/glpk/glpenv.h \
+	../optional/glpk/glpenv01.c ../optional/glpk/glpenv02.c \
+	../optional/glpk/glpenv03.c ../optional/glpk/glpenv04.c \
+	../optional/glpk/glpenv05.c ../optional/glpk/glpenv06.c \
+	../optional/glpk/glpenv07.c ../optional/glpk/glpenv08.c \
+	../optional/glpk/glpfhv.c ../optional/glpk/glpfhv.h \
+	../optional/glpk/glpgmp.c ../optional/glpk/glpgmp.h \
+	../optional/glpk/glphbm.c ../optional/glpk/glphbm.h \
+	../optional/glpk/glpini01.c ../optional/glpk/glpini02.c \
+	../optional/glpk/glpios.h ../optional/glpk/glpios01.c \
+	../optional/glpk/glpios02.c ../optional/glpk/glpios03.c \
+	../optional/glpk/glpios04.c ../optional/glpk/glpios05.c \
+	../optional/glpk/glpios06.c ../optional/glpk/glpios07.c \
+	../optional/glpk/glpios08.c ../optional/glpk/glpios09.c \
+	../optional/glpk/glpios10.c ../optional/glpk/glpios11.c \
+	../optional/glpk/glpios12.c ../optional/glpk/glpipm.c \
+	../optional/glpk/glpipm.h ../optional/glpk/glpk.h \
+	../optional/glpk/glplib.h ../optional/glpk/glplib01.c \
+	../optional/glpk/glplib02.c ../optional/glpk/glplib03.c \
+	../optional/glpk/glplpf.c ../optional/glpk/glplpf.h \
+	../optional/glpk/glplpx01.c ../optional/glpk/glplpx02.c \
+	../optional/glpk/glplpx03.c ../optional/glpk/glpluf.c \
+	../optional/glpk/glpluf.h ../optional/glpk/glplux.c \
+	../optional/glpk/glplux.h ../optional/glpk/glpmat.c \
+	../optional/glpk/glpmat.h ../optional/glpk/glpmpl.h \
+	../optional/glpk/glpmpl01.c ../optional/glpk/glpmpl02.c \
+	../optional/glpk/glpmpl03.c ../optional/glpk/glpmpl04.c \
+	../optional/glpk/glpmpl05.c ../optional/glpk/glpmpl06.c \
+	../optional/glpk/glpmps.c ../optional/glpk/glpnet.h \
+	../optional/glpk/glpnet01.c ../optional/glpk/glpnet02.c \
+	../optional/glpk/glpnet03.c ../optional/glpk/glpnet04.c \
+	../optional/glpk/glpnet05.c ../optional/glpk/glpnet06.c \
+	../optional/glpk/glpnet07.c ../optional/glpk/glpnet08.c \
+	../optional/glpk/glpnet09.c ../optional/glpk/glpnpp.h \
+	../optional/glpk/glpnpp01.c ../optional/glpk/glpnpp02.c \
+	../optional/glpk/glpnpp03.c ../optional/glpk/glpnpp04.c \
+	../optional/glpk/glpnpp05.c ../optional/glpk/glpqmd.c \
+	../optional/glpk/glpqmd.h ../optional/glpk/glprgr.c \
+	../optional/glpk/glprgr.h ../optional/glpk/glprng.h \
+	../optional/glpk/glprng01.c ../optional/glpk/glprng02.c \
+	../optional/glpk/glpscf.c ../optional/glpk/glpscf.h \
+	../optional/glpk/glpscl.c ../optional/glpk/glpsdf.c \
+	../optional/glpk/glpspm.c ../optional/glpk/glpspm.h \
+	../optional/glpk/glpspx.h ../optional/glpk/glpspx01.c \
+	../optional/glpk/glpspx02.c ../optional/glpk/glpsql.c \
+	../optional/glpk/glpsql.h ../optional/glpk/glpssx.h \
+	../optional/glpk/glpssx01.c ../optional/glpk/glpssx02.c \
+	../optional/glpk/glpstd.h ../optional/glpk/glptsp.c \
+	../optional/glpk/glptsp.h ../optional/glpk/amd/amd.h \
+	../optional/glpk/amd/amd_1.c ../optional/glpk/amd/amd_2.c \
+	../optional/glpk/amd/amd_aat.c \
+	../optional/glpk/amd/amd_control.c \
+	../optional/glpk/amd/amd_defaults.c \
+	../optional/glpk/amd/amd_dump.c \
+	../optional/glpk/amd/amd_info.c \
+	../optional/glpk/amd/amd_internal.h \
+	../optional/glpk/amd/amd_order.c \
+	../optional/glpk/amd/amd_post_tree.c \
+	../optional/glpk/amd/amd_postorder.c \
+	../optional/glpk/amd/amd_preprocess.c \
+	../optional/glpk/amd/amd_valid.c \
+	../optional/glpk/colamd/colamd.c \
+	../optional/glpk/colamd/colamd.h
+am__objects_4 = ../optional/glpk/libglpk_la-glpapi01.lo \
+	../optional/glpk/libglpk_la-glpapi02.lo \
+	../optional/glpk/libglpk_la-glpapi03.lo \
+	../optional/glpk/libglpk_la-glpapi04.lo \
+	../optional/glpk/libglpk_la-glpapi05.lo \
+	../optional/glpk/libglpk_la-glpapi06.lo \
+	../optional/glpk/libglpk_la-glpapi07.lo \
+	../optional/glpk/libglpk_la-glpapi08.lo \
+	../optional/glpk/libglpk_la-glpapi09.lo \
+	../optional/glpk/libglpk_la-glpapi10.lo \
+	../optional/glpk/libglpk_la-glpapi11.lo \
+	../optional/glpk/libglpk_la-glpapi12.lo \
+	../optional/glpk/libglpk_la-glpapi13.lo \
+	../optional/glpk/libglpk_la-glpapi14.lo \
+	../optional/glpk/libglpk_la-glpapi15.lo \
+	../optional/glpk/libglpk_la-glpapi16.lo \
+	../optional/glpk/libglpk_la-glpapi17.lo \
+	../optional/glpk/libglpk_la-glpapi18.lo \
+	../optional/glpk/libglpk_la-glpapi19.lo \
+	../optional/glpk/libglpk_la-glpavl.lo \
+	../optional/glpk/libglpk_la-glpbfd.lo \
+	../optional/glpk/libglpk_la-glpbfx.lo \
+	../optional/glpk/libglpk_la-glpcpx.lo \
+	../optional/glpk/libglpk_la-glpdmp.lo \
+	../optional/glpk/libglpk_la-glpdmx.lo \
+	../optional/glpk/libglpk_la-glpenv01.lo \
+	../optional/glpk/libglpk_la-glpenv02.lo \
+	../optional/glpk/libglpk_la-glpenv03.lo \
+	../optional/glpk/libglpk_la-glpenv04.lo \
+	../optional/glpk/libglpk_la-glpenv05.lo \
+	../optional/glpk/libglpk_la-glpenv06.lo \
+	../optional/glpk/libglpk_la-glpenv07.lo \
+	../optional/glpk/libglpk_la-glpenv08.lo \
+	../optional/glpk/libglpk_la-glpfhv.lo \
+	../optional/glpk/libglpk_la-glpgmp.lo \
+	../optional/glpk/libglpk_la-glphbm.lo \
+	../optional/glpk/libglpk_la-glpini01.lo \
+	../optional/glpk/libglpk_la-glpini02.lo \
+	../optional/glpk/libglpk_la-glpios01.lo \
+	../optional/glpk/libglpk_la-glpios02.lo \
+	../optional/glpk/libglpk_la-glpios03.lo \
+	../optional/glpk/libglpk_la-glpios04.lo \
+	../optional/glpk/libglpk_la-glpios05.lo \
+	../optional/glpk/libglpk_la-glpios06.lo \
+	../optional/glpk/libglpk_la-glpios07.lo \
+	../optional/glpk/libglpk_la-glpios08.lo \
+	../optional/glpk/libglpk_la-glpios09.lo \
+	../optional/glpk/libglpk_la-glpios10.lo \
+	../optional/glpk/libglpk_la-glpios11.lo \
+	../optional/glpk/libglpk_la-glpios12.lo \
+	../optional/glpk/libglpk_la-glpipm.lo \
+	../optional/glpk/libglpk_la-glplib01.lo \
+	../optional/glpk/libglpk_la-glplib02.lo \
+	../optional/glpk/libglpk_la-glplib03.lo \
+	../optional/glpk/libglpk_la-glplpf.lo \
+	../optional/glpk/libglpk_la-glplpx01.lo \
+	../optional/glpk/libglpk_la-glplpx02.lo \
+	../optional/glpk/libglpk_la-glplpx03.lo \
+	../optional/glpk/libglpk_la-glpluf.lo \
+	../optional/glpk/libglpk_la-glplux.lo \
+	../optional/glpk/libglpk_la-glpmat.lo \
+	../optional/glpk/libglpk_la-glpmpl01.lo \
+	../optional/glpk/libglpk_la-glpmpl02.lo \
+	../optional/glpk/libglpk_la-glpmpl03.lo \
+	../optional/glpk/libglpk_la-glpmpl04.lo \
+	../optional/glpk/libglpk_la-glpmpl05.lo \
+	../optional/glpk/libglpk_la-glpmpl06.lo \
+	../optional/glpk/libglpk_la-glpmps.lo \
+	../optional/glpk/libglpk_la-glpnet01.lo \
+	../optional/glpk/libglpk_la-glpnet02.lo \
+	../optional/glpk/libglpk_la-glpnet03.lo \
+	../optional/glpk/libglpk_la-glpnet04.lo \
+	../optional/glpk/libglpk_la-glpnet05.lo \
+	../optional/glpk/libglpk_la-glpnet06.lo \
+	../optional/glpk/libglpk_la-glpnet07.lo \
+	../optional/glpk/libglpk_la-glpnet08.lo \
+	../optional/glpk/libglpk_la-glpnet09.lo \
+	../optional/glpk/libglpk_la-glpnpp01.lo \
+	../optional/glpk/libglpk_la-glpnpp02.lo \
+	../optional/glpk/libglpk_la-glpnpp03.lo \
+	../optional/glpk/libglpk_la-glpnpp04.lo \
+	../optional/glpk/libglpk_la-glpnpp05.lo \
+	../optional/glpk/libglpk_la-glpqmd.lo \
+	../optional/glpk/libglpk_la-glprgr.lo \
+	../optional/glpk/libglpk_la-glprng01.lo \
+	../optional/glpk/libglpk_la-glprng02.lo \
+	../optional/glpk/libglpk_la-glpscf.lo \
+	../optional/glpk/libglpk_la-glpscl.lo \
+	../optional/glpk/libglpk_la-glpsdf.lo \
+	../optional/glpk/libglpk_la-glpspm.lo \
+	../optional/glpk/libglpk_la-glpspx01.lo \
+	../optional/glpk/libglpk_la-glpspx02.lo \
+	../optional/glpk/libglpk_la-glpsql.lo \
+	../optional/glpk/libglpk_la-glpssx01.lo \
+	../optional/glpk/libglpk_la-glpssx02.lo \
+	../optional/glpk/libglpk_la-glptsp.lo \
+	../optional/glpk/amd/libglpk_la-amd_1.lo \
+	../optional/glpk/amd/libglpk_la-amd_2.lo \
+	../optional/glpk/amd/libglpk_la-amd_aat.lo \
+	../optional/glpk/amd/libglpk_la-amd_control.lo \
+	../optional/glpk/amd/libglpk_la-amd_defaults.lo \
+	../optional/glpk/amd/libglpk_la-amd_dump.lo \
+	../optional/glpk/amd/libglpk_la-amd_info.lo \
+	../optional/glpk/amd/libglpk_la-amd_order.lo \
+	../optional/glpk/amd/libglpk_la-amd_post_tree.lo \
+	../optional/glpk/amd/libglpk_la-amd_postorder.lo \
+	../optional/glpk/amd/libglpk_la-amd_preprocess.lo \
+	../optional/glpk/amd/libglpk_la-amd_valid.lo \
+	../optional/glpk/colamd/libglpk_la-colamd.lo
+ at INTERNAL_GLPK_TRUE@am_libglpk_la_OBJECTS = $(am__objects_4)
+libglpk_la_OBJECTS = $(am_libglpk_la_OBJECTS)
+libglpk_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libglpk_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+ at INTERNAL_GLPK_TRUE@am_libglpk_la_rpath =
+am__DEPENDENCIES_1 =
+libigraph_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(F2C_LIB) \
+	$(BLAS_LIB) $(LAPACK_LIB) $(ARPACK_LIB) $(GLPK_LIB) \
+	$(PRPACK_LIB) $(PLFIT_LIB)
+am__objects_5 = cs/libigraph_la-cs_add.lo cs/libigraph_la-cs_happly.lo \
+	cs/libigraph_la-cs_pvec.lo cs/libigraph_la-cs_amd.lo \
+	cs/libigraph_la-cs_house.lo cs/libigraph_la-cs_qr.lo \
+	cs/libigraph_la-cs_chol.lo cs/libigraph_la-cs_ipvec.lo \
+	cs/libigraph_la-cs_qrsol.lo cs/libigraph_la-cs_cholsol.lo \
+	cs/libigraph_la-cs_leaf.lo cs/libigraph_la-cs_randperm.lo \
+	cs/libigraph_la-cs_compress.lo cs/libigraph_la-cs_load.lo \
+	cs/libigraph_la-cs_reach.lo cs/libigraph_la-cs_counts.lo \
+	cs/libigraph_la-cs_lsolve.lo cs/libigraph_la-cs_scatter.lo \
+	cs/libigraph_la-cs_cumsum.lo cs/libigraph_la-cs_ltsolve.lo \
+	cs/libigraph_la-cs_scc.lo cs/libigraph_la-cs_dfs.lo \
+	cs/libigraph_la-cs_lu.lo cs/libigraph_la-cs_schol.lo \
+	cs/libigraph_la-cs_dmperm.lo cs/libigraph_la-cs_lusol.lo \
+	cs/libigraph_la-cs_spsolve.lo cs/libigraph_la-cs_droptol.lo \
+	cs/libigraph_la-cs_malloc.lo cs/libigraph_la-cs_sqr.lo \
+	cs/libigraph_la-cs_dropzeros.lo cs/libigraph_la-cs_maxtrans.lo \
+	cs/libigraph_la-cs_symperm.lo cs/libigraph_la-cs_dupl.lo \
+	cs/libigraph_la-cs_multiply.lo cs/libigraph_la-cs_tdfs.lo \
+	cs/libigraph_la-cs_entry.lo cs/libigraph_la-cs_norm.lo \
+	cs/libigraph_la-cs_transpose.lo cs/libigraph_la-cs_ereach.lo \
+	cs/libigraph_la-cs_permute.lo cs/libigraph_la-cs_updown.lo \
+	cs/libigraph_la-cs_etree.lo cs/libigraph_la-cs_pinv.lo \
+	cs/libigraph_la-cs_usolve.lo cs/libigraph_la-cs_fkeep.lo \
+	cs/libigraph_la-cs_post.lo cs/libigraph_la-cs_util.lo \
+	cs/libigraph_la-cs_gaxpy.lo cs/libigraph_la-cs_print.lo \
+	cs/libigraph_la-cs_utsolve.lo
+am__objects_6 = libigraph_la-basic_query.lo libigraph_la-games.lo \
+	libigraph_la-cocitation.lo libigraph_la-iterators.lo \
+	libigraph_la-structural_properties.lo \
+	libigraph_la-components.lo libigraph_la-layout.lo \
+	libigraph_la-structure_generators.lo \
+	libigraph_la-conversion.lo \
+	libigraph_la-type_indexededgelist.lo \
+	libigraph_la-spanning_trees.lo libigraph_la-igraph_error.lo \
+	libigraph_la-interrupt.lo libigraph_la-other.lo \
+	libigraph_la-foreign.lo libigraph_la-random.lo \
+	libigraph_la-attributes.lo libigraph_la-foreign-ncol-parser.lo \
+	libigraph_la-foreign-ncol-lexer.lo \
+	libigraph_la-foreign-lgl-parser.lo \
+	libigraph_la-foreign-lgl-lexer.lo \
+	libigraph_la-foreign-pajek-parser.lo \
+	libigraph_la-foreign-pajek-lexer.lo \
+	libigraph_la-foreign-gml-parser.lo \
+	libigraph_la-foreign-gml-lexer.lo libigraph_la-dqueue.lo \
+	libigraph_la-heap.lo libigraph_la-igraph_heap.lo \
+	libigraph_la-igraph_stack.lo libigraph_la-igraph_strvector.lo \
+	libigraph_la-igraph_trie.lo libigraph_la-matrix.lo \
+	libigraph_la-vector.lo libigraph_la-vector_ptr.lo \
+	libigraph_la-memory.lo libigraph_la-adjlist.lo \
+	libigraph_la-visitors.lo libigraph_la-igraph_grid.lo \
+	libigraph_la-atlas.lo libigraph_la-topology.lo \
+	libigraph_la-motifs.lo libigraph_la-progress.lo \
+	libigraph_la-operators.lo libigraph_la-igraph_psumtree.lo \
+	libigraph_la-array.lo libigraph_la-igraph_hashtable.lo \
+	libigraph_la-foreign-graphml.lo libigraph_la-flow.lo \
+	libigraph_la-igraph_buckets.lo libigraph_la-NetDataTypes.lo \
+	libigraph_la-NetRoutines.lo libigraph_la-clustertool.lo \
+	libigraph_la-pottsmodel_2.lo \
+	libigraph_la-spectral_properties.lo libigraph_la-cores.lo \
+	libigraph_la-igraph_set.lo libigraph_la-cliques.lo \
+	libigraph_la-revolver_cit.lo libigraph_la-revolver_grow.lo \
+	libigraph_la-walktrap.lo libigraph_la-walktrap_heap.lo \
+	libigraph_la-walktrap_graph.lo \
+	libigraph_la-walktrap_communities.lo libigraph_la-infomap.lo \
+	libigraph_la-infomap_Greedy.lo libigraph_la-infomap_Node.lo \
+	libigraph_la-infomap_FlowGraph.lo libigraph_la-spmatrix.lo \
+	libigraph_la-community.lo libigraph_la-fast_community.lo \
+	libigraph_la-evolver_cit.lo libigraph_la-gml_tree.lo \
+	libigraph_la-bliss_orbit.lo libigraph_la-bliss_eqrefhash.lo \
+	libigraph_la-bliss_partition.lo libigraph_la-bliss_graph.lo \
+	libigraph_la-bliss_timer.lo libigraph_la-bliss_heap.lo \
+	libigraph_la-bliss_utils.lo libigraph_la-bliss.lo \
+	libigraph_la-cattributes.lo libigraph_la-revolver_ml_cit.lo \
+	libigraph_la-zeroin.lo libigraph_la-bfgs.lo \
+	libigraph_la-math.lo libigraph_la-forestfire.lo \
+	libigraph_la-microscopic_update.lo libigraph_la-blas.lo \
+	libigraph_la-arpack.lo libigraph_la-centrality.lo \
+	libigraph_la-drl_layout.lo libigraph_la-drl_parse.lo \
+	libigraph_la-drl_graph.lo libigraph_la-DensityGrid.lo \
+	libigraph_la-gengraph_box_list.lo \
+	libigraph_la-gengraph_degree_sequence.lo \
+	libigraph_la-gengraph_graph_molloy_hash.lo \
+	libigraph_la-gengraph_graph_molloy_optimized.lo \
+	libigraph_la-gengraph_mr-connected.lo \
+	libigraph_la-gengraph_powerlaw.lo \
+	libigraph_la-gengraph_random.lo libigraph_la-decomposition.lo \
+	libigraph_la-bipartite.lo libigraph_la-drl_layout_3d.lo \
+	libigraph_la-drl_graph_3d.lo libigraph_la-DensityGrid_3d.lo \
+	libigraph_la-foreign-dl-parser.lo \
+	libigraph_la-foreign-dl-lexer.lo $(am__objects_5) \
+	libigraph_la-sparsemat.lo libigraph_la-mixing.lo \
+	libigraph_la-bigint.lo libigraph_la-bignum.lo \
+	libigraph_la-version.lo libigraph_la-optimal_modularity.lo \
+	libigraph_la-igraph_fixed_vectorlist.lo \
+	libigraph_la-separators.lo libigraph_la-igraph_marked_queue.lo \
+	libigraph_la-igraph_estack.lo libigraph_la-st-cuts.lo \
+	libigraph_la-cohesive_blocks.lo libigraph_la-statusbar.lo \
+	libigraph_la-lapack.lo libigraph_la-complex.lo \
+	libigraph_la-eigen.lo libigraph_la-feedback_arc_set.lo \
+	libigraph_la-sugiyama.lo libigraph_la-glpk_support.lo \
+	libigraph_la-igraph_hrg_types.lo libigraph_la-igraph_hrg.lo \
+	libigraph_la-distances.lo libigraph_la-fortran_intrinsics.lo \
+	libigraph_la-matching.lo libigraph_la-scg.lo \
+	libigraph_la-scg_approximate_methods.lo \
+	libigraph_la-scg_exact_scg.lo libigraph_la-scg_kmeans.lo \
+	libigraph_la-scg_utils.lo libigraph_la-scg_optimal_method.lo \
+	libigraph_la-qsort.lo libigraph_la-qsort_r.lo \
+	libigraph_la-types.lo libigraph_la-lad.lo \
+	libigraph_la-hacks.lo libigraph_la-triangles.lo \
+	libigraph_la-glet.lo libigraph_la-maximal_cliques.lo \
+	libigraph_la-sbm.lo libigraph_la-sir.lo libigraph_la-prpack.lo
+am__objects_7 =
+am_libigraph_la_OBJECTS = $(am__objects_6) $(am__objects_7)
+libigraph_la_OBJECTS = $(am_libigraph_la_OBJECTS)
+libigraph_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libigraph_la_CXXFLAGS) \
+	$(CXXFLAGS) $(libigraph_la_LDFLAGS) $(LDFLAGS) -o $@
+liblapack_la_LIBADD =
+am__liblapack_la_SOURCES_DIST = f2c.h lapack/dgeev.c lapack/dgebak.c \
+	lapack/xerbla.c lapack/dgebal.c lapack/disnan.c \
+	lapack/dlaisnan.c lapack/dgehrd.c lapack/dgehd2.c \
+	lapack/dlarf.c lapack/iladlc.c lapack/iladlr.c lapack/dlarfg.c \
+	lapack/dlapy2.c lapack/dlahr2.c lapack/dlacpy.c \
+	lapack/dlarfb.c lapack/ilaenv.c lapack/ieeeck.c \
+	lapack/iparmq.c lapack/dhseqr.c lapack/dlahqr.c \
+	lapack/dlabad.c lapack/dlanv2.c lapack/dlaqr0.c \
+	lapack/dlaqr3.c lapack/dlaqr4.c lapack/dlaqr2.c \
+	lapack/dlaset.c lapack/dormhr.c lapack/dormqr.c \
+	lapack/dlarft.c lapack/dorm2r.c lapack/dtrexc.c \
+	lapack/dlaexc.c lapack/dlange.c lapack/dlassq.c \
+	lapack/dlarfx.c lapack/dlartg.c lapack/dlasy2.c \
+	lapack/dlaqr5.c lapack/dlaqr1.c lapack/dlascl.c \
+	lapack/dorghr.c lapack/dorgqr.c lapack/dorg2r.c \
+	lapack/dtrevc.c lapack/dlaln2.c lapack/dladiv.c \
+	lapack/dsyevr.c lapack/dlansy.c lapack/dormtr.c \
+	lapack/dormql.c lapack/dorm2l.c lapack/dstebz.c \
+	lapack/dlaebz.c lapack/dstein.c lapack/dlagtf.c \
+	lapack/dlagts.c lapack/dlarnv.c lapack/dlaruv.c \
+	lapack/dstemr.c lapack/dlae2.c lapack/dlaev2.c lapack/dlanst.c \
+	lapack/dlarrc.c lapack/dlarre.c lapack/dlarra.c \
+	lapack/dlarrb.c lapack/dlaneg.c lapack/dlarrd.c \
+	lapack/dlarrk.c lapack/dlasq2.c lapack/dlasq3.c \
+	lapack/dlasq4.c lapack/dlasq5.c lapack/dlasq6.c \
+	lapack/dlasrt.c lapack/dlarrj.c lapack/dlarrr.c \
+	lapack/dlarrv.c lapack/dlar1v.c lapack/dlarrf.c \
+	lapack/dsterf.c lapack/dsytrd.c lapack/dlatrd.c \
+	lapack/dsytd2.c lapack/dlanhs.c lapack/dgeqr2.c \
+	lapack/dtrsen.c lapack/dlacn2.c lapack/dtrsyl.c lapack/dlasr.c \
+	lapack/dsteqr.c lapack/dgeevx.c lapack/dtrsna.c \
+	lapack/dlaqtr.c lapack/dgetrf.c lapack/dgetf2.c \
+	lapack/dlaswp.c lapack/dgetrs.c lapack/dgesv.c \
+	lapack/len_trim.c
+am__objects_8 = lapack/liblapack_la-dgeev.lo \
+	lapack/liblapack_la-dgebak.lo lapack/liblapack_la-xerbla.lo \
+	lapack/liblapack_la-dgebal.lo lapack/liblapack_la-disnan.lo \
+	lapack/liblapack_la-dlaisnan.lo lapack/liblapack_la-dgehrd.lo \
+	lapack/liblapack_la-dgehd2.lo lapack/liblapack_la-dlarf.lo \
+	lapack/liblapack_la-iladlc.lo lapack/liblapack_la-iladlr.lo \
+	lapack/liblapack_la-dlarfg.lo lapack/liblapack_la-dlapy2.lo \
+	lapack/liblapack_la-dlahr2.lo lapack/liblapack_la-dlacpy.lo \
+	lapack/liblapack_la-dlarfb.lo lapack/liblapack_la-ilaenv.lo \
+	lapack/liblapack_la-ieeeck.lo lapack/liblapack_la-iparmq.lo \
+	lapack/liblapack_la-dhseqr.lo lapack/liblapack_la-dlahqr.lo \
+	lapack/liblapack_la-dlabad.lo lapack/liblapack_la-dlanv2.lo \
+	lapack/liblapack_la-dlaqr0.lo lapack/liblapack_la-dlaqr3.lo \
+	lapack/liblapack_la-dlaqr4.lo lapack/liblapack_la-dlaqr2.lo \
+	lapack/liblapack_la-dlaset.lo lapack/liblapack_la-dormhr.lo \
+	lapack/liblapack_la-dormqr.lo lapack/liblapack_la-dlarft.lo \
+	lapack/liblapack_la-dorm2r.lo lapack/liblapack_la-dtrexc.lo \
+	lapack/liblapack_la-dlaexc.lo lapack/liblapack_la-dlange.lo \
+	lapack/liblapack_la-dlassq.lo lapack/liblapack_la-dlarfx.lo \
+	lapack/liblapack_la-dlartg.lo lapack/liblapack_la-dlasy2.lo \
+	lapack/liblapack_la-dlaqr5.lo lapack/liblapack_la-dlaqr1.lo \
+	lapack/liblapack_la-dlascl.lo lapack/liblapack_la-dorghr.lo \
+	lapack/liblapack_la-dorgqr.lo lapack/liblapack_la-dorg2r.lo \
+	lapack/liblapack_la-dtrevc.lo lapack/liblapack_la-dlaln2.lo \
+	lapack/liblapack_la-dladiv.lo lapack/liblapack_la-dsyevr.lo \
+	lapack/liblapack_la-dlansy.lo lapack/liblapack_la-dormtr.lo \
+	lapack/liblapack_la-dormql.lo lapack/liblapack_la-dorm2l.lo \
+	lapack/liblapack_la-dstebz.lo lapack/liblapack_la-dlaebz.lo \
+	lapack/liblapack_la-dstein.lo lapack/liblapack_la-dlagtf.lo \
+	lapack/liblapack_la-dlagts.lo lapack/liblapack_la-dlarnv.lo \
+	lapack/liblapack_la-dlaruv.lo lapack/liblapack_la-dstemr.lo \
+	lapack/liblapack_la-dlae2.lo lapack/liblapack_la-dlaev2.lo \
+	lapack/liblapack_la-dlanst.lo lapack/liblapack_la-dlarrc.lo \
+	lapack/liblapack_la-dlarre.lo lapack/liblapack_la-dlarra.lo \
+	lapack/liblapack_la-dlarrb.lo lapack/liblapack_la-dlaneg.lo \
+	lapack/liblapack_la-dlarrd.lo lapack/liblapack_la-dlarrk.lo \
+	lapack/liblapack_la-dlasq2.lo lapack/liblapack_la-dlasq3.lo \
+	lapack/liblapack_la-dlasq4.lo lapack/liblapack_la-dlasq5.lo \
+	lapack/liblapack_la-dlasq6.lo lapack/liblapack_la-dlasrt.lo \
+	lapack/liblapack_la-dlarrj.lo lapack/liblapack_la-dlarrr.lo \
+	lapack/liblapack_la-dlarrv.lo lapack/liblapack_la-dlar1v.lo \
+	lapack/liblapack_la-dlarrf.lo lapack/liblapack_la-dsterf.lo \
+	lapack/liblapack_la-dsytrd.lo lapack/liblapack_la-dlatrd.lo \
+	lapack/liblapack_la-dsytd2.lo lapack/liblapack_la-dlanhs.lo \
+	lapack/liblapack_la-dgeqr2.lo lapack/liblapack_la-dtrsen.lo \
+	lapack/liblapack_la-dlacn2.lo lapack/liblapack_la-dtrsyl.lo \
+	lapack/liblapack_la-dlasr.lo lapack/liblapack_la-dsteqr.lo \
+	lapack/liblapack_la-dgeevx.lo lapack/liblapack_la-dtrsna.lo \
+	lapack/liblapack_la-dlaqtr.lo lapack/liblapack_la-dgetrf.lo \
+	lapack/liblapack_la-dgetf2.lo lapack/liblapack_la-dlaswp.lo \
+	lapack/liblapack_la-dgetrs.lo lapack/liblapack_la-dgesv.lo \
+	lapack/liblapack_la-len_trim.lo
+ at INTERNAL_LAPACK_TRUE@am_liblapack_la_OBJECTS = $(am__objects_8)
+liblapack_la_OBJECTS = $(am_liblapack_la_OBJECTS)
+liblapack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(liblapack_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+ at INTERNAL_LAPACK_TRUE@am_liblapack_la_rpath =
+libplfit_la_LIBADD =
+am__objects_9 = plfit/error.lo plfit/gss.lo plfit/kolmogorov.lo \
+	plfit/lbfgs.lo plfit/options.lo plfit/plfit.lo plfit/zeta.lo
+am_libplfit_la_OBJECTS = $(am__objects_9)
+libplfit_la_OBJECTS = $(am_libplfit_la_OBJECTS)
+libprpack_la_LIBADD =
+am__objects_10 = prpack/libprpack_la-prpack_base_graph.lo \
+	prpack/libprpack_la-prpack_igraph_graph.lo \
+	prpack/libprpack_la-prpack_preprocessed_ge_graph.lo \
+	prpack/libprpack_la-prpack_preprocessed_gs_graph.lo \
+	prpack/libprpack_la-prpack_preprocessed_scc_graph.lo \
+	prpack/libprpack_la-prpack_preprocessed_schur_graph.lo \
+	prpack/libprpack_la-prpack_result.lo \
+	prpack/libprpack_la-prpack_solver.lo \
+	prpack/libprpack_la-prpack_utils.lo
+am_libprpack_la_OBJECTS = $(am__objects_10)
+libprpack_la_OBJECTS = $(am_libprpack_la_OBJECTS)
+AM_V_P = $(am__v_P_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I. at am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_ at AM_V@)
+am__v_CC_ = $(am__v_CC_ at AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_ at AM_V@)
+am__v_CXX_ = $(am__v_CXX_ at AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_ at AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_ at AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+AM_V_LEX = $(am__v_LEX_ at AM_V@)
+am__v_LEX_ = $(am__v_LEX_ at AM_DEFAULT_V@)
+am__v_LEX_0 = @echo "  LEX     " $@;
+am__v_LEX_1 = 
+YLWRAP = $(top_srcdir)/ylwrap
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+		   -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_ at AM_V@)
+am__v_YACC_ = $(am__v_YACC_ at AM_DEFAULT_V@)
+am__v_YACC_0 = @echo "  YACC    " $@;
+am__v_YACC_1 = 
+DIST_SOURCES = $(am__libarpack_la_SOURCES_DIST) \
+	$(am__libblas_la_SOURCES_DIST) \
+	$(am__libdlamch_la_SOURCES_DIST) $(am__libf2c_la_SOURCES_DIST) \
+	$(am__libglpk_la_SOURCES_DIST) $(libigraph_la_SOURCES) \
+	$(am__liblapack_la_SOURCES_DIST) $(libplfit_la_SOURCES) \
+	$(libprpack_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+HEADERS = $(include_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOM4TE = @AUTOM4TE@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLOATSTORE = @FLOATSTORE@
+GREP = @GREP@
+HAVE_TLS = @HAVE_TLS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_LIBS_PRIVATE = @PKGCONFIG_LIBS_PRIVATE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WERROR_CFLAGS = @WERROR_CFLAGS@
+XML2CONFIG = @XML2CONFIG@
+XML2_CFLAGS = @XML2_CFLAGS@
+XML2_LIBS = @XML2_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = $(prefix)/include/igraph
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# This is to make sure that the headers get built before they are included
+BUILT_SOURCES = foreign-ncol-parser.h foreign-lgl-parser.h \
+	foreign-dl-parser.h foreign-gml-parser.h \
+	foreign-pajek-parser.h $(am__append_1)
+
+# This is needed to ensure that yacc (or bison) builds the header files
+# Unfortunately this is not the default behaviour in MinGW/MSYS
+AM_YFLAGS = -d
+lib_LTLIBRARIES = libigraph.la
+BLAS = lapack/dscal.c lapack/dswap.c lapack/lsame.c lapack/idamax.c lapack/daxpy.c lapack/dgemv.c lapack/dger.c lapack/dnrm2.c lapack/dgemm.c lapack/dcopy.c lapack/dtrmm.c lapack/dtrmv.c lapack/drot.c lapack/ddot.c lapack/dasum.c lapack/dsymv.c lapack/dsyr2k.c lapack/dsyr2.c lapack/dtrsm.c 
+LAPACK = lapack/dgeev.c lapack/dgebak.c lapack/xerbla.c \
+	lapack/dgebal.c lapack/disnan.c lapack/dlaisnan.c \
+	lapack/dgehrd.c lapack/dgehd2.c lapack/dlarf.c lapack/iladlc.c \
+	lapack/iladlr.c lapack/dlarfg.c lapack/dlapy2.c \
+	lapack/dlahr2.c lapack/dlacpy.c lapack/dlarfb.c \
+	lapack/ilaenv.c lapack/ieeeck.c lapack/iparmq.c \
+	lapack/dhseqr.c lapack/dlahqr.c lapack/dlabad.c \
+	lapack/dlanv2.c lapack/dlaqr0.c lapack/dlaqr3.c \
+	lapack/dlaqr4.c lapack/dlaqr2.c lapack/dlaset.c \
+	lapack/dormhr.c lapack/dormqr.c lapack/dlarft.c \
+	lapack/dorm2r.c lapack/dtrexc.c lapack/dlaexc.c \
+	lapack/dlange.c lapack/dlassq.c lapack/dlarfx.c \
+	lapack/dlartg.c lapack/dlasy2.c lapack/dlaqr5.c \
+	lapack/dlaqr1.c lapack/dlascl.c lapack/dorghr.c \
+	lapack/dorgqr.c lapack/dorg2r.c lapack/dtrevc.c \
+	lapack/dlaln2.c lapack/dladiv.c lapack/dsyevr.c \
+	lapack/dlansy.c lapack/dormtr.c lapack/dormql.c \
+	lapack/dorm2l.c lapack/dstebz.c lapack/dlaebz.c \
+	lapack/dstein.c lapack/dlagtf.c lapack/dlagts.c \
+	lapack/dlarnv.c lapack/dlaruv.c lapack/dstemr.c lapack/dlae2.c \
+	lapack/dlaev2.c lapack/dlanst.c lapack/dlarrc.c \
+	lapack/dlarre.c lapack/dlarra.c lapack/dlarrb.c \
+	lapack/dlaneg.c lapack/dlarrd.c lapack/dlarrk.c \
+	lapack/dlasq2.c lapack/dlasq3.c lapack/dlasq4.c \
+	lapack/dlasq5.c lapack/dlasq6.c lapack/dlasrt.c \
+	lapack/dlarrj.c lapack/dlarrr.c lapack/dlarrv.c \
+	lapack/dlar1v.c lapack/dlarrf.c lapack/dsterf.c \
+	lapack/dsytrd.c lapack/dlatrd.c lapack/dsytd2.c \
+	lapack/dlanhs.c lapack/dgeqr2.c lapack/dtrsen.c \
+	lapack/dlacn2.c lapack/dtrsyl.c lapack/dlasr.c lapack/dsteqr.c \
+	lapack/dgeevx.c lapack/dtrsna.c lapack/dlaqtr.c \
+	lapack/dgetrf.c lapack/dgetf2.c lapack/dlaswp.c \
+	lapack/dgetrs.c lapack/dgesv.c lapack/len_trim.c
+ARPACK = lapack/dnaupd.c lapack/dnaup2.c lapack/dgetv0.c lapack/dvout.c lapack/second.c lapack/dmout.c lapack/dnaitr.c lapack/ivout.c lapack/dnapps.c lapack/dnconv.c lapack/dneigh.c lapack/dlaqrb.c lapack/dngets.c lapack/dsortc.c lapack/dstatn.c lapack/dneupd.c lapack/dsaupd.c lapack/dsaup2.c lapack/dsaitr.c lapack/dsapps.c lapack/dsconv.c lapack/dseigt.c lapack/dstqrb.c lapack/dsgets.c lapack/dsortr.c lapack/dstats.c lapack/dseupd.c lapack/dsesrt.c 
+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
+
+F2C = f2c/abort_.c	  f2c/dolio.c	    f2c/r_sin.c\
+	f2c/dummy.c	  f2c/dtime_.c	    f2c/iio.c	      f2c/r_sinh.c\
+	f2c/backspac.c	  f2c/due.c	    f2c/ilnw.c	      f2c/r_sqrt.c\
+	f2c/c_abs.c	  f2c/ef1asc_.c	    f2c/inquire.c     f2c/r_tan.c\
+	f2c/c_cos.c	  f2c/ef1cmc_.c	    f2c/l_ge.c	      f2c/r_tanh.c\
+	f2c/c_div.c	  f2c/endfile.c	    f2c/l_gt.c	      f2c/rdfmt.c\
+	f2c/c_exp.c	  f2c/erf_.c	    f2c/l_le.c	      f2c/rewind.c\
+	f2c/c_log.c	  f2c/erfc_.c	    f2c/l_lt.c	      f2c/rsfe.c\
+	f2c/c_sin.c	  f2c/err.c	    f2c/lbitbits.c    f2c/rsli.c\
+	f2c/c_sqrt.c	  f2c/etime_.c	    f2c/lbitshft.c    f2c/rsne.c\
+	f2c/cabs.c	  f2c/exit_.c	    f2c/lread.c	      f2c/s_cat.c\
+	f2c/close.c	  f2c/f77_aloc.c    f2c/lwrite.c      f2c/s_cmp.c\
+	f2c/ctype.c	  f2c/f77vers.c	    f2c/s_copy.c\
+	f2c/d_abs.c	  f2c/fmt.c	    f2c/open.c	      f2c/s_paus.c\
+	f2c/d_acos.c	  f2c/fmtlib.c	    f2c/pow_ci.c      f2c/s_rnge.c\
+	f2c/d_asin.c	  f2c/ftell_.c	    f2c/pow_dd.c      f2c/s_stop.c\
+	f2c/d_atan.c	  f2c/pow_di.c      f2c/sfe.c\
+	f2c/d_atn2.c	  f2c/getenv_.c	    f2c/pow_hh.c      f2c/sig_die.c\
+	f2c/d_cnjg.c	  f2c/h_abs.c	    f2c/pow_ii.c      f2c/signal_.c\
+	f2c/d_cos.c	  f2c/h_dim.c	    f2c/pow_ri.c      f2c/signbit.c\
+	f2c/d_cosh.c	  f2c/h_dnnt.c	    f2c/pow_zi.c      f2c/sue.c\
+	f2c/d_dim.c	  f2c/h_indx.c	    f2c/pow_zz.c      f2c/system_.c\
+	f2c/d_exp.c	  f2c/h_len.c	    f2c/r_abs.c	      f2c/typesize.c\
+	f2c/d_imag.c	  f2c/h_mod.c	    f2c/r_acos.c      f2c/uio.c\
+	f2c/d_int.c	  f2c/h_nint.c	    f2c/r_asin.c      f2c/uninit.c\
+	f2c/d_lg10.c	  f2c/h_sign.c	    f2c/r_atan.c      f2c/util.c\
+	f2c/d_log.c	  f2c/hl_ge.c	    f2c/r_atn2.c      f2c/wref.c\
+	f2c/d_mod.c	  f2c/hl_gt.c	    f2c/r_cnjg.c      f2c/wrtfmt.c\
+	f2c/d_nint.c	  f2c/hl_le.c	    f2c/r_cos.c	      f2c/wsfe.c\
+	f2c/d_prod.c	  f2c/hl_lt.c	    f2c/r_cosh.c      f2c/wsle.c\
+	f2c/d_sign.c	  f2c/i77vers.c	    f2c/r_dim.c	      f2c/wsne.c\
+	f2c/d_sin.c	  f2c/i_abs.c	    f2c/r_exp.c	      f2c/xwsne.c\
+	f2c/d_sinh.c	  f2c/i_dim.c	    f2c/r_imag.c      f2c/z_abs.c\
+	f2c/d_sqrt.c	  f2c/i_dnnt.c	    f2c/r_int.c	      f2c/z_cos.c\
+	f2c/d_tan.c	  f2c/i_indx.c	    f2c/r_lg10.c      f2c/z_div.c\
+	f2c/d_tanh.c	  f2c/i_len.c	    f2c/r_log.c	      f2c/z_exp.c\
+	f2c/derf_.c	  f2c/i_mod.c	    f2c/r_mod.c	      f2c/z_log.c\
+	f2c/derfc_.c	  f2c/i_nint.c	    f2c/r_nint.c      f2c/z_sin.c\
+	f2c/dfe.c	  f2c/i_sign.c	    f2c/r_sign.c      f2c/z_sqrt.c
+
+
+# We also have to pack f2c/arithchk.c in the distribution in case the
+# user wants to compile it using the internal f2c. f2c/arithchk.c is
+# not linked into libf2c.la (hence we cannot add it to libf2c_la_SOURCES)
+# but is needed to build f2c/arith.h
+EXTRA_DIST = f2c/arithchk.c
+ at INTERNAL_F2C_TRUE@libf2c_la_SOURCES = f2c.h f2c/fio.h f2c/fmt.h f2c/sysdep1.h\
+ at INTERNAL_F2C_TRUE@					  f2c/sysdep1.h0 f2c/lio.h f2c/fp.h f2c/signal1.h\
+ at INTERNAL_F2C_TRUE@					  f2c/signal1.h0 $(F2C)
+
+ at INTERNAL_F2C_TRUE@libf2c_la_CFLAGS = -DSkip_f2c_Undefs -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+ at INTERNAL_F2C_TRUE@F2C_LIB = libf2c.la
+ at INTERNAL_BLAS_TRUE@libblas_la_SOURCES = f2c.h $(BLAS)
+ at INTERNAL_BLAS_TRUE@libblas_la_CFLAGS = -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+ at INTERNAL_BLAS_TRUE@BLAS_LIB = libblas.la
+ at INTERNAL_LAPACK_TRUE@liblapack_la_SOURCES = f2c.h $(LAPACK)
+ at INTERNAL_LAPACK_TRUE@liblapack_la_CFLAGS = -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+ at INTERNAL_LAPACK_TRUE@libdlamch_la_SOURCES = lapack/dlamch.c
+ at INTERNAL_LAPACK_TRUE@libdlamch_la_CFLAGS = $(FLOATSTORE) -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+ at INTERNAL_LAPACK_TRUE@LAPACK_LIB = liblapack.la libdlamch.la
+ at INTERNAL_ARPACK_TRUE@libarpack_la_SOURCES = f2c.h $(ARPACK)
+ at INTERNAL_ARPACK_TRUE@libarpack_la_CFLAGS = -I. -I$(top_srcdir)/include -I$(top_builddir)/include $(WARNING_CFLAGS)
+ at INTERNAL_ARPACK_TRUE@ARPACK_LIB = libarpack.la
+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/glpk/glpapi17.c \
+	../optional/glpk/glpapi18.c ../optional/glpk/glpapi19.c \
+	../optional/glpk/glpavl.c ../optional/glpk/glpavl.h \
+	../optional/glpk/glpbfd.c ../optional/glpk/glpbfd.h \
+	../optional/glpk/glpbfx.c ../optional/glpk/glpbfx.h \
+	../optional/glpk/glpcpx.c ../optional/glpk/glpdmp.c \
+	../optional/glpk/glpdmp.h ../optional/glpk/glpdmx.c \
+	../optional/glpk/glpenv.h ../optional/glpk/glpenv01.c \
+	../optional/glpk/glpenv02.c ../optional/glpk/glpenv03.c \
+	../optional/glpk/glpenv04.c ../optional/glpk/glpenv05.c \
+	../optional/glpk/glpenv06.c ../optional/glpk/glpenv07.c \
+	../optional/glpk/glpenv08.c ../optional/glpk/glpfhv.c \
+	../optional/glpk/glpfhv.h ../optional/glpk/glpgmp.c \
+	../optional/glpk/glpgmp.h ../optional/glpk/glphbm.c \
+	../optional/glpk/glphbm.h ../optional/glpk/glpini01.c \
+	../optional/glpk/glpini02.c ../optional/glpk/glpios.h \
+	../optional/glpk/glpios01.c ../optional/glpk/glpios02.c \
+	../optional/glpk/glpios03.c ../optional/glpk/glpios04.c \
+	../optional/glpk/glpios05.c ../optional/glpk/glpios06.c \
+	../optional/glpk/glpios07.c ../optional/glpk/glpios08.c \
+	../optional/glpk/glpios09.c ../optional/glpk/glpios10.c \
+	../optional/glpk/glpios11.c ../optional/glpk/glpios12.c \
+	../optional/glpk/glpipm.c ../optional/glpk/glpipm.h \
+	../optional/glpk/glpk.h ../optional/glpk/glplib.h \
+	../optional/glpk/glplib01.c ../optional/glpk/glplib02.c \
+	../optional/glpk/glplib03.c ../optional/glpk/glplpf.c \
+	../optional/glpk/glplpf.h ../optional/glpk/glplpx01.c \
+	../optional/glpk/glplpx02.c ../optional/glpk/glplpx03.c \
+	../optional/glpk/glpluf.c ../optional/glpk/glpluf.h \
+	../optional/glpk/glplux.c ../optional/glpk/glplux.h \
+	../optional/glpk/glpmat.c ../optional/glpk/glpmat.h \
+	../optional/glpk/glpmpl.h ../optional/glpk/glpmpl01.c \
+	../optional/glpk/glpmpl02.c ../optional/glpk/glpmpl03.c \
+	../optional/glpk/glpmpl04.c ../optional/glpk/glpmpl05.c \
+	../optional/glpk/glpmpl06.c ../optional/glpk/glpmps.c \
+	../optional/glpk/glpnet.h ../optional/glpk/glpnet01.c \
+	../optional/glpk/glpnet02.c ../optional/glpk/glpnet03.c \
+	../optional/glpk/glpnet04.c ../optional/glpk/glpnet05.c \
+	../optional/glpk/glpnet06.c ../optional/glpk/glpnet07.c \
+	../optional/glpk/glpnet08.c ../optional/glpk/glpnet09.c \
+	../optional/glpk/glpnpp.h ../optional/glpk/glpnpp01.c \
+	../optional/glpk/glpnpp02.c ../optional/glpk/glpnpp03.c \
+	../optional/glpk/glpnpp04.c ../optional/glpk/glpnpp05.c \
+	../optional/glpk/glpqmd.c ../optional/glpk/glpqmd.h \
+	../optional/glpk/glprgr.c ../optional/glpk/glprgr.h \
+	../optional/glpk/glprng.h ../optional/glpk/glprng01.c \
+	../optional/glpk/glprng02.c ../optional/glpk/glpscf.c \
+	../optional/glpk/glpscf.h ../optional/glpk/glpscl.c \
+	../optional/glpk/glpsdf.c ../optional/glpk/glpspm.c \
+	../optional/glpk/glpspm.h ../optional/glpk/glpspx.h \
+	../optional/glpk/glpspx01.c ../optional/glpk/glpspx02.c \
+	../optional/glpk/glpsql.c ../optional/glpk/glpsql.h \
+	../optional/glpk/glpssx.h ../optional/glpk/glpssx01.c \
+	../optional/glpk/glpssx02.c ../optional/glpk/glpstd.h \
+	../optional/glpk/glptsp.c ../optional/glpk/glptsp.h \
+	../optional/glpk/amd/amd.h ../optional/glpk/amd/amd_1.c \
+	../optional/glpk/amd/amd_2.c ../optional/glpk/amd/amd_aat.c \
+	../optional/glpk/amd/amd_control.c \
+	../optional/glpk/amd/amd_defaults.c \
+	../optional/glpk/amd/amd_dump.c \
+	../optional/glpk/amd/amd_info.c \
+	../optional/glpk/amd/amd_internal.h \
+	../optional/glpk/amd/amd_order.c \
+	../optional/glpk/amd/amd_post_tree.c \
+	../optional/glpk/amd/amd_postorder.c \
+	../optional/glpk/amd/amd_preprocess.c \
+	../optional/glpk/amd/amd_valid.c \
+	../optional/glpk/colamd/colamd.c \
+	../optional/glpk/colamd/colamd.h
+ at INTERNAL_GLPK_TRUE@libglpk_la_SOURCES = $(GLPK)
+ at INTERNAL_GLPK_TRUE@libglpk_la_CFLAGS = -I$(top_srcdir)/optional/glpk
+ at INTERNAL_GLPK_TRUE@libglpk_la_CPPFLAGS = -I$(top_srcdir)/include
+ at INTERNAL_GLPK_TRUE@GLPK_LIB = libglpk.la
+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
+
+libprpack_la_SOURCES = $(PRPACK)
+libprpack_la_CFLAGS = -I$(top_srcdir)/include -DPRPACK_IGRAPH_SUPPORT
+libprpack_la_CPPFLAGS = -I$(top_srcdir)/include -DPRPACK_IGRAPH_SUPPORT
+PRPACK_LIB = libprpack.la
+libplfit_la_SOURCES = $(PLFIT)
+PLFIT_LIB = libplfit.la
+noinst_LTLIBRARIES = $(F2C_LIB) $(BLAS_LIB) $(LAPACK_LIB) $(ARPACK_LIB) \
+					 $(GLPK_LIB) $(PLFIT_LIB) $(PRPACK_LIB)
+
+CS = cs/cs_add.c       cs/cs_happly.c    cs/cs_pvec.c         \
+	cs/cs_amd.c       cs/cs_house.c     cs/cs_qr.c        \
+	cs/cs_chol.c      cs/cs_ipvec.c     cs/cs_qrsol.c     \
+	cs/cs_cholsol.c   cs/cs_leaf.c      cs/cs_randperm.c  \
+	cs/cs_compress.c  cs/cs_load.c      cs/cs_reach.c     \
+	cs/cs_counts.c    cs/cs_lsolve.c    cs/cs_scatter.c   \
+	cs/cs_cumsum.c    cs/cs_ltsolve.c   cs/cs_scc.c       \
+	cs/cs_dfs.c       cs/cs_lu.c        cs/cs_schol.c     \
+	cs/cs_dmperm.c    cs/cs_lusol.c     cs/cs_spsolve.c   \
+	cs/cs_droptol.c   cs/cs_malloc.c    cs/cs_sqr.c       \
+	cs/cs_dropzeros.c cs/cs_maxtrans.c  cs/cs_symperm.c   \
+	cs/cs_dupl.c      cs/cs_multiply.c  cs/cs_tdfs.c      \
+	cs/cs_entry.c     cs/cs_norm.c      cs/cs_transpose.c \
+	cs/cs_ereach.c    cs/cs_permute.c   cs/cs_updown.c    \
+	cs/cs_etree.c     cs/cs_pinv.c      cs/cs_usolve.c    \
+	cs/cs_fkeep.c     cs/cs_post.c      cs/cs_util.c      \
+	cs/cs_gaxpy.c     cs/cs_print.c     cs/cs_utsolve.c   \
+	cs/cs.h	    cs/UFconfig.h
+
+HEADERS_PRIVATE = atlas-edges.h \
+		bliss_bignum.hh		bliss_defs.hh \
+		bliss_eqrefhash.hh	bliss_graph.hh \
+		bliss_heap.hh		bliss_kqueue.hh \
+		bliss_kstack.hh		bliss_orbit.hh \
+		bliss_partition.hh	bliss_timer.hh \
+		bliss_utils.hh \
+		NetDataTypes.h		NetRoutines.h \
+		pottsmodel_2.h \
+		igraph_gml_tree.h \
+		walktrap_graph.h	walktrap_communities.h \
+		walktrap_heap.h \
+		infomap_Greedy.h infomap_Node.h infomap_Greedy.h infomap_FlowGraph.h \
+		igraph_math.h \
+		drl_layout.h drl_parse.h drl_graph.h \
+		drl_graph_3d.h		drl_layout_3d.h \
+		drl_Node.h	drl_Node_3d.h \
+		DensityGrid.h	DensityGrid_3d.h \
+		igraph_flow_internal.h \
+		vector.pmt matrix.pmt stack.pmt dqueue.pmt heap.pmt array.pmt \
+		igraph_types_internal.h \
+		foreign-dl-header.h bignum.h bigint.h \
+		gengraph_box_list.h gengraph_definitions.h \
+		gengraph_degree_sequence.h gengraph_graph_molloy_hash.h \
+		gengraph_graph_molloy_optimized.h \
+		gengraph_hash.h gengraph_header.h gengraph_powerlaw.h \
+		gengraph_qsort.h gengraph_random.h gengraph_vertex_cover.h \
+		igraph_blas_internal.h igraph_arpack_internal.h \
+		igraph_lapack_internal.h igraph_glpk_support.h \
+		igraph_marked_queue.h igraph_estack.h \
+		hrg_dendro.h hrg_graph.h hrg_rbtree.h hrg_splittree_eq.h \
+		hrg_graph_simp.h foreign-gml-header.h \
+		foreign-ncol-header.h foreign-lgl-header.h \
+		foreign-pajek-header.h igraph_interrupt_internal.h \
+		scg_headers.h igraph_hacks_internal.h triangles_template.h \
+		triangles_template1.h maximal_cliques_template.h prpack.h
+
+HEADERS_PUBLIC = ../include/igraph.h 		../include/igraph_memory.h    \
+		../include/igraph_random.h 	../include/igraph_types.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_arpack.h 	\
+		../include/igraph_attributes.h 	../include/igraph_error.h     \
+		../include/igraph_pmt.h 	../include/igraph_pmt_off.h   \
+		../include/igraph_adjlist.h	../include/igraph_iterators.h \
+		../include/igraph_bipartite.h	../include/igraph_layout.h    \
+		../include/igraph_centrality.h	../include/igraph_motifs.h    \
+		../include/igraph_cliques.h	../include/igraph_neighborhood.h \
+		../include/igraph_cocitation.h	../include/igraph_nongraph.h  \
+		../include/igraph_community.h	../include/igraph_operators.h \
+		../include/igraph_components.h	../include/igraph_paths.h     \
+		../include/igraph_constructors.h ../include/igraph_progress.h \
+		../include/igraph_conversion.h	../include/igraph_revolver.h  \
+		../include/igraph_datatype.h	../include/igraph_structural.h\
+		../include/igraph_flow.h	../include/igraph_topology.h  \
+		../include/igraph_foreign.h	../include/igraph_transitivity.h \
+		../include/igraph_games.h	../include/igraph_visitor.h   \
+		../include/igraph_interface.h	../include/igraph_constants.h \
+		../include/igraph_vector_pmt.h	../include/igraph_matrix_pmt.h\
+		../include/igraph_array_pmt.h	../include/igraph_dqueue_pmt.h\
+		../include/igraph_stack_pmt.h	../include/igraph_heap_pmt.h  \
+		../include/igraph_vector_ptr.h	../include/igraph_spmatrix.h  \
+		../include/igraph_strvector.h	../include/igraph_psumtree.h  \
+		../include/igraph_sparsemat.h   ../include/igraph_mixing.h    \
+		../include/igraph_version.h     ../include/igraph_blas.h      \
+		../include/igraph_separators.h  ../include/igraph_cohesive_blocks.h \
+		../include/igraph_lapack.h	../include/igraph_complex.h   \
+		../include/igraph_eigen.h	../include/igraph_statusbar.h \
+		../include/igraph_hrg.h         ../include/igraph_microscopic_update.h \
+		../include/igraph_interrupt.h   ../include/igraph_threading.h \
+		../include/igraph_scg.h		../include/igraph_qsort.h \
+		../include/igraph_matching.h	../include/igraph_graphlets.h \
+		../include/igraph_vector_type.h ../include/igraph_epidemics.h
+
+SOURCES = basic_query.c games.c cocitation.c iterators.c \
+			     structural_properties.c components.c layout.c \
+			     structure_generators.c conversion.c \
+			     type_indexededgelist.c spanning_trees.c \
+			     igraph_error.c interrupt.c other.c foreign.c random.c \
+			     attributes.c \
+			     foreign-ncol-parser.y foreign-ncol-lexer.l \
+			     foreign-lgl-parser.y foreign-lgl-lexer.l \
+			     foreign-pajek-parser.y foreign-pajek-lexer.l \
+			     foreign-gml-parser.y foreign-gml-lexer.l \
+			     dqueue.c heap.c igraph_heap.c igraph_stack.c \
+			     igraph_strvector.c igraph_trie.c matrix.c \
+			     vector.c vector_ptr.c memory.c adjlist.c \
+			     visitors.c igraph_grid.c atlas.c topology.c \
+			     motifs.c progress.c operators.c \
+			     igraph_psumtree.c array.c igraph_hashtable.c \
+			     foreign-graphml.c flow.c igraph_buckets.c \
+			     NetDataTypes.cpp NetRoutines.cpp clustertool.cpp \
+			     pottsmodel_2.cpp spectral_properties.c cores.c \
+			     igraph_set.c cliques.c revolver_cit.c revolver_grow.c\
+			     walktrap.cpp walktrap_heap.cpp \
+			     walktrap_graph.cpp walktrap_communities.cpp \
+			     infomap.cc infomap_Greedy.cc infomap_Node.cc infomap_FlowGraph.cc \
+			     spmatrix.c community.c fast_community.c \
+			     evolver_cit.c gml_tree.c \
+			     bliss_orbit.cc bliss_eqrefhash.cc \
+			     bliss_partition.cc bliss_graph.cc bliss_timer.cc \
+			     bliss_heap.cc bliss_utils.cc bliss.cc \
+			     cattributes.c revolver_ml_cit.c zeroin.c bfgs.c math.c \
+			     forestfire.c microscopic_update.c \
+			     blas.c arpack.c centrality.c drl_layout.cpp drl_parse.cpp \
+			     drl_graph.cpp DensityGrid.cpp \
+			     gengraph_box_list.cpp gengraph_degree_sequence.cpp \
+			     gengraph_graph_molloy_hash.cpp \
+			     gengraph_graph_molloy_optimized.cpp \
+			     gengraph_mr-connected.cpp gengraph_powerlaw.cpp \
+			     gengraph_random.cpp decomposition.c bipartite.c \
+			     drl_layout_3d.cpp drl_graph_3d.cpp \
+			     DensityGrid_3d.cpp \
+			     foreign-dl-parser.y foreign-dl-lexer.l \
+			     $(CS) sparsemat.c mixing.c bigint.c bignum.c \
+			     version.c optimal_modularity.c \
+			     igraph_fixed_vectorlist.c separators.c \
+			     igraph_marked_queue.c igraph_estack.c st-cuts.c \
+			     cohesive_blocks.c statusbar.c \
+			     lapack.c complex.c eigen.c feedback_arc_set.c \
+			     sugiyama.c glpk_support.c \
+				 igraph_hrg_types.cc igraph_hrg.cc \
+			     distances.c fortran_intrinsics.c matching.c \
+			     scg.c scg_approximate_methods.c scg_exact_scg.c \
+			     scg_kmeans.c scg_utils.c scg_optimal_method.c \
+			     qsort.c qsort_r.c types.c lad.c hacks.c \
+			     triangles.c glet.c maximal_cliques.c sbm.c \
+			     sir.c  prpack.cpp
+
+libigraph_la_SOURCES = $(SOURCES) $(HEADERS_PRIVATE)
+libigraph_la_CFLAGS = -I$(top_srcdir)/include \
+	-I$(top_builddir)/include $(WARNING_CFLAGS) $(am__append_2) \
+	-I$(top_srcdir)/src/prpack -DPRPACK_IGRAPH_SUPPORT
+libigraph_la_CXXFLAGS = -I$(top_srcdir)/include \
+	-I$(top_builddir)/include $(WARNING_CFLAGS) $(am__append_3) \
+	-I$(top_srcdir)/src/prpack -DPRPACK_IGRAPH_SUPPORT
+libigraph_la_LDFLAGS = -no-undefined
+libigraph_la_LIBADD = -lm $(XML2_LIBS) $(F2C_LIB) $(BLAS_LIB) \
+				 $(LAPACK_LIB) $(ARPACK_LIB) $(GLPK_LIB) $(PRPACK_LIB) \
+				 $(PLFIT_LIB)
+
+include_HEADERS = $(HEADERS_PUBLIC)
+MAINTAINERCLEANFILES = Makefile.in foreign-lgl-parser.h foreign-ncol-parser.h
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .cpp .l .lo .o .obj .y
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(srcdir)/lapack/blas.inc $(srcdir)/lapack/lapack.inc $(srcdir)/lapack/arpack.inc $(srcdir)/plfit/plfit.inc $(srcdir)/../optional/glpk/glpk.inc $(srcdir)/prpack/prpack.inc $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+$(srcdir)/lapack/blas.inc $(srcdir)/lapack/lapack.inc $(srcdir)/lapack/arpack.inc $(srcdir)/plfit/plfit.inc $(srcdir)/../optional/glpk/glpk.inc $(srcdir)/prpack/prpack.inc:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+lapack/$(am__dirstamp):
+	@$(MKDIR_P) lapack
+	@: > lapack/$(am__dirstamp)
+lapack/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) lapack/$(DEPDIR)
+	@: > lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dnaupd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dnaup2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dgetv0.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dvout.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-second.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dmout.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dnaitr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-ivout.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dnapps.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dnconv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dneigh.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dlaqrb.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dngets.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsortc.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dstatn.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dneupd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsaupd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsaup2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsaitr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsapps.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsconv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dseigt.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dstqrb.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsgets.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsortr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dstats.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dseupd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libarpack_la-dsesrt.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+
+libarpack.la: $(libarpack_la_OBJECTS) $(libarpack_la_DEPENDENCIES) $(EXTRA_libarpack_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libarpack_la_LINK) $(am_libarpack_la_rpath) $(libarpack_la_OBJECTS) $(libarpack_la_LIBADD) $(LIBS)
+lapack/libblas_la-dscal.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dswap.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-lsame.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-idamax.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-daxpy.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dgemv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dger.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dnrm2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dgemm.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dcopy.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dtrmm.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dtrmv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-drot.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-ddot.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dasum.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dsymv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dsyr2k.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dsyr2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/libblas_la-dtrsm.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+
+libblas.la: $(libblas_la_OBJECTS) $(libblas_la_DEPENDENCIES) $(EXTRA_libblas_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libblas_la_LINK) $(am_libblas_la_rpath) $(libblas_la_OBJECTS) $(libblas_la_LIBADD) $(LIBS)
+lapack/libdlamch_la-dlamch.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+
+libdlamch.la: $(libdlamch_la_OBJECTS) $(libdlamch_la_DEPENDENCIES) $(EXTRA_libdlamch_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libdlamch_la_LINK) $(am_libdlamch_la_rpath) $(libdlamch_la_OBJECTS) $(libdlamch_la_LIBADD) $(LIBS)
+f2c/$(am__dirstamp):
+	@$(MKDIR_P) f2c
+	@: > f2c/$(am__dirstamp)
+f2c/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) f2c/$(DEPDIR)
+	@: > f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-abort_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-dolio.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_sin.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-dummy.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-dtime_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-iio.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_sinh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-backspac.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-due.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-ilnw.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_sqrt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_abs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-ef1asc_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-inquire.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_tan.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_cos.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-ef1cmc_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-l_ge.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_tanh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_div.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-endfile.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-l_gt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-rdfmt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_exp.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-erf_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-l_le.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-rewind.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_log.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-erfc_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-l_lt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-rsfe.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_sin.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-err.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-lbitbits.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-rsli.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-c_sqrt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-etime_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-lbitshft.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-rsne.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-cabs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-exit_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-lread.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-s_cat.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-close.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-f77_aloc.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-lwrite.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-s_cmp.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-ctype.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-f77vers.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-s_copy.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_abs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-fmt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-open.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-s_paus.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_acos.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-fmtlib.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_ci.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-s_rnge.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_asin.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-ftell_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_dd.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-s_stop.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_atan.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_di.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-sfe.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_atn2.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-getenv_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_hh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-sig_die.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_cnjg.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_abs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_ii.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-signal_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_cos.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_dim.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_ri.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-signbit.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_cosh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_dnnt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_zi.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-sue.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_dim.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_indx.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-pow_zz.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-system_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_exp.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_len.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_abs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-typesize.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_imag.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_mod.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_acos.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-uio.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_int.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_nint.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_asin.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-uninit.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_lg10.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-h_sign.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_atan.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-util.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_log.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-hl_ge.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_atn2.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-wref.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_mod.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-hl_gt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_cnjg.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-wrtfmt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_nint.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-hl_le.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_cos.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-wsfe.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_prod.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-hl_lt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_cosh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-wsle.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_sign.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i77vers.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_dim.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-wsne.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_sin.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_abs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_exp.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-xwsne.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_sinh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_dim.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_imag.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_abs.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_sqrt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_dnnt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_int.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_cos.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_tan.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_indx.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_lg10.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_div.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-d_tanh.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_len.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_log.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_exp.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-derf_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_mod.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_mod.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_log.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-derfc_.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_nint.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_nint.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_sin.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-dfe.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-i_sign.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-r_sign.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+f2c/libf2c_la-z_sqrt.lo: f2c/$(am__dirstamp) \
+	f2c/$(DEPDIR)/$(am__dirstamp)
+
+libf2c.la: $(libf2c_la_OBJECTS) $(libf2c_la_DEPENDENCIES) $(EXTRA_libf2c_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libf2c_la_LINK) $(am_libf2c_la_rpath) $(libf2c_la_OBJECTS) $(libf2c_la_LIBADD) $(LIBS)
+../optional/glpk/$(am__dirstamp):
+	@$(MKDIR_P) ../optional/glpk
+	@: > ../optional/glpk/$(am__dirstamp)
+../optional/glpk/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) ../optional/glpk/$(DEPDIR)
+	@: > ../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi04.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi05.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi06.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi07.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi08.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi09.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi10.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi11.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi12.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi13.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi14.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi15.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi16.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi17.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi18.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpapi19.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpavl.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpbfd.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpbfx.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpcpx.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpdmp.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpdmx.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv04.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv05.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv06.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv07.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpenv08.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpfhv.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpgmp.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glphbm.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpini01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpini02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios04.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios05.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios06.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios07.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios08.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios09.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios10.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios11.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpios12.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpipm.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplib01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplib02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplib03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplpf.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplpx01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplpx02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplpx03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpluf.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glplux.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmat.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmpl01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmpl02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmpl03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmpl04.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmpl05.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmpl06.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpmps.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet04.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet05.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet06.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet07.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet08.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnet09.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnpp01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnpp02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnpp03.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnpp04.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpnpp05.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpqmd.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glprgr.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glprng01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glprng02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpscf.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpscl.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpsdf.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpspm.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpspx01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpspx02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpsql.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpssx01.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glpssx02.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/libglpk_la-glptsp.lo:  \
+	../optional/glpk/$(am__dirstamp) \
+	../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/$(am__dirstamp):
+	@$(MKDIR_P) ../optional/glpk/amd
+	@: > ../optional/glpk/amd/$(am__dirstamp)
+../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) ../optional/glpk/amd/$(DEPDIR)
+	@: > ../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_1.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_2.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_aat.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_control.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_defaults.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_dump.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_info.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_order.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_post_tree.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_postorder.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_preprocess.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/amd/libglpk_la-amd_valid.lo:  \
+	../optional/glpk/amd/$(am__dirstamp) \
+	../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/colamd/$(am__dirstamp):
+	@$(MKDIR_P) ../optional/glpk/colamd
+	@: > ../optional/glpk/colamd/$(am__dirstamp)
+../optional/glpk/colamd/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) ../optional/glpk/colamd/$(DEPDIR)
+	@: > ../optional/glpk/colamd/$(DEPDIR)/$(am__dirstamp)
+../optional/glpk/colamd/libglpk_la-colamd.lo:  \
+	../optional/glpk/colamd/$(am__dirstamp) \
+	../optional/glpk/colamd/$(DEPDIR)/$(am__dirstamp)
+
+libglpk.la: $(libglpk_la_OBJECTS) $(libglpk_la_DEPENDENCIES) $(EXTRA_libglpk_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libglpk_la_LINK) $(am_libglpk_la_rpath) $(libglpk_la_OBJECTS) $(libglpk_la_LIBADD) $(LIBS)
+foreign-ncol-parser.h: foreign-ncol-parser.c
+	@if test ! -f $@; then rm -f foreign-ncol-parser.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) foreign-ncol-parser.c; else :; fi
+foreign-lgl-parser.h: foreign-lgl-parser.c
+	@if test ! -f $@; then rm -f foreign-lgl-parser.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) foreign-lgl-parser.c; else :; fi
+foreign-pajek-parser.h: foreign-pajek-parser.c
+	@if test ! -f $@; then rm -f foreign-pajek-parser.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) foreign-pajek-parser.c; else :; fi
+foreign-gml-parser.h: foreign-gml-parser.c
+	@if test ! -f $@; then rm -f foreign-gml-parser.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) foreign-gml-parser.c; else :; fi
+foreign-dl-parser.h: foreign-dl-parser.c
+	@if test ! -f $@; then rm -f foreign-dl-parser.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) foreign-dl-parser.c; else :; fi
+cs/$(am__dirstamp):
+	@$(MKDIR_P) cs
+	@: > cs/$(am__dirstamp)
+cs/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) cs/$(DEPDIR)
+	@: > cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_add.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_happly.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_pvec.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_amd.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_house.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_qr.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_chol.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_ipvec.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_qrsol.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_cholsol.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_leaf.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_randperm.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_compress.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_load.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_reach.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_counts.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_lsolve.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_scatter.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_cumsum.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_ltsolve.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_scc.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_dfs.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_lu.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_schol.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_dmperm.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_lusol.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_spsolve.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_droptol.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_malloc.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_sqr.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_dropzeros.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_maxtrans.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_symperm.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_dupl.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_multiply.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_tdfs.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_entry.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_norm.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_transpose.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_ereach.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_permute.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_updown.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_etree.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_pinv.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_usolve.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_fkeep.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_post.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_util.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_gaxpy.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_print.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+cs/libigraph_la-cs_utsolve.lo: cs/$(am__dirstamp) \
+	cs/$(DEPDIR)/$(am__dirstamp)
+
+libigraph.la: $(libigraph_la_OBJECTS) $(libigraph_la_DEPENDENCIES) $(EXTRA_libigraph_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(libigraph_la_LINK) -rpath $(libdir) $(libigraph_la_OBJECTS) $(libigraph_la_LIBADD) $(LIBS)
+lapack/liblapack_la-dgeev.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgebak.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-xerbla.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgebal.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-disnan.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaisnan.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgehrd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgehd2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarf.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-iladlc.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-iladlr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarfg.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlapy2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlahr2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlacpy.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarfb.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-ilaenv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-ieeeck.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-iparmq.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dhseqr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlahqr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlabad.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlanv2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqr0.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqr3.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqr4.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqr2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaset.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dormhr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dormqr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarft.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dorm2r.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dtrexc.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaexc.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlange.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlassq.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarfx.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlartg.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasy2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqr5.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqr1.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlascl.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dorghr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dorgqr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dorg2r.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dtrevc.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaln2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dladiv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dsyevr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlansy.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dormtr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dormql.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dorm2l.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dstebz.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaebz.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dstein.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlagtf.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlagts.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarnv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaruv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dstemr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlae2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaev2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlanst.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrc.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarre.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarra.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrb.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaneg.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrk.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasq2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasq3.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasq4.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasq5.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasq6.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasrt.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrj.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlar1v.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlarrf.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dsterf.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dsytrd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlatrd.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dsytd2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlanhs.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgeqr2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dtrsen.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlacn2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dtrsyl.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlasr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dsteqr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgeevx.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dtrsna.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaqtr.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgetrf.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgetf2.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dlaswp.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgetrs.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-dgesv.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+lapack/liblapack_la-len_trim.lo: lapack/$(am__dirstamp) \
+	lapack/$(DEPDIR)/$(am__dirstamp)
+
+liblapack.la: $(liblapack_la_OBJECTS) $(liblapack_la_DEPENDENCIES) $(EXTRA_liblapack_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(liblapack_la_LINK) $(am_liblapack_la_rpath) $(liblapack_la_OBJECTS) $(liblapack_la_LIBADD) $(LIBS)
+plfit/$(am__dirstamp):
+	@$(MKDIR_P) plfit
+	@: > plfit/$(am__dirstamp)
+plfit/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) plfit/$(DEPDIR)
+	@: > plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/error.lo: plfit/$(am__dirstamp) plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/gss.lo: plfit/$(am__dirstamp) plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/kolmogorov.lo: plfit/$(am__dirstamp) \
+	plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/lbfgs.lo: plfit/$(am__dirstamp) plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/options.lo: plfit/$(am__dirstamp) \
+	plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/plfit.lo: plfit/$(am__dirstamp) plfit/$(DEPDIR)/$(am__dirstamp)
+plfit/zeta.lo: plfit/$(am__dirstamp) plfit/$(DEPDIR)/$(am__dirstamp)
+
+libplfit.la: $(libplfit_la_OBJECTS) $(libplfit_la_DEPENDENCIES) $(EXTRA_libplfit_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libplfit_la_OBJECTS) $(libplfit_la_LIBADD) $(LIBS)
+prpack/$(am__dirstamp):
+	@$(MKDIR_P) prpack
+	@: > prpack/$(am__dirstamp)
+prpack/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) prpack/$(DEPDIR)
+	@: > prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_base_graph.lo: prpack/$(am__dirstamp) \
+	prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_igraph_graph.lo: prpack/$(am__dirstamp) \
+	prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_preprocessed_ge_graph.lo:  \
+	prpack/$(am__dirstamp) prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_preprocessed_gs_graph.lo:  \
+	prpack/$(am__dirstamp) prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_preprocessed_scc_graph.lo:  \
+	prpack/$(am__dirstamp) prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_preprocessed_schur_graph.lo:  \
+	prpack/$(am__dirstamp) prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_result.lo: prpack/$(am__dirstamp) \
+	prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_solver.lo: prpack/$(am__dirstamp) \
+	prpack/$(DEPDIR)/$(am__dirstamp)
+prpack/libprpack_la-prpack_utils.lo: prpack/$(am__dirstamp) \
+	prpack/$(DEPDIR)/$(am__dirstamp)
+
+libprpack.la: $(libprpack_la_OBJECTS) $(libprpack_la_DEPENDENCIES) $(EXTRA_libprpack_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(CXXLINK)  $(libprpack_la_OBJECTS) $(libprpack_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f ../optional/glpk/*.$(OBJEXT)
+	-rm -f ../optional/glpk/*.lo
+	-rm -f ../optional/glpk/amd/*.$(OBJEXT)
+	-rm -f ../optional/glpk/amd/*.lo
+	-rm -f ../optional/glpk/colamd/*.$(OBJEXT)
+	-rm -f ../optional/glpk/colamd/*.lo
+	-rm -f cs/*.$(OBJEXT)
+	-rm -f cs/*.lo
+	-rm -f f2c/*.$(OBJEXT)
+	-rm -f f2c/*.lo
+	-rm -f lapack/*.$(OBJEXT)
+	-rm -f lapack/*.lo
+	-rm -f plfit/*.$(OBJEXT)
+	-rm -f plfit/*.lo
+	-rm -f prpack/*.$(OBJEXT)
+	-rm -f prpack/*.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi04.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi05.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi06.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi07.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi08.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi09.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi10.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi11.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi12.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi13.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi14.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi15.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi16.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi17.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi18.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi19.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpavl.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpcpx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv04.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv05.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv06.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv07.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv08.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpfhv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpgmp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glphbm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpini01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpini02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios04.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios05.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios06.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios07.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios08.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios09.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios10.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios11.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpios12.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpipm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplib01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplib02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplib03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplpf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpluf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glplux.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmat.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl04.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl05.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl06.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpmps.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet04.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet05.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet06.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet07.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet08.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet09.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp03.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp04.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp05.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpqmd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glprgr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glprng01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glprng02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpscf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpscl.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpsdf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpspm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpsql.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx01.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx02.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/$(DEPDIR)/libglpk_la-glptsp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_1.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_aat.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_control.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_defaults.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_dump.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_info.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_order.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_post_tree.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_postorder.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_preprocess.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_valid.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ../optional/glpk/colamd/$(DEPDIR)/libglpk_la-colamd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-DensityGrid.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-DensityGrid_3d.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-NetDataTypes.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-NetRoutines.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-adjlist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-arpack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-array.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-atlas.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-attributes.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-basic_query.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bfgs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bigint.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bignum.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bipartite.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-blas.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_eqrefhash.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_heap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_orbit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_partition.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_timer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-bliss_utils.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-cattributes.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-centrality.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-cliques.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-clustertool.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-cocitation.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-cohesive_blocks.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-community.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-complex.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-components.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-conversion.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-cores.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-decomposition.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-distances.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-dqueue.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-drl_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-drl_graph_3d.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-drl_layout.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-drl_layout_3d.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-drl_parse.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-eigen.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-evolver_cit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-fast_community.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-feedback_arc_set.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-flow.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-dl-lexer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-dl-parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-gml-lexer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-gml-parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-graphml.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-lgl-lexer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-lgl-parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-ncol-lexer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-ncol-parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-pajek-lexer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign-pajek-parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-foreign.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-forestfire.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-fortran_intrinsics.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-games.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_box_list.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_degree_sequence.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_graph_molloy_hash.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_graph_molloy_optimized.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_mr-connected.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_powerlaw.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gengraph_random.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-glet.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-glpk_support.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-gml_tree.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-hacks.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-heap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_buckets.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_error.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_estack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_fixed_vectorlist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_grid.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_hashtable.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_heap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_hrg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_hrg_types.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_marked_queue.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_psumtree.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_set.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_stack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_strvector.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-igraph_trie.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-infomap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-infomap_FlowGraph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-infomap_Greedy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-infomap_Node.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-interrupt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-iterators.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-lad.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-lapack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-layout.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-matching.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-math.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-matrix.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-maximal_cliques.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-memory.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-microscopic_update.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-mixing.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-motifs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-operators.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-optimal_modularity.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-other.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-pottsmodel_2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-progress.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-prpack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-qsort.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-qsort_r.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-random.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-revolver_cit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-revolver_grow.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-revolver_ml_cit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-sbm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-scg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-scg_approximate_methods.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-scg_exact_scg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-scg_kmeans.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-scg_optimal_method.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-scg_utils.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-separators.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-sir.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-spanning_trees.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-sparsemat.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-spectral_properties.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-spmatrix.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-st-cuts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-statusbar.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-structural_properties.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-structure_generators.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-sugiyama.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-topology.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-triangles.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-type_indexededgelist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-types.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-vector.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-vector_ptr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-version.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-visitors.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-walktrap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-walktrap_communities.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-walktrap_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-walktrap_heap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libigraph_la-zeroin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_add.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_amd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_chol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_cholsol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_compress.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_counts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_cumsum.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_dfs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_dmperm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_droptol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_dropzeros.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_dupl.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_entry.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_ereach.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_etree.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_fkeep.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_gaxpy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_happly.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_house.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_ipvec.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_leaf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_load.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_lsolve.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_ltsolve.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_lu.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_lusol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_malloc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_maxtrans.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_multiply.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_norm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_permute.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_pinv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_post.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_print.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_pvec.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_qr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_qrsol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_randperm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_reach.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_scatter.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_scc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_schol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_spsolve.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_sqr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_symperm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_tdfs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_transpose.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_updown.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_usolve.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at cs/$(DEPDIR)/libigraph_la-cs_utsolve.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-abort_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-backspac.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_abs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_cos.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_div.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_exp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_sin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-c_sqrt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-cabs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-close.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-ctype.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_abs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_acos.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_asin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_atan.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_atn2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_cnjg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_cos.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_cosh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_dim.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_exp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_imag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_int.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_lg10.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_mod.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_nint.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_prod.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_sign.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_sin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_sinh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_sqrt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_tan.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-d_tanh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-derf_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-derfc_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-dfe.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-dolio.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-dtime_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-due.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-dummy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-ef1asc_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-ef1cmc_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-endfile.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-erf_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-erfc_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-err.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-etime_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-exit_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-f77_aloc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-f77vers.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-fmt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-fmtlib.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-ftell_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-getenv_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_abs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_dim.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_dnnt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_indx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_len.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_mod.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_nint.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-h_sign.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-hl_ge.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-hl_gt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-hl_le.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-hl_lt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i77vers.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_abs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_dim.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_dnnt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_indx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_len.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_mod.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_nint.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-i_sign.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-iio.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-ilnw.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-inquire.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-l_ge.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-l_gt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-l_le.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-l_lt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-lbitbits.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-lbitshft.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-lread.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-lwrite.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-open.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_ci.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_dd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_di.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_hh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_ii.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_ri.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_zi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-pow_zz.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_abs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_acos.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_asin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_atan.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_atn2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_cnjg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_cos.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_cosh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_dim.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_exp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_imag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_int.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_lg10.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_mod.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_nint.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_sign.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_sin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_sinh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_sqrt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_tan.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-r_tanh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-rdfmt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-rewind.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-rsfe.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-rsli.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-rsne.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-s_cat.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-s_cmp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-s_copy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-s_paus.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-s_rnge.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-s_stop.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-sfe.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-sig_die.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-signal_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-signbit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-sue.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-system_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-typesize.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-uio.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-uninit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-wref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-wrtfmt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-wsfe.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-wsle.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-wsne.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-xwsne.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_abs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_cos.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_div.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_exp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_sin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at f2c/$(DEPDIR)/libf2c_la-z_sqrt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dgetv0.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dlaqrb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dmout.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dnaitr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dnapps.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dnaup2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dnaupd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dnconv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dneigh.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dneupd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dngets.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsaitr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsapps.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsaup2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsaupd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsconv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dseigt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsesrt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dseupd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsgets.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsortc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dsortr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dstatn.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dstats.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dstqrb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-dvout.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-ivout.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libarpack_la-second.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dasum.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-daxpy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dcopy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-ddot.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dgemm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dgemv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dger.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dnrm2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-drot.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dscal.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dswap.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dsymv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dsyr2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dsyr2k.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dtrmm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dtrmv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-dtrsm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-idamax.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libblas_la-lsame.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/libdlamch_la-dlamch.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgebak.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgebal.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgeev.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgeevx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgehd2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgehrd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgeqr2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgesv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgetf2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgetrf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dgetrs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dhseqr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-disnan.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlabad.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlacn2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlacpy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dladiv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlae2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaebz.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaev2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaexc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlagtf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlagts.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlahqr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlahr2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaisnan.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaln2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaneg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlange.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlanhs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlanst.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlansy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlanv2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlapy2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqr0.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqr1.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqr2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqr3.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqr4.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqr5.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaqtr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlar1v.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarfb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarfg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarft.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarfx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarnv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarra.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarre.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrj.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrk.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlarrv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlartg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaruv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlascl.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaset.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasq2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasq3.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasq4.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasq5.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasq6.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasrt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlassq.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlaswp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlasy2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dlatrd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dorg2r.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dorghr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dorgqr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dorm2l.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dorm2r.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dormhr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dormql.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dormqr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dormtr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dstebz.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dstein.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dstemr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dsteqr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dsterf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dsyevr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dsytd2.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dsytrd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dtrevc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dtrexc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dtrsen.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dtrsna.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-dtrsyl.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-ieeeck.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-iladlc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-iladlr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-ilaenv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-iparmq.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-len_trim.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at lapack/$(DEPDIR)/liblapack_la-xerbla.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/error.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/gss.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/kolmogorov.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/lbfgs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/options.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/plfit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plfit/$(DEPDIR)/zeta.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_base_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_igraph_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_ge_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_gs_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_scc_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_schur_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_result.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_solver.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at prpack/$(DEPDIR)/libprpack_la-prpack_utils.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+lapack/libarpack_la-dnaupd.lo: lapack/dnaupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dnaupd.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dnaupd.Tpo -c -o lapack/libarpack_la-dnaupd.lo `test -f 'lapack/dnaupd.c' || echo '$(srcdir)/'`lapack/dnaupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dnaupd.Tpo lapack/$(DEPDIR)/libarpack_la-dnaupd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dnaupd.c' object='lapack/libarpack_la-dnaupd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dnaupd.lo `test -f 'lapack/dnaupd.c' || echo '$(srcdir)/'`lapack/dnaupd.c
+
+lapack/libarpack_la-dnaup2.lo: lapack/dnaup2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dnaup2.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dnaup2.Tpo -c -o lapack/libarpack_la-dnaup2.lo `test -f 'lapack/dnaup2.c' || echo '$(srcdir)/'`lapack/dnaup2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dnaup2.Tpo lapack/$(DEPDIR)/libarpack_la-dnaup2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dnaup2.c' object='lapack/libarpack_la-dnaup2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dnaup2.lo `test -f 'lapack/dnaup2.c' || echo '$(srcdir)/'`lapack/dnaup2.c
+
+lapack/libarpack_la-dgetv0.lo: lapack/dgetv0.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dgetv0.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dgetv0.Tpo -c -o lapack/libarpack_la-dgetv0.lo `test -f 'lapack/dgetv0.c' || echo '$(srcdir)/'`lapack/dgetv0.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dgetv0.Tpo lapack/$(DEPDIR)/libarpack_la-dgetv0.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgetv0.c' object='lapack/libarpack_la-dgetv0.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dgetv0.lo `test -f 'lapack/dgetv0.c' || echo '$(srcdir)/'`lapack/dgetv0.c
+
+lapack/libarpack_la-dvout.lo: lapack/dvout.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dvout.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dvout.Tpo -c -o lapack/libarpack_la-dvout.lo `test -f 'lapack/dvout.c' || echo '$(srcdir)/'`lapack/dvout.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dvout.Tpo lapack/$(DEPDIR)/libarpack_la-dvout.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dvout.c' object='lapack/libarpack_la-dvout.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dvout.lo `test -f 'lapack/dvout.c' || echo '$(srcdir)/'`lapack/dvout.c
+
+lapack/libarpack_la-second.lo: lapack/second.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-second.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-second.Tpo -c -o lapack/libarpack_la-second.lo `test -f 'lapack/second.c' || echo '$(srcdir)/'`lapack/second.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-second.Tpo lapack/$(DEPDIR)/libarpack_la-second.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/second.c' object='lapack/libarpack_la-second.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-second.lo `test -f 'lapack/second.c' || echo '$(srcdir)/'`lapack/second.c
+
+lapack/libarpack_la-dmout.lo: lapack/dmout.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dmout.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dmout.Tpo -c -o lapack/libarpack_la-dmout.lo `test -f 'lapack/dmout.c' || echo '$(srcdir)/'`lapack/dmout.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dmout.Tpo lapack/$(DEPDIR)/libarpack_la-dmout.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dmout.c' object='lapack/libarpack_la-dmout.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dmout.lo `test -f 'lapack/dmout.c' || echo '$(srcdir)/'`lapack/dmout.c
+
+lapack/libarpack_la-dnaitr.lo: lapack/dnaitr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dnaitr.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dnaitr.Tpo -c -o lapack/libarpack_la-dnaitr.lo `test -f 'lapack/dnaitr.c' || echo '$(srcdir)/'`lapack/dnaitr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dnaitr.Tpo lapack/$(DEPDIR)/libarpack_la-dnaitr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dnaitr.c' object='lapack/libarpack_la-dnaitr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dnaitr.lo `test -f 'lapack/dnaitr.c' || echo '$(srcdir)/'`lapack/dnaitr.c
+
+lapack/libarpack_la-ivout.lo: lapack/ivout.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-ivout.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-ivout.Tpo -c -o lapack/libarpack_la-ivout.lo `test -f 'lapack/ivout.c' || echo '$(srcdir)/'`lapack/ivout.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-ivout.Tpo lapack/$(DEPDIR)/libarpack_la-ivout.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/ivout.c' object='lapack/libarpack_la-ivout.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-ivout.lo `test -f 'lapack/ivout.c' || echo '$(srcdir)/'`lapack/ivout.c
+
+lapack/libarpack_la-dnapps.lo: lapack/dnapps.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dnapps.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dnapps.Tpo -c -o lapack/libarpack_la-dnapps.lo `test -f 'lapack/dnapps.c' || echo '$(srcdir)/'`lapack/dnapps.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dnapps.Tpo lapack/$(DEPDIR)/libarpack_la-dnapps.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dnapps.c' object='lapack/libarpack_la-dnapps.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dnapps.lo `test -f 'lapack/dnapps.c' || echo '$(srcdir)/'`lapack/dnapps.c
+
+lapack/libarpack_la-dnconv.lo: lapack/dnconv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dnconv.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dnconv.Tpo -c -o lapack/libarpack_la-dnconv.lo `test -f 'lapack/dnconv.c' || echo '$(srcdir)/'`lapack/dnconv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dnconv.Tpo lapack/$(DEPDIR)/libarpack_la-dnconv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dnconv.c' object='lapack/libarpack_la-dnconv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dnconv.lo `test -f 'lapack/dnconv.c' || echo '$(srcdir)/'`lapack/dnconv.c
+
+lapack/libarpack_la-dneigh.lo: lapack/dneigh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dneigh.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dneigh.Tpo -c -o lapack/libarpack_la-dneigh.lo `test -f 'lapack/dneigh.c' || echo '$(srcdir)/'`lapack/dneigh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dneigh.Tpo lapack/$(DEPDIR)/libarpack_la-dneigh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dneigh.c' object='lapack/libarpack_la-dneigh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dneigh.lo `test -f 'lapack/dneigh.c' || echo '$(srcdir)/'`lapack/dneigh.c
+
+lapack/libarpack_la-dlaqrb.lo: lapack/dlaqrb.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dlaqrb.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dlaqrb.Tpo -c -o lapack/libarpack_la-dlaqrb.lo `test -f 'lapack/dlaqrb.c' || echo '$(srcdir)/'`lapack/dlaqrb.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dlaqrb.Tpo lapack/$(DEPDIR)/libarpack_la-dlaqrb.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqrb.c' object='lapack/libarpack_la-dlaqrb.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dlaqrb.lo `test -f 'lapack/dlaqrb.c' || echo '$(srcdir)/'`lapack/dlaqrb.c
+
+lapack/libarpack_la-dngets.lo: lapack/dngets.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dngets.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dngets.Tpo -c -o lapack/libarpack_la-dngets.lo `test -f 'lapack/dngets.c' || echo '$(srcdir)/'`lapack/dngets.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dngets.Tpo lapack/$(DEPDIR)/libarpack_la-dngets.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dngets.c' object='lapack/libarpack_la-dngets.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dngets.lo `test -f 'lapack/dngets.c' || echo '$(srcdir)/'`lapack/dngets.c
+
+lapack/libarpack_la-dsortc.lo: lapack/dsortc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsortc.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsortc.Tpo -c -o lapack/libarpack_la-dsortc.lo `test -f 'lapack/dsortc.c' || echo '$(srcdir)/'`lapack/dsortc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsortc.Tpo lapack/$(DEPDIR)/libarpack_la-dsortc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsortc.c' object='lapack/libarpack_la-dsortc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsortc.lo `test -f 'lapack/dsortc.c' || echo '$(srcdir)/'`lapack/dsortc.c
+
+lapack/libarpack_la-dstatn.lo: lapack/dstatn.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dstatn.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dstatn.Tpo -c -o lapack/libarpack_la-dstatn.lo `test -f 'lapack/dstatn.c' || echo '$(srcdir)/'`lapack/dstatn.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dstatn.Tpo lapack/$(DEPDIR)/libarpack_la-dstatn.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dstatn.c' object='lapack/libarpack_la-dstatn.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dstatn.lo `test -f 'lapack/dstatn.c' || echo '$(srcdir)/'`lapack/dstatn.c
+
+lapack/libarpack_la-dneupd.lo: lapack/dneupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dneupd.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dneupd.Tpo -c -o lapack/libarpack_la-dneupd.lo `test -f 'lapack/dneupd.c' || echo '$(srcdir)/'`lapack/dneupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dneupd.Tpo lapack/$(DEPDIR)/libarpack_la-dneupd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dneupd.c' object='lapack/libarpack_la-dneupd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dneupd.lo `test -f 'lapack/dneupd.c' || echo '$(srcdir)/'`lapack/dneupd.c
+
+lapack/libarpack_la-dsaupd.lo: lapack/dsaupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsaupd.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsaupd.Tpo -c -o lapack/libarpack_la-dsaupd.lo `test -f 'lapack/dsaupd.c' || echo '$(srcdir)/'`lapack/dsaupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsaupd.Tpo lapack/$(DEPDIR)/libarpack_la-dsaupd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsaupd.c' object='lapack/libarpack_la-dsaupd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsaupd.lo `test -f 'lapack/dsaupd.c' || echo '$(srcdir)/'`lapack/dsaupd.c
+
+lapack/libarpack_la-dsaup2.lo: lapack/dsaup2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsaup2.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsaup2.Tpo -c -o lapack/libarpack_la-dsaup2.lo `test -f 'lapack/dsaup2.c' || echo '$(srcdir)/'`lapack/dsaup2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsaup2.Tpo lapack/$(DEPDIR)/libarpack_la-dsaup2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsaup2.c' object='lapack/libarpack_la-dsaup2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsaup2.lo `test -f 'lapack/dsaup2.c' || echo '$(srcdir)/'`lapack/dsaup2.c
+
+lapack/libarpack_la-dsaitr.lo: lapack/dsaitr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsaitr.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsaitr.Tpo -c -o lapack/libarpack_la-dsaitr.lo `test -f 'lapack/dsaitr.c' || echo '$(srcdir)/'`lapack/dsaitr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsaitr.Tpo lapack/$(DEPDIR)/libarpack_la-dsaitr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsaitr.c' object='lapack/libarpack_la-dsaitr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsaitr.lo `test -f 'lapack/dsaitr.c' || echo '$(srcdir)/'`lapack/dsaitr.c
+
+lapack/libarpack_la-dsapps.lo: lapack/dsapps.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsapps.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsapps.Tpo -c -o lapack/libarpack_la-dsapps.lo `test -f 'lapack/dsapps.c' || echo '$(srcdir)/'`lapack/dsapps.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsapps.Tpo lapack/$(DEPDIR)/libarpack_la-dsapps.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsapps.c' object='lapack/libarpack_la-dsapps.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsapps.lo `test -f 'lapack/dsapps.c' || echo '$(srcdir)/'`lapack/dsapps.c
+
+lapack/libarpack_la-dsconv.lo: lapack/dsconv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsconv.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsconv.Tpo -c -o lapack/libarpack_la-dsconv.lo `test -f 'lapack/dsconv.c' || echo '$(srcdir)/'`lapack/dsconv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsconv.Tpo lapack/$(DEPDIR)/libarpack_la-dsconv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsconv.c' object='lapack/libarpack_la-dsconv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsconv.lo `test -f 'lapack/dsconv.c' || echo '$(srcdir)/'`lapack/dsconv.c
+
+lapack/libarpack_la-dseigt.lo: lapack/dseigt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dseigt.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dseigt.Tpo -c -o lapack/libarpack_la-dseigt.lo `test -f 'lapack/dseigt.c' || echo '$(srcdir)/'`lapack/dseigt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dseigt.Tpo lapack/$(DEPDIR)/libarpack_la-dseigt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dseigt.c' object='lapack/libarpack_la-dseigt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dseigt.lo `test -f 'lapack/dseigt.c' || echo '$(srcdir)/'`lapack/dseigt.c
+
+lapack/libarpack_la-dstqrb.lo: lapack/dstqrb.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dstqrb.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dstqrb.Tpo -c -o lapack/libarpack_la-dstqrb.lo `test -f 'lapack/dstqrb.c' || echo '$(srcdir)/'`lapack/dstqrb.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dstqrb.Tpo lapack/$(DEPDIR)/libarpack_la-dstqrb.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dstqrb.c' object='lapack/libarpack_la-dstqrb.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dstqrb.lo `test -f 'lapack/dstqrb.c' || echo '$(srcdir)/'`lapack/dstqrb.c
+
+lapack/libarpack_la-dsgets.lo: lapack/dsgets.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsgets.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsgets.Tpo -c -o lapack/libarpack_la-dsgets.lo `test -f 'lapack/dsgets.c' || echo '$(srcdir)/'`lapack/dsgets.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsgets.Tpo lapack/$(DEPDIR)/libarpack_la-dsgets.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsgets.c' object='lapack/libarpack_la-dsgets.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsgets.lo `test -f 'lapack/dsgets.c' || echo '$(srcdir)/'`lapack/dsgets.c
+
+lapack/libarpack_la-dsortr.lo: lapack/dsortr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsortr.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsortr.Tpo -c -o lapack/libarpack_la-dsortr.lo `test -f 'lapack/dsortr.c' || echo '$(srcdir)/'`lapack/dsortr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsortr.Tpo lapack/$(DEPDIR)/libarpack_la-dsortr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsortr.c' object='lapack/libarpack_la-dsortr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsortr.lo `test -f 'lapack/dsortr.c' || echo '$(srcdir)/'`lapack/dsortr.c
+
+lapack/libarpack_la-dstats.lo: lapack/dstats.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dstats.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dstats.Tpo -c -o lapack/libarpack_la-dstats.lo `test -f 'lapack/dstats.c' || echo '$(srcdir)/'`lapack/dstats.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dstats.Tpo lapack/$(DEPDIR)/libarpack_la-dstats.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dstats.c' object='lapack/libarpack_la-dstats.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dstats.lo `test -f 'lapack/dstats.c' || echo '$(srcdir)/'`lapack/dstats.c
+
+lapack/libarpack_la-dseupd.lo: lapack/dseupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dseupd.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dseupd.Tpo -c -o lapack/libarpack_la-dseupd.lo `test -f 'lapack/dseupd.c' || echo '$(srcdir)/'`lapack/dseupd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dseupd.Tpo lapack/$(DEPDIR)/libarpack_la-dseupd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dseupd.c' object='lapack/libarpack_la-dseupd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dseupd.lo `test -f 'lapack/dseupd.c' || echo '$(srcdir)/'`lapack/dseupd.c
+
+lapack/libarpack_la-dsesrt.lo: lapack/dsesrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -MT lapack/libarpack_la-dsesrt.lo -MD -MP -MF lapack/$(DEPDIR)/libarpack_la-dsesrt.Tpo -c -o lapack/libarpack_la-dsesrt.lo `test -f 'lapack/dsesrt.c' || echo '$(srcdir)/'`lapack/dsesrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libarpack_la-dsesrt.Tpo lapack/$(DEPDIR)/libarpack_la-dsesrt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsesrt.c' object='lapack/libarpack_la-dsesrt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libarpack_la_CFLAGS) $(CFLAGS) -c -o lapack/libarpack_la-dsesrt.lo `test -f 'lapack/dsesrt.c' || echo '$(srcdir)/'`lapack/dsesrt.c
+
+lapack/libblas_la-dscal.lo: lapack/dscal.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dscal.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dscal.Tpo -c -o lapack/libblas_la-dscal.lo `test -f 'lapack/dscal.c' || echo '$(srcdir)/'`lapack/dscal.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dscal.Tpo lapack/$(DEPDIR)/libblas_la-dscal.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dscal.c' object='lapack/libblas_la-dscal.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dscal.lo `test -f 'lapack/dscal.c' || echo '$(srcdir)/'`lapack/dscal.c
+
+lapack/libblas_la-dswap.lo: lapack/dswap.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dswap.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dswap.Tpo -c -o lapack/libblas_la-dswap.lo `test -f 'lapack/dswap.c' || echo '$(srcdir)/'`lapack/dswap.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dswap.Tpo lapack/$(DEPDIR)/libblas_la-dswap.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dswap.c' object='lapack/libblas_la-dswap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dswap.lo `test -f 'lapack/dswap.c' || echo '$(srcdir)/'`lapack/dswap.c
+
+lapack/libblas_la-lsame.lo: lapack/lsame.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-lsame.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-lsame.Tpo -c -o lapack/libblas_la-lsame.lo `test -f 'lapack/lsame.c' || echo '$(srcdir)/'`lapack/lsame.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-lsame.Tpo lapack/$(DEPDIR)/libblas_la-lsame.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/lsame.c' object='lapack/libblas_la-lsame.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-lsame.lo `test -f 'lapack/lsame.c' || echo '$(srcdir)/'`lapack/lsame.c
+
+lapack/libblas_la-idamax.lo: lapack/idamax.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-idamax.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-idamax.Tpo -c -o lapack/libblas_la-idamax.lo `test -f 'lapack/idamax.c' || echo '$(srcdir)/'`lapack/idamax.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-idamax.Tpo lapack/$(DEPDIR)/libblas_la-idamax.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/idamax.c' object='lapack/libblas_la-idamax.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-idamax.lo `test -f 'lapack/idamax.c' || echo '$(srcdir)/'`lapack/idamax.c
+
+lapack/libblas_la-daxpy.lo: lapack/daxpy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-daxpy.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-daxpy.Tpo -c -o lapack/libblas_la-daxpy.lo `test -f 'lapack/daxpy.c' || echo '$(srcdir)/'`lapack/daxpy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-daxpy.Tpo lapack/$(DEPDIR)/libblas_la-daxpy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/daxpy.c' object='lapack/libblas_la-daxpy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-daxpy.lo `test -f 'lapack/daxpy.c' || echo '$(srcdir)/'`lapack/daxpy.c
+
+lapack/libblas_la-dgemv.lo: lapack/dgemv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dgemv.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dgemv.Tpo -c -o lapack/libblas_la-dgemv.lo `test -f 'lapack/dgemv.c' || echo '$(srcdir)/'`lapack/dgemv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dgemv.Tpo lapack/$(DEPDIR)/libblas_la-dgemv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgemv.c' object='lapack/libblas_la-dgemv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dgemv.lo `test -f 'lapack/dgemv.c' || echo '$(srcdir)/'`lapack/dgemv.c
+
+lapack/libblas_la-dger.lo: lapack/dger.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dger.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dger.Tpo -c -o lapack/libblas_la-dger.lo `test -f 'lapack/dger.c' || echo '$(srcdir)/'`lapack/dger.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dger.Tpo lapack/$(DEPDIR)/libblas_la-dger.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dger.c' object='lapack/libblas_la-dger.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dger.lo `test -f 'lapack/dger.c' || echo '$(srcdir)/'`lapack/dger.c
+
+lapack/libblas_la-dnrm2.lo: lapack/dnrm2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dnrm2.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dnrm2.Tpo -c -o lapack/libblas_la-dnrm2.lo `test -f 'lapack/dnrm2.c' || echo '$(srcdir)/'`lapack/dnrm2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dnrm2.Tpo lapack/$(DEPDIR)/libblas_la-dnrm2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dnrm2.c' object='lapack/libblas_la-dnrm2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dnrm2.lo `test -f 'lapack/dnrm2.c' || echo '$(srcdir)/'`lapack/dnrm2.c
+
+lapack/libblas_la-dgemm.lo: lapack/dgemm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dgemm.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dgemm.Tpo -c -o lapack/libblas_la-dgemm.lo `test -f 'lapack/dgemm.c' || echo '$(srcdir)/'`lapack/dgemm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dgemm.Tpo lapack/$(DEPDIR)/libblas_la-dgemm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgemm.c' object='lapack/libblas_la-dgemm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dgemm.lo `test -f 'lapack/dgemm.c' || echo '$(srcdir)/'`lapack/dgemm.c
+
+lapack/libblas_la-dcopy.lo: lapack/dcopy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dcopy.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dcopy.Tpo -c -o lapack/libblas_la-dcopy.lo `test -f 'lapack/dcopy.c' || echo '$(srcdir)/'`lapack/dcopy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dcopy.Tpo lapack/$(DEPDIR)/libblas_la-dcopy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dcopy.c' object='lapack/libblas_la-dcopy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dcopy.lo `test -f 'lapack/dcopy.c' || echo '$(srcdir)/'`lapack/dcopy.c
+
+lapack/libblas_la-dtrmm.lo: lapack/dtrmm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dtrmm.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dtrmm.Tpo -c -o lapack/libblas_la-dtrmm.lo `test -f 'lapack/dtrmm.c' || echo '$(srcdir)/'`lapack/dtrmm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dtrmm.Tpo lapack/$(DEPDIR)/libblas_la-dtrmm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrmm.c' object='lapack/libblas_la-dtrmm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dtrmm.lo `test -f 'lapack/dtrmm.c' || echo '$(srcdir)/'`lapack/dtrmm.c
+
+lapack/libblas_la-dtrmv.lo: lapack/dtrmv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dtrmv.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dtrmv.Tpo -c -o lapack/libblas_la-dtrmv.lo `test -f 'lapack/dtrmv.c' || echo '$(srcdir)/'`lapack/dtrmv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dtrmv.Tpo lapack/$(DEPDIR)/libblas_la-dtrmv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrmv.c' object='lapack/libblas_la-dtrmv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dtrmv.lo `test -f 'lapack/dtrmv.c' || echo '$(srcdir)/'`lapack/dtrmv.c
+
+lapack/libblas_la-drot.lo: lapack/drot.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-drot.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-drot.Tpo -c -o lapack/libblas_la-drot.lo `test -f 'lapack/drot.c' || echo '$(srcdir)/'`lapack/drot.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-drot.Tpo lapack/$(DEPDIR)/libblas_la-drot.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/drot.c' object='lapack/libblas_la-drot.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-drot.lo `test -f 'lapack/drot.c' || echo '$(srcdir)/'`lapack/drot.c
+
+lapack/libblas_la-ddot.lo: lapack/ddot.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-ddot.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-ddot.Tpo -c -o lapack/libblas_la-ddot.lo `test -f 'lapack/ddot.c' || echo '$(srcdir)/'`lapack/ddot.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-ddot.Tpo lapack/$(DEPDIR)/libblas_la-ddot.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/ddot.c' object='lapack/libblas_la-ddot.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-ddot.lo `test -f 'lapack/ddot.c' || echo '$(srcdir)/'`lapack/ddot.c
+
+lapack/libblas_la-dasum.lo: lapack/dasum.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dasum.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dasum.Tpo -c -o lapack/libblas_la-dasum.lo `test -f 'lapack/dasum.c' || echo '$(srcdir)/'`lapack/dasum.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dasum.Tpo lapack/$(DEPDIR)/libblas_la-dasum.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dasum.c' object='lapack/libblas_la-dasum.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dasum.lo `test -f 'lapack/dasum.c' || echo '$(srcdir)/'`lapack/dasum.c
+
+lapack/libblas_la-dsymv.lo: lapack/dsymv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dsymv.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dsymv.Tpo -c -o lapack/libblas_la-dsymv.lo `test -f 'lapack/dsymv.c' || echo '$(srcdir)/'`lapack/dsymv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dsymv.Tpo lapack/$(DEPDIR)/libblas_la-dsymv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsymv.c' object='lapack/libblas_la-dsymv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dsymv.lo `test -f 'lapack/dsymv.c' || echo '$(srcdir)/'`lapack/dsymv.c
+
+lapack/libblas_la-dsyr2k.lo: lapack/dsyr2k.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dsyr2k.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dsyr2k.Tpo -c -o lapack/libblas_la-dsyr2k.lo `test -f 'lapack/dsyr2k.c' || echo '$(srcdir)/'`lapack/dsyr2k.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dsyr2k.Tpo lapack/$(DEPDIR)/libblas_la-dsyr2k.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsyr2k.c' object='lapack/libblas_la-dsyr2k.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dsyr2k.lo `test -f 'lapack/dsyr2k.c' || echo '$(srcdir)/'`lapack/dsyr2k.c
+
+lapack/libblas_la-dsyr2.lo: lapack/dsyr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dsyr2.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dsyr2.Tpo -c -o lapack/libblas_la-dsyr2.lo `test -f 'lapack/dsyr2.c' || echo '$(srcdir)/'`lapack/dsyr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dsyr2.Tpo lapack/$(DEPDIR)/libblas_la-dsyr2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsyr2.c' object='lapack/libblas_la-dsyr2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dsyr2.lo `test -f 'lapack/dsyr2.c' || echo '$(srcdir)/'`lapack/dsyr2.c
+
+lapack/libblas_la-dtrsm.lo: lapack/dtrsm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -MT lapack/libblas_la-dtrsm.lo -MD -MP -MF lapack/$(DEPDIR)/libblas_la-dtrsm.Tpo -c -o lapack/libblas_la-dtrsm.lo `test -f 'lapack/dtrsm.c' || echo '$(srcdir)/'`lapack/dtrsm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libblas_la-dtrsm.Tpo lapack/$(DEPDIR)/libblas_la-dtrsm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrsm.c' object='lapack/libblas_la-dtrsm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libblas_la_CFLAGS) $(CFLAGS) -c -o lapack/libblas_la-dtrsm.lo `test -f 'lapack/dtrsm.c' || echo '$(srcdir)/'`lapack/dtrsm.c
+
+lapack/libdlamch_la-dlamch.lo: lapack/dlamch.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdlamch_la_CFLAGS) $(CFLAGS) -MT lapack/libdlamch_la-dlamch.lo -MD -MP -MF lapack/$(DEPDIR)/libdlamch_la-dlamch.Tpo -c -o lapack/libdlamch_la-dlamch.lo `test -f 'lapack/dlamch.c' || echo '$(srcdir)/'`lapack/dlamch.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/libdlamch_la-dlamch.Tpo lapack/$(DEPDIR)/libdlamch_la-dlamch.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlamch.c' object='lapack/libdlamch_la-dlamch.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdlamch_la_CFLAGS) $(CFLAGS) -c -o lapack/libdlamch_la-dlamch.lo `test -f 'lapack/dlamch.c' || echo '$(srcdir)/'`lapack/dlamch.c
+
+f2c/libf2c_la-abort_.lo: f2c/abort_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-abort_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-abort_.Tpo -c -o f2c/libf2c_la-abort_.lo `test -f 'f2c/abort_.c' || echo '$(srcdir)/'`f2c/abort_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-abort_.Tpo f2c/$(DEPDIR)/libf2c_la-abort_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/abort_.c' object='f2c/libf2c_la-abort_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-abort_.lo `test -f 'f2c/abort_.c' || echo '$(srcdir)/'`f2c/abort_.c
+
+f2c/libf2c_la-dolio.lo: f2c/dolio.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-dolio.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-dolio.Tpo -c -o f2c/libf2c_la-dolio.lo `test -f 'f2c/dolio.c' || echo '$(srcdir)/'`f2c/dolio.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-dolio.Tpo f2c/$(DEPDIR)/libf2c_la-dolio.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/dolio.c' object='f2c/libf2c_la-dolio.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-dolio.lo `test -f 'f2c/dolio.c' || echo '$(srcdir)/'`f2c/dolio.c
+
+f2c/libf2c_la-r_sin.lo: f2c/r_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_sin.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_sin.Tpo -c -o f2c/libf2c_la-r_sin.lo `test -f 'f2c/r_sin.c' || echo '$(srcdir)/'`f2c/r_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_sin.Tpo f2c/$(DEPDIR)/libf2c_la-r_sin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_sin.c' object='f2c/libf2c_la-r_sin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_sin.lo `test -f 'f2c/r_sin.c' || echo '$(srcdir)/'`f2c/r_sin.c
+
+f2c/libf2c_la-dummy.lo: f2c/dummy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-dummy.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-dummy.Tpo -c -o f2c/libf2c_la-dummy.lo `test -f 'f2c/dummy.c' || echo '$(srcdir)/'`f2c/dummy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-dummy.Tpo f2c/$(DEPDIR)/libf2c_la-dummy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/dummy.c' object='f2c/libf2c_la-dummy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-dummy.lo `test -f 'f2c/dummy.c' || echo '$(srcdir)/'`f2c/dummy.c
+
+f2c/libf2c_la-dtime_.lo: f2c/dtime_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-dtime_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-dtime_.Tpo -c -o f2c/libf2c_la-dtime_.lo `test -f 'f2c/dtime_.c' || echo '$(srcdir)/'`f2c/dtime_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-dtime_.Tpo f2c/$(DEPDIR)/libf2c_la-dtime_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/dtime_.c' object='f2c/libf2c_la-dtime_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-dtime_.lo `test -f 'f2c/dtime_.c' || echo '$(srcdir)/'`f2c/dtime_.c
+
+f2c/libf2c_la-iio.lo: f2c/iio.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-iio.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-iio.Tpo -c -o f2c/libf2c_la-iio.lo `test -f 'f2c/iio.c' || echo '$(srcdir)/'`f2c/iio.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-iio.Tpo f2c/$(DEPDIR)/libf2c_la-iio.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/iio.c' object='f2c/libf2c_la-iio.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-iio.lo `test -f 'f2c/iio.c' || echo '$(srcdir)/'`f2c/iio.c
+
+f2c/libf2c_la-r_sinh.lo: f2c/r_sinh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_sinh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_sinh.Tpo -c -o f2c/libf2c_la-r_sinh.lo `test -f 'f2c/r_sinh.c' || echo '$(srcdir)/'`f2c/r_sinh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_sinh.Tpo f2c/$(DEPDIR)/libf2c_la-r_sinh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_sinh.c' object='f2c/libf2c_la-r_sinh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_sinh.lo `test -f 'f2c/r_sinh.c' || echo '$(srcdir)/'`f2c/r_sinh.c
+
+f2c/libf2c_la-backspac.lo: f2c/backspac.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-backspac.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-backspac.Tpo -c -o f2c/libf2c_la-backspac.lo `test -f 'f2c/backspac.c' || echo '$(srcdir)/'`f2c/backspac.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-backspac.Tpo f2c/$(DEPDIR)/libf2c_la-backspac.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/backspac.c' object='f2c/libf2c_la-backspac.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-backspac.lo `test -f 'f2c/backspac.c' || echo '$(srcdir)/'`f2c/backspac.c
+
+f2c/libf2c_la-due.lo: f2c/due.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-due.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-due.Tpo -c -o f2c/libf2c_la-due.lo `test -f 'f2c/due.c' || echo '$(srcdir)/'`f2c/due.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-due.Tpo f2c/$(DEPDIR)/libf2c_la-due.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/due.c' object='f2c/libf2c_la-due.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-due.lo `test -f 'f2c/due.c' || echo '$(srcdir)/'`f2c/due.c
+
+f2c/libf2c_la-ilnw.lo: f2c/ilnw.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-ilnw.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-ilnw.Tpo -c -o f2c/libf2c_la-ilnw.lo `test -f 'f2c/ilnw.c' || echo '$(srcdir)/'`f2c/ilnw.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-ilnw.Tpo f2c/$(DEPDIR)/libf2c_la-ilnw.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/ilnw.c' object='f2c/libf2c_la-ilnw.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-ilnw.lo `test -f 'f2c/ilnw.c' || echo '$(srcdir)/'`f2c/ilnw.c
+
+f2c/libf2c_la-r_sqrt.lo: f2c/r_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_sqrt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_sqrt.Tpo -c -o f2c/libf2c_la-r_sqrt.lo `test -f 'f2c/r_sqrt.c' || echo '$(srcdir)/'`f2c/r_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_sqrt.Tpo f2c/$(DEPDIR)/libf2c_la-r_sqrt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_sqrt.c' object='f2c/libf2c_la-r_sqrt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_sqrt.lo `test -f 'f2c/r_sqrt.c' || echo '$(srcdir)/'`f2c/r_sqrt.c
+
+f2c/libf2c_la-c_abs.lo: f2c/c_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_abs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_abs.Tpo -c -o f2c/libf2c_la-c_abs.lo `test -f 'f2c/c_abs.c' || echo '$(srcdir)/'`f2c/c_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_abs.Tpo f2c/$(DEPDIR)/libf2c_la-c_abs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_abs.c' object='f2c/libf2c_la-c_abs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_abs.lo `test -f 'f2c/c_abs.c' || echo '$(srcdir)/'`f2c/c_abs.c
+
+f2c/libf2c_la-ef1asc_.lo: f2c/ef1asc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-ef1asc_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-ef1asc_.Tpo -c -o f2c/libf2c_la-ef1asc_.lo `test -f 'f2c/ef1asc_.c' || echo '$(srcdir)/'`f2c/ef1asc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-ef1asc_.Tpo f2c/$(DEPDIR)/libf2c_la-ef1asc_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/ef1asc_.c' object='f2c/libf2c_la-ef1asc_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-ef1asc_.lo `test -f 'f2c/ef1asc_.c' || echo '$(srcdir)/'`f2c/ef1asc_.c
+
+f2c/libf2c_la-inquire.lo: f2c/inquire.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-inquire.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-inquire.Tpo -c -o f2c/libf2c_la-inquire.lo `test -f 'f2c/inquire.c' || echo '$(srcdir)/'`f2c/inquire.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-inquire.Tpo f2c/$(DEPDIR)/libf2c_la-inquire.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/inquire.c' object='f2c/libf2c_la-inquire.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-inquire.lo `test -f 'f2c/inquire.c' || echo '$(srcdir)/'`f2c/inquire.c
+
+f2c/libf2c_la-r_tan.lo: f2c/r_tan.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_tan.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_tan.Tpo -c -o f2c/libf2c_la-r_tan.lo `test -f 'f2c/r_tan.c' || echo '$(srcdir)/'`f2c/r_tan.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_tan.Tpo f2c/$(DEPDIR)/libf2c_la-r_tan.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_tan.c' object='f2c/libf2c_la-r_tan.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_tan.lo `test -f 'f2c/r_tan.c' || echo '$(srcdir)/'`f2c/r_tan.c
+
+f2c/libf2c_la-c_cos.lo: f2c/c_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_cos.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_cos.Tpo -c -o f2c/libf2c_la-c_cos.lo `test -f 'f2c/c_cos.c' || echo '$(srcdir)/'`f2c/c_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_cos.Tpo f2c/$(DEPDIR)/libf2c_la-c_cos.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_cos.c' object='f2c/libf2c_la-c_cos.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_cos.lo `test -f 'f2c/c_cos.c' || echo '$(srcdir)/'`f2c/c_cos.c
+
+f2c/libf2c_la-ef1cmc_.lo: f2c/ef1cmc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-ef1cmc_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-ef1cmc_.Tpo -c -o f2c/libf2c_la-ef1cmc_.lo `test -f 'f2c/ef1cmc_.c' || echo '$(srcdir)/'`f2c/ef1cmc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-ef1cmc_.Tpo f2c/$(DEPDIR)/libf2c_la-ef1cmc_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/ef1cmc_.c' object='f2c/libf2c_la-ef1cmc_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-ef1cmc_.lo `test -f 'f2c/ef1cmc_.c' || echo '$(srcdir)/'`f2c/ef1cmc_.c
+
+f2c/libf2c_la-l_ge.lo: f2c/l_ge.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-l_ge.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-l_ge.Tpo -c -o f2c/libf2c_la-l_ge.lo `test -f 'f2c/l_ge.c' || echo '$(srcdir)/'`f2c/l_ge.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-l_ge.Tpo f2c/$(DEPDIR)/libf2c_la-l_ge.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/l_ge.c' object='f2c/libf2c_la-l_ge.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-l_ge.lo `test -f 'f2c/l_ge.c' || echo '$(srcdir)/'`f2c/l_ge.c
+
+f2c/libf2c_la-r_tanh.lo: f2c/r_tanh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_tanh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_tanh.Tpo -c -o f2c/libf2c_la-r_tanh.lo `test -f 'f2c/r_tanh.c' || echo '$(srcdir)/'`f2c/r_tanh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_tanh.Tpo f2c/$(DEPDIR)/libf2c_la-r_tanh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_tanh.c' object='f2c/libf2c_la-r_tanh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_tanh.lo `test -f 'f2c/r_tanh.c' || echo '$(srcdir)/'`f2c/r_tanh.c
+
+f2c/libf2c_la-c_div.lo: f2c/c_div.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_div.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_div.Tpo -c -o f2c/libf2c_la-c_div.lo `test -f 'f2c/c_div.c' || echo '$(srcdir)/'`f2c/c_div.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_div.Tpo f2c/$(DEPDIR)/libf2c_la-c_div.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_div.c' object='f2c/libf2c_la-c_div.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_div.lo `test -f 'f2c/c_div.c' || echo '$(srcdir)/'`f2c/c_div.c
+
+f2c/libf2c_la-endfile.lo: f2c/endfile.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-endfile.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-endfile.Tpo -c -o f2c/libf2c_la-endfile.lo `test -f 'f2c/endfile.c' || echo '$(srcdir)/'`f2c/endfile.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-endfile.Tpo f2c/$(DEPDIR)/libf2c_la-endfile.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/endfile.c' object='f2c/libf2c_la-endfile.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-endfile.lo `test -f 'f2c/endfile.c' || echo '$(srcdir)/'`f2c/endfile.c
+
+f2c/libf2c_la-l_gt.lo: f2c/l_gt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-l_gt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-l_gt.Tpo -c -o f2c/libf2c_la-l_gt.lo `test -f 'f2c/l_gt.c' || echo '$(srcdir)/'`f2c/l_gt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-l_gt.Tpo f2c/$(DEPDIR)/libf2c_la-l_gt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/l_gt.c' object='f2c/libf2c_la-l_gt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-l_gt.lo `test -f 'f2c/l_gt.c' || echo '$(srcdir)/'`f2c/l_gt.c
+
+f2c/libf2c_la-rdfmt.lo: f2c/rdfmt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-rdfmt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-rdfmt.Tpo -c -o f2c/libf2c_la-rdfmt.lo `test -f 'f2c/rdfmt.c' || echo '$(srcdir)/'`f2c/rdfmt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-rdfmt.Tpo f2c/$(DEPDIR)/libf2c_la-rdfmt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/rdfmt.c' object='f2c/libf2c_la-rdfmt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-rdfmt.lo `test -f 'f2c/rdfmt.c' || echo '$(srcdir)/'`f2c/rdfmt.c
+
+f2c/libf2c_la-c_exp.lo: f2c/c_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_exp.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_exp.Tpo -c -o f2c/libf2c_la-c_exp.lo `test -f 'f2c/c_exp.c' || echo '$(srcdir)/'`f2c/c_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_exp.Tpo f2c/$(DEPDIR)/libf2c_la-c_exp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_exp.c' object='f2c/libf2c_la-c_exp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_exp.lo `test -f 'f2c/c_exp.c' || echo '$(srcdir)/'`f2c/c_exp.c
+
+f2c/libf2c_la-erf_.lo: f2c/erf_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-erf_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-erf_.Tpo -c -o f2c/libf2c_la-erf_.lo `test -f 'f2c/erf_.c' || echo '$(srcdir)/'`f2c/erf_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-erf_.Tpo f2c/$(DEPDIR)/libf2c_la-erf_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/erf_.c' object='f2c/libf2c_la-erf_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-erf_.lo `test -f 'f2c/erf_.c' || echo '$(srcdir)/'`f2c/erf_.c
+
+f2c/libf2c_la-l_le.lo: f2c/l_le.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-l_le.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-l_le.Tpo -c -o f2c/libf2c_la-l_le.lo `test -f 'f2c/l_le.c' || echo '$(srcdir)/'`f2c/l_le.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-l_le.Tpo f2c/$(DEPDIR)/libf2c_la-l_le.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/l_le.c' object='f2c/libf2c_la-l_le.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-l_le.lo `test -f 'f2c/l_le.c' || echo '$(srcdir)/'`f2c/l_le.c
+
+f2c/libf2c_la-rewind.lo: f2c/rewind.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-rewind.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-rewind.Tpo -c -o f2c/libf2c_la-rewind.lo `test -f 'f2c/rewind.c' || echo '$(srcdir)/'`f2c/rewind.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-rewind.Tpo f2c/$(DEPDIR)/libf2c_la-rewind.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/rewind.c' object='f2c/libf2c_la-rewind.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-rewind.lo `test -f 'f2c/rewind.c' || echo '$(srcdir)/'`f2c/rewind.c
+
+f2c/libf2c_la-c_log.lo: f2c/c_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_log.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_log.Tpo -c -o f2c/libf2c_la-c_log.lo `test -f 'f2c/c_log.c' || echo '$(srcdir)/'`f2c/c_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_log.Tpo f2c/$(DEPDIR)/libf2c_la-c_log.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_log.c' object='f2c/libf2c_la-c_log.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_log.lo `test -f 'f2c/c_log.c' || echo '$(srcdir)/'`f2c/c_log.c
+
+f2c/libf2c_la-erfc_.lo: f2c/erfc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-erfc_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-erfc_.Tpo -c -o f2c/libf2c_la-erfc_.lo `test -f 'f2c/erfc_.c' || echo '$(srcdir)/'`f2c/erfc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-erfc_.Tpo f2c/$(DEPDIR)/libf2c_la-erfc_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/erfc_.c' object='f2c/libf2c_la-erfc_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-erfc_.lo `test -f 'f2c/erfc_.c' || echo '$(srcdir)/'`f2c/erfc_.c
+
+f2c/libf2c_la-l_lt.lo: f2c/l_lt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-l_lt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-l_lt.Tpo -c -o f2c/libf2c_la-l_lt.lo `test -f 'f2c/l_lt.c' || echo '$(srcdir)/'`f2c/l_lt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-l_lt.Tpo f2c/$(DEPDIR)/libf2c_la-l_lt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/l_lt.c' object='f2c/libf2c_la-l_lt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-l_lt.lo `test -f 'f2c/l_lt.c' || echo '$(srcdir)/'`f2c/l_lt.c
+
+f2c/libf2c_la-rsfe.lo: f2c/rsfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-rsfe.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-rsfe.Tpo -c -o f2c/libf2c_la-rsfe.lo `test -f 'f2c/rsfe.c' || echo '$(srcdir)/'`f2c/rsfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-rsfe.Tpo f2c/$(DEPDIR)/libf2c_la-rsfe.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/rsfe.c' object='f2c/libf2c_la-rsfe.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-rsfe.lo `test -f 'f2c/rsfe.c' || echo '$(srcdir)/'`f2c/rsfe.c
+
+f2c/libf2c_la-c_sin.lo: f2c/c_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_sin.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_sin.Tpo -c -o f2c/libf2c_la-c_sin.lo `test -f 'f2c/c_sin.c' || echo '$(srcdir)/'`f2c/c_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_sin.Tpo f2c/$(DEPDIR)/libf2c_la-c_sin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_sin.c' object='f2c/libf2c_la-c_sin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_sin.lo `test -f 'f2c/c_sin.c' || echo '$(srcdir)/'`f2c/c_sin.c
+
+f2c/libf2c_la-err.lo: f2c/err.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-err.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-err.Tpo -c -o f2c/libf2c_la-err.lo `test -f 'f2c/err.c' || echo '$(srcdir)/'`f2c/err.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-err.Tpo f2c/$(DEPDIR)/libf2c_la-err.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/err.c' object='f2c/libf2c_la-err.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-err.lo `test -f 'f2c/err.c' || echo '$(srcdir)/'`f2c/err.c
+
+f2c/libf2c_la-lbitbits.lo: f2c/lbitbits.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-lbitbits.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-lbitbits.Tpo -c -o f2c/libf2c_la-lbitbits.lo `test -f 'f2c/lbitbits.c' || echo '$(srcdir)/'`f2c/lbitbits.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-lbitbits.Tpo f2c/$(DEPDIR)/libf2c_la-lbitbits.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/lbitbits.c' object='f2c/libf2c_la-lbitbits.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-lbitbits.lo `test -f 'f2c/lbitbits.c' || echo '$(srcdir)/'`f2c/lbitbits.c
+
+f2c/libf2c_la-rsli.lo: f2c/rsli.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-rsli.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-rsli.Tpo -c -o f2c/libf2c_la-rsli.lo `test -f 'f2c/rsli.c' || echo '$(srcdir)/'`f2c/rsli.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-rsli.Tpo f2c/$(DEPDIR)/libf2c_la-rsli.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/rsli.c' object='f2c/libf2c_la-rsli.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-rsli.lo `test -f 'f2c/rsli.c' || echo '$(srcdir)/'`f2c/rsli.c
+
+f2c/libf2c_la-c_sqrt.lo: f2c/c_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-c_sqrt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-c_sqrt.Tpo -c -o f2c/libf2c_la-c_sqrt.lo `test -f 'f2c/c_sqrt.c' || echo '$(srcdir)/'`f2c/c_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-c_sqrt.Tpo f2c/$(DEPDIR)/libf2c_la-c_sqrt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/c_sqrt.c' object='f2c/libf2c_la-c_sqrt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-c_sqrt.lo `test -f 'f2c/c_sqrt.c' || echo '$(srcdir)/'`f2c/c_sqrt.c
+
+f2c/libf2c_la-etime_.lo: f2c/etime_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-etime_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-etime_.Tpo -c -o f2c/libf2c_la-etime_.lo `test -f 'f2c/etime_.c' || echo '$(srcdir)/'`f2c/etime_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-etime_.Tpo f2c/$(DEPDIR)/libf2c_la-etime_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/etime_.c' object='f2c/libf2c_la-etime_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-etime_.lo `test -f 'f2c/etime_.c' || echo '$(srcdir)/'`f2c/etime_.c
+
+f2c/libf2c_la-lbitshft.lo: f2c/lbitshft.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-lbitshft.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-lbitshft.Tpo -c -o f2c/libf2c_la-lbitshft.lo `test -f 'f2c/lbitshft.c' || echo '$(srcdir)/'`f2c/lbitshft.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-lbitshft.Tpo f2c/$(DEPDIR)/libf2c_la-lbitshft.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/lbitshft.c' object='f2c/libf2c_la-lbitshft.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-lbitshft.lo `test -f 'f2c/lbitshft.c' || echo '$(srcdir)/'`f2c/lbitshft.c
+
+f2c/libf2c_la-rsne.lo: f2c/rsne.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-rsne.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-rsne.Tpo -c -o f2c/libf2c_la-rsne.lo `test -f 'f2c/rsne.c' || echo '$(srcdir)/'`f2c/rsne.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-rsne.Tpo f2c/$(DEPDIR)/libf2c_la-rsne.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/rsne.c' object='f2c/libf2c_la-rsne.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-rsne.lo `test -f 'f2c/rsne.c' || echo '$(srcdir)/'`f2c/rsne.c
+
+f2c/libf2c_la-cabs.lo: f2c/cabs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-cabs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-cabs.Tpo -c -o f2c/libf2c_la-cabs.lo `test -f 'f2c/cabs.c' || echo '$(srcdir)/'`f2c/cabs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-cabs.Tpo f2c/$(DEPDIR)/libf2c_la-cabs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/cabs.c' object='f2c/libf2c_la-cabs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-cabs.lo `test -f 'f2c/cabs.c' || echo '$(srcdir)/'`f2c/cabs.c
+
+f2c/libf2c_la-exit_.lo: f2c/exit_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-exit_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-exit_.Tpo -c -o f2c/libf2c_la-exit_.lo `test -f 'f2c/exit_.c' || echo '$(srcdir)/'`f2c/exit_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-exit_.Tpo f2c/$(DEPDIR)/libf2c_la-exit_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/exit_.c' object='f2c/libf2c_la-exit_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-exit_.lo `test -f 'f2c/exit_.c' || echo '$(srcdir)/'`f2c/exit_.c
+
+f2c/libf2c_la-lread.lo: f2c/lread.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-lread.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-lread.Tpo -c -o f2c/libf2c_la-lread.lo `test -f 'f2c/lread.c' || echo '$(srcdir)/'`f2c/lread.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-lread.Tpo f2c/$(DEPDIR)/libf2c_la-lread.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/lread.c' object='f2c/libf2c_la-lread.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-lread.lo `test -f 'f2c/lread.c' || echo '$(srcdir)/'`f2c/lread.c
+
+f2c/libf2c_la-s_cat.lo: f2c/s_cat.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-s_cat.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-s_cat.Tpo -c -o f2c/libf2c_la-s_cat.lo `test -f 'f2c/s_cat.c' || echo '$(srcdir)/'`f2c/s_cat.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-s_cat.Tpo f2c/$(DEPDIR)/libf2c_la-s_cat.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/s_cat.c' object='f2c/libf2c_la-s_cat.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-s_cat.lo `test -f 'f2c/s_cat.c' || echo '$(srcdir)/'`f2c/s_cat.c
+
+f2c/libf2c_la-close.lo: f2c/close.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-close.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-close.Tpo -c -o f2c/libf2c_la-close.lo `test -f 'f2c/close.c' || echo '$(srcdir)/'`f2c/close.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-close.Tpo f2c/$(DEPDIR)/libf2c_la-close.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/close.c' object='f2c/libf2c_la-close.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-close.lo `test -f 'f2c/close.c' || echo '$(srcdir)/'`f2c/close.c
+
+f2c/libf2c_la-f77_aloc.lo: f2c/f77_aloc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-f77_aloc.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-f77_aloc.Tpo -c -o f2c/libf2c_la-f77_aloc.lo `test -f 'f2c/f77_aloc.c' || echo '$(srcdir)/'`f2c/f77_aloc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-f77_aloc.Tpo f2c/$(DEPDIR)/libf2c_la-f77_aloc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/f77_aloc.c' object='f2c/libf2c_la-f77_aloc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-f77_aloc.lo `test -f 'f2c/f77_aloc.c' || echo '$(srcdir)/'`f2c/f77_aloc.c
+
+f2c/libf2c_la-lwrite.lo: f2c/lwrite.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-lwrite.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-lwrite.Tpo -c -o f2c/libf2c_la-lwrite.lo `test -f 'f2c/lwrite.c' || echo '$(srcdir)/'`f2c/lwrite.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-lwrite.Tpo f2c/$(DEPDIR)/libf2c_la-lwrite.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/lwrite.c' object='f2c/libf2c_la-lwrite.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-lwrite.lo `test -f 'f2c/lwrite.c' || echo '$(srcdir)/'`f2c/lwrite.c
+
+f2c/libf2c_la-s_cmp.lo: f2c/s_cmp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-s_cmp.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-s_cmp.Tpo -c -o f2c/libf2c_la-s_cmp.lo `test -f 'f2c/s_cmp.c' || echo '$(srcdir)/'`f2c/s_cmp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-s_cmp.Tpo f2c/$(DEPDIR)/libf2c_la-s_cmp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/s_cmp.c' object='f2c/libf2c_la-s_cmp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-s_cmp.lo `test -f 'f2c/s_cmp.c' || echo '$(srcdir)/'`f2c/s_cmp.c
+
+f2c/libf2c_la-ctype.lo: f2c/ctype.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-ctype.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-ctype.Tpo -c -o f2c/libf2c_la-ctype.lo `test -f 'f2c/ctype.c' || echo '$(srcdir)/'`f2c/ctype.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-ctype.Tpo f2c/$(DEPDIR)/libf2c_la-ctype.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/ctype.c' object='f2c/libf2c_la-ctype.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-ctype.lo `test -f 'f2c/ctype.c' || echo '$(srcdir)/'`f2c/ctype.c
+
+f2c/libf2c_la-f77vers.lo: f2c/f77vers.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-f77vers.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-f77vers.Tpo -c -o f2c/libf2c_la-f77vers.lo `test -f 'f2c/f77vers.c' || echo '$(srcdir)/'`f2c/f77vers.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-f77vers.Tpo f2c/$(DEPDIR)/libf2c_la-f77vers.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/f77vers.c' object='f2c/libf2c_la-f77vers.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-f77vers.lo `test -f 'f2c/f77vers.c' || echo '$(srcdir)/'`f2c/f77vers.c
+
+f2c/libf2c_la-s_copy.lo: f2c/s_copy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-s_copy.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-s_copy.Tpo -c -o f2c/libf2c_la-s_copy.lo `test -f 'f2c/s_copy.c' || echo '$(srcdir)/'`f2c/s_copy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-s_copy.Tpo f2c/$(DEPDIR)/libf2c_la-s_copy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/s_copy.c' object='f2c/libf2c_la-s_copy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-s_copy.lo `test -f 'f2c/s_copy.c' || echo '$(srcdir)/'`f2c/s_copy.c
+
+f2c/libf2c_la-d_abs.lo: f2c/d_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_abs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_abs.Tpo -c -o f2c/libf2c_la-d_abs.lo `test -f 'f2c/d_abs.c' || echo '$(srcdir)/'`f2c/d_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_abs.Tpo f2c/$(DEPDIR)/libf2c_la-d_abs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_abs.c' object='f2c/libf2c_la-d_abs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_abs.lo `test -f 'f2c/d_abs.c' || echo '$(srcdir)/'`f2c/d_abs.c
+
+f2c/libf2c_la-fmt.lo: f2c/fmt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-fmt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-fmt.Tpo -c -o f2c/libf2c_la-fmt.lo `test -f 'f2c/fmt.c' || echo '$(srcdir)/'`f2c/fmt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-fmt.Tpo f2c/$(DEPDIR)/libf2c_la-fmt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/fmt.c' object='f2c/libf2c_la-fmt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-fmt.lo `test -f 'f2c/fmt.c' || echo '$(srcdir)/'`f2c/fmt.c
+
+f2c/libf2c_la-open.lo: f2c/open.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-open.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-open.Tpo -c -o f2c/libf2c_la-open.lo `test -f 'f2c/open.c' || echo '$(srcdir)/'`f2c/open.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-open.Tpo f2c/$(DEPDIR)/libf2c_la-open.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/open.c' object='f2c/libf2c_la-open.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-open.lo `test -f 'f2c/open.c' || echo '$(srcdir)/'`f2c/open.c
+
+f2c/libf2c_la-s_paus.lo: f2c/s_paus.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-s_paus.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-s_paus.Tpo -c -o f2c/libf2c_la-s_paus.lo `test -f 'f2c/s_paus.c' || echo '$(srcdir)/'`f2c/s_paus.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-s_paus.Tpo f2c/$(DEPDIR)/libf2c_la-s_paus.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/s_paus.c' object='f2c/libf2c_la-s_paus.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-s_paus.lo `test -f 'f2c/s_paus.c' || echo '$(srcdir)/'`f2c/s_paus.c
+
+f2c/libf2c_la-d_acos.lo: f2c/d_acos.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_acos.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_acos.Tpo -c -o f2c/libf2c_la-d_acos.lo `test -f 'f2c/d_acos.c' || echo '$(srcdir)/'`f2c/d_acos.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_acos.Tpo f2c/$(DEPDIR)/libf2c_la-d_acos.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_acos.c' object='f2c/libf2c_la-d_acos.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_acos.lo `test -f 'f2c/d_acos.c' || echo '$(srcdir)/'`f2c/d_acos.c
+
+f2c/libf2c_la-fmtlib.lo: f2c/fmtlib.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-fmtlib.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-fmtlib.Tpo -c -o f2c/libf2c_la-fmtlib.lo `test -f 'f2c/fmtlib.c' || echo '$(srcdir)/'`f2c/fmtlib.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-fmtlib.Tpo f2c/$(DEPDIR)/libf2c_la-fmtlib.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/fmtlib.c' object='f2c/libf2c_la-fmtlib.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-fmtlib.lo `test -f 'f2c/fmtlib.c' || echo '$(srcdir)/'`f2c/fmtlib.c
+
+f2c/libf2c_la-pow_ci.lo: f2c/pow_ci.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_ci.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_ci.Tpo -c -o f2c/libf2c_la-pow_ci.lo `test -f 'f2c/pow_ci.c' || echo '$(srcdir)/'`f2c/pow_ci.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_ci.Tpo f2c/$(DEPDIR)/libf2c_la-pow_ci.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_ci.c' object='f2c/libf2c_la-pow_ci.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_ci.lo `test -f 'f2c/pow_ci.c' || echo '$(srcdir)/'`f2c/pow_ci.c
+
+f2c/libf2c_la-s_rnge.lo: f2c/s_rnge.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-s_rnge.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-s_rnge.Tpo -c -o f2c/libf2c_la-s_rnge.lo `test -f 'f2c/s_rnge.c' || echo '$(srcdir)/'`f2c/s_rnge.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-s_rnge.Tpo f2c/$(DEPDIR)/libf2c_la-s_rnge.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/s_rnge.c' object='f2c/libf2c_la-s_rnge.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-s_rnge.lo `test -f 'f2c/s_rnge.c' || echo '$(srcdir)/'`f2c/s_rnge.c
+
+f2c/libf2c_la-d_asin.lo: f2c/d_asin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_asin.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_asin.Tpo -c -o f2c/libf2c_la-d_asin.lo `test -f 'f2c/d_asin.c' || echo '$(srcdir)/'`f2c/d_asin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_asin.Tpo f2c/$(DEPDIR)/libf2c_la-d_asin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_asin.c' object='f2c/libf2c_la-d_asin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_asin.lo `test -f 'f2c/d_asin.c' || echo '$(srcdir)/'`f2c/d_asin.c
+
+f2c/libf2c_la-ftell_.lo: f2c/ftell_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-ftell_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-ftell_.Tpo -c -o f2c/libf2c_la-ftell_.lo `test -f 'f2c/ftell_.c' || echo '$(srcdir)/'`f2c/ftell_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-ftell_.Tpo f2c/$(DEPDIR)/libf2c_la-ftell_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/ftell_.c' object='f2c/libf2c_la-ftell_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-ftell_.lo `test -f 'f2c/ftell_.c' || echo '$(srcdir)/'`f2c/ftell_.c
+
+f2c/libf2c_la-pow_dd.lo: f2c/pow_dd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_dd.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_dd.Tpo -c -o f2c/libf2c_la-pow_dd.lo `test -f 'f2c/pow_dd.c' || echo '$(srcdir)/'`f2c/pow_dd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_dd.Tpo f2c/$(DEPDIR)/libf2c_la-pow_dd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_dd.c' object='f2c/libf2c_la-pow_dd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_dd.lo `test -f 'f2c/pow_dd.c' || echo '$(srcdir)/'`f2c/pow_dd.c
+
+f2c/libf2c_la-s_stop.lo: f2c/s_stop.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-s_stop.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-s_stop.Tpo -c -o f2c/libf2c_la-s_stop.lo `test -f 'f2c/s_stop.c' || echo '$(srcdir)/'`f2c/s_stop.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-s_stop.Tpo f2c/$(DEPDIR)/libf2c_la-s_stop.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/s_stop.c' object='f2c/libf2c_la-s_stop.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-s_stop.lo `test -f 'f2c/s_stop.c' || echo '$(srcdir)/'`f2c/s_stop.c
+
+f2c/libf2c_la-d_atan.lo: f2c/d_atan.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_atan.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_atan.Tpo -c -o f2c/libf2c_la-d_atan.lo `test -f 'f2c/d_atan.c' || echo '$(srcdir)/'`f2c/d_atan.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_atan.Tpo f2c/$(DEPDIR)/libf2c_la-d_atan.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_atan.c' object='f2c/libf2c_la-d_atan.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_atan.lo `test -f 'f2c/d_atan.c' || echo '$(srcdir)/'`f2c/d_atan.c
+
+f2c/libf2c_la-pow_di.lo: f2c/pow_di.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_di.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_di.Tpo -c -o f2c/libf2c_la-pow_di.lo `test -f 'f2c/pow_di.c' || echo '$(srcdir)/'`f2c/pow_di.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_di.Tpo f2c/$(DEPDIR)/libf2c_la-pow_di.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_di.c' object='f2c/libf2c_la-pow_di.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_di.lo `test -f 'f2c/pow_di.c' || echo '$(srcdir)/'`f2c/pow_di.c
+
+f2c/libf2c_la-sfe.lo: f2c/sfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-sfe.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-sfe.Tpo -c -o f2c/libf2c_la-sfe.lo `test -f 'f2c/sfe.c' || echo '$(srcdir)/'`f2c/sfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-sfe.Tpo f2c/$(DEPDIR)/libf2c_la-sfe.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/sfe.c' object='f2c/libf2c_la-sfe.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-sfe.lo `test -f 'f2c/sfe.c' || echo '$(srcdir)/'`f2c/sfe.c
+
+f2c/libf2c_la-d_atn2.lo: f2c/d_atn2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_atn2.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_atn2.Tpo -c -o f2c/libf2c_la-d_atn2.lo `test -f 'f2c/d_atn2.c' || echo '$(srcdir)/'`f2c/d_atn2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_atn2.Tpo f2c/$(DEPDIR)/libf2c_la-d_atn2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_atn2.c' object='f2c/libf2c_la-d_atn2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_atn2.lo `test -f 'f2c/d_atn2.c' || echo '$(srcdir)/'`f2c/d_atn2.c
+
+f2c/libf2c_la-getenv_.lo: f2c/getenv_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-getenv_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-getenv_.Tpo -c -o f2c/libf2c_la-getenv_.lo `test -f 'f2c/getenv_.c' || echo '$(srcdir)/'`f2c/getenv_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-getenv_.Tpo f2c/$(DEPDIR)/libf2c_la-getenv_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/getenv_.c' object='f2c/libf2c_la-getenv_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-getenv_.lo `test -f 'f2c/getenv_.c' || echo '$(srcdir)/'`f2c/getenv_.c
+
+f2c/libf2c_la-pow_hh.lo: f2c/pow_hh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_hh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_hh.Tpo -c -o f2c/libf2c_la-pow_hh.lo `test -f 'f2c/pow_hh.c' || echo '$(srcdir)/'`f2c/pow_hh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_hh.Tpo f2c/$(DEPDIR)/libf2c_la-pow_hh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_hh.c' object='f2c/libf2c_la-pow_hh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_hh.lo `test -f 'f2c/pow_hh.c' || echo '$(srcdir)/'`f2c/pow_hh.c
+
+f2c/libf2c_la-sig_die.lo: f2c/sig_die.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-sig_die.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-sig_die.Tpo -c -o f2c/libf2c_la-sig_die.lo `test -f 'f2c/sig_die.c' || echo '$(srcdir)/'`f2c/sig_die.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-sig_die.Tpo f2c/$(DEPDIR)/libf2c_la-sig_die.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/sig_die.c' object='f2c/libf2c_la-sig_die.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-sig_die.lo `test -f 'f2c/sig_die.c' || echo '$(srcdir)/'`f2c/sig_die.c
+
+f2c/libf2c_la-d_cnjg.lo: f2c/d_cnjg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_cnjg.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_cnjg.Tpo -c -o f2c/libf2c_la-d_cnjg.lo `test -f 'f2c/d_cnjg.c' || echo '$(srcdir)/'`f2c/d_cnjg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_cnjg.Tpo f2c/$(DEPDIR)/libf2c_la-d_cnjg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_cnjg.c' object='f2c/libf2c_la-d_cnjg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_cnjg.lo `test -f 'f2c/d_cnjg.c' || echo '$(srcdir)/'`f2c/d_cnjg.c
+
+f2c/libf2c_la-h_abs.lo: f2c/h_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_abs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_abs.Tpo -c -o f2c/libf2c_la-h_abs.lo `test -f 'f2c/h_abs.c' || echo '$(srcdir)/'`f2c/h_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_abs.Tpo f2c/$(DEPDIR)/libf2c_la-h_abs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_abs.c' object='f2c/libf2c_la-h_abs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_abs.lo `test -f 'f2c/h_abs.c' || echo '$(srcdir)/'`f2c/h_abs.c
+
+f2c/libf2c_la-pow_ii.lo: f2c/pow_ii.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_ii.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_ii.Tpo -c -o f2c/libf2c_la-pow_ii.lo `test -f 'f2c/pow_ii.c' || echo '$(srcdir)/'`f2c/pow_ii.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_ii.Tpo f2c/$(DEPDIR)/libf2c_la-pow_ii.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_ii.c' object='f2c/libf2c_la-pow_ii.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_ii.lo `test -f 'f2c/pow_ii.c' || echo '$(srcdir)/'`f2c/pow_ii.c
+
+f2c/libf2c_la-signal_.lo: f2c/signal_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-signal_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-signal_.Tpo -c -o f2c/libf2c_la-signal_.lo `test -f 'f2c/signal_.c' || echo '$(srcdir)/'`f2c/signal_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-signal_.Tpo f2c/$(DEPDIR)/libf2c_la-signal_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/signal_.c' object='f2c/libf2c_la-signal_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-signal_.lo `test -f 'f2c/signal_.c' || echo '$(srcdir)/'`f2c/signal_.c
+
+f2c/libf2c_la-d_cos.lo: f2c/d_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_cos.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_cos.Tpo -c -o f2c/libf2c_la-d_cos.lo `test -f 'f2c/d_cos.c' || echo '$(srcdir)/'`f2c/d_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_cos.Tpo f2c/$(DEPDIR)/libf2c_la-d_cos.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_cos.c' object='f2c/libf2c_la-d_cos.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_cos.lo `test -f 'f2c/d_cos.c' || echo '$(srcdir)/'`f2c/d_cos.c
+
+f2c/libf2c_la-h_dim.lo: f2c/h_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_dim.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_dim.Tpo -c -o f2c/libf2c_la-h_dim.lo `test -f 'f2c/h_dim.c' || echo '$(srcdir)/'`f2c/h_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_dim.Tpo f2c/$(DEPDIR)/libf2c_la-h_dim.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_dim.c' object='f2c/libf2c_la-h_dim.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_dim.lo `test -f 'f2c/h_dim.c' || echo '$(srcdir)/'`f2c/h_dim.c
+
+f2c/libf2c_la-pow_ri.lo: f2c/pow_ri.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_ri.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_ri.Tpo -c -o f2c/libf2c_la-pow_ri.lo `test -f 'f2c/pow_ri.c' || echo '$(srcdir)/'`f2c/pow_ri.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_ri.Tpo f2c/$(DEPDIR)/libf2c_la-pow_ri.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_ri.c' object='f2c/libf2c_la-pow_ri.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_ri.lo `test -f 'f2c/pow_ri.c' || echo '$(srcdir)/'`f2c/pow_ri.c
+
+f2c/libf2c_la-signbit.lo: f2c/signbit.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-signbit.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-signbit.Tpo -c -o f2c/libf2c_la-signbit.lo `test -f 'f2c/signbit.c' || echo '$(srcdir)/'`f2c/signbit.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-signbit.Tpo f2c/$(DEPDIR)/libf2c_la-signbit.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/signbit.c' object='f2c/libf2c_la-signbit.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-signbit.lo `test -f 'f2c/signbit.c' || echo '$(srcdir)/'`f2c/signbit.c
+
+f2c/libf2c_la-d_cosh.lo: f2c/d_cosh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_cosh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_cosh.Tpo -c -o f2c/libf2c_la-d_cosh.lo `test -f 'f2c/d_cosh.c' || echo '$(srcdir)/'`f2c/d_cosh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_cosh.Tpo f2c/$(DEPDIR)/libf2c_la-d_cosh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_cosh.c' object='f2c/libf2c_la-d_cosh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_cosh.lo `test -f 'f2c/d_cosh.c' || echo '$(srcdir)/'`f2c/d_cosh.c
+
+f2c/libf2c_la-h_dnnt.lo: f2c/h_dnnt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_dnnt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_dnnt.Tpo -c -o f2c/libf2c_la-h_dnnt.lo `test -f 'f2c/h_dnnt.c' || echo '$(srcdir)/'`f2c/h_dnnt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_dnnt.Tpo f2c/$(DEPDIR)/libf2c_la-h_dnnt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_dnnt.c' object='f2c/libf2c_la-h_dnnt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_dnnt.lo `test -f 'f2c/h_dnnt.c' || echo '$(srcdir)/'`f2c/h_dnnt.c
+
+f2c/libf2c_la-pow_zi.lo: f2c/pow_zi.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_zi.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_zi.Tpo -c -o f2c/libf2c_la-pow_zi.lo `test -f 'f2c/pow_zi.c' || echo '$(srcdir)/'`f2c/pow_zi.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_zi.Tpo f2c/$(DEPDIR)/libf2c_la-pow_zi.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_zi.c' object='f2c/libf2c_la-pow_zi.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_zi.lo `test -f 'f2c/pow_zi.c' || echo '$(srcdir)/'`f2c/pow_zi.c
+
+f2c/libf2c_la-sue.lo: f2c/sue.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-sue.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-sue.Tpo -c -o f2c/libf2c_la-sue.lo `test -f 'f2c/sue.c' || echo '$(srcdir)/'`f2c/sue.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-sue.Tpo f2c/$(DEPDIR)/libf2c_la-sue.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/sue.c' object='f2c/libf2c_la-sue.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-sue.lo `test -f 'f2c/sue.c' || echo '$(srcdir)/'`f2c/sue.c
+
+f2c/libf2c_la-d_dim.lo: f2c/d_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_dim.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_dim.Tpo -c -o f2c/libf2c_la-d_dim.lo `test -f 'f2c/d_dim.c' || echo '$(srcdir)/'`f2c/d_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_dim.Tpo f2c/$(DEPDIR)/libf2c_la-d_dim.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_dim.c' object='f2c/libf2c_la-d_dim.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_dim.lo `test -f 'f2c/d_dim.c' || echo '$(srcdir)/'`f2c/d_dim.c
+
+f2c/libf2c_la-h_indx.lo: f2c/h_indx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_indx.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_indx.Tpo -c -o f2c/libf2c_la-h_indx.lo `test -f 'f2c/h_indx.c' || echo '$(srcdir)/'`f2c/h_indx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_indx.Tpo f2c/$(DEPDIR)/libf2c_la-h_indx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_indx.c' object='f2c/libf2c_la-h_indx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_indx.lo `test -f 'f2c/h_indx.c' || echo '$(srcdir)/'`f2c/h_indx.c
+
+f2c/libf2c_la-pow_zz.lo: f2c/pow_zz.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-pow_zz.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-pow_zz.Tpo -c -o f2c/libf2c_la-pow_zz.lo `test -f 'f2c/pow_zz.c' || echo '$(srcdir)/'`f2c/pow_zz.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-pow_zz.Tpo f2c/$(DEPDIR)/libf2c_la-pow_zz.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/pow_zz.c' object='f2c/libf2c_la-pow_zz.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-pow_zz.lo `test -f 'f2c/pow_zz.c' || echo '$(srcdir)/'`f2c/pow_zz.c
+
+f2c/libf2c_la-system_.lo: f2c/system_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-system_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-system_.Tpo -c -o f2c/libf2c_la-system_.lo `test -f 'f2c/system_.c' || echo '$(srcdir)/'`f2c/system_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-system_.Tpo f2c/$(DEPDIR)/libf2c_la-system_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/system_.c' object='f2c/libf2c_la-system_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-system_.lo `test -f 'f2c/system_.c' || echo '$(srcdir)/'`f2c/system_.c
+
+f2c/libf2c_la-d_exp.lo: f2c/d_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_exp.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_exp.Tpo -c -o f2c/libf2c_la-d_exp.lo `test -f 'f2c/d_exp.c' || echo '$(srcdir)/'`f2c/d_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_exp.Tpo f2c/$(DEPDIR)/libf2c_la-d_exp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_exp.c' object='f2c/libf2c_la-d_exp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_exp.lo `test -f 'f2c/d_exp.c' || echo '$(srcdir)/'`f2c/d_exp.c
+
+f2c/libf2c_la-h_len.lo: f2c/h_len.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_len.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_len.Tpo -c -o f2c/libf2c_la-h_len.lo `test -f 'f2c/h_len.c' || echo '$(srcdir)/'`f2c/h_len.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_len.Tpo f2c/$(DEPDIR)/libf2c_la-h_len.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_len.c' object='f2c/libf2c_la-h_len.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_len.lo `test -f 'f2c/h_len.c' || echo '$(srcdir)/'`f2c/h_len.c
+
+f2c/libf2c_la-r_abs.lo: f2c/r_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_abs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_abs.Tpo -c -o f2c/libf2c_la-r_abs.lo `test -f 'f2c/r_abs.c' || echo '$(srcdir)/'`f2c/r_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_abs.Tpo f2c/$(DEPDIR)/libf2c_la-r_abs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_abs.c' object='f2c/libf2c_la-r_abs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_abs.lo `test -f 'f2c/r_abs.c' || echo '$(srcdir)/'`f2c/r_abs.c
+
+f2c/libf2c_la-typesize.lo: f2c/typesize.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-typesize.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-typesize.Tpo -c -o f2c/libf2c_la-typesize.lo `test -f 'f2c/typesize.c' || echo '$(srcdir)/'`f2c/typesize.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-typesize.Tpo f2c/$(DEPDIR)/libf2c_la-typesize.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/typesize.c' object='f2c/libf2c_la-typesize.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-typesize.lo `test -f 'f2c/typesize.c' || echo '$(srcdir)/'`f2c/typesize.c
+
+f2c/libf2c_la-d_imag.lo: f2c/d_imag.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_imag.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_imag.Tpo -c -o f2c/libf2c_la-d_imag.lo `test -f 'f2c/d_imag.c' || echo '$(srcdir)/'`f2c/d_imag.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_imag.Tpo f2c/$(DEPDIR)/libf2c_la-d_imag.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_imag.c' object='f2c/libf2c_la-d_imag.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_imag.lo `test -f 'f2c/d_imag.c' || echo '$(srcdir)/'`f2c/d_imag.c
+
+f2c/libf2c_la-h_mod.lo: f2c/h_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_mod.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_mod.Tpo -c -o f2c/libf2c_la-h_mod.lo `test -f 'f2c/h_mod.c' || echo '$(srcdir)/'`f2c/h_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_mod.Tpo f2c/$(DEPDIR)/libf2c_la-h_mod.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_mod.c' object='f2c/libf2c_la-h_mod.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_mod.lo `test -f 'f2c/h_mod.c' || echo '$(srcdir)/'`f2c/h_mod.c
+
+f2c/libf2c_la-r_acos.lo: f2c/r_acos.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_acos.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_acos.Tpo -c -o f2c/libf2c_la-r_acos.lo `test -f 'f2c/r_acos.c' || echo '$(srcdir)/'`f2c/r_acos.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_acos.Tpo f2c/$(DEPDIR)/libf2c_la-r_acos.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_acos.c' object='f2c/libf2c_la-r_acos.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_acos.lo `test -f 'f2c/r_acos.c' || echo '$(srcdir)/'`f2c/r_acos.c
+
+f2c/libf2c_la-uio.lo: f2c/uio.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-uio.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-uio.Tpo -c -o f2c/libf2c_la-uio.lo `test -f 'f2c/uio.c' || echo '$(srcdir)/'`f2c/uio.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-uio.Tpo f2c/$(DEPDIR)/libf2c_la-uio.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/uio.c' object='f2c/libf2c_la-uio.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-uio.lo `test -f 'f2c/uio.c' || echo '$(srcdir)/'`f2c/uio.c
+
+f2c/libf2c_la-d_int.lo: f2c/d_int.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_int.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_int.Tpo -c -o f2c/libf2c_la-d_int.lo `test -f 'f2c/d_int.c' || echo '$(srcdir)/'`f2c/d_int.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_int.Tpo f2c/$(DEPDIR)/libf2c_la-d_int.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_int.c' object='f2c/libf2c_la-d_int.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_int.lo `test -f 'f2c/d_int.c' || echo '$(srcdir)/'`f2c/d_int.c
+
+f2c/libf2c_la-h_nint.lo: f2c/h_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_nint.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_nint.Tpo -c -o f2c/libf2c_la-h_nint.lo `test -f 'f2c/h_nint.c' || echo '$(srcdir)/'`f2c/h_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_nint.Tpo f2c/$(DEPDIR)/libf2c_la-h_nint.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_nint.c' object='f2c/libf2c_la-h_nint.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_nint.lo `test -f 'f2c/h_nint.c' || echo '$(srcdir)/'`f2c/h_nint.c
+
+f2c/libf2c_la-r_asin.lo: f2c/r_asin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_asin.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_asin.Tpo -c -o f2c/libf2c_la-r_asin.lo `test -f 'f2c/r_asin.c' || echo '$(srcdir)/'`f2c/r_asin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_asin.Tpo f2c/$(DEPDIR)/libf2c_la-r_asin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_asin.c' object='f2c/libf2c_la-r_asin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_asin.lo `test -f 'f2c/r_asin.c' || echo '$(srcdir)/'`f2c/r_asin.c
+
+f2c/libf2c_la-uninit.lo: f2c/uninit.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-uninit.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-uninit.Tpo -c -o f2c/libf2c_la-uninit.lo `test -f 'f2c/uninit.c' || echo '$(srcdir)/'`f2c/uninit.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-uninit.Tpo f2c/$(DEPDIR)/libf2c_la-uninit.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/uninit.c' object='f2c/libf2c_la-uninit.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-uninit.lo `test -f 'f2c/uninit.c' || echo '$(srcdir)/'`f2c/uninit.c
+
+f2c/libf2c_la-d_lg10.lo: f2c/d_lg10.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_lg10.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_lg10.Tpo -c -o f2c/libf2c_la-d_lg10.lo `test -f 'f2c/d_lg10.c' || echo '$(srcdir)/'`f2c/d_lg10.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_lg10.Tpo f2c/$(DEPDIR)/libf2c_la-d_lg10.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_lg10.c' object='f2c/libf2c_la-d_lg10.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_lg10.lo `test -f 'f2c/d_lg10.c' || echo '$(srcdir)/'`f2c/d_lg10.c
+
+f2c/libf2c_la-h_sign.lo: f2c/h_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-h_sign.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-h_sign.Tpo -c -o f2c/libf2c_la-h_sign.lo `test -f 'f2c/h_sign.c' || echo '$(srcdir)/'`f2c/h_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-h_sign.Tpo f2c/$(DEPDIR)/libf2c_la-h_sign.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/h_sign.c' object='f2c/libf2c_la-h_sign.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-h_sign.lo `test -f 'f2c/h_sign.c' || echo '$(srcdir)/'`f2c/h_sign.c
+
+f2c/libf2c_la-r_atan.lo: f2c/r_atan.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_atan.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_atan.Tpo -c -o f2c/libf2c_la-r_atan.lo `test -f 'f2c/r_atan.c' || echo '$(srcdir)/'`f2c/r_atan.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_atan.Tpo f2c/$(DEPDIR)/libf2c_la-r_atan.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_atan.c' object='f2c/libf2c_la-r_atan.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_atan.lo `test -f 'f2c/r_atan.c' || echo '$(srcdir)/'`f2c/r_atan.c
+
+f2c/libf2c_la-util.lo: f2c/util.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-util.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-util.Tpo -c -o f2c/libf2c_la-util.lo `test -f 'f2c/util.c' || echo '$(srcdir)/'`f2c/util.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-util.Tpo f2c/$(DEPDIR)/libf2c_la-util.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/util.c' object='f2c/libf2c_la-util.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-util.lo `test -f 'f2c/util.c' || echo '$(srcdir)/'`f2c/util.c
+
+f2c/libf2c_la-d_log.lo: f2c/d_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_log.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_log.Tpo -c -o f2c/libf2c_la-d_log.lo `test -f 'f2c/d_log.c' || echo '$(srcdir)/'`f2c/d_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_log.Tpo f2c/$(DEPDIR)/libf2c_la-d_log.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_log.c' object='f2c/libf2c_la-d_log.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_log.lo `test -f 'f2c/d_log.c' || echo '$(srcdir)/'`f2c/d_log.c
+
+f2c/libf2c_la-hl_ge.lo: f2c/hl_ge.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-hl_ge.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-hl_ge.Tpo -c -o f2c/libf2c_la-hl_ge.lo `test -f 'f2c/hl_ge.c' || echo '$(srcdir)/'`f2c/hl_ge.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-hl_ge.Tpo f2c/$(DEPDIR)/libf2c_la-hl_ge.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/hl_ge.c' object='f2c/libf2c_la-hl_ge.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-hl_ge.lo `test -f 'f2c/hl_ge.c' || echo '$(srcdir)/'`f2c/hl_ge.c
+
+f2c/libf2c_la-r_atn2.lo: f2c/r_atn2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_atn2.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_atn2.Tpo -c -o f2c/libf2c_la-r_atn2.lo `test -f 'f2c/r_atn2.c' || echo '$(srcdir)/'`f2c/r_atn2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_atn2.Tpo f2c/$(DEPDIR)/libf2c_la-r_atn2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_atn2.c' object='f2c/libf2c_la-r_atn2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_atn2.lo `test -f 'f2c/r_atn2.c' || echo '$(srcdir)/'`f2c/r_atn2.c
+
+f2c/libf2c_la-wref.lo: f2c/wref.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-wref.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-wref.Tpo -c -o f2c/libf2c_la-wref.lo `test -f 'f2c/wref.c' || echo '$(srcdir)/'`f2c/wref.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-wref.Tpo f2c/$(DEPDIR)/libf2c_la-wref.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/wref.c' object='f2c/libf2c_la-wref.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-wref.lo `test -f 'f2c/wref.c' || echo '$(srcdir)/'`f2c/wref.c
+
+f2c/libf2c_la-d_mod.lo: f2c/d_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_mod.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_mod.Tpo -c -o f2c/libf2c_la-d_mod.lo `test -f 'f2c/d_mod.c' || echo '$(srcdir)/'`f2c/d_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_mod.Tpo f2c/$(DEPDIR)/libf2c_la-d_mod.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_mod.c' object='f2c/libf2c_la-d_mod.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_mod.lo `test -f 'f2c/d_mod.c' || echo '$(srcdir)/'`f2c/d_mod.c
+
+f2c/libf2c_la-hl_gt.lo: f2c/hl_gt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-hl_gt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-hl_gt.Tpo -c -o f2c/libf2c_la-hl_gt.lo `test -f 'f2c/hl_gt.c' || echo '$(srcdir)/'`f2c/hl_gt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-hl_gt.Tpo f2c/$(DEPDIR)/libf2c_la-hl_gt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/hl_gt.c' object='f2c/libf2c_la-hl_gt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-hl_gt.lo `test -f 'f2c/hl_gt.c' || echo '$(srcdir)/'`f2c/hl_gt.c
+
+f2c/libf2c_la-r_cnjg.lo: f2c/r_cnjg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_cnjg.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_cnjg.Tpo -c -o f2c/libf2c_la-r_cnjg.lo `test -f 'f2c/r_cnjg.c' || echo '$(srcdir)/'`f2c/r_cnjg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_cnjg.Tpo f2c/$(DEPDIR)/libf2c_la-r_cnjg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_cnjg.c' object='f2c/libf2c_la-r_cnjg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_cnjg.lo `test -f 'f2c/r_cnjg.c' || echo '$(srcdir)/'`f2c/r_cnjg.c
+
+f2c/libf2c_la-wrtfmt.lo: f2c/wrtfmt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-wrtfmt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-wrtfmt.Tpo -c -o f2c/libf2c_la-wrtfmt.lo `test -f 'f2c/wrtfmt.c' || echo '$(srcdir)/'`f2c/wrtfmt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-wrtfmt.Tpo f2c/$(DEPDIR)/libf2c_la-wrtfmt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/wrtfmt.c' object='f2c/libf2c_la-wrtfmt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-wrtfmt.lo `test -f 'f2c/wrtfmt.c' || echo '$(srcdir)/'`f2c/wrtfmt.c
+
+f2c/libf2c_la-d_nint.lo: f2c/d_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_nint.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_nint.Tpo -c -o f2c/libf2c_la-d_nint.lo `test -f 'f2c/d_nint.c' || echo '$(srcdir)/'`f2c/d_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_nint.Tpo f2c/$(DEPDIR)/libf2c_la-d_nint.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_nint.c' object='f2c/libf2c_la-d_nint.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_nint.lo `test -f 'f2c/d_nint.c' || echo '$(srcdir)/'`f2c/d_nint.c
+
+f2c/libf2c_la-hl_le.lo: f2c/hl_le.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-hl_le.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-hl_le.Tpo -c -o f2c/libf2c_la-hl_le.lo `test -f 'f2c/hl_le.c' || echo '$(srcdir)/'`f2c/hl_le.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-hl_le.Tpo f2c/$(DEPDIR)/libf2c_la-hl_le.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/hl_le.c' object='f2c/libf2c_la-hl_le.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-hl_le.lo `test -f 'f2c/hl_le.c' || echo '$(srcdir)/'`f2c/hl_le.c
+
+f2c/libf2c_la-r_cos.lo: f2c/r_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_cos.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_cos.Tpo -c -o f2c/libf2c_la-r_cos.lo `test -f 'f2c/r_cos.c' || echo '$(srcdir)/'`f2c/r_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_cos.Tpo f2c/$(DEPDIR)/libf2c_la-r_cos.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_cos.c' object='f2c/libf2c_la-r_cos.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_cos.lo `test -f 'f2c/r_cos.c' || echo '$(srcdir)/'`f2c/r_cos.c
+
+f2c/libf2c_la-wsfe.lo: f2c/wsfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-wsfe.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-wsfe.Tpo -c -o f2c/libf2c_la-wsfe.lo `test -f 'f2c/wsfe.c' || echo '$(srcdir)/'`f2c/wsfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-wsfe.Tpo f2c/$(DEPDIR)/libf2c_la-wsfe.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/wsfe.c' object='f2c/libf2c_la-wsfe.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-wsfe.lo `test -f 'f2c/wsfe.c' || echo '$(srcdir)/'`f2c/wsfe.c
+
+f2c/libf2c_la-d_prod.lo: f2c/d_prod.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_prod.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_prod.Tpo -c -o f2c/libf2c_la-d_prod.lo `test -f 'f2c/d_prod.c' || echo '$(srcdir)/'`f2c/d_prod.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_prod.Tpo f2c/$(DEPDIR)/libf2c_la-d_prod.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_prod.c' object='f2c/libf2c_la-d_prod.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_prod.lo `test -f 'f2c/d_prod.c' || echo '$(srcdir)/'`f2c/d_prod.c
+
+f2c/libf2c_la-hl_lt.lo: f2c/hl_lt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-hl_lt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-hl_lt.Tpo -c -o f2c/libf2c_la-hl_lt.lo `test -f 'f2c/hl_lt.c' || echo '$(srcdir)/'`f2c/hl_lt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-hl_lt.Tpo f2c/$(DEPDIR)/libf2c_la-hl_lt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/hl_lt.c' object='f2c/libf2c_la-hl_lt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-hl_lt.lo `test -f 'f2c/hl_lt.c' || echo '$(srcdir)/'`f2c/hl_lt.c
+
+f2c/libf2c_la-r_cosh.lo: f2c/r_cosh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_cosh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_cosh.Tpo -c -o f2c/libf2c_la-r_cosh.lo `test -f 'f2c/r_cosh.c' || echo '$(srcdir)/'`f2c/r_cosh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_cosh.Tpo f2c/$(DEPDIR)/libf2c_la-r_cosh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_cosh.c' object='f2c/libf2c_la-r_cosh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_cosh.lo `test -f 'f2c/r_cosh.c' || echo '$(srcdir)/'`f2c/r_cosh.c
+
+f2c/libf2c_la-wsle.lo: f2c/wsle.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-wsle.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-wsle.Tpo -c -o f2c/libf2c_la-wsle.lo `test -f 'f2c/wsle.c' || echo '$(srcdir)/'`f2c/wsle.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-wsle.Tpo f2c/$(DEPDIR)/libf2c_la-wsle.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/wsle.c' object='f2c/libf2c_la-wsle.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-wsle.lo `test -f 'f2c/wsle.c' || echo '$(srcdir)/'`f2c/wsle.c
+
+f2c/libf2c_la-d_sign.lo: f2c/d_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_sign.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_sign.Tpo -c -o f2c/libf2c_la-d_sign.lo `test -f 'f2c/d_sign.c' || echo '$(srcdir)/'`f2c/d_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_sign.Tpo f2c/$(DEPDIR)/libf2c_la-d_sign.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_sign.c' object='f2c/libf2c_la-d_sign.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_sign.lo `test -f 'f2c/d_sign.c' || echo '$(srcdir)/'`f2c/d_sign.c
+
+f2c/libf2c_la-i77vers.lo: f2c/i77vers.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i77vers.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i77vers.Tpo -c -o f2c/libf2c_la-i77vers.lo `test -f 'f2c/i77vers.c' || echo '$(srcdir)/'`f2c/i77vers.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i77vers.Tpo f2c/$(DEPDIR)/libf2c_la-i77vers.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i77vers.c' object='f2c/libf2c_la-i77vers.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i77vers.lo `test -f 'f2c/i77vers.c' || echo '$(srcdir)/'`f2c/i77vers.c
+
+f2c/libf2c_la-r_dim.lo: f2c/r_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_dim.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_dim.Tpo -c -o f2c/libf2c_la-r_dim.lo `test -f 'f2c/r_dim.c' || echo '$(srcdir)/'`f2c/r_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_dim.Tpo f2c/$(DEPDIR)/libf2c_la-r_dim.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_dim.c' object='f2c/libf2c_la-r_dim.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_dim.lo `test -f 'f2c/r_dim.c' || echo '$(srcdir)/'`f2c/r_dim.c
+
+f2c/libf2c_la-wsne.lo: f2c/wsne.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-wsne.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-wsne.Tpo -c -o f2c/libf2c_la-wsne.lo `test -f 'f2c/wsne.c' || echo '$(srcdir)/'`f2c/wsne.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-wsne.Tpo f2c/$(DEPDIR)/libf2c_la-wsne.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/wsne.c' object='f2c/libf2c_la-wsne.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-wsne.lo `test -f 'f2c/wsne.c' || echo '$(srcdir)/'`f2c/wsne.c
+
+f2c/libf2c_la-d_sin.lo: f2c/d_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_sin.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_sin.Tpo -c -o f2c/libf2c_la-d_sin.lo `test -f 'f2c/d_sin.c' || echo '$(srcdir)/'`f2c/d_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_sin.Tpo f2c/$(DEPDIR)/libf2c_la-d_sin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_sin.c' object='f2c/libf2c_la-d_sin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_sin.lo `test -f 'f2c/d_sin.c' || echo '$(srcdir)/'`f2c/d_sin.c
+
+f2c/libf2c_la-i_abs.lo: f2c/i_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_abs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_abs.Tpo -c -o f2c/libf2c_la-i_abs.lo `test -f 'f2c/i_abs.c' || echo '$(srcdir)/'`f2c/i_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_abs.Tpo f2c/$(DEPDIR)/libf2c_la-i_abs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_abs.c' object='f2c/libf2c_la-i_abs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_abs.lo `test -f 'f2c/i_abs.c' || echo '$(srcdir)/'`f2c/i_abs.c
+
+f2c/libf2c_la-r_exp.lo: f2c/r_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_exp.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_exp.Tpo -c -o f2c/libf2c_la-r_exp.lo `test -f 'f2c/r_exp.c' || echo '$(srcdir)/'`f2c/r_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_exp.Tpo f2c/$(DEPDIR)/libf2c_la-r_exp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_exp.c' object='f2c/libf2c_la-r_exp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_exp.lo `test -f 'f2c/r_exp.c' || echo '$(srcdir)/'`f2c/r_exp.c
+
+f2c/libf2c_la-xwsne.lo: f2c/xwsne.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-xwsne.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-xwsne.Tpo -c -o f2c/libf2c_la-xwsne.lo `test -f 'f2c/xwsne.c' || echo '$(srcdir)/'`f2c/xwsne.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-xwsne.Tpo f2c/$(DEPDIR)/libf2c_la-xwsne.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/xwsne.c' object='f2c/libf2c_la-xwsne.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-xwsne.lo `test -f 'f2c/xwsne.c' || echo '$(srcdir)/'`f2c/xwsne.c
+
+f2c/libf2c_la-d_sinh.lo: f2c/d_sinh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_sinh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_sinh.Tpo -c -o f2c/libf2c_la-d_sinh.lo `test -f 'f2c/d_sinh.c' || echo '$(srcdir)/'`f2c/d_sinh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_sinh.Tpo f2c/$(DEPDIR)/libf2c_la-d_sinh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_sinh.c' object='f2c/libf2c_la-d_sinh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_sinh.lo `test -f 'f2c/d_sinh.c' || echo '$(srcdir)/'`f2c/d_sinh.c
+
+f2c/libf2c_la-i_dim.lo: f2c/i_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_dim.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_dim.Tpo -c -o f2c/libf2c_la-i_dim.lo `test -f 'f2c/i_dim.c' || echo '$(srcdir)/'`f2c/i_dim.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_dim.Tpo f2c/$(DEPDIR)/libf2c_la-i_dim.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_dim.c' object='f2c/libf2c_la-i_dim.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_dim.lo `test -f 'f2c/i_dim.c' || echo '$(srcdir)/'`f2c/i_dim.c
+
+f2c/libf2c_la-r_imag.lo: f2c/r_imag.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_imag.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_imag.Tpo -c -o f2c/libf2c_la-r_imag.lo `test -f 'f2c/r_imag.c' || echo '$(srcdir)/'`f2c/r_imag.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_imag.Tpo f2c/$(DEPDIR)/libf2c_la-r_imag.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_imag.c' object='f2c/libf2c_la-r_imag.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_imag.lo `test -f 'f2c/r_imag.c' || echo '$(srcdir)/'`f2c/r_imag.c
+
+f2c/libf2c_la-z_abs.lo: f2c/z_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_abs.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_abs.Tpo -c -o f2c/libf2c_la-z_abs.lo `test -f 'f2c/z_abs.c' || echo '$(srcdir)/'`f2c/z_abs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_abs.Tpo f2c/$(DEPDIR)/libf2c_la-z_abs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_abs.c' object='f2c/libf2c_la-z_abs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_abs.lo `test -f 'f2c/z_abs.c' || echo '$(srcdir)/'`f2c/z_abs.c
+
+f2c/libf2c_la-d_sqrt.lo: f2c/d_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_sqrt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_sqrt.Tpo -c -o f2c/libf2c_la-d_sqrt.lo `test -f 'f2c/d_sqrt.c' || echo '$(srcdir)/'`f2c/d_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_sqrt.Tpo f2c/$(DEPDIR)/libf2c_la-d_sqrt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_sqrt.c' object='f2c/libf2c_la-d_sqrt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_sqrt.lo `test -f 'f2c/d_sqrt.c' || echo '$(srcdir)/'`f2c/d_sqrt.c
+
+f2c/libf2c_la-i_dnnt.lo: f2c/i_dnnt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_dnnt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_dnnt.Tpo -c -o f2c/libf2c_la-i_dnnt.lo `test -f 'f2c/i_dnnt.c' || echo '$(srcdir)/'`f2c/i_dnnt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_dnnt.Tpo f2c/$(DEPDIR)/libf2c_la-i_dnnt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_dnnt.c' object='f2c/libf2c_la-i_dnnt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_dnnt.lo `test -f 'f2c/i_dnnt.c' || echo '$(srcdir)/'`f2c/i_dnnt.c
+
+f2c/libf2c_la-r_int.lo: f2c/r_int.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_int.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_int.Tpo -c -o f2c/libf2c_la-r_int.lo `test -f 'f2c/r_int.c' || echo '$(srcdir)/'`f2c/r_int.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_int.Tpo f2c/$(DEPDIR)/libf2c_la-r_int.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_int.c' object='f2c/libf2c_la-r_int.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_int.lo `test -f 'f2c/r_int.c' || echo '$(srcdir)/'`f2c/r_int.c
+
+f2c/libf2c_la-z_cos.lo: f2c/z_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_cos.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_cos.Tpo -c -o f2c/libf2c_la-z_cos.lo `test -f 'f2c/z_cos.c' || echo '$(srcdir)/'`f2c/z_cos.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_cos.Tpo f2c/$(DEPDIR)/libf2c_la-z_cos.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_cos.c' object='f2c/libf2c_la-z_cos.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_cos.lo `test -f 'f2c/z_cos.c' || echo '$(srcdir)/'`f2c/z_cos.c
+
+f2c/libf2c_la-d_tan.lo: f2c/d_tan.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_tan.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_tan.Tpo -c -o f2c/libf2c_la-d_tan.lo `test -f 'f2c/d_tan.c' || echo '$(srcdir)/'`f2c/d_tan.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_tan.Tpo f2c/$(DEPDIR)/libf2c_la-d_tan.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_tan.c' object='f2c/libf2c_la-d_tan.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_tan.lo `test -f 'f2c/d_tan.c' || echo '$(srcdir)/'`f2c/d_tan.c
+
+f2c/libf2c_la-i_indx.lo: f2c/i_indx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_indx.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_indx.Tpo -c -o f2c/libf2c_la-i_indx.lo `test -f 'f2c/i_indx.c' || echo '$(srcdir)/'`f2c/i_indx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_indx.Tpo f2c/$(DEPDIR)/libf2c_la-i_indx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_indx.c' object='f2c/libf2c_la-i_indx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_indx.lo `test -f 'f2c/i_indx.c' || echo '$(srcdir)/'`f2c/i_indx.c
+
+f2c/libf2c_la-r_lg10.lo: f2c/r_lg10.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_lg10.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_lg10.Tpo -c -o f2c/libf2c_la-r_lg10.lo `test -f 'f2c/r_lg10.c' || echo '$(srcdir)/'`f2c/r_lg10.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_lg10.Tpo f2c/$(DEPDIR)/libf2c_la-r_lg10.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_lg10.c' object='f2c/libf2c_la-r_lg10.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_lg10.lo `test -f 'f2c/r_lg10.c' || echo '$(srcdir)/'`f2c/r_lg10.c
+
+f2c/libf2c_la-z_div.lo: f2c/z_div.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_div.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_div.Tpo -c -o f2c/libf2c_la-z_div.lo `test -f 'f2c/z_div.c' || echo '$(srcdir)/'`f2c/z_div.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_div.Tpo f2c/$(DEPDIR)/libf2c_la-z_div.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_div.c' object='f2c/libf2c_la-z_div.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_div.lo `test -f 'f2c/z_div.c' || echo '$(srcdir)/'`f2c/z_div.c
+
+f2c/libf2c_la-d_tanh.lo: f2c/d_tanh.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-d_tanh.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-d_tanh.Tpo -c -o f2c/libf2c_la-d_tanh.lo `test -f 'f2c/d_tanh.c' || echo '$(srcdir)/'`f2c/d_tanh.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-d_tanh.Tpo f2c/$(DEPDIR)/libf2c_la-d_tanh.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/d_tanh.c' object='f2c/libf2c_la-d_tanh.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-d_tanh.lo `test -f 'f2c/d_tanh.c' || echo '$(srcdir)/'`f2c/d_tanh.c
+
+f2c/libf2c_la-i_len.lo: f2c/i_len.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_len.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_len.Tpo -c -o f2c/libf2c_la-i_len.lo `test -f 'f2c/i_len.c' || echo '$(srcdir)/'`f2c/i_len.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_len.Tpo f2c/$(DEPDIR)/libf2c_la-i_len.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_len.c' object='f2c/libf2c_la-i_len.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_len.lo `test -f 'f2c/i_len.c' || echo '$(srcdir)/'`f2c/i_len.c
+
+f2c/libf2c_la-r_log.lo: f2c/r_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_log.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_log.Tpo -c -o f2c/libf2c_la-r_log.lo `test -f 'f2c/r_log.c' || echo '$(srcdir)/'`f2c/r_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_log.Tpo f2c/$(DEPDIR)/libf2c_la-r_log.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_log.c' object='f2c/libf2c_la-r_log.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_log.lo `test -f 'f2c/r_log.c' || echo '$(srcdir)/'`f2c/r_log.c
+
+f2c/libf2c_la-z_exp.lo: f2c/z_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_exp.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_exp.Tpo -c -o f2c/libf2c_la-z_exp.lo `test -f 'f2c/z_exp.c' || echo '$(srcdir)/'`f2c/z_exp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_exp.Tpo f2c/$(DEPDIR)/libf2c_la-z_exp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_exp.c' object='f2c/libf2c_la-z_exp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_exp.lo `test -f 'f2c/z_exp.c' || echo '$(srcdir)/'`f2c/z_exp.c
+
+f2c/libf2c_la-derf_.lo: f2c/derf_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-derf_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-derf_.Tpo -c -o f2c/libf2c_la-derf_.lo `test -f 'f2c/derf_.c' || echo '$(srcdir)/'`f2c/derf_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-derf_.Tpo f2c/$(DEPDIR)/libf2c_la-derf_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/derf_.c' object='f2c/libf2c_la-derf_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-derf_.lo `test -f 'f2c/derf_.c' || echo '$(srcdir)/'`f2c/derf_.c
+
+f2c/libf2c_la-i_mod.lo: f2c/i_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_mod.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_mod.Tpo -c -o f2c/libf2c_la-i_mod.lo `test -f 'f2c/i_mod.c' || echo '$(srcdir)/'`f2c/i_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_mod.Tpo f2c/$(DEPDIR)/libf2c_la-i_mod.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_mod.c' object='f2c/libf2c_la-i_mod.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_mod.lo `test -f 'f2c/i_mod.c' || echo '$(srcdir)/'`f2c/i_mod.c
+
+f2c/libf2c_la-r_mod.lo: f2c/r_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_mod.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_mod.Tpo -c -o f2c/libf2c_la-r_mod.lo `test -f 'f2c/r_mod.c' || echo '$(srcdir)/'`f2c/r_mod.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_mod.Tpo f2c/$(DEPDIR)/libf2c_la-r_mod.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_mod.c' object='f2c/libf2c_la-r_mod.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_mod.lo `test -f 'f2c/r_mod.c' || echo '$(srcdir)/'`f2c/r_mod.c
+
+f2c/libf2c_la-z_log.lo: f2c/z_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_log.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_log.Tpo -c -o f2c/libf2c_la-z_log.lo `test -f 'f2c/z_log.c' || echo '$(srcdir)/'`f2c/z_log.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_log.Tpo f2c/$(DEPDIR)/libf2c_la-z_log.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_log.c' object='f2c/libf2c_la-z_log.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_log.lo `test -f 'f2c/z_log.c' || echo '$(srcdir)/'`f2c/z_log.c
+
+f2c/libf2c_la-derfc_.lo: f2c/derfc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-derfc_.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-derfc_.Tpo -c -o f2c/libf2c_la-derfc_.lo `test -f 'f2c/derfc_.c' || echo '$(srcdir)/'`f2c/derfc_.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-derfc_.Tpo f2c/$(DEPDIR)/libf2c_la-derfc_.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/derfc_.c' object='f2c/libf2c_la-derfc_.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-derfc_.lo `test -f 'f2c/derfc_.c' || echo '$(srcdir)/'`f2c/derfc_.c
+
+f2c/libf2c_la-i_nint.lo: f2c/i_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_nint.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_nint.Tpo -c -o f2c/libf2c_la-i_nint.lo `test -f 'f2c/i_nint.c' || echo '$(srcdir)/'`f2c/i_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_nint.Tpo f2c/$(DEPDIR)/libf2c_la-i_nint.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_nint.c' object='f2c/libf2c_la-i_nint.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_nint.lo `test -f 'f2c/i_nint.c' || echo '$(srcdir)/'`f2c/i_nint.c
+
+f2c/libf2c_la-r_nint.lo: f2c/r_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_nint.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_nint.Tpo -c -o f2c/libf2c_la-r_nint.lo `test -f 'f2c/r_nint.c' || echo '$(srcdir)/'`f2c/r_nint.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_nint.Tpo f2c/$(DEPDIR)/libf2c_la-r_nint.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_nint.c' object='f2c/libf2c_la-r_nint.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_nint.lo `test -f 'f2c/r_nint.c' || echo '$(srcdir)/'`f2c/r_nint.c
+
+f2c/libf2c_la-z_sin.lo: f2c/z_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_sin.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_sin.Tpo -c -o f2c/libf2c_la-z_sin.lo `test -f 'f2c/z_sin.c' || echo '$(srcdir)/'`f2c/z_sin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_sin.Tpo f2c/$(DEPDIR)/libf2c_la-z_sin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_sin.c' object='f2c/libf2c_la-z_sin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_sin.lo `test -f 'f2c/z_sin.c' || echo '$(srcdir)/'`f2c/z_sin.c
+
+f2c/libf2c_la-dfe.lo: f2c/dfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-dfe.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-dfe.Tpo -c -o f2c/libf2c_la-dfe.lo `test -f 'f2c/dfe.c' || echo '$(srcdir)/'`f2c/dfe.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-dfe.Tpo f2c/$(DEPDIR)/libf2c_la-dfe.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/dfe.c' object='f2c/libf2c_la-dfe.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-dfe.lo `test -f 'f2c/dfe.c' || echo '$(srcdir)/'`f2c/dfe.c
+
+f2c/libf2c_la-i_sign.lo: f2c/i_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-i_sign.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-i_sign.Tpo -c -o f2c/libf2c_la-i_sign.lo `test -f 'f2c/i_sign.c' || echo '$(srcdir)/'`f2c/i_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-i_sign.Tpo f2c/$(DEPDIR)/libf2c_la-i_sign.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/i_sign.c' object='f2c/libf2c_la-i_sign.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-i_sign.lo `test -f 'f2c/i_sign.c' || echo '$(srcdir)/'`f2c/i_sign.c
+
+f2c/libf2c_la-r_sign.lo: f2c/r_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-r_sign.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-r_sign.Tpo -c -o f2c/libf2c_la-r_sign.lo `test -f 'f2c/r_sign.c' || echo '$(srcdir)/'`f2c/r_sign.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-r_sign.Tpo f2c/$(DEPDIR)/libf2c_la-r_sign.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/r_sign.c' object='f2c/libf2c_la-r_sign.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-r_sign.lo `test -f 'f2c/r_sign.c' || echo '$(srcdir)/'`f2c/r_sign.c
+
+f2c/libf2c_la-z_sqrt.lo: f2c/z_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -MT f2c/libf2c_la-z_sqrt.lo -MD -MP -MF f2c/$(DEPDIR)/libf2c_la-z_sqrt.Tpo -c -o f2c/libf2c_la-z_sqrt.lo `test -f 'f2c/z_sqrt.c' || echo '$(srcdir)/'`f2c/z_sqrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) f2c/$(DEPDIR)/libf2c_la-z_sqrt.Tpo f2c/$(DEPDIR)/libf2c_la-z_sqrt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='f2c/z_sqrt.c' object='f2c/libf2c_la-z_sqrt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libf2c_la_CFLAGS) $(CFLAGS) -c -o f2c/libf2c_la-z_sqrt.lo `test -f 'f2c/z_sqrt.c' || echo '$(srcdir)/'`f2c/z_sqrt.c
+
+../optional/glpk/libglpk_la-glpapi01.lo: ../optional/glpk/glpapi01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi01.Tpo -c -o ../optional/glpk/libglpk_la-glpapi01.lo `test -f '../optional/glpk/glpapi01.c' || echo '$(srcdir)/'`../optional/glpk/glpapi01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi01.c' object='../optional/glpk/libglpk_la-glpapi01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi01.lo `test -f '../optional/glpk/glpapi01.c' || echo '$(srcdir)/'`../optional/glpk/glpapi01.c
+
+../optional/glpk/libglpk_la-glpapi02.lo: ../optional/glpk/glpapi02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi02.Tpo -c -o ../optional/glpk/libglpk_la-glpapi02.lo `test -f '../optional/glpk/glpapi02.c' || echo '$(srcdir)/'`../optional/glpk/glpapi02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi02.c' object='../optional/glpk/libglpk_la-glpapi02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi02.lo `test -f '../optional/glpk/glpapi02.c' || echo '$(srcdir)/'`../optional/glpk/glpapi02.c
+
+../optional/glpk/libglpk_la-glpapi03.lo: ../optional/glpk/glpapi03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi03.Tpo -c -o ../optional/glpk/libglpk_la-glpapi03.lo `test -f '../optional/glpk/glpapi03.c' || echo '$(srcdir)/'`../optional/glpk/glpapi03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi03.c' object='../optional/glpk/libglpk_la-glpapi03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi03.lo `test -f '../optional/glpk/glpapi03.c' || echo '$(srcdir)/'`../optional/glpk/glpapi03.c
+
+../optional/glpk/libglpk_la-glpapi04.lo: ../optional/glpk/glpapi04.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi04.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi04.Tpo -c -o ../optional/glpk/libglpk_la-glpapi04.lo `test -f '../optional/glpk/glpapi04.c' || echo '$(srcdir)/'`../optional/glpk/glpapi04.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi04.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi04.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi04.c' object='../optional/glpk/libglpk_la-glpapi04.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi04.lo `test -f '../optional/glpk/glpapi04.c' || echo '$(srcdir)/'`../optional/glpk/glpapi04.c
+
+../optional/glpk/libglpk_la-glpapi05.lo: ../optional/glpk/glpapi05.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi05.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi05.Tpo -c -o ../optional/glpk/libglpk_la-glpapi05.lo `test -f '../optional/glpk/glpapi05.c' || echo '$(srcdir)/'`../optional/glpk/glpapi05.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi05.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi05.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi05.c' object='../optional/glpk/libglpk_la-glpapi05.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi05.lo `test -f '../optional/glpk/glpapi05.c' || echo '$(srcdir)/'`../optional/glpk/glpapi05.c
+
+../optional/glpk/libglpk_la-glpapi06.lo: ../optional/glpk/glpapi06.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi06.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi06.Tpo -c -o ../optional/glpk/libglpk_la-glpapi06.lo `test -f '../optional/glpk/glpapi06.c' || echo '$(srcdir)/'`../optional/glpk/glpapi06.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi06.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi06.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi06.c' object='../optional/glpk/libglpk_la-glpapi06.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi06.lo `test -f '../optional/glpk/glpapi06.c' || echo '$(srcdir)/'`../optional/glpk/glpapi06.c
+
+../optional/glpk/libglpk_la-glpapi07.lo: ../optional/glpk/glpapi07.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi07.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi07.Tpo -c -o ../optional/glpk/libglpk_la-glpapi07.lo `test -f '../optional/glpk/glpapi07.c' || echo '$(srcdir)/'`../optional/glpk/glpapi07.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi07.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi07.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi07.c' object='../optional/glpk/libglpk_la-glpapi07.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi07.lo `test -f '../optional/glpk/glpapi07.c' || echo '$(srcdir)/'`../optional/glpk/glpapi07.c
+
+../optional/glpk/libglpk_la-glpapi08.lo: ../optional/glpk/glpapi08.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi08.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi08.Tpo -c -o ../optional/glpk/libglpk_la-glpapi08.lo `test -f '../optional/glpk/glpapi08.c' || echo '$(srcdir)/'`../optional/glpk/glpapi08.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi08.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi08.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi08.c' object='../optional/glpk/libglpk_la-glpapi08.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi08.lo `test -f '../optional/glpk/glpapi08.c' || echo '$(srcdir)/'`../optional/glpk/glpapi08.c
+
+../optional/glpk/libglpk_la-glpapi09.lo: ../optional/glpk/glpapi09.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi09.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi09.Tpo -c -o ../optional/glpk/libglpk_la-glpapi09.lo `test -f '../optional/glpk/glpapi09.c' || echo '$(srcdir)/'`../optional/glpk/glpapi09.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi09.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi09.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi09.c' object='../optional/glpk/libglpk_la-glpapi09.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi09.lo `test -f '../optional/glpk/glpapi09.c' || echo '$(srcdir)/'`../optional/glpk/glpapi09.c
+
+../optional/glpk/libglpk_la-glpapi10.lo: ../optional/glpk/glpapi10.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi10.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi10.Tpo -c -o ../optional/glpk/libglpk_la-glpapi10.lo `test -f '../optional/glpk/glpapi10.c' || echo '$(srcdir)/'`../optional/glpk/glpapi10.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi10.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi10.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi10.c' object='../optional/glpk/libglpk_la-glpapi10.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi10.lo `test -f '../optional/glpk/glpapi10.c' || echo '$(srcdir)/'`../optional/glpk/glpapi10.c
+
+../optional/glpk/libglpk_la-glpapi11.lo: ../optional/glpk/glpapi11.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi11.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi11.Tpo -c -o ../optional/glpk/libglpk_la-glpapi11.lo `test -f '../optional/glpk/glpapi11.c' || echo '$(srcdir)/'`../optional/glpk/glpapi11.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi11.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi11.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi11.c' object='../optional/glpk/libglpk_la-glpapi11.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi11.lo `test -f '../optional/glpk/glpapi11.c' || echo '$(srcdir)/'`../optional/glpk/glpapi11.c
+
+../optional/glpk/libglpk_la-glpapi12.lo: ../optional/glpk/glpapi12.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi12.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi12.Tpo -c -o ../optional/glpk/libglpk_la-glpapi12.lo `test -f '../optional/glpk/glpapi12.c' || echo '$(srcdir)/'`../optional/glpk/glpapi12.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi12.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi12.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi12.c' object='../optional/glpk/libglpk_la-glpapi12.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi12.lo `test -f '../optional/glpk/glpapi12.c' || echo '$(srcdir)/'`../optional/glpk/glpapi12.c
+
+../optional/glpk/libglpk_la-glpapi13.lo: ../optional/glpk/glpapi13.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi13.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi13.Tpo -c -o ../optional/glpk/libglpk_la-glpapi13.lo `test -f '../optional/glpk/glpapi13.c' || echo '$(srcdir)/'`../optional/glpk/glpapi13.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi13.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi13.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi13.c' object='../optional/glpk/libglpk_la-glpapi13.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi13.lo `test -f '../optional/glpk/glpapi13.c' || echo '$(srcdir)/'`../optional/glpk/glpapi13.c
+
+../optional/glpk/libglpk_la-glpapi14.lo: ../optional/glpk/glpapi14.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi14.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi14.Tpo -c -o ../optional/glpk/libglpk_la-glpapi14.lo `test -f '../optional/glpk/glpapi14.c' || echo '$(srcdir)/'`../optional/glpk/glpapi14.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi14.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi14.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi14.c' object='../optional/glpk/libglpk_la-glpapi14.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi14.lo `test -f '../optional/glpk/glpapi14.c' || echo '$(srcdir)/'`../optional/glpk/glpapi14.c
+
+../optional/glpk/libglpk_la-glpapi15.lo: ../optional/glpk/glpapi15.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi15.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi15.Tpo -c -o ../optional/glpk/libglpk_la-glpapi15.lo `test -f '../optional/glpk/glpapi15.c' || echo '$(srcdir)/'`../optional/glpk/glpapi15.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi15.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi15.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi15.c' object='../optional/glpk/libglpk_la-glpapi15.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi15.lo `test -f '../optional/glpk/glpapi15.c' || echo '$(srcdir)/'`../optional/glpk/glpapi15.c
+
+../optional/glpk/libglpk_la-glpapi16.lo: ../optional/glpk/glpapi16.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi16.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi16.Tpo -c -o ../optional/glpk/libglpk_la-glpapi16.lo `test -f '../optional/glpk/glpapi16.c' || echo '$(srcdir)/'`../optional/glpk/glpapi16.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi16.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi16.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi16.c' object='../optional/glpk/libglpk_la-glpapi16.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi16.lo `test -f '../optional/glpk/glpapi16.c' || echo '$(srcdir)/'`../optional/glpk/glpapi16.c
+
+../optional/glpk/libglpk_la-glpapi17.lo: ../optional/glpk/glpapi17.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi17.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi17.Tpo -c -o ../optional/glpk/libglpk_la-glpapi17.lo `test -f '../optional/glpk/glpapi17.c' || echo '$(srcdir)/'`../optional/glpk/glpapi17.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi17.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi17.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi17.c' object='../optional/glpk/libglpk_la-glpapi17.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi17.lo `test -f '../optional/glpk/glpapi17.c' || echo '$(srcdir)/'`../optional/glpk/glpapi17.c
+
+../optional/glpk/libglpk_la-glpapi18.lo: ../optional/glpk/glpapi18.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi18.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi18.Tpo -c -o ../optional/glpk/libglpk_la-glpapi18.lo `test -f '../optional/glpk/glpapi18.c' || echo '$(srcdir)/'`../optional/glpk/glpapi18.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi18.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi18.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi18.c' object='../optional/glpk/libglpk_la-glpapi18.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi18.lo `test -f '../optional/glpk/glpapi18.c' || echo '$(srcdir)/'`../optional/glpk/glpapi18.c
+
+../optional/glpk/libglpk_la-glpapi19.lo: ../optional/glpk/glpapi19.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpapi19.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi19.Tpo -c -o ../optional/glpk/libglpk_la-glpapi19.lo `test -f '../optional/glpk/glpapi19.c' || echo '$(srcdir)/'`../optional/glpk/glpapi19.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi19.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpapi19.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpapi19.c' object='../optional/glpk/libglpk_la-glpapi19.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpapi19.lo `test -f '../optional/glpk/glpapi19.c' || echo '$(srcdir)/'`../optional/glpk/glpapi19.c
+
+../optional/glpk/libglpk_la-glpavl.lo: ../optional/glpk/glpavl.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpavl.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpavl.Tpo -c -o ../optional/glpk/libglpk_la-glpavl.lo `test -f '../optional/glpk/glpavl.c' || echo '$(srcdir)/'`../optional/glpk/glpavl.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpavl.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpavl.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpavl.c' object='../optional/glpk/libglpk_la-glpavl.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpavl.lo `test -f '../optional/glpk/glpavl.c' || echo '$(srcdir)/'`../optional/glpk/glpavl.c
+
+../optional/glpk/libglpk_la-glpbfd.lo: ../optional/glpk/glpbfd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpbfd.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfd.Tpo -c -o ../optional/glpk/libglpk_la-glpbfd.lo `test -f '../optional/glpk/glpbfd.c' || echo '$(srcdir)/'`../optional/glpk/glpbfd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfd.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpbfd.c' object='../optional/glpk/libglpk_la-glpbfd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpbfd.lo `test -f '../optional/glpk/glpbfd.c' || echo '$(srcdir)/'`../optional/glpk/glpbfd.c
+
+../optional/glpk/libglpk_la-glpbfx.lo: ../optional/glpk/glpbfx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpbfx.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfx.Tpo -c -o ../optional/glpk/libglpk_la-glpbfx.lo `test -f '../optional/glpk/glpbfx.c' || echo '$(srcdir)/'`../optional/glpk/glpbfx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfx.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpbfx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpbfx.c' object='../optional/glpk/libglpk_la-glpbfx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpbfx.lo `test -f '../optional/glpk/glpbfx.c' || echo '$(srcdir)/'`../optional/glpk/glpbfx.c
+
+../optional/glpk/libglpk_la-glpcpx.lo: ../optional/glpk/glpcpx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpcpx.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpcpx.Tpo -c -o ../optional/glpk/libglpk_la-glpcpx.lo `test -f '../optional/glpk/glpcpx.c' || echo '$(srcdir)/'`../optional/glpk/glpcpx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpcpx.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpcpx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpcpx.c' object='../optional/glpk/libglpk_la-glpcpx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpcpx.lo `test -f '../optional/glpk/glpcpx.c' || echo '$(srcdir)/'`../optional/glpk/glpcpx.c
+
+../optional/glpk/libglpk_la-glpdmp.lo: ../optional/glpk/glpdmp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpdmp.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmp.Tpo -c -o ../optional/glpk/libglpk_la-glpdmp.lo `test -f '../optional/glpk/glpdmp.c' || echo '$(srcdir)/'`../optional/glpk/glpdmp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmp.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpdmp.c' object='../optional/glpk/libglpk_la-glpdmp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpdmp.lo `test -f '../optional/glpk/glpdmp.c' || echo '$(srcdir)/'`../optional/glpk/glpdmp.c
+
+../optional/glpk/libglpk_la-glpdmx.lo: ../optional/glpk/glpdmx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpdmx.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmx.Tpo -c -o ../optional/glpk/libglpk_la-glpdmx.lo `test -f '../optional/glpk/glpdmx.c' || echo '$(srcdir)/'`../optional/glpk/glpdmx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmx.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpdmx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpdmx.c' object='../optional/glpk/libglpk_la-glpdmx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpdmx.lo `test -f '../optional/glpk/glpdmx.c' || echo '$(srcdir)/'`../optional/glpk/glpdmx.c
+
+../optional/glpk/libglpk_la-glpenv01.lo: ../optional/glpk/glpenv01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv01.Tpo -c -o ../optional/glpk/libglpk_la-glpenv01.lo `test -f '../optional/glpk/glpenv01.c' || echo '$(srcdir)/'`../optional/glpk/glpenv01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv01.c' object='../optional/glpk/libglpk_la-glpenv01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv01.lo `test -f '../optional/glpk/glpenv01.c' || echo '$(srcdir)/'`../optional/glpk/glpenv01.c
+
+../optional/glpk/libglpk_la-glpenv02.lo: ../optional/glpk/glpenv02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv02.Tpo -c -o ../optional/glpk/libglpk_la-glpenv02.lo `test -f '../optional/glpk/glpenv02.c' || echo '$(srcdir)/'`../optional/glpk/glpenv02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv02.c' object='../optional/glpk/libglpk_la-glpenv02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv02.lo `test -f '../optional/glpk/glpenv02.c' || echo '$(srcdir)/'`../optional/glpk/glpenv02.c
+
+../optional/glpk/libglpk_la-glpenv03.lo: ../optional/glpk/glpenv03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv03.Tpo -c -o ../optional/glpk/libglpk_la-glpenv03.lo `test -f '../optional/glpk/glpenv03.c' || echo '$(srcdir)/'`../optional/glpk/glpenv03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv03.c' object='../optional/glpk/libglpk_la-glpenv03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv03.lo `test -f '../optional/glpk/glpenv03.c' || echo '$(srcdir)/'`../optional/glpk/glpenv03.c
+
+../optional/glpk/libglpk_la-glpenv04.lo: ../optional/glpk/glpenv04.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv04.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv04.Tpo -c -o ../optional/glpk/libglpk_la-glpenv04.lo `test -f '../optional/glpk/glpenv04.c' || echo '$(srcdir)/'`../optional/glpk/glpenv04.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv04.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv04.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv04.c' object='../optional/glpk/libglpk_la-glpenv04.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv04.lo `test -f '../optional/glpk/glpenv04.c' || echo '$(srcdir)/'`../optional/glpk/glpenv04.c
+
+../optional/glpk/libglpk_la-glpenv05.lo: ../optional/glpk/glpenv05.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv05.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv05.Tpo -c -o ../optional/glpk/libglpk_la-glpenv05.lo `test -f '../optional/glpk/glpenv05.c' || echo '$(srcdir)/'`../optional/glpk/glpenv05.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv05.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv05.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv05.c' object='../optional/glpk/libglpk_la-glpenv05.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv05.lo `test -f '../optional/glpk/glpenv05.c' || echo '$(srcdir)/'`../optional/glpk/glpenv05.c
+
+../optional/glpk/libglpk_la-glpenv06.lo: ../optional/glpk/glpenv06.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv06.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv06.Tpo -c -o ../optional/glpk/libglpk_la-glpenv06.lo `test -f '../optional/glpk/glpenv06.c' || echo '$(srcdir)/'`../optional/glpk/glpenv06.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv06.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv06.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv06.c' object='../optional/glpk/libglpk_la-glpenv06.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv06.lo `test -f '../optional/glpk/glpenv06.c' || echo '$(srcdir)/'`../optional/glpk/glpenv06.c
+
+../optional/glpk/libglpk_la-glpenv07.lo: ../optional/glpk/glpenv07.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv07.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv07.Tpo -c -o ../optional/glpk/libglpk_la-glpenv07.lo `test -f '../optional/glpk/glpenv07.c' || echo '$(srcdir)/'`../optional/glpk/glpenv07.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv07.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv07.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv07.c' object='../optional/glpk/libglpk_la-glpenv07.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv07.lo `test -f '../optional/glpk/glpenv07.c' || echo '$(srcdir)/'`../optional/glpk/glpenv07.c
+
+../optional/glpk/libglpk_la-glpenv08.lo: ../optional/glpk/glpenv08.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpenv08.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv08.Tpo -c -o ../optional/glpk/libglpk_la-glpenv08.lo `test -f '../optional/glpk/glpenv08.c' || echo '$(srcdir)/'`../optional/glpk/glpenv08.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv08.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpenv08.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpenv08.c' object='../optional/glpk/libglpk_la-glpenv08.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpenv08.lo `test -f '../optional/glpk/glpenv08.c' || echo '$(srcdir)/'`../optional/glpk/glpenv08.c
+
+../optional/glpk/libglpk_la-glpfhv.lo: ../optional/glpk/glpfhv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpfhv.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpfhv.Tpo -c -o ../optional/glpk/libglpk_la-glpfhv.lo `test -f '../optional/glpk/glpfhv.c' || echo '$(srcdir)/'`../optional/glpk/glpfhv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpfhv.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpfhv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpfhv.c' object='../optional/glpk/libglpk_la-glpfhv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpfhv.lo `test -f '../optional/glpk/glpfhv.c' || echo '$(srcdir)/'`../optional/glpk/glpfhv.c
+
+../optional/glpk/libglpk_la-glpgmp.lo: ../optional/glpk/glpgmp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpgmp.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpgmp.Tpo -c -o ../optional/glpk/libglpk_la-glpgmp.lo `test -f '../optional/glpk/glpgmp.c' || echo '$(srcdir)/'`../optional/glpk/glpgmp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpgmp.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpgmp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpgmp.c' object='../optional/glpk/libglpk_la-glpgmp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpgmp.lo `test -f '../optional/glpk/glpgmp.c' || echo '$(srcdir)/'`../optional/glpk/glpgmp.c
+
+../optional/glpk/libglpk_la-glphbm.lo: ../optional/glpk/glphbm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glphbm.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glphbm.Tpo -c -o ../optional/glpk/libglpk_la-glphbm.lo `test -f '../optional/glpk/glphbm.c' || echo '$(srcdir)/'`../optional/glpk/glphbm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glphbm.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glphbm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glphbm.c' object='../optional/glpk/libglpk_la-glphbm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glphbm.lo `test -f '../optional/glpk/glphbm.c' || echo '$(srcdir)/'`../optional/glpk/glphbm.c
+
+../optional/glpk/libglpk_la-glpini01.lo: ../optional/glpk/glpini01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpini01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpini01.Tpo -c -o ../optional/glpk/libglpk_la-glpini01.lo `test -f '../optional/glpk/glpini01.c' || echo '$(srcdir)/'`../optional/glpk/glpini01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpini01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpini01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpini01.c' object='../optional/glpk/libglpk_la-glpini01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpini01.lo `test -f '../optional/glpk/glpini01.c' || echo '$(srcdir)/'`../optional/glpk/glpini01.c
+
+../optional/glpk/libglpk_la-glpini02.lo: ../optional/glpk/glpini02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpini02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpini02.Tpo -c -o ../optional/glpk/libglpk_la-glpini02.lo `test -f '../optional/glpk/glpini02.c' || echo '$(srcdir)/'`../optional/glpk/glpini02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpini02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpini02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpini02.c' object='../optional/glpk/libglpk_la-glpini02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpini02.lo `test -f '../optional/glpk/glpini02.c' || echo '$(srcdir)/'`../optional/glpk/glpini02.c
+
+../optional/glpk/libglpk_la-glpios01.lo: ../optional/glpk/glpios01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios01.Tpo -c -o ../optional/glpk/libglpk_la-glpios01.lo `test -f '../optional/glpk/glpios01.c' || echo '$(srcdir)/'`../optional/glpk/glpios01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios01.c' object='../optional/glpk/libglpk_la-glpios01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios01.lo `test -f '../optional/glpk/glpios01.c' || echo '$(srcdir)/'`../optional/glpk/glpios01.c
+
+../optional/glpk/libglpk_la-glpios02.lo: ../optional/glpk/glpios02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios02.Tpo -c -o ../optional/glpk/libglpk_la-glpios02.lo `test -f '../optional/glpk/glpios02.c' || echo '$(srcdir)/'`../optional/glpk/glpios02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios02.c' object='../optional/glpk/libglpk_la-glpios02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios02.lo `test -f '../optional/glpk/glpios02.c' || echo '$(srcdir)/'`../optional/glpk/glpios02.c
+
+../optional/glpk/libglpk_la-glpios03.lo: ../optional/glpk/glpios03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios03.Tpo -c -o ../optional/glpk/libglpk_la-glpios03.lo `test -f '../optional/glpk/glpios03.c' || echo '$(srcdir)/'`../optional/glpk/glpios03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios03.c' object='../optional/glpk/libglpk_la-glpios03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios03.lo `test -f '../optional/glpk/glpios03.c' || echo '$(srcdir)/'`../optional/glpk/glpios03.c
+
+../optional/glpk/libglpk_la-glpios04.lo: ../optional/glpk/glpios04.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios04.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios04.Tpo -c -o ../optional/glpk/libglpk_la-glpios04.lo `test -f '../optional/glpk/glpios04.c' || echo '$(srcdir)/'`../optional/glpk/glpios04.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios04.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios04.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios04.c' object='../optional/glpk/libglpk_la-glpios04.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios04.lo `test -f '../optional/glpk/glpios04.c' || echo '$(srcdir)/'`../optional/glpk/glpios04.c
+
+../optional/glpk/libglpk_la-glpios05.lo: ../optional/glpk/glpios05.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios05.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios05.Tpo -c -o ../optional/glpk/libglpk_la-glpios05.lo `test -f '../optional/glpk/glpios05.c' || echo '$(srcdir)/'`../optional/glpk/glpios05.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios05.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios05.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios05.c' object='../optional/glpk/libglpk_la-glpios05.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios05.lo `test -f '../optional/glpk/glpios05.c' || echo '$(srcdir)/'`../optional/glpk/glpios05.c
+
+../optional/glpk/libglpk_la-glpios06.lo: ../optional/glpk/glpios06.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios06.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios06.Tpo -c -o ../optional/glpk/libglpk_la-glpios06.lo `test -f '../optional/glpk/glpios06.c' || echo '$(srcdir)/'`../optional/glpk/glpios06.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios06.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios06.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios06.c' object='../optional/glpk/libglpk_la-glpios06.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios06.lo `test -f '../optional/glpk/glpios06.c' || echo '$(srcdir)/'`../optional/glpk/glpios06.c
+
+../optional/glpk/libglpk_la-glpios07.lo: ../optional/glpk/glpios07.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios07.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios07.Tpo -c -o ../optional/glpk/libglpk_la-glpios07.lo `test -f '../optional/glpk/glpios07.c' || echo '$(srcdir)/'`../optional/glpk/glpios07.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios07.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios07.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios07.c' object='../optional/glpk/libglpk_la-glpios07.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios07.lo `test -f '../optional/glpk/glpios07.c' || echo '$(srcdir)/'`../optional/glpk/glpios07.c
+
+../optional/glpk/libglpk_la-glpios08.lo: ../optional/glpk/glpios08.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios08.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios08.Tpo -c -o ../optional/glpk/libglpk_la-glpios08.lo `test -f '../optional/glpk/glpios08.c' || echo '$(srcdir)/'`../optional/glpk/glpios08.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios08.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios08.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios08.c' object='../optional/glpk/libglpk_la-glpios08.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios08.lo `test -f '../optional/glpk/glpios08.c' || echo '$(srcdir)/'`../optional/glpk/glpios08.c
+
+../optional/glpk/libglpk_la-glpios09.lo: ../optional/glpk/glpios09.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios09.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios09.Tpo -c -o ../optional/glpk/libglpk_la-glpios09.lo `test -f '../optional/glpk/glpios09.c' || echo '$(srcdir)/'`../optional/glpk/glpios09.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios09.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios09.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios09.c' object='../optional/glpk/libglpk_la-glpios09.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios09.lo `test -f '../optional/glpk/glpios09.c' || echo '$(srcdir)/'`../optional/glpk/glpios09.c
+
+../optional/glpk/libglpk_la-glpios10.lo: ../optional/glpk/glpios10.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios10.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios10.Tpo -c -o ../optional/glpk/libglpk_la-glpios10.lo `test -f '../optional/glpk/glpios10.c' || echo '$(srcdir)/'`../optional/glpk/glpios10.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios10.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios10.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios10.c' object='../optional/glpk/libglpk_la-glpios10.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios10.lo `test -f '../optional/glpk/glpios10.c' || echo '$(srcdir)/'`../optional/glpk/glpios10.c
+
+../optional/glpk/libglpk_la-glpios11.lo: ../optional/glpk/glpios11.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios11.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios11.Tpo -c -o ../optional/glpk/libglpk_la-glpios11.lo `test -f '../optional/glpk/glpios11.c' || echo '$(srcdir)/'`../optional/glpk/glpios11.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios11.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios11.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios11.c' object='../optional/glpk/libglpk_la-glpios11.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios11.lo `test -f '../optional/glpk/glpios11.c' || echo '$(srcdir)/'`../optional/glpk/glpios11.c
+
+../optional/glpk/libglpk_la-glpios12.lo: ../optional/glpk/glpios12.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpios12.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpios12.Tpo -c -o ../optional/glpk/libglpk_la-glpios12.lo `test -f '../optional/glpk/glpios12.c' || echo '$(srcdir)/'`../optional/glpk/glpios12.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpios12.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpios12.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpios12.c' object='../optional/glpk/libglpk_la-glpios12.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpios12.lo `test -f '../optional/glpk/glpios12.c' || echo '$(srcdir)/'`../optional/glpk/glpios12.c
+
+../optional/glpk/libglpk_la-glpipm.lo: ../optional/glpk/glpipm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpipm.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpipm.Tpo -c -o ../optional/glpk/libglpk_la-glpipm.lo `test -f '../optional/glpk/glpipm.c' || echo '$(srcdir)/'`../optional/glpk/glpipm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpipm.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpipm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpipm.c' object='../optional/glpk/libglpk_la-glpipm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpipm.lo `test -f '../optional/glpk/glpipm.c' || echo '$(srcdir)/'`../optional/glpk/glpipm.c
+
+../optional/glpk/libglpk_la-glplib01.lo: ../optional/glpk/glplib01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplib01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplib01.Tpo -c -o ../optional/glpk/libglpk_la-glplib01.lo `test -f '../optional/glpk/glplib01.c' || echo '$(srcdir)/'`../optional/glpk/glplib01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplib01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplib01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplib01.c' object='../optional/glpk/libglpk_la-glplib01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplib01.lo `test -f '../optional/glpk/glplib01.c' || echo '$(srcdir)/'`../optional/glpk/glplib01.c
+
+../optional/glpk/libglpk_la-glplib02.lo: ../optional/glpk/glplib02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplib02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplib02.Tpo -c -o ../optional/glpk/libglpk_la-glplib02.lo `test -f '../optional/glpk/glplib02.c' || echo '$(srcdir)/'`../optional/glpk/glplib02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplib02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplib02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplib02.c' object='../optional/glpk/libglpk_la-glplib02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplib02.lo `test -f '../optional/glpk/glplib02.c' || echo '$(srcdir)/'`../optional/glpk/glplib02.c
+
+../optional/glpk/libglpk_la-glplib03.lo: ../optional/glpk/glplib03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplib03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplib03.Tpo -c -o ../optional/glpk/libglpk_la-glplib03.lo `test -f '../optional/glpk/glplib03.c' || echo '$(srcdir)/'`../optional/glpk/glplib03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplib03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplib03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplib03.c' object='../optional/glpk/libglpk_la-glplib03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplib03.lo `test -f '../optional/glpk/glplib03.c' || echo '$(srcdir)/'`../optional/glpk/glplib03.c
+
+../optional/glpk/libglpk_la-glplpf.lo: ../optional/glpk/glplpf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplpf.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplpf.Tpo -c -o ../optional/glpk/libglpk_la-glplpf.lo `test -f '../optional/glpk/glplpf.c' || echo '$(srcdir)/'`../optional/glpk/glplpf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplpf.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplpf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplpf.c' object='../optional/glpk/libglpk_la-glplpf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplpf.lo `test -f '../optional/glpk/glplpf.c' || echo '$(srcdir)/'`../optional/glpk/glplpf.c
+
+../optional/glpk/libglpk_la-glplpx01.lo: ../optional/glpk/glplpx01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplpx01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx01.Tpo -c -o ../optional/glpk/libglpk_la-glplpx01.lo `test -f '../optional/glpk/glplpx01.c' || echo '$(srcdir)/'`../optional/glpk/glplpx01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplpx01.c' object='../optional/glpk/libglpk_la-glplpx01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplpx01.lo `test -f '../optional/glpk/glplpx01.c' || echo '$(srcdir)/'`../optional/glpk/glplpx01.c
+
+../optional/glpk/libglpk_la-glplpx02.lo: ../optional/glpk/glplpx02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplpx02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx02.Tpo -c -o ../optional/glpk/libglpk_la-glplpx02.lo `test -f '../optional/glpk/glplpx02.c' || echo '$(srcdir)/'`../optional/glpk/glplpx02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplpx02.c' object='../optional/glpk/libglpk_la-glplpx02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplpx02.lo `test -f '../optional/glpk/glplpx02.c' || echo '$(srcdir)/'`../optional/glpk/glplpx02.c
+
+../optional/glpk/libglpk_la-glplpx03.lo: ../optional/glpk/glplpx03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplpx03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx03.Tpo -c -o ../optional/glpk/libglpk_la-glplpx03.lo `test -f '../optional/glpk/glplpx03.c' || echo '$(srcdir)/'`../optional/glpk/glplpx03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplpx03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplpx03.c' object='../optional/glpk/libglpk_la-glplpx03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplpx03.lo `test -f '../optional/glpk/glplpx03.c' || echo '$(srcdir)/'`../optional/glpk/glplpx03.c
+
+../optional/glpk/libglpk_la-glpluf.lo: ../optional/glpk/glpluf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpluf.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpluf.Tpo -c -o ../optional/glpk/libglpk_la-glpluf.lo `test -f '../optional/glpk/glpluf.c' || echo '$(srcdir)/'`../optional/glpk/glpluf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpluf.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpluf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpluf.c' object='../optional/glpk/libglpk_la-glpluf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpluf.lo `test -f '../optional/glpk/glpluf.c' || echo '$(srcdir)/'`../optional/glpk/glpluf.c
+
+../optional/glpk/libglpk_la-glplux.lo: ../optional/glpk/glplux.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glplux.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glplux.Tpo -c -o ../optional/glpk/libglpk_la-glplux.lo `test -f '../optional/glpk/glplux.c' || echo '$(srcdir)/'`../optional/glpk/glplux.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glplux.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glplux.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glplux.c' object='../optional/glpk/libglpk_la-glplux.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glplux.lo `test -f '../optional/glpk/glplux.c' || echo '$(srcdir)/'`../optional/glpk/glplux.c
+
+../optional/glpk/libglpk_la-glpmat.lo: ../optional/glpk/glpmat.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmat.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmat.Tpo -c -o ../optional/glpk/libglpk_la-glpmat.lo `test -f '../optional/glpk/glpmat.c' || echo '$(srcdir)/'`../optional/glpk/glpmat.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmat.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmat.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmat.c' object='../optional/glpk/libglpk_la-glpmat.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmat.lo `test -f '../optional/glpk/glpmat.c' || echo '$(srcdir)/'`../optional/glpk/glpmat.c
+
+../optional/glpk/libglpk_la-glpmpl01.lo: ../optional/glpk/glpmpl01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmpl01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl01.Tpo -c -o ../optional/glpk/libglpk_la-glpmpl01.lo `test -f '../optional/glpk/glpmpl01.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmpl01.c' object='../optional/glpk/libglpk_la-glpmpl01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmpl01.lo `test -f '../optional/glpk/glpmpl01.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl01.c
+
+../optional/glpk/libglpk_la-glpmpl02.lo: ../optional/glpk/glpmpl02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmpl02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl02.Tpo -c -o ../optional/glpk/libglpk_la-glpmpl02.lo `test -f '../optional/glpk/glpmpl02.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmpl02.c' object='../optional/glpk/libglpk_la-glpmpl02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmpl02.lo `test -f '../optional/glpk/glpmpl02.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl02.c
+
+../optional/glpk/libglpk_la-glpmpl03.lo: ../optional/glpk/glpmpl03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmpl03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl03.Tpo -c -o ../optional/glpk/libglpk_la-glpmpl03.lo `test -f '../optional/glpk/glpmpl03.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmpl03.c' object='../optional/glpk/libglpk_la-glpmpl03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmpl03.lo `test -f '../optional/glpk/glpmpl03.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl03.c
+
+../optional/glpk/libglpk_la-glpmpl04.lo: ../optional/glpk/glpmpl04.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmpl04.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl04.Tpo -c -o ../optional/glpk/libglpk_la-glpmpl04.lo `test -f '../optional/glpk/glpmpl04.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl04.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl04.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl04.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmpl04.c' object='../optional/glpk/libglpk_la-glpmpl04.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmpl04.lo `test -f '../optional/glpk/glpmpl04.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl04.c
+
+../optional/glpk/libglpk_la-glpmpl05.lo: ../optional/glpk/glpmpl05.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmpl05.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl05.Tpo -c -o ../optional/glpk/libglpk_la-glpmpl05.lo `test -f '../optional/glpk/glpmpl05.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl05.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl05.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl05.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmpl05.c' object='../optional/glpk/libglpk_la-glpmpl05.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmpl05.lo `test -f '../optional/glpk/glpmpl05.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl05.c
+
+../optional/glpk/libglpk_la-glpmpl06.lo: ../optional/glpk/glpmpl06.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmpl06.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl06.Tpo -c -o ../optional/glpk/libglpk_la-glpmpl06.lo `test -f '../optional/glpk/glpmpl06.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl06.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl06.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmpl06.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmpl06.c' object='../optional/glpk/libglpk_la-glpmpl06.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmpl06.lo `test -f '../optional/glpk/glpmpl06.c' || echo '$(srcdir)/'`../optional/glpk/glpmpl06.c
+
+../optional/glpk/libglpk_la-glpmps.lo: ../optional/glpk/glpmps.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpmps.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpmps.Tpo -c -o ../optional/glpk/libglpk_la-glpmps.lo `test -f '../optional/glpk/glpmps.c' || echo '$(srcdir)/'`../optional/glpk/glpmps.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpmps.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpmps.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpmps.c' object='../optional/glpk/libglpk_la-glpmps.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpmps.lo `test -f '../optional/glpk/glpmps.c' || echo '$(srcdir)/'`../optional/glpk/glpmps.c
+
+../optional/glpk/libglpk_la-glpnet01.lo: ../optional/glpk/glpnet01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet01.Tpo -c -o ../optional/glpk/libglpk_la-glpnet01.lo `test -f '../optional/glpk/glpnet01.c' || echo '$(srcdir)/'`../optional/glpk/glpnet01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet01.c' object='../optional/glpk/libglpk_la-glpnet01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet01.lo `test -f '../optional/glpk/glpnet01.c' || echo '$(srcdir)/'`../optional/glpk/glpnet01.c
+
+../optional/glpk/libglpk_la-glpnet02.lo: ../optional/glpk/glpnet02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet02.Tpo -c -o ../optional/glpk/libglpk_la-glpnet02.lo `test -f '../optional/glpk/glpnet02.c' || echo '$(srcdir)/'`../optional/glpk/glpnet02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet02.c' object='../optional/glpk/libglpk_la-glpnet02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet02.lo `test -f '../optional/glpk/glpnet02.c' || echo '$(srcdir)/'`../optional/glpk/glpnet02.c
+
+../optional/glpk/libglpk_la-glpnet03.lo: ../optional/glpk/glpnet03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet03.Tpo -c -o ../optional/glpk/libglpk_la-glpnet03.lo `test -f '../optional/glpk/glpnet03.c' || echo '$(srcdir)/'`../optional/glpk/glpnet03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet03.c' object='../optional/glpk/libglpk_la-glpnet03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet03.lo `test -f '../optional/glpk/glpnet03.c' || echo '$(srcdir)/'`../optional/glpk/glpnet03.c
+
+../optional/glpk/libglpk_la-glpnet04.lo: ../optional/glpk/glpnet04.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet04.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet04.Tpo -c -o ../optional/glpk/libglpk_la-glpnet04.lo `test -f '../optional/glpk/glpnet04.c' || echo '$(srcdir)/'`../optional/glpk/glpnet04.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet04.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet04.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet04.c' object='../optional/glpk/libglpk_la-glpnet04.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet04.lo `test -f '../optional/glpk/glpnet04.c' || echo '$(srcdir)/'`../optional/glpk/glpnet04.c
+
+../optional/glpk/libglpk_la-glpnet05.lo: ../optional/glpk/glpnet05.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet05.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet05.Tpo -c -o ../optional/glpk/libglpk_la-glpnet05.lo `test -f '../optional/glpk/glpnet05.c' || echo '$(srcdir)/'`../optional/glpk/glpnet05.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet05.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet05.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet05.c' object='../optional/glpk/libglpk_la-glpnet05.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet05.lo `test -f '../optional/glpk/glpnet05.c' || echo '$(srcdir)/'`../optional/glpk/glpnet05.c
+
+../optional/glpk/libglpk_la-glpnet06.lo: ../optional/glpk/glpnet06.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet06.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet06.Tpo -c -o ../optional/glpk/libglpk_la-glpnet06.lo `test -f '../optional/glpk/glpnet06.c' || echo '$(srcdir)/'`../optional/glpk/glpnet06.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet06.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet06.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet06.c' object='../optional/glpk/libglpk_la-glpnet06.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet06.lo `test -f '../optional/glpk/glpnet06.c' || echo '$(srcdir)/'`../optional/glpk/glpnet06.c
+
+../optional/glpk/libglpk_la-glpnet07.lo: ../optional/glpk/glpnet07.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet07.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet07.Tpo -c -o ../optional/glpk/libglpk_la-glpnet07.lo `test -f '../optional/glpk/glpnet07.c' || echo '$(srcdir)/'`../optional/glpk/glpnet07.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet07.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet07.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet07.c' object='../optional/glpk/libglpk_la-glpnet07.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet07.lo `test -f '../optional/glpk/glpnet07.c' || echo '$(srcdir)/'`../optional/glpk/glpnet07.c
+
+../optional/glpk/libglpk_la-glpnet08.lo: ../optional/glpk/glpnet08.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet08.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet08.Tpo -c -o ../optional/glpk/libglpk_la-glpnet08.lo `test -f '../optional/glpk/glpnet08.c' || echo '$(srcdir)/'`../optional/glpk/glpnet08.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet08.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet08.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet08.c' object='../optional/glpk/libglpk_la-glpnet08.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet08.lo `test -f '../optional/glpk/glpnet08.c' || echo '$(srcdir)/'`../optional/glpk/glpnet08.c
+
+../optional/glpk/libglpk_la-glpnet09.lo: ../optional/glpk/glpnet09.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnet09.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet09.Tpo -c -o ../optional/glpk/libglpk_la-glpnet09.lo `test -f '../optional/glpk/glpnet09.c' || echo '$(srcdir)/'`../optional/glpk/glpnet09.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet09.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnet09.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnet09.c' object='../optional/glpk/libglpk_la-glpnet09.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnet09.lo `test -f '../optional/glpk/glpnet09.c' || echo '$(srcdir)/'`../optional/glpk/glpnet09.c
+
+../optional/glpk/libglpk_la-glpnpp01.lo: ../optional/glpk/glpnpp01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnpp01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp01.Tpo -c -o ../optional/glpk/libglpk_la-glpnpp01.lo `test -f '../optional/glpk/glpnpp01.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnpp01.c' object='../optional/glpk/libglpk_la-glpnpp01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnpp01.lo `test -f '../optional/glpk/glpnpp01.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp01.c
+
+../optional/glpk/libglpk_la-glpnpp02.lo: ../optional/glpk/glpnpp02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnpp02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp02.Tpo -c -o ../optional/glpk/libglpk_la-glpnpp02.lo `test -f '../optional/glpk/glpnpp02.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnpp02.c' object='../optional/glpk/libglpk_la-glpnpp02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnpp02.lo `test -f '../optional/glpk/glpnpp02.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp02.c
+
+../optional/glpk/libglpk_la-glpnpp03.lo: ../optional/glpk/glpnpp03.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnpp03.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp03.Tpo -c -o ../optional/glpk/libglpk_la-glpnpp03.lo `test -f '../optional/glpk/glpnpp03.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp03.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp03.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp03.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnpp03.c' object='../optional/glpk/libglpk_la-glpnpp03.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnpp03.lo `test -f '../optional/glpk/glpnpp03.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp03.c
+
+../optional/glpk/libglpk_la-glpnpp04.lo: ../optional/glpk/glpnpp04.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnpp04.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp04.Tpo -c -o ../optional/glpk/libglpk_la-glpnpp04.lo `test -f '../optional/glpk/glpnpp04.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp04.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp04.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp04.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnpp04.c' object='../optional/glpk/libglpk_la-glpnpp04.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnpp04.lo `test -f '../optional/glpk/glpnpp04.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp04.c
+
+../optional/glpk/libglpk_la-glpnpp05.lo: ../optional/glpk/glpnpp05.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpnpp05.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp05.Tpo -c -o ../optional/glpk/libglpk_la-glpnpp05.lo `test -f '../optional/glpk/glpnpp05.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp05.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp05.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpnpp05.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpnpp05.c' object='../optional/glpk/libglpk_la-glpnpp05.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpnpp05.lo `test -f '../optional/glpk/glpnpp05.c' || echo '$(srcdir)/'`../optional/glpk/glpnpp05.c
+
+../optional/glpk/libglpk_la-glpqmd.lo: ../optional/glpk/glpqmd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpqmd.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpqmd.Tpo -c -o ../optional/glpk/libglpk_la-glpqmd.lo `test -f '../optional/glpk/glpqmd.c' || echo '$(srcdir)/'`../optional/glpk/glpqmd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpqmd.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpqmd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpqmd.c' object='../optional/glpk/libglpk_la-glpqmd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpqmd.lo `test -f '../optional/glpk/glpqmd.c' || echo '$(srcdir)/'`../optional/glpk/glpqmd.c
+
+../optional/glpk/libglpk_la-glprgr.lo: ../optional/glpk/glprgr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glprgr.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glprgr.Tpo -c -o ../optional/glpk/libglpk_la-glprgr.lo `test -f '../optional/glpk/glprgr.c' || echo '$(srcdir)/'`../optional/glpk/glprgr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glprgr.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glprgr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glprgr.c' object='../optional/glpk/libglpk_la-glprgr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glprgr.lo `test -f '../optional/glpk/glprgr.c' || echo '$(srcdir)/'`../optional/glpk/glprgr.c
+
+../optional/glpk/libglpk_la-glprng01.lo: ../optional/glpk/glprng01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glprng01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glprng01.Tpo -c -o ../optional/glpk/libglpk_la-glprng01.lo `test -f '../optional/glpk/glprng01.c' || echo '$(srcdir)/'`../optional/glpk/glprng01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glprng01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glprng01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glprng01.c' object='../optional/glpk/libglpk_la-glprng01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glprng01.lo `test -f '../optional/glpk/glprng01.c' || echo '$(srcdir)/'`../optional/glpk/glprng01.c
+
+../optional/glpk/libglpk_la-glprng02.lo: ../optional/glpk/glprng02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glprng02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glprng02.Tpo -c -o ../optional/glpk/libglpk_la-glprng02.lo `test -f '../optional/glpk/glprng02.c' || echo '$(srcdir)/'`../optional/glpk/glprng02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glprng02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glprng02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glprng02.c' object='../optional/glpk/libglpk_la-glprng02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glprng02.lo `test -f '../optional/glpk/glprng02.c' || echo '$(srcdir)/'`../optional/glpk/glprng02.c
+
+../optional/glpk/libglpk_la-glpscf.lo: ../optional/glpk/glpscf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpscf.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpscf.Tpo -c -o ../optional/glpk/libglpk_la-glpscf.lo `test -f '../optional/glpk/glpscf.c' || echo '$(srcdir)/'`../optional/glpk/glpscf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpscf.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpscf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpscf.c' object='../optional/glpk/libglpk_la-glpscf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpscf.lo `test -f '../optional/glpk/glpscf.c' || echo '$(srcdir)/'`../optional/glpk/glpscf.c
+
+../optional/glpk/libglpk_la-glpscl.lo: ../optional/glpk/glpscl.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpscl.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpscl.Tpo -c -o ../optional/glpk/libglpk_la-glpscl.lo `test -f '../optional/glpk/glpscl.c' || echo '$(srcdir)/'`../optional/glpk/glpscl.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpscl.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpscl.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpscl.c' object='../optional/glpk/libglpk_la-glpscl.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpscl.lo `test -f '../optional/glpk/glpscl.c' || echo '$(srcdir)/'`../optional/glpk/glpscl.c
+
+../optional/glpk/libglpk_la-glpsdf.lo: ../optional/glpk/glpsdf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpsdf.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpsdf.Tpo -c -o ../optional/glpk/libglpk_la-glpsdf.lo `test -f '../optional/glpk/glpsdf.c' || echo '$(srcdir)/'`../optional/glpk/glpsdf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpsdf.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpsdf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpsdf.c' object='../optional/glpk/libglpk_la-glpsdf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpsdf.lo `test -f '../optional/glpk/glpsdf.c' || echo '$(srcdir)/'`../optional/glpk/glpsdf.c
+
+../optional/glpk/libglpk_la-glpspm.lo: ../optional/glpk/glpspm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpspm.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpspm.Tpo -c -o ../optional/glpk/libglpk_la-glpspm.lo `test -f '../optional/glpk/glpspm.c' || echo '$(srcdir)/'`../optional/glpk/glpspm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpspm.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpspm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpspm.c' object='../optional/glpk/libglpk_la-glpspm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpspm.lo `test -f '../optional/glpk/glpspm.c' || echo '$(srcdir)/'`../optional/glpk/glpspm.c
+
+../optional/glpk/libglpk_la-glpspx01.lo: ../optional/glpk/glpspx01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpspx01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx01.Tpo -c -o ../optional/glpk/libglpk_la-glpspx01.lo `test -f '../optional/glpk/glpspx01.c' || echo '$(srcdir)/'`../optional/glpk/glpspx01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpspx01.c' object='../optional/glpk/libglpk_la-glpspx01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpspx01.lo `test -f '../optional/glpk/glpspx01.c' || echo '$(srcdir)/'`../optional/glpk/glpspx01.c
+
+../optional/glpk/libglpk_la-glpspx02.lo: ../optional/glpk/glpspx02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpspx02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx02.Tpo -c -o ../optional/glpk/libglpk_la-glpspx02.lo `test -f '../optional/glpk/glpspx02.c' || echo '$(srcdir)/'`../optional/glpk/glpspx02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpspx02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpspx02.c' object='../optional/glpk/libglpk_la-glpspx02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpspx02.lo `test -f '../optional/glpk/glpspx02.c' || echo '$(srcdir)/'`../optional/glpk/glpspx02.c
+
+../optional/glpk/libglpk_la-glpsql.lo: ../optional/glpk/glpsql.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpsql.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpsql.Tpo -c -o ../optional/glpk/libglpk_la-glpsql.lo `test -f '../optional/glpk/glpsql.c' || echo '$(srcdir)/'`../optional/glpk/glpsql.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpsql.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpsql.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpsql.c' object='../optional/glpk/libglpk_la-glpsql.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpsql.lo `test -f '../optional/glpk/glpsql.c' || echo '$(srcdir)/'`../optional/glpk/glpsql.c
+
+../optional/glpk/libglpk_la-glpssx01.lo: ../optional/glpk/glpssx01.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpssx01.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx01.Tpo -c -o ../optional/glpk/libglpk_la-glpssx01.lo `test -f '../optional/glpk/glpssx01.c' || echo '$(srcdir)/'`../optional/glpk/glpssx01.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx01.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx01.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpssx01.c' object='../optional/glpk/libglpk_la-glpssx01.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpssx01.lo `test -f '../optional/glpk/glpssx01.c' || echo '$(srcdir)/'`../optional/glpk/glpssx01.c
+
+../optional/glpk/libglpk_la-glpssx02.lo: ../optional/glpk/glpssx02.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glpssx02.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx02.Tpo -c -o ../optional/glpk/libglpk_la-glpssx02.lo `test -f '../optional/glpk/glpssx02.c' || echo '$(srcdir)/'`../optional/glpk/glpssx02.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx02.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glpssx02.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glpssx02.c' object='../optional/glpk/libglpk_la-glpssx02.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glpssx02.lo `test -f '../optional/glpk/glpssx02.c' || echo '$(srcdir)/'`../optional/glpk/glpssx02.c
+
+../optional/glpk/libglpk_la-glptsp.lo: ../optional/glpk/glptsp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/libglpk_la-glptsp.lo -MD -MP -MF ../optional/glpk/$(DEPDIR)/libglpk_la-glptsp.Tpo -c -o ../optional/glpk/libglpk_la-glptsp.lo `test -f '../optional/glpk/glptsp.c' || echo '$(srcdir)/'`../optional/glpk/glptsp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/$(DEPDIR)/libglpk_la-glptsp.Tpo ../optional/glpk/$(DEPDIR)/libglpk_la-glptsp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/glptsp.c' object='../optional/glpk/libglpk_la-glptsp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/libglpk_la-glptsp.lo `test -f '../optional/glpk/glptsp.c' || echo '$(srcdir)/'`../optional/glpk/glptsp.c
+
+../optional/glpk/amd/libglpk_la-amd_1.lo: ../optional/glpk/amd/amd_1.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_1.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_1.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_1.lo `test -f '../optional/glpk/amd/amd_1.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_1.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_1.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_1.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_1.c' object='../optional/glpk/amd/libglpk_la-amd_1.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_1.lo `test -f '../optional/glpk/amd/amd_1.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_1.c
+
+../optional/glpk/amd/libglpk_la-amd_2.lo: ../optional/glpk/amd/amd_2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_2.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_2.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_2.lo `test -f '../optional/glpk/amd/amd_2.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_2.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_2.c' object='../optional/glpk/amd/libglpk_la-amd_2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_2.lo `test -f '../optional/glpk/amd/amd_2.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_2.c
+
+../optional/glpk/amd/libglpk_la-amd_aat.lo: ../optional/glpk/amd/amd_aat.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_aat.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_aat.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_aat.lo `test -f '../optional/glpk/amd/amd_aat.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_aat.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_aat.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_aat.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_aat.c' object='../optional/glpk/amd/libglpk_la-amd_aat.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_aat.lo `test -f '../optional/glpk/amd/amd_aat.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_aat.c
+
+../optional/glpk/amd/libglpk_la-amd_control.lo: ../optional/glpk/amd/amd_control.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_control.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_control.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_control.lo `test -f '../optional/glpk/amd/amd_control.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_control.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_control.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_control.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_control.c' object='../optional/glpk/amd/libglpk_la-amd_control.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_control.lo `test -f '../optional/glpk/amd/amd_control.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_control.c
+
+../optional/glpk/amd/libglpk_la-amd_defaults.lo: ../optional/glpk/amd/amd_defaults.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_defaults.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_defaults.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_defaults.lo `test -f '../optional/glpk/amd/amd_defaults.c' || echo '$(srcdir)/'`../optional/glpk/amd/am [...]
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_defaults.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_defaults.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_defaults.c' object='../optional/glpk/amd/libglpk_la-amd_defaults.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_defaults.lo `test -f '../optional/glpk/amd/amd_defaults.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_defaults.c
+
+../optional/glpk/amd/libglpk_la-amd_dump.lo: ../optional/glpk/amd/amd_dump.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_dump.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_dump.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_dump.lo `test -f '../optional/glpk/amd/amd_dump.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_dump.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_dump.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_dump.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_dump.c' object='../optional/glpk/amd/libglpk_la-amd_dump.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_dump.lo `test -f '../optional/glpk/amd/amd_dump.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_dump.c
+
+../optional/glpk/amd/libglpk_la-amd_info.lo: ../optional/glpk/amd/amd_info.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_info.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_info.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_info.lo `test -f '../optional/glpk/amd/amd_info.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_info.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_info.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_info.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_info.c' object='../optional/glpk/amd/libglpk_la-amd_info.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_info.lo `test -f '../optional/glpk/amd/amd_info.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_info.c
+
+../optional/glpk/amd/libglpk_la-amd_order.lo: ../optional/glpk/amd/amd_order.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_order.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_order.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_order.lo `test -f '../optional/glpk/amd/amd_order.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_order.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_order.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_order.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_order.c' object='../optional/glpk/amd/libglpk_la-amd_order.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_order.lo `test -f '../optional/glpk/amd/amd_order.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_order.c
+
+../optional/glpk/amd/libglpk_la-amd_post_tree.lo: ../optional/glpk/amd/amd_post_tree.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_post_tree.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_post_tree.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_post_tree.lo `test -f '../optional/glpk/amd/amd_post_tree.c' || echo '$(srcdir)/'`../optional/glpk/am [...]
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_post_tree.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_post_tree.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_post_tree.c' object='../optional/glpk/amd/libglpk_la-amd_post_tree.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_post_tree.lo `test -f '../optional/glpk/amd/amd_post_tree.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_post_tree.c
+
+../optional/glpk/amd/libglpk_la-amd_postorder.lo: ../optional/glpk/amd/amd_postorder.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_postorder.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_postorder.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_postorder.lo `test -f '../optional/glpk/amd/amd_postorder.c' || echo '$(srcdir)/'`../optional/glpk/am [...]
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_postorder.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_postorder.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_postorder.c' object='../optional/glpk/amd/libglpk_la-amd_postorder.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_postorder.lo `test -f '../optional/glpk/amd/amd_postorder.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_postorder.c
+
+../optional/glpk/amd/libglpk_la-amd_preprocess.lo: ../optional/glpk/amd/amd_preprocess.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_preprocess.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_preprocess.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_preprocess.lo `test -f '../optional/glpk/amd/amd_preprocess.c' || echo '$(srcdir)/'`../optional/glp [...]
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_preprocess.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_preprocess.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_preprocess.c' object='../optional/glpk/amd/libglpk_la-amd_preprocess.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_preprocess.lo `test -f '../optional/glpk/amd/amd_preprocess.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_preprocess.c
+
+../optional/glpk/amd/libglpk_la-amd_valid.lo: ../optional/glpk/amd/amd_valid.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/amd/libglpk_la-amd_valid.lo -MD -MP -MF ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_valid.Tpo -c -o ../optional/glpk/amd/libglpk_la-amd_valid.lo `test -f '../optional/glpk/amd/amd_valid.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_valid.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_valid.Tpo ../optional/glpk/amd/$(DEPDIR)/libglpk_la-amd_valid.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/amd/amd_valid.c' object='../optional/glpk/amd/libglpk_la-amd_valid.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/amd/libglpk_la-amd_valid.lo `test -f '../optional/glpk/amd/amd_valid.c' || echo '$(srcdir)/'`../optional/glpk/amd/amd_valid.c
+
+../optional/glpk/colamd/libglpk_la-colamd.lo: ../optional/glpk/colamd/colamd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -MT ../optional/glpk/colamd/libglpk_la-colamd.lo -MD -MP -MF ../optional/glpk/colamd/$(DEPDIR)/libglpk_la-colamd.Tpo -c -o ../optional/glpk/colamd/libglpk_la-colamd.lo `test -f '../optional/glpk/colamd/colamd.c' || echo '$(srcdir)/'`../optional/glpk/colamd/colamd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ../optional/glpk/colamd/$(DEPDIR)/libglpk_la-colamd.Tpo ../optional/glpk/colamd/$(DEPDIR)/libglpk_la-colamd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../optional/glpk/colamd/colamd.c' object='../optional/glpk/colamd/libglpk_la-colamd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(libglpk_la_CFLAGS) $(CFLAGS) -c -o ../optional/glpk/colamd/libglpk_la-colamd.lo `test -f '../optional/glpk/colamd/colamd.c' || echo '$(srcdir)/'`../optional/glpk/colamd/colamd.c
+
+libigraph_la-basic_query.lo: basic_query.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-basic_query.lo -MD -MP -MF $(DEPDIR)/libigraph_la-basic_query.Tpo -c -o libigraph_la-basic_query.lo `test -f 'basic_query.c' || echo '$(srcdir)/'`basic_query.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-basic_query.Tpo $(DEPDIR)/libigraph_la-basic_query.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='basic_query.c' object='libigraph_la-basic_query.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-basic_query.lo `test -f 'basic_query.c' || echo '$(srcdir)/'`basic_query.c
+
+libigraph_la-games.lo: games.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-games.lo -MD -MP -MF $(DEPDIR)/libigraph_la-games.Tpo -c -o libigraph_la-games.lo `test -f 'games.c' || echo '$(srcdir)/'`games.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-games.Tpo $(DEPDIR)/libigraph_la-games.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='games.c' object='libigraph_la-games.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-games.lo `test -f 'games.c' || echo '$(srcdir)/'`games.c
+
+libigraph_la-cocitation.lo: cocitation.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-cocitation.lo -MD -MP -MF $(DEPDIR)/libigraph_la-cocitation.Tpo -c -o libigraph_la-cocitation.lo `test -f 'cocitation.c' || echo '$(srcdir)/'`cocitation.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-cocitation.Tpo $(DEPDIR)/libigraph_la-cocitation.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cocitation.c' object='libigraph_la-cocitation.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-cocitation.lo `test -f 'cocitation.c' || echo '$(srcdir)/'`cocitation.c
+
+libigraph_la-iterators.lo: iterators.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-iterators.lo -MD -MP -MF $(DEPDIR)/libigraph_la-iterators.Tpo -c -o libigraph_la-iterators.lo `test -f 'iterators.c' || echo '$(srcdir)/'`iterators.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-iterators.Tpo $(DEPDIR)/libigraph_la-iterators.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='iterators.c' object='libigraph_la-iterators.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-iterators.lo `test -f 'iterators.c' || echo '$(srcdir)/'`iterators.c
+
+libigraph_la-structural_properties.lo: structural_properties.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-structural_properties.lo -MD -MP -MF $(DEPDIR)/libigraph_la-structural_properties.Tpo -c -o libigraph_la-structural_properties.lo `test -f 'structural_properties.c' || echo '$(srcdir)/'`structural_properties.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-structural_properties.Tpo $(DEPDIR)/libigraph_la-structural_properties.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='structural_properties.c' object='libigraph_la-structural_properties.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-structural_properties.lo `test -f 'structural_properties.c' || echo '$(srcdir)/'`structural_properties.c
+
+libigraph_la-components.lo: components.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-components.lo -MD -MP -MF $(DEPDIR)/libigraph_la-components.Tpo -c -o libigraph_la-components.lo `test -f 'components.c' || echo '$(srcdir)/'`components.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-components.Tpo $(DEPDIR)/libigraph_la-components.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='components.c' object='libigraph_la-components.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-components.lo `test -f 'components.c' || echo '$(srcdir)/'`components.c
+
+libigraph_la-layout.lo: layout.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-layout.lo -MD -MP -MF $(DEPDIR)/libigraph_la-layout.Tpo -c -o libigraph_la-layout.lo `test -f 'layout.c' || echo '$(srcdir)/'`layout.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-layout.Tpo $(DEPDIR)/libigraph_la-layout.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='layout.c' object='libigraph_la-layout.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-layout.lo `test -f 'layout.c' || echo '$(srcdir)/'`layout.c
+
+libigraph_la-structure_generators.lo: structure_generators.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-structure_generators.lo -MD -MP -MF $(DEPDIR)/libigraph_la-structure_generators.Tpo -c -o libigraph_la-structure_generators.lo `test -f 'structure_generators.c' || echo '$(srcdir)/'`structure_generators.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-structure_generators.Tpo $(DEPDIR)/libigraph_la-structure_generators.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='structure_generators.c' object='libigraph_la-structure_generators.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-structure_generators.lo `test -f 'structure_generators.c' || echo '$(srcdir)/'`structure_generators.c
+
+libigraph_la-conversion.lo: conversion.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-conversion.lo -MD -MP -MF $(DEPDIR)/libigraph_la-conversion.Tpo -c -o libigraph_la-conversion.lo `test -f 'conversion.c' || echo '$(srcdir)/'`conversion.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-conversion.Tpo $(DEPDIR)/libigraph_la-conversion.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='conversion.c' object='libigraph_la-conversion.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-conversion.lo `test -f 'conversion.c' || echo '$(srcdir)/'`conversion.c
+
+libigraph_la-type_indexededgelist.lo: type_indexededgelist.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-type_indexededgelist.lo -MD -MP -MF $(DEPDIR)/libigraph_la-type_indexededgelist.Tpo -c -o libigraph_la-type_indexededgelist.lo `test -f 'type_indexededgelist.c' || echo '$(srcdir)/'`type_indexededgelist.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-type_indexededgelist.Tpo $(DEPDIR)/libigraph_la-type_indexededgelist.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='type_indexededgelist.c' object='libigraph_la-type_indexededgelist.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-type_indexededgelist.lo `test -f 'type_indexededgelist.c' || echo '$(srcdir)/'`type_indexededgelist.c
+
+libigraph_la-spanning_trees.lo: spanning_trees.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-spanning_trees.lo -MD -MP -MF $(DEPDIR)/libigraph_la-spanning_trees.Tpo -c -o libigraph_la-spanning_trees.lo `test -f 'spanning_trees.c' || echo '$(srcdir)/'`spanning_trees.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-spanning_trees.Tpo $(DEPDIR)/libigraph_la-spanning_trees.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='spanning_trees.c' object='libigraph_la-spanning_trees.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-spanning_trees.lo `test -f 'spanning_trees.c' || echo '$(srcdir)/'`spanning_trees.c
+
+libigraph_la-igraph_error.lo: igraph_error.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_error.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_error.Tpo -c -o libigraph_la-igraph_error.lo `test -f 'igraph_error.c' || echo '$(srcdir)/'`igraph_error.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_error.Tpo $(DEPDIR)/libigraph_la-igraph_error.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_error.c' object='libigraph_la-igraph_error.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_error.lo `test -f 'igraph_error.c' || echo '$(srcdir)/'`igraph_error.c
+
+libigraph_la-interrupt.lo: interrupt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-interrupt.lo -MD -MP -MF $(DEPDIR)/libigraph_la-interrupt.Tpo -c -o libigraph_la-interrupt.lo `test -f 'interrupt.c' || echo '$(srcdir)/'`interrupt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-interrupt.Tpo $(DEPDIR)/libigraph_la-interrupt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='interrupt.c' object='libigraph_la-interrupt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-interrupt.lo `test -f 'interrupt.c' || echo '$(srcdir)/'`interrupt.c
+
+libigraph_la-other.lo: other.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-other.lo -MD -MP -MF $(DEPDIR)/libigraph_la-other.Tpo -c -o libigraph_la-other.lo `test -f 'other.c' || echo '$(srcdir)/'`other.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-other.Tpo $(DEPDIR)/libigraph_la-other.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='other.c' object='libigraph_la-other.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-other.lo `test -f 'other.c' || echo '$(srcdir)/'`other.c
+
+libigraph_la-foreign.lo: foreign.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign.Tpo -c -o libigraph_la-foreign.lo `test -f 'foreign.c' || echo '$(srcdir)/'`foreign.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign.Tpo $(DEPDIR)/libigraph_la-foreign.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign.c' object='libigraph_la-foreign.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign.lo `test -f 'foreign.c' || echo '$(srcdir)/'`foreign.c
+
+libigraph_la-random.lo: random.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-random.lo -MD -MP -MF $(DEPDIR)/libigraph_la-random.Tpo -c -o libigraph_la-random.lo `test -f 'random.c' || echo '$(srcdir)/'`random.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-random.Tpo $(DEPDIR)/libigraph_la-random.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='random.c' object='libigraph_la-random.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-random.lo `test -f 'random.c' || echo '$(srcdir)/'`random.c
+
+libigraph_la-attributes.lo: attributes.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-attributes.lo -MD -MP -MF $(DEPDIR)/libigraph_la-attributes.Tpo -c -o libigraph_la-attributes.lo `test -f 'attributes.c' || echo '$(srcdir)/'`attributes.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-attributes.Tpo $(DEPDIR)/libigraph_la-attributes.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='attributes.c' object='libigraph_la-attributes.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-attributes.lo `test -f 'attributes.c' || echo '$(srcdir)/'`attributes.c
+
+libigraph_la-foreign-ncol-parser.lo: foreign-ncol-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-ncol-parser.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-ncol-parser.Tpo -c -o libigraph_la-foreign-ncol-parser.lo `test -f 'foreign-ncol-parser.c' || echo '$(srcdir)/'`foreign-ncol-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-ncol-parser.Tpo $(DEPDIR)/libigraph_la-foreign-ncol-parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-ncol-parser.c' object='libigraph_la-foreign-ncol-parser.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-ncol-parser.lo `test -f 'foreign-ncol-parser.c' || echo '$(srcdir)/'`foreign-ncol-parser.c
+
+libigraph_la-foreign-ncol-lexer.lo: foreign-ncol-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-ncol-lexer.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-ncol-lexer.Tpo -c -o libigraph_la-foreign-ncol-lexer.lo `test -f 'foreign-ncol-lexer.c' || echo '$(srcdir)/'`foreign-ncol-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-ncol-lexer.Tpo $(DEPDIR)/libigraph_la-foreign-ncol-lexer.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-ncol-lexer.c' object='libigraph_la-foreign-ncol-lexer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-ncol-lexer.lo `test -f 'foreign-ncol-lexer.c' || echo '$(srcdir)/'`foreign-ncol-lexer.c
+
+libigraph_la-foreign-lgl-parser.lo: foreign-lgl-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-lgl-parser.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-lgl-parser.Tpo -c -o libigraph_la-foreign-lgl-parser.lo `test -f 'foreign-lgl-parser.c' || echo '$(srcdir)/'`foreign-lgl-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-lgl-parser.Tpo $(DEPDIR)/libigraph_la-foreign-lgl-parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-lgl-parser.c' object='libigraph_la-foreign-lgl-parser.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-lgl-parser.lo `test -f 'foreign-lgl-parser.c' || echo '$(srcdir)/'`foreign-lgl-parser.c
+
+libigraph_la-foreign-lgl-lexer.lo: foreign-lgl-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-lgl-lexer.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-lgl-lexer.Tpo -c -o libigraph_la-foreign-lgl-lexer.lo `test -f 'foreign-lgl-lexer.c' || echo '$(srcdir)/'`foreign-lgl-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-lgl-lexer.Tpo $(DEPDIR)/libigraph_la-foreign-lgl-lexer.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-lgl-lexer.c' object='libigraph_la-foreign-lgl-lexer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-lgl-lexer.lo `test -f 'foreign-lgl-lexer.c' || echo '$(srcdir)/'`foreign-lgl-lexer.c
+
+libigraph_la-foreign-pajek-parser.lo: foreign-pajek-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-pajek-parser.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-pajek-parser.Tpo -c -o libigraph_la-foreign-pajek-parser.lo `test -f 'foreign-pajek-parser.c' || echo '$(srcdir)/'`foreign-pajek-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-pajek-parser.Tpo $(DEPDIR)/libigraph_la-foreign-pajek-parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-pajek-parser.c' object='libigraph_la-foreign-pajek-parser.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-pajek-parser.lo `test -f 'foreign-pajek-parser.c' || echo '$(srcdir)/'`foreign-pajek-parser.c
+
+libigraph_la-foreign-pajek-lexer.lo: foreign-pajek-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-pajek-lexer.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-pajek-lexer.Tpo -c -o libigraph_la-foreign-pajek-lexer.lo `test -f 'foreign-pajek-lexer.c' || echo '$(srcdir)/'`foreign-pajek-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-pajek-lexer.Tpo $(DEPDIR)/libigraph_la-foreign-pajek-lexer.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-pajek-lexer.c' object='libigraph_la-foreign-pajek-lexer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-pajek-lexer.lo `test -f 'foreign-pajek-lexer.c' || echo '$(srcdir)/'`foreign-pajek-lexer.c
+
+libigraph_la-foreign-gml-parser.lo: foreign-gml-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-gml-parser.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-gml-parser.Tpo -c -o libigraph_la-foreign-gml-parser.lo `test -f 'foreign-gml-parser.c' || echo '$(srcdir)/'`foreign-gml-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-gml-parser.Tpo $(DEPDIR)/libigraph_la-foreign-gml-parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-gml-parser.c' object='libigraph_la-foreign-gml-parser.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-gml-parser.lo `test -f 'foreign-gml-parser.c' || echo '$(srcdir)/'`foreign-gml-parser.c
+
+libigraph_la-foreign-gml-lexer.lo: foreign-gml-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-gml-lexer.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-gml-lexer.Tpo -c -o libigraph_la-foreign-gml-lexer.lo `test -f 'foreign-gml-lexer.c' || echo '$(srcdir)/'`foreign-gml-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-gml-lexer.Tpo $(DEPDIR)/libigraph_la-foreign-gml-lexer.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-gml-lexer.c' object='libigraph_la-foreign-gml-lexer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-gml-lexer.lo `test -f 'foreign-gml-lexer.c' || echo '$(srcdir)/'`foreign-gml-lexer.c
+
+libigraph_la-dqueue.lo: dqueue.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-dqueue.lo -MD -MP -MF $(DEPDIR)/libigraph_la-dqueue.Tpo -c -o libigraph_la-dqueue.lo `test -f 'dqueue.c' || echo '$(srcdir)/'`dqueue.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-dqueue.Tpo $(DEPDIR)/libigraph_la-dqueue.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dqueue.c' object='libigraph_la-dqueue.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-dqueue.lo `test -f 'dqueue.c' || echo '$(srcdir)/'`dqueue.c
+
+libigraph_la-heap.lo: heap.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-heap.lo -MD -MP -MF $(DEPDIR)/libigraph_la-heap.Tpo -c -o libigraph_la-heap.lo `test -f 'heap.c' || echo '$(srcdir)/'`heap.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-heap.Tpo $(DEPDIR)/libigraph_la-heap.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='heap.c' object='libigraph_la-heap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-heap.lo `test -f 'heap.c' || echo '$(srcdir)/'`heap.c
+
+libigraph_la-igraph_heap.lo: igraph_heap.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_heap.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_heap.Tpo -c -o libigraph_la-igraph_heap.lo `test -f 'igraph_heap.c' || echo '$(srcdir)/'`igraph_heap.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_heap.Tpo $(DEPDIR)/libigraph_la-igraph_heap.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_heap.c' object='libigraph_la-igraph_heap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_heap.lo `test -f 'igraph_heap.c' || echo '$(srcdir)/'`igraph_heap.c
+
+libigraph_la-igraph_stack.lo: igraph_stack.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_stack.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_stack.Tpo -c -o libigraph_la-igraph_stack.lo `test -f 'igraph_stack.c' || echo '$(srcdir)/'`igraph_stack.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_stack.Tpo $(DEPDIR)/libigraph_la-igraph_stack.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_stack.c' object='libigraph_la-igraph_stack.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_stack.lo `test -f 'igraph_stack.c' || echo '$(srcdir)/'`igraph_stack.c
+
+libigraph_la-igraph_strvector.lo: igraph_strvector.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_strvector.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_strvector.Tpo -c -o libigraph_la-igraph_strvector.lo `test -f 'igraph_strvector.c' || echo '$(srcdir)/'`igraph_strvector.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_strvector.Tpo $(DEPDIR)/libigraph_la-igraph_strvector.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_strvector.c' object='libigraph_la-igraph_strvector.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_strvector.lo `test -f 'igraph_strvector.c' || echo '$(srcdir)/'`igraph_strvector.c
+
+libigraph_la-igraph_trie.lo: igraph_trie.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_trie.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_trie.Tpo -c -o libigraph_la-igraph_trie.lo `test -f 'igraph_trie.c' || echo '$(srcdir)/'`igraph_trie.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_trie.Tpo $(DEPDIR)/libigraph_la-igraph_trie.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_trie.c' object='libigraph_la-igraph_trie.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_trie.lo `test -f 'igraph_trie.c' || echo '$(srcdir)/'`igraph_trie.c
+
+libigraph_la-matrix.lo: matrix.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-matrix.lo -MD -MP -MF $(DEPDIR)/libigraph_la-matrix.Tpo -c -o libigraph_la-matrix.lo `test -f 'matrix.c' || echo '$(srcdir)/'`matrix.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-matrix.Tpo $(DEPDIR)/libigraph_la-matrix.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='matrix.c' object='libigraph_la-matrix.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-matrix.lo `test -f 'matrix.c' || echo '$(srcdir)/'`matrix.c
+
+libigraph_la-vector.lo: vector.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-vector.lo -MD -MP -MF $(DEPDIR)/libigraph_la-vector.Tpo -c -o libigraph_la-vector.lo `test -f 'vector.c' || echo '$(srcdir)/'`vector.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-vector.Tpo $(DEPDIR)/libigraph_la-vector.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vector.c' object='libigraph_la-vector.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-vector.lo `test -f 'vector.c' || echo '$(srcdir)/'`vector.c
+
+libigraph_la-vector_ptr.lo: vector_ptr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-vector_ptr.lo -MD -MP -MF $(DEPDIR)/libigraph_la-vector_ptr.Tpo -c -o libigraph_la-vector_ptr.lo `test -f 'vector_ptr.c' || echo '$(srcdir)/'`vector_ptr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-vector_ptr.Tpo $(DEPDIR)/libigraph_la-vector_ptr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vector_ptr.c' object='libigraph_la-vector_ptr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-vector_ptr.lo `test -f 'vector_ptr.c' || echo '$(srcdir)/'`vector_ptr.c
+
+libigraph_la-memory.lo: memory.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-memory.lo -MD -MP -MF $(DEPDIR)/libigraph_la-memory.Tpo -c -o libigraph_la-memory.lo `test -f 'memory.c' || echo '$(srcdir)/'`memory.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-memory.Tpo $(DEPDIR)/libigraph_la-memory.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='memory.c' object='libigraph_la-memory.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-memory.lo `test -f 'memory.c' || echo '$(srcdir)/'`memory.c
+
+libigraph_la-adjlist.lo: adjlist.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-adjlist.lo -MD -MP -MF $(DEPDIR)/libigraph_la-adjlist.Tpo -c -o libigraph_la-adjlist.lo `test -f 'adjlist.c' || echo '$(srcdir)/'`adjlist.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-adjlist.Tpo $(DEPDIR)/libigraph_la-adjlist.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='adjlist.c' object='libigraph_la-adjlist.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-adjlist.lo `test -f 'adjlist.c' || echo '$(srcdir)/'`adjlist.c
+
+libigraph_la-visitors.lo: visitors.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-visitors.lo -MD -MP -MF $(DEPDIR)/libigraph_la-visitors.Tpo -c -o libigraph_la-visitors.lo `test -f 'visitors.c' || echo '$(srcdir)/'`visitors.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-visitors.Tpo $(DEPDIR)/libigraph_la-visitors.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='visitors.c' object='libigraph_la-visitors.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-visitors.lo `test -f 'visitors.c' || echo '$(srcdir)/'`visitors.c
+
+libigraph_la-igraph_grid.lo: igraph_grid.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_grid.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_grid.Tpo -c -o libigraph_la-igraph_grid.lo `test -f 'igraph_grid.c' || echo '$(srcdir)/'`igraph_grid.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_grid.Tpo $(DEPDIR)/libigraph_la-igraph_grid.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_grid.c' object='libigraph_la-igraph_grid.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_grid.lo `test -f 'igraph_grid.c' || echo '$(srcdir)/'`igraph_grid.c
+
+libigraph_la-atlas.lo: atlas.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-atlas.lo -MD -MP -MF $(DEPDIR)/libigraph_la-atlas.Tpo -c -o libigraph_la-atlas.lo `test -f 'atlas.c' || echo '$(srcdir)/'`atlas.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-atlas.Tpo $(DEPDIR)/libigraph_la-atlas.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='atlas.c' object='libigraph_la-atlas.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-atlas.lo `test -f 'atlas.c' || echo '$(srcdir)/'`atlas.c
+
+libigraph_la-topology.lo: topology.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-topology.lo -MD -MP -MF $(DEPDIR)/libigraph_la-topology.Tpo -c -o libigraph_la-topology.lo `test -f 'topology.c' || echo '$(srcdir)/'`topology.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-topology.Tpo $(DEPDIR)/libigraph_la-topology.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='topology.c' object='libigraph_la-topology.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-topology.lo `test -f 'topology.c' || echo '$(srcdir)/'`topology.c
+
+libigraph_la-motifs.lo: motifs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-motifs.lo -MD -MP -MF $(DEPDIR)/libigraph_la-motifs.Tpo -c -o libigraph_la-motifs.lo `test -f 'motifs.c' || echo '$(srcdir)/'`motifs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-motifs.Tpo $(DEPDIR)/libigraph_la-motifs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='motifs.c' object='libigraph_la-motifs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-motifs.lo `test -f 'motifs.c' || echo '$(srcdir)/'`motifs.c
+
+libigraph_la-progress.lo: progress.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-progress.lo -MD -MP -MF $(DEPDIR)/libigraph_la-progress.Tpo -c -o libigraph_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-progress.Tpo $(DEPDIR)/libigraph_la-progress.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='progress.c' object='libigraph_la-progress.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c
+
+libigraph_la-operators.lo: operators.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-operators.lo -MD -MP -MF $(DEPDIR)/libigraph_la-operators.Tpo -c -o libigraph_la-operators.lo `test -f 'operators.c' || echo '$(srcdir)/'`operators.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-operators.Tpo $(DEPDIR)/libigraph_la-operators.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='operators.c' object='libigraph_la-operators.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-operators.lo `test -f 'operators.c' || echo '$(srcdir)/'`operators.c
+
+libigraph_la-igraph_psumtree.lo: igraph_psumtree.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_psumtree.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_psumtree.Tpo -c -o libigraph_la-igraph_psumtree.lo `test -f 'igraph_psumtree.c' || echo '$(srcdir)/'`igraph_psumtree.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_psumtree.Tpo $(DEPDIR)/libigraph_la-igraph_psumtree.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_psumtree.c' object='libigraph_la-igraph_psumtree.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_psumtree.lo `test -f 'igraph_psumtree.c' || echo '$(srcdir)/'`igraph_psumtree.c
+
+libigraph_la-array.lo: array.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-array.lo -MD -MP -MF $(DEPDIR)/libigraph_la-array.Tpo -c -o libigraph_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-array.Tpo $(DEPDIR)/libigraph_la-array.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='array.c' object='libigraph_la-array.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+
+libigraph_la-igraph_hashtable.lo: igraph_hashtable.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_hashtable.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_hashtable.Tpo -c -o libigraph_la-igraph_hashtable.lo `test -f 'igraph_hashtable.c' || echo '$(srcdir)/'`igraph_hashtable.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_hashtable.Tpo $(DEPDIR)/libigraph_la-igraph_hashtable.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_hashtable.c' object='libigraph_la-igraph_hashtable.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_hashtable.lo `test -f 'igraph_hashtable.c' || echo '$(srcdir)/'`igraph_hashtable.c
+
+libigraph_la-foreign-graphml.lo: foreign-graphml.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-graphml.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-graphml.Tpo -c -o libigraph_la-foreign-graphml.lo `test -f 'foreign-graphml.c' || echo '$(srcdir)/'`foreign-graphml.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-graphml.Tpo $(DEPDIR)/libigraph_la-foreign-graphml.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-graphml.c' object='libigraph_la-foreign-graphml.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-graphml.lo `test -f 'foreign-graphml.c' || echo '$(srcdir)/'`foreign-graphml.c
+
+libigraph_la-flow.lo: flow.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-flow.lo -MD -MP -MF $(DEPDIR)/libigraph_la-flow.Tpo -c -o libigraph_la-flow.lo `test -f 'flow.c' || echo '$(srcdir)/'`flow.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-flow.Tpo $(DEPDIR)/libigraph_la-flow.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='flow.c' object='libigraph_la-flow.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-flow.lo `test -f 'flow.c' || echo '$(srcdir)/'`flow.c
+
+libigraph_la-igraph_buckets.lo: igraph_buckets.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_buckets.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_buckets.Tpo -c -o libigraph_la-igraph_buckets.lo `test -f 'igraph_buckets.c' || echo '$(srcdir)/'`igraph_buckets.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_buckets.Tpo $(DEPDIR)/libigraph_la-igraph_buckets.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_buckets.c' object='libigraph_la-igraph_buckets.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_buckets.lo `test -f 'igraph_buckets.c' || echo '$(srcdir)/'`igraph_buckets.c
+
+libigraph_la-spectral_properties.lo: spectral_properties.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-spectral_properties.lo -MD -MP -MF $(DEPDIR)/libigraph_la-spectral_properties.Tpo -c -o libigraph_la-spectral_properties.lo `test -f 'spectral_properties.c' || echo '$(srcdir)/'`spectral_properties.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-spectral_properties.Tpo $(DEPDIR)/libigraph_la-spectral_properties.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='spectral_properties.c' object='libigraph_la-spectral_properties.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-spectral_properties.lo `test -f 'spectral_properties.c' || echo '$(srcdir)/'`spectral_properties.c
+
+libigraph_la-cores.lo: cores.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-cores.lo -MD -MP -MF $(DEPDIR)/libigraph_la-cores.Tpo -c -o libigraph_la-cores.lo `test -f 'cores.c' || echo '$(srcdir)/'`cores.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-cores.Tpo $(DEPDIR)/libigraph_la-cores.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cores.c' object='libigraph_la-cores.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-cores.lo `test -f 'cores.c' || echo '$(srcdir)/'`cores.c
+
+libigraph_la-igraph_set.lo: igraph_set.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_set.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_set.Tpo -c -o libigraph_la-igraph_set.lo `test -f 'igraph_set.c' || echo '$(srcdir)/'`igraph_set.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_set.Tpo $(DEPDIR)/libigraph_la-igraph_set.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_set.c' object='libigraph_la-igraph_set.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_set.lo `test -f 'igraph_set.c' || echo '$(srcdir)/'`igraph_set.c
+
+libigraph_la-cliques.lo: cliques.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-cliques.lo -MD -MP -MF $(DEPDIR)/libigraph_la-cliques.Tpo -c -o libigraph_la-cliques.lo `test -f 'cliques.c' || echo '$(srcdir)/'`cliques.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-cliques.Tpo $(DEPDIR)/libigraph_la-cliques.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cliques.c' object='libigraph_la-cliques.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-cliques.lo `test -f 'cliques.c' || echo '$(srcdir)/'`cliques.c
+
+libigraph_la-revolver_cit.lo: revolver_cit.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-revolver_cit.lo -MD -MP -MF $(DEPDIR)/libigraph_la-revolver_cit.Tpo -c -o libigraph_la-revolver_cit.lo `test -f 'revolver_cit.c' || echo '$(srcdir)/'`revolver_cit.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-revolver_cit.Tpo $(DEPDIR)/libigraph_la-revolver_cit.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='revolver_cit.c' object='libigraph_la-revolver_cit.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-revolver_cit.lo `test -f 'revolver_cit.c' || echo '$(srcdir)/'`revolver_cit.c
+
+libigraph_la-revolver_grow.lo: revolver_grow.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-revolver_grow.lo -MD -MP -MF $(DEPDIR)/libigraph_la-revolver_grow.Tpo -c -o libigraph_la-revolver_grow.lo `test -f 'revolver_grow.c' || echo '$(srcdir)/'`revolver_grow.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-revolver_grow.Tpo $(DEPDIR)/libigraph_la-revolver_grow.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='revolver_grow.c' object='libigraph_la-revolver_grow.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-revolver_grow.lo `test -f 'revolver_grow.c' || echo '$(srcdir)/'`revolver_grow.c
+
+libigraph_la-spmatrix.lo: spmatrix.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-spmatrix.lo -MD -MP -MF $(DEPDIR)/libigraph_la-spmatrix.Tpo -c -o libigraph_la-spmatrix.lo `test -f 'spmatrix.c' || echo '$(srcdir)/'`spmatrix.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-spmatrix.Tpo $(DEPDIR)/libigraph_la-spmatrix.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='spmatrix.c' object='libigraph_la-spmatrix.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-spmatrix.lo `test -f 'spmatrix.c' || echo '$(srcdir)/'`spmatrix.c
+
+libigraph_la-community.lo: community.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-community.lo -MD -MP -MF $(DEPDIR)/libigraph_la-community.Tpo -c -o libigraph_la-community.lo `test -f 'community.c' || echo '$(srcdir)/'`community.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-community.Tpo $(DEPDIR)/libigraph_la-community.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='community.c' object='libigraph_la-community.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-community.lo `test -f 'community.c' || echo '$(srcdir)/'`community.c
+
+libigraph_la-fast_community.lo: fast_community.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-fast_community.lo -MD -MP -MF $(DEPDIR)/libigraph_la-fast_community.Tpo -c -o libigraph_la-fast_community.lo `test -f 'fast_community.c' || echo '$(srcdir)/'`fast_community.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-fast_community.Tpo $(DEPDIR)/libigraph_la-fast_community.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='fast_community.c' object='libigraph_la-fast_community.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-fast_community.lo `test -f 'fast_community.c' || echo '$(srcdir)/'`fast_community.c
+
+libigraph_la-evolver_cit.lo: evolver_cit.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-evolver_cit.lo -MD -MP -MF $(DEPDIR)/libigraph_la-evolver_cit.Tpo -c -o libigraph_la-evolver_cit.lo `test -f 'evolver_cit.c' || echo '$(srcdir)/'`evolver_cit.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-evolver_cit.Tpo $(DEPDIR)/libigraph_la-evolver_cit.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='evolver_cit.c' object='libigraph_la-evolver_cit.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-evolver_cit.lo `test -f 'evolver_cit.c' || echo '$(srcdir)/'`evolver_cit.c
+
+libigraph_la-gml_tree.lo: gml_tree.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-gml_tree.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gml_tree.Tpo -c -o libigraph_la-gml_tree.lo `test -f 'gml_tree.c' || echo '$(srcdir)/'`gml_tree.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gml_tree.Tpo $(DEPDIR)/libigraph_la-gml_tree.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gml_tree.c' object='libigraph_la-gml_tree.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-gml_tree.lo `test -f 'gml_tree.c' || echo '$(srcdir)/'`gml_tree.c
+
+libigraph_la-cattributes.lo: cattributes.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-cattributes.lo -MD -MP -MF $(DEPDIR)/libigraph_la-cattributes.Tpo -c -o libigraph_la-cattributes.lo `test -f 'cattributes.c' || echo '$(srcdir)/'`cattributes.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-cattributes.Tpo $(DEPDIR)/libigraph_la-cattributes.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cattributes.c' object='libigraph_la-cattributes.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-cattributes.lo `test -f 'cattributes.c' || echo '$(srcdir)/'`cattributes.c
+
+libigraph_la-revolver_ml_cit.lo: revolver_ml_cit.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-revolver_ml_cit.lo -MD -MP -MF $(DEPDIR)/libigraph_la-revolver_ml_cit.Tpo -c -o libigraph_la-revolver_ml_cit.lo `test -f 'revolver_ml_cit.c' || echo '$(srcdir)/'`revolver_ml_cit.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-revolver_ml_cit.Tpo $(DEPDIR)/libigraph_la-revolver_ml_cit.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='revolver_ml_cit.c' object='libigraph_la-revolver_ml_cit.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-revolver_ml_cit.lo `test -f 'revolver_ml_cit.c' || echo '$(srcdir)/'`revolver_ml_cit.c
+
+libigraph_la-zeroin.lo: zeroin.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-zeroin.lo -MD -MP -MF $(DEPDIR)/libigraph_la-zeroin.Tpo -c -o libigraph_la-zeroin.lo `test -f 'zeroin.c' || echo '$(srcdir)/'`zeroin.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-zeroin.Tpo $(DEPDIR)/libigraph_la-zeroin.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='zeroin.c' object='libigraph_la-zeroin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-zeroin.lo `test -f 'zeroin.c' || echo '$(srcdir)/'`zeroin.c
+
+libigraph_la-bfgs.lo: bfgs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-bfgs.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bfgs.Tpo -c -o libigraph_la-bfgs.lo `test -f 'bfgs.c' || echo '$(srcdir)/'`bfgs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bfgs.Tpo $(DEPDIR)/libigraph_la-bfgs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bfgs.c' object='libigraph_la-bfgs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-bfgs.lo `test -f 'bfgs.c' || echo '$(srcdir)/'`bfgs.c
+
+libigraph_la-math.lo: math.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-math.lo -MD -MP -MF $(DEPDIR)/libigraph_la-math.Tpo -c -o libigraph_la-math.lo `test -f 'math.c' || echo '$(srcdir)/'`math.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-math.Tpo $(DEPDIR)/libigraph_la-math.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='math.c' object='libigraph_la-math.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-math.lo `test -f 'math.c' || echo '$(srcdir)/'`math.c
+
+libigraph_la-forestfire.lo: forestfire.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-forestfire.lo -MD -MP -MF $(DEPDIR)/libigraph_la-forestfire.Tpo -c -o libigraph_la-forestfire.lo `test -f 'forestfire.c' || echo '$(srcdir)/'`forestfire.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-forestfire.Tpo $(DEPDIR)/libigraph_la-forestfire.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='forestfire.c' object='libigraph_la-forestfire.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-forestfire.lo `test -f 'forestfire.c' || echo '$(srcdir)/'`forestfire.c
+
+libigraph_la-microscopic_update.lo: microscopic_update.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-microscopic_update.lo -MD -MP -MF $(DEPDIR)/libigraph_la-microscopic_update.Tpo -c -o libigraph_la-microscopic_update.lo `test -f 'microscopic_update.c' || echo '$(srcdir)/'`microscopic_update.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-microscopic_update.Tpo $(DEPDIR)/libigraph_la-microscopic_update.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='microscopic_update.c' object='libigraph_la-microscopic_update.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-microscopic_update.lo `test -f 'microscopic_update.c' || echo '$(srcdir)/'`microscopic_update.c
+
+libigraph_la-blas.lo: blas.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-blas.lo -MD -MP -MF $(DEPDIR)/libigraph_la-blas.Tpo -c -o libigraph_la-blas.lo `test -f 'blas.c' || echo '$(srcdir)/'`blas.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-blas.Tpo $(DEPDIR)/libigraph_la-blas.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='blas.c' object='libigraph_la-blas.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-blas.lo `test -f 'blas.c' || echo '$(srcdir)/'`blas.c
+
+libigraph_la-arpack.lo: arpack.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-arpack.lo -MD -MP -MF $(DEPDIR)/libigraph_la-arpack.Tpo -c -o libigraph_la-arpack.lo `test -f 'arpack.c' || echo '$(srcdir)/'`arpack.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-arpack.Tpo $(DEPDIR)/libigraph_la-arpack.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='arpack.c' object='libigraph_la-arpack.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-arpack.lo `test -f 'arpack.c' || echo '$(srcdir)/'`arpack.c
+
+libigraph_la-centrality.lo: centrality.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-centrality.lo -MD -MP -MF $(DEPDIR)/libigraph_la-centrality.Tpo -c -o libigraph_la-centrality.lo `test -f 'centrality.c' || echo '$(srcdir)/'`centrality.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-centrality.Tpo $(DEPDIR)/libigraph_la-centrality.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='centrality.c' object='libigraph_la-centrality.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-centrality.lo `test -f 'centrality.c' || echo '$(srcdir)/'`centrality.c
+
+libigraph_la-decomposition.lo: decomposition.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-decomposition.lo -MD -MP -MF $(DEPDIR)/libigraph_la-decomposition.Tpo -c -o libigraph_la-decomposition.lo `test -f 'decomposition.c' || echo '$(srcdir)/'`decomposition.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-decomposition.Tpo $(DEPDIR)/libigraph_la-decomposition.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='decomposition.c' object='libigraph_la-decomposition.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-decomposition.lo `test -f 'decomposition.c' || echo '$(srcdir)/'`decomposition.c
+
+libigraph_la-bipartite.lo: bipartite.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-bipartite.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bipartite.Tpo -c -o libigraph_la-bipartite.lo `test -f 'bipartite.c' || echo '$(srcdir)/'`bipartite.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bipartite.Tpo $(DEPDIR)/libigraph_la-bipartite.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bipartite.c' object='libigraph_la-bipartite.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-bipartite.lo `test -f 'bipartite.c' || echo '$(srcdir)/'`bipartite.c
+
+libigraph_la-foreign-dl-parser.lo: foreign-dl-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-dl-parser.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-dl-parser.Tpo -c -o libigraph_la-foreign-dl-parser.lo `test -f 'foreign-dl-parser.c' || echo '$(srcdir)/'`foreign-dl-parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-dl-parser.Tpo $(DEPDIR)/libigraph_la-foreign-dl-parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-dl-parser.c' object='libigraph_la-foreign-dl-parser.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-dl-parser.lo `test -f 'foreign-dl-parser.c' || echo '$(srcdir)/'`foreign-dl-parser.c
+
+libigraph_la-foreign-dl-lexer.lo: foreign-dl-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-foreign-dl-lexer.lo -MD -MP -MF $(DEPDIR)/libigraph_la-foreign-dl-lexer.Tpo -c -o libigraph_la-foreign-dl-lexer.lo `test -f 'foreign-dl-lexer.c' || echo '$(srcdir)/'`foreign-dl-lexer.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-foreign-dl-lexer.Tpo $(DEPDIR)/libigraph_la-foreign-dl-lexer.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='foreign-dl-lexer.c' object='libigraph_la-foreign-dl-lexer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-foreign-dl-lexer.lo `test -f 'foreign-dl-lexer.c' || echo '$(srcdir)/'`foreign-dl-lexer.c
+
+cs/libigraph_la-cs_add.lo: cs/cs_add.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_add.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_add.Tpo -c -o cs/libigraph_la-cs_add.lo `test -f 'cs/cs_add.c' || echo '$(srcdir)/'`cs/cs_add.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_add.Tpo cs/$(DEPDIR)/libigraph_la-cs_add.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_add.c' object='cs/libigraph_la-cs_add.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_add.lo `test -f 'cs/cs_add.c' || echo '$(srcdir)/'`cs/cs_add.c
+
+cs/libigraph_la-cs_happly.lo: cs/cs_happly.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_happly.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_happly.Tpo -c -o cs/libigraph_la-cs_happly.lo `test -f 'cs/cs_happly.c' || echo '$(srcdir)/'`cs/cs_happly.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_happly.Tpo cs/$(DEPDIR)/libigraph_la-cs_happly.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_happly.c' object='cs/libigraph_la-cs_happly.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_happly.lo `test -f 'cs/cs_happly.c' || echo '$(srcdir)/'`cs/cs_happly.c
+
+cs/libigraph_la-cs_pvec.lo: cs/cs_pvec.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_pvec.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_pvec.Tpo -c -o cs/libigraph_la-cs_pvec.lo `test -f 'cs/cs_pvec.c' || echo '$(srcdir)/'`cs/cs_pvec.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_pvec.Tpo cs/$(DEPDIR)/libigraph_la-cs_pvec.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_pvec.c' object='cs/libigraph_la-cs_pvec.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_pvec.lo `test -f 'cs/cs_pvec.c' || echo '$(srcdir)/'`cs/cs_pvec.c
+
+cs/libigraph_la-cs_amd.lo: cs/cs_amd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_amd.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_amd.Tpo -c -o cs/libigraph_la-cs_amd.lo `test -f 'cs/cs_amd.c' || echo '$(srcdir)/'`cs/cs_amd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_amd.Tpo cs/$(DEPDIR)/libigraph_la-cs_amd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_amd.c' object='cs/libigraph_la-cs_amd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_amd.lo `test -f 'cs/cs_amd.c' || echo '$(srcdir)/'`cs/cs_amd.c
+
+cs/libigraph_la-cs_house.lo: cs/cs_house.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_house.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_house.Tpo -c -o cs/libigraph_la-cs_house.lo `test -f 'cs/cs_house.c' || echo '$(srcdir)/'`cs/cs_house.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_house.Tpo cs/$(DEPDIR)/libigraph_la-cs_house.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_house.c' object='cs/libigraph_la-cs_house.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_house.lo `test -f 'cs/cs_house.c' || echo '$(srcdir)/'`cs/cs_house.c
+
+cs/libigraph_la-cs_qr.lo: cs/cs_qr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_qr.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_qr.Tpo -c -o cs/libigraph_la-cs_qr.lo `test -f 'cs/cs_qr.c' || echo '$(srcdir)/'`cs/cs_qr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_qr.Tpo cs/$(DEPDIR)/libigraph_la-cs_qr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_qr.c' object='cs/libigraph_la-cs_qr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_qr.lo `test -f 'cs/cs_qr.c' || echo '$(srcdir)/'`cs/cs_qr.c
+
+cs/libigraph_la-cs_chol.lo: cs/cs_chol.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_chol.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_chol.Tpo -c -o cs/libigraph_la-cs_chol.lo `test -f 'cs/cs_chol.c' || echo '$(srcdir)/'`cs/cs_chol.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_chol.Tpo cs/$(DEPDIR)/libigraph_la-cs_chol.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_chol.c' object='cs/libigraph_la-cs_chol.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_chol.lo `test -f 'cs/cs_chol.c' || echo '$(srcdir)/'`cs/cs_chol.c
+
+cs/libigraph_la-cs_ipvec.lo: cs/cs_ipvec.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_ipvec.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_ipvec.Tpo -c -o cs/libigraph_la-cs_ipvec.lo `test -f 'cs/cs_ipvec.c' || echo '$(srcdir)/'`cs/cs_ipvec.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_ipvec.Tpo cs/$(DEPDIR)/libigraph_la-cs_ipvec.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_ipvec.c' object='cs/libigraph_la-cs_ipvec.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_ipvec.lo `test -f 'cs/cs_ipvec.c' || echo '$(srcdir)/'`cs/cs_ipvec.c
+
+cs/libigraph_la-cs_qrsol.lo: cs/cs_qrsol.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_qrsol.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_qrsol.Tpo -c -o cs/libigraph_la-cs_qrsol.lo `test -f 'cs/cs_qrsol.c' || echo '$(srcdir)/'`cs/cs_qrsol.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_qrsol.Tpo cs/$(DEPDIR)/libigraph_la-cs_qrsol.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_qrsol.c' object='cs/libigraph_la-cs_qrsol.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_qrsol.lo `test -f 'cs/cs_qrsol.c' || echo '$(srcdir)/'`cs/cs_qrsol.c
+
+cs/libigraph_la-cs_cholsol.lo: cs/cs_cholsol.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_cholsol.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_cholsol.Tpo -c -o cs/libigraph_la-cs_cholsol.lo `test -f 'cs/cs_cholsol.c' || echo '$(srcdir)/'`cs/cs_cholsol.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_cholsol.Tpo cs/$(DEPDIR)/libigraph_la-cs_cholsol.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_cholsol.c' object='cs/libigraph_la-cs_cholsol.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_cholsol.lo `test -f 'cs/cs_cholsol.c' || echo '$(srcdir)/'`cs/cs_cholsol.c
+
+cs/libigraph_la-cs_leaf.lo: cs/cs_leaf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_leaf.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_leaf.Tpo -c -o cs/libigraph_la-cs_leaf.lo `test -f 'cs/cs_leaf.c' || echo '$(srcdir)/'`cs/cs_leaf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_leaf.Tpo cs/$(DEPDIR)/libigraph_la-cs_leaf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_leaf.c' object='cs/libigraph_la-cs_leaf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_leaf.lo `test -f 'cs/cs_leaf.c' || echo '$(srcdir)/'`cs/cs_leaf.c
+
+cs/libigraph_la-cs_randperm.lo: cs/cs_randperm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_randperm.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_randperm.Tpo -c -o cs/libigraph_la-cs_randperm.lo `test -f 'cs/cs_randperm.c' || echo '$(srcdir)/'`cs/cs_randperm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_randperm.Tpo cs/$(DEPDIR)/libigraph_la-cs_randperm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_randperm.c' object='cs/libigraph_la-cs_randperm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_randperm.lo `test -f 'cs/cs_randperm.c' || echo '$(srcdir)/'`cs/cs_randperm.c
+
+cs/libigraph_la-cs_compress.lo: cs/cs_compress.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_compress.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_compress.Tpo -c -o cs/libigraph_la-cs_compress.lo `test -f 'cs/cs_compress.c' || echo '$(srcdir)/'`cs/cs_compress.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_compress.Tpo cs/$(DEPDIR)/libigraph_la-cs_compress.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_compress.c' object='cs/libigraph_la-cs_compress.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_compress.lo `test -f 'cs/cs_compress.c' || echo '$(srcdir)/'`cs/cs_compress.c
+
+cs/libigraph_la-cs_load.lo: cs/cs_load.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_load.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_load.Tpo -c -o cs/libigraph_la-cs_load.lo `test -f 'cs/cs_load.c' || echo '$(srcdir)/'`cs/cs_load.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_load.Tpo cs/$(DEPDIR)/libigraph_la-cs_load.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_load.c' object='cs/libigraph_la-cs_load.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_load.lo `test -f 'cs/cs_load.c' || echo '$(srcdir)/'`cs/cs_load.c
+
+cs/libigraph_la-cs_reach.lo: cs/cs_reach.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_reach.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_reach.Tpo -c -o cs/libigraph_la-cs_reach.lo `test -f 'cs/cs_reach.c' || echo '$(srcdir)/'`cs/cs_reach.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_reach.Tpo cs/$(DEPDIR)/libigraph_la-cs_reach.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_reach.c' object='cs/libigraph_la-cs_reach.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_reach.lo `test -f 'cs/cs_reach.c' || echo '$(srcdir)/'`cs/cs_reach.c
+
+cs/libigraph_la-cs_counts.lo: cs/cs_counts.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_counts.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_counts.Tpo -c -o cs/libigraph_la-cs_counts.lo `test -f 'cs/cs_counts.c' || echo '$(srcdir)/'`cs/cs_counts.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_counts.Tpo cs/$(DEPDIR)/libigraph_la-cs_counts.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_counts.c' object='cs/libigraph_la-cs_counts.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_counts.lo `test -f 'cs/cs_counts.c' || echo '$(srcdir)/'`cs/cs_counts.c
+
+cs/libigraph_la-cs_lsolve.lo: cs/cs_lsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_lsolve.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_lsolve.Tpo -c -o cs/libigraph_la-cs_lsolve.lo `test -f 'cs/cs_lsolve.c' || echo '$(srcdir)/'`cs/cs_lsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_lsolve.Tpo cs/$(DEPDIR)/libigraph_la-cs_lsolve.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_lsolve.c' object='cs/libigraph_la-cs_lsolve.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_lsolve.lo `test -f 'cs/cs_lsolve.c' || echo '$(srcdir)/'`cs/cs_lsolve.c
+
+cs/libigraph_la-cs_scatter.lo: cs/cs_scatter.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_scatter.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_scatter.Tpo -c -o cs/libigraph_la-cs_scatter.lo `test -f 'cs/cs_scatter.c' || echo '$(srcdir)/'`cs/cs_scatter.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_scatter.Tpo cs/$(DEPDIR)/libigraph_la-cs_scatter.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_scatter.c' object='cs/libigraph_la-cs_scatter.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_scatter.lo `test -f 'cs/cs_scatter.c' || echo '$(srcdir)/'`cs/cs_scatter.c
+
+cs/libigraph_la-cs_cumsum.lo: cs/cs_cumsum.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_cumsum.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_cumsum.Tpo -c -o cs/libigraph_la-cs_cumsum.lo `test -f 'cs/cs_cumsum.c' || echo '$(srcdir)/'`cs/cs_cumsum.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_cumsum.Tpo cs/$(DEPDIR)/libigraph_la-cs_cumsum.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_cumsum.c' object='cs/libigraph_la-cs_cumsum.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_cumsum.lo `test -f 'cs/cs_cumsum.c' || echo '$(srcdir)/'`cs/cs_cumsum.c
+
+cs/libigraph_la-cs_ltsolve.lo: cs/cs_ltsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_ltsolve.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_ltsolve.Tpo -c -o cs/libigraph_la-cs_ltsolve.lo `test -f 'cs/cs_ltsolve.c' || echo '$(srcdir)/'`cs/cs_ltsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_ltsolve.Tpo cs/$(DEPDIR)/libigraph_la-cs_ltsolve.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_ltsolve.c' object='cs/libigraph_la-cs_ltsolve.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_ltsolve.lo `test -f 'cs/cs_ltsolve.c' || echo '$(srcdir)/'`cs/cs_ltsolve.c
+
+cs/libigraph_la-cs_scc.lo: cs/cs_scc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_scc.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_scc.Tpo -c -o cs/libigraph_la-cs_scc.lo `test -f 'cs/cs_scc.c' || echo '$(srcdir)/'`cs/cs_scc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_scc.Tpo cs/$(DEPDIR)/libigraph_la-cs_scc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_scc.c' object='cs/libigraph_la-cs_scc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_scc.lo `test -f 'cs/cs_scc.c' || echo '$(srcdir)/'`cs/cs_scc.c
+
+cs/libigraph_la-cs_dfs.lo: cs/cs_dfs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_dfs.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_dfs.Tpo -c -o cs/libigraph_la-cs_dfs.lo `test -f 'cs/cs_dfs.c' || echo '$(srcdir)/'`cs/cs_dfs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_dfs.Tpo cs/$(DEPDIR)/libigraph_la-cs_dfs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_dfs.c' object='cs/libigraph_la-cs_dfs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_dfs.lo `test -f 'cs/cs_dfs.c' || echo '$(srcdir)/'`cs/cs_dfs.c
+
+cs/libigraph_la-cs_lu.lo: cs/cs_lu.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_lu.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_lu.Tpo -c -o cs/libigraph_la-cs_lu.lo `test -f 'cs/cs_lu.c' || echo '$(srcdir)/'`cs/cs_lu.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_lu.Tpo cs/$(DEPDIR)/libigraph_la-cs_lu.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_lu.c' object='cs/libigraph_la-cs_lu.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_lu.lo `test -f 'cs/cs_lu.c' || echo '$(srcdir)/'`cs/cs_lu.c
+
+cs/libigraph_la-cs_schol.lo: cs/cs_schol.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_schol.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_schol.Tpo -c -o cs/libigraph_la-cs_schol.lo `test -f 'cs/cs_schol.c' || echo '$(srcdir)/'`cs/cs_schol.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_schol.Tpo cs/$(DEPDIR)/libigraph_la-cs_schol.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_schol.c' object='cs/libigraph_la-cs_schol.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_schol.lo `test -f 'cs/cs_schol.c' || echo '$(srcdir)/'`cs/cs_schol.c
+
+cs/libigraph_la-cs_dmperm.lo: cs/cs_dmperm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_dmperm.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_dmperm.Tpo -c -o cs/libigraph_la-cs_dmperm.lo `test -f 'cs/cs_dmperm.c' || echo '$(srcdir)/'`cs/cs_dmperm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_dmperm.Tpo cs/$(DEPDIR)/libigraph_la-cs_dmperm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_dmperm.c' object='cs/libigraph_la-cs_dmperm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_dmperm.lo `test -f 'cs/cs_dmperm.c' || echo '$(srcdir)/'`cs/cs_dmperm.c
+
+cs/libigraph_la-cs_lusol.lo: cs/cs_lusol.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_lusol.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_lusol.Tpo -c -o cs/libigraph_la-cs_lusol.lo `test -f 'cs/cs_lusol.c' || echo '$(srcdir)/'`cs/cs_lusol.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_lusol.Tpo cs/$(DEPDIR)/libigraph_la-cs_lusol.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_lusol.c' object='cs/libigraph_la-cs_lusol.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_lusol.lo `test -f 'cs/cs_lusol.c' || echo '$(srcdir)/'`cs/cs_lusol.c
+
+cs/libigraph_la-cs_spsolve.lo: cs/cs_spsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_spsolve.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_spsolve.Tpo -c -o cs/libigraph_la-cs_spsolve.lo `test -f 'cs/cs_spsolve.c' || echo '$(srcdir)/'`cs/cs_spsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_spsolve.Tpo cs/$(DEPDIR)/libigraph_la-cs_spsolve.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_spsolve.c' object='cs/libigraph_la-cs_spsolve.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_spsolve.lo `test -f 'cs/cs_spsolve.c' || echo '$(srcdir)/'`cs/cs_spsolve.c
+
+cs/libigraph_la-cs_droptol.lo: cs/cs_droptol.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_droptol.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_droptol.Tpo -c -o cs/libigraph_la-cs_droptol.lo `test -f 'cs/cs_droptol.c' || echo '$(srcdir)/'`cs/cs_droptol.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_droptol.Tpo cs/$(DEPDIR)/libigraph_la-cs_droptol.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_droptol.c' object='cs/libigraph_la-cs_droptol.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_droptol.lo `test -f 'cs/cs_droptol.c' || echo '$(srcdir)/'`cs/cs_droptol.c
+
+cs/libigraph_la-cs_malloc.lo: cs/cs_malloc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_malloc.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_malloc.Tpo -c -o cs/libigraph_la-cs_malloc.lo `test -f 'cs/cs_malloc.c' || echo '$(srcdir)/'`cs/cs_malloc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_malloc.Tpo cs/$(DEPDIR)/libigraph_la-cs_malloc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_malloc.c' object='cs/libigraph_la-cs_malloc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_malloc.lo `test -f 'cs/cs_malloc.c' || echo '$(srcdir)/'`cs/cs_malloc.c
+
+cs/libigraph_la-cs_sqr.lo: cs/cs_sqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_sqr.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_sqr.Tpo -c -o cs/libigraph_la-cs_sqr.lo `test -f 'cs/cs_sqr.c' || echo '$(srcdir)/'`cs/cs_sqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_sqr.Tpo cs/$(DEPDIR)/libigraph_la-cs_sqr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_sqr.c' object='cs/libigraph_la-cs_sqr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_sqr.lo `test -f 'cs/cs_sqr.c' || echo '$(srcdir)/'`cs/cs_sqr.c
+
+cs/libigraph_la-cs_dropzeros.lo: cs/cs_dropzeros.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_dropzeros.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_dropzeros.Tpo -c -o cs/libigraph_la-cs_dropzeros.lo `test -f 'cs/cs_dropzeros.c' || echo '$(srcdir)/'`cs/cs_dropzeros.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_dropzeros.Tpo cs/$(DEPDIR)/libigraph_la-cs_dropzeros.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_dropzeros.c' object='cs/libigraph_la-cs_dropzeros.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_dropzeros.lo `test -f 'cs/cs_dropzeros.c' || echo '$(srcdir)/'`cs/cs_dropzeros.c
+
+cs/libigraph_la-cs_maxtrans.lo: cs/cs_maxtrans.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_maxtrans.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_maxtrans.Tpo -c -o cs/libigraph_la-cs_maxtrans.lo `test -f 'cs/cs_maxtrans.c' || echo '$(srcdir)/'`cs/cs_maxtrans.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_maxtrans.Tpo cs/$(DEPDIR)/libigraph_la-cs_maxtrans.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_maxtrans.c' object='cs/libigraph_la-cs_maxtrans.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_maxtrans.lo `test -f 'cs/cs_maxtrans.c' || echo '$(srcdir)/'`cs/cs_maxtrans.c
+
+cs/libigraph_la-cs_symperm.lo: cs/cs_symperm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_symperm.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_symperm.Tpo -c -o cs/libigraph_la-cs_symperm.lo `test -f 'cs/cs_symperm.c' || echo '$(srcdir)/'`cs/cs_symperm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_symperm.Tpo cs/$(DEPDIR)/libigraph_la-cs_symperm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_symperm.c' object='cs/libigraph_la-cs_symperm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_symperm.lo `test -f 'cs/cs_symperm.c' || echo '$(srcdir)/'`cs/cs_symperm.c
+
+cs/libigraph_la-cs_dupl.lo: cs/cs_dupl.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_dupl.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_dupl.Tpo -c -o cs/libigraph_la-cs_dupl.lo `test -f 'cs/cs_dupl.c' || echo '$(srcdir)/'`cs/cs_dupl.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_dupl.Tpo cs/$(DEPDIR)/libigraph_la-cs_dupl.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_dupl.c' object='cs/libigraph_la-cs_dupl.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_dupl.lo `test -f 'cs/cs_dupl.c' || echo '$(srcdir)/'`cs/cs_dupl.c
+
+cs/libigraph_la-cs_multiply.lo: cs/cs_multiply.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_multiply.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_multiply.Tpo -c -o cs/libigraph_la-cs_multiply.lo `test -f 'cs/cs_multiply.c' || echo '$(srcdir)/'`cs/cs_multiply.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_multiply.Tpo cs/$(DEPDIR)/libigraph_la-cs_multiply.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_multiply.c' object='cs/libigraph_la-cs_multiply.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_multiply.lo `test -f 'cs/cs_multiply.c' || echo '$(srcdir)/'`cs/cs_multiply.c
+
+cs/libigraph_la-cs_tdfs.lo: cs/cs_tdfs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_tdfs.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_tdfs.Tpo -c -o cs/libigraph_la-cs_tdfs.lo `test -f 'cs/cs_tdfs.c' || echo '$(srcdir)/'`cs/cs_tdfs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_tdfs.Tpo cs/$(DEPDIR)/libigraph_la-cs_tdfs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_tdfs.c' object='cs/libigraph_la-cs_tdfs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_tdfs.lo `test -f 'cs/cs_tdfs.c' || echo '$(srcdir)/'`cs/cs_tdfs.c
+
+cs/libigraph_la-cs_entry.lo: cs/cs_entry.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_entry.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_entry.Tpo -c -o cs/libigraph_la-cs_entry.lo `test -f 'cs/cs_entry.c' || echo '$(srcdir)/'`cs/cs_entry.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_entry.Tpo cs/$(DEPDIR)/libigraph_la-cs_entry.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_entry.c' object='cs/libigraph_la-cs_entry.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_entry.lo `test -f 'cs/cs_entry.c' || echo '$(srcdir)/'`cs/cs_entry.c
+
+cs/libigraph_la-cs_norm.lo: cs/cs_norm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_norm.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_norm.Tpo -c -o cs/libigraph_la-cs_norm.lo `test -f 'cs/cs_norm.c' || echo '$(srcdir)/'`cs/cs_norm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_norm.Tpo cs/$(DEPDIR)/libigraph_la-cs_norm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_norm.c' object='cs/libigraph_la-cs_norm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_norm.lo `test -f 'cs/cs_norm.c' || echo '$(srcdir)/'`cs/cs_norm.c
+
+cs/libigraph_la-cs_transpose.lo: cs/cs_transpose.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_transpose.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_transpose.Tpo -c -o cs/libigraph_la-cs_transpose.lo `test -f 'cs/cs_transpose.c' || echo '$(srcdir)/'`cs/cs_transpose.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_transpose.Tpo cs/$(DEPDIR)/libigraph_la-cs_transpose.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_transpose.c' object='cs/libigraph_la-cs_transpose.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_transpose.lo `test -f 'cs/cs_transpose.c' || echo '$(srcdir)/'`cs/cs_transpose.c
+
+cs/libigraph_la-cs_ereach.lo: cs/cs_ereach.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_ereach.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_ereach.Tpo -c -o cs/libigraph_la-cs_ereach.lo `test -f 'cs/cs_ereach.c' || echo '$(srcdir)/'`cs/cs_ereach.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_ereach.Tpo cs/$(DEPDIR)/libigraph_la-cs_ereach.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_ereach.c' object='cs/libigraph_la-cs_ereach.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_ereach.lo `test -f 'cs/cs_ereach.c' || echo '$(srcdir)/'`cs/cs_ereach.c
+
+cs/libigraph_la-cs_permute.lo: cs/cs_permute.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_permute.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_permute.Tpo -c -o cs/libigraph_la-cs_permute.lo `test -f 'cs/cs_permute.c' || echo '$(srcdir)/'`cs/cs_permute.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_permute.Tpo cs/$(DEPDIR)/libigraph_la-cs_permute.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_permute.c' object='cs/libigraph_la-cs_permute.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_permute.lo `test -f 'cs/cs_permute.c' || echo '$(srcdir)/'`cs/cs_permute.c
+
+cs/libigraph_la-cs_updown.lo: cs/cs_updown.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_updown.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_updown.Tpo -c -o cs/libigraph_la-cs_updown.lo `test -f 'cs/cs_updown.c' || echo '$(srcdir)/'`cs/cs_updown.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_updown.Tpo cs/$(DEPDIR)/libigraph_la-cs_updown.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_updown.c' object='cs/libigraph_la-cs_updown.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_updown.lo `test -f 'cs/cs_updown.c' || echo '$(srcdir)/'`cs/cs_updown.c
+
+cs/libigraph_la-cs_etree.lo: cs/cs_etree.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_etree.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_etree.Tpo -c -o cs/libigraph_la-cs_etree.lo `test -f 'cs/cs_etree.c' || echo '$(srcdir)/'`cs/cs_etree.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_etree.Tpo cs/$(DEPDIR)/libigraph_la-cs_etree.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_etree.c' object='cs/libigraph_la-cs_etree.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_etree.lo `test -f 'cs/cs_etree.c' || echo '$(srcdir)/'`cs/cs_etree.c
+
+cs/libigraph_la-cs_pinv.lo: cs/cs_pinv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_pinv.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_pinv.Tpo -c -o cs/libigraph_la-cs_pinv.lo `test -f 'cs/cs_pinv.c' || echo '$(srcdir)/'`cs/cs_pinv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_pinv.Tpo cs/$(DEPDIR)/libigraph_la-cs_pinv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_pinv.c' object='cs/libigraph_la-cs_pinv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_pinv.lo `test -f 'cs/cs_pinv.c' || echo '$(srcdir)/'`cs/cs_pinv.c
+
+cs/libigraph_la-cs_usolve.lo: cs/cs_usolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_usolve.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_usolve.Tpo -c -o cs/libigraph_la-cs_usolve.lo `test -f 'cs/cs_usolve.c' || echo '$(srcdir)/'`cs/cs_usolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_usolve.Tpo cs/$(DEPDIR)/libigraph_la-cs_usolve.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_usolve.c' object='cs/libigraph_la-cs_usolve.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_usolve.lo `test -f 'cs/cs_usolve.c' || echo '$(srcdir)/'`cs/cs_usolve.c
+
+cs/libigraph_la-cs_fkeep.lo: cs/cs_fkeep.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_fkeep.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_fkeep.Tpo -c -o cs/libigraph_la-cs_fkeep.lo `test -f 'cs/cs_fkeep.c' || echo '$(srcdir)/'`cs/cs_fkeep.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_fkeep.Tpo cs/$(DEPDIR)/libigraph_la-cs_fkeep.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_fkeep.c' object='cs/libigraph_la-cs_fkeep.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_fkeep.lo `test -f 'cs/cs_fkeep.c' || echo '$(srcdir)/'`cs/cs_fkeep.c
+
+cs/libigraph_la-cs_post.lo: cs/cs_post.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_post.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_post.Tpo -c -o cs/libigraph_la-cs_post.lo `test -f 'cs/cs_post.c' || echo '$(srcdir)/'`cs/cs_post.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_post.Tpo cs/$(DEPDIR)/libigraph_la-cs_post.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_post.c' object='cs/libigraph_la-cs_post.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_post.lo `test -f 'cs/cs_post.c' || echo '$(srcdir)/'`cs/cs_post.c
+
+cs/libigraph_la-cs_util.lo: cs/cs_util.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_util.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_util.Tpo -c -o cs/libigraph_la-cs_util.lo `test -f 'cs/cs_util.c' || echo '$(srcdir)/'`cs/cs_util.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_util.Tpo cs/$(DEPDIR)/libigraph_la-cs_util.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_util.c' object='cs/libigraph_la-cs_util.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_util.lo `test -f 'cs/cs_util.c' || echo '$(srcdir)/'`cs/cs_util.c
+
+cs/libigraph_la-cs_gaxpy.lo: cs/cs_gaxpy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_gaxpy.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_gaxpy.Tpo -c -o cs/libigraph_la-cs_gaxpy.lo `test -f 'cs/cs_gaxpy.c' || echo '$(srcdir)/'`cs/cs_gaxpy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_gaxpy.Tpo cs/$(DEPDIR)/libigraph_la-cs_gaxpy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_gaxpy.c' object='cs/libigraph_la-cs_gaxpy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_gaxpy.lo `test -f 'cs/cs_gaxpy.c' || echo '$(srcdir)/'`cs/cs_gaxpy.c
+
+cs/libigraph_la-cs_print.lo: cs/cs_print.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_print.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_print.Tpo -c -o cs/libigraph_la-cs_print.lo `test -f 'cs/cs_print.c' || echo '$(srcdir)/'`cs/cs_print.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_print.Tpo cs/$(DEPDIR)/libigraph_la-cs_print.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_print.c' object='cs/libigraph_la-cs_print.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_print.lo `test -f 'cs/cs_print.c' || echo '$(srcdir)/'`cs/cs_print.c
+
+cs/libigraph_la-cs_utsolve.lo: cs/cs_utsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT cs/libigraph_la-cs_utsolve.lo -MD -MP -MF cs/$(DEPDIR)/libigraph_la-cs_utsolve.Tpo -c -o cs/libigraph_la-cs_utsolve.lo `test -f 'cs/cs_utsolve.c' || echo '$(srcdir)/'`cs/cs_utsolve.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) cs/$(DEPDIR)/libigraph_la-cs_utsolve.Tpo cs/$(DEPDIR)/libigraph_la-cs_utsolve.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cs/cs_utsolve.c' object='cs/libigraph_la-cs_utsolve.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o cs/libigraph_la-cs_utsolve.lo `test -f 'cs/cs_utsolve.c' || echo '$(srcdir)/'`cs/cs_utsolve.c
+
+libigraph_la-sparsemat.lo: sparsemat.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-sparsemat.lo -MD -MP -MF $(DEPDIR)/libigraph_la-sparsemat.Tpo -c -o libigraph_la-sparsemat.lo `test -f 'sparsemat.c' || echo '$(srcdir)/'`sparsemat.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-sparsemat.Tpo $(DEPDIR)/libigraph_la-sparsemat.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sparsemat.c' object='libigraph_la-sparsemat.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-sparsemat.lo `test -f 'sparsemat.c' || echo '$(srcdir)/'`sparsemat.c
+
+libigraph_la-mixing.lo: mixing.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-mixing.lo -MD -MP -MF $(DEPDIR)/libigraph_la-mixing.Tpo -c -o libigraph_la-mixing.lo `test -f 'mixing.c' || echo '$(srcdir)/'`mixing.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-mixing.Tpo $(DEPDIR)/libigraph_la-mixing.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mixing.c' object='libigraph_la-mixing.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-mixing.lo `test -f 'mixing.c' || echo '$(srcdir)/'`mixing.c
+
+libigraph_la-bigint.lo: bigint.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-bigint.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bigint.Tpo -c -o libigraph_la-bigint.lo `test -f 'bigint.c' || echo '$(srcdir)/'`bigint.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bigint.Tpo $(DEPDIR)/libigraph_la-bigint.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bigint.c' object='libigraph_la-bigint.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-bigint.lo `test -f 'bigint.c' || echo '$(srcdir)/'`bigint.c
+
+libigraph_la-bignum.lo: bignum.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-bignum.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bignum.Tpo -c -o libigraph_la-bignum.lo `test -f 'bignum.c' || echo '$(srcdir)/'`bignum.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bignum.Tpo $(DEPDIR)/libigraph_la-bignum.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bignum.c' object='libigraph_la-bignum.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-bignum.lo `test -f 'bignum.c' || echo '$(srcdir)/'`bignum.c
+
+libigraph_la-version.lo: version.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-version.lo -MD -MP -MF $(DEPDIR)/libigraph_la-version.Tpo -c -o libigraph_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-version.Tpo $(DEPDIR)/libigraph_la-version.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='version.c' object='libigraph_la-version.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c
+
+libigraph_la-optimal_modularity.lo: optimal_modularity.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-optimal_modularity.lo -MD -MP -MF $(DEPDIR)/libigraph_la-optimal_modularity.Tpo -c -o libigraph_la-optimal_modularity.lo `test -f 'optimal_modularity.c' || echo '$(srcdir)/'`optimal_modularity.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-optimal_modularity.Tpo $(DEPDIR)/libigraph_la-optimal_modularity.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='optimal_modularity.c' object='libigraph_la-optimal_modularity.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-optimal_modularity.lo `test -f 'optimal_modularity.c' || echo '$(srcdir)/'`optimal_modularity.c
+
+libigraph_la-igraph_fixed_vectorlist.lo: igraph_fixed_vectorlist.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_fixed_vectorlist.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_fixed_vectorlist.Tpo -c -o libigraph_la-igraph_fixed_vectorlist.lo `test -f 'igraph_fixed_vectorlist.c' || echo '$(srcdir)/'`igraph_fixed_vectorlist.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_fixed_vectorlist.Tpo $(DEPDIR)/libigraph_la-igraph_fixed_vectorlist.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_fixed_vectorlist.c' object='libigraph_la-igraph_fixed_vectorlist.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_fixed_vectorlist.lo `test -f 'igraph_fixed_vectorlist.c' || echo '$(srcdir)/'`igraph_fixed_vectorlist.c
+
+libigraph_la-separators.lo: separators.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-separators.lo -MD -MP -MF $(DEPDIR)/libigraph_la-separators.Tpo -c -o libigraph_la-separators.lo `test -f 'separators.c' || echo '$(srcdir)/'`separators.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-separators.Tpo $(DEPDIR)/libigraph_la-separators.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='separators.c' object='libigraph_la-separators.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-separators.lo `test -f 'separators.c' || echo '$(srcdir)/'`separators.c
+
+libigraph_la-igraph_marked_queue.lo: igraph_marked_queue.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_marked_queue.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_marked_queue.Tpo -c -o libigraph_la-igraph_marked_queue.lo `test -f 'igraph_marked_queue.c' || echo '$(srcdir)/'`igraph_marked_queue.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_marked_queue.Tpo $(DEPDIR)/libigraph_la-igraph_marked_queue.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_marked_queue.c' object='libigraph_la-igraph_marked_queue.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_marked_queue.lo `test -f 'igraph_marked_queue.c' || echo '$(srcdir)/'`igraph_marked_queue.c
+
+libigraph_la-igraph_estack.lo: igraph_estack.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-igraph_estack.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_estack.Tpo -c -o libigraph_la-igraph_estack.lo `test -f 'igraph_estack.c' || echo '$(srcdir)/'`igraph_estack.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_estack.Tpo $(DEPDIR)/libigraph_la-igraph_estack.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='igraph_estack.c' object='libigraph_la-igraph_estack.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-igraph_estack.lo `test -f 'igraph_estack.c' || echo '$(srcdir)/'`igraph_estack.c
+
+libigraph_la-st-cuts.lo: st-cuts.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-st-cuts.lo -MD -MP -MF $(DEPDIR)/libigraph_la-st-cuts.Tpo -c -o libigraph_la-st-cuts.lo `test -f 'st-cuts.c' || echo '$(srcdir)/'`st-cuts.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-st-cuts.Tpo $(DEPDIR)/libigraph_la-st-cuts.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='st-cuts.c' object='libigraph_la-st-cuts.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-st-cuts.lo `test -f 'st-cuts.c' || echo '$(srcdir)/'`st-cuts.c
+
+libigraph_la-cohesive_blocks.lo: cohesive_blocks.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-cohesive_blocks.lo -MD -MP -MF $(DEPDIR)/libigraph_la-cohesive_blocks.Tpo -c -o libigraph_la-cohesive_blocks.lo `test -f 'cohesive_blocks.c' || echo '$(srcdir)/'`cohesive_blocks.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-cohesive_blocks.Tpo $(DEPDIR)/libigraph_la-cohesive_blocks.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cohesive_blocks.c' object='libigraph_la-cohesive_blocks.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-cohesive_blocks.lo `test -f 'cohesive_blocks.c' || echo '$(srcdir)/'`cohesive_blocks.c
+
+libigraph_la-statusbar.lo: statusbar.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-statusbar.lo -MD -MP -MF $(DEPDIR)/libigraph_la-statusbar.Tpo -c -o libigraph_la-statusbar.lo `test -f 'statusbar.c' || echo '$(srcdir)/'`statusbar.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-statusbar.Tpo $(DEPDIR)/libigraph_la-statusbar.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='statusbar.c' object='libigraph_la-statusbar.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-statusbar.lo `test -f 'statusbar.c' || echo '$(srcdir)/'`statusbar.c
+
+libigraph_la-lapack.lo: lapack.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-lapack.lo -MD -MP -MF $(DEPDIR)/libigraph_la-lapack.Tpo -c -o libigraph_la-lapack.lo `test -f 'lapack.c' || echo '$(srcdir)/'`lapack.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-lapack.Tpo $(DEPDIR)/libigraph_la-lapack.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack.c' object='libigraph_la-lapack.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-lapack.lo `test -f 'lapack.c' || echo '$(srcdir)/'`lapack.c
+
+libigraph_la-complex.lo: complex.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-complex.lo -MD -MP -MF $(DEPDIR)/libigraph_la-complex.Tpo -c -o libigraph_la-complex.lo `test -f 'complex.c' || echo '$(srcdir)/'`complex.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-complex.Tpo $(DEPDIR)/libigraph_la-complex.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='complex.c' object='libigraph_la-complex.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-complex.lo `test -f 'complex.c' || echo '$(srcdir)/'`complex.c
+
+libigraph_la-eigen.lo: eigen.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-eigen.lo -MD -MP -MF $(DEPDIR)/libigraph_la-eigen.Tpo -c -o libigraph_la-eigen.lo `test -f 'eigen.c' || echo '$(srcdir)/'`eigen.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-eigen.Tpo $(DEPDIR)/libigraph_la-eigen.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='eigen.c' object='libigraph_la-eigen.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-eigen.lo `test -f 'eigen.c' || echo '$(srcdir)/'`eigen.c
+
+libigraph_la-feedback_arc_set.lo: feedback_arc_set.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-feedback_arc_set.lo -MD -MP -MF $(DEPDIR)/libigraph_la-feedback_arc_set.Tpo -c -o libigraph_la-feedback_arc_set.lo `test -f 'feedback_arc_set.c' || echo '$(srcdir)/'`feedback_arc_set.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-feedback_arc_set.Tpo $(DEPDIR)/libigraph_la-feedback_arc_set.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='feedback_arc_set.c' object='libigraph_la-feedback_arc_set.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-feedback_arc_set.lo `test -f 'feedback_arc_set.c' || echo '$(srcdir)/'`feedback_arc_set.c
+
+libigraph_la-sugiyama.lo: sugiyama.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-sugiyama.lo -MD -MP -MF $(DEPDIR)/libigraph_la-sugiyama.Tpo -c -o libigraph_la-sugiyama.lo `test -f 'sugiyama.c' || echo '$(srcdir)/'`sugiyama.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-sugiyama.Tpo $(DEPDIR)/libigraph_la-sugiyama.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sugiyama.c' object='libigraph_la-sugiyama.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-sugiyama.lo `test -f 'sugiyama.c' || echo '$(srcdir)/'`sugiyama.c
+
+libigraph_la-glpk_support.lo: glpk_support.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-glpk_support.lo -MD -MP -MF $(DEPDIR)/libigraph_la-glpk_support.Tpo -c -o libigraph_la-glpk_support.lo `test -f 'glpk_support.c' || echo '$(srcdir)/'`glpk_support.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-glpk_support.Tpo $(DEPDIR)/libigraph_la-glpk_support.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='glpk_support.c' object='libigraph_la-glpk_support.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-glpk_support.lo `test -f 'glpk_support.c' || echo '$(srcdir)/'`glpk_support.c
+
+libigraph_la-distances.lo: distances.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-distances.lo -MD -MP -MF $(DEPDIR)/libigraph_la-distances.Tpo -c -o libigraph_la-distances.lo `test -f 'distances.c' || echo '$(srcdir)/'`distances.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-distances.Tpo $(DEPDIR)/libigraph_la-distances.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='distances.c' object='libigraph_la-distances.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-distances.lo `test -f 'distances.c' || echo '$(srcdir)/'`distances.c
+
+libigraph_la-fortran_intrinsics.lo: fortran_intrinsics.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-fortran_intrinsics.lo -MD -MP -MF $(DEPDIR)/libigraph_la-fortran_intrinsics.Tpo -c -o libigraph_la-fortran_intrinsics.lo `test -f 'fortran_intrinsics.c' || echo '$(srcdir)/'`fortran_intrinsics.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-fortran_intrinsics.Tpo $(DEPDIR)/libigraph_la-fortran_intrinsics.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='fortran_intrinsics.c' object='libigraph_la-fortran_intrinsics.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-fortran_intrinsics.lo `test -f 'fortran_intrinsics.c' || echo '$(srcdir)/'`fortran_intrinsics.c
+
+libigraph_la-matching.lo: matching.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-matching.lo -MD -MP -MF $(DEPDIR)/libigraph_la-matching.Tpo -c -o libigraph_la-matching.lo `test -f 'matching.c' || echo '$(srcdir)/'`matching.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-matching.Tpo $(DEPDIR)/libigraph_la-matching.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='matching.c' object='libigraph_la-matching.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-matching.lo `test -f 'matching.c' || echo '$(srcdir)/'`matching.c
+
+libigraph_la-scg.lo: scg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-scg.lo -MD -MP -MF $(DEPDIR)/libigraph_la-scg.Tpo -c -o libigraph_la-scg.lo `test -f 'scg.c' || echo '$(srcdir)/'`scg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-scg.Tpo $(DEPDIR)/libigraph_la-scg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='scg.c' object='libigraph_la-scg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-scg.lo `test -f 'scg.c' || echo '$(srcdir)/'`scg.c
+
+libigraph_la-scg_approximate_methods.lo: scg_approximate_methods.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-scg_approximate_methods.lo -MD -MP -MF $(DEPDIR)/libigraph_la-scg_approximate_methods.Tpo -c -o libigraph_la-scg_approximate_methods.lo `test -f 'scg_approximate_methods.c' || echo '$(srcdir)/'`scg_approximate_methods.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-scg_approximate_methods.Tpo $(DEPDIR)/libigraph_la-scg_approximate_methods.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='scg_approximate_methods.c' object='libigraph_la-scg_approximate_methods.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-scg_approximate_methods.lo `test -f 'scg_approximate_methods.c' || echo '$(srcdir)/'`scg_approximate_methods.c
+
+libigraph_la-scg_exact_scg.lo: scg_exact_scg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-scg_exact_scg.lo -MD -MP -MF $(DEPDIR)/libigraph_la-scg_exact_scg.Tpo -c -o libigraph_la-scg_exact_scg.lo `test -f 'scg_exact_scg.c' || echo '$(srcdir)/'`scg_exact_scg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-scg_exact_scg.Tpo $(DEPDIR)/libigraph_la-scg_exact_scg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='scg_exact_scg.c' object='libigraph_la-scg_exact_scg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-scg_exact_scg.lo `test -f 'scg_exact_scg.c' || echo '$(srcdir)/'`scg_exact_scg.c
+
+libigraph_la-scg_kmeans.lo: scg_kmeans.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-scg_kmeans.lo -MD -MP -MF $(DEPDIR)/libigraph_la-scg_kmeans.Tpo -c -o libigraph_la-scg_kmeans.lo `test -f 'scg_kmeans.c' || echo '$(srcdir)/'`scg_kmeans.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-scg_kmeans.Tpo $(DEPDIR)/libigraph_la-scg_kmeans.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='scg_kmeans.c' object='libigraph_la-scg_kmeans.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-scg_kmeans.lo `test -f 'scg_kmeans.c' || echo '$(srcdir)/'`scg_kmeans.c
+
+libigraph_la-scg_utils.lo: scg_utils.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-scg_utils.lo -MD -MP -MF $(DEPDIR)/libigraph_la-scg_utils.Tpo -c -o libigraph_la-scg_utils.lo `test -f 'scg_utils.c' || echo '$(srcdir)/'`scg_utils.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-scg_utils.Tpo $(DEPDIR)/libigraph_la-scg_utils.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='scg_utils.c' object='libigraph_la-scg_utils.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-scg_utils.lo `test -f 'scg_utils.c' || echo '$(srcdir)/'`scg_utils.c
+
+libigraph_la-scg_optimal_method.lo: scg_optimal_method.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-scg_optimal_method.lo -MD -MP -MF $(DEPDIR)/libigraph_la-scg_optimal_method.Tpo -c -o libigraph_la-scg_optimal_method.lo `test -f 'scg_optimal_method.c' || echo '$(srcdir)/'`scg_optimal_method.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-scg_optimal_method.Tpo $(DEPDIR)/libigraph_la-scg_optimal_method.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='scg_optimal_method.c' object='libigraph_la-scg_optimal_method.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-scg_optimal_method.lo `test -f 'scg_optimal_method.c' || echo '$(srcdir)/'`scg_optimal_method.c
+
+libigraph_la-qsort.lo: qsort.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-qsort.lo -MD -MP -MF $(DEPDIR)/libigraph_la-qsort.Tpo -c -o libigraph_la-qsort.lo `test -f 'qsort.c' || echo '$(srcdir)/'`qsort.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-qsort.Tpo $(DEPDIR)/libigraph_la-qsort.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='qsort.c' object='libigraph_la-qsort.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-qsort.lo `test -f 'qsort.c' || echo '$(srcdir)/'`qsort.c
+
+libigraph_la-qsort_r.lo: qsort_r.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-qsort_r.lo -MD -MP -MF $(DEPDIR)/libigraph_la-qsort_r.Tpo -c -o libigraph_la-qsort_r.lo `test -f 'qsort_r.c' || echo '$(srcdir)/'`qsort_r.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-qsort_r.Tpo $(DEPDIR)/libigraph_la-qsort_r.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='qsort_r.c' object='libigraph_la-qsort_r.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-qsort_r.lo `test -f 'qsort_r.c' || echo '$(srcdir)/'`qsort_r.c
+
+libigraph_la-types.lo: types.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-types.lo -MD -MP -MF $(DEPDIR)/libigraph_la-types.Tpo -c -o libigraph_la-types.lo `test -f 'types.c' || echo '$(srcdir)/'`types.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-types.Tpo $(DEPDIR)/libigraph_la-types.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='types.c' object='libigraph_la-types.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-types.lo `test -f 'types.c' || echo '$(srcdir)/'`types.c
+
+libigraph_la-lad.lo: lad.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-lad.lo -MD -MP -MF $(DEPDIR)/libigraph_la-lad.Tpo -c -o libigraph_la-lad.lo `test -f 'lad.c' || echo '$(srcdir)/'`lad.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-lad.Tpo $(DEPDIR)/libigraph_la-lad.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lad.c' object='libigraph_la-lad.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-lad.lo `test -f 'lad.c' || echo '$(srcdir)/'`lad.c
+
+libigraph_la-hacks.lo: hacks.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-hacks.lo -MD -MP -MF $(DEPDIR)/libigraph_la-hacks.Tpo -c -o libigraph_la-hacks.lo `test -f 'hacks.c' || echo '$(srcdir)/'`hacks.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-hacks.Tpo $(DEPDIR)/libigraph_la-hacks.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hacks.c' object='libigraph_la-hacks.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-hacks.lo `test -f 'hacks.c' || echo '$(srcdir)/'`hacks.c
+
+libigraph_la-triangles.lo: triangles.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-triangles.lo -MD -MP -MF $(DEPDIR)/libigraph_la-triangles.Tpo -c -o libigraph_la-triangles.lo `test -f 'triangles.c' || echo '$(srcdir)/'`triangles.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-triangles.Tpo $(DEPDIR)/libigraph_la-triangles.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='triangles.c' object='libigraph_la-triangles.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-triangles.lo `test -f 'triangles.c' || echo '$(srcdir)/'`triangles.c
+
+libigraph_la-glet.lo: glet.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-glet.lo -MD -MP -MF $(DEPDIR)/libigraph_la-glet.Tpo -c -o libigraph_la-glet.lo `test -f 'glet.c' || echo '$(srcdir)/'`glet.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-glet.Tpo $(DEPDIR)/libigraph_la-glet.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='glet.c' object='libigraph_la-glet.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-glet.lo `test -f 'glet.c' || echo '$(srcdir)/'`glet.c
+
+libigraph_la-maximal_cliques.lo: maximal_cliques.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-maximal_cliques.lo -MD -MP -MF $(DEPDIR)/libigraph_la-maximal_cliques.Tpo -c -o libigraph_la-maximal_cliques.lo `test -f 'maximal_cliques.c' || echo '$(srcdir)/'`maximal_cliques.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-maximal_cliques.Tpo $(DEPDIR)/libigraph_la-maximal_cliques.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='maximal_cliques.c' object='libigraph_la-maximal_cliques.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-maximal_cliques.lo `test -f 'maximal_cliques.c' || echo '$(srcdir)/'`maximal_cliques.c
+
+libigraph_la-sbm.lo: sbm.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-sbm.lo -MD -MP -MF $(DEPDIR)/libigraph_la-sbm.Tpo -c -o libigraph_la-sbm.lo `test -f 'sbm.c' || echo '$(srcdir)/'`sbm.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-sbm.Tpo $(DEPDIR)/libigraph_la-sbm.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sbm.c' object='libigraph_la-sbm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-sbm.lo `test -f 'sbm.c' || echo '$(srcdir)/'`sbm.c
+
+libigraph_la-sir.lo: sir.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -MT libigraph_la-sir.lo -MD -MP -MF $(DEPDIR)/libigraph_la-sir.Tpo -c -o libigraph_la-sir.lo `test -f 'sir.c' || echo '$(srcdir)/'`sir.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-sir.Tpo $(DEPDIR)/libigraph_la-sir.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sir.c' object='libigraph_la-sir.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CFLAGS) $(CFLAGS) -c -o libigraph_la-sir.lo `test -f 'sir.c' || echo '$(srcdir)/'`sir.c
+
+lapack/liblapack_la-dgeev.lo: lapack/dgeev.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgeev.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgeev.Tpo -c -o lapack/liblapack_la-dgeev.lo `test -f 'lapack/dgeev.c' || echo '$(srcdir)/'`lapack/dgeev.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgeev.Tpo lapack/$(DEPDIR)/liblapack_la-dgeev.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgeev.c' object='lapack/liblapack_la-dgeev.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgeev.lo `test -f 'lapack/dgeev.c' || echo '$(srcdir)/'`lapack/dgeev.c
+
+lapack/liblapack_la-dgebak.lo: lapack/dgebak.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgebak.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgebak.Tpo -c -o lapack/liblapack_la-dgebak.lo `test -f 'lapack/dgebak.c' || echo '$(srcdir)/'`lapack/dgebak.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgebak.Tpo lapack/$(DEPDIR)/liblapack_la-dgebak.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgebak.c' object='lapack/liblapack_la-dgebak.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgebak.lo `test -f 'lapack/dgebak.c' || echo '$(srcdir)/'`lapack/dgebak.c
+
+lapack/liblapack_la-xerbla.lo: lapack/xerbla.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-xerbla.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-xerbla.Tpo -c -o lapack/liblapack_la-xerbla.lo `test -f 'lapack/xerbla.c' || echo '$(srcdir)/'`lapack/xerbla.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-xerbla.Tpo lapack/$(DEPDIR)/liblapack_la-xerbla.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/xerbla.c' object='lapack/liblapack_la-xerbla.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-xerbla.lo `test -f 'lapack/xerbla.c' || echo '$(srcdir)/'`lapack/xerbla.c
+
+lapack/liblapack_la-dgebal.lo: lapack/dgebal.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgebal.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgebal.Tpo -c -o lapack/liblapack_la-dgebal.lo `test -f 'lapack/dgebal.c' || echo '$(srcdir)/'`lapack/dgebal.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgebal.Tpo lapack/$(DEPDIR)/liblapack_la-dgebal.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgebal.c' object='lapack/liblapack_la-dgebal.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgebal.lo `test -f 'lapack/dgebal.c' || echo '$(srcdir)/'`lapack/dgebal.c
+
+lapack/liblapack_la-disnan.lo: lapack/disnan.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-disnan.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-disnan.Tpo -c -o lapack/liblapack_la-disnan.lo `test -f 'lapack/disnan.c' || echo '$(srcdir)/'`lapack/disnan.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-disnan.Tpo lapack/$(DEPDIR)/liblapack_la-disnan.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/disnan.c' object='lapack/liblapack_la-disnan.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-disnan.lo `test -f 'lapack/disnan.c' || echo '$(srcdir)/'`lapack/disnan.c
+
+lapack/liblapack_la-dlaisnan.lo: lapack/dlaisnan.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaisnan.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaisnan.Tpo -c -o lapack/liblapack_la-dlaisnan.lo `test -f 'lapack/dlaisnan.c' || echo '$(srcdir)/'`lapack/dlaisnan.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaisnan.Tpo lapack/$(DEPDIR)/liblapack_la-dlaisnan.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaisnan.c' object='lapack/liblapack_la-dlaisnan.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaisnan.lo `test -f 'lapack/dlaisnan.c' || echo '$(srcdir)/'`lapack/dlaisnan.c
+
+lapack/liblapack_la-dgehrd.lo: lapack/dgehrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgehrd.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgehrd.Tpo -c -o lapack/liblapack_la-dgehrd.lo `test -f 'lapack/dgehrd.c' || echo '$(srcdir)/'`lapack/dgehrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgehrd.Tpo lapack/$(DEPDIR)/liblapack_la-dgehrd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgehrd.c' object='lapack/liblapack_la-dgehrd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgehrd.lo `test -f 'lapack/dgehrd.c' || echo '$(srcdir)/'`lapack/dgehrd.c
+
+lapack/liblapack_la-dgehd2.lo: lapack/dgehd2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgehd2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgehd2.Tpo -c -o lapack/liblapack_la-dgehd2.lo `test -f 'lapack/dgehd2.c' || echo '$(srcdir)/'`lapack/dgehd2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgehd2.Tpo lapack/$(DEPDIR)/liblapack_la-dgehd2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgehd2.c' object='lapack/liblapack_la-dgehd2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgehd2.lo `test -f 'lapack/dgehd2.c' || echo '$(srcdir)/'`lapack/dgehd2.c
+
+lapack/liblapack_la-dlarf.lo: lapack/dlarf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarf.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarf.Tpo -c -o lapack/liblapack_la-dlarf.lo `test -f 'lapack/dlarf.c' || echo '$(srcdir)/'`lapack/dlarf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarf.Tpo lapack/$(DEPDIR)/liblapack_la-dlarf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarf.c' object='lapack/liblapack_la-dlarf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarf.lo `test -f 'lapack/dlarf.c' || echo '$(srcdir)/'`lapack/dlarf.c
+
+lapack/liblapack_la-iladlc.lo: lapack/iladlc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-iladlc.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-iladlc.Tpo -c -o lapack/liblapack_la-iladlc.lo `test -f 'lapack/iladlc.c' || echo '$(srcdir)/'`lapack/iladlc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-iladlc.Tpo lapack/$(DEPDIR)/liblapack_la-iladlc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/iladlc.c' object='lapack/liblapack_la-iladlc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-iladlc.lo `test -f 'lapack/iladlc.c' || echo '$(srcdir)/'`lapack/iladlc.c
+
+lapack/liblapack_la-iladlr.lo: lapack/iladlr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-iladlr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-iladlr.Tpo -c -o lapack/liblapack_la-iladlr.lo `test -f 'lapack/iladlr.c' || echo '$(srcdir)/'`lapack/iladlr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-iladlr.Tpo lapack/$(DEPDIR)/liblapack_la-iladlr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/iladlr.c' object='lapack/liblapack_la-iladlr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-iladlr.lo `test -f 'lapack/iladlr.c' || echo '$(srcdir)/'`lapack/iladlr.c
+
+lapack/liblapack_la-dlarfg.lo: lapack/dlarfg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarfg.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarfg.Tpo -c -o lapack/liblapack_la-dlarfg.lo `test -f 'lapack/dlarfg.c' || echo '$(srcdir)/'`lapack/dlarfg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarfg.Tpo lapack/$(DEPDIR)/liblapack_la-dlarfg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarfg.c' object='lapack/liblapack_la-dlarfg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarfg.lo `test -f 'lapack/dlarfg.c' || echo '$(srcdir)/'`lapack/dlarfg.c
+
+lapack/liblapack_la-dlapy2.lo: lapack/dlapy2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlapy2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlapy2.Tpo -c -o lapack/liblapack_la-dlapy2.lo `test -f 'lapack/dlapy2.c' || echo '$(srcdir)/'`lapack/dlapy2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlapy2.Tpo lapack/$(DEPDIR)/liblapack_la-dlapy2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlapy2.c' object='lapack/liblapack_la-dlapy2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlapy2.lo `test -f 'lapack/dlapy2.c' || echo '$(srcdir)/'`lapack/dlapy2.c
+
+lapack/liblapack_la-dlahr2.lo: lapack/dlahr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlahr2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlahr2.Tpo -c -o lapack/liblapack_la-dlahr2.lo `test -f 'lapack/dlahr2.c' || echo '$(srcdir)/'`lapack/dlahr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlahr2.Tpo lapack/$(DEPDIR)/liblapack_la-dlahr2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlahr2.c' object='lapack/liblapack_la-dlahr2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlahr2.lo `test -f 'lapack/dlahr2.c' || echo '$(srcdir)/'`lapack/dlahr2.c
+
+lapack/liblapack_la-dlacpy.lo: lapack/dlacpy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlacpy.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlacpy.Tpo -c -o lapack/liblapack_la-dlacpy.lo `test -f 'lapack/dlacpy.c' || echo '$(srcdir)/'`lapack/dlacpy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlacpy.Tpo lapack/$(DEPDIR)/liblapack_la-dlacpy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlacpy.c' object='lapack/liblapack_la-dlacpy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlacpy.lo `test -f 'lapack/dlacpy.c' || echo '$(srcdir)/'`lapack/dlacpy.c
+
+lapack/liblapack_la-dlarfb.lo: lapack/dlarfb.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarfb.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarfb.Tpo -c -o lapack/liblapack_la-dlarfb.lo `test -f 'lapack/dlarfb.c' || echo '$(srcdir)/'`lapack/dlarfb.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarfb.Tpo lapack/$(DEPDIR)/liblapack_la-dlarfb.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarfb.c' object='lapack/liblapack_la-dlarfb.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarfb.lo `test -f 'lapack/dlarfb.c' || echo '$(srcdir)/'`lapack/dlarfb.c
+
+lapack/liblapack_la-ilaenv.lo: lapack/ilaenv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-ilaenv.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-ilaenv.Tpo -c -o lapack/liblapack_la-ilaenv.lo `test -f 'lapack/ilaenv.c' || echo '$(srcdir)/'`lapack/ilaenv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-ilaenv.Tpo lapack/$(DEPDIR)/liblapack_la-ilaenv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/ilaenv.c' object='lapack/liblapack_la-ilaenv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-ilaenv.lo `test -f 'lapack/ilaenv.c' || echo '$(srcdir)/'`lapack/ilaenv.c
+
+lapack/liblapack_la-ieeeck.lo: lapack/ieeeck.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-ieeeck.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-ieeeck.Tpo -c -o lapack/liblapack_la-ieeeck.lo `test -f 'lapack/ieeeck.c' || echo '$(srcdir)/'`lapack/ieeeck.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-ieeeck.Tpo lapack/$(DEPDIR)/liblapack_la-ieeeck.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/ieeeck.c' object='lapack/liblapack_la-ieeeck.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-ieeeck.lo `test -f 'lapack/ieeeck.c' || echo '$(srcdir)/'`lapack/ieeeck.c
+
+lapack/liblapack_la-iparmq.lo: lapack/iparmq.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-iparmq.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-iparmq.Tpo -c -o lapack/liblapack_la-iparmq.lo `test -f 'lapack/iparmq.c' || echo '$(srcdir)/'`lapack/iparmq.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-iparmq.Tpo lapack/$(DEPDIR)/liblapack_la-iparmq.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/iparmq.c' object='lapack/liblapack_la-iparmq.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-iparmq.lo `test -f 'lapack/iparmq.c' || echo '$(srcdir)/'`lapack/iparmq.c
+
+lapack/liblapack_la-dhseqr.lo: lapack/dhseqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dhseqr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dhseqr.Tpo -c -o lapack/liblapack_la-dhseqr.lo `test -f 'lapack/dhseqr.c' || echo '$(srcdir)/'`lapack/dhseqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dhseqr.Tpo lapack/$(DEPDIR)/liblapack_la-dhseqr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dhseqr.c' object='lapack/liblapack_la-dhseqr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dhseqr.lo `test -f 'lapack/dhseqr.c' || echo '$(srcdir)/'`lapack/dhseqr.c
+
+lapack/liblapack_la-dlahqr.lo: lapack/dlahqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlahqr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlahqr.Tpo -c -o lapack/liblapack_la-dlahqr.lo `test -f 'lapack/dlahqr.c' || echo '$(srcdir)/'`lapack/dlahqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlahqr.Tpo lapack/$(DEPDIR)/liblapack_la-dlahqr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlahqr.c' object='lapack/liblapack_la-dlahqr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlahqr.lo `test -f 'lapack/dlahqr.c' || echo '$(srcdir)/'`lapack/dlahqr.c
+
+lapack/liblapack_la-dlabad.lo: lapack/dlabad.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlabad.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlabad.Tpo -c -o lapack/liblapack_la-dlabad.lo `test -f 'lapack/dlabad.c' || echo '$(srcdir)/'`lapack/dlabad.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlabad.Tpo lapack/$(DEPDIR)/liblapack_la-dlabad.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlabad.c' object='lapack/liblapack_la-dlabad.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlabad.lo `test -f 'lapack/dlabad.c' || echo '$(srcdir)/'`lapack/dlabad.c
+
+lapack/liblapack_la-dlanv2.lo: lapack/dlanv2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlanv2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlanv2.Tpo -c -o lapack/liblapack_la-dlanv2.lo `test -f 'lapack/dlanv2.c' || echo '$(srcdir)/'`lapack/dlanv2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlanv2.Tpo lapack/$(DEPDIR)/liblapack_la-dlanv2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlanv2.c' object='lapack/liblapack_la-dlanv2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlanv2.lo `test -f 'lapack/dlanv2.c' || echo '$(srcdir)/'`lapack/dlanv2.c
+
+lapack/liblapack_la-dlaqr0.lo: lapack/dlaqr0.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqr0.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqr0.Tpo -c -o lapack/liblapack_la-dlaqr0.lo `test -f 'lapack/dlaqr0.c' || echo '$(srcdir)/'`lapack/dlaqr0.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqr0.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqr0.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqr0.c' object='lapack/liblapack_la-dlaqr0.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqr0.lo `test -f 'lapack/dlaqr0.c' || echo '$(srcdir)/'`lapack/dlaqr0.c
+
+lapack/liblapack_la-dlaqr3.lo: lapack/dlaqr3.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqr3.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqr3.Tpo -c -o lapack/liblapack_la-dlaqr3.lo `test -f 'lapack/dlaqr3.c' || echo '$(srcdir)/'`lapack/dlaqr3.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqr3.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqr3.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqr3.c' object='lapack/liblapack_la-dlaqr3.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqr3.lo `test -f 'lapack/dlaqr3.c' || echo '$(srcdir)/'`lapack/dlaqr3.c
+
+lapack/liblapack_la-dlaqr4.lo: lapack/dlaqr4.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqr4.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqr4.Tpo -c -o lapack/liblapack_la-dlaqr4.lo `test -f 'lapack/dlaqr4.c' || echo '$(srcdir)/'`lapack/dlaqr4.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqr4.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqr4.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqr4.c' object='lapack/liblapack_la-dlaqr4.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqr4.lo `test -f 'lapack/dlaqr4.c' || echo '$(srcdir)/'`lapack/dlaqr4.c
+
+lapack/liblapack_la-dlaqr2.lo: lapack/dlaqr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqr2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqr2.Tpo -c -o lapack/liblapack_la-dlaqr2.lo `test -f 'lapack/dlaqr2.c' || echo '$(srcdir)/'`lapack/dlaqr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqr2.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqr2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqr2.c' object='lapack/liblapack_la-dlaqr2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqr2.lo `test -f 'lapack/dlaqr2.c' || echo '$(srcdir)/'`lapack/dlaqr2.c
+
+lapack/liblapack_la-dlaset.lo: lapack/dlaset.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaset.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaset.Tpo -c -o lapack/liblapack_la-dlaset.lo `test -f 'lapack/dlaset.c' || echo '$(srcdir)/'`lapack/dlaset.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaset.Tpo lapack/$(DEPDIR)/liblapack_la-dlaset.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaset.c' object='lapack/liblapack_la-dlaset.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaset.lo `test -f 'lapack/dlaset.c' || echo '$(srcdir)/'`lapack/dlaset.c
+
+lapack/liblapack_la-dormhr.lo: lapack/dormhr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dormhr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dormhr.Tpo -c -o lapack/liblapack_la-dormhr.lo `test -f 'lapack/dormhr.c' || echo '$(srcdir)/'`lapack/dormhr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dormhr.Tpo lapack/$(DEPDIR)/liblapack_la-dormhr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dormhr.c' object='lapack/liblapack_la-dormhr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dormhr.lo `test -f 'lapack/dormhr.c' || echo '$(srcdir)/'`lapack/dormhr.c
+
+lapack/liblapack_la-dormqr.lo: lapack/dormqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dormqr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dormqr.Tpo -c -o lapack/liblapack_la-dormqr.lo `test -f 'lapack/dormqr.c' || echo '$(srcdir)/'`lapack/dormqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dormqr.Tpo lapack/$(DEPDIR)/liblapack_la-dormqr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dormqr.c' object='lapack/liblapack_la-dormqr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dormqr.lo `test -f 'lapack/dormqr.c' || echo '$(srcdir)/'`lapack/dormqr.c
+
+lapack/liblapack_la-dlarft.lo: lapack/dlarft.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarft.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarft.Tpo -c -o lapack/liblapack_la-dlarft.lo `test -f 'lapack/dlarft.c' || echo '$(srcdir)/'`lapack/dlarft.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarft.Tpo lapack/$(DEPDIR)/liblapack_la-dlarft.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarft.c' object='lapack/liblapack_la-dlarft.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarft.lo `test -f 'lapack/dlarft.c' || echo '$(srcdir)/'`lapack/dlarft.c
+
+lapack/liblapack_la-dorm2r.lo: lapack/dorm2r.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dorm2r.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dorm2r.Tpo -c -o lapack/liblapack_la-dorm2r.lo `test -f 'lapack/dorm2r.c' || echo '$(srcdir)/'`lapack/dorm2r.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dorm2r.Tpo lapack/$(DEPDIR)/liblapack_la-dorm2r.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dorm2r.c' object='lapack/liblapack_la-dorm2r.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dorm2r.lo `test -f 'lapack/dorm2r.c' || echo '$(srcdir)/'`lapack/dorm2r.c
+
+lapack/liblapack_la-dtrexc.lo: lapack/dtrexc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dtrexc.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dtrexc.Tpo -c -o lapack/liblapack_la-dtrexc.lo `test -f 'lapack/dtrexc.c' || echo '$(srcdir)/'`lapack/dtrexc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dtrexc.Tpo lapack/$(DEPDIR)/liblapack_la-dtrexc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrexc.c' object='lapack/liblapack_la-dtrexc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dtrexc.lo `test -f 'lapack/dtrexc.c' || echo '$(srcdir)/'`lapack/dtrexc.c
+
+lapack/liblapack_la-dlaexc.lo: lapack/dlaexc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaexc.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaexc.Tpo -c -o lapack/liblapack_la-dlaexc.lo `test -f 'lapack/dlaexc.c' || echo '$(srcdir)/'`lapack/dlaexc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaexc.Tpo lapack/$(DEPDIR)/liblapack_la-dlaexc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaexc.c' object='lapack/liblapack_la-dlaexc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaexc.lo `test -f 'lapack/dlaexc.c' || echo '$(srcdir)/'`lapack/dlaexc.c
+
+lapack/liblapack_la-dlange.lo: lapack/dlange.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlange.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlange.Tpo -c -o lapack/liblapack_la-dlange.lo `test -f 'lapack/dlange.c' || echo '$(srcdir)/'`lapack/dlange.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlange.Tpo lapack/$(DEPDIR)/liblapack_la-dlange.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlange.c' object='lapack/liblapack_la-dlange.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlange.lo `test -f 'lapack/dlange.c' || echo '$(srcdir)/'`lapack/dlange.c
+
+lapack/liblapack_la-dlassq.lo: lapack/dlassq.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlassq.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlassq.Tpo -c -o lapack/liblapack_la-dlassq.lo `test -f 'lapack/dlassq.c' || echo '$(srcdir)/'`lapack/dlassq.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlassq.Tpo lapack/$(DEPDIR)/liblapack_la-dlassq.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlassq.c' object='lapack/liblapack_la-dlassq.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlassq.lo `test -f 'lapack/dlassq.c' || echo '$(srcdir)/'`lapack/dlassq.c
+
+lapack/liblapack_la-dlarfx.lo: lapack/dlarfx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarfx.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarfx.Tpo -c -o lapack/liblapack_la-dlarfx.lo `test -f 'lapack/dlarfx.c' || echo '$(srcdir)/'`lapack/dlarfx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarfx.Tpo lapack/$(DEPDIR)/liblapack_la-dlarfx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarfx.c' object='lapack/liblapack_la-dlarfx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarfx.lo `test -f 'lapack/dlarfx.c' || echo '$(srcdir)/'`lapack/dlarfx.c
+
+lapack/liblapack_la-dlartg.lo: lapack/dlartg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlartg.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlartg.Tpo -c -o lapack/liblapack_la-dlartg.lo `test -f 'lapack/dlartg.c' || echo '$(srcdir)/'`lapack/dlartg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlartg.Tpo lapack/$(DEPDIR)/liblapack_la-dlartg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlartg.c' object='lapack/liblapack_la-dlartg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlartg.lo `test -f 'lapack/dlartg.c' || echo '$(srcdir)/'`lapack/dlartg.c
+
+lapack/liblapack_la-dlasy2.lo: lapack/dlasy2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasy2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasy2.Tpo -c -o lapack/liblapack_la-dlasy2.lo `test -f 'lapack/dlasy2.c' || echo '$(srcdir)/'`lapack/dlasy2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasy2.Tpo lapack/$(DEPDIR)/liblapack_la-dlasy2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasy2.c' object='lapack/liblapack_la-dlasy2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasy2.lo `test -f 'lapack/dlasy2.c' || echo '$(srcdir)/'`lapack/dlasy2.c
+
+lapack/liblapack_la-dlaqr5.lo: lapack/dlaqr5.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqr5.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqr5.Tpo -c -o lapack/liblapack_la-dlaqr5.lo `test -f 'lapack/dlaqr5.c' || echo '$(srcdir)/'`lapack/dlaqr5.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqr5.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqr5.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqr5.c' object='lapack/liblapack_la-dlaqr5.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqr5.lo `test -f 'lapack/dlaqr5.c' || echo '$(srcdir)/'`lapack/dlaqr5.c
+
+lapack/liblapack_la-dlaqr1.lo: lapack/dlaqr1.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqr1.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqr1.Tpo -c -o lapack/liblapack_la-dlaqr1.lo `test -f 'lapack/dlaqr1.c' || echo '$(srcdir)/'`lapack/dlaqr1.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqr1.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqr1.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqr1.c' object='lapack/liblapack_la-dlaqr1.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqr1.lo `test -f 'lapack/dlaqr1.c' || echo '$(srcdir)/'`lapack/dlaqr1.c
+
+lapack/liblapack_la-dlascl.lo: lapack/dlascl.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlascl.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlascl.Tpo -c -o lapack/liblapack_la-dlascl.lo `test -f 'lapack/dlascl.c' || echo '$(srcdir)/'`lapack/dlascl.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlascl.Tpo lapack/$(DEPDIR)/liblapack_la-dlascl.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlascl.c' object='lapack/liblapack_la-dlascl.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlascl.lo `test -f 'lapack/dlascl.c' || echo '$(srcdir)/'`lapack/dlascl.c
+
+lapack/liblapack_la-dorghr.lo: lapack/dorghr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dorghr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dorghr.Tpo -c -o lapack/liblapack_la-dorghr.lo `test -f 'lapack/dorghr.c' || echo '$(srcdir)/'`lapack/dorghr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dorghr.Tpo lapack/$(DEPDIR)/liblapack_la-dorghr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dorghr.c' object='lapack/liblapack_la-dorghr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dorghr.lo `test -f 'lapack/dorghr.c' || echo '$(srcdir)/'`lapack/dorghr.c
+
+lapack/liblapack_la-dorgqr.lo: lapack/dorgqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dorgqr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dorgqr.Tpo -c -o lapack/liblapack_la-dorgqr.lo `test -f 'lapack/dorgqr.c' || echo '$(srcdir)/'`lapack/dorgqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dorgqr.Tpo lapack/$(DEPDIR)/liblapack_la-dorgqr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dorgqr.c' object='lapack/liblapack_la-dorgqr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dorgqr.lo `test -f 'lapack/dorgqr.c' || echo '$(srcdir)/'`lapack/dorgqr.c
+
+lapack/liblapack_la-dorg2r.lo: lapack/dorg2r.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dorg2r.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dorg2r.Tpo -c -o lapack/liblapack_la-dorg2r.lo `test -f 'lapack/dorg2r.c' || echo '$(srcdir)/'`lapack/dorg2r.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dorg2r.Tpo lapack/$(DEPDIR)/liblapack_la-dorg2r.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dorg2r.c' object='lapack/liblapack_la-dorg2r.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dorg2r.lo `test -f 'lapack/dorg2r.c' || echo '$(srcdir)/'`lapack/dorg2r.c
+
+lapack/liblapack_la-dtrevc.lo: lapack/dtrevc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dtrevc.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dtrevc.Tpo -c -o lapack/liblapack_la-dtrevc.lo `test -f 'lapack/dtrevc.c' || echo '$(srcdir)/'`lapack/dtrevc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dtrevc.Tpo lapack/$(DEPDIR)/liblapack_la-dtrevc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrevc.c' object='lapack/liblapack_la-dtrevc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dtrevc.lo `test -f 'lapack/dtrevc.c' || echo '$(srcdir)/'`lapack/dtrevc.c
+
+lapack/liblapack_la-dlaln2.lo: lapack/dlaln2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaln2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaln2.Tpo -c -o lapack/liblapack_la-dlaln2.lo `test -f 'lapack/dlaln2.c' || echo '$(srcdir)/'`lapack/dlaln2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaln2.Tpo lapack/$(DEPDIR)/liblapack_la-dlaln2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaln2.c' object='lapack/liblapack_la-dlaln2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaln2.lo `test -f 'lapack/dlaln2.c' || echo '$(srcdir)/'`lapack/dlaln2.c
+
+lapack/liblapack_la-dladiv.lo: lapack/dladiv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dladiv.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dladiv.Tpo -c -o lapack/liblapack_la-dladiv.lo `test -f 'lapack/dladiv.c' || echo '$(srcdir)/'`lapack/dladiv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dladiv.Tpo lapack/$(DEPDIR)/liblapack_la-dladiv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dladiv.c' object='lapack/liblapack_la-dladiv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dladiv.lo `test -f 'lapack/dladiv.c' || echo '$(srcdir)/'`lapack/dladiv.c
+
+lapack/liblapack_la-dsyevr.lo: lapack/dsyevr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dsyevr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dsyevr.Tpo -c -o lapack/liblapack_la-dsyevr.lo `test -f 'lapack/dsyevr.c' || echo '$(srcdir)/'`lapack/dsyevr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dsyevr.Tpo lapack/$(DEPDIR)/liblapack_la-dsyevr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsyevr.c' object='lapack/liblapack_la-dsyevr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dsyevr.lo `test -f 'lapack/dsyevr.c' || echo '$(srcdir)/'`lapack/dsyevr.c
+
+lapack/liblapack_la-dlansy.lo: lapack/dlansy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlansy.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlansy.Tpo -c -o lapack/liblapack_la-dlansy.lo `test -f 'lapack/dlansy.c' || echo '$(srcdir)/'`lapack/dlansy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlansy.Tpo lapack/$(DEPDIR)/liblapack_la-dlansy.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlansy.c' object='lapack/liblapack_la-dlansy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlansy.lo `test -f 'lapack/dlansy.c' || echo '$(srcdir)/'`lapack/dlansy.c
+
+lapack/liblapack_la-dormtr.lo: lapack/dormtr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dormtr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dormtr.Tpo -c -o lapack/liblapack_la-dormtr.lo `test -f 'lapack/dormtr.c' || echo '$(srcdir)/'`lapack/dormtr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dormtr.Tpo lapack/$(DEPDIR)/liblapack_la-dormtr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dormtr.c' object='lapack/liblapack_la-dormtr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dormtr.lo `test -f 'lapack/dormtr.c' || echo '$(srcdir)/'`lapack/dormtr.c
+
+lapack/liblapack_la-dormql.lo: lapack/dormql.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dormql.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dormql.Tpo -c -o lapack/liblapack_la-dormql.lo `test -f 'lapack/dormql.c' || echo '$(srcdir)/'`lapack/dormql.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dormql.Tpo lapack/$(DEPDIR)/liblapack_la-dormql.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dormql.c' object='lapack/liblapack_la-dormql.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dormql.lo `test -f 'lapack/dormql.c' || echo '$(srcdir)/'`lapack/dormql.c
+
+lapack/liblapack_la-dorm2l.lo: lapack/dorm2l.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dorm2l.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dorm2l.Tpo -c -o lapack/liblapack_la-dorm2l.lo `test -f 'lapack/dorm2l.c' || echo '$(srcdir)/'`lapack/dorm2l.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dorm2l.Tpo lapack/$(DEPDIR)/liblapack_la-dorm2l.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dorm2l.c' object='lapack/liblapack_la-dorm2l.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dorm2l.lo `test -f 'lapack/dorm2l.c' || echo '$(srcdir)/'`lapack/dorm2l.c
+
+lapack/liblapack_la-dstebz.lo: lapack/dstebz.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dstebz.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dstebz.Tpo -c -o lapack/liblapack_la-dstebz.lo `test -f 'lapack/dstebz.c' || echo '$(srcdir)/'`lapack/dstebz.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dstebz.Tpo lapack/$(DEPDIR)/liblapack_la-dstebz.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dstebz.c' object='lapack/liblapack_la-dstebz.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dstebz.lo `test -f 'lapack/dstebz.c' || echo '$(srcdir)/'`lapack/dstebz.c
+
+lapack/liblapack_la-dlaebz.lo: lapack/dlaebz.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaebz.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaebz.Tpo -c -o lapack/liblapack_la-dlaebz.lo `test -f 'lapack/dlaebz.c' || echo '$(srcdir)/'`lapack/dlaebz.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaebz.Tpo lapack/$(DEPDIR)/liblapack_la-dlaebz.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaebz.c' object='lapack/liblapack_la-dlaebz.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaebz.lo `test -f 'lapack/dlaebz.c' || echo '$(srcdir)/'`lapack/dlaebz.c
+
+lapack/liblapack_la-dstein.lo: lapack/dstein.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dstein.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dstein.Tpo -c -o lapack/liblapack_la-dstein.lo `test -f 'lapack/dstein.c' || echo '$(srcdir)/'`lapack/dstein.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dstein.Tpo lapack/$(DEPDIR)/liblapack_la-dstein.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dstein.c' object='lapack/liblapack_la-dstein.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dstein.lo `test -f 'lapack/dstein.c' || echo '$(srcdir)/'`lapack/dstein.c
+
+lapack/liblapack_la-dlagtf.lo: lapack/dlagtf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlagtf.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlagtf.Tpo -c -o lapack/liblapack_la-dlagtf.lo `test -f 'lapack/dlagtf.c' || echo '$(srcdir)/'`lapack/dlagtf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlagtf.Tpo lapack/$(DEPDIR)/liblapack_la-dlagtf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlagtf.c' object='lapack/liblapack_la-dlagtf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlagtf.lo `test -f 'lapack/dlagtf.c' || echo '$(srcdir)/'`lapack/dlagtf.c
+
+lapack/liblapack_la-dlagts.lo: lapack/dlagts.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlagts.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlagts.Tpo -c -o lapack/liblapack_la-dlagts.lo `test -f 'lapack/dlagts.c' || echo '$(srcdir)/'`lapack/dlagts.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlagts.Tpo lapack/$(DEPDIR)/liblapack_la-dlagts.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlagts.c' object='lapack/liblapack_la-dlagts.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlagts.lo `test -f 'lapack/dlagts.c' || echo '$(srcdir)/'`lapack/dlagts.c
+
+lapack/liblapack_la-dlarnv.lo: lapack/dlarnv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarnv.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarnv.Tpo -c -o lapack/liblapack_la-dlarnv.lo `test -f 'lapack/dlarnv.c' || echo '$(srcdir)/'`lapack/dlarnv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarnv.Tpo lapack/$(DEPDIR)/liblapack_la-dlarnv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarnv.c' object='lapack/liblapack_la-dlarnv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarnv.lo `test -f 'lapack/dlarnv.c' || echo '$(srcdir)/'`lapack/dlarnv.c
+
+lapack/liblapack_la-dlaruv.lo: lapack/dlaruv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaruv.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaruv.Tpo -c -o lapack/liblapack_la-dlaruv.lo `test -f 'lapack/dlaruv.c' || echo '$(srcdir)/'`lapack/dlaruv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaruv.Tpo lapack/$(DEPDIR)/liblapack_la-dlaruv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaruv.c' object='lapack/liblapack_la-dlaruv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaruv.lo `test -f 'lapack/dlaruv.c' || echo '$(srcdir)/'`lapack/dlaruv.c
+
+lapack/liblapack_la-dstemr.lo: lapack/dstemr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dstemr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dstemr.Tpo -c -o lapack/liblapack_la-dstemr.lo `test -f 'lapack/dstemr.c' || echo '$(srcdir)/'`lapack/dstemr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dstemr.Tpo lapack/$(DEPDIR)/liblapack_la-dstemr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dstemr.c' object='lapack/liblapack_la-dstemr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dstemr.lo `test -f 'lapack/dstemr.c' || echo '$(srcdir)/'`lapack/dstemr.c
+
+lapack/liblapack_la-dlae2.lo: lapack/dlae2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlae2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlae2.Tpo -c -o lapack/liblapack_la-dlae2.lo `test -f 'lapack/dlae2.c' || echo '$(srcdir)/'`lapack/dlae2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlae2.Tpo lapack/$(DEPDIR)/liblapack_la-dlae2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlae2.c' object='lapack/liblapack_la-dlae2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlae2.lo `test -f 'lapack/dlae2.c' || echo '$(srcdir)/'`lapack/dlae2.c
+
+lapack/liblapack_la-dlaev2.lo: lapack/dlaev2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaev2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaev2.Tpo -c -o lapack/liblapack_la-dlaev2.lo `test -f 'lapack/dlaev2.c' || echo '$(srcdir)/'`lapack/dlaev2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaev2.Tpo lapack/$(DEPDIR)/liblapack_la-dlaev2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaev2.c' object='lapack/liblapack_la-dlaev2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaev2.lo `test -f 'lapack/dlaev2.c' || echo '$(srcdir)/'`lapack/dlaev2.c
+
+lapack/liblapack_la-dlanst.lo: lapack/dlanst.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlanst.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlanst.Tpo -c -o lapack/liblapack_la-dlanst.lo `test -f 'lapack/dlanst.c' || echo '$(srcdir)/'`lapack/dlanst.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlanst.Tpo lapack/$(DEPDIR)/liblapack_la-dlanst.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlanst.c' object='lapack/liblapack_la-dlanst.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlanst.lo `test -f 'lapack/dlanst.c' || echo '$(srcdir)/'`lapack/dlanst.c
+
+lapack/liblapack_la-dlarrc.lo: lapack/dlarrc.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrc.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrc.Tpo -c -o lapack/liblapack_la-dlarrc.lo `test -f 'lapack/dlarrc.c' || echo '$(srcdir)/'`lapack/dlarrc.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrc.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrc.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrc.c' object='lapack/liblapack_la-dlarrc.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrc.lo `test -f 'lapack/dlarrc.c' || echo '$(srcdir)/'`lapack/dlarrc.c
+
+lapack/liblapack_la-dlarre.lo: lapack/dlarre.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarre.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarre.Tpo -c -o lapack/liblapack_la-dlarre.lo `test -f 'lapack/dlarre.c' || echo '$(srcdir)/'`lapack/dlarre.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarre.Tpo lapack/$(DEPDIR)/liblapack_la-dlarre.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarre.c' object='lapack/liblapack_la-dlarre.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarre.lo `test -f 'lapack/dlarre.c' || echo '$(srcdir)/'`lapack/dlarre.c
+
+lapack/liblapack_la-dlarra.lo: lapack/dlarra.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarra.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarra.Tpo -c -o lapack/liblapack_la-dlarra.lo `test -f 'lapack/dlarra.c' || echo '$(srcdir)/'`lapack/dlarra.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarra.Tpo lapack/$(DEPDIR)/liblapack_la-dlarra.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarra.c' object='lapack/liblapack_la-dlarra.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarra.lo `test -f 'lapack/dlarra.c' || echo '$(srcdir)/'`lapack/dlarra.c
+
+lapack/liblapack_la-dlarrb.lo: lapack/dlarrb.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrb.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrb.Tpo -c -o lapack/liblapack_la-dlarrb.lo `test -f 'lapack/dlarrb.c' || echo '$(srcdir)/'`lapack/dlarrb.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrb.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrb.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrb.c' object='lapack/liblapack_la-dlarrb.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrb.lo `test -f 'lapack/dlarrb.c' || echo '$(srcdir)/'`lapack/dlarrb.c
+
+lapack/liblapack_la-dlaneg.lo: lapack/dlaneg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaneg.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaneg.Tpo -c -o lapack/liblapack_la-dlaneg.lo `test -f 'lapack/dlaneg.c' || echo '$(srcdir)/'`lapack/dlaneg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaneg.Tpo lapack/$(DEPDIR)/liblapack_la-dlaneg.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaneg.c' object='lapack/liblapack_la-dlaneg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaneg.lo `test -f 'lapack/dlaneg.c' || echo '$(srcdir)/'`lapack/dlaneg.c
+
+lapack/liblapack_la-dlarrd.lo: lapack/dlarrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrd.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrd.Tpo -c -o lapack/liblapack_la-dlarrd.lo `test -f 'lapack/dlarrd.c' || echo '$(srcdir)/'`lapack/dlarrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrd.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrd.c' object='lapack/liblapack_la-dlarrd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrd.lo `test -f 'lapack/dlarrd.c' || echo '$(srcdir)/'`lapack/dlarrd.c
+
+lapack/liblapack_la-dlarrk.lo: lapack/dlarrk.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrk.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrk.Tpo -c -o lapack/liblapack_la-dlarrk.lo `test -f 'lapack/dlarrk.c' || echo '$(srcdir)/'`lapack/dlarrk.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrk.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrk.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrk.c' object='lapack/liblapack_la-dlarrk.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrk.lo `test -f 'lapack/dlarrk.c' || echo '$(srcdir)/'`lapack/dlarrk.c
+
+lapack/liblapack_la-dlasq2.lo: lapack/dlasq2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasq2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasq2.Tpo -c -o lapack/liblapack_la-dlasq2.lo `test -f 'lapack/dlasq2.c' || echo '$(srcdir)/'`lapack/dlasq2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasq2.Tpo lapack/$(DEPDIR)/liblapack_la-dlasq2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasq2.c' object='lapack/liblapack_la-dlasq2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasq2.lo `test -f 'lapack/dlasq2.c' || echo '$(srcdir)/'`lapack/dlasq2.c
+
+lapack/liblapack_la-dlasq3.lo: lapack/dlasq3.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasq3.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasq3.Tpo -c -o lapack/liblapack_la-dlasq3.lo `test -f 'lapack/dlasq3.c' || echo '$(srcdir)/'`lapack/dlasq3.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasq3.Tpo lapack/$(DEPDIR)/liblapack_la-dlasq3.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasq3.c' object='lapack/liblapack_la-dlasq3.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasq3.lo `test -f 'lapack/dlasq3.c' || echo '$(srcdir)/'`lapack/dlasq3.c
+
+lapack/liblapack_la-dlasq4.lo: lapack/dlasq4.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasq4.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasq4.Tpo -c -o lapack/liblapack_la-dlasq4.lo `test -f 'lapack/dlasq4.c' || echo '$(srcdir)/'`lapack/dlasq4.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasq4.Tpo lapack/$(DEPDIR)/liblapack_la-dlasq4.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasq4.c' object='lapack/liblapack_la-dlasq4.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasq4.lo `test -f 'lapack/dlasq4.c' || echo '$(srcdir)/'`lapack/dlasq4.c
+
+lapack/liblapack_la-dlasq5.lo: lapack/dlasq5.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasq5.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasq5.Tpo -c -o lapack/liblapack_la-dlasq5.lo `test -f 'lapack/dlasq5.c' || echo '$(srcdir)/'`lapack/dlasq5.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasq5.Tpo lapack/$(DEPDIR)/liblapack_la-dlasq5.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasq5.c' object='lapack/liblapack_la-dlasq5.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasq5.lo `test -f 'lapack/dlasq5.c' || echo '$(srcdir)/'`lapack/dlasq5.c
+
+lapack/liblapack_la-dlasq6.lo: lapack/dlasq6.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasq6.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasq6.Tpo -c -o lapack/liblapack_la-dlasq6.lo `test -f 'lapack/dlasq6.c' || echo '$(srcdir)/'`lapack/dlasq6.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasq6.Tpo lapack/$(DEPDIR)/liblapack_la-dlasq6.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasq6.c' object='lapack/liblapack_la-dlasq6.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasq6.lo `test -f 'lapack/dlasq6.c' || echo '$(srcdir)/'`lapack/dlasq6.c
+
+lapack/liblapack_la-dlasrt.lo: lapack/dlasrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasrt.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasrt.Tpo -c -o lapack/liblapack_la-dlasrt.lo `test -f 'lapack/dlasrt.c' || echo '$(srcdir)/'`lapack/dlasrt.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasrt.Tpo lapack/$(DEPDIR)/liblapack_la-dlasrt.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasrt.c' object='lapack/liblapack_la-dlasrt.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasrt.lo `test -f 'lapack/dlasrt.c' || echo '$(srcdir)/'`lapack/dlasrt.c
+
+lapack/liblapack_la-dlarrj.lo: lapack/dlarrj.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrj.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrj.Tpo -c -o lapack/liblapack_la-dlarrj.lo `test -f 'lapack/dlarrj.c' || echo '$(srcdir)/'`lapack/dlarrj.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrj.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrj.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrj.c' object='lapack/liblapack_la-dlarrj.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrj.lo `test -f 'lapack/dlarrj.c' || echo '$(srcdir)/'`lapack/dlarrj.c
+
+lapack/liblapack_la-dlarrr.lo: lapack/dlarrr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrr.Tpo -c -o lapack/liblapack_la-dlarrr.lo `test -f 'lapack/dlarrr.c' || echo '$(srcdir)/'`lapack/dlarrr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrr.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrr.c' object='lapack/liblapack_la-dlarrr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrr.lo `test -f 'lapack/dlarrr.c' || echo '$(srcdir)/'`lapack/dlarrr.c
+
+lapack/liblapack_la-dlarrv.lo: lapack/dlarrv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrv.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrv.Tpo -c -o lapack/liblapack_la-dlarrv.lo `test -f 'lapack/dlarrv.c' || echo '$(srcdir)/'`lapack/dlarrv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrv.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrv.c' object='lapack/liblapack_la-dlarrv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrv.lo `test -f 'lapack/dlarrv.c' || echo '$(srcdir)/'`lapack/dlarrv.c
+
+lapack/liblapack_la-dlar1v.lo: lapack/dlar1v.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlar1v.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlar1v.Tpo -c -o lapack/liblapack_la-dlar1v.lo `test -f 'lapack/dlar1v.c' || echo '$(srcdir)/'`lapack/dlar1v.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlar1v.Tpo lapack/$(DEPDIR)/liblapack_la-dlar1v.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlar1v.c' object='lapack/liblapack_la-dlar1v.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlar1v.lo `test -f 'lapack/dlar1v.c' || echo '$(srcdir)/'`lapack/dlar1v.c
+
+lapack/liblapack_la-dlarrf.lo: lapack/dlarrf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlarrf.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlarrf.Tpo -c -o lapack/liblapack_la-dlarrf.lo `test -f 'lapack/dlarrf.c' || echo '$(srcdir)/'`lapack/dlarrf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlarrf.Tpo lapack/$(DEPDIR)/liblapack_la-dlarrf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlarrf.c' object='lapack/liblapack_la-dlarrf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlarrf.lo `test -f 'lapack/dlarrf.c' || echo '$(srcdir)/'`lapack/dlarrf.c
+
+lapack/liblapack_la-dsterf.lo: lapack/dsterf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dsterf.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dsterf.Tpo -c -o lapack/liblapack_la-dsterf.lo `test -f 'lapack/dsterf.c' || echo '$(srcdir)/'`lapack/dsterf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dsterf.Tpo lapack/$(DEPDIR)/liblapack_la-dsterf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsterf.c' object='lapack/liblapack_la-dsterf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dsterf.lo `test -f 'lapack/dsterf.c' || echo '$(srcdir)/'`lapack/dsterf.c
+
+lapack/liblapack_la-dsytrd.lo: lapack/dsytrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dsytrd.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dsytrd.Tpo -c -o lapack/liblapack_la-dsytrd.lo `test -f 'lapack/dsytrd.c' || echo '$(srcdir)/'`lapack/dsytrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dsytrd.Tpo lapack/$(DEPDIR)/liblapack_la-dsytrd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsytrd.c' object='lapack/liblapack_la-dsytrd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dsytrd.lo `test -f 'lapack/dsytrd.c' || echo '$(srcdir)/'`lapack/dsytrd.c
+
+lapack/liblapack_la-dlatrd.lo: lapack/dlatrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlatrd.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlatrd.Tpo -c -o lapack/liblapack_la-dlatrd.lo `test -f 'lapack/dlatrd.c' || echo '$(srcdir)/'`lapack/dlatrd.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlatrd.Tpo lapack/$(DEPDIR)/liblapack_la-dlatrd.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlatrd.c' object='lapack/liblapack_la-dlatrd.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlatrd.lo `test -f 'lapack/dlatrd.c' || echo '$(srcdir)/'`lapack/dlatrd.c
+
+lapack/liblapack_la-dsytd2.lo: lapack/dsytd2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dsytd2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dsytd2.Tpo -c -o lapack/liblapack_la-dsytd2.lo `test -f 'lapack/dsytd2.c' || echo '$(srcdir)/'`lapack/dsytd2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dsytd2.Tpo lapack/$(DEPDIR)/liblapack_la-dsytd2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsytd2.c' object='lapack/liblapack_la-dsytd2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dsytd2.lo `test -f 'lapack/dsytd2.c' || echo '$(srcdir)/'`lapack/dsytd2.c
+
+lapack/liblapack_la-dlanhs.lo: lapack/dlanhs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlanhs.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlanhs.Tpo -c -o lapack/liblapack_la-dlanhs.lo `test -f 'lapack/dlanhs.c' || echo '$(srcdir)/'`lapack/dlanhs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlanhs.Tpo lapack/$(DEPDIR)/liblapack_la-dlanhs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlanhs.c' object='lapack/liblapack_la-dlanhs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlanhs.lo `test -f 'lapack/dlanhs.c' || echo '$(srcdir)/'`lapack/dlanhs.c
+
+lapack/liblapack_la-dgeqr2.lo: lapack/dgeqr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgeqr2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgeqr2.Tpo -c -o lapack/liblapack_la-dgeqr2.lo `test -f 'lapack/dgeqr2.c' || echo '$(srcdir)/'`lapack/dgeqr2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgeqr2.Tpo lapack/$(DEPDIR)/liblapack_la-dgeqr2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgeqr2.c' object='lapack/liblapack_la-dgeqr2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgeqr2.lo `test -f 'lapack/dgeqr2.c' || echo '$(srcdir)/'`lapack/dgeqr2.c
+
+lapack/liblapack_la-dtrsen.lo: lapack/dtrsen.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dtrsen.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dtrsen.Tpo -c -o lapack/liblapack_la-dtrsen.lo `test -f 'lapack/dtrsen.c' || echo '$(srcdir)/'`lapack/dtrsen.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dtrsen.Tpo lapack/$(DEPDIR)/liblapack_la-dtrsen.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrsen.c' object='lapack/liblapack_la-dtrsen.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dtrsen.lo `test -f 'lapack/dtrsen.c' || echo '$(srcdir)/'`lapack/dtrsen.c
+
+lapack/liblapack_la-dlacn2.lo: lapack/dlacn2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlacn2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlacn2.Tpo -c -o lapack/liblapack_la-dlacn2.lo `test -f 'lapack/dlacn2.c' || echo '$(srcdir)/'`lapack/dlacn2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlacn2.Tpo lapack/$(DEPDIR)/liblapack_la-dlacn2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlacn2.c' object='lapack/liblapack_la-dlacn2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlacn2.lo `test -f 'lapack/dlacn2.c' || echo '$(srcdir)/'`lapack/dlacn2.c
+
+lapack/liblapack_la-dtrsyl.lo: lapack/dtrsyl.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dtrsyl.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dtrsyl.Tpo -c -o lapack/liblapack_la-dtrsyl.lo `test -f 'lapack/dtrsyl.c' || echo '$(srcdir)/'`lapack/dtrsyl.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dtrsyl.Tpo lapack/$(DEPDIR)/liblapack_la-dtrsyl.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrsyl.c' object='lapack/liblapack_la-dtrsyl.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dtrsyl.lo `test -f 'lapack/dtrsyl.c' || echo '$(srcdir)/'`lapack/dtrsyl.c
+
+lapack/liblapack_la-dlasr.lo: lapack/dlasr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlasr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlasr.Tpo -c -o lapack/liblapack_la-dlasr.lo `test -f 'lapack/dlasr.c' || echo '$(srcdir)/'`lapack/dlasr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlasr.Tpo lapack/$(DEPDIR)/liblapack_la-dlasr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlasr.c' object='lapack/liblapack_la-dlasr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlasr.lo `test -f 'lapack/dlasr.c' || echo '$(srcdir)/'`lapack/dlasr.c
+
+lapack/liblapack_la-dsteqr.lo: lapack/dsteqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dsteqr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dsteqr.Tpo -c -o lapack/liblapack_la-dsteqr.lo `test -f 'lapack/dsteqr.c' || echo '$(srcdir)/'`lapack/dsteqr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dsteqr.Tpo lapack/$(DEPDIR)/liblapack_la-dsteqr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dsteqr.c' object='lapack/liblapack_la-dsteqr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dsteqr.lo `test -f 'lapack/dsteqr.c' || echo '$(srcdir)/'`lapack/dsteqr.c
+
+lapack/liblapack_la-dgeevx.lo: lapack/dgeevx.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgeevx.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgeevx.Tpo -c -o lapack/liblapack_la-dgeevx.lo `test -f 'lapack/dgeevx.c' || echo '$(srcdir)/'`lapack/dgeevx.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgeevx.Tpo lapack/$(DEPDIR)/liblapack_la-dgeevx.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgeevx.c' object='lapack/liblapack_la-dgeevx.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgeevx.lo `test -f 'lapack/dgeevx.c' || echo '$(srcdir)/'`lapack/dgeevx.c
+
+lapack/liblapack_la-dtrsna.lo: lapack/dtrsna.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dtrsna.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dtrsna.Tpo -c -o lapack/liblapack_la-dtrsna.lo `test -f 'lapack/dtrsna.c' || echo '$(srcdir)/'`lapack/dtrsna.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dtrsna.Tpo lapack/$(DEPDIR)/liblapack_la-dtrsna.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dtrsna.c' object='lapack/liblapack_la-dtrsna.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dtrsna.lo `test -f 'lapack/dtrsna.c' || echo '$(srcdir)/'`lapack/dtrsna.c
+
+lapack/liblapack_la-dlaqtr.lo: lapack/dlaqtr.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaqtr.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaqtr.Tpo -c -o lapack/liblapack_la-dlaqtr.lo `test -f 'lapack/dlaqtr.c' || echo '$(srcdir)/'`lapack/dlaqtr.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaqtr.Tpo lapack/$(DEPDIR)/liblapack_la-dlaqtr.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaqtr.c' object='lapack/liblapack_la-dlaqtr.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaqtr.lo `test -f 'lapack/dlaqtr.c' || echo '$(srcdir)/'`lapack/dlaqtr.c
+
+lapack/liblapack_la-dgetrf.lo: lapack/dgetrf.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgetrf.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgetrf.Tpo -c -o lapack/liblapack_la-dgetrf.lo `test -f 'lapack/dgetrf.c' || echo '$(srcdir)/'`lapack/dgetrf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgetrf.Tpo lapack/$(DEPDIR)/liblapack_la-dgetrf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgetrf.c' object='lapack/liblapack_la-dgetrf.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgetrf.lo `test -f 'lapack/dgetrf.c' || echo '$(srcdir)/'`lapack/dgetrf.c
+
+lapack/liblapack_la-dgetf2.lo: lapack/dgetf2.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgetf2.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgetf2.Tpo -c -o lapack/liblapack_la-dgetf2.lo `test -f 'lapack/dgetf2.c' || echo '$(srcdir)/'`lapack/dgetf2.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgetf2.Tpo lapack/$(DEPDIR)/liblapack_la-dgetf2.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgetf2.c' object='lapack/liblapack_la-dgetf2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgetf2.lo `test -f 'lapack/dgetf2.c' || echo '$(srcdir)/'`lapack/dgetf2.c
+
+lapack/liblapack_la-dlaswp.lo: lapack/dlaswp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dlaswp.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dlaswp.Tpo -c -o lapack/liblapack_la-dlaswp.lo `test -f 'lapack/dlaswp.c' || echo '$(srcdir)/'`lapack/dlaswp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dlaswp.Tpo lapack/$(DEPDIR)/liblapack_la-dlaswp.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dlaswp.c' object='lapack/liblapack_la-dlaswp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dlaswp.lo `test -f 'lapack/dlaswp.c' || echo '$(srcdir)/'`lapack/dlaswp.c
+
+lapack/liblapack_la-dgetrs.lo: lapack/dgetrs.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgetrs.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgetrs.Tpo -c -o lapack/liblapack_la-dgetrs.lo `test -f 'lapack/dgetrs.c' || echo '$(srcdir)/'`lapack/dgetrs.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgetrs.Tpo lapack/$(DEPDIR)/liblapack_la-dgetrs.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgetrs.c' object='lapack/liblapack_la-dgetrs.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgetrs.lo `test -f 'lapack/dgetrs.c' || echo '$(srcdir)/'`lapack/dgetrs.c
+
+lapack/liblapack_la-dgesv.lo: lapack/dgesv.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-dgesv.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-dgesv.Tpo -c -o lapack/liblapack_la-dgesv.lo `test -f 'lapack/dgesv.c' || echo '$(srcdir)/'`lapack/dgesv.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-dgesv.Tpo lapack/$(DEPDIR)/liblapack_la-dgesv.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/dgesv.c' object='lapack/liblapack_la-dgesv.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-dgesv.lo `test -f 'lapack/dgesv.c' || echo '$(srcdir)/'`lapack/dgesv.c
+
+lapack/liblapack_la-len_trim.lo: lapack/len_trim.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -MT lapack/liblapack_la-len_trim.lo -MD -MP -MF lapack/$(DEPDIR)/liblapack_la-len_trim.Tpo -c -o lapack/liblapack_la-len_trim.lo `test -f 'lapack/len_trim.c' || echo '$(srcdir)/'`lapack/len_trim.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) lapack/$(DEPDIR)/liblapack_la-len_trim.Tpo lapack/$(DEPDIR)/liblapack_la-len_trim.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='lapack/len_trim.c' object='lapack/liblapack_la-len_trim.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblapack_la_CFLAGS) $(CFLAGS) -c -o lapack/liblapack_la-len_trim.lo `test -f 'lapack/len_trim.c' || echo '$(srcdir)/'`lapack/len_trim.c
+
+.cc.o:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+libigraph_la-NetDataTypes.lo: NetDataTypes.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-NetDataTypes.lo -MD -MP -MF $(DEPDIR)/libigraph_la-NetDataTypes.Tpo -c -o libigraph_la-NetDataTypes.lo `test -f 'NetDataTypes.cpp' || echo '$(srcdir)/'`NetDataTypes.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-NetDataTypes.Tpo $(DEPDIR)/libigraph_la-NetDataTypes.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='NetDataTypes.cpp' object='libigraph_la-NetDataTypes.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-NetDataTypes.lo `test -f 'NetDataTypes.cpp' || echo '$(srcdir)/'`NetDataTypes.cpp
+
+libigraph_la-NetRoutines.lo: NetRoutines.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-NetRoutines.lo -MD -MP -MF $(DEPDIR)/libigraph_la-NetRoutines.Tpo -c -o libigraph_la-NetRoutines.lo `test -f 'NetRoutines.cpp' || echo '$(srcdir)/'`NetRoutines.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-NetRoutines.Tpo $(DEPDIR)/libigraph_la-NetRoutines.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='NetRoutines.cpp' object='libigraph_la-NetRoutines.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-NetRoutines.lo `test -f 'NetRoutines.cpp' || echo '$(srcdir)/'`NetRoutines.cpp
+
+libigraph_la-clustertool.lo: clustertool.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-clustertool.lo -MD -MP -MF $(DEPDIR)/libigraph_la-clustertool.Tpo -c -o libigraph_la-clustertool.lo `test -f 'clustertool.cpp' || echo '$(srcdir)/'`clustertool.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-clustertool.Tpo $(DEPDIR)/libigraph_la-clustertool.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='clustertool.cpp' object='libigraph_la-clustertool.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-clustertool.lo `test -f 'clustertool.cpp' || echo '$(srcdir)/'`clustertool.cpp
+
+libigraph_la-pottsmodel_2.lo: pottsmodel_2.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-pottsmodel_2.lo -MD -MP -MF $(DEPDIR)/libigraph_la-pottsmodel_2.Tpo -c -o libigraph_la-pottsmodel_2.lo `test -f 'pottsmodel_2.cpp' || echo '$(srcdir)/'`pottsmodel_2.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-pottsmodel_2.Tpo $(DEPDIR)/libigraph_la-pottsmodel_2.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='pottsmodel_2.cpp' object='libigraph_la-pottsmodel_2.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-pottsmodel_2.lo `test -f 'pottsmodel_2.cpp' || echo '$(srcdir)/'`pottsmodel_2.cpp
+
+libigraph_la-walktrap.lo: walktrap.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-walktrap.lo -MD -MP -MF $(DEPDIR)/libigraph_la-walktrap.Tpo -c -o libigraph_la-walktrap.lo `test -f 'walktrap.cpp' || echo '$(srcdir)/'`walktrap.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-walktrap.Tpo $(DEPDIR)/libigraph_la-walktrap.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='walktrap.cpp' object='libigraph_la-walktrap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-walktrap.lo `test -f 'walktrap.cpp' || echo '$(srcdir)/'`walktrap.cpp
+
+libigraph_la-walktrap_heap.lo: walktrap_heap.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-walktrap_heap.lo -MD -MP -MF $(DEPDIR)/libigraph_la-walktrap_heap.Tpo -c -o libigraph_la-walktrap_heap.lo `test -f 'walktrap_heap.cpp' || echo '$(srcdir)/'`walktrap_heap.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-walktrap_heap.Tpo $(DEPDIR)/libigraph_la-walktrap_heap.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='walktrap_heap.cpp' object='libigraph_la-walktrap_heap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-walktrap_heap.lo `test -f 'walktrap_heap.cpp' || echo '$(srcdir)/'`walktrap_heap.cpp
+
+libigraph_la-walktrap_graph.lo: walktrap_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-walktrap_graph.lo -MD -MP -MF $(DEPDIR)/libigraph_la-walktrap_graph.Tpo -c -o libigraph_la-walktrap_graph.lo `test -f 'walktrap_graph.cpp' || echo '$(srcdir)/'`walktrap_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-walktrap_graph.Tpo $(DEPDIR)/libigraph_la-walktrap_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='walktrap_graph.cpp' object='libigraph_la-walktrap_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-walktrap_graph.lo `test -f 'walktrap_graph.cpp' || echo '$(srcdir)/'`walktrap_graph.cpp
+
+libigraph_la-walktrap_communities.lo: walktrap_communities.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-walktrap_communities.lo -MD -MP -MF $(DEPDIR)/libigraph_la-walktrap_communities.Tpo -c -o libigraph_la-walktrap_communities.lo `test -f 'walktrap_communities.cpp' || echo '$(srcdir)/'`walktrap_communities.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-walktrap_communities.Tpo $(DEPDIR)/libigraph_la-walktrap_communities.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='walktrap_communities.cpp' object='libigraph_la-walktrap_communities.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-walktrap_communities.lo `test -f 'walktrap_communities.cpp' || echo '$(srcdir)/'`walktrap_communities.cpp
+
+libigraph_la-infomap.lo: infomap.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-infomap.lo -MD -MP -MF $(DEPDIR)/libigraph_la-infomap.Tpo -c -o libigraph_la-infomap.lo `test -f 'infomap.cc' || echo '$(srcdir)/'`infomap.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-infomap.Tpo $(DEPDIR)/libigraph_la-infomap.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='infomap.cc' object='libigraph_la-infomap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-infomap.lo `test -f 'infomap.cc' || echo '$(srcdir)/'`infomap.cc
+
+libigraph_la-infomap_Greedy.lo: infomap_Greedy.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-infomap_Greedy.lo -MD -MP -MF $(DEPDIR)/libigraph_la-infomap_Greedy.Tpo -c -o libigraph_la-infomap_Greedy.lo `test -f 'infomap_Greedy.cc' || echo '$(srcdir)/'`infomap_Greedy.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-infomap_Greedy.Tpo $(DEPDIR)/libigraph_la-infomap_Greedy.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='infomap_Greedy.cc' object='libigraph_la-infomap_Greedy.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-infomap_Greedy.lo `test -f 'infomap_Greedy.cc' || echo '$(srcdir)/'`infomap_Greedy.cc
+
+libigraph_la-infomap_Node.lo: infomap_Node.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-infomap_Node.lo -MD -MP -MF $(DEPDIR)/libigraph_la-infomap_Node.Tpo -c -o libigraph_la-infomap_Node.lo `test -f 'infomap_Node.cc' || echo '$(srcdir)/'`infomap_Node.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-infomap_Node.Tpo $(DEPDIR)/libigraph_la-infomap_Node.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='infomap_Node.cc' object='libigraph_la-infomap_Node.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-infomap_Node.lo `test -f 'infomap_Node.cc' || echo '$(srcdir)/'`infomap_Node.cc
+
+libigraph_la-infomap_FlowGraph.lo: infomap_FlowGraph.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-infomap_FlowGraph.lo -MD -MP -MF $(DEPDIR)/libigraph_la-infomap_FlowGraph.Tpo -c -o libigraph_la-infomap_FlowGraph.lo `test -f 'infomap_FlowGraph.cc' || echo '$(srcdir)/'`infomap_FlowGraph.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-infomap_FlowGraph.Tpo $(DEPDIR)/libigraph_la-infomap_FlowGraph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='infomap_FlowGraph.cc' object='libigraph_la-infomap_FlowGraph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-infomap_FlowGraph.lo `test -f 'infomap_FlowGraph.cc' || echo '$(srcdir)/'`infomap_FlowGraph.cc
+
+libigraph_la-bliss_orbit.lo: bliss_orbit.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_orbit.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_orbit.Tpo -c -o libigraph_la-bliss_orbit.lo `test -f 'bliss_orbit.cc' || echo '$(srcdir)/'`bliss_orbit.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_orbit.Tpo $(DEPDIR)/libigraph_la-bliss_orbit.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_orbit.cc' object='libigraph_la-bliss_orbit.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_orbit.lo `test -f 'bliss_orbit.cc' || echo '$(srcdir)/'`bliss_orbit.cc
+
+libigraph_la-bliss_eqrefhash.lo: bliss_eqrefhash.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_eqrefhash.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_eqrefhash.Tpo -c -o libigraph_la-bliss_eqrefhash.lo `test -f 'bliss_eqrefhash.cc' || echo '$(srcdir)/'`bliss_eqrefhash.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_eqrefhash.Tpo $(DEPDIR)/libigraph_la-bliss_eqrefhash.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_eqrefhash.cc' object='libigraph_la-bliss_eqrefhash.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_eqrefhash.lo `test -f 'bliss_eqrefhash.cc' || echo '$(srcdir)/'`bliss_eqrefhash.cc
+
+libigraph_la-bliss_partition.lo: bliss_partition.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_partition.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_partition.Tpo -c -o libigraph_la-bliss_partition.lo `test -f 'bliss_partition.cc' || echo '$(srcdir)/'`bliss_partition.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_partition.Tpo $(DEPDIR)/libigraph_la-bliss_partition.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_partition.cc' object='libigraph_la-bliss_partition.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_partition.lo `test -f 'bliss_partition.cc' || echo '$(srcdir)/'`bliss_partition.cc
+
+libigraph_la-bliss_graph.lo: bliss_graph.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_graph.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_graph.Tpo -c -o libigraph_la-bliss_graph.lo `test -f 'bliss_graph.cc' || echo '$(srcdir)/'`bliss_graph.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_graph.Tpo $(DEPDIR)/libigraph_la-bliss_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_graph.cc' object='libigraph_la-bliss_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_graph.lo `test -f 'bliss_graph.cc' || echo '$(srcdir)/'`bliss_graph.cc
+
+libigraph_la-bliss_timer.lo: bliss_timer.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_timer.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_timer.Tpo -c -o libigraph_la-bliss_timer.lo `test -f 'bliss_timer.cc' || echo '$(srcdir)/'`bliss_timer.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_timer.Tpo $(DEPDIR)/libigraph_la-bliss_timer.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_timer.cc' object='libigraph_la-bliss_timer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_timer.lo `test -f 'bliss_timer.cc' || echo '$(srcdir)/'`bliss_timer.cc
+
+libigraph_la-bliss_heap.lo: bliss_heap.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_heap.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_heap.Tpo -c -o libigraph_la-bliss_heap.lo `test -f 'bliss_heap.cc' || echo '$(srcdir)/'`bliss_heap.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_heap.Tpo $(DEPDIR)/libigraph_la-bliss_heap.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_heap.cc' object='libigraph_la-bliss_heap.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_heap.lo `test -f 'bliss_heap.cc' || echo '$(srcdir)/'`bliss_heap.cc
+
+libigraph_la-bliss_utils.lo: bliss_utils.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss_utils.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss_utils.Tpo -c -o libigraph_la-bliss_utils.lo `test -f 'bliss_utils.cc' || echo '$(srcdir)/'`bliss_utils.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss_utils.Tpo $(DEPDIR)/libigraph_la-bliss_utils.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss_utils.cc' object='libigraph_la-bliss_utils.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss_utils.lo `test -f 'bliss_utils.cc' || echo '$(srcdir)/'`bliss_utils.cc
+
+libigraph_la-bliss.lo: bliss.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-bliss.lo -MD -MP -MF $(DEPDIR)/libigraph_la-bliss.Tpo -c -o libigraph_la-bliss.lo `test -f 'bliss.cc' || echo '$(srcdir)/'`bliss.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-bliss.Tpo $(DEPDIR)/libigraph_la-bliss.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='bliss.cc' object='libigraph_la-bliss.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-bliss.lo `test -f 'bliss.cc' || echo '$(srcdir)/'`bliss.cc
+
+libigraph_la-drl_layout.lo: drl_layout.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-drl_layout.lo -MD -MP -MF $(DEPDIR)/libigraph_la-drl_layout.Tpo -c -o libigraph_la-drl_layout.lo `test -f 'drl_layout.cpp' || echo '$(srcdir)/'`drl_layout.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-drl_layout.Tpo $(DEPDIR)/libigraph_la-drl_layout.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='drl_layout.cpp' object='libigraph_la-drl_layout.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-drl_layout.lo `test -f 'drl_layout.cpp' || echo '$(srcdir)/'`drl_layout.cpp
+
+libigraph_la-drl_parse.lo: drl_parse.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-drl_parse.lo -MD -MP -MF $(DEPDIR)/libigraph_la-drl_parse.Tpo -c -o libigraph_la-drl_parse.lo `test -f 'drl_parse.cpp' || echo '$(srcdir)/'`drl_parse.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-drl_parse.Tpo $(DEPDIR)/libigraph_la-drl_parse.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='drl_parse.cpp' object='libigraph_la-drl_parse.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-drl_parse.lo `test -f 'drl_parse.cpp' || echo '$(srcdir)/'`drl_parse.cpp
+
+libigraph_la-drl_graph.lo: drl_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-drl_graph.lo -MD -MP -MF $(DEPDIR)/libigraph_la-drl_graph.Tpo -c -o libigraph_la-drl_graph.lo `test -f 'drl_graph.cpp' || echo '$(srcdir)/'`drl_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-drl_graph.Tpo $(DEPDIR)/libigraph_la-drl_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='drl_graph.cpp' object='libigraph_la-drl_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-drl_graph.lo `test -f 'drl_graph.cpp' || echo '$(srcdir)/'`drl_graph.cpp
+
+libigraph_la-DensityGrid.lo: DensityGrid.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-DensityGrid.lo -MD -MP -MF $(DEPDIR)/libigraph_la-DensityGrid.Tpo -c -o libigraph_la-DensityGrid.lo `test -f 'DensityGrid.cpp' || echo '$(srcdir)/'`DensityGrid.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-DensityGrid.Tpo $(DEPDIR)/libigraph_la-DensityGrid.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='DensityGrid.cpp' object='libigraph_la-DensityGrid.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-DensityGrid.lo `test -f 'DensityGrid.cpp' || echo '$(srcdir)/'`DensityGrid.cpp
+
+libigraph_la-gengraph_box_list.lo: gengraph_box_list.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_box_list.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_box_list.Tpo -c -o libigraph_la-gengraph_box_list.lo `test -f 'gengraph_box_list.cpp' || echo '$(srcdir)/'`gengraph_box_list.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_box_list.Tpo $(DEPDIR)/libigraph_la-gengraph_box_list.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_box_list.cpp' object='libigraph_la-gengraph_box_list.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_box_list.lo `test -f 'gengraph_box_list.cpp' || echo '$(srcdir)/'`gengraph_box_list.cpp
+
+libigraph_la-gengraph_degree_sequence.lo: gengraph_degree_sequence.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_degree_sequence.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_degree_sequence.Tpo -c -o libigraph_la-gengraph_degree_sequence.lo `test -f 'gengraph_degree_sequence.cpp' || echo '$(srcdir)/'`gengraph_degree_sequence.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_degree_sequence.Tpo $(DEPDIR)/libigraph_la-gengraph_degree_sequence.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_degree_sequence.cpp' object='libigraph_la-gengraph_degree_sequence.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_degree_sequence.lo `test -f 'gengraph_degree_sequence.cpp' || echo '$(srcdir)/'`gengraph_degree_sequence.cpp
+
+libigraph_la-gengraph_graph_molloy_hash.lo: gengraph_graph_molloy_hash.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_graph_molloy_hash.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_graph_molloy_hash.Tpo -c -o libigraph_la-gengraph_graph_molloy_hash.lo `test -f 'gengraph_graph_molloy_hash.cpp' || echo '$(srcdir)/'`gengraph_graph_molloy_hash.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_graph_molloy_hash.Tpo $(DEPDIR)/libigraph_la-gengraph_graph_molloy_hash.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_graph_molloy_hash.cpp' object='libigraph_la-gengraph_graph_molloy_hash.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_graph_molloy_hash.lo `test -f 'gengraph_graph_molloy_hash.cpp' || echo '$(srcdir)/'`gengraph_graph_molloy_hash.cpp
+
+libigraph_la-gengraph_graph_molloy_optimized.lo: gengraph_graph_molloy_optimized.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_graph_molloy_optimized.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_graph_molloy_optimized.Tpo -c -o libigraph_la-gengraph_graph_molloy_optimized.lo `test -f 'gengraph_graph_molloy_optimized.cpp' || echo '$(srcdir)/'`gengraph_graph_molloy [...]
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_graph_molloy_optimized.Tpo $(DEPDIR)/libigraph_la-gengraph_graph_molloy_optimized.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_graph_molloy_optimized.cpp' object='libigraph_la-gengraph_graph_molloy_optimized.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_graph_molloy_optimized.lo `test -f 'gengraph_graph_molloy_optimized.cpp' || echo '$(srcdir)/'`gengraph_graph_molloy_optimized.cpp
+
+libigraph_la-gengraph_mr-connected.lo: gengraph_mr-connected.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_mr-connected.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_mr-connected.Tpo -c -o libigraph_la-gengraph_mr-connected.lo `test -f 'gengraph_mr-connected.cpp' || echo '$(srcdir)/'`gengraph_mr-connected.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_mr-connected.Tpo $(DEPDIR)/libigraph_la-gengraph_mr-connected.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_mr-connected.cpp' object='libigraph_la-gengraph_mr-connected.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_mr-connected.lo `test -f 'gengraph_mr-connected.cpp' || echo '$(srcdir)/'`gengraph_mr-connected.cpp
+
+libigraph_la-gengraph_powerlaw.lo: gengraph_powerlaw.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_powerlaw.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_powerlaw.Tpo -c -o libigraph_la-gengraph_powerlaw.lo `test -f 'gengraph_powerlaw.cpp' || echo '$(srcdir)/'`gengraph_powerlaw.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_powerlaw.Tpo $(DEPDIR)/libigraph_la-gengraph_powerlaw.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_powerlaw.cpp' object='libigraph_la-gengraph_powerlaw.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_powerlaw.lo `test -f 'gengraph_powerlaw.cpp' || echo '$(srcdir)/'`gengraph_powerlaw.cpp
+
+libigraph_la-gengraph_random.lo: gengraph_random.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-gengraph_random.lo -MD -MP -MF $(DEPDIR)/libigraph_la-gengraph_random.Tpo -c -o libigraph_la-gengraph_random.lo `test -f 'gengraph_random.cpp' || echo '$(srcdir)/'`gengraph_random.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-gengraph_random.Tpo $(DEPDIR)/libigraph_la-gengraph_random.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='gengraph_random.cpp' object='libigraph_la-gengraph_random.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-gengraph_random.lo `test -f 'gengraph_random.cpp' || echo '$(srcdir)/'`gengraph_random.cpp
+
+libigraph_la-drl_layout_3d.lo: drl_layout_3d.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-drl_layout_3d.lo -MD -MP -MF $(DEPDIR)/libigraph_la-drl_layout_3d.Tpo -c -o libigraph_la-drl_layout_3d.lo `test -f 'drl_layout_3d.cpp' || echo '$(srcdir)/'`drl_layout_3d.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-drl_layout_3d.Tpo $(DEPDIR)/libigraph_la-drl_layout_3d.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='drl_layout_3d.cpp' object='libigraph_la-drl_layout_3d.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-drl_layout_3d.lo `test -f 'drl_layout_3d.cpp' || echo '$(srcdir)/'`drl_layout_3d.cpp
+
+libigraph_la-drl_graph_3d.lo: drl_graph_3d.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-drl_graph_3d.lo -MD -MP -MF $(DEPDIR)/libigraph_la-drl_graph_3d.Tpo -c -o libigraph_la-drl_graph_3d.lo `test -f 'drl_graph_3d.cpp' || echo '$(srcdir)/'`drl_graph_3d.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-drl_graph_3d.Tpo $(DEPDIR)/libigraph_la-drl_graph_3d.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='drl_graph_3d.cpp' object='libigraph_la-drl_graph_3d.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-drl_graph_3d.lo `test -f 'drl_graph_3d.cpp' || echo '$(srcdir)/'`drl_graph_3d.cpp
+
+libigraph_la-DensityGrid_3d.lo: DensityGrid_3d.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-DensityGrid_3d.lo -MD -MP -MF $(DEPDIR)/libigraph_la-DensityGrid_3d.Tpo -c -o libigraph_la-DensityGrid_3d.lo `test -f 'DensityGrid_3d.cpp' || echo '$(srcdir)/'`DensityGrid_3d.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-DensityGrid_3d.Tpo $(DEPDIR)/libigraph_la-DensityGrid_3d.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='DensityGrid_3d.cpp' object='libigraph_la-DensityGrid_3d.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-DensityGrid_3d.lo `test -f 'DensityGrid_3d.cpp' || echo '$(srcdir)/'`DensityGrid_3d.cpp
+
+libigraph_la-igraph_hrg_types.lo: igraph_hrg_types.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-igraph_hrg_types.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_hrg_types.Tpo -c -o libigraph_la-igraph_hrg_types.lo `test -f 'igraph_hrg_types.cc' || echo '$(srcdir)/'`igraph_hrg_types.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_hrg_types.Tpo $(DEPDIR)/libigraph_la-igraph_hrg_types.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='igraph_hrg_types.cc' object='libigraph_la-igraph_hrg_types.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-igraph_hrg_types.lo `test -f 'igraph_hrg_types.cc' || echo '$(srcdir)/'`igraph_hrg_types.cc
+
+libigraph_la-igraph_hrg.lo: igraph_hrg.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-igraph_hrg.lo -MD -MP -MF $(DEPDIR)/libigraph_la-igraph_hrg.Tpo -c -o libigraph_la-igraph_hrg.lo `test -f 'igraph_hrg.cc' || echo '$(srcdir)/'`igraph_hrg.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-igraph_hrg.Tpo $(DEPDIR)/libigraph_la-igraph_hrg.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='igraph_hrg.cc' object='libigraph_la-igraph_hrg.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-igraph_hrg.lo `test -f 'igraph_hrg.cc' || echo '$(srcdir)/'`igraph_hrg.cc
+
+libigraph_la-prpack.lo: prpack.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -MT libigraph_la-prpack.lo -MD -MP -MF $(DEPDIR)/libigraph_la-prpack.Tpo -c -o libigraph_la-prpack.lo `test -f 'prpack.cpp' || echo '$(srcdir)/'`prpack.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libigraph_la-prpack.Tpo $(DEPDIR)/libigraph_la-prpack.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack.cpp' object='libigraph_la-prpack.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libigraph_la_CXXFLAGS) $(CXXFLAGS) -c -o libigraph_la-prpack.lo `test -f 'prpack.cpp' || echo '$(srcdir)/'`prpack.cpp
+
+prpack/libprpack_la-prpack_base_graph.lo: prpack/prpack_base_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_base_graph.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_base_graph.Tpo -c -o prpack/libprpack_la-prpack_base_graph.lo `test -f 'prpack/prpack_base_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_base_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_base_graph.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_base_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_base_graph.cpp' object='prpack/libprpack_la-prpack_base_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_base_graph.lo `test -f 'prpack/prpack_base_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_base_graph.cpp
+
+prpack/libprpack_la-prpack_igraph_graph.lo: prpack/prpack_igraph_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_igraph_graph.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_igraph_graph.Tpo -c -o prpack/libprpack_la-prpack_igraph_graph.lo `test -f 'prpack/prpack_igraph_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_igraph_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_igraph_graph.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_igraph_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_igraph_graph.cpp' object='prpack/libprpack_la-prpack_igraph_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_igraph_graph.lo `test -f 'prpack/prpack_igraph_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_igraph_graph.cpp
+
+prpack/libprpack_la-prpack_preprocessed_ge_graph.lo: prpack/prpack_preprocessed_ge_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_preprocessed_ge_graph.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_ge_graph.Tpo -c -o prpack/libprpack_la-prpack_preprocessed_ge_graph.lo `test -f 'prpack/prpack_preprocessed_ge_graph.cpp' || echo '$(srcdir)/'`prpac [...]
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_ge_graph.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_ge_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_preprocessed_ge_graph.cpp' object='prpack/libprpack_la-prpack_preprocessed_ge_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_preprocessed_ge_graph.lo `test -f 'prpack/prpack_preprocessed_ge_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_preprocessed_ge_graph.cpp
+
+prpack/libprpack_la-prpack_preprocessed_gs_graph.lo: prpack/prpack_preprocessed_gs_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_preprocessed_gs_graph.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_gs_graph.Tpo -c -o prpack/libprpack_la-prpack_preprocessed_gs_graph.lo `test -f 'prpack/prpack_preprocessed_gs_graph.cpp' || echo '$(srcdir)/'`prpac [...]
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_gs_graph.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_gs_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_preprocessed_gs_graph.cpp' object='prpack/libprpack_la-prpack_preprocessed_gs_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_preprocessed_gs_graph.lo `test -f 'prpack/prpack_preprocessed_gs_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_preprocessed_gs_graph.cpp
+
+prpack/libprpack_la-prpack_preprocessed_scc_graph.lo: prpack/prpack_preprocessed_scc_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_preprocessed_scc_graph.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_scc_graph.Tpo -c -o prpack/libprpack_la-prpack_preprocessed_scc_graph.lo `test -f 'prpack/prpack_preprocessed_scc_graph.cpp' || echo '$(srcdir)/'`p [...]
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_scc_graph.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_scc_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_preprocessed_scc_graph.cpp' object='prpack/libprpack_la-prpack_preprocessed_scc_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_preprocessed_scc_graph.lo `test -f 'prpack/prpack_preprocessed_scc_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_preprocessed_scc_graph.cpp
+
+prpack/libprpack_la-prpack_preprocessed_schur_graph.lo: prpack/prpack_preprocessed_schur_graph.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_preprocessed_schur_graph.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_schur_graph.Tpo -c -o prpack/libprpack_la-prpack_preprocessed_schur_graph.lo `test -f 'prpack/prpack_preprocessed_schur_graph.cpp' || echo '$(src [...]
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_schur_graph.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_preprocessed_schur_graph.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_preprocessed_schur_graph.cpp' object='prpack/libprpack_la-prpack_preprocessed_schur_graph.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_preprocessed_schur_graph.lo `test -f 'prpack/prpack_preprocessed_schur_graph.cpp' || echo '$(srcdir)/'`prpack/prpack_preprocessed_schur_graph.cpp
+
+prpack/libprpack_la-prpack_result.lo: prpack/prpack_result.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_result.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_result.Tpo -c -o prpack/libprpack_la-prpack_result.lo `test -f 'prpack/prpack_result.cpp' || echo '$(srcdir)/'`prpack/prpack_result.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_result.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_result.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_result.cpp' object='prpack/libprpack_la-prpack_result.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_result.lo `test -f 'prpack/prpack_result.cpp' || echo '$(srcdir)/'`prpack/prpack_result.cpp
+
+prpack/libprpack_la-prpack_solver.lo: prpack/prpack_solver.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_solver.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_solver.Tpo -c -o prpack/libprpack_la-prpack_solver.lo `test -f 'prpack/prpack_solver.cpp' || echo '$(srcdir)/'`prpack/prpack_solver.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_solver.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_solver.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_solver.cpp' object='prpack/libprpack_la-prpack_solver.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_solver.lo `test -f 'prpack/prpack_solver.cpp' || echo '$(srcdir)/'`prpack/prpack_solver.cpp
+
+prpack/libprpack_la-prpack_utils.lo: prpack/prpack_utils.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT prpack/libprpack_la-prpack_utils.lo -MD -MP -MF prpack/$(DEPDIR)/libprpack_la-prpack_utils.Tpo -c -o prpack/libprpack_la-prpack_utils.lo `test -f 'prpack/prpack_utils.cpp' || echo '$(srcdir)/'`prpack/prpack_utils.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prpack/$(DEPDIR)/libprpack_la-prpack_utils.Tpo prpack/$(DEPDIR)/libprpack_la-prpack_utils.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prpack/prpack_utils.cpp' object='prpack/libprpack_la-prpack_utils.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprpack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o prpack/libprpack_la-prpack_utils.lo `test -f 'prpack/prpack_utils.cpp' || echo '$(srcdir)/'`prpack/prpack_utils.cpp
+
+.cpp.o:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+.l.c:
+	$(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+	$(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf ../optional/glpk/.libs ../optional/glpk/_libs
+	-rm -rf ../optional/glpk/amd/.libs ../optional/glpk/amd/_libs
+	-rm -rf ../optional/glpk/colamd/.libs ../optional/glpk/colamd/_libs
+	-rm -rf cs/.libs cs/_libs
+	-rm -rf f2c/.libs f2c/_libs
+	-rm -rf lapack/.libs lapack/_libs
+	-rm -rf plfit/.libs plfit/_libs
+	-rm -rf prpack/.libs prpack/_libs
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f ../optional/glpk/$(DEPDIR)/$(am__dirstamp)
+	-rm -f ../optional/glpk/$(am__dirstamp)
+	-rm -f ../optional/glpk/amd/$(DEPDIR)/$(am__dirstamp)
+	-rm -f ../optional/glpk/amd/$(am__dirstamp)
+	-rm -f ../optional/glpk/colamd/$(DEPDIR)/$(am__dirstamp)
+	-rm -f ../optional/glpk/colamd/$(am__dirstamp)
+	-rm -f cs/$(DEPDIR)/$(am__dirstamp)
+	-rm -f cs/$(am__dirstamp)
+	-rm -f f2c/$(DEPDIR)/$(am__dirstamp)
+	-rm -f f2c/$(am__dirstamp)
+	-rm -f lapack/$(DEPDIR)/$(am__dirstamp)
+	-rm -f lapack/$(am__dirstamp)
+	-rm -f plfit/$(DEPDIR)/$(am__dirstamp)
+	-rm -f plfit/$(am__dirstamp)
+	-rm -f prpack/$(DEPDIR)/$(am__dirstamp)
+	-rm -f prpack/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-rm -f foreign-dl-lexer.c
+	-rm -f foreign-dl-parser.c
+	-rm -f foreign-dl-parser.h
+	-rm -f foreign-gml-lexer.c
+	-rm -f foreign-gml-parser.c
+	-rm -f foreign-gml-parser.h
+	-rm -f foreign-lgl-lexer.c
+	-rm -f foreign-lgl-parser.c
+	-rm -f foreign-lgl-parser.h
+	-rm -f foreign-ncol-lexer.c
+	-rm -f foreign-ncol-parser.c
+	-rm -f foreign-ncol-parser.h
+	-rm -f foreign-pajek-lexer.c
+	-rm -f foreign-pajek-parser.c
+	-rm -f foreign-pajek-parser.h
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ../optional/glpk/$(DEPDIR) ../optional/glpk/amd/$(DEPDIR) ../optional/glpk/colamd/$(DEPDIR) ./$(DEPDIR) cs/$(DEPDIR) f2c/$(DEPDIR) lapack/$(DEPDIR) plfit/$(DEPDIR) prpack/$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ../optional/glpk/$(DEPDIR) ../optional/glpk/amd/$(DEPDIR) ../optional/glpk/colamd/$(DEPDIR) ./$(DEPDIR) cs/$(DEPDIR) f2c/$(DEPDIR) lapack/$(DEPDIR) plfit/$(DEPDIR) prpack/$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \
+	cscopelist-am ctags ctags-am distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-includeHEADERS install-info install-info-am \
+	install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES
+
+ at INTERNAL_F2C_TRUE@  f2c/arith.h: f2c/arithchk.c
+ at INTERNAL_F2C_TRUE@	$(CC) $(CFLAGS) -DNO_FPINIT f2c/arithchk.c -lm -o f2c/arith || \
+ at INTERNAL_F2C_TRUE@	$(CC) -DNO_LONG_LONG $(CFLAGS) -DNO_FPINIT f2c/arithchk.c \
+ at INTERNAL_F2C_TRUE@		$(WARNING_CFLAGS) -lm -o f2c/arith
+ at INTERNAL_F2C_TRUE@	f2c/arith > f2c/arith.h
+ at INTERNAL_F2C_TRUE@  f2c/sysdep1.h: f2c/sysdep1.h0
+ at INTERNAL_F2C_TRUE@	cp f2c/sysdep1.h0 f2c/sysdep1.h
+ at INTERNAL_F2C_TRUE@  f2c/signal1.h: f2c/signal1.h0
+ at INTERNAL_F2C_TRUE@	cp f2c/signal1.h0 f2c/signal1.h
+
+echosources:
+	$(info $(SOURCES) $(LAPACK) $(ARPACK) $(BLAS) $(libf2c_la_SOURCES) \
+	$(libdlamch_la_SOURCES) $(libplfit_la_SOURCES))
+
+echoheaders:
+	$(info $(HEADERS_PUBLIC))
+
+echoheadersprivate:
+	$(info $(HEADERS_PRIVATE))
+
+.PHONY: sources
+
+parsersources: $(DIST_COMMON)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/NetDataTypes.cpp b/src/NetDataTypes.cpp
new file mode 100644
index 0000000..b2113c5
--- /dev/null
+++ b/src/NetDataTypes.cpp
@@ -0,0 +1,225 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by J�rg Reichardt 
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          NetDataTypes.cpp  -  description
+                             -------------------
+    begin                : Mon Oct 6 2003
+    copyright            : (C) 2003 by Joerg Reichardt
+    email                : reichardt at mitte
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include "NetDataTypes.h"
+
+//#################################################################################
+//###############################################################################
+//Constructor
+NNode::NNode(unsigned long ind, unsigned long c_ind, DLList<NLink*> *ll, char* n, int states)
+{
+   index=ind;
+   cluster_index=c_ind;
+   neighbours = new DLList<NNode*>();
+   n_links = new DLList<NLink*>();
+   global_link_list=ll;
+   strcpy(name,n);
+   color.red=0;
+   color.green=0;
+   color.blue=0;
+   strcpy(color.pajek_c,"Green");
+   clustering=0.0;
+   marker=0;
+   affiliations=0;
+   weight=0.0;
+   affinity=0.0;
+   distance=0;
+   max_states=states;
+   state_history=new unsigned long[states+1];
+}
+
+//Destructor
+NNode::~NNode()
+{
+  Disconnect_From_All();
+  delete neighbours;
+  delete n_links;
+  delete [] state_history;
+  neighbours=NULL;
+  n_links=NULL;
+  state_history=NULL;
+}
+
+void NNode::Add_StateHistory(unsigned int state)
+{
+  if (max_states>=state) {
+    state_history[state]++;
+  }
+}
+
+void NNode::Set_Color(RGBcolor c)
+{
+  color.red=c.red; color.blue=c.blue; color.green=c.green;
+  strcpy(color.pajek_c,c.pajek_c);
+}
+
+int NNode::Connect_To(NNode* neighbour, double weight)
+{
+  NLink *link;
+  //sollen doppelte Links erlaubt sein??  NEIN
+  if (!neighbour) return 0;
+  if (!(neighbours->Is_In_List(neighbour)) && (neighbour!=this))
+    {
+      neighbours->Push(neighbour);        // nachbar hier eintragen
+      neighbour->neighbours->Push(this); // diesen knoten beim nachbarn eintragen
+
+      link=new NLink(this,neighbour, weight);        //link erzeugen
+      global_link_list->Push(link);                        // in globaler liste eintragen
+      n_links->Push(link);                                   // bei diesem Knoten eintragen
+      neighbour->n_links->Push(link);                  // beim nachbarn eintragen
+
+      return(1);
+    }
+   return(0);
+}
+
+NLink *NNode::Get_LinkToNeighbour(NNode* neighbour)
+{
+  DLList_Iter<NLink*> iter;
+  NLink *l_cur, *link=0;
+  bool found=false;
+  // finde einen bestimmten Link aus der Liste der links eines Knotens
+  l_cur=iter.First(n_links);
+  while (!iter.End() && !found)
+  {
+    if (((l_cur->Get_Start()==this) && (l_cur->Get_End()==neighbour)) || ((l_cur->Get_End()==this) && (l_cur->Get_Start()==neighbour)))
+    {
+      found=true;
+      link=l_cur;
+    }
+    l_cur=iter.Next();
+  }
+  if (found) return link; else return NULL;
+}
+
+int NNode::Disconnect_From(NNode* neighbour)
+{
+  //sollen doppelte Links erlaubt sein??  s.o.
+  if (!neighbours) return 0;
+  neighbours->fDelete(neighbour);
+  n_links->fDelete(Get_LinkToNeighbour(neighbour));
+  neighbour->n_links->fDelete(neighbour->Get_LinkToNeighbour(this));
+  neighbour->neighbours->fDelete(this);
+  return 1;
+}
+
+int NNode::Disconnect_From_All()
+{
+ int number_of_neighbours=0;
+ while (neighbours->Size()) {
+      Disconnect_From(neighbours->Pop());
+      number_of_neighbours++;
+ }
+ return(number_of_neighbours) ;
+}
+
+/*
+int NNode::Disconnect_From_All_Grandchildren()
+{
+ int n_l=links->Size();
+ unsigned long pos=0;
+ while ((n_l--)>1) {  //alle bis auf das erste loeschen
+      pos=(links->Get(n_l+1))->links->Is_In_List(this);
+     // printf("%d %d\n",n_l,pos);
+      (links->Get(n_l+1))->links->Delete(pos);
+  }
+ return(pos) ;
+}
+*/
+
+double NNode::Get_Links_Among_Neigbours(void)
+{
+//  long neighbours1, neighbours2;
+  double lam=0;
+  DLList_Iter<NNode*> iter1, iter2;
+//  neighbours1=neighbours->Size();        //so viele Nachbarn hat die Betrachtete Node
+  NNode *step1,*step2;
+  step1=iter1.First(neighbours);
+  while (!iter1.End()) //  for (int n1=1;n1<=neighbours1; n1++)
+  {
+    //step1=neighbours->Get(n1);
+    //neighbours2=step1->neighbours->Size();  //so viele Nachbarn hat der n1-ste Nachbar
+    step2=iter2.First(step1->Get_Neighbours());
+    while (!iter2.End()) //for (int n2=1;n2<=neighbours2; n2++)
+    {
+        //step2=step1->neighbours->Get(n2);
+        if (step2->Get_Neighbours()->Is_In_List(this)) {lam++;}
+        step2=iter2.Next();
+    }
+  step1=iter1.Next();
+  }
+  return(lam/2.0);
+}
+
+
+double NNode::Get_Clustering()
+{
+  double c;
+  unsigned long k;
+  k=neighbours->Size();
+  if (k<=1) return(0);
+  c=2.0*Get_Links_Among_Neigbours()/double(k*k-k);
+  return(c);
+}
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//Constructor
+NLink::NLink(NNode *s, NNode *e, double w)
+{
+   start=s;
+   end=e;
+   weight=w;
+   old_weight=0;
+   marker=0;
+}
+
+//Destructor
+NLink::~NLink()
+{
+  if (start && end) start->Disconnect_From(end);
+}
diff --git a/src/NetDataTypes.h b/src/NetDataTypes.h
new file mode 100644
index 0000000..c640049
--- /dev/null
+++ b/src/NetDataTypes.h
@@ -0,0 +1,821 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by J�rg Reichardt 
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          NetDataTypes.h  -  description
+                             -------------------
+    begin                : Mon Oct 6 2003
+    copyright            : (C) 2003 by Joerg Reichardt
+    email                : reichardt at mitte
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+#ifndef NETDATATYPES_H
+#define NETDATATYPES_H
+
+#include <string.h>
+
+//###########################################################################################
+
+struct HUGE_INDEX
+{
+    unsigned int field_index;
+    unsigned long in_field_index;
+};
+
+template <class DATA> class HugeArray
+{
+  private:
+  unsigned long int size;
+  unsigned int highest_field_index;
+  unsigned long max_bit_left;
+  unsigned long max_index;
+  DATA *data;
+  DATA *fields[32];
+  public:
+  HUGE_INDEX get_huge_index(unsigned long);
+  DATA &Set(unsigned long);
+  DATA Get(unsigned long);
+  HugeArray(void);
+  ~HugeArray(void);
+  DATA &operator[](unsigned long);
+  unsigned long Size(void) {return max_index;}
+} ;
+//###############################################################################################
+template <class L_DATA > class DLList;
+template <class L_DATA > class DL_Indexed_List;
+template <class L_DATA > class ClusterList;
+template <class L_DATA > class DLList_Iter;
+
+template <class L_DATA>
+class DLItem
+{
+      friend class DLList<L_DATA> ;
+      friend class DL_Indexed_List<L_DATA>;
+      friend class DLList_Iter<L_DATA>;
+      private:
+      L_DATA  item;
+      unsigned long index;
+      DLItem *previous;
+      DLItem *next;
+      DLItem(L_DATA i, unsigned long ind);
+      DLItem(L_DATA i, unsigned long ind, DLItem<L_DATA> *p, DLItem<L_DATA> *n); 
+      ~DLItem();
+      public:
+      void del() { delete item; }
+};
+
+template <class L_DATA >
+class DLList
+{
+  friend class DLList_Iter<L_DATA>;
+  protected:
+    DLItem<L_DATA>  *head;
+    DLItem<L_DATA>  *tail;
+    unsigned long number_of_items;
+    DLItem<L_DATA> *pInsert(L_DATA, DLItem<L_DATA>*);
+    L_DATA pDelete(DLItem<L_DATA>*);
+  public:
+    DLList(void);
+    ~DLList();
+    unsigned long Size(void) { return number_of_items; }
+    int Insert(L_DATA, unsigned long);
+    int Delete(unsigned long);
+    int fDelete(L_DATA);
+    L_DATA Push(L_DATA);
+    L_DATA Pop(void);
+    L_DATA Get(unsigned long);
+    int Enqueue(L_DATA);
+    L_DATA Dequeue(void);
+    unsigned long Is_In_List(L_DATA);
+    void delete_items();
+};
+
+template <class L_DATA>
+class DL_Indexed_List : virtual public DLList<L_DATA>
+{
+  friend class DLList_Iter<L_DATA>;
+  private:
+   DLItem<L_DATA> *pInsert(L_DATA, DLItem<L_DATA>*);
+   L_DATA pDelete(DLItem<L_DATA>*);
+   HugeArray<DLItem<L_DATA>*> array;
+   unsigned long last_index;
+  public:
+      DL_Indexed_List(void);
+    ~DL_Indexed_List();
+    L_DATA Push(L_DATA);
+    L_DATA Pop(void);
+    L_DATA Get(unsigned long);
+};
+
+//#####################################################################################################
+
+template <class L_DATA> class DLList_Iter
+{
+    private:
+     DLList<L_DATA>  *list;
+     DLItem<L_DATA> *current;
+     bool end_reached;
+    public:
+      DLList_Iter(void);
+      ~DLList_Iter() {end_reached=true;};
+      L_DATA Next(void);
+      L_DATA Previous(void);
+      L_DATA First(DLList<L_DATA> *l);
+      L_DATA Last(DLList<L_DATA> *l);
+      bool End(void) {return end_reached;}
+      DLItem<L_DATA> *Get_Current(void) {return current;}
+      L_DATA Get_Current_Item(void) {return current->item;}
+      void Set_Current(DLItem<L_DATA> *c) {current=c;}
+      void Set_Status(bool s) {end_reached=s;}
+      bool Swap(DLList_Iter<L_DATA>);  //swapt die beiden Elemente, wenn sie in der gleichen Liste stehen!!
+ 
+};
+
+//#####################################################################################################
+ struct RGBcolor {
+    unsigned int red;
+    unsigned int green;
+    unsigned int blue;
+    char pajek_c[20];
+};
+//-------------------------------------------------------------------------------
+
+class NLink;
+
+class NNode
+{
+  friend class NLink;
+  private :
+    unsigned long index;
+    unsigned long cluster_index;
+    unsigned long marker, affiliations;
+    unsigned long *state_history;
+    unsigned int max_states;
+    long distance;
+    double clustering;
+    double weight;
+    double affinity;
+//    double old_weight;
+    
+    DLList<NNode*> *neighbours;    //list with pointers to neighbours
+    DLList<NLink*> *n_links;
+    DLList<NLink*> *global_link_list;
+    char name[255];
+    RGBcolor color;
+  public :
+    NNode(unsigned long, unsigned long, DLList<NLink*>*, char*, int);
+    ~NNode();
+    unsigned long Get_Index(void)  { return(index); }
+    unsigned long Get_ClusterIndex(void) { return(cluster_index);}
+    unsigned long Get_Marker(void) { return marker;}
+    void Set_Marker(unsigned long m) {marker=m;}
+    unsigned long Get_Affiliations(void) { return affiliations;}
+    void Set_Affiliations(unsigned long m) {affiliations=m;}
+    void Set_ClusterIndex(unsigned long ci) { cluster_index=ci; return;}
+    void Set_Index(unsigned long i) {index=i; return;}
+    unsigned long Get_Degree(void) { return(neighbours->Size());}
+    char *Get_Name(void) {return name;}
+    void Set_Name(char* n) {strcpy(name,n);}
+    double Get_Links_Among_Neigbours(void);
+    double Get_Clustering(void);
+    double Get_Weight(void) {return weight;}
+    double Get_Affinity(void) {return affinity;}
+    unsigned long *Get_StateHistory(void) {return state_history;}
+    void Add_StateHistory(unsigned int q);
+  //  double Get_OldWeight(void) {return old_weight;}
+    void Set_Weight(double w) {weight=w;}
+    void Set_Affinity(double w) {affinity=w;}
+
+  //  void Set_OldWeight(double w) {old_weight=w;}
+    long Get_Distance(void) {return distance;}
+    void Set_Distance(long d) {distance=d;}
+    int  Connect_To(NNode*, double);
+    DLList<NNode*> *Get_Neighbours(void) {return neighbours;}
+    DLList<NLink*> *Get_Links(void) {return n_links;}
+    int  Disconnect_From(NNode*);
+    int  Disconnect_From_All(void);
+    bool Is_Linked_To(NNode*);
+    RGBcolor Get_Color(void) {return color;}
+    void Set_Color(RGBcolor c);
+    NLink *Get_LinkToNeighbour(NNode *neighbour);
+};
+
+//#####################################################################################################
+
+class NLink
+{
+  friend class NNode;
+  private :
+    NNode *start;
+    NNode *end;
+    double weight;
+    double old_weight;
+    unsigned long index;
+    unsigned long marker;
+  public :
+    NLink( NNode*, NNode*, double);
+    ~NLink();
+    unsigned long Get_Start_Index(void)  { return(start->Get_Index()); }
+    unsigned long Get_End_Index(void)    { return(end->Get_Index()); }
+    NNode *Get_Start(void) {return(start);}
+    NNode *Get_End(void) {return(end);}
+    double Get_Weight(void) {return weight;}
+    void Set_Weight(double w) {weight=w;}
+    double Get_OldWeight(void) {return old_weight;}
+    void Set_OldWeight(double w) {old_weight=w;}
+    unsigned long Get_Marker(void) {return marker;}
+    void Set_Marker(unsigned long m) {marker=m;}
+    unsigned long Get_Index() {return index;}
+    void Set_Index(unsigned long i) {index=i;}
+};
+
+//#####################################################################################################
+
+template <class L_DATA>  class ClusterList : public DLList<L_DATA>
+{
+  friend class DLList_Iter<L_DATA>;
+  private:
+  long links_out_of_cluster;
+  unsigned long links_inside_cluster;
+  unsigned long frequency;
+  double cluster_energy;
+  DLList<L_DATA> *candidates;
+  long marker;
+  public:
+  ClusterList(void);
+   ~ClusterList();
+  long Get_Links_OOC(void) {return(links_out_of_cluster);}
+  void Set_Links_OOC(long looc) {links_out_of_cluster=looc;}
+  unsigned long Get_Links_IC(void) {return(links_inside_cluster);}
+  unsigned long Get_Frequency(void) {return(frequency);}
+  void IncreaseFrequency(void) {frequency++;}
+  void Set_Links_IC(unsigned long lic) {links_inside_cluster=lic;}
+  double Get_Energy(void) {return (cluster_energy);}
+  void Set_Energy(double e) {cluster_energy=e;}
+  DLList<L_DATA> *Get_Candidates(void) {return candidates;}
+  bool operator<(ClusterList<L_DATA> &b);
+  bool operator==(ClusterList <L_DATA> &b);
+  long Get_Marker(void) {return marker;}
+  void Set_Marker(long m) {marker=m;}  
+};
+//#####################################################################################################
+template <class L_DATA>
+class DL_Node_List : virtual public DL_Indexed_List<NNode*>
+{
+  friend class DLList_Iter<L_DATA>;
+  private:
+   DLItem<L_DATA> *pInsert(NNode*, DLItem<NNode*>*);
+   NNode* pDelete(DLItem<NNode*>*);
+   HugeArray<DLItem<NNode*>*> array;
+   unsigned long last_index;
+  public:
+    DL_Node_List(void);
+    ~DL_Node_List();
+    NNode* Push(NNode*);
+    NNode* Pop(void);
+    NNode* Get(unsigned long);
+    int Delete(unsigned long);
+
+};
+//#####################################################################################################
+
+
+
+struct cluster_join_move
+{
+  ClusterList<NNode*> *c1;
+  ClusterList<NNode*> *c2;
+  double joint_energy;
+  long joint_looc;
+  unsigned long joint_lic;
+} ;
+
+struct network
+{
+  DL_Indexed_List<NNode*> *node_list;
+  DL_Indexed_List<NLink*> *link_list;
+  DL_Indexed_List<ClusterList<NNode*>*> *cluster_list;
+  DL_Indexed_List<cluster_join_move*> *moveset;
+  unsigned long max_k;
+  unsigned long min_k;
+  unsigned long diameter;
+  double av_weight;
+  double max_weight;
+  double min_weight;
+  double sum_weights;
+  double av_k;
+  double av_bids;
+  unsigned long max_bids;
+  unsigned long min_bids;
+  unsigned long sum_bids;
+} ;
+
+/*
+struct network
+{
+  DLList<NNode*> *node_list;
+  DLList<NLink*> *link_list;
+  DLList<ClusterList<NNode*>*> *cluster_list;
+  DLList<cluster_join_move*> *moveset;
+} ;
+*/
+
+template <class DATA>
+HugeArray<DATA>::HugeArray(void)
+{
+ max_bit_left=1<<31;   //wir setzen das 31. Bit auf 1
+ size=2;
+ max_index=0;
+ highest_field_index=0;
+ data=new DATA[2]; //ein extra Platz fuer das Nullelement
+ data[0]=0;
+ data[1]=0; 
+ for (int i=0; i<32; i++) fields[i]=NULL;
+ fields[highest_field_index]=data;
+}
+
+template <class DATA> HugeArray<DATA>::~HugeArray(void)
+{
+ for (unsigned int i=0; i<=highest_field_index; i++)
+ {
+   data=fields[i];
+   delete [] data;
+ }
+}
+
+template <class DATA>
+HUGE_INDEX HugeArray<DATA>::get_huge_index(unsigned long index)
+{
+  HUGE_INDEX h_index;
+  unsigned int shift_index=0;
+  unsigned long help_index;
+  help_index=index;
+  if (index<2) {
+    h_index.field_index=0;
+    h_index.in_field_index=index;
+    return h_index;
+  }
+  // wie oft muessen wir help_index nach links shiften, damit das 31. Bit gesetzt ist??
+  while (!(max_bit_left & help_index))
+  {
+    help_index <<= 1;
+    shift_index++;
+  }
+  h_index.field_index=31-shift_index;       // das hoechste  besetzte Bit im Index
+  help_index=1 << h_index.field_index;    // in help_index wird das hoechste besetzte Bit von Index gesetzt
+  h_index.in_field_index=(index ^ help_index);   // index XOR help_index, womit alle bits unter dem hoechsten erhalten bleiben
+  return h_index;
+}
+
+template <class DATA>
+DATA &HugeArray<DATA>::Set(unsigned long int index)
+{
+ HUGE_INDEX h_index;
+ unsigned long data_size;
+ while (size<index+1)
+ {
+    highest_field_index++;
+    data_size=1<<highest_field_index;
+    data=new DATA[data_size];
+    for (unsigned long i=0; i<data_size; i++)
+    {
+      data[i]=0;
+    }
+    size=size+data_size;   //overflow noch abfangen
+    //printf("Vergroesserung auf: %u bei index %u\n",size,index);
+    fields[highest_field_index]=data;
+ }
+ h_index=get_huge_index(index);
+ //printf("index %lu = %lu . %lu\n",index,h_index.field_index,h_index.in_field_index);
+ data=fields[h_index.field_index];
+ if (max_index<index) {max_index=index;}
+ return(data[h_index.in_field_index]);
+}
+
+template <class DATA>
+DATA HugeArray<DATA>::Get(unsigned long index)
+{
+  return(Set(index));
+}
+
+
+template <class DATA>
+DATA &HugeArray<DATA>::operator[](unsigned long index)
+{
+  return(Set(index));
+}
+
+                                                                                                                                                                                                                                                                                                                                                                  
+//###############################################################################
+template <class L_DATA>
+DLItem<L_DATA>::DLItem(L_DATA i, unsigned long ind) : item(i), index(ind), previous(0), next(0)
+{
+}
+
+template <class L_DATA>
+DLItem<L_DATA>::DLItem(L_DATA i, unsigned long ind, DLItem<L_DATA> *p, DLItem<L_DATA> *n) : item(i), index(ind), previous(p), next(n)
+{
+}
+
+template <class L_DATA>
+DLItem<L_DATA>::~DLItem()
+{
+ //delete item;      //eigentlich muessten wir pruefen, ob item ueberhaupt ein Pointer ist...
+ //previous=NULL;
+ //next=NULL;
+}
+
+
+//######################################################################################################################
+template <class L_DATA>
+DLList<L_DATA>::DLList(void)
+{
+   head=tail=NULL;
+   number_of_items=0;
+   head=new DLItem<L_DATA>(NULL,0);  //fuer head und Tail gibt es das gleiche Array-Element!! Vorsicht!!
+   tail=new DLItem<L_DATA>(NULL,0);
+   if ( !head || !tail )
+     {
+      if (head) delete(head);
+      if (tail) delete(tail);
+      return;
+     }  else {
+     head->next=tail;
+     tail->previous=head;
+   }
+}
+
+template <class L_DATA>
+DLList<L_DATA>::~DLList()
+{
+  DLItem<L_DATA> *cur=head, *next;
+  while (cur)
+    {
+      next=cur->next;
+      delete(cur);
+      cur=next;
+    }
+    number_of_items=0;
+  //  printf("Liste Zerstoert!\n");
+}
+
+template <class L_DATA>
+void DLList<L_DATA>::delete_items() {
+  DLItem<L_DATA> *cur, *next;
+  cur=this->head;
+  while (cur)
+    {
+      next=cur->next;
+      cur->del();
+      cur=next;
+    }
+  this->number_of_items=0;
+}  
+
+//privates Insert
+template <class L_DATA>
+DLItem<L_DATA> *DLList<L_DATA>::pInsert(L_DATA data, DLItem<L_DATA> *pos)
+{
+   DLItem<L_DATA> *i=new DLItem<L_DATA>(data, number_of_items+1, pos->previous, pos);
+   if (i)
+      {
+      pos->previous->next=i;
+      pos->previous=i;
+      number_of_items++;
+      return(i);
+      }
+   else return(0);
+}
+//privates delete
+template <class L_DATA>
+L_DATA DLList<L_DATA>::pDelete(DLItem<L_DATA> *i)
+{
+  L_DATA data=i->item;
+  i->previous->next=i->next;
+  i->next->previous=i->previous;
+//  array[i->index]=0;
+  delete(i);
+  number_of_items--;
+  return(data);
+}
+//oeffentliches Insert
+template <class L_DATA>
+int DLList<L_DATA>::Insert(L_DATA data, unsigned long pos)
+{
+  if ((pos<0)||(pos>(number_of_items))) return(0);
+  DLItem<L_DATA> *cur=head;
+  while(pos--) cur=cur->next;
+  return(pInsert(data,cur)!=0);
+}
+//oeffentliche Delete
+template <class L_DATA>
+int DLList<L_DATA>::Delete(unsigned long pos)
+{
+  if ((pos<0)||(pos>(number_of_items))) return(0);
+  DLItem<L_DATA> *cur=head;
+  while(pos--) cur=cur->next;
+  return(pDelete(cur)!=0);
+}
+
+//oeffentliche Delete
+template <class L_DATA>
+int DLList<L_DATA>::fDelete(L_DATA data)
+{
+  if ((number_of_items==0) || (!data)) return(0);
+  DLItem<L_DATA> *cur;
+  cur=head->next;
+  while ((cur!=tail) && (cur->item!=data)) cur=cur->next;
+  if (cur!=tail) return(pDelete(cur)!=0);
+  return(0);
+}
+
+template <class L_DATA>
+L_DATA DLList<L_DATA>::Push(L_DATA data)
+{
+  DLItem<L_DATA> *tmp;
+  tmp=pInsert(data,tail);
+  if (tmp) return (tmp->item);
+  return(0);
+}
+
+template <class L_DATA>
+L_DATA DLList<L_DATA>::Pop(void)
+{
+  return(pDelete(tail->previous));
+}
+
+
+template <class L_DATA>
+L_DATA DLList<L_DATA>::Get(unsigned long pos)
+{
+  if ((pos<1)||(pos>(number_of_items+1))) return(0);
+//  return(array[pos]->item);
+  DLItem<L_DATA> *cur=head;
+  while(pos--) cur=cur->next;
+  return(cur->item);
+}
+
+
+template <class L_DATA>
+int DLList<L_DATA>::Enqueue(L_DATA data)
+{
+  return(pInsert(data,tail)!=0);
+}
+
+template <class L_DATA>
+L_DATA DLList<L_DATA>::Dequeue(void)
+{
+  return(pDelete(head->next));
+}
+
+//gibt Index des gesuchte Listenelement zurueck, besser waere eigentlich zeiger
+template <class L_DATA>
+unsigned long DLList<L_DATA>::Is_In_List(L_DATA data)
+{
+  DLItem<L_DATA> *cur=head, *next;
+  unsigned long pos=0;
+  while (cur)
+    {
+      next=cur->next;
+      if (cur->item==data) return(pos) ;
+      cur=next;
+      pos++;
+    }
+  return(0);
+}
+
+//######################################################################################################################
+template <class L_DATA>
+DL_Indexed_List<L_DATA>::DL_Indexed_List(void) : DLList<L_DATA>()
+{
+  last_index=0;
+}
+
+template <class L_DATA>
+DL_Indexed_List<L_DATA>::~DL_Indexed_List()
+{
+  /* This is already done by the DLList destructor */
+/*   DLItem<L_DATA> *cur, *next; */
+/*   cur=this->head; */
+/*   while (cur) */
+/*     { */
+/*       next=cur->next; */
+/*       delete(cur); */
+/*       cur=next; */
+/*     } */
+/*     this->number_of_items=0; */
+  //  printf("Liste Zerstoert!\n");
+}
+
+//privates Insert
+template <class L_DATA>
+DLItem<L_DATA> *DL_Indexed_List<L_DATA>::pInsert(L_DATA data, DLItem<L_DATA> *pos)
+{
+    DLItem<L_DATA> *i=new DLItem<L_DATA>(data, last_index, pos->previous, pos);
+   if (i)
+      {
+      pos->previous->next=i;
+      pos->previous=i;
+      this->number_of_items++;
+      array[last_index]=i;
+      last_index++;
+      return(i);
+      }
+   else return(0);
+}
+//privates delete
+template <class L_DATA>
+L_DATA DL_Indexed_List<L_DATA>::pDelete(DLItem<L_DATA> *i)
+{
+  L_DATA data=i->item;
+  i->previous->next=i->next;
+  i->next->previous=i->previous;
+  array[i->index]=0;
+  last_index=i->index;
+  delete(i);
+  this->number_of_items--;
+  return(data);
+}
+template <class L_DATA>
+L_DATA DL_Indexed_List<L_DATA>::Push(L_DATA data)
+{
+  DLItem<L_DATA> *tmp;
+  tmp=pInsert(data,this->tail);
+  if (tmp) return (tmp->item);
+  return(0);
+}
+
+template <class L_DATA>
+L_DATA DL_Indexed_List<L_DATA>::Pop(void)
+{
+  return(pDelete(this->tail->previous));
+}
+
+template <class L_DATA>
+L_DATA DL_Indexed_List<L_DATA>::Get(unsigned long pos)
+{
+  if (pos > this->number_of_items - 1) return(0);
+  return(array[pos]->item);
+}
+
+//#######################################################################################
+
+//************************************************************************************************************
+template <class L_DATA>
+ClusterList<L_DATA>::ClusterList(void) : DLList<L_DATA>()
+{
+  links_out_of_cluster=0;
+  links_inside_cluster=0;
+  frequency=1;
+  cluster_energy=1e30;
+  candidates=new DLList<L_DATA>();
+  marker=0;
+}
+
+template <class L_DATA>
+ClusterList<L_DATA>::~ClusterList() 
+{
+  while (candidates->Size()) {
+    candidates->Pop();
+  }
+  delete candidates;
+}
+
+
+template <class L_DATA>
+bool ClusterList<L_DATA>::operator==(ClusterList<L_DATA> &b)
+{
+bool found=false;
+L_DATA n_cur, n_cur_b;
+DLList_Iter<L_DATA> a_iter,b_iter;
+
+if (this->Size()!=b.Size()) return false;
+
+n_cur=a_iter.First(this);
+while (!(a_iter.End()))
+{
+  found=false;
+  n_cur_b=b_iter.First(&b);
+  while (!(b_iter.End()) && !found)
+  {
+    if (n_cur==n_cur_b) found=true;
+    n_cur_b=b_iter.Next();
+  }
+  if (!found) return false;
+  n_cur=a_iter.Next();
+}
+return(found);
+}
+//A<B ist Wahr, wenn A echte Teilmenge von B ist
+template <class L_DATA>
+bool ClusterList<L_DATA>::operator<(ClusterList<L_DATA> &b)
+{
+bool found=false;
+L_DATA n_cur, n_cur_b;
+DLList_Iter<L_DATA> a_iter, b_iter;
+
+if (this->Size()>=b.Size()) return false;
+n_cur=a_iter.First(this);
+while (!(a_iter.End()))
+{
+  found=false;
+  n_cur_b=b_iter.First(&b);
+  while (!(b_iter.End()) && !found)
+  {
+    if (n_cur==n_cur_b) found=true;
+    n_cur_b=b_iter.Next();
+  }
+  if (!found) return false;
+  n_cur=a_iter.Next();
+}
+return(found);
+}
+
+//#####################################################################################
+template <class L_DATA>
+DLList_Iter<L_DATA>::DLList_Iter()
+{
+  list=NULL;
+  current=NULL;
+  end_reached=true;
+}
+
+template <class L_DATA>
+L_DATA DLList_Iter<L_DATA>::Next(void)
+{
+  current=current->next;
+  if (current==(list->tail)) end_reached=true;
+  return(current->item);
+}
+
+template <class L_DATA>
+L_DATA DLList_Iter<L_DATA>::Previous(void)
+{
+  current=current->previous;
+  if (current==(list->head)) end_reached=true;
+  return(current->item);
+}
+
+template <class L_DATA>
+L_DATA DLList_Iter<L_DATA>::First(DLList<L_DATA> *l)
+{
+    list=l;
+    current=list->head->next;
+    if (current==(list->tail)) end_reached=true;
+    else end_reached=false;
+    return(current->item);
+}
+
+template <class L_DATA>
+L_DATA DLList_Iter<L_DATA>::Last(DLList<L_DATA> *l)
+{
+    list=l;
+    current=list->tail->previous;
+    if (current==(list->head)) end_reached=true;         // falls die List leer ist
+    else end_reached=false;
+    return(current->item);
+}
+
+template <class L_DATA>
+bool DLList_Iter<L_DATA>::Swap(DLList_Iter<L_DATA> b)
+{
+  L_DATA h;
+  if (list!=b.list) return false; //elemeten muessen aus der gleichen List stammen
+  if (end_reached || b.end_reached) return false;
+  h=current->item; current->item=b.current->item; b.current->item=h;
+  return true;
+} 
+
+#endif
+
diff --git a/src/NetRoutines.cpp b/src/NetRoutines.cpp
new file mode 100644
index 0000000..daca200
--- /dev/null
+++ b/src/NetRoutines.cpp
@@ -0,0 +1,278 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by J�rg Reichardt 
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          NetRoutines.cpp  -  description
+                             -------------------
+    begin                : Tue Oct 28 2003
+    copyright            : (C) 2003 by Joerg Reichardt
+    email                : reichardt at mitte
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include "NetRoutines.h"
+#include "NetDataTypes.h"
+
+#include "igraph_types.h"
+#include "igraph_interface.h"
+#include "igraph_conversion.h"
+
+int igraph_i_read_network(const igraph_t *graph, 
+			  const igraph_vector_t *weights,
+			  network *net, igraph_bool_t use_weights, 
+			  unsigned int states) {
+  
+  double av_k=0.0, sum_weight=0.0, min_weight=1e60, max_weight=-1e60;
+  unsigned long min_k=999999999, max_k=0;
+  long max_index=0;
+  char name[255];
+  NNode *node1,*node2;
+  DLList_Iter<NNode*> iter;
+  igraph_vector_t edgelist;
+  long int no_of_edges=(long int)igraph_ecount(graph);
+  long int ii;
+  char *empty=new char[1];
+  empty[0]='\0';
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edgelist, no_of_edges*2);
+  IGRAPH_CHECK(igraph_get_edgelist(graph, &edgelist, 0 /* rowwise */));
+
+  for (ii=0; ii<no_of_edges; ii++) {
+    long int i1=(long int)VECTOR(edgelist)[2*ii]+1;
+    long int i2=(long int)VECTOR(edgelist)[2*ii+1]+1;
+    igraph_real_t Links;
+    if (use_weights) {
+      Links=VECTOR(*weights)[ii];
+    } else {
+      Links=1.0;
+    }
+    // From the original source
+    if (max_index<i1) {
+      for (int i=max_index; i<i1; i++)
+	net->node_list->Push(new NNode(i,0,net->link_list, empty,states));
+      max_index=i1;
+    }
+    if (max_index<i2) {
+      for (int i=max_index; i<i2; i++)
+	net->node_list->Push(new NNode(i,0,net->link_list, empty,states));
+      max_index=i2;
+    }
+    
+    node1=net->node_list->Get(i1-1);
+    sprintf(name,"%li",i1);
+    node1->Set_Name(name);
+    
+    node2=net->node_list->Get(i2-1);
+    sprintf(name,"%li",i2);
+    node2->Set_Name(name);
+    
+    node1->Connect_To(node2,Links);
+    
+    if (Links<min_weight) min_weight=Links;
+    if (Links>max_weight) max_weight=Links;
+    sum_weight+=Links;
+  }
+
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_vector_destroy(&edgelist);
+  
+  node1=iter.First(net->node_list);
+  while (!iter.End())
+  {
+    if (node1->Get_Degree()>max_k) max_k=node1->Get_Degree();
+    if (node1->Get_Degree()<min_k) min_k=node1->Get_Degree();
+    av_k+=node1->Get_Degree();
+    node1=iter.Next();
+  }
+  net->av_k=av_k/double(net->node_list->Size());
+  net->sum_weights=sum_weight;
+  net->av_weight=sum_weight/double(net->link_list->Size());
+  net->min_k=min_k;
+  net->max_k=max_k;
+  net->min_weight=min_weight;
+  net->max_weight=max_weight;
+  net->sum_bids=0;
+  net->min_bids=0;
+  net->max_bids=0;
+  
+  delete [] empty;
+
+  return 0;
+}
+
+//###############################################################################################################
+void reduce_cliques(DLList<ClusterList<NNode*>*> *global_cluster_list, FILE *file)
+{
+  unsigned long size;
+  ClusterList<NNode*> *c_cur, *largest_c=0;
+  DLList<ClusterList<NNode*>*> *subsets;
+  DLList_Iter<ClusterList<NNode*>*> c_iter, sub_iter;
+  DLList_Iter<NNode*> iter;
+  NNode *n_cur;
+
+  if (!(global_cluster_list->Size())) return;
+  //wir suchen den groessten Cluster
+
+  c_cur=c_iter.First(global_cluster_list);
+  size=0;
+  while (!(c_iter.End()))
+  {
+    if (c_cur->Size()>size)
+      {
+        size=c_cur->Size();
+        largest_c=c_cur;
+      }
+    c_cur=c_iter.Next();
+  }
+// printf("Groesster Cluster hat %u Elemente.\n",largest_c->Size());
+
+  //Schauen, ob es Teilmengen gibt, die ebenfalls gefunden wurden
+  subsets=new DLList<ClusterList<NNode*>*>();
+  c_cur=c_iter.First(global_cluster_list);
+  while (!(c_iter.End()))
+  {
+    if ((*c_cur<*largest_c || *c_cur==*largest_c) && c_cur!=largest_c)   //alle echten Teilcluster von largest_c und die doppelten
+    {
+      subsets->Push(c_cur);
+    }
+    c_cur=c_iter.Next();
+  }
+  // die gefundenen Subsets werden aus der cluster_liste geloescht
+  while (subsets->Size())
+  {
+    global_cluster_list->fDelete(subsets->Pop());
+  }
+  delete subsets;
+  // Dann schreiben wir den groessten Cluster in das File
+  fprintf(file,"Energie: %1.12f   Nodes:%3lu    -   ",largest_c->Get_Energy(),largest_c->Size());
+  
+  n_cur=iter.First(largest_c);
+  while (!(iter.End()))
+  {
+     fprintf(file,"%s",n_cur->Get_Name());
+     n_cur=iter.Next();
+     if (n_cur) fprintf(file,", ");
+   }
+   fprintf(file,"\n");
+   
+   
+  //Schliesslich schmeissen wir noch den eben gefundenen groessten Cluster raus
+ global_cluster_list->fDelete(largest_c);
+  //und dann geht es von vorn mit der Reduzierten ClusterListe los
+  reduce_cliques(global_cluster_list, file);
+
+}
+//##################################################################################
+void reduce_cliques2(network *net, bool only_double, long marker)
+{
+  unsigned long size;
+  ClusterList<NNode*> *c_cur, *largest_c=0;
+  DLList_Iter<ClusterList<NNode*>*> c_iter;
+  do
+  {
+    //wir suchen den groessten, nicht markierten Cluster
+    size=0;
+    c_cur=c_iter.First(net->cluster_list);
+    while (!(c_iter.End()))
+    {
+      if ((c_cur->Size()>size) && (c_cur->Get_Marker()!=marker))
+        {
+          size=c_cur->Size();
+          largest_c=c_cur;
+        }
+      c_cur=c_iter.Next();
+    }
+    // printf("Groesster Cluster hat %u Elemente.\n",largest_c->Size());
+    //Schauen, ob es Teilmengen gibt, die ebenfalls gefunden wurden
+    c_cur=c_iter.First(net->cluster_list);
+    while (!(c_iter.End()))
+    {
+      if (((!only_double && (*c_cur<*largest_c)) || (*c_cur==*largest_c)) && (c_cur!=largest_c))   //alle echten Teilcluster von largest_c und die doppelten
+      {
+        net->cluster_list->fDelete(c_cur);
+        while (c_cur->Get_Candidates()->Size()) c_cur->Get_Candidates()->Pop();
+        while (c_cur->Size()) c_cur->Pop();    // die knoten aber nicht loeschen!!
+        delete c_cur;    // nicht vergessen, die global geloeschte Clusterliste zu loeschen
+      }
+      c_cur=c_iter.Next();      
+    }
+    //Schliesslich markieren wir noch den eben gefundenen groessten Cluster
+    largest_c->Set_Marker(marker);
+  } while (size);
+}
+
+//##################################################################################################
+unsigned long iterate_nsf_hierarchy(NNode *parent, unsigned long depth,FILE *file)
+{
+    NNode* next_node;
+    unsigned long newdepth, maxdepth;
+    bool first=true;
+    DLList_Iter<NNode*> *iter;
+    maxdepth=newdepth=depth;
+    iter=new DLList_Iter<NNode*>;
+    next_node=iter->First(parent->Get_Neighbours());
+    while (!(iter->End()))
+    {
+      if (next_node->Get_Marker()>parent->Get_Marker())  // wir gehen nach unten
+      {
+        if (first) fprintf(file,",(");                 // eine Neue Klammer auf
+        if (first) fprintf(file,"%s",next_node->Get_Name());  // nur vor dem ersten kein Komma
+          else fprintf(file,",%s",next_node->Get_Name());     // sonst immer mit Komma
+        first=false;
+        newdepth=iterate_nsf_hierarchy(next_node,depth+1, file);
+        if (maxdepth<newdepth) maxdepth=newdepth;
+     }
+    next_node=iter->Next();
+    }
+    if (!first) fprintf(file,")");                     //hat es ueberhaupt einen gegeben?
+                                                       //dann klamer zu!
+    delete iter;
+    return maxdepth;
+}
+
+//################################################################
+void clear_all_markers(network *net)
+{
+  DLList_Iter<NNode*> iter;
+  NNode *n_cur;
+  n_cur=iter.First(net->node_list);
+  while (!iter.End())
+  {
+    n_cur->Set_Marker(0);
+    n_cur=iter.Next();
+  }
+}
+
diff --git a/src/NetRoutines.h b/src/NetRoutines.h
new file mode 100644
index 0000000..5517d2e
--- /dev/null
+++ b/src/NetRoutines.h
@@ -0,0 +1,61 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by J�rg Reichardt 
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          NetRoutines.h  -  description
+                             -------------------
+    begin                : Tue Oct 28 2003
+    copyright            : (C) 2003 by Joerg Reichardt
+    email                : reichardt at mitte
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef NETROUTINES_H
+#define NETROUTINES_H
+
+#include "NetDataTypes.h"
+#include "igraph_types.h"
+#include "igraph_datatype.h"
+
+int igraph_i_read_network(const igraph_t *graph,
+			  const igraph_vector_t *weights,
+			  network *net, igraph_bool_t use_weights,
+			  unsigned int states);
+
+void reduce_cliques(DLList<ClusterList<NNode*>*>*, FILE *file);
+void reduce_cliques2(network*, bool,  long );
+void clear_all_markers(network *net);
+
+#endif
+
diff --git a/src/adjlist.c b/src/adjlist.c
new file mode 100644
index 0000000..865abe1
--- /dev/null
+++ b/src/adjlist.c
@@ -0,0 +1,856 @@
+/* -*- 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
+
+*/
+
+#include "igraph_adjlist.h"
+#include "igraph_memory.h"
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+#include "config.h"
+
+#include <string.h>   /* memset */
+#include <stdio.h>
+
+/**
+ * \section about_adjlists
+ * <para>Sometimes it is easier to work with a graph which is in
+ * adjacency list format: a list of vectors; each vector contains the
+ * neighbor vertices or incident edges of a given vertex. Typically,
+ * this representation is good if we need to iterate over the neighbors
+ * of all vertices many times. E.g. when finding the shortest paths
+ * between every pairs of vertices or calculating closeness centrality
+ * for all the vertices.</para>
+ * 
+ * <para>The <type>igraph_adjlist_t</type> stores the adjacency lists
+ * of a graph. After creation it is independent of the original graph,
+ * it can be modified freely with the usual vector operations, the
+ * graph is not affected. E.g. the adjacency list can be used to
+ * rewire the edges of a graph efficiently. If one used the
+ * straightforward \ref igraph_delete_edges() and \ref
+ * igraph_add_edges() combination for this that needs O(|V|+|E|) time
+ * for every single deletion and insertion operation, it is thus very
+ * slow if many edges are rewired. Extracting the graph into an
+ * adjacency list, do all the rewiring operations on the vectors of
+ * the adjacency list and then creating a new graph needs (depending
+ * on how exactly the rewiring is done) typically O(|V|+|E|) time for
+ * the whole rewiring process.</para>
+ * 
+ * <para>Lazy adjacency lists are a bit different. When creating a
+ * lazy adjacency list, the neighbors of the vertices are not queried,
+ * only some memory is allocated for the vectors. When \ref
+ * igraph_lazy_adjlist_get() is called for vertex v the first time,
+ * the neighbors of v are queried and stored in a vector of the
+ * adjacency list, so they don't need to be queried again. Lazy
+ * adjacency lists are handy if you have an at least linear operation
+ * (because initialization is generally linear in terms of number of
+ * vertices), but you don't know how many vertices you will visit
+ * during the computation.
+ * </para>
+ *
+ * <para>
+ * \example examples/simple/adjlist.c
+ * </para>
+ */
+
+/**
+ * \function igraph_adjlist_init
+ * Initialize an adjacency list of vertices from a given graph
+ * 
+ * Create a list of vectors containing the neighbors of all vertices
+ * in a graph. The adjacency list is independent of the graph after
+ * creation, e.g. the graph can be destroyed and modified, the
+ * adjacency list contains the state of the graph at the time of its
+ * initialization. 
+ * \param graph The input graph. 
+ * \param al Pointer to an uninitialized <type>igraph_adjlist_t</type> object.
+ * \param mode Constant specifying whether outgoing
+ *   (<code>IGRAPH_OUT</code>), incoming (<code>IGRAPH_IN</code>),
+ *   or both (<code>IGRAPH_ALL</code>) types of neighbors to include
+ *   in the adjacency list. It is ignored for undirected networks.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ */
+
+int igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, 
+			  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 adjlist view", IGRAPH_EINVMODE);
+  }
+
+  igraph_vector_init(&tmp, 0);
+  IGRAPH_FINALLY(igraph_vector_destroy, &tmp);
+
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+
+  al->length=igraph_vcount(graph);
+  al->adjs=igraph_Calloc(al->length, igraph_vector_int_t);
+  if (al->adjs == 0) {
+    IGRAPH_ERROR("Cannot create adjlist view", IGRAPH_ENOMEM);
+  }
+
+  IGRAPH_FINALLY(igraph_adjlist_destroy, al);
+  for (i=0; i<al->length; i++) {
+    int j, n;
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_CHECK(igraph_neighbors(graph, &tmp, i, mode));
+    n=igraph_vector_size(&tmp);
+    IGRAPH_CHECK(igraph_vector_int_init(&al->adjs[i], n));
+    for (j=0; j<n; j++) {
+      VECTOR(al->adjs[i])[j] = VECTOR(tmp)[j];
+    }
+  }
+
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_adjlist_init_empty
+ * Initialize an empty adjacency list
+ * 
+ * Creates a list of vectors, one for each vertex. This is useful when you
+ * are \em constructing a graph using an adjacency list representation as
+ * it does not require your graph to exist yet.
+ * \param no_of_nodes The number of vertices
+ * \param al Pointer to an uninitialized <type>igraph_adjlist_t</type> object.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), linear in the number of vertices.
+ */
+
+int igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes) {
+  long int i;
+
+  al->length=no_of_nodes;
+  al->adjs=igraph_Calloc(al->length, igraph_vector_int_t);
+  if (al->adjs == 0) {
+    IGRAPH_ERROR("Cannot create adjlist view", IGRAPH_ENOMEM);
+  }
+
+  IGRAPH_FINALLY(igraph_adjlist_destroy, al);
+  for (i=0; i<al->length; i++) {
+    IGRAPH_CHECK(igraph_vector_int_init(&al->adjs[i], 0));
+  }
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_adjlist_init_complementer
+ * Adjacency lists for the complementer graph
+ * 
+ * This function creates adjacency lists for the complementer 
+ * of the input graph. In the complementer graph all edges are present
+ * which are not present in the original graph. Multiple edges in the
+ * input graph are ignored.
+ * \param graph The input graph.
+ * \param al Pointer to a not yet initialized adjacency list.
+ * \param mode Constant specifying whether outgoing
+ *   (<code>IGRAPH_OUT</code>), incoming (<code>IGRAPH_IN</code>),
+ *   or both (<code>IGRAPH_ALL</code>) types of neighbors (in the
+ *   complementer graph) to include in the adjacency list. It is
+ *   ignored for undirected networks.
+ * \param loops Whether to consider loop edges.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^2+|E|), quadratic in the number of vertices.
+ */
+
+int igraph_adjlist_init_complementer(const igraph_t *graph,
+				       igraph_adjlist_t *al, 
+				       igraph_neimode_t mode,
+				       igraph_bool_t loops) {
+  igraph_integer_t i, j, k, n;
+  igraph_bool_t* seen;
+  igraph_vector_t vec;
+
+  if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_EINVMODE);
+  }
+
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+
+  al->length=igraph_vcount(graph);
+  al->adjs=igraph_Calloc(al->length, igraph_vector_int_t);
+  if (al->adjs == 0) {
+    IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_ENOMEM);
+  }
+
+  IGRAPH_FINALLY(igraph_adjlist_destroy, al);
+
+  n=al->length;
+  seen=igraph_Calloc(n, igraph_bool_t);
+  if (seen==0) {
+    IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, seen);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&vec, 0);
+
+  for (i=0; i<al->length; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    igraph_neighbors(graph, &vec, i, mode);
+    memset(seen, 0, sizeof(igraph_bool_t)*(unsigned) al->length);
+    n=al->length;
+    if (!loops) { seen[i] = 1; n--; }
+    for (j=0; j<igraph_vector_size(&vec); j++) {
+      if (! seen [ (long int) VECTOR(vec)[j] ] ) {
+	n--;
+	seen[ (long int) VECTOR(vec)[j] ] = 1;
+      }
+    }
+    IGRAPH_CHECK(igraph_vector_int_init(&al->adjs[i], n));
+    for (j=0, k=0; k<n; j++) {
+      if (!seen[j]) {
+	VECTOR(al->adjs[i])[k++] = j;
+      }
+    }
+  }
+
+  igraph_Free(seen);
+  igraph_vector_destroy(&vec);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+/**
+ * \function igraph_adjlist_destroy
+ * Deallocate memory
+ * 
+ * Free all memory allocated for an adjacency list. 
+ * \param al The adjacency list to destroy.
+ * 
+ * Time complexity: depends on memory management.
+ */
+
+void igraph_adjlist_destroy(igraph_adjlist_t *al) {
+  long int i;
+  for (i=0; i<al->length; i++) {
+    if (&al->adjs[i]) { igraph_vector_int_destroy(&al->adjs[i]); }
+  }
+  igraph_Free(al->adjs);
+}
+
+/**
+ * \function igraph_adjlist_clear
+ * Removes all edges from an adjacency list.
+ *
+ * \param al The adjacency list.
+ * Time complexity: depends on memory management, typically O(n), where n is
+ * the total number of elements in the adjacency list.
+ */
+void igraph_adjlist_clear(igraph_adjlist_t *al) {
+  long int i;
+  for (i=0; i<al->length; i++) {
+    igraph_vector_int_clear(&al->adjs[i]);
+  }
+}
+
+/**
+ * \function igraph_adjlist_size
+ * Number of vertices in an adjacency list.
+ * 
+ * \param al The adjacency list.
+ * \return The number of elements.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al) {
+  return al->length;
+}
+
+/* igraph_vector_int_t *igraph_adjlist_get(igraph_adjlist_t *al, igraph_integer_t no) { */
+/*   return &al->adjs[(long int)no]; */
+/* } */
+
+/**
+ * \function igraph_adjlist_sort
+ * Sort each vector in an adjacency list.
+ * 
+ * Sorts every vector of the adjacency list.
+ * \param al The adjacency list.
+ * 
+ * Time complexity: O(n log n), n is the total number of elements in
+ * the adjacency list.
+ */
+
+void igraph_adjlist_sort(igraph_adjlist_t *al) {
+  long int i;
+  for (i=0; i<al->length; i++)
+    igraph_vector_int_sort(&al->adjs[i]);
+}
+
+/**
+ * \function igraph_adjlist_simplify
+ * Simplify
+ * 
+ * Simplify an adjacency list, ie. remove loop and multiple edges.
+ * \param al The adjacency list.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of edges and
+ * vertices.
+ */
+
+int igraph_adjlist_simplify(igraph_adjlist_t *al) {
+  long int i;
+  long int n=al->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=&al->adjs[i];
+    long int j, l=igraph_vector_int_size(v);
+    VECTOR(mark)[i] = i+1;
+    for (j=0; j<l; /* nothing */) {
+      long int e=(long int) VECTOR(*v)[j];
+      if (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;
+}
+
+int igraph_adjlist_remove_duplicate(const igraph_t *graph,
+				    igraph_adjlist_t *al) {
+  long int i;
+  long int n=al->length;
+  IGRAPH_UNUSED(graph);
+  for (i=0; i<n; i++) {
+    igraph_vector_int_t *v=&al->adjs[i];
+    long int j, p=1, l=igraph_vector_int_size(v);
+    for (j=1; j<l; j++) {
+      long int e=(long int) VECTOR(*v)[j];
+      /* Non-loop edges, and one end of loop edges are fine. */
+      /* We use here, that the vector is sorted and we also keep it sorted */
+      if (e != i || VECTOR(*v)[j-1] != e) {
+	VECTOR(*v)[p++] = e;
+      }
+    }
+    igraph_vector_int_resize(v, p);
+  }
+  
+  return 0;
+}
+
+#ifndef USING_R
+int igraph_adjlist_print(const igraph_adjlist_t *al) {
+  long int i;
+  long int n=al->length;
+  for (i=0; i<n; i++) {
+    igraph_vector_int_t *v=&al->adjs[i];
+    igraph_vector_int_print(v);
+  }
+  return 0;
+}
+#endif
+
+int igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile) {
+  long int i;
+  long int n=al->length;
+  for (i=0; i<n; i++) {
+    igraph_vector_int_t *v=&al->adjs[i];
+    igraph_vector_int_fprint(v, outfile);
+  }
+  return 0;
+}
+
+int igraph_adjedgelist_remove_duplicate(const igraph_t *graph, 
+					igraph_inclist_t *al) {
+    IGRAPH_WARNING("igraph_adjedgelist_remove_duplicate() is deprecated, use "
+                   "igraph_inclist_remove_duplicate() instead");
+    return igraph_inclist_remove_duplicate(graph, al);
+}
+
+#ifndef USING_R
+int igraph_adjedgelist_print(const igraph_inclist_t *al, FILE *outfile) {
+    IGRAPH_WARNING("igraph_adjedgelist_print() is deprecated, use "
+                   "igraph_inclist_print() instead");
+    return igraph_inclist_fprint(al, outfile);
+}
+#endif
+
+/**
+ * \function igraph_adjedgelist_init
+ * Initialize an incidence list of edges
+ *
+ * This function was superseded by \ref igraph_inclist_init() in igraph 0.6.
+ * Please use \ref igraph_inclist_init() instead of this function.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+int igraph_adjedgelist_init(const igraph_t *graph, 
+			                igraph_inclist_t *il, 
+			                igraph_neimode_t mode) {
+    IGRAPH_WARNING("igraph_adjedgelist_init() is deprecated, use "
+                   "igraph_inclist_init() instead");
+    return igraph_inclist_init(graph, il, mode);
+}
+
+/**
+ * \function igraph_adjedgelist_destroy
+ * Frees all memory allocated for an incidence list.
+ *
+ * This function was superseded by \ref igraph_inclist_destroy() in igraph 0.6.
+ * Please use \ref igraph_inclist_destroy() instead of this function.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+void igraph_adjedgelist_destroy(igraph_inclist_t *il) {
+    IGRAPH_WARNING("igraph_adjedgelist_destroy() is deprecated, use "
+                   "igraph_inclist_destroy() instead");
+    igraph_inclist_destroy(il);
+}
+
+int igraph_inclist_remove_duplicate(const igraph_t *graph, 
+					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];
+    long int j, p=1, l=igraph_vector_size(v);
+    for (j=1; j<l; j++) {
+      long int e=(long int) VECTOR(*v)[j];
+      /* Non-loop edges and one end of loop edges are fine. */
+      /* We use here, that the vector is sorted and we also keep it sorted */
+      if (IGRAPH_FROM(graph, e) != IGRAPH_TO(graph, e) ||
+	  VECTOR(*v)[j-1] != e) {
+	VECTOR(*v)[p++] = e;
+      }
+    }
+    igraph_vector_resize(v, p);
+  }
+  
+  return 0;
+}
+
+#ifndef USING_R
+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);
+  }
+  return 0;
+}
+#endif
+
+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);
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_inclist_init
+ * Initialize an incidence list of edges
+ * 
+ * Create a list of vectors containing the incident edges for all
+ * vertices. The incidence list is independent of the graph after
+ * creation, subsequent changes of the graph object do not update the
+ * incidence list, and changes to the incidence list do not update the
+ * graph.
+ * \param graph The input graph.
+ * \param il Pointer to an uninitialized incidence list.
+ * \param mode Constant specifying whether incoming edges
+ *   (<code>IGRAPH_IN</code>), outgoing edges (<code>IGRAPH_OUT</code>) or
+ *   both (<code>IGRAPH_ALL</code>) to include in the incidence lists
+ *   of directed graphs. It is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ */
+
+int igraph_inclist_init(const igraph_t *graph, 
+			      igraph_inclist_t *il, 
+			      igraph_neimode_t mode) {
+  igraph_integer_t i;
+
+  if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_EINVMODE);
+  }
+
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+
+  il->length=igraph_vcount(graph);
+  il->incs=igraph_Calloc(il->length, igraph_vector_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++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_CHECK(igraph_vector_init(&il->incs[i], 0));
+    IGRAPH_CHECK(igraph_incident(graph, &il->incs[i], i, mode));
+  }
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_inclist_init_empty
+ * \brief Initialize an incidence list corresponding to an empty graph.
+ * 
+ * This function essentially creates a list of empty vectors that may
+ * be treated as an incidence list for a graph with a given number of
+ * vertices.
+ *
+ * \param il Pointer to an uninitialized incidence list.
+ * \param n  The number of vertices in the incidence list.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), linear in the number of vertices.
+ */
+
+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);
+  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_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_inclist_destroy
+ * Frees all memory allocated for an incidence list.
+ *
+ * \param eal The incidence list to destroy.
+ * 
+ * Time complexity: depends on memory management.
+ */
+
+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]);
+  }
+  igraph_Free(il->incs);
+}
+
+/**
+ * \function igraph_inclist_clear
+ * Removes all edges from an incidence list.
+ *
+ * \param il The incidence list.
+ * Time complexity: depends on memory management, typically O(n), where n is
+ * the total number of elements in the incidence list.
+ */
+void igraph_inclist_clear(igraph_inclist_t *il) {
+  long int i;
+  for (i=0; i<il->length; i++) {
+    igraph_vector_clear(&il->incs[i]);
+  }
+}
+
+/**
+ * \function igraph_lazy_adjlist_init
+ * Constructor
+ *
+ * Create a lazy adjacency list for vertices. This function only
+ * allocates some memory for storing the vectors of an adjacency list,
+ * but the neighbor vertices are not queried, only at the \ref
+ * igraph_lazy_adjlist_get() calls. 
+ * \param graph The input graph.
+ * \param al Pointer to an uninitialized adjacency list object.
+ * \param mode Constant, it gives whether incoming edges
+ *   (<code>IGRAPH_IN</code>), outgoing edges
+ *   (<code>IGRPAH_OUT</code>) or both types of edges
+ *   (<code>IGRAPH_ALL</code>) are considered. It is ignored for
+ *   undirected graphs.
+ * \param simplify Constant, it gives whether to simplify the vectors
+ *   in the adjacency list (<code>IGRAPH_SIMPLIFY</code>) or not
+ *   (<code>IGRAPH_DONT_SIMPLIFY</code>).
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), the number of vertices, possibly, but
+ * depends on the underlying memory management too.
+ */
+
+int igraph_lazy_adjlist_init(const igraph_t *graph,
+			       igraph_lazy_adjlist_t *al,
+			       igraph_neimode_t mode,
+			       igraph_lazy_adlist_simplify_t simplify) {
+  if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Cannor create adjlist view", IGRAPH_EINVMODE);
+  }
+
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }  
+  al->mode=mode;
+  al->simplify=simplify;
+  al->graph=graph;
+  
+  al->length=igraph_vcount(graph);
+  al->adjs=igraph_Calloc(al->length, igraph_vector_t*);
+  if (al->adjs == 0) {
+    IGRAPH_ERROR("Cannot create lazy adjlist view", IGRAPH_ENOMEM);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_lazy_adjlist_destroy
+ * Deallocate memory
+ * 
+ * Free all allocated memory for a lazy adjacency list.
+ * \param al The adjacency list to deallocate.
+ * 
+ * Time complexity: depends on the memory management.
+ */
+
+void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al) {
+  igraph_lazy_adjlist_clear(al);
+  igraph_Free(al->adjs);
+}
+
+/**
+ * \function igraph_lazy_adjlist_clear
+ * Removes all edges from a lazy adjacency list.
+ *
+ * \param al The lazy adjacency list.
+ * Time complexity: depends on memory management, typically O(n), where n is
+ * the total number of elements in the adjacency list.
+ */
+void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al) {
+  long int i, n=al->length;
+  for (i=0; i<n; i++) {
+    if (al->adjs[i] != 0) {
+      igraph_vector_destroy(al->adjs[i]);
+      igraph_Free(al->adjs[i]);
+    }
+  }
+}
+
+igraph_vector_t *igraph_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al,
+						igraph_integer_t pno) {
+  igraph_integer_t no=pno;
+  int ret;
+  if (al->adjs[no] == 0) {
+    al->adjs[no] = igraph_Calloc(1, igraph_vector_t);
+    if (al->adjs[no] == 0) {
+      igraph_error("Lazy adjlist failed", __FILE__, __LINE__, 
+		   IGRAPH_ENOMEM);
+    }
+    ret=igraph_vector_init(al->adjs[no], 0);
+    if (ret != 0) {
+      igraph_error("", __FILE__, __LINE__, ret);
+    }
+    ret=igraph_neighbors(al->graph, al->adjs[no], no, al->mode);
+    if (ret != 0) {
+      igraph_error("", __FILE__, __LINE__, ret);
+    }
+
+    if (al->simplify == IGRAPH_SIMPLIFY) {
+      igraph_vector_t *v=al->adjs[no];
+      long int i, p=0, n=igraph_vector_size(v);
+      for (i=0; i<n; i++) {
+	if (VECTOR(*v)[i] != no && 
+	    (i==n-1 || VECTOR(*v)[i+1] != VECTOR(*v)[i])) {
+	  VECTOR(*v)[p]=VECTOR(*v)[i];
+	  p++;
+	}
+      }
+      igraph_vector_resize(v, p);
+    }
+  }
+  
+  return al->adjs[no];
+}
+
+/**
+ * \function igraph_lazy_adjedgelist_init
+ * Initializes a lazy incidence list of edges
+ *
+ * This function was superseded by \ref igraph_lazy_inclist_init() in igraph 0.6.
+ * Please use \ref igraph_lazy_inclist_init() instead of this function.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+int igraph_lazy_adjedgelist_init(const igraph_t *graph, 
+			                igraph_lazy_inclist_t *il, 
+			                igraph_neimode_t mode) {
+    IGRAPH_WARNING("igraph_lazy_adjedgelist_init() is deprecated, use "
+                   "igraph_lazy_inclist_init() instead");
+    return igraph_lazy_inclist_init(graph, il, mode);
+}
+
+/**
+ * \function igraph_lazy_adjedgelist_destroy
+ * Frees all memory allocated for an incidence list.
+ *
+ * This function was superseded by \ref igraph_lazy_inclist_destroy() in igraph 0.6.
+ * Please use \ref igraph_lazy_inclist_destroy() instead of this function.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+void igraph_lazy_adjedgelist_destroy(igraph_lazy_inclist_t *il) {
+    IGRAPH_WARNING("igraph_lazy_adjedgelist_destroy() is deprecated, use "
+                   "igraph_lazy_inclist_destroy() instead");
+    igraph_lazy_inclist_destroy(il);
+}
+
+igraph_vector_t *igraph_lazy_adjedgelist_get_real(igraph_lazy_adjedgelist_t *il,
+						    igraph_integer_t pno) {
+    IGRAPH_WARNING("igraph_lazy_adjedgelist_get_real() is deprecated, use "
+                   "igraph_lazy_inclist_get_real() instead");
+    return igraph_lazy_inclist_get_real(il, pno);
+}
+
+/**
+ * \function igraph_lazy_inclist_init
+ * Initializes a lazy incidence list of edges
+ * 
+ * Create a lazy incidence list for edges. This function only
+ * allocates some memory for storing the vectors of an incidence list,
+ * but the incident edges are not queried, only when \ref
+ * igraph_lazy_inclist_get() is called.
+ * \param graph The input graph.
+ * \param al Pointer to an uninitialized incidence list.
+ * \param mode Constant, it gives whether incoming edges
+ *   (<code>IGRAPH_IN</code>), outgoing edges
+ *   (<code>IGRPAH_OUT</code>) or both types of edges
+ *   (<code>IGRAPH_ALL</code>) are considered. It is ignored for
+ *   undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), the number of vertices, possibly. But it
+ * also depends on the underlying memory management.
+ */
+
+int igraph_lazy_inclist_init(const igraph_t *graph,
+				   igraph_lazy_inclist_t *al,
+				   igraph_neimode_t mode) {
+
+  if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Cannot create lazy incidence list view", IGRAPH_EINVMODE);
+  }
+  
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+  
+  al->mode=mode;
+  al->graph=graph;
+  
+  al->length=igraph_vcount(graph);
+  al->incs=igraph_Calloc(al->length, igraph_vector_t*);
+  if (al->incs == 0) {
+    IGRAPH_ERROR("Cannot create lazy incidence list view", IGRAPH_ENOMEM);
+  }
+
+  return 0;
+  
+}
+
+/**
+ * \function igraph_lazy_inclist_destroy
+ * Deallocates memory
+ * 
+ * Frees all allocated memory for a lazy incidence list.
+ * \param al The incidence list to deallocate.
+ * 
+ * Time complexity: depends on memory management.
+ */
+
+void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il) {
+  igraph_lazy_inclist_clear(il);
+  igraph_Free(il->incs);
+}
+
+/**
+ * \function igraph_lazy_inclist_clear
+ * Removes all edges from a lazy incidence list.
+ *
+ * \param il The lazy incidence list.
+ * Time complexity: depends on memory management, typically O(n), where n is
+ * the total number of elements in the incidence list.
+ */
+void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il) {
+  long int i, n=il->length;
+  for (i=0; i<n; i++) {
+    if (il->incs[i] != 0) {
+      igraph_vector_destroy(il->incs[i]);
+      igraph_Free(il->incs[i]);
+    }
+  }
+}
+
+igraph_vector_t *igraph_lazy_inclist_get_real(igraph_lazy_inclist_t *il,
+						    igraph_integer_t pno) {
+  igraph_integer_t no=pno;
+  int ret;
+  if (il->incs[no] == 0) {
+    il->incs[no] = igraph_Calloc(1, igraph_vector_t);
+    if (il->incs[no] == 0) {
+      igraph_error("Lazy incidence list query failed", __FILE__, __LINE__, 
+		   IGRAPH_ENOMEM);
+    }
+    ret=igraph_vector_init(il->incs[no], 0);
+    if (ret != 0) {
+      igraph_error("", __FILE__, __LINE__, ret);
+    }
+    ret=igraph_incident(il->graph, il->incs[no], no, il->mode);
+    if (ret != 0) {
+      igraph_error("", __FILE__, __LINE__, ret);
+    }
+  }
+  return il->incs[no];
+}
diff --git a/src/arpack.c b/src/arpack.c
new file mode 100644
index 0000000..500db65
--- /dev/null
+++ b/src/arpack.c
@@ -0,0 +1,1344 @@
+/* -*- mode: C -*-  */
+/* vim:set sw=2 ts=2 sts=2 et: */
+/* 
+   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_arpack.h"
+#include "igraph_arpack_internal.h"
+#include "igraph_memory.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+/* The ARPACK example file dssimp.f is used as a template */
+
+int igraph_i_arpack_err_dsaupd(int error) {
+  switch (error) {
+  case  1:      return IGRAPH_ARPACK_MAXIT;
+  case  3:      return IGRAPH_ARPACK_NOSHIFT;
+  case -1:      return IGRAPH_ARPACK_NPOS;
+  case -2:      return IGRAPH_ARPACK_NEVNPOS;
+  case -3:      return IGRAPH_ARPACK_NCVSMALL;
+  case -4:      return IGRAPH_ARPACK_NONPOSI;
+  case -5:      return IGRAPH_ARPACK_WHICHINV;
+  case -6:      return IGRAPH_ARPACK_BMATINV;
+  case -7:      return IGRAPH_ARPACK_WORKLSMALL;
+  case -8:      return IGRAPH_ARPACK_TRIDERR;
+  case -9:      return IGRAPH_ARPACK_ZEROSTART;
+  case -10:     return IGRAPH_ARPACK_MODEINV;
+  case -11:     return IGRAPH_ARPACK_MODEBMAT;
+  case -12:     return IGRAPH_ARPACK_ISHIFT;
+  case -13:     return IGRAPH_ARPACK_NEVBE;
+  case -9999:   return IGRAPH_ARPACK_NOFACT;
+  default:      return IGRAPH_ARPACK_UNKNOWN;
+  }
+}
+
+int igraph_i_arpack_err_dseupd(int error) {
+  switch (error) {
+  case -1:      return IGRAPH_ARPACK_NPOS;
+  case -2:      return IGRAPH_ARPACK_NEVNPOS;
+  case -3:      return IGRAPH_ARPACK_NCVSMALL;
+  case -5:      return IGRAPH_ARPACK_WHICHINV;
+  case -6:      return IGRAPH_ARPACK_BMATINV;
+  case -7:      return IGRAPH_ARPACK_WORKLSMALL;
+  case -8:      return IGRAPH_ARPACK_TRIDERR;
+  case -9:      return IGRAPH_ARPACK_ZEROSTART;
+  case -10:     return IGRAPH_ARPACK_MODEINV;
+  case -11:     return IGRAPH_ARPACK_MODEBMAT;
+  case -12:     return IGRAPH_ARPACK_NEVBE;
+  case -14:     return IGRAPH_ARPACK_FAILED;
+  case -15:     return IGRAPH_ARPACK_HOWMNY;
+  case -16:     return IGRAPH_ARPACK_HOWMNYS;
+  case -17:     return IGRAPH_ARPACK_EVDIFF;
+  default:      return IGRAPH_ARPACK_UNKNOWN;
+  }
+  
+}
+
+int igraph_i_arpack_err_dnaupd(int error) {
+  switch (error) {
+  case  1:      return IGRAPH_ARPACK_MAXIT;
+  case  3:      return IGRAPH_ARPACK_NOSHIFT;
+  case -1:      return IGRAPH_ARPACK_NPOS;
+  case -2:      return IGRAPH_ARPACK_NEVNPOS;
+  case -3:      return IGRAPH_ARPACK_NCVSMALL;
+  case -4:      return IGRAPH_ARPACK_NONPOSI;
+  case -5:      return IGRAPH_ARPACK_WHICHINV;
+  case -6:      return IGRAPH_ARPACK_BMATINV;
+  case -7:      return IGRAPH_ARPACK_WORKLSMALL;
+  case -8:      return IGRAPH_ARPACK_TRIDERR;
+  case -9:      return IGRAPH_ARPACK_ZEROSTART;
+  case -10:     return IGRAPH_ARPACK_MODEINV;
+  case -11:     return IGRAPH_ARPACK_MODEBMAT;
+  case -12:     return IGRAPH_ARPACK_ISHIFT;
+  case -9999:   return IGRAPH_ARPACK_NOFACT;
+  default:      return IGRAPH_ARPACK_UNKNOWN;
+  }
+}
+
+int igraph_i_arpack_err_dneupd(int error) {
+  switch (error) {
+  case  1:      return IGRAPH_ARPACK_REORDER;
+  case -1:      return IGRAPH_ARPACK_NPOS;
+  case -2:      return IGRAPH_ARPACK_NEVNPOS;
+  case -3:      return IGRAPH_ARPACK_NCVSMALL;
+  case -5:      return IGRAPH_ARPACK_WHICHINV;
+  case -6:      return IGRAPH_ARPACK_BMATINV;
+  case -7:      return IGRAPH_ARPACK_WORKLSMALL;
+  case -8:      return IGRAPH_ARPACK_SHUR;
+  case -9:      return IGRAPH_ARPACK_LAPACK;
+  case -10:     return IGRAPH_ARPACK_MODEINV;
+  case -11:     return IGRAPH_ARPACK_MODEBMAT;
+  case -12:     return IGRAPH_ARPACK_HOWMNYS;
+  case -13:     return IGRAPH_ARPACK_HOWMNY;
+  case -14:     return IGRAPH_ARPACK_FAILED;
+  case -15:     return IGRAPH_ARPACK_EVDIFF;
+  default:      return IGRAPH_ARPACK_UNKNOWN;
+  }
+}
+
+/**
+ * \function igraph_arpack_options_init
+ * Initialize ARPACK options
+ *
+ * Initializes ARPACK options, set them to default values.
+ * You can always pass the initialized \ref igraph_arpack_options_t
+ * object to built-in igraph functions without any modification. The
+ * built-in igraph functions modify the options to perform their
+ * calculation, e.g. \ref igraph_pagerank() always searches for the
+ * eigenvalue with the largest magnitude, regardless of the supplied
+ * value.
+ * </para><para>
+ * If you want to implement your own function involving eigenvalue
+ * calculation using ARPACK, however, you will likely need to set up
+ * the fields for yourself.
+ * \param o The \ref igraph_arpack_options_t object to initialize.
+ *
+ * Time complexity: O(1).
+ */
+
+void igraph_arpack_options_init(igraph_arpack_options_t *o) {
+  o->bmat[0]='I';
+  o->n=0;			/* needs to be updated! */
+  o->which[0]='X'; o->which[1]='X';
+  o->nev=1;
+  o->tol=0;
+  o->ncv=0;         /* 0 means "automatic" */
+  o->ldv=o->n;			/* will be updated to (real) n */
+  o->ishift=1;
+  o->mxiter=3000;
+  o->nb=1;
+  o->mode=1;
+  o->start=0;
+  o->lworkl=0;
+  o->sigma=0;
+  o->sigmai=0;
+  o->info=o->start;
+  
+  o->iparam[0]=o->ishift; o->iparam[1]=0; o->iparam[2]=o->mxiter; o->iparam[3]=o->nb;
+  o->iparam[4]=0; o->iparam[5]=0; o->iparam[6]=o->mode; o->iparam[7]=0;
+  o->iparam[8]=0; o->iparam[9]=0; o->iparam[10]=0;
+}
+
+/**
+ * \function igraph_arpack_storage_init
+ * Initialize ARPACK storage
+ *
+ * You only need this function if you want to run multiple eigenvalue
+ * calculations using ARPACK, and want to spare the memory
+ * allocation/deallocation between each two runs. Otherwise it is safe
+ * to supply a null pointer as the \c storage argument of both \ref
+ * igraph_arpack_rssolve() and \ref igraph_arpack_rnsolve() to make
+ * memory allocated and deallocated automatically.
+ *
+ * </para><para>Don't forget to call the \ref
+ * igraph_arpack_storage_destroy() function on the storage object if
+ * you don't need it any more.
+ * \param s The \ref igraph_arpack_storage_t object to initialize.
+ * \param maxn The maximum order of the matrices.
+ * \param maxncv The maximum NCV parameter intended to use.
+ * \param maxldv The maximum LDV parameter intended to use.
+ * \param symm Whether symmetric or non-symmetric problems will be
+ *    solved using this \ref igraph_arpack_storage_t. (You cannot use
+ *    the same storage both with symmetric and non-symmetric solvers.)
+ * \return Error code.
+ *
+ * Time complexity: O(maxncv*(maxldv+maxn)).
+ */
+
+int igraph_arpack_storage_init(igraph_arpack_storage_t *s, long int maxn,
+			       long int maxncv, long int maxldv,
+			       igraph_bool_t symm) {
+  
+  /* TODO: check arguments */
+  s->maxn=(int) maxn;
+  s->maxncv=(int) maxncv;
+  s->maxldv=(int) maxldv;
+
+#define CHECKMEM(x) \
+    if (!x) { \
+      IGRAPH_ERROR("Cannot allocate memory for ARPACK", IGRAPH_ENOMEM); \
+    } \
+    IGRAPH_FINALLY(igraph_free, x);
+
+  s->v=igraph_Calloc(maxldv * maxncv, igraph_real_t); CHECKMEM(s->v);
+  s->workd=igraph_Calloc(3*maxn, igraph_real_t); CHECKMEM(s->workd);
+  s->d=igraph_Calloc(2*maxncv, igraph_real_t); CHECKMEM(s->d);
+  s->resid=igraph_Calloc(maxn, igraph_real_t); CHECKMEM(s->resid);
+  s->ax=igraph_Calloc(maxn, igraph_real_t); CHECKMEM(s->ax);
+  s->select=igraph_Calloc(maxncv, int); CHECKMEM(s->select);
+
+  if (symm) {
+    s->workl=igraph_Calloc(maxncv*(maxncv+8), igraph_real_t); CHECKMEM(s->workl);
+    s->di=0;
+    s->workev=0;
+  } else {
+    s->workl=igraph_Calloc(3*maxncv*(maxncv+2), igraph_real_t); CHECKMEM(s->workl);
+    s->di=igraph_Calloc(2*maxncv, igraph_real_t); CHECKMEM(s->di);
+    s->workev=igraph_Calloc(3*maxncv, igraph_real_t); CHECKMEM(s->workev);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+#undef CHECKMEM
+  
+  IGRAPH_FINALLY_CLEAN(7);
+  return 0;
+}
+
+/**
+ * \function igraph_arpack_storage_destroy
+ * Deallocate ARPACK storage
+ *
+ * \param s The \ref igraph_arpack_storage_t object for which the
+ *    memory will be deallocated.
+ *
+ * Time complexity: operating system dependent.
+ */
+
+void igraph_arpack_storage_destroy(igraph_arpack_storage_t *s) {
+  
+  if (s->di) {
+    igraph_Free(s->di);
+  }
+  if (s->workev) {
+    igraph_Free(s->workev);
+  }
+  
+  igraph_Free(s->workl);
+  igraph_Free(s->select);
+  igraph_Free(s->ax);
+  igraph_Free(s->resid);
+  igraph_Free(s->d);
+  igraph_Free(s->workd);
+  igraph_Free(s->v);
+}
+
+/**
+ * "Solver" for 1x1 eigenvalue problems since ARPACK sometimes blows up with
+ * these.
+ */
+int igraph_i_arpack_rssolve_1x1(igraph_arpack_function_t *fun, void *extra,
+        igraph_arpack_options_t* options,
+        igraph_vector_t* values, igraph_matrix_t* vectors) {
+  igraph_real_t a, b;
+  int nev = options->nev;
+
+  if (nev <= 0) {
+    IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS);
+  }
+
+  /* Probe the value in the matrix */
+  a = 1;
+  if (fun(&b, &a, 1, extra)) {
+	  IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+  }
+
+  options->nconv=nev;
+
+  if (values != 0) {
+    IGRAPH_CHECK(igraph_vector_resize(values, 1));
+    VECTOR(*values)[0] = b;
+  }
+
+  if (vectors != 0) {
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, 1, 1));
+    MATRIX(*vectors, 0, 0) = 1;
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * "Solver" for 1x1 eigenvalue problems since ARPACK sometimes blows up with
+ * these.
+ */
+int igraph_i_arpack_rnsolve_1x1(igraph_arpack_function_t *fun, void *extra,
+        igraph_arpack_options_t* options,
+        igraph_matrix_t* values, igraph_matrix_t* vectors) {
+  igraph_real_t a, b;
+  int nev = options->nev;
+
+  if (nev <= 0) {
+    IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS);
+  }
+
+  /* Probe the value in the matrix */
+  a = 1;
+  if (fun(&b, &a, 1, extra)) {
+	  IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+  }
+
+  options->nconv=nev;
+
+  if (values != 0) {
+    IGRAPH_CHECK(igraph_matrix_resize(values, 1, 2));
+    MATRIX(*values, 0, 0) = b; MATRIX(*values, 0, 1) = 0;
+  }
+
+  if (vectors != 0) {
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, 1, 1));
+    MATRIX(*vectors, 0, 0) = 1; 
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * "Solver" for 2x2 nonsymmetric eigenvalue problems since ARPACK sometimes
+ * blows up with these.
+ */
+int igraph_i_arpack_rnsolve_2x2(igraph_arpack_function_t *fun, void *extra,
+        igraph_arpack_options_t* options, igraph_matrix_t* values,
+        igraph_matrix_t* vectors) {
+  igraph_real_t vec[2], mat[4];
+  igraph_real_t a, b, c, d;
+  igraph_real_t trace, det, tsq4_minus_d;
+  igraph_complex_t eval1, eval2;
+  igraph_complex_t evec1[2], evec2[2];
+  igraph_bool_t swap_evals = 0;
+  igraph_bool_t complex_evals = 0;
+  int nev = options->nev;
+
+  if (nev <= 0) {
+    IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS);
+  }
+  if (nev > 2)
+    nev = 2;
+
+  /* Probe the values in the matrix */
+  vec[0] = 1; vec[1] = 0;
+  if (fun(mat, vec, 2, extra)) {
+	  IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+  }
+  vec[0] = 0; vec[1] = 1;
+  if (fun(mat+2, vec, 2, extra)) {
+	  IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+  }
+  a = mat[0]; b = mat[2]; c = mat[1]; d = mat[3];
+
+  /* Get the trace and the determinant */
+  trace = a+d;
+  det = a*d - b*c;
+  tsq4_minus_d = trace*trace / 4 - det;
+
+  /* Calculate the eigenvalues */
+  complex_evals = tsq4_minus_d < 0;
+  eval1 = igraph_complex_sqrt_real(tsq4_minus_d);
+  if (complex_evals) {
+    eval2 = igraph_complex_mul_real(eval1, -1);
+  } else {
+    /* to avoid having -0 in the imaginary part */
+    eval2 = igraph_complex(-IGRAPH_REAL(eval1), 0);
+  }
+  eval1 = igraph_complex_add_real(eval1, trace/2);
+  eval2 = igraph_complex_add_real(eval2, trace/2);
+
+  if (c != 0) {
+    evec1[0] = igraph_complex_sub_real(eval1, d);
+    evec1[1] = igraph_complex(c, 0);
+    evec2[0] = igraph_complex_sub_real(eval2, d);
+    evec2[1] = igraph_complex(c, 0);
+  } else if (b != 0) {
+    evec1[0] = igraph_complex(b, 0);
+    evec1[1] = igraph_complex_sub_real(eval1, a);
+    evec2[0] = igraph_complex(b, 0);
+    evec2[1] = igraph_complex_sub_real(eval2, a);
+  } else {
+    evec1[0] = igraph_complex(1, 0);
+    evec1[1] = igraph_complex(0, 0);
+    evec2[0] = igraph_complex(0, 0);
+    evec2[1] = igraph_complex(1, 0);
+  }
+
+  /* Sometimes we have to swap eval1 with eval2 and evec1 with eval2;
+   * determine whether we have to do it now */
+  if (options->which[0] == 'S') {
+    if (options->which[1] == 'M') {
+      /* eval1 must be the one with the smallest magnitude */
+      swap_evals = (igraph_complex_mod(eval1) > igraph_complex_mod(eval2));
+    } else if (options->which[1] == 'R') {
+      /* eval1 must be the one with the smallest real part */
+      swap_evals = (IGRAPH_REAL(eval1) > IGRAPH_REAL(eval2));
+    } else if (options->which[1] == 'I') {
+      /* eval1 must be the one with the smallest imaginary part */
+      swap_evals = (IGRAPH_IMAG(eval1) > IGRAPH_IMAG(eval2));
+    } else {
+      IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV);
+    }
+  } else if (options->which[0] == 'L') {
+    if (options->which[1] == 'M') {
+      /* eval1 must be the one with the largest magnitude */
+      swap_evals = (igraph_complex_mod(eval1) < igraph_complex_mod(eval2));
+    } else if (options->which[1] == 'R') {
+      /* eval1 must be the one with the largest real part */
+      swap_evals = (IGRAPH_REAL(eval1) < IGRAPH_REAL(eval2));
+    } else if (options->which[1] == 'I') {
+      /* eval1 must be the one with the largest imaginary part */
+      swap_evals = (IGRAPH_IMAG(eval1) < IGRAPH_IMAG(eval2));
+    } else {
+      IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV);
+    }
+  } else if (options->which[0] == 'X' && options->which[1] == 'X') {
+    /* No preference on the ordering of eigenvectors */
+  } else {
+    /* fprintf(stderr, "%c%c\n", options->which[0], options->which[1]); */
+    IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV);
+  }
+
+  options->nconv=nev;
+
+  if (swap_evals) {
+    igraph_complex_t dummy;
+    dummy = eval1; eval1 = eval2; eval2 = dummy;
+    dummy = evec1[0]; evec1[0] = evec2[0]; evec2[0] = dummy;
+    dummy = evec1[1]; evec1[1] = evec2[1]; evec2[1] = dummy;
+  }
+
+  if (complex_evals) {
+    /* The eigenvalues are conjugate pairs, so we store only the
+     * one with positive imaginary part */
+    if (IGRAPH_IMAG(eval1) < 0) {
+      eval1 = eval2;
+      evec1[0] = evec2[0]; evec1[1] = evec2[1];
+    }
+  }
+
+  if (values != 0) {
+    IGRAPH_CHECK(igraph_matrix_resize(values, nev, 2));
+    MATRIX(*values, 0, 0) = IGRAPH_REAL(eval1);
+    MATRIX(*values, 0, 1) = IGRAPH_IMAG(eval1);
+    if (nev > 1) {
+      MATRIX(*values, 1, 0) = IGRAPH_REAL(eval2);
+      MATRIX(*values, 1, 1) = IGRAPH_IMAG(eval2);
+    }
+  }
+
+  if (vectors != 0) {
+    if (complex_evals) {
+      IGRAPH_CHECK(igraph_matrix_resize(vectors, 2, 2));
+      MATRIX(*vectors, 0, 0) = IGRAPH_REAL(evec1[0]);
+      MATRIX(*vectors, 1, 0) = IGRAPH_REAL(evec1[1]);
+      MATRIX(*vectors, 0, 1) = IGRAPH_IMAG(evec1[0]);
+      MATRIX(*vectors, 1, 1) = IGRAPH_IMAG(evec1[1]);
+    } else {
+      IGRAPH_CHECK(igraph_matrix_resize(vectors, 2, nev));
+      MATRIX(*vectors, 0, 0) = IGRAPH_REAL(evec1[0]);
+      MATRIX(*vectors, 1, 0) = IGRAPH_REAL(evec1[1]);
+      if (nev > 1) {
+        MATRIX(*vectors, 0, 1) = IGRAPH_REAL(evec2[0]);
+        MATRIX(*vectors, 1, 1) = IGRAPH_REAL(evec2[1]);
+      }
+    }
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * "Solver" for symmetric 2x2 eigenvalue problems since ARPACK sometimes blows
+ * up with these.
+ */
+int igraph_i_arpack_rssolve_2x2(igraph_arpack_function_t *fun, void *extra,
+        igraph_arpack_options_t* options, igraph_vector_t* values,
+        igraph_matrix_t* vectors) {
+  igraph_real_t vec[2], mat[4];
+  igraph_real_t a, b, c, d;
+  igraph_real_t trace, det, tsq4_minus_d;
+  igraph_real_t eval1, eval2;
+  int nev = options->nev;
+
+  if (nev <= 0) {
+    IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS);
+  }
+  if (nev > 2)
+    nev = 2;
+
+  /* Probe the values in the matrix */
+  vec[0] = 1; vec[1] = 0;
+  if (fun(mat, vec, 2, extra)) {
+	  IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+  }
+  vec[0] = 0; vec[1] = 1;
+  if (fun(mat+2, vec, 2, extra)) {
+	  IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+  }
+  a = mat[0]; b = mat[2]; c = mat[1]; d = mat[3];
+
+  /* Get the trace and the determinant */
+  trace = a+d;
+  det = a*d - b*c;
+  tsq4_minus_d = trace*trace / 4 - det;
+
+  if (tsq4_minus_d >= 0) {
+    /* Both eigenvalues are real */
+    eval1 = trace/2 + sqrt(tsq4_minus_d);
+    eval2 = trace/2 - sqrt(tsq4_minus_d);
+    if (c != 0) {
+      mat[0] = eval1-d; mat[2] = eval2-d;
+      mat[1] = c;       mat[3] = c;
+    } else if (b != 0) {
+      mat[0] = b;       mat[2] = b;
+      mat[1] = eval1-a; mat[3] = eval2-a;
+    } else {
+      mat[0] = 1; mat[2] = 0;
+      mat[1] = 0; mat[3] = 1;
+    }
+  } else {
+    /* Both eigenvalues are complex. Should not happen with symmetric
+     * matrices. */
+    IGRAPH_ERROR("ARPACK error, 2x2 matrix is not symmetric", IGRAPH_EINVAL);
+  }
+
+  /* eval1 is always the larger eigenvalue. If we want the smaller
+   * one, we have to swap eval1 with eval2 and also the columns of mat */
+  if (options->which[0] == 'S') {
+    trace = eval1; eval1 = eval2; eval2 = trace;
+    trace = mat[0]; mat[0] = mat[2]; mat[2] = trace;
+    trace = mat[1]; mat[1] = mat[3]; mat[3] = trace;
+  } else if (options->which[0] == 'L' || options->which[0] == 'B') {
+    /* Nothing to do here */
+  } else if (options->which[0] == 'X' && options->which[1] == 'X') {
+    /* No preference on the ordering of eigenvectors */
+  } else {
+    IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV);
+  }
+
+  options->nconv=nev;
+
+  if (values != 0) {
+    IGRAPH_CHECK(igraph_vector_resize(values, nev));
+    VECTOR(*values)[0] = eval1;
+    if (nev > 1) {
+      VECTOR(*values)[1] = eval2;
+    }
+  }
+
+  if (vectors != 0) {
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, 2, nev));
+    MATRIX(*vectors, 0, 0) = mat[0];
+    MATRIX(*vectors, 1, 0) = mat[1];
+    if (nev > 1) {
+      MATRIX(*vectors, 0, 1) = mat[2];
+      MATRIX(*vectors, 1, 1) = mat[3];
+    }
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_arpack_rssort(igraph_vector_t *values, igraph_matrix_t *vectors,
+			 const igraph_arpack_options_t *options, 
+			 igraph_real_t *d, const igraph_real_t *v) {
+
+  igraph_vector_t order;
+  char sort[2];
+  int apply=1;
+  unsigned int n=(unsigned int) options->n;
+  int nconv=options->nconv;
+  int nev=options->nev;
+  unsigned int nans= (unsigned int) (nconv < nev ? nconv : nev);
+
+#define which(a,b) (options->which[0]==a && options->which[1]==b)
+
+  if (which('L','A')) {
+    sort[0]='S'; sort[1]='A';
+  } else if (which('S','A')) {
+    sort[0]='L'; sort[1]='A';
+  } else if (which('L','M')) {
+    sort[0]='S'; sort[1]='M';
+  } else if (which('S','M')) {
+    sort[0]='L'; sort[1]='M';
+  } else if (which('B','E')) {
+    sort[0]='L'; sort[1]='A';
+  }
+
+  IGRAPH_CHECK(igraph_vector_init_seq(&order, 0, nconv-1));
+  IGRAPH_FINALLY(igraph_vector_destroy, &order);
+#ifdef HAVE_GFORTRAN
+  igraphdsortr_(sort, &apply, &nconv, d, VECTOR(order), /*which_len=*/ 2);
+#else
+  igraphdsortr_(sort, &apply, &nconv, d, VECTOR(order));
+#endif
+
+  /* BE is special */
+  if (which('B','E')) {
+    int w=0, l1=0, l2=nev-1;
+    igraph_vector_t order2, d2;
+    IGRAPH_VECTOR_INIT_FINALLY(&order2, nev);
+    IGRAPH_VECTOR_INIT_FINALLY(&d2, nev);
+    while (l1 <= l2) {
+      VECTOR(order2)[w] = VECTOR(order)[l1]; 
+      VECTOR(d2)[w]=d[l1]; 
+      w++; l1++;
+      if (l1 <= l2) {
+	VECTOR(order2)[w] = VECTOR(order)[l2]; 
+	VECTOR(d2)[w]=d[l2]; 
+	w++; l2--;
+      }
+    }
+    igraph_vector_update(&order, &order2);
+    igraph_vector_copy_to(&d2, d);
+    igraph_vector_destroy(&order2);
+    igraph_vector_destroy(&d2);
+    IGRAPH_FINALLY_CLEAN(2);  
+  }
+
+#undef which
+
+  /* Copy values */
+  if (values) { 
+    IGRAPH_CHECK(igraph_vector_resize(values, nans));
+    memcpy(VECTOR(*values), d, sizeof(igraph_real_t) * nans);
+  }
+
+  /* Reorder vectors */
+  if (vectors) {
+    int i;
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, n, nans));
+    for (i=0; i<nans; i++) { 
+      unsigned int idx=(unsigned int) VECTOR(order)[i];
+      const igraph_real_t *ptr=v + n * idx;
+      memcpy(&MATRIX(*vectors, 0, i), ptr, sizeof(igraph_real_t) * n);
+    }
+  }
+  
+  igraph_vector_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_arpack_rnsort(igraph_matrix_t *values, igraph_matrix_t *vectors,
+			 const igraph_arpack_options_t *options, 
+			 igraph_real_t *dr, igraph_real_t *di, 
+			 igraph_real_t *v) {
+
+  igraph_vector_t order;
+  char sort[2];
+  int apply=1;
+  unsigned int n=(unsigned int) options->n;
+  int nconv=options->nconv;
+  int nev=options->nev;
+  unsigned int nans=(unsigned int) (nconv < nev ? nconv : nev);
+
+#define which(a,b) (options->which[0]==a && options->which[1]==b)
+
+  if (which('L','M')) {
+    sort[0]='S'; sort[1]='M';
+  } else if (which('S', 'M')) {
+    sort[0]='L'; sort[1]='M';
+  } else if (which('L', 'R')) {
+    sort[0]='S'; sort[1]='R';
+  } else if (which('S', 'R')) {
+    sort[0]='L'; sort[1]='R';
+  } else if (which('L', 'I')) {
+    sort[0]='S'; sort[1]='I';
+  } else if (which('S', 'I')) {
+    sort[0]='L'; sort[1]='I';
+  }
+
+#undef which
+  
+  IGRAPH_CHECK(igraph_vector_init_seq(&order, 0, nconv-1));
+  IGRAPH_FINALLY(igraph_vector_destroy, &order);
+#ifdef HAVE_GFORTRAN
+  igraphdsortc_(sort, &apply, &nconv, dr, di, VECTOR(order), /*which_len=*/ 2);
+#else
+  igraphdsortc_(sort, &apply, &nconv, dr, di, VECTOR(order));
+#endif
+
+  if (values) {
+    IGRAPH_CHECK(igraph_matrix_resize(values, nans, 2));
+    memcpy(&MATRIX(*values, 0, 0), dr, sizeof(igraph_real_t) * nans);
+    memcpy(&MATRIX(*values, 0, 1), di, sizeof(igraph_real_t) * nans);
+  }
+
+  if (vectors) {
+    int i, nc=0, nr=0, ncol, wh=0, vx=0;
+    for (i=0; i<nans; i++) {
+      if (di[i] == 0) { nr++; } else { nc++; }
+    }
+    ncol=(nc/2)*2 + (nc%2)*2 + nr;
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, n, ncol));
+    for (i=0; i<nans; i++) {
+      unsigned int idx=(unsigned int) VECTOR(order)[i];
+      igraph_real_t *ptr=v + n * idx;
+      if (di[i]==0) {
+	memcpy(&MATRIX(*vectors, 0, vx), ptr, sizeof(igraph_real_t) * n);
+	vx++;
+      } else if (wh==0) {
+	if (di[i] < 0) { ptr -= n; }
+	memcpy(&MATRIX(*vectors, 0, vx), ptr, sizeof(igraph_real_t) * n * 2);
+	wh=1-wh;
+	vx+=2;
+      } else {
+	wh=1-wh;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_i_arpack_auto_ncv
+ * \brief Tries to set up the value of \c ncv in an \c igraph_arpack_options_t
+ *        automagically.
+ */
+void igraph_i_arpack_auto_ncv(igraph_arpack_options_t* options) {
+  /* This is similar to how Octave determines the value of ncv, with some
+   * modifications. */
+  int min_ncv = options->nev * 2 + 1;
+
+  /* Use twice the number of desired eigenvectors plus one by default */
+  options->ncv = min_ncv;
+  /* ...but use at least 20 Lanczos vectors... */
+  if (options->ncv < 20) {
+    options->ncv = 20;
+  }
+  /* ...but having ncv close to n leads to some problems with small graphs
+   * (example: PageRank of "A <--> C, D <--> E, B"), so we don't let it
+   * to be larger than n / 2...
+   */
+  if (options->ncv > options->n / 2) {
+    options->ncv = options->n / 2;
+  }
+  /* ...but we need at least min_ncv. */
+  if (options->ncv < min_ncv) {
+    options->ncv = min_ncv;
+  }
+  /* ...but at most n-1 */
+  if (options->ncv > options->n) {
+    options->ncv = options->n;
+  }
+}
+
+/**
+ * \function igraph_i_arpack_report_no_convergence
+ * \brief Prints a warning that informs the user that the ARPACK solver
+ *        did not converge.
+ */
+void igraph_i_arpack_report_no_convergence(const igraph_arpack_options_t* options) {
+  char buf[1024];
+  snprintf(buf, sizeof(buf), "ARPACK solver failed to converge (%d iterations, "
+      "%d/%d eigenvectors converged)", options->iparam[2],
+      options->iparam[4], options->nev);
+  IGRAPH_WARNING(buf);
+}
+
+/**
+ * \function igraph_arpack_rssolve
+ * \brief ARPACK solver for symmetric matrices
+ *
+ * This is the ARPACK solver for symmetric matrices. Please use
+ * \ref igraph_arpack_rnsolve() for non-symmetric matrices.
+ * \param fun Pointer to an \ref igraph_arpack_function_t object,
+ *     the function that performs the matrix-vector multiplication.
+ * \param extra An extra argument to be passed to \c fun.
+ * \param options An \ref igraph_arpack_options_t object.
+ * \param storage An \ref igraph_arpack_storage_t object, or a null
+ *     pointer. In the latter case memory allocation and deallocation
+ *     is performed automatically. Either this or the \p vectors argument 
+ *     must be non-null if the ARPACK iteration is started from a 
+ *     given starting vector. If both are given \p vectors take 
+ *     precedence.
+ * \param values If not a null pointer, then it should be a pointer to an
+ *     initialized vector. The eigenvalues will be stored here. The
+ *     vector will be resized as needed.
+ * \param vectors If not a null pointer, then it must be a pointer to
+ *     an initialized matrix. The eigenvectors will be stored in the
+ *     columns of the matrix. The matrix will be resized as needed.
+ *     Either this or the \p vectors argument must be non-null if the
+ *     ARPACK iteration is started from a given starting vector. If
+ *     both are given \p vectors take precedence.
+ * \return Error code.
+ *
+ * Time complexity: depends on the matrix-vector
+ * multiplication. Usually a small number of iterations is enough, so
+ * if the matrix is sparse and the matrix-vector multiplication can be
+ * done in O(n) time (the number of vertices), then the eigenvalues
+ * are found in O(n) time as well.
+ */
+
+int igraph_arpack_rssolve(igraph_arpack_function_t *fun, void *extra,
+			  igraph_arpack_options_t *options,
+			  igraph_arpack_storage_t *storage,
+			  igraph_vector_t *values, igraph_matrix_t *vectors) {
+  
+  igraph_real_t *v, *workl, *workd, *d, *resid, *ax;
+  igraph_bool_t free_them=0;
+  int *select, i;
+
+  int ido=0;
+  int rvec= vectors || storage ? 1 : 0;	/* calculate eigenvectors? */
+  char *all="All";
+
+  int origldv=options->ldv, origlworkl=options->lworkl,
+    orignev=options->nev, origncv=options->ncv;
+  char origwhich[2]={ options->which[0], options->which[1] };
+  igraph_real_t origtol=options->tol;
+
+  /* Special case for 1x1 and 2x2 matrices */
+  if (options->n == 1) {
+    return igraph_i_arpack_rssolve_1x1(fun, extra, options, values, vectors);
+  } else if (options->n == 2) {
+    return igraph_i_arpack_rssolve_2x2(fun, extra, options, values, vectors);
+  }
+
+  /* Brush up options if needed */
+  if (options->ldv == 0) { options->ldv=options->n; }
+  if (options->ncv == 0) {
+		igraph_i_arpack_auto_ncv(options);
+  }
+  if (options->lworkl == 0) { options->lworkl=options->ncv*(options->ncv+8); }
+  if (options->which[0] == 'X') { options->which[0]='L'; options->which[1]='M'; }
+  
+  if (storage) {
+    /* Storage provided */
+    if (storage->maxn < options->n) {
+      IGRAPH_ERROR("Not enough storage for ARPACK (`n')", IGRAPH_EINVAL);
+    }
+    if (storage->maxncv < options->ncv) {
+      IGRAPH_ERROR("Not enough storage for ARPACK (`ncv')", IGRAPH_EINVAL);
+    }
+    if (storage->maxldv < options->ldv) {
+      IGRAPH_ERROR("Not enough storage for ARPACK (`ldv')", IGRAPH_EINVAL);
+    }
+
+    v      = storage->v;
+    workl  = storage->workl;
+    workd  = storage->workd;
+    d      = storage->d;
+    resid  = storage->resid;
+    ax     = storage->ax;
+    select = storage->select;
+    
+  } else {
+    /* Storage not provided */
+    free_them=1;
+    
+#define CHECKMEM(x) \
+    if (!x) { \
+      IGRAPH_ERROR("Cannot allocate memory for ARPACK", IGRAPH_ENOMEM); \
+    } \
+    IGRAPH_FINALLY(igraph_free, x);
+
+    v=igraph_Calloc(options->ldv * options->ncv, igraph_real_t); CHECKMEM(v);
+    workl=igraph_Calloc(options->lworkl, igraph_real_t); CHECKMEM(workl);
+    workd=igraph_Calloc(3*options->n, igraph_real_t); CHECKMEM(workd);
+    d=igraph_Calloc(2*options->ncv, igraph_real_t); CHECKMEM(d);
+    resid=igraph_Calloc(options->n, igraph_real_t); CHECKMEM(resid);
+    ax=igraph_Calloc(options->n, igraph_real_t); CHECKMEM(ax);
+    select=igraph_Calloc(options->ncv, int); CHECKMEM(select);
+
+#undef CHECKMEM
+
+  }
+
+  /* Set final bits */
+  options->iparam[0]=options->ishift;
+  options->iparam[2]=options->mxiter;
+  options->iparam[3]=options->nb;
+  options->iparam[4]=0;
+  options->iparam[6]=options->mode;
+  options->info=options->start;
+  if (options->start) {
+    if (!storage && !vectors) {
+      IGRAPH_ERROR("Starting vector not given", IGRAPH_EINVAL);
+    }
+    if (vectors && (igraph_matrix_nrow(vectors) != options->n || 
+		    igraph_matrix_ncol(vectors) != 1)) {
+      IGRAPH_ERROR("Invalid starting vector size", IGRAPH_EINVAL);
+    }
+    if (vectors) {
+      for (i=0; i<options->n; i++) {
+	resid[i]=MATRIX(*vectors, i, 0);
+      }
+    }
+  }
+
+  /* Ok, we have everything */
+  while (1) {
+#ifdef HAVE_GFORTRAN
+    igraphdsaupd_(&ido, options->bmat, &options->n, options->which,
+		  &options->nev, &options->tol,
+		  resid, &options->ncv, v, &options->ldv,
+		  options->iparam, options->ipntr,
+		  workd, workl, &options->lworkl, &options->info,
+		  /*bmat_len=*/ 1, /*which_len=*/ 2);
+#else
+    igraphdsaupd_(&ido, options->bmat, &options->n, options->which,
+    		  &options->nev, &options->tol,
+    		  resid, &options->ncv, v, &options->ldv,
+    		  options->iparam, options->ipntr,
+    		  workd, workl, &options->lworkl, &options->info);
+#endif
+
+    if (ido==-1 || ido==1) {
+      igraph_real_t *from=workd+options->ipntr[0]-1;
+      igraph_real_t *to=workd+options->ipntr[1]-1;
+      if (fun(to, from, options->n, extra) != 0) {
+	IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+      }
+      
+    } else {
+      break;
+    }
+  }
+  
+  if (options->info == 1) {
+    igraph_i_arpack_report_no_convergence(options);
+  }
+  if (options->info != 0) {
+    IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dsaupd(options->info));
+  }
+  
+  options->ierr=0;
+#ifdef HAVE_GFORTRAN
+  igraphdseupd_(&rvec, all, select, d, v, &options->ldv,
+		&options->sigma, options->bmat, &options->n,
+		options->which, &options->nev, &options->tol,
+		resid, &options->ncv, v, &options->ldv, options->iparam,
+		options->ipntr, workd, workl, &options->lworkl,
+		&options->ierr, /*howmny_len=*/ 1, /*bmat_len=*/ 1,
+		/*which_len=*/ 2);
+#else
+  igraphdseupd_(&rvec, all, select, d, v, &options->ldv,
+  		&options->sigma, options->bmat, &options->n,
+  		options->which, &options->nev, &options->tol,
+  		resid, &options->ncv, v, &options->ldv, options->iparam,
+  		options->ipntr, workd, workl, &options->lworkl,
+  		&options->ierr);
+#endif
+
+  if (options->ierr != 0) {
+    IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dseupd(options->ierr));
+  }
+  
+  /* Save the result */
+  
+  options->noiter=options->iparam[2];
+  options->nconv=options->iparam[4];
+  options->numop=options->iparam[8];
+  options->numopb=options->iparam[9];
+  options->numreo=options->iparam[10];
+
+  if (options->nconv < options->nev) {
+    IGRAPH_WARNING("Not enough eigenvalues/vectors in symmetric ARPACK "
+		   "solver");
+  }
+
+  if (values || vectors) { 
+    IGRAPH_CHECK(igraph_arpack_rssort(values, vectors, options, d, v));
+  }
+  
+  options->ldv=origldv;
+  options->ncv=origncv;
+  options->lworkl=origlworkl;
+  options->which[0] = origwhich[0]; options->which[1] = origwhich[1];
+  options->tol=origtol;
+  options->nev=orignev;
+    
+  /* Clean up if needed */
+  if (free_them) {
+    igraph_Free(select);
+    igraph_Free(ax);
+    igraph_Free(resid);
+    igraph_Free(d);
+    igraph_Free(workd);
+    igraph_Free(workl);
+    igraph_Free(v);
+    IGRAPH_FINALLY_CLEAN(7);
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_arpack_rnsolve
+ * \brief ARPACK solver for non-symmetric matrices
+ *
+ * Please always consider calling \ref igraph_arpack_rssolve() if your
+ * matrix is symmetric, it is much faster.
+ * \ref igraph_arpack_rnsolve() for non-symmetric matrices.
+ * </para><para>
+ * Note that ARPACK is not called for 2x2 matrices as an exact algebraic
+ * solution exists in these cases.
+ *
+ * \param fun Pointer to an \ref igraph_arpack_function_t object,
+ *     the function that performs the matrix-vector multiplication.
+ * \param extra An extra argument to be passed to \c fun.
+ * \param options An \ref igraph_arpack_options_t object.
+ * \param storage An \ref igraph_arpack_storage_t object, or a null
+ *     pointer. In the latter case memory allocation and deallocation
+ *     is performed automatically.
+ * \param values If not a null pointer, then it should be a pointer to an
+ *     initialized matrix. The (possibly complex) eigenvalues will be
+ *     stored here. The matrix will have two columns, the first column
+ *     contains the real, the second the imaginary parts of the
+ *     eigenvalues.
+ *     The matrix will be resized as needed.
+ * \param vectors If not a null pointer, then it must be a pointer to
+ *     an initialized matrix. The eigenvectors will be stored in the
+ *     columns of the matrix. The matrix will be resized as needed.
+ * \return Error code.
+ *
+ * Time complexity: depends on the matrix-vector
+ * multiplication. Usually a small number of iterations is enough, so
+ * if the matrix is sparse and the matrix-vector multiplication can be
+ * done in O(n) time (the number of vertices), then the eigenvalues
+ * are found in O(n) time as well.
+ */
+
+int igraph_arpack_rnsolve(igraph_arpack_function_t *fun, void *extra,
+			  igraph_arpack_options_t *options,
+			  igraph_arpack_storage_t *storage,
+			  igraph_matrix_t *values, igraph_matrix_t *vectors) {
+
+  igraph_real_t *v, *workl, *workd, *dr, *di, *resid, *workev;
+  igraph_bool_t free_them=0;
+  int *select, i;
+  
+  int ido=0;
+  int rvec= vectors || storage ? 1 : 0;
+  char *all="All";
+  
+  int origldv=options->ldv, origlworkl=options->lworkl,
+    orignev=options->nev, origncv=options->ncv;
+  char origwhich[2]={ options->which[0], options->which[1] };
+  igraph_real_t origtol=options->tol;
+  int d_size;
+
+  /* Special case for 1x1 and 2x2 matrices */
+  if (options->n == 1) {
+    return igraph_i_arpack_rnsolve_1x1(fun, extra, options, values, vectors);
+  } else if (options->n == 2) {
+    return igraph_i_arpack_rnsolve_2x2(fun, extra, options, values, vectors);
+  }
+
+  /* Brush up options if needed */
+  if (options->ldv == 0) { options->ldv=options->n; }
+  if (options->ncv == 0) {
+		igraph_i_arpack_auto_ncv(options);
+  }
+  if (options->lworkl == 0) { options->lworkl=3*options->ncv*(options->ncv+2); }
+  if (options->which[0] == 'X') { options->which[0]='L'; options->which[1]='M'; }
+  
+  if (storage) {
+    /* Storage provided */
+    if (storage->maxn < options->n) {
+      IGRAPH_ERROR("Not enough storage for ARPACK (`n')", IGRAPH_EINVAL);
+    }
+    if (storage->maxncv < options->ncv) {
+      IGRAPH_ERROR("Not enough storage for ARPACK (`ncv')", IGRAPH_EINVAL);
+    }
+    if (storage->maxldv < options->ldv) {
+      IGRAPH_ERROR("Not enough storage for ARPACK (`ldv')", IGRAPH_EINVAL);
+    }
+
+    v      = storage->v;
+    workl  = storage->workl;
+    workd  = storage->workd;
+    workev = storage->workev;
+    dr     = storage->d;
+    di     = storage->di;
+    d_size = options->n;
+    resid  = storage->resid;
+    select = storage->select;
+    
+  } else {
+    /* Storage not provided */
+    free_them=1;
+    
+#define CHECKMEM(x) \
+    if (!x) { \
+      IGRAPH_ERROR("Cannot allocate memory for ARPACK", IGRAPH_ENOMEM); \
+    } \
+    IGRAPH_FINALLY(igraph_free, x);
+
+    v=igraph_Calloc(options->n * options->ncv, igraph_real_t); CHECKMEM(v);
+    workl=igraph_Calloc(options->lworkl, igraph_real_t); CHECKMEM(workl);
+    workd=igraph_Calloc(3*options->n, igraph_real_t); CHECKMEM(workd);
+    d_size = 2*options->nev+1 > options->ncv ? 2*options->nev+1 : options->ncv;
+    dr=igraph_Calloc(d_size, igraph_real_t); CHECKMEM(dr);
+    di=igraph_Calloc(d_size, igraph_real_t); CHECKMEM(di);
+    resid=igraph_Calloc(options->n, igraph_real_t); CHECKMEM(resid);
+    select=igraph_Calloc(options->ncv, int); CHECKMEM(select);
+    workev=igraph_Calloc(3*options->ncv, igraph_real_t); CHECKMEM(workev);
+    
+#undef CHECKMEM
+
+  }
+  
+  /* Set final bits */
+  options->iparam[0]=options->ishift;
+  options->iparam[2]=options->mxiter;
+  options->iparam[3]=options->nb;
+  options->iparam[4]=0;
+  options->iparam[6]=options->mode;
+  options->info=options->start;
+  if (options->start) {
+    if (igraph_matrix_nrow(vectors) != options->n || igraph_matrix_ncol(vectors) != 1) {
+      IGRAPH_ERROR("Invalid starting vector size", IGRAPH_EINVAL);
+    }
+    for (i=0; i<options->n; i++) {
+      resid[i]=MATRIX(*vectors, i, 0);
+    }
+  }
+  
+  /* Ok, we have everything */
+  while (1) {
+#ifdef HAVE_GFORTRAN
+    igraphdnaupd_(&ido, options->bmat, &options->n, options->which,
+		  &options->nev, &options->tol,
+		  resid, &options->ncv, v, &options->ldv,
+		  options->iparam, options->ipntr,
+		  workd, workl, &options->lworkl, &options->info,
+		  /*bmat_len=*/ 1, /*which_len=*/ 2);
+
+#else
+    igraphdnaupd_(&ido, options->bmat, &options->n, options->which,
+    		  &options->nev, &options->tol,
+    		  resid, &options->ncv, v, &options->ldv,
+    		  options->iparam, options->ipntr,
+    		  workd, workl, &options->lworkl, &options->info);
+#endif
+    
+    if (ido==-1 || ido==1) {
+      igraph_real_t *from=workd+options->ipntr[0]-1;
+      igraph_real_t *to=workd+options->ipntr[1]-1;
+      if (fun(to, from, options->n, extra) != 0) {
+	IGRAPH_ERROR("ARPACK error while evaluating matrix-vector product",
+		     IGRAPH_ARPACK_PROD);
+      }
+      
+    } else {
+      break;
+    }
+  }
+
+  if (options->info == 1) {
+    igraph_i_arpack_report_no_convergence(options);
+  }
+  if (options->info != 0) {
+    IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dnaupd(options->info));
+  }
+
+  options->ierr=0;
+#ifdef HAVE_GFORTRAN
+  igraphdneupd_(&rvec, all, select, dr, di, v, &options->ldv,
+		&options->sigma, &options->sigmai, workev, options->bmat,
+		&options->n, options->which, &options->nev, &options->tol,
+		resid, &options->ncv, v, &options->ldv, options->iparam,
+		options->ipntr, workd, workl, &options->lworkl,
+		&options->ierr, /*howmny_len=*/ 1, /*bmat_len=*/ 1,
+		/*which_len=*/ 2);
+#else
+  igraphdneupd_(&rvec, all, select, dr, di, v, &options->ldv,
+  		&options->sigma, &options->sigmai, workev, options->bmat,
+  		&options->n, options->which, &options->nev, &options->tol,
+  		resid, &options->ncv, v, &options->ldv, options->iparam,
+  		options->ipntr, workd, workl, &options->lworkl,
+  		&options->ierr);
+#endif
+
+  if (options->ierr != 0) {
+    IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dneupd(options->info));
+  }
+
+  /* Save the result */
+  
+  options->noiter=options->iparam[2];
+  options->nconv=options->iparam[4];
+  options->numop=options->iparam[8];
+  options->numopb=options->iparam[9];
+  options->numreo=options->iparam[10];
+
+  if (options->nconv < options->nev) {
+    IGRAPH_WARNING("Not enough eigenvalues/vectors in ARPACK "
+		   "solver");
+  }
+
+  if (values || vectors) { 
+    IGRAPH_CHECK(igraph_arpack_rnsort(values, vectors, options,
+				      dr, di, v));
+  }
+
+  options->ldv=origldv;
+  options->ncv=origncv;
+  options->lworkl=origlworkl;
+  options->which[0] = origwhich[0]; options->which[1] = origwhich[1];
+  options->tol=origtol;
+  options->nev=orignev;
+  
+  /* Clean up if needed */
+  if (free_them) {
+    igraph_Free(workev);
+    igraph_Free(select);
+    igraph_Free(resid);
+    igraph_Free(di);
+    igraph_Free(dr);
+    igraph_Free(workd);
+    igraph_Free(workl);
+    igraph_Free(v);
+    IGRAPH_FINALLY_CLEAN(8);
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_arpack_unpack_complex
+ * \brief Make the result of the non-symmetric ARPACK solver more readable
+ *
+ * This function works on the output of \ref igraph_arpack_rnsolve and
+ * brushes it up a bit: it only keeps \p nev eigenvalues/vectors and
+ * every eigenvector is stored in two columns of the \p vectors
+ * matrix.
+ *
+ * </para><para>
+ * The output of the non-symmetric ARPACK solver is somewhat hard to
+ * parse, as real eigenvectors occupy only one column in the matrix,
+ * and the complex conjugate eigenvectors are not stored at all
+ * (usually). The other problem is that the solver might return more
+ * eigenvalues than requested. The common use of this function is to
+ * call it directly after \ref igraph_arpack_rnsolve with its \p
+ * vectors and \p values argument and \c options->nev as \p nev.
+ * \param vectors The eigenvector matrix, as returned by \ref
+ *   igraph_arpack_rnsolve. It will be resized, typically it will be
+ *   larger.
+ * \param values The eigenvalue matrix, as returned by \ref
+ *   igraph_arpack_rnsolve. It will be resized, typically extra,
+ *   unneeded rows (=eigenvalues) will be removed.
+ * \param nev The number of eigenvalues/vectors to keep. Can be less
+ *   or equal than the number originally requested from ARPACK.
+ * \return Error code.
+ *
+ * Time complexity: linear in the number of elements in the \p vectors
+ * matrix.
+ */
+
+int igraph_arpack_unpack_complex(igraph_matrix_t *vectors, igraph_matrix_t *values,
+				 long int nev) {
+
+  long int nodes=igraph_matrix_nrow(vectors);
+  long int no_evs=igraph_matrix_nrow(values);
+  long int i, j, k, wh;
+  size_t colsize=(unsigned) nodes * sizeof(igraph_real_t);
+
+  /* Error checks */
+  if (nev < 0) {
+    IGRAPH_ERROR("`nev' cannot be negative", IGRAPH_EINVAL);
+  }
+  if (nev > no_evs) {
+    IGRAPH_ERROR("`nev' too large, we don't have that many in `values'",
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_matrix_resize(vectors, nodes, nev * 2));
+  for (i=nev; i<igraph_matrix_nrow(values); i++) {
+    IGRAPH_CHECK(igraph_matrix_remove_row(values, i));
+  }
+  
+  /* Calculate where to start copying */
+  for (i=0, j=0, wh=0; i<nev; i++) {
+    if (MATRIX(*values,i,1) == 0) { /* TODO: == 0.0 ???? */
+      /* real */
+      j++;
+    } else {
+      /* complex */
+      if (wh==0) { j+=2; wh=1-wh; }
+    }
+  }
+  j--;
+
+  /* if (j>=origcol) { */
+  /*   IGRAPH_WARNING("Too few columns in `vectors', ARPACK results are likely wrong"); */
+  /* } */
+
+  /* We copy the j-th eigenvector to the (k-1)-th and k-th column */
+  k=nev*2-1;
+
+  for (i=nev-1; i>=0; i--) {
+    if (MATRIX(*values,i,1)==0) {
+
+      /* real */
+      memset( &MATRIX(*vectors,0,k), 0, colsize);
+      if (k-1 != j) {
+	memcpy( &MATRIX(*vectors,0,k-1), &MATRIX(*vectors,0,j), colsize);
+      }
+      k-=2;
+      j-=1;
+    } else {
+      /* complex */
+      if (k!=j) {
+	/* Separate copy required, otherwise 'from' and 'to' might
+	   overlap */
+	memcpy( &MATRIX(*vectors,0,k), &MATRIX(*vectors,0,j), colsize);
+	memcpy( &MATRIX(*vectors,0,k-1), &MATRIX(*vectors,0,j-1), colsize);
+      }
+      if (i>1 && MATRIX(*values,i,1) != -MATRIX(*values,i-1,1)) {
+	/* The next one is not a conjugate of this one */
+	j-=2;
+      } else {
+	/* Conjugate */
+	int l;
+	for (l=0; l<nodes; l++) {
+	  MATRIX(*vectors,l,k) = - MATRIX(*vectors,l,k);	 
+	}
+      }
+      k-=2;
+    }
+  }
+
+  return 0;
+}
diff --git a/src/array.c b/src/array.c
new file mode 100644
index 0000000..f07e64a
--- /dev/null
+++ b/src/array.c
@@ -0,0 +1,50 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_types.h"
+#include "igraph_vector.h"
+#include "igraph_array.h"
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "array.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "array.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "array.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "array.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
diff --git a/src/array.pmt b/src/array.pmt
new file mode 100644
index 0000000..e16254f
--- /dev/null
+++ b/src/array.pmt
@@ -0,0 +1,90 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_types.h"
+
+int FUNCTION(igraph_array3,init)(TYPE(igraph_array3) *a, long int n1, long int n2, 
+				 long int n3) {
+  int ret;
+  ret=FUNCTION(igraph_vector,init)(&a->data, n1*n2*n3);
+  a->n1=n1;
+  a->n2=n2;
+  a->n3=n3;
+  a->n1n2=n1*n2;
+  
+  return ret;
+}
+
+void FUNCTION(igraph_array3,destroy)(TYPE(igraph_array3) *a) {
+  FUNCTION(igraph_vector,destroy)(&a->data);
+}
+
+long int FUNCTION(igraph_array3,size)(const TYPE(igraph_array3) *a) {
+  return (a->n1n2) * (a->n3);
+}
+
+long int FUNCTION(igraph_array3,n)(const TYPE(igraph_array3) *a, long int idx) {
+  switch (idx) {
+  case 1: return a->n1;
+    break;
+  case 2: return a->n2;
+    break;
+  case 3: return a->n3;
+    break;
+  }
+  return 0;
+}
+
+int FUNCTION(igraph_array3,resize)(TYPE(igraph_array3) *a, long int n1, long int n2, 
+				   long int n3) {
+  int ret=FUNCTION(igraph_vector,resize)(&a->data, n1*n2*n3);
+  a->n1=n1;
+  a->n2=n2;
+  a->n3=n3;
+  a->n1n2=n1*n2;
+  
+  return ret;
+}
+
+void FUNCTION(igraph_array3,null)(TYPE(igraph_array3) *a) {
+  FUNCTION(igraph_vector,null)(&a->data);
+}
+
+BASE FUNCTION(igraph_array3,sum)(const TYPE(igraph_array3) *a) {
+  return FUNCTION(igraph_vector,sum)(&a->data);
+}
+
+void FUNCTION(igraph_array3,scale)(TYPE(igraph_array3) *a, BASE by) {
+  FUNCTION(igraph_vector,scale)(&a->data, by);
+}
+
+void FUNCTION(igraph_array3,fill)(TYPE(igraph_array3) *a, BASE e) {
+  FUNCTION(igraph_vector,fill)(&a->data, e);
+}
+
+int FUNCTION(igraph_array3,update)(TYPE(igraph_array3) *to, 
+				   const TYPE(igraph_array3) *from) {
+  IGRAPH_CHECK(FUNCTION(igraph_array3,resize)(to, from->n1, from->n2, from->n3));
+  FUNCTION(igraph_vector,update)(&to->data, &from->data);  
+  return 0;
+}
diff --git a/src/atlas-edges.h b/src/atlas-edges.h
new file mode 100644
index 0000000..4f6ae55
--- /dev/null
+++ b/src/atlas-edges.h
@@ -0,0 +1,1294 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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
+
+*/
+
+#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
+
+const igraph_real_t igraph_i_atlas_edges[]={
+	0,0,
+	1,0,
+	2,0,
+	2,1,0,1,
+	3,0,
+	3,1,1,2,
+	3,2,0,1,0,2,
+	3,3,0,1,0,2,1,2,
+	4,0,
+	4,1,3,2,
+	4,2,3,2,3,1,
+	4,2,0,1,3,2,
+	4,3,3,2,1,2,3,1,
+	4,3,3,0,3,1,3,2,
+	4,3,0,1,1,2,0,3,
+	4,4,3,2,1,2,3,1,3,0,
+	4,4,0,1,1,2,2,3,0,3,
+	4,5,0,1,0,2,0,3,1,2,2,3,
+	4,6,0,1,1,2,0,2,3,0,3,1,3,2,
+	5,0,
+	5,1,4,3,
+	5,2,1,2,0,1,
+	5,2,0,2,4,3,
+	5,3,1,2,0,1,2,0,
+	5,3,4,3,3,2,3,1,
+	5,3,3,2,4,3,0,4,
+	5,3,1,2,0,1,4,3,
+	5,4,4,3,1,2,3,1,3,2,
+	5,4,0,3,1,0,2,1,3,2,
+	5,4,4,3,4,0,4,1,4,2,
+	5,4,4,0,3,1,4,3,3,2,
+	5,4,2,3,1,2,0,1,4,0,
+	5,4,1,2,0,1,2,0,4,3,
+	5,5,0,3,2,0,3,2,1,0,2,1,
+	5,5,4,2,4,3,2,3,4,1,4,0,
+	5,5,0,1,1,2,2,3,0,4,0,2,
+	5,5,4,0,1,2,4,3,3,2,3,1,
+	5,5,1,0,4,1,2,4,3,2,1,3,
+	5,5,0,1,1,2,2,3,3,4,0,4,
+	5,6,1,0,4,1,4,0,0,3,1,3,3,4,
+	5,6,1,0,4,1,2,4,3,2,1,3,2,1,
+	5,6,1,0,4,1,2,4,3,2,1,3,3,4,
+	5,6,0,1,4,3,2,3,4,2,4,0,4,1,
+	5,6,0,4,3,0,4,3,2,3,1,2,0,1,
+	5,6,2,1,0,2,3,0,1,3,4,1,0,4,
+	5,7,4,0,1,2,4,3,3,2,3,1,4,1,2,4,
+	5,7,4,1,2,4,3,2,1,3,3,4,0,3,4,0,
+	5,7,0,1,1,2,2,3,3,4,0,4,1,3,4,1,
+	5,7,2,1,0,2,3,0,1,3,4,1,0,4,2,4,
+	5,8,1,0,4,1,2,4,3,2,1,3,4,0,3,4,0,3,
+	5,8,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,
+	5,9,0,1,3,4,0,3,0,4,1,2,1,3,1,4,2,3,2,4,
+	5,10,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,
+	6,0,
+	6,1,5,4,
+	6,2,0,3,5,4,
+	6,2,1,3,1,2,
+	6,3,1,3,2,1,3,2,
+	6,3,0,3,5,0,4,0,
+	6,3,4,3,5,4,0,5,
+	6,3,4,3,5,1,5,2,
+	6,3,1,2,3,0,5,4,
+	6,4,0,3,4,0,5,4,0,5,
+	6,4,3,0,5,3,4,5,0,4,
+	6,4,5,1,5,3,5,2,0,5,
+	6,4,4,3,3,1,4,0,3,2,
+	6,4,0,2,1,3,2,1,5,3,
+	6,4,1,3,2,1,3,2,0,5,
+	6,4,1,2,0,3,5,0,4,0,
+	6,4,4,5,1,2,0,5,3,4,
+	6,4,0,2,4,0,3,1,5,3,
+	6,5,3,0,5,3,4,5,0,4,5,0,
+	6,5,5,3,3,1,3,2,4,3,4,5,
+	6,5,5,3,5,4,2,3,3,4,0,4,
+	6,5,4,3,1,2,4,0,3,2,3,1,
+	6,5,1,4,3,4,4,0,2,1,3,2,
+	6,5,0,1,1,2,2,3,3,4,0,4,
+	6,5,5,3,5,4,5,0,5,1,5,2,
+	6,5,1,4,5,1,1,0,2,1,2,3,
+	6,5,0,1,3,4,0,2,3,0,5,3,
+	6,5,1,0,2,1,2,4,1,3,5,3,
+	6,5,4,3,0,5,4,0,3,2,3,1,
+	6,5,1,2,0,1,4,5,1,3,2,3,
+	6,5,0,1,0,5,2,3,3,4,4,5,
+	6,5,4,3,5,1,5,2,0,3,4,0,
+	6,5,1,2,3,0,5,3,4,5,0,4,
+	6,6,0,3,5,0,4,5,3,4,5,3,4,0,
+	6,6,1,4,2,4,4,0,2,3,3,1,3,4,
+	6,6,1,4,2,4,4,0,2,1,3,1,2,3,
+	6,6,2,0,5,4,4,3,5,3,4,0,2,4,
+	6,6,3,2,4,3,0,4,1,0,2,1,0,3,
+	6,6,4,1,3,1,4,2,3,2,2,0,1,0,
+	6,6,5,2,5,3,5,4,3,4,5,1,5,0,
+	6,6,4,3,4,2,4,0,1,4,3,0,5,3,
+	6,6,4,3,3,5,5,4,5,1,3,2,4,0,
+	6,6,4,2,1,2,4,3,4,1,4,0,0,5,
+	6,6,1,2,3,1,0,3,2,0,4,0,5,0,
+	6,6,2,0,4,2,1,4,2,1,3,1,5,3,
+	6,6,1,2,3,1,0,3,2,0,4,0,5,3,
+	6,6,5,3,2,5,2,0,4,2,4,3,3,1,
+	6,6,0,2,3,4,1,0,5,3,4,5,3,0,
+	6,6,1,2,3,0,5,3,4,5,0,4,5,0,
+	6,6,4,3,1,2,4,0,3,2,3,1,5,0,
+	6,6,1,4,2,4,4,0,0,5,3,1,2,3,
+	6,6,0,1,1,2,2,3,3,4,0,4,1,5,
+	6,6,0,1,1,2,2,3,3,4,4,5,0,5,
+	6,6,1,3,2,1,3,2,0,4,5,0,4,5,
+	6,7,0,1,1,2,0,2,3,0,3,1,3,2,0,5,
+	6,7,1,4,2,4,2,1,3,1,2,3,2,0,0,1,
+	6,7,0,1,1,2,2,3,3,4,0,4,1,3,4,1,
+	6,7,0,1,3,2,0,2,3,0,3,1,5,1,5,2,
+	6,7,1,4,2,4,2,3,0,4,3,1,4,5,3,4,
+	6,7,1,0,4,1,2,4,3,2,5,1,2,5,1,2,
+	6,7,0,4,2,0,1,2,3,1,5,3,3,0,2,3,
+	6,7,1,4,2,4,2,3,2,1,3,1,4,5,0,4,
+	6,7,1,0,4,1,2,4,3,2,5,1,2,5,4,5,
+	6,7,0,1,1,2,0,2,3,0,3,1,3,2,5,4,
+	6,7,0,5,4,0,5,4,0,2,3,0,3,2,0,1,
+	6,7,0,1,1,2,2,3,3,4,0,4,1,5,4,1,
+	6,7,0,1,4,0,1,4,0,2,3,0,3,2,3,5,
+	6,7,1,4,2,4,4,0,0,5,3,1,2,3,3,4,
+	6,7,2,0,3,2,4,3,5,4,2,5,1,2,4,1,
+	6,7,1,5,0,1,4,0,3,4,2,3,1,2,0,3,
+	6,7,1,4,2,4,4,0,0,5,3,1,2,3,2,1,
+	6,7,0,1,1,2,2,3,3,4,0,4,0,2,5,1,
+	6,7,2,0,4,1,1,2,5,4,2,5,3,1,5,3,
+	6,7,5,0,3,5,2,3,0,2,1,3,4,1,3,4,
+	6,7,1,3,2,1,0,2,5,0,4,5,3,4,2,3,
+	6,7,0,1,1,2,2,3,3,4,4,5,0,5,0,3,
+	6,7,4,3,0,4,1,0,2,1,3,2,0,5,5,3,
+	6,7,1,2,0,1,2,0,3,0,4,3,5,4,3,5,
+	6,8,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,
+	6,8,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,
+	6,8,0,1,1,2,0,2,3,0,3,1,3,2,5,0,0,4,
+	6,8,1,2,3,1,0,3,1,0,2,0,3,2,5,3,4,0,
+	6,8,0,1,2,4,0,2,5,2,3,1,3,2,2,1,4,1,
+	6,8,0,1,1,2,2,3,3,4,0,4,1,3,4,1,1,5,
+	6,8,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,
+	6,8,0,1,2,5,0,2,4,0,3,1,3,2,2,1,5,1,
+	6,8,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,0,
+	6,8,0,1,2,5,0,2,4,0,3,1,3,2,3,0,5,1,
+	6,8,2,0,3,2,4,3,5,4,2,5,1,2,4,1,5,3,
+	6,8,0,1,1,2,0,2,3,0,3,1,3,2,0,5,5,4,
+	6,8,0,1,2,5,0,2,4,0,3,1,3,2,5,1,5,3,
+	6,8,1,4,2,4,2,3,0,4,3,1,4,5,0,5,3,4,
+	6,8,0,1,1,2,2,3,3,4,0,4,5,0,5,2,0,2,
+	6,8,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,
+	6,8,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,
+	6,8,1,3,2,1,0,2,5,0,4,5,3,4,1,4,0,1,
+	6,8,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,
+	6,8,1,4,2,4,2,3,0,4,3,1,4,5,0,5,2,1,
+	6,8,0,1,1,2,2,3,3,4,0,4,4,5,5,3,1,5,
+	6,8,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,1,
+	6,8,0,1,1,2,2,3,3,4,0,4,1,5,5,2,5,0,
+	6,8,0,1,1,2,2,3,3,4,4,5,0,5,4,1,5,2,
+	6,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,
+	6,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,2,
+	6,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,0,4,
+	6,9,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,4,5,
+	6,9,2,0,4,1,1,2,5,4,2,5,3,1,5,3,3,2,4,3,
+	6,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,5,
+	6,9,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,
+	6,9,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,
+	6,9,1,3,2,1,0,2,5,0,4,5,3,4,0,4,1,0,4,1,
+	6,9,1,3,2,1,0,2,5,0,4,5,3,4,4,1,1,0,5,1,
+	6,9,0,1,1,2,0,2,3,0,3,1,3,2,5,4,4,0,5,0,
+	6,9,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,
+	6,9,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,
+	6,9,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,
+	6,9,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,
+	6,9,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,2,0,
+	6,9,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,
+	6,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,
+	6,9,0,1,1,2,2,3,3,4,4,5,0,5,0,3,4,2,5,2,
+	6,9,2,3,0,2,3,0,4,3,1,4,5,1,4,5,1,0,5,2,
+	6,9,0,1,1,2,2,3,3,4,4,5,0,5,0,3,5,2,4,1,
+	6,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,
+	6,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,4,5,
+	6,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,5,
+	6,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,1,0,
+	6,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,5,1,5,
+	6,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,2,4,
+	6,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,
+	6,10,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,
+	6,10,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,5,2,
+	6,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,
+	6,10,0,1,2,4,0,2,4,5,3,1,3,2,4,1,5,1,5,2,5,3,
+	6,10,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,
+	6,10,0,1,1,2,2,3,3,4,4,5,0,5,2,4,0,2,1,3,5,1,
+	6,10,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,3,2,0,3,
+	6,10,1,3,2,1,0,2,5,0,4,5,3,4,4,1,5,3,2,5,1,0,
+	6,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,1,5,
+	6,11,0,1,2,4,0,2,2,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,
+	6,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,
+	6,11,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,0,2,
+	6,11,1,3,2,1,0,2,5,0,4,5,3,4,4,1,5,3,2,5,1,0,5,1,
+	6,11,1,3,4,1,3,4,2,3,0,2,4,0,5,4,2,5,4,2,0,5,1,5,
+	6,11,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,
+	6,11,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,
+	6,11,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,0,3,
+	6,12,0,1,1,2,0,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,4,3,
+	6,12,3,2,1,3,2,1,0,2,5,0,2,5,2,4,5,1,0,3,1,4,0,1,0,4,
+	6,12,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,4,5,
+	6,12,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,2,3,
+	6,12,0,1,1,2,0,2,3,2,3,1,4,0,2,4,5,1,0,5,4,5,3,4,5,3,
+	6,13,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,2,3,0,4,
+	6,13,0,1,1,2,0,2,3,2,3,1,4,0,2,4,5,1,0,5,4,5,3,4,5,3,3,0,
+	6,14,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,1,3,2,0,4,0,5,3,
+	6,15,0,1,0,2,0,3,0,4,0,5,1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,
+	7,0,
+	7,1,6,5,
+	7,2,2,3,1,2,
+	7,2,5,4,6,0,
+	7,3,0,4,4,2,2,0,
+	7,3,0,1,0,6,0,5,
+	7,3,5,4,6,0,5,6,
+	7,3,3,2,1,2,5,6,
+	7,3,3,1,5,6,0,4,
+	7,4,2,5,6,2,5,6,1,2,
+	7,4,1,2,4,1,5,4,2,5,
+	7,4,1,0,5,1,1,2,4,1,
+	7,4,1,0,2,1,5,2,6,2,
+	7,4,3,4,2,3,1,2,0,1,
+	7,4,4,2,0,4,2,0,5,6,
+	7,4,0,1,6,0,0,5,4,2,
+	7,4,3,1,5,4,6,5,0,6,
+	7,4,0,4,3,0,2,5,6,2,
+	7,4,2,3,1,2,6,0,5,4,
+	7,5,0,4,3,0,1,3,4,1,1,0,
+	7,5,2,5,6,2,5,6,4,2,3,2,
+	7,5,4,2,4,0,2,0,5,4,6,0,
+	7,5,2,5,6,2,5,6,1,2,0,1,
+	7,5,4,1,0,4,3,0,1,3,2,1,
+	7,5,1,2,0,1,4,0,3,4,2,3,
+	7,5,5,1,5,0,2,5,3,5,4,5,
+	7,5,1,5,6,1,1,0,2,1,3,2,
+	7,5,1,5,4,1,2,3,6,2,2,1,
+	7,5,1,5,6,1,1,2,2,3,4,3,
+	7,5,2,1,3,2,4,3,5,4,3,6,
+	7,5,6,5,2,6,1,2,5,2,3,4,
+	7,5,4,3,5,4,6,5,0,6,1,0,
+	7,5,0,4,3,0,2,5,6,2,5,6,
+	7,5,4,1,5,2,6,5,3,6,2,3,
+	7,5,1,4,3,1,1,0,2,1,6,5,
+	7,5,0,4,3,0,1,0,2,1,6,5,
+	7,5,0,4,3,0,2,1,5,2,6,2,
+	7,5,6,5,3,4,2,3,1,2,0,1,
+	7,5,2,3,1,2,6,0,5,6,5,4,
+	7,5,0,1,4,6,5,4,3,2,6,5,
+	7,6,1,5,6,1,5,6,2,5,1,2,6,2,
+	7,6,1,4,3,1,2,3,4,2,1,0,2,1,
+	7,6,0,4,3,0,1,3,2,1,1,4,3,4,
+	7,6,5,2,4,5,2,4,3,2,6,3,2,6,
+	7,6,1,2,4,1,5,4,2,5,0,1,4,0,
+	7,6,1,2,5,1,4,5,2,4,0,2,5,0,
+	7,6,2,5,6,2,5,6,2,4,1,2,3,2,
+	7,6,1,4,3,1,2,3,1,2,2,5,6,2,
+	7,6,5,4,6,5,1,6,5,1,3,6,0,1,
+	7,6,6,5,1,6,5,1,3,1,0,3,1,4,
+	7,6,0,4,3,0,2,3,4,2,2,5,6,2,
+	7,6,1,4,3,1,2,3,1,2,2,5,6,5,
+	7,6,2,3,1,2,3,6,5,4,6,5,5,2,
+	7,6,2,5,6,2,5,6,1,4,3,1,2,1,
+	7,6,4,5,0,4,3,0,2,3,4,2,6,3,
+	7,6,0,4,3,0,1,3,6,5,1,4,1,0,
+	7,6,1,4,3,1,2,3,5,2,6,5,2,6,
+	7,6,6,3,5,6,4,5,1,4,2,1,5,2,
+	7,6,1,0,3,1,6,3,5,6,4,5,1,4,
+	7,6,0,1,1,2,2,3,3,4,4,5,0,5,
+	7,6,0,4,3,0,4,3,2,5,6,2,5,6,
+	7,6,6,3,0,6,6,2,5,6,6,1,4,6,
+	7,6,2,4,5,2,2,3,6,2,1,2,1,0,
+	7,6,1,0,2,1,5,2,1,4,3,1,6,2,
+	7,6,1,0,2,1,3,6,1,3,4,1,5,4,
+	7,6,1,0,2,1,5,2,6,5,1,4,3,1,
+	7,6,1,0,2,4,5,2,6,5,2,6,3,2,
+	7,6,4,0,1,4,3,1,2,1,5,2,6,2,
+	7,6,6,5,1,2,0,1,2,0,3,2,0,4,
+	7,6,0,4,3,0,1,0,2,1,5,2,6,2,
+	7,6,1,0,3,1,6,3,2,6,4,1,5,4,
+	7,6,2,5,6,2,4,2,1,4,3,1,0,3,
+	7,6,0,4,3,0,2,3,4,2,1,2,6,5,
+	7,6,0,4,3,0,2,1,5,2,6,5,2,6,
+	7,6,3,4,1,0,2,1,5,2,6,5,2,6,
+	7,6,4,5,0,4,3,0,6,3,1,0,2,1,
+	7,6,2,5,6,2,5,6,1,4,3,1,1,0,
+	7,6,4,5,3,4,2,3,1,2,0,1,6,0,
+	7,6,6,4,5,6,4,5,2,3,1,2,0,1,
+	7,6,0,1,4,0,2,3,5,2,6,5,3,6,
+	7,6,1,2,0,1,4,0,3,4,2,3,6,5,
+	7,7,1,4,3,1,2,3,4,2,1,0,2,1,3,4,
+	7,7,1,2,5,1,4,5,2,4,0,2,5,0,5,2,
+	7,7,0,1,1,2,2,3,3,4,0,4,1,3,4,1,
+	7,7,1,2,5,1,4,5,2,4,0,2,5,0,1,0,
+	7,7,0,4,3,0,2,3,4,2,2,5,6,2,2,0,
+	7,7,1,4,3,1,2,3,4,2,1,0,2,1,2,6,
+	7,7,1,4,3,1,2,3,4,2,1,0,3,4,6,3,
+	7,7,0,4,3,0,2,3,4,2,2,5,6,2,3,4,
+	7,7,0,4,3,0,1,3,3,6,1,4,1,0,5,4,
+	7,7,0,4,3,0,1,3,6,5,1,4,1,0,3,4,
+	7,7,5,2,4,5,2,4,3,2,6,3,2,6,2,1,
+	7,7,0,1,1,2,2,3,3,4,0,4,0,2,2,5,
+	7,7,5,2,4,5,2,4,3,2,6,3,2,6,3,1,
+	7,7,1,4,3,1,2,3,4,2,2,0,2,1,6,0,
+	7,7,1,2,5,1,4,5,2,4,0,2,5,0,3,5,
+	7,7,0,1,1,2,2,3,3,4,0,4,0,2,3,5,
+	7,7,0,1,1,2,2,3,3,4,0,4,0,2,1,5,
+	7,7,3,2,4,3,3,5,2,4,5,2,6,1,6,4,
+	7,7,1,2,5,1,4,5,2,4,0,2,5,0,0,3,
+	7,7,3,4,1,3,2,1,6,2,5,6,1,5,4,1,
+	7,7,0,1,4,0,1,4,2,1,3,2,5,3,4,5,
+	7,7,6,3,5,6,1,5,2,1,3,2,4,2,5,4,
+	7,7,1,2,4,1,5,4,6,5,3,6,2,3,5,2,
+	7,7,4,1,3,4,1,3,2,1,6,2,5,6,2,5,
+	7,7,3,0,6,3,0,6,1,0,0,2,5,0,0,4,
+	7,7,1,5,6,1,1,2,3,1,4,3,1,4,4,0,
+	7,7,5,0,6,5,0,6,5,2,1,5,6,3,4,6,
+	7,7,4,1,0,4,1,0,2,1,0,3,6,0,4,5,
+	7,7,5,2,6,5,2,6,2,4,3,2,1,0,2,1,
+	7,7,4,1,0,4,3,0,1,3,2,1,1,5,6,1,
+	7,7,1,0,4,1,0,4,5,4,2,1,3,2,6,1,
+	7,7,0,1,4,0,1,4,2,1,3,2,5,4,6,4,
+	7,7,2,3,5,2,6,5,3,6,1,2,4,5,0,5,
+	7,7,0,4,3,0,1,3,4,1,1,0,2,1,6,5,
+	7,7,2,5,6,2,5,6,4,2,1,2,0,1,3,1,
+	7,7,2,5,6,2,4,2,1,4,3,1,2,3,0,1,
+	7,7,6,2,5,6,2,5,1,2,0,1,4,1,3,1,
+	7,7,0,4,3,0,1,3,4,1,5,4,2,1,6,3,
+	7,7,2,5,6,2,5,6,4,5,3,6,1,2,0,1,
+	7,7,2,5,6,2,1,4,1,2,0,1,4,0,0,3,
+	7,7,6,5,1,2,4,1,0,4,3,0,1,3,3,4,
+	7,7,4,1,0,4,1,0,3,6,2,3,0,2,5,0,
+	7,7,4,1,0,4,3,0,1,3,2,1,5,2,6,1,
+	7,7,4,1,0,4,1,0,2,3,0,2,5,0,6,5,
+	7,7,0,1,5,0,6,5,3,6,2,3,0,2,4,0,
+	7,7,1,0,4,1,2,4,3,2,4,3,0,4,6,5,
+	7,7,3,6,2,3,1,2,0,1,4,0,1,4,5,4,
+	7,7,1,0,5,1,6,5,2,6,1,2,3,2,4,3,
+	7,7,2,3,1,2,0,1,4,0,5,4,6,5,4,1,
+	7,7,5,2,6,5,2,6,1,2,4,1,0,4,3,1,
+	7,7,2,3,1,2,0,1,4,0,5,4,6,5,5,2,
+	7,7,1,4,0,1,2,0,3,2,5,3,0,5,6,3,
+	7,7,2,1,3,2,6,3,5,6,0,5,2,0,5,4,
+	7,7,5,2,6,5,2,6,1,2,0,1,4,0,3,0,
+	7,7,4,1,0,4,3,0,1,3,2,1,5,2,6,2,
+	7,7,1,0,2,1,5,2,4,5,0,4,4,1,6,3,
+	7,7,2,5,6,2,0,4,3,0,1,3,4,1,1,0,
+	7,7,6,5,0,4,3,0,1,3,4,1,2,4,3,2,
+	7,7,2,1,5,2,4,5,0,4,3,0,6,3,2,6,
+	7,7,4,0,3,4,1,3,2,1,5,2,6,5,2,6,
+	7,7,6,5,2,6,1,2,4,1,0,4,3,0,1,3,
+	7,7,4,1,0,4,2,0,3,2,6,3,5,6,0,5,
+	7,7,0,4,3,0,4,3,2,1,5,2,6,5,2,6,
+	7,7,0,1,1,2,2,3,3,4,4,5,5,6,0,6,
+	7,7,1,0,4,1,0,4,5,2,6,5,3,6,2,3,
+	7,8,0,1,4,0,5,4,2,5,1,2,5,1,4,1,2,4,
+	7,8,4,1,5,4,2,5,1,2,0,1,5,0,0,4,2,0,
+	7,8,0,4,3,0,1,3,4,1,1,0,3,4,5,1,6,1,
+	7,8,4,1,5,4,2,5,1,2,5,1,6,5,2,4,3,2,
+	7,8,1,3,0,1,4,0,2,4,1,2,4,1,5,4,1,5,
+	7,8,2,0,3,2,6,3,5,6,0,5,3,0,0,6,4,0,
+	7,8,1,0,2,1,5,2,4,5,0,4,2,0,5,0,6,5,
+	7,8,1,0,2,1,3,2,1,3,4,3,2,4,5,2,3,5,
+	7,8,2,0,3,2,6,3,5,6,0,5,3,0,6,0,4,5,
+	7,8,1,0,2,1,4,3,1,5,4,1,2,4,5,2,3,5,
+	7,8,3,5,2,1,4,3,1,5,4,1,2,4,5,2,4,6,
+	7,8,0,4,3,0,1,3,4,1,1,0,3,4,2,1,5,2,
+	7,8,3,5,2,1,4,3,1,5,4,1,2,4,5,2,0,3,
+	7,8,4,0,2,4,0,2,3,0,2,3,5,2,6,5,2,6,
+	7,8,3,2,6,3,5,6,2,5,0,2,5,0,4,5,2,4,
+	7,8,0,5,4,0,2,4,5,2,1,5,4,1,3,4,5,3,
+	7,8,2,3,1,2,4,1,5,4,1,5,5,2,6,5,3,6,
+	7,8,5,2,4,5,0,4,3,0,6,3,2,6,4,2,3,2,
+	7,8,0,4,3,0,1,3,4,1,2,4,3,2,5,4,2,5,
+	7,8,5,6,2,5,6,2,3,2,4,3,0,4,3,0,2,4,
+	7,8,1,0,5,0,3,2,1,3,5,2,6,1,6,2,6,5,
+	7,8,5,4,6,5,3,6,0,3,4,0,2,4,3,2,0,2,
+	7,8,0,1,1,2,2,3,3,4,4,5,0,5,4,2,1,5,
+	7,8,5,0,6,2,0,6,1,0,2,1,5,2,4,5,4,6,
+	7,8,0,4,3,0,1,3,4,1,1,0,2,1,1,5,6,1,
+	7,8,0,2,4,0,1,4,0,1,3,0,1,3,5,1,6,1,
+	7,8,4,2,0,4,3,0,1,3,4,1,1,0,1,5,6,1,
+	7,8,0,4,3,0,4,3,1,4,3,1,1,5,2,1,6,1,
+	7,8,2,1,0,2,3,0,5,3,2,5,3,2,4,3,6,5,
+	7,8,4,2,0,4,3,0,1,3,4,1,3,4,1,5,6,1,
+	7,8,2,1,0,2,3,0,5,3,2,5,6,5,4,3,5,0,
+	7,8,1,0,2,1,3,2,1,3,4,2,3,4,4,5,6,4,
+	7,8,6,5,1,2,4,1,0,4,3,0,1,3,0,1,3,4,
+	7,8,0,1,6,5,2,3,6,4,6,3,6,2,6,0,6,1,
+	7,8,6,4,1,2,2,3,6,5,4,5,6,2,6,0,6,1,
+	7,8,0,1,1,2,2,3,6,5,6,4,6,3,6,0,6,2,
+	7,8,0,4,3,0,1,3,4,1,1,0,6,1,5,1,2,5,
+	7,8,3,0,2,3,4,2,0,4,1,0,2,1,5,2,6,2,
+	7,8,2,1,3,2,6,3,5,6,0,5,2,0,5,2,4,5,
+	7,8,1,0,2,1,3,2,4,3,5,2,1,5,6,1,2,6,
+	7,8,2,5,4,2,1,4,3,1,0,3,1,0,2,1,6,2,
+	7,8,4,5,0,4,3,0,2,3,4,2,1,4,3,1,6,3,
+	7,8,0,1,4,0,1,4,2,1,4,2,5,4,1,5,6,3,
+	7,8,0,1,2,0,3,2,4,3,1,4,2,1,1,6,5,0,
+	7,8,4,5,0,4,1,0,4,1,3,0,1,3,6,1,2,6,
+	7,8,2,5,4,2,0,4,1,0,4,1,3,0,1,3,6,1,
+	7,8,1,6,2,1,0,2,1,0,4,1,3,4,2,3,4,5,
+	7,8,0,1,2,0,3,2,4,3,1,4,2,1,1,6,5,3,
+	7,8,0,4,3,0,4,3,1,4,3,1,5,1,6,2,1,6,
+	7,8,2,3,1,2,0,1,5,0,4,5,0,4,2,0,6,5,
+	7,8,4,5,0,4,3,0,1,3,4,1,2,4,3,2,6,2,
+	7,8,2,3,1,2,0,1,4,0,5,4,4,1,2,6,5,2,
+	7,8,0,1,1,2,2,3,6,3,4,5,6,2,6,0,6,1,
+	7,8,4,1,0,4,3,0,1,3,0,1,2,1,5,2,6,2,
+	7,8,0,1,1,2,2,3,6,5,4,5,6,2,6,4,6,1,
+	7,8,0,1,4,0,0,2,5,0,6,5,3,6,2,3,5,2,
+	7,8,0,4,3,0,2,3,4,2,1,4,3,1,2,5,6,2,
+	7,8,4,5,3,4,1,3,2,1,6,2,4,6,3,2,0,1,
+	7,8,1,0,2,6,3,2,4,3,5,2,1,5,6,1,6,5,
+	7,8,2,3,1,2,0,1,4,0,5,4,6,5,5,2,4,1,
+	7,8,4,1,0,4,3,0,1,3,3,4,2,1,2,5,6,2,
+	7,8,0,6,4,0,1,4,3,1,0,3,2,4,3,2,5,2,
+	7,8,0,4,3,0,1,3,4,1,2,4,3,2,1,0,6,5,
+	7,8,0,1,4,0,3,2,6,3,5,6,2,5,6,2,3,5,
+	7,8,5,2,6,5,2,6,4,2,0,4,3,0,2,3,1,2,
+	7,8,2,0,1,2,0,1,5,0,4,5,0,4,6,0,3,6,
+	7,8,0,1,2,0,3,2,2,1,1,4,5,4,5,3,1,6,
+	7,8,1,6,2,1,0,2,1,0,4,1,3,4,2,3,5,6,
+	7,8,6,1,0,6,1,0,5,1,0,5,2,1,3,2,4,3,
+	7,8,6,5,2,6,1,2,4,1,3,4,0,3,4,0,2,4,
+	7,8,1,6,0,1,5,0,1,5,3,0,4,3,2,4,0,2,
+	7,8,2,6,4,2,0,4,1,0,4,1,3,4,5,3,2,5,
+	7,8,1,0,2,1,6,2,5,6,1,5,4,1,3,4,2,3,
+	7,8,6,1,4,3,1,0,5,1,3,2,2,1,4,6,5,4,
+	7,8,4,2,0,4,1,0,4,1,3,4,6,3,5,6,3,5,
+	7,8,4,1,2,4,0,2,6,0,3,6,0,3,5,0,4,5,
+	7,8,5,6,4,5,0,4,3,0,2,3,4,2,1,4,3,1,
+	7,8,6,3,5,6,4,5,0,4,1,0,2,1,5,2,4,1,
+	7,8,0,1,2,0,3,2,2,1,1,4,5,4,5,3,4,6,
+	7,8,4,0,3,4,2,3,6,2,5,6,1,5,4,1,2,1,
+	7,8,6,1,0,6,4,3,5,1,0,5,2,1,3,2,5,6,
+	7,8,6,2,5,6,3,5,6,3,4,3,0,4,1,0,4,1,
+	7,8,0,1,1,2,2,3,3,4,4,5,0,5,0,6,5,1,
+	7,8,0,1,1,2,2,3,3,4,4,5,0,5,0,6,4,2,
+	7,8,0,1,2,0,3,2,4,3,1,4,2,1,5,6,0,5,
+	7,8,4,0,2,4,3,2,6,3,5,6,4,5,1,2,5,1,
+	7,8,5,1,2,4,3,2,0,3,5,0,4,5,1,2,0,6,
+	7,8,5,6,2,5,4,2,0,4,3,0,2,3,1,4,3,1,
+	7,8,0,4,1,0,4,1,3,4,5,3,6,5,2,6,4,2,
+	7,8,0,1,6,5,2,3,3,4,6,4,0,5,6,2,6,1,
+	7,8,1,2,0,1,4,0,5,4,2,5,3,2,6,3,5,6,
+	7,8,0,1,1,2,2,3,3,4,4,5,0,5,2,6,1,6,
+	7,8,6,2,5,6,2,5,1,2,4,1,0,4,3,0,1,3,
+	7,8,0,1,1,2,2,3,3,4,4,5,0,5,6,5,6,1,
+	7,8,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,3,
+	7,8,0,4,1,0,3,2,1,4,2,5,5,3,6,4,6,3,
+	7,8,0,4,3,0,1,3,4,1,1,0,6,2,5,6,2,5,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,
+	7,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,2,
+	7,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,0,4,
+	7,9,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,4,5,
+	7,9,2,0,4,1,1,2,5,4,2,5,3,1,5,3,3,2,4,3,
+	7,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,5,
+	7,9,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,
+	7,9,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,
+	7,9,1,3,2,1,0,2,5,0,4,5,3,4,0,4,1,0,4,1,
+	7,9,1,3,2,1,0,2,5,0,4,5,3,4,4,1,1,0,5,1,
+	7,9,0,1,1,2,0,2,3,0,3,1,3,2,5,4,4,0,5,0,
+	7,9,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,
+	7,9,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,
+	7,9,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,
+	7,9,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,
+	7,9,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,2,0,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,0,3,4,2,5,2,
+	7,9,2,3,0,2,3,0,4,3,1,4,5,1,4,5,1,0,5,2,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,0,3,5,2,4,1,
+	7,9,0,1,1,2,0,2,3,0,3,1,3,2,5,0,0,4,0,6,
+	7,9,0,1,1,2,0,2,3,0,3,1,3,2,5,0,0,4,2,6,
+	7,9,1,2,3,1,0,3,1,0,2,0,3,2,5,3,4,0,1,6,
+	7,9,0,1,2,4,0,2,3,1,3,2,2,1,4,1,5,2,2,6,
+	7,9,0,1,2,4,0,2,5,2,3,1,3,2,2,1,4,1,1,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,1,5,1,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,1,5,4,6,
+	7,9,0,1,2,5,0,2,4,0,3,1,3,2,2,1,5,1,1,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,4,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,6,
+	7,9,0,1,2,5,0,2,4,0,3,1,3,2,2,1,5,1,0,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,0,1,6,
+	7,9,2,0,3,2,4,3,5,4,2,5,1,2,4,1,5,3,2,6,
+	7,9,0,1,2,5,0,2,4,0,3,1,3,2,3,0,5,1,0,6,
+	7,9,0,1,1,2,0,2,3,0,3,1,3,2,5,0,0,4,5,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,0,4,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,2,6,
+	7,9,2,0,3,2,4,3,5,4,2,5,1,2,4,1,5,3,5,6,
+	7,9,1,2,3,1,0,3,1,0,2,0,3,2,4,0,6,5,6,3,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,0,0,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,6,5,4,0,3,2,4,
+	7,9,0,1,2,5,0,2,4,0,3,1,3,2,2,1,5,1,5,6,
+	7,9,2,0,3,2,4,3,5,4,2,5,1,2,4,1,5,3,4,6,
+	7,9,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,0,2,6,
+	7,9,0,1,2,5,0,2,4,0,3,1,3,2,3,0,5,1,5,6,
+	7,9,0,1,2,5,0,2,5,4,3,1,3,2,3,0,5,1,2,6,
+	7,9,0,1,2,5,0,2,4,0,3,1,3,2,5,1,5,3,0,6,
+	7,9,0,1,1,2,0,2,3,0,3,1,3,2,0,5,5,4,5,6,
+	7,9,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,3,4,4,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,0,5,2,0,2,0,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,3,4,3,6,
+	7,9,0,1,2,4,0,2,5,2,3,1,3,2,2,1,4,1,5,6,
+	7,9,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,2,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,6,5,6,1,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,3,4,2,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,3,4,0,6,
+	7,9,1,3,2,1,0,2,5,0,6,5,3,6,1,6,0,1,1,4,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,0,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,2,1,4,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,5,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,4,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,5,6,
+	7,9,1,3,2,1,0,2,5,0,6,5,3,6,1,6,0,1,0,4,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,0,5,2,0,2,1,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,0,5,2,0,2,4,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,2,1,2,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,3,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,2,6,
+	7,9,0,1,2,5,0,2,5,1,3,1,3,2,2,1,6,0,6,4,
+	7,9,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,1,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,0,5,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,0,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,3,6,
+	7,9,1,3,2,1,0,2,5,0,6,5,3,6,1,6,0,1,2,4,
+	7,9,0,1,1,2,2,3,3,4,0,4,4,5,5,3,1,5,3,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,1,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,1,4,6,
+	7,9,0,1,2,5,0,2,5,1,3,1,3,2,3,0,6,4,6,0,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,5,5,2,5,0,1,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,2,1,6,0,
+	7,9,5,3,3,2,4,3,5,4,2,5,1,2,4,1,6,0,6,2,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,5,5,2,5,0,0,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,4,5,5,3,1,5,5,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,4,6,
+	7,9,1,3,2,1,0,2,5,0,6,5,3,6,1,6,0,1,5,4,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,4,1,5,2,5,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,4,5,5,3,1,5,1,6,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,2,1,3,6,
+	7,9,0,1,1,2,0,2,3,0,3,1,3,2,0,5,5,4,4,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,4,5,5,3,1,5,0,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,1,5,5,2,5,0,4,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,1,0,6,
+	7,9,0,1,2,5,0,2,5,3,3,1,3,2,5,1,6,4,6,0,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,4,1,5,2,0,6,
+	7,9,6,3,1,2,6,5,3,4,6,4,0,5,6,0,6,1,6,2,
+	7,9,0,1,2,0,3,2,4,3,1,4,2,1,6,2,5,6,2,5,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,3,4,6,5,6,0,
+	7,9,1,4,2,4,2,3,0,4,3,1,4,5,0,5,6,4,6,3,
+	7,9,4,1,5,4,6,5,3,6,2,3,1,2,5,2,0,5,2,0,
+	7,9,4,1,3,1,2,3,4,0,5,0,5,2,5,4,6,4,5,6,
+	7,9,1,0,2,1,6,2,3,6,5,3,4,5,3,4,2,3,0,2,
+	7,9,0,2,5,0,1,5,2,1,4,2,5,4,6,5,3,6,2,3,
+	7,9,0,1,1,2,2,3,3,4,4,5,5,6,0,6,1,3,4,1,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,4,5,1,6,1,0,6,
+	7,9,0,4,1,0,4,1,3,4,2,3,6,2,5,6,1,5,2,1,
+	7,9,0,1,2,0,3,2,4,3,1,4,2,1,5,3,6,5,3,6,
+	7,9,6,5,3,6,2,3,0,4,0,5,1,0,2,0,1,2,5,4,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,3,5,1,6,1,0,6,
+	7,9,5,2,6,5,3,6,2,3,0,2,4,0,5,4,1,5,0,1,
+	7,9,2,4,1,2,4,1,5,4,0,5,1,0,6,4,3,6,2,3,
+	7,9,6,2,5,6,2,5,1,2,0,1,4,0,1,4,3,1,0,3,
+	7,9,0,5,6,0,1,6,4,1,2,4,3,2,1,3,5,1,6,5,
+	7,9,6,5,3,6,2,3,5,2,0,5,1,0,4,1,0,4,2,0,
+	7,9,0,4,3,0,1,3,4,1,2,4,6,2,5,6,2,5,3,2,
+	7,9,1,0,4,1,5,4,0,5,6,0,3,6,2,3,0,2,3,4,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,1,6,3,
+	7,9,0,1,1,2,2,3,0,3,4,1,5,4,5,3,6,0,6,4,
+	7,9,0,1,4,0,1,4,2,1,5,2,4,5,6,5,3,6,2,3,
+	7,9,1,0,6,3,0,4,5,0,3,5,5,6,1,2,1,4,6,2,
+	7,9,6,2,5,6,2,5,1,2,0,3,4,0,1,4,3,1,3,4,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,6,1,5,6,6,0,
+	7,9,0,4,1,0,2,1,3,2,0,3,2,4,5,4,6,5,3,6,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,4,2,6,1,5,6,
+	7,9,0,1,1,2,2,3,3,4,0,4,5,3,5,4,6,1,6,5,
+	7,9,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,4,6,2,
+	7,9,0,4,3,0,4,3,6,1,5,6,1,5,2,1,5,2,6,2,
+	7,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,
+	7,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,4,
+	7,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,1,0,
+	7,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,5,1,5,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,2,4,
+	7,10,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,
+	7,10,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,5,2,
+	7,10,0,1,2,4,0,2,4,5,3,1,3,2,4,1,5,1,5,2,5,3,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,2,4,0,2,1,3,5,1,
+	7,10,0,1,1,2,3,4,0,2,3,0,2,4,5,2,1,5,4,1,3,5,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,4,1,5,3,2,5,1,0,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,2,2,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,2,1,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,0,4,1,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,0,4,0,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,0,4,3,6,
+	7,10,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,4,5,4,6,
+	7,10,2,0,4,1,1,2,5,4,2,5,3,1,5,3,3,2,4,3,3,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,5,2,6,
+	7,10,2,0,4,1,1,2,5,4,2,5,3,1,5,3,3,2,4,3,2,6,
+	7,10,2,3,1,2,4,1,5,4,2,5,0,2,4,0,0,1,5,0,6,5,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,0,4,5,6,
+	7,10,2,0,4,1,1,2,5,4,2,5,3,1,5,3,3,2,4,3,4,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,4,5,6,5,
+	7,10,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,6,5,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,0,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,2,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,1,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,3,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,0,4,1,0,4,1,0,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,4,1,1,0,5,1,1,6,
+	7,10,0,1,1,2,0,2,3,0,3,1,3,2,5,4,4,0,5,0,0,6,
+	7,10,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,3,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,5,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,3,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,4,1,1,0,5,1,0,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,2,0,5,3,2,3,6,2,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,6,4,6,2,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,2,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,4,1,1,0,5,1,5,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,3,0,4,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,3,6,
+	7,10,0,1,1,2,0,2,3,0,3,1,3,2,5,4,4,0,5,0,2,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,2,0,5,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,2,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,2,0,5,3,2,3,0,6,
+	7,10,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,1,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,4,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,6,4,6,0,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,5,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,0,4,1,0,4,1,5,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,2,0,0,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,4,1,1,0,5,1,2,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,0,3,4,2,5,2,2,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,5,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,0,6,
+	7,10,0,1,1,2,0,2,3,0,3,1,3,2,5,4,4,0,5,0,5,6,
+	7,10,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,6,5,6,4,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,1,6,
+	7,10,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,4,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,4,6,
+	7,10,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,2,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,0,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,0,3,4,2,5,2,5,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,1,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,3,6,
+	7,10,4,3,4,1,1,2,5,4,2,5,3,1,5,3,3,2,6,0,6,2,
+	7,10,1,0,2,1,3,2,4,3,5,4,1,5,6,1,4,6,2,6,5,2,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,0,3,4,2,5,2,0,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,3,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,2,6,
+	7,10,0,1,2,5,0,2,3,0,3,1,3,2,2,1,5,1,6,5,6,4,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,1,6,
+	7,10,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,6,
+	7,10,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,2,0,1,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,1,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,0,3,4,2,5,2,1,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,3,0,5,2,5,0,5,1,4,6,
+	7,10,2,3,0,2,3,0,4,3,1,4,5,1,4,5,1,0,5,2,4,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,0,3,5,2,4,1,0,6,
+	7,10,4,0,1,4,3,1,2,3,1,2,6,1,0,6,5,0,1,5,0,1,
+	7,10,3,2,6,3,5,6,0,5,2,0,5,2,1,5,2,1,4,2,5,4,
+	7,10,2,0,1,2,3,1,0,3,6,0,1,6,5,1,0,5,4,0,1,4,
+	7,10,6,4,1,2,6,5,3,4,4,5,0,5,6,0,6,1,6,2,6,3,
+	7,10,0,1,6,5,2,3,3,4,6,4,0,5,6,0,6,1,6,2,6,3,
+	7,10,0,1,2,0,3,2,4,3,1,4,2,1,0,5,5,2,6,1,2,6,
+	7,10,0,1,2,0,3,2,4,3,1,4,2,1,5,0,5,2,6,2,0,6,
+	7,10,6,4,1,2,6,5,3,4,4,5,0,5,6,3,6,1,6,2,0,4,
+	7,10,1,0,2,1,0,2,3,2,4,3,2,4,5,2,4,5,6,4,1,6,
+	7,10,0,1,0,3,0,4,0,5,0,6,1,2,1,3,1,4,2,5,2,6,
+	7,10,0,2,5,0,4,5,2,4,1,2,5,1,6,5,3,6,2,3,2,6,
+	7,10,0,1,2,0,3,2,4,3,1,4,2,1,5,1,0,5,6,0,2,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,2,6,4,0,2,4,0,
+	7,10,0,4,3,0,2,3,5,2,6,5,2,6,4,2,1,4,3,1,4,3,
+	7,10,1,6,2,1,0,2,1,0,4,1,3,4,2,3,5,6,4,5,3,1,
+	7,10,6,5,1,2,2,3,3,4,4,5,0,5,6,0,6,1,6,2,6,4,
+	7,10,0,1,6,5,2,3,3,4,6,4,0,5,6,0,6,1,6,2,5,3,
+	7,10,0,1,1,2,2,3,5,4,0,4,5,0,5,3,5,2,6,5,6,1,
+	7,10,0,3,2,0,1,2,3,1,4,3,2,4,0,4,6,0,5,6,0,5,
+	7,10,0,3,2,0,1,2,3,1,4,3,0,5,0,4,6,0,5,6,1,4,
+	7,10,0,1,6,5,2,3,3,4,6,4,0,5,6,0,6,1,6,2,4,2,
+	7,10,1,2,5,1,6,5,2,6,1,6,5,2,4,1,0,4,3,0,1,3,
+	7,10,4,2,6,2,5,3,4,1,2,0,6,3,5,2,0,1,0,4,6,0,
+	7,10,4,2,3,6,5,3,5,1,2,0,6,0,5,2,1,4,0,4,5,4,
+	7,10,4,0,5,4,4,1,2,1,3,2,0,3,3,4,5,3,6,1,6,5,
+	7,10,0,4,1,0,2,1,4,2,3,4,5,3,4,5,5,2,6,3,2,6,
+	7,10,1,6,2,1,0,2,1,0,4,1,3,4,2,3,5,6,4,5,4,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,3,6,1,6,5,5,1,
+	7,10,1,0,4,1,0,4,2,0,3,2,6,3,5,6,0,5,5,2,6,2,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,3,5,1,5,4,6,1,5,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,2,4,4,1,6,1,6,5,
+	7,10,0,1,2,0,3,2,4,3,1,4,2,1,5,3,2,5,6,1,4,6,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,2,5,4,6,5,6,0,0,2,
+	7,10,2,0,5,2,1,5,0,1,3,0,5,3,6,5,4,6,0,4,4,3,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,4,2,1,5,6,2,6,5,
+	7,10,5,0,6,5,2,6,3,2,0,3,4,0,2,4,4,3,1,4,3,1,
+	7,10,0,1,1,2,2,3,3,4,0,4,6,3,5,6,3,5,4,5,4,6,
+	7,10,5,2,2,1,3,2,4,3,1,4,5,0,6,1,6,0,1,5,2,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,2,6,4,4,2,5,1,
+	7,10,4,2,2,3,4,1,0,1,3,0,6,4,0,6,5,0,4,5,1,5,
+	7,10,2,1,5,2,3,5,0,3,4,0,6,4,3,6,1,3,4,1,5,4,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,6,5,6,3,
+	7,10,0,1,4,0,1,4,2,1,5,2,4,5,6,5,3,6,2,3,5,3,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,5,6,1,6,2,4,2,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,0,5,3,5,2,6,5,6,4,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,3,6,2,4,0,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,4,6,5,6,3,
+	7,10,0,5,6,0,1,6,0,1,1,5,2,1,3,2,4,3,6,4,4,5,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,5,6,4,2,0,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,1,6,5,6,3,
+	7,10,2,1,2,0,3,2,4,3,1,4,5,1,5,0,6,0,1,6,6,5,
+	7,10,0,1,1,2,2,3,3,4,0,4,5,3,5,1,6,1,6,4,6,5,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,5,2,4,1,6,0,5,6,
+	7,10,3,1,0,3,5,0,1,5,2,1,6,2,0,6,0,4,4,2,4,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,4,6,1,6,2,6,5,
+	7,10,0,3,2,0,1,2,3,1,4,3,2,4,5,4,5,0,6,4,6,1,
+	7,10,0,1,6,5,2,3,3,4,6,4,0,5,6,2,6,1,4,2,5,1,
+	7,10,5,2,6,5,2,6,4,2,0,4,3,0,2,3,1,0,1,3,4,1,
+	7,10,3,4,1,3,4,1,0,4,3,0,1,0,2,1,5,2,6,5,2,6,
+	7,10,5,6,2,5,6,2,3,6,0,3,4,0,5,4,1,4,3,1,2,1,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,1,6,5,4,2,
+	7,10,1,0,2,1,3,2,0,3,5,0,1,5,4,5,6,4,3,6,2,6,
+	7,10,0,1,1,2,2,3,3,4,4,5,0,5,4,1,2,5,6,0,3,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,1,5,
+	7,11,0,1,2,4,0,2,2,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,
+	7,11,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,0,2,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,5,1,
+	7,11,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,5,4,6,5,6,
+	7,11,3,6,1,3,2,1,0,2,5,0,6,5,2,6,5,1,0,3,1,6,0,1,
+	7,11,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,0,3,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,4,6,4,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,3,6,4,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,2,4,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,2,5,6,2,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,2,0,6,
+	7,11,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,6,5,
+	7,11,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,1,0,4,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,5,1,5,1,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,5,1,5,6,4,
+	7,11,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,4,5,1,0,1,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,2,4,2,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,5,1,5,5,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,2,6,
+	7,11,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,6,1,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,3,6,
+	7,11,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,6,4,
+	7,11,0,4,1,5,1,6,2,3,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,11,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,5,2,0,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,0,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,1,6,
+	7,11,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,5,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,5,4,3,5,1,5,0,6,
+	7,11,0,1,2,4,0,2,4,5,3,1,3,2,4,1,5,1,5,2,5,3,2,6,
+	7,11,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,3,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,2,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,5,6,
+	7,11,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,5,2,5,6,
+	7,11,0,1,2,4,0,2,4,5,3,1,3,2,4,1,5,1,5,2,5,3,5,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,4,5,6,
+	7,11,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,5,2,1,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,4,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,5,6,
+	7,11,0,1,2,4,0,2,4,5,3,1,3,2,4,1,5,1,5,2,5,3,4,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,4,0,2,4,1,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,6,5,6,2,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,5,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,2,4,0,2,1,3,5,1,1,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,1,6,
+	7,11,1,0,4,1,0,4,5,0,4,5,3,4,1,3,5,1,2,3,1,2,2,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,3,2,0,3,2,4,5,2,1,6,
+	7,11,0,6,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,5,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,4,1,5,3,2,5,1,0,1,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,2,4,0,2,1,3,5,1,5,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,2,4,0,2,1,3,5,1,6,3,
+	7,11,4,3,0,4,1,0,2,1,3,2,0,5,5,3,0,3,1,5,5,2,4,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,2,5,0,5,2,0,5,1,4,1,6,3,
+	7,11,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,3,2,0,3,1,6,
+	7,11,1,3,2,1,0,2,5,0,4,5,3,4,4,1,5,3,2,5,1,0,6,2,
+	7,11,0,1,2,4,0,2,4,5,3,1,3,2,4,1,5,1,5,2,5,3,0,6,
+	7,11,0,6,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,
+	7,11,6,5,0,6,5,0,1,5,6,1,2,6,5,2,3,5,6,3,4,6,5,4,
+	7,11,0,1,2,0,3,2,4,3,1,4,2,1,5,1,2,5,6,2,1,6,3,1,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,1,3,5,6,1,4,6,1,4,3,1,
+	7,11,1,4,2,3,4,2,0,6,4,5,6,5,3,1,6,4,3,0,3,6,4,3,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,4,2,6,4,2,6,5,2,0,2,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,4,0,3,0,2,0,6,0,3,6,
+	7,11,0,1,2,0,5,2,6,5,2,6,1,2,4,1,2,4,3,2,4,3,3,1,
+	7,11,4,5,1,4,2,1,3,2,6,3,5,6,2,5,4,2,3,5,0,5,2,0,
+	7,11,0,1,1,2,2,3,3,4,0,4,4,2,5,2,5,0,6,2,4,6,5,4,
+	7,11,0,1,1,2,2,3,3,4,0,4,6,1,2,6,0,2,6,0,5,2,0,5,
+	7,11,0,5,6,0,1,6,5,1,2,5,6,2,4,3,3,2,4,5,6,4,6,5,
+	7,11,0,5,6,0,1,6,5,1,2,5,6,2,3,6,5,3,4,5,6,4,4,3,
+	7,11,0,5,0,6,1,2,1,6,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,0,2,2,4,5,2,4,5,6,5,6,0,
+	7,11,0,1,1,2,2,3,3,4,4,5,5,6,0,6,4,2,0,4,2,0,6,4,
+	7,11,0,1,2,0,3,2,4,3,1,4,5,1,5,2,6,1,2,6,4,2,5,4,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,5,1,2,5,4,2,6,2,4,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,4,6,2,0,2,4,0,
+	7,11,0,1,1,2,2,3,3,4,0,4,3,1,5,3,4,5,1,4,6,5,6,1,
+	7,11,0,4,3,0,4,3,2,4,3,2,1,3,2,1,4,1,5,2,6,5,2,6,
+	7,11,0,5,0,6,1,4,1,6,2,3,2,5,3,4,3,5,3,6,4,5,4,6,
+	7,11,0,1,4,0,5,4,6,5,3,6,2,3,1,2,4,1,2,4,5,2,1,5,
+	7,11,0,4,3,0,4,3,2,4,6,2,1,6,5,1,2,5,3,2,1,3,4,1,
+	7,11,0,1,6,5,2,3,3,4,4,5,0,5,6,0,6,1,6,2,6,3,6,4,
+	7,11,4,1,0,4,1,0,3,1,0,3,5,1,6,5,1,6,2,1,5,2,6,2,
+	7,11,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,4,6,5,4,6,
+	7,11,1,0,2,1,3,2,4,3,0,4,2,0,5,2,6,5,3,6,6,0,0,5,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,0,2,4,0,6,4,0,6,3,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,2,0,5,2,6,5,4,6,0,5,6,0,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,6,0,2,6,3,6,0,3,4,0,
+	7,11,4,6,5,4,6,5,3,6,5,3,2,5,3,2,5,0,6,0,1,0,2,1,
+	7,11,2,0,4,2,5,4,3,5,1,3,0,1,2,1,3,2,6,3,5,6,4,3,
+	7,11,4,3,4,2,1,4,3,1,0,3,1,0,3,2,3,5,2,5,6,0,4,6,
+	7,11,0,1,0,2,2,3,5,1,1,3,5,2,6,3,6,0,5,3,4,5,3,4,
+	7,11,4,0,1,4,6,1,0,6,3,0,1,3,5,1,0,5,6,5,2,3,0,2,
+	7,11,0,1,5,0,4,5,1,4,2,1,3,2,4,3,4,2,6,4,2,6,3,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,5,1,3,5,6,3,4,6,5,6,
+	7,11,6,3,5,6,2,5,3,2,5,3,4,5,2,4,1,2,5,1,0,1,4,0,
+	7,11,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,1,6,5,4,6,
+	7,11,0,4,3,0,2,3,5,2,6,5,2,6,4,2,1,4,3,1,1,0,2,1,
+	7,11,5,0,0,1,3,0,5,3,2,5,6,2,4,6,5,4,1,5,6,1,3,6,
+	7,11,0,1,2,0,3,2,4,3,1,4,2,1,5,1,2,5,6,4,6,2,3,6,
+	7,11,3,2,6,3,5,6,0,5,2,0,1,2,0,1,5,1,2,5,4,2,6,4,
+	7,11,0,1,1,2,2,3,3,4,0,4,4,1,5,3,5,1,6,4,6,5,3,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,0,5,3,6,0,6,2,6,3,5,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,5,1,6,5,4,6,3,6,1,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,5,1,6,5,1,6,2,6,4,2,
+	7,11,0,1,1,2,2,3,0,3,4,0,4,3,4,2,6,1,6,4,5,2,3,5,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,5,1,6,1,4,6,6,5,2,6,
+	7,11,0,3,0,6,1,2,1,5,2,4,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,11,5,1,6,5,4,6,3,4,2,3,0,2,1,0,5,0,6,0,2,6,4,2,
+	7,11,1,0,2,1,3,2,4,3,0,4,5,2,3,5,6,0,6,5,6,2,3,6,
+	7,11,0,3,4,0,2,4,3,2,1,3,4,1,5,1,6,0,6,1,5,3,4,5,
+	7,11,0,5,0,6,1,3,1,4,2,3,2,5,2,6,3,4,4,5,4,6,5,6,
+	7,11,0,2,1,0,2,1,0,3,3,1,5,4,5,3,6,4,6,2,6,0,1,6,
+	7,11,4,1,5,4,2,5,1,2,0,1,5,0,6,5,3,6,2,3,0,2,4,0,
+	7,11,0,1,2,0,3,2,4,3,1,4,6,1,6,2,5,1,3,5,5,2,4,5,
+	7,11,0,5,0,6,1,4,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,6,3,6,4,6,2,2,0,4,0,
+	7,11,0,2,1,0,2,1,0,3,3,1,5,4,5,3,6,4,6,2,4,0,1,4,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,6,2,0,6,1,6,
+	7,11,0,3,4,0,1,4,3,1,4,3,0,1,2,4,6,2,5,6,2,5,1,2,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,6,1,6,5,
+	7,11,4,1,5,4,2,5,1,2,0,1,4,0,5,0,6,5,3,6,2,3,5,3,
+	7,11,0,1,1,2,2,3,0,3,4,0,4,3,4,2,5,1,5,4,6,5,4,6,
+	7,11,0,1,1,2,2,3,5,4,0,4,5,0,5,1,5,2,5,3,6,3,6,4,
+	7,11,0,4,3,0,1,3,4,1,3,4,5,1,6,5,1,6,2,1,5,2,6,2,
+	7,11,4,1,0,4,3,0,2,5,5,4,6,5,2,6,1,2,3,1,6,3,2,3,
+	7,11,0,1,1,2,2,3,0,3,4,0,4,2,5,4,5,3,6,0,6,5,3,6,
+	7,11,5,2,2,4,5,3,4,1,5,4,0,1,3,0,0,2,6,2,6,3,0,6,
+	7,11,0,1,1,2,2,3,3,4,0,4,5,0,5,4,5,2,5,3,6,1,0,6,
+	7,11,0,3,0,4,1,2,1,5,1,6,2,4,2,6,3,5,3,6,4,5,5,6,
+	7,11,4,0,3,4,5,3,0,5,1,0,2,1,3,2,4,1,5,2,6,4,5,6,
+	7,11,2,3,4,2,0,4,5,0,1,5,4,1,3,4,5,3,1,0,6,5,6,2,
+	7,11,4,1,0,4,3,0,4,3,5,4,6,5,2,6,1,2,3,1,6,3,2,5,
+	7,11,0,3,4,0,2,4,3,2,1,3,0,1,6,0,5,6,2,5,1,5,4,1,
+	7,11,0,3,0,4,1,4,1,5,1,6,2,3,2,5,2,6,3,6,4,5,5,6,
+	7,11,0,1,1,2,2,3,0,3,4,0,4,3,4,2,5,1,5,4,6,1,5,6,
+	7,11,4,1,5,4,6,5,3,6,2,3,1,2,0,1,5,0,4,0,5,2,6,2,
+	7,11,0,1,1,2,2,3,3,4,0,4,4,2,3,5,4,5,3,0,6,5,6,1,
+	7,11,0,4,1,0,4,1,3,4,2,3,1,2,6,1,5,6,3,5,5,4,2,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,5,1,4,2,6,2,3,6,4,6,
+	7,11,0,1,1,2,2,3,3,4,4,5,0,5,6,2,1,6,5,2,4,1,0,3,
+	7,11,0,3,0,4,1,2,1,5,1,6,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,11,0,1,1,2,2,3,5,4,0,4,5,3,5,1,6,3,6,4,4,2,0,3,
+	7,11,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,4,2,6,3,6,4,5,
+	7,11,4,3,2,4,3,2,0,3,2,1,5,4,5,0,6,4,6,1,1,5,0,6,
+	7,11,6,4,3,6,1,3,4,1,0,4,2,0,3,2,0,1,5,0,6,5,5,2,
+	7,11,6,1,2,6,1,2,0,1,3,0,4,3,5,4,3,5,2,0,4,0,5,6,
+	7,12,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,4,3,0,2,
+	7,12,3,6,1,3,2,1,0,2,5,0,6,5,2,6,5,1,0,3,1,6,0,1,0,6,
+	7,12,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,5,1,2,4,
+	7,12,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,2,3,
+	7,12,0,1,1,2,0,2,3,2,3,1,4,0,2,4,5,1,0,5,4,5,3,4,5,3,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,1,5,6,1,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,4,6,5,3,
+	7,12,0,1,2,4,0,2,2,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,1,6,
+	7,12,0,1,2,4,0,2,2,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,3,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,4,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,6,1,
+	7,12,0,1,2,4,0,2,2,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,0,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,0,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,2,6,
+	7,12,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,0,2,1,6,
+	7,12,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,0,2,4,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,0,2,6,1,6,5,
+	7,12,1,3,2,1,0,2,5,0,4,5,3,4,5,1,5,3,2,5,1,0,4,1,1,6,
+	7,12,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,3,5,0,3,5,6,
+	7,12,3,6,1,3,2,1,0,2,5,0,6,5,2,6,5,1,0,3,1,6,0,1,1,4,
+	7,12,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,3,5,0,3,3,6,
+	7,12,0,1,2,4,0,2,2,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,4,6,
+	7,12,1,3,2,1,0,2,5,0,4,5,3,4,5,1,5,3,2,5,1,0,4,1,2,6,
+	7,12,3,6,1,3,2,1,0,2,5,0,6,5,2,6,5,1,0,3,1,6,0,1,0,4,
+	7,12,1,3,4,1,3,4,2,3,0,2,4,0,5,4,2,5,4,2,0,5,1,5,3,6,
+	7,12,1,3,4,1,3,4,2,3,0,2,4,0,5,4,2,5,4,2,0,5,1,5,0,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,1,3,4,1,2,4,0,3,5,0,4,5,5,6,
+	7,12,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,0,3,5,6,
+	7,12,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,4,6,
+	7,12,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,0,6,
+	7,12,3,6,1,3,2,1,0,2,5,0,6,5,2,6,5,1,0,3,1,6,0,1,4,5,
+	7,12,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,3,6,
+	7,12,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,0,3,0,6,
+	7,12,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,0,2,5,6,
+	7,12,0,3,6,0,5,6,3,5,1,3,6,1,4,6,3,4,2,3,6,2,3,6,5,4,
+	7,12,0,1,4,0,5,4,1,5,4,1,2,4,1,2,6,1,4,6,2,6,3,2,4,3,
+	7,12,4,1,3,2,3,0,4,2,5,1,5,0,3,5,4,3,5,4,6,5,3,6,4,6,
+	7,12,0,1,1,2,0,2,3,0,3,1,3,2,4,2,3,4,5,3,0,5,6,3,1,6,
+	7,12,0,1,1,2,0,2,3,0,3,1,3,2,6,3,0,6,5,0,1,5,4,1,2,4,
+	7,12,6,2,5,6,3,5,2,3,1,2,4,1,5,4,2,5,4,2,0,4,1,0,5,1,
+	7,12,5,4,6,5,3,6,4,3,0,4,3,0,1,3,0,1,4,1,3,5,2,3,4,2,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,5,0,1,5,6,1,0,6,
+	7,12,1,2,0,1,2,0,3,2,0,3,1,3,4,2,0,4,5,4,2,5,6,2,1,6,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,2,4,5,6,4,3,6,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,5,0,1,5,6,1,2,6,
+	7,12,1,2,0,1,2,0,3,2,0,3,1,3,4,2,0,4,6,4,2,6,5,2,4,5,
+	7,12,1,0,2,1,0,2,3,0,4,3,0,4,5,0,3,5,4,5,6,4,3,6,6,0,
+	7,12,0,1,1,2,0,2,3,0,3,1,3,2,4,1,0,4,5,0,2,5,6,5,2,6,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,6,4,0,6,5,0,3,5,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,1,5,6,1,0,6,5,0,4,5,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,6,1,0,6,5,0,2,5,
+	7,12,5,4,3,5,4,3,6,4,3,6,2,3,4,2,0,4,3,0,1,0,2,1,6,2,
+	7,12,4,1,3,2,3,0,4,2,5,1,5,0,3,5,4,3,5,4,6,5,0,6,3,6,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,6,1,0,6,5,0,1,5,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,3,1,5,1,6,5,4,6,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,5,4,3,5,6,3,4,6,
+	7,12,1,0,2,1,3,2,0,3,4,3,1,4,4,0,5,4,0,5,3,5,6,0,1,6,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,6,2,4,6,5,0,1,5,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,5,4,2,5,1,5,6,1,5,6,
+	7,12,0,2,1,0,2,1,0,3,3,1,4,2,5,3,6,1,6,4,4,0,3,4,1,5,
+	7,12,0,1,1,2,0,2,3,0,3,2,4,3,4,1,0,4,5,2,5,4,6,0,3,6,
+	7,12,5,0,2,5,6,2,3,6,2,3,1,2,0,1,4,0,1,4,5,1,6,5,0,2,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,6,4,2,6,5,2,3,5,
+	7,12,0,2,1,0,5,1,3,5,6,3,2,6,4,2,3,4,5,4,2,5,1,2,4,1,
+	7,12,0,2,1,0,2,1,0,3,3,1,4,0,1,4,4,2,3,4,5,4,6,5,3,6,
+	7,12,0,1,1,2,0,2,3,0,3,1,3,2,6,1,2,6,4,6,3,4,5,3,6,5,
+	7,12,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,5,0,6,5,0,6,3,4,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,1,2,5,6,0,3,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,5,3,5,1,5,4,6,3,4,6,1,6,6,5,
+	7,12,0,5,0,6,1,3,1,4,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,12,0,1,1,2,2,3,3,4,0,4,5,2,6,5,0,6,6,2,0,5,1,5,6,1,
+	7,12,0,1,6,5,2,3,3,4,4,5,0,5,6,0,6,1,6,2,6,3,6,4,5,1,
+	7,12,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,6,1,5,6,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,1,4,5,6,4,5,6,
+	7,12,2,1,0,2,5,0,4,5,3,4,5,1,5,3,2,5,1,0,4,1,6,3,6,1,
+	7,12,0,4,0,6,1,3,1,5,1,6,2,3,2,5,2,6,3,5,4,5,4,6,5,6,
+	7,12,0,5,0,6,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,12,0,1,2,4,0,2,2,1,4,6,4,1,5,1,5,2,5,3,0,3,6,1,2,6,
+	7,12,0,1,1,2,2,3,5,4,0,4,5,3,5,1,6,3,6,4,4,2,0,3,4,3,
+	7,12,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,6,1,6,5,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,1,6,5,0,6,1,6,
+	7,12,0,3,4,0,2,4,3,2,1,3,4,1,1,0,5,1,5,2,6,1,2,6,4,6,
+	7,12,0,1,1,2,2,3,0,3,4,2,5,0,5,4,4,1,1,6,5,3,1,5,6,2,
+	7,12,0,1,1,2,2,3,0,3,4,2,5,0,5,4,4,1,1,5,5,3,6,1,4,6,
+	7,12,0,1,1,2,2,3,0,3,4,2,5,0,5,4,4,1,1,5,5,3,6,1,0,6,
+	7,12,4,3,1,2,0,1,0,3,4,0,6,4,4,2,5,4,6,2,6,3,3,2,5,1,
+	7,12,2,3,4,2,0,4,6,0,6,5,4,5,1,3,5,1,0,5,6,1,3,6,5,3,
+	7,12,0,3,0,5,1,2,1,5,1,6,2,4,2,6,3,4,3,6,4,5,4,6,5,6,
+	7,12,0,3,0,6,1,4,1,5,1,6,2,3,2,4,2,5,3,6,4,5,4,6,5,6,
+	7,12,0,1,1,2,2,3,4,5,0,4,4,3,5,3,6,1,3,6,6,2,0,6,4,6,
+	7,12,0,1,2,4,0,2,6,1,3,1,3,2,4,1,5,1,5,2,5,3,0,3,4,6,
+	7,12,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,6,3,1,6,
+	7,12,4,3,1,2,5,0,0,3,4,0,4,1,4,2,5,1,6,2,6,3,3,2,6,4,
+	7,12,2,3,4,2,5,4,0,5,6,0,1,6,3,1,6,3,5,3,1,5,4,0,3,0,
+	7,12,0,3,0,5,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,6,4,6,5,6,
+	7,12,3,2,1,2,5,0,0,3,4,0,4,1,6,4,5,1,6,2,6,3,6,1,0,6,
+	7,12,0,5,0,6,1,3,1,4,1,6,2,3,2,4,2,6,3,5,4,5,4,6,5,6,
+	7,12,0,3,0,5,1,2,1,4,1,6,2,4,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,12,0,3,0,6,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,4,6,5,6,
+	7,12,0,5,0,6,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,6,
+	7,12,0,1,1,2,2,3,0,3,4,2,5,0,5,4,4,1,3,4,5,3,2,6,6,1,
+	7,12,0,1,1,2,2,3,0,3,4,2,5,0,5,4,4,1,3,4,5,3,6,1,6,5,
+	7,12,0,2,0,6,1,4,1,5,1,6,2,3,2,5,3,4,3,5,3,6,4,5,4,6,
+	7,12,0,5,0,6,1,3,1,4,1,6,2,3,2,4,2,5,3,4,3,6,4,5,5,6,
+	7,12,0,1,1,2,2,3,0,3,4,1,2,4,5,2,0,5,4,3,6,5,6,4,3,5,
+	7,12,0,2,0,6,1,2,1,4,1,5,2,3,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,12,0,2,0,6,1,3,1,4,1,5,2,4,2,5,3,4,3,5,3,6,4,6,5,6,
+	7,12,0,2,0,6,1,3,1,4,1,5,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,12,0,5,0,6,1,3,1,4,1,6,2,3,2,4,2,6,3,4,3,5,4,5,5,6,
+	7,12,0,5,0,6,1,2,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,
+	7,12,3,0,2,3,4,2,0,4,5,1,5,2,6,1,6,0,3,6,5,3,4,5,6,4,
+	7,12,0,5,0,6,1,2,1,3,1,4,2,3,2,4,3,5,3,6,4,5,4,6,5,6,
+	7,12,0,1,0,2,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,12,3,0,2,3,4,2,0,4,5,1,5,2,6,1,6,0,3,6,5,3,6,4,1,3,
+	7,12,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,4,2,5,3,6,4,6,5,6,
+	7,12,2,3,4,2,5,2,4,1,6,0,3,0,3,1,6,3,5,6,1,5,4,0,3,4,
+	7,12,2,3,4,2,4,1,2,5,6,0,6,4,3,1,6,3,0,3,1,5,4,0,5,3,
+	7,12,0,4,0,5,0,6,1,2,1,3,1,6,2,3,2,6,3,5,4,5,4,6,5,6,
+	7,12,3,0,2,3,4,2,0,4,5,1,5,2,6,1,6,0,3,6,1,3,6,4,5,4,
+	7,12,6,3,1,2,2,3,0,3,4,2,5,0,0,6,4,1,3,4,6,5,5,1,0,4,
+	7,12,0,3,0,5,0,6,1,2,1,5,1,6,2,4,2,6,3,4,3,5,4,5,4,6,
+	7,12,0,3,0,5,0,6,1,2,1,4,1,6,2,3,2,5,3,4,4,5,4,6,5,6,
+	7,12,0,3,0,5,0,6,1,2,1,5,1,6,2,3,2,4,3,4,4,5,4,6,5,6,
+	7,12,0,4,3,0,1,3,4,1,1,0,4,5,2,4,6,2,5,6,2,5,3,2,6,3,
+	7,12,0,1,1,2,2,3,0,3,4,0,4,1,5,2,5,4,6,4,6,3,6,2,5,3,
+	7,12,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,5,2,6,3,4,4,5,4,6,
+	7,12,3,0,4,2,3,1,4,0,5,2,5,1,4,3,5,4,3,5,6,1,0,6,2,6,
+	7,12,1,0,4,1,0,4,5,0,6,5,1,6,3,4,5,3,2,3,5,2,6,3,2,6,
+	7,12,0,1,2,0,2,3,3,4,0,4,0,5,6,1,4,6,6,5,2,6,3,1,5,3,
+	7,12,0,1,1,2,2,3,3,4,4,5,0,5,6,0,6,1,6,2,6,3,6,4,6,5,
+	7,12,3,6,1,2,0,6,0,3,4,0,4,1,4,2,4,3,5,1,2,5,4,5,6,4,
+	7,13,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,6,1,4,1,5,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,4,3,0,2,6,4,
+	7,13,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,0,4,1,6,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,2,3,2,4,2,5,2,6,3,6,4,5,5,6,
+	7,13,0,6,1,4,1,5,1,6,2,3,2,4,2,5,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,3,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,13,0,6,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,5,6,
+	7,13,0,6,1,3,1,4,1,5,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,13,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,4,5,1,6,
+	7,13,0,1,1,2,2,3,4,5,0,4,1,3,4,1,2,4,0,3,5,3,4,3,0,2,5,6,
+	7,13,0,5,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,6,4,6,5,6,
+	7,13,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,13,5,6,0,5,6,0,4,6,5,4,1,5,6,1,3,6,5,3,2,5,6,2,1,0,2,1,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,2,3,2,4,2,6,
+	7,13,3,4,0,3,4,0,1,4,3,1,2,3,4,2,1,0,2,1,6,0,3,6,5,3,4,5,
+	7,13,3,4,0,3,4,0,1,4,3,1,2,3,4,2,1,0,2,1,6,0,3,6,5,3,0,5,
+	7,13,3,4,0,3,4,0,1,4,3,1,2,3,4,2,1,0,2,1,6,4,0,6,5,0,3,5,
+	7,13,0,5,0,6,1,3,1,4,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,2,3,2,4,3,5,4,6,
+	7,13,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,5,1,6,5,1,6,
+	7,13,0,4,0,6,1,3,1,5,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,5,0,6,1,4,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,5,6,
+	7,13,0,5,0,6,1,3,1,4,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,13,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,5,3,6,5,4,6,
+	7,13,0,5,0,6,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,13,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,6,1,6,5,5,1,
+	7,13,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,4,0,5,6,0,3,6,6,4,
+	7,13,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,6,1,5,1,2,6,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,2,3,2,4,5,6,
+	7,13,1,0,2,1,4,2,1,4,3,1,0,3,2,3,5,2,1,5,0,5,6,0,1,6,2,6,
+	7,13,2,5,6,2,5,6,4,5,3,4,0,3,4,0,1,4,3,1,6,3,2,1,4,2,3,2,
+	7,13,0,3,0,6,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,13,2,4,3,2,1,3,4,1,0,4,3,0,6,3,1,6,5,1,4,5,6,4,3,5,1,2,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,2,4,2,5,3,5,3,6,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,2,3,2,4,3,5,5,6,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,2,3,2,5,3,6,4,5,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,6,2,4,2,5,3,4,3,5,
+	7,13,0,2,0,6,1,4,1,5,1,6,2,3,2,5,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,2,5,1,2,5,1,4,5,3,4,0,3,4,0,3,2,4,2,1,3,6,3,2,6,1,6,
+	7,13,0,4,0,6,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,5,3,6,4,5,5,6,
+	7,13,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,0,4,6,1,4,6,
+	7,13,2,3,0,2,3,0,4,3,1,4,5,1,4,5,1,0,5,2,5,0,6,5,1,6,4,0,
+	7,13,0,1,1,2,0,2,3,0,1,3,3,2,4,0,2,5,3,4,5,3,0,5,6,4,6,1,
+	7,13,2,3,0,2,3,0,4,3,1,4,5,1,4,5,1,0,5,2,6,2,5,6,0,5,1,2,
+	7,13,5,4,6,2,6,4,4,3,5,0,3,1,3,2,6,3,5,6,4,0,1,4,5,1,0,3,
+	7,13,0,2,0,6,1,3,1,4,1,5,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,1,5,4,1,0,4,5,0,2,5,4,2,3,4,5,3,0,1,2,0,3,2,6,5,6,4,
+	7,13,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,0,4,0,6,4,6,
+	7,13,0,4,3,0,2,3,4,2,1,4,3,1,1,0,5,0,4,5,1,5,6,1,0,6,3,6,
+	7,13,0,5,0,6,1,2,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,1,3,2,1,0,2,5,0,4,5,3,4,4,1,5,3,2,5,1,0,6,3,4,6,5,1,
+	7,13,5,2,0,2,3,0,4,3,1,4,5,1,4,5,1,0,6,2,6,3,1,2,3,1,4,0,
+	7,13,1,0,2,1,0,2,0,3,3,2,6,2,1,6,5,1,6,5,4,6,5,4,0,5,4,0,
+	7,13,0,5,0,6,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,6,
+	7,13,0,5,0,6,1,3,1,4,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,13,0,1,1,2,4,1,3,1,0,4,2,3,0,3,2,0,5,0,6,5,4,6,3,5,4,2,
+	7,13,0,5,0,6,1,2,1,3,1,4,2,4,2,5,2,6,3,4,3,5,3,6,4,6,5,6,
+	7,13,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,0,4,2,3,6,5,0,6,
+	7,13,5,2,0,2,3,0,4,3,1,4,5,1,4,5,1,0,6,2,6,3,2,3,5,0,4,0,
+	7,13,0,1,1,2,2,3,5,4,0,4,5,0,5,1,5,2,5,3,6,3,6,4,4,2,0,3,
+	7,13,0,1,0,6,1,4,1,5,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,6,5,6,
+	7,13,0,1,0,6,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,13,0,1,1,2,2,3,3,4,0,4,6,2,0,6,5,0,2,5,5,3,4,5,6,4,3,6,
+	7,13,0,1,1,2,2,3,3,4,0,4,6,5,0,6,0,2,2,5,5,3,4,5,6,4,3,6,
+	7,13,3,4,0,3,4,0,3,6,3,1,2,3,4,2,1,0,2,1,5,2,3,5,6,2,5,6,
+	7,13,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,6,5,3,6,4,6,
+	7,13,1,0,2,1,6,0,1,4,3,1,0,3,2,3,1,6,1,5,2,6,4,3,5,4,6,5,
+	7,13,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,2,5,2,6,3,5,4,6,
+	7,13,0,6,1,2,2,3,0,3,4,2,5,0,6,3,4,1,3,4,6,5,1,5,3,5,1,3,
+	7,13,0,1,1,2,2,3,0,3,4,0,4,1,6,4,4,3,5,4,5,2,6,0,3,6,3,5,
+	7,13,0,1,1,2,2,3,3,6,0,4,6,5,0,6,6,4,2,5,5,3,4,5,1,5,6,1,
+	7,13,0,4,0,5,0,6,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,13,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,5,2,6,3,4,4,5,4,6,5,6,
+	7,13,2,3,5,2,6,5,3,6,4,3,5,4,0,5,2,0,1,2,0,1,5,1,4,2,6,4,
+	7,13,2,1,0,5,6,0,4,6,5,4,1,5,6,1,3,6,5,3,2,5,6,2,1,0,3,4,
+	7,13,0,1,2,0,2,3,3,4,0,4,0,5,6,1,4,6,6,5,2,6,3,1,5,3,6,0,
+	7,13,0,4,0,5,0,6,1,2,1,5,1,6,2,3,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,13,2,3,0,2,3,0,4,3,4,6,5,1,4,5,3,1,5,2,6,0,6,1,2,1,4,1,
+	7,13,0,1,1,2,2,3,0,3,4,0,4,1,4,3,5,4,5,2,5,1,6,5,1,6,2,6,
+	7,13,0,4,0,5,0,6,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,5,3,6,4,6,
+	7,13,3,0,2,3,4,2,0,4,5,1,5,2,6,1,6,0,3,6,1,3,6,4,5,4,5,3,
+	7,13,0,4,0,5,0,6,1,2,1,4,1,5,2,3,2,6,3,4,3,5,3,6,4,6,5,6,
+	7,13,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,4,2,5,3,4,3,6,4,6,5,6,
+	7,13,0,2,0,5,0,6,1,2,1,4,1,6,2,3,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,3,4,5,0,3,5,0,6,6,4,2,3,4,2,1,0,2,1,1,6,5,1,2,5,6,2,
+	7,13,0,2,0,5,0,6,1,2,1,3,1,4,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,13,3,0,2,3,4,2,0,4,5,3,5,2,5,4,1,3,1,0,4,1,6,0,3,6,1,6,
+	7,13,2,3,0,2,3,0,4,3,1,4,5,1,4,5,6,0,1,6,6,3,4,6,1,2,5,0,
+	7,13,0,4,0,5,0,6,1,2,1,3,1,6,2,3,2,5,2,6,3,4,3,5,4,5,4,6,
+	7,13,0,4,0,5,0,6,1,2,1,3,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,
+	7,13,0,1,1,2,2,3,0,3,4,0,4,1,5,3,5,4,6,4,6,2,6,5,5,2,3,6,
+	7,13,0,1,0,5,0,6,1,3,1,4,2,3,2,4,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,13,0,1,0,5,0,6,1,3,1,4,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,13,0,1,2,0,2,3,3,4,0,4,0,5,6,1,4,6,6,5,2,6,3,1,5,3,2,1,
+	7,14,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,1,3,2,0,4,0,5,3,
+	7,14,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,2,3,0,4,1,6,
+	7,14,0,6,1,3,1,4,1,5,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,2,4,2,5,2,6,3,4,3,5,3,6,4,6,5,6,
+	7,14,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,14,0,3,1,2,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,3,6,5,3,4,5,6,4,
+	7,14,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,6,2,1,6,5,1,0,5,
+	7,14,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,5,2,3,5,6,4,0,6,
+	7,14,3,4,1,3,2,1,0,2,5,0,4,5,2,4,5,1,0,3,1,4,0,1,0,4,6,4,0,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,3,4,3,5,4,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,6,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,14,3,4,1,3,2,1,0,2,5,0,4,5,0,1,5,1,0,4,1,4,5,3,2,5,6,4,0,6,
+	7,14,1,3,2,1,0,2,5,0,4,5,3,4,5,3,2,5,1,0,4,1,6,1,5,1,2,6,0,4,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,6,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,14,2,3,4,2,6,3,4,0,6,0,3,4,3,1,5,4,5,0,0,3,1,5,5,3,6,4,6,1,
+	7,14,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,5,3,6,5,4,6,5,4,
+	7,14,3,1,1,4,2,3,3,4,0,4,1,5,0,1,0,2,2,5,5,3,4,5,1,2,6,2,5,6,
+	7,14,0,3,0,6,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,14,0,3,0,6,1,2,1,4,1,5,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,5,0,6,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,14,0,1,0,6,1,4,1,5,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,5,0,6,1,2,1,3,1,4,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,4,6,5,2,1,5,0,5,6,3,
+	7,14,0,1,1,2,2,3,3,4,0,4,5,0,5,1,5,2,5,3,5,4,4,2,3,0,6,1,5,6,
+	7,14,0,4,0,6,1,2,1,3,1,5,1,6,2,3,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,14,0,4,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,5,5,6,
+	7,14,0,5,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,14,2,3,0,2,3,0,4,3,1,4,5,1,1,2,5,2,4,0,3,1,5,0,6,5,6,4,0,1,
+	7,14,2,3,0,2,3,0,4,3,1,4,5,1,4,5,5,2,6,0,6,1,5,0,1,2,3,1,4,0,
+	7,14,5,6,0,5,6,0,4,6,5,4,1,5,6,1,3,6,5,3,2,5,6,2,1,0,2,1,3,4,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,5,1,6,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,14,0,1,2,0,2,3,3,4,0,4,0,5,6,1,4,6,6,5,2,6,3,1,5,3,6,0,3,6,
+	7,14,3,1,4,2,4,5,4,0,1,4,0,3,5,0,5,2,6,1,3,6,6,0,5,6,6,2,4,6,
+	7,14,0,4,3,0,2,3,4,2,1,4,3,1,1,0,2,1,5,4,1,5,6,1,3,6,0,5,6,0,
+	7,14,3,4,4,2,1,5,4,0,1,4,5,3,3,0,5,2,6,4,0,6,3,6,2,6,5,6,1,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,4,1,5,2,3,2,6,3,6,4,5,4,6,5,6,
+	7,14,2,3,4,2,6,3,4,0,4,5,3,4,3,1,5,2,1,6,5,6,6,0,5,3,6,4,0,1,
+	7,14,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,4,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,14,0,4,0,5,0,6,1,2,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,14,2,3,4,2,6,3,4,0,1,4,6,0,3,1,5,2,4,5,5,6,1,5,5,3,6,4,3,0,
+	7,14,3,1,4,2,0,3,4,0,1,4,5,3,5,0,5,2,6,4,1,6,6,3,0,6,6,5,2,6,
+	7,14,0,1,4,2,3,0,4,0,4,5,5,3,1,3,5,2,6,4,2,6,6,5,3,6,6,1,0,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,6,2,5,3,4,3,5,3,6,4,5,4,6,
+	7,14,0,1,0,2,0,3,0,4,0,5,0,6,1,5,1,6,2,3,2,4,3,5,3,6,4,5,4,6,
+	7,14,2,3,4,2,6,3,4,0,1,4,6,1,3,1,5,2,5,0,5,6,4,5,5,3,6,0,3,0,
+	7,14,2,3,4,2,3,0,4,0,4,5,3,4,3,1,5,2,0,1,5,6,6,0,5,3,6,4,1,6,
+	7,14,0,4,0,5,0,6,1,3,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,14,0,3,0,4,0,6,1,2,1,4,1,5,2,3,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,4,0,5,0,6,1,2,1,3,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,5,6,
+	7,14,0,1,0,5,0,6,1,4,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,5,6,
+	7,14,0,1,0,4,0,6,1,3,1,5,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,14,2,3,4,2,6,3,4,0,1,4,4,5,3,1,5,2,5,0,6,1,0,6,5,3,6,4,3,0,
+	7,14,0,1,0,5,0,6,1,3,1,4,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,4,0,5,0,6,1,2,1,3,1,4,2,3,2,5,2,6,3,5,3,6,4,5,4,6,5,6,
+	7,14,0,4,0,5,0,6,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,5,6,
+	7,14,2,3,4,2,6,3,4,0,4,5,3,5,3,1,5,2,3,0,1,4,6,0,1,6,6,4,0,1,
+	7,14,0,4,0,5,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,6,
+	7,14,0,4,0,5,0,6,1,2,1,3,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,5,4,6,
+	7,14,0,4,0,5,0,6,1,2,1,3,1,5,1,6,2,3,2,4,2,6,3,4,3,5,4,6,5,6,
+	7,14,0,3,0,4,0,5,1,2,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,6,5,6,
+	7,14,0,3,0,4,0,5,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,6,4,6,5,6,
+	7,14,0,1,1,2,2,3,3,4,4,5,5,6,0,6,0,2,5,0,3,5,1,3,6,1,4,6,2,4,
+	7,14,0,3,0,4,0,5,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,6,4,5,
+	7,15,0,1,0,2,0,3,0,4,0,5,1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,
+	7,15,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,1,3,2,0,4,0,5,3,1,6,
+	7,15,0,1,1,2,2,3,3,4,4,5,0,5,2,4,5,2,1,5,1,4,1,3,2,0,4,0,5,3,0,6,
+	7,15,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,3,4,3,5,3,6,5,6,
+	7,15,0,1,0,2,0,3,0,4,0,5,0,6,1,5,1,6,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,15,3,4,4,5,0,3,0,4,0,5,0,6,3,6,4,6,5,6,1,5,3,5,2,3,2,4,1,6,0,1,
+	7,15,3,4,4,5,0,3,0,4,0,5,0,6,3,6,1,3,1,4,1,5,3,5,2,3,2,4,6,1,4,6,
+	7,15,0,1,1,2,2,3,0,3,4,0,4,1,4,2,4,3,5,1,0,5,5,2,3,5,4,5,6,1,5,6,
+	7,15,4,3,4,5,5,3,0,1,0,5,0,3,2,4,1,5,1,3,6,5,3,6,6,0,1,6,6,2,4,6,
+	7,15,3,4,4,5,5,6,0,4,0,5,0,6,3,6,1,3,4,6,1,5,3,5,2,3,2,4,1,6,0,1,
+	7,15,0,2,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,15,6,1,4,5,0,3,0,4,0,5,0,6,3,6,1,3,1,4,1,5,3,5,2,3,2,4,5,6,4,6,
+	7,15,3,4,4,5,0,3,0,4,0,5,4,6,3,6,1,3,1,4,1,5,3,5,2,3,2,4,5,6,5,2,
+	7,15,3,4,4,5,0,3,0,4,6,0,4,6,3,6,1,3,1,4,1,5,3,5,2,3,2,4,5,6,5,2,
+	7,15,0,1,1,2,0,2,3,0,1,3,2,3,5,1,3,5,4,3,2,4,6,2,3,6,6,1,0,5,4,0,
+	7,15,0,1,2,0,3,2,4,3,1,4,3,1,4,2,0,4,3,0,6,3,4,6,5,4,3,5,6,2,5,1,
+	7,15,0,1,0,2,0,3,0,4,1,2,1,3,1,4,2,3,2,4,3,4,5,3,4,5,6,4,5,6,6,3,
+	7,15,0,1,1,2,2,3,0,3,4,0,4,3,4,2,6,1,2,6,5,2,4,5,6,4,0,6,6,5,3,6,
+	7,15,0,1,5,3,1,3,0,4,3,0,4,3,2,4,5,2,4,5,6,4,2,6,6,5,3,6,6,1,0,6,
+	7,15,5,2,4,5,3,1,0,4,0,5,0,3,2,4,1,5,1,4,6,3,1,6,6,0,5,6,6,2,4,6,
+	7,15,0,1,1,2,2,3,3,4,4,5,0,5,0,3,2,0,3,1,6,4,5,6,6,3,0,6,6,2,1,6,
+	7,15,5,2,3,0,5,3,0,4,0,5,4,3,2,4,1,5,1,4,6,4,2,6,6,0,5,6,6,3,1,6,
+	7,15,0,4,0,5,0,6,1,2,1,3,1,6,2,3,2,4,2,5,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,15,6,1,4,5,0,3,0,4,0,5,4,6,3,6,1,3,1,4,0,6,3,5,2,3,2,4,5,6,5,2,
+	7,15,3,4,0,1,0,3,0,4,0,5,4,6,3,6,1,3,1,4,6,0,1,6,2,3,2,4,5,6,5,2,
+	7,15,0,1,0,2,0,3,0,4,0,5,0,6,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,6,
+	7,15,5,2,4,5,5,3,0,4,0,1,1,3,2,4,3,0,1,4,6,4,1,6,6,0,3,6,6,2,5,6,
+	7,15,5,0,4,3,5,3,5,2,0,1,1,3,2,4,3,0,1,4,6,2,5,6,6,4,3,6,6,0,1,6,
+	7,15,3,4,4,5,0,3,4,6,0,1,1,6,3,6,1,3,1,4,6,0,0,5,2,3,2,4,5,6,5,2,
+	7,15,0,2,0,3,0,6,1,3,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,15,0,4,0,5,0,6,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,15,3,4,5,0,0,3,0,4,4,6,1,6,3,6,1,3,1,4,6,0,1,5,2,3,2,4,5,6,5,2,
+	7,15,6,4,5,2,0,3,0,4,2,4,1,6,3,6,1,3,1,4,6,0,3,5,2,3,0,1,5,6,4,5,
+	7,15,0,4,0,5,0,6,1,2,1,3,1,5,1,6,2,3,2,4,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,15,0,1,0,2,0,3,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,15,2,3,0,2,3,0,4,3,1,4,5,1,4,5,1,0,5,2,6,2,5,6,6,1,0,6,6,4,3,6,
+	7,15,3,0,3,5,3,4,2,0,2,5,2,4,1,4,1,5,1,0,6,0,1,6,6,5,3,6,6,4,2,6,
+	7,15,0,3,0,4,0,5,0,6,1,2,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,15,3,4,6,2,0,3,0,4,5,0,1,6,3,6,1,3,1,4,6,0,4,5,2,3,2,4,5,1,5,2,
+	7,15,3,4,6,2,0,3,0,4,5,0,5,6,3,6,1,3,1,4,0,1,4,6,2,3,2,4,5,1,5,2,
+	7,15,0,1,1,2,2,3,3,4,0,4,6,2,1,6,6,0,4,6,5,4,0,5,3,5,6,3,5,2,1,5,
+	7,16,0,1,0,2,0,3,0,4,0,5,1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,2,6,
+	7,16,3,0,4,1,4,3,1,3,4,0,2,5,6,2,5,6,1,5,4,5,3,5,0,5,0,6,3,6,4,6,6,1,
+	7,16,0,1,0,2,0,3,0,4,0,5,0,6,1,6,2,3,2,4,2,5,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,16,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,
+	7,16,3,4,5,1,0,3,0,4,5,0,4,6,3,6,1,3,1,4,6,0,3,5,2,3,2,4,5,6,4,5,2,5,
+	7,16,2,4,3,1,3,0,4,3,4,0,5,2,4,5,5,0,3,5,5,1,6,5,1,6,3,6,6,0,4,6,6,2,
+	7,16,0,1,0,2,0,3,0,4,0,5,0,6,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,16,2,4,4,1,3,0,3,1,4,0,5,2,4,5,5,0,3,5,6,5,1,5,6,1,3,6,4,6,6,2,6,0,
+	7,16,0,1,0,3,0,5,0,6,1,3,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,16,2,5,0,1,4,5,1,3,5,0,4,3,5,3,2,4,1,4,3,0,6,3,2,6,6,4,5,6,6,1,0,6,
+	7,16,0,1,0,2,0,3,0,4,0,5,0,6,1,3,1,6,2,4,2,5,2,6,3,4,3,5,4,5,4,6,5,6,
+	7,16,2,5,5,1,3,1,0,4,5,0,4,3,5,3,2,4,1,4,3,0,6,2,4,6,5,6,6,1,0,6,3,6,
+	7,16,1,6,0,1,0,3,0,4,5,0,4,6,3,6,1,3,1,4,6,0,3,5,2,3,2,4,5,6,4,5,2,5,
+	7,16,3,4,5,1,0,3,0,4,5,0,4,6,3,6,1,3,1,4,6,0,1,6,2,3,2,4,5,6,0,1,2,5,
+	7,16,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,5,2,6,3,4,3,6,4,5,
+	7,16,0,1,0,2,0,3,0,4,0,5,0,6,1,4,1,5,1,6,2,3,2,5,2,6,3,4,3,6,4,5,5,6,
+	7,16,0,1,0,2,0,3,0,4,0,5,0,6,1,4,1,5,1,6,2,4,2,5,2,6,3,4,3,5,3,6,5,6,
+	7,16,2,5,5,1,3,5,0,4,0,1,4,3,3,2,2,4,1,4,0,5,6,4,2,6,6,3,5,6,6,1,0,6,
+	7,16,5,6,5,1,0,3,0,4,0,1,4,6,3,6,1,3,1,4,6,0,3,5,2,3,2,4,6,2,4,5,2,5,
+	7,16,3,4,5,1,0,3,0,4,0,1,4,6,3,6,1,3,1,4,6,0,5,0,2,3,2,4,6,2,6,5,2,5,
+	7,16,5,0,5,1,0,3,0,4,6,1,4,6,3,6,1,3,1,4,6,0,3,5,2,3,2,4,6,2,4,5,2,5,
+	7,17,0,1,0,2,0,3,0,4,0,5,1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,6,2,1,6,
+	7,17,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,4,5,4,6,
+	7,17,4,0,4,3,0,1,3,0,2,4,3,1,5,3,4,5,5,2,6,5,5,0,1,5,6,1,0,6,6,4,2,6,3,6,
+	7,17,0,1,5,1,5,3,0,4,5,0,4,3,3,1,2,5,1,4,3,0,2,4,6,2,5,6,6,3,1,6,6,0,4,6,
+	7,17,3,4,5,1,0,3,0,4,4,5,4,6,3,6,1,3,1,4,0,1,3,5,2,3,2,4,2,5,5,0,5,6,6,2,
+	7,17,3,2,4,1,0,1,3,0,2,4,4,3,5,1,4,5,5,2,0,5,5,3,6,5,2,6,6,3,0,6,1,6,4,6,
+	7,17,3,2,4,1,4,0,3,0,2,4,3,1,5,2,4,5,5,0,3,5,5,1,6,5,2,6,6,0,3,6,6,4,1,6,
+	7,17,3,2,5,1,5,0,0,4,0,1,4,3,5,3,2,5,1,4,3,0,2,4,6,4,5,6,6,2,3,6,6,0,1,6,
+	7,17,3,2,5,1,5,0,0,4,4,5,0,1,3,1,2,5,1,4,3,0,2,4,6,0,3,6,6,1,5,6,6,2,4,6,
+	7,17,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,5,3,6,4,5,4,6,
+	7,18,0,1,0,2,0,3,0,4,0,5,1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,6,1,0,6,5,6,
+	7,18,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,
+	7,18,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,4,1,5,2,3,2,4,2,5,2,6,3,4,3,6,4,5,4,6,5,6,
+	7,18,0,1,0,2,0,3,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,18,4,0,4,5,3,0,3,5,2,0,2,5,1,3,1,4,1,5,1,0,2,3,2,4,6,0,5,6,6,1,2,6,6,4,3,6,
+	7,19,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,19,0,1,0,2,0,3,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,6,4,5,4,6,5,6,
+	7,20,0,1,0,2,0,3,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+	7,21,0,1,0,2,0,3,0,4,0,5,0,6,1,2,1,3,1,4,1,5,1,6,2,3,2,4,2,5,2,6,3,4,3,5,3,6,4,5,4,6,5,6,
+};
+
+const long int igraph_i_atlas_edges_pos[]={0, 2, 4, 6, 10, 12, 16, 22, 30, 32, 36, 42, 48, 56, 64, 72, 82, 92, 104, 118, 120, 124, 130, 136, 144, 152, 160, 168, 178, 188, 198, 208, 218, 228, 240, 252, 264, 276, 288, 300, 314, 328, 342, 356, 370, 384, 400, 416, 432, 448, 466, 484, 504, 526, 528, 532, 538, 544, 552, 560, 568, 576, 584, 594, 604, 614, 624, 634, 644, 654, 664, 674, 686, 698, 710, 722, 734, 746, 758, 770, 782, 794, 806, 818, 830, 842, 854, 868, 882, 896, 910, 924, 938, 952, 9 [...]
+
+__END_DECLS
diff --git a/src/atlas.c b/src/atlas.c
new file mode 100644
index 0000000..1f38ce7
--- /dev/null
+++ b/src/atlas.c
@@ -0,0 +1,82 @@
+/* -*- mode: C -*-  */
+/* 
+   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
+   (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_constructors.h"
+#include "atlas-edges.h"
+#include "config.h"
+
+/**
+ * \function igraph_atlas
+ * \brief Create a small graph from the \quote Graph Atlas \endquote.
+ * 
+ * </para><para>
+ * The number of the graph is given as a parameter. 
+ * The graphs are listed: \olist
+ *      \oli in increasing order of number of nodes;
+ *      \oli for a fixed number of nodes, in increasing order of the 
+ *           number of edges;
+ *      \oli for fixed numbers of nodes and edges, in increasing 
+ *           order of the degree sequence, for example 111223 < 112222; 
+ *      \oli for fixed degree sequence, in increasing number of 
+ *           automorphisms.
+ *      \endolist
+ *
+ * </para><para>
+ * The data was converted from the NetworkX software package, 
+ * see http://networkx.github.io .
+ * 
+ * </para><para>
+ * See \emb An Atlas of Graphs \eme by Ronald C. Read and Robin J. Wilson, 
+ * Oxford University Press, 1998.
+ * 
+ * \param graph Pointer to an uninitialized graph object. 
+ * \param number The number of the graph to generate.
+ * 
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number of 
+ * edges.
+ * 
+ * \example examples/simple/igraph_atlas.c
+ */
+int igraph_atlas(igraph_t *graph, int number) {
+  
+  igraph_integer_t pos, n, e;
+  igraph_vector_t v=IGRAPH_VECTOR_NULL;
+
+  if (number < 0 ||
+      number >= (int) (sizeof(igraph_i_atlas_edges_pos)/sizeof(long int))) {
+    IGRAPH_ERROR("No such graph in atlas", IGRAPH_EINVAL);
+  }
+
+  pos=(igraph_integer_t) igraph_i_atlas_edges_pos[number];
+  n=(igraph_integer_t) igraph_i_atlas_edges[pos];
+  e=(igraph_integer_t) igraph_i_atlas_edges[pos+1];
+  
+  IGRAPH_CHECK(igraph_create(graph, 
+			     igraph_vector_view(&v,igraph_i_atlas_edges+pos+2, 
+						e*2),  
+			     n, IGRAPH_UNDIRECTED));
+  
+  return 0;
+}
diff --git a/src/attributes.c b/src/attributes.c
new file mode 100644
index 0000000..50b40eb
--- /dev/null
+++ b/src/attributes.c
@@ -0,0 +1,430 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_attributes.h"
+#include "igraph_memory.h"
+#include "config.h"
+
+#include <string.h>
+#include <stdarg.h>
+
+/* Should you ever want to have a thread-local attribute handler table, prepend
+ * IGRAPH_THREAD_LOCAL to the following declaration */
+igraph_attribute_table_t *igraph_i_attribute_table=0;
+
+int igraph_i_attribute_init(igraph_t *graph, void *attr) {
+  graph->attr=0;
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->init(graph, attr);
+  } else {
+    return 0;
+  }
+}
+  
+void igraph_i_attribute_destroy(igraph_t *graph) {
+  if (igraph_i_attribute_table) {
+    igraph_i_attribute_table->destroy(graph);
+  }
+}
+  
+int igraph_i_attribute_copy(igraph_t *to, const igraph_t *from, igraph_bool_t ga,
+			    igraph_bool_t va, igraph_bool_t ea) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->copy(to, from, ga, va, ea);
+  } else {
+    return 0;
+    }
+  }
+  
+int igraph_i_attribute_add_vertices(igraph_t *graph, long int nv, void *attr) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->add_vertices(graph, nv, attr);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_permute_vertices(const igraph_t *graph, 
+					igraph_t *newgraph,
+					const igraph_vector_t *idx) {
+  
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->permute_vertices(graph, newgraph, idx);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_combine_vertices(const igraph_t *graph,
+			igraph_t *newgraph,
+			const igraph_vector_ptr_t *merges,
+			const igraph_attribute_combination_t *comb) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->combine_vertices(graph, newgraph, 
+						      merges,
+						      comb);
+  } else {
+    return 0;
+  }
+} 
+  
+int igraph_i_attribute_add_edges(igraph_t *graph, 
+				 const igraph_vector_t *edges, void *attr) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->add_edges(graph, edges, attr);
+  } else { 
+    return 0;
+  }
+}
+  
+int igraph_i_attribute_permute_edges(const igraph_t *graph, 
+				     igraph_t *newgraph,
+				     const igraph_vector_t *idx) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->permute_edges(graph, newgraph, idx);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_combine_edges(const igraph_t *graph,
+			igraph_t *newgraph,
+			const igraph_vector_ptr_t *merges,
+			const igraph_attribute_combination_t *comb) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->combine_edges(graph, newgraph, 
+						   merges, 
+						   comb);
+  } else {
+    return 0;
+  }
+} 
+
+int igraph_i_attribute_get_info(const igraph_t *graph,
+				igraph_strvector_t *gnames, 
+				igraph_vector_t *gtypes,
+				igraph_strvector_t *vnames,
+				igraph_vector_t *vtypes,
+				igraph_strvector_t *enames,
+				igraph_vector_t *etypes) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_info(graph, gnames, gtypes, 
+	  			              vnames, vtypes, 
+				              enames, etypes);
+  } else {
+    return 0;
+  }
+}
+
+igraph_bool_t igraph_i_attribute_has_attr(const igraph_t *graph, 
+					  igraph_attribute_elemtype_t type,
+					  const char *name) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->has_attr(graph, type, name);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_gettype(const igraph_t *graph,
+			       igraph_attribute_type_t *type,
+			       igraph_attribute_elemtype_t elemtype,
+			       const char *name) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->gettype(graph, type, elemtype, name);
+  } else {
+    return 0;
+  }
+  
+}
+
+int igraph_i_attribute_get_numeric_graph_attr(const igraph_t *graph,
+					      const char *name,
+					      igraph_vector_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_numeric_graph_attr(graph, name, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_numeric_vertex_attr(const igraph_t *graph, 
+					       const char *name,
+					       igraph_vs_t vs,
+					       igraph_vector_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_numeric_vertex_attr(graph, name, vs, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_numeric_edge_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_es_t es,
+					     igraph_vector_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_numeric_edge_attr(graph, name, es, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_string_graph_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_strvector_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_string_graph_attr(graph, name, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_string_vertex_attr(const igraph_t *graph, 
+					      const char *name,
+					      igraph_vs_t vs,
+					      igraph_strvector_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_string_vertex_attr(graph, name, vs, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_string_edge_attr(const igraph_t *graph,
+					    const char *name,
+					    igraph_es_t es,
+					    igraph_strvector_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_string_edge_attr(graph, name, es, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_bool_graph_attr(const igraph_t *graph,
+					   const char *name,
+					   igraph_vector_bool_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_bool_graph_attr(graph, name, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_bool_vertex_attr(const igraph_t *graph, 
+					    const char *name,
+					    igraph_vs_t vs,
+					    igraph_vector_bool_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_bool_vertex_attr(graph, name, vs, value);
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_attribute_get_bool_edge_attr(const igraph_t *graph,
+					  const char *name,
+					  igraph_es_t es,
+					  igraph_vector_bool_t *value) {
+  if (igraph_i_attribute_table) {
+    return igraph_i_attribute_table->get_bool_edge_attr(graph, name, es, value);
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * \function igraph_i_set_attribute_table
+ * \brief Attach an attribute table.
+ * 
+ * This function attaches attribute handling code to the igraph library.
+ * Note that the attribute handler table is \em not thread-local even if
+ * igraph is compiled in thread-local mode. In the vast majority of cases,
+ * this is not a significant restriction.
+ *
+ * \param table Pointer to an \ref igraph_attribute_table_t object
+ *    containing the functions for attribute manipulation. Supply \c
+ *    NULL here if you don't want attributes.
+ * \return Pointer to the old attribute handling table.
+ * 
+ * Time complexity: O(1).
+ */
+  
+igraph_attribute_table_t *
+igraph_i_set_attribute_table(const igraph_attribute_table_t * table) {
+  igraph_attribute_table_t *old=igraph_i_attribute_table;
+  igraph_i_attribute_table=(igraph_attribute_table_t*) table;
+  return old;
+}
+
+igraph_bool_t igraph_has_attribute_table() {
+  return igraph_i_attribute_table != 0;
+}
+  
+int igraph_attribute_combination_init(igraph_attribute_combination_t *comb) {
+  IGRAPH_CHECK(igraph_vector_ptr_init(&comb->list, 0));
+  return 0;
+}
+
+void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb) {
+  long int i, n=igraph_vector_ptr_size(&comb->list);
+  for (i=0; i<n; i++) {
+    igraph_attribute_combination_record_t *rec=VECTOR(comb->list)[i];
+    if (rec->name) { igraph_Free(rec->name); }
+    igraph_Free(rec);    
+  }
+  igraph_vector_ptr_destroy(&comb->list);
+}
+
+int igraph_attribute_combination_add(igraph_attribute_combination_t *comb, 
+				     const char *name,
+				     igraph_attribute_combination_type_t type,
+				     void *func) {
+  long int i, n=igraph_vector_ptr_size(&comb->list);
+
+  /* Search, in case it is already there */
+  for (i=0; i<n; i++) {
+    igraph_attribute_combination_record_t *r=VECTOR(comb->list)[i];
+    const char *n=r->name;
+    if ( (!name && !n) ||
+	 (name && n && !strcmp(n, name)) ) {
+      r->type=type;
+      r->func=func;
+      break;
+    }
+  }
+
+  if (i==n) {
+    /* This is a new attribute name */
+    igraph_attribute_combination_record_t *rec=
+      igraph_Calloc(1, igraph_attribute_combination_record_t);
+
+    if (!rec) {
+      IGRAPH_ERROR("Cannot create attribute combination data",
+		   IGRAPH_ENOMEM);
+    }
+    if (!name) { 
+      rec->name=0;
+    } else {
+      rec->name=strdup(name);
+    }
+    rec->type=type;
+    rec->func=func;
+    
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(&comb->list, rec));
+    
+  }
+  
+  return 0;
+}
+
+int igraph_attribute_combination_remove(igraph_attribute_combination_t *comb, 
+					const char *name) {
+  long int i, n=igraph_vector_ptr_size(&comb->list);
+
+  /* Search, in case it is already there */
+  for (i=0; i<n; i++) {
+    igraph_attribute_combination_record_t *r=VECTOR(comb->list)[i];
+    const char *n=r->name;
+    if ( (!name && !n) ||
+	 (name && n && !strcmp(n, name)) ) {
+      break;
+    }
+  }
+  
+  if (i!=n) {
+    igraph_attribute_combination_record_t *r=VECTOR(comb->list)[i];
+    if (r->name) { igraph_Free(r->name); }
+    igraph_Free(r);
+    igraph_vector_ptr_remove(&comb->list, i);
+  } else {
+    /* It is not there, we don't do anything */
+  }
+  
+  return 0;
+}
+
+int igraph_attribute_combination_query(const igraph_attribute_combination_t *comb,
+				       const char *name,
+				       igraph_attribute_combination_type_t *type,
+				       void **func) {
+  long int i, def=-1, len=igraph_vector_ptr_size(&comb->list);
+
+  for (i=0; i<len; i++) {
+    igraph_attribute_combination_record_t *rec=VECTOR(comb->list)[i];
+    const char *n=rec->name;
+    if ( (!name && !n) ||
+	 (name && n && !strcmp(n, name)) ) {
+      *type=rec->type;
+      *func=rec->func;
+      return 0;
+    }
+    if (!n) {
+      def=i;
+    }
+  }
+  
+  if (def==-1) {
+    /* Did not find anything */
+    *type=IGRAPH_ATTRIBUTE_COMBINE_DEFAULT;
+    *func=0;
+  } else {
+    igraph_attribute_combination_record_t *rec=VECTOR(comb->list)[def];
+    *type=rec->type;
+    *func=rec->func;
+  }
+
+  return 0;
+}
+
+int igraph_attribute_combination(igraph_attribute_combination_t *comb, ...) {
+
+  va_list ap;
+
+  IGRAPH_CHECK(igraph_attribute_combination_init(comb));
+  
+  va_start(ap, comb);
+  while (1) { 
+    void *func=0;
+    igraph_attribute_combination_type_t type;
+    const char *name;
+    
+    name=va_arg(ap, const char *);
+    
+    if (name == IGRAPH_NO_MORE_ATTRIBUTES) { break; }
+    
+    type=(igraph_attribute_combination_type_t)va_arg(ap, int);
+    if (type == IGRAPH_ATTRIBUTE_COMBINE_FUNCTION) {
+      func=va_arg(ap, void*);      
+    }
+
+    if (strlen(name)==0) { name=0; }
+    
+    IGRAPH_CHECK(igraph_attribute_combination_add(comb, name, type, func));
+  }
+  
+  va_end(ap);
+  
+  return 0;
+}
diff --git a/src/basic_query.c b/src/basic_query.c
new file mode 100644
index 0000000..54fc66c
--- /dev/null
+++ b/src/basic_query.c
@@ -0,0 +1,64 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_datatype.h"
+#include "igraph_types.h"
+#include "igraph_interface.h"
+#include "igraph_structural.h"
+#include "config.h"
+
+/**
+ * \ingroup structural
+ * \function igraph_are_connected
+ * \brief Decides whether two vertices are connected 
+ *
+ * \param graph The graph object.
+ * \param v1 The first vertex.
+ * \param v2 The second vertex.
+ * \param res Boolean, \c TRUE if there is an edge from
+ *         \p v1 to \p v2, \c FALSE otherwise.
+ * \return The error code \c IGRAPH_EINVVID is returned if an invalid
+ *         vertex ID is given.
+ * 
+ * The function is of course symmetric for undirected graphs.
+ *
+ * </para><para>
+ * Time complexity: O( min(log(d1), log(d2)) ),
+ * d1 is the (out-)degree of \p v1 and d2 is the (in-)degree of \p v2.
+ */
+int igraph_are_connected(const igraph_t *graph, 
+			 igraph_integer_t v1, igraph_integer_t v2,
+			 igraph_bool_t *res) {
+
+  long int nov=igraph_vcount(graph);
+  igraph_integer_t eid=-1;
+
+  if (v1 < 0 || v2 < 0 || v1 > nov-1 || v2 > nov-1) {
+    IGRAPH_ERROR("are connected", IGRAPH_EINVVID);
+  }
+
+  igraph_get_eid(graph, &eid, v1, v2, /*directed=*/1, /*error=*/ 0);
+  *res = (eid >=0);
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/src/bfgs.c b/src/bfgs.c
new file mode 100644
index 0000000..400d0e4
--- /dev/null
+++ b/src/bfgs.c
@@ -0,0 +1,201 @@
+/* -*- 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_nongraph.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_statusbar.h"
+#include "memory.h"
+#include "config.h"
+
+#include <math.h>
+
+/* This is from GNU R's optim.c, slightly adapted to igraph */
+
+#define stepredn	0.2
+#define acctol		0.0001
+#define reltest		10.0
+#define FALSE           0
+#define TRUE            1
+
+/*  BFGS variable-metric method, based on Pascal code
+in J.C. Nash, `Compact Numerical Methods for Computers', 2nd edition,
+converted by p2c then re-crafted by B.D. Ripley */
+
+int
+igraph_bfgs(igraph_vector_t *b, igraph_real_t *Fmin, 
+	    igraph_scalar_function_t fminfn, igraph_vector_function_t fmingr,
+	    int maxit, int trace,
+	    igraph_real_t abstol, igraph_real_t reltol, int nREPORT, void *ex,
+	    igraph_integer_t *fncount, igraph_integer_t *grcount)
+{
+  int n=(int) igraph_vector_size(b);
+  igraph_bool_t accpoint, enough;
+  igraph_vector_t g, t, X, c;
+  igraph_matrix_t B;		/* Lmatrix really */
+  int   count, funcount, gradcount;
+  igraph_real_t f, gradproj;
+  int   i, j, ilast, iter = 0;
+  igraph_real_t s, steplength;
+  igraph_real_t D1, D2;
+
+  if (maxit <= 0) {
+    *Fmin = fminfn(b, 0, ex);
+    *fncount = 1;
+    *grcount = 0;
+    return 0;
+  }
+
+  if (nREPORT <= 0)
+    IGRAPH_ERROR("REPORT must be > 0 (method = \"BFGS\")", IGRAPH_EINVAL);
+  IGRAPH_VECTOR_INIT_FINALLY(&g, n);
+  IGRAPH_VECTOR_INIT_FINALLY(&t, n);
+  IGRAPH_VECTOR_INIT_FINALLY(&X, n);
+  IGRAPH_VECTOR_INIT_FINALLY(&c, n);
+  IGRAPH_MATRIX_INIT_FINALLY(&B, n, n);
+  f = fminfn(b, 0, ex);
+  if (!IGRAPH_FINITE(f))
+    IGRAPH_ERROR("initial value in 'BFGS' is not finite", IGRAPH_DIVERGED);
+  if (trace) igraph_statusf("initial  value %f ", 0, f);
+  *Fmin = f;
+  funcount = gradcount = 1;
+  fmingr(b, 0, &g, ex);
+  iter++;
+  ilast = gradcount;
+
+  do {
+
+    IGRAPH_ALLOW_INTERRUPTION();      
+
+    if (ilast == gradcount) {
+      for (i = 0; i < n; i++) {
+	for (j = 0; j < i; j++) MATRIX(B,i,j) = 0.0;
+	MATRIX(B, i, i) = 1.0;
+      }
+    }
+    for (i = 0; i < n; i++) {
+      VECTOR(X)[i] = VECTOR(*b)[i];
+      VECTOR(c)[i] = VECTOR(g)[i];
+    }
+    gradproj = 0.0;
+    for (i = 0; i < n; i++) {
+      s = 0.0;
+      for (j = 0; j <= i; j++) s -= MATRIX(B,i,j) * VECTOR(g)[j];
+      for (j = i + 1; j < n; j++) s -= MATRIX(B,j,i) * VECTOR(g)[j];
+      VECTOR(t)[i] = s;
+      gradproj += s * VECTOR(g)[i];
+    }
+
+    if (gradproj < 0.0) {	/* search direction is downhill */
+      steplength = 1.0;
+      accpoint = FALSE;
+      do {
+	count = 0;
+	for (i = 0; i < n; i++) {
+	  VECTOR(*b)[i] = VECTOR(X)[i] + steplength * VECTOR(t)[i];
+	  if (reltest + VECTOR(X)[i] == reltest + VECTOR(*b)[i]) /* no change */
+	    count++;
+	}
+	if (count < n) {
+	  f = fminfn(b, 0, ex);
+	  funcount++;
+	  accpoint = IGRAPH_FINITE(f) &&
+	    (f <= *Fmin + gradproj * steplength * acctol);
+	  if (!accpoint) {
+	    steplength *= stepredn;
+	  }
+	}
+      } while (!(count == n || accpoint));
+      enough = (f > abstol) &&
+	fabs(f - *Fmin) > reltol * (fabs(*Fmin) + reltol);
+      /* stop if value if small or if relative change is low */
+      if (!enough) {
+	count = n;
+	*Fmin = f;
+      }
+      if (count < n) {/* making progress */
+	*Fmin = f;
+	fmingr(b, 0, &g, ex);
+	gradcount++;
+	iter++;
+	D1 = 0.0;
+	for (i = 0; i < n; i++) {
+	  VECTOR(t)[i] = steplength * VECTOR(t)[i];
+	  VECTOR(c)[i] = VECTOR(g)[i] - VECTOR(c)[i];
+	  D1 += VECTOR(t)[i] * VECTOR(c)[i];
+	}
+	if (D1 > 0) {
+	  D2 = 0.0;
+	  for (i = 0; i < n; i++) {
+	    s = 0.0;
+	    for (j = 0; j <= i; j++)
+	      s += MATRIX(B,i,j) * VECTOR(c)[j];
+	    for (j = i + 1; j < n; j++)
+	      s += MATRIX(B,j,i) * VECTOR(c)[j];
+	    VECTOR(X)[i] = s;
+	    D2 += s * VECTOR(c)[i];
+	  }
+	  D2 = 1.0 + D2 / D1;
+	  for (i = 0; i < n; i++) {
+	    for (j = 0; j <= i; j++)
+	      MATRIX(B,i,j) += (D2 * VECTOR(t)[i] * VECTOR(t)[j]
+				- VECTOR(X)[i] * VECTOR(t)[j] 
+				- VECTOR(t)[i] * VECTOR(X)[j]) / D1;
+	  }
+	} else {	/* D1 < 0 */
+	  ilast = gradcount;
+	}
+      } else {	/* no progress */
+	if (ilast < gradcount) {
+	  count = 0;
+	  ilast = gradcount;
+	}
+      }
+    } else {		/* uphill search */
+      count = 0;
+      if (ilast == gradcount) count = n;
+      else ilast = gradcount;
+      /* Resets unless has just been reset */
+    }
+    if (trace && (iter % nREPORT == 0))
+      igraph_statusf("iter%4d value %f", 0, iter, f);
+    if (iter >= maxit) break;
+    if (gradcount - ilast > 2 * n)
+      ilast = gradcount;	/* periodic restart */
+  } while (count != n || ilast != gradcount);
+  if (trace) {
+    igraph_statusf("final  value %f ", 0, *Fmin);
+    if (iter < maxit) igraph_status("converged", 0);
+    else igraph_statusf("stopped after %i iterations", 0, iter);
+  }
+  *fncount = funcount;
+  *grcount = gradcount;
+  
+  igraph_matrix_destroy(&B);
+  igraph_vector_destroy(&c);
+  igraph_vector_destroy(&X);
+  igraph_vector_destroy(&t);
+  igraph_vector_destroy(&g);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return (iter<maxit) ? 0 : IGRAPH_DIVERGED;
+}
diff --git a/src/bigint.c b/src/bigint.c
new file mode 100644
index 0000000..9616b8a
--- /dev/null
+++ b/src/bigint.c
@@ -0,0 +1,315 @@
+/* -*- 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
+
+*/
+
+#include "bigint.h"
+#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);
+  return 0;
+}
+
+void igraph_biguint_destroy(igraph_biguint_t *b) {
+  igraph_vector_limb_destroy(&b->v);
+}
+
+int igraph_biguint_copy(igraph_biguint_t *to, igraph_biguint_t *from) {
+  return igraph_vector_limb_copy(&to->v, &from->v);
+}
+
+int igraph_biguint_extend(igraph_biguint_t *b, limb_t l) {
+  return igraph_vector_limb_push_back(&b->v, l);
+}
+
+int igraph_biguint_size(igraph_biguint_t *b) {
+  return (int) igraph_vector_limb_size(&b->v);
+}
+
+int igraph_biguint_resize(igraph_biguint_t *b, int newlength) {
+  int origlen=igraph_biguint_size(b);
+  IGRAPH_CHECK(igraph_vector_limb_resize(&b->v, newlength));
+  if (newlength > origlen) {
+    memset(VECTOR(b->v) + origlen, 0,
+	   (size_t) (newlength-origlen) * sizeof(limb_t));
+  }
+  return 0;
+}
+
+int igraph_biguint_reserve(igraph_biguint_t *b, int length) {
+  return igraph_vector_limb_reserve(&b->v, length);
+}
+
+int igraph_biguint_zero(igraph_biguint_t *b) {
+  igraph_vector_limb_clear(&b->v);
+  return 0;
+}
+
+int igraph_biguint_set_limb(igraph_biguint_t *b, int value) {
+  IGRAPH_CHECK(igraph_vector_limb_resize(&b->v, 1));
+  VECTOR(b->v)[0]=(limb_t) value;
+  return 0;
+}
+
+igraph_real_t igraph_biguint_get(igraph_biguint_t *b) {
+  int size=igraph_biguint_size(b);
+  int i;
+  double val=VECTOR(b->v)[size-1];
+  if (size==0) { return 0.0; }
+  for (i=size-2; i>=0; i--) {
+    val = val * LIMBMASK + VECTOR(b->v)[i];
+    if (!IGRAPH_FINITE(val)) break;
+  }
+  return val;
+}
+
+int igraph_biguint_compare_limb(igraph_biguint_t *b, limb_t l) {
+  int n=igraph_biguint_size(b);
+  return bn_cmp_limb(VECTOR(b->v), l, (count_t) n);
+}
+
+int igraph_biguint_compare(igraph_biguint_t *left, igraph_biguint_t *right) {
+  /* bn_cmp requires the two numbers to have the same number of limbs,
+     so we do this partially by hand here */
+  int size_left=igraph_biguint_size(left);
+  int size_right=igraph_biguint_size(right);
+  while (size_left > size_right) { 
+    if (VECTOR(left->v)[--size_left] > 0) { return +1; }
+  }
+  while (size_right > size_left) {
+    if (VECTOR(right->v)[--size_right] > 0) { return -1; }
+  }
+  return bn_cmp( VECTOR(left->v), VECTOR(right->v), (count_t) size_right );
+}
+
+
+igraph_bool_t igraph_biguint_equal(igraph_biguint_t *left, igraph_biguint_t *right) {
+  return 0 == igraph_biguint_compare(left, right);
+}
+
+
+igraph_bool_t igraph_biguint_bigger(igraph_biguint_t *left, 
+				   igraph_biguint_t *right) {
+  return 0 < igraph_biguint_compare(left, right);
+}
+
+
+igraph_bool_t igraph_biguint_biggerorequal(igraph_biguint_t *left, 
+					  igraph_biguint_t *right) {
+  return 0 <= igraph_biguint_compare(left, right);
+}
+
+int igraph_biguint_inc(igraph_biguint_t *res, igraph_biguint_t *b) {
+  return igraph_biguint_add_limb(res, b, 1);
+}
+
+int igraph_biguint_dec(igraph_biguint_t *res, igraph_biguint_t *b) {
+  return igraph_biguint_sub_limb(res, b, 1);
+}
+
+
+int igraph_biguint_add_limb(igraph_biguint_t *res, igraph_biguint_t *b, 
+			    limb_t l) {
+  int nlimb=igraph_biguint_size(b);
+  limb_t carry;
+  
+  if (res != b) { IGRAPH_CHECK(igraph_biguint_resize(res, nlimb)); }
+  
+  carry=bn_add_limb( VECTOR(res->v), VECTOR(b->v), l, (count_t) nlimb);
+  if (carry) { 
+    IGRAPH_CHECK(igraph_biguint_extend(res, carry));
+  }
+  return 0;
+}
+
+int igraph_biguint_sub_limb(igraph_biguint_t *res, igraph_biguint_t *b, 
+			    limb_t l) {
+  int nlimb=igraph_biguint_size(b);
+  
+  if (res != b) { IGRAPH_CHECK(igraph_biguint_resize(res, nlimb)); }
+
+  /* We don't check the return value here */
+  bn_sub_limb( VECTOR(res->v), VECTOR(b->v), l, (count_t) nlimb);
+
+  return 0;
+}
+
+int igraph_biguint_mul_limb(igraph_biguint_t *res, igraph_biguint_t *b,
+			    limb_t l) {
+  int nlimb=igraph_biguint_size(b);
+  limb_t carry;
+  
+  if (res!= b) { IGRAPH_CHECK(igraph_biguint_resize(res, nlimb)); }
+  
+  carry=bn_mul_limb( VECTOR(res->v), VECTOR(b->v), l, (count_t) nlimb);
+  if (carry) { 
+    IGRAPH_CHECK(igraph_biguint_extend(res, carry));
+  }
+  return 0;
+}
+
+int igraph_biguint_add(igraph_biguint_t *res, igraph_biguint_t *left, 
+		       igraph_biguint_t *right) {
+
+  int size_left=igraph_biguint_size(left);
+  int size_right=igraph_biguint_size(right);
+  limb_t carry;
+
+  if (size_left > size_right) { 
+    IGRAPH_CHECK(igraph_biguint_resize(right, size_left));
+    size_right=size_left;
+  } else if (size_left < size_right) {
+    IGRAPH_CHECK(igraph_biguint_resize(left, size_right));
+    size_left=size_right;
+  }
+  IGRAPH_CHECK(igraph_biguint_resize(res, size_left));
+  
+  carry=bn_add( VECTOR(res->v), VECTOR(left->v), VECTOR(right->v), 
+		(count_t) size_left);
+  if (carry) {
+    IGRAPH_CHECK(igraph_biguint_extend(res, carry));
+  }
+  return 0;
+}
+
+int igraph_biguint_sub(igraph_biguint_t *res, igraph_biguint_t *left, 
+		       igraph_biguint_t *right) {
+ 
+  int size_left=igraph_biguint_size(left);
+  int size_right=igraph_biguint_size(right);
+  
+  if (size_left > size_right) { 
+    IGRAPH_CHECK(igraph_biguint_resize(right, size_left));
+    size_right=size_left;
+  } else if (size_left < size_right) {
+    IGRAPH_CHECK(igraph_biguint_resize(left, size_right));
+    size_left=size_right;
+  }
+  IGRAPH_CHECK(igraph_biguint_resize(res, size_left));
+
+  /* We don't check return value, left should not be smaller than right! */
+  bn_sub( VECTOR(res->v), VECTOR(left->v), VECTOR(right->v), 
+	  (count_t) size_left);
+  
+  return 0;
+}
+
+int igraph_biguint_mul(igraph_biguint_t *res, igraph_biguint_t *left,
+		       igraph_biguint_t *right) {
+
+  int size_left=igraph_biguint_size(left);
+  int size_right=igraph_biguint_size(right);
+  
+  if (size_left > size_right) { 
+    IGRAPH_CHECK(igraph_biguint_resize(right, size_left));
+    size_right=size_left;
+  } else if (size_left < size_right) {
+    IGRAPH_CHECK(igraph_biguint_resize(left, size_right));
+    size_left=size_right;
+  }
+  IGRAPH_CHECK(igraph_biguint_resize(res, 2*size_left));
+  
+  bn_mul( VECTOR(res->v), VECTOR(left->v), VECTOR(right->v), 
+	  (count_t) size_left );
+  return 0;
+}
+
+int igraph_biguint_div(igraph_biguint_t *q, igraph_biguint_t *r,
+		       igraph_biguint_t *u, igraph_biguint_t *v) {
+
+  int ret;
+  int size_q=igraph_biguint_size(q);
+  int size_r=igraph_biguint_size(r);
+  int size_u=igraph_biguint_size(u);
+  int size_v=igraph_biguint_size(v);
+  int size_qru = size_q > size_r ? size_q : size_r;
+  size_qru = size_u > size_qru ? size_u : size_qru;
+  
+  if (size_q < size_qru) { IGRAPH_CHECK(igraph_biguint_resize(q, size_qru)); }
+  if (size_r < size_qru) { IGRAPH_CHECK(igraph_biguint_resize(r, size_qru)); }
+  if (size_u < size_qru) { IGRAPH_CHECK(igraph_biguint_resize(u, size_qru)); }
+
+  ret=bn_div( VECTOR(q->v), VECTOR(r->v), VECTOR(u->v), VECTOR(v->v), 
+	      (count_t) size_qru, (count_t) size_v );
+  
+  if (ret) {
+    IGRAPH_ERROR("Bigint division by zero", IGRAPH_EDIVZERO);
+  }
+  
+  return 0;
+}
+
+#ifndef USING_R
+int igraph_biguint_print(igraph_biguint_t *b) {
+  return igraph_biguint_fprint(b, stdout);
+}
+#endif
+
+int igraph_biguint_fprint(igraph_biguint_t *b, FILE *file) {
+
+  /* It is hard to control memory allocation for the bn2d function,
+     so we do our own version */
+
+  int n=igraph_biguint_size(b);
+  long int size=12*n+1;
+  igraph_biguint_t tmp;
+  char *dst;
+  limb_t r;
+
+  /* Zero? */
+  if (!bn_cmp_limb(VECTOR(b->v), 0, (count_t) n)) {
+    fputs("0", file);
+    return 0;
+  }
+  
+  IGRAPH_CHECK(igraph_biguint_copy(&tmp, b));
+  IGRAPH_FINALLY(igraph_biguint_destroy, &tmp);
+  dst=igraph_Calloc(size, char);
+  if (!dst) {
+    IGRAPH_ERROR("Cannot print big number", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, dst);
+  
+  size--;
+  dst[size]='\0';
+  while (0 != bn_cmp_limb(VECTOR(tmp.v), 0, (count_t) n)) {
+    r=bn_div_limb(VECTOR(tmp.v), VECTOR(tmp.v), 10, (count_t) n);
+    dst[--size] = '0' + (char) r;
+  }
+
+  fputs(&dst[size], file);
+  
+  igraph_Free(dst);
+  igraph_biguint_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
diff --git a/src/bigint.h b/src/bigint.h
new file mode 100644
index 0000000..545ccdc
--- /dev/null
+++ b/src/bigint.h
@@ -0,0 +1,105 @@
+/* -*- 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_BIGINT_H
+#define IGRAPH_BIGINT_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_vector.h"
+#include "bignum.h"
+
+#include <stdio.h>
+
+/* Arbitrary precision integer */
+
+#define BASE_LIMB
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LIMB
+
+typedef struct igraph_biguint_t {
+  igraph_vector_limb_t v;
+} igraph_biguint_t;
+
+#define IGRAPH_BIGUINT_DEFAULT_SIZE 5
+
+int igraph_biguint_init(igraph_biguint_t *b);
+void igraph_biguint_destroy(igraph_biguint_t *b);
+int igraph_biguint_copy(igraph_biguint_t *to, igraph_biguint_t *from);
+
+int igraph_biguint_extend(igraph_biguint_t *b, limb_t l);
+
+int igraph_biguint_size(igraph_biguint_t *b);
+int igraph_biguint_resize(igraph_biguint_t *b, int newlength);
+int igraph_biguint_reserve(igraph_biguint_t *b, int length);
+
+int igraph_biguint_zero(igraph_biguint_t *b);
+int igraph_biguint_set_limb(igraph_biguint_t *b, int value);
+
+igraph_real_t igraph_biguint_get(igraph_biguint_t *b);
+
+int igraph_biguint_compare_limb(igraph_biguint_t *b, limb_t l);
+int igraph_biguint_compare(igraph_biguint_t *left, igraph_biguint_t *right);
+igraph_bool_t igraph_biguint_equal(igraph_biguint_t *left, igraph_biguint_t *right);
+igraph_bool_t igraph_biguint_bigger(igraph_biguint_t *left, 
+				   igraph_biguint_t *right);
+igraph_bool_t igraph_biguint_biggerorequal(igraph_biguint_t *left, 
+					  igraph_biguint_t *right);
+
+int igraph_biguint_inc(igraph_biguint_t *res, igraph_biguint_t *b);
+int igraph_biguint_dec(igraph_biguint_t *res, igraph_biguint_t *b);
+
+int igraph_biguint_add_limb(igraph_biguint_t *res, igraph_biguint_t *b, 
+			    limb_t l);
+int igraph_biguint_sub_limb(igraph_biguint_t *res, igraph_biguint_t *b, 
+			    limb_t l);
+int igraph_biguint_mul_limb(igraph_biguint_t *res, igraph_biguint_t *b,
+			    limb_t l);
+
+int igraph_biguint_add(igraph_biguint_t *res, igraph_biguint_t *left, 
+		       igraph_biguint_t *right);
+int igraph_biguint_sub(igraph_biguint_t *res, igraph_biguint_t *left, 
+		       igraph_biguint_t *right);
+int igraph_biguint_mul(igraph_biguint_t *res, igraph_biguint_t *left,
+		       igraph_biguint_t *right);
+int igraph_biguint_div(igraph_biguint_t *q, igraph_biguint_t *r,
+		       igraph_biguint_t *u, igraph_biguint_t *v);
+
+int igraph_biguint_print(igraph_biguint_t *b);
+int igraph_biguint_fprint(igraph_biguint_t *b, FILE *file);
+
+__END_DECLS
+
+#endif
diff --git a/src/bignum.c b/src/bignum.c
new file mode 100644
index 0000000..8eb7a9d
--- /dev/null
+++ b/src/bignum.c
@@ -0,0 +1,1953 @@
+/******************************************************************************
+ * bn.c - big number math implementation
+ *
+ * Copyright (c) 2004 by Juergen Buchmueller <pullmoll at stop1984.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ *
+ *	$Id: bignum.c,v 1.17 2005/07/23 02:55:53 pullmoll Exp $
+ ******************************************************************************/
+#include <math.h>
+#include "bignum.h"
+#include "config.h"
+#include "math.h"
+#include "igraph_error.h"
+
+#ifndef	ASM_X86
+#ifdef	X86
+#define	ASM_X86	1
+#endif
+#endif
+
+/**
+ * @brief Return hex representation of a big number
+ *
+ * Returns the hex representation of a[],
+ * where a is a big number integer with nlimb limbs.
+ *
+ * @param a pointer to an array of limbs
+ * @param nlimb number of limbs in the array
+ *
+ * @result string containing the hex representation of a
+ */
+const char *bn2x(limb_t *a, count_t nlimb)
+{
+	static IGRAPH_THREAD_LOCAL count_t which = 0;
+	static IGRAPH_THREAD_LOCAL char *xbuff[8] = {
+		NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL
+	};
+	char *dst;
+	count_t size;
+	count_t n = nlimb;
+
+	if (0 == n)
+		return "0";
+
+	which = (which + 1) % 8;
+	size = 8 * n + 1;
+	if (NULL != xbuff[which])
+		free(xbuff[which]);
+	dst = xbuff[which] = calloc(size, sizeof(char));
+	if (NULL == dst)
+		return "memory error";
+	while (n-- > 0) {
+		dst += snprintf(dst, size, "%08x", a[n]);
+		size -= 8;
+	}
+	return xbuff[which];
+}
+
+/**
+ * @brief Return decimal representation of a big number
+ *
+ * Returns the decimal representation of a[],
+ * where a is a big number integer with nlimb limbs.
+ *
+ * @param a pointer to an array of limbs
+ * @param nlimb number of limbs in the array
+ *
+ * @result string containing the decimal representation of a
+ */
+const char *bn2d(limb_t *a, count_t nlimb)
+{
+	static IGRAPH_THREAD_LOCAL count_t which = 0;
+	static IGRAPH_THREAD_LOCAL char *dbuff[8] = {
+		NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL
+	};
+	static IGRAPH_THREAD_LOCAL limb_t v[BN_MAXSIZE];
+	limb_t r;
+	char *dst;
+	count_t size;
+	count_t n = bn_sizeof(a, nlimb);
+
+	if (0 == n)
+		return "0";
+
+	bn_copy(v, a, n);
+	which = (which + 1) % 8;
+	size = 12 * n + 1;
+	if (NULL != dbuff[which])
+		free(dbuff[which]);
+	dst = dbuff[which] = calloc(size, sizeof(char));
+	if (NULL == dst)
+		return "memory error";
+	size--;
+	while (0 != bn_cmp_limb(v, 0, n)) {
+		r = bn_div_limb(v, v, 10, n);
+		dst[--size] = '0' + (char) r;
+	}
+	return &dst[size];
+}
+
+/**
+ * @brief Return decimal representation of a big number pair
+ *
+ * Returns the decimal representation of a[].b[],
+ * where a is a big number integer with alimb limbs,
+ * and b is a multiprecision fixed fraction with blimb limbs.
+ *
+ * @param a pointer to an array of limbs
+ * @param alimb number of limbs in the a array
+ * @param b pointer to an array of limbs
+ * @param blimb number of limbs in the b array
+ *
+ * @result string containing the decimal representation of a.b
+ */
+const char *bn2f(limb_t *a, count_t alimb, limb_t *b, count_t blimb)
+{
+	static IGRAPH_THREAD_LOCAL count_t which = 0;
+	static IGRAPH_THREAD_LOCAL char *dbuff[8] = {
+		NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL
+	};
+	static IGRAPH_THREAD_LOCAL limb_t v[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t w[BN_MAXSIZE];
+	limb_t r;
+	char *dst;
+	count_t size;
+
+	bn_copy(v, a, alimb);
+	bn_copy(w, b, blimb);
+
+	which = (which + 1) % 8;
+	size = 12 * (alimb + blimb) + 1 + 1;
+	if (NULL != dbuff[which])
+		free(dbuff[which]);
+	dst = dbuff[which] = calloc(size, sizeof(char));
+	if (NULL == dst)
+		return "memory error";
+	size = 12 * alimb;
+	while (0 != bn_cmp_limb(w, 0, blimb) && size < 12 * (alimb + blimb)) {
+		r = bn_mul_limb(w, w, 10, blimb);
+		dst[size++] = '0' + (char) r;
+	}
+
+	size = 12 * alimb;
+	dst[size] = '.';
+	while (0 != bn_cmp_limb(v, 0, alimb) && size > 0) {
+		r = bn_div_limb(v, v, 10, alimb);
+		dst[--size] = '0' + (char) r;
+	}
+
+	return &dst[size];
+}
+
+/**
+ * @brief Return binary representation of a big number
+ *
+ * Returns the binary representation of a[],
+ * where a is a big number integer with nlimb limbs.
+ *
+ * @param a pointer to an array of limbs
+ * @param nlimb number of limbs in the array
+ *
+ * @result string containing the binary representation of a
+ */
+const char *bn2b(limb_t *a, count_t nlimb)
+{
+	static IGRAPH_THREAD_LOCAL count_t which = 0;
+	static IGRAPH_THREAD_LOCAL char *bbuff[8] = {
+		NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL
+	};
+	limb_t r;
+	char *dst;
+	count_t size;
+	count_t n = bn_sizeof(a, nlimb);
+
+	if (0 == n)
+		return "0";
+
+	which = (which + 1) % 8;
+	size = LIMBBITS * n + 1;
+	if (NULL != bbuff[which])
+		free(bbuff[which]);
+	dst = bbuff[which] = calloc(size, sizeof(char));
+	if (NULL == dst)
+		return "memory error";
+	n = 0;
+	size--;
+	while (size-- > 0) {
+		r = (a[n/LIMBBITS] >> (n%LIMBBITS)) & 1;
+		n++;
+		dst[size] = '0' + (char) r;
+	}
+	return &dst[size];
+}
+
+/**
+ * @brief Zero an array of limbs
+ *
+ * Sets a[] = 0
+ * where a is a big number integer of nlimb limbs.
+ *
+ * @param a pointer to an array of limbs
+ * @param nlimb number of limbs in the array
+ *
+ */
+void bn_zero(limb_t a[], count_t nlimb)
+{
+	memset(a, 0, nlimb * sizeof(limb_t));
+}
+
+/**
+ * @brief Set an array of limbs to a single limb value
+ *
+ * Sets a[] = d
+ * where a is a big number integer of nlimb limbs,
+ * and d is a single limb
+ *
+ * @param a pointer to an array of limbs to set
+ * @param d limb value to set a to
+ * @param nlimb number of limbs in the array
+ *
+ */
+void bn_limb(limb_t a[], limb_t d, count_t nlimb)
+{
+	memset(a, 0, nlimb * sizeof(limb_t));
+	a[0] = d;
+}
+
+/**
+ * @brief Copy an array of limbs
+ *
+ * Sets a[] = b[]
+ * where a and b are a big number integers of nlimb limbs
+ *
+ * @param a pointer to an array of limbs (destination)
+ * @param b pointer to an array of limbs (source)
+ * @param nlimb number of limbs in the arrays
+ */
+void bn_copy(limb_t a[], limb_t b[], count_t nlimb)
+{
+	memcpy(a, b, nlimb * sizeof(limb_t));
+}
+
+/**
+ * @brief Return significant size of a big number
+ *
+ * Returns size of significant limbs in a[]
+ * i.e. searches for the first non-zero limb from
+ * nlimb-1 downto 0.
+ *
+ * @param a pointer to an array of limbs (candidate)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result number of significant limbs in a
+ */
+count_t bn_sizeof(limb_t a[], count_t nlimb)
+{
+	while (nlimb-- > 0)
+		if (0 != a[nlimb])
+			return ++nlimb;
+	return 0;
+}
+
+
+/**
+ * @brief Return sign of a bignum minus a limb
+ *
+ * Returns the sign of (a[] - b)
+ * where a is a big number integer of nlimb limbs,
+ * and b is a single limb
+ +
+ * @param a pointer to an array of limbs (minuend)
+ * @param b a single limb (subtrahend)
+ * @param nlimb number of limbs in the array a
+ *
+ * @result sign of the comparison: -1 a<b, 0 a=b, +1 a>b
+ */
+int bn_cmp_limb(limb_t a[], limb_t b, count_t nlimb)
+{
+	if (0 == nlimb)
+		return 0;
+
+	while (nlimb-- > 1)
+		if (0 != a[nlimb])
+			return +1;
+	if (a[0] < b)
+		return -1;
+	if (a[0] > b)
+		return +1;
+	return 0;
+}
+
+/**
+ * @brief Return sign of bignum a minus bignum b
+ *
+ * Returns the sign of (a[] - b[])
+ * where a and b are a big number integers of nlimb limbs
+ *
+ * @param a pointer to an array of limbs (minuend)
+ * @param b pointer to an array of limbs (subtrahend)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result sign of the comparison: -1 a<b, 0 a=b, +1 a>b
+ */
+int bn_cmp(limb_t a[], limb_t b[], count_t nlimb)
+{
+	if (0 == nlimb)
+		return 0;
+
+	while (nlimb-- > 0) {
+		if (a[nlimb] > b[nlimb])
+			return +1;	/* GT */
+		if (a[nlimb] < b[nlimb])
+			return -1;	/* LT */
+	}
+
+	return 0;	/* EQ */
+}
+
+/**
+ * @brief Single limb is even test
+ *
+ * Returns 1 if a is even, else 0
+ * where a is a single limb
+ *
+ * @param a a single limb
+ *
+ * @result zero if a is odd, 1 if a is even
+ */
+int sl_iseven(limb_t a)
+{
+	return (a & 1) ? 0 : 1;
+}
+
+/**
+ * @brief bignum is even test
+ *
+ * Returns 1 if a[] is even, else 0
+ * where a is a big number integer of nlimb limbs
+ * Note: a zero limb big number integer is even!
+ *
+ * @param a pointer to an array of limbs
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero if a is odd, 1 if a is even
+ */
+int bn_iseven(limb_t *a, count_t nlimb)
+{
+	if (0 == nlimb)
+		return 1;
+	return (a[0] & 1) ? 0 : 1;
+}
+
+/**
+ * @brief Add a single limb to a bignum
+ *
+ * Computes w[] = u[] + v
+ * where w, u are big number integers of nlimb lims each,
+ * and v is a single limb.
+ * Returns carry if the addition overflows.
+ *
+ * Ref: Derived from Knuth Algorithm A.
+ *
+ * @param w pointer to an array of limbs receiving result
+ * @param u pointer to an array of limbs (addend 1)
+ * @param v a single limb
+ * @param nlimb number of limbs in the arrays w and u
+ *
+ * @result The carry status of the addition
+ */
+limb_t bn_add_limb(limb_t w[], limb_t u[], limb_t v, count_t nlimb)
+{
+	limb_t carry;
+	count_t j;
+
+	/* Copy u to w, so we can bail out if no borrow is left */
+	if (w != u)
+		bn_copy(w, u, nlimb);
+
+	/* Add v to first limb of u */
+	w[0] += v;
+	carry = (w[0] < v ? 1 : 0);
+
+	/* Add carry to subsequent limbs */
+	for (j = 1; 0 != carry && j < nlimb; j++) {
+		w[j] += carry;
+		carry = (w[j] < carry ? 1 : 0);
+	}
+	return carry;
+}
+
+
+/**
+ * @brief Subtract a single limb from a bignum
+ *
+ * Computes w[] = u[] - v
+ * where w, u are big number integers of nlimb limbs each,
+ * and v is a single limb.
+ * Returns borrow (0 if u >= v, or 1 if v > u).
+ * 
+ * Ref: Derived from Knuth Algorithm S.
+ *
+ * @param w pointer to an array of limbs receiving the result
+ * @param u pointer to an array of limbs (minuend)
+ * @param v single limb (subtrahend)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result borrow of the subtraction (0 if u >= v, 1 if u < v)
+ */
+limb_t bn_sub_limb(limb_t w[], limb_t u[], limb_t v, count_t nlimb)
+{
+	limb_t borrow;
+	count_t j;
+
+	/* Copy u to w, so we can bail out if no borrow is left */
+	if (w != u)
+		bn_copy(w, u, nlimb);
+
+	/* Subtract v from first limb of u */
+	w[0] -= v;
+	borrow = (w[0] > ~v ? 1 : 0);
+
+	/* Subtract borrow from subsequent limbs */
+	for (j = 1; 0 != borrow && j < nlimb; j++) {
+		w[j] -= borrow;
+		borrow = (w[j] > ~borrow ? 1 : 0);
+	}
+
+	return borrow;
+}
+
+/**
+ * @brief Divide a bignum by a single limb
+ *
+ * Computes quotient q[] = u[] / v
+ * and returns remainder r = u[] % v
+ * where q, u are big number integers of nlimb limbs each,
+ * and v is a single limb.
+ * 
+ * Makes no assumptions about normalisation.
+ * 
+ * Ref: Knuth Vol 2 Ch 4.3.1 Exercise 16 p625
+ *
+ * @param q pointer to an array of limbs receiving the quotient
+ * @param u pointer to an array of limbs (dividend)
+ * @param v single limb (divisor)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result single limb remainder of the division (modulo)
+ */
+limb_t bn_div_limb(limb_t q[], limb_t u[], limb_t v, count_t nlimb)
+{
+	count_t j;
+	limb_t t[2], r;
+	count_t shift;
+
+	if (0 == nlimb)
+		return 0;
+	if (0 == v)
+		return LIMBMASK;	/* Divide by zero error */
+
+	/*
+	 * Normalize first:
+	 * qequires high bit of V to be set,
+	 * so find most significant by shifting
+	 * until DIGMSB is set.
+	 */
+	for (shift = 0; 0 == (v & DIGMSB); shift++)
+		v <<= 1;
+	r = bn_shl(q, u, shift, nlimb);
+	
+	j = nlimb;
+	while (j-- > 0) {
+		t[0] = q[j];
+		t[1] = r;
+		sl_div(&q[j], &r, t, v);
+	}
+
+	/* Unnormalize */
+	r >>= shift;
+	return r;
+}
+
+/**
+ * @brief Modulo a bignum by a single limb
+ *
+ * Computes remainder (modulo) r = u[] mod v
+ * Computes r = u[] mod v
+ * where u is a big number integer of nlimb
+ * and r, v are single precision limbs
+ * 
+ * Use remainder from divide function.
+ *
+ * @param u pointer to an array of limbs (dividend)
+ * @param v single limb (divisor)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result single limb remainder of the division (modulo)
+ */
+limb_t bn_mod_limb(limb_t u[], limb_t v, count_t nlimb)
+{
+	static IGRAPH_THREAD_LOCAL limb_t q[2*BN_MAXSIZE];
+	limb_t r;
+
+	r = bn_div_limb(q, u, v, nlimb);
+
+	bn_zero(q, nlimb);
+	return r;
+}
+
+/**
+ * @brief Multiply a bignum by a single limb
+ *
+ * Computes product w[] = u[] * v
+ * Returns overflow k
+ * where w, u are big number integers of nlimb each
+ * and v is a single limb
+ *
+ * @param w pointer to an array of limbs to receive the result
+ * @param u pointer to an array of limbs (factor)
+ * @param v single limb (other factor)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero if no overflow, else overflow (value of w[nlimb])
+ */
+limb_t bn_mul_limb(limb_t w[], limb_t u[], limb_t v, count_t nlimb)
+{
+	limb_t t[2];
+	limb_t carry;
+	count_t j;
+
+	if (0 == v) {
+		bn_zero(w, nlimb);
+		return 0;
+	}
+
+	for (j = 0, carry = 0; j < nlimb; j++) {
+		sl_mul(t, u[j], v);
+		w[j] = t[0] + carry;
+		carry = t[1] + (w[j] < carry ? 1 : 0);
+	}
+
+	return carry;
+}
+
+#if	HAVE_U64
+/**
+ * @brief Computes quotient and remainder of 64 bit / 32 bit
+ *
+ * Computes quotient q = u[] / v, remainder r = u[] mod v
+ * where u[] is a double limb.
+ *
+ * With native support for double limb division
+ *
+ * @param q pointer to the limb to receive the quotient
+ * @param r pointer to the limb to receive the remainder
+ * @param u pointer to an array of two limbs
+ * @param v single limb divisor
+ *
+ * @result zero on success
+ */
+limb_t sl_div(limb_t *q, limb_t *r, limb_t u[2], limb_t v)
+{
+#if	ASM_X86
+	limb_t qq;
+	limb_t rr;
+
+	if (0 == v)
+		/* division by zero */
+		return LIMBMASK;
+	asm volatile(
+		"divl	%4"
+		: "=a"(qq), "=d"(rr)
+		: "a"(u[0]), "d"(u[1]), "g"(v));
+	*q = qq;
+	*r = rr;
+#else
+	dlimb_t dd;
+
+	if (0 == v)
+		/* division by zero */
+		return LIMBMASK;
+	dd = ((dlimb_t)u[1] << LIMBBITS) | u[0];
+	*q = (limb_t) (dd / v);
+	*r = dd % v;
+#endif
+	return 0;
+}
+
+#else
+
+#define B (HALFMASK + 1)
+
+/**
+ * @brief Computes quotient and remainder of 64 bit / 32 bit
+ *
+ * Computes quotient q = u / v, remainder r = u mod v
+ * where u is a double limb
+ * and q, v, r are single precision limbs.
+ * Returns high limb of quotient (max value is 1)
+ * Assumes normalized such that v1 >= b/2
+ * where b is size of HALF_DIGIT
+ * i.e. the most significant bit of v should be one
+ * 
+ * In terms of half-limbs in Knuth notation:
+ *   (q2q1q0) = (u4u3u2u1u0) / (v1v0)
+ *   (r1r0) = (u4u3u2u1u0) % (v1v0)
+ * for m = 2, n = 2 where u4 = 0
+ *
+ * We set q = (q1q0) and return q2 as "overflow'
+ * Returned q2 is either 0 or 1.
+ *
+ * @param q pointer to the limb to receive the quotient
+ * @param r pointer to the limb to receive the remainder
+ * @param u pointer to an array of two limbs
+ * @param v single limb divisor
+ *
+ * @result zero on success
+ */
+limb_t sl_div(limb_t *q, limb_t *r, limb_t u[2], limb_t v)
+{
+	limb_t quot;
+	limb_t rem;
+	limb_t ul;
+	limb_t uh;
+	limb_t p0;
+	limb_t p1;
+	limb_t v0;
+	limb_t v1;
+	limb_t u0;
+	limb_t u1;
+	limb_t u2;
+	limb_t u3;
+	limb_t borrow;
+	limb_t q1;
+	limb_t q2;
+	limb_t s;
+	limb_t t;
+
+	/* Check for normalisation */
+	if (0 == (v & DIGMSB)) {
+		*q = *r = 0;
+		return LIMBMASK;
+	}
+	
+	/* Split up into half-limbs */
+	v0 = LSH(v);
+	v1 = MSH(v);
+	u0 = LSH(u[0]);
+	u1 = MSH(u[0]);
+	u2 = LSH(u[1]);
+	u3 = MSH(u[1]);
+
+	/* Do three rounds of Knuth Algorithm D Vol 2 p272 */
+
+	/*
+	 * ROUND 1 calculate q2:
+	 * estimate quot = (u4u3)/v1 = 0 or 1,
+	 * then set (u4u3u2) -= quot*(v1v0) where u4 = 0.
+	 */
+	quot = u3 / v1;
+	if (quot > 0) {
+		rem = u3 - quot * v1;
+		t = SHL(rem) | u2;
+		if (quot * v0 > t)
+			quot--;
+	}
+	uh = 0;		/* (u4) */
+	ul = u[1];	/* (u3u2) */
+	if (quot > 0) {
+		/* (u4u3u2) -= quot*(v1v0) where u4 = 0 */
+		p0 = quot * v0;
+		p1 = quot * v1;
+		s = p0 + SHL(p1);
+		ul -= s;
+		borrow = (ul > ~s ? 1 : 0);
+		uh -= MSH(p1) - borrow;
+
+		if (0 != MSH(uh)) {
+			/* add back */
+			quot--;
+			ul += v;
+			uh = 0;
+		}
+	}
+	q2 = quot;
+
+	/*
+	 * ROUND 2 calculate q1:
+	 * estimate quot = (u3u2) / v1,
+	 * then set (u3u2u1) -= quot*(v1v0)
+	 */
+	t = ul;
+	quot = t / v1;
+	rem = t - quot * v1;
+	/* Test on v0 */
+	t = SHL(rem) | u1;
+	if (B == quot || (quot * v0) > t) {
+		quot--;
+		rem += v1;
+		t = SHL(rem) | u1;
+		if (rem < B && (quot * v0) > t)
+			quot--;
+	}
+
+	/*
+	 * multiply and subtract:
+	 * (u3u2u1)' = (u3u2u1) - quot*(v1v0)	
+	 */
+	uh = MSH(ul);	/* (0u3) */
+	ul = SHL(ul) | u1;	/* (u2u1) */
+	p0 = quot * v0;
+	p1 = quot * v1;
+	s = p0 + SHL(p1);
+	ul -= s;
+	borrow = (ul > ~s ? 1 : 0);
+	uh -= MSH(p1) - borrow;
+
+	if (0 != MSH(uh)) {
+		/* add back v */
+		quot--;
+		ul += v;
+		uh = 0;
+	}
+
+	/* quotient q1 */
+	q1 = quot;
+
+	/*
+	 * ROUND 3:
+	 * calculate q0; estimate quot = (u2u1) / v1,
+	 * then set (u2u1u0) -= quot(v1v0)
+	 */
+	t = ul;
+	quot = t / v1;
+	rem = t - quot * v1;
+	/* Test on v0 */
+	t = SHL(rem) | u0;
+	if (B == quot || (quot * v0) > t) {
+		quot--;
+		rem += v1;
+		t = SHL(rem) | u0;
+		if (rem < B && (quot * v0) > t)
+			quot--;
+	}
+
+	/*
+	 * multiply and subtract:
+	 * (u2u1u0)" = (u2u1u0)' - quot(v1v0)
+	 */
+	uh = MSH(ul);			/* (0u2) */
+	ul = SHL(ul) | u0;	/* (u1u0) */
+
+	p0 = quot * v0;
+	p1 = quot * v1;
+	s = p0 + SHL(p1);
+	ul -= s;
+	borrow = (ul > ~s ? 1 : 0);
+	uh -= MSH(p1) - borrow;
+	if (0 != MSH(uh)) {
+		/* add back v */
+		quot--;
+		ul += v;
+		uh = 0;
+	}
+
+	/* quotient q1q0 */
+	*q = SHL(q1) | LSH(quot);
+
+	/* Remainder is in (u1u0) i.e. ul */
+	*r = ul;
+
+	/* quotient q2 (overflow) is returned */
+	return q2;
+}
+
+#endif	/* HAVE_U64 */
+
+/**
+ * @brief Return greatest common divisor of two single limbs
+ *
+ * Returns gcd(x, y)
+ *
+ * Ref: Schneier 2nd ed, p245
+ *
+ * @param x single limb candidate #1
+ * @param y single limb candidate #2
+ *
+ * @result return zero if x and y are zero, else gcd(x,y)
+ */
+limb_t sl_gcd(limb_t x, limb_t y)
+{
+	limb_t g;
+
+	if (x + y == 0)
+		return 0;	/* Error */
+
+	g = y;
+	while (x > 0) {
+		g = x;
+		x = y % x;
+		y = g;
+	}
+	return g;
+}
+
+/**
+ * @brief Compute single limb exp = x^e mod m
+ *
+ * Computes exp = x^e mod m
+ * Binary left-to-right method
+ *
+ * @param exp pointer to limb to receive result
+ * @param x single limb x (base)
+ * @param e single limb e (exponent)
+ * @param m single limb m (modulus)
+ *
+ * @result zero on success (always!?)
+ */
+int sl_modexp(limb_t *exp, limb_t x, limb_t e, limb_t m)
+{
+	limb_t mask;
+	limb_t y;	/* Temp variable */
+
+	/* Find most significant bit in e */
+	for (mask = DIGMSB; mask > 0; mask >>= 1) {
+		if (e & mask)
+			break;
+	}
+
+	y = x;
+
+	for (mask >>= 1; mask > 0; mask >>= 1) {
+		sl_modmul(&y, y, y, m);		/* y = (y^2) % m */
+		if (e & mask)
+			sl_modmul(&y, y, x, m);	/* y = (y*x) % m*/
+	}
+
+	*exp = y;
+	return 0;
+}
+
+/**
+ * @brief Compute single limb inverse inv = u^(-1) % v
+ *
+ * Computes inv = u^(-1) % v
+ * Ref: Knuth Algorithm X Vol 2 p 342 
+ * ignoring u2, v2, t2 and avoiding negative numbers
+ *
+ * @param inv pointer to limb to receive result
+ * @param u single limb to inverse
+ * @param v single limb modulus
+ *
+ * @result zero on success (always!?)
+ */
+int sl_modinv(limb_t *inv, limb_t u, limb_t v)
+{
+	limb_t u1, u3, v1, v3, t1, t3, q, w;
+	int iter = 1;
+	
+	/* Step X1. Initialize */
+	u1 = 1;
+	u3 = u;
+	v1 = 0;
+	v3 = v;
+
+	/* Step X2. */
+	while (v3 != 0) {
+		/* Step X3. */
+		q = u3 / v3;	/* Divide and */
+		t3 = u3 % v3;
+		w = q * v1;	/* "Subtract" */
+		t1 = u1 + w;
+		/* Swap */
+		u1 = v1;
+		v1 = t1;
+		u3 = v3;
+		v3 = t3;
+		iter = -iter;
+	}
+
+	if (iter < 0)
+		*inv = v - u1;
+	else
+		*inv = u1;
+
+	return 0;
+}
+
+/**
+ * @brief Compute single limb a = (x * y) % mod
+ *
+ * Computes a = (x * y) % m
+ *
+ * @param a pointer to single limb to receive result
+ * @param x single limb factor 1
+ * @param y single limb factor 2
+ * @param m single limb modulus
+ *
+ * @result zero on success (always!?)
+ */
+int sl_modmul(limb_t *a, limb_t x, limb_t y, limb_t m)
+{
+	static IGRAPH_THREAD_LOCAL limb_t pp[2];
+
+	/* pp[] = x * y */
+	sl_mul(pp, x, y);
+
+	/* *a = pp[] % m */
+	*a = bn_mod_limb(pp, m, 2);
+
+	/* Clean temp */
+	pp[0] = pp[1] = 0;
+	return 0;
+}
+
+#if	HAVE_U64
+/**
+ * @brief Compute double limb product of two single limbs
+ *
+ * Computes p[] = x * y
+ * where p is two limbs (double precision) and x, y are single
+ * limbs. Use double precision natively supported on this machine.
+ *
+ * @param p pointer to an array of two limbs receiving the result
+ * @param x single limb factor #1
+ * @param y single limb factor #2
+ *
+ * @result zero on success (always)
+ */
+int sl_mul(limb_t p[2], limb_t x, limb_t y)
+{
+	dlimb_t dd;
+
+	dd = (dlimb_t)x * y;
+	p[0] = (limb_t)dd;
+	p[1] = (limb_t)(dd >> 32);
+	return 0;
+}
+
+#else
+
+/**
+ * @brief Compute double limb product of two single limbs
+ *
+ * Computes p[] = x * y
+ * Source: Arbitrary Precision Computation
+ * http://numbers.computation.free.fr/Constants/constants.html
+ *
+ * The limbs x and y are split in halves and the four products
+ * x1*y1, x0*y1, x1*y0 and x0*y0 are added shifting them to
+ * their respective least significant bit position:
+ * p[1] = x1*y1 + high(x0*y1 + x1*y0) + ch << 16 + cl
+ * p[0] = x0*y0 + low(x0*y1 + x1*y0) << 16
+ * ch = carry from adding x0*y1 + x1*y0
+ * cl = carry from adding low(x0*y1 + x1*y0) << 16 to p[0]
+ *
+ * @param p pointer to an array of two limbs receiving the result
+ * @param x single limb factor #1
+ * @param y single limb factor #2
+ *
+ * @result zero on success (always)
+ */
+int sl_mul(limb_t p[2], limb_t x, limb_t y)
+{
+	limb_t x0, y0, x1, y1;
+	limb_t t, u, carry;
+
+	/*
+	 * Split each x,y into two halves
+	 *   x = x0 + B*x1
+	 *   y = y0 + B*y1
+	 * where B = 2^16, half the limb size
+	 * Product is
+	 *   xy = x0y0 + B(x0y1 + x1y0) + B^2(x1y1)
+	 */
+	x0 = LSH(x);
+	x1 = MSH(x);
+	y0 = LSH(y);
+	y1 = MSH(y);
+
+	/* Compute low part (w/o carry) */
+	p[0] = x0 * y0;
+
+	/* middle part */
+	t = x0 * y1;
+	u = x1 * y0;
+	t += u;
+	carry = (t < u ? 1 : 0);
+
+	/*
+	 * The carry will go to high half of p[1],
+	 * and the high half of t will go into the
+	 * into low half of p[1]
+	 */
+	carry = SHL(carry) + MSH(t);
+
+	/* add low half of t to high half of p[0] */
+	t = SHL(t);
+	p[0] += t;
+	if (p[0] < t)
+		carry++;
+
+	p[1] = x1 * y1 + carry;
+
+	return 0;
+}
+
+#endif	/* HAVE_U64 */
+
+/**
+ * @brief Compute division of big number by a "half digit"
+ *
+ * Computes q[] = u[] / v, also returns r = u[] % v
+ * where q, a are big number integers of nlimb limbs each,
+ * and d, r are single limbs
+ *
+ * Using bit-by-bit method from MSB to LSB,
+ * so v must be <= HALFMASK
+ * 
+ * According to "Principles in PGP by Phil Zimmermann"
+ *
+ * @param q pointer to an array of limbs to receive the result
+ * @param u pointer to an array of limbs (dividend)
+ * @param v single limb (actually half limb) divisor
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result returns remainder of the division
+ */
+limb_t bn_div_hdig(limb_t q[], limb_t u[], limb_t v, count_t nlimb)
+{
+	limb_t mask = DIGMSB;
+	limb_t r = 0;
+	if (v > HALFMASK) {
+	        igraph_errorf("bn_div_hdig called with v:%x", __FILE__,
+			      __LINE__, (int) v);
+	}
+	
+	if (0 == nlimb)
+		return 0;
+	if (0 == v)
+		return 0;	/* Divide by zero error */
+
+	/* Initialize quotient */
+	bn_zero(q, nlimb);
+	
+	/* Work from MSB to LSB */
+	while (nlimb > 0) {
+		/* Multiply remainder by 2 */
+		r <<= 1;
+
+		/* Look at current bit */
+		if (u[nlimb-1] & mask)
+			r++;
+		if (r >= v) {
+			/* Remainder became greater than divisor */
+			r -= v;
+			q[nlimb-1] |= mask;
+		}
+
+		/* next bit */
+		mask >>= 1;
+		if (0 != mask)
+			continue;
+
+		/* next limb */
+		--nlimb;
+		mask = DIGMSB;
+	}
+	return r;
+}
+
+/**
+ * @brief Compute single limb remainder of bignum % single limb
+ *
+ * Computes r = u[] % v
+ * where a is a big number integer of nlimb
+ * and r, v are single limbs, using bit-by-bit
+ * method from MSB to LSB.
+ * 
+ * Ref:
+ *   Derived from principles in PGP by Phil Zimmermann
+ * Note:
+ *   This method will only work until r <<= 1 overflows.
+ *   i.e. for d < DIGMSB, but we keep HALF_DIGIT
+ *   limit for safety, and also because we don't
+ *   have a 32nd bit.
+ *
+ * @param u pointer to big number to divide
+ * @param v single limb (actually half limb) modulus
+ * @param nlimb number of limbs in the array
+ *
+ * @result returns remainder of the division
+ */
+limb_t bn_mod_hdig(limb_t u[], limb_t v, count_t nlimb)
+{
+	limb_t mask;
+	limb_t r;
+
+	if (0 == nlimb)
+		return 0;
+	if (0 == v)
+		return 0;	/* Divide by zero error */
+
+	if (v > HALFMASK) {
+	        igraph_errorf("bn_mod_hdig called with v:%x", __FILE__,
+			      __LINE__, (int) v);
+	}
+
+	/* Work from left to right */
+	mask = DIGMSB;
+	r = 0;
+	while (nlimb > 0) {
+		/* Multiply remainder by 2 */
+		r <<= 1;
+
+		/* Look at current bit */
+		if (u[nlimb-1] & mask)
+			r++;
+
+		if (r >= v)
+			/* Remainder became greater than divisor */
+			r -= v;
+
+		/* next bit */
+		mask >>= 1;
+		if (0 != mask)
+			continue;
+
+		/* next limb */
+		--nlimb;
+		mask = DIGMSB;
+	}
+	return r;
+}
+
+/**
+ * @brief Addition of two bignum arrays
+ *
+ * Computes w[] = u[] + v[]
+ * where w, u, v are big number integers of nlimb limbs each.
+ * Returns carry, i.e. w[nlimb], as 0 or 1.
+ * 
+ * Ref: Knuth Vol 2 Ch 4.3.1 p 266 Algorithm A.
+ *
+ * @param w pointer to array of limbs to receive the result
+ * @param u pointer to array of limbs (addend #1)
+ * @param v pointer to array of limbs (addend #2)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result returns the carry, i.e. w[nlimb], as 0 or 1
+ */
+limb_t bn_add(limb_t w[], limb_t u[], limb_t v[], count_t nlimb)
+{
+	limb_t carry;
+	count_t j;
+
+	for (j = 0, carry = 0; j < nlimb; j++) {
+		/*
+		 * add limbs w[j] = u[j] + v[j] + carry;
+		 * set carry = 1 if carry (overflow) occurs
+		 */
+		w[j] = u[j] + carry;
+		carry = (w[j] < carry ? 1 : 0);
+
+		w[j] = w[j] + v[j];
+		if (w[j] < v[j])
+			carry++;
+	}
+
+	/* w[n] = carry */
+	return carry;
+}
+
+/**
+ * @brief Subtraction of two bignum arrays
+ *
+ * Calculates w[] = u[] - v[] where u[] >= v[]
+ * w, u, v are big number integers of nlimb limbs each
+ * Returns 0 if ok, or 1 if v was greater than u.
+ * 
+ * Ref: Knuth Vol 2 Ch 4.3.1 p 267 Algorithm S.
+ *
+ * @param w pointer to array of limbs to receive the result
+ * @param u pointer to array of limbs (minuend)
+ * @param v pointer to array of limbs (subtrahend)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero on success, 1 if v was greater than u
+ */
+limb_t bn_sub(limb_t w[], limb_t u[], limb_t v[], count_t nlimb)
+{
+	limb_t borrow;
+	count_t j;
+
+	for (j = 0, borrow = 0; j < nlimb; j++) {
+		/*
+		 * Subtract limbs w[j] = u[j] - v[j] - borrow;
+		 * set borrow = 1 if borrow occurs
+		 */
+		w[j] = u[j] - borrow;
+		borrow = (w[j] > ~borrow ? 1 : 0);
+
+		w[j] = w[j] - v[j];
+		if (w[j] > ~v[j])
+			borrow++;
+	}
+
+	/* borrow should be 0, if u >= v */
+	return borrow;
+}
+
+/**
+ * @brief Product of two bignum arrays
+ *
+ * Computes product w[] = u[] * v[]
+ * where u, v are big number integers of nlimb each
+ * and w is a big number integer of 2*nlimb limbs.
+ * 
+ * Ref: Knuth Vol 2 Ch 4.3.1 p 268 Algorithm M.
+ *
+ * @param w pointer to array of limbs to receive the result
+ * @param u pointer to array of limbs (factor #1)
+ * @param v pointer to array of limbs (factor #2)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero on success (always!?)
+ */
+int bn_mul(limb_t w[], limb_t u[], limb_t v[], count_t nlimb)
+{
+	limb_t t[2];
+	limb_t carry;
+	count_t i, j, m, n;
+
+	m = n = nlimb;
+
+	/* zero result */
+	bn_zero(w, 2*nlimb);
+
+	for (j = 0; j < n; j++) {
+		/* zero multiplier? */
+		if (0 == v[j]) {
+			w[j+m] = 0;
+			continue;
+		}
+		/* Initialize i */
+		carry = 0;
+		for (i = 0; i < m; i++) {
+			/*
+			 * Multiply and add:
+			 * t = u[i] * v[j] + w[i+j] + carry
+			 */
+			sl_mul(t, u[i], v[j]);
+
+			t[0] += carry;
+			if (t[0] < carry)
+				t[1]++;
+			t[0] += w[i+j];
+			if (t[0] < w[i+j])
+				t[1]++;
+
+			w[i+j] = t[0];
+			carry = t[1];
+		}	
+		w[j+m] = carry;
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Shift left a bignum by a number of bits (less than LIMBBITS)
+ *
+ * Computes a[] = b[] << x
+ * Where a and b are big number integers of nlimb each.
+ * The shift count must be less than LIMBBITS
+ *
+ * @param a pointer to array of limbs to receive the result
+ * @param b pointer to array of limbs to shift left
+ * @param x number of bits to shift (must be less than LIMBBITS)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result returns a single limb "carry", i.e. bits that came out left
+ */
+limb_t bn_shl(limb_t a[], limb_t b[], count_t x, count_t nlimb)
+{
+	count_t i, y;
+	limb_t carry, temp;
+
+	if (0 == nlimb)
+		return 0;
+
+	if (0 == x) {
+		/* no shift at all */
+		if (a != b)
+			bn_copy(a, b, nlimb);
+		return 0;
+	}
+
+	/* check shift amount */
+	if (x >= LIMBBITS) {
+	        igraph_errorf("bn_shl() called with x >= %d", __FILE__,
+			      __LINE__, LIMBBITS);
+		return 0;
+	}
+
+	y = LIMBBITS - x;
+	carry = 0;
+	for (i = 0; i < nlimb; i++) {
+		temp = b[i] >> y;
+		a[i] = (b[i] << x) | carry;
+		carry = temp;
+	}
+
+	return carry;
+}
+
+/**
+ * @brief Shift right a bignum by a number of bits (less than LIMBBITS)
+ *
+ * Computes a[] = b[] >> x
+ * Where a and b are big number integers of nlimb each.
+ * The shift count must be less than LIMBBITS
+ *
+ * @param a pointer to array of limbs to receive the result
+ * @param b pointer to array of limbs to shift right
+ * @param x number of bits to shift (must be less than LIMBBITS)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result returns a single limb "carry", i.e. bits that came out right
+ */
+limb_t bn_shr(limb_t a[], limb_t b[], count_t x, count_t nlimb)
+{
+	count_t i, y;
+	limb_t carry, temp;
+
+	if (0 == nlimb)
+		return 0;
+
+	if (0 == x) {
+		/* no shift at all */
+		if (a != b)
+			bn_copy(a, b, nlimb);
+		return 0;
+	}
+
+	/* check shift amount */
+	if (x >= LIMBBITS) {
+	        igraph_errorf("bn_shr() called with x >= %d", __FILE__,
+			      __LINE__, LIMBBITS);
+	}
+
+	y = LIMBBITS - x;
+	carry = 0;
+	i = nlimb;
+	while (i-- > 0) {
+		temp = b[i] << y;
+		a[i] = (b[i] >> x) | carry;
+		carry = temp;
+	}
+
+	return carry;
+}
+
+/**
+ * @brief Check a quotient for overflow
+ *
+ * Returns 1 if quot is too big,
+ * i.e. if (quot * Vn-2) > (b.rem + Uj+n-2)
+ * Returns 0 if ok
+ *
+ * @param quot quotient under test
+ * @param rem remainder
+ * @param
+ *
+ * @result zero on success
+ */
+static int quot_overflow(limb_t quot, limb_t rem, limb_t v, limb_t u)
+{
+	limb_t t[2];
+
+	sl_mul(t, quot, v);
+	if (t[1] < rem)
+		return 0;
+	if (t[1] > rem)
+		return 1;
+	if (t[0] > u)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * @brief Compute quotient and remainder of bignum division
+ *
+ * Computes quotient q[] = u[] / v[]
+ * and remainder r[] = u[] % v[]
+ * where q, r, u are big number integers of ulimb limbs,
+ * and the divisor v of vlimb limbs.
+ * 
+ * Ref: Knuth Vol 2 Ch 4.3.1 p 272 Algorithm D.
+ *
+ * @param q pointer to array of limbs to receive quotient
+ * @param r pointer to array of limbs to receive remainder
+ * @param u pointer to array of limbs (dividend)
+ * @param ulimb number of limbs in the q, r, u arrays
+ * @param v pointer to array of limbs (divisor)
+ * @param vlimb number of limbs in the v array
+ *
+ * @result zero on success, LIMBASK on division by zero
+ */
+int bn_div(limb_t q[], limb_t r[], limb_t u[], limb_t v[],
+	count_t ulimb, count_t vlimb)
+{
+	static IGRAPH_THREAD_LOCAL limb_t qq[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t uu[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t vv[BN_MAXSIZE];
+	limb_t mask;
+	limb_t overflow;
+	limb_t quot;
+	limb_t rem;
+	limb_t t[2];
+	limb_t *ww;
+	count_t n, m, i, j, shift;
+	int ok, cmp;
+
+	/* find size of v */
+	n = bn_sizeof(v, vlimb);
+
+	/* Catch special cases */
+	if (0 == n)
+	  return (int) LIMBMASK;	/* Error: divide by zero */
+
+	if (1 == n) {
+		/* Use short division instead */
+		r[0] = bn_div_limb(q, u, v[0], ulimb);
+		return 0;
+	}
+
+	/* find size of u */
+	m = bn_sizeof(u, ulimb);
+
+	if (m < n) {
+		/* v > u: just set q = 0 and r = u */
+		bn_zero(q, ulimb);
+		bn_copy(r, u, ulimb);
+		return 0;
+	}
+
+	if (m == n) {
+		/* u and v are the same length: compare them */
+		cmp = bn_cmp(u, v, (unsigned int)n);
+		if (0 == cmp) {
+			/* v == u: set q = 1 and r = 0 */
+			bn_limb(q, 1, ulimb);
+			bn_zero(r, ulimb);
+			return 0;
+		}
+		if (cmp < 0) {
+			/* v > u: set q = 0 and r = u */
+			bn_zero(q, ulimb);
+			bn_copy(r, u, ulimb);
+			return 0;
+		}
+	}
+
+	/* m greater than or equal to n */
+	m -= n;
+
+	/* clear quotient qq */
+	bn_zero(qq, ulimb);
+
+	/*
+	 * Normalize v: requires high bit of v[n-1] to be set,
+	 * so find most significant bit, then shift left
+	 */
+	mask = DIGMSB;
+	for (shift = 0; shift < LIMBBITS; shift++) {
+		if (v[n-1] & mask)
+			break;
+		mask >>= 1;
+	}
+
+	/* normalize vv from v */
+	overflow = bn_shl(vv, v, shift, n);
+
+	/* copy normalized dividend u into remainder uu */
+	overflow = bn_shl(uu, u, shift, n + m);
+
+	/* new limb u[m+n] */
+	t[0] = overflow;
+
+	j = m + 1;
+	while (j-- > 0) {
+		/* quot = (b * u[j+n] + u[j+n-1]) / v[n-1] */
+		ok = 0;
+
+		/* This is Uj+n */
+		t[1] = t[0];
+		t[0] = uu[j+n-1];
+
+		overflow = sl_div(&quot, &rem, t, vv[n-1]);
+
+		if (overflow) {
+			/* quot = b */
+			quot = LIMBMASK;
+			rem = uu[j+n-1] + vv[n-1];
+			if (rem < vv[n-1])
+				ok = 1;
+		}
+		if (0 == ok && quot_overflow(quot, rem, vv[n-2], uu[j+n-2])) {
+			/* quot * v[n-2] > b * rem + u[j+n-2] */
+			quot--;
+			rem += vv[n-1];
+			if (rem >= vv[n-1])
+				if (quot_overflow(quot, rem, vv[n-2], uu[j+n-2]))
+					quot--;
+		}
+
+		/* multiply and subtract vv[] * quot */
+		ww = &uu[j];
+
+		if (0 == quot) {
+			overflow = 0;
+		} else {
+			/* quot is non zero */
+			limb_t tt[2];
+			limb_t borrow;
+
+			for (i = 0, borrow = 0; i < n; i++) {
+				sl_mul(tt, quot, vv[i]);
+				ww[i] -= borrow;
+				borrow = (ww[i] > ~borrow ? 1 : 0);
+
+				ww[i] -= tt[0];
+				if (ww[i] > ~tt[0])
+					borrow++;
+				borrow += tt[1];
+			}
+
+			/*
+			 * w[n] is not in array w[0..n-1]:
+			 * subtract final borrow
+			 */
+			overflow = t[1] - borrow;
+		}
+
+		/* test for remainder */
+		if (overflow) {
+			quot--;
+			/* add back if mul/sub was negative */
+			overflow = bn_add(ww, ww, vv, n);
+		}
+
+		qq[j] = quot;
+
+		/* u[j+n] for next round */
+		t[0] = uu[j+n-1];
+	}
+
+	/* clear uu[] limbs from n to n+m */
+	for (j = n; j < m+n; j++)
+		uu[j] = 0;
+
+	/* denormalize remainder */
+	bn_shr(r, uu, shift, n);
+
+	/* copy quotient */
+	bn_copy(q, qq, n + m);
+
+	/* clear temps */
+	bn_zero(qq, n);
+	bn_zero(uu, n);
+	bn_zero(vv, n);
+	return 0;
+}
+
+/**
+ * @brief Compute remainder of bignum division (modulo)
+ *
+ * Calculates r[] = u[] % v[]
+ * where r, v are big number integers of length vlimb
+ * and u is a big number integer of length ulimb.
+ * r may overlap v.
+ * 
+ * Note that r here is only vlimb long, 
+ * whereas in bn_div it is ulimb long.
+ * 
+ * Use remainder from bn_div function.
+ *
+ * @param r pointer to array of limbs to receive remainder
+ * @param u pointer to array of limbs (dividend)
+ * @param ulimb number of limbs in the u array
+ * @param v pointer to array of limbs (divisor)
+ * @param vlimb number of limbs in the r and v array
+ *
+ * @result zero on success, LIMBASK on division by zero
+ */
+limb_t bn_mod(limb_t r[], limb_t u[], count_t ulimb, limb_t v[], count_t vlimb)
+{
+	static IGRAPH_THREAD_LOCAL limb_t qq[2*BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t rr[2*BN_MAXSIZE];
+	limb_t d0;
+
+	/* rr[] = u[] % v[n] */
+	d0 = (limb_t) bn_div(qq, rr, u, v, ulimb, vlimb);
+
+	/* copy vlimb limbs of remainder */
+	bn_copy(r, rr, vlimb);
+
+	/* zero temps */
+	bn_zero(rr, ulimb);
+	bn_zero(qq, ulimb);
+
+	return d0;
+}
+
+/**
+ * @brief Compute greatest common divisor
+ *
+ * Computes g = gcd(x, y)
+ * Reference: Schneier
+ *
+ * @param g pointer to array of limbs to receive the gcd
+ * @param x pointer to array of limbs (candidate #1)
+ * @param y pointer to array of limbs (candidate #2)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero on succes (always)
+ */
+int bn_gcd(limb_t g[], limb_t x[], limb_t y[], count_t nlimb)
+{	
+	static IGRAPH_THREAD_LOCAL limb_t yy[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t xx[BN_MAXSIZE];
+	
+	bn_copy(xx, x, nlimb);
+	bn_copy(yy, y, nlimb);
+
+	/* g = y */
+	bn_copy(g, yy, nlimb);
+	
+	/* while (x > 0) { */
+	while (0 != bn_cmp_limb(xx, 0, nlimb)) {
+		/* g = x */
+		bn_copy(g, xx, nlimb);
+		/* x = y % x */
+		bn_mod(xx, yy, nlimb, xx, nlimb);
+		/* y = g */
+		bn_copy(yy, g, nlimb);
+	}
+
+	bn_zero(xx, nlimb);
+	bn_zero(yy, nlimb);
+	
+	/* gcd is left in g */
+	return 0;
+}
+
+/**
+ * @brief Compute modular exponentiation of bignums
+ *
+ * Computes y[] = (x[]^e[]) % m[]
+ * Binary MSB to LSB method
+ *
+ * @param y pointer to array of limbs to receive the result
+ * @param x pointer to array of limbs (base)
+ * @param e pointer to array of limbs (exponent)
+ * @param m pointer to array of limbs (modulus)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero on success, -1 on error (nlimb is zero)
+ */
+int bn_modexp(limb_t y[], limb_t x[], limb_t e[], limb_t m[], count_t nlimb)
+{
+	limb_t mask;
+	count_t n;
+	
+	if (nlimb == 0)
+		return -1;
+
+	/* Find second-most significant bit in e */
+	n = bn_sizeof(e, nlimb);
+	for (mask = DIGMSB; 0 != mask; mask >>= 1) {
+		if (e[n-1] & mask)
+			break;
+	}
+	/* next bit, because we start off with y[] == x[] */
+	mask >>= 1;
+	if (0 == mask) {
+		mask = DIGMSB;
+		n--;
+	}
+
+	/* y[] = x[] */
+	bn_copy(y, x, nlimb);
+
+	while (n > 0) {
+		/* y[] = (y[] ^ 2) % m[] */
+		bn_modmul(y, y, y, m, nlimb);
+
+		if (e[n-1] & mask)
+			/* y[] = (y[] * x[]) % m[] */
+			bn_modmul(y, y, x, m, nlimb);
+
+		/* next bit */
+		mask >>= 1;
+		if (0 == mask) {
+			mask = DIGMSB;
+			n--;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Compute modular product of two bignums
+ *
+ * Computes a[] = (x[] * y[]) % m[]
+ * where a, x, y and m are big numbers of nlimb length
+ *
+ * @param a pointer to array of limbs to receive the result
+ * @param x pointer to array of limbs (factor #1)
+ * @param y pointer to array of limbs (factor #2)
+ * @param m pointer to array of limbs (modulus)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero on success, LIMBMASK if m was zero (division by zero)
+ */
+limb_t bn_modmul(limb_t a[], limb_t x[], limb_t y[], limb_t m[], count_t nlimb)
+{
+	static IGRAPH_THREAD_LOCAL limb_t pp[2*BN_MAXSIZE];
+	limb_t d0;
+
+	/* pp[] = x[] * y[] (NB: double size pp[]) */
+	bn_mul(pp, x, y, nlimb);
+
+	/* a[] = pp[] % m[] */
+	d0 = bn_mod(a, pp, 2*nlimb, m, nlimb);
+
+	/* zero temp */
+	bn_zero(pp, 2*nlimb);
+
+	return d0;
+}
+
+/**
+ * @brief Compute modular inverse
+ *
+ * Computes inv[] = u[]^(-1) % v[]
+ * Ref: Knuth Algorithm X Vol 2 p 342
+ * ignoring u2, v2, t2 and avoiding negative numbers.
+ *
+ * @param inv pointer to array of limbs receiving the result
+ * @param u pointer to array of limbs (candidate)
+ * @param v pointer to array of limbs (modulus)
+ * @param nlimb number of limbs in the arrays
+ *
+ * @result zero on success
+ */
+int bn_modinv(limb_t inv[], limb_t u[], limb_t v[], count_t nlimb)
+{
+	/* Allocate temp variables */
+	static IGRAPH_THREAD_LOCAL limb_t u1[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t u3[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t v1[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t v3[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t t1[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t t3[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t q[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t w[2*BN_MAXSIZE];
+	int iter;
+
+	/* Step X1. Initialize */
+	bn_limb(u1, 1, nlimb);	/* u1 = 1 */
+	bn_limb(v1, 0, nlimb);	/* v1 = 0 */
+	bn_copy(u3, u, nlimb);	/* u3 = u */
+	bn_copy(v3, v, nlimb);	/* v3 = v */
+
+	/* remember odd/even iterations */
+	iter = 1;
+
+	/* Step X2. Loop while v3 != 0 */
+	while (0 != bn_cmp_limb(v3, 0, nlimb)) {
+		/* Step X3. Divide and "Subtract" */
+		/* q = u3 / v3, t3 = u3 % v3 */
+		bn_div(q, t3, u3, v3, nlimb, nlimb);
+		/* w = q * v1 */
+		bn_mul(w, q, v1, nlimb);
+		/* t1 = u1 + w */
+		bn_add(t1, u1, w, nlimb);
+
+		/* Swap u1 <= v1 <= t1 */
+		bn_copy(u1, v1, nlimb);
+		bn_copy(v1, t1, nlimb);
+
+		/* Swap u3 <= v3 <= t3 */
+		bn_copy(u3, v3, nlimb);
+		bn_copy(v3, t3, nlimb);
+
+		iter ^= 1;
+	}
+
+	if (iter)
+		bn_copy(inv, u1, nlimb);	/* inv = u1 */
+	else
+		bn_sub(inv, v, u1, nlimb);	/* inv = v - u1 */
+
+	/* clear temp vars */
+	bn_zero(u1, nlimb);
+	bn_zero(v1, nlimb);
+	bn_zero(t1, nlimb);
+	bn_zero(u3, nlimb);
+	bn_zero(v3, nlimb);
+	bn_zero(t3, nlimb);
+	bn_zero(q, nlimb);
+	bn_zero(w, 2*nlimb);
+
+	return 0;
+}
+
+/**
+ * @brief Compute square root (and fraction) of a bignum
+ *
+ * Compute q[] = sqrt(u[]),
+ * where q and u are big number integers of nlimb limbs
+ *
+ * Method according to sqrt.html of 2001-08-15:
+ * Act on bytes from MSB to LSB, counting the number of times
+ * that we can subtract consecutive odd numbers starting with
+ * 1, 3, 5. Just uses add, subtract, shift and comparisons.
+ *
+ * The pointer r can be NULL if caller is not interested in
+ * the (partial) fraction.
+ *
+ * @param q pointer to array of limbs to receive the result (integer)
+ * @param r pointer to array of limbs to receive the result (fraction)
+ * @param u pointer to array of limbs (square)
+ * @param rlimb number of limbs in the q and r arrays
+ * @param ulimb number of limbs in the u array
+ *
+ * @result zero on success
+ */
+int bn_sqrt(limb_t q[], limb_t r[], limb_t u[], count_t rlimb, count_t ulimb)
+{
+	static IGRAPH_THREAD_LOCAL limb_t step[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t accu[BN_MAXSIZE];
+	static IGRAPH_THREAD_LOCAL limb_t w[2*BN_MAXSIZE];
+	limb_t d;
+	count_t m, n;
+	count_t shift;
+
+	bn_zero(q, ulimb);
+	bn_limb(step, 1, BN_MAXSIZE);
+	bn_limb(accu, 0, BN_MAXSIZE);
+	n = bn_sizeof(u, ulimb);
+
+	/* determine first non-zero byte from MSB to LSB */
+	if (0 != (u[n-1] >> 24)) {
+		shift = 32;
+	} else if (0 != (u[n-1] >> 16)) {
+		shift = 24;
+	} else if (0 != (u[n-1] >> 8)) {
+		shift = 16;
+	} else {
+		shift = 8;
+	}
+
+	m = 1;
+	while (n-- > 0) {
+		while (shift > 0) {
+			/* shift accu one byte left */
+			bn_shl(accu, accu, 8, m+1);
+
+			/* shift for next byte from u[] */
+			shift -= 8;
+			accu[0] |= (u[n] >> shift) & 0xff;
+
+			/* digit = 0 */
+			d = 0;
+			/* subtract consecutive odd numbers step[] until overflow */
+			for (d = 0; bn_cmp(step, accu, m+1) <= 0; d++) {
+				bn_sub(accu, accu, step, m+1);
+				bn_add_limb(step, step, 2, m+1);
+			}
+
+			/* put digit into result */
+			bn_shl(q, q, 4, m);
+			q[0] |= d;
+
+			/* step[] = 2 * q[] * 16 + 1 */
+			bn_shl(step, q, 5, m+1);
+			bn_add_limb(step, step, 1, m+1);
+		}
+		shift = 32;
+		if (0 == (n & 1))
+			m++;
+	}
+
+	/* Caller does not want to know the fraction? */
+	if (NULL == r)
+		return 0;
+
+	/* nothing left to do if remainder is zero */
+	if (0 == bn_cmp_limb(accu, 0, ulimb)) {
+		bn_zero(r, rlimb);
+		return 0;
+	}
+
+	/* Start off with the integer part */
+	bn_zero(w, 2*BN_MAXSIZE);
+	bn_copy(w, q, ulimb);
+
+	n = rlimb * (LIMBBITS / 4);
+	while (n-- > 0) {
+		/* shift accu one byte left */
+		bn_shl(accu, accu, 8, rlimb);
+
+		/* subtract consecutive odd numbers step[] until overflow */
+		for (d = 0; bn_cmp(step, accu, rlimb) <= 0; d++) {
+			bn_sub(accu, accu, step, rlimb);
+			bn_add_limb(step, step, 2, rlimb);
+		}
+
+		/* put digit into result */
+		bn_shl(w, w, 4, rlimb);
+		w[0] |= d;
+
+		/* step[] = 2 * w[] * 16 + 1 */
+		bn_shl(step, w, 5, rlimb);
+		bn_add_limb(step, step, 1, rlimb);
+	}
+
+	/* copy remainder */
+	bn_copy(r, w, rlimb);
+	return 0;
+}
diff --git a/src/bignum.h b/src/bignum.h
new file mode 100644
index 0000000..7361388
--- /dev/null
+++ b/src/bignum.h
@@ -0,0 +1,120 @@
+/*****************************************************************************
+ *  Entropy - Emerging Network To Reduce Orwellian Potency Yield
+ *
+ *  Copyright (C) 2005 Juergen Buchmueller <pullmoll at t-online.de>
+ *
+ *  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
+ *
+ *	$Id: bignum.h,v 1.6 2005/08/11 17:57:39 pullmoll Exp $
+ *****************************************************************************/
+#ifndef _bignum_h_
+#define _bignum_h_
+
+#include "config.h"
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#else
+#  ifdef HAVE_SYS_INT_TYPES_H
+#    include <sys/int_types.h>
+#  else
+#    include "pstdint.h"
+#  endif
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef	O_BINARY
+#define	O_BINARY 0
+#endif
+
+#ifndef	HAVE_U64
+#define	HAVE_U64 1
+#endif
+
+/* up to 512 limbs (512 * 32 = 16384 bits) numbers */
+#define	BN_MAXSIZE 512
+#define	LIMBBITS 32
+#define	LIMBMASK 0xfffffffful
+#define	HALFMASK 0x0000fffful
+#define	DIGMSB 0x80000000ul
+#define	DIGLSB 0x00000001ul
+
+typedef uint32_t count_t;
+typedef uint16_t half_t;
+typedef uint32_t limb_t;
+#if HAVE_U64
+typedef uint64_t dlimb_t;
+#endif
+
+/* less significant half limb */
+#define	LSH(d)	((half_t)(d))
+/* more significant half limb */
+#define	MSH(d)	((limb_t)(d)>>16)
+/* shift left half limb */
+#define	SHL(d)	((limb_t)(d)<<16)
+
+/* single limb functions */
+limb_t sl_div(limb_t *q, limb_t *r, limb_t u[2], limb_t v);
+limb_t sl_gcd(limb_t x, limb_t y);
+int sl_modexp(limb_t *exp, limb_t x, limb_t n, limb_t d);
+int sl_modinv(limb_t *inv, limb_t u, limb_t v);
+int sl_modmul(limb_t *a, limb_t x, limb_t y, limb_t m);
+int sl_mul(limb_t p[2], limb_t x, limb_t y);
+
+/* big number functions (max. MAXSIZE limbs) */
+void bn_zero(limb_t a[], count_t nlimb);
+void bn_limb(limb_t a[], limb_t d, count_t nlimb);
+void bn_copy(limb_t a[], limb_t b[], count_t nlimb);
+count_t bn_sizeof(limb_t a[], count_t nlimb);
+int bn_cmp_limb(limb_t a[], limb_t b, count_t nlimb);
+int bn_cmp(limb_t a[], limb_t b[], count_t nlimb);
+
+/* big number to hex, decimal, binary */
+const char *bn2x(limb_t a[], count_t nlimb);
+const char *bn2d(limb_t a[], count_t nlimb);
+const char *bn2f(limb_t a[], count_t alimb, limb_t b[], count_t blimb);
+const char *bn2b(limb_t a[], count_t nlimb);
+
+/* big number with single limb operations */
+limb_t bn_add_limb(limb_t w[], limb_t u[], limb_t v, count_t nlimb);
+limb_t bn_sub_limb(limb_t w[], limb_t u[], limb_t v, count_t nlimb);
+limb_t bn_div_limb(limb_t q[], limb_t u[], limb_t v, count_t nlimb);
+limb_t bn_mod_limb(limb_t u[], limb_t d, count_t nlimb);
+limb_t bn_mul_limb(limb_t w[], limb_t u[], limb_t v, count_t nlimb);
+
+/* big number with single limb <= HALFMASK operations */
+limb_t bn_div_half(limb_t q[], limb_t u[], limb_t v, count_t nlimb);
+limb_t bn_mod_half(limb_t a[], limb_t d, count_t nlimb);
+
+/* big number operations */
+limb_t bn_add(limb_t w[], limb_t u[], limb_t v[], count_t nlimb);
+limb_t bn_sub(limb_t w[], limb_t u[], limb_t v[], count_t nlimb);
+limb_t bn_shl(limb_t a[], limb_t b[], count_t x, count_t nlimb);
+limb_t bn_shr(limb_t a[], limb_t b[], count_t x, count_t nlimb);
+int bn_mul(limb_t w[], limb_t u[], limb_t v[], count_t nlimb);
+int bn_div(limb_t q[], limb_t r[], limb_t u[], limb_t v[], count_t ulimb, count_t vlimb);
+limb_t bn_mod(limb_t r[], limb_t u[], count_t ulimb, limb_t v[], count_t vlimb);
+int bn_gcd(limb_t g[], limb_t x[], limb_t y[], count_t nlimb);
+int bn_sqrt(limb_t g[], limb_t x[], limb_t y[], count_t rlimb, count_t nlimb);
+int bn_modexp(limb_t y[], limb_t x[], limb_t e[], limb_t m[], count_t nlimb);
+int bn_modinv(limb_t inv[], limb_t u[], limb_t v[], count_t nlimb);
+limb_t bn_modmul(limb_t a[], limb_t x[], limb_t y[], limb_t m[], count_t nlimb);
+
+#endif	/* !defined(_bignum_h_) */
diff --git a/src/bipartite.c b/src/bipartite.c
new file mode 100644
index 0000000..182559e
--- /dev/null
+++ b/src/bipartite.c
@@ -0,0 +1,1118 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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_bipartite.h"
+#include "igraph_attributes.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_constructors.h"
+#include "igraph_dqueue.h"
+#include "igraph_random.h"
+#include "igraph_nongraph.h"
+
+/**
+ * \section about_bipartite Bipartite networks in igraph
+ *
+ * <para>
+ * A bipartite network contains two kinds of vertices and connections
+ * are only possible between two vertices of different kind. There are
+ * many natural examples, e.g. movies and actors as vertices and a
+ * movie is connected to all participating actors, etc.
+ * 
+ * </para><para>
+ * igraph does not have direct support for bipartite networks, at
+ * least not at the C language level. In other words the igraph_t
+ * structure does not contain information about the vertex types. 
+ * The C functions for bipartite networks usually have an additional
+ * input argument to graph, called \c types, a boolean vector giving
+ * the vertex types.
+ * 
+ * </para><para>
+ * Most functions creating bipartite networks are able to create this
+ * extra vector, you just need to supply an initialized boolean vector
+ * to them.</para>
+ */
+
+/**
+ * \function igraph_bipartite_projection_size
+ * Calculate the number of vertices and edges in the bipartite projections
+ *
+ * This function calculates the number of vertices and edges in the 
+ * two projections of a bipartite network. This is useful if you have
+ * a big bipartite network and you want to estimate the amount of
+ * memory you would need to calculate the projections themselves.
+ * 
+ * \param graph The input graph.
+ * \param types Boolean vector giving the vertex types of the graph.
+ * \param vcount1 Pointer to an \c igraph_integer_t, the number of
+ *     vertices in the first projection is stored here.
+ * \param ecount1 Pointer to an \c igraph_integer_t, the number of 
+ *     edges in the first projection is stored here.
+ * \param vcount2 Pointer to an \c igraph_integer_t, the number of 
+ *     vertices in the second projection is stored here.
+ * \param ecount2 Pointer to an \c igraph_integer_t, the number of 
+ *     edges in the second projection is stored here.
+ * \return Error code.
+ *
+ * \sa \ref igraph_bipartite_projection() to calculate the actual
+ * projection.
+ *
+ * Time complexity: O(|V|*d^2+|E|), |V| is the number of vertices, |E|
+ * is the number of edges, d is the average (total) degree of the
+ * graphs.
+ * 
+ * \example examples/simple/igraph_bipartite_projection.c
+ */
+
+int igraph_bipartite_projection_size(const igraph_t *graph,
+				     const igraph_vector_bool_t *types,
+				     igraph_integer_t *vcount1,
+				     igraph_integer_t *ecount1,
+				     igraph_integer_t *vcount2,
+				     igraph_integer_t *ecount2) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int vc1=0, ec1=0, vc2=0, ec2=0;
+  igraph_adjlist_t adjlist;
+  igraph_vector_long_t added;
+  long int i;
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &added);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_vector_int_t *neis1;
+    long int neilen1, j;
+    long int *ecptr;
+    if (VECTOR(*types)[i]) { 
+      vc2++; 
+      ecptr=&ec2;
+    } else { 
+      vc1++; 
+      ecptr=&ec1;
+    }
+    neis1=igraph_adjlist_get(&adjlist, i);
+    neilen1=igraph_vector_int_size(neis1);
+    for (j=0; j<neilen1; j++) {
+      long int k, neilen2, nei=(long int) VECTOR(*neis1)[j];
+      igraph_vector_int_t *neis2=igraph_adjlist_get(&adjlist, nei);
+      if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
+	IGRAPH_ERROR("Non-bipartite edge found in bipartite projection",
+		     IGRAPH_EINVAL);
+      }
+      neilen2=igraph_vector_int_size(neis2);
+      for (k=0; k<neilen2; k++) {
+	long int nei2=(long int) VECTOR(*neis2)[k];
+	if (nei2 <= i) { continue; }
+	if (VECTOR(added)[nei2] == i+1) { continue; }
+	VECTOR(added)[nei2] = i+1;
+	(*ecptr)++;
+      }
+    }
+  }
+
+  *vcount1=(igraph_integer_t) vc1;
+  *ecount1=(igraph_integer_t) ec1;
+  *vcount2=(igraph_integer_t) vc2;
+  *ecount2=(igraph_integer_t) ec2;
+
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_long_destroy(&added);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+int igraph_i_bipartite_projection(const igraph_t *graph,
+				  const igraph_vector_bool_t *types,
+				  igraph_t *proj,
+				  int which,
+				  igraph_vector_t *multiplicity) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, j, k;
+  igraph_integer_t remaining_nodes=0;
+  igraph_vector_t vertex_perm, vertex_index;
+  igraph_vector_t edges;
+  igraph_adjlist_t adjlist;
+  igraph_vector_int_t *neis1, *neis2;
+  long int neilen1, neilen2;
+  igraph_vector_long_t added;
+  igraph_vector_t mult;
+
+  if (which < 0) { return 0; }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&vertex_perm, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&vertex_perm, no_of_nodes));
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vertex_index, no_of_nodes);
+  IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &added);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  if (multiplicity) { 
+    IGRAPH_VECTOR_INIT_FINALLY(&mult, no_of_nodes); 
+    igraph_vector_clear(multiplicity);
+  }
+  
+  for (i=0; i<no_of_nodes; i++) {
+    if (VECTOR(*types)[i] == which) {
+      VECTOR(vertex_index)[i] = ++remaining_nodes;
+      igraph_vector_push_back(&vertex_perm, i);
+    }
+  }
+
+  for (i=0; i<no_of_nodes; i++) {
+    if (VECTOR(*types)[i] == which) {
+      long int new_i=(long int) VECTOR(vertex_index)[i]-1;
+      long int iedges=0;
+      neis1=igraph_adjlist_get(&adjlist, i);
+      neilen1=igraph_vector_int_size(neis1);
+      for (j=0; j<neilen1; j++) {
+	long int nei=(long int) VECTOR(*neis1)[j];
+	if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
+	  IGRAPH_ERROR("Non-bipartite edge found in bipartite projection",
+		       IGRAPH_EINVAL);
+	}
+	neis2=igraph_adjlist_get(&adjlist, nei);
+	neilen2=igraph_vector_int_size(neis2);
+	for (k=0; k<neilen2; k++) {
+	  long int nei2=(long int) VECTOR(*neis2)[k], new_nei2;
+	  if (nei2 <= i) { continue; }
+	  if (VECTOR(added)[nei2] == i+1) { 
+	    if (multiplicity) { VECTOR(mult)[nei2]+=1; }
+	    continue; 
+	  }
+	  VECTOR(added)[nei2] = i+1;
+	  if (multiplicity) { VECTOR(mult)[nei2]=1; }
+	  iedges++;
+
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, new_i));
+	  if (multiplicity) { 
+	    /* If we need the multiplicity as well, then we put in the
+	       old vertex ids here and rewrite it later */
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, nei2));
+	  } else { 
+	    new_nei2=(long int) VECTOR(vertex_index)[nei2]-1;
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, new_nei2));
+	  }
+	}
+      }
+      if (multiplicity) {
+	/* OK, we need to go through all the edges added for vertex new_i 
+	   and check their multiplicity */
+	long int now=igraph_vector_size(&edges);
+	long int from=now-iedges*2;
+	for (j=from; j<now; j+=2) {
+	  long int nei2=(long int) VECTOR(edges)[j+1];
+	  long int new_nei2=(long int) VECTOR(vertex_index)[nei2]-1;
+	  long int m=(long int) VECTOR(mult)[nei2];
+	  VECTOR(edges)[j+1]=new_nei2;
+	  IGRAPH_CHECK(igraph_vector_push_back(multiplicity, m));
+	}
+      }
+    } /* if VECTOR(*type)[i] == which */
+  }
+
+  if (multiplicity) { 
+    igraph_vector_destroy(&mult);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_long_destroy(&added);
+  igraph_vector_destroy(&vertex_index);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  IGRAPH_CHECK(igraph_create(proj, &edges, remaining_nodes, 
+			     /*directed=*/ 0));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, proj);
+  
+  IGRAPH_I_ATTRIBUTE_DESTROY(proj);
+  IGRAPH_I_ATTRIBUTE_COPY(proj, graph, 1, 0, 0);
+  IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm));
+  igraph_vector_destroy(&vertex_perm);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_bipartite_projection
+ * Create one or both projections of a bipartite (two-mode) network
+ * 
+ * Creates one or both projections of a bipartite graph. 
+ * \param graph The bipartite input graph. Directedness of the edges
+ *   is ignored.
+ * \param types Boolean vector giving the vertex types of the graph.
+ * \param proj1 Pointer to an uninitialized graph object, the first
+ *   projection will be created here. It a null pointer, then it is
+ *   ignored, see also the \p probe1 argument.
+ * \param multiplicity1 Pointer to a vector, or a null pointer. If not
+ *   the latter, then the multiplicity of the edges is stored
+ *   here. 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 multiplicity2 The same as \c multiplicity1, but for the
+ *   other projection.
+ * \param proj2 Pointer to an uninitialized graph object, the second
+ *   projection is created here, if it is not a null pointer. See also
+ *   the \p probe1 argument.
+ * \return Error code.
+ *
+ * \sa \ref igraph_bipartite_projection_size() to calculate the number
+ * of vertices and edges in the projections, without creating the
+ * projection graphs themselves.
+ * 
+ * Time complexity: O(|V|*d^2+|E|), |V| is the number of vertices, |E|
+ * is the number of edges, d is the average (total) degree of the
+ * graphs.
+ * 
+ * \example examples/simple/igraph_bipartite_projection.c
+ */
+
+int igraph_bipartite_projection(const igraph_t *graph, 
+				const igraph_vector_bool_t *types,
+				igraph_t *proj1,
+				igraph_t *proj2,
+				igraph_vector_t *multiplicity1,
+				igraph_vector_t *multiplicity2,
+				igraph_integer_t probe1) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+
+  /* t1 is -1 if proj1 is omitted, it is 0 if it belongs to type zero,
+     it is 1 if it belongs to type one. The same for t2 */
+  int t1, t2;
+  
+  if (igraph_vector_bool_size(types) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid bipartite type vector size", IGRAPH_EINVAL);
+  }
+  
+  if (probe1 >= no_of_nodes) {
+    IGRAPH_ERROR("No such vertex to probe", IGRAPH_EINVAL);
+  }
+  
+  if (probe1 >= 0 && !proj1) {
+    IGRAPH_ERROR("`probe1' given, but `proj1' is a null pointer", IGRAPH_EINVAL);
+  }
+  
+  if (probe1 >=0) {
+    t1=VECTOR(*types)[(long int)probe1];
+    if (proj2) {
+      t2=1-t1;
+    } else {
+      t2=-1;
+    }
+  } else {
+    t1 = proj1 ? 0 : -1;
+    t2 = proj2 ? 1 : -1;
+  }
+
+  IGRAPH_CHECK(igraph_i_bipartite_projection(graph, types, proj1, t1, multiplicity1));
+  IGRAPH_FINALLY(igraph_destroy, proj1);
+  IGRAPH_CHECK(igraph_i_bipartite_projection(graph, types, proj2, t2, multiplicity2));
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+  
+
+/** 
+ * \function igraph_full_bipartite
+ * Create a full bipartite network
+ * 
+ * A bipartite network contains two kinds of vertices and connections
+ * are only possible between two vertices of different kind. There are
+ * many natural examples, e.g. movies and actors as vertices and a
+ * movie is connected to all participating actors, etc.
+ * 
+ * </para><para>
+ * igraph does not have direct support for bipartite networks, at
+ * least not at the C language level. In other words the igraph_t
+ * structure does not contain information about the vertex types. 
+ * The C functions for bipartite networks usually have an additional
+ * input argument to graph, called \c types, a boolean vector giving
+ * the vertex types.
+ * 
+ * </para><para>
+ * Most functions creating bipartite networks are able to create this
+ * extra vector, you just need to supply an initialized boolean vector
+ * to them.
+ * 
+ * \param graph Pointer to an igraph_t object, the graph will be
+ *   created here.
+ * \param types Pointer to a boolean vector. If not a null pointer,
+ *   then the vertex types will be stored here.
+ * \param n1 Integer, the number of vertices of the first kind.
+ * \param n2 Integer, the number of vertices of the second kind.
+ * \param directed Boolean, whether to create a directed graph.
+ * \param mode A constant that gives the type of connections for
+ *   directed graphs. If \c IGRAPH_OUT, then edges point from vertices
+ *   of the first kind to vertices of the second kind; if \c
+ *   IGRAPH_IN, then the opposite direction is realized; if \c
+ *   IGRAPH_ALL, then mutual edges will be created.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ * 
+ * \sa \ref igraph_full() for non-bipartite full graphs.
+ */
+
+int igraph_full_bipartite(igraph_t *graph, 
+			  igraph_vector_bool_t *types,
+			  igraph_integer_t n1, igraph_integer_t n2,
+			  igraph_bool_t directed, 
+			  igraph_neimode_t mode) {
+  
+  igraph_integer_t nn1=n1, nn2=n2;
+  igraph_integer_t no_of_nodes=nn1+nn2;
+  igraph_vector_t edges;
+  long int no_of_edges;
+  long int ptr=0;
+  long int i, j;
+  
+  if (!directed) {
+    no_of_edges=nn1 * nn2;
+  } else if (mode==IGRAPH_OUT || mode==IGRAPH_IN) {
+    no_of_edges=nn1 * nn2;
+  } else { /* mode==IGRAPH_ALL */
+    no_of_edges=nn1 * nn2 * 2;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+
+  if (!directed || mode==IGRAPH_OUT) {
+
+    for (i=0; i<nn1; i++) {
+      for (j=0; j<nn2; j++) {
+	VECTOR(edges)[ptr++]=i;
+	VECTOR(edges)[ptr++]=nn1+j;
+      }
+    }
+    
+  } else if (mode==IGRAPH_IN) {
+
+    for (i=0; i<nn1; i++) {
+      for (j=0; j<nn2; j++) {
+	VECTOR(edges)[ptr++]=nn1+j;
+	VECTOR(edges)[ptr++]=i;
+      }
+    }
+    
+  } else {
+    
+    for (i=0; i<nn1; i++) {
+      for (j=0; j<nn2; j++) {
+	VECTOR(edges)[ptr++]=i;
+	VECTOR(edges)[ptr++]=nn1+j;
+	VECTOR(edges)[ptr++]=nn1+j;
+	VECTOR(edges)[ptr++]=i;
+      }
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, graph);
+
+  if (types) {
+    IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes));
+    igraph_vector_bool_null(types);
+    for (i=nn1; i<no_of_nodes; i++) {
+      VECTOR(*types)[i] = 1;
+    }
+  }
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_create_bipartite
+ * Create a bipartite graph
+ * 
+ * This is a simple wrapper function to create a bipartite graph. It
+ * does a little more than \ref igraph_create(), e.g. it checks that
+ * the graph is indeed bipartite with respect to the given \p types
+ * vector. If there is an edge connecting two vertices of the same
+ * kind, then an error is reported.
+ * \param graph Pointer to an uninitialized graph object, the result is
+ *   created here.
+ * \param types Boolean vector giving the vertex types. The length of
+ *   the vector defines the number of vertices in the graph.
+ * \param edges Vector giving the edges of the graph. The highest
+ *   vertex id in this vector must be smaller than the length of the
+ *   \p types vector.
+ * \param directed Boolean scalar, whether to create a directed
+ *   graph.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ * 
+ * \example examples/simple/igraph_bipartite_create.c
+ */
+ 
+int igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool_t *types,
+			    const igraph_vector_t *edges, 
+			    igraph_bool_t directed) {
+
+  igraph_integer_t no_of_nodes=
+    (igraph_integer_t) igraph_vector_bool_size(types);
+  long int no_of_edges=igraph_vector_size(edges);
+  igraph_real_t min_edge=0, max_edge=0;
+  igraph_bool_t min_type=0, max_type=0;
+  long int i;
+
+  if (no_of_edges % 2 != 0) {
+    IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVEVECTOR);
+  }
+  no_of_edges /= 2;
+  
+  if (no_of_edges != 0) {
+    igraph_vector_minmax(edges, &min_edge, &max_edge);
+  }
+  if (min_edge < 0 || max_edge >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid (negative) vertex id", IGRAPH_EINVVID);
+  }
+
+  /* Check types vector */
+  if (no_of_nodes != 0) {
+    igraph_vector_bool_minmax(types, &min_type, &max_type);
+    if (min_type < 0 || max_type > 1) {
+      IGRAPH_WARNING("Non-binary type vector when creating a bipartite graph");
+    }
+  }
+
+  /* Check bipartiteness */
+  for (i=0; i<no_of_edges*2; i+=2) {
+    long int from=(long int) VECTOR(*edges)[i];
+    long int to=(long int) VECTOR(*edges)[i+1];
+    long int t1=VECTOR(*types)[from];
+    long int t2=VECTOR(*types)[to];
+    if ( (t1 && t2) || (!t1 && !t2) ) {
+      IGRAPH_ERROR("Invalid edges, not a bipartite graph", IGRAPH_EINVAL);
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_empty(graph, no_of_nodes, directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  IGRAPH_CHECK(igraph_add_edges(graph, edges, 0));
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+  
+/**
+ * \function igraph_incidence
+ * Create a bipartite graph from an incidence matrix
+ *
+ * A bipartite (or two-mode) graph contains two types of vertices and
+ * edges always connect vertices of different types. An incidence
+ * matrix is an nxm matrix, n and m are the number of vertices of the
+ * two types, respectively. Nonzero elements in the matrix denote
+ * edges between the two corresponding vertices.
+ * 
+ * </para><para>
+ * Note that this function can operate in two modes, depending on the
+ * \p multiple argument. If it is FALSE (i.e. 0), then a single edge is
+ * created for every non-zero element in the incidence matrix. If \p
+ * multiple is TRUE (i.e. 1), 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.
+ * 
+ * </para><para>
+ * This function does not create multiple edges if \p multiple is
+ * FALSE, but might create some if it is TRUE.
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param types Pointer to an initialized boolean vector, or a null
+ *   pointer. If not a null pointer, then the vertex types are stored
+ *   here. It is resized as needed.
+ * \param incidence The incidence matrix.
+ * \param directed Gives whether to create an undirected or a directed
+ *   graph.
+ * \param mode Specifies the direction of the edges in a directed
+ *   graph. If \c IGRAPH_OUT, then edges point from vertices
+ *   of the first kind (corresponding to rows) to vertices of the 
+ *   second kind (corresponding to columns); if \c
+ *   IGRAPH_IN, then the opposite direction is realized; if \c
+ *   IGRAPH_ALL, then mutual edges will be created.
+ * \param multiple How to interpret the incidence matrix elements. See
+ *   details below.
+ * \return Error code.
+ * 
+ * Time complexity: O(n*m), the size of the incidence matrix.
+ */
+
+int igraph_incidence(igraph_t *graph, igraph_vector_bool_t *types,
+		     const igraph_matrix_t *incidence, 
+		     igraph_bool_t directed,
+		     igraph_neimode_t mode, igraph_bool_t multiple) {
+  
+  igraph_integer_t n1=(igraph_integer_t) igraph_matrix_nrow(incidence);
+  igraph_integer_t n2=(igraph_integer_t) igraph_matrix_ncol(incidence);
+  igraph_integer_t no_of_nodes=n1+n2;
+  igraph_vector_t edges;
+  long int i, j, k;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  if (multiple) { 
+
+    for (i=0; i<n1; i++) {
+      for (j=0; j<n2; j++) { 
+	long int elem=(long int) MATRIX(*incidence, i, j);
+	long int from, to;
+	
+	if (!elem) { continue; }
+	
+	if (mode == IGRAPH_IN) {
+	  from=n1+j;
+	  to=i;
+	} else {
+	  from=i;
+	  to=n1+j;
+	}
+	
+	if (mode != IGRAPH_ALL || !directed) {
+	  for (k=0; k<elem; k++) {
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+	  }
+	} else {
+	  for (k=0; k<elem; k++) {
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+	  }
+	}	  
+      }
+    }
+
+  } else {
+    
+    for (i=0; i<n1; i++) {
+      for (j=0; j<n2; j++) { 
+	long int from, to;
+	
+	if (MATRIX(*incidence, i, j) != 0) {
+	  if (mode == IGRAPH_IN) {
+	    from=n1+j;
+	    to=i;
+	  } else {
+	    from=i;
+	    to=n1+j;
+	  }
+	  if (mode != IGRAPH_ALL || !directed) {
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+	  } else {
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+	  }	    
+	}
+      }
+    }
+    
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed));
+  igraph_vector_destroy(&edges); 
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  
+  if (types) {
+    IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes));
+    igraph_vector_bool_null(types);
+    for (i=n1; i<no_of_nodes; i++) {
+      VECTOR(*types)[i] = 1;
+    }
+  }
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/** 
+ * \function igraph_get_incidence
+ * Convert a bipartite graph into an incidence matrix
+ * 
+ * \param graph The input graph, edge directions are ignored.
+ * \param types Boolean vector containing the vertex types.
+ * \param res Pointer to an initialized matrix, the result is stored
+ *   here. An element of the matrix gives the number of edges
+ *   (irrespectively of their direction) between the two corresponding
+ *   vertices. 
+ * \param row_ids Pointer to an initialized vector or a null
+ *   pointer. If not a null pointer, then the vertex ids (in the
+ *   graph) corresponding to the rows of the result matrix are stored
+ *   here.
+ * \param col_ids Pointer to an initialized vector or a null
+ *   pointer. If not a null pointer, then the vertex ids corresponding
+ *   to the columns of the result matrix are stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(n*m), n and m are number of vertices of the two
+ * different kind.
+ * 
+ * \sa \ref igraph_incidence() for the opposite operation.
+ */
+
+int igraph_get_incidence(const igraph_t *graph,
+			 const igraph_vector_bool_t *types,
+			 igraph_matrix_t *res,
+			 igraph_vector_t *row_ids,
+			 igraph_vector_t *col_ids) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int n1=0, n2=0, i;
+  igraph_vector_t perm;
+  long int p1, p2;
+
+  if (igraph_vector_bool_size(types) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid vertex type vector for bipartite graph", 
+		 IGRAPH_EINVAL);
+  }
+  
+  for (i=0; i<no_of_nodes; i++) {
+    n1 += VECTOR(*types)[i] == 0 ? 1 : 0;
+  }
+  n2 = no_of_nodes-n1;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&perm, no_of_nodes);
+  
+  for (i=0, p1=0, p2=n1; i<no_of_nodes; i++) {
+    VECTOR(perm)[i] = VECTOR(*types)[i] ? p2++ : p1++;
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, n1, n2));
+  igraph_matrix_null(res);
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+    long int to=IGRAPH_TO(graph, i);
+    long int from2=(long int) VECTOR(perm)[from];
+    long int to2=(long int) VECTOR(perm)[to];
+    if (! VECTOR(*types)[from]) {
+      MATRIX(*res, from2, to2-n1) += 1;
+    } else {
+      MATRIX(*res, to2, from2-n1) += 1;
+    }
+  }
+
+  if (row_ids) { 
+    IGRAPH_CHECK(igraph_vector_resize(row_ids, n1));
+  }
+  if (col_ids) {
+    IGRAPH_CHECK(igraph_vector_resize(col_ids, n2));
+  }
+  if (row_ids || col_ids) {
+    for (i=0; i<no_of_nodes; i++) {
+      if (! VECTOR(*types)[i]) {
+	if (row_ids) {
+	  long int i2=(long int) VECTOR(perm)[i];
+	  VECTOR(*row_ids)[i2] = i;
+	}
+      } else {
+	if (col_ids) {
+	  long int i2=(long int) VECTOR(perm)[i];
+	  VECTOR(*col_ids)[i2-n1] = i;
+	}
+      }
+    }
+  }
+
+  igraph_vector_destroy(&perm);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_is_bipartite
+ * Check whether a graph is bipartite
+ *
+ * </para><para>
+ * 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.
+ * 
+ * </para><para>
+ * 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.
+ * 
+ * </para><para>
+ * 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.
+ * 
+ * \param graph The input graph.
+ * \param res Pointer to a boolean, the result is stored here.
+ * \param type Pointer to an initialized boolean vector, or a null
+ *   pointer. If not a null pointer and a mapping was found, then it
+ *   is stored here. If not a null pointer, but no mapping was found,
+ *   the contents of this vector is invalid.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ */
+    
+int igraph_is_bipartite(const igraph_t *graph,
+			igraph_bool_t *res,
+			igraph_vector_bool_t *type) {
+  
+  /* We basically do a breadth first search and label the
+     vertices along the way. We stop as soon as we can find a
+     contradiction. 
+  
+     In the 'seen' vector 0 means 'not seen yet', 1 means type 1, 
+     2 means type 2.
+  */
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_char_t seen;
+  igraph_dqueue_t Q;
+  igraph_vector_t neis;
+  igraph_bool_t bi=1;
+  long int i;
+  
+  IGRAPH_CHECK(igraph_vector_char_init(&seen, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &seen);
+  IGRAPH_DQUEUE_INIT_FINALLY(&Q, 100);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  for (i=0; bi && i<no_of_nodes; i++) {
+    
+    if (VECTOR(seen)[i]) { continue; }
+    
+    IGRAPH_CHECK(igraph_dqueue_push(&Q, i));
+    VECTOR(seen)[i]=1;
+    
+    while (bi && !igraph_dqueue_empty(&Q)) {
+      long int n, j;
+      igraph_integer_t actnode=(igraph_integer_t) igraph_dqueue_pop(&Q);
+      char acttype=VECTOR(seen)[actnode];
+      
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, IGRAPH_ALL));
+      n=igraph_vector_size(&neis);
+      for (j=0; j<n; j++) {
+	long int nei=(long int) VECTOR(neis)[j];
+	if (VECTOR(seen)[nei]) {
+	  long int neitype=VECTOR(seen)[nei];
+	  if (neitype == acttype) { 
+	    bi=0; 
+	    break;
+	  }
+	} else {
+	  VECTOR(seen)[nei] = 3 - acttype;
+	  IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));
+	}
+      }
+    }
+  }
+
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (res) { *res=bi; }
+  
+  if (type && bi) { 
+    IGRAPH_CHECK(igraph_vector_bool_resize(type, no_of_nodes));
+    for (i=0; i<no_of_nodes; i++) {
+      VECTOR(*type)[i] = VECTOR(seen)[i] - 1;
+    }
+  }
+
+  igraph_vector_char_destroy(&seen);
+  IGRAPH_FINALLY_CLEAN(1);
+    
+  return 0;
+}
+
+int igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t *types,
+			      igraph_integer_t n1, igraph_integer_t n2, 
+			      igraph_real_t p, igraph_bool_t directed, 
+			      igraph_neimode_t mode) {
+
+  int retval=0;
+  igraph_vector_t edges, s;
+  int i;
+
+  if (p < 0.0 || p > 1.0) {
+    IGRAPH_ERROR("Invalid connection probability", IGRAPH_EINVAL);
+  }
+
+  if (types) {
+    IGRAPH_CHECK(igraph_vector_bool_resize(types, n1 + n2));
+    igraph_vector_bool_null(types);
+    for (i=n1; i<n1+n2; i++) {
+      VECTOR(*types)[i] = 1;
+    }
+  }
+
+  if (p == 0 || n1 * n2 < 1) {
+    IGRAPH_CHECK(retval=igraph_empty(graph, n1 + n2, directed));
+  } else if (p == 1.0) {
+    IGRAPH_CHECK(retval=igraph_full_bipartite(graph, types, n1, n2, directed,
+					      mode));
+  } else {
+
+    long int to, from, slen;
+    double maxedges, last;
+    if (!directed || mode != IGRAPH_ALL) {
+      maxedges = n1 * n2;
+    } else {
+      maxedges = 2 * n1 * n2;
+    }
+    
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&s, (long) (maxedges*p*1.1)));
+    
+    RNG_BEGIN();
+
+    last=RNG_GEOM(p);
+    while (last < maxedges) {
+      IGRAPH_CHECK(igraph_vector_push_back(&s, last));
+      last += RNG_GEOM(p);
+      last += 1;
+    }
+    
+    RNG_END();
+
+    slen=igraph_vector_size(&s);
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, slen * 2));
+
+    for (i=0; i<slen; i++) {
+      if (!directed || mode != IGRAPH_ALL) {
+	to=(long) floor(VECTOR(s)[i]/n1);
+	from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1);
+	to += n1;
+      } else {
+	long int n1n2 = n1 * n2;
+	if (VECTOR(s)[i] < n1n2) {
+	  to=(long) floor(VECTOR(s)[i]/n1);
+	  from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1);
+	  to += n1;
+	} else {
+	  to=(long) floor( (VECTOR(s)[i]-n1n2) /n2);
+	  from=(long) (VECTOR(s)[i] - n1n2 - ((igraph_real_t) to) * n2);
+	  from += n1;	  
+	}
+      }
+
+      if (mode != IGRAPH_IN) {
+	igraph_vector_push_back(&edges, from);
+	igraph_vector_push_back(&edges, to);
+      } else {
+	igraph_vector_push_back(&edges, to);
+	igraph_vector_push_back(&edges, from);	
+      }
+    }
+
+    igraph_vector_destroy(&s);
+    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_CHECK(retval=igraph_create(graph, &edges, n1+n2, directed));
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return retval;
+}
+
+int igraph_bipartite_game_gnm(igraph_t *graph, igraph_vector_bool_t *types,
+			      igraph_integer_t n1, igraph_integer_t n2, 
+			      igraph_integer_t m, igraph_bool_t directed, 
+			      igraph_neimode_t mode) {
+  igraph_vector_t edges;
+  igraph_vector_t s;
+  int retval=0;
+
+  if (n1 < 0 || n2 < 0) { 
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (m < 0) { 
+    IGRAPH_ERROR("Invalid number of edges", IGRAPH_EINVAL);
+  }
+
+  if (types) {
+    long int i;
+    IGRAPH_CHECK(igraph_vector_bool_resize(types, n1 + n2));
+    igraph_vector_bool_null(types);
+    for (i=n1; i<n1+n2; i++) {
+      VECTOR(*types)[i] = 1;
+    }
+  }
+  
+  if (m == 0 || n1 * n2 == 0) {
+    IGRAPH_CHECK(retval=igraph_empty(graph, n1 + n2, directed));
+  } else {
+    
+    long int i;
+    double maxedges;
+    if (!directed || mode != IGRAPH_ALL) {
+      maxedges = n1 * n2;
+    } else {
+      maxedges = 2 * n1 * n2;
+    }
+    
+    if (m > maxedges) {
+      IGRAPH_ERROR("Invalid number (too large) of edges", IGRAPH_EINVAL);
+    }
+    
+    if (maxedges == m) {
+      IGRAPH_CHECK(retval=igraph_full_bipartite(graph, types, n1, n2, 
+						directed, mode));
+    } else {
+
+      long int to, from;
+      IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+      IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+      IGRAPH_CHECK(igraph_random_sample(&s, 0, maxedges-1, m));
+      IGRAPH_CHECK(igraph_vector_reserve(&edges, igraph_vector_size(&s)*2));
+
+      for (i=0; i<m; i++) {
+	if (!directed || mode != IGRAPH_ALL) {
+	  to=(long) floor(VECTOR(s)[i]/n1);
+	  from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1);
+	  to += n1;
+	} else {
+	  long int n1n2 = n1 * n2;
+	  if (VECTOR(s)[i] < n1n2) {
+	    to=(long) floor(VECTOR(s)[i]/n1);
+	    from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1);
+	    to += n1;
+	  } else {
+	    to=(long) floor( (VECTOR(s)[i]-n1n2) /n2);
+	    from=(long) (VECTOR(s)[i] - n1n2 - ((igraph_real_t) to) * n2);
+	    from += n1;
+	  }
+	}
+
+	if (mode != IGRAPH_IN) {
+	  igraph_vector_push_back(&edges, from);
+	  igraph_vector_push_back(&edges, to);
+	} else {
+	  igraph_vector_push_back(&edges, to);
+	  igraph_vector_push_back(&edges, from);	
+	}
+      }
+
+      igraph_vector_destroy(&s);
+      IGRAPH_FINALLY_CLEAN(1);
+      IGRAPH_CHECK(retval=igraph_create(graph, &edges, n1+n2, directed));
+      igraph_vector_destroy(&edges);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }  
+
+  return retval;
+}
+
+/** 
+ * \function igraph_bipartite_game
+ * Generate a bipartite random graph (similar to Erdos-Renyi)
+ * 
+ * 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.
+ * \param graph Pointer to an uninitialized igraph graph, the result
+ *    is stored here. 
+ * \param types Pointer to an initialized boolean vector, or a null
+ *    pointer. If not a null pointer, then the vertex types are stored
+ *    here. Bottom vertices come first, n1 of them, then n2 top
+ *    vertices.
+ * \param type The type of the random graph, possible values:
+ *        \clist
+ *        \cli IGRAPH_ERDOS_RENYI_GNM
+ *          G(n,m) graph,  
+ *          m edges are
+ *          selected uniformly randomly in a graph with
+ *          n vertices.
+ *        \cli IGRAPH_ERDOS_RENYI_GNP
+ *          G(n,p) graph,
+ *          every possible edge is included in the graph with
+ *          probability p.
+ *        \endclist
+ * \param n1 The number of bottom vertices. 
+ * \param n2 The number of top verices.
+ * \param p The connection probability for G(n,p) graphs. It is
+ *     ignored for G(n,m) graphs.
+ * \param m The number of edges for G(n,m) graphs. It is ignored for
+ *     G(n,p) graphs.
+ * \param directed Boolean, whether to generate a directed graph. See
+ *     also the \p mode argument.
+ * \param mode Specifies how to direct the edges in directed
+ *     graphs. If it is \c IGRAPH_OUT, then directed edges point from
+ *     bottom vertices to top vertices. If it is \c IGRAPH_IN, edges
+ *     point from top vertices to bottom vertices. \c IGRAPH_OUT and
+ *     \c IGRAPH_IN do not generate mutual edges. If this argument is 
+ *     \c IGRAPH_ALL, then each edge direction is considered
+ *     independently and mutual edges might be generated. This
+ *     argument is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_erdos_renyi_game.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ */
+
+int igraph_bipartite_game(igraph_t *graph, igraph_vector_bool_t *types, 
+			  igraph_erdos_renyi_t type, 
+			  igraph_integer_t n1, igraph_integer_t n2, 
+			  igraph_real_t p, igraph_integer_t m, 
+			  igraph_bool_t directed, igraph_neimode_t mode) {
+  int retval=0;
+
+  if (n1 < 0 || n2 < 0) { 
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL); 
+  }
+
+  if (type == IGRAPH_ERDOS_RENYI_GNP) {
+    retval=igraph_bipartite_game_gnp(graph, types, n1, n2, p, directed, mode);
+  } else if (type == IGRAPH_ERDOS_RENYI_GNM) {
+    retval=igraph_bipartite_game_gnm(graph, types, n1, n2, m, directed, mode);
+  } else {
+    IGRAPH_ERROR("Invalid type", IGRAPH_EINVAL);
+  }
+  return retval;
+}
diff --git a/src/blas.c b/src/blas.c
new file mode 100644
index 0000000..041546e
--- /dev/null
+++ b/src/blas.c
@@ -0,0 +1,104 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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_blas.h"
+#include "igraph_blas_internal.h"
+
+#include <assert.h>
+
+/**
+ * \function igraph_blas_dgemv
+ * \brief Matrix-vector multiplication using BLAS, vector version.
+ *
+ * This function is a somewhat more user-friendly interface to
+ * the \c dgemv function in BLAS. \c dgemv performs the operation
+ * y = alpha*A*x + beta*y, where x and y are vectors and A is an
+ * appropriately sized matrix (symmetric or unsymmetric).
+ *
+ * \param transpose whether to transpose the matrix \p A
+ * \param alpha     the constant \p alpha
+ * \param a         the matrix \p A
+ * \param x         the vector \p x
+ * \param beta      the constant \p beta
+ * \param y         the vector \p y (which will be modified in-place)
+ *
+ * Time complexity: O(nk) if the matrix is of size n x k
+ *
+ * \sa \ref igraph_blas_dgemv_array if you have arrays instead of
+ *     vectors.
+ * 
+ * \example examples/simple/blas.c
+ */
+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) {
+  char trans = transpose ? 'T' : 'N';
+  int m, n;
+  int inc = 1;
+
+  m = (int) igraph_matrix_nrow(a);
+  n = (int) igraph_matrix_ncol(a);
+
+  assert(igraph_vector_size(x) == transpose ? m : n);
+  assert(igraph_vector_size(y) == transpose ? n : m);
+
+  igraphdgemv_(&trans, &m, &n, &alpha, VECTOR(a->data), &m,
+               VECTOR(*x), &inc, &beta, VECTOR(*y), &inc);
+}
+
+/**
+ * \function igraph_blas_dgemv_array
+ * \brief Matrix-vector multiplication using BLAS, array version.
+ *
+ * This function is a somewhat more user-friendly interface to
+ * the \c dgemv function in BLAS. \c dgemv performs the operation
+ * y = alpha*A*x + beta*y, where x and y are vectors and A is an
+ * appropriately sized matrix (symmetric or unsymmetric).
+ *
+ * \param transpose whether to transpose the matrix \p A
+ * \param alpha     the constant \p alpha
+ * \param a         the matrix \p A
+ * \param x         the vector \p x as a regular C array
+ * \param beta      the constant \p beta
+ * \param y         the vector \p y as a regular C array
+ *                  (which will be modified in-place)
+ *
+ * Time complexity: O(nk) if the matrix is of size n x k
+ *
+ * \sa \ref igraph_blas_dgemv if you have vectors instead of
+ *     arrays.
+ */
+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) {
+  char trans = transpose ? 'T' : 'N';
+  int m, n;
+  int inc = 1;
+
+  m = (int) igraph_matrix_nrow(a);
+  n = (int) igraph_matrix_ncol(a);
+
+  igraphdgemv_(&trans, &m, &n, &alpha, VECTOR(a->data), &m,
+               (igraph_real_t*)x, &inc, &beta, y, &inc);
+}
diff --git a/src/bliss.cc b/src/bliss.cc
new file mode 100644
index 0000000..6eb29cc
--- /dev/null
+++ b/src/bliss.cc
@@ -0,0 +1,317 @@
+/*
+ Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include "bliss_timer.hh"
+#include "bliss_graph.hh"
+#include "bliss_kqueue.hh"
+#include "bliss_utils.hh"
+
+#include "igraph_types.h"
+#include "igraph_topology.h"
+
+#include <string.h>
+
+using namespace igraph;
+using namespace std;
+
+/**
+ * \function igraph_canonical_permutation
+ * Canonical permutation using BLISS
+ * 
+ * This function computes the canonical permutation which transforms
+ * the graph into a canonical form by using the BLISS algorithm.
+ * 
+ * \param graph The input graph, it is treated as undirected and the
+ *    multiple edges are ignored.
+ * \param labeling Pointer to a vector, the result is stored here. The
+ *    permutation takes vertex 0 to the first element of the vector,
+ *    vertex 1 to the second, etc. The vector will be resized as
+ *    needed.
+ * \param sh The split heuristics to be used in BLISS. See \ref
+ *    igraph_bliss_sh_t.
+ * \param info If not \c NULL then information on BLISS internals is
+ *    stored here. See \ref igraph_bliss_info_t.
+ * \return Error code.
+ * 
+ * Time complexity: exponential, in practice it is fast for many graphs.
+ */
+int igraph_canonical_permutation(const igraph_t *graph, igraph_vector_t *labeling,
+				 igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
+  Graph *g = Graph::from_igraph(graph);
+  Stats stats;
+  const unsigned int N=g->get_nof_vertices();
+  unsigned int gsh=Graph::sh_flm;
+
+  switch (sh) { 
+  case IGRAPH_BLISS_F:    gsh= Graph::sh_f;   break;
+  case IGRAPH_BLISS_FL:   gsh= Graph::sh_fl;  break;
+  case IGRAPH_BLISS_FS:   gsh= Graph::sh_fs;  break;
+  case IGRAPH_BLISS_FM:   gsh= Graph::sh_fm;  break;
+  case IGRAPH_BLISS_FLM:  gsh= Graph::sh_flm; break;
+  case IGRAPH_BLISS_FSM:  gsh= Graph::sh_fsm; break;
+  }
+
+  g->set_splitting_heuristics(gsh);
+  const unsigned int *cl = g->canonical_form(stats);
+  IGRAPH_CHECK(igraph_vector_resize(labeling, N));
+  for (unsigned int i=0; i<N; i++) {
+    VECTOR(*labeling)[i] = cl[i];
+  }
+  delete g;
+
+  if (info) { 
+    info->nof_nodes      = stats.nof_nodes;
+    info->nof_leaf_nodes = stats.nof_leaf_nodes;
+    info->nof_bad_nodes  = stats.nof_bad_nodes;
+    info->nof_canupdates = stats.nof_canupdates;
+    info->max_level      = stats.max_level;
+    stats.group_size.tostring(&info->group_size);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_automorphisms
+ * Number of automorphisms using BLISS
+ * 
+ * The number of automorphisms of a graph is computed using BLISS. The
+ * result is returned as part of the \p info structure, in tag \c
+ * group_size. It is returned as a string, as it can be very high even
+ * for relatively small graphs. If the GNU MP library is used then
+ * this number is exact, otherwise a <type>long double</type> is used
+ * and it is only approximate. See also \ref igraph_bliss_info_t.
+ * 
+ * \param graph The input graph, it is treated as undirected and the
+ *    multiple edges are ignored.
+ * \param sh The split heuristics to be used in BLISS. See \ref
+ *    igraph_bliss_sh_t.
+ * \param info The result is stored here, in particular in the \c
+ *    group_size tag of \p info.
+ * \return Error code.
+ * 
+ * Time complexity: exponential, in practice it is fast for many graphs.
+ */
+int igraph_automorphisms(const igraph_t *graph,
+			 igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
+  
+  Graph *g = Graph::from_igraph(graph);
+  Stats stats;
+  unsigned int gsh=Graph::sh_flm;
+
+  switch (sh) { 
+  case IGRAPH_BLISS_F:    gsh= Graph::sh_f;   break;
+  case IGRAPH_BLISS_FL:   gsh= Graph::sh_fl;  break;
+  case IGRAPH_BLISS_FS:   gsh= Graph::sh_fs;  break;
+  case IGRAPH_BLISS_FM:   gsh= Graph::sh_fm;  break;
+  case IGRAPH_BLISS_FLM:  gsh= Graph::sh_flm; break;
+  case IGRAPH_BLISS_FSM:  gsh= Graph::sh_fsm; break;
+  }
+
+  g->set_splitting_heuristics(gsh);
+  g->find_automorphisms(stats);
+
+  if (info) { 
+    info->nof_nodes      = stats.nof_nodes;
+    info->nof_leaf_nodes = stats.nof_leaf_nodes;
+    info->nof_bad_nodes  = stats.nof_bad_nodes;
+    info->nof_canupdates = stats.nof_canupdates;
+    info->max_level      = stats.max_level;
+    stats.group_size.tostring(&info->group_size);
+  }
+  delete g;
+  
+  return 0;
+}
+
+bool bliss_verbose = false;
+// FILE *bliss_verbstr = stdout;
+
+namespace igraph {
+
+typedef enum {FORMAT_BIN = 0, FORMAT_ADJ} Format;
+// static Format input_format;
+
+// static char *infilename = 0;
+
+// static bool opt_canonize = false;
+// static char *opt_output_can_file = 0;
+// static unsigned int sh = Graph::sh_fm;
+
+// static void usage(FILE *fp, char *argv0)
+// {
+//   char *program_name;
+  
+//   program_name = strrchr(argv0, '/');
+  
+//   if(program_name) program_name++;
+//   else program_name = argv0;
+  
+//   if(!*program_name) program_name = "bliss";
+//   fprintf(fp, "bliss, version 0.35, compiled " __DATE__ "\n");
+//   fprintf(fp, "Copyright 2003-2006 Tommi Junttila\n");
+//   fprintf(fp,
+// "%s [<graph file>]\n"
+// "\n"
+// "  -can        compute canonical form\n"
+// "  -ocan=f     compute canonical form and output it in file f\n"
+// //"  -v        switch verbose mode on\n"
+// "  -sh=x       select splitting heuristics, where x is\n"
+// "                f    first non-singleton cell\n"
+// "                fl   first largest non-singleton cell\n"
+// "                fs   first smallest non-singleton cell\n"
+// "                fm   first maximally non-trivially connected non-singleton cell [default]\n"
+// "                flm  first largest maximally non-trivially connected non-singleton cell\n"
+// "                fsm  first smallest maximally non-trivially connected non-singleton cell\n"
+//           ,program_name);
+// }
+
+
+// static void parse_options(int argc, char ** argv)
+// {
+//   for(int i = 1; i < argc; i++)
+//     {
+//       //if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-verbose") == 0)
+//       //bliss_verbose = true;
+//       /*
+//       if(strcmp(argv[i], "-bin") == 0)
+// 	input_format = FORMAT_BIN;
+//       else if(strcmp(argv[i], "-adj") == 0)
+// 	input_format = FORMAT_ADJ;
+//       */
+//       if(strcmp(argv[i], "-can") == 0)
+// 	opt_canonize = true;
+//       else if((strncmp(argv[i], "-ocan=", 6) == 0) && (strlen(argv[i]) > 6))
+// 	{
+// 	  opt_canonize = true;
+// 	  opt_output_can_file = argv[i]+6;
+// 	}
+//       else if(strcmp(argv[i], "-sh=f") == 0)
+// 	sh = Graph::sh_f;
+//       else if(strcmp(argv[i], "-sh=fs") == 0)
+// 	sh = Graph::sh_fs;
+//       else if(strcmp(argv[i], "-sh=fl") == 0)
+// 	sh = Graph::sh_fl;
+//       else if(strcmp(argv[i], "-sh=fm") == 0)
+// 	sh = Graph::sh_fm;
+//       else if(strcmp(argv[i], "-sh=fsm") == 0)
+// 	sh = Graph::sh_fsm;
+//       else if(strcmp(argv[i], "-sh=flm") == 0)
+// 	sh = Graph::sh_flm;
+//       else if(argv[i][0] == '-') {
+// 	fprintf(stderr, "unknown command line argument `%s'\n", argv[i]);
+// 	usage(stderr, argv[0]);
+// 	exit(1);
+//       }
+//       else {
+// 	if(infilename) {
+// 	  fprintf(stderr, "too many file arguments\n");
+// 	  usage(stderr, argv[0]);
+// 	  exit(1);
+// 	}
+// 	else {
+// 	  infilename = argv[i];
+// 	}
+//       }
+//     }
+// }			    
+
+}
+
+// using namespace igraph;
+
+// int main(int argc, char **argv)
+// {
+//   Timer t;
+//   t.start();
+
+//   parse_options(argc, argv);
+
+//   Graph *g = 0;
+  
+//   FILE *infile = stdin;
+//   if(infilename) {
+//     if(input_format == FORMAT_BIN)
+//       infile = fopen(infilename, "rb");
+//     else
+//       infile = fopen(infilename, "r");
+//     if(!infile) {
+//       fprintf(stderr, "cannot not open `%s' for input\n", infilename);
+//       exit(1); }
+//   }
+
+//   g = Graph::read_dimacs(infile);
+
+//   if(infile != stdin)
+//     fclose(infile);
+
+//   if(!g)
+//     return 0;
+  
+//   fprintf(stdout, "Graph read in %.2fs\n", t.get_intermediate());
+  
+// #ifdef DEBUG_PRINT_DOT
+//   g->to_dot("debug_graph.dot");
+// #endif
+
+//   Stats stats;
+
+//   g->set_splitting_heuristics(sh);
+
+//   if(opt_canonize)
+//     {
+//       const unsigned int *cl = g->canonical_form(stats);
+//       //fprintf(stdout, "Canonical labeling: ");
+//       //print_permutation(stdout, g->get_nof_vertices(), cl);
+//       //fprintf(stdout, "\n");
+//       if(opt_output_can_file)
+// 	{
+// 	  Graph *cf = g->permute(cl);
+// 	  FILE *fp = fopen(opt_output_can_file, "w");
+// 	  if(!fp)
+// 	    {
+// 	      fprintf(stderr, "Can not open '%s' for outputting the canonical form", opt_output_can_file);
+// 	      exit(1);
+// 	    }
+// 	  cf->print_dimacs(fp);
+// 	  fclose(fp);
+// 	  delete cf;
+// 	}
+//     }
+//   else
+//     {
+//       g->find_automorphisms(stats);
+//     }
+
+//   printf("Nodes:\t\t%lu\n", stats.nof_nodes);
+//   printf("Leaf nodes:\t%lu\n", stats.nof_leaf_nodes);
+//   printf("Bad nodes:\t%lu\n", stats.nof_bad_nodes);
+//   printf("Canrep updates:\t%lu\n", stats.nof_canupdates);
+//   printf("Generators:\t%lu\n", stats.nof_generators);
+//   printf("Max level:\t%lu\n", stats.max_level);
+//   printf("|Aut|:\t\t"); stats.group_size.print(stdout); printf("\n");
+
+//   t.stop();
+//   printf("Total time:\t%.2fs\n", t.get_duration());
+
+//   delete g;
+
+//   return 0;
+// }
+
diff --git a/src/bliss_bignum.hh b/src/bliss_bignum.hh
new file mode 100644
index 0000000..ddc65c2
--- /dev/null
+++ b/src/bliss_bignum.hh
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_BIGNUM_HH
+#define BLISS_BIGNUM_HH
+
+#include <cstdlib>
+#include <cmath>
+#include <sstream>
+#include "bliss_defs.hh"
+#include "igraph_math.h"
+
+#include "igraph_memory.h"
+#include "igraph_error.h"
+
+/*
+ * Simple class for big integers (or approximation of such) in order
+ * compute group sizes.
+ * Set BLISS_USE_GMP in defs.hh to use the GMP library.
+ */
+
+
+#if defined(BLISS_USE_GMP)
+
+#include <gmp.h>
+
+namespace igraph {
+
+class BigNum
+{
+  mpz_t v;
+public:
+  BigNum() {mpz_init(v); }
+  ~BigNum() {mpz_clear(v); }
+  void assign(const int n) {mpz_set_si(v, n); }
+  void multiply(const int n) {mpz_mul_si(v, v, n); }
+  int tostring(char **str); 
+};
+
+}
+
+#else
+
+namespace igraph {
+
+class BigNum
+{
+  long double v;
+public:
+  BigNum(): v(0.0) {}
+  void assign(const int n) {v = (long double)n; }
+  void multiply(const int n) {v *= (long double)n; }
+  int tostring(char **str); 
+};
+
+}
+
+#endif
+
+#endif
diff --git a/src/bliss_defs.hh b/src/bliss_defs.hh
new file mode 100644
index 0000000..da10e9f
--- /dev/null
+++ b/src/bliss_defs.hh
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_DEFS_HH
+#define BLISS_DEFS_HH
+
+#include "config.h"
+#include <cassert>
+
+/* Define this if you have gmp and want to have exact group sizes.
+ * Remember to include -lgmp in LIB in Makefile. */
+#if HAVE_GMP == 1
+#  define BLISS_USE_GMP
+#endif
+
+#if defined(DEBUG)
+#define CONSISTENCY_CHECKS
+#define EXPENSIVE_CONSISTENCY_CHECKS
+#endif
+//#define PRINT_SEARCH_TREE_DOT
+
+/* Force a check that the found automorphisms are valid */
+#if defined(CONSISTENCY_CHECKS)
+#define VERIFY_AUTOMORPHISMS
+/* Force a check that the generated partitions are equitable */
+#define VERIFY_EQUITABLEDNESS
+#endif
+
+
+#if defined(CONSISTENCY_CHECKS)
+#define DEBUG_ASSERT(a) assert(a)
+#else
+#define DEBUG_ASSERT(a) ;
+#endif
+
+#endif
diff --git a/src/bliss_eqrefhash.cc b/src/bliss_eqrefhash.cc
new file mode 100644
index 0000000..cf3d557
--- /dev/null
+++ b/src/bliss_eqrefhash.cc
@@ -0,0 +1,143 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include "bliss_eqrefhash.hh"
+
+using namespace std;
+
+namespace igraph {
+
+/*
+ * Random bits generated by
+ * http://www.fourmilab.ch/hotbits/
+ */
+const static unsigned int rtab[256] = {
+  0xAEAA35B8, 0x65632E16, 0x155EDBA9, 0x01349B39,
+  0x8EB8BD97, 0x8E4C5367, 0x8EA78B35, 0x2B1B4072,
+  0xC1163893, 0x269A8642, 0xC79D7F6D, 0x6A32DEA0,
+  0xD4D2DA56, 0xD96D4F47, 0x47B5F48A, 0x2587C6BF,
+  0x642B71D8, 0x5DBBAF58, 0x5C178169, 0xA16D9279,
+  0x75CDA063, 0x291BC48B, 0x01AC2F47, 0x5416DF7C,
+  0x45307514, 0xB3E1317B, 0xE1C7A8DE, 0x3ACDAC96,
+  0x11B96831, 0x32DE22DD, 0x6A1DA93B, 0x58B62381,
+  0x283810E2, 0xBC30E6A6, 0x8EE51705, 0xB06E8DFB,
+  0x729AB12A, 0xA9634922, 0x1A6E8525, 0x49DD4E19,
+  0xE5DB3D44, 0x8C5B3A02, 0xEBDE2864, 0xA9146D9F,
+  0x736D2CB4, 0xF5229F42, 0x712BA846, 0x20631593,
+  0x89C02603, 0xD5A5BF6A, 0x823F4E18, 0x5BE5DEFF,
+  0x1C4EBBFA, 0x5FAB8490, 0x6E559B0C, 0x1FE528D6,
+  0xB3198066, 0x4A965EB5, 0xFE8BB3D5, 0x4D2F6234,
+  0x5F125AA4, 0xBCC640FA, 0x4F8BC191, 0xA447E537,
+  0xAC474D3C, 0x703BFA2C, 0x617DC0E7, 0xF26299D7,
+  0xC90FD835, 0x33B71C7B, 0x6D83E138, 0xCBB1BB14,
+  0x029CF5FF, 0x7CBD093D, 0x4C9825EF, 0x845C4D6D,
+  0x124349A5, 0x53942D21, 0x800E60DA, 0x2BA6EB7F,
+  0xCEBF30D3, 0xEB18D449, 0xE281F724, 0x58B1CB09,
+  0xD469A13D, 0x9C7495C3, 0xE53A7810, 0xA866C08E,
+  0x832A038B, 0xDDDCA484, 0xD5FE0DDE, 0x0756002B,
+  0x2FF51342, 0x60FEC9C8, 0x061A53E3, 0x47B1884E,
+  0xDC17E461, 0xA17A6A37, 0x3158E7E2, 0xA40D873B,
+  0x45AE2140, 0xC8F36149, 0x63A4EE2D, 0xD7107447,
+  0x6F90994F, 0x5006770F, 0xC1F3CA9A, 0x91B317B2,
+  0xF61B4406, 0xA8C9EE8F, 0xC6939B75, 0xB28BBC3B,
+  0x36BF4AEF, 0x3B12118D, 0x4D536ECF, 0x9CF4B46B,
+  0xE8AB1E03, 0x8225A360, 0x7AE4A130, 0xC4EE8B50,
+  0x50651797, 0x5BB4C59F, 0xD120EE47, 0x24F3A386,
+  0xBE579B45, 0x3A378EFC, 0xC5AB007B, 0x3668942B,
+  0x2DBDCC3A, 0x6F37F64C, 0xC24F862A, 0xB6F97FCF,
+  0x9E4FA23D, 0x551AE769, 0x46A8A5A6, 0xDC1BCFDD,
+  0x8F684CF9, 0x501D811B, 0x84279F80, 0x2614E0AC,
+  0x86445276, 0xAEA0CE71, 0x0812250F, 0xB586D18A,
+  0xC68D721B, 0x44514E1D, 0x37CDB99A, 0x24731F89,
+  0xFA72E589, 0x81E6EBA2, 0x15452965, 0x55523D9D,
+  0x2DC47E14, 0x2E7FA107, 0xA7790F23, 0x40EBFDBB,
+  0x77E7906B, 0x6C1DB960, 0x1A8B9898, 0x65FA0D90,
+  0xED28B4D8, 0x34C3ED75, 0x768FD2EC, 0xFAB60BCB,
+  0x962C75F4, 0x304F0498, 0x0A41A36B, 0xF7DE2A4A,
+  0xF4770FE2, 0x73C93BBB, 0xD21C82C5, 0x6C387447,
+  0x8CDB4CB9, 0x2CC243E8, 0x41859E3D, 0xB667B9CB,
+  0x89681E8A, 0x61A0526C, 0x883EDDDC, 0x539DE9A4,
+  0xC29E1DEC, 0x97C71EC5, 0x4A560A66, 0xBD7ECACF,
+  0x576AE998, 0x31CE5616, 0x97172A6C, 0x83D047C4,
+  0x274EA9A8, 0xEB31A9DA, 0x327209B5, 0x14D1F2CB,
+  0x00FE1D96, 0x817DBE08, 0xD3E55AED, 0xF2D30AFC,
+  0xFB072660, 0x866687D6, 0x92552EB9, 0xEA8219CD,
+  0xF7927269, 0xF1948483, 0x694C1DF5, 0xB7D8B7BF,
+  0xFFBC5D2F, 0x2E88B849, 0x883FD32B, 0xA0331192,
+  0x8CB244DF, 0x41FAF895, 0x16902220, 0x97FB512A,
+  0x2BEA3CC4, 0xAF9CAE61, 0x41ACD0D5, 0xFD2F28FF,
+  0xE780ADFA, 0xB3A3A76E, 0x7112AD87, 0x7C3D6058,
+  0x69E64FFF, 0xE5F8617C, 0x8580727C, 0x41F54F04,
+  0xD72BE498, 0x653D1795, 0x1275A327, 0x14B499D4,
+  0x4E34D553, 0x4687AA39, 0x68B64292, 0x5C18ABC3,
+  0x41EABFCC, 0x92A85616, 0x82684CF8, 0x5B9F8A4E,
+  0x35382FFE, 0xFB936318, 0x52C08E15, 0x80918B2E,
+  0x199EDEE0, 0xA9470163, 0xEC44ACDD, 0x612D6735,
+  0x8F88EA7D, 0x759F5EA4, 0xE5CC7240, 0x68CFEB8B,
+  0x04725601, 0x0C22C23E, 0x5BC97174, 0x89965841,
+  0x5D939479, 0x690F338A, 0x3C2D4380, 0xDAE97F2B
+};
+
+
+void BuzzHash::update(unsigned int i)
+{
+  i++;
+  while(i > 0) {
+    h ^= rtab[i & 0xff];
+    const unsigned int b = h & 0x80000000;
+    h = h << 1;
+    if(b != 0)
+      h++;
+    i = i >> 8;
+  }
+}
+
+int BuzzHash::cmp(const BuzzHash &other)
+{
+  if(h < other.h)
+    return -1;
+  if(h == other.h)
+    return 0;
+  return 1;
+}
+
+
+int PerfectHash::cmp(const PerfectHash &other)
+{
+  if(h.size() < other.h.size())
+    return -1;
+  if(h.size() > other.h.size())
+    return 1;
+  std::vector<unsigned int>::const_iterator i1 = h.begin();
+  std::vector<unsigned int>::const_iterator i2 = other.h.begin();
+  while(i1 != h.end())
+    {
+      const unsigned int v1 = *i1;
+      const unsigned int v2 = *i2;
+      if(v1 < v2)
+	return -1;
+      if(v1 > v2)
+	return 1;
+      i1++;
+      i2++;
+    }
+  return 0;
+}
+
+}
diff --git a/src/bliss_eqrefhash.hh b/src/bliss_eqrefhash.hh
new file mode 100644
index 0000000..1e215e8
--- /dev/null
+++ b/src/bliss_eqrefhash.hh
@@ -0,0 +1,58 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_EQREFHASH_HH
+#define BLISS_EQREFHASH_HH
+
+#include <vector>
+
+#define EqrefHash BuzzHash
+//#define EqrefHash PerfectHash
+
+namespace igraph {
+
+class BuzzHash
+{
+protected:
+  unsigned int h;
+public:
+  void reset() {h = 0; }
+  void update(unsigned int);
+  int cmp(const BuzzHash &other);
+  bool is_lt(const BuzzHash &other) {return(cmp(other) < 0); }
+  bool is_le(const BuzzHash &other) {return(cmp(other) <= 0); }
+  bool is_equal(const BuzzHash &other) {return(cmp(other) == 0); }
+};
+
+class PerfectHash
+{
+protected:
+  std::vector<unsigned int> h;
+public:
+  void reset() {h.clear(); }
+  void update(unsigned int i) {h.push_back(i); }
+  int cmp(const PerfectHash &other);
+  bool is_lt(const PerfectHash &other) {return(cmp(other) < 0); }
+  bool is_le(const PerfectHash &other) {return(cmp(other) <= 0); }
+  bool is_equal(const PerfectHash &other) {return(cmp(other) == 0); }
+};
+
+}
+
+#endif
diff --git a/src/bliss_graph.cc b/src/bliss_graph.cc
new file mode 100644
index 0000000..4a3c5fe
--- /dev/null
+++ b/src/bliss_graph.cc
@@ -0,0 +1,2495 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include <cstdio>
+#include <cassert>
+#include <cctype>
+#include <set>
+#include <list>
+#include <algorithm>
+#include "bliss_defs.hh"
+#include "bliss_timer.hh"
+#include "bliss_graph.hh"
+#include "bliss_partition.hh"
+#include <climits>		// INT_MAX, etc
+
+#include "igraph_datatype.h"
+#include "igraph_interface.h"
+#include "igraph_topology.h"
+#include "igraph_statusbar.h"
+
+using namespace std;
+
+extern bool bliss_verbose;
+// extern FILE *bliss_verbstr;
+
+namespace igraph {
+
+static const bool should_not_happen = false;
+
+/*-------------------------------------------------------------------------
+ *
+ * Constructor and destructor routines for the abstract graph class
+ *
+ *-------------------------------------------------------------------------*/
+
+
+AbstractGraph::AbstractGraph()
+{
+  /* Initialize stuff */
+  first_path_labeling = 0;
+  first_path_labeling_inv = 0;
+  best_path_labeling = 0;
+  best_path_labeling_inv = 0;
+  first_path_automorphism = 0;
+  best_path_automorphism = 0;
+  //certificate = 0;
+  in_search = false;
+}
+
+
+AbstractGraph::~AbstractGraph()
+{
+  if(first_path_labeling) {
+    free(first_path_labeling); first_path_labeling = 0; }
+  if(first_path_labeling_inv) {
+    free(first_path_labeling_inv); first_path_labeling_inv = 0; }
+  if(best_path_labeling) {
+    free(best_path_labeling); best_path_labeling = 0; }
+  if(best_path_labeling_inv) {
+    free(best_path_labeling_inv); best_path_labeling_inv = 0; }
+  if(first_path_automorphism) {
+    free(first_path_automorphism); first_path_automorphism = 0; }
+  if(best_path_automorphism) {
+    free(best_path_automorphism); best_path_automorphism = 0; }
+  //if(certificate) {
+  //  free(certificate); certificate = 0; }
+  while(!long_prune_fixed.empty())
+    {
+      delete long_prune_fixed.back();
+      long_prune_fixed.pop_back();
+    }
+  while(!long_prune_mcrs.empty())
+    {
+      delete long_prune_mcrs.back();
+      long_prune_mcrs.pop_back();
+    }
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Routines for refinement to equitable partition
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void AbstractGraph::refine_to_equitable()
+{
+  assert(p.splitting_queue.is_empty());
+
+  for(Cell *cell = p.first_cell; cell; cell = cell->next)
+    {
+      p.add_in_splitting_queue(cell);
+    }
+
+  return do_refine_to_equitable();
+}
+
+
+void AbstractGraph::refine_to_equitable(Cell *cell1)
+{
+  DEBUG_ASSERT(cell1->length == 1);
+
+#ifdef EXPENSIVE_CONSISTENCY_CHECKS
+  for(Cell *cell = p.first_cell; cell; cell = cell->next) {
+    assert(cell->in_splitting_queue == false);
+    assert(cell->in_neighbour_heap == false);
+  }
+#endif
+  
+  assert(p.splitting_queue.is_empty());
+
+  p.add_in_splitting_queue(cell1);
+
+  return do_refine_to_equitable();
+}
+
+
+void AbstractGraph::refine_to_equitable(Cell *cell1, Cell *cell2)
+{
+  DEBUG_ASSERT(cell1->length == 1);
+  DEBUG_ASSERT(cell2->length == 1);
+
+#ifdef EXPENSIVE_CONSISTENCY_CHECKS
+  for(Cell *cell = p.first_cell; cell; cell = cell->next) {
+    assert(cell->in_splitting_queue == false);
+    assert(cell->in_neighbour_heap == false);
+  }
+#endif
+  
+  assert(p.splitting_queue.is_empty());
+
+  p.add_in_splitting_queue(cell1);
+  p.add_in_splitting_queue(cell2);
+
+  return do_refine_to_equitable();
+}
+
+
+void AbstractGraph::do_refine_to_equitable()
+{
+  assert(!p.splitting_queue.is_empty());
+  assert(neighbour_heap.is_empty());
+
+  eqref_hash.reset();
+
+  while(!p.splitting_queue.is_empty())
+    {
+      Cell *cell = p.splitting_queue.pop_front();
+      DEBUG_ASSERT(cell->in_splitting_queue);
+      cell->in_splitting_queue = false;
+
+      if(cell->length == 1)
+	{
+	  if(in_search) {
+	    if(first_path_automorphism) {
+	      /* Build the (potential) automorphism on-the-fly */
+	      assert(first_path_labeling_inv);
+	      first_path_automorphism[first_path_labeling_inv[cell->first]] =
+		p.elements[cell->first];
+	    }
+	    if(best_path_automorphism)
+	      {
+		/* Build the (potential) automorphism on-the-fly */
+		assert(best_path_labeling_inv);
+		best_path_automorphism[best_path_labeling_inv[cell->first]] =
+		  p.elements[cell->first];
+	      }
+	  }
+	  
+	  bool worse = split_neighbourhood_of_unit_cell(cell);
+	  if(in_search && worse)
+	    goto worse_exit;
+	}
+      else
+	{
+	  split_neighbourhood_of_cell(cell);
+	}
+    }
+
+  eqref_worse_than_certificate = false;
+  return;
+
+ worse_exit:
+  /* Clear splitting_queue */
+  p.clear_splitting_queue();
+  eqref_worse_than_certificate = true;
+  return;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Routines for handling the canonical labeling
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void AbstractGraph::update_labeling(unsigned int * const labeling)
+{
+  const unsigned int N = get_nof_vertices();
+  unsigned int *ep = p.elements;
+  for(unsigned int i = 0; i < N; i++, ep++)
+    labeling[*ep] = i;
+}
+
+
+void AbstractGraph::update_labeling_and_its_inverse(unsigned int * const labeling,
+						    unsigned int * const labeling_inv)
+{
+  const unsigned int N = get_nof_vertices();
+  unsigned int *ep = p.elements;
+  unsigned int *clip = labeling_inv;
+
+  for(unsigned int i = 0; i < N; ) {
+    labeling[*ep] = i;
+    i++;
+    *clip = *ep;
+    ep++;
+    clip++;
+  }
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Routines for handling automorphisms
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void AbstractGraph::reset_permutation(unsigned int *perm)
+{
+  const unsigned int N = get_nof_vertices();
+  for(unsigned int i = 0; i < N; i++, perm++)
+    *perm = i;
+}
+
+
+bool AbstractGraph::is_automorphism(unsigned int * const perm)
+{
+  IGRAPH_UNUSED(perm);
+  assert(should_not_happen);
+  return false;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Long prune code
+ *
+ *-------------------------------------------------------------------------*/
+
+void AbstractGraph::long_prune_init()
+{
+  const unsigned int N = get_nof_vertices();
+  long_prune_temp.clear();
+  long_prune_temp.resize(N);
+#ifdef DEBUG
+  for(unsigned int i = 0; i < N; i++)
+    assert(long_prune_temp[i] == false);
+#endif
+  const unsigned int nof_fitting_in_max_mem =
+    (long_prune_options_max_mem * 1024 * 1024) / (((N * 2) / 8)+1);
+  long_prune_max_stored_autss = long_prune_options_max_stored_auts;
+  /* Had some problems with g++ in using (a<b)?a:b when constants involved,
+     so had to make this in a stupid way...*/
+  if(nof_fitting_in_max_mem < long_prune_options_max_stored_auts)
+    long_prune_max_stored_autss = nof_fitting_in_max_mem;
+
+  while(!long_prune_fixed.empty())
+    {
+      delete long_prune_fixed.back();
+      long_prune_fixed.pop_back();
+    }
+  while(!long_prune_mcrs.empty())
+    {
+      delete long_prune_mcrs.back();
+      long_prune_mcrs.pop_back();
+    }
+  for(unsigned int i = 0; i < long_prune_max_stored_autss; i++)
+    {
+      long_prune_fixed.push_back(new std::vector<bool>(N));
+      long_prune_mcrs.push_back(new std::vector<bool>(N));
+    }
+  long_prune_begin = 0;
+  long_prune_end = 0;
+}
+
+void AbstractGraph::long_prune_swap(const unsigned int i, const unsigned int j)
+{
+  assert(long_prune_begin <= long_prune_end);
+  assert(i >= long_prune_begin);
+  assert(i < long_prune_end);
+  assert(j >= long_prune_begin);
+  assert(j < long_prune_end);
+  const unsigned int real_i = i % long_prune_max_stored_autss;
+  const unsigned int real_j = j % long_prune_max_stored_autss;
+  std::vector<bool> * tmp = long_prune_fixed[real_i];
+  long_prune_fixed[real_i] = long_prune_fixed[real_j];
+  long_prune_fixed[real_j] = tmp;
+  tmp = long_prune_mcrs[real_i];
+  long_prune_mcrs[real_i] = long_prune_mcrs[real_j];
+  long_prune_mcrs[real_j] = tmp;
+}
+
+std::vector<bool> &AbstractGraph::long_prune_get_fixed(const unsigned int index)
+{
+  assert(long_prune_begin <= long_prune_end);
+  assert(index >= long_prune_begin);
+  assert(index < long_prune_end);
+  return *long_prune_fixed[index % long_prune_max_stored_autss];
+}
+
+std::vector<bool> &AbstractGraph::long_prune_get_mcrs(const unsigned int index)
+{
+  assert(long_prune_begin <= long_prune_end);
+  assert(index >= long_prune_begin);
+  assert(index < long_prune_end);
+  return *long_prune_mcrs[index % long_prune_max_stored_autss];
+}
+
+
+void AbstractGraph::long_prune_add_automorphism(const unsigned int *aut)
+{
+  if(long_prune_max_stored_autss == 0)
+    return;
+
+  const unsigned int N = get_nof_vertices();
+
+#ifdef DEBUG
+  assert(long_prune_temp.size() == N);
+  for(unsigned int i = 0; i < N; i++)
+    assert(long_prune_temp[i] == false);
+#endif
+
+  DEBUG_ASSERT(long_prune_fixed.size() == long_prune_mcrs.size());
+  assert(long_prune_begin <= long_prune_end);
+  if(long_prune_end - long_prune_begin == long_prune_max_stored_autss)
+    {
+      long_prune_begin++;
+    }
+  long_prune_end++;
+  std::vector<bool> &fixed = long_prune_get_fixed(long_prune_end-1);
+  std::vector<bool> &mcrs = long_prune_get_mcrs(long_prune_end-1);
+
+  for(unsigned int i = 0; i < N; i++)
+    {
+      fixed[i] = (aut[i] == i);
+      if(!long_prune_temp[i])
+	{
+	  mcrs[i] = true;
+	  unsigned int j = aut[i];
+	  while(j != i)
+	    {
+	      assert(i <= j);
+	      long_prune_temp[j] = true;
+	      j = aut[j];
+	    }
+	}
+      else
+	{
+	  mcrs[i] = false;
+	}
+      long_prune_temp[i] = false;
+    }
+
+
+#ifdef DEBUG
+  for(unsigned int i = 0; i < N; i++)
+    assert(long_prune_temp[i] == false);
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Routines for handling orbit information
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void AbstractGraph::update_orbit_information(Orbit &o, const unsigned int *p)
+{
+  const unsigned int N = get_nof_vertices();
+  for(unsigned int i = 0; i < N; i++)
+    if(p[i] != i)
+      o.merge_orbits(i, p[i]);
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Print a permutation in cycle notation
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void AbstractGraph::print_permutation(FILE *fp, const unsigned int *perm)
+{
+  const unsigned int N = get_nof_vertices();
+  for(unsigned int i = 0; i < N; i++) {
+    unsigned int j = perm[i];
+    if(j == i)
+      continue;
+    bool is_first = true;
+    while(j != i) {
+      if(j < i) {
+	is_first = false;
+	break;
+      }
+      j = perm[j];
+    }
+    if(!is_first)
+      continue;
+    fprintf(fp, "(%u,", i);
+    j = perm[i];
+    while(j != i) {
+      fprintf(fp, "%u", j);
+      j = perm[j];
+      if(j != i)
+	fprintf(fp, ",");
+    }
+    fprintf(fp, ")");
+  }
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * The actual backtracking search
+ *
+ *-------------------------------------------------------------------------*/
+
+
+typedef struct {
+  int split_element;
+  unsigned int split_cell_first;
+  unsigned int refinement_stack_size;
+  unsigned int certificate_index;
+
+  bool in_first_path;
+  bool in_best_path;
+  bool equal_to_first_path;
+  int cmp_to_best_path;
+
+  bool needs_long_prune;
+  unsigned int long_prune_begin;
+  std::set<unsigned int, std::less<unsigned int> > long_prune_redundant;
+  
+  EqrefHash eqref_hash;
+  unsigned int subcertificate_length;
+} LevelInfo;
+
+
+
+typedef struct t_path_info {
+  unsigned int splitting_element;
+  unsigned int certificate_index;
+  unsigned int subcertificate_length;
+  EqrefHash eqref_hash;
+} PathInfo;
+
+
+void AbstractGraph::search(const bool canonical, Stats &stats)
+{
+  const unsigned int N = get_nof_vertices();
+
+  // const bool write_automorphisms = 0;
+
+  unsigned int all_same_level = UINT_MAX;
+
+  p.graph = this;
+
+  /*
+   * Must be done!
+   */
+  remove_duplicate_edges();
+
+  /*
+   * Reset search statistics
+   */
+  stats.group_size.assign(1);
+  stats.nof_nodes = 1;
+  stats.nof_leaf_nodes = 1;
+  stats.nof_bad_nodes = 0;
+  stats.nof_canupdates = 0;
+  stats.nof_generators = 0;
+  stats.max_level = 0;
+
+  if(first_path_labeling)
+    {
+      free(first_path_labeling);
+      first_path_labeling = 0;
+    }
+  if(first_path_labeling_inv)
+    {
+      free(first_path_labeling_inv);
+      first_path_labeling_inv = 0;
+   }
+  if(first_path_automorphism)
+    {
+      free(first_path_automorphism);
+      first_path_automorphism = 0;
+   }
+
+  if(best_path_labeling)
+    {
+      free(best_path_labeling);
+      best_path_labeling = 0;
+    }
+  if(best_path_labeling_inv)
+    {
+      free(best_path_labeling_inv);
+      best_path_labeling_inv = 0;
+   }
+  if(best_path_automorphism)
+    {
+      free(best_path_automorphism);
+      best_path_automorphism = 0;
+   }
+
+  if(N == 0)
+    return;
+
+  p.init(N);
+  neighbour_heap.init(N);
+
+  in_search = false;
+
+  p.level = 0;
+
+  Timer t1;
+  t1.start();
+
+  make_initial_equitable_partition();
+
+#if defined(VERIFY_EQUITABLEDNESS)
+  assert(is_equitable());
+#endif
+
+  t1.stop();
+  
+  igraph_statusf("Initial partition computed in %.2fs", 0,
+		 t1.get_duration());
+  
+  /*
+   * Allocate space for the labelings
+   */
+  if(first_path_labeling)
+    free(first_path_labeling);
+  first_path_labeling = (unsigned int*)calloc(N, sizeof(unsigned int));
+  if(best_path_labeling)
+    free(best_path_labeling);
+  best_path_labeling = (unsigned int*)calloc(N, sizeof(unsigned int));
+
+  /*
+   * Are there any non-singleton cells?
+   */
+  if(p.is_discrete())
+    {
+      update_labeling(best_path_labeling);
+      return;
+    }
+
+  //p.print_signature(stderr); fprintf(stderr, "\n");
+
+  /*
+   * Allocate space for the inverses of the labelings
+   */
+  if(first_path_labeling_inv)
+    free(first_path_labeling_inv);
+  first_path_labeling_inv = (unsigned int*)calloc(N, sizeof(unsigned int));
+  if(best_path_labeling_inv)
+    free(best_path_labeling_inv);
+  best_path_labeling_inv = (unsigned int*)calloc(N, sizeof(unsigned int));
+
+
+  /*
+   * Allocate space for the automorphisms
+   */
+  if(first_path_automorphism) free(first_path_automorphism);
+  first_path_automorphism = (unsigned int*)malloc(N * sizeof(unsigned int));
+  if(best_path_automorphism) free(best_path_automorphism);
+  best_path_automorphism = (unsigned int*)malloc(N * sizeof(unsigned int));
+
+
+  /*
+   * Initialize orbit information
+   */
+  first_path_orbits.init(N);
+  best_path_orbits.init(N);
+
+  /*
+   * Initialize certificate memory
+   */
+  initialize_certificate();
+  //assert(certificate);
+  assert(certificate_index == 0);
+
+  LevelInfo info;
+  std::vector<LevelInfo> search_stack;
+  std::vector<PathInfo> first_path_info;
+  std::vector<PathInfo> best_path_info;
+
+  search_stack.clear();
+  p.refinement_stack.clean();
+  assert(neighbour_heap.is_empty());
+
+  /*
+   * Initialize long prune
+   */
+  long_prune_init();
+
+  /*
+   * Build the first level info
+   */
+  info.split_cell_first = find_next_cell_to_be_splitted(p.first_cell)->first;
+  info.split_element = -1;
+  info.refinement_stack_size = p.refinement_stack.size();
+  info.certificate_index = 0;
+  info.in_first_path = false;
+  info.in_best_path = false;
+  info.long_prune_begin = 0;
+  search_stack.push_back(info);
+
+  /*
+   * Set status and global flags for search related procedures
+   */
+  in_search = true;
+  refine_compare_certificate = false;
+  stats.nof_leaf_nodes = 0;
+
+
+#ifdef PRINT_SEARCH_TREE_DOT
+  dotty_output = fopen("debug_stree.dot", "w");
+  fprintf(dotty_output, "digraph stree {\n");
+  fprintf(dotty_output, "\"n\" [label=\"");
+  fprintf(dotty_output, "M"); //p.print(dotty_output);
+  fprintf(dotty_output, "\"];\n");
+#endif
+
+  p.consistency_check();
+
+  /*
+   * The actual backtracking search
+   */
+  while(!search_stack.empty()) 
+    {
+      info = search_stack.back();
+      search_stack.pop_back();
+
+      p.consistency_check();
+
+      /*
+       * Restore partition, certificate index, and split cell
+       */
+      p.unrefine(p.level, info.refinement_stack_size);
+      assert(info.certificate_index <= certificate_size);
+      certificate_index = info.certificate_index;
+      certificate_current_path.resize(certificate_index);
+      Cell * const cell = p.element_to_cell_map[p.elements[info.split_cell_first]];
+      assert(cell->length > 1);
+
+      p.consistency_check();
+
+      if(p.level > 0 && !info.in_first_path)
+	{
+	  if(info.split_element == -1)
+	    {
+	      info.needs_long_prune = true;
+	    }
+	  else if(info.needs_long_prune)
+	    {
+	      info.needs_long_prune = false;
+	      /* THIS IS A QUITE HORRIBLE HACK! */
+	      unsigned int begin = (info.long_prune_begin>long_prune_begin)?info.long_prune_begin:long_prune_begin;
+	      for(unsigned int i = begin; i < long_prune_end; i++)
+		{
+		  const std::vector<bool> &fixed = long_prune_get_fixed(i);
+		  bool fixes_all = true;
+		  for(unsigned int l = 0; l < p.level; l++)
+		    {
+		      if(fixed[search_stack[l].split_element] == false)
+			{
+			  fixes_all = false;
+			  break;
+			}
+		    }
+		  if(!fixes_all)
+		    {
+		      long_prune_swap(begin, i);
+		      begin++;
+		      info.long_prune_begin = begin;
+		      continue;
+		    }
+		  const std::vector<bool> &mcrs = long_prune_get_mcrs(i);
+		  unsigned int *ep = p.elements + cell->first;
+		  for(unsigned int j = cell->length; j > 0; j--, ep++) {
+		    if(mcrs[*ep] == false)
+		      {
+			info.long_prune_redundant.insert(*ep);
+		      }
+		  }
+		}
+	    }
+	}
+
+      /*
+       * Find the next smallest element in cell
+       */
+      unsigned int next_split_element = UINT_MAX;
+      unsigned int *next_split_element_pos = 0;
+      unsigned int *ep = p.elements + cell->first;
+      if(info.in_first_path)
+	{
+	  /* Find the next larger splitting element that is a mor */
+	  for(unsigned int i = cell->length; i > 0; i--, ep++) {
+	    if((int)(*ep) > info.split_element &&
+	       *ep < next_split_element &&
+	       first_path_orbits.is_minimal_representative(*ep)) {
+	      next_split_element = *ep;
+	      next_split_element_pos = ep;
+	    }
+	  }
+	}
+      else if(info.in_best_path)
+	{
+	  /* Find the next larger splitting element that is a mor */
+	  for(unsigned int i = cell->length; i > 0; i--, ep++) {
+	    if((int)(*ep) > info.split_element &&
+	       *ep < next_split_element &&
+	       best_path_orbits.is_minimal_representative(*ep) &&
+	       (info.long_prune_redundant.find(*ep) ==
+		info.long_prune_redundant.end())) {
+	      next_split_element = *ep;
+	      next_split_element_pos = ep;
+	    }
+	  }
+	}
+      else
+	{
+	  /* Find the next larger splitting element */
+	  for(unsigned int i = cell->length; i > 0; i--, ep++) {
+	    if((int)(*ep) > info.split_element &&
+	       *ep < next_split_element &&
+	       (info.long_prune_redundant.find(*ep) ==
+		info.long_prune_redundant.end())) {
+	      next_split_element = *ep;
+	      next_split_element_pos = ep;
+	    }
+	  }
+	}
+      if(next_split_element == UINT_MAX)
+	{
+	  /*
+	   * No more splitting elements (unexplored children) in the cell
+	   */
+	  /* Update group size if required */
+	  if(info.in_first_path == true) {
+	    const unsigned int index =
+	      first_path_orbits.orbit_size(first_path_info[p.level].splitting_element);
+	    stats.group_size.multiply(index);
+	    /*
+	     * Update all_same_level
+	     */
+	    if(index == cell->length && all_same_level == p.level+1)
+	      all_same_level = p.level;
+	    igraph_statusf("Level %u: orbits=%u, index=%u/%u, "
+			   "all_same_level=%u", 0, 
+			   p.level,
+			   first_path_orbits.nof_orbits(),
+			   index, cell->length,
+			   all_same_level);
+	  }
+	  /* Backtrack to the previous level */
+	  p.level--;
+	  continue;
+	}
+
+      /* Split on smallest */
+      info.split_element = next_split_element;
+      
+      /*
+       * Save the current search situation
+       */
+      search_stack.push_back(info);
+
+      /*
+       * No more in the first path
+       */
+      info.in_first_path = false;
+      /*
+       * No more in the best path
+       */
+      info.in_best_path = false;
+
+      p.level++;
+      stats.nof_nodes++;
+      if(p.level > stats.max_level)
+	stats.max_level = p.level;
+
+      p.consistency_check();
+
+      /*
+       * Move the split element to be the last in the cell
+       */
+      *next_split_element_pos = p.elements[cell->first + cell->length - 1];
+      p.in_pos[*next_split_element_pos] = next_split_element_pos;
+      p.elements[cell->first + cell->length - 1] = next_split_element;
+      p.in_pos[next_split_element] = p.elements+ cell->first + cell->length -1;
+      /*
+       * Split the cell in two:
+       * the last element in the cell (split element) forms a singleton cell
+       */
+      Cell * const new_cell = p.aux_split_in_two(cell, cell->length - 1);
+      p.element_to_cell_map[p.elements[new_cell->first]] = new_cell;
+      p.consistency_check();
+
+      /*      
+      const bool prev_equal_to_first_path = info.equal_to_first_path;
+      const int prev_cmp_to_best_path = info.cmp_to_best_path;
+      */
+      //assert(!(!info.equal_to_first_path && info.cmp_to_best_path < 0));
+
+      if(!first_path_info.empty())
+	{
+	  refine_equal_to_first = info.equal_to_first_path;
+	  if(refine_equal_to_first)
+	    refine_first_path_subcertificate_end =
+	      first_path_info[p.level-1].certificate_index +
+	      first_path_info[p.level-1].subcertificate_length;
+	  if(canonical)
+	    {
+	      refine_cmp_to_best = info.cmp_to_best_path;
+	      if(refine_cmp_to_best == 0)
+		refine_best_path_subcertificate_end =
+		  best_path_info[p.level-1].certificate_index +
+		  best_path_info[p.level-1].subcertificate_length;
+	    }
+	  else
+	    refine_cmp_to_best = -1;
+	}
+      /*
+       * Refine the new partition to equitable
+       */
+      if(cell->length == 1)
+	refine_to_equitable(cell, new_cell);
+      else 
+	refine_to_equitable(new_cell);
+
+      p.consistency_check();
+
+
+#ifdef PRINT_SEARCH_TREE_DOT
+      fprintf(dotty_output, "\"n");
+      for(unsigned int i = 0; i < search_stack.size(); i++) {
+	fprintf(dotty_output, "%u", search_stack[i].split_element);
+	if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
+      }
+      fprintf(dotty_output, "\"");
+      fprintf(dotty_output, " [label=\"");
+      fprintf(dotty_output, "%u",cell->first); /*p.print(dotty_output);*/
+      fprintf(dotty_output, "\"]");
+      if(!first_path_info.empty() && canonical && refine_cmp_to_best > 0) {
+	fprintf(dotty_output, "[color=green]");
+      }
+      fprintf(dotty_output, ";\n");
+      
+      fprintf(dotty_output, "\"n");
+      for(unsigned int i = 0; i < search_stack.size() - 1; i++) {
+	fprintf(dotty_output, "%u", search_stack[i].split_element);
+	if(i < search_stack.size() - 2) fprintf(dotty_output, ".");
+      }
+      fprintf(dotty_output, "\" -> \"n");
+      for(unsigned int i = 0; i < search_stack.size(); i++) {
+	fprintf(dotty_output, "%u", search_stack[i].split_element);
+	if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
+      }
+      fprintf(dotty_output, "\" [label=\"%d\"];\n", next_split_element);
+#endif
+
+      /*
+      if(prev_cmp_to_best_path == 0 && refine_cmp_to_best < 0)
+	fprintf(stderr, "BP- ");
+      if(prev_cmp_to_best_path == 0 && refine_cmp_to_best > 0)
+	fprintf(stderr, "BP+ ");
+      */
+
+      if(p.is_discrete())
+	{
+	  /* Update statistics */
+	  stats.nof_leaf_nodes++;
+	  /*
+	    if(stats.nof_leaf_nodes % 100 == 0) {
+	    fprintf(stdout, "Nodes: %lu, Leafs: %lu, Bad: %lu\n",
+	    stats.nof_nodes, stats.nof_leaf_nodes,
+	    stats.nof_bad_nodes);
+	    fflush(stdout);
+	    }
+	  */
+	}
+
+      if(!first_path_info.empty())
+	{
+	  /* We are no longer on the first path */
+	  assert(best_path_info.size() > 0);
+	  assert(certificate_current_path.size() >= certificate_index);
+	  const unsigned int subcertificate_length = 
+	    certificate_current_path.size() - certificate_index;
+	  if(refine_equal_to_first)
+	    {
+	      /* Was equal to the first path so far */
+	      assert(first_path_info.size() >= p.level);
+	      PathInfo &first_pinfo = first_path_info[p.level-1];
+	      assert(first_pinfo.certificate_index == certificate_index);
+	      if(subcertificate_length != first_pinfo.subcertificate_length)
+		{
+		  refine_equal_to_first = false;
+		}
+	      else if(first_pinfo.eqref_hash.cmp(eqref_hash) != 0)
+		{
+		  refine_equal_to_first = false;
+		}
+	    }
+	  if(canonical && (refine_cmp_to_best == 0))
+	    {
+	      /* Was equal to the best path so far */
+	      assert(best_path_info.size() >= p.level);
+	      PathInfo &best_pinfo = best_path_info[p.level-1];
+	      assert(best_pinfo.certificate_index == certificate_index);
+	      if(subcertificate_length < best_pinfo.subcertificate_length)
+		{
+		  refine_cmp_to_best = -1;
+		  //fprintf(stderr, "BSCL- ");
+		}
+	      else if(subcertificate_length > best_pinfo.subcertificate_length)
+		{
+		  refine_cmp_to_best = 1;
+		  //fprintf(stderr, "BSCL+ ");
+		}
+	      else if(best_pinfo.eqref_hash.cmp(eqref_hash) > 0)
+		{
+		  refine_cmp_to_best = -1;
+		  //fprintf(stderr, "BHL- ");
+		}
+	      else if(best_pinfo.eqref_hash.cmp(eqref_hash) < 0)
+		{
+		  refine_cmp_to_best = 1;
+		  //fprintf(stderr, "BHL+ ");
+		}
+	    }
+	  if(refine_equal_to_first == false &&
+	     (!canonical || (refine_cmp_to_best < 0)))
+	    {
+	      /* Backtrack */
+#ifdef PRINT_SEARCH_TREE_DOT
+	      fprintf(dotty_output, "\"n");
+	      for(unsigned int i = 0; i < search_stack.size(); i++) {
+		fprintf(dotty_output, "%u", search_stack[i].split_element);
+		if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
+	      }
+	      fprintf(dotty_output, "\" [color=red];\n");
+#endif
+	      stats.nof_bad_nodes++;
+	      if(search_stack.back().equal_to_first_path == true &&
+		 p.level > all_same_level)
+		{
+		  assert(all_same_level >= 1);
+		  for(unsigned int i = all_same_level;
+		      i < search_stack.size();
+		      i++)
+		    {
+		      search_stack[i].equal_to_first_path = false;
+		    }
+		}
+	      while(!search_stack.empty())
+		{
+		  p.level--;
+		  LevelInfo &info2 = search_stack.back();
+		  if(!(info2.equal_to_first_path == false &&
+		       (!canonical || (info2.cmp_to_best_path < 0))))
+		    break;
+		  search_stack.pop_back();
+		}
+	      continue;
+	    }
+	}
+
+#if defined(VERIFY_EQUITABLEDNESS)
+      /* The new partition should be equitable */
+      assert(is_equitable());
+#endif
+
+      info.equal_to_first_path = refine_equal_to_first;
+      info.cmp_to_best_path = refine_cmp_to_best;
+
+      certificate_index = certificate_current_path.size();
+
+      search_stack.back().eqref_hash = eqref_hash;
+      search_stack.back().subcertificate_length =
+	certificate_index - info.certificate_index;
+
+
+      if(!p.is_discrete())
+	{
+	  /*
+	   * An internal, non-leaf node
+	   */
+	  /* Build the next node info */
+	  /* Find the next cell to be splitted */
+	  assert(cell == p.element_to_cell_map[p.elements[info.split_cell_first]]);
+	  Cell * const next_split_cell = find_next_cell_to_be_splitted(cell);
+	  assert(next_split_cell);
+	  /* Copy current info to the search stack */
+	  search_stack.push_back(info);
+	  LevelInfo &new_info = search_stack.back();
+	  new_info.split_cell_first = next_split_cell->first;
+	  new_info.split_element = -1;
+	  new_info.certificate_index = certificate_index;
+	  new_info.refinement_stack_size = p.refinement_stack.size();
+	  new_info.long_prune_redundant.clear();
+	  new_info.long_prune_begin = info.long_prune_begin;
+	  continue;
+	}
+
+      /*
+       * A leaf node
+       */
+      assert(certificate_index == certificate_size);
+
+      if(first_path_info.empty())
+	{
+	  /* The first path, update first_path and best_path */
+	  //fprintf(stdout, "Level %u: FIRST\n", p.level); fflush(stdout);
+	  stats.nof_canupdates++;
+	  /*
+	   * Update labelings and their inverses
+	   */
+	  update_labeling_and_its_inverse(first_path_labeling,
+					  first_path_labeling_inv);
+	  update_labeling_and_its_inverse(best_path_labeling,
+					  best_path_labeling_inv);
+	  /*
+	   * Reset automorphism array
+	   */
+	  reset_permutation(first_path_automorphism);
+	  reset_permutation(best_path_automorphism);
+	  /*
+	   * Reset orbit information
+	   */
+	  first_path_orbits.reset();
+	  best_path_orbits.reset();
+	  /*
+	   * Reset group size
+	   */
+	  stats.group_size.assign(1);
+	  /*
+	   * Reset all_same_level
+	   */
+	  all_same_level = p.level;
+	  /*
+	   * Mark the current path to be the first and best one and save it
+	   */
+	  const unsigned int base_size = search_stack.size();
+	  assert(p.level == base_size);
+	  best_path_info.clear();
+	  //fprintf(stdout, " New base is: ");
+	  for(unsigned int i = 0; i < base_size; i++) {
+	    search_stack[i].in_first_path = true;
+	    search_stack[i].in_best_path = true;
+	    search_stack[i].equal_to_first_path = true;
+	    search_stack[i].cmp_to_best_path = 0;
+	    PathInfo path_info;
+	    path_info.splitting_element = search_stack[i].split_element;
+	    path_info.certificate_index = search_stack[i].certificate_index;
+	    path_info.eqref_hash = search_stack[i].eqref_hash;
+	    path_info.subcertificate_length = search_stack[i].subcertificate_length;
+	    first_path_info.push_back(path_info);
+	    best_path_info.push_back(path_info);
+	    //fprintf(stdout, "%u ", search_stack[i].split_element);
+	  }
+	  //fprintf(stdout, "\n"); fflush(stdout);
+	  certificate_first_path = certificate_current_path;
+	  certificate_best_path = certificate_current_path;
+
+	  refine_compare_certificate = true;
+	  /*
+	   * Backtrack to the previous level
+	   */
+	  p.level--;
+	  continue;
+	}
+
+      DEBUG_ASSERT(first_path_info.size() > 0);
+
+      //fprintf(stdout, "Level %u: LEAF %d %d\n", p.level, info.equal_to_first_path, info.cmp_to_best_path); fflush(stdout);
+
+      if(info.equal_to_first_path)
+	{
+	  /*
+	   * An automorphism found: aut[i] = elements[first_path_labeling[i]]
+	   */
+	  assert(!info.in_first_path);
+	  //fprintf(stdout, "A"); fflush(stdout);
+	  
+#ifdef PRINT_SEARCH_TREE_DOT
+	  fprintf(dotty_output, "\"n");
+	  for(unsigned int i = 0; i < search_stack.size(); i++) {
+	    fprintf(dotty_output, "%u", search_stack[i].split_element);
+	    if(i < search_stack.size() - 1) fprintf(dotty_output, ".");
+	  }
+	  fprintf(dotty_output, "\" [color=blue];\n");
+#endif
+	  
+#if defined(DEBUG)
+	  /* Verify that the automorphism is correctly built */
+	  for(unsigned int i = 0; i < N; i++)
+	    assert(first_path_automorphism[i] ==
+		   p.elements[first_path_labeling[i]]);
+#endif
+	  
+#if defined(VERIFY_AUTOMORPHISMS)
+	  /* Verify that it really is an automorphism */
+	  assert(is_automorphism(first_path_automorphism));
+#endif
+
+	  long_prune_add_automorphism(first_path_automorphism);
+
+	  /*
+	   * Update orbit information
+	   */
+	  update_orbit_information(first_path_orbits, first_path_automorphism);
+	  
+	  /*
+	   * Compute backjumping level
+	   */
+	  unsigned int backjumping_level = 0;
+	  for(unsigned int i = search_stack.size(); i > 0; i--) {
+	    const unsigned int split_element =
+	      search_stack[backjumping_level].split_element;
+	    if(first_path_automorphism[split_element] != split_element)
+	      break;
+	    backjumping_level++;
+	  }
+	  assert(backjumping_level < p.level);
+	  /*
+	   * Go back to backjumping_level
+	   */
+	  p.level = backjumping_level;
+	  search_stack.resize(p.level + 1);
+	  
+	  // if(write_automorphisms)
+	  //   {
+	  //     print_permutation(stdout, first_path_automorphism);
+	  //     fprintf(stdout, "\n");
+	  //   }
+	  stats.nof_generators++;
+	  continue;
+	}
+
+      assert(canonical);
+      assert(info.cmp_to_best_path >= 0);
+      if(info.cmp_to_best_path > 0)
+	{
+	  /*
+	   * A new, better representative found
+	   */
+	  //fprintf(stdout, "Level %u: NEW BEST\n", p.level); fflush(stdout);
+	  stats.nof_canupdates++;
+	  /*
+	   * Update canonical labeling and its inverse
+	   */
+	  update_labeling_and_its_inverse(best_path_labeling,
+					  best_path_labeling_inv);
+	  /* Reset best path automorphism */
+	  reset_permutation(best_path_automorphism);
+	  /* Reset best path orbit structure */
+	  best_path_orbits.reset();
+	  /*
+	   * Mark the current path to be the best one and save it
+	   */
+	  const unsigned int base_size = search_stack.size();
+	  assert(p.level == base_size);
+	  best_path_info.clear();
+	  //fprintf(stdout, " New base is: ");
+	  for(unsigned int i = 0; i < base_size; i++) {
+	    search_stack[i].cmp_to_best_path = 0;
+	    search_stack[i].in_best_path = true;
+	    PathInfo path_info;
+	    path_info.splitting_element = search_stack[i].split_element;
+	    path_info.certificate_index = search_stack[i].certificate_index;
+	    path_info.eqref_hash = search_stack[i].eqref_hash;
+	    path_info.subcertificate_length = search_stack[i].subcertificate_length;
+	    best_path_info.push_back(path_info);
+	    //fprintf(stdout, "%u ", search_stack[i].split_element);
+	  }
+	  certificate_best_path = certificate_current_path;
+	  //fprintf(stdout, "\n"); fflush(stdout);
+	  /*
+	   * Backtrack to the previous level
+	   */
+	  p.level--;
+	  continue;
+	}
+
+      {
+	//fprintf(stderr, "BAUT ");
+	/*
+	 * Equal to the previous best path
+	 */
+#if defined(DEBUG)
+	/* Verify that the automorphism is correctly built */
+	for(unsigned int i = 0; i < N; i++)
+	  assert(best_path_automorphism[i] ==
+		 p.elements[best_path_labeling[i]]);
+#endif
+	
+#if defined(VERIFY_AUTOMORPHISMS)
+	/* Verify that it really is an automorphism */
+	assert(is_automorphism(best_path_automorphism));
+#endif
+      
+	unsigned int gca_level_with_first = 0;
+	for(unsigned int i = search_stack.size(); i > 0; i--) {
+	  if((int)first_path_info[gca_level_with_first].splitting_element !=
+	     search_stack[gca_level_with_first].split_element)
+	    break;
+	  gca_level_with_first++;
+	}
+	assert(gca_level_with_first < p.level);
+
+	unsigned int gca_level_with_best = 0;
+	for(unsigned int i = search_stack.size(); i > 0; i--) {
+	  if((int)best_path_info[gca_level_with_best].splitting_element !=
+	     search_stack[gca_level_with_best].split_element)
+	    break;
+	  gca_level_with_best++;
+	}
+	assert(gca_level_with_best < p.level);
+
+	long_prune_add_automorphism(best_path_automorphism);
+	    
+	/*
+	 * Update orbit information
+	 */
+	update_orbit_information(best_path_orbits, best_path_automorphism);
+
+	/*
+	 * Update orbit information
+	 */
+	const unsigned int nof_old_orbits = first_path_orbits.nof_orbits();
+	update_orbit_information(first_path_orbits, best_path_automorphism);
+	if(nof_old_orbits != first_path_orbits.nof_orbits())
+	  {
+	    // if(write_automorphisms)
+	    //   {
+	    // 	print_permutation(stdout, best_path_automorphism);
+	    // 	fprintf(stdout, "\n");
+	    //   }
+	    stats.nof_generators++;
+	  }
+	  
+	/*
+	 * Compute backjumping level
+	 */
+	unsigned int backjumping_level = p.level - 1;
+	if(!first_path_orbits.is_minimal_representative(search_stack[gca_level_with_first].split_element))
+	  {
+	    backjumping_level = gca_level_with_first;
+	    /*fprintf(stderr, "bj1: %u %u\n", p.level, backjumping_level);*/
+	  }
+	else
+	  {
+	    assert(!best_path_orbits.is_minimal_representative(search_stack[gca_level_with_best].split_element));
+	    backjumping_level = gca_level_with_best;
+	    /*fprintf(stderr, "bj2: %u %u\n", p.level, backjumping_level);*/
+	  }
+	/* Backtrack */
+	search_stack.resize(backjumping_level + 1);
+	p.level = backjumping_level;
+	continue;
+      }
+    }
+
+#ifdef PRINT_SEARCH_TREE_DOT
+  fprintf(dotty_output, "}\n");
+  fclose(dotty_output);
+#endif
+}
+
+
+
+
+void AbstractGraph::find_automorphisms(Stats &stats)
+{
+  search(false, stats);
+
+  if(first_path_labeling)
+    {
+      free(first_path_labeling);
+      first_path_labeling = 0;
+    }
+  if(best_path_labeling)
+    {
+      free(best_path_labeling);
+      best_path_labeling = 0;
+    }
+}
+
+
+const unsigned int *AbstractGraph::canonical_form(Stats &stats)
+{
+  search(true, stats);
+
+  return best_path_labeling;
+}
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Routines for undirected graphs
+ *
+ *-------------------------------------------------------------------------*/
+
+Graph::Vertex::Vertex()
+{
+  label = 1;
+  nof_edges = 0;
+}
+
+
+Graph::Vertex::~Vertex()
+{
+  ;
+}
+
+
+void Graph::Vertex::add_edge(const unsigned int other_vertex)
+{
+  edges.push_back(other_vertex);
+  nof_edges++;
+  DEBUG_ASSERT(nof_edges == edges.size());
+}
+
+
+void Graph::Vertex::remove_duplicate_edges(bool * const duplicate_array)
+{
+  for(std::vector<unsigned int>::iterator iter = edges.begin();
+      iter != edges.end(); )
+    {
+      const unsigned int dest_vertex = *iter;
+      if(duplicate_array[dest_vertex] == true)
+	{
+	  /* A duplicate edge found! */
+	  iter = edges.erase(iter);
+	  nof_edges--;
+	  DEBUG_ASSERT(nof_edges == edges.size());
+	}
+      else
+	{
+	  /* Not seen earlier, mark as seen */
+	  duplicate_array[dest_vertex] = true;
+	  iter++;
+	}
+    }
+
+  /* Clear duplicate_array */
+  for(std::vector<unsigned int>::iterator iter = edges.begin();
+      iter != edges.end();
+      iter++)
+    {
+      duplicate_array[*iter] = false;
+    }
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Constructor and destructor for undirected graphs
+ *
+ *-------------------------------------------------------------------------*/
+
+
+Graph::Graph(const unsigned int nof_vertices)
+{
+  vertices.resize(nof_vertices);
+  sh = sh_flm;
+}
+
+
+Graph::~Graph()
+{
+  ;
+}
+
+
+unsigned int Graph::add_vertex(const unsigned int new_label)
+{
+  const unsigned int new_vertex_num = vertices.size();
+  vertices.resize(new_vertex_num + 1);
+  vertices.back().label = new_label;
+  return new_vertex_num;
+}
+
+
+void Graph::add_edge(const unsigned int vertex1, const unsigned int vertex2)
+{
+  //fprintf(stderr, "(%u,%u) ", vertex1, vertex2);
+  assert(vertex1 < vertices.size());
+  assert(vertex2 < vertices.size());
+  vertices[vertex1].add_edge(vertex2);
+  vertices[vertex2].add_edge(vertex1);
+}
+
+
+void Graph::change_label(const unsigned int vertex,
+			   const unsigned int new_label)
+{
+  assert(vertex < vertices.size());
+  vertices[vertex].label = new_label;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Read graph in the DIMACS format
+ *
+ *-------------------------------------------------------------------------*/
+
+// Graph *Graph::read_dimacs(FILE *fp)
+// {
+//   Graph *g = 0;
+//   unsigned int nof_vertices, nof_edges;
+//   unsigned int line_num = 1;
+//   int c;
+  
+//   /* read comments and problem line*/
+//   while(1) {
+//     c = getc(fp);
+//     if(c == 'c') {
+//       while((c = getc(fp)) != '\n') {
+//         if(c == EOF) {
+//           fprintf(stderr, "error in line %u: not in DIMACS format\n",
+//                   line_num);
+//           goto error_exit;
+//         }
+//       }
+//       line_num++;
+//       continue;
+//     }
+//     if(c == 'p') {
+//       if(fscanf(fp, " edge %u %u\n", &nof_vertices, &nof_edges) != 2) {
+//         fprintf(stderr, "error in line %u: not in DIMACS format\n",
+//                 line_num);
+//         goto error_exit; }
+//       line_num++;
+//       break;
+//     }
+//     fprintf(stderr, "error in line %u: not in DIMACS format\n", line_num);
+//     goto error_exit;
+//   }
+  
+//   if(nof_vertices <= 0) {
+//     fprintf(stderr, "error: no vertices\n");
+//     goto error_exit;
+//   }
+// #if 0
+//   if(nof_edges <= 0) {
+//     fprintf(stderr, "error: no edges\n");
+//     goto error_exit;
+//   }
+// #endif
+//   if(bliss_verbose) {
+//     fprintf(bliss_verbstr, "Instance has %d vertices and %d edges\n",
+//             nof_vertices, nof_edges);
+//     fflush(bliss_verbstr);
+//   }
+
+//   g = new Graph(nof_vertices);
+
+//   //
+//   // Read vertex labels
+//   //
+//   if(bliss_verbose) {
+//     fprintf(bliss_verbstr, "Reading vertex labels...\n");
+//     fflush(bliss_verbstr); }
+//   while(1) {
+//     c = getc(fp);
+//     if(c != 'n') {
+//       ungetc(c, fp);
+//       break;
+//     }
+//     ungetc(c, fp);
+//     unsigned int vertex, label;
+//     if(fscanf(fp, "n %u %u\n", &vertex, &label) != 2) {
+//       fprintf(stderr, "error in line %u: not in DIMACS format\n",
+// 	      line_num);
+//       goto error_exit;
+//     }
+//     if(vertex > nof_vertices) {
+//       fprintf(stderr, "error in line %u: not in DIMACS format\n",
+// 	      line_num);
+//       goto error_exit;
+//     }
+//     line_num++;
+//     g->change_label(vertex - 1, label);
+//   }
+//   if(bliss_verbose) {
+//     fprintf(bliss_verbstr, "Done\n");
+//     fflush(bliss_verbstr); }
+
+//   //
+//   // Read edges
+//   //
+//   if(bliss_verbose) {
+//     fprintf(bliss_verbstr, "Reading edges...\n");
+//     fflush(bliss_verbstr); }
+//   for(unsigned i = 0; i < nof_edges; i++) {
+//     unsigned int from, to;
+//     if(fscanf(fp, "e %u %u\n", &from, &to) != 2) {
+//       fprintf(stderr, "error in line %u: not in DIMACS format\n",
+// 	      line_num);
+//       goto error_exit;
+//     }
+//     if(from > nof_vertices || to > nof_vertices) {
+//       fprintf(stderr, "error in line %u: not in DIMACS format\n",
+// 	      line_num);
+//       goto error_exit;
+//     }
+//     line_num++;
+//     g->add_edge(from - 1, to - 1);
+//   }
+//   if(bliss_verbose) {
+//     fprintf(bliss_verbstr, "Done\n");
+//     fflush(bliss_verbstr);
+//   }
+
+//   return g;
+
+//  error_exit:
+//   if(g)
+//     delete g;
+//   return 0;
+
+// }
+
+Graph *Graph::from_igraph(const igraph_t *graph) {
+  
+  unsigned int nof_vertices= (unsigned int)igraph_vcount(graph);
+  unsigned int nof_edges= (unsigned int)igraph_ecount(graph);
+  Graph *g=new Graph(nof_vertices);
+//   for (unsigned int i=0; i<nof_vertices; i++) {
+//     g->change_label(i, i);
+//   }
+  for (unsigned int i=0; i<nof_edges; i++) {
+    g->add_edge((unsigned int)IGRAPH_FROM(graph, i), 
+		(unsigned int)IGRAPH_TO(graph, i));
+  }  
+  return g;
+}
+
+void Graph::print_dimacs(FILE *fp)
+{
+  unsigned int nof_edges = 0;
+  for(unsigned int i = 0; i < get_nof_vertices(); i++)
+    {
+      Vertex &v = vertices[i];
+      for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+	  ei != v.edges.end();
+	  ei++)
+	{
+	  const unsigned int dest_i = *ei;
+	  if(dest_i < i)
+	    continue;
+	  nof_edges++;
+	}
+    }
+
+  fprintf(fp, "p edge %u %u\n", get_nof_vertices(), nof_edges);
+  for(unsigned int i = 0; i < get_nof_vertices(); i++)
+    {
+      Vertex &v = vertices[i];
+      if(v.label != 1)
+	{
+	  fprintf(fp, "n %u %u\n", i+1, v.label);
+	}
+    }
+  for(unsigned int i = 0; i < get_nof_vertices(); i++)
+    {
+      Vertex &v = vertices[i];
+      for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+	  ei != v.edges.end();
+	  ei++)
+	{
+	  const unsigned int dest_i = *ei;
+	  if(dest_i < i)
+	    continue;
+	  fprintf(fp, "e %u %u\n", i+1, dest_i+1);
+	}
+    }
+}
+
+
+
+
+Graph *Graph::permute(const unsigned int *perm)
+{
+  Graph *g = new Graph(get_nof_vertices());
+  for(unsigned int i = 0; i < get_nof_vertices(); i++)
+    {
+      Vertex &v = vertices[i];
+      Vertex &permuted_v = g->vertices[perm[i]];
+      permuted_v.label = v.label;
+      for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+	  ei != v.edges.end();
+	  ei++)
+	{
+	  const unsigned int dest_v = *ei;
+	  permuted_v.add_edge(perm[dest_v]);
+	}
+      std::sort(permuted_v.edges.begin(), permuted_v.edges.end());
+    }
+  return g;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Print graph in graphviz format
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void Graph::to_dot(const char *file_name)
+{
+  FILE *fp = fopen(file_name, "w");
+  if(fp)
+    to_dot(fp);
+  fclose(fp);
+}
+
+
+void Graph::to_dot(FILE *fp)
+{
+  remove_duplicate_edges();
+
+  fprintf(fp, "graph g {\n");
+
+  unsigned int vnum = 0;
+  for(std::vector<Vertex>::iterator vi = vertices.begin();
+      vi != vertices.end();
+      vi++, vnum++)
+    {
+      Vertex &v = *vi;
+      fprintf(fp, "v%u [label=\"%u:%u\"];\n", vnum, vnum, v.label);
+      for(std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+	  ei != v.edges.end();
+	  ei++)
+	{
+	  const unsigned int vnum2 = *ei;
+	  if(vnum2 > vnum)
+	    fprintf(fp, "v%u -- v%u\n", vnum, vnum2);
+	}
+    }
+
+  fprintf(fp, "}\n");
+}
+
+
+
+
+
+void Graph::remove_duplicate_edges()
+{
+  bool *duplicate_array = (bool*)calloc(vertices.size(), sizeof(bool));
+
+  for(std::vector<Vertex>::iterator vi = vertices.begin();
+      vi != vertices.end();
+      vi++)
+    {
+#ifdef EXPENSIVE_CONSISTENCY_CHECKS
+      for(unsigned int i = 0; i < vertices.size(); i++)
+	assert(duplicate_array[i] == false);
+#endif
+      Vertex &v = *vi;
+      v.remove_duplicate_edges(duplicate_array);
+    }
+
+  free(duplicate_array);
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Partition independent invariants
+ *
+ *-------------------------------------------------------------------------*/
+
+
+unsigned int Graph::label_invariant(Graph *g, unsigned int v)
+{
+  DEBUG_ASSERT(v < g->vertices.size());
+  return g->vertices[v].label;
+}
+
+
+unsigned int Graph::degree_invariant(Graph *g, unsigned int v)
+{
+  DEBUG_ASSERT(v < g->vertices.size());
+  DEBUG_ASSERT(g->vertices[v].edges.size() ==
+	       g->vertices[v].nof_edges);
+  return g->vertices[v].nof_edges;
+}
+
+
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Refine the partition p according to a partition independent invariant
+ *
+ *-------------------------------------------------------------------------*/
+
+bool Graph::refine_according_to_invariant(unsigned int (*inv)(Graph * const g, unsigned int v))
+{
+  bool refined = false;
+
+  for(Cell *cell = p.first_cell; cell; )
+    {
+      assert(cell->max_ival == 0);
+      assert(cell->max_ival_count == 0);
+      
+      Cell * const next_cell = cell->next;
+
+      if(cell->length == 1)
+	{
+	  cell = next_cell;
+	  continue;
+	}
+      
+      const unsigned int *ep = p.elements + cell->first;
+      for(unsigned int i = cell->length; i > 0; i--, ep++)
+	{
+	  unsigned int ival = inv(this, *ep);
+	  p.invariant_values[*ep] = ival;
+	  if(ival > cell->max_ival) {
+	    cell->max_ival = ival;
+	    cell->max_ival_count = 1;
+	  }
+	  else if(ival == cell->max_ival) {
+	    cell->max_ival_count++;
+	  }
+	}
+      Cell * const last_new_cell = p.zplit_cell(cell, true);
+      refined = (last_new_cell != cell);
+      cell = next_cell;
+    }
+
+  return refined;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Split the neighbourhood of a cell according to the equitable invariant
+ *
+ *-------------------------------------------------------------------------*/
+
+
+void Graph::split_neighbourhood_of_cell(Cell * const cell)
+{
+  DEBUG_ASSERT(neighbour_heap.is_empty());
+  DEBUG_ASSERT(cell->length > 1);
+
+  eqref_hash.update(cell->first);
+  eqref_hash.update(cell->length);
+
+  unsigned int *ep = p.elements + cell->first;
+  for(unsigned int i = cell->length; i > 0; i--)
+    {
+      const Vertex &v = vertices[*ep];
+      ep++;
+      
+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+      for(unsigned int j = v.nof_edges; j > 0; j--)
+	{
+	  const unsigned int dest_vertex = *ei++;
+	  Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
+	  if(neighbour_cell->length == 1)
+	    continue;
+	  const unsigned int ival = p.invariant_values[dest_vertex] + 1;
+	  p.invariant_values[dest_vertex] = ival;
+	  if(ival > neighbour_cell->max_ival) {
+	    neighbour_cell->max_ival = ival;
+	    neighbour_cell->max_ival_count = 1;
+	  }
+	  else if(ival == neighbour_cell->max_ival) {
+	    neighbour_cell->max_ival_count++;
+	  }
+	  if(!neighbour_cell->in_neighbour_heap) {
+	    neighbour_cell->in_neighbour_heap = true;
+	    neighbour_heap.insert(neighbour_cell->first);
+	  }
+	}
+    }
+
+  while(!neighbour_heap.is_empty())
+    {
+      const unsigned int start = neighbour_heap.remove();
+      Cell * const neighbour_cell = p.element_to_cell_map[p.elements[start]];
+      DEBUG_ASSERT(neighbour_cell->first == start);
+      DEBUG_ASSERT(neighbour_cell->in_neighbour_heap);
+      neighbour_cell->in_neighbour_heap = false;
+      
+      DEBUG_ASSERT(neighbour_cell->length > 1);
+      DEBUG_ASSERT(neighbour_cell->max_ival >= 1);
+      DEBUG_ASSERT(neighbour_cell->max_ival_count >= 1);
+      
+      eqref_hash.update(neighbour_cell->first);
+      eqref_hash.update(neighbour_cell->length);
+      eqref_hash.update(neighbour_cell->max_ival);
+      eqref_hash.update(neighbour_cell->max_ival_count);
+
+      Cell * const last_new_cell = p.zplit_cell(neighbour_cell, true);
+      /* Update hash */
+      const Cell *c = neighbour_cell;
+      while(1)
+	{
+	  eqref_hash.update(c->first);
+	  eqref_hash.update(c->length);
+	  if(c == last_new_cell)
+	    break;
+	  c = c->next;
+	}
+    }
+}
+
+
+bool Graph::split_neighbourhood_of_unit_cell(Cell * const unit_cell)
+{
+  DEBUG_ASSERT(neighbour_heap.is_empty());
+
+  DEBUG_ASSERT(unit_cell->length == 1);
+  DEBUG_ASSERT(p.element_to_cell_map[p.elements[unit_cell->first]] == unit_cell);
+  DEBUG_ASSERT(p.in_pos[p.elements[unit_cell->first]] ==
+               p.elements + unit_cell->first);
+
+  eqref_hash.update(0x87654321);
+  eqref_hash.update(unit_cell->first);
+  eqref_hash.update(1);
+
+  const Vertex &v = vertices[p.elements[unit_cell->first]];
+
+  std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+  for(unsigned int j = v.nof_edges; j > 0; j--)
+    {
+      const unsigned int dest_vertex = *ei++;
+      Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
+      DEBUG_ASSERT(*p.in_pos[dest_vertex] == dest_vertex);
+      
+      if(neighbour_cell->length == 1) {
+	DEBUG_ASSERT(!neighbour_cell->in_neighbour_heap);
+	if(in_search) {
+	  neighbour_cell->in_neighbour_heap = true;
+	  neighbour_heap.insert(neighbour_cell->first);
+	}
+	continue;
+      }
+      if(!neighbour_cell->in_neighbour_heap) {
+	neighbour_cell->in_neighbour_heap = true;
+	neighbour_heap.insert(neighbour_cell->first);
+      }
+      neighbour_cell->max_ival_count++;
+      DEBUG_ASSERT(neighbour_cell->max_ival_count <= neighbour_cell->length);
+      
+      unsigned int * const swap_position =
+	p.elements + neighbour_cell->first + neighbour_cell->length -
+	neighbour_cell->max_ival_count;
+      DEBUG_ASSERT(p.in_pos[dest_vertex] <= swap_position);
+      *p.in_pos[dest_vertex] = *swap_position;
+      p.in_pos[*swap_position] = p.in_pos[dest_vertex];
+      *swap_position = dest_vertex;
+      p.in_pos[dest_vertex] = swap_position;
+    }
+
+  while(!neighbour_heap.is_empty())
+    {
+      const unsigned int start = neighbour_heap.remove();
+      Cell *neighbour_cell = p.element_to_cell_map[p.elements[start]];
+      DEBUG_ASSERT(neighbour_cell->in_neighbour_heap);
+      neighbour_cell->in_neighbour_heap = false;
+
+#ifdef DEBUG
+      assert(neighbour_cell->first == start);
+      if(neighbour_cell->length == 1) {
+	assert(neighbour_cell->max_ival_count == 0);
+      } else {
+	assert(neighbour_cell->max_ival_count > 0);
+	assert(neighbour_cell->max_ival_count <= neighbour_cell->length);
+      }
+#endif
+
+      eqref_hash.update(neighbour_cell->first);
+      eqref_hash.update(neighbour_cell->length);
+      eqref_hash.update(neighbour_cell->max_ival_count);
+
+      if(neighbour_cell->length > 1 &&
+	 neighbour_cell->max_ival_count != neighbour_cell->length) {
+
+	p.consistency_check();
+
+	Cell * const new_cell = p.aux_split_in_two(neighbour_cell, neighbour_cell->length - neighbour_cell->max_ival_count);
+	unsigned int *ep = p.elements + new_cell->first;
+	unsigned int * const lp = p.elements+new_cell->first+new_cell->length;
+	while(ep < lp) {
+	  DEBUG_ASSERT(p.in_pos[*ep] == ep);
+	  p.element_to_cell_map[*ep] = new_cell;
+	  ep++;
+	}
+	neighbour_cell->max_ival_count = 0;
+
+	p.consistency_check();
+
+	/* update hash */
+	eqref_hash.update(neighbour_cell->first);
+	eqref_hash.update(neighbour_cell->length);
+	eqref_hash.update(0);
+	eqref_hash.update(new_cell->first);
+	eqref_hash.update(new_cell->length);
+	eqref_hash.update(1);
+
+	/* Add cells in splitting_queue */
+	DEBUG_ASSERT(!new_cell->in_splitting_queue);
+	if(neighbour_cell->in_splitting_queue) {
+	  /* Both cells must be included in splitting_queue in order
+	     to have refinement to equitable partition */
+	  p.add_in_splitting_queue(new_cell);
+	} else {
+	  Cell *min_cell, *max_cell;
+	  if(neighbour_cell->length <= new_cell->length) {
+	    min_cell = neighbour_cell;
+	    max_cell = new_cell;
+	  } else {
+	    min_cell = new_cell;
+	    max_cell = neighbour_cell;
+	  }
+	  /* Put the smaller cell in splitting_queue */
+	  p.add_in_splitting_queue(min_cell);
+	  if(max_cell->length == 1) {
+	    /* Put the "larger" cell also in splitting_queue */
+	    p.add_in_splitting_queue(max_cell);
+	  }
+	}
+	/* Update pointer for certificate generation */
+	neighbour_cell = new_cell;
+      }
+      else
+	neighbour_cell->max_ival_count = 0;
+
+      /*
+       * Build certificate if required
+       */
+      if(in_search)
+	{
+	  for(unsigned int i = neighbour_cell->first,
+		j = neighbour_cell->length,
+		c_index = certificate_current_path.size();
+	      j > 0;
+	      j--, i++, c_index += 2)
+	    {
+	      if(refine_compare_certificate)
+		{
+		  if(refine_equal_to_first)
+		    {
+		      if(c_index >= refine_first_path_subcertificate_end)
+			refine_equal_to_first = false;
+		      else if(certificate_first_path[c_index] !=
+			      unit_cell->first)
+			refine_equal_to_first = false;
+		      else if(certificate_first_path[c_index+1] != i)
+			refine_equal_to_first = false;
+		    }
+		  if(refine_cmp_to_best == 0)
+		    {
+		      if(c_index >= refine_best_path_subcertificate_end)
+			{
+			  refine_cmp_to_best = 1;
+			}
+		      else if(unit_cell->first>certificate_best_path[c_index])
+			{
+			  refine_cmp_to_best = 1;
+			}
+		      else if(unit_cell->first<certificate_best_path[c_index])
+			{
+			  refine_cmp_to_best = -1;
+			}
+		      else if(i > certificate_best_path[c_index+1])
+			{
+			  refine_cmp_to_best = 1;
+			}
+		      else if(i < certificate_best_path[c_index+1])
+			{
+			  refine_cmp_to_best = -1;
+			}
+		    }
+		  if((refine_equal_to_first == false) &&
+		     (refine_cmp_to_best < 0))
+		    goto worse_exit;
+		}
+	      certificate_current_path.push_back(unit_cell->first);
+	      certificate_current_path.push_back(i);
+	    }
+	} /* if(in_search) */
+    } /* while(!neighbour_heap.is_empty()) */
+  
+  return false;
+
+ worse_exit:
+  while(!neighbour_heap.is_empty())
+    {
+      const unsigned int start = neighbour_heap.remove();
+      Cell * const neighbour_cell = p.element_to_cell_map[p.elements[start]];
+      DEBUG_ASSERT(neighbour_cell->in_neighbour_heap);
+      neighbour_cell->in_neighbour_heap = false;
+      neighbour_cell->max_ival_count = 0;
+    }
+  return true;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Check whether the current partition p is equitable
+ * Slow: use only for debugging purposes
+ * Side effect: resets max_ival and max_ival_count fields in cells
+ *
+ *-------------------------------------------------------------------------*/
+
+bool Graph::is_equitable()
+{
+  bool result = true;
+
+  /*
+   * Max ival and max_ival_count are used for counting purposes,
+   * they should be reset...
+   */
+  for(Cell *cell = p.first_cell; cell; cell = cell->next)
+    {
+      assert(cell->prev_next_ptr && *(cell->prev_next_ptr) == cell);
+      assert(cell->max_ival == 0);
+      assert(cell->max_ival_count == 0);
+    }
+
+
+  for(Cell *cell = p.first_cell; cell; cell = cell->next)
+    {
+      if(cell->length == 1)
+	continue;
+
+      unsigned int *ep = p.elements + cell->first;
+      Vertex &first_vertex = vertices[*ep++];
+
+      /* Count edges of the first vertex for cells in max_ival */
+      std::vector<unsigned int>::const_iterator ei = first_vertex.edges.begin();
+      for(unsigned int j = first_vertex.nof_edges; j > 0; j--)
+	{
+	  p.element_to_cell_map[*ei++]->max_ival++;
+	}
+
+      /* Count and compare edges of the other vertices */
+      for(unsigned int i = cell->length; i > 1; i--)
+	{
+	  Vertex &vertex = vertices[*ep++];
+	  std::vector<unsigned int>::const_iterator ei = vertex.edges.begin();
+	  for(unsigned int j = vertex.nof_edges; j > 0; j--)
+	    {
+	      p.element_to_cell_map[*ei++]->max_ival_count++;
+	    }
+	  for(Cell *cell2 = p.first_cell; cell2; cell2 = cell2->next)
+	    {
+	      if(cell2->max_ival != cell2->max_ival_count)
+		{
+		  result = false;
+		  goto done;
+		}
+	      cell2->max_ival_count = 0;
+	    }
+	}
+      /* Reset max_ival */
+      for(Cell *cell2 = p.first_cell; cell2; cell2 = cell2->next)
+	{
+	  cell2->max_ival = 0;
+	  assert(cell2->max_ival_count == 0);
+	}
+    }
+
+ done:
+
+  for(Cell *cell = p.first_cell; cell; cell = cell->next)
+    {
+      cell->max_ival = 0;
+      cell->max_ival_count = 0;
+    }
+
+  return result;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Build the initial equitable partition
+ *
+ *-------------------------------------------------------------------------*/
+
+void Graph::make_initial_equitable_partition()
+{
+  refine_according_to_invariant(&label_invariant);
+  p.clear_splitting_queue();
+  //p.print_signature(stderr); fprintf(stderr, "\n");
+
+  refine_according_to_invariant(&degree_invariant);
+  p.clear_splitting_queue();
+  //p.print_signature(stderr); fprintf(stderr, "\n");
+
+  /* To do: add loop invariant */
+
+  refine_to_equitable();
+  p.refinement_stack.clean();
+  //p.print_signature(stderr); fprintf(stderr, "\n");
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Find the next cell to be splitted
+ *
+ *-------------------------------------------------------------------------*/
+
+Cell *Graph::find_next_cell_to_be_splitted(Cell *cell)
+{
+  assert(!p.is_discrete());
+  switch(sh) {
+  case sh_f:
+    return sh_first(cell);
+  case sh_fs:
+    return sh_first_smallest(cell);
+  case sh_fl:
+    return sh_first_largest(cell);
+  case sh_fm:
+    return sh_first_max_neighbours(cell);
+  case sh_fsm:
+    return sh_first_smallest_max_neighbours(cell);
+  case sh_flm:
+    return sh_first_largest_max_neighbours(cell);
+  default:
+    assert(false && "Unknown splitting heuristics");
+    return 0;
+  }
+}
+
+/* First nonsingleton cell */
+Cell *Graph::sh_first(Cell *cell)
+{
+  IGRAPH_UNUSED(cell);
+  return p.first_nonsingleton_cell;
+}
+
+/* First smallest nonsingleton cell. */
+Cell *Graph::sh_first_smallest(Cell *cell)
+{
+  Cell *best_cell = 0;
+  unsigned int best_size = UINT_MAX;
+  for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
+    {
+      assert(cell->length > 1);
+      if(cell->length < best_size)
+	{
+	  best_size = cell->length;
+	  best_cell = cell;
+	}
+    }
+  assert(best_cell);
+  return best_cell;
+}
+
+/* First largest nonsingleton cell. */
+Cell *Graph::sh_first_largest(Cell *cell)
+{
+  Cell *best_cell = 0;
+  unsigned int best_size = 0;
+  for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
+    {
+      assert(cell->length > 1);
+      if(cell->length > best_size)
+	{
+	  best_size = cell->length;
+	  best_cell = cell;
+	}
+    }
+  assert(best_cell);
+  return best_cell;
+}
+
+/* First nonsingleton cell with max number of neighbouring
+ * nonsingleton cells.
+ * Assumes that the partition p is equitable.
+ * Messes up in_neighbour_heap and max_ival fields of cells
+ * (assumes they are false/0).
+ */
+Cell *Graph::sh_first_max_neighbours(Cell *cell)
+{
+  Cell *best_cell = 0;
+  int best_value = -1;
+  for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
+    {
+      assert(cell->length > 1);
+	
+      const Vertex &v = vertices[p.elements[cell->first]];
+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+      std::list<Cell*> neighbour_cells_visited;
+      for(unsigned int j = v.nof_edges; j > 0; j--)
+	{
+	  const unsigned int dest_vertex = *ei++;
+	  Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
+	  if(neighbour_cell->length == 1)
+	    continue;
+	  neighbour_cell->max_ival++;
+	  if(neighbour_cell->in_neighbour_heap)
+	    continue;
+	  neighbour_cell->in_neighbour_heap = true;
+	  neighbour_cells_visited.push_back(neighbour_cell);
+	}
+      int value = 0;
+      while(!neighbour_cells_visited.empty())
+	{
+	  Cell * const neighbour_cell = neighbour_cells_visited.front();
+	  neighbour_cells_visited.pop_front();
+	  assert(neighbour_cell->in_neighbour_heap);
+	  neighbour_cell->in_neighbour_heap = false;
+	  if(neighbour_cell->max_ival != neighbour_cell->length)
+	    value++;
+	  neighbour_cell->max_ival = 0;
+	}
+      if(value > best_value)
+	{
+	  best_value = value;
+	  best_cell = cell;
+	}
+    }
+  assert(best_cell);
+  return best_cell;
+}
+/* First smallest nonsingleton cell with max number of neighbouring
+ * nonsingleton cells.
+ * Assumes that the partition p is equitable.
+ * Messes up in_neighbour_heap and max_ival fields of cells
+ * (assumes they are false).
+ */
+Cell *Graph::sh_first_smallest_max_neighbours(Cell *cell)
+{
+  Cell *best_cell = 0;
+  int best_value = -1;
+  int best_size = INT_MAX;
+  for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
+    {
+      assert(cell->length > 1);
+	
+      const Vertex &v = vertices[p.elements[cell->first]];
+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+      std::list<Cell*> neighbour_cells_visited;
+      for(unsigned int j = v.nof_edges; j > 0; j--)
+	{
+	  const unsigned int dest_vertex = *ei++;
+	  Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
+	  if(neighbour_cell->length == 1)
+	    continue;
+	  neighbour_cell->max_ival++;
+	  if(neighbour_cell->in_neighbour_heap)
+	    continue;
+	  neighbour_cell->in_neighbour_heap = true;
+	  neighbour_cells_visited.push_back(neighbour_cell);
+	}
+      int value = 0;
+      while(!neighbour_cells_visited.empty())
+	{
+	  Cell * const neighbour_cell = neighbour_cells_visited.front();
+	  neighbour_cells_visited.pop_front();
+	  assert(neighbour_cell->in_neighbour_heap);
+	  neighbour_cell->in_neighbour_heap = false;
+	  if(neighbour_cell->max_ival != neighbour_cell->length)
+	    value++;
+	  neighbour_cell->max_ival = 0;
+	}
+      if((value > best_value) ||
+	 (value == best_value && (int)cell->length < best_size))
+	{
+	  best_value = value;
+	  best_size = cell->length;
+	  best_cell = cell;
+	}
+    }
+  assert(best_cell);
+  return best_cell;
+}
+/* First largest nonsingleton cell with max number of neighbouring
+ * nonsingleton cells.
+ * Assumes that the partition p is equitable.
+ * Messes up in_neighbour_heap and max_ival fields of cells
+ * (assumes they are false/0).
+ */
+Cell *Graph::sh_first_largest_max_neighbours(Cell *cell)
+{
+  Cell *best_cell = 0;
+  int best_value = -1;
+  int best_size = -1;
+  for(cell = p.first_nonsingleton_cell; cell; cell = cell->next_nonsingleton)
+    {
+      assert(cell->length > 1);
+	
+      const Vertex &v = vertices[p.elements[cell->first]];
+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();
+      std::list<Cell*> neighbour_cells_visited;
+      for(unsigned int j = v.nof_edges; j > 0; j--)
+	{
+	  const unsigned int dest_vertex = *ei++;
+	  Cell * const neighbour_cell = p.element_to_cell_map[dest_vertex];
+	  if(neighbour_cell->length == 1)
+	    continue;
+	  neighbour_cell->max_ival++;
+	  if(neighbour_cell->in_neighbour_heap)
+	    continue;
+	  neighbour_cell->in_neighbour_heap = true;
+	  neighbour_cells_visited.push_back(neighbour_cell);
+	}
+      int value = 0;
+      while(!neighbour_cells_visited.empty())
+	{
+	  Cell * const neighbour_cell = neighbour_cells_visited.front();
+	  neighbour_cells_visited.pop_front();
+	  assert(neighbour_cell->in_neighbour_heap);
+	  neighbour_cell->in_neighbour_heap = false;
+	  if(neighbour_cell->max_ival != neighbour_cell->length)
+	    value++;
+	  neighbour_cell->max_ival = 0;
+	}
+      if((value > best_value) ||
+	 (value == best_value && (int)cell->length > best_size))
+	{
+	  best_value = value;
+	  best_size = cell->length;
+	  best_cell = cell;
+	}
+    }
+  assert(best_cell);
+  return best_cell;
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Initialize the certificate size and memory
+ *
+ *-------------------------------------------------------------------------*/
+
+void Graph::initialize_certificate()
+{
+  certificate_size = 0;
+  for(Cell *cell = p.first_cell; cell; cell = cell->next)
+    {
+      if(cell->length > 1) {
+	certificate_size +=
+	  vertices[p.elements[cell->first]].nof_edges * 2 * cell->length;
+      }
+    }
+  //if(certificate)
+  //  free(certificate);
+  //certificate = (unsigned int*)malloc(certificate_size * sizeof(unsigned int));
+  certificate_index = 0;
+
+  certificate_current_path.clear();
+  certificate_first_path.clear();
+  certificate_best_path.clear();
+}
+
+
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Check whether perm is an automorphism
+ *
+ *-------------------------------------------------------------------------*/
+
+bool Graph::is_automorphism(unsigned int * const perm)
+{
+  std::set<unsigned int, std::less<unsigned int> > edges1;
+  std::set<unsigned int, std::less<unsigned int> > edges2;
+
+  bool result = true;
+
+  for(unsigned int i = 0; i < vertices.size(); i++)
+    {
+      Vertex &v1 = vertices[i];
+      edges1.clear();
+      for(std::vector<unsigned int>::iterator ei = v1.edges.begin();
+	  ei != v1.edges.end();
+	  ei++)
+	edges1.insert(perm[*ei]);
+      
+      Vertex &v2 = vertices[perm[i]];
+      edges2.clear();
+      for(std::vector<unsigned int>::iterator ei = v2.edges.begin();
+	  ei != v2.edges.end();
+	  ei++)
+	edges2.insert(*ei);
+
+      if(!(edges1 == edges2))
+	{
+	  result = false;
+	  goto done;
+	}
+    }
+
+ done:
+
+  return result;
+}
+
+}
diff --git a/src/bliss_graph.hh b/src/bliss_graph.hh
new file mode 100644
index 0000000..1784ec3
--- /dev/null
+++ b/src/bliss_graph.hh
@@ -0,0 +1,236 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_GRAPH_HH
+#define BLISS_GRAPH_HH
+
+namespace igraph {
+  class AbstractGraph;
+}
+
+#include <cstdio>
+#include <vector>
+#include "bliss_kstack.hh"
+#include "bliss_kqueue.hh"
+#include "bliss_heap.hh"
+#include "bliss_orbit.hh"
+#include "bliss_partition.hh"
+#include "bliss_bignum.hh"
+#include "bliss_eqrefhash.hh"
+
+#include "igraph_datatype.h"
+
+namespace igraph {
+
+typedef struct t_Stats
+{
+  BigNum group_size;
+  long unsigned int nof_nodes;
+  long unsigned int nof_leaf_nodes;
+  long unsigned int nof_bad_nodes;
+  long unsigned int nof_canupdates;
+  long unsigned int nof_generators;
+  unsigned long int max_level;
+} Stats;
+
+class AbstractGraph
+{
+  friend class Partition;
+protected:
+  AbstractGraph();
+  virtual ~AbstractGraph();
+  
+  Partition p;
+
+  bool in_search;
+
+  bool refine_compare_certificate;
+  bool refine_equal_to_first;
+  unsigned int refine_first_path_subcertificate_end;
+  int refine_cmp_to_best;
+  unsigned int refine_best_path_subcertificate_end;
+
+  /* Max mem used by long prune in megabytes */
+  static const unsigned int long_prune_options_max_mem = 20;
+  static const unsigned int long_prune_options_max_stored_auts = 50;
+  unsigned int long_prune_max_stored_autss;
+  std::vector<std::vector<bool> *> long_prune_fixed;
+  std::vector<std::vector<bool> *> long_prune_mcrs;
+  std::vector<bool> long_prune_temp;
+  unsigned int long_prune_begin;
+  unsigned int long_prune_end;
+  void long_prune_init();
+  void long_prune_add_automorphism(const unsigned int *aut);
+  std::vector<bool> &long_prune_get_fixed(const unsigned int index);
+  std::vector<bool> &long_prune_get_mcrs(const unsigned int index);
+  void long_prune_swap(const unsigned int i, const unsigned int j);
+
+  /*
+   * Data structures and routines for refining the partition p into equitable
+   */
+  Heap neighbour_heap;
+  virtual bool split_neighbourhood_of_unit_cell(Cell *) = 0;
+  virtual void split_neighbourhood_of_cell(Cell * const) = 0;
+  void refine_to_equitable();
+  void refine_to_equitable(Cell *cell);
+  void refine_to_equitable(Cell *cell1, Cell *cell2);
+  void do_refine_to_equitable();
+  unsigned int eqref_max_certificate_index;
+  bool eqref_worse_than_certificate;
+  //void eqref_update_hash(unsigned int i);
+  EqrefHash eqref_hash;
+
+  /* For debugging purposes only */
+  virtual bool is_equitable() {assert(0); return false; }
+
+  void print_permutation(FILE *, const unsigned int *perm);
+
+  unsigned int *first_path_labeling;
+  unsigned int *first_path_labeling_inv;
+  Orbit         first_path_orbits;
+  unsigned int *first_path_automorphism;
+
+  unsigned int *best_path_labeling;
+  unsigned int *best_path_labeling_inv;
+  Orbit         best_path_orbits;
+  unsigned int *best_path_automorphism;
+
+  void update_labeling(unsigned int * const lab);
+  void update_labeling_and_its_inverse(unsigned int * const lab,
+				       unsigned int * const lab_inv);
+  void update_orbit_information(Orbit &o, const unsigned int *perm);
+
+  void reset_permutation(unsigned int *perm);
+
+  /* Mainly for debugging purposes */
+  virtual bool is_automorphism(unsigned int * const perm);
+
+  std::vector<unsigned int> certificate_current_path;
+  std::vector<unsigned int> certificate_first_path;
+  std::vector<unsigned int> certificate_best_path;
+
+  //unsigned int *certificate;
+  unsigned int certificate_size;
+  unsigned int certificate_index;
+  virtual void initialize_certificate() = 0;
+
+  virtual void remove_duplicate_edges() = 0;
+  virtual void make_initial_equitable_partition() = 0;
+  virtual Cell *find_next_cell_to_be_splitted(Cell *cell) = 0;
+
+  void search(const bool canonical, Stats &stats);
+
+#ifdef PRINT_SEARCH_TREE_DOT
+  FILE *dotty_output;
+#endif
+
+public:
+  virtual unsigned int get_nof_vertices() = 0;
+
+  void find_automorphisms(Stats &stats);
+  const unsigned int *canonical_form(Stats &stats);
+};
+
+
+
+
+/*
+ * Undirected, vertex labeled graph
+ * Multiple edges between vertices are not allowed (i.e., will be ignored)
+ */
+class Graph : public AbstractGraph
+{
+  class Vertex {
+  public:
+    Vertex();
+    ~Vertex();
+    void add_edge(const unsigned int other_vertex);
+    void remove_duplicate_edges(bool * const);
+
+    unsigned int label;
+    unsigned int nof_edges;
+    std::vector<unsigned int> edges;
+  };
+  std::vector<Vertex> vertices;
+  void remove_duplicate_edges();
+
+  /*
+   * Partition independent invariants for this graph class
+   */
+  static unsigned int label_invariant(Graph *g, unsigned int v);
+  static unsigned int degree_invariant(Graph *g, unsigned int v);
+
+  bool refine_according_to_invariant(unsigned int (*inv)(Graph * g,
+							 unsigned int v));
+
+  /*
+   * Routines needed when refining the partition p into equitable
+   */
+  bool split_neighbourhood_of_unit_cell(Cell *);
+  void split_neighbourhood_of_cell(Cell * const);
+
+  /* For debugging purposes only */
+  bool is_equitable();
+
+  Cell *find_next_cell_to_be_splitted(Cell *cell);
+  /* Splitting heuristics */
+  unsigned int sh;
+  Cell *sh_first(Cell *cell);
+  Cell *sh_first_smallest(Cell *cell);
+  Cell *sh_first_largest(Cell *cell);
+  Cell *sh_first_max_neighbours(Cell *cell);
+  Cell *sh_first_smallest_max_neighbours(Cell *cell);
+  Cell *sh_first_largest_max_neighbours(Cell *cell);
+
+  void make_initial_equitable_partition();
+  void initialize_certificate();
+
+  bool is_automorphism(unsigned int * const perm);
+
+public:
+  Graph(const unsigned int nof_vertices = 0);
+  ~Graph();
+
+  static const unsigned int sh_f   = 0;
+  static const unsigned int sh_fs  = 1;
+  static const unsigned int sh_fl  = 2;
+  static const unsigned int sh_fm  = 3;
+  static const unsigned int sh_fsm = 4;
+  static const unsigned int sh_flm = 5;
+
+  static Graph *read_dimacs(FILE *);
+  static Graph *from_igraph(const igraph_t *graph);
+  void print_dimacs(FILE *);
+
+  void to_dot(FILE *fp);
+  void to_dot(const char *file_name);
+
+  unsigned int get_nof_vertices() {return vertices.size(); }
+  Graph *permute(const unsigned int *perm);
+  
+  unsigned int add_vertex(const unsigned int label = 1);
+  void add_edge(const unsigned int vertex1, const unsigned int vertex2);
+  void change_label(const unsigned int vertex, const unsigned int new_label);
+
+  void set_splitting_heuristics(unsigned int shs) {sh = shs; }
+};
+
+}
+
+#endif
diff --git a/src/bliss_heap.cc b/src/bliss_heap.cc
new file mode 100644
index 0000000..b2b571f
--- /dev/null
+++ b/src/bliss_heap.cc
@@ -0,0 +1,95 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include <cstdlib>
+#include <cstdio>
+#include <climits>
+#include "bliss_defs.hh"
+#include "bliss_heap.hh"
+
+using namespace std;
+
+namespace igraph {
+
+Heap::~Heap()
+{
+  if(array)
+    {
+      free(array);
+      array = 0;
+    }
+}
+
+void Heap::upheap(unsigned int index)
+{
+  assert(n >= 1);
+  assert(index >= 1 && index <= n);
+  const unsigned int v = array[index];
+  array[0] = UINT_MAX;
+  while(array[index/2] <= v)
+    {
+      array[index] = array[index/2];
+      index = index/2;
+    }
+  array[index] = v;
+}
+
+void Heap::downheap(unsigned int index)
+{
+  const unsigned int v = array[index];
+  while(index <= n/2)
+    {
+      unsigned int new_index = index + index;
+      if(new_index < n && array[new_index] < array[new_index+1])
+	new_index++;
+      if(v >= array[new_index])
+	break;
+      array[index] = array[new_index];
+      index = new_index;
+    }
+  array[index] = v;
+}
+
+void Heap::init(unsigned int size)
+{
+  array = (unsigned int*)malloc((size + 1) * sizeof(unsigned int));
+  n = 0;
+#if defined(CONSISTENCY_CHECKS)
+  assert(size > 0);
+  N = size;
+#endif
+}
+
+void Heap::insert(unsigned int v)
+{
+  DEBUG_ASSERT(n < N);
+  array[++n] = v;
+  upheap(n);
+}
+
+unsigned int Heap::remove()
+{
+  DEBUG_ASSERT(n >= 1 && n <= N);
+  const unsigned int v = array[1];
+  array[1] = array[n--];
+  downheap(1);
+  return v;
+}
+
+}
diff --git a/src/bliss_heap.hh b/src/bliss_heap.hh
new file mode 100644
index 0000000..a6954d6
--- /dev/null
+++ b/src/bliss_heap.hh
@@ -0,0 +1,47 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_HEAP_HH
+#define BLISS_HEAP_HH
+
+namespace igraph {
+
+class Heap
+{
+#if defined(CONSISTENCY_CHECKS)
+  unsigned int N;
+#endif
+  unsigned int n;
+  unsigned int *array;
+  void upheap(unsigned int k);
+  void downheap(unsigned int k);
+public:
+  Heap() {array = 0; n = 0; }
+  ~Heap();
+  void init(unsigned int size);
+
+  bool is_empty() const {return(n==0); }
+  void clear() {n = 0;}
+  void insert(unsigned int v);
+  unsigned int remove();
+};
+
+}
+
+#endif
diff --git a/src/bliss_kqueue.hh b/src/bliss_kqueue.hh
new file mode 100644
index 0000000..eabf856
--- /dev/null
+++ b/src/bliss_kqueue.hh
@@ -0,0 +1,144 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_KQUEUE_HH
+#define BLISS_KQUEUE_HH
+
+#include "bliss_defs.hh"
+#include <cstdlib>		// malloc
+
+namespace igraph {
+
+/* 
+ * A queue with fixed capacity
+ */
+template <class Type>
+class KQueue
+{
+public:
+  KQueue();
+  ~KQueue();
+  void init(const unsigned int k);
+  
+  bool is_empty() const;
+  unsigned int size() const;
+  unsigned int capacity() const;
+  void clear();
+
+  Type front() const;
+  Type pop_front();
+  void push_front(Type e);
+  Type pop_back();
+  void push_back(Type e);
+private:
+  Type *entries, *end;
+  Type *head, *tail;
+};
+
+template <class Type>
+KQueue<Type>::KQueue()
+{
+  entries = 0;
+  end = 0;
+  head = 0;
+  tail = 0;
+}
+
+template <class Type>
+KQueue<Type>::~KQueue()
+{
+  if(entries)
+    free(entries);
+}
+
+template <class Type>
+void KQueue<Type>::init(const unsigned int k)
+{
+  assert(k > 0);
+  if(entries)
+    free(entries);
+  entries = (Type*)malloc((k + 1) * sizeof(Type));
+  end = entries + k + 1;
+  head = entries;
+  tail = head;
+}
+
+template <class Type>
+void KQueue<Type>::clear()
+{
+  head = entries;
+  tail = head;
+}
+
+template <class Type>
+bool KQueue<Type>::is_empty() const
+{
+  return(head == tail);
+}
+
+template <class Type>
+unsigned int KQueue<Type>::size() const
+{
+  if(tail >= head)
+    return(tail - head);
+  return((end - head) + (tail - entries));
+}
+
+template <class Type>
+Type KQueue<Type>::front() const
+{
+  DEBUG_ASSERT(head != tail);
+  return *head;
+}
+
+template <class Type>
+Type KQueue<Type>::pop_front()
+{
+  DEBUG_ASSERT(head != tail);
+  Type *old_head = head;
+  head++;
+  if(head == end)
+    head = entries;
+  return *old_head;
+}
+
+template <class Type>
+void KQueue<Type>::push_front(Type e)
+{
+  if(head == entries)
+    head = end - 1;
+  else
+    head--;
+  DEBUG_ASSERT(head != tail);
+  *head = e;
+}
+
+template <class Type>
+void KQueue<Type>::push_back(Type e)
+{
+  *tail = e;
+  tail++;
+  if(tail == end)
+    tail = entries;
+  DEBUG_ASSERT(head != tail);
+}
+
+}
+
+#endif
diff --git a/src/bliss_kstack.hh b/src/bliss_kstack.hh
new file mode 100644
index 0000000..b2eb251
--- /dev/null
+++ b/src/bliss_kstack.hh
@@ -0,0 +1,98 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_KSTACK_H
+#define BLISS_KSTACK_H
+
+#include "bliss_defs.hh"
+#include <cstdlib>		// malloc
+
+namespace igraph {
+
+/* 
+ * A stack with fixed capacity
+ */
+template <class Type>
+class KStack {
+public:
+  KStack();
+  KStack(int k);
+  ~KStack();
+  void init(int k);
+
+  bool is_empty() const {return(cursor == entries); }
+  Type top() const {DEBUG_ASSERT(cursor > entries); return *cursor; }
+  Type pop() {
+    DEBUG_ASSERT(cursor > entries);
+    Type obj = *cursor;
+    cursor--;
+    return obj;
+  }
+  void push(Type obj) {
+    DEBUG_ASSERT(cursor < entries + kapacity);
+    cursor++;
+    *cursor = obj;
+  }
+  void clean() {cursor = entries; }
+  unsigned int size() const {return(cursor - entries);
+  }
+  Type element_at(unsigned int i) {
+    assert(i < size());
+    return entries[i+1];
+  }
+  int capacity() {return kapacity; }
+private:
+  int kapacity;
+  Type *entries;
+  Type *cursor;
+};
+
+template <class Type>
+KStack<Type>::KStack() {
+  kapacity = 0;
+  entries = 0;
+  cursor = 0;
+}
+
+template <class Type>
+KStack<Type>::KStack(int k) {
+  assert(k > 0);
+  kapacity = k;
+  entries = (Type*)malloc((k+1) * sizeof(Type));
+  cursor = entries;
+}
+
+template <class Type>
+void KStack<Type>::init(int k) {
+  assert(k > 0);
+  if(entries)
+    free(entries);
+  kapacity = k;
+  entries = (Type*)malloc((k+1) * sizeof(Type));
+  cursor = entries;
+}
+
+template <class Type>
+KStack<Type>::~KStack() {
+  free(entries);
+}
+
+}
+
+#endif
diff --git a/src/bliss_orbit.cc b/src/bliss_orbit.cc
new file mode 100644
index 0000000..1c19459
--- /dev/null
+++ b/src/bliss_orbit.cc
@@ -0,0 +1,153 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include <cstdlib>
+#include <cassert>
+#include "bliss_defs.hh"
+#include "bliss_orbit.hh"
+
+using namespace std;
+
+namespace igraph {
+
+Orbit::Orbit()
+{
+  orbits = 0;
+  in_orbit = 0;
+  nof_elements = 0;
+}
+
+
+Orbit::~Orbit()
+{
+  if(orbits)
+    {
+      free(orbits);
+      orbits = 0;
+    }
+  if(in_orbit)
+    {
+      free(in_orbit);
+      in_orbit = 0;
+    }
+  nof_elements = 0;
+}
+
+
+void Orbit::init(const unsigned int n)
+{
+  assert(n > 0);
+  if(orbits) free(orbits);
+  orbits = (OrbitEntry*)malloc(n * sizeof(OrbitEntry));
+  if(in_orbit) free(in_orbit);
+  in_orbit = (OrbitEntry**)malloc(n * sizeof(OrbitEntry*));
+  nof_elements = n;
+
+  reset();
+}
+
+
+void Orbit::reset()
+{
+  assert(orbits);
+  assert(in_orbit);
+
+  for(unsigned int i = 0; i < nof_elements; i++)
+    {
+      orbits[i].element = i;
+      orbits[i].next = 0;
+      orbits[i].size = 1;
+      in_orbit[i] = &orbits[i];
+    }
+  _nof_orbits = nof_elements;
+}
+
+
+void Orbit::merge_orbits(OrbitEntry *orbit1, OrbitEntry *orbit2)
+{
+  DEBUG_ASSERT((orbit1 == orbit2) == (orbit1->element == orbit2->element));
+  DEBUG_ASSERT(orbit1->element < nof_elements);
+  DEBUG_ASSERT(orbit2->element < nof_elements);
+
+  if(orbit1 != orbit2)
+    {
+      _nof_orbits--;
+      /* Only update the elements in the smaller orbit */
+      if(orbit1->size > orbit2->size)
+	{
+	  OrbitEntry * const temp = orbit2;
+	  orbit2 = orbit1;
+	  orbit1 = temp;
+	}
+      /* Link the elements of orbit1 to the almost beginning of orbit2 */
+      OrbitEntry *e = orbit1;
+      while(e->next)
+	{
+	  in_orbit[e->element] = orbit2;
+	  e = e->next;
+	}
+      in_orbit[e->element] = orbit2;
+      e->next = orbit2->next;
+      orbit2->next = orbit1;
+      /* Keep the minimal orbit representative in the beginning */
+      if(orbit1->element < orbit2->element)
+	{
+	  const unsigned int temp = orbit1->element;
+	  orbit1->element = orbit2->element;
+	  orbit2->element = temp;
+	}
+      orbit2->size += orbit1->size;
+    }
+}
+
+
+void Orbit::merge_orbits(unsigned int e1, unsigned int e2)
+{
+  DEBUG_ASSERT(e1 < nof_elements);
+  DEBUG_ASSERT(e2 < nof_elements);
+
+  merge_orbits(in_orbit[e1], in_orbit[e2]);
+}
+
+
+bool Orbit::is_minimal_representative(unsigned int element)
+{
+  return(get_minimal_representative(element) == element);
+}
+
+
+unsigned int Orbit::get_minimal_representative(unsigned int element)
+{
+  DEBUG_ASSERT(element < nof_elements);
+
+  OrbitEntry * const orbit = in_orbit[element];
+
+  DEBUG_ASSERT(orbit->element <= element);
+  return(orbit->element);
+}
+
+
+unsigned int Orbit::orbit_size(unsigned int element)
+{
+  DEBUG_ASSERT(element < nof_elements);
+  
+  return(in_orbit[element]->size);
+}
+
+}
diff --git a/src/bliss_orbit.hh b/src/bliss_orbit.hh
new file mode 100644
index 0000000..6f5a3c4
--- /dev/null
+++ b/src/bliss_orbit.hh
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_ORBIT_HH
+#define BLISS_ORBIT_HH
+
+namespace igraph {
+
+class Orbit
+{
+protected:
+  class OrbitEntry {
+  public:
+    unsigned int element;
+    OrbitEntry *next;
+    unsigned int size;
+  };
+  OrbitEntry *orbits;
+  OrbitEntry **in_orbit;
+  unsigned int nof_elements;
+  unsigned int _nof_orbits;
+  void merge_orbits(OrbitEntry *o1, OrbitEntry *o2);
+public:
+  Orbit();
+  ~Orbit();
+  void init(const unsigned int n);
+  void reset();
+  void merge_orbits(unsigned int e1, unsigned int e2);
+  bool is_minimal_representative(unsigned int e);
+  unsigned int get_minimal_representative(unsigned int e);
+  unsigned int orbit_size(unsigned int e);
+  unsigned int nof_orbits() const {return _nof_orbits; }
+};
+
+}
+
+#endif
diff --git a/src/bliss_partition.cc b/src/bliss_partition.cc
new file mode 100644
index 0000000..cdea6ce
--- /dev/null
+++ b/src/bliss_partition.cc
@@ -0,0 +1,917 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include <cassert>
+#include <vector>
+#include <list>
+#include "bliss_graph.hh"
+#include "bliss_partition.hh"
+
+using namespace std;
+
+namespace igraph {
+
+static const bool should_not_happen = false;
+
+Partition::Partition()
+{
+  elements = 0;
+  in_pos = 0;
+  invariant_values = 0;
+  cells = 0;
+  free_cells = 0;
+  element_to_cell_map = 0;
+  graph = 0;
+}
+
+Partition::~Partition()
+{
+  if(elements) {
+    free(elements); elements = 0; }
+  if(cells) {
+    free(cells); cells = 0; }
+  if(element_to_cell_map) {
+    free(element_to_cell_map); element_to_cell_map = 0; }
+  if(in_pos) {
+    free(in_pos); in_pos = 0; }
+  if(invariant_values) {
+    free(invariant_values); invariant_values = 0; }
+}
+
+void Partition::init(const unsigned int N)
+{
+  assert(N > 0);
+
+  if(elements)
+    free(elements);
+  elements = (unsigned int*)malloc(N * sizeof(unsigned int));
+  for(unsigned int i = 0; i < N; i++)
+    elements[i] = i;
+
+  if(in_pos)
+    free(in_pos);
+  in_pos = (unsigned int**)malloc(N * sizeof(unsigned int*));
+  for(unsigned int i = 0; i < N; i++)
+    in_pos[i] = elements + i;
+
+  if(invariant_values)
+    free(invariant_values);
+  invariant_values = (unsigned int*)malloc(N * sizeof(unsigned int));
+  for(unsigned int i = 0; i < N; i++)
+    invariant_values[i] = 0;
+
+  if(cells)
+    free(cells);
+  cells = (Cell*)malloc(N * sizeof(Cell));
+
+  cells[0].first = 0;
+  cells[0].length = N;
+  cells[0].max_ival = 0;
+  cells[0].max_ival_count = 0;
+  cells[0].in_splitting_queue = false;
+  cells[0].in_neighbour_heap = false;
+  cells[0].next = 0;
+  cells[0].prev_next_ptr = &first_cell;
+  cells[0].next_nonsingleton = 0;
+  cells[0].prev_nonsingleton = 0;
+  cells[0].split_level = 0;
+  first_cell = &cells[0];
+  if(N == 1)
+    first_nonsingleton_cell = 0;
+  else
+    first_nonsingleton_cell = &cells[0];
+
+  for(unsigned int i = 1; i < N; i++)
+    {
+      cells[i].first = 0;
+      cells[i].length = 0;
+      cells[i].max_ival = 0;
+      cells[i].max_ival_count = 0;
+      cells[i].in_splitting_queue = false;
+      cells[i].in_neighbour_heap = false;
+      cells[i].next = (i < N-1)?&cells[i+1]:0;
+      cells[i].prev_next_ptr = (i == 1)?&free_cells:&(cells[i-1].next);
+      cells[i].next_nonsingleton = 0;
+      cells[i].prev_nonsingleton = 0;
+    }
+  if(N > 1)
+    free_cells = &cells[1];
+  else
+    free_cells = 0;
+
+  if(element_to_cell_map)
+    free(element_to_cell_map);
+  element_to_cell_map = (Cell **)malloc(N * sizeof(Cell *));
+  for(unsigned int i = 0; i < N; i++)
+    element_to_cell_map[i] = first_cell;
+
+  splitting_queue.init(N);
+  refinement_stack.init(N);
+  level = 0;
+}
+
+/*
+ * For debugging purposes only.
+ * Checks that the ordered list of nonsingleton cells is consistent.
+ */
+void Partition::consistency_check()
+{
+#ifdef DEBUG
+  for(const Cell *cell = first_cell; cell; cell = cell->next)
+    {
+      assert(cell->prev_next_ptr && *(cell->prev_next_ptr) == cell);
+    }
+  const bool do_print = false;
+  if(do_print)
+    {
+      fprintf(stderr, "\nRef stack: ");
+      for(unsigned int j = 0; j < refinement_stack.size(); j++)
+	{
+	  const RefInfo i = refinement_stack.element_at(j);
+	  fprintf(stderr, "f%u,%d,%d ",
+	      i.split_cell_first,
+		  i.prev_nonsingleton_first,
+		  i.next_nonsingleton_first);
+	}
+      fprintf(stderr, "\n");
+      for(const Cell *cell = first_nonsingleton_cell; cell;
+	  cell = cell->next_nonsingleton)
+	{
+	  fprintf(stderr, "%u:%u->", cell->first, cell->length);
+	  if(cell->next_nonsingleton)
+	    assert(cell->first < cell->next_nonsingleton->first);
+	}
+      fprintf(stderr, "\n");
+    }
+  const Cell *next_nonsingleton = first_nonsingleton_cell;
+  const Cell *prev_nonsingleton = 0;
+  if(next_nonsingleton)
+    assert(next_nonsingleton->prev_nonsingleton == 0);
+  for(const Cell *cell = first_cell; cell; cell = cell->next)
+    {
+      assert(!cell->next || cell->next->prev_next_ptr == &(cell->next));
+      if(cell->length > 1)
+	{
+	  if(do_print)
+	    fprintf(stderr, "%u:%u=>", cell->first, cell->length);
+	  assert(cell == next_nonsingleton); 
+	  assert(cell->prev_nonsingleton == prev_nonsingleton);
+	  next_nonsingleton = cell->next_nonsingleton;
+	  prev_nonsingleton = cell;
+	  if(next_nonsingleton)
+	    assert(next_nonsingleton->first > cell->first);
+	}
+      else
+	{
+	  assert(cell != next_nonsingleton);
+	  assert(cell->next_nonsingleton == 0);
+	  assert(cell->prev_nonsingleton == 0);
+	}
+    }
+  assert(next_nonsingleton == 0);
+  if(do_print)
+    fprintf(stderr, "\n");
+#endif
+}
+
+Cell *Partition::aux_split_in_two(Cell * const cell,
+				  const unsigned int first_half_size)
+{
+  RefInfo i;
+
+  DEBUG_ASSERT(first_half_size > 0);
+  DEBUG_ASSERT(first_half_size < cell->length);
+
+  /* (Pseudo)allocate new cell */
+  Cell * const new_cell = free_cells;
+  DEBUG_ASSERT(new_cell);
+  free_cells = new_cell->next;
+  /* Update new cell parameters */
+  new_cell->first = cell->first + first_half_size;
+  new_cell->length = cell->length - first_half_size;
+  new_cell->next = cell->next;
+  if(new_cell->next)
+    new_cell->next->prev_next_ptr = &(new_cell->next);
+  new_cell->prev_next_ptr = &(cell->next);
+  new_cell->split_level = cell->split_level;
+  /* Update old, splitted cell parameters */
+  cell->length = first_half_size;
+  cell->next = new_cell;
+  cell->split_level = level;
+  
+  /* Add cell in refinement_stack for backtracking */
+  i.split_cell_first = cell->first;
+  if(cell->prev_nonsingleton)
+    i.prev_nonsingleton_first = cell->prev_nonsingleton->first;
+  else
+    i.prev_nonsingleton_first = -1;
+  if(cell->next_nonsingleton)
+    i.next_nonsingleton_first = cell->next_nonsingleton->first;
+  else
+    i.next_nonsingleton_first = -1;
+  refinement_stack.push(i);
+
+  /* Modify nonsingleton cell list */
+  if(new_cell->length > 1)
+    {
+      new_cell->prev_nonsingleton = cell;
+      new_cell->next_nonsingleton = cell->next_nonsingleton;
+      if(new_cell->next_nonsingleton)
+	new_cell->next_nonsingleton->prev_nonsingleton = new_cell;
+      cell->next_nonsingleton = new_cell;
+    }
+  else
+    {
+      new_cell->next_nonsingleton = 0;
+      new_cell->prev_nonsingleton = 0;
+    }
+
+  if(cell->length == 1)
+    {
+      if(cell->prev_nonsingleton)
+	cell->prev_nonsingleton->next_nonsingleton = cell->next_nonsingleton;
+      else
+	first_nonsingleton_cell = cell->next_nonsingleton;
+      if(cell->next_nonsingleton)
+	cell->next_nonsingleton->prev_nonsingleton = cell->prev_nonsingleton;
+      cell->next_nonsingleton = 0;
+      cell->prev_nonsingleton = 0;
+    }
+
+  return new_cell;
+} 
+
+void Partition::add_in_splitting_queue(Cell * const cell)
+{
+  static const unsigned int smallish_cell_threshold = 1;
+  assert(!cell->in_splitting_queue);
+  cell->in_splitting_queue = true;
+  if(cell->length <= smallish_cell_threshold)
+    splitting_queue.push_front(cell);
+  else
+    splitting_queue.push_back(cell);    
+}
+
+
+void Partition::clear_splitting_queue()
+{
+  while(!splitting_queue.is_empty())
+    {
+      Cell * const cell = splitting_queue.pop_front();
+      assert(cell->in_splitting_queue);
+      cell->in_splitting_queue = false;
+    }
+}
+
+
+
+/*
+ * Assumes that the invariant values are NOT the same
+ * and that the cell contains more than one element
+ */
+Cell *Partition::sort_and_split_cell1(Cell *cell)
+{
+#if defined(EXPENSIVE_CONSISTENCY_CHECKS)
+  assert(cell->length > 1);
+  assert(cell->first + cell->length <= graph->get_nof_vertices());
+  bool found0 = false, found1 = false;
+  for(unsigned int i = 0; i < cell->length; i++)
+    {
+      if(invariant_values[elements[cell->first + i]] == 0)
+	found0 = true;
+      else if(invariant_values[elements[cell->first + i]] == 1)
+	found1 = true;
+      else
+	assert(should_not_happen);
+    }
+  assert(found0);
+  assert(found1);
+#endif
+
+  consistency_check();
+
+  /* Allocate new cell */
+  Cell *new_cell = free_cells;
+  DEBUG_ASSERT(new_cell);
+  free_cells = new_cell->next;
+  if(free_cells) free_cells->prev_next_ptr = &(free_cells);
+
+  /* Sort vertices in the cell according to the invariant values */
+  unsigned int *ep0 = elements + cell->first;
+  unsigned int *ep1 = ep0 + cell->length;
+  while(ep1 > ep0)
+    {
+      const unsigned int element = *ep0;
+      const unsigned int ival = invariant_values[element];
+      invariant_values[element] = 0;
+      DEBUG_ASSERT(ival <= 1);
+      DEBUG_ASSERT(element_to_cell_map[element] == cell);
+      DEBUG_ASSERT(in_pos[element] == ep0);
+      if(ival == 0)
+	{
+	  ep0++;
+	}
+      else
+	{
+	  ep1--;
+	  *ep0 = *ep1;
+	  *ep1 = element;
+	  element_to_cell_map[element] = new_cell;
+	  in_pos[element] = ep1;
+	  in_pos[*ep0] = ep0;
+	}
+    }
+
+  DEBUG_ASSERT(ep1 != elements + cell->first);
+  DEBUG_ASSERT(ep0 != elements + cell->first + cell->length);
+
+  /* Update new cell parameters */
+  new_cell->first = ep1 - elements;
+  new_cell->length = cell->length - (new_cell->first - cell->first);
+  new_cell->next = cell->next;
+  if(new_cell->next)
+    new_cell->next->prev_next_ptr = &(new_cell->next);
+  new_cell->prev_next_ptr = &(cell->next);
+  new_cell->split_level = cell->split_level;
+  /* Update old, splitted cell parameters */
+  cell->length = new_cell->first - cell->first;
+  cell->next = new_cell;
+  cell->split_level = level;
+
+  /* Add cell in refinement stack for backtracking */
+  {
+    RefInfo i;
+    i.split_cell_first = cell->first;
+    if(cell->prev_nonsingleton)
+      i.prev_nonsingleton_first = cell->prev_nonsingleton->first;
+    else
+      i.prev_nonsingleton_first = -1;
+    if(cell->next_nonsingleton)
+      i.next_nonsingleton_first = cell->next_nonsingleton->first;
+    else
+      i.next_nonsingleton_first = -1;
+    /* Modify nonsingleton cell list */
+    if(new_cell->length > 1)
+      {
+	new_cell->prev_nonsingleton = cell;
+	new_cell->next_nonsingleton = cell->next_nonsingleton;
+	if(new_cell->next_nonsingleton)
+	  new_cell->next_nonsingleton->prev_nonsingleton = new_cell;
+	cell->next_nonsingleton = new_cell;
+      }
+    else
+      {
+	new_cell->next_nonsingleton = 0;
+	new_cell->prev_nonsingleton = 0;
+      }
+    if(cell->length == 1)
+      {
+	if(cell->prev_nonsingleton)
+	  cell->prev_nonsingleton->next_nonsingleton = cell->next_nonsingleton;
+	else
+	  first_nonsingleton_cell = cell->next_nonsingleton;
+	if(cell->next_nonsingleton)
+	  cell->next_nonsingleton->prev_nonsingleton = cell->prev_nonsingleton;
+	cell->next_nonsingleton = 0;
+	cell->prev_nonsingleton = 0;
+      }
+    refinement_stack.push(i);
+  }
+
+
+  /* Add cells in splitting queue */
+  DEBUG_ASSERT(!new_cell->in_splitting_queue);
+  if(cell->in_splitting_queue) {
+    /* Both cells must be included in splitting_queue in order to have
+       refinement to equitable partition */
+    add_in_splitting_queue(new_cell);
+  } else {
+    Cell *min_cell, *max_cell;
+    if(cell->length <= new_cell->length) {
+      min_cell = cell;
+      max_cell = new_cell;
+    } else {
+      min_cell = new_cell;
+      max_cell = cell;
+    }
+    /* Put the smaller cell in splitting_queue */
+    add_in_splitting_queue(min_cell);
+    if(max_cell->length == 1) {
+      /* Put the "larger" cell also in splitting_queue */
+      add_in_splitting_queue(max_cell);
+    }
+  }
+
+  consistency_check();
+
+  return new_cell;
+}
+
+
+
+/*
+ * Tables and a subroutine for distribution count sorting
+ */
+static IGRAPH_THREAD_LOCAL unsigned int count[256] = {
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+static IGRAPH_THREAD_LOCAL unsigned int start[256];
+
+/*
+ * Build start array so that start[0] = 0 and start[i+1] = start[i] + count[i]
+ */
+static void cumulate_count(const unsigned int max) 
+{
+  DEBUG_ASSERT(max <= 255);
+  unsigned int *count_p = count;
+  unsigned int *start_p = start;
+  unsigned int sum = 0;
+  for(unsigned int i = max+1; i > 0; i--)
+    {
+      *start_p = sum;
+      start_p++;
+      sum += *count_p;
+      count_p++;
+    }
+}
+
+
+/*
+ * Distribution count sorting of cells with invariant values less than 256 
+ */
+Cell *Partition::sort_and_split_cell255(Cell * const cell,
+					const unsigned int max_ival)
+{
+  //DEBUG_ASSERT(cell->first + cell->length <= graph->vertices.size());
+
+  DEBUG_ASSERT(max_ival <= 255);
+
+  if(cell->length == 1)
+    {
+      /* Reset invariant value */
+      invariant_values[elements[cell->first]] = 0;
+      return cell;
+    }
+  
+#ifdef CONSISTENCY_CHECKS
+  for(unsigned int i = 0; i < 256; i++)
+    assert(count[i] == 0);
+#endif
+
+  /*
+   * Compute the distribution of invariant values to the count array
+   */
+  {
+    const unsigned int *ep = elements + cell->first;
+    DEBUG_ASSERT(element_to_cell_map[*ep] == cell);
+    const unsigned int ival = invariant_values[*ep];
+    DEBUG_ASSERT(ival <= 255);
+    count[ival]++;
+    ep++;
+#ifdef CONSISTENCY_CHECKS
+    bool equal_invariant_values = true;
+#endif
+    for(unsigned int i = cell->length - 1; i > 0; i--)
+      {
+	DEBUG_ASSERT(element_to_cell_map[*ep] == cell);
+	const unsigned int ival2 = invariant_values[*ep];
+	DEBUG_ASSERT(ival2 <= 255);
+	DEBUG_ASSERT(ival2 <= max_ival);
+	count[ival2]++;
+#ifdef CONSISTENCY_CHECKS
+	if(ival2 != ival) {
+	  equal_invariant_values = false;
+	}
+#endif
+	ep++;
+      }
+#ifdef CONSISTENCY_CHECKS
+    DEBUG_ASSERT(!equal_invariant_values);
+    if(equal_invariant_values) {
+      DEBUG_ASSERT(count[ival] == cell->length);
+      count[ival] = 0;
+      clear_ivs(cell);
+      return cell;
+    }
+#endif
+  }
+
+  /* Build start array */
+  cumulate_count(max_ival);
+
+  //DEBUG_ASSERT(start[255] + count[255] == cell->length);
+  DEBUG_ASSERT(start[max_ival] + count[max_ival] == cell->length);
+
+  /* Do the sorting */
+  for(unsigned int i = 0; i <= max_ival; i++)
+    {
+      unsigned int *ep = elements + cell->first + start[i];
+      for(unsigned int j = count[i]; j > 0; j--)
+	{
+	  while(true)
+	    {
+	      const unsigned int element = *ep;
+	      const unsigned int ival = invariant_values[element];
+	      if(ival == i)
+		break;
+	      DEBUG_ASSERT(ival > i);
+	      DEBUG_ASSERT(count[ival] > 0);
+	      *ep = elements[cell->first + start[ival]];
+	      elements[cell->first + start[ival]] = element;
+	      start[ival]++;
+	      count[ival]--;
+	    }
+	  ep++;
+	}
+      count[i] = 0;
+    }
+
+#if defined(CONSISTENCY_CHECKS)
+  for(unsigned int i = 0; i < 256; i++)
+    assert(count[i] == 0);
+#endif
+
+#if defined(VERBOSEDEBUG)
+  {
+    const unsigned int *ep = elements + cell->first;
+    fprintf(stderr, "\n");
+    for(unsigned int i = cell->length; i > 0; i--, ep++)
+      fprintf(stderr, "%u ", invariant_values[*ep]);
+    fprintf(stderr, "\n");
+  }
+#endif
+
+  /* split cell */
+  Cell * const cell2 = split_cell(cell);
+  DEBUG_ASSERT(cell2 != cell);
+  return cell2;
+}
+
+
+/*
+ * Sort the elements in a cell according to their invariant values
+ * The invariant values are not cleared
+ * Warning: the in_pos array is left in incorrect state
+ */
+bool Partition::shellsort_cell(Cell *cell)
+{
+  unsigned int h;
+  unsigned int *ep;
+
+  //DEBUG_ASSERT(cell->first + cell->length <= graph->vertices.size());
+
+  if(cell->length == 1)
+    return false;
+
+  /* Check whether all the elements have the same invariant value */
+  bool equal_invariant_values = true;
+  {
+    ep = elements + cell->first;
+    const unsigned int ival = invariant_values[*ep];
+    DEBUG_ASSERT(element_to_cell_map[*ep] == cell);
+    ep++;
+    for(unsigned int i = cell->length - 1; i > 0; i--)
+      {
+	DEBUG_ASSERT(element_to_cell_map[*ep] == cell);
+	if(invariant_values[*ep] != ival) {
+	  equal_invariant_values = false;
+	  break;
+	}
+	ep++;
+      }
+  }
+  if(equal_invariant_values)
+    return false;
+
+  ep = elements + cell->first;
+
+  for(h = 1; h <= cell->length/9; h = 3*h + 1)
+    ;
+  for( ; h > 0; h = h/3) {
+    for(unsigned int i = h; i < cell->length; i++) {
+      const unsigned int element = ep[i];
+      const unsigned int ival = invariant_values[element];
+      unsigned int j = i;
+      while(j >= h && invariant_values[ep[j-h]] > ival) {
+        ep[j] = ep[j-h];
+        j -= h;
+      }
+      ep[j] = element;
+    }
+  }
+  return true;
+}
+
+
+void Partition::clear_ivs(Cell * const cell)
+{
+  unsigned int *ep = elements + cell->first;
+  for(unsigned int i = cell->length; i > 0; i--, ep++)
+    invariant_values[*ep] = 0;
+}
+
+
+/*
+ * Assumes that the elements in the cell are sorted according to their
+ * invariant values
+ */
+Cell *Partition::split_cell(Cell * const original_cell)
+{
+  Cell *cell = original_cell;
+  const bool original_cell_was_in_splitting_queue =
+    original_cell->in_splitting_queue;
+  Cell *largest_new_cell = 0;
+
+  consistency_check();
+
+  while(true) 
+    {
+      unsigned int *ep = elements + cell->first;
+      const unsigned int * const lp = ep + cell->length;
+      const unsigned int ival = invariant_values[*ep];
+      invariant_values[*ep] = 0;
+      element_to_cell_map[*ep] = cell;
+      in_pos[*ep] = ep;
+      ep++;
+      while(ep < lp)
+	{
+	  const unsigned int e = *ep;
+	  if(invariant_values[e] != ival)
+	    break;
+	  invariant_values[e] = 0;
+	  in_pos[e] = ep;
+	  ep++;
+	  element_to_cell_map[e] = cell;
+	}
+      if(ep == lp)
+	break;
+      
+      Cell * const new_cell = aux_split_in_two(cell, (ep - elements) - cell->first);
+      
+      if(graph->in_search)
+	{
+	  graph->eqref_hash.update(new_cell->first);
+	  graph->eqref_hash.update(new_cell->length);
+	  graph->eqref_hash.update(ival);
+	}
+      
+      /* Add cells in splitting_queue */
+      assert(!new_cell->in_splitting_queue);
+      if(original_cell_was_in_splitting_queue)
+	{
+	  /* In this case, all new cells are inserted in splitting_queue */
+	  assert(cell->in_splitting_queue);
+	  add_in_splitting_queue(new_cell);
+	}
+      else
+	{
+	  /* Otherwise, we can omit one new cell from splitting_queue */
+	  assert(!cell->in_splitting_queue);
+	  if(largest_new_cell == 0) {
+	    largest_new_cell = cell;
+	  } else {
+	    assert(!largest_new_cell->in_splitting_queue);
+	    if(cell->length > largest_new_cell->length) {
+	      add_in_splitting_queue(largest_new_cell);
+	      largest_new_cell = cell;
+	    } else {
+	      add_in_splitting_queue(cell);
+	    }
+	  }
+	}
+      /* Process the rest of the cell */
+      cell = new_cell;
+    }
+
+  consistency_check();
+  
+  if(original_cell == cell) {
+    /* All the elements in cell had the same invariant value */
+    return cell;
+  }
+
+  /* Add cells in splitting_queue */
+  if(!original_cell_was_in_splitting_queue)
+    {
+      /* Also consider the last new cell */
+      assert(largest_new_cell);
+      if(cell->length > largest_new_cell->length)
+	{
+	  add_in_splitting_queue(largest_new_cell);
+	  largest_new_cell = cell;
+	}
+      else
+	{
+	  add_in_splitting_queue(cell);
+	}
+      if(largest_new_cell->length == 1)
+	{
+	  /* Needed in certificate computation */
+	  add_in_splitting_queue(largest_new_cell);
+	}
+    }
+
+  return cell;
+}
+
+
+Cell *Partition::zplit_cell(Cell * const cell, const bool max_ival_info_ok)
+{
+  assert(cell);
+
+  Cell *last_new_cell = cell;
+
+  if(!max_ival_info_ok)
+    {
+      /* Compute max_ival info */
+      assert(cell->max_ival == 0);
+      assert(cell->max_ival_count == 0);
+      unsigned int *ep = elements + cell->first;
+      for(unsigned int i = cell->length; i > 0; i--, ep++)
+	{
+	  const unsigned int ival = invariant_values[*ep];
+	  if(ival > cell->max_ival)
+	    {
+	      cell->max_ival = ival;
+	      cell->max_ival_count = 1;
+	    }
+	  else if(ival == cell->max_ival)
+	    {
+	      cell->max_ival_count++;
+	    }
+	}
+    }
+
+#ifdef CONSISTENCY_CHECKS
+  /* Verify max_ival info */
+  {
+    unsigned int max_ival = 0;
+    unsigned int max_ival_count = 0;
+    unsigned int *ep = elements + cell->first;
+    for(unsigned int i = cell->length; i > 0; i--, ep++)
+      {
+	const unsigned int ival = invariant_values[*ep];
+	if(ival > max_ival)
+	  {
+	    max_ival = ival;
+	    max_ival_count = 1;
+	  }
+	else if(ival == max_ival)
+	  {
+	    max_ival_count++;
+	  }
+      }
+    assert(max_ival == cell->max_ival);
+    assert(max_ival_count == cell->max_ival_count);
+  }
+#endif
+
+  /* max_ival info has been computed */
+
+  if(cell->max_ival_count == cell->length)
+    {
+      /* All invariant values are the same */
+      if(cell->max_ival > 0)
+	clear_ivs(cell);
+      goto done;
+    }
+
+  /* All invariant values are not the same */
+  if(cell->max_ival == 1)
+    {
+      /* Specialized splitting for cells with binary invariant values */
+      last_new_cell = sort_and_split_cell1(cell);
+      goto done;
+    }
+  if(cell->max_ival < 256)
+    {
+      /* Specialized splitting for cells with invariant values < 256 */
+      last_new_cell = sort_and_split_cell255(cell, cell->max_ival);
+      goto done;
+    }
+  {
+    /* Generic sorting and splitting */
+    const bool sorted = shellsort_cell(cell);
+    assert(sorted);
+    last_new_cell = split_cell(cell);
+    goto done;
+  }
+
+ done:
+  cell->max_ival = 0;
+  cell->max_ival_count = 0;
+  return last_new_cell;
+}
+
+
+
+
+
+
+void Partition::unrefine(unsigned int dest_split_level,
+			 unsigned int dest_refinement_stack_size)
+{
+  assert(refinement_stack.size() >= dest_refinement_stack_size);
+  while(refinement_stack.size() > dest_refinement_stack_size)
+    {
+      RefInfo i = refinement_stack.pop();
+      const unsigned int first = i.split_cell_first;
+      //const unsigned int first = refinement_stack.pop();
+      Cell *cell = element_to_cell_map[elements[first]];
+
+      if(cell->first != first) {
+	assert(cell->split_level <= dest_split_level);
+	goto done;
+      }
+      if(cell->split_level <= dest_split_level) {
+	goto done;
+      }
+
+      {
+	const unsigned int new_first = cell->first;
+	do
+	  {
+	    Cell * const next_cell = cell->next;
+	    assert(next_cell);
+	    /* (Pseudo)free cell */
+	    cell->first = 0;
+	    cell->length = 0;
+	    cell->next->prev_next_ptr = cell->prev_next_ptr;
+	    *(cell->prev_next_ptr) = cell->next;
+	    cell->next = free_cells;
+	    if(cell->next)
+	      cell->next->prev_next_ptr = &(cell->next);
+	    cell->prev_next_ptr = &free_cells;
+	    free_cells = cell;
+	    
+	    cell = next_cell;
+	  }
+	while(cell->split_level > dest_split_level);
+	/* Update element_to_cell_map values of elements added in cell */
+	unsigned int *ep = elements + new_first;
+	unsigned int * const lp = elements + cell->first;
+	while(ep < lp) {
+	  element_to_cell_map[*ep] = cell;
+	  ep++;
+	}
+	/* Update cell parameters */
+	cell->length = (cell->first + cell->length) - new_first;
+	cell->first = new_first;
+      }
+
+    done:
+      if(i.prev_nonsingleton_first >= 0)
+	{
+	  Cell * const prev_cell = element_to_cell_map[elements[i.prev_nonsingleton_first]];
+	  DEBUG_ASSERT(prev_cell->length > 1);
+	  cell->prev_nonsingleton = prev_cell;
+	  prev_cell->next_nonsingleton = cell;
+	}
+      else
+	{
+	  //assert(cell->prev_nonsingleton == 0);
+	  cell->prev_nonsingleton = 0;
+	  first_nonsingleton_cell = cell;
+	}
+
+      if(i.next_nonsingleton_first >= 0)
+	{
+	  Cell * const next_cell = element_to_cell_map[elements[i.next_nonsingleton_first]];
+	  DEBUG_ASSERT(next_cell->length > 1);
+	  cell->next_nonsingleton = next_cell;
+	  next_cell->prev_nonsingleton = cell;
+	}
+      else
+	{
+	  //assert(cell->next_nonsingleton == 0);
+	  cell->next_nonsingleton = 0;
+	}
+    }
+
+  consistency_check();
+}
+
+}
diff --git a/src/bliss_partition.hh b/src/bliss_partition.hh
new file mode 100644
index 0000000..4059d8a
--- /dev/null
+++ b/src/bliss_partition.hh
@@ -0,0 +1,127 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_PARTITION_HH
+#define BLISS_PARTITION_HH
+
+namespace igraph {
+
+class Cell;
+class Partition;
+
+}
+
+#include <cstdlib>
+#include "bliss_kstack.hh"
+#include "bliss_kqueue.hh"
+#include "bliss_heap.hh"
+#include "bliss_orbit.hh"
+#include "bliss_graph.hh"
+
+namespace igraph {
+
+class Cell
+{
+public:
+  /* Index of the first element of the cell in the Partition::elements array */
+  unsigned int first;
+  unsigned int length;
+  unsigned int max_ival;
+  unsigned int max_ival_count;
+  bool in_neighbour_heap;
+  bool in_splitting_queue;
+  Cell *next;
+  Cell **prev_next_ptr;
+  Cell *next_nonsingleton;
+  Cell *prev_nonsingleton;
+  unsigned int split_level;
+};
+
+
+class Partition
+{
+public:
+  AbstractGraph *graph;
+
+  /* Used during equitable partition refinement */
+  KQueue<Cell *> splitting_queue;
+  void add_in_splitting_queue(Cell * const cell);
+  void clear_splitting_queue();
+
+  class RefInfo {
+  public:
+    unsigned int split_cell_first;
+    int prev_nonsingleton_first;
+    int next_nonsingleton_first;
+  };
+
+  /* Used for unrefinement */
+  KStack<RefInfo> refinement_stack;
+
+  Cell *aux_split_in_two(Cell * const cell,
+			 const unsigned int first_half_size);
+
+  /* The current search level */
+  unsigned int level;
+
+  void unrefine(unsigned int dest_level, unsigned int dest_split_stack_size);
+
+  void consistency_check();
+public:
+  Cell *cells;
+  Cell *free_cells;
+  Cell *first_cell;
+  Cell *first_nonsingleton_cell;
+  unsigned int *elements;
+  unsigned int *invariant_values;
+  /* element_to_cell_map[e] gives the cell of element e */
+  Cell **element_to_cell_map;
+  /* in_pos[e] points to the elements array s.t. *in_pos[e] = e  */
+  unsigned int **in_pos;
+
+  Partition();
+  ~Partition();
+  void init(const unsigned int);
+
+  bool is_discrete() const {return(free_cells == 0); }
+
+  /*
+   * Splits "cell" into [cell_1,...,cell_n] so that &cell_1 == &cell
+   *  according to the invariant_values of elements in the cell
+   * Returns cell_n which is different from "cell" iff
+   *   the cell was actually splitted.
+   * max_ival_info_ok indicates that the max_ival and max_ival_count fields
+   *  in cell have proper values
+   * Clears the invariant values of elements in cell and cell's max_ival and
+   *   max_ival_count fields
+   */
+  Cell *zplit_cell(Cell * const cell, const bool max_ival_info_ok);
+
+private:
+  /* Auxiliary routines for sorting and splitting cells */
+  void clear_ivs(Cell * const cell);
+  Cell *sort_and_split_cell1(Cell *cell);
+  Cell *sort_and_split_cell255(Cell * const cell, const unsigned int max_ival);
+  bool shellsort_cell(Cell *cell);
+  Cell *split_cell(Cell * const cell);
+};
+
+}
+
+#endif
diff --git a/src/bliss_timer.cc b/src/bliss_timer.cc
new file mode 100644
index 0000000..6a57e12
--- /dev/null
+++ b/src/bliss_timer.cc
@@ -0,0 +1,111 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include <unistd.h>
+#ifdef HAVE_TIMES_H
+#include <sys/times.h>
+#else
+#include <ctime>
+#endif
+#include "bliss_timer.hh"
+
+using namespace std;
+
+namespace igraph {
+
+#ifdef HAVE_TIMES_H
+static const double numTicksPerSec = (double)(sysconf(_SC_CLK_TCK));
+#else
+static const double numTicksPerSec = CLOCKS_PER_SEC;
+#endif
+
+Timer::Timer()
+{
+  start_time = 0.0;
+  end_time = 0.0;
+}
+
+void Timer::start()
+{
+
+#ifdef HAVE_TIMES_H
+  struct tms clkticks;
+
+  times(&clkticks);
+  start_time =
+    ((double) clkticks.tms_utime + (double) clkticks.tms_stime) /
+    numTicksPerSec;
+
+#else
+
+  clock_t clkticks;
+  
+  clkticks=clock();
+  start_time = (double)clkticks / numTicksPerSec;
+
+#endif
+}
+
+void Timer::stop()
+{
+#ifdef HAVE_TIMES_H
+  struct tms clkticks;
+
+  times(&clkticks);
+  end_time =
+    ((double) clkticks.tms_utime + (double) clkticks.tms_stime) /
+    numTicksPerSec;
+#else
+
+  clock_t clkticks;
+  
+  clkticks=clock();
+  end_time = (double)clkticks / numTicksPerSec;
+
+#endif
+}
+
+double Timer::get_intermediate()
+{
+#ifdef HAVE_TIMES_H
+  struct tms clkticks;
+
+  times(&clkticks);
+  double intermediate = 
+    ((double) clkticks.tms_utime + (double) clkticks.tms_stime) /
+    numTicksPerSec;
+
+#else
+
+  clock_t clkticks;
+  
+  clkticks=clock();
+  double intermediate = (double)clkticks / numTicksPerSec;
+
+#endif
+
+  return intermediate - start_time;
+}
+
+double Timer::get_duration()
+{
+  return(end_time - start_time);
+}
+
+}
diff --git a/src/bliss_timer.hh b/src/bliss_timer.hh
new file mode 100644
index 0000000..bffee57
--- /dev/null
+++ b/src/bliss_timer.hh
@@ -0,0 +1,38 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_TIMER_HH
+#define BLISS_TIMER_HH
+
+namespace igraph {
+
+class Timer
+{
+  double start_time, end_time;
+public:
+  Timer();
+  void start();
+  void stop();
+  double get_intermediate();
+  double get_duration();
+};
+
+}
+
+#endif
diff --git a/src/bliss_utils.cc b/src/bliss_utils.cc
new file mode 100644
index 0000000..a5cc763
--- /dev/null
+++ b/src/bliss_utils.cc
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#include "bliss_utils.hh"
+#include "bliss_bignum.hh"
+
+using namespace std;
+
+#include <cstring>
+
+#if defined(BLISS_USE_GMP)
+
+namespace igraph {
+
+int BigNum::tostring(char **str) { 
+  *str=igraph_Calloc(mpz_sizeinbase(v, 10)+2, char);
+  if (! *str) { 
+    IGRAPH_ERROR("Cannot convert big number to string", IGRAPH_ENOMEM);
+  }
+  mpz_get_str(*str, 10, v);
+  return 0;
+}
+
+}
+
+#else
+
+namespace igraph {
+
+int BigNum::tostring(char **str) {
+  int size=static_cast<int>( (log(abs(v))/log(10.0))+4 );
+  *str=igraph_Calloc(size, char );
+  if (! *str) {
+    IGRAPH_ERROR("Cannot convert big number to string", IGRAPH_ENOMEM);
+  }
+  std::stringstream ss;
+  ss << v;
+  strncpy(*str, ss.str().c_str(), size);
+  return 0;
+}
+
+}
+
+#endif
diff --git a/src/bliss_utils.hh b/src/bliss_utils.hh
new file mode 100644
index 0000000..04e1be9
--- /dev/null
+++ b/src/bliss_utils.hh
@@ -0,0 +1,23 @@
+/*
+Copyright (C) 2003-2006 Tommi Junttila
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+*/
+
+/* FSF address fixed in the above notice on 1 Oct 2009 by Tamas Nepusz */
+
+#ifndef BLISS_UTILS_HH
+#define BLISS_UTILS_HH
+
+#endif
diff --git a/src/cattributes.c b/src/cattributes.c
new file mode 100644
index 0000000..a7f413f
--- /dev/null
+++ b/src/cattributes.c
@@ -0,0 +1,3718 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_attributes.h"
+#include "igraph_memory.h"
+#include "config.h"
+#include "igraph_math.h"
+#include "igraph_interface.h"
+#include "igraph_random.h"
+
+#include <string.h>
+
+/* An attribute is either a numeric vector (vector_t) or a string
+   vector (strvector_t). The attribute itself is stored in a 
+   struct igraph_attribute_record_t, there is one such object for each
+   attribute. The igraph_t has a pointer to an array of three
+   vector_ptr_t's which contains pointers to
+   igraph_i_cattribute_t's. Graph attributes are first, then vertex 
+   and edge attributes. */
+
+igraph_bool_t igraph_i_cattribute_find(const igraph_vector_ptr_t *ptrvec, 
+				       const char *name, long int *idx) {
+  long int i, n=igraph_vector_ptr_size(ptrvec);
+  igraph_bool_t l=0;
+  for (i=0; !l && i<n; i++) {
+    igraph_attribute_record_t *rec=VECTOR(*ptrvec)[i];
+    l= !strcmp(rec->name, name);
+  }
+  if (idx) { *idx=i-1; }
+  return l;
+}
+
+typedef struct igraph_i_cattributes_t {
+  igraph_vector_ptr_t gal;
+  igraph_vector_ptr_t val;
+  igraph_vector_ptr_t eal;
+} igraph_i_cattributes_t;
+
+int igraph_i_cattributes_copy_attribute_record(igraph_attribute_record_t **newrec, 
+					       const igraph_attribute_record_t *rec) {
+  igraph_vector_t *num, *newnum;
+  igraph_strvector_t *str, *newstr;
+  
+  *newrec=igraph_Calloc(1, igraph_attribute_record_t);
+  if (!(*newrec)) { IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); }
+  IGRAPH_FINALLY(igraph_free, *newrec);
+  (*newrec)->type=rec->type;
+  (*newrec)->name=strdup(rec->name);
+  if (!(*newrec)->name) { IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); }
+  IGRAPH_FINALLY(igraph_free, (void*)(*newrec)->name);
+  if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+    num=(igraph_vector_t *)rec->value;
+    newnum=igraph_Calloc(1, igraph_vector_t);
+    if (!newnum) { 
+      IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); 
+    }
+    IGRAPH_FINALLY(igraph_free, newnum);
+    IGRAPH_CHECK(igraph_vector_copy(newnum, num));
+    IGRAPH_FINALLY(igraph_vector_destroy, newnum);
+    (*newrec)->value=newnum;
+  } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
+    str=(igraph_strvector_t*)rec->value;
+    newstr=igraph_Calloc(1, igraph_strvector_t);
+    if (!newstr) { 
+      IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); 
+    }
+    IGRAPH_FINALLY(igraph_free, newstr);
+    IGRAPH_CHECK(igraph_strvector_copy(newstr, str));
+    IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
+    (*newrec)->value=newstr;
+  }
+
+  IGRAPH_FINALLY_CLEAN(4);
+  return 0;
+}
+
+
+int igraph_i_cattribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) {
+  igraph_attribute_record_t *attr_rec;
+  long int i, n;
+  igraph_i_cattributes_t *nattr;
+
+  n = attr ? igraph_vector_ptr_size(attr) : 0;
+
+  nattr=igraph_Calloc(1, igraph_i_cattributes_t);
+  if (!nattr) {
+    IGRAPH_ERROR("Can't init attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, nattr);
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->gal, n));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->gal);
+  IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->val, 0));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->val);
+  IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->eal, 0));
+  IGRAPH_FINALLY_CLEAN(3);
+
+  for (i=0; i<n; i++) {
+    IGRAPH_CHECK(igraph_i_cattributes_copy_attribute_record(
+	  &attr_rec, VECTOR(*attr)[i]));
+    VECTOR(nattr->gal)[i] = attr_rec;
+  }
+
+  graph->attr=nattr;
+
+  return 0;
+}
+
+void igraph_i_cattribute_destroy(igraph_t *graph) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *als[3]= { &attr->gal, &attr->val, &attr->eal };
+  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]);
+    for (i=0; i<n; i++) {
+      rec=VECTOR(*als[a])[i];
+      if (rec) { 
+	if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+	  num=(igraph_vector_t*)rec->value;
+	  igraph_vector_destroy(num);
+	  igraph_free(num);
+	} else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
+	  str=(igraph_strvector_t*)rec->value;
+	  igraph_strvector_destroy(str);
+	  igraph_free(str);
+	} else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
+	  boolvec=(igraph_vector_bool_t*)rec->value;
+	  igraph_vector_bool_destroy(boolvec);
+	  igraph_free(boolvec);
+	}
+	igraph_free((char*)rec->name);
+	igraph_free(rec);
+      }
+    }
+  }
+  igraph_vector_ptr_destroy(&attr->gal);
+  igraph_vector_ptr_destroy(&attr->val);
+  igraph_vector_ptr_destroy(&attr->eal);
+  igraph_free(graph->attr);
+  graph->attr=0;
+}
+
+/* Almost the same as destroy, but we might have null pointers */
+
+void igraph_i_cattribute_copy_free(igraph_i_cattributes_t *attr) {
+  igraph_vector_ptr_t *als[3] = { &attr->gal, &attr->val, &attr->eal };
+  long int i, n, a;
+  igraph_vector_t *num;
+  igraph_strvector_t *str;
+  igraph_attribute_record_t *rec;
+  for (a=0; a<3; a++) {
+    n=igraph_vector_ptr_size(als[a]);
+    for (i=0; i<n; i++) {
+      rec=VECTOR(*als[a])[i];
+      if (!rec) { continue; }
+      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+	num=(igraph_vector_t*)rec->value;
+	igraph_vector_destroy(num);
+	igraph_free(num);
+      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
+	str=(igraph_strvector_t*)rec->value;
+	igraph_strvector_destroy(str);
+	igraph_free(str);
+      }
+      igraph_free((char*)rec->name);
+      igraph_free(rec);
+    }
+  }  
+}
+
+/* No reference counting here. If you use attributes in C you should
+   know what you're doing. */
+
+int igraph_i_cattribute_copy(igraph_t *to, const igraph_t *from, 
+			     igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea) {
+  igraph_i_cattributes_t *attrfrom=from->attr, *attrto;
+  igraph_vector_ptr_t *alto[3], *alfrom[3]={ &attrfrom->gal, &attrfrom->val, 
+					     &attrfrom->eal };
+  long int i, n, a;
+  igraph_bool_t copy[3] = { ga, va, ea };
+  to->attr=attrto=igraph_Calloc(1, igraph_i_cattributes_t);
+  if (!attrto) { 
+    IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, attrto);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->gal, 0);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->val, 0);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->eal, 0);
+  IGRAPH_FINALLY_CLEAN(3);
+  IGRAPH_FINALLY(igraph_i_cattribute_copy_free, attrto);
+
+  alto[0]=&attrto->gal; alto[1]=&attrto->val; alto[2]=&attrto->eal;
+  for (a=0; a<3; a++) {
+    if (copy[a]) {
+      n=igraph_vector_ptr_size(alfrom[a]);
+      IGRAPH_CHECK(igraph_vector_ptr_resize(alto[a], n));
+      igraph_vector_ptr_null(alto[a]);
+      for (i=0; i<n; i++) {
+	igraph_attribute_record_t *newrec;
+	IGRAPH_CHECK(igraph_i_cattributes_copy_attribute_record(&newrec, 
+								VECTOR(*alfrom[a])[i]));
+	VECTOR(*alto[a])[i]=newrec;
+      }
+    }
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
+				     igraph_vector_ptr_t *nattr) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int length=igraph_vector_ptr_size(val);
+  long int nattrno=nattr==NULL ? 0 : igraph_vector_ptr_size(nattr);
+  long int origlen=igraph_vcount(graph)-nv;
+  long int newattrs=0, i;
+  igraph_vector_t news;
+  
+  /* First add the new attributes if any */
+  newattrs=0;
+  IGRAPH_VECTOR_INIT_FINALLY(&news, 0);
+  for (i=0; i<nattrno; i++) {
+    igraph_attribute_record_t *nattr_entry=VECTOR(*nattr)[i];
+    const char *nname=nattr_entry->name;
+    long int j;
+    igraph_bool_t l=igraph_i_cattribute_find(val, nname, &j);
+    if (!l) {
+      newattrs++;
+      IGRAPH_CHECK(igraph_vector_push_back(&news, i));
+    } else {
+      /* check types */
+      if (nattr_entry->type != 
+	  ((igraph_attribute_record_t*)VECTOR(*val)[j])->type) {
+	IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL);
+      }
+    }
+  }
+
+  /* Add NA/empty string vectors for the existing vertices */
+  if (newattrs != 0) {
+    for (i=0; i<newattrs; i++) {
+      igraph_attribute_record_t *tmp=VECTOR(*nattr)[(long int)VECTOR(news)[i]];
+      igraph_attribute_record_t *newrec=igraph_Calloc(1, igraph_attribute_record_t);
+      igraph_attribute_type_t type=tmp->type;
+      if (!newrec) { 
+	IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, newrec);
+      newrec->type=type;
+      newrec->name=strdup(tmp->name);
+      if (!newrec->name) { 
+	IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, (char*)newrec->name);
+      if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_vector_t *newnum=igraph_Calloc(1, igraph_vector_t);
+	if (!newnum) {
+	  IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, newnum);
+	IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen);
+	newrec->value=newnum;
+	igraph_vector_fill(newnum, IGRAPH_NAN);
+      } else if (type==IGRAPH_ATTRIBUTE_STRING) {
+	igraph_strvector_t *newstr=igraph_Calloc(1, igraph_strvector_t);
+	if (!newstr) {
+	  IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, newstr);
+	IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen);
+	newrec->value=newstr;
+      }
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(val, newrec));
+      IGRAPH_FINALLY_CLEAN(4);
+    }
+    length=igraph_vector_ptr_size(val);
+  }
+  
+  /* Now append the new values */
+  for (i=0; i<length; i++) {
+    igraph_attribute_record_t *oldrec=VECTOR(*val)[i];
+    igraph_attribute_record_t *newrec=0;
+    const char *name=oldrec->name;
+    long int j;
+    igraph_bool_t l=0;
+    if (nattr) { l=igraph_i_cattribute_find(nattr, name, &j); }
+    if (l) {
+      /* This attribute is present in nattr */
+      igraph_vector_t *oldnum, *newnum;
+      igraph_strvector_t *oldstr, *newstr;
+      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;
+      if (oldrec->type != newrec->type) {
+	IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);
+      }
+      switch (oldrec->type) {
+      case IGRAPH_ATTRIBUTE_NUMERIC:
+	if (nv != igraph_vector_size(newnum)) {
+	  IGRAPH_ERROR("Invalid numeric attribute length", IGRAPH_EINVAL);
+	}
+	IGRAPH_CHECK(igraph_vector_append(oldnum, newnum));
+	break;
+      case IGRAPH_ATTRIBUTE_STRING:
+	if (nv != igraph_strvector_size(newstr)) {
+	  IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);
+	}
+	IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr));
+	break;
+      default:
+	IGRAPH_WARNING("Invalid attribute type");	
+	break;
+      }
+    } else {
+      /* No such attribute, append NA's */
+      igraph_vector_t *oldnum=(igraph_vector_t *)oldrec->value;
+      igraph_strvector_t *oldstr=(igraph_strvector_t*)oldrec->value;
+      switch (oldrec->type) {
+      case IGRAPH_ATTRIBUTE_NUMERIC:
+	IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen+nv));
+	for (j=origlen; j<origlen+nv; j++) {
+	  VECTOR(*oldnum)[j]=IGRAPH_NAN;
+	}
+	break;
+      case IGRAPH_ATTRIBUTE_STRING:
+	IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen+nv));
+	break;
+      default:
+	IGRAPH_WARNING("Invalid attribute type");
+	break;
+      }
+    }
+  }  
+  
+  igraph_vector_destroy(&news);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+void igraph_i_cattribute_permute_free(igraph_vector_ptr_t *v) {
+  long int i, n=igraph_vector_ptr_size(v);
+  for (i=0; i<n; i++) {
+    igraph_attribute_record_t *rec=VECTOR(*v)[i];
+    igraph_Free(rec->name);
+    if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_vector_t *numv= (igraph_vector_t*) rec->value;
+      igraph_vector_destroy(numv);
+      igraph_Free(numv);
+    } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
+      igraph_strvector_t *strv= (igraph_strvector_t*) rec->value;
+      igraph_strvector_destroy(strv);
+      igraph_Free(strv);
+    }
+    igraph_Free(rec);
+  }
+  igraph_vector_ptr_clear(v);
+}
+
+int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
+					 igraph_t *newgraph,
+					 const igraph_vector_t *idx) {
+
+  if (graph==newgraph) {
+
+    igraph_i_cattributes_t *attr=graph->attr;
+    igraph_vector_ptr_t *val=&attr->val;
+    long int valno=igraph_vector_ptr_size(val);
+    long int i;
+    
+    for (i=0; i<valno; i++) {
+      igraph_attribute_record_t *oldrec=VECTOR(*val)[i];
+      igraph_attribute_type_t type=oldrec->type;
+      igraph_vector_t *num, *newnum;
+      igraph_strvector_t *str, *newstr;
+      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_VECTOR_INIT_FINALLY(newnum, 0);
+	igraph_vector_index(num, newnum, idx);
+	oldrec->value=newnum;
+	igraph_vector_destroy(num);
+	igraph_Free(num);
+	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_CHECK(igraph_strvector_init(newstr, 0));
+	IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
+	igraph_strvector_index(str, newstr, idx);
+	oldrec->value=newstr;
+	igraph_strvector_destroy(str);
+	igraph_Free(str);
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
+      default:
+	IGRAPH_WARNING("Unknown edge attribute ignored");
+      }
+    }
+
+  } else { 
+    igraph_i_cattributes_t *attr=graph->attr;
+    igraph_vector_ptr_t *val=&attr->val;
+    long int valno=igraph_vector_ptr_size(val);
+    long int i;
+    
+    /* New vertex attributes */
+    igraph_i_cattributes_t *new_attr=newgraph->attr;
+    igraph_vector_ptr_t *new_val=&new_attr->val;
+    if (igraph_vector_ptr_size(new_val) != 0) { 
+      IGRAPH_ERROR("Vertex attributes were already copied", 
+		   IGRAPH_EATTRIBUTES);
+    }
+    IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, valno));
+    
+    IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_val);
+    
+    for (i=0; i<valno; i++) {
+      igraph_attribute_record_t *oldrec=VECTOR(*val)[i];
+      igraph_attribute_type_t type=oldrec->type;
+      igraph_vector_t *num, *newnum;
+      igraph_strvector_t *str, *newstr;
+      
+      /* The record itself */
+      igraph_attribute_record_t *new_rec=
+	igraph_Calloc(1, igraph_attribute_record_t);
+      if (!new_rec) { 
+	IGRAPH_ERROR("Cannot create vertex attributes", IGRAPH_ENOMEM);
+      }
+      new_rec->name = strdup(oldrec->name);
+      new_rec->type = oldrec->type;
+      VECTOR(*new_val)[i]=new_rec;
+      
+      /* The data */
+      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_VECTOR_INIT_FINALLY(newnum, 0);
+	igraph_vector_index(num, newnum, idx);
+	new_rec->value=newnum;
+	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_CHECK(igraph_strvector_init(newstr, 0));
+	IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
+	igraph_strvector_index(str, newstr, idx);
+	new_rec->value=newstr;
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
+      default:
+	IGRAPH_WARNING("Unknown vertex attribute ignored");
+      }
+    }
+  }
+
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_i_cattributes_cn_sum(const igraph_attribute_record_t *oldrec, 
+				igraph_attribute_record_t * newrec, 
+				const igraph_vector_ptr_t *merges) {
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_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_VECTOR_INIT_FINALLY(newv, newlen);
+  
+  for (i=0; i<newlen; i++) {
+    igraph_real_t s=0.0;
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    for (j=0; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];      
+      s += VECTOR(*oldv)[x];
+    }
+    VECTOR(*newv)[i]=s;
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;
+  
+  return 0;
+}
+
+int igraph_i_cattributes_cn_prod(const igraph_attribute_record_t *oldrec, 
+				 igraph_attribute_record_t * newrec, 
+				 const igraph_vector_ptr_t *merges) {
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_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_VECTOR_INIT_FINALLY(newv, newlen);
+  
+  for (i=0; i<newlen; i++) {
+    igraph_real_t s=1.0;
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    for (j=0; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];      
+      s *= VECTOR(*oldv)[x];
+    }
+    VECTOR(*newv)[i]=s;
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;
+  
+  return 0;
+}
+
+int igraph_i_cattributes_cn_min(const igraph_attribute_record_t *oldrec, 
+				igraph_attribute_record_t * newrec, 
+				const igraph_vector_ptr_t *merges) {
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_real_t nan=IGRAPH_NAN;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    igraph_real_t m= n > 0 ? VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ] : nan;
+    for (j=1; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];      
+      igraph_real_t val=VECTOR(*oldv)[x];
+      if (val < m) { m=val; }
+    }
+    VECTOR(*newv)[i]=m;
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cn_max(const igraph_attribute_record_t *oldrec, 
+				igraph_attribute_record_t * newrec, 
+				const igraph_vector_ptr_t *merges) {
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_real_t nan=IGRAPH_NAN;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    igraph_real_t m= n > 0 ? VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ] : nan;
+    for (j=1; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];      
+      igraph_real_t val=VECTOR(*oldv)[x];
+      if (val > m) { m=val; }
+    }
+    VECTOR(*newv)[i]=m;
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cn_random(const igraph_attribute_record_t *oldrec, 
+				   igraph_attribute_record_t * newrec, 
+				   const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_real_t nan=IGRAPH_NAN;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+
+  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]=nan;
+    } 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_cn_first(const igraph_attribute_record_t *oldrec, 
+				  igraph_attribute_record_t * newrec, 
+				  const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_real_t nan=IGRAPH_NAN;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+
+  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]=nan;
+    } else {
+      VECTOR(*newv)[i]=VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
+    }
+  }
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cn_last(const igraph_attribute_record_t *oldrec, 
+				 igraph_attribute_record_t * newrec, 
+				 const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_real_t nan=IGRAPH_NAN;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+
+  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]=nan;
+    } 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_cn_mean(const igraph_attribute_record_t *oldrec, 
+				 igraph_attribute_record_t * newrec, 
+				 const igraph_vector_ptr_t *merges) {
+  const igraph_vector_t *oldv=oldrec->value;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_real_t nan=IGRAPH_NAN;
+ 
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+  
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    igraph_real_t s= n > 0 ? 0.0 : nan;
+    for (j=0; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];      
+      s += VECTOR(*oldv)[x];
+    }
+    if (n>0) { s=s/n; }
+    VECTOR(*newv)[i]=s;
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;
+  
+  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, 
+				 igraph_cattributes_combine_num_t *func) {
+  
+  const igraph_vector_t *oldv=oldrec->value;
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_vector_t *newv=igraph_Calloc(1, igraph_vector_t);
+  igraph_vector_t values;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&values, 0);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    igraph_real_t res;
+    IGRAPH_CHECK(igraph_vector_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_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) {
+  
+  const igraph_strvector_t *oldv=oldrec->value;
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_strvector_t *newv=igraph_Calloc(1, igraph_strvector_t);
+  
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_strvector_destroy, newv);
+
+  RNG_BEGIN();
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int n=igraph_vector_size(idx);
+    char *tmp;
+    if (n==0) {
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, ""));
+    } else if (n==1) {
+      igraph_strvector_get(oldv, 0, &tmp);
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
+    } else {
+      long int r=RNG_INTEGER(0, n-1);
+      igraph_strvector_get(oldv, r, &tmp);
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
+    }
+  }
+  
+  RNG_END();
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;
+
+  return 0;  
+}
+
+int igraph_i_cattributes_sn_first(const igraph_attribute_record_t *oldrec,
+				  igraph_attribute_record_t *newrec,
+				  const igraph_vector_ptr_t *merges) {
+  
+  const igraph_strvector_t *oldv=oldrec->value;
+  long int i, newlen=igraph_vector_ptr_size(merges);
+  igraph_strvector_t *newv=igraph_Calloc(1, igraph_strvector_t);
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_strvector_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) {
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, ""));
+    } else {
+      char *tmp;
+      igraph_strvector_get(oldv, (long int) VECTOR(*idx)[0], &tmp);
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
+    }
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;    
+
+  return 0;
+}
+
+int igraph_i_cattributes_sn_last(const igraph_attribute_record_t *oldrec,
+				 igraph_attribute_record_t *newrec,
+				 const igraph_vector_ptr_t *merges) {
+  
+  const igraph_strvector_t *oldv=oldrec->value;
+  long int i, newlen=igraph_vector_ptr_size(merges);
+  igraph_strvector_t *newv=igraph_Calloc(1, igraph_strvector_t);
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_strvector_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) {
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, ""));
+    } else {
+      char *tmp;
+      igraph_strvector_get(oldv, (long int) VECTOR(*idx)[n-1], &tmp);
+      IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
+    }
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;    
+
+  return 0;
+}
+
+int igraph_i_cattributes_sn_concat(const igraph_attribute_record_t *oldrec,
+				   igraph_attribute_record_t *newrec,
+				   const igraph_vector_ptr_t *merges) {
+
+  const igraph_strvector_t *oldv=oldrec->value;
+  long int i, newlen=igraph_vector_ptr_size(merges);
+  igraph_strvector_t *newv=igraph_Calloc(1, igraph_strvector_t);
+  
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_strvector_destroy, newv);
+  
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    size_t len=0;
+    char *tmp, *tmp2;
+    for (j=0; j<n; j++) {
+      igraph_strvector_get(oldv, j, &tmp);
+      len += strlen(tmp);
+    }
+    tmp2=igraph_Calloc(len+1, char);
+    if (!tmp2) {
+      IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, tmp2);
+    len=0;
+    for (j=0; j<n; j++) {
+      igraph_strvector_get(oldv, j, &tmp);
+      strcpy(tmp2+len, tmp);
+      len+=strlen(tmp);
+    }
+    
+    IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp2));
+    igraph_Free(tmp2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;
+
+  return 0;
+}
+
+int igraph_i_cattributes_sn_func(const igraph_attribute_record_t *oldrec,
+				 igraph_attribute_record_t *newrec,
+				 const igraph_vector_ptr_t *merges,
+				 igraph_cattributes_combine_str_t *func) {
+
+  const igraph_strvector_t *oldv=oldrec->value;
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_strvector_t *newv=igraph_Calloc(1, igraph_strvector_t);
+  igraph_strvector_t values;
+  
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_strvector_destroy, newv);
+  
+  IGRAPH_CHECK(igraph_strvector_init(newv, 0));
+  IGRAPH_FINALLY(igraph_strvector_destroy, &values);
+  
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    char *res;
+    IGRAPH_CHECK(igraph_strvector_resize(&values, n));
+    for (j=0; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];
+      char *elem;
+      igraph_strvector_get(oldv, x, &elem);
+      IGRAPH_CHECK(igraph_strvector_set(newv, j, elem));
+    }
+    IGRAPH_CHECK(func(&values, &res));
+    IGRAPH_FINALLY(igraph_free, res);
+    IGRAPH_CHECK(igraph_strvector_set(newv, i, res));
+    IGRAPH_FINALLY_CLEAN(1);
+    igraph_Free(res);
+  }
+  
+  igraph_strvector_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(3);
+  newrec->value = newv;
+  
+  return 0;
+}
+  
+
+int igraph_i_cattribute_combine_vertices(const igraph_t *graph,
+			 igraph_t *newgraph,
+			 const igraph_vector_ptr_t *merges,
+			 const igraph_attribute_combination_t *comb) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_i_cattributes_t *toattr=newgraph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  igraph_vector_ptr_t *new_val=&toattr->val;
+  long int valno=igraph_vector_ptr_size(val);
+  long int i, j, keepno=0;
+  int *TODO;
+  void **funcs;
+
+  TODO=igraph_Calloc(valno, int);
+  if (!TODO) {
+    IGRAPH_ERROR("Cannot combine vertex attributes", 
+		 IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, TODO);
+  funcs=igraph_Calloc(valno, void*);
+  if (!funcs) {
+    IGRAPH_ERROR("Cannot combine vertex attributes",
+		 IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, funcs);
+  
+  for (i=0; i<valno; i++) {
+    igraph_attribute_record_t *oldrec=VECTOR(*val)[i];    
+    const char *name=oldrec->name;
+    igraph_attribute_combination_type_t todo;
+    void *voidfunc;
+    igraph_attribute_combination_query(comb, name, &todo, &voidfunc);
+    TODO[i]=todo;
+    funcs[i]=voidfunc;
+    if (todo != IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
+      keepno++;
+    }
+  }
+
+  IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, keepno));
+  IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_val);
+  
+  for (i=0, j=0; i<valno; i++) {
+    igraph_attribute_record_t *newrec, *oldrec=VECTOR(*val)[i];
+    const char *name=oldrec->name;
+    igraph_attribute_combination_type_t todo=
+      (igraph_attribute_combination_type_t) (TODO[i]);
+    igraph_attribute_type_t type=oldrec->type;
+    igraph_cattributes_combine_num_t *numfunc=
+      (igraph_cattributes_combine_num_t*) funcs[i];
+    igraph_cattributes_combine_str_t *strfunc=
+      (igraph_cattributes_combine_str_t*) funcs[i];
+    
+    if (todo==IGRAPH_ATTRIBUTE_COMBINE_DEFAULT || 
+	todo==IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
+      continue;
+    }
+    
+    newrec=igraph_Calloc(1, igraph_attribute_record_t);
+    if (!newrec) {
+      IGRAPH_ERROR("Cannot combine vertex attributes", 
+		   IGRAPH_ENOMEM);
+    }
+    newrec->name = strdup(name);
+    newrec->type = type;
+    VECTOR(*new_val)[j] = newrec;
+
+    if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+      switch (todo) {
+      case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, newrec, merges,
+						  numfunc));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_SUM:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_PROD:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MIN:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MAX:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_LAST:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
+	IGRAPH_ERROR("Median calculation not implemented", 
+		     IGRAPH_UNIMPLEMENTED);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
+	IGRAPH_ERROR("Cannot concatenate numeric attributes", 
+		     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:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_func(oldrec, newrec, merges,
+						  strfunc));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_SUM:
+	IGRAPH_ERROR("Cannot sum strings", IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_PROD:
+	IGRAPH_ERROR("Cannot multiply strings", IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MIN:
+	IGRAPH_ERROR("Cannot find minimum of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MAX:
+	IGRAPH_ERROR("Cannot find maximum of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
+	IGRAPH_ERROR("Cannot calculate mean of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
+	IGRAPH_ERROR("Cannot calculate median of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_first(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_LAST:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_last(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_concat(oldrec, newrec, merges));
+	break;
+      default:
+	IGRAPH_ERROR("Unknown attribute_combination",
+		     IGRAPH_UNIMPLEMENTED);
+	break;
+      }
+    } else {
+      IGRAPH_ERROR("Unknown attribute type, this should not happen", 
+		   IGRAPH_UNIMPLEMENTED);
+    }
+    
+    j++;    
+  }
+
+  igraph_free(funcs);
+  igraph_free(TODO);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/* void igraph_i_cattribute_delete_vertices(igraph_t *graph, */
+/* 				       const igraph_vector_t *eidx, */
+/* 				       const igraph_vector_t *vidx) { */
+  
+/*   igraph_i_cattributes_t *attr=graph->attr; */
+/*   igraph_vector_ptr_t *val=&attr->val; */
+/*   igraph_vector_ptr_t *eal=&attr->eal; */
+/*   long int valno=igraph_vector_ptr_size(val); */
+/*   long int ealno=igraph_vector_ptr_size(eal); */
+/*   long int i; */
+/*   long int origlen, newlen; */
+  
+/*   /\* Vertices *\/ */
+/*   origlen=igraph_vector_size(vidx); */
+/*   newlen=0; */
+/*   for (i=0; i<origlen; i++) { */
+/*     if (VECTOR(*vidx)[i]>0) { */
+/*       newlen++; */
+/*     } */
+/*   } */
+/*   for (i=0; i<valno; i++) { */
+/*     igraph_attribute_record_t *oldrec=VECTOR(*val)[i]; */
+/*     igraph_attribute_type_t type=oldrec->type; */
+/*     igraph_vector_t *num=(igraph_vector_t*)oldrec->value; */
+/*     igraph_strvector_t *str=(igraph_strvector_t*)oldrec->value; */
+/*     switch (type) { */
+/*     case IGRAPH_ATTRIBUTE_NUMERIC: */
+/*       igraph_vector_permdelete(num, vidx, origlen-newlen); */
+/*       break; */
+/*     case IGRAPH_ATTRIBUTE_STRING: */
+/*       igraph_strvector_permdelete(str, vidx, origlen-newlen); */
+/*       break; */
+/*     default: */
+/*       IGRAPH_WARNING("Unknown vertex attribute ignored"); */
+/*     } */
+/*   } */
+
+/*   /\* Edges *\/ */
+/*   origlen=igraph_vector_size(eidx); */
+/*   newlen=0; */
+/*   for (i=0; i<origlen; i++) { */
+/*     if (VECTOR(*eidx)[i]>0) { */
+/*       newlen++; */
+/*     } */
+/*   } */
+/*   for (i=0; i<ealno; i++) { */
+/*     igraph_attribute_record_t *oldrec=VECTOR(*eal)[i]; */
+/*     igraph_attribute_type_t type=oldrec->type; */
+/*     igraph_vector_t *num=(igraph_vector_t*)oldrec->value; */
+/*     igraph_strvector_t *str=(igraph_strvector_t*)oldrec->value; */
+/*     switch (type) { */
+/*     case IGRAPH_ATTRIBUTE_NUMERIC: */
+/*       igraph_vector_permdelete(num, eidx, origlen-newlen); */
+/*       break; */
+/*     case IGRAPH_ATTRIBUTE_STRING: */
+/*       igraph_strvector_permdelete(str, eidx, origlen-newlen); */
+/*       break; */
+/*     default: */
+/*       IGRAPH_WARNING("Unknown edge attribute ignored"); */
+/*     } */
+/*   } */
+/* } */
+
+int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
+				 igraph_vector_ptr_t *nattr) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int ealno=igraph_vector_ptr_size(eal);
+  long int ne=igraph_vector_size(edges)/2;
+  long int origlen=igraph_ecount(graph)-ne;
+  long int nattrno= nattr == 0 ? 0 : igraph_vector_ptr_size(nattr);
+  igraph_vector_t news;
+  long int newattrs, i;
+  
+  /* First add the new attributes if any */
+  newattrs=0;
+  IGRAPH_VECTOR_INIT_FINALLY(&news, 0);
+  for (i=0; i<nattrno; i++) {
+    igraph_attribute_record_t *nattr_entry=VECTOR(*nattr)[i];
+    const char *nname=nattr_entry->name;
+    long int j;
+    igraph_bool_t l=igraph_i_cattribute_find(eal, nname, &j);
+    if (!l) {
+      newattrs++;
+      IGRAPH_CHECK(igraph_vector_push_back(&news, i));
+    } else {
+      /* check types */
+      if (nattr_entry->type != 
+	  ((igraph_attribute_record_t*)VECTOR(*eal)[j])->type) {
+	IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL);
+      }
+    }
+  }
+
+  /* Add NA/empty string vectors for the existing vertices */
+  if (newattrs != 0) {
+    for (i=0; i<newattrs; i++) {
+      igraph_attribute_record_t *tmp=VECTOR(*nattr)[(long int)VECTOR(news)[i]];
+      igraph_attribute_record_t *newrec=igraph_Calloc(1, igraph_attribute_record_t);
+      igraph_attribute_type_t type=tmp->type;
+      if (!newrec) { 
+	IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, newrec);
+      newrec->type=type;
+      newrec->name=strdup(tmp->name);
+      if (!newrec->name) { 
+	IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, (char*)newrec->name);
+      if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_vector_t *newnum=igraph_Calloc(1, igraph_vector_t);
+	if (!newnum) {
+	  IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, newnum);
+	IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen);
+	newrec->value=newnum;
+	igraph_vector_fill(newnum, IGRAPH_NAN);
+      } else if (type==IGRAPH_ATTRIBUTE_STRING) {
+	igraph_strvector_t *newstr=igraph_Calloc(1, igraph_strvector_t);
+	if (!newstr) {
+	  IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, newstr);
+	IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen);
+	newrec->value=newstr;	
+      }
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, newrec));
+      IGRAPH_FINALLY_CLEAN(4);
+    }
+    ealno=igraph_vector_ptr_size(eal);
+  }
+  
+  /* Now append the new values */
+  for (i=0; i<ealno; i++) {
+    igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];
+    igraph_attribute_record_t *newrec=0;
+    const char *name=oldrec->name;
+    long int j;
+    igraph_bool_t l=0;
+    if (nattr) { l=igraph_i_cattribute_find(nattr, name, &j); }
+    if (l) {
+      /* This attribute is present in nattr */
+      igraph_vector_t *oldnum, *newnum;
+      igraph_strvector_t *oldstr, *newstr;
+      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;
+      if (oldrec->type != newrec->type) {
+	IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);
+      }
+      switch (oldrec->type) {
+      case IGRAPH_ATTRIBUTE_NUMERIC:
+	if (ne != igraph_vector_size(newnum)) {
+	  IGRAPH_ERROR("Invalid numeric attribute length", IGRAPH_EINVAL);
+	}
+	IGRAPH_CHECK(igraph_vector_append(oldnum, newnum));
+	break;
+      case IGRAPH_ATTRIBUTE_STRING:
+	if (ne != igraph_strvector_size(newstr)) {
+	  IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);
+	}
+	IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr));
+	break;
+      default:
+	IGRAPH_WARNING("Invalid attribute type");	
+	break;
+      }
+    } else {
+      /* No such attribute, append NA's */
+      igraph_vector_t *oldnum=(igraph_vector_t *)oldrec->value;
+      igraph_strvector_t *oldstr=(igraph_strvector_t*)oldrec->value;
+      switch (oldrec->type) {
+      case IGRAPH_ATTRIBUTE_NUMERIC:
+	IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen+ne));
+	for (j=origlen; j<origlen+ne; j++) {
+	  VECTOR(*oldnum)[j]=IGRAPH_NAN;
+	}
+	break;
+      case IGRAPH_ATTRIBUTE_STRING:
+	IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen+ne));
+	break;
+      default:
+	IGRAPH_WARNING("Invalid attribute type");
+	break;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&news);
+  IGRAPH_FINALLY_CLEAN(1);
+   
+  return 0;
+}
+
+/* void igraph_i_cattribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) { */
+
+/*   igraph_i_cattributes_t *attr=graph->attr; */
+/*   igraph_vector_ptr_t *eal=&attr->eal; */
+/*   long int ealno=igraph_vector_ptr_size(eal); */
+/*   long int i; */
+/*   long int origlen=igraph_vector_size(idx), newlen; */
+
+/*   newlen=0; */
+/*   for (i=0; i<origlen; i++) { */
+/*     if (VECTOR(*idx)[i]>0) { */
+/*       newlen++; */
+/*     } */
+/*   } */
+/*   for (i=0; i<ealno; i++) { */
+/*     igraph_attribute_record_t *oldrec=VECTOR(*eal)[i]; */
+/*     igraph_attribute_type_t type=oldrec->type; */
+/*     igraph_vector_t *num=(igraph_vector_t*)oldrec->value; */
+/*     igraph_strvector_t *str=(igraph_strvector_t*)oldrec->value; */
+/*     switch (type) { */
+/*     case IGRAPH_ATTRIBUTE_NUMERIC: */
+/*       igraph_vector_permdelete(num, idx, origlen-newlen); */
+/*       break; */
+/*     case IGRAPH_ATTRIBUTE_STRING: */
+/*       igraph_strvector_permdelete(str, idx, origlen-newlen); */
+/*       break; */
+/*     default: */
+/*       IGRAPH_WARNING("Unknown edge attribute ignored"); */
+/*     } */
+/*   } */
+  
+/* } */
+
+int igraph_i_cattribute_permute_edges(const igraph_t *graph,
+				      igraph_t *newgraph,
+				      const igraph_vector_t *idx) {
+
+  if (graph == newgraph) {
+
+    igraph_i_cattributes_t *attr=graph->attr;
+    igraph_vector_ptr_t *eal=&attr->eal;
+    long int ealno=igraph_vector_ptr_size(eal);
+    long int i;
+    
+    for (i=0; i<ealno; i++) {
+      igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];
+      igraph_attribute_type_t type=oldrec->type;
+      igraph_vector_t *num, *newnum;
+      igraph_strvector_t *str, *newstr;
+      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_VECTOR_INIT_FINALLY(newnum, 0);
+	igraph_vector_index(num, newnum, idx);
+	oldrec->value=newnum;
+	igraph_vector_destroy(num);
+	igraph_Free(num);
+	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_CHECK(igraph_strvector_init(newstr, 0));
+	IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
+	igraph_strvector_index(str, newstr, idx);
+	oldrec->value=newstr;
+	igraph_strvector_destroy(str);
+	igraph_Free(str);
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
+      default:
+	IGRAPH_WARNING("Unknown edge attribute ignored");
+      }
+    }
+    
+  } else { 
+
+    igraph_i_cattributes_t *attr=graph->attr;
+    igraph_vector_ptr_t *eal=&attr->eal;
+    long int ealno=igraph_vector_ptr_size(eal);
+    long int i;
+    
+    /* New edge attributes */
+    igraph_i_cattributes_t *new_attr=newgraph->attr;
+    igraph_vector_ptr_t *new_eal=&new_attr->eal;
+    IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, ealno));
+    
+    IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_eal);
+    
+    for (i=0; i<ealno; i++) {
+      igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];
+      igraph_attribute_type_t type=oldrec->type;
+      igraph_vector_t *num, *newnum;
+      igraph_strvector_t *str, *newstr;
+      
+      /* The record itself */
+      igraph_attribute_record_t *new_rec=
+	igraph_Calloc(1, igraph_attribute_record_t);
+      if (!new_rec) {
+	IGRAPH_ERROR("Cannot create edge attributes", IGRAPH_ENOMEM);
+      }
+      new_rec->name = strdup(oldrec->name);
+      new_rec->type = oldrec->type;
+      VECTOR(*new_eal)[i] = new_rec;
+      
+      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_VECTOR_INIT_FINALLY(newnum, 0);
+	igraph_vector_index(num, newnum, idx);
+	new_rec->value=newnum;
+	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_CHECK(igraph_strvector_init(newstr, 0));
+	IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
+	igraph_strvector_index(str, newstr, idx);
+	new_rec->value=newstr;
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
+      default:
+	IGRAPH_WARNING("Unknown edge attribute ignored");
+      }
+    }
+    IGRAPH_FINALLY_CLEAN(1);    
+  }
+  
+  return 0;
+}
+
+int igraph_i_cattribute_combine_edges(const igraph_t *graph,
+			 igraph_t *newgraph,
+			 const igraph_vector_ptr_t *merges,
+			 const igraph_attribute_combination_t *comb) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_i_cattributes_t *toattr=newgraph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  igraph_vector_ptr_t *new_eal=&toattr->eal;
+  long int ealno=igraph_vector_ptr_size(eal);
+  long int i, j, keepno=0;
+  int *TODO;
+  void **funcs;
+
+  TODO=igraph_Calloc(ealno, int);
+  if (!TODO) {
+    IGRAPH_ERROR("Cannot combine edge attributes", 
+		 IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, TODO);
+  funcs=igraph_Calloc(ealno, void*);
+  if (!funcs) {
+    IGRAPH_ERROR("Cannot combine edge attributes",
+		 IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, funcs);
+  
+  for (i=0; i<ealno; i++) {
+    igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];    
+    const char *name=oldrec->name;
+    igraph_attribute_combination_type_t todo;
+    void *voidfunc;
+    igraph_attribute_combination_query(comb, name, &todo, &voidfunc);
+    TODO[i]=todo;
+    funcs[i]=voidfunc;
+    if (todo != IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
+      keepno++;
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, keepno));
+  IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_eal);
+  
+  for (i=0, j=0; i<ealno; i++) {
+    igraph_attribute_record_t *newrec, *oldrec=VECTOR(*eal)[i];
+    const char *name=oldrec->name;
+    igraph_attribute_combination_type_t todo=
+      (igraph_attribute_combination_type_t) (TODO[i]);
+    igraph_attribute_type_t type=oldrec->type;
+    igraph_cattributes_combine_num_t *numfunc=
+      (igraph_cattributes_combine_num_t*) funcs[i];
+    igraph_cattributes_combine_str_t *strfunc=
+      (igraph_cattributes_combine_str_t*) funcs[i];
+    
+    if (todo==IGRAPH_ATTRIBUTE_COMBINE_DEFAULT || 
+	todo==IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
+      continue;
+    }
+  
+    newrec=igraph_Calloc(1, igraph_attribute_record_t);
+    if (!newrec) {
+      IGRAPH_ERROR("Cannot combine edge attributes", 
+		   IGRAPH_ENOMEM);
+    }
+    newrec->name = strdup(name);
+    newrec->type = type;
+    VECTOR(*new_eal)[j] = newrec;
+
+    if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+      switch (todo) {
+      case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, newrec, merges,
+						  numfunc));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_SUM:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_PROD:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MIN:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MAX:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_LAST:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
+	IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
+	IGRAPH_ERROR("Median calculation not implemented", 
+		     IGRAPH_UNIMPLEMENTED);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
+	IGRAPH_ERROR("Cannot concatenate numeric attributes", 
+		     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:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_func(oldrec, newrec, merges, 
+						  strfunc));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_SUM:
+	IGRAPH_ERROR("Cannot sum strings", IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_PROD:
+	IGRAPH_ERROR("Cannot multiply strings", IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MIN:
+	IGRAPH_ERROR("Cannot find minimum of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MAX:
+	IGRAPH_ERROR("Cannot find maximum of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
+	IGRAPH_ERROR("Cannot calculate mean of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
+	IGRAPH_ERROR("Cannot calculate median of strings", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_first(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_LAST:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_last(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
+	IGRAPH_CHECK(igraph_i_cattributes_sn_concat(oldrec, newrec, merges));
+	break;
+      default:
+	IGRAPH_ERROR("Unknown attribute_combination",
+		     IGRAPH_UNIMPLEMENTED);
+	break;
+      }
+    } else {
+      IGRAPH_ERROR("Unknown attribute type, this should not happen", 
+		   IGRAPH_UNIMPLEMENTED);
+    }
+    
+    j++;    
+  }
+
+  igraph_free(funcs);
+  igraph_free(TODO);
+  IGRAPH_FINALLY_CLEAN(2);    
+  
+  return 0;
+}
+
+int igraph_i_cattribute_get_info(const igraph_t *graph,
+				 igraph_strvector_t *gnames,
+				 igraph_vector_t *gtypes,
+				 igraph_strvector_t *vnames,
+				 igraph_vector_t *vtypes,
+				 igraph_strvector_t *enames,
+				 igraph_vector_t *etypes) {
+  
+  igraph_strvector_t *names[3] = { gnames, vnames, enames };
+  igraph_vector_t *types[3] = { gtypes, vtypes, etypes };
+  igraph_i_cattributes_t *at=graph->attr;
+  igraph_vector_ptr_t *attr[3]={ &at->gal, &at->val, &at->eal };
+  long int i,j;
+
+  for (i=0; i<3; i++) {
+    igraph_strvector_t *n=names[i];
+    igraph_vector_t *t=types[i];
+    igraph_vector_ptr_t *al=attr[i];
+    long int len=igraph_vector_ptr_size(al);
+    
+    if (n) {
+      IGRAPH_CHECK(igraph_strvector_resize(n, len));
+    }
+    if (t) {
+      IGRAPH_CHECK(igraph_vector_resize(t, len));
+    }
+
+    for (j=0; j<len; j++) {
+      igraph_attribute_record_t *rec=VECTOR(*al)[j];
+      const char *name=rec->name;
+      igraph_attribute_type_t type=rec->type;      
+      if (n) {
+	IGRAPH_CHECK(igraph_strvector_set(n, j, name));
+      }
+      if (t) {
+	VECTOR(*t)[j]=type;
+      }
+    }
+  }
+  
+  return 0;
+}
+
+igraph_bool_t igraph_i_cattribute_has_attr(const igraph_t *graph,
+					 igraph_attribute_elemtype_t type,
+					 const char *name) {
+  igraph_i_cattributes_t *at=graph->attr;
+  igraph_vector_ptr_t *attr[3]={ &at->gal, &at->val, &at->eal };
+  long int attrnum;
+
+  switch (type) {
+  case IGRAPH_ATTRIBUTE_GRAPH:
+    attrnum=0;
+    break;
+  case IGRAPH_ATTRIBUTE_VERTEX:
+    attrnum=1;
+    break;
+  case IGRAPH_ATTRIBUTE_EDGE:
+    attrnum=2;
+    break;
+  default:
+    IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL);
+    break;
+  }
+
+  return igraph_i_cattribute_find(attr[attrnum], name, 0);
+}
+
+int igraph_i_cattribute_gettype(const igraph_t *graph,
+			      igraph_attribute_type_t *type,
+			      igraph_attribute_elemtype_t elemtype,
+			      const char *name) {
+  long int attrnum;
+  igraph_attribute_record_t *rec;  
+  igraph_i_cattributes_t *at=graph->attr;
+  igraph_vector_ptr_t *attr[3]={ &at->gal, &at->val, &at->eal };
+  igraph_vector_ptr_t *al;
+  long int j;
+  igraph_bool_t l=0;
+  
+  switch (elemtype) {
+  case IGRAPH_ATTRIBUTE_GRAPH:
+    attrnum=0;
+    break;
+  case IGRAPH_ATTRIBUTE_VERTEX:
+    attrnum=1;
+    break;
+  case IGRAPH_ATTRIBUTE_EDGE:
+    attrnum=2;
+    break;
+  default:
+    IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL);
+    break;
+  }
+
+  al=attr[attrnum];
+  l=igraph_i_cattribute_find(al, name, &j);  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }  
+  rec=VECTOR(*al)[j];
+  *type=rec->type;
+
+  return 0;
+}
+
+int igraph_i_cattribute_get_numeric_graph_attr(const igraph_t *graph,
+					      const char *name,
+					      igraph_vector_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_t *num;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*gal)[j];
+  num=(igraph_vector_t*)rec->value;
+  IGRAPH_CHECK(igraph_vector_resize(value, 1));
+  VECTOR(*value)[0]=VECTOR(*num)[0];
+  
+  return 0;
+}
+
+int igraph_i_cattribute_get_bool_graph_attr(const igraph_t *graph,
+					    const char *name,
+					    igraph_vector_bool_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_bool_t *log;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*gal)[j];
+  log=(igraph_vector_bool_t*)rec->value;
+  IGRAPH_CHECK(igraph_vector_bool_resize(value, 1));
+  VECTOR(*value)[0]=VECTOR(*log)[0];
+  
+  return 0;
+}
+
+int igraph_i_cattribute_get_string_graph_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_strvector_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_strvector_t *str;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*gal)[j];
+  str=(igraph_strvector_t*)rec->value;
+  IGRAPH_CHECK(igraph_strvector_resize(value, 1));
+  IGRAPH_CHECK(igraph_strvector_set(value, 0, STR(*str,0)));
+
+  return 0;
+}
+
+int igraph_i_cattribute_get_numeric_vertex_attr(const igraph_t *graph,
+					      const char *name,
+					      igraph_vs_t vs,
+					      igraph_vector_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_t *num;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*val)[j];
+  num=(igraph_vector_t*)rec->value;
+  if (igraph_vs_is_all(&vs)) {
+    igraph_vector_clear(value);
+    IGRAPH_CHECK(igraph_vector_append(value, num));
+  } 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_resize(value, IGRAPH_VIT_SIZE(it)));
+    for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
+      long int v=IGRAPH_VIT_GET(it);
+      VECTOR(*value)[i]=VECTOR(*num)[v];
+    }
+    igraph_vit_destroy(&it);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+int igraph_i_cattribute_get_bool_vertex_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_vs_t vs,
+					     igraph_vector_bool_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_bool_t *log;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*val)[j];
+  log=(igraph_vector_bool_t*)rec->value;
+  if (igraph_vs_is_all(&vs)) {
+    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);
+      VECTOR(*value)[i]=VECTOR(*log)[v];
+    }
+    igraph_vit_destroy(&it);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+int igraph_i_cattribute_get_string_vertex_attr(const igraph_t *graph,
+					     const char *name,
+					     igraph_vs_t vs,
+					     igraph_strvector_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_strvector_t *str;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*val)[j];
+  str=(igraph_strvector_t*)rec->value;
+  if (igraph_vs_is_all(&vs)) {
+    igraph_strvector_resize(value, 0);
+    IGRAPH_CHECK(igraph_strvector_append(value, str));
+  } else {
+    igraph_vit_t it;
+    long int i=0;
+    IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
+    IGRAPH_FINALLY(igraph_vit_destroy, &it);
+    IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_VIT_SIZE(it)));
+    for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
+      long int v=IGRAPH_VIT_GET(it);
+      char *s;
+      igraph_strvector_get(str, v, &s);
+      IGRAPH_CHECK(igraph_strvector_set(value, i, s));
+    }
+    igraph_vit_destroy(&it);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+int igraph_i_cattribute_get_numeric_edge_attr(const igraph_t *graph,
+					    const char *name,
+					    igraph_es_t es,
+					    igraph_vector_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_t *num;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*eal)[j];
+  num=(igraph_vector_t*)rec->value;
+  if (igraph_es_is_all(&es)) {
+    igraph_vector_clear(value);
+    IGRAPH_CHECK(igraph_vector_append(value, num));
+  } else {
+    igraph_eit_t it;
+    long int i=0;
+    IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
+    IGRAPH_FINALLY(igraph_eit_destroy, &it);
+    IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_EIT_SIZE(it)));
+    for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {
+      long int e=IGRAPH_EIT_GET(it);
+      VECTOR(*value)[i]=VECTOR(*num)[e];
+    }
+    igraph_eit_destroy(&it);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+int igraph_i_cattribute_get_string_edge_attr(const igraph_t *graph,
+					   const char *name,
+					   igraph_es_t es,
+					   igraph_strvector_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_strvector_t *str;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*eal)[j];
+  str=(igraph_strvector_t*)rec->value;
+  if (igraph_es_is_all(&es)) {
+    igraph_strvector_resize(value, 0);
+    IGRAPH_CHECK(igraph_strvector_append(value, str));
+  } else {
+    igraph_eit_t it;
+    long int i=0;
+    IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
+    IGRAPH_FINALLY(igraph_eit_destroy, &it);
+    IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_EIT_SIZE(it)));
+    for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {
+      long int e=IGRAPH_EIT_GET(it);
+      char *s;
+      igraph_strvector_get(str, e, &s);
+      IGRAPH_CHECK(igraph_strvector_set(value, i, s));
+    }
+    igraph_eit_destroy(&it);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+int igraph_i_cattribute_get_bool_edge_attr(const igraph_t *graph,
+					   const char *name,
+					   igraph_es_t es,
+					   igraph_vector_bool_t *value) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_bool_t *log;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (!l) {
+    IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
+  }
+
+  rec=VECTOR(*eal)[j];
+  log=(igraph_vector_bool_t*)rec->value;
+  if (igraph_es_is_all(&es)) {
+    igraph_vector_bool_clear(value);
+    IGRAPH_CHECK(igraph_vector_bool_append(value, log));
+  } else {
+    igraph_eit_t it;
+    long int i=0;
+    IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
+    IGRAPH_FINALLY(igraph_eit_destroy, &it);
+    IGRAPH_CHECK(igraph_vector_bool_resize(value, IGRAPH_EIT_SIZE(it)));
+    for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {
+      long int e=IGRAPH_EIT_GET(it);
+      VECTOR(*value)[i]=VECTOR(*log)[e];
+    }
+    igraph_eit_destroy(&it);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+/* -------------------------------------- */
+
+const igraph_attribute_table_t igraph_cattribute_table={
+  &igraph_i_cattribute_init, &igraph_i_cattribute_destroy,
+  &igraph_i_cattribute_copy, &igraph_i_cattribute_add_vertices,
+  &igraph_i_cattribute_permute_vertices, 
+  &igraph_i_cattribute_combine_vertices, &igraph_i_cattribute_add_edges,
+  &igraph_i_cattribute_permute_edges,
+  &igraph_i_cattribute_combine_edges,
+  &igraph_i_cattribute_get_info,
+  &igraph_i_cattribute_has_attr, &igraph_i_cattribute_gettype,
+  &igraph_i_cattribute_get_numeric_graph_attr,
+  &igraph_i_cattribute_get_string_graph_attr,
+  &igraph_i_cattribute_get_bool_graph_attr,
+  &igraph_i_cattribute_get_numeric_vertex_attr,
+  &igraph_i_cattribute_get_string_vertex_attr,
+  &igraph_i_cattribute_get_bool_vertex_attr,
+  &igraph_i_cattribute_get_numeric_edge_attr,
+  &igraph_i_cattribute_get_string_edge_attr,
+  &igraph_i_cattribute_get_bool_edge_attr
+};
+
+/* -------------------------------------- */
+
+/**
+ * \section cattributes
+ * <para>There is an experimental attribute handler that can be used
+ * from C code. In this section we show how this works. This attribute
+ * handler is by default not attached (the default is no attribute
+ * handler), so we first need to attach it: 
+ * <programlisting>
+ * igraph_i_set_attribute_table(&igraph_cattribute_table);
+ * </programlisting>
+ * </para>
+ * <para>Now the attribute functions are available. Please note that
+ * the attribute handler must be attached before you call any other
+ * igraph functions, otherwise you might end up with graphs without
+ * attributes and an active attribute handler, which might cause
+ * unexpected program behaviour. The rule is that you attach the
+ * attribute handler in the beginning of your
+ * <function>main()</function> and never touch it again. (Detaching
+ * the attribute handler might lead to memory leaks.)</para>
+ * 
+ * <para>It is not currently possible to have attribute handlers on a
+ * per-graph basis. All graphs in an application must be managed with
+ * the same attribute handler. (Including the default case when there
+ * is no attribute handler at all.</para>
+ * 
+ * <para>The C attribute handler supports attaching real numbers and
+ * character strings as attributes. No vectors are allowed, ie. every
+ * vertex might have an attribute called <code>name</code>, but it is
+ * not possible to have a <code>coords</code> graph (or other)
+ * attribute which is a vector of numbers.</para>
+ * 
+ * \example examples/simple/cattributes.c
+ * \example examples/simple/cattributes2.c
+ * \example examples/simple/cattributes3.c
+ * \example examples/simple/cattributes4.c
+ */
+
+/**
+ * \function igraph_cattribute_GAN
+ * Query a numeric graph attribute.
+ * 
+ * Returns the value of the given numeric graph attribute.
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute to query.
+ * \return The value of the attribute.
+ *
+ * \sa \ref GAN for a simpler interface.
+ * 
+ * Time complexity: O(Ag), the number of graph attributes.
+ */
+igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_t *num;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*gal)[j];
+  num=(igraph_vector_t*)rec->value;
+  return VECTOR(*num)[0];
+}
+
+/**
+ * \function igraph_cattribute_GAB
+ * Query a boolean graph attribute.
+ * 
+ * Returns the value of the given numeric graph attribute.
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute to query.
+ * \return The value of the attribute.
+ *
+ * \sa \ref GAB for a simpler interface.
+ * 
+ * Time complexity: O(Ag), the number of graph attributes.
+ */
+igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_bool_t *log;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*gal)[j];
+  log=(igraph_vector_bool_t*)rec->value;
+  return VECTOR(*log)[0];
+}
+
+/**
+ * \function igraph_cattribute_GAS
+ * Query a string graph attribute.
+ * 
+ * Returns a <type>const</type> pointer to the string graph attribute
+ * specified in \p name.
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute to query.
+ * \return The value of the attribute.
+ *
+ * \sa \ref GAS for a simpler interface.
+ * 
+ * Time complexity: O(Ag), the number of graph attributes.
+ */
+const char* igraph_cattribute_GAS(const igraph_t *graph, const char *name) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_strvector_t *str;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*gal)[j];
+  str=(igraph_strvector_t*)rec->value;
+  return STR(*str, 0);  
+}
+
+/**
+ * \function igraph_cattribute_VAN
+ * Query a numeric vertex attribute.
+ * 
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vid The id of the queried vertex.
+ * \return The value of the attribute.
+ * 
+ * \sa \ref VAN macro for a simpler interface.
+ * 
+ * Time complexity: O(Av), the number of vertex attributes.
+ */
+igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name,
+				      igraph_integer_t vid) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_t *num;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*val)[j];
+  num=(igraph_vector_t*)rec->value;
+  return VECTOR(*num)[(long int)vid];
+}
+
+/**
+ * \function igraph_cattribute_VAB
+ * Query a boolean vertex attribute.
+ * 
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vid The id of the queried vertex.
+ * \return The value of the attribute.
+ * 
+ * \sa \ref VAB macro for a simpler interface.
+ * 
+ * Time complexity: O(Av), the number of vertex attributes.
+ */
+igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name,
+				    igraph_integer_t vid) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_bool_t *log;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*val)[j];
+  log=(igraph_vector_bool_t*)rec->value;
+  return VECTOR(*log)[(long int)vid];
+}
+
+/**
+ * \function igraph_cattribute_VAS
+ * Query a string vertex attribute.
+ * 
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vid The id of the queried vertex.
+ * \return The value of the attribute.
+ * 
+ * \sa The macro \ref VAS for a simpler interface.
+ *
+ * Time complexity: O(Av), the number of vertex attributes.
+ */
+const char* igraph_cattribute_VAS(const igraph_t *graph, const char *name,
+				    igraph_integer_t vid) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_strvector_t *str;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*val)[j];
+  str=(igraph_strvector_t*)rec->value;
+  return STR(*str, (long int)vid);  
+}
+
+/**
+ * \function igraph_cattribute_EAN
+ * Query a numeric edge attribute.
+ * 
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param eid The id of the queried edge.
+ * \return The value of the attribute.
+ * 
+ * \sa \ref EAN for an easier interface.
+ *
+ * Time complexity: O(Ae), the number of edge attributes.
+ */
+igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name,
+				      igraph_integer_t eid) {  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_t *num;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*eal)[j];
+  num=(igraph_vector_t*)rec->value;
+  return VECTOR(*num)[(long int)eid];
+}
+
+/**
+ * \function igraph_cattribute_EAB
+ * Query a boolean edge attribute.
+ * 
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param eid The id of the queried edge.
+ * \return The value of the attribute.
+ * 
+ * \sa \ref EAB for an easier interface.
+ *
+ * Time complexity: O(Ae), the number of edge attributes.
+ */
+igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name,
+				    igraph_integer_t eid) {  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_vector_bool_t *log;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+
+  rec=VECTOR(*eal)[j];
+  log=(igraph_vector_bool_t*)rec->value;
+  return VECTOR(*log)[(long int)eid];
+}
+
+/**
+ * \function igraph_cattribute_EAS
+ * Query a string edge attribute.
+ * 
+ * The attribute must exist, otherwise an error is triggered.
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param eid The id of the queried edge.
+ * \return The value of the attribute.
+ *
+ * \se \ref EAS if you want to type less.
+ * 
+ * Time complexity: O(Ae), the number of edge attributes.
+ */
+const char* igraph_cattribute_EAS(const igraph_t *graph, const char *name,
+				    igraph_integer_t eid) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_attribute_record_t *rec;
+  igraph_strvector_t *str;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (!l) {
+    igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
+    return 0;
+  }
+  
+  rec=VECTOR(*eal)[j];
+  str=(igraph_strvector_t*)rec->value;
+  return STR(*str, (long int)eid);  
+}
+
+/**
+ * \function igraph_cattribute_VANV
+ * Query a numeric vertex attribute for many vertices
+ *
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vids The vertices to query.
+ * \param result Pointer to an initialized vector, the result is
+ *    stored here. It will be resized, if needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(v), where v is the number of vertices in 'vids'.
+ */
+
+int igraph_cattribute_VANV(const igraph_t *graph, const char *name, 
+			   igraph_vs_t vids, igraph_vector_t *result) {
+
+  return igraph_i_cattribute_get_numeric_vertex_attr(graph, name, vids, 
+						     result);
+}
+
+/**
+ * \function igraph_cattribute_VABV
+ * Query a boolean vertex attribute for many vertices
+ *
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vids The vertices to query.
+ * \param result Pointer to an initialized boolean vector, the result is
+ *    stored here. It will be resized, if needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(v), where v is the number of vertices in 'vids'.
+ */
+
+int igraph_cattribute_VABV(const igraph_t *graph, const char *name, 
+			   igraph_vs_t vids, igraph_vector_bool_t *result) {
+
+  return igraph_i_cattribute_get_bool_vertex_attr(graph, name, vids, 
+						  result);
+}
+
+/**
+ * \function igraph_cattribute_EANV
+ * Query a numeric edge attribute for many edges
+ *
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param eids The edges to query.
+ * \param result Pointer to an initialized vector, the result is 
+ *    stored here. It will be resized, if needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(e), where e is the number of edges in 'eids'.
+ */
+
+int igraph_cattribute_EANV(const igraph_t *graph, const char *name,
+			   igraph_es_t eids, igraph_vector_t *result) {
+
+  return igraph_i_cattribute_get_numeric_edge_attr(graph, name, eids, 
+						   result);
+}
+
+/**
+ * \function igraph_cattribute_EABV
+ * Query a boolean edge attribute for many edges
+ *
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param eids The edges to query.
+ * \param result Pointer to an initialized boolean vector, the result is 
+ *    stored here. It will be resized, if needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(e), where e is the number of edges in 'eids'.
+ */
+
+int igraph_cattribute_EABV(const igraph_t *graph, const char *name,
+			   igraph_es_t eids, igraph_vector_bool_t *result) {
+
+  return igraph_i_cattribute_get_bool_edge_attr(graph, name, eids, 
+						result);
+}
+
+/**
+ * \function igraph_cattribute_VASV
+ * Query a string vertex attribute for many vertices
+ *
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vids The vertices to query.
+ * \param result Pointer to an initialized string vector, the result
+ *     is stored here. It will be resized, if needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(v), where v is the number of vertices in 'vids'.
+ * (We assume that the string attributes have a bounded length.)
+ */
+
+int igraph_cattribute_VASV(const igraph_t *graph, const char *name, 
+			   igraph_vs_t vids, igraph_strvector_t *result) {
+
+  return igraph_i_cattribute_get_string_vertex_attr(graph, name, vids, 
+						    result);
+}
+
+/**
+ * \function igraph_cattribute_EASV
+ * Query a string edge attribute for many edges
+ *
+ * \param graph The input graph.
+ * \param name The name of the attribute.
+ * \param vids The edges to query.
+ * \param result Pointer to an initialized string vector, the result
+ *     is stored here. It will be resized, if needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(e), where e is the number of edges in
+ * 'eids'. (We assume that the string attributes have a bounded length.)
+ */
+
+int igraph_cattribute_EASV(const igraph_t *graph, const char *name,
+			   igraph_es_t eids, igraph_strvector_t *result) {
+
+  return igraph_i_cattribute_get_string_edge_attr(graph, name, eids, 
+						   result);
+}
+
+/**
+ * \function igraph_cattribute_list
+ * List all attributes
+ * 
+ * See \ref igraph_attribute_type_t for the various attribute types.
+ * \param graph The input graph.
+ * \param gnames String vector, the names of the graph attributes.
+ * \param gtypes Numeric vector, the types of the graph attributes.
+ * \param vnames String vector, the names of the vertex attributes.
+ * \param vtypes Numeric vector, the types of the vertex attributes.
+ * \param enames String vector, the names of the edge attributes.
+ * \param etypes Numeric vector, the types of the edge attributes.
+ * \return Error code.
+ * 
+ * Naturally, the string vector with the attribute names and the
+ * numeric vector with the attribute types are in the right order,
+ * i.e. the first name corresponds to the first type, etc.
+ * 
+ * Time complexity: O(Ag+Av+Ae), the number of all attributes.
+ */
+int igraph_cattribute_list(const igraph_t *graph,
+			   igraph_strvector_t *gnames, igraph_vector_t *gtypes,
+			   igraph_strvector_t *vnames, igraph_vector_t *vtypes,
+			   igraph_strvector_t *enames, igraph_vector_t *etypes) {
+  return igraph_i_cattribute_get_info(graph, gnames, gtypes, vnames, vtypes,
+				      enames, etypes);
+}
+
+/**
+ * \function igraph_cattribute_has_attr
+ * Checks whether a (graph, vertex or edge) attribute exists
+ * 
+ * \param graph The graph.
+ * \param type The type of the attribute, \c IGRAPH_ATTRIBUTE_GRAPH, 
+ *        \c IGRAPH_ATTRIBUTE_VERTEX or \c IGRAPH_ATTRIBUTE_EDGE.
+ * \param name Character constant, the name of the attribute.
+ * \return Logical value, TRUE if the attribute exists, FALSE otherwise.
+ * 
+ * Time complexity: O(A), the number of (graph, vertex or edge) 
+ * attributes, assuming attribute names are not too long.
+ */
+igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph,
+					 igraph_attribute_elemtype_t type,
+					 const char *name) {
+  return igraph_i_cattribute_has_attr(graph, type, name);
+}
+
+/**
+ * \function igraph_cattribute_GAN_set
+ * Set a numeric graph attribute
+ * 
+ * \param graph The graph.
+ * \param name Name of the graph attribute. If there is no such
+ *   attribute yet, then it will be added.
+ * \param value The (new) value of the graph attribute.
+ * \return Error code.
+ * 
+ * \se \ref SETGAN if you want to type less.
+ * 
+ * Time complexity: O(1).
+ */
+int igraph_cattribute_GAN_set(igraph_t *graph, const char *name, 
+			      igraph_real_t value) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*gal)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_vector_t *num=(igraph_vector_t *)rec->value;
+      VECTOR(*num)[0]=value;
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_t *num;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    num=igraph_Calloc(1, igraph_vector_t);
+    if (!num) { 
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, num);
+    IGRAPH_VECTOR_INIT_FINALLY(num, 1);
+    VECTOR(*num)[0]=value;
+    rec->value=num;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_GAB_set
+ * Set a boolean graph attribute
+ * 
+ * \param graph The graph.
+ * \param name Name of the graph attribute. If there is no such
+ *   attribute yet, then it will be added.
+ * \param value The (new) value of the graph attribute.
+ * \return Error code.
+ * 
+ * \se \ref SETGAN if you want to type less.
+ * 
+ * Time complexity: O(1).
+ */
+int igraph_cattribute_GAB_set(igraph_t *graph, const char *name, 
+			      igraph_bool_t value) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*gal)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_vector_bool_t *log=(igraph_vector_bool_t *)rec->value;
+      VECTOR(*log)[0]=value;
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_bool_t *log;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_BOOLEAN;
+    log=igraph_Calloc(1, igraph_vector_bool_t);
+    if (!log) { 
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, log);
+    IGRAPH_CHECK(igraph_vector_bool_init(log, 1));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
+    VECTOR(*log)[0]=value;
+    rec->value=log;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_GAS_set
+ * Set a string graph attribute.
+ * 
+ * \param graph The graph.
+ * \param name Name of the graph attribute. If there is no such
+ *   attribute yet, then it will be added.
+ * \param value The (new) value of the graph attribute. It will be
+ *   copied. 
+ * \return Error code.
+ * 
+ * \se \ref SETGAS if you want to type less.
+ * 
+ * Time complexity: O(1).
+ */
+int igraph_cattribute_GAS_set(igraph_t *graph, const char *name, 
+			      const char *value) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*gal)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_strvector_t *str=(igraph_strvector_t*)rec->value;
+      IGRAPH_CHECK(igraph_strvector_set(str, 0, value));
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_strvector_t *str;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    str=igraph_Calloc(1, igraph_strvector_t);
+    if (!str) {
+      IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, str);
+    IGRAPH_STRVECTOR_INIT_FINALLY(str, 1);
+    IGRAPH_CHECK(igraph_strvector_set(str, 0, value));
+    rec->value=str;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_VAN_set
+ * Set a numeric vertex attribute
+ * 
+ * The attribute will be added if not present already. If present it
+ * will be overwritten. The same \p value is set for all vertices
+ * included in \p vid.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param vid Vertices for which to set the attribute.
+ * \param value The (new) value of the attribute.
+ * \return Error code.
+ * 
+ * \sa \ref SETVAN for a simpler way.
+ * 
+ * Time complexity: O(n), the number of vertices if the attribute is
+ * new, O(|vid|) otherwise.
+ */
+int igraph_cattribute_VAN_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t vid, igraph_real_t value) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*val)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_vector_t *num=(igraph_vector_t*)rec->value;
+      VECTOR(*num)[(long int)vid]=value;
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_t *num;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    num=igraph_Calloc(1, igraph_vector_t);
+    if (!num) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, num);
+    IGRAPH_VECTOR_INIT_FINALLY(num, igraph_vcount(graph));
+    igraph_vector_fill(num, IGRAPH_NAN);
+    VECTOR(*num)[(long int)vid]=value;
+    rec->value=num;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_VAB_set
+ * Set a boolean vertex attribute
+ * 
+ * The attribute will be added if not present already. If present it
+ * will be overwritten. The same \p value is set for all vertices
+ * included in \p vid.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param vid Vertices for which to set the attribute.
+ * \param value The (new) value of the attribute.
+ * \return Error code.
+ * 
+ * \sa \ref SETVAB for a simpler way.
+ * 
+ * Time complexity: O(n), the number of vertices if the attribute is
+ * new, O(|vid|) otherwise.
+ */
+int igraph_cattribute_VAB_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t vid, igraph_bool_t value) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*val)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_vector_bool_t *log=(igraph_vector_bool_t*)rec->value;
+      VECTOR(*log)[(long int)vid]=value;
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_bool_t *log;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_BOOLEAN;
+    log=igraph_Calloc(1, igraph_vector_bool_t);
+    if (!log) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, log);
+    IGRAPH_CHECK(igraph_vector_bool_init(log, igraph_vcount(graph)));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
+    igraph_vector_bool_fill(log, 0);
+    VECTOR(*log)[(long int)vid]=value;
+    rec->value=log;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_VAS_set
+ * Set a string vertex attribute
+ * 
+ * The attribute will be added if not present already. If present it
+ * will be overwritten. The same \p value is set for all vertices
+ * included in \p vid.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param vid Vertices for which to set the attribute.
+ * \param value The (new) value of the attribute.
+ * \return Error code.
+ * 
+ * \sa \ref SETVAS for a simpler way.
+ * 
+ * Time complexity: O(n*l), n is the number of vertices, l is the
+ * length of the string to set. If the attribute if not new then only
+ * O(|vid|*l).
+ */
+int igraph_cattribute_VAS_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t vid, const char *value) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*val)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_strvector_t *str=(igraph_strvector_t*)rec->value;
+      IGRAPH_CHECK(igraph_strvector_set(str, vid, value));
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_strvector_t *str;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    str=igraph_Calloc(1, igraph_strvector_t);
+    if (!str) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, str);
+    IGRAPH_STRVECTOR_INIT_FINALLY(str, igraph_vcount(graph));
+    IGRAPH_CHECK(igraph_strvector_set(str, vid, value));
+    rec->value=str;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_EAN_set
+ * Set a numeric edge attribute
+ * 
+ * The attribute will be added if not present already. If present it
+ * will be overwritten. The same \p value is set for all edges
+ * included in \p vid.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param eid Edges for which to set the attribute.
+ * \param value The (new) value of the attribute.
+ * \return Error code.
+ * 
+ * \sa \ref SETEAN for a simpler way.
+ * 
+ * Time complexity: O(e), the number of edges if the attribute is
+ * new, O(|eid|) otherwise.
+ */
+int igraph_cattribute_EAN_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t eid, igraph_real_t value) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*eal)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_vector_t *num=(igraph_vector_t*)rec->value;
+      VECTOR(*num)[(long int)eid]=value;
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_t *num;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    num=igraph_Calloc(1, igraph_vector_t);
+    if (!num) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, num);
+    IGRAPH_VECTOR_INIT_FINALLY(num, igraph_ecount(graph));
+    igraph_vector_fill(num, IGRAPH_NAN);
+    VECTOR(*num)[(long int)eid]=value;
+    rec->value=num;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_EAB_set
+ * Set a boolean edge attribute
+ * 
+ * The attribute will be added if not present already. If present it
+ * will be overwritten. The same \p value is set for all edges
+ * included in \p vid.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param eid Edges for which to set the attribute.
+ * \param value The (new) value of the attribute.
+ * \return Error code.
+ * 
+ * \sa \ref SETEAB for a simpler way.
+ * 
+ * Time complexity: O(e), the number of edges if the attribute is
+ * new, O(|eid|) otherwise.
+ */
+int igraph_cattribute_EAB_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t eid, igraph_bool_t value) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*eal)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_vector_bool_t *log=(igraph_vector_bool_t*)rec->value;
+      VECTOR(*log)[(long int)eid]=value;
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_bool_t *log;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_BOOLEAN;
+    log=igraph_Calloc(1, igraph_vector_bool_t);
+    if (!log) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, log);
+    IGRAPH_CHECK(igraph_vector_bool_init(log, igraph_ecount(graph)));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
+    igraph_vector_bool_fill(log, 0);
+    VECTOR(*log)[(long int)eid]=value;
+    rec->value=log;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_EAS_set
+ * Set a string edge attribute
+ * 
+ * The attribute will be added if not present already. If present it
+ * will be overwritten. The same \p value is set for all edges
+ * included in \p vid.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param eid Edges for which to set the attribute.
+ * \param value The (new) value of the attribute.
+ * \return Error code.
+ * 
+ * \sa \ref SETEAS for a simpler way.
+ * 
+ * Time complexity: O(e*l), n is the number of edges, l is the
+ * length of the string to set. If the attribute if not new then only
+ * O(|eid|*l).
+ */
+int igraph_cattribute_EAS_set(igraph_t *graph, const char *name, 
+			      igraph_integer_t eid, const char *value) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (l) {
+    igraph_attribute_record_t *rec=VECTOR(*eal)[j];
+    if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
+      IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
+    } else {
+      igraph_strvector_t *str=(igraph_strvector_t*)rec->value;
+      IGRAPH_CHECK(igraph_strvector_set(str, eid, value));
+    }
+  } else {
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_strvector_t *str;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    str=igraph_Calloc(1, igraph_strvector_t);
+    if (!str) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, str);
+    IGRAPH_STRVECTOR_INIT_FINALLY(str, igraph_ecount(graph));
+    IGRAPH_CHECK(igraph_strvector_set(str, eid, value));
+    rec->value=str;
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_VAN_setv
+ * Set a numeric vertex attribute for all vertices.
+ * 
+ * The attribute will be added if not present yet.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param v The new attribute values. The length of this vector must
+ *   match the number of vertices.
+ * \return Error code.
+ * 
+ * \sa \ref SETVANV for a simpler way.
+ * 
+ * Time complexity: O(n), the number of vertices.
+ */
+
+int igraph_cattribute_VAN_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_t *v) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+
+  /* Check length first */
+  if (igraph_vector_size(v) != igraph_vcount(graph)) {
+    IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);
+  }
+  
+  if (l) {
+    /* Already present, check type */
+    igraph_attribute_record_t *rec=VECTOR(*val)[j];
+    igraph_vector_t *num=(igraph_vector_t *)rec->value;
+    if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
+      IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
+    }
+    igraph_vector_clear(num);
+    IGRAPH_CHECK(igraph_vector_append(num, v));
+  } else {
+    /* Add it */
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_t *num;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    num=igraph_Calloc(1, igraph_vector_t);
+    if (!num) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, num);
+    rec->value=num;
+    IGRAPH_CHECK(igraph_vector_copy(num, v));
+    IGRAPH_FINALLY(igraph_vector_destroy, num);
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+/**
+ * \function igraph_cattribute_VAB_setv
+ * Set a boolean vertex attribute for all vertices.
+ * 
+ * The attribute will be added if not present yet.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param v The new attribute values. The length of this boolean vector must
+ *   match the number of vertices.
+ * \return Error code.
+ * 
+ * \sa \ref SETVANV for a simpler way.
+ * 
+ * Time complexity: O(n), the number of vertices.
+ */
+
+int igraph_cattribute_VAB_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_bool_t *v) {
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+
+  /* Check length first */
+  if (igraph_vector_bool_size(v) != igraph_vcount(graph)) {
+    IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);
+  }
+  
+  if (l) {
+    /* Already present, check type */
+    igraph_attribute_record_t *rec=VECTOR(*val)[j];
+    igraph_vector_bool_t *log=(igraph_vector_bool_t *)rec->value;
+    if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
+      IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
+    }
+    igraph_vector_bool_clear(log);
+    IGRAPH_CHECK(igraph_vector_bool_append(log, v));
+  } else {
+    /* Add it */
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_bool_t *log;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->type=IGRAPH_ATTRIBUTE_BOOLEAN;
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    log=igraph_Calloc(1, igraph_vector_bool_t);
+    if (!log) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, log);
+    rec->value=log;
+    IGRAPH_CHECK(igraph_vector_bool_copy(log, v));
+    IGRAPH_FINALLY(igraph_vector_destroy, log);
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_VAS_setv
+ * Set a string vertex attribute for all vertices.
+ * 
+ * The attribute will be added if not present yet.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param sv String vector, the new attribute values. The length of this vector must
+ *   match the number of vertices.
+ * \return Error code.
+ * 
+ * \sa \ref SETVASV for a simpler way.
+ * 
+ * Time complexity: O(n+l), n is the number of vertices, l is the
+ * total length of the strings.
+ */
+int igraph_cattribute_VAS_setv(igraph_t *graph, const char *name,
+			       const igraph_strvector_t *sv) {
+  
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  /* Check length first */
+  if (igraph_strvector_size(sv) != igraph_vcount(graph)) {
+    IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);
+  }
+
+  if (l) {
+    /* Already present, check type */
+    igraph_attribute_record_t *rec=VECTOR(*val)[j];
+    igraph_strvector_t *str=(igraph_strvector_t *)rec->value;
+    if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
+      IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
+    }
+    igraph_strvector_clear(str);
+    IGRAPH_CHECK(igraph_strvector_append(str, sv));
+  } else { 
+    /* Add it */
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_strvector_t *str;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    str=igraph_Calloc(1, igraph_strvector_t);
+    if (!str) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, str);
+    rec->value=str;
+    IGRAPH_CHECK(igraph_strvector_copy(str, sv));
+    IGRAPH_FINALLY(igraph_strvector_destroy, str);
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_EAN_setv
+ * Set a numeric edge attribute for all vertices.
+ * 
+ * The attribute will be added if not present yet.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param v The new attribute values. The length of this vector must
+ *   match the number of edges.
+ * \return Error code.
+ * 
+ * \sa \ref SETEANV for a simpler way.
+ * 
+ * Time complexity: O(e), the number of edges.
+ */
+int igraph_cattribute_EAN_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_t *v) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+
+  /* Check length first */
+  if (igraph_vector_size(v) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);
+  }
+  
+  if (l) {
+    /* Already present, check type */
+    igraph_attribute_record_t *rec=VECTOR(*eal)[j];
+    igraph_vector_t *num=(igraph_vector_t *)rec->value;
+    if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
+      IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
+    }
+    igraph_vector_clear(num);
+    IGRAPH_CHECK(igraph_vector_append(num, v));
+  } else {
+    /* Add it */
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_t *num;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    num=igraph_Calloc(1, igraph_vector_t);
+    if (!num) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, num);
+    rec->value=num;
+    IGRAPH_CHECK(igraph_vector_copy(num, v));
+    IGRAPH_FINALLY(igraph_vector_destroy, num);
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_EAB_setv
+ * Set a boolean edge attribute for all vertices.
+ * 
+ * The attribute will be added if not present yet.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param v The new attribute values. The length of this vector must
+ *   match the number of edges.
+ * \return Error code.
+ * 
+ * \sa \ref SETEABV for a simpler way.
+ * 
+ * Time complexity: O(e), the number of edges.
+ */
+int igraph_cattribute_EAB_setv(igraph_t *graph, const char *name, 
+			       const igraph_vector_bool_t *v) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+
+  /* Check length first */
+  if (igraph_vector_bool_size(v) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);
+  }
+  
+  if (l) {
+    /* Already present, check type */
+    igraph_attribute_record_t *rec=VECTOR(*eal)[j];
+    igraph_vector_bool_t *log=(igraph_vector_bool_t *)rec->value;
+    if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
+      IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
+    }
+    igraph_vector_bool_clear(log);
+    IGRAPH_CHECK(igraph_vector_bool_append(log, v));
+  } else {
+    /* Add it */
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_vector_bool_t *log;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->type=IGRAPH_ATTRIBUTE_BOOLEAN;
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    log=igraph_Calloc(1, igraph_vector_bool_t);
+    if (!log) {
+      IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, log);
+    rec->value=log;
+    IGRAPH_CHECK(igraph_vector_bool_copy(log, v));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_cattribute_EAS_setv
+ * Set a string edge attribute for all vertices.
+ * 
+ * The attribute will be added if not present yet.
+ * \param graph The graph.
+ * \param name Name of the attribute.
+ * \param sv String vector, the new attribute values. The length of this vector must
+ *   match the number of edges.
+ * \return Error code.
+ * 
+ * \sa \ref SETEASV for a simpler way.
+ * 
+ * Time complexity: O(e+l), e is the number of edges, l is the
+ * total length of the strings.
+ */
+int igraph_cattribute_EAS_setv(igraph_t *graph, const char *name,
+			       const igraph_strvector_t *sv) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  /* Check length first */
+  if (igraph_strvector_size(sv) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);
+  }
+
+  if (l) {
+    /* Already present, check type */
+    igraph_attribute_record_t *rec=VECTOR(*eal)[j];
+    igraph_strvector_t *str=(igraph_strvector_t *)rec->value;
+    if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
+      IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
+    }
+    igraph_strvector_clear(str);
+    IGRAPH_CHECK(igraph_strvector_append(str, sv));
+  } else { 
+    /* Add it */
+    igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);
+    igraph_strvector_t *str;
+    if (!rec) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, rec);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    rec->name=strdup(name);
+    if (!rec->name) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (char*)rec->name);
+    str=igraph_Calloc(1, igraph_strvector_t);
+    if (!str) {
+      IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, str);
+    rec->value=str;
+    IGRAPH_CHECK(igraph_strvector_copy(str, sv));
+    IGRAPH_FINALLY(igraph_strvector_destroy, str);
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
+    IGRAPH_FINALLY_CLEAN(4);
+  }
+
+  return 0;
+}
+
+void igraph_i_cattribute_free_rec(igraph_attribute_record_t *rec) {
+  
+  if (rec->type==IGRAPH_ATTRIBUTE_NUMERIC) {
+    igraph_vector_t *num=(igraph_vector_t*)rec->value;
+    igraph_vector_destroy(num);
+  } else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
+    igraph_strvector_t *str=(igraph_strvector_t*)rec->value;
+    igraph_strvector_destroy(str);
+  }
+  igraph_Free(rec->name);
+  igraph_Free(rec->value);
+  igraph_Free(rec);
+}
+
+/**
+ * \function igraph_cattribute_remove_g
+ * Remove a graph attribute
+ * 
+ * \param graph The graph object.
+ * \param name Name of the graph attribute to remove.
+ * 
+ * \sa \ref DELGA for a simpler way.
+ * 
+ */
+void igraph_cattribute_remove_g(igraph_t *graph, const char *name) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *gal=&attr->gal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(gal, name, &j);
+  
+  if (l) {
+    igraph_i_cattribute_free_rec(VECTOR(*gal)[j]);
+    igraph_vector_ptr_remove(gal, j);
+  } else {
+    IGRAPH_WARNING("Cannot remove non-existent graph attribute");
+  }  
+}
+
+/**
+ * \function igraph_cattribute_remove_v
+ * Remove a vertex attribute
+ * 
+ * \param graph The graph object.
+ * \param name Name of the vertex attribute to remove.
+ * 
+ * \sa \ref DELVA for a simpler way.
+ * 
+ */
+void igraph_cattribute_remove_v(igraph_t *graph, const char *name) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *val=&attr->val;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
+  
+  if (l) {
+    igraph_i_cattribute_free_rec(VECTOR(*val)[j]);
+    igraph_vector_ptr_remove(val, j);
+  } else {
+    IGRAPH_WARNING("Cannot remove non-existent graph attribute");
+  }  
+}
+
+/**
+ * \function igraph_cattribute_remove_e
+ * Remove an edge attribute
+ * 
+ * \param graph The graph object.
+ * \param name Name of the edge attribute to remove.
+ * 
+ * \sa \ref DELEA for a simpler way.
+ * 
+ */
+void igraph_cattribute_remove_e(igraph_t *graph, const char *name) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+  igraph_vector_ptr_t *eal=&attr->eal;
+  long int j;
+  igraph_bool_t l=igraph_i_cattribute_find(eal, name, &j);
+  
+  if (l) {
+    igraph_i_cattribute_free_rec(VECTOR(*eal)[j]);
+    igraph_vector_ptr_remove(eal, j);
+  } else {
+    IGRAPH_WARNING("Cannot remove non-existent graph attribute");
+  }  
+}
+
+/**
+ * \function igraph_cattribute_remove_all
+ * Remove all graph/vertex/edge attributes
+ * 
+ * \param graph The graph object.
+ * \param g Boolean, whether to remove graph attributes.
+ * \param v Boolean, whether to remove vertex attributes.
+ * \param e Boolean, whether to remove edge attributes.
+ * 
+ * \sa \ref DELGAS, \ref DELVAS, \ref DELEAS, \ref DELALL for simpler
+ * ways.
+ */
+void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g,
+				  igraph_bool_t v, igraph_bool_t e) {
+
+  igraph_i_cattributes_t *attr=graph->attr;
+
+  if (g) {
+    igraph_vector_ptr_t *gal=&attr->gal;
+    long int i, n=igraph_vector_ptr_size(gal);
+    for (i=0;i<n;i++) {
+      igraph_i_cattribute_free_rec(VECTOR(*gal)[i]);
+    }
+    igraph_vector_ptr_clear(gal);
+  }
+  if (v) {
+    igraph_vector_ptr_t *val=&attr->val;
+    long int i, n=igraph_vector_ptr_size(val);
+    for (i=0;i<n;i++) {
+      igraph_i_cattribute_free_rec(VECTOR(*val)[i]);
+    }
+    igraph_vector_ptr_clear(val);    
+  }
+  if (e) {
+    igraph_vector_ptr_t *eal=&attr->eal;
+    long int i, n=igraph_vector_ptr_size(eal);
+    for (i=0;i<n;i++) {
+      igraph_i_cattribute_free_rec(VECTOR(*eal)[i]);
+    }
+    igraph_vector_ptr_clear(eal);
+  }
+}
diff --git a/src/centrality.c b/src/centrality.c
new file mode 100644
index 0000000..fb15908
--- /dev/null
+++ b/src/centrality.c
@@ -0,0 +1,3380 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   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 <math.h>
+#include <string.h>    /* memset */
+#include <assert.h>
+#include "igraph_centrality.h"
+#include "igraph_math.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_topology.h"
+#include "igraph_types_internal.h"
+#include "igraph_stack.h"
+#include "igraph_dqueue.h"
+#include "config.h"
+
+#include "bigint.h"
+#include "prpack.h"
+
+int igraph_personalized_pagerank_arpack(const igraph_t *graph, 
+		    igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    igraph_vector_t *reset,
+		    const igraph_vector_t *weights,
+		    igraph_arpack_options_t *options);
+
+igraph_bool_t igraph_i_vector_mostly_negative(const igraph_vector_t *vector) {
+  /* Many of the centrality measures correspond to the eigenvector of some
+   * matrix. When v is an eigenvector, c*v is also an eigenvector, therefore
+   * it may happen that all the scores in the eigenvector are negative, in which
+   * case we want to negate them since the centrality scores should be positive.
+   * However, since ARPACK is not always stable, sometimes it happens that
+   * *some* of the centrality scores are small negative numbers. This function
+   * helps distinguish between the two cases; it should return true if most of
+   * the values are relatively large negative numbers, in which case we should
+   * negate the eigenvector.
+   */
+  long int i, n = igraph_vector_size(vector);
+  igraph_real_t mi, ma;
+
+  if (n == 0)
+    return 0;
+
+  mi = ma = VECTOR(*vector)[0];
+  for (i = 1; i < n; i++) {
+    if (VECTOR(*vector)[i] < mi)
+      mi = VECTOR(*vector)[i];
+    if (VECTOR(*vector)[i] > ma)
+      ma = VECTOR(*vector)[i];
+  }
+
+  if (mi >= 0)
+    return 0;
+  if (ma <= 0)
+    return 1;
+
+  mi /= ma;
+  return (mi < 1e-5) ? 1 : 0;
+}
+
+int igraph_i_eigenvector_centrality(igraph_real_t *to, const igraph_real_t *from,
+				    int n, void *extra) {
+  igraph_adjlist_t *adjlist=extra;
+  igraph_vector_int_t *neis;
+  long int i, j, nlen;
+  
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(adjlist, 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];
+    }
+  }				      
+  
+  
+  return 0;
+}
+
+typedef struct igraph_i_eigenvector_centrality_t {
+  const igraph_t *graph;
+  const igraph_inclist_t *inclist;
+  const igraph_vector_t *weights;
+} igraph_i_eigenvector_centrality_t;
+
+int igraph_i_eigenvector_centrality2(igraph_real_t *to, const igraph_real_t *from,
+				     int n, void *extra) {
+
+  igraph_i_eigenvector_centrality_t *data=extra;
+  const igraph_t *graph=data->graph;
+  const igraph_inclist_t *inclist=data->inclist;
+  const igraph_vector_t *weights=data->weights;
+  igraph_vector_t *edges;
+  long int i, j, nlen;
+
+  for (i=0; i<n; i++) {
+    edges=igraph_inclist_get(inclist, i);
+    nlen=igraph_vector_size(edges);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=(long int) VECTOR(*edges)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      to[i] += w * from[nei];
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_eigenvector_centrality_loop(igraph_adjlist_t *adjlist) {
+  
+  long int i, j, k, nlen, n=igraph_adjlist_size(adjlist);
+  igraph_vector_int_t *neis;
+
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(adjlist, i);
+    nlen=igraph_vector_int_size(neis);    
+    for (j=0; j<nlen && VECTOR(*neis)[j]<i; j++) ;
+    for (k=j; k<nlen && VECTOR(*neis)[k]==i; k++) ;
+    if (k!=j) {
+      /* First loop edge is 'j', first non-loop edge is 'k' */
+      igraph_vector_int_remove_section(neis, j+(k-j)/2, k);
+    }
+  }
+
+  return 0;
+}
+
+int igraph_eigenvector_centrality_undirected(const igraph_t *graph, igraph_vector_t *vector,
+					     igraph_real_t *value, igraph_bool_t scale,
+					     const igraph_vector_t *weights,
+					     igraph_arpack_options_t *options) {
+  
+  igraph_vector_t values;
+  igraph_matrix_t vectors;
+  igraph_vector_t degree;
+  long int i;
+  
+  options->n=igraph_vcount(graph);
+  options->start=1;		/* no random start vector */
+
+  if (igraph_ecount(graph) == 0) {
+    /* special case: empty graph */
+    if (value)
+      *value = 0;
+    if (vector) {
+      igraph_vector_resize(vector, igraph_vcount(graph));
+      igraph_vector_fill(vector, 1);
+    }
+	return IGRAPH_SUCCESS;
+  }
+
+  if (weights) {
+	igraph_real_t min, max;
+
+    if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+      IGRAPH_ERROR("Invalid length of weights vector when calculating "
+                   "eigenvector centrality", IGRAPH_EINVAL);
+	}
+    IGRAPH_CHECK(igraph_vector_minmax(weights, &min, &max));
+    if (min == 0 && max == 0) {
+      /* special case: all weights are zeros */
+      if (value)
+        *value = 0;
+      if (vector) {
+        igraph_vector_resize(vector, igraph_vcount(graph));
+        igraph_vector_fill(vector, 1);
+      }
+      return IGRAPH_SUCCESS;
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&values, 0);
+  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, options->n);
+  IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), 
+			     IGRAPH_ALL, /*loops=*/ 0));
+  RNG_BEGIN();
+  for (i=0; i<options->n; i++) {
+    if (VECTOR(degree)[i]) {
+      MATRIX(vectors, i, 0) = VECTOR(degree)[i] + RNG_UNIF(-1e-4, 1e-4);
+    } else {
+      MATRIX(vectors, i, 0) = 1.0;
+    }
+  }
+  RNG_END();
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  options->n = igraph_vcount(graph);
+  options->nev = 1;
+  options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rssolve */
+  options->which[0]='L'; options->which[1]='A';
+  options->start=1;		/* no random start vector */
+
+  if (!weights) {
+    
+    igraph_adjlist_t adjlist;
+
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+    IGRAPH_CHECK(igraph_i_eigenvector_centrality_loop(&adjlist));
+    
+    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigenvector_centrality,
+				       &adjlist, options, 0, &values, &vectors));
+
+    igraph_adjlist_destroy(&adjlist);
+    IGRAPH_FINALLY_CLEAN(1);
+    
+  } else {
+    
+    igraph_inclist_t inclist;
+    igraph_i_eigenvector_centrality_t data = { graph, &inclist, weights };
+    
+    IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+
+    IGRAPH_CHECK(igraph_inclist_remove_duplicate(graph, &inclist));
+    
+    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigenvector_centrality2,
+				       &data, options, 0, &values, &vectors));
+    
+    igraph_inclist_destroy(&inclist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (value) {
+    *value=VECTOR(values)[0];
+  }
+  
+  if (vector) {
+    igraph_real_t amax=0;
+    long int which=0;
+    long int i;
+    IGRAPH_CHECK(igraph_vector_resize(vector, options->n));
+
+    if (VECTOR(values)[0] <= 0) {
+      /* Pathological case: largest eigenvalue is zero, therefore all the
+       * scores can also be zeros, this will be a valid eigenvector.
+       * This usually happens with graphs that have lots of sinks and
+       * sources only. */
+      igraph_vector_fill(vector, 0);
+    } else {
+      for (i=0; i<options->n; i++) {
+        igraph_real_t tmp;
+        VECTOR(*vector)[i] = MATRIX(vectors, i, 0);
+        tmp=fabs(VECTOR(*vector)[i]);
+        if (tmp>amax) { amax=tmp; which=i; }
+      }
+      if (scale && amax!=0) { 
+        igraph_vector_scale(vector, 1/VECTOR(*vector)[which]); 
+      } else if (igraph_i_vector_mostly_negative(vector)) {
+        igraph_vector_scale(vector, -1.0);
+      }
+
+      /* Correction for numeric inaccuracies (eliminating -0.0) */
+      for (i=0; i<options->n; i++) {
+        if (VECTOR(*vector)[i] < 0)
+		    VECTOR(*vector)[i] = 0;
+      }
+    }
+  }
+
+  if (options->info) {
+    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
+  }
+  
+  igraph_matrix_destroy(&vectors);
+  igraph_vector_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/* int igraph_i_evcent_dir(igraph_real_t *to, const igraph_real_t *from, */
+/* 			long int n, void *extra) { */
+/*   /\* TODO *\/ */
+/*   return 0; */
+/* } */
+
+/* int igraph_i_evcent_dir2(igraph_real_t *to, const igraph_real_t *from, */
+/* 			 long int n, void *extra) { */
+/*   /\* TODO *\/ */
+/*   return 0; */
+/* } */
+
+int igraph_eigenvector_centrality_directed(const igraph_t *graph, igraph_vector_t *vector,
+					   igraph_real_t *value, igraph_bool_t scale,
+					   const igraph_vector_t *weights,
+					   igraph_arpack_options_t *options) {
+  
+  igraph_matrix_t values;
+  igraph_matrix_t vectors;
+  igraph_vector_t indegree;
+  igraph_bool_t dag;
+  long int i;
+
+  if (igraph_ecount(graph) == 0) {
+    /* special case: empty graph */
+    if (value)
+      *value = 0;
+    if (vector) {
+      igraph_vector_resize(vector, igraph_vcount(graph));
+      igraph_vector_fill(vector, 1);
+    }
+    return IGRAPH_SUCCESS;
+  }
+
+  /* Quick check: if the graph is a DAG, all the eigenvector centralities are
+   * zeros, and so is the eigenvalue */
+  IGRAPH_CHECK(igraph_is_dag(graph, &dag));
+  if (dag) {
+    /* special case: graph is a DAG */
+    IGRAPH_WARNING("graph is directed and acyclic; eigenvector centralities "
+        "will be zeros");
+    if (value)
+      *value = 0;
+    if (vector) {
+      igraph_vector_resize(vector, igraph_vcount(graph));
+      igraph_vector_fill(vector, 0);
+    }
+    return IGRAPH_SUCCESS;
+  }
+
+  if (weights) {
+    igraph_real_t min, max;
+
+    if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+      IGRAPH_ERROR("Invalid length of weights vector when calculating "
+                   "eigenvector centrality", IGRAPH_EINVAL);
+    }
+    if (igraph_is_directed(graph)) {
+      IGRAPH_WARNING("Weighted directed graph in eigenvector centrality");
+    }
+
+	IGRAPH_CHECK(igraph_vector_minmax(weights, &min, &max));
+
+	if (min < 0.0) {
+      IGRAPH_WARNING("Negative weights, eigenpair might be complex");
+    }
+    if (min == 0.0 && max == 0.0) {
+      /* special case: all weights are zeros */
+      if (value)
+        *value = 0;
+      if (vector) {
+        igraph_vector_resize(vector, igraph_vcount(graph));
+        igraph_vector_fill(vector, 1);
+      }
+      return IGRAPH_SUCCESS;
+    }
+  }
+
+  options->n=igraph_vcount(graph);
+  options->start=1;
+  options->nev=1;
+  options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rnsolve */
+  /* LM mode is not OK here because +1 and -1 can be eigenvalues at the
+   * same time, e.g.: a -> b -> a, c -> a */
+  options->which[0]='L' ; options->which[1]='R';
+
+  IGRAPH_MATRIX_INIT_FINALLY(&values, 0, 0);
+  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&indegree, options->n);
+  IGRAPH_CHECK(igraph_strength(graph, &indegree, igraph_vss_all(), 
+	       IGRAPH_IN, /*loops=*/ 1, weights));
+  RNG_BEGIN();
+  for (i=0; i<options->n; i++) {
+    if (VECTOR(indegree)[i]) {
+      MATRIX(vectors, i, 0) = VECTOR(indegree)[i] + RNG_UNIF(-1e-4, 1e-4);
+    } else {
+      MATRIX(vectors, i, 0) = 1.0;
+    }
+  }
+  RNG_END();
+  igraph_vector_destroy(&indegree);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  if (!weights) {
+    igraph_adjlist_t adjlist;
+
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+    
+    IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_eigenvector_centrality,
+				       &adjlist, options, 0, &values, 
+				       &vectors));
+    
+    igraph_adjlist_destroy(&adjlist);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    igraph_inclist_t inclist;
+    igraph_i_eigenvector_centrality_t data={ graph, &inclist, weights };
+
+    IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); 
+    
+    IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_eigenvector_centrality2,
+				       &data, options, 0, &values, &vectors));
+    
+    igraph_inclist_destroy(&inclist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (value) {
+    *value=MATRIX(values, 0, 0);
+  }
+
+  if (vector) {
+    igraph_real_t amax=0;
+    long int which=0;
+    long int i;
+    IGRAPH_CHECK(igraph_vector_resize(vector, options->n));
+
+    if (MATRIX(values, 0, 0) <= 0) {
+      /* Pathological case: largest eigenvalue is zero, therefore all the
+       * scores can also be zeros, this will be a valid eigenvector.
+       * This usually happens with graphs that have lots of sinks and
+       * sources only. */
+      igraph_vector_fill(vector, 0);
+      MATRIX(values, 0, 0) = 0;
+    } else {
+      for (i=0; i<options->n; i++) {
+        igraph_real_t tmp;
+        VECTOR(*vector)[i] = MATRIX(vectors, i, 0);
+        tmp=fabs(VECTOR(*vector)[i]);
+        if (tmp>amax) { amax=tmp; which=i; }
+      }
+      if (scale && amax!=0) { 
+        igraph_vector_scale(vector, 1/VECTOR(*vector)[which]); 
+      } else if (igraph_i_vector_mostly_negative(vector)) {
+        igraph_vector_scale(vector, -1.0);
+      }
+    }
+
+    /* Correction for numeric inaccuracies (eliminating -0.0) */
+    for (i=0; i<options->n; i++) {
+      if (VECTOR(*vector)[i] < 0)
+		    VECTOR(*vector)[i] = 0;
+    }
+  }
+
+  if (options->info) {
+    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
+  }
+  
+  igraph_matrix_destroy(&vectors);
+  igraph_matrix_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(2);  
+
+  return 0;
+}
+
+/**
+ * \function igraph_eigenvector_centrality
+ * Eigenvector centrality of the vertices
+ * 
+ * Eigenvector centrality is a measure of the importance of a node in a
+ * network. It assigns relative scores to all nodes in the network based
+ * on the principle that connections to high-scoring nodes contribute
+ * more to the score of the node in question than equal connections to
+ * low-scoring nodes. In practice, this is determined by calculating the
+ * eigenvector corresponding to the largest positive eigenvalue of the
+ * adjacency matrix. The centrality scores returned by igraph are always
+ * normalized such that the largest eigenvector centrality score is one
+ * (with one exception, see below).
+ *
+ * </para><para>
+ * Since the eigenvector centrality scores of nodes in different components
+ * do not affect each other, it may be beneficial for large graphs to
+ * decompose it first into weakly connected components and calculate the
+ * centrality scores individually for each component.
+ *
+ * </para><para>
+ * Also note that the adjacency matrix of a directed acyclic graph or the
+ * adjacency matrix of an empty graph does not possess positive eigenvalues,
+ * therefore the eigenvector centrality is not defined for these graphs.
+ * igraph will return an eigenvalue of zero in such cases. The eigenvector
+ * centralities will all be equal for an empty graph and will all be zeros
+ * for a directed acyclic graph. Such pathological cases can be detected
+ * by asking igraph to calculate the eigenvalue as well (using the \p value
+ * parameter, see below) and checking whether the eigenvalue is very close
+ * to zero.
+ *
+ * \param graph The input graph. It might be directed.
+ * \param vector Pointer to an initialized vector, it will be resized
+ *     as needed. The result of the computation is stored here. It can
+ *     be a null pointer, then it is ignored.
+ * \param value If not a null pointer, then the eigenvalue
+ *     corresponding to the found eigenvector is stored here.
+ * \param directed Boolean scalar, whether to consider edge directions
+ *     in a directed graph. It is ignored for undirected graphs.
+ * \param scale If not zero then the result will be scaled such that
+ *     the absolute value of the maximum centrality is one.
+ * \param weights A null pointer (=no edge weights), or a vector
+ *     giving the weights of the edges. The algorithm might result
+ *     complex numbers is some weights are negative. In this case only
+ *     the real part is reported.
+ * \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) parameter and 
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \return Error code.
+ * 
+ * Time complexity: depends on the input graph, usually it is O(|V|+|E|).
+ * 
+ * \sa \ref igraph_pagerank and \ref igraph_personalized_pagerank for 
+ *   modifications of eigenvector centrality.
+ * 
+ * \example examples/simple/eigenvector_centrality.c
+ */
+
+int igraph_eigenvector_centrality(const igraph_t *graph, 
+				  igraph_vector_t *vector,
+				  igraph_real_t *value, 
+				  igraph_bool_t directed, igraph_bool_t scale,
+				  const igraph_vector_t *weights,
+				  igraph_arpack_options_t *options) {
+
+  if (directed && igraph_is_directed(graph)) {
+    return igraph_eigenvector_centrality_directed(graph, vector, value,
+						  scale, weights, options);
+  } else {
+    return igraph_eigenvector_centrality_undirected(graph, vector, value, 
+						    scale, weights, options);
+  }
+}
+
+/* struct for the unweighted variant of the HITS algorithm */
+typedef struct igraph_i_kleinberg_data_t {
+  igraph_adjlist_t *in;
+  igraph_adjlist_t *out;
+  igraph_vector_t *tmp;
+} igraph_i_kleinberg_data_t;
+
+/* struct for the weighted variant of the HITS algorithm */
+typedef struct igraph_i_kleinberg_data2_t {
+  const igraph_t *graph;
+  igraph_inclist_t *in;
+  igraph_inclist_t *out;
+  igraph_vector_t *tmp;
+  const igraph_vector_t *weights;
+} igraph_i_kleinberg_data2_t;
+
+/* ARPACK auxiliary routine for the unweighted HITS algorithm */
+int igraph_i_kleinberg_unweighted(igraph_real_t *to,
+                                  const igraph_real_t *from,
+                                  int n, void *extra) {
+  igraph_i_kleinberg_data_t *data = (igraph_i_kleinberg_data_t*)extra;
+  igraph_adjlist_t *in = data->in;
+  igraph_adjlist_t *out = data->out;
+  igraph_vector_t *tmp = data->tmp;
+  igraph_vector_int_t *neis;
+  long int i, j, nlen;
+  
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(in, 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];
+    }
+  }
+  
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(out, 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];
+    }
+  }      
+  
+  return 0;
+}
+
+/* ARPACK auxiliary routine for the weighted HITS algorithm */
+int igraph_i_kleinberg_weighted(igraph_real_t *to,
+                                const igraph_real_t *from,
+                                int n, void *extra) {
+
+  igraph_i_kleinberg_data2_t *data = (igraph_i_kleinberg_data2_t*)extra;
+  igraph_inclist_t *in = data->in; 
+  igraph_inclist_t *out = data->out; 
+  igraph_vector_t *tmp = data->tmp;
+  const igraph_vector_t *weights = data->weights; 
+  const igraph_t *g = data->graph;
+  igraph_vector_t *neis;
+  long int i, j, nlen;
+  
+  for (i=0; i<n; i++) {
+    neis=igraph_inclist_get(in, i);
+    nlen=igraph_vector_size(neis);
+    VECTOR(*tmp)[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei_edge = (long int) VECTOR(*neis)[j];
+      long int nei=IGRAPH_OTHER(g, nei_edge, i);
+      VECTOR(*tmp)[i] += from[nei] * VECTOR(*weights)[nei_edge];
+    }
+  }
+  
+  for (i=0; i<n; i++) {
+    neis=igraph_inclist_get(out, i);
+    nlen=igraph_vector_size(neis);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei_edge=(long int) VECTOR(*neis)[j];
+      long int nei=IGRAPH_OTHER(g, nei_edge, i);
+      to[i] += VECTOR(*tmp)[nei] * VECTOR(*weights)[nei_edge];
+    }
+  }      
+  
+  return 0;
+}
+
+int igraph_i_kleinberg(const igraph_t *graph, igraph_vector_t *vector,
+		       igraph_real_t *value, igraph_bool_t scale,
+			   const igraph_vector_t *weights,
+		       igraph_arpack_options_t *options, int inout) {
+  
+  igraph_adjlist_t myinadjlist, myoutadjlist;
+  igraph_inclist_t myininclist, myoutinclist;
+  igraph_adjlist_t *inadjlist, *outadjlist;
+  igraph_inclist_t *ininclist, *outinclist;
+  igraph_vector_t tmp;
+  igraph_vector_t values;
+  igraph_matrix_t vectors;
+  igraph_i_kleinberg_data_t extra;
+  igraph_i_kleinberg_data2_t extra2;
+  long int i;
+
+  if (igraph_ecount(graph) == 0 || igraph_vcount(graph) == 1) {
+    /* special case: empty graph or single vertex */
+    if (value)
+      *value = igraph_ecount(graph) ? 1.0 : IGRAPH_NAN;
+    if (vector) {
+      igraph_vector_resize(vector, igraph_vcount(graph));
+      igraph_vector_fill(vector, 1);
+    }
+	return IGRAPH_SUCCESS;
+  }
+
+  if (weights) {
+	igraph_real_t min, max;
+
+    if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+      IGRAPH_ERROR("Invalid length of weights vector when calculating "
+                   "hub or authority scores", IGRAPH_EINVAL);
+	}
+    IGRAPH_CHECK(igraph_vector_minmax(weights, &min, &max));
+    if (min == 0 && max == 0) {
+      /* special case: all weights are zeros */
+      if (value)
+        *value = IGRAPH_NAN;
+      if (vector) {
+        igraph_vector_resize(vector, igraph_vcount(graph));
+        igraph_vector_fill(vector, 1);
+      }
+      return IGRAPH_SUCCESS;
+    }
+  }
+
+  options->n=igraph_vcount(graph);
+  options->start=1;     /* no random start vector */
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&values, 0);
+  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, options->n);
+  
+  if (inout==0) {
+    inadjlist=&myinadjlist; 
+    outadjlist=&myoutadjlist;
+    ininclist=&myininclist;
+    outinclist=&myoutinclist;
+  } else if (inout==1) {
+    inadjlist=&myoutadjlist;
+    outadjlist=&myinadjlist;
+    ininclist=&myoutinclist;
+    outinclist=&myininclist;
+  } else {
+    /* This should not happen */
+    IGRAPH_ERROR("Invalid 'inout' argument, please do not call "
+                 "this function directly", IGRAPH_FAILURE);
+  }
+
+  if (weights == 0) {
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &myinadjlist, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &myinadjlist);
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &myoutadjlist, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &myoutadjlist);
+  } else {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &myininclist, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &myininclist);
+    IGRAPH_CHECK(igraph_inclist_init(graph, &myoutinclist, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &myoutinclist);
+  }
+
+  IGRAPH_CHECK(igraph_degree(graph, &tmp, igraph_vss_all(), IGRAPH_ALL, 0));
+  for (i=0; i<options->n; i++) {
+    if (VECTOR(tmp)[i] != 0) { 
+      MATRIX(vectors, i, 0) = VECTOR(tmp)[i];
+    } else {
+      MATRIX(vectors, i, 0) = 1.0;
+    }
+  }
+	
+  extra.in=inadjlist; extra.out=outadjlist; extra.tmp=&tmp;
+  extra2.in=ininclist; extra2.out=outinclist; extra2.tmp=&tmp;
+  extra2.graph=graph; extra2.weights=weights;
+
+  options->nev = 1;
+  options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rssolve */
+  options->which[0]='L'; options->which[1]='M';
+
+  if (weights == 0) {
+    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_kleinberg_unweighted, &extra,
+                                       options, 0, &values, &vectors));
+    igraph_adjlist_destroy(&myoutadjlist);
+    igraph_adjlist_destroy(&myinadjlist);
+	IGRAPH_FINALLY_CLEAN(2);
+  } else {
+    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_kleinberg_weighted, &extra2,
+                                       options, 0, &values, &vectors));
+    igraph_inclist_destroy(&myoutinclist);
+    igraph_inclist_destroy(&myininclist);
+	IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  if (value) { 
+    *value = VECTOR(values)[0];
+  }
+
+  if (vector) {
+    igraph_real_t amax=0;
+    long int which=0;
+    long int i;
+    IGRAPH_CHECK(igraph_vector_resize(vector, options->n));
+    for (i=0; i<options->n; i++) {
+      igraph_real_t tmp;
+      VECTOR(*vector)[i] = MATRIX(vectors, i, 0);
+      tmp=fabs(VECTOR(*vector)[i]);
+      if (tmp>amax) { amax=tmp; which=i; }
+    }
+    if (scale && amax!=0) {
+      igraph_vector_scale(vector, 1/VECTOR(*vector)[which]);
+    } else if (igraph_i_vector_mostly_negative(vector)) {
+      igraph_vector_scale(vector, -1.0);
+	}
+
+    /* Correction for numeric inaccuracies (eliminating -0.0) */
+    for (i=0; i<options->n; i++) {
+      if (VECTOR(*vector)[i] < 0)
+		  VECTOR(*vector)[i] = 0;
+    }
+  }
+  
+  if (options->info) {
+    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
+  }
+  igraph_matrix_destroy(&vectors);
+  igraph_vector_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_hub_score
+ * Kleinberg's hub scores
+ * 
+ * The hub scores of the vertices are defined as the principal
+ * eigenvector of <code>A*A^T</code>, where <code>A</code> is the adjacency
+ * matrix of the graph, <code>A^T</code> is its transposed.
+ * </para><para> 
+ * See the following reference on the meaning of this score:
+ * J. Kleinberg. Authoritative sources in a hyperlinked
+ * environment. \emb Proc. 9th ACM-SIAM Symposium on Discrete
+ * Algorithms, \eme 1998. Extended version in \emb Journal of the
+ * ACM \eme 46(1999). Also appears as IBM Research Report RJ 10076, May
+ * 1997.
+ * \param graph The input graph. Can be directed and undirected.
+ * \param vector Pointer to an initialized vector, the result is
+ *    stored here. If a null pointer then it is ignored.
+ * \param value If not a null pointer then the eigenvalue
+ *    corresponding to the calculated eigenvector is stored here.
+ * \param scale If not zero then the result will be scaled such that
+ *     the absolute value of the maximum centrality is one.
+ * \param weights A null pointer (=no edge weights), or a vector
+ *     giving the weights of the edges.
+ * \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) parameter and 
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \return Error code.
+ * 
+ * Time complexity: depends on the input graph, usually it is O(|V|),
+ * the number of vertices.
+ * 
+ * \sa \ref igraph_authority_score() for the companion measure,
+ * \ref igraph_pagerank(), \ref igraph_personalized_pagerank(),
+ * \ref igraph_eigenvector_centrality() for similar measures.
+ */
+
+int igraph_hub_score(const igraph_t *graph, igraph_vector_t *vector,
+		     igraph_real_t *value, igraph_bool_t scale,
+			 const igraph_vector_t *weights,
+		     igraph_arpack_options_t *options) {
+
+  return igraph_i_kleinberg(graph, vector, value, scale, weights, options, 0);
+}
+
+/**
+ * \function igraph_authority_score
+ * Kleinerg's authority scores
+ * 
+ * The authority scores of the vertices are defined as the principal
+ * eigenvector of <code>A^T*A</code>, where <code>A</code> is the adjacency
+ * matrix of the graph, <code>A^T</code> is its transposed.
+ * </para><para> 
+ * See the following reference on the meaning of this score:
+ * J. Kleinberg. Authoritative sources in a hyperlinked
+ * environment. \emb Proc. 9th ACM-SIAM Symposium on Discrete
+ * Algorithms, \eme 1998. Extended version in \emb Journal of the
+ * ACM \eme 46(1999). Also appears as IBM Research Report RJ 10076, May
+ * 1997.
+ * \param graph The input graph. Can be directed and undirected.
+ * \param vector Pointer to an initialized vector, the result is
+ *    stored here. If a null pointer then it is ignored.
+ * \param value If not a null pointer then the eigenvalue
+ *    corresponding to the calculated eigenvector is stored here.
+ * \param scale If not zero then the result will be scaled such that
+ *     the absolute value of the maximum centrality is one.
+ * \param weights A null pointer (=no edge weights), or a vector
+ *     giving the weights of the edges.
+ * \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) parameter and 
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \return Error code.
+ * 
+ * Time complexity: depends on the input graph, usually it is O(|V|),
+ * the number of vertices.
+ * 
+ * \sa \ref igraph_hub_score() for the companion measure,
+ * \ref igraph_pagerank(), \ref igraph_personalized_pagerank(),
+ * \ref igraph_eigenvector_centrality() for similar measures.
+ */
+			    
+int igraph_authority_score(const igraph_t *graph, igraph_vector_t *vector,
+			   igraph_real_t *value, igraph_bool_t scale,
+			   const igraph_vector_t *weights,
+			   igraph_arpack_options_t *options) {
+
+  return igraph_i_kleinberg(graph, vector, value, scale, weights, options, 1);
+}
+
+typedef struct igraph_i_pagerank_data_t {
+  const igraph_t *graph;
+  igraph_adjlist_t *adjlist;
+  igraph_real_t damping;
+  igraph_vector_t *outdegree;
+  igraph_vector_t *tmp;
+  igraph_vector_t *reset;
+} igraph_i_pagerank_data_t;
+
+typedef struct igraph_i_pagerank_data2_t {
+  const igraph_t *graph;
+  igraph_inclist_t *inclist;
+  const igraph_vector_t *weights;
+  igraph_real_t damping;
+  igraph_vector_t *outdegree;
+  igraph_vector_t *tmp;
+  igraph_vector_t *reset;
+} igraph_i_pagerank_data2_t;
+
+int igraph_i_pagerank(igraph_real_t *to, const igraph_real_t *from,
+		      int n, void *extra) {
+  
+  igraph_i_pagerank_data_t *data=extra;
+  igraph_adjlist_t *adjlist=data->adjlist;
+  igraph_vector_t *outdegree=data->outdegree;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_t *reset=data->reset;
+  igraph_vector_int_t *neis;
+  long int i, j, nlen;
+  igraph_real_t sumfrom=0.0;
+  igraph_real_t fact=1-data->damping;
+
+  /* Calculate p(x) / outdegree(x) in advance for all the vertices.
+   * Note that we may divide by zero here; this is intentional since
+   * we won't use those values and we save a comparison this way.
+   * At the same time, we calculate the global probability of a
+   * random jump in `sumfrom`. For vertices with no outgoing edges,
+   * we will surely jump from there if we are there, hence those
+   * vertices contribute p(x) to the teleportation probability.
+   * For vertices with some outgoing edges, we jump from there with
+   * probability `fact` if we are there, hence they contribute
+   * p(x)*fact */
+  for (i=0; i<n; i++) {
+    sumfrom += VECTOR(*outdegree)[i]!=0 ? from[i] * fact : from[i];
+    VECTOR(*tmp)[i] = from[i] / VECTOR(*outdegree)[i];
+  }
+
+  /* Here we calculate the part of the `to` vector that results from
+   * moving along links (and not from teleportation) */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(adjlist, 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] *= data->damping;
+  }
+
+  /* Now we add the contribution from random jumps. `reset` is a vector
+   * that defines the probability of ending up in vertex i after a jump.
+   * `sumfrom` is the global probability of jumping as mentioned above. */
+  /* printf("sumfrom = %.6f\n", (float)sumfrom); */
+
+  if (reset) {
+    /* Running personalized PageRank */
+    for (i=0; i<n; i++) {
+      to[i] += sumfrom * VECTOR(*reset)[i];
+    }
+  } else {
+    /* Traditional PageRank with uniform reset vector */
+    sumfrom /= n;
+    for (i=0; i<n; i++) {
+      to[i] += sumfrom;
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_pagerank2(igraph_real_t *to, const igraph_real_t *from,
+		       int n, void *extra) {
+
+  igraph_i_pagerank_data2_t *data=extra;
+  const igraph_t *graph=data->graph;
+  igraph_inclist_t *inclist=data->inclist;
+  const igraph_vector_t *weights=data->weights;
+  igraph_vector_t *outdegree=data->outdegree;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_t *reset=data->reset;
+  long int i, j, nlen;
+  igraph_real_t sumfrom=0.0;
+  igraph_vector_t *neis;
+  igraph_real_t fact=1-data->damping;
+
+  /*
+  printf("PageRank weighted: multiplying vector: ");
+  for (i=0; i<n; i++) { printf(" %.4f", from[i]); }
+  printf("\n");
+  */
+
+  for (i=0; i<n; i++) {
+    sumfrom += VECTOR(*outdegree)[i]!=0 ? from[i] * fact : from[i];
+    VECTOR(*tmp)[i] = from[i] / VECTOR(*outdegree)[i];
+  }
+  
+  for (i=0; i<n; i++) {
+    neis=igraph_inclist_get(inclist, i);
+    nlen=igraph_vector_size(neis);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=(long int) VECTOR(*neis)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      to[i] += VECTOR(*weights)[edge] * VECTOR(*tmp)[nei];
+    }
+    to[i] *= data->damping;
+  }
+
+  /* printf("sumfrom = %.6f\n", (float)sumfrom); */
+
+  if (reset) {
+    /* Running personalized PageRank */
+    for (i=0; i<n; i++) {
+      to[i] += sumfrom * VECTOR(*reset)[i];
+    }
+  } else {
+    /* Traditional PageRank with uniform reset vector */
+    sumfrom /= n;
+    for (i=0; i<n; i++) {
+      to[i] += sumfrom;
+    }
+  }
+
+  /*
+  printf("PageRank weighted: multiplied vector: ");
+  for (i=0; i<n; i++) { printf(" %.4f", to[i]); }
+  printf("\n");
+  */
+
+  return 0;
+}
+
+/**
+ * \function igraph_pagerank
+ * \brief Calculates the Google PageRank for the specified vertices.
+ *
+ * Starting from version 0.7, igraph has three PageRank implementations,
+ * and the user can choose between them. The first implementation is
+ * \c IGRAPH_PAGERANK_ALGO_POWER, also available as the (now
+ * deprecated) function \ref igraph_pagerank_old(). The second
+ * implementation is based on the ARPACK library, this was the default
+ * before igraph version 0.7: \c IGRAPH_PAGERANK_ALGO_ARPACK.
+ *
+ * The third and recommmended implementation is \c
+ * IGRAPH_PAGERANK_ALGO_PRPACK. This is using the the PRPACK package,
+ * see https://github.com/dgleich/prpack .
+ *
+ * </para><para>
+ * 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.
+ * </para>
+ * 
+ * <para>
+ * For the explanation of the PageRank algorithm, see the following
+ * webpage:
+ * http://infolab.stanford.edu/~backrub/google.html , or the
+ * following reference:
+ * </para>
+ * 
+ * <para>
+ * 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.
+ * </para>
+ * <para>
+ * \param graph The graph object.
+ * \param algo The PageRank implementation to use. Possible values:
+ *    \c IGRAPH_PAGERANK_ALGO_POWER, \c IGRAPH_PAGERANK_ALGO_ARPACK,
+ *    \c IGRAPH_PAGERANK_ALGO_PRPACK.
+ * \param vector Pointer to an initialized vector, the result is
+ *    stored here. It is resized as needed.
+ * \param value Pointer to a real variable, the eigenvalue
+ *    corresponding to the PageRank vector is stored here. It should
+ *    be always exactly one.
+ * \param vids The vertex ids for which the PageRank is returned.
+ * \param directed Boolean, whether to consider the directedness of
+ *    the edges. This is ignored for undirected graphs.
+ * \param damping The damping factor ("d" in the original paper)
+ * \param weights Optional edge weights, it is either a null pointer,
+ *    then the edges are not weighted, or a vector of the same length
+ *    as the number of edges.
+ * \param options Options to the power method or ARPACK. For the power
+ *    method, \c IGRAPH_PAGERANK_ALGO_POWER it must be a pointer to
+ *    a \ref igraph_pagerank_power_options_t object.
+ *    For \c IGRAPH_PAGERANK_ALGO_ARPACK it must be a pointer to an
+ *    \ref igraph_arpack_options_t object. See \ref igraph_arpack_options_t
+ *    for details. Note that the function overwrites the
+ *    <code>n</code> (number of vertices), <code>nev</code> (1),
+ *    <code>ncv</code> (3) and <code>which</code> (LM) parameters and
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVVID, invalid vertex id in
+ *         \p vids. 
+ * 
+ * Time complexity: depends on the input graph, usually it is O(|E|),
+ * the number of edges.
+ * 
+ * \sa \ref igraph_pagerank_old() for the old implementation, 
+ * \ref igraph_personalized_pagerank() and \ref igraph_personalized_pagerank_vs()
+ * for the personalized PageRank measure, \ref igraph_arpack_rssolve() and
+ * \ref igraph_arpack_rnsolve() for the underlying machinery.
+ * 
+ * \example examples/simple/igraph_pagerank.c
+ */
+
+int igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t algo,
+		    igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    const igraph_vector_t *weights, void *options) {
+  return igraph_personalized_pagerank(graph, algo, vector, value, vids, 
+				      directed, damping, 0, weights, 
+				      options);
+}
+
+/**
+ * \function igraph_personalized_pagerank_vs
+ * \brief Calculates the personalized Google PageRank for the specified vertices.
+ * 
+ * The personalized PageRank is similar to the original PageRank measure, but the
+ * random walk is reset in every step with probability 1-damping to a non-uniform
+ * distribution (instead of the uniform distribution in the original PageRank measure.
+ *
+ * </para><para>
+ * This simplified interface takes a vertex sequence and resets the random walk to
+ * one of the vertices in the specified vertex sequence, chosen uniformly. A typical
+ * application of personalized PageRank is when the random walk is reset to the same
+ * vertex every time - this can easily be achieved using \ref igraph_vss_1() which
+ * generates a vertex sequence containing only a single vertex.
+ * 
+ * </para><para>
+ * Please note that the personalized PageRank of a given vertex depends on the
+ * personalized PageRank of all other vertices, so even if you want to calculate
+ * the personalized PageRank for only some of the vertices, all of them must be
+ * calculated. Requesting the personalized PageRank for only some of the vertices
+ * does not result in any performance increase at all.
+ * </para>
+ * 
+ * <para>
+ * \param graph The graph object.
+ * \param algo The PageRank implementation to use. Possible values:
+ *    \c IGRAPH_PAGERANK_ALGO_POWER, \c IGRAPH_PAGERANK_ALGO_ARPACK,
+ *    \c IGRAPH_PAGERANK_ALGO_PRPACK.
+ * \param vector Pointer to an initialized vector, the result is
+ *    stored here. It is resized as needed.
+ * \param value Pointer to a real variable, the eigenvalue
+ *    corresponding to the PageRank vector is stored here. It should
+ *    be always exactly one.
+ * \param vids The vertex ids for which the PageRank is returned.
+ * \param directed Boolean, whether to consider the directedness of
+ *    the edges. This is ignored for undirected graphs.
+ * \param damping The damping factor ("d" in the original paper)
+ * \param reset_vids IDs of the vertices used when resetting the random walk.
+ * \param weights Optional edge weights, it is either a null pointer,
+ *    then the edges are not weighted, or a vector of the same length
+ *    as the number of edges.
+ * \param options Options to the power method or ARPACK. For the power
+ *    method, \c IGRAPH_PAGERANK_ALGO_POWER it must be a pointer to
+ *    a \ref igraph_pagerank_power_options_t object.
+ *    For \c IGRAPH_PAGERANK_ALGO_ARPACK it must be a pointer to an
+ *    \ref igraph_arpack_options_t object. See \ref igraph_arpack_options_t
+ *    for details. Note that the function overwrites the
+ *    <code>n</code> (number of vertices), <code>nev</code> (1),
+ *    <code>ncv</code> (3) and <code>which</code> (LM) parameters and
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVVID, invalid vertex id in
+ *         \p vids or an empty reset vertex sequence in
+ *         \p vids_reset.
+ * 
+ * Time complexity: depends on the input graph, usually it is O(|E|),
+ * the number of edges.
+ * 
+ * \sa \ref igraph_pagerank() for the non-personalized implementation, 
+ * \ref igraph_arpack_rssolve() and \ref igraph_arpack_rnsolve() for
+ * the underlying machinery.
+ */
+
+int igraph_personalized_pagerank_vs(const igraph_t *graph, 
+		    igraph_pagerank_algo_t algo, igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    igraph_vs_t reset_vids,
+		    const igraph_vector_t *weights,
+		    void *options) {
+	igraph_vector_t reset;
+	igraph_vit_t vit;
+
+	IGRAPH_VECTOR_INIT_FINALLY(&reset, igraph_vcount(graph));
+	IGRAPH_CHECK(igraph_vit_create(graph, reset_vids, &vit));
+	IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+	while (!IGRAPH_VIT_END(vit)) {
+		VECTOR(reset)[(long int)IGRAPH_VIT_GET(vit)]++;
+		IGRAPH_VIT_NEXT(vit);
+	}
+	igraph_vit_destroy(&vit);
+	IGRAPH_FINALLY_CLEAN(1);
+	
+	IGRAPH_CHECK(igraph_personalized_pagerank(graph, algo, vector, 
+						  value, vids, directed, 
+						  damping, &reset, weights,
+						  options));
+
+	igraph_vector_destroy(&reset);
+	IGRAPH_FINALLY_CLEAN(1);
+
+	return 0;
+}
+
+/**
+ * \function igraph_personalized_pagerank
+ * \brief Calculates the personalized Google PageRank for the specified vertices.
+ * 
+ * The personalized PageRank is similar to the original PageRank measure, but the
+ * random walk is reset in every step with probability 1-damping to a non-uniform
+ * distribution (instead of the uniform distribution in the original PageRank measure.
+ *
+ * </para><para>
+ * Please note that the personalized PageRank of a given vertex depends on the
+ * personalized PageRank of all other vertices, so even if you want to calculate
+ * the personalized PageRank for only some of the vertices, all of them must be
+ * calculated. Requesting the personalized PageRank for only some of the vertices
+ * does not result in any performance increase at all.
+ * </para>
+ * 
+ * <para>
+ * \param graph The graph object.
+ * \param algo The PageRank implementation to use. Possible values:
+ *    \c IGRAPH_PAGERANK_ALGO_POWER, \c IGRAPH_PAGERANK_ALGO_ARPACK,
+ *    \c IGRAPH_PAGERANK_ALGO_PRPACK.
+ * \param vector Pointer to an initialized vector, the result is
+ *    stored here. It is resized as needed.
+ * \param value Pointer to a real variable, the eigenvalue
+ *    corresponding to the PageRank vector is stored here. It should
+ *    be always exactly one.
+ * \param vids The vertex ids for which the PageRank is returned.
+ * \param directed Boolean, whether to consider the directedness of
+ *    the edges. This is ignored for undirected graphs.
+ * \param damping The damping factor ("d" in the original paper)
+ * \param reset The probability distribution over the vertices used when
+ *    resetting the random walk. It is either a null pointer (denoting
+ *    a uniform choice that results in the original PageRank measure)
+ *    or a vector of the same length as the number of vertices.
+ * \param weights Optional edge weights, it is either a null pointer,
+ *    then the edges are not weighted, or a vector of the same length
+ *    as the number of edges.
+ * \param options Options to the power method or ARPACK. For the power
+ *    method, \c IGRAPH_PAGERANK_ALGO_POWER it must be a pointer to
+ *    a \ref igraph_pagerank_power_options_t object.
+ *    For \c IGRAPH_PAGERANK_ALGO_ARPACK it must be a pointer to an
+ *    \ref igraph_arpack_options_t object. See \ref igraph_arpack_options_t
+ *    for details. Note that the function overwrites the
+ *    <code>n</code> (number of vertices), <code>nev</code> (1),
+ *    <code>ncv</code> (3) and <code>which</code> (LM) parameters and
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVVID, invalid vertex id in
+ *         \p vids or an invalid reset vector in \p reset. 
+ * 
+ * Time complexity: depends on the input graph, usually it is O(|E|),
+ * the number of edges.
+ * 
+ * \sa \ref igraph_pagerank() for the non-personalized implementation, 
+ * \ref igraph_arpack_rssolve() and \ref igraph_arpack_rnsolve() for
+ * the underlying machinery.
+ */
+int igraph_personalized_pagerank(const igraph_t *graph, 
+		    igraph_pagerank_algo_t algo, igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    igraph_vector_t *reset,
+		    const igraph_vector_t *weights,
+		    void *options) {
+
+  if (algo == IGRAPH_PAGERANK_ALGO_POWER) {
+    igraph_pagerank_power_options_t *o = 
+      (igraph_pagerank_power_options_t *) options;
+    if (reset) { 
+      IGRAPH_WARNING("Cannot use weights with power method, "
+		     "weights will be ignored");
+    }
+    return igraph_pagerank_old(graph, vector, vids, directed, 
+			       o->niter, o->eps, damping, 
+			       /*old=*/ 0);
+  } else if (algo == IGRAPH_PAGERANK_ALGO_ARPACK) {
+    igraph_arpack_options_t *o= (igraph_arpack_options_t*) options;
+    return igraph_personalized_pagerank_arpack(graph, vector, value, vids,
+					       directed, damping, reset, 
+					       weights, o);
+  } else if (algo == IGRAPH_PAGERANK_ALGO_PRPACK) {
+    return igraph_personalized_pagerank_prpack(graph, vector, value, vids,
+					       directed, damping, reset, 
+					       weights);
+  } else {
+    IGRAPH_ERROR("Unknown PageRank algorithm", IGRAPH_EINVAL);
+  }
+
+  return 0;
+}
+
+/*
+ * ARPACK-based implementation of \c igraph_personalized_pagerank.
+ *
+ * See \c igraph_personalized_pagerank for the documentation of the parameters.
+ */
+int igraph_personalized_pagerank_arpack(const igraph_t *graph, igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    igraph_vector_t *reset,
+		    const igraph_vector_t *weights,
+		    igraph_arpack_options_t *options) {
+  igraph_matrix_t values;
+  igraph_matrix_t vectors;
+  igraph_neimode_t dirmode;
+  igraph_vector_t outdegree;
+  igraph_vector_t indegree;
+  igraph_vector_t tmp;
+
+  long int i;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+
+  if (no_of_edges == 0) {
+    /* special case: empty graph */
+    if (value)
+      *value = 1.0;
+    if (vector) {
+      igraph_vector_resize(vector, no_of_nodes);
+      igraph_vector_fill(vector, 1.0 / no_of_nodes);
+    }
+	return IGRAPH_SUCCESS;
+  }
+
+  options->n = (int) no_of_nodes;
+  options->nev = 1;
+  options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rnsolve */
+  options->which[0]='L'; options->which[1]='M';
+  options->start = 1;		/* no random start vector */
+
+  directed = directed && igraph_is_directed(graph);
+
+  if (weights) {
+    igraph_real_t min, max;
+
+	if (igraph_vector_size(weights) != no_of_edges) {
+      IGRAPH_ERROR("Invalid length of weights vector when calculating "
+                   "PageRank scores", IGRAPH_EINVAL);
+    }
+
+    IGRAPH_CHECK(igraph_vector_minmax(weights, &min, &max));
+    if (min == 0 && max == 0) {
+      /* special case: all weights are zeros */
+      if (value)
+        *value = 1.0;
+      if (vector) {
+        igraph_vector_resize(vector, igraph_vcount(graph));
+        igraph_vector_fill(vector, 1.0 / no_of_nodes);
+      }
+      return IGRAPH_SUCCESS;
+    }
+  }
+
+  if (reset && igraph_vector_size(reset) != no_of_nodes)
+  {
+    IGRAPH_ERROR("Invalid length of reset vector when calculating "
+		 "personalized PageRank scores", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_MATRIX_INIT_FINALLY(&values, 0, 0);
+  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);
+
+  if (directed) { dirmode=IGRAPH_IN; } else { dirmode=IGRAPH_ALL; }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&indegree, options->n);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdegree, options->n);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, options->n);
+
+  RNG_BEGIN();
+
+  if (reset) {
+	/* Normalize reset vector so the sum is 1 */
+	double reset_sum;
+	if (igraph_vector_min(reset) < 0)
+	  IGRAPH_ERROR("the reset vector must not contain negative elements", IGRAPH_EINVAL);
+	reset_sum = igraph_vector_sum(reset);
+	if (reset_sum == 0)
+	  IGRAPH_ERROR("the sum of the elements in the reset vector must not be zero", IGRAPH_EINVAL);
+	igraph_vector_scale(reset, 1.0/reset_sum);
+  }
+
+  if (!weights) {
+    
+    igraph_adjlist_t adjlist;
+    igraph_i_pagerank_data_t data = { graph, &adjlist, damping,
+				      &outdegree, &tmp, reset };
+
+    IGRAPH_CHECK(igraph_degree(graph, &outdegree, igraph_vss_all(),
+			       directed ? IGRAPH_OUT : IGRAPH_ALL, /*loops=*/ 0));
+    IGRAPH_CHECK(igraph_degree(graph, &indegree, igraph_vss_all(),
+			       directed ? IGRAPH_IN : IGRAPH_ALL, /*loops=*/ 0));
+    /* Set up an appropriate starting vector. We start from the in-degrees
+     * plus some small random noise to avoid convergence problems */
+    for (i=0; i<options->n; i++) {
+      if (VECTOR(indegree)[i])
+        MATRIX(vectors, i, 0) = VECTOR(indegree)[i] + RNG_UNIF(-1e-4, 1e-4);
+      else
+        MATRIX(vectors, i, 0) = 1;
+    }
+
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, dirmode));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+    IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_pagerank,
+				       &data, options, 0, &values, &vectors));
+
+    igraph_adjlist_destroy(&adjlist);
+    IGRAPH_FINALLY_CLEAN(1);
+    
+  } else {
+    
+    igraph_inclist_t inclist;
+    igraph_bool_t negative_weight_warned = 0;
+    igraph_i_pagerank_data2_t data = { graph, &inclist, weights,
+				       damping, &outdegree, &tmp, reset };    
+
+    IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, dirmode));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+
+    /* Weighted degree */
+    for (i=0; i<no_of_edges; i++) {
+      long int from=IGRAPH_FROM(graph, i);
+      long int to=IGRAPH_TO(graph, i);
+      igraph_real_t weight=VECTOR(*weights)[i];
+      if (weight < 0 && !negative_weight_warned) {
+        IGRAPH_WARNING("replacing negative weights with zeros");
+        weight = 0;
+        negative_weight_warned = 1;
+      }
+      VECTOR(outdegree)[from] += weight;
+      VECTOR(indegree) [to]   += weight;
+      if (!directed) { 
+        VECTOR(outdegree)[to]   += weight;
+        VECTOR(indegree) [from] += weight;
+      }
+    }
+    /* Set up an appropriate starting vector. We start from the in-degrees
+     * plus some small random noise to avoid convergence problems */
+    for (i=0; i<options->n; i++) {
+      if (VECTOR(indegree)[i])
+        MATRIX(vectors, i, 0) = VECTOR(indegree)[i] + RNG_UNIF(-1e-4, 1e-4);
+      else
+        MATRIX(vectors, i, 0) = 1;
+    }
+    
+    IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_pagerank2,
+				       &data, options, 0, &values, &vectors));
+    
+    igraph_inclist_destroy(&inclist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  RNG_END();
+
+  igraph_vector_destroy(&tmp);
+  igraph_vector_destroy(&outdegree);
+  igraph_vector_destroy(&indegree);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (value) {
+    *value=MATRIX(values, 0, 0);
+  }
+  
+  if (vector) {
+    long int i;
+    igraph_vit_t vit;
+    long int nodes_to_calc;
+    igraph_real_t sum=0;
+    
+    for (i=0; i<no_of_nodes; i++) { 
+      sum += MATRIX(vectors, i, 0);
+    }
+
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+    nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+
+    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] = MATRIX(vectors, (long int)IGRAPH_VIT_GET(vit), 0);
+      VECTOR(*vector)[i] /= sum;
+    }
+    
+    igraph_vit_destroy(&vit);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (options->info) {
+    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
+  }
+  
+  igraph_matrix_destroy(&vectors);
+  igraph_matrix_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_betweenness
+ * \brief Betweenness centrality of some vertices.
+ * 
+ * </para><para>
+ * The betweenness centrality of a vertex is the number of geodesics
+ * going through it. If there are more than one geodesic between two
+ * vertices, the value of these geodesics are weighted by one over the 
+ * number of geodesics.
+ * \param graph The graph object.
+ * \param res The result of the computation, a vector containing the
+ *        betweenness scores for the specified vertices.
+ * \param vids The vertices of which the betweenness centrality scores
+ *        will be calculated.
+ * \param directed Logical, if true directed paths will be considered
+ *        for directed graphs. It is ignored for undirected graphs.
+ * \param weights An optional vector containing edge weights for 
+ *        calculating weighted betweenness. Supply a null pointer here
+ *        for unweighted betweenness.
+ * \param nobigint Logical, if true, then we don't use big integers
+ *        for the calculation, setting this to 1 (=true) should
+ *        work for most graphs. It is currently ignored for weighted
+ *        graphs.
+ * \return Error code:
+ *        \c IGRAPH_ENOMEM, not enough memory for
+ *        temporary data. 
+ *        \c IGRAPH_EINVVID, invalid vertex id passed in
+ *        \p vids. 
+ *
+ * Time complexity: O(|V||E|),
+ * |V| and 
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ * Note that the time complexity is independent of the number of
+ * vertices for which the score is calculated.
+ *
+ * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness().
+ *     See \ref igraph_edge_betweenness() for calculating the betweenness score
+ *     of the edges in a graph. See \ref igraph_betweenness_estimate() to
+ *     estimate the betweenness score of the vertices in a graph.
+ * 
+ * \example examples/simple/igraph_betweenness.c
+ */
+int igraph_betweenness(const igraph_t *graph, igraph_vector_t *res,
+		       const igraph_vs_t vids, igraph_bool_t directed, 
+		       const igraph_vector_t* weights, igraph_bool_t nobigint) {
+  return igraph_betweenness_estimate(graph, res, vids, directed, -1, weights,
+				     nobigint);
+}
+
+int igraph_i_betweenness_estimate_weighted(const igraph_t *graph, 
+					 igraph_vector_t *res, 
+					 const igraph_vs_t vids, 
+					 igraph_bool_t directed,
+					 igraph_real_t cutoff, 
+					 const igraph_vector_t *weights, 
+					 igraph_bool_t nobigint) {
+
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_integer_t no_of_edges=(igraph_integer_t) igraph_ecount(graph);
+  igraph_2wheap_t Q;
+  igraph_inclist_t inclist;
+  igraph_adjlist_t fathers;
+  long int source, j;
+  igraph_stack_t S;
+  igraph_neimode_t mode= directed ? IGRAPH_OUT : IGRAPH_ALL;
+  igraph_vector_t dist, nrgeo, tmpscore;
+  igraph_vector_t v_tmpres, *tmpres=&v_tmpres;
+  igraph_vit_t vit;
+
+  IGRAPH_UNUSED(nobigint);
+
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(weights) <= 0) {
+    IGRAPH_ERROR("Weight vector must be positive", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
+  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, mode));  
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+  IGRAPH_CHECK(igraph_adjlist_init_empty(&fathers, no_of_nodes));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &fathers);
+
+  IGRAPH_CHECK(igraph_stack_init(&S, no_of_nodes));
+  IGRAPH_FINALLY(igraph_stack_destroy, &S);
+  IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmpscore, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&nrgeo, no_of_nodes);
+
+  if (igraph_vs_is_all(&vids)) {
+    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+    igraph_vector_null(res);
+    tmpres=res;
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(tmpres, no_of_nodes);
+  }
+
+  for (source=0; source<no_of_nodes; source++) {
+    IGRAPH_PROGRESS("Betweenness centrality: ", 100.0*source/no_of_nodes, 0);
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    igraph_2wheap_push_with_index(&Q, source, 0);
+    VECTOR(dist)[source]=1.0;
+    VECTOR(nrgeo)[source]=1;
+    
+    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;
+      long int nlen;
+      
+      igraph_stack_push(&S, minnei);
+      
+      if (cutoff >=0 && VECTOR(dist)[minnei] >= cutoff+1.0) { continue; }
+      
+      /* Now check all neighbors of 'minnei' for a shorter path */
+      neis=igraph_inclist_get(&inclist, minnei);
+      nlen=igraph_vector_size(neis);
+      for (j=0; j<nlen; j++) {
+	long int edge=(long int) VECTOR(*neis)[j];
+	long int to=IGRAPH_OTHER(graph, edge, minnei);
+	igraph_real_t altdist=mindist + VECTOR(*weights)[edge];
+	igraph_real_t curdist=VECTOR(dist)[to];
+	if (curdist==0) {
+	  /* This is the first non-infinite distance */
+	  igraph_vector_int_t *v=igraph_adjlist_get(&fathers, to);
+	  igraph_vector_int_resize(v,1);
+	  VECTOR(*v)[0]=minnei;
+	  VECTOR(nrgeo)[to] = VECTOR(nrgeo)[minnei];
+
+	  VECTOR(dist)[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_int_t *v=igraph_adjlist_get(&fathers, to);
+	  igraph_vector_int_resize(v,1);
+	  VECTOR(*v)[0]=minnei;
+	  VECTOR(nrgeo)[to] = VECTOR(nrgeo)[minnei];
+
+	  VECTOR(dist)[to]=altdist+1.0;
+	  IGRAPH_CHECK(igraph_2wheap_modify(&Q, to, -altdist));
+	} else if (altdist == curdist-1) {
+	  igraph_vector_int_t *v=igraph_adjlist_get(&fathers, to);
+	  igraph_vector_int_push_back(v, minnei);
+	  VECTOR(nrgeo)[to] += VECTOR(nrgeo)[minnei];
+	}
+      }
+      
+    } /* !igraph_2wheap_empty(&Q) */
+
+    while (!igraph_stack_empty(&S)) {
+      long int w=(long int) igraph_stack_pop(&S);
+      igraph_vector_int_t *fatv=igraph_adjlist_get(&fathers, w);
+      long int fatv_len=igraph_vector_int_size(fatv);
+      for (j=0; j<fatv_len; j++) {
+	long int f=(long int) VECTOR(*fatv)[j];
+	VECTOR(tmpscore)[f] += VECTOR(nrgeo)[f]/VECTOR(nrgeo)[w] * (1+VECTOR(tmpscore)[w]);
+      }
+      if (w!=source) { VECTOR(*tmpres)[w] += VECTOR(tmpscore)[w]; }
+
+      VECTOR(tmpscore)[w]=0;
+      VECTOR(dist)[w]=0;
+      VECTOR(nrgeo)[w]=0;
+      igraph_vector_int_clear(igraph_adjlist_get(&fathers, w));
+    }
+    
+  } /* source < no_of_nodes */
+
+  if (!igraph_vs_is_all(&vids)) {
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+    IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
+    
+    for (j=0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit);
+	 IGRAPH_VIT_NEXT(vit), j++) {
+      long int node=IGRAPH_VIT_GET(vit);
+      VECTOR(*res)[j] = VECTOR(*tmpres)[node];
+    }
+    
+    no_of_nodes = (igraph_integer_t) j;
+    
+    igraph_vit_destroy(&vit);
+    igraph_vector_destroy(tmpres);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  if (!directed || !igraph_is_directed(graph)) {
+    for (j=0; j<no_of_nodes; j++) {
+      VECTOR(*res)[j] /= 2.0;
+    }
+  }
+  
+  IGRAPH_PROGRESS("Betweenness centrality: ", 100.0, 0);
+
+  igraph_vector_destroy(&nrgeo);
+  igraph_vector_destroy(&tmpscore);
+  igraph_vector_destroy(&dist);
+  igraph_stack_destroy(&S);
+  igraph_adjlist_destroy(&fathers);
+  igraph_inclist_destroy(&inclist);
+  igraph_2wheap_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(7);
+  
+  return 0;
+}
+
+void igraph_i_destroy_biguints(igraph_biguint_t *p) {
+  igraph_biguint_t *p2 = p;
+  while ( *((long int*)(p)) ) {
+    igraph_biguint_destroy(p);
+    p++;
+  }
+  igraph_Free(p2);
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_betweenness_estimate
+ * \brief Estimated betweenness centrality of some vertices.
+ * 
+ * </para><para>
+ * The betweenness centrality of a vertex is the number of geodesics
+ * going through it. If there are more than one geodesic between two
+ * vertices, the value of these geodesics are weighted by one over the 
+ * number of geodesics. When estimating betweenness centrality, igraph
+ * takes into consideration only those paths that are shorter than or
+ * equal to a prescribed length. Note that the estimated centrality
+ * will always be less than the real one.
+ *
+ * \param graph The graph object.
+ * \param res The result of the computation, a vector containing the
+ *        estimated betweenness scores for the specified vertices.
+ * \param vids The vertices of which the betweenness centrality scores
+ *        will be estimated.
+ * \param directed Logical, if true directed paths will be considered
+ *        for directed graphs. It is ignored for undirected graphs.
+ * \param cutoff The maximal length of paths that will be considered.
+ *        If zero or negative, the exact betweenness will be calculated
+ *        (no upper limit on path lengths).
+ * \param weights An optional vector containing edge weights for 
+ *        calculating weighted betweenness. Supply a null pointer here
+ *        for unweighted betweenness.
+ * \param nobigint Logical, if true, then we don't use big integers
+ *        for the calculation, setting this to 1 (=true) should
+ *        work for most graphs. It is currently ignored for weighted
+ *        graphs.
+ * \return Error code:
+ *        \c IGRAPH_ENOMEM, not enough memory for
+ *        temporary data. 
+ *        \c IGRAPH_EINVVID, invalid vertex id passed in
+ *        \p vids. 
+ *
+ * Time complexity: O(|V||E|),
+ * |V| and 
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ * Note that the time complexity is independent of the number of
+ * vertices for which the score is calculated.
+ *
+ * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness().
+ *     See \ref igraph_edge_betweenness() for calculating the betweenness score
+ *     of the edges in a graph.
+ */
+int igraph_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res, 
+				const igraph_vs_t vids, igraph_bool_t directed,
+				igraph_real_t cutoff, 
+				const igraph_vector_t *weights, 
+				igraph_bool_t nobigint) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  long int *distance;
+  unsigned long long int *nrgeo=0;  /* must be long long; consider grid
+				       graphs for example */
+  igraph_biguint_t *big_nrgeo=0;
+  double *tmpscore;
+  igraph_stack_t stack=IGRAPH_STACK_NULL;
+  long int source;
+  long int j, k, nneis;
+  igraph_vector_int_t *neis;
+  igraph_vector_t v_tmpres, *tmpres=&v_tmpres;
+  igraph_vit_t vit;
+
+  igraph_adjlist_t adjlist_out, adjlist_in;
+  igraph_adjlist_t *adjlist_out_p, *adjlist_in_p;
+
+  igraph_biguint_t D, R, T;
+
+  if (weights) { 
+    return igraph_i_betweenness_estimate_weighted(graph, res, vids, directed,
+						cutoff, weights, nobigint);
+  }
+
+  if (!igraph_vs_is_all(&vids)) {
+    /* subset */
+    IGRAPH_VECTOR_INIT_FINALLY(tmpres, no_of_nodes);
+  } else {
+    /* only  */
+    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+    igraph_vector_null(res);
+    tmpres=res;
+  }
+
+  directed=directed && igraph_is_directed(graph);
+  if (directed) {
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_out, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_out);
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_in, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_in);
+    adjlist_out_p=&adjlist_out;
+    adjlist_in_p=&adjlist_in;
+  } else {
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_out, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_out);
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_in, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_in);
+    adjlist_out_p=&adjlist_out;
+    adjlist_in_p=&adjlist_in;
+  }
+  for (j=0; j<no_of_nodes; j++) {
+    igraph_vector_int_clear(igraph_adjlist_get(adjlist_in_p, j));
+  }
+  
+  distance=igraph_Calloc(no_of_nodes, long int);
+  if (distance==0) {
+    IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, distance);
+  if (nobigint) {
+    nrgeo=igraph_Calloc(no_of_nodes, unsigned long long int);
+    if (nrgeo==0) {
+      IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, nrgeo);
+  } else {
+    /* +1 is to have one containing zeros, when we free it, we stop
+       at the zero */
+    big_nrgeo=igraph_Calloc(no_of_nodes+1, igraph_biguint_t);
+    if (!big_nrgeo) {
+      IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_i_destroy_biguints, big_nrgeo);
+    for (j=0; j<no_of_nodes; j++) {
+      IGRAPH_CHECK(igraph_biguint_init(&big_nrgeo[j]));
+    }
+    IGRAPH_CHECK(igraph_biguint_init(&D));
+    IGRAPH_FINALLY(igraph_biguint_destroy, &D);
+    IGRAPH_CHECK(igraph_biguint_init(&R));
+    IGRAPH_FINALLY(igraph_biguint_destroy, &R);
+    IGRAPH_CHECK(igraph_biguint_init(&T));
+    IGRAPH_FINALLY(igraph_biguint_destroy, &T);
+  }
+  tmpscore=igraph_Calloc(no_of_nodes, double);
+  if (tmpscore==0) {
+    IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, tmpscore);
+
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  igraph_stack_init(&stack, no_of_nodes);
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+    
+  /* here we go */
+  
+  for (source=0; source<no_of_nodes; source++) {
+    IGRAPH_PROGRESS("Betweenness centrality: ", 100.0*source/no_of_nodes, 0);
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    IGRAPH_CHECK(igraph_dqueue_push(&q, source));
+    if (nobigint) { 
+      nrgeo[source]=1;
+    } else {
+      igraph_biguint_set_limb(&big_nrgeo[source], 1);
+    }
+    distance[source]=1;
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      IGRAPH_CHECK(igraph_stack_push(&stack, actnode));
+
+      if (cutoff >= 0 && distance[actnode] >= cutoff+1) { continue; }
+      
+      neis = igraph_adjlist_get(adjlist_out_p, actnode);
+      nneis = igraph_vector_int_size(neis);
+      for (j=0; j<nneis; j++) {
+        long int neighbor=(long int) VECTOR(*neis)[j];
+        if (distance[neighbor]==0) {
+	  distance[neighbor]=distance[actnode]+1;
+	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	} 
+	if (distance[neighbor]==distance[actnode]+1) {
+	  igraph_vector_int_t *v=igraph_adjlist_get(adjlist_in_p, 
+						    neighbor);
+	  igraph_vector_int_push_back(v, actnode);
+	  if (nobigint) { 
+	    nrgeo[neighbor]+=nrgeo[actnode];
+	  } else {
+	    IGRAPH_CHECK(igraph_biguint_add(&big_nrgeo[neighbor],
+					    &big_nrgeo[neighbor], 
+					    &big_nrgeo[actnode]));
+	  }
+	}
+      }
+    } /* while !igraph_dqueue_empty */
+    
+    /* Ok, we've the distance of each node and also the number of
+       shortest paths to them. Now we do an inverse search, starting
+       with the farthest nodes. */
+    while (!igraph_stack_empty(&stack)) {
+      long int actnode=(long int) igraph_stack_pop(&stack);
+      neis = igraph_adjlist_get(adjlist_in_p, actnode);
+      nneis = igraph_vector_int_size(neis);
+      for (j=0; j<nneis; j++) {
+        long int neighbor=(long int) VECTOR(*neis)[j];
+	if (nobigint) {
+	  tmpscore[neighbor] +=  (tmpscore[actnode]+1)*
+	    ((double)(nrgeo[neighbor]))/nrgeo[actnode];
+	} else {
+	  if (!igraph_biguint_compare_limb(&big_nrgeo[actnode], 0)) {
+	    tmpscore[neighbor] = IGRAPH_INFINITY;
+	  } else {
+	    double div;
+	    limb_t shift=1000000000L;
+	    IGRAPH_CHECK(igraph_biguint_mul_limb(&T, &big_nrgeo[neighbor], 
+						 shift));	  
+	    igraph_biguint_div(&D, &R, &T, &big_nrgeo[actnode]);
+	    div=igraph_biguint_get(&D) / shift;
+	    tmpscore[neighbor] += (tmpscore[actnode]+1) * div;
+	  }
+	}
+      }
+      
+      if (actnode != source) { VECTOR(*tmpres)[actnode] += tmpscore[actnode]; }
+
+      distance[actnode]=0;
+      if (nobigint) { 
+	nrgeo[actnode]=0;
+      } else {
+	igraph_biguint_set_limb(&big_nrgeo[actnode], 0);
+      }
+      tmpscore[actnode]=0;
+      igraph_vector_int_clear(igraph_adjlist_get(adjlist_in_p, actnode));
+    }
+
+  } /* for source < no_of_nodes */
+
+  IGRAPH_PROGRESS("Betweenness centrality: ", 100.0, 0);
+
+  /* clean  */
+  igraph_Free(distance);
+  if (nobigint) {
+    igraph_Free(nrgeo); 
+  } else {
+    igraph_biguint_destroy(&T);
+    igraph_biguint_destroy(&R);
+    igraph_biguint_destroy(&D);
+    IGRAPH_FINALLY_CLEAN(3);
+    igraph_i_destroy_biguints(big_nrgeo);
+  }
+  igraph_Free(tmpscore);
+  
+  igraph_dqueue_destroy(&q);
+  igraph_stack_destroy(&stack);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  /* Keep only the requested vertices */
+  if (!igraph_vs_is_all(&vids)) { 
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+    IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
+
+    for (k=0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit);
+	 IGRAPH_VIT_NEXT(vit), k++) {
+      long int node=IGRAPH_VIT_GET(vit);
+      VECTOR(*res)[k] = VECTOR(*tmpres)[node];
+    }
+
+    igraph_vit_destroy(&vit);
+    igraph_vector_destroy(tmpres);
+    IGRAPH_FINALLY_CLEAN(2);
+  }     
+
+  /* divide by 2 for undirected graph */
+  if (!directed) {
+    nneis=igraph_vector_size(res);
+    for (j=0; j<nneis; j++) {
+      VECTOR(*res)[j] /= 2.0;
+    }
+  }
+  
+  igraph_adjlist_destroy(&adjlist_out);
+  igraph_adjlist_destroy(&adjlist_in);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph, 
+					      igraph_vector_t *result,
+					      igraph_bool_t directed, 
+					      igraph_real_t cutoff,
+					      const igraph_vector_t *weights) {
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_integer_t no_of_edges=(igraph_integer_t) igraph_ecount(graph);
+  igraph_2wheap_t Q;
+  igraph_inclist_t inclist;
+  igraph_inclist_t fathers;
+  igraph_neimode_t mode= directed ? IGRAPH_OUT : IGRAPH_ALL;
+  igraph_vector_t distance, tmpscore;
+  igraph_vector_long_t nrgeo;
+  long int source, j;
+  igraph_stack_t S;
+
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(weights) < 0) {
+    IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, mode));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+  IGRAPH_CHECK(igraph_inclist_init_empty(&fathers, no_of_nodes));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &fathers);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&distance, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmpscore, no_of_nodes);
+  IGRAPH_CHECK(igraph_vector_long_init(&nrgeo, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &nrgeo);
+
+  IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
+  IGRAPH_CHECK(igraph_stack_init(&S, no_of_nodes));
+  IGRAPH_FINALLY(igraph_stack_destroy, &S);
+
+  IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));
+  igraph_vector_null(result);
+
+  for (source=0; source<no_of_nodes; source++) {
+    IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0*source/no_of_nodes, 0);
+    IGRAPH_ALLOW_INTERRUPTION();
+
+/*     printf("source: %li\n", source); */
+    
+    igraph_vector_null(&distance);
+    igraph_vector_null(&tmpscore);
+    igraph_vector_long_null(&nrgeo);
+    
+    igraph_2wheap_push_with_index(&Q, source, 0);
+    VECTOR(distance)[source]=1.0;
+    VECTOR(nrgeo)[source]=1;
+    
+    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;
+      long int nlen;
+
+/*       printf("SP to %li is final, dist: %g, nrgeo: %li\n", minnei, */
+/* 	     VECTOR(distance)[minnei]-1.0, VECTOR(nrgeo)[minnei]); */
+      
+      igraph_stack_push(&S, minnei);
+
+      if (cutoff >=0 && VECTOR(distance)[minnei] >= cutoff+1.0) { continue; }
+
+      neis=igraph_inclist_get(&inclist, minnei);
+      nlen=igraph_vector_size(neis);
+      for (j=0; j<nlen; j++) {
+	long int edge=(long int) VECTOR(*neis)[j];
+	long int to=IGRAPH_OTHER(graph, edge, minnei);
+	igraph_real_t altdist=mindist + VECTOR(*weights)[edge];
+	igraph_real_t curdist=VECTOR(distance)[to];
+	
+	if (curdist==0) {
+	  /* This is the first finite distance to 'to' */
+	  igraph_vector_t *v=igraph_inclist_get(&fathers, to);
+/* 	  printf("Found first path to %li (from %li)\n", to, minnei); */
+	  igraph_vector_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);
+/* 	  printf("Found a shorter path to %li (from %li)\n", to, minnei); */
+	  igraph_vector_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);
+/* 	  printf("Found a second SP to %li (from %li)\n", to, minnei); */
+	  igraph_vector_push_back(v, edge);
+	  VECTOR(nrgeo)[to] += VECTOR(nrgeo)[minnei];
+	}
+      }
+	  
+    } /* igraph_2wheap_empty(&Q) */
+
+    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);
+/*       printf("Popping %li.\n", w); */
+      for (j=0; j<fatv_len; j++) {
+	long int fedge=(long int) VECTOR(*fatv)[j];
+	long int neighbor=IGRAPH_OTHER(graph, fedge, w);
+	VECTOR(tmpscore)[neighbor] += ((double)VECTOR(nrgeo)[neighbor]) /
+	  VECTOR(nrgeo)[w] * (1.0+VECTOR(tmpscore)[w]);
+/* 	printf("Scoring %li (edge %li)\n", neighbor, fedge); */
+	VECTOR(*result)[fedge] += 
+	  ((VECTOR(tmpscore)[w]+1) * VECTOR(nrgeo)[neighbor]) / 
+	  VECTOR(nrgeo)[w];
+      }
+      
+      VECTOR(tmpscore)[w]=0;
+      VECTOR(distance)[w]=0;
+      VECTOR(nrgeo)[w]=0;
+      igraph_vector_clear(fatv);
+    }
+    
+  } /* source < no_of_nodes */
+
+  if (!directed || !igraph_is_directed(graph)) {
+    for (j=0; j<no_of_edges; j++) {
+      VECTOR(*result)[j] /= 2.0;
+    }
+  }
+
+  IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0, 0);
+
+  igraph_stack_destroy(&S);
+  igraph_2wheap_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  igraph_inclist_destroy(&inclist);
+  igraph_inclist_destroy(&fathers);  
+  igraph_vector_destroy(&distance);
+  igraph_vector_destroy(&tmpscore);
+  igraph_vector_long_destroy(&nrgeo);
+  IGRAPH_FINALLY_CLEAN(5);
+  
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_edge_betweenness
+ * \brief Betweenness centrality of the edges.
+ * 
+ * </para><para>
+ * The betweenness centrality of an edge is the number of geodesics
+ * going through it. If there are more than one geodesics between two
+ * vertices, the value of these geodesics are weighted by one over the 
+ * number of geodesics.
+ * \param graph The graph object.
+ * \param result The result of the computation, vector containing the
+ *        betweenness scores for the edges.
+ * \param directed Logical, if true directed paths will be considered
+ *        for directed graphs. It is ignored for undirected graphs.
+ * \param weights An optional weight vector for weighted edge
+ *        betweenness. Supply a null pointer here for the unweighted
+ *        version. 
+ * \return Error code:
+ *        \c IGRAPH_ENOMEM, not enough memory for
+ *        temporary data. 
+ *
+ * Time complexity: O(|V||E|),
+ * |V| and
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ *
+ * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness().
+ *     See \ref igraph_edge_betweenness() for calculating the betweenness score
+ *     of the edges in a graph. See \ref igraph_edge_betweenness_estimate() to
+ *     estimate the betweenness score of the edges in a graph.
+ * 
+ * \example examples/simple/igraph_edge_betweenness.c
+ */
+int igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *result,
+                            igraph_bool_t directed, 
+			    const igraph_vector_t *weights) {
+  return igraph_edge_betweenness_estimate(graph, result, directed, -1, 
+					  weights);
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_edge_betweenness_estimate
+ * \brief Estimated betweenness centrality of the edges.
+ * 
+ * </para><para>
+ * The betweenness centrality of an edge is the number of geodesics
+ * going through it. If there are more than one geodesics between two
+ * vertices, the value of these geodesics are weighted by one over the 
+ * number of geodesics. When estimating betweenness centrality, igraph
+ * takes into consideration only those paths that are shorter than or
+ * equal to a prescribed length. Note that the estimated centrality
+ * will always be less than the real one.
+ * \param graph The graph object.
+ * \param result The result of the computation, vector containing the
+ *        betweenness scores for the edges.
+ * \param directed Logical, if true directed paths will be considered
+ *        for directed graphs. It is ignored for undirected graphs.
+ * \param cutoff The maximal length of paths that will be considered.
+ *        If zero or negative, the exact betweenness will be calculated
+ *        (no upper limit on path lengths).
+ * \param weights An optional weight vector for weighted
+ *        betweenness. Supply a null pointer here for unweighted
+ *        betweenness.
+ * \return Error code:
+ *        \c IGRAPH_ENOMEM, not enough memory for
+ *        temporary data. 
+ *
+ * Time complexity: O(|V||E|),
+ * |V| and
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ *
+ * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness().
+ *     See \ref igraph_betweenness() for calculating the betweenness score
+ *     of the vertices in a graph.
+ */
+int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *result,
+                                     igraph_bool_t directed, igraph_real_t cutoff,
+				     const igraph_vector_t *weights) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  long int *distance;
+  unsigned long long int *nrgeo;
+  double *tmpscore;
+  igraph_stack_t stack=IGRAPH_STACK_NULL;
+  long int source;
+  long int j;
+
+  igraph_inclist_t elist_out, elist_in;
+  igraph_inclist_t *elist_out_p, *elist_in_p;
+  igraph_vector_t *neip;
+  long int neino;
+  long int i;
+
+  if (weights) { 
+    return igraph_i_edge_betweenness_estimate_weighted(graph, result, 
+						     directed, cutoff, weights);
+  }
+
+  directed=directed && igraph_is_directed(graph);
+  if (directed) {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &elist_out, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &elist_out);
+    IGRAPH_CHECK(igraph_inclist_init(graph, &elist_in, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &elist_in);
+    elist_out_p=&elist_out;
+    elist_in_p=&elist_in;
+  } else {
+    IGRAPH_CHECK(igraph_inclist_init(graph,&elist_out, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &elist_out);
+    elist_out_p=elist_in_p=&elist_out;
+  }
+  
+  distance=igraph_Calloc(no_of_nodes, long int);
+  if (distance==0) {
+    IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, distance);
+  nrgeo=igraph_Calloc(no_of_nodes, unsigned long long int);
+  if (nrgeo==0) {
+    IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, nrgeo);
+  tmpscore=igraph_Calloc(no_of_nodes, double);
+  if (tmpscore==0) {
+    IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, tmpscore);
+
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_CHECK(igraph_stack_init(&stack, no_of_nodes));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+
+  IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));
+
+  igraph_vector_null(result);
+
+  /* here we go */
+  
+  for (source=0; source<no_of_nodes; source++) {
+    IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0*source/no_of_nodes, 0);
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    memset(distance, 0, (size_t) no_of_nodes * sizeof(long int));
+    memset(nrgeo, 0, (size_t) no_of_nodes*sizeof(unsigned long long int));
+    memset(tmpscore, 0, (size_t) no_of_nodes*sizeof(double));
+    igraph_stack_clear(&stack); /* it should be empty anyway... */
+    
+    IGRAPH_CHECK(igraph_dqueue_push(&q, source));
+      
+    nrgeo[source]=1;
+    distance[source]=0;
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+
+      /* TODO: we could just as well 'break' here, no? */
+      if (cutoff > 0 && distance[actnode] >= cutoff ) continue;
+
+      neip=igraph_inclist_get(elist_out_p, actnode);
+      neino=igraph_vector_size(neip);
+      for (i=0; i<neino; i++) {
+	igraph_integer_t edge=(igraph_integer_t) VECTOR(*neip)[i], from, to;
+	long int neighbor;
+	igraph_edge(graph, edge, &from, &to);
+	neighbor = actnode!=from ? from : to;
+	if (nrgeo[neighbor] != 0) {
+	  /* we've already seen this node, another shortest path? */
+	  if (distance[neighbor]==distance[actnode]+1) {
+	    nrgeo[neighbor]+=nrgeo[actnode];
+	  }
+	} else {
+	  /* we haven't seen this node yet */
+	  nrgeo[neighbor]+=nrgeo[actnode];
+	  distance[neighbor]=distance[actnode]+1;
+	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, neighbor));
+	}
+      }
+    } /* while !igraph_dqueue_empty */
+    
+    /* Ok, we've the distance of each node and also the number of
+       shortest paths to them. Now we do an inverse search, starting
+       with the farthest nodes. */
+    while (!igraph_stack_empty(&stack)) {
+      long int actnode=(long int) igraph_stack_pop(&stack);
+      if (distance[actnode]<1) { continue; } /* skip source node */
+      
+      /* set the temporary score of the friends */
+      neip=igraph_inclist_get(elist_in_p, actnode);
+      neino=igraph_vector_size(neip);
+      for (i=0; i<neino; i++) {
+	igraph_integer_t from, to;
+	long int neighbor;
+	igraph_integer_t edgeno=(igraph_integer_t) VECTOR(*neip)[i];
+	igraph_edge(graph, edgeno, &from, &to);
+	neighbor= actnode != from ? from : to;
+	if (distance[neighbor]==distance[actnode]-1 &&
+	    nrgeo[neighbor] != 0) {
+	  tmpscore[neighbor] +=
+	    (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
+	  VECTOR(*result)[edgeno] +=
+	    (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
+	}
+      }
+    }
+    /* Ok, we've the scores for this source */
+  } /* for source <= no_of_nodes */
+  IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0, 0);
+
+  /* clean and return */
+  igraph_Free(distance);
+  igraph_Free(nrgeo);
+  igraph_Free(tmpscore);
+  igraph_dqueue_destroy(&q);
+  igraph_stack_destroy(&stack);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  if (directed) {
+    igraph_inclist_destroy(&elist_out);
+    igraph_inclist_destroy(&elist_in);
+    IGRAPH_FINALLY_CLEAN(2);
+  } else {
+    igraph_inclist_destroy(&elist_out);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  /* divide by 2 for undirected graph */
+  if (!directed || !igraph_is_directed(graph)) {
+    for (j=0; j<igraph_vector_size(result); j++) {
+      VECTOR(*result)[j] /= 2.0;
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_closeness
+ * \brief Closeness centrality calculations for some vertices.
+ *
+ * </para><para>
+ * The closeness centrality of a vertex measures how easily other
+ * vertices can be reached from it (or the other way: how easily it
+ * can be reached from the other vertices). It is defined as the
+ * number of the number of vertices minus one divided by the sum of the
+ * lengths of all geodesics from/to the given vertex.
+ *
+ * </para><para>
+ * If the graph is not connected, and there is no path between two
+ * vertices, the number of vertices is used instead the length of the
+ * geodesic. This is always longer than the longest possible geodesic.
+ * 
+ * \param graph The graph object.
+ * \param res The result of the computation, a vector containing the
+ *        closeness centrality scores for the given vertices.
+ * \param vids Vector giving the vertices for which the closeness
+ *        centrality scores will be computed.
+ * \param mode The type of shortest paths to be used for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the lengths of the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the lengths of the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an
+ *          undirected one for the computation.
+ *        \endclist
+ * \param weights An optional vector containing edge weights for
+ *        weighted closeness. Supply a null pointer here for
+ *        traditional, unweighted closeness.
+ * \param normalized Boolean, whether to normalize results by multiplying
+ *        by the number of vertices minus one.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ *
+ * Time complexity: O(n|E|),
+ * n is the number 
+ * of vertices for which the calculation is done and
+ * |E| is the number 
+ * of edges in the graph.
+ *
+ * \sa Other centrality types: \ref igraph_degree(), \ref igraph_betweenness().
+ *   See \ref igraph_closeness_estimate() to estimate closeness values.
+ */
+int igraph_closeness(const igraph_t *graph, igraph_vector_t *res,
+                     const igraph_vs_t vids, igraph_neimode_t mode, 
+		     const igraph_vector_t *weights,
+		     igraph_bool_t normalized) {
+  return igraph_closeness_estimate(graph, res, vids, mode, -1, weights,
+				   normalized);
+}
+
+int igraph_i_closeness_estimate_weighted(const igraph_t *graph, 
+				       igraph_vector_t *res, 
+				       const igraph_vs_t vids, 
+				       igraph_neimode_t mode,
+				       igraph_real_t cutoff,
+				       const igraph_vector_t *weights,
+				       igraph_bool_t normalized) {
+
+  /* See igraph_shortest_paths_dijkstra() for the implementation 
+     details and the dirty tricks. */
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  
+  igraph_2wheap_t Q;
+  igraph_vit_t vit;
+  long int nodes_to_calc;
+  
+  igraph_lazy_inclist_t inclist;
+  long int i, j;
+  
+  igraph_vector_t dist;
+  igraph_vector_long_t which;
+  long int nodes_reached;
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+  
+  if (igraph_vector_min(weights) < 0) {
+    IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+  
+  IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
+  IGRAPH_CHECK(igraph_vector_long_init(&which, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &which);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  igraph_vector_null(res);
+
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    
+    long int source=IGRAPH_VIT_GET(vit);
+    igraph_2wheap_clear(&Q);
+    igraph_2wheap_push_with_index(&Q, source, 0);
+    VECTOR(which)[source]=i+1;
+    VECTOR(dist)[source]=0.0;
+    nodes_reached=0;
+    
+    while (!igraph_2wheap_empty(&Q)) {
+      igraph_integer_t minnei=(igraph_integer_t) igraph_2wheap_max_index(&Q);
+      igraph_real_t mindist=-igraph_2wheap_delete_max(&Q);
+      
+      /* Now check all neighbors of minnei for a shorter path */
+      igraph_vector_t *neis=igraph_lazy_inclist_get(&inclist, minnei);
+      long int nlen=igraph_vector_size(neis);
+
+      VECTOR(*res)[i] += mindist;
+      nodes_reached++;
+      
+      if (cutoff>0 && mindist>=cutoff) continue;    /* NOT break!!! */
+      
+      for (j=0; j<nlen; j++) {
+	long int edge=(long int) VECTOR(*neis)[j];
+	long int to=IGRAPH_OTHER(graph, edge, minnei);
+	igraph_real_t altdist=mindist+VECTOR(*weights)[edge];
+	igraph_real_t curdist=VECTOR(dist)[to];
+	if (VECTOR(which)[to] != i+1) {
+	  /* First non-infinite distance */
+	  VECTOR(which)[to]=i+1;
+	  VECTOR(dist)[to]=altdist;
+	  IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, to, -altdist));
+	} else if (altdist < curdist) {
+	  /* This is a shorter path */
+	  VECTOR(dist)[to]=altdist;
+	  IGRAPH_CHECK(igraph_2wheap_modify(&Q, to, -altdist));
+	}
+      }
+
+    } /* !igraph_2wheap_empty(&Q) */
+
+    /* using igraph_real_t here instead of igraph_integer_t to avoid overflow */
+    VECTOR(*res)[i] += ((igraph_real_t)no_of_nodes * (no_of_nodes-nodes_reached));
+    VECTOR(*res)[i] = (no_of_nodes-1) / VECTOR(*res)[i];
+
+  } /* !IGRAPH_VIT_END(vit) */
+
+  if (!normalized) {
+    for (i=0; i<nodes_to_calc; i++) {
+      VECTOR(*res)[i] /= (no_of_nodes-1);
+    }
+  }
+
+  igraph_vector_long_destroy(&which);
+  igraph_vector_destroy(&dist);
+  igraph_lazy_inclist_destroy(&inclist);
+  igraph_2wheap_destroy(&Q);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_closeness_estimate
+ * \brief Closeness centrality estimations for some vertices.
+ *
+ * </para><para>
+ * The closeness centrality of a vertex measures how easily other
+ * vertices can be reached from it (or the other way: how easily it
+ * can be reached from the other vertices). It is defined as the
+ * number of the number of vertices minus one divided by the sum of the
+ * lengths of all geodesics from/to the given vertex. When estimating
+ * closeness centrality, igraph considers paths having a length less than
+ * or equal to a prescribed cutoff value.
+ *
+ * </para><para>
+ * If the graph is not connected, and there is no such path between two
+ * vertices, the number of vertices is used instead the length of the
+ * geodesic. This is always longer than the longest possible geodesic.
+ *
+ * </para><para>
+ * Since the estimation considers vertex pairs with a distance greater than
+ * the given value as disconnected, the resulting estimation will always be
+ * lower than the actual closeness centrality.
+ * 
+ * \param graph The graph object.
+ * \param res The result of the computation, a vector containing the
+ *        closeness centrality scores for the given vertices.
+ * \param vids Vector giving the vertices for which the closeness
+ *        centrality scores will be computed.
+ * \param mode The type of shortest paths to be used for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the lengths of the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the lengths of the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an
+ *          undirected one for the computation.
+ *        \endclist
+ * \param cutoff The maximal length of paths that will be considered.
+ *        If zero or negative, the exact closeness will be calculated
+ *        (no upper limit on path lengths).
+ * \param weights An optional vector containing edge weights for
+ *        weighted closeness. Supply a null pointer here for
+ *        traditional, unweighted closeness.
+ * \param normalized Boolean, whether to normalize results by multiplying
+ *        by the number of vertices minus one.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ *
+ * Time complexity: O(n|E|),
+ * n is the number 
+ * of vertices for which the calculation is done and
+ * |E| is the number 
+ * of edges in the graph.
+ *
+ * \sa Other centrality types: \ref igraph_degree(), \ref igraph_betweenness().
+ */
+int igraph_closeness_estimate(const igraph_t *graph, igraph_vector_t *res, 
+		              const igraph_vs_t vids, igraph_neimode_t mode,
+                              igraph_real_t cutoff,
+			      const igraph_vector_t *weights,
+			      igraph_bool_t normalized) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t already_counted;
+  igraph_vector_int_t *neis;
+  long int i, j;
+  long int nodes_reached;
+  igraph_adjlist_t allneis;
+
+  igraph_dqueue_t q;
+  
+  long int nodes_to_calc;
+  igraph_vit_t vit;
+
+  if (weights) { 
+    return igraph_i_closeness_estimate_weighted(graph, res, vids, mode, cutoff,
+						weights, normalized);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+  
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("calculating closeness", IGRAPH_EINVMODE);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&already_counted, no_of_nodes);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, mode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  igraph_vector_null(res);
+  
+  for (IGRAPH_VIT_RESET(vit), i=0; 
+       !IGRAPH_VIT_END(vit); 
+       IGRAPH_VIT_NEXT(vit), i++) {
+    igraph_dqueue_clear(&q);
+    IGRAPH_CHECK(igraph_dqueue_push(&q, IGRAPH_VIT_GET(vit)));
+    IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+    nodes_reached=1;
+    VECTOR(already_counted)[(long int)IGRAPH_VIT_GET(vit)]=i+1;
+
+    IGRAPH_PROGRESS("Closeness: ", 100.0*i/no_of_nodes, NULL);
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int act=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      
+      VECTOR(*res)[i] += actdist;
+
+      if (cutoff>0 && actdist>=cutoff) continue;   /* NOT break!!! */
+
+      neis=igraph_adjlist_get(&allneis, act);
+      for (j=0; j<igraph_vector_int_size(neis); j++) {
+        long int neighbor=(long int) VECTOR(*neis)[j];
+        if (VECTOR(already_counted)[neighbor] == i+1) { continue; }
+        VECTOR(already_counted)[neighbor] = i+1;
+        nodes_reached++;
+        IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+        IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+      }
+    }
+    /* using igraph_real_t here instead of igraph_integer_t to avoid overflow */
+    VECTOR(*res)[i] += ((igraph_real_t)no_of_nodes * (no_of_nodes-nodes_reached));
+    VECTOR(*res)[i] = (no_of_nodes-1) / VECTOR(*res)[i];
+  }
+
+  if (!normalized) {
+    for (i=0; i<nodes_to_calc; i++) {
+      VECTOR(*res)[i] /= (no_of_nodes-1);
+    }
+  }
+
+  IGRAPH_PROGRESS("Closeness: ", 100.0, NULL);
+
+  /* Clean */
+  igraph_dqueue_destroy(&q);
+  igraph_vector_destroy(&already_counted);
+  igraph_vit_destroy(&vit);
+  igraph_adjlist_destroy(&allneis);
+  IGRAPH_FINALLY_CLEAN(4);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_centralization
+ * Calculate the centralization score from the node level scores
+ * 
+ * For a centrality score defined on the vertices of a graph, it is
+ * possible to define a graph level centralization index, by
+ * calculating the sum of the deviation from the maximum centrality
+ * score. Consequently, the higher the centralization index of the
+ * graph, the more centralized the structure is.
+ * 
+ * </para><para>In order to make graphs of different sizes comparable,
+ * the centralization index is usually normalized to a number between
+ * zero and one, by dividing the (unnormalized) centralization score
+ * of the most centralized structure with the same number of vertices.
+ * 
+ * </para><para>For most centrality indices the most centralized
+ * structure is the star graph, a single center connected to all other
+ * nodes in the network. There are some variation depending on whether
+ * the graph is directed or not, whether loop edges are allowed, etc. 
+ * 
+ * </para><para>
+ * This function simply calculates the graph level index, if the node
+ * level scores and the theoretical maximum are given. It is called by
+ * all the measure-specific centralization functions.
+ * 
+ * \param scores A vector containing the node-level centrality
+ *     scores.
+ * \param theoretical_max The graph level centrality score of the most
+ *     centralized graph with the same number of vertices. Only used
+ *     if \c normalized set to true.
+ * \param normalized Boolean, whether to normalize the centralization
+ *     by dividing the supplied theoretical maximum.
+ * \return The graph level index.
+ * 
+ * \sa \ref igraph_centralization_degree(), \ref
+ * igraph_centralization_betweenness(), \ref
+ * igraph_centralization_closeness(), and \ref
+ * igraph_centralization_eigenvector_centrality() for specific
+ * centralization functions.
+ * 
+ * Time complexity: O(n), the length of the score vector.
+ * 
+ * \example examples/simple/centralization.c
+ */
+
+igraph_real_t igraph_centralization(const igraph_vector_t *scores,
+				    igraph_real_t theoretical_max,
+				    igraph_bool_t normalized) {
+  
+  long int no_of_nodes=igraph_vector_size(scores);
+  igraph_real_t maxscore=0.0;
+  igraph_real_t cent=0.0;
+  
+  if (no_of_nodes != 0) {
+    maxscore = igraph_vector_max(scores);
+    cent = no_of_nodes * maxscore - igraph_vector_sum(scores);
+    if (normalized) { cent = cent/theoretical_max; }
+  } else {
+    cent = IGRAPH_NAN;
+  }
+
+  return cent;
+}
+
+/**
+ * \function igraph_centralization_degree
+ * Calculate vertex degree and graph centralization
+ * 
+ * This function calculates the degree of the vertices by passing its
+ * arguments to \ref igraph_degree(); and it calculates the graph
+ * level centralization index based on the results by calling \ref
+ * igraph_centralization().
+ * \param graph The input graph.
+ * \param res A vector if you need the node-level degree scores, or a
+ *     null pointer otherwise.
+ * \param mode Constant the specifies the type of degree for directed
+ *     graphs. Possible values: \c IGRAPH_IN, \c IGRAPH_OUT and \c
+ *     IGRAPH_ALL. This argument is ignored for undirected graphs.
+ * \param loops Boolean, whether to consider loop edges when
+ *     calculating the degree (and the centralization).
+ * \param centralization Pointer to a real number, the centralization
+ *     score is placed here.
+ * \param theoretical_max Pointer to real number or a null pointer. If
+ *     not a null pointer, then the theoretical maximum graph
+ *     centrality score for a graph with the same number vertices is
+ *     stored here.
+ * \param normalized Boolean, whether to calculate a normalized
+ *     centralization score. See \ref igraph_centralization() for how
+ *     the normalization is done.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_centralization(), \ref igraph_degree().
+ * 
+ * Time complexity: the complexity of \ref igraph_degree() plus O(n),
+ * the number of vertices queried, for calculating the centralization
+ * score.
+ */
+
+int igraph_centralization_degree(const igraph_t *graph, igraph_vector_t *res, 
+				 igraph_neimode_t mode, igraph_bool_t loops,
+				 igraph_real_t *centralization,
+				 igraph_real_t *theoretical_max,
+				 igraph_bool_t normalized) {
+  
+  igraph_vector_t myscores;
+  igraph_vector_t *scores=res;
+  igraph_real_t *tmax=theoretical_max, mytmax;
+
+  if (!tmax) { tmax=&mytmax; }
+
+  if (!res) {
+    scores=&myscores;
+    IGRAPH_VECTOR_INIT_FINALLY(scores, 0);
+  }
+  
+  IGRAPH_CHECK(igraph_degree(graph, scores, igraph_vss_all(), mode, loops));
+  
+  IGRAPH_CHECK(igraph_centralization_degree_tmax(graph, 0, mode, loops, 
+						 tmax));
+
+  *centralization = igraph_centralization(scores, *tmax, normalized);
+  
+  if (!res) {
+    igraph_vector_destroy(scores);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_centralization_degree_tmax
+ * Theoretical maximum for graph centralization based on degree
+ * 
+ * This function returns the theoretical maximum graph centrality
+ * based on vertex degree. 
+ * 
+ * </para><para>
+ * There are two ways to call this function, the first is to supply a
+ * graph as the <code>graph</code> argument, and then the number of
+ * vertices is taken from this object, and its directedness is
+ * considered as well. The <code>nodes</code> argument is ignored in
+ * this case. The <code>mode</code> argument is also ignored if the
+ * supplied graph is undirected.
+ * 
+ * </para><para>
+ * The other way is to supply a null pointer as the <code>graph</code>
+ * argument. In this case the <code>nodes</code> and <code>mode</code>
+ * arguments are considered.
+ * 
+ * </para><para>
+ * The most centralized structure is the star. More specifically, for
+ * undirected graphs it is the star, for directed graphs it is the
+ * in-star or the out-star.
+ * \param graph A graph object or a null pointer, see the description
+ *     above.
+ * \param nodes The number of nodes. This is ignored if the
+ *     <code>graph</code> argument is not a null pointer.
+ * \param mode Constant, whether the calculation is based on in-degree
+ *     (<code>IGRAPH_IN</code>), out-degree (<code>IGRAPH_OUT</code>)
+ *     or total degree (<code>IGRAPH_ALL</code>). This is ignored if
+ *     the <code>graph</code> argument is not a null pointer and the
+ *     given graph is undirected. 
+ * \param loops Boolean scalar, whether to consider loop edges in the
+ *     calculation. 
+ * \param res Pointer to a real variable, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ * 
+ * \sa \ref igraph_centralization_degree() and \ref
+ * igraph_centralization().
+ */
+
+int igraph_centralization_degree_tmax(const igraph_t *graph, 
+				      igraph_integer_t nodes,
+				      igraph_neimode_t mode,
+				      igraph_bool_t loops,
+				      igraph_real_t *res) {
+
+  igraph_bool_t directed=mode != IGRAPH_ALL;
+  igraph_real_t real_nodes;
+
+  if (graph) {
+    directed=igraph_is_directed(graph);
+    nodes=igraph_vcount(graph);
+  }
+
+  real_nodes = nodes;    /* implicit cast to igraph_real_t */
+
+  if (directed) {
+    switch (mode) {
+    case IGRAPH_IN:
+    case IGRAPH_OUT:
+      if (!loops) {
+	*res = (real_nodes-1) * (real_nodes-1);
+      } else {
+	*res = (real_nodes-1) * real_nodes;
+      }
+      break;
+    case IGRAPH_ALL:
+      if (!loops) {
+	*res = 2 * (real_nodes-1) * (real_nodes-2);
+      } else {
+	*res = 2 * (real_nodes-1) * (real_nodes-1);
+      }
+      break;
+    }
+  } else {
+    if (!loops) {
+      *res = (real_nodes-1) * (real_nodes-2);
+    } else {
+      *res = (real_nodes-1) * real_nodes;
+    }
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_centralization_betweenness
+ * Calculate vertex betweenness and graph centralization
+ * 
+ * This function calculates the betweenness centrality of the vertices
+ * by passing its arguments to \ref igraph_betweenness(); and it
+ * calculates the graph level centralization index based on the
+ * results by calling \ref igraph_centralization().
+ * \param graph The input graph.
+ * \param res A vector if you need the node-level betweenness scores, or a
+ *     null pointer otherwise.
+ * \param directed Boolean, whether to consider directed paths when
+ *     calculating betweenness.
+ * \param nobigint Logical, if true, then we don't use big integers
+ *        for the calculation, setting this to zero (=false) should
+ *        work for most graphs. It is currently ignored for weighted
+ *        graphs.
+ * \param centralization Pointer to a real number, the centralization
+ *     score is placed here.
+ * \param theoretical_max Pointer to real number or a null pointer. If
+ *     not a null pointer, then the theoretical maximum graph
+ *     centrality score for a graph with the same number vertices is
+ *     stored here.
+ * \param normalized Boolean, whether to calculate a normalized
+ *     centralization score. See \ref igraph_centralization() for how
+ *     the normalization is done.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_centralization(), \ref igraph_betweenness().
+ * 
+ * Time complexity: the complexity of \ref igraph_betweenness() plus
+ * O(n), the number of vertices queried, for calculating the
+ * centralization score.
+ */
+
+int igraph_centralization_betweenness(const igraph_t *graph, 
+				      igraph_vector_t *res,
+				      igraph_bool_t directed,
+				      igraph_bool_t nobigint,
+				      igraph_real_t *centralization,
+				      igraph_real_t *theoretical_max,
+				      igraph_bool_t normalized) {
+  
+  igraph_vector_t myscores;
+  igraph_vector_t *scores=res;
+  igraph_real_t *tmax=theoretical_max, mytmax;
+
+  if (!tmax) { tmax=&mytmax; }
+
+  if (!res) {
+    scores=&myscores;
+    IGRAPH_VECTOR_INIT_FINALLY(scores, 0);
+  }
+  
+  IGRAPH_CHECK(igraph_betweenness(graph, scores, igraph_vss_all(), directed, 
+				  /*weights=*/ 0, nobigint));
+  
+  IGRAPH_CHECK(igraph_centralization_betweenness_tmax(graph, 0, directed, 
+						      tmax));
+  
+  *centralization = igraph_centralization(scores, *tmax, normalized);
+  
+  if (!res) {
+    igraph_vector_destroy(scores);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_centralization_betweenness_tmax
+ * Theoretical maximum for graph centralization based on betweenness
+ * 
+ * This function returns the theoretical maximum graph centrality
+ * based on vertex betweenness. 
+ * 
+ * </para><para>
+ * There are two ways to call this function, the first is to supply a
+ * graph as the <code>graph</code> argument, and then the number of
+ * vertices is taken from this object, and its directedness is
+ * considered as well. The <code>nodes</code> argument is ignored in
+ * this case. The <code>directed</code> argument is also ignored if the
+ * supplied graph is undirected.
+ * 
+ * </para><para>
+ * The other way is to supply a null pointer as the <code>graph</code>
+ * argument. In this case the <code>nodes</code> and <code>directed</code>
+ * arguments are considered.
+ * 
+ * </para><para>
+ * The most centralized structure is the star.
+ * \param graph A graph object or a null pointer, see the description
+ *     above.
+ * \param nodes The number of nodes. This is ignored if the
+ *     <code>graph</code> argument is not a null pointer.
+ * \param directed Boolean scalar, whether to use directed paths in
+ *     the betweenness calculation. This argument is ignored if
+ *     <code>graph</code> is not a null pointer and it is undirected.
+ * \param res Pointer to a real variable, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ * 
+ * \sa \ref igraph_centralization_betweenness() and \ref
+ * igraph_centralization().
+ */
+
+int igraph_centralization_betweenness_tmax(const igraph_t *graph, 
+					   igraph_integer_t nodes,
+					   igraph_bool_t directed,
+					   igraph_real_t *res) {
+  igraph_real_t real_nodes;
+
+  if (graph) { 
+    directed=directed && igraph_is_directed(graph); 
+    nodes=igraph_vcount(graph);
+  }
+
+  real_nodes = nodes;    /* implicit cast to igraph_real_t */
+
+  if (directed) {
+    *res = (real_nodes-1) * (real_nodes-1) * (real_nodes-2);
+  } else {
+    *res = (real_nodes-1) * (real_nodes-1) * (real_nodes-2) / 2.0;
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_centralization_closeness
+ * Calculate vertex closeness and graph centralization
+ * 
+ * This function calculates the closeness centrality of the vertices
+ * by passing its arguments to \ref igraph_closeness(); and it
+ * calculates the graph level centralization index based on the
+ * results by calling \ref igraph_centralization().
+ * \param graph The input graph.
+ * \param res A vector if you need the node-level closeness scores, or a
+ *     null pointer otherwise.
+ * \param mode Constant the specifies the type of closeness for directed
+ *     graphs. Possible values: \c IGRAPH_IN, \c IGRAPH_OUT and \c
+ *     IGRAPH_ALL. This argument is ignored for undirected graphs. See
+ *     \ref igraph_closeness() argument with the same name for more.
+ * \param centralization Pointer to a real number, the centralization
+ *     score is placed here.
+ * \param theoretical_max Pointer to real number or a null pointer. If
+ *     not a null pointer, then the theoretical maximum graph
+ *     centrality score for a graph with the same number vertices is
+ *     stored here.
+ * \param normalized Boolean, whether to calculate a normalized
+ *     centralization score. See \ref igraph_centralization() for how
+ *     the normalization is done.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_centralization(), \ref igraph_closeness().
+ * 
+ * Time complexity: the complexity of \ref igraph_closeness() plus
+ * O(n), the number of vertices queried, for calculating the
+ * centralization score.
+ */
+
+int igraph_centralization_closeness(const igraph_t *graph, 
+				    igraph_vector_t *res, 
+				    igraph_neimode_t mode, 
+				    igraph_real_t *centralization,
+				    igraph_real_t *theoretical_max,
+				    igraph_bool_t normalized) {
+
+  igraph_vector_t myscores;
+  igraph_vector_t *scores=res;
+  igraph_real_t *tmax=theoretical_max, mytmax;
+
+  if (!tmax) { tmax=&mytmax; }    
+
+  if (!res) {
+    scores=&myscores;
+    IGRAPH_VECTOR_INIT_FINALLY(scores, 0);
+  }
+  
+  IGRAPH_CHECK(igraph_closeness(graph, scores, igraph_vss_all(), mode, 
+				/*weights=*/ 0, /*normalize=*/ 1));
+
+  IGRAPH_CHECK(igraph_centralization_closeness_tmax(graph, 0, mode, 
+						    tmax));
+
+  *centralization = igraph_centralization(scores, *tmax, normalized);
+  
+  if (!res) {
+    igraph_vector_destroy(scores);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_centralization_closeness_tmax
+ * Theoretical maximum for graph centralization based on closeness
+ * 
+ * This function returns the theoretical maximum graph centrality
+ * based on vertex closeness. 
+ * 
+ * </para><para>
+ * There are two ways to call this function, the first is to supply a
+ * graph as the <code>graph</code> argument, and then the number of
+ * vertices is taken from this object, and its directedness is
+ * considered as well. The <code>nodes</code> argument is ignored in
+ * this case. The <code>mode</code> argument is also ignored if the
+ * supplied graph is undirected.
+ * 
+ * </para><para>
+ * The other way is to supply a null pointer as the <code>graph</code>
+ * argument. In this case the <code>nodes</code> and <code>mode</code>
+ * arguments are considered.
+ * 
+ * </para><para>
+ * The most centralized structure is the star.
+ * \param graph A graph object or a null pointer, see the description
+ *     above.
+ * \param nodes The number of nodes. This is ignored if the
+ *     <code>graph</code> argument is not a null pointer.
+ * \param mode Constant, specifies what kinf of distances to consider
+ *     to calculate closeness. See the <code>mode</code> argument of
+ *     \ref igraph_closeness() for details. This argument is ignored
+ *     if <code>graph</code> is not a null pointer and it is
+ *     undirected.
+ * \param res Pointer to a real variable, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ * 
+ * \sa \ref igraph_centralization_closeness() and \ref
+ * igraph_centralization().
+ */
+
+int igraph_centralization_closeness_tmax(const igraph_t *graph,
+					 igraph_integer_t nodes,
+					 igraph_neimode_t mode,
+					 igraph_real_t *res) {
+  igraph_real_t real_nodes;
+
+  if (graph) {
+    nodes=igraph_vcount(graph); 
+    if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+  }
+
+  real_nodes = nodes;    /* implicit cast to igraph_real_t */
+
+  if (mode != IGRAPH_ALL) {
+    *res = (real_nodes-1) * (1.0-1.0/real_nodes);
+  } else {
+    *res = (real_nodes-1) * (real_nodes-2) / (2.0*real_nodes-3);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_centralization_eigenvector_centrality
+ * Calculate eigenvector centrality scores and graph centralization
+ * 
+ * This function calculates the eigenvector centrality of the vertices
+ * by passing its arguments to \ref igraph_eigenvector_centrality);
+ * and it calculates the graph level centralization index based on the
+ * results by calling \ref igraph_centralization().
+ * \param graph The input graph.
+ * \param vector A vector if you need the node-level eigenvector
+ *      centrality scores, or a null pointer otherwise.
+ * \param value If not a null pointer, then the leading eigenvalue is
+ *      stored here.
+ * \param scale If not zero then the result will be scaled, such that
+ *     the absolute value of the maximum centrality is one.
+ * \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) parameter and 
+ *    it always starts the calculation from a non-random vector
+ *    calculated based on the degree of the vertices.
+ * \param centralization Pointer to a real number, the centralization
+ *     score is placed here.
+ * \param theoretical_max Pointer to real number or a null pointer. If
+ *     not a null pointer, then the theoretical maximum graph
+ *     centrality score for a graph with the same number vertices is
+ *     stored here.
+ * \param normalized Boolean, whether to calculate a normalized
+ *     centralization score. See \ref igraph_centralization() for how
+ *     the normalization is done.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_centralization(), \ref igraph_eigenvector_centrality().
+ * 
+ * Time complexity: the complexity of \ref
+ * igraph_eigenvector_centrality() plus O(|V|), the number of vertices
+ * for the calculating the centralization.
+ */
+
+int igraph_centralization_eigenvector_centrality(
+					 const igraph_t *graph,
+					 igraph_vector_t *vector,
+					 igraph_real_t *value,
+					 igraph_bool_t directed,
+					 igraph_bool_t scale,
+					 igraph_arpack_options_t *options,
+					 igraph_real_t *centralization,
+					 igraph_real_t *theoretical_max,
+					 igraph_bool_t normalized) {
+  
+  igraph_vector_t myscores;
+  igraph_vector_t *scores=vector;
+  igraph_real_t realvalue, *myvalue=value;
+  igraph_real_t *tmax=theoretical_max, mytmax;
+
+  if (!tmax) { tmax=&mytmax; }
+
+  if (!vector) {
+    scores=&myscores;
+    IGRAPH_VECTOR_INIT_FINALLY(scores, 0);
+  }
+  if (!value) {
+    myvalue=&realvalue;
+  }
+  
+  IGRAPH_CHECK(igraph_eigenvector_centrality(graph, scores, myvalue, directed,
+					     scale, /*weights=*/ 0, 
+					     options));
+
+  IGRAPH_CHECK(igraph_centralization_eigenvector_centrality_tmax(
+						 graph, 0, directed, 
+						 scale, 
+						 tmax));
+
+  *centralization = igraph_centralization(scores, *tmax, normalized);
+  
+  if (!vector) {
+    igraph_vector_destroy(scores);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_centralization_eigenvector_centrality_tmax
+ * Theoretical maximum centralization for eigenvector centrality
+ * 
+ * This function returns the theoretical maximum graph centrality
+ * based on vertex eigenvector centrality. 
+ * 
+ * </para><para>
+ * There are two ways to call this function, the first is to supply a
+ * graph as the <code>graph</code> argument, and then the number of
+ * vertices is taken from this object, and its directedness is
+ * considered as well. The <code>nodes</code> argument is ignored in
+ * this case. The <code>directed</code> argument is also ignored if the
+ * supplied graph is undirected.
+ * 
+ * </para><para>
+ * The other way is to supply a null pointer as the <code>graph</code>
+ * argument. In this case the <code>nodes</code> and <code>directed</code>
+ * arguments are considered.
+ * 
+ * </para><para>
+ * The most centralized directed structure is the in-star. The most
+ * centralized undirected structure is the graph with a single edge.
+ * \param graph A graph object or a null pointer, see the description
+ *     above.
+ * \param nodes The number of nodes. This is ignored if the
+ *     <code>graph</code> argument is not a null pointer.
+ * \param directed Boolean scalar, whether to consider edge
+ *     directions. This argument is ignored if
+ *     <code>graph</code> is not a null pointer and it is undirected.
+ * \param scale Whether to rescale the node-level centrality scores to
+ *     have a maximum of one.
+ * \param res Pointer to a real variable, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ * 
+ * \sa \ref igraph_centralization_closeness() and \ref
+ * igraph_centralization().
+ */
+
+int igraph_centralization_eigenvector_centrality_tmax(
+					 const igraph_t *graph,
+					 igraph_integer_t nodes,
+					 igraph_bool_t directed,
+					 igraph_bool_t scale, 
+					 igraph_real_t *res) {
+
+  if (graph) {
+    nodes=igraph_vcount(graph);
+    directed=directed && igraph_is_directed(graph);
+  }
+  
+  if (directed) {
+    *res = nodes - 1; 
+  } else {
+    if (scale) { 
+      *res = nodes - 2;
+    } else {
+      *res = (nodes-2.0) / M_SQRT2;
+    }
+  }
+
+  return 0;
+}
diff --git a/src/cliques.c b/src/cliques.c
new file mode 100644
index 0000000..0fde867
--- /dev/null
+++ b/src/cliques.c
@@ -0,0 +1,1166 @@
+ /* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_cliques.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_constants.h"
+#include "igraph_adjlist.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_interface.h"
+#include "igraph_progress.h"
+#include "igraph_stack.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>    /* memset */
+
+void igraph_i_cliques_free_res(igraph_vector_ptr_t *res) {
+  long i, n;
+  
+  n = igraph_vector_ptr_size(res);
+  for (i=0; i<n; i++) {
+    if (VECTOR(*res)[i] != 0) {
+      igraph_vector_destroy(VECTOR(*res)[i]);
+      igraph_free(VECTOR(*res)[i]);
+    }
+  }
+  igraph_vector_ptr_clear(res);
+}
+
+int igraph_i_find_k_cliques(const igraph_t *graph,
+			    long int size,
+			    const igraph_real_t *member_storage,
+			    igraph_real_t **new_member_storage,
+			    long int old_clique_count,
+			    long int *clique_count,
+			    igraph_vector_t *neis,
+			    igraph_bool_t independent_vertices) {
+
+  long int j, k, l, m, n, new_member_storage_size;
+  const igraph_real_t *c1, *c2;
+  igraph_real_t v1, v2;
+  igraph_bool_t ok;
+  
+  /* Allocate the storage */
+  *new_member_storage=igraph_Realloc(*new_member_storage, 
+				     (size_t) (size*old_clique_count),
+				     igraph_real_t);
+  if (*new_member_storage == 0) {
+    IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
+  }
+  new_member_storage_size = size*old_clique_count;
+  IGRAPH_FINALLY(igraph_free, *new_member_storage);
+
+  m=n=0;
+  
+  /* Now consider all pairs of i-1-cliques and see if they can be merged */
+  for (j=0; j<old_clique_count; j++) {
+    for (k=j+1; k<old_clique_count; k++) {
+      IGRAPH_ALLOW_INTERRUPTION();
+        
+      /* Since cliques are represented by their vertex indices in increasing
+       * order, two cliques can be merged iff they have exactly the same
+       * indices excluding one AND there is an edge between the two different
+       * vertices */
+      c1 = member_storage+j*(size-1);
+      c2 = member_storage+k*(size-1);
+      /* Find the longest prefixes of c1 and c2 that are equal */
+      for (l=0; l<size-1 && c1[l] == c2[l]; l++)
+	(*new_member_storage)[m++]=c1[l];
+      /* Now, if l == size-1, the two vectors are totally equal.
+	 This is a bug */
+      if (l == size-1) {
+	IGRAPH_WARNING("possible bug in igraph_cliques");
+	m=n;
+      } else {
+	/* Assuming that j<k, c1[l] is always less than c2[l], since cliques
+	 * are ordered alphabetically. Now add c1[l] and store c2[l] in a
+	 * dummy variable */
+	(*new_member_storage)[m++]=c1[l];
+	v1=c1[l];
+	v2=c2[l];
+	l++;
+	/* Copy the remaining part of the two vectors. Every member pair
+	 * found in the remaining parts satisfies the following:
+	 * 1. If they are equal, they should be added.
+	 * 2. If they are not equal, the smaller must be equal to the
+	 *    one stored in the dummy variable. If not, the two vectors
+	 *    differ in more than one place. The larger will be stored in
+	 *    the dummy variable again.
+	 */
+	ok=1;
+	for (; l<size-1; l++) {
+	  if (c1[l] == c2[l]) {
+	    (*new_member_storage)[m++]=c1[l];
+	    ok=0;
+	  } else if (ok) {
+	    if (c1[l] < c2[l]) {
+	      if (c1[l] == v1) {
+		(*new_member_storage)[m++]=c1[l];
+		v2 = c2[l];
+	      } else break;
+	    } else {
+	      if (ok && c2[l] == v1) {
+		(*new_member_storage)[m++]=c2[l];
+		v2 = c1[l];
+	      } else break;
+	    }
+	  } else break;
+	}
+	/* Now, if l != size-1, the two vectors had a difference in more than
+	 * one place, so the whole clique is invalid. */
+	if (l != size-1) {
+	  /* Step back in new_member_storage */
+	  m=n;
+	} else {
+	  /* v1 and v2 are the two different vertices. Check for an edge
+	   * if we are looking for cliques and check for the absence of an
+	   * edge if we are looking for independent vertex sets */
+	  IGRAPH_CHECK(igraph_neighbors(graph, neis, (igraph_integer_t) v1,
+					IGRAPH_ALL));
+	  l=igraph_vector_search(neis, 0, v2, 0);
+	  if ((l && !independent_vertices) || (!l && independent_vertices)) {
+	    /* Found a new clique, step forward in new_member_storage */
+	    if (m==n || v2>(*new_member_storage)[m-1]) {
+	      (*new_member_storage)[m++]=v2;
+	      n=m;
+	    } else {
+	      m=n;
+	    }
+	  } else {
+	    m=n;
+	  }
+	}
+        /* See if new_member_storage is full. If so, reallocate */
+        if (m == new_member_storage_size) {
+            IGRAPH_FINALLY_CLEAN(1);
+            *new_member_storage = igraph_Realloc(*new_member_storage,
+					  (size_t) new_member_storage_size*2,
+                                          igraph_real_t);
+            if (*new_member_storage == 0)
+                IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
+            new_member_storage_size *= 2;
+            IGRAPH_FINALLY(igraph_free, *new_member_storage);
+        }
+      }
+    }
+  }
+
+  /* Calculate how many cliques have we found */
+  *clique_count = n/size;
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}  
+
+/* Internal function for calculating cliques or independent vertex sets.
+ * They are practically the same except that the complementer of the graph
+ * should be used in the latter case.
+ */
+int igraph_i_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
+		     igraph_integer_t min_size, igraph_integer_t max_size,
+		     igraph_bool_t independent_vertices) {
+
+  igraph_integer_t no_of_nodes;
+  igraph_vector_t neis;
+  igraph_real_t *member_storage=0, *new_member_storage, *c1;
+  long int i, j, k, clique_count, old_clique_count;
+  
+  if (igraph_is_directed(graph))
+    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");
+
+  no_of_nodes = igraph_vcount(graph);
+  
+  if (min_size < 0) { min_size = 0; }
+  if (max_size > no_of_nodes || max_size <= 0) { max_size = no_of_nodes; }
+
+  igraph_vector_ptr_clear(res);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_FINALLY(igraph_i_cliques_free_res, res);
+    
+  /* Will be resized later, if needed. */
+  member_storage=igraph_Calloc(1, igraph_real_t);
+  if (member_storage==0) {
+    IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, member_storage);
+  
+  /* Find all 1-cliques: every vertex will be a clique */
+  new_member_storage=igraph_Calloc(no_of_nodes, igraph_real_t);
+  if (new_member_storage==0) {
+    IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, new_member_storage);
+  
+  for (i=0; i<no_of_nodes; i++) {
+    new_member_storage[i] = i;
+  }
+  clique_count = no_of_nodes;
+  old_clique_count = 0;
+
+  /* Add size 1 cliques if requested */
+  if (min_size <= 1) {
+    IGRAPH_CHECK(igraph_vector_ptr_resize(res, no_of_nodes));
+    igraph_vector_ptr_null(res);
+    for (i=0; i<no_of_nodes; i++) {
+      igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
+      if (p==0) {
+	IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, p);
+      IGRAPH_CHECK(igraph_vector_init(p, 1));
+      VECTOR(*p)[0]=i;
+      VECTOR(*res)[i]=p;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }      
+
+  for (i=2; i<=max_size && clique_count > 1; i++) {
+
+    /* Here new_member_storage contains the cliques found in the previous
+       iteration. Save this into member_storage, might be needed later  */
+
+    c1=member_storage;
+    member_storage=new_member_storage;
+    new_member_storage=c1;
+    old_clique_count=clique_count;
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    /* Calculate the cliques */
+    
+    IGRAPH_FINALLY_CLEAN(2);
+    IGRAPH_CHECK(igraph_i_find_k_cliques(graph, i, member_storage,
+					 &new_member_storage,
+					 old_clique_count,
+					 &clique_count,
+					 &neis,
+					 independent_vertices));
+    IGRAPH_FINALLY(igraph_free, member_storage);
+    IGRAPH_FINALLY(igraph_free, new_member_storage);
+    
+    /* Add the cliques just found to the result if requested */
+    if (i>=min_size && i<=max_size) {
+      for (j=0, k=0; j<clique_count; j++, k+=i) {
+	igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
+	if (p==0) {
+	  IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, p);
+	IGRAPH_CHECK(igraph_vector_init_copy(p, &new_member_storage[k], i));
+	IGRAPH_FINALLY(igraph_vector_destroy, p);
+	IGRAPH_CHECK(igraph_vector_ptr_push_back(res, p));
+	IGRAPH_FINALLY_CLEAN(2);
+      }
+    }
+    
+  } /* i <= max_size && clique_count != 0 */
+  
+  igraph_free(member_storage);
+  igraph_free(new_member_storage);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(4); /* 3 here, +1 is igraph_i_cliques_free_res */
+  
+  return 0;
+}
+
+/**
+ * \function igraph_cliques
+ * \brief Find all or some cliques in a graph
+ *
+ * </para><para>
+ * Cliques are fully connected subgraphs of a graph.
+ *
+ * </para><para>
+ * If you are only interested in the size of the largest clique in the graph,
+ * use \ref igraph_clique_number() instead.
+ *
+ * </para><para>The current implementation of this function searches
+ * for maximal independent vertex sets (see \ref
+ * igraph_maximal_independent_vertex_sets()) in the complementer graph
+ * using the algorithm published in: 
+ * S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm
+ * for generating all the maximal independent sets. SIAM J Computing,
+ * 6:505--517, 1977.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   objects which contain the indices of vertices involved in a clique.
+ *   The pointer vector will be resized if needed but note that the
+ *   objects in the pointer vector will not be freed.
+ * \param min_size Integer giving the minimum size of the cliques to be
+ *   returned. If negative or zero, no lower bound will be used.
+ * \param max_size Integer giving the maximum size of the cliques to be
+ *   returned. If negative or zero, no upper bound will be used.
+ * \return Error code.
+ *
+ * \sa \ref igraph_largest_cliques() and \ref igraph_clique_number().
+ *
+ * Time complexity: TODO
+ * 
+ * \example examples/simple/igraph_cliques.c
+ */
+int igraph_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
+                   igraph_integer_t min_size, igraph_integer_t max_size) {
+  return igraph_i_cliques(graph, res, min_size, max_size, 0);
+}
+
+typedef int(*igraph_i_maximal_clique_func_t)(const igraph_vector_t*, void*, igraph_bool_t*);
+typedef struct {
+    igraph_vector_ptr_t* result;
+    igraph_integer_t min_size;
+    igraph_integer_t max_size;
+} igraph_i_maximal_clique_data_t;
+
+int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data);
+
+int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
+                                        igraph_vector_ptr_t *res,
+                                        igraph_integer_t *clique_number,
+                                        igraph_bool_t keep_only_largest,
+					igraph_bool_t complementer);
+
+/**
+ * \function igraph_independent_vertex_sets
+ * \brief Find all independent vertex sets in a graph
+ *
+ * </para><para>
+ * A vertex set is considered independent if there are no edges between
+ * them.
+ *
+ * </para><para>
+ * If you are interested in the size of the largest independent vertex set,
+ * use \ref igraph_independence_number() instead.
+ *
+ * </para><para>
+ * The current implementation was ported to igraph from the Very Nauty Graph
+ * Library by Keith Briggs and uses the algorithm from the paper
+ * S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm
+ * for generating all the maximal independent sets. SIAM J Computing,
+ * 6:505--517, 1977.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   objects which contain the indices of vertices involved in an independent
+ *   vertex set. The pointer vector will be resized if needed but note that the
+ *   objects in the pointer vector will not be freed.
+ * \param min_size Integer giving the minimum size of the sets to be
+ *   returned. If negative or zero, no lower bound will be used.
+ * \param max_size Integer giving the maximum size of the sets to be
+ *   returned. If negative or zero, no upper bound will be used. 
+ * \return Error code.
+ *
+ * \sa \ref igraph_largest_independent_vertex_sets(), 
+ * \ref igraph_independence_number().
+ *
+ * Time complexity: TODO
+ * 
+ * \example examples/simple/igraph_independent_sets.c
+ */
+int igraph_independent_vertex_sets(const igraph_t *graph,
+				   igraph_vector_ptr_t *res,
+				   igraph_integer_t min_size,
+				   igraph_integer_t max_size) {
+  return igraph_i_cliques(graph, res, min_size, max_size, 1);
+}
+
+/**
+ * \function igraph_largest_independent_vertex_sets
+ * \brief Finds the largest independent vertex set(s) in a graph.
+ * 
+ * </para><para>
+ * An independent vertex set is largest if there is no other
+ * independent vertex set with more vertices in the graph.
+ *
+ * </para><para>
+ * The current implementation was ported to igraph from the Very Nauty Graph
+ * Library by Keith Briggs and uses the algorithm from the paper
+ * S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm
+ * for generating all the maximal independent sets. SIAM J Computing,
+ * 6:505--517, 1977.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *     here. It will be resized as needed.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_independent_vertex_sets(), \ref
+ * igraph_maximal_independent_vertex_sets().
+ * 
+ * Time complexity: TODO
+ */
+
+int igraph_largest_independent_vertex_sets(const igraph_t *graph,
+					   igraph_vector_ptr_t *res) {
+  return igraph_i_maximal_or_largest_cliques_or_indsets(graph, res, 0, 1, 0);
+}
+
+typedef struct igraph_i_max_ind_vsets_data_t {
+  igraph_integer_t matrix_size;
+  igraph_adjlist_t adj_list;         /* Adjacency list of the graph */
+  igraph_vector_t deg;                 /* Degrees of individual nodes */
+  igraph_set_t* buckets;               /* Bucket array */
+  /* The IS value for each node. Still to be explained :) */
+  igraph_integer_t* IS;
+  igraph_integer_t largest_set_size;   /* Size of the largest set encountered */
+  igraph_bool_t keep_only_largest;     /* True if we keep only the largest sets */
+} igraph_i_max_ind_vsets_data_t;
+
+int igraph_i_maximal_independent_vertex_sets_backtrack(const igraph_t *graph,
+						       igraph_vector_ptr_t *res,
+						       igraph_i_max_ind_vsets_data_t *clqdata,
+						       igraph_integer_t level) {
+  long int v1, v2, v3, c, j, k;
+  igraph_vector_int_t *neis1, *neis2;
+  igraph_bool_t f;
+  igraph_integer_t j1;
+  long int it_state;
+
+  IGRAPH_ALLOW_INTERRUPTION();
+
+  if (level >= clqdata->matrix_size-1) {
+    igraph_integer_t size=0;
+    if (res) {
+      igraph_vector_t *vec;
+      vec = igraph_Calloc(1, igraph_vector_t);
+      if (vec == 0)
+        IGRAPH_ERROR("igraph_i_maximal_independent_vertex_sets failed", IGRAPH_ENOMEM);
+      IGRAPH_VECTOR_INIT_FINALLY(vec, 0);
+      for (v1=0; v1<clqdata->matrix_size; v1++)
+	if (clqdata->IS[v1] == 0) {
+	  IGRAPH_CHECK(igraph_vector_push_back(vec, v1));
+	}
+      size=(igraph_integer_t) igraph_vector_size(vec);
+      if (!clqdata->keep_only_largest)
+        IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec));
+      else {
+        if (size > clqdata->largest_set_size) {
+          /* We are keeping only the largest sets, and we've found one that's
+           * larger than all previous sets, so we have to clear the list */
+          j=igraph_vector_ptr_size(res);
+          for (v1=0; v1<j; v1++) {
+            igraph_vector_destroy(VECTOR(*res)[v1]);
+            free(VECTOR(*res)[v1]);
+          }
+          igraph_vector_ptr_clear(res);
+          IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec));
+        } else if (size == clqdata->largest_set_size) {
+          IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec));
+        } else {
+		  igraph_vector_destroy(vec);
+		  free(vec);
+		}
+      }
+      IGRAPH_FINALLY_CLEAN(1);
+    } else {
+      for (v1=0, size=0; v1<clqdata->matrix_size; v1++)
+	if (clqdata->IS[v1] == 0) size++;
+    }
+    if (size>clqdata->largest_set_size) clqdata->largest_set_size=size;
+  } else {
+    v1 = level+1;
+    /* Count the number of vertices with an index less than v1 that have
+     * an IS value of zero */
+    neis1 = igraph_adjlist_get(&clqdata->adj_list, v1);
+    c = 0;
+    j = 0;
+    while (j<VECTOR(clqdata->deg)[v1] && 
+	   (v2=(long int) VECTOR(*neis1)[j]) <= level) {
+      if (clqdata->IS[v2] == 0) c++;
+      j++;
+    }
+
+    if (c == 0) {
+      /* If there are no such nodes... */
+      j = 0;
+      while (j<VECTOR(clqdata->deg)[v1] && 
+	     (v2=(long int) VECTOR(*neis1)[j]) <= level) {
+	clqdata->IS[v2]++;
+	j++;
+      }
+      IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata, (igraph_integer_t) v1));
+      j = 0;
+      while (j<VECTOR(clqdata->deg)[v1] && 
+	     (v2=(long int) VECTOR(*neis1)[j]) <= level) {
+	clqdata->IS[v2]--;
+	j++;
+      }
+    } else {
+      /* If there are such nodes, store the count in the IS value of v1 */
+      clqdata->IS[v1] = (igraph_integer_t) c;
+      IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata, (igraph_integer_t) v1));
+      clqdata->IS[v1] = 0;
+      
+      f=1;
+      j=0;
+      while (j<VECTOR(clqdata->deg)[v1] && 
+	     (v2=(long int) VECTOR(*neis1)[j]) <= level) {
+	if (clqdata->IS[v2] == 0) {
+	  IGRAPH_CHECK(igraph_set_add(&clqdata->buckets[v1],
+				      (igraph_integer_t) j));
+	  neis2 = igraph_adjlist_get(&clqdata->adj_list, v2);
+	  k = 0;
+	  while (k<VECTOR(clqdata->deg)[v2] &&
+		 (v3=(long int) VECTOR(*neis2)[k])<=level) {
+	    clqdata->IS[v3]--;
+	    if (clqdata->IS[v3] == 0) f=0;
+	    k++;
+	  }
+	}
+	clqdata->IS[v2]++;
+	j++;
+      }
+
+      if (f) 
+	IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata, (igraph_integer_t) v1));
+
+      j=0;
+      while (j<VECTOR(clqdata->deg)[v1] && 
+	     (v2=(long int) VECTOR(*neis1)[j]) <= level) {
+	clqdata->IS[v2]--;
+	j++;
+      }
+      
+      it_state=0;
+      while (igraph_set_iterate(&clqdata->buckets[v1], &it_state, &j1)) {
+	j=(long)j1;
+	v2=(long int) VECTOR(*neis1)[j];
+	neis2 = igraph_adjlist_get(&clqdata->adj_list, v2);
+	k = 0;
+	while (k<VECTOR(clqdata->deg)[v2] && 
+	       (v3=(long int) VECTOR(*neis2)[k])<=level) {
+	  clqdata->IS[v3]++;
+	  k++;
+	}
+      }
+      igraph_set_clear(&clqdata->buckets[v1]);
+    }
+  }
+
+  return 0;
+}
+
+void igraph_i_free_set_array(igraph_set_t* array) {
+  long int i = 0;
+  while (igraph_set_inited(array+i)) {
+    igraph_set_destroy(array+i);
+    i++;
+  }
+  igraph_Free(array);
+}
+
+/**
+ * \function igraph_maximal_independent_vertex_sets
+ * \brief Find all maximal independent vertex sets of a graph
+ *
+ * </para><para>
+ * A maximal independent vertex set is an independent vertex set which
+ * can't be extended any more by adding a new vertex to it.
+ *
+ * </para><para>
+ * The algorithm used here is based on the following paper:
+ * S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm for
+ * generating all the maximal independent sets. SIAM J Computing,
+ * 6:505--517, 1977.
+ *
+ * </para><para>
+ * The implementation was originally written by Kevin O'Neill and modified
+ * by K M Briggs in the Very Nauty Graph Library. I simply re-wrote it to
+ * use igraph's data structures.
+ * 
+ * </para><para>
+ * If you are interested in the size of the largest independent vertex set,
+ * use \ref igraph_independence_number() instead.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   objects which contain the indices of vertices involved in an independent
+ *   vertex set. The pointer vector will be resized if needed but note that the
+ *   objects in the pointer vector will not be freed.
+ * \return Error code.
+ *
+ * \sa \ref igraph_maximal_cliques(), \ref
+ * igraph_independence_number()
+ * 
+ * Time complexity: TODO.
+ */
+int igraph_maximal_independent_vertex_sets(const igraph_t *graph,
+					   igraph_vector_ptr_t *res) {
+  igraph_i_max_ind_vsets_data_t clqdata;
+  igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph), i;
+
+  if (igraph_is_directed(graph))
+    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");
+
+  clqdata.matrix_size=no_of_nodes;
+  clqdata.keep_only_largest=0;
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &clqdata.adj_list, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list);
+
+  clqdata.IS = igraph_Calloc(no_of_nodes, igraph_integer_t);
+  if (clqdata.IS == 0)
+    IGRAPH_ERROR("igraph_maximal_independent_vertex_sets failed", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_free, clqdata.IS);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&clqdata.deg, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++)
+    VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i));
+
+  clqdata.buckets = igraph_Calloc(no_of_nodes+1, igraph_set_t);
+  if (clqdata.buckets == 0)
+    IGRAPH_ERROR("igraph_maximal_independent_vertex_sets failed", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_i_free_set_array, clqdata.buckets);
+
+  for (i=0; i<no_of_nodes; i++)
+    IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0));
+
+  igraph_vector_ptr_clear(res);
+  
+  /* Do the show */
+  clqdata.largest_set_size=0;
+  IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph, res, &clqdata, 0));
+
+  /* Cleanup */
+  for (i=0; i<no_of_nodes; i++) igraph_set_destroy(&clqdata.buckets[i]);
+  igraph_adjlist_destroy(&clqdata.adj_list);
+  igraph_vector_destroy(&clqdata.deg);
+  igraph_free(clqdata.IS);
+  igraph_free(clqdata.buckets);
+  IGRAPH_FINALLY_CLEAN(4);
+  return 0;
+}
+
+/**
+ * \function igraph_independence_number
+ * \brief Find the independence number of the graph
+ *
+ * </para><para>
+ * The independence number of a graph is the cardinality of the largest
+ * independent vertex set.
+ *
+ * </para><para>
+ * The current implementation was ported to igraph from the Very Nauty Graph
+ * Library by Keith Briggs and uses the algorithm from the paper
+ * S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm
+ * for generating all the maximal independent sets. SIAM J Computing,
+ * 6:505--517, 1977.
+ *
+ * \param graph The input graph.
+ * \param no The independence number will be returned to the \c
+ *   igraph_integer_t pointed by this variable.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_independent_vertex_sets().
+ *
+ * Time complexity: TODO.
+ */
+int igraph_independence_number(const igraph_t *graph, igraph_integer_t *no) {
+  igraph_i_max_ind_vsets_data_t clqdata;
+  igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph), i;
+
+  if (igraph_is_directed(graph))
+    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");
+
+  clqdata.matrix_size=no_of_nodes;
+  clqdata.keep_only_largest=0;
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &clqdata.adj_list, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list);
+
+  clqdata.IS = igraph_Calloc(no_of_nodes, igraph_integer_t);
+  if (clqdata.IS == 0)
+    IGRAPH_ERROR("igraph_independence_number failed", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_free, clqdata.IS);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&clqdata.deg, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++)
+    VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i));
+
+  clqdata.buckets = igraph_Calloc(no_of_nodes+1, igraph_set_t);
+  if (clqdata.buckets == 0)
+    IGRAPH_ERROR("igraph_independence_number failed", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_i_free_set_array, clqdata.buckets);
+
+  for (i=0; i<no_of_nodes; i++)
+    IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0));
+
+  /* Do the show */
+  clqdata.largest_set_size=0;
+  IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph, 0, &clqdata, 0));
+  *no = clqdata.largest_set_size;
+
+  /* Cleanup */
+  for (i=0; i<no_of_nodes; i++) igraph_set_destroy(&clqdata.buckets[i]);
+  igraph_adjlist_destroy(&clqdata.adj_list);
+  igraph_vector_destroy(&clqdata.deg);
+  igraph_free(clqdata.IS);
+  igraph_free(clqdata.buckets);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/*************************************************************************/
+/* MAXIMAL CLIQUES, LARGEST CLIQUES                                      */
+/*************************************************************************/
+
+int igraph_i_maximal_cliques_store_max_size(const igraph_vector_t* clique, void* data,
+    igraph_bool_t* cont) {
+  igraph_integer_t* result = (igraph_integer_t*)data;
+  IGRAPH_UNUSED(cont);
+  if (*result < igraph_vector_size(clique))
+    *result = (igraph_integer_t) igraph_vector_size(clique);
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_maximal_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
+  igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data;
+  igraph_vector_t* vec;
+
+  IGRAPH_UNUSED(cont);
+  vec = igraph_Calloc(1, igraph_vector_t);
+  if (vec == 0)
+    IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM);
+
+  IGRAPH_CHECK(igraph_vector_copy(vec, clique));
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec));
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_maximal_cliques_store_size_check(const igraph_vector_t* clique, void* data_, igraph_bool_t* cont) {
+  igraph_i_maximal_clique_data_t* data = (igraph_i_maximal_clique_data_t*)data_;
+  igraph_vector_t* vec;
+  igraph_integer_t size = (igraph_integer_t) igraph_vector_size(clique);
+
+  IGRAPH_UNUSED(cont);
+  if (size < data->min_size || size > data->max_size)
+    return IGRAPH_SUCCESS;
+
+  vec = igraph_Calloc(1, igraph_vector_t);
+  if (vec == 0)
+    IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM);
+
+  IGRAPH_CHECK(igraph_vector_copy(vec, clique));
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(data->result, vec));
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_largest_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
+  igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data;
+  igraph_vector_t* vec;
+  long int i, n;
+
+  IGRAPH_UNUSED(cont);
+  /* Is the current clique at least as large as the others that we have found? */
+  if (!igraph_vector_ptr_empty(result)) {
+    n = igraph_vector_size(clique);
+    if (n < igraph_vector_size(VECTOR(*result)[0]))
+      return IGRAPH_SUCCESS;
+
+    if (n > igraph_vector_size(VECTOR(*result)[0])) {
+      for (i = 0; i < igraph_vector_ptr_size(result); i++)
+        igraph_vector_destroy(VECTOR(*result)[i]);
+      igraph_vector_ptr_free_all(result);
+      igraph_vector_ptr_resize(result, 0);
+    }
+  }
+
+  vec = igraph_Calloc(1, igraph_vector_t);
+  if (vec == 0)
+    IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM);
+
+  IGRAPH_CHECK(igraph_vector_copy(vec, clique));
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec));
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_largest_cliques
+ * \brief Finds the largest clique(s) in a graph.
+ * 
+ * </para><para>
+ * A clique is largest (quite intuitively) if there is no other clique
+ * in the graph which contains more vertices. 
+ * 
+ * </para><para>
+ * Note that this is not necessarily the same as a maximal clique,
+ * ie. the largest cliques are always maximal but a maximal clique is
+ * not always largest.
+ *
+ * </para><para>The current implementation of this function searches
+ * for maximal cliques using \ref igraph_maximal_cliques() and drops
+ * those that are not the largest.
+ *
+ * </para><para>The implementation of this function changed between
+ * igraph 0.5 and 0.6, so the order of the cliques and the order of
+ * vertices within the cliques will almost surely be different between
+ * these two versions.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to an initialized pointer vector, the result
+ *        will be stored here. It will be resized as needed. Note that
+ *        vertices of a clique may be returned in arbitrary order.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_cliques(), \ref igraph_maximal_cliques()
+ * 
+ * Time complexity: O(3^(|V|/3)) worst case.
+ */
+
+int igraph_largest_cliques(const igraph_t *graph, igraph_vector_ptr_t *res) {
+  igraph_vector_ptr_clear(res);
+  IGRAPH_FINALLY(igraph_i_cliques_free_res, res);
+  IGRAPH_CHECK(igraph_i_maximal_cliques(graph, &igraph_i_largest_cliques_store, (void*)res));
+  IGRAPH_FINALLY_CLEAN(1);
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_clique_number
+ * \brief Find the clique number of the graph
+ *
+ * </para><para>
+ * The clique number of a graph is the size of the largest clique.
+ *
+ * \param graph The input graph.
+ * \param no The clique number will be returned to the \c igraph_integer_t
+ *   pointed by this variable.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_cliques(), \ref igraph_largest_cliques().
+ * 
+ * Time complexity: O(3^(|V|/3)) worst case.
+ */
+int igraph_clique_number(const igraph_t *graph, igraph_integer_t *no) {
+  *no = 0;
+  return igraph_i_maximal_cliques(graph, &igraph_i_maximal_cliques_store_max_size, (void*)no);
+}
+
+typedef struct {
+  igraph_vector_int_t cand;
+  igraph_vector_int_t fini;
+  igraph_vector_int_t cand_filtered;
+} igraph_i_maximal_cliques_stack_frame;
+
+void igraph_i_maximal_cliques_stack_frame_destroy(igraph_i_maximal_cliques_stack_frame *frame) {
+  igraph_vector_int_destroy(&frame->cand);
+  igraph_vector_int_destroy(&frame->fini);
+  igraph_vector_int_destroy(&frame->cand_filtered);
+}
+
+void igraph_i_maximal_cliques_stack_destroy(igraph_stack_ptr_t *stack) {
+  igraph_i_maximal_cliques_stack_frame *frame;
+
+  while (!igraph_stack_ptr_empty(stack)) {
+    frame = (igraph_i_maximal_cliques_stack_frame*)igraph_stack_ptr_pop(stack);
+    igraph_i_maximal_cliques_stack_frame_destroy(frame);
+    free(frame);
+  }
+
+  igraph_stack_ptr_destroy(stack);
+}
+
+int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) {
+  int directed=igraph_is_directed(graph);
+  long int i, j, k, l;
+  igraph_integer_t no_of_nodes, nodes_to_check, nodes_done;
+  igraph_integer_t best_cand = 0, best_cand_degree = 0, best_fini_cand_degree;
+  igraph_adjlist_t adj_list;
+  igraph_stack_ptr_t stack;
+  igraph_i_maximal_cliques_stack_frame frame, *new_frame_ptr;
+  igraph_vector_t clique;
+  igraph_vector_int_t new_cand, new_fini, cn, best_cand_nbrs,
+    best_fini_cand_nbrs;
+  igraph_bool_t cont = 1;
+  int assret;
+
+  if (directed)
+    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");
+
+  no_of_nodes = igraph_vcount(graph);
+  if (no_of_nodes == 0)
+    return IGRAPH_SUCCESS;
+
+  /* Construct an adjacency list representation */
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adj_list, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_list);
+  IGRAPH_CHECK(igraph_adjlist_simplify(&adj_list));
+  igraph_adjlist_sort(&adj_list);
+
+  /* Initialize stack */
+  IGRAPH_CHECK(igraph_stack_ptr_init(&stack, 0));
+  IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_destroy, &stack);
+
+  /* Create the initial (empty) clique */
+  IGRAPH_VECTOR_INIT_FINALLY(&clique, 0);
+
+  /* Initialize new_cand, new_fini, cn, best_cand_nbrs and best_fini_cand_nbrs (will be used later) */
+  igraph_vector_int_init(&new_cand, 0);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &new_cand);
+  igraph_vector_int_init(&new_fini, 0);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &new_fini);
+  igraph_vector_int_init(&cn, 0);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &cn);
+  igraph_vector_int_init(&best_cand_nbrs, 0);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &best_cand_nbrs);
+  igraph_vector_int_init(&best_fini_cand_nbrs, 0);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &best_fini_cand_nbrs);
+
+  /* Find the vertex with the highest degree */
+  best_cand = 0; best_cand_degree = (igraph_integer_t) igraph_vector_int_size(igraph_adjlist_get(&adj_list, 0));
+  for (i = 1; i < no_of_nodes; i++) {
+    j = igraph_vector_int_size(igraph_adjlist_get(&adj_list, i));
+    if (j > best_cand_degree) {
+      best_cand = (igraph_integer_t) i;
+      best_cand_degree = (igraph_integer_t) j;
+    }
+  }
+
+  /* Create the initial stack frame */
+  IGRAPH_CHECK(igraph_vector_int_init_seq(&frame.cand, 0, no_of_nodes-1));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &frame.cand);
+  IGRAPH_CHECK(igraph_vector_int_init(&frame.fini, 0));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &frame.fini);
+  IGRAPH_CHECK(igraph_vector_int_init(&frame.cand_filtered, 0));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &frame.cand_filtered);
+  IGRAPH_CHECK(igraph_vector_int_difference_sorted(&frame.cand,
+        igraph_adjlist_get(&adj_list, best_cand), &frame.cand_filtered));
+  IGRAPH_FINALLY_CLEAN(3);
+  IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_frame_destroy, &frame);
+
+  /* TODO: frame.cand and frame.fini should be a set instead of a vector */
+
+  /* Main loop starts here */
+  nodes_to_check = (igraph_integer_t) igraph_vector_int_size(&frame.cand_filtered); nodes_done = 0;
+  while (!igraph_vector_int_empty(&frame.cand_filtered) || !igraph_stack_ptr_empty(&stack)) {
+    if (igraph_vector_int_empty(&frame.cand_filtered)) {
+      /* No candidates left to check in this stack frame, pop out the previous stack frame */
+      igraph_i_maximal_cliques_stack_frame *newframe = igraph_stack_ptr_pop(&stack);
+      igraph_i_maximal_cliques_stack_frame_destroy(&frame);
+      frame = *newframe;
+      free(newframe);
+
+      if (igraph_stack_ptr_size(&stack) == 1) {
+        /* We will be using the next candidate node in the next iteration, so we can increase
+         * nodes_done by 1 */
+        nodes_done++;
+      }
+
+      /* For efficiency reasons, we only check for interruption and show progress here */
+      IGRAPH_PROGRESS("Maximal cliques: ", 100.0 * nodes_done / nodes_to_check, NULL);
+      IGRAPH_ALLOW_INTERRUPTION();
+
+      igraph_vector_pop_back(&clique);
+      continue;
+    }
+
+    /* Try the next node in the clique */
+    i = (long int) igraph_vector_int_pop_back(&frame.cand_filtered);
+    IGRAPH_CHECK(igraph_vector_push_back(&clique, i));
+
+    /* Remove the node from the candidate list */
+    assret=igraph_vector_int_binsearch(&frame.cand, i, &j); assert(assret);
+    igraph_vector_int_remove(&frame.cand, j);
+
+    /* Add the node to the finished list */
+    assret = !igraph_vector_int_binsearch(&frame.fini, i, &j); assert(assret);
+    IGRAPH_CHECK(igraph_vector_int_insert(&frame.fini, j, i));
+
+    /* Create new_cand and new_fini */
+    IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&frame.cand, igraph_adjlist_get(&adj_list, i), &new_cand));
+    IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&frame.fini, igraph_adjlist_get(&adj_list, i), &new_fini));
+
+    /* Do we have anything more to search? */
+    if (igraph_vector_int_empty(&new_cand)) {
+      if (igraph_vector_int_empty(&new_fini)) {
+        /* We have a maximal clique here */
+        IGRAPH_CHECK(func(&clique, data, &cont));
+        if (!cont) {
+          /* The callback function requested to stop the search */
+          break;
+        }
+      }
+      igraph_vector_pop_back(&clique);
+      continue;
+    }
+    if (igraph_vector_int_empty(&new_fini) && 
+	igraph_vector_int_size(&new_cand) == 1) {
+      /* Shortcut: only one node left */
+      IGRAPH_CHECK(igraph_vector_push_back(&clique, VECTOR(new_cand)[0]));
+      IGRAPH_CHECK(func(&clique, data, &cont));
+      if (!cont) {
+        /* The callback function requested to stop the search */
+        break;
+      }
+      igraph_vector_pop_back(&clique);
+      igraph_vector_pop_back(&clique);
+      continue;
+    }
+
+    /* Find the next best candidate node in new_fini */
+    l = igraph_vector_int_size(&new_cand);
+    best_cand_degree = -1;
+    j = igraph_vector_int_size(&new_fini);
+    for (i = 0; i < j; i++) {
+      k = (long int)VECTOR(new_fini)[i];
+      IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
+      if (igraph_vector_int_size(&cn) > best_cand_degree) {
+        best_cand_degree = (igraph_integer_t) igraph_vector_int_size(&cn);
+        IGRAPH_CHECK(igraph_vector_int_update(&best_fini_cand_nbrs, &cn));
+        if (best_cand_degree == l) {
+          /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */
+          break;
+        }
+      }
+    }
+    /* Shortcut here: we don't have to examine new_cand */
+    if (best_cand_degree == l) {
+      igraph_vector_pop_back(&clique);
+      continue;
+    }
+    /* Still finding best candidate node */
+    best_fini_cand_degree = best_cand_degree;
+    best_cand_degree = -1;
+    j = igraph_vector_int_size(&new_cand);
+    l = l - 1;
+    for (i = 0; i < j; i++) {
+      k = (long int)VECTOR(new_cand)[i];
+      IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
+      if (igraph_vector_int_size(&cn) > best_cand_degree) {
+        best_cand_degree = (igraph_integer_t) igraph_vector_int_size(&cn);
+        IGRAPH_CHECK(igraph_vector_int_update(&best_cand_nbrs, &cn));
+        if (best_cand_degree == l) {
+          /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */
+          break;
+        }
+      }
+    }
+
+    /* Create a new stack frame in case we back out later */
+    new_frame_ptr = igraph_Calloc(1, igraph_i_maximal_cliques_stack_frame);
+    if (new_frame_ptr == 0) {
+      IGRAPH_ERROR("cannot allocate new stack frame", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, new_frame_ptr);
+    *new_frame_ptr = frame;
+    memset(&frame, 0, sizeof(frame));
+    IGRAPH_CHECK(igraph_stack_ptr_push(&stack, new_frame_ptr));
+    IGRAPH_FINALLY_CLEAN(1);  /* ownership of new_frame_ptr taken by the stack */
+    /* Ownership of the current frame and its vectors (frame.cand, frame.done, frame.cand_filtered)
+     * is taken by the stack from now on. Vectors in frame must be re-initialized with new_cand,
+     * new_fini and stuff. The old frame.cand and frame.fini won't be leaked because they are
+     * managed by the stack now. */
+    frame.cand = new_cand;
+    frame.fini = new_fini;
+    IGRAPH_CHECK(igraph_vector_int_init(&new_cand, 0));
+    IGRAPH_CHECK(igraph_vector_int_init(&new_fini, 0));
+    IGRAPH_CHECK(igraph_vector_int_init(&frame.cand_filtered, 0));
+
+    /* Adjust frame.cand_filtered */
+    if (best_cand_degree < best_fini_cand_degree) {
+      IGRAPH_CHECK(igraph_vector_int_difference_sorted(&frame.cand, &best_fini_cand_nbrs, &frame.cand_filtered));
+    } else {
+      IGRAPH_CHECK(igraph_vector_int_difference_sorted(&frame.cand, &best_cand_nbrs, &frame.cand_filtered));
+    }
+  }
+
+  IGRAPH_PROGRESS("Maximal cliques: ", 100.0, NULL);
+
+  igraph_adjlist_destroy(&adj_list);
+  igraph_vector_destroy(&clique);
+  igraph_vector_int_destroy(&new_cand);
+  igraph_vector_int_destroy(&new_fini);
+  igraph_vector_int_destroy(&cn);
+  igraph_vector_int_destroy(&best_cand_nbrs);
+  igraph_vector_int_destroy(&best_fini_cand_nbrs);
+  igraph_i_maximal_cliques_stack_frame_destroy(&frame);
+  igraph_i_maximal_cliques_stack_destroy(&stack);
+  IGRAPH_FINALLY_CLEAN(9);
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
+                                        igraph_vector_ptr_t *res,
+                                        igraph_integer_t *clique_number,
+                                        igraph_bool_t keep_only_largest,
+                                        igraph_bool_t complementer) {
+  igraph_i_max_ind_vsets_data_t clqdata;
+  igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph), i;
+
+  if (igraph_is_directed(graph))
+    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");
+
+  clqdata.matrix_size=no_of_nodes;
+  clqdata.keep_only_largest=keep_only_largest;
+
+  if (complementer)
+    IGRAPH_CHECK(igraph_adjlist_init_complementer(graph, &clqdata.adj_list, IGRAPH_ALL, 0));
+  else
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &clqdata.adj_list, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list);
+
+  clqdata.IS = igraph_Calloc(no_of_nodes, igraph_integer_t);
+  if (clqdata.IS == 0)
+    IGRAPH_ERROR("igraph_i_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_free, clqdata.IS);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&clqdata.deg, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++)
+    VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i));
+
+  clqdata.buckets = igraph_Calloc(no_of_nodes+1, igraph_set_t);
+  if (clqdata.buckets == 0)
+    IGRAPH_ERROR("igraph_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_i_free_set_array, clqdata.buckets);
+
+  for (i=0; i<no_of_nodes; i++)
+    IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0));
+
+  if (res) igraph_vector_ptr_clear(res);
+  
+  /* Do the show */
+  clqdata.largest_set_size=0;
+  IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph, res, &clqdata, 0));
+
+  /* Cleanup */
+  for (i=0; i<no_of_nodes; i++) igraph_set_destroy(&clqdata.buckets[i]);
+  igraph_adjlist_destroy(&clqdata.adj_list);
+  igraph_vector_destroy(&clqdata.deg);
+  igraph_free(clqdata.IS);
+  igraph_free(clqdata.buckets);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  if (clique_number) *clique_number = clqdata.largest_set_size;
+  return 0;
+}
diff --git a/src/clustertool.cpp b/src/clustertool.cpp
new file mode 100644
index 0000000..c59678e
--- /dev/null
+++ b/src/clustertool.cpp
@@ -0,0 +1,657 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by Joerg Reichardt 
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          main.cpp  -  description
+                             -------------------
+    begin                : Tue Jul 13 11:26:47 CEST 2004
+    copyright            : (C) 2004 by 
+    email                : 
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+
+#include "NetDataTypes.h"
+#include "NetRoutines.h"
+#include "pottsmodel_2.h"
+
+#include "igraph_community.h"
+#include "igraph_error.h"
+#include "igraph_random.h"
+#include "igraph_math.h"
+#include "igraph_interface.h"
+#include "igraph_components.h"
+#include "igraph_interrupt_internal.h"
+
+int igraph_i_community_spinglass_orig(const igraph_t *graph,
+				      const igraph_vector_t *weights,
+				      igraph_real_t *modularity,
+				      igraph_real_t *temperature,
+				      igraph_vector_t *membership, 
+				      igraph_vector_t *csize, 
+				      igraph_integer_t spins,
+				      igraph_bool_t parupdate,
+				      igraph_real_t starttemp,
+				      igraph_real_t stoptemp,
+				      igraph_real_t coolfact,
+				      igraph_spincomm_update_t update_rule,
+				      igraph_real_t gamma);
+
+int igraph_i_community_spinglass_negative(const igraph_t *graph,
+					  const igraph_vector_t *weights,
+					  igraph_real_t *modularity,
+					  igraph_real_t *temperature,
+					  igraph_vector_t *membership, 
+					  igraph_vector_t *csize,
+					  igraph_integer_t spins,
+					  igraph_bool_t parupdate,
+					  igraph_real_t starttemp,
+					  igraph_real_t stoptemp,
+					  igraph_real_t coolfact,
+					  igraph_spincomm_update_t update_rule,
+					  igraph_real_t gamma,
+/* 					  igraph_matrix_t *adhesion, */
+/* 					  igraph_matrix_t *normalised_adhesion, */
+/* 					  igraph_real_t *polarization, */
+					  igraph_real_t gamma_minus);
+
+/**
+ * \function igraph_community_spinglass
+ * \brief Community detection based on statistical mechanics
+ * 
+ * This function implements the community structure detection
+ * algorithm proposed by Joerg Reichardt and Stefan Bornholdt. 
+ * The algorithm is described in their paper: Statistical Mechanics of 
+ * Community Detection, http://arxiv.org/abs/cond-mat/0603718 .
+ * 
+ * </para><para> From version 0.6 igraph also supports an extension to
+ * the algorithm that allows negative edge weights. This is described
+ * in  V.A. Traag and Jeroen Bruggeman: Community detection in networks 
+ * with positive and negative links, http://arxiv.org/abs/0811.2329 .
+ * \param graph The input graph, it may be directed but the direction
+ *     of the edge is not used in the algorithm.
+ * \param weights The vector giving the edge weights, it may be \c NULL, 
+ *     in which case all edges are weighted equally. Edge weights
+ *     should be positive, altough this is not tested.
+ * \param modularity Pointer to a real number, if not \c NULL then the
+ *     modularity score of the solution will be stored here. This is the 
+ *     gereralized modularity that simplifies to the one defined in
+ *     M. E. J. Newman and M. Girvan, Phys. Rev. E 69, 026113 (2004), 
+ *     if the gamma parameter is one.
+ * \param temperature Pointer to a real number, if not \c NULL then
+ *     the temperature at the end of the algorithm will be stored
+ *     here.
+ * \param membership Pointer to an initialized vector or \c NULL. If
+ *     not \c NULL then the result of the clustering will be stored
+ *     here, for each vertex the number of its cluster is given, the 
+ *     first cluster is numbered zero. The vector will be resized as
+ *     needed. 
+ * \param csize Pointer to an initialized vector or \c NULL. If not \c
+ *     NULL then the sizes of the clusters will stored here in cluster
+ *     number order. The vector will be resized as needed.
+ * \param spins Integer giving the number of spins, ie. the maximum
+ *     number of clusters. Usually it is not a program to give a high
+ *     number here, the default was 25 in the original code. Even if
+ *     the number of spins is high the number of clusters in the
+ *     result might small.
+ * \param parupdate A logical constant, whether to update all spins in
+ *     parallel. The default for this argument was \c FALSE (ie. 0) in
+ *     the original code. It is not implemented in the \c
+ *     IGRAPH_SPINCOMM_INP_NEG implementation.
+ * \param starttemp Real number, the temperature at the start. The
+ *     value of this argument was 1.0 in the original code.
+ * \param stoptemp Real number, the algorithm stops at this
+ *     temperature. The default was 0.01 in the original code.
+ * \param coolfact Real number, the coolinf factor for the simulated
+ *     annealing. The default was 0.99 in the original code.
+ * \param update_rule The type of the update rule. Possible values: \c
+ *     IGRAPH_SPINCOMM_UPDATE_SIMPLE and \c
+ *     IGRAPH_SPINCOMM_UPDATE_CONFIG. Basically this parameter defined
+ *     the null model based on which the actual clustering is done. If
+ *     this is \c IGRAPH_SPINCOMM_UPDATE_SIMPLE then the random graph
+ *     (ie. G(n,p)), if it is \c IGRAPH_SPINCOMM_UPDATE then the
+ *     configuration model is used. The configuration means that the
+ *     baseline for the clustering is a random graph with the same
+ *     degree distribution as the input graph.
+ * \param gamma Real number. The gamma parameter of the
+ *     algorithm. This defined the weight of the missing and existing
+ *     links in the quality function for the clustering. The default
+ *     value in the original code was 1.0, which is equal weight to 
+ *     missing and existing edges. Smaller values make the existing
+ *     links contibute more to the energy function which is minimized
+ *     in the algorithm. Bigger values make the missing links more
+ *     important. (If my understanding is correct.)
+ * \param implementation Constant, chooses between the two
+ *     implementations of the spin-glass algorithm that are included
+ *     in igraph. \c IGRAPH_SPINCOMM_IMP_ORIG selects the original
+ *     implementation, this is faster, \c IGRAPH_SPINCOMM_INP_NEG selects
+ *     a new implementation by Vincent Traag that allows negative edge
+ *     weights.
+ * \param gamma_minus Real number. Parameter for the \c
+ *     IGRAPH_SPINCOMM_IMP_NEG implementation. This
+ *     specifies the balance between the importance of present and
+ *     non-present negative weighted edges in a community. Smaller values of 
+ *     \p gamma_minus lead 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. 
+ * \return Error code.
+ * 
+ * \sa igraph_community_spinglass_single() for calculating the community
+ * of a single vertex.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/spinglass.c
+ */
+
+int igraph_community_spinglass(const igraph_t *graph,
+			       const igraph_vector_t *weights,
+			       igraph_real_t *modularity,
+			       igraph_real_t *temperature,
+			       igraph_vector_t *membership, 
+			       igraph_vector_t *csize, 
+			       igraph_integer_t spins,
+			       igraph_bool_t parupdate,
+			       igraph_real_t starttemp,
+			       igraph_real_t stoptemp,
+			       igraph_real_t coolfact,
+			       igraph_spincomm_update_t update_rule,
+			       igraph_real_t gamma,
+			       /* the rest is for the NegSpin implementation */
+			       igraph_spinglass_implementation_t implementation,
+/* 			       igraph_matrix_t *adhesion, */
+/* 			       igraph_matrix_t *normalised_adhesion, */
+/* 			       igraph_real_t *polarization, */
+			       igraph_real_t gamma_minus) {
+  
+  switch (implementation) {
+  case IGRAPH_SPINCOMM_IMP_ORIG:
+    return igraph_i_community_spinglass_orig(graph, weights, modularity, 
+					     temperature, membership, csize, 
+					     spins, parupdate, starttemp, 
+					     stoptemp, coolfact, update_rule, 
+					     gamma);
+    break;
+  case IGRAPH_SPINCOMM_IMP_NEG:
+    return igraph_i_community_spinglass_negative(graph, weights, modularity, 
+						 temperature, membership, csize, 
+						 spins, parupdate, starttemp, 
+						 stoptemp, coolfact, 
+						 update_rule, gamma, 
+/* 						 adhesion, normalised_adhesion, */
+/* 						 polarization, */
+						 gamma_minus);
+    break;
+  default:
+    IGRAPH_ERROR("Unknown `implementation' in spinglass community finding",
+		 IGRAPH_EINVAL);
+  }
+  
+  return 0;
+}
+
+int igraph_i_community_spinglass_orig(const igraph_t *graph,
+				      const igraph_vector_t *weights,
+				      igraph_real_t *modularity,
+				      igraph_real_t *temperature,
+				      igraph_vector_t *membership, 
+				      igraph_vector_t *csize, 
+				      igraph_integer_t spins,
+				      igraph_bool_t parupdate,
+				      igraph_real_t starttemp,
+				      igraph_real_t stoptemp,
+				      igraph_real_t coolfact,
+				      igraph_spincomm_update_t update_rule,
+				      igraph_real_t gamma) {
+
+  unsigned long changes, runs;
+  igraph_bool_t use_weights=0;
+  bool zeroT;
+  double kT, acc, prob;
+  ClusterList<NNode*> *cl_cur;
+  network *net;
+  PottsModel *pm;
+
+  /* Check arguments */
+
+  if (spins < 2 || spins > 500) {
+    IGRAPH_ERROR("Invalid number of spins", IGRAPH_EINVAL);
+  }
+  if (update_rule != IGRAPH_SPINCOMM_UPDATE_SIMPLE &&
+      update_rule != IGRAPH_SPINCOMM_UPDATE_CONFIG) {
+    IGRAPH_ERROR("Invalid update rule", IGRAPH_EINVAL);
+  }
+  if (weights) {
+    if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+      IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+    }
+    use_weights=1;
+  }
+  if (coolfact < 0 || coolfact>=1.0) {
+    IGRAPH_ERROR("Invalid cooling factor", IGRAPH_EINVAL);
+  }
+  if (gamma < 0.0) {
+    IGRAPH_ERROR("Invalid gamme value", IGRAPH_EINVAL);
+  }
+  if (starttemp/stoptemp<1.0) {
+    IGRAPH_ERROR("starttemp should be larger in absolute value than stoptemp",
+		 IGRAPH_EINVAL);
+  }
+  
+  /* Check whether we have a single component */
+  igraph_bool_t conn;
+  IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
+  if (!conn) {
+    IGRAPH_ERROR("Cannot work with unconnected graph", IGRAPH_EINVAL);
+  }
+
+  net = new network;
+  net->node_list   =new DL_Indexed_List<NNode*>();
+  net->link_list   =new DL_Indexed_List<NLink*>();
+  net->cluster_list=new DL_Indexed_List<ClusterList<NNode*>*>();
+
+  /* Transform the igraph_t */
+  IGRAPH_CHECK(igraph_i_read_network(graph, weights,
+				     net, use_weights, 0));
+
+  prob=2.0*net->sum_weights/double(net->node_list->Size())
+    /double(net->node_list->Size()-1);
+
+  pm=new PottsModel(net,(unsigned int)spins,update_rule);
+
+  /* initialize the random number generator */
+  RNG_BEGIN();
+  
+  if ((stoptemp==0.0) && (starttemp==0.0)) zeroT=true; else zeroT=false;
+  if (!zeroT) kT=pm->FindStartTemp(gamma, prob, starttemp); else kT=stoptemp;
+  /* assign random initial configuration */
+  pm->assign_initial_conf(-1);
+  runs=0;
+  changes=1;
+
+  while (changes>0 && (kT/stoptemp>1.0 || (zeroT && runs<150))) {
+
+    IGRAPH_ALLOW_INTERRUPTION(); /* This is not clean.... */
+    
+    runs++;
+    if (!zeroT) {
+      kT*=coolfact;
+      if (parupdate) { 
+	changes=pm->HeatBathParallelLookup(gamma, prob, kT, 50);
+      } else {
+	acc=pm->HeatBathLookup(gamma, prob, kT, 50);
+	if (acc<(1.0-1.0/double(spins))*0.01) {
+	  changes=0; 
+	} else { 
+	  changes=1;
+	}
+      }
+    } else {
+      if (parupdate) { 
+	changes=pm->HeatBathParallelLookupZeroTemp(gamma, prob, 50);
+      } else {
+	acc=pm->HeatBathLookupZeroTemp(gamma, prob, 50);
+	/* less than 1 percent acceptance ratio */
+	if (acc<(1.0-1.0/double(spins))*0.01) {
+	  changes=0; 
+	} else { 
+	  changes=1;
+	}
+      }
+    }
+  } /* while loop */
+
+  pm->WriteClusters(modularity, temperature, csize, membership, kT, gamma);
+
+  while (net->link_list->Size()) delete net->link_list->Pop();
+  while (net->node_list->Size()) delete net->node_list->Pop();
+  while (net->cluster_list->Size())
+    {
+      cl_cur=net->cluster_list->Pop();
+      while (cl_cur->Size()) cl_cur->Pop();
+      delete cl_cur;
+    }
+  delete net->link_list;
+  delete net->node_list;
+  delete net->cluster_list;
+  
+  RNG_END();
+  
+  delete net;
+  delete pm;
+
+  return 0;
+}
+
+/**
+ * \function igraph_community_spinglass_single
+ * \brief Community of a single node based on statistical mechanics
+ * 
+ * This function implements the community structure detection
+ * algorithm proposed by Joerg Reichardt and Stefan Bornholdt. It is
+ * described in their paper: Statistical Mechanics of 
+ * Community Detection, http://arxiv.org/abs/cond-mat/0603718 .
+ * 
+ * </para><para>
+ * This function calculates the community of a single vertex without
+ * calculating all the communities in the graph.
+ * 
+ * \param graph The input graph, it may be directed but the direction
+ *    of the edges is not used in the algorithm.
+ * \param weights Pointer to a vector with the weights of the edges.
+ *    Alternatively \c NULL can be supplied to have the same weight
+ *    for every edge.
+ * \param vertex The vertex id of the vertex of which ths community is 
+ *    calculated.
+ * \param community Pointer to an initialized vector, the result, the
+ *    ids of the vertices in the community of the input vertex will be
+ *    stored here. The vector will be resized as needed.
+ * \param cohesion Pointer to a real variable, if not \c NULL the
+ *     cohesion index of the community will be stored here.
+ * \param adhesion Pointer to a real variable, if not \c NULL the
+ *     adhesion index of the community will be stored here.
+ * \param inner_links Pointer to an integer, if not \c NULL the 
+ *     number of edges within the community is stored here.
+ * \param outer_links Pointer to an integer, if not \c NULL the 
+ *     number of edges between the community and the rest of the graph  
+ *     will be stored here.
+ * \param spins The number of spins to use, this can be higher than
+ *    the actual number of clusters in the network, in which case some
+ *    clusters will contain zero vertices.
+ * \param update_rule The type of the update rule. Possible values: \c
+ *     IGRAPH_SPINCOMM_UPDATE_SIMPLE and \c
+ *     IGRAPH_SPINCOMM_UPDATE_CONFIG. Basically this parameter defined
+ *     the null model based on which the actual clustering is done. If
+ *     this is \c IGRAPH_SPINCOMM_UPDATE_SIMPLE then the random graph
+ *     (ie. G(n,p)), if it is \c IGRAPH_SPINCOMM_UPDATE then the
+ *     configuration model is used. The configuration means that the
+ *     baseline for the clustering is a random graph with the same
+ *     degree distribution as the input graph.
+ * \param gamma Real number. The gamma parameter of the
+ *     algorithm. This defined the weight of the missing and existing
+ *     links in the quality function for the clustering. The default
+ *     value in the original code was 1.0, which is equal weight to 
+ *     missing and existing edges. Smaller values make the existing
+ *     links contibute more to the energy function which is minimized
+ *     in the algorithm. Bigger values make the missing links more
+ *     important. (If my understanding is correct.)
+ * \return Error code.
+ * 
+ * \sa igraph_community_spinglass() for the traditional version of the 
+ * algorithm.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_community_spinglass_single(const igraph_t *graph,
+				      const igraph_vector_t *weights,
+				      igraph_integer_t vertex,
+				      igraph_vector_t *community,
+				      igraph_real_t *cohesion,
+				      igraph_real_t *adhesion,
+				      igraph_integer_t *inner_links,
+				      igraph_integer_t *outer_links,
+				      igraph_integer_t spins,
+				      igraph_spincomm_update_t update_rule,
+				      igraph_real_t gamma) {
+
+  igraph_bool_t use_weights=0;
+  double prob;
+  ClusterList<NNode*> *cl_cur;
+  network *net;
+  PottsModel *pm;
+  char startnode[255];
+
+  /* Check arguments */
+
+  if (spins < 2 || spins > 500) {
+    IGRAPH_ERROR("Invalid number of spins", IGRAPH_EINVAL);
+  }
+  if (update_rule != IGRAPH_SPINCOMM_UPDATE_SIMPLE &&
+      update_rule != IGRAPH_SPINCOMM_UPDATE_CONFIG) {
+    IGRAPH_ERROR("Invalid update rule", IGRAPH_EINVAL);
+  }
+  if (weights) {
+    if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+      IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+    }
+    use_weights=1;
+  }
+  if (gamma < 0.0) {
+    IGRAPH_ERROR("Invalid gamme value", IGRAPH_EINVAL);
+  }
+  if (vertex < 0 || vertex > igraph_vcount(graph)) {
+    IGRAPH_ERROR("Invalid vertex id", IGRAPH_EINVAL);
+  }
+  
+  /* Check whether we have a single component */
+  igraph_bool_t conn;
+  IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
+  if (!conn) {
+    IGRAPH_ERROR("Cannot work with unconnected graph", IGRAPH_EINVAL);
+  }
+
+  net = new network;
+  net->node_list   =new DL_Indexed_List<NNode*>();
+  net->link_list   =new DL_Indexed_List<NLink*>();
+  net->cluster_list=new DL_Indexed_List<ClusterList<NNode*>*>();
+
+  /* Transform the igraph_t */
+  IGRAPH_CHECK(igraph_i_read_network(graph, weights,
+				     net, use_weights, 0));
+
+  prob=2.0*net->sum_weights/double(net->node_list->Size())
+    /double(net->node_list->Size()-1);
+
+  pm=new PottsModel(net,(unsigned int)spins,update_rule);
+
+  /* initialize the random number generator */
+  RNG_BEGIN();
+
+  /* to be exected, if we want to find the community around a particular node*/
+  /* the initial conf is needed, because otherwise, 
+     the degree of the nodes is not in the weight property, stupid!!! */
+  pm->assign_initial_conf(-1);
+  snprintf(startnode, 255, "%li", (long int)vertex+1);
+  pm->FindCommunityFromStart(gamma, prob, startnode, community,
+			     cohesion, adhesion, inner_links, outer_links);
+  
+  while (net->link_list->Size()) delete net->link_list->Pop();
+  while (net->node_list->Size()) delete net->node_list->Pop();
+  while (net->cluster_list->Size())
+    {
+      cl_cur=net->cluster_list->Pop();
+      while (cl_cur->Size()) cl_cur->Pop();
+      delete cl_cur;
+    }
+  delete net->link_list;
+  delete net->node_list;
+  delete net->cluster_list;
+  
+  RNG_END();
+
+  delete net;
+  delete pm;
+
+  return 0;
+}
+
+int igraph_i_community_spinglass_negative(const igraph_t *graph,
+					  const igraph_vector_t *weights,
+					  igraph_real_t *modularity,
+					  igraph_real_t *temperature,
+					  igraph_vector_t *membership, 
+					  igraph_vector_t *csize,
+					  igraph_integer_t spins,
+					  igraph_bool_t parupdate,
+					  igraph_real_t starttemp,
+					  igraph_real_t stoptemp,
+					  igraph_real_t coolfact,
+					  igraph_spincomm_update_t update_rule,
+					  igraph_real_t gamma,
+/* 					  igraph_matrix_t *adhesion, */
+/* 					  igraph_matrix_t *normalised_adhesion, */
+/* 					  igraph_real_t *polarization, */
+					  igraph_real_t gamma_minus) {
+
+  unsigned long changes, runs;
+  igraph_bool_t use_weights=0;
+  bool zeroT;
+  double kT, acc;
+  ClusterList<NNode*> *cl_cur;
+  network *net;
+  PottsModelN *pm;
+  igraph_real_t d_n;
+  igraph_real_t d_p;
+
+  /* Check arguments */
+
+  if (parupdate) {
+    IGRAPH_ERROR("Parallel spin update not implemented with "
+		 "negative gamma", IGRAPH_UNIMPLEMENTED);
+  }
+
+  if (spins < 2 || spins > 500) {
+    IGRAPH_ERROR("Invalid number of spins", IGRAPH_EINVAL);
+  }
+  if (update_rule != IGRAPH_SPINCOMM_UPDATE_SIMPLE &&
+      update_rule != IGRAPH_SPINCOMM_UPDATE_CONFIG) {
+    IGRAPH_ERROR("Invalid update rule", IGRAPH_EINVAL);
+  }
+  if (weights) {
+    if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+      IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+    }
+    use_weights=1;
+  }
+  if (coolfact < 0 || coolfact>=1.0) {
+    IGRAPH_ERROR("Invalid cooling factor", IGRAPH_EINVAL);
+  }
+  if (gamma < 0.0) {
+    IGRAPH_ERROR("Invalid gamma value", IGRAPH_EINVAL);
+  }
+  if (starttemp/stoptemp<1.0) {
+    IGRAPH_ERROR("starttemp should be larger in absolute value than stoptemp",
+		 IGRAPH_EINVAL);
+  }
+  
+  /* Check whether we have a single component */
+  igraph_bool_t conn;
+  IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
+  if (!conn) {
+    IGRAPH_ERROR("Cannot work with unconnected graph", IGRAPH_EINVAL);
+  }
+  
+  igraph_vector_minmax(weights, &d_n, &d_p);
+  if (d_n > 0) { d_n=0; }
+  if (d_p < 0) { d_p=0; }
+  d_n = -d_n;
+
+  net = new network;
+  net->node_list   =new DL_Indexed_List<NNode*>();
+  net->link_list   =new DL_Indexed_List<NLink*>();
+  net->cluster_list=new DL_Indexed_List<ClusterList<NNode*>*>();
+
+  /* Transform the igraph_t */
+  IGRAPH_CHECK(igraph_i_read_network(graph, weights,
+				     net, use_weights, 0));
+	
+  bool directed = igraph_is_directed(graph);
+  
+  pm=new PottsModelN(net,(unsigned int)spins, directed);
+
+  /* initialize the random number generator */
+  RNG_BEGIN();
+  
+  if ((stoptemp==0.0) && (starttemp==0.0)) zeroT=true; else zeroT=false;
+
+  //Begin at a high enough temperature
+  kT=pm->FindStartTemp(gamma, gamma_minus, starttemp);
+
+  /* assign random initial configuration */
+  pm->assign_initial_conf(true);
+
+  runs=0;
+  changes=1;
+  acc = 0;
+	while (changes>0 && (kT/stoptemp>1.0 || (zeroT && runs<150))) 
+	{
+		
+		IGRAPH_ALLOW_INTERRUPTION(); /* This is not clean.... */
+		
+		runs++;
+		kT = kT*coolfact; 
+		acc=pm->HeatBathLookup(gamma, gamma_minus, kT, 50);
+		if (acc<(1.0-1.0/double(spins))*0.001)
+			changes=0; 
+		else 
+			changes=1;
+		
+	} /* while loop */
+
+  /* These are needed, otherwise 'modularity' is not calculated */
+  igraph_matrix_t adhesion, normalized_adhesion;
+  igraph_real_t polarization;
+  IGRAPH_MATRIX_INIT_FINALLY(&adhesion, 0, 0);
+  IGRAPH_MATRIX_INIT_FINALLY(&normalized_adhesion, 0, 0);
+  pm->WriteClusters(modularity, temperature, csize, membership, 
+		    &adhesion, &normalized_adhesion, &polarization, 
+		    kT, d_p, d_n, gamma, gamma_minus);
+  igraph_matrix_destroy(&normalized_adhesion);
+  igraph_matrix_destroy(&adhesion);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  while (net->link_list->Size()) delete net->link_list->Pop();
+  while (net->node_list->Size()) delete net->node_list->Pop();
+  while (net->cluster_list->Size())
+    {
+      cl_cur=net->cluster_list->Pop();
+      while (cl_cur->Size()) cl_cur->Pop();
+      delete cl_cur;
+    }
+  
+  RNG_END();
+
+  return 0;
+}
diff --git a/src/cocitation.c b/src/cocitation.c
new file mode 100644
index 0000000..18d1522
--- /dev/null
+++ b/src/cocitation.c
@@ -0,0 +1,764 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include "igraph_cocitation.h"
+#include "igraph_memory.h"
+#include "igraph_adjlist.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_interface.h"
+#include "config.h"
+#include <math.h>
+
+int igraph_cocitation_real(const igraph_t *graph, igraph_matrix_t *res, 
+                           igraph_vs_t vids, igraph_neimode_t mode,
+                           igraph_vector_t *weights);
+
+/**
+ * \ingroup structural
+ * \function igraph_cocitation
+ * \brief Cocitation coupling.
+ * 
+ * </para><para>
+ * Two vertices are cocited if there is another vertex citing both of
+ * them. \ref igraph_cocitation() simply counts how many times two vertices are
+ * cocited.
+ * The cocitation score for each given vertex and all other vertices
+ * in the graph will be calculated.
+ * \param graph The graph object to analyze.
+ * \param res Pointer to a matrix, the result of the calculation will
+ *        be stored here. The number of its rows is the same as the
+ *        number of vertex ids in \p vids, the number of
+ *        columns is the number of vertices in the graph.
+ * \param vids The vertex ids of the vertices for which the
+ *        calculation will be done.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ * 
+ * Time complexity: O(|V|d^2), |V| is
+ * the number of vertices in the graph,
+ * d is the (maximum) degree of 
+ * the vertices in the graph.
+ *
+ * \sa \ref igraph_bibcoupling()
+ * 
+ * \example examples/simple/igraph_cocitation.c
+ */
+
+int igraph_cocitation(const igraph_t *graph, igraph_matrix_t *res, 
+                      const igraph_vs_t vids) {
+  return igraph_cocitation_real(graph, res, vids, IGRAPH_OUT, 0);
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_bibcoupling
+ * \brief Bibliographic coupling.
+ * 
+ * </para><para>
+ * The bibliographic coupling of two vertices is the number
+ * of other vertices they both cite, \ref igraph_bibcoupling() calculates
+ * this.
+ * The bibliographic coupling  score for each given vertex and all
+ * other vertices in the graph will be calculated.
+ * \param graph The graph object to analyze.
+ * \param res Pointer to a matrix, the result of the calculation will
+ *        be stored here. The number of its rows is the same as the
+ *        number of vertex ids in \p vids, the number of
+ *        columns is the number of vertices in the graph.
+ * \param vids The vertex ids of the vertices for which the
+ *        calculation will be done.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ * 
+ * Time complexity: O(|V|d^2),
+ * |V| is the number of vertices in
+ * the graph, d is the (maximum)
+ * degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_cocitation()
+ */
+
+int igraph_bibcoupling(const igraph_t *graph, igraph_matrix_t *res, 
+                       const igraph_vs_t vids) {
+  return igraph_cocitation_real(graph, res, vids, IGRAPH_IN, 0);
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_inverse_log_weighted
+ * \brief Vertex similarity based on the inverse logarithm of vertex degrees. 
+ * 
+ * </para><para>
+ * 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.
+ *
+ * </para><para>
+ * Isolated vertices will have zero similarity to any other vertex.
+ * Self-similarities are not calculated.
+ *
+ * </para><para>
+ * 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.
+ *
+ * \param graph The graph object to analyze.
+ * \param res Pointer to a matrix, the result of the calculation will
+ *        be stored here. The number of its rows is the same as the
+ *        number of vertex ids in \p vids, the number of
+ *        columns is the number of vertices in the graph.
+ * \param vids The vertex ids of the vertices for which the
+ *        calculation will be done.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node. Nodes
+ *          will be weighted according to their in-degree.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node. Nodes
+ *          will be weighted according to their out-degree.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation. Every node is weighted according to its undirected
+ *          degree.
+ *        \endclist
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ * 
+ * Time complexity: O(|V|d^2),
+ * |V| is the number of vertices in
+ * the graph, d is the (maximum)
+ * degree of the vertices in the graph.
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+
+int igraph_similarity_inverse_log_weighted(const igraph_t *graph,
+  igraph_matrix_t *res, const igraph_vs_t vids, igraph_neimode_t mode) {
+  igraph_vector_t weights;
+  igraph_neimode_t mode0;
+  long int i, no_of_nodes;
+
+  switch (mode) {
+    case IGRAPH_OUT: mode0 = IGRAPH_IN; break;
+    case IGRAPH_IN: mode0 = IGRAPH_OUT; break;
+    default: mode0 = IGRAPH_ALL;
+  }
+
+  no_of_nodes = igraph_vcount(graph);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&weights, no_of_nodes);
+  IGRAPH_CHECK(igraph_degree(graph, &weights, igraph_vss_all(), mode0, 1));
+  for (i=0; i < no_of_nodes; i++) {
+    if (VECTOR(weights)[i] > 1)
+      VECTOR(weights)[i] = 1.0 / log(VECTOR(weights)[i]);
+  }
+
+  IGRAPH_CHECK(igraph_cocitation_real(graph, res, vids, mode0, &weights));
+  igraph_vector_destroy(&weights);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_cocitation_real(const igraph_t *graph, igraph_matrix_t *res, 
+                           igraph_vs_t vids,
+                           igraph_neimode_t mode,
+                           igraph_vector_t *weights) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_vids;
+  long int from, i, j, k, l, u, v;
+  igraph_vector_t neis=IGRAPH_VECTOR_NULL;
+  igraph_vector_t vid_reverse_index;
+  igraph_vit_t vit;
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  no_of_vids = IGRAPH_VIT_SIZE(vit);
+
+  /* Create a mapping from vertex IDs to the row of the matrix where
+   * the result for this vertex will appear */
+  IGRAPH_VECTOR_INIT_FINALLY(&vid_reverse_index, no_of_nodes);
+  igraph_vector_fill(&vid_reverse_index, -1);
+  for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    v = IGRAPH_VIT_GET(vit);
+    if (v < 0 || v >= no_of_nodes)
+      IGRAPH_ERROR("invalid vertex ID in vertex selector", IGRAPH_EINVAL);
+    VECTOR(vid_reverse_index)[v] = i;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_vids, no_of_nodes));
+  igraph_matrix_null(res);
+
+  /* The result */
+  
+  for (from=0; from<no_of_nodes; from++) {
+    igraph_real_t weight = 1;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, 
+				  (igraph_integer_t) from, mode));
+    if (weights)
+      weight = VECTOR(*weights)[from];
+
+    for (i=0; i < igraph_vector_size(&neis)-1; i++) {
+      u = (long int) VECTOR(neis)[i];
+      k = (long int) VECTOR(vid_reverse_index)[u];
+      for (j=i+1; j<igraph_vector_size(&neis); j++) {
+        v = (long int) VECTOR(neis)[j];
+        l = (long int) VECTOR(vid_reverse_index)[v];
+        if (k != -1)
+          MATRIX(*res, k, v) += weight;
+        if (l != -1)
+          MATRIX(*res, l, u) += weight;
+      }
+    }
+  }
+
+  /* Clean up */
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&vid_reverse_index);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+int igraph_i_neisets_intersect(const igraph_vector_t *v1,
+			       const igraph_vector_t *v2, long int *len_union,
+			       long int *len_intersection);
+
+int igraph_i_neisets_intersect(const igraph_vector_t *v1,
+  const igraph_vector_t *v2, long int *len_union,
+  long int *len_intersection) {
+  /* ASSERT: v1 and v2 are sorted */
+  long int i, j, i0, jj0;
+  i0 = igraph_vector_size(v1); jj0 = igraph_vector_size(v2);
+  *len_union = i0+jj0; *len_intersection = 0;
+  i = 0; j = 0;
+  while (i < i0 && j < jj0) {
+    if (VECTOR(*v1)[i] == VECTOR(*v2)[j]) {
+      (*len_intersection)++; (*len_union)--;
+      i++; j++;
+    } else if (VECTOR(*v1)[i] < VECTOR(*v2)[j]) i++;
+    else j++;
+  }
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_jaccard
+ * \brief Jaccard similarity coefficient for the given vertices.
+ *
+ * </para><para>
+ * 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. This function calculates
+ * the pairwise Jaccard similarities for some (or all) of the vertices.
+ *
+ * \param graph The graph object to analyze
+ * \param res Pointer to a matrix, the result of the calculation will
+ *        be stored here. The number of its rows and columns is the same
+ *        as the number of vertex ids in \p vids.
+ * \param vids The vertex ids of the vertices for which the
+ *        calculation will be done.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation.
+ *        \endclist
+ * \param loops Whether to include the vertices themselves in the neighbor
+ *        sets.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(|V|^2 d),
+ * |V| is the number of vertices in the vertex iterator given, d is the
+ * (maximum) degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_similarity_dice(), a measure very similar to the Jaccard
+ *   coefficient
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+int igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t *res,
+    const igraph_vs_t vids, igraph_neimode_t mode, igraph_bool_t loops) {
+  igraph_lazy_adjlist_t al;
+  igraph_vit_t vit, vit2;
+  long int i, j, k;
+  long int len_union, len_intersection;
+  igraph_vector_t *v1, *v2;
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit2));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit2);
+
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &al, mode, IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &al);
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, IGRAPH_VIT_SIZE(vit), IGRAPH_VIT_SIZE(vit)));
+
+  if (loops) {
+    for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+      i=IGRAPH_VIT_GET(vit);
+      v1=igraph_lazy_adjlist_get(&al, (igraph_integer_t) i);
+      if (!igraph_vector_binsearch(v1, i, &k))
+        igraph_vector_insert(v1, k, i);
+    }
+  }
+
+  for (IGRAPH_VIT_RESET(vit), i=0;
+    !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    MATRIX(*res, i, i) = 1.0;
+    for (IGRAPH_VIT_RESET(vit2), j=0;
+      !IGRAPH_VIT_END(vit2); IGRAPH_VIT_NEXT(vit2), j++) {
+      if (j <= i)
+        continue;
+      v1=igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit));
+      v2=igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit2));
+      igraph_i_neisets_intersect(v1, v2, &len_union, &len_intersection);
+      if (len_union > 0)
+        MATRIX(*res, i, j) = ((igraph_real_t)len_intersection)/len_union;
+      else
+        MATRIX(*res, i, j) = 0.0;
+      MATRIX(*res, j, i) = MATRIX(*res, i, j);
+    }
+  }
+
+  igraph_lazy_adjlist_destroy(&al);
+  igraph_vit_destroy(&vit);
+  igraph_vit_destroy(&vit2);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_jaccard_pairs
+ * \brief Jaccard similarity coefficient for given vertex pairs.
+ *
+ * </para><para>
+ * 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. This function calculates
+ * the pairwise Jaccard similarities for a list of vertex pairs.
+ *
+ * \param graph The graph object to analyze
+ * \param res Pointer to a vector, the result of the calculation will
+ *        be stored here. The number of elements is the same as the number
+ *        of pairs in \p pairs.
+ * \param pairs A vector that contains the pairs for which the similarity
+ *        will be calculated. Each pair is defined by two consecutive elements,
+ *        i.e. the first and second element of the vector specifies the first
+ *        pair, the third and fourth element specifies the second pair and so on.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation.
+ *        \endclist
+ * \param loops Whether to include the vertices themselves in the neighbor
+ *        sets.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(nd), n is the number of pairs in the given vector, d is
+ * the (maximum) degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_similarity_jaccard() to calculate the Jaccard similarity
+ *   between all pairs of a vertex set, or \ref igraph_similarity_dice() and
+ *   \ref igraph_similarity_dice_pairs() for a measure very similar to the
+ *   Jaccard coefficient
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+int igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops) {
+  igraph_lazy_adjlist_t al;
+  long int i, j, k, u, v;
+  long int len_union, len_intersection;
+  igraph_vector_t *v1, *v2;
+  igraph_bool_t *seen;
+
+  k = igraph_vector_size(pairs);
+  if (k % 2 != 0)
+    IGRAPH_ERROR("number of elements in `pairs' must be even", IGRAPH_EINVAL);
+  IGRAPH_CHECK(igraph_vector_resize(res, k/2));
+
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &al, mode, IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &al);
+
+  if (loops) {
+    /* Add the loop edges */
+    i = igraph_vcount(graph);
+    seen = igraph_Calloc(i, igraph_bool_t);
+    if (seen == 0)
+      IGRAPH_ERROR("cannot calculate Jaccard similarity", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(free, seen);
+
+    for (i = 0; i < k; i++) {
+      j = (long int) VECTOR(*pairs)[i];
+      if (seen[j])
+        continue;
+      seen[j] = 1;
+      v1=igraph_lazy_adjlist_get(&al, (igraph_integer_t) j);
+      if (!igraph_vector_binsearch(v1, j, &u))
+        igraph_vector_insert(v1, u, j);
+    }
+
+    free(seen);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  for (i = 0, j = 0; i < k; i += 2, j++) {
+    u = (long int) VECTOR(*pairs)[i];
+    v = (long int) VECTOR(*pairs)[i+1];
+
+    if (u == v) {
+      VECTOR(*res)[j] = 1.0;
+      continue;
+    }
+
+    v1 = igraph_lazy_adjlist_get(&al, (igraph_integer_t) u);
+    v2 = igraph_lazy_adjlist_get(&al, (igraph_integer_t) v);
+    igraph_i_neisets_intersect(v1, v2, &len_union, &len_intersection);
+    if (len_union > 0)
+      VECTOR(*res)[j] = ((igraph_real_t)len_intersection) / len_union;
+    else
+      VECTOR(*res)[j] = 0.0;
+  }
+
+  igraph_lazy_adjlist_destroy(&al);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_jaccard_es
+ * \brief Jaccard similarity coefficient for a given edge selector.
+ *
+ * </para><para>
+ * 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. This function calculates
+ * the pairwise Jaccard similarities for the endpoints of edges in a given edge
+ * selector.
+ *
+ * \param graph The graph object to analyze
+ * \param res Pointer to a vector, the result of the calculation will
+ *        be stored here. The number of elements is the same as the number
+ *        of edges in \p es.
+ * \param es An edge selector that specifies the edges to be included in the
+ *        result.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation.
+ *        \endclist
+ * \param loops Whether to include the vertices themselves in the neighbor
+ *        sets.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(nd), n is the number of edges in the edge selector, d is
+ * the (maximum) degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_similarity_jaccard() and \ref igraph_similarity_jaccard_pairs()
+ *   to calculate the Jaccard similarity between all pairs of a vertex set or
+ *   some selected vertex pairs, or \ref igraph_similarity_dice(),
+ *   \ref igraph_similarity_dice_pairs() and \ref igraph_similarity_dice_es() for a
+ *   measure very similar to the Jaccard coefficient
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+int igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops) {
+  igraph_vector_t v;
+  igraph_eit_t eit;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&v, 0);
+
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+  while (!IGRAPH_EIT_END(eit)) {
+    long int eid = IGRAPH_EIT_GET(eit);
+    igraph_vector_push_back(&v, IGRAPH_FROM(graph, eid));
+    igraph_vector_push_back(&v, IGRAPH_TO(graph, eid));
+    IGRAPH_EIT_NEXT(eit);
+  }
+
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  IGRAPH_CHECK(igraph_similarity_jaccard_pairs(graph, res, &v, mode, loops));
+  igraph_vector_destroy(&v);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_dice
+ * \brief Dice similarity coefficient.
+ *
+ * </para><para>
+ * The Dice similarity coefficient of two vertices is twice the number of common
+ * neighbors divided by the sum of the degrees of the vertices. This function
+ * calculates the pairwise Dice similarities for some (or all) of the vertices.
+ *
+ * \param graph The graph object to analyze
+ * \param res Pointer to a matrix, the result of the calculation will
+ *        be stored here. The number of its rows and columns is the same
+ *        as the number of vertex ids in \p vids.
+ * \param vids The vertex ids of the vertices for which the
+ *        calculation will be done.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation.
+ *        \endclist
+ * \param loops Whether to include the vertices themselves as their own
+ *        neighbors.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(|V|^2 d),
+ * |V| is the number of vertices in the vertex iterator given, d is the
+ * (maximum) degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_similarity_jaccard(), a measure very similar to the Dice
+ *   coefficient
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+int igraph_similarity_dice(const igraph_t *graph, igraph_matrix_t *res,
+    const igraph_vs_t vids, igraph_neimode_t mode, igraph_bool_t loops) {
+  long int i, j, nr, nc;
+
+  IGRAPH_CHECK(igraph_similarity_jaccard(graph, res, vids, mode, loops));
+
+  nr = igraph_matrix_nrow(res);
+  nc = igraph_matrix_ncol(res);
+  for (i = 0; i < nr; i++) {
+    for (j = 0; j < nc; j++) {
+      igraph_real_t x = MATRIX(*res, i, j);
+      MATRIX(*res, i, j) = 2*x / (1+x);
+    }
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_dice_pairs
+ * \brief Dice similarity coefficient for given vertex pairs.
+ *
+ * </para><para>
+ * The Dice similarity coefficient of two vertices is twice the number of common
+ * neighbors divided by the sum of the degrees of the vertices. This function
+ * calculates the pairwise Dice similarities for a list of vertex pairs.
+ *
+ * \param graph The graph object to analyze
+ * \param res Pointer to a vector, the result of the calculation will
+ *        be stored here. The number of elements is the same as the number
+ *        of pairs in \p pairs.
+ * \param pairs A vector that contains the pairs for which the similarity
+ *        will be calculated. Each pair is defined by two consecutive elements,
+ *        i.e. the first and second element of the vector specifies the first
+ *        pair, the third and fourth element specifies the second pair and so on.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation.
+ *        \endclist
+ * \param loops Whether to include the vertices themselves as their own
+ *        neighbors.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(nd), n is the number of pairs in the given vector, d is
+ * the (maximum) degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_similarity_dice() to calculate the Dice similarity
+ *   between all pairs of a vertex set, or \ref igraph_similarity_jaccard(),
+ *   \ref igraph_similarity_jaccard_pairs() and \ref igraph_similarity_jaccard_es()
+ *   for a measure very similar to the Dice coefficient
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+int igraph_similarity_dice_pairs(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops) {
+  long int i, n;
+
+  IGRAPH_CHECK(igraph_similarity_jaccard_pairs(graph, res, pairs, mode, loops));
+  n = igraph_vector_size(res);
+  for (i = 0; i < n; i++) {
+    igraph_real_t x = VECTOR(*res)[i];
+    VECTOR(*res)[i] = 2*x / (1+x);
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_similarity_dice_es
+ * \brief Dice similarity coefficient for a given edge selector.
+ *
+ * </para><para>
+ * The Dice similarity coefficient of two vertices is twice the number of common
+ * neighbors divided by the sum of the degrees of the vertices. This function
+ * calculates the pairwise Dice similarities for the endpoints of edges in a given
+ * edge selector.
+ *
+ * \param graph The graph object to analyze
+ * \param res Pointer to a vector, the result of the calculation will
+ *        be stored here. The number of elements is the same as the number
+ *        of edges in \p es.
+ * \param es An edge selector that specifies the edges to be included in the
+ *        result.
+ * \param mode The type of neighbors to be used for the calculation in
+ *        directed graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          the outgoing edges will be considered for each node.
+ *        \cli IGRAPH_IN
+ *          the incoming edges will be considered for each node.
+ *        \cli IGRAPH_ALL
+ *          the directed graph is considered as an undirected one for the
+ *          computation.
+ *        \endclist
+ * \param loops Whether to include the vertices themselves as their own
+ *        neighbors.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(nd), n is the number of pairs in the given vector, d is
+ * the (maximum) degree of the vertices in the graph.
+ *
+ * \sa \ref igraph_similarity_dice() and \ref igraph_similarity_dice_pairs()
+ *   to calculate the Dice similarity between all pairs of a vertex set or
+ *   some selected vertex pairs, or \ref igraph_similarity_jaccard(),
+ *   \ref igraph_similarity_jaccard_pairs() and \ref igraph_similarity_jaccard_es()
+ *   for a measure very similar to the Dice coefficient
+ * 
+ * \example examples/simple/igraph_similarity.c
+ */
+int igraph_similarity_dice_es(const igraph_t *graph, igraph_vector_t *res,
+	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops) {
+  long int i, n;
+
+  IGRAPH_CHECK(igraph_similarity_jaccard_es(graph, res, es, mode, loops));
+  n = igraph_vector_size(res);
+  for (i = 0; i < n; i++) {
+    igraph_real_t x = VECTOR(*res)[i];
+    VECTOR(*res)[i] = 2*x / (1+x);
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
diff --git a/src/cohesive_blocks.c b/src/cohesive_blocks.c
new file mode 100644
index 0000000..0c0adf8
--- /dev/null
+++ b/src/cohesive_blocks.c
@@ -0,0 +1,567 @@
+/* -*- 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_cohesive_blocks.h"
+#include "igraph_interface.h"
+#include "igraph_memory.h"
+#include "igraph_flow.h"
+#include "igraph_separators.h"
+#include "igraph_structural.h"
+#include "igraph_components.h"
+#include "igraph_dqueue.h"
+#include "igraph_constructors.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_statusbar.h"
+
+void igraph_i_cohesive_blocks_free(igraph_vector_ptr_t *ptr) {
+  long int i, n=igraph_vector_ptr_size(ptr);
+
+  for (i=0; i<n; i++) {
+    igraph_t *g=VECTOR(*ptr)[i];
+    if (g) {
+      igraph_destroy(g);
+      igraph_free(g);
+    }
+  }
+}
+
+void igraph_i_cohesive_blocks_free2(igraph_vector_ptr_t *ptr) {
+  long int i, n=igraph_vector_ptr_size(ptr);
+
+  for (i=0; i<n; i++) {
+    igraph_vector_long_t *v=VECTOR(*ptr)[i];
+    if (v) {
+      igraph_vector_long_destroy(v);
+      igraph_free(v);
+    }
+  }
+}
+
+void igraph_i_cohesive_blocks_free3(igraph_vector_ptr_t *ptr) {
+  long int i, n=igraph_vector_ptr_size(ptr);
+
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*ptr)[i];
+    if (v) {
+      igraph_vector_destroy(v);
+      igraph_free(v);
+    }
+  }
+}
+
+/* This is kind of a BFS to find the components of the graph, after
+ * deleting the vertices marked in 'excluded'.
+ * These vertices are not put in the BFS queue, but they are added to
+ * all neighboring components.
+ */
+
+int igraph_i_cb_components(igraph_t *graph, 
+			   const igraph_vector_bool_t *excluded,
+			   igraph_vector_long_t *components,
+			   long int *no,
+			   /* working area follows */
+			   igraph_vector_long_t *compid, 
+			   igraph_dqueue_t *Q,
+			   igraph_vector_t *neis) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  long int cno=0;
+
+  igraph_vector_long_clear(components);
+  igraph_dqueue_clear(Q);
+  IGRAPH_CHECK(igraph_vector_long_resize(compid, no_of_nodes));
+  igraph_vector_long_null(compid);
+  
+  for (i=0; i<no_of_nodes; i++) {    
+
+    if (VECTOR(*compid)[i])   { continue; }
+    if (VECTOR(*excluded)[i]) { continue; }
+    
+    IGRAPH_CHECK(igraph_dqueue_push(Q, i));
+    IGRAPH_CHECK(igraph_vector_long_push_back(components, i));
+    VECTOR(*compid)[i] = ++cno;
+    
+    while (!igraph_dqueue_empty(Q)) {
+      igraph_integer_t node=(igraph_integer_t) igraph_dqueue_pop(Q);
+      long int j, n;
+      IGRAPH_CHECK(igraph_neighbors(graph, neis, node, IGRAPH_ALL));
+      n=igraph_vector_size(neis);
+      for (j=0; j<n; j++) {
+	long int v=(long int) VECTOR(*neis)[j];
+	if (VECTOR(*excluded)[v]) {
+	  if (VECTOR(*compid)[v] != cno) {
+	    VECTOR(*compid)[v] = cno;
+	    IGRAPH_CHECK(igraph_vector_long_push_back(components, v));
+	  }
+	} else {
+	  if (!VECTOR(*compid)[v]) {
+	    VECTOR(*compid)[v] = cno; /* could be anything positive */
+	    IGRAPH_CHECK(igraph_vector_long_push_back(components, v));
+	    IGRAPH_CHECK(igraph_dqueue_push(Q, v));
+	  }
+	}
+      }
+    } /* while !igraph_dqueue_empty */
+
+    IGRAPH_CHECK(igraph_vector_long_push_back(components, -1));
+    
+  } /* for i<no_of_nodes */
+  
+  *no=cno;
+
+  return 0;
+}
+
+igraph_bool_t igraph_i_cb_isin(const igraph_vector_t *needle, 
+			       const igraph_vector_t *haystack) {
+  long int nlen=igraph_vector_size(needle);
+  long int hlen=igraph_vector_size(haystack);
+  long int np=0, hp=0;
+  
+  if (hlen < nlen) { return 0; }
+  
+  while (np<nlen && hp<hlen) {
+    if (VECTOR(*needle)[np] == VECTOR(*haystack)[hp]) {
+      np++; hp++; 
+    } else if (VECTOR(*needle)[np] < VECTOR(*haystack)[hp]) {
+      return 0;
+    } else {
+      hp++;
+    }
+  }
+  
+  return np==nlen;
+}
+
+/**
+ * \function igraph_cohesive_blocks
+ * Identifies the hierarchical cohesive block structure of a graph
+ * 
+ * Cohesive blocking is a method of determining hierarchical subsets of
+ * graph vertices based on their structural cohesion (or vertex
+ * connectivity). For a given graph G, a subset of its vertices
+ * S is said to be maximally k-cohesive if there is
+ * no superset of S with vertex connectivity greater than or equal to k.
+ * Cohesive blocking is a process through which, given a
+ * k-cohesive set of vertices, maximally l-cohesive subsets are
+ * recursively identified with l>k. Thus a hiearchy of vertex subsets
+ * is found, whith the entire graph G at its root. See the following 
+ * reference for details: J. Moody and D. R. White. Structural
+ * cohesion and embeddedness: A hierarchical concept of social
+ * groups. American Sociological Review, 68(1):103--127, Feb 2003. 
+ *
+ * </para><para>This function implements cohesive blocking and
+ * calculates the complete cohesive block hierarchy of a graph.
+ *
+ * \param graph The input graph. It must be undirected and simple. See 
+ *    \ref igraph_is_simple().
+ * \param blocks If not a null pointer, then it must be an initialized 
+ *    vector of pointers and the cohesive blocks are stored here. 
+ *    Each block is encoded with a numeric vector, that contains the 
+ *    vertex ids of the block.
+ * \param cohesion If not a null pointer, then it must be an initialized 
+ *    vector and the cohesion of the blocks is stored here, in the same 
+ *    order as the blocks in the \p blocks pointer vector.
+ * \param parent If not a null pointer, then it must be an initialized 
+ *    vector and the block hierarchy is stored here. For each block, the 
+ *    id (i.e. the position in the \p blocks pointer vector) of its 
+ *    parent block is stored. For the top block in the hierarchy, 
+ *    -1 is stored.
+ * \param block_tree If not a null pointer, then it must be a pointer 
+ *    to an uninitialized graph, and the block hierarchy is stored 
+ *    here as an igraph graph. The vertex ids correspond to the order 
+ *    of the blocks in the \p blocks vector.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/cohesive_blocks.c
+ */
+
+int igraph_cohesive_blocks(const igraph_t *graph,
+			   igraph_vector_ptr_t *blocks,
+			   igraph_vector_t *cohesion,
+			   igraph_vector_t *parent,
+			   igraph_t *block_tree) {
+
+  /* Some implementation comments. Everything is relatively
+     straightforward, except, that we need to follow the vertex ids
+     of the various subgraphs, without having to store two-way
+     mappings at each level. The subgraphs can overlap, this
+     complicates things a bit.
+
+     The 'Q' vector is used as a double ended queue and it contains
+     the subgraphs to work on in the future. Some other vectors are
+     associated with it. 'Qparent' gives the parent graph of a graph
+     in Q. Qmapping gives the mapping of the vertices from the graph
+     to the parent graph. Qcohesion is the vertex connectivity of the 
+     graph. 
+
+     Qptr is an integer and points to the next graph to work on.
+  */
+  
+  igraph_vector_ptr_t Q;
+  igraph_vector_ptr_t Qmapping;
+  igraph_vector_long_t Qparent;
+  igraph_vector_long_t Qcohesion;
+  igraph_vector_bool_t Qcheck;
+  long int Qptr=0;
+  igraph_integer_t conn;
+
+  igraph_t *graph_copy;
+  
+  igraph_vector_ptr_t separators;
+  igraph_vector_t compvertices;
+  igraph_vector_long_t components;
+  igraph_vector_bool_t marked;
+
+  igraph_vector_long_t compid;
+  igraph_dqueue_t bfsQ;
+  igraph_vector_t neis;
+
+  if (igraph_is_directed(graph)) {
+    IGRAPH_ERROR("Cohesive blocking only works on undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_STATUS("Starting cohesive block calculation.\n", 0);
+
+  if (blocks)   { igraph_vector_ptr_clear(blocks); }
+  if (cohesion) { igraph_vector_clear(cohesion);   }
+  if (parent)   { igraph_vector_clear(parent);     }
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&Q, 1));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Q);
+  IGRAPH_FINALLY(igraph_i_cohesive_blocks_free, &Q);
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&Qmapping, 1));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Qmapping);
+  IGRAPH_FINALLY(igraph_i_cohesive_blocks_free2, &Qmapping);
+
+  IGRAPH_CHECK(igraph_vector_long_init(&Qparent, 1));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &Qparent);
+
+  IGRAPH_CHECK(igraph_vector_long_init(&Qcohesion, 1));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &Qcohesion);
+
+  IGRAPH_CHECK(igraph_vector_bool_init(&Qcheck, 1));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &Qcheck);
+  
+  IGRAPH_CHECK(igraph_vector_ptr_init(&separators, 0));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &separators);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&compvertices, 0);
+  IGRAPH_CHECK(igraph_vector_bool_init(&marked, 0));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &marked);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_dqueue_init(&bfsQ, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &bfsQ);
+  IGRAPH_CHECK(igraph_vector_long_init(&compid, 0));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &compid);
+  IGRAPH_CHECK(igraph_vector_long_init(&components, 0));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &components);
+  
+  /* Put the input graph in the queue */
+  graph_copy=igraph_Calloc(1, igraph_t);
+  if (!graph_copy) { 
+    IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM);
+  }
+  IGRAPH_CHECK(igraph_copy(graph_copy, graph));
+  VECTOR(Q)[0] = graph_copy;
+  VECTOR(Qmapping)[0] = 0;	/* Identity mapping */
+  VECTOR(Qparent)[0] = -1;	/* Has no parent */
+  IGRAPH_CHECK(igraph_vertex_connectivity(graph, &conn, /*checks=*/ 1));
+  VECTOR(Qcohesion)[0] = conn;
+  VECTOR(Qcheck)[0] = 0;  
+
+  /* Then work until the queue is empty */
+  while (Qptr < igraph_vector_ptr_size(&Q)) {
+    igraph_t *mygraph=VECTOR(Q)[Qptr];
+    igraph_bool_t mycheck=VECTOR(Qcheck)[Qptr];
+    long int mynodes=igraph_vcount(mygraph);
+    long int i, nsep;
+    long int no, kept=0;
+    long int cptr=0;
+    long int nsepv=0;
+    igraph_bool_t addedsep=0;
+
+    IGRAPH_STATUSF(("Candidate %li: %li vertices,", 
+		    0, Qptr, mynodes));
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    /* Get the separators */
+    IGRAPH_CHECK(igraph_minimum_size_separators(mygraph, &separators));
+    IGRAPH_FINALLY(igraph_i_cohesive_blocks_free3, &separators);
+    nsep=igraph_vector_ptr_size(&separators);
+    
+    IGRAPH_STATUSF((" %li separators,", 0, nsep));
+
+    /* Remove them from the graph, also mark them */    
+    IGRAPH_CHECK(igraph_vector_bool_resize(&marked, mynodes));
+    igraph_vector_bool_null(&marked);
+    for (i=0; i<nsep; i++) {
+      igraph_vector_t *v=VECTOR(separators)[i];
+      long int j, n=igraph_vector_size(v);
+      for (j=0; j<n; j++) {
+	long int vv=(long int) VECTOR(*v)[j];
+	if (!VECTOR(marked)[vv]) {
+	  nsepv++;
+	  VECTOR(marked)[vv] = 1;
+	}
+      }
+    }
+    
+    /* Find the connected components, omitting the separator vertices, 
+       but including the neighboring separator vertices
+     */
+    IGRAPH_CHECK(igraph_i_cb_components(mygraph, &marked, 
+					&components, &no,
+					&compid, &bfsQ, &neis));
+
+    /* Add the separator vertices themselves, as another component,
+       but only if there is at least one vertex not included in any 
+       separator. */
+    if (nsepv != mynodes) {
+      addedsep=1;
+      for (i=0; i<mynodes; i++) {
+	if (VECTOR(marked)[i]) {
+	  IGRAPH_CHECK(igraph_vector_long_push_back(&components, i));
+	}
+      }
+      IGRAPH_CHECK(igraph_vector_long_push_back(&components, -1));
+      no++;
+    }
+
+    IGRAPH_STATUSF((" %li new candidates,", 0, no));
+
+    for (i=0; i<no; i++) {
+      igraph_vector_t *newmapping;
+      igraph_t *newgraph;
+      igraph_integer_t maxdeg;
+
+      igraph_vector_clear(&compvertices);
+      
+      while (1) {
+	long int v=VECTOR(components)[cptr++];
+	if (v < 0) { break; }
+	IGRAPH_CHECK(igraph_vector_push_back(&compvertices, v));
+      }
+      
+      newmapping=igraph_Calloc(1, igraph_vector_t);
+      if (!newmapping) {
+	IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, newmapping);
+      IGRAPH_VECTOR_INIT_FINALLY(newmapping, 0);
+      newgraph=igraph_Calloc(1, igraph_t);
+      if (!newgraph) { 
+	IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, newgraph);
+      IGRAPH_CHECK(igraph_induced_subgraph_map(mygraph, newgraph, 
+					igraph_vss_vector(&compvertices),
+					IGRAPH_SUBGRAPH_AUTO,
+					/*map=*/ 0,
+					/*invmap=*/ newmapping));
+      IGRAPH_FINALLY(igraph_destroy, newgraph);
+
+      IGRAPH_CHECK(igraph_maxdegree(newgraph, &maxdeg, igraph_vss_all(),
+				    IGRAPH_ALL, IGRAPH_LOOPS));
+      if (maxdeg > VECTOR(Qcohesion)[Qptr]) {
+	igraph_integer_t newconn;
+	kept++;
+	IGRAPH_CHECK(igraph_vector_ptr_push_back(&Q, newgraph));
+	IGRAPH_FINALLY_CLEAN(2);
+	IGRAPH_CHECK(igraph_vector_ptr_push_back(&Qmapping, newmapping));
+	IGRAPH_FINALLY_CLEAN(2);
+	IGRAPH_CHECK(igraph_vertex_connectivity(newgraph, &newconn, 
+						/*checks=*/ 1));
+	IGRAPH_CHECK(igraph_vector_long_push_back(&Qcohesion, newconn));
+	IGRAPH_CHECK(igraph_vector_long_push_back(&Qparent, Qptr));
+	IGRAPH_CHECK(igraph_vector_bool_push_back(&Qcheck, 
+						  mycheck || addedsep));
+      } else {
+	igraph_destroy(newgraph);
+	igraph_free(newgraph);
+	igraph_vector_destroy(newmapping);
+	igraph_free(newmapping);
+	IGRAPH_FINALLY_CLEAN(4);
+      }
+    }
+
+    IGRAPH_STATUSF((" keeping %li.\n", 0, kept));
+
+    igraph_destroy(mygraph);
+    igraph_free(mygraph);
+    VECTOR(Q)[Qptr] = 0;
+    igraph_i_cohesive_blocks_free3(&separators);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    Qptr++;
+  }
+
+  igraph_vector_long_destroy(&components);
+  igraph_vector_long_destroy(&compid);
+  igraph_dqueue_destroy(&bfsQ);
+  igraph_vector_destroy(&neis);
+  igraph_vector_bool_destroy(&marked);
+  igraph_vector_destroy(&compvertices);
+  igraph_vector_ptr_destroy(&separators);
+  IGRAPH_FINALLY_CLEAN(7);
+
+  if (blocks || cohesion || parent || block_tree) {
+    igraph_integer_t noblocks=(igraph_integer_t) Qptr, badblocks=0;
+    igraph_vector_bool_t removed;
+    long int i, resptr=0;
+    igraph_vector_long_t rewritemap;
+    
+    IGRAPH_CHECK(igraph_vector_bool_init(&removed, noblocks));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed);
+    IGRAPH_CHECK(igraph_vector_long_init(&rewritemap, noblocks));
+    IGRAPH_FINALLY(igraph_vector_long_destroy, &rewritemap);
+
+    for (i=1; i<noblocks; i++) {
+      long int p=VECTOR(Qparent)[i];
+      while (VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; }
+      if (VECTOR(Qcohesion)[p] >= VECTOR(Qcohesion)[i]) {
+	VECTOR(removed)[i]=1;
+	badblocks++;
+      }
+    }
+
+    /* Rewrite the mappings */
+    for (i=1; i<Qptr; i++) {
+      long int p=VECTOR(Qparent)[i];
+      igraph_vector_t *mapping=VECTOR(Qmapping)[i];
+      igraph_vector_t *pmapping=VECTOR(Qmapping)[p];
+      long int j, n=igraph_vector_size(mapping);
+
+      if (!pmapping) { continue; }
+      for (j=0; j<n; j++) {
+	long int v=(long int) VECTOR(*mapping)[j];
+	VECTOR(*mapping)[j] = VECTOR(*pmapping)[v];
+      }
+    }
+
+    /* Because we also put the separator vertices in the queue, it is 
+       not ensured that the found blocks are not subsets of each other.
+       We check this now. */
+    for (i=1; i<noblocks; i++) {
+      long int j, ic;
+      igraph_vector_t *ivec;
+      if (!VECTOR(Qcheck)[i] || VECTOR(removed)[i]) { continue; }
+      ivec=VECTOR(Qmapping)[i];
+      ic=VECTOR(Qcohesion)[i];
+      for (j=1; j<noblocks; j++) {
+	igraph_vector_t *jvec;
+	long int jc;
+	if (j==i || !VECTOR(Qcheck)[j] || VECTOR(removed)[j]) { continue; }
+	jvec=VECTOR(Qmapping)[j];
+	jc=VECTOR(Qcohesion)[j];
+	if (igraph_i_cb_isin(ivec, jvec) && jc >= ic) { 
+	  badblocks++; 
+	  VECTOR(removed)[i]=1;
+	  break;
+	}
+      }
+    }
+	  
+    noblocks -= badblocks;
+
+    if (blocks) { IGRAPH_CHECK(igraph_vector_ptr_resize(blocks, noblocks)); }
+    if (cohesion) { IGRAPH_CHECK(igraph_vector_resize(cohesion, noblocks)); }
+    if (parent) { IGRAPH_CHECK(igraph_vector_resize(parent, noblocks)); }
+
+    for (i=0; i<Qptr; i++) {
+      if (VECTOR(removed)[i]) { 
+	IGRAPH_STATUSF(("Candidate %li ignored.\n", 0, i));
+	continue; 
+      } else {
+	IGRAPH_STATUSF(("Candidate %li is a cohesive (sub)block\n", 0, i));
+      }
+      VECTOR(rewritemap)[i] = resptr;
+      if (cohesion) { VECTOR(*cohesion)[resptr]=VECTOR(Qcohesion)[i]; }
+      if (parent || block_tree) {
+	long int p=VECTOR(Qparent)[i];
+	while (p>=0 && VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; }
+	if (p>=0) { p=VECTOR(rewritemap)[p]; }
+	VECTOR(Qparent)[i]=p;
+	if (parent) { VECTOR(*parent)[resptr]=p; }
+      }
+      if (blocks) {
+	VECTOR(*blocks)[resptr]=VECTOR(Qmapping)[i];
+	VECTOR(Qmapping)[i]=0;
+      }
+      resptr++;
+    }
+
+    /* Plus the original graph */
+    if (blocks) {
+      igraph_vector_t *orig=igraph_Calloc(1, igraph_vector_t);
+      if (!orig) { 
+	IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); 
+      }
+      IGRAPH_FINALLY(igraph_free, orig);
+      IGRAPH_CHECK(igraph_vector_init_seq(orig, 0, igraph_vcount(graph)-1));
+      VECTOR(*blocks)[0]=orig;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    if (block_tree) {
+      igraph_vector_t edges;
+      long int eptr=0;
+      IGRAPH_VECTOR_INIT_FINALLY(&edges, noblocks*2-2);
+      for (i=1; i<Qptr; i++) {
+	if (VECTOR(removed)[i]) { continue; }
+	VECTOR(edges)[eptr++] = VECTOR(Qparent)[i];
+	VECTOR(edges)[eptr++] = VECTOR(rewritemap)[i];
+      }
+      
+      IGRAPH_CHECK(igraph_create(block_tree, &edges, noblocks, 
+				 IGRAPH_DIRECTED));
+      igraph_vector_destroy(&edges);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    igraph_vector_long_destroy(&rewritemap);
+    igraph_vector_bool_destroy(&removed);
+    IGRAPH_FINALLY_CLEAN(2);
+
+  }
+
+  igraph_vector_bool_destroy(&Qcheck);
+  igraph_vector_long_destroy(&Qcohesion);
+  igraph_vector_long_destroy(&Qparent);
+  igraph_i_cohesive_blocks_free2(&Qmapping);
+  IGRAPH_FINALLY_CLEAN(4);
+  
+  igraph_vector_ptr_destroy(&Qmapping);
+  igraph_vector_ptr_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(3);  	/* + the elements of Q, they were
+				   already destroyed */
+
+  IGRAPH_STATUS("Cohesive blocking done.\n", 0);
+
+  return 0;
+}
diff --git a/src/community.c b/src/community.c
new file mode 100644
index 0000000..3370679
--- /dev/null
+++ b/src/community.c
@@ -0,0 +1,3520 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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_community.h"
+#include "igraph_constructors.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_arpack.h"
+#include "igraph_arpack_internal.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_components.h"
+#include "igraph_dqueue.h"
+#include "igraph_progress.h"
+#include "igraph_stack.h"
+#include "igraph_spmatrix.h"
+#include "igraph_statusbar.h"
+#include "igraph_types_internal.h"
+#include "igraph_conversion.h"
+#include "igraph_centrality.h"
+#include "config.h"
+
+#include <string.h>
+#include <math.h>
+
+int igraph_i_rewrite_membership_vector(igraph_vector_t *membership) {
+  long int no=(long int) igraph_vector_max(membership)+1;
+  igraph_vector_t idx;
+  long int realno=0;
+  long int i;
+  long int len=igraph_vector_size(membership);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&idx, no);
+  for (i=0; i<len; i++) {
+    long int t=(long int) VECTOR(*membership)[i];
+    if (VECTOR(idx)[t]) {
+      VECTOR(*membership)[i]=VECTOR(idx)[t]-1;
+    } else {
+      VECTOR(idx)[t]=++realno;
+      VECTOR(*membership)[i]=VECTOR(idx)[t]-1;
+    }
+  }
+  igraph_vector_destroy(&idx);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_community_eb_get_merges2(const igraph_t *graph, 
+				      const igraph_vector_t *edges,
+                                      const igraph_vector_t *weights,
+				      igraph_matrix_t *res,
+				      igraph_vector_t *bridges, 
+				      igraph_vector_t *modularity, 
+				      igraph_vector_t *membership) {
+
+  igraph_vector_t mymembership;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  igraph_real_t maxmod=-1;
+  long int midx=0;
+  igraph_integer_t no_comps;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&mymembership, no_of_nodes);
+  
+  if (membership) {
+    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+  }
+
+  if (modularity || res || bridges) {
+    IGRAPH_CHECK(igraph_clusters(graph, 0, 0, &no_comps,
+				 IGRAPH_WEAK));
+
+    if (modularity) {
+      IGRAPH_CHECK(igraph_vector_resize(modularity,
+					no_of_nodes-no_comps+1));
+    }
+    if (res) {
+      IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes-no_comps,
+					2));
+    }
+    if (bridges) {
+      IGRAPH_CHECK(igraph_vector_resize(bridges,
+					no_of_nodes-no_comps));
+    }
+  }
+
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(mymembership)[i]=i;
+  }
+  if (membership) {
+    igraph_vector_update(membership, &mymembership);
+  }
+  
+  IGRAPH_CHECK(igraph_modularity(graph, &mymembership, &maxmod, weights));
+  if (modularity) {
+    VECTOR(*modularity)[0]=maxmod;
+  }
+
+  for (i=igraph_vector_size(edges)-1; i>=0; i--) {
+    long int edge=(long int) VECTOR(*edges)[i];
+    long int from=IGRAPH_FROM(graph, edge);
+    long int to=IGRAPH_TO(graph, edge);
+    long int c1=(long int) VECTOR(mymembership)[from];
+    long int c2=(long int) VECTOR(mymembership)[to];
+    igraph_real_t actmod;
+    long int j;
+    if (c1 != c2) {		/* this is a merge */
+      if (res) {
+	MATRIX(*res, midx, 0)=c1;
+	MATRIX(*res, midx, 1)=c2;
+      }
+      if (bridges) {
+	VECTOR(*bridges)[midx]=i+1;
+      }
+
+      /* The new cluster has id no_of_nodes+midx+1 */
+      for (j=0; j<no_of_nodes; j++) {
+	if (VECTOR(mymembership)[j]==c1 ||
+	    VECTOR(mymembership)[j]==c2) {
+	  VECTOR(mymembership)[j]=no_of_nodes+midx;
+	}
+      }
+      
+      IGRAPH_CHECK(igraph_modularity(graph, &mymembership, &actmod, weights));
+      if (modularity) {
+	VECTOR(*modularity)[midx+1]=actmod;
+	if (actmod > maxmod) {
+	  maxmod=actmod;
+	  if (membership) {
+	    igraph_vector_update(membership, &mymembership);
+	  }
+	}
+      }
+            
+      midx++;
+    }
+  }
+
+  if (membership) {
+    IGRAPH_CHECK(igraph_i_rewrite_membership_vector(membership));
+  }
+
+  igraph_vector_destroy(&mymembership);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+
+/**
+ * \function igraph_community_eb_get_merges
+ * \brief Calculating the merges, ie. the dendrogram for an edge betweenness community structure
+ * 
+ * </para><para> 
+ * This function is handy if you have a sequence of edge which are
+ * gradually removed from the network and you would like to know how
+ * the network falls apart into separate components. The edge sequence
+ * may come from the \ref igraph_community_edge_betweenness()
+ * function, but this is not necessary. Note that \ref
+ * igraph_community_edge_betweenness can also calculate the
+ * dendrogram, via its \p merges argument.
+ *
+ * \param graph The input graph.
+ * \param edges Vector containing the edges to be removed from the
+ *    network, all edges are expected to appear exactly once in the
+ *    vector.
+ * \param weights An optional vector containing edge weights. If null,
+ *     the unweighted modularity scores will be calculated. If not null,
+ *     the weighted modularity scores will be calculated. Ignored if both
+ *     \p modularity and \p membership are nulls.
+ * \param res Pointer to an initialized matrix, if not NULL then the 
+ *    dendrogram will be stored here, in the same form as for the \ref
+ *    igraph_community_walktrap() function: the matrix has two columns
+ *    and each line is a merge given by the ids of the merged
+ *    components. The component ids are number from zero and
+ *    component ids smaller than the number of vertices in the graph
+ *    belong to individual vertices. The non-trivial components
+ *    containing at least two vertices are numbered from \c n, \c n is
+ *    the number of vertices in the graph. So if the first line
+ *    contains \c a and \c b that means that components \c a and \c b
+ *    are merged into component \c n, the second line creates
+ *    component \c n+1, etc. The matrix will be resized as needed.
+ * \param bridges Pointer to an initialized vector or NULL. If not
+ *    null then the index of the edge removals which split the network
+ *    will be stored here. The vector will be resized as needed.
+ * \param modularity If not a null pointer, then the modularity values
+ *    for the different divisions, corresponding to the merges matrix,
+ *    will be stored here.
+ * \param membership If not a null pointer, then the membership vector
+ *    for the best division (in terms of modularity) will be stored
+ *    here.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_community_edge_betweenness().
+ * 
+ * Time complexity: O(|E|+|V|log|V|), |V| is the number of vertices,
+ * |E| is the number of edges.
+ */
+
+int igraph_community_eb_get_merges(const igraph_t *graph, 
+				   const igraph_vector_t *edges,
+                                   const igraph_vector_t *weights,
+				   igraph_matrix_t *res,
+				   igraph_vector_t *bridges, 
+				   igraph_vector_t *modularity, 
+				   igraph_vector_t *membership) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t ptr;
+  long int i, midx=0;
+  igraph_integer_t no_comps;
+
+  if (membership || modularity) {
+    return igraph_i_community_eb_get_merges2(graph, edges, weights, res,
+					     bridges, modularity, 
+					     membership);
+  }
+
+  IGRAPH_CHECK(igraph_clusters(graph, 0, 0, &no_comps, IGRAPH_WEAK));
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&ptr, no_of_nodes*2-1);
+  if (res) { 
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes-no_comps, 2));
+  }
+  if (bridges) {
+    IGRAPH_CHECK(igraph_vector_resize(bridges, no_of_nodes-no_comps));
+  }
+  
+  for (i=igraph_vector_size(edges)-1; i>=0; i--) {
+    igraph_integer_t edge=(igraph_integer_t) VECTOR(*edges)[i];
+    igraph_integer_t from, to, c1, c2, idx;
+    igraph_edge(graph, edge, &from, &to);
+    idx=from+1;
+    while (VECTOR(ptr)[idx-1] != 0) {
+      idx=(igraph_integer_t) VECTOR(ptr)[idx-1];
+    }
+    c1=idx-1;
+    idx=to+1;
+    while (VECTOR(ptr)[idx-1] != 0) {
+      idx=(igraph_integer_t) VECTOR(ptr)[idx-1];
+    }
+    c2=idx-1;
+    if (c1 != c2) {		/* this is a merge */
+      if (res) {
+	MATRIX(*res, midx, 0)=c1;
+	MATRIX(*res, midx, 1)=c2;
+      }
+      if (bridges) {
+	VECTOR(*bridges)[midx]=i+1;
+      }
+      
+      VECTOR(ptr)[c1]=no_of_nodes+midx+1;
+      VECTOR(ptr)[c2]=no_of_nodes+midx+1;
+      VECTOR(ptr)[from]=no_of_nodes+midx+1;
+      VECTOR(ptr)[to]=no_of_nodes+midx+1;
+      
+      midx++;
+    }
+  }
+
+  igraph_vector_destroy(&ptr);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/* Find the smallest active element in the vector */
+long int igraph_i_vector_which_max_not_null(const igraph_vector_t *v, 
+					    const char *passive) {
+  long int which, i=0, size=igraph_vector_size(v);
+  igraph_real_t max;
+  while (passive[i]) {
+    i++;
+  }
+  which=i;
+  max=VECTOR(*v)[which];
+  for (i++; i<size; i++) {
+    igraph_real_t elem=VECTOR(*v)[i];
+    if (!passive[i] && elem > max) {
+      max=elem;
+      which=i;
+    }
+  }
+  
+  return which;
+}
+
+/**
+ * \function igraph_community_edge_betweenness
+ * \brief Community finding based on edge betweenness
+ * 
+ * Community structure detection based on the betweenness of the edges
+ * in the network. The algorithm was invented by M. Girvan and
+ * M. Newman, see: M. Girvan and M. E. J. Newman: Community structure in
+ * social and biological networks, Proc. Nat. Acad. Sci. USA 99, 7821-7826
+ * (2002).
+ * 
+ * </para><para>
+ * The idea is that the betweenness of the edges connecting two
+ * communities is typically high, as many of the shortest paths
+ * between nodes in separate communities go through them. So we
+ * gradually remove the edge with highest betweenness from the
+ * network, and recalculate edge betweenness after every removal. 
+ * This way sooner or later the network falls off to two components,
+ * then after a while one of these components falls off to two smaller 
+ * components, etc. until all edges are removed. This is a divisive
+ * hierarchical approach, the result is a dendrogram.
+ * \param graph The input graph.
+ * \param result Pointer to an initialized vector, the result will be
+ *     stored here, the ids of the removed edges in the order of their 
+ *     removal. It will be resized as needed. It may be NULL if
+ *     the edge IDs are not needed by the caller.
+ * \param edge_betweenness Pointer to an initialized vector or
+ *     NULL. In the former case the edge betweenness of the removed
+ *     edge is stored here. The vector will be resized as needed.
+ * \param merges Pointer to an initialized matrix or NULL. If not NULL
+ *     then merges performed by the algorithm are stored here. Even if
+ *     this is a divisive algorithm, we can replay it backwards and
+ *     note which two clusters were merged. Clusters are numbered from
+ *     zero, see the \p merges argument of \ref
+ *     igraph_community_walktrap() for details. The matrix will be
+ *     resized as needed.
+ * \param bridges Pointer to an initialized vector of NULL. If not
+ *     NULL then all edge removals which separated the network into
+ *     more components are marked here.
+ * \param modularity If not a null pointer, then the modularity values
+ *     of the different divisions are stored here, in the order
+ *     corresponding to the merge matrix. The modularity values will
+ *     take weights into account if \p weights is not null.
+ * \param membership If not a null pointer, then the membership vector,
+ *     corresponding to the highest modularity value, is stored here.
+ * \param directed Logical constant, whether to calculate directed
+ *    betweenness (ie. directed paths) for directed graphs. It is
+ *    ignored for undirected graphs.
+ * \param weights An optional vector containing edge weights. If null,
+ *     the unweighted edge betweenness scores will be calculated and
+ *     used. If not null, the weighted edge betweenness scores will be
+ *     calculated and used.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_community_eb_get_merges(), \ref
+ * igraph_community_spinglass(), \ref igraph_community_walktrap().
+ * 
+ * Time complexity: O(|V||E|^2), as the betweenness calculation requires
+ * O(|V||E|) and we do it |E|-1 times.
+ * 
+ * \example examples/simple/igraph_community_edge_betweenness.c
+ */
+  
+int igraph_community_edge_betweenness(const igraph_t *graph, 
+				      igraph_vector_t *result,
+				      igraph_vector_t *edge_betweenness,
+				      igraph_matrix_t *merges,
+				      igraph_vector_t *bridges,
+				      igraph_vector_t *modularity,
+				      igraph_vector_t *membership,
+				      igraph_bool_t directed,
+				      const igraph_vector_t *weights) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  double *distance, *tmpscore;
+  unsigned long long int *nrgeo;
+  long int source, i, e;
+  
+  igraph_inclist_t elist_out, elist_in, fathers;
+  igraph_inclist_t *elist_out_p, *elist_in_p;
+  igraph_vector_t *neip;
+  long int neino;
+  igraph_vector_t eb;
+  long int maxedge, pos;
+  igraph_integer_t from, to;
+  igraph_bool_t result_owned = 0;
+  igraph_stack_t stack=IGRAPH_STACK_NULL;
+  igraph_real_t steps, steps_done;
+
+  char *passive;
+
+  /* Needed only for the unweighted case */
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+
+  /* Needed only for the weighted case */
+  igraph_2wheap_t heap;
+
+  if (result == 0) {
+    result = igraph_Calloc(1, igraph_vector_t);
+    if (result == 0)
+      IGRAPH_ERROR("edge betweenness community structure failed", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(igraph_free, result);
+    IGRAPH_VECTOR_INIT_FINALLY(result, 0);
+    result_owned = 1;
+  }
+
+  directed=directed && igraph_is_directed(graph);
+  if (directed) {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &elist_out, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &elist_out);
+    IGRAPH_CHECK(igraph_inclist_init(graph, &elist_in, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &elist_in);
+    elist_out_p=&elist_out;
+    elist_in_p=&elist_in;
+  } else {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &elist_out, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &elist_out);
+    elist_out_p=elist_in_p=&elist_out;
+  }
+  
+  distance=igraph_Calloc(no_of_nodes, double);
+  if (distance==0) {
+    IGRAPH_ERROR("edge betweenness community structure failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, distance);
+  nrgeo=igraph_Calloc(no_of_nodes, unsigned long long int);
+  if (nrgeo==0) {
+    IGRAPH_ERROR("edge betweenness community structure failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, nrgeo);
+  tmpscore=igraph_Calloc(no_of_nodes, double);
+  if (tmpscore==0) {
+    IGRAPH_ERROR("edge betweenness community structure failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, tmpscore);
+
+  if (weights == 0) {
+    IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  } else {
+    if (igraph_vector_min(weights) <= 0) {
+      IGRAPH_ERROR("weights must be strictly positive", IGRAPH_EINVAL);
+    }
+    IGRAPH_CHECK(igraph_2wheap_init(&heap, no_of_nodes));
+    IGRAPH_FINALLY(igraph_2wheap_destroy, &heap);
+    IGRAPH_CHECK(igraph_inclist_init_empty(&fathers, 
+					   (igraph_integer_t) no_of_nodes));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &fathers);
+  }
+
+  IGRAPH_CHECK(igraph_stack_init(&stack, no_of_nodes));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+  
+  IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));
+  if (edge_betweenness) {
+    IGRAPH_CHECK(igraph_vector_resize(edge_betweenness, no_of_edges));
+    VECTOR(*edge_betweenness)[no_of_edges-1]=0;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&eb, no_of_edges);
+  
+  passive=igraph_Calloc(no_of_edges, char);
+  if (!passive) {
+    IGRAPH_ERROR("edge betweenness community structure failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, passive);
+
+  /* Estimate the number of steps to be taken.
+   * It is assumed that one iteration is O(|E||V|), but |V| is constant
+   * anyway, so we will have approximately |E|^2 / 2 steps, and one
+   * iteration of the outer loop advances the step counter by the number
+   * of remaining edges at that iteration.
+   */
+  steps = no_of_edges / 2.0 * (no_of_edges+1);
+  steps_done = 0;
+
+  for (e=0; e<no_of_edges; steps_done += no_of_edges-e, e++) {
+    IGRAPH_PROGRESS("Edge betweenness community detection: ",
+        100.0*steps_done/steps, NULL);
+
+    igraph_vector_null(&eb);
+
+    if (weights == 0) {
+      /* Unweighted variant follows */
+
+      /* The following for loop is copied almost intact from
+       * igraph_edge_betweenness_estimate */
+      for (source=0; source<no_of_nodes; source++) {
+
+        IGRAPH_ALLOW_INTERRUPTION();
+
+        memset(distance, 0, (size_t) no_of_nodes*sizeof(double));
+        memset(nrgeo, 0, (size_t) no_of_nodes*sizeof(unsigned long long int));
+        memset(tmpscore, 0, (size_t) no_of_nodes*sizeof(double));
+        igraph_stack_clear(&stack); /* it should be empty anyway... */
+        
+        IGRAPH_CHECK(igraph_dqueue_push(&q, source));
+        
+        nrgeo[source]=1;
+        distance[source]=0;
+        
+        while (!igraph_dqueue_empty(&q)) {
+          long int actnode=(long int) igraph_dqueue_pop(&q);
+          
+          neip=igraph_inclist_get(elist_out_p, actnode);
+          neino=igraph_vector_size(neip);
+          for (i=0; i<neino; i++) {
+            igraph_integer_t edge=(igraph_integer_t) VECTOR(*neip)[i], from, to;
+            long int neighbor;
+            igraph_edge(graph, edge, &from, &to);
+            neighbor = actnode!=from ? from : to;
+            if (nrgeo[neighbor] != 0) {
+              /* we've already seen this node, another shortest path? */
+              if (distance[neighbor]==distance[actnode]+1) {
+                nrgeo[neighbor]+=nrgeo[actnode];
+              }
+            } else {
+              /* we haven't seen this node yet */
+              nrgeo[neighbor]+=nrgeo[actnode];
+              distance[neighbor]=distance[actnode]+1;
+              IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+              IGRAPH_CHECK(igraph_stack_push(&stack, neighbor));
+            }
+          }
+        } /* while !igraph_dqueue_empty */
+        
+        /* Ok, we've the distance of each node and also the number of
+           shortest paths to them. Now we do an inverse search, starting
+           with the farthest nodes. */
+        while (!igraph_stack_empty(&stack)) {
+          long int actnode=(long int) igraph_stack_pop(&stack);
+          if (distance[actnode]<1) { continue; } /* skip source node */
+          
+          /* set the temporary score of the friends */
+          neip=igraph_inclist_get(elist_in_p, actnode);
+          neino=igraph_vector_size(neip);
+          for (i=0; i<neino; i++) {
+            long int edge = (long int) VECTOR(*neip)[i];
+            long int neighbor = IGRAPH_OTHER(graph, edge, actnode);
+            if (distance[neighbor]==distance[actnode]-1 &&
+                nrgeo[neighbor] != 0) {
+              tmpscore[neighbor] +=
+                (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
+              VECTOR(eb)[edge] +=
+                (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
+            }
+          }
+        }
+        /* Ok, we've the scores for this source */
+      } /* for source <= no_of_nodes */
+    } else {
+      /* Weighted variant follows */
+
+      /* The following for loop is copied almost intact from
+       * igraph_i_edge_betweenness_estimate_weighted */
+      for (source=0; source<no_of_nodes; source++) {
+        /* This will contain the edge betweenness in the current step */
+        IGRAPH_ALLOW_INTERRUPTION();
+
+        memset(distance, 0, (size_t) no_of_nodes*sizeof(double));
+        memset(nrgeo, 0, (size_t) no_of_nodes*sizeof(unsigned long long int));
+        memset(tmpscore, 0, (size_t) no_of_nodes*sizeof(double));
+
+        igraph_2wheap_push_with_index(&heap, source, 0);
+        distance[source]=1.0;
+        nrgeo[source]=1;
+
+        while (!igraph_2wheap_empty(&heap)) {
+          long int minnei = igraph_2wheap_max_index(&heap);
+          igraph_real_t mindist = -igraph_2wheap_delete_max(&heap);
+
+          igraph_stack_push(&stack, minnei);
+
+          neip=igraph_inclist_get(elist_out_p, minnei);
+          neino=igraph_vector_size(neip);
+
+          for (i=0; i<neino; i++) {
+            long int edge=(long int) 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;
+
+            if (curdist == 0) {
+              /* This is the first finite distance to 'to' */
+              v = igraph_inclist_get(&fathers, to);
+              igraph_vector_resize(v, 1);
+              VECTOR(*v)[0] = edge;
+              nrgeo[to] = nrgeo[minnei];
+              distance[to] = altdist + 1.0;
+              IGRAPH_CHECK(igraph_2wheap_push_with_index(&heap, to, -altdist));
+            } else if (altdist < curdist-1) {
+              /* This is a shorter path */
+              v = igraph_inclist_get(&fathers, to);
+              igraph_vector_resize(v, 1);
+              VECTOR(*v)[0] = edge;
+              nrgeo[to] = nrgeo[minnei];
+              distance[to] = altdist + 1.0;
+              IGRAPH_CHECK(igraph_2wheap_modify(&heap, to, -altdist));
+            } else if (altdist == curdist-1) {
+              /* Another path with the same length */
+              v = igraph_inclist_get(&fathers, to);
+              igraph_vector_push_back(v, edge);
+              nrgeo[to] += nrgeo[minnei];
+            }
+          }
+        } /* igraph_2wheap_empty(&Q) */
+
+        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);
+
+          for (i = 0; i < fatv_len; i++) {
+            long int fedge = (long int) VECTOR(*fatv)[i];
+            long int neighbor = IGRAPH_OTHER(graph, fedge, w);
+            tmpscore[neighbor] += (tmpscore[w] + 1) * nrgeo[neighbor] / nrgeo[w];
+            VECTOR(eb)[fedge] += (tmpscore[w] + 1) * nrgeo[neighbor] / nrgeo[w];
+          }
+
+          tmpscore[w] = 0;
+          distance[w] = 0;
+          nrgeo[w] = 0;
+          igraph_vector_clear(fatv);
+        }
+      } /* source < no_of_nodes */
+    }
+    
+    /* Now look for the smallest edge betweenness */
+    /* and eliminate that edge from the network */
+    maxedge=igraph_i_vector_which_max_not_null(&eb, passive);
+    VECTOR(*result)[e]=maxedge;
+    if (edge_betweenness) {
+      VECTOR(*edge_betweenness)[e]=VECTOR(eb)[maxedge];
+      if (!directed) { 
+	VECTOR(*edge_betweenness)[e] /= 2.0;
+      }
+    }
+    passive[maxedge]=1;
+    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);
+    VECTOR(*neip)[pos]=VECTOR(*neip)[neino-1];
+    igraph_vector_pop_back(neip);
+    
+    neip=igraph_inclist_get(elist_out_p, from);
+    neino=igraph_vector_size(neip);
+    igraph_vector_search(neip, 0, maxedge, &pos);
+    VECTOR(*neip)[pos]=VECTOR(*neip)[neino-1];
+    igraph_vector_pop_back(neip);
+  }
+
+  IGRAPH_PROGRESS("Edge betweenness community detection: ", 100.0, NULL);
+
+  igraph_free(passive);
+  igraph_vector_destroy(&eb);
+  igraph_stack_destroy(&stack);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (weights == 0) {
+    igraph_dqueue_destroy(&q);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    igraph_2wheap_destroy(&heap);
+    igraph_inclist_destroy(&fathers);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  igraph_free(tmpscore);
+  igraph_free(nrgeo);
+  igraph_free(distance);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (directed) {
+    igraph_inclist_destroy(&elist_out);
+    igraph_inclist_destroy(&elist_in);
+    IGRAPH_FINALLY_CLEAN(2);
+  } else {
+    igraph_inclist_destroy(&elist_out);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (merges || bridges || modularity || membership) {
+    IGRAPH_CHECK(igraph_community_eb_get_merges(graph, result, weights, merges,
+						bridges, modularity, 
+						membership));
+  }
+  
+  if (result_owned) {
+    igraph_vector_destroy(result);
+    free(result);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  return 0;
+}
+
+
+/**
+ * \function igraph_community_to_membership 
+ * \brief Create membership vector from community structure dendrogram
+ * 
+ * This function creates a membership vector from a community
+ * structure dendrogram. A membership vector contains for each vertex
+ * the id of its graph component, the graph components are numbered
+ * from zero, see the same argument of \ref igraph_clusters() for an
+ * example of a membership vector.
+ * 
+ * </para><para>
+ * Many community detection algorithms return with a \em merges
+ * matrix, \ref igraph_community_walktrap() and \ref
+ * igraph_community_edge_betweenness() are two examples. The matrix
+ * contains the merge operations performed while mapping the
+ * hierarchical structure of a network. If the matrix has \c n-1 rows,
+ * where \c n is the number of vertices in the graph, then it contains
+ * the hierarchical structure of the whole network and it is called a
+ * dendrogram. 
+ * 
+ * </para><para>
+ * This function performs \p steps merge operations as prescribed by
+ * the \p merges matrix and returns the current state of the network.
+ * 
+ * </para><para>
+ * If \p merges is not a complete dendrogram, it is possible to
+ * take \p steps steps if \p steps is not bigger than the number 
+ * lines in \p merges.
+ * \param merges The two-column matrix containing the merge
+ *    operations. See \ref igraph_community_walktrap() for the
+ *    detailed syntax.
+ * \param nodes The number of leaf nodes in the dendrogram
+ * \param steps Integer constant, the number of steps to take.
+ * \param membership Pointer to an initialized vector, the membership
+ *    results will be stored here, if not NULL. The vector will be
+ *    resized as needed.
+ * \param csize Pointer to an initialized vector, or NULL. If not NULL
+ *    then the sizes of the components will be stored here, the vector
+ *    will be resized as needed.
+ * 
+ * \sa \ref igraph_community_walktrap(), \ref
+ * igraph_community_edge_betweenness(), \ref
+ * igraph_community_fastgreedy() for community structure detection
+ * algorithms.
+ * 
+ * Time complexity: O(|V|), the number of vertices in the graph.
+ */
+
+int igraph_community_to_membership(const igraph_matrix_t *merges,
+				   igraph_integer_t nodes,
+				   igraph_integer_t steps,
+				   igraph_vector_t *membership,
+				   igraph_vector_t *csize) {
+  
+  long int no_of_nodes=nodes;
+  long int components=no_of_nodes-steps;
+  long int i, found=0;
+  igraph_vector_t tmp;
+  
+  if (steps > igraph_matrix_nrow(merges)) {
+    IGRAPH_ERROR("`steps' to big or `merges' matrix too short", IGRAPH_EINVAL);
+  }
+
+  if (membership) {
+    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+    igraph_vector_null(membership);
+  }
+  if (csize) {
+    IGRAPH_CHECK(igraph_vector_resize(csize, components));
+    igraph_vector_null(csize);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, steps);
+  
+  for (i=steps-1; i>=0; i--) {
+    long int c1=(long int) MATRIX(*merges, i, 0);
+    long int c2=(long int) MATRIX(*merges, i, 1);
+
+    /* new component? */
+    if (VECTOR(tmp)[i]==0) {
+      found++;
+      VECTOR(tmp)[i]=found;
+    }
+
+    if (c1<no_of_nodes) {
+      long int cid=(long int) VECTOR(tmp)[i]-1;
+      if (membership) { VECTOR(*membership)[c1]=cid+1; }
+      if (csize) { VECTOR(*csize)[cid] += 1; }
+    } else {
+      VECTOR(tmp)[c1-no_of_nodes]=VECTOR(tmp)[i];
+    }
+    
+    if (c2<no_of_nodes) { 
+      long int cid=(long int) VECTOR(tmp)[i]-1;
+      if (membership) {	VECTOR(*membership)[c2]=cid+1; }
+      if (csize) { VECTOR(*csize)[cid] += 1; }
+    } else {
+      VECTOR(tmp)[c2-no_of_nodes]=VECTOR(tmp)[i];
+    }
+    
+  }
+  
+  if (membership || csize) {
+    for (i=0; i<no_of_nodes; i++) {
+      long int tmp=(long int) VECTOR(*membership)[i];
+      if (tmp!=0) {
+	if (membership) {
+	  VECTOR(*membership)[i]=tmp-1;
+	}
+      } else {
+	if (csize) {
+	  VECTOR(*csize)[found]+=1;
+	}
+	if (membership) {
+	  VECTOR(*membership)[i]=found;
+	}
+	found++;
+      }
+    }
+  }
+  
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_modularity
+ * \brief Calculate the modularity of a graph with respect to some vertex types
+ * 
+ * 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 is defined as 
+ * Q=1/(2m) * sum((Aij - ki*kj / (2m)) delta(ci,cj), i, j), here `m' is the
+ * number of edges, `Aij' is the element of the `A' adjacency matrix
+ * in row `i' and column `j', `ki' is the degree of `i', `kj' is the
+ * degree of `j', `ci' is the type (or component) of `i', `cj' that of
+ * `j', the sum goes over all `i' and `j' pairs of vertices, and
+ * `delta(x,y)' is one if x=y and zero otherwise.
+ *
+ * </para><para>
+ * Modularity on weighted graphs is also meaningful. When taking edge
+ * weights into account, `Aij' becomes the weight of the corresponding
+ * edge (or 0 if there is no edge), `ki' is the total weight of edges
+ * incident on vertex `i', `kj' is the total weight of edges incident
+ * on vertex `j' and `m' is the total weight of all edges.
+ * 
+ * </para><para>
+ * See also Clauset, A.; Newman, M. E. J.; Moore, C. Finding
+ * community structure in very large networks, Physical Review E,
+ * 2004, 70, 066111.
+ * \param graph The input graph.
+ * \param membership Numeric vector which gives the type of each
+ *     vertex, ie. the component to which it belongs.
+ *     It does not have to be consecutive, i.e. empty communities are
+ *     allowed. 
+ * \param modularity Pointer to a real number, the result will be
+ *     stored here.
+ * \param weights Weight vector or NULL if no weights are specified.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges.
+ */
+
+int igraph_modularity(const igraph_t *graph, 
+		      const igraph_vector_t *membership,
+		      igraph_real_t *modularity,
+			  const igraph_vector_t *weights) {
+  
+  igraph_vector_t e, a;
+  long int types=(long int) igraph_vector_max(membership)+1;
+  long int no_of_edges=igraph_ecount(graph);
+  long int i;
+  igraph_integer_t from, to;
+  igraph_real_t m;
+  long int c1, c2;
+
+  if (igraph_vector_size(membership) < igraph_vcount(graph)) {
+    IGRAPH_ERROR("cannot calculate modularity, membership vector too short",
+      IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&e, types);
+  IGRAPH_VECTOR_INIT_FINALLY(&a, types);
+  
+  if (weights) {
+    if (igraph_vector_size(weights) < no_of_edges)
+      IGRAPH_ERROR("cannot calculate modularity, weight vector too short",
+        IGRAPH_EINVAL);
+    m=igraph_vector_sum(weights);
+    for (i=0; i<no_of_edges; i++) {
+      igraph_real_t w=VECTOR(*weights)[i];
+      if (w < 0)
+        IGRAPH_ERROR("negative weight in weight vector", IGRAPH_EINVAL);
+      igraph_edge(graph, (igraph_integer_t) i, &from, &to);
+      c1=(long int) VECTOR(*membership)[from];
+      c2=(long int) VECTOR(*membership)[to];
+      if (c1==c2) VECTOR(e)[c1] += 2*w;
+      VECTOR(a)[c1] += w;
+      VECTOR(a)[c2] += w;
+    }
+  } else {
+    m=no_of_edges;
+    for (i=0; i<no_of_edges; i++) {
+      igraph_edge(graph, (igraph_integer_t) i, &from, &to);
+      c1=(long int) VECTOR(*membership)[from];
+      c2=(long int) VECTOR(*membership)[to];
+      if (c1==c2) VECTOR(e)[c1] += 2;
+      VECTOR(a)[c1] += 1;
+      VECTOR(a)[c2] += 1;
+    }
+  }
+
+  *modularity=0.0;
+  if (m > 0) {
+    for (i=0; i<types; i++) {
+      igraph_real_t tmp=VECTOR(a)[i]/2/m;
+      *modularity += VECTOR(e)[i]/2/m;
+      *modularity -= tmp*tmp;
+    }
+  }
+  
+  igraph_vector_destroy(&e);
+  igraph_vector_destroy(&a);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_modularity_matrix
+ */
+
+int igraph_modularity_matrix(const igraph_t *graph, 
+			     const igraph_vector_t *membership,
+			     igraph_matrix_t *modmat, 
+			     const igraph_vector_t *weights) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);  
+  igraph_real_t sw= weights ? igraph_vector_sum(weights) : no_of_edges;
+  igraph_vector_t deg;
+  long int i, j;
+
+  if (igraph_vector_size(membership) != igraph_vcount(graph)) {
+    IGRAPH_ERROR("Cannot calculate modularity matrix, invalid "
+		 "membership vector length", IGRAPH_EINVAL);
+  }
+  
+  if (weights && igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, no_of_nodes);
+  if (!weights) {
+    IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(), IGRAPH_ALL, 
+			       IGRAPH_LOOPS));
+  } else {
+    IGRAPH_CHECK(igraph_strength(graph, &deg, igraph_vss_all(), IGRAPH_ALL, 
+				 IGRAPH_LOOPS, weights));
+  }
+  IGRAPH_CHECK(igraph_get_adjacency(graph, modmat, IGRAPH_GET_ADJACENCY_BOTH, 
+				    /*eids=*/ 0));
+
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<no_of_nodes; j++) {
+      MATRIX(*modmat, i, j) -= VECTOR(deg)[i] * VECTOR(deg)[j] / 2.0 / sw;
+    }
+  }
+  
+  igraph_vector_destroy(&deg);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_reindex_membership
+ * \brief Makes the IDs in a membership vector continuous
+ *
+ * This function reindexes component IDs in a membership vector
+ * in a way that the new IDs start from zero and go up to C-1,
+ * where C is the number of unique component IDs in the original
+ * vector.
+ *
+ * This function was contributed by Tom Gregorovic.
+ *
+ * \param  membership  Numeric vector which gives the type of each
+ *                     vertex, ie. the component to which it belongs.
+ *                     The vector will be altered in-place.
+ * \param  new_to_old  Pointer to a vector which will contain the
+ *                     old component ID for each new one, or NULL,
+ *                     in which case it is not returned. The vector
+ *                     will be resized as needed.
+ *
+ * Time complexity: should be O(n log n) for n elements.
+ */
+int igraph_reindex_membership(igraph_vector_t *membership,
+                              igraph_vector_t *new_to_old) {
+  long int i, pos, size = igraph_vector_size(membership);
+  igraph_vector_t old_sorted, *new_to_old_real;
+  igraph_real_t last_id, this_id;
+
+  /* Make sure that membership is not empty; if empty, return
+   * immediately */
+  if (size == 0) {
+    if (new_to_old != 0) {
+      igraph_vector_clear(new_to_old);
+    }
+    return 0;
+  }
+
+  /* Prepare storage space for new_to_old */
+  if (new_to_old == 0) {
+    new_to_old_real = igraph_Calloc(1, igraph_vector_t);
+    if (new_to_old_real == 0)
+      IGRAPH_ERROR("cannot reindex membership vector", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(igraph_free, new_to_old_real);
+    IGRAPH_VECTOR_INIT_FINALLY(new_to_old_real, 0);
+  } else {
+    new_to_old_real = new_to_old;
+    IGRAPH_CHECK(igraph_vector_resize(new_to_old_real, 0));
+  }
+
+  /* Create sorted membership vector */
+  IGRAPH_CHECK(igraph_vector_copy(&old_sorted, membership));
+  IGRAPH_FINALLY(igraph_vector_destroy, &old_sorted);
+  igraph_vector_sort(&old_sorted);
+
+  /* Create new_to_old_real */
+  last_id = VECTOR(old_sorted)[0] - 1;
+  for (i = 0; i < size; i++) {
+    this_id = VECTOR(old_sorted)[i];
+    if (last_id != this_id) {
+      IGRAPH_CHECK(igraph_vector_push_back(new_to_old_real, this_id));
+      last_id = this_id;
+    }
+  }
+
+  /* old_sorted not needed anymore */
+  igraph_vector_destroy(&old_sorted);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Reindex the original membership vector */
+  for (i = 0; i < size; i++) {
+    this_id = VECTOR(*membership)[i];
+    igraph_vector_binsearch(new_to_old_real, this_id, &pos);
+    VECTOR(*membership)[i] = pos;
+  }
+
+  /* Get rid of new_to_old_real if it was allocated by us */
+  if (new_to_old == 0) {
+    igraph_vector_destroy(new_to_old_real);
+    igraph_free(new_to_old_real);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  return 0;
+}
+
+/********************************************************************/
+
+/**
+ * \section about_leading_eigenvector_methods
+ * 
+ * <para>
+ * The function documented in these section implements the 
+ * <quote>leading eigenvector</quote> method developed by Mark Newman and 
+ * published in MEJ Newman: Finding community structure using the
+ * eigenvectors of matrices, Phys Rev E 74:036104 (2006).</para>
+ * 
+ * <para>
+ * The heart of the method is the definition of the modularity matrix,
+ * B, which is B=A-P, A being the adjacency matrix of the (undirected)
+ * network, and P contains the probability that certain edges are
+ * present according to the <quote>configuration model</quote> In
+ * other words, a Pij element of P is the probability that there is an
+ * edge between vertices i and j in a random network in which the
+ * degrees of all vertices are the same as in the input graph.</para>
+ * 
+ * <para>
+ * 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 community structure.
+ * Check Newman's paper to understand why this is a good method for
+ * detecting community structure. </para>
+ * 
+ * <para>
+ * The leading eigenvector community structure detection method is 
+ * implemented in \ref igraph_community_leading_eigenvector(). 
+ * After the initial split, the following splits are done in a
+ * way to optimize modularity regarding to the original network. 
+ * </para>
+ * 
+ * <para>
+ * \example examples/simple/igraph_community_leading_eigenvector.c
+ * </para>
+ */
+
+typedef struct igraph_i_community_leading_eigenvector_data_t {
+  igraph_vector_t *idx;
+  igraph_vector_t *idx2;
+  igraph_adjlist_t *adjlist;
+  igraph_inclist_t *inclist;
+  igraph_vector_t *tmp;
+  long int no_of_edges;
+  igraph_vector_t *mymembership;
+  long int comm;
+  const igraph_vector_t *weights;
+  const igraph_t *graph;
+  igraph_vector_t *strength;
+  igraph_real_t sumweights;
+} igraph_i_community_leading_eigenvector_data_t;
+
+int igraph_i_community_leading_eigenvector(igraph_real_t *to,
+					   const igraph_real_t *from,
+					   int n, void *extra) {
+  
+  igraph_i_community_leading_eigenvector_data_t *data=extra;
+  long int j, k, nlen, size=n;
+  igraph_vector_t *idx=data->idx;
+  igraph_vector_t *idx2=data->idx2;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_adjlist_t *adjlist=data->adjlist;
+  igraph_real_t ktx, ktx2;
+  long int no_of_edges=data->no_of_edges;
+  igraph_vector_t *mymembership=data->mymembership;
+  long int comm=data->comm;
+
+  /* Ax */
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, oldid);
+    nlen=igraph_vector_int_size(neis);
+    to[j]=0.0;
+    VECTOR(*tmp)[j]=0.0;
+    for (k=0; k<nlen; k++) {
+      long int nei=(long int) VECTOR(*neis)[k];
+      long int neimemb=(long int) VECTOR(*mymembership)[nei];
+      if (neimemb==comm) {
+	to[j] += from[ (long int) VECTOR(*idx2)[nei] ];
+	VECTOR(*tmp)[j] += 1;
+      }
+    }
+  }
+  
+  /* Now calculate k^Tx/2m */
+  ktx=0.0; ktx2=0.0;
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, oldid);
+    long int degree=igraph_vector_int_size(neis);
+    ktx += from[j] * degree;
+    ktx2 += degree;
+  }
+  ktx = ktx / no_of_edges/2.0;
+  ktx2 = ktx2 / no_of_edges/2.0;
+  
+  /* Now calculate Bx */
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, oldid);
+    igraph_real_t degree=igraph_vector_int_size(neis);
+    to[j] = to[j] - ktx*degree;
+    VECTOR(*tmp)[j] = VECTOR(*tmp)[j] - ktx2*degree;
+  }
+  
+  /* -d_ij summa l in G B_il */
+  for (j=0; j<size; j++) {
+    to[j] -= VECTOR(*tmp)[j] * from[j];
+  }
+
+  return 0;
+}
+
+int igraph_i_community_leading_eigenvector2(igraph_real_t *to,
+					    const igraph_real_t *from,
+					    int n, void *extra) {
+  
+  igraph_i_community_leading_eigenvector_data_t *data=extra;
+  long int j, k, nlen, size=n;
+  igraph_vector_t *idx=data->idx;
+  igraph_vector_t *idx2=data->idx2;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_adjlist_t *adjlist=data->adjlist;
+  igraph_real_t ktx, ktx2;
+  long int no_of_edges=data->no_of_edges;
+  igraph_vector_t *mymembership=data->mymembership;
+  long int comm=data->comm;
+
+  /* Ax */
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, oldid);
+    nlen=igraph_vector_int_size(neis);
+    to[j]=0.0;
+    VECTOR(*tmp)[j]=0.0;
+    for (k=0; k<nlen; k++) {
+      long int nei=(long int) VECTOR(*neis)[k];
+      long int neimemb=(long int) VECTOR(*mymembership)[nei];
+      if (neimemb==comm) {
+	long int fi=(long int) VECTOR(*idx2)[nei];
+	if (fi < size) {
+	  to[j] += from[fi];
+	}
+	VECTOR(*tmp)[j] += 1;
+      }
+    }
+  }
+  
+  /* Now calculate k^Tx/2m */
+  ktx=0.0; ktx2=0.0;
+  for (j=0; j<size+1; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, oldid);
+    long int degree=igraph_vector_int_size(neis);
+    if (j<size) {
+      ktx += from[j] * degree;
+    }
+    ktx2 += degree;
+  }
+  ktx = ktx / no_of_edges/2.0;
+  ktx2 = ktx2 / no_of_edges/2.0;
+  
+  /* Now calculate Bx */
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, oldid);
+    igraph_real_t degree=igraph_vector_int_size(neis);
+    to[j] = to[j] - ktx*degree;
+    VECTOR(*tmp)[j] = VECTOR(*tmp)[j] - ktx2*degree;
+  }
+  
+  /* -d_ij summa l in G B_il */
+  for (j=0; j<size; j++) {
+    to[j] -= VECTOR(*tmp)[j] * from[j];
+  }
+
+  return 0;
+}
+
+int igraph_i_community_leading_eigenvector_weighted(igraph_real_t *to,
+					    const igraph_real_t *from,
+					    int n, void *extra) {
+
+  igraph_i_community_leading_eigenvector_data_t *data=extra;
+  long int j, k, nlen, size=n;
+  igraph_vector_t *idx=data->idx;
+  igraph_vector_t *idx2=data->idx2;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_inclist_t *inclist=data->inclist;
+  igraph_real_t ktx, ktx2;
+  igraph_vector_t *mymembership=data->mymembership;
+  long int comm=data->comm;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_t *strength=data->strength;
+  igraph_real_t sw=data->sumweights;
+  
+  /* 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);
+    to[j]=0.0;
+    VECTOR(*tmp)[j]=0.0;
+    for (k=0; k<nlen; k++) {
+      long int edge=(long int) VECTOR(*inc)[k];
+      igraph_real_t w=VECTOR(*weights)[edge];
+      long int nei=IGRAPH_OTHER(graph, edge, oldid);
+      long int neimemb=(long int) VECTOR(*mymembership)[nei];
+      if (neimemb==comm) {
+	to[j] += from[ (long int) VECTOR(*idx2)[nei] ] * w;
+	VECTOR(*tmp)[j] += w;
+      }
+    }
+  }
+
+  /* k^Tx/2m */
+  ktx=0.0; ktx2=0.0;
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_real_t str=VECTOR(*strength)[oldid];
+    ktx += from[j] * str;
+    ktx2 += str;
+  }
+  ktx = ktx / sw / 2.0;
+  ktx2 = ktx2 / sw / 2.0;
+
+  /* Bx */
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_real_t str=VECTOR(*strength)[oldid];
+    to[j] = to[j] - ktx * str;
+    VECTOR(*tmp)[j] = VECTOR(*tmp)[j] - ktx2*str;
+  }
+
+  /* -d_ij summa l in G B_il */
+  for (j=0; j<size; j++) {
+    to[j] -= VECTOR(*tmp)[j] * from[j];
+  }
+
+  return 0;
+}
+
+int igraph_i_community_leading_eigenvector2_weighted(igraph_real_t *to,
+					    const igraph_real_t *from,
+					    int n, void *extra) {
+  
+  igraph_i_community_leading_eigenvector_data_t *data=extra;
+  long int j, k, nlen, size=n;
+  igraph_vector_t *idx=data->idx;
+  igraph_vector_t *idx2=data->idx2;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_inclist_t *inclist=data->inclist;
+  igraph_real_t ktx, ktx2;
+  igraph_vector_t *mymembership=data->mymembership;
+  long int comm=data->comm;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_t *strength=data->strength;
+  igraph_real_t sw=data->sumweights;
+
+  /* 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);
+    to[j]=0.0;
+    VECTOR(*tmp)[j]=0.0;
+    for (k=0; k<nlen; k++) {
+      long int edge=(long int) VECTOR(*inc)[k];
+      igraph_real_t w=VECTOR(*weights)[edge];
+      long int nei=IGRAPH_OTHER(graph, edge, oldid);
+      long int neimemb=(long int) VECTOR(*mymembership)[nei];
+      if (neimemb==comm) {
+	long int fi=(long int) VECTOR(*idx2)[nei];
+	if (fi < size) {
+	  to[j] += from[fi] * w;
+	}
+	VECTOR(*tmp)[j] += w;
+      }
+    }
+  }
+  
+  /* k^Tx/2m */
+  ktx=0.0; ktx2=0.0;
+  for (j=0; j<size+1; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_real_t str=VECTOR(*strength)[oldid];
+    if (j<size) { 
+      ktx += from[j] * str;
+    } 
+    ktx2 += str;
+  }
+  ktx = ktx / sw / 2.0;
+  ktx2 = ktx2 / sw / 2.0;
+
+  /* Bx */
+  for (j=0; j<size; j++) {
+    long int oldid=(long int) VECTOR(*idx)[j];
+    igraph_real_t str=VECTOR(*strength)[oldid];
+    to[j] = to[j] - ktx * str;
+    VECTOR(*tmp)[j] = VECTOR(*tmp)[j] - ktx2 * str;
+  }
+
+  /* -d_ij summa l in G B_il */
+  for (j=0; j<size; j++) {
+    to[j] -= VECTOR(*tmp)[j] * from[j];
+  }
+
+  return 0;
+}
+
+void igraph_i_levc_free(igraph_vector_ptr_t *ptr) { 
+  long int i, n=igraph_vector_ptr_size(ptr);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*ptr)[i];
+    if (v) {
+      igraph_vector_destroy(v);
+      igraph_free(v);
+    }
+  }
+}
+
+void igraph_i_error_handler_none(const char *reason, const char *file,
+				 int line, int igraph_errno) {
+  IGRAPH_UNUSED(reason);
+  IGRAPH_UNUSED(file);
+  IGRAPH_UNUSED(line);
+  IGRAPH_UNUSED(igraph_errno);  
+  /* do nothing */
+}
+
+
+/**
+ * \ingroup communities
+ * \function igraph_community_leading_eigenvector
+ * \brief Leading eigenvector community finding (proper version).
+ * 
+ * Newman's leading eigenvector method for detecting community
+ * structure. This is the proper implementation of the recursive,
+ * divisive algorithm: each split is done by maximizing the modularity 
+ * regarding the original network, see MEJ Newman: Finding community
+ * structure in networks using the eigenvectors of matrices,
+ * Phys Rev E 74:036104 (2006).
+ * 
+ * \param graph The undirected input graph.
+ * \param weights The weights of the edges, or a null pointer for 
+ *    unweighted graphs.
+ * \param merges The result of the algorithm, a matrix containing the
+ *    information about the splits performed. The matrix is built in
+ *    the opposite way however, it is like the result of an
+ *    agglomerative algorithm. If at the end of the algorithm (after
+ *    \p steps steps was done) there are <quote>p</quote> communities,
+ *    then these are numbered from zero to <quote>p-1</quote>. The
+ *    first line of the matrix contains the first <quote>merge</quote>
+ *    (which is in reality the last split) of two communities into
+ *    community <quote>p</quote>, the merge in the second line forms 
+ *    community <quote>p+1</quote>, etc. The matrix should be
+ *    initialized before calling and will be resized as needed.
+ *    This argument is ignored of it is \c NULL.
+ * \param membership The membership of the vertices after all the
+ *    splits were performed will be stored here. The vector must be
+ *    initialized  before calling and will be resized as needed.
+ *    This argument is ignored if it is \c NULL. This argument can 
+ *    also be used to supply a starting configuration for the community 
+ *    finding, in the format of a membership vector. In this case the 
+ *    \p start argument must be set to 1.
+ * \param steps The maximum number of steps to perform. It might
+ *    happen that some component (or the whole network) has no
+ *    underlying community structure and no further steps can be
+ *    done. If you want as many steps as possible then supply the 
+ *    number of vertices in the network here.
+ * \param options The options for ARPACK. \c n is always
+ *    overwritten. \c ncv is set to at least 4.
+ * \param modularity If not a null pointer, then it must be a pointer
+ *    to a real number and the modularity score of the final division
+ *    is stored here.
+ * \param start Boolean, whether to use the community structure given 
+ *    in the \p membership argument as a starting point.
+ * \param eigenvalues Pointer to an initialized vector or a null
+ *    pointer. If not a null pointer, then the eigenvalues calculated
+ *    along the community structure detection are stored here. The
+ *    non-positive eigenvalues, that do not result a split, are stored
+ *    as well.
+ * \param eigenvectors If not a null pointer, then the eigenvectors 
+ *    that are calculated in each step of the algorithm, are stored here, 
+ *    in a pointer vector. Each eigenvector is stored in an
+ *    \ref igraph_vector_t object. The user is responsible of
+ *    deallocating the memory that belongs to the individual vectors,
+ *    by calling first \ref igraph_vector_destroy(), and then
+ *    <code>free()</code> on them.
+ * \param history Pointer to an initialized vector or a null pointer. 
+ *    If not a null pointer, then a trace of the algorithm is stored
+ *    here, encoded numerically. The various operations:
+ *    \clist
+ *    \cli IGRAPH_LEVC_HIST_START_FULL
+ *      Start the algorithm from an initial state where each connected
+ *      component is a separate community.
+ *    \cli IGRAPH_LEVC_HIST_START_GIVEN
+ *      Start the algorithm from a given community structure. The next
+ *      value in the vector contains the initial number of
+ *      communities.
+ *    \cli IGRAPH_LEVC_HIST_SPLIT
+ *      Split a community into two communities. The id of the splitted
+ *      community is given in the next element of the history vector. 
+ *      The id of the first new community is the same as the id of the
+ *      splitted community. The id of the second community equals to
+ *      the number of communities before the split.
+ *    \cli IGRAPH_LEVC_HIST_FAILED
+ *      Tried to split a community, but it was not worth it, as it
+ *      does not result in a bigger modularity value. The id of the
+ *      community is given in the next element of the vector.
+ *    \endclist
+ * \param callback A null pointer or a function of type \ref
+ *    igraph_community_leading_eigenvector_callback_t. If given, this
+ *    callback function is called after each eigenvector/eigenvalue
+ *    calculation. If the callback returns a non-zero value, then the
+ *    community finding algorithm stops. See the arguments passed to
+ *    the callback at the documentation of \ref
+ *    igraph_community_leading_eigenvector_callback_t. 
+ * \param callback_extra Extra argument to pass to the callback
+ *    function.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_community_walktrap() and \ref
+ * igraph_community_spinglass() for other community structure
+ * detection methods.
+ * 
+ * Time complexity: O(|E|+|V|^2*steps), |V| is the number of vertices,
+ * |E| the number of edges, <quote>steps</quote> the number of splits
+ * performed.
+ */
+
+int igraph_community_leading_eigenvector(const igraph_t *graph,
+        const igraph_vector_t *weights,
+	igraph_matrix_t *merges,
+	igraph_vector_t *membership,
+	igraph_integer_t steps,
+	igraph_arpack_options_t *options, 
+	igraph_real_t *modularity,
+	igraph_bool_t start,
+	igraph_vector_t *eigenvalues,
+	igraph_vector_ptr_t *eigenvectors,
+	igraph_vector_t *history,
+        igraph_community_leading_eigenvector_callback_t *callback,
+        void *callback_extra) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_dqueue_t tosplit;
+  igraph_vector_t idx, idx2, mymerges;
+  igraph_vector_t strength, tmp;
+  long int staken=0;
+  igraph_adjlist_t adjlist;
+  igraph_inclist_t inclist;
+  long int i, j, k, l;
+  long int communities;
+  igraph_vector_t vmembership, *mymembership=membership;
+  igraph_i_community_leading_eigenvector_data_t extra;
+  igraph_arpack_storage_t storage;
+  igraph_real_t mod=0;
+  igraph_arpack_function_t *arpcb1 = 
+    weights ? igraph_i_community_leading_eigenvector_weighted : 
+    igraph_i_community_leading_eigenvector;
+  igraph_arpack_function_t *arpcb2 = 
+    weights ? igraph_i_community_leading_eigenvector2_weighted : 
+    igraph_i_community_leading_eigenvector2;
+  igraph_real_t sumweights=0.0;
+
+  if (weights && no_of_edges != igraph_vector_size(weights)) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (start && !membership) { 
+    IGRAPH_ERROR("Cannot start from given configuration if memberships "
+		 "missing", IGRAPH_EINVAL);
+  }
+  
+  if (start && membership && 
+      igraph_vector_size(membership) != no_of_nodes) {
+    IGRAPH_ERROR("Wrong length for vector of predefined memberships", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (start && membership && igraph_vector_max(membership) >= no_of_nodes) {
+    IGRAPH_WARNING("Too many communities in membership start vector");
+  }
+
+  if (igraph_is_directed(graph)) {
+    IGRAPH_WARNING("This method was developed for undirected graphs");
+  }
+  
+  if (steps < 0 || steps > no_of_nodes-1) {
+    steps=(igraph_integer_t) no_of_nodes-1;
+  }
+  
+  if (!membership) {
+    mymembership=&vmembership;
+    IGRAPH_VECTOR_INIT_FINALLY(mymembership, 0);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&mymerges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&mymerges, steps*2));
+  IGRAPH_VECTOR_INIT_FINALLY(&idx, 0);
+  if (eigenvalues)  { igraph_vector_clear(eigenvalues);      }
+  if (eigenvectors) { 
+    igraph_vector_ptr_clear(eigenvectors); 
+    IGRAPH_FINALLY(igraph_i_levc_free, eigenvectors);
+  }
+
+  IGRAPH_STATUS("Starting leading eigenvector method.\n", 0);
+
+  if (!start) {
+    /* Calculate the weakly connected components in the graph and use them as
+     * an initial split */
+    IGRAPH_CHECK(igraph_clusters(graph, mymembership, &idx, 0, IGRAPH_WEAK));
+    communities = igraph_vector_size(&idx);
+    IGRAPH_STATUSF(("Starting from %li component(s).\n", 0, communities));
+    if (history) { 
+      IGRAPH_CHECK(igraph_vector_push_back(history, 
+					   IGRAPH_LEVC_HIST_START_FULL));
+    }
+  } else {
+    /* Just create the idx vector for the given membership vector */
+    communities=(long int) igraph_vector_max(mymembership)+1;
+    IGRAPH_STATUSF(("Starting from given membership vector with %li "
+		    "communities.\n", 0, communities));
+    if (history) { 
+      IGRAPH_CHECK(igraph_vector_push_back(history, 
+					   IGRAPH_LEVC_HIST_START_GIVEN));
+      IGRAPH_CHECK(igraph_vector_push_back(history, communities));
+    }
+    IGRAPH_CHECK(igraph_vector_resize(&idx, communities));
+    igraph_vector_null(&idx);
+    for (i=0; i<no_of_nodes; i++) {
+      int t=(int) VECTOR(*mymembership)[i];
+      VECTOR(idx)[t] += 1;
+    }
+  }
+
+  IGRAPH_DQUEUE_INIT_FINALLY(&tosplit, 100);
+  for (i = 0; i < communities; i++) {
+    if (VECTOR(idx)[i] > 2) {
+      igraph_dqueue_push(&tosplit, i);
+    }
+  }
+  for (i=1; i<communities; i++) {
+    /* Record merge */
+    IGRAPH_CHECK(igraph_vector_push_back(&mymerges, i-1));
+    IGRAPH_CHECK(igraph_vector_push_back(&mymerges, i));
+    if (eigenvalues) { 
+      IGRAPH_CHECK(igraph_vector_push_back(eigenvalues, IGRAPH_NAN));
+    }
+    if (eigenvectors) { 
+      igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
+      if (!v) { 
+	IGRAPH_ERROR("Cannot do leading eigenvector community detection", 
+		     IGRAPH_ENOMEM); 
+      }
+      IGRAPH_FINALLY(igraph_free, v);
+      IGRAPH_VECTOR_INIT_FINALLY(v, 0);
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(eigenvectors, v));
+      IGRAPH_FINALLY_CLEAN(2);
+    }
+    if (history) {
+      IGRAPH_CHECK(igraph_vector_push_back(history, IGRAPH_LEVC_HIST_SPLIT));
+      IGRAPH_CHECK(igraph_vector_push_back(history, i-1));
+    }
+  }
+  staken = communities - 1;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, no_of_nodes);
+  IGRAPH_CHECK(igraph_vector_resize(&idx, no_of_nodes));
+  igraph_vector_null(&idx);
+  IGRAPH_VECTOR_INIT_FINALLY(&idx2, no_of_nodes);
+  if (!weights) { 
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  } else {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+    IGRAPH_VECTOR_INIT_FINALLY(&strength, no_of_nodes);
+    IGRAPH_CHECK(igraph_strength(graph, &strength, igraph_vss_all(), 
+				 IGRAPH_ALL, IGRAPH_LOOPS, weights));
+    sumweights=igraph_vector_sum(weights);
+  }
+
+  options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rssolve */
+  options->start = 0;
+  options->which[0]='L'; options->which[1]='A';
+
+  /* Memory for ARPACK */
+  /* We are allocating memory for 20 eigenvectors since options->ncv won't be
+   * larger than 20 when using automatic mode in igraph_arpack_rssolve */
+  IGRAPH_CHECK(igraph_arpack_storage_init(&storage, (int) no_of_nodes, 20,
+					  (int) no_of_nodes, 1));
+  IGRAPH_FINALLY(igraph_arpack_storage_destroy, &storage);
+  extra.idx=&idx;
+  extra.idx2=&idx2;
+  extra.tmp=&tmp;
+  extra.adjlist=&adjlist;
+  extra.inclist=&inclist;
+  extra.weights=weights;
+  extra.sumweights=sumweights;
+  extra.graph=graph;
+  extra.strength=&strength;
+  extra.no_of_edges=no_of_edges;
+  extra.mymembership=mymembership;
+
+  while (!igraph_dqueue_empty(&tosplit) && staken < steps) {
+    long int comm=(long int) igraph_dqueue_pop_back(&tosplit); 
+				/* depth first search */
+    long int size=0;
+    igraph_real_t tmpev;
+
+    IGRAPH_STATUSF(("Trying to split community %li... ", 0, comm));
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    for (i=0; i<no_of_nodes; i++) {
+      if (VECTOR(*mymembership)[i]==comm) {
+        VECTOR(idx)[size]=i;
+        VECTOR(idx2)[i]=size++;
+      }
+    }
+
+    staken++;
+    if (size<=2) {
+      continue;
+    }
+
+    /* We solve two eigenproblems, one for the original modularity
+       matrix, and one for the modularity matrix after deleting the
+       last row and last column from it. This is a trick to find
+       multiple leading eigenvalues, because ARPACK is sometimes
+       unstable when the first two eigenvalues are requested, but it
+       does much better for the single principal eigenvalue. */
+
+    /* We start with the smaller eigenproblem. */
+
+    options->n=(int) size-1;
+    options->info=0;
+    options->nev=1;
+    options->ldv=0;
+    options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rssolve */
+    options->nconv = 0;
+    options->lworkl = 0;		/* we surely have enough space */
+    extra.comm=comm;
+
+    /* We try calling the solver twice, once from a random starting
+       point, once from a fixed one. This is because for some hard
+       cases it tends to fail. We need to suppress error handling for
+       the first call. */
+    {
+      int i;
+      igraph_error_handler_t *errh=
+	igraph_set_error_handler(igraph_i_error_handler_none);
+      igraph_warning_handler_t *warnh=
+	igraph_set_warning_handler(igraph_warning_handler_ignore);
+      igraph_arpack_rssolve(arpcb2, &extra, options, &storage,
+			    /*values=*/ 0, /*vectors=*/ 0);
+      igraph_set_error_handler(errh);
+      igraph_set_warning_handler(warnh);
+      if (options->nconv < 1) {
+	/* Call again, from a fixed starting point */
+	options->start=1;
+	options->info=0;
+	options->ncv=0;
+	options->lworkl = 0;	/* we surely have enough space */
+	for (i=0; i < options->n ; i++) {
+	  storage.resid[i] = 1;
+	}
+	IGRAPH_CHECK(igraph_arpack_rssolve(arpcb2, &extra, options, &storage,
+					   /*values=*/ 0, /*vectors=*/ 0));
+	options->start=0;	
+      }
+    }
+    
+    if (options->nconv < 1) {
+      IGRAPH_ERROR("ARPACK did not converge", IGRAPH_ARPACK_FAILED);
+    }
+
+    tmpev=storage.d[0];
+
+    /* Now we do the original eigenproblem, again, twice if needed */
+
+    options->n=(int) size;
+    options->info=0;
+    options->nev=1;
+    options->ldv=0;
+    options->nconv=0;
+    options->lworkl = 0;	/* we surely have enough space */
+    options->ncv = 0;   /* 0 means "automatic" in igraph_arpack_rssolve */
+    
+    {
+      int i;
+      igraph_error_handler_t *errh=
+	igraph_set_error_handler(igraph_i_error_handler_none);
+      igraph_arpack_rssolve(arpcb1, &extra, options, &storage,
+			    /*values=*/ 0, /*vectors=*/ 0);
+      igraph_set_error_handler(errh);
+      if (options->nconv < 1) {
+	/* Call again from a fixed starting point */
+	options->start=1;
+	options->info=0;
+	options->ncv=0;
+	options->lworkl = 0;	/* we surely have enough space */
+	for (i=0; i < options->n; i++) { storage.resid[i] = 1; }
+	IGRAPH_CHECK(igraph_arpack_rssolve(arpcb1, &extra, options, &storage, 
+					   /*values=*/ 0, /*vectors=*/ 0));
+	options->start=0;
+      }
+    }
+
+    if (options->nconv < 1) {
+      IGRAPH_ERROR("ARPACK did not converge", IGRAPH_ARPACK_FAILED);
+    }
+
+    /* Ok, we have the leading eigenvector of the modularity matrix*/
+    
+    /* ---------------------------------------------------------------*/
+    /* To avoid numeric errors */
+    if (fabs(storage.d[0]) < 1e-8) { 
+      storage.d[0] = 0;
+    }
+
+    /* We replace very small (in absolute value) elements of the 
+       leading eigenvector with zero, to get the same result, 
+       consistently.*/
+    for (i=0; i<size; i++) {
+      if (fabs(storage.v[i]) < 1e-8) {
+	storage.v[i]=0;
+      }
+    }
+
+    /* Just to have the always the same result, we multiply by -1
+       if the first (nonzero) element is not positive. */
+    for (i=0; i<size; i++) {
+      if (storage.v[i] != 0) { break; }
+    }
+    if (i<size && storage.v[i]<0) {
+      for (i=0; i<size; i++) {
+        storage.v[i] = - storage.v[i];
+      }
+    }
+    /* ---------------------------------------------------------------*/
+
+    if (callback) {
+      igraph_vector_t vv;
+      int ret;
+      igraph_vector_view(&vv, storage.v, size);
+      ret=callback(mymembership, comm, storage.d[0], &vv, 
+		   arpcb1, &extra, callback_extra);
+      if (ret) {
+	break;
+      }
+    }
+
+    if (eigenvalues) {
+      IGRAPH_CHECK(igraph_vector_push_back(eigenvalues, storage.d[0]));
+    }
+
+    if (eigenvectors) { 
+      igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
+      if (!v) { 
+	IGRAPH_ERROR("Cannot do leading eigenvector community detection", 
+		     IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, v);
+      IGRAPH_VECTOR_INIT_FINALLY(v, size);
+      for (i=0; i<size; i++) {
+	VECTOR(*v)[i]=storage.v[i];
+      }
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(eigenvectors, v));
+      IGRAPH_FINALLY_CLEAN(2);
+    }
+
+    if (storage.d[0] <= 0) {
+      IGRAPH_STATUS("no split.\n", 0);
+      if (history) { 
+	IGRAPH_CHECK(igraph_vector_push_back(history, 
+					     IGRAPH_LEVC_HIST_FAILED));
+	IGRAPH_CHECK(igraph_vector_push_back(history, comm));
+      }					     
+      continue; 
+    }
+
+    /* Check for multiple leading eigenvalues */
+
+    if (fabs(storage.d[0]-tmpev) < 1e-8) {
+      IGRAPH_STATUS("multiple principal eigenvalue, no split.\n", 0);
+      if (history) { 
+	IGRAPH_CHECK(igraph_vector_push_back(history, 
+					     IGRAPH_LEVC_HIST_FAILED));
+	IGRAPH_CHECK(igraph_vector_push_back(history, comm));
+      }					     
+      continue;
+    }
+
+    /* Count the number of vertices in each community after the split */
+    l=0;
+    for (j=0; j<size; j++) {
+      if (storage.v[j] < 0) {
+	storage.v[j] = -1;
+        l++;
+      } else {
+	storage.v[j] = 1;
+      }
+    }
+    if (l==0 || l==size) {
+      IGRAPH_STATUS("no split.\n", 0);
+      if (history) { 
+	IGRAPH_CHECK(igraph_vector_push_back(history, 
+					     IGRAPH_LEVC_HIST_FAILED));
+	IGRAPH_CHECK(igraph_vector_push_back(history, comm));
+      }					     
+      continue;
+    }
+
+    /* Check that Q increases with our choice of split */
+    arpcb1(storage.v+size, storage.v, (int) size, &extra);
+    mod=0;
+    for (i=0; i<size; i++) {
+      mod += storage.v[size+i] * storage.v[i];
+    }
+    if (mod <= 1e-8) {
+      IGRAPH_STATUS("no modularity increase, no split.\n", 0);
+      if (history) { 
+	IGRAPH_CHECK(igraph_vector_push_back(history, 
+					     IGRAPH_LEVC_HIST_FAILED));
+	IGRAPH_CHECK(igraph_vector_push_back(history, comm));
+      }					     
+      continue;      
+    }
+
+    communities++;
+    IGRAPH_STATUS("split.\n", 0);
+    
+    /* Rewrite the mymembership vector */
+    for (j=0; j<size; j++) {
+      if (storage.v[j] < 0) {
+        long int oldid=(long int) VECTOR(idx)[j];
+        VECTOR(*mymembership)[oldid]=communities-1;
+      }
+    }
+
+    /* Record merge */
+    IGRAPH_CHECK(igraph_vector_push_back(&mymerges, comm));
+    IGRAPH_CHECK(igraph_vector_push_back(&mymerges, communities-1));
+    if (history) {
+      IGRAPH_CHECK(igraph_vector_push_back(history, IGRAPH_LEVC_HIST_SPLIT));
+      IGRAPH_CHECK(igraph_vector_push_back(history, comm));
+    }
+
+    /* Store the resulting communities in the queue if needed */
+    if (l > 1) {
+      IGRAPH_CHECK(igraph_dqueue_push(&tosplit, communities-1));
+    }
+    if (size-l > 1) {
+      IGRAPH_CHECK(igraph_dqueue_push(&tosplit, comm));
+    }
+    
+  }
+  
+  igraph_arpack_storage_destroy(&storage);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (!weights) { 
+    igraph_adjlist_destroy(&adjlist);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    igraph_inclist_destroy(&inclist);
+    igraph_vector_destroy(&strength);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  igraph_dqueue_destroy(&tosplit);
+  igraph_vector_destroy(&tmp);
+  igraph_vector_destroy(&idx2);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  IGRAPH_STATUS("Done.\n", 0);
+
+  /* reform the mymerges vector */
+  if (merges) {
+    igraph_vector_null(&idx);
+    l=igraph_vector_size(&mymerges);
+    k=communities;
+    j=0;
+    IGRAPH_CHECK(igraph_matrix_resize(merges, l/2, 2));
+    for (i=l; i>0; i-=2) {
+      long int from=(long int) VECTOR(mymerges)[i-1];
+      long int to=(long int) VECTOR(mymerges)[i-2];
+      MATRIX(*merges, j, 0)=VECTOR(mymerges)[i-2];
+      MATRIX(*merges, j, 1)=VECTOR(mymerges)[i-1];    
+      if (VECTOR(idx)[from]!=0) {
+	MATRIX(*merges, j, 1)=VECTOR(idx)[from]-1;
+      }
+      if (VECTOR(idx)[to]!=0) {
+	MATRIX(*merges, j, 0)=VECTOR(idx)[to]-1;
+      }
+      VECTOR(idx)[to]=++k;
+      j++;
+    }      
+  }
+  
+  if (eigenvectors) { IGRAPH_FINALLY_CLEAN(1); }
+  igraph_vector_destroy(&idx);
+  igraph_vector_destroy(&mymerges);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (modularity) {
+    IGRAPH_CHECK(igraph_modularity(graph, mymembership, modularity, 
+				   weights));
+  }
+  
+  if (!membership) {
+    igraph_vector_destroy(mymembership);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_le_community_to_membership
+ * Vertex membership from the leading eigenvector community structure
+ * 
+ * This function creates a membership vector from the
+ * result of \ref igraph_community_leading_eigenvector(),
+ * It takes \c membership
+ * and performs \c steps merges, according to the supplied
+ * \c merges matrix.
+ * \param merges The matrix defining the merges to make. 
+ *     This is usually from the output of the leading eigenvector community
+ *     structure detection routines.
+ * \param steps The number of steps to make according to \c merges.
+ * \param membership Initially the starting membership vector, 
+ *     on output the resulting membership vector, after performing \c steps merges.
+ * \param csize Optionally the sizes of the communities is stored here, 
+ *     if this is not a null pointer, but an initialized vector.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), the number of vertices.
+ */
+
+int igraph_le_community_to_membership(const igraph_matrix_t *merges,
+				      igraph_integer_t steps,
+				      igraph_vector_t *membership,
+				      igraph_vector_t *csize) {
+
+  long int no_of_nodes=igraph_vector_size(membership);
+  igraph_vector_t fake_memb;
+  long int components, i;
+
+  if (igraph_matrix_nrow(merges) < steps) {
+    IGRAPH_ERROR("`steps' to big or `merges' matrix too short", IGRAPH_EINVAL);
+  }    
+  
+  components=(long int) igraph_vector_max(membership)+1;
+  if (components > no_of_nodes) { 
+    IGRAPH_ERROR("Invalid membership vector, too many components", IGRAPH_EINVAL);
+  }
+  if (steps >= components) {
+    IGRAPH_ERROR("Cannot make `steps' steps from supplied membership vector",
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&fake_memb, components);
+  
+  /* Check membership vector */
+  for (i=0; i<no_of_nodes; i++) {
+    if (VECTOR(*membership)[i] < 0) {
+      IGRAPH_ERROR("Invalid membership vector, negative id", IGRAPH_EINVAL);
+    }
+    VECTOR(fake_memb)[ (long int) VECTOR(*membership)[i] ] += 1;
+  }
+  for (i=0; i<components; i++) {
+    if (VECTOR(fake_memb)[i] == 0) {
+      IGRAPH_ERROR("Invalid membership vector, empty cluster", IGRAPH_EINVAL);
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_community_to_membership(merges, (igraph_integer_t)
+					      components, steps, 
+					      &fake_memb, 0));
+  
+  /* Ok, now we have the membership of the initial components, 
+     rewrite the original membership vector. */
+
+  if (csize) {
+    IGRAPH_CHECK(igraph_vector_resize(csize, components-steps));
+    igraph_vector_null(csize);
+  }
+
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(*membership)[i] = VECTOR(fake_memb)[ (long int) VECTOR(*membership)[i] ];
+    if (csize) {
+      VECTOR(*csize)[ (long int) VECTOR(*membership)[i] ] += 1;
+    }
+  }
+
+  igraph_vector_destroy(&fake_memb);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;  
+}
+
+/********************************************************************/
+
+/**
+ * \ingroup communities
+ * \function igraph_community_label_propagation
+ * \brief Community detection based on label propagation
+ *
+ * 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.
+ * 
+ * </para><para>
+ * Weights are taken into account as follows: when the new label of node
+ * i is determined, the algorithm iterates over all edges incident on
+ * node i and calculate the total weight of edges leading to other
+ * nodes with label 0, 1, 2, ..., k-1 (where k is the number of possible
+ * labels). The new label of node i will then be the label whose edges
+ * (among the ones incident on node i) have the highest total weight.
+ * 
+ * \param graph The input graph, should be undirected to make sense.
+ * \param membership The membership vector, the result is returned here.
+ *    For each vertex it gives the ID of its community (label).
+ * \param weights The weight vector, it should contain a positive
+ *    weight for all the edges.
+ * \param initial The initial state. If 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 Boolean 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.
+ * \param modularity If not a null pointer, then it must be a pointer
+ *   to a real number. The modularity score of the detected community
+ *   structure is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(m+n)
+ * 
+ * \example examples/simple/igraph_community_label_propagation.c
+ */
+int igraph_community_label_propagation(const igraph_t *graph,
+                                       igraph_vector_t *membership,
+                                       const igraph_vector_t *weights,
+                                       const igraph_vector_t *initial,
+                                       igraph_vector_bool_t *fixed, 
+				       igraph_real_t *modularity) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int no_of_not_fixed_nodes=no_of_nodes;
+  long int i, j, k;
+  igraph_adjlist_t al;
+  igraph_inclist_t il;
+  igraph_bool_t running = 1;
+
+  igraph_vector_t label_counters, dominant_labels, nonzero_labels, node_order;
+
+  /* The implementation uses a trick to avoid negative array indexing:
+   * elements of the membership vector are increased by 1 at the start
+   * of the algorithm; this to allow us to denote unlabeled vertices
+   * (if any) by zeroes. The membership vector is shifted back in the end
+   */
+
+  /* Do some initial checks */
+  if (fixed && igraph_vector_bool_size(fixed) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid fixed labeling vector length", IGRAPH_EINVAL);
+  }
+  if (weights) {
+    if (igraph_vector_size(weights) != no_of_edges) {
+      IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+    } else if (igraph_vector_min(weights) < 0) {
+      IGRAPH_ERROR("Weights must be non-negative", IGRAPH_EINVAL);
+    }
+  }
+  if (fixed && !initial) {
+    IGRAPH_WARNING("Ignoring fixed vertices as no initial labeling given");
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+
+  if (initial) {
+    if (igraph_vector_size(initial) != no_of_nodes) {
+      IGRAPH_ERROR("Invalid initial labeling vector length", IGRAPH_EINVAL);
+    }
+    /* Check if the labels used are valid, initialize membership vector */
+    for (i=0; i<no_of_nodes; i++) {
+      if (VECTOR(*initial)[i] < 0) {
+        VECTOR(*membership)[i] = 0;
+      } else {
+        VECTOR(*membership)[i] = floor(VECTOR(*initial)[i]) + 1;
+      }
+    }
+    if (fixed) {
+      for (i=0; i<no_of_nodes; i++) {
+        if (VECTOR(*fixed)[i]) {
+          if (VECTOR(*membership)[i] == 0) {
+            IGRAPH_WARNING("Fixed nodes cannot be unlabeled, ignoring them");
+            VECTOR(*fixed)[i] = 0;
+          } else {
+            no_of_not_fixed_nodes--;
+          }
+        }
+      }
+    }
+
+    i = (long int) igraph_vector_max(membership);
+    if (i > no_of_nodes) {
+      IGRAPH_ERROR("elements of the initial labeling vector must be between 0 and |V|-1", IGRAPH_EINVAL);
+    }
+    if (i <= 0) {
+      IGRAPH_ERROR("at least one vertex must be labeled in the initial labeling", IGRAPH_EINVAL);
+    }
+  } else {
+    for (i=0; i<no_of_nodes; i++) {
+      VECTOR(*membership)[i] = i;
+    }
+  }
+
+  /* Create an adjacency/incidence list representation for efficiency.
+   * For the unweighted case, the adjacency list is enough. For the
+   * weighted case, we need the incidence list */
+  if (weights) {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &il, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &il);
+  } else {
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &al, IGRAPH_IN));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
+  }
+
+  /* Create storage space for counting distinct labels and dominant ones */
+  IGRAPH_VECTOR_INIT_FINALLY(&label_counters, no_of_nodes+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&dominant_labels, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&nonzero_labels, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&dominant_labels, 2));
+
+  RNG_BEGIN();
+
+  /* Initialize node ordering vector with only the not fixed nodes */
+  if (fixed) {
+    IGRAPH_VECTOR_INIT_FINALLY(&node_order, no_of_not_fixed_nodes);
+    for (i=0, j=0; i<no_of_nodes; i++) {
+      if (!VECTOR(*fixed)[i]) {
+        VECTOR(node_order)[j] = i;
+        j++;
+      }
+    }
+  } else {
+    IGRAPH_CHECK(igraph_vector_init_seq(&node_order, 0, no_of_nodes-1));
+    IGRAPH_FINALLY(igraph_vector_destroy, &node_order);
+  }
+
+  running = 1;
+  while (running) {
+    long int v1, num_neis;
+    igraph_real_t max_count;
+    igraph_vector_int_t *neis;
+    igraph_vector_t *ineis;
+    igraph_bool_t was_zero;
+
+    running = 0;
+
+    /* Shuffle the node ordering vector */
+    IGRAPH_CHECK(igraph_vector_shuffle(&node_order));
+    /* In the prescribed order, loop over the vertices and reassign labels */
+    for (i=0; i<no_of_not_fixed_nodes; i++) {
+      v1 = (long int) VECTOR(node_order)[i];
+
+      /* Count the weights corresponding to different labels */
+      igraph_vector_clear(&dominant_labels);
+      igraph_vector_clear(&nonzero_labels);
+      max_count = 0.0;
+      if (weights) {
+        ineis = igraph_inclist_get(&il, v1);
+        num_neis = igraph_vector_size(ineis);
+        for (j=0; j<num_neis; j++) {
+          k = (long int) VECTOR(*membership)[
+		     (long)IGRAPH_OTHER(graph, VECTOR(*ineis)[j], v1) ];
+          if (k == 0)
+            continue;   /* skip if it has no label yet */
+          was_zero = (VECTOR(label_counters)[k] == 0);
+          VECTOR(label_counters)[k] += VECTOR(*weights)[(long)VECTOR(*ineis)[j]];
+          if (was_zero && VECTOR(label_counters)[k] != 0) {
+            /* counter just became nonzero */
+            IGRAPH_CHECK(igraph_vector_push_back(&nonzero_labels, k));
+          }
+          if (max_count < VECTOR(label_counters)[k]) {
+            max_count = VECTOR(label_counters)[k];
+            IGRAPH_CHECK(igraph_vector_resize(&dominant_labels, 1));
+            VECTOR(dominant_labels)[0] = k;
+          } else if (max_count == VECTOR(label_counters)[k]) {
+            IGRAPH_CHECK(igraph_vector_push_back(&dominant_labels, k));
+          }
+        }
+      } else {
+        neis = igraph_adjlist_get(&al, v1);
+        num_neis = igraph_vector_int_size(neis);
+        for (j=0; j<num_neis; j++) {
+          k = (long int) VECTOR(*membership)[(long)VECTOR(*neis)[j]];
+          if (k == 0)
+            continue;   /* skip if it has no label yet */
+          VECTOR(label_counters)[k]++;
+          if (VECTOR(label_counters)[k] == 1) {
+            /* counter just became nonzero */
+            IGRAPH_CHECK(igraph_vector_push_back(&nonzero_labels, k));
+          }
+          if (max_count < VECTOR(label_counters)[k]) {
+            max_count = VECTOR(label_counters)[k];
+            IGRAPH_CHECK(igraph_vector_resize(&dominant_labels, 1));
+            VECTOR(dominant_labels)[0] = k;
+          } else if (max_count == VECTOR(label_counters)[k]) {
+            IGRAPH_CHECK(igraph_vector_push_back(&dominant_labels, k));
+          }
+        }
+      }
+
+      if (igraph_vector_size(&dominant_labels) > 0) {
+        /* Select randomly from the dominant labels */
+        k = RNG_INTEGER(0, igraph_vector_size(&dominant_labels)-1); 
+        k = (long int) VECTOR(dominant_labels)[k];
+        /* Check if the _current_ label of the node is also dominant */
+        if (VECTOR(label_counters)[(long)VECTOR(*membership)[v1]]!=max_count) {
+          /* Nope, we need at least one more iteration */
+          running = 1;
+        }
+        VECTOR(*membership)[v1] = k;
+      }
+
+      /* Clear the nonzero elements in label_counters */
+      num_neis = igraph_vector_size(&nonzero_labels);
+      for (j = 0; j < num_neis; j++) {
+        VECTOR(label_counters)[(long int)VECTOR(nonzero_labels)[j]] = 0;
+      }
+    }
+  }
+
+  RNG_END();
+
+  /* Shift back the membership vector, permute labels in increasing order */
+  /* We recycle label_counters here :) */
+  igraph_vector_fill(&label_counters, -1);
+  j = 0;
+  for (i=0; i<no_of_nodes; i++) {
+    k = (long)VECTOR(*membership)[i]-1;
+    if (k >= 0) {
+      if (VECTOR(label_counters)[k] == -1) {
+        /* We have seen this label for the first time */
+        VECTOR(label_counters)[k] = j;
+        k = j;
+        j++;
+      } else {
+        k = (long int) VECTOR(label_counters)[k];
+      }
+    } else {
+      /* This is an unlabeled vertex */
+    }
+    VECTOR(*membership)[i] = k;
+  }
+
+  if (weights)
+    igraph_inclist_destroy(&il);
+  else
+    igraph_adjlist_destroy(&al);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  if (modularity) {
+    IGRAPH_CHECK(igraph_modularity(graph, membership, modularity,
+				   weights));
+  }
+
+  igraph_vector_destroy(&node_order);
+  igraph_vector_destroy(&label_counters);
+  igraph_vector_destroy(&dominant_labels);
+  igraph_vector_destroy(&nonzero_labels);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/********************************************************************/
+
+/* Structure storing a community */
+typedef struct {
+  igraph_integer_t size;           /* Size of the community */
+  igraph_real_t weight_inside;     /* Sum of edge weights inside community */
+  igraph_real_t weight_all;        /* Sum of edge weights starting/ending
+                                      in the community */
+} igraph_i_multilevel_community;
+
+/* Global community list structure */
+typedef struct {
+  long int communities_no, vertices_no;  /* Number of communities, number of vertices */
+  igraph_real_t weight_sum;              /* Sum of edges weight in the whole graph */
+  igraph_i_multilevel_community *item;   /* List of communities */
+  igraph_vector_t *membership;           /* Community IDs */
+  igraph_vector_t *weights;        /* Graph edge weights */
+} igraph_i_multilevel_community_list;
+
+/* Computes the modularity of a community partitioning */
+igraph_real_t igraph_i_multilevel_community_modularity(
+  const igraph_i_multilevel_community_list *communities) {
+  igraph_real_t result = 0;
+  long int i;
+  igraph_real_t m = communities->weight_sum;
+  
+  for (i = 0; i < communities->vertices_no; i++) {
+    if (communities->item[i].size > 0) {
+      result += (communities->item[i].weight_inside - communities->item[i].weight_all*communities->item[i].weight_all/m)/m;
+    } 
+  }
+
+  return result;
+}
+
+typedef struct {
+  long int from;
+  long int to;
+  long int id;
+} igraph_i_multilevel_link;
+
+int igraph_i_multilevel_link_cmp(const void *a, const void *b)
+{
+  long int r = (((igraph_i_multilevel_link*)a)->from -
+                ((igraph_i_multilevel_link*)b)->from);
+  if (r != 0) return (int) r;
+  
+  return (int) (((igraph_i_multilevel_link*)a)->to -
+		((igraph_i_multilevel_link*)b)->to);
+}
+
+/* removes multiple edges and returns new edge id's for each edge in |E|log|E| */
+int igraph_i_multilevel_simplify_multiple(igraph_t *graph, igraph_vector_t *eids) {
+  long int ecount = igraph_ecount(graph);
+  long int i, l = -1, last_from = -1, last_to = -1;
+  igraph_bool_t directed = igraph_is_directed(graph);
+  igraph_integer_t from, to;
+  igraph_vector_t edges;
+  igraph_i_multilevel_link *links;
+
+  /* Make sure there's enough space in eids to store the new edge IDs */
+  IGRAPH_CHECK(igraph_vector_resize(eids, ecount));
+
+  links = igraph_Calloc(ecount, igraph_i_multilevel_link);
+  if (links == 0) {
+    IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, links);
+
+  for (i = 0; i < ecount; i++) {
+    igraph_edge(graph, (igraph_integer_t) i, &from, &to);
+    links[i].from = from;
+    links[i].to = to;
+    links[i].id = i;
+  }  
+
+  qsort((void*)links, (size_t) ecount, sizeof(igraph_i_multilevel_link),
+      igraph_i_multilevel_link_cmp);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  for (i = 0; i < ecount; i++) {
+    if (links[i].from == last_from && links[i].to == last_to) {
+      VECTOR(*eids)[links[i].id] = l;
+      continue;
+    }
+
+    last_from = links[i].from;
+    last_to = links[i].to;
+
+    igraph_vector_push_back(&edges, last_from);
+    igraph_vector_push_back(&edges, last_to);
+
+    l++;
+
+    VECTOR(*eids)[links[i].id] = l;
+  }
+
+  free(links);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_destroy(graph);
+  IGRAPH_CHECK(igraph_create(graph, &edges, igraph_vcount(graph), directed));
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+typedef struct {
+  long int community;
+  igraph_real_t weight;
+} igraph_i_multilevel_community_link;
+
+int igraph_i_multilevel_community_link_cmp(const void *a, const void *b)
+{
+  return (int) (((igraph_i_multilevel_community_link*)a)->community -
+		((igraph_i_multilevel_community_link*)b)->community);
+}
+
+/**
+ * Given a graph, a community structure and a vertex ID, this method
+ * calculates:
+ *
+ * - edges: the list of edge IDs that are incident on the vertex
+ * - weight_all: the total weight of these edges
+ * - weight_inside: the total weight of edges that stay within the same
+ *   community where the given vertex is right now, excluding loop edges
+ * - weight_loop: the total weight of loop edges
+ * - links_community and links_weight: together these two vectors list the
+ *   communities incident on this vertex and the total weight of edges
+ *   pointing to these communities
+ */
+int igraph_i_multilevel_community_links(const igraph_t *graph,
+  const igraph_i_multilevel_community_list *communities,
+  igraph_integer_t vertex, igraph_vector_t *edges,
+  igraph_real_t *weight_all, igraph_real_t *weight_inside, igraph_real_t *weight_loop,
+  igraph_vector_t *links_community, igraph_vector_t *links_weight) {
+  
+  long int i, n, last = -1, c = -1;
+  igraph_real_t weight = 1;
+  long int to, to_community;
+  long int community = (long int) VECTOR(*(communities->membership))[(long int)vertex];
+  igraph_i_multilevel_community_link *links;
+
+  *weight_all = *weight_inside = *weight_loop = 0;
+
+  igraph_vector_clear(links_community);
+  igraph_vector_clear(links_weight);
+
+  /* Get the list of incident edges */
+  igraph_incident(graph, edges, vertex, IGRAPH_ALL);
+
+  n = igraph_vector_size(edges);
+  links = igraph_Calloc(n, igraph_i_multilevel_community_link);
+  if (links == 0) {
+    IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, links);
+
+  for (i = 0; i < n; i++) {
+    long int eidx = (long int) VECTOR(*edges)[i];
+    weight = VECTOR(*communities->weights)[eidx];
+
+    to = IGRAPH_OTHER(graph, eidx, vertex);
+
+    *weight_all += weight;
+    if (to == vertex) {
+      *weight_loop += weight;
+      
+      links[i].community = community;
+      links[i].weight = 0;
+      continue;
+    }
+
+    to_community = (long int)VECTOR(*(communities->membership))[to];
+    if (community == to_community)
+      *weight_inside += weight;
+
+    /* debug("Link %ld (C: %ld) <-> %ld (C: %ld)\n", vertex, community, to, to_community); */
+    
+    links[i].community = to_community;
+    links[i].weight = weight;
+  }
+
+  /* Sort links by community ID and merge the same */
+  qsort((void*)links, (size_t) n, sizeof(igraph_i_multilevel_community_link),
+      igraph_i_multilevel_community_link_cmp);
+  for (i = 0; i < n; i++) {
+    to_community = links[i].community;
+    if (to_community != last) {
+      igraph_vector_push_back(links_community, to_community);
+      igraph_vector_push_back(links_weight, links[i].weight);
+      last = to_community;
+      c++;
+    } else {    
+      VECTOR(*links_weight)[c] += links[i].weight;
+    }
+  }
+
+  igraph_free(links);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+igraph_real_t igraph_i_multilevel_community_modularity_gain(
+  const igraph_i_multilevel_community_list *communities,
+  igraph_integer_t community, igraph_integer_t vertex,
+  igraph_real_t weight_all, igraph_real_t weight_inside) {
+  IGRAPH_UNUSED(vertex);
+  return weight_inside -
+      communities->item[(long int)community].weight_all*weight_all/communities->weight_sum;
+}
+
+/* Shrinks communities into single vertices, keeping all the edges.
+ * This method is internal because it destroys the graph in-place and
+ * creates a new one -- this is fine for the multilevel community
+ * detection where a copy of the original graph is used anyway.
+ * The membership vector will also be rewritten by the underlying
+ * igraph_membership_reindex call */
+int igraph_i_multilevel_shrink(igraph_t *graph, igraph_vector_t *membership) {
+  igraph_vector_t edges;
+  long int no_of_nodes = igraph_vcount(graph);
+  long int no_of_edges = igraph_ecount(graph);
+  igraph_bool_t directed = igraph_is_directed(graph);
+
+  long int i;
+  igraph_eit_t eit;
+
+  if (no_of_nodes == 0)
+    return 0;
+
+  if (igraph_vector_size(membership) < no_of_nodes) {
+    IGRAPH_ERROR("cannot shrink graph, membership vector too short",
+        IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2);
+
+  IGRAPH_CHECK(igraph_reindex_membership(membership, 0));
+
+  /* Create the new edgelist */
+  igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &eit);
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+  i = 0;
+  while (!IGRAPH_EIT_END(eit)) {
+    igraph_integer_t from, to;
+    IGRAPH_CHECK(igraph_edge(graph, IGRAPH_EIT_GET(eit), &from, &to));
+    VECTOR(edges)[i++] = VECTOR(*membership)[(long int) from];
+    VECTOR(edges)[i++] = VECTOR(*membership)[(long int) to];
+    IGRAPH_EIT_NEXT(eit);
+  }
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Create the new graph */
+  igraph_destroy(graph);
+  no_of_nodes = (long int) igraph_vector_max(membership)+1;
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \ingroup communities
+ * \function igraph_i_community_multilevel_step
+ * \brief Performs a single step of the multi-level modularity optimization method
+ *
+ * This function implements a single step of 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, http://arxiv.org/abs/0803.0476 for the details.
+ *
+ * This function was contributed by Tom Gregorovic.
+ *
+ * \param graph   The input graph. It must be an undirected graph.
+ * \param weights Numeric vector containing edge weights. If \c NULL, every edge
+ *     has equal weight. The weights are expected to be non-negative.
+ * \param membership The membership vector, the result is returned here.
+ *     For each vertex it gives the ID of its community.
+ * \param modularity The modularity of the partition is returned here.
+ *     \c NULL means that the modularity is not needed.
+ * \return Error code.
+ *
+ * Time complexity: in average near linear on sparse graphs.
+ */
+int igraph_i_community_multilevel_step(igraph_t *graph,
+  igraph_vector_t *weights, igraph_vector_t *membership,
+  igraph_real_t *modularity) {
+  
+  long int i, j;
+  long int vcount = igraph_vcount(graph);
+  long int ecount = igraph_ecount(graph);
+  igraph_integer_t ffrom, fto;
+  igraph_real_t q, pass_q;
+  int pass;
+  igraph_bool_t changed = 0;
+  igraph_vector_t links_community;
+  igraph_vector_t links_weight;
+  igraph_vector_t edges;
+  igraph_vector_t temp_membership;
+  igraph_i_multilevel_community_list communities;
+
+  /* Initial sanity checks on the input parameters */
+  if (igraph_is_directed(graph)) {
+    IGRAPH_ERROR("multi-level community detection works for undirected graphs only",
+        IGRAPH_UNIMPLEMENTED);
+  }
+  if (igraph_vector_size(weights) < igraph_ecount(graph))
+    IGRAPH_ERROR("multi-level community detection: weight vector too short", IGRAPH_EINVAL);
+  if (igraph_vector_any_smaller(weights, 0))
+    IGRAPH_ERROR("weights must be positive", IGRAPH_EINVAL);
+
+  /* Initialize data structures */
+  IGRAPH_VECTOR_INIT_FINALLY(&links_community, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&links_weight, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&temp_membership, vcount);
+  IGRAPH_CHECK(igraph_vector_resize(membership, vcount));
+ 
+  /* Initialize list of communities from graph vertices */
+  communities.vertices_no = vcount;
+  communities.communities_no = vcount;
+  communities.weights = weights;
+  communities.weight_sum = 2 * igraph_vector_sum(weights);
+  communities.membership = membership;
+  communities.item = igraph_Calloc(vcount, igraph_i_multilevel_community);
+  if (communities.item == 0) {
+    IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, communities.item);
+
+  /* Still initializing the communities data structure */
+  for (i=0; i < vcount; i++) {
+    VECTOR(*communities.membership)[i] = i;
+    communities.item[i].size = 1;
+    communities.item[i].weight_inside = 0;
+    communities.item[i].weight_all = 0;
+  }
+
+  /* Some more initialization :) */
+  for (i = 0; i < ecount; i++) {
+    igraph_real_t weight = 1;
+    igraph_edge(graph, (igraph_integer_t) i, &ffrom, &fto);
+
+    weight = VECTOR(*weights)[i];
+    communities.item[(long int) ffrom].weight_all += weight;
+    communities.item[(long int) fto].weight_all += weight;
+    if (ffrom == fto)
+      communities.item[(long int) ffrom].weight_inside += 2*weight;
+  }
+
+  q = igraph_i_multilevel_community_modularity(&communities);
+  pass = 1;
+
+  do { /* Pass begin */
+    long int temp_communities_no = communities.communities_no;
+
+    pass_q = q;
+    changed = 0;
+    
+    /* Save the current membership, it will be restored in case of worse result */
+    IGRAPH_CHECK(igraph_vector_update(&temp_membership, communities.membership));
+
+    for (i = 0; i < vcount; i++) {
+      /* Exclude vertex from its current community */
+      igraph_real_t weight_all = 0;
+      igraph_real_t weight_inside = 0;
+      igraph_real_t weight_loop = 0;
+      igraph_real_t max_q_gain = 0;
+      igraph_real_t max_weight;
+      long int old_id, new_id, n;
+
+      igraph_i_multilevel_community_links(graph, &communities, 
+					  (igraph_integer_t) i, &edges,
+					  &weight_all, &weight_inside, 
+					  &weight_loop, &links_community,
+					  &links_weight);
+
+      old_id = (long int)VECTOR(*(communities.membership))[i];
+      new_id = old_id;
+
+      /* Update old community */
+      igraph_vector_set(communities.membership, i, -1);
+      communities.item[old_id].size--;
+      if (communities.item[old_id].size == 0) {communities.communities_no--;}
+      communities.item[old_id].weight_all -= weight_all;
+      communities.item[old_id].weight_inside -= 2*weight_inside + weight_loop;
+
+      /* debug("Remove %ld all: %lf Inside: %lf\n", i, -weight_all, -2*weight_inside + weight_loop); */
+
+      /* Find new community to join with the best modification gain */
+      max_q_gain = 0;
+      max_weight = weight_inside;
+      n = igraph_vector_size(&links_community);
+
+      for (j = 0; j < n; j++) {
+        long int c = (long int) VECTOR(links_community)[j];
+        igraph_real_t w = VECTOR(links_weight)[j];
+
+        igraph_real_t q_gain = 
+	  igraph_i_multilevel_community_modularity_gain(&communities, 
+							(igraph_integer_t) c, 
+							(igraph_integer_t) i,
+							weight_all, w);
+        /* debug("Link %ld -> %ld weight: %lf gain: %lf\n", i, c, (double) w, (double) q_gain); */
+        if (q_gain > max_q_gain) {
+          new_id = c;
+          max_q_gain = q_gain;
+          max_weight = w;
+        }
+      }
+
+      /* debug("Added vertex %ld to community %ld (gain %lf).\n", i, new_id, (double) max_q_gain); */
+
+      /* Add vertex to "new" community and update it */
+      igraph_vector_set(communities.membership, i, new_id);
+      if (communities.item[new_id].size == 0) {communities.communities_no++;}
+      communities.item[new_id].size++;
+      communities.item[new_id].weight_all += weight_all;
+      communities.item[new_id].weight_inside += 2*max_weight + weight_loop;
+
+      if (new_id != old_id) {
+        changed++;
+      }
+    }
+
+    q = igraph_i_multilevel_community_modularity(&communities);
+
+    if (changed && (q > pass_q)) { 
+      /* debug("Pass %d (changed: %d) Communities: %ld Modularity from %lf to %lf\n",
+        pass, changed, communities.communities_no, (double) pass_q, (double) q); */
+      pass++;
+    } else {
+      /* No changes or the modularity became worse, restore last membership */
+      IGRAPH_CHECK(igraph_vector_update(communities.membership, &temp_membership));
+      communities.communities_no = temp_communities_no;
+      break;
+    }
+
+    IGRAPH_ALLOW_INTERRUPTION();
+  } while (changed && (q > pass_q)); /* Pass end */
+
+  if (modularity) {
+    *modularity = q;
+  }
+
+  /* debug("Result Communities: %ld Modularity: %lf\n",
+    communities.communities_no, (double) q); */
+
+  IGRAPH_CHECK(igraph_reindex_membership(membership, 0));
+
+  /* Shrink the nodes of the graph according to the present community structure
+   * and simplify the resulting graph */
+
+  /* TODO: check if we really need to copy temp_membership */
+  IGRAPH_CHECK(igraph_vector_update(&temp_membership, membership));
+  IGRAPH_CHECK(igraph_i_multilevel_shrink(graph, &temp_membership));
+  igraph_vector_destroy(&temp_membership);
+  IGRAPH_FINALLY_CLEAN(1);  
+  
+  /* Update edge weights after shrinking and simplification */
+  /* Here we reuse the edges vector as we don't need the previous contents anymore */
+  /* TODO: can we use igraph_simplify here? */
+  IGRAPH_CHECK(igraph_i_multilevel_simplify_multiple(graph, &edges));
+
+  /* We reuse the links_weight vector to store the old edge weights */
+  IGRAPH_CHECK(igraph_vector_update(&links_weight, weights));
+  igraph_vector_fill(weights, 0);
+   
+  for (i = 0; i < ecount; i++) {
+    VECTOR(*weights)[(long int)VECTOR(edges)[i]] += VECTOR(links_weight)[i];
+  }
+
+  igraph_free(communities.item);
+  igraph_vector_destroy(&links_community);
+  igraph_vector_destroy(&links_weight);
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(4);
+  
+  return 0;
+}
+
+/**
+ * \ingroup communities
+ * \function igraph_community_multilevel
+ * \brief Finding community structure by multi-level optimization of modularity
+ * 
+ * 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, J Stat Mech P10008 (2008)
+ * for the details (preprint: http://arxiv.org/abs/arXiv:0803.0476).
+ *
+ * It is based on the modularity measure and a hierarchical 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.
+ *
+ * \param graph The input graph. It must be an undirected graph.
+ * \param weights Numeric vector containing edge weights. If \c NULL, every edge
+ *    has equal weight. The weights are expected to be non-negative.
+ * \param membership The membership vector, the result is returned here.
+ *    For each vertex it gives the ID of its community. The vector
+ *    must be initialized and it will be resized accordingly.
+ * \param memberships Numeric matrix that will contain the membership
+ *     vector after each level, if not \c NULL. It must be initialized and
+ *     it will be resized accordingly.
+ * \param modularity Numeric vector that will contain the modularity score
+ *     after each level, if not \c NULL. It must be initialized and it
+ *     will be resized accordingly.
+ * \return Error code.
+ *
+ * Time complexity: in average near linear on sparse graphs.
+ * 
+ * \example examples/simple/igraph_community_multilevel.c
+ */
+
+int igraph_community_multilevel(const igraph_t *graph,
+  const igraph_vector_t *weights, igraph_vector_t *membership,
+  igraph_matrix_t *memberships, igraph_vector_t *modularity) {
+ 
+  igraph_t g;
+  igraph_vector_t w, m, level_membership;
+  igraph_real_t prev_q = -1, q = -1;
+  int i, level = 1;
+  long int vcount = igraph_vcount(graph);
+
+  /* Make a copy of the original graph, we will do the merges on the copy */
+  IGRAPH_CHECK(igraph_copy(&g, graph));
+  IGRAPH_FINALLY(igraph_destroy, &g);
+
+  if (weights) {
+    IGRAPH_CHECK(igraph_vector_copy(&w, weights));   
+    IGRAPH_FINALLY(igraph_vector_destroy, &w);  
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&w, igraph_ecount(&g));
+    igraph_vector_fill(&w, 1);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&m, vcount);
+  IGRAPH_VECTOR_INIT_FINALLY(&level_membership, vcount);
+
+  if (memberships || membership) {
+    /* Put each vertex in its own community */
+    for (i = 0; i < vcount; i++) {
+      VECTOR(level_membership)[i] = i;
+    }
+  }
+  if (memberships) {
+    /* Resize the membership matrix to have vcount columns and no rows */
+    IGRAPH_CHECK(igraph_matrix_resize(memberships, 0, vcount));
+  }
+  if (modularity) {
+    /* Clear the modularity vector */
+    igraph_vector_clear(modularity);
+  }
+  
+  while (1) {
+    /* Remember the previous modularity and vertex count, do a single step */
+    igraph_integer_t step_vcount = igraph_vcount(&g);
+
+    prev_q = q;
+    IGRAPH_CHECK(igraph_i_community_multilevel_step(&g, &w, &m, &q));
+
+    /* Were there any merges? If not, we have to stop the process */
+    if (igraph_vcount(&g) == step_vcount || q < prev_q)
+      break;
+
+    if (memberships || membership) {
+      for (i = 0; i < vcount; i++) {
+        /* Readjust the membership vector */
+        VECTOR(level_membership)[i] = VECTOR(m)[(long int) VECTOR(level_membership)[i]];
+      }
+    }
+
+    if (modularity) {
+      /* If we have to return the modularity scores, add it to the modularity vector */
+      IGRAPH_CHECK(igraph_vector_push_back(modularity, q));
+    }
+
+    if (memberships) {
+      /* If we have to return the membership vectors at each level, store the new
+       * membership vector */
+      IGRAPH_CHECK(igraph_matrix_add_rows(memberships, 1));
+      IGRAPH_CHECK(igraph_matrix_set_row(memberships, &level_membership, level - 1));
+    }
+
+    /* debug("Level: %d Communities: %ld Modularity: %f\n", level, (long int) igraph_vcount(&g),
+      (double) q); */
+
+    /* Increase the level counter */
+    level++;
+  }
+
+  /* It might happen that there are no merges, so every vertex is in its 
+     own community. We still might want the modularity score for that. */
+  if (modularity && igraph_vector_size(modularity) == 0) {
+    igraph_vector_t tmp;
+    igraph_real_t mod;
+    int i;
+    IGRAPH_VECTOR_INIT_FINALLY(&tmp, vcount);
+    for (i=0; i<vcount; i++) { VECTOR(tmp)[i]=i; }
+    IGRAPH_CHECK(igraph_modularity(graph, &tmp, &mod, weights));
+    igraph_vector_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_CHECK(igraph_vector_resize(modularity, 1));
+    VECTOR(*modularity)[0]=mod;
+  }
+
+  /* If we need the final membership vector, copy it to the output */
+  if (membership) {
+    IGRAPH_CHECK(igraph_vector_resize(membership, vcount));   
+    for (i = 0; i < vcount; i++) {
+      VECTOR(*membership)[i] = VECTOR(level_membership)[i];
+    }
+  }
+
+  /* Destroy the copy of the graph */
+  igraph_destroy(&g);
+
+  /* Destroy the temporary vectors */
+  igraph_vector_destroy(&m);
+  igraph_vector_destroy(&w);
+  igraph_vector_destroy(&level_membership);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+
+int igraph_i_compare_communities_vi(const igraph_vector_t *v1,
+    const igraph_vector_t *v2, igraph_real_t* result);
+int igraph_i_compare_communities_nmi(const igraph_vector_t *v1,
+    const igraph_vector_t *v2, igraph_real_t* result);
+int igraph_i_compare_communities_rand(const igraph_vector_t *v1,
+    const igraph_vector_t *v2, igraph_real_t* result, igraph_bool_t adjust);
+int igraph_i_split_join_distance(const igraph_vector_t *v1,
+    const igraph_vector_t *v2, igraph_integer_t* distance12,
+    igraph_integer_t* distance21);
+
+/**
+ * \ingroup communities
+ * \function igraph_compare_communities
+ * \brief Compares community structures using various metrics
+ *
+ * This function assesses the distance between two community structures
+ * using the variation of information (VI) metric of Meila (2003), the
+ * normalized mutual information (NMI) of Danon et al (2005), the
+ * split-join distance of van Dongen (2000), the Rand index of Rand (1971)
+ * or the adjusted Rand index of Hubert and Arabie (1985).
+ *
+ * </para><para>
+ * References:
+ *
+ * </para><para>
+ * Meila M: Comparing clusterings by the variation of information.
+ * In: Schölkopf B, Warmuth MK (eds.). 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.
+ *
+ * </para><para>
+ * Danon L, Diaz-Guilera A, Duch J, Arenas A: Comparing community structure
+ * identification. J Stat Mech P09008, 2005.
+ *
+ * </para><para>
+ * 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.
+ * 
+ * </para><para>
+ * Rand WM: Objective criteria for the evaluation of clustering methods.
+ * J Am Stat Assoc 66(336):846-850, 1971.
+ *
+ * </para><para>
+ * Hubert L and Arabie P: Comparing partitions. Journal of Classification
+ * 2:193-218, 1985.
+ *
+ * \param  comm1   the membership vector of the first community structure
+ * \param  comm2   the membership vector of the second community structure
+ * \param  result  the result is stored here.
+ * \param  method  the comparison method to use. \c IGRAPH_COMMCMP_VI
+ *                 selects the variation of information (VI) metric of
+ *                 Meila (2003), \c IGRAPH_COMMCMP_NMI selects the
+ *                 normalized mutual information measure proposed by
+ *                 Danon et al (2005), \c IGRAPH_COMMCMP_SPLIT_JOIN
+ *                 selects the split-join distance of van Dongen (2000),
+ *                 \c IGRAPH_COMMCMP_RAND selects the unadjusted Rand
+ *                 index (1971) and \c IGRAPH_COMMCMP_ADJUSTED_RAND
+ *                 selects the adjusted Rand index.
+ *
+ * \return  Error code.
+ *
+ * Time complexity: O(n log(n)).
+ */
+int igraph_compare_communities(const igraph_vector_t *comm1,
+    const igraph_vector_t *comm2, igraph_real_t* result,
+    igraph_community_comparison_t method) {
+  igraph_vector_t c1, c2;
+
+  if (igraph_vector_size(comm1) != igraph_vector_size(comm2)) {
+    IGRAPH_ERROR("community membership vectors have different lengths", IGRAPH_EINVAL);
+  }
+
+  /* Copy and reindex membership vectors to make sure they are continuous */
+  IGRAPH_CHECK(igraph_vector_copy(&c1, comm1));
+  IGRAPH_FINALLY(igraph_vector_destroy, &c1);
+
+  IGRAPH_CHECK(igraph_vector_copy(&c2, comm2));
+  IGRAPH_FINALLY(igraph_vector_destroy, &c2);
+
+  IGRAPH_CHECK(igraph_reindex_membership(&c1, 0));
+  IGRAPH_CHECK(igraph_reindex_membership(&c2, 0));
+
+  switch (method) {
+    case IGRAPH_COMMCMP_VI:
+      IGRAPH_CHECK(igraph_i_compare_communities_vi(&c1, &c2, result));
+      break;
+
+    case IGRAPH_COMMCMP_NMI:
+      IGRAPH_CHECK(igraph_i_compare_communities_nmi(&c1, &c2, result));
+      break;
+
+    case IGRAPH_COMMCMP_SPLIT_JOIN:
+      {
+        igraph_integer_t d12, d21;
+        IGRAPH_CHECK(igraph_i_split_join_distance(&c1, &c2, &d12, &d21));
+        *result = d12 + d21;
+      }
+      break;
+
+    case IGRAPH_COMMCMP_RAND:
+    case IGRAPH_COMMCMP_ADJUSTED_RAND:
+      IGRAPH_CHECK(igraph_i_compare_communities_rand(&c1, &c2, result,
+            method == IGRAPH_COMMCMP_ADJUSTED_RAND));
+      break;
+
+    default:
+      IGRAPH_ERROR("unknown community comparison method", IGRAPH_EINVAL);
+  }
+
+  /* Clean up everything */
+  igraph_vector_destroy(&c1);
+  igraph_vector_destroy(&c2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \ingroup communities
+ * \function igraph_split_join_distance
+ * \brief Calculates the 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:
+ *
+ * </para><para>
+ * 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.
+ *
+ * </para><para>
+ * The split-join distance will be returned in two arguments, \c distance12
+ * will contain the projection distance of the first partition from the
+ * second, while \c distance21 will be 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.
+ *
+ * </para><para>
+ * Reference:
+ *
+ * </para><para>
+ * 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.
+ * 
+ * \param  comm1       the membership vector of the first community structure
+ * \param  comm2       the membership vector of the second community structure
+ * \param  distance12  pointer to an \c igraph_integer_t, the projection distance
+ *                     of the first community structure from the second one will be
+ *                     returned here.
+ * \param  distance21  pointer to an \c igraph_integer_t, the projection distance
+ *                     of the second community structure from the first one will be
+ *                     returned here.
+ * \return  Error code.
+ *
+ * \see \ref igraph_compare_communities() with the \c IGRAPH_COMMCMP_SPLIT_JOIN
+ * method if you are not interested in the individual distances but only the sum
+ * of them.
+ *
+ * Time complexity: O(n log(n)).
+ */
+int igraph_split_join_distance(const igraph_vector_t *comm1,
+    const igraph_vector_t *comm2, igraph_integer_t *distance12,
+    igraph_integer_t *distance21) {
+  igraph_vector_t c1, c2;
+
+  if (igraph_vector_size(comm1) != igraph_vector_size(comm2)) {
+    IGRAPH_ERROR("community membership vectors have different lengths", IGRAPH_EINVAL);
+  }
+
+  /* Copy and reindex membership vectors to make sure they are continuous */
+  IGRAPH_CHECK(igraph_vector_copy(&c1, comm1));
+  IGRAPH_FINALLY(igraph_vector_destroy, &c1);
+
+  IGRAPH_CHECK(igraph_vector_copy(&c2, comm2));
+  IGRAPH_FINALLY(igraph_vector_destroy, &c2);
+
+  IGRAPH_CHECK(igraph_reindex_membership(&c1, 0));
+  IGRAPH_CHECK(igraph_reindex_membership(&c2, 0));
+
+  IGRAPH_CHECK(igraph_i_split_join_distance(&c1, &c2, distance12, distance21));
+
+  /* Clean up everything */
+  igraph_vector_destroy(&c1);
+  igraph_vector_destroy(&c2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * Calculates the entropy and the mutual information for two reindexed community
+ * membership vectors v1 and v2. This is needed by both Meila's and Danon's
+ * community comparison measure.
+ */
+int igraph_i_entropy_and_mutual_information(const igraph_vector_t* v1,
+    const igraph_vector_t* v2, double* h1, double* h2, double* mut_inf) {
+  long int i, n = igraph_vector_size(v1);
+  long int k1 = (long int)igraph_vector_max(v1)+1;
+  long int k2 = (long int)igraph_vector_max(v2)+1;
+  double *p1, *p2;
+  igraph_spmatrix_t m;
+  igraph_spmatrix_iter_t mit;
+
+  p1 = igraph_Calloc(k1, double);
+  if (p1 == 0) {
+    IGRAPH_ERROR("igraph_i_entropy_and_mutual_information failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, p1);
+  p2 = igraph_Calloc(k2, double);
+  if (p2 == 0) {
+    IGRAPH_ERROR("igraph_i_entropy_and_mutual_information failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, p2);
+
+  /* Calculate the entropy of v1 */
+  *h1 = 0.0;
+  for (i = 0; i < n; i++)
+    p1[(long int)VECTOR(*v1)[i]]++;
+  for (i = 0; i < k1; i++) {
+    p1[i] /= n;
+    *h1 -= p1[i] * log(p1[i]);
+  }
+
+  /* Calculate the entropy of v2 */
+  *h2 = 0.0;
+  for (i = 0; i < n; i++)
+    p2[(long int)VECTOR(*v2)[i]]++;
+  for (i = 0; i < k2; i++) {
+    p2[i] /= n;
+    *h2 -= p2[i] * log(p2[i]);
+  }
+
+  /* We will only need the logs of p1 and p2 from now on */
+  for (i = 0; i < k1; i++) {
+    p1[i] = log(p1[i]);
+  }
+  for (i = 0; i < k2; i++) {
+    p2[i] = log(p2[i]);
+  }
+
+  /* Calculate the mutual information of v1 and v2 */
+  *mut_inf = 0.0;
+  IGRAPH_CHECK(igraph_spmatrix_init(&m, k1, k2));
+  IGRAPH_FINALLY(igraph_spmatrix_destroy, &m);
+  for (i = 0; i < n; i++) {
+    IGRAPH_CHECK(igraph_spmatrix_add_e(&m,
+          (int)VECTOR(*v1)[i], (int)VECTOR(*v2)[i], 1));
+  }
+  IGRAPH_CHECK(igraph_spmatrix_iter_create(&mit, &m));
+  IGRAPH_FINALLY(igraph_spmatrix_iter_destroy, &mit);
+  while (!igraph_spmatrix_iter_end(&mit)) {
+    double p = mit.value / n;
+    *mut_inf += p * (log(p) - p1[mit.ri] - p2[mit.ci]);
+    igraph_spmatrix_iter_next(&mit);
+  }
+
+  igraph_spmatrix_iter_destroy(&mit);
+  igraph_spmatrix_destroy(&m);
+  free(p1); free(p2);
+
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/**
+ * Implementation of the normalized mutual information (NMI) measure of
+ * Danon et al. This function assumes that the community membership
+ * vectors have already been normalized using igraph_reindex_communities().
+ *
+ * </para><para>
+ * Reference: Danon L, Diaz-Guilera A, Duch J, Arenas A: Comparing community
+ * structure identification. J Stat Mech P09008, 2005.
+ *
+ * </para><para>
+ * Time complexity: O(n log(n))
+ */
+int igraph_i_compare_communities_nmi(const igraph_vector_t *v1, const igraph_vector_t *v2,
+    igraph_real_t* result) {
+  double h1, h2, mut_inf;
+
+  IGRAPH_CHECK(igraph_i_entropy_and_mutual_information(v1, v2, &h1, &h2, &mut_inf));
+
+  if (h1 == 0 && h2 == 0)
+    *result = 1;
+  else
+    *result = 2 * mut_inf / (h1 + h2);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Implementation of the variation of information metric (VI) of
+ * Meila et al. This function assumes that the community membership
+ * vectors have already been normalized using igraph_reindex_communities().
+ *
+ * </para><para>
+ * Reference: Meila M: Comparing clusterings by the variation of information.
+ * In: Schölkopf B, Warmuth MK (eds.). 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.
+ *
+ * </para><para>
+ * Time complexity: O(n log(n))
+ */
+int igraph_i_compare_communities_vi(const igraph_vector_t *v1, const igraph_vector_t *v2,
+    igraph_real_t* result) {
+  double h1, h2, mut_inf;
+
+  IGRAPH_CHECK(igraph_i_entropy_and_mutual_information(v1, v2, &h1, &h2, &mut_inf));
+  *result = h1 + h2 - 2*mut_inf;
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \brief Calculates the confusion matrix for two clusterings.
+ *
+ * </para><para>
+ * This function assumes that the community membership vectors have already
+ * been normalized using igraph_reindex_communities().
+ *
+ * </para><para>
+ * Time complexity: O(n log(max(k1, k2))), where n is the number of vertices, k1
+ * and k2 are the number of clusters in each of the clusterings.
+ */
+int igraph_i_confusion_matrix(const igraph_vector_t *v1, const igraph_vector_t *v2,
+    igraph_spmatrix_t *m) {
+  long int k1 = (long int)igraph_vector_max(v1)+1;
+  long int k2 = (long int)igraph_vector_max(v2)+1;
+  long int i, n = igraph_vector_size(v1);
+
+  IGRAPH_CHECK(igraph_spmatrix_resize(m, k1, k2));
+  for (i = 0; i < n; i++) {
+    IGRAPH_CHECK(igraph_spmatrix_add_e(m,
+          (int)VECTOR(*v1)[i], (int)VECTOR(*v2)[i], 1));
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Implementation of the split-join distance of van Dongen.
+ *
+ * </para><para>
+ * This function assumes that the community membership vectors have already
+ * been normalized using igraph_reindex_communities().
+ *
+ * </para><para>
+ * Reference: 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.
+ *
+ * </para><para>
+ * Time complexity: O(n log(max(k1, k2))), where n is the number of vertices, k1
+ * and k2 are the number of clusters in each of the clusterings.
+ */
+int igraph_i_split_join_distance(const igraph_vector_t *v1, const igraph_vector_t *v2,
+    igraph_integer_t* distance12, igraph_integer_t* distance21) {
+  long int n = igraph_vector_size(v1);
+  igraph_vector_t rowmax, colmax;
+  igraph_spmatrix_t m;
+  igraph_spmatrix_iter_t mit;
+
+  /* Calculate the confusion matrix */
+  IGRAPH_CHECK(igraph_spmatrix_init(&m, 1, 1));
+  IGRAPH_FINALLY(igraph_spmatrix_destroy, &m);
+  IGRAPH_CHECK(igraph_i_confusion_matrix(v1, v2, &m));
+
+  /* Initialize vectors that will store the row/columnwise maxima */
+  IGRAPH_VECTOR_INIT_FINALLY(&rowmax, igraph_spmatrix_nrow(&m));
+  IGRAPH_VECTOR_INIT_FINALLY(&colmax, igraph_spmatrix_ncol(&m));
+
+  /* Find the row/columnwise maxima */
+  IGRAPH_CHECK(igraph_spmatrix_iter_create(&mit, &m));
+  IGRAPH_FINALLY(igraph_spmatrix_iter_destroy, &mit);
+  while (!igraph_spmatrix_iter_end(&mit)) {
+    if (mit.value > VECTOR(rowmax)[mit.ri])
+      VECTOR(rowmax)[mit.ri] = mit.value;
+    if (mit.value > VECTOR(colmax)[mit.ci])
+      VECTOR(colmax)[mit.ci] = mit.value;
+    igraph_spmatrix_iter_next(&mit);
+  }
+  igraph_spmatrix_iter_destroy(&mit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Calculate the distances */
+  *distance12 = (igraph_integer_t) (n - igraph_vector_sum(&rowmax));
+  *distance21 = (igraph_integer_t) (n - igraph_vector_sum(&colmax));
+
+  igraph_vector_destroy(&rowmax);
+  igraph_vector_destroy(&colmax);
+  igraph_spmatrix_destroy(&m);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Implementation of the adjusted and unadjusted Rand indices.
+ *
+ * </para><para>
+ * This function assumes that the community membership vectors have already
+ * been normalized using igraph_reindex_communities().
+ *
+ * </para><para>
+ * References:
+ *
+ * </para><para>
+ * Rand WM: Objective criteria for the evaluation of clustering methods. J Am
+ * Stat Assoc 66(336):846-850, 1971.
+ *
+ * </para><para>
+ * Hubert L and Arabie P: Comparing partitions. Journal of Classification
+ * 2:193-218, 1985.
+ *
+ * </para><para>
+ * Time complexity: O(n log(max(k1, k2))), where n is the number of vertices, k1
+ * and k2 are the number of clusters in each of the clusterings.
+ */
+int igraph_i_compare_communities_rand(const igraph_vector_t *v1,
+    const igraph_vector_t *v2, igraph_real_t *result, igraph_bool_t adjust) {
+  igraph_spmatrix_t m;
+  igraph_spmatrix_iter_t mit;
+  igraph_vector_t rowsums, colsums;
+  long int i, nrow, ncol;
+  double rand, n;
+  double frac_pairs_in_1, frac_pairs_in_2;
+
+  /* Calculate the confusion matrix */
+  IGRAPH_CHECK(igraph_spmatrix_init(&m, 1, 1));
+  IGRAPH_FINALLY(igraph_spmatrix_destroy, &m);
+  IGRAPH_CHECK(igraph_i_confusion_matrix(v1, v2, &m));
+
+  /* The unadjusted Rand index is defined as (a+d) / (a+b+c+d), where:
+   *
+   * - a is the number of pairs in the same cluster both in v1 and v2. This
+   *   equals the sum of n(i,j) choose 2 for all i and j.
+   *
+   * - b is the number of pairs in the same cluster in v1 and in different
+   *   clusters in v2. This is sum n(i,*) choose 2 for all i minus a.
+   *   n(i,*) is the number of elements in cluster i in v1.
+   *
+   * - c is the number of pairs in the same cluster in v2 and in different
+   *   clusters in v1. This is sum n(*,j) choose 2 for all j minus a.
+   *   n(*,j) is the number of elements in cluster j in v2.
+   *
+   * - d is (n choose 2) - a - b - c.
+   *
+   * Therefore, a+d = (n choose 2) - b - c
+   *                = (n choose 2) - sum (n(i,*) choose 2)
+   *                               - sum (n(*,j) choose 2)
+   *                               + 2 * sum (n(i,j) choose 2).
+   *
+   * Since a+b+c+d = (n choose 2) and this goes in the denominator, we can
+   * just as well start dividing each term in a+d by (n choose 2), which
+   * yields:
+   *
+   * 1 - sum( n(i,*)/n * (n(i,*)-1)/(n-1) )
+   *   - sum( n(*,i)/n * (n(*,i)-1)/(n-1) )
+   *   + sum( n(i,j)/n * (n(i,j)-1)/(n-1) ) * 2
+   */
+
+  /* Calculate row and column sums */
+  nrow = igraph_spmatrix_nrow(&m);
+  ncol = igraph_spmatrix_ncol(&m);
+  n = igraph_vector_size(v1) + 0.0;
+  IGRAPH_VECTOR_INIT_FINALLY(&rowsums, nrow);
+  IGRAPH_VECTOR_INIT_FINALLY(&colsums, ncol);
+  IGRAPH_CHECK(igraph_spmatrix_rowsums(&m, &rowsums));
+  IGRAPH_CHECK(igraph_spmatrix_colsums(&m, &colsums));
+
+  /* Start calculating the unadjusted Rand index */
+  rand = 0.0;
+  IGRAPH_CHECK(igraph_spmatrix_iter_create(&mit, &m));
+  IGRAPH_FINALLY(igraph_spmatrix_iter_destroy, &mit);
+  while (!igraph_spmatrix_iter_end(&mit)) {
+    rand += (mit.value / n) * (mit.value-1) / (n-1);
+    igraph_spmatrix_iter_next(&mit);
+  }
+  igraph_spmatrix_iter_destroy(&mit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  frac_pairs_in_1 = frac_pairs_in_2 = 0.0;
+  for (i = 0; i < nrow; i++) {
+    frac_pairs_in_1 += (VECTOR(rowsums)[i] / n) * (VECTOR(rowsums)[i]-1) / (n-1);
+  }
+  for (i = 0; i < ncol; i++) {
+    frac_pairs_in_2 += (VECTOR(colsums)[i] / n) * (VECTOR(colsums)[i]-1) / (n-1);
+  }
+
+  rand = 1.0 + 2 * rand - frac_pairs_in_1 - frac_pairs_in_2;
+
+  if (adjust) {
+    double expected = frac_pairs_in_1 * frac_pairs_in_2 +
+                      (1-frac_pairs_in_1) * (1-frac_pairs_in_2);
+    rand = (rand - expected) / (1 - expected);
+  }
+
+  igraph_vector_destroy(&rowsums);
+  igraph_vector_destroy(&colsums);
+  igraph_spmatrix_destroy(&m);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  *result = rand;
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/src/complex.c b/src/complex.c
new file mode 100644
index 0000000..1a9c03b
--- /dev/null
+++ b/src/complex.c
@@ -0,0 +1,390 @@
+/* -*- 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_complex.h"
+#include "igraph_math.h"
+#include <math.h>
+
+/**
+ * \example igraph_complex.c
+ */
+
+igraph_complex_t igraph_complex(igraph_real_t x, igraph_real_t y) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = x;
+  IGRAPH_IMAG(res) = y;
+  return res;
+}
+
+igraph_complex_t igraph_complex_polar(igraph_real_t r, igraph_real_t theta) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = r * cos(theta);
+  IGRAPH_IMAG(res) = r * sin(theta);
+  return res;
+}
+
+igraph_bool_t igraph_complex_eq_tol(igraph_complex_t z1,
+				    igraph_complex_t z2, 
+				    igraph_real_t tol) {
+  if (fabs(IGRAPH_REAL(z1) - IGRAPH_REAL(z2)) > tol ||
+      fabs(IGRAPH_IMAG(z1) - IGRAPH_IMAG(z2)) > tol) {
+    return 0;
+  }
+  return 1;
+}
+
+igraph_real_t igraph_complex_mod(igraph_complex_t z) {
+  igraph_real_t x=IGRAPH_REAL(z);
+  igraph_real_t y=IGRAPH_IMAG(z);
+  return hypot(x,y);
+}
+
+igraph_real_t igraph_complex_arg(igraph_complex_t z) {
+  igraph_real_t x=IGRAPH_REAL(z);
+  igraph_real_t y=IGRAPH_IMAG(z);
+  if (x==0.0 && y==0.0) { return 0.0; }
+  return atan2(y,x);
+}
+
+igraph_complex_t igraph_complex_add(igraph_complex_t z1, 
+				    igraph_complex_t z2) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z1) + IGRAPH_REAL(z2);
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z1) + IGRAPH_IMAG(z2);
+  return res;
+}
+
+igraph_complex_t igraph_complex_sub(igraph_complex_t z1, 
+				    igraph_complex_t z2) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z1) - IGRAPH_REAL(z2);
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z1) - IGRAPH_IMAG(z2);
+  return res;
+}
+
+igraph_complex_t igraph_complex_mul(igraph_complex_t z1, 
+				    igraph_complex_t z2) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z1) * IGRAPH_REAL(z2) - 
+    IGRAPH_IMAG(z1) * IGRAPH_IMAG(z2);
+  IGRAPH_IMAG(res) = IGRAPH_REAL(z1) * IGRAPH_IMAG(z2) + 
+    IGRAPH_IMAG(z1) * IGRAPH_REAL(z2);
+  return res;
+}
+
+igraph_complex_t igraph_complex_div(igraph_complex_t z1,
+				    igraph_complex_t z2) {
+  igraph_complex_t res;
+  igraph_real_t z1r = IGRAPH_REAL(z1), z1i = IGRAPH_IMAG(z1);
+  igraph_real_t z2r = IGRAPH_REAL(z2), z2i = IGRAPH_IMAG(z2);
+  igraph_real_t s = 1.0 / igraph_complex_abs(z2);
+  igraph_real_t sz2r = s * z2r;
+  igraph_real_t sz2i = s * z2i;
+  IGRAPH_REAL(res) = (z1r * sz2r + z1i * sz2i) * s;
+  IGRAPH_IMAG(res) = (z1i * sz2r - z1r * sz2i) * s;
+  return res;
+}
+
+igraph_complex_t igraph_complex_add_real(igraph_complex_t z, 
+					 igraph_real_t x) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z) + x;
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z);
+  return res;
+}
+
+igraph_complex_t igraph_complex_add_imag(igraph_complex_t z, 
+					 igraph_real_t y) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z);
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z) + y;
+  return res;
+}
+
+igraph_complex_t igraph_complex_sub_real(igraph_complex_t z, 
+					 igraph_real_t x) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z) - x;
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z);
+  return res;
+}
+
+igraph_complex_t igraph_complex_sub_imag(igraph_complex_t z, 
+					 igraph_real_t y) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z);
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z) - y;
+  return res;
+}
+
+igraph_complex_t igraph_complex_mul_real(igraph_complex_t z, 
+					 igraph_real_t x) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z) * x;
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z) * x;
+  return res;
+}
+
+igraph_complex_t igraph_complex_mul_imag(igraph_complex_t z, 
+					 igraph_real_t y) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = - IGRAPH_IMAG(z) * y;
+  IGRAPH_IMAG(res) =   IGRAPH_REAL(z) * y;
+  return res;
+}
+
+igraph_complex_t igraph_complex_div_real(igraph_complex_t z, 
+					 igraph_real_t x) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = IGRAPH_REAL(z) / x;
+  IGRAPH_IMAG(res) = IGRAPH_IMAG(z) / x;
+  return res;  
+}
+
+igraph_complex_t igraph_complex_div_imag(igraph_complex_t z, 
+					 igraph_real_t y) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) =   IGRAPH_IMAG(z) / y;
+  IGRAPH_IMAG(res) = - IGRAPH_REAL(z) / y;
+  return res;
+}
+
+igraph_complex_t igraph_complex_conj(igraph_complex_t z) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) =   IGRAPH_REAL(z);
+  IGRAPH_IMAG(res) = - IGRAPH_IMAG(z);
+  return res;
+}
+
+igraph_complex_t igraph_complex_neg(igraph_complex_t z) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = - IGRAPH_REAL(z);
+  IGRAPH_IMAG(res) = - IGRAPH_IMAG(z);
+  return res;
+}
+
+igraph_complex_t igraph_complex_inv(igraph_complex_t z) {
+  igraph_complex_t res;
+  igraph_real_t s = 1.0 / igraph_complex_abs(z);
+  IGRAPH_REAL(res) =   (IGRAPH_REAL(z) * s) * s;
+  IGRAPH_IMAG(res) = - (IGRAPH_IMAG(z) * s) * s;
+  return res;
+}
+
+igraph_real_t igraph_complex_abs(igraph_complex_t z) {
+  return hypot(IGRAPH_REAL(z), IGRAPH_IMAG(z));
+}
+
+igraph_real_t igraph_complex_logabs(igraph_complex_t z) {
+  igraph_real_t xabs = fabs(IGRAPH_REAL(z));
+  igraph_real_t yabs = fabs(IGRAPH_IMAG(z));
+  igraph_real_t max, u;
+  if (xabs >= yabs) {
+    max = xabs;
+    u = yabs / xabs;
+  } else {
+    max = yabs;
+    u = xabs / yabs;
+  }
+  return log (max) + 0.5 * log1p (u * u);
+}
+
+igraph_complex_t igraph_complex_sqrt(igraph_complex_t z) {
+  igraph_complex_t res;
+
+  if (IGRAPH_REAL(z)==0.0 && IGRAPH_IMAG(z) == 0.0) { 
+    IGRAPH_REAL(res) = IGRAPH_IMAG(res) = 0.0;
+  } else {
+    igraph_real_t x = fabs (IGRAPH_REAL(z));
+    igraph_real_t y = fabs (IGRAPH_IMAG(z));
+    igraph_real_t w;
+    if (x >= y)  {
+      igraph_real_t t = y / x;
+      w = sqrt (x) * sqrt (0.5 * (1.0 + sqrt (1.0 + t * t)));
+    } else {
+      igraph_real_t t = x / y;
+      w = sqrt (y) * sqrt (0.5 * (t + sqrt (1.0 + t * t)));
+    }
+
+    if (IGRAPH_REAL(z) >= 0.0) {
+      igraph_real_t ai = IGRAPH_IMAG(z);
+      IGRAPH_REAL(res) = w;
+      IGRAPH_IMAG(res) = ai / (2.0 * w);
+    } else {
+      igraph_real_t ai = IGRAPH_IMAG(z);
+      igraph_real_t vi = (ai >= 0) ? w : -w;
+      IGRAPH_REAL(res) = ai / (2.0 * vi);
+      IGRAPH_IMAG(res) = vi;
+    }
+  }
+  
+  return res;
+}
+
+igraph_complex_t igraph_complex_sqrt_real(igraph_real_t x) {
+  igraph_complex_t res;
+  if (x >= 0) {
+    IGRAPH_REAL(res) = sqrt(x);
+    IGRAPH_IMAG(res) = 0.0;
+  } else {
+    IGRAPH_REAL(res) = 0.0;
+    IGRAPH_IMAG(res) = sqrt(-x);
+  }
+  return res;
+}
+
+igraph_complex_t igraph_complex_exp(igraph_complex_t z) {
+  igraph_real_t rho   = exp(IGRAPH_REAL(z));
+  igraph_real_t theta = IGRAPH_IMAG(z);
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = rho * cos(theta);
+  IGRAPH_IMAG(res) = rho * sin(theta);
+  return res;
+}
+
+igraph_complex_t igraph_complex_pow(igraph_complex_t z1,
+				    igraph_complex_t z2) {
+  igraph_complex_t res;
+
+  if (IGRAPH_REAL(z1) == 0 && IGRAPH_IMAG(z1) == 0.0) {
+    if (IGRAPH_REAL(z2) == 0 && IGRAPH_IMAG(z2) == 0.0) {
+      IGRAPH_REAL(res) = 1.0;
+      IGRAPH_IMAG(res) = 0.0;
+    } else {
+      IGRAPH_REAL(res) = IGRAPH_IMAG(res) = 0.0;
+    }
+  } else if (IGRAPH_REAL(z2) == 1.0 && IGRAPH_IMAG(z2) == 0.0) {
+    IGRAPH_REAL(res) = IGRAPH_REAL(z1); 
+    IGRAPH_IMAG(res) = IGRAPH_IMAG(z1);
+  } else if (IGRAPH_REAL(z2) == -1.0 && IGRAPH_IMAG(z2) == 0.0) {
+    res = igraph_complex_inv(z1);
+  } else {
+    igraph_real_t logr = igraph_complex_logabs (z1);
+    igraph_real_t theta = igraph_complex_arg (z1);
+    igraph_real_t z2r = IGRAPH_REAL(z2), z2i = IGRAPH_IMAG(z2);
+    igraph_real_t rho = exp (logr * z2r - z2i * theta);
+    igraph_real_t beta = theta * z2r + z2i * logr;
+    IGRAPH_REAL(res) = rho * cos(beta);
+    IGRAPH_IMAG(res) = rho * sin(beta);
+  }
+
+  return res;
+}
+
+igraph_complex_t igraph_complex_pow_real(igraph_complex_t z, 
+					 igraph_real_t x) {
+  igraph_complex_t res;
+  if (IGRAPH_REAL(z) == 0.0 && IGRAPH_IMAG(z) == 0.0) {
+    if (x==0) {
+      IGRAPH_REAL(res) = 1.0;
+      IGRAPH_IMAG(res) = 0.0;
+    } else { 
+      IGRAPH_REAL(res) = IGRAPH_IMAG(res) = 0.0;
+    }
+  } else {
+    igraph_real_t logr = igraph_complex_logabs(z);
+    igraph_real_t theta = igraph_complex_arg(z);
+    igraph_real_t rho = exp (logr * x);
+    igraph_real_t beta = theta * x;
+    IGRAPH_REAL(res) = rho * cos(beta);
+    IGRAPH_IMAG(res) = rho * sin(beta);
+  }
+  return res;
+}
+
+igraph_complex_t igraph_complex_log(igraph_complex_t z) {
+  igraph_complex_t res;
+  IGRAPH_REAL(res) = igraph_complex_logabs(z);
+  IGRAPH_IMAG(res) = igraph_complex_arg(z);
+  return res;
+}
+
+igraph_complex_t igraph_complex_log10(igraph_complex_t z) {
+  return igraph_complex_mul_real(igraph_complex_log(z), 1/log(10.0));
+}
+
+igraph_complex_t igraph_complex_log_b(igraph_complex_t z, 
+				      igraph_complex_t b) {
+  return igraph_complex_div (igraph_complex_log(z), igraph_complex_log(b));
+}
+
+igraph_complex_t igraph_complex_sin(igraph_complex_t z) {
+  igraph_real_t zr = IGRAPH_REAL(z); 
+  igraph_real_t zi = IGRAPH_IMAG(z);
+  igraph_complex_t res;
+  if (zi == 0.0) { 
+    IGRAPH_REAL(res) = sin(zr);
+    IGRAPH_IMAG(res) = 0.0;
+  } else {
+    IGRAPH_REAL(res) = sin(zr) * cosh(zi);
+    IGRAPH_IMAG(res) = cos(zr) * sinh(zi);
+  }
+  return res;
+}
+
+igraph_complex_t igraph_complex_cos(igraph_complex_t z) {
+  igraph_real_t zr=IGRAPH_REAL(z);
+  igraph_real_t zi=IGRAPH_IMAG(z);
+  igraph_complex_t res;
+  if (zi == 0.0) {
+    IGRAPH_REAL(res) = cos(zr);
+    IGRAPH_IMAG(res) = 0.0;
+  } else { 
+    IGRAPH_REAL(res) = cos(zr) * cosh(zi);
+    IGRAPH_IMAG(res) = sin(zr) * sinh(-zi);
+  }
+  return res;
+}
+
+igraph_complex_t igraph_complex_tan(igraph_complex_t z) {
+  igraph_real_t zr=IGRAPH_REAL(z);
+  igraph_real_t zi=IGRAPH_IMAG(z);
+  igraph_complex_t res;
+  if (fabs (zi) < 1) {
+    igraph_real_t D = pow (cos (zr), 2.0) + pow (sinh (zi), 2.0);
+    IGRAPH_REAL(res) = 0.5 * sin (2 * zr) / D;
+    IGRAPH_IMAG(res) = 0.5 * sinh (2 * zi) / D;
+  } else {
+    igraph_real_t u = exp (-zi);
+    igraph_real_t C = 2 * u / (1 - pow (u, 2.0));
+    igraph_real_t D = 1 + pow (cos (zr), 2.0) * pow (C, 2.0);
+    igraph_real_t S = pow (C, 2.0);
+    igraph_real_t T = 1.0 / tanh (zi);
+    IGRAPH_REAL(res) = 0.5 * sin (2 * zr) * S / D;
+    IGRAPH_IMAG(res) = T / D;
+  }
+  return res;
+}
+
+igraph_complex_t igraph_complex_sec(igraph_complex_t z) {
+  return igraph_complex_inv(igraph_complex_cos(z));
+}
+
+igraph_complex_t igraph_complex_csc(igraph_complex_t z) {
+  return igraph_complex_inv(igraph_complex_sin(z));
+}
+
+igraph_complex_t igraph_complex_cot(igraph_complex_t z) {
+  return igraph_complex_inv(igraph_complex_tan(z));
+}
+
diff --git a/src/components.c b/src/components.c
new file mode 100644
index 0000000..151f5d1
--- /dev/null
+++ b/src/components.c
@@ -0,0 +1,838 @@
+/* -*- 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
+
+*/
+
+#include "igraph_components.h"
+#include "igraph_memory.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_structural.h"
+#include "igraph_dqueue.h"
+#include "igraph_stack.h"
+#include "igraph_vector.h"
+#include "config.h"
+#include <string.h>
+#include <limits.h>
+
+int igraph_clusters_weak(const igraph_t *graph, igraph_vector_t *membership,
+			 igraph_vector_t *csize, igraph_integer_t *no);
+
+int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
+			   igraph_vector_t *csize, igraph_integer_t *no);
+
+/**
+ * \ingroup structural
+ * \function igraph_clusters
+ * \brief Calculates the (weakly or strongly) connected components in a graph. 
+ *
+ * \param graph The graph object to analyze.
+ * \param membership First half of the result will be stored here. For
+ *        every vertex the id of its component is given. The vector
+ *        has to be preinitialized and will be resized. Alternatively 
+ *        this argument can be \c NULL, in which case it is ignored.
+ * \param csize The second half of the result. For every component it
+ *        gives its size, the order is defined by the component ids.
+ *        The vector has to be preinitialized and will be resized.
+ *        Alternatively this argument can be \c NULL, in which
+ *        case it is ignored.
+ * \param no Pointer to an integer, if not \c NULL then the number of 
+ *        clusters will be stored here.
+ * \param mode For directed graph this specifies whether to calculate
+ *        weakly or strongly connected components. Possible values: 
+ *        \c IGRAPH_WEAK,
+ *        \c IGRAPH_STRONG. This argument is 
+ *        ignored for undirected graphs.
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid mode argument.
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| and 
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ */
+
+int igraph_clusters(const igraph_t *graph, igraph_vector_t *membership, 
+		    igraph_vector_t *csize, igraph_integer_t *no,
+		    igraph_connectedness_t mode) {
+  if (mode==IGRAPH_WEAK || !igraph_is_directed(graph)) {
+    return igraph_clusters_weak(graph, membership, csize, no);
+  } else if (mode==IGRAPH_STRONG) {
+    return igraph_clusters_strong(graph, membership, csize, no);
+  } else {
+    IGRAPH_ERROR("Cannot calculate clusters", IGRAPH_EINVAL);
+  }
+  
+  return 1;
+}
+
+int igraph_clusters_weak(const igraph_t *graph, igraph_vector_t *membership,
+			 igraph_vector_t *csize, igraph_integer_t *no) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  char *already_added;
+  long int first_node, act_cluster_size=0, no_of_clusters=1;
+  
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  
+  long int i;
+  igraph_vector_t neis=IGRAPH_VECTOR_NULL;
+
+  already_added=igraph_Calloc(no_of_nodes,char);
+  if (already_added==0) {
+    IGRAPH_ERROR("Cannot calculate clusters", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, already_added);
+
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, no_of_nodes > 100000 ? 10000 : no_of_nodes/10);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  /* Memory for result, csize is dynamically allocated */
+  if (membership) { 
+    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+  }
+  if (csize) { 
+    igraph_vector_clear(csize);
+  }
+
+  /* The algorithm */
+
+  for (first_node=0; first_node < no_of_nodes; ++first_node) {
+    if (already_added[first_node]==1) continue;
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    already_added[first_node]=1;
+    act_cluster_size=1;
+    if (membership) {
+      VECTOR(*membership)[first_node]=no_of_clusters-1;
+    }
+    IGRAPH_CHECK(igraph_dqueue_push(&q, first_node));
+    
+    while ( !igraph_dqueue_empty(&q) ) {
+      long int act_node=(long int) igraph_dqueue_pop(&q);
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis, 
+				    (igraph_integer_t) act_node, IGRAPH_ALL));
+      for (i=0; i<igraph_vector_size(&neis); i++) {
+	long int neighbor=(long int) VECTOR(neis)[i];
+	if (already_added[neighbor]==1) { continue; }
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	already_added[neighbor]=1;
+	act_cluster_size++;
+	if (membership) {
+	  VECTOR(*membership)[neighbor]=no_of_clusters-1;
+	}
+      }
+    }
+    no_of_clusters++;
+    if (csize) {
+      IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size));
+    }
+  }
+  
+  /* Cleaning up */
+  
+  if (no) { *no = (igraph_integer_t) no_of_clusters-1; }
+  
+  igraph_Free(already_added);
+  igraph_dqueue_destroy(&q);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
+			   igraph_vector_t *csize, igraph_integer_t *no) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t next_nei=IGRAPH_VECTOR_NULL;
+  
+  long int i;
+  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;
+
+  /* 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));
+  }
+  IGRAPH_CHECK(igraph_vector_reserve(&out, no_of_nodes));
+
+  igraph_vector_null(&out);
+  if (csize) {
+    igraph_vector_clear(csize);
+  }
+  
+  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; }
+    
+    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));
+      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)) {
+	/* 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];
+	if (VECTOR(next_nei)[neighbor] == 0) {
+	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	}
+	VECTOR(next_nei)[act_node]++;
+      } else {
+	/* 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);
+      }
+    } /* while q */
+  }  /* for */
+
+  /* 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 */
+  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;
+    if (membership) {
+      VECTOR(*membership)[grandfather]=no_of_clusters-1;
+    }
+    IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather));
+    
+    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];
+	if (VECTOR(next_nei)[neighbor] != 0) { continue; }
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	VECTOR(next_nei)[neighbor]=1;
+	act_cluster_size++;
+	if (membership) {
+	  VECTOR(*membership)[neighbor]=no_of_clusters-1;
+	}
+      }
+    }
+    no_of_clusters++;
+    if (csize) {
+      IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size));
+    }
+  }
+  
+  if (no) { *no=(igraph_integer_t) no_of_clusters-1; }
+
+  /* Clean up, return */
+
+  igraph_vector_destroy(&out);
+  igraph_vector_destroy(&tmp);
+  igraph_dqueue_destroy(&q);
+  igraph_vector_destroy(&next_nei);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+int igraph_is_connected_weak(const igraph_t *graph, igraph_bool_t *res);
+
+/**
+ * \ingroup structural
+ * \function igraph_is_connected
+ * \brief Decides whether the graph is (weakly or strongly) connected.
+ * 
+ * A graph with zero vertices (i.e. the null graph) is connected by definition.
+ *
+ * \param graph The graph object to analyze.
+ * \param res Pointer to a logical variable, the result will be stored
+ *        here. 
+ * \param mode For a directed graph this specifies whether to calculate
+ *        weak or strong connectedness. Possible values: 
+ *        \c IGRAPH_WEAK,
+ *        \c IGRAPH_STRONG. This argument is 
+ *        ignored for undirected graphs.
+ * \return Error code:
+ *        \c IGRAPH_EINVAL: invalid mode argument.
+ *
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices 
+ * plus the number of edges in the graph.
+ */
+
+int igraph_is_connected(const igraph_t *graph, igraph_bool_t *res, 
+			igraph_connectedness_t mode) {
+  if (igraph_vcount(graph) == 0) {
+    *res = 1;
+    return IGRAPH_SUCCESS;
+  }
+
+  if (mode==IGRAPH_WEAK || !igraph_is_directed(graph)) {
+    return igraph_is_connected_weak(graph, res);
+  } else if (mode==IGRAPH_STRONG) {
+    int retval;
+    igraph_integer_t no;
+    retval = igraph_clusters_strong(graph, 0, 0, &no);
+    *res = (no==1);
+    return retval;
+  } else {
+    IGRAPH_ERROR("mode argument", IGRAPH_EINVAL);
+  }
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_is_connected_weak
+ * \brief Query whether the graph is weakly connected.
+ *
+ * A graph with zero vertices (i.e. the null graph) is weakly connected by
+ * definition. A directed graph is weakly connected if its undirected version
+ * is connected. In the case of undirected graphs, weakly connected and
+ * connected are equivalent.
+ *
+ * \param graph The graph object to analyze.
+ * \param res Pointer to a logical variable; the result will be stored here.
+ * \return Error code:
+ *        \c IGRAPH_ENOMEM: unable to allocate requested memory.
+ *
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number of
+ * edges in the graph.
+ */
+
+int igraph_is_connected_weak(const igraph_t *graph, igraph_bool_t *res) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  char *already_added;
+  igraph_vector_t neis=IGRAPH_VECTOR_NULL;
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  
+  long int i, j;
+
+  if (no_of_nodes == 0) {
+    *res = 1;
+    return IGRAPH_SUCCESS;
+  }
+
+  already_added=igraph_Calloc(no_of_nodes, char);
+  if (already_added==0) {
+    IGRAPH_ERROR("is connected (weak) failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, already_added); /* TODO: hack */
+
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 10);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  
+  /* Try to find at least two clusters */
+  already_added[0]=1;
+  IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+  
+  j=1;
+  while ( !igraph_dqueue_empty(&q)) {
+    long int actnode=(long int) igraph_dqueue_pop(&q);
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actnode,
+				  IGRAPH_ALL));
+    for (i=0; i <igraph_vector_size(&neis); i++) {
+      long int neighbor=(long int) VECTOR(neis)[i];
+      if (already_added[neighbor] != 0) { continue; }
+      IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+      j++;
+      already_added[neighbor]++;
+    }
+  }
+  
+  /* Connected? */
+  *res = (j == no_of_nodes);
+
+  igraph_Free(already_added);
+  igraph_dqueue_destroy(&q);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/** 
+ * \function igraph_decompose_destroy
+ * \brief Free the memory allocated by \ref igraph_decompose().
+ * 
+ * \param complist The list of graph components, as returned by 
+ *        \ref igraph_decompose().
+ * 
+ * Time complexity: O(c), c is the number of components.
+ */ 
+
+void igraph_decompose_destroy(igraph_vector_ptr_t *complist) {
+  long int i;
+  for (i=0; i<igraph_vector_ptr_size(complist); i++) {
+    if (VECTOR(*complist)[i] != 0) {
+      igraph_destroy(VECTOR(*complist)[i]);
+      igraph_free(VECTOR(*complist)[i]);
+    }
+  }
+}
+
+/**
+ * \function igraph_decompose
+ * \brief Decompose a graph into connected components.
+ * 
+ * Create separate graph for each component of a graph. Note that the
+ * vertex ids in the new graphs will be different than in the original 
+ * graph. (Except if there is only one component in the original graph.)
+ * 
+ * \param graph The original graph.
+ * \param components This pointer vector will contain pointers to the
+ *   subcomponent graphs. It should be initialized before calling this
+ *   function and will be resized to hold the graphs. Don't forget to 
+ *   call \ref igraph_destroy() and free() on the elements of
+ *   this pointer vector to free unneeded memory. Alternatively, you can 
+ *   simply call \ref igraph_decompose_destroy() that does this for you.
+ * \param mode Either \c IGRAPH_WEAK or \c IGRAPH_STRONG for weakly
+ *    and strongly connected components respectively. Right now only
+ *    the former is implemented.
+ * \param maxcompno The maximum number of components to return. The
+ *    first \p maxcompno components will be returned (which hold at
+ *    least \p minelements vertices, see the next parameter), the
+ *    others will be ignored. Supply -1 here if you don't want to limit
+ *    the number of components.
+ * \param minelements The minimum number of vertices a component
+ *    should contain in order to place it in the \p components
+ *    vector. Eg. supply 2 here to ignore isolated vertices.
+ * \return Error code, \c IGRAPH_ENOMEM if there is not enough memory
+ *   to perform the operation.
+ *
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges. 
+ * 
+ * \example examples/simple/igraph_decompose.c
+ */
+
+int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components, 
+		     igraph_connectedness_t mode,
+		     long int maxcompno, long int minelements) {
+
+  long int actstart;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int resco=0;		/* number of graphs created so far */ 
+  char *already_added;
+  igraph_dqueue_t q;
+  igraph_vector_t verts;
+  igraph_vector_t neis;
+  long int i;
+  igraph_t *newg;
+
+  if (!igraph_is_directed(graph)) {
+    mode=IGRAPH_WEAK;
+  }
+
+  if (mode != IGRAPH_WEAK) {
+    IGRAPH_ERROR("only 'IGRAPH_WEAK' is implemented", IGRAPH_EINVAL);
+  }
+
+  if (maxcompno<0) {
+    maxcompno=LONG_MAX;
+  }
+
+  igraph_vector_ptr_clear(components);
+  IGRAPH_FINALLY(igraph_decompose_destroy, components);
+
+  already_added=igraph_Calloc(no_of_nodes, char);
+  if (already_added==0) {
+    IGRAPH_ERROR("Cannot decompose graph", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, already_added);
+
+  IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
+  IGRAPH_VECTOR_INIT_FINALLY(&verts, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  
+  for(actstart=0; resco<maxcompno && actstart < no_of_nodes; actstart++) {
+    
+    if (already_added[actstart]) { continue; }
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    igraph_vector_clear(&verts);
+    already_added[actstart]=1;
+    IGRAPH_CHECK(igraph_vector_push_back(&verts, actstart));
+    IGRAPH_CHECK(igraph_dqueue_push(&q, actstart));
+    
+    while (!igraph_dqueue_empty(&q) ) {
+      long int actvert=(long int) igraph_dqueue_pop(&q);
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actvert,
+				    IGRAPH_ALL));
+      for (i=0; i<igraph_vector_size(&neis); i++) {
+	long int neighbor=(long int) VECTOR(neis)[i];
+	if (already_added[neighbor]==1) { continue; }
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	IGRAPH_CHECK(igraph_vector_push_back(&verts, neighbor));
+	already_added[neighbor]=1;
+      }
+    }
+    
+    /* ok, we have a component */
+    if (igraph_vector_size(&verts)<minelements) { continue; }
+
+    newg=igraph_Calloc(1, igraph_t);
+    if (newg==0) {
+      IGRAPH_ERROR("Cannot decompose graph", IGRAPH_ENOMEM);
+    }
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(components, newg));
+    IGRAPH_CHECK(igraph_induced_subgraph(graph, newg, 
+					 igraph_vss_vector(&verts), 
+					 IGRAPH_SUBGRAPH_AUTO));
+    resco++;
+    
+  } /* for actstart++ */
+
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&verts);
+  igraph_dqueue_destroy(&q);
+  igraph_free(already_added);
+  IGRAPH_FINALLY_CLEAN(5);	/* + components */
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_articulation_points
+ * Find the articulation points in a graph.
+ * 
+ * A vertex is an articulation point if its removal increases 
+ * the number of connected components in the graph.
+ * \param graph The input graph.
+ * \param res Pointer to an initialized vector, the 
+ *    articulation points will be stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and edges.
+ * 
+ * \sa \ref igraph_biconnected_components(), \ref igraph_clusters()
+ */
+
+int igraph_articulation_points(const igraph_t *graph,
+			       igraph_vector_t *res) {
+
+  igraph_integer_t no;
+  return igraph_biconnected_components(graph, &no, 0, 0, 0, res);
+}
+
+void igraph_i_free_vectorlist(igraph_vector_ptr_t *list);
+
+void igraph_i_free_vectorlist(igraph_vector_ptr_t *list) {
+  long int i, n=igraph_vector_ptr_size(list);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*list)[i];
+    if (v) { 
+      igraph_vector_destroy(v);
+      igraph_Free(v);
+    }
+  }
+  igraph_vector_ptr_destroy(list);
+}
+
+/**
+ * \function igraph_biconnected_components
+ * Calculate biconnected components
+ * 
+ * A graph is biconnected if the removal of any single vertex (and
+ * its incident edges) does not disconnect it.
+ * 
+ * </para><para>
+ * 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.
+ * \param graph The input graph.
+ * \param no The number of biconnected components will be stored here.
+ * \param tree_edges If not a NULL pointer, then the found components
+ *     are stored here, in a list of vectors. Every vector in the list
+ *     is a biconnected component, represented by its edges. More precisely, 
+ *     a spanning tree of the biconnected component is returned.
+ *     Note you'll have to 
+ *     destroy each vector first by calling \ref igraph_vector_destroy()
+ *     and then <code>free()</code> on it, plus you need to call 
+ *     \ref igraph_vector_ptr_destroy() on the list to regain all 
+ *     allocated memory.
+ * \param component_edges If not a NULL pointer, then the edges of the
+ *     biconnected components are stored here, in the same form as for
+ *     \c tree_edges.
+ * \param components If not a NULL pointer, then the vertices of the
+ *     biconnected components are stored here, in the same format as
+ *     for the previous two arguments.
+ * \param articulation_points If not a NULL pointer, then the 
+ *     articulation points of the graph are stored in this vector.
+ *     A vertex is an articulation point if its removal increases the 
+ *     number of (weakly) connected components in the graph.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges, but only if you do not calculate \c components and
+ * \c component_edges. If you calculate \c components, then it is
+ * quadratic in the number of vertices. If you calculate \c
+ * component_edges as well, then it is cubic in the number of
+ * vertices.
+ * 
+ * \sa \ref igraph_articulation_points(), \ref igraph_clusters().
+ * 
+ * \example examples/simple/igraph_biconnected_components.c
+ */
+
+int igraph_biconnected_components(const igraph_t *graph,
+				  igraph_integer_t *no,
+				  igraph_vector_ptr_t *tree_edges,
+				  igraph_vector_ptr_t *component_edges,
+				  igraph_vector_ptr_t *components,
+				  igraph_vector_t *articulation_points) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_long_t nextptr;
+  igraph_vector_long_t num, low;
+  igraph_vector_bool_t found;
+  igraph_vector_t *adjedges;
+  igraph_stack_t path;
+  igraph_vector_t edgestack;
+  igraph_inclist_t inclist;
+  long int i, counter, rootdfs=0;  
+  igraph_vector_long_t vertex_added;
+  long int comps=0;
+  igraph_vector_ptr_t *mycomponents=components, vcomponents;
+
+  IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr);
+  IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &num);
+  IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &low);
+  IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &found);
+
+  IGRAPH_CHECK(igraph_stack_init(&path, 100));
+  IGRAPH_FINALLY(igraph_stack_destroy, &path);
+  IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100));
+
+  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+
+  IGRAPH_CHECK(igraph_vector_long_init(&vertex_added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &vertex_added);
+
+  if (no) {
+    *no=0;
+  }
+  if (tree_edges) {
+    igraph_vector_ptr_clear(tree_edges);
+  }
+  if (components) {
+    igraph_vector_ptr_clear(components);
+  }
+  if (component_edges) {
+    igraph_vector_ptr_clear(component_edges);
+  }
+  if (articulation_points) {
+    igraph_vector_clear(articulation_points);
+  }
+  if (component_edges && !components) {
+    mycomponents=&vcomponents;
+    IGRAPH_CHECK(igraph_vector_ptr_init(mycomponents, 0));
+    IGRAPH_FINALLY(igraph_i_free_vectorlist, mycomponents);
+  }
+
+  for (i=0; i<no_of_nodes; i++) {
+    
+    if (VECTOR(low)[i] != 0) { continue; } /* already visited */
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    IGRAPH_CHECK(igraph_stack_push(&path, i));
+    counter=1; 
+    rootdfs=0;
+    VECTOR(low)[i]=VECTOR(num)[i]=counter++;
+    while (!igraph_stack_empty(&path)) {
+      long int n;
+      long int act=(long int) igraph_stack_top(&path);
+      long int actnext=VECTOR(nextptr)[act];
+      
+      adjedges=igraph_inclist_get(&inclist, act);
+      n=igraph_vector_size(adjedges);
+      if (actnext < n) {
+	/* Step down (maybe) */
+	long int edge=(long int) VECTOR(*adjedges)[actnext];
+	long int nei=IGRAPH_OTHER(graph, edge, act);
+	if (VECTOR(low)[nei] == 0) {
+	  if (act==i) { rootdfs++; }
+	  IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge));
+	  IGRAPH_CHECK(igraph_stack_push(&path, nei));
+	  VECTOR(low)[nei] = VECTOR(num)[nei]=counter++;
+	} else {
+	  /* Update low value if needed */
+	  if (VECTOR(num)[nei] < VECTOR(low)[act]) {
+	    VECTOR(low)[act]=VECTOR(num)[nei];
+	  }
+	}
+	VECTOR(nextptr)[act] += 1;
+      } else {
+	/* Step up */
+	igraph_stack_pop(&path);
+	if (!igraph_stack_empty(&path)) {
+	  long int prev=(long int) igraph_stack_top(&path);
+	  /* Update LOW value if needed */
+	  if (VECTOR(low)[act] < VECTOR(low)[prev]) {
+	    VECTOR(low)[prev] = VECTOR(low)[act];
+	  }
+	  /* Check for articulation point */
+	  if (VECTOR(low)[act] >= VECTOR(num)[prev]) {
+	    if (articulation_points && !VECTOR(found)[prev] 
+		&& prev != i /* the root */) {
+	      IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev));
+	      VECTOR(found)[prev] = 1;
+	    }
+	    if (no) { *no += 1; }
+
+	    /*------------------------------------*/
+	    /* Record the biconnected component just found */
+	    if (tree_edges || mycomponents) {
+	      igraph_vector_t *v = 0, *v2 = 0;
+	      comps++;
+	      if (tree_edges) { 
+		v=igraph_Calloc(1, igraph_vector_t);
+		if (!v) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); }
+		IGRAPH_CHECK(igraph_vector_init(v, 0));
+		IGRAPH_FINALLY(igraph_vector_destroy, v);
+	      }
+	      if (mycomponents) {
+		v2=igraph_Calloc(1, igraph_vector_t);
+		if (!v2) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); }
+		IGRAPH_CHECK(igraph_vector_init(v2, 0));
+		IGRAPH_FINALLY(igraph_vector_destroy, v2);
+	      }
+	      
+	      while (!igraph_vector_empty(&edgestack)) {
+		long int e=(long int) igraph_vector_pop_back(&edgestack);
+		long int from=IGRAPH_FROM(graph,e);
+		long int to=IGRAPH_TO(graph,e);
+		if (tree_edges) { 
+		  IGRAPH_CHECK(igraph_vector_push_back(v, e));
+		}
+		if (mycomponents) {
+		  if (VECTOR(vertex_added)[from] != comps) { 
+		    VECTOR(vertex_added)[from] = comps;
+		    IGRAPH_CHECK(igraph_vector_push_back(v2, from));
+		  }
+		  if (VECTOR(vertex_added)[to] != comps) {
+		    VECTOR(vertex_added)[to] = comps;
+		    IGRAPH_CHECK(igraph_vector_push_back(v2, to));
+		  }
+		}
+		if (from==prev || to==prev) {
+		  break;
+		}
+	      }
+	      
+	      if (mycomponents) {
+		IGRAPH_CHECK(igraph_vector_ptr_push_back(mycomponents, v2));
+		IGRAPH_FINALLY_CLEAN(1);
+	      }
+	      if (tree_edges) { 
+		IGRAPH_CHECK(igraph_vector_ptr_push_back(tree_edges, v));
+		IGRAPH_FINALLY_CLEAN(1);
+	      }
+	      if (component_edges) {
+		igraph_vector_t *nodes=VECTOR(*mycomponents)[comps-1];
+		igraph_vector_t *vv=igraph_Calloc(1, igraph_vector_t);
+		long int ii, no_vert=igraph_vector_size(nodes);
+		if (!vv) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); }
+		IGRAPH_CHECK(igraph_vector_init(vv, 0));
+		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, 
+								vert);
+		  long int j, nn=igraph_vector_size(edges);
+		  for (j=0; j<nn; j++) {
+		    long int e=(long int) VECTOR(*edges)[j];
+		    long int nei=IGRAPH_OTHER(graph, e, vert);
+		    if (VECTOR(vertex_added)[nei] == comps && nei<vert) {
+		      IGRAPH_CHECK(igraph_vector_push_back(vv, e));
+		    }
+		  }
+		}
+		IGRAPH_CHECK(igraph_vector_ptr_push_back(component_edges, vv));
+		IGRAPH_FINALLY_CLEAN(1);
+	      }
+	    } /* record component if requested */
+	    /*------------------------------------*/
+
+	  }
+	} /* !igraph_stack_empty(&path) */
+      }
+      
+    } /* !igraph_stack_empty(&path) */
+    
+    if (articulation_points && rootdfs >= 2) {
+      IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i));
+    }
+
+  } /* i < no_of_nodes */
+
+  if (mycomponents != components) {
+    igraph_i_free_vectorlist(mycomponents);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_long_destroy(&vertex_added);
+  igraph_inclist_destroy(&inclist);
+  igraph_vector_destroy(&edgestack);
+  igraph_stack_destroy(&path);
+  igraph_vector_bool_destroy(&found);
+  igraph_vector_long_destroy(&low);
+  igraph_vector_long_destroy(&num);
+  igraph_vector_long_destroy(&nextptr);
+  IGRAPH_FINALLY_CLEAN(8);
+
+  return 0;
+}
+
diff --git a/src/conversion.c b/src/conversion.c
new file mode 100644
index 0000000..a84a354
--- /dev/null
+++ b/src/conversion.c
@@ -0,0 +1,847 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_conversion.h"
+#include "igraph_iterators.h"
+#include "igraph_interface.h"
+#include "igraph_attributes.h"
+#include "igraph_constructors.h"
+#include "igraph_types_internal.h"
+#include "igraph_sparsemat.h"
+#include "config.h"
+
+/**
+ * \ingroup conversion
+ * \function igraph_get_adjacency
+ * \brief Returns the adjacency matrix of a graph
+ * 
+ * </para><para>
+ * The result is an incidence matrix, it contains numbers greater
+ * than one if there are multiple edges in the graph.
+ * \param graph Pointer to the graph to convert
+ * \param res Pointer to an initialized matrix object, it will be
+ *        resized if needed.
+ * \param type Constant giving the type of the adjacency matrix to
+ *        create for undirected graphs. It is ignored for directed
+ *        graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_GET_ADJACENCY_UPPER 
+ *          the upper right triangle of the matrix is used.
+ *        \cli IGRAPH_GET_ADJACENCY_LOWER 
+ *          the lower left triangle of the matrix is used.
+ *        \cli IGRAPH_GET_ADJACENCY_BOTH 
+ *          the whole matrix is used, a symmetric matrix is returned.
+ *        \endclist
+ * \param type eids Logical, if true, then the edges ids plus one 
+ *        are stored in the adjacency matrix, instead of the number of 
+ *        edges between the two vertices. (The plus one is needed, since
+ *        edge ids start from zero, and zero means no edge in this case.)
+ * \return Error code:
+ *        \c IGRAPH_EINVAL invalid type argument.
+ *
+ * \sa igraph_get_adjacency_sparse if you want a sparse matrix representation
+ *
+ * Time complexity: O(|V||V|),
+ * |V| is the 
+ * number of vertices in the graph.
+ */
+
+int igraph_get_adjacency(const igraph_t *graph, igraph_matrix_t *res,
+			 igraph_get_adjacency_t type, igraph_bool_t eids) {
+  
+  igraph_eit_t edgeit;
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  int retval=0;
+  long int from, to;
+  igraph_integer_t ffrom, fto;
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes));
+  igraph_matrix_null(res);
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
+  
+  if (directed) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      long int edge=IGRAPH_EIT_GET(edgeit);
+      igraph_edge(graph, (igraph_integer_t) edge, &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      if (eids) { 
+	MATRIX(*res, from, to) = edge+1;
+      } else { 
+	MATRIX(*res, from, to) += 1;
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else if (type==IGRAPH_GET_ADJACENCY_UPPER) {
+    while (!IGRAPH_EIT_END(edgeit)) {  
+      long int edge=IGRAPH_EIT_GET(edgeit);
+      igraph_edge(graph, (igraph_integer_t) edge, &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      if (to < from) {
+	if (eids) { 
+	  MATRIX(*res, to, from) = edge+1;
+	} else {
+	  MATRIX(*res, to, from) += 1;
+	}
+      } else {
+	if (eids) {
+	  MATRIX(*res, from, to) = edge+1;
+	} else { 
+	  MATRIX(*res, from, to) += 1;    
+	}
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else if (type==IGRAPH_GET_ADJACENCY_LOWER) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      long int edge=IGRAPH_EIT_GET(edgeit);
+      igraph_edge(graph, (igraph_integer_t) edge, &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      if (to < from) {
+	if (eids) {
+	  MATRIX(*res, from, to) = edge+1;
+	} else {
+	  MATRIX(*res, from, to) += 1;
+	}
+      } else {
+	if (eids) { 
+	  MATRIX(*res, to, from) = edge+1;
+	} else {
+	  MATRIX(*res, to, from) += 1;
+	}
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else if (type==IGRAPH_GET_ADJACENCY_BOTH) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      long int edge=IGRAPH_EIT_GET(edgeit);
+      igraph_edge(graph, (igraph_integer_t) edge, &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      if (eids) { 
+	MATRIX(*res, from, to) = edge+1;
+      } else {
+	MATRIX(*res, from, to) += 1;
+      }
+      if (from != to) {
+	if (eids) { 
+	  MATRIX(*res, to, from) = edge+1;
+	} else {
+	  MATRIX(*res, to, from) += 1;
+	}
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else {
+    IGRAPH_ERROR("Invalid type argument", IGRAPH_EINVAL);
+  }
+
+  igraph_eit_destroy(&edgeit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return retval;
+}
+
+/**
+ * \ingroup conversion
+ * \function igraph_get_adjacency_sparse
+ * \brief Returns the adjacency matrix of a graph in sparse matrix format
+ * 
+ * </para><para>
+ * The result is an incidence matrix, it contains numbers greater
+ * than one if there are multiple edges in the graph.
+ * \param graph Pointer to the graph to convert
+ * \param res Pointer to an initialized sparse matrix object, it will be
+ *        resized if needed.
+ * \param type Constant giving the type of the adjacency matrix to
+ *        create for undirected graphs. It is ignored for directed
+ *        graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_GET_ADJACENCY_UPPER 
+ *          the upper right triangle of the matrix is used.
+ *        \cli IGRAPH_GET_ADJACENCY_LOWER 
+ *          the lower left triangle of the matrix is used.
+ *        \cli IGRAPH_GET_ADJACENCY_BOTH 
+ *          the whole matrix is used, a symmetric matrix is returned.
+ *        \endclist
+ * \return Error code:
+ *        \c IGRAPH_EINVAL invalid type argument.
+ *
+ * \sa igraph_get_adjacency if you would like to get a normal matrix
+ *   ( \type igraph_matrix_t )
+ *
+ * Time complexity: O(|V||V|),
+ * |V| is the 
+ * number of vertices in the graph.
+ */
+
+int igraph_get_adjacency_sparse(const igraph_t *graph, igraph_spmatrix_t *res,
+			 igraph_get_adjacency_t type) {
+  
+  igraph_eit_t edgeit;
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  int retval=0;
+  long int from, to;
+  igraph_integer_t ffrom, fto;
+  
+  igraph_spmatrix_null(res);
+  IGRAPH_CHECK(igraph_spmatrix_resize(res, no_of_nodes, no_of_nodes));
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
+  
+  if (directed) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      igraph_spmatrix_add_e(res, from, to, 1);
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else if (type==IGRAPH_GET_ADJACENCY_UPPER) {
+    while (!IGRAPH_EIT_END(edgeit)) {  
+      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      if (to < from) {
+        igraph_spmatrix_add_e(res, to, from, 1);
+      } else {
+        igraph_spmatrix_add_e(res, from, to, 1);
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else if (type==IGRAPH_GET_ADJACENCY_LOWER) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      if (to > from) {
+        igraph_spmatrix_add_e(res, to, from, 1);
+      } else {
+        igraph_spmatrix_add_e(res, from, to, 1);
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else if (type==IGRAPH_GET_ADJACENCY_BOTH) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+      from=ffrom;
+      to=fto;
+      igraph_spmatrix_add_e(res, from, to, 1);
+      if (from != to) {
+        igraph_spmatrix_add_e(res, to, from, 1);
+      }
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else {
+    IGRAPH_ERROR("Invalid type argument", IGRAPH_EINVAL);
+  }
+
+  igraph_eit_destroy(&edgeit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return retval;
+}
+
+/**
+ * \ingroup conversion
+ * \function igraph_get_edgelist
+ * \brief Returns the list of edges in a graph
+ * 
+ * </para><para>The order of the edges is given by the edge ids.
+ * \param graph Pointer to the graph object
+ * \param res Pointer to an initialized vector object, it will be
+ *        resized.
+ * \param bycol Logical, if true, the edges will be returned
+ *        columnwise, eg. the first edge is
+ *        <code>res[0]->res[|E|]</code>, the second is
+ *        <code>res[1]->res[|E|+1]</code>, etc.
+ * \return Error code.
+ * 
+ * Time complexity: O(|E|), the
+ * number of edges in the graph.
+ */
+
+int igraph_get_edgelist(const igraph_t *graph, igraph_vector_t *res, igraph_bool_t bycol) {
+
+  igraph_eit_t edgeit;
+  long int no_of_edges=igraph_ecount(graph);
+  long int vptr=0;
+  igraph_integer_t from, to;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, no_of_edges*2));
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID),
+				 &edgeit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
+  
+  if (bycol) {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to);
+      VECTOR(*res)[vptr]=from;
+      VECTOR(*res)[vptr+no_of_edges]=to;
+      vptr++;
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  } else {
+    while (!IGRAPH_EIT_END(edgeit)) {
+      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to);
+      VECTOR(*res)[vptr++]=from;
+      VECTOR(*res)[vptr++]=to;
+      IGRAPH_EIT_NEXT(edgeit);
+    }
+  }
+  
+  igraph_eit_destroy(&edgeit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_to_directed
+ * \brief Convert an undirected graph to a directed one
+ * 
+ * </para><para>
+ * If the supplied graph is directed, this function does nothing.
+ * \param graph The graph object to convert.
+ * \param mode Constant, specifies the details of how exactly the
+ *        conversion is done. Possible values: \c
+ *        IGRAPH_TO_DIRECTED_ARBITRARY: the number of edges in the
+ *        graph stays the same, an arbitrarily directed edge is
+ *        created for each undirected edge; 
+ *         \c IGRAPH_TO_DIRECTED_MUTUAL: two directed edges are
+ *        created for each undirected edge, one in each direction.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges.
+ */
+
+int igraph_to_directed(igraph_t *graph,
+		       igraph_to_directed_t mode) {
+
+  if (mode != IGRAPH_TO_DIRECTED_ARBITRARY &&
+      mode != IGRAPH_TO_DIRECTED_MUTUAL) {
+    IGRAPH_ERROR("Cannot directed graph, invalid mode", IGRAPH_EINVAL);
+  }
+
+  if (igraph_is_directed(graph)) {
+    return 0;
+  }
+
+  if (mode==IGRAPH_TO_DIRECTED_ARBITRARY) {
+
+    igraph_t newgraph;
+    igraph_vector_t edges;
+    long int no_of_edges=igraph_ecount(graph);
+    long int no_of_nodes=igraph_vcount(graph);
+    long int size=no_of_edges*2;
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, size);
+    IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
+
+    IGRAPH_CHECK(igraph_create(&newgraph, &edges,
+			       (igraph_integer_t) no_of_nodes,
+			       IGRAPH_DIRECTED));
+    IGRAPH_FINALLY(igraph_destroy, &newgraph);
+    igraph_vector_destroy(&edges);
+    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
+    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
+    IGRAPH_FINALLY_CLEAN(2);
+    igraph_destroy(graph);
+    *graph=newgraph;
+
+  } else if (mode==IGRAPH_TO_DIRECTED_MUTUAL) {
+    
+    igraph_t newgraph;
+    igraph_vector_t edges;
+    igraph_vector_t index;
+    long int no_of_edges=igraph_ecount(graph);
+    long int no_of_nodes=igraph_vcount(graph);
+    long int size=no_of_edges*4;
+    long int i;
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, size));
+    IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
+    IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4));
+    IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_edges*2);
+    for (i=0; i<no_of_edges; i++) {
+      VECTOR(edges)[no_of_edges*2+i*2]  =VECTOR(edges)[i*2+1];
+      VECTOR(edges)[no_of_edges*2+i*2+1]=VECTOR(edges)[i*2];
+      VECTOR(index)[i] = VECTOR(index)[no_of_edges+i] = i;
+    }
+
+    IGRAPH_CHECK(igraph_create(&newgraph, &edges, 
+			       (igraph_integer_t) no_of_nodes,
+			       IGRAPH_DIRECTED));
+    IGRAPH_FINALLY(igraph_destroy, &newgraph);
+    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
+    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,/*edges=*/0);
+    IGRAPH_CHECK(igraph_i_attribute_permute_edges(graph, &newgraph, &index));
+    
+    igraph_vector_destroy(&index);
+    igraph_vector_destroy(&edges);
+    igraph_destroy(graph);
+    IGRAPH_FINALLY_CLEAN(3);
+    *graph=newgraph;
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_to_undirected
+ * \brief Convert a directed graph to an undirected one.
+ * 
+ * </para><para>
+ * If the supplied graph is undirected, this function does nothing.
+ * \param graph The graph object to convert.
+ * \param mode Constant, specifies the details of how exactly the
+ *        conversion is done. Possible values: \c 
+ *        IGRAPH_TO_UNDIRECTED_EACH: the number of edges remains
+ *        constant, an undirected edge is created for each directed
+ *        one, this version might create graphs with multiple edges; 
+ *        \c IGRAPH_TO_UNDIRECTED_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. \c IGRAPH_TO_UNDIRECTED_MUTUAL creates an undirected 
+ *        edge for each pair of mutual edges in the directed graph. 
+ *        Non-mutual edges are lost. This mode might create multiple
+ *        edges.
+ * \param edge_comb What to do with the edge attributes. See the igraph 
+ *        manual section about attributes for details.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges. 
+ * 
+ * \example examples/simple/igraph_to_undirected.c
+ */
+
+int igraph_to_undirected(igraph_t *graph,
+			 igraph_to_undirected_t mode,
+			 const igraph_attribute_combination_t *edge_comb) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t edges;
+  igraph_t newgraph;
+  igraph_bool_t attr=edge_comb && igraph_has_attribute_table();
+  
+  if (mode != IGRAPH_TO_UNDIRECTED_EACH &&
+      mode != IGRAPH_TO_UNDIRECTED_COLLAPSE && 
+      mode != IGRAPH_TO_UNDIRECTED_MUTUAL) {
+    IGRAPH_ERROR("Cannot undirect graph, invalid mode", IGRAPH_EINVAL);
+  }
+  
+  if (!igraph_is_directed(graph)) {
+    return 0;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  
+  if (mode==IGRAPH_TO_UNDIRECTED_EACH) {
+    igraph_es_t es;
+    igraph_eit_t eit;
+
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+    IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
+    IGRAPH_FINALLY(igraph_es_destroy, &es);
+    IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+    IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+    
+    while (!IGRAPH_EIT_END(eit)) {
+      long int edge=IGRAPH_EIT_GET(eit);
+      igraph_integer_t from, to;
+      igraph_edge(graph, (igraph_integer_t) edge, &from, &to);
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+      IGRAPH_EIT_NEXT(eit);
+    }
+    
+    igraph_eit_destroy(&eit);
+    igraph_es_destroy(&es);
+    IGRAPH_FINALLY_CLEAN(2);
+    
+    IGRAPH_CHECK(igraph_create(&newgraph, &edges, 
+			       (igraph_integer_t) no_of_nodes, 
+			       IGRAPH_UNDIRECTED));
+    IGRAPH_FINALLY(igraph_destroy, &newgraph);
+    igraph_vector_destroy(&edges);
+    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
+    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
+    IGRAPH_FINALLY_CLEAN(2);
+    igraph_destroy(graph);
+    *graph=newgraph;
+    
+  } else if (mode==IGRAPH_TO_UNDIRECTED_COLLAPSE) {
+    igraph_vector_t inadj, outadj;
+    long int i;
+    igraph_vector_t mergeinto;
+    long int actedge=0;
+
+    if (attr) {
+      IGRAPH_VECTOR_INIT_FINALLY(&mergeinto, no_of_edges);
+    }
+
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+    IGRAPH_VECTOR_INIT_FINALLY(&inadj, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&outadj, 0);
+    
+    for (i=0; i<no_of_nodes; i++) {
+      long int n_out, n_in;
+      long int p1=-1, p2=-1;
+      long int e1=0, e2=0, n1=0, n2=0;
+      IGRAPH_CHECK(igraph_incident(graph, &outadj, (igraph_integer_t) i, 
+				   IGRAPH_OUT));
+      IGRAPH_CHECK(igraph_incident(graph, &inadj, (igraph_integer_t) i, 
+				   IGRAPH_IN));
+      n_out=igraph_vector_size(&outadj);
+      n_in=igraph_vector_size(&inadj);
+
+#define STEPOUT() if ( (++p1) < n_out) {	\
+	e1 = (long int) VECTOR(outadj)[p1];	\
+	n1 = IGRAPH_TO(graph, e1);		\
+      }
+#define STEPIN()  if ( (++p2) < n_in) {	        \
+        e2 = (long int) VECTOR(inadj )[p2];	\
+	n2 = IGRAPH_FROM(graph, e2);		\
+      }
+
+      STEPOUT();
+      STEPIN();
+
+      while (p1 < n_out && n1 <= i && p2 < n_in && n2 <= i) {
+	long int last;
+	if (n1==n2) {
+	  last=n1;
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, n1));
+	  if (attr) {
+	    VECTOR(mergeinto)[e1]=actedge;
+	    VECTOR(mergeinto)[e2]=actedge;
+	    actedge++;
+	  }
+	  while (p1 < n_out && last==n1) { STEPOUT(); }
+	  while (p2 < n_in  && last==n2) { STEPIN (); }
+	} else if (n1<n2) {
+	  last=n1;
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, n1));
+	  if (attr) {
+	    VECTOR(mergeinto)[e1]=actedge;
+	    actedge++;
+	  }
+	  while (p1 < n_out && last==n1) { STEPOUT(); }
+	} else { /* n2<n1 */
+	  last=n2;
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, n2));
+	  if (attr) {
+	    VECTOR(mergeinto)[e2]=actedge;
+	    actedge++;
+	  }
+	  while (p2 < n_in && last==n2) { STEPIN(); }
+	}
+      }
+      while (p1 < n_out && n1 <= i) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, n1));
+	if (attr) {
+	  VECTOR(mergeinto)[e1]=actedge;
+	  actedge++;
+	}
+	STEPOUT();	
+      }
+      while (p2 < n_in && n2 <= i) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, n2));
+	if (attr) {
+	  VECTOR(mergeinto)[e2]=actedge;
+	  actedge++;
+	}
+	STEPIN();
+      }
+    }
+	
+#undef STEPOUT
+#undef STEPIN 
+
+    igraph_vector_destroy(&outadj);
+    igraph_vector_destroy(&inadj);
+    IGRAPH_FINALLY_CLEAN(2);
+
+    IGRAPH_CHECK(igraph_create(&newgraph, &edges,
+			       (igraph_integer_t) no_of_nodes,
+			       IGRAPH_UNDIRECTED));
+    IGRAPH_FINALLY(igraph_destroy, &newgraph);
+    igraph_vector_destroy(&edges);
+    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
+    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,0); /* no edge attributes */
+
+    if (attr) {
+      igraph_fixed_vectorlist_t vl;
+      IGRAPH_CHECK(igraph_fixed_vectorlist_convert(&vl, &mergeinto, 
+						   actedge));
+      IGRAPH_FINALLY(igraph_fixed_vectorlist_destroy, &vl);
+      
+      IGRAPH_CHECK(igraph_i_attribute_combine_edges(graph, &newgraph, &vl.v, 
+						    edge_comb));
+      
+      igraph_fixed_vectorlist_destroy(&vl);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    IGRAPH_FINALLY_CLEAN(2);
+    igraph_destroy(graph);
+    *graph=newgraph;
+    
+    if (attr) {
+      igraph_vector_destroy(&mergeinto);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  } else if (mode==IGRAPH_TO_UNDIRECTED_MUTUAL) {
+    igraph_vector_t inadj, outadj;
+    long int i;
+    igraph_vector_t mergeinto;
+    long int actedge=0;
+
+    if (attr) {
+      IGRAPH_VECTOR_INIT_FINALLY(&mergeinto, no_of_edges);
+      igraph_vector_fill(&mergeinto, -1);
+    }
+    
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+    IGRAPH_VECTOR_INIT_FINALLY(&inadj, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&outadj, 0);
+
+    for (i=0; i<no_of_nodes; i++) {
+      long int n_out, n_in; 
+      long int p1=-1, p2=-1;
+      long int e1=0, e2=0, n1=0, n2=0;
+      IGRAPH_CHECK(igraph_incident(graph, &outadj, (igraph_integer_t) i, 
+				   IGRAPH_OUT));
+      IGRAPH_CHECK(igraph_incident(graph, &inadj,  (igraph_integer_t) i, 
+				   IGRAPH_IN));
+      n_out=igraph_vector_size(&outadj);
+      n_in=igraph_vector_size(&inadj);
+
+#define STEPOUT() if ( (++p1) < n_out) {	\
+	e1 = (long int) VECTOR(outadj)[p1];	\
+	n1 = IGRAPH_TO(graph, e1);		\
+      }
+#define STEPIN()  if ( (++p2) < n_in) {	        \
+        e2 = (long int) VECTOR(inadj )[p2];	\
+	n2 = IGRAPH_FROM(graph, e2);		\
+      }
+
+      STEPOUT();
+      STEPIN();
+
+      while (p1 < n_out && n1 <= i && p2 < n_in && n2 <= i) {
+	if (n1==n2) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, n1));
+	  if (attr) {
+	    VECTOR(mergeinto)[e1]=actedge;
+	    VECTOR(mergeinto)[e2]=actedge;
+	    actedge++;
+	  }
+	  STEPOUT();
+	  STEPIN();
+	} else if (n1<n2) {
+	  STEPOUT();
+	} else { /* n2<n1 */
+	  STEPIN();
+	}
+      }
+    }
+
+#undef STEPOUT
+#undef STEPIN      
+
+    igraph_vector_destroy(&outadj);
+    igraph_vector_destroy(&inadj);
+    IGRAPH_FINALLY_CLEAN(2);
+
+    IGRAPH_CHECK(igraph_create(&newgraph, &edges,
+			       (igraph_integer_t) no_of_nodes, 
+			       IGRAPH_UNDIRECTED));
+    IGRAPH_FINALLY(igraph_destroy, &newgraph);
+    igraph_vector_destroy(&edges);
+    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
+    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,0); /* no edge attributes */
+
+    if (attr) {
+      igraph_fixed_vectorlist_t vl;
+      IGRAPH_CHECK(igraph_fixed_vectorlist_convert(&vl, &mergeinto, 
+						   actedge));
+      IGRAPH_FINALLY(igraph_fixed_vectorlist_destroy, &vl);
+      
+      IGRAPH_CHECK(igraph_i_attribute_combine_edges(graph, &newgraph, &vl.v, 
+						    edge_comb));
+      
+      igraph_fixed_vectorlist_destroy(&vl);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    IGRAPH_FINALLY_CLEAN(2);
+    igraph_destroy(graph);
+    *graph=newgraph;
+    
+    if (attr) {
+      igraph_vector_destroy(&mergeinto);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_get_stochastic
+ * Stochastic adjacency matrix of a graph
+ * 
+ * Stochastic matrix of a graph. The stochastic matrix of a graph is
+ * its adjacency matrix, normalized row-wise or column-wise, such that
+ * the sum of each row (or column) is one. 
+ * \param graph The input graph. 
+ * \param sparsemat Pointer to an initialized matrix, the
+ *    result is stored here.
+ * \param column_wise Whether to normalize column-wise. For undirected
+ *    graphs this argument does not have any effect.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V||V|), quadratic in the number of vertices.
+ * 
+ * \sa igraph_get_stochastic_sparsemat(), the sparse version of this
+ * function.
+ */
+
+int igraph_get_stochastic(const igraph_t *graph, 
+			  igraph_matrix_t *matrix,
+			  igraph_bool_t column_wise) {
+  
+  int no_of_nodes=igraph_vcount(graph);
+  igraph_real_t sum;
+  int i, j;
+  
+  IGRAPH_CHECK(igraph_get_adjacency(graph, matrix, 
+				    IGRAPH_GET_ADJACENCY_BOTH, /*eids=*/ 0));
+  
+  if (!column_wise) {
+    for (i=0; i<no_of_nodes; i++) {
+      sum=0.0; 
+      for (j=0; j<no_of_nodes; j++) { 
+	sum += MATRIX(*matrix, i, j);
+      }
+      for (j=0; j<no_of_nodes; j++) {
+	MATRIX(*matrix, i, j) /= sum;
+      }
+    }
+  } else {
+    for (i=0; i<no_of_nodes; i++) {
+      sum=0.0; 
+      for (j=0; j<no_of_nodes; j++) { 
+	sum += MATRIX(*matrix, j, i);
+      }
+      for (j=0; j<no_of_nodes; j++) {
+	MATRIX(*matrix, j, i) /= sum;
+      }
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_normalize_sparsemat(igraph_sparsemat_t *sparsemat, 
+				 igraph_bool_t column_wise);
+
+
+int igraph_i_normalize_sparsemat(igraph_sparsemat_t *sparsemat, 
+				 igraph_bool_t column_wise) {
+  igraph_vector_t sum;
+  int no_of_nodes=(int) igraph_sparsemat_nrow(sparsemat);
+  int i;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&sum, no_of_nodes);
+
+  if (!column_wise) {
+    IGRAPH_CHECK(igraph_sparsemat_rowsums(sparsemat, &sum));
+    for (i=0; i<no_of_nodes; i++) {
+      if (VECTOR(sum)[i] == 0.0) {
+	IGRAPH_ERROR("Zero out-degree vertices not allowed", 
+		     IGRAPH_EINVAL);
+      }
+      VECTOR(sum)[i] = 1.0 / VECTOR(sum)[i];
+    }
+    IGRAPH_CHECK(igraph_sparsemat_scale_rows(sparsemat, &sum));
+  } else {
+    IGRAPH_CHECK(igraph_sparsemat_colsums(sparsemat, &sum));
+    for (i=0; i<no_of_nodes; i++) {
+      if (VECTOR(sum)[i] == 0.0) {
+	IGRAPH_ERROR("Zero out-degree vertices not allowed", 
+		     IGRAPH_EINVAL);
+      }
+      VECTOR(sum)[i] = 1.0 / VECTOR(sum)[i];
+    }
+    IGRAPH_CHECK(igraph_sparsemat_scale_cols(sparsemat, &sum));
+  }
+
+  igraph_vector_destroy(&sum);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_get_stochastic_sparsemat
+ * \brief Stochastic adjacency matrix of a graph
+ * 
+ * Stochastic matrix of a graph. The stochastic matrix of a graph is
+ * its adjacency matrix, normalized row-wise or column-wise, such that
+ * the sum of each row (or column) is one. 
+ * \param graph The input graph. 
+ * \param sparsemat Pointer to an uninitialized sparse matrix, the
+ *    result is stored here.
+ * \param column_wise Whether to normalize column-wise. For undirected
+ *    graphs this argument does not have any effect.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ * 
+ * \sa igraph_get_stochastic(), the dense version of this function.
+ */
+
+int igraph_get_stochastic_sparsemat(const igraph_t *graph, 
+				    igraph_sparsemat_t *sparsemat,
+				    igraph_bool_t column_wise) {
+  
+  IGRAPH_CHECK(igraph_get_sparsemat(graph, sparsemat));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, sparsemat);
+  IGRAPH_CHECK(igraph_i_normalize_sparsemat(sparsemat, column_wise));
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
diff --git a/src/cores.c b/src/cores.c
new file mode 100644
index 0000000..ab7da25
--- /dev/null
+++ b/src/cores.c
@@ -0,0 +1,159 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_community.h"
+#include "igraph_memory.h"
+#include "igraph_interface.h"
+#include "igraph_iterators.h"
+#include "config.h"
+
+/**
+ * \function igraph_coreness 
+ * \brief Finding the coreness of the vertices in a network.
+ *
+ * The k-core of a graph is a maximal subgraph in which each vertex
+ * has at least degree k. (Degree here means the degree in the
+ * subgraph of course.). The coreness of a vertex is the highest order 
+ * of a k-core containing the vertex.
+ * 
+ * </para><para>
+ * This function implements the algorithm presented in Vladimir
+ * Batagelj, Matjaz Zaversnik: An O(m) Algorithm for Cores
+ * Decomposition of Networks. 
+ * \param graph The input graph.
+ * \param cores Pointer to an initialized vector, the result of the
+ *        computation will be stored here. It will be resized as
+ *        needed. For each vertex it contains the highest order of a
+ *        core containing the vertex.
+ * \param mode For directed graph it specifies whether to calculate
+ *        in-cores, out-cores or the undirected version. It is ignored
+ *        for undirected graphs. Possible values: \c IGRAPH_ALL
+ *        undirected version, \c IGRAPH_IN in-cores, \c IGRAPH_OUT
+ *        out-cores. 
+ * \return Error code.
+ *
+ * Time complexity: O(|E|), the number of edges.
+ */
+
+int igraph_coreness(const igraph_t *graph, igraph_vector_t *cores, 
+		    igraph_neimode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int *bin, *vert, *pos;
+  long int maxdeg;
+  long int i, j=0;
+  igraph_vector_t neis;
+  igraph_neimode_t omode;
+  
+  if (mode != IGRAPH_ALL && mode != IGRAPH_OUT && mode != IGRAPH_IN) {
+    IGRAPH_ERROR("Invalid mode in k-cores", IGRAPH_EINVAL);
+  }
+  if (!igraph_is_directed(graph) || mode==IGRAPH_ALL) {
+    mode=omode=IGRAPH_ALL;
+  } else if (mode==IGRAPH_IN) {
+    omode=IGRAPH_OUT;
+  } else {
+    omode=IGRAPH_IN;
+  }
+
+  vert=igraph_Calloc(no_of_nodes, long int);
+  if (vert==0) {
+    IGRAPH_ERROR("Cannot calculate k-cores", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, vert);
+  pos=igraph_Calloc(no_of_nodes, long int);
+  if (pos==0) {
+    IGRAPH_ERROR("Cannot calculate k-cores", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, pos);
+
+  /* maximum degree + degree of vertices */
+  IGRAPH_CHECK(igraph_degree(graph, cores, igraph_vss_all(), mode, 
+			     IGRAPH_LOOPS));
+  maxdeg = (long int) igraph_vector_max(cores);
+
+  bin=igraph_Calloc(maxdeg+1, long int);
+  if (bin==0) {
+    IGRAPH_ERROR("Cannot calculate k-cores", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, bin);
+
+  /* degree histogram */
+  for (i=0; i<no_of_nodes; i++) {
+    bin[ (long int)VECTOR(*cores)[i] ] += 1;
+  }
+  
+  /* start pointers */
+  j=0;
+  for (i=0; i<=maxdeg; i++) {
+    long int k=bin[i];
+    bin[i] = j;
+    j += k;
+  }
+  
+  /* sort in vert (and corrupt bin) */
+  for (i=0; i<no_of_nodes; i++) {
+    pos[i] = bin[(long int)VECTOR(*cores)[i]];
+    vert[pos[i]] = i;
+    bin[(long int)VECTOR(*cores)[i]] += 1;
+  }
+  
+  /* correct bin */
+  for (i=maxdeg; i>0; i--) {
+    bin[i] = bin[i-1];
+  }
+  bin[0]=0;
+
+  /* this is the main algorithm */
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, maxdeg);
+  for (i=0; i<no_of_nodes; i++) {
+    long int v=vert[i];
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, omode));
+    for (j=0; j<igraph_vector_size(&neis); j++) {
+      long int u=(long int) VECTOR(neis)[j];
+      if (VECTOR(*cores)[u] > VECTOR(*cores)[v]) {
+	long int du=(long int) VECTOR(*cores)[u];
+	long int pu=pos[u];
+	long int pw=bin[du];
+	long int w=vert[pw];
+	if (u != w) {
+	  pos[u]=pw;
+	  pos[w]=pu;
+	  vert[pu]=w;
+	  vert[pw]=u;
+	}
+	bin[du] += 1;
+	VECTOR(*cores)[u] -= 1;
+      }
+    }
+  }
+  
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_free(bin);
+  igraph_free(pos);
+  igraph_free(vert);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
diff --git a/src/cs/UFconfig.h b/src/cs/UFconfig.h
new file mode 100644
index 0000000..3844ccc
--- /dev/null
+++ b/src/cs/UFconfig.h
@@ -0,0 +1,118 @@
+/* ========================================================================== */
+/* === UFconfig.h =========================================================== */
+/* ========================================================================== */
+
+/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages
+ * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others).
+ *
+ * UFconfig.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 UFconfig.mk:
+ *
+ * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \
+ *   -D'UF_long_id="%lld"'
+ *
+ * This file defines UF_long as either long (on all but _WIN64) or
+ * __int64 on Windows 64.  The intent is that a UF_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) 2007, University of Florida.  No licensing restrictions
+ * apply to this file or to the UFconfig directory.  Author: Timothy A. Davis.
+ */
+
+#ifndef _UFCONFIG_H
+#define _UFCONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <limits.h>
+
+/* ========================================================================== */
+/* === UF_long ============================================================== */
+/* ========================================================================== */
+
+#ifndef UF_long
+
+#ifdef _WIN64
+
+#define UF_long __int64
+#define UF_long_max _I64_MAX
+#define UF_long_id "%I64d"
+
+#else
+
+#define UF_long long
+#define UF_long_max LONG_MAX
+#define UF_long_id "%ld"
+
+#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 Version 3.3.0 contains the following packages:
+ *
+ *  AMD		    version 2.2.0
+ *  CAMD	    version 2.2.0
+ *  COLAMD	    version 2.7.1
+ *  CCOLAMD	    version 2.7.1
+ *  CHOLMOD	    version 1.7.1
+ *  CSparse	    version 2.2.3
+ *  CXSparse	    version 2.2.3
+ *  KLU		    version 1.1.0
+ *  BTF		    version 1.0.1
+ *  LDL		    version 2.0.1
+ *  UFconfig	    version number is the same as SuiteSparse
+ *  UMFPACK	    version 5.3.0
+ *  RBio	    version 1.1.1
+ *  UFcollection    version 1.2.0
+ *  LINFACTOR       version 1.1.0
+ *  MESHND          version 1.1.1
+ *  SSMULT          version 2.0.0
+ *  MATLAB_Tools    no specific version number
+ *  SuiteSparseQR   version 1.1.1
+ *
+ * Other package dependencies:
+ *  BLAS	    required by CHOLMOD and UMFPACK
+ *  LAPACK	    required by CHOLMOD
+ *  METIS 4.0.1	    required by CHOLMOD (optional) and KLU (optional)
+ */
+
+#define SUITESPARSE_DATE "Mar 24, 2009"
+#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define SUITESPARSE_MAIN_VERSION 3
+#define SUITESPARSE_SUB_VERSION 3
+#define SUITESPARSE_SUBSUB_VERSION 0
+#define SUITESPARSE_VERSION \
+    SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/cs/cs.h b/src/cs/cs.h
new file mode 100644
index 0000000..abaf267
--- /dev/null
+++ b/src/cs/cs.h
@@ -0,0 +1,756 @@
+/*
+ * 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
+ */
+
+#ifndef _CXS_H
+#define _CXS_H
+#include <stdlib.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#endif
+
+
+#ifdef __cplusplus
+#ifndef NCOMPLEX
+#include <complex>
+typedef std::complex<double> cs_complex_t ;
+#endif
+extern "C" {
+#else
+#ifndef NCOMPLEX
+#include <complex.h>
+#define cs_complex_t double _Complex
+#endif
+#endif
+
+#define CS_VER 2                    /* CXSparse Version 2.2.3 */
+#define CS_SUBVER 2
+#define CS_SUBSUB 3
+#define CS_DATE "Mar 24, 2009"      /* CXSparse release date */
+#define CS_COPYRIGHT "Copyright (c) Timothy A. Davis, 2006-2009"
+#define CXSPARSE
+
+/* define UF_long */
+#include "UFconfig.h"
+
+/* -------------------------------------------------------------------------- */
+/* double/int version of CXSparse */
+/* -------------------------------------------------------------------------- */
+
+/* --- primary CSparse routines and data structures ------------------------- */
+
+typedef struct cs_di_sparse  /* matrix in compressed-column or triplet form */
+{
+    int nzmax ;     /* maximum number of entries */
+    int m ;         /* number of rows */
+    int n ;         /* number of columns */
+    int *p ;        /* column pointers (size n+1) or col indices (size nzmax) */
+    int *i ;        /* row indices, size nzmax */
+    double *x ;     /* numerical values, size nzmax */
+    int nz ;        /* # of entries in triplet matrix, -1 for compressed-col */
+} cs_di ;
+
+cs_di *cs_di_add (const cs_di *A, const cs_di *B, double alpha, double beta) ;
+int cs_di_cholsol (int order, const cs_di *A, double *b) ;
+int cs_di_dupl (cs_di *A) ;
+int cs_di_entry (cs_di *T, int i, int j, double x) ;
+int cs_di_lusol (int order, const cs_di *A, double *b, double tol) ;
+int cs_di_gaxpy (const cs_di *A, const double *x, double *y) ;
+cs_di *cs_di_multiply (const cs_di *A, const cs_di *B) ;
+int cs_di_qrsol (int order, const cs_di *A, double *b) ;
+cs_di *cs_di_transpose (const cs_di *A, int values) ;
+cs_di *cs_di_compress (const cs_di *T) ;
+double cs_di_norm (const cs_di *A) ;
+int cs_di_print (const cs_di *A, int brief) ;
+cs_di *cs_di_load (FILE *f) ;
+
+/* utilities */
+void *cs_di_calloc (int n, size_t size) ;
+void *cs_di_free (void *p) ;
+void *cs_di_realloc (void *p, int n, size_t size, int *ok) ;
+cs_di *cs_di_spalloc (int m, int n, int nzmax, int values, int t) ;
+cs_di *cs_di_spfree (cs_di *A) ;
+int cs_di_sprealloc (cs_di *A, int nzmax) ;
+void *cs_di_malloc (int n, size_t size) ;
+
+/* --- secondary CSparse routines and data structures ----------------------- */
+
+typedef struct cs_di_symbolic  /* symbolic Cholesky, LU, or QR analysis */
+{
+    int *pinv ;     /* inverse row perm. for QR, fill red. perm for Chol */
+    int *q ;        /* fill-reducing column permutation for LU and QR */
+    int *parent ;   /* elimination tree for Cholesky and QR */
+    int *cp ;       /* column pointers for Cholesky, row counts for QR */
+    int *leftmost ; /* leftmost[i] = min(find(A(i,:))), for QR */
+    int m2 ;        /* # of rows for QR, after adding fictitious rows */
+    double lnz ;    /* # entries in L for LU or Cholesky; in V for QR */
+    double unz ;    /* # entries in U for LU; in R for QR */
+} cs_dis ;
+
+typedef struct cs_di_numeric   /* numeric Cholesky, LU, or QR factorization */
+{
+    cs_di *L ;      /* L for LU and Cholesky, V for QR */
+    cs_di *U ;      /* U for LU, r for QR, not used for Cholesky */
+    int *pinv ;     /* partial pivoting for LU */
+    double *B ;     /* beta [0..n-1] for QR */
+} cs_din ;
+
+typedef struct cs_di_dmperm_results    /* cs_di_dmperm or cs_di_scc output */
+{
+    int *p ;        /* size m, row permutation */
+    int *q ;        /* size n, column permutation */
+    int *r ;        /* size nb+1, block k is rows r[k] to r[k+1]-1 in A(p,q) */
+    int *s ;        /* size nb+1, block k is cols s[k] to s[k+1]-1 in A(p,q) */
+    int nb ;        /* # of blocks in fine dmperm decomposition */
+    int rr [5] ;    /* coarse row decomposition */
+    int cc [5] ;    /* coarse column decomposition */
+} cs_did ;
+
+int *cs_di_amd (int order, const cs_di *A) ;
+cs_din *cs_di_chol (const cs_di *A, const cs_dis *S) ;
+cs_did *cs_di_dmperm (const cs_di *A, int seed) ;
+int cs_di_droptol (cs_di *A, double tol) ;
+int cs_di_dropzeros (cs_di *A) ;
+int cs_di_happly (const cs_di *V, int i, double beta, double *x) ;
+int cs_di_ipvec (const int *p, const double *b, double *x, int n) ;
+int cs_di_lsolve (const cs_di *L, double *x) ;
+int cs_di_ltsolve (const cs_di *L, double *x) ;
+cs_din *cs_di_lu (const cs_di *A, const cs_dis *S, double tol) ;
+cs_di *cs_di_permute (const cs_di *A, const int *pinv, const int *q,
+    int values) ;
+int *cs_di_pinv (const int *p, int n) ;
+int cs_di_pvec (const int *p, const double *b, double *x, int n) ;
+cs_din *cs_di_qr (const cs_di *A, const cs_dis *S) ;
+cs_dis *cs_di_schol (int order, const cs_di *A) ;
+cs_dis *cs_di_sqr (int order, const cs_di *A, int qr) ;
+cs_di *cs_di_symperm (const cs_di *A, const int *pinv, int values) ;
+int cs_di_usolve (const cs_di *U, double *x) ;
+int cs_di_utsolve (const cs_di *U, double *x) ;
+int cs_di_updown (cs_di *L, int sigma, const cs_di *C, const int *parent) ;
+
+/* utilities */
+cs_dis *cs_di_sfree (cs_dis *S) ;
+cs_din *cs_di_nfree (cs_din *N) ;
+cs_did *cs_di_dfree (cs_did *D) ;
+
+/* --- tertiary CSparse routines -------------------------------------------- */
+
+int *cs_di_counts (const cs_di *A, const int *parent, const int *post,
+    int ata) ;
+double cs_di_cumsum (int *p, int *c, int n) ;
+int cs_di_dfs (int j, cs_di *G, int top, int *xi, int *pstack,
+    const int *pinv) ;
+int *cs_di_etree (const cs_di *A, int ata) ;
+int cs_di_fkeep (cs_di *A, int (*fkeep) (int, int, double, void *),
+    void *other) ;
+double cs_di_house (double *x, double *beta, int n) ;
+int *cs_di_maxtrans (const cs_di *A, int seed) ;
+int *cs_di_post (const int *parent, int n) ;
+cs_did *cs_di_scc (cs_di *A) ;
+int cs_di_scatter (const cs_di *A, int j, double beta, int *w, double *x,
+    int mark, cs_di *C, int nz) ;
+int cs_di_tdfs (int j, int k, int *head, const int *next, int *post,
+    int *stack) ;
+int cs_di_leaf (int i, int j, const int *first, int *maxfirst, int *prevleaf,
+    int *ancestor, int *jleaf) ;
+int cs_di_reach (cs_di *G, const cs_di *B, int k, int *xi, const int *pinv) ;
+int cs_di_spsolve (cs_di *L, const cs_di *B, int k, int *xi, double *x,
+    const int *pinv, int lo) ;
+int cs_di_ereach (const cs_di *A, int k, const int *parent, int *s, int *w) ;
+int *cs_di_randperm (int n, int seed) ;
+
+/* utilities */
+cs_did *cs_di_dalloc (int m, int n) ;
+cs_di *cs_di_done (cs_di *C, void *w, void *x, int ok) ;
+int *cs_di_idone (int *p, cs_di *C, void *w, int ok) ;
+cs_din *cs_di_ndone (cs_din *N, cs_di *C, void *w, void *x, int ok) ;
+cs_did *cs_di_ddone (cs_did *D, cs_di *C, void *w, int ok) ;
+
+
+/* -------------------------------------------------------------------------- */
+/* double/UF_long version of CXSparse */
+/* -------------------------------------------------------------------------- */
+
+/* --- primary CSparse routines and data structures ------------------------- */
+
+typedef struct cs_dl_sparse  /* matrix in compressed-column or triplet form */
+{
+    UF_long nzmax ; /* maximum number of entries */
+    UF_long m ;     /* number of rows */
+    UF_long n ;     /* number of columns */
+    UF_long *p ;    /* column pointers (size n+1) or col indlces (size nzmax) */
+    UF_long *i ;    /* row indices, size nzmax */
+    double *x ;     /* numerical values, size nzmax */
+    UF_long nz ;    /* # of entries in triplet matrix, -1 for compressed-col */
+} cs_dl ;
+
+cs_dl *cs_dl_add (const cs_dl *A, const cs_dl *B, double alpha, double beta) ;
+UF_long cs_dl_cholsol (UF_long order, const cs_dl *A, double *b) ;
+UF_long cs_dl_dupl (cs_dl *A) ;
+UF_long cs_dl_entry (cs_dl *T, UF_long i, UF_long j, double x) ;
+UF_long cs_dl_lusol (UF_long order, const cs_dl *A, double *b, double tol) ;
+UF_long cs_dl_gaxpy (const cs_dl *A, const double *x, double *y) ;
+cs_dl *cs_dl_multiply (const cs_dl *A, const cs_dl *B) ;
+UF_long cs_dl_qrsol (UF_long order, const cs_dl *A, double *b) ;
+cs_dl *cs_dl_transpose (const cs_dl *A, UF_long values) ;
+cs_dl *cs_dl_compress (const cs_dl *T) ;
+double cs_dl_norm (const cs_dl *A) ;
+UF_long cs_dl_print (const cs_dl *A, UF_long brief) ;
+cs_dl *cs_dl_load (FILE *f) ;
+
+/* utilities */
+void *cs_dl_calloc (UF_long n, size_t size) ;
+void *cs_dl_free (void *p) ;
+void *cs_dl_realloc (void *p, UF_long n, size_t size, UF_long *ok) ;
+cs_dl *cs_dl_spalloc (UF_long m, UF_long n, UF_long nzmax, UF_long values,
+    UF_long t) ;
+cs_dl *cs_dl_spfree (cs_dl *A) ;
+UF_long cs_dl_sprealloc (cs_dl *A, UF_long nzmax) ;
+void *cs_dl_malloc (UF_long n, size_t size) ;
+
+/* --- secondary CSparse routines and data structures ----------------------- */
+
+typedef struct cs_dl_symbolic  /* symbolic Cholesky, LU, or QR analysis */
+{
+    UF_long *pinv ;     /* inverse row perm. for QR, fill red. perm for Chol */
+    UF_long *q ;        /* fill-reducing column permutation for LU and QR */
+    UF_long *parent ;   /* elimination tree for Cholesky and QR */
+    UF_long *cp ;       /* column pointers for Cholesky, row counts for QR */
+    UF_long *leftmost ; /* leftmost[i] = min(find(A(i,:))), for QR */
+    UF_long m2 ;        /* # of rows for QR, after adding fictitious rows */
+    double lnz ;        /* # entries in L for LU or Cholesky; in V for QR */
+    double unz ;        /* # entries in U for LU; in R for QR */
+} cs_dls ;
+
+typedef struct cs_dl_numeric   /* numeric Cholesky, LU, or QR factorization */
+{
+    cs_dl *L ;      /* L for LU and Cholesky, V for QR */
+    cs_dl *U ;      /* U for LU, r for QR, not used for Cholesky */
+    UF_long *pinv ; /* partial pivoting for LU */
+    double *B ;     /* beta [0..n-1] for QR */
+} cs_dln ;
+
+typedef struct cs_dl_dmperm_results    /* cs_dl_dmperm or cs_dl_scc output */
+{
+    UF_long *p ;    /* size m, row permutation */
+    UF_long *q ;    /* size n, column permutation */
+    UF_long *r ;    /* size nb+1, block k is rows r[k] to r[k+1]-1 in A(p,q) */
+    UF_long *s ;    /* size nb+1, block k is cols s[k] to s[k+1]-1 in A(p,q) */
+    UF_long nb ;    /* # of blocks in fine dmperm decomposition */
+    UF_long rr [5] ;    /* coarse row decomposition */
+    UF_long cc [5] ;    /* coarse column decomposition */
+} cs_dld ;
+
+UF_long *cs_dl_amd (UF_long order, const cs_dl *A) ;
+cs_dln *cs_dl_chol (const cs_dl *A, const cs_dls *S) ;
+cs_dld *cs_dl_dmperm (const cs_dl *A, UF_long seed) ;
+UF_long cs_dl_droptol (cs_dl *A, double tol) ;
+UF_long cs_dl_dropzeros (cs_dl *A) ;
+UF_long cs_dl_happly (const cs_dl *V, UF_long i, double beta, double *x) ;
+UF_long cs_dl_ipvec (const UF_long *p, const double *b, double *x, UF_long n) ;
+UF_long cs_dl_lsolve (const cs_dl *L, double *x) ;
+UF_long cs_dl_ltsolve (const cs_dl *L, double *x) ;
+cs_dln *cs_dl_lu (const cs_dl *A, const cs_dls *S, double tol) ;
+cs_dl *cs_dl_permute (const cs_dl *A, const UF_long *pinv, const UF_long *q,
+    UF_long values) ;
+UF_long *cs_dl_pinv (const UF_long *p, UF_long n) ;
+UF_long cs_dl_pvec (const UF_long *p, const double *b, double *x, UF_long n) ;
+cs_dln *cs_dl_qr (const cs_dl *A, const cs_dls *S) ;
+cs_dls *cs_dl_schol (UF_long order, const cs_dl *A) ;
+cs_dls *cs_dl_sqr (UF_long order, const cs_dl *A, UF_long qr) ;
+cs_dl *cs_dl_symperm (const cs_dl *A, const UF_long *pinv, UF_long values) ;
+UF_long cs_dl_usolve (const cs_dl *U, double *x) ;
+UF_long cs_dl_utsolve (const cs_dl *U, double *x) ;
+UF_long cs_dl_updown (cs_dl *L, UF_long sigma, const cs_dl *C,
+    const UF_long *parent) ;
+
+/* utilities */
+cs_dls *cs_dl_sfree (cs_dls *S) ;
+cs_dln *cs_dl_nfree (cs_dln *N) ;
+cs_dld *cs_dl_dfree (cs_dld *D) ;
+
+/* --- tertiary CSparse routines -------------------------------------------- */
+
+UF_long *cs_dl_counts (const cs_dl *A, const UF_long *parent,
+    const UF_long *post, UF_long ata) ;
+double cs_dl_cumsum (UF_long *p, UF_long *c, UF_long n) ;
+UF_long cs_dl_dfs (UF_long j, cs_dl *G, UF_long top, UF_long *xi,
+    UF_long *pstack, const UF_long *pinv) ;
+UF_long *cs_dl_etree (const cs_dl *A, UF_long ata) ;
+UF_long cs_dl_fkeep (cs_dl *A,
+    UF_long (*fkeep) (UF_long, UF_long, double, void *), void *other) ;
+double cs_dl_house (double *x, double *beta, UF_long n) ;
+UF_long *cs_dl_maxtrans (const cs_dl *A, UF_long seed) ;
+UF_long *cs_dl_post (const UF_long *parent, UF_long n) ;
+cs_dld *cs_dl_scc (cs_dl *A) ;
+UF_long cs_dl_scatter (const cs_dl *A, UF_long j, double beta, UF_long *w,
+    double *x, UF_long mark,cs_dl *C, UF_long nz) ;
+UF_long cs_dl_tdfs (UF_long j, UF_long k, UF_long *head, const UF_long *next,
+    UF_long *post, UF_long *stack) ;
+UF_long cs_dl_leaf (UF_long i, UF_long j, const UF_long *first,
+    UF_long *maxfirst, UF_long *prevleaf, UF_long *ancestor, UF_long *jleaf) ;
+UF_long cs_dl_reach (cs_dl *G, const cs_dl *B, UF_long k, UF_long *xi,
+    const UF_long *pinv) ;
+UF_long cs_dl_spsolve (cs_dl *L, const cs_dl *B, UF_long k, UF_long *xi,
+    double *x, const UF_long *pinv, UF_long lo) ;
+UF_long cs_dl_ereach (const cs_dl *A, UF_long k, const UF_long *parent,
+    UF_long *s, UF_long *w) ;
+UF_long *cs_dl_randperm (UF_long n, UF_long seed) ;
+
+/* utilities */
+cs_dld *cs_dl_dalloc (UF_long m, UF_long n) ;
+cs_dl *cs_dl_done (cs_dl *C, void *w, void *x, UF_long ok) ;
+UF_long *cs_dl_idone (UF_long *p, cs_dl *C, void *w, UF_long ok) ;
+cs_dln *cs_dl_ndone (cs_dln *N, cs_dl *C, void *w, void *x, UF_long ok) ;
+cs_dld *cs_dl_ddone (cs_dld *D, cs_dl *C, void *w, UF_long ok) ;
+
+
+/* -------------------------------------------------------------------------- */
+/* complex/int version of CXSparse */
+/* -------------------------------------------------------------------------- */
+
+#ifndef NCOMPLEX
+
+/* --- primary CSparse routines and data structures ------------------------- */
+
+typedef struct cs_ci_sparse  /* matrix in compressed-column or triplet form */
+{
+    int nzmax ;     /* maximum number of entries */
+    int m ;         /* number of rows */
+    int n ;         /* number of columns */
+    int *p ;        /* column pointers (size n+1) or col indices (size nzmax) */
+    int *i ;        /* row indices, size nzmax */
+    cs_complex_t *x ;    /* numerical values, size nzmax */
+    int nz ;        /* # of entries in triplet matrix, -1 for compressed-col */
+} cs_ci ;
+
+cs_ci *cs_ci_add (const cs_ci *A, const cs_ci *B, cs_complex_t alpha,
+    cs_complex_t beta) ;
+int cs_ci_cholsol (int order, const cs_ci *A, cs_complex_t *b) ;
+int cs_ci_dupl (cs_ci *A) ;
+int cs_ci_entry (cs_ci *T, int i, int j, cs_complex_t x) ;
+int cs_ci_lusol (int order, const cs_ci *A, cs_complex_t *b, double tol) ;
+int cs_ci_gaxpy (const cs_ci *A, const cs_complex_t *x, cs_complex_t *y) ;
+cs_ci *cs_ci_multiply (const cs_ci *A, const cs_ci *B) ;
+int cs_ci_qrsol (int order, const cs_ci *A, cs_complex_t *b) ;
+cs_ci *cs_ci_transpose (const cs_ci *A, int values) ;
+cs_ci *cs_ci_compress (const cs_ci *T) ;
+double cs_ci_norm (const cs_ci *A) ;
+int cs_ci_print (const cs_ci *A, int brief) ;
+cs_ci *cs_ci_load (FILE *f) ;
+
+/* utilities */
+void *cs_ci_calloc (int n, size_t size) ;
+void *cs_ci_free (void *p) ;
+void *cs_ci_realloc (void *p, int n, size_t size, int *ok) ;
+cs_ci *cs_ci_spalloc (int m, int n, int nzmax, int values, int t) ;
+cs_ci *cs_ci_spfree (cs_ci *A) ;
+int cs_ci_sprealloc (cs_ci *A, int nzmax) ;
+void *cs_ci_malloc (int n, size_t size) ;
+
+/* --- secondary CSparse routines and data structures ----------------------- */
+
+typedef struct cs_ci_symbolic  /* symbolic Cholesky, LU, or QR analysis */
+{
+    int *pinv ;     /* inverse row perm. for QR, fill red. perm for Chol */
+    int *q ;        /* fill-reducing column permutation for LU and QR */
+    int *parent ;   /* elimination tree for Cholesky and QR */
+    int *cp ;       /* column pointers for Cholesky, row counts for QR */
+    int *leftmost ; /* leftmost[i] = min(find(A(i,:))), for QR */
+    int m2 ;        /* # of rows for QR, after adding fictitious rows */
+    double lnz ;    /* # entries in L for LU or Cholesky; in V for QR */
+    double unz ;    /* # entries in U for LU; in R for QR */
+} cs_cis ;
+
+typedef struct cs_ci_numeric   /* numeric Cholesky, LU, or QR factorization */
+{
+    cs_ci *L ;      /* L for LU and Cholesky, V for QR */
+    cs_ci *U ;      /* U for LU, r for QR, not used for Cholesky */
+    int *pinv ;     /* partial pivoting for LU */
+    double *B ;     /* beta [0..n-1] for QR */
+} cs_cin ;
+
+typedef struct cs_ci_dmperm_results    /* cs_ci_dmperm or cs_ci_scc output */
+{
+    int *p ;        /* size m, row permutation */
+    int *q ;        /* size n, column permutation */
+    int *r ;        /* size nb+1, block k is rows r[k] to r[k+1]-1 in A(p,q) */
+    int *s ;        /* size nb+1, block k is cols s[k] to s[k+1]-1 in A(p,q) */
+    int nb ;        /* # of blocks in fine dmperm decomposition */
+    int rr [5] ;    /* coarse row decomposition */
+    int cc [5] ;    /* coarse column decomposition */
+} cs_cid ;
+
+int *cs_ci_amd (int order, const cs_ci *A) ;
+cs_cin *cs_ci_chol (const cs_ci *A, const cs_cis *S) ;
+cs_cid *cs_ci_dmperm (const cs_ci *A, int seed) ;
+int cs_ci_droptol (cs_ci *A, double tol) ;
+int cs_ci_dropzeros (cs_ci *A) ;
+int cs_ci_happly (const cs_ci *V, int i, double beta, cs_complex_t *x) ;
+int cs_ci_ipvec (const int *p, const cs_complex_t *b, cs_complex_t *x, int n) ;
+int cs_ci_lsolve (const cs_ci *L, cs_complex_t *x) ;
+int cs_ci_ltsolve (const cs_ci *L, cs_complex_t *x) ;
+cs_cin *cs_ci_lu (const cs_ci *A, const cs_cis *S, double tol) ;
+cs_ci *cs_ci_permute (const cs_ci *A, const int *pinv, const int *q,
+    int values) ;
+int *cs_ci_pinv (const int *p, int n) ;
+int cs_ci_pvec (const int *p, const cs_complex_t *b, cs_complex_t *x, int n) ;
+cs_cin *cs_ci_qr (const cs_ci *A, const cs_cis *S) ;
+cs_cis *cs_ci_schol (int order, const cs_ci *A) ;
+cs_cis *cs_ci_sqr (int order, const cs_ci *A, int qr) ;
+cs_ci *cs_ci_symperm (const cs_ci *A, const int *pinv, int values) ;
+int cs_ci_usolve (const cs_ci *U, cs_complex_t *x) ;
+int cs_ci_utsolve (const cs_ci *U, cs_complex_t *x) ;
+int cs_ci_updown (cs_ci *L, int sigma, const cs_ci *C, const int *parent) ;
+
+/* utilities */
+cs_cis *cs_ci_sfree (cs_cis *S) ;
+cs_cin *cs_ci_nfree (cs_cin *N) ;
+cs_cid *cs_ci_dfree (cs_cid *D) ;
+
+/* --- tertiary CSparse routines -------------------------------------------- */
+
+int *cs_ci_counts (const cs_ci *A, const int *parent, const int *post,
+    int ata) ;
+double cs_ci_cumsum (int *p, int *c, int n) ;
+int cs_ci_dfs (int j, cs_ci *G, int top, int *xi, int *pstack,
+    const int *pinv) ;
+int *cs_ci_etree (const cs_ci *A, int ata) ;
+int cs_ci_fkeep (cs_ci *A, int (*fkeep) (int, int, cs_complex_t, void *),
+    void *other) ;
+cs_complex_t cs_ci_house (cs_complex_t *x, double *beta, int n) ;
+int *cs_ci_maxtrans (const cs_ci *A, int seed) ;
+int *cs_ci_post (const int *parent, int n) ;
+cs_cid *cs_ci_scc (cs_ci *A) ;
+int cs_ci_scatter (const cs_ci *A, int j, cs_complex_t beta, int *w, 
+    cs_complex_t *x, int mark,cs_ci *C, int nz) ;
+int cs_ci_tdfs (int j, int k, int *head, const int *next, int *post,
+    int *stack) ;
+int cs_ci_leaf (int i, int j, const int *first, int *maxfirst, int *prevleaf,
+    int *ancestor, int *jleaf) ;
+int cs_ci_reach (cs_ci *G, const cs_ci *B, int k, int *xi, const int *pinv) ;
+int cs_ci_spsolve (cs_ci *L, const cs_ci *B, int k, int *xi, 
+    cs_complex_t *x, const int *pinv, int lo) ;
+int cs_ci_ereach (const cs_ci *A, int k, const int *parent, int *s, int *w) ;
+int *cs_ci_randperm (int n, int seed) ;
+
+/* utilities */
+cs_cid *cs_ci_dalloc (int m, int n) ;
+cs_ci *cs_ci_done (cs_ci *C, void *w, void *x, int ok) ;
+int *cs_ci_idone (int *p, cs_ci *C, void *w, int ok) ;
+cs_cin *cs_ci_ndone (cs_cin *N, cs_ci *C, void *w, void *x, int ok) ;
+cs_cid *cs_ci_ddone (cs_cid *D, cs_ci *C, void *w, int ok) ;
+
+
+/* -------------------------------------------------------------------------- */
+/* complex/UF_long version of CXSparse */
+/* -------------------------------------------------------------------------- */
+
+/* --- primary CSparse routines and data structures ------------------------- */
+
+typedef struct cs_cl_sparse  /* matrix in compressed-column or triplet form */
+{
+    UF_long nzmax ; /* maximum number of entries */
+    UF_long m ;     /* number of rows */
+    UF_long n ;     /* number of columns */
+    UF_long *p ;    /* column pointers (size n+1) or col indlces (size nzmax) */
+    UF_long *i ;    /* row indices, size nzmax */
+    cs_complex_t *x ;    /* numerical values, size nzmax */
+    UF_long nz ;    /* # of entries in triplet matrix, -1 for compressed-col */
+} cs_cl ;
+
+cs_cl *cs_cl_add (const cs_cl *A, const cs_cl *B, cs_complex_t alpha,
+    cs_complex_t beta) ;
+UF_long cs_cl_cholsol (UF_long order, const cs_cl *A, cs_complex_t *b) ;
+UF_long cs_cl_dupl (cs_cl *A) ;
+UF_long cs_cl_entry (cs_cl *T, UF_long i, UF_long j, cs_complex_t x) ;
+UF_long cs_cl_lusol (UF_long order, const cs_cl *A, cs_complex_t *b,
+    double tol) ;
+UF_long cs_cl_gaxpy (const cs_cl *A, const cs_complex_t *x, cs_complex_t *y) ;
+cs_cl *cs_cl_multiply (const cs_cl *A, const cs_cl *B) ;
+UF_long cs_cl_qrsol (UF_long order, const cs_cl *A, cs_complex_t *b) ;
+cs_cl *cs_cl_transpose (const cs_cl *A, UF_long values) ;
+cs_cl *cs_cl_compress (const cs_cl *T) ;
+double cs_cl_norm (const cs_cl *A) ;
+UF_long cs_cl_print (const cs_cl *A, UF_long brief) ;
+cs_cl *cs_cl_load (FILE *f) ;
+
+/* utilities */
+void *cs_cl_calloc (UF_long n, size_t size) ;
+void *cs_cl_free (void *p) ;
+void *cs_cl_realloc (void *p, UF_long n, size_t size, UF_long *ok) ;
+cs_cl *cs_cl_spalloc (UF_long m, UF_long n, UF_long nzmax, UF_long values,
+    UF_long t) ;
+cs_cl *cs_cl_spfree (cs_cl *A) ;
+UF_long cs_cl_sprealloc (cs_cl *A, UF_long nzmax) ;
+void *cs_cl_malloc (UF_long n, size_t size) ;
+
+/* --- secondary CSparse routines and data structures ----------------------- */
+
+typedef struct cs_cl_symbolic  /* symbolic Cholesky, LU, or QR analysis */
+{
+    UF_long *pinv ;     /* inverse row perm. for QR, fill red. perm for Chol */
+    UF_long *q ;        /* fill-reducing column permutation for LU and QR */
+    UF_long *parent ;   /* elimination tree for Cholesky and QR */
+    UF_long *cp ;       /* column pointers for Cholesky, row counts for QR */
+    UF_long *leftmost ; /* leftmost[i] = min(find(A(i,:))), for QR */
+    UF_long m2 ;        /* # of rows for QR, after adding fictitious rows */
+    double lnz ;        /* # entries in L for LU or Cholesky; in V for QR */
+    double unz ;        /* # entries in U for LU; in R for QR */
+} cs_cls ;
+
+typedef struct cs_cl_numeric   /* numeric Cholesky, LU, or QR factorization */
+{
+    cs_cl *L ;          /* L for LU and Cholesky, V for QR */
+    cs_cl *U ;          /* U for LU, r for QR, not used for Cholesky */
+    UF_long *pinv ;     /* partial pivoting for LU */
+    double *B ;         /* beta [0..n-1] for QR */
+} cs_cln ;
+
+typedef struct cs_cl_dmperm_results    /* cs_cl_dmperm or cs_cl_scc output */
+{
+    UF_long *p ;    /* size m, row permutation */
+    UF_long *q ;    /* size n, column permutation */
+    UF_long *r ;    /* size nb+1, block k is rows r[k] to r[k+1]-1 in A(p,q) */
+    UF_long *s ;    /* size nb+1, block k is cols s[k] to s[k+1]-1 in A(p,q) */
+    UF_long nb ;    /* # of blocks in fine dmperm decomposition */
+    UF_long rr [5] ;   /* coarse row decomposition */
+    UF_long cc [5] ;   /* coarse column decomposition */
+} cs_cld ;
+
+UF_long *cs_cl_amd (UF_long order, const cs_cl *A) ;
+cs_cln *cs_cl_chol (const cs_cl *A, const cs_cls *S) ;
+cs_cld *cs_cl_dmperm (const cs_cl *A, UF_long seed) ;
+UF_long cs_cl_droptol (cs_cl *A, double tol) ;
+UF_long cs_cl_dropzeros (cs_cl *A) ;
+UF_long cs_cl_happly (const cs_cl *V, UF_long i, double beta, cs_complex_t *x) ;
+UF_long cs_cl_ipvec (const UF_long *p, const cs_complex_t *b,
+    cs_complex_t *x, UF_long n) ;
+UF_long cs_cl_lsolve (const cs_cl *L, cs_complex_t *x) ;
+UF_long cs_cl_ltsolve (const cs_cl *L, cs_complex_t *x) ;
+cs_cln *cs_cl_lu (const cs_cl *A, const cs_cls *S, double tol) ;
+cs_cl *cs_cl_permute (const cs_cl *A, const UF_long *pinv, const UF_long *q,
+    UF_long values) ;
+UF_long *cs_cl_pinv (const UF_long *p, UF_long n) ;
+UF_long cs_cl_pvec (const UF_long *p, const cs_complex_t *b,
+    cs_complex_t *x, UF_long n) ;
+cs_cln *cs_cl_qr (const cs_cl *A, const cs_cls *S) ;
+cs_cls *cs_cl_schol (UF_long order, const cs_cl *A) ;
+cs_cls *cs_cl_sqr (UF_long order, const cs_cl *A, UF_long qr) ;
+cs_cl *cs_cl_symperm (const cs_cl *A, const UF_long *pinv, UF_long values) ;
+UF_long cs_cl_usolve (const cs_cl *U, cs_complex_t *x) ;
+UF_long cs_cl_utsolve (const cs_cl *U, cs_complex_t *x) ;
+UF_long cs_cl_updown (cs_cl *L, UF_long sigma, const cs_cl *C,
+    const UF_long *parent) ;
+
+/* utilities */
+cs_cls *cs_cl_sfree (cs_cls *S) ;
+cs_cln *cs_cl_nfree (cs_cln *N) ;
+cs_cld *cs_cl_dfree (cs_cld *D) ;
+
+/* --- tertiary CSparse routines -------------------------------------------- */
+
+UF_long *cs_cl_counts (const cs_cl *A, const UF_long *parent,
+    const UF_long *post, UF_long ata) ;
+double cs_cl_cumsum (UF_long *p, UF_long *c, UF_long n) ;
+UF_long cs_cl_dfs (UF_long j, cs_cl *G, UF_long top, UF_long *xi,
+    UF_long *pstack, const UF_long *pinv) ;
+UF_long *cs_cl_etree (const cs_cl *A, UF_long ata) ;
+UF_long cs_cl_fkeep (cs_cl *A,
+    UF_long (*fkeep) (UF_long, UF_long, cs_complex_t, void *), void *other) ;
+cs_complex_t cs_cl_house (cs_complex_t *x, double *beta, UF_long n) ;
+UF_long *cs_cl_maxtrans (const cs_cl *A, UF_long seed) ;
+UF_long *cs_cl_post (const UF_long *parent, UF_long n) ;
+cs_cld *cs_cl_scc (cs_cl *A) ;
+UF_long cs_cl_scatter (const cs_cl *A, UF_long j, cs_complex_t beta,
+    UF_long *w, cs_complex_t *x, UF_long mark,cs_cl *C, UF_long nz) ;
+UF_long cs_cl_tdfs (UF_long j, UF_long k, UF_long *head, const UF_long *next,
+    UF_long *post, UF_long *stack) ;
+UF_long cs_cl_leaf (UF_long i, UF_long j, const UF_long *first,
+    UF_long *maxfirst, UF_long *prevleaf, UF_long *ancestor, UF_long *jleaf) ;
+UF_long cs_cl_reach (cs_cl *G, const cs_cl *B, UF_long k, UF_long *xi,
+    const UF_long *pinv) ;
+UF_long cs_cl_spsolve (cs_cl *L, const cs_cl *B, UF_long k, UF_long *xi, 
+    cs_complex_t *x, const UF_long *pinv, UF_long lo) ;
+UF_long cs_cl_ereach (const cs_cl *A, UF_long k, const UF_long *parent,
+    UF_long *s, UF_long *w) ;
+UF_long *cs_cl_randperm (UF_long n, UF_long seed) ;
+
+/* utilities */
+cs_cld *cs_cl_dalloc (UF_long m, UF_long n) ;
+cs_cl *cs_cl_done (cs_cl *C, void *w, void *x, UF_long ok) ;
+UF_long *cs_cl_idone (UF_long *p, cs_cl *C, void *w, UF_long ok) ;
+cs_cln *cs_cl_ndone (cs_cln *N, cs_cl *C, void *w, void *x, UF_long ok) ;
+cs_cld *cs_cl_ddone (cs_cld *D, cs_cl *C, void *w, UF_long ok) ;
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Macros for constructing each version of CSparse */
+/* -------------------------------------------------------------------------- */
+
+#ifdef CS_LONG
+#define CS_INT UF_long
+#define CS_INT_MAX UF_long_max
+#define CS_ID UF_long_id
+#ifdef CS_COMPLEX
+#define CS_ENTRY cs_complex_t
+#define CS_NAME(nm) cs_cl ## nm
+#define cs cs_cl
+#else
+#define CS_ENTRY double
+#define CS_NAME(nm) cs_dl ## nm
+#define cs cs_dl
+#endif
+#else
+#define CS_INT int
+#define CS_INT_MAX INT_MAX
+#define CS_ID "%d"
+#ifdef CS_COMPLEX
+#define CS_ENTRY cs_complex_t
+#define CS_NAME(nm) cs_ci ## nm
+#define cs cs_ci
+#else
+#define CS_ENTRY double
+#define CS_NAME(nm) cs_di ## nm
+#define cs cs_di
+#endif
+#endif
+
+#ifdef CS_COMPLEX
+#define CS_REAL(x) creal(x)
+#define CS_IMAG(x) cimag(x)
+#define CS_CONJ(x) conj(x)
+#define CS_ABS(x) cabs(x)
+#else
+#define CS_REAL(x) (x)
+#define CS_IMAG(x) (0.)
+#define CS_CONJ(x) (x)
+#define CS_ABS(x) fabs(x)
+#endif
+
+#define CS_MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define CS_MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define CS_FLIP(i) (-(i)-2)
+#define CS_UNFLIP(i) (((i) < 0) ? CS_FLIP(i) : (i))
+#define CS_MARKED(w,j) (w [j] < 0)
+#define CS_MARK(w,j) { w [j] = CS_FLIP (w [j]) ; }
+#define CS_CSC(A) (A && (A->nz == -1))
+#define CS_TRIPLET(A) (A && (A->nz >= 0))
+
+/* --- primary CSparse routines and data structures ------------------------- */
+
+#define cs_add CS_NAME (_add)
+#define cs_cholsol CS_NAME (_cholsol)
+#define cs_dupl CS_NAME (_dupl)
+#define cs_entry CS_NAME (_entry)
+#define cs_lusol CS_NAME (_lusol)
+#define cs_gaxpy CS_NAME (_gaxpy)
+#define cs_multiply CS_NAME (_multiply)
+#define cs_qrsol CS_NAME (_qrsol)
+#define cs_transpose CS_NAME (_transpose)
+#define cs_compress CS_NAME (_compress)
+#define cs_norm CS_NAME (_norm)
+#define cs_print CS_NAME (_print)
+#define cs_load CS_NAME (_load)
+
+/* utilities */
+#define cs_calloc CS_NAME (_calloc)
+#define cs_free CS_NAME (_free)
+#define cs_realloc CS_NAME (_realloc)
+#define cs_spalloc CS_NAME (_spalloc)
+#define cs_spfree CS_NAME (_spfree)
+#define cs_sprealloc CS_NAME (_sprealloc)
+#define cs_malloc CS_NAME (_malloc)
+
+/* --- secondary CSparse routines and data structures ----------------------- */
+#define css CS_NAME (s)
+#define csn CS_NAME (n)
+#define csd CS_NAME (d)
+
+#define cs_amd CS_NAME (_amd)
+#define cs_chol CS_NAME (_chol)
+#define cs_dmperm CS_NAME (_dmperm)
+#define cs_droptol CS_NAME (_droptol)
+#define cs_dropzeros CS_NAME (_dropzeros)
+#define cs_happly CS_NAME (_happly)
+#define cs_ipvec CS_NAME (_ipvec)
+#define cs_lsolve CS_NAME (_lsolve)
+#define cs_ltsolve CS_NAME (_ltsolve)
+#define cs_lu CS_NAME (_lu)
+#define cs_permute CS_NAME (_permute)
+#define cs_pinv CS_NAME (_pinv)
+#define cs_pvec CS_NAME (_pvec)
+#define cs_qr CS_NAME (_qr)
+#define cs_schol CS_NAME (_schol)
+#define cs_sqr CS_NAME (_sqr)
+#define cs_symperm CS_NAME (_symperm)
+#define cs_usolve CS_NAME (_usolve)
+#define cs_utsolve CS_NAME (_utsolve)
+#define cs_updown CS_NAME (_updown)
+
+/* utilities */
+#define cs_sfree CS_NAME (_sfree)
+#define cs_nfree CS_NAME (_nfree)
+#define cs_dfree CS_NAME (_dfree)
+
+/* --- tertiary CSparse routines -------------------------------------------- */
+#define cs_counts CS_NAME (_counts)
+#define cs_cumsum CS_NAME (_cumsum)
+#define cs_dfs CS_NAME (_dfs)
+#define cs_etree CS_NAME (_etree)
+#define cs_fkeep CS_NAME (_fkeep)
+#define cs_house CS_NAME (_house)
+#define cs_invmatch CS_NAME (_invmatch)
+#define cs_maxtrans CS_NAME (_maxtrans)
+#define cs_post CS_NAME (_post)
+#define cs_scc CS_NAME (_scc)
+#define cs_scatter CS_NAME (_scatter)
+#define cs_tdfs CS_NAME (_tdfs)
+#define cs_reach CS_NAME (_reach)
+#define cs_spsolve CS_NAME (_spsolve)
+#define cs_ereach CS_NAME (_ereach)
+#define cs_randperm CS_NAME (_randperm)
+#define cs_leaf CS_NAME (_leaf)
+
+/* utilities */
+#define cs_dalloc CS_NAME (_dalloc)
+#define cs_done CS_NAME (_done)
+#define cs_idone CS_NAME (_idone)
+#define cs_ndone CS_NAME (_ndone)
+#define cs_ddone CS_NAME (_ddone)
+
+/* -------------------------------------------------------------------------- */
+/* Conversion routines */
+/* -------------------------------------------------------------------------- */
+
+#ifndef NCOMPLEX
+cs_di *cs_i_real (cs_ci *A, int real) ;
+cs_ci *cs_i_complex (cs_di *A, int real) ;
+cs_dl *cs_l_real (cs_cl *A, UF_long real) ;
+cs_cl *cs_l_complex (cs_dl *A, UF_long real) ;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/cs/cs_add.c b/src/cs/cs_add.c
new file mode 100644
index 0000000..0bb7b4d
--- /dev/null
+++ b/src/cs/cs_add.c
@@ -0,0 +1,48 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* C = alpha*A + beta*B */
+cs *cs_add (const cs *A, const cs *B, CS_ENTRY alpha, CS_ENTRY beta)
+{
+    CS_INT p, j, nz = 0, anz, *Cp, *Ci, *Bp, m, n, bnz, *w, values ;
+    CS_ENTRY *x, *Bx, *Cx ;
+    cs *C ;
+    if (!CS_CSC (A) || !CS_CSC (B)) return (NULL) ;         /* check inputs */
+    if (A->m != B->m || A->n != B->n) return (NULL) ;
+    m = A->m ; anz = A->p [A->n] ;
+    n = B->n ; Bp = B->p ; Bx = B->x ; bnz = Bp [n] ;
+    w = cs_calloc (m, sizeof (CS_INT)) ;                       /* get workspace */
+    values = (A->x != NULL) && (Bx != NULL) ;
+    x = values ? cs_malloc (m, sizeof (CS_ENTRY)) : NULL ;    /* get workspace */
+    C = cs_spalloc (m, n, anz + bnz, values, 0) ;           /* allocate result*/
+    if (!C || !w || (values && !x)) return (cs_done (C, w, x, 0)) ;
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    for (j = 0 ; j < n ; j++)
+    {
+        Cp [j] = nz ;                   /* column j of C starts here */
+        nz = cs_scatter (A, j, alpha, w, x, j+1, C, nz) ;   /* alpha*A(:,j)*/
+        nz = cs_scatter (B, j, beta, w, x, j+1, C, nz) ;    /* beta*B(:,j) */
+        if (values) for (p = Cp [j] ; p < nz ; p++) Cx [p] = x [Ci [p]] ;
+    }
+    Cp [n] = nz ;                       /* finalize the last column of C */
+    cs_sprealloc (C, 0) ;               /* remove extra space from C */
+    return (cs_done (C, w, x, 1)) ;     /* success; free workspace, return C */
+}
diff --git a/src/cs/cs_amd.c b/src/cs/cs_amd.c
new file mode 100644
index 0000000..09196cb
--- /dev/null
+++ b/src/cs/cs_amd.c
@@ -0,0 +1,387 @@
+/*
+ * 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 "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+
+#include "cs.h"
+/* clear w */
+static CS_INT cs_wclear (CS_INT mark, CS_INT lemax, CS_INT *w, CS_INT n)
+{
+    CS_INT k ;
+    if (mark < 2 || (mark + lemax < 0))
+    {
+        for (k = 0 ; k < n ; k++) if (w [k] != 0) w [k] = 1 ;
+        mark = 2 ;
+    }
+    return (mark) ;     /* at this point, w [0..n-1] < mark holds */
+}
+
+/* keep off-diagonal entries; drop diagonal entries */
+static CS_INT cs_diag (CS_INT i, CS_INT j, CS_ENTRY aij, void *other) { return (i != j) ; }
+
+/* p = amd(A+A') if symmetric is true, or amd(A'A) otherwise */
+CS_INT *cs_amd (CS_INT order, const cs *A)  /* order 0:natural, 1:Chol, 2:LU, 3:QR */
+{
+    cs *C, *A2, *AT ;
+    CS_INT *Cp, *Ci, *last, *W, *len, *nv, *next, *P, *head, *elen, *degree, *w,
+        *hhead, *ATp, *ATi, d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1,
+        k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi,
+        ok, cnz, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, n, m, t ;
+    unsigned CS_INT h ;
+    /* --- Construct matrix C ----------------------------------------------- */
+    if (!CS_CSC (A) || order <= 0 || order > 3) return (NULL) ; /* check */
+    AT = cs_transpose (A, 0) ;              /* compute A' */
+    if (!AT) return (NULL) ;
+    m = A->m ; n = A->n ;
+    dense = CS_MAX (16, 10 * sqrt ((double) n)) ;   /* find dense threshold */
+    dense = CS_MIN (n-2, dense) ;
+    if (order == 1 && n == m)
+    {
+        C = cs_add (A, AT, 0, 0) ;          /* C = A+A' */
+    }
+    else if (order == 2)
+    {
+        ATp = AT->p ;                       /* drop dense columns from AT */
+        ATi = AT->i ;
+        for (p2 = 0, j = 0 ; j < m ; j++)
+        {
+            p = ATp [j] ;                   /* column j of AT starts here */
+            ATp [j] = p2 ;                  /* new column j starts here */
+            if (ATp [j+1] - p > dense) continue ;   /* skip dense col j */
+            for ( ; p < ATp [j+1] ; p++) ATi [p2++] = ATi [p] ;
+        }
+        ATp [m] = p2 ;                      /* finalize AT */
+        A2 = cs_transpose (AT, 0) ;         /* A2 = AT' */
+        C = A2 ? cs_multiply (AT, A2) : NULL ;  /* C=A'*A with no dense rows */
+        cs_spfree (A2) ;
+    }
+    else
+    {
+        C = cs_multiply (AT, A) ;           /* C=A'*A */
+    }
+    cs_spfree (AT) ;
+    if (!C) return (NULL) ;
+    cs_fkeep (C, &cs_diag, NULL) ;          /* drop diagonal entries */
+    Cp = C->p ;
+    cnz = Cp [n] ;
+    P = cs_malloc (n+1, sizeof (CS_INT)) ;     /* allocate result */
+    W = cs_malloc (8*(n+1), sizeof (CS_INT)) ; /* get workspace */
+    t = cnz + cnz/5 + 2*n ;                 /* add elbow room to C */
+    if (!P || !W || !cs_sprealloc (C, t)) return (cs_idone (P, C, W, 0)) ;
+    len  = W           ; nv     = W +   (n+1) ; next   = W + 2*(n+1) ;
+    head = W + 3*(n+1) ; elen   = W + 4*(n+1) ; degree = W + 5*(n+1) ;
+    w    = W + 6*(n+1) ; hhead  = W + 7*(n+1) ;
+    last = P ;                              /* use P as workspace for last */
+    /* --- Initialize quotient graph ---------------------------------------- */
+    for (k = 0 ; k < n ; k++) len [k] = Cp [k+1] - Cp [k] ;
+    len [n] = 0 ;
+    nzmax = C->nzmax ;
+    Ci = C->i ;
+    for (i = 0 ; i <= n ; i++)
+    {
+        head [i] = -1 ;                     /* degree list i is empty */
+        last [i] = -1 ;
+        next [i] = -1 ;
+        hhead [i] = -1 ;                    /* hash list i is empty */
+        nv [i] = 1 ;                        /* node i is just one node */
+        w [i] = 1 ;                         /* node i is alive */
+        elen [i] = 0 ;                      /* Ek of node i is empty */
+        degree [i] = len [i] ;              /* degree of node i */
+    }
+    mark = cs_wclear (0, 0, w, n) ;         /* clear w */
+    elen [n] = -2 ;                         /* n is a dead element */
+    Cp [n] = -1 ;                           /* n is a root of assembly tree */
+    w [n] = 0 ;                             /* n is a dead element */
+    /* --- Initialize degree lists ------------------------------------------ */
+    for (i = 0 ; i < n ; i++)
+    {
+        d = degree [i] ;
+        if (d == 0)                         /* node i is empty */
+        {
+            elen [i] = -2 ;                 /* element i is dead */
+            nel++ ;
+            Cp [i] = -1 ;                   /* i is a root of assembly tree */
+            w [i] = 0 ;
+        }
+        else if (d > dense)                 /* node i is dense */
+        {
+            nv [i] = 0 ;                    /* absorb i into element n */
+            elen [i] = -1 ;                 /* node i is dead */
+            nel++ ;
+            Cp [i] = CS_FLIP (n) ;
+            nv [n]++ ;
+        }
+        else
+        {
+            if (head [d] != -1) last [head [d]] = i ;
+            next [i] = head [d] ;           /* put node i in degree list d */
+            head [d] = i ;
+        }
+    }
+    while (nel < n)                         /* while (selecting pivots) do */
+    {
+        /* --- Select node of minimum approximate degree -------------------- */
+        for (k = -1 ; mindeg < n && (k = head [mindeg]) == -1 ; mindeg++) ;
+        if (next [k] != -1) last [next [k]] = -1 ;
+        head [mindeg] = next [k] ;          /* remove k from degree list */
+        elenk = elen [k] ;                  /* elenk = |Ek| */
+        nvk = nv [k] ;                      /* # of nodes k represents */
+        nel += nvk ;                        /* nv[k] nodes of A eliminated */
+        /* --- Garbage collection ------------------------------------------- */
+        if (elenk > 0 && cnz + mindeg >= nzmax)
+        {
+            for (j = 0 ; j < n ; j++)
+            {
+                if ((p = Cp [j]) >= 0)      /* j is a live node or element */
+                {
+                    Cp [j] = Ci [p] ;       /* save first entry of object */
+                    Ci [p] = CS_FLIP (j) ;  /* first entry is now CS_FLIP(j) */
+                }
+            }
+            for (q = 0, p = 0 ; p < cnz ; ) /* scan all of memory */
+            {
+                if ((j = CS_FLIP (Ci [p++])) >= 0)  /* found object j */
+                {
+                    Ci [q] = Cp [j] ;       /* restore first entry of object */
+                    Cp [j] = q++ ;          /* new pointer to object j */
+                    for (k3 = 0 ; k3 < len [j]-1 ; k3++) Ci [q++] = Ci [p++] ;
+                }
+            }
+            cnz = q ;                       /* Ci [cnz...nzmax-1] now free */
+        }
+        /* --- Construct new element ---------------------------------------- */
+        dk = 0 ;
+        nv [k] = -nvk ;                     /* flag k as in Lk */
+        p = Cp [k] ;
+        pk1 = (elenk == 0) ? p : cnz ;      /* do in place if elen[k] == 0 */
+        pk2 = pk1 ;
+        for (k1 = 1 ; k1 <= elenk + 1 ; k1++)
+        {
+            if (k1 > elenk)
+            {
+                e = k ;                     /* search the nodes in k */
+                pj = p ;                    /* list of nodes starts at Ci[pj]*/
+                ln = len [k] - elenk ;      /* length of list of nodes in k */
+            }
+            else
+            {
+                e = Ci [p++] ;              /* search the nodes in e */
+                pj = Cp [e] ;
+                ln = len [e] ;              /* length of list of nodes in e */
+            }
+            for (k2 = 1 ; k2 <= ln ; k2++)
+            {
+                i = Ci [pj++] ;
+                if ((nvi = nv [i]) <= 0) continue ; /* node i dead, or seen */
+                dk += nvi ;                 /* degree[Lk] += size of node i */
+                nv [i] = -nvi ;             /* negate nv[i] to denote i in Lk*/
+                Ci [pk2++] = i ;            /* place i in Lk */
+                if (next [i] != -1) last [next [i]] = last [i] ;
+                if (last [i] != -1)         /* remove i from degree list */
+                {
+                    next [last [i]] = next [i] ;
+                }
+                else
+                {
+                    head [degree [i]] = next [i] ;
+                }
+            }
+            if (e != k)
+            {
+                Cp [e] = CS_FLIP (k) ;      /* absorb e into k */
+                w [e] = 0 ;                 /* e is now a dead element */
+            }
+        }
+        if (elenk != 0) cnz = pk2 ;         /* Ci [cnz...nzmax] is free */
+        degree [k] = dk ;                   /* external degree of k - |Lk\i| */
+        Cp [k] = pk1 ;                      /* element k is in Ci[pk1..pk2-1] */
+        len [k] = pk2 - pk1 ;
+        elen [k] = -2 ;                     /* k is now an element */
+        /* --- Find set differences ----------------------------------------- */
+        mark = cs_wclear (mark, lemax, w, n) ;  /* clear w if necessary */
+        for (pk = pk1 ; pk < pk2 ; pk++)    /* scan 1: find |Le\Lk| */
+        {
+            i = Ci [pk] ;
+            if ((eln = elen [i]) <= 0) continue ;/* skip if elen[i] empty */
+            nvi = -nv [i] ;                      /* nv [i] was negated */
+            wnvi = mark - nvi ;
+            for (p = Cp [i] ; p <= Cp [i] + eln - 1 ; p++)  /* scan Ei */
+            {
+                e = Ci [p] ;
+                if (w [e] >= mark)
+                {
+                    w [e] -= nvi ;          /* decrement |Le\Lk| */
+                }
+                else if (w [e] != 0)        /* ensure e is a live element */
+                {
+                    w [e] = degree [e] + wnvi ; /* 1st time e seen in scan 1 */
+                }
+            }
+        }
+        /* --- Degree update ------------------------------------------------ */
+        for (pk = pk1 ; pk < pk2 ; pk++)    /* scan2: degree update */
+        {
+            i = Ci [pk] ;                   /* consider node i in Lk */
+            p1 = Cp [i] ;
+            p2 = p1 + elen [i] - 1 ;
+            pn = p1 ;
+            for (h = 0, d = 0, p = p1 ; p <= p2 ; p++)    /* scan Ei */
+            {
+                e = Ci [p] ;
+                if (w [e] != 0)             /* e is an unabsorbed element */
+                {
+                    dext = w [e] - mark ;   /* dext = |Le\Lk| */
+                    if (dext > 0)
+                    {
+                        d += dext ;         /* sum up the set differences */
+                        Ci [pn++] = e ;     /* keep e in Ei */
+                        h += e ;            /* compute the hash of node i */
+                    }
+                    else
+                    {
+                        Cp [e] = CS_FLIP (k) ;  /* aggressive absorb. e->k */
+                        w [e] = 0 ;             /* e is a dead element */
+                    }
+                }
+            }
+            elen [i] = pn - p1 + 1 ;        /* elen[i] = |Ei| */
+            p3 = pn ;
+            p4 = p1 + len [i] ;
+            for (p = p2 + 1 ; p < p4 ; p++) /* prune edges in Ai */
+            {
+                j = Ci [p] ;
+                if ((nvj = nv [j]) <= 0) continue ; /* node j dead or in Lk */
+                d += nvj ;                  /* degree(i) += |j| */
+                Ci [pn++] = j ;             /* place j in node list of i */
+                h += j ;                    /* compute hash for node i */
+            }
+            if (d == 0)                     /* check for mass elimination */
+            {
+                Cp [i] = CS_FLIP (k) ;      /* absorb i into k */
+                nvi = -nv [i] ;
+                dk -= nvi ;                 /* |Lk| -= |i| */
+                nvk += nvi ;                /* |k| += nv[i] */
+                nel += nvi ;
+                nv [i] = 0 ;
+                elen [i] = -1 ;             /* node i is dead */
+            }
+            else
+            {
+                degree [i] = CS_MIN (degree [i], d) ;   /* update degree(i) */
+                Ci [pn] = Ci [p3] ;         /* move first node to end */
+                Ci [p3] = Ci [p1] ;         /* move 1st el. to end of Ei */
+                Ci [p1] = k ;               /* add k as 1st element in of Ei */
+                len [i] = pn - p1 + 1 ;     /* new len of adj. list of node i */
+                h %= n ;                    /* finalize hash of i */
+                next [i] = hhead [h] ;      /* place i in hash bucket */
+                hhead [h] = i ;
+                last [i] = h ;              /* save hash of i in last[i] */
+            }
+        }                                   /* scan2 is done */
+        degree [k] = dk ;                   /* finalize |Lk| */
+        lemax = CS_MAX (lemax, dk) ;
+        mark = cs_wclear (mark+lemax, lemax, w, n) ;    /* clear w */
+        /* --- Supernode detection ------------------------------------------ */
+        for (pk = pk1 ; pk < pk2 ; pk++)
+        {
+            i = Ci [pk] ;
+            if (nv [i] >= 0) continue ;         /* skip if i is dead */
+            h = last [i] ;                      /* scan hash bucket of node i */
+            i = hhead [h] ;
+            hhead [h] = -1 ;                    /* hash bucket will be empty */
+            for ( ; i != -1 && next [i] != -1 ; i = next [i], mark++)
+            {
+                ln = len [i] ;
+                eln = elen [i] ;
+                for (p = Cp [i]+1 ; p <= Cp [i] + ln-1 ; p++) w [Ci [p]] = mark;
+                jlast = i ;
+                for (j = next [i] ; j != -1 ; ) /* compare i with all j */
+                {
+                    ok = (len [j] == ln) && (elen [j] == eln) ;
+                    for (p = Cp [j] + 1 ; ok && p <= Cp [j] + ln - 1 ; p++)
+                    {
+                        if (w [Ci [p]] != mark) ok = 0 ;    /* compare i and j*/
+                    }
+                    if (ok)                     /* i and j are identical */
+                    {
+                        Cp [j] = CS_FLIP (i) ;  /* absorb j into i */
+                        nv [i] += nv [j] ;
+                        nv [j] = 0 ;
+                        elen [j] = -1 ;         /* node j is dead */
+                        j = next [j] ;          /* delete j from hash bucket */
+                        next [jlast] = j ;
+                    }
+                    else
+                    {
+                        jlast = j ;             /* j and i are different */
+                        j = next [j] ;
+                    }
+                }
+            }
+        }
+        /* --- Finalize new element------------------------------------------ */
+        for (p = pk1, pk = pk1 ; pk < pk2 ; pk++)   /* finalize Lk */
+        {
+            i = Ci [pk] ;
+            if ((nvi = -nv [i]) <= 0) continue ;/* skip if i is dead */
+            nv [i] = nvi ;                      /* restore nv[i] */
+            d = degree [i] + dk - nvi ;         /* compute external degree(i) */
+            d = CS_MIN (d, n - nel - nvi) ;
+            if (head [d] != -1) last [head [d]] = i ;
+            next [i] = head [d] ;               /* put i back in degree list */
+            last [i] = -1 ;
+            head [d] = i ;
+            mindeg = CS_MIN (mindeg, d) ;       /* find new minimum degree */
+            degree [i] = d ;
+            Ci [p++] = i ;                      /* place i in Lk */
+        }
+        nv [k] = nvk ;                      /* # nodes absorbed into k */
+        if ((len [k] = p-pk1) == 0)         /* length of adj list of element k*/
+        {
+            Cp [k] = -1 ;                   /* k is a root of the tree */
+            w [k] = 0 ;                     /* k is now a dead element */
+        }
+        if (elenk != 0) cnz = p ;           /* free unused space in Lk */
+    }
+    /* --- Postordering ----------------------------------------------------- */
+    for (i = 0 ; i < n ; i++) Cp [i] = CS_FLIP (Cp [i]) ;/* fix assembly tree */
+    for (j = 0 ; j <= n ; j++) head [j] = -1 ;
+    for (j = n ; j >= 0 ; j--)              /* place unordered nodes in lists */
+    {
+        if (nv [j] > 0) continue ;          /* skip if j is an element */
+        next [j] = head [Cp [j]] ;          /* place j in list of its parent */
+        head [Cp [j]] = j ;
+    }
+    for (e = n ; e >= 0 ; e--)              /* place elements in lists */
+    {
+        if (nv [e] <= 0) continue ;         /* skip unless e is an element */
+        if (Cp [e] != -1)
+        {
+            next [e] = head [Cp [e]] ;      /* place e in list of its parent */
+            head [Cp [e]] = e ;
+        }
+    }
+    for (k = 0, i = 0 ; i <= n ; i++)       /* postorder the assembly tree */
+    {
+        if (Cp [i] == -1) k = cs_tdfs (i, k, head, next, P, w) ;
+    }
+    return (cs_idone (P, C, W, 1)) ;
+}
diff --git a/src/cs/cs_chol.c b/src/cs/cs_chol.c
new file mode 100644
index 0000000..489a7d0
--- /dev/null
+++ b/src/cs/cs_chol.c
@@ -0,0 +1,79 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* L = chol (A, [pinv parent cp]), pinv is optional */
+csn *cs_chol (const cs *A, const css *S)
+{
+    CS_ENTRY d, lki, *Lx, *x, *Cx ;
+    CS_INT top, i, p, k, n, *Li, *Lp, *cp, *pinv, *s, *c, *parent, *Cp, *Ci ;
+    cs *L, *C, *E ;
+    csn *N ;
+    if (!CS_CSC (A) || !S || !S->cp || !S->parent) return (NULL) ;
+    n = A->n ;
+    N = cs_calloc (1, sizeof (csn)) ;       /* allocate result */
+    c = cs_malloc (2*n, sizeof (CS_INT)) ;     /* get CS_INT workspace */
+    x = cs_malloc (n, sizeof (CS_ENTRY)) ;    /* get CS_ENTRY workspace */
+    cp = S->cp ; pinv = S->pinv ; parent = S->parent ;
+    C = pinv ? cs_symperm (A, pinv, 1) : ((cs *) A) ;
+    E = pinv ? C : NULL ;           /* E is alias for A, or a copy E=A(p,p) */
+    if (!N || !c || !x || !C) return (cs_ndone (N, E, c, x, 0)) ;
+    s = c + n ;
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    N->L = L = cs_spalloc (n, n, cp [n], 1, 0) ;    /* allocate result */
+    if (!L) return (cs_ndone (N, E, c, x, 0)) ;
+    Lp = L->p ; Li = L->i ; Lx = L->x ;
+    for (k = 0 ; k < n ; k++) Lp [k] = c [k] = cp [k] ;
+    for (k = 0 ; k < n ; k++)       /* compute L(k,:) for L*L' = C */
+    {
+        /* --- Nonzero pattern of L(k,:) ------------------------------------ */
+        top = cs_ereach (C, k, parent, s, c) ;      /* find pattern of L(k,:) */
+        x [k] = 0 ;                                 /* x (0:k) is now zero */
+        for (p = Cp [k] ; p < Cp [k+1] ; p++)       /* x = full(triu(C(:,k))) */
+        {
+            if (Ci [p] <= k) x [Ci [p]] = Cx [p] ;
+        }
+        d = x [k] ;                     /* d = C(k,k) */
+        x [k] = 0 ;                     /* clear x for k+1st iteration */
+        /* --- Triangular solve --------------------------------------------- */
+        for ( ; top < n ; top++)    /* solve L(0:k-1,0:k-1) * x = C(:,k) */
+        {
+            i = s [top] ;               /* s [top..n-1] is pattern of L(k,:) */
+            lki = x [i] / Lx [Lp [i]] ; /* L(k,i) = x (i) / L(i,i) */
+            x [i] = 0 ;                 /* clear x for k+1st iteration */
+            for (p = Lp [i] + 1 ; p < c [i] ; p++)
+            {
+                x [Li [p]] -= Lx [p] * lki ;
+            }
+            d -= lki * CS_CONJ (lki) ;            /* d = d - L(k,i)*L(k,i) */
+            p = c [i]++ ;
+            Li [p] = k ;                /* store L(k,i) in column i */
+            Lx [p] = CS_CONJ (lki) ;
+        }
+        /* --- Compute L(k,k) ----------------------------------------------- */
+        if (CS_REAL (d) <= 0 || CS_IMAG (d) != 0)
+	    return (cs_ndone (N, E, c, x, 0)) ; /* not pos def */
+        p = c [k]++ ;
+        Li [p] = k ;                /* store L(k,k) = sqrt (d) in column k */
+        Lx [p] = sqrt (d) ;
+    }
+    Lp [n] = cp [n] ;               /* finalize L */
+    return (cs_ndone (N, E, c, x, 1)) ; /* success: free E,s,x; return N */
+}
diff --git a/src/cs/cs_cholsol.c b/src/cs/cs_cholsol.c
new file mode 100644
index 0000000..45db65a
--- /dev/null
+++ b/src/cs/cs_cholsol.c
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* x=A\b where A is symmetric positive definite; b overwritten with solution */
+CS_INT cs_cholsol (CS_INT order, const cs *A, CS_ENTRY *b)
+{
+    CS_ENTRY *x ;
+    css *S ;
+    csn *N ;
+    CS_INT n, ok ;
+    if (!CS_CSC (A) || !b) return (0) ;     /* check inputs */
+    n = A->n ;
+    S = cs_schol (order, A) ;               /* ordering and symbolic analysis */
+    N = cs_chol (A, S) ;                    /* numeric Cholesky factorization */
+    x = cs_malloc (n, sizeof (CS_ENTRY)) ;    /* get workspace */
+    ok = (S && N && x) ;
+    if (ok)
+    {
+        cs_ipvec (S->pinv, b, x, n) ;   /* x = P*b */
+        cs_lsolve (N->L, x) ;           /* x = L\x */
+        cs_ltsolve (N->L, x) ;          /* x = L'\x */
+        cs_pvec (S->pinv, x, b, n) ;    /* b = P'*x */
+    }
+    cs_free (x) ;
+    cs_sfree (S) ;
+    cs_nfree (N) ;
+    return (ok) ;
+}
diff --git a/src/cs/cs_compress.c b/src/cs/cs_compress.c
new file mode 100644
index 0000000..c9a639a
--- /dev/null
+++ b/src/cs/cs_compress.c
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* C = compressed-column form of a triplet matrix T */
+cs *cs_compress (const cs *T)
+{
+    CS_INT m, n, nz, p, k, *Cp, *Ci, *w, *Ti, *Tj ;
+    CS_ENTRY *Cx, *Tx ;
+    cs *C ;
+    if (!CS_TRIPLET (T)) return (NULL) ;                /* check inputs */
+    m = T->m ; n = T->n ; Ti = T->i ; Tj = T->p ; Tx = T->x ; nz = T->nz ;
+    C = cs_spalloc (m, n, nz, Tx != NULL, 0) ;          /* allocate result */
+    w = cs_calloc (n, sizeof (CS_INT)) ;                   /* get workspace */
+    if (!C || !w) return (cs_done (C, w, NULL, 0)) ;    /* out of memory */
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    for (k = 0 ; k < nz ; k++) w [Tj [k]]++ ;           /* column counts */
+    cs_cumsum (Cp, w, n) ;                              /* column pointers */
+    for (k = 0 ; k < nz ; k++)
+    {
+        Ci [p = w [Tj [k]]++] = Ti [k] ;    /* A(i,j) is the pth entry in C */
+        if (Cx) Cx [p] = Tx [k] ;
+    }
+    return (cs_done (C, w, NULL, 1)) ;      /* success; free w and return C */
+}
diff --git a/src/cs/cs_counts.c b/src/cs/cs_counts.c
new file mode 100644
index 0000000..118a260
--- /dev/null
+++ b/src/cs/cs_counts.c
@@ -0,0 +1,81 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* column counts of LL'=A or LL'=A'A, given parent & post ordering */
+#define HEAD(k,j) (ata ? head [k] : j)
+#define NEXT(J)   (ata ? next [J] : -1)
+static void init_ata (cs *AT, const CS_INT *post, CS_INT *w, CS_INT **head, CS_INT **next)
+{
+    CS_INT i, k, p, m = AT->n, n = AT->m, *ATp = AT->p, *ATi = AT->i ;
+    *head = w+4*n, *next = w+5*n+1 ;
+    for (k = 0 ; k < n ; k++) w [post [k]] = k ;    /* invert post */
+    for (i = 0 ; i < m ; i++)
+    {
+        for (k = n, p = ATp[i] ; p < ATp[i+1] ; p++) k = CS_MIN (k, w [ATi[p]]);
+        (*next) [i] = (*head) [k] ;     /* place row i in linked list k */
+        (*head) [k] = i ;
+    }
+}
+CS_INT *cs_counts (const cs *A, const CS_INT *parent, const CS_INT *post, CS_INT ata)
+{
+    CS_INT i, j, k, n, m, J, s, p, q, jleaf, *ATp, *ATi, *maxfirst, *prevleaf,
+        *ancestor, *head = NULL, *next = NULL, *colcount, *w, *first, *delta ;
+    cs *AT ;
+    if (!CS_CSC (A) || !parent || !post) return (NULL) ;    /* check inputs */
+    m = A->m ; n = A->n ;
+    s = 4*n + (ata ? (n+m+1) : 0) ;
+    delta = colcount = cs_malloc (n, sizeof (CS_INT)) ;    /* allocate result */
+    w = cs_malloc (s, sizeof (CS_INT)) ;                   /* get workspace */
+    AT = cs_transpose (A, 0) ;                          /* AT = A' */
+    if (!AT || !colcount || !w) return (cs_idone (colcount, AT, w, 0)) ;
+    ancestor = w ; maxfirst = w+n ; prevleaf = w+2*n ; first = w+3*n ;
+    for (k = 0 ; k < s ; k++) w [k] = -1 ;      /* clear workspace w [0..s-1] */
+    for (k = 0 ; k < n ; k++)                   /* find first [j] */
+    {
+        j = post [k] ;
+        delta [j] = (first [j] == -1) ? 1 : 0 ;  /* delta[j]=1 if j is a leaf */
+        for ( ; j != -1 && first [j] == -1 ; j = parent [j]) first [j] = k ;
+    }
+    ATp = AT->p ; ATi = AT->i ;
+    if (ata) init_ata (AT, post, w, &head, &next) ;
+    for (i = 0 ; i < n ; i++) ancestor [i] = i ; /* each node in its own set */
+    for (k = 0 ; k < n ; k++)
+    {
+        j = post [k] ;          /* j is the kth node in postordered etree */
+        if (parent [j] != -1) delta [parent [j]]-- ;    /* j is not a root */
+        for (J = HEAD (k,j) ; J != -1 ; J = NEXT (J))   /* J=j for LL'=A case */
+        {
+            for (p = ATp [J] ; p < ATp [J+1] ; p++)
+            {
+                i = ATi [p] ;
+                q = cs_leaf (i, j, first, maxfirst, prevleaf, ancestor, &jleaf);
+                if (jleaf >= 1) delta [j]++ ;   /* A(i,j) is in skeleton */
+                if (jleaf == 2) delta [q]-- ;   /* account for overlap in q */
+            }
+        }
+        if (parent [j] != -1) ancestor [j] = parent [j] ;
+    }
+    for (j = 0 ; j < n ; j++)           /* sum up delta's of each child */
+    {
+        if (parent [j] != -1) colcount [parent [j]] += colcount [j] ;
+    }
+    return (cs_idone (colcount, AT, w, 1)) ;    /* success: free workspace */
+} 
diff --git a/src/cs/cs_cumsum.c b/src/cs/cs_cumsum.c
new file mode 100644
index 0000000..d7145f2
--- /dev/null
+++ b/src/cs/cs_cumsum.c
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* p [0..n] = cumulative sum of c [0..n-1], and then copy p [0..n-1] into c */
+double cs_cumsum (CS_INT *p, CS_INT *c, CS_INT n)
+{
+    CS_INT i, nz = 0 ;
+    double nz2 = 0 ;
+    if (!p || !c) return (-1) ;     /* check inputs */
+    for (i = 0 ; i < n ; i++)
+    {
+        p [i] = nz ;
+        nz += c [i] ;
+        nz2 += c [i] ;              /* also in double to avoid CS_INT overflow */
+        c [i] = p [i] ;             /* also copy p[0..n-1] back into c[0..n-1]*/
+    }
+    p [n] = nz ;
+    return (nz2) ;                  /* return sum (c [0..n-1]) */
+}
diff --git a/src/cs/cs_dfs.c b/src/cs/cs_dfs.c
new file mode 100644
index 0000000..0dd3b6f
--- /dev/null
+++ b/src/cs/cs_dfs.c
@@ -0,0 +1,56 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* depth-first-search of the graph of a matrix, starting at node j */
+CS_INT cs_dfs (CS_INT j, cs *G, CS_INT top, CS_INT *xi, CS_INT *pstack, const CS_INT *pinv)
+{
+    CS_INT i, p, p2, done, jnew, head = 0, *Gp, *Gi ;
+    if (!CS_CSC (G) || !xi || !pstack) return (-1) ;    /* check inputs */
+    Gp = G->p ; Gi = G->i ;
+    xi [0] = j ;                /* initialize the recursion stack */
+    while (head >= 0)
+    {
+        j = xi [head] ;         /* get j from the top of the recursion stack */
+        jnew = pinv ? (pinv [j]) : j ;
+        if (!CS_MARKED (Gp, j))
+        {
+            CS_MARK (Gp, j) ;       /* mark node j as visited */
+            pstack [head] = (jnew < 0) ? 0 : CS_UNFLIP (Gp [jnew]) ;
+        }
+        done = 1 ;                  /* node j done if no unvisited neighbors */
+        p2 = (jnew < 0) ? 0 : CS_UNFLIP (Gp [jnew+1]) ;
+        for (p = pstack [head] ; p < p2 ; p++)  /* examine all neighbors of j */
+        {
+            i = Gi [p] ;            /* consider neighbor node i */
+            if (CS_MARKED (Gp, i)) continue ;   /* skip visited node i */
+            pstack [head] = p ;     /* pause depth-first search of node j */
+            xi [++head] = i ;       /* start dfs at node i */
+            done = 0 ;              /* node j is not done */
+            break ;                 /* break, to start dfs (i) */
+        }
+        if (done)               /* depth-first search at node j is done */
+        {
+            head-- ;            /* remove j from the recursion stack */
+            xi [--top] = j ;    /* and place in the output stack */
+        }
+    }
+    return (top) ;
+}
diff --git a/src/cs/cs_dmperm.c b/src/cs/cs_dmperm.c
new file mode 100644
index 0000000..a989028
--- /dev/null
+++ b/src/cs/cs_dmperm.c
@@ -0,0 +1,164 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* breadth-first search for coarse decomposition (C0,C1,R1 or R0,R3,C3) */
+static CS_INT cs_bfs (const cs *A, CS_INT n, CS_INT *wi, CS_INT *wj, CS_INT *queue,
+    const CS_INT *imatch, const CS_INT *jmatch, CS_INT mark)
+{
+    CS_INT *Ap, *Ai, head = 0, tail = 0, j, i, p, j2 ;
+    cs *C ;
+    for (j = 0 ; j < n ; j++)           /* place all unmatched nodes in queue */
+    {
+        if (imatch [j] >= 0) continue ; /* skip j if matched */
+        wj [j] = 0 ;                    /* j in set C0 (R0 if transpose) */
+        queue [tail++] = j ;            /* place unmatched col j in queue */
+    }
+    if (tail == 0) return (1) ;         /* quick return if no unmatched nodes */
+    C = (mark == 1) ? ((cs *) A) : cs_transpose (A, 0) ;
+    if (!C) return (0) ;                /* bfs of C=A' to find R3,C3 from R0 */
+    Ap = C->p ; Ai = C->i ;
+    while (head < tail)                 /* while queue is not empty */
+    {
+        j = queue [head++] ;            /* get the head of the queue */
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            i = Ai [p] ;
+            if (wi [i] >= 0) continue ; /* skip if i is marked */
+            wi [i] = mark ;             /* i in set R1 (C3 if transpose) */
+            j2 = jmatch [i] ;           /* traverse alternating path to j2 */
+            if (wj [j2] >= 0) continue ;/* skip j2 if it is marked */
+            wj [j2] = mark ;            /* j2 in set C1 (R3 if transpose) */
+            queue [tail++] = j2 ;       /* add j2 to queue */
+        }
+    }
+    if (mark != 1) cs_spfree (C) ;      /* free A' if it was created */
+    return (1) ;
+}
+
+/* collect matched rows and columns into p and q */
+static void cs_matched (CS_INT n, const CS_INT *wj, const CS_INT *imatch, CS_INT *p, CS_INT *q,
+    CS_INT *cc, CS_INT *rr, CS_INT set, CS_INT mark)
+{
+    CS_INT kc = cc [set], j ;
+    CS_INT kr = rr [set-1] ;
+    for (j = 0 ; j < n ; j++)
+    {
+        if (wj [j] != mark) continue ;      /* skip if j is not in C set */
+        p [kr++] = imatch [j] ;
+        q [kc++] = j ;
+    }
+    cc [set+1] = kc ;
+    rr [set] = kr ;
+}
+
+/* collect unmatched rows into the permutation vector p */
+static void cs_unmatched (CS_INT m, const CS_INT *wi, CS_INT *p, CS_INT *rr, CS_INT set)
+{
+    CS_INT i, kr = rr [set] ;
+    for (i = 0 ; i < m ; i++) if (wi [i] == 0) p [kr++] = i ;
+    rr [set+1] = kr ;
+}
+
+/* return 1 if row i is in R2 */
+static CS_INT cs_rprune (CS_INT i, CS_INT j, CS_ENTRY aij, void *other)
+{
+    CS_INT *rr = (CS_INT *) other ;
+    return (i >= rr [1] && i < rr [2]) ;
+}
+
+/* Given A, compute coarse and then fine dmperm */
+csd *cs_dmperm (const cs *A, CS_INT seed)
+{
+    CS_INT m, n, i, j, k, cnz, nc, *jmatch, *imatch, *wi, *wj, *pinv, *Cp, *Ci,
+        *ps, *rs, nb1, nb2, *p, *q, *cc, *rr, *r, *s, ok ;
+    cs *C ;
+    csd *D, *scc ;
+    /* --- Maximum matching ------------------------------------------------- */
+    if (!CS_CSC (A)) return (NULL) ;            /* check inputs */
+    m = A->m ; n = A->n ;
+    D = cs_dalloc (m, n) ;                      /* allocate result */
+    if (!D) return (NULL) ;
+    p = D->p ; q = D->q ; r = D->r ; s = D->s ; cc = D->cc ; rr = D->rr ;
+    jmatch = cs_maxtrans (A, seed) ;            /* max transversal */
+    imatch = jmatch + m ;                       /* imatch = inverse of jmatch */
+    if (!jmatch) return (cs_ddone (D, NULL, jmatch, 0)) ;
+    /* --- Coarse decomposition --------------------------------------------- */
+    wi = r ; wj = s ;                           /* use r and s as workspace */
+    for (j = 0 ; j < n ; j++) wj [j] = -1 ;     /* unmark all cols for bfs */
+    for (i = 0 ; i < m ; i++) wi [i] = -1 ;     /* unmark all rows for bfs */
+    cs_bfs (A, n, wi, wj, q, imatch, jmatch, 1) ;       /* find C1, R1 from C0*/
+    ok = cs_bfs (A, m, wj, wi, p, jmatch, imatch, 3) ;  /* find R3, C3 from R0*/
+    if (!ok) return (cs_ddone (D, NULL, jmatch, 0)) ;
+    cs_unmatched (n, wj, q, cc, 0) ;                    /* unmatched set C0 */
+    cs_matched (n, wj, imatch, p, q, cc, rr, 1, 1) ;    /* set R1 and C1 */
+    cs_matched (n, wj, imatch, p, q, cc, rr, 2, -1) ;   /* set R2 and C2 */
+    cs_matched (n, wj, imatch, p, q, cc, rr, 3, 3) ;    /* set R3 and C3 */
+    cs_unmatched (m, wi, p, rr, 3) ;                    /* unmatched set R0 */
+    cs_free (jmatch) ;
+    /* --- Fine decomposition ----------------------------------------------- */
+    pinv = cs_pinv (p, m) ;         /* pinv=p' */
+    if (!pinv) return (cs_ddone (D, NULL, NULL, 0)) ;
+    C = cs_permute (A, pinv, q, 0) ;/* C=A(p,q) (it will hold A(R2,C2)) */
+    cs_free (pinv) ;
+    if (!C) return (cs_ddone (D, NULL, NULL, 0)) ;
+    Cp = C->p ;
+    nc = cc [3] - cc [2] ;          /* delete cols C0, C1, and C3 from C */
+    if (cc [2] > 0) for (j = cc [2] ; j <= cc [3] ; j++) Cp [j-cc[2]] = Cp [j] ;
+    C->n = nc ;
+    if (rr [2] - rr [1] < m)        /* delete rows R0, R1, and R3 from C */
+    {
+        cs_fkeep (C, cs_rprune, rr) ;
+        cnz = Cp [nc] ;
+        Ci = C->i ;
+        if (rr [1] > 0) for (k = 0 ; k < cnz ; k++) Ci [k] -= rr [1] ;
+    }
+    C->m = nc ;
+    scc = cs_scc (C) ;              /* find strongly connected components of C*/
+    if (!scc) return (cs_ddone (D, C, NULL, 0)) ;
+    /* --- Combine coarse and fine decompositions --------------------------- */
+    ps = scc->p ;                   /* C(ps,ps) is the permuted matrix */
+    rs = scc->r ;                   /* kth block is rs[k]..rs[k+1]-1 */
+    nb1 = scc->nb  ;                /* # of blocks of A(R2,C2) */
+    for (k = 0 ; k < nc ; k++) wj [k] = q [ps [k] + cc [2]] ;
+    for (k = 0 ; k < nc ; k++) q [k + cc [2]] = wj [k] ;
+    for (k = 0 ; k < nc ; k++) wi [k] = p [ps [k] + rr [1]] ;
+    for (k = 0 ; k < nc ; k++) p [k + rr [1]] = wi [k] ;
+    nb2 = 0 ;                       /* create the fine block partitions */
+    r [0] = s [0] = 0 ;
+    if (cc [2] > 0) nb2++ ;         /* leading coarse block A (R1, [C0 C1]) */
+    for (k = 0 ; k < nb1 ; k++)     /* coarse block A (R2,C2) */
+    {
+        r [nb2] = rs [k] + rr [1] ; /* A (R2,C2) splits into nb1 fine blocks */
+        s [nb2] = rs [k] + cc [2] ;
+        nb2++ ;
+    }
+    if (rr [2] < m)
+    {
+        r [nb2] = rr [2] ;          /* trailing coarse block A ([R3 R0], C3) */
+        s [nb2] = cc [3] ;
+        nb2++ ;
+    }
+    r [nb2] = m ;
+    s [nb2] = n ;
+    D->nb = nb2 ;
+    cs_dfree (scc) ;
+    return (cs_ddone (D, C, NULL, 1)) ;
+}
diff --git a/src/cs/cs_droptol.c b/src/cs/cs_droptol.c
new file mode 100644
index 0000000..15cbdcc
--- /dev/null
+++ b/src/cs/cs_droptol.c
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+static CS_INT cs_tol (CS_INT i, CS_INT j, CS_ENTRY aij, void *tol)
+{
+    return (CS_ABS (aij) > *((double *) tol)) ;
+}
+CS_INT cs_droptol (cs *A, double tol)
+{
+    return (cs_fkeep (A, &cs_tol, &tol)) ;    /* keep all large entries */
+}
diff --git a/src/cs/cs_dropzeros.c b/src/cs/cs_dropzeros.c
new file mode 100644
index 0000000..1cceb20
--- /dev/null
+++ b/src/cs/cs_dropzeros.c
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+static CS_INT cs_nonzero (CS_INT i, CS_INT j, CS_ENTRY aij, void *other)
+{
+    return (aij != 0) ;
+}
+CS_INT cs_dropzeros (cs *A)
+{
+    return (cs_fkeep (A, &cs_nonzero, NULL)) ;  /* keep all nonzero entries */
+} 
diff --git a/src/cs/cs_dupl.c b/src/cs/cs_dupl.c
new file mode 100644
index 0000000..a775cdb
--- /dev/null
+++ b/src/cs/cs_dupl.c
@@ -0,0 +1,54 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* remove duplicate entries from A */
+CS_INT cs_dupl (cs *A)
+{
+    CS_INT i, j, p, q, nz = 0, n, m, *Ap, *Ai, *w ;
+    CS_ENTRY *Ax ;
+    if (!CS_CSC (A)) return (0) ;               /* check inputs */
+    m = A->m ; n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    w = cs_malloc (m, sizeof (CS_INT)) ;           /* get workspace */
+    if (!w) return (0) ;                        /* out of memory */
+    for (i = 0 ; i < m ; i++) w [i] = -1 ;      /* row i not yet seen */
+    for (j = 0 ; j < n ; j++)
+    {
+        q = nz ;                                /* column j will start at q */
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            i = Ai [p] ;                        /* A(i,j) is nonzero */
+            if (w [i] >= q)
+            {
+                Ax [w [i]] += Ax [p] ;          /* A(i,j) is a duplicate */
+            }
+            else
+            {
+                w [i] = nz ;                    /* record where row i occurs */
+                Ai [nz] = i ;                   /* keep A(i,j) */
+                Ax [nz++] = Ax [p] ;
+            }
+        }
+        Ap [j] = q ;                            /* record start of column j */
+    }
+    Ap [n] = nz ;                               /* finalize A */
+    cs_free (w) ;                               /* free workspace */
+    return (cs_sprealloc (A, 0)) ;              /* remove extra space from A */
+}
diff --git a/src/cs/cs_entry.c b/src/cs/cs_entry.c
new file mode 100644
index 0000000..1630c76
--- /dev/null
+++ b/src/cs/cs_entry.c
@@ -0,0 +1,33 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* add an entry to a triplet matrix; return 1 if ok, 0 otherwise */
+CS_INT cs_entry (cs *T, CS_INT i, CS_INT j, CS_ENTRY x)
+{
+    if (!CS_TRIPLET (T) || i < 0 || j < 0) return (0) ;     /* check inputs */
+    if (T->nz >= T->nzmax && !cs_sprealloc (T,2*(T->nzmax))) return (0) ;
+    if (T->x) T->x [T->nz] = x ;
+    T->i [T->nz] = i ;
+    T->p [T->nz++] = j ;
+    T->m = CS_MAX (T->m, i+1) ;
+    T->n = CS_MAX (T->n, j+1) ;
+    return (1) ;
+}
diff --git a/src/cs/cs_ereach.c b/src/cs/cs_ereach.c
new file mode 100644
index 0000000..8ae79e4
--- /dev/null
+++ b/src/cs/cs_ereach.c
@@ -0,0 +1,43 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* find nonzero pattern of Cholesky L(k,1:k-1) using etree and triu(A(:,k)) */
+CS_INT cs_ereach (const cs *A, CS_INT k, const CS_INT *parent, CS_INT *s, CS_INT *w)
+{
+    CS_INT i, p, n, len, top, *Ap, *Ai ;
+    if (!CS_CSC (A) || !parent || !s || !w) return (-1) ;   /* check inputs */
+    top = n = A->n ; Ap = A->p ; Ai = A->i ;
+    CS_MARK (w, k) ;                /* mark node k as visited */
+    for (p = Ap [k] ; p < Ap [k+1] ; p++)
+    {
+        i = Ai [p] ;                /* A(i,k) is nonzero */
+        if (i > k) continue ;       /* only use upper triangular part of A */
+        for (len = 0 ; !CS_MARKED (w,i) ; i = parent [i]) /* traverse up etree*/
+        {
+            s [len++] = i ;         /* L(k,i) is nonzero */
+            CS_MARK (w, i) ;        /* mark i as visited */
+        }
+        while (len > 0) s [--top] = s [--len] ; /* push path onto stack */
+    }
+    for (p = top ; p < n ; p++) CS_MARK (w, s [p]) ;    /* unmark all nodes */
+    CS_MARK (w, k) ;                /* unmark node k */
+    return (top) ;                  /* s [top..n-1] contains pattern of L(k,:)*/
+}
diff --git a/src/cs/cs_etree.c b/src/cs/cs_etree.c
new file mode 100644
index 0000000..0d815b7
--- /dev/null
+++ b/src/cs/cs_etree.c
@@ -0,0 +1,50 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* compute the etree of A (using triu(A), or A'A without forming A'A */
+CS_INT *cs_etree (const cs *A, CS_INT ata)
+{
+    CS_INT i, k, p, m, n, inext, *Ap, *Ai, *w, *parent, *ancestor, *prev ;
+    if (!CS_CSC (A)) return (NULL) ;        /* check inputs */
+    m = A->m ; n = A->n ; Ap = A->p ; Ai = A->i ;
+    parent = cs_malloc (n, sizeof (CS_INT)) ;              /* allocate result */
+    w = cs_malloc (n + (ata ? m : 0), sizeof (CS_INT)) ;   /* get workspace */
+    if (!w || !parent) return (cs_idone (parent, NULL, w, 0)) ;
+    ancestor = w ; prev = w + n ;
+    if (ata) for (i = 0 ; i < m ; i++) prev [i] = -1 ;
+    for (k = 0 ; k < n ; k++)
+    {
+        parent [k] = -1 ;                   /* node k has no parent yet */
+        ancestor [k] = -1 ;                 /* nor does k have an ancestor */
+        for (p = Ap [k] ; p < Ap [k+1] ; p++)
+        {
+            i = ata ? (prev [Ai [p]]) : (Ai [p]) ;
+            for ( ; i != -1 && i < k ; i = inext)   /* traverse from i to k */
+            {
+                inext = ancestor [i] ;              /* inext = ancestor of i */
+                ancestor [i] = k ;                  /* path compression */
+                if (inext == -1) parent [i] = k ;   /* no anc., parent is k */
+            }
+            if (ata) prev [Ai [p]] = k ;
+        }
+    }
+    return (cs_idone (parent, NULL, w, 1)) ;
+}
diff --git a/src/cs/cs_fkeep.c b/src/cs/cs_fkeep.c
new file mode 100644
index 0000000..91820bb
--- /dev/null
+++ b/src/cs/cs_fkeep.c
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* drop entries for which fkeep(A(i,j)) is false; return nz if OK, else -1 */
+CS_INT cs_fkeep (cs *A, CS_INT (*fkeep) (CS_INT, CS_INT, CS_ENTRY, void *), void *other)
+{
+    CS_INT j, p, nz = 0, n, *Ap, *Ai ;
+    CS_ENTRY *Ax ;
+    if (!CS_CSC (A) || !fkeep) return (-1) ;    /* check inputs */
+    n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    for (j = 0 ; j < n ; j++)
+    {
+        p = Ap [j] ;                        /* get current location of col j */
+        Ap [j] = nz ;                       /* record new location of col j */
+        for ( ; p < Ap [j+1] ; p++)
+        {
+            if (fkeep (Ai [p], j, Ax ? Ax [p] : 1, other))
+            {
+                if (Ax) Ax [nz] = Ax [p] ;  /* keep A(i,j) */
+                Ai [nz++] = Ai [p] ;
+            }
+        }
+    }
+    Ap [n] = nz ;                           /* finalize A */
+    cs_sprealloc (A, 0) ;                   /* remove extra space from A */
+    return (nz) ;
+}
diff --git a/src/cs/cs_gaxpy.c b/src/cs/cs_gaxpy.c
new file mode 100644
index 0000000..8c70bd8
--- /dev/null
+++ b/src/cs/cs_gaxpy.c
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* y = A*x+y */
+CS_INT cs_gaxpy (const cs *A, const CS_ENTRY *x, CS_ENTRY *y)
+{
+    CS_INT p, j, n, *Ap, *Ai ;
+    CS_ENTRY *Ax ;
+    if (!CS_CSC (A) || !x || !y) return (0) ;       /* check inputs */
+    n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    for (j = 0 ; j < n ; j++)
+    {
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            y [Ai [p]] += Ax [p] * x [j] ;
+        }
+    }
+    return (1) ;
+}
diff --git a/src/cs/cs_happly.c b/src/cs/cs_happly.c
new file mode 100644
index 0000000..02431be
--- /dev/null
+++ b/src/cs/cs_happly.c
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* apply the ith Householder vector to x */
+CS_INT cs_happly (const cs *V, CS_INT i, double beta, CS_ENTRY *x)
+{
+    CS_INT p, *Vp, *Vi ;
+    CS_ENTRY *Vx, tau = 0 ;
+    if (!CS_CSC (V) || !x) return (0) ;     /* check inputs */
+    Vp = V->p ; Vi = V->i ; Vx = V->x ;
+    for (p = Vp [i] ; p < Vp [i+1] ; p++)   /* tau = v'*x */
+    {
+        tau += CS_CONJ (Vx [p]) * x [Vi [p]] ;
+    }
+    tau *= beta ;                           /* tau = beta*(v'*x) */
+    for (p = Vp [i] ; p < Vp [i+1] ; p++)   /* x = x - v*tau */
+    {
+        x [Vi [p]] -= Vx [p] * tau ;
+    }
+    return (1) ;
+}
diff --git a/src/cs/cs_house.c b/src/cs/cs_house.c
new file mode 100644
index 0000000..f719db7
--- /dev/null
+++ b/src/cs/cs_house.c
@@ -0,0 +1,50 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* create a Householder reflection [v,beta,s]=house(x), overwrite x with v,
+ * where (I-beta*v*v')*x = s*e1 and e1 = [1 0 ... 0]'.
+ * Note that this CXSparse version is different than CSparse.  See Higham,
+ * Accuracy & Stability of Num Algorithms, 2nd ed, 2002, page 357. */
+CS_ENTRY cs_house (CS_ENTRY *x, double *beta, CS_INT n)
+{
+    CS_ENTRY s = 0 ;
+    CS_INT i ;
+    if (!x || !beta) return (-1) ;          /* check inputs */
+    /* s = norm(x) */
+    for (i = 0 ; i < n ; i++) s += x [i] * CS_CONJ (x [i]) ;
+    s = sqrt (s) ;
+    if (s == 0)
+    {
+        (*beta) = 0 ;
+        x [0] = 1 ;
+    }
+    else
+    {
+        /* s = sign(x[0]) * norm (x) ; */
+        if (x [0] != 0)
+        {
+            s *= x [0] / CS_ABS (x [0]) ;
+        }
+        x [0] += s ;
+        (*beta) = 1. / CS_REAL (CS_CONJ (s) * x [0]) ;
+    }
+    return (-s) ;
+}
diff --git a/src/cs/cs_ipvec.c b/src/cs/cs_ipvec.c
new file mode 100644
index 0000000..ad58333
--- /dev/null
+++ b/src/cs/cs_ipvec.c
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* x(p) = b, for dense vectors x and b; p=NULL denotes identity */
+CS_INT cs_ipvec (const CS_INT *p, const CS_ENTRY *b, CS_ENTRY *x, CS_INT n)
+{
+    CS_INT k ;
+    if (!x || !b) return (0) ;                              /* check inputs */
+    for (k = 0 ; k < n ; k++) x [p ? p [k] : k] = b [k] ;
+    return (1) ;
+}
diff --git a/src/cs/cs_leaf.c b/src/cs/cs_leaf.c
new file mode 100644
index 0000000..6e6cceb
--- /dev/null
+++ b/src/cs/cs_leaf.c
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* consider A(i,j), node j in ith row subtree and return lca(jprev,j) */
+CS_INT cs_leaf (CS_INT i, CS_INT j, const CS_INT *first, CS_INT *maxfirst, CS_INT *prevleaf,
+    CS_INT *ancestor, CS_INT *jleaf)
+{
+    CS_INT q, s, sparent, jprev ;
+    if (!first || !maxfirst || !prevleaf || !ancestor || !jleaf) return (-1) ;
+    *jleaf = 0 ;
+    if (i <= j || first [j] <= maxfirst [i]) return (-1) ;  /* j not a leaf */
+    maxfirst [i] = first [j] ;      /* update max first[j] seen so far */
+    jprev = prevleaf [i] ;          /* jprev = previous leaf of ith subtree */
+    prevleaf [i] = j ;
+    *jleaf = (jprev == -1) ? 1: 2 ; /* j is first or subsequent leaf */
+    if (*jleaf == 1) return (i) ;   /* if 1st leaf, q = root of ith subtree */
+    for (q = jprev ; q != ancestor [q] ; q = ancestor [q]) ;
+    for (s = jprev ; s != q ; s = sparent)
+    {
+        sparent = ancestor [s] ;    /* path compression */
+        ancestor [s] = q ;
+    }
+    return (q) ;                    /* q = least common ancester (jprev,j) */
+}
diff --git a/src/cs/cs_load.c b/src/cs/cs_load.c
new file mode 100644
index 0000000..0730d82
--- /dev/null
+++ b/src/cs/cs_load.c
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* load a triplet matrix from a file */
+cs *cs_load (FILE *f)
+{
+    CS_INT i, j ;
+    double x ;
+#ifdef CS_COMPLEX
+    double xi ;
+#endif
+    cs *T ;
+    if (!f) return (NULL) ;                             /* check inputs */
+    T = cs_spalloc (0, 0, 1, 1, 1) ;                    /* allocate result */
+#ifdef CS_COMPLEX
+    while (fscanf (f, ""CS_ID" "CS_ID" %lg %lg\n", &i, &j, &x, &xi) == 4)
+#else
+    while (fscanf (f, ""CS_ID" "CS_ID" %lg\n", &i, &j, &x) == 3)
+#endif
+    {
+#ifdef CS_COMPLEX
+        if (!cs_entry (T, i, j, x + xi*I)) return (cs_spfree (T)) ;
+#else
+        if (!cs_entry (T, i, j, x)) return (cs_spfree (T)) ;
+#endif
+    }
+    return (T) ;
+}
diff --git a/src/cs/cs_lsolve.c b/src/cs/cs_lsolve.c
new file mode 100644
index 0000000..1ec645d
--- /dev/null
+++ b/src/cs/cs_lsolve.c
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* solve Lx=b where x and b are dense.  x=b on input, solution on output. */
+CS_INT cs_lsolve (const cs *L, CS_ENTRY *x)
+{
+    CS_INT p, j, n, *Lp, *Li ;
+    CS_ENTRY *Lx ;
+    if (!CS_CSC (L) || !x) return (0) ;                     /* check inputs */
+    n = L->n ; Lp = L->p ; Li = L->i ; Lx = L->x ;
+    for (j = 0 ; j < n ; j++)
+    {
+        x [j] /= Lx [Lp [j]] ;
+        for (p = Lp [j]+1 ; p < Lp [j+1] ; p++)
+        {
+            x [Li [p]] -= Lx [p] * x [j] ;
+        }
+    }
+    return (1) ;
+}
diff --git a/src/cs/cs_ltsolve.c b/src/cs/cs_ltsolve.c
new file mode 100644
index 0000000..6610216
--- /dev/null
+++ b/src/cs/cs_ltsolve.c
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* solve L'x=b where x and b are dense.  x=b on input, solution on output. */
+CS_INT cs_ltsolve (const cs *L, CS_ENTRY *x)
+{
+    CS_INT p, j, n, *Lp, *Li ;
+    CS_ENTRY *Lx ;
+    if (!CS_CSC (L) || !x) return (0) ;                     /* check inputs */
+    n = L->n ; Lp = L->p ; Li = L->i ; Lx = L->x ;
+    for (j = n-1 ; j >= 0 ; j--)
+    {
+        for (p = Lp [j]+1 ; p < Lp [j+1] ; p++)
+        {
+            x [j] -= CS_CONJ (Lx [p]) * x [Li [p]] ;
+        }
+        x [j] /= CS_CONJ (Lx [Lp [j]]) ;
+    }
+    return (1) ;
+}
diff --git a/src/cs/cs_lu.c b/src/cs/cs_lu.c
new file mode 100644
index 0000000..38e1525
--- /dev/null
+++ b/src/cs/cs_lu.c
@@ -0,0 +1,109 @@
+/*
+ * 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 "-Wconversion"
+
+#include "cs.h"
+/* [L,U,pinv]=lu(A, [q lnz unz]). lnz and unz can be guess */
+csn *cs_lu (const cs *A, const css *S, double tol)
+{
+    cs *L, *U ;
+    csn *N ;
+    CS_ENTRY pivot, *Lx, *Ux, *x ;
+    double a, t ;
+    CS_INT *Lp, *Li, *Up, *Ui, *pinv, *xi, *q, n, ipiv, k, top, p, i, col, lnz,unz;
+    if (!CS_CSC (A) || !S) return (NULL) ;          /* check inputs */
+    n = A->n ;
+    q = S->q ; lnz = S->lnz ; unz = S->unz ;
+    x = cs_malloc (n, sizeof (CS_ENTRY)) ;            /* get CS_ENTRY workspace */
+    xi = cs_malloc (2*n, sizeof (CS_INT)) ;            /* get CS_INT workspace */
+    N = cs_calloc (1, sizeof (csn)) ;               /* allocate result */
+    if (!x || !xi || !N) return (cs_ndone (N, NULL, xi, x, 0)) ;
+    N->L = L = cs_spalloc (n, n, lnz, 1, 0) ;       /* allocate result L */
+    N->U = U = cs_spalloc (n, n, unz, 1, 0) ;       /* allocate result U */
+    N->pinv = pinv = cs_malloc (n, sizeof (CS_INT)) ;  /* allocate result pinv */
+    if (!L || !U || !pinv) return (cs_ndone (N, NULL, xi, x, 0)) ;
+    Lp = L->p ; Up = U->p ;
+    for (i = 0 ; i < n ; i++) x [i] = 0 ;           /* clear workspace */
+    for (i = 0 ; i < n ; i++) pinv [i] = -1 ;       /* no rows pivotal yet */
+    for (k = 0 ; k <= n ; k++) Lp [k] = 0 ;         /* no cols of L yet */
+    lnz = unz = 0 ;
+    for (k = 0 ; k < n ; k++)       /* compute L(:,k) and U(:,k) */
+    {
+        /* --- Triangular solve --------------------------------------------- */
+        Lp [k] = lnz ;              /* L(:,k) starts here */
+        Up [k] = unz ;              /* U(:,k) starts here */
+        if ((lnz + n > L->nzmax && !cs_sprealloc (L, 2*L->nzmax + n)) ||
+            (unz + n > U->nzmax && !cs_sprealloc (U, 2*U->nzmax + n)))
+        {
+            return (cs_ndone (N, NULL, xi, x, 0)) ;
+        }
+        Li = L->i ; Lx = L->x ; Ui = U->i ; Ux = U->x ;
+        col = q ? (q [k]) : k ;
+        top = cs_spsolve (L, A, col, xi, x, pinv, 1) ;  /* x = L\A(:,col) */
+        /* --- Find pivot --------------------------------------------------- */
+        ipiv = -1 ;
+        a = -1 ;
+        for (p = top ; p < n ; p++)
+        {
+            i = xi [p] ;            /* x(i) is nonzero */
+            if (pinv [i] < 0)       /* row i is not yet pivotal */
+            {
+                if ((t = CS_ABS (x [i])) > a)
+                {
+                    a = t ;         /* largest pivot candidate so far */
+                    ipiv = i ;
+                }
+            }
+            else                    /* x(i) is the entry U(pinv[i],k) */
+            {
+                Ui [unz] = pinv [i] ;
+                Ux [unz++] = x [i] ;
+            }
+        }
+        if (ipiv == -1 || a <= 0) return (cs_ndone (N, NULL, xi, x, 0)) ;
+        if (pinv [col] < 0 && CS_ABS (x [col]) >= a*tol) ipiv = col ;
+        /* --- Divide by pivot ---------------------------------------------- */
+        pivot = x [ipiv] ;          /* the chosen pivot */
+        Ui [unz] = k ;              /* last entry in U(:,k) is U(k,k) */
+        Ux [unz++] = pivot ;
+        pinv [ipiv] = k ;           /* ipiv is the kth pivot row */
+        Li [lnz] = ipiv ;           /* first entry in L(:,k) is L(k,k) = 1 */
+        Lx [lnz++] = 1 ;
+        for (p = top ; p < n ; p++) /* L(k+1:n,k) = x / pivot */
+        {
+            i = xi [p] ;
+            if (pinv [i] < 0)       /* x(i) is an entry in L(:,k) */
+            {
+                Li [lnz] = i ;      /* save unpermuted row in L */
+                Lx [lnz++] = x [i] / pivot ;    /* scale pivot column */
+            }
+            x [i] = 0 ;             /* x [0..n-1] = 0 for next k */
+        }
+    }
+    /* --- Finalize L and U ------------------------------------------------- */
+    Lp [n] = lnz ;
+    Up [n] = unz ;
+    Li = L->i ;                     /* fix row indices of L for final pinv */
+    for (p = 0 ; p < lnz ; p++) Li [p] = pinv [Li [p]] ;
+    cs_sprealloc (L, 0) ;           /* remove extra space from L and U */
+    cs_sprealloc (U, 0) ;
+    return (cs_ndone (N, NULL, xi, x, 1)) ;     /* success */
+}
diff --git a/src/cs/cs_lusol.c b/src/cs/cs_lusol.c
new file mode 100644
index 0000000..492fcd6
--- /dev/null
+++ b/src/cs/cs_lusol.c
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* x=A\b where A is unsymmetric; b overwritten with solution */
+CS_INT cs_lusol (CS_INT order, const cs *A, CS_ENTRY *b, double tol)
+{
+    CS_ENTRY *x ;
+    css *S ;
+    csn *N ;
+    CS_INT n, ok ;
+    if (!CS_CSC (A) || !b) return (0) ;     /* check inputs */
+    n = A->n ;
+    S = cs_sqr (order, A, 0) ;              /* ordering and symbolic analysis */
+    N = cs_lu (A, S, tol) ;                 /* numeric LU factorization */
+    x = cs_malloc (n, sizeof (CS_ENTRY)) ;    /* get workspace */
+    ok = (S && N && x) ;
+    if (ok)
+    {
+        cs_ipvec (N->pinv, b, x, n) ;       /* x = b(p) */
+        cs_lsolve (N->L, x) ;               /* x = L\x */
+        cs_usolve (N->U, x) ;               /* x = U\x */
+        cs_ipvec (S->q, x, b, n) ;          /* b(q) = x */
+    }
+    cs_free (x) ;
+    cs_sfree (S) ;
+    cs_nfree (N) ;
+    return (ok) ;
+}
diff --git a/src/cs/cs_malloc.c b/src/cs/cs_malloc.c
new file mode 100644
index 0000000..f9eb876
--- /dev/null
+++ b/src/cs/cs_malloc.c
@@ -0,0 +1,57 @@
+/*
+ * 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"
+#ifdef MATLAB_MEX_FILE
+#define malloc mxMalloc
+#define free mxFree
+#define realloc mxRealloc
+#define calloc mxCalloc
+#endif
+
+/* wrapper for malloc */
+void *cs_malloc (CS_INT n, size_t size)
+{
+    return (malloc (CS_MAX (n,1) * size)) ;
+}
+
+/* wrapper for calloc */
+void *cs_calloc (CS_INT n, size_t size)
+{
+    return (calloc (CS_MAX (n,1), size)) ;
+}
+
+/* wrapper for free */
+void *cs_free (void *p)
+{
+    if (p) free (p) ;       /* free p if it is not already NULL */
+    return (NULL) ;         /* return NULL to simplify the use of cs_free */
+}
+
+/* wrapper for realloc */
+void *cs_realloc (void *p, CS_INT n, size_t size, CS_INT *ok)
+{
+    void *pnew ;
+    pnew = realloc (p, CS_MAX (n,1) * size) ; /* realloc the block */
+    *ok = (pnew != NULL) ;                  /* realloc fails if pnew is NULL */
+    return ((*ok) ? pnew : p) ;             /* return original p if failure */
+}
diff --git a/src/cs/cs_maxtrans.c b/src/cs/cs_maxtrans.c
new file mode 100644
index 0000000..b5edb3d
--- /dev/null
+++ b/src/cs/cs_maxtrans.c
@@ -0,0 +1,112 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* find an augmenting path starting at column k and extend the match if found */
+static void cs_augment (CS_INT k, const cs *A, CS_INT *jmatch, CS_INT *cheap, CS_INT *w,
+        CS_INT *js, CS_INT *is, CS_INT *ps)
+{
+    CS_INT found = 0, p, i = -1, *Ap = A->p, *Ai = A->i, head = 0, j ;
+    js [0] = k ;                        /* start with just node k in jstack */
+    while (head >= 0)
+    {
+        /* --- Start (or continue) depth-first-search at node j ------------- */
+        j = js [head] ;                 /* get j from top of jstack */
+        if (w [j] != k)                 /* 1st time j visited for kth path */
+        {
+            w [j] = k ;                 /* mark j as visited for kth path */
+            for (p = cheap [j] ; p < Ap [j+1] && !found ; p++)
+            {
+                i = Ai [p] ;            /* try a cheap assignment (i,j) */
+                found = (jmatch [i] == -1) ;
+            }
+            cheap [j] = p ;             /* start here next time j is traversed*/
+            if (found)
+            {
+                is [head] = i ;         /* column j matched with row i */
+                break ;                 /* end of augmenting path */
+            }
+            ps [head] = Ap [j] ;        /* no cheap match: start dfs for j */
+        }
+        /* --- Depth-first-search of neighbors of j ------------------------- */
+        for (p = ps [head] ; p < Ap [j+1] ; p++)
+        {
+            i = Ai [p] ;                /* consider row i */
+            if (w [jmatch [i]] == k) continue ; /* skip jmatch [i] if marked */
+            ps [head] = p + 1 ;         /* pause dfs of node j */
+            is [head] = i ;             /* i will be matched with j if found */
+            js [++head] = jmatch [i] ;  /* start dfs at column jmatch [i] */
+            break ;
+        }
+        if (p == Ap [j+1]) head-- ;     /* node j is done; pop from stack */
+    }                                   /* augment the match if path found: */
+    if (found) for (p = head ; p >= 0 ; p--) jmatch [is [p]] = js [p] ;
+}
+
+/* find a maximum transveral */
+CS_INT *cs_maxtrans (const cs *A, CS_INT seed)  /*[jmatch [0..m-1]; imatch [0..n-1]]*/
+{
+    CS_INT i, j, k, n, m, p, n2 = 0, m2 = 0, *Ap, *jimatch, *w, *cheap, *js, *is,
+        *ps, *Ai, *Cp, *jmatch, *imatch, *q ;
+    cs *C ;
+    if (!CS_CSC (A)) return (NULL) ;                /* check inputs */
+    n = A->n ; m = A->m ; Ap = A->p ; Ai = A->i ;
+    w = jimatch = cs_calloc (m+n, sizeof (CS_INT)) ;   /* allocate result */
+    if (!jimatch) return (NULL) ;
+    for (k = 0, j = 0 ; j < n ; j++)    /* count nonempty rows and columns */
+    {
+        n2 += (Ap [j] < Ap [j+1]) ;
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            w [Ai [p]] = 1 ;
+            k += (j == Ai [p]) ;        /* count entries already on diagonal */
+        }
+    }
+    if (k == CS_MIN (m,n))              /* quick return if diagonal zero-free */
+    {
+        jmatch = jimatch ; imatch = jimatch + m ;
+        for (i = 0 ; i < k ; i++) jmatch [i] = i ;
+        for (      ; i < m ; i++) jmatch [i] = -1 ;
+        for (j = 0 ; j < k ; j++) imatch [j] = j ;
+        for (      ; j < n ; j++) imatch [j] = -1 ;
+        return (cs_idone (jimatch, NULL, NULL, 1)) ;
+    }
+    for (i = 0 ; i < m ; i++) m2 += w [i] ;
+    C = (m2 < n2) ? cs_transpose (A,0) : ((cs *) A) ; /* transpose if needed */
+    if (!C) return (cs_idone (jimatch, (m2 < n2) ? C : NULL, NULL, 0)) ;
+    n = C->n ; m = C->m ; Cp = C->p ;
+    jmatch = (m2 < n2) ? jimatch + n : jimatch ;
+    imatch = (m2 < n2) ? jimatch : jimatch + m ;
+    w = cs_malloc (5*n, sizeof (CS_INT)) ;             /* get workspace */
+    if (!w) return (cs_idone (jimatch, (m2 < n2) ? C : NULL, w, 0)) ;
+    cheap = w + n ; js = w + 2*n ; is = w + 3*n ; ps = w + 4*n ;
+    for (j = 0 ; j < n ; j++) cheap [j] = Cp [j] ;  /* for cheap assignment */
+    for (j = 0 ; j < n ; j++) w [j] = -1 ;          /* all columns unflagged */
+    for (i = 0 ; i < m ; i++) jmatch [i] = -1 ;     /* nothing matched yet */
+    q = cs_randperm (n, seed) ;                     /* q = random permutation */
+    for (k = 0 ; k < n ; k++)   /* augment, starting at column q[k] */
+    {
+        cs_augment (q ? q [k]: k, C, jmatch, cheap, w, js, is, ps) ;
+    }
+    cs_free (q) ;
+    for (j = 0 ; j < n ; j++) imatch [j] = -1 ;     /* find row match */
+    for (i = 0 ; i < m ; i++) if (jmatch [i] >= 0) imatch [jmatch [i]] = i ;
+    return (cs_idone (jimatch, (m2 < n2) ? C : NULL, w, 1)) ;
+}
diff --git a/src/cs/cs_multiply.c b/src/cs/cs_multiply.c
new file mode 100644
index 0000000..c630894
--- /dev/null
+++ b/src/cs/cs_multiply.c
@@ -0,0 +1,55 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* C = A*B */
+cs *cs_multiply (const cs *A, const cs *B)
+{
+    CS_INT p, j, nz = 0, anz, *Cp, *Ci, *Bp, m, n, bnz, *w, values, *Bi ;
+    CS_ENTRY *x, *Bx, *Cx ;
+    cs *C ;
+    if (!CS_CSC (A) || !CS_CSC (B)) return (NULL) ;      /* check inputs */
+    if (A->n != B->m) return (NULL) ;
+    m = A->m ; anz = A->p [A->n] ;
+    n = B->n ; Bp = B->p ; Bi = B->i ; Bx = B->x ; bnz = Bp [n] ;
+    w = cs_calloc (m, sizeof (CS_INT)) ;                    /* get workspace */
+    values = (A->x != NULL) && (Bx != NULL) ;
+    x = values ? cs_malloc (m, sizeof (CS_ENTRY)) : NULL ; /* get workspace */
+    C = cs_spalloc (m, n, anz + bnz, values, 0) ;        /* allocate result */
+    if (!C || !w || (values && !x)) return (cs_done (C, w, x, 0)) ;
+    Cp = C->p ;
+    for (j = 0 ; j < n ; j++)
+    {
+        if (nz + m > C->nzmax && !cs_sprealloc (C, 2*(C->nzmax)+m))
+        {
+            return (cs_done (C, w, x, 0)) ;             /* out of memory */
+        } 
+        Ci = C->i ; Cx = C->x ;         /* C->i and C->x may be reallocated */
+        Cp [j] = nz ;                   /* column j of C starts here */
+        for (p = Bp [j] ; p < Bp [j+1] ; p++)
+        {
+            nz = cs_scatter (A, Bi [p], Bx ? Bx [p] : 1, w, x, j+1, C, nz) ;
+        }
+        if (values) for (p = Cp [j] ; p < nz ; p++) Cx [p] = x [Ci [p]] ;
+    }
+    Cp [n] = nz ;                       /* finalize the last column of C */
+    cs_sprealloc (C, 0) ;               /* remove extra space from C */
+    return (cs_done (C, w, x, 1)) ;     /* success; free workspace, return C */
+}
diff --git a/src/cs/cs_norm.c b/src/cs/cs_norm.c
new file mode 100644
index 0000000..a095219
--- /dev/null
+++ b/src/cs/cs_norm.c
@@ -0,0 +1,36 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* 1-norm of a sparse matrix = max (sum (abs (A))), largest column sum */
+double cs_norm (const cs *A)
+{
+    CS_INT p, j, n, *Ap ;
+    CS_ENTRY *Ax ;
+    double norm = 0, s ;
+    if (!CS_CSC (A) || !A->x) return (-1) ;             /* check inputs */
+    n = A->n ; Ap = A->p ; Ax = A->x ;
+    for (j = 0 ; j < n ; j++)
+    {
+        for (s = 0, p = Ap [j] ; p < Ap [j+1] ; p++) s += CS_ABS (Ax [p]) ;
+        norm = CS_MAX (norm, s) ;
+    }
+    return (norm) ;
+}
diff --git a/src/cs/cs_permute.c b/src/cs/cs_permute.c
new file mode 100644
index 0000000..74f96dd
--- /dev/null
+++ b/src/cs/cs_permute.c
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* C = A(p,q) where p and q are permutations of 0..m-1 and 0..n-1. */
+cs *cs_permute (const cs *A, const CS_INT *pinv, const CS_INT *q, CS_INT values)
+{
+    CS_INT t, j, k, nz = 0, m, n, *Ap, *Ai, *Cp, *Ci ;
+    CS_ENTRY *Cx, *Ax ;
+    cs *C ;
+    if (!CS_CSC (A)) return (NULL) ;    /* check inputs */
+    m = A->m ; n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    C = cs_spalloc (m, n, Ap [n], values && Ax != NULL, 0) ;  /* alloc result */
+    if (!C) return (cs_done (C, NULL, NULL, 0)) ;   /* out of memory */
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    for (k = 0 ; k < n ; k++)
+    {
+        Cp [k] = nz ;                   /* column k of C is column q[k] of A */
+        j = q ? (q [k]) : k ;
+        for (t = Ap [j] ; t < Ap [j+1] ; t++)
+        {
+            if (Cx) Cx [nz] = Ax [t] ;  /* row i of A is row pinv[i] of C */
+            Ci [nz++] = pinv ? (pinv [Ai [t]]) : Ai [t] ;
+        }
+    }
+    Cp [n] = nz ;                       /* finalize the last column of C */
+    return (cs_done (C, NULL, NULL, 1)) ;
+}
diff --git a/src/cs/cs_pinv.c b/src/cs/cs_pinv.c
new file mode 100644
index 0000000..644024c
--- /dev/null
+++ b/src/cs/cs_pinv.c
@@ -0,0 +1,31 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* pinv = p', or p = pinv' */
+CS_INT *cs_pinv (CS_INT const *p, CS_INT n)
+{
+    CS_INT k, *pinv ;
+    if (!p) return (NULL) ;                     /* p = NULL denotes identity */
+    pinv = cs_malloc (n, sizeof (CS_INT)) ;        /* allocate result */
+    if (!pinv) return (NULL) ;                  /* out of memory */
+    for (k = 0 ; k < n ; k++) pinv [p [k]] = k ;/* invert the permutation */
+    return (pinv) ;                             /* return result */
+}
diff --git a/src/cs/cs_post.c b/src/cs/cs_post.c
new file mode 100644
index 0000000..209433f
--- /dev/null
+++ b/src/cs/cs_post.c
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* post order a forest */
+CS_INT *cs_post (const CS_INT *parent, CS_INT n)
+{
+    CS_INT j, k = 0, *post, *w, *head, *next, *stack ;
+    if (!parent) return (NULL) ;                        /* check inputs */
+    post = cs_malloc (n, sizeof (CS_INT)) ;                /* allocate result */
+    w = cs_malloc (3*n, sizeof (CS_INT)) ;                 /* get workspace */
+    if (!w || !post) return (cs_idone (post, NULL, w, 0)) ;
+    head = w ; next = w + n ; stack = w + 2*n ;
+    for (j = 0 ; j < n ; j++) head [j] = -1 ;           /* empty linked lists */
+    for (j = n-1 ; j >= 0 ; j--)            /* traverse nodes in reverse order*/
+    {
+        if (parent [j] == -1) continue ;    /* j is a root */
+        next [j] = head [parent [j]] ;      /* add j to list of its parent */
+        head [parent [j]] = j ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+        if (parent [j] != -1) continue ;    /* skip j if it is not a root */
+        k = cs_tdfs (j, k, head, next, post, stack) ;
+    }
+    return (cs_idone (post, NULL, w, 1)) ;  /* success; free w, return post */
+}
diff --git a/src/cs/cs_print.c b/src/cs/cs_print.c
new file mode 100644
index 0000000..5fb67a8
--- /dev/null
+++ b/src/cs/cs_print.c
@@ -0,0 +1,66 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* print a sparse matrix */
+/* CS_INT cs_print (const cs *A, CS_INT brief) */
+/* { */
+/*     CS_INT p, j, m, n, nzmax, nz, *Ap, *Ai ; */
+/*     CS_ENTRY *Ax ; */
+/*     if (!A) { printf ("(null)\n") ; return (0) ; } */
+/*     m = A->m ; n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ; */
+/*     nzmax = A->nzmax ; nz = A->nz ; */
+/*     printf ("CXSparse Version %d.%d.%d, %s.  %s\n", CS_VER, CS_SUBVER, */
+/*         CS_SUBSUB, CS_DATE, CS_COPYRIGHT) ; */
+/*     if (nz < 0) */
+/*     { */
+/*         printf (""CS_ID"-by-"CS_ID", nzmax: "CS_ID" nnz: "CS_ID", 1-norm: %g\n", m, n, nzmax, */
+/*                 Ap [n], cs_norm (A)) ; */
+/*         for (j = 0 ; j < n ; j++) */
+/*         { */
+/*             printf ("    col "CS_ID" : locations "CS_ID" to "CS_ID"\n", j, Ap [j], Ap [j+1]-1); */
+/*             for (p = Ap [j] ; p < Ap [j+1] ; p++) */
+/*             { */
+/* #ifdef CS_COMPLEX */
+/*                 printf ("      "CS_ID" : (%g, %g)\n", Ai [p],  */
+/* 		    Ax ? CS_REAL (Ax [p]) : 1, Ax ? CS_IMAG (Ax [p]) : 0) ; */
+/* #else */
+/*                 printf ("      "CS_ID" : %g\n", Ai [p], Ax ? Ax [p] : 1) ; */
+/* #endif */
+/*                 if (brief && p > 20) { printf ("  ...\n") ; return (1) ; } */
+/*             } */
+/*         } */
+/*     } */
+/*     else */
+/*     { */
+/*         printf ("triplet: "CS_ID"-by-"CS_ID", nzmax: "CS_ID" nnz: "CS_ID"\n", m, n, nzmax, nz) ; */
+/*         for (p = 0 ; p < nz ; p++) */
+/*         { */
+/* #ifdef CS_COMPLEX */
+/*             printf ("    "CS_ID" "CS_ID" : (%g, %g)\n", Ai [p], Ap [p],  */
+/* 		    Ax ? CS_REAL (Ax [p]) : 1, Ax ? CS_IMAG (Ax [p]) : 0) ; */
+/* #else */
+/*             printf ("    "CS_ID" "CS_ID" : %g\n", Ai [p], Ap [p], Ax ? Ax [p] : 1) ; */
+/* #endif */
+/*             if (brief && p > 20) { printf ("  ...\n") ; return (1) ; } */
+/*         } */
+/*     } */
+/*     return (1) ; */
+/* } */
diff --git a/src/cs/cs_pvec.c b/src/cs/cs_pvec.c
new file mode 100644
index 0000000..ac7f1d7
--- /dev/null
+++ b/src/cs/cs_pvec.c
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* x = b(p), for dense vectors x and b; p=NULL denotes identity */
+CS_INT cs_pvec (const CS_INT *p, const CS_ENTRY *b, CS_ENTRY *x, CS_INT n)
+{
+    CS_INT k ;
+    if (!x || !b) return (0) ;                              /* check inputs */
+    for (k = 0 ; k < n ; k++) x [k] = b [p ? p [k] : k] ;
+    return (1) ;
+}
diff --git a/src/cs/cs_qr.c b/src/cs/cs_qr.c
new file mode 100644
index 0000000..68090ca
--- /dev/null
+++ b/src/cs/cs_qr.c
@@ -0,0 +1,96 @@
+/*
+ * 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 "-Wconversion"
+
+#include "cs.h"
+/* sparse QR factorization [V,beta,pinv,R] = qr (A) */
+csn *cs_qr (const cs *A, const css *S)
+{
+    CS_ENTRY *Rx, *Vx, *Ax, *x ;
+    double *Beta ;
+    CS_INT i, k, p, m, n, vnz, p1, top, m2, len, col, rnz, *s, *leftmost, *Ap, *Ai,
+        *parent, *Rp, *Ri, *Vp, *Vi, *w, *pinv, *q ;
+    cs *R, *V ;
+    csn *N ;
+    if (!CS_CSC (A) || !S) return (NULL) ;
+    m = A->m ; n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    q = S->q ; parent = S->parent ; pinv = S->pinv ; m2 = S->m2 ;
+    vnz = S->lnz ; rnz = S->unz ; leftmost = S->leftmost ;
+    w = cs_malloc (m2+n, sizeof (CS_INT)) ;            /* get CS_INT workspace */
+    x = cs_malloc (m2, sizeof (CS_ENTRY)) ;           /* get CS_ENTRY workspace */
+    N = cs_calloc (1, sizeof (csn)) ;               /* allocate result */
+    if (!w || !x || !N) return (cs_ndone (N, NULL, w, x, 0)) ;
+    s = w + m2 ;                                    /* s is size n */
+    for (k = 0 ; k < m2 ; k++) x [k] = 0 ;          /* clear workspace x */
+    N->L = V = cs_spalloc (m2, n, vnz, 1, 0) ;      /* allocate result V */
+    N->U = R = cs_spalloc (m2, n, rnz, 1, 0) ;      /* allocate result R */
+    N->B = Beta = cs_malloc (n, sizeof (double)) ;  /* allocate result Beta */
+    if (!R || !V || !Beta) return (cs_ndone (N, NULL, w, x, 0)) ;
+    Rp = R->p ; Ri = R->i ; Rx = R->x ;
+    Vp = V->p ; Vi = V->i ; Vx = V->x ;
+    for (i = 0 ; i < m2 ; i++) w [i] = -1 ; /* clear w, to mark nodes */
+    rnz = 0 ; vnz = 0 ;
+    for (k = 0 ; k < n ; k++)               /* compute V and R */
+    {
+        Rp [k] = rnz ;                      /* R(:,k) starts here */
+        Vp [k] = p1 = vnz ;                 /* V(:,k) starts here */
+        w [k] = k ;                         /* add V(k,k) to pattern of V */
+        Vi [vnz++] = k ;
+        top = n ;
+        col = q ? q [k] : k ;
+        for (p = Ap [col] ; p < Ap [col+1] ; p++)   /* find R(:,k) pattern */
+        {
+            i = leftmost [Ai [p]] ;         /* i = min(find(A(i,q))) */
+            for (len = 0 ; w [i] != k ; i = parent [i]) /* traverse up to k */
+            {
+                s [len++] = i ;
+                w [i] = k ;
+            }
+            while (len > 0) s [--top] = s [--len] ; /* push path on stack */
+            i = pinv [Ai [p]] ;             /* i = permuted row of A(:,col) */
+            x [i] = Ax [p] ;                /* x (i) = A(:,col) */
+            if (i > k && w [i] < k)         /* pattern of V(:,k) = x (k+1:m) */
+            {
+                Vi [vnz++] = i ;            /* add i to pattern of V(:,k) */
+                w [i] = k ;
+            }
+        }
+        for (p = top ; p < n ; p++) /* for each i in pattern of R(:,k) */
+        {
+            i = s [p] ;                     /* R(i,k) is nonzero */
+            cs_happly (V, i, Beta [i], x) ; /* apply (V(i),Beta(i)) to x */
+            Ri [rnz] = i ;                  /* R(i,k) = x(i) */
+            Rx [rnz++] = x [i] ;
+            x [i] = 0 ;
+            if (parent [i] == k) vnz = cs_scatter (V, i, 0, w, NULL, k, V, vnz);
+        }
+        for (p = p1 ; p < vnz ; p++)        /* gather V(:,k) = x */
+        {
+            Vx [p] = x [Vi [p]] ;
+            x [Vi [p]] = 0 ;
+        }
+        Ri [rnz] = k ;                     /* R(k,k) = norm (x) */
+        Rx [rnz++] = cs_house (Vx+p1, Beta+k, vnz-p1) ; /* [v,beta]=house(x) */
+    }
+    Rp [n] = rnz ;                          /* finalize R */
+    Vp [n] = vnz ;                          /* finalize V */
+    return (cs_ndone (N, NULL, w, x, 1)) ;  /* success */
+}
diff --git a/src/cs/cs_qrsol.c b/src/cs/cs_qrsol.c
new file mode 100644
index 0000000..0ad45ff
--- /dev/null
+++ b/src/cs/cs_qrsol.c
@@ -0,0 +1,73 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* x=A\b where A can be rectangular; b overwritten with solution */
+CS_INT cs_qrsol (CS_INT order, const cs *A, CS_ENTRY *b)
+{
+    CS_ENTRY *x ;
+    css *S ;
+    csn *N ;
+    cs *AT = NULL ;
+    CS_INT k, m, n, ok ;
+    if (!CS_CSC (A) || !b) return (0) ; /* check inputs */
+    n = A->n ;
+    m = A->m ;
+    if (m >= n)
+    {
+        S = cs_sqr (order, A, 1) ;          /* ordering and symbolic analysis */
+        N = cs_qr (A, S) ;                  /* numeric QR factorization */
+        x = cs_calloc (S ? S->m2 : 1, sizeof (CS_ENTRY)) ;    /* get workspace */
+        ok = (S && N && x) ;
+        if (ok)
+        {
+            cs_ipvec (S->pinv, b, x, m) ;   /* x(0:m-1) = b(p(0:m-1) */
+            for (k = 0 ; k < n ; k++)       /* apply Householder refl. to x */
+            {
+                cs_happly (N->L, k, N->B [k], x) ;
+            }
+            cs_usolve (N->U, x) ;           /* x = R\x */
+            cs_ipvec (S->q, x, b, n) ;      /* b(q(0:n-1)) = x(0:n-1) */
+        }
+    }
+    else
+    {
+        AT = cs_transpose (A, 1) ;          /* Ax=b is underdetermined */
+        S = cs_sqr (order, AT, 1) ;         /* ordering and symbolic analysis */
+        N = cs_qr (AT, S) ;                 /* numeric QR factorization of A' */
+        x = cs_calloc (S ? S->m2 : 1, sizeof (CS_ENTRY)) ;    /* get workspace */
+        ok = (AT && S && N && x) ;
+        if (ok)
+        {
+            cs_pvec (S->q, b, x, m) ;       /* x(q(0:m-1)) = b(0:m-1) */
+            cs_utsolve (N->U, x) ;          /* x = R'\x */
+            for (k = m-1 ; k >= 0 ; k--)    /* apply Householder refl. to x */
+            {
+                cs_happly (N->L, k, N->B [k], x) ;
+            }
+            cs_pvec (S->pinv, x, b, n) ;    /* b(0:n-1) = x(p(0:n-1)) */
+        }
+    }
+    cs_free (x) ;
+    cs_sfree (S) ;
+    cs_nfree (N) ;
+    cs_spfree (AT) ;
+    return (ok) ;
+}
diff --git a/src/cs/cs_randperm.c b/src/cs/cs_randperm.c
new file mode 100644
index 0000000..014578a
--- /dev/null
+++ b/src/cs/cs_randperm.c
@@ -0,0 +1,44 @@
+/*
+ * 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/cs/cs_reach.c b/src/cs/cs_reach.c
new file mode 100644
index 0000000..35b43f8
--- /dev/null
+++ b/src/cs/cs_reach.c
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* xi [top...n-1] = nodes reachable from graph of G*P' via nodes in B(:,k).
+ * xi [n...2n-1] used as workspace */
+CS_INT cs_reach (cs *G, const cs *B, CS_INT k, CS_INT *xi, const CS_INT *pinv)
+{
+    CS_INT p, n, top, *Bp, *Bi, *Gp ;
+    if (!CS_CSC (G) || !CS_CSC (B) || !xi) return (-1) ;    /* check inputs */
+    n = G->n ; Bp = B->p ; Bi = B->i ; Gp = G->p ;
+    top = n ;
+    for (p = Bp [k] ; p < Bp [k+1] ; p++)
+    {
+        if (!CS_MARKED (Gp, Bi [p]))    /* start a dfs at unmarked node i */
+        {
+            top = cs_dfs (Bi [p], G, top, xi, xi+n, pinv) ;
+        }
+    }
+    for (p = top ; p < n ; p++) CS_MARK (Gp, xi [p]) ;  /* restore G */
+    return (top) ;
+}
diff --git a/src/cs/cs_scatter.c b/src/cs/cs_scatter.c
new file mode 100644
index 0000000..8910c62
--- /dev/null
+++ b/src/cs/cs_scatter.c
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* x = x + beta * A(:,j), where x is a dense vector and A(:,j) is sparse */
+CS_INT cs_scatter (const cs *A, CS_INT j, CS_ENTRY beta, CS_INT *w, CS_ENTRY *x, CS_INT mark,
+    cs *C, CS_INT nz)
+{
+    CS_INT i, p, *Ap, *Ai, *Ci ;
+    CS_ENTRY *Ax ;
+    if (!CS_CSC (A) || !w || !CS_CSC (C)) return (-1) ;     /* check inputs */
+    Ap = A->p ; Ai = A->i ; Ax = A->x ; Ci = C->i ;
+    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+    {
+        i = Ai [p] ;                            /* A(i,j) is nonzero */
+        if (w [i] < mark)
+        {
+            w [i] = mark ;                      /* i is new entry in column j */
+            Ci [nz++] = i ;                     /* add i to pattern of C(:,j) */
+            if (x) x [i] = beta * Ax [p] ;      /* x(i) = beta*A(i,j) */
+        }
+        else if (x) x [i] += beta * Ax [p] ;    /* i exists in C(:,j) already */
+    }
+    return (nz) ;
+}
diff --git a/src/cs/cs_scc.c b/src/cs/cs_scc.c
new file mode 100644
index 0000000..c9637ba
--- /dev/null
+++ b/src/cs/cs_scc.c
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* find the strongly connected components of a square matrix */
+csd *cs_scc (cs *A)     /* matrix A temporarily modified, then restored */
+{
+    CS_INT n, i, k, b, nb = 0, top, *xi, *pstack, *p, *r, *Ap, *ATp, *rcopy, *Blk ;
+    cs *AT ;
+    csd *D ;
+    if (!CS_CSC (A)) return (NULL) ;                /* check inputs */
+    n = A->n ; Ap = A->p ;
+    D = cs_dalloc (n, 0) ;                          /* allocate result */
+    AT = cs_transpose (A, 0) ;                      /* AT = A' */
+    xi = cs_malloc (2*n+1, sizeof (CS_INT)) ;          /* get workspace */
+    if (!D || !AT || !xi) return (cs_ddone (D, AT, xi, 0)) ;
+    Blk = xi ; rcopy = pstack = xi + n ;
+    p = D->p ; r = D->r ; ATp = AT->p ;
+    top = n ;
+    for (i = 0 ; i < n ; i++)   /* first dfs(A) to find finish times (xi) */
+    {
+        if (!CS_MARKED (Ap, i)) top = cs_dfs (i, A, top, xi, pstack, NULL) ;
+    }
+    for (i = 0 ; i < n ; i++) CS_MARK (Ap, i) ; /* restore A; unmark all nodes*/
+    top = n ;
+    nb = n ;
+    for (k = 0 ; k < n ; k++)   /* dfs(A') to find strongly connnected comp */
+    {
+        i = xi [k] ;            /* get i in reverse order of finish times */
+        if (CS_MARKED (ATp, i)) continue ;  /* skip node i if already ordered */
+        r [nb--] = top ;        /* node i is the start of a component in p */
+        top = cs_dfs (i, AT, top, p, pstack, NULL) ;
+    }
+    r [nb] = 0 ;                /* first block starts at zero; shift r up */
+    for (k = nb ; k <= n ; k++) r [k-nb] = r [k] ;
+    D->nb = nb = n-nb ;         /* nb = # of strongly connected components */
+    for (b = 0 ; b < nb ; b++)  /* sort each block in natural order */
+    {
+        for (k = r [b] ; k < r [b+1] ; k++) Blk [p [k]] = b ;
+    }
+    for (b = 0 ; b <= nb ; b++) rcopy [b] = r [b] ;
+    for (i = 0 ; i < n ; i++) p [rcopy [Blk [i]]++] = i ;
+    return (cs_ddone (D, AT, xi, 1)) ;
+}
diff --git a/src/cs/cs_schol.c b/src/cs/cs_schol.c
new file mode 100644
index 0000000..20f6d1e
--- /dev/null
+++ b/src/cs/cs_schol.c
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* ordering and symbolic analysis for a Cholesky factorization */
+css *cs_schol (CS_INT order, const cs *A)
+{
+    CS_INT n, *c, *post, *P ;
+    cs *C ;
+    css *S ;
+    if (!CS_CSC (A)) return (NULL) ;        /* check inputs */
+    n = A->n ;
+    S = cs_calloc (1, sizeof (css)) ;       /* allocate result S */
+    if (!S) return (NULL) ;                 /* out of memory */
+    P = cs_amd (order, A) ;                 /* P = amd(A+A'), or natural */
+    S->pinv = cs_pinv (P, n) ;              /* find inverse permutation */
+    cs_free (P) ;
+    if (order && !S->pinv) return (cs_sfree (S)) ;
+    C = cs_symperm (A, S->pinv, 0) ;        /* C = spones(triu(A(P,P))) */
+    S->parent = cs_etree (C, 0) ;           /* find etree of C */
+    post = cs_post (S->parent, n) ;         /* postorder the etree */
+    c = cs_counts (C, S->parent, post, 0) ; /* find column counts of chol(C) */
+    cs_free (post) ;
+    cs_spfree (C) ;
+    S->cp = cs_malloc (n+1, sizeof (CS_INT)) ; /* allocate result S->cp */
+    S->unz = S->lnz = cs_cumsum (S->cp, c, n) ; /* find column pointers for L */
+    cs_free (c) ;
+    return ((S->lnz >= 0) ? S : cs_sfree (S)) ;
+}
diff --git a/src/cs/cs_spsolve.c b/src/cs/cs_spsolve.c
new file mode 100644
index 0000000..175ab55
--- /dev/null
+++ b/src/cs/cs_spsolve.c
@@ -0,0 +1,48 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* solve Gx=b(:,k), where G is either upper (lo=0) or lower (lo=1) triangular */
+CS_INT cs_spsolve (cs *G, const cs *B, CS_INT k, CS_INT *xi, CS_ENTRY *x, const CS_INT *pinv,
+    CS_INT lo)
+{
+    CS_INT j, J, p, q, px, top, n, *Gp, *Gi, *Bp, *Bi ;
+    CS_ENTRY *Gx, *Bx ;
+    if (!CS_CSC (G) || !CS_CSC (B) || !xi || !x) return (-1) ;
+    Gp = G->p ; Gi = G->i ; Gx = G->x ; n = G->n ;
+    Bp = B->p ; Bi = B->i ; Bx = B->x ;
+    top = cs_reach (G, B, k, xi, pinv) ;        /* xi[top..n-1]=Reach(B(:,k)) */
+    for (p = top ; p < n ; p++) x [xi [p]] = 0 ;    /* clear x */
+    for (p = Bp [k] ; p < Bp [k+1] ; p++) x [Bi [p]] = Bx [p] ; /* scatter B */
+    for (px = top ; px < n ; px++)
+    {
+        j = xi [px] ;                               /* x(j) is nonzero */
+        J = pinv ? (pinv [j]) : j ;                 /* j maps to col J of G */
+        if (J < 0) continue ;                       /* column J is empty */
+        x [j] /= Gx [lo ? (Gp [J]) : (Gp [J+1]-1)] ;/* x(j) /= G(j,j) */
+        p = lo ? (Gp [J]+1) : (Gp [J]) ;            /* lo: L(j,j) 1st entry */
+        q = lo ? (Gp [J+1]) : (Gp [J+1]-1) ;        /* up: U(j,j) last entry */
+        for ( ; p < q ; p++)
+        {
+            x [Gi [p]] -= Gx [p] * x [j] ;          /* x(i) -= G(i,j) * x(j) */
+        }
+    }
+    return (top) ;                                  /* return top of stack */
+}
diff --git a/src/cs/cs_sqr.c b/src/cs/cs_sqr.c
new file mode 100644
index 0000000..1a7ec7f
--- /dev/null
+++ b/src/cs/cs_sqr.c
@@ -0,0 +1,108 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* compute nnz(V) = S->lnz, S->pinv, S->leftmost, S->m2 from A and S->parent */
+static CS_INT cs_vcount (const cs *A, css *S)
+{
+    CS_INT i, k, p, pa, n = A->n, m = A->m, *Ap = A->p, *Ai = A->i, *next, *head,
+        *tail, *nque, *pinv, *leftmost, *w, *parent = S->parent ;
+    S->pinv = pinv = cs_malloc (m+n, sizeof (CS_INT)) ;        /* allocate pinv, */
+    S->leftmost = leftmost = cs_malloc (m, sizeof (CS_INT)) ;  /* and leftmost */
+    w = cs_malloc (m+3*n, sizeof (CS_INT)) ;   /* get workspace */
+    if (!pinv || !w || !leftmost)
+    {
+        cs_free (w) ;                       /* pinv and leftmost freed later */
+        return (0) ;                        /* out of memory */
+    }
+    next = w ; head = w + m ; tail = w + m + n ; nque = w + m + 2*n ;
+    for (k = 0 ; k < n ; k++) head [k] = -1 ;   /* queue k is empty */
+    for (k = 0 ; k < n ; k++) tail [k] = -1 ;
+    for (k = 0 ; k < n ; k++) nque [k] = 0 ;
+    for (i = 0 ; i < m ; i++) leftmost [i] = -1 ;
+    for (k = n-1 ; k >= 0 ; k--)
+    {
+        for (p = Ap [k] ; p < Ap [k+1] ; p++)
+        {
+            leftmost [Ai [p]] = k ;         /* leftmost[i] = min(find(A(i,:)))*/
+        }
+    }
+    for (i = m-1 ; i >= 0 ; i--)            /* scan rows in reverse order */
+    {
+        pinv [i] = -1 ;                     /* row i is not yet ordered */
+        k = leftmost [i] ;
+        if (k == -1) continue ;             /* row i is empty */
+        if (nque [k]++ == 0) tail [k] = i ; /* first row in queue k */
+        next [i] = head [k] ;               /* put i at head of queue k */
+        head [k] = i ;
+    }
+    S->lnz = 0 ;
+    S->m2 = m ;
+    for (k = 0 ; k < n ; k++)               /* find row permutation and nnz(V)*/
+    {
+        i = head [k] ;                      /* remove row i from queue k */
+        S->lnz++ ;                          /* count V(k,k) as nonzero */
+        if (i < 0) i = S->m2++ ;            /* add a fictitious row */
+        pinv [i] = k ;                      /* associate row i with V(:,k) */
+        if (--nque [k] <= 0) continue ;     /* skip if V(k+1:m,k) is empty */
+        S->lnz += nque [k] ;                /* nque [k] is nnz (V(k+1:m,k)) */
+        if ((pa = parent [k]) != -1)        /* move all rows to parent of k */
+        {
+            if (nque [pa] == 0) tail [pa] = tail [k] ;
+            next [tail [k]] = head [pa] ;
+            head [pa] = next [i] ;
+            nque [pa] += nque [k] ;
+        }
+    }
+    for (i = 0 ; i < m ; i++) if (pinv [i] < 0) pinv [i] = k++ ;
+    cs_free (w) ;
+    return (1) ;
+}
+
+/* symbolic ordering and analysis for QR or LU */
+css *cs_sqr (CS_INT order, const cs *A, CS_INT qr)
+{
+    CS_INT n, k, ok = 1, *post ;
+    css *S ;
+    if (!CS_CSC (A)) return (NULL) ;        /* check inputs */
+    n = A->n ;
+    S = cs_calloc (1, sizeof (css)) ;       /* allocate result S */
+    if (!S) return (NULL) ;                 /* out of memory */
+    S->q = cs_amd (order, A) ;              /* fill-reducing ordering */
+    if (order && !S->q) return (cs_sfree (S)) ;
+    if (qr)                                 /* QR symbolic analysis */
+    {
+        cs *C = order ? cs_permute (A, NULL, S->q, 0) : ((cs *) A) ;
+        S->parent = cs_etree (C, 1) ;       /* etree of C'*C, where C=A(:,q) */
+        post = cs_post (S->parent, n) ;
+        S->cp = cs_counts (C, S->parent, post, 1) ;  /* col counts chol(C'*C) */
+        cs_free (post) ;
+        ok = C && S->parent && S->cp && cs_vcount (C, S) ;
+        if (ok) for (S->unz = 0, k = 0 ; k < n ; k++) S->unz += S->cp [k] ;
+        ok = ok && S->lnz >= 0 && S->unz >= 0 ;     /* CS_INT overflow guard */
+        if (order) cs_spfree (C) ;
+    }
+    else
+    {
+        S->unz = 4*(A->p [n]) + n ;         /* for LU factorization only, */
+        S->lnz = S->unz ;                   /* guess nnz(L) and nnz(U) */
+    }
+    return (ok ? S : cs_sfree (S)) ;        /* return result S */
+}
diff --git a/src/cs/cs_symperm.c b/src/cs/cs_symperm.c
new file mode 100644
index 0000000..33c24bc
--- /dev/null
+++ b/src/cs/cs_symperm.c
@@ -0,0 +1,59 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* C = A(p,p) where A and C are symmetric the upper part stored; pinv not p */
+cs *cs_symperm (const cs *A, const CS_INT *pinv, CS_INT values)
+{
+    CS_INT i, j, p, q, i2, j2, n, *Ap, *Ai, *Cp, *Ci, *w ;
+    CS_ENTRY *Cx, *Ax ;
+    cs *C ;
+    if (!CS_CSC (A)) return (NULL) ;                    /* check inputs */
+    n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    C = cs_spalloc (n, n, Ap [n], values && (Ax != NULL), 0) ; /* alloc result*/
+    w = cs_calloc (n, sizeof (CS_INT)) ;                   /* get workspace */
+    if (!C || !w) return (cs_done (C, w, NULL, 0)) ;    /* out of memory */
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    for (j = 0 ; j < n ; j++)           /* count entries in each column of C */
+    {
+        j2 = pinv ? pinv [j] : j ;      /* column j of A is column j2 of C */
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            i = Ai [p] ;
+            if (i > j) continue ;       /* skip lower triangular part of A */
+            i2 = pinv ? pinv [i] : i ;  /* row i of A is row i2 of C */
+            w [CS_MAX (i2, j2)]++ ;     /* column count of C */
+        }
+    }
+    cs_cumsum (Cp, w, n) ;              /* compute column pointers of C */
+    for (j = 0 ; j < n ; j++)
+    {
+        j2 = pinv ? pinv [j] : j ;      /* column j of A is column j2 of C */
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            i = Ai [p] ;
+            if (i > j) continue ;       /* skip lower triangular part of A*/
+            i2 = pinv ? pinv [i] : i ;  /* row i of A is row i2 of C */
+            Ci [q = w [CS_MAX (i2, j2)]++] = CS_MIN (i2, j2) ;
+            if (Cx) Cx [q] = (i2 <= j2) ? Ax [p] : CS_CONJ (Ax [p]) ;
+        }
+    }
+    return (cs_done (C, w, NULL, 1)) ;  /* success; free workspace, return C */
+}
diff --git a/src/cs/cs_tdfs.c b/src/cs/cs_tdfs.c
new file mode 100644
index 0000000..4b11ea1
--- /dev/null
+++ b/src/cs/cs_tdfs.c
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* depth-first search and postorder of a tree rooted at node j */
+CS_INT cs_tdfs (CS_INT j, CS_INT k, CS_INT *head, const CS_INT *next, CS_INT *post, CS_INT *stack)
+{
+    CS_INT i, p, top = 0 ;
+    if (!head || !next || !post || !stack) return (-1) ;    /* check inputs */
+    stack [0] = j ;                 /* place j on the stack */
+    while (top >= 0)                /* while (stack is not empty) */
+    {
+        p = stack [top] ;           /* p = top of stack */
+        i = head [p] ;              /* i = youngest child of p */
+        if (i == -1)
+        {
+            top-- ;                 /* p has no unordered children left */
+            post [k++] = p ;        /* node p is the kth postordered node */
+        }
+        else
+        {
+            head [p] = next [i] ;   /* remove i from children of p */
+            stack [++top] = i ;     /* start dfs on child node i */
+        }
+    }
+    return (k) ;
+}
diff --git a/src/cs/cs_transpose.c b/src/cs/cs_transpose.c
new file mode 100644
index 0000000..bf51a03
--- /dev/null
+++ b/src/cs/cs_transpose.c
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* C = A' */
+cs *cs_transpose (const cs *A, CS_INT values)
+{
+    CS_INT p, q, j, *Cp, *Ci, n, m, *Ap, *Ai, *w ;
+    CS_ENTRY *Cx, *Ax ;
+    cs *C ;
+    if (!CS_CSC (A)) return (NULL) ;    /* check inputs */
+    m = A->m ; n = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ;
+    C = cs_spalloc (n, m, Ap [n], values && Ax, 0) ;       /* allocate result */
+    w = cs_calloc (m, sizeof (CS_INT)) ;                      /* get workspace */
+    if (!C || !w) return (cs_done (C, w, NULL, 0)) ;       /* out of memory */
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    for (p = 0 ; p < Ap [n] ; p++) w [Ai [p]]++ ;          /* row counts */
+    cs_cumsum (Cp, w, m) ;                                 /* row pointers */
+    for (j = 0 ; j < n ; j++)
+    {
+        for (p = Ap [j] ; p < Ap [j+1] ; p++)
+        {
+            Ci [q = w [Ai [p]]++] = j ; /* place A(i,j) as entry C(j,i) */
+            if (Cx) Cx [q] = (values > 0) ? CS_CONJ (Ax [p]) : Ax [p] ;
+        }
+    }
+    return (cs_done (C, w, NULL, 1)) ;  /* success; free w and return C */
+}
diff --git a/src/cs/cs_updown.c b/src/cs/cs_updown.c
new file mode 100644
index 0000000..d6a2f19
--- /dev/null
+++ b/src/cs/cs_updown.c
@@ -0,0 +1,68 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* sparse Cholesky update/downdate, L*L' + sigma*w*w' (sigma = +1 or -1) */
+CS_INT cs_updown (cs *L, CS_INT sigma, const cs *C, const CS_INT *parent)
+{
+    CS_INT n, p, f, j, *Lp, *Li, *Cp, *Ci ;
+    CS_ENTRY *Lx, *Cx, alpha, gamma, w1, w2, *w ;
+    double beta = 1, beta2 = 1, delta ;
+#ifdef CS_COMPLEX
+    cs_complex_t phase ;
+#endif
+    if (!CS_CSC (L) || !CS_CSC (C) || !parent) return (0) ;  /* check inputs */
+    Lp = L->p ; Li = L->i ; Lx = L->x ; n = L->n ;
+    Cp = C->p ; Ci = C->i ; Cx = C->x ;
+    if ((p = Cp [0]) >= Cp [1]) return (1) ;        /* return if C empty */
+    w = cs_malloc (n, sizeof (CS_ENTRY)) ;          /* get workspace */
+    if (!w) return (0) ;                            /* out of memory */
+    f = Ci [p] ;
+    for ( ; p < Cp [1] ; p++) f = CS_MIN (f, Ci [p]) ;  /* f = min (find (C)) */
+    for (j = f ; j != -1 ; j = parent [j]) w [j] = 0 ;  /* clear workspace w */
+    for (p = Cp [0] ; p < Cp [1] ; p++) w [Ci [p]] = Cx [p] ; /* w = C */
+    for (j = f ; j != -1 ; j = parent [j])          /* walk path f up to root */
+    {
+        p = Lp [j] ;
+        alpha = w [j] / Lx [p] ;                    /* alpha = w(j) / L(j,j) */
+        beta2 = beta*beta + sigma*alpha*CS_CONJ(alpha) ;
+        if (beta2 <= 0) break ;                     /* not positive definite */
+        beta2 = sqrt (beta2) ;
+        delta = (sigma > 0) ? (beta / beta2) : (beta2 / beta) ;
+        gamma = sigma * CS_CONJ(alpha) / (beta2 * beta) ;
+        Lx [p] = delta * Lx [p] + ((sigma > 0) ? (gamma * w [j]) : 0) ;
+        beta = beta2 ;
+#ifdef CS_COMPLEX
+        phase = CS_ABS (Lx [p]) / Lx [p] ;  /* phase = abs(L(j,j))/L(j,j)*/
+        Lx [p] *= phase ;                   /* L(j,j) = L(j,j) * phase */
+#endif
+        for (p++ ; p < Lp [j+1] ; p++)
+        {
+            w1 = w [Li [p]] ;
+            w [Li [p]] = w2 = w1 - alpha * Lx [p] ;
+            Lx [p] = delta * Lx [p] + gamma * ((sigma > 0) ? w1 : w2) ;
+#ifdef CS_COMPLEX
+            Lx [p] *= phase ;               /* L(i,j) = L(i,j) * phase */
+#endif
+        }
+    }
+    cs_free (w) ;
+    return (beta2 > 0) ;
+}
diff --git a/src/cs/cs_usolve.c b/src/cs/cs_usolve.c
new file mode 100644
index 0000000..a94fa26
--- /dev/null
+++ b/src/cs/cs_usolve.c
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* solve Ux=b where x and b are dense.  x=b on input, solution on output. */
+CS_INT cs_usolve (const cs *U, CS_ENTRY *x)
+{
+    CS_INT p, j, n, *Up, *Ui ;
+    CS_ENTRY *Ux ;
+    if (!CS_CSC (U) || !x) return (0) ;                     /* check inputs */
+    n = U->n ; Up = U->p ; Ui = U->i ; Ux = U->x ;
+    for (j = n-1 ; j >= 0 ; j--)
+    {
+        x [j] /= Ux [Up [j+1]-1] ;
+        for (p = Up [j] ; p < Up [j+1]-1 ; p++)
+        {
+            x [Ui [p]] -= Ux [p] * x [j] ;
+        }
+    }
+    return (1) ;
+}
diff --git a/src/cs/cs_util.c b/src/cs/cs_util.c
new file mode 100644
index 0000000..8e10a94
--- /dev/null
+++ b/src/cs/cs_util.c
@@ -0,0 +1,139 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* allocate a sparse matrix (triplet form or compressed-column form) */
+cs *cs_spalloc (CS_INT m, CS_INT n, CS_INT nzmax, CS_INT values, CS_INT triplet)
+{
+    cs *A = cs_calloc (1, sizeof (cs)) ;    /* allocate the cs struct */
+    if (!A) return (NULL) ;                 /* out of memory */
+    A->m = m ;                              /* define dimensions and nzmax */
+    A->n = n ;
+    A->nzmax = nzmax = CS_MAX (nzmax, 1) ;
+    A->nz = triplet ? 0 : -1 ;              /* allocate triplet or comp.col */
+    A->p = cs_malloc (triplet ? nzmax : n+1, sizeof (CS_INT)) ;
+    A->i = cs_malloc (nzmax, sizeof (CS_INT)) ;
+    A->x = values ? cs_malloc (nzmax, sizeof (CS_ENTRY)) : NULL ;
+    return ((!A->p || !A->i || (values && !A->x)) ? cs_spfree (A) : A) ;
+}
+
+/* change the max # of entries sparse matrix */
+CS_INT cs_sprealloc (cs *A, CS_INT nzmax)
+{
+    CS_INT ok, oki, okj = 1, okx = 1 ;
+    if (!A) return (0) ;
+    if (nzmax <= 0) nzmax = (CS_CSC (A)) ? (A->p [A->n]) : A->nz ;
+    A->i = cs_realloc (A->i, nzmax, sizeof (CS_INT), &oki) ;
+    if (CS_TRIPLET (A)) A->p = cs_realloc (A->p, nzmax, sizeof (CS_INT), &okj) ;
+    if (A->x) A->x = cs_realloc (A->x, nzmax, sizeof (CS_ENTRY), &okx) ;
+    ok = (oki && okj && okx) ;
+    if (ok) A->nzmax = nzmax ;
+    return (ok) ;
+}
+
+/* free a sparse matrix */
+cs *cs_spfree (cs *A)
+{
+    if (!A) return (NULL) ;     /* do nothing if A already NULL */
+    cs_free (A->p) ;
+    cs_free (A->i) ;
+    cs_free (A->x) ;
+    return (cs_free (A)) ;      /* free the cs struct and return NULL */
+}
+
+/* free a numeric factorization */
+csn *cs_nfree (csn *N)
+{
+    if (!N) return (NULL) ;     /* do nothing if N already NULL */
+    cs_spfree (N->L) ;
+    cs_spfree (N->U) ;
+    cs_free (N->pinv) ;
+    cs_free (N->B) ;
+    return (cs_free (N)) ;      /* free the csn struct and return NULL */
+}
+
+/* free a symbolic factorization */
+css *cs_sfree (css *S)
+{
+    if (!S) return (NULL) ;     /* do nothing if S already NULL */
+    cs_free (S->pinv) ;
+    cs_free (S->q) ;
+    cs_free (S->parent) ;
+    cs_free (S->cp) ;
+    cs_free (S->leftmost) ;
+    return (cs_free (S)) ;      /* free the css struct and return NULL */
+}
+
+/* allocate a cs_dmperm or cs_scc result */
+csd *cs_dalloc (CS_INT m, CS_INT n)
+{
+    csd *D ;
+    D = cs_calloc (1, sizeof (csd)) ;
+    if (!D) return (NULL) ;
+    D->p = cs_malloc (m, sizeof (CS_INT)) ;
+    D->r = cs_malloc (m+6, sizeof (CS_INT)) ;
+    D->q = cs_malloc (n, sizeof (CS_INT)) ;
+    D->s = cs_malloc (n+6, sizeof (CS_INT)) ;
+    return ((!D->p || !D->r || !D->q || !D->s) ? cs_dfree (D) : D) ;
+}
+
+/* free a cs_dmperm or cs_scc result */
+csd *cs_dfree (csd *D)
+{
+    if (!D) return (NULL) ;     /* do nothing if D already NULL */
+    cs_free (D->p) ;
+    cs_free (D->q) ;
+    cs_free (D->r) ;
+    cs_free (D->s) ;
+    return (cs_free (D)) ;
+}
+
+/* free workspace and return a sparse matrix result */
+cs *cs_done (cs *C, void *w, void *x, CS_INT ok)
+{
+    cs_free (w) ;                       /* free workspace */
+    cs_free (x) ;
+    return (ok ? C : cs_spfree (C)) ;   /* return result if OK, else free it */
+}
+
+/* free workspace and return CS_INT array result */
+CS_INT *cs_idone (CS_INT *p, cs *C, void *w, CS_INT ok)
+{
+    cs_spfree (C) ;                     /* free temporary matrix */
+    cs_free (w) ;                       /* free workspace */
+    return (ok ? p : cs_free (p)) ;     /* return result if OK, else free it */
+}
+
+/* free workspace and return a numeric factorization (Cholesky, LU, or QR) */
+csn *cs_ndone (csn *N, cs *C, void *w, void *x, CS_INT ok)
+{
+    cs_spfree (C) ;                     /* free temporary matrix */
+    cs_free (w) ;                       /* free workspace */
+    cs_free (x) ;
+    return (ok ? N : cs_nfree (N)) ;    /* return result if OK, else free it */
+}
+
+/* free workspace and return a csd result */
+csd *cs_ddone (csd *D, cs *C, void *w, CS_INT ok)
+{
+    cs_spfree (C) ;                     /* free temporary matrix */
+    cs_free (w) ;                       /* free workspace */
+    return (ok ? D : cs_dfree (D)) ;    /* return result if OK, else free it */
+}
diff --git a/src/cs/cs_utsolve.c b/src/cs/cs_utsolve.c
new file mode 100644
index 0000000..c4522ab
--- /dev/null
+++ b/src/cs/cs_utsolve.c
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+#include "cs.h"
+/* solve U'x=b where x and b are dense.  x=b on input, solution on output. */
+CS_INT cs_utsolve (const cs *U, CS_ENTRY *x)
+{
+    CS_INT p, j, n, *Up, *Ui ;
+    CS_ENTRY *Ux ;
+    if (!CS_CSC (U) || !x) return (0) ;                     /* check inputs */
+    n = U->n ; Up = U->p ; Ui = U->i ; Ux = U->x ;
+    for (j = 0 ; j < n ; j++)
+    {
+        for (p = Up [j] ; p < Up [j+1]-1 ; p++)
+        {
+            x [j] -= CS_CONJ (Ux [p]) * x [Ui [p]] ;
+        }
+        x [j] /= CS_CONJ (Ux [Up [j+1]-1]) ;
+    }
+    return (1) ;
+}
diff --git a/src/decomposition.c b/src/decomposition.c
new file mode 100644
index 0000000..f5814aa
--- /dev/null
+++ b/src/decomposition.c
@@ -0,0 +1,444 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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_structural.h"
+#include "igraph_error.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+
+/**
+ * \function igraph_maximum_cardinality_search
+ * Maximum cardinality search
+ * 
+ * This function implements the maximum cardinality search algorithm
+ * discussed in 
+ * Robert E Tarjan and Mihalis Yannakakis: Simple linear-time
+ * algorithms to test chordality of graphs, test acyclicity of
+ * hypergraphs, and selectively reduce acyclic hypergraphs.
+ * SIAM Journal of Computation 13, 566--579, 1984.
+ * 
+ * \param graph The input graph. Can be directed, but the direction
+ *   of the edges is ignored.
+ * \param alpha Pointer to an initialized vector, the result is stored here. 
+ *   It will be resized, as needed. Upon return it contains
+ *   the rank of the each vertex.
+ * \param alpham1 Pointer to an initialized vector or a \c NULL
+ *   pointer. If not \c NULL, then the inverse of \p alpha is stored
+ *   here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in terms of the number of
+ * vertices and edges.  
+ * 
+ * \sa \ref igraph_is_chordal().
+ */
+
+int igraph_maximum_cardinality_search(const igraph_t *graph,
+				      igraph_vector_t *alpha,
+				      igraph_vector_t *alpham1) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_long_t size;
+  igraph_vector_long_t head, next, prev; /* doubly linked list with head */
+  long int i;
+  igraph_adjlist_t adjlist;
+  
+  /***************/
+  /* local j, v; */
+  /***************/
+  
+  long int j, v;
+
+  IGRAPH_CHECK(igraph_vector_long_init(&size, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &size);
+  IGRAPH_CHECK(igraph_vector_long_init(&head, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &head);
+  IGRAPH_CHECK(igraph_vector_long_init(&next, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &next);
+  IGRAPH_CHECK(igraph_vector_long_init(&prev, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &prev);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  
+  IGRAPH_CHECK(igraph_vector_resize(alpha, no_of_nodes));
+  if (alpham1) {
+    IGRAPH_CHECK(igraph_vector_resize(alpham1, no_of_nodes));
+  }
+  
+  /***********************************************/
+  /* for i in [0,n-1] -> set(i) := emptyset rof; */
+  /***********************************************/
+
+  /* nothing to do, 'head' contains all zeros */
+
+  /*********************************************************/
+  /* for v in vertices -> size(v):=0; add v to set(0) rof; */
+  /*********************************************************/
+
+  VECTOR(head)[0]=1;
+  for (v=0; v<no_of_nodes; v++) {
+    VECTOR(next)[v]=v+2;
+    VECTOR(prev)[v]=v;
+  }
+  VECTOR(next)[no_of_nodes-1] = 0;
+  /* size is already all zero */
+
+  /***************/
+  /* i:=n; j:=0; */
+  /***************/
+
+  i=no_of_nodes; j=0;
+  
+  /**************/
+  /* do i>=1 -> */
+  /**************/
+
+  while (i>=1) {
+    long int x, k, len;
+    igraph_vector_int_t *neis;
+
+    /********************************/
+    /* v :=  delete any from set(j) */
+    /********************************/
+
+    v=VECTOR(head)[j]-1;
+    x=VECTOR(next)[v];
+    VECTOR(head)[j]=x;
+    if (x != 0) {
+      VECTOR(prev)[x-1]=0;
+    }
+    
+    /*************************************************/
+    /* alpha(v) := i; alpham1(i) := v; size(v) := -1 */
+    /*************************************************/
+
+    VECTOR(*alpha)[v]=i-1; 
+    if (alpham1) { 
+      VECTOR(*alpham1)[i-1]=v;
+    }
+    VECTOR(size)[v]=-1;
+    
+    /********************************************/
+    /* for {v,w} in E such that size(w) >= 0 -> */
+    /********************************************/
+    
+    neis=igraph_adjlist_get(&adjlist, v);
+    len=igraph_vector_int_size(neis);
+    for (k=0; k<len; k++) {
+      long int w=(long int) VECTOR(*neis)[k];
+      long int ws=VECTOR(size)[w];
+      if (ws >= 0) {
+
+	/******************************/
+	/* delete w from set(size(w)) */
+	/******************************/
+	
+	long int nw=VECTOR(next)[w];
+	long int pw=VECTOR(prev)[w];
+	if (nw != 0) {
+	  VECTOR(prev)[nw-1] = pw;
+	}
+	if (pw != 0) {
+	  VECTOR(next)[pw-1] = nw;
+	} else {
+	  VECTOR(head)[ws]=nw;
+	}
+
+	/******************************/
+	/* size(w) := size(w)+1       */
+	/******************************/
+
+	VECTOR(size)[w] += 1;
+
+	/******************************/
+	/* add w to set(size(w))      */
+	/******************************/
+
+	ws=VECTOR(size)[w];
+	nw=VECTOR(head)[ws];
+	VECTOR(next)[w]=nw;
+	VECTOR(prev)[w]=0;
+	if (nw != 0) {
+	  VECTOR(prev)[nw-1]=w+1;
+	}
+	VECTOR(head)[ws]=w+1;
+
+      }
+    }
+    
+    /***********************/
+    /* i := i-1; j := j+1; */
+    /***********************/
+    
+    i -= 1;
+    j += 1;
+    
+    /*********************************************/
+    /* do j>=0 and set(j)=emptyset -> j:=j-1; od */ 
+    /*********************************************/
+    
+    while (j>=0 && VECTOR(head)[j]==0) j--;
+    
+  }
+  
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_long_destroy(&prev);
+  igraph_vector_long_destroy(&next);
+  igraph_vector_long_destroy(&head);
+  igraph_vector_long_destroy(&size);
+  IGRAPH_FINALLY_CLEAN(5);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_is_chordal
+ * Decides whether a graph is chordal
+ * 
+ * A graph is chordal 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.
+ *
+ * If either \p alpha or \p alpha1 is given, then the other is
+ * calculated by taking simply the inverse. If neither are given,
+ * then \ref igraph_maximum_cardinality_search() is called to calculate
+ * them.
+ * \param graph The input graph, it might be directed, but edge
+ *    direction is ignored.
+ * \param alpha Either an alpha vector coming from
+ *    \ref igraph_maximum_cardinality_search() (on the same graph), or a
+ *    null pointer. 
+ * \param alpham1 Either an inverse alpha vector coming from \ref
+ *    igraph_maximum_cardinality_search() (on the same graph) or a null
+ *    pointer.
+ * \param chordal Pointer to a boolean, the result is stored here.
+ * \param fill_in Pointer to an initialized vector, or a null
+ *    pointer. If not a null pointer, then the fill-in of the graph is
+ *    stored here. The fill-in is the set of edges that are needed to
+ *    make the graph chordal. The vector is resized as needed.
+ * \param newgraph Pointer to an uninitialized graph, or a null
+ *   pointer. If not a null pointer, then a new triangulated graph is
+ *   created here. This essentially means adding the fill-in edges to 
+ *   the original graph.
+ * \return Error code.
+ * 
+ * Time complexity: O(n).
+ * 
+ * \sa \ref igraph_maximum_cardinality_search().
+ */
+
+int igraph_is_chordal(const igraph_t *graph,
+		      const igraph_vector_t *alpha,
+		      const igraph_vector_t *alpham1,
+		      igraph_bool_t *chordal,
+		      igraph_vector_t *fill_in,
+		      igraph_t *newgraph) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  const igraph_vector_t *my_alpha=alpha, *my_alpham1=alpham1;
+  igraph_vector_t v_alpha, v_alpham1;
+  igraph_vector_long_t f, index;
+  long int i;
+  igraph_adjlist_t adjlist;
+  igraph_vector_long_t mark;
+  igraph_bool_t calc_edges= fill_in || newgraph;
+  igraph_vector_t *my_fill_in=fill_in, v_fill_in;
+
+  /*****************/
+  /* local v, w, x */
+  /*****************/
+
+  long int v, w, x;
+
+  if (!chordal && !calc_edges) {
+    /* Nothing to calculate */
+    return 0;
+  }
+  
+  if (!alpha && !alpham1) {
+    IGRAPH_VECTOR_INIT_FINALLY(&v_alpha, no_of_nodes);
+    my_alpha=&v_alpha;
+    IGRAPH_VECTOR_INIT_FINALLY(&v_alpham1, no_of_nodes);
+    my_alpham1=&v_alpham1;
+    IGRAPH_CHECK(igraph_maximum_cardinality_search(graph, 
+					    (igraph_vector_t*) my_alpha, 
+					    (igraph_vector_t*) my_alpham1));
+  } else if (alpha && !alpham1) {
+    long int v;
+    IGRAPH_VECTOR_INIT_FINALLY(&v_alpham1, no_of_nodes);
+    my_alpham1=&v_alpham1;
+    for (v=0; v<no_of_nodes; v++) {
+      long int i=(long int) VECTOR(*my_alpha)[v];
+      VECTOR(*my_alpham1)[i]=v;
+    }
+  } else if (!alpha && alpham1) { 
+    long int i;
+    IGRAPH_VECTOR_INIT_FINALLY(&v_alpha, no_of_nodes);
+    my_alpha=&v_alpha;
+    for (i=0; i<no_of_nodes; i++) {
+      long int v=(long int) VECTOR(*my_alpham1)[i];
+      VECTOR(*my_alpha)[v]=i;
+    }
+  }
+
+  if (!fill_in && newgraph) {
+    IGRAPH_VECTOR_INIT_FINALLY(&v_fill_in, 0);
+    my_fill_in=&v_fill_in;
+  }
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&f, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &f);
+  IGRAPH_CHECK(igraph_vector_long_init(&index, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &index);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  IGRAPH_CHECK(igraph_vector_long_init(&mark, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &mark);
+  if (my_fill_in) { igraph_vector_clear(my_fill_in); }
+
+  if (chordal) { *chordal=1; }
+
+  /*********************/
+  /* for i in [1,n] -> */
+  /*********************/
+
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_vector_int_t *neis;
+    long int j, len;
+    
+    /**********************************************/
+    /* w := alpham1(i); f(w) := w; index(w) := i; */
+    /**********************************************/
+    
+    w=(long int) VECTOR(*my_alpham1)[i]; 
+    VECTOR(f)[w]=w;
+    VECTOR(index)[w]=i;
+   
+    /******************************************/
+    /* for {v,w} in E such that alpha(v)<i -> */
+    /******************************************/
+
+    neis=igraph_adjlist_get(&adjlist, w);
+    len=igraph_vector_int_size(neis);
+    for (j=0; j<len; j++) {
+      v=(long int) VECTOR(*neis)[j];
+      VECTOR(mark)[v] = w+1;
+    }
+    
+    for (j=0; j<len; j++) {
+      v=(long int) VECTOR(*neis)[j];
+      if (VECTOR(*my_alpha)[v] >= i) { continue; }
+      
+      /**********/
+      /* x := v */
+      /**********/
+
+      x=v;
+      
+      /********************/
+      /* do index(x)<i -> */
+      /********************/
+      
+      while (VECTOR(index)[x] < i) {
+	
+	/******************/
+	/* index(x) := i; */
+	/******************/
+	
+	VECTOR(index)[x] = i;
+	
+	/**********************************/
+	/* add {x,w} to E union F(alpha); */
+	/**********************************/
+
+	if (VECTOR(mark)[x] != w+1) {
+
+	  if (chordal) {
+	    *chordal=0;
+	  }
+	  
+	  if (my_fill_in) {
+	    IGRAPH_CHECK(igraph_vector_push_back(my_fill_in, x));
+	    IGRAPH_CHECK(igraph_vector_push_back(my_fill_in, w));
+	  }
+	  
+	  if (!calc_edges) { 
+	    /* make sure that we exit from all loops */
+	    i=no_of_nodes;
+	    j=len; 
+	    break; 
+	  }
+	}
+	
+	/*************/
+	/* x := f(x) */
+	/*************/
+	
+	x=VECTOR(f)[x];
+	
+      }	/* while (VECTOR(index)[x] < i) */
+      
+      /*****************************/
+      /* if (f(x)=x -> f(x):=w; fi */
+      /*****************************/
+      
+      if (VECTOR(f)[x] == x) { 
+	VECTOR(f)[x] = w;
+      }
+    }
+  }
+
+  igraph_vector_long_destroy(&mark);
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_long_destroy(&index);
+  igraph_vector_long_destroy(&f);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  if (newgraph) {
+    IGRAPH_CHECK(igraph_copy(newgraph, graph));
+    IGRAPH_FINALLY(igraph_destroy, newgraph);
+    IGRAPH_CHECK(igraph_add_edges(newgraph, my_fill_in, 0));
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (!fill_in && newgraph) {
+    igraph_vector_destroy(&v_fill_in);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (!alpha && !alpham1) {
+    igraph_vector_destroy(&v_alpham1);
+    igraph_vector_destroy(&v_alpha);
+    IGRAPH_FINALLY_CLEAN(2);
+  } else if (alpha && !alpham1) {
+    igraph_vector_destroy(&v_alpham1);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (!alpha && alpham1) { 
+    igraph_vector_destroy(&v_alpha);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
diff --git a/src/distances.c b/src/distances.c
new file mode 100644
index 0000000..758f189
--- /dev/null
+++ b/src/distances.c
@@ -0,0 +1,211 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   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
+
+*/
+
+#include "igraph_datatype.h"
+#include "igraph_dqueue.h"
+#include "igraph_iterators.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_vector.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+
+int igraph_i_eccentricity(const igraph_t *graph,
+			  igraph_vector_t *res,
+			  igraph_vs_t vids,
+			  igraph_neimode_t mode,
+			  const igraph_adjlist_t *adjlist) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_long_t q;
+  igraph_vit_t vit;
+  igraph_vector_int_t counted;
+  int i, mark=1;
+  igraph_vector_t vneis;
+  igraph_vector_int_t *neis;
+
+  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&counted, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &counted);
+
+  if (!adjlist) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vneis, 0);
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
+  igraph_vector_fill(res, -1);
+
+  for (i=0, IGRAPH_VIT_RESET(vit); 
+       !IGRAPH_VIT_END(vit); 
+       IGRAPH_VIT_NEXT(vit), mark++, i++) {
+
+    long int source;
+    source=IGRAPH_VIT_GET(vit);
+    IGRAPH_CHECK(igraph_dqueue_long_push(&q, source));
+    IGRAPH_CHECK(igraph_dqueue_long_push(&q, 0));
+    VECTOR(counted)[source]=mark;
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    while (!igraph_dqueue_long_empty(&q)) {
+      long int act=igraph_dqueue_long_pop(&q);
+      long int dist=igraph_dqueue_long_pop(&q);
+      int j, n;
+
+      if (dist > VECTOR(*res)[i]) {
+	VECTOR(*res)[i]=dist;
+      }
+
+      if (adjlist) {
+	neis=igraph_adjlist_get(adjlist, act);
+	n=(int) igraph_vector_int_size(neis);
+	for (j=0; j<n; j++) {
+	  int nei=(int) VECTOR(*neis)[j];
+	  if (VECTOR(counted)[nei] != mark) {
+	    VECTOR(counted)[nei]=mark;
+	    IGRAPH_CHECK(igraph_dqueue_long_push(&q, nei));
+	    IGRAPH_CHECK(igraph_dqueue_long_push(&q, dist+1));
+	  }
+	}  
+      } else {
+	IGRAPH_CHECK(igraph_neighbors(graph, &vneis,
+				      (igraph_integer_t) act, mode));
+	n=(int) igraph_vector_size(&vneis);
+	for (j=0; j<n; j++) {
+	  int nei=(int) VECTOR(vneis)[j];
+	  if (VECTOR(counted)[nei] != mark) {
+	    VECTOR(counted)[nei]=mark;
+	    IGRAPH_CHECK(igraph_dqueue_long_push(&q, nei));
+	    IGRAPH_CHECK(igraph_dqueue_long_push(&q, dist+1));
+	  }
+	}  
+      }
+    } /* while !igraph_dqueue_long_empty(dqueue) */
+
+  } /* for IGRAPH_VIT_NEXT(vit) */
+
+  if (!adjlist) {
+    igraph_vector_destroy(&vneis);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_vector_int_destroy(&counted);
+  igraph_vit_destroy(&vit);
+  igraph_dqueue_long_destroy(&q);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_eccentricity
+ * Eccentricity of some vertices
+ * 
+ * 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.
+ * 
+ * </para><para>
+ * This implementation ignores vertex pairs that are in different
+ * components. Isolated vertices have eccentricity zero.
+ * 
+ * \param graph The input graph, it can be directed or undirected.
+ * \param res Pointer to an initialized vector, the result is stored
+ *    here.
+ * \param vids The vertices for which the eccentricity is calculated.
+ * \param mode What kind of paths to consider for the calculation:
+ *    \c IGRAPH_OUT, paths that follow edge directions;
+ *    \c IGRAPH_IN, paths that follow the opposite directions; and
+ *    \c IGRAPH_ALL, paths that ignore edge directions. This argument
+ *    is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(v*(|V|+|E|)), where |V| is the number of
+ * vertices, |E| is the number of edges and v is the number of
+ * vertices for which eccentricity is calculated.
+ * 
+ * \sa \ref igraph_radius().
+ * 
+ * \example examples/simple/igraph_eccentricity.c
+ */
+
+int igraph_eccentricity(const igraph_t *graph, 
+			igraph_vector_t *res,
+			igraph_vs_t vids,
+			igraph_neimode_t mode) {
+
+  return igraph_i_eccentricity(graph, res, vids, mode, /*adjlist=*/ 0);
+}
+
+/**
+ * \function igraph_radius
+ * Radius of a graph
+ * 
+ * The radius of a graph is the defined as the minimum eccentricity of 
+ * its vertices, see \ref igraph_eccentricity().
+ * 
+ * \param graph The input graph, it can be directed or undirected.
+ * \param radius Pointer to a real variable, the result is stored
+ *   here.
+ * \param mode What kind of paths to consider for the calculation:
+ *    \c IGRAPH_OUT, paths that follow edge directions;
+ *    \c IGRAPH_IN, paths that follow the opposite directions; and
+ *    \c IGRAPH_ALL, paths that ignore edge directions. This argument
+ *    is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|(|V|+|E|)), where |V| is the number of
+ * vertices and |E| is the number of edges.
+ * 
+ * \sa \ref igraph_eccentricity().
+ * 
+ * \example examples/simple/igraph_radius.c
+ */
+
+int igraph_radius(const igraph_t *graph, igraph_real_t *radius, 
+		  igraph_neimode_t mode) {
+
+  int no_of_nodes=igraph_vcount(graph);
+
+  if (no_of_nodes==0) {
+    *radius = IGRAPH_NAN;
+  } else {
+    igraph_adjlist_t adjlist;
+    igraph_vector_t ecc;
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, mode));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+    IGRAPH_VECTOR_INIT_FINALLY(&ecc, igraph_vcount(graph));
+    IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc, igraph_vss_all(), 
+				       mode, &adjlist));
+    *radius = igraph_vector_min(&ecc);
+    igraph_vector_destroy(&ecc);
+    igraph_adjlist_destroy(&adjlist);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  
+  return 0;
+}
diff --git a/src/dqueue.c b/src/dqueue.c
new file mode 100644
index 0000000..45a2d62
--- /dev/null
+++ b/src/dqueue.c
@@ -0,0 +1,49 @@
+/* -*- 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_types.h"
+#include "igraph_dqueue.h"
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "dqueue.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "dqueue.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "dqueue.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "dqueue.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
diff --git a/src/dqueue.pmt b/src/dqueue.pmt
new file mode 100644
index 0000000..3835863
--- /dev/null
+++ b/src/dqueue.pmt
@@ -0,0 +1,382 @@
+/* -*- 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
+
+*/
+
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+/** 
+ * \section igraph_dqueue
+ * <para>
+ * This is the classic data type of the double ended queue. Most of
+ * the time it is used if a First-In-First-Out (FIFO) behavior is
+ * needed. See the operations below.
+ * </para>
+ * 
+ * <para>
+ * \example examples/simple/dqueue.c
+ * </para>
+ */
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_init
+ * \brief Initialize a double ended queue (deque).
+ * 
+ * The queue will be always empty.
+ * \param q Pointer to an uninitialized deque.
+ * \param size How many elements to allocate memory for. 
+ * \return Error code.
+ * 
+ * Time complexity: O(\p size).
+ */
+
+int FUNCTION(igraph_dqueue,init) (TYPE(igraph_dqueue)* q, long int size) {
+        assert(q != 0);
+	if (size <= 0 ) { size=1; }
+	q->stor_begin=igraph_Calloc(size, BASE);
+	if (q->stor_begin==0) {
+	  IGRAPH_ERROR("dqueue init failed", IGRAPH_ENOMEM);
+	}
+	q->stor_end=q->stor_begin + size;
+	q->begin=q->stor_begin;
+	q->end=NULL;
+	
+	return 0;
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_destroy
+ * \brief Destroy a double ended queue.
+ * 
+ * \param q The queue to destroy
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_dqueue,destroy) (TYPE(igraph_dqueue)* q) {
+  assert(q != 0);
+  if (q->stor_begin != 0) {
+    igraph_Free(q->stor_begin);
+    q->stor_begin=0;
+  }
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_empty
+ * \brief Decide whether the queue is empty.
+ * 
+ * \param q The queue.
+ * \return Boolean, \c TRUE if \p q contains at least one element, \c
+ * FALSE otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t FUNCTION(igraph_dqueue,empty) (const TYPE(igraph_dqueue)* q) {
+  assert(q != 0);
+  assert(q->stor_begin != 0);
+  return q->end == NULL;
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_clear
+ * \brief Remove all elements from the queue.
+ * 
+ * \param q The queue
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_dqueue,clear)   (TYPE(igraph_dqueue)* q) {
+  assert(q != 0);
+  assert(q->stor_begin != 0);
+  q->begin=q->stor_begin;
+  q->end=NULL;
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_full
+ * \brief Check whether the queue is full.
+ *
+ * If a queue is full the next igraph_dqueue_push() operation will allocate
+ * more memory.
+ * \param q The queue.
+ * \return \c TRUE if \p q is full, \c FALSE otherwise.
+ * 
+ * Time complecity: O(1).
+ */
+
+igraph_bool_t FUNCTION(igraph_dqueue,full) (TYPE(igraph_dqueue)* q) {
+  assert(q != 0);
+  assert(q->stor_begin != 0);
+  return q->begin == q->end;
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_size
+ * \brief Number of elements in the queue.
+ * 
+ * \param q The queue.
+ * \return Integer, the number of elements currently in the queue.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_dqueue,size) (const TYPE(igraph_dqueue)* q) {
+        assert(q != 0);
+        assert(q->stor_begin != 0);
+	if (q->end==NULL) {
+		return 0;
+	} else if (q->begin < q->end) {
+		return q->end - q->begin;
+	} else {
+		return q->stor_end - q->begin + q->end - q->stor_begin;
+	}
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_head
+ * \brief Head of the queue.
+ * 
+ * The queue must contain at least one element.
+ * \param q The queue.
+ * \return The first element in the queue.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_dqueue,head) (const TYPE(igraph_dqueue)* q) {
+        assert(q != 0);
+	assert(q->stor_begin != 0);
+	return *(q->begin);
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_back
+ * \brief Tail of the queue.
+ * 
+ * The queue must contain at least one element.
+ * \param q The queue.
+ * \return The last element in the queue.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_dqueue,back) (const TYPE(igraph_dqueue)* q) {
+        assert(q != 0);
+	assert(q->stor_begin != 0);
+	if (q->end == q->stor_begin)
+		return *(q->stor_end-1);
+	return *(q->end-1);
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_pop
+ * \brief Remove the head.
+ * 
+ * Removes and returns the first element in the queue. The queue must
+ * be non-empty.
+ * \param q The input queue.
+ * \return The first element in the queue.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_dqueue,pop) (TYPE(igraph_dqueue)* q) {
+	BASE tmp=*(q->begin);
+        assert(q != 0);
+	assert(q->stor_begin != 0);
+	(q->begin)++;
+	if (q->begin==q->stor_end) {
+		q->begin=q->stor_begin;
+	}
+	if (q->begin==q->end) {
+		q->end=NULL;
+	}
+
+	return tmp;
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_pop_back
+ * \brief Remove the tail
+ *
+ * Removes and returns the last element in the queue. The queue must
+ * be non-empty.
+ * \param q The queue.
+ * \return The last element in the queue.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_dqueue,pop_back) (TYPE(igraph_dqueue)* q) {
+	BASE tmp;
+        assert(q != 0);
+	assert(q->stor_begin != 0);
+	if (q->end != q->stor_begin) {
+		tmp=*((q->end)-1);
+		q->end = (q->end)-1;
+	} else {
+		tmp=*((q->stor_end)-1);
+		q->end = (q->stor_end)-1;
+	}
+	if (q->begin==q->end) {
+		q->end=NULL;
+	}
+	
+	return tmp;
+}
+
+/**
+ * \ingroup dqueue
+ * \function igraph_dqueue_push
+ * \brief Appends an element.
+ *
+ * Append an element to the end of the queue.
+ * \param q The queue.
+ * \param elem The element to append.
+ * \return Error code.
+ *
+ * Time complexity: O(1) if no memory allocation is needed, O(n), the
+ * number of elements in the queue otherwise. But not that by
+ * allocating always twice as much memory as the current size of the
+ * queue we ensure that n push operations can always be done in at
+ * most O(n) time. (Assuming memory allocation is at most linear.)
+ */
+
+int FUNCTION(igraph_dqueue,push) (TYPE(igraph_dqueue)* q, BASE elem) {
+        assert(q != 0);
+	assert(q->stor_begin != 0);
+	if (q->begin != q->end) {
+		/* not full */
+		if (q->end==NULL) {
+			q->end=q->begin;
+		}			
+		*(q->end) = elem;
+		(q->end)++;
+		if (q->end==q->stor_end) {
+			q->end=q->stor_begin;
+		}
+	} else {
+		/* full, allocate more storage */
+		
+		BASE *bigger=NULL, *old=q->stor_begin;
+
+		bigger=igraph_Calloc( 2*(q->stor_end - q->stor_begin)+1, BASE );
+		if (bigger==0) {
+		  IGRAPH_ERROR("dqueue push failed", IGRAPH_ENOMEM);
+		}
+
+		if (q->stor_end - q->begin) {
+			memcpy(bigger, q->begin, 
+			       (size_t)(q->stor_end - q->begin) * sizeof(BASE));
+		}
+		if (q->end - q->stor_begin > 0) {
+			memcpy(bigger + (q->stor_end - q->begin), q->stor_begin,
+			       (size_t)(q->end - q->stor_begin) * sizeof(BASE));
+		}
+		
+		q->end       =bigger + (q->stor_end - q->stor_begin);
+		q->stor_end  =bigger + 2*(q->stor_end - q->stor_begin) + 1;
+		q->stor_begin=bigger;
+		q->begin     =bigger;
+				
+		*(q->end) = elem;
+		(q->end)++;
+		if (q->end==q->stor_end) {
+			q->end=q->stor_begin;
+		}
+
+		igraph_Free(old);
+	}
+	
+	return 0;
+}
+
+#if defined (OUT_FORMAT)
+
+#ifndef USING_R
+int FUNCTION(igraph_dqueue,print)(const TYPE(igraph_dqueue)* q) {
+  return FUNCTION(igraph_dqueue,fprint)(q, stdout);
+}
+#endif
+
+int FUNCTION(igraph_dqueue,fprint)(const TYPE(igraph_dqueue)* q, FILE *file) {
+  if (q->end != NULL) {
+    /* There is one element at least */
+    BASE *p=q->begin;
+    fprintf(file, OUT_FORMAT, *p);
+    p++;
+    if (q->end > q->begin) {
+      /* Q is in one piece */
+      while (p != q->end) {
+	fprintf(file, " " OUT_FORMAT, *p);
+	p++;
+      }
+    } else {
+      /* Q is in two pieces */
+      while (p != q->stor_end) {
+	fprintf(file, " " OUT_FORMAT, *p);
+	p++;
+      }
+      p=q->stor_begin;
+      while (p != q->end) {
+	fprintf(file, " " OUT_FORMAT, *p);
+	p++;
+      }
+    }
+  }
+
+  fprintf(file, "\n");
+
+  return 0;
+}
+
+#endif
+
+BASE FUNCTION(igraph_dqueue,e)(const TYPE(igraph_dqueue) *q, long int idx) {
+  if ((q->begin + idx < q->end) ||
+      (q->begin >= q->end && q->begin+idx < q->stor_end)) {
+    return q->begin[idx];
+  } else if (q->begin >= q->end && q->stor_begin+idx < q->end) {
+    idx = idx-(q->stor_end - q->begin);
+    return q->stor_begin[idx];
+  } else {
+    return 0;			/* Error */
+  }
+}
diff --git a/src/drl_Node.h b/src/drl_Node.h
new file mode 100644
index 0000000..df482d6
--- /dev/null
+++ b/src/drl_Node.h
@@ -0,0 +1,66 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __NODE_H__
+#define __NODE_H__
+
+// The node class contains information about a given node for
+// use by the density server process.
+
+// structure coord used to pass position information between
+// density server and graph class
+
+namespace drl {
+
+class Node {
+
+ public:
+  
+  bool fixed;	// if true do not change the
+				// position of this node
+  int id;
+  
+  float x,y;
+  float sub_x,sub_y;
+  float energy;
+
+ public:
+  
+  Node( int node_id ) { x = y = 0.0; fixed = false; 
+						id = node_id; }
+  ~Node() { }
+  
+};
+
+} // namespace drl
+
+#endif //__NODE_H__
diff --git a/src/drl_Node_3d.h b/src/drl_Node_3d.h
new file mode 100644
index 0000000..8536d9e
--- /dev/null
+++ b/src/drl_Node_3d.h
@@ -0,0 +1,66 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __NODE_H__
+#define __NODE_H__
+
+// The node class contains information about a given node for
+// use by the density server process.
+
+// structure coord used to pass position information between
+// density server and graph class
+
+namespace drl3d {
+
+class Node {
+
+ public:
+  
+  bool fixed;	// if true do not change the
+				// position of this node
+  int id;
+  
+  float x,y,z;
+  float sub_x,sub_y,sub_z;
+  float energy;
+
+ public:
+  
+  Node( int node_id ) { x = y = z = 0.0; fixed = false; 
+						id = node_id; }
+  ~Node() { }
+  
+};
+
+} // namespace drl3d
+
+#endif //__NODE_H__
diff --git a/src/drl_graph.cpp b/src/drl_graph.cpp
new file mode 100644
index 0000000..5e53c00
--- /dev/null
+++ b/src/drl_graph.cpp
@@ -0,0 +1,1286 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains the member definitions of the master class
+
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <vector>
+#include <cstdlib>
+#include <cmath>
+#include <cstring>
+
+using namespace std;
+
+#include "drl_graph.h"
+#include "igraph_random.h"
+#include "igraph_interface.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+namespace drl {
+
+// constructor -- initializes the schedule variables (as in 
+// graph constructor)
+
+// graph::graph ( int proc_id, int tot_procs, char *int_file )
+// {
+		  
+// 		  // MPI parameters
+// 		  myid = proc_id;
+// 		  num_procs = tot_procs;
+
+// 		  // initial annealing parameters
+// 		  STAGE = 0;
+// 		  iterations = 0;
+// 		  temperature = 2000;
+// 		  attraction = 10;
+// 		  damping_mult = 1.0;
+// 		  min_edges = 20;
+// 		  first_add = fine_first_add = true;
+// 		  fineDensity = false;
+
+// 		  // Brian's original Vx schedule
+// 		  liquid.iterations = 200;
+// 		  liquid.temperature = 2000;
+// 		  liquid.attraction = 2;
+// 		  liquid.damping_mult = 1.0;
+// 		  liquid.time_elapsed = 0;
+
+// 		  expansion.iterations = 200;
+// 		  expansion.temperature = 2000;
+// 		  expansion.attraction = 10;
+// 		  expansion.damping_mult = 1.0;
+// 		  expansion.time_elapsed = 0;
+
+// 		  cooldown.iterations = 200;
+// 		  cooldown.temperature = 2000;
+// 		  cooldown.attraction = 1;
+// 		  cooldown.damping_mult = .1;
+// 		  cooldown.time_elapsed = 0;
+
+// 		  crunch.iterations = 50;
+// 		  crunch.temperature = 250;
+// 		  crunch.attraction = 1;
+// 		  crunch. damping_mult = .25;
+// 		  crunch.time_elapsed = 0;
+
+// 		  simmer.iterations = 100;
+// 		  simmer.temperature = 250;
+// 		  simmer.attraction = .5;
+// 		  simmer.damping_mult = 0.0;
+// 		  simmer.time_elapsed = 0;
+
+// 		  // scan .int file for node info
+// 		  scan_int ( int_file );
+		  
+// 		  // populate node positions and ids
+// 		  positions.reserve ( num_nodes );
+// 		  map < int, int >::iterator cat_iter;
+// 		  for ( cat_iter = id_catalog.begin();
+// 			    cat_iter != id_catalog.end();
+// 				cat_iter++ )
+// 			positions.push_back ( Node( cat_iter->first ) );
+		  
+// 		  /*
+// 		  // output positions .ids for debugging
+// 		  for ( int id = 0; id < num_nodes; id++ )
+// 			cout << positions[id].id << endl;
+// 		  */
+		  
+// 		  // read .int file for graph info
+// 		  read_int ( int_file );
+		  
+// 		  // initialize density server
+// 		  density_server.Init();
+		  
+// }
+
+graph::graph(const igraph_t *igraph, 
+	     const igraph_layout_drl_options_t *options,
+	     const igraph_vector_t *weights) {
+  myid = 0;
+  num_procs = 1;
+  
+  STAGE = 0;
+  iterations = options->init_iterations;
+  temperature = options->init_temperature;
+  attraction = options->init_attraction;
+  damping_mult = options->init_damping_mult;
+  min_edges = 20;
+  first_add = fine_first_add = true;
+  fineDensity = false;
+  
+  // Brian's original Vx schedule
+  liquid.iterations = options->liquid_iterations;
+  liquid.temperature = options->liquid_temperature;
+  liquid.attraction = options->liquid_attraction;
+  liquid.damping_mult = options->liquid_damping_mult;
+  liquid.time_elapsed = 0;
+  
+  expansion.iterations = options->expansion_iterations;
+  expansion.temperature = options->expansion_temperature;
+  expansion.attraction = options->expansion_attraction;
+  expansion.damping_mult = options->expansion_damping_mult;
+  expansion.time_elapsed = 0;
+  
+  cooldown.iterations = options->cooldown_iterations;
+  cooldown.temperature = options->cooldown_temperature;
+  cooldown.attraction = options->cooldown_attraction;
+  cooldown.damping_mult = options->cooldown_damping_mult;
+  cooldown.time_elapsed = 0;
+  
+  crunch.iterations = options->crunch_iterations;
+  crunch.temperature = options->crunch_temperature;
+  crunch.attraction = options->crunch_attraction;
+  crunch.damping_mult = options->crunch_damping_mult;
+  crunch.time_elapsed = 0;
+  
+  simmer.iterations = options->simmer_iterations;
+  simmer.temperature = options->simmer_temperature;
+  simmer.attraction = options->simmer_attraction;
+  simmer.damping_mult = options->simmer_damping_mult;
+  simmer.time_elapsed = 0;
+  
+  // scan .int file for node info
+  highest_sim = 1.0;
+  num_nodes=igraph_vcount(igraph);
+  long int no_of_edges=igraph_ecount(igraph);
+  for (long int i=0; i<num_nodes; i++) {
+    id_catalog[i] = 1;
+  }
+  map< int, int>::iterator cat_iter;
+  for ( cat_iter = id_catalog.begin();
+	cat_iter != id_catalog.end(); cat_iter++) {
+    cat_iter->second = cat_iter->first;
+  }
+  
+  // populate node positions and ids  
+  positions.reserve ( num_nodes );
+  for ( cat_iter = id_catalog.begin();
+	cat_iter != id_catalog.end();
+	cat_iter++ ) {
+    positions.push_back ( Node( cat_iter->first ) );
+  }
+  
+  // read .int file for graph info
+  long int node_1, node_2;
+  double weight;
+  for (long int i=0; i<no_of_edges; i++) {
+    node_1=IGRAPH_FROM(igraph, i);
+    node_2=IGRAPH_TO(igraph,i);
+    weight = weights ? VECTOR(*weights)[i] : 1.0 ;
+    (neighbors[id_catalog[node_1]])[id_catalog[node_2]] = weight;    
+    (neighbors[id_catalog[node_2]])[id_catalog[node_1]] = weight;  
+  }
+  
+  // initialize density server
+  density_server.Init();
+    
+}
+
+// The following subroutine scans the .int file for the following
+// information: number nodes, node ids, and highest similarity.  The
+// corresponding graph globals are populated: num_nodes, id_catalog,
+// and highest_sim.
+
+// void graph::scan_int ( char *filename )
+// {
+
+//   cout << "Proc. " << myid << " scanning .int file ..." << endl;
+  
+//   // Open (sim) File
+//   ifstream fp ( filename );
+//   if ( !fp )
+//   {
+// 	cout << "Error: could not open " << filename << ".  Program terminated." << endl;
+// 	#ifdef MUSE_MPI
+// 	  MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 	#else
+// 	  exit (1);
+//     #endif
+//   }	
+  
+//   // Read file, parse, and add into data structure
+//   int id1, id2;
+//   float edge_weight;
+//   highest_sim = -1.0;
+//   while ( !fp.eof () )
+// 	{
+// 	  fp >> id1 >> id2 >> edge_weight;
+	  
+// 	  // ignore negative weights!
+// 	  if ( edge_weight <= 0 )
+// 	  {
+// 	     cout << "Error: found negative edge weight in " << filename << ".  Program stopped." << endl;
+// 		 #ifdef MUSE_MPI
+// 	       MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 	     #else
+// 	       exit (1);
+//          #endif
+// 	   }
+
+// 	   if ( highest_sim < edge_weight )
+// 	      highest_sim = edge_weight;
+	
+// 	   id_catalog[id1] = 1;
+// 	   id_catalog[id2] = 1;
+// 	}
+
+//   fp.close();
+
+//   if ( id_catalog.size() == 0 )
+//   {
+//     cout << "Error: Proc. " << myid << ": " << filename << " is empty.  Program terminated." << endl;
+// 	#ifdef MUSE_MPI
+// 	  MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 	#else
+// 	  exit (1);
+// 	#endif
+//   }
+  
+//   // label nodes with sequential integers starting at 0
+//   map< int, int>::iterator cat_iter;
+//   int id_label;
+//   for ( cat_iter = id_catalog.begin(), id_label = 0;
+// 	    cat_iter != id_catalog.end(); cat_iter++, id_label++ )
+//     cat_iter->second = id_label;
+
+//   /*
+//   // output id_catalog for debugging:
+//   for ( cat_iter = id_catalog.begin();
+// 		cat_iter != id_catalog.end();
+// 		cat_iter++ )
+// 	cout << cat_iter->first << "\t" << cat_iter->second << endl;
+//   */
+  
+//   num_nodes = id_catalog.size();  
+// }
+
+// read in .parms file, if present
+
+/*
+void graph::read_parms ( char *parms_file )
+{
+
+		  // read from .parms file
+		  ifstream parms_in ( parms_file );
+		  if ( !parms_in )
+		  {
+		    cout << "Error: could not open .parms file!  Program stopped." << endl;
+			#ifdef MUSE_MPI
+			  MPI_Abort ( MPI_COMM_WORLD, 1 );
+			#else
+			  exit (1);
+			#endif
+		  }
+		  
+		  cout << "Processor " << myid << " reading .parms file." << endl;
+		  
+		  // read in stage parameters
+		  string parm_label;	// this is ignored in the .parms file
+		  
+		  // initial parameters
+		  parms_in >> parm_label >> iterations;
+		  parms_in >> parm_label >> temperature;
+		  parms_in >> parm_label >> attraction;
+		  parms_in >> parm_label >> damping_mult;
+		  
+		  // liquid stage
+		  parms_in >> parm_label >> liquid.iterations;
+		  parms_in >> parm_label >> liquid.temperature;
+		  parms_in >> parm_label >> liquid.attraction;
+		  parms_in >> parm_label >> liquid.damping_mult;
+		  
+		  // expansion stage
+		  parms_in >> parm_label >> expansion.iterations;
+		  parms_in >> parm_label >> expansion.temperature;
+		  parms_in >> parm_label >> expansion.attraction;
+		  parms_in >> parm_label >> expansion.damping_mult;
+		  
+		  // cooldown stage
+		  parms_in >> parm_label >> cooldown.iterations;
+		  parms_in >> parm_label >> cooldown.temperature;
+		  parms_in >> parm_label >> cooldown.attraction;
+		  parms_in >> parm_label >> cooldown.damping_mult;
+		  
+		  // crunch stage
+		  parms_in >> parm_label >> crunch.iterations;
+		  parms_in >> parm_label >> crunch.temperature;
+		  parms_in >> parm_label >> crunch.attraction;
+		  parms_in >> parm_label >> crunch.damping_mult;
+		  
+		  // simmer stage
+		  parms_in >> parm_label >> simmer.iterations;
+		  parms_in >> parm_label >> simmer.temperature;
+		  parms_in >> parm_label >> simmer.attraction;
+		  parms_in >> parm_label >> simmer.damping_mult;
+		  
+		  parms_in.close();
+
+		  // print out parameters for double checking
+		  if ( myid == 0 )
+		  {
+		    cout << "Processor 0 reports the following inputs:" << endl;
+			cout << "inital.iterations = " << iterations << endl;
+			cout << "initial.temperature = " << temperature << endl;
+			cout << "initial.attraction = " << attraction << endl;
+			cout << "initial.damping_mult = " << damping_mult << endl;
+			cout << " ..." << endl;
+			cout << "liquid.iterations = " << liquid.iterations << endl;
+			cout << "liquid.temperature = " << liquid.temperature << endl;
+			cout << "liquid.attraction = " << liquid.attraction << endl;
+			cout << "liquid.damping_mult = " << liquid.damping_mult << endl;
+			cout << " ..." << endl;
+			cout << "simmer.iterations = " << simmer.iterations << endl;
+			cout << "simmer.temperature = " << simmer.temperature << endl;
+			cout << "simmer.attraction = " << simmer.attraction << endl;
+			cout << "simmer.damping_mult = " << simmer.damping_mult << endl;
+		  }
+
+}
+*/
+
+// init_parms -- this subroutine initializes the edge_cut variables
+// used in the original VxOrd starting with the edge_cut parameter.
+// In our version, edge_cut = 0 means no cutting, 1 = maximum cut.
+// We also set the random seed here.
+
+void graph::init_parms ( int rand_seed, float edge_cut, float real_parm )
+{
+        IGRAPH_UNUSED(rand_seed);
+
+	// first we translate edge_cut the former tcl sliding scale
+	//CUT_END = cut_length_end = 39000.0 * (1.0 - edge_cut) + 1000.0;
+	CUT_END = cut_length_end = 40000.0 * (1.0 - edge_cut);
+	
+	// cut_length_end cannot actually be 0
+	if ( cut_length_end <= 1.0 )
+	  cut_length_end = 1.0;
+	  
+	float cut_length_start = 4.0 * cut_length_end;
+	
+	// now we set the parameters used by ReCompute
+	cut_off_length = cut_length_start;
+	cut_rate = ( cut_length_start - cut_length_end ) / 400.0;
+	
+	// finally set the number of iterations to leave .real coords fixed
+	int full_comp_iters;
+	full_comp_iters = liquid.iterations + expansion.iterations +
+					  cooldown.iterations + crunch.iterations + 3;
+    
+	// adjust real parm to iterations (do not enter simmer halfway)
+	if ( real_parm < 0 )
+		real_iterations = (int)real_parm;
+	else if ( real_parm == 1)
+		real_iterations = full_comp_iters + simmer.iterations + 100;
+	else
+		real_iterations = (int)(real_parm*full_comp_iters);
+		
+	tot_iterations = 0;
+	if ( real_iterations > 0 )
+		real_fixed = true;
+	else
+		real_fixed = false;
+
+    // calculate total expected iterations (for progress bar display)
+    tot_expected_iterations = liquid.iterations +
+                              expansion.iterations + cooldown.iterations +
+                              crunch.iterations + simmer.iterations;
+
+	/*
+	// output edge_cutting parms (for debugging)
+	cout << "Processor " << myid << ": "
+	     << "cut_length_end = CUT_END = " << cut_length_end
+	     << ", cut_length_start = " << cut_length_start
+	     << ", cut_rate = " << cut_rate << endl;
+	*/
+	
+	// set random seed
+	// srand ( rand_seed ); // Don't need this in igraph
+	
+}
+
+void graph::init_parms(const igraph_layout_drl_options_t *options) {
+  double rand_seed = 0.0;
+  double real_in = -1.0;
+  init_parms(rand_seed, options->edge_cut, real_in);
+}
+
+// The following subroutine reads a .real file to obtain initial
+// coordinates.  If a node is missing coordinates the coordinates
+// are computed 
+
+// void graph::read_real ( char *real_file )
+// {
+//   cout << "Processor " << myid << " reading .real file ..." << endl;
+  
+//   // read in .real file and mark as fixed
+//   ifstream real_in ( real_file );
+//   if ( !real_in )
+//   {
+//     cout << "Error: proc. " << myid << " could not open .real file." << endl;
+//     #ifdef MUSE_MPI
+// 	  MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 	#else
+// 	  exit (1);
+// 	#endif
+//   }
+  
+//   int real_id;
+//   float real_x, real_y;
+//   while ( !real_in.eof () )
+//   {
+//     real_id = -1;
+//     real_in >> real_id >> real_x >> real_y;
+// 	if ( real_id >= 0 )
+// 	{
+// 	  positions[id_catalog[real_id]].x = real_x;
+// 	  positions[id_catalog[real_id]].y = real_y;
+// 	  positions[id_catalog[real_id]].fixed = true;
+	  
+// 	  /*
+// 	  // output positions read (for debugging)
+//       cout << id_catalog[real_id] << " (" << positions[id_catalog[real_id]].x
+// 		   << ", " << positions[id_catalog[real_id]].y << ") " 
+// 		   << positions[id_catalog[real_id]].fixed << endl;
+// 	  */
+	  
+// 	  // add node to density grid
+// 	  if ( real_iterations > 0 )
+// 	    density_server.Add ( positions[id_catalog[real_id]], fineDensity );
+// 	}
+		 
+//   }
+  
+//   real_in.close();
+// }
+
+int graph::read_real ( const igraph_matrix_t *real_mat, 
+		       const igraph_vector_bool_t *fixed) {
+  long int n=igraph_matrix_nrow(real_mat);
+  for (long int i=0; i<n; i++) {
+    positions[id_catalog[i]].x = MATRIX(*real_mat, i, 0);
+    positions[id_catalog[i]].y = MATRIX(*real_mat, i, 1);
+    positions[id_catalog[i]].fixed = fixed ? VECTOR(*fixed)[i] : false;
+    
+    if ( real_iterations > 0 ) {
+      density_server.Add ( positions[id_catalog[i]], fineDensity );
+    }
+  }
+
+  return 0;
+}
+
+// The read_part_int subroutine reads the .int
+// file produced by convert_sim and gathers the nodes and their
+// neighbors in the range start_ind to end_ind.
+
+// void graph::read_int ( char *file_name )
+// {
+
+// 	ifstream int_file;
+	
+// 	int_file.open ( file_name );
+// 	if ( !int_file )
+// 	{
+// 		cout << "Error (worker process " << myid << "): could not open .int file." << endl;
+// 		#ifdef MUSE_MPI
+// 		  MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 		#else
+// 		  exit (1);
+// 		#endif
+// 	}
+	
+// 	cout << "Processor " << myid << " reading .int file ..." << endl;
+	
+// 	int node_1, node_2;
+// 	float weight;
+	
+//     while ( !int_file.eof() )
+// 	{
+// 		weight = 0;		// all weights should be >= 0
+// 		int_file >> node_1 >> node_2 >> weight;
+// 		if ( weight )		// otherwise we are at end of file
+// 								// or it is a self-connected node
+// 		{
+// 			    // normalization from original vxord
+// 			    weight /= highest_sim;
+// 				weight = weight*fabs(weight);
+				
+// 				// initialize graph
+// 				if ( ( node_1 % num_procs ) == myid )
+// 					(neighbors[id_catalog[node_1]])[id_catalog[node_2]] = weight;
+// 				if ( ( node_2 % num_procs ) == myid )
+// 					(neighbors[id_catalog[node_2]])[id_catalog[node_1]] = weight;
+// 		}
+// 	}
+// 	int_file.close();
+	
+// 	/*
+// 	// the following code outputs the contents of the neighbors structure
+// 	// (to be used for debugging)
+	
+// 	map<int, map<int,float> >::iterator i;
+// 	map<int,float>::iterator j;
+	
+// 	for ( i = neighbors.begin(); i != neighbors.end(); i++ ) {
+// 	  cout << myid << ": " << i->first << " ";
+// 		for (j = (i->second).begin(); j != (i->second).end(); j++ )
+// 			cout << j->first << " (" << j->second << ") ";
+// 		cout << endl;
+// 		}
+// 	*/
+	
+// }
+
+/*********************************************
+ * Function: ReCompute				         *
+ * Description: Compute the graph locations	 *
+ * Modified from original code by B. Wylie   *
+ ********************************************/
+
+int graph::ReCompute( ) 
+{
+
+  // carryover from original VxOrd
+  int MIN = 1;
+  
+  /*
+  // output parameters (for debugging)
+  cout << "ReCompute is using the following parameters: "<< endl;
+  cout << "STAGE: " << STAGE << ", iter: " << iterations << ", temp = " << temperature
+       << ", attract = " << attraction << ", damping_mult = " << damping_mult
+	   << ", min_edges = " << min_edges << ", cut_off_length = " << cut_off_length
+	   << ", fineDensity = " << fineDensity << endl; 
+  */
+
+  /* igraph progress report */
+  float progress = (tot_iterations * 100.0 / tot_expected_iterations);
+
+  switch (STAGE) {
+    case 0:
+      if (iterations == 0)
+        IGRAPH_PROGRESS("DrL layout (initialization stage)", progress, 0);
+      else
+        IGRAPH_PROGRESS("DrL layout (liquid stage)", progress, 0);
+      break;
+    case 1:
+      IGRAPH_PROGRESS("DrL layout (expansion stage)", progress, 0); break;
+    case 2:
+      IGRAPH_PROGRESS("DrL layout (cooldown and cluster phase)", progress, 0); break;
+    case 3:
+      IGRAPH_PROGRESS("DrL layout (crunch phase)", progress, 0); break;
+    case 5:
+      IGRAPH_PROGRESS("DrL layout (simmer phase)", progress, 0); break;
+    case 6:
+      IGRAPH_PROGRESS("DrL layout (final phase)", 100.0, 0); break;
+    default:
+      IGRAPH_PROGRESS("DrL layout (unknown phase)", 0.0, 0); break;
+  }
+
+  /* Compute Energies for individual nodes */
+  update_nodes ();
+  
+  // check to see if we need to free fixed nodes
+  tot_iterations++;
+  if ( tot_iterations >= real_iterations )
+	 real_fixed = false;
+
+
+  	// ****************************************
+	// AUTOMATIC CONTROL SECTION
+	// ****************************************
+
+	// STAGE 0: LIQUID
+	if (STAGE == 0) {
+
+		if ( iterations == 0 )
+		{
+			start_time = time( NULL );
+// 			if ( myid == 0 )
+// 				cout << "Entering liquid stage ...";
+		}
+
+		if (iterations < liquid.iterations) {
+			temperature = liquid.temperature;
+			attraction = liquid.attraction;
+			damping_mult = liquid.damping_mult;
+			iterations++;
+// 			if ( myid == 0 )
+// 				cout << "." << flush;
+		
+		} else {
+
+			stop_time = time( NULL );
+			liquid.time_elapsed = liquid.time_elapsed + (stop_time - start_time);
+			temperature = expansion.temperature;
+			attraction = expansion.attraction;
+			damping_mult = expansion.damping_mult;
+			iterations = 0;
+
+			// go to next stage
+			STAGE = 1;
+			start_time = time( NULL );
+			
+// 			if ( myid == 0 )
+// 				cout << "Entering expansion stage ...";
+		}
+	}
+
+	// STAGE 1: EXPANSION
+	if (STAGE == 1) {
+
+		if (iterations < expansion.iterations) {
+				
+			// Play with vars
+			if (attraction > 1) attraction -= .05;
+			if (min_edges > 12) min_edges -= .05;
+			cut_off_length -= cut_rate;
+			if (damping_mult > .1) damping_mult -= .005;
+			iterations++;
+// 			if ( myid == 0 ) cout << "." << flush;
+	
+		} else {
+
+			stop_time = time( NULL );
+			expansion.time_elapsed = expansion.time_elapsed + (stop_time - start_time);
+		  	min_edges = 12;
+			damping_mult = cooldown.damping_mult;
+			
+			STAGE = 2;
+			attraction = cooldown.attraction;
+			temperature = cooldown.temperature;
+			iterations = 0;
+			start_time = time( NULL );
+			
+// 			if ( myid == 0 )
+// 				cout << "Entering cool-down stage ...";
+		}
+	}
+
+	// STAGE 2: Cool down and cluster
+	else if(STAGE==2) {
+
+		if (iterations < cooldown.iterations) {
+
+			// Reduce temperature
+			if (temperature > 50) temperature -= 10;
+
+			// Reduce cut length
+			if (cut_off_length > cut_length_end) cut_off_length -= cut_rate*2;
+			if (min_edges > MIN) min_edges -= .2;
+			//min_edges = 99;
+			iterations++;
+// 			if ( myid == 0 )
+// 				cout << "." << flush;
+			
+		} else {
+
+			stop_time = time( NULL );
+			cooldown.time_elapsed = cooldown.time_elapsed + (stop_time - start_time);
+			cut_off_length = cut_length_end;
+			temperature = crunch.temperature;
+			damping_mult = crunch.damping_mult;
+			min_edges = MIN;
+			//min_edges = 99; // In other words: no more cutting
+			
+			STAGE = 3;
+			iterations = 0;
+			attraction = crunch.attraction;
+			start_time = time( NULL );
+			
+// 			if ( myid == 0 )
+// 				cout << "Entering crunch stage ...";
+		}  
+	}
+
+	// STAGE 3: Crunch
+	else if(STAGE==3) {
+	
+		if (iterations < crunch.iterations)
+		{
+			iterations++;
+// 			if ( myid == 0 ) cout << "." << flush;
+		}
+		else {
+		
+			stop_time = time( NULL );
+			crunch.time_elapsed = crunch.time_elapsed + (stop_time - start_time);
+			iterations = 0;
+			temperature = simmer.temperature;
+			attraction = simmer.attraction;
+			damping_mult = simmer.damping_mult;
+			min_edges = 99;
+			fineDensity = true;
+			
+			STAGE = 5;
+			start_time = time( NULL );
+				
+// 			if ( myid == 0 )
+// 				cout << "Entering simmer stage ...";
+		}  
+	}
+
+	// STAGE 5: Simmer
+	else if( STAGE==5 ) {
+
+		if (iterations < simmer.iterations) {
+			if (temperature > 50) temperature -= 2;
+			iterations++;
+// 			if ( myid == 0 ) cout << "." << flush;
+		} else {
+			stop_time = time( NULL );
+			simmer.time_elapsed = simmer.time_elapsed + (stop_time - start_time);
+			
+			STAGE = 6;
+			
+// 			if ( myid == 0 )
+// 				cout << "Layout calculation completed in " <<
+// 				  ( liquid.time_elapsed + expansion.time_elapsed +
+// 				    cooldown.time_elapsed + crunch.time_elapsed +
+// 				    simmer.time_elapsed )
+// 				     << " seconds (not including I/O)." 
+// 				     << endl;
+		}
+	}
+
+	// STAGE 6: All Done!
+	else if ( STAGE == 6)
+	{
+	  
+	  /*
+	  // output parameters (for debugging)
+	  cout << "ReCompute is using the following parameters: "<< endl;
+      cout << "STAGE: " << STAGE << ", iter: " << iterations << ", temp = " << temperature
+           << ", attract = " << attraction << ", damping_mult = " << damping_mult
+	       << ", min_edges = " << min_edges << ", cut_off_length = " << cut_off_length
+	       << ", fineDensity = " << fineDensity << endl; 
+	  */
+	  
+	  return 0;
+	}
+	
+	// ****************************************
+	// END AUTOMATIC CONTROL SECTION
+	// ****************************************
+
+	// Still need more recomputation
+	return 1;
+
+}
+
+// update_nodes -- this function will complete the primary node update
+// loop in layout's recompute routine.  It follows exactly the same
+// sequence to ensure similarity of parallel layout to the standard layout
+
+void graph::update_nodes ( )
+{
+	
+	vector<int> node_indices;			// node list of nodes currently being updated
+	float old_positions[2*MAX_PROCS];	// positions before update
+	float new_positions[2*MAX_PROCS];	// positions after update
+    
+	bool all_fixed;						// check if all nodes are fixed
+	
+	// initial node list consists of 0,1,...,num_procs
+	for ( int i = 0; i < num_procs; i++ )
+	  node_indices.push_back( i );
+
+	// next we calculate the number of nodes there would be if the
+	// num_nodes by num_procs schedule grid were perfectly square
+	int square_num_nodes = (int)(num_procs + num_procs*floor ((float)(num_nodes-1)/(float)num_procs ));
+
+	for ( int i = myid; i < square_num_nodes; i += num_procs )
+	{
+	
+		// get old positions
+		get_positions ( node_indices, old_positions );
+		
+		// default new position is old position
+		get_positions ( node_indices, new_positions );
+		
+		if ( i < num_nodes )
+		{
+
+		  // advance random sequence according to myid
+		  for ( int j = 0; j < 2*myid; j++ )
+		    RNG_UNIF01();
+		    // rand();
+
+		  // calculate node energy possibilities
+		  if ( !(positions[i].fixed && real_fixed) )
+			update_node_pos ( i, old_positions, new_positions );
+
+		  // advance random sequence for next iteration
+		  for ( unsigned int j = 2*myid; j < 2*(node_indices.size()-1); j++ )
+		    RNG_UNIF01();
+		    // rand();
+
+		}
+		else
+		{
+		  // advance random sequence according to use by
+		  // the other processors
+		  for ( unsigned int j = 0; j < 2*(node_indices.size()); j++ )
+		    RNG_UNIF01();
+		    //rand();
+		}
+		
+		// check if anything was actually updated (e.g. everything was fixed)
+		all_fixed = true;
+		for ( unsigned int j = 0; j < node_indices.size (); j++ )
+		  if ( !(positions [ node_indices[j] ].fixed && real_fixed) )
+		    all_fixed = false;
+		  
+		// update positions across processors (if not all fixed)
+		if ( !all_fixed )
+		{
+		  #ifdef MUSE_MPI
+  		    MPI_Allgather ( &new_positions[2*myid], 2, MPI_FLOAT,
+			  	            new_positions, 2, MPI_FLOAT, MPI_COMM_WORLD ); 
+		  #endif
+		
+		  // update positions (old to new)
+		  update_density ( node_indices, old_positions, new_positions );
+		}
+		
+		/*
+		if ( myid == 0 )
+		  {
+		    // output node list (for debugging)
+		    for ( unsigned int j = 0; j < node_indices.size(); j++ )
+		      cout << node_indices[j] << " ";
+		    cout << endl;
+		  }
+		*/
+
+		// compute node list for next update
+		for ( unsigned int j = 0; j < node_indices.size(); j++ )
+		  node_indices [j] += num_procs;
+	
+		while ( !node_indices.empty() && node_indices.back() >= num_nodes )
+		  node_indices.pop_back ( );
+			
+	}
+	
+	// update first_add and fine_first_add
+	first_add = false;
+	if ( fineDensity ) fine_first_add = false;
+	
+}
+
+// The get_positions function takes the node_indices list
+// and returns the corresponding positions in an array.
+
+void graph::get_positions ( vector<int> &node_indices,
+			    float return_positions[2*MAX_PROCS]  )
+{
+	
+	// fill positions
+	for(unsigned int i=0; i < node_indices.size(); i++)
+	{
+		return_positions[2*i] = positions[ node_indices[i] ].x;
+		return_positions[2*i+1] = positions[ node_indices[i] ].y;
+	}
+	
+}
+
+// update_node_pos -- this subroutine does the actual work of computing
+// the new position of a given node.  num_act_proc gives the number
+// of active processes at this level for use by the random number
+// generators.
+
+void graph::update_node_pos ( int node_ind,
+			      float old_positions[2*MAX_PROCS],
+			      float new_positions[2*MAX_PROCS] )
+{	
+
+		float energies[2];			// node energies for possible positions
+		float updated_pos[2][2];	// possible positions
+		float pos_x, pos_y;
+		
+		// old VxOrd parameter
+		float jump_length = .010 * temperature;
+		
+		// subtract old node
+		density_server.Subtract ( positions[node_ind], first_add, fine_first_add, fineDensity );
+
+		// compute node energy for old solution
+		energies[0] = Compute_Node_Energy ( node_ind );
+
+	        // move node to centroid position
+		Solve_Analytic ( node_ind, pos_x, pos_y );
+		positions[node_ind].x = updated_pos[0][0] = pos_x;
+		positions[node_ind].y = updated_pos[0][1] = pos_y;
+
+		/*
+		// ouput random numbers (for debugging)
+		int rand_0, rand_1;
+		rand_0 = rand();
+		rand_1 = rand();
+		cout << myid << ": " << rand_0 << ", " << rand_1 << endl;
+		*/
+
+		// Do random method (RAND_MAX is C++ maximum random number)
+		updated_pos[1][0] = updated_pos[0][0] + (.5 - RNG_UNIF01()) * jump_length;
+		updated_pos[1][1] = updated_pos[0][1] + (.5 - RNG_UNIF01()) * jump_length;
+		
+		// compute node energy for random position
+		positions[node_ind].x = updated_pos[1][0];
+		positions[node_ind].y = updated_pos[1][1];
+		energies[1] = Compute_Node_Energy ( node_ind );
+		
+		/*
+		// output update possiblities (debugging):
+		cout << node_ind << ": (" << updated_pos[0][0] << "," << updated_pos[0][1]
+			 << "), " << energies[0] << "; (" << updated_pos[1][0] << ","
+			 << updated_pos[1][1] << "), " << energies[1] << endl;
+		*/
+			 
+		// add back old position
+		positions[node_ind].x = old_positions[2*myid];
+		positions[node_ind].y = old_positions[2*myid+1];
+		if ( !fineDensity && !first_add )
+			density_server.Add ( positions[node_ind], fineDensity );
+		else if ( !fine_first_add )
+			density_server.Add ( positions[node_ind], fineDensity );
+		
+		// choose updated node position with lowest energy
+		if ( energies[0] < energies[1] )
+		{
+			new_positions[2*myid] = updated_pos[0][0];
+			new_positions[2*myid+1] = updated_pos[0][1];
+			positions[node_ind].energy = energies[0];
+		}
+		else
+		{
+			new_positions[2*myid] = updated_pos[1][0];
+			new_positions[2*myid+1] = updated_pos[1][1];
+			positions[node_ind].energy = energies[1];
+		}
+		
+}
+
+// update_density takes a sequence of node_indices and their positions and
+// updates the positions by subtracting the old positions and adding the
+// new positions to the density grid.
+
+void graph::update_density ( vector<int> &node_indices,
+			     float old_positions[2*MAX_PROCS],
+			     float new_positions[2*MAX_PROCS] )
+{
+	
+	// go through each node and subtract old position from
+	// density grid before adding new position
+	for ( unsigned int i = 0; i < node_indices.size(); i++ )
+	{
+		positions[node_indices[i]].x = old_positions[2*i];
+		positions[node_indices[i]].y = old_positions[2*i+1];
+		density_server.Subtract ( positions[node_indices[i]],
+					  first_add, fine_first_add, fineDensity );
+		
+		positions[node_indices[i]].x = new_positions[2*i];
+		positions[node_indices[i]].y = new_positions[2*i+1];
+		density_server.Add ( positions[node_indices[i]], fineDensity );
+	}	
+
+}
+
+/********************************************
+* Function: Compute_Node_Energy			    *
+* Description: Compute the node energy		*
+* This code has been modified from the      *
+* original code by B. Wylie.                *
+*********************************************/
+
+float graph::Compute_Node_Energy( int node_ind )
+{
+	
+	/* Want to expand 4th power range of attraction */
+	float attraction_factor = attraction*attraction*
+			attraction*attraction*2e-2;
+	
+	map <int,float>::iterator EI;
+	float x_dis,y_dis;
+	float energy_distance, weight;
+	float node_energy=0;
+	
+	// Add up all connection energies
+	for(EI = neighbors[node_ind].begin(); EI != neighbors[node_ind].end(); ++EI) {
+
+		// Get edge weight
+		weight = EI->second;
+				
+		// Compute x,y distance
+		x_dis = positions[ node_ind ].x - positions[ EI->first ].x;
+		y_dis = positions[ node_ind ].y - positions[ EI->first ].y;
+		
+		// Energy Distance
+		energy_distance = x_dis*x_dis + y_dis*y_dis;
+		if (STAGE<2) energy_distance *= energy_distance;
+
+		// In the liquid phase we want to discourage long link distances
+		if (STAGE==0) energy_distance *= energy_distance;
+
+		node_energy += weight * attraction_factor * energy_distance;
+	}
+
+	// output effect of density (debugging)
+	//cout << "[before: " << node_energy;
+	
+	// add density
+	node_energy += density_server.GetDensity ( positions[ node_ind ].x, positions[ node_ind ].y,
+											   fineDensity );
+
+	// after calling density server (debugging)
+	//cout << ", after: " << node_energy << "]" << endl;
+	
+	// return computated energy
+	return node_energy;
+}
+
+
+/*********************************************
+* Function: Solve_Analytic			         *
+* Description: Compute the node position     *
+* This is a modified version of the function *
+* originally written by B. Wylie		     *
+*********************************************/
+
+void graph::Solve_Analytic( int node_ind, float &pos_x, float &pos_y )
+{
+
+   map <int,float>::iterator EI;
+   float total_weight = 0;
+   float x_dis, y_dis,x_cen=0, y_cen=0;
+   float x=0,y=0,dis;
+   float damping,weight;
+
+   // Sum up all connections
+   for(EI = neighbors[node_ind].begin(); EI != neighbors[node_ind].end(); ++EI) {
+		weight = EI->second;
+		total_weight += weight;
+		x +=  weight * positions[ EI->first ].x;  
+		y +=  weight * positions[ EI->first ].y;
+   }
+
+   // Now set node position
+   if (total_weight > 0) {
+
+		// Compute centriod
+		x_cen = x/total_weight;
+		y_cen = y/total_weight;
+		damping = 1.0 - damping_mult;
+		pos_x = damping*positions[ node_ind ].x + (1.0-damping) * x_cen;
+		pos_y = damping*positions[ node_ind ].y + (1.0-damping) * y_cen;
+   } else {
+		pos_x = positions[ node_ind ].x;
+		pos_y = positions[ node_ind ].y;
+   }
+   
+   // No cut edge flag (?)
+   if (min_edges == 99) return;
+
+   // Don't cut at end of scale
+   if ( CUT_END >= 39500 ) return;
+
+   float num_connections = sqrt((double)neighbors[node_ind].size());
+   float maxLength = 0;
+
+   map<int, float>::iterator maxIndex;
+
+   // Go through nodes edges... cutting if necessary
+   for(EI = maxIndex = neighbors[node_ind].begin();
+	   EI !=neighbors[node_ind].end(); ++EI) {
+
+		// Check for at least min edges
+		if (neighbors[node_ind].size() < min_edges) continue;
+
+		x_dis = x_cen - positions[ EI->first ].x;
+		y_dis = y_cen - positions[ EI->first ].y;
+		dis = x_dis*x_dis+y_dis*y_dis;
+		dis *= num_connections;
+
+		// Store maximum edge
+		if (dis > maxLength) {maxLength = dis; maxIndex=EI;}
+   }
+
+   // If max length greater than cut_length then cut
+   if (maxLength > cut_off_length) neighbors[ node_ind ].erase( maxIndex ); 
+   
+}
+
+
+// write_coord writes out the coordinate file of the final solutions
+
+// void graph::write_coord( const char *file_name )
+// {
+
+//   ofstream coordOUT( file_name );
+//   if ( !coordOUT )
+//   {
+// 	cout << "Could not open " << file_name << ".  Program terminated." << endl;
+// 	#ifdef MUSE_MPI
+// 	  MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 	#else
+// 	  exit (1);
+// 	#endif
+//   }
+  
+//   cout << "Writing out solution to " << file_name << " ..." << endl;
+  
+//   for (unsigned int i = 0; i < positions.size(); i++) {
+//     coordOUT << positions[i].id << "\t" << positions[i].x << "\t" << positions[i].y <<endl;
+//   }
+//   coordOUT.close();
+  
+// }
+
+// write_sim -- outputs .edges file, takes as input .coord filename,
+// with .coord extension
+
+/*
+void graph::write_sim ( const char *file_name )
+{
+
+  string prefix_name ( file_name, strlen(file_name)-7 );
+  prefix_name = prefix_name + ".iedges";
+
+  // first we overwrite, then we append
+  ofstream simOUT;
+  if ( myid == 0 )
+    simOUT.open ( prefix_name.c_str() );
+  else
+    simOUT.open ( prefix_name.c_str(), ios::app );
+
+  if ( !simOUT )
+    {
+      cout << "Could not open " << prefix_name << ". Program terminated." << endl;
+	  #ifdef MUSE_MPI
+	    MPI_Abort ( MPI_COMM_WORLD, 1 );
+	  #else
+	    exit (1);
+	  #endif
+    }
+  
+
+  cout << "Proc. " << myid << " writing to " << prefix_name << " ..." << endl;
+
+      
+  // the following code outputs the contents of the neighbors structure
+
+  map<int, map<int,float> >::iterator i;
+  map<int,float>::iterator j;
+  
+  for ( i = neighbors.begin(); i != neighbors.end(); i++ )
+    for (j = (i->second).begin(); j != (i->second).end(); j++ )
+	simOUT << positions[i->first].id << "\t"
+	       << positions[j->first].id << "\t"
+	       << j->second << endl;
+
+  simOUT.close();
+
+}
+*/
+
+// get_tot_energy adds up the energy for each node to give an estimate of the
+// quality of the minimization.
+
+float graph::get_tot_energy ( )
+{
+
+	float my_tot_energy, tot_energy;
+	my_tot_energy = 0;
+	for ( int i = myid; i < num_nodes; i += num_procs )
+	  my_tot_energy += positions[i].energy;
+	  
+	//vector<Node>::iterator i;
+    //for ( i = positions.begin(); i != positions.end(); i++ )
+	//	tot_energy += i->energy;
+	
+	#ifdef MUSE_MPI
+		MPI_Reduce ( &my_tot_energy, &tot_energy, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD );
+	#else
+		tot_energy = my_tot_energy;
+	#endif
+	
+	return tot_energy;
+	
+}
+
+
+// The following subroutine draws the graph with possible intermediate
+// output (int_out is set to 0 if not proc. 0).  int_out is the parameter
+// passed by the user, and coord_file is the .coord file.
+
+// void graph::draw_graph ( int int_out, char *coord_file )
+// {
+	
+// 	// layout graph (with possible intermediate output)
+// 	int count_iter = 0, count_file = 1;
+// 	char int_coord_file [MAX_FILE_NAME + MAX_INT_LENGTH];
+// 	while ( ReCompute( ) )
+// 		if ( (int_out > 0) && (count_iter == int_out) )
+// 		{
+// 			// output intermediate solution
+// 			sprintf ( int_coord_file, "%s.%d", coord_file, count_file );
+// 			write_coord ( int_coord_file );
+			
+// 			count_iter = 0;
+// 			count_file++;
+// 		}
+// 		else
+// 			count_iter++;
+	
+// }
+
+int graph::draw_graph(igraph_matrix_t *res) {
+  int count_iter=0;
+  while (ReCompute()) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    count_iter++;
+  }
+  long int n=positions.size();
+  IGRAPH_CHECK(igraph_matrix_resize(res, n, 2));
+  for (long int i=0; i<n; i++) {
+    MATRIX(*res, i, 0) = positions[i].x;
+    MATRIX(*res, i, 1) = positions[i].y;
+  }
+  return 0;
+}
+
+} // namespace drl
diff --git a/src/drl_graph.h b/src/drl_graph.h
new file mode 100644
index 0000000..d01868f
--- /dev/null
+++ b/src/drl_graph.h
@@ -0,0 +1,128 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// The graph class contains the methods necessary to draw the
+// graph.  It calls on the density server class to obtain
+// position and density information
+
+#include "DensityGrid.h"
+#include "igraph_layout.h"
+
+namespace drl {
+
+// layout schedule information
+struct layout_schedule {
+	int iterations;
+	float temperature;
+	float attraction;
+	float damping_mult;
+	time_t time_elapsed;
+};
+
+class graph {
+
+public:
+
+    // Methods
+	void init_parms ( int rand_seed, float edge_cut, float real_parm );
+	void init_parms ( const igraph_layout_drl_options_t *options );
+	void read_parms ( char *parms_file );
+	void read_real ( char *real_file );
+	int read_real ( const igraph_matrix_t *real_mat, 
+			const igraph_vector_bool_t *fixed);
+	void scan_int ( char *filename );
+	void read_int ( char *file_name );
+	void draw_graph ( int int_out, char *coord_file );
+	int draw_graph (igraph_matrix_t *res);
+	void write_coord ( const char *file_name );
+	void write_sim ( const char *file_name );
+	float get_tot_energy ( );
+	
+	// Con/Decon
+	graph( int proc_id, int tot_procs, char *int_file );
+		~graph( ) { }
+	graph( const igraph_t *igraph, 
+	       const igraph_layout_drl_options_t *options,
+	       const igraph_vector_t *weights);
+	
+private:
+
+	// Methods
+	int ReCompute ( );
+	void update_nodes ( );
+	float Compute_Node_Energy ( int node_ind );
+	void Solve_Analytic ( int node_ind, float &pos_x, float &pos_y );
+	void get_positions ( vector<int> &node_indices, float return_positions[2*MAX_PROCS] );
+	void update_density ( vector<int> &node_indices,
+								 float old_positions[2*MAX_PROCS],
+								 float new_positions[2*MAX_PROCS] );
+	void update_node_pos ( int node_ind,
+				      float old_positions[2*MAX_PROCS],
+				      float new_positions[2*MAX_PROCS] );
+								  
+	// MPI information
+	int myid, num_procs;
+	
+	// graph decomposition information
+	int num_nodes;					// number of nodes in graph
+	float highest_sim;				// highest sim for normalization
+	map <int, int> id_catalog;		// id_catalog[file id] = internal id
+	map <int, map <int, float> > neighbors;		// neighbors of nodes on this proc.
+	
+	// graph layout information
+	vector<Node> positions;  
+	DensityGrid density_server;
+  
+	// original VxOrd information
+	int STAGE, iterations;
+	float temperature, attraction, damping_mult;
+	float min_edges, CUT_END, cut_length_end, cut_off_length, cut_rate;
+	bool first_add, fine_first_add, fineDensity;  
+	
+	// scheduling variables
+	layout_schedule liquid;
+	layout_schedule expansion;
+	layout_schedule cooldown;
+	layout_schedule crunch;
+	layout_schedule simmer;
+	
+	// timing statistics
+        time_t start_time, stop_time;
+	
+	// online clustering information
+	int real_iterations;    // number of iterations to hold .real input fixed
+	int tot_iterations;
+    int tot_expected_iterations; // for progress bar
+	bool real_fixed;
+};
+
+} // namespace drl
diff --git a/src/drl_graph_3d.cpp b/src/drl_graph_3d.cpp
new file mode 100644
index 0000000..b34f1b3
--- /dev/null
+++ b/src/drl_graph_3d.cpp
@@ -0,0 +1,854 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains the member definitions of the master class
+
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <vector>
+#include <cstdlib>
+#include <cmath>
+#include <cstring>
+
+using namespace std;
+
+#include "drl_graph_3d.h"
+#include "igraph_random.h"
+#include "igraph_interface.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+namespace drl3d {
+
+graph::graph(const igraph_t *igraph, 
+	     const igraph_layout_drl_options_t *options,
+	     const igraph_vector_t *weights) {
+  myid = 0;
+  num_procs = 1;
+  
+  STAGE = 0;
+  iterations = options->init_iterations;
+  temperature = options->init_temperature;
+  attraction = options->init_attraction;
+  damping_mult = options->init_damping_mult;
+  min_edges = 20;
+  first_add = fine_first_add = true;
+  fineDensity = false;
+  
+  // Brian's original Vx schedule
+  liquid.iterations = options->liquid_iterations;
+  liquid.temperature = options->liquid_temperature;
+  liquid.attraction = options->liquid_attraction;
+  liquid.damping_mult = options->liquid_damping_mult;
+  liquid.time_elapsed = 0;
+  
+  expansion.iterations = options->expansion_iterations;
+  expansion.temperature = options->expansion_temperature;
+  expansion.attraction = options->expansion_attraction;
+  expansion.damping_mult = options->expansion_damping_mult;
+  expansion.time_elapsed = 0;
+  
+  cooldown.iterations = options->cooldown_iterations;
+  cooldown.temperature = options->cooldown_temperature;
+  cooldown.attraction = options->cooldown_attraction;
+  cooldown.damping_mult = options->cooldown_damping_mult;
+  cooldown.time_elapsed = 0;
+  
+  crunch.iterations = options->crunch_iterations;
+  crunch.temperature = options->crunch_temperature;
+  crunch.attraction = options->crunch_attraction;
+  crunch.damping_mult = options->crunch_damping_mult;
+  crunch.time_elapsed = 0;
+  
+  simmer.iterations = options->simmer_iterations;
+  simmer.temperature = options->simmer_temperature;
+  simmer.attraction = options->simmer_attraction;
+  simmer.damping_mult = options->simmer_damping_mult;
+  simmer.time_elapsed = 0;
+  
+  // scan .int file for node info
+  highest_sim = 1.0;
+  num_nodes=igraph_vcount(igraph);
+  long int no_of_edges=igraph_ecount(igraph);
+  for (long int i=0; i<num_nodes; i++) {
+    id_catalog[i] = 1;
+  }
+  map< int, int>::iterator cat_iter;
+  for ( cat_iter = id_catalog.begin();
+	cat_iter != id_catalog.end(); cat_iter++) {
+    cat_iter->second = cat_iter->first;
+  }
+  
+  // populate node positions and ids  
+  positions.reserve ( num_nodes );
+  for ( cat_iter = id_catalog.begin();
+	cat_iter != id_catalog.end();
+	cat_iter++ ) {
+    positions.push_back ( Node( cat_iter->first ) );
+  }
+  
+  // read .int file for graph info
+  long int node_1, node_2;
+  double weight;
+  for (long int i=0; i<no_of_edges; i++) {
+    node_1=IGRAPH_FROM(igraph, i);
+    node_2=IGRAPH_TO(igraph,i);
+    weight = weights ? VECTOR(*weights)[i] : 1.0 ;
+    (neighbors[id_catalog[node_1]])[id_catalog[node_2]] = weight;    
+    (neighbors[id_catalog[node_2]])[id_catalog[node_1]] = weight;  
+  }
+  
+  // initialize density server
+  density_server.Init();
+    
+}
+
+// init_parms -- this subroutine initializes the edge_cut variables
+// used in the original VxOrd starting with the edge_cut parameter.
+// In our version, edge_cut = 0 means no cutting, 1 = maximum cut.
+// We also set the random seed here.
+
+void graph::init_parms ( int rand_seed, float edge_cut, float real_parm )
+{
+
+        IGRAPH_UNUSED(rand_seed);
+	// first we translate edge_cut the former tcl sliding scale
+	//CUT_END = cut_length_end = 39000.0 * (1.0 - edge_cut) + 1000.0;
+	CUT_END = cut_length_end = 40000.0 * (1.0 - edge_cut);
+	
+	// cut_length_end cannot actually be 0
+	if ( cut_length_end <= 1.0 )
+	  cut_length_end = 1.0;
+	  
+	float cut_length_start = 4.0 * cut_length_end;
+	
+	// now we set the parameters used by ReCompute
+	cut_off_length = cut_length_start;
+	cut_rate = ( cut_length_start - cut_length_end ) / 400.0;
+	
+	// finally set the number of iterations to leave .real coords fixed
+	int full_comp_iters;
+	full_comp_iters = liquid.iterations + expansion.iterations +
+					  cooldown.iterations + crunch.iterations + 3;
+    
+	// adjust real parm to iterations (do not enter simmer halfway)
+	if ( real_parm < 0 )
+		real_iterations = (int)real_parm;
+	else if ( real_parm == 1)
+		real_iterations = full_comp_iters + simmer.iterations + 100;
+	else
+		real_iterations = (int)(real_parm*full_comp_iters);
+		
+	tot_iterations = 0;
+	if ( real_iterations > 0 )
+		real_fixed = true;
+	else
+		real_fixed = false;
+
+    // calculate total expected iterations (for progress bar display)
+    tot_expected_iterations = liquid.iterations +
+                              expansion.iterations + cooldown.iterations +
+                              crunch.iterations + simmer.iterations;
+
+	/*
+	// output edge_cutting parms (for debugging)
+	cout << "Processor " << myid << ": "
+	     << "cut_length_end = CUT_END = " << cut_length_end
+	     << ", cut_length_start = " << cut_length_start
+	     << ", cut_rate = " << cut_rate << endl;
+	*/
+	
+	// set random seed
+	// srand ( rand_seed ); // Don't need this in igraph
+	
+}
+
+void graph::init_parms(const igraph_layout_drl_options_t *options) {
+  double rand_seed = 0.0;
+  double real_in = -1.0;
+  init_parms(rand_seed, options->edge_cut, real_in);
+}
+
+int graph::read_real ( const igraph_matrix_t *real_mat, 
+		       const igraph_vector_bool_t *fixed) {
+  long int n=igraph_matrix_nrow(real_mat);
+  for (long int i=0; i<n; i++) {
+    positions[id_catalog[i]].x = MATRIX(*real_mat, i, 0);
+    positions[id_catalog[i]].y = MATRIX(*real_mat, i, 1);
+    positions[id_catalog[i]].z = MATRIX(*real_mat, i, 2);
+    positions[id_catalog[i]].fixed = fixed ? VECTOR(*fixed)[i] : false;
+    
+    if ( real_iterations > 0 ) {
+      density_server.Add ( positions[id_catalog[i]], fineDensity );
+    }
+  }
+
+  return 0;
+}
+
+/*********************************************
+ * Function: ReCompute				         *
+ * Description: Compute the graph locations	 *
+ * Modified from original code by B. Wylie   *
+ ********************************************/
+
+int graph::ReCompute( ) 
+{
+
+  // carryover from original VxOrd
+  int MIN = 1;
+  
+  /*
+  // output parameters (for debugging)
+  cout << "ReCompute is using the following parameters: "<< endl;
+  cout << "STAGE: " << STAGE << ", iter: " << iterations << ", temp = " << temperature
+       << ", attract = " << attraction << ", damping_mult = " << damping_mult
+	   << ", min_edges = " << min_edges << ", cut_off_length = " << cut_off_length
+	   << ", fineDensity = " << fineDensity << endl; 
+  */
+
+  /* igraph progress report */
+  float progress = (tot_iterations * 100.0 / tot_expected_iterations);
+
+  switch (STAGE) {
+    case 0:
+      if (iterations == 0)
+        IGRAPH_PROGRESS("DrL layout (initialization stage)", progress, 0);
+      else
+        IGRAPH_PROGRESS("DrL layout (liquid stage)", progress, 0);
+      break;
+    case 1:
+      IGRAPH_PROGRESS("DrL layout (expansion stage)", progress, 0); break;
+    case 2:
+      IGRAPH_PROGRESS("DrL layout (cooldown and cluster phase)", progress, 0); break;
+    case 3:
+      IGRAPH_PROGRESS("DrL layout (crunch phase)", progress, 0); break;
+    case 5:
+      IGRAPH_PROGRESS("DrL layout (simmer phase)", progress, 0); break;
+    case 6:
+      IGRAPH_PROGRESS("DrL layout (final phase)", 100.0, 0); break;
+    default:
+      IGRAPH_PROGRESS("DrL layout (unknown phase)", 0.0, 0); break;
+  }
+
+  /* Compute Energies for individual nodes */
+  update_nodes ();
+  
+  // check to see if we need to free fixed nodes
+  tot_iterations++;
+  if ( tot_iterations >= real_iterations )
+	 real_fixed = false;
+
+
+  	// ****************************************
+	// AUTOMATIC CONTROL SECTION
+	// ****************************************
+
+	// STAGE 0: LIQUID
+	if (STAGE == 0) {
+
+		if ( iterations == 0 )
+		{
+			start_time = time( NULL );
+// 			if ( myid == 0 )
+// 				cout << "Entering liquid stage ...";
+		}
+
+		if (iterations < liquid.iterations) {
+			temperature = liquid.temperature;
+			attraction = liquid.attraction;
+			damping_mult = liquid.damping_mult;
+			iterations++;
+// 			if ( myid == 0 )
+// 				cout << "." << flush;
+		
+		} else {
+
+			stop_time = time( NULL );
+			liquid.time_elapsed = liquid.time_elapsed + (stop_time - start_time);
+			temperature = expansion.temperature;
+			attraction = expansion.attraction;
+			damping_mult = expansion.damping_mult;
+			iterations = 0;
+
+			// go to next stage
+			STAGE = 1;
+			start_time = time( NULL );
+			
+// 			if ( myid == 0 )
+// 				cout << "Entering expansion stage ...";
+		}
+	}
+
+	// STAGE 1: EXPANSION
+	if (STAGE == 1) {
+
+		if (iterations < expansion.iterations) {
+				
+			// Play with vars
+			if (attraction > 1) attraction -= .05;
+			if (min_edges > 12) min_edges -= .05;
+			cut_off_length -= cut_rate;
+			if (damping_mult > .1) damping_mult -= .005;
+			iterations++;
+// 			if ( myid == 0 ) cout << "." << flush;
+	
+		} else {
+
+			stop_time = time( NULL );
+			expansion.time_elapsed = expansion.time_elapsed + (stop_time - start_time);
+		  	min_edges = 12;
+			damping_mult = cooldown.damping_mult;
+			
+			STAGE = 2;
+			attraction = cooldown.attraction;
+			temperature = cooldown.temperature;
+			iterations = 0;
+			start_time = time( NULL );
+			
+// 			if ( myid == 0 )
+// 				cout << "Entering cool-down stage ...";
+		}
+	}
+
+	// STAGE 2: Cool down and cluster
+	else if(STAGE==2) {
+
+		if (iterations < cooldown.iterations) {
+
+			// Reduce temperature
+			if (temperature > 50) temperature -= 10;
+
+			// Reduce cut length
+			if (cut_off_length > cut_length_end) cut_off_length -= cut_rate*2;
+			if (min_edges > MIN) min_edges -= .2;
+			//min_edges = 99;
+			iterations++;
+// 			if ( myid == 0 )
+// 				cout << "." << flush;
+			
+		} else {
+
+			stop_time = time( NULL );
+			cooldown.time_elapsed = cooldown.time_elapsed + (stop_time - start_time);
+			cut_off_length = cut_length_end;
+			temperature = crunch.temperature;
+			damping_mult = crunch.damping_mult;
+			min_edges = MIN;
+			//min_edges = 99; // In other words: no more cutting
+			
+			STAGE = 3;
+			iterations = 0;
+			attraction = crunch.attraction;
+			start_time = time( NULL );
+			
+// 			if ( myid == 0 )
+// 				cout << "Entering crunch stage ...";
+		}  
+	}
+
+	// STAGE 3: Crunch
+	else if(STAGE==3) {
+	
+		if (iterations < crunch.iterations)
+		{
+			iterations++;
+// 			if ( myid == 0 ) cout << "." << flush;
+		}
+		else {
+		
+			stop_time = time( NULL );
+			crunch.time_elapsed = crunch.time_elapsed + (stop_time - start_time);
+			iterations = 0;
+			temperature = simmer.temperature;
+			attraction = simmer.attraction;
+			damping_mult = simmer.damping_mult;
+			min_edges = 99;
+			fineDensity = true;
+			
+			STAGE = 5;
+			start_time = time( NULL );
+				
+// 			if ( myid == 0 )
+// 				cout << "Entering simmer stage ...";
+		}  
+	}
+
+	// STAGE 5: Simmer
+	else if( STAGE==5 ) {
+
+		if (iterations < simmer.iterations) {
+			if (temperature > 50) temperature -= 2;
+			iterations++;
+// 			if ( myid == 0 ) cout << "." << flush;
+		} else {
+			stop_time = time( NULL );
+			simmer.time_elapsed = simmer.time_elapsed + (stop_time - start_time);
+			
+			STAGE = 6;
+			
+// 			if ( myid == 0 )
+// 				cout << "Layout calculation completed in " <<
+// 				  ( liquid.time_elapsed + expansion.time_elapsed +
+// 				    cooldown.time_elapsed + crunch.time_elapsed +
+// 				    simmer.time_elapsed )
+// 				     << " seconds (not including I/O)." 
+// 				     << endl;
+		}
+	}
+
+	// STAGE 6: All Done!
+	else if ( STAGE == 6)
+	{
+	  
+	  /*
+	  // output parameters (for debugging)
+	  cout << "ReCompute is using the following parameters: "<< endl;
+      cout << "STAGE: " << STAGE << ", iter: " << iterations << ", temp = " << temperature
+           << ", attract = " << attraction << ", damping_mult = " << damping_mult
+	       << ", min_edges = " << min_edges << ", cut_off_length = " << cut_off_length
+	       << ", fineDensity = " << fineDensity << endl; 
+	  */
+	  
+	  return 0;
+	}
+	
+	// ****************************************
+	// END AUTOMATIC CONTROL SECTION
+	// ****************************************
+
+	// Still need more recomputation
+	return 1;
+
+}
+
+// update_nodes -- this function will complete the primary node update
+// loop in layout's recompute routine.  It follows exactly the same
+// sequence to ensure similarity of parallel layout to the standard layout
+
+void graph::update_nodes ( )
+{
+	
+	vector<int> node_indices;			// node list of nodes currently being updated
+	float old_positions[2*MAX_PROCS];	// positions before update
+	float new_positions[2*MAX_PROCS];	// positions after update
+    
+	bool all_fixed;						// check if all nodes are fixed
+	
+	// initial node list consists of 0,1,...,num_procs
+	for ( int i = 0; i < num_procs; i++ )
+	  node_indices.push_back( i );
+
+	// next we calculate the number of nodes there would be if the
+	// num_nodes by num_procs schedule grid were perfectly square
+	int square_num_nodes = (int)(num_procs + num_procs*floor ((float)(num_nodes-1)/(float)num_procs ));
+
+	for ( int i = myid; i < square_num_nodes; i += num_procs )
+	{
+	
+		// get old positions
+		get_positions ( node_indices, old_positions );
+		
+		// default new position is old position
+		get_positions ( node_indices, new_positions );
+		
+		if ( i < num_nodes )
+		{
+
+		  // advance random sequence according to myid
+		  for ( int j = 0; j < 2*myid; j++ )
+		    RNG_UNIF01();
+		    // rand();
+
+		  // calculate node energy possibilities
+		  if ( !(positions[i].fixed && real_fixed) )
+			update_node_pos ( i, old_positions, new_positions );
+
+		  // advance random sequence for next iteration
+		  for ( unsigned int j = 2*myid; j < 2*(node_indices.size()-1); j++ )
+		    RNG_UNIF01();
+		    // rand();
+
+		}
+		else
+		{
+		  // advance random sequence according to use by
+		  // the other processors
+		  for ( unsigned int j = 0; j < 2*(node_indices.size()); j++ )
+		    RNG_UNIF01();
+		    //rand();
+		}
+		
+		// check if anything was actually updated (e.g. everything was fixed)
+		all_fixed = true;
+		for ( unsigned int j = 0; j < node_indices.size (); j++ )
+		  if ( !(positions [ node_indices[j] ].fixed && real_fixed) )
+		    all_fixed = false;
+		  
+		// update positions across processors (if not all fixed)
+		if ( !all_fixed )
+		{
+		  #ifdef MUSE_MPI
+  		    MPI_Allgather ( &new_positions[2*myid], 2, MPI_FLOAT,
+			  	            new_positions, 2, MPI_FLOAT, MPI_COMM_WORLD ); 
+		  #endif
+		
+		  // update positions (old to new)
+		  update_density ( node_indices, old_positions, new_positions );
+		}
+		
+		/*
+		if ( myid == 0 )
+		  {
+		    // output node list (for debugging)
+		    for ( unsigned int j = 0; j < node_indices.size(); j++ )
+		      cout << node_indices[j] << " ";
+		    cout << endl;
+		  }
+		*/
+
+		// compute node list for next update
+		for ( unsigned int j = 0; j < node_indices.size(); j++ )
+		  node_indices [j] += num_procs;
+		
+		while ( !node_indices.empty() && node_indices.back() >= num_nodes )
+		  node_indices.pop_back ( );
+			
+	}
+	
+	// update first_add and fine_first_add
+	first_add = false;
+	if ( fineDensity ) fine_first_add = false;
+	
+}
+
+// The get_positions function takes the node_indices list
+// and returns the corresponding positions in an array.
+
+void graph::get_positions ( vector<int> &node_indices,
+			    float return_positions[3*MAX_PROCS]  )
+{
+	
+	// fill positions
+	for(unsigned int i=0; i < node_indices.size(); i++)
+	{
+		return_positions[3*i] = positions[ node_indices[i] ].x;
+		return_positions[3*i+1] = positions[ node_indices[i] ].y;
+		return_positions[3*i+2] = positions[ node_indices[i] ].z;
+	}
+	
+}
+
+// update_node_pos -- this subroutine does the actual work of computing
+// the new position of a given node.  num_act_proc gives the number
+// of active processes at this level for use by the random number
+// generators.
+
+void graph::update_node_pos ( int node_ind,
+			      float old_positions[3*MAX_PROCS],
+			      float new_positions[3*MAX_PROCS] )
+{	
+
+		float energies[2];			// node energies for possible positions
+		float updated_pos[2][3];	// possible positions
+		float pos_x, pos_y, pos_z;
+		
+		// old VxOrd parameter
+		float jump_length = .010 * temperature;
+		
+		// subtract old node
+		density_server.Subtract ( positions[node_ind], first_add, fine_first_add, fineDensity );
+
+		// compute node energy for old solution
+		energies[0] = Compute_Node_Energy ( node_ind );
+
+	        // move node to centroid position
+		Solve_Analytic ( node_ind, pos_x, pos_y, pos_z );
+		positions[node_ind].x = updated_pos[0][0] = pos_x;
+		positions[node_ind].y = updated_pos[0][1] = pos_y;
+		positions[node_ind].z = updated_pos[0][2] = pos_z;
+
+		/*
+		// ouput random numbers (for debugging)
+		int rand_0, rand_1;
+		rand_0 = rand();
+		rand_1 = rand();
+		cout << myid << ": " << rand_0 << ", " << rand_1 << endl;
+		*/
+
+		// Do random method (RAND_MAX is C++ maximum random number)
+		updated_pos[1][0] = updated_pos[0][0] + (.5 - RNG_UNIF01()) * jump_length;
+		updated_pos[1][1] = updated_pos[0][1] + (.5 - RNG_UNIF01()) * jump_length;
+		updated_pos[1][2] = updated_pos[0][2] + (.5 - RNG_UNIF01()) * jump_length;
+		
+		// compute node energy for random position
+		positions[node_ind].x = updated_pos[1][0];
+		positions[node_ind].y = updated_pos[1][1];
+		positions[node_ind].z = updated_pos[1][2];
+		energies[1] = Compute_Node_Energy ( node_ind );
+		
+		/*
+		// output update possiblities (debugging):
+		cout << node_ind << ": (" << updated_pos[0][0] << "," << updated_pos[0][1]
+			 << "), " << energies[0] << "; (" << updated_pos[1][0] << ","
+			 << updated_pos[1][1] << "), " << energies[1] << endl;
+		*/
+			 
+		// add back old position
+		positions[node_ind].x = old_positions[3*myid];
+		positions[node_ind].y = old_positions[3*myid+1];
+		positions[node_ind].z = old_positions[3*myid+2];
+		if ( !fineDensity && !first_add )
+			density_server.Add ( positions[node_ind], fineDensity );
+		else if ( !fine_first_add )
+			density_server.Add ( positions[node_ind], fineDensity );
+		
+		// choose updated node position with lowest energy
+		if ( energies[0] < energies[1] )
+		{
+			new_positions[3*myid] = updated_pos[0][0];
+			new_positions[3*myid+1] = updated_pos[0][1];
+			new_positions[3*myid+2] = updated_pos[0][2];
+			positions[node_ind].energy = energies[0];
+		}
+		else
+		{
+			new_positions[3*myid] = updated_pos[1][0];
+			new_positions[3*myid+1] = updated_pos[1][1];
+			new_positions[3*myid+2] = updated_pos[1][2];
+			positions[node_ind].energy = energies[1];
+		}
+		
+}
+
+// update_density takes a sequence of node_indices and their positions and
+// updates the positions by subtracting the old positions and adding the
+// new positions to the density grid.
+
+void graph::update_density ( vector<int> &node_indices,
+			     float old_positions[3*MAX_PROCS],
+			     float new_positions[3*MAX_PROCS] )
+{
+	
+	// go through each node and subtract old position from
+	// density grid before adding new position
+	for ( unsigned int i = 0; i < node_indices.size(); i++ )
+	{
+		positions[node_indices[i]].x = old_positions[3*i];
+		positions[node_indices[i]].y = old_positions[3*i+1];
+		positions[node_indices[i]].z = old_positions[3*i+2];
+		density_server.Subtract ( positions[node_indices[i]],
+					  first_add, fine_first_add, fineDensity );
+		
+		positions[node_indices[i]].x = new_positions[3*i];
+		positions[node_indices[i]].y = new_positions[3*i+1];
+		positions[node_indices[i]].z = new_positions[3*i+2];
+		density_server.Add ( positions[node_indices[i]], fineDensity );
+	}	
+
+}
+
+/********************************************
+* Function: Compute_Node_Energy			    *
+* Description: Compute the node energy		*
+* This code has been modified from the      *
+* original code by B. Wylie.                *
+*********************************************/
+
+float graph::Compute_Node_Energy( int node_ind )
+{
+	
+	/* Want to expand 4th power range of attraction */
+	float attraction_factor = attraction*attraction*
+			attraction*attraction*2e-2;
+	
+	map <int,float>::iterator EI;
+	float x_dis,y_dis,z_dis;
+	float energy_distance, weight;
+	float node_energy=0;
+	
+	// Add up all connection energies
+	for(EI = neighbors[node_ind].begin(); EI != neighbors[node_ind].end(); ++EI) {
+
+		// Get edge weight
+		weight = EI->second;
+				
+		// Compute x,y distance
+		x_dis = positions[ node_ind ].x - positions[ EI->first ].x;
+		y_dis = positions[ node_ind ].y - positions[ EI->first ].y;
+		z_dis = positions[ node_ind ].z - positions[ EI->first ].z;
+		
+		// Energy Distance
+		energy_distance = x_dis*x_dis + y_dis*y_dis + z_dis*z_dis;
+		if (STAGE<2) energy_distance *= energy_distance;
+
+		// In the liquid phase we want to discourage long link distances
+		if (STAGE==0) energy_distance *= energy_distance;
+
+		node_energy += weight * attraction_factor * energy_distance;
+	}
+
+	// output effect of density (debugging)
+	//cout << "[before: " << node_energy;
+	
+	// add density
+	node_energy += density_server.GetDensity ( positions[ node_ind ].x, positions[ node_ind ].y,
+						   positions[ node_ind ].z, fineDensity );
+
+	// after calling density server (debugging)
+	//cout << ", after: " << node_energy << "]" << endl;
+	
+	// return computated energy
+	return node_energy;
+}
+
+
+/*********************************************
+* Function: Solve_Analytic			         *
+* Description: Compute the node position     *
+* This is a modified version of the function *
+* originally written by B. Wylie		     *
+*********************************************/
+
+void graph::Solve_Analytic( int node_ind, float &pos_x, float &pos_y,
+			    float &pos_z)
+{
+
+   map <int,float>::iterator EI;
+   float total_weight = 0;
+   float x_dis, y_dis, z_dis, x_cen=0, y_cen=0, z_cen=0;
+   float x=0,y=0,z=0,dis;
+   float damping,weight;
+
+   // Sum up all connections
+   for(EI = neighbors[node_ind].begin(); EI != neighbors[node_ind].end(); ++EI) {
+		weight = EI->second;
+		total_weight += weight;
+		x +=  weight * positions[ EI->first ].x;  
+		y +=  weight * positions[ EI->first ].y;
+		z +=  weight * positions[ EI->first ].z;
+   }
+
+   // Now set node position
+   if (total_weight > 0) {
+
+		// Compute centriod
+		x_cen = x/total_weight;
+		y_cen = y/total_weight;
+		z_cen = z/total_weight;
+		damping = 1.0 - damping_mult;
+		pos_x = damping*positions[ node_ind ].x + (1.0-damping) * x_cen;
+		pos_y = damping*positions[ node_ind ].y + (1.0-damping) * y_cen;
+		pos_z = damping*positions[ node_ind ].z + (1.0-damping) * z_cen;
+   }
+   
+   // No cut edge flag (?)
+   if (min_edges == 99) return;
+
+   // Don't cut at end of scale
+   if ( CUT_END >= 39500 ) return;
+
+   float num_connections = (float)sqrt((float)neighbors[node_ind].size());
+   float maxLength = 0;
+
+   map<int, float>::iterator maxIndex;
+
+   // Go through nodes edges... cutting if necessary
+   for(EI = maxIndex = neighbors[node_ind].begin();
+	   EI !=neighbors[node_ind].end(); ++EI) {
+
+		// Check for at least min edges
+		if (neighbors[node_ind].size() < min_edges) continue;
+
+		x_dis = x_cen - positions[ EI->first ].x;
+		y_dis = y_cen - positions[ EI->first ].y;
+		z_dis = z_cen - positions[ EI->first ].z;
+		dis = x_dis*x_dis+y_dis*y_dis+z_dis*z_dis;
+		dis *= num_connections;
+
+		// Store maximum edge
+		if (dis > maxLength) {maxLength = dis; maxIndex=EI;}
+   }
+
+   // If max length greater than cut_length then cut
+   if (maxLength > cut_off_length) neighbors[ node_ind ].erase( maxIndex ); 
+   
+}
+
+
+// get_tot_energy adds up the energy for each node to give an estimate of the
+// quality of the minimization.
+
+float graph::get_tot_energy ( )
+{
+
+	float my_tot_energy, tot_energy;
+	my_tot_energy = 0;
+	for ( int i = myid; i < num_nodes; i += num_procs )
+	  my_tot_energy += positions[i].energy;
+	  
+	//vector<Node>::iterator i;
+    //for ( i = positions.begin(); i != positions.end(); i++ )
+	//	tot_energy += i->energy;
+	
+	#ifdef MUSE_MPI
+		MPI_Reduce ( &my_tot_energy, &tot_energy, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD );
+	#else
+		tot_energy = my_tot_energy;
+	#endif
+	
+	return tot_energy;
+	
+}
+
+
+int graph::draw_graph(igraph_matrix_t *res) {
+  int count_iter=0;
+  while (ReCompute()) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    count_iter++;
+  }
+  long int n=positions.size();
+  IGRAPH_CHECK(igraph_matrix_resize(res, n, 3));
+  for (long int i=0; i<n; i++) {
+    MATRIX(*res, i, 0) = positions[i].x;
+    MATRIX(*res, i, 1) = positions[i].y;
+    MATRIX(*res, i, 2) = positions[i].z;
+  }
+  return 0;
+}
+
+} // namespace drl3d
diff --git a/src/drl_graph_3d.h b/src/drl_graph_3d.h
new file mode 100644
index 0000000..1777a40
--- /dev/null
+++ b/src/drl_graph_3d.h
@@ -0,0 +1,120 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// The graph class contains the methods necessary to draw the
+// graph.  It calls on the density server class to obtain
+// position and density information
+
+#include "DensityGrid_3d.h"
+#include "igraph_layout.h"
+
+namespace drl3d {
+
+// layout schedule information
+struct layout_schedule {
+	int iterations;
+	float temperature;
+	float attraction;
+	float damping_mult;
+	time_t time_elapsed;
+};
+
+class graph {
+
+public:
+
+    // Methods
+	void init_parms ( int rand_seed, float edge_cut, float real_parm );
+	void init_parms ( const igraph_layout_drl_options_t *options );
+	int read_real ( const igraph_matrix_t *real_mat, 
+			const igraph_vector_bool_t *fixed);
+	int draw_graph (igraph_matrix_t *res);
+	float get_tot_energy ( );
+	
+	// Con/Decon
+	graph( const igraph_t *igraph, 
+	       const igraph_layout_drl_options_t *options,
+	       const igraph_vector_t *weights);
+	~graph( ) { }
+	
+private:
+
+	// Methods
+	int ReCompute ( );
+	void update_nodes ( );
+	float Compute_Node_Energy ( int node_ind );
+	void Solve_Analytic ( int node_ind, float &pos_x, float &pos_y, float &pos_z );
+	void get_positions ( vector<int> &node_indices, float return_positions[3*MAX_PROCS] );
+	void update_density ( vector<int> &node_indices,
+			      float old_positions[3*MAX_PROCS],
+			      float new_positions[3*MAX_PROCS] );
+	void update_node_pos ( int node_ind,
+			       float old_positions[3*MAX_PROCS],
+			       float new_positions[3*MAX_PROCS] );
+								  
+	// MPI information
+	int myid, num_procs;
+	
+	// graph decomposition information
+	int num_nodes;					// number of nodes in graph
+	float highest_sim;				// highest sim for normalization
+	map <int, int> id_catalog;		// id_catalog[file id] = internal id
+	map <int, map <int, float> > neighbors;		// neighbors of nodes on this proc.
+	
+	// graph layout information
+	vector<Node> positions;  
+	DensityGrid density_server;
+  
+	// original VxOrd information
+	int STAGE, iterations;
+	float temperature, attraction, damping_mult;
+	float min_edges, CUT_END, cut_length_end, cut_off_length, cut_rate;
+	bool first_add, fine_first_add, fineDensity;  
+	
+	// scheduling variables
+	layout_schedule liquid;
+	layout_schedule expansion;
+	layout_schedule cooldown;
+	layout_schedule crunch;
+	layout_schedule simmer;
+	
+	// timing statistics
+        time_t start_time, stop_time;
+	
+	// online clustering information
+	int real_iterations;    // number of iterations to hold .real input fixed
+	int tot_iterations;
+    int tot_expected_iterations; // for progress bar
+	bool real_fixed;
+};
+
+} // namespace drl3d
diff --git a/src/drl_layout.cpp b/src/drl_layout.cpp
new file mode 100644
index 0000000..3bf3f41
--- /dev/null
+++ b/src/drl_layout.cpp
@@ -0,0 +1,472 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// Layout
+//
+// This program implements a parallel force directed graph drawing
+// algorithm.  The algorithm used is based upon a random decomposition
+// of the graph and simulated shared memory of node position and density.
+// In this version, the simulated shared memory is spread among all processors
+//
+// The structure of the inputs and outputs of this code will be displayed
+// if the program is called without parameters, or if an erroneous
+// parameter is passed to the program.
+//
+// S. Martin
+// 5/6/2005
+
+// C++ library routines
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <set>
+#include <string>
+#include <deque>
+#include <vector>
+
+using namespace std;
+
+// layout routines and constants
+#include "drl_layout.h"
+#include "drl_parse.h"
+#include "drl_graph.h"
+
+// MPI
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+using namespace drl;
+#include "igraph_layout.h"
+#include "igraph_random.h"
+#include "igraph_interface.h"
+
+namespace drl {
+
+// int main(int argc, char **argv) {
+  
+  
+//   // initialize MPI
+//   int myid, num_procs;
+  
+//   #ifdef MUSE_MPI
+//     MPI_Init ( &argc, &argv );
+//     MPI_Comm_size ( MPI_COMM_WORLD, &num_procs );
+//     MPI_Comm_rank ( MPI_COMM_WORLD, &myid );
+//   #else
+//     myid = 0;
+// 	num_procs = 1;
+//   #endif
+  
+//   // parameters that must be broadcast to all processors
+//   int rand_seed;
+//   float edge_cut;
+  
+//   char int_file[MAX_FILE_NAME];
+//   char coord_file[MAX_FILE_NAME];
+//   char real_file[MAX_FILE_NAME];
+//   char parms_file[MAX_FILE_NAME];
+  
+//   int int_out = 0;
+//   int edges_out = 0;
+//   int parms_in = 0;
+//   float real_in = -1.0;
+  
+//   // user interaction is handled by processor 0
+//   if ( myid == 0 )
+//   {
+//     if ( num_procs > MAX_PROCS )
+// 	{
+// 		cout << "Error: Maximum number of processors is " << MAX_PROCS << "." << endl;
+// 		cout << "Adjust compile time parameter." << endl;
+// 		#ifdef MUSE_MPI
+// 		  MPI_Abort ( MPI_COMM_WORLD, 1 );
+// 		#else
+// 		  exit (1);
+// 		#endif
+// 	}
+	
+// 	// get user input
+//     parse command_line ( argc, argv );
+// 	rand_seed = command_line.rand_seed;
+// 	edge_cut = command_line.edge_cut;
+// 	int_out = command_line.int_out;
+// 	edges_out = command_line.edges_out;
+// 	parms_in = command_line.parms_in;
+// 	real_in = command_line.real_in;
+// 	strcpy ( coord_file, command_line.coord_file.c_str() );
+// 	strcpy ( int_file, command_line.sim_file.c_str() );
+// 	strcpy ( real_file, command_line.real_file.c_str() );
+// 	strcpy ( parms_file, command_line.parms_file.c_str() );
+	
+//   }
+  
+//   // now we initialize all processors by reading .int file
+//   #ifdef MUSE_MPI
+//     MPI_Bcast ( &int_file, MAX_FILE_NAME, MPI_CHAR, 0, MPI_COMM_WORLD );
+//   #endif
+//   graph neighbors ( myid, num_procs, int_file );
+  
+//   // check for user supplied parameters
+//   #ifdef MUSE_MPI
+//     MPI_Bcast ( &parms_in, 1, MPI_INT, 0, MPI_COMM_WORLD );
+//   #endif
+//   if ( parms_in )
+//   {
+//     #ifdef MUSE_MPI
+// 	  MPI_Bcast ( &parms_file, MAX_FILE_NAME, MPI_CHAR, 0, MPI_COMM_WORLD );
+// 	#endif
+// 	neighbors.read_parms ( parms_file );
+//   }
+
+//   // set random seed, edge cutting, and real iterations parameters
+//   #ifdef MUSE_MPI
+//     MPI_Bcast ( &rand_seed, 1, MPI_INT, 0, MPI_COMM_WORLD );
+//     MPI_Bcast ( &edge_cut, 1, MPI_FLOAT, 0, MPI_COMM_WORLD );
+// 	MPI_Bcast ( &real_in, 1, MPI_INT, 0, MPI_COMM_WORLD );
+//   #endif
+//   neighbors.init_parms ( rand_seed, edge_cut, real_in );
+
+//   // check for .real file with existing coordinates
+//   if ( real_in >= 0 )
+//   {
+//     #ifdef MUSE_MPI
+// 	  MPI_Bcast ( &real_file, MAX_FILE_NAME, MPI_CHAR, 0, MPI_COMM_WORLD );
+// 	#endif
+// 	neighbors.read_real ( real_file );
+//   }
+  
+//   neighbors.draw_graph ( int_out, coord_file );
+
+//   // do we have to write out the edges?
+//   #ifdef MUSE_MPI
+//     MPI_Bcast ( &edges_out, 1, MPI_INT, 0, MPI_COMM_WORLD );
+//   #endif
+//   if ( edges_out )
+//     {
+// 	  #ifdef MUSE_MPI
+//         MPI_Bcast ( &coord_file, MAX_FILE_NAME, MPI_CHAR, 0, MPI_COMM_WORLD );
+// 	  #endif
+//       for ( int i = 0; i < num_procs; i++ )
+// 	  {
+// 	    if ( myid == i )
+// 	      neighbors.write_sim ( coord_file );
+// 	    #ifdef MUSE_MPI
+//   	      MPI_Barrier ( MPI_COMM_WORLD );
+// 	    #endif
+// 	  }
+//     }
+  
+//   // finally we output file and quit
+//   float tot_energy;
+//   tot_energy = neighbors.get_tot_energy ();
+//   if ( myid == 0 )
+//   {
+// 	neighbors.write_coord ( coord_file );
+// 	cout << "Total Energy: " << tot_energy << "." << endl
+// 	     << "Program terminated successfully." << endl;
+//   }
+
+//   // MPI finalize
+//   #ifdef MUSE_MPI
+//     MPI_Finalize ();
+//   #endif
+
+//   return 0;
+// }
+
+} // namespace drl
+
+/**
+ * \section about_drl
+ * 
+ * <para>
+ * DrL is a sophisticated layout generator developed and implemented by 
+ * Shawn Martin et al. As of October 2012 the original DrL homepage is
+ * unfortunately not available. You can read more about this algorithm
+ * in 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.
+ * </para>
+ * 
+ * <para>
+ * Only a subset of the complete DrL functionality is 
+ * included in igraph, parallel runs and recursive, multi-level
+ * layouting is not supported.
+ * </para>
+ * 
+ * <para>
+ * The parameters of the layout are stored in an \ref
+ * igraph_layout_drl_options_t structure, this can be initialized by
+ * calling the function \ref igraph_layout_drl_options_init(). 
+ * The fields of this structure can then be adjusted by hand if needed.
+ * The layout is calculated by an \ref igraph_layout_drl() call.
+ * </para>
+ */
+
+/**
+ * \function igraph_layout_drl_options_init
+ * Initialize parameters for the DrL layout generator
+ * 
+ * This function can be used to initialize the struct holding the
+ * parameters for the DrL layout generator. There are a number of
+ * predefined templates available, it is a good idea to start from one
+ * of these by modifying some parameters.
+ * \param options The struct to initialize.
+ * \param templ The template to use. Currently the following templates
+ *     are supplied: \c IGRAPH_LAYOUT_DRL_DEFAULT, \c
+ *     IGRAPH_LAYOUT_DRL_COARSEN, \c IGRAPH_LAYOUT_DRL_COARSEST, 
+ *     \c IGRAPH_LAYOUT_DRL_REFINE and \c IGRAPH_LAYOUT_DRL_FINAL.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_layout_drl_options_init(igraph_layout_drl_options_t *options,
+				   igraph_layout_drl_default_t templ) {
+
+  options->edge_cut=32.0/40.0;
+    
+  switch (templ) {
+  case IGRAPH_LAYOUT_DRL_DEFAULT:
+    options->init_iterations   = 0;
+    options->init_temperature  = 2000;
+    options->init_attraction   = 10;
+    options->init_damping_mult = 1.0;
+
+    options->liquid_iterations   = 200;
+    options->liquid_temperature  = 2000;
+    options->liquid_attraction   = 10;
+    options->liquid_damping_mult = 1.0;
+
+    options->expansion_iterations   = 200;
+    options->expansion_temperature  = 2000;
+    options->expansion_attraction   = 2;
+    options->expansion_damping_mult = 1.0;
+
+    options->cooldown_iterations   = 200;
+    options->cooldown_temperature  = 2000;
+    options->cooldown_attraction   = 1;
+    options->cooldown_damping_mult = .1;
+
+    options->crunch_iterations   = 50;
+    options->crunch_temperature  = 250;
+    options->crunch_attraction   = 1;
+    options->crunch_damping_mult = 0.25;
+
+    options->simmer_iterations   = 100;
+    options->simmer_temperature  = 250;
+    options->simmer_attraction   = .5;
+    options->simmer_damping_mult = 0;
+    
+    break;
+  case IGRAPH_LAYOUT_DRL_COARSEN:
+    options->init_iterations   = 0;
+    options->init_temperature  = 2000;
+    options->init_attraction   = 10;
+    options->init_damping_mult = 1.0;
+
+    options->liquid_iterations   = 200;
+    options->liquid_temperature  = 2000;
+    options->liquid_attraction   = 2;
+    options->liquid_damping_mult = 1.0;
+
+    options->expansion_iterations   = 200;
+    options->expansion_temperature  = 2000;
+    options->expansion_attraction   = 10;
+    options->expansion_damping_mult = 1.0;
+
+    options->cooldown_iterations   = 200;
+    options->cooldown_temperature  = 2000;
+    options->cooldown_attraction   = 1;
+    options->cooldown_damping_mult = .1;
+
+    options->crunch_iterations   = 50;
+    options->crunch_temperature  = 250;
+    options->crunch_attraction   = 1;
+    options->crunch_damping_mult = 0.25;
+
+    options->simmer_iterations   = 100;
+    options->simmer_temperature  = 250;
+    options->simmer_attraction   = .5;
+    options->simmer_damping_mult = 0;
+
+    break;
+  case IGRAPH_LAYOUT_DRL_COARSEST:
+    options->init_iterations   = 0;
+    options->init_temperature  = 2000;
+    options->init_attraction   = 10;
+    options->init_damping_mult = 1.0;
+
+    options->liquid_iterations   = 200;
+    options->liquid_temperature  = 2000;
+    options->liquid_attraction   = 2;
+    options->liquid_damping_mult = 1.0;
+
+    options->expansion_iterations   = 200;
+    options->expansion_temperature  = 2000;
+    options->expansion_attraction   = 10;
+    options->expansion_damping_mult = 1.0;
+
+    options->cooldown_iterations   = 200;
+    options->cooldown_temperature  = 2000;
+    options->cooldown_attraction   = 1;
+    options->cooldown_damping_mult = .1;
+
+    options->crunch_iterations   = 200;
+    options->crunch_temperature  = 250;
+    options->crunch_attraction   = 1;
+    options->crunch_damping_mult = 0.25;
+
+    options->simmer_iterations   = 100;
+    options->simmer_temperature  = 250;
+    options->simmer_attraction   = .5;
+    options->simmer_damping_mult = 0;
+
+    break;
+  case IGRAPH_LAYOUT_DRL_REFINE:
+    options->init_iterations   = 0;
+    options->init_temperature  = 50;
+    options->init_attraction   = .5;
+    options->init_damping_mult = 0;
+
+    options->liquid_iterations   = 0;
+    options->liquid_temperature  = 2000;
+    options->liquid_attraction   = 2;
+    options->liquid_damping_mult = 1.0;
+
+    options->expansion_iterations   = 50;
+    options->expansion_temperature  = 500;
+    options->expansion_attraction   = .1;
+    options->expansion_damping_mult = .25;
+
+    options->cooldown_iterations   = 50;
+    options->cooldown_temperature  = 200;
+    options->cooldown_attraction   = 1;
+    options->cooldown_damping_mult = .1;
+
+    options->crunch_iterations   = 50;
+    options->crunch_temperature  = 250;
+    options->crunch_attraction   = 1;
+    options->crunch_damping_mult = 0.25;
+
+    options->simmer_iterations   = 0;
+    options->simmer_temperature  = 250;
+    options->simmer_attraction   = .5;
+    options->simmer_damping_mult = 0;
+
+    break;
+  case IGRAPH_LAYOUT_DRL_FINAL:
+    options->init_iterations   = 0;
+    options->init_temperature  = 50;
+    options->init_attraction   = .5;
+    options->init_damping_mult = 0;
+
+    options->liquid_iterations   = 0;
+    options->liquid_temperature  = 2000;
+    options->liquid_attraction   = 2;
+    options->liquid_damping_mult = 1.0;
+
+    options->expansion_iterations   = 50;
+    options->expansion_temperature  = 50;
+    options->expansion_attraction   = .1;
+    options->expansion_damping_mult = .25;
+
+    options->cooldown_iterations   = 50;
+    options->cooldown_temperature  = 200;
+    options->cooldown_attraction   = 1;
+    options->cooldown_damping_mult = .1;
+
+    options->crunch_iterations   = 50;
+    options->crunch_temperature  = 250;
+    options->crunch_attraction   = 1;
+    options->crunch_damping_mult = 0.25;
+
+    options->simmer_iterations   = 25;
+    options->simmer_temperature  = 250;
+    options->simmer_attraction   = .5;
+    options->simmer_damping_mult = 0;
+    
+  default:
+    IGRAPH_ERROR("Unkown DrL template", IGRAPH_EINVAL);
+    break;
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_layout_drl
+ * The DrL layout generator
+ * 
+ * This function implements the force-directed DrL layout generator.
+ * Please see more in 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. 
+ * \param graph The input graph.
+ * \param use_seed Logical scalar, if true, then the coordinates
+ *    supplied in the \p res argument are used as starting points.
+ * \param res Pointer to a matrix, the result layout is stored
+ *    here. It will be resized as needed.
+ * \param options The parameters to pass to the layout generator.
+ * \param weights Edge weights, pointer to a vector. If this is a null
+ *    pointer then every edge will have the same weight.
+ * \param fixed Pointer to a logical vector, or a null pointer. This
+ *    can be used to fix the position of some vertices. Vertices for
+ *    which it is true will not be moved, but stay at the coordinates
+ *    given in the \p res matrix. This argument is ignored if it is a
+ *    null pointer or if use_seed is false.
+ * \return Error code.
+ * 
+ * Time complexity: ???.
+ */
+
+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) {
+  
+  RNG_BEGIN();
+
+  drl::graph neighbors(graph, options, weights);
+  neighbors.init_parms(options);
+  if (use_seed) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, igraph_vcount(graph), 2));
+    neighbors.read_real(res, fixed);
+  }
+  neighbors.draw_graph(res);
+
+  RNG_END();
+  
+  return 0;
+}	      
diff --git a/src/drl_layout.h b/src/drl_layout.h
new file mode 100644
index 0000000..0e00937
--- /dev/null
+++ b/src/drl_layout.h
@@ -0,0 +1,65 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains compile time parameters which affect the entire
+// DrL program.
+
+#define DRL_VERSION "3.2 5/5/2006"
+
+// compile time parameters for MPI message passing
+#define MAX_PROCS 256	   // maximum number of processors
+#define MAX_FILE_NAME 250   // max length of filename
+#define MAX_INT_LENGTH 4   // max length of integer suffix of intermediate .coord file
+
+// Compile time adjustable parameters for the Density grid
+
+#define GRID_SIZE 1000			// size of Density grid
+#define VIEW_SIZE 4000.0		// actual physical size of layout plane
+								// these values use more memory but have
+								// little effect on performance or layout
+								
+#define RADIUS 10				// radius for density fall-off:
+								// larger values tends to slow down
+								// the program and clump the data
+
+#define HALF_VIEW 2000			// 1/2 of VIEW_SIZE
+#define VIEW_TO_GRID .25		// ratio of GRID_SIZE to VIEW_SIZE
+
+/*
+// original values for VxOrd
+#define GRID_SIZE 400			// size of VxOrd Density grid
+#define VIEW_SIZE 1600.0		// actual physical size of VxOrd plane
+#define RADIUS 10				// radius for density fall-off
+
+#define HALF_VIEW 800			// 1/2 of VIEW_SIZE
+#define VIEW_TO_GRID .25		// ratio of GRID_SIZE to VIEW_SIZE
+*/
diff --git a/src/drl_layout_3d.cpp b/src/drl_layout_3d.cpp
new file mode 100644
index 0000000..7441c1c
--- /dev/null
+++ b/src/drl_layout_3d.cpp
@@ -0,0 +1,123 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// Layout
+//
+// This program implements a parallel force directed graph drawing
+// algorithm.  The algorithm used is based upon a random decomposition
+// of the graph and simulated shared memory of node position and density.
+// In this version, the simulated shared memory is spread among all processors
+//
+// The structure of the inputs and outputs of this code will be displayed
+// if the program is called without parameters, or if an erroneous
+// parameter is passed to the program.
+//
+// S. Martin
+// 5/6/2005
+
+// C++ library routines
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <set>
+#include <string>
+#include <deque>
+#include <vector>
+
+using namespace std;
+
+// layout routines and constants
+#include "drl_layout_3d.h"
+#include "drl_parse.h"
+#include "drl_graph_3d.h"
+
+// MPI
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+using namespace drl3d;
+#include "igraph_layout.h"
+#include "igraph_random.h"
+#include "igraph_interface.h"
+
+/**
+ * \function igraph_layout_drl_3d
+ * The DrL layout generator, 3d version.
+ * 
+ * This function implements the force-directed DrL layout generator.
+ * Please see more in the technical report: Martin, S., Brown, W.M.,
+ * Klavans, R., Boyack, K.W., DrL: Distributed Recursive (Graph)
+ * Layout. SAND Reports, 2008. 2936: p. 1-10.
+ *
+ * </para><para> This function uses a modified DrL generator that does
+ * the layout in three dimensions.
+ * \param graph The input graph.
+ * \param use_seed Logical scalar, if true, then the coordinates
+ *    supplied in the \p res argument are used as starting points.
+ * \param res Pointer to a matrix, the result layout is stored
+ *    here. It will be resized as needed.
+ * \param options The parameters to pass to the layout generator.
+ * \param weights Edge weights, pointer to a vector. If this is a null
+ *    pointer then every edge will have the same weight.
+ * \param fixed Pointer to a logical vector, or a null pointer. This
+ *    can be used to fix the position of some vertices. Vertices for
+ *    which it is true will not be moved, but stay at the coordinates
+ *    given in the \p res matrix. This argument is ignored if it is a
+ *    null pointer or if use_seed is false.
+ * \return Error code.
+ * 
+ * Time complexity: ???.
+ * 
+ * \sa \ref igraph_layout_drl() for the standard 2d version.
+ */
+
+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) {
+  
+  RNG_BEGIN();
+
+  drl3d::graph neighbors(graph, options, weights);
+  neighbors.init_parms(options);
+  if (use_seed) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, igraph_vcount(graph), 3));
+    neighbors.read_real(res, fixed);
+  }
+  neighbors.draw_graph(res);
+
+  RNG_END();
+  
+  return 0;
+}	      
diff --git a/src/drl_layout_3d.h b/src/drl_layout_3d.h
new file mode 100644
index 0000000..1901c85
--- /dev/null
+++ b/src/drl_layout_3d.h
@@ -0,0 +1,65 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains compile time parameters which affect the entire
+// DrL program.
+
+#define DRL_VERSION "3.2 5/5/2006"
+
+// compile time parameters for MPI message passing
+#define MAX_PROCS 256	   // maximum number of processors
+#define MAX_FILE_NAME 250   // max length of filename
+#define MAX_INT_LENGTH 4   // max length of integer suffix of intermediate .coord file
+
+// Compile time adjustable parameters for the Density grid
+
+#define GRID_SIZE 100			// size of Density grid
+#define VIEW_SIZE 250.0		// actual physical size of layout plane
+								// these values use more memory but have
+								// little effect on performance or layout
+								
+#define RADIUS 10				// radius for density fall-off:
+								// larger values tends to slow down
+								// the program and clump the data
+
+#define HALF_VIEW 125.0			// 1/2 of VIEW_SIZE
+#define VIEW_TO_GRID .4			// ratio of GRID_SIZE to VIEW_SIZE
+
+/*
+// original values for VxOrd
+#define GRID_SIZE 400			// size of VxOrd Density grid
+#define VIEW_SIZE 1600.0		// actual physical size of VxOrd plane
+#define RADIUS 10				// radius for density fall-off
+
+#define HALF_VIEW 800			// 1/2 of VIEW_SIZE
+#define VIEW_TO_GRID .25		// ratio of GRID_SIZE to VIEW_SIZE
+*/
diff --git a/src/drl_parse.cpp b/src/drl_parse.cpp
new file mode 100644
index 0000000..e6a7b66
--- /dev/null
+++ b/src/drl_parse.cpp
@@ -0,0 +1,205 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// This file contains the methods for the parse.h class
+
+#include <string>
+#include <iostream>
+#include <map>
+#include <cstdlib>
+#include <cstdio>
+
+using namespace std;
+
+#include "drl_layout.h"
+#include "drl_parse.h"
+
+namespace drl {
+
+// void parse::print_syntax( const char *error_string )
+// {
+//   cout << endl << "Error: " << error_string << endl;
+//   cout << endl << "Layout" << endl
+// 	   <<     "------" << endl
+// 	   << "S. Martin" << endl
+// 	   << "Version " << DRL_VERSION << endl << endl
+// 	   << "This program provides a parallel adaptation of a force directed" << endl
+// 	   << "graph layout algorithm for use with large datasets." << endl << endl
+// 	   << "Usage: layout [options] root_file" << endl << endl
+// 	   << "root_file -- the root name of the file being processed." << endl << endl
+// 	   << "INPUT" << endl
+// 	   << "-----" << endl
+// 	   << "root_file.int -- the input file containing the graph to draw using layout." << endl
+// 	   << "  The .int file must have the suffix \".int\" and each line of .int file" << endl
+// 	   << "  should have the form" << endl
+// 	   << "\tnode_id <tab> node_id <tab> weight" << endl
+// 	   << "  where node_id's are integers in sequence starting from 0, and" << endl
+// 	   << "  weight is a float > 0." << endl << endl
+// 	   << "OUTPUT" << endl
+// 	   << "------" << endl
+// 	   << "root_file.icoord -- the resulting output file, containing an ordination" << endl
+// 	   << "  of the graph.  The .icoord file will have the suffix \".icoord\" and" << endl
+// 	   << "  each line of the .icoord file will be of the form" << endl
+// 	   << "\tnode_id <tab> x-coord <tab> y-coord" << endl << endl
+// 	   << "Options:" << endl << endl
+// 	   << "\t-s {int>=0} random seed (default value is 0)" << endl
+// 	   << "\t-c {real[0,1]} edge cutting (default 32/40 = .8)" << endl
+// 	   << "\t   (old max was 39/40 = .975)" << endl
+// 	   << "\t-p input parameters from .parms file" << endl
+// 	   << "\t-r {real[0,1]} input coordinates from .real file" << endl
+// 	   << "\t   (hold fixed until fraction of optimization schedule reached)" << endl
+// 	   << "\t-i {int>=0} intermediate output interval (default 0: no output)" << endl
+// 	   << "\t-e output .iedges file (same prefix as .coord file)" << endl << endl;
+ 
+//   #ifdef MUSE_MPI
+//     MPI_Abort ( MPI_COMM_WORLD, 1 );
+//   #else
+//     exit (1);
+//   #endif
+// }
+
+// parse::parse ( int argc, char** argv)
+// {
+//   map<string,string> m;
+
+//   // make sure there is at least one argument  
+//   if ( argc < 2)
+// 	print_syntax ( "not enough arguments!" );
+  
+//   // make sure coord_file ends in ".coord"
+//   parms_file = real_file = sim_file = coord_file = argv[argc-1];
+//   parms_file = parms_file + ".parms";
+//   real_file = real_file + ".real";
+//   sim_file = sim_file + ".int";
+//   coord_file = coord_file + ".icoord";
+  
+//   char error_string[200];
+//   sprintf ( error_string, "%s %d %s", "root file name cannot be longer than", MAX_FILE_NAME-7,
+// 				   "characters.");
+//   if ( coord_file.length() > MAX_FILE_NAME )
+// 	print_syntax ( error_string );
+	
+//   // echo sim_file and coord_file
+//   cout << "Using " << sim_file << " for .int file, and " << coord_file << " for .icoord file." << endl;
+  
+//   // set defaults
+//   rand_seed = 0;
+//   //edge_cut = 32.0/39.0; // (old default)
+//   edge_cut = 32.0/40.0;
+//   int_out = 0;
+//   edges_out = 0;
+//   parms_in = 0;
+//   real_in = -1.0;
+
+//   // now check for optional arguments
+//   string arg;
+//   for( int i = 1; i<argc-1; i++ )
+//   {
+// 	arg = argv[i];
+
+// 	// check for random seed
+//     if ( arg == "-s" )
+// 	{
+// 		i++;
+// 		if ( i >= (argc-1) )
+// 			print_syntax ( "-s flag has no argument." );
+// 		else
+// 		{
+// 			rand_seed = atoi ( argv[i] );
+// 			if ( rand_seed < 0 )
+// 				print_syntax ( "random seed must be >= 0." );
+// 		}
+// 	}
+// 	// check for edge cutting
+// 	else if ( arg == "-c" )
+// 	{
+// 		i++;
+// 		if ( i >= (argc-1) )
+// 			print_syntax ( "-c flag has no argument." );
+// 		else
+// 		{
+// 			edge_cut = atof ( argv[i] );
+// 			if ( (edge_cut < 0) || (edge_cut > 1) )
+// 				print_syntax ( "edge cut must be between 0 and 1." );
+// 		}
+// 	}		
+// 	// check for intermediate output
+// 	else if ( arg == "-i" )
+// 	{
+// 		i++;
+// 		if ( i >= (argc-1) )
+// 			print_syntax ( "-i flag has no argument." );
+// 		else
+// 		{
+// 			int_out = atoi ( argv[i] );
+// 			if ( int_out < 0 )
+// 				print_syntax ( "intermediate output must be >= 0." );
+// 		}
+// 	}
+// 	// check for .real input
+// 	else if ( arg == "-r" )
+// 	{
+// 		i++;
+// 		if ( i >= (argc-1) )
+// 			print_syntax ( "-r flag has no argument." );
+// 		else
+// 		{
+// 			real_in = atof ( argv[i] );
+// 			if ( (real_in < 0) || (real_in > 1) )
+// 				print_syntax ( "real iteration fraction must be from 0 to 1." );
+// 		}
+// 	}
+// 	else if ( arg == "-e" )
+// 		edges_out = 1;
+// 	else if ( arg == "-p" )
+// 		parms_in = 1;
+// 	else
+// 		print_syntax ( "unrecongized option!" );
+//   }
+  
+//   if ( parms_in )
+//     cout << "Using " << parms_file << " for .parms file." << endl;
+	
+//   if ( real_in >= 0 )
+//     cout << "Using " << real_file << " for .real file." << endl;
+	
+//   // echo arguments input or default
+//   cout << "Using random seed = " << rand_seed << endl
+//        << "      edge_cutting = " << edge_cut << endl
+//        << "      intermediate output = " << int_out << endl
+//        << "      output .iedges file = " << edges_out << endl;
+//   if ( real_in >= 0 )
+// 	cout << "      holding .real fixed until iterations = " << real_in << endl;
+
+// }
+
+} // namespace drl
diff --git a/src/drl_parse.h b/src/drl_parse.h
new file mode 100644
index 0000000..73ad538
--- /dev/null
+++ b/src/drl_parse.h
@@ -0,0 +1,70 @@
+/* 
+ * Copyright 2007 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+ * certain rights in this software.
+ * 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are 
+ * met:
+ * 
+ *     * Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Sandia National Laboratories nor the names of 
+ * its contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// The parse class contains the methods necessary to parse
+// the command line, print help, and do error checking
+
+#ifdef MUSE_MPI
+  #include <mpi.h>
+#endif
+
+namespace drl {
+	
+class parse {
+
+public:
+
+    // Methods
+	
+	parse ( int argc, char **argv );
+	~parse () {}
+	
+	// user parameters
+	string sim_file;		// .sim file
+	string coord_file;		// .coord file
+	string parms_file;		// .parms file
+	string real_file;	    // .real file
+	
+	int rand_seed;		// random seed int >= 0
+	float edge_cut;			// edge cutting real [0,1]
+	int int_out;			// intermediate output, int >= 1
+	int edges_out;                  // true if .edges file is requested
+	int parms_in;		    // true if .parms file is to be read
+	float real_in;		    // true if .real file is to be read
+	
+private:
+
+	void print_syntax ( const char *error_string );
+	
+};
+
+} // namespace drl
diff --git a/src/eigen.c b/src/eigen.c
new file mode 100644
index 0000000..04ffc57
--- /dev/null
+++ b/src/eigen.c
@@ -0,0 +1,1453 @@
+/* -*- 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_eigen.h"
+#include "igraph_qsort.h"
+#include "igraph_blas.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+int igraph_i_eigen_arpackfun_to_mat(igraph_arpack_function_t *fun,
+				    int n, void *extra, 
+				    igraph_matrix_t *res) {
+  
+  int i;
+  igraph_vector_t v;
+
+  IGRAPH_CHECK(igraph_matrix_init(res, n, n));
+  IGRAPH_FINALLY(igraph_matrix_destroy, res);
+  IGRAPH_VECTOR_INIT_FINALLY(&v, n);
+  VECTOR(v)[0]=1;
+  IGRAPH_CHECK(fun(/*to=*/ &MATRIX(*res, 0, 0), /*from=*/ VECTOR(v), n, 
+		   extra));
+  for (i=1; i<n; i++) {
+    VECTOR(v)[i-1]=0;
+    VECTOR(v)[i  ]=1;
+    IGRAPH_CHECK(fun(/*to=*/ &MATRIX(*res, 0, i), /*from=*/ VECTOR(v), n, 
+		     extra));
+  }
+  igraph_vector_destroy(&v);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_lm(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  igraph_matrix_t vec1, vec2;
+  igraph_vector_t val1, val2;
+  int n=(int) igraph_matrix_nrow(A);
+  int p1=0, p2=which->howmany-1, pr=0;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&val1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&val2, 0);
+  
+  if (vectors) { 
+    IGRAPH_CHECK(igraph_matrix_init(&vec1, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &vec1);
+    IGRAPH_CHECK(igraph_matrix_init(&vec2, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &vec1);
+  }
+  
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT,
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0,
+				    /*il=*/ 1, /*iu=*/ which->howmany,
+				    /*abstol=*/ 1e-14, &val1, 
+				    vectors ? &vec1 : 0, 
+				    /*support=*/ 0));
+  
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT,	
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0,
+				    /*il=*/ n-which->howmany+1, /*iu=*/ n,
+				    /*abstol=*/ 1e-14, &val2, 
+				    vectors ? &vec2 : 0, 
+				    /*support=*/ 0));
+  
+  if (values) { IGRAPH_CHECK(igraph_vector_resize(values, which->howmany)); }
+  if (vectors) { 
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, n, which->howmany));
+  }
+  
+  while (pr < which->howmany) { 
+    if (p2 < 0 || fabs(VECTOR(val1)[p1]) > fabs(VECTOR(val2)[p2])) { 
+      if (values) { 
+	VECTOR(*values)[pr]=VECTOR(val1)[p1];
+      }
+      if (vectors) {
+	memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec1,0,p1), 
+	       sizeof(igraph_real_t) * (size_t) n);
+      }
+      p1++;
+      pr++;
+    } else {
+      if (values) { 
+	VECTOR(*values)[pr]=VECTOR(val2)[p2];
+      }
+      if (vectors) {
+	memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec2,0,p2), 
+	       sizeof(igraph_real_t) * (size_t) n);
+      }
+      p2--;
+      pr++;
+    }
+  }
+  
+   
+  if (vectors) { 
+    igraph_matrix_destroy(&vec2);
+    igraph_matrix_destroy(&vec1);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  igraph_vector_destroy(&val2);
+  igraph_vector_destroy(&val1);
+  IGRAPH_FINALLY_CLEAN(2);
+    
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_sm(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+  
+  igraph_vector_t val;
+  igraph_matrix_t vec;
+  int i, w=0, n=(int) igraph_matrix_nrow(A);
+  igraph_real_t small;
+  int p1, p2, pr=0;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&val, 0);
+  
+  if (vectors) {
+    IGRAPH_MATRIX_INIT_FINALLY(&vec, 0, 0);
+  }
+  
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_ALL, /*vl=*/ 0, 
+				    /*vu=*/ 0, /*vestimate=*/ 0, 
+				    /*il=*/ 0, /*iu=*/ 0, 
+				    /*abstol=*/ 1e-14, &val, 
+				    vectors ? &vec : 0,
+				    /*support=*/ 0));
+
+  /* Look for smallest value */
+  small=fabs(VECTOR(val)[0]);
+  for (i=1; i<n; i++) {
+    igraph_real_t v=fabs(VECTOR(val)[i]);
+    if (v < small) { 
+      small=v;
+      w=i;
+    }
+  }
+  p1=w-1; p2=w;
+  
+  if (values) { IGRAPH_CHECK(igraph_vector_resize(values, which->howmany)); }
+  if (vectors) { 
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, n, which->howmany));
+  }
+
+  while (pr < which->howmany) {
+    if (p2 == n-1 || fabs(VECTOR(val)[p1]) < fabs(VECTOR(val)[p2])) {
+      if (values) { 
+	VECTOR(*values)[pr]=VECTOR(val)[p1];
+      }
+      if (vectors) {
+	memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec,0,p1), 
+	       sizeof(igraph_real_t) * (size_t) n);
+      }
+      p1--;
+      pr++;
+    } else {
+      if (values) { 
+	VECTOR(*values)[pr]=VECTOR(val)[p2];
+      }
+      if (vectors) {
+	memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec,0,p2), 
+	       sizeof(igraph_real_t) * (size_t) n);
+      }
+      p2++;
+      pr++;
+    }
+  }
+
+  if (vectors) {
+    igraph_matrix_destroy(&vec);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_vector_destroy(&val);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_la(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  /* TODO: ordering? */
+  
+  int n=(int) igraph_matrix_nrow(A);
+  int il=n-which->howmany+1;
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT,
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0,
+				    /*il=*/ il, /*iu=*/ n, 
+				    /*abstol=*/ 1e-14, values, vectors, 
+				    /*support=*/ 0));
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_sa(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  /* TODO: ordering? */
+
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT,
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0,
+				    /*il=*/ 1, /*iu=*/ which->howmany,
+				    /*abstol=*/ 1e-14, values, vectors, 
+				    /*support=*/ 0));
+
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_be(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  /* TODO: ordering? */
+
+  igraph_matrix_t vec1, vec2;
+  igraph_vector_t val1, val2;
+  int n=(int) igraph_matrix_nrow(A);
+  int p1=0, p2=which->howmany/2, pr=0;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&val1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&val2, 0);
+  
+  if (vectors) { 
+    IGRAPH_CHECK(igraph_matrix_init(&vec1, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &vec1);
+    IGRAPH_CHECK(igraph_matrix_init(&vec2, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &vec1);
+  }
+
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT,
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0,
+				    /*il=*/ 1, /*iu=*/ (which->howmany)/2,
+				    /*abstol=*/ 1e-14, &val1, 
+				    vectors ? &vec1 : 0, 
+				    /*support=*/ 0));
+  
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT,	
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0,
+				    /*il=*/ n-(which->howmany)/2, /*iu=*/ n,
+				    /*abstol=*/ 1e-14, &val2, 
+				    vectors ? &vec2 : 0, 
+				    /*support=*/ 0));
+
+  if (values) { IGRAPH_CHECK(igraph_vector_resize(values, which->howmany)); }
+  if (vectors) { 
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, n, which->howmany));
+  }
+
+  while (pr < which->howmany) {
+    if (pr % 2) { 
+      if (values) { 
+	VECTOR(*values)[pr]=VECTOR(val1)[p1];
+      }
+      if (vectors) {
+	memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec1,0,p1), 
+	       sizeof(igraph_real_t) * (size_t) n);
+      }
+      p1++;
+      pr++;
+    } else {
+      if (values) { 
+	VECTOR(*values)[pr]=VECTOR(val2)[p2];
+      }
+      if (vectors) {
+	memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec2,0,p2), 
+	       sizeof(igraph_real_t) * (size_t) n);
+      }
+      p2--;
+      pr++;
+    }
+  }
+  
+  if (vectors) { 
+    igraph_matrix_destroy(&vec2);
+    igraph_matrix_destroy(&vec1);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  igraph_vector_destroy(&val2);
+  igraph_vector_destroy(&val1);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_all(const igraph_matrix_t *A,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_ALL, /*vl=*/ 0, 
+				    /*vu=*/ 0, /*vestimate=*/ 0, 
+				    /*il=*/ 0, /*iu=*/ 0, 
+				    /*abstol=*/ 1e-14, values, vectors, 
+				    /*support=*/ 0));
+
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_iv(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_INTERVAL, 
+				    /*vl=*/ which->vl, /*vu=*/ which->vu, 
+				    /*vestimate=*/ which->vestimate, 
+				    /*il=*/ 0, /*iu=*/ 0, 
+				    /*abstol=*/ 1e-14, values, vectors, 
+				    /*support=*/ 0));
+
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack_sel(const igraph_matrix_t *A,
+			      const igraph_eigen_which_t *which,
+			      igraph_vector_t *values,
+			      igraph_matrix_t *vectors) {
+
+  IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT, 
+				    /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0, 
+				    /*il=*/ which->il, /*iu=*/ which->iu, 
+				    /*abstol=*/ 1e-14, values, vectors, 
+				    /*support=*/ 0));
+
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_lapack(const igraph_matrix_t *A,
+			   const igraph_sparsemat_t *sA,
+			   igraph_arpack_function_t *fun,
+			   int n, void *extra,
+			   const igraph_eigen_which_t *which,
+			   igraph_vector_t *values,
+			   igraph_matrix_t *vectors) {
+
+  const igraph_matrix_t *myA=A;
+  igraph_matrix_t mA;
+
+  /* First we need to create a dense square matrix */
+
+  if (A) {
+    n=(int) igraph_matrix_nrow(A);
+  } else if (sA) {
+    n=(int) igraph_sparsemat_nrow(sA);
+    IGRAPH_CHECK(igraph_matrix_init(&mA, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &mA);
+    IGRAPH_CHECK(igraph_sparsemat_as_matrix(&mA, sA));
+    myA=&mA;
+  } else if (fun) {
+    IGRAPH_CHECK(igraph_i_eigen_arpackfun_to_mat(fun, n, extra, &mA));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &mA);
+    myA=&mA;
+  }
+  
+  switch (which->pos) {
+  case IGRAPH_EIGEN_LM:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_lm(myA, which, 
+							   values, vectors));
+    break;
+  case IGRAPH_EIGEN_SM:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_sm(myA, which, 
+							   values, vectors));
+    break;
+  case IGRAPH_EIGEN_LA:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_la(myA, which, 
+							   values, vectors));
+    break;
+  case IGRAPH_EIGEN_SA:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_sa(myA, which, 
+							   values, vectors));
+    break;
+  case IGRAPH_EIGEN_BE:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_be(myA, which, 
+							   values, vectors));
+    break;
+  case IGRAPH_EIGEN_ALL:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_all(myA,
+							    values,
+							    vectors));
+    break;
+  case IGRAPH_EIGEN_INTERVAL:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_iv(myA, which,
+							   values,
+							   vectors));
+    break;
+  case IGRAPH_EIGEN_SELECT:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack_sel(myA, which,
+							    values,
+							    vectors));
+    break;
+  default:
+    /* This cannot happen */
+    break;
+  }
+  
+  if (!A) { 
+    igraph_matrix_destroy(&mA);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+typedef struct igraph_i_eigen_matrix_sym_arpack_data_t {
+  const igraph_matrix_t *A;
+  const igraph_sparsemat_t *sA;
+} igraph_i_eigen_matrix_sym_arpack_data_t;
+
+int igraph_i_eigen_matrix_sym_arpack_cb(igraph_real_t *to, 
+					const igraph_real_t *from,
+					int n, void *extra) {
+  
+  igraph_i_eigen_matrix_sym_arpack_data_t *data=
+    (igraph_i_eigen_matrix_sym_arpack_data_t *) extra;
+
+  if (data->A) {
+    igraph_blas_dgemv_array(/*transpose=*/ 0, /*alpha=*/ 1.0,
+			    data->A, from, /*beta=*/ 0.0, to);
+  } else { /* data->sA */
+    igraph_vector_t vto, vfrom;
+    igraph_vector_view(&vto, to, n);
+    igraph_vector_view(&vfrom, to, n);
+    igraph_vector_null(&vto);
+    igraph_sparsemat_gaxpy(data->sA, &vfrom, &vto);
+  }
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_arpack_be(const igraph_matrix_t *A, 
+			   const igraph_sparsemat_t *sA, 
+			   igraph_arpack_function_t *fun, 
+			   int n, void *extra,
+			   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_t tmpvalues, tmpvalues2;
+  igraph_matrix_t tmpvectors, tmpvectors2;
+  igraph_i_eigen_matrix_sym_arpack_data_t myextra = { A, sA };  
+  int low=(int) floor(which->howmany/2.0), high=(int) ceil(which->howmany/2.0);
+  int l1, l2, w;
+
+  if (low + high >= n) {
+    IGRAPH_ERROR("Requested too many eigenvalues/vectors", IGRAPH_EINVAL);
+  }
+
+  if (!fun) { 
+    fun=igraph_i_eigen_matrix_sym_arpack_cb;
+    extra=(void*) &myextra;
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&tmpvalues, high);
+  IGRAPH_MATRIX_INIT_FINALLY(&tmpvectors, n, high);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmpvalues2, low);
+  IGRAPH_MATRIX_INIT_FINALLY(&tmpvectors2, n, low);
+
+  options->n=n;
+  options->nev=high;
+  options->ncv= 2*options->nev < n ? 2*options->nev : n;
+  options->which[0]='L'; options->which[1]='A';
+  
+  IGRAPH_CHECK(igraph_arpack_rssolve(fun, extra, options, storage, 
+				     &tmpvalues, &tmpvectors));
+
+  options->nev=low;
+  options->ncv= 2*options->nev < n ? 2*options->nev : n;
+  options->which[0]='S'; options->which[1]='A';
+
+  IGRAPH_CHECK(igraph_arpack_rssolve(fun, extra, options, storage,
+				     &tmpvalues2, &tmpvectors2));
+
+  IGRAPH_CHECK(igraph_vector_resize(values, low+high));
+  IGRAPH_CHECK(igraph_matrix_resize(vectors, n, low+high));
+  
+  l1=0; l2=0; w=0;
+  while (w < which->howmany) {
+    VECTOR(*values)[w] = VECTOR(tmpvalues)[l1];
+    memcpy(&MATRIX(*vectors, 0, w), &MATRIX(tmpvectors, 0, l1), 
+	   (size_t) n * sizeof(igraph_real_t));
+    w++; l1++;
+    if (w < which->howmany) {
+      VECTOR(*values)[w] = VECTOR(tmpvalues2)[l2];
+      memcpy(&MATRIX(*vectors, 0, w), &MATRIX(tmpvectors2, 0, l2), 
+	     (size_t) n * sizeof(igraph_real_t));
+      w++; l2++;
+    }
+  }
+
+  igraph_matrix_destroy(&tmpvectors2);
+  igraph_vector_destroy(&tmpvalues2);
+  igraph_matrix_destroy(&tmpvectors);
+  igraph_vector_destroy(&tmpvalues);
+  IGRAPH_FINALLY_CLEAN(4);
+    
+  return 0;
+}
+
+int igraph_i_eigen_matrix_symmetric_arpack(const igraph_matrix_t *A, 
+			   const igraph_sparsemat_t *sA, 
+			   igraph_arpack_function_t *fun, 
+			   int n, void *extra,
+			   const igraph_eigen_which_t *which, 
+			   igraph_arpack_options_t *options,
+			   igraph_arpack_storage_t *storage,
+			   igraph_vector_t *values, 
+			   igraph_matrix_t *vectors) {
+  
+  /* For ARPACK we need a matrix multiplication operation.
+     This can be done in any format, so everything is fine, 
+     we don't have to convert. */
+
+  igraph_i_eigen_matrix_sym_arpack_data_t myextra = { A, sA };
+
+  if (!options) { 
+    IGRAPH_ERROR("`options' must be given for ARPACK algorithm",
+		 IGRAPH_EINVAL);
+  }
+
+  if (which->pos == IGRAPH_EIGEN_BE) {
+    return igraph_i_eigen_matrix_symmetric_arpack_be(A, sA, fun, n, extra,
+						     which, options, storage,
+						     values, vectors);
+  } else {
+
+    switch (which->pos) {
+    case IGRAPH_EIGEN_LM:
+      options->which[0]='L'; options->which[1]='M';
+      options->nev=which->howmany;
+      break;
+    case IGRAPH_EIGEN_SM:
+      options->which[0]='S'; options->which[1]='M';
+      options->nev=which->howmany;
+      break;
+    case IGRAPH_EIGEN_LA:
+      options->which[0]='L'; options->which[1]='A';
+      options->nev=which->howmany;
+      break;
+    case IGRAPH_EIGEN_SA:
+      options->which[0]='S'; options->which[1]='A';
+      options->nev=which->howmany;
+      break;
+    case IGRAPH_EIGEN_ALL:
+      options->which[0]='L'; options->which[1]='M';
+      options->nev=n;
+      break;
+    case IGRAPH_EIGEN_INTERVAL:
+      IGRAPH_ERROR("Interval of eigenvectors with ARPACK", 
+		   IGRAPH_UNIMPLEMENTED);
+      /* TODO */
+      break;
+    case IGRAPH_EIGEN_SELECT:
+      IGRAPH_ERROR("Selected eigenvalues with ARPACK",
+		   IGRAPH_UNIMPLEMENTED);
+      /* TODO */
+      break;
+    default:
+      /* This cannot happen */
+      break;
+    }
+
+    options->n=n;
+    options->ncv= 2*options->nev < n ? 2*options->nev : n;
+    
+    if (!fun) { 
+      fun=igraph_i_eigen_matrix_sym_arpack_cb;
+      extra=(void*) &myextra;
+    }
+    
+    IGRAPH_CHECK(igraph_arpack_rssolve(fun, extra, options, storage, 
+				       values, vectors));
+    return 0;
+  }
+}
+
+/* Get the eigenvalues and the eigenvectors from the compressed 
+   form. Order them according to the ordering criteria.
+   Comparison functions for the reordering first */
+
+typedef int (*igraph_i_eigen_matrix_lapack_cmp_t)(void*, const void*, 
+						  const void *);
+
+typedef struct igraph_i_eml_cmp_t {
+  const igraph_vector_t *mag, *real, *imag;
+} igraph_i_eml_cmp_t;
+
+/* TODO: these should be defined in some header */
+
+#define EPS        (DBL_EPSILON*100)
+#define LESS(a,b)  ((a) < (b)-EPS)
+#define MORE(a,b)  ((a) > (b)+EPS)
+#define ZERO(a)    ((a) > -EPS && (a) < EPS)
+#define NONZERO(a) ((a) < -EPS || (a) > EPS)
+
+/* Largest magnitude. Ordering is according to 
+   1 Larger magnitude
+   2 Real eigenvalues before complex ones
+   3 Larger real part
+   4 Larger imaginary part */
+
+int igraph_i_eigen_matrix_lapack_cmp_lm(void *extra, const void *a,
+					const void *b) {
+  igraph_i_eml_cmp_t *myextra=(igraph_i_eml_cmp_t *) extra;
+  int *aa=(int*) a, *bb=(int*) b;
+  igraph_real_t a_m=VECTOR(*myextra->mag)[*aa];
+  igraph_real_t b_m=VECTOR(*myextra->mag)[*bb];
+
+  if (LESS(a_m, b_m)) {
+    return 1;
+  } else if (MORE(a_m, b_m)) {
+    return -1;
+  } else {
+    igraph_real_t a_r=VECTOR(*myextra->real)[*aa];
+    igraph_real_t a_i=VECTOR(*myextra->imag)[*aa];
+    igraph_real_t b_r=VECTOR(*myextra->real)[*bb];
+    igraph_real_t b_i=VECTOR(*myextra->imag)[*bb];
+    if (ZERO(a_i)    && NONZERO(b_i))  { return -1; }
+    if (NONZERO(a_i) && ZERO(b_i))     { return  1; }
+    if (MORE(a_r, b_r)) { return -1; }
+    if (LESS(a_r, b_r)) { return  1; }
+    if (MORE(a_i, b_i)) { return -1; }
+    if (LESS(a_i, b_i)) { return  1; }
+  }
+  return 0;
+}
+
+/* Smallest marginude. Ordering is according to
+   1 Magnitude (smaller first)
+   2 Complex eigenvalues before real ones
+   3 Smaller real part
+   4 Smaller imaginary part
+   This ensures that lm has exactly the opposite order to sm */
+
+int igraph_i_eigen_matrix_lapack_cmp_sm(void *extra, const void *a,
+					const void *b) {
+  igraph_i_eml_cmp_t *myextra=(igraph_i_eml_cmp_t *) extra;
+  int *aa=(int*) a, *bb=(int*) b;
+  igraph_real_t a_m=VECTOR(*myextra->mag)[*aa];
+  igraph_real_t b_m=VECTOR(*myextra->mag)[*bb];
+
+  if (MORE(a_m, b_m)) {
+    return 1;
+  } else if (LESS(a_m, b_m)) {
+    return -1;
+  } else {
+    igraph_real_t a_r=VECTOR(*myextra->real)[*aa];
+    igraph_real_t a_i=VECTOR(*myextra->imag)[*aa];
+    igraph_real_t b_r=VECTOR(*myextra->real)[*bb];
+    igraph_real_t b_i=VECTOR(*myextra->imag)[*bb];
+    if (NONZERO(a_i) && ZERO(b_i))    { return -1; }
+    if (ZERO(a_i)    && NONZERO(b_i)) { return  1; }
+    if (LESS(a_r, b_r)) { return -1; }
+    if (MORE(a_r, b_r)) { return  1; }
+    if (LESS(a_i, b_i)) { return -1; }
+    if (MORE(a_i, b_i)) { return  1; }
+  }
+  return 0;
+}  
+
+/* Largest real part. Ordering is according to 
+   1 Larger real part
+   2 Real eigenvalues come before complex ones
+   3 Larger complex part */ 
+
+int igraph_i_eigen_matrix_lapack_cmp_lr(void *extra, const void *a,
+					const void *b) {
+
+  igraph_i_eml_cmp_t *myextra=(igraph_i_eml_cmp_t *) extra;
+  int *aa=(int*) a, *bb=(int*) b;
+  igraph_real_t a_r=VECTOR(*myextra->real)[*aa];
+  igraph_real_t b_r=VECTOR(*myextra->real)[*bb];
+  
+  if (MORE(a_r, b_r)) {
+    return -1;
+  } else if (LESS(a_r, b_r)) {
+    return 1;
+  } else {
+    igraph_real_t a_i=VECTOR(*myextra->imag)[*aa];
+    igraph_real_t b_i=VECTOR(*myextra->imag)[*bb];
+    if (ZERO(a_i) && NONZERO(b_i)) { return -1; }
+    if (NONZERO(a_i) && ZERO(b_i)) { return  1; }
+    if (MORE(a_i, b_i)) { return -1; }
+    if (LESS(a_i, b_i)) { return  1; }    
+  }
+  
+  return 0;
+}
+
+/* Largest real part. Ordering is according to 
+   1 Smaller real part
+   2 Complex eigenvalues come before real ones
+   3 Smaller complex part 
+   This is opposite to LR
+*/ 
+
+int igraph_i_eigen_matrix_lapack_cmp_sr(void *extra, const void *a,
+					const void *b) {
+
+  igraph_i_eml_cmp_t *myextra=(igraph_i_eml_cmp_t *) extra;
+  int *aa=(int*) a, *bb=(int*) b;
+  igraph_real_t a_r=VECTOR(*myextra->real)[*aa];
+  igraph_real_t b_r=VECTOR(*myextra->real)[*bb];
+  
+  if (LESS(a_r, b_r)) {
+    return -1;
+  } else if (MORE(a_r, b_r)) {
+    return 1;
+  } else {
+    igraph_real_t a_i=VECTOR(*myextra->imag)[*aa];
+    igraph_real_t b_i=VECTOR(*myextra->imag)[*bb];
+    if (NONZERO(a_i) && ZERO(b_i)) { return -1; }
+    if (ZERO(a_i) && NONZERO(b_i)) { return  1; }
+    if (LESS(a_i, b_i)) { return -1; }
+    if (MORE(a_i, b_i)) { return  1; }    
+  }
+
+  return 0;
+}
+
+/* Order:
+   1 Larger imaginary part
+   2 Real eigenvalues before complex ones
+   3 Larger real part */
+
+int igraph_i_eigen_matrix_lapack_cmp_li(void *extra, const void *a,
+					const void *b) {
+
+  igraph_i_eml_cmp_t *myextra=(igraph_i_eml_cmp_t *) extra;
+  int *aa=(int*) a, *bb=(int*) b;
+  igraph_real_t a_i=VECTOR(*myextra->imag)[*aa];
+  igraph_real_t b_i=VECTOR(*myextra->imag)[*bb];
+  
+  if (MORE(a_i, b_i)) {
+    return -1;
+  } else if (LESS(a_i, b_i)) {
+    return 1;
+  } else {
+    igraph_real_t a_r=VECTOR(*myextra->real)[*aa];
+    igraph_real_t b_r=VECTOR(*myextra->real)[*bb];
+    if (ZERO(a_i) && NONZERO(b_i)) { return -1; }
+    if (NONZERO(a_i) && ZERO(b_i)) { return  1; }
+    if (MORE(a_r, b_r)) { return -1; }
+    if (LESS(a_r, b_r)) { return  1; }    
+  }
+  
+  return 0;
+}
+
+/* Order:
+   1 Smaller imaginary part
+   2 Complex eigenvalues before real ones
+   3 Smaller real part
+   Order is opposite to LI */
+
+int igraph_i_eigen_matrix_lapack_cmp_si(void *extra, const void *a,
+					const void *b) {
+  
+  igraph_i_eml_cmp_t *myextra=(igraph_i_eml_cmp_t *) extra;
+  int *aa=(int*) a, *bb=(int*) b;
+  igraph_real_t a_i=VECTOR(*myextra->imag)[*aa];
+  igraph_real_t b_i=VECTOR(*myextra->imag)[*bb];
+  
+  if (LESS(a_i, b_i)) {
+    return -1;
+  } else if (MORE(a_i, b_i)) {
+    return 1;
+  } else {
+    igraph_real_t a_r=VECTOR(*myextra->real)[*aa];
+    igraph_real_t b_r=VECTOR(*myextra->real)[*bb];
+    if (NONZERO(a_i) && ZERO(b_i)) { return -1; }
+    if (ZERO(a_i) && NONZERO(b_i)) { return  1; }
+    if (LESS(a_r, b_r)) { return -1; }
+    if (MORE(a_r, b_r)) { return  1; }    
+  }
+  
+  return 0;
+}
+
+#undef EPS
+#undef LESS
+#undef MORE
+#undef ZERO
+#undef NONZERO
+
+#define INITMAG()							\
+  do {									\
+    int i;								\
+    IGRAPH_VECTOR_INIT_FINALLY(&mag, nev);				\
+    hasmag=1;								\
+    for (i=0; i<nev; i++) {						\
+      VECTOR(mag)[i] = VECTOR(*real)[i] * VECTOR(*real)[i] +		\
+	VECTOR(*imag)[i] * VECTOR(*imag)[i];				\
+    }									\
+  } while (0)
+
+int igraph_i_eigen_matrix_lapack_reorder(const igraph_vector_t *real,
+					 const igraph_vector_t *imag,
+					 const igraph_matrix_t *compressed,
+					 const igraph_eigen_which_t *which,
+					 igraph_vector_complex_t *values,
+					 igraph_matrix_complex_t *vectors) {
+  igraph_vector_int_t idx;
+  igraph_vector_t mag;
+  igraph_bool_t hasmag=0;
+  int nev=(int) igraph_vector_size(real);
+  int howmany=0, start=0;
+  int i;  
+  igraph_i_eigen_matrix_lapack_cmp_t cmpfunc=0;
+  igraph_i_eml_cmp_t vextra = { &mag, real, imag };
+  void *extra=&vextra;
+  
+  IGRAPH_CHECK(igraph_vector_int_init(&idx, nev));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &idx);
+
+  switch (which->pos) { 
+  case IGRAPH_EIGEN_LM:
+    INITMAG();
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_lm;
+    howmany=which->howmany;
+    break;
+  case IGRAPH_EIGEN_ALL:
+    INITMAG();
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_sm;
+    howmany=nev;
+    break;
+  case IGRAPH_EIGEN_SM:
+    INITMAG();
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_sm;
+    howmany=which->howmany;
+    break;
+  case IGRAPH_EIGEN_LR:
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_lr;
+    howmany=which->howmany;
+    break;
+  case IGRAPH_EIGEN_SR:
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_sr;
+    howmany=which->howmany;
+    break;
+  case IGRAPH_EIGEN_SELECT:
+    INITMAG();
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_sm;
+    start=which->il-1;
+    howmany=which->iu - which->il + 1;
+    break;
+  case IGRAPH_EIGEN_LI:
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_li;
+    howmany=which->howmany;
+    break;
+  case IGRAPH_EIGEN_SI:
+    cmpfunc=igraph_i_eigen_matrix_lapack_cmp_si;
+    howmany=which->howmany;
+    break;
+  case IGRAPH_EIGEN_INTERVAL:
+  case IGRAPH_EIGEN_BE:
+  default:
+    IGRAPH_ERROR("Unimplemented eigenvalue ordering", IGRAPH_UNIMPLEMENTED);
+    break;
+  }
+  
+  for (i=0; i<nev; i++) {
+    VECTOR(idx)[i] = i;
+  }
+
+  igraph_qsort_r(VECTOR(idx), (size_t) nev, sizeof(VECTOR(idx)[0]), extra, 
+		 cmpfunc);
+
+  if (hasmag) {
+    igraph_vector_destroy(&mag);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (values) {
+    IGRAPH_CHECK(igraph_vector_complex_resize(values, howmany));
+    for (i=0; i<howmany; i++) {
+      int x=VECTOR(idx)[start+i];
+      VECTOR(*values)[i] = igraph_complex(VECTOR(*real)[x], 
+					  VECTOR(*imag)[x]);
+    }
+  }
+
+  if (vectors) {
+    int n=(int) igraph_matrix_nrow(compressed);
+    IGRAPH_CHECK(igraph_matrix_complex_resize(vectors, n, howmany));
+    for (i=0; i<howmany; i++) {
+      int j, x=VECTOR(idx)[start+i];
+      if (VECTOR(*imag)[x] == 0) { 
+	/* real eigenvalue */
+	for (j=0; j<n; j++) {
+	  MATRIX(*vectors, j, i) = igraph_complex(MATRIX(*compressed, j, x),
+						  0.0);
+	}
+      } else {
+	/* complex eigenvalue */
+	int neg=1, co=0;
+	if (VECTOR(*imag)[x] < 0) { neg=-1; co=1; }
+	for (j=0; j<n; j++) {
+	  MATRIX(*vectors, j, i) = 
+	    igraph_complex(MATRIX(*compressed, j, x-co),
+			   neg * MATRIX(*compressed, j, x+1-co));
+	}
+      }
+    }
+  }
+
+  igraph_vector_int_destroy(&idx);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_eigen_matrix_lapack_common(const igraph_matrix_t *A,
+					const igraph_eigen_which_t *which, 
+					igraph_vector_complex_t *values,
+					igraph_matrix_complex_t *vectors) {
+
+  igraph_vector_t valuesreal, valuesimag;
+  igraph_matrix_t vectorsright, *myvectors= vectors ? &vectorsright : 0;
+  int n=(int) igraph_matrix_nrow(A);
+  int info=1;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&valuesreal, n);
+  IGRAPH_VECTOR_INIT_FINALLY(&valuesimag, n);
+  if (vectors) { IGRAPH_MATRIX_INIT_FINALLY(&vectorsright, n, n); }
+  IGRAPH_CHECK(igraph_lapack_dgeev(A, &valuesreal, &valuesimag, 
+				   /*vectorsleft=*/ 0, myvectors, &info));
+
+  IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_reorder(&valuesreal, 
+						    &valuesimag, 
+						    myvectors, which, values,
+						    vectors));
+  
+  if (vectors) { 
+    igraph_matrix_destroy(&vectorsright);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  igraph_vector_destroy(&valuesimag);
+  igraph_vector_destroy(&valuesreal);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+  
+}
+
+int igraph_i_eigen_matrix_lapack_lm(const igraph_matrix_t *A,
+				    const igraph_eigen_which_t *which,
+				    igraph_vector_complex_t *values,
+				    igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack_sm(const igraph_matrix_t *A,
+				    const igraph_eigen_which_t *which,
+				    igraph_vector_complex_t *values,
+				    igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack_lr(const igraph_matrix_t *A,
+				    const igraph_eigen_which_t *which,
+				    igraph_vector_complex_t *values,
+				    igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+
+int igraph_i_eigen_matrix_lapack_sr(const igraph_matrix_t *A,
+				    const igraph_eigen_which_t *which,
+				    igraph_vector_complex_t *values,
+				    igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack_li(const igraph_matrix_t *A,
+				    const igraph_eigen_which_t *which,
+				    igraph_vector_complex_t *values,
+				    igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack_si(const igraph_matrix_t *A,
+				    const igraph_eigen_which_t *which,
+				    igraph_vector_complex_t *values,
+				    igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack_select(const igraph_matrix_t *A,
+					const igraph_eigen_which_t *which,
+					igraph_vector_complex_t *values,
+					igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack_all(const igraph_matrix_t *A,
+				     const igraph_eigen_which_t *which,
+				     igraph_vector_complex_t *values,
+				     igraph_matrix_complex_t *vectors) {
+  return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
+}
+
+int igraph_i_eigen_matrix_lapack(const igraph_matrix_t *A,
+				 const igraph_sparsemat_t *sA,
+				 igraph_arpack_function_t *fun,
+				 int n, void *extra, 
+				 const igraph_eigen_which_t *which,
+				 igraph_vector_complex_t *values,
+				 igraph_matrix_complex_t *vectors) {
+  
+  const igraph_matrix_t *myA=A;
+  igraph_matrix_t mA;
+  
+  /* We need to create a dense square matrix first */
+  
+  if (A) {
+    n=(int) igraph_matrix_nrow(A);
+  } else if (sA) {
+    n=(int) igraph_sparsemat_nrow(sA);
+    IGRAPH_CHECK(igraph_matrix_init(&mA, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &mA);
+    IGRAPH_CHECK(igraph_sparsemat_as_matrix(&mA, sA));
+    myA=&mA;
+  } else if (fun) {
+    IGRAPH_CHECK(igraph_i_eigen_arpackfun_to_mat(fun, n, extra, &mA));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &mA);
+  }
+
+  switch (which->pos) {
+  case IGRAPH_EIGEN_LM:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_lm(myA, which, 
+						 values, vectors));
+    break;
+  case IGRAPH_EIGEN_SM:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_sm(myA, which, 
+						 values, vectors));
+    break;
+  case IGRAPH_EIGEN_LR:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_lr(myA, which, 
+						 values, vectors));
+    break;
+  case IGRAPH_EIGEN_SR:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_sr(myA, which, 
+						 values, vectors));
+    break;
+  case IGRAPH_EIGEN_LI:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_li(myA, which, 
+						 values, vectors));
+    break;
+  case IGRAPH_EIGEN_SI:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_si(myA, which, 
+						 values, vectors));
+    break;
+  case IGRAPH_EIGEN_SELECT:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_select(myA, which, 
+						     values, vectors));
+    break;
+  case IGRAPH_EIGEN_ALL:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack_all(myA, which,
+						  values,
+						  vectors));
+    break;
+  default:
+    /* This cannot happen */
+    break;
+  }
+  
+  if (!A) { 
+    igraph_matrix_destroy(&mA);
+    IGRAPH_FINALLY_CLEAN(1);
+  }  
+  
+  return 0;
+}
+
+int igraph_i_eigen_checks(const igraph_matrix_t *A, 
+			  const igraph_sparsemat_t *sA,
+			  igraph_arpack_function_t *fun, int n) {
+  
+  if ( (A?1:0)+(sA?1:0)+(fun?1:0) != 1) {
+    IGRAPH_ERROR("Exactly one of 'A', 'sA' and 'fun' must be given", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (A) {
+    if (n != igraph_matrix_ncol(A) || n != igraph_matrix_nrow(A)) {
+      IGRAPH_ERROR("Invalid matrix", IGRAPH_NONSQUARE);
+    }
+  } else if (sA) {
+    if (n != igraph_sparsemat_ncol(sA) || n != igraph_sparsemat_nrow(sA)) {
+      IGRAPH_ERROR("Invalid matrix", IGRAPH_NONSQUARE);
+    }
+  }
+
+  return 0;
+}
+					   
+/** 
+ * \function igraph_eigen_matrix_symmetric
+ * 
+ * \example examples/simple/igraph_eigen_matrix_symmetric.c
+ */ 
+
+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) {
+
+  IGRAPH_CHECK(igraph_i_eigen_checks(A, sA, fun, n));
+  
+  if (which->pos != IGRAPH_EIGEN_LM && 
+      which->pos != IGRAPH_EIGEN_SM && 
+      which->pos != IGRAPH_EIGEN_LA && 
+      which->pos != IGRAPH_EIGEN_SA && 
+      which->pos != IGRAPH_EIGEN_BE && 
+      which->pos != IGRAPH_EIGEN_ALL && 
+      which->pos != IGRAPH_EIGEN_INTERVAL && 
+      which->pos != IGRAPH_EIGEN_SELECT) {
+    IGRAPH_ERROR("Invalid 'pos' position in 'which'", IGRAPH_EINVAL);
+  }
+
+  switch (algorithm) {
+  case IGRAPH_EIGEN_AUTO:
+    if (which->howmany==n || n < 100) {
+      IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack(A, sA, fun, n,
+							  extra, which, 
+							  values, vectors));
+    } else {
+      IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_arpack(A, sA, fun, n, 
+							  extra, which, 
+							  options, storage,
+							  values, vectors));
+    }
+    break;
+  case IGRAPH_EIGEN_LAPACK:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_lapack(A, sA, fun, n ,extra,
+							which, values, 
+							vectors));
+    break;
+  case IGRAPH_EIGEN_ARPACK:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_symmetric_arpack(A, sA, fun, n, extra,
+							which, options, 
+							storage,
+							values, vectors));
+    break;
+  default:
+    IGRAPH_ERROR("Unknown 'algorithm'", IGRAPH_EINVAL);
+  }
+    
+  return 0;
+}
+
+/** 
+ * \function igraph_eigen_matrix
+ * 
+ */ 
+
+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) {
+
+  IGRAPH_CHECK(igraph_i_eigen_checks(A, sA, fun, n));
+  
+  if (which->pos != IGRAPH_EIGEN_LM && 
+      which->pos != IGRAPH_EIGEN_SM && 
+      which->pos != IGRAPH_EIGEN_LR && 
+      which->pos != IGRAPH_EIGEN_SR && 
+      which->pos != IGRAPH_EIGEN_LI && 
+      which->pos != IGRAPH_EIGEN_SI &&
+      which->pos != IGRAPH_EIGEN_SELECT &&
+      which->pos != IGRAPH_EIGEN_ALL) {
+    IGRAPH_ERROR("Invalid 'pos' position in 'which'", IGRAPH_EINVAL);
+  }
+
+  switch (algorithm) {
+  case IGRAPH_EIGEN_AUTO:
+    IGRAPH_ERROR("'AUTO' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_LAPACK:
+    IGRAPH_CHECK(igraph_i_eigen_matrix_lapack(A, sA, fun, n, extra, which,
+					      values, vectors));
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_ARPACK:
+    IGRAPH_ERROR("'ARPACK' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_COMP_AUTO:
+    IGRAPH_ERROR("'COMP_AUTO' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_COMP_LAPACK:
+    IGRAPH_ERROR("'COMP_LAPACK' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_COMP_ARPACK:
+    IGRAPH_ERROR("'COMP_ARPACK' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  default:
+    IGRAPH_ERROR("Unknown `algorithm'", IGRAPH_EINVAL);
+  }
+
+  return 0;
+}
+
+int igraph_i_eigen_adjacency_arpack_sym_cb(igraph_real_t *to,
+					   const igraph_real_t *from,
+					   int n, void *extra) {
+  igraph_adjlist_t *adjlist = (igraph_adjlist_t *) extra;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(adjlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int nei = VECTOR(*neis)[j];
+      to[i] += from[nei];
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_eigen_adjacency_arpack(const igraph_t *graph, 
+				    const igraph_eigen_which_t *which,
+				    igraph_arpack_options_t *options,
+				    igraph_arpack_storage_t* storage,
+				    igraph_vector_t *values,
+				    igraph_matrix_t *vectors,
+				    igraph_vector_complex_t *cmplxvalues,
+				    igraph_matrix_complex_t *cmplxvectors){
+
+	igraph_adjlist_t adjlist;
+	void *extra=(void*) &adjlist;
+	int n=igraph_vcount(graph);
+
+  if (!options) { 
+    IGRAPH_ERROR("`options' must be given for ARPACK algorithm",
+		 IGRAPH_EINVAL);
+  }
+	
+  if (igraph_is_directed(graph)) {
+    IGRAPH_ERROR("ARPACK adjacency eigensolver not implemented for "
+		 "directed graphs", IGRAPH_UNIMPLEMENTED);
+  }
+  if (which->pos == IGRAPH_EIGEN_INTERVAL) {
+    IGRAPH_ERROR("ARPACK adjacency eigensolver does not implement "
+		 "`INTERNAL' eigenvalues", IGRAPH_UNIMPLEMENTED);
+  }
+  if (which->pos == IGRAPH_EIGEN_SELECT) {
+    IGRAPH_ERROR("ARPACK adjacency eigensolver does not implement "
+		 "`SELECT' eigenvalues", IGRAPH_UNIMPLEMENTED);
+  }
+  if (which->pos == IGRAPH_EIGEN_ALL) {
+    IGRAPH_ERROR("ARPACK adjacency eigensolver does not implement "
+		 "`ALL' eigenvalues", IGRAPH_UNIMPLEMENTED);
+  }
+
+  switch (which->pos) {
+  case IGRAPH_EIGEN_LM:
+    options->which[0]='L'; options->which[1]='M';
+    options->nev=which->howmany;
+    break;
+  case IGRAPH_EIGEN_SM:
+    options->which[0]='S'; options->which[1]='M';
+    options->nev=which->howmany;
+    break;
+  case IGRAPH_EIGEN_LA:
+    options->which[0]='L'; options->which[1]='A';
+    options->nev=which->howmany;
+    break;
+  case IGRAPH_EIGEN_SA:
+    options->which[0]='S'; options->which[1]='A';
+    options->nev=which->howmany;
+    break;
+  case IGRAPH_EIGEN_ALL:
+    options->which[0]='L'; options->which[1]='M';
+    options->nev=n;
+    break;
+  case IGRAPH_EIGEN_BE:
+    IGRAPH_ERROR("Eigenvectors from both ends with ARPACK",
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_INTERVAL:
+    IGRAPH_ERROR("Interval of eigenvectors with ARPACK",
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_SELECT:
+    IGRAPH_ERROR("Selected eigenvalues with ARPACK",
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  default:
+    /* This cannot happen */
+    break;
+  }
+
+  options->n=n;
+  options->ncv= 2*options->nev < n ? 2*options->nev : n;
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+  IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigen_adjacency_arpack_sym_cb,
+				     extra, options, storage, values, vectors));
+
+  igraph_adjlist_destroy(&adjlist);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/** 
+ * \function igraph_eigen_adjacency
+ *
+ */ 
+
+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) {
+
+  if (which->pos != IGRAPH_EIGEN_LM && 
+      which->pos != IGRAPH_EIGEN_SM && 
+      which->pos != IGRAPH_EIGEN_LA && 
+      which->pos != IGRAPH_EIGEN_SA && 
+      which->pos != IGRAPH_EIGEN_BE && 
+      which->pos != IGRAPH_EIGEN_SELECT &&
+      which->pos != IGRAPH_EIGEN_INTERVAL &&
+      which->pos != IGRAPH_EIGEN_ALL) {
+    IGRAPH_ERROR("Invalid 'pos' position in 'which'", IGRAPH_EINVAL);
+  }
+
+  switch (algorithm) {
+  case IGRAPH_EIGEN_AUTO:
+    IGRAPH_ERROR("'AUTO' algorithm not implemented yet", 
+								 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_LAPACK:
+    IGRAPH_ERROR("'LAPACK' algorithm not implemented yet",  
+								 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_ARPACK:
+		IGRAPH_CHECK(igraph_i_eigen_adjacency_arpack(graph, which, options,
+																								 storage, values, vectors,
+																								 cmplxvalues,
+																								 cmplxvectors));
+    break;
+  case IGRAPH_EIGEN_COMP_AUTO:
+    IGRAPH_ERROR("'COMP_AUTO' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_COMP_LAPACK:
+    IGRAPH_ERROR("'COMP_LAPACK' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  case IGRAPH_EIGEN_COMP_ARPACK:
+    IGRAPH_ERROR("'COMP_ARPACK' algorithm not implemented yet", 
+		 IGRAPH_UNIMPLEMENTED);
+    /* TODO */
+    break;
+  default:
+    IGRAPH_ERROR("Unknown `algorithm'", IGRAPH_EINVAL);
+  }
+	
+	
+  return 0;
+}
+
+/** 
+ * \function igraph_eigen_laplacian
+ *
+ */ 
+
+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) {
+
+  IGRAPH_ERROR("'igraph_eigen_laplacian'", IGRAPH_UNIMPLEMENTED);
+  /* TODO */
+  return 0;
+}
diff --git a/src/evolver_cit.c b/src/evolver_cit.c
new file mode 100644
index 0000000..4b30e4b
--- /dev/null
+++ b/src/evolver_cit.c
@@ -0,0 +1,179 @@
+/* -*- 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
new file mode 100644
index 0000000..5f367fd
--- /dev/null
+++ b/src/f2c.h
@@ -0,0 +1,230 @@
+/* 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/abort_.c b/src/f2c/abort_.c
new file mode 100644
index 0000000..92c841a
--- /dev/null
+++ b/src/f2c/abort_.c
@@ -0,0 +1,22 @@
+#include "stdio.h"
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern VOID sig_die();
+
+int abort_()
+#else
+extern void sig_die(const char*,int);
+
+int abort_(void)
+#endif
+{
+sig_die("Fortran abort routine called", 1);
+return 0;	/* not reached */
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/arithchk.c b/src/f2c/arithchk.c
new file mode 100644
index 0000000..0522d96
--- /dev/null
+++ b/src/f2c/arithchk.c
@@ -0,0 +1,245 @@
+/****************************************************************
+Copyright (C) 1997, 1998, 2000 Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+/* Try to deduce arith.h from arithmetic properties. */
+
+#include <stdio.h>
+#include <math.h>
+#include <errno.h>
+
+#ifdef NO_FPINIT
+#define fpinit_ASL()
+#else
+#ifndef KR_headers
+extern
+#ifdef __cplusplus
+	"C"
+#endif
+	void fpinit_ASL(void);
+#endif /*KR_headers*/
+#endif /*NO_FPINIT*/
+
+ static int dalign;
+ typedef struct
+Akind {
+	char *name;
+	int   kind;
+	} Akind;
+
+ static Akind
+IEEE_8087	= { "IEEE_8087", 1 },
+IEEE_MC68k	= { "IEEE_MC68k", 2 },
+IBM		= { "IBM", 3 },
+VAX		= { "VAX", 4 },
+CRAY		= { "CRAY", 5};
+
+ static double t_nan;
+
+ static Akind *
+Lcheck(void)
+{
+	union {
+		double d;
+		long L[2];
+		} u;
+	struct {
+		double d;
+		long L;
+		} x[2];
+
+	if (sizeof(x) > 2*(sizeof(double) + sizeof(long)))
+		dalign = 1;
+	u.L[0] = u.L[1] = 0;
+	u.d = 1e13;
+	if (u.L[0] == 1117925532 && u.L[1] == -448790528)
+		return &IEEE_MC68k;
+	if (u.L[1] == 1117925532 && u.L[0] == -448790528)
+		return &IEEE_8087;
+	if (u.L[0] == -2065213935 && u.L[1] == 10752)
+		return &VAX;
+	if (u.L[0] == 1267827943 && u.L[1] == 704643072)
+		return &IBM;
+	return 0;
+	}
+
+ static Akind *
+icheck(void)
+{
+	union {
+		double d;
+		int L[2];
+		} u;
+	struct {
+		double d;
+		int L;
+		} x[2];
+
+	if (sizeof(x) > 2*(sizeof(double) + sizeof(int)))
+		dalign = 1;
+	u.L[0] = u.L[1] = 0;
+	u.d = 1e13;
+	if (u.L[0] == 1117925532 && u.L[1] == -448790528)
+		return &IEEE_MC68k;
+	if (u.L[1] == 1117925532 && u.L[0] == -448790528)
+		return &IEEE_8087;
+	if (u.L[0] == -2065213935 && u.L[1] == 10752)
+		return &VAX;
+	if (u.L[0] == 1267827943 && u.L[1] == 704643072)
+		return &IBM;
+	return 0;
+	}
+
+char *emptyfmt = "";	/* avoid possible warning message with printf("") */
+
+ static Akind *
+ccheck(void)
+{
+	union {
+		double d;
+		long L;
+		} u;
+	long Cray1;
+
+	/* Cray1 = 4617762693716115456 -- without overflow on non-Crays */
+	Cray1 = printf(emptyfmt) < 0 ? 0 : 4617762;
+	if (printf(emptyfmt, Cray1) >= 0)
+		Cray1 = 1000000*Cray1 + 693716;
+	if (printf(emptyfmt, Cray1) >= 0)
+		Cray1 = 1000000*Cray1 + 115456;
+	u.d = 1e13;
+	if (u.L == Cray1)
+		return &CRAY;
+	return 0;
+	}
+
+ static int
+fzcheck(void)
+{
+	double a, b;
+	int i;
+
+	a = 1.;
+	b = .1;
+	for(i = 155;; b *= b, i >>= 1) {
+		if (i & 1) {
+			a *= b;
+			if (i == 1)
+				break;
+			}
+		}
+	b = a * a;
+	return b == 0.;
+	}
+
+ static int
+need_nancheck(void)
+{
+	double t;
+
+	errno = 0;
+	t = log(t_nan);
+	if (errno == 0)
+		return 1;
+	errno = 0;
+	t = sqrt(t_nan);
+	return errno == 0;
+	}
+
+ void
+get_nanbits(unsigned int *b, int k)
+{
+	union { double d; unsigned int z[2]; } u, u1, u2;
+
+	k = 2 - k;
+	u1.z[k] = u2.z[k] = 0x7ff00000;
+	u1.z[1-k] = u2.z[1-k] = 0;
+	u.d = u1.d - u2.d;	/* Infinity - Infinity */
+	b[0] = u.z[0];
+	b[1] = u.z[1];
+	}
+
+ int
+main(void)
+{
+	FILE *f;
+	Akind *a = 0;
+	int Ldef = 0;
+	unsigned int nanbits[2];
+
+	fpinit_ASL();
+#ifdef WRITE_ARITH_H	/* for Symantec's buggy "make" */
+	f = fopen("arith.h", "w");
+	if (!f) {
+		printf("Cannot open arith.h\n");
+		return 1;
+		}
+#else
+	f = stdout;
+#endif
+
+	if (sizeof(double) == 2*sizeof(long))
+		a = Lcheck();
+	else if (sizeof(double) == 2*sizeof(int)) {
+		Ldef = 1;
+		a = icheck();
+		}
+	else if (sizeof(double) == sizeof(long))
+		a = ccheck();
+	if (a) {
+		fprintf(f, "#define %s\n#define Arith_Kind_ASL %d\n",
+			a->name, a->kind);
+		if (Ldef)
+			fprintf(f, "#define Long int\n#define Intcast (int)(long)\n");
+		if (dalign)
+			fprintf(f, "#define Double_Align\n");
+		if (sizeof(char*) == 8)
+			fprintf(f, "#define X64_bit_pointers\n");
+#ifndef NO_LONG_LONG
+		if (sizeof(long long) < 8)
+#endif
+			fprintf(f, "#define NO_LONG_LONG\n");
+		if (a->kind <= 2) {
+			if (fzcheck())
+				fprintf(f, "#define Sudden_Underflow\n");
+			t_nan = -a->kind;
+			if (need_nancheck())
+				fprintf(f, "#define NANCHECK\n");
+			if (sizeof(double) == 2*sizeof(unsigned int)) {
+				get_nanbits(nanbits, a->kind);
+				fprintf(f, "#define QNaN0 0x%x\n", nanbits[0]);
+				fprintf(f, "#define QNaN1 0x%x\n", nanbits[1]);
+				}
+			}
+		return 0;
+		}
+	fprintf(f, "/* Unknown arithmetic */\n");
+	return 1;
+	}
+
+#ifdef __sun
+#ifdef __i386
+/* kludge for Intel Solaris */
+void fpsetprec(int x) { }
+#endif
+#endif
diff --git a/src/f2c/backspac.c b/src/f2c/backspac.c
new file mode 100644
index 0000000..908a618
--- /dev/null
+++ b/src/f2c/backspac.c
@@ -0,0 +1,76 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef KR_headers
+integer f_back(a) alist *a;
+#else
+integer f_back(alist *a)
+#endif
+{	unit *b;
+	OFF_T v, w, x, y, z;
+	uiolen n;
+	FILE *f;
+
+	f__curunit = b = &f__units[a->aunit];	/* curunit for error messages */
+	if(a->aunit >= MXUNIT || a->aunit < 0)
+		err(a->aerr,101,"backspace")
+	if(b->useek==0) err(a->aerr,106,"backspace")
+	if(b->ufd == NULL) {
+		fk_open(1, 1, a->aunit);
+		return(0);
+		}
+	if(b->uend==1)
+	{	b->uend=0;
+		return(0);
+	}
+	if(b->uwrt) {
+		t_runc(a);
+		if (f__nowreading(b))
+			err(a->aerr,errno,"backspace")
+		}
+	f = b->ufd;	/* may have changed in t_runc() */
+	if(b->url>0)
+	{
+		x=FTELL(f);
+		y = x % b->url;
+		if(y == 0) x--;
+		x /= b->url;
+		x *= b->url;
+		(void) FSEEK(f,x,SEEK_SET);
+		return(0);
+	}
+
+	if(b->ufmt==0)
+	{	FSEEK(f,-(OFF_T)sizeof(uiolen),SEEK_CUR);
+		fread((char *)&n,sizeof(uiolen),1,f);
+		FSEEK(f,-(OFF_T)n-2*sizeof(uiolen),SEEK_CUR);
+		return(0);
+	}
+	w = x = FTELL(f);
+	z = 0;
+ loop:
+	while(x) {
+		x -= x < 64 ? x : 64;
+		FSEEK(f,x,SEEK_SET);
+		for(y = x; y < w; y++) {
+			if (getc(f) != '\n')
+				continue;
+			v = FTELL(f);
+			if (v == w) {
+				if (z)
+					goto break2;
+				goto loop;
+				}
+			z = v;
+			}
+		err(a->aerr,(EOF),"backspace")
+		}
+ break2:
+	FSEEK(f, z, SEEK_SET);
+	return 0;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_abs.c b/src/f2c/c_abs.c
new file mode 100644
index 0000000..11e3354
--- /dev/null
+++ b/src/f2c/c_abs.c
@@ -0,0 +1,20 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern double f__cabs();
+
+double c_abs(z) f2c_complex *z;
+#else
+extern double f__cabs(double, double);
+
+double c_abs(f2c_complex *z)
+#endif
+{
+return( f__cabs( z->r, z->i ) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_cos.c b/src/f2c/c_cos.c
new file mode 100644
index 0000000..0cd9fdc
--- /dev/null
+++ b/src/f2c/c_cos.c
@@ -0,0 +1,23 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+extern double sin(), cos(), sinh(), cosh();
+
+VOID c_cos(r, z) f2c_complex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void c_cos(f2c_complex *r, f2c_complex *z)
+#endif
+{
+	double zi = z->i, zr = z->r;
+	r->r =   cos(zr) * cosh(zi);
+	r->i = - sin(zr) * sinh(zi);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_div.c b/src/f2c/c_div.c
new file mode 100644
index 0000000..421a72c
--- /dev/null
+++ b/src/f2c/c_div.c
@@ -0,0 +1,53 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern VOID sig_die();
+VOID c_div(c, a, b)
+f2c_complex *a, *b, *c;
+#else
+extern void sig_die(const char*,int);
+void c_div(f2c_complex *c, f2c_complex *a, f2c_complex *b)
+#endif
+{
+	double ratio, den;
+	double abr, abi, cr;
+
+	if( (abr = b->r) < 0.)
+		abr = - abr;
+	if( (abi = b->i) < 0.)
+		abi = - abi;
+	if( abr <= abi )
+		{
+		if(abi == 0) {
+#ifdef IEEE_COMPLEX_DIVIDE
+			float af, bf;
+			af = bf = abr;
+			if (a->i != 0 || a->r != 0)
+				af = 1.;
+			c->i = c->r = af / bf;
+			return;
+#else
+			sig_die("complex division by zero", 1);
+#endif
+			}
+		ratio = (double)b->r / b->i ;
+		den = b->i * (1 + ratio*ratio);
+		cr = (a->r*ratio + a->i) / den;
+		c->i = (a->i*ratio - a->r) / den;
+		}
+
+	else
+		{
+		ratio = (double)b->i / b->r ;
+		den = b->r * (1 + ratio*ratio);
+		cr = (a->r + a->i*ratio) / den;
+		c->i = (a->i - a->r*ratio) / den;
+		}
+	c->r = cr;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_exp.c b/src/f2c/c_exp.c
new file mode 100644
index 0000000..e795196
--- /dev/null
+++ b/src/f2c/c_exp.c
@@ -0,0 +1,25 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+extern double exp(), cos(), sin();
+
+ VOID c_exp(r, z) f2c_complex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void c_exp(f2c_complex *r, f2c_complex *z)
+#endif
+{
+	double expx, zi = z->i;
+
+	expx = exp(z->r);
+	r->r = expx * cos(zi);
+	r->i = expx * sin(zi);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_log.c b/src/f2c/c_log.c
new file mode 100644
index 0000000..118fcee
--- /dev/null
+++ b/src/f2c/c_log.c
@@ -0,0 +1,23 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+extern double log(), f__cabs(), atan2();
+VOID c_log(r, z) f2c_complex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern double f__cabs(double, double);
+
+void c_log(f2c_complex *r, f2c_complex *z)
+#endif
+{
+	double zi, zr;
+	r->i = atan2(zi = z->i, zr = z->r);
+	r->r = log( f__cabs(zr, zi) );
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_sin.c b/src/f2c/c_sin.c
new file mode 100644
index 0000000..f0ef0b4
--- /dev/null
+++ b/src/f2c/c_sin.c
@@ -0,0 +1,23 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+extern double sin(), cos(), sinh(), cosh();
+
+VOID c_sin(r, z) f2c_complex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void c_sin(f2c_complex *r, f2c_complex *z)
+#endif
+{
+	double zi = z->i, zr = z->r;
+	r->r = sin(zr) * cosh(zi);
+	r->i = cos(zr) * sinh(zi);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/c_sqrt.c b/src/f2c/c_sqrt.c
new file mode 100644
index 0000000..b07f5e7
--- /dev/null
+++ b/src/f2c/c_sqrt.c
@@ -0,0 +1,41 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+extern double sqrt(), f__cabs();
+
+VOID c_sqrt(r, z) f2c_complex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern double f__cabs(double, double);
+
+void c_sqrt(f2c_complex *r, f2c_complex *z)
+#endif
+{
+	double mag, t;
+	double zi = z->i, zr = z->r;
+
+	if( (mag = f__cabs(zr, zi)) == 0.)
+		r->r = r->i = 0.;
+	else if(zr > 0)
+		{
+		r->r = t = sqrt(0.5 * (mag + zr) );
+		t = zi / t;
+		r->i = 0.5 * t;
+		}
+	else
+		{
+		t = sqrt(0.5 * (mag - zr) );
+		if(zi < 0)
+			t = -t;
+		r->i = t;
+		t = zi / t;
+		r->r = 0.5 * t;
+		}
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/cabs.c b/src/f2c/cabs.c
new file mode 100644
index 0000000..84750d5
--- /dev/null
+++ b/src/f2c/cabs.c
@@ -0,0 +1,33 @@
+#ifdef KR_headers
+extern double sqrt();
+double f__cabs(real, imag) double real, imag;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double f__cabs(double real, double imag)
+#endif
+{
+double temp;
+
+if(real < 0)
+	real = -real;
+if(imag < 0)
+	imag = -imag;
+if(imag > real){
+	temp = real;
+	real = imag;
+	imag = temp;
+}
+if((real+imag) == real)
+	return(real);
+
+temp = imag/real;
+temp = real*sqrt(1.0 + temp*temp);  /*overflow!!*/
+return(temp);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/close.c b/src/f2c/close.c
new file mode 100644
index 0000000..e958c71
--- /dev/null
+++ b/src/f2c/close.c
@@ -0,0 +1,101 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef KR_headers
+integer f_clos(a) cllist *a;
+#else
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#ifdef NON_UNIX_STDIO
+#ifndef unlink
+#define unlink remove
+#endif
+#else
+#ifdef MSDOS
+#include "io.h"
+#else
+#ifdef __cplusplus
+extern "C" int unlink(const char*);
+#else
+extern int unlink(const char*);
+#endif
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+integer f_clos(cllist *a)
+#endif
+{	unit *b;
+
+	if(a->cunit >= MXUNIT) return(0);
+	b= &f__units[a->cunit];
+	if(b->ufd==NULL)
+		goto done;
+	if (b->uscrtch == 1)
+		goto Delete;
+	if (!a->csta)
+		goto Keep;
+	switch(*a->csta) {
+		default:
+	 	Keep:
+		case 'k':
+		case 'K':
+			if(b->uwrt == 1)
+				t_runc((alist *)a);
+			if(b->ufnm) {
+				fclose(b->ufd);
+				free(b->ufnm);
+				}
+			break;
+		case 'd':
+		case 'D':
+		Delete:
+			fclose(b->ufd);
+			if(b->ufnm) {
+				unlink(b->ufnm); /*SYSDEP*/
+				free(b->ufnm);
+				}
+		}
+	b->ufd=NULL;
+ done:
+	b->uend=0;
+	b->ufnm=NULL;
+	return(0);
+	}
+ void
+#ifdef KR_headers
+f_exit()
+#else
+f_exit(void)
+#endif
+{	int i;
+	static cllist xx;
+	if (!xx.cerr) {
+		xx.cerr=1;
+		xx.csta=NULL;
+		for(i=0;i<MXUNIT;i++)
+		{
+			xx.cunit=i;
+			(void) f_clos(&xx);
+		}
+	}
+}
+ int
+#ifdef KR_headers
+flush_()
+#else
+flush_(void)
+#endif
+{	int i;
+	for(i=0;i<MXUNIT;i++)
+		if(f__units[i].ufd != NULL && f__units[i].uwrt)
+			fflush(f__units[i].ufd);
+return 0;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/ctype.c b/src/f2c/ctype.c
new file mode 100644
index 0000000..96bdf1c
--- /dev/null
+++ b/src/f2c/ctype.c
@@ -0,0 +1,2 @@
+#define My_ctype_DEF
+#include "ctype.h"
diff --git a/src/f2c/d_abs.c b/src/f2c/d_abs.c
new file mode 100644
index 0000000..2f7a153
--- /dev/null
+++ b/src/f2c/d_abs.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double d_abs(x) doublereal *x;
+#else
+double d_abs(doublereal *x)
+#endif
+{
+if(*x >= 0)
+	return(*x);
+return(- *x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_acos.c b/src/f2c/d_acos.c
new file mode 100644
index 0000000..69005b5
--- /dev/null
+++ b/src/f2c/d_acos.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double acos();
+double d_acos(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_acos(doublereal *x)
+#endif
+{
+return( acos(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_asin.c b/src/f2c/d_asin.c
new file mode 100644
index 0000000..d5196ab
--- /dev/null
+++ b/src/f2c/d_asin.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double asin();
+double d_asin(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_asin(doublereal *x)
+#endif
+{
+return( asin(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_atan.c b/src/f2c/d_atan.c
new file mode 100644
index 0000000..d8856f8
--- /dev/null
+++ b/src/f2c/d_atan.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double atan();
+double d_atan(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_atan(doublereal *x)
+#endif
+{
+return( atan(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_atn2.c b/src/f2c/d_atn2.c
new file mode 100644
index 0000000..5611385
--- /dev/null
+++ b/src/f2c/d_atn2.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double atan2();
+double d_atn2(x,y) doublereal *x, *y;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_atn2(doublereal *x, doublereal *y)
+#endif
+{
+return( atan2(*x,*y) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_cnjg.c b/src/f2c/d_cnjg.c
new file mode 100644
index 0000000..38471d9
--- /dev/null
+++ b/src/f2c/d_cnjg.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ VOID
+#ifdef KR_headers
+d_cnjg(r, z) doublecomplex *r, *z;
+#else
+d_cnjg(doublecomplex *r, doublecomplex *z)
+#endif
+{
+	doublereal zi = z->i;
+	r->r = z->r;
+	r->i = -zi;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_cos.c b/src/f2c/d_cos.c
new file mode 100644
index 0000000..12def9a
--- /dev/null
+++ b/src/f2c/d_cos.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double cos();
+double d_cos(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_cos(doublereal *x)
+#endif
+{
+return( cos(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_cosh.c b/src/f2c/d_cosh.c
new file mode 100644
index 0000000..9214c7a
--- /dev/null
+++ b/src/f2c/d_cosh.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double cosh();
+double d_cosh(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_cosh(doublereal *x)
+#endif
+{
+return( cosh(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_dim.c b/src/f2c/d_dim.c
new file mode 100644
index 0000000..627ddb6
--- /dev/null
+++ b/src/f2c/d_dim.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double d_dim(a,b) doublereal *a, *b;
+#else
+double d_dim(doublereal *a, doublereal *b)
+#endif
+{
+return( *a > *b ? *a - *b : 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_exp.c b/src/f2c/d_exp.c
new file mode 100644
index 0000000..e9ab5d4
--- /dev/null
+++ b/src/f2c/d_exp.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double exp();
+double d_exp(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_exp(doublereal *x)
+#endif
+{
+return( exp(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_imag.c b/src/f2c/d_imag.c
new file mode 100644
index 0000000..d17b9dd
--- /dev/null
+++ b/src/f2c/d_imag.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double d_imag(z) doublecomplex *z;
+#else
+double d_imag(doublecomplex *z)
+#endif
+{
+return(z->i);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_int.c b/src/f2c/d_int.c
new file mode 100644
index 0000000..6da4ce3
--- /dev/null
+++ b/src/f2c/d_int.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+double d_int(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_int(doublereal *x)
+#endif
+{
+return( (*x>0) ? floor(*x) : -floor(- *x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_lg10.c b/src/f2c/d_lg10.c
new file mode 100644
index 0000000..664c19d
--- /dev/null
+++ b/src/f2c/d_lg10.c
@@ -0,0 +1,21 @@
+#include "f2c.h"
+
+#define log10e 0.43429448190325182765
+
+#ifdef KR_headers
+double log();
+double d_lg10(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_lg10(doublereal *x)
+#endif
+{
+return( log10e * log(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_log.c b/src/f2c/d_log.c
new file mode 100644
index 0000000..e74be02
--- /dev/null
+++ b/src/f2c/d_log.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double log();
+double d_log(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_log(doublereal *x)
+#endif
+{
+return( log(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_mod.c b/src/f2c/d_mod.c
new file mode 100644
index 0000000..3766d9f
--- /dev/null
+++ b/src/f2c/d_mod.c
@@ -0,0 +1,46 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+#ifdef IEEE_drem
+double drem();
+#else
+double floor();
+#endif
+double d_mod(x,y) doublereal *x, *y;
+#else
+#ifdef IEEE_drem
+double drem(double, double);
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+double d_mod(doublereal *x, doublereal *y)
+#endif
+{
+#ifdef IEEE_drem
+	double xa, ya, z;
+	if ((ya = *y) < 0.)
+		ya = -ya;
+	z = drem(xa = *x, ya);
+	if (xa > 0) {
+		if (z < 0)
+			z += ya;
+		}
+	else if (z > 0)
+		z -= ya;
+	return z;
+#else
+	double quotient;
+	if( (quotient = *x / *y) >= 0)
+		quotient = floor(quotient);
+	else
+		quotient = -floor(-quotient);
+	return(*x - (*y) * quotient );
+#endif
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_nint.c b/src/f2c/d_nint.c
new file mode 100644
index 0000000..66f2dd0
--- /dev/null
+++ b/src/f2c/d_nint.c
@@ -0,0 +1,20 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+double d_nint(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_nint(doublereal *x)
+#endif
+{
+return( (*x)>=0 ?
+	floor(*x + .5) : -floor(.5 - *x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_prod.c b/src/f2c/d_prod.c
new file mode 100644
index 0000000..f9f348b
--- /dev/null
+++ b/src/f2c/d_prod.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double d_prod(x,y) real *x, *y;
+#else
+double d_prod(real *x, real *y)
+#endif
+{
+return( (*x) * (*y) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_sign.c b/src/f2c/d_sign.c
new file mode 100644
index 0000000..d06e0d1
--- /dev/null
+++ b/src/f2c/d_sign.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double d_sign(a,b) doublereal *a, *b;
+#else
+double d_sign(doublereal *a, doublereal *b)
+#endif
+{
+double x;
+x = (*a >= 0 ? *a : - *a);
+return( *b >= 0 ? x : -x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_sin.c b/src/f2c/d_sin.c
new file mode 100644
index 0000000..ebd4eec
--- /dev/null
+++ b/src/f2c/d_sin.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sin();
+double d_sin(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_sin(doublereal *x)
+#endif
+{
+return( sin(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_sinh.c b/src/f2c/d_sinh.c
new file mode 100644
index 0000000..2479a6f
--- /dev/null
+++ b/src/f2c/d_sinh.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sinh();
+double d_sinh(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_sinh(doublereal *x)
+#endif
+{
+return( sinh(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_sqrt.c b/src/f2c/d_sqrt.c
new file mode 100644
index 0000000..a7fa66c
--- /dev/null
+++ b/src/f2c/d_sqrt.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sqrt();
+double d_sqrt(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_sqrt(doublereal *x)
+#endif
+{
+return( sqrt(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_tan.c b/src/f2c/d_tan.c
new file mode 100644
index 0000000..7d252c4
--- /dev/null
+++ b/src/f2c/d_tan.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double tan();
+double d_tan(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_tan(doublereal *x)
+#endif
+{
+return( tan(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/d_tanh.c b/src/f2c/d_tanh.c
new file mode 100644
index 0000000..415b585
--- /dev/null
+++ b/src/f2c/d_tanh.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double tanh();
+double d_tanh(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double d_tanh(doublereal *x)
+#endif
+{
+return( tanh(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/derf_.c b/src/f2c/derf_.c
new file mode 100644
index 0000000..d935d31
--- /dev/null
+++ b/src/f2c/derf_.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double erf();
+double derf_(x) doublereal *x;
+#else
+extern double erf(double);
+double derf_(doublereal *x)
+#endif
+{
+return( erf(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/derfc_.c b/src/f2c/derfc_.c
new file mode 100644
index 0000000..18f5c61
--- /dev/null
+++ b/src/f2c/derfc_.c
@@ -0,0 +1,20 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern double erfc();
+
+double derfc_(x) doublereal *x;
+#else
+extern double erfc(double);
+
+double derfc_(doublereal *x)
+#endif
+{
+return( erfc(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/dfe.c b/src/f2c/dfe.c
new file mode 100644
index 0000000..c6b10d0
--- /dev/null
+++ b/src/f2c/dfe.c
@@ -0,0 +1,151 @@
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int
+y_rsk(Void)
+{
+	if(f__curunit->uend || f__curunit->url <= f__recpos
+		|| f__curunit->url == 1) return 0;
+	do {
+		getc(f__cf);
+	} while(++f__recpos < f__curunit->url);
+	return 0;
+}
+
+ int
+y_getc(Void)
+{
+	int ch;
+	if(f__curunit->uend) return(-1);
+	if((ch=getc(f__cf))!=EOF)
+	{
+		f__recpos++;
+		if(f__curunit->url>=f__recpos ||
+			f__curunit->url==1)
+			return(ch);
+		else	return(' ');
+	}
+	if(feof(f__cf))
+	{
+		f__curunit->uend=1;
+		errno=0;
+		return(-1);
+	}
+	err(f__elist->cierr,errno,"readingd");
+}
+
+ static int
+y_rev(Void)
+{
+	if (f__recpos < f__hiwater)
+		f__recpos = f__hiwater;
+	if (f__curunit->url > 1)
+		while(f__recpos < f__curunit->url)
+			(*f__putn)(' ');
+	if (f__recpos)
+		f__putbuf(0);
+	f__recpos = 0;
+	return(0);
+}
+
+ static int
+y_err(Void)
+{
+	err(f__elist->cierr, 110, "dfe");
+}
+
+ static int
+y_newrec(Void)
+{
+	y_rev();
+	f__hiwater = f__cursor = 0;
+	return(1);
+}
+
+ int
+#ifdef KR_headers
+c_dfe(a) cilist *a;
+#else
+c_dfe(cilist *a)
+#endif
+{
+	f__sequential=0;
+	f__formatted=f__external=1;
+	f__elist=a;
+	f__cursor=f__scale=f__recpos=0;
+	f__curunit = &f__units[a->ciunit];
+	if(a->ciunit>MXUNIT || a->ciunit<0)
+		err(a->cierr,101,"startchk");
+	if(f__curunit->ufd==NULL && fk_open(DIR,FMT,a->ciunit))
+		err(a->cierr,104,"dfe");
+	f__cf=f__curunit->ufd;
+	if(!f__curunit->ufmt) err(a->cierr,102,"dfe")
+	if(!f__curunit->useek) err(a->cierr,104,"dfe")
+	f__fmtbuf=a->cifmt;
+	if(a->cirec <= 0)
+		err(a->cierr,130,"dfe")
+	FSEEK(f__cf,(OFF_T)f__curunit->url * (a->cirec-1),SEEK_SET);
+	f__curunit->uend = 0;
+	return(0);
+}
+#ifdef KR_headers
+integer s_rdfe(a) cilist *a;
+#else
+integer s_rdfe(cilist *a)
+#endif
+{
+	int n;
+	if(!f__init) f_init();
+	f__reading=1;
+	if(n=c_dfe(a))return(n);
+	if(f__curunit->uwrt && f__nowreading(f__curunit))
+		err(a->cierr,errno,"read start");
+	f__getn = y_getc;
+	f__doed = rd_ed;
+	f__doned = rd_ned;
+	f__dorevert = f__donewrec = y_err;
+	f__doend = y_rsk;
+	if(pars_f(f__fmtbuf)<0)
+		err(a->cierr,100,"read start");
+	fmt_bg();
+	return(0);
+}
+#ifdef KR_headers
+integer s_wdfe(a) cilist *a;
+#else
+integer s_wdfe(cilist *a)
+#endif
+{
+	int n;
+	if(!f__init) f_init();
+	f__reading=0;
+	if(n=c_dfe(a)) return(n);
+	if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit))
+		err(a->cierr,errno,"startwrt");
+	f__putn = x_putc;
+	f__doed = w_ed;
+	f__doned= w_ned;
+	f__dorevert = y_err;
+	f__donewrec = y_newrec;
+	f__doend = y_rev;
+	if(pars_f(f__fmtbuf)<0)
+		err(a->cierr,100,"startwrt");
+	fmt_bg();
+	return(0);
+}
+integer e_rdfe(Void)
+{
+	en_fio();
+	return 0;
+}
+integer e_wdfe(Void)
+{
+	return en_fio();
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/dolio.c b/src/f2c/dolio.c
new file mode 100644
index 0000000..4070d87
--- /dev/null
+++ b/src/f2c/dolio.c
@@ -0,0 +1,26 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef KR_headers
+extern int (*f__lioproc)();
+
+integer do_lio(type,number,ptr,len) ftnint *number,*type; char *ptr; ftnlen len;
+#else
+extern int (*f__lioproc)(ftnint*, char*, ftnlen, ftnint);
+
+integer do_lio(ftnint *type, ftnint *number, char *ptr, ftnlen len)
+#endif
+{
+	return((*f__lioproc)(number,ptr,len,*type));
+}
+#ifdef __cplusplus
+	}
+#endif
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/dtime_.c b/src/f2c/dtime_.c
new file mode 100644
index 0000000..6a09b3e
--- /dev/null
+++ b/src/f2c/dtime_.c
@@ -0,0 +1,63 @@
+#include "time.h"
+
+#ifdef MSDOS
+#undef USE_CLOCK
+#define USE_CLOCK
+#endif
+
+#ifndef REAL
+#define REAL double
+#endif
+
+#ifndef USE_CLOCK
+#define _INCLUDE_POSIX_SOURCE	/* for HP-UX */
+#define _INCLUDE_XOPEN_SOURCE	/* for HP-UX */
+#include "sys/types.h"
+#include "sys/times.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+#undef Hz
+#ifdef CLK_TCK
+#define Hz CLK_TCK
+#else
+#ifdef HZ
+#define Hz HZ
+#else
+#define Hz 60
+#endif
+#endif
+
+ REAL
+#ifdef KR_headers
+dtime_(tarray) float *tarray;
+#else
+dtime_(float *tarray)
+#endif
+{
+#ifdef USE_CLOCK
+#ifndef CLOCKS_PER_SECOND
+#define CLOCKS_PER_SECOND Hz
+#endif
+	static double t0;
+	double t = clock();
+	tarray[1] = 0;
+	tarray[0] = (t - t0) / CLOCKS_PER_SECOND;
+	t0 = t;
+	return tarray[0];
+#else
+	struct tms t;
+	static struct tms t0;
+
+	times(&t);
+	tarray[0] = (double)(t.tms_utime - t0.tms_utime) / Hz;
+	tarray[1] = (double)(t.tms_stime - t0.tms_stime) / Hz;
+	t0 = t;
+	return tarray[0] + tarray[1];
+#endif
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/due.c b/src/f2c/due.c
new file mode 100644
index 0000000..a7f4cec
--- /dev/null
+++ b/src/f2c/due.c
@@ -0,0 +1,77 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int
+#ifdef KR_headers
+c_due(a) cilist *a;
+#else
+c_due(cilist *a)
+#endif
+{
+	if(!f__init) f_init();
+	f__sequential=f__formatted=f__recpos=0;
+	f__external=1;
+	f__curunit = &f__units[a->ciunit];
+	if(a->ciunit>=MXUNIT || a->ciunit<0)
+		err(a->cierr,101,"startio");
+	f__elist=a;
+	if(f__curunit->ufd==NULL && fk_open(DIR,UNF,a->ciunit) ) err(a->cierr,104,"due");
+	f__cf=f__curunit->ufd;
+	if(f__curunit->ufmt) err(a->cierr,102,"cdue")
+	if(!f__curunit->useek) err(a->cierr,104,"cdue")
+	if(f__curunit->ufd==NULL) err(a->cierr,114,"cdue")
+	if(a->cirec <= 0)
+		err(a->cierr,130,"due")
+	FSEEK(f__cf,(OFF_T)(a->cirec-1)*f__curunit->url,SEEK_SET);
+	f__curunit->uend = 0;
+	return(0);
+}
+#ifdef KR_headers
+integer s_rdue(a) cilist *a;
+#else
+integer s_rdue(cilist *a)
+#endif
+{
+	int n;
+	f__reading=1;
+	if(n=c_due(a)) return(n);
+	if(f__curunit->uwrt && f__nowreading(f__curunit))
+		err(a->cierr,errno,"read start");
+	return(0);
+}
+#ifdef KR_headers
+integer s_wdue(a) cilist *a;
+#else
+integer s_wdue(cilist *a)
+#endif
+{
+	int n;
+	f__reading=0;
+	if(n=c_due(a)) return(n);
+	if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit))
+		err(a->cierr,errno,"write start");
+	return(0);
+}
+integer e_rdue(Void)
+{
+	if(f__curunit->url==1 || f__recpos==f__curunit->url)
+		return(0);
+	FSEEK(f__cf,(OFF_T)(f__curunit->url-f__recpos),SEEK_CUR);
+	if(FTELL(f__cf)%f__curunit->url)
+		err(f__elist->cierr,200,"syserr");
+	return(0);
+}
+integer e_wdue(Void)
+{
+#ifdef ALWAYS_FLUSH
+	if (fflush(f__cf))
+		err(f__elist->cierr,errno,"write end");
+#endif
+	return(e_rdue());
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/dummy.c b/src/f2c/dummy.c
new file mode 100644
index 0000000..f2d3c80
--- /dev/null
+++ b/src/f2c/dummy.c
@@ -0,0 +1,2 @@
+
+int MAIN__(void) { return 0; }
diff --git a/src/f2c/ef1asc_.c b/src/f2c/ef1asc_.c
new file mode 100644
index 0000000..70be0bc
--- /dev/null
+++ b/src/f2c/ef1asc_.c
@@ -0,0 +1,25 @@
+/* EFL support routine to copy string b to string a */
+
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define M	( (long) (sizeof(long) - 1) )
+#define EVEN(x)	( ( (x)+ M) & (~M) )
+
+#ifdef KR_headers
+extern VOID s_copy();
+ef1asc_(a, la, b, lb) ftnint *a, *b; ftnlen *la, *lb;
+#else
+extern void s_copy(char*,char*,ftnlen,ftnlen);
+int ef1asc_(ftnint *a, ftnlen *la, ftnint *b, ftnlen *lb)
+#endif
+{
+s_copy( (char *)a, (char *)b, EVEN(*la), *lb );
+return 0;	/* ignored return value */
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/ef1cmc_.c b/src/f2c/ef1cmc_.c
new file mode 100644
index 0000000..4b420ae
--- /dev/null
+++ b/src/f2c/ef1cmc_.c
@@ -0,0 +1,20 @@
+/* EFL support routine to compare two character strings */
+
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+integer ef1cmc_(a, la, b, lb) ftnint *a, *b; ftnlen *la, *lb;
+#else
+extern integer s_cmp(char*,char*,ftnlen,ftnlen);
+integer ef1cmc_(ftnint *a, ftnlen *la, ftnint *b, ftnlen *lb)
+#endif
+{
+return( s_cmp( (char *)a, (char *)b, *la, *lb) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/endfile.c b/src/f2c/endfile.c
new file mode 100644
index 0000000..04020d3
--- /dev/null
+++ b/src/f2c/endfile.c
@@ -0,0 +1,160 @@
+#include "f2c.h"
+#include "fio.h"
+
+/* Compile this with -DNO_TRUNCATE if unistd.h does not exist or */
+/* if it does not define int truncate(const char *name, off_t). */
+
+#ifdef MSDOS
+#undef NO_TRUNCATE
+#define NO_TRUNCATE
+#endif
+
+#ifndef NO_TRUNCATE
+#include "unistd.h"
+#endif
+
+#ifdef KR_headers
+extern char *strcpy();
+extern FILE *tmpfile();
+#else
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#include "string.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+extern char *f__r_mode[], *f__w_mode[];
+
+#ifdef KR_headers
+integer f_end(a) alist *a;
+#else
+integer f_end(alist *a)
+#endif
+{
+	unit *b;
+	FILE *tf;
+
+	if(a->aunit>=MXUNIT || a->aunit<0) err(a->aerr,101,"endfile");
+	b = &f__units[a->aunit];
+	if(b->ufd==NULL) {
+		char nbuf[10];
+		sprintf(nbuf,"fort.%ld",(long)a->aunit);
+		if (tf = FOPEN(nbuf, f__w_mode[0]))
+			fclose(tf);
+		return(0);
+		}
+	b->uend=1;
+	return(b->useek ? t_runc(a) : 0);
+}
+
+#ifdef NO_TRUNCATE
+ static int
+#ifdef KR_headers
+copy(from, len, to) FILE *from, *to; register long len;
+#else
+copy(FILE *from, register long len, FILE *to)
+#endif
+{
+	int len1;
+	char buf[BUFSIZ];
+
+	while(fread(buf, len1 = len > BUFSIZ ? BUFSIZ : (int)len, 1, from)) {
+		if (!fwrite(buf, len1, 1, to))
+			return 1;
+		if ((len -= len1) <= 0)
+			break;
+		}
+	return 0;
+	}
+#endif /* NO_TRUNCATE */
+
+ int
+#ifdef KR_headers
+t_runc(a) alist *a;
+#else
+t_runc(alist *a)
+#endif
+{
+	OFF_T loc, len;
+	unit *b;
+	int rc;
+	FILE *bf;
+#ifdef NO_TRUNCATE
+	FILE *tf;
+#endif
+
+	b = &f__units[a->aunit];
+	if(b->url)
+		return(0);	/*don't truncate direct files*/
+	loc=FTELL(bf = b->ufd);
+	FSEEK(bf,(OFF_T)0,SEEK_END);
+	len=FTELL(bf);
+	if (loc >= len || b->useek == 0)
+		return(0);
+#ifdef NO_TRUNCATE
+	if (b->ufnm == NULL)
+		return 0;
+	rc = 0;
+	fclose(b->ufd);
+	if (!loc) {
+		if (!(bf = FOPEN(b->ufnm, f__w_mode[b->ufmt])))
+			rc = 1;
+		if (b->uwrt)
+			b->uwrt = 1;
+		goto done;
+		}
+	if (!(bf = FOPEN(b->ufnm, f__r_mode[0]))
+	 || !(tf = tmpfile())) {
+#ifdef NON_UNIX_STDIO
+ bad:
+#endif
+		rc = 1;
+		goto done;
+		}
+	if (copy(bf, (long)loc, tf)) {
+ bad1:
+		rc = 1;
+		goto done1;
+		}
+	if (!(bf = FREOPEN(b->ufnm, f__w_mode[0], bf)))
+		goto bad1;
+	rewind(tf);
+	if (copy(tf, (long)loc, bf))
+		goto bad1;
+	b->uwrt = 1;
+	b->urw = 2;
+#ifdef NON_UNIX_STDIO
+	if (b->ufmt) {
+		fclose(bf);
+		if (!(bf = FOPEN(b->ufnm, f__w_mode[3])))
+			goto bad;
+		FSEEK(bf,(OFF_T)0,SEEK_END);
+		b->urw = 3;
+		}
+#endif
+done1:
+	fclose(tf);
+done:
+	f__cf = b->ufd = bf;
+#else /* NO_TRUNCATE */
+	if (b->urw & 2)
+		fflush(b->ufd); /* necessary on some Linux systems */
+#ifndef FTRUNCATE
+#define FTRUNCATE ftruncate
+#endif
+	rc = FTRUNCATE(fileno(b->ufd), loc);
+	/* The following FSEEK is unnecessary on some systems, */
+	/* but should be harmless. */
+	FSEEK(b->ufd, (OFF_T)0, SEEK_END);
+#endif /* NO_TRUNCATE */
+	if (rc)
+		err(a->aerr,111,"endfile");
+	return 0;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/erf_.c b/src/f2c/erf_.c
new file mode 100644
index 0000000..532fec6
--- /dev/null
+++ b/src/f2c/erf_.c
@@ -0,0 +1,22 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef REAL
+#define REAL double
+#endif
+
+#ifdef KR_headers
+double erf();
+REAL erf_(x) real *x;
+#else
+extern double erf(double);
+REAL erf_(real *x)
+#endif
+{
+return( erf((double)*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/erfc_.c b/src/f2c/erfc_.c
new file mode 100644
index 0000000..6f6c9f1
--- /dev/null
+++ b/src/f2c/erfc_.c
@@ -0,0 +1,22 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef REAL
+#define REAL double
+#endif
+
+#ifdef KR_headers
+double erfc();
+REAL erfc_(x) real *x;
+#else
+extern double erfc(double);
+REAL erfc_(real *x)
+#endif
+{
+return( erfc((double)*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/err.c b/src/f2c/err.c
new file mode 100644
index 0000000..80a3b74
--- /dev/null
+++ b/src/f2c/err.c
@@ -0,0 +1,293 @@
+#include "sysdep1.h"	/* here to get stat64 on some badly designed Linux systems */
+#include "f2c.h"
+#ifdef KR_headers
+#define Const /*nothing*/
+extern char *malloc();
+#else
+#define Const const
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#endif
+#include "fio.h"
+#include "fmt.h"	/* for struct syl */
+
+/* Compile this with -DNO_ISATTY if unistd.h does not exist or */
+/* if it does not define int isatty(int). */
+#ifdef NO_ISATTY
+#define isatty(x) 0
+#else
+#include <unistd.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*global definitions*/
+unit f__units[MXUNIT];	/*unit table*/
+flag f__init;	/*0 on entry, 1 after initializations*/
+cilist *f__elist;	/*active external io list*/
+icilist *f__svic;	/*active internal io list*/
+flag f__reading;	/*1 if reading, 0 if writing*/
+flag f__cplus,f__cblank;
+Const char *f__fmtbuf;
+flag f__external;	/*1 if external io, 0 if internal */
+#ifdef KR_headers
+int (*f__doed)(),(*f__doned)();
+int (*f__doend)(),(*f__donewrec)(),(*f__dorevert)();
+int (*f__getn)();	/* for formatted input */
+void (*f__putn)();	/* for formatted output */
+#else
+int (*f__getn)(void);	/* for formatted input */
+void (*f__putn)(int);	/* for formatted output */
+int (*f__doed)(struct syl*, char*, ftnlen),(*f__doned)(struct syl*);
+int (*f__dorevert)(void),(*f__donewrec)(void),(*f__doend)(void);
+#endif
+flag f__sequential;	/*1 if sequential io, 0 if direct*/
+flag f__formatted;	/*1 if formatted io, 0 if unformatted*/
+FILE *f__cf;	/*current file*/
+unit *f__curunit;	/*current unit*/
+int f__recpos;	/*place in current record*/
+OFF_T f__cursor, f__hiwater;
+int f__scale;
+char *f__icptr;
+
+/*error messages*/
+Const char *F_err[] =
+{
+	"error in format",				/* 100 */
+	"illegal unit number",				/* 101 */
+	"formatted io not allowed",			/* 102 */
+	"unformatted io not allowed",			/* 103 */
+	"direct io not allowed",			/* 104 */
+	"sequential io not allowed",			/* 105 */
+	"can't backspace file",				/* 106 */
+	"null file name",				/* 107 */
+	"can't stat file",				/* 108 */
+	"unit not connected",				/* 109 */
+	"off end of record",				/* 110 */
+	"truncation failed in endfile",			/* 111 */
+	"incomprehensible list input",			/* 112 */
+	"out of free space",				/* 113 */
+	"unit not connected",				/* 114 */
+	"read unexpected character",			/* 115 */
+	"bad logical input field",			/* 116 */
+	"bad variable type",				/* 117 */
+	"bad namelist name",				/* 118 */
+	"variable not in namelist",			/* 119 */
+	"no end record",				/* 120 */
+	"variable count incorrect",			/* 121 */
+	"subscript for scalar variable",		/* 122 */
+	"invalid array section",			/* 123 */
+	"substring out of bounds",			/* 124 */
+	"subscript out of bounds",			/* 125 */
+	"can't read file",				/* 126 */
+	"can't write file",				/* 127 */
+	"'new' file exists",				/* 128 */
+	"can't append to file",				/* 129 */
+	"non-positive record number",			/* 130 */
+	"nmLbuf overflow"				/* 131 */
+};
+#define MAXERR (sizeof(F_err)/sizeof(char *)+100)
+
+ int
+#ifdef KR_headers
+f__canseek(f) FILE *f; /*SYSDEP*/
+#else
+f__canseek(FILE *f) /*SYSDEP*/
+#endif
+{
+#ifdef NON_UNIX_STDIO
+	return !isatty(fileno(f));
+#else
+	struct STAT_ST x;
+
+	if (FSTAT(fileno(f),&x) < 0)
+		return(0);
+#ifdef S_IFMT
+	switch(x.st_mode & S_IFMT) {
+	case S_IFDIR:
+	case S_IFREG:
+		if(x.st_nlink > 0)	/* !pipe */
+			return(1);
+		else
+			return(0);
+	case S_IFCHR:
+		if(isatty(fileno(f)))
+			return(0);
+		return(1);
+#ifdef S_IFBLK
+	case S_IFBLK:
+		return(1);
+#endif
+	}
+#else
+#ifdef S_ISDIR
+	/* POSIX version */
+	if (S_ISREG(x.st_mode) || S_ISDIR(x.st_mode)) {
+		if(x.st_nlink > 0)	/* !pipe */
+			return(1);
+		else
+			return(0);
+		}
+	if (S_ISCHR(x.st_mode)) {
+		if(isatty(fileno(f)))
+			return(0);
+		return(1);
+		}
+	if (S_ISBLK(x.st_mode))
+		return(1);
+#else
+	Help! How does fstat work on this system?
+#endif
+#endif
+	return(0);	/* who knows what it is? */
+#endif
+}
+
+ void
+#ifdef KR_headers
+f__fatal(n,s) char *s;
+#else
+f__fatal(int n, const char *s)
+#endif
+{
+	if(n<100 && n>=0) perror(s); /*SYSDEP*/
+	else if(n >= (int)MAXERR || n < -1)
+	{	fprintf(stderr,"%s: illegal error number %d\n",s,n);
+	}
+	else if(n == -1) fprintf(stderr,"%s: end of file\n",s);
+	else
+		fprintf(stderr,"%s: %s\n",s,F_err[n-100]);
+	if (f__curunit) {
+		fprintf(stderr,"apparent state: unit %d ",
+			(int)(f__curunit-f__units));
+		fprintf(stderr, f__curunit->ufnm ? "named %s\n" : "(unnamed)\n",
+			f__curunit->ufnm);
+		}
+	else
+		fprintf(stderr,"apparent state: internal I/O\n");
+	if (f__fmtbuf)
+		fprintf(stderr,"last format: %s\n",f__fmtbuf);
+	fprintf(stderr,"lately %s %s %s %s",f__reading?"reading":"writing",
+		f__sequential?"sequential":"direct",f__formatted?"formatted":"unformatted",
+		f__external?"external":"internal");
+	sig_die(" IO", 1);
+}
+/*initialization routine*/
+ VOID
+f_init(Void)
+{	unit *p;
+
+	f__init=1;
+	p= &f__units[0];
+	p->ufd=stderr;
+	p->useek=f__canseek(stderr);
+	p->ufmt=1;
+	p->uwrt=1;
+	p = &f__units[5];
+	p->ufd=stdin;
+	p->useek=f__canseek(stdin);
+	p->ufmt=1;
+	p->uwrt=0;
+	p= &f__units[6];
+	p->ufd=stdout;
+	p->useek=f__canseek(stdout);
+	p->ufmt=1;
+	p->uwrt=1;
+}
+
+ int
+#ifdef KR_headers
+f__nowreading(x) unit *x;
+#else
+f__nowreading(unit *x)
+#endif
+{
+	OFF_T loc;
+	int ufmt, urw;
+	extern char *f__r_mode[], *f__w_mode[];
+
+	if (x->urw & 1)
+		goto done;
+	if (!x->ufnm)
+		goto cantread;
+	ufmt = x->url ? 0 : x->ufmt;
+	loc = FTELL(x->ufd);
+	urw = 3;
+	if (!FREOPEN(x->ufnm, f__w_mode[ufmt|2], x->ufd)) {
+		urw = 1;
+		if(!FREOPEN(x->ufnm, f__r_mode[ufmt], x->ufd)) {
+ cantread:
+			errno = 126;
+			return 1;
+			}
+		}
+	FSEEK(x->ufd,loc,SEEK_SET);
+	x->urw = urw;
+ done:
+	x->uwrt = 0;
+	return 0;
+}
+
+ int
+#ifdef KR_headers
+f__nowwriting(x) unit *x;
+#else
+f__nowwriting(unit *x)
+#endif
+{
+	OFF_T loc;
+	int ufmt;
+	extern char *f__w_mode[];
+
+	if (x->urw & 2) {
+		if (x->urw & 1)
+			FSEEK(x->ufd, (OFF_T)0, SEEK_CUR);
+		goto done;
+		}
+	if (!x->ufnm)
+		goto cantwrite;
+	ufmt = x->url ? 0 : x->ufmt;
+	if (x->uwrt == 3) { /* just did write, rewind */
+		if (!(f__cf = x->ufd =
+				FREOPEN(x->ufnm,f__w_mode[ufmt],x->ufd)))
+			goto cantwrite;
+		x->urw = 2;
+		}
+	else {
+		loc=FTELL(x->ufd);
+		if (!(f__cf = x->ufd =
+			FREOPEN(x->ufnm, f__w_mode[ufmt | 2], x->ufd)))
+			{
+			x->ufd = NULL;
+ cantwrite:
+			errno = 127;
+			return(1);
+			}
+		x->urw = 3;
+		FSEEK(x->ufd,loc,SEEK_SET);
+		}
+ done:
+	x->uwrt = 1;
+	return 0;
+}
+
+ int
+#ifdef KR_headers
+err__fl(f, m, s) int f, m; char *s;
+#else
+err__fl(int f, int m, const char *s)
+#endif
+{
+	if (!f)
+		f__fatal(m, s);
+	if (f__doend)
+		(*f__doend)();
+	return errno = m;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/etime_.c b/src/f2c/etime_.c
new file mode 100644
index 0000000..2d9a36d
--- /dev/null
+++ b/src/f2c/etime_.c
@@ -0,0 +1,57 @@
+#include "time.h"
+
+#ifdef MSDOS
+#undef USE_CLOCK
+#define USE_CLOCK
+#endif
+
+#ifndef REAL
+#define REAL double
+#endif
+
+#ifndef USE_CLOCK
+#define _INCLUDE_POSIX_SOURCE	/* for HP-UX */
+#define _INCLUDE_XOPEN_SOURCE	/* for HP-UX */
+#include "sys/types.h"
+#include "sys/times.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+#undef Hz
+#ifdef CLK_TCK
+#define Hz CLK_TCK
+#else
+#ifdef HZ
+#define Hz HZ
+#else
+#define Hz 60
+#endif
+#endif
+
+ REAL
+#ifdef KR_headers
+etime_(tarray) float *tarray;
+#else
+etime_(float *tarray)
+#endif
+{
+#ifdef USE_CLOCK
+#ifndef CLOCKS_PER_SECOND
+#define CLOCKS_PER_SECOND Hz
+#endif
+	double t = clock();
+	tarray[1] = 0;
+	return tarray[0] = t / CLOCKS_PER_SECOND;
+#else
+	struct tms t;
+
+	times(&t);
+	return	  (tarray[0] = (double)t.tms_utime/Hz)
+		+ (tarray[1] = (double)t.tms_stime/Hz);
+#endif
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/exit_.c b/src/f2c/exit_.c
new file mode 100644
index 0000000..08e9d07
--- /dev/null
+++ b/src/f2c/exit_.c
@@ -0,0 +1,43 @@
+/* This gives the effect of
+
+	subroutine exit(rc)
+	integer*4 rc
+	stop
+	end
+
+ * with the added side effect of supplying rc as the program's exit code.
+ */
+
+#include "f2c.h"
+#undef abs
+#undef min
+#undef max
+#ifndef KR_headers
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern void f_exit(void);
+#endif
+
+ void
+#ifdef KR_headers
+exit_(rc) integer *rc;
+#else
+exit_(integer *rc)
+#endif
+{
+#ifdef NO_ONEXIT
+	f_exit();
+#endif
+	exit(*rc);
+	}
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/f77_aloc.c b/src/f2c/f77_aloc.c
new file mode 100644
index 0000000..f536099
--- /dev/null
+++ b/src/f2c/f77_aloc.c
@@ -0,0 +1,44 @@
+#include "f2c.h"
+#undef abs
+#undef min
+#undef max
+#include "stdio.h"
+
+static integer memfailure = 3;
+
+#ifdef KR_headers
+extern char *malloc();
+extern void exit_();
+
+ char *
+F77_aloc(Len, whence) integer Len; char *whence;
+#else
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern void exit_(integer*);
+#ifdef __cplusplus
+	}
+#endif
+
+ char *
+F77_aloc(integer Len, const char *whence)
+#endif
+{
+	char *rv;
+	unsigned int uLen = (unsigned int) Len;	/* for K&R C */
+
+	if (!(rv = (char*)malloc(uLen))) {
+		fprintf(stderr, "malloc(%u) failure in %s\n",
+			uLen, whence);
+		exit_(&memfailure);
+		}
+	return rv;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/f77vers.c b/src/f2c/f77vers.c
new file mode 100644
index 0000000..70cd6fe
--- /dev/null
+++ b/src/f2c/f77vers.c
@@ -0,0 +1,97 @@
+ char 
+_libf77_version_f2c[] = "\n@(#) LIBF77 VERSION (f2c) 20051004\n";
+
+/*
+2.00	11 June 1980.  File version.c added to library.
+2.01	31 May 1988.  s_paus() flushes stderr; names of hl_* fixed
+	[ d]erf[c ] added
+	 8 Aug. 1989: #ifdefs for f2c -i2 added to s_cat.c
+	29 Nov. 1989: s_cmp returns long (for f2c)
+	30 Nov. 1989: arg types from f2c.h
+	12 Dec. 1989: s_rnge allows long names
+	19 Dec. 1989: getenv_ allows unsorted environment
+	28 Mar. 1990: add exit(0) to end of main()
+	 2 Oct. 1990: test signal(...) == SIG_IGN rather than & 01 in main
+	17 Oct. 1990: abort() calls changed to sig_die(...,1)
+	22 Oct. 1990: separate sig_die from main
+	25 Apr. 1991: minor, theoretically invisible tweaks to s_cat, sig_die
+	31 May  1991: make system_ return status
+	18 Dec. 1991: change long to ftnlen (for -i2) many places
+	28 Feb. 1992: repair z_sqrt.c (scribbled on input, gave wrong answer)
+	18 July 1992: for n < 0, repair handling of 0**n in pow_[dr]i.c
+			and m**n in pow_hh.c and pow_ii.c;
+			catch SIGTRAP in main() for error msg before abort
+	23 July 1992: switch to ANSI prototypes unless KR_headers is #defined
+	23 Oct. 1992: fix botch in signal_.c (erroneous deref of 2nd arg);
+			change Cabs to f__cabs.
+	12 March 1993: various tweaks for C++
+	 2 June 1994: adjust so abnormal terminations invoke f_exit just once
+	16 Sept. 1994: s_cmp: treat characters as unsigned in comparisons.
+	19 Sept. 1994: s_paus: flush after end of PAUSE; add -DMSDOS
+	12 Jan. 1995:	pow_[dhiqrz][hiq]: adjust x**i to work on machines
+			that sign-extend right shifts when i is the most
+			negative integer.
+	26 Jan. 1995: adjust s_cat.c, s_copy.c to permit the left-hand side
+			of character assignments to appear on the right-hand
+			side (unless compiled with -DNO_OVERWRITE).
+	27 Jan. 1995: minor tweak to s_copy.c: copy forward whenever
+			possible (for better cache behavior).
+	30 May 1995:  added subroutine exit(rc) integer rc. Version not changed.
+	29 Aug. 1995: add F77_aloc.c; use it in s_cat.c and system_.c.
+	6 Sept. 1995: fix return type of system_ under -DKR_headers.
+	19 Dec. 1995: s_cat.c: fix bug when 2nd or later arg overlaps lhs.
+	19 Mar. 1996: s_cat.c: supply missing break after overlap detection.
+	13 May 1996:  add [lq]bitbits.c and [lq]bitshft.c (f90 bit intrinsics).
+	19 June 1996: add casts to unsigned in [lq]bitshft.c.
+	26 Feb. 1997: adjust functions with a complex output argument
+			to permit aliasing it with input arguments.
+			(For now, at least, this is just for possible
+			benefit of g77.)
+	4 April 1997: [cz]_div.c: tweaks invisible on most systems (that may
+			affect systems using gratuitous extra precision).
+	19 Sept. 1997: [de]time_.c (Unix systems only): change return
+			type to double.
+	2 May 1999:	getenv_.c: omit environ in favor of getenv().
+			c_cos.c, c_exp.c, c_sin.c, d_cnjg.c, r_cnjg.c,
+			z_cos.c, z_exp.c, z_log.c, z_sin.c: cope fully with
+			overlapping arguments caused by equivalence.
+	3 May 1999:	"invisible" tweaks to omit compiler warnings in
+			abort_.c, ef1asc_.c, s_rnge.c, s_stop.c.
+
+	7 Sept. 1999: [cz]_div.c: arrange for compilation under
+			-DIEEE_COMPLEX_DIVIDE to make these routines
+			avoid calling sig_die when the denominator
+			vanishes; instead, they return pairs of NaNs
+			or Infinities, depending whether the numerator
+			also vanishes or not.  VERSION not changed.
+	15 Nov. 1999: s_rnge.c: add casts for the case of
+			sizeof(ftnint) == sizeof(int) < sizeof(long).
+	10 March 2000: z_log.c: improve accuracy of Real(log(z)) for, e.g.,
+			z near (+-1,eps) with |eps| small.  For the old
+			evaluation, compile with -DPre20000310 .
+	20 April 2000: s_cat.c: tweak argument types to accord with
+			calls by f2c when ftnint and ftnlen are of
+			different sizes (different numbers of bits).
+	4 July 2000: adjustments to permit compilation by C++ compilers;
+			VERSION string remains unchanged.
+	29 Sept. 2000: dtime_.c, etime_.c: use floating-point divide.
+			dtime_.d, erf_.c, erfc_.c, etime.c: for use with
+			"f2c -R", compile with -DREAL=float.
+	23 June 2001: add uninit.c; [fi]77vers.c: make version strings
+			visible as extern char _lib[fi]77_version_f2c[].
+	5 July 2001: modify uninit.c for __mc68k__ under Linux.
+	16 Nov. 2001: uninit.c: Linux Power PC logic supplied by Alan Bain.
+	18 Jan. 2002: fix glitches in qbit_bits(): wrong return type,
+			missing ~ on y in return value.
+	14 March 2002: z_log.c: add code to cope with buggy compilers
+			(e.g., some versions of gcc under -O2 or -O3)
+			that do floating-point comparisons against values
+			computed into extended-precision registers on some
+			systems (such as Intel IA32 systems).  Compile with
+			-DNO_DOUBLE_EXTENDED to omit the new logic.
+	4 Oct. 2002: uninit.c: on IRIX systems, omit use of shell variables.
+	10 Oct 2005: uninit.c: on IA32 Linux systems, leave the rounding
+			precision alone rather than forcing it to 53 bits;
+			compile with -DUNINIT_F2C_PRECISION_53 to get the
+			former behavior.
+*/
diff --git a/src/f2c/fio.h b/src/f2c/fio.h
new file mode 100644
index 0000000..ebf7696
--- /dev/null
+++ b/src/f2c/fio.h
@@ -0,0 +1,141 @@
+#ifndef SYSDEP_H_INCLUDED
+#include "sysdep1.h"
+#endif
+#include "stdio.h"
+#include "errno.h"
+#ifndef NULL
+/* ANSI C */
+#include "stddef.h"
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef FOPEN
+#define FOPEN fopen
+#endif
+
+#ifndef FREOPEN
+#define FREOPEN freopen
+#endif
+
+#ifndef FSEEK
+#define FSEEK fseek
+#endif
+
+#ifndef FSTAT
+#define FSTAT fstat
+#endif
+
+#ifndef FTELL
+#define FTELL ftell
+#endif
+
+#ifndef OFF_T
+#define OFF_T long
+#endif
+
+#ifndef STAT_ST
+#define STAT_ST stat
+#endif
+
+#ifndef STAT
+#define STAT stat
+#endif
+
+#ifdef MSDOS
+#ifndef NON_UNIX_STDIO
+#define NON_UNIX_STDIO
+#endif
+#endif
+
+#ifdef UIOLEN_int
+typedef int uiolen;
+#else
+typedef long uiolen;
+#endif
+
+/*units*/
+typedef struct
+{	FILE *ufd;	/*0=unconnected*/
+	char *ufnm;
+#ifndef MSDOS
+	long uinode;
+	int udev;
+#endif
+	int url;	/*0=sequential*/
+	flag useek;	/*true=can backspace, use dir, ...*/
+	flag ufmt;
+	flag urw;	/* (1 for can read) | (2 for can write) */
+	flag ublnk;
+	flag uend;
+	flag uwrt;	/*last io was write*/
+	flag uscrtch;
+} unit;
+
+#undef Void
+#ifdef KR_headers
+#define Void /*void*/
+extern int (*f__getn)();	/* for formatted input */
+extern void (*f__putn)();	/* for formatted output */
+extern void x_putc();
+extern long f__inode();
+extern VOID sig_die();
+extern int (*f__donewrec)(), t_putc(), x_wSL();
+extern int c_sfe(), err__fl(), xrd_SL(), f__putbuf();
+#else
+#define Void void
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int (*f__getn)(void);	/* for formatted input */
+extern void (*f__putn)(int);	/* for formatted output */
+extern void x_putc(int);
+extern long f__inode(char*,int*);
+extern void sig_die(const char*,int);
+extern void f__fatal(int, const char*);
+extern int t_runc(alist*);
+extern int f__nowreading(unit*), f__nowwriting(unit*);
+extern int fk_open(int,int,ftnint);
+extern int en_fio(void);
+extern void f_init(void);
+extern int (*f__donewrec)(void), t_putc(int), x_wSL(void);
+extern void b_char(const char*,char*,ftnlen), g_char(const char*,ftnlen,char*);
+extern int c_sfe(cilist*), z_rnew(void);
+extern int err__fl(int,int,const char*);
+extern int xrd_SL(void);
+extern int f__putbuf(int);
+#endif
+extern flag f__init;
+extern cilist *f__elist;	/*active external io list*/
+extern flag f__reading,f__external,f__sequential,f__formatted;
+extern int (*f__doend)(Void);
+extern FILE *f__cf;	/*current file*/
+extern unit *f__curunit;	/*current unit*/
+extern unit f__units[];
+#define err(f,m,s) {if(f) errno= m; else f__fatal(m,s); return(m);}
+#define errfl(f,m,s) return err__fl((int)f,m,s)
+
+/*Table sizes*/
+#define MXUNIT 100
+
+extern int f__recpos;	/*position in current record*/
+extern OFF_T f__cursor;	/* offset to move to */
+extern OFF_T f__hiwater;	/* so TL doesn't confuse us */
+#ifdef __cplusplus
+	}
+#endif
+
+#define WRITE	1
+#define READ	2
+#define SEQ	3
+#define DIR	4
+#define FMT	5
+#define UNF	6
+#define EXT	7
+#define INT	8
+
+#define buf_end(x) (x->_flag & _IONBF ? x->_ptr : x->_base + BUFSIZ)
diff --git a/src/f2c/fmt.c b/src/f2c/fmt.c
new file mode 100644
index 0000000..286c98f
--- /dev/null
+++ b/src/f2c/fmt.c
@@ -0,0 +1,530 @@
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define skip(s) while(*s==' ') s++
+#ifdef interdata
+#define SYLMX 300
+#endif
+#ifdef pdp11
+#define SYLMX 300
+#endif
+#ifdef vax
+#define SYLMX 300
+#endif
+#ifndef SYLMX
+#define SYLMX 300
+#endif
+#define GLITCH '\2'
+	/* special quote character for stu */
+extern flag f__cblank,f__cplus;	/*blanks in I and compulsory plus*/
+static struct syl f__syl[SYLMX];
+int f__parenlvl,f__pc,f__revloc;
+#ifdef KR_headers
+#define Const /*nothing*/
+#else
+#define Const const
+#endif
+
+ static
+#ifdef KR_headers
+char *ap_end(s) char *s;
+#else
+const char *ap_end(const char *s)
+#endif
+{	char quote;
+	quote= *s++;
+	for(;*s;s++)
+	{	if(*s!=quote) continue;
+		if(*++s!=quote) return(s);
+	}
+	if(f__elist->cierr) {
+		errno = 100;
+		return(NULL);
+	}
+	f__fatal(100, "bad string");
+	/*NOTREACHED*/ return 0;
+}
+ static int
+#ifdef KR_headers
+op_gen(a,b,c,d)
+#else
+op_gen(int a, int b, int c, int d)
+#endif
+{	struct syl *p= &f__syl[f__pc];
+	if(f__pc>=SYLMX)
+	{	fprintf(stderr,"format too complicated:\n");
+		sig_die(f__fmtbuf, 1);
+	}
+	p->op=a;
+	p->p1=b;
+	p->p2.i[0]=c;
+	p->p2.i[1]=d;
+	return(f__pc++);
+}
+#ifdef KR_headers
+static char *f_list();
+static char *gt_num(s,n,n1) char *s; int *n, n1;
+#else
+static const char *f_list(const char*);
+static const char *gt_num(const char *s, int *n, int n1)
+#endif
+{	int m=0,f__cnt=0;
+	char c;
+	for(c= *s;;c = *s)
+	{	if(c==' ')
+		{	s++;
+			continue;
+		}
+		if(c>'9' || c<'0') break;
+		m=10*m+c-'0';
+		f__cnt++;
+		s++;
+	}
+	if(f__cnt==0) {
+		if (!n1)
+			s = 0;
+		*n=n1;
+		}
+	else *n=m;
+	return(s);
+}
+
+ static
+#ifdef KR_headers
+char *f_s(s,curloc) char *s;
+#else
+const char *f_s(const char *s, int curloc)
+#endif
+{
+	skip(s);
+	if(*s++!='(')
+	{
+		return(NULL);
+	}
+	if(f__parenlvl++ ==1) f__revloc=curloc;
+	if(op_gen(RET1,curloc,0,0)<0 ||
+		(s=f_list(s))==NULL)
+	{
+		return(NULL);
+	}
+	skip(s);
+	return(s);
+}
+
+ static int
+#ifdef KR_headers
+ne_d(s,p) char *s,**p;
+#else
+ne_d(const char *s, const char **p)
+#endif
+{	int n,x,sign=0;
+	struct syl *sp;
+	switch(*s)
+	{
+	default:
+		return(0);
+	case ':': (void) op_gen(COLON,0,0,0); break;
+	case '$':
+		(void) op_gen(NONL, 0, 0, 0); break;
+	case 'B':
+	case 'b':
+		if(*++s=='z' || *s == 'Z') (void) op_gen(BZ,0,0,0);
+		else (void) op_gen(BN,0,0,0);
+		break;
+	case 'S':
+	case 's':
+		if(*(s+1)=='s' || *(s+1) == 'S')
+		{	x=SS;
+			s++;
+		}
+		else if(*(s+1)=='p' || *(s+1) == 'P')
+		{	x=SP;
+			s++;
+		}
+		else x=S;
+		(void) op_gen(x,0,0,0);
+		break;
+	case '/': (void) op_gen(SLASH,0,0,0); break;
+	case '-': sign=1;
+	case '+':	s++;	/*OUTRAGEOUS CODING TRICK*/
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+		if (!(s=gt_num(s,&n,0))) {
+ bad:			*p = 0;
+			return 1;
+			}
+		switch(*s)
+		{
+		default:
+			return(0);
+		case 'P':
+		case 'p': if(sign) n= -n; (void) op_gen(P,n,0,0); break;
+		case 'X':
+		case 'x': (void) op_gen(X,n,0,0); break;
+		case 'H':
+		case 'h':
+			sp = &f__syl[op_gen(H,n,0,0)];
+			sp->p2.s = (char*)s + 1;
+			s+=n;
+			break;
+		}
+		break;
+	case GLITCH:
+	case '"':
+	case '\'':
+		sp = &f__syl[op_gen(APOS,0,0,0)];
+		sp->p2.s = (char*)s;
+		if((*p = ap_end(s)) == NULL)
+			return(0);
+		return(1);
+	case 'T':
+	case 't':
+		if(*(s+1)=='l' || *(s+1) == 'L')
+		{	x=TL;
+			s++;
+		}
+		else if(*(s+1)=='r'|| *(s+1) == 'R')
+		{	x=TR;
+			s++;
+		}
+		else x=T;
+		if (!(s=gt_num(s+1,&n,0)))
+			goto bad;
+		s--;
+		(void) op_gen(x,n,0,0);
+		break;
+	case 'X':
+	case 'x': (void) op_gen(X,1,0,0); break;
+	case 'P':
+	case 'p': (void) op_gen(P,1,0,0); break;
+	}
+	s++;
+	*p=s;
+	return(1);
+}
+
+ static int
+#ifdef KR_headers
+e_d(s,p) char *s,**p;
+#else
+e_d(const char *s, const char **p)
+#endif
+{	int i,im,n,w,d,e,found=0,x=0;
+	Const char *sv=s;
+	s=gt_num(s,&n,1);
+	(void) op_gen(STACK,n,0,0);
+	switch(*s++)
+	{
+	default: break;
+	case 'E':
+	case 'e':	x=1;
+	case 'G':
+	case 'g':
+		found=1;
+		if (!(s=gt_num(s,&w,0))) {
+ bad:
+			*p = 0;
+			return 1;
+			}
+		if(w==0) break;
+		if(*s=='.') {
+			if (!(s=gt_num(s+1,&d,0)))
+				goto bad;
+			}
+		else d=0;
+		if(*s!='E' && *s != 'e')
+			(void) op_gen(x==1?E:G,w,d,0);	/* default is Ew.dE2 */
+		else {
+			if (!(s=gt_num(s+1,&e,0)))
+				goto bad;
+			(void) op_gen(x==1?EE:GE,w,d,e);
+			}
+		break;
+	case 'O':
+	case 'o':
+		i = O;
+		im = OM;
+		goto finish_I;
+	case 'Z':
+	case 'z':
+		i = Z;
+		im = ZM;
+		goto finish_I;
+	case 'L':
+	case 'l':
+		found=1;
+		if (!(s=gt_num(s,&w,0)))
+			goto bad;
+		if(w==0) break;
+		(void) op_gen(L,w,0,0);
+		break;
+	case 'A':
+	case 'a':
+		found=1;
+		skip(s);
+		if(*s>='0' && *s<='9')
+		{	s=gt_num(s,&w,1);
+			if(w==0) break;
+			(void) op_gen(AW,w,0,0);
+			break;
+		}
+		(void) op_gen(A,0,0,0);
+		break;
+	case 'F':
+	case 'f':
+		if (!(s=gt_num(s,&w,0)))
+			goto bad;
+		found=1;
+		if(w==0) break;
+		if(*s=='.') {
+			if (!(s=gt_num(s+1,&d,0)))
+				goto bad;
+			}
+		else d=0;
+		(void) op_gen(F,w,d,0);
+		break;
+	case 'D':
+	case 'd':
+		found=1;
+		if (!(s=gt_num(s,&w,0)))
+			goto bad;
+		if(w==0) break;
+		if(*s=='.') {
+			if (!(s=gt_num(s+1,&d,0)))
+				goto bad;
+			}
+		else d=0;
+		(void) op_gen(D,w,d,0);
+		break;
+	case 'I':
+	case 'i':
+		i = I;
+		im = IM;
+ finish_I:
+		if (!(s=gt_num(s,&w,0)))
+			goto bad;
+		found=1;
+		if(w==0) break;
+		if(*s!='.')
+		{	(void) op_gen(i,w,0,0);
+			break;
+		}
+		if (!(s=gt_num(s+1,&d,0)))
+			goto bad;
+		(void) op_gen(im,w,d,0);
+		break;
+	}
+	if(found==0)
+	{	f__pc--; /*unSTACK*/
+		*p=sv;
+		return(0);
+	}
+	*p=s;
+	return(1);
+}
+ static
+#ifdef KR_headers
+char *i_tem(s) char *s;
+#else
+const char *i_tem(const char *s)
+#endif
+{	const char *t;
+	int n,curloc;
+	if(*s==')') return(s);
+	if(ne_d(s,&t)) return(t);
+	if(e_d(s,&t)) return(t);
+	s=gt_num(s,&n,1);
+	if((curloc=op_gen(STACK,n,0,0))<0) return(NULL);
+	return(f_s(s,curloc));
+}
+
+ static
+#ifdef KR_headers
+char *f_list(s) char *s;
+#else
+const char *f_list(const char *s)
+#endif
+{
+	for(;*s!=0;)
+	{	skip(s);
+		if((s=i_tem(s))==NULL) return(NULL);
+		skip(s);
+		if(*s==',') s++;
+		else if(*s==')')
+		{	if(--f__parenlvl==0)
+			{
+				(void) op_gen(REVERT,f__revloc,0,0);
+				return(++s);
+			}
+			(void) op_gen(GOTO,0,0,0);
+			return(++s);
+		}
+	}
+	return(NULL);
+}
+
+ int
+#ifdef KR_headers
+pars_f(s) char *s;
+#else
+pars_f(const char *s)
+#endif
+{
+	f__parenlvl=f__revloc=f__pc=0;
+	if(f_s(s,0) == NULL)
+	{
+		return(-1);
+	}
+	return(0);
+}
+#define STKSZ 10
+int f__cnt[STKSZ],f__ret[STKSZ],f__cp,f__rp;
+flag f__workdone, f__nonl;
+
+ static int
+#ifdef KR_headers
+type_f(n)
+#else
+type_f(int n)
+#endif
+{
+	switch(n)
+	{
+	default:
+		return(n);
+	case RET1:
+		return(RET1);
+	case REVERT: return(REVERT);
+	case GOTO: return(GOTO);
+	case STACK: return(STACK);
+	case X:
+	case SLASH:
+	case APOS: case H:
+	case T: case TL: case TR:
+		return(NED);
+	case F:
+	case I:
+	case IM:
+	case A: case AW:
+	case O: case OM:
+	case L:
+	case E: case EE: case D:
+	case G: case GE:
+	case Z: case ZM:
+		return(ED);
+	}
+}
+#ifdef KR_headers
+integer do_fio(number,ptr,len) ftnint *number; ftnlen len; char *ptr;
+#else
+integer do_fio(ftnint *number, char *ptr, ftnlen len)
+#endif
+{	struct syl *p;
+	int n,i;
+	for(i=0;i<*number;i++,ptr+=len)
+	{
+loop:	switch(type_f((p= &f__syl[f__pc])->op))
+	{
+	default:
+		fprintf(stderr,"unknown code in do_fio: %d\n%s\n",
+			p->op,f__fmtbuf);
+		err(f__elist->cierr,100,"do_fio");
+	case NED:
+		if((*f__doned)(p))
+		{	f__pc++;
+			goto loop;
+		}
+		f__pc++;
+		continue;
+	case ED:
+		if(f__cnt[f__cp]<=0)
+		{	f__cp--;
+			f__pc++;
+			goto loop;
+		}
+		if(ptr==NULL)
+			return((*f__doend)());
+		f__cnt[f__cp]--;
+		f__workdone=1;
+		if((n=(*f__doed)(p,ptr,len))>0)
+			errfl(f__elist->cierr,errno,"fmt");
+		if(n<0)
+			err(f__elist->ciend,(EOF),"fmt");
+		continue;
+	case STACK:
+		f__cnt[++f__cp]=p->p1;
+		f__pc++;
+		goto loop;
+	case RET1:
+		f__ret[++f__rp]=p->p1;
+		f__pc++;
+		goto loop;
+	case GOTO:
+		if(--f__cnt[f__cp]<=0)
+		{	f__cp--;
+			f__rp--;
+			f__pc++;
+			goto loop;
+		}
+		f__pc=1+f__ret[f__rp--];
+		goto loop;
+	case REVERT:
+		f__rp=f__cp=0;
+		f__pc = p->p1;
+		if(ptr==NULL)
+			return((*f__doend)());
+		if(!f__workdone) return(0);
+		if((n=(*f__dorevert)()) != 0) return(n);
+		goto loop;
+	case COLON:
+		if(ptr==NULL)
+			return((*f__doend)());
+		f__pc++;
+		goto loop;
+	case NONL:
+		f__nonl = 1;
+		f__pc++;
+		goto loop;
+	case S:
+	case SS:
+		f__cplus=0;
+		f__pc++;
+		goto loop;
+	case SP:
+		f__cplus = 1;
+		f__pc++;
+		goto loop;
+	case P:	f__scale=p->p1;
+		f__pc++;
+		goto loop;
+	case BN:
+		f__cblank=0;
+		f__pc++;
+		goto loop;
+	case BZ:
+		f__cblank=1;
+		f__pc++;
+		goto loop;
+	}
+	}
+	return(0);
+}
+
+ int
+en_fio(Void)
+{	ftnint one=1;
+	return(do_fio(&one,(char *)NULL,(ftnint)0));
+}
+
+ VOID
+fmt_bg(Void)
+{
+	f__workdone=f__cp=f__rp=f__pc=f__cursor=0;
+	f__cnt[0]=f__ret[0]=0;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/fmt.h b/src/f2c/fmt.h
new file mode 100644
index 0000000..ddfa551
--- /dev/null
+++ b/src/f2c/fmt.h
@@ -0,0 +1,105 @@
+struct syl
+{	int op;
+	int p1;
+	union { int i[2]; char *s;} p2;
+	};
+#define RET1 1
+#define REVERT 2
+#define GOTO 3
+#define X 4
+#define SLASH 5
+#define STACK 6
+#define I 7
+#define ED 8
+#define NED 9
+#define IM 10
+#define APOS 11
+#define H 12
+#define TL 13
+#define TR 14
+#define T 15
+#define COLON 16
+#define S 17
+#define SP 18
+#define SS 19
+#define P 20
+#define BN 21
+#define BZ 22
+#define F 23
+#define E 24
+#define EE 25
+#define D 26
+#define G 27
+#define GE 28
+#define L 29
+#define A 30
+#define AW 31
+#define O 32
+#define NONL 33
+#define OM 34
+#define Z 35
+#define ZM 36
+typedef union
+{	real pf;
+	doublereal pd;
+} ufloat;
+typedef union
+{	short is;
+#ifndef KR_headers
+	signed
+#endif
+		char ic;
+	integer il;
+#ifdef Allow_TYQUAD
+	longint ili;
+#endif
+} Uint;
+#ifdef KR_headers
+extern int (*f__doed)(),(*f__doned)();
+extern int (*f__dorevert)();
+extern int rd_ed(),rd_ned();
+extern int w_ed(),w_ned();
+extern int signbit_f2c();
+extern char *f__fmtbuf;
+#else
+#ifdef __cplusplus
+extern "C" {
+#define Cextern extern "C"
+#else
+#define Cextern extern
+#endif
+extern const char *f__fmtbuf;
+extern int (*f__doed)(struct syl*, char*, ftnlen),(*f__doned)(struct syl*);
+extern int (*f__dorevert)(void);
+extern void fmt_bg(void);
+extern int pars_f(const char*);
+extern int rd_ed(struct syl*, char*, ftnlen),rd_ned(struct syl*);
+extern int signbit_f2c(double*);
+extern int w_ed(struct syl*, char*, ftnlen),w_ned(struct syl*);
+extern int wrt_E(ufloat*, int, int, int, ftnlen);
+extern int wrt_F(ufloat*, int, int, ftnlen);
+extern int wrt_L(Uint*, int, ftnlen);
+#endif
+extern int f__pc,f__parenlvl,f__revloc;
+extern flag f__cblank,f__cplus,f__workdone, f__nonl;
+extern int f__scale;
+#ifdef __cplusplus
+	}
+#endif
+#define GET(x) if((x=(*f__getn)())<0) return(x)
+#define VAL(x) (x!='\n'?x:' ')
+#define PUT(x) (*f__putn)(x)
+
+#undef TYQUAD
+#ifndef Allow_TYQUAD
+#undef longint
+#define longint long
+#else
+#define TYQUAD 14
+#endif
+
+#ifdef KR_headers
+extern char *f__icvt();
+#else
+Cextern char *f__icvt(longint, int*, int*, int);
+#endif
diff --git a/src/f2c/fmtlib.c b/src/f2c/fmtlib.c
new file mode 100644
index 0000000..279f66f
--- /dev/null
+++ b/src/f2c/fmtlib.c
@@ -0,0 +1,51 @@
+/*	@(#)fmtlib.c	1.2	*/
+#define MAXINTLENGTH 23
+
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifndef Allow_TYQUAD
+#undef longint
+#define longint long
+#undef ulongint
+#define ulongint unsigned long
+#endif
+
+#ifdef KR_headers
+char *f__icvt(value,ndigit,sign, base) longint value; int *ndigit,*sign;
+ register int base;
+#else
+char *f__icvt(longint value, int *ndigit, int *sign, int base)
+#endif
+{
+	static char buf[MAXINTLENGTH+1];
+	register int i;
+	ulongint uvalue;
+
+	if(value > 0) {
+		uvalue = value;
+		*sign = 0;
+		}
+	else if (value < 0) {
+		uvalue = -value;
+		*sign = 1;
+		}
+	else {
+		*sign = 0;
+		*ndigit = 1;
+		buf[MAXINTLENGTH-1] = '0';
+		return &buf[MAXINTLENGTH-1];
+		}
+	i = MAXINTLENGTH;
+	do {
+		buf[--i] = (uvalue%base) + '0';
+		uvalue /= base;
+		}
+		while(uvalue > 0);
+	*ndigit = MAXINTLENGTH - i;
+	return &buf[i];
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/fp.h b/src/f2c/fp.h
new file mode 100644
index 0000000..40743d7
--- /dev/null
+++ b/src/f2c/fp.h
@@ -0,0 +1,28 @@
+#define FMAX 40
+#define EXPMAXDIGS 8
+#define EXPMAX 99999999
+/* FMAX = max number of nonzero digits passed to atof() */
+/* EXPMAX = 10^EXPMAXDIGS - 1 = largest allowed exponent absolute value */
+
+#ifdef V10 /* Research Tenth-Edition Unix */
+#include "local.h"
+#endif
+
+/* MAXFRACDIGS and MAXINTDIGS are for wrt_F -- bounds (not necessarily
+   tight) on the maximum number of digits to the right and left of
+ * the decimal point.
+ */
+
+#ifdef VAX
+#define MAXFRACDIGS 56
+#define MAXINTDIGS 38
+#else
+#ifdef CRAY
+#define MAXFRACDIGS 9880
+#define MAXINTDIGS 9864
+#else
+/* values that suffice for IEEE double */
+#define MAXFRACDIGS 344
+#define MAXINTDIGS 308
+#endif
+#endif
diff --git a/src/f2c/ftell_.c b/src/f2c/ftell_.c
new file mode 100644
index 0000000..0acd60f
--- /dev/null
+++ b/src/f2c/ftell_.c
@@ -0,0 +1,52 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ static FILE *
+#ifdef KR_headers
+unit_chk(Unit, who) integer Unit; char *who;
+#else
+unit_chk(integer Unit, const char *who)
+#endif
+{
+	if (Unit >= MXUNIT || Unit < 0)
+		f__fatal(101, who);
+	return f__units[Unit].ufd;
+	}
+
+ integer
+#ifdef KR_headers
+ftell_(Unit) integer *Unit;
+#else
+ftell_(integer *Unit)
+#endif
+{
+	FILE *f;
+	return (f = unit_chk(*Unit, "ftell")) ? ftell(f) : -1L;
+	}
+
+ int
+#ifdef KR_headers
+fseek_(Unit, offset, whence) integer *Unit, *offset, *whence;
+#else
+fseek_(integer *Unit, integer *offset, integer *whence)
+#endif
+{
+	FILE *f;
+	int w = (int)*whence;
+#ifdef SEEK_SET
+	static int wohin[3] = { SEEK_SET, SEEK_CUR, SEEK_END };
+#endif
+	if (w < 0 || w > 2)
+		w = 0;
+#ifdef SEEK_SET
+	w = wohin[w];
+#endif
+	return	!(f = unit_chk(*Unit, "fseek"))
+		|| fseek(f, *offset, w) ? 1 : 0;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/getenv_.c b/src/f2c/getenv_.c
new file mode 100644
index 0000000..b615a37
--- /dev/null
+++ b/src/f2c/getenv_.c
@@ -0,0 +1,62 @@
+#include "f2c.h"
+#undef abs
+#ifdef KR_headers
+extern char *F77_aloc(), *getenv();
+#else
+#include <stdlib.h>
+#include <string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern char *F77_aloc(ftnlen, const char*);
+#endif
+
+/*
+ * getenv - f77 subroutine to return environment variables
+ *
+ * called by:
+ *	call getenv (ENV_NAME, char_var)
+ * where:
+ *	ENV_NAME is the name of an environment variable
+ *	char_var is a character variable which will receive
+ *		the current value of ENV_NAME, or all blanks
+ *		if ENV_NAME is not defined
+ */
+
+#ifdef KR_headers
+ VOID
+getenv_(fname, value, flen, vlen) char *value, *fname; ftnlen vlen, flen;
+#else
+ void
+getenv_(char *fname, char *value, ftnlen flen, ftnlen vlen)
+#endif
+{
+	char buf[256], *ep, *fp;
+	integer i;
+
+	if (flen <= 0)
+		goto add_blanks;
+	for(i = 0; i < sizeof(buf); i++) {
+		if (i == flen || (buf[i] = fname[i]) == ' ') {
+			buf[i] = 0;
+			ep = getenv(buf);
+			goto have_ep;
+			}
+		}
+	while(i < flen && fname[i] != ' ')
+		i++;
+	strncpy(fp = F77_aloc(i+1, "getenv_"), fname, (int)i);
+	fp[i] = 0;
+	ep = getenv(fp);
+	free(fp);
+ have_ep:
+	if (ep)
+		while(*ep && vlen-- > 0)
+			*value++ = *ep++;
+ add_blanks:
+	while(vlen-- > 0)
+		*value++ = ' ';
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_abs.c b/src/f2c/h_abs.c
new file mode 100644
index 0000000..db69068
--- /dev/null
+++ b/src/f2c/h_abs.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint h_abs(x) shortint *x;
+#else
+shortint h_abs(shortint *x)
+#endif
+{
+if(*x >= 0)
+	return(*x);
+return(- *x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_dim.c b/src/f2c/h_dim.c
new file mode 100644
index 0000000..443427a
--- /dev/null
+++ b/src/f2c/h_dim.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint h_dim(a,b) shortint *a, *b;
+#else
+shortint h_dim(shortint *a, shortint *b)
+#endif
+{
+return( *a > *b ? *a - *b : 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_dnnt.c b/src/f2c/h_dnnt.c
new file mode 100644
index 0000000..1ec641c
--- /dev/null
+++ b/src/f2c/h_dnnt.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+shortint h_dnnt(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+shortint h_dnnt(doublereal *x)
+#endif
+{
+return (shortint)(*x >= 0. ? floor(*x + .5) : -floor(.5 - *x));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_indx.c b/src/f2c/h_indx.c
new file mode 100644
index 0000000..018f2f4
--- /dev/null
+++ b/src/f2c/h_indx.c
@@ -0,0 +1,32 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint h_indx(a, b, la, lb) char *a, *b; ftnlen la, lb;
+#else
+shortint h_indx(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+ftnlen i, n;
+char *s, *t, *bend;
+
+n = la - lb + 1;
+bend = b + lb;
+
+for(i = 0 ; i < n ; ++i)
+	{
+	s = a + i;
+	t = b;
+	while(t < bend)
+		if(*s++ != *t++)
+			goto no;
+	return((shortint)i+1);
+	no: ;
+	}
+return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_len.c b/src/f2c/h_len.c
new file mode 100644
index 0000000..8b0aea9
--- /dev/null
+++ b/src/f2c/h_len.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint h_len(s, n) char *s; ftnlen n;
+#else
+shortint h_len(char *s, ftnlen n)
+#endif
+{
+return(n);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_mod.c b/src/f2c/h_mod.c
new file mode 100644
index 0000000..611ef0a
--- /dev/null
+++ b/src/f2c/h_mod.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint h_mod(a,b) short *a, *b;
+#else
+shortint h_mod(short *a, short *b)
+#endif
+{
+return( *a % *b);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_nint.c b/src/f2c/h_nint.c
new file mode 100644
index 0000000..9e2282f
--- /dev/null
+++ b/src/f2c/h_nint.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+shortint h_nint(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+shortint h_nint(real *x)
+#endif
+{
+return (shortint)(*x >= 0 ? floor(*x + .5) : -floor(.5 - *x));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/h_sign.c b/src/f2c/h_sign.c
new file mode 100644
index 0000000..4e21438
--- /dev/null
+++ b/src/f2c/h_sign.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint h_sign(a,b) shortint *a, *b;
+#else
+shortint h_sign(shortint *a, shortint *b)
+#endif
+{
+shortint x;
+x = (*a >= 0 ? *a : - *a);
+return( *b >= 0 ? x : -x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/hl_ge.c b/src/f2c/hl_ge.c
new file mode 100644
index 0000000..8c72f03
--- /dev/null
+++ b/src/f2c/hl_ge.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+shortlogical hl_ge(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+shortlogical hl_ge(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) >= 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/hl_gt.c b/src/f2c/hl_gt.c
new file mode 100644
index 0000000..a448522
--- /dev/null
+++ b/src/f2c/hl_gt.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+shortlogical hl_gt(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+shortlogical hl_gt(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) > 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/hl_le.c b/src/f2c/hl_le.c
new file mode 100644
index 0000000..31cbc43
--- /dev/null
+++ b/src/f2c/hl_le.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+shortlogical hl_le(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+shortlogical hl_le(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) <= 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/hl_lt.c b/src/f2c/hl_lt.c
new file mode 100644
index 0000000..7ad3c71
--- /dev/null
+++ b/src/f2c/hl_lt.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+shortlogical hl_lt(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+shortlogical hl_lt(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) < 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i77vers.c b/src/f2c/i77vers.c
new file mode 100644
index 0000000..60cc24e
--- /dev/null
+++ b/src/f2c/i77vers.c
@@ -0,0 +1,343 @@
+ char
+_libi77_version_f2c[] = "\n@(#) LIBI77 VERSION (f2c) pjw,dmg-mods 20030321\n";
+
+/*
+2.01	$ format added
+2.02	Coding bug in open.c repaired
+2.03	fixed bugs in lread.c (read * with negative f-format) and lio.c
+	and lio.h (e-format conforming to spec)
+2.04	changed open.c and err.c (fopen and freopen respectively) to
+	update to new c-library (append mode)
+2.05	added namelist capability
+2.06	allow internal list and namelist I/O
+*/
+
+/*
+close.c:
+	allow upper-case STATUS= values
+endfile.c
+	create fort.nnn if unit nnn not open;
+	else if (file length == 0) use creat() rather than copy;
+	use local copy() rather than forking /bin/cp;
+	rewind, fseek to clear buffer (for no reading past EOF)
+err.c
+	use neither setbuf nor setvbuf; make stderr buffered
+fio.h
+	#define _bufend
+inquire.c
+	upper case responses;
+	omit byfile test from SEQUENTIAL=
+	answer "YES" to DIRECT= for unopened file (open to debate)
+lio.c
+	flush stderr, stdout at end of each stmt
+	space before character strings in list output only at line start
+lio.h
+	adjust LEW, LED consistent with old libI77
+lread.c
+	use atof()
+	allow "nnn*," when reading complex constants
+open.c
+	try opening for writing when open for read fails, with
+	special uwrt value (2) delaying creat() to first write;
+	set curunit so error messages don't drop core;
+	no file name ==> fort.nnn except for STATUS='SCRATCH'
+rdfmt.c
+	use atof(); trust EOF == end-of-file (so don't read past
+	end-of-file after endfile stmt)
+sfe.c
+	flush stderr, stdout at end of each stmt
+wrtfmt.c:
+	use upper case
+	put wrt_E and wrt_F into wref.c, use sprintf()
+		rather than ecvt() and fcvt() [more accurate on VAX]
+*/
+
+/* 16 Oct. 1988: uwrt = 3 after write, rewind, so close won't zap the file. */
+
+/* 10 July 1989: change _bufend to buf_end in fio.h, wsfe.c, wrtfmt.c */
+
+/* 28 Nov. 1989: corrections for IEEE and Cray arithmetic */
+/* 29 Nov. 1989: change various int return types to long for f2c */
+/* 30 Nov. 1989: various types from f2c.h */
+/*  6 Dec. 1989: types corrected various places */
+/* 19 Dec. 1989: make iostat= work right for internal I/O */
+/*  8 Jan. 1990: add rsne, wsne -- routines for handling NAMELIST */
+/* 28 Jan. 1990: have NAMELIST read treat $ as &, general white
+		 space as blank */
+/* 27 Mar. 1990: change an = to == in rd_L(rdfmt.c) so formatted reads
+		 of logical values reject letters other than fFtT;
+		 have nowwriting reset cf */
+/* 14 Aug. 1990: adjust lread.c to treat tabs as spaces in list input */
+/* 17 Aug. 1990: adjust open.c to recognize blank='Z...' as well as
+		 blank='z...' when reopening an open file */
+/* 30 Aug. 1990: prevent embedded blanks in list output of complex values;
+		 omit exponent field in list output of values of
+		 magnitude between 10 and 1e8; prevent writing stdin
+		 and reading stdout or stderr; don't close stdin, stdout,
+		 or stderr when reopening units 5, 6, 0. */
+/* 18 Sep. 1990: add component udev to unit and consider old == new file
+		 iff uinode and udev values agree; use stat rather than
+		 access to check existence of file (when STATUS='OLD')*/
+/* 2 Oct. 1990:  adjust rewind.c so two successive rewinds after a write
+		 don't clobber the file. */
+/* 9 Oct. 1990:  add #include "fcntl.h" to endfile.c, err.c, open.c;
+		 adjust g_char in util.c for segmented memories. */
+/* 17 Oct. 1990: replace abort() and _cleanup() with calls on
+		 sig_die(...,1) (defined in main.c). */
+/* 5 Nov. 1990:  changes to open.c: complain if new= is specified and the
+		 file already exists; allow file= to be omitted in open stmts
+		 and allow status='replace' (Fortran 90 extensions). */
+/* 11 Dec. 1990: adjustments for POSIX. */
+/* 15 Jan. 1991: tweak i_ungetc in rsli.c to allow reading from
+		 strings in read-only memory. */
+/* 25 Apr. 1991: adjust namelist stuff to work with f2c -i2 */
+/* 26 Apr. 1991: fix some bugs with NAMELIST read of multi-dim. arrays */
+/* 16 May 1991:  increase LEFBL in lio.h to bypass NeXT bug */
+/* 17 Oct. 1991: change type of length field in sequential unformatted
+		 records from int to long (for systems where sizeof(int)
+		 can vary, depending on the compiler or compiler options). */
+/* 14 Nov. 1991: change uint to Uint in fmt.h, rdfmt.c, wrtfmt.c. */
+/* 25 Nov. 1991: change uint to Uint in lwrite.c; change sizeof(int) to
+		 sizeof(uioint) in fseeks in sue.c (missed on 17 Oct.). */
+/* 1 Dec. 1991:  uio.c: add test for read failure (seq. unformatted reads);
+		 adjust an error return from EOF to off end of record */
+/* 12 Dec. 1991: rsli.c: fix bug with internal list input that caused
+		 the last character of each record to be ignored.
+		 iio.c: adjust error message in internal formatted
+		 input from "end-of-file" to "off end of record" if
+		 the format specifies more characters than the
+		 record contains. */
+/* 17 Jan. 1992: lread.c, rsne.c: in list and namelist input,
+		 treat "r* ," and "r*," alike (where r is a
+		 positive integer constant), and fix a bug in
+		 handling null values following items with repeat
+		 counts (e.g., 2*1,,3); for namelist reading
+		 of a numeric array, allow a new name-value subsequence
+		 to terminate the current one (as though the current
+		 one ended with the right number of null values).
+		 lio.h, lwrite.c: omit insignificant zeros in
+		 list and namelist output. To get the old
+		 behavior, compile with -DOld_list_output . */
+/* 18 Jan. 1992: make list output consistent with F format by
+		 printing .1 rather than 0.1 (introduced yesterday). */
+/* 3 Feb. 1992:  rsne.c: fix namelist read bug that caused the
+		 character following a comma to be ignored. */
+/* 19 May 1992:  adjust iio.c, ilnw.c, rdfmt.c and rsli.c to make err=
+		 work with internal list and formatted I/O. */
+/* 18 July 1992: adjust rsne.c to allow namelist input to stop at
+		 an & (e.g. &end). */
+/* 23 July 1992: switch to ANSI prototypes unless KR_headers is #defined ;
+		 recognize Z format (assuming 8-bit bytes). */
+/* 14 Aug. 1992: tweak wrt_E in wref.c to avoid -NaN */
+/* 23 Oct. 1992: Supply missing l_eof = 0 assignment to s_rsne() in rsne.c
+		 (so end-of-file on other files won't confuse namelist
+		 reads of external files).  Prepend f__ to external
+		 names that are only of internal interest to lib[FI]77. */
+/* 1 Feb. 1993:  backspace.c: fix bug that bit when last char of 2nd
+		 buffer == '\n'.
+		 endfile.c: guard against tiny L_tmpnam; close and reopen
+		 files in t_runc().
+		 lio.h: lengthen LINTW (buffer size in lwrite.c).
+		 err.c, open.c: more prepending of f__ (to [rw]_mode). */
+/* 5 Feb. 1993:  tweaks to NAMELIST: rsne.c: ? prints the namelist being
+		 sought; namelists of the wrong name are skipped (after
+		 an error message; xwsne.c: namelist writes have a
+		 newline before each new variable.
+		 open.c: ACCESS='APPEND' positions sequential files
+		 at EOF (nonstandard extension -- that doesn't require
+		 changing data structures). */
+/* 9 Feb. 1993:  Change some #ifdef MSDOS lines to #ifdef NON_UNIX_STDIO.
+		 err.c: under NON_UNIX_STDIO, avoid close(creat(name,0666))
+		 when the unit has another file descriptor for name. */
+/* 4 March 1993: err.c, open.c: take declaration of fdopen from rawio.h;
+		 open.c: always give f__w_mode[] 4 elements for use
+		 in t_runc (in endfile.c -- for change of 1 Feb. 1993). */
+/* 6 March 1993: uio.c: adjust off-end-of-record test for sequential
+		 unformatted reads to respond to err= rather than end=. */
+/* 12 March 1993: various tweaks for C++ */
+/* 6 April 1993: adjust error returns for formatted inputs to flush
+		 the current input line when err=label is specified.
+		 To restore the old behavior (input left mid-line),
+		 either adjust the #definition of errfl in fio.h or
+		 omit the invocation of f__doend in err__fl (in err.c).	*/
+/* 23 June 1993: iio.c: fix bug in format reversions for internal writes. */
+/* 5 Aug. 1993:  lread.c: fix bug in handling repetition counts for
+		 logical data (during list or namelist input).
+		 Change struct f__syl to struct syl (for buggy compilers). */
+/* 7 Aug. 1993:  lread.c: fix bug in namelist reading of incomplete
+		 logical arrays. */
+/* 9 Aug. 1993:  lread.c: fix bug in namelist reading of an incomplete
+		 array of numeric data followed by another namelist
+		 item whose name starts with 'd', 'D', 'e', or 'E'. */
+/* 8 Sept. 1993: open.c: protect #include "sys/..." with
+		 #ifndef NON_UNIX_STDIO; Version date not changed. */
+/* 10 Nov. 1993: backspace.c: add nonsense for #ifdef MSDOS */
+/* 8 Dec. 1993:  iio.c: adjust internal formatted reads to treat
+		 short records as though padded with blanks
+		 (rather than causing an "off end of record" error). */
+/* 22 Feb. 1994: lread.c: check that realloc did not return NULL. */
+/* 6 June 1994:  Under NON_UNIX_STDIO, use binary mode for direct
+		 formatted files (avoiding any confusion regarding \n). */
+/* 5 July 1994:  Fix bug (introduced 6 June 1994?) in reopening files
+		 under NON_UNIX_STDIO. */
+/* 6 July 1994:  wref.c: protect with #ifdef GOOD_SPRINTF_EXPONENT an
+		 optimization that requires exponents to have 2 digits
+		 when 2 digits suffice.
+		 lwrite.c wsfe.c (list and formatted external output):
+		 omit ' ' carriage-control when compiled with
+		 -DOMIT_BLANK_CC .  Off-by-one bug fixed in character
+		 count for list output of character strings.
+		 Omit '.' in list-directed printing of Nan, Infinity. */
+/* 12 July 1994: wrtfmt.c: under G11.4, write 0. as "  .0000    " rather
+		 than "  .0000E+00". */
+/* 3 Aug. 1994:  lwrite.c: do not insert a newline when appending an
+		 oversize item to an empty line. */
+/* 12 Aug. 1994: rsli.c rsne.c: fix glitch (reset nml_read) that kept
+		 ERR= (in list- or format-directed input) from working
+		 after a NAMELIST READ. */
+/* 7 Sept. 1994: typesize.c: adjust to allow types LOGICAL*1, LOGICAL*2,
+		 INTEGER*1, and (under -DAllow_TYQUAD) INTEGER*8
+		 in NAMELISTs. */
+/* 6 Oct. 1994:  util.c: omit f__mvgbt, as it is never used. */
+/* 2 Nov. 1994:  add #ifdef ALWAYS_FLUSH logic. */
+/* 26 Jan. 1995: wref.c: fix glitch in printing the exponent of 0 when
+		 GOOD_SPRINTF_EXPONENT is not #defined. */
+/* 24 Feb. 1995: iio.c: z_getc: insert (unsigned char *) to allow
+		 internal reading of characters with high-bit set
+		 (on machines that sign-extend characters). */
+/* 14 March 1995:lread.c and rsfe.c: adjust s_rsle and s_rsfe to
+		 check for end-of-file (to prevent infinite loops
+		 with empty read statements). */
+/* 26 May 1995:  iio.c: z_wnew: fix bug in handling T format items
+		 in internal writes whose last item is written to
+		 an earlier position than some previous item. */
+/* 29 Aug. 1995: backspace.c: adjust MSDOS logic. */
+/* 6 Sept. 1995: Adjust namelist input to treat a subscripted name
+		 whose subscripts do not involve colons similarly
+		 to the name without a subscript: accept several
+		 values, stored in successive elements starting at
+		 the indicated subscript.  Adjust namelist output
+		 to quote character strings (avoiding confusion with
+		 arrays of character strings).  Adjust f_init calls
+		 for people who don't use libF77's main(); now open and
+		 namelist read statements invoke f_init if needed. */
+/* 7 Sept. 1995: Fix some bugs with -DAllow_TYQUAD (for integer*8).
+		 Add -DNo_Namelist_Comments lines to rsne.c. */
+/* 5 Oct. 1995:  wrtfmt.c: fix bug with t editing (f__cursor was not
+		 always zeroed in mv_cur). */
+/* 11 Oct. 1995: move defs of f__hiwater, f__svic, f__icptr from wrtfmt.c
+		 to err.c */
+/* 15 Mar. 1996: lread.c, rsfe.c: honor END= in READ stmt with empty iolist */
+
+/* 13 May 1996:  add ftell_.c and fseek_.c */
+/* 9 June 1996:  Adjust rsli.c and lread.c so internal list input with
+		 too few items in the input string will honor end= . */
+/* 12 Sept. 1995:fmtlib.c: fix glitch in printing the most negative integer. */
+/* 25 Sept. 1995:fmt.h: for formatted writes of negative integer*1 values,
+		 make ic signed on ANSI systems.  If formatted writes of
+		 integer*1 values trouble you when using a K&R C compiler,
+		 switch to an ANSI compiler or use a compiler flag that
+		 makes characters signed. */
+/* 9 Dec. 1996:	 d[fu]e.c, err.c: complain about non-positive rec=
+		 in direct read and write statements.
+		 ftell_.c: change param "unit" to "Unit" for -DKR_headers. */
+/* 26 Feb. 1997: ftell_.c: on systems that define SEEK_SET, etc., use
+		 SEEK_SET, SEEK_CUR, SEEK_END for *whence = 0, 1, 2. */
+/* 7 Apr. 1997:	 fmt.c: adjust to complain at missing numbers in formats
+		 (but still treat missing ".nnn" as ".0"). */
+/* 11 Apr. 1997: err.c: attempt to make stderr line buffered rather
+		 than fully buffered.  (Buffering is needed for format
+		 items T and TR.) */
+/* 27 May 1997:  ftell_.c: fix typo (that caused the third argument to be
+		 treated as 2 on some systems). */
+/* 5 Aug. 1997:  lread.c: adjust to accord with a change to the Fortran 8X
+		 draft (in 1990 or 1991) that rescinded permission to elide
+		 quote marks in namelist input of character data; compile
+		 with -DF8X_NML_ELIDE_QUOTES to get the old behavior.
+		 wrtfmt.o: wrt_G: tweak to print the right number of 0's
+		 for zero under G format. */
+/* 16 Aug. 1997: iio.c: fix bug in internal writes to an array of character
+		 strings that sometimes caused one more array element than
+		 required by the format to be blank-filled.  Example:
+		 format(1x). */
+/* 16 Sept. 1997:fmt.[ch] rdfmt.c wrtfmt.c: tweak struct syl for machines
+		 with 64-bit pointers and 32-bit ints that did not 64-bit
+		 align struct syl (e.g., Linux on the DEC Alpha). */
+/* 19 Jan. 1998: backspace.c: for b->ufmt==0, change sizeof(int) to
+		 sizeof(uiolen).  On machines where this would make a
+		 difference, it is best for portability to compile libI77 with
+		 -DUIOLEN_int (which will render the change invisible). */
+/* 4 March 1998: open.c: fix glitch in comparing file names under
+		-DNON_UNIX_STDIO */
+/* 17 March 1998: endfile.c, open.c: acquire temporary files from tmpfile(),
+		 unless compiled with -DNON_ANSI_STDIO, which uses mktemp().
+		 New buffering scheme independent of NON_UNIX_STDIO for
+		 handling T format items.  Now -DNON_UNIX_STDIO is no
+		 longer be necessary for Linux, and libf2c no longer
+		 causes stderr to be buffered -- the former setbuf or
+		 setvbuf call for stderr was to make T format items work.
+		 open.c: use the Posix access() function to check existence
+		 or nonexistence of files, except under -DNON_POSIX_STDIO,
+		 where trial fopen calls are used. */
+/* 5 April 1998: wsfe.c: make $ format item work: this was lost in the
+		 changes of 17 March 1998. */
+/* 28 May 1998:	 backspace.c dfe.c due.c iio.c lread.c rsfe.c sue.c wsfe.c:
+		 set f__curunit sooner so various error messages will
+		 correctly identify the I/O unit involved. */
+/* 17 June 1998: lread.c: unless compiled with
+		 ALLOW_FLOAT_IN_INTEGER_LIST_INPUT #defined, treat
+		 floating-point numbers (containing either a decimal point
+		 or an exponent field) as errors when they appear as list
+		 input for integer data. */
+/* 7 Sept. 1998: move e_wdfe from sfe.c to dfe.c, where it was originally.
+		 Why did it ever move to sfe.c? */
+/* 2 May 1999:	 open.c: set f__external (to get "external" versus "internal"
+		 right in the error message if we cannot open the file).
+		 err.c: cast a pointer difference to (int) for %d.
+		 rdfmt.c: omit fixed-length buffer that could be overwritten
+		 by formats Inn or Lnn with nn > 83. */
+/* 3 May 1999:	open.c: insert two casts for machines with 64-bit longs. */
+/* 18 June 1999: backspace.c: allow for b->ufd changing in t_runc */
+/* 27 June 1999: rsne.c: fix bug in namelist input: a misplaced increment */
+/*		 could cause wrong array elements to be assigned; e.g.,	*/
+/*		 "&input k(5)=10*1 &end" assigned k(5) and k(15..23)	*/
+/* 15 Nov. 1999: endfile.c: set state to writing (b->uwrt = 1) when an */
+/*		endfile statement requires copying the file. */
+/*		(Otherwise an immediately following rewind statement */
+/*		could make the file appear empty.)  Also, supply a */
+/*		missing (long) cast in the sprintf call. */
+/*		 sfe.c: add #ifdef ALWAYS_FLUSH logic, for formatted I/O: */
+/*		Compiling libf2c with -DALWAYS_FLUSH should prevent losing */
+/*		any data in buffers should the program fault.  It also */
+/*		makes the program run more slowly. */
+/* 20 April 2000: rsne.c, xwsne.c: tweaks that only matter if ftnint and */
+/*		ftnlen are of different fundamental types (different numbers */
+/*		of bits).  Since these files will not compile when this */
+/*		change matters, the above VERSION string remains unchanged. */
+/* 4 July 2000: adjustments to permit compilation by C++ compilers; */
+/*		VERSION string remains unchanged. */
+/* 5 Dec. 2000: lread.c: under namelist input, when reading a logical array, */
+/*		treat Tstuff= and Fstuff= as new assignments rather than as */
+/*		logical constants. */
+/* 22 Feb. 2001: endfile.c: adjust to use truncate() unless compiled with */
+/*		-DNO_TRUNCATE (or with -DMSDOS). */
+/* 1 March 2001: endfile.c:  switch to ftruncate (absent -DNO_TRUNCATE), */
+/*		thus permitting truncation of scratch files on true Unix */
+/*		systems, where scratch files have no name.  Add an fflush() */
+/*		(surprisingly) needed on some Linux systems. */
+/* 11 Oct. 2001: backspac.c dfe.c due.c endfile.c err.c fio.h fmt.c fmt.h */
+/*		inquire.c open.c rdfmt.c sue.c util.c: change fseek and */
+/*		ftell to FSEEK and FTELL (#defined to be fseek and ftell, */
+/*		respectively, in fio.h unless otherwise #defined), and use */
+/*		type OFF_T (#defined to be long unless otherwise #defined) */
+/*		to permit handling files over 2GB long where possible, */
+/*		with suitable -D options, provided for some systems in new */
+/*		header file sysdep1.h (copied from sysdep1.h0 by default). */
+/* 15 Nov. 2001: endfile.c: add FSEEK after FTRUNCATE. */
+/* 28 Nov. 2001: fmt.h lwrite.c wref.c and (new) signbit.c: on IEEE systems, */
+/*		print -0 as -0 when compiled with -DSIGNED_ZEROS.  See */
+/*		comments in makefile or (better) libf2c/makefile.* . */
+/* 6 Sept. 2002: rsne.c: fix bug with multiple repeat counts in reading */
+/*		namelists, e.g., &nl a(2) = 3*1.0, 2*2.0, 3*3.0 /  */
+/* 21 March 2003: err.c: before writing to a file after reading from it, */
+/*		f_seek(file, 0, SEEK_CUR) to make writing legal in ANSI C. */
diff --git a/src/f2c/i_abs.c b/src/f2c/i_abs.c
new file mode 100644
index 0000000..2b92c4a
--- /dev/null
+++ b/src/f2c/i_abs.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer i_abs(x) integer *x;
+#else
+integer i_abs(integer *x)
+#endif
+{
+if(*x >= 0)
+	return(*x);
+return(- *x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_dim.c b/src/f2c/i_dim.c
new file mode 100644
index 0000000..60ed4d8
--- /dev/null
+++ b/src/f2c/i_dim.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer i_dim(a,b) integer *a, *b;
+#else
+integer i_dim(integer *a, integer *b)
+#endif
+{
+return( *a > *b ? *a - *b : 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_dnnt.c b/src/f2c/i_dnnt.c
new file mode 100644
index 0000000..3abc2dc
--- /dev/null
+++ b/src/f2c/i_dnnt.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+integer i_dnnt(x) doublereal *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+integer i_dnnt(doublereal *x)
+#endif
+{
+return (integer)(*x >= 0. ? floor(*x + .5) : -floor(.5 - *x));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_indx.c b/src/f2c/i_indx.c
new file mode 100644
index 0000000..1925639
--- /dev/null
+++ b/src/f2c/i_indx.c
@@ -0,0 +1,32 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer i_indx(a, b, la, lb) char *a, *b; ftnlen la, lb;
+#else
+integer i_indx(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+ftnlen i, n;
+char *s, *t, *bend;
+
+n = la - lb + 1;
+bend = b + lb;
+
+for(i = 0 ; i < n ; ++i)
+	{
+	s = a + i;
+	t = b;
+	while(t < bend)
+		if(*s++ != *t++)
+			goto no;
+	return(i+1);
+	no: ;
+	}
+return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_len.c b/src/f2c/i_len.c
new file mode 100644
index 0000000..0f7b188
--- /dev/null
+++ b/src/f2c/i_len.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer i_len(s, n) char *s; ftnlen n;
+#else
+integer i_len(char *s, ftnlen n)
+#endif
+{
+return(n);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_mod.c b/src/f2c/i_mod.c
new file mode 100644
index 0000000..4a9b560
--- /dev/null
+++ b/src/f2c/i_mod.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer i_mod(a,b) integer *a, *b;
+#else
+integer i_mod(integer *a, integer *b)
+#endif
+{
+return( *a % *b);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_nint.c b/src/f2c/i_nint.c
new file mode 100644
index 0000000..fe9fd68
--- /dev/null
+++ b/src/f2c/i_nint.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+integer i_nint(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+integer i_nint(real *x)
+#endif
+{
+return (integer)(*x >= 0 ? floor(*x + .5) : -floor(.5 - *x));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/i_sign.c b/src/f2c/i_sign.c
new file mode 100644
index 0000000..4c20e94
--- /dev/null
+++ b/src/f2c/i_sign.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer i_sign(a,b) integer *a, *b;
+#else
+integer i_sign(integer *a, integer *b)
+#endif
+{
+integer x;
+x = (*a >= 0 ? *a : - *a);
+return( *b >= 0 ? x : -x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/iio.c b/src/f2c/iio.c
new file mode 100644
index 0000000..8553efc
--- /dev/null
+++ b/src/f2c/iio.c
@@ -0,0 +1,159 @@
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern char *f__icptr;
+char *f__icend;
+extern icilist *f__svic;
+int f__icnum;
+
+ int
+z_getc(Void)
+{
+	if(f__recpos++ < f__svic->icirlen) {
+		if(f__icptr >= f__icend) err(f__svic->iciend,(EOF),"endfile");
+		return(*(unsigned char *)f__icptr++);
+		}
+	return '\n';
+}
+
+ void
+#ifdef KR_headers
+z_putc(c)
+#else
+z_putc(int c)
+#endif
+{
+	if (f__icptr < f__icend && f__recpos++ < f__svic->icirlen)
+		*f__icptr++ = c;
+}
+
+ int
+z_rnew(Void)
+{
+	f__icptr = f__svic->iciunit + (++f__icnum)*f__svic->icirlen;
+	f__recpos = 0;
+	f__cursor = 0;
+	f__hiwater = 0;
+	return 1;
+}
+
+ static int
+z_endp(Void)
+{
+	(*f__donewrec)();
+	return 0;
+	}
+
+ int
+#ifdef KR_headers
+c_si(a) icilist *a;
+#else
+c_si(icilist *a)
+#endif
+{
+	f__elist = (cilist *)a;
+	f__fmtbuf=a->icifmt;
+	f__curunit = 0;
+	f__sequential=f__formatted=1;
+	f__external=0;
+	if(pars_f(f__fmtbuf)<0)
+		err(a->icierr,100,"startint");
+	fmt_bg();
+	f__cblank=f__cplus=f__scale=0;
+	f__svic=a;
+	f__icnum=f__recpos=0;
+	f__cursor = 0;
+	f__hiwater = 0;
+	f__icptr = a->iciunit;
+	f__icend = f__icptr + a->icirlen*a->icirnum;
+	f__cf = 0;
+	return(0);
+}
+
+ int
+iw_rev(Void)
+{
+	if(f__workdone)
+		z_endp();
+	f__hiwater = f__recpos = f__cursor = 0;
+	return(f__workdone=0);
+	}
+
+#ifdef KR_headers
+integer s_rsfi(a) icilist *a;
+#else
+integer s_rsfi(icilist *a)
+#endif
+{	int n;
+	if(n=c_si(a)) return(n);
+	f__reading=1;
+	f__doed=rd_ed;
+	f__doned=rd_ned;
+	f__getn=z_getc;
+	f__dorevert = z_endp;
+	f__donewrec = z_rnew;
+	f__doend = z_endp;
+	return(0);
+}
+
+ int
+z_wnew(Void)
+{
+	if (f__recpos < f__hiwater) {
+		f__icptr += f__hiwater - f__recpos;
+		f__recpos = f__hiwater;
+		}
+	while(f__recpos++ < f__svic->icirlen)
+		*f__icptr++ = ' ';
+	f__recpos = 0;
+	f__cursor = 0;
+	f__hiwater = 0;
+	f__icnum++;
+	return 1;
+}
+#ifdef KR_headers
+integer s_wsfi(a) icilist *a;
+#else
+integer s_wsfi(icilist *a)
+#endif
+{	int n;
+	if(n=c_si(a)) return(n);
+	f__reading=0;
+	f__doed=w_ed;
+	f__doned=w_ned;
+	f__putn=z_putc;
+	f__dorevert = iw_rev;
+	f__donewrec = z_wnew;
+	f__doend = z_endp;
+	return(0);
+}
+integer e_rsfi(Void)
+{	int n = en_fio();
+	f__fmtbuf = NULL;
+	return(n);
+}
+integer e_wsfi(Void)
+{
+	int n;
+	n = en_fio();
+	f__fmtbuf = NULL;
+	if(f__svic->icirnum != 1
+	 && (f__icnum >  f__svic->icirnum
+	 || (f__icnum == f__svic->icirnum && (f__recpos | f__hiwater))))
+		err(f__svic->icierr,110,"inwrite");
+	if (f__recpos < f__hiwater)
+		f__recpos = f__hiwater;
+	if (f__recpos >= f__svic->icirlen)
+		err(f__svic->icierr,110,"recend");
+	if (!f__recpos && f__icnum)
+		return n;
+	while(f__recpos++ < f__svic->icirlen)
+		*f__icptr++ = ' ';
+	return n;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/ilnw.c b/src/f2c/ilnw.c
new file mode 100644
index 0000000..e8b3d49
--- /dev/null
+++ b/src/f2c/ilnw.c
@@ -0,0 +1,83 @@
+#include "f2c.h"
+#include "fio.h"
+#include "lio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern char *f__icptr;
+extern char *f__icend;
+extern icilist *f__svic;
+extern int f__icnum;
+#ifdef KR_headers
+extern void z_putc();
+#else
+extern void z_putc(int);
+#endif
+
+ static int
+z_wSL(Void)
+{
+	while(f__recpos < f__svic->icirlen)
+		z_putc(' ');
+	return z_rnew();
+	}
+
+ static void
+#ifdef KR_headers
+c_liw(a) icilist *a;
+#else
+c_liw(icilist *a)
+#endif
+{
+	f__reading = 0;
+	f__external = 0;
+	f__formatted = 1;
+	f__putn = z_putc;
+	L_len = a->icirlen;
+	f__donewrec = z_wSL;
+	f__svic = a;
+	f__icnum = f__recpos = 0;
+	f__cursor = 0;
+	f__cf = 0;
+	f__curunit = 0;
+	f__icptr = a->iciunit;
+	f__icend = f__icptr + a->icirlen*a->icirnum;
+	f__elist = (cilist *)a;
+	}
+
+ integer
+#ifdef KR_headers
+s_wsni(a) icilist *a;
+#else
+s_wsni(icilist *a)
+#endif
+{
+	cilist ca;
+
+	c_liw(a);
+	ca.cifmt = a->icifmt;
+	x_wsne(&ca);
+	z_wSL();
+	return 0;
+	}
+
+ integer
+#ifdef KR_headers
+s_wsli(a) icilist *a;
+#else
+s_wsli(icilist *a)
+#endif
+{
+	f__lioproc = l_write;
+	c_liw(a);
+	return(0);
+	}
+
+integer e_wsli(Void)
+{
+	z_wSL();
+	return(0);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/inquire.c b/src/f2c/inquire.c
new file mode 100644
index 0000000..5936a67
--- /dev/null
+++ b/src/f2c/inquire.c
@@ -0,0 +1,117 @@
+#include "f2c.h"
+#include "fio.h"
+#include "string.h"
+#ifdef NON_UNIX_STDIO
+#ifndef MSDOS
+#include "unistd.h" /* for access() */
+#endif
+#endif
+#ifdef KR_headers
+integer f_inqu(a) inlist *a;
+#else
+#ifdef __cplusplus
+extern "C" integer f_inqu(inlist*);
+#endif
+#ifdef MSDOS
+#undef abs
+#undef min
+#undef max
+#include "io.h"
+#endif
+integer f_inqu(inlist *a)
+#endif
+{	flag byfile;
+	int i;
+#ifndef NON_UNIX_STDIO
+	int n;
+#endif
+	unit *p;
+	char buf[256];
+	long x;
+	if(a->infile!=NULL)
+	{	byfile=1;
+		g_char(a->infile,a->infilen,buf);
+#ifdef NON_UNIX_STDIO
+		x = access(buf,0) ? -1 : 0;
+		for(i=0,p=NULL;i<MXUNIT;i++)
+			if(f__units[i].ufd != NULL
+			 && f__units[i].ufnm != NULL
+			 && !strcmp(f__units[i].ufnm,buf)) {
+				p = &f__units[i];
+				break;
+				}
+#else
+		x=f__inode(buf, &n);
+		for(i=0,p=NULL;i<MXUNIT;i++)
+			if(f__units[i].uinode==x
+			&& f__units[i].ufd!=NULL
+			&& f__units[i].udev == n) {
+				p = &f__units[i];
+				break;
+				}
+#endif
+	}
+	else
+	{
+		byfile=0;
+		if(a->inunit<MXUNIT && a->inunit>=0)
+		{
+			p= &f__units[a->inunit];
+		}
+		else
+		{
+			p=NULL;
+		}
+	}
+	if(a->inex!=NULL)
+		if(byfile && x != -1 || !byfile && p!=NULL)
+			*a->inex=1;
+		else *a->inex=0;
+	if(a->inopen!=NULL)
+		if(byfile) *a->inopen=(p!=NULL);
+		else *a->inopen=(p!=NULL && p->ufd!=NULL);
+	if(a->innum!=NULL) *a->innum= p-f__units;
+	if(a->innamed!=NULL)
+		if(byfile || p!=NULL && p->ufnm!=NULL)
+			*a->innamed=1;
+		else	*a->innamed=0;
+	if(a->inname!=NULL)
+		if(byfile)
+			b_char(buf,a->inname,a->innamlen);
+		else if(p!=NULL && p->ufnm!=NULL)
+			b_char(p->ufnm,a->inname,a->innamlen);
+	if(a->inacc!=NULL && p!=NULL && p->ufd!=NULL)
+		if(p->url)
+			b_char("DIRECT",a->inacc,a->inacclen);
+		else	b_char("SEQUENTIAL",a->inacc,a->inacclen);
+	if(a->inseq!=NULL)
+		if(p!=NULL && p->url)
+			b_char("NO",a->inseq,a->inseqlen);
+		else	b_char("YES",a->inseq,a->inseqlen);
+	if(a->indir!=NULL)
+		if(p==NULL || p->url)
+			b_char("YES",a->indir,a->indirlen);
+		else	b_char("NO",a->indir,a->indirlen);
+	if(a->infmt!=NULL)
+		if(p!=NULL && p->ufmt==0)
+			b_char("UNFORMATTED",a->infmt,a->infmtlen);
+		else	b_char("FORMATTED",a->infmt,a->infmtlen);
+	if(a->inform!=NULL)
+		if(p!=NULL && p->ufmt==0)
+		b_char("NO",a->inform,a->informlen);
+		else b_char("YES",a->inform,a->informlen);
+	if(a->inunf)
+		if(p!=NULL && p->ufmt==0)
+			b_char("YES",a->inunf,a->inunflen);
+		else if (p!=NULL) b_char("NO",a->inunf,a->inunflen);
+		else b_char("UNKNOWN",a->inunf,a->inunflen);
+	if(a->inrecl!=NULL && p!=NULL)
+		*a->inrecl=p->url;
+	if(a->innrec!=NULL && p!=NULL && p->url>0)
+		*a->innrec=(ftnint)(FTELL(p->ufd)/p->url+1);
+	if(a->inblank && p!=NULL && p->ufmt)
+		if(p->ublnk)
+			b_char("ZERO",a->inblank,a->inblanklen);
+		else	b_char("NULL",a->inblank,a->inblanklen);
+	return(0);
+}
diff --git a/src/f2c/l_ge.c b/src/f2c/l_ge.c
new file mode 100644
index 0000000..a84f0ee
--- /dev/null
+++ b/src/f2c/l_ge.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+logical l_ge(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+logical l_ge(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) >= 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/l_gt.c b/src/f2c/l_gt.c
new file mode 100644
index 0000000..ae6950d
--- /dev/null
+++ b/src/f2c/l_gt.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+logical l_gt(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+logical l_gt(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) > 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/l_le.c b/src/f2c/l_le.c
new file mode 100644
index 0000000..625b49a
--- /dev/null
+++ b/src/f2c/l_le.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+logical l_le(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+logical l_le(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) <= 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/l_lt.c b/src/f2c/l_lt.c
new file mode 100644
index 0000000..ab21b36
--- /dev/null
+++ b/src/f2c/l_lt.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern integer s_cmp();
+logical l_lt(a,b,la,lb) char *a, *b; ftnlen la, lb;
+#else
+extern integer s_cmp(char *, char *, ftnlen, ftnlen);
+logical l_lt(char *a, char *b, ftnlen la, ftnlen lb)
+#endif
+{
+return(s_cmp(a,b,la,lb) < 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/lbitbits.c b/src/f2c/lbitbits.c
new file mode 100644
index 0000000..5b6ccf7
--- /dev/null
+++ b/src/f2c/lbitbits.c
@@ -0,0 +1,68 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef LONGBITS
+#define LONGBITS 32
+#endif
+
+ integer
+#ifdef KR_headers
+lbit_bits(a, b, len) integer a, b, len;
+#else
+lbit_bits(integer a, integer b, integer len)
+#endif
+{
+	/* Assume 2's complement arithmetic */
+
+	unsigned long x, y;
+
+	x = (unsigned long) a;
+	y = (unsigned long)-1L;
+	x >>= b;
+	y <<= len;
+	return (integer)(x & ~y);
+	}
+
+ integer
+#ifdef KR_headers
+lbit_cshift(a, b, len) integer a, b, len;
+#else
+lbit_cshift(integer a, integer b, integer len)
+#endif
+{
+	unsigned long x, y, z;
+
+	x = (unsigned long)a;
+	if (len <= 0) {
+		if (len == 0)
+			return 0;
+		goto full_len;
+		}
+	if (len >= LONGBITS) {
+ full_len:
+		if (b >= 0) {
+			b %= LONGBITS;
+			return (integer)(x << b | x >> LONGBITS -b );
+			}
+		b = -b;
+		b %= LONGBITS;
+		return (integer)(x << LONGBITS - b | x >> b);
+		}
+	y = z = (unsigned long)-1;
+	y <<= len;
+	z &= ~y;
+	y &= x;
+	x &= z;
+	if (b >= 0) {
+		b %= len;
+		return (integer)(y | z & (x << b | x >> len - b));
+		}
+	b = -b;
+	b %= len;
+	return (integer)(y | z & (x >> b | x << len - b));
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/lbitshft.c b/src/f2c/lbitshft.c
new file mode 100644
index 0000000..fbee94f
--- /dev/null
+++ b/src/f2c/lbitshft.c
@@ -0,0 +1,17 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ integer
+#ifdef KR_headers
+lbit_shift(a, b) integer a; integer b;
+#else
+lbit_shift(integer a, integer b)
+#endif
+{
+	return b >= 0 ? a << b : (integer)((uinteger)a >> -b);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/lio.h b/src/f2c/lio.h
new file mode 100644
index 0000000..f9fd1cd
--- /dev/null
+++ b/src/f2c/lio.h
@@ -0,0 +1,74 @@
+/*	copy of ftypes from the compiler */
+/* variable types
+ * numeric assumptions:
+ *	int < reals < complexes
+ *	TYDREAL-TYREAL = TYDCOMPLEX-TYCOMPLEX
+ */
+
+/* 0-10 retain their old (pre LOGICAL*1, etc.) */
+/* values to allow mixing old and new objects. */
+
+#define TYUNKNOWN 0
+#define TYADDR 1
+#define TYSHORT 2
+#define TYLONG 3
+#define TYREAL 4
+#define TYDREAL 5
+#define TYCOMPLEX 6
+#define TYDCOMPLEX 7
+#define TYLOGICAL 8
+#define TYCHAR 9
+#define TYSUBR 10
+#define TYINT1 11
+#define TYLOGICAL1 12
+#define TYLOGICAL2 13
+#ifdef Allow_TYQUAD
+#undef TYQUAD
+#define TYQUAD 14
+#endif
+
+#define	LINTW	24
+#define	LINE	80
+#define	LLOGW	2
+#ifdef Old_list_output
+#define	LLOW	1.0
+#define	LHIGH	1.e9
+#define	LEFMT	" %# .8E"
+#define	LFFMT	" %# .9g"
+#else
+#define	LGFMT	"%.9G"
+#endif
+/* LEFBL 20 should suffice; 24 overcomes a NeXT bug. */
+#define	LEFBL	24
+
+typedef union
+{
+	char	flchar;
+	short	flshort;
+	ftnint	flint;
+#ifdef Allow_TYQUAD
+	longint fllongint;
+#endif
+	real	flreal;
+	doublereal	fldouble;
+} flex;
+#ifdef KR_headers
+extern int (*f__lioproc)(), (*l_getc)(), (*l_ungetc)();
+extern int l_read(), l_write();
+#else
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int (*f__lioproc)(ftnint*, char*, ftnlen, ftnint);
+extern int l_write(ftnint*, char*, ftnlen, ftnint);
+extern void x_wsne(cilist*);
+extern int c_le(cilist*), (*l_getc)(void), (*l_ungetc)(int,FILE*);
+extern int l_read(ftnint*,char*,ftnlen,ftnint);
+extern integer e_rsle(void), e_wsle(void), s_wsne(cilist*);
+extern int z_rnew(void);
+#endif
+extern ftnint L_len;
+extern int f__scale;
+#ifdef __cplusplus
+	}
+#endif
diff --git a/src/f2c/lread.c b/src/f2c/lread.c
new file mode 100644
index 0000000..699cda1
--- /dev/null
+++ b/src/f2c/lread.c
@@ -0,0 +1,806 @@
+#include "f2c.h"
+#include "fio.h"
+
+/* Compile with -DF8X_NML_ELIDE_QUOTES to permit eliding quotation */
+/* marks in namelist input a la the Fortran 8X Draft published in  */
+/* the May 1989 issue of Fortran Forum. */
+
+
+#ifdef Allow_TYQUAD
+static longint f__llx;
+#endif
+
+#ifdef KR_headers
+extern double atof();
+extern char *malloc(), *realloc();
+int (*f__lioproc)(), (*l_getc)(), (*l_ungetc)();
+#else
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#endif
+
+#include "fmt.h"
+#include "lio.h"
+#include "ctype.h"
+#include "fp.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern char *f__fmtbuf;
+#else
+extern const char *f__fmtbuf;
+int (*f__lioproc)(ftnint*, char*, ftnlen, ftnint), (*l_getc)(void),
+	(*l_ungetc)(int,FILE*);
+#endif
+
+int l_eof;
+
+#define isblnk(x) (f__ltab[x+1]&B)
+#define issep(x) (f__ltab[x+1]&SX)
+#define isapos(x) (f__ltab[x+1]&AX)
+#define isexp(x) (f__ltab[x+1]&EX)
+#define issign(x) (f__ltab[x+1]&SG)
+#define iswhit(x) (f__ltab[x+1]&WH)
+#define SX 1
+#define B 2
+#define AX 4
+#define EX 8
+#define SG 16
+#define WH 32
+char f__ltab[128+1] = {	/* offset one for EOF */
+	0,
+	0,0,AX,0,0,0,0,0,0,WH|B,SX|WH,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	SX|B|WH,0,AX,0,0,0,0,AX,0,0,0,SG,SX,SG,0,SX,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,EX,EX,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	AX,0,0,0,EX,EX,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+#ifdef ungetc
+ static int
+#ifdef KR_headers
+un_getc(x,f__cf) int x; FILE *f__cf;
+#else
+un_getc(int x, FILE *f__cf)
+#endif
+{ return ungetc(x,f__cf); }
+#else
+#define un_getc ungetc
+#ifdef KR_headers
+ extern int ungetc();
+#else
+extern int ungetc(int, FILE*);	/* for systems with a buggy stdio.h */
+#endif
+#endif
+
+ int
+t_getc(Void)
+{	int ch;
+	if(f__curunit->uend) return(EOF);
+	if((ch=getc(f__cf))!=EOF) return(ch);
+	if(feof(f__cf))
+		f__curunit->uend = l_eof = 1;
+	return(EOF);
+}
+integer e_rsle(Void)
+{
+	int ch;
+	if(f__curunit->uend) return(0);
+	while((ch=t_getc())!='\n')
+		if (ch == EOF) {
+			if(feof(f__cf))
+				f__curunit->uend = l_eof = 1;
+			return EOF;
+			}
+	return(0);
+}
+
+flag f__lquit;
+int f__lcount,f__ltype,nml_read;
+char *f__lchar;
+double f__lx,f__ly;
+#define ERR(x) if(n=(x)) return(n)
+#define GETC(x) (x=(*l_getc)())
+#define Ungetc(x,y) (*l_ungetc)(x,y)
+
+ static int
+#ifdef KR_headers
+l_R(poststar, reqint) int poststar, reqint;
+#else
+l_R(int poststar, int reqint)
+#endif
+{
+	char s[FMAX+EXPMAXDIGS+4];
+	register int ch;
+	register char *sp, *spe, *sp1;
+	long e, exp;
+	int havenum, havestar, se;
+
+	if (!poststar) {
+		if (f__lcount > 0)
+			return(0);
+		f__lcount = 1;
+		}
+#ifdef Allow_TYQUAD
+	f__llx = 0;
+#endif
+	f__ltype = 0;
+	exp = 0;
+	havestar = 0;
+retry:
+	sp1 = sp = s;
+	spe = sp + FMAX;
+	havenum = 0;
+
+	switch(GETC(ch)) {
+		case '-': *sp++ = ch; sp1++; spe++;
+		case '+':
+			GETC(ch);
+		}
+	while(ch == '0') {
+		++havenum;
+		GETC(ch);
+		}
+	while(isdigit(ch)) {
+		if (sp < spe) *sp++ = ch;
+		else ++exp;
+		GETC(ch);
+		}
+	if (ch == '*' && !poststar) {
+		if (sp == sp1 || exp || *s == '-') {
+			errfl(f__elist->cierr,112,"bad repetition count");
+			}
+		poststar = havestar = 1;
+		*sp = 0;
+		f__lcount = atoi(s);
+		goto retry;
+		}
+	if (ch == '.') {
+#ifndef ALLOW_FLOAT_IN_INTEGER_LIST_INPUT
+		if (reqint)
+			errfl(f__elist->cierr,115,"invalid integer");
+#endif
+		GETC(ch);
+		if (sp == sp1)
+			while(ch == '0') {
+				++havenum;
+				--exp;
+				GETC(ch);
+				}
+		while(isdigit(ch)) {
+			if (sp < spe)
+				{ *sp++ = ch; --exp; }
+			GETC(ch);
+			}
+		}
+	havenum += sp - sp1;
+	se = 0;
+	if (issign(ch))
+		goto signonly;
+	if (havenum && isexp(ch)) {
+#ifndef ALLOW_FLOAT_IN_INTEGER_LIST_INPUT
+		if (reqint)
+			errfl(f__elist->cierr,115,"invalid integer");
+#endif
+		GETC(ch);
+		if (issign(ch)) {
+signonly:
+			if (ch == '-') se = 1;
+			GETC(ch);
+			}
+		if (!isdigit(ch)) {
+bad:
+			errfl(f__elist->cierr,112,"exponent field");
+			}
+
+		e = ch - '0';
+		while(isdigit(GETC(ch))) {
+			e = 10*e + ch - '0';
+			if (e > EXPMAX)
+				goto bad;
+			}
+		if (se)
+			exp -= e;
+		else
+			exp += e;
+		}
+	(void) Ungetc(ch, f__cf);
+	if (sp > sp1) {
+		++havenum;
+		while(*--sp == '0')
+			++exp;
+		if (exp)
+			sprintf(sp+1, "e%ld", exp);
+		else
+			sp[1] = 0;
+		f__lx = atof(s);
+#ifdef Allow_TYQUAD
+		if (reqint&2 && (se = sp - sp1 + exp) > 14 && se < 20) {
+			/* Assuming 64-bit longint and 32-bit long. */
+			if (exp < 0)
+				sp += exp;
+			if (sp1 <= sp) {
+				f__llx = *sp1 - '0';
+				while(++sp1 <= sp)
+					f__llx = 10*f__llx + (*sp1 - '0');
+				}
+			while(--exp >= 0)
+				f__llx *= 10;
+			if (*s == '-')
+				f__llx = -f__llx;
+			}
+#endif
+		}
+	else
+		f__lx = 0.;
+	if (havenum)
+		f__ltype = TYLONG;
+	else
+		switch(ch) {
+			case ',':
+			case '/':
+				break;
+			default:
+				if (havestar && ( ch == ' '
+						||ch == '\t'
+						||ch == '\n'))
+					break;
+				if (nml_read > 1) {
+					f__lquit = 2;
+					return 0;
+					}
+				errfl(f__elist->cierr,112,"invalid number");
+			}
+	return 0;
+	}
+
+ static int
+#ifdef KR_headers
+rd_count(ch) register int ch;
+#else
+rd_count(register int ch)
+#endif
+{
+	if (ch < '0' || ch > '9')
+		return 1;
+	f__lcount = ch - '0';
+	while(GETC(ch) >= '0' && ch <= '9')
+		f__lcount = 10*f__lcount + ch - '0';
+	Ungetc(ch,f__cf);
+	return f__lcount <= 0;
+	}
+
+ static int
+l_C(Void)
+{	int ch, nml_save;
+	double lz;
+	if(f__lcount>0) return(0);
+	f__ltype=0;
+	GETC(ch);
+	if(ch!='(')
+	{
+		if (nml_read > 1 && (ch < '0' || ch > '9')) {
+			Ungetc(ch,f__cf);
+			f__lquit = 2;
+			return 0;
+			}
+		if (rd_count(ch))
+			if(!f__cf || !feof(f__cf))
+				errfl(f__elist->cierr,112,"complex format");
+			else
+				err(f__elist->cierr,(EOF),"lread");
+		if(GETC(ch)!='*')
+		{
+			if(!f__cf || !feof(f__cf))
+				errfl(f__elist->cierr,112,"no star");
+			else
+				err(f__elist->cierr,(EOF),"lread");
+		}
+		if(GETC(ch)!='(')
+		{	Ungetc(ch,f__cf);
+			return(0);
+		}
+	}
+	else
+		f__lcount = 1;
+	while(iswhit(GETC(ch)));
+	Ungetc(ch,f__cf);
+	nml_save = nml_read;
+	nml_read = 0;
+	if (ch = l_R(1,0))
+		return ch;
+	if (!f__ltype)
+		errfl(f__elist->cierr,112,"no real part");
+	lz = f__lx;
+	while(iswhit(GETC(ch)));
+	if(ch!=',')
+	{	(void) Ungetc(ch,f__cf);
+		errfl(f__elist->cierr,112,"no comma");
+	}
+	while(iswhit(GETC(ch)));
+	(void) Ungetc(ch,f__cf);
+	if (ch = l_R(1,0))
+		return ch;
+	if (!f__ltype)
+		errfl(f__elist->cierr,112,"no imaginary part");
+	while(iswhit(GETC(ch)));
+	if(ch!=')') errfl(f__elist->cierr,112,"no )");
+	f__ly = f__lx;
+	f__lx = lz;
+#ifdef Allow_TYQUAD
+	f__llx = 0;
+#endif
+	nml_read = nml_save;
+	return(0);
+}
+
+ static char nmLbuf[256], *nmL_next;
+ static int (*nmL_getc_save)(Void);
+#ifdef KR_headers
+ static int (*nmL_ungetc_save)(/* int, FILE* */);
+#else
+ static int (*nmL_ungetc_save)(int, FILE*);
+#endif
+
+ static int
+nmL_getc(Void)
+{
+	int rv;
+	if (rv = *nmL_next++)
+		return rv;
+	l_getc = nmL_getc_save;
+	l_ungetc = nmL_ungetc_save;
+	return (*l_getc)();
+	}
+
+ static int
+#ifdef KR_headers
+nmL_ungetc(x, f) int x; FILE *f;
+#else
+nmL_ungetc(int x, FILE *f)
+#endif
+{
+	f = f;	/* banish non-use warning */
+	return *--nmL_next = x;
+	}
+
+ static int
+#ifdef KR_headers
+Lfinish(ch, dot, rvp) int ch, dot, *rvp;
+#else
+Lfinish(int ch, int dot, int *rvp)
+#endif
+{
+	char *s, *se;
+	static char what[] = "namelist input";
+
+	s = nmLbuf + 2;
+	se = nmLbuf + sizeof(nmLbuf) - 1;
+	*s++ = ch;
+	while(!issep(GETC(ch)) && ch!=EOF) {
+		if (s >= se) {
+ nmLbuf_ovfl:
+			return *rvp = err__fl(f__elist->cierr,131,what);
+			}
+		*s++ = ch;
+		if (ch != '=')
+			continue;
+		if (dot)
+			return *rvp = err__fl(f__elist->cierr,112,what);
+ got_eq:
+		*s = 0;
+		nmL_getc_save = l_getc;
+		l_getc = nmL_getc;
+		nmL_ungetc_save = l_ungetc;
+		l_ungetc = nmL_ungetc;
+		nmLbuf[1] = *(nmL_next = nmLbuf) = ',';
+		*rvp = f__lcount = 0;
+		return 1;
+		}
+	if (dot)
+		goto done;
+	for(;;) {
+		if (s >= se)
+			goto nmLbuf_ovfl;
+		*s++ = ch;
+		if (!isblnk(ch))
+			break;
+		if (GETC(ch) == EOF)
+			goto done;
+		}
+	if (ch == '=')
+		goto got_eq;
+ done:
+	Ungetc(ch, f__cf);
+	return 0;
+	}
+
+ static int
+l_L(Void)
+{
+	int ch, rv, sawdot;
+
+	if(f__lcount>0)
+		return(0);
+	f__lcount = 1;
+	f__ltype=0;
+	GETC(ch);
+	if(isdigit(ch))
+	{
+		rd_count(ch);
+		if(GETC(ch)!='*')
+			if(!f__cf || !feof(f__cf))
+				errfl(f__elist->cierr,112,"no star");
+			else
+				err(f__elist->cierr,(EOF),"lread");
+		GETC(ch);
+	}
+	sawdot = 0;
+	if(ch == '.') {
+		sawdot = 1;
+		GETC(ch);
+		}
+	switch(ch)
+	{
+	case 't':
+	case 'T':
+		if (nml_read && Lfinish(ch, sawdot, &rv))
+			return rv;
+		f__lx=1;
+		break;
+	case 'f':
+	case 'F':
+		if (nml_read && Lfinish(ch, sawdot, &rv))
+			return rv;
+		f__lx=0;
+		break;
+	default:
+		if(isblnk(ch) || issep(ch) || ch==EOF)
+		{	(void) Ungetc(ch,f__cf);
+			return(0);
+		}
+		if (nml_read > 1) {
+			Ungetc(ch,f__cf);
+			f__lquit = 2;
+			return 0;
+			}
+		errfl(f__elist->cierr,112,"logical");
+	}
+	f__ltype=TYLONG;
+	while(!issep(GETC(ch)) && ch!=EOF);
+	Ungetc(ch, f__cf);
+	return(0);
+}
+
+#define BUFSIZE	128
+
+ static int
+l_CHAR(Void)
+{	int ch,size,i;
+	static char rafail[] = "realloc failure";
+	char quote,*p;
+	if(f__lcount>0) return(0);
+	f__ltype=0;
+	if(f__lchar!=NULL) free(f__lchar);
+	size=BUFSIZE;
+	p=f__lchar = (char *)malloc((unsigned int)size);
+	if(f__lchar == NULL)
+		errfl(f__elist->cierr,113,"no space");
+
+	GETC(ch);
+	if(isdigit(ch)) {
+		/* allow Fortran 8x-style unquoted string...	*/
+		/* either find a repetition count or the string	*/
+		f__lcount = ch - '0';
+		*p++ = ch;
+		for(i = 1;;) {
+			switch(GETC(ch)) {
+				case '*':
+					if (f__lcount == 0) {
+						f__lcount = 1;
+#ifndef F8X_NML_ELIDE_QUOTES
+						if (nml_read)
+							goto no_quote;
+#endif
+						goto noquote;
+						}
+					p = f__lchar;
+					goto have_lcount;
+				case ',':
+				case ' ':
+				case '\t':
+				case '\n':
+				case '/':
+					Ungetc(ch,f__cf);
+					/* no break */
+				case EOF:
+					f__lcount = 1;
+					f__ltype = TYCHAR;
+					return *p = 0;
+				}
+			if (!isdigit(ch)) {
+				f__lcount = 1;
+#ifndef F8X_NML_ELIDE_QUOTES
+				if (nml_read) {
+ no_quote:
+					errfl(f__elist->cierr,112,
+						"undelimited character string");
+					}
+#endif
+				goto noquote;
+				}
+			*p++ = ch;
+			f__lcount = 10*f__lcount + ch - '0';
+			if (++i == size) {
+				f__lchar = (char *)realloc(f__lchar,
+					(unsigned int)(size += BUFSIZE));
+				if(f__lchar == NULL)
+					errfl(f__elist->cierr,113,rafail);
+				p = f__lchar + i;
+				}
+			}
+		}
+	else	(void) Ungetc(ch,f__cf);
+ have_lcount:
+	if(GETC(ch)=='\'' || ch=='"') quote=ch;
+	else if(isblnk(ch) || (issep(ch) && ch != '\n') || ch==EOF) {
+		Ungetc(ch,f__cf);
+		return 0;
+		}
+#ifndef F8X_NML_ELIDE_QUOTES
+	else if (nml_read > 1) {
+		Ungetc(ch,f__cf);
+		f__lquit = 2;
+		return 0;
+		}
+#endif
+	else {
+		/* Fortran 8x-style unquoted string */
+		*p++ = ch;
+		for(i = 1;;) {
+			switch(GETC(ch)) {
+				case ',':
+				case ' ':
+				case '\t':
+				case '\n':
+				case '/':
+					Ungetc(ch,f__cf);
+					/* no break */
+				case EOF:
+					f__ltype = TYCHAR;
+					return *p = 0;
+				}
+ noquote:
+			*p++ = ch;
+			if (++i == size) {
+				f__lchar = (char *)realloc(f__lchar,
+					(unsigned int)(size += BUFSIZE));
+				if(f__lchar == NULL)
+					errfl(f__elist->cierr,113,rafail);
+				p = f__lchar + i;
+				}
+			}
+		}
+	f__ltype=TYCHAR;
+	for(i=0;;)
+	{	while(GETC(ch)!=quote && ch!='\n'
+			&& ch!=EOF && ++i<size) *p++ = ch;
+		if(i==size)
+		{
+		newone:
+			f__lchar= (char *)realloc(f__lchar,
+					(unsigned int)(size += BUFSIZE));
+			if(f__lchar == NULL)
+				errfl(f__elist->cierr,113,rafail);
+			p=f__lchar+i-1;
+			*p++ = ch;
+		}
+		else if(ch==EOF) return(EOF);
+		else if(ch=='\n')
+		{	if(*(p-1) != '\\') continue;
+			i--;
+			p--;
+			if(++i<size) *p++ = ch;
+			else goto newone;
+		}
+		else if(GETC(ch)==quote)
+		{	if(++i<size) *p++ = ch;
+			else goto newone;
+		}
+		else
+		{	(void) Ungetc(ch,f__cf);
+			*p = 0;
+			return(0);
+		}
+	}
+}
+
+ int
+#ifdef KR_headers
+c_le(a) cilist *a;
+#else
+c_le(cilist *a)
+#endif
+{
+	if(!f__init)
+		f_init();
+	f__fmtbuf="list io";
+	f__curunit = &f__units[a->ciunit];
+	if(a->ciunit>=MXUNIT || a->ciunit<0)
+		err(a->cierr,101,"stler");
+	f__scale=f__recpos=0;
+	f__elist=a;
+	if(f__curunit->ufd==NULL && fk_open(SEQ,FMT,a->ciunit))
+		err(a->cierr,102,"lio");
+	f__cf=f__curunit->ufd;
+	if(!f__curunit->ufmt) err(a->cierr,103,"lio")
+	return(0);
+}
+
+ int
+#ifdef KR_headers
+l_read(number,ptr,len,type) ftnint *number,type; char *ptr; ftnlen len;
+#else
+l_read(ftnint *number, char *ptr, ftnlen len, ftnint type)
+#endif
+{
+#define Ptr ((flex *)ptr)
+	int i,n,ch;
+	doublereal *yy;
+	real *xx;
+	for(i=0;i<*number;i++)
+	{
+		if(f__lquit) return(0);
+		if(l_eof)
+			err(f__elist->ciend, EOF, "list in")
+		if(f__lcount == 0) {
+			f__ltype = 0;
+			for(;;)  {
+				GETC(ch);
+				switch(ch) {
+				case EOF:
+					err(f__elist->ciend,(EOF),"list in")
+				case ' ':
+				case '\t':
+				case '\n':
+					continue;
+				case '/':
+					f__lquit = 1;
+					goto loopend;
+				case ',':
+					f__lcount = 1;
+					goto loopend;
+				default:
+					(void) Ungetc(ch, f__cf);
+					goto rddata;
+				}
+			}
+		}
+	rddata:
+		switch((int)type)
+		{
+		case TYINT1:
+		case TYSHORT:
+		case TYLONG:
+#ifndef ALLOW_FLOAT_IN_INTEGER_LIST_INPUT
+			ERR(l_R(0,1));
+			break;
+#endif
+		case TYREAL:
+		case TYDREAL:
+			ERR(l_R(0,0));
+			break;
+#ifdef TYQUAD
+		case TYQUAD:
+			n = l_R(0,2);
+			if (n)
+				return n;
+			break;
+#endif
+		case TYCOMPLEX:
+		case TYDCOMPLEX:
+			ERR(l_C());
+			break;
+		case TYLOGICAL1:
+		case TYLOGICAL2:
+		case TYLOGICAL:
+			ERR(l_L());
+			break;
+		case TYCHAR:
+			ERR(l_CHAR());
+			break;
+		}
+	while (GETC(ch) == ' ' || ch == '\t');
+	if (ch != ',' || f__lcount > 1)
+		Ungetc(ch,f__cf);
+	loopend:
+		if(f__lquit) return(0);
+		if(f__cf && ferror(f__cf)) {
+			clearerr(f__cf);
+			errfl(f__elist->cierr,errno,"list in");
+			}
+		if(f__ltype==0) goto bump;
+		switch((int)type)
+		{
+		case TYINT1:
+		case TYLOGICAL1:
+			Ptr->flchar = (char)f__lx;
+			break;
+		case TYLOGICAL2:
+		case TYSHORT:
+			Ptr->flshort = (short)f__lx;
+			break;
+		case TYLOGICAL:
+		case TYLONG:
+			Ptr->flint = (ftnint)f__lx;
+			break;
+#ifdef Allow_TYQUAD
+		case TYQUAD:
+			if (!(Ptr->fllongint = f__llx))
+				Ptr->fllongint = f__lx;
+			break;
+#endif
+		case TYREAL:
+			Ptr->flreal=f__lx;
+			break;
+		case TYDREAL:
+			Ptr->fldouble=f__lx;
+			break;
+		case TYCOMPLEX:
+			xx=(real *)ptr;
+			*xx++ = f__lx;
+			*xx = f__ly;
+			break;
+		case TYDCOMPLEX:
+			yy=(doublereal *)ptr;
+			*yy++ = f__lx;
+			*yy = f__ly;
+			break;
+		case TYCHAR:
+			b_char(f__lchar,ptr,len);
+			break;
+		}
+	bump:
+		if(f__lcount>0) f__lcount--;
+		ptr += len;
+		if (nml_read)
+			nml_read++;
+	}
+	return(0);
+#undef Ptr
+}
+#ifdef KR_headers
+integer s_rsle(a) cilist *a;
+#else
+integer s_rsle(cilist *a)
+#endif
+{
+	int n;
+
+	f__reading=1;
+	f__external=1;
+	f__formatted=1;
+	if(n=c_le(a)) return(n);
+	f__lioproc = l_read;
+	f__lquit = 0;
+	f__lcount = 0;
+	l_eof = 0;
+	if(f__curunit->uwrt && f__nowreading(f__curunit))
+		err(a->cierr,errno,"read start");
+	if(f__curunit->uend)
+		err(f__elist->ciend,(EOF),"read start");
+	l_getc = t_getc;
+	l_ungetc = un_getc;
+	f__doend = xrd_SL;
+	return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/lwrite.c b/src/f2c/lwrite.c
new file mode 100644
index 0000000..9e0d93d
--- /dev/null
+++ b/src/f2c/lwrite.c
@@ -0,0 +1,314 @@
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#include "lio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ftnint L_len;
+int f__Aquote;
+
+ static VOID
+donewrec(Void)
+{
+	if (f__recpos)
+		(*f__donewrec)();
+	}
+
+ static VOID
+#ifdef KR_headers
+lwrt_I(n) longint n;
+#else
+lwrt_I(longint n)
+#endif
+{
+	char *p;
+	int ndigit, sign;
+
+	p = f__icvt(n, &ndigit, &sign, 10);
+	if(f__recpos + ndigit >= L_len)
+		donewrec();
+	PUT(' ');
+	if (sign)
+		PUT('-');
+	while(*p)
+		PUT(*p++);
+}
+ static VOID
+#ifdef KR_headers
+lwrt_L(n, len) ftnint n; ftnlen len;
+#else
+lwrt_L(ftnint n, ftnlen len)
+#endif
+{
+	if(f__recpos+LLOGW>=L_len)
+		donewrec();
+	wrt_L((Uint *)&n,LLOGW, len);
+}
+ static VOID
+#ifdef KR_headers
+lwrt_A(p,len) char *p; ftnlen len;
+#else
+lwrt_A(char *p, ftnlen len)
+#endif
+{
+	int a;
+	char *p1, *pe;
+
+	a = 0;
+	pe = p + len;
+	if (f__Aquote) {
+		a = 3;
+		if (len > 1 && p[len-1] == ' ') {
+			while(--len > 1 && p[len-1] == ' ');
+			pe = p + len;
+			}
+		p1 = p;
+		while(p1 < pe)
+			if (*p1++ == '\'')
+				a++;
+		}
+	if(f__recpos+len+a >= L_len)
+		donewrec();
+	if (a
+#ifndef OMIT_BLANK_CC
+		|| !f__recpos
+#endif
+		)
+		PUT(' ');
+	if (a) {
+		PUT('\'');
+		while(p < pe) {
+			if (*p == '\'')
+				PUT('\'');
+			PUT(*p++);
+			}
+		PUT('\'');
+		}
+	else
+		while(p < pe)
+			PUT(*p++);
+}
+
+ static int
+#ifdef KR_headers
+l_g(buf, n) char *buf; double n;
+#else
+l_g(char *buf, double n)
+#endif
+{
+#ifdef Old_list_output
+	doublereal absn;
+	char *fmt;
+
+	absn = n;
+	if (absn < 0)
+		absn = -absn;
+	fmt = LLOW <= absn && absn < LHIGH ? LFFMT : LEFMT;
+#ifdef USE_STRLEN
+	sprintf(buf, fmt, n);
+	return strlen(buf);
+#else
+	return sprintf(buf, fmt, n);
+#endif
+
+#else
+	register char *b, c, c1;
+
+	b = buf;
+	*b++ = ' ';
+	if (n < 0) {
+		*b++ = '-';
+		n = -n;
+		}
+	else
+		*b++ = ' ';
+	if (n == 0) {
+#ifdef SIGNED_ZEROS
+		if (signbit_f2c(&n))
+			*b++ = '-';
+#endif
+		*b++ = '0';
+		*b++ = '.';
+		*b = 0;
+		goto f__ret;
+		}
+	sprintf(b, LGFMT, n);
+	switch(*b) {
+#ifndef WANT_LEAD_0
+		case '0':
+			while(b[0] = b[1])
+				b++;
+			break;
+#endif
+		case 'i':
+		case 'I':
+			/* Infinity */
+		case 'n':
+		case 'N':
+			/* NaN */
+			while(*++b);
+			break;
+
+		default:
+	/* Fortran 77 insists on having a decimal point... */
+		    for(;; b++)
+			switch(*b) {
+			case 0:
+				*b++ = '.';
+				*b = 0;
+				goto f__ret;
+			case '.':
+				while(*++b);
+				goto f__ret;
+			case 'E':
+				for(c1 = '.', c = 'E';  *b = c1;
+					c1 = c, c = *++b);
+				goto f__ret;
+			}
+		}
+ f__ret:
+	return b - buf;
+#endif
+	}
+
+ static VOID
+#ifdef KR_headers
+l_put(s) register char *s;
+#else
+l_put(register char *s)
+#endif
+{
+#ifdef KR_headers
+	register void (*pn)() = f__putn;
+#else
+	register void (*pn)(int) = f__putn;
+#endif
+	register int c;
+
+	while(c = *s++)
+		(*pn)(c);
+	}
+
+ static VOID
+#ifdef KR_headers
+lwrt_F(n) double n;
+#else
+lwrt_F(double n)
+#endif
+{
+	char buf[LEFBL];
+
+	if(f__recpos + l_g(buf,n) >= L_len)
+		donewrec();
+	l_put(buf);
+}
+ static VOID
+#ifdef KR_headers
+lwrt_C(a,b) double a,b;
+#else
+lwrt_C(double a, double b)
+#endif
+{
+	char *ba, *bb, bufa[LEFBL], bufb[LEFBL];
+	int al, bl;
+
+	al = l_g(bufa, a);
+	for(ba = bufa; *ba == ' '; ba++)
+		--al;
+	bl = l_g(bufb, b) + 1;	/* intentionally high by 1 */
+	for(bb = bufb; *bb == ' '; bb++)
+		--bl;
+	if(f__recpos + al + bl + 3 >= L_len)
+		donewrec();
+#ifdef OMIT_BLANK_CC
+	else
+#endif
+	PUT(' ');
+	PUT('(');
+	l_put(ba);
+	PUT(',');
+	if (f__recpos + bl >= L_len) {
+		(*f__donewrec)();
+#ifndef OMIT_BLANK_CC
+		PUT(' ');
+#endif
+		}
+	l_put(bb);
+	PUT(')');
+}
+
+ int
+#ifdef KR_headers
+l_write(number,ptr,len,type) ftnint *number,type; char *ptr; ftnlen len;
+#else
+l_write(ftnint *number, char *ptr, ftnlen len, ftnint type)
+#endif
+{
+#define Ptr ((flex *)ptr)
+	int i;
+	longint x;
+	double y,z;
+	real *xx;
+	doublereal *yy;
+	for(i=0;i< *number; i++)
+	{
+		switch((int)type)
+		{
+		default: f__fatal(117,"unknown type in lio");
+		case TYINT1:
+			x = Ptr->flchar;
+			goto xint;
+		case TYSHORT:
+			x=Ptr->flshort;
+			goto xint;
+#ifdef Allow_TYQUAD
+		case TYQUAD:
+			x = Ptr->fllongint;
+			goto xint;
+#endif
+		case TYLONG:
+			x=Ptr->flint;
+		xint:	lwrt_I(x);
+			break;
+		case TYREAL:
+			y=Ptr->flreal;
+			goto xfloat;
+		case TYDREAL:
+			y=Ptr->fldouble;
+		xfloat: lwrt_F(y);
+			break;
+		case TYCOMPLEX:
+			xx= &Ptr->flreal;
+			y = *xx++;
+			z = *xx;
+			goto xcomplex;
+		case TYDCOMPLEX:
+			yy = &Ptr->fldouble;
+			y= *yy++;
+			z = *yy;
+		xcomplex:
+			lwrt_C(y,z);
+			break;
+		case TYLOGICAL1:
+			x = Ptr->flchar;
+			goto xlog;
+		case TYLOGICAL2:
+			x = Ptr->flshort;
+			goto xlog;
+		case TYLOGICAL:
+			x = Ptr->flint;
+		xlog:	lwrt_L(Ptr->flint, len);
+			break;
+		case TYCHAR:
+			lwrt_A(ptr,len);
+			break;
+		}
+		ptr += len;
+	}
+	return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/open.c b/src/f2c/open.c
new file mode 100644
index 0000000..a06428d
--- /dev/null
+++ b/src/f2c/open.c
@@ -0,0 +1,301 @@
+#include "f2c.h"
+#include "fio.h"
+#include "string.h"
+#ifndef NON_POSIX_STDIO
+#ifdef MSDOS
+#include "io.h"
+#else
+#include "unistd.h"	/* for access */
+#endif
+#endif
+
+#ifdef KR_headers
+extern char *malloc();
+#ifdef NON_ANSI_STDIO
+extern char *mktemp();
+#endif
+extern integer f_clos();
+#define Const /*nothing*/
+#else
+#define Const const
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int f__canseek(FILE*);
+extern integer f_clos(cllist*);
+#endif
+
+#ifdef NON_ANSI_RW_MODES
+Const char *f__r_mode[2] = {"r", "r"};
+Const char *f__w_mode[4] = {"w", "w", "r+w", "r+w"};
+#else
+Const char *f__r_mode[2] = {"rb", "r"};
+Const char *f__w_mode[4] = {"wb", "w", "r+b", "r+"};
+#endif
+
+ static char f__buf0[400], *f__buf = f__buf0;
+ int f__buflen = (int)sizeof(f__buf0);
+
+ static void
+#ifdef KR_headers
+f__bufadj(n, c) int n, c;
+#else
+f__bufadj(int n, int c)
+#endif
+{
+	unsigned int len;
+	char *nbuf, *s, *t, *te;
+
+	if (f__buf == f__buf0)
+		f__buflen = 1024;
+	while(f__buflen <= n)
+		f__buflen <<= 1;
+	len = (unsigned int)f__buflen;
+	if (len != f__buflen || !(nbuf = (char*)malloc(len)))
+		f__fatal(113, "malloc failure");
+	s = nbuf;
+	t = f__buf;
+	te = t + c;
+	while(t < te)
+		*s++ = *t++;
+	if (f__buf != f__buf0)
+		free(f__buf);
+	f__buf = nbuf;
+	}
+
+ int
+#ifdef KR_headers
+f__putbuf(c) int c;
+#else
+f__putbuf(int c)
+#endif
+{
+	char *s, *se;
+	int n;
+
+	if (f__hiwater > f__recpos)
+		f__recpos = f__hiwater;
+	n = f__recpos + 1;
+	if (n >= f__buflen)
+		f__bufadj(n, f__recpos);
+	s = f__buf;
+	se = s + f__recpos;
+	if (c)
+		*se++ = c;
+	*se = 0;
+	for(;;) {
+		fputs(s, f__cf);
+		s += strlen(s);
+		if (s >= se)
+			break;	/* normally happens the first time */
+		putc(*s++, f__cf);
+		}
+	return 0;
+	}
+
+ void
+#ifdef KR_headers
+x_putc(c)
+#else
+x_putc(int c)
+#endif
+{
+	if (f__recpos >= f__buflen)
+		f__bufadj(f__recpos, f__buflen);
+	f__buf[f__recpos++] = c;
+	}
+
+#define opnerr(f,m,s) {if(f) errno= m; else opn_err(m,s,a); return(m);}
+
+ static void
+#ifdef KR_headers
+opn_err(m, s, a) int m; char *s; olist *a;
+#else
+opn_err(int m, const char *s, olist *a)
+#endif
+{
+	if (a->ofnm) {
+		/* supply file name to error message */
+		if (a->ofnmlen >= f__buflen)
+			f__bufadj((int)a->ofnmlen, 0);
+		g_char(a->ofnm, a->ofnmlen, f__curunit->ufnm = f__buf);
+		}
+	f__fatal(m, s);
+	}
+
+#ifdef KR_headers
+integer f_open(a) olist *a;
+#else
+integer f_open(olist *a)
+#endif
+{	unit *b;
+	integer rv;
+	char buf[256], *s;
+	cllist x;
+	int ufmt;
+	FILE *tf;
+#ifndef NON_UNIX_STDIO
+	int n;
+#endif
+	f__external = 1;
+	if(a->ounit>=MXUNIT || a->ounit<0)
+		err(a->oerr,101,"open")
+	if (!f__init)
+		f_init();
+	f__curunit = b = &f__units[a->ounit];
+	if(b->ufd) {
+		if(a->ofnm==0)
+		{
+		same:	if (a->oblnk)
+				b->ublnk = *a->oblnk == 'z' || *a->oblnk == 'Z';
+			return(0);
+		}
+#ifdef NON_UNIX_STDIO
+		if (b->ufnm
+		 && strlen(b->ufnm) == a->ofnmlen
+		 && !strncmp(b->ufnm, a->ofnm, (unsigned)a->ofnmlen))
+			goto same;
+#else
+		g_char(a->ofnm,a->ofnmlen,buf);
+		if (f__inode(buf,&n) == b->uinode && n == b->udev)
+			goto same;
+#endif
+		x.cunit=a->ounit;
+		x.csta=0;
+		x.cerr=a->oerr;
+		if ((rv = f_clos(&x)) != 0)
+			return rv;
+		}
+	b->url = (int)a->orl;
+	b->ublnk = a->oblnk && (*a->oblnk == 'z' || *a->oblnk == 'Z');
+	if(a->ofm==0)
+	{	if(b->url>0) b->ufmt=0;
+		else b->ufmt=1;
+	}
+	else if(*a->ofm=='f' || *a->ofm == 'F') b->ufmt=1;
+	else b->ufmt=0;
+	ufmt = b->ufmt;
+#ifdef url_Adjust
+	if (b->url && !ufmt)
+		url_Adjust(b->url);
+#endif
+	if (a->ofnm) {
+		g_char(a->ofnm,a->ofnmlen,buf);
+		if (!buf[0])
+			opnerr(a->oerr,107,"open")
+		}
+	else
+		sprintf(buf, "fort.%ld", (long)a->ounit);
+	b->uscrtch = 0;
+	b->uend=0;
+	b->uwrt = 0;
+	b->ufd = 0;
+	b->urw = 3;
+	switch(a->osta ? *a->osta : 'u')
+	{
+	case 'o':
+	case 'O':
+#ifdef NON_POSIX_STDIO
+		if (!(tf = FOPEN(buf,"r")))
+			opnerr(a->oerr,errno,"open")
+		fclose(tf);
+#else
+		if (access(buf,0))
+			opnerr(a->oerr,errno,"open")
+#endif
+		break;
+	 case 's':
+	 case 'S':
+		b->uscrtch=1;
+#ifdef NON_ANSI_STDIO
+		(void) strcpy(buf,"tmp.FXXXXXX");
+		(void) mktemp(buf);
+		goto replace;
+#else
+		if (!(b->ufd = tmpfile()))
+			opnerr(a->oerr,errno,"open")
+		b->ufnm = 0;
+#ifndef NON_UNIX_STDIO
+		b->uinode = b->udev = -1;
+#endif
+		b->useek = 1;
+		return 0;
+#endif
+
+	case 'n':
+	case 'N':
+#ifdef NON_POSIX_STDIO
+		if ((tf = FOPEN(buf,"r")) || (tf = FOPEN(buf,"a"))) {
+			fclose(tf);
+			opnerr(a->oerr,128,"open")
+			}
+#else
+		if (!access(buf,0))
+			opnerr(a->oerr,128,"open")
+#endif
+		/* no break */
+	case 'r':	/* Fortran 90 replace option */
+	case 'R':
+#ifdef NON_ANSI_STDIO
+ replace:
+#endif
+		if (tf = FOPEN(buf,f__w_mode[0]))
+			fclose(tf);
+	}
+
+	b->ufnm=(char *) malloc((unsigned int)(strlen(buf)+1));
+	if(b->ufnm==NULL) opnerr(a->oerr,113,"no space");
+	(void) strcpy(b->ufnm,buf);
+	if ((s = a->oacc) && b->url)
+		ufmt = 0;
+	if(!(tf = FOPEN(buf, f__w_mode[ufmt|2]))) {
+		if (tf = FOPEN(buf, f__r_mode[ufmt]))
+			b->urw = 1;
+		else if (tf = FOPEN(buf, f__w_mode[ufmt])) {
+			b->uwrt = 1;
+			b->urw = 2;
+			}
+		else
+			err(a->oerr, errno, "open");
+		}
+	b->useek = f__canseek(b->ufd = tf);
+#ifndef NON_UNIX_STDIO
+	if((b->uinode = f__inode(buf,&b->udev)) == -1)
+		opnerr(a->oerr,108,"open")
+#endif
+	if(b->useek)
+		if (a->orl)
+			rewind(b->ufd);
+		else if ((s = a->oacc) && (*s == 'a' || *s == 'A')
+			&& FSEEK(b->ufd, 0L, SEEK_END))
+				opnerr(a->oerr,129,"open");
+	return(0);
+}
+
+ int
+#ifdef KR_headers
+fk_open(seq,fmt,n) ftnint n;
+#else
+fk_open(int seq, int fmt, ftnint n)
+#endif
+{	char nbuf[10];
+	olist a;
+	(void) sprintf(nbuf,"fort.%ld",(long)n);
+	a.oerr=1;
+	a.ounit=n;
+	a.ofnm=nbuf;
+	a.ofnmlen=strlen(nbuf);
+	a.osta=NULL;
+	a.oacc= (char*)(seq==SEQ?"s":"d");
+	a.ofm = (char*)(fmt==FMT?"f":"u");
+	a.orl = seq==DIR?1:0;
+	a.oblnk=NULL;
+	return(f_open(&a));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_ci.c b/src/f2c/pow_ci.c
new file mode 100644
index 0000000..f0799f4
--- /dev/null
+++ b/src/f2c/pow_ci.c
@@ -0,0 +1,26 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+VOID pow_ci(p, a, b) 	/* p = a**b  */
+ f2c_complex *p, *a; integer *b;
+#else
+extern void pow_zi(doublecomplex*, doublecomplex*, integer*);
+void pow_ci(f2c_complex *p, f2c_complex *a, integer *b) 	/* p = a**b  */
+#endif
+{
+doublecomplex p1, a1;
+
+a1.r = a->r;
+a1.i = a->i;
+
+pow_zi(&p1, &a1, b);
+
+p->r = p1.r;
+p->i = p1.i;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_dd.c b/src/f2c/pow_dd.c
new file mode 100644
index 0000000..08fc208
--- /dev/null
+++ b/src/f2c/pow_dd.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double pow();
+double pow_dd(ap, bp) doublereal *ap, *bp;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double pow_dd(doublereal *ap, doublereal *bp)
+#endif
+{
+return(pow(*ap, *bp) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_di.c b/src/f2c/pow_di.c
new file mode 100644
index 0000000..abf36cb
--- /dev/null
+++ b/src/f2c/pow_di.c
@@ -0,0 +1,41 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double pow_di(ap, bp) doublereal *ap; integer *bp;
+#else
+double pow_di(doublereal *ap, integer *bp)
+#endif
+{
+double pow, x;
+integer n;
+unsigned long u;
+
+pow = 1;
+x = *ap;
+n = *bp;
+
+if(n != 0)
+	{
+	if(n < 0)
+		{
+		n = -n;
+		x = 1/x;
+		}
+	for(u = n; ; )
+		{
+		if(u & 01)
+			pow *= x;
+		if(u >>= 1)
+			x *= x;
+		else
+			break;
+		}
+	}
+return(pow);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_hh.c b/src/f2c/pow_hh.c
new file mode 100644
index 0000000..8821685
--- /dev/null
+++ b/src/f2c/pow_hh.c
@@ -0,0 +1,39 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+shortint pow_hh(ap, bp) shortint *ap, *bp;
+#else
+shortint pow_hh(shortint *ap, shortint *bp)
+#endif
+{
+	shortint pow, x, n;
+	unsigned u;
+
+	x = *ap;
+	n = *bp;
+
+	if (n <= 0) {
+		if (n == 0 || x == 1)
+			return 1;
+		if (x != -1)
+			return x == 0 ? 1/x : 0;
+		n = -n;
+		}
+	u = n;
+	for(pow = 1; ; )
+		{
+		if(u & 01)
+			pow *= x;
+		if(u >>= 1)
+			x *= x;
+		else
+			break;
+		}
+	return(pow);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_ii.c b/src/f2c/pow_ii.c
new file mode 100644
index 0000000..748d121
--- /dev/null
+++ b/src/f2c/pow_ii.c
@@ -0,0 +1,39 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer pow_ii(ap, bp) integer *ap, *bp;
+#else
+integer pow_ii(integer *ap, integer *bp)
+#endif
+{
+	integer pow, x, n;
+	unsigned long u;
+
+	x = *ap;
+	n = *bp;
+
+	if (n <= 0) {
+		if (n == 0 || x == 1)
+			return 1;
+		if (x != -1)
+			return x == 0 ? 1/x : 0;
+		n = -n;
+		}
+	u = n;
+	for(pow = 1; ; )
+		{
+		if(u & 01)
+			pow *= x;
+		if(u >>= 1)
+			x *= x;
+		else
+			break;
+		}
+	return(pow);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_ri.c b/src/f2c/pow_ri.c
new file mode 100644
index 0000000..e29d416
--- /dev/null
+++ b/src/f2c/pow_ri.c
@@ -0,0 +1,41 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double pow_ri(ap, bp) real *ap; integer *bp;
+#else
+double pow_ri(real *ap, integer *bp)
+#endif
+{
+double pow, x;
+integer n;
+unsigned long u;
+
+pow = 1;
+x = *ap;
+n = *bp;
+
+if(n != 0)
+	{
+	if(n < 0)
+		{
+		n = -n;
+		x = 1/x;
+		}
+	for(u = n; ; )
+		{
+		if(u & 01)
+			pow *= x;
+		if(u >>= 1)
+			x *= x;
+		else
+			break;
+		}
+	}
+return(pow);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_zi.c b/src/f2c/pow_zi.c
new file mode 100644
index 0000000..1c0a4b0
--- /dev/null
+++ b/src/f2c/pow_zi.c
@@ -0,0 +1,60 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+VOID pow_zi(p, a, b) 	/* p = a**b  */
+ doublecomplex *p, *a; integer *b;
+#else
+extern void z_div(doublecomplex*, doublecomplex*, doublecomplex*);
+void pow_zi(doublecomplex *p, doublecomplex *a, integer *b) 	/* p = a**b  */
+#endif
+{
+	integer n;
+	unsigned long u;
+	double t;
+	doublecomplex q, x;
+	static doublecomplex one = {1.0, 0.0};
+
+	n = *b;
+	q.r = 1;
+	q.i = 0;
+
+	if(n == 0)
+		goto done;
+	if(n < 0)
+		{
+		n = -n;
+		z_div(&x, &one, a);
+		}
+	else
+		{
+		x.r = a->r;
+		x.i = a->i;
+		}
+
+	for(u = n; ; )
+		{
+		if(u & 01)
+			{
+			t = q.r * x.r - q.i * x.i;
+			q.i = q.r * x.i + q.i * x.r;
+			q.r = t;
+			}
+		if(u >>= 1)
+			{
+			t = x.r * x.r - x.i * x.i;
+			x.i = 2 * x.r * x.i;
+			x.r = t;
+			}
+		else
+			break;
+		}
+ done:
+	p->i = q.i;
+	p->r = q.r;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/pow_zz.c b/src/f2c/pow_zz.c
new file mode 100644
index 0000000..b5ffd33
--- /dev/null
+++ b/src/f2c/pow_zz.c
@@ -0,0 +1,29 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double log(), exp(), cos(), sin(), atan2(), f__cabs();
+VOID pow_zz(r,a,b) doublecomplex *r, *a, *b;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern double f__cabs(double,double);
+void pow_zz(doublecomplex *r, doublecomplex *a, doublecomplex *b)
+#endif
+{
+double logr, logi, x, y;
+
+logr = log( f__cabs(a->r, a->i) );
+logi = atan2(a->i, a->r);
+
+x = exp( logr * b->r - logi * b->i );
+y = logr * b->i + logi * b->r;
+
+r->r = x * cos(y);
+r->i = x * sin(y);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_abs.c b/src/f2c/r_abs.c
new file mode 100644
index 0000000..f3291fb
--- /dev/null
+++ b/src/f2c/r_abs.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double r_abs(x) real *x;
+#else
+double r_abs(real *x)
+#endif
+{
+if(*x >= 0)
+	return(*x);
+return(- *x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_acos.c b/src/f2c/r_acos.c
new file mode 100644
index 0000000..103c7ff
--- /dev/null
+++ b/src/f2c/r_acos.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double acos();
+double r_acos(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_acos(real *x)
+#endif
+{
+return( acos(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_asin.c b/src/f2c/r_asin.c
new file mode 100644
index 0000000..432b940
--- /dev/null
+++ b/src/f2c/r_asin.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double asin();
+double r_asin(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_asin(real *x)
+#endif
+{
+return( asin(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_atan.c b/src/f2c/r_atan.c
new file mode 100644
index 0000000..7656982
--- /dev/null
+++ b/src/f2c/r_atan.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double atan();
+double r_atan(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_atan(real *x)
+#endif
+{
+return( atan(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_atn2.c b/src/f2c/r_atn2.c
new file mode 100644
index 0000000..ab957b8
--- /dev/null
+++ b/src/f2c/r_atn2.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double atan2();
+double r_atn2(x,y) real *x, *y;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_atn2(real *x, real *y)
+#endif
+{
+return( atan2(*x,*y) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_cnjg.c b/src/f2c/r_cnjg.c
new file mode 100644
index 0000000..2af713d
--- /dev/null
+++ b/src/f2c/r_cnjg.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+VOID r_cnjg(r, z) f2c_complex *r, *z;
+#else
+VOID r_cnjg(f2c_complex *r, f2c_complex *z)
+#endif
+{
+	real zi = z->i;
+	r->r = z->r;
+	r->i = -zi;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_cos.c b/src/f2c/r_cos.c
new file mode 100644
index 0000000..4418f0c
--- /dev/null
+++ b/src/f2c/r_cos.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double cos();
+double r_cos(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_cos(real *x)
+#endif
+{
+return( cos(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_cosh.c b/src/f2c/r_cosh.c
new file mode 100644
index 0000000..f547835
--- /dev/null
+++ b/src/f2c/r_cosh.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double cosh();
+double r_cosh(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_cosh(real *x)
+#endif
+{
+return( cosh(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_dim.c b/src/f2c/r_dim.c
new file mode 100644
index 0000000..d573ca3
--- /dev/null
+++ b/src/f2c/r_dim.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double r_dim(a,b) real *a, *b;
+#else
+double r_dim(real *a, real *b)
+#endif
+{
+return( *a > *b ? *a - *b : 0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_exp.c b/src/f2c/r_exp.c
new file mode 100644
index 0000000..4e67979
--- /dev/null
+++ b/src/f2c/r_exp.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double exp();
+double r_exp(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_exp(real *x)
+#endif
+{
+return( exp(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_imag.c b/src/f2c/r_imag.c
new file mode 100644
index 0000000..621839b
--- /dev/null
+++ b/src/f2c/r_imag.c
@@ -0,0 +1,16 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double r_imag(z) f2c_complex *z;
+#else
+double r_imag(f2c_complex *z)
+#endif
+{
+return(z->i);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_int.c b/src/f2c/r_int.c
new file mode 100644
index 0000000..bff8717
--- /dev/null
+++ b/src/f2c/r_int.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+double r_int(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_int(real *x)
+#endif
+{
+return( (*x>0) ? floor(*x) : -floor(- *x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_lg10.c b/src/f2c/r_lg10.c
new file mode 100644
index 0000000..64ffddf
--- /dev/null
+++ b/src/f2c/r_lg10.c
@@ -0,0 +1,21 @@
+#include "f2c.h"
+
+#define log10e 0.43429448190325182765
+
+#ifdef KR_headers
+double log();
+double r_lg10(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_lg10(real *x)
+#endif
+{
+return( log10e * log(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_log.c b/src/f2c/r_log.c
new file mode 100644
index 0000000..94c79b0
--- /dev/null
+++ b/src/f2c/r_log.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double log();
+double r_log(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_log(real *x)
+#endif
+{
+return( log(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_mod.c b/src/f2c/r_mod.c
new file mode 100644
index 0000000..63ed175
--- /dev/null
+++ b/src/f2c/r_mod.c
@@ -0,0 +1,46 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+#ifdef IEEE_drem
+double drem();
+#else
+double floor();
+#endif
+double r_mod(x,y) real *x, *y;
+#else
+#ifdef IEEE_drem
+double drem(double, double);
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+double r_mod(real *x, real *y)
+#endif
+{
+#ifdef IEEE_drem
+	double xa, ya, z;
+	if ((ya = *y) < 0.)
+		ya = -ya;
+	z = drem(xa = *x, ya);
+	if (xa > 0) {
+		if (z < 0)
+			z += ya;
+		}
+	else if (z > 0)
+		z -= ya;
+	return z;
+#else
+	double quotient;
+	if( (quotient = (double)*x / *y) >= 0)
+		quotient = floor(quotient);
+	else
+		quotient = -floor(-quotient);
+	return(*x - (*y) * quotient );
+#endif
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_nint.c b/src/f2c/r_nint.c
new file mode 100644
index 0000000..7cc3f1b
--- /dev/null
+++ b/src/f2c/r_nint.c
@@ -0,0 +1,20 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double floor();
+double r_nint(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_nint(real *x)
+#endif
+{
+return( (*x)>=0 ?
+	floor(*x + .5) : -floor(.5 - *x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_sign.c b/src/f2c/r_sign.c
new file mode 100644
index 0000000..797db1a
--- /dev/null
+++ b/src/f2c/r_sign.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double r_sign(a,b) real *a, *b;
+#else
+double r_sign(real *a, real *b)
+#endif
+{
+double x;
+x = (*a >= 0 ? *a : - *a);
+return( *b >= 0 ? x : -x);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_sin.c b/src/f2c/r_sin.c
new file mode 100644
index 0000000..37e0df2
--- /dev/null
+++ b/src/f2c/r_sin.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sin();
+double r_sin(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_sin(real *x)
+#endif
+{
+return( sin(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_sinh.c b/src/f2c/r_sinh.c
new file mode 100644
index 0000000..39878f0
--- /dev/null
+++ b/src/f2c/r_sinh.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sinh();
+double r_sinh(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_sinh(real *x)
+#endif
+{
+return( sinh(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_sqrt.c b/src/f2c/r_sqrt.c
new file mode 100644
index 0000000..e7b2c1c
--- /dev/null
+++ b/src/f2c/r_sqrt.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sqrt();
+double r_sqrt(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_sqrt(real *x)
+#endif
+{
+return( sqrt(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_tan.c b/src/f2c/r_tan.c
new file mode 100644
index 0000000..1774bed
--- /dev/null
+++ b/src/f2c/r_tan.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double tan();
+double r_tan(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_tan(real *x)
+#endif
+{
+return( tan(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/r_tanh.c b/src/f2c/r_tanh.c
new file mode 100644
index 0000000..7739c6c
--- /dev/null
+++ b/src/f2c/r_tanh.c
@@ -0,0 +1,19 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double tanh();
+double r_tanh(x) real *x;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+double r_tanh(real *x)
+#endif
+{
+return( tanh(*x) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/rdfmt.c b/src/f2c/rdfmt.c
new file mode 100644
index 0000000..09f3ccf
--- /dev/null
+++ b/src/f2c/rdfmt.c
@@ -0,0 +1,553 @@
+#include "f2c.h"
+#include "fio.h"
+
+#ifdef KR_headers
+extern double atof();
+#define Const /*nothing*/
+#else
+#define Const const
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#endif
+
+#include "fmt.h"
+#include "fp.h"
+#include "ctype.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ static int
+#ifdef KR_headers
+rd_Z(n,w,len) Uint *n; ftnlen len;
+#else
+rd_Z(Uint *n, int w, ftnlen len)
+#endif
+{
+	long x[9];
+	char *s, *s0, *s1, *se, *t;
+	Const char *sc;
+	int ch, i, w1, w2;
+	static char hex[256];
+	static int one = 1;
+	int bad = 0;
+
+	if (!hex['0']) {
+		sc = "0123456789";
+		while(ch = *sc++)
+			hex[ch] = ch - '0' + 1;
+		sc = "ABCDEF";
+		while(ch = *sc++)
+			hex[ch] = hex[ch + 'a' - 'A'] = ch - 'A' + 11;
+		}
+	s = s0 = (char *)x;
+	s1 = (char *)&x[4];
+	se = (char *)&x[8];
+	if (len > 4*sizeof(long))
+		return errno = 117;
+	while (w) {
+		GET(ch);
+		if (ch==',' || ch=='\n')
+			break;
+		w--;
+		if (ch > ' ') {
+			if (!hex[ch & 0xff])
+				bad++;
+			*s++ = ch;
+			if (s == se) {
+				/* discard excess characters */
+				for(t = s0, s = s1; t < s1;)
+					*t++ = *s++;
+				s = s1;
+				}
+			}
+		}
+	if (bad)
+		return errno = 115;
+	w = (int)len;
+	w1 = s - s0;
+	w2 = w1+1 >> 1;
+	t = (char *)n;
+	if (*(char *)&one) {
+		/* little endian */
+		t += w - 1;
+		i = -1;
+		}
+	else
+		i = 1;
+	for(; w > w2; t += i, --w)
+		*t = 0;
+	if (!w)
+		return 0;
+	if (w < w2)
+		s0 = s - (w << 1);
+	else if (w1 & 1) {
+		*t = hex[*s0++ & 0xff] - 1;
+		if (!--w)
+			return 0;
+		t += i;
+		}
+	do {
+		*t = hex[*s0 & 0xff]-1 << 4 | hex[s0[1] & 0xff]-1;
+		t += i;
+		s0 += 2;
+		}
+		while(--w);
+	return 0;
+	}
+
+ static int
+#ifdef KR_headers
+rd_I(n,w,len, base) Uint *n; int w; ftnlen len; register int base;
+#else
+rd_I(Uint *n, int w, ftnlen len, register int base)
+#endif
+{
+	int ch, sign;
+	longint x = 0;
+
+	if (w <= 0)
+		goto have_x;
+	for(;;) {
+		GET(ch);
+		if (ch != ' ')
+			break;
+		if (!--w)
+			goto have_x;
+		}
+	sign = 0;
+	switch(ch) {
+	  case ',':
+	  case '\n':
+		w = 0;
+		goto have_x;
+	  case '-':
+		sign = 1;
+	  case '+':
+		break;
+	  default:
+		if (ch >= '0' && ch <= '9') {
+			x = ch - '0';
+			break;
+			}
+		goto have_x;
+		}
+	while(--w) {
+		GET(ch);
+		if (ch >= '0' && ch <= '9') {
+			x = x*base + ch - '0';
+			continue;
+			}
+		if (ch != ' ') {
+			if (ch == '\n' || ch == ',')
+				w = 0;
+			break;
+			}
+		if (f__cblank)
+			x *= base;
+		}
+	if (sign)
+		x = -x;
+ have_x:
+	if(len == sizeof(integer))
+		n->il=x;
+	else if(len == sizeof(char))
+		n->ic = (char)x;
+#ifdef Allow_TYQUAD
+	else if (len == sizeof(longint))
+		n->ili = x;
+#endif
+	else
+		n->is = (short)x;
+	if (w) {
+		while(--w)
+			GET(ch);
+		return errno = 115;
+		}
+	return 0;
+}
+
+ static int
+#ifdef KR_headers
+rd_L(n,w,len) ftnint *n; ftnlen len;
+#else
+rd_L(ftnint *n, int w, ftnlen len)
+#endif
+{	int ch, dot, lv;
+
+	if (w <= 0)
+		goto bad;
+	for(;;) {
+		GET(ch);
+		--w;
+		if (ch != ' ')
+			break;
+		if (!w)
+			goto bad;
+		}
+	dot = 0;
+ retry:
+	switch(ch) {
+	  case '.':
+		if (dot++ || !w)
+			goto bad;
+		GET(ch);
+		--w;
+		goto retry;
+	  case 't':
+	  case 'T':
+		lv = 1;
+		break;
+	  case 'f':
+	  case 'F':
+		lv = 0;
+		break;
+	  default:
+ bad:
+		for(; w > 0; --w)
+			GET(ch);
+		/* no break */
+	  case ',':
+	  case '\n':
+		return errno = 116;
+		}
+	switch(len) {
+		case sizeof(char):	*(char *)n = (char)lv;	 break;
+		case sizeof(short):	*(short *)n = (short)lv; break;
+		default:		*n = lv;
+		}
+	while(w-- > 0) {
+		GET(ch);
+		if (ch == ',' || ch == '\n')
+			break;
+		}
+	return 0;
+}
+
+ static int
+#ifdef KR_headers
+rd_F(p, w, d, len) ufloat *p; ftnlen len;
+#else
+rd_F(ufloat *p, int w, int d, ftnlen len)
+#endif
+{
+	char s[FMAX+EXPMAXDIGS+4];
+	register int ch;
+	register char *sp, *spe, *sp1;
+	double x;
+	int scale1, se;
+	long e, exp;
+
+	sp1 = sp = s;
+	spe = sp + FMAX;
+	exp = -d;
+	x = 0.;
+
+	do {
+		GET(ch);
+		w--;
+		} while (ch == ' ' && w);
+	switch(ch) {
+		case '-': *sp++ = ch; sp1++; spe++;
+		case '+':
+			if (!w) goto zero;
+			--w;
+			GET(ch);
+		}
+	while(ch == ' ') {
+blankdrop:
+		if (!w--) goto zero; GET(ch); }
+	while(ch == '0')
+		{ if (!w--) goto zero; GET(ch); }
+	if (ch == ' ' && f__cblank)
+		goto blankdrop;
+	scale1 = f__scale;
+	while(isdigit(ch)) {
+digloop1:
+		if (sp < spe) *sp++ = ch;
+		else ++exp;
+digloop1e:
+		if (!w--) goto done;
+		GET(ch);
+		}
+	if (ch == ' ') {
+		if (f__cblank)
+			{ ch = '0'; goto digloop1; }
+		goto digloop1e;
+		}
+	if (ch == '.') {
+		exp += d;
+		if (!w--) goto done;
+		GET(ch);
+		if (sp == sp1) { /* no digits yet */
+			while(ch == '0') {
+skip01:
+				--exp;
+skip0:
+				if (!w--) goto done;
+				GET(ch);
+				}
+			if (ch == ' ') {
+				if (f__cblank) goto skip01;
+				goto skip0;
+				}
+			}
+		while(isdigit(ch)) {
+digloop2:
+			if (sp < spe)
+				{ *sp++ = ch; --exp; }
+digloop2e:
+			if (!w--) goto done;
+			GET(ch);
+			}
+		if (ch == ' ') {
+			if (f__cblank)
+				{ ch = '0'; goto digloop2; }
+			goto digloop2e;
+			}
+		}
+	switch(ch) {
+	  default:
+		break;
+	  case '-': se = 1; goto signonly;
+	  case '+': se = 0; goto signonly;
+	  case 'e':
+	  case 'E':
+	  case 'd':
+	  case 'D':
+		if (!w--)
+			goto bad;
+		GET(ch);
+		while(ch == ' ') {
+			if (!w--)
+				goto bad;
+			GET(ch);
+			}
+		se = 0;
+	  	switch(ch) {
+		  case '-': se = 1;
+		  case '+':
+signonly:
+			if (!w--)
+				goto bad;
+			GET(ch);
+			}
+		while(ch == ' ') {
+			if (!w--)
+				goto bad;
+			GET(ch);
+			}
+		if (!isdigit(ch))
+			goto bad;
+
+		e = ch - '0';
+		for(;;) {
+			if (!w--)
+				{ ch = '\n'; break; }
+			GET(ch);
+			if (!isdigit(ch)) {
+				if (ch == ' ') {
+					if (f__cblank)
+						ch = '0';
+					else continue;
+					}
+				else
+					break;
+				}
+			e = 10*e + ch - '0';
+			if (e > EXPMAX && sp > sp1)
+				goto bad;
+			}
+		if (se)
+			exp -= e;
+		else
+			exp += e;
+		scale1 = 0;
+		}
+	switch(ch) {
+	  case '\n':
+	  case ',':
+		break;
+	  default:
+bad:
+		return (errno = 115);
+		}
+done:
+	if (sp > sp1) {
+		while(*--sp == '0')
+			++exp;
+		if (exp -= scale1)
+			sprintf(sp+1, "e%ld", exp);
+		else
+			sp[1] = 0;
+		x = atof(s);
+		}
+zero:
+	if (len == sizeof(real))
+		p->pf = x;
+	else
+		p->pd = x;
+	return(0);
+	}
+
+
+ static int
+#ifdef KR_headers
+rd_A(p,len) char *p; ftnlen len;
+#else
+rd_A(char *p, ftnlen len)
+#endif
+{	int i,ch;
+	for(i=0;i<len;i++)
+	{	GET(ch);
+		*p++=VAL(ch);
+	}
+	return(0);
+}
+ static int
+#ifdef KR_headers
+rd_AW(p,w,len) char *p; ftnlen len;
+#else
+rd_AW(char *p, int w, ftnlen len)
+#endif
+{	int i,ch;
+	if(w>=len)
+	{	for(i=0;i<w-len;i++)
+			GET(ch);
+		for(i=0;i<len;i++)
+		{	GET(ch);
+			*p++=VAL(ch);
+		}
+		return(0);
+	}
+	for(i=0;i<w;i++)
+	{	GET(ch);
+		*p++=VAL(ch);
+	}
+	for(i=0;i<len-w;i++) *p++=' ';
+	return(0);
+}
+ static int
+#ifdef KR_headers
+rd_H(n,s) char *s;
+#else
+rd_H(int n, char *s)
+#endif
+{	int i,ch;
+	for(i=0;i<n;i++)
+		if((ch=(*f__getn)())<0) return(ch);
+		else *s++ = ch=='\n'?' ':ch;
+	return(1);
+}
+ static int
+#ifdef KR_headers
+rd_POS(s) char *s;
+#else
+rd_POS(char *s)
+#endif
+{	char quote;
+	int ch;
+	quote= *s++;
+	for(;*s;s++)
+		if(*s==quote && *(s+1)!=quote) break;
+		else if((ch=(*f__getn)())<0) return(ch);
+		else *s = ch=='\n'?' ':ch;
+	return(1);
+}
+
+ int
+#ifdef KR_headers
+rd_ed(p,ptr,len) struct syl *p; char *ptr; ftnlen len;
+#else
+rd_ed(struct syl *p, char *ptr, ftnlen len)
+#endif
+{	int ch;
+	for(;f__cursor>0;f__cursor--) if((ch=(*f__getn)())<0) return(ch);
+	if(f__cursor<0)
+	{	if(f__recpos+f__cursor < 0) /*err(elist->cierr,110,"fmt")*/
+			f__cursor = -f__recpos;	/* is this in the standard? */
+		if(f__external == 0) {
+			extern char *f__icptr;
+			f__icptr += f__cursor;
+		}
+		else if(f__curunit && f__curunit->useek)
+			(void) FSEEK(f__cf, f__cursor,SEEK_CUR);
+		else
+			err(f__elist->cierr,106,"fmt");
+		f__recpos += f__cursor;
+		f__cursor=0;
+	}
+	switch(p->op)
+	{
+	default: fprintf(stderr,"rd_ed, unexpected code: %d\n", p->op);
+		sig_die(f__fmtbuf, 1);
+	case IM:
+	case I: ch = rd_I((Uint *)ptr,p->p1,len, 10);
+		break;
+
+		/* O and OM don't work right for character, double, complex, */
+		/* or doublecomplex, and they differ from Fortran 90 in */
+		/* showing a minus sign for negative values. */
+
+	case OM:
+	case O: ch = rd_I((Uint *)ptr, p->p1, len, 8);
+		break;
+	case L: ch = rd_L((ftnint *)ptr,p->p1,len);
+		break;
+	case A:	ch = rd_A(ptr,len);
+		break;
+	case AW:
+		ch = rd_AW(ptr,p->p1,len);
+		break;
+	case E: case EE:
+	case D:
+	case G:
+	case GE:
+	case F:	ch = rd_F((ufloat *)ptr,p->p1,p->p2.i[0],len);
+		break;
+
+		/* Z and ZM assume 8-bit bytes. */
+
+	case ZM:
+	case Z:
+		ch = rd_Z((Uint *)ptr, p->p1, len);
+		break;
+	}
+	if(ch == 0) return(ch);
+	else if(ch == EOF) return(EOF);
+	if (f__cf)
+		clearerr(f__cf);
+	return(errno);
+}
+
+ int
+#ifdef KR_headers
+rd_ned(p) struct syl *p;
+#else
+rd_ned(struct syl *p)
+#endif
+{
+	switch(p->op)
+	{
+	default: fprintf(stderr,"rd_ned, unexpected code: %d\n", p->op);
+		sig_die(f__fmtbuf, 1);
+	case APOS:
+		return(rd_POS(p->p2.s));
+	case H:	return(rd_H(p->p1,p->p2.s));
+	case SLASH: return((*f__donewrec)());
+	case TR:
+	case X:	f__cursor += p->p1;
+		return(1);
+	case T: f__cursor=p->p1-f__recpos - 1;
+		return(1);
+	case TL: f__cursor -= p->p1;
+		if(f__cursor < -f__recpos)	/* TL1000, 1X */
+			f__cursor = -f__recpos;
+		return(1);
+	}
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/rewind.c b/src/f2c/rewind.c
new file mode 100644
index 0000000..9a0e07e
--- /dev/null
+++ b/src/f2c/rewind.c
@@ -0,0 +1,30 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef KR_headers
+integer f_rew(a) alist *a;
+#else
+integer f_rew(alist *a)
+#endif
+{
+	unit *b;
+	if(a->aunit>=MXUNIT || a->aunit<0)
+		err(a->aerr,101,"rewind");
+	b = &f__units[a->aunit];
+	if(b->ufd == NULL || b->uwrt == 3)
+		return(0);
+	if(!b->useek)
+		err(a->aerr,106,"rewind")
+	if(b->uwrt) {
+		(void) t_runc(a);
+		b->uwrt = 3;
+		}
+	rewind(b->ufd);
+	b->uend=0;
+	return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/rsfe.c b/src/f2c/rsfe.c
new file mode 100644
index 0000000..abe9724
--- /dev/null
+++ b/src/f2c/rsfe.c
@@ -0,0 +1,91 @@
+/* read sequential formatted external */
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int
+xrd_SL(Void)
+{	int ch;
+	if(!f__curunit->uend)
+		while((ch=getc(f__cf))!='\n')
+			if (ch == EOF) {
+				f__curunit->uend = 1;
+				break;
+				}
+	f__cursor=f__recpos=0;
+	return(1);
+}
+
+ int
+x_getc(Void)
+{	int ch;
+	if(f__curunit->uend) return(EOF);
+	ch = getc(f__cf);
+	if(ch!=EOF && ch!='\n')
+	{	f__recpos++;
+		return(ch);
+	}
+	if(ch=='\n')
+	{	(void) ungetc(ch,f__cf);
+		return(ch);
+	}
+	if(f__curunit->uend || feof(f__cf))
+	{	errno=0;
+		f__curunit->uend=1;
+		return(-1);
+	}
+	return(-1);
+}
+
+ int
+x_endp(Void)
+{
+	xrd_SL();
+	return f__curunit->uend == 1 ? EOF : 0;
+}
+
+ int
+x_rev(Void)
+{
+	(void) xrd_SL();
+	return(0);
+}
+#ifdef KR_headers
+integer s_rsfe(a) cilist *a; /* start */
+#else
+integer s_rsfe(cilist *a) /* start */
+#endif
+{	int n;
+	if(!f__init) f_init();
+	f__reading=1;
+	f__sequential=1;
+	f__formatted=1;
+	f__external=1;
+	if(n=c_sfe(a)) return(n);
+	f__elist=a;
+	f__cursor=f__recpos=0;
+	f__scale=0;
+	f__fmtbuf=a->cifmt;
+	f__cf=f__curunit->ufd;
+	if(pars_f(f__fmtbuf)<0) err(a->cierr,100,"startio");
+	f__getn= x_getc;
+	f__doed= rd_ed;
+	f__doned= rd_ned;
+	fmt_bg();
+	f__doend=x_endp;
+	f__donewrec=xrd_SL;
+	f__dorevert=x_rev;
+	f__cblank=f__curunit->ublnk;
+	f__cplus=0;
+	if(f__curunit->uwrt && f__nowreading(f__curunit))
+		err(a->cierr,errno,"read start");
+	if(f__curunit->uend)
+		err(f__elist->ciend,(EOF),"read start");
+	return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/rsli.c b/src/f2c/rsli.c
new file mode 100644
index 0000000..3d4ea42
--- /dev/null
+++ b/src/f2c/rsli.c
@@ -0,0 +1,109 @@
+#include "f2c.h"
+#include "fio.h"
+#include "lio.h"
+#include "fmt.h" /* for f__doend */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern flag f__lquit;
+extern int f__lcount;
+extern char *f__icptr;
+extern char *f__icend;
+extern icilist *f__svic;
+extern int f__icnum, f__recpos;
+
+static int i_getc(Void)
+{
+	if(f__recpos >= f__svic->icirlen) {
+		if (f__recpos++ == f__svic->icirlen)
+			return '\n';
+		z_rnew();
+		}
+	f__recpos++;
+	if(f__icptr >= f__icend)
+		return EOF;
+	return(*f__icptr++);
+	}
+
+ static
+#ifdef KR_headers
+int i_ungetc(ch, f) int ch; FILE *f;
+#else
+int i_ungetc(int ch, FILE *f)
+#endif
+{
+	if (--f__recpos == f__svic->icirlen)
+		return '\n';
+	if (f__recpos < -1)
+		err(f__svic->icierr,110,"recend");
+	/* *--icptr == ch, and icptr may point to read-only memory */
+	return *--f__icptr /* = ch */;
+	}
+
+ static void
+#ifdef KR_headers
+c_lir(a) icilist *a;
+#else
+c_lir(icilist *a)
+#endif
+{
+	extern int l_eof;
+	f__reading = 1;
+	f__external = 0;
+	f__formatted = 1;
+	f__svic = a;
+	L_len = a->icirlen;
+	f__recpos = -1;
+	f__icnum = f__recpos = 0;
+	f__cursor = 0;
+	l_getc = i_getc;
+	l_ungetc = i_ungetc;
+	l_eof = 0;
+	f__icptr = a->iciunit;
+	f__icend = f__icptr + a->icirlen*a->icirnum;
+	f__cf = 0;
+	f__curunit = 0;
+	f__elist = (cilist *)a;
+	}
+
+
+#ifdef KR_headers
+integer s_rsli(a) icilist *a;
+#else
+integer s_rsli(icilist *a)
+#endif
+{
+	f__lioproc = l_read;
+	f__lquit = 0;
+	f__lcount = 0;
+	c_lir(a);
+	f__doend = 0;
+	return(0);
+	}
+
+integer e_rsli(Void)
+{ return 0; }
+
+#ifdef KR_headers
+integer s_rsni(a) icilist *a;
+#else
+extern int x_rsne(cilist*);
+
+integer s_rsni(icilist *a)
+#endif
+{
+	extern int nml_read;
+	integer rv;
+	cilist ca;
+	ca.ciend = a->iciend;
+	ca.cierr = a->icierr;
+	ca.cifmt = a->icifmt;
+	c_lir(a);
+	rv = x_rsne(&ca);
+	nml_read = 0;
+	return rv;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/rsne.c b/src/f2c/rsne.c
new file mode 100644
index 0000000..e8e9dae
--- /dev/null
+++ b/src/f2c/rsne.c
@@ -0,0 +1,618 @@
+#include "f2c.h"
+#include "fio.h"
+#include "lio.h"
+
+#define MAX_NL_CACHE 3	/* maximum number of namelist hash tables to cache */
+#define MAXDIM 20	/* maximum number of subscripts */
+
+ struct dimen {
+	ftnlen extent;
+	ftnlen curval;
+	ftnlen delta;
+	ftnlen stride;
+	};
+ typedef struct dimen dimen;
+
+ struct hashentry {
+	struct hashentry *next;
+	char *name;
+	Vardesc *vd;
+	};
+ typedef struct hashentry hashentry;
+
+ struct hashtab {
+	struct hashtab *next;
+	Namelist *nl;
+	int htsize;
+	hashentry *tab[1];
+	};
+ typedef struct hashtab hashtab;
+
+ static hashtab *nl_cache;
+ static int n_nlcache;
+ static hashentry **zot;
+ static int colonseen;
+ extern ftnlen f__typesize[];
+
+ extern flag f__lquit;
+ extern int f__lcount, nml_read;
+ extern int t_getc(Void);
+
+#ifdef KR_headers
+ extern char *malloc(), *memset();
+#define Const /*nothing*/
+
+#ifdef ungetc
+ static int
+un_getc(x,f__cf) int x; FILE *f__cf;
+{ return ungetc(x,f__cf); }
+#else
+#define un_getc ungetc
+ extern int ungetc();
+#endif
+
+#else
+#define Const const
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#include "string.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ungetc
+ static int
+un_getc(int x, FILE *f__cf)
+{ return ungetc(x,f__cf); }
+#else
+#define un_getc ungetc
+extern int ungetc(int, FILE*);	/* for systems with a buggy stdio.h */
+#endif
+#endif
+
+ static Vardesc *
+#ifdef KR_headers
+hash(ht, s) hashtab *ht; register char *s;
+#else
+hash(hashtab *ht, register char *s)
+#endif
+{
+	register int c, x;
+	register hashentry *h;
+	char *s0 = s;
+
+	for(x = 0; c = *s++; x = x & 0x4000 ? ((x << 1) & 0x7fff) + 1 : x << 1)
+		x += c;
+	for(h = *(zot = ht->tab + x % ht->htsize); h; h = h->next)
+		if (!strcmp(s0, h->name))
+			return h->vd;
+	return 0;
+	}
+
+ hashtab *
+#ifdef KR_headers
+mk_hashtab(nl) Namelist *nl;
+#else
+mk_hashtab(Namelist *nl)
+#endif
+{
+	int nht, nv;
+	hashtab *ht;
+	Vardesc *v, **vd, **vde;
+	hashentry *he;
+
+	hashtab **x, **x0, *y;
+	for(x = &nl_cache; y = *x; x0 = x, x = &y->next)
+		if (nl == y->nl)
+			return y;
+	if (n_nlcache >= MAX_NL_CACHE) {
+		/* discard least recently used namelist hash table */
+		y = *x0;
+		free((char *)y->next);
+		y->next = 0;
+		}
+	else
+		n_nlcache++;
+	nv = nl->nvars;
+	if (nv >= 0x4000)
+		nht = 0x7fff;
+	else {
+		for(nht = 1; nht < nv; nht <<= 1);
+		nht += nht - 1;
+		}
+	ht = (hashtab *)malloc(sizeof(hashtab) + (nht-1)*sizeof(hashentry *)
+				+ nv*sizeof(hashentry));
+	if (!ht)
+		return 0;
+	he = (hashentry *)&ht->tab[nht];
+	ht->nl = nl;
+	ht->htsize = nht;
+	ht->next = nl_cache;
+	nl_cache = ht;
+	memset((char *)ht->tab, 0, nht*sizeof(hashentry *));
+	vd = nl->vars;
+	vde = vd + nv;
+	while(vd < vde) {
+		v = *vd++;
+		if (!hash(ht, v->name)) {
+			he->next = *zot;
+			*zot = he;
+			he->name = v->name;
+			he->vd = v;
+			he++;
+			}
+		}
+	return ht;
+	}
+
+static char Alpha[256], Alphanum[256];
+
+ static VOID
+nl_init(Void) {
+	Const char *s;
+	int c;
+
+	if(!f__init)
+		f_init();
+	for(s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; c = *s++; )
+		Alpha[c]
+		= Alphanum[c]
+		= Alpha[c + 'a' - 'A']
+		= Alphanum[c + 'a' - 'A']
+		= c;
+	for(s = "0123456789_"; c = *s++; )
+		Alphanum[c] = c;
+	}
+
+#define GETC(x) (x=(*l_getc)())
+#define Ungetc(x,y) (*l_ungetc)(x,y)
+
+ static int
+#ifdef KR_headers
+getname(s, slen) register char *s; int slen;
+#else
+getname(register char *s, int slen)
+#endif
+{
+	register char *se = s + slen - 1;
+	register int ch;
+
+	GETC(ch);
+	if (!(*s++ = Alpha[ch & 0xff])) {
+		if (ch != EOF)
+			ch = 115;
+		errfl(f__elist->cierr, ch, "namelist read");
+		}
+	while(*s = Alphanum[GETC(ch) & 0xff])
+		if (s < se)
+			s++;
+	if (ch == EOF)
+		err(f__elist->cierr, EOF, "namelist read");
+	if (ch > ' ')
+		Ungetc(ch,f__cf);
+	return *s = 0;
+	}
+
+ static int
+#ifdef KR_headers
+getnum(chp, val) int *chp; ftnlen *val;
+#else
+getnum(int *chp, ftnlen *val)
+#endif
+{
+	register int ch, sign;
+	register ftnlen x;
+
+	while(GETC(ch) <= ' ' && ch >= 0);
+	if (ch == '-') {
+		sign = 1;
+		GETC(ch);
+		}
+	else {
+		sign = 0;
+		if (ch == '+')
+			GETC(ch);
+		}
+	x = ch - '0';
+	if (x < 0 || x > 9)
+		return 115;
+	while(GETC(ch) >= '0' && ch <= '9')
+		x = 10*x + ch - '0';
+	while(ch <= ' ' && ch >= 0)
+		GETC(ch);
+	if (ch == EOF)
+		return EOF;
+	*val = sign ? -x : x;
+	*chp = ch;
+	return 0;
+	}
+
+ static int
+#ifdef KR_headers
+getdimen(chp, d, delta, extent, x1)
+ int *chp; dimen *d; ftnlen delta, extent, *x1;
+#else
+getdimen(int *chp, dimen *d, ftnlen delta, ftnlen extent, ftnlen *x1)
+#endif
+{
+	register int k;
+	ftnlen x2, x3;
+
+	if (k = getnum(chp, x1))
+		return k;
+	x3 = 1;
+	if (*chp == ':') {
+		if (k = getnum(chp, &x2))
+			return k;
+		x2 -= *x1;
+		if (*chp == ':') {
+			if (k = getnum(chp, &x3))
+				return k;
+			if (!x3)
+				return 123;
+			x2 /= x3;
+			colonseen = 1;
+			}
+		if (x2 < 0 || x2 >= extent)
+			return 123;
+		d->extent = x2 + 1;
+		}
+	else
+		d->extent = 1;
+	d->curval = 0;
+	d->delta = delta;
+	d->stride = x3;
+	return 0;
+	}
+
+#ifndef No_Namelist_Questions
+ static Void
+#ifdef KR_headers
+print_ne(a) cilist *a;
+#else
+print_ne(cilist *a)
+#endif
+{
+	flag intext = f__external;
+	int rpsave = f__recpos;
+	FILE *cfsave = f__cf;
+	unit *usave = f__curunit;
+	cilist t;
+	t = *a;
+	t.ciunit = 6;
+	s_wsne(&t);
+	fflush(f__cf);
+	f__external = intext;
+	f__reading = 1;
+	f__recpos = rpsave;
+	f__cf = cfsave;
+	f__curunit = usave;
+	f__elist = a;
+	}
+#endif
+
+ static char where0[] = "namelist read start ";
+
+ int
+#ifdef KR_headers
+x_rsne(a) cilist *a;
+#else
+x_rsne(cilist *a)
+#endif
+{
+	int ch, got1, k, n, nd, quote, readall;
+	Namelist *nl;
+	static char where[] = "namelist read";
+	char buf[64];
+	hashtab *ht;
+	Vardesc *v;
+	dimen *dn, *dn0, *dn1;
+	ftnlen *dims, *dims1;
+	ftnlen b, b0, b1, ex, no, nomax, size, span;
+	ftnint no1, no2, type;
+	char *vaddr;
+	long iva, ivae;
+	dimen dimens[MAXDIM], substr;
+
+	if (!Alpha['a'])
+		nl_init();
+	f__reading=1;
+	f__formatted=1;
+	got1 = 0;
+ top:
+	for(;;) switch(GETC(ch)) {
+		case EOF:
+ eof:
+			err(a->ciend,(EOF),where0);
+		case '&':
+		case '$':
+			goto have_amp;
+#ifndef No_Namelist_Questions
+		case '?':
+			print_ne(a);
+			continue;
+#endif
+		default:
+			if (ch <= ' ' && ch >= 0)
+				continue;
+#ifndef No_Namelist_Comments
+			while(GETC(ch) != '\n')
+				if (ch == EOF)
+					goto eof;
+#else
+			errfl(a->cierr, 115, where0);
+#endif
+		}
+ have_amp:
+	if (ch = getname(buf,sizeof(buf)))
+		return ch;
+	nl = (Namelist *)a->cifmt;
+	if (strcmp(buf, nl->name))
+#ifdef No_Bad_Namelist_Skip
+		errfl(a->cierr, 118, where0);
+#else
+	{
+		fprintf(stderr,
+			"Skipping namelist \"%s\": seeking namelist \"%s\".\n",
+			buf, nl->name);
+		fflush(stderr);
+		for(;;) switch(GETC(ch)) {
+			case EOF:
+				err(a->ciend, EOF, where0);
+			case '/':
+			case '&':
+			case '$':
+				if (f__external)
+					e_rsle();
+				else
+					z_rnew();
+				goto top;
+			case '"':
+			case '\'':
+				quote = ch;
+ more_quoted:
+				while(GETC(ch) != quote)
+					if (ch == EOF)
+						err(a->ciend, EOF, where0);
+				if (GETC(ch) == quote)
+					goto more_quoted;
+				Ungetc(ch,f__cf);
+			default:
+				continue;
+			}
+		}
+#endif
+	ht = mk_hashtab(nl);
+	if (!ht)
+		errfl(f__elist->cierr, 113, where0);
+	for(;;) {
+		for(;;) switch(GETC(ch)) {
+			case EOF:
+				if (got1)
+					return 0;
+				err(a->ciend, EOF, where0);
+			case '/':
+			case '$':
+			case '&':
+				return 0;
+			default:
+				if (ch <= ' ' && ch >= 0 || ch == ',')
+					continue;
+				Ungetc(ch,f__cf);
+				if (ch = getname(buf,sizeof(buf)))
+					return ch;
+				goto havename;
+			}
+ havename:
+		v = hash(ht,buf);
+		if (!v)
+			errfl(a->cierr, 119, where);
+		while(GETC(ch) <= ' ' && ch >= 0);
+		vaddr = v->addr;
+		type = v->type;
+		if (type < 0) {
+			size = -type;
+			type = TYCHAR;
+			}
+		else
+			size = f__typesize[type];
+		ivae = size;
+		iva = readall = 0;
+		if (ch == '(' /*)*/ ) {
+			dn = dimens;
+			if (!(dims = v->dims)) {
+				if (type != TYCHAR)
+					errfl(a->cierr, 122, where);
+				if (k = getdimen(&ch, dn, (ftnlen)size,
+						(ftnlen)size, &b))
+					errfl(a->cierr, k, where);
+				if (ch != ')')
+					errfl(a->cierr, 115, where);
+				b1 = dn->extent;
+				if (--b < 0 || b + b1 > size)
+					return 124;
+				iva += b;
+				size = b1;
+				while(GETC(ch) <= ' ' && ch >= 0);
+				goto scalar;
+				}
+			nd = (int)dims[0];
+			nomax = span = dims[1];
+			ivae = iva + size*nomax;
+			colonseen = 0;
+			if (k = getdimen(&ch, dn, size, nomax, &b))
+				errfl(a->cierr, k, where);
+			no = dn->extent;
+			b0 = dims[2];
+			dims1 = dims += 3;
+			ex = 1;
+			for(n = 1; n++ < nd; dims++) {
+				if (ch != ',')
+					errfl(a->cierr, 115, where);
+				dn1 = dn + 1;
+				span /= *dims;
+				if (k = getdimen(&ch, dn1, dn->delta**dims,
+						span, &b1))
+					errfl(a->cierr, k, where);
+				ex *= *dims;
+				b += b1*ex;
+				no *= dn1->extent;
+				dn = dn1;
+				}
+			if (ch != ')')
+				errfl(a->cierr, 115, where);
+			readall = 1 - colonseen;
+			b -= b0;
+			if (b < 0 || b >= nomax)
+				errfl(a->cierr, 125, where);
+			iva += size * b;
+			dims = dims1;
+			while(GETC(ch) <= ' ' && ch >= 0);
+			no1 = 1;
+			dn0 = dimens;
+			if (type == TYCHAR && ch == '(' /*)*/) {
+				if (k = getdimen(&ch, &substr, size, size, &b))
+					errfl(a->cierr, k, where);
+				if (ch != ')')
+					errfl(a->cierr, 115, where);
+				b1 = substr.extent;
+				if (--b < 0 || b + b1 > size)
+					return 124;
+				iva += b;
+				b0 = size;
+				size = b1;
+				while(GETC(ch) <= ' ' && ch >= 0);
+				if (b1 < b0)
+					goto delta_adj;
+				}
+			if (readall)
+				goto delta_adj;
+			for(; dn0 < dn; dn0++) {
+				if (dn0->extent != *dims++ || dn0->stride != 1)
+					break;
+				no1 *= dn0->extent;
+				}
+			if (dn0 == dimens && dimens[0].stride == 1) {
+				no1 = dimens[0].extent;
+				dn0++;
+				}
+ delta_adj:
+			ex = 0;
+			for(dn1 = dn0; dn1 <= dn; dn1++)
+				ex += (dn1->extent-1)
+					* (dn1->delta *= dn1->stride);
+			for(dn1 = dn; dn1 > dn0; dn1--) {
+				ex -= (dn1->extent - 1) * dn1->delta;
+				dn1->delta -= ex;
+				}
+			}
+		else if (dims = v->dims) {
+			no = no1 = dims[1];
+			ivae = iva + no*size;
+			}
+		else
+ scalar:
+			no = no1 = 1;
+		if (ch != '=')
+			errfl(a->cierr, 115, where);
+		got1 = nml_read = 1;
+		f__lcount = 0;
+	 readloop:
+		for(;;) {
+			if (iva >= ivae || iva < 0) {
+				f__lquit = 1;
+				goto mustend;
+				}
+			else if (iva + no1*size > ivae)
+				no1 = (ivae - iva)/size;
+			f__lquit = 0;
+			if (k = l_read(&no1, vaddr + iva, size, type))
+				return k;
+			if (f__lquit == 1)
+				return 0;
+			if (readall) {
+				iva += dn0->delta;
+				if (f__lcount > 0) {
+					no2 = (ivae - iva)/size;
+					if (no2 > f__lcount)
+						no2 = f__lcount;
+					if (k = l_read(&no2, vaddr + iva,
+							size, type))
+						return k;
+					iva += no2 * dn0->delta;
+					}
+				}
+ mustend:
+			GETC(ch);
+			if (readall)
+				if (iva >= ivae)
+					readall = 0;
+				else for(;;) {
+					switch(ch) {
+						case ' ':
+						case '\t':
+						case '\n':
+							GETC(ch);
+							continue;
+						}
+					break;
+					}
+			if (ch == '/' || ch == '$' || ch == '&') {
+				f__lquit = 1;
+				return 0;
+				}
+			else if (f__lquit) {
+				while(ch <= ' ' && ch >= 0)
+					GETC(ch);
+				Ungetc(ch,f__cf);
+				if (!Alpha[ch & 0xff] && ch >= 0)
+					errfl(a->cierr, 125, where);
+				break;
+				}
+			Ungetc(ch,f__cf);
+			if (readall && !Alpha[ch & 0xff])
+				goto readloop;
+			if ((no -= no1) <= 0)
+				break;
+			for(dn1 = dn0; dn1 <= dn; dn1++) {
+				if (++dn1->curval < dn1->extent) {
+					iva += dn1->delta;
+					goto readloop;
+					}
+				dn1->curval = 0;
+				}
+			break;
+			}
+		}
+	}
+
+ integer
+#ifdef KR_headers
+s_rsne(a) cilist *a;
+#else
+s_rsne(cilist *a)
+#endif
+{
+	extern int l_eof;
+	int n;
+
+	f__external=1;
+	l_eof = 0;
+	if(n = c_le(a))
+		return n;
+	if(f__curunit->uwrt && f__nowreading(f__curunit))
+		err(a->cierr,errno,where0);
+	l_getc = t_getc;
+	l_ungetc = un_getc;
+	f__doend = xrd_SL;
+	n = x_rsne(a);
+	nml_read = 0;
+	if (n)
+		return n;
+	return e_rsle();
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/s_cat.c b/src/f2c/s_cat.c
new file mode 100644
index 0000000..8d92a63
--- /dev/null
+++ b/src/f2c/s_cat.c
@@ -0,0 +1,86 @@
+/* Unless compiled with -DNO_OVERWRITE, this variant of s_cat allows the
+ * target of a concatenation to appear on its right-hand side (contrary
+ * to the Fortran 77 Standard, but in accordance with Fortran 90).
+ */
+
+#include "f2c.h"
+#ifndef NO_OVERWRITE
+#include "stdio.h"
+#undef abs
+#ifdef KR_headers
+ extern char *F77_aloc();
+ extern void free();
+ extern void exit_();
+#else
+#undef min
+#undef max
+#include "stdlib.h"
+extern
+#ifdef __cplusplus
+	"C"
+#endif
+	char *F77_aloc(ftnlen, const char*);
+#endif
+#include "string.h"
+#endif /* NO_OVERWRITE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ VOID
+#ifdef KR_headers
+s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
+#else
+s_cat(char *lp, char *rpp[], ftnint rnp[], ftnint *np, ftnlen ll)
+#endif
+{
+	ftnlen i, nc;
+	char *rp;
+	ftnlen n = *np;
+#ifndef NO_OVERWRITE
+	ftnlen L, m;
+	char *lp0, *lp1;
+
+	lp0 = 0;
+	lp1 = lp;
+	L = ll;
+	i = 0;
+	while(i < n) {
+		rp = rpp[i];
+		m = rnp[i++];
+		if (rp >= lp1 || rp + m <= lp) {
+			if ((L -= m) <= 0) {
+				n = i;
+				break;
+				}
+			lp1 += m;
+			continue;
+			}
+		lp0 = lp;
+		lp = lp1 = F77_aloc(L = ll, "s_cat");
+		break;
+		}
+	lp1 = lp;
+#endif /* NO_OVERWRITE */
+	for(i = 0 ; i < n ; ++i) {
+		nc = ll;
+		if(rnp[i] < nc)
+			nc = rnp[i];
+		ll -= nc;
+		rp = rpp[i];
+		while(--nc >= 0)
+			*lp++ = *rp++;
+		}
+	while(--ll >= 0)
+		*lp++ = ' ';
+#ifndef NO_OVERWRITE
+	if (lp0) {
+		memcpy(lp0, lp1, L);
+		free(lp1);
+		}
+#endif
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/s_cmp.c b/src/f2c/s_cmp.c
new file mode 100644
index 0000000..3a2ea67
--- /dev/null
+++ b/src/f2c/s_cmp.c
@@ -0,0 +1,50 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* compare two strings */
+
+#ifdef KR_headers
+integer s_cmp(a0, b0, la, lb) char *a0, *b0; ftnlen la, lb;
+#else
+integer s_cmp(char *a0, char *b0, ftnlen la, ftnlen lb)
+#endif
+{
+register unsigned char *a, *aend, *b, *bend;
+a = (unsigned char *)a0;
+b = (unsigned char *)b0;
+aend = a + la;
+bend = b + lb;
+
+if(la <= lb)
+	{
+	while(a < aend)
+		if(*a != *b)
+			return( *a - *b );
+		else
+			{ ++a; ++b; }
+
+	while(b < bend)
+		if(*b != ' ')
+			return( ' ' - *b );
+		else	++b;
+	}
+
+else
+	{
+	while(b < bend)
+		if(*a == *b)
+			{ ++a; ++b; }
+		else
+			return( *a - *b );
+	while(a < aend)
+		if(*a != ' ')
+			return(*a - ' ');
+		else	++a;
+	}
+return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/s_copy.c b/src/f2c/s_copy.c
new file mode 100644
index 0000000..9dacfc7
--- /dev/null
+++ b/src/f2c/s_copy.c
@@ -0,0 +1,57 @@
+/* Unless compiled with -DNO_OVERWRITE, this variant of s_copy allows the
+ * target of an assignment to appear on its right-hand side (contrary
+ * to the Fortran 77 Standard, but in accordance with Fortran 90),
+ * as in  a(2:5) = a(4:7) .
+ */
+
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* assign strings:  a = b */
+
+#ifdef KR_headers
+VOID s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
+#else
+void s_copy(register char *a, register char *b, ftnlen la, ftnlen lb)
+#endif
+{
+	register char *aend, *bend;
+
+	aend = a + la;
+
+	if(la <= lb)
+#ifndef NO_OVERWRITE
+		if (a <= b || a >= b + la)
+#endif
+			while(a < aend)
+				*a++ = *b++;
+#ifndef NO_OVERWRITE
+		else
+			for(b += la; a < aend; )
+				*--aend = *--b;
+#endif
+
+	else {
+		bend = b + lb;
+#ifndef NO_OVERWRITE
+		if (a <= b || a >= bend)
+#endif
+			while(b < bend)
+				*a++ = *b++;
+#ifndef NO_OVERWRITE
+		else {
+			a += lb;
+			while(b < bend)
+				*--a = *--bend;
+			a += lb;
+			}
+#endif
+		while(a < aend)
+			*a++ = ' ';
+		}
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/s_paus.c b/src/f2c/s_paus.c
new file mode 100644
index 0000000..51d80eb
--- /dev/null
+++ b/src/f2c/s_paus.c
@@ -0,0 +1,96 @@
+#include "stdio.h"
+#include "f2c.h"
+#define PAUSESIG 15
+
+#include "signal1.h"
+#ifdef KR_headers
+#define Void /* void */
+#define Int /* int */
+#else
+#define Void void
+#define Int int
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int getpid(void), isatty(int), pause(void);
+#endif
+
+extern VOID f_exit(Void);
+
+#ifndef MSDOS
+ static VOID
+waitpause(Sigarg)
+{	Use_Sigarg;
+	return;
+	}
+#endif
+
+ static VOID
+#ifdef KR_headers
+s_1paus(fin) FILE *fin;
+#else
+s_1paus(FILE *fin)
+#endif
+{
+	fprintf(stderr,
+	"To resume execution, type go.  Other input will terminate the job.\n");
+	fflush(stderr);
+	if( getc(fin)!='g' || getc(fin)!='o' || getc(fin)!='\n' ) {
+		fprintf(stderr, "STOP\n");
+#ifdef NO_ONEXIT
+		f_exit();
+#endif
+		exit(0);
+		}
+	}
+
+ int
+#ifdef KR_headers
+s_paus(s, n) char *s; ftnlen n;
+#else
+s_paus(char *s, ftnlen n)
+#endif
+{
+	fprintf(stderr, "PAUSE ");
+	if(n > 0)
+		fprintf(stderr, " %.*s", (int)n, s);
+	fprintf(stderr, " statement executed\n");
+	if( isatty(fileno(stdin)) )
+		s_1paus(stdin);
+	else {
+#ifdef MSDOS
+		FILE *fin;
+		fin = fopen("con", "r");
+		if (!fin) {
+			fprintf(stderr, "s_paus: can't open con!\n");
+			fflush(stderr);
+			exit(1);
+			}
+		s_1paus(fin);
+		fclose(fin);
+#else
+		fprintf(stderr,
+		"To resume execution, execute a   kill -%d %d   command\n",
+			PAUSESIG, getpid() );
+		signal1(PAUSESIG, waitpause);
+		fflush(stderr);
+		pause();
+#endif
+		}
+	fprintf(stderr, "Execution resumes after PAUSE.\n");
+	fflush(stderr);
+	return 0; /* NOT REACHED */
+#ifdef __cplusplus
+	}
+#endif
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/s_rnge.c b/src/f2c/s_rnge.c
new file mode 100644
index 0000000..3dbc513
--- /dev/null
+++ b/src/f2c/s_rnge.c
@@ -0,0 +1,32 @@
+#include "stdio.h"
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* called when a subscript is out of range */
+
+#ifdef KR_headers
+extern VOID sig_die();
+integer s_rnge(varn, offset, procn, line) char *varn, *procn; ftnint offset, line;
+#else
+extern VOID sig_die(const char*,int);
+integer s_rnge(char *varn, ftnint offset, char *procn, ftnint line)
+#endif
+{
+register int i;
+
+fprintf(stderr, "Subscript out of range on file line %ld, procedure ",
+	(long)line);
+while((i = *procn) && i != '_' && i != ' ')
+	putc(*procn++, stderr);
+fprintf(stderr, ".\nAttempt to access the %ld-th element of variable ",
+	(long)offset+1);
+while((i = *varn) && i != ' ')
+	putc(*varn++, stderr);
+sig_die(".", 1);
+return 0;	/* not reached */
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/s_stop.c b/src/f2c/s_stop.c
new file mode 100644
index 0000000..68233ae
--- /dev/null
+++ b/src/f2c/s_stop.c
@@ -0,0 +1,48 @@
+#include "stdio.h"
+#include "f2c.h"
+
+#ifdef KR_headers
+extern void f_exit();
+int s_stop(s, n) char *s; ftnlen n;
+#else
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+void f_exit(void);
+
+int s_stop(char *s, ftnlen n)
+#endif
+{
+int i;
+
+if(n > 0)
+	{
+	fprintf(stderr, "STOP ");
+	for(i = 0; i<n ; ++i)
+		putc(*s++, stderr);
+	fprintf(stderr, " statement executed\n");
+	}
+#ifdef NO_ONEXIT
+f_exit();
+#endif
+exit(0);
+
+/* We cannot avoid (useless) compiler diagnostics here:		*/
+/* some compilers complain if there is no return statement,	*/
+/* and others complain that this one cannot be reached.		*/
+
+return 0; /* NOT REACHED */
+}
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/sfe.c b/src/f2c/sfe.c
new file mode 100644
index 0000000..d24af6d
--- /dev/null
+++ b/src/f2c/sfe.c
@@ -0,0 +1,47 @@
+/* sequential formatted external common routines*/
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern char *f__fmtbuf;
+#else
+extern const char *f__fmtbuf;
+#endif
+
+integer e_rsfe(Void)
+{	int n;
+	n=en_fio();
+	f__fmtbuf=NULL;
+	return(n);
+}
+
+ int
+#ifdef KR_headers
+c_sfe(a) cilist *a; /* check */
+#else
+c_sfe(cilist *a) /* check */
+#endif
+{	unit *p;
+	f__curunit = p = &f__units[a->ciunit];
+	if(a->ciunit >= MXUNIT || a->ciunit<0)
+		err(a->cierr,101,"startio");
+	if(p->ufd==NULL && fk_open(SEQ,FMT,a->ciunit)) err(a->cierr,114,"sfe")
+	if(!p->ufmt) err(a->cierr,102,"sfe")
+	return(0);
+}
+integer e_wsfe(Void)
+{
+	int n = en_fio();
+	f__fmtbuf = NULL;
+#ifdef ALWAYS_FLUSH
+	if (!n && fflush(f__cf))
+		err(f__elist->cierr, errno, "write end");
+#endif
+	return n;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/sig_die.c b/src/f2c/sig_die.c
new file mode 100644
index 0000000..63a73d9
--- /dev/null
+++ b/src/f2c/sig_die.c
@@ -0,0 +1,51 @@
+#include "stdio.h"
+#include "signal.h"
+
+#ifndef SIGIOT
+#ifdef SIGABRT
+#define SIGIOT SIGABRT
+#endif
+#endif
+
+#ifdef KR_headers
+void sig_die(s, kill) char *s; int kill;
+#else
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern void f_exit(void);
+
+void sig_die(const char *s, int kill)
+#endif
+{
+	/* print error message, then clear buffers */
+	fprintf(stderr, "%s\n", s);
+
+	if(kill)
+		{
+		fflush(stderr);
+		f_exit();
+		fflush(stderr);
+		/* now get a core */
+#ifdef SIGIOT
+		signal(SIGIOT, SIG_DFL);
+#endif
+		abort();
+		}
+	else {
+#ifdef NO_ONEXIT
+		f_exit();
+#endif
+		exit(1);
+		}
+	}
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/signal1.h b/src/f2c/signal1.h
new file mode 100644
index 0000000..a383774
--- /dev/null
+++ b/src/f2c/signal1.h
@@ -0,0 +1,35 @@
+/* You may need to adjust the definition of signal1 to supply a */
+/* cast to the correct argument type.  This detail is system- and */
+/* compiler-dependent.   The #define below assumes signal.h declares */
+/* type SIG_PF for the signal function's second argument. */
+
+/* For some C++ compilers, "#define Sigarg_t ..." may be appropriate. */
+
+#include <signal.h>
+
+#ifndef Sigret_t
+#define Sigret_t void
+#endif
+#ifndef Sigarg_t
+#ifdef KR_headers
+#define Sigarg_t
+#else
+#define Sigarg_t int
+#endif
+#endif /*Sigarg_t*/
+
+#ifdef USE_SIG_PF	/* compile with -DUSE_SIG_PF under IRIX */
+#define sig_pf SIG_PF
+#else
+typedef Sigret_t (*sig_pf)(Sigarg_t);
+#endif
+
+#define signal1(a,b) signal(a,(sig_pf)b)
+
+#ifdef __cplusplus
+#define Sigarg ...
+#define Use_Sigarg
+#else
+#define Sigarg Int n
+#define Use_Sigarg n = n	/* shut up compiler warning */
+#endif
diff --git a/src/f2c/signal1.h0 b/src/f2c/signal1.h0
new file mode 100644
index 0000000..a383774
--- /dev/null
+++ b/src/f2c/signal1.h0
@@ -0,0 +1,35 @@
+/* You may need to adjust the definition of signal1 to supply a */
+/* cast to the correct argument type.  This detail is system- and */
+/* compiler-dependent.   The #define below assumes signal.h declares */
+/* type SIG_PF for the signal function's second argument. */
+
+/* For some C++ compilers, "#define Sigarg_t ..." may be appropriate. */
+
+#include <signal.h>
+
+#ifndef Sigret_t
+#define Sigret_t void
+#endif
+#ifndef Sigarg_t
+#ifdef KR_headers
+#define Sigarg_t
+#else
+#define Sigarg_t int
+#endif
+#endif /*Sigarg_t*/
+
+#ifdef USE_SIG_PF	/* compile with -DUSE_SIG_PF under IRIX */
+#define sig_pf SIG_PF
+#else
+typedef Sigret_t (*sig_pf)(Sigarg_t);
+#endif
+
+#define signal1(a,b) signal(a,(sig_pf)b)
+
+#ifdef __cplusplus
+#define Sigarg ...
+#define Use_Sigarg
+#else
+#define Sigarg Int n
+#define Use_Sigarg n = n	/* shut up compiler warning */
+#endif
diff --git a/src/f2c/signal_.c b/src/f2c/signal_.c
new file mode 100644
index 0000000..3b0e6cf
--- /dev/null
+++ b/src/f2c/signal_.c
@@ -0,0 +1,21 @@
+#include "f2c.h"
+#include "signal1.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ ftnint
+#ifdef KR_headers
+signal_(sigp, proc) integer *sigp; sig_pf proc;
+#else
+signal_(integer *sigp, sig_pf proc)
+#endif
+{
+	int sig;
+	sig = (int)*sigp;
+
+	return (ftnint)signal(sig, proc);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/signbit.c b/src/f2c/signbit.c
new file mode 100644
index 0000000..de95a3b
--- /dev/null
+++ b/src/f2c/signbit.c
@@ -0,0 +1,24 @@
+#include "arith.h"
+
+#ifndef Long
+#define Long long
+#endif
+
+ int
+#ifdef KR_headers
+signbit_f2c(x) double *x;
+#else
+signbit_f2c(double *x)
+#endif
+{
+#ifdef IEEE_MC68k
+	if (*(Long*)x & 0x80000000)
+		return 1;
+#else
+#ifdef IEEE_8087
+	if (((Long*)x)[1] & 0x80000000)
+		return 1;
+#endif /*IEEE_8087*/
+#endif /*IEEE_MC68k*/
+	return 0;
+	}
diff --git a/src/f2c/sue.c b/src/f2c/sue.c
new file mode 100644
index 0000000..191e326
--- /dev/null
+++ b/src/f2c/sue.c
@@ -0,0 +1,90 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern uiolen f__reclen;
+OFF_T f__recloc;
+
+ int
+#ifdef KR_headers
+c_sue(a) cilist *a;
+#else
+c_sue(cilist *a)
+#endif
+{
+	f__external=f__sequential=1;
+	f__formatted=0;
+	f__curunit = &f__units[a->ciunit];
+	if(a->ciunit >= MXUNIT || a->ciunit < 0)
+		err(a->cierr,101,"startio");
+	f__elist=a;
+	if(f__curunit->ufd==NULL && fk_open(SEQ,UNF,a->ciunit))
+		err(a->cierr,114,"sue");
+	f__cf=f__curunit->ufd;
+	if(f__curunit->ufmt) err(a->cierr,103,"sue")
+	if(!f__curunit->useek) err(a->cierr,103,"sue")
+	return(0);
+}
+#ifdef KR_headers
+integer s_rsue(a) cilist *a;
+#else
+integer s_rsue(cilist *a)
+#endif
+{
+	int n;
+	if(!f__init) f_init();
+	f__reading=1;
+	if(n=c_sue(a)) return(n);
+	f__recpos=0;
+	if(f__curunit->uwrt && f__nowreading(f__curunit))
+		err(a->cierr, errno, "read start");
+	if(fread((char *)&f__reclen,sizeof(uiolen),1,f__cf)
+		!= 1)
+	{	if(feof(f__cf))
+		{	f__curunit->uend = 1;
+			err(a->ciend, EOF, "start");
+		}
+		clearerr(f__cf);
+		err(a->cierr, errno, "start");
+	}
+	return(0);
+}
+#ifdef KR_headers
+integer s_wsue(a) cilist *a;
+#else
+integer s_wsue(cilist *a)
+#endif
+{
+	int n;
+	if(!f__init) f_init();
+	if(n=c_sue(a)) return(n);
+	f__reading=0;
+	f__reclen=0;
+	if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit))
+		err(a->cierr, errno, "write start");
+	f__recloc=FTELL(f__cf);
+	FSEEK(f__cf,(OFF_T)sizeof(uiolen),SEEK_CUR);
+	return(0);
+}
+integer e_wsue(Void)
+{	OFF_T loc;
+	fwrite((char *)&f__reclen,sizeof(uiolen),1,f__cf);
+#ifdef ALWAYS_FLUSH
+	if (fflush(f__cf))
+		err(f__elist->cierr, errno, "write end");
+#endif
+	loc=FTELL(f__cf);
+	FSEEK(f__cf,f__recloc,SEEK_SET);
+	fwrite((char *)&f__reclen,sizeof(uiolen),1,f__cf);
+	FSEEK(f__cf,loc,SEEK_SET);
+	return(0);
+}
+integer e_rsue(Void)
+{
+	FSEEK(f__cf,(OFF_T)(f__reclen-f__recpos+sizeof(uiolen)),SEEK_CUR);
+	return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/sysdep1.h b/src/f2c/sysdep1.h
new file mode 100644
index 0000000..50e97e8
--- /dev/null
+++ b/src/f2c/sysdep1.h
@@ -0,0 +1,71 @@
+#ifndef SYSDEP_H_INCLUDED
+#define SYSDEP_H_INCLUDED
+
+#ifdef _MSC_VER
+#define FTRUNCATE chsize
+#endif
+
+#undef USE_LARGEFILE
+#ifndef NO_LONG_LONG
+
+#ifdef __sun__
+#define USE_LARGEFILE
+#define OFF_T off64_t
+#endif
+
+#ifdef __linux__
+#define USE_LARGEFILE
+#define OFF_T __off64_t
+#endif
+
+#ifdef _AIX43
+#define _LARGE_FILES
+#define _LARGE_FILE_API
+#define USE_LARGEFILE
+#endif /*_AIX43*/
+
+#ifdef __hpux
+#define _FILE64
+#define _LARGEFILE64_SOURCE
+#define USE_LARGEFILE
+#endif /*__hpux*/
+
+#ifdef __sgi
+#define USE_LARGEFILE
+#endif /*__sgi*/
+
+#ifdef __FreeBSD__
+#define OFF_T off_t
+#define FSEEK fseeko
+#define FTELL ftello
+#endif
+
+#ifdef USE_LARGEFILE
+#ifndef OFF_T
+#define OFF_T off64_t
+#endif
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#define FOPEN fopen64
+#define FREOPEN freopen64
+#define FSEEK fseeko64
+#define FSTAT fstat64
+#define FTELL ftello64
+#define FTRUNCATE ftruncate64
+#define STAT stat64
+#define STAT_ST stat64
+#endif /*USE_LARGEFILE*/
+#endif /*NO_LONG_LONG*/
+
+#ifndef NON_UNIX_STDIO
+#ifndef USE_LARGEFILE
+#define _INCLUDE_POSIX_SOURCE	/* for HP-UX */
+#define _INCLUDE_XOPEN_SOURCE	/* for HP-UX */
+#include "sys/types.h"
+#include "sys/stat.h"
+#endif
+#endif
+
+#endif /*SYSDEP_H_INCLUDED*/
diff --git a/src/f2c/sysdep1.h0 b/src/f2c/sysdep1.h0
new file mode 100644
index 0000000..50e97e8
--- /dev/null
+++ b/src/f2c/sysdep1.h0
@@ -0,0 +1,71 @@
+#ifndef SYSDEP_H_INCLUDED
+#define SYSDEP_H_INCLUDED
+
+#ifdef _MSC_VER
+#define FTRUNCATE chsize
+#endif
+
+#undef USE_LARGEFILE
+#ifndef NO_LONG_LONG
+
+#ifdef __sun__
+#define USE_LARGEFILE
+#define OFF_T off64_t
+#endif
+
+#ifdef __linux__
+#define USE_LARGEFILE
+#define OFF_T __off64_t
+#endif
+
+#ifdef _AIX43
+#define _LARGE_FILES
+#define _LARGE_FILE_API
+#define USE_LARGEFILE
+#endif /*_AIX43*/
+
+#ifdef __hpux
+#define _FILE64
+#define _LARGEFILE64_SOURCE
+#define USE_LARGEFILE
+#endif /*__hpux*/
+
+#ifdef __sgi
+#define USE_LARGEFILE
+#endif /*__sgi*/
+
+#ifdef __FreeBSD__
+#define OFF_T off_t
+#define FSEEK fseeko
+#define FTELL ftello
+#endif
+
+#ifdef USE_LARGEFILE
+#ifndef OFF_T
+#define OFF_T off64_t
+#endif
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#define FOPEN fopen64
+#define FREOPEN freopen64
+#define FSEEK fseeko64
+#define FSTAT fstat64
+#define FTELL ftello64
+#define FTRUNCATE ftruncate64
+#define STAT stat64
+#define STAT_ST stat64
+#endif /*USE_LARGEFILE*/
+#endif /*NO_LONG_LONG*/
+
+#ifndef NON_UNIX_STDIO
+#ifndef USE_LARGEFILE
+#define _INCLUDE_POSIX_SOURCE	/* for HP-UX */
+#define _INCLUDE_XOPEN_SOURCE	/* for HP-UX */
+#include "sys/types.h"
+#include "sys/stat.h"
+#endif
+#endif
+
+#endif /*SYSDEP_H_INCLUDED*/
diff --git a/src/f2c/system_.c b/src/f2c/system_.c
new file mode 100644
index 0000000..b18e8a6
--- /dev/null
+++ b/src/f2c/system_.c
@@ -0,0 +1,42 @@
+/* f77 interface to system routine */
+
+#include "f2c.h"
+
+#ifdef KR_headers
+extern char *F77_aloc();
+
+ integer
+system_(s, n) register char *s; ftnlen n;
+#else
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern char *F77_aloc(ftnlen, const char*);
+
+ integer
+system_(register char *s, ftnlen n)
+#endif
+{
+	char buff0[256], *buff;
+	register char *bp, *blast;
+	integer rv;
+
+	buff = bp = n < sizeof(buff0)
+			? buff0 : F77_aloc(n+1, "system_");
+	blast = bp + n;
+
+	while(bp < blast && *s)
+		*bp++ = *s++;
+	*bp = 0;
+	rv = system(buff);
+	if (buff != buff0)
+		free(buff);
+	return rv;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/typesize.c b/src/f2c/typesize.c
new file mode 100644
index 0000000..4128eef
--- /dev/null
+++ b/src/f2c/typesize.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ftnlen f__typesize[] = { 0, 0, sizeof(shortint), sizeof(integer),
+			sizeof(real), sizeof(doublereal),
+			sizeof(f2c_complex), sizeof(doublecomplex),
+			sizeof(logical), sizeof(char),
+			0, sizeof(integer1),
+			sizeof(logical1), sizeof(shortlogical),
+#ifdef Allow_TYQUAD
+			sizeof(longint),
+#endif
+			0};
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/uio.c b/src/f2c/uio.c
new file mode 100644
index 0000000..44f768d
--- /dev/null
+++ b/src/f2c/uio.c
@@ -0,0 +1,75 @@
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+uiolen f__reclen;
+
+ int
+#ifdef KR_headers
+do_us(number,ptr,len) ftnint *number; char *ptr; ftnlen len;
+#else
+do_us(ftnint *number, char *ptr, ftnlen len)
+#endif
+{
+	if(f__reading)
+	{
+		f__recpos += (int)(*number * len);
+		if(f__recpos>f__reclen)
+			err(f__elist->cierr, 110, "do_us");
+		if (fread(ptr,(int)len,(int)(*number),f__cf) != *number)
+			err(f__elist->ciend, EOF, "do_us");
+		return(0);
+	}
+	else
+	{
+		f__reclen += *number * len;
+		(void) fwrite(ptr,(int)len,(int)(*number),f__cf);
+		return(0);
+	}
+}
+#ifdef KR_headers
+integer do_ud(number,ptr,len) ftnint *number; char *ptr; ftnlen len;
+#else
+integer do_ud(ftnint *number, char *ptr, ftnlen len)
+#endif
+{
+	f__recpos += (int)(*number * len);
+	if(f__recpos > f__curunit->url && f__curunit->url!=1)
+		err(f__elist->cierr,110,"do_ud");
+	if(f__reading)
+	{
+#ifdef Pad_UDread
+#ifdef KR_headers
+	int i;
+#else
+	size_t i;
+#endif
+		if (!(i = fread(ptr,(int)len,(int)(*number),f__cf))
+		 && !(f__recpos - *number*len))
+			err(f__elist->cierr,EOF,"do_ud")
+		if (i < *number)
+			memset(ptr + i*len, 0, (*number - i)*len);
+		return 0;
+#else
+		if(fread(ptr,(int)len,(int)(*number),f__cf) != *number)
+			err(f__elist->cierr,EOF,"do_ud")
+		else return(0);
+#endif
+	}
+	(void) fwrite(ptr,(int)len,(int)(*number),f__cf);
+	return(0);
+}
+#ifdef KR_headers
+integer do_uio(number,ptr,len) ftnint *number; char *ptr; ftnlen len;
+#else
+integer do_uio(ftnint *number, char *ptr, ftnlen len)
+#endif
+{
+	if(f__sequential)
+		return(do_us(number,ptr,len));
+	else	return(do_ud(number,ptr,len));
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/uninit.c b/src/f2c/uninit.c
new file mode 100644
index 0000000..93c8be5
--- /dev/null
+++ b/src/f2c/uninit.c
@@ -0,0 +1,463 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "arith.h"
+
+#define TYSHORT 2
+#define TYLONG 3
+#define TYREAL 4
+#define TYDREAL 5
+#define TYCOMPLEX 6
+#define TYDCOMPLEX 7
+#define TYINT1 11
+#define TYQUAD 14
+#ifndef Long
+#define Long long
+#endif
+
+#ifdef __mips
+#define RNAN	0xffc00000 /* Quiet NaN */
+#define DNAN0	0xfff80000 /* Signalling NaN double Big endian */
+#define DNAN1	0
+#endif
+
+#ifdef _PA_RISC1_1
+#define RNAN	0xffc00000 /* Quiet Nan -- big endian */
+#define DNAN0	0xfff80000
+#define DNAN1	0
+#endif
+
+#ifndef RNAN
+#define RNAN	0xff800001
+#ifdef IEEE_MC68k /* set on PPC*/
+#define DNAN0	0xfff00000 /* Quiet NaN big endian */
+#define DNAN1	1
+#else
+#define DNAN0	1   /* LSB, MSB for little endian machines */
+#define DNAN1	0xfff00000
+#endif
+#endif /*RNAN*/
+
+#ifdef KR_headers
+#define Void /*void*/
+#define FA7UL (unsigned Long) 0xfa7a7a7aL
+#else
+#define Void void
+#define FA7UL 0xfa7a7a7aUL
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static void ieee0(Void);
+
+static unsigned Long rnan = RNAN,
+	dnan0 = DNAN0,
+	dnan1 = DNAN1;
+
+double _0 = 0.;
+
+void unsupported_error()
+{
+  fprintf(stderr,"Runtime Error: Your Architecture is not supported by the"
+                       " -trapuv option of f2c\n");
+  exit(-1);
+}
+
+
+
+ void
+#ifdef KR_headers
+_uninit_f2c(x, type, len) void *x; int type; long len;
+#else
+_uninit_f2c(void *x, int type, long len)
+#endif
+{
+	static int first = 1;
+
+	unsigned Long *lx, *lxe;
+
+	if (first) {
+		first = 0;
+		ieee0();
+		}
+	if (len == 1)
+	 switch(type) {
+	  case TYINT1:
+		*(char*)x = 'Z';
+		return;
+	  case TYSHORT:
+		*(short*)x = 0xfa7a;
+		break;
+	  case TYLONG:
+		*(unsigned Long*)x = FA7UL;
+		return;
+	  case TYQUAD:
+	  case TYCOMPLEX:
+	  case TYDCOMPLEX:
+		break;
+	  case TYREAL:
+		*(unsigned Long*)x = rnan;
+		return;
+	  case TYDREAL:
+		lx = (unsigned Long*)x;
+		lx[0] = dnan0;
+		lx[1] = dnan1;
+		return;
+	  default:
+		printf("Surprise type %d in _uninit_f2c\n", type);
+	  }
+	switch(type) {
+	  case TYINT1:
+		memset(x, 'Z', len);
+		break;
+	  case TYSHORT:
+		*(short*)x = 0xfa7a;
+		break;
+	  case TYQUAD:
+		len *= 2;
+		/* no break */
+	  case TYLONG:
+		lx = (unsigned Long*)x;
+		lxe = lx + len;
+		while(lx < lxe)
+			*lx++ = FA7UL;
+		break;
+	  case TYCOMPLEX:
+		len *= 2;
+		/* no break */
+	  case TYREAL:
+		lx = (unsigned Long*)x;
+		lxe = lx + len;
+		while(lx < lxe)
+			*lx++ = rnan;
+		break;
+	  case TYDCOMPLEX:
+		len *= 2;
+		/* no break */
+	  case TYDREAL:
+		lx = (unsigned Long*)x;
+		for(lxe = lx + 2*len; lx < lxe; lx += 2) {
+			lx[0] = dnan0;
+			lx[1] = dnan1;
+			}
+	  }
+	}
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef MSpc
+#ifdef MSDOS
+#define MSpc
+#else
+#ifdef _WIN32
+#define MSpc
+#endif
+#endif
+#endif
+
+#ifdef MSpc
+#define IEEE0_done
+#include "float.h"
+#include "signal.h"
+
+ static void
+ieee0(Void)
+{
+#ifndef __alpha
+#ifndef EM_DENORMAL
+#define EM_DENORMAL _EM_DENORMAL
+#endif
+#ifndef EM_UNDERFLOW
+#define EM_UNDERFLOW _EM_UNDERFLOW
+#endif
+#ifndef EM_INEXACT
+#define EM_INEXACT _EM_INEXACT
+#endif
+#ifndef MCW_EM
+#define MCW_EM _MCW_EM
+#endif
+	_control87(EM_DENORMAL | EM_UNDERFLOW | EM_INEXACT, MCW_EM);
+#endif
+	/* With MS VC++, compiling and linking with -Zi will permit */
+	/* clicking to invoke the MS C++ debugger, which will show */
+	/* the point of error -- provided SIGFPE is SIG_DFL. */
+	signal(SIGFPE, SIG_DFL);
+	}
+#endif /* MSpc */
+
+/* What follows is for SGI IRIX only */
+#if defined(__mips) && defined(__sgi)   /* must link with -lfpe */
+#define IEEE0_done
+/* code from Eric Grosse */
+#include <stdlib.h>
+#include <stdio.h>
+#include "/usr/include/sigfpe.h"	/* full pathname for lcc -N */
+#include "/usr/include/sys/fpu.h"
+
+ static void
+#ifdef KR_headers
+ieeeuserhand(exception, val) unsigned exception[5]; int val[2];
+#else
+ieeeuserhand(unsigned exception[5], int val[2])
+#endif
+{
+	fflush(stdout);
+	fprintf(stderr,"ieee0() aborting because of ");
+	if(exception[0]==_OVERFL) fprintf(stderr,"overflow\n");
+	else if(exception[0]==_UNDERFL) fprintf(stderr,"underflow\n");
+	else if(exception[0]==_DIVZERO) fprintf(stderr,"divide by 0\n");
+	else if(exception[0]==_INVALID) fprintf(stderr,"invalid operation\n");
+	else fprintf(stderr,"\tunknown reason\n");
+	fflush(stderr);
+	abort();
+}
+
+ static void
+#ifdef KR_headers
+ieeeuserhand2(j) unsigned int **j;
+#else
+ieeeuserhand2(unsigned int **j)
+#endif
+{
+	fprintf(stderr,"ieee0() aborting because of confusion\n");
+	abort();
+}
+
+ static void
+ieee0(Void)
+{
+	int i;
+	for(i=1; i<=4; i++){
+		sigfpe_[i].count = 1000;
+		sigfpe_[i].trace = 1;
+		sigfpe_[i].repls = _USER_DETERMINED;
+		}
+	sigfpe_[1].repls = _ZERO;	/* underflow */
+	handle_sigfpes( _ON,
+		_EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,
+		ieeeuserhand,_ABORT_ON_ERROR,ieeeuserhand2);
+	}
+#endif /* IRIX mips */
+
+/*
+ * The following is the preferred method but depends upon a GLIBC extension only
+ * to be found in GLIBC 2.2 or later.  It is a GNU extension, not included in the
+ * C99 extensions which allow the FP status register to be examined in a platform
+ * independent way.  It should be used if at all possible  -- AFRB
+ */
+
+
+#if (defined(__GLIBC__)&& ( __GLIBC__>=2) && (__GLIBC_MINOR__>=2) )
+#define _GNU_SOURCE 1
+#define IEEE0_done
+#include <fenv.h>
+ static void
+  ieee0(Void)
+        
+{
+    /* Clear all exception flags */
+    if (fedisableexcept(FE_ALL_EXCEPT)==-1)
+         unsupported_error();
+    if (feenableexcept(FE_DIVBYZERO|FE_INVALID|FE_OVERFLOW)==-1)
+         unsupported_error();
+}
+
+#endif /* Glibc control */
+
+/* Many linux cases will be treated through GLIBC.  Note that modern
+ * linux runs on many non-i86 plaforms and as a result the following code
+ * must be processor dependent rather than simply OS specific */
+
+#if (defined(__linux__)&&(!defined(IEEE0_done)))
+#define IEEE0_done
+#include <fpu_control.h>
+
+
+#ifdef __alpha__
+#ifndef USE_setfpucw
+#define __setfpucw(x) __fpu_control = (x)
+#endif
+#endif
+
+/* Not all versions of libc define _FPU_SETCW;
+ *  * some only provide the __setfpucw() function.
+ *   */
+#ifndef _FPU_SETCW
+#define _FPU_SETCW(cw) __setfpucw(cw)
+#endif
+
+/* The exact set of flags we want to set in the FPU control word
+ * depends on the architecture.
+ * Note also that whether an exception is enabled or disabled when
+ * the _FPU_MASK_nn bit is set is architecture dependent!
+ * Enabled-when-set: M68k, ARM, MIPS, PowerPC
+ * Disabled-when-set: x86, Alpha
+ * The state we are after is:
+ * exceptions on division by zero, overflow and invalid operation.
+ */
+
+
+#ifdef __alpha__
+#ifndef USE_setfpucw
+#define __setfpucw(x) __fpu_control = (x)
+#endif
+#endif
+
+
+#ifndef _FPU_SETCW
+#undef  Can_use__setfpucw
+#define Can_use__setfpucw
+#endif
+
+#undef RQD_FPU_MASK
+#undef RQD_FPU_CLEAR_MASK
+
+#if (defined(__mc68000__) || defined(__mc68020__) || defined(mc68020) || defined (__mc68k__))
+/* Reported 20010705 by Alan Bain <alanb at chiark.greenend.org.uk> */
+/* Note that IEEE 754 IOP (illegal operation) */
+/* = Signaling NAN (SNAN) + operation error (OPERR). */
+#define RQD_FPU_STATE (_FPU_IEEE + _FPU_DOUBLE + _FPU_MASK_OPERR + \
+                 _FPU_MASK_DZ + _FPU_MASK_SNAN+_FPU_MASK_OVFL)
+#define RQD_FPU_MASK (_FPU_MASK_OPERR+_FPU_MASK_DZ+_FPU_MASK_SNAN+_FPU_MASK_OVFL)
+
+#elif (defined(__powerpc__)||defined(_ARCH_PPC)||defined(_ARCH_PWR)) /* !__mc68k__ */
+    /* The following is NOT a mistake -- the author of the fpu_control.h
+     * for the PPC has erroneously defined IEEE mode to turn on exceptions
+     * other than Inexact! Start from default then and turn on only the ones
+     * which we want*/
+
+    /* I have changed _FPU_MASK_UM here to _FPU_MASK_ZM, because that is
+     * in line with all the other architectures specified here. -- AFRB
+     */
+#define RQD_FPU_STATE (_FPU_DEFAULT +_FPU_MASK_OM+_FPU_MASK_IM+_FPU_MASK_ZM)
+#define RQD_FPU_MASK (_FPU_MASK_OM+_FPU_MASK_IM+_FPU_MASK_ZM)
+
+#elif (defined(__arm__))
+    /* On ARM too, IEEE implies all exceptions enabled.
+     * -- Peter Maydell <pmaydell at chiark.greenend.org.uk>
+     * Unfortunately some version of ARMlinux don't include any
+     * flags in the fpu_control.h file
+     */
+#define RQD_FPU_STATE (_FPU_DEFAULT +_FPU_MASK_OM+_FPU_MASK_IM+_FPU_MASK_ZM)
+#define RQD_FPU_MASK (_FPU_MASK_OM+_FPU_MASK_IM+_FPU_MASK_ZM)
+
+#elif (defined(__mips__))
+    /* And same again for MIPS; _FPU_IEEE => exceptions seems a common meme.
+     *  * MIPS uses different MASK constant names, no idea why -- PMM
+     *   */
+#define RQD_FPU_STATE (_FPU_DEFAULT +_FPU_MASK_O+_FPU_MASK_V+_FPU_MASK_Z)
+#define RQD_FPU_MASK (_FPU_MASK_O+_FPU_MASK_V+_FPU_MASK_Z)
+
+#elif (defined(__sparc__))
+#define RQD_FPU_STATE (_FPU_DEFAULT +_FPU_DOUBLE+_FPU_MASK_OM+_FPU_MASK_IM+_FPU_MASK_ZM)
+#define RQD_FPU_MASK (_FPU_MASK_OM+_FPU_MASK_IM+_FPU_MASK_ZM)
+
+#elif (defined(__i386__) || defined(__alpha__))
+    /* This case is for Intel, and also Alpha, because the Alpha header 
+     * purposely emulates x86 flags and meanings for compatibility with
+     * stupid programs.
+     * We used to try this case for anything defining _FPU_IEEE, but I think
+     * that that's a bad idea because it isn't really likely to work.
+     * Instead for unknown architectures we just won't allow -trapuv to work.
+     * Trying this case was just getting us 
+     *  (a) compile errors on archs which didn't know all these constants
+     *  (b) silent wrong behaviour on archs (like SPARC) which do know all
+     *      constants but have different semantics for them
+     */
+#define RQD_FPU_STATE (_FPU_IEEE - _FPU_EXTENDED + _FPU_DOUBLE - _FPU_MASK_IM - _FPU_MASK_ZM - _FPU_MASK_OM)
+#define RQD_FPU_CLEAR_MASK (_FPU_MASK_IM + _FPU_MASK_ZM + _FPU_MASK_OM)
+#endif
+
+static void ieee0(Void)
+{
+#ifdef RQD_FPU_STATE
+        
+#ifndef UNINIT_F2C_PRECISION_53 /* 20051004 */
+        __fpu_control = RQD_FPU_STATE;
+        _FPU_SETCW(__fpu_control);
+#else 
+	/* unmask invalid, etc., and keep current rounding precision */
+	fpu_control_t cw;
+	_FPU_GETCW(cw);
+#ifdef RQD_FPU_CLEAR_MASK
+	cw &= ~ RQD_FPU_CLEAR_MASK;
+#else
+        cw |= RQD_FPU_MASK;
+#endif
+	_FPU_SETCW(cw);
+#endif
+
+#else /* !_FPU_IEEE */
+
+	fprintf(stderr, "\n%s\n%s\n%s\n%s\n",
+		"WARNING:  _uninit_f2c in libf2c does not know how",
+		"to enable trapping on this system, so f2c's -trapuv",
+		"option will not detect uninitialized variables unless",
+		"you can enable trapping manually.");
+	fflush(stderr);
+
+#endif /* _FPU_IEEE */
+	}
+#endif /* __linux__ */
+
+/* Specific to OSF/1 */
+#if (defined(__alpha)&&defined(__osf__))
+#ifndef IEEE0_done
+#define IEEE0_done
+#include <machine/fpu.h>
+ static void
+ieee0(Void)
+{
+	ieee_set_fp_control(IEEE_TRAP_ENABLE_INV);
+	}
+#endif /*IEEE0_done*/
+#endif /*__alpha OSF/1*/
+
+#ifdef __hpux
+#define IEEE0_done
+#define _INCLUDE_HPUX_SOURCE
+#include <math.h>
+
+#ifndef FP_X_INV
+#include <fenv.h>
+#define fpsetmask fesettrapenable
+#define FP_X_INV FE_INVALID
+#endif
+
+ static void
+ieee0(Void)
+{
+	fpsetmask(FP_X_INV);
+	}
+#endif /*__hpux*/
+
+#ifdef _AIX
+#define IEEE0_done
+#include <fptrap.h>
+
+ static void
+ieee0(Void)
+{
+	fp_enable(TRP_INVALID);
+	fp_trap(FP_TRAP_SYNC);
+	}
+#endif /*_AIX*/
+
+#ifdef __sun
+#define IEEE0_done
+#include <ieeefp.h>
+
+ static void
+ieee0(Void)
+{
+	fpsetmask(FP_X_INV);
+	}
+#endif /*__sparc*/
+
+#ifndef IEEE0_done
+ static void
+ieee0(Void) {}
+#endif
diff --git a/src/f2c/util.c b/src/f2c/util.c
new file mode 100644
index 0000000..ad4bec5
--- /dev/null
+++ b/src/f2c/util.c
@@ -0,0 +1,57 @@
+#include "sysdep1.h"	/* here to get stat64 on some badly designed Linux systems */
+#include "f2c.h"
+#include "fio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ VOID
+#ifdef KR_headers
+#define Const /*nothing*/
+g_char(a,alen,b) char *a,*b; ftnlen alen;
+#else
+#define Const const
+g_char(const char *a, ftnlen alen, char *b)
+#endif
+{
+	Const char *x = a + alen;
+	char *y = b + alen;
+
+	for(;; y--) {
+		if (x <= a) {
+			*b = 0;
+			return;
+			}
+		if (*--x != ' ')
+			break;
+		}
+	*y-- = 0;
+	do *y-- = *x;
+		while(x-- > a);
+	}
+
+ VOID
+#ifdef KR_headers
+b_char(a,b,blen) char *a,*b; ftnlen blen;
+#else
+b_char(const char *a, char *b, ftnlen blen)
+#endif
+{	int i;
+	for(i=0;i<blen && *a!=0;i++) *b++= *a++;
+	for(;i<blen;i++) *b++=' ';
+}
+#ifndef NON_UNIX_STDIO
+#ifdef KR_headers
+long f__inode(a, dev) char *a; int *dev;
+#else
+long f__inode(char *a, int *dev)
+#endif
+{	struct STAT_ST x;
+	if(STAT(a,&x)<0) return(-1);
+	*dev = x.st_dev;
+	return(x.st_ino);
+}
+#endif
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/wref.c b/src/f2c/wref.c
new file mode 100644
index 0000000..f2074b7
--- /dev/null
+++ b/src/f2c/wref.c
@@ -0,0 +1,294 @@
+#include "f2c.h"
+#include "fio.h"
+
+#ifndef KR_headers
+#undef abs
+#undef min
+#undef max
+#include "stdlib.h"
+#include "string.h"
+#endif
+
+#include "fmt.h"
+#include "fp.h"
+#ifndef VAX
+#include "ctype.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+ int
+#ifdef KR_headers
+wrt_E(p,w,d,e,len) ufloat *p; ftnlen len;
+#else
+wrt_E(ufloat *p, int w, int d, int e, ftnlen len)
+#endif
+{
+	char buf[FMAX+EXPMAXDIGS+4], *s, *se;
+	int d1, delta, e1, i, sign, signspace;
+	double dd;
+#ifdef WANT_LEAD_0
+	int insert0 = 0;
+#endif
+#ifndef VAX
+	int e0 = e;
+#endif
+
+	if(e <= 0)
+		e = 2;
+	if(f__scale) {
+		if(f__scale >= d + 2 || f__scale <= -d)
+			goto nogood;
+		}
+	if(f__scale <= 0)
+		--d;
+	if (len == sizeof(real))
+		dd = p->pf;
+	else
+		dd = p->pd;
+	if (dd < 0.) {
+		signspace = sign = 1;
+		dd = -dd;
+		}
+	else {
+		sign = 0;
+		signspace = (int)f__cplus;
+#ifndef VAX
+		if (!dd) {
+#ifdef SIGNED_ZEROS
+			if (signbit_f2c(&dd))
+				signspace = sign = 1;
+#endif
+			dd = 0.;	/* avoid -0 */
+			}
+#endif
+		}
+	delta = w - (2 /* for the . and the d adjustment above */
+			+ 2 /* for the E+ */ + signspace + d + e);
+#ifdef WANT_LEAD_0
+	if (f__scale <= 0 && delta > 0) {
+		delta--;
+		insert0 = 1;
+		}
+	else
+#endif
+	if (delta < 0) {
+nogood:
+		while(--w >= 0)
+			PUT('*');
+		return(0);
+		}
+	if (f__scale < 0)
+		d += f__scale;
+	if (d > FMAX) {
+		d1 = d - FMAX;
+		d = FMAX;
+		}
+	else
+		d1 = 0;
+	sprintf(buf,"%#.*E", d, dd);
+#ifndef VAX
+	/* check for NaN, Infinity */
+	if (!isdigit(buf[0])) {
+		switch(buf[0]) {
+			case 'n':
+			case 'N':
+				signspace = 0;	/* no sign for NaNs */
+			}
+		delta = w - strlen(buf) - signspace;
+		if (delta < 0)
+			goto nogood;
+		while(--delta >= 0)
+			PUT(' ');
+		if (signspace)
+			PUT(sign ? '-' : '+');
+		for(s = buf; *s; s++)
+			PUT(*s);
+		return 0;
+		}
+#endif
+	se = buf + d + 3;
+#ifdef GOOD_SPRINTF_EXPONENT /* When possible, exponent has 2 digits. */
+	if (f__scale != 1 && dd)
+		sprintf(se, "%+.2d", atoi(se) + 1 - f__scale);
+#else
+	if (dd)
+		sprintf(se, "%+.2d", atoi(se) + 1 - f__scale);
+	else
+		strcpy(se, "+00");
+#endif
+	s = ++se;
+	if (e < 2) {
+		if (*s != '0')
+			goto nogood;
+		}
+#ifndef VAX
+	/* accommodate 3 significant digits in exponent */
+	if (s[2]) {
+#ifdef Pedantic
+		if (!e0 && !s[3])
+			for(s -= 2, e1 = 2; s[0] = s[1]; s++);
+
+	/* Pedantic gives the behavior that Fortran 77 specifies,	*/
+	/* i.e., requires that E be specified for exponent fields	*/
+	/* of more than 3 digits.  With Pedantic undefined, we get	*/
+	/* the behavior that Cray displays -- you get a bigger		*/
+	/* exponent field if it fits.	*/
+#else
+		if (!e0) {
+			for(s -= 2, e1 = 2; s[0] = s[1]; s++)
+#ifdef CRAY
+				delta--;
+			if ((delta += 4) < 0)
+				goto nogood
+#endif
+				;
+			}
+#endif
+		else if (e0 >= 0)
+			goto shift;
+		else
+			e1 = e;
+		}
+	else
+ shift:
+#endif
+		for(s += 2, e1 = 2; *s; ++e1, ++s)
+			if (e1 >= e)
+				goto nogood;
+	while(--delta >= 0)
+		PUT(' ');
+	if (signspace)
+		PUT(sign ? '-' : '+');
+	s = buf;
+	i = f__scale;
+	if (f__scale <= 0) {
+#ifdef WANT_LEAD_0
+		if (insert0)
+			PUT('0');
+#endif
+		PUT('.');
+		for(; i < 0; ++i)
+			PUT('0');
+		PUT(*s);
+		s += 2;
+		}
+	else if (f__scale > 1) {
+		PUT(*s);
+		s += 2;
+		while(--i > 0)
+			PUT(*s++);
+		PUT('.');
+		}
+	if (d1) {
+		se -= 2;
+		while(s < se) PUT(*s++);
+		se += 2;
+		do PUT('0'); while(--d1 > 0);
+		}
+	while(s < se)
+		PUT(*s++);
+	if (e < 2)
+		PUT(s[1]);
+	else {
+		while(++e1 <= e)
+			PUT('0');
+		while(*s)
+			PUT(*s++);
+		}
+	return 0;
+	}
+
+ int
+#ifdef KR_headers
+wrt_F(p,w,d,len) ufloat *p; ftnlen len;
+#else
+wrt_F(ufloat *p, int w, int d, ftnlen len)
+#endif
+{
+	int d1, sign, n;
+	double x;
+	char *b, buf[MAXINTDIGS+MAXFRACDIGS+4], *s;
+
+	x= (len==sizeof(real)?p->pf:p->pd);
+	if (d < MAXFRACDIGS)
+		d1 = 0;
+	else {
+		d1 = d - MAXFRACDIGS;
+		d = MAXFRACDIGS;
+		}
+	if (x < 0.)
+		{ x = -x; sign = 1; }
+	else {
+		sign = 0;
+#ifndef VAX
+		if (!x) {
+#ifdef SIGNED_ZEROS
+			if (signbit_f2c(&x))
+				sign = 2;
+#endif
+			x = 0.;
+			}
+#endif
+		}
+
+	if (n = f__scale)
+		if (n > 0)
+			do x *= 10.; while(--n > 0);
+		else
+			do x *= 0.1; while(++n < 0);
+
+#ifdef USE_STRLEN
+	sprintf(b = buf, "%#.*f", d, x);
+	n = strlen(b) + d1;
+#else
+	n = sprintf(b = buf, "%#.*f", d, x) + d1;
+#endif
+
+#ifndef WANT_LEAD_0
+	if (buf[0] == '0' && d)
+		{ ++b; --n; }
+#endif
+	if (sign == 1) {
+		/* check for all zeros */
+		for(s = b;;) {
+			while(*s == '0') s++;
+			switch(*s) {
+				case '.':
+					s++; continue;
+				case 0:
+					sign = 0;
+				}
+			break;
+			}
+		}
+	if (sign || f__cplus)
+		++n;
+	if (n > w) {
+#ifdef WANT_LEAD_0
+		if (buf[0] == '0' && --n == w)
+			++b;
+		else
+#endif
+		{
+			while(--w >= 0)
+				PUT('*');
+			return 0;
+			}
+		}
+	for(w -= n; --w >= 0; )
+		PUT(' ');
+	if (sign)
+		PUT('-');
+	else if (f__cplus)
+		PUT('+');
+	while(n = *b++)
+		PUT(n);
+	while(--d1 >= 0)
+		PUT('0');
+	return 0;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/wrtfmt.c b/src/f2c/wrtfmt.c
new file mode 100644
index 0000000..a970db9
--- /dev/null
+++ b/src/f2c/wrtfmt.c
@@ -0,0 +1,377 @@
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern icilist *f__svic;
+extern char *f__icptr;
+
+ static int
+mv_cur(Void)	/* shouldn't use fseek because it insists on calling fflush */
+		/* instead we know too much about stdio */
+{
+	int cursor = f__cursor;
+	f__cursor = 0;
+	if(f__external == 0) {
+		if(cursor < 0) {
+			if(f__hiwater < f__recpos)
+				f__hiwater = f__recpos;
+			f__recpos += cursor;
+			f__icptr += cursor;
+			if(f__recpos < 0)
+				err(f__elist->cierr, 110, "left off");
+		}
+		else if(cursor > 0) {
+			if(f__recpos + cursor >= f__svic->icirlen)
+				err(f__elist->cierr, 110, "recend");
+			if(f__hiwater <= f__recpos)
+				for(; cursor > 0; cursor--)
+					(*f__putn)(' ');
+			else if(f__hiwater <= f__recpos + cursor) {
+				cursor -= f__hiwater - f__recpos;
+				f__icptr += f__hiwater - f__recpos;
+				f__recpos = f__hiwater;
+				for(; cursor > 0; cursor--)
+					(*f__putn)(' ');
+			}
+			else {
+				f__icptr += cursor;
+				f__recpos += cursor;
+			}
+		}
+		return(0);
+	}
+	if (cursor > 0) {
+		if(f__hiwater <= f__recpos)
+			for(;cursor>0;cursor--) (*f__putn)(' ');
+		else if(f__hiwater <= f__recpos + cursor) {
+			cursor -= f__hiwater - f__recpos;
+			f__recpos = f__hiwater;
+			for(; cursor > 0; cursor--)
+				(*f__putn)(' ');
+		}
+		else {
+			f__recpos += cursor;
+		}
+	}
+	else if (cursor < 0)
+	{
+		if(cursor + f__recpos < 0)
+			err(f__elist->cierr,110,"left off");
+		if(f__hiwater < f__recpos)
+			f__hiwater = f__recpos;
+		f__recpos += cursor;
+	}
+	return(0);
+}
+
+ static int
+#ifdef KR_headers
+wrt_Z(n,w,minlen,len) Uint *n; int w, minlen; ftnlen len;
+#else
+wrt_Z(Uint *n, int w, int minlen, ftnlen len)
+#endif
+{
+	register char *s, *se;
+	register int i, w1;
+	static int one = 1;
+	static char hex[] = "0123456789ABCDEF";
+	s = (char *)n;
+	--len;
+	if (*(char *)&one) {
+		/* little endian */
+		se = s;
+		s += len;
+		i = -1;
+		}
+	else {
+		se = s + len;
+		i = 1;
+		}
+	for(;; s += i)
+		if (s == se || *s)
+			break;
+	w1 = (i*(se-s) << 1) + 1;
+	if (*s & 0xf0)
+		w1++;
+	if (w1 > w)
+		for(i = 0; i < w; i++)
+			(*f__putn)('*');
+	else {
+		if ((minlen -= w1) > 0)
+			w1 += minlen;
+		while(--w >= w1)
+			(*f__putn)(' ');
+		while(--minlen >= 0)
+			(*f__putn)('0');
+		if (!(*s & 0xf0)) {
+			(*f__putn)(hex[*s & 0xf]);
+			if (s == se)
+				return 0;
+			s += i;
+			}
+		for(;; s += i) {
+			(*f__putn)(hex[*s >> 4 & 0xf]);
+			(*f__putn)(hex[*s & 0xf]);
+			if (s == se)
+				break;
+			}
+		}
+	return 0;
+	}
+
+ static int
+#ifdef KR_headers
+wrt_I(n,w,len, base) Uint *n; ftnlen len; register int base;
+#else
+wrt_I(Uint *n, int w, ftnlen len, register int base)
+#endif
+{	int ndigit,sign,spare,i;
+	longint x;
+	char *ans;
+	if(len==sizeof(integer)) x=n->il;
+	else if(len == sizeof(char)) x = n->ic;
+#ifdef Allow_TYQUAD
+	else if (len == sizeof(longint)) x = n->ili;
+#endif
+	else x=n->is;
+	ans=f__icvt(x,&ndigit,&sign, base);
+	spare=w-ndigit;
+	if(sign || f__cplus) spare--;
+	if(spare<0)
+		for(i=0;i<w;i++) (*f__putn)('*');
+	else
+	{	for(i=0;i<spare;i++) (*f__putn)(' ');
+		if(sign) (*f__putn)('-');
+		else if(f__cplus) (*f__putn)('+');
+		for(i=0;i<ndigit;i++) (*f__putn)(*ans++);
+	}
+	return(0);
+}
+ static int
+#ifdef KR_headers
+wrt_IM(n,w,m,len,base) Uint *n; ftnlen len; int base;
+#else
+wrt_IM(Uint *n, int w, int m, ftnlen len, int base)
+#endif
+{	int ndigit,sign,spare,i,xsign;
+	longint x;
+	char *ans;
+	if(sizeof(integer)==len) x=n->il;
+	else if(len == sizeof(char)) x = n->ic;
+#ifdef Allow_TYQUAD
+	else if (len == sizeof(longint)) x = n->ili;
+#endif
+	else x=n->is;
+	ans=f__icvt(x,&ndigit,&sign, base);
+	if(sign || f__cplus) xsign=1;
+	else xsign=0;
+	if(ndigit+xsign>w || m+xsign>w)
+	{	for(i=0;i<w;i++) (*f__putn)('*');
+		return(0);
+	}
+	if(x==0 && m==0)
+	{	for(i=0;i<w;i++) (*f__putn)(' ');
+		return(0);
+	}
+	if(ndigit>=m)
+		spare=w-ndigit-xsign;
+	else
+		spare=w-m-xsign;
+	for(i=0;i<spare;i++) (*f__putn)(' ');
+	if(sign) (*f__putn)('-');
+	else if(f__cplus) (*f__putn)('+');
+	for(i=0;i<m-ndigit;i++) (*f__putn)('0');
+	for(i=0;i<ndigit;i++) (*f__putn)(*ans++);
+	return(0);
+}
+ static int
+#ifdef KR_headers
+wrt_AP(s) char *s;
+#else
+wrt_AP(char *s)
+#endif
+{	char quote;
+	int i;
+
+	if(f__cursor && (i = mv_cur()))
+		return i;
+	quote = *s++;
+	for(;*s;s++)
+	{	if(*s!=quote) (*f__putn)(*s);
+		else if(*++s==quote) (*f__putn)(*s);
+		else return(1);
+	}
+	return(1);
+}
+ static int
+#ifdef KR_headers
+wrt_H(a,s) char *s;
+#else
+wrt_H(int a, char *s)
+#endif
+{
+	int i;
+
+	if(f__cursor && (i = mv_cur()))
+		return i;
+	while(a--) (*f__putn)(*s++);
+	return(1);
+}
+
+ int
+#ifdef KR_headers
+wrt_L(n,len, sz) Uint *n; ftnlen sz;
+#else
+wrt_L(Uint *n, int len, ftnlen sz)
+#endif
+{	int i;
+	long x;
+	if(sizeof(long)==sz) x=n->il;
+	else if(sz == sizeof(char)) x = n->ic;
+	else x=n->is;
+	for(i=0;i<len-1;i++)
+		(*f__putn)(' ');
+	if(x) (*f__putn)('T');
+	else (*f__putn)('F');
+	return(0);
+}
+ static int
+#ifdef KR_headers
+wrt_A(p,len) char *p; ftnlen len;
+#else
+wrt_A(char *p, ftnlen len)
+#endif
+{
+	while(len-- > 0) (*f__putn)(*p++);
+	return(0);
+}
+ static int
+#ifdef KR_headers
+wrt_AW(p,w,len) char * p; ftnlen len;
+#else
+wrt_AW(char * p, int w, ftnlen len)
+#endif
+{
+	while(w>len)
+	{	w--;
+		(*f__putn)(' ');
+	}
+	while(w-- > 0)
+		(*f__putn)(*p++);
+	return(0);
+}
+
+ static int
+#ifdef KR_headers
+wrt_G(p,w,d,e,len) ufloat *p; ftnlen len;
+#else
+wrt_G(ufloat *p, int w, int d, int e, ftnlen len)
+#endif
+{	double up = 1,x;
+	int i=0,oldscale,n,j;
+	x = len==sizeof(real)?p->pf:p->pd;
+	if(x < 0 ) x = -x;
+	if(x<.1) {
+		if (x != 0.)
+			return(wrt_E(p,w,d,e,len));
+		i = 1;
+		goto have_i;
+		}
+	for(;i<=d;i++,up*=10)
+	{	if(x>=up) continue;
+ have_i:
+		oldscale = f__scale;
+		f__scale = 0;
+		if(e==0) n=4;
+		else	n=e+2;
+		i=wrt_F(p,w-n,d-i,len);
+		for(j=0;j<n;j++) (*f__putn)(' ');
+		f__scale=oldscale;
+		return(i);
+	}
+	return(wrt_E(p,w,d,e,len));
+}
+
+ int
+#ifdef KR_headers
+w_ed(p,ptr,len) struct syl *p; char *ptr; ftnlen len;
+#else
+w_ed(struct syl *p, char *ptr, ftnlen len)
+#endif
+{
+	int i;
+
+	if(f__cursor && (i = mv_cur()))
+		return i;
+	switch(p->op)
+	{
+	default:
+		fprintf(stderr,"w_ed, unexpected code: %d\n", p->op);
+		sig_die(f__fmtbuf, 1);
+	case I:	return(wrt_I((Uint *)ptr,p->p1,len, 10));
+	case IM:
+		return(wrt_IM((Uint *)ptr,p->p1,p->p2.i[0],len,10));
+
+		/* O and OM don't work right for character, double, complex, */
+		/* or doublecomplex, and they differ from Fortran 90 in */
+		/* showing a minus sign for negative values. */
+
+	case O:	return(wrt_I((Uint *)ptr, p->p1, len, 8));
+	case OM:
+		return(wrt_IM((Uint *)ptr,p->p1,p->p2.i[0],len,8));
+	case L:	return(wrt_L((Uint *)ptr,p->p1, len));
+	case A: return(wrt_A(ptr,len));
+	case AW:
+		return(wrt_AW(ptr,p->p1,len));
+	case D:
+	case E:
+	case EE:
+		return(wrt_E((ufloat *)ptr,p->p1,p->p2.i[0],p->p2.i[1],len));
+	case G:
+	case GE:
+		return(wrt_G((ufloat *)ptr,p->p1,p->p2.i[0],p->p2.i[1],len));
+	case F:	return(wrt_F((ufloat *)ptr,p->p1,p->p2.i[0],len));
+
+		/* Z and ZM assume 8-bit bytes. */
+
+	case Z: return(wrt_Z((Uint *)ptr,p->p1,0,len));
+	case ZM:
+		return(wrt_Z((Uint *)ptr,p->p1,p->p2.i[0],len));
+	}
+}
+
+ int
+#ifdef KR_headers
+w_ned(p) struct syl *p;
+#else
+w_ned(struct syl *p)
+#endif
+{
+	switch(p->op)
+	{
+	default: fprintf(stderr,"w_ned, unexpected code: %d\n", p->op);
+		sig_die(f__fmtbuf, 1);
+	case SLASH:
+		return((*f__donewrec)());
+	case T: f__cursor = p->p1-f__recpos - 1;
+		return(1);
+	case TL: f__cursor -= p->p1;
+		if(f__cursor < -f__recpos)	/* TL1000, 1X */
+			f__cursor = -f__recpos;
+		return(1);
+	case TR:
+	case X:
+		f__cursor += p->p1;
+		return(1);
+	case APOS:
+		return(wrt_AP(p->p2.s));
+	case H:
+		return(wrt_H(p->p1,p->p2.s));
+	}
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/wsfe.c b/src/f2c/wsfe.c
new file mode 100644
index 0000000..8709f3b
--- /dev/null
+++ b/src/f2c/wsfe.c
@@ -0,0 +1,78 @@
+/*write sequential formatted external*/
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int
+x_wSL(Void)
+{
+	int n = f__putbuf('\n');
+	f__hiwater = f__recpos = f__cursor = 0;
+	return(n == 0);
+}
+
+ static int
+xw_end(Void)
+{
+	int n;
+
+	if(f__nonl) {
+		f__putbuf(n = 0);
+		fflush(f__cf);
+		}
+	else
+		n = f__putbuf('\n');
+	f__hiwater = f__recpos = f__cursor = 0;
+	return n;
+}
+
+ static int
+xw_rev(Void)
+{
+	int n = 0;
+	if(f__workdone) {
+		n = f__putbuf('\n');
+		f__workdone = 0;
+		}
+	f__hiwater = f__recpos = f__cursor = 0;
+	return n;
+}
+
+#ifdef KR_headers
+integer s_wsfe(a) cilist *a;	/*start*/
+#else
+integer s_wsfe(cilist *a)	/*start*/
+#endif
+{	int n;
+	if(!f__init) f_init();
+	f__reading=0;
+	f__sequential=1;
+	f__formatted=1;
+	f__external=1;
+	if(n=c_sfe(a)) return(n);
+	f__elist=a;
+	f__hiwater = f__cursor=f__recpos=0;
+	f__nonl = 0;
+	f__scale=0;
+	f__fmtbuf=a->cifmt;
+	f__cf=f__curunit->ufd;
+	if(pars_f(f__fmtbuf)<0) err(a->cierr,100,"startio");
+	f__putn= x_putc;
+	f__doed= w_ed;
+	f__doned= w_ned;
+	f__doend=xw_end;
+	f__dorevert=xw_rev;
+	f__donewrec=x_wSL;
+	fmt_bg();
+	f__cplus=0;
+	f__cblank=f__curunit->ublnk;
+	if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit))
+		err(a->cierr,errno,"write start");
+	return(0);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/wsle.c b/src/f2c/wsle.c
new file mode 100644
index 0000000..3e60270
--- /dev/null
+++ b/src/f2c/wsle.c
@@ -0,0 +1,42 @@
+#include "f2c.h"
+#include "fio.h"
+#include "fmt.h"
+#include "lio.h"
+#include "string.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+integer s_wsle(a) cilist *a;
+#else
+integer s_wsle(cilist *a)
+#endif
+{
+	int n;
+	if(n=c_le(a)) return(n);
+	f__reading=0;
+	f__external=1;
+	f__formatted=1;
+	f__putn = x_putc;
+	f__lioproc = l_write;
+	L_len = LINE;
+	f__donewrec = x_wSL;
+	if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit))
+		err(a->cierr, errno, "list output start");
+	return(0);
+	}
+
+integer e_wsle(Void)
+{
+	int n = f__putbuf('\n');
+	f__recpos=0;
+#ifdef ALWAYS_FLUSH
+	if (!n && fflush(f__cf))
+		err(f__elist->cierr, errno, "write end");
+#endif
+	return(n);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/wsne.c b/src/f2c/wsne.c
new file mode 100644
index 0000000..e204a51
--- /dev/null
+++ b/src/f2c/wsne.c
@@ -0,0 +1,32 @@
+#include "f2c.h"
+#include "fio.h"
+#include "lio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ integer
+#ifdef KR_headers
+s_wsne(a) cilist *a;
+#else
+s_wsne(cilist *a)
+#endif
+{
+	int n;
+
+	if(n=c_le(a))
+		return(n);
+	f__reading=0;
+	f__external=1;
+	f__formatted=1;
+	f__putn = x_putc;
+	L_len = LINE;
+	f__donewrec = x_wSL;
+	if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit))
+		err(a->cierr, errno, "namelist output start");
+	x_wsne(a);
+	return e_wsle();
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/xwsne.c b/src/f2c/xwsne.c
new file mode 100644
index 0000000..f810d3e
--- /dev/null
+++ b/src/f2c/xwsne.c
@@ -0,0 +1,77 @@
+#include "f2c.h"
+#include "fio.h"
+#include "lio.h"
+#include "fmt.h"
+
+extern int f__Aquote;
+
+ static VOID
+nl_donewrec(Void)
+{
+	(*f__donewrec)();
+	PUT(' ');
+	}
+
+#ifdef KR_headers
+x_wsne(a) cilist *a;
+#else
+#include "string.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ VOID
+x_wsne(cilist *a)
+#endif
+{
+	Namelist *nl;
+	char *s;
+	Vardesc *v, **vd, **vde;
+	ftnint number, type;
+	ftnlen *dims;
+	ftnlen size;
+	extern ftnlen f__typesize[];
+
+	nl = (Namelist *)a->cifmt;
+	PUT('&');
+	for(s = nl->name; *s; s++)
+		PUT(*s);
+	PUT(' ');
+	f__Aquote = 1;
+	vd = nl->vars;
+	vde = vd + nl->nvars;
+	while(vd < vde) {
+		v = *vd++;
+		s = v->name;
+#ifdef No_Extra_Namelist_Newlines
+		if (f__recpos+strlen(s)+2 >= L_len)
+#endif
+			nl_donewrec();
+		while(*s)
+			PUT(*s++);
+		PUT(' ');
+		PUT('=');
+		number = (dims = v->dims) ? dims[1] : 1;
+		type = v->type;
+		if (type < 0) {
+			size = -type;
+			type = TYCHAR;
+			}
+		else
+			size = f__typesize[type];
+		l_write(&number, v->addr, size, type);
+		if (vd < vde) {
+			if (f__recpos+2 >= L_len)
+				nl_donewrec();
+			PUT(',');
+			PUT(' ');
+			}
+		else if (f__recpos+1 >= L_len)
+			nl_donewrec();
+		}
+	f__Aquote = 0;
+	PUT('/');
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_abs.c b/src/f2c/z_abs.c
new file mode 100644
index 0000000..4d8a015
--- /dev/null
+++ b/src/f2c/z_abs.c
@@ -0,0 +1,18 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+double f__cabs();
+double z_abs(z) doublecomplex *z;
+#else
+double f__cabs(double, double);
+double z_abs(doublecomplex *z)
+#endif
+{
+return( f__cabs( z->r, z->i ) );
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_cos.c b/src/f2c/z_cos.c
new file mode 100644
index 0000000..4abe8bf
--- /dev/null
+++ b/src/f2c/z_cos.c
@@ -0,0 +1,21 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sin(), cos(), sinh(), cosh();
+VOID z_cos(r, z) doublecomplex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+void z_cos(doublecomplex *r, doublecomplex *z)
+#endif
+{
+	double zi = z->i, zr = z->r;
+	r->r =   cos(zr) * cosh(zi);
+	r->i = - sin(zr) * sinh(zi);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_div.c b/src/f2c/z_div.c
new file mode 100644
index 0000000..e45f360
--- /dev/null
+++ b/src/f2c/z_div.c
@@ -0,0 +1,50 @@
+#include "f2c.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef KR_headers
+extern VOID sig_die();
+VOID z_div(c, a, b) doublecomplex *a, *b, *c;
+#else
+extern void sig_die(const char*, int);
+void z_div(doublecomplex *c, doublecomplex *a, doublecomplex *b)
+#endif
+{
+	double ratio, den;
+	double abr, abi, cr;
+
+	if( (abr = b->r) < 0.)
+		abr = - abr;
+	if( (abi = b->i) < 0.)
+		abi = - abi;
+	if( abr <= abi )
+		{
+		if(abi == 0) {
+#ifdef IEEE_COMPLEX_DIVIDE
+			if (a->i != 0 || a->r != 0)
+				abi = 1.;
+			c->i = c->r = abi / abr;
+			return;
+#else
+			sig_die("complex division by zero", 1);
+#endif
+			}
+		ratio = b->r / b->i ;
+		den = b->i * (1 + ratio*ratio);
+		cr = (a->r*ratio + a->i) / den;
+		c->i = (a->i*ratio - a->r) / den;
+		}
+
+	else
+		{
+		ratio = b->i / b->r ;
+		den = b->r * (1 + ratio*ratio);
+		cr = (a->r + a->i*ratio) / den;
+		c->i = (a->i - a->r*ratio) / den;
+		}
+	c->r = cr;
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_exp.c b/src/f2c/z_exp.c
new file mode 100644
index 0000000..7b8edfe
--- /dev/null
+++ b/src/f2c/z_exp.c
@@ -0,0 +1,23 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double exp(), cos(), sin();
+VOID z_exp(r, z) doublecomplex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+void z_exp(doublecomplex *r, doublecomplex *z)
+#endif
+{
+	double expx, zi = z->i;
+
+	expx = exp(z->r);
+	r->r = expx * cos(zi);
+	r->i = expx * sin(zi);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_log.c b/src/f2c/z_log.c
new file mode 100644
index 0000000..4f11bbe
--- /dev/null
+++ b/src/f2c/z_log.c
@@ -0,0 +1,121 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double log(), f__cabs(), atan2();
+#define ANSI(x) ()
+#else
+#define ANSI(x) x
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern double f__cabs(double, double);
+#endif
+
+#ifndef NO_DOUBLE_EXTENDED
+#ifndef GCC_COMPARE_BUG_FIXED
+#ifndef Pre20000310
+#ifdef Comment
+Some versions of gcc, such as 2.95.3 and 3.0.4, are buggy under -O2 or -O3:
+on IA32 (Intel 80x87) systems, they may do comparisons on values computed
+in extended-precision registers.  This can lead to the test "s > s0" that
+was used below being carried out incorrectly.  The fix below cannot be
+spoiled by overzealous optimization, since the compiler cannot know
+whether gcc_bug_bypass_diff_F2C will be nonzero.  (We expect it always
+to be zero.  The weird name is unlikely to collide with anything.)
+
+An example (provided by Ulrich Jakobus) where the bug fix matters is
+
+	double complex a, b
+	a = (.1099557428756427618354862829619, .9857360542953131909982289471372)
+	b = log(a)
+
+An alternative to the fix below would be to use 53-bit rounding precision,
+but the means of specifying this 80x87 feature are highly unportable.
+#endif /*Comment*/
+#define BYPASS_GCC_COMPARE_BUG
+double (*gcc_bug_bypass_diff_F2C) ANSI((double*,double*));
+ static double
+#ifdef KR_headers
+diff1(a,b) double *a, *b;
+#else
+diff1(double *a, double *b)
+#endif
+{ return *a - *b; }
+#endif /*Pre20000310*/
+#endif /*GCC_COMPARE_BUG_FIXED*/
+#endif /*NO_DOUBLE_EXTENDED*/
+
+#ifdef KR_headers
+VOID z_log(r, z) doublecomplex *r, *z;
+#else
+void z_log(doublecomplex *r, doublecomplex *z)
+#endif
+{
+	double s, s0, t, t2, u, v;
+	double zi = z->i, zr = z->r;
+#ifdef BYPASS_GCC_COMPARE_BUG
+	double (*diff) ANSI((double*,double*));
+#endif
+
+	r->i = atan2(zi, zr);
+#ifdef Pre20000310
+	r->r = log( f__cabs( zr, zi ) );
+#else
+	if (zi < 0)
+		zi = -zi;
+	if (zr < 0)
+		zr = -zr;
+	if (zr < zi) {
+		t = zi;
+		zi = zr;
+		zr = t;
+		}
+	t = zi/zr;
+	s = zr * sqrt(1 + t*t);
+	/* now s = f__cabs(zi,zr), and zr = |zr| >= |zi| = zi */
+	if ((t = s - 1) < 0)
+		t = -t;
+	if (t > .01)
+		r->r = log(s);
+	else {
+
+#ifdef Comment
+
+	log(1+x) = x - x^2/2 + x^3/3 - x^4/4 + - ...
+
+		 = x(1 - x/2 + x^2/3 -+...)
+
+	[sqrt(y^2 + z^2) - 1] * [sqrt(y^2 + z^2) + 1] = y^2 + z^2 - 1, so
+
+	sqrt(y^2 + z^2) - 1 = (y^2 + z^2 - 1) / [sqrt(y^2 + z^2) + 1]
+
+#endif /*Comment*/
+
+#ifdef BYPASS_GCC_COMPARE_BUG
+		if (!(diff = gcc_bug_bypass_diff_F2C))
+			diff = diff1;
+#endif
+		t = ((zr*zr - 1.) + zi*zi) / (s + 1);
+		t2 = t*t;
+		s = 1. - 0.5*t;
+		u = v = 1;
+		do {
+			s0 = s;
+			u *= t2;
+			v += 2;
+			s += u/v - t*u/(v+1);
+			}
+#ifdef BYPASS_GCC_COMPARE_BUG
+			while(s - s0 > 1e-18 || (*diff)(&s,&s0) > 0.);
+#else
+			while(s > s0);
+#endif
+		r->r = s*t;
+		}
+#endif
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_sin.c b/src/f2c/z_sin.c
new file mode 100644
index 0000000..01225a9
--- /dev/null
+++ b/src/f2c/z_sin.c
@@ -0,0 +1,21 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sin(), cos(), sinh(), cosh();
+VOID z_sin(r, z) doublecomplex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+void z_sin(doublecomplex *r, doublecomplex *z)
+#endif
+{
+	double zi = z->i, zr = z->r;
+	r->r = sin(zr) * cosh(zi);
+	r->i = cos(zr) * sinh(zi);
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/f2c/z_sqrt.c b/src/f2c/z_sqrt.c
new file mode 100644
index 0000000..35bd44c
--- /dev/null
+++ b/src/f2c/z_sqrt.c
@@ -0,0 +1,35 @@
+#include "f2c.h"
+
+#ifdef KR_headers
+double sqrt(), f__cabs();
+VOID z_sqrt(r, z) doublecomplex *r, *z;
+#else
+#undef abs
+#include "math.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern double f__cabs(double, double);
+void z_sqrt(doublecomplex *r, doublecomplex *z)
+#endif
+{
+	double mag, zi = z->i, zr = z->r;
+
+	if( (mag = f__cabs(zr, zi)) == 0.)
+		r->r = r->i = 0.;
+	else if(zr > 0)
+		{
+		r->r = sqrt(0.5 * (mag + zr) );
+		r->i = zi / r->r / 2;
+		}
+	else
+		{
+		r->i = sqrt(0.5 * (mag - zr) );
+		if(zi < 0)
+			r->i = - r->i;
+		r->r = zi / r->i / 2;
+		}
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/fast_community.c b/src/fast_community.c
new file mode 100644
index 0000000..8acb4e1
--- /dev/null
+++ b/src/fast_community.c
@@ -0,0 +1,921 @@
+/* -*- 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_community.h"
+#include "igraph_memory.h"
+#include "igraph_iterators.h"
+#include "igraph_interface.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_structural.h"
+#include "igraph_vector_ptr.h"
+#include "config.h"
+
+/* #define IGRAPH_FASTCOMM_DEBUG */
+
+#ifdef _MSC_VER
+/* MSVC does not support variadic macros */
+#include <stdarg.h>
+void debug(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+#ifdef IGRAPH_FASTCOMM_DEBUG
+    vfprintf(stderr, fmt, args);
+#endif
+    va_end(args);
+}
+#else
+#  ifdef IGRAPH_FASTCOMM_DEBUG
+#    define debug(...) fprintf(stderr, __VA_ARGS__)
+#  else
+#    define debug(...) 
+#  endif
+#endif
+
+/*
+ * Implementation of the community structure algorithm originally published
+ * by Clauset et al in:
+ *
+ * A. Clauset, M.E.J. Newman and C. Moore, "Finding community structure in
+ * very large networks.". Phys. Rev. E 70, 066111 (2004).
+ *
+ * The data structures being used are slightly different and they are described
+ * most closely in:
+ *
+ * K. Wakita, T. Tsurumi, "Finding community structure in mega-scale social
+ * networks.". arXiv:cs/0702048v1.
+ *
+ * We maintain a vector of communities, each of which containing a list of
+ * pointers to their neighboring communities along with the increase in the
+ * modularity score that could be achieved by joining the two communities.
+ * Each community has a pointer to one of its neighbors - the one which would
+ * result in the highest increase in modularity after a join. The local
+ * (community-level) maximums are also stored in an indexed max-heap. The
+ * max-heap itself stores its elements in an array which satisfies the heap
+ * property, but to allow us to access any of the elements in the array based
+ * on the community index (and not based on the array index - which depends on
+ * the element's actual position in the heap), we also maintain an index
+ * vector in the heap: the ith element of the index vector contains the
+ * position of community i in the array of the max-heap. When we perform
+ * sifting operations on the heap to restore the heap property, we also maintain
+ * the index vector.
+ */
+
+/* Structure storing a pair of communities along with their dQ values */
+typedef struct s_igraph_i_fastgreedy_commpair {
+  long int first;       /* first member of the community pair */
+  long int second;      /* second member of the community pair */
+  igraph_real_t *dq;    /* pointer to a member of the dq vector storing the */
+                        /* increase in modularity achieved when joining */
+  struct s_igraph_i_fastgreedy_commpair *opposite;
+} igraph_i_fastgreedy_commpair;
+
+/* Structure storing a community */
+typedef struct {
+  igraph_integer_t id;      /* Identifier of the community (for merges matrix) */
+  igraph_integer_t size;    /* Size of the community */
+  igraph_vector_ptr_t neis; /* references to neighboring communities */
+  igraph_i_fastgreedy_commpair* maxdq; /* community pair with maximal dq */
+} igraph_i_fastgreedy_community;
+
+/* Global community list structure */
+typedef struct {
+  long int no_of_communities, n;  /* number of communities, number of vertices */
+  igraph_i_fastgreedy_community* e;     /* list of communities */
+  igraph_i_fastgreedy_community** heap; /* heap of communities */
+  igraph_integer_t *heapindex; /* heap index to speed up lookup by community idx */
+} igraph_i_fastgreedy_community_list;
+
+/* Scans the community neighborhood list for the new maximal dq value.
+ * Returns 1 if the maximum is different from the previous one,
+ * 0 otherwise. */
+int igraph_i_fastgreedy_community_rescan_max(
+  igraph_i_fastgreedy_community* comm) {
+  long int i, n;
+  igraph_i_fastgreedy_commpair *p, *oldmax;
+
+  n = igraph_vector_ptr_size(&comm->neis);
+  if (n==0) {
+    comm->maxdq = 0;
+    return 1;
+  }
+  
+  oldmax = comm->maxdq;
+  comm->maxdq = (igraph_i_fastgreedy_commpair*)VECTOR(comm->neis)[0];
+  for (i=1; i<n; i++) {
+	p = (igraph_i_fastgreedy_commpair*)VECTOR(comm->neis)[i];
+	if (*p->dq > *comm->maxdq->dq) comm->maxdq=p;
+  }
+  if (oldmax == comm->maxdq) return 0;
+  return 1;
+}
+
+/* Destroys the global community list object */
+void igraph_i_fastgreedy_community_list_destroy(
+  igraph_i_fastgreedy_community_list* list) {
+  long int i;
+  for (i=0; i<list->n; i++) {
+	igraph_vector_ptr_destroy(&list->e[i].neis);
+  }
+  free(list->e);
+  if (list->heapindex != 0) free(list->heapindex);
+  if (list->heap != 0) free(list->heap);
+}
+
+/* Community list heap maintenance: sift down */
+void igraph_i_fastgreedy_community_list_sift_down(
+  igraph_i_fastgreedy_community_list* list, long int idx) {
+  long int root, child, c1, c2;
+  igraph_i_fastgreedy_community* dummy;
+  igraph_integer_t dummy2;
+
+  root = idx;
+  while (root*2+1 < list->no_of_communities) {
+    child = root*2+1;
+	if (child+1 < list->no_of_communities &&
+		*list->heap[child]->maxdq->dq < *list->heap[child+1]->maxdq->dq)
+	  child++;
+	if (*list->heap[root]->maxdq->dq < *list->heap[child]->maxdq->dq) {
+	  c1 = list->heap[root]->maxdq->first;
+	  c2 = list->heap[child]->maxdq->first;
+
+	  dummy = list->heap[root];
+	  list->heap[root] = list->heap[child];
+	  list->heap[child] = dummy;
+	  
+	  dummy2 = list->heapindex[c1];
+	  list->heapindex[c1] = list->heapindex[c2];
+	  list->heapindex[c2] = dummy2;
+
+	  root = child;
+	} else break;
+  }
+}
+
+/* Community list heap maintenance: sift up */
+void igraph_i_fastgreedy_community_list_sift_up(
+  igraph_i_fastgreedy_community_list* list, long int idx) {
+  long int root, parent, c1, c2;
+  igraph_i_fastgreedy_community* dummy;
+  igraph_integer_t dummy2;
+
+  root = idx;
+  while (root>0) {
+    parent = (root-1)/2;
+	if (*list->heap[parent]->maxdq->dq < *list->heap[root]->maxdq->dq) {
+	  c1 = list->heap[root]->maxdq->first;
+	  c2 = list->heap[parent]->maxdq->first;
+	  
+	  dummy = list->heap[parent];
+	  list->heap[parent] = list->heap[root];
+	  list->heap[root] = dummy;
+	  
+	  dummy2 = list->heapindex[c1];
+	  list->heapindex[c1] = list->heapindex[c2];
+	  list->heapindex[c2] = dummy2;
+
+	  root = parent;
+	} else break;
+  }
+}
+
+/* Builds the community heap for the first time */
+void igraph_i_fastgreedy_community_list_build_heap(
+  igraph_i_fastgreedy_community_list* list) {
+  long int i;
+  for (i=list->no_of_communities/2-1; i>=0; i--)
+	igraph_i_fastgreedy_community_list_sift_down(list, i);
+}
+
+/* Finds the element belonging to a given community in the heap and return its
+ * index in the heap array */
+#define igraph_i_fastgreedy_community_list_find_in_heap(list, idx) (list)->heapindex[idx]
+
+/* Dumps the heap - for debugging purposes */
+void igraph_i_fastgreedy_community_list_dump_heap(
+  igraph_i_fastgreedy_community_list* list) {
+  long int i;
+  debug("Heap:\n");
+  for (i=0; i<list->no_of_communities; i++) {
+	debug("(%ld, %p, %p)", i, list->heap[i],
+	  list->heap[i]->maxdq);
+	if (list->heap[i]->maxdq) {
+	  debug(" (%ld, %ld, %.7f)", list->heap[i]->maxdq->first,
+		list->heap[i]->maxdq->second, *list->heap[i]->maxdq->dq);
+	}
+	debug("\n");
+  }
+  debug("Heap index:\n");
+  for (i=0; i<list->no_of_communities; i++) debug("%ld ", (long)list->heapindex[i]);
+  debug("\nEND\n");
+}
+
+/* Checks if the community heap satisfies the heap property.
+ * Only useful for debugging. */
+void igraph_i_fastgreedy_community_list_check_heap(
+  igraph_i_fastgreedy_community_list* list) {
+  long int i;
+  for (i=0; i<list->no_of_communities/2; i++) {
+	if ((2*i+1<list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2*i+1]->maxdq->dq) ||
+		(2*i+2<list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2*i+2]->maxdq->dq)) {
+	  IGRAPH_WARNING("Heap property violated");
+	  debug("Position: %ld, %ld and %ld\n", i, 2*i+1, 2*i+2);
+	  igraph_i_fastgreedy_community_list_dump_heap(list);
+	}
+  }
+}
+
+/* Removes a given element from the heap */
+void igraph_i_fastgreedy_community_list_remove(
+  igraph_i_fastgreedy_community_list* list, long int idx) {
+  igraph_real_t old;
+  long int commidx;
+  
+  /* First adjust the index */
+  commidx=list->heap[list->no_of_communities-1]->maxdq->first;
+  list->heapindex[commidx] = (igraph_integer_t) idx;
+  commidx=list->heap[idx]->maxdq->first;
+  list->heapindex[commidx] = -1;
+
+  /* Now remove the element */
+  old=*list->heap[idx]->maxdq->dq;
+  list->heap[idx] = list->heap[list->no_of_communities-1];
+  list->no_of_communities--;
+  
+  /* Recover heap property */
+  if (old > *list->heap[idx]->maxdq->dq)
+	igraph_i_fastgreedy_community_list_sift_down(list, idx);
+  else
+	igraph_i_fastgreedy_community_list_sift_up(list, idx);
+}
+
+/* Removes a given element from the heap when there are no more neighbors
+ * for it (comm->maxdq is NULL) */
+void igraph_i_fastgreedy_community_list_remove2(
+  igraph_i_fastgreedy_community_list* list, long int idx, long int comm) {
+  long int i;
+ 
+  if (idx == list->no_of_communities-1) {
+    /* We removed the rightmost element on the bottom level, no problem,
+     * there's nothing to be done */
+    list->heapindex[comm] = -1;
+    list->no_of_communities--;
+    return;
+  }
+
+  /* First adjust the index */
+  i=list->heap[list->no_of_communities-1]->maxdq->first;
+  list->heapindex[i] = (igraph_integer_t) idx;
+  list->heapindex[comm] = -1;
+
+  /* Now remove the element */
+  list->heap[idx] = list->heap[list->no_of_communities-1];
+  list->no_of_communities--;
+  
+  /* Recover heap property */
+  for (i=list->no_of_communities/2-1; i>=0; i--)
+	igraph_i_fastgreedy_community_list_sift_down(list, i);
+}
+
+/* Removes the pair belonging to community k from the neighborhood list
+ * of community c (that is, clist[c]) and recalculates maxdq */
+void igraph_i_fastgreedy_community_remove_nei(
+  igraph_i_fastgreedy_community_list* list, long int c, long int k) {
+  long int i, n;
+  igraph_bool_t rescan=0;
+  igraph_i_fastgreedy_commpair *p;
+  igraph_i_fastgreedy_community *comm;
+  igraph_real_t olddq;
+
+  comm=&list->e[c];
+  n=igraph_vector_ptr_size(&comm->neis);
+  for (i=0; i<n; i++) {
+	p=(igraph_i_fastgreedy_commpair*)VECTOR(comm->neis)[i];
+    if (p->second == k) {
+	  /* Check current maxdq */
+	  if (comm->maxdq == p) rescan=1;
+	  break;
+	}
+  }
+  if (i<n) {
+	olddq = *comm->maxdq->dq;
+	igraph_vector_ptr_remove(&comm->neis, i);
+	if (rescan) {
+	  igraph_i_fastgreedy_community_rescan_max(comm);
+      i=igraph_i_fastgreedy_community_list_find_in_heap(list, c);
+	  if (comm->maxdq) {
+        if (*comm->maxdq->dq > olddq)
+		  igraph_i_fastgreedy_community_list_sift_up(list, i);
+        else
+		  igraph_i_fastgreedy_community_list_sift_down(list, i);
+      } else {
+        /* no more neighbors for this community. we should remove this
+         * community from the heap and restore the heap property */
+        debug("REMOVING (NO MORE NEIS): %ld\n", i);
+        igraph_i_fastgreedy_community_list_remove2(list, i, c);
+      }
+	}
+  }
+}
+
+/* Updates the dq value of community pair p in the community with index p->first
+ * of the community list clist to newdq and restores the heap property
+ * in community c if necessary. Returns 1 if the maximum in the row had
+ * to be updated, zero otherwise */
+int igraph_i_fastgreedy_community_update_dq(
+  igraph_i_fastgreedy_community_list* list,
+  igraph_i_fastgreedy_commpair* p, igraph_real_t newdq) {
+  long int i,j,to,from;
+  igraph_real_t olddq;
+  igraph_i_fastgreedy_community *comm_to, *comm_from;
+  to=p->first; from=p->second;
+  comm_to=&list->e[to];
+  comm_from=&list->e[from];
+  if (comm_to->maxdq == p && newdq >= *p->dq) {
+	/* If we are adjusting the current maximum and it is increased, we don't
+	 * have to re-scan for the new maximum */
+	*p->dq = newdq;
+	/* The maximum was increased, so perform a sift-up in the heap */
+	i = igraph_i_fastgreedy_community_list_find_in_heap(list, to);
+	igraph_i_fastgreedy_community_list_sift_up(list, i);
+	/* Let's check the opposite side. If the pair was not the maximal in
+	 * the opposite side (the other community list)... */
+	if (comm_from->maxdq != p->opposite) {
+	  if (*comm_from->maxdq->dq < newdq) {
+	    /* ...and it will become the maximal, we need to adjust and sift up */
+		comm_from->maxdq = p->opposite;
+	    j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+	    igraph_i_fastgreedy_community_list_sift_up(list, j);
+	  } else {
+		/* The pair was not the maximal in the opposite side and it will
+		 * NOT become the maximal, there's nothing to do there */
+	  }
+	} else {
+	  /* The pair was maximal in the opposite side, so we need to sift it up
+	   * with the new value */
+	  j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+	  igraph_i_fastgreedy_community_list_sift_up(list, j);
+	}
+	return 1;
+  } else if (comm_to->maxdq != p && (newdq <= *comm_to->maxdq->dq)) {
+	/* If we are modifying an item which is not the current maximum, and the
+	 * new value is less than the current maximum, we don't
+	 * have to re-scan for the new maximum */
+	olddq = *p->dq;
+	*p->dq = newdq;
+	/* However, if the item was the maximum on the opposite side, we'd better
+	 * re-scan it */
+	if (comm_from->maxdq == p->opposite) {
+	  if (olddq>newdq) {
+		/* Decreased the maximum on the other side, we have to re-scan for the
+		 * new maximum */
+		igraph_i_fastgreedy_community_rescan_max(comm_from);
+  	    j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+	    igraph_i_fastgreedy_community_list_sift_down(list, j);
+	  } else {
+		/* Increased the maximum on the other side, we don't have to re-scan
+		 * but we might have to sift up */
+		j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+		igraph_i_fastgreedy_community_list_sift_up(list, j);
+	  }
+	}
+	return 0;
+  } else {
+	/* We got here in two cases:
+     (1) the pair we are modifying right now is the maximum in the given
+	     community and we are decreasing it
+	 (2) the pair we are modifying right now is NOT the maximum in the
+	     given community, but we increase it so much that it will become
+		 the new maximum
+     */
+    *p->dq = newdq;
+    if (comm_to->maxdq != p) {
+	  /* case (2) */
+	  comm_to->maxdq = p;
+	  /* The maximum was increased, so perform a sift-up in the heap */
+	  i = igraph_i_fastgreedy_community_list_find_in_heap(list, to);
+	  igraph_i_fastgreedy_community_list_sift_up(list, i);
+	  /* Opposite side. Chances are that the new value became the maximum
+	   * in the opposite side, but check it first */
+	  if (comm_from->maxdq != p->opposite) {
+		if (*comm_from->maxdq->dq < newdq) {
+		  /* Yes, it will become the new maximum */
+		  comm_from->maxdq = p->opposite;
+  	      j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+	      igraph_i_fastgreedy_community_list_sift_up(list, j);
+		} else {
+		  /* No, nothing to do there */
+		}
+	  } else {
+	    /* Already increased the maximum on the opposite side, so sift it up */
+  	    j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+	    igraph_i_fastgreedy_community_list_sift_up(list, j);
+	  }
+    } else {
+	  /* case (1) */
+	  /* This is the worst, we have to re-scan the whole community to find
+	   * the new maximum and update the global maximum as well if necessary */
+      igraph_i_fastgreedy_community_rescan_max(comm_to);
+	  /* The maximum was decreased, so perform a sift-down in the heap */
+	  i = igraph_i_fastgreedy_community_list_find_in_heap(list, to);
+	  igraph_i_fastgreedy_community_list_sift_down(list, i);
+  	  if (comm_from->maxdq != p->opposite) {
+		/* The one that we decreased on the opposite side is not the
+		 * maximal one. Nothing to do. */
+	  } else {
+		/* We decreased the maximal on the opposite side as well. Re-scan
+		 * and sift down */
+		igraph_i_fastgreedy_community_rescan_max(comm_from);
+	    j = igraph_i_fastgreedy_community_list_find_in_heap(list, from);
+	    igraph_i_fastgreedy_community_list_sift_down(list, j);
+      }
+    }
+  }
+  return 1;
+}
+
+/* Auxiliary function to sort a community pair list with respect to the
+ * `second` field */
+int igraph_i_fastgreedy_commpair_cmp(const void* p1, const void* p2) {
+  igraph_i_fastgreedy_commpair *cp1, *cp2;
+  cp1=*(igraph_i_fastgreedy_commpair**)p1;
+  cp2=*(igraph_i_fastgreedy_commpair**)p2;
+  return (int) (cp1->second - cp2->second);
+}
+
+/**
+ * \function igraph_community_fastgreedy
+ * \brief Finding community structure by greedy optimization of modularity
+ * 
+ * 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.
+ *
+ * </para><para>
+ * Some improvements proposed in K Wakita, T Tsurumi: Finding community
+ * structure in mega-scale social networks,
+ * http://www.arxiv.org/abs/cs.CY/0702048v1 have also been implemented.
+ *
+ * \param graph The input graph. It must be a graph without multiple edges.
+ *    This is checked and an error message is given for graphs with multiple
+ *    edges.
+ * \param weights Potentially a numeric vector containing edge
+ *    weights. Supply a null pointer here for unweighted graphs. The
+ *    weights are expected to be non-negative.
+ * \param merges Pointer to an initialized matrix or NULL, the result of the
+ *    computation is stored here. The matrix has two columns and each
+ *    merge corresponds to one merge, the ids of the two merged
+ *    components are stored. The component ids are numbered from zero and 
+ *    the first \c n components are the individual vertices, \c n is
+ *    the number of vertices in the graph. Component \c n is created
+ *    in the first merge, component \c n+1 in the second merge, etc.
+ *    The matrix will be resized as needed. If this argument is NULL
+ *    then it is ignored completely.
+ * \param modularity Pointer to an initialized vector or NULL pointer,
+ *    in the former case the modularity scores along the stages of the
+ *    computation are recorded here. The vector will be resized as
+ *    needed.
+ * \param membership Pointer to a vector. If not a null pointer, then
+ *    the membership vector corresponding to the best split (in terms
+ *    of modularity) is stored here. 
+ * \return Error code.
+ *
+ * \sa \ref igraph_community_walktrap(), \ref
+ * igraph_community_edge_betweenness() for other community detection
+ * algorithms, \ref igraph_community_to_membership() to convert the
+ * dendrogram to a membership vector.
+ *
+ * Time complexity: O(|E||V|log|V|) in the worst case,
+ * O(|E|+|V|log^2|V|) typically, |V| is the number of vertices, |E| is
+ * the number of edges.
+ * 
+ * \example examples/simple/igraph_community_fastgreedy.c
+ */
+int igraph_community_fastgreedy(const igraph_t *graph,
+				const igraph_vector_t *weights,
+				igraph_matrix_t *merges, 
+				igraph_vector_t *modularity, 
+				igraph_vector_t *membership) {
+  long int no_of_edges, no_of_nodes, no_of_joins, total_joins;
+  long int i, j, k, n, m, from, to, dummy;
+  igraph_integer_t ffrom, fto;
+  igraph_eit_t edgeit;
+  igraph_i_fastgreedy_commpair *pairs, *p1, *p2;
+  igraph_i_fastgreedy_community_list communities;
+  igraph_vector_t a;
+  igraph_real_t q, *dq, weight_sum, loop_weight_sum;
+  igraph_bool_t has_multiple;
+
+  /*long int join_order[] = { 16,5, 5,6, 6,0, 4,0, 10,0, 26,29, 29,33, 23,33, 27,33, 25,24, 24,31, 12,3, 21,1, 30,8, 8,32, 9,2, 17,1, 11,0, 7,3, 3,2, 13,2, 1,2, 28,31, 31,33, 22,32, 18,32, 20,32, 32,33, 15,33, 14,33, 0,19, 19,2, -1,-1 };*/
+  /*long int join_order[] = { 43,42, 42,41, 44,41, 41,36, 35,36, 37,36, 36,29, 38,29, 34,29, 39,29, 33,29, 40,29, 32,29, 14,29, 30,29, 31,29, 6,18, 18,4, 23,4, 21,4, 19,4, 27,4, 20,4, 22,4, 26,4, 25,4, 24,4, 17,4, 0,13, 13,2, 1,2, 11,2, 8,2, 5,2, 3,2, 10,2, 9,2, 7,2, 2,28, 28,15, 12,15, 29,16, 4,15, -1,-1 };*/
+
+  no_of_nodes = igraph_vcount(graph);
+  no_of_edges = igraph_ecount(graph);
+  
+  if (igraph_is_directed(graph)) {
+	IGRAPH_ERROR("fast greedy community detection works for undirected graphs only", IGRAPH_UNIMPLEMENTED);
+  }
+
+  total_joins=no_of_nodes-1;
+
+  if (weights != 0) {
+    if (igraph_vector_size(weights) < igraph_ecount(graph))
+      IGRAPH_ERROR("fast greedy community detection: weight vector too short", IGRAPH_EINVAL);
+    if (igraph_vector_any_smaller(weights, 0))
+      IGRAPH_ERROR("weights must be positive", IGRAPH_EINVAL);
+    weight_sum = igraph_vector_sum(weights);
+  } else weight_sum = no_of_edges;
+
+  IGRAPH_CHECK(igraph_has_multiple(graph, &has_multiple));
+  if (has_multiple) {
+    IGRAPH_ERROR("fast-greedy community finding works only on graphs without multiple edges", IGRAPH_EINVAL);
+  }
+
+  if (merges != 0) {
+	IGRAPH_CHECK(igraph_matrix_resize(merges, total_joins, 2));
+	igraph_matrix_null(merges);
+  }
+  if (modularity != 0) {
+	IGRAPH_CHECK(igraph_vector_resize(modularity, total_joins+1));
+  }
+
+  /* Create degree vector */
+  IGRAPH_VECTOR_INIT_FINALLY(&a, no_of_nodes);
+  if (weights) {
+    debug("Calculating weighted degrees\n");
+    for (i=0; i < no_of_edges; i++) {
+      VECTOR(a)[(long int)IGRAPH_FROM(graph, i)] += VECTOR(*weights)[i];
+      VECTOR(a)[(long int)IGRAPH_TO(graph, i)] += VECTOR(*weights)[i];
+    }
+  } else {
+    debug("Calculating degrees\n");
+    IGRAPH_CHECK(igraph_degree(graph, &a, igraph_vss_all(), IGRAPH_ALL, 1));
+  }
+
+  /* Create list of communities */
+  debug("Creating community list\n");
+  communities.n = no_of_nodes;
+  communities.no_of_communities = no_of_nodes;
+  communities.e = (igraph_i_fastgreedy_community*)calloc((size_t) no_of_nodes, sizeof(igraph_i_fastgreedy_community));
+  if (communities.e == 0) {
+	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, communities.e);
+  communities.heap = (igraph_i_fastgreedy_community**)calloc((size_t) no_of_nodes, sizeof(igraph_i_fastgreedy_community*));
+  if (communities.heap == 0) {
+	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, communities.heap);
+  communities.heapindex = (igraph_integer_t*)calloc((size_t)no_of_nodes, sizeof(igraph_integer_t));
+  if (communities.heapindex == 0) {
+	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY_CLEAN(2);
+  IGRAPH_FINALLY(igraph_i_fastgreedy_community_list_destroy, &communities);
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_vector_ptr_init(&communities.e[i].neis, 0);
+    communities.e[i].id = (igraph_integer_t) i;
+    communities.e[i].size = 1;
+  }
+
+  /* Create list of community pairs from edges */
+  debug("Allocating dq vector\n");
+  dq = (igraph_real_t*)calloc((size_t) no_of_edges, sizeof(igraph_real_t));
+  if (dq == 0) {
+	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, dq);
+  debug("Creating community pair list\n");
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
+  pairs = (igraph_i_fastgreedy_commpair*)calloc(2*(size_t) no_of_edges, sizeof(igraph_i_fastgreedy_commpair));
+  if (pairs == 0) {
+	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, pairs);
+  loop_weight_sum = 0;
+  for (i=0, j=0; !IGRAPH_EIT_END(edgeit); i+=2, j++, IGRAPH_EIT_NEXT(edgeit)) {
+    long int eidx = IGRAPH_EIT_GET(edgeit);
+    igraph_edge(graph, (igraph_integer_t) eidx, &ffrom, &fto);
+    
+	/* Create the pairs themselves */
+	from = (long int)ffrom; to = (long int)fto;
+	if (from == to) {
+      loop_weight_sum += weights ? 2*VECTOR(*weights)[eidx] : 2;
+      continue;
+    }
+
+	if (from>to) {
+	  dummy=from; from=to; to=dummy;
+	}
+    if (weights) {
+      dq[j]=2*(VECTOR(*weights)[eidx]/(weight_sum*2.0) - VECTOR(a)[from]*VECTOR(a)[to]/(4.0*weight_sum*weight_sum));
+    } else {
+	  dq[j]=2*(1.0/(no_of_edges*2.0) - VECTOR(a)[from]*VECTOR(a)[to]/(4.0*no_of_edges*no_of_edges));
+    }
+	pairs[i].first = from;
+	pairs[i].second = to;
+    pairs[i].dq = &dq[j];
+	pairs[i].opposite = &pairs[i+1];
+	pairs[i+1].first = to;
+	pairs[i+1].second = from;
+	pairs[i+1].dq = pairs[i].dq;
+	pairs[i+1].opposite = &pairs[i];
+	/* Link the pair to the communities */
+	igraph_vector_ptr_push_back(&communities.e[from].neis, &pairs[i]);
+	igraph_vector_ptr_push_back(&communities.e[to].neis, &pairs[i+1]);
+	/* Update maximums */
+	if (communities.e[from].maxdq==0 || *communities.e[from].maxdq->dq < *pairs[i].dq)
+	  communities.e[from].maxdq = &pairs[i];
+	if (communities.e[to].maxdq==0 || *communities.e[to].maxdq->dq < *pairs[i+1].dq)
+	  communities.e[to].maxdq = &pairs[i+1];
+  }
+  igraph_eit_destroy(&edgeit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Sorting community neighbor lists by community IDs */
+  debug("Sorting community neighbor lists\n");
+  for (i=0, j=0; i<no_of_nodes; i++) {
+	igraph_vector_ptr_sort(&communities.e[i].neis, igraph_i_fastgreedy_commpair_cmp);
+    /* Isolated vertices and vertices with loop edges only won't be stored in
+     * the heap (to avoid maxdq == 0) */
+    if (communities.e[i].maxdq != 0) {
+      communities.heap[j] = &communities.e[i];
+      communities.heapindex[i] = (igraph_integer_t) j;
+      j++;
+    } else {
+      communities.heapindex[i] = -1;
+    }
+  }
+  communities.no_of_communities = j;
+
+  /* Calculate proper vector a (see paper) and initial modularity */
+  q = 2.0 * (weights ? weight_sum : no_of_edges);
+  if (q == 0) {
+    /* All the weights are zero */
+  } else {
+    igraph_vector_scale(&a, 1.0 / q);
+    q = loop_weight_sum / q;
+    for (i=0; i<no_of_nodes; i++)
+	  q -= VECTOR(a)[i]*VECTOR(a)[i];
+  }
+
+  /* Initializing community heap */
+  debug("Initializing community heap\n");
+  igraph_i_fastgreedy_community_list_build_heap(&communities);
+
+  debug("Initial modularity: %.4f\n", q);
+
+  /* Let's rock ;) */
+  no_of_joins=0;
+  while (no_of_joins<total_joins) {
+    IGRAPH_ALLOW_INTERRUPTION();
+	IGRAPH_PROGRESS("fast greedy community detection", no_of_joins*100.0/total_joins, 0);
+    
+	/* Store the modularity */
+	if (modularity)
+      VECTOR(*modularity)[no_of_joins] = q;
+    
+	/* Some debug info if needed */
+	/* igraph_i_fastgreedy_community_list_check_heap(&communities); */
+#ifdef DEBUG
+	debug("===========================================\n");
+	for (i=0; i<communities.n; i++) {
+	  if (communities.e[i].maxdq == 0) {
+	    debug("Community #%ld: PASSIVE\n", i);
+	    continue;
+	  }
+      debug("Community #%ld\n ", i);
+	  for (j=0; j<igraph_vector_ptr_size(&communities.e[i].neis); j++) {
+	    p1=(igraph_i_fastgreedy_commpair*)VECTOR(communities.e[i].neis)[j];
+	    debug(" (%ld,%ld,%.4f)", p1->first, p1->second, *p1->dq);
+	  }
+	  p1=communities.e[i].maxdq;
+	  debug("\n  Maxdq: (%ld,%ld,%.4f)\n", p1->first, p1->second, *p1->dq);
+    }
+	debug("Global maxdq is: (%ld,%ld,%.4f)\n", communities.heap[0]->maxdq->first,
+	    communities.heap[0]->maxdq->second, *communities.heap[0]->maxdq->dq);
+    for (i=0; i<communities.no_of_communities; i++)
+	  debug("(%ld,%ld,%.4f) ", communities.heap[i]->maxdq->first, communities.heap[i]->maxdq->second, *communities.heap[0]->maxdq->dq);
+	debug("\n");
+#endif
+	if (communities.heap[0] == 0) break; /* no more communities */
+	if (communities.heap[0]->maxdq == 0) break; /* there are only isolated comms */
+    to=communities.heap[0]->maxdq->second;
+	from=communities.heap[0]->maxdq->first;
+
+	debug("Q[%ld] = %.7f\tdQ = %.7f\t |H| = %ld\n",
+	  no_of_joins, q, *communities.heap[0]->maxdq->dq, no_of_nodes-no_of_joins-1);
+
+	/* DEBUG */
+	/* from=join_order[no_of_joins*2]; to=join_order[no_of_joins*2+1];
+	if (to == -1) break;
+    for (i=0; i<igraph_vector_ptr_size(&communities.e[to].neis); i++) {
+      p1=(igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i];
+	  if (p1->second == from) communities.maxdq = p1;
+	} */
+
+	n = igraph_vector_ptr_size(&communities.e[to].neis);
+	m = igraph_vector_ptr_size(&communities.e[from].neis);
+	/*if (n>m) {
+	  dummy=n; n=m; m=dummy;
+	  dummy=to; to=from; from=dummy;
+	}*/
+	debug("  joining: %ld <- %ld\n", to, from);
+    q += *communities.heap[0]->maxdq->dq; 
+	
+	/* Merge the second community into the first */
+	i = j = 0;
+	while (i<n && j<m) {
+	  p1 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i];
+	  p2 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[from].neis)[j];
+	  debug("Pairs: %ld-%ld and %ld-%ld\n", p1->first, p1->second,
+		  p2->first, p2->second);
+	  if (p1->second < p2->second) {
+		/* Considering p1 from now on */
+		debug("    Considering: %ld-%ld\n", p1->first, p1->second);
+	    if (p1->second == from) {
+		  debug("    WILL REMOVE: %ld-%ld\n", to, from);
+	    } else {
+		  /* chain, case 1 */
+		  debug("    CHAIN(1): %ld-%ld %ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n",
+		    to, p1->second, from, *p1->dq, -2*VECTOR(a)[from]*VECTOR(a)[p1->second], p1->first, p1->second, *p1->dq-2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
+		  igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq - 2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
+		}
+		i++;
+	  } else if (p1->second == p2->second) {
+	    /* p1->first, p1->second and p2->first form a triangle */
+		debug("    Considering: %ld-%ld and %ld-%ld\n", p1->first, p1->second,
+		  p2->first, p2->second);
+		/* Update dq value */
+		debug("    TRIANGLE: %ld-%ld-%ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n",
+		  to, p1->second, from, *p1->dq, *p2->dq, p1->first, p1->second, *p1->dq+*p2->dq);
+		igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq + *p2->dq);
+        igraph_i_fastgreedy_community_remove_nei(&communities, p1->second, from);
+		i++;
+		j++;
+	  } else {
+		debug("    Considering: %ld-%ld\n", p2->first, p2->second);
+		if (p2->second == to) {
+		  debug("    WILL REMOVE: %ld-%ld\n", p2->second, p2->first);
+		} else {
+		  /* chain, case 2 */
+		  debug("    CHAIN(2): %ld %ld-%ld, newdq(%ld,%ld)=%.7f\n",
+		    to, p2->second, from, to, p2->second, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
+		  p2->opposite->second=to;
+	      /* need to re-sort community nei list `p2->second` */
+	      /* TODO: quicksort is O(n*logn), although we could do a deletion and
+	       * insertion which can be done in O(logn) if deletion is O(1) */
+	      debug("    Re-sorting community %ld\n", p2->second);
+	      igraph_vector_ptr_sort(&communities.e[p2->second].neis, igraph_i_fastgreedy_commpair_cmp);
+		  /* link from.neis[j] to the current place in to.neis if
+		   * from.neis[j] != to */
+		  p2->first=to;
+		  IGRAPH_CHECK(igraph_vector_ptr_insert(&communities.e[to].neis,i,p2));
+		  n++; i++;
+		  if (*p2->dq > *communities.e[to].maxdq->dq) {
+		    communities.e[to].maxdq = p2;
+            k=igraph_i_fastgreedy_community_list_find_in_heap(&communities, to);
+		    igraph_i_fastgreedy_community_list_sift_up(&communities, k);
+		  }
+		  igraph_i_fastgreedy_community_update_dq(&communities, p2, *p2->dq - 2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
+		}
+		j++;
+	  }
+	}
+
+	while (i<n) {
+	  p1 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i];
+	  if (p1->second == from) {
+	    debug("    WILL REMOVE: %ld-%ld\n", p1->first, from);
+	  } else {
+	    /* chain, case 1 */
+	    debug("    CHAIN(1): %ld-%ld %ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n",
+	      to, p1->second, from, *p1->dq, -2*VECTOR(a)[from]*VECTOR(a)[p1->second], p1->first, p1->second, *p1->dq-2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
+	    igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq - 2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
+	  }
+	  i++;
+	}
+	while (j<m) {
+	  p2 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[from].neis)[j];
+      if (to == p2->second) { j++; continue; }
+	  /* chain, case 2 */
+	  debug("    CHAIN(2): %ld %ld-%ld, newdq(%ld,%ld)=%.7f\n",
+	    to, p2->second, from, p1->first, p2->second, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
+	  p2->opposite->second=to;
+	  /* need to re-sort community nei list `p2->second` */
+	  /* TODO: quicksort is O(n*logn), although we could do a deletion and
+	   * insertion which can be done in O(logn) if deletion is O(1) */
+	  debug("    Re-sorting community %ld\n", p2->second);
+	  igraph_vector_ptr_sort(&communities.e[p2->second].neis, igraph_i_fastgreedy_commpair_cmp);
+	  /* link from.neis[j] to the current place in to.neis if
+	   * from.neis[j] != to */
+	  p2->first=to;
+	  IGRAPH_CHECK(igraph_vector_ptr_push_back(&communities.e[to].neis,p2));
+	  if (*p2->dq > *communities.e[to].maxdq->dq) {
+	    communities.e[to].maxdq = p2;
+        k=igraph_i_fastgreedy_community_list_find_in_heap(&communities, to);
+		igraph_i_fastgreedy_community_list_sift_up(&communities, k);
+	  }
+	  igraph_i_fastgreedy_community_update_dq(&communities, p2, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
+	  j++;
+	}
+
+	/* Now, remove community `from` from the neighbors of community `to` */
+	if (communities.no_of_communities > 2) {
+	  debug("    REMOVING: %ld-%ld\n", to, from);
+	  igraph_i_fastgreedy_community_remove_nei(&communities, to, from);
+	  i=igraph_i_fastgreedy_community_list_find_in_heap(&communities, from);
+	  igraph_i_fastgreedy_community_list_remove(&communities, i);
+    }
+	communities.e[from].maxdq=0;
+
+    /* Update community sizes */
+    communities.e[to].size += communities.e[from].size;
+    communities.e[from].size = 0;
+
+	/* record what has been merged */
+	/* igraph_vector_ptr_clear is not enough here as it won't free
+	 * the memory consumed by communities.e[from].neis. Thanks
+	 * to Tom Gregorovic for pointing that out. */
+	igraph_vector_ptr_destroy(&communities.e[from].neis);
+	if (merges) {
+	  MATRIX(*merges, no_of_joins, 0) = communities.e[to].id;
+	  MATRIX(*merges, no_of_joins, 1) = communities.e[from].id;
+	  communities.e[to].id = (igraph_integer_t) (no_of_nodes+no_of_joins);
+    }
+
+	/* Update vector a */
+	VECTOR(a)[to] += VECTOR(a)[from];
+	VECTOR(a)[from] = 0.0;
+	
+	no_of_joins++;
+  }
+  /* TODO: continue merging when some isolated communities remained. Always
+   * joining the communities with the least number of nodes results in the
+   * smallest decrease in modularity every step. Now we're simply deleting
+   * the excess rows from the merge matrix */
+  if (no_of_joins < total_joins) {
+    long int *ivec;
+    ivec=igraph_Calloc(igraph_matrix_nrow(merges), long int);
+    if (ivec == 0)
+      IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(free, ivec);
+    for (i=0; i<no_of_joins; i++) ivec[i] = i+1;
+    igraph_matrix_permdelete_rows(merges, ivec, total_joins-no_of_joins);
+    free(ivec);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  IGRAPH_PROGRESS("fast greedy community detection", 100.0, 0);
+
+  if (modularity) {
+	VECTOR(*modularity)[no_of_joins] = q;
+	igraph_vector_resize(modularity, no_of_joins+1);
+  }
+
+  debug("Freeing memory\n");
+  free(pairs);
+  free(dq);
+  igraph_i_fastgreedy_community_list_destroy(&communities);
+  igraph_vector_destroy(&a);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  if (membership) {
+    long int m=igraph_vector_which_max(modularity);
+    IGRAPH_CHECK(igraph_community_to_membership(merges,
+						(igraph_integer_t) no_of_nodes, 
+						/*steps=*/ (igraph_integer_t) m,
+						membership, 
+						/*csize=*/ 0));
+  }
+
+  return 0;
+}
+
+#ifdef IGRAPH_FASTCOMM_DEBUG
+#undef IGRAPH_FASTCOMM_DEBUG
+#endif
+
+
diff --git a/src/feedback_arc_set.c b/src/feedback_arc_set.c
new file mode 100644
index 0000000..81b0c4a
--- /dev/null
+++ b/src/feedback_arc_set.c
@@ -0,0 +1,643 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   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
+
+*/
+
+#include "igraph_centrality.h"
+#include "igraph_components.h"
+#include "igraph_constants.h"
+#include "igraph_datatype.h"
+#include "igraph_dqueue.h"
+#include "igraph_error.h"
+#include "igraph_glpk_support.h"
+#include "igraph_interface.h"
+#include "igraph_memory.h"
+#include "igraph_structural.h"
+#include "igraph_types.h"
+#include "igraph_visitor.h"
+
+int igraph_i_feedback_arc_set_ip(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights);
+
+
+/**
+ * \ingroup structural
+ * \function igraph_feedback_arc_set
+ * \brief Calculates a feedback arc set of the graph using different
+ *        algorithms.
+ *
+ * </para><para>
+ * A feedback arc set is a set of edges whose removal makes the graph acyclic.
+ * We are usually interested in \em minimum feedback arc sets, i.e. sets of edges
+ * whose total weight is minimal among all the feedback arc sets.
+ *
+ * </para><para>
+ * For undirected graphs, the problem is simple: one has to find a maximum weight
+ * spanning tree and then remove all the edges not in the spanning tree. For directed
+ * graphs, this is an NP-hard problem, and various heuristics are usually used to
+ * find an approximate solution to the problem. This function implements a few of
+ * these heuristics.
+ *
+ * \param graph  The graph object.
+ * \param result An initialized vector, the result will be returned here.
+ * \param weights Weight vector or NULL if no weights are specified.
+ * \param algo   The algorithm to use to solve the problem if the graph is directed.
+ *        Possible values:
+ *        \clist
+ *        \cli IGRAPH_FAS_EXACT_IP
+ *          Finds a \em minimum feedback arc set using integer programming (IP).
+ *          The complexity of this algorithm is exponential of course.
+ *        \cli IGRAPH_FAS_APPROX_EADES
+ *          Finds a feedback arc set using the heuristic of Eades, Lin and
+ *          Smyth (1993). This is guaranteed to be smaller than |E|/2 - |V|/6,
+ *          and it is linear in the number of edges (i.e. O(|E|)).
+ *          For more details, see Eades P, Lin X and Smyth WF: A fast and effective
+ *          heuristic for the feedback arc set problem. In: Proc Inf Process Lett
+ *          319-323, 1993.
+ *        \endclist
+ *
+ * \return Error code:
+ *         \c IGRAPH_EINVAL if an unknown method was specified or the weight vector
+ *            is invalid.
+ *
+ * \example examples/simple/igraph_feedback_arc_set.c
+ * \example examples/simple/igraph_feedback_arc_set_ip.c
+ *
+ * Time complexity: depends on \p algo, see the time complexities there.
+ */
+int igraph_feedback_arc_set(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights, igraph_fas_algorithm_t algo) {
+
+  if (weights && igraph_vector_size(weights) < igraph_ecount(graph))
+    IGRAPH_ERROR("cannot calculate feedback arc set, weight vector too short",
+      IGRAPH_EINVAL);
+
+  if (!igraph_is_directed(graph))
+    return igraph_i_feedback_arc_set_undirected(graph, result, weights, 0);
+
+  switch (algo) {
+    case IGRAPH_FAS_EXACT_IP:
+      return igraph_i_feedback_arc_set_ip(graph, result, weights);
+
+    case IGRAPH_FAS_APPROX_EADES:
+      return igraph_i_feedback_arc_set_eades(graph, result, weights, 0);
+
+    default:
+      IGRAPH_ERROR("Invalid algorithm", IGRAPH_EINVAL);
+  }
+}
+
+/**
+ * Solves the feedback arc set problem for undirected graphs.
+ */
+int igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights, igraph_vector_t *layering) {
+  igraph_vector_t edges;
+  long int i, j, n, no_of_nodes = igraph_vcount(graph);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_nodes-1);
+  if (weights) {
+    /* Find a maximum weight spanning tree. igraph has a routine for minimum
+     * spanning trees, so we negate the weights */
+    igraph_vector_t vcopy;
+    IGRAPH_CHECK(igraph_vector_copy(&vcopy, weights));
+    IGRAPH_FINALLY(igraph_vector_destroy, &vcopy);
+    igraph_vector_scale(&vcopy, -1);
+    IGRAPH_CHECK(igraph_minimum_spanning_tree(graph, &edges, &vcopy));
+    igraph_vector_destroy(&vcopy);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    /* Any spanning tree will do */
+    IGRAPH_CHECK(igraph_minimum_spanning_tree(graph, &edges, 0));
+  }
+
+  /* Now we have a bunch of edges that constitute a spanning forest. We have
+   * to come up with a layering, and return those edges that are not in the
+   * spanning forest */
+  igraph_vector_sort(&edges);
+  IGRAPH_CHECK(igraph_vector_push_back(&edges, -1));  /* guard element */
+
+  if (result != 0) {
+    igraph_vector_clear(result);
+    n = igraph_ecount(graph);
+    for (i = 0, j = 0; i < n; i++) {
+      if (i == VECTOR(edges)[j]) {
+        j++;
+        continue;
+      }
+      IGRAPH_CHECK(igraph_vector_push_back(result, i));
+    }
+  }
+
+  if (layering != 0) {
+    igraph_vector_t degrees;
+    igraph_vector_t roots;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&degrees, no_of_nodes);
+    IGRAPH_VECTOR_INIT_FINALLY(&roots, no_of_nodes);
+
+    IGRAPH_CHECK(igraph_strength(graph, &degrees, igraph_vss_all(),
+        IGRAPH_ALL, 0, weights));
+    IGRAPH_CHECK((int) igraph_vector_qsort_ind(&degrees, &roots, 
+					       /* descending = */ 1));
+    IGRAPH_CHECK(igraph_bfs(graph,
+          /* root = */ 0,
+          /* roots = */ &roots,
+          /* mode = */ IGRAPH_OUT,
+          /* unreachable = */ 0,
+          /* restricted = */ 0,
+          /* order = */ 0,
+          /* rank = */ 0,
+          /* father = */ 0,
+          /* pred = */ 0,
+          /* succ = */ 0,
+          /* dist = */ layering,
+          /* callback = */ 0,
+          /* extra = */ 0));
+
+    igraph_vector_destroy(&degrees);
+    igraph_vector_destroy(&roots);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Solves the feedback arc set problem using the heuristics of Eades et al.
+ */
+int igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights, igraph_vector_t *layers) {
+  long int i, j, k, v, eid, no_of_nodes=igraph_vcount(graph), nodes_left;
+  igraph_dqueue_t sources, sinks;
+  igraph_vector_t neis;
+  igraph_vector_t indegrees, outdegrees;
+  igraph_vector_t instrengths, outstrengths;
+  long int* ordering;
+  long int order_next_pos = 0, order_next_neg = -1;
+  igraph_real_t diff, maxdiff;
+
+  ordering = igraph_Calloc(no_of_nodes, long int);
+  IGRAPH_FINALLY(igraph_free, ordering);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&indegrees, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdegrees, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&instrengths, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&outstrengths, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_dqueue_init(&sources, 0));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &sources);
+  IGRAPH_CHECK(igraph_dqueue_init(&sinks, 0));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &sinks);
+
+  IGRAPH_CHECK(igraph_degree(graph, &indegrees, igraph_vss_all(), IGRAPH_IN, 0));
+  IGRAPH_CHECK(igraph_degree(graph, &outdegrees, igraph_vss_all(), IGRAPH_OUT, 0));
+
+  if (weights) {
+    IGRAPH_CHECK(igraph_strength(graph, &instrengths, igraph_vss_all(), IGRAPH_IN, 0, weights));
+    IGRAPH_CHECK(igraph_strength(graph, &outstrengths, igraph_vss_all(), IGRAPH_OUT, 0, weights));
+  } else {
+    IGRAPH_CHECK(igraph_vector_update(&instrengths, &indegrees));
+    IGRAPH_CHECK(igraph_vector_update(&outstrengths, &outdegrees));
+  }
+
+  /* Find initial sources and sinks */
+  nodes_left = no_of_nodes;
+  for (i = 0; i < no_of_nodes; i++) {
+    if (VECTOR(indegrees)[i] == 0) {
+      if (VECTOR(outdegrees)[i] == 0) {
+        /* Isolated vertex, we simply ignore it */
+        nodes_left--;
+        ordering[i] = order_next_pos++;
+        VECTOR(indegrees)[i] = VECTOR(outdegrees)[i] = -1;
+      } else {
+        /* This is a source */
+        igraph_dqueue_push(&sources, i);
+      }
+    } else if (VECTOR(outdegrees)[i] == 0) {
+      /* This is a sink */
+      igraph_dqueue_push(&sinks, i);
+    }
+  }
+
+  /* While we have any nodes left... */
+  while (nodes_left > 0) {
+    /* (1) Remove the sources one by one */
+    while (!igraph_dqueue_empty(&sources)) {
+      i=(long)igraph_dqueue_pop(&sources);
+      /* Add the node to the ordering */
+      ordering[i] = order_next_pos++;
+      /* Exclude the node from further searches */
+      VECTOR(indegrees)[i] = VECTOR(outdegrees)[i] = -1;
+      /* Get the neighbors and decrease their degrees */
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) i,
+				   IGRAPH_OUT));
+      j = igraph_vector_size(&neis);
+      for (i = 0; i < j; i++) {
+        eid = (long int) VECTOR(neis)[i];
+        k = IGRAPH_TO(graph, eid);
+        if (VECTOR(indegrees)[k] <= 0) {
+          /* Already removed, continue */
+          continue;
+        }
+        VECTOR(indegrees)[k]--;
+        VECTOR(instrengths)[k] -= (weights ? VECTOR(*weights)[eid] : 1.0);
+        if (VECTOR(indegrees)[k] == 0)
+          IGRAPH_CHECK(igraph_dqueue_push(&sources, k));
+      }
+      nodes_left--;
+    }
+
+    /* (2) Remove the sinks one by one */
+    while (!igraph_dqueue_empty(&sinks)) {
+      i=(long)igraph_dqueue_pop(&sinks);
+      /* Maybe the vertex became sink and source at the same time, hence it
+       * was already removed in the previous iteration. Check it. */
+      if (VECTOR(indegrees)[i] < 0)
+        continue;
+      /* Add the node to the ordering */
+      ordering[i] = order_next_neg--;
+      /* Exclude the node from further searches */
+      VECTOR(indegrees)[i] = VECTOR(outdegrees)[i] = -1;
+      /* Get the neighbors and decrease their degrees */
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) i, 
+				   IGRAPH_IN));
+      j = igraph_vector_size(&neis);
+      for (i = 0; i < j; i++) {
+        eid = (long int) VECTOR(neis)[i];
+        k = IGRAPH_FROM(graph, eid);
+        if (VECTOR(outdegrees)[k] <= 0) {
+          /* Already removed, continue */
+          continue;
+        }
+        VECTOR(outdegrees)[k]--;
+        VECTOR(outstrengths)[k] -= (weights ? VECTOR(*weights)[eid] : 1.0);
+        if (VECTOR(outdegrees)[k] == 0)
+          IGRAPH_CHECK(igraph_dqueue_push(&sinks, k));
+      }
+      nodes_left--;
+    }
+
+    /* (3) No more sources or sinks. Find the node with the largest
+     * difference between its out-strength and in-strength */
+    v = -1; maxdiff = -IGRAPH_INFINITY;
+    for (i = 0; i < no_of_nodes; i++) {
+      if (VECTOR(outdegrees)[i] < 0)
+        continue;
+      diff = VECTOR(outstrengths)[i]-VECTOR(instrengths)[i];
+      if (diff > maxdiff) {
+        maxdiff = diff;
+        v = i;
+      }
+    }
+    if (v >= 0) {
+      /* Remove vertex v */
+      ordering[v] = order_next_pos++;
+      /* Remove outgoing edges */
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) v, 
+				   IGRAPH_OUT));
+      j = igraph_vector_size(&neis);
+      for (i = 0; i < j; i++) {
+        eid = (long int) VECTOR(neis)[i];
+        k = IGRAPH_TO(graph, eid);
+        if (VECTOR(indegrees)[k] <= 0) {
+          /* Already removed, continue */
+          continue;
+        }
+        VECTOR(indegrees)[k]--;
+        VECTOR(instrengths)[k] -= (weights ? VECTOR(*weights)[eid] : 1.0);
+        if (VECTOR(indegrees)[k] == 0)
+          IGRAPH_CHECK(igraph_dqueue_push(&sources, k));
+      }
+      /* Remove incoming edges */
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) v,
+				   IGRAPH_IN));
+      j = igraph_vector_size(&neis);
+      for (i = 0; i < j; i++) {
+        eid = (long int) VECTOR(neis)[i];
+        k = IGRAPH_FROM(graph, eid);
+        if (VECTOR(outdegrees)[k] <= 0) {
+          /* Already removed, continue */
+          continue;
+        }
+        VECTOR(outdegrees)[k]--;
+        VECTOR(outstrengths)[k] -= (weights ? VECTOR(*weights)[eid] : 1.0);
+        if (VECTOR(outdegrees)[k] == 0 && VECTOR(indegrees)[k] > 0)
+          IGRAPH_CHECK(igraph_dqueue_push(&sinks, k));
+      }
+
+      VECTOR(outdegrees)[v] = -1;
+      VECTOR(indegrees)[v] = -1;
+      nodes_left--;
+    }
+  }
+
+  igraph_dqueue_destroy(&sinks);
+  igraph_dqueue_destroy(&sources);
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&outstrengths);
+  igraph_vector_destroy(&instrengths);
+  igraph_vector_destroy(&outdegrees);
+  igraph_vector_destroy(&indegrees);
+  IGRAPH_FINALLY_CLEAN(7);
+
+  /* Tidy up the ordering */
+  for (i = 0; i < no_of_nodes; i++) {
+    if (ordering[i] < 0)
+      ordering[i] += no_of_nodes;
+  }
+
+  /* Find the feedback edges based on the ordering */
+  if (result != 0) {
+    igraph_vector_clear(result);
+    j = igraph_ecount(graph);
+    for (i = 0; i < j; i++) {
+      long int from = IGRAPH_FROM(graph, i), to = IGRAPH_TO(graph, i);
+      if (from == to || ordering[from] > ordering[to])
+        IGRAPH_CHECK(igraph_vector_push_back(result, i));
+    }
+  }
+
+  /* If we have also requested a layering, return that as well */
+  if (layers != 0) {
+    igraph_vector_t ranks;
+    igraph_vector_long_t order_vec;
+
+    IGRAPH_CHECK(igraph_vector_resize(layers, no_of_nodes));
+    igraph_vector_null(layers);
+
+    igraph_vector_long_view(&order_vec, ordering, no_of_nodes);
+
+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&ranks, 0);
+
+    IGRAPH_CHECK((int) igraph_vector_long_qsort_ind(&order_vec, &ranks, 0));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      long int from = (long int) VECTOR(ranks)[i];
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) from, 
+				    IGRAPH_OUT));
+      k = igraph_vector_size(&neis);
+      for (j = 0; j < k; j++) {
+        long int to = (long int) VECTOR(neis)[j];
+        if (from == to)
+          continue;
+        if (ordering[from] > ordering[to])
+          continue;
+        if (VECTOR(*layers)[to] < VECTOR(*layers)[from] + 1)
+          VECTOR(*layers)[to] = VECTOR(*layers)[from] + 1;
+      }
+    }
+
+    igraph_vector_destroy(&neis);
+    igraph_vector_destroy(&ranks);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  /* Free the ordering vector */
+  igraph_free(ordering);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Solves the feedback arc set problem using integer programming.
+ */
+int igraph_i_feedback_arc_set_ip(const igraph_t *graph, igraph_vector_t *result,
+        const igraph_vector_t *weights) {
+#ifndef HAVE_GLPK
+  IGRAPH_ERROR("GLPK is not available", IGRAPH_UNIMPLEMENTED);    
+#else
+
+  igraph_integer_t no_of_components;
+  igraph_integer_t no_of_vertices = igraph_vcount(graph);
+  igraph_integer_t no_of_edges = igraph_ecount(graph);
+  igraph_vector_t membership, ordering, vertex_remapping;
+  igraph_vector_ptr_t vertices_by_components, edges_by_components;
+  long int i, j, k, l, m, n, from, to;
+  igraph_real_t weight;
+  glp_prob *ip;
+  glp_iocp parm;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&membership, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&ordering, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vertex_remapping, no_of_vertices);
+  
+  igraph_vector_clear(result);
+
+  /* Decompose the graph into connected components */
+  IGRAPH_CHECK(igraph_clusters(graph, &membership, 0, &no_of_components,
+        IGRAPH_WEAK));
+
+  /* Construct vertex and edge lists for each of the components */
+  IGRAPH_CHECK(igraph_vector_ptr_init(&vertices_by_components, no_of_components));
+  IGRAPH_CHECK(igraph_vector_ptr_init(&edges_by_components, no_of_components));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &vertices_by_components);
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &edges_by_components);
+  for (i = 0; i < no_of_components; i++) {
+    igraph_vector_t* vptr;
+    vptr = igraph_Calloc(1, igraph_vector_t);
+    if (vptr == 0)
+      IGRAPH_ERROR("cannot calculate feedback arc set using IP", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(free, vptr);
+    IGRAPH_CHECK(igraph_vector_init(vptr, 0));
+    IGRAPH_FINALLY_CLEAN(1);
+    VECTOR(vertices_by_components)[i] = vptr;
+  }
+  IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&vertices_by_components, igraph_vector_destroy);
+  for (i = 0; i < no_of_components; i++) {
+    igraph_vector_t* vptr;
+    vptr = igraph_Calloc(1, igraph_vector_t);
+    if (vptr == 0)
+      IGRAPH_ERROR("cannot calculate feedback arc set using IP", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(free, vptr);
+    IGRAPH_CHECK(igraph_vector_init(vptr, 0));
+    IGRAPH_FINALLY_CLEAN(1);
+    VECTOR(edges_by_components)[i] = vptr;
+  }
+  IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&edges_by_components, igraph_vector_destroy);
+  for (i = 0; i < no_of_vertices; i++) {
+    j = (long int) VECTOR(membership)[i];
+    IGRAPH_CHECK(igraph_vector_push_back(VECTOR(vertices_by_components)[j], i));
+  }
+  for (i = 0; i < no_of_edges; i++) {
+    j = (long int) VECTOR(membership)[(long)IGRAPH_FROM(graph, i)];
+    IGRAPH_CHECK(igraph_vector_push_back(VECTOR(edges_by_components)[j], i));
+  }
+
+#define VAR2IDX(i, j) (i*(n-1)+j-(i+1)*i/2)
+
+  /* Configure GLPK */
+  glp_term_out(GLP_OFF);
+  glp_init_iocp(&parm);
+  parm.br_tech = GLP_BR_DTH;
+  parm.bt_tech = GLP_BT_BLB;
+  parm.pp_tech = GLP_PP_ALL;
+  parm.presolve = GLP_ON;
+  parm.binarize = GLP_OFF;
+  parm.cb_func = igraph_i_glpk_interruption_hook;
+
+  /* Solve an IP for feedback arc sets in each of the components */
+  for (i = 0; i < no_of_components; i++) {
+    igraph_vector_t* vertices_in_comp = (igraph_vector_t*)VECTOR(vertices_by_components)[i];
+    igraph_vector_t* edges_in_comp = (igraph_vector_t*)VECTOR(edges_by_components)[i];
+
+    /*
+     * Let x_ij denote whether layer(i) < layer(j).
+     *
+     * The standard formulation of the problem is as follows:
+     *
+     * max sum_{i,j} w_ij x_ij
+     *
+     * subject to
+     *
+     * (1) x_ij + x_ji = 1   (i.e. either layer(i) < layer(j) or layer(i) > layer(j))
+     *     for all i < j
+     * (2) x_ij + x_jk + x_ki <= 2 for all i < j, i < k, j != k
+     *
+     * Note that x_ij = 1 implies that x_ji = 0 and vice versa; in other words,
+     * x_ij = 1 - x_ji. Thus, we can get rid of the (1) constraints and half of the
+     * x_ij variables (where j < i) if we rewrite constraints of type (2) as follows:
+     *
+     * (2a) x_ij + x_jk - x_ik <= 1 for all i < j, i < k, j < k
+     * (2b) x_ij - x_kj - x_ik <= 0 for all i < j, i < k, j > k
+     *
+     * The goal function then becomes:
+     *
+     * max sum_{i<j} (w_ij-w_ji) x_ij
+     */
+    n = igraph_vector_size(vertices_in_comp);
+    ip = glp_create_prob();
+    IGRAPH_FINALLY(glp_delete_prob, ip);
+    glp_set_obj_dir(ip, GLP_MAX);
+
+    /* Construct a mapping from vertex IDs to the [0; n-1] range */
+    for (j = 0; j < n; j++)
+      VECTOR(vertex_remapping)[(long)VECTOR(*vertices_in_comp)[j]] = j;
+
+    /* Set up variables */
+    k = n*(n-1)/2;
+    glp_add_cols(ip, (int) k);
+    for (j = 1; j <= k; j++)
+      glp_set_col_kind(ip, (int) j, GLP_BV);
+
+    /* Set up coefficients in the goal function */
+    k = igraph_vector_size(edges_in_comp);
+    for (j = 0; j < k; j++) {
+      l = (long int) VECTOR(*edges_in_comp)[j];
+      from = (long int) VECTOR(vertex_remapping)[(long)IGRAPH_FROM(graph, l)];
+      to = (long int) VECTOR(vertex_remapping)[(long)IGRAPH_TO(graph, l)];
+      if (from == to)
+        continue;
+
+      weight = weights ? VECTOR(*weights)[l] : 1;
+
+      if (from < to) {
+        l = VAR2IDX(from, to);
+        glp_set_obj_coef(ip, (int) l, glp_get_obj_coef(ip, (int) l) + weight);
+      } else {
+        l = VAR2IDX(to, from);
+        glp_set_obj_coef(ip, (int) l, glp_get_obj_coef(ip, (int) l) - weight);
+      }
+    }
+
+    /* Add constraints */
+    glp_add_rows(ip, (int)(n*(n-1)/2 + n*(n-1)*(n-2)/3));
+    m = 1;
+    for (j = 0; j < n; j++) {
+      int ind[4];
+      double val[4] = {0, 1, 1, -1};
+      for (k = j+1; k < n; k++) {
+        ind[1] = (int) VAR2IDX(j, k);
+        /* Type (2a) */
+        val[2] = 1;
+        for (l = k+1; l < n; l++, m++) {
+          ind[2] = (int) VAR2IDX(k, l);
+          ind[3] = (int) VAR2IDX(j, l);
+          glp_set_row_bnds(ip, (int) m, GLP_UP, 1, 1);
+          glp_set_mat_row(ip, (int) m, 3, ind, val);
+        }
+        /* Type (2b) */
+        val[2] = -1;
+        for (l = j+1; l < k; l++, m++) {
+          ind[2] = (int) VAR2IDX(l, k);
+          ind[3] = (int) VAR2IDX(j, l);
+          glp_set_row_bnds(ip, (int) m, GLP_UP, 0, 0);
+          glp_set_mat_row(ip, (int) m, 3, ind, val);
+        }
+      }
+    }
+
+    /* Solve the problem */
+    IGRAPH_GLPK_CHECK(glp_intopt(ip, &parm), "Feedback arc set using IP failed");
+
+    /* Find the ordering of the vertices */
+    IGRAPH_CHECK(igraph_vector_resize(&ordering, n));
+    igraph_vector_null(&ordering);
+    m = n * (n-1) / 2;
+    j = 0; k = 1;
+    for (l = 1; l <= m; l++) {
+      /* variable l always corresponds to the (j, k) vertex pair */
+      /* printf("(%ld, %ld) = %g\n", i, j, glp_mip_col_val(ip, l)); */
+      if (glp_mip_col_val(ip, (int) l) > 0) {
+        /* j comes earlier in the ordering than k */
+        VECTOR(ordering)[j]++;
+      } else {
+        /* k comes earlier in the ordering than j */
+        VECTOR(ordering)[k]++;
+      }
+      k++;
+      if (k == n) {
+        j++; k = j+1;
+      }
+    }
+
+    /* Find the feedback edges */
+    k = igraph_vector_size(edges_in_comp);
+    for (j = 0; j < k; j++) {
+      l = (long int) VECTOR(*edges_in_comp)[j];
+      from = (long int) VECTOR(vertex_remapping)[(long)IGRAPH_FROM(graph, l)];
+      to = (long int) VECTOR(vertex_remapping)[(long)IGRAPH_TO(graph, l)];
+      if (from == to || VECTOR(ordering)[from] < VECTOR(ordering)[to])
+        IGRAPH_CHECK(igraph_vector_push_back(result, l));
+    }
+
+    /* Clean up */
+    glp_delete_prob(ip);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_ptr_destroy_all(&vertices_by_components);
+  igraph_vector_ptr_destroy_all(&edges_by_components);
+  igraph_vector_destroy(&vertex_remapping);
+  igraph_vector_destroy(&ordering);
+  igraph_vector_destroy(&membership);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return IGRAPH_SUCCESS;
+#endif
+}
+
diff --git a/src/flow.c b/src/flow.c
new file mode 100644
index 0000000..a266aa7
--- /dev/null
+++ b/src/flow.c
@@ -0,0 +1,2476 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_flow.h"
+#include "igraph_error.h"
+#include "igraph_memory.h"
+#include "igraph_constants.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_conversion.h"
+#include "igraph_constructors.h"
+#include "igraph_progress.h"
+#include "igraph_structural.h"
+#include "igraph_components.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+#include "igraph_math.h"
+#include "igraph_dqueue.h"
+#include "igraph_visitor.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_topology.h"
+
+#include <limits.h>
+#include <stdio.h>
+
+/*
+ * Some general remarks about the functions in this file.
+ *
+ * The following measures can be calculated:
+ * ( 1) s-t maximum flow value, directed graph
+ * ( 2) s-t maximum flow value, undirected graph
+ * ( 3) s-t maximum flow, directed graph
+ * ( 4) s-t maximum flow, undirected graph
+ * ( 5) s-t minimum cut value, directed graph
+ * ( 6) s-t minimum cut value, undirected graph
+ * ( 7) minimum cut value, directed graph
+ * ( 8) minimum cut value, undirected graph
+ * ( 9) s-t minimum cut, directed graph
+ * (10) s-t minimum cut, undirected graph
+ * (11) minimum cut, directed graph
+ * (12) minimum cut, undirected graph
+ * (13) s-t edge connectivity, directed graph
+ * (14) s-t edge connectivity, undirected graph
+ * (15) edge connectivity, directed graph
+ * (16) edge connectivity, undirected graph
+ * (17) s-t vertex connectivity, directed graph
+ * (18) s-t vertex connectivity, undirected graph
+ * (19) vertex connectivity, directed graph
+ * (20) vertex connectivity, undirected graph
+ * (21) s-t number of edge disjoint paths, directed graph
+ * (22) s-t number of edge disjoint paths, undirected graph
+ * (23) s-t number of vertex disjoint paths, directed graph
+ * (24) s-t number of vertex disjoint paths, undirected graph
+ * (25) graph adhesion, directed graph
+ * (26) graph adhesion, undirected graph
+ * (27) graph cohesion, directed graph
+ * (28) graph cohesion, undirected graph
+ * 
+ * This is how they are calculated:
+ * ( 1) igraph_maxflow_value, calls igraph_maxflow.
+ * ( 2) igraph_maxflow_value, calls igraph_maxflow, this calls
+ *      igraph_i_maxflow_undirected. This transforms the graph into a
+ *      directed graph, including two mutual edges instead of every
+ *      undirected edge, then igraph_maxflow is called again with the
+ *      directed graph.
+ * ( 3) igraph_maxflow, does the push-relabel algorithm, optionally
+ *      calculates the cut, the partitions and the flow itself.
+ * ( 4) igraph_maxflow calls igraph_i_maxflow_undirected, this converts 
+ *      the undirected graph into a directed one, adding two mutual edges
+ *      for each undirected edge, then igraph_maxflow is called again, 
+ *      with the directed graph. After igraph_maxflow returns, we need 
+ *      to edit the flow (and the cut) to make it sense for the
+ *      original graph.
+ * ( 5) igraph_st_mincut_value, we just call igraph_maxflow_value
+ * ( 6) igraph_st_mincut_value, we just call igraph_maxflow_value
+ * ( 7) igraph_mincut_value, we call igraph_maxflow_value (|V|-1)*2
+ *      times, from vertex 0 to all other vertices and from all other
+ *      vertices to vertex 0
+ * ( 8) We call igraph_i_mincut_value_undirected, that calls 
+ *      igraph_i_mincut_undirected with partition=partition2=cut=NULL
+ *      The Stoer-Wagner algorithm is used.
+ * ( 9) igraph_st_mincut, just calls igraph_maxflow.
+ * (10) igraph_st_mincut, just calls igraph_maxflow.
+ * (11) igraph_mincut, calls igraph_i_mincut_directed, which runs 
+ *      the maximum flow algorithm 2(|V|-1) times, from vertex zero to
+ *      and from all other vertices and stores the smallest cut.
+ * (12) igraph_mincut, igraph_i_mincut_undirected is called, 
+ *      this is the Stoer-Wagner algorithm
+ * (13) We just call igraph_maxflow_value, back to (1)
+ * (14) We just call igraph_maxflow_value, back to (2)
+ * (15) We just call igraph_mincut_value (possibly after some basic
+ *      checks). Back to (7)
+ * (16) We just call igraph_mincut_value (possibly after some basic
+ *      checks). Back to (8).
+ * (17) We call igraph_i_st_vertex_connectivity_directed.
+ *      That creates a new graph with 2*|V| vertices and smartly chosen
+ *      edges, so that the s-t edge connectivity of this graph is the
+ *      same as the s-t vertex connectivity of the original graph.
+ *      So finally it calls igraph_maxflow_value, go to (1)
+ * (18) We call igraph_i_st_vertex_connectivity_undirected.
+ *      We convert the graph to a directed one,
+ *      IGRAPH_TO_DIRECTED_MUTUAL method. Then we call 
+ *      igraph_i_st_vertex_connectivity_directed, see (17).
+ * (19) We call igraph_i_vertex_connectivity_directed.
+ *      That calls igraph_st_vertex_connectivity for all pairs of
+ *      vertices. Back to (17).
+ * (20) We call igraph_i_vertex_connectivity_undirected.
+ *      That converts the graph into a directed one
+ *      (IGRAPH_TO_DIRECTED_MUTUAL) and calls the directed version,
+ *      igraph_i_vertex_connectivity_directed, see (19).
+ * (21) igraph_edge_disjoint_paths, we just call igraph_maxflow_value, (1).
+ * (22) igraph_edge_disjoint_paths, we just call igraph_maxflow_value, (2).
+ * (23) igraph_vertex_disjoint_paths, if there is a connection between
+ *      the two vertices, then we remove that (or all of them if there
+ *      are many), as this could mess up vertex connectivity
+ *      calculation. The we call
+ *      igraph_i_st_vertex_connectivity_directed, see (19).
+ * (24) igraph_vertex_disjoint_paths, if there is a connection between
+ *      the two vertices, then we remove that (or all of them if there
+ *      are many), as this could mess up vertex connectivity
+ *      calculation. The we call
+ *      igraph_i_st_vertex_connectivity_undirected, see (20).
+ * (25) We just call igraph_edge_connectivity, see (15). 
+ * (26) We just call igraph_edge_connectivity, see (16).
+ * (27) We just call igraph_vertex_connectivity, see (19).
+ * (28) We just call igraph_vertex_connectivity, see (20).
+ */
+
+/*
+ * This is an internal function that calculates the maximum flow value
+ * on undirected graphs, either for an s-t vertex pair or for the
+ * graph (i.e. all vertex pairs). 
+ * 
+ * It does it by converting the undirected graph to a corresponding
+ * directed graph, including reciprocal directed edges instead of each
+ * undirected edge.
+ */
+
+int igraph_i_maxflow_undirected(const igraph_t *graph, 
+				igraph_real_t *value,
+				igraph_vector_t *flow,
+				igraph_vector_t *cut,
+				igraph_vector_t *partition,
+				igraph_vector_t *partition2,
+				igraph_integer_t source, 
+				igraph_integer_t target,
+				const igraph_vector_t *capacity,
+				igraph_maxflow_stats_t *stats) {
+  igraph_integer_t no_of_edges=(igraph_integer_t) igraph_ecount(graph);
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_vector_t edges;
+  igraph_vector_t newcapacity;
+  igraph_t newgraph;
+  long int i;
+  
+  /* We need to convert this to directed by hand, since we need to be
+     sure that the edge ids will be handled properly to build the new
+     capacity vector. */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&newcapacity, no_of_edges*2);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*4));
+  IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
+  IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4));
+  for (i=0; i<no_of_edges; i++) {
+    VECTOR(edges)[no_of_edges*2+i*2] = VECTOR(edges)[i*2+1];
+    VECTOR(edges)[no_of_edges*2+i*2+1] = VECTOR(edges)[i*2];
+    VECTOR(newcapacity)[i] = VECTOR(newcapacity)[no_of_edges+i] = 
+      capacity ? VECTOR(*capacity)[i] : 1.0;
+  }
+  
+  IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED));
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+  
+  IGRAPH_CHECK(igraph_maxflow(&newgraph, value, flow, cut, partition,
+			      partition2, source, target, &newcapacity, stats));
+
+  if (cut) {
+    long int i, cs=igraph_vector_size(cut);
+    for (i=0; i<cs; i++) {
+      if (VECTOR(*cut)[i] >= no_of_edges) {
+	VECTOR(*cut)[i] -= no_of_edges;
+      }
+    }
+  }
+  
+  /* The flow has one non-zero value for each real-nonreal edge pair,
+     by definition, we convert it to a positive-negative vector. If
+     for an edge the flow is negative that means that it is going
+     from the bigger vertex id to the smaller one. For positive
+     values the direction is the opposite. */
+  if (flow) {
+    long int i;
+    for (i=0; i<no_of_edges; i++) {
+      VECTOR(*flow)[i] -= VECTOR(*flow)[i+no_of_edges];
+    }
+    IGRAPH_CHECK(igraph_vector_resize(flow, no_of_edges));
+  }
+  
+  igraph_destroy(&newgraph);
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&newcapacity);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+#define FIRST(i)       (VECTOR(*first)[(i)])
+#define LAST(i)        (VECTOR(*first)[(i)+1])
+#define CURRENT(i)     (VECTOR(*current)[(i)])
+#define RESCAP(i)      (VECTOR(*rescap)[(i)])
+#define REV(i)         (VECTOR(*rev)[(i)])
+#define HEAD(i)        (VECTOR(*to)[(i)])
+#define EXCESS(i)      (VECTOR(*excess)[(i)])
+#define DIST(i)        (VECTOR(*distance)[(i)])
+#define DISCHARGE(v)   (igraph_i_mf_discharge((v), &current, &first, &rescap, \
+					      &to, &distance, &excess,	      \
+					      no_of_nodes, source, target,    \
+					      &buckets, &ibuckets,	      \
+					      &rev, stats, &npushsince,       \
+					      &nrelabelsince))
+#define PUSH(v,e,n)    (igraph_i_mf_push((v), (e), (n), current, rescap,      \
+					 excess, target, source, buckets,     \
+					 ibuckets, distance, rev, stats,      \
+					 npushsince))
+#define RELABEL(v)     (igraph_i_mf_relabel((v), no_of_nodes, distance,	      \
+					    first, rescap, to, current,       \
+					    stats, nrelabelsince))
+#define GAP(b)         (igraph_i_mf_gap((b), stats, buckets, ibuckets,        \
+					no_of_nodes, distance))
+#define BFS()          (igraph_i_mf_bfs(&bfsq, source, target, no_of_nodes,   \
+					&buckets, &ibuckets, &distance,       \
+					&first,	&current, &to, &excess,       \
+					&rescap, &rev))
+
+void igraph_i_mf_gap(long int b, igraph_maxflow_stats_t *stats,
+		     igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets,
+		     long int no_of_nodes,
+		     igraph_vector_long_t *distance) {
+
+  long int bo;
+  (stats->nogap)++;
+  for (bo=b+1; bo <= no_of_nodes; bo++) {
+    while (!igraph_dbuckets_empty_bucket(ibuckets, bo)) {
+      long int n=igraph_dbuckets_pop(ibuckets, bo);
+      (stats->nogapnodes)++;
+      DIST(n)=no_of_nodes;
+    }
+  }
+}
+
+void igraph_i_mf_relabel(long int v, long int no_of_nodes,
+			 igraph_vector_long_t *distance,
+			 igraph_vector_long_t *first,
+			 igraph_vector_t *rescap, igraph_vector_long_t *to,
+			 igraph_vector_long_t *current,
+			 igraph_maxflow_stats_t *stats, int *nrelabelsince) {
+
+    long int min=no_of_nodes;
+    long int k, l, min_edge=0;
+    (stats->norelabel)++; (*nrelabelsince)++;
+    DIST(v)=no_of_nodes;
+    for (k=FIRST(v), l=LAST(v); k<l; k++) {
+      if (RESCAP(k) > 0 && DIST(HEAD(k)) < min) {
+	min=DIST(HEAD(k));
+	min_edge=k;
+      }
+    }
+    min++;
+    if (min < no_of_nodes) {
+      DIST(v) = min;
+      CURRENT(v) = min_edge;
+    }
+}
+
+void igraph_i_mf_push(long int v, long int e, long int n,
+		      igraph_vector_long_t *current,
+		      igraph_vector_t *rescap, igraph_vector_t *excess,
+		      long int target, long int source,
+		      igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets,
+		      igraph_vector_long_t *distance,
+		      igraph_vector_long_t *rev, igraph_maxflow_stats_t *stats,
+		      int *npushsince) {
+  igraph_real_t delta=
+    RESCAP(e) < EXCESS(v) ? RESCAP(e) : EXCESS(v);
+  (stats->nopush)++; (*npushsince)++;
+  if (EXCESS(n) == 0 && n != target) {
+    igraph_dbuckets_delete(ibuckets, DIST(n), n);
+    igraph_buckets_add(buckets, (long int) DIST(n), n);
+  }
+  RESCAP(e) -= delta;
+  RESCAP(REV(e)) += delta;
+  EXCESS(n) += delta;
+  EXCESS(v) -= delta;
+}
+
+void igraph_i_mf_discharge(long int v,
+			   igraph_vector_long_t *current,
+			   igraph_vector_long_t *first,
+			   igraph_vector_t *rescap,
+			   igraph_vector_long_t *to,
+			   igraph_vector_long_t *distance,
+			   igraph_vector_t *excess,
+			   long int no_of_nodes, long int source,
+			   long int target, igraph_buckets_t *buckets,
+			   igraph_dbuckets_t *ibuckets,
+			   igraph_vector_long_t *rev,
+			   igraph_maxflow_stats_t *stats,
+			   int *npushsince, int *nrelabelsince) {
+  do {
+    long int i;
+    long int start=(long int) CURRENT(v);
+    long int stop =(long int) LAST(v);
+    for (i = start; i < stop; i++) {
+      if (RESCAP(i) > 0) {
+	long int nei=HEAD(i);
+	if (DIST(v) == DIST(nei)+1) {
+	  PUSH((v), i, nei);
+	  if (EXCESS(v) == 0) { break; }
+	}
+      }
+    }
+    if (i == stop) {
+      long int origdist=DIST(v);
+      RELABEL(v);
+      if (igraph_buckets_empty_bucket(buckets, origdist) &&
+	  igraph_dbuckets_empty_bucket(ibuckets, origdist)) {
+	GAP(origdist);
+      }
+      if (DIST(v) == no_of_nodes) { break; }
+    } else {
+      CURRENT(v) = i;
+      igraph_dbuckets_add(ibuckets, DIST(v), v);
+      break;
+    }
+  } while (1);
+}
+
+void igraph_i_mf_bfs(igraph_dqueue_long_t *bfsq,
+		     long int source, long int target,
+		     long int no_of_nodes, igraph_buckets_t *buckets,
+		     igraph_dbuckets_t *ibuckets,
+		     igraph_vector_long_t *distance,
+		     igraph_vector_long_t *first, igraph_vector_long_t *current,
+		     igraph_vector_long_t *to, igraph_vector_t *excess,
+		     igraph_vector_t *rescap, igraph_vector_long_t *rev) {
+
+  long int k, l;
+
+  igraph_buckets_clear(buckets);
+  igraph_dbuckets_clear(ibuckets);
+  igraph_vector_long_fill(distance, no_of_nodes);
+  DIST(target) = 0;
+
+  igraph_dqueue_long_push(bfsq, target);
+  while (!igraph_dqueue_long_empty(bfsq)) {
+    long int node=igraph_dqueue_long_pop(bfsq);
+    long int ndist=DIST(node)+1;
+    for (k=FIRST(node), l=LAST(node); k<l; k++) {
+      if (RESCAP(REV(k)) > 0) {
+	long int nei=HEAD(k);
+	if (DIST(nei) == no_of_nodes) {
+	  DIST(nei) = ndist;
+	  CURRENT(nei) = FIRST(nei);
+	  if (EXCESS(nei) > 0) {
+	    igraph_buckets_add(buckets, ndist, nei);
+	  } else {
+	    igraph_dbuckets_add(ibuckets, ndist, nei);
+	  }
+	  igraph_dqueue_long_push(bfsq, nei);
+	}
+      }
+    }
+  }
+}
+
+/**
+ * \function igraph_maxflow
+ * Maximum network flow between a pair of vertices
+ * 
+ * </para><para>This function implements the Goldberg-Tarjan algorithm for
+ * calculating value of the maximum flow in a directed or undirected
+ * graph. The algorithm was given in Andrew V. Goldberg, Robert
+ * E. Tarjan: A New Approach to the Maximum-Flow Problem, Journal of
+ * the ACM, 35(4), 921-940, 1988. </para>
+ * 
+ * <para> The input of the function is a graph, a vector
+ * of real numbers giving the capacity of the edges and two vertices
+ * of the graph, the source and the target. A flow is a function 
+ * assigning positive real numbers to the edges and satisfying two
+ * requirements: (1) the flow value is less than the capacity of the
+ * edge and (2) at each vertex except the source and the target, the
+ * incoming flow (ie. the sum of the flow on the incoming edges) is
+ * the same as the outgoing flow (ie. the sum of the flow on the
+ * outgoing edges). The value of the flow is the incoming flow at the
+ * target vertex. The maximum flow is the flow with the maximum
+ * value.
+ * 
+ * \param graph The input graph, either directed or undirected.
+ * \param value Pointer to a real number, the value of the maximum
+ *        will be placed here, unless it is a null pointer.
+ * \param flow If not a null pointer, then it must be a pointer to an
+ *        initialized vector. The vector will be resized, and the flow
+ *        on each edge will be placed in it, in the order of the edge
+ *        ids. For undirected graphs this argument is bit trickier,
+ *        since for these the flow direction is not predetermined by
+ *        the edge direction. For these graphs the elements of the
+ *        \p flow 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.
+ * \param cut A null pointer or a pointer to an initialized vector. 
+ *        If not a null pointer, then the minimum cut corresponding to
+ *        the maximum flow is stored here, i.e. all edge ids that are
+ *        part of the minimum cut are stored in the vector.
+ * \param partition A null pointer or a pointer to an initialized
+ *        vector. If not a null pointer, then the first partition of
+ *        the minimum cut that corresponds to the maximum flow will be
+ *        placed here. The first partition is always the one that
+ *        contains the source vertex.
+ * \param partition2 A null pointer or a pointer to an initialized
+ *        vector. If not a null pointer, then the second partition of
+ *        the minimum cut that corresponds to the maximum flow will be
+ *        placed here. The second partition is always the one that
+ *        contains the target vertex.
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \param capacity Vector containing the capacity of the edges. If NULL, then
+ *        every edge is considered to have capacity 1.0.
+ * \param stats Counts of the number of different operations
+ *        preformed by the algorithm are stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^3). In practice it is much faster, but i
+ * cannot prove a better lower bound for the data structure i've
+ * used. In fact, this implementation runs much faster than the
+ * \c hi_pr implementation discussed in
+ * B. V. Cherkassky and A. V. Goldberg: On implementing the 
+ * push-relabel method for the maximum flow problem, (Algorithmica, 
+ * 19:390--410, 1997) on all the graph classes i've tried.
+ * 
+ * \sa \ref igraph_mincut_value(), \ref igraph_edge_connectivity(),
+ * \ref igraph_vertex_connectivity() for 
+ * properties based on the maximum flow.
+ * 
+ * \example examples/simple/flow.c
+ * \example examples/simple/flow2.c
+ */
+
+int igraph_maxflow(const igraph_t *graph, igraph_real_t *value,
+		   igraph_vector_t *flow, igraph_vector_t *cut,
+		   igraph_vector_t *partition, igraph_vector_t *partition2,
+		   igraph_integer_t source, igraph_integer_t target,
+		   const igraph_vector_t *capacity,
+		   igraph_maxflow_stats_t *stats) {
+
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_integer_t no_of_orig_edges=(igraph_integer_t) igraph_ecount(graph);
+  igraph_integer_t no_of_edges=2*no_of_orig_edges;
+
+  igraph_vector_t rescap, excess;
+  igraph_vector_long_t from, to, rev, distance;
+  igraph_vector_t edges, rank;
+  igraph_vector_long_t current, first;
+  igraph_buckets_t buckets;
+  igraph_dbuckets_t ibuckets;
+
+  igraph_dqueue_long_t bfsq;
+
+  long int i, j, idx;
+  int npushsince=0, nrelabelsince=0;
+
+  igraph_maxflow_stats_t local_stats;   /* used if the user passed a null pointer for stats */
+
+  if (stats == 0) {
+    stats = &local_stats;
+  }
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_CHECK(igraph_i_maxflow_undirected(graph, value, flow, cut,
+					     partition, partition2, source,
+					     target, capacity, stats));
+    return 0;
+  }
+
+  if (capacity && igraph_vector_size(capacity) != no_of_orig_edges) {
+    IGRAPH_ERROR("Invalid capacity vector", IGRAPH_EINVAL);
+  }
+  if (source<0 || source>=no_of_nodes || target<0 || target>=no_of_nodes) {
+    IGRAPH_ERROR("Invalid source or target vertex", IGRAPH_EINVAL);
+  }
+
+  stats->nopush = stats->norelabel = stats->nogap = stats->nogapnodes =
+    stats->nobfs = 0;
+
+  /* 
+   * The data structure:
+   * - First of all, we consider every edge twice, first the edge
+   *   itself, but also its opposite.
+   * - (from, to) contain all edges (original + opposite), ordered by 
+   *   the id of the source vertex. During the algorithm we just need
+   *   'to', so from is destroyed soon. We only need it in the
+   *   beginning, to create the 'first' pointers.
+   * - 'first' is a pointer vector for 'to', first[i] points to the
+   *   first neighbor of vertex i and first[i+1]-1 is the last
+   *   neighbor of vertex i. (Unless vertex i is isolate, in which
+   *   case first[i]==first[i+1]).
+   * - 'rev' contains a mapping from an edge to its opposite pair
+   * - 'rescap' contains the residual capacities of the edges, this is
+   *   initially equal to the capacity of the edges for the original
+   *   edges and it is zero for the opposite edges.
+   * - 'excess' contains the excess flow for the vertices. I.e. the flow
+   *   that is coming in, but it is not going out.
+   * - 'current' stores the next neighboring vertex to check, for every
+   *   vertex, when excess flow is being pushed to neighbors.
+   * - 'distance' stores the distance of the vertices from the source.
+   * - 'rank' and 'edges' are only needed temporarily, for ordering and
+   *   storing the edges.
+   * - we use an igraph_buckets_t data structure ('buckets') to find
+   *   the vertices with the highest 'distance' values quickly.
+   *   This always contains the vertices that have a positive excess
+   *   flow.
+   */
+#undef FIRST
+#undef LAST
+#undef CURRENT
+#undef RESCAP
+#undef REV
+#undef HEAD
+#undef EXCESS
+#undef DIST
+#define FIRST(i)       (VECTOR(first)[(i)])
+#define LAST(i)        (VECTOR(first)[(i)+1])
+#define CURRENT(i)     (VECTOR(current)[(i)])
+#define RESCAP(i)      (VECTOR(rescap)[(i)])
+#define REV(i)         (VECTOR(rev)[(i)])
+#define HEAD(i)        (VECTOR(to)[(i)])
+#define EXCESS(i)      (VECTOR(excess)[(i)])
+#define DIST(i)        (VECTOR(distance)[(i)])
+
+  igraph_dqueue_long_init(&bfsq,             no_of_nodes);
+  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &bfsq);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&to,       no_of_edges);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&rev,      no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&rescap,        no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&excess,        no_of_nodes);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&distance, no_of_nodes);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&first,    no_of_nodes+1);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&rank,          no_of_edges);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&from,     no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges,         no_of_edges);
+  
+  /* Create the basic data structure */
+  IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
+  IGRAPH_CHECK(igraph_vector_rank(&edges, &rank, no_of_nodes));
+  
+  for (i=0; i<no_of_edges; i+=2) {
+    long int pos=(long int) VECTOR(rank)[i];
+    long int pos2=(long int) VECTOR(rank)[i+1];
+    VECTOR(from)[pos] = VECTOR(edges)[i];
+    VECTOR(to)[pos]   = VECTOR(edges)[i+1];
+    VECTOR(from)[pos2] = VECTOR(edges)[i+1];
+    VECTOR(to)[pos2]   = VECTOR(edges)[i];
+    VECTOR(rev)[pos] = pos2;
+    VECTOR(rev)[pos2] = pos;
+    VECTOR(rescap)[pos] = capacity ? VECTOR(*capacity)[i/2] : 1.0;
+    VECTOR(rescap)[pos2] = 0.0;
+  }  
+ 
+  /* The first pointers. This is a but trickier, than one would
+     think, because of the possible isolate vertices. */
+  
+  idx=-1;
+  for (i=0; i<=VECTOR(from)[0]; i++) {
+    idx++; VECTOR(first)[idx]=0;
+  }
+  for (i=1; i<no_of_edges; i++) {
+    long int n=(long int) (VECTOR(from)[i] - 
+			   VECTOR(from)[ (long int) VECTOR(first)[idx] ]);
+    for (j=0; j<n; j++) {
+      idx++; VECTOR(first)[idx]=i;
+    }
+  }
+  idx++;
+  while (idx < no_of_nodes+1) {
+    VECTOR(first)[idx++] = no_of_edges;
+  }
+
+  igraph_vector_long_destroy(&from);
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (!flow) {
+    igraph_vector_destroy(&rank);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  /* And the current pointers, initially the same as the first */
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&current, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(current)[i] = VECTOR(first)[i];
+  }
+
+  /* OK, the graph is set up, initialization */
+
+  IGRAPH_CHECK(igraph_buckets_init(&buckets, no_of_nodes+1, no_of_nodes));
+  IGRAPH_FINALLY(igraph_buckets_destroy, &buckets);
+  IGRAPH_CHECK(igraph_dbuckets_init(&ibuckets, no_of_nodes+1, no_of_nodes));
+  IGRAPH_FINALLY(igraph_dbuckets_destroy, &ibuckets);
+
+  /* Send as much flow as possible from the source to its neighbors */
+  for (i=FIRST(source), j=LAST(source); i<j; i++) {
+    if (HEAD(i) != source) {
+      igraph_real_t delta=RESCAP(i);
+      RESCAP(i) = 0;
+      RESCAP(REV(i)) += delta;
+      EXCESS(HEAD(i)) += delta;
+    }
+  }
+
+  BFS();
+  (stats->nobfs)++;
+
+  while (!igraph_buckets_empty(&buckets)) {
+    long int vertex=igraph_buckets_popmax(&buckets);
+    DISCHARGE(vertex);
+    if (npushsince > no_of_nodes / 2 && nrelabelsince > no_of_nodes) {
+      (stats->nobfs)++;
+      BFS();
+      npushsince = nrelabelsince = 0;
+    }
+  }
+
+  /* Store the result */
+  if (value) {
+    *value=EXCESS(target);
+  }  
+
+  /* If we also need the minimum cut */
+  if (cut || partition || partition2) {
+    /* We need to find all vertices from which the target is reachable 
+       in the residual graph. We do a breadth-first search, going
+       backwards. */
+    igraph_dqueue_t Q;
+    igraph_vector_bool_t added;
+    long int marked=0;
+
+    IGRAPH_CHECK(igraph_vector_bool_init(&added, no_of_nodes));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &added);
+
+    IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
+    IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
+
+    igraph_dqueue_push(&Q, target);
+    VECTOR(added)[(long int)target]=1;
+    marked++;
+    while (!igraph_dqueue_empty(&Q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&Q);
+      for (i=FIRST(actnode), j=LAST(actnode); i<j; i++) {
+	long int nei=HEAD(i);
+	if (!VECTOR(added)[nei] && RESCAP(REV(i)) > 0.0) {
+	  VECTOR(added)[nei]=1;
+	  marked++;
+	  IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));
+	}
+      }
+    }    
+    igraph_dqueue_destroy(&Q);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    /* Now we marked each vertex that is on one side of the cut,
+       check the crossing edges */
+
+    if (cut) {
+      igraph_vector_clear(cut);
+      for (i=0; i<no_of_orig_edges; i++) {
+	long int f=IGRAPH_FROM(graph, i);
+	long int t=IGRAPH_TO(graph, i);
+	if (!VECTOR(added)[f] && VECTOR(added)[t]) {
+	  IGRAPH_CHECK(igraph_vector_push_back(cut, i));
+	}
+      }
+    }
+
+    if (partition2) {
+      long int x=0;
+      IGRAPH_CHECK(igraph_vector_resize(partition2, marked));
+      for (i=0; i<no_of_nodes; i++) {
+	if (VECTOR(added)[i]) {
+	  VECTOR(*partition2)[x++]=i;
+	}
+      }
+    }
+
+    if (partition) {
+      long int x=0;
+      IGRAPH_CHECK(igraph_vector_resize(partition,
+					no_of_nodes-marked));
+      for (i=0; i<no_of_nodes; i++) {
+	if (!VECTOR(added)[i]) {
+	  VECTOR(*partition)[x++]=i;
+	}
+      }
+    }
+    
+    igraph_vector_bool_destroy(&added);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (flow) {
+    /* Initialize the backward distances, with a breadth-first search 
+       from the source */ 
+    igraph_dqueue_t Q;
+    igraph_vector_int_t added;
+    long int j, k, l;
+    igraph_t flow_graph;
+    igraph_vector_t flow_edges;
+    igraph_bool_t dag;
+
+    IGRAPH_CHECK(igraph_vector_int_init(&added, no_of_nodes));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &added);
+    IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
+    IGRAPH_FINALLY(igraph_dqueue_destroy, &added);
+    
+    igraph_dqueue_push(&Q, source);
+    igraph_dqueue_push(&Q, 0);
+    VECTOR(added)[(long int)source]=1;
+    while (!igraph_dqueue_empty(&Q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&Q);
+      long int actdist=(long int) igraph_dqueue_pop(&Q);
+      DIST(actnode)=actdist;
+	  
+      for (i=FIRST(actnode), j=LAST(actnode); i<j; i++) {
+	long int nei=HEAD(i);
+	if (!VECTOR(added)[nei] && RESCAP(REV(i)) > 0.0) {
+	  VECTOR(added)[nei]=1;
+	  IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));
+	  IGRAPH_CHECK(igraph_dqueue_push(&Q, actdist+1));
+	}
+      }
+    } /* !igraph_dqueue_empty(&Q) */
+	  
+    igraph_vector_int_destroy(&added);
+    igraph_dqueue_destroy(&Q);
+    IGRAPH_FINALLY_CLEAN(2);
+
+    /* Reinitialize the buckets */
+    igraph_buckets_clear(&buckets);
+    for (i=0; i<no_of_nodes; i++) {
+      if (EXCESS(i) > 0.0 && i != source && i != target) {
+	igraph_buckets_add(&buckets, (long int) DIST(i), i);
+      }
+    }
+
+    /* Now we return the flow to the source */
+    while (!igraph_buckets_empty(&buckets)) {
+      long int vertex=igraph_buckets_popmax(&buckets);
+
+      /* DISCHARGE(vertex) comes here */
+      do {
+	for (i=(long int) CURRENT(vertex), j=LAST(vertex); i<j; i++) {
+	  if (RESCAP(i) > 0) {
+	    long int nei=HEAD(i);
+	    
+	    if (DIST(vertex) == DIST(nei)+1) {
+	      igraph_real_t delta=
+		RESCAP(i) < EXCESS(vertex) ? RESCAP(i) : EXCESS(vertex);
+	      RESCAP(i) -= delta;
+	      RESCAP(REV(i)) += delta;
+	      
+	      if (nei != source && EXCESS(nei) == 0.0 &&
+		  DIST(nei) != no_of_nodes) {
+		igraph_buckets_add(&buckets, (long int) DIST(nei), nei);
+	      }
+	      
+	      EXCESS(nei) += delta;
+	      EXCESS(vertex) -= delta;
+	      
+	      if (EXCESS(vertex) == 0) break;
+	      
+	    }
+	  }
+	}
+	
+	if (i==j) {
+	  
+	  /* RELABEL(vertex) comes here */	
+	  igraph_real_t min;
+	  long int min_edge=0;
+	  DIST(vertex)=min=no_of_nodes;
+	  for (k=FIRST(vertex), l=LAST(vertex); k<l; k++) {
+	    if (RESCAP(k) > 0) {
+	      if (DIST(HEAD(k)) < min) {
+		min=DIST(HEAD(k));
+		min_edge=k;
+	      }
+	    }
+	  }
+	  
+	  min++;
+	  
+	  if (min < no_of_nodes) {
+	    DIST(vertex)=min;
+	    CURRENT(vertex)=min_edge;
+	    /* Vertex is still active */
+	    igraph_buckets_add(&buckets, (long int) DIST(vertex), vertex);
+	  }
+	  
+	  /* TODO: gap heuristics here ??? */
+
+	} else {
+	  CURRENT(vertex) = FIRST(vertex);
+	}
+	
+	break;
+	
+      } while (1);
+    }
+
+    /* We need to eliminate flow cycles now. Before that we check that
+       there is a cycle in the flow graph.
+
+       First we do a couple of DFSes from the source vertex to the
+       target and factor out the paths we find. If there is no more
+       path to the target, then all remaining flow must be in flow
+       cycles, so we don't need it at all.
+       
+       Some details. 'stack' contains the whole path of the DFS, both
+       the vertices and the edges, they are alternating in the stack.
+       'current' helps finding the next outgoing edge of a vertex
+       quickly, the next edge of 'v' is FIRST(v)+CURRENT(v). If this
+       is LAST(v), then there are no more edges to try.
+
+       The 'added' vector contains 0 if the vertex was not visited
+       before, 1 if it is currently in 'stack', and 2 if it is not in
+       'stack', but it was visited before. */
+    
+    IGRAPH_VECTOR_INIT_FINALLY(&flow_edges, 0);
+    for (i=0, j=0; i<no_of_edges; i+=2, j++) {
+      long int pos=(long int) VECTOR(rank)[i];
+      if ((capacity ? VECTOR(*capacity)[j] : 1.0) > RESCAP(pos)) {
+	IGRAPH_CHECK(igraph_vector_push_back(&flow_edges, 
+					     IGRAPH_FROM(graph, j)));
+	IGRAPH_CHECK(igraph_vector_push_back(&flow_edges, 
+					     IGRAPH_TO(graph, j)));
+      }
+    }
+    IGRAPH_CHECK(igraph_create(&flow_graph, &flow_edges, no_of_nodes, 
+			       IGRAPH_DIRECTED));
+    igraph_vector_destroy(&flow_edges);
+    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_FINALLY(igraph_destroy, &flow_graph);
+    IGRAPH_CHECK(igraph_is_dag(&flow_graph, &dag));
+    igraph_destroy(&flow_graph);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    if (!dag) {
+      igraph_vector_long_t stack;
+      igraph_vector_t mycap;
+
+      IGRAPH_CHECK(igraph_vector_long_init(&stack, 0));
+      IGRAPH_FINALLY(igraph_vector_long_destroy, &stack);
+      IGRAPH_CHECK(igraph_vector_int_init(&added, no_of_nodes));
+      IGRAPH_FINALLY(igraph_vector_int_destroy, &added);
+      IGRAPH_VECTOR_INIT_FINALLY(&mycap, no_of_edges);
+      
+#define MYCAP(i)      (VECTOR(mycap)[(i)])
+
+      for (i=0; i<no_of_edges; i+=2) {
+	long int pos=(long int) VECTOR(rank)[i];
+	long int pos2=(long int) VECTOR(rank)[i+1];
+	MYCAP(pos) = (capacity ? VECTOR(*capacity)[i/2] : 1.0) - RESCAP(pos);
+	MYCAP(pos2) = 0.0;
+      }
+      
+      do { 
+	igraph_vector_long_null(&current);
+	igraph_vector_long_clear(&stack);
+	igraph_vector_int_null(&added);
+	
+	IGRAPH_CHECK(igraph_vector_long_push_back(&stack, -1));
+	IGRAPH_CHECK(igraph_vector_long_push_back(&stack, source));
+	VECTOR(added)[(long int)source]=1;
+	while (!igraph_vector_long_empty(&stack) &&
+	       igraph_vector_long_tail(&stack) != target) {
+	  long int actnode=igraph_vector_long_tail(&stack);
+	  long int edge=FIRST(actnode) + (long int) CURRENT(actnode);
+	  long int nei;
+	  while (edge < LAST(actnode) && MYCAP(edge)==0.0) { edge++; }
+	  nei=edge < LAST(actnode) ? HEAD(edge) : -1;
+	  
+	  if (edge < LAST(actnode) && !VECTOR(added)[nei]) {
+	    /* Go forward along next edge, if the vertex was not
+	       visited before */
+	    IGRAPH_CHECK(igraph_vector_long_push_back(&stack, edge));
+	    IGRAPH_CHECK(igraph_vector_long_push_back(&stack, nei));
+	    VECTOR(added)[nei]=1;
+	    CURRENT(actnode) += 1;
+	  } else if (edge < LAST(actnode) && VECTOR(added)[nei]==1) {
+	    /* We found a flow cycle, factor it out. Go back in stack
+	       until we find 'nei' again, determine the flow along the
+	       cycle. */
+	    igraph_real_t thisflow=MYCAP(edge);
+	    long int idx;
+	    for (idx=igraph_vector_long_size(&stack)-2; 
+		 idx >= 0 && VECTOR(stack)[idx+1] != nei; idx-=2) {
+	      long int e=VECTOR(stack)[idx];
+	      igraph_real_t rcap= e >= 0 ? MYCAP(e) : MYCAP(edge);
+	      if (rcap < thisflow) { thisflow=rcap; }
+	    }
+	    MYCAP(edge) -= thisflow; RESCAP(edge) += thisflow;
+	    for (idx=igraph_vector_long_size(&stack)-2; 
+		 idx >= 0 && VECTOR(stack)[idx+1] != nei; idx-=2) {
+	      long int e=VECTOR(stack)[idx];
+	      if (e >= 0) { MYCAP(e) -= thisflow; RESCAP(e) += thisflow; }
+	    }
+	    CURRENT(actnode) += 1;
+	  } else if (edge < LAST(actnode)) { /* && VECTOR(added)[nei]==2 */
+	    /* The next edge leads to a vertex that was visited before,
+	       but it is currently not in 'stack' */
+	    CURRENT(actnode) += 1;
+	  } else {
+	    /* Go backward, take out the node and the edge that leads to it */
+	    igraph_vector_long_pop_back(&stack);
+	    igraph_vector_long_pop_back(&stack);
+	    VECTOR(added)[actnode]=2;
+	  }
+	}
+      
+	/* If non-empty, then it contains a path from source to target
+	   in the residual graph. We factor out this path from the flow. */
+	if (!igraph_vector_long_empty(&stack)) {
+	  long int pl=igraph_vector_long_size(&stack);
+	  igraph_real_t thisflow=EXCESS(target);
+	  for (i=2; i<pl; i+=2) {
+	    long int edge=VECTOR(stack)[i];
+	    igraph_real_t rcap=MYCAP(edge);
+	    if (rcap < thisflow) { thisflow=rcap; }
+	  }
+	  for (i=2; i<pl; i+=2) {
+	    long int edge=VECTOR(stack)[i];
+	    MYCAP(edge) -= thisflow;
+	  }
+	}
+	
+      } while (!igraph_vector_long_empty(&stack));
+      
+      igraph_vector_destroy(&mycap);
+      igraph_vector_int_destroy(&added);
+      igraph_vector_long_destroy(&stack);
+      IGRAPH_FINALLY_CLEAN(3);
+    }
+
+    /* ----------------------------------------------------------- */
+
+    IGRAPH_CHECK(igraph_vector_resize(flow, no_of_orig_edges));
+    for (i=0, j=0; i<no_of_edges; i+=2, j++) {
+      long int pos=(long int) VECTOR(rank)[i];
+      VECTOR(*flow)[j] = (capacity ? VECTOR(*capacity)[j] : 1.0) - 
+	RESCAP(pos);
+    }
+    
+    igraph_vector_destroy(&rank);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_dbuckets_destroy(&ibuckets);
+  igraph_buckets_destroy(&buckets);
+  igraph_vector_long_destroy(&current);
+  igraph_vector_long_destroy(&first);
+  igraph_vector_long_destroy(&distance);
+  igraph_vector_destroy(&excess);
+  igraph_vector_destroy(&rescap);
+  igraph_vector_long_destroy(&rev);
+  igraph_vector_long_destroy(&to);
+  igraph_dqueue_long_destroy(&bfsq);
+  IGRAPH_FINALLY_CLEAN(10);
+
+  return 0;
+}
+
+/**
+ * \function igraph_maxflow_value
+ * \brief Maximum flow in a network with the push/relabel algorithm
+ * 
+ * </para><para>This function implements the Goldberg-Tarjan algorithm for
+ * calculating value of the maximum flow in a directed or undirected
+ * graph. The algorithm was given in Andrew V. Goldberg, Robert
+ * E. Tarjan: A New Approach to the Maximum-Flow Problem, Journal of
+ * the ACM, 35(4), 921-940, 1988. </para>
+ * 
+ * <para> The input of the function is a graph, a vector
+ * of real numbers giving the capacity of the edges and two vertices
+ * of the graph, the source and the target. A flow is a function 
+ * assigning positive real numbers to the edges and satisfying two
+ * requirements: (1) the flow value is less than the capacity of the
+ * edge and (2) at each vertex except the source and the target, the
+ * incoming flow (ie. the sum of the flow on the incoming edges) is
+ * the same as the outgoing flow (ie. the sum of the flow on the
+ * outgoing edges). The value of the flow is the incoming flow at the
+ * target vertex. The maximum flow is the flow with the maximum
+ * value. </para>
+ * 
+ * <para> According to a theorem by Ford and Fulkerson 
+ * (L. R. Ford Jr. and D. R. Fulkerson. Maximal flow through a
+ * network. Canadian J. Math., 8:399-404, 1956.) the maximum flow
+ * between two vertices is the same as the 
+ * minimum cut between them (also called the minimum s-t cut). So \ref
+ * igraph_st_mincut_value() gives the same result in all cases as \c
+ * igraph_maxflow_value().</para>
+ * 
+ * <para> Note that the value of the maximum flow is the same as the
+ * minimum cut in the graph.
+ * \param graph The input graph, either directed or undirected.
+ * \param value Pointer to a real number, the result will be placed here.
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \param capacity Vector containing the capacity of the edges. If NULL, then
+ *        every edge is considered to have capacity 1.0.
+ * \param stats Counts of the number of different operations
+ *        preformed by the algorithm are stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^3).
+ *
+ * \sa \ref igraph_maxflow() to calculate the actual flow. 
+ * \ref igraph_mincut_value(), \ref igraph_edge_connectivity(),
+ * \ref igraph_vertex_connectivity() for 
+ * properties based on the maximum flow.
+ */
+
+int igraph_maxflow_value(const igraph_t *graph, igraph_real_t *value,
+			 igraph_integer_t source, igraph_integer_t target,
+			 const igraph_vector_t *capacity,
+			 igraph_maxflow_stats_t *stats) {
+
+  return igraph_maxflow(graph, value, /*flow=*/ 0, /*cut=*/ 0, 
+			/*partition=*/ 0, /*partition1=*/ 0,
+			source, target, capacity, stats);
+}
+
+/**
+ * \function igraph_st_mincut_value
+ * \brief The minimum s-t cut in a graph
+ * 
+ * </para><para> The minimum s-t cut in a weighted (=valued) graph is the
+ * total minimum edge weight needed to remove from the graph to
+ * eliminate all paths from a given vertex (\c source) to
+ * another vertex (\c target). Directed paths are considered in
+ * directed graphs, and undirected paths in undirected graphs.  </para>
+ * 
+ * <para> The minimum s-t cut between two vertices is known to be same
+ * as the maximum flow between these two vertices. So this function
+ * calls \ref igraph_maxflow_value() to do the calculation.
+ * \param graph The input graph.
+ * \param value Pointer to a real variable, the result will be stored
+ *        here. 
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \param capacity Pointer to the capacity vector, it should contain
+ *        non-negative numbers and its length should be the same the
+ *        the number of edges in the graph. It can be a null pointer, then
+ *        every edge has unit capacity.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^3), see also the discussion for \ref
+ * igraph_maxflow_value(), |V| is the number of vertices. 
+ */
+
+int igraph_st_mincut_value(const igraph_t *graph, igraph_real_t *value,
+			   igraph_integer_t source, igraph_integer_t target,
+			   const igraph_vector_t *capacity) {
+  
+  if (source == target) {
+    IGRAPH_ERROR("source and target vertices are the same", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_maxflow_value(graph, value, source, target, capacity, 0));
+
+  return 0;
+}			    
+
+/** 
+ * \function igraph_st_mincut
+ * Minimum cut between a source and a target vertex
+ * 
+ * Finds the edge set that has the smallest total capacity among all
+ * edge sets that disconnect the source and target vertices.
+ * 
+ * </para><para>The calculation is performed using maximum flow
+ * techniques, by calling \ref igraph_maxflow().
+ * \param graph The input graph.
+ * \param value Pointer to a real variable, the value of the cut is
+ *        stored here.
+ * \param cut Pointer to a real vector, the edge ids that are included
+ *        in the cut are stored here. This argument is ignored if it
+ *        is a null pointer.
+ * \param partition Pointer to a real vector, the vertex ids of the
+ *        vertices in the first partition of the cut are stored
+ *        here. The first partition is always the one that contains the
+ *        source vertex. This argument is ignored if it is a null pointer.
+ * \param partition2 Pointer to a real vector, the vertex ids of the
+ *        vertices in the second partition of the cut are stored here.
+ *        The second partition is always the one that contains the
+ *        target vertex. This argument is ignored if it is a null pointer.
+ * \param source Integer, the id of the source vertex.
+ * \param target Integer, the id of the target vertex.
+ * \param capacity Vector containing the capacity of the edges. If a
+ *        null pointer, then every edge is considered to have capacity
+ *        1.0.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_maxflow().
+ * 
+ * Time complexity: see \ref igraph_maxflow().
+ */
+
+int igraph_st_mincut(const igraph_t *graph, igraph_real_t *value,
+		     igraph_vector_t *cut, igraph_vector_t *partition,
+		     igraph_vector_t *partition2,
+		     igraph_integer_t source, igraph_integer_t target,
+		     const igraph_vector_t *capacity) {
+
+  return igraph_maxflow(graph, value, /*flow=*/ 0, 
+			cut, partition, partition2, 
+			source, target, capacity, 0);
+}
+
+/* This is a flow-based version, but there is a better one
+   for undirected graphs */
+
+/* int igraph_i_mincut_value_undirected(const igraph_t *graph, */
+/* 				     igraph_real_t *res, */
+/* 				     const igraph_vector_t *capacity) { */
+  
+/*   long int no_of_edges=igraph_ecount(graph); */
+/*   long int no_of_nodes=igraph_vcount(graph); */
+/*   igraph_vector_t edges; */
+/*   igraph_vector_t newcapacity; */
+/*   igraph_t newgraph; */
+/*   long int i; */
+  
+/*   /\* We need to convert this to directed by hand, since we need to be */
+/*      sure that the edge ids will be handled properly to build the new */
+/*      capacity vector. *\/ */
+
+/*   IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); */
+/*   IGRAPH_VECTOR_INIT_FINALLY(&newcapacity, no_of_edges*2); */
+/*   IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*4)); */
+/*   IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); */
+/*   IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4)); */
+/*   for (i=0; i<no_of_edges; i++) { */
+/*     VECTOR(edges)[no_of_edges*2+i*2] = VECTOR(edges)[i*2+1]; */
+/*     VECTOR(edges)[no_of_edges*2+i*2+1] = VECTOR(edges)[i*2]; */
+/*     VECTOR(newcapacity)[i] = VECTOR(newcapacity)[no_of_edges+i] =  */
+/*       capacity ? VECTOR(*capacity)[i] : 1.0 ; */
+/*   } */
+  
+/*   IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED)); */
+/*   IGRAPH_FINALLY(igraph_destroy, &newgraph); */
+  
+/*   IGRAPH_CHECK(igraph_mincut_value(&newgraph, res, &newcapacity)); */
+  
+/*   igraph_destroy(&newgraph); */
+/*   igraph_vector_destroy(&edges); */
+/*   igraph_vector_destroy(&newcapacity); */
+/*   IGRAPH_FINALLY_CLEAN(3); */
+  
+/*   return 0; */
+/* } */
+
+/*
+ * This is the Stoer-Wagner algorithm, it works for calculating the
+ * minimum cut for undirected graphs, for the whole graph. 
+ * I.e. this is basically the edge-connectivity of the graph. 
+ * It can also calculate the cut itself, not just the cut value.
+ */
+
+int igraph_i_mincut_undirected(const igraph_t *graph, 
+			       igraph_real_t *res,
+			       igraph_vector_t *partition,
+			       igraph_vector_t *partition2,
+			       igraph_vector_t *cut,
+			       const igraph_vector_t *capacity) {
+  
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_integer_t no_of_edges=(igraph_integer_t) igraph_ecount(graph);  
+
+  igraph_i_cutheap_t heap;
+  igraph_real_t mincut=IGRAPH_INFINITY;	/* infinity */
+  long int i;
+  
+  igraph_adjlist_t adjlist;
+  igraph_inclist_t inclist;
+
+  igraph_vector_t mergehist;
+  igraph_bool_t calc_cut=partition || partition2 || cut;
+  long int act_step=0, mincut_step=0;
+  
+  if (capacity && igraph_vector_size(capacity) != no_of_edges) {
+    IGRAPH_ERROR("Invalid capacity vector size", IGRAPH_EINVAL);
+  }
+
+  /* Check if the graph is connected at all */
+  {
+    igraph_vector_t memb, csize;
+    igraph_integer_t no;
+    IGRAPH_VECTOR_INIT_FINALLY(&memb, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&csize, 0);
+    IGRAPH_CHECK(igraph_clusters(graph, &memb, &csize, &no,
+				 /*mode=*/ IGRAPH_WEAK));
+    if (no != 1) {
+      if (res) { *res = 0;                 }
+      if (cut) { igraph_vector_clear(cut); }
+      if (partition) {
+	int j=0;
+	IGRAPH_CHECK(igraph_vector_resize(partition, 
+					  (long int) VECTOR(csize)[0]));
+	for (i=0; i<no_of_nodes; i++) {
+	  if (VECTOR(memb)[i] == 0) { VECTOR(*partition)[j++] = i; }
+	}
+      }
+      if (partition2) {
+	int j=0;
+	IGRAPH_CHECK(igraph_vector_resize(partition2, no_of_nodes - 
+					  (long int) VECTOR(csize)[0]));
+	for (i=0; i<no_of_nodes; i++) {
+	  if (VECTOR(memb)[i] != 0) { VECTOR(*partition2)[j++] = i; }
+	}
+      }
+    }
+    igraph_vector_destroy(&csize);
+    igraph_vector_destroy(&memb);
+    IGRAPH_FINALLY_CLEAN(2);
+    
+    if (no != 1) { return 0; }
+  }
+
+  if (calc_cut) {
+    IGRAPH_VECTOR_INIT_FINALLY(&mergehist, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&mergehist, no_of_nodes*2));
+  }
+
+  IGRAPH_CHECK(igraph_i_cutheap_init(&heap, no_of_nodes));
+  IGRAPH_FINALLY(igraph_i_cutheap_destroy, &heap);
+
+  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+  while (igraph_i_cutheap_size(&heap) >= 2) {
+
+    long int last;
+    igraph_real_t acut;
+    long int a, n;
+
+    igraph_vector_t *edges, *edges2;
+    igraph_vector_int_t *neis, *neis2;
+   
+    do {
+      a=igraph_i_cutheap_popmax(&heap);
+
+      /* 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);
+      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];
+	igraph_real_t weight=capacity ? VECTOR(*capacity)[(long int)edge] : 1.0;
+	igraph_i_cutheap_update(&heap, to, weight);
+      }
+            
+    } while (igraph_i_cutheap_active_size(&heap) > 1);
+
+    /* Now, there is only one active vertex left, 
+       calculate the cut of the phase */
+    acut=igraph_i_cutheap_maxvalue(&heap);
+    last=igraph_i_cutheap_popmax(&heap);
+
+    if (acut < mincut) {
+      mincut=acut;
+      mincut_step=act_step;
+    }    
+
+    if (mincut == 0) {
+      break;
+    }
+
+    /* And contract the last and the remaining vertex (a and last) */
+    /* Before actually doing that, make some notes */
+    act_step++;
+    if (calc_cut) {
+      IGRAPH_CHECK(igraph_vector_push_back(&mergehist, a));
+      IGRAPH_CHECK(igraph_vector_push_back(&mergehist, last));
+    }
+    /* First remove the a--last edge if there is one, a is still the
+       last deactivated vertex */
+    edges=igraph_inclist_get(&inclist, a);
+    neis=igraph_adjlist_get(&adjlist, a);
+    n=igraph_vector_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);
+	n--;
+      } else {
+	i++;
+      }
+    }
+    
+    edges=igraph_inclist_get(&inclist, last);
+    neis=igraph_adjlist_get(&adjlist, last);
+    n=igraph_vector_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);
+	n--;
+      } else {
+	i++;
+      }
+    }
+
+    /* Now rewrite the edge lists of last's neighbors */
+    neis=igraph_adjlist_get(&adjlist, last);
+    n=igraph_vector_int_size(neis);    
+    for (i=0; i<n; i++) {     
+      igraph_integer_t nei=(igraph_integer_t) VECTOR(*neis)[i];
+      long int n2, j;
+      neis2=igraph_adjlist_get(&adjlist, nei);
+      n2=igraph_vector_int_size(neis2);
+      for (j=0; j<n2; j++) {
+	if (VECTOR(*neis2)[j] == last) {
+	  VECTOR(*neis2)[j] = a;
+	}
+      }
+    }
+    
+    /* And append the lists of last to the lists of a */
+    edges=igraph_inclist_get(&inclist, a);
+    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(neis, neis2));
+    igraph_vector_clear(edges2); /* TODO: free it */
+    igraph_vector_int_clear(neis2);	 /* TODO: free it */
+
+    /* Remove the deleted vertex from the heap entirely */
+    igraph_i_cutheap_reset_undefine(&heap, last);    
+  }
+
+  *res=mincut;
+
+  igraph_inclist_destroy(&inclist);
+  igraph_adjlist_destroy(&adjlist);
+  igraph_i_cutheap_destroy(&heap);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (calc_cut) {
+    long int bignode=(long int) VECTOR(mergehist)[2*mincut_step+1];
+    long int i, idx;
+    long int size=1;
+    char *mark;
+    mark=igraph_Calloc(no_of_nodes, char);
+    if (!mark) { 
+      IGRAPH_ERROR("Not enough memory for minimum cut", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, mark);
+    
+    /* first count the vertices in the partition */
+    mark[bignode]=1;
+    for (i=mincut_step-1; i>=0; i--) {
+      if ( mark[ (long int) VECTOR(mergehist)[2*i] ] ) {
+	size++;
+	mark [ (long int) VECTOR(mergehist)[2*i+1] ]=1;
+      }
+    }
+	
+    /* now store them, if requested */
+    if (partition) {
+      IGRAPH_CHECK(igraph_vector_resize(partition, size));
+      idx=0;
+      VECTOR(*partition)[idx++]=bignode;
+      for (i=mincut_step-1; i>=0; i--) {
+	if (mark[ (long int) VECTOR(mergehist)[2*i] ]) {
+	  VECTOR(*partition)[idx++] = VECTOR(mergehist)[2*i+1];
+	}
+      }
+    }
+
+    /* The other partition too? */
+    if (partition2) {
+      IGRAPH_CHECK(igraph_vector_resize(partition2, no_of_nodes-size));
+      idx=0;
+      for (i=0; i<no_of_nodes; i++) {
+	if (!mark[i]) {
+	  VECTOR(*partition2)[idx++]=i;
+	}
+      }
+    }
+    
+    /* The edges in the cut are also requested? */
+    /* We want as few memory allocated for 'cut' as possible,
+       so we first collect the edges in mergehist, we don't 
+       need that anymore. Then we copy it to 'cut';  */
+    if (cut) {
+      igraph_integer_t from, to;
+      igraph_vector_clear(&mergehist);
+      for (i=0; i<no_of_edges; i++) {
+	igraph_edge(graph, (igraph_integer_t) i, &from, &to);
+	if ((mark[(long int)from] && !mark[(long int)to]) ||
+	    (mark[(long int)to] && !mark[(long int)from])) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&mergehist, i));
+	}
+      }
+      igraph_vector_clear(cut);
+      IGRAPH_CHECK(igraph_vector_append(cut, &mergehist));
+    }
+
+    igraph_free(mark);
+    igraph_vector_destroy(&mergehist);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  
+  return 0;
+}
+
+int igraph_i_mincut_directed(const igraph_t *graph,
+			     igraph_real_t *value,
+			     igraph_vector_t *partition,
+			     igraph_vector_t *partition2,
+			     igraph_vector_t *cut,
+			     const igraph_vector_t *capacity) {
+  long int i;
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_real_t flow;
+  igraph_real_t minmaxflow=IGRAPH_INFINITY;
+  igraph_vector_t mypartition, mypartition2, mycut;
+  igraph_vector_t *ppartition=0, *ppartition2=0, *pcut=0;
+  igraph_vector_t bestpartition, bestpartition2, bestcut;
+
+  if (partition) {
+    IGRAPH_VECTOR_INIT_FINALLY(&bestpartition, 0);
+  }
+  if (partition2) {
+    IGRAPH_VECTOR_INIT_FINALLY(&bestpartition2, 0);
+  }
+  if (cut) {
+    IGRAPH_VECTOR_INIT_FINALLY(&bestcut, 0);
+  }
+  
+  if (partition) {
+    IGRAPH_VECTOR_INIT_FINALLY(&mypartition, 0);
+    ppartition=&mypartition;
+  }
+  if (partition2) {
+    IGRAPH_VECTOR_INIT_FINALLY(&mypartition2, 0);
+    ppartition2=&mypartition2;
+  }
+  if (cut) {
+    IGRAPH_VECTOR_INIT_FINALLY(&mycut, 0);
+    pcut=&mycut;
+  }
+
+  for (i=1; i<no_of_nodes; i++) {
+    IGRAPH_CHECK(igraph_maxflow(graph, /*value=*/ &flow, /*flow=*/ 0, 
+				pcut, ppartition, ppartition2, /*source=*/ 0,
+				/*target=*/ (igraph_integer_t) i, capacity, 0));
+    if (flow < minmaxflow) {
+      minmaxflow = flow;
+      if (cut) { 
+	IGRAPH_CHECK(igraph_vector_update(&bestcut, &mycut)); 
+      }
+      if (partition) { 
+	IGRAPH_CHECK(igraph_vector_update(&bestpartition, &mypartition)); 
+      }
+      if (partition2) { 
+	IGRAPH_CHECK(igraph_vector_update(&bestpartition2, &mypartition2)); 
+      }
+
+      if (minmaxflow == 0) { break; }
+    }
+    IGRAPH_CHECK(igraph_maxflow(graph, /*value=*/ &flow, /*flow=*/ 0,
+				pcut, ppartition, ppartition2, 
+				/*source=*/ (igraph_integer_t) i,
+				/*target=*/ 0, capacity, 0));
+    if (flow < minmaxflow) {
+      minmaxflow = flow;
+      if (cut) { 
+	IGRAPH_CHECK(igraph_vector_update(&bestcut, &mycut)); 
+      }
+      if (partition) { 
+	IGRAPH_CHECK(igraph_vector_update(&bestpartition, &mypartition)); 
+      }
+      if (partition2) { 
+	IGRAPH_CHECK(igraph_vector_update(&bestpartition2, &mypartition2)); 
+      }
+
+      if (minmaxflow == 0) { break; }
+    }
+  }
+  
+  if (value) {
+    *value = minmaxflow;
+  }
+
+  if (cut) {
+    igraph_vector_destroy(&mycut);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (partition) {
+    igraph_vector_destroy(&mypartition);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (partition2) {
+    igraph_vector_destroy(&mypartition2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (cut) {
+    IGRAPH_CHECK(igraph_vector_update(cut, &bestcut));
+    igraph_vector_destroy(&bestcut);
+    IGRAPH_FINALLY_CLEAN(1);
+  }  
+  if (partition2) {
+    IGRAPH_CHECK(igraph_vector_update(partition2, &bestpartition2));
+    igraph_vector_destroy(&bestpartition2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (partition) {
+    IGRAPH_CHECK(igraph_vector_update(partition, &bestpartition));
+    igraph_vector_destroy(&bestpartition);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_mincut
+ * \brief Calculates the minimum cut in a graph.
+ * 
+ * This function calculates the minimum cut in a graph. 
+ * The minimum cut is the minimum set of edges which needs to be
+ * removed to disconnect the graph. The minimum is calculated using
+ * the weights (\p capacity) of the edges, so the cut with the minimum
+ * total capacity is calculated. 
+ * 
+ * </para><para> For directed graphs an implementation based on
+ * calculating 2|V|-2 maximum flows is used. 
+ * For undirected graphs we use the Stoer-Wagner
+ * algorithm, as described in M. Stoer and F. Wagner: A simple min-cut
+ * algorithm, Journal of the ACM, 44 585-591, 1997.
+ * 
+ * </para><para>
+ * The first implementation of the actual cut calculation for
+ * undirected graphs was made by Gregory Benison, thanks Greg.
+ * \param graph The input graph.
+ * \param value Pointer to a float, the value of the cut will be
+ *    stored here.
+ * \param partition Pointer to an initialized vector, the ids
+ *    of the vertices in the first partition after separating the
+ *    graph will be stored here. The vector will be resized as
+ *    needed. This argument is ignored if it is a NULL pointer. 
+ * \param partition2 Pointer to an initialized vector the ids
+ *    of the vertices in the second partition will be stored here. 
+ *    The vector will be resized as needed. This argument is ignored
+ *    if it is a NULL pointer.
+ * \param cut Pointer to an initialized vector, the ids of the edges
+ *    in the cut will be stored here. This argument is ignored if it
+ *    is a NULL pointer.
+ * \param capacity A numeric vector giving the capacities of the
+ *    edges. If a null pointer then all edges have unit capacity.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_mincut_value(), a simpler interface for calculating
+ * the value of the cut only.
+ *
+ * Time complexity: for directed graphs it is O(|V|^4), but see the
+ * remarks at \ref igraph_maxflow(). For undirected graphs it is
+ * O(|V||E|+|V|^2 log|V|). |V| and |E| are the number of vertices and
+ * edges respectively.
+ * 
+ * \example examples/simple/igraph_mincut.c
+ */
+
+int igraph_mincut(const igraph_t *graph,
+		  igraph_real_t *value,
+		  igraph_vector_t *partition,
+		  igraph_vector_t *partition2,
+		  igraph_vector_t *cut,
+		  const igraph_vector_t *capacity) {
+  
+  if (igraph_is_directed(graph)) {
+    if (partition || partition2 || cut) {
+      igraph_i_mincut_directed(graph, value, partition, partition2, cut, 
+			       capacity);
+    } else {
+      return igraph_mincut_value(graph, value, capacity);      
+    }
+  } else {
+    IGRAPH_CHECK(igraph_i_mincut_undirected(graph, value, partition,
+					    partition2, cut, capacity));
+    return IGRAPH_SUCCESS;
+  }
+  
+  return 0;
+}
+    
+
+int igraph_i_mincut_value_undirected(const igraph_t *graph, 
+				     igraph_real_t *res,
+				     const igraph_vector_t *capacity) {
+  return igraph_i_mincut_undirected(graph, res, 0, 0, 0, capacity);
+}
+
+/** 
+ * \function igraph_mincut_value
+ * \brief The minimum edge cut in a graph
+ * 
+ * </para><para> The minimum edge cut in a graph is the total minimum
+ * weight of the edges needed to remove from the graph to make the
+ * graph \em not strongly connected. (If the original graph is not
+ * strongly connected then this is zero.) Note that in undirected
+ * graphs strong connectedness is the same as weak connectedness. </para>
+ * 
+ * <para> The minimum cut can be calculated with maximum flow
+ * techniques, although the current implementation does this only for
+ * directed graphs and a separate non-flow based implementation is
+ * used for undirected graphs. See Mechthild Stoer and Frank Wagner: A
+ * simple min-cut algorithm, Journal of the ACM 44 585--591, 1997.
+ * For directed graphs
+ * the maximum flow is calculated between a fixed vertex and all the
+ * other vertices in the graph and this is done in both
+ * directions. Then the minimum is taken to get the minimum cut.
+ * 
+ * \param graph The input graph. 
+ * \param res Pointer to a real variable, the result will be stored
+ *    here.
+ * \param capacity Pointer to the capacity vector, it should contain
+ *    the same number of non-negative numbers as the number of edges in
+ *    the graph. If a null pointer then all edges will have unit capacity.
+ * \return Error code.
+ *
+ * \sa \ref igraph_mincut(), \ref igraph_maxflow_value(), \ref
+ * igraph_st_mincut_value(). 
+ * 
+ * Time complexity: O(log(|V|)*|V|^2) for undirected graphs and 
+ * O(|V|^4) for directed graphs, but see also the discussion at the
+ * documentation of \ref igraph_maxflow_value().
+ */
+
+int igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, 
+			const igraph_vector_t *capacity) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_real_t minmaxflow, flow;
+  long int i;
+
+  minmaxflow=IGRAPH_INFINITY;
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_CHECK(igraph_i_mincut_value_undirected(graph, res, capacity));
+    return 0;
+  }    
+
+  for (i=1; i<no_of_nodes; i++) {
+    IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, 0, (igraph_integer_t) i,
+				      capacity, 0));
+    if (flow < minmaxflow) {
+      minmaxflow = flow;
+      if (flow==0) break;
+    }
+    IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, (igraph_integer_t) i, 0,
+				      capacity, 0));
+    if (flow < minmaxflow) {
+      minmaxflow = flow;
+      if (flow==0) break;
+    }
+  }
+
+  if (res) {
+    *res=minmaxflow;
+  }
+  
+  return 0;
+}
+
+int igraph_i_st_vertex_connectivity_directed(const igraph_t *graph,
+					     igraph_integer_t *res,
+					     igraph_integer_t source, 
+					     igraph_integer_t target,
+					     igraph_vconn_nei_t neighbors) {
+  
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_integer_t no_of_edges=(igraph_integer_t) igraph_ecount(graph);
+  igraph_vector_t edges;
+  igraph_real_t real_res;
+  igraph_t newgraph;
+  long int i;
+  igraph_bool_t conn1;
+  
+  if (source<0 || source>=no_of_nodes || target<0 || target>=no_of_nodes) {
+    IGRAPH_ERROR("Invalid source or target vertex", IGRAPH_EINVAL);
+  }
+
+  switch (neighbors) {
+  case IGRAPH_VCONN_NEI_ERROR:
+    IGRAPH_CHECK(igraph_are_connected(graph, source, target, &conn1));
+    if (conn1) {
+      IGRAPH_ERROR("vertices connected", IGRAPH_EINVAL);
+      return 0;
+    }
+    break;
+  case IGRAPH_VCONN_NEI_NEGATIVE:
+    IGRAPH_CHECK(igraph_are_connected(graph, source, target, &conn1));
+    if (conn1) {
+      *res=-1;
+      return 0;
+    }
+    break;
+  case IGRAPH_VCONN_NEI_NUMBER_OF_NODES:
+    IGRAPH_CHECK(igraph_are_connected(graph, source, target, &conn1));
+    if (conn1) {
+      *res=no_of_nodes;
+      return 0;
+    }
+    break;
+  case IGRAPH_VCONN_NEI_IGNORE:
+    break;
+  default:
+    IGRAPH_ERROR("Unknown `igraph_vconn_nei_t'", IGRAPH_EINVAL);
+    break;
+  }
+  
+  /* Create the new graph */
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, 2*(no_of_edges+no_of_nodes)));
+  IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
+  IGRAPH_CHECK(igraph_vector_resize(&edges, 2*(no_of_edges+no_of_nodes)));
+  
+  for (i=0; i<2*no_of_edges; i+=2) {
+    igraph_integer_t to=(igraph_integer_t) VECTOR(edges)[i+1];
+    if (to != source && to != target) {
+      VECTOR(edges)[i+1] = no_of_nodes + to;
+      }
+  }
+  
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(edges)[ 2*(no_of_edges+i)   ] = no_of_nodes+i;
+    VECTOR(edges)[ 2*(no_of_edges+i)+1 ] = i;
+  }
+  
+  IGRAPH_CHECK(igraph_create(&newgraph, &edges, 2*no_of_nodes, 
+			     igraph_is_directed(graph)));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+  
+  /* Do the maximum flow */
+  
+  no_of_nodes=igraph_vcount(&newgraph);
+  no_of_edges=igraph_ecount(&newgraph);
+  
+  IGRAPH_CHECK(igraph_maxflow_value(&newgraph, &real_res, 
+				    source, target, 0, 0));
+  *res = (igraph_integer_t)real_res;
+
+  igraph_destroy(&newgraph);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_st_vertex_connectivity_undirected(const igraph_t *graph, 
+					       igraph_integer_t *res,
+					       igraph_integer_t source,
+					       igraph_integer_t target,
+					       igraph_vconn_nei_t neighbors){
+  
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_t newgraph;
+  igraph_bool_t conn;
+  
+  if (source<0 || source>=no_of_nodes || target<0 || target>=no_of_nodes) {
+    IGRAPH_ERROR("Invalid source or target vertex", IGRAPH_EINVAL);
+  }
+
+  switch (neighbors) {
+  case IGRAPH_VCONN_NEI_ERROR:
+    IGRAPH_CHECK(igraph_are_connected(graph, source, target, &conn));
+    if (conn) { 
+      IGRAPH_ERROR("vertices connected", IGRAPH_EINVAL);      
+      return 0;
+    }
+    break;
+  case IGRAPH_VCONN_NEI_NEGATIVE:
+    IGRAPH_CHECK(igraph_are_connected(graph, source, target, &conn));
+    if (conn) {
+      *res=-1;
+      return 0;
+    }
+    break;
+  case IGRAPH_VCONN_NEI_NUMBER_OF_NODES:
+    IGRAPH_CHECK(igraph_are_connected(graph, source, target, &conn));
+    if (conn) {
+      *res=no_of_nodes;
+      return 0;
+    }
+    break;
+  case IGRAPH_VCONN_NEI_IGNORE:
+    break;
+  default:
+    IGRAPH_ERROR("Unknown `igraph_vconn_nei_t'", IGRAPH_EINVAL);
+    break;
+  }
+
+  IGRAPH_CHECK(igraph_copy(&newgraph, graph));
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+  IGRAPH_CHECK(igraph_to_directed(&newgraph, IGRAPH_TO_DIRECTED_MUTUAL));
+
+  IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(&newgraph, res, 
+							source, target, 
+							IGRAPH_VCONN_NEI_IGNORE));
+  
+  igraph_destroy(&newgraph);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_st_vertex_connectivity
+ * \brief The vertex connectivity of a pair of vertices
+ * 
+ * </para><para>The vertex connectivity of two vertices (\c source and
+ * \c target) is the minimum number of vertices that have to be
+ * deleted to eliminate all paths from \c source to \c
+ * target. Directed paths are considered in directed graphs.</para>
+ * 
+ * <para>The vertex connectivity of a pair is the same as the number
+ * of different (ie. node-independent) paths from source to
+ * target.</para> 
+ *
+ * <para>The current implementation uses maximum flow calculations to
+ * obtain the result.
+ * \param graph The input graph.
+ * \param res Pointer to an integer, the result will be stored here.
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \param neighbors A constant giving what to do if the two vertices
+ *     are connected. Possible values: 
+ *     \c IGRAPH_VCONN_NEI_ERROR, stop with an error message,
+ *     \c IGRAPH_VCONN_NEGATIVE, return -1.
+ *     \c IGRAPH_VCONN_NUMBER_OF_NODES, return the number of nodes.
+ *     \c IGRAPH_VCONN_IGNORE, ignore the fact that the two vertices
+ *        are connected and calculated the number of vertices needed
+ *        to eliminate all paths except for the trivial (direct) paths
+ *        between \c source and \c vertex. TOOD: what about neighbors?
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^3), but see the discussion at \ref
+ * igraph_maxflow_value(). 
+ * 
+ * \sa \ref igraph_vertex_connectivity(),
+ * \ref igraph_edge_connectivity(),
+ * \ref igraph_maxflow_value().
+ */
+
+int igraph_st_vertex_connectivity(const igraph_t *graph, 
+				  igraph_integer_t *res,
+				  igraph_integer_t source,
+				  igraph_integer_t target,
+				  igraph_vconn_nei_t neighbors) {
+
+  if (source == target) { 
+    IGRAPH_ERROR("source and target vertices are the same", IGRAPH_EINVAL);
+  }
+  
+  if (igraph_is_directed(graph)) {
+    IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(graph, res,
+							  source, target,
+							  neighbors));
+  } else {
+    IGRAPH_CHECK(igraph_i_st_vertex_connectivity_undirected(graph, res,
+							    source, target,
+							    neighbors));
+  }
+  
+  return 0;
+}
+
+int igraph_i_vertex_connectivity_directed(const igraph_t *graph, 
+					igraph_integer_t *res) {
+
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  long int i, j;
+  igraph_integer_t minconn=no_of_nodes-1, conn;
+
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<no_of_nodes; j++) {
+      if (i==j) { continue; }
+
+      IGRAPH_ALLOW_INTERRUPTION();
+
+      IGRAPH_CHECK(igraph_st_vertex_connectivity(graph, &conn, 
+					 (igraph_integer_t) i, 
+					 (igraph_integer_t) j, 
+					 IGRAPH_VCONN_NEI_NUMBER_OF_NODES));
+      if (conn < minconn) {
+	minconn = conn;
+	if (conn == 0) { break; }
+      }
+    }
+    if (conn == 0) { break; }
+  }
+
+  if (res) {
+    *res = minconn;
+  }
+
+  return 0;
+}
+
+int igraph_i_vertex_connectivity_undirected(const igraph_t *graph, 
+					    igraph_integer_t *res) {
+  igraph_t newgraph;
+
+  IGRAPH_CHECK(igraph_copy(&newgraph, graph));
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+  IGRAPH_CHECK(igraph_to_directed(&newgraph, IGRAPH_TO_DIRECTED_MUTUAL));
+  
+  IGRAPH_CHECK(igraph_i_vertex_connectivity_directed(&newgraph, res));
+  
+  igraph_destroy(&newgraph);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;  
+}
+
+/* Use that vertex.connectivity(G) <= edge.connectivity(G) <= min(degree(G)) */
+int igraph_i_connectivity_checks(const igraph_t *graph,
+				 igraph_integer_t *res,
+				 igraph_bool_t *found) {
+  igraph_bool_t conn;
+  *found=0;
+  IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_STRONG));
+  if (!conn) {
+    *res=0;
+    *found=1;
+  } else {
+    igraph_vector_t degree;
+    IGRAPH_VECTOR_INIT_FINALLY(&degree, 0);
+    if (!igraph_is_directed(graph)) {
+      IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(),
+				 IGRAPH_OUT, IGRAPH_LOOPS));
+      if (igraph_vector_min(&degree)==1) {
+	*res=1;
+	*found=1;
+      }
+    } else {
+      /* directed, check both in- & out-degree */
+      IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(),
+				 IGRAPH_OUT, IGRAPH_LOOPS));
+      if (igraph_vector_min(&degree)==1) {
+	*res=1;
+	*found=1;
+      } else {
+	IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(),
+				   IGRAPH_IN, IGRAPH_LOOPS));
+	if (igraph_vector_min(&degree)==1) {
+	  *res=1;
+	  *found=1;
+	}
+      }
+    }
+    igraph_vector_destroy(&degree);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_vertex_connectivity
+ * The vertex connectivity of a graph
+ * 
+ * </para><para> The vertex connectivity of a graph is the minimum
+ * vertex connectivity along each pairs of vertices in the graph.
+ * </para>
+ * <para> The vertex connectivity of a graph is the same as group
+ * cohesion as defined in Douglas R. White and Frank Harary: The
+ * cohesiveness of blocks in social networks: node connectivity and
+ * conditional density, Sociological Methodology 31:305--359, 2001.
+ * \param graph The input graph.
+ * \param res Pointer to an integer, the result will be stored here. 
+ * \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.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^5).
+ * 
+ * \sa \ref igraph_st_vertex_connectivity(), \ref igraph_maxflow_value(),
+ * and \ref igraph_edge_connectivity(). 
+ */
+
+int igraph_vertex_connectivity(const igraph_t *graph, igraph_integer_t *res, 
+			       igraph_bool_t checks) {
+
+  igraph_bool_t ret=0;
+
+  if (checks) {
+    IGRAPH_CHECK(igraph_i_connectivity_checks(graph, res, &ret));
+  }
+  
+  /* Are we done yet? */
+  if (!ret) {
+    if (igraph_is_directed(graph)) {
+      IGRAPH_CHECK(igraph_i_vertex_connectivity_directed(graph, res));
+    } else {
+      IGRAPH_CHECK(igraph_i_vertex_connectivity_undirected(graph, res));
+    }
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_st_edge_connectivity
+ * \brief Edge connectivity of a pair of vertices
+ * 
+ * </para><para> The edge connectivity of two vertices (\c source and
+ * \c target) in a graph is the minimum number of edges that
+ * have to be deleted from the graph to eliminate all paths from \c
+ * source to \c target.</para>
+ * 
+ * <para>This function uses the maximum flow algorithm to calculate
+ * the edge connectivity.
+ * \param graph The input graph, it has to be directed.
+ * \param res Pointer to an integer, the result will be stored here.
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \return Error code.
+ *
+ * Time complexity: O(|V|^3). 
+ * 
+ * \sa \ref igraph_maxflow_value(), \ref igraph_edge_connectivity(),
+ * \ref igraph_st_vertex_connectivity(), \ref
+ * igraph_vertex_connectivity().
+ */
+
+int igraph_st_edge_connectivity(const igraph_t *graph, igraph_integer_t *res,
+				igraph_integer_t source, 
+				igraph_integer_t target) {
+  igraph_real_t flow;
+
+  if (source == target) {
+    IGRAPH_ERROR("source and target vertices are the same", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, 0, 0));
+  *res = (igraph_integer_t) flow;
+
+  return 0;
+}
+
+
+/**
+ * \function igraph_edge_connectivity
+ * \brief The minimum edge connectivity in a graph.
+ * 
+ * </para><para> This is the minimum of the edge connectivity over all
+ * pairs of vertices in the graph. </para>
+ * 
+ * <para>
+ * The edge connectivity of a graph is the same as group adhesion as
+ * defined in Douglas R. White and Frank Harary: The cohesiveness of
+ * blocks in social networks: node connectivity and conditional
+ * density, Sociological Methodology 31:305--359, 2001.
+ * \param graph The input graph.
+ * \param res Pointer to an integer, the result will be stored here.
+ * \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 Error code.
+ * 
+ * Time complexity: O(log(|V|)*|V|^2) for undirected graphs and 
+ * O(|V|^4) for directed graphs, but see also the discussion at the
+ * documentation of \ref igraph_maxflow_value().
+ * 
+ * \sa \ref igraph_st_edge_connectivity(), \ref igraph_maxflow_value(), 
+ * \ref igraph_vertex_connectivity().
+ */
+
+int igraph_edge_connectivity(const igraph_t *graph, igraph_integer_t *res,
+			     igraph_bool_t checks) {
+  igraph_bool_t ret=0;
+  
+  /* Use that vertex.connectivity(G) <= edge.connectivity(G) <= min(degree(G)) */
+  if (checks) {
+    IGRAPH_CHECK(igraph_i_connectivity_checks(graph, res, &ret));
+  }  
+
+  if (!ret) {
+    igraph_real_t real_res;
+    IGRAPH_CHECK(igraph_mincut_value(graph, &real_res, 0));
+	*res = (igraph_integer_t)real_res;
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_edge_disjoint_paths
+ * \brief The maximum number of edge-disjoint paths between two vertices. 
+ * 
+ * </para><para> A set of paths between two vertices is called
+ * edge-disjoint if they do not share any edges. The maximum number of
+ * edge-disjoint paths are calculated by this function using maximum
+ * flow techniques. Directed paths are considered in directed
+ * graphs. </para>
+ * 
+ * <para> Note that the number of disjoint paths is the same as the
+ * edge connectivity of the two vertices using uniform edge weights.
+ * \param graph The input graph, can be directed or undirected.
+ * \param res Pointer to an integer variable, the result will be
+ *        stored here. 
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^3), but see the discussion at \ref
+ * igraph_maxflow_value().
+ * 
+ * \sa \ref igraph_vertex_disjoint_paths(), \ref
+ * igraph_st_edge_connectivity(), \ref igraph_maxflow_value().
+ */
+
+int igraph_edge_disjoint_paths(const igraph_t *graph, igraph_integer_t *res,
+			       igraph_integer_t source, 
+			       igraph_integer_t target) {
+
+  igraph_real_t flow;
+
+  if (source == target) {
+    IGRAPH_ERROR("Not implemented for source=target", IGRAPH_UNIMPLEMENTED);
+  }
+
+  IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, 0, 0));
+
+  *res = (igraph_integer_t) flow;
+  
+  return 0;
+}
+
+/**
+ * \function igraph_vertex_disjoint_paths
+ * \brief Maximum number of vertex-disjoint paths between two vertices.
+ * 
+ * </para><para> A set of paths between two vertices is called
+ * vertex-disjoint if they share no vertices. The calculation is
+ * performed by using maximum flow techniques. </para>
+ * 
+ * <para> Note that the number of vertex-disjoint paths is the same as
+ * the vertex connectivity of the two vertices in most cases (if the
+ * two vertices are not connected by an edge).
+ * \param graph The input graph.
+ * \param res Pointer to an integer variable, the result will be
+ *        stored here. 
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^3).
+ * 
+ * \sa \ref igraph_edge_disjoint_paths(), \ref
+ * igraph_vertex_connectivity(), \ref igraph_maxflow_value().
+ */
+
+int igraph_vertex_disjoint_paths(const igraph_t *graph, igraph_integer_t *res,
+				 igraph_integer_t source,
+				 igraph_integer_t target) {
+
+  igraph_bool_t conn;
+
+  if (source==target) {
+    IGRAPH_ERROR("The source==target case is not implemented",
+		 IGRAPH_UNIMPLEMENTED);
+  }
+
+  igraph_are_connected(graph, source, target, &conn);
+  if (conn) { 
+    /* We need to remove every (possibly directed) edge between source
+       and target and calculate the disjoint paths on the new
+       graph. Finally we add 1 for the removed connection(s).  */
+    igraph_es_t es;
+    igraph_vector_t v;
+    igraph_t newgraph;
+    IGRAPH_VECTOR_INIT_FINALLY(&v, 2);
+    VECTOR(v)[0]=source;
+    VECTOR(v)[1]=target;
+    IGRAPH_CHECK(igraph_es_multipairs(&es, &v, IGRAPH_DIRECTED));
+    IGRAPH_FINALLY(igraph_es_destroy, &es);
+    
+    IGRAPH_CHECK(igraph_copy(&newgraph, graph));    
+    IGRAPH_FINALLY(igraph_destroy, &newgraph);
+    IGRAPH_CHECK(igraph_delete_edges(&newgraph, es));
+
+    if (igraph_is_directed(graph)) {
+      IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(&newgraph, res,
+							    source, target,
+							    IGRAPH_VCONN_NEI_IGNORE));
+    } else {
+      IGRAPH_CHECK(igraph_i_st_vertex_connectivity_undirected(&newgraph, res,
+							      source, target, 
+							      IGRAPH_VCONN_NEI_IGNORE));
+    }
+
+    if (res) {
+      *res += 1;
+    }
+    
+    IGRAPH_FINALLY_CLEAN(3);
+    igraph_destroy(&newgraph);
+    igraph_es_destroy(&es);
+    igraph_vector_destroy(&v);
+  }
+
+  /* These do nothing if the two vertices are connected, 
+     so it is safe to call them. */
+
+  if (igraph_is_directed(graph)) {
+    IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(graph, res,
+							  source, target,
+							  IGRAPH_VCONN_NEI_IGNORE));
+  } else {
+    IGRAPH_CHECK(igraph_i_st_vertex_connectivity_undirected(graph, res,
+							    source, target,
+							    IGRAPH_VCONN_NEI_IGNORE));
+  }    
+  
+  return 0;
+}
+
+/**
+ * \function igraph_adhesion
+ * \brief Graph adhesion, this is (almost) the same as edge connectivity.
+ * 
+ * </para><para> This quantity is defined by White and Harary in
+ * The cohesiveness of blocks in social networks: node connectivity and
+ * conditional density, (Sociological Methodology 31:305--359, 2001)
+ * and basically it is the edge connectivity of the graph
+ * with uniform edge weights.
+ * \param graph The input graph, either directed or undirected.
+ * \param res Pointer to an integer, the result will be stored here.
+ * \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 adhesion is obviously zero. Otherwise
+ *    if the minimum degree is one then the adhesion is also
+ *    one. It is a good idea to perform these checks, as they can be
+ *    done quickly compared to the edge connectivity calculation itself. 
+ *    They were suggested by Peter McMahan, thanks Peter.
+* \return Error code.
+ * 
+ * Time complexity: O(log(|V|)*|V|^2) for undirected graphs and 
+ * O(|V|^4) for directed graphs, but see also the discussion at the
+ * documentation of \ref igraph_maxflow_value().
+ *
+ * \sa \ref igraph_cohesion(), \ref igraph_maxflow_value(), \ref
+ * igraph_edge_connectivity(), \ref igraph_mincut_value().
+ */
+
+int igraph_adhesion(const igraph_t *graph, igraph_integer_t *res,
+		    igraph_bool_t checks) {
+  return igraph_edge_connectivity(graph, res, checks);
+}
+
+/**
+ * \function igraph_cohesion
+ * \brief Graph cohesion, this is the same as vertex connectivity. 
+ * 
+ * </para><para> This quantity was defined by White and Harary in <quote>The
+ * cohesiveness of blocks in social networks: node connectivity and
+ * conditional density</quote>, (Sociological Methodology 31:305--359, 2001)
+ * and it is the same as the vertex connectivity of a 
+ * graph. 
+ * \param graph The input graph.
+ * \param res Pointer to an integer variable, the result will be
+ *        stored here.
+ * \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 cohesion is obviously zero. Otherwise
+ *    if the minimum degree is one then the cohesion is also
+ *    one. It is a good idea to perform these checks, as they can be
+ *    done quickly compared to the vertex connectivity calculation itself. 
+ *    They were suggested by Peter McMahan, thanks Peter.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^4), |V| is the number of vertices. In
+ * practice it is more like O(|V|^2), see \ref igraph_maxflow_value().
+ * 
+ * \sa \ref igraph_vertex_connectivity(), \ref igraph_adhesion(), 
+ * \ref igraph_maxflow_value().
+ */
+
+int igraph_cohesion(const igraph_t *graph, igraph_integer_t *res,
+		    igraph_bool_t checks) {
+  
+  IGRAPH_CHECK(igraph_vertex_connectivity(graph, res, checks));
+  return 0;
+}
+
+/**
+ * \function igraph_gomory_hu_tree
+ * \brief Gomory-Hu tree of a graph.
+ *
+ * </para><para>
+ * The Gomory-Hu tree is a concise representation of the value of all the
+ * maximum flows (or minimum cuts) in a graph. The vertices of the tree
+ * correspond exactly to the vertices of the original graph in the same order.
+ * Edges of the Gomory-Hu tree are annotated by flow values.  The value of
+ * the maximum flow (or minimum cut) between an arbitrary (u,v) vertex
+ * pair in the original graph is then given by the minimum flow value (i.e.
+ * edge annotation) along the shortest path between u and v in the
+ * Gomory-Hu tree.
+ *
+ * </para><para>This implementation uses Gusfield's algorithm to construct the
+ * Gomory-Hu tree. See the following paper for more details:
+ * 
+ * </para><para>
+ * Gusfield D: Very simple methods for all pairs network flow analysis. SIAM J
+ * Comput 19(1):143-155, 1990.
+ *
+ * \param graph The input graph.
+ * \param tree  Pointer to an uninitialized graph; the result will be
+ *              stored here.
+ * \param flows Pointer to an uninitialized vector; the flow values
+ *              corresponding to each edge in the Gomory-Hu tree will
+ *              be returned here. You may pass a NULL pointer here if you are
+ *              not interested in the flow values.
+ * \param capacity Vector containing the capacity of the edges. If NULL, then
+ *        every edge is considered to have capacity 1.0.
+ * \return Error code.
+ *
+ * Time complexity: O(|V|^4) since it performs a max-flow calculation
+ * between vertex zero and every other vertex and max-flow is
+ * O(|V|^3).
+ *
+ * \sa \ref igraph_maxflow()
+ */
+int igraph_gomory_hu_tree(const igraph_t *graph, igraph_t *tree,
+			  igraph_vector_t *flows, const igraph_vector_t *capacity) {
+
+  igraph_integer_t no_of_nodes = igraph_vcount(graph);
+  igraph_integer_t source, target, mid, i, n;
+  igraph_vector_t neighbors;
+  igraph_vector_t flow_values;
+  igraph_vector_t partition;
+  igraph_vector_t partition2;
+  igraph_real_t flow_value;
+
+  if (igraph_is_directed(graph)) {
+    IGRAPH_ERROR("Gomory-Hu tree can only be calculated for undirected graphs",
+	IGRAPH_EINVAL);
+  }
+  
+  /* Allocate memory */
+  IGRAPH_VECTOR_INIT_FINALLY(&neighbors, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&flow_values, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&partition, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&partition2, 0);
+
+  /* Initialize the tree: every edge points to node 0 */
+  /* Actually, this is done implicitly since both 'neighbors' and 'flow_values' are
+   * initialized to zero already */
+
+  /* For each source vertex except vertex zero... */
+  for (source = 1; source < no_of_nodes; source++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_PROGRESS("Gomory-Hu tree", (100.0 * (source - 1)) / (no_of_nodes-1), 0);
+
+    /* Find its current neighbor in the tree */
+    target = VECTOR(neighbors)[(long int)source];
+
+    /* Find the maximum flow between source and target */
+    IGRAPH_CHECK(igraph_maxflow(graph, &flow_value, 0, 0, &partition, &partition2,
+	  source, target, capacity, 0));
+
+    /* Store the maximum flow and determine which side each node is on */
+    VECTOR(flow_values)[(long int)source] = flow_value;
+
+    /* Update the tree */
+    /* igraph_maxflow() guarantees that the source vertex will be in &partition
+     * and not in &partition2 */
+    n = igraph_vector_size(&partition);
+    for (i = 0; i < n; i++) {
+      mid = VECTOR(partition)[i];
+      if (mid > source && VECTOR(neighbors)[(long int)mid] == target) {
+	VECTOR(neighbors)[(long int)mid] = source;
+      }
+    }
+  }
+
+  IGRAPH_PROGRESS("Gomory-Hu tree", 100.0, 0);
+  
+  /* Re-use the 'partition' vector as an edge list now */
+  IGRAPH_CHECK(igraph_vector_resize(&partition, 2*(no_of_nodes-1)));
+  for (i = 1, mid = 0; i < no_of_nodes; i++, mid += 2) {
+    VECTOR(partition)[(long int)mid]   = i;
+    VECTOR(partition)[(long int)mid+1] = VECTOR(neighbors)[(long int)i];
+  }
+
+  /* Create the tree graph; we use igraph_subgraph_edges here to keep the
+   * graph and vertex attributes */
+  IGRAPH_CHECK(igraph_subgraph_edges(graph, tree, igraph_ess_none(), 0));
+  IGRAPH_CHECK(igraph_add_edges(tree, &partition, 0));
+
+  /* Free the allocated memory */
+  igraph_vector_destroy(&partition2);
+  igraph_vector_destroy(&partition);
+  igraph_vector_destroy(&neighbors);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  /* Return the flow values to the caller */
+  if (flows != 0) {
+    IGRAPH_CHECK(igraph_vector_update(flows, &flow_values));
+    if (no_of_nodes > 0) {
+      igraph_vector_remove(flows, 0);
+    }
+  }
+
+  /* Free the remaining allocated memory */
+  igraph_vector_destroy(&flow_values);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return IGRAPH_SUCCESS;
+}
+
diff --git a/src/foreign-dl-header.h b/src/foreign-dl-header.h
new file mode 100644
index 0000000..16aaf61
--- /dev/null
+++ b/src/foreign-dl-header.h
@@ -0,0 +1,41 @@
+/* 
+   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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_types_internal.h"
+
+typedef enum { IGRAPH_DL_MATRIX, 
+	       IGRAPH_DL_EDGELIST1, IGRAPH_DL_NODELIST1 } igraph_i_dl_type_t;
+
+typedef struct {
+  void *scanner;
+  int eof;
+  int mode;
+  long int n;
+  long int from, to;
+  igraph_vector_t edges;
+  igraph_vector_t weights;
+  igraph_strvector_t labels;
+  igraph_trie_t trie;
+  igraph_i_dl_type_t type;
+  char errmsg[300];
+} igraph_i_dl_parsedata_t;
diff --git a/src/foreign-dl-lexer.c b/src/foreign-dl-lexer.c
new file mode 100644
index 0000000..4895632
--- /dev/null
+++ b/src/foreign-dl-lexer.c
@@ -0,0 +1,2231 @@
+#line 2 "foreign-dl-lexer.c"
+
+#line 4 "foreign-dl-lexer.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE igraph_dl_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via igraph_dl_yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void igraph_dl_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void igraph_dl_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_dl_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void igraph_dl_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_dl_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_dl_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void igraph_dl_yypop_buffer_state (yyscan_t yyscanner );
+
+static void igraph_dl_yyensure_buffer_stack (yyscan_t yyscanner );
+static void igraph_dl_yy_load_buffer_state (yyscan_t yyscanner );
+static void igraph_dl_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER igraph_dl_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE igraph_dl_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_dl_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_dl_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *igraph_dl_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *igraph_dl_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void igraph_dl_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer igraph_dl_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        igraph_dl_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_dl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        igraph_dl_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_dl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define igraph_dl_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (yy_size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 24
+#define YY_END_OF_BUFFER 25
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[129] =
+    {   0,
+        0,    0,    0,    0,    0,    0,   18,   18,   21,   21,
+       25,   23,   22,    1,    1,    4,   23,   23,   23,   23,
+       12,   11,   12,   12,   14,   15,   13,   17,   18,   17,
+       16,   20,   21,   19,   22,    1,    4,    0,    0,    0,
+        0,    0,    3,   12,   12,   12,   12,   14,   13,   17,
+       18,   16,   17,   17,   20,   21,   19,    0,    2,    0,
+        0,    3,   12,   12,   16,   17,   16,    0,    0,    0,
+       12,   12,    5,    0,    0,    5,   12,    0,    0,   12,
+        0,    0,    0,    6,   12,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    7,    9,    0,
+       10,    7,    7,    9,    8,   10,    8,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        2,    2,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    6,    7,    8,    9,    1,   10,   11,   10,
+       10,   10,   10,   10,   10,   10,   10,   12,    1,    1,
+       13,    1,    1,    1,   14,   15,    1,   16,   17,   18,
+       19,    1,   20,    1,    1,   21,   22,   23,   24,    1,
+        1,   25,   26,   27,   28,    1,    1,   29,    1,    1,
+        1,    1,    1,    1,    1,    1,   14,   15,    1,   16,
+
+       17,   18,   19,    1,   20,    1,    1,   21,   22,   23,
+       24,    1,    1,   25,   26,   27,   28,    1,    1,   29,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[30] =
+    {   0,
+        1,    2,    3,    3,    2,    1,    3,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[138] =
+    {   0,
+        0,   22,   44,   64,   84,   94,  104,  114,  124,  134,
+      287,  288,    4,  282,  282,    2,    1,  260,  269,   15,
+       29,  288,   39,   50,    0,  288,   34,    0,   52,   19,
+       64,    0,   54,   51,   74,  288,   67,  255,   88,  256,
+      265,  138,   98,  108,  118,  128,  144,    0,  145,    0,
+      151,  151,   72,  159,    0,  152,  153,  265,  169,  256,
+      260,  170,  171,  175,  171,  168,  173,  264,  261,  253,
+      184,  185,  288,  246,  246,  189,  193,  195,  197,  199,
+      205,  218,  209,  288,  210,    0,  255,  242,  245,  246,
+      248,  245,  249,  231,  228,  217,  211,  200,  184,  181,
+
+      172,  150,  138,  138,  128,  126,  106,   75,   66,   67,
+       45,   45,   36,   42,   39,   22,   26,  219,  211,    6,
+      220,  227,  228,  232,  237,  238,  242,  288,  247,  250,
+      253,  256,  259,  262,    7,    6,    0
+    } ;
+
+static yyconst flex_int16_t yy_def[138] =
+    {   0,
+      129,  129,  130,  130,  131,  131,  132,  132,  133,  133,
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+      134,  128,  134,  134,  135,  128,  135,  136,  128,  136,
+      136,  137,  128,  137,  128,  128,  128,  128,  128,  128,
+      128,  128,  128,  134,  128,  134,  134,  135,  128,  136,
+      128,  136,  136,  136,  137,  128,  137,  128,  128,  128,
+      128,  128,  134,  134,  136,  136,  136,  128,  128,  128,
+      134,  134,  128,  128,  128,  134,  134,  128,  128,  134,
+      128,  128,  128,  128,  128,   82,  128,  128,  128,  128,
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+      128,  128,  128,  128,  128,  128,  128,    0,  128,  128,
+      128,  128,  128,  128,  128,  128,  128
+    } ;
+
+static yyconst flex_int16_t yy_nxt[318] =
+    {   0,
+       55,   13,   14,   15,   13,   35,   50,   48,   35,   16,
+       16,   37,   37,  128,   38,   17,   42,   18,  128,   42,
+       19,   39,   20,   13,   14,   15,   13,   43,   52,   52,
+       45,   16,   16,   45,  125,   49,  121,   17,   49,   18,
+       45,  120,   19,   45,   20,   12,   14,   15,   22,  119,
+       22,   45,   46,   51,   45,   56,   51,  118,   56,   23,
+       57,   57,  117,   47,   24,   12,   14,   15,   22,  116,
+       22,  115,   53,   52,   52,   35,   37,   37,   35,   23,
+       54,   65,   65,  114,   24,   26,   14,   15,   26,   59,
+       12,  113,   59,   27,   27,   26,   14,   15,   26,   62,
+
+       12,  112,   62,   27,   27,   29,   14,   15,   29,   45,
+       12,   30,   45,   31,   31,   29,   14,   15,   29,   45,
+       12,   30,   45,   31,   31,   33,   14,   15,   33,   45,
+       12,  111,   45,   34,   34,   33,   14,   15,   33,   42,
+       12,  110,   42,   34,   34,   45,   49,  109,   45,   49,
+       43,  108,   51,   56,   63,   51,   56,  107,   64,   53,
+       52,   52,   57,   57,   66,  106,   66,   54,   67,   67,
+       59,   62,   45,   59,   62,   45,   45,   67,   67,   45,
+       65,   65,   67,   67,   71,   45,   45,   54,   45,   45,
+       45,   72,  105,   45,   45,   76,   81,   45,   83,   81,
+
+       85,   83,  104,   85,  103,   77,   81,   82,   84,   81,
+       83,   85,  124,   83,   85,  124,  102,   82,   80,   86,
+      122,  126,   86,  122,  126,   90,   90,  101,  122,  122,
+      123,  122,  122,  124,   87,   88,  124,  100,  127,  126,
+       89,  127,  126,  127,   99,   98,  127,   12,   12,   12,
+       21,   21,   21,   25,   25,   25,   28,   28,   28,   32,
+       32,   32,   44,   44,   97,   96,   95,   94,   93,   92,
+       91,   79,   78,   75,   74,   73,   70,   69,   68,   61,
+       60,   58,   41,   40,   36,   36,  128,   11,  128,  128,
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+      128,  128,  128,  128,  128,  128,  128
+    } ;
+
+static yyconst flex_int16_t yy_chk[318] =
+    {   0,
+      137,    1,    1,    1,    1,   13,  136,  135,   13,    1,
+        1,   16,   16,    0,   17,    1,   20,    1,    0,   20,
+        1,   17,    1,    2,    2,    2,    2,   20,   30,   30,
+       21,    2,    2,   21,  120,   27,  117,    2,   27,    2,
+       23,  116,    2,   23,    2,    3,    3,    3,    3,  115,
+        3,   24,   23,   29,   24,   33,   29,  114,   33,    3,
+       34,   34,  113,   24,    3,    4,    4,    4,    4,  112,
+        4,  111,   31,   31,   31,   35,   37,   37,   35,    4,
+       31,   53,   53,  110,    4,    5,    5,    5,    5,   39,
+        5,  109,   39,    5,    5,    6,    6,    6,    6,   43,
+
+        6,  108,   43,    6,    6,    7,    7,    7,    7,   44,
+        7,    7,   44,    7,    7,    8,    8,    8,    8,   45,
+        8,    8,   45,    8,    8,    9,    9,    9,    9,   46,
+        9,  107,   46,    9,    9,   10,   10,   10,   10,   42,
+       10,  106,   42,   10,   10,   47,   49,  105,   47,   49,
+       42,  104,   51,   56,   46,   51,   56,  103,   47,   52,
+       52,   52,   57,   57,   54,  102,   54,   52,   54,   54,
+       59,   62,   63,   59,   62,   63,   64,   66,   66,   64,
+       65,   65,   67,   67,   63,   71,   72,   65,   71,   72,
+       76,   64,  101,   76,   77,   71,   78,   77,   79,   78,
+
+       80,   79,  100,   80,   99,   72,   81,   78,   79,   81,
+       83,   85,  119,   83,   85,  119,   98,   81,   77,   82,
+      118,  121,   82,  118,  121,   83,   85,   97,  122,  123,
+      118,  122,  123,  124,   82,   82,  124,   96,  125,  126,
+       82,  125,  126,  127,   95,   94,  127,  129,  129,  129,
+      130,  130,  130,  131,  131,  131,  132,  132,  132,  133,
+      133,  133,  134,  134,   93,   92,   91,   90,   89,   88,
+       87,   75,   74,   70,   69,   68,   61,   60,   58,   41,
+       40,   38,   19,   18,   15,   14,   11,  128,  128,  128,
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+
+      128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
+      128,  128,  128,  128,  128,  128,  128
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "foreign-dl-lexer.l"
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+#line 24 "foreign-dl-lexer.l"
+
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include "foreign-dl-header.h"
+#include "foreign-dl-parser.h"
+#define YY_EXTRA_TYPE igraph_i_dl_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+#define YY_NO_INPUT 1
+
+#line 610 "foreign-dl-lexer.c"
+
+#define INITIAL 0
+#define LABELM 1
+#define FULLMATRIX 2
+#define EDGELIST 3
+#define NODELIST 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    yy_size_t yy_n_chars;
+    yy_size_t yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    YYLTYPE * yylloc_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+    #    define yylloc yyg->yylloc_r
+    
+int igraph_dl_yylex_init (yyscan_t* scanner);
+
+int igraph_dl_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int igraph_dl_yylex_destroy (yyscan_t yyscanner );
+
+int igraph_dl_yyget_debug (yyscan_t yyscanner );
+
+void igraph_dl_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE igraph_dl_yyget_extra (yyscan_t yyscanner );
+
+void igraph_dl_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *igraph_dl_yyget_in (yyscan_t yyscanner );
+
+void igraph_dl_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *igraph_dl_yyget_out (yyscan_t yyscanner );
+
+void igraph_dl_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t igraph_dl_yyget_leng (yyscan_t yyscanner );
+
+char *igraph_dl_yyget_text (yyscan_t yyscanner );
+
+int igraph_dl_yyget_lineno (yyscan_t yyscanner );
+
+void igraph_dl_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * igraph_dl_yyget_lval (yyscan_t yyscanner );
+
+void igraph_dl_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+       YYLTYPE *igraph_dl_yyget_lloc (yyscan_t yyscanner );
+    
+        void igraph_dl_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+    
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int igraph_dl_yywrap (yyscan_t yyscanner );
+#else
+extern int igraph_dl_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		yy_size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int igraph_dl_yylex \
+               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int igraph_dl_yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 84 "foreign-dl-lexer.l"
+
+
+#line 856 "foreign-dl-lexer.c"
+
+    yylval = yylval_param;
+
+    yylloc = yylloc_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			igraph_dl_yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				igraph_dl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		igraph_dl_yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 129 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 288 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 86 "foreign-dl-lexer.l"
+{ return NEWLINE; }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 88 "foreign-dl-lexer.l"
+{ return DL; }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 89 "foreign-dl-lexer.l"
+{
+  return NEQ; }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 91 "foreign-dl-lexer.l"
+{ return NUM; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 93 "foreign-dl-lexer.l"
+{ 
+  switch (yyextra->mode) { 
+  case 0: BEGIN(FULLMATRIX); 
+    break;
+  case 1: BEGIN(EDGELIST);
+    break;
+  case 2: BEGIN(NODELIST);
+    break;
+  } 
+  return DATA; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 104 "foreign-dl-lexer.l"
+{ BEGIN(LABELM); return LABELS; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 105 "foreign-dl-lexer.l"
+{
+  return LABELSEMBEDDED; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 107 "foreign-dl-lexer.l"
+{
+  yyextra->mode=0; return FORMATFULLMATRIX; }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 109 "foreign-dl-lexer.l"
+{
+  yyextra->mode=1; return FORMATEDGELIST1; }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 111 "foreign-dl-lexer.l"
+{
+  yyextra->mode=2; return FORMATNODELIST1; }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 114 "foreign-dl-lexer.l"
+{ /* eaten up */ }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 115 "foreign-dl-lexer.l"
+{ return LABEL; }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 117 "foreign-dl-lexer.l"
+{ return DIGIT; }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 118 "foreign-dl-lexer.l"
+{ return LABEL; }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 119 "foreign-dl-lexer.l"
+{ }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 121 "foreign-dl-lexer.l"
+{ return NUM; }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 122 "foreign-dl-lexer.l"
+{ return LABEL; }
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 123 "foreign-dl-lexer.l"
+{ }
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 125 "foreign-dl-lexer.l"
+{ return NUM; }
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 126 "foreign-dl-lexer.l"
+{ return LABEL; }
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 127 "foreign-dl-lexer.l"
+{ }
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 129 "foreign-dl-lexer.l"
+{ /* eaten up */ }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(LABELM):
+case YY_STATE_EOF(FULLMATRIX):
+case YY_STATE_EOF(EDGELIST):
+case YY_STATE_EOF(NODELIST):
+#line 131 "foreign-dl-lexer.l"
+{ 
+                          if (yyextra->eof) {
+			    yyterminate();
+			  } else {
+			    yyextra->eof=1;
+			    BEGIN(INITIAL);
+			    return EOFF;
+			  }			  
+                        }
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 141 "foreign-dl-lexer.l"
+{ return 0; }
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 143 "foreign-dl-lexer.l"
+ECHO;
+	YY_BREAK
+#line 1094 "foreign-dl-lexer.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * igraph_dl_yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( igraph_dl_yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of igraph_dl_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					igraph_dl_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			igraph_dl_yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) igraph_dl_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 129 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 129 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 128);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					igraph_dl_yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( igraph_dl_yywrap(yyscanner ) )
+						return 0;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void igraph_dl_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        igraph_dl_yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            igraph_dl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	igraph_dl_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	igraph_dl_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_dl_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		igraph_dl_yypop_buffer_state();
+	 *		igraph_dl_yypush_buffer_state(new_buffer);
+     */
+	igraph_dl_yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	igraph_dl_yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (igraph_dl_yywrap()) processing, but the only time this flag
+	 * is looked at is after igraph_dl_yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void igraph_dl_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE igraph_dl_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) igraph_dl_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_dl_yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) igraph_dl_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_dl_yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	igraph_dl_yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with igraph_dl_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void igraph_dl_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		igraph_dl_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	igraph_dl_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a igraph_dl_yyrestart() or at EOF.
+ */
+    static void igraph_dl_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	igraph_dl_yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then igraph_dl_yy_init_buffer was _probably_
+     * called from igraph_dl_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_dl_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		igraph_dl_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_dl_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	igraph_dl_yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from igraph_dl_yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from igraph_dl_yy_switch_to_buffer. */
+	igraph_dl_yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_dl_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	igraph_dl_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		igraph_dl_yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void igraph_dl_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	yy_size_t num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_dl_yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_dl_yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_dl_yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_dl_yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE igraph_dl_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) igraph_dl_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_dl_yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	igraph_dl_yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to igraph_dl_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       igraph_dl_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE igraph_dl_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return igraph_dl_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to igraph_dl_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE igraph_dl_yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n, i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) igraph_dl_yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_dl_yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = igraph_dl_yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in igraph_dl_yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE igraph_dl_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_dl_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_dl_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_dl_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_dl_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t igraph_dl_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *igraph_dl_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void igraph_dl_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_dl_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_dl_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_dl_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_dl_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see igraph_dl_yy_switch_to_buffer
+ */
+void igraph_dl_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void igraph_dl_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int igraph_dl_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void igraph_dl_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * igraph_dl_yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void igraph_dl_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+YYLTYPE *igraph_dl_yyget_lloc  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylloc;
+}
+    
+void igraph_dl_yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylloc = yylloc_param;
+}
+    
+/* User-visible API */
+
+/* igraph_dl_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int igraph_dl_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) igraph_dl_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* igraph_dl_yylex_init_extra has the same functionality as igraph_dl_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to igraph_dl_yyalloc in
+ * the yyextra field.
+ */
+
+int igraph_dl_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    igraph_dl_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) igraph_dl_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    igraph_dl_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from igraph_dl_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * igraph_dl_yylex_init()
+     */
+    return 0;
+}
+
+/* igraph_dl_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int igraph_dl_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		igraph_dl_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		igraph_dl_yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	igraph_dl_yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        igraph_dl_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * igraph_dl_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    igraph_dl_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *igraph_dl_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *igraph_dl_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void igraph_dl_yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see igraph_dl_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 143 "foreign-dl-lexer.l"
diff --git a/src/foreign-dl-lexer.l b/src/foreign-dl-lexer.l
new file mode 100644
index 0000000..c234822
--- /dev/null
+++ b/src/foreign-dl-lexer.l
@@ -0,0 +1,142 @@
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include "foreign-dl-header.h"
+#include "foreign-dl-parser.h"
+#define YY_EXTRA_TYPE igraph_i_dl_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+%}
+
+%option noyywrap
+%option prefix="igraph_dl_yy"
+%option outfile="lex.yy.c"
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+digit      [0-9]
+whitespace [ \t\v\f]
+
+%x LABELM FULLMATRIX EDGELIST NODELIST
+
+%% 
+
+<*>\n\r|\r\n|\r|\n         { return NEWLINE; }
+
+[dD][lL]{whitespace}+      { return DL; }
+[nN]{whitespace}*[=]{whitespace}* {
+  return NEQ; }
+{digit}+                   { return NUM; }
+
+<INITIAL,LABELM>[dD][aA][tT][aA][:]        { 
+  switch (yyextra->mode) { 
+  case 0: BEGIN(FULLMATRIX); 
+    break;
+  case 1: BEGIN(EDGELIST);
+    break;
+  case 2: BEGIN(NODELIST);
+    break;
+  } 
+  return DATA; }
+
+[lL][aA][bB][eE][lL][sS]:  { BEGIN(LABELM); return LABELS; }
+<INITIAL,LABELM>[lL][aA][bB][eE][lL][sS]{whitespace}+[eE][mM][bB][eE][dD][dD][eE][dD]:?{whitespace}* {
+  return LABELSEMBEDDED; }
+[fF][oO][rR][mM][aA][tT]{whitespace}*[=]{whitespace}*[fF][uU][lL][lL][mM][aA][tT][rR][iI][xX]{whitespace}* {
+  yyextra->mode=0; return FORMATFULLMATRIX; }
+[fF][oO][rR][mM][aA][tT]{whitespace}*[=]{whitespace}*[eE][dD][gG][eE][lL][iI][sS][tT][1]{whitespace}* {
+  yyextra->mode=1; return FORMATEDGELIST1; }
+[fF][oO][rR][mM][aA][tT]{whitespace}*[=]{whitespace}*[nN][oO][dD][eE][lL][iI][sS][tT][1]{whitespace}* {
+  yyextra->mode=2; return FORMATNODELIST1; }
+
+<LABELM>[, ]                               { /* eaten up */ }
+<LABELM>[^, \t\n\r\f\v]+{whitespace}*      { return LABEL; }
+
+<FULLMATRIX>{digit}{whitespace}*          { return DIGIT; }
+<FULLMATRIX>[^ \t\n\r\v\f,]+              { return LABEL; }
+<FULLMATRIX>{whitespace}                  { }
+
+<EDGELIST>\-?{digit}+(\.{digit}+)?([eE](\+|\-)?{digit}+)?  { return NUM; }
+<EDGELIST>[^ \t\n\r\v\f,]+                                 { return LABEL; }
+<EDGELIST>{whitespace}*                                    { }
+
+<NODELIST>{digit}+                      { return NUM; }
+<NODELIST>[^ \t\r\n\v\f,]+              { return LABEL; }
+<NODELIST>{whitespace}*                 { }
+
+{whitespace}+                      { /* eaten up */ }
+
+<<EOF>>                 { 
+                          if (yyextra->eof) {
+			    yyterminate();
+			  } else {
+			    yyextra->eof=1;
+			    BEGIN(INITIAL);
+			    return EOFF;
+			  }			  
+                        }
+
+<*>. { return 0; }
+
diff --git a/src/foreign-dl-parser.c b/src/foreign-dl-parser.c
new file mode 100644
index 0000000..97d745f
--- /dev/null
+++ b/src/foreign-dl-parser.c
@@ -0,0 +1,2148 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 1
+
+/* Substitute the variable and function names.  */
+#define yyparse igraph_dl_yyparse
+#define yylex   igraph_dl_yylex
+#define yyerror igraph_dl_yyerror
+#define yylval  igraph_dl_yylval
+#define yychar  igraph_dl_yychar
+#define yydebug igraph_dl_yydebug
+#define yynerrs igraph_dl_yynerrs
+#define yylloc igraph_dl_yylloc
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NUM = 258,
+     NEWLINE = 259,
+     DL = 260,
+     NEQ = 261,
+     DATA = 262,
+     LABELS = 263,
+     LABELSEMBEDDED = 264,
+     FORMATFULLMATRIX = 265,
+     FORMATEDGELIST1 = 266,
+     FORMATNODELIST1 = 267,
+     DIGIT = 268,
+     LABEL = 269,
+     EOFF = 270
+   };
+#endif
+/* Tokens.  */
+#define NUM 258
+#define NEWLINE 259
+#define DL 260
+#define NEQ 261
+#define DATA 262
+#define LABELS 263
+#define LABELSEMBEDDED 264
+#define FORMATFULLMATRIX 265
+#define FORMATEDGELIST1 266
+#define FORMATNODELIST1 267
+#define DIGIT 268
+#define LABEL 269
+#define EOFF 270
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 23 "foreign-dl-parser.y"
+
+
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include "igraph_hacks_internal.h"
+#include "igraph_math.h"
+#include "igraph_types_internal.h"
+#include "foreign-dl-header.h"
+#include "foreign-dl-parser.h"
+#include <stdio.h>
+
+#define yyscan_t void*
+
+int igraph_dl_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);
+int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context, 
+		      const char *s);
+char *igraph_dl_yyget_text (yyscan_t yyscanner );
+int igraph_dl_yyget_leng (yyscan_t yyscanner );
+
+int igraph_i_dl_add_str(char *newstr, int length, 
+			igraph_i_dl_parsedata_t *context);
+int igraph_i_dl_add_edge(long int from, long int to,
+			 igraph_i_dl_parsedata_t *context);
+int igraph_i_dl_add_edge_w(long int from, long int to, 
+			   igraph_real_t weight,
+			   igraph_i_dl_parsedata_t *context);
+
+extern igraph_real_t igraph_pajek_get_number(const char *str, long int len);
+
+#define scanner context->scanner
+ 
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 91 "foreign-dl-parser.y"
+{
+  long int integer;
+  igraph_real_t real;
+}
+/* Line 193 of yacc.c.  */
+#line 198 "foreign-dl-parser.c"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 223 "foreign-dl-parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+    YYLTYPE yyls;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  4
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   118
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  16
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  37
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  66
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  137
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   270
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,    11,    12,    15,    16,    18,    20,    22,
+      24,    28,    30,    31,    33,    37,    45,    51,    52,    56,
+      57,    61,    62,    65,    67,    69,    73,    74,    78,    80,
+      82,    85,    89,    93,    96,   104,   110,   120,   130,   131,
+     134,   139,   143,   145,   146,   149,   154,   158,   160,   162,
+     166,   169,   177,   183,   193,   203,   204,   207,   211,   213,
+     214,   217,   218,   221,   225,   227,   228
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      17,     0,    -1,     5,     6,    38,     4,    20,    18,    19,
+      -1,    -1,    18,    22,    -1,    -1,    15,    -1,    21,    -1,
+      34,    -1,    43,    -1,    10,    22,    23,    -1,    23,    -1,
+      -1,     4,    -1,     7,    22,    25,    -1,     8,    22,    24,
+      22,     7,    22,    25,    -1,     9,    22,     7,    22,    28,
+      -1,    -1,    24,    22,    14,    -1,    -1,    25,    26,     4,
+      -1,    -1,    26,    27,    -1,    13,    -1,    29,    -1,    30,
+       4,    32,    -1,    -1,    30,    22,    31,    -1,    14,    -1,
+      33,    -1,    32,    33,    -1,    14,    26,     4,    -1,    11,
+      22,    35,    -1,     7,    36,    -1,     8,    22,    24,    22,
+       7,    22,    36,    -1,     9,    22,     7,    22,    39,    -1,
+       8,    22,    24,    22,     9,    22,     7,    22,    39,    -1,
+       9,    22,     8,    22,    24,    22,     7,    22,    39,    -1,
+      -1,    36,    37,    -1,    38,    38,    41,     4,    -1,    38,
+      38,     4,    -1,     3,    -1,    -1,    39,    40,    -1,    42,
+      42,    41,     4,    -1,    42,    42,     4,    -1,     3,    -1,
+      14,    -1,    12,    22,    44,    -1,     7,    45,    -1,     8,
+      22,    24,    22,     7,    22,    45,    -1,     9,    22,     7,
+      22,    49,    -1,     8,    22,    24,    22,     9,    22,     7,
+      22,    49,    -1,     9,    22,     8,    22,    24,    22,     7,
+      22,    49,    -1,    -1,    45,    46,    -1,    47,    48,     4,
+      -1,     3,    -1,    -1,    48,    38,    -1,    -1,    49,    50,
+      -1,    51,    52,     4,    -1,    42,    -1,    -1,    52,    42,
+      -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   115,   115,   117,   117,   119,   119,   121,   122,   123,
+     126,   126,   128,   128,   130,   131,   132,   135,   136,   142,
+     142,   147,   147,   149,   159,   161,   163,   163,   165,   169,
+     173,   178,   182,   184,   185,   186,   187,   188,   191,   192,
+     195,   197,   201,   204,   205,   208,   210,   214,   217,   233,
+     235,   236,   237,   238,   239,   242,   243,   246,   248,   251,
+     251,   257,   258,   261,   263,   267,   267
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "NUM", "NEWLINE", "DL", "NEQ", "DATA",
+  "LABELS", "LABELSEMBEDDED", "FORMATFULLMATRIX", "FORMATEDGELIST1",
+  "FORMATNODELIST1", "DIGIT", "LABEL", "EOFF", "$accept", "input", "trail",
+  "eof", "rest", "formfullmatrix", "newline", "fullmatrix", "labels",
+  "fullmatrixdata", "zerooneseq", "zeroone", "labeledfullmatrixdata",
+  "reallabeledfullmatrixdata", "labelseq", "label", "labeledmatrixlines",
+  "labeledmatrixline", "edgelist1", "edgelist1rest", "edgelist1data",
+  "edgelist1dataline", "integer", "labelededgelist1data",
+  "labelededgelist1dataline", "weight", "elabel", "nodelist1",
+  "nodelist1rest", "nodelist1data", "nodelist1dataline", "from", "tolist",
+  "labelednodelist1data", "labelednodelist1dataline", "fromelabel",
+  "labeltolist", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    16,    17,    18,    18,    19,    19,    20,    20,    20,
+      21,    21,    22,    22,    23,    23,    23,    24,    24,    25,
+      25,    26,    26,    27,    28,    29,    30,    30,    31,    32,
+      32,    33,    34,    35,    35,    35,    35,    35,    36,    36,
+      37,    37,    38,    39,    39,    40,    40,    41,    42,    43,
+      44,    44,    44,    44,    44,    45,    45,    46,    47,    48,
+      48,    49,    49,    50,    51,    52,    52
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     7,     0,     2,     0,     1,     1,     1,     1,
+       3,     1,     0,     1,     3,     7,     5,     0,     3,     0,
+       3,     0,     2,     1,     1,     3,     0,     3,     1,     1,
+       2,     3,     3,     2,     7,     5,     9,     9,     0,     2,
+       4,     3,     1,     0,     2,     4,     3,     1,     1,     3,
+       2,     7,     5,     9,     9,     0,     2,     3,     1,     0,
+       2,     0,     2,     3,     1,     0,     2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     0,     0,     0,     1,    42,     0,     0,    12,    12,
+      12,    12,    12,    12,     3,     7,    11,     8,     9,    13,
+      19,    17,     0,     0,     0,     0,     5,    14,    12,    12,
+      10,    38,    12,    12,    32,    55,    12,    12,    49,     6,
+       2,     4,     0,     0,    26,    33,    17,     0,    50,    17,
+       0,    20,    23,    22,    12,    18,    16,    24,    12,    39,
+       0,    12,    12,    12,    58,    56,    59,    12,    12,    12,
+      19,     0,     0,     0,     0,    43,    17,     0,     0,    61,
+      17,    15,    21,    25,    29,    28,    27,    47,    41,     0,
+      12,    12,    35,    12,    57,    60,    12,    12,    52,    12,
+       0,    30,    40,    38,     0,    48,    44,     0,     0,    55,
+       0,    64,    62,    65,     0,    31,    34,    12,     0,    12,
+      51,    12,     0,    12,    43,    46,     0,    43,    61,    63,
+      66,    61,    36,    45,    37,    53,    54
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     2,    26,    40,    14,    15,    20,    16,    28,    27,
+      42,    53,    56,    57,    58,    86,    83,    84,    17,    34,
+      45,    59,    60,    92,   106,    89,   107,    18,    38,    48,
+      65,    66,    77,    98,   112,   113,   122
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -93
+static const yytype_int8 yypact[] =
+{
+      41,     3,    38,    47,   -93,   -93,    57,    56,    76,    76,
+      76,    76,    76,    76,   -93,   -93,   -93,   -93,   -93,   -93,
+     -93,   -93,    89,    48,    66,    69,     7,    70,    76,    76,
+     -93,   -93,    76,    76,   -93,   -93,    76,    76,   -93,   -93,
+     -93,   -93,     8,    19,   -93,    47,   -93,     6,    86,   -93,
+      63,   -93,   -93,   -93,    76,   -93,   -93,   -93,    91,   -93,
+      47,    76,    76,    76,   -93,   -93,   -93,    76,    76,    76,
+     -93,    83,    84,    82,    22,   -93,   -93,    88,    25,   -93,
+     -93,    70,   -93,    83,   -93,   -93,   -93,   -93,   -93,    95,
+      76,    76,    87,    76,   -93,   -93,    76,    76,    87,    76,
+      12,   -93,   -93,   -93,    93,   -93,   -93,    87,    28,   -93,
+      96,   -93,   -93,   -93,    33,   -93,    47,    76,    90,    76,
+      86,    76,     4,    76,   -93,   -93,    98,   -93,   -93,   -93,
+     -93,   -93,    87,   -93,    87,    87,    87
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -93,   -93,   -93,   -93,   -93,   -93,    -9,    81,   -39,    35,
+      24,   -93,   -93,   -93,   -93,   -93,   -93,    26,   -93,   -93,
+      10,   -93,     2,   -76,   -93,   -11,   -92,   -93,   -93,     9,
+     -93,   -93,   -93,   -59,   -93,   -93,   -93
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -22
+static const yytype_int16 yytable[] =
+{
+      21,    22,    23,    24,    25,     6,   111,    61,   129,     3,
+      67,    19,    51,    62,    63,   118,   115,    41,   105,    43,
+      44,    52,    39,    46,    47,    52,    54,    49,    50,    90,
+     130,    91,    96,    55,    97,   119,    55,    93,     4,    55,
+     123,    99,    55,   111,   111,    70,     1,    55,   132,    72,
+       5,   134,    74,    75,    76,     8,     9,    10,    78,    79,
+      80,     7,    73,     8,     9,    10,    11,    12,    13,   135,
+      68,    69,   136,    31,    32,    33,    35,    36,    37,    95,
+      19,   103,   104,   -21,   108,    87,    88,   109,   110,    64,
+     114,     5,    94,    87,   125,    71,    29,    82,    85,   102,
+     117,   105,   133,   121,    30,    81,   100,   126,   124,   101,
+     127,     0,   128,   116,   131,     0,     0,     0,   120
+};
+
+static const yytype_int16 yycheck[] =
+{
+       9,    10,    11,    12,    13,     3,    98,    46,     4,     6,
+      49,     4,     4,     7,     8,   107,     4,    26,    14,    28,
+      29,    13,    15,    32,    33,    13,     7,    36,    37,     7,
+     122,     9,     7,    14,     9,     7,    14,    76,     0,    14,
+       7,    80,    14,   135,   136,    54,     5,    14,   124,    58,
+       3,   127,    61,    62,    63,     7,     8,     9,    67,    68,
+      69,     4,    60,     7,     8,     9,    10,    11,    12,   128,
+       7,     8,   131,     7,     8,     9,     7,     8,     9,    77,
+       4,    90,    91,    13,    93,     3,     4,    96,    97,     3,
+      99,     3,     4,     3,     4,     4,     7,    14,    14,     4,
+       7,    14,     4,     7,    23,    70,    82,   118,   117,    83,
+     119,    -1,   121,   103,   123,    -1,    -1,    -1,   109
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     5,    17,     6,     0,     3,    38,     4,     7,     8,
+       9,    10,    11,    12,    20,    21,    23,    34,    43,     4,
+      22,    22,    22,    22,    22,    22,    18,    25,    24,     7,
+      23,     7,     8,     9,    35,     7,     8,     9,    44,    15,
+      19,    22,    26,    22,    22,    36,    22,    22,    45,    22,
+      22,     4,    13,    27,     7,    14,    28,    29,    30,    37,
+      38,    24,     7,     8,     3,    46,    47,    24,     7,     8,
+      22,     4,    22,    38,    22,    22,    22,    48,    22,    22,
+      22,    25,    14,    32,    33,    14,    31,     3,     4,    41,
+       7,     9,    39,    24,     4,    38,     7,     9,    49,    24,
+      26,    33,     4,    22,    22,    14,    40,    42,    22,    22,
+      22,    42,    50,    51,    22,     4,    36,     7,    42,     7,
+      45,     7,    52,     7,    22,     4,    41,    22,    22,     4,
+      42,    22,    39,     4,    39,    49,    49
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, Location, context); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_dl_parsedata_t* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_dl_parsedata_t* context;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (yylocationp);
+  YYUSE (context);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_dl_parsedata_t* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_dl_parsedata_t* context;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, igraph_i_dl_parsedata_t* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+    YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
+    int yyrule;
+    igraph_i_dl_parsedata_t* context;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       , &(yylsp[(yyi + 1) - (yynrhs)])		       , context);
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+

+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, igraph_i_dl_parsedata_t* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
+    igraph_i_dl_parsedata_t* context;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (context);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (igraph_i_dl_parsedata_t* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (igraph_i_dl_parsedata_t* context)
+#else
+int
+yyparse (context)
+    igraph_i_dl_parsedata_t* context;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+/* Location data for the look-ahead symbol.  */
+YYLTYPE yylloc;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+  /* The locations where the error started and ended.  */
+  YYLTYPE yyerror_range[2];
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+  yylsp = yyls;
+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  /* Initialize the default location before parsing starts.  */
+  yylloc.first_line   = yylloc.last_line   = 1;
+  yylloc.first_column = yylloc.last_column = 0;
+#endif
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+	YYLTYPE *yyls1 = yyls;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+	yyls = yyls1;
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+	YYSTACK_RELOCATE (yyls);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 115 "foreign-dl-parser.y"
+    { context->n=(yyvsp[(3) - (7)].integer); }
+    break;
+
+  case 7:
+#line 121 "foreign-dl-parser.y"
+    { context->type=IGRAPH_DL_MATRIX; }
+    break;
+
+  case 8:
+#line 122 "foreign-dl-parser.y"
+    { context->type=IGRAPH_DL_EDGELIST1; }
+    break;
+
+  case 9:
+#line 123 "foreign-dl-parser.y"
+    { context->type=IGRAPH_DL_NODELIST1; }
+    break;
+
+  case 10:
+#line 126 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 11:
+#line 126 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 14:
+#line 130 "foreign-dl-parser.y"
+    { }
+    break;
+
+  case 15:
+#line 131 "foreign-dl-parser.y"
+    { }
+    break;
+
+  case 16:
+#line 132 "foreign-dl-parser.y"
+    { }
+    break;
+
+  case 17:
+#line 135 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 18:
+#line 136 "foreign-dl-parser.y"
+    { 
+	      igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), 
+                                  igraph_dl_yyget_leng(scanner), 
+				  context); }
+    break;
+
+  case 19:
+#line 142 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 20:
+#line 142 "foreign-dl-parser.y"
+    {
+  context->from += 1;
+  context->to = 0;
+ }
+    break;
+
+  case 22:
+#line 147 "foreign-dl-parser.y"
+    { }
+    break;
+
+  case 23:
+#line 149 "foreign-dl-parser.y"
+    {
+  if (igraph_dl_yyget_text(scanner)[0]=='1') {
+    IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+					 context->from));
+    IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+					 context->to));
+  }
+  context->to += 1;
+}
+    break;
+
+  case 24:
+#line 159 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 25:
+#line 161 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 28:
+#line 165 "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 "foreign-dl-parser.y"
+    {
+	         context->from += 1; 
+		 context->to = 0;
+               }
+    break;
+
+  case 30:
+#line 173 "foreign-dl-parser.y"
+    { 
+	         context->from += 1; 
+		 context->to = 0;
+               }
+    break;
+
+  case 31:
+#line 178 "foreign-dl-parser.y"
+    { }
+    break;
+
+  case 32:
+#line 182 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 33:
+#line 184 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 34:
+#line 185 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 35:
+#line 186 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 36:
+#line 187 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 37:
+#line 188 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 38:
+#line 191 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 39:
+#line 192 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 40:
+#line 195 "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 "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 "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 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 44:
+#line 205 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 45:
+#line 208 "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 "foreign-dl-parser.y"
+    {
+			  igraph_i_dl_add_edge((yyvsp[(1) - (3)].integer), (yyvsp[(2) - (3)].integer), context);
+ }
+    break;
+
+  case 47:
+#line 214 "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 "foreign-dl-parser.y"
+    {
+  /* Copy label list to trie, if needed */
+  if (igraph_strvector_size(&context->labels) != 0) {
+    long int i, id, n=igraph_strvector_size(&context->labels);
+    for (i=0; i<n; i++) {
+      igraph_trie_get(&context->trie,
+		      STR(context->labels, i), &id);
+    }
+    igraph_strvector_clear(&context->labels);
+  }
+  igraph_trie_get2(&context->trie, igraph_dl_yyget_text(scanner), 
+		   igraph_dl_yyget_leng(scanner), &(yyval.integer));
+ }
+    break;
+
+  case 49:
+#line 233 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 50:
+#line 235 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 51:
+#line 236 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 52:
+#line 237 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 53:
+#line 238 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 54:
+#line 239 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 55:
+#line 242 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 56:
+#line 243 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 57:
+#line 246 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 58:
+#line 248 "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 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 60:
+#line 251 "foreign-dl-parser.y"
+    { 
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+				       context->from-1)); 
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, (yyvsp[(2) - (2)].integer)-1));
+ }
+    break;
+
+  case 61:
+#line 257 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 62:
+#line 258 "foreign-dl-parser.y"
+    {}
+    break;
+
+  case 63:
+#line 261 "foreign-dl-parser.y"
+    { }
+    break;
+
+  case 64:
+#line 263 "foreign-dl-parser.y"
+    {
+  context->from=(yyvsp[(1) - (1)].integer);
+ }
+    break;
+
+  case 66:
+#line 267 "foreign-dl-parser.y"
+    {
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+				       context->from));
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, (yyvsp[(2) - (2)].integer)));
+ }
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 1887 "foreign-dl-parser.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (&yylloc, context, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (&yylloc, context, yymsg);
+	  }
+	else
+	  {
+	    yyerror (&yylloc, context, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+  yyerror_range[0] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, &yylloc, context);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[0] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      yyerror_range[0] = *yylsp;
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+  yyerror_range[1] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the look-ahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (&yylloc, context, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, &yylloc, context);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 273 "foreign-dl-parser.y"
+
+
+int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context, 
+		      const char *s) {
+  snprintf(context->errmsg, 
+	   sizeof(context->errmsg)/sizeof(char)-1, 
+	   "%s in line %i", s, locp->first_line);
+  return 0;
+}
+
+int igraph_i_dl_add_str(char *newstr, int length, 
+			igraph_i_dl_parsedata_t *context) {
+  int tmp=newstr[length];
+  newstr[length]='\0';
+  IGRAPH_CHECK(igraph_strvector_add(&context->labels, newstr));
+  newstr[length]=tmp;
+  return 0;
+}
+
+int igraph_i_dl_add_edge(long int from, long int to, 
+			 igraph_i_dl_parsedata_t *context) {
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, from));
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, to));
+  return 0;
+}
+
+int igraph_i_dl_add_edge_w(long int from, long int to, 
+			   igraph_real_t weight,
+			   igraph_i_dl_parsedata_t *context) {
+  long int n=igraph_vector_size(&context->weights);
+  long int n2=igraph_vector_size(&context->edges)/2;
+  if (n != n2) {
+    igraph_vector_resize(&context->weights, n2);
+    for (; n<n2; n++) {
+      VECTOR(context->weights)[n]=IGRAPH_NAN;
+    }
+  }
+  IGRAPH_CHECK(igraph_i_dl_add_edge(from, to, context));
+  IGRAPH_CHECK(igraph_vector_push_back(&context->weights, weight));
+  return 0;
+}
+
diff --git a/src/foreign-dl-parser.h b/src/foreign-dl-parser.h
new file mode 100644
index 0000000..9725571
--- /dev/null
+++ b/src/foreign-dl-parser.h
@@ -0,0 +1,105 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NUM = 258,
+     NEWLINE = 259,
+     DL = 260,
+     NEQ = 261,
+     DATA = 262,
+     LABELS = 263,
+     LABELSEMBEDDED = 264,
+     FORMATFULLMATRIX = 265,
+     FORMATEDGELIST1 = 266,
+     FORMATNODELIST1 = 267,
+     DIGIT = 268,
+     LABEL = 269,
+     EOFF = 270
+   };
+#endif
+/* Tokens.  */
+#define NUM 258
+#define NEWLINE 259
+#define DL 260
+#define NEQ 261
+#define DATA 262
+#define LABELS 263
+#define LABELSEMBEDDED 264
+#define FORMATFULLMATRIX 265
+#define FORMATEDGELIST1 266
+#define FORMATNODELIST1 267
+#define DIGIT 268
+#define LABEL 269
+#define EOFF 270
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 91 "foreign-dl-parser.y"
+{
+  long int integer;
+  igraph_real_t real;
+}
+/* Line 1529 of yacc.c.  */
+#line 84 "foreign-dl-parser.h"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
diff --git a/src/foreign-dl-parser.y b/src/foreign-dl-parser.y
new file mode 100644
index 0000000..8a04651
--- /dev/null
+++ b/src/foreign-dl-parser.y
@@ -0,0 +1,313 @@
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include "igraph_hacks_internal.h"
+#include "igraph_math.h"
+#include "igraph_types_internal.h"
+#include "foreign-dl-header.h"
+#include "foreign-dl-parser.h"
+#include <stdio.h>
+
+#define yyscan_t void*
+
+int igraph_dl_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);
+int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context, 
+		      const char *s);
+char *igraph_dl_yyget_text (yyscan_t yyscanner );
+int igraph_dl_yyget_leng (yyscan_t yyscanner );
+
+int igraph_i_dl_add_str(char *newstr, int length, 
+			igraph_i_dl_parsedata_t *context);
+int igraph_i_dl_add_edge(long int from, long int to,
+			 igraph_i_dl_parsedata_t *context);
+int igraph_i_dl_add_edge_w(long int from, long int to, 
+			   igraph_real_t weight,
+			   igraph_i_dl_parsedata_t *context);
+
+extern igraph_real_t igraph_pajek_get_number(const char *str, long int len);
+
+#define scanner context->scanner
+ 
+%}
+
+%pure-parser
+%output="y.tab.c"
+%name-prefix="igraph_dl_yy"
+%defines
+%locations
+%error-verbose
+%parse-param { igraph_i_dl_parsedata_t* context }
+%lex-param { void* scanner }
+
+%union {
+  long int integer;
+  igraph_real_t real;
+};
+
+%type <integer> integer elabel;
+%type <real> weight;
+
+%token NUM
+%token NEWLINE
+%token DL
+%token NEQ
+%token DATA
+%token LABELS
+%token LABELSEMBEDDED
+%token FORMATFULLMATRIX
+%token FORMATEDGELIST1
+%token FORMATNODELIST1
+%token DIGIT
+%token LABEL
+%token EOFF
+
+%%
+
+input: DL NEQ integer NEWLINE rest trail eof { context->n=$3; };
+
+trail: | trail newline;
+
+eof: | EOFF;
+
+rest:    formfullmatrix { context->type=IGRAPH_DL_MATRIX; }
+      |  edgelist1      { context->type=IGRAPH_DL_EDGELIST1; }
+      |  nodelist1      { context->type=IGRAPH_DL_NODELIST1; }
+; 
+
+formfullmatrix:  FORMATFULLMATRIX newline fullmatrix {} | fullmatrix {} ;
+
+newline: | NEWLINE ;
+
+fullmatrix:   DATA newline fullmatrixdata { }
+            | LABELS newline labels newline DATA newline fullmatrixdata { }
+            | LABELSEMBEDDED newline DATA newline labeledfullmatrixdata { }
+;
+
+labels: 	    {}		/* nothing, empty matrix */
+            | labels newline LABEL { 
+	      igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), 
+                                  igraph_dl_yyget_leng(scanner), 
+				  context); }
+;
+
+fullmatrixdata: {} | fullmatrixdata zerooneseq NEWLINE {
+  context->from += 1;
+  context->to = 0;
+ } ;
+
+zerooneseq: | zerooneseq zeroone { } ;
+
+zeroone: DIGIT {
+  if (igraph_dl_yyget_text(scanner)[0]=='1') {
+    IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+					 context->from));
+    IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+					 context->to));
+  }
+  context->to += 1;
+} ;
+
+labeledfullmatrixdata: reallabeledfullmatrixdata {} ;
+
+reallabeledfullmatrixdata: labelseq NEWLINE labeledmatrixlines {} ;
+
+labelseq: | labelseq newline label ;
+
+label: LABEL { igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), 
+                                   igraph_dl_yyget_leng(scanner), 
+				   context); };
+
+labeledmatrixlines: labeledmatrixline {
+	         context->from += 1; 
+		 context->to = 0;
+               } 
+             | labeledmatrixlines labeledmatrixline { 
+	         context->from += 1; 
+		 context->to = 0;
+               };
+
+labeledmatrixline: LABEL zerooneseq NEWLINE { } ;
+
+/*-----------------------------------------------------------*/
+
+edgelist1: FORMATEDGELIST1 newline edgelist1rest {} ;
+
+edgelist1rest:   DATA edgelist1data {}
+             | LABELS newline labels newline DATA newline edgelist1data {}
+             | LABELSEMBEDDED newline DATA newline labelededgelist1data {}
+             | LABELS newline labels newline LABELSEMBEDDED newline DATA newline labelededgelist1data {}
+             | LABELSEMBEDDED newline LABELS newline labels newline DATA newline labelededgelist1data {}
+;
+
+edgelist1data: 		{}	/* nothing, empty graph */
+             | edgelist1data edgelist1dataline {}
+;
+
+edgelist1dataline: integer integer weight NEWLINE {
+                   igraph_i_dl_add_edge_w($1-1, $2-1, $3, context); }
+                 | integer integer NEWLINE {
+		   igraph_i_dl_add_edge($1-1, $2-1, context);
+} ;
+
+integer: NUM { $$=igraph_pajek_get_number(igraph_dl_yyget_text(scanner), 
+					  igraph_dl_yyget_leng(scanner)); };
+
+labelededgelist1data: 	{}	/* nothing, empty graph */
+             | labelededgelist1data labelededgelist1dataline {}
+;
+
+labelededgelist1dataline: elabel elabel weight NEWLINE {
+                          igraph_i_dl_add_edge_w($1, $2, $3, context); }
+                        | elabel elabel NEWLINE {
+			  igraph_i_dl_add_edge($1, $2, context);
+ };
+
+weight: NUM { $$=igraph_pajek_get_number(igraph_dl_yyget_text(scanner), 
+					 igraph_dl_yyget_leng(scanner)); };
+
+elabel: LABEL {
+  /* Copy label list to trie, if needed */
+  if (igraph_strvector_size(&context->labels) != 0) {
+    long int i, id, n=igraph_strvector_size(&context->labels);
+    for (i=0; i<n; i++) {
+      igraph_trie_get(&context->trie,
+		      STR(context->labels, i), &id);
+    }
+    igraph_strvector_clear(&context->labels);
+  }
+  igraph_trie_get2(&context->trie, igraph_dl_yyget_text(scanner), 
+		   igraph_dl_yyget_leng(scanner), &$$);
+ };
+
+/*-----------------------------------------------------------*/
+
+nodelist1: FORMATNODELIST1 newline nodelist1rest {} ;
+
+nodelist1rest:   DATA nodelist1data {}
+             | LABELS newline labels newline DATA newline nodelist1data {}
+             | LABELSEMBEDDED newline DATA newline labelednodelist1data {}
+             | LABELS newline labels newline LABELSEMBEDDED newline DATA newline labelednodelist1data {}
+             | LABELSEMBEDDED newline LABELS newline labels newline DATA newline labelednodelist1data {}
+;
+
+nodelist1data: 		{}	/* nothing, empty graph */
+             | nodelist1data nodelist1dataline {}
+;
+
+nodelist1dataline: from tolist NEWLINE {} ;
+
+from: NUM { context->from=igraph_pajek_get_number(igraph_dl_yyget_text(scanner),
+							  igraph_dl_yyget_leng(scanner)); } ;
+
+tolist: {} | tolist integer { 
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+				       context->from-1)); 
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, $2-1));
+ } ;
+
+labelednodelist1data: 		{}	/* nothing, empty graph */
+           | labelednodelist1data labelednodelist1dataline {}
+;
+
+labelednodelist1dataline: fromelabel labeltolist NEWLINE { } ;
+
+fromelabel: elabel {
+  context->from=$1;
+ };
+
+labeltolist: | labeltolist elabel {
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
+				       context->from));
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, $2));
+ } ;
+
+%%
+
+int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context, 
+		      const char *s) {
+  snprintf(context->errmsg, 
+	   sizeof(context->errmsg)/sizeof(char)-1, 
+	   "%s in line %i", s, locp->first_line);
+  return 0;
+}
+
+int igraph_i_dl_add_str(char *newstr, int length, 
+			igraph_i_dl_parsedata_t *context) {
+  int tmp=newstr[length];
+  newstr[length]='\0';
+  IGRAPH_CHECK(igraph_strvector_add(&context->labels, newstr));
+  newstr[length]=tmp;
+  return 0;
+}
+
+int igraph_i_dl_add_edge(long int from, long int to, 
+			 igraph_i_dl_parsedata_t *context) {
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, from));
+  IGRAPH_CHECK(igraph_vector_push_back(&context->edges, to));
+  return 0;
+}
+
+int igraph_i_dl_add_edge_w(long int from, long int to, 
+			   igraph_real_t weight,
+			   igraph_i_dl_parsedata_t *context) {
+  long int n=igraph_vector_size(&context->weights);
+  long int n2=igraph_vector_size(&context->edges)/2;
+  if (n != n2) {
+    igraph_vector_resize(&context->weights, n2);
+    for (; n<n2; n++) {
+      VECTOR(context->weights)[n]=IGRAPH_NAN;
+    }
+  }
+  IGRAPH_CHECK(igraph_i_dl_add_edge(from, to, context));
+  IGRAPH_CHECK(igraph_vector_push_back(&context->weights, weight));
+  return 0;
+}
diff --git a/src/foreign-gml-header.h b/src/foreign-gml-header.h
new file mode 100644
index 0000000..4c6e58b
--- /dev/null
+++ b/src/foreign-gml-header.h
@@ -0,0 +1,30 @@
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi at rmki.kfki.hu>
+   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_gml_tree.h"
+
+typedef struct {
+  void *scanner;
+  int eof;
+  char errmsg[300];
+  igraph_gml_tree_t *tree;
+} igraph_i_gml_parsedata_t;
diff --git a/src/foreign-gml-lexer.c b/src/foreign-gml-lexer.c
new file mode 100644
index 0000000..872edf4
--- /dev/null
+++ b/src/foreign-gml-lexer.c
@@ -0,0 +1,2054 @@
+#line 2 "foreign-gml-lexer.c"
+
+#line 4 "foreign-gml-lexer.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE igraph_gml_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via igraph_gml_yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void igraph_gml_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void igraph_gml_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_gml_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void igraph_gml_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_gml_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_gml_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void igraph_gml_yypop_buffer_state (yyscan_t yyscanner );
+
+static void igraph_gml_yyensure_buffer_stack (yyscan_t yyscanner );
+static void igraph_gml_yy_load_buffer_state (yyscan_t yyscanner );
+static void igraph_gml_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER igraph_gml_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE igraph_gml_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_gml_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_gml_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *igraph_gml_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *igraph_gml_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void igraph_gml_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer igraph_gml_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        igraph_gml_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_gml_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        igraph_gml_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_gml_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define igraph_gml_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (yy_size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 9
+#define YY_END_OF_BUFFER 10
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[29] =
+    {   0,
+        0,    0,   10,    9,    8,    7,    7,    9,    9,    3,
+        4,    5,    6,    1,    9,    7,    0,    2,    3,    0,
+        0,    4,    0,    1,    3,    0,    3,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    5,    6,    1,    1,    1,    1,    1,
+        1,    1,    7,    1,    8,    9,    1,   10,   10,   10,
+       10,   10,   10,   10,   10,   10,   10,    1,    1,    1,
+        1,    1,    1,    1,   11,   11,   11,   11,   12,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       13,    1,   14,    1,   11,    1,   11,   11,   11,   11,
+
+       12,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[15] =
+    {   0,
+        1,    1,    1,    2,    1,    1,    1,    1,    1,    3,
+        3,    3,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[32] =
+    {   0,
+        0,   11,   42,   43,   43,   37,   37,   34,   28,    9,
+        0,   43,   43,   34,   33,   43,   30,   43,    0,   24,
+       15,    0,   30,   43,   14,   21,   10,   43,   26,   13,
+       29
+    } ;
+
+static yyconst flex_int16_t yy_def[32] =
+    {   0,
+       28,    1,   28,   28,   28,   28,   28,   29,   28,   28,
+       30,   28,   28,   28,   31,   28,   29,   28,   10,   28,
+       28,   30,   31,   28,   28,   28,   28,    0,   28,   28,
+       28
+    } ;
+
+static yyconst flex_int16_t yy_nxt[58] =
+    {   0,
+        4,    5,    6,    7,    8,    4,    4,    9,    4,   10,
+       11,   11,   12,   13,   14,   22,   15,   20,   19,   27,
+       21,   26,   26,   25,   27,   21,   17,   17,   17,   23,
+       27,   23,   24,   25,   18,   24,   16,   19,   18,   16,
+       16,   28,    3,   28,   28,   28,   28,   28,   28,   28,
+       28,   28,   28,   28,   28,   28,   28
+    } ;
+
+static yyconst flex_int16_t yy_chk[58] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    2,   30,    2,   10,   10,   27,
+       10,   21,   21,   25,   21,   25,   29,   29,   29,   31,
+       26,   31,   23,   20,   17,   15,   14,    9,    8,    7,
+        6,    3,   28,   28,   28,   28,   28,   28,   28,   28,
+       28,   28,   28,   28,   28,   28,   28
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "foreign-gml-lexer.l"
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+#line 24 "foreign-gml-lexer.l"
+
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-gml-header.h"
+#include "foreign-gml-parser.h"
+#define YY_EXTRA_TYPE igraph_i_gml_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+#define YY_NO_INPUT 1
+#line 518 "foreign-gml-lexer.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    yy_size_t yy_n_chars;
+    yy_size_t yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    YYLTYPE * yylloc_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+    #    define yylloc yyg->yylloc_r
+    
+int igraph_gml_yylex_init (yyscan_t* scanner);
+
+int igraph_gml_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int igraph_gml_yylex_destroy (yyscan_t yyscanner );
+
+int igraph_gml_yyget_debug (yyscan_t yyscanner );
+
+void igraph_gml_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE igraph_gml_yyget_extra (yyscan_t yyscanner );
+
+void igraph_gml_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *igraph_gml_yyget_in (yyscan_t yyscanner );
+
+void igraph_gml_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *igraph_gml_yyget_out (yyscan_t yyscanner );
+
+void igraph_gml_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t igraph_gml_yyget_leng (yyscan_t yyscanner );
+
+char *igraph_gml_yyget_text (yyscan_t yyscanner );
+
+int igraph_gml_yyget_lineno (yyscan_t yyscanner );
+
+void igraph_gml_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * igraph_gml_yyget_lval (yyscan_t yyscanner );
+
+void igraph_gml_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+       YYLTYPE *igraph_gml_yyget_lloc (yyscan_t yyscanner );
+    
+        void igraph_gml_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+    
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int igraph_gml_yywrap (yyscan_t yyscanner );
+#else
+extern int igraph_gml_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		yy_size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int igraph_gml_yylex \
+               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int igraph_gml_yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	if ( yyleng > 0 ) \
+		YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+				(yytext[yyleng - 1] == '\n'); \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 81 "foreign-gml-lexer.l"
+
+
+#line 763 "foreign-gml-lexer.c"
+
+    yylval = yylval_param;
+
+    yylloc = yylloc_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			igraph_gml_yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				igraph_gml_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		igraph_gml_yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+		yy_current_state += YY_AT_BOL();
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 29 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 43 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 83 "foreign-gml-lexer.l"
+{ /* comments ignored */ }
+	YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 85 "foreign-gml-lexer.l"
+{ return STRING; }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 86 "foreign-gml-lexer.l"
+{ return NUM; }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 87 "foreign-gml-lexer.l"
+{ return KEYWORD; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 88 "foreign-gml-lexer.l"
+{ return LISTOPEN; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 89 "foreign-gml-lexer.l"
+{ return LISTCLOSE; }
+	YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 90 "foreign-gml-lexer.l"
+{ }
+	YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+#line 91 "foreign-gml-lexer.l"
+{ /* other whitespace ignored */ }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 93 "foreign-gml-lexer.l"
+{ 
+                          if (yyextra->eof) {
+			    yyterminate();
+			  } else {
+			    yyextra->eof=1;
+			    return EOFF;
+			  }			  
+                        }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 102 "foreign-gml-lexer.l"
+ECHO;
+	YY_BREAK
+#line 911 "foreign-gml-lexer.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * igraph_gml_yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( igraph_gml_yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of igraph_gml_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					igraph_gml_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			igraph_gml_yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) igraph_gml_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+	yy_current_state += YY_AT_BOL();
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 29 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 29 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 28);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					igraph_gml_yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( igraph_gml_yywrap(yyscanner ) )
+						return 0;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void igraph_gml_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        igraph_gml_yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            igraph_gml_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	igraph_gml_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	igraph_gml_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_gml_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		igraph_gml_yypop_buffer_state();
+	 *		igraph_gml_yypush_buffer_state(new_buffer);
+     */
+	igraph_gml_yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	igraph_gml_yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (igraph_gml_yywrap()) processing, but the only time this flag
+	 * is looked at is after igraph_gml_yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void igraph_gml_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE igraph_gml_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) igraph_gml_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_gml_yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) igraph_gml_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_gml_yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	igraph_gml_yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with igraph_gml_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void igraph_gml_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		igraph_gml_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	igraph_gml_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a igraph_gml_yyrestart() or at EOF.
+ */
+    static void igraph_gml_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	igraph_gml_yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then igraph_gml_yy_init_buffer was _probably_
+     * called from igraph_gml_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_gml_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		igraph_gml_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_gml_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	igraph_gml_yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from igraph_gml_yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from igraph_gml_yy_switch_to_buffer. */
+	igraph_gml_yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_gml_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	igraph_gml_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		igraph_gml_yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void igraph_gml_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	yy_size_t num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_gml_yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_gml_yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_gml_yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_gml_yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE igraph_gml_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) igraph_gml_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_gml_yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	igraph_gml_yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to igraph_gml_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       igraph_gml_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE igraph_gml_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return igraph_gml_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to igraph_gml_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE igraph_gml_yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n, i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) igraph_gml_yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_gml_yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = igraph_gml_yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in igraph_gml_yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE igraph_gml_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_gml_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_gml_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_gml_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_gml_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t igraph_gml_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *igraph_gml_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void igraph_gml_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_gml_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_gml_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_gml_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_gml_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see igraph_gml_yy_switch_to_buffer
+ */
+void igraph_gml_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void igraph_gml_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int igraph_gml_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void igraph_gml_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * igraph_gml_yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void igraph_gml_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+YYLTYPE *igraph_gml_yyget_lloc  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylloc;
+}
+    
+void igraph_gml_yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylloc = yylloc_param;
+}
+    
+/* User-visible API */
+
+/* igraph_gml_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int igraph_gml_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) igraph_gml_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* igraph_gml_yylex_init_extra has the same functionality as igraph_gml_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to igraph_gml_yyalloc in
+ * the yyextra field.
+ */
+
+int igraph_gml_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    igraph_gml_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) igraph_gml_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    igraph_gml_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from igraph_gml_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * igraph_gml_yylex_init()
+     */
+    return 0;
+}
+
+/* igraph_gml_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int igraph_gml_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		igraph_gml_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		igraph_gml_yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	igraph_gml_yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        igraph_gml_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * igraph_gml_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    igraph_gml_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *igraph_gml_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *igraph_gml_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void igraph_gml_yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see igraph_gml_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 102 "foreign-gml-lexer.l"
+
+
+
diff --git a/src/foreign-gml-lexer.l b/src/foreign-gml-lexer.l
new file mode 100644
index 0000000..4d7354a
--- /dev/null
+++ b/src/foreign-gml-lexer.l
@@ -0,0 +1,102 @@
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-gml-header.h"
+#include "foreign-gml-parser.h"
+#define YY_EXTRA_TYPE igraph_i_gml_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+%}
+
+%option noyywrap
+%option prefix="igraph_gml_yy"
+%option outfile="lex.yy.c"
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+digit       [0-9]
+whitespace  [ \r\n\t]
+
+%%
+
+^#[^\n\r]*[\n]|[\r]     { /* comments ignored */ }
+
+\"[^\"]*\"                                      { return STRING; }
+\-?{digit}+(\.{digit}+)?([eE](\+|\-)?{digit}+)? { return NUM; }
+[a-zA-Z_][a-zA-Z_0-9]*  { return KEYWORD; }
+\[                      { return LISTOPEN; }
+\]                      { return LISTCLOSE; }
+\n\r|\r\n|\r|\n         { }
+{whitespace}            { /* other whitespace ignored */ }
+
+<<EOF>>                 { 
+                          if (yyextra->eof) {
+			    yyterminate();
+			  } else {
+			    yyextra->eof=1;
+			    return EOFF;
+			  }			  
+                        }
+
+%%
diff --git a/src/foreign-gml-parser.c b/src/foreign-gml-parser.c
new file mode 100644
index 0000000..425d106
--- /dev/null
+++ b/src/foreign-gml-parser.c
@@ -0,0 +1,1859 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 1
+
+/* Substitute the variable and function names.  */
+#define yyparse igraph_gml_yyparse
+#define yylex   igraph_gml_yylex
+#define yyerror igraph_gml_yyerror
+#define yylval  igraph_gml_yylval
+#define yychar  igraph_gml_yychar
+#define yydebug igraph_gml_yydebug
+#define yynerrs igraph_gml_yynerrs
+#define yylloc igraph_gml_yylloc
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     STRING = 258,
+     NUM = 259,
+     KEYWORD = 260,
+     LISTOPEN = 261,
+     LISTCLOSE = 262,
+     EOFF = 263
+   };
+#endif
+/* Tokens.  */
+#define STRING 258
+#define NUM 259
+#define KEYWORD 260
+#define LISTOPEN 261
+#define LISTCLOSE 262
+#define EOFF 263
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 23 "foreign-gml-parser.y"
+
+
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "igraph_error.h"
+#include "igraph_memory.h"
+#include "config.h"
+#include "igraph_hacks_internal.h"
+#include "igraph_math.h"
+#include "igraph_gml_tree.h"
+#include "foreign-gml-header.h"
+#include "foreign-gml-parser.h"
+
+#define yyscan_t void*
+
+int igraph_gml_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, void *scanner);
+int igraph_gml_yyerror(YYLTYPE* locp, igraph_i_gml_parsedata_t *context, 
+		       char *s);
+char *igraph_gml_yyget_text (yyscan_t yyscanner );
+int igraph_gml_yyget_leng (yyscan_t yyscanner );
+void igraph_i_gml_get_keyword(char *s, int len, void *res);
+void igraph_i_gml_get_string(char *s, int len, void *res);
+double igraph_i_gml_get_real(char *s, int len);
+igraph_gml_tree_t *igraph_i_gml_make_numeric(char* s, int len, double value);
+igraph_gml_tree_t *igraph_i_gml_make_numeric2(char* s, int len, 
+					      char *v, int vlen);
+igraph_gml_tree_t *igraph_i_gml_make_string(char* s, int len, 
+					    char *value, int valuelen);
+igraph_gml_tree_t *igraph_i_gml_make_list(char* s, int len, 
+					  igraph_gml_tree_t *list);
+igraph_gml_tree_t *igraph_i_gml_merge(igraph_gml_tree_t *t1, igraph_gml_tree_t* t2);
+
+#define scanner context->scanner
+#define USE(x) /*(x)*/
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 98 "foreign-gml-parser.y"
+{
+   struct {
+      char *s;
+      int len;
+   } str;
+   void *tree;
+   double real;
+}
+/* Line 193 of yacc.c.  */
+#line 195 "foreign-gml-parser.c"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 220 "foreign-gml-parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+    YYLTYPE yyls;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  6
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   14
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  9
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  7
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  12
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  17
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   263
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     5,     8,    10,    13,    16,    19,    24,
+      27,    29,    31
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      10,     0,    -1,    11,    -1,    11,     8,    -1,    12,    -1,
+      11,    12,    -1,    13,    14,    -1,    13,    15,    -1,    13,
+       6,    11,     7,    -1,    13,    13,    -1,     5,    -1,     4,
+      -1,     3,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,   125,   125,   126,   129,   130,   132,   134,   136,   138,
+     142,   145,   148
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "STRING", "NUM", "KEYWORD", "LISTOPEN",
+  "LISTCLOSE", "EOFF", "$accept", "input", "list", "keyvalue", "key",
+  "num", "string", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,     9,    10,    10,    11,    11,    12,    12,    12,    12,
+      13,    14,    15
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     2,     1,     2,     2,     2,     4,     2,
+       1,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,    10,     0,     2,     4,     0,     1,     3,     5,    12,
+      11,     0,     9,     6,     7,     0,     8
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     2,     3,     4,     5,    13,    14
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -4
+static const yytype_int8 yypact[] =
+{
+       1,    -4,    10,     0,    -4,    -2,    -4,    -4,    -4,    -4,
+      -4,     1,    -4,    -4,    -4,     2,    -4
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+      -4,    -4,     3,    -3,     6,    -4,    -4
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+       8,     9,    10,     1,    11,     1,     1,     1,     7,    16,
+       6,    12,     8,     0,    15
+};
+
+static const yytype_int8 yycheck[] =
+{
+       3,     3,     4,     5,     6,     5,     5,     5,     8,     7,
+       0,     5,    15,    -1,    11
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     5,    10,    11,    12,    13,     0,     8,    12,     3,
+       4,     6,    13,    14,    15,    11,     7
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, Location, context); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_gml_parsedata_t* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_gml_parsedata_t* context;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (yylocationp);
+  YYUSE (context);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_gml_parsedata_t* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_gml_parsedata_t* context;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, igraph_i_gml_parsedata_t* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+    YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
+    int yyrule;
+    igraph_i_gml_parsedata_t* context;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       , &(yylsp[(yyi + 1) - (yynrhs)])		       , context);
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+

+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, igraph_i_gml_parsedata_t* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
+    igraph_i_gml_parsedata_t* context;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (context);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 5: /* "KEYWORD" */
+#line 120 "foreign-gml-parser.y"
+	{ igraph_Free((yyvaluep->str).s); };
+#line 1124 "foreign-gml-parser.c"
+	break;
+      case 11: /* "list" */
+#line 121 "foreign-gml-parser.y"
+	{ igraph_gml_tree_destroy((yyvaluep->tree)); };
+#line 1129 "foreign-gml-parser.c"
+	break;
+      case 12: /* "keyvalue" */
+#line 121 "foreign-gml-parser.y"
+	{ igraph_gml_tree_destroy((yyvaluep->tree)); };
+#line 1134 "foreign-gml-parser.c"
+	break;
+      case 13: /* "key" */
+#line 120 "foreign-gml-parser.y"
+	{ igraph_Free((yyvaluep->str).s); };
+#line 1139 "foreign-gml-parser.c"
+	break;
+      case 15: /* "string" */
+#line 120 "foreign-gml-parser.y"
+	{ igraph_Free((yyvaluep->str).s); };
+#line 1144 "foreign-gml-parser.c"
+	break;
+
+      default:
+	break;
+    }
+}
+

+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (igraph_i_gml_parsedata_t* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (igraph_i_gml_parsedata_t* context)
+#else
+int
+yyparse (context)
+    igraph_i_gml_parsedata_t* context;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+/* Location data for the look-ahead symbol.  */
+YYLTYPE yylloc;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+  /* The locations where the error started and ended.  */
+  YYLTYPE yyerror_range[2];
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+  yylsp = yyls;
+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  /* Initialize the default location before parsing starts.  */
+  yylloc.first_line   = yylloc.last_line   = 1;
+  yylloc.first_column = yylloc.last_column = 0;
+#endif
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+	YYLTYPE *yyls1 = yyls;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+	yyls = yyls1;
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+	YYSTACK_RELOCATE (yyls);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 125 "foreign-gml-parser.y"
+    { context->tree=(yyvsp[(1) - (1)].tree); }
+    break;
+
+  case 3:
+#line 126 "foreign-gml-parser.y"
+    { context->tree=(yyvsp[(1) - (2)].tree); }
+    break;
+
+  case 4:
+#line 129 "foreign-gml-parser.y"
+    { (yyval.tree)=(yyvsp[(1) - (1)].tree); }
+    break;
+
+  case 5:
+#line 130 "foreign-gml-parser.y"
+    { (yyval.tree)=igraph_i_gml_merge((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)); }
+    break;
+
+  case 6:
+#line 133 "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 "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 "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 "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 "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 "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 "foreign-gml-parser.y"
+    { igraph_i_gml_get_string(igraph_gml_yyget_text(scanner), 
+					 igraph_gml_yyget_leng(scanner), 
+					 &(yyval.str)); }
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 1528 "foreign-gml-parser.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (&yylloc, context, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (&yylloc, context, yymsg);
+	  }
+	else
+	  {
+	    yyerror (&yylloc, context, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+  yyerror_range[0] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, &yylloc, context);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[0] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      yyerror_range[0] = *yylsp;
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+  yyerror_range[1] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the look-ahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (&yylloc, context, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, &yylloc, context);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 152 "foreign-gml-parser.y"
+
+
+int igraph_gml_yyerror(YYLTYPE* locp, igraph_i_gml_parsedata_t *context, 
+		       char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1, 
+	   "Parse error in GML file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+void igraph_i_gml_get_keyword(char *s, int len, void *res) {
+  struct { char *s; int len; } *p=res;
+  p->s=igraph_Calloc(len+1, char);
+  if (!p->s) { 
+    igraph_error("Cannot read GML file", __FILE__, __LINE__, IGRAPH_PARSEERROR);
+  }
+  memcpy(p->s, s, sizeof(char)*len);
+  p->s[len]='\0';
+  p->len=len;
+}
+
+void igraph_i_gml_get_string(char *s, int len, void *res) {
+  struct { char *s; int len; } *p=res;
+  p->s=igraph_Calloc(len-1, char);
+  if (!p->s) { 
+    igraph_error("Cannot read GML file", __FILE__, __LINE__, IGRAPH_PARSEERROR);
+  }
+  memcpy(p->s, s+1, sizeof(char)*(len-2));
+  p->s[len-2]='\0';
+  p->len=len-2;
+}
+
+double igraph_i_gml_get_real(char *s, int len) {
+  igraph_real_t num;
+  char tmp=s[len];
+  s[len]='\0';
+  sscanf(s, "%lf", &num);
+  s[len]=tmp;
+  return num;
+} 
+
+igraph_gml_tree_t *igraph_i_gml_make_numeric(char* s, int len, double value) {
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  if (floor(value)==value) {
+    igraph_gml_tree_init_integer(t, s, len, value);
+  } else {
+    igraph_gml_tree_init_real(t, s, len, value);
+  }
+  
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_make_numeric2(char* s, int len, 
+					      char *v, int vlen) {
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  char tmp=v[vlen];
+  igraph_real_t value=0;
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  v[vlen]='\0';
+  if (strcasecmp(v, "inf")) {
+    value=IGRAPH_INFINITY;
+  } else if (strcasecmp(v, "nan")) {
+    value=IGRAPH_NAN;
+  } else {
+    igraph_error("Parse error", __FILE__, __LINE__, IGRAPH_PARSEERROR);
+  }
+  v[vlen]=tmp;
+  igraph_gml_tree_init_real(t, s, len, value);  
+
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_make_string(char* s, int len, 
+					    char *value, int valuelen) {
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  igraph_gml_tree_init_string(t, s, len, value, valuelen);
+
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_make_list(char* s, int len, 
+					  igraph_gml_tree_t *list) {
+  
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  igraph_gml_tree_init_tree(t, s, len, list);
+
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_merge(igraph_gml_tree_t *t1, igraph_gml_tree_t* t2) {
+
+  igraph_gml_tree_mergedest(t1, t2);
+  igraph_Free(t2);
+
+  return t1;
+}
+
diff --git a/src/foreign-gml-parser.h b/src/foreign-gml-parser.h
new file mode 100644
index 0000000..c47254a
--- /dev/null
+++ b/src/foreign-gml-parser.h
@@ -0,0 +1,95 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     STRING = 258,
+     NUM = 259,
+     KEYWORD = 260,
+     LISTOPEN = 261,
+     LISTCLOSE = 262,
+     EOFF = 263
+   };
+#endif
+/* Tokens.  */
+#define STRING 258
+#define NUM 259
+#define KEYWORD 260
+#define LISTOPEN 261
+#define LISTCLOSE 262
+#define EOFF 263
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 98 "foreign-gml-parser.y"
+{
+   struct {
+      char *s;
+      int len;
+   } str;
+   void *tree;
+   double real;
+}
+/* Line 1529 of yacc.c.  */
+#line 74 "foreign-gml-parser.h"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
diff --git a/src/foreign-gml-parser.y b/src/foreign-gml-parser.y
new file mode 100644
index 0000000..65e8c42
--- /dev/null
+++ b/src/foreign-gml-parser.y
@@ -0,0 +1,262 @@
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "igraph_error.h"
+#include "igraph_memory.h"
+#include "config.h"
+#include "igraph_hacks_internal.h"
+#include "igraph_math.h"
+#include "igraph_gml_tree.h"
+#include "foreign-gml-header.h"
+#include "foreign-gml-parser.h"
+
+#define yyscan_t void*
+
+int igraph_gml_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, void *scanner);
+int igraph_gml_yyerror(YYLTYPE* locp, igraph_i_gml_parsedata_t *context, 
+		       char *s);
+char *igraph_gml_yyget_text (yyscan_t yyscanner );
+int igraph_gml_yyget_leng (yyscan_t yyscanner );
+void igraph_i_gml_get_keyword(char *s, int len, void *res);
+void igraph_i_gml_get_string(char *s, int len, void *res);
+double igraph_i_gml_get_real(char *s, int len);
+igraph_gml_tree_t *igraph_i_gml_make_numeric(char* s, int len, double value);
+igraph_gml_tree_t *igraph_i_gml_make_numeric2(char* s, int len, 
+					      char *v, int vlen);
+igraph_gml_tree_t *igraph_i_gml_make_string(char* s, int len, 
+					    char *value, int valuelen);
+igraph_gml_tree_t *igraph_i_gml_make_list(char* s, int len, 
+					  igraph_gml_tree_t *list);
+igraph_gml_tree_t *igraph_i_gml_merge(igraph_gml_tree_t *t1, igraph_gml_tree_t* t2);
+
+#define scanner context->scanner
+#define USE(x) /*(x)*/
+
+%}
+
+%pure-parser
+%output="y.tab.c"
+%name-prefix="igraph_gml_yy"
+%defines
+%locations
+%error-verbose
+%parse-param { igraph_i_gml_parsedata_t* context }
+%lex-param { void *scanner }
+
+%union {
+   struct {
+      char *s;
+      int len;
+   } str;
+   void *tree;
+   double real;
+}
+
+%type <tree>    list;
+%type <tree>    keyvalue;
+%type <str>     key;
+%type <real>    num;
+%type <str>     string;
+
+%token STRING
+%token NUM
+%token <str>    KEYWORD
+%token LISTOPEN
+%token LISTCLOSE
+%token EOFF
+
+%destructor { igraph_Free($$.s); } string key KEYWORD;
+%destructor { igraph_gml_tree_destroy($$); } list keyvalue;
+
+%%
+
+input:   list      { context->tree=$1; } 
+       | list EOFF { context->tree=$1; }
+;
+
+list:   keyvalue      { $$=$1; } 
+      | list keyvalue { $$=igraph_i_gml_merge($1, $2); };
+
+keyvalue:   key num
+            { $$=igraph_i_gml_make_numeric($1.s, $1.len, $2); }
+	  | key string
+            { $$=igraph_i_gml_make_string($1.s, $1.len, $2.s, $2.len); }
+          | key LISTOPEN list LISTCLOSE
+            { $$=igraph_i_gml_make_list($1.s, $1.len, $3); }
+          | key key
+            { $$=igraph_i_gml_make_numeric2($1.s, $1.len, $2.s, $2.len); }
+;
+
+key: KEYWORD { igraph_i_gml_get_keyword(igraph_gml_yyget_text(scanner), 
+					igraph_gml_yyget_leng(scanner), 
+					&$$); USE($1) };
+num : NUM { $$=igraph_i_gml_get_real(igraph_gml_yyget_text(scanner), 
+				     igraph_gml_yyget_leng(scanner)); };
+
+string: STRING { igraph_i_gml_get_string(igraph_gml_yyget_text(scanner), 
+					 igraph_gml_yyget_leng(scanner), 
+					 &$$); };
+
+%%
+
+int igraph_gml_yyerror(YYLTYPE* locp, igraph_i_gml_parsedata_t *context, 
+		       char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1, 
+	   "Parse error in GML file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+void igraph_i_gml_get_keyword(char *s, int len, void *res) {
+  struct { char *s; int len; } *p=res;
+  p->s=igraph_Calloc(len+1, char);
+  if (!p->s) { 
+    igraph_error("Cannot read GML file", __FILE__, __LINE__, IGRAPH_PARSEERROR);
+  }
+  memcpy(p->s, s, sizeof(char)*len);
+  p->s[len]='\0';
+  p->len=len;
+}
+
+void igraph_i_gml_get_string(char *s, int len, void *res) {
+  struct { char *s; int len; } *p=res;
+  p->s=igraph_Calloc(len-1, char);
+  if (!p->s) { 
+    igraph_error("Cannot read GML file", __FILE__, __LINE__, IGRAPH_PARSEERROR);
+  }
+  memcpy(p->s, s+1, sizeof(char)*(len-2));
+  p->s[len-2]='\0';
+  p->len=len-2;
+}
+
+double igraph_i_gml_get_real(char *s, int len) {
+  igraph_real_t num;
+  char tmp=s[len];
+  s[len]='\0';
+  sscanf(s, "%lf", &num);
+  s[len]=tmp;
+  return num;
+} 
+
+igraph_gml_tree_t *igraph_i_gml_make_numeric(char* s, int len, double value) {
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  if (floor(value)==value) {
+    igraph_gml_tree_init_integer(t, s, len, value);
+  } else {
+    igraph_gml_tree_init_real(t, s, len, value);
+  }
+  
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_make_numeric2(char* s, int len, 
+					      char *v, int vlen) {
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  char tmp=v[vlen];
+  igraph_real_t value=0;
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  v[vlen]='\0';
+  if (strcasecmp(v, "inf")) {
+    value=IGRAPH_INFINITY;
+  } else if (strcasecmp(v, "nan")) {
+    value=IGRAPH_NAN;
+  } else {
+    igraph_error("Parse error", __FILE__, __LINE__, IGRAPH_PARSEERROR);
+  }
+  v[vlen]=tmp;
+  igraph_gml_tree_init_real(t, s, len, value);  
+
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_make_string(char* s, int len, 
+					    char *value, int valuelen) {
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  igraph_gml_tree_init_string(t, s, len, value, valuelen);
+
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_make_list(char* s, int len, 
+					  igraph_gml_tree_t *list) {
+  
+  igraph_gml_tree_t *t=igraph_Calloc(1, igraph_gml_tree_t);
+  if (!t) { 
+    igraph_error("Cannot build GML tree", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;
+  }
+  igraph_gml_tree_init_tree(t, s, len, list);
+
+  return t;
+}
+
+igraph_gml_tree_t *igraph_i_gml_merge(igraph_gml_tree_t *t1, igraph_gml_tree_t* t2) {
+
+  igraph_gml_tree_mergedest(t1, t2);
+  igraph_Free(t2);
+
+  return t1;
+}
diff --git a/src/foreign-graphml.c b/src/foreign-graphml.c
new file mode 100644
index 0000000..e7ac529
--- /dev/null
+++ b/src/foreign-graphml.c
@@ -0,0 +1,1511 @@
+/* -*- mode: C -*-  */
+/* 
+   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
+   (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_foreign.h"
+#include "config.h"
+#include <math.h>               /* isnan */
+#include "igraph_math.h"
+#include "igraph_attributes.h"
+#include "igraph_interface.h"
+#include "igraph_types_internal.h"
+
+#include <ctype.h>		/* isspace */
+#include <string.h>
+#include "igraph_memory.h"
+#include <stdarg.h> 		/* va_start & co */
+
+#if HAVE_LIBXML == 1
+#include <libxml/encoding.h>
+#include <libxml/parser.h>
+
+
+xmlEntity blankEntityStruct = {
+#ifndef XML_WITHOUT_CORBA
+  0,
+#endif
+  XML_ENTITY_DECL,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  XML_EXTERNAL_GENERAL_PARSED_ENTITY,
+  0,
+  0,
+  0,
+  0,
+  0,
+  1
+};
+
+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);           \
+  }                                                           \
+  return;                                                     \
+} while (1)
+
+/* TODO: proper error handling */
+
+typedef struct igraph_i_graphml_attribute_record_t {
+  const char *id;         	/* GraphML id */
+  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 */
+  igraph_attribute_record_t record;
+} igraph_i_graphml_attribute_record_t;
+
+struct igraph_i_graphml_parser_state {
+  enum { START, INSIDE_GRAPHML, INSIDE_GRAPH, INSIDE_NODE, INSIDE_EDGE,
+      INSIDE_KEY, INSIDE_DEFAULT, INSIDE_DATA, FINISH, UNKNOWN, ERROR } st;
+  igraph_t *g;
+  igraph_trie_t node_trie;
+  igraph_strvector_t edgeids;
+  igraph_vector_t edgelist;
+  igraph_vector_int_t prev_state_stack;
+  unsigned int unknown_depth;
+  int index;
+  igraph_bool_t successful, edges_directed, destroyed;
+  igraph_trie_t v_names;
+  igraph_vector_ptr_t v_attrs;
+  igraph_trie_t e_names;
+  igraph_vector_ptr_t e_attrs;
+  igraph_trie_t g_names;
+  igraph_vector_ptr_t g_attrs;
+  xmlChar *data_key;
+  igraph_attribute_elemtype_t data_type;
+  char *error_message;
+  char *data_char;
+};
+
+static void igraph_i_report_unhandled_attribute_target(const char* target,
+    const char* file, int line) {
+  igraph_warningf("Attribute target '%s' is not handled; ignoring corresponding "
+      "attribute specifications", file, line, 0, target);
+}
+
+igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data) {
+  int value;
+  if (char_data == 0)
+    return 0;
+  if (!strcasecmp("true", char_data))
+    return 1;
+  if (!strcasecmp("yes", char_data))
+    return 1;
+  if (!strcasecmp("false", char_data))
+    return 0;
+  if (!strcasecmp("no", char_data))
+    return 0;
+  if (sscanf(char_data, "%d", &value) == 0)
+    return 0;
+  return value != 0;
+}
+
+void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
+  long int i;
+
+  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);
+  igraph_trie_destroy(&state->e_names);
+  igraph_trie_destroy(&state->g_names);
+  igraph_vector_destroy(&state->edgelist);
+  igraph_vector_int_destroy(&state->prev_state_stack);
+   
+  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_FINALLY_CLEAN(1);
+}
+
+void igraph_i_graphml_sax_handler_error(void *state0, const char* msg, ...) {
+  struct igraph_i_graphml_parser_state *state=
+    (struct igraph_i_graphml_parser_state*)state0;
+  va_list ap;
+  
+  va_start(ap, msg);
+  
+  if (state->error_message == 0)
+    state->error_message=igraph_Calloc(4096, char);
+   
+  state->successful=0;
+  state->st=ERROR;
+  vsnprintf(state->error_message, 4096, msg, ap);
+   
+  va_end(ap);
+}
+
+xmlEntityPtr igraph_i_graphml_sax_handler_get_entity(void *state0,
+						     const xmlChar* name) {
+  xmlEntityPtr predef = xmlGetPredefinedEntity(name);
+  IGRAPH_UNUSED(state0);
+  if (predef != NULL) return predef;
+  IGRAPH_WARNING("unknown XML entity found\n");
+  return blankEntity;
+}
+
+void igraph_i_graphml_handle_unknown_start_tag(struct igraph_i_graphml_parser_state *state) {
+  if (state->st != UNKNOWN) {
+    igraph_vector_int_push_back(&state->prev_state_stack, state->st);
+    state->st=UNKNOWN;
+    state->unknown_depth=1;
+  } else {
+    state->unknown_depth++;
+  }
+}
+
+void igraph_i_graphml_sax_handler_start_document(void *state0) {
+  struct igraph_i_graphml_parser_state *state=
+    (struct igraph_i_graphml_parser_state*)state0;
+  int ret;
+  
+  state->st=START;
+  state->successful=1;
+  state->edges_directed=0;
+  state->destroyed=0;
+  state->data_key=0;
+  state->error_message=0;
+  state->data_char=0;
+  state->unknown_depth=0;
+
+  ret=igraph_vector_int_init(&state->prev_state_stack, 0);
+  if (ret) {
+    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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  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);
+  }
+  IGRAPH_FINALLY(igraph_trie_destroy, &state->g_names);
+  
+  IGRAPH_FINALLY_CLEAN(10);
+  IGRAPH_FINALLY(igraph_i_graphml_destroy_state, state);
+}
+
+void igraph_i_graphml_sax_handler_end_document(void *state0) {
+  struct igraph_i_graphml_parser_state *state=
+    (struct igraph_i_graphml_parser_state*)state0;
+  long i, l;
+  int r;
+  igraph_attribute_record_t idrec, eidrec;
+  const char *idstr="id";
+  igraph_bool_t already_has_vertex_id=0, already_has_edge_id=0;
+
+  if (!state->successful) return;
+
+  if (state->index<0) {
+
+    igraph_vector_ptr_t vattr, eattr, gattr;
+    long int esize=igraph_vector_ptr_size(&state->e_attrs);
+    const void **tmp;
+    r=igraph_vector_ptr_init(&vattr, 
+			     igraph_vector_ptr_size(&state->v_attrs)+1);
+    if (r) {
+      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
+      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
+      return;
+    }
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattr);
+    if (igraph_strvector_size(&state->edgeids) != 0) {
+      esize++;      
+    }
+    r=igraph_vector_ptr_init(&eattr, esize);
+    if (r) {
+      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
+      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
+      return;
+    }
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &eattr);
+    r=igraph_vector_ptr_init(&gattr, igraph_vector_ptr_size(&state->g_attrs));
+    if (r) {
+      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
+      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
+      return;
+    }
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &gattr);
+
+    for (i=0; i<igraph_vector_ptr_size(&state->v_attrs); i++) {
+      igraph_i_graphml_attribute_record_t *graphmlrec=
+	VECTOR(state->v_attrs)[i];
+      igraph_attribute_record_t *rec=&graphmlrec->record;
+
+      /* Check that the name of the vertex attribute is not 'id'.
+	 If it is then we cannot the complimentary 'id' attribute. */
+      if (! strcmp(rec->name, idstr)) {
+	already_has_vertex_id=1;
+      }
+
+      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_vector_t *vec=(igraph_vector_t*)rec->value;
+	long int origsize=igraph_vector_size(vec);
+	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;
+	}
+      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
+	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
+	long int origsize=igraph_strvector_size(strvec);
+	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, "");
+	}
+      } 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);
+	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(vattr)[i]=rec;
+    }
+    if (!already_has_vertex_id) {
+      idrec.name=idstr;
+      idrec.type=IGRAPH_ATTRIBUTE_STRING;
+      tmp=&idrec.value;
+      igraph_trie_getkeys(&state->node_trie, (const igraph_strvector_t **)tmp);
+      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++) {
+      igraph_i_graphml_attribute_record_t *graphmlrec=
+	VECTOR(state->e_attrs)[i];
+      igraph_attribute_record_t *rec=&graphmlrec->record;
+
+      if (! strcmp(rec->name, idstr)) {
+	already_has_edge_id=1;
+      }
+
+      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_vector_t *vec=(igraph_vector_t*)rec->value;
+	long int origsize=igraph_vector_size(vec);
+	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;
+	}
+      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
+	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
+	long int origsize=igraph_strvector_size(strvec);
+	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, "");
+	}
+      } 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);
+	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(eattr)[i]=rec;
+    }
+    if (igraph_strvector_size(&state->edgeids) != 0) {
+      if (!already_has_edge_id) {
+	long int origsize=igraph_strvector_size(&state->edgeids);
+	eidrec.name=idstr;
+	eidrec.type=IGRAPH_ATTRIBUTE_STRING;
+	igraph_strvector_resize(&state->edgeids, 
+				igraph_vector_size(&state->edgelist)/2);
+	for (; origsize < igraph_strvector_size(&state->edgeids); origsize++) {
+	  igraph_strvector_set(&state->edgeids, origsize, "");
+	}
+	eidrec.value=&state->edgeids;
+	VECTOR(eattr)[(long int)igraph_vector_ptr_size(&eattr)-1]=&eidrec;
+      } else {
+	igraph_vector_ptr_pop_back(&eattr);
+	IGRAPH_WARNING("Could not add edge ids, "
+		       "there is already an 'id' edge attribute");
+      }
+    }
+
+    for (i=0; i<igraph_vector_ptr_size(&state->g_attrs); i++) {
+      igraph_i_graphml_attribute_record_t *graphmlrec=
+	VECTOR(state->g_attrs)[i];
+      igraph_attribute_record_t *rec=&graphmlrec->record;
+      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_vector_t *vec=(igraph_vector_t*)rec->value;
+	long int origsize=igraph_vector_size(vec);
+	igraph_vector_resize(vec, 1);
+	for (l=origsize; l<1; l++) {
+	  VECTOR(*vec)[l]=IGRAPH_NAN;
+	}
+      } 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, "");
+	}
+      } 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(gattr)[i]=rec;
+    }
+    
+    igraph_empty_attrs(state->g, 0, state->edges_directed, &gattr);
+    igraph_add_vertices(state->g, (igraph_integer_t) 
+			igraph_trie_size(&state->node_trie), &vattr);
+    igraph_add_edges(state->g, &state->edgelist, &eattr);
+
+    igraph_vector_ptr_destroy(&vattr);
+    igraph_vector_ptr_destroy(&eattr);
+    igraph_vector_ptr_destroy(&gattr);
+    IGRAPH_FINALLY_CLEAN(3);     
+  }
+
+  igraph_i_graphml_destroy_state(state);
+}
+
+#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) {
+  xmlChar **it;
+  igraph_trie_t *trie=0;
+  igraph_vector_ptr_t *ptrvector=0;
+  long int id;
+  unsigned short int skip=0;
+  int ret;
+  igraph_i_graphml_attribute_record_t *rec;
+
+  if (!state->successful) return;
+   
+  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);
+  }
+  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")) { 
+	rec->type=I_GRAPHML_BOOLEAN;
+	rec->record.type=IGRAPH_ATTRIBUTE_BOOLEAN;	    
+      } else if (xmlStrEqual(*(it+1), toXmlChar("string"))) {
+	rec->type=I_GRAPHML_STRING;
+	rec->record.type=IGRAPH_ATTRIBUTE_STRING;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("float"))) { 
+	rec->type=I_GRAPHML_FLOAT;
+	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("double"))) { 
+	rec->type=I_GRAPHML_DOUBLE;
+	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("int"))) {
+	rec->type=I_GRAPHML_INTEGER;
+	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("long"))) {
+	rec->type=I_GRAPHML_LONG;
+	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
+      } else {
+        GRAPHML_PARSE_ERROR(state,
+            "Cannot parse GraphML file, unknown attribute type");
+      }
+    } else if (xmlStrEqual(*it, toXmlChar("for"))) {
+      /* graph, vertex or edge attribute? */
+      if (xmlStrEqual(*(it+1), toXmlChar("graph"))) { 
+	trie=&state->g_names;
+	ptrvector=&state->g_attrs;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("node"))) {
+	trie=&state->v_names;
+	ptrvector=&state->v_attrs;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("edge"))) {
+	trie=&state->e_names;
+	ptrvector=&state->e_attrs;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("graphml"))) {
+        igraph_i_report_unhandled_attribute_target("graphml", __FILE__, __LINE__);
+        skip=1;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("hyperedge"))) {
+        igraph_i_report_unhandled_attribute_target("hyperedge", __FILE__, __LINE__);
+        skip=1;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("port"))) {
+        igraph_i_report_unhandled_attribute_target("port", __FILE__, __LINE__);
+        skip=1;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("endpoint"))) {
+        igraph_i_report_unhandled_attribute_target("endpoint", __FILE__, __LINE__);
+        skip=1;
+      } else if (xmlStrEqual(*(it+1), toXmlChar("all"))) {
+        /* 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");
+      }
+    }
+  }
+  
+  /* throw an error if there is no ID; this is a clear violation of the GraphML
+   * DTD */
+  if (rec->id == 0) {
+    GRAPHML_PARSE_ERROR(state, "Found <key> tag with no 'id' attribute");
+  }
+
+  /* in case of a missing attr.name attribute, use the id as the attribute name */
+  if (rec->record.name == 0) {
+    rec->record.name=strdup(rec->id);
+  }
+
+  /* if the attribute type is missing, throw an error */
+  if (!skip && rec->type == I_GRAPHML_UNKNOWN_TYPE) {
+    igraph_warningf("Ignoring <key id=\"%s\"> because of a missing or unknown 'attr.type' attribute", __FILE__, __LINE__, 0, rec->id);
+    skip = 1;
+  }
+
+  /* if the value of the 'for' attribute was unknown, throw an error */
+  if (!skip && trie == 0) {
+    GRAPHML_PARSE_ERROR(state,
+        "Cannot parse GraphML file, missing 'for' attribute in a <key> tag");
+  }
+	
+  /* if the code above requested skipping the attribute, free everything and
+   * return */
+  if (skip) {
+    igraph_free(rec);
+    IGRAPH_FINALLY_CLEAN(1);
+    return;
+  }
+
+  /* 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");
+  }
+
+  ret=igraph_vector_ptr_push_back(ptrvector, rec);
+  if (ret) {
+    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot read GraphML file", ret);
+  }
+
+  /* Ownership of 'rec' is now taken by ptrvector so we can clean the
+   * finally stack */
+  IGRAPH_FINALLY_CLEAN(1);	/* rec */
+
+  /* create the attribute values */
+  switch (rec->record.type) {
+    igraph_vector_t *vec;
+    igraph_vector_bool_t *boolvec;
+    igraph_strvector_t *strvec;
+  case IGRAPH_ATTRIBUTE_BOOLEAN:
+    boolvec=igraph_Calloc(1, igraph_vector_bool_t);
+    if (boolvec==0) {
+      GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+    }
+    rec->record.value=boolvec;
+    igraph_vector_bool_init(boolvec, 0);    
+    break;
+  case IGRAPH_ATTRIBUTE_NUMERIC:
+    vec=igraph_Calloc(1, igraph_vector_t);
+    if (vec==0) {
+      GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+    }
+    rec->record.value=vec;
+    igraph_vector_init(vec, 0);    
+    break;
+  case IGRAPH_ATTRIBUTE_STRING:
+    strvec=igraph_Calloc(1, igraph_strvector_t);
+    if (strvec==0) {
+      GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+    }
+    rec->record.value=strvec;
+    igraph_strvector_init(strvec, 0);
+    break;
+  default: break;
+  }
+}
+
+void igraph_i_graphml_attribute_data_setup(struct igraph_i_graphml_parser_state *state,
+					   const xmlChar **attrs,
+					   igraph_attribute_elemtype_t type) {
+  xmlChar **it;
+
+  if (!state->successful)
+    return;
+
+  for (it=(xmlChar**)attrs; *it; it+=2) {
+    if (xmlStrEqual(*it, toXmlChar("key"))) {
+      if (state->data_key) {
+	free(state->data_key);
+      }
+      state->data_key=xmlStrdup(*(it+1));
+      if (state->data_char) {
+        free(state->data_char);
+      }
+      state->data_char=0;
+      state->data_type=type;
+    } else {
+      /* ignore */
+    }
+  }
+}
+
+void igraph_i_graphml_attribute_data_add(struct igraph_i_graphml_parser_state *state,
+					 const xmlChar *data, int len) {
+  long int data_char_new_start=0;
+
+  if (!state->successful) return;
+
+  if (state->data_char) {
+    data_char_new_start=(long int) strlen(state->data_char);
+    state->data_char=igraph_Realloc(state->data_char, 
+				    (size_t)(data_char_new_start+len+1), char);
+  } else {
+    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);
+  }
+  memcpy(state->data_char+data_char_new_start, data, 
+	 (size_t) len*sizeof(xmlChar));
+  state->data_char[data_char_new_start+len]='\0';
+}
+
+void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state *state) {
+  const char *key=fromXmlChar(state->data_key);
+  igraph_attribute_elemtype_t type=state->data_type;
+  igraph_trie_t *trie=0;
+  igraph_vector_ptr_t *ptrvector=0;
+  igraph_i_graphml_attribute_record_t *graphmlrec;
+  igraph_attribute_record_t *rec;
+  long int recid, id=0;
+  int ret;
+  
+  switch (type) {
+  case IGRAPH_ATTRIBUTE_GRAPH:
+    trie=&state->g_names;
+    ptrvector=&state->g_attrs;
+    id=0;
+    break;
+  case IGRAPH_ATTRIBUTE_VERTEX:
+    trie=&state->v_names;
+    ptrvector=&state->v_attrs;
+    id=igraph_trie_size(&state->node_trie)-1; /* hack */
+    break;
+  case IGRAPH_ATTRIBUTE_EDGE:
+    trie=&state->e_names;
+    ptrvector=&state->e_attrs;
+    id=igraph_vector_size(&state->edgelist)/2-1; /* hack */
+    break;
+  default:
+    /* impossible */
+    break;
+  }
+  
+  igraph_trie_check(trie, key, &recid);
+  if (recid < 0) {
+    /* no such attribute key, issue a warning */
+    igraph_warningf(
+        "unknown attribute key '%s' in a <data> tag, ignoring attribute",
+        __FILE__, __LINE__, 0,
+        key
+    );
+    igraph_Free(state->data_char);
+    return;
+  }
+   
+  graphmlrec=VECTOR(*ptrvector)[recid];
+  rec=&graphmlrec->record;
+
+  switch (rec->type) {
+    igraph_vector_bool_t *boolvec;
+    igraph_vector_t *vec;
+    igraph_strvector_t *strvec;
+    igraph_real_t num;
+    long int s, i;
+  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);
+      }
+      for (i=s; i<id; i++) {
+	VECTOR(*boolvec)[i]=0;
+      }
+    }
+    VECTOR(*boolvec)[id] = igraph_i_graphml_parse_boolean(state->data_char);
+    break;
+  case IGRAPH_ATTRIBUTE_NUMERIC:
+    vec=(igraph_vector_t *)rec->value;
+    s=igraph_vector_size(vec);
+    if (id >= s) {
+      ret=igraph_vector_resize(vec, id+1);
+      if (ret) {
+        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+      }
+      for (i=s; i<id; i++) {
+	VECTOR(*vec)[i]=IGRAPH_NAN;
+      }
+    }
+    if (state->data_char)
+      sscanf(state->data_char, "%lf", &num);
+    else
+      num=0;
+    VECTOR(*vec)[id]=num;
+    break;
+  case IGRAPH_ATTRIBUTE_STRING:
+    strvec=(igraph_strvector_t *)rec->value;
+    s=igraph_strvector_size(strvec);
+    if (id >= s) {
+      ret=igraph_strvector_resize(strvec, id+1);
+      if (ret) {
+        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+      }
+      for (i=s;i<id;i++) {
+	igraph_strvector_set(strvec, i, "");
+      }
+    }
+    if (state->data_char)
+      ret=igraph_strvector_set(strvec, id, (char*)state->data_char);
+    else
+      ret=igraph_strvector_set(strvec, id, "");
+    if (ret) {
+      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_sax_handler_start_element(void *state0,
+						const xmlChar* name,
+						const xmlChar** attrs) {
+  struct igraph_i_graphml_parser_state *state=
+    (struct igraph_i_graphml_parser_state*)state0;
+  xmlChar** it;
+  long int id1, id2;
+
+  if (!state->successful)
+    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")))
+      state->st=INSIDE_GRAPHML;
+    else
+      igraph_i_graphml_handle_unknown_start_tag(state);
+    break;
+    
+  case INSIDE_GRAPHML:
+    /* If we are in the INSIDE_GRAPHML state and received a graph tag,
+     * 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 (state->index==0) {
+	state->st=INSIDE_GRAPH;
+	for (it=(xmlChar**)attrs; *it; it+=2) {
+	  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;
+	  }
+	}
+      }
+      state->index--;
+    } else if (xmlStrEqual(name, toXmlChar("key"))) {
+      igraph_i_graphml_add_attribute_key(attrs, state);
+      state->st=INSIDE_KEY;
+    } 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;
+    else igraph_i_graphml_handle_unknown_start_tag(state);
+    break;
+
+  case INSIDE_DEFAULT:
+    /* If we are in the INSIDE_DEFAULT state, every further tag will be unknown */
+    igraph_i_graphml_handle_unknown_start_tag(state);
+    break;
+    
+  case INSIDE_GRAPH:
+    /* If we are in the INSIDE_GRAPH state, check for node and edge tags */
+    if (xmlStrEqual(name, 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);
+	}
+	if (xmlStrEqual(*it, toXmlChar("id"))) {
+	  long int edges=igraph_vector_size(&state->edgelist)/2+1;
+	  long int origsize=igraph_strvector_size(&state->edgeids);
+	  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)));
+	}
+      }
+      if (id1>=0 && id2>=0) {
+	igraph_vector_push_back(&state->edgelist, id1);
+	igraph_vector_push_back(&state->edgelist, id2);
+      } else {
+	igraph_i_graphml_sax_handler_error(state, "Edge with missing source or target encountered");
+	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);
+	  break;
+	}
+      }
+      state->st=INSIDE_NODE;
+    } else if (xmlStrEqual(name, toXmlChar("data"))) {
+      igraph_i_graphml_attribute_data_setup(state, attrs, IGRAPH_ATTRIBUTE_GRAPH);
+      igraph_vector_int_push_back(&state->prev_state_stack, state->st);
+      state->st=INSIDE_DATA;
+    } else
+      igraph_i_graphml_handle_unknown_start_tag(state);
+    break;
+    
+  case INSIDE_NODE:
+    if (xmlStrEqual(name, toXmlChar("data"))) {
+      igraph_i_graphml_attribute_data_setup(state, attrs,
+					    IGRAPH_ATTRIBUTE_VERTEX);
+      igraph_vector_int_push_back(&state->prev_state_stack, state->st);
+      state->st=INSIDE_DATA;
+    }
+    break;
+    
+  case INSIDE_EDGE:
+    if (xmlStrEqual(name, toXmlChar("data"))) {
+      igraph_i_graphml_attribute_data_setup(state, attrs, 
+					    IGRAPH_ATTRIBUTE_EDGE);
+      igraph_vector_int_push_back(&state->prev_state_stack, state->st);
+      state->st=INSIDE_DATA;
+    }
+    break;
+
+  case INSIDE_DATA:
+    /* We do not expect any new tags within a <data> tag */
+    igraph_i_graphml_handle_unknown_start_tag(state);
+    break;
+
+  case UNKNOWN:
+    igraph_i_graphml_handle_unknown_start_tag(state);
+    break;
+
+  default:
+    break;
+  }
+}
+
+void igraph_i_graphml_sax_handler_end_element(void *state0,
+						const xmlChar* name) {
+  struct igraph_i_graphml_parser_state *state=
+    (struct igraph_i_graphml_parser_state*)state0;
+
+  if (!state->successful)
+    return;
+
+  IGRAPH_UNUSED(name);
+
+  switch (state->st) {
+  case INSIDE_GRAPHML:
+    state->st=FINISH;
+    break;
+    
+  case INSIDE_GRAPH:
+    state->st=INSIDE_GRAPHML;
+    break;
+    
+  case INSIDE_KEY:
+    state->st=INSIDE_GRAPHML;
+    break;
+
+  case INSIDE_DEFAULT:
+    state->st=INSIDE_KEY;
+    break;
+    
+  case INSIDE_NODE:
+    state->st=INSIDE_GRAPH;
+    break;
+    
+  case INSIDE_EDGE:
+    state->st=INSIDE_GRAPH;
+    break;
+
+  case INSIDE_DATA:
+    igraph_i_graphml_attribute_data_finish(state);
+    state->st = igraph_vector_int_pop_back(&state->prev_state_stack);
+    break;
+    
+  case UNKNOWN:
+    state->unknown_depth--;
+    if (!state->unknown_depth) {
+      state->st = igraph_vector_int_pop_back(&state->prev_state_stack);
+    }
+    break;
+    
+  default:
+    break;
+  }
+}
+
+void igraph_i_graphml_sax_handler_chars(void* state0, const xmlChar* ch, int len) {
+  struct igraph_i_graphml_parser_state *state=
+    (struct igraph_i_graphml_parser_state*)state0;
+  
+  if (!state->successful)
+    return;
+
+  switch (state->st) {
+  case INSIDE_KEY:
+  case INSIDE_DEFAULT:
+    break;
+    
+  case INSIDE_DATA:
+    igraph_i_graphml_attribute_data_add(state, ch, len);
+    break;
+    
+  default:
+    /* just ignore it */
+    break;
+  }
+}
+
+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
+};
+
+#endif
+
+int igraph_i_xml_escape(char* src, char** dest) {
+  long int destlen=0;
+  char *s, *d;
+  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;
+  }
+  *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) {
+    case '&':
+      strcpy(d, "&"); d+=4; break;
+    case '<':
+      strcpy(d, "<"); d+=3; break;
+    case '>':
+      strcpy(d, ">"); d+=3; break;
+    case '"':
+      strcpy(d, """); d+=5; break;
+    case '\'':
+      strcpy(d, "'"); d+=5; break;
+    default:
+      *d = *s;
+    }
+  }
+  *d=0;
+  return 0;
+}
+
+/**
+ * \ingroup loadsave
+ * \function igraph_read_graph_graphml
+ * \brief Reads a graph from a GraphML file.
+ * 
+ * </para><para>
+ * GraphML is an XML-based file format for representing various types of
+ * graphs. Currently only the most basic import functionality is implemented
+ * in igraph: it can read GraphML files without nested graphs and hyperedges.
+ * Attributes of the graph are loaded only if an attribute interface
+ * is attached, ie. if you use igraph from R or Python.
+ *
+ * </para><para>
+ * Graph attribute names are taken from the \c attr.name attributes of the
+ * \c key tags in the GraphML file. Since \c attr.name is not mandatory,
+ * igraph will fall back to the \c id attribute of the \c key tag if
+ * \c attr.name is missing.
+ *
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream A stream, it should be readable.
+ * \param index If the GraphML file contains more than one graph, the one
+ *              specified by this index will be loaded. Indices start from
+ *              zero, so supply zero here if your GraphML file contains only
+ *              a single graph.
+ * 
+ * \return Error code:
+ *         \c IGRAPH_PARSEERROR: if there is a
+ *         problem reading the file, or the file is syntactically
+ *         incorrect.
+ *         \c IGRAPH_UNIMPLEMENTED: the GraphML functionality was disabled
+ *         at compile-time
+ * 
+ * \example examples/simple/graphml.c
+ */
+int igraph_read_graph_graphml(igraph_t *graph, FILE *instream,
+			      int index) {
+
+#if HAVE_LIBXML == 1
+  xmlParserCtxtPtr ctxt;
+  struct igraph_i_graphml_parser_state state;
+  int res;
+  char buffer[4096];
+
+  if (index<0)
+    IGRAPH_ERROR("Graph index must be non-negative", IGRAPH_EINVAL);
+
+  xmlInitParser();
+
+  /* Create a progressive parser context */
+  state.g=graph;
+  state.index=index<0?0:index;
+  res=(int) fread(buffer, 1, 4096, instream);
+  ctxt=xmlCreatePushParserCtxt(&igraph_i_graphml_sax_handler,
+			       &state,
+			       buffer,
+			       res,
+			       NULL);
+/*   ctxt=xmlCreateIOParserCtxt(&igraph_i_graphml_sax_handler, &state, */
+/* 			     igraph_i_libxml2_read_callback, */
+/* 			     igraph_i_libxml2_close_callback, */
+/* 			     instream, XML_CHAR_ENCODING_NONE); */
+  if (ctxt==NULL)
+    IGRAPH_ERROR("Can't create progressive parser context", IGRAPH_PARSEERROR);
+
+  /* Parse the file */
+  while ((res=(int) fread(buffer, 1, 4096, instream))>0) {
+    xmlParseChunk(ctxt, buffer, res, 0);
+    if (!state.successful) break;
+  }
+  xmlParseChunk(ctxt, buffer, res, 1);
+  
+  /* Free the context */
+  xmlFreeParserCtxt(ctxt);
+  if (!state.successful) {
+    if (state.error_message != 0)
+      IGRAPH_ERROR(state.error_message, IGRAPH_PARSEERROR);
+    else
+      IGRAPH_ERROR("Malformed GraphML file", IGRAPH_PARSEERROR);
+  }
+  if (state.index>=0)
+    IGRAPH_ERROR("Graph index was too large", IGRAPH_EINVAL);
+  
+  return 0;
+#else
+  IGRAPH_ERROR("GraphML support is disabled", IGRAPH_UNIMPLEMENTED);
+#endif
+}
+
+/**
+ * \ingroup loadsave
+ * \function igraph_write_graph_graphml
+ * \brief Writes the graph to a file in GraphML format
+ *
+ * </para><para>
+ * GraphML is an XML-based file format for representing various types of
+ * graphs. See the GraphML Primer (http://graphml.graphdrawing.org/primer/graphml-primer.html)
+ * for detailed format description.
+ * 
+ * \param graph The graph to write. 
+ * \param outstream The stream object to write to, it should be
+ *        writable.
+ * \param prefixattr Logical value, whether to put a prefix in front of the 
+ *        attribute names to ensure uniqueness if the graph has vertex and 
+ *        edge (or graph) attributes with the same name.
+ * \return Error code:
+ *         \c IGRAPH_EFILE if there is an error
+ *         writing the file. 
+ *
+ * Time complexity: O(|V|+|E|) otherwise. All
+ * file operations are expected to have time complexity 
+ * O(1). 
+ * 
+ * \example examples/simple/graphml.c
+ */
+int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream, 
+			       igraph_bool_t prefixattr) {
+  int ret;
+  igraph_integer_t l, vc;
+  igraph_eit_t it;
+  igraph_strvector_t gnames, vnames, enames;
+  igraph_vector_t gtypes, vtypes, etypes;
+  long int i;
+  igraph_vector_t numv;
+  igraph_strvector_t strv;
+  igraph_vector_bool_t boolv;
+  const char *gprefix= prefixattr ? "g_" : "";
+  const char *vprefix= prefixattr ? "v_" : "";
+  const char *eprefix= prefixattr ? "e_" : "";
+  
+  ret=fprintf(outstream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  ret=fprintf(outstream, "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  ret=fprintf(outstream, "         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  ret=fprintf(outstream, "         xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  ret=fprintf(outstream, "         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  ret=fprintf(outstream, "<!-- Created by igraph -->\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+
+  /* dump the <key> elements if any */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
+  IGRAPH_VECTOR_BOOL_INIT_FINALLY(&boolv, 1);
+
+  IGRAPH_STRVECTOR_INIT_FINALLY(&gnames, 0);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&vnames, 0);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&enames, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&gtypes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
+  igraph_i_attribute_get_info(graph,
+			      &gnames, &gtypes,
+			      &vnames, &vtypes,
+			      &enames, &etypes);
+  
+  /* graph attributes */
+  for (i=0; i<igraph_vector_size(&gtypes); i++) {
+    char *name, *name_escaped;
+    igraph_strvector_get(&gnames, i, &name);
+    IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+    if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"graph\" attr.name=\"%s\" attr.type=\"string\"/>\n", gprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);      
+    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"graph\" attr.name=\"%s\" attr.type=\"double\"/>\n", gprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);            
+    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"graph\" attr.name=\"%s\" attr.type=\"boolean\"/>\n", gprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);            
+    }
+    igraph_Free(name_escaped);
+  }
+
+  /* vertex attributes */
+  for (i=0; i<igraph_vector_size(&vtypes); i++) {
+    char *name, *name_escaped;
+    igraph_strvector_get(&vnames, i, &name);
+    IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+    if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"node\" attr.name=\"%s\" attr.type=\"string\"/>\n", vprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);      
+    } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"node\" attr.name=\"%s\" attr.type=\"double\"/>\n", vprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);            
+    } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"node\" attr.name=\"%s\" attr.type=\"boolean\"/>\n", vprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);            
+    }
+    igraph_Free(name_escaped);
+  }
+
+  /* edge attributes */
+  for (i=0; i<igraph_vector_size(&etypes); i++) {
+    char *name, *name_escaped;
+    igraph_strvector_get(&enames, i, &name);
+    IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+    if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"edge\" attr.name=\"%s\" attr.type=\"string\"/>\n", eprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+    } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"edge\" attr.name=\"%s\" attr.type=\"double\"/>\n", eprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+    } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+      ret=fprintf(outstream, "  <key id=\"%s%s\" for=\"edge\" attr.name=\"%s\" attr.type=\"boolean\"/>\n", eprefix, name_escaped, name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+    }
+    igraph_Free(name_escaped);
+  }
+
+  ret=fprintf(outstream, "  <graph id=\"G\" edgedefault=\"%s\">\n", (igraph_is_directed(graph)?"directed":"undirected"));
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+
+  /* Write the graph atributes before anything else */
+  
+  for (i=0; i<igraph_vector_size(&gtypes); i++) {
+    char *name, *name_escaped;
+    if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_strvector_get(&gnames, i, &name);
+      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]);
+        igraph_Free(name_escaped);
+        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+      char *s, *s_escaped;
+      igraph_strvector_get(&gnames, i, &name);
+      IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+      ret=fprintf(outstream, "    <data key=\"%s%s\">", gprefix, 
+		  name_escaped);
+      igraph_Free(name_escaped);
+      IGRAPH_CHECK(igraph_i_attribute_get_string_graph_attr(graph, name, &strv));
+      igraph_strvector_get(&strv, 0, &s);
+      IGRAPH_CHECK(igraph_i_xml_escape(s, &s_escaped));
+      ret=fprintf(outstream, "%s", s_escaped);
+      igraph_Free(s_escaped);
+      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_BOOLEAN) {
+      igraph_strvector_get(&gnames, i, &name);
+      IGRAPH_CHECK(igraph_i_attribute_get_bool_graph_attr(graph, name, &boolv));
+      IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+      ret=fprintf(outstream, "    <data key=\"%s%s\">%s</data>\n",
+                  gprefix, name_escaped, VECTOR(boolv)[0] ? "true" : "false");
+      igraph_Free(name_escaped);
+      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+    }
+  }
+    
+  /* Let's dump the nodes first */
+  vc=igraph_vcount(graph);
+  for (l=0; l<vc; l++) {
+    char *name, *name_escaped;
+    ret=fprintf(outstream, "    <node id=\"n%ld\">\n", (long)l);
+
+    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+    
+    for (i=0; i<igraph_vector_size(&vtypes); i++) {
+      if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+        igraph_strvector_get(&vnames, i, &name);
+        IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, name,
+                     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]);
+          igraph_Free(name_escaped);
+          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+        }
+      } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+        char *s, *s_escaped;
+        igraph_strvector_get(&vnames, i, &name);
+        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+        ret=fprintf(outstream, "      <data key=\"%s%s\">", vprefix, 
+		    name_escaped);
+        igraph_Free(name_escaped);
+        IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, name,
+                     igraph_vss_1(l), &strv));
+        igraph_strvector_get(&strv, 0, &s);
+        IGRAPH_CHECK(igraph_i_xml_escape(s, &s_escaped));
+        ret=fprintf(outstream, "%s", s_escaped);
+        igraph_Free(s_escaped);
+        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_BOOLEAN) {
+        igraph_strvector_get(&vnames, i, &name);
+        IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, name,
+                     igraph_vss_1(l), &boolv));
+        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+        ret=fprintf(outstream, "      <data key=\"%s%s\">%s</data>\n",
+                    vprefix, name_escaped, VECTOR(boolv)[0] ? "true" : "false");
+        igraph_Free(name_escaped);
+        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+    }
+
+    ret=fprintf(outstream, "    </node>\n");
+    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);    
+  }
+  
+  /* Now the edges */
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &it));
+  IGRAPH_FINALLY(igraph_eit_destroy, &it);
+  while (!IGRAPH_EIT_END(it)) {
+    igraph_integer_t from, to;
+    char *name, *name_escaped;
+    long int edge=IGRAPH_EIT_GET(it);
+    igraph_edge(graph, (igraph_integer_t) edge, &from, &to);
+    ret=fprintf(outstream, "    <edge source=\"n%ld\" target=\"n%ld\">\n", 
+		(long int)from, (long int)to);
+    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+
+    for (i=0; i<igraph_vector_size(&etypes); i++) {
+      if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+        igraph_strvector_get(&enames, i, &name);
+        IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, name,
+			      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]);
+          igraph_Free(name_escaped);
+          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+        }
+      } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+        char *s, *s_escaped;
+        igraph_strvector_get(&enames, i, &name);
+        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+        ret=fprintf(outstream, "      <data key=\"%s%s\">", eprefix, 
+		    name_escaped);
+        igraph_Free(name_escaped);
+        IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, name,
+			     igraph_ess_1((igraph_integer_t) edge), &strv));
+        igraph_strvector_get(&strv, 0, &s);
+        IGRAPH_CHECK(igraph_i_xml_escape(s, &s_escaped));
+        ret=fprintf(outstream, "%s", s_escaped);
+        igraph_Free(s_escaped);
+        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_BOOLEAN) {
+        igraph_strvector_get(&enames, i, &name);
+        IGRAPH_CHECK(igraph_i_attribute_get_bool_edge_attr(graph, name,
+			   igraph_ess_1((igraph_integer_t) edge), &boolv));
+        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
+        ret=fprintf(outstream, "      <data key=\"%s%s\">%s</data>\n",
+                    eprefix, name_escaped, VECTOR(boolv)[0] ? "true" : "false");
+        igraph_Free(name_escaped);
+        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+    }
+
+    ret=fprintf(outstream, "    </edge>\n");
+    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+    IGRAPH_EIT_NEXT(it);
+  }
+  igraph_eit_destroy(&it);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  ret=fprintf(outstream, "  </graph>\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  fprintf(outstream, "</graphml>\n");
+  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+  
+  igraph_strvector_destroy(&gnames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&enames);
+  igraph_vector_destroy(&gtypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&etypes);
+  igraph_vector_destroy(&numv);
+  igraph_strvector_destroy(&strv);
+  igraph_vector_bool_destroy(&boolv);
+  IGRAPH_FINALLY_CLEAN(9);
+
+  return 0;
+}
diff --git a/src/foreign-lgl-header.h b/src/foreign-lgl-header.h
new file mode 100644
index 0000000..46e5cf6
--- /dev/null
+++ b/src/foreign-lgl-header.h
@@ -0,0 +1,35 @@
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi at rmki.kfki.hu>
+   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_vector.h"
+#include "igraph_types_internal.h"
+
+typedef struct {
+  void *scanner;
+  int eof;
+  char errmsg[300];
+  int has_weights;
+  igraph_vector_t *vector;
+  igraph_vector_t *weights;
+  igraph_trie_t *trie;
+  int actvertex;
+} igraph_i_lgl_parsedata_t;
diff --git a/src/foreign-lgl-lexer.c b/src/foreign-lgl-lexer.c
new file mode 100644
index 0000000..4dcfdcc
--- /dev/null
+++ b/src/foreign-lgl-lexer.c
@@ -0,0 +1,2013 @@
+#line 2 "foreign-lgl-lexer.c"
+
+#line 4 "foreign-lgl-lexer.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE igraph_lgl_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via igraph_lgl_yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void igraph_lgl_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void igraph_lgl_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_lgl_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void igraph_lgl_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_lgl_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_lgl_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void igraph_lgl_yypop_buffer_state (yyscan_t yyscanner );
+
+static void igraph_lgl_yyensure_buffer_stack (yyscan_t yyscanner );
+static void igraph_lgl_yy_load_buffer_state (yyscan_t yyscanner );
+static void igraph_lgl_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER igraph_lgl_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE igraph_lgl_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_lgl_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_lgl_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *igraph_lgl_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *igraph_lgl_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void igraph_lgl_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer igraph_lgl_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        igraph_lgl_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_lgl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        igraph_lgl_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_lgl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define igraph_lgl_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (yy_size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 5
+#define YY_END_OF_BUFFER 6
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[13] =
+    {   0,
+        2,    2,    6,    4,    2,    3,    3,    1,    4,    2,
+        3,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    1,    5,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[6] =
+    {   0,
+        1,    2,    3,    4,    5
+    } ;
+
+static yyconst flex_int16_t yy_base[17] =
+    {   0,
+        0,    0,   10,    0,    0,    0,    0,   11,    0,    0,
+       11,   11,    8,    6,    3,    3
+    } ;
+
+static yyconst flex_int16_t yy_def[17] =
+    {   0,
+       12,    1,   12,   13,   14,   15,   16,   12,   13,   14,
+       12,    0,   12,   12,   12,   12
+    } ;
+
+static yyconst flex_int16_t yy_nxt[17] =
+    {   0,
+        4,    5,    6,    7,    8,   11,   11,   10,    9,   12,
+        3,   12,   12,   12,   12,   12
+    } ;
+
+static yyconst flex_int16_t yy_chk[17] =
+    {   0,
+        1,    1,    1,    1,    1,   16,   15,   14,   13,    3,
+       12,   12,   12,   12,   12,   12
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "foreign-lgl-lexer.l"
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+#line 24 "foreign-lgl-lexer.l"
+
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-lgl-header.h"
+#include "foreign-lgl-parser.h"
+#define YY_EXTRA_TYPE igraph_i_lgl_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+#define YY_NO_INPUT 1
+#line 504 "foreign-lgl-lexer.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    yy_size_t yy_n_chars;
+    yy_size_t yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    YYLTYPE * yylloc_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+    #    define yylloc yyg->yylloc_r
+    
+int igraph_lgl_yylex_init (yyscan_t* scanner);
+
+int igraph_lgl_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int igraph_lgl_yylex_destroy (yyscan_t yyscanner );
+
+int igraph_lgl_yyget_debug (yyscan_t yyscanner );
+
+void igraph_lgl_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE igraph_lgl_yyget_extra (yyscan_t yyscanner );
+
+void igraph_lgl_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *igraph_lgl_yyget_in (yyscan_t yyscanner );
+
+void igraph_lgl_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *igraph_lgl_yyget_out (yyscan_t yyscanner );
+
+void igraph_lgl_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t igraph_lgl_yyget_leng (yyscan_t yyscanner );
+
+char *igraph_lgl_yyget_text (yyscan_t yyscanner );
+
+int igraph_lgl_yyget_lineno (yyscan_t yyscanner );
+
+void igraph_lgl_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * igraph_lgl_yyget_lval (yyscan_t yyscanner );
+
+void igraph_lgl_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+       YYLTYPE *igraph_lgl_yyget_lloc (yyscan_t yyscanner );
+    
+        void igraph_lgl_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+    
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int igraph_lgl_yywrap (yyscan_t yyscanner );
+#else
+extern int igraph_lgl_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		yy_size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int igraph_lgl_yylex \
+               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int igraph_lgl_yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 80 "foreign-lgl-lexer.l"
+
+
+ /* --------------------------------------------------hashmark------*/
+#line 747 "foreign-lgl-lexer.c"
+
+    yylval = yylval_param;
+
+    yylloc = yylloc_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			igraph_lgl_yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				igraph_lgl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		igraph_lgl_yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 13 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 11 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 83 "foreign-lgl-lexer.l"
+{ return HASH; }
+	YY_BREAK
+/* ------------------------------------------------whitespace------*/
+case 2:
+YY_RULE_SETUP
+#line 86 "foreign-lgl-lexer.l"
+{ }
+	YY_BREAK
+/* ---------------------------------------------------newline------*/
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 89 "foreign-lgl-lexer.l"
+{ return NEWLINE; }
+	YY_BREAK
+/* ----------------------------------------------alphanumeric------*/
+case 4:
+YY_RULE_SETUP
+#line 92 "foreign-lgl-lexer.l"
+{ return ALNUM; }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 94 "foreign-lgl-lexer.l"
+{ if (yyextra->eof) {
+                       yyterminate();
+                    } else {
+                       yyextra->eof=1;
+                       return NEWLINE; 
+                    }
+                  }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 102 "foreign-lgl-lexer.l"
+ECHO;
+	YY_BREAK
+#line 873 "foreign-lgl-lexer.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * igraph_lgl_yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( igraph_lgl_yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of igraph_lgl_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					igraph_lgl_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			igraph_lgl_yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) igraph_lgl_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 13 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 13 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 12);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					igraph_lgl_yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( igraph_lgl_yywrap(yyscanner ) )
+						return 0;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void igraph_lgl_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        igraph_lgl_yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            igraph_lgl_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	igraph_lgl_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	igraph_lgl_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_lgl_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		igraph_lgl_yypop_buffer_state();
+	 *		igraph_lgl_yypush_buffer_state(new_buffer);
+     */
+	igraph_lgl_yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	igraph_lgl_yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (igraph_lgl_yywrap()) processing, but the only time this flag
+	 * is looked at is after igraph_lgl_yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void igraph_lgl_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE igraph_lgl_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) igraph_lgl_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_lgl_yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) igraph_lgl_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_lgl_yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	igraph_lgl_yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with igraph_lgl_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void igraph_lgl_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		igraph_lgl_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	igraph_lgl_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a igraph_lgl_yyrestart() or at EOF.
+ */
+    static void igraph_lgl_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	igraph_lgl_yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then igraph_lgl_yy_init_buffer was _probably_
+     * called from igraph_lgl_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_lgl_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		igraph_lgl_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_lgl_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	igraph_lgl_yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from igraph_lgl_yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from igraph_lgl_yy_switch_to_buffer. */
+	igraph_lgl_yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_lgl_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	igraph_lgl_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		igraph_lgl_yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void igraph_lgl_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	yy_size_t num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_lgl_yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_lgl_yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_lgl_yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_lgl_yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE igraph_lgl_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) igraph_lgl_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_lgl_yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	igraph_lgl_yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to igraph_lgl_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       igraph_lgl_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE igraph_lgl_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return igraph_lgl_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to igraph_lgl_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE igraph_lgl_yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n, i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) igraph_lgl_yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_lgl_yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = igraph_lgl_yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in igraph_lgl_yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE igraph_lgl_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_lgl_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_lgl_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_lgl_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_lgl_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t igraph_lgl_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *igraph_lgl_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void igraph_lgl_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_lgl_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_lgl_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_lgl_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_lgl_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see igraph_lgl_yy_switch_to_buffer
+ */
+void igraph_lgl_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void igraph_lgl_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int igraph_lgl_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void igraph_lgl_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * igraph_lgl_yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void igraph_lgl_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+YYLTYPE *igraph_lgl_yyget_lloc  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylloc;
+}
+    
+void igraph_lgl_yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylloc = yylloc_param;
+}
+    
+/* User-visible API */
+
+/* igraph_lgl_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int igraph_lgl_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) igraph_lgl_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* igraph_lgl_yylex_init_extra has the same functionality as igraph_lgl_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to igraph_lgl_yyalloc in
+ * the yyextra field.
+ */
+
+int igraph_lgl_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    igraph_lgl_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) igraph_lgl_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    igraph_lgl_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from igraph_lgl_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * igraph_lgl_yylex_init()
+     */
+    return 0;
+}
+
+/* igraph_lgl_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int igraph_lgl_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		igraph_lgl_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		igraph_lgl_yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	igraph_lgl_yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        igraph_lgl_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * igraph_lgl_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    igraph_lgl_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *igraph_lgl_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *igraph_lgl_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void igraph_lgl_yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see igraph_lgl_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 102 "foreign-lgl-lexer.l"
+
+
+
diff --git a/src/foreign-lgl-lexer.l b/src/foreign-lgl-lexer.l
new file mode 100644
index 0000000..1df87b3
--- /dev/null
+++ b/src/foreign-lgl-lexer.l
@@ -0,0 +1,102 @@
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-lgl-header.h"
+#include "foreign-lgl-parser.h"
+#define YY_EXTRA_TYPE igraph_i_lgl_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+%}
+
+%option noyywrap
+%option prefix="igraph_lgl_yy"
+%option outfile="lex.yy.c"
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+alnum [^ \t\r\n#]
+
+%%
+
+ /* --------------------------------------------------hashmark------*/
+#                    { return HASH; }
+
+ /* ------------------------------------------------whitespace------*/
+[ \t]*               { }
+
+ /* ---------------------------------------------------newline------*/
+\n\r|\r\n|\n|\r      { return NEWLINE; }
+
+ /* ----------------------------------------------alphanumeric------*/
+{alnum}+             { return ALNUM; }
+
+<<EOF>>           { if (yyextra->eof) {
+                       yyterminate();
+                    } else {
+                       yyextra->eof=1;
+                       return NEWLINE; 
+                    }
+                  }
+
+%%
diff --git a/src/foreign-lgl-parser.c b/src/foreign-lgl-parser.c
new file mode 100644
index 0000000..6c478d0
--- /dev/null
+++ b/src/foreign-lgl-parser.c
@@ -0,0 +1,1698 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 1
+
+/* Substitute the variable and function names.  */
+#define yyparse igraph_lgl_yyparse
+#define yylex   igraph_lgl_yylex
+#define yyerror igraph_lgl_yyerror
+#define yylval  igraph_lgl_yylval
+#define yychar  igraph_lgl_yychar
+#define yydebug igraph_lgl_yydebug
+#define yynerrs igraph_lgl_yynerrs
+#define yylloc igraph_lgl_yylloc
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     ALNUM = 258,
+     NEWLINE = 259,
+     HASH = 260
+   };
+#endif
+/* Tokens.  */
+#define ALNUM 258
+#define NEWLINE 259
+#define HASH 260
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 23 "foreign-lgl-parser.y"
+
+
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "igraph_hacks_internal.h"
+#include "igraph_types.h" 
+#include "igraph_types_internal.h"
+#include "igraph_math.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "config.h"
+#include "foreign-lgl-header.h"
+#include "foreign-lgl-parser.h"
+
+#define yyscan_t void*
+
+int igraph_lgl_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, 
+		     void* scanner);
+int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, 
+		       char *s);
+char *igraph_lgl_yyget_text (yyscan_t yyscanner );
+int igraph_lgl_yyget_leng (yyscan_t yyscanner );
+igraph_real_t igraph_lgl_get_number(const char *str, long int len);
+
+#define scanner context->scanner
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 86 "foreign-lgl-parser.y"
+{
+  long int edgenum;
+  double weightnum;
+}
+/* Line 193 of yacc.c.  */
+#line 173 "foreign-lgl-parser.c"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 198 "foreign-lgl-parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+    YYLTYPE yyls;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   10
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  6
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  8
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  12
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  17
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   260
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     4,     7,    10,    13,    17,    18,    21,
+      24,    28,    30
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+       7,     0,    -1,    -1,     7,     4,    -1,     7,     8,    -1,
+       9,    10,    -1,     5,    12,     4,    -1,    -1,    10,    11,
+      -1,    12,     4,    -1,    12,    13,     4,    -1,     3,    -1,
+       3,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,   100,   100,   101,   102,   105,   107,   109,   109,   111,
+     116,   125,   130
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "ALNUM", "NEWLINE", "HASH", "$accept",
+  "input", "vertex", "vertexdef", "edges", "edge", "edgeid", "weight", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,     6,     7,     7,     7,     8,     9,    10,    10,    11,
+      11,    12,    13
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     2,     3,     0,     2,     2,
+       3,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,     0,     1,     3,     0,     4,     7,    11,     0,     5,
+       6,     8,     0,    12,     9,     0,    10
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     1,     5,     6,     9,    11,     8,    15
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -3
+static const yytype_int8 yypact[] =
+{
+      -3,     0,    -3,    -3,     3,    -3,    -3,    -3,    -1,     3,
+      -3,    -3,    -2,    -3,    -3,     4,    -3
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+      -3,    -3,    -3,    -3,    -3,    -3,     1,    -3
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+       2,    13,    14,    10,     3,     4,     7,     0,    16,     0,
+      12
+};
+
+static const yytype_int8 yycheck[] =
+{
+       0,     3,     4,     4,     4,     5,     3,    -1,     4,    -1,
+       9
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     7,     0,     4,     5,     8,     9,     3,    12,    10,
+       4,    11,    12,     3,     4,    13,     4
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, Location, context); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_lgl_parsedata_t* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_lgl_parsedata_t* context;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (yylocationp);
+  YYUSE (context);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_lgl_parsedata_t* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_lgl_parsedata_t* context;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, igraph_i_lgl_parsedata_t* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+    YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
+    int yyrule;
+    igraph_i_lgl_parsedata_t* context;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       , &(yylsp[(yyi + 1) - (yynrhs)])		       , context);
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+

+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, igraph_i_lgl_parsedata_t* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
+    igraph_i_lgl_parsedata_t* context;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (context);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (igraph_i_lgl_parsedata_t* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (igraph_i_lgl_parsedata_t* context)
+#else
+int
+yyparse (context)
+    igraph_i_lgl_parsedata_t* context;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+/* Location data for the look-ahead symbol.  */
+YYLTYPE yylloc;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+  /* The locations where the error started and ended.  */
+  YYLTYPE yyerror_range[2];
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+  yylsp = yyls;
+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  /* Initialize the default location before parsing starts.  */
+  yylloc.first_line   = yylloc.last_line   = 1;
+  yylloc.first_column = yylloc.last_column = 0;
+#endif
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+	YYLTYPE *yyls1 = yyls;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+	yyls = yyls1;
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+	YYSTACK_RELOCATE (yyls);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 6:
+#line 107 "foreign-lgl-parser.y"
+    { context->actvertex=(yyvsp[(2) - (3)].edgenum); }
+    break;
+
+  case 9:
+#line 111 "foreign-lgl-parser.y"
+    { 
+             igraph_vector_push_back(context->vector, context->actvertex);
+             igraph_vector_push_back(context->vector, (yyvsp[(1) - (2)].edgenum));
+             igraph_vector_push_back(context->weights, 0);
+           }
+    break;
+
+  case 10:
+#line 116 "foreign-lgl-parser.y"
+    { 
+	     igraph_vector_push_back(context->vector, context->actvertex);
+             igraph_vector_push_back(context->vector, (yyvsp[(1) - (3)].edgenum));
+             igraph_vector_push_back(context->weights, (yyvsp[(2) - (3)].weightnum));
+	     context->has_weights = 1;
+           }
+    break;
+
+  case 11:
+#line 125 "foreign-lgl-parser.y"
+    { igraph_trie_get2(context->trie, 
+				   igraph_lgl_yyget_text(scanner), 
+				   igraph_lgl_yyget_leng(scanner), 
+				   &(yyval.edgenum)); }
+    break;
+
+  case 12:
+#line 130 "foreign-lgl-parser.y"
+    { (yyval.weightnum)=igraph_lgl_get_number(igraph_lgl_yyget_text(scanner), 
+					   igraph_lgl_yyget_leng(scanner)); }
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 1458 "foreign-lgl-parser.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (&yylloc, context, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (&yylloc, context, yymsg);
+	  }
+	else
+	  {
+	    yyerror (&yylloc, context, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+  yyerror_range[0] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, &yylloc, context);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[0] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      yyerror_range[0] = *yylsp;
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+  yyerror_range[1] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the look-ahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (&yylloc, context, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, &yylloc, context);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 133 "foreign-lgl-parser.y"
+
+
+int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, 
+		       char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char), 
+	   "Parse error in LGL file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+igraph_real_t igraph_lgl_get_number(const char *str, long int length) {
+  igraph_real_t num;
+  char *tmp=igraph_Calloc(length+1, char);
+  
+  strncpy(tmp, str, length);
+  tmp[length]='\0';
+  sscanf(tmp, "%lf", &num);
+  igraph_Free(tmp);
+  return num;
+} 
+
diff --git a/src/foreign-lgl-parser.h b/src/foreign-lgl-parser.h
new file mode 100644
index 0000000..86595d8
--- /dev/null
+++ b/src/foreign-lgl-parser.h
@@ -0,0 +1,85 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     ALNUM = 258,
+     NEWLINE = 259,
+     HASH = 260
+   };
+#endif
+/* Tokens.  */
+#define ALNUM 258
+#define NEWLINE 259
+#define HASH 260
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 86 "foreign-lgl-parser.y"
+{
+  long int edgenum;
+  double weightnum;
+}
+/* Line 1529 of yacc.c.  */
+#line 64 "foreign-lgl-parser.h"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
diff --git a/src/foreign-lgl-parser.y b/src/foreign-lgl-parser.y
new file mode 100644
index 0000000..66e61b9
--- /dev/null
+++ b/src/foreign-lgl-parser.y
@@ -0,0 +1,152 @@
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "igraph_hacks_internal.h"
+#include "igraph_types.h" 
+#include "igraph_types_internal.h"
+#include "igraph_math.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "config.h"
+#include "foreign-lgl-header.h"
+#include "foreign-lgl-parser.h"
+
+#define yyscan_t void*
+
+int igraph_lgl_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, 
+		     void* scanner);
+int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, 
+		       char *s);
+char *igraph_lgl_yyget_text (yyscan_t yyscanner );
+int igraph_lgl_yyget_leng (yyscan_t yyscanner );
+igraph_real_t igraph_lgl_get_number(const char *str, long int len);
+
+#define scanner context->scanner
+%}
+
+%pure-parser
+%output="y.tab.c"
+%name-prefix="igraph_lgl_yy"
+%defines
+%locations
+%error-verbose
+%parse-param { igraph_i_lgl_parsedata_t* context }
+%lex-param { void *scanner }
+
+%union {
+  long int edgenum;
+  double weightnum;
+}
+
+%type <edgenum>   edgeid
+%type <weightnum> weight
+
+%token ALNUM
+%token NEWLINE
+%token HASH
+
+%%
+
+input :    /* empty */
+         | input NEWLINE
+         | input vertex
+;
+
+vertex : vertexdef edges ;
+
+vertexdef : HASH edgeid NEWLINE       { context->actvertex=$2; } ;
+
+edges :   /* empty */ | edges edge ;
+
+edge :   edgeid NEWLINE             { 
+             igraph_vector_push_back(context->vector, context->actvertex);
+             igraph_vector_push_back(context->vector, $1);
+             igraph_vector_push_back(context->weights, 0);
+           }
+       | edgeid weight NEWLINE      { 
+	     igraph_vector_push_back(context->vector, context->actvertex);
+             igraph_vector_push_back(context->vector, $1);
+             igraph_vector_push_back(context->weights, $2);
+	     context->has_weights = 1;
+           } 
+;
+
+
+edgeid : ALNUM  { igraph_trie_get2(context->trie, 
+				   igraph_lgl_yyget_text(scanner), 
+				   igraph_lgl_yyget_leng(scanner), 
+				   &$$); };
+
+weight : ALNUM  { $$=igraph_lgl_get_number(igraph_lgl_yyget_text(scanner), 
+					   igraph_lgl_yyget_leng(scanner)); } ;
+
+%%
+
+int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, 
+		       char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char), 
+	   "Parse error in LGL file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+igraph_real_t igraph_lgl_get_number(const char *str, long int length) {
+  igraph_real_t num;
+  char *tmp=igraph_Calloc(length+1, char);
+  
+  strncpy(tmp, str, length);
+  tmp[length]='\0';
+  sscanf(tmp, "%lf", &num);
+  igraph_Free(tmp);
+  return num;
+} 
diff --git a/src/foreign-ncol-header.h b/src/foreign-ncol-header.h
new file mode 100644
index 0000000..b810db2
--- /dev/null
+++ b/src/foreign-ncol-header.h
@@ -0,0 +1,34 @@
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi at rmki.kfki.hu>
+   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_vector.h"
+#include "igraph_types_internal.h"
+
+typedef struct {
+  void *scanner;
+  int eof;
+  char errmsg[300];
+  int has_weights;
+  igraph_vector_t *vector;
+  igraph_vector_t *weights;
+  igraph_trie_t *trie;
+} igraph_i_ncol_parsedata_t;
diff --git a/src/foreign-ncol-lexer.c b/src/foreign-ncol-lexer.c
new file mode 100644
index 0000000..050e489
--- /dev/null
+++ b/src/foreign-ncol-lexer.c
@@ -0,0 +1,2008 @@
+#line 2 "foreign-ncol-lexer.c"
+
+#line 4 "foreign-ncol-lexer.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE igraph_ncol_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via igraph_ncol_yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void igraph_ncol_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void igraph_ncol_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_ncol_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void igraph_ncol_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_ncol_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_ncol_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void igraph_ncol_yypop_buffer_state (yyscan_t yyscanner );
+
+static void igraph_ncol_yyensure_buffer_stack (yyscan_t yyscanner );
+static void igraph_ncol_yy_load_buffer_state (yyscan_t yyscanner );
+static void igraph_ncol_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER igraph_ncol_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE igraph_ncol_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_ncol_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_ncol_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *igraph_ncol_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *igraph_ncol_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void igraph_ncol_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer igraph_ncol_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        igraph_ncol_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_ncol_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        igraph_ncol_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_ncol_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define igraph_ncol_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (yy_size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 4
+#define YY_END_OF_BUFFER 5
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[12] =
+    {   0,
+        1,    1,    5,    3,    1,    2,    2,    3,    1,    2,
+        0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[5] =
+    {   0,
+        1,    2,    3,    4
+    } ;
+
+static yyconst flex_int16_t yy_base[16] =
+    {   0,
+        0,    0,    9,    0,    0,    0,    0,    0,    0,   10,
+       10,    7,    5,    2,    2
+    } ;
+
+static yyconst flex_int16_t yy_def[16] =
+    {   0,
+       11,    1,   11,   12,   13,   14,   15,   12,   13,   11,
+        0,   11,   11,   11,   11
+    } ;
+
+static yyconst flex_int16_t yy_nxt[15] =
+    {   0,
+        4,    5,    6,    7,   10,   10,    9,    8,   11,    3,
+       11,   11,   11,   11
+    } ;
+
+static yyconst flex_int16_t yy_chk[15] =
+    {   0,
+        1,    1,    1,    1,   15,   14,   13,   12,    3,   11,
+       11,   11,   11,   11
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "foreign-ncol-lexer.l"
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+#line 24 "foreign-ncol-lexer.l"
+
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-ncol-header.h"
+#include "foreign-ncol-parser.h"
+#define YY_EXTRA_TYPE igraph_i_ncol_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+#define YY_NO_INPUT 1
+#line 504 "foreign-ncol-lexer.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    yy_size_t yy_n_chars;
+    yy_size_t yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    YYLTYPE * yylloc_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+    #    define yylloc yyg->yylloc_r
+    
+int igraph_ncol_yylex_init (yyscan_t* scanner);
+
+int igraph_ncol_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int igraph_ncol_yylex_destroy (yyscan_t yyscanner );
+
+int igraph_ncol_yyget_debug (yyscan_t yyscanner );
+
+void igraph_ncol_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE igraph_ncol_yyget_extra (yyscan_t yyscanner );
+
+void igraph_ncol_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *igraph_ncol_yyget_in (yyscan_t yyscanner );
+
+void igraph_ncol_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *igraph_ncol_yyget_out (yyscan_t yyscanner );
+
+void igraph_ncol_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t igraph_ncol_yyget_leng (yyscan_t yyscanner );
+
+char *igraph_ncol_yyget_text (yyscan_t yyscanner );
+
+int igraph_ncol_yyget_lineno (yyscan_t yyscanner );
+
+void igraph_ncol_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * igraph_ncol_yyget_lval (yyscan_t yyscanner );
+
+void igraph_ncol_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+       YYLTYPE *igraph_ncol_yyget_lloc (yyscan_t yyscanner );
+    
+        void igraph_ncol_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+    
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int igraph_ncol_yywrap (yyscan_t yyscanner );
+#else
+extern int igraph_ncol_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		yy_size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int igraph_ncol_yylex \
+               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int igraph_ncol_yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 80 "foreign-ncol-lexer.l"
+
+
+ /* ------------------------------------------------whitespace------*/
+#line 747 "foreign-ncol-lexer.c"
+
+    yylval = yylval_param;
+
+    yylloc = yylloc_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			igraph_ncol_yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				igraph_ncol_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		igraph_ncol_yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 12 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 10 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 83 "foreign-ncol-lexer.l"
+{ }
+	YY_BREAK
+/* ---------------------------------------------------newline------*/
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 86 "foreign-ncol-lexer.l"
+{ return NEWLINE; }
+	YY_BREAK
+/* ----------------------------------------------alphanumeric------*/
+case 3:
+YY_RULE_SETUP
+#line 89 "foreign-ncol-lexer.l"
+{ return ALNUM; }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 91 "foreign-ncol-lexer.l"
+{ if (yyextra->eof) {
+                       yyterminate();
+                    } else {
+                       yyextra->eof=1;
+                       return NEWLINE; 
+                    }
+                  }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 99 "foreign-ncol-lexer.l"
+ECHO;
+	YY_BREAK
+#line 867 "foreign-ncol-lexer.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * igraph_ncol_yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( igraph_ncol_yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of igraph_ncol_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					igraph_ncol_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			igraph_ncol_yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) igraph_ncol_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 12 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 12 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 11);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					igraph_ncol_yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( igraph_ncol_yywrap(yyscanner ) )
+						return 0;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void igraph_ncol_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        igraph_ncol_yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            igraph_ncol_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	igraph_ncol_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	igraph_ncol_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_ncol_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		igraph_ncol_yypop_buffer_state();
+	 *		igraph_ncol_yypush_buffer_state(new_buffer);
+     */
+	igraph_ncol_yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	igraph_ncol_yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (igraph_ncol_yywrap()) processing, but the only time this flag
+	 * is looked at is after igraph_ncol_yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void igraph_ncol_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE igraph_ncol_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) igraph_ncol_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_ncol_yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) igraph_ncol_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_ncol_yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	igraph_ncol_yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with igraph_ncol_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void igraph_ncol_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		igraph_ncol_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	igraph_ncol_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a igraph_ncol_yyrestart() or at EOF.
+ */
+    static void igraph_ncol_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	igraph_ncol_yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then igraph_ncol_yy_init_buffer was _probably_
+     * called from igraph_ncol_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_ncol_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		igraph_ncol_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_ncol_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	igraph_ncol_yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from igraph_ncol_yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from igraph_ncol_yy_switch_to_buffer. */
+	igraph_ncol_yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_ncol_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	igraph_ncol_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		igraph_ncol_yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void igraph_ncol_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	yy_size_t num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_ncol_yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_ncol_yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_ncol_yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_ncol_yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE igraph_ncol_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) igraph_ncol_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_ncol_yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	igraph_ncol_yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to igraph_ncol_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       igraph_ncol_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE igraph_ncol_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return igraph_ncol_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to igraph_ncol_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE igraph_ncol_yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n, i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) igraph_ncol_yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_ncol_yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = igraph_ncol_yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in igraph_ncol_yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE igraph_ncol_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_ncol_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_ncol_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_ncol_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_ncol_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t igraph_ncol_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *igraph_ncol_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void igraph_ncol_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_ncol_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_ncol_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_ncol_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_ncol_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see igraph_ncol_yy_switch_to_buffer
+ */
+void igraph_ncol_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void igraph_ncol_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int igraph_ncol_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void igraph_ncol_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * igraph_ncol_yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void igraph_ncol_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+YYLTYPE *igraph_ncol_yyget_lloc  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylloc;
+}
+    
+void igraph_ncol_yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylloc = yylloc_param;
+}
+    
+/* User-visible API */
+
+/* igraph_ncol_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int igraph_ncol_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) igraph_ncol_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* igraph_ncol_yylex_init_extra has the same functionality as igraph_ncol_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to igraph_ncol_yyalloc in
+ * the yyextra field.
+ */
+
+int igraph_ncol_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    igraph_ncol_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) igraph_ncol_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    igraph_ncol_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from igraph_ncol_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * igraph_ncol_yylex_init()
+     */
+    return 0;
+}
+
+/* igraph_ncol_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int igraph_ncol_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		igraph_ncol_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		igraph_ncol_yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	igraph_ncol_yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        igraph_ncol_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * igraph_ncol_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    igraph_ncol_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *igraph_ncol_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *igraph_ncol_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void igraph_ncol_yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see igraph_ncol_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 99 "foreign-ncol-lexer.l"
+
+
+
+
diff --git a/src/foreign-ncol-lexer.l b/src/foreign-ncol-lexer.l
new file mode 100644
index 0000000..1411736
--- /dev/null
+++ b/src/foreign-ncol-lexer.l
@@ -0,0 +1,100 @@
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-ncol-header.h"
+#include "foreign-ncol-parser.h"
+#define YY_EXTRA_TYPE igraph_i_ncol_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+%}
+
+%option noyywrap
+%option prefix="igraph_ncol_yy"
+%option outfile="lex.yy.c"
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+alnum [^ \t\n\r]
+
+%%
+
+ /* ------------------------------------------------whitespace------*/
+[ \t]*               { }
+
+ /* ---------------------------------------------------newline------*/
+\n\r|\r\n|\n|\r      { return NEWLINE; }
+
+ /* ----------------------------------------------alphanumeric------*/
+{alnum}+             { return ALNUM; }
+
+<<EOF>>           { if (yyextra->eof) {
+                       yyterminate();
+                    } else {
+                       yyextra->eof=1;
+                       return NEWLINE; 
+                    }
+                  }
+
+%%
+
diff --git a/src/foreign-ncol-parser.c b/src/foreign-ncol-parser.c
new file mode 100644
index 0000000..1749b10
--- /dev/null
+++ b/src/foreign-ncol-parser.c
@@ -0,0 +1,1687 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 1
+
+/* Substitute the variable and function names.  */
+#define yyparse igraph_ncol_yyparse
+#define yylex   igraph_ncol_yylex
+#define yyerror igraph_ncol_yyerror
+#define yylval  igraph_ncol_yylval
+#define yychar  igraph_ncol_yychar
+#define yydebug igraph_ncol_yydebug
+#define yynerrs igraph_ncol_yynerrs
+#define yylloc igraph_ncol_yylloc
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     ALNUM = 258,
+     NEWLINE = 259
+   };
+#endif
+/* Tokens.  */
+#define ALNUM 258
+#define NEWLINE 259
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 23 "foreign-ncol-parser.y"
+
+
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "igraph_hacks_internal.h"
+#include "igraph_types.h" 
+#include "igraph_types_internal.h"
+#include "igraph_math.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "config.h"
+#include "foreign-ncol-header.h"
+#include "foreign-ncol-parser.h"
+
+#define yyscan_t void*
+
+int igraph_ncol_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, 
+		      void* scanner);
+int igraph_ncol_yyerror(YYLTYPE* locp, 
+			igraph_i_ncol_parsedata_t *context, 
+			const char *s);
+char *igraph_ncol_yyget_text (yyscan_t yyscanner );
+int igraph_ncol_yyget_leng (yyscan_t yyscanner );
+igraph_real_t igraph_ncol_get_number(const char *str, long int len);
+
+#define scanner context->scanner
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 87 "foreign-ncol-parser.y"
+{
+  long int edgenum;
+  double weightnum;
+}
+/* Line 193 of yacc.c.  */
+#line 172 "foreign-ncol-parser.c"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 197 "foreign-ncol-parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+    YYLTYPE yyls;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   10
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  5
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  5
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  8
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  12
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   259
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint8 yyprhs[] =
+{
+       0,     0,     3,     4,     7,    10,    14,    19,    21
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+       6,     0,    -1,    -1,     6,     4,    -1,     6,     7,    -1,
+       8,     8,     4,    -1,     8,     8,     9,     4,    -1,     3,
+      -1,     3,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint8 yyrline[] =
+{
+       0,   100,   100,   101,   102,   105,   110,   118,   123
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "ALNUM", "NEWLINE", "$accept", "input",
+  "edge", "edgeid", "weight", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,     5,     6,     6,     6,     7,     7,     8,     9
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     3,     4,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,     0,     1,     7,     3,     4,     0,     0,     8,     5,
+       0,     6
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     1,     5,     6,    10
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -3
+static const yytype_int8 yypact[] =
+{
+      -3,     0,    -3,    -3,    -3,    -3,     2,    -2,    -3,    -3,
+       3,    -3
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+      -3,    -3,    -3,     4,    -3
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+       2,     8,     9,     3,     4,     3,     0,    11,     0,     0,
+       7
+};
+
+static const yytype_int8 yycheck[] =
+{
+       0,     3,     4,     3,     4,     3,    -1,     4,    -1,    -1,
+       6
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     6,     0,     3,     4,     7,     8,     8,     3,     4,
+       9,     4
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, Location, context); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_ncol_parsedata_t* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_ncol_parsedata_t* context;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (yylocationp);
+  YYUSE (context);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_ncol_parsedata_t* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_ncol_parsedata_t* context;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, igraph_i_ncol_parsedata_t* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+    YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
+    int yyrule;
+    igraph_i_ncol_parsedata_t* context;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       , &(yylsp[(yyi + 1) - (yynrhs)])		       , context);
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+

+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, igraph_i_ncol_parsedata_t* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
+    igraph_i_ncol_parsedata_t* context;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (context);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (igraph_i_ncol_parsedata_t* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (igraph_i_ncol_parsedata_t* context)
+#else
+int
+yyparse (context)
+    igraph_i_ncol_parsedata_t* context;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+/* Location data for the look-ahead symbol.  */
+YYLTYPE yylloc;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+  /* The locations where the error started and ended.  */
+  YYLTYPE yyerror_range[2];
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+  yylsp = yyls;
+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  /* Initialize the default location before parsing starts.  */
+  yylloc.first_line   = yylloc.last_line   = 1;
+  yylloc.first_column = yylloc.last_column = 0;
+#endif
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+	YYLTYPE *yyls1 = yyls;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+	yyls = yyls1;
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+	YYSTACK_RELOCATE (yyls);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 5:
+#line 105 "foreign-ncol-parser.y"
+    { 
+           igraph_vector_push_back(context->vector, (yyvsp[(1) - (3)].edgenum));
+           igraph_vector_push_back(context->vector, (yyvsp[(2) - (3)].edgenum));
+           igraph_vector_push_back(context->weights, 0);
+       }
+    break;
+
+  case 6:
+#line 110 "foreign-ncol-parser.y"
+    { 
+           igraph_vector_push_back(context->vector, (yyvsp[(1) - (4)].edgenum));
+           igraph_vector_push_back(context->vector, (yyvsp[(2) - (4)].edgenum));
+           igraph_vector_push_back(context->weights, (yyvsp[(3) - (4)].weightnum));
+	   context->has_weights = 1;
+       }
+    break;
+
+  case 7:
+#line 118 "foreign-ncol-parser.y"
+    { igraph_trie_get2(context->trie, 
+				   igraph_ncol_yyget_text(scanner),
+				   igraph_ncol_yyget_leng(scanner), 
+				   &(yyval.edgenum)); }
+    break;
+
+  case 8:
+#line 123 "foreign-ncol-parser.y"
+    { (yyval.weightnum)=igraph_ncol_get_number(igraph_ncol_yyget_text(scanner), 
+					    igraph_ncol_yyget_leng(scanner)); }
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 1446 "foreign-ncol-parser.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (&yylloc, context, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (&yylloc, context, yymsg);
+	  }
+	else
+	  {
+	    yyerror (&yylloc, context, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+  yyerror_range[0] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, &yylloc, context);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[0] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      yyerror_range[0] = *yylsp;
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+  yyerror_range[1] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the look-ahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (&yylloc, context, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, &yylloc, context);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 126 "foreign-ncol-parser.y"
+
+
+int igraph_ncol_yyerror(YYLTYPE* locp, 
+			igraph_i_ncol_parsedata_t *context, 
+			const char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1, 
+	   "Parse error in NCOL file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+igraph_real_t igraph_ncol_get_number(const char *str, long int length) {
+  igraph_real_t num;
+  char *tmp=igraph_Calloc(length+1, char);
+  
+  strncpy(tmp, str, length);
+  tmp[length]='\0';
+  sscanf(tmp, "%lf", &num);
+  igraph_Free(tmp);
+  return num;
+} 
+
diff --git a/src/foreign-ncol-parser.h b/src/foreign-ncol-parser.h
new file mode 100644
index 0000000..e02187f
--- /dev/null
+++ b/src/foreign-ncol-parser.h
@@ -0,0 +1,83 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     ALNUM = 258,
+     NEWLINE = 259
+   };
+#endif
+/* Tokens.  */
+#define ALNUM 258
+#define NEWLINE 259
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 87 "foreign-ncol-parser.y"
+{
+  long int edgenum;
+  double weightnum;
+}
+/* Line 1529 of yacc.c.  */
+#line 62 "foreign-ncol-parser.h"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
diff --git a/src/foreign-ncol-parser.y b/src/foreign-ncol-parser.y
new file mode 100644
index 0000000..70d04ef
--- /dev/null
+++ b/src/foreign-ncol-parser.y
@@ -0,0 +1,146 @@
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "igraph_hacks_internal.h"
+#include "igraph_types.h" 
+#include "igraph_types_internal.h"
+#include "igraph_math.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "config.h"
+#include "foreign-ncol-header.h"
+#include "foreign-ncol-parser.h"
+
+#define yyscan_t void*
+
+int igraph_ncol_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, 
+		      void* scanner);
+int igraph_ncol_yyerror(YYLTYPE* locp, 
+			igraph_i_ncol_parsedata_t *context, 
+			const char *s);
+char *igraph_ncol_yyget_text (yyscan_t yyscanner );
+int igraph_ncol_yyget_leng (yyscan_t yyscanner );
+igraph_real_t igraph_ncol_get_number(const char *str, long int len);
+
+#define scanner context->scanner
+%}
+
+%pure-parser
+%output="y.tab.c"
+%name-prefix="igraph_ncol_yy"
+%defines
+%locations
+%error-verbose
+%parse-param { igraph_i_ncol_parsedata_t* context }
+%lex-param { void *scanner }
+
+%union {
+  long int edgenum;
+  double weightnum;
+}
+
+%type <edgenum>   edgeid
+%type <weightnum> weight
+
+%token ALNUM
+%token NEWLINE
+
+%%
+
+input :    /* empty */
+         | input NEWLINE
+         | input edge
+;
+
+edge :   edgeid edgeid NEWLINE        { 
+           igraph_vector_push_back(context->vector, $1);
+           igraph_vector_push_back(context->vector, $2);
+           igraph_vector_push_back(context->weights, 0);
+       }
+       | edgeid edgeid weight NEWLINE { 
+           igraph_vector_push_back(context->vector, $1);
+           igraph_vector_push_back(context->vector, $2);
+           igraph_vector_push_back(context->weights, $3);
+	   context->has_weights = 1;
+       }
+;
+
+edgeid : ALNUM  { igraph_trie_get2(context->trie, 
+				   igraph_ncol_yyget_text(scanner),
+				   igraph_ncol_yyget_leng(scanner), 
+				   &$$); };
+
+weight : ALNUM  { $$=igraph_ncol_get_number(igraph_ncol_yyget_text(scanner), 
+					    igraph_ncol_yyget_leng(scanner)); } ;
+
+%%
+
+int igraph_ncol_yyerror(YYLTYPE* locp, 
+			igraph_i_ncol_parsedata_t *context, 
+			const char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1, 
+	   "Parse error in NCOL file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+igraph_real_t igraph_ncol_get_number(const char *str, long int length) {
+  igraph_real_t num;
+  char *tmp=igraph_Calloc(length+1, char);
+  
+  strncpy(tmp, str, length);
+  tmp[length]='\0';
+  sscanf(tmp, "%lf", &num);
+  igraph_Free(tmp);
+  return num;
+} 
diff --git a/src/foreign-pajek-header.h b/src/foreign-pajek-header.h
new file mode 100644
index 0000000..555ee9c
--- /dev/null
+++ b/src/foreign-pajek-header.h
@@ -0,0 +1,43 @@
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi at rmki.kfki.hu>
+   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_vector.h"
+#include "igraph_types_internal.h"
+
+typedef struct {
+  void *scanner;
+  int eof;
+  char errmsg[300];
+  igraph_vector_t *vector;
+  igraph_bool_t directed;
+  int vcount, vcount2;
+  int actfrom;
+  int actto;
+  int mode; /* 0: general, 1: vertex, 2: edge */
+  igraph_trie_t *vertex_attribute_names;
+  igraph_vector_ptr_t *vertex_attributes;
+  igraph_trie_t *edge_attribute_names;
+  igraph_vector_ptr_t *edge_attributes;
+  int vertexid;
+  int actvertex;
+  int actedge;
+} igraph_i_pajek_parsedata_t;
diff --git a/src/foreign-pajek-lexer.c b/src/foreign-pajek-lexer.c
new file mode 100644
index 0000000..27c144e
--- /dev/null
+++ b/src/foreign-pajek-lexer.c
@@ -0,0 +1,2469 @@
+#line 2 "foreign-pajek-lexer.c"
+
+#line 4 "foreign-pajek-lexer.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE igraph_pajek_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via igraph_pajek_yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void igraph_pajek_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void igraph_pajek_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_pajek_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void igraph_pajek_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_pajek_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void igraph_pajek_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void igraph_pajek_yypop_buffer_state (yyscan_t yyscanner );
+
+static void igraph_pajek_yyensure_buffer_stack (yyscan_t yyscanner );
+static void igraph_pajek_yy_load_buffer_state (yyscan_t yyscanner );
+static void igraph_pajek_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER igraph_pajek_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE igraph_pajek_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_pajek_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE igraph_pajek_yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *igraph_pajek_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *igraph_pajek_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void igraph_pajek_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer igraph_pajek_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        igraph_pajek_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_pajek_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        igraph_pajek_yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            igraph_pajek_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define igraph_pajek_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (yy_size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 47
+#define YY_END_OF_BUFFER 48
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[160] =
+    {   0,
+        1,    1,   48,   46,    1,   12,   12,   46,   46,   46,
+       46,   46,   15,   46,   46,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+        1,   12,   46,    0,   13,   46,    0,    2,    3,   46,
+        0,   14,   46,   46,   46,   46,   46,   15,   46,   46,
+       29,   46,   46,   46,   46,   46,   26,   46,   46,   46,
+       46,   46,   46,   38,   46,   46,   46,   46,   27,   46,
+       23,   22,   28,   46,   46,   30,   46,   46,   13,    2,
+        2,   14,   46,   46,   46,   46,   46,   15,   46,   15,
+       33,   34,   37,   19,   20,   46,   46,   31,   32,   18,
+
+       35,   36,   43,   41,   39,   46,   42,   46,   46,   46,
+       46,   46,    3,   46,   46,   46,    4,   46,   46,   45,
+       46,   21,   46,   25,   46,   46,    7,   46,   46,   46,
+       46,   24,   40,   44,   46,   46,   46,    8,   46,   46,
+       46,   46,   46,   46,   46,   11,   46,   46,   16,   17,
+       46,   46,    5,   46,    9,   46,    6,   10,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    5,    1,    1,    6,    1,    1,    7,
+        8,    9,   10,    1,   11,   12,    1,   13,   14,   15,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+        1,    1,    1,    1,   16,   17,   18,   19,   20,   21,
+       22,   23,   24,    1,   25,   26,   27,   28,   29,   30,
+       31,   32,   33,   34,   35,   36,   37,   38,   39,   40,
+        1,    1,    1,    1,   41,    1,   16,   17,   18,   19,
+
+       20,   21,   22,   23,   24,    1,   25,   26,   27,   28,
+       29,   30,   31,   32,   33,   34,   35,   36,   37,   38,
+       39,   40,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[42] =
+    {   0,
+        1,    2,    2,    2,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1
+    } ;
+
+static yyconst flex_int16_t yy_base[167] =
+    {   0,
+        0,    0,  288,    0,  285,  282,  282,   40,   44,   47,
+       36,   44,   53,   67,   42,   72,  255,   39,  265,   47,
+       96,   81,   84,   87,   91,  250,   99,  240,  239,    0,
+      277,  289,  103,  273,    0,  107,   74,  273,  113,  116,
+      268,    0,  243,  255,  257,  252,  251,  117,  108,  125,
+      289,  139,  142,  145,  148,  151,  289,  128,  155,  160,
+      163,  166,  169,  289,  172,  175,  178,  181,  289,  246,
+      289,  289,  289,  229,  242,  289,  246,  245,  289,  261,
+      130,  289,  246,  241,  228,  227,  228,  173,  176,  181,
+      289,  289,  289,  289,  289,  225,  195,  289,  289,  289,
+
+      289,  289,  289,  289,  289,  234,  289,  200,  237,  203,
+      240,  239,  251,  220,  232,  219,  213,  215,  206,  289,
+      209,  289,  212,  289,  230,  229,  220,  212,  220,  214,
+      218,  289,  289,  289,  207,  206,  215,  212,  199,  204,
+      217,  215,  218,  167,  168,    0,  135,  107,  289,  289,
+       91,   80,    0,   63,    0,   58,    0,    0,  289,   79,
+      222,  224,  226,  228,  230,  232
+    } ;
+
+static yyconst flex_int16_t yy_def[167] =
+    {   0,
+      159,    1,  159,  160,  159,  159,  159,  161,  162,  163,
+      160,  160,  160,  160,  160,  160,  160,  160,  160,  160,
+      160,  160,  160,  160,  160,  160,  160,  160,  160,  160,
+      159,  159,  161,  164,  160,  162,  165,  159,  165,  163,
+      166,  160,  160,  160,  160,  160,  160,  160,  160,  160,
+      159,  160,  160,  160,  160,  160,  159,  160,  160,  160,
+      160,  160,  160,  159,  160,  160,  160,  160,  159,  160,
+      159,  159,  159,  160,  160,  159,  160,  160,  159,  159,
+      159,  159,  160,  160,  160,  160,  160,  160,  160,  160,
+      159,  159,  159,  159,  159,  160,  160,  159,  159,  159,
+
+      159,  159,  159,  159,  159,  160,  159,  160,  160,  160,
+      160,  160,  159,  160,  160,  160,  160,  160,  160,  159,
+      160,  159,  160,  159,  160,  160,  160,  160,  160,  160,
+      160,  159,  159,  159,  160,  160,  160,  160,  160,  160,
+      160,  160,  160,  160,  160,  160,  160,  160,  159,  159,
+      160,  160,  160,  160,  160,  160,  160,  160,    0,  159,
+      159,  159,  159,  159,  159,  159
+    } ;
+
+static yyconst flex_int16_t yy_nxt[331] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,    4,   11,    4,
+       12,    4,   13,   13,   13,   14,   15,   16,    4,    4,
+       17,    4,   18,   19,   20,   21,    4,    4,    4,   22,
+       23,   24,   25,    4,   26,    4,   27,   28,   29,    4,
+        4,   34,   34,   34,   35,   37,   38,   39,   41,   41,
+       41,   43,   59,   60,   42,   44,   48,   48,   48,   55,
+       62,   63,   45,   46,   49,   48,   48,   48,   51,   51,
+       51,   47,   50,   57,   57,   57,   38,   39,   56,   30,
+       52,   53,   69,   69,   69,   71,   71,   71,   72,   72,
+       72,  158,   73,   73,   73,  157,   54,   64,   64,   64,
+
+       76,   76,   76,   70,   34,   34,   34,   35,   37,   38,
+       39,   65,  156,   66,   74,   81,   39,   41,   41,   41,
+       88,   88,   88,   42,  155,   67,  154,   68,   49,   48,
+       48,   48,  113,   80,   89,   89,   50,   90,   90,   90,
+       91,   91,   91,   92,   92,   92,   93,   93,   93,   94,
+       94,   94,   95,   95,   95,   96,   98,   98,   98,  153,
+       97,   99,   99,   99,  100,  100,  100,  101,  101,  101,
+      102,  102,  102,  103,  103,  103,  104,  104,  104,  105,
+      105,  105,  107,  107,  107,   88,   88,   88,   90,   90,
+       90,  152,   50,   90,   90,   90,  120,  120,  120,  151,
+
+      106,  122,  122,  122,  124,  124,  124,  132,  132,  132,
+      133,  133,  133,  134,  134,  134,  149,  149,  149,  150,
+      150,  150,   33,   33,   36,   36,   40,   40,   34,   34,
+       37,   37,   41,   41,  148,  147,  146,  145,  144,  143,
+      142,  141,  140,  139,  138,  137,  136,  135,  131,  130,
+      129,  128,  127,  113,  126,  125,  123,  121,  119,  118,
+      117,  116,  115,  114,   80,  112,  111,  110,  109,  108,
+       87,   86,   85,   84,   83,   82,   80,   79,   31,   78,
+       77,   75,   61,   58,   32,   32,   31,  159,    3,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159
+    } ;
+
+static yyconst flex_int16_t yy_chk[331] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    8,    8,    8,    8,    9,    9,    9,   10,   10,
+       10,   11,   18,   18,   10,   11,   12,   12,   12,   15,
+       20,   20,   11,   11,   13,   13,   13,   13,   14,   14,
+       14,   11,   13,   16,   16,   16,   37,   37,   15,  160,
+       14,   14,   22,   22,   22,   23,   23,   23,   24,   24,
+       24,  156,   25,   25,   25,  154,   14,   21,   21,   21,
+
+       27,   27,   27,   22,   33,   33,   33,   33,   36,   36,
+       36,   21,  152,   21,   25,   39,   39,   40,   40,   40,
+       49,   49,   49,   40,  151,   21,  148,   21,   48,   48,
+       48,   48,   81,   81,   50,   50,   48,   50,   50,   50,
+       52,   52,   52,   53,   53,   53,   54,   54,   54,   55,
+       55,   55,   56,   56,   56,   58,   59,   59,   59,  147,
+       58,   60,   60,   60,   61,   61,   61,   62,   62,   62,
+       63,   63,   63,   65,   65,   65,   66,   66,   66,   67,
+       67,   67,   68,   68,   68,   88,   88,   88,   89,   89,
+       89,  145,   88,   90,   90,   90,   97,   97,   97,  144,
+
+       67,  108,  108,  108,  110,  110,  110,  119,  119,  119,
+      121,  121,  121,  123,  123,  123,  142,  142,  142,  143,
+      143,  143,  161,  161,  162,  162,  163,  163,  164,  164,
+      165,  165,  166,  166,  141,  140,  139,  138,  137,  136,
+      135,  131,  130,  129,  128,  127,  126,  125,  118,  117,
+      116,  115,  114,  113,  112,  111,  109,  106,   96,   87,
+       86,   85,   84,   83,   80,   78,   77,   75,   74,   70,
+       47,   46,   45,   44,   43,   41,   38,   34,   31,   29,
+       28,   26,   19,   17,    7,    6,    5,    3,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "foreign-pajek-lexer.l"
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+#line 24 "foreign-pajek-lexer.l"
+
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-pajek-header.h"
+#include "foreign-pajek-parser.h"
+#define YY_EXTRA_TYPE igraph_i_pajek_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+#define YY_NO_INPUT 1
+#line 623 "foreign-pajek-lexer.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    yy_size_t yy_n_chars;
+    yy_size_t yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    YYLTYPE * yylloc_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+    #    define yylloc yyg->yylloc_r
+    
+int igraph_pajek_yylex_init (yyscan_t* scanner);
+
+int igraph_pajek_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int igraph_pajek_yylex_destroy (yyscan_t yyscanner );
+
+int igraph_pajek_yyget_debug (yyscan_t yyscanner );
+
+void igraph_pajek_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE igraph_pajek_yyget_extra (yyscan_t yyscanner );
+
+void igraph_pajek_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *igraph_pajek_yyget_in (yyscan_t yyscanner );
+
+void igraph_pajek_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *igraph_pajek_yyget_out (yyscan_t yyscanner );
+
+void igraph_pajek_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t igraph_pajek_yyget_leng (yyscan_t yyscanner );
+
+char *igraph_pajek_yyget_text (yyscan_t yyscanner );
+
+int igraph_pajek_yyget_lineno (yyscan_t yyscanner );
+
+void igraph_pajek_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * igraph_pajek_yyget_lval (yyscan_t yyscanner );
+
+void igraph_pajek_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+       YYLTYPE *igraph_pajek_yyget_lloc (yyscan_t yyscanner );
+    
+        void igraph_pajek_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+    
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int igraph_pajek_yywrap (yyscan_t yyscanner );
+#else
+extern int igraph_pajek_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		yy_size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int igraph_pajek_yylex \
+               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int igraph_pajek_yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 81 "foreign-pajek-lexer.l"
+
+
+#line 865 "foreign-pajek-lexer.c"
+
+    yylval = yylval_param;
+
+    yylloc = yylloc_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			igraph_pajek_yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				igraph_pajek_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		igraph_pajek_yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 160 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 289 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 83 "foreign-pajek-lexer.l"
+{ }
+	YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 84 "foreign-pajek-lexer.l"
+{ }
+	YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 85 "foreign-pajek-lexer.l"
+{ }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 86 "foreign-pajek-lexer.l"
+{ return NETWORKLINE; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 87 "foreign-pajek-lexer.l"
+{ return NETWORKLINE; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 88 "foreign-pajek-lexer.l"
+{ return VERTICESLINE; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 89 "foreign-pajek-lexer.l"
+{ return ARCSLINE; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 90 "foreign-pajek-lexer.l"
+{ return EDGESLINE; }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 91 "foreign-pajek-lexer.l"
+{ return ARCSLISTLINE; }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 92 "foreign-pajek-lexer.l"
+{ return EDGESLISTLINE; }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 93 "foreign-pajek-lexer.l"
+{ return MATRIXLINE; }
+	YY_BREAK
+case 12:
+/* rule 12 can match eol */
+YY_RULE_SETUP
+#line 94 "foreign-pajek-lexer.l"
+{ yyextra->mode=0; return NEWLINE; }
+	YY_BREAK
+case 13:
+/* rule 13 can match eol */
+YY_RULE_SETUP
+#line 95 "foreign-pajek-lexer.l"
+{ return QSTR; }
+	YY_BREAK
+case 14:
+/* rule 14 can match eol */
+YY_RULE_SETUP
+#line 96 "foreign-pajek-lexer.l"
+{ return PSTR; }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 97 "foreign-pajek-lexer.l"
+{ 
+                    return NUM; }
+	YY_BREAK
+case 16:
+/* rule 16 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 6;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 100 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_X_FACT; } else { return ALNUM; } }
+	YY_BREAK
+case 17:
+/* rule 17 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 6;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 101 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_Y_FACT; } else { return ALNUM; } }
+	YY_BREAK
+case 18:
+/* rule 18 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 102 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_IC; } else { return ALNUM; } }
+	YY_BREAK
+case 19:
+/* rule 19 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 103 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_BC; } else { return ALNUM; } }
+	YY_BREAK
+case 20:
+/* rule 20 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 104 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_BW; } else { return ALNUM; } }
+	YY_BREAK
+case 21:
+/* rule 21 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 3;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 105 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_PHI; } else { return ALNUM; } }
+	YY_BREAK
+case 22:
+/* rule 22 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 106 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_R; } else { return ALNUM; } }
+	YY_BREAK
+case 23:
+/* rule 23 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 107 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_Q; } else { return ALNUM; } }
+	YY_BREAK
+case 24:
+/* rule 24 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 108 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_FONT; } else { return ALNUM; } }
+	YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 3;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 109 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_URL; } else { return ALNUM; } }
+	YY_BREAK
+case 26:
+/* rule 26 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 111 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_C; } else { return ALNUM; } }
+	YY_BREAK
+case 27:
+/* rule 27 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 112 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_P; } else { return ALNUM; } }
+	YY_BREAK
+case 28:
+/* rule 28 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 113 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_S; } else { return ALNUM; } }
+	YY_BREAK
+case 29:
+/* rule 29 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 114 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_A; } else { return ALNUM; } }
+	YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 115 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_W; } else { return ALNUM; } }
+	YY_BREAK
+case 31:
+/* rule 31 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 116 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_H1; } else { return ALNUM; } }
+	YY_BREAK
+case 32:
+/* rule 32 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 117 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_H2; } else { return ALNUM; } }
+	YY_BREAK
+case 33:
+/* rule 33 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 118 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_A1; } else { return ALNUM; } }
+	YY_BREAK
+case 34:
+/* rule 34 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 119 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_A2; } else { return ALNUM; } }
+	YY_BREAK
+case 35:
+/* rule 35 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 120 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_K1; } else { return ALNUM; } }
+	YY_BREAK
+case 36:
+/* rule 36 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 121 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_K2; } else { return ALNUM; } }
+	YY_BREAK
+case 37:
+/* rule 37 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 122 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_AP; } else { return ALNUM; } }
+	YY_BREAK
+case 38:
+/* rule 38 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 123 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_L; } else { return ALNUM; } }
+	YY_BREAK
+case 39:
+/* rule 39 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 124 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==2) { return EP_LP; } else { return ALNUM; } }
+	YY_BREAK
+case 40:
+/* rule 40 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 126 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_LPHI; } else
+                             if (yyextra->mode==2) { return EP_LPHI; } else { return ALNUM; } }
+	YY_BREAK
+case 41:
+/* rule 41 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 128 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_LC; } else
+                             if (yyextra->mode==2) { return EP_LC; } else { return ALNUM; } }
+	YY_BREAK
+case 42:
+/* rule 42 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 130 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_LR; } else
+                             if (yyextra->mode==2) { return EP_LR; } else { return ALNUM; } }
+	YY_BREAK
+case 43:
+/* rule 43 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 132 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_LA; } else
+                             if (yyextra->mode==2) { return EP_LA; } else { return ALNUM; } }
+	YY_BREAK
+case 44:
+/* rule 44 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 134 "foreign-pajek-lexer.l"
+{ if (yyextra->mode==1) { return VP_SIZE; } else 
+                             if (yyextra->mode==2) { return EP_SIZE; } else { return ALNUM; } }
+	YY_BREAK
+case 45:
+/* rule 45 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 3;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 136 "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 "foreign-pajek-lexer.l"
+{ return ALNUM; }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 141 "foreign-pajek-lexer.l"
+{ if (yyextra->eof) {
+                       yyterminate();
+                    } else {
+                       yyextra->eof=1;
+                       return NEWLINE; 
+                    }
+                  }
+	YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 148 "foreign-pajek-lexer.l"
+ECHO;
+	YY_BREAK
+#line 1329 "foreign-pajek-lexer.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * igraph_pajek_yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( igraph_pajek_yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of igraph_pajek_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					igraph_pajek_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			igraph_pajek_yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) igraph_pajek_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 160 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 160 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 159);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					igraph_pajek_yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( igraph_pajek_yywrap(yyscanner ) )
+						return 0;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void igraph_pajek_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        igraph_pajek_yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            igraph_pajek_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	igraph_pajek_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	igraph_pajek_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_pajek_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		igraph_pajek_yypop_buffer_state();
+	 *		igraph_pajek_yypush_buffer_state(new_buffer);
+     */
+	igraph_pajek_yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	igraph_pajek_yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (igraph_pajek_yywrap()) processing, but the only time this flag
+	 * is looked at is after igraph_pajek_yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void igraph_pajek_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE igraph_pajek_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) igraph_pajek_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_pajek_yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) igraph_pajek_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_pajek_yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	igraph_pajek_yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with igraph_pajek_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void igraph_pajek_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		igraph_pajek_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	igraph_pajek_yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a igraph_pajek_yyrestart() or at EOF.
+ */
+    static void igraph_pajek_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	igraph_pajek_yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then igraph_pajek_yy_init_buffer was _probably_
+     * called from igraph_pajek_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void igraph_pajek_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		igraph_pajek_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_pajek_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	igraph_pajek_yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from igraph_pajek_yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from igraph_pajek_yy_switch_to_buffer. */
+	igraph_pajek_yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void igraph_pajek_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	igraph_pajek_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		igraph_pajek_yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void igraph_pajek_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	yy_size_t num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_pajek_yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_pajek_yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)igraph_pajek_yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in igraph_pajek_yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE igraph_pajek_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) igraph_pajek_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_pajek_yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	igraph_pajek_yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to igraph_pajek_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       igraph_pajek_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE igraph_pajek_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return igraph_pajek_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to igraph_pajek_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE igraph_pajek_yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n, i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) igraph_pajek_yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in igraph_pajek_yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = igraph_pajek_yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in igraph_pajek_yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE igraph_pajek_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_pajek_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int igraph_pajek_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_pajek_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *igraph_pajek_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t igraph_pajek_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *igraph_pajek_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void igraph_pajek_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_pajek_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_pajek_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void igraph_pajek_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "igraph_pajek_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see igraph_pajek_yy_switch_to_buffer
+ */
+void igraph_pajek_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void igraph_pajek_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int igraph_pajek_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void igraph_pajek_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * igraph_pajek_yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void igraph_pajek_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+YYLTYPE *igraph_pajek_yyget_lloc  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylloc;
+}
+    
+void igraph_pajek_yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylloc = yylloc_param;
+}
+    
+/* User-visible API */
+
+/* igraph_pajek_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int igraph_pajek_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) igraph_pajek_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* igraph_pajek_yylex_init_extra has the same functionality as igraph_pajek_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to igraph_pajek_yyalloc in
+ * the yyextra field.
+ */
+
+int igraph_pajek_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    igraph_pajek_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) igraph_pajek_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    igraph_pajek_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from igraph_pajek_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * igraph_pajek_yylex_init()
+     */
+    return 0;
+}
+
+/* igraph_pajek_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int igraph_pajek_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		igraph_pajek_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		igraph_pajek_yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	igraph_pajek_yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        igraph_pajek_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * igraph_pajek_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    igraph_pajek_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *igraph_pajek_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *igraph_pajek_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void igraph_pajek_yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see igraph_pajek_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 148 "foreign-pajek-lexer.l"
+
+
+
diff --git a/src/foreign-pajek-lexer.l b/src/foreign-pajek-lexer.l
new file mode 100644
index 0000000..c49c5ce
--- /dev/null
+++ b/src/foreign-pajek-lexer.l
@@ -0,0 +1,148 @@
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include "config.h"
+#include <stdlib.h>
+#include "foreign-pajek-header.h"
+#include "foreign-pajek-parser.h"
+#define YY_EXTRA_TYPE igraph_i_pajek_parsedata_t*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+/* We assume that 'file' is 'stderr' here. */
+#define fprintf(file, msg, ...) \
+  igraph_warningf(msg, __FILE__, __LINE__, 0, __VA_ARGS__)
+#ifdef stdout 
+#  undef stdout
+#endif
+#define stdout 0
+#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
+				__LINE__, IGRAPH_PARSEERROR);
+%}
+
+%option noyywrap
+%option prefix="igraph_pajek_yy"
+%option outfile="lex.yy.c"
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+digit [0-9]
+word [^ \t\r\n]
+
+%%
+
+[ \t]*          { }
+%[^\n]*\n[\r]*  { }
+%[^\n]*\r[\n]*  { }
+\*[Nn][eE][Tt]                         { return NETWORKLINE; }
+\*[Nn][Ee][Tt][Ww][Oo][Rr][Kk]         { return NETWORKLINE; }
+\*[Vv][Ee][Rr][Tt][Ii][Cc][Ee][Ss]     { return VERTICESLINE; }
+\*[Aa][Rr][Cc][Ss]                     { return ARCSLINE; }
+\*[Ee][Dd][Gg][Ee][Ss]                 { return EDGESLINE; }
+\*[Aa][Rr][Cc][Ss][Ll][Ii][Ss][Tt]     { return ARCSLISTLINE; }
+\*[Ee][Dd][Gg][Ee][Ss][Ll][Ii][Ss][Tt] { return EDGESLISTLINE; }
+\*[Mm][Aa][Tt][Rr][Ii][Xx]             { return MATRIXLINE; }
+\n\r|\r\n|\n|\r   { yyextra->mode=0; return NEWLINE; }
+\"[^\"]*\"        { return QSTR; }
+\([^\)]*\)        { return PSTR; }
+\-?{digit}+(\.{digit}+)?([eE](\+|\-)?{digit}+)? { 
+                    return NUM; }
+
+[Xx]_[Ff][Aa][Cc][Tt]/[ \t\n\r]  { if (yyextra->mode==1) { return VP_X_FACT; } else { return ALNUM; } }
+[Yy]_[Ff][Aa][Cc][Tt]/[ \t\n\r]  { if (yyextra->mode==1) { return VP_Y_FACT; } else { return ALNUM; } }
+[Ii][Cc]/[ \t\n\r]               { if (yyextra->mode==1) { return VP_IC; } else { return ALNUM; } }
+[Bb][Cc]/[ \t\n\r]               { if (yyextra->mode==1) { return VP_BC; } else { return ALNUM; } }
+[Bb][Ww]/[ \t\n\r]               { if (yyextra->mode==1) { return VP_BW; } else { return ALNUM; } }
+[Pp][Hh][Ii]/[ \t\n\r]           { if (yyextra->mode==1) { return VP_PHI; } else { return ALNUM; } }
+[Rr]/[ \t\n\r]                   { if (yyextra->mode==1) { return VP_R; } else { return ALNUM; } }
+[Qq]/[ \t\n\r]                   { if (yyextra->mode==1) { return VP_Q; } else { return ALNUM; } }
+[Ff][Oo][Nn][Tt]/[ \t\n\r]       { if (yyextra->mode==1) { return VP_FONT; } else { return ALNUM; } }
+[Uu][Rr][Ll]/[ \t\n\r]           { if (yyextra->mode==1) { return VP_URL; } else { return ALNUM; } }
+
+[Cc]/[ \t\n\r]       { if (yyextra->mode==2) { return EP_C; } else { return ALNUM; } }
+[Pp]/[ \t\n\r]       { if (yyextra->mode==2) { return EP_P; } else { return ALNUM; } }
+[Ss]/[ \t\n\r]       { if (yyextra->mode==2) { return EP_S; } else { return ALNUM; } }
+[Aa]/[ \t\n\r]       { if (yyextra->mode==2) { return EP_A; } else { return ALNUM; } }
+[Ww]/[ \t\n\r]       { if (yyextra->mode==2) { return EP_W; } else { return ALNUM; } }
+[Hh]1/[ \t\n\r]      { if (yyextra->mode==2) { return EP_H1; } else { return ALNUM; } }
+[Hh]2/[ \t\n\r]      { if (yyextra->mode==2) { return EP_H2; } else { return ALNUM; } }
+[Aa]1/[ \t\n\r]      { if (yyextra->mode==2) { return EP_A1; } else { return ALNUM; } }
+[Aa]2/[ \t\n\r]      { if (yyextra->mode==2) { return EP_A2; } else { return ALNUM; } }
+[Kk]1/[ \t\n\r]      { if (yyextra->mode==2) { return EP_K1; } else { return ALNUM; } }
+[Kk]2/[ \t\n\r]      { if (yyextra->mode==2) { return EP_K2; } else { return ALNUM; } }
+[Aa][Pp]/[ \t\n\r]   { if (yyextra->mode==2) { return EP_AP; } else { return ALNUM; } }
+[Ll]/[ \t\n\r]       { if (yyextra->mode==2) { return EP_L; } else { return ALNUM; } }
+[Ll][Pp]/[ \t\n\r]   { if (yyextra->mode==2) { return EP_LP; } else { return ALNUM; } }
+
+[Ll][Pp][Hh][Ii]/[ \t\n\r] { if (yyextra->mode==1) { return VP_LPHI; } else
+                             if (yyextra->mode==2) { return EP_LPHI; } else { return ALNUM; } }
+[Ll][Cc]/[ \t\n\r]         { if (yyextra->mode==1) { return VP_LC; } else
+                             if (yyextra->mode==2) { return EP_LC; } else { return ALNUM; } }
+[Ll][Rr]/[ \t\n\r]         { if (yyextra->mode==1) { return VP_LR; } else
+                             if (yyextra->mode==2) { return EP_LR; } else { return ALNUM; } }
+[Ll][Aa]/[ \t\n\r]         { if (yyextra->mode==1) { return VP_LA; } else
+                             if (yyextra->mode==2) { return EP_LA; } else { return ALNUM; } }
+[Ss][Ii][Zz][Ee]/[ \t\n\r] { if (yyextra->mode==1) { return VP_SIZE; } else 
+                             if (yyextra->mode==2) { return EP_SIZE; } else { return ALNUM; } }
+[Ff][Oo][Ss]/[ \t\n\r]     { if (yyextra->mode==1) { return VP_FOS; } else 
+                             if (yyextra->mode==2) { return EP_FOS; } else { return ALNUM; } }
+                             
+{word}+           { return ALNUM; }
+
+<<EOF>>           { if (yyextra->eof) {
+                       yyterminate();
+                    } else {
+                       yyextra->eof=1;
+                       return NEWLINE; 
+                    }
+                  }
+%%
diff --git a/src/foreign-pajek-parser.c b/src/foreign-pajek-parser.c
new file mode 100644
index 0000000..9279e09
--- /dev/null
+++ b/src/foreign-pajek-parser.c
@@ -0,0 +1,2817 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 1
+
+/* Substitute the variable and function names.  */
+#define yyparse igraph_pajek_yyparse
+#define yylex   igraph_pajek_yylex
+#define yyerror igraph_pajek_yyerror
+#define yylval  igraph_pajek_yylval
+#define yychar  igraph_pajek_yychar
+#define yydebug igraph_pajek_yydebug
+#define yynerrs igraph_pajek_yynerrs
+#define yylloc igraph_pajek_yylloc
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NEWLINE = 258,
+     NUM = 259,
+     ALNUM = 260,
+     QSTR = 261,
+     PSTR = 262,
+     NETWORKLINE = 263,
+     VERTICESLINE = 264,
+     ARCSLINE = 265,
+     EDGESLINE = 266,
+     ARCSLISTLINE = 267,
+     EDGESLISTLINE = 268,
+     MATRIXLINE = 269,
+     VP_X_FACT = 270,
+     VP_Y_FACT = 271,
+     VP_IC = 272,
+     VP_BC = 273,
+     VP_LC = 274,
+     VP_LR = 275,
+     VP_LPHI = 276,
+     VP_BW = 277,
+     VP_FOS = 278,
+     VP_PHI = 279,
+     VP_R = 280,
+     VP_Q = 281,
+     VP_LA = 282,
+     VP_FONT = 283,
+     VP_URL = 284,
+     VP_SIZE = 285,
+     EP_C = 286,
+     EP_S = 287,
+     EP_A = 288,
+     EP_W = 289,
+     EP_H1 = 290,
+     EP_H2 = 291,
+     EP_A1 = 292,
+     EP_A2 = 293,
+     EP_K1 = 294,
+     EP_K2 = 295,
+     EP_AP = 296,
+     EP_P = 297,
+     EP_L = 298,
+     EP_LP = 299,
+     EP_LR = 300,
+     EP_LPHI = 301,
+     EP_LC = 302,
+     EP_LA = 303,
+     EP_SIZE = 304,
+     EP_FOS = 305
+   };
+#endif
+/* Tokens.  */
+#define NEWLINE 258
+#define NUM 259
+#define ALNUM 260
+#define QSTR 261
+#define PSTR 262
+#define NETWORKLINE 263
+#define VERTICESLINE 264
+#define ARCSLINE 265
+#define EDGESLINE 266
+#define ARCSLISTLINE 267
+#define EDGESLISTLINE 268
+#define MATRIXLINE 269
+#define VP_X_FACT 270
+#define VP_Y_FACT 271
+#define VP_IC 272
+#define VP_BC 273
+#define VP_LC 274
+#define VP_LR 275
+#define VP_LPHI 276
+#define VP_BW 277
+#define VP_FOS 278
+#define VP_PHI 279
+#define VP_R 280
+#define VP_Q 281
+#define VP_LA 282
+#define VP_FONT 283
+#define VP_URL 284
+#define VP_SIZE 285
+#define EP_C 286
+#define EP_S 287
+#define EP_A 288
+#define EP_W 289
+#define EP_H1 290
+#define EP_H2 291
+#define EP_A1 292
+#define EP_A2 293
+#define EP_K1 294
+#define EP_K2 295
+#define EP_AP 296
+#define EP_P 297
+#define EP_L 298
+#define EP_LP 299
+#define EP_LR 300
+#define EP_LPHI 301
+#define EP_LC 302
+#define EP_LA 303
+#define EP_SIZE 304
+#define EP_FOS 305
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 23 "foreign-pajek-parser.y"
+
+
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "igraph_hacks_internal.h"
+#include "igraph_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "igraph_attributes.h"
+#include "config.h"
+#include "igraph_math.h"
+#include <math.h>
+#include "foreign-pajek-header.h"
+#include "foreign-pajek-parser.h"
+
+#define yyscan_t void*
+
+int igraph_pajek_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, 
+		       void* scanner);
+int igraph_pajek_yyerror(YYLTYPE* locp, 
+			 igraph_i_pajek_parsedata_t *context, 
+			 char *s);
+char *igraph_pajek_yyget_text (yyscan_t yyscanner );
+int igraph_pajek_yyget_leng (yyscan_t yyscanner );
+
+int igraph_i_pajek_add_string_vertex_attribute(const char *name, 
+					       const char *value,
+					       int len, 
+					       igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_string_edge_attribute(const char *name, 
+					     const char *value,
+					     int len,
+					     igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_numeric_vertex_attribute(const char *name, 
+						igraph_real_t value,
+						igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_numeric_edge_attribute(const char *name, 
+					      igraph_real_t value, 
+					      igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_numeric_attribute(igraph_trie_t *names,
+					 igraph_vector_ptr_t *attrs,
+					 long int count,
+					 const char *attrname,
+					 igraph_integer_t vid,
+					 igraph_real_t number);
+int igraph_i_pajek_add_string_attribute(igraph_trie_t *names,
+					igraph_vector_ptr_t *attrs,
+					long int count,
+					const char *attrname,
+					igraph_integer_t vid,
+					const char *str);
+
+int igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t *context);
+
+extern igraph_real_t igraph_pajek_get_number(const char *str, long int len);
+extern long int igraph_i_pajek_actvertex;
+extern long int igraph_i_pajek_actedge;
+
+#define scanner context->scanner
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 123 "foreign-pajek-parser.y"
+{
+  long int intnum;
+  double   realnum;  
+  struct {
+    char *str;
+    int len;
+  } string;  
+}
+/* Line 193 of yacc.c.  */
+#line 304 "foreign-pajek-parser.c"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 329 "foreign-pajek-parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+    YYLTYPE yyls;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  5
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   250
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  51
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  66
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  137
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  207
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   305
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     7,     8,    12,    16,    19,    23,    24,
+      27,    29,    32,    33,    41,    43,    45,    46,    49,    53,
+      54,    56,    57,    60,    62,    65,    68,    73,    78,    83,
+      86,    89,    92,    95,    98,   101,   104,   107,   110,   111,
+     115,   116,   120,   121,   125,   126,   130,   131,   135,   137,
+     138,   141,   144,   147,   150,   153,   157,   162,   163,   166,
+     168,   169,   176,   178,   180,   184,   189,   190,   193,   195,
+     196,   203,   205,   207,   208,   210,   211,   214,   216,   221,
+     224,   227,   230,   233,   236,   239,   242,   245,   248,   251,
+     254,   257,   260,   263,   266,   267,   271,   272,   276,   277,
+     281,   282,   286,   287,   291,   293,   297,   298,   301,   303,
+     307,   308,   311,   313,   315,   319,   320,   323,   325,   329,
+     330,   333,   335,   337,   341,   343,   344,   347,   350,   351,
+     354,   356,   358,   360,   361,   364,   366,   368
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      52,     0,    -1,    53,    54,    72,    -1,    -1,     8,   115,
+       3,    -1,    55,     3,    56,    -1,     9,   113,    -1,     9,
+     113,   113,    -1,    -1,    56,    57,    -1,     3,    -1,    59,
+       3,    -1,    -1,    59,    58,    60,    61,    62,    63,     3,
+      -1,   113,    -1,   116,    -1,    -1,   114,   114,    -1,   114,
+     114,   114,    -1,    -1,   116,    -1,    -1,    63,    64,    -1,
+      65,    -1,    15,   114,    -1,    16,   114,    -1,    17,   114,
+     114,   114,    -1,    18,   114,   114,   114,    -1,    19,   114,
+     114,   114,    -1,    20,   114,    -1,    21,   114,    -1,    22,
+     114,    -1,    23,   114,    -1,    24,   114,    -1,    25,   114,
+      -1,    26,   114,    -1,    27,   114,    -1,    30,   114,    -1,
+      -1,    28,    66,    71,    -1,    -1,    29,    67,    71,    -1,
+      -1,    17,    68,    71,    -1,    -1,    18,    69,    71,    -1,
+      -1,    19,    70,    71,    -1,   116,    -1,    -1,    72,    73,
+      -1,    72,    79,    -1,    72,    95,    -1,    72,   101,    -1,
+      72,   107,    -1,    10,     3,    74,    -1,    10,   114,     3,
+      74,    -1,    -1,    74,    75,    -1,     3,    -1,    -1,    77,
+      78,    76,    85,    86,     3,    -1,   113,    -1,   113,    -1,
+      11,     3,    80,    -1,    11,   114,     3,    80,    -1,    -1,
+      80,    81,    -1,     3,    -1,    -1,    83,    84,    82,    85,
+      86,     3,    -1,   113,    -1,   113,    -1,    -1,   114,    -1,
+      -1,    86,    87,    -1,    88,    -1,    31,   114,   114,   114,
+      -1,    32,   114,    -1,    34,   114,    -1,    35,   114,    -1,
+      36,   114,    -1,    37,   114,    -1,    38,   114,    -1,    39,
+     114,    -1,    40,   114,    -1,    41,   114,    -1,    44,   114,
+      -1,    45,   114,    -1,    46,   114,    -1,    48,   114,    -1,
+      49,   114,    -1,    50,   114,    -1,    -1,    33,    89,    94,
+      -1,    -1,    42,    90,    94,    -1,    -1,    43,    91,    94,
+      -1,    -1,    47,    92,    94,    -1,    -1,    31,    93,    94,
+      -1,   116,    -1,    12,     3,    96,    -1,    -1,    96,    97,
+      -1,     3,    -1,    99,    98,     3,    -1,    -1,    98,   100,
+      -1,   113,    -1,   113,    -1,    13,     3,   102,    -1,    -1,
+     102,   103,    -1,     3,    -1,   105,   104,     3,    -1,    -1,
+     104,   106,    -1,   113,    -1,   113,    -1,   108,     3,   109,
+      -1,    14,    -1,    -1,   109,   110,    -1,   111,     3,    -1,
+      -1,   112,   111,    -1,   114,    -1,     4,    -1,     4,    -1,
+      -1,   115,   116,    -1,     5,    -1,     4,    -1,     6,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   196,   196,   200,   200,   202,   204,   208,   214,   214,
+     216,   217,   218,   218,   221,   223,   227,   228,   232,   238,
+     238,   242,   242,   245,   246,   249,   252,   257,   262,   267,
+     270,   273,   276,   279,   282,   285,   288,   291,   296,   296,
+     300,   300,   304,   304,   308,   308,   313,   313,   320,   322,
+     322,   322,   322,   322,   322,   324,   325,   327,   327,   329,
+     330,   330,   336,   338,   340,   341,   343,   343,   345,   346,
+     346,   352,   354,   356,   356,   360,   360,   363,   364,   369,
+     372,   375,   378,   381,   384,   387,   390,   393,   396,   399,
+     402,   405,   408,   411,   416,   416,   420,   420,   424,   424,
+     428,   428,   432,   432,   438,   440,   442,   442,   444,   444,
+     446,   446,   448,   450,   455,   457,   457,   459,   459,   461,
+     461,   463,   465,   472,   474,   479,   479,   481,   483,   483,
+     485,   505,   508,   511,   511,   513,   515,   517
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "NEWLINE", "NUM", "ALNUM", "QSTR",
+  "PSTR", "NETWORKLINE", "VERTICESLINE", "ARCSLINE", "EDGESLINE",
+  "ARCSLISTLINE", "EDGESLISTLINE", "MATRIXLINE", "VP_X_FACT", "VP_Y_FACT",
+  "VP_IC", "VP_BC", "VP_LC", "VP_LR", "VP_LPHI", "VP_BW", "VP_FOS",
+  "VP_PHI", "VP_R", "VP_Q", "VP_LA", "VP_FONT", "VP_URL", "VP_SIZE",
+  "EP_C", "EP_S", "EP_A", "EP_W", "EP_H1", "EP_H2", "EP_A1", "EP_A2",
+  "EP_K1", "EP_K2", "EP_AP", "EP_P", "EP_L", "EP_LP", "EP_LR", "EP_LPHI",
+  "EP_LC", "EP_LA", "EP_SIZE", "EP_FOS", "$accept", "input", "nethead",
+  "vertices", "verticeshead", "vertdefs", "vertexline", "@1", "vertex",
+  "vertexid", "vertexcoords", "shape", "params", "param", "vpword", "@2",
+  "@3", "@4", "@5", "@6", "vpwordpar", "edgeblock", "arcs", "arcsdefs",
+  "arcsline", "@7", "arcfrom", "arcto", "edges", "edgesdefs", "edgesline",
+  "@8", "edgefrom", "edgeto", "weight", "edgeparams", "edgeparam",
+  "epword", "@9", "@10", "@11", "@12", "@13", "epwordpar", "arcslist",
+  "arcslistlines", "arclistline", "arctolist", "arclistfrom", "arclistto",
+  "edgeslist", "edgelistlines", "edgelistline", "edgetolist",
+  "edgelistfrom", "edgelistto", "adjmatrix", "matrixline",
+  "adjmatrixlines", "adjmatrixline", "adjmatrixnumbers", "adjmatrixentry",
+  "longint", "number", "words", "word", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    51,    52,    53,    53,    54,    55,    55,    56,    56,
+      57,    57,    58,    57,    59,    60,    61,    61,    61,    62,
+      62,    63,    63,    64,    64,    64,    64,    64,    64,    64,
+      64,    64,    64,    64,    64,    64,    64,    64,    66,    65,
+      67,    65,    68,    65,    69,    65,    70,    65,    71,    72,
+      72,    72,    72,    72,    72,    73,    73,    74,    74,    75,
+      76,    75,    77,    78,    79,    79,    80,    80,    81,    82,
+      81,    83,    84,    85,    85,    86,    86,    87,    87,    87,
+      87,    87,    87,    87,    87,    87,    87,    87,    87,    87,
+      87,    87,    87,    87,    89,    88,    90,    88,    91,    88,
+      92,    88,    93,    88,    94,    95,    96,    96,    97,    97,
+      98,    98,    99,   100,   101,   102,   102,   103,   103,   104,
+     104,   105,   106,   107,   108,   109,   109,   110,   111,   111,
+     112,   113,   114,   115,   115,   116,   116,   116
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     3,     0,     3,     3,     2,     3,     0,     2,
+       1,     2,     0,     7,     1,     1,     0,     2,     3,     0,
+       1,     0,     2,     1,     2,     2,     4,     4,     4,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     0,     3,
+       0,     3,     0,     3,     0,     3,     0,     3,     1,     0,
+       2,     2,     2,     2,     2,     3,     4,     0,     2,     1,
+       0,     6,     1,     1,     3,     4,     0,     2,     1,     0,
+       6,     1,     1,     0,     1,     0,     2,     1,     4,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     0,     3,     0,     3,     0,     3,
+       0,     3,     0,     3,     1,     3,     0,     2,     1,     3,
+       0,     2,     1,     1,     3,     0,     2,     1,     3,     0,
+       2,     1,     1,     3,     1,     0,     2,     2,     0,     2,
+       1,     1,     1,     0,     2,     1,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       3,   133,     0,     0,     0,     1,     0,    49,     0,     4,
+     136,   135,   137,   134,   131,     6,     2,     8,     7,     0,
+       0,     0,     0,   124,    50,    51,    52,    53,    54,     0,
+       5,    57,   132,     0,    66,     0,   106,   115,   125,    10,
+       9,    12,    14,    55,    57,    64,    66,   105,   114,   123,
+      11,     0,    59,    58,     0,    62,    56,    68,    67,     0,
+      71,    65,   108,   107,   110,   112,   117,   116,   119,   121,
+     126,     0,   128,   130,    16,    15,    60,    63,    69,    72,
+       0,     0,   127,   129,    19,     0,    73,    73,   109,   111,
+     113,   118,   120,   122,    21,    20,    17,    75,    74,    75,
+       0,    18,     0,     0,    13,     0,     0,    42,    44,    46,
+       0,     0,     0,     0,     0,     0,     0,     0,    38,    40,
+       0,    22,    23,    61,   102,     0,    94,     0,     0,     0,
+       0,     0,     0,     0,     0,    96,    98,     0,     0,     0,
+     100,     0,     0,     0,    76,    77,    70,    24,    25,     0,
+       0,     0,     0,     0,     0,    29,    30,    31,    32,    33,
+      34,    35,    36,     0,     0,    37,     0,     0,    79,     0,
+      80,    81,    82,    83,    84,    85,    86,    87,     0,     0,
+      88,    89,    90,     0,    91,    92,    93,    43,    48,     0,
+      45,     0,    47,     0,    39,    41,   103,   104,     0,    95,
+      97,    99,   101,    26,    27,    28,    78
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     2,     3,     7,     8,    30,    40,    51,    41,    74,
+      84,    94,   100,   121,   122,   163,   164,   149,   151,   153,
+     187,    16,    24,    43,    53,    86,    54,    76,    25,    45,
+      58,    87,    59,    78,    97,   102,   144,   145,   169,   178,
+     179,   183,   166,   196,    26,    47,    63,    80,    64,    89,
+      27,    48,    67,    81,    68,    92,    28,    29,    49,    70,
+      71,    72,    55,    73,     4,   188
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -167
+static const yytype_int16 yypact[] =
+{
+      -4,  -167,     7,    36,    22,  -167,    44,  -167,    49,  -167,
+    -167,  -167,  -167,  -167,  -167,    44,    10,  -167,  -167,    12,
+      27,    51,    56,  -167,  -167,  -167,  -167,  -167,  -167,    58,
+      29,  -167,  -167,    59,  -167,    60,  -167,  -167,  -167,  -167,
+    -167,    61,  -167,    31,  -167,    33,  -167,    35,    37,    39,
+    -167,     5,  -167,  -167,    44,  -167,    31,  -167,  -167,    44,
+    -167,    33,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,
+    -167,    62,    65,  -167,    65,  -167,  -167,  -167,  -167,  -167,
+      47,    53,  -167,  -167,     5,    65,    65,    65,  -167,  -167,
+    -167,  -167,  -167,  -167,  -167,  -167,    65,  -167,  -167,  -167,
+     220,  -167,   151,   172,  -167,    65,    65,    65,    65,    65,
+      65,    65,    65,    65,    65,    65,    65,    65,  -167,  -167,
+      65,  -167,  -167,  -167,    65,    65,  -167,    65,    65,    65,
+      65,    65,    65,    65,    65,  -167,  -167,    65,    65,    65,
+    -167,    65,    65,    65,  -167,  -167,  -167,  -167,  -167,     5,
+      65,     5,    65,     5,    65,  -167,  -167,  -167,  -167,  -167,
+    -167,  -167,  -167,     5,     5,  -167,     5,    65,  -167,     5,
+    -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,     5,     5,
+    -167,  -167,  -167,     5,  -167,  -167,  -167,  -167,  -167,    65,
+    -167,    65,  -167,    65,  -167,  -167,  -167,  -167,    65,  -167,
+    -167,  -167,  -167,  -167,  -167,  -167,  -167
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,
+    -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,
+    -145,  -167,  -167,    26,  -167,  -167,  -167,  -167,  -167,    25,
+    -167,  -167,  -167,  -167,   -15,   -26,  -167,  -167,  -167,  -167,
+    -167,  -167,  -167,  -166,  -167,  -167,  -167,  -167,  -167,  -167,
+    -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,  -167,
+       2,  -167,    -1,   -19,  -167,    -2
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -129
+static const yytype_int16 yytable[] =
+{
+      33,    35,    13,   199,     1,    15,   190,     5,   192,    10,
+      11,    12,   200,   201,    18,    31,    32,   202,   194,   195,
+      19,    20,    21,    22,    23,     9,    10,    11,    12,    42,
+      34,    32,    39,    14,    52,    14,    57,    14,    62,    14,
+      66,    14,  -128,    32,    60,     6,    65,    69,    14,    75,
+      88,    14,    17,    77,    36,    85,    91,    14,    79,    37,
+      60,    38,    44,    46,    50,    82,    96,    98,    98,    32,
+      56,    61,    99,   103,    83,     0,     0,   101,     0,    90,
+      93,     0,    95,     0,     0,     0,   147,   148,   150,   152,
+     154,   155,   156,   157,   158,   159,   160,   161,   162,     0,
+       0,   165,     0,     0,     0,   167,   168,     0,   170,   171,
+     172,   173,   174,   175,   176,   177,     0,     0,   180,   181,
+     182,     0,   184,   185,   186,     0,     0,     0,     0,     0,
+       0,   189,     0,   191,     0,   193,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   198,     0,
+       0,     0,     0,     0,   123,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   197,     0,     0,   197,     0,     0,
+     203,     0,   204,     0,   205,   146,   197,   197,     0,   206,
+       0,   197,   124,   125,   126,   127,   128,   129,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,   139,   140,   141,
+     142,   143,     0,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,   139,   140,
+     141,   142,   143,   104,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   105,   106,   107,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120
+};
+
+static const yytype_int16 yycheck[] =
+{
+      19,    20,     4,   169,     8,     6,   151,     0,   153,     4,
+       5,     6,   178,   179,    15,     3,     4,   183,   163,   164,
+      10,    11,    12,    13,    14,     3,     4,     5,     6,    30,
+       3,     4,     3,     4,     3,     4,     3,     4,     3,     4,
+       3,     4,     3,     4,    45,     9,    47,    48,     4,    51,
+       3,     4,     3,    54,     3,    74,     3,     4,    59,     3,
+      61,     3,     3,     3,     3,     3,    85,    86,    87,     4,
+      44,    46,    87,    99,    72,    -1,    -1,    96,    -1,    80,
+      81,    -1,    84,    -1,    -1,    -1,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,    -1,
+      -1,   120,    -1,    -1,    -1,   124,   125,    -1,   127,   128,
+     129,   130,   131,   132,   133,   134,    -1,    -1,   137,   138,
+     139,    -1,   141,   142,   143,    -1,    -1,    -1,    -1,    -1,
+      -1,   150,    -1,   152,    -1,   154,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   167,    -1,
+      -1,    -1,    -1,    -1,     3,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   166,    -1,    -1,   169,    -1,    -1,
+     189,    -1,   191,    -1,   193,     3,   178,   179,    -1,   198,
+      -1,   183,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    -1,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,     3,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
+      30
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     8,    52,    53,   115,     0,     9,    54,    55,     3,
+       4,     5,     6,   116,     4,   113,    72,     3,   113,    10,
+      11,    12,    13,    14,    73,    79,    95,   101,   107,   108,
+      56,     3,     4,   114,     3,   114,     3,     3,     3,     3,
+      57,    59,   113,    74,     3,    80,     3,    96,   102,   109,
+       3,    58,     3,    75,    77,   113,    74,     3,    81,    83,
+     113,    80,     3,    97,    99,   113,     3,   103,   105,   113,
+     110,   111,   112,   114,    60,   116,    78,   113,    84,   113,
+      98,   104,     3,   111,    61,   114,    76,    82,     3,   100,
+     113,     3,   106,   113,    62,   116,   114,    85,   114,    85,
+      63,   114,    86,    86,     3,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
+      30,    64,    65,     3,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,    41,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    87,    88,     3,   114,   114,    68,
+     114,    69,   114,    70,   114,   114,   114,   114,   114,   114,
+     114,   114,   114,    66,    67,   114,    93,   114,   114,    89,
+     114,   114,   114,   114,   114,   114,   114,   114,    90,    91,
+     114,   114,   114,    92,   114,   114,   114,    71,   116,   114,
+      71,   114,    71,   114,    71,    71,    94,   116,   114,    94,
+      94,    94,    94,   114,   114,   114,   114
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, Location, context); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_pajek_parsedata_t* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_pajek_parsedata_t* context;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (yylocationp);
+  YYUSE (context);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, igraph_i_pajek_parsedata_t* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    igraph_i_pajek_parsedata_t* context;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, igraph_i_pajek_parsedata_t* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+    YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
+    int yyrule;
+    igraph_i_pajek_parsedata_t* context;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       , &(yylsp[(yyi + 1) - (yynrhs)])		       , context);
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+

+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, igraph_i_pajek_parsedata_t* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
+    igraph_i_pajek_parsedata_t* context;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (context);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (igraph_i_pajek_parsedata_t* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (igraph_i_pajek_parsedata_t* context)
+#else
+int
+yyparse (context)
+    igraph_i_pajek_parsedata_t* context;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+/* Location data for the look-ahead symbol.  */
+YYLTYPE yylloc;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+  /* The locations where the error started and ended.  */
+  YYLTYPE yyerror_range[2];
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+  yylsp = yyls;
+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  /* Initialize the default location before parsing starts.  */
+  yylloc.first_line   = yylloc.last_line   = 1;
+  yylloc.first_column = yylloc.last_column = 0;
+#endif
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+	YYLTYPE *yyls1 = yyls;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+	yyls = yyls1;
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+	YYSTACK_RELOCATE (yyls);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 196 "foreign-pajek-parser.y"
+    {
+  if (context->vcount2 > 0) { igraph_i_pajek_check_bipartite(context); }
+ }
+    break;
+
+  case 6:
+#line 204 "foreign-pajek-parser.y"
+    { 
+  context->vcount=(yyvsp[(2) - (2)].intnum); 
+  context->vcount2=0;
+            }
+    break;
+
+  case 7:
+#line 208 "foreign-pajek-parser.y"
+    { 
+  context->vcount=(yyvsp[(2) - (3)].intnum);
+  context->vcount2=(yyvsp[(3) - (3)].intnum);
+  igraph_i_pajek_add_bipartite_type(context);
+}
+    break;
+
+  case 12:
+#line 218 "foreign-pajek-parser.y"
+    { context->actvertex=(yyvsp[(1) - (1)].intnum); }
+    break;
+
+  case 13:
+#line 218 "foreign-pajek-parser.y"
+    { }
+    break;
+
+  case 14:
+#line 221 "foreign-pajek-parser.y"
+    { (yyval.intnum)=(yyvsp[(1) - (1)].intnum); context->mode=1; }
+    break;
+
+  case 15:
+#line 223 "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 "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);
+	    }
+    break;
+
+  case 18:
+#line 232 "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);
+  igraph_i_pajek_add_numeric_vertex_attribute("z", (yyvsp[(3) - (3)].realnum), context);
+	    }
+    break;
+
+  case 20:
+#line 238 "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 "foreign-pajek-parser.y"
+    {
+	 igraph_i_pajek_add_numeric_vertex_attribute("xfact", (yyvsp[(2) - (2)].realnum), context);
+       }
+    break;
+
+  case 25:
+#line 249 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("yfact", (yyvsp[(2) - (2)].realnum), context);
+       }
+    break;
+
+  case 26:
+#line 252 "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);
+	 igraph_i_pajek_add_numeric_vertex_attribute("color-blue", (yyvsp[(4) - (4)].realnum), context);
+       }
+    break;
+
+  case 27:
+#line 257 "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);
+	 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-blue", (yyvsp[(4) - (4)].realnum), context);
+       }
+    break;
+
+  case 28:
+#line 262 "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);
+	 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-blue", (yyvsp[(4) - (4)].realnum), context);
+       }
+    break;
+
+  case 29:
+#line 267 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("labeldist", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 30:
+#line 270 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("labeldegree2", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 31:
+#line 273 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("framewidth", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 32:
+#line 276 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("fontsize", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 33:
+#line 279 "foreign-pajek-parser.y"
+    {       
+         igraph_i_pajek_add_numeric_vertex_attribute("rotation", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 34:
+#line 282 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("radius", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 35:
+#line 285 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("diamondratio", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 36:
+#line 288 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("labeldegree", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 37:
+#line 291 "foreign-pajek-parser.y"
+    {
+         igraph_i_pajek_add_numeric_vertex_attribute("vertexsize", (yyvsp[(2) - (2)].realnum), context);
+     }
+    break;
+
+  case 38:
+#line 296 "foreign-pajek-parser.y"
+    { context->mode=3; }
+    break;
+
+  case 39:
+#line 296 "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);
+     }
+    break;
+
+  case 40:
+#line 300 "foreign-pajek-parser.y"
+    { context->mode=3; }
+    break;
+
+  case 41:
+#line 300 "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);
+     }
+    break;
+
+  case 42:
+#line 304 "foreign-pajek-parser.y"
+    { context->mode=3; }
+    break;
+
+  case 43:
+#line 304 "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);
+     }
+    break;
+
+  case 44:
+#line 308 "foreign-pajek-parser.y"
+    { context->mode=3; }
+    break;
+
+  case 45:
+#line 308 "foreign-pajek-parser.y"
+    {
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("framecolor", 
+						    (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
+     }
+    break;
+
+  case 46:
+#line 313 "foreign-pajek-parser.y"
+    { context->mode=3; }
+    break;
+
+  case 47:
+#line 313 "foreign-pajek-parser.y"
+    {
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("labelcolor", 
+						    (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
+     }
+    break;
+
+  case 48:
+#line 320 "foreign-pajek-parser.y"
+    { (yyval.string)=(yyvsp[(1) - (1)].string); }
+    break;
+
+  case 55:
+#line 324 "foreign-pajek-parser.y"
+    { context->directed=1; }
+    break;
+
+  case 56:
+#line 325 "foreign-pajek-parser.y"
+    { context->directed=1; }
+    break;
+
+  case 60:
+#line 330 "foreign-pajek-parser.y"
+    { context->actedge++;
+	                  context->mode=2; }
+    break;
+
+  case 61:
+#line 331 "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 "foreign-pajek-parser.y"
+    { context->directed=0; }
+    break;
+
+  case 65:
+#line 341 "foreign-pajek-parser.y"
+    { context->directed=0; }
+    break;
+
+  case 69:
+#line 346 "foreign-pajek-parser.y"
+    { context->actedge++; 
+	                    context->mode=2; }
+    break;
+
+  case 70:
+#line 347 "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 "foreign-pajek-parser.y"
+    {
+  igraph_i_pajek_add_numeric_edge_attribute("weight", (yyvsp[(1) - (1)].realnum), context);
+}
+    break;
+
+  case 78:
+#line 364 "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);
+       igraph_i_pajek_add_numeric_edge_attribute("color-blue", (yyvsp[(4) - (4)].realnum), context);
+   }
+    break;
+
+  case 79:
+#line 369 "foreign-pajek-parser.y"
+    { 
+       igraph_i_pajek_add_numeric_edge_attribute("arrowsize", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 80:
+#line 372 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("edgewidth", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 81:
+#line 375 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("hook1", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 82:
+#line 378 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("hook2", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 83:
+#line 381 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("angle1", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 84:
+#line 384 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("angle2", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 85:
+#line 387 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("velocity1", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 86:
+#line 390 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("velocity2", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 87:
+#line 393 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("arrowpos", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 88:
+#line 396 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("labelpos", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 89:
+#line 399 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("labelangle", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 90:
+#line 402 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("labelangle2", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 91:
+#line 405 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("labeldegree", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 92:
+#line 408 "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 "foreign-pajek-parser.y"
+    {
+       igraph_i_pajek_add_numeric_edge_attribute("fontsize", (yyvsp[(2) - (2)].realnum), context);
+   }
+    break;
+
+  case 94:
+#line 416 "foreign-pajek-parser.y"
+    { context->mode=4; }
+    break;
+
+  case 95:
+#line 416 "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);
+    }
+    break;
+
+  case 96:
+#line 420 "foreign-pajek-parser.y"
+    { context->mode=4; }
+    break;
+
+  case 97:
+#line 420 "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);
+    }
+    break;
+
+  case 98:
+#line 424 "foreign-pajek-parser.y"
+    { context->mode=4; }
+    break;
+
+  case 99:
+#line 424 "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);
+    }
+    break;
+
+  case 100:
+#line 428 "foreign-pajek-parser.y"
+    { context->mode=4; }
+    break;
+
+  case 101:
+#line 428 "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);
+    }
+    break;
+
+  case 102:
+#line 432 "foreign-pajek-parser.y"
+    { context->mode=4; }
+    break;
+
+  case 103:
+#line 432 "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);
+    }
+    break;
+
+  case 104:
+#line 438 "foreign-pajek-parser.y"
+    { context->mode=2; (yyval.string)=(yyvsp[(1) - (1)].string); }
+    break;
+
+  case 105:
+#line 440 "foreign-pajek-parser.y"
+    { context->directed=1; }
+    break;
+
+  case 112:
+#line 448 "foreign-pajek-parser.y"
+    { context->mode=0; context->actfrom=fabs((yyvsp[(1) - (1)].intnum))-1; }
+    break;
+
+  case 113:
+#line 450 "foreign-pajek-parser.y"
+    { 
+  igraph_vector_push_back(context->vector, context->actfrom); 
+  igraph_vector_push_back(context->vector, fabs((yyvsp[(1) - (1)].intnum))-1); 
+}
+    break;
+
+  case 114:
+#line 455 "foreign-pajek-parser.y"
+    { context->directed=0; }
+    break;
+
+  case 121:
+#line 463 "foreign-pajek-parser.y"
+    { context->mode=0; context->actfrom=fabs((yyvsp[(1) - (1)].intnum))-1; }
+    break;
+
+  case 122:
+#line 465 "foreign-pajek-parser.y"
+    { 
+  igraph_vector_push_back(context->vector, context->actfrom); 
+  igraph_vector_push_back(context->vector, fabs((yyvsp[(1) - (1)].intnum))-1); 
+}
+    break;
+
+  case 124:
+#line 474 "foreign-pajek-parser.y"
+    { context->actfrom=0; 
+                         context->actto=0; 
+                         context->directed=(context->vcount2==0);
+                       }
+    break;
+
+  case 127:
+#line 481 "foreign-pajek-parser.y"
+    { context->actfrom++; context->actto=0; }
+    break;
+
+  case 130:
+#line 485 "foreign-pajek-parser.y"
+    {
+  if ((yyvsp[(1) - (1)].realnum) != 0) {
+    if (context->vcount2==0) {
+      context->actedge++;
+      igraph_i_pajek_add_numeric_edge_attribute("weight", (yyvsp[(1) - (1)].realnum), context);    
+      igraph_vector_push_back(context->vector, context->actfrom);
+      igraph_vector_push_back(context->vector, context->actto);
+    } else if (context->vcount2 + context->actto < context->vcount) {
+      context->actedge++;
+      igraph_i_pajek_add_numeric_edge_attribute("weight", (yyvsp[(1) - (1)].realnum), context);    
+      igraph_vector_push_back(context->vector, context->actfrom);
+      igraph_vector_push_back(context->vector, 
+			      context->vcount2+context->actto);
+    }
+  }
+  context->actto++;
+}
+    break;
+
+  case 131:
+#line 505 "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 "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 "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 "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 "foreign-pajek-parser.y"
+    { (yyval.string).str=igraph_pajek_yyget_text(scanner)+1; 
+               (yyval.string).len=igraph_pajek_yyget_leng(scanner)-2; }
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 2358 "foreign-pajek-parser.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (&yylloc, context, YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (&yylloc, context, yymsg);
+	  }
+	else
+	  {
+	    yyerror (&yylloc, context, YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+  yyerror_range[0] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, &yylloc, context);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[0] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      yyerror_range[0] = *yylsp;
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+  yyerror_range[1] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the look-ahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (&yylloc, context, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval, &yylloc, context);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, yylsp, context);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 520 "foreign-pajek-parser.y"
+
+
+int igraph_pajek_yyerror(YYLTYPE* locp, 
+			 igraph_i_pajek_parsedata_t *context, 
+			 char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1, 
+	   "Parse error in Pajek file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+igraph_real_t igraph_pajek_get_number(const char *str, long int length) {
+  igraph_real_t num;
+  char *tmp=igraph_Calloc(length+1, char);
+  
+  strncpy(tmp, str, length);
+  tmp[length]='\0';
+  sscanf(tmp, "%lf", &num);
+  igraph_Free(tmp);
+  return num;
+} 
+
+/* TODO: NA's */
+
+int igraph_i_pajek_add_numeric_attribute(igraph_trie_t *names,
+					 igraph_vector_ptr_t *attrs,
+					 long int count,
+					 const char *attrname,
+					 igraph_integer_t vid,
+					 igraph_real_t number) {
+  long int attrsize=igraph_trie_size(names);
+  long int id;
+  igraph_vector_t *na;
+  igraph_attribute_record_t *rec;
+
+  igraph_trie_get(names, attrname, &id);
+  if (id == attrsize) {
+    /* add a new attribute */
+    rec=igraph_Calloc(1, igraph_attribute_record_t);
+    na=igraph_Calloc(1, igraph_vector_t);
+    igraph_vector_init(na, count);
+    rec->name=strdup(attrname);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    rec->value=na;
+    igraph_vector_ptr_push_back(attrs, rec);
+  }
+  rec=VECTOR(*attrs)[id];
+  na=(igraph_vector_t*)rec->value;
+  if (igraph_vector_size(na) == vid) {
+    IGRAPH_CHECK(igraph_vector_push_back(na, number));
+  } else if (igraph_vector_size(na) < vid) {
+    long int origsize=igraph_vector_size(na);
+    IGRAPH_CHECK(igraph_vector_resize(na, (long int)vid+1));
+    for (;origsize<count; origsize++) {
+      VECTOR(*na)[origsize] = IGRAPH_NAN;
+    }
+    VECTOR(*na)[(long int) vid] = number;
+  } else { 
+    VECTOR(*na)[(long int) vid] = number;
+  }    
+
+  return 0;
+}
+
+/* TODO: NA's */
+
+int igraph_i_pajek_add_string_attribute(igraph_trie_t *names,
+					igraph_vector_ptr_t *attrs,
+					long int count,
+					const char *attrname,
+					igraph_integer_t vid,
+					const char *str) {
+  long int attrsize=igraph_trie_size(names);
+  long int id;
+  igraph_strvector_t *na;
+  igraph_attribute_record_t *rec;
+  long int i;
+
+  igraph_trie_get(names, attrname, &id);
+  if (id == attrsize) {
+    /* add a new attribute */
+    rec=igraph_Calloc(1, igraph_attribute_record_t);
+    na=igraph_Calloc(1, igraph_strvector_t);
+    igraph_strvector_init(na, count);
+    for (i=0; i<count; i++) {
+      igraph_strvector_set(na, i, "");
+    }
+    rec->name=strdup(attrname);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    rec->value=na;
+    igraph_vector_ptr_push_back(attrs, rec);
+  }
+  rec=VECTOR(*attrs)[id];
+  na=(igraph_strvector_t*)rec->value;
+  if (igraph_strvector_size(na) <= vid) { 
+    long int origsize=igraph_strvector_size(na);
+    IGRAPH_CHECK(igraph_strvector_resize(na, vid+1));
+    for (;origsize<count; origsize++) {
+      igraph_strvector_set(na, origsize, "");
+    }
+  }
+  igraph_strvector_set(na, vid, str);
+
+  return 0;
+}
+
+int igraph_i_pajek_add_string_vertex_attribute(const char *name, 
+					       const char *value,
+					       int len,
+					       igraph_i_pajek_parsedata_t *context) {
+  char *tmp;
+  int ret;
+
+  tmp=igraph_Calloc(len+1, char);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp);
+  strncpy(tmp, value, len);
+  tmp[len]='\0';
+
+  ret=igraph_i_pajek_add_string_attribute(context->vertex_attribute_names,
+					  context->vertex_attributes,
+					  context->vcount,
+					  name, context->actvertex-1,
+					  tmp);
+  
+  igraph_Free(tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return ret;
+}
+
+int igraph_i_pajek_add_string_edge_attribute(const char *name, 
+					     const char *value,
+					     int len, 
+					     igraph_i_pajek_parsedata_t *context) {
+  char *tmp;
+  int ret;
+
+  tmp=igraph_Calloc(len+1, char);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp);
+  strncpy(tmp, value, len);
+  tmp[len]='\0';
+  
+  ret=igraph_i_pajek_add_string_attribute(context->edge_attribute_names,
+					  context->edge_attributes,
+					  context->actedge,
+					  name, context->actedge-1,
+					  tmp);
+
+  igraph_Free(tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return ret;
+}
+
+int igraph_i_pajek_add_numeric_vertex_attribute(const char *name, 
+						igraph_real_t value, 
+						igraph_i_pajek_parsedata_t *context) {
+  
+  return
+    igraph_i_pajek_add_numeric_attribute(context->vertex_attribute_names,
+					 context->vertex_attributes,
+					 context->vcount,
+					 name, context->actvertex-1,
+					 value);
+}
+
+int igraph_i_pajek_add_numeric_edge_attribute(const char *name, 
+					      igraph_real_t value, 
+					      igraph_i_pajek_parsedata_t *context) {
+
+  return
+    igraph_i_pajek_add_numeric_attribute(context->edge_attribute_names,
+					 context->edge_attributes,
+					 context->actedge,
+					 name, context->actedge-1,
+					 value);
+}
+
+int igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t *context) {
+  
+  const char *attrname="type";
+  igraph_trie_t *names=context->vertex_attribute_names;
+  igraph_vector_ptr_t *attrs=context->vertex_attributes;
+  int i, n=context->vcount, n1=context->vcount2;
+  long int attrid, attrsize=igraph_trie_size(names);
+  igraph_attribute_record_t *rec;  
+  igraph_vector_t *na;
+
+  if (n1 > n) { 
+    IGRAPH_ERROR("Invalid number of vertices in bipartite Pajek file", 
+		 IGRAPH_PARSEERROR);
+  }
+
+  igraph_trie_get(names, attrname, &attrid);
+  if (attrid != attrsize) { 
+    IGRAPH_ERROR("Duplicate 'type' attribute in Pajek file, "
+		 "this should not happen", IGRAPH_EINTERNAL);
+  }
+  
+  /* add a new attribute */
+  rec=igraph_Calloc(1, igraph_attribute_record_t);
+  na=igraph_Calloc(1, igraph_vector_t);
+  igraph_vector_init(na, n);
+  rec->name=strdup(attrname);
+  rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+  rec->value=na;
+  igraph_vector_ptr_push_back(attrs, rec);
+
+  for (i=0; i<n1; i++) { 
+    VECTOR(*na)[i] = 0;
+  }
+  for (i=n1; i<n; i++) { 
+    VECTOR(*na)[i] = 1;
+  }
+
+  return 0;
+}
+
+int igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t *context) {
+  const igraph_vector_t *edges=context->vector;
+  int i, n1=context->vcount2;
+  int ne=igraph_vector_size(edges);
+  
+  for (i=0; i<ne; i+=2) {
+    int v1=VECTOR(*edges)[i];
+    int v2=VECTOR(*edges)[i+1];
+    if ( (v1 < n1 && v2 < n1) || (v1 > n1 && v2 > n1) ) {
+      IGRAPH_WARNING("Invalid edge in bipartite graph");
+    }
+  }
+  
+  return 0;
+}
+
diff --git a/src/foreign-pajek-parser.h b/src/foreign-pajek-parser.h
new file mode 100644
index 0000000..bd37e00
--- /dev/null
+++ b/src/foreign-pajek-parser.h
@@ -0,0 +1,179 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NEWLINE = 258,
+     NUM = 259,
+     ALNUM = 260,
+     QSTR = 261,
+     PSTR = 262,
+     NETWORKLINE = 263,
+     VERTICESLINE = 264,
+     ARCSLINE = 265,
+     EDGESLINE = 266,
+     ARCSLISTLINE = 267,
+     EDGESLISTLINE = 268,
+     MATRIXLINE = 269,
+     VP_X_FACT = 270,
+     VP_Y_FACT = 271,
+     VP_IC = 272,
+     VP_BC = 273,
+     VP_LC = 274,
+     VP_LR = 275,
+     VP_LPHI = 276,
+     VP_BW = 277,
+     VP_FOS = 278,
+     VP_PHI = 279,
+     VP_R = 280,
+     VP_Q = 281,
+     VP_LA = 282,
+     VP_FONT = 283,
+     VP_URL = 284,
+     VP_SIZE = 285,
+     EP_C = 286,
+     EP_S = 287,
+     EP_A = 288,
+     EP_W = 289,
+     EP_H1 = 290,
+     EP_H2 = 291,
+     EP_A1 = 292,
+     EP_A2 = 293,
+     EP_K1 = 294,
+     EP_K2 = 295,
+     EP_AP = 296,
+     EP_P = 297,
+     EP_L = 298,
+     EP_LP = 299,
+     EP_LR = 300,
+     EP_LPHI = 301,
+     EP_LC = 302,
+     EP_LA = 303,
+     EP_SIZE = 304,
+     EP_FOS = 305
+   };
+#endif
+/* Tokens.  */
+#define NEWLINE 258
+#define NUM 259
+#define ALNUM 260
+#define QSTR 261
+#define PSTR 262
+#define NETWORKLINE 263
+#define VERTICESLINE 264
+#define ARCSLINE 265
+#define EDGESLINE 266
+#define ARCSLISTLINE 267
+#define EDGESLISTLINE 268
+#define MATRIXLINE 269
+#define VP_X_FACT 270
+#define VP_Y_FACT 271
+#define VP_IC 272
+#define VP_BC 273
+#define VP_LC 274
+#define VP_LR 275
+#define VP_LPHI 276
+#define VP_BW 277
+#define VP_FOS 278
+#define VP_PHI 279
+#define VP_R 280
+#define VP_Q 281
+#define VP_LA 282
+#define VP_FONT 283
+#define VP_URL 284
+#define VP_SIZE 285
+#define EP_C 286
+#define EP_S 287
+#define EP_A 288
+#define EP_W 289
+#define EP_H1 290
+#define EP_H2 291
+#define EP_A1 292
+#define EP_A2 293
+#define EP_K1 294
+#define EP_K2 295
+#define EP_AP 296
+#define EP_P 297
+#define EP_L 298
+#define EP_LP 299
+#define EP_LR 300
+#define EP_LPHI 301
+#define EP_LC 302
+#define EP_LA 303
+#define EP_SIZE 304
+#define EP_FOS 305
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 123 "foreign-pajek-parser.y"
+{
+  long int intnum;
+  double   realnum;  
+  struct {
+    char *str;
+    int len;
+  } string;  
+}
+/* Line 1529 of yacc.c.  */
+#line 158 "foreign-pajek-parser.h"
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
diff --git a/src/foreign-pajek-parser.y b/src/foreign-pajek-parser.y
new file mode 100644
index 0000000..7233077
--- /dev/null
+++ b/src/foreign-pajek-parser.y
@@ -0,0 +1,758 @@
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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 library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "igraph_hacks_internal.h"
+#include "igraph_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "igraph_attributes.h"
+#include "config.h"
+#include "igraph_math.h"
+#include <math.h>
+#include "foreign-pajek-header.h"
+#include "foreign-pajek-parser.h"
+
+#define yyscan_t void*
+
+int igraph_pajek_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, 
+		       void* scanner);
+int igraph_pajek_yyerror(YYLTYPE* locp, 
+			 igraph_i_pajek_parsedata_t *context, 
+			 char *s);
+char *igraph_pajek_yyget_text (yyscan_t yyscanner );
+int igraph_pajek_yyget_leng (yyscan_t yyscanner );
+
+int igraph_i_pajek_add_string_vertex_attribute(const char *name, 
+					       const char *value,
+					       int len, 
+					       igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_string_edge_attribute(const char *name, 
+					     const char *value,
+					     int len,
+					     igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_numeric_vertex_attribute(const char *name, 
+						igraph_real_t value,
+						igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_numeric_edge_attribute(const char *name, 
+					      igraph_real_t value, 
+					      igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_add_numeric_attribute(igraph_trie_t *names,
+					 igraph_vector_ptr_t *attrs,
+					 long int count,
+					 const char *attrname,
+					 igraph_integer_t vid,
+					 igraph_real_t number);
+int igraph_i_pajek_add_string_attribute(igraph_trie_t *names,
+					igraph_vector_ptr_t *attrs,
+					long int count,
+					const char *attrname,
+					igraph_integer_t vid,
+					const char *str);
+
+int igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t *context);
+int igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t *context);
+
+extern igraph_real_t igraph_pajek_get_number(const char *str, long int len);
+extern long int igraph_i_pajek_actvertex;
+extern long int igraph_i_pajek_actedge;
+
+#define scanner context->scanner
+
+%}
+
+%pure-parser
+%output="y.tab.c"
+%name-prefix="igraph_pajek_yy"
+%defines
+%locations
+%error-verbose
+%parse-param { igraph_i_pajek_parsedata_t* context }
+%lex-param { void *scanner }
+
+%union {
+  long int intnum;
+  double   realnum;  
+  struct {
+    char *str;
+    int len;
+  } string;  
+}
+
+%type <intnum>   longint;
+%type <intnum>   arcfrom;
+%type <intnum>   arcto;
+%type <intnum>   edgefrom;
+%type <intnum>   edgeto;
+%type <realnum>  number;
+%type <string>   word;
+%type <string>   vpwordpar;
+%type <string>   epwordpar;
+%type <intnum>   vertex;
+
+%token NEWLINE
+%token NUM
+%token ALNUM
+%token QSTR
+%token PSTR
+%token NETWORKLINE
+%token VERTICESLINE
+%token ARCSLINE
+%token EDGESLINE
+%token ARCSLISTLINE
+%token EDGESLISTLINE
+%token MATRIXLINE
+
+%token VP_X_FACT
+%token VP_Y_FACT
+%token VP_IC
+%token VP_BC
+%token VP_LC
+%token VP_LR
+%token VP_LPHI
+%token VP_BW
+%token VP_FOS
+%token VP_PHI
+%token VP_R
+%token VP_Q
+%token VP_LA
+%token VP_FONT
+%token VP_URL
+%token VP_SIZE
+
+%token EP_C
+%token EP_S
+%token EP_A
+%token EP_W
+%token EP_H1
+%token EP_H2
+%token EP_A1
+%token EP_A2
+%token EP_K1
+%token EP_K2
+%token EP_AP
+%token EP_P
+%token EP_L
+%token EP_LP
+%token EP_LR
+%token EP_LPHI
+%token EP_LC
+%token EP_LA
+%token EP_SIZE
+%token EP_FOS
+
+%%
+
+input: nethead vertices edgeblock {
+  if (context->vcount2 > 0) { igraph_i_pajek_check_bipartite(context); }
+ };
+
+nethead: /* empty */ | NETWORKLINE words NEWLINE;
+
+vertices: verticeshead NEWLINE vertdefs;
+
+verticeshead: VERTICESLINE longint { 
+  context->vcount=$2; 
+  context->vcount2=0;
+            } 
+            | VERTICESLINE longint longint { 
+  context->vcount=$2;
+  context->vcount2=$3;
+  igraph_i_pajek_add_bipartite_type(context);
+};
+
+vertdefs: /* empty */  | vertdefs vertexline;
+
+vertexline: NEWLINE |
+            vertex NEWLINE |
+            vertex { context->actvertex=$1; } vertexid vertexcoords shape params NEWLINE { }
+;
+
+vertex: longint { $$=$1; context->mode=1; };
+
+vertexid: word {
+  igraph_i_pajek_add_string_vertex_attribute("id", $1.str, $1.len, context);
+};
+
+vertexcoords: /* empty */ 
+            | number number { 
+  igraph_i_pajek_add_numeric_vertex_attribute("x", $1, context);
+  igraph_i_pajek_add_numeric_vertex_attribute("y", $2, context);
+	    }
+            | number number number { 
+  igraph_i_pajek_add_numeric_vertex_attribute("x", $1, context);
+  igraph_i_pajek_add_numeric_vertex_attribute("y", $2, context);
+  igraph_i_pajek_add_numeric_vertex_attribute("z", $3, context);
+	    };
+
+shape: /* empty */ | word { 
+  igraph_i_pajek_add_string_vertex_attribute("shape", $1.str, $1.len, context);
+};
+
+params: /* empty */ | params param;
+
+param:
+       vpword
+     | VP_X_FACT number {
+	 igraph_i_pajek_add_numeric_vertex_attribute("xfact", $2, context);
+       }
+     | VP_Y_FACT number {
+         igraph_i_pajek_add_numeric_vertex_attribute("yfact", $2, context);
+       }
+     | VP_IC number number number { /* RGB color */
+         igraph_i_pajek_add_numeric_vertex_attribute("color-red", $2, context);
+	 igraph_i_pajek_add_numeric_vertex_attribute("color-green", $3, context);
+	 igraph_i_pajek_add_numeric_vertex_attribute("color-blue", $4, context);
+       }
+     | VP_BC number number number {
+         igraph_i_pajek_add_numeric_vertex_attribute("framecolor-red", $2, context);
+	 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-green", $3, context);
+	 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-blue", $4, context);
+       }
+     | VP_LC number number number {
+         igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-red", $2, context);
+	 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-green", $3, context);
+	 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-blue", $4, context);
+       }
+     | VP_LR number {
+         igraph_i_pajek_add_numeric_vertex_attribute("labeldist", $2, context);
+     }  
+     | VP_LPHI number {
+         igraph_i_pajek_add_numeric_vertex_attribute("labeldegree2", $2, context);
+     }  
+     | VP_BW number {
+         igraph_i_pajek_add_numeric_vertex_attribute("framewidth", $2, context);
+     }         
+     | VP_FOS number {
+         igraph_i_pajek_add_numeric_vertex_attribute("fontsize", $2, context);
+     }          
+     | VP_PHI number {       
+         igraph_i_pajek_add_numeric_vertex_attribute("rotation", $2, context);
+     }         
+     | VP_R number {
+         igraph_i_pajek_add_numeric_vertex_attribute("radius", $2, context);
+     }         
+     | VP_Q number {
+         igraph_i_pajek_add_numeric_vertex_attribute("diamondratio", $2, context);
+     }         
+     | VP_LA number {
+         igraph_i_pajek_add_numeric_vertex_attribute("labeldegree", $2, context);
+     }         
+     | VP_SIZE number {
+         igraph_i_pajek_add_numeric_vertex_attribute("vertexsize", $2, context);
+     } 
+;
+
+vpword: VP_FONT { context->mode=3; } vpwordpar { 
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("font", $3.str, $3.len, context);
+     } 
+     | VP_URL { context->mode=3; } vpwordpar {
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("url", $3.str, $3.len, context);
+     } 
+     | VP_IC { context->mode=3; } vpwordpar {
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("color", $3.str, $3.len, context);
+     } 
+     | VP_BC { context->mode=3; } vpwordpar {
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("framecolor", 
+						    $3.str, $3.len, context);
+     } 
+     | VP_LC { context->mode=3; } vpwordpar {
+         context->mode=1;
+	 igraph_i_pajek_add_string_vertex_attribute("labelcolor", 
+						    $3.str, $3.len, context);
+     } 
+;
+
+vpwordpar: word { $$=$1; };
+
+edgeblock: /* empty */ | edgeblock arcs | edgeblock edges | edgeblock arcslist | edgeblock edgeslist | edgeblock adjmatrix;
+
+arcs:   ARCSLINE NEWLINE arcsdefs        { context->directed=1; } 
+      | ARCSLINE number NEWLINE arcsdefs { context->directed=1; }; 
+
+arcsdefs: /* empty */ | arcsdefs arcsline;
+
+arcsline: NEWLINE | 
+          arcfrom arcto { context->actedge++;
+	                  context->mode=2; } weight edgeparams NEWLINE  { 
+  igraph_vector_push_back(context->vector, $1-1);
+  igraph_vector_push_back(context->vector, $2-1); }
+;
+
+arcfrom: longint;
+
+arcto: longint;
+
+edges:   EDGESLINE NEWLINE edgesdefs { context->directed=0; }
+       | EDGESLINE number NEWLINE edgesdefs { context->directed=0; }
+
+edgesdefs: /* empty */ | edgesdefs edgesline;
+
+edgesline: NEWLINE | 
+          edgefrom edgeto { context->actedge++; 
+	                    context->mode=2; } weight edgeparams NEWLINE { 
+  igraph_vector_push_back(context->vector, $1-1);
+  igraph_vector_push_back(context->vector, $2-1); }
+;
+
+edgefrom: longint;
+
+edgeto: longint;
+
+weight: /* empty */ | number {
+  igraph_i_pajek_add_numeric_edge_attribute("weight", $1, context);
+};
+
+edgeparams: /* empty */ | edgeparams edgeparam;
+
+edgeparam:
+     epword
+   | EP_C number number number {
+       igraph_i_pajek_add_numeric_edge_attribute("color-red", $2, context);
+       igraph_i_pajek_add_numeric_edge_attribute("color-green", $3, context);
+       igraph_i_pajek_add_numeric_edge_attribute("color-blue", $4, context);
+   }
+   | EP_S number { 
+       igraph_i_pajek_add_numeric_edge_attribute("arrowsize", $2, context);
+   }
+   | EP_W number {
+       igraph_i_pajek_add_numeric_edge_attribute("edgewidth", $2, context);
+   }
+   | EP_H1 number {
+       igraph_i_pajek_add_numeric_edge_attribute("hook1", $2, context);
+   }
+   | EP_H2 number {
+       igraph_i_pajek_add_numeric_edge_attribute("hook2", $2, context);
+   }
+   | EP_A1 number {
+       igraph_i_pajek_add_numeric_edge_attribute("angle1", $2, context);
+   }
+   | EP_A2 number {
+       igraph_i_pajek_add_numeric_edge_attribute("angle2", $2, context);
+   }
+   | EP_K1 number {
+       igraph_i_pajek_add_numeric_edge_attribute("velocity1", $2, context);
+   }
+   | EP_K2 number {
+       igraph_i_pajek_add_numeric_edge_attribute("velocity2", $2, context);
+   }
+   | EP_AP number {
+       igraph_i_pajek_add_numeric_edge_attribute("arrowpos", $2, context);
+   }
+   | EP_LP number {
+       igraph_i_pajek_add_numeric_edge_attribute("labelpos", $2, context);
+   }
+   | EP_LR number {
+       igraph_i_pajek_add_numeric_edge_attribute("labelangle", $2, context);
+   }
+   | EP_LPHI number {
+       igraph_i_pajek_add_numeric_edge_attribute("labelangle2", $2, context);
+   }
+   | EP_LA number {
+       igraph_i_pajek_add_numeric_edge_attribute("labeldegree", $2, context);
+   }
+   | EP_SIZE number {		/* what is this??? */
+       igraph_i_pajek_add_numeric_edge_attribute("arrowsize", $2, context);
+   }
+   | EP_FOS number {
+       igraph_i_pajek_add_numeric_edge_attribute("fontsize", $2, context);
+   }
+;
+
+epword: EP_A { context->mode=4; } epwordpar {
+      context->mode=2;
+      igraph_i_pajek_add_string_edge_attribute("arrowtype", $3.str, $3.len, context);
+    }
+    | EP_P { context->mode=4; } epwordpar {
+      context->mode=2;
+      igraph_i_pajek_add_string_edge_attribute("linepattern", $3.str, $3.len, context);
+    }
+    | EP_L { context->mode=4; } epwordpar {
+      context->mode=2;
+      igraph_i_pajek_add_string_edge_attribute("label", $3.str, $3.len, context);
+    }
+    | EP_LC { context->mode=4; } epwordpar {
+      context->mode=2;
+      igraph_i_pajek_add_string_edge_attribute("labelcolor", $3.str, $3.len, context);
+    }
+    | EP_C { context->mode=4; } epwordpar {
+      context->mode=2;
+      igraph_i_pajek_add_string_edge_attribute("color", $3.str, $3.len, context);
+    }
+;
+
+epwordpar: word { context->mode=2; $$=$1; };
+
+arcslist: ARCSLISTLINE NEWLINE arcslistlines { context->directed=1; };
+
+arcslistlines: /* empty */ | arcslistlines arclistline;
+
+arclistline: NEWLINE | arclistfrom arctolist NEWLINE;
+
+arctolist: /* empty */ | arctolist arclistto;
+
+arclistfrom: longint { context->mode=0; context->actfrom=fabs($1)-1; };
+
+arclistto: longint { 
+  igraph_vector_push_back(context->vector, context->actfrom); 
+  igraph_vector_push_back(context->vector, fabs($1)-1); 
+};
+
+edgeslist: EDGESLISTLINE NEWLINE edgelistlines { context->directed=0; };
+
+edgelistlines: /* empty */ | edgelistlines edgelistline;
+
+edgelistline: NEWLINE | edgelistfrom edgetolist NEWLINE;
+
+edgetolist: /* empty */ | edgetolist edgelistto;
+
+edgelistfrom: longint { context->mode=0; context->actfrom=fabs($1)-1; };
+
+edgelistto: longint { 
+  igraph_vector_push_back(context->vector, context->actfrom); 
+  igraph_vector_push_back(context->vector, fabs($1)-1); 
+};
+
+/* -----------------------------------------------------*/
+
+adjmatrix: matrixline NEWLINE adjmatrixlines;
+
+matrixline: MATRIXLINE { context->actfrom=0; 
+                         context->actto=0; 
+                         context->directed=(context->vcount2==0);
+                       };
+
+adjmatrixlines: /* empty */ | adjmatrixlines adjmatrixline;
+
+adjmatrixline: adjmatrixnumbers NEWLINE { context->actfrom++; context->actto=0; };
+
+adjmatrixnumbers: /* empty */ | adjmatrixentry adjmatrixnumbers;
+
+adjmatrixentry: number {
+  if ($1 != 0) {
+    if (context->vcount2==0) {
+      context->actedge++;
+      igraph_i_pajek_add_numeric_edge_attribute("weight", $1, context);    
+      igraph_vector_push_back(context->vector, context->actfrom);
+      igraph_vector_push_back(context->vector, context->actto);
+    } else if (context->vcount2 + context->actto < context->vcount) {
+      context->actedge++;
+      igraph_i_pajek_add_numeric_edge_attribute("weight", $1, context);    
+      igraph_vector_push_back(context->vector, context->actfrom);
+      igraph_vector_push_back(context->vector, 
+			      context->vcount2+context->actto);
+    }
+  }
+  context->actto++;
+};
+
+/* -----------------------------------------------------*/
+
+longint: NUM { $$=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),
+					  igraph_pajek_yyget_leng(scanner)); };
+
+number: NUM  { $$=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),
+					  igraph_pajek_yyget_leng(scanner)); };
+
+words: /* empty */ | words word;
+
+word: ALNUM { $$.str=igraph_pajek_yyget_text(scanner); 
+              $$.len=igraph_pajek_yyget_leng(scanner); }
+      | NUM { $$.str=igraph_pajek_yyget_text(scanner); 
+              $$.len=igraph_pajek_yyget_leng(scanner); }
+      | QSTR { $$.str=igraph_pajek_yyget_text(scanner)+1; 
+               $$.len=igraph_pajek_yyget_leng(scanner)-2; };
+
+%%
+
+int igraph_pajek_yyerror(YYLTYPE* locp, 
+			 igraph_i_pajek_parsedata_t *context, 
+			 char *s) {
+  snprintf(context->errmsg, sizeof(context->errmsg)/sizeof(char)-1, 
+	   "Parse error in Pajek file, line %i (%s)", 
+	   locp->first_line, s);
+  return 0;
+}
+
+igraph_real_t igraph_pajek_get_number(const char *str, long int length) {
+  igraph_real_t num;
+  char *tmp=igraph_Calloc(length+1, char);
+  
+  strncpy(tmp, str, length);
+  tmp[length]='\0';
+  sscanf(tmp, "%lf", &num);
+  igraph_Free(tmp);
+  return num;
+} 
+
+/* TODO: NA's */
+
+int igraph_i_pajek_add_numeric_attribute(igraph_trie_t *names,
+					 igraph_vector_ptr_t *attrs,
+					 long int count,
+					 const char *attrname,
+					 igraph_integer_t vid,
+					 igraph_real_t number) {
+  long int attrsize=igraph_trie_size(names);
+  long int id;
+  igraph_vector_t *na;
+  igraph_attribute_record_t *rec;
+
+  igraph_trie_get(names, attrname, &id);
+  if (id == attrsize) {
+    /* add a new attribute */
+    rec=igraph_Calloc(1, igraph_attribute_record_t);
+    na=igraph_Calloc(1, igraph_vector_t);
+    igraph_vector_init(na, count);
+    rec->name=strdup(attrname);
+    rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+    rec->value=na;
+    igraph_vector_ptr_push_back(attrs, rec);
+  }
+  rec=VECTOR(*attrs)[id];
+  na=(igraph_vector_t*)rec->value;
+  if (igraph_vector_size(na) == vid) {
+    IGRAPH_CHECK(igraph_vector_push_back(na, number));
+  } else if (igraph_vector_size(na) < vid) {
+    long int origsize=igraph_vector_size(na);
+    IGRAPH_CHECK(igraph_vector_resize(na, (long int)vid+1));
+    for (;origsize<count; origsize++) {
+      VECTOR(*na)[origsize] = IGRAPH_NAN;
+    }
+    VECTOR(*na)[(long int) vid] = number;
+  } else { 
+    VECTOR(*na)[(long int) vid] = number;
+  }    
+
+  return 0;
+}
+
+/* TODO: NA's */
+
+int igraph_i_pajek_add_string_attribute(igraph_trie_t *names,
+					igraph_vector_ptr_t *attrs,
+					long int count,
+					const char *attrname,
+					igraph_integer_t vid,
+					const char *str) {
+  long int attrsize=igraph_trie_size(names);
+  long int id;
+  igraph_strvector_t *na;
+  igraph_attribute_record_t *rec;
+  long int i;
+
+  igraph_trie_get(names, attrname, &id);
+  if (id == attrsize) {
+    /* add a new attribute */
+    rec=igraph_Calloc(1, igraph_attribute_record_t);
+    na=igraph_Calloc(1, igraph_strvector_t);
+    igraph_strvector_init(na, count);
+    for (i=0; i<count; i++) {
+      igraph_strvector_set(na, i, "");
+    }
+    rec->name=strdup(attrname);
+    rec->type=IGRAPH_ATTRIBUTE_STRING;
+    rec->value=na;
+    igraph_vector_ptr_push_back(attrs, rec);
+  }
+  rec=VECTOR(*attrs)[id];
+  na=(igraph_strvector_t*)rec->value;
+  if (igraph_strvector_size(na) <= vid) { 
+    long int origsize=igraph_strvector_size(na);
+    IGRAPH_CHECK(igraph_strvector_resize(na, vid+1));
+    for (;origsize<count; origsize++) {
+      igraph_strvector_set(na, origsize, "");
+    }
+  }
+  igraph_strvector_set(na, vid, str);
+
+  return 0;
+}
+
+int igraph_i_pajek_add_string_vertex_attribute(const char *name, 
+					       const char *value,
+					       int len,
+					       igraph_i_pajek_parsedata_t *context) {
+  char *tmp;
+  int ret;
+
+  tmp=igraph_Calloc(len+1, char);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp);
+  strncpy(tmp, value, len);
+  tmp[len]='\0';
+
+  ret=igraph_i_pajek_add_string_attribute(context->vertex_attribute_names,
+					  context->vertex_attributes,
+					  context->vcount,
+					  name, context->actvertex-1,
+					  tmp);
+  
+  igraph_Free(tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return ret;
+}
+
+int igraph_i_pajek_add_string_edge_attribute(const char *name, 
+					     const char *value,
+					     int len, 
+					     igraph_i_pajek_parsedata_t *context) {
+  char *tmp;
+  int ret;
+
+  tmp=igraph_Calloc(len+1, char);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp);
+  strncpy(tmp, value, len);
+  tmp[len]='\0';
+  
+  ret=igraph_i_pajek_add_string_attribute(context->edge_attribute_names,
+					  context->edge_attributes,
+					  context->actedge,
+					  name, context->actedge-1,
+					  tmp);
+
+  igraph_Free(tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return ret;
+}
+
+int igraph_i_pajek_add_numeric_vertex_attribute(const char *name, 
+						igraph_real_t value, 
+						igraph_i_pajek_parsedata_t *context) {
+  
+  return
+    igraph_i_pajek_add_numeric_attribute(context->vertex_attribute_names,
+					 context->vertex_attributes,
+					 context->vcount,
+					 name, context->actvertex-1,
+					 value);
+}
+
+int igraph_i_pajek_add_numeric_edge_attribute(const char *name, 
+					      igraph_real_t value, 
+					      igraph_i_pajek_parsedata_t *context) {
+
+  return
+    igraph_i_pajek_add_numeric_attribute(context->edge_attribute_names,
+					 context->edge_attributes,
+					 context->actedge,
+					 name, context->actedge-1,
+					 value);
+}
+
+int igraph_i_pajek_add_bipartite_type(igraph_i_pajek_parsedata_t *context) {
+  
+  const char *attrname="type";
+  igraph_trie_t *names=context->vertex_attribute_names;
+  igraph_vector_ptr_t *attrs=context->vertex_attributes;
+  int i, n=context->vcount, n1=context->vcount2;
+  long int attrid, attrsize=igraph_trie_size(names);
+  igraph_attribute_record_t *rec;  
+  igraph_vector_t *na;
+
+  if (n1 > n) { 
+    IGRAPH_ERROR("Invalid number of vertices in bipartite Pajek file", 
+		 IGRAPH_PARSEERROR);
+  }
+
+  igraph_trie_get(names, attrname, &attrid);
+  if (attrid != attrsize) { 
+    IGRAPH_ERROR("Duplicate 'type' attribute in Pajek file, "
+		 "this should not happen", IGRAPH_EINTERNAL);
+  }
+  
+  /* add a new attribute */
+  rec=igraph_Calloc(1, igraph_attribute_record_t);
+  na=igraph_Calloc(1, igraph_vector_t);
+  igraph_vector_init(na, n);
+  rec->name=strdup(attrname);
+  rec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+  rec->value=na;
+  igraph_vector_ptr_push_back(attrs, rec);
+
+  for (i=0; i<n1; i++) { 
+    VECTOR(*na)[i] = 0;
+  }
+  for (i=n1; i<n; i++) { 
+    VECTOR(*na)[i] = 1;
+  }
+
+  return 0;
+}
+
+int igraph_i_pajek_check_bipartite(igraph_i_pajek_parsedata_t *context) {
+  const igraph_vector_t *edges=context->vector;
+  int i, n1=context->vcount2;
+  int ne=igraph_vector_size(edges);
+  
+  for (i=0; i<ne; i+=2) {
+    int v1=VECTOR(*edges)[i];
+    int v2=VECTOR(*edges)[i+1];
+    if ( (v1 < n1 && v2 < n1) || (v1 > n1 && v2 > n1) ) {
+      IGRAPH_WARNING("Invalid edge in bipartite graph");
+    }
+  }
+  
+  return 0;
+}
diff --git a/src/foreign.c b/src/foreign.c
new file mode 100644
index 0000000..d5b2767
--- /dev/null
+++ b/src/foreign.c
@@ -0,0 +1,3334 @@
+/* -*- mode: C -*-  */
+/* 
+   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
+
+*/
+
+#include "igraph_foreign.h"
+#include "config.h"
+#include "igraph_math.h"
+#include "igraph_gml_tree.h"
+#include "igraph_memory.h"
+#include "igraph_attributes.h"
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_constructors.h"
+#include "igraph_types_internal.h"
+
+#include <ctype.h>		/* isspace */
+#include <string.h>
+#include <time.h>
+
+/**
+ * \section about_loadsave 
+ * 
+ * <para>These functions can write a graph to a file, or read a graph
+ * from a file.</para>
+ * 
+ * <para>Note that as \a igraph uses the traditional C streams, it is
+ * possible to read/write files from/to memory, at least on GNU
+ * operating systems supporting \quote non-standard\endquote streams.</para>
+ */
+
+/**
+ * \ingroup loadsave
+ * \function igraph_read_graph_edgelist
+ * \brief Reads an edge list from a file and creates a graph.
+ * 
+ * </para><para>
+ * This format is simply a series of even number integers separated by
+ * whitespace. The one edge (ie. two integers) per line format is thus
+ * not required (but recommended for readability). Edges of directed
+ * graphs are assumed to be in from, to order.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream Pointer to a stream, it should be readable.
+ * \param n The number of vertices in the graph. If smaller than the
+ *        largest integer in the file it will be ignored. It is thus
+ *        safe to supply zero here.
+ * \param directed Logical, if true the graph is directed, if false it
+ *        will be undirected.
+ * \return Error code:
+ *         \c IGRAPH_PARSEERROR: if there is a
+ *         problem reading the file, or the file is syntactically
+ *         incorrect. 
+ * 
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges. It is assumed that
+ * reading an integer requires O(1)
+ * time. 
+ */
+
+int igraph_read_graph_edgelist(igraph_t *graph, FILE *instream, 
+			       igraph_integer_t n, igraph_bool_t directed) {
+
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int from, to;
+  int c;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, 100));
+
+  /* skip all whitespace */
+  do {
+    c = getc (instream);
+  } while (isspace (c));
+  ungetc (c, instream);
+  
+  while (!feof(instream)) {
+    int read;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    read=fscanf(instream, "%li", &from);
+    if (read != 1) { 
+      IGRAPH_ERROR("parsing edgelist file failed", IGRAPH_PARSEERROR); 
+    }
+    read=fscanf(instream, "%li", &to);
+    if (read != 1) { 
+      IGRAPH_ERROR("parsing edgelist file failed", IGRAPH_PARSEERROR); 
+    }
+    IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
+    IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+    
+    /* skip all whitespace */
+    do {
+      c = getc (instream);
+    } while (isspace (c));
+    ungetc (c, instream);    
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+#include "foreign-ncol-header.h"
+
+int igraph_ncol_yylex_init_extra (igraph_i_ncol_parsedata_t* user_defined,
+				void* scanner);
+int igraph_ncol_yylex_destroy (void *scanner );
+int igraph_ncol_yyparse (igraph_i_ncol_parsedata_t* context);
+void igraph_ncol_yyset_in  (FILE * in_str, void* yyscanner );
+
+/**
+ * \ingroup loadsave
+ * \function igraph_read_graph_ncol
+ * \brief Reads a <code>.ncol</code> file used by LGL.
+ *
+ * Also useful for creating graphs from \quote named\endquote (and
+ * optionally weighted) edge lists. 
+ * 
+ * </para><para>
+ * This format is used by the Large Graph Layout program
+ * (http://lgl.sourceforge.net), 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 follow 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.
+ *
+ * </para><para>
+ * The resulting graph is always undirected.
+ * LGL cannot deal with files which contain multiple or loop edges, 
+ * this is however not checked here, as \a igraph is happy with
+ * these.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream Pointer to a stream, it should be readable.
+ * \param predefnames Pointer to the symbolic names of the vertices in
+ *        the file. If \c NULL is given here then vertex ids will be
+ *        assigned to vertex names in the order of their appearance in
+ *        the \c .ncol file. If it is not \c NULL and some unknown
+ *        vertex names are found in the \c .ncol file then new vertex
+ *        ids will be assigned to them. 
+ * \param names Logical value, if TRUE the symbolic names of the
+ *        vertices will be added to the graph as a vertex attribute
+ *        called \quote name\endquote.
+ * \param weights Whether to add the weights of the edges to the
+ *        graph as an edge attribute called \quote weight\endquote.
+ *        \c IGRAPH_ADD_WEIGHTS_YES adds the weights (even if they
+ *        are not present in the file, in this case they are assumed
+ *        to be zero). \c IGRAPH_ADD_WEIGHTS_NO does not add any
+ *        edge attribute. \c IGRAPH_ADD_WEIGHTS_IF_PRESENT adds the
+ *        attribute if and only if there is at least one explicit
+ *        edge weight in the input file.
+ * \param directed Whether to create a directed graph. As this format
+ *        was originally used only for undirected graphs there is no
+ *        information in the file about the directedness of the graph.
+ *        Set this parameter to \c IGRAPH_DIRECTED or \c
+ *        IGRAPH_UNDIRECTED to create a directed or undirected graph.
+ * \return Error code:
+ *         \c IGRAPH_PARSEERROR: if there is a
+ *          problem reading 
+ *         the file, or the file is syntactically incorrect.
+ *
+ * Time complexity:
+ * O(|V|+|E|log(|V|)) if we neglect
+ * the time required by the parsing. As usual
+ * |V| is the number of vertices,
+ * while |E| is the number of edges. 
+ * 
+ * \sa \ref igraph_read_graph_lgl(), \ref igraph_write_graph_ncol()
+ */
+
+int igraph_read_graph_ncol(igraph_t *graph, FILE *instream, 
+			   igraph_strvector_t *predefnames,
+			   igraph_bool_t names, 
+			   igraph_add_weights_t weights,
+			   igraph_bool_t directed) {
+  
+  igraph_vector_t edges, ws;
+  igraph_trie_t trie=IGRAPH_TRIE_NULL;
+  long int no_predefined=0;
+  igraph_vector_ptr_t name, weight;
+  igraph_vector_ptr_t *pname=0, *pweight=0;
+  igraph_attribute_record_t namerec, weightrec;
+  const char *namestr="name", *weightstr="weight";
+  igraph_i_ncol_parsedata_t context;
+
+  IGRAPH_CHECK(igraph_empty(graph, 0, directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  IGRAPH_TRIE_INIT_FINALLY(&trie, names);
+  IGRAPH_VECTOR_INIT_FINALLY(&ws, 0);
+
+  /* Add the predefined names, if any */
+  if (predefnames != 0) {
+    long int i, id, n;
+    char *key;
+    n=no_predefined=igraph_strvector_size(predefnames);
+    for (i=0; i<n; i++) {
+      igraph_strvector_get(predefnames, i, &key);
+      igraph_trie_get(&trie, key, &id);
+      if (id != i) {
+        IGRAPH_WARNING("reading NCOL file, duplicate entry in predefnames");
+        no_predefined--;
+      }
+    }
+  }
+  
+  context.has_weights=0;
+  context.vector=&edges;
+  context.weights=&ws;
+  context.trie=≜
+  context.eof=0;
+
+  igraph_ncol_yylex_init_extra(&context, &context.scanner);
+  IGRAPH_FINALLY(igraph_ncol_yylex_destroy, context.scanner);
+
+  igraph_ncol_yyset_in(instream, context.scanner);  
+
+  if (igraph_ncol_yyparse(&context)) {
+    if (context.errmsg) {
+      IGRAPH_ERROR(context.errmsg, IGRAPH_PARSEERROR);
+    } else {
+      IGRAPH_ERROR("Cannot read NCOL file", IGRAPH_PARSEERROR);
+    }
+  }
+
+  if (predefnames != 0 && 
+      igraph_trie_size(&trie) != no_predefined) {
+    IGRAPH_WARNING("unknown vertex/vertices found, predefnames extended");    
+  }
+
+  if (names) {
+    const igraph_strvector_t *namevec;
+    IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1)); 
+    pname=&name;
+    igraph_trie_getkeys(&trie, &namevec); /* dirty */
+    namerec.name=namestr;
+    namerec.type=IGRAPH_ATTRIBUTE_STRING;
+    namerec.value=namevec;
+    VECTOR(name)[0]=&namerec;
+  }
+
+  if (weights == IGRAPH_ADD_WEIGHTS_YES ||
+      (weights == IGRAPH_ADD_WEIGHTS_IF_PRESENT && context.has_weights)) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1)); 
+    pweight=&weight;
+    weightrec.name=weightstr;
+    weightrec.type=IGRAPH_ATTRIBUTE_NUMERIC;
+    weightrec.value=&ws;
+    VECTOR(weight)[0]=&weightrec;
+  }
+
+  IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) 
+				   igraph_vector_max(&edges)+1, pname));
+  IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight));
+
+  if (pname) {
+    igraph_vector_ptr_destroy(pname);
+  }
+  if (pweight) {
+    igraph_vector_ptr_destroy(pweight);
+  }
+  igraph_vector_destroy(&ws); 
+  igraph_trie_destroy(&trie);
+  igraph_vector_destroy(&edges);
+  igraph_ncol_yylex_destroy(context.scanner);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+#include "foreign-lgl-header.h"
+
+int igraph_lgl_yylex_init_extra (igraph_i_lgl_parsedata_t* user_defined,
+				void* scanner);
+int igraph_lgl_yylex_destroy (void *scanner );
+int igraph_lgl_yyparse (igraph_i_lgl_parsedata_t* context);
+void igraph_lgl_yyset_in  (FILE * in_str, void* yyscanner );
+
+/**
+ * \ingroup loadsave
+ * \function igraph_read_graph_lgl
+ * \brief Reads a graph from an <code>.lgl</code> file
+ * 
+ * </para><para>
+ * The <code>.lgl</code> format is used by the Large Graph
+ * Layout visualization software
+ * (http://lgl.sourceforge.net), it can 
+ * describe undirected optionally weighted graphs. From the LGL
+ * manual: 
+ * 
+ * \blockquote <para>The second format is the LGL file format
+ * (<code>.lgl</code> 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:
+ * \verbatim # vertex1name
+vertex2name [optionalWeight]
+vertex3name [optionalWeight] \endverbatim
+ * 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.</para> \endblockquote
+ * 
+ * </para><para>
+ * LGL cannot handle loop and multiple edges or directed graphs, but
+ * in \a igraph it is not an error to have multiple and loop edges.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream A stream, it should be readable.
+ * \param names Logical value, if TRUE the symbolic names of the
+ *        vertices will be added to the graph as a vertex attribute
+ *        called \quote name\endquote.
+ * \param weights Whether to add the weights of the edges to the
+ *        graph as an edge attribute called \quote weight\endquote.
+ *        \c IGRAPH_ADD_WEIGHTS_YES adds the weights (even if they
+ *        are not present in the file, in this case they are assumed
+ *        to be zero). \c IGRAPH_ADD_WEIGHTS_NO does not add any
+ *        edge attribute. \c IGRAPH_ADD_WEIGHTS_IF_PRESENT adds the
+ *        attribute if and only if there is at least one explicit
+ *        edge weight in the input file.
+ * \param directed Whether to create a directed graph. As this format
+ *        was originally used only for undirected graphs there is no
+ *        information in the file about the directedness of the graph.
+ *        Set this parameter to \c IGRAPH_DIRECTED or \c
+ *        IGRAPH_UNDIRECTED to create a directed or undirected graph.
+ * \return Error code:
+ *         \c IGRAPH_PARSEERROR: if there is a
+ *         problem reading the file, or the file is syntactically
+ *         incorrect. 
+ *
+ * Time complexity:
+ * O(|V|+|E|log(|V|)) if we neglect
+ * the time required by the parsing. As usual
+ * |V| is the number of vertices,
+ * while |E| is the number of edges. 
+ * 
+ * \sa \ref igraph_read_graph_ncol(), \ref igraph_write_graph_lgl()
+ * 
+ * \example examples/simple/igraph_read_graph_lgl.c
+ */
+
+int igraph_read_graph_lgl(igraph_t *graph, FILE *instream,
+			  igraph_bool_t names, 
+			  igraph_add_weights_t weights,
+			  igraph_bool_t directed) {
+
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL, ws=IGRAPH_VECTOR_NULL;
+  igraph_trie_t trie=IGRAPH_TRIE_NULL;
+  igraph_vector_ptr_t name, weight;
+  igraph_vector_ptr_t *pname=0, *pweight=0;
+  igraph_attribute_record_t namerec, weightrec;
+  const char *namestr="name", *weightstr="weight";
+  igraph_i_lgl_parsedata_t context;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&ws, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_TRIE_INIT_FINALLY(&trie, names);
+  
+  context.has_weights=0;
+  context.vector=&edges;
+  context.weights=&ws;
+  context.trie=≜
+  context.eof=0;
+
+  igraph_lgl_yylex_init_extra(&context, &context.scanner);
+  IGRAPH_FINALLY(igraph_lgl_yylex_destroy, context.scanner);
+
+  igraph_lgl_yyset_in(instream, context.scanner);  
+
+  if (igraph_lgl_yyparse(&context)) {
+    if (context.errmsg) {
+      IGRAPH_ERROR(context.errmsg, IGRAPH_PARSEERROR);
+    } else {
+      IGRAPH_ERROR("Cannot read LGL file", IGRAPH_PARSEERROR);
+    }
+  }
+
+  IGRAPH_CHECK(igraph_empty(graph, 0, directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+
+  if (names) {
+    const igraph_strvector_t *namevec;
+    IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1)); 
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &name);
+    pname=&name;
+    igraph_trie_getkeys(&trie, &namevec); /* dirty */
+    namerec.name=namestr;
+    namerec.type=IGRAPH_ATTRIBUTE_STRING;
+    namerec.value=namevec;
+    VECTOR(name)[0]=&namerec;
+  }
+
+  if (weights == IGRAPH_ADD_WEIGHTS_YES ||
+      (weights == IGRAPH_ADD_WEIGHTS_IF_PRESENT && context.has_weights)) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1)); 
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &weight);
+    pweight=&weight;
+    weightrec.name=weightstr;
+    weightrec.type=IGRAPH_ATTRIBUTE_NUMERIC;
+    weightrec.value=&ws;
+    VECTOR(weight)[0]=&weightrec;
+  }
+
+  IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) 
+				   igraph_trie_size(&trie), pname));
+  IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight));
+  
+  if (pweight) {
+    igraph_vector_ptr_destroy(pweight);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (pname) {
+    igraph_vector_ptr_destroy(pname);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_trie_destroy(&trie);
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&ws);
+  igraph_lgl_yylex_destroy(context.scanner);
+  IGRAPH_FINALLY_CLEAN(5);
+  
+  return 0;
+}
+
+#include "foreign-pajek-header.h"
+
+int igraph_pajek_yylex_init_extra(igraph_i_pajek_parsedata_t* user_defined,
+				  void* scanner);
+int igraph_pajek_yylex_destroy (void *scanner );
+int igraph_pajek_yyparse (igraph_i_pajek_parsedata_t* context);
+void igraph_pajek_yyset_in  (FILE * in_str, void* yyscanner );
+
+/**
+ * \function igraph_read_graph_pajek
+ * \brief Reads a file in Pajek format
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param file An already opened file handler.
+ * \return Error code.
+ * 
+ * </para><para>
+ * Only a subset of the Pajek format is implemented. This is partially
+ * because this format is not very well documented, but also because
+ * <command>igraph</command> does not support some Pajek features, like 
+ * multigraphs.
+ * 
+ * </para><para>
+ * Starting from version 0.6.1 igraph reads bipartite (two-mode) 
+ * graphs from Pajek files and add the \c type vertex attribute for them.
+ * Warnings are given for invalid edges, i.e. edges connecting
+ * vertices of the same type.
+ * 
+ * </para><para> 
+ * The list of the current limitations:
+ * \olist
+ * \oli Only <filename>.net</filename> files are supported, Pajek
+ * project files (<filename>.paj</filename>) are not. These might be
+ * supported in the future if there is need for it.
+ * \oli Time events networks are not supported.
+ * \oli Hypergraphs (ie. graphs with non-binary edges) are not
+ * supported.
+ * \oli Graphs with both directed and non-directed edges are not
+ * supported, are they cannot be represented in
+ * <command>igraph</command>.
+ * \oli Only Pajek networks are supported, permutations, hierarchies,
+ * clusters and vectors are not.
+ * \oli Graphs with multiple edge sets are not supported.
+ * \endolist
+ * 
+ * </para><para>
+ * If there are attribute handlers installed,
+ * <command>igraph</command> also reads the vertex and edge attributes
+ * from the file. Most attributes are renamed to be more informative: 
+ * `\c color' instead of `\c c', `\c xfact' instead of `\c x_fact',
+ * `\c yfact' instead of `y_fact', `\c labeldist' instead of `\c lr',
+ * `\c labeldegree2' instead of `\c lphi', `\c framewidth' instead of `\c bw',
+ * `\c fontsize'
+ * instead of `\c fos', `\c rotation' instead of `\c phi', `\c radius' instead
+ * of `\c r',
+ * `\c diamondratio' instead of `\c q', `\c labeldegree' instead of `\c la',
+ * `\c vertexsize'
+ * instead of `\c size', `\c color' instead of `\c ic', `\c framecolor' instead of
+ * `\c bc', `\c labelcolor' instead of `\c lc', these belong to vertices. 
+ * 
+ * </para><para>
+ * Edge attributes are also renamed, `\c s' to `\c arrowsize', `\c w'
+ * to `\c edgewidth', `\c h1' to `\c hook1', `\c h2' to `\c hook2',
+ * `\c a1' to `\c angle1', `\c a2' to `\c angle2', `\c k1' to 
+ * `\c velocity1', `\c k2' to `\c velocity2', `\c ap' to `\c
+ * arrowpos', `\c lp' to `\c labelpos', `\c lr' to 
+ * `\c labelangle', `\c lphi' to `\c labelangle2', `\c la' to `\c
+ * labeldegree', `\c fos' to 
+ * `\c fontsize', `\c a' to `\c arrowtype', `\c p' to `\c
+ * linepattern', `\c l' to `\c label', `\c lc' to 
+ * `\c labelcolor', `\c c' to `\c color'.
+ * 
+ * </para><para>
+ * In addition the following vertex attributes might be added: `\c id'
+ * if there are vertex ids in the file, `\c x' and `\c y' or `\c x'
+ * and `\c y' and `\c z' if there are vertex coordinates in the file.
+ * 
+ * </para><para>The `\c weight' edge attribute might be
+ * added if there are edge weights present.
+ * 
+ * </para><para>
+ * See the pajek homepage:
+ * http://vlado.fmf.uni-lj.si/pub/networks/pajek/ for more info on
+ * Pajek and the Pajek manual:
+ * http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/pajekman.pdf for
+ * information on the Pajek file format.
+ *
+ * </para><para>
+ * Time complexity: O(|V|+|E|+|A|), |V| is the number of vertices, |E|
+ * the number of edges, |A| the number of attributes (vertex + edge)
+ * in the graph if there are attribute handlers installed.
+ * 
+ * \sa \ref igraph_write_graph_pajek() for writing Pajek files, \ref
+ * igraph_read_graph_graphml() for reading GraphML files.
+ * 
+ * \example examples/simple/foreign.c
+ */
+
+int igraph_read_graph_pajek(igraph_t *graph, FILE *instream) {
+
+  igraph_vector_t edges;
+  igraph_trie_t vattrnames;
+  igraph_vector_ptr_t vattrs;
+  igraph_trie_t eattrnames;
+  igraph_vector_ptr_t eattrs;
+  long int i, j;
+  igraph_i_pajek_parsedata_t context;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  IGRAPH_TRIE_INIT_FINALLY(&vattrnames, 1);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&vattrs, 0);
+  IGRAPH_TRIE_INIT_FINALLY(&eattrnames, 1);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&eattrs, 0);
+
+  context.vector=&edges;
+  context.mode=0;
+  context.vcount=-1;
+  context.vertexid=0;
+  context.vertex_attribute_names=&vattrnames;
+  context.vertex_attributes=&vattrs;
+  context.edge_attribute_names=&eattrnames;
+  context.edge_attributes=&eattrs;
+  context.actedge=0;
+  context.eof=0;
+
+  igraph_pajek_yylex_init_extra(&context, &context.scanner);
+  IGRAPH_FINALLY(igraph_pajek_yylex_destroy, context.scanner);
+
+  igraph_pajek_yyset_in(instream, context.scanner);    
+
+  if (igraph_pajek_yyparse(&context)) {
+    if (context.errmsg) {
+      IGRAPH_ERROR(context.errmsg, IGRAPH_PARSEERROR);
+    } else {
+      IGRAPH_ERROR("Cannot read Pajek file", IGRAPH_PARSEERROR);
+    }
+  }
+
+  if (context.vcount < 0)
+    IGRAPH_ERROR("invalid vertex count in Pajek file", IGRAPH_EINVAL);
+  if (context.vcount2 < 0) 
+    IGRAPH_ERROR("invalid 2-mode vertex count in Pajek file", IGRAPH_EINVAL);
+  
+  for (i=0; i<igraph_vector_ptr_size(&eattrs); i++) {
+    igraph_attribute_record_t *rec=VECTOR(eattrs)[i];
+    if (rec->type==IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_vector_t *vec=(igraph_vector_t*)rec->value;
+      long int origsize=igraph_vector_size(vec);
+      igraph_vector_resize(vec, context.actedge);
+      for (j=origsize; j<context.actedge; j++) {
+	VECTOR(*vec)[j] = IGRAPH_NAN;
+      }
+    } 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, context.actedge);
+      for (j=origsize; j<context.actedge; j++) {
+	igraph_strvector_set(strvec, j, "");
+      }
+    }
+  }
+
+  IGRAPH_CHECK(igraph_empty(graph, 0, context.directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  IGRAPH_CHECK(igraph_add_vertices(graph, context.vcount, &vattrs));
+  IGRAPH_CHECK(igraph_add_edges(graph, &edges, &eattrs));
+
+  for (i=0; i<igraph_vector_ptr_size(&vattrs); i++) {
+    igraph_attribute_record_t *rec=VECTOR(vattrs)[i];
+    if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_vector_t *vec=(igraph_vector_t*) rec->value;
+      igraph_vector_destroy(vec);
+      igraph_Free(vec);
+    } else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
+      igraph_strvector_t *strvec=(igraph_strvector_t *)rec->value;
+      igraph_strvector_destroy(strvec);
+      igraph_Free(strvec);
+    }
+    igraph_free( (char*)(rec->name));
+    igraph_Free(rec);
+  }
+
+  for (i=0; i<igraph_vector_ptr_size(&eattrs); i++) {
+    igraph_attribute_record_t *rec=VECTOR(eattrs)[i];
+    if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_vector_t *vec=(igraph_vector_t*) rec->value;
+      igraph_vector_destroy(vec);
+      igraph_Free(vec);
+    } else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
+      igraph_strvector_t *strvec=(igraph_strvector_t *)rec->value;
+      igraph_strvector_destroy(strvec);
+      igraph_Free(strvec);
+    }
+    igraph_free( (char*)(rec->name));
+    igraph_Free(rec);
+  }
+
+  igraph_vector_destroy(&edges);  
+  igraph_vector_ptr_destroy(&eattrs);
+  igraph_trie_destroy(&eattrnames);
+  igraph_vector_ptr_destroy(&vattrs);
+  igraph_trie_destroy(&vattrnames);
+  igraph_pajek_yylex_destroy(context.scanner);
+
+  IGRAPH_FINALLY_CLEAN(7);
+  return 0;
+}
+
+/**
+ * \function igraph_read_graph_dimacs
+ * \brief Read a graph in DIMACS format.
+ * 
+ * This function reads the DIMACS file format, more specifically the 
+ * version for network flow problems, see the files at
+ * ftp://dimacs.rutgers.edu/pub/netflow/general-info/
+ * 
+ * </para><para>
+ * 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</code> the line is a comment line and it is
+ * ignored. There is one problem line (<code>p</code> 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>, <code>max</code> or <code>asn</code>), the
+ * number of vertices and number of edges in the graph.
+ * Exactly two node identification lines are expected
+ * (<code>n</code>), 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</code> (=source) or <code>t</code>
+ * (=target). Arc lines start with <code>a</code> and have three
+ * fields: the source vertex, the target vertex and the edge capacity.
+ * 
+ * </para><para>
+ * Vertex ids are numbered from 1.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream The file to read from.
+ * \param source Pointer to an integer, the id of the source node will
+ *    be stored here. (The igraph vertex id, which is one less than
+ *    the actual number in the file.) It is ignored if
+ *    <code>NULL</code>.
+ * \param target Pointer to an integer, the (igraph) id of the target
+ *    node will be stored here. It is ignored if <code>NULL</code>.
+ * \param capacity Pointer to an initialized vector, the capacity of
+ *    the edges will be stored here if not <code>NULL</code>.
+ * \param directed Boolean, whether to create a directed graph.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|+c), the number of vertices plus the
+ * number of edges, plus the size of the file in characters.
+ * 
+ * \sa \ref igraph_write_graph_dimacs()
+ */
+
+int igraph_read_graph_dimacs(igraph_t *graph, FILE *instream,
+			     igraph_strvector_t *problem,
+			     igraph_vector_t *label,
+			     igraph_integer_t *source, 
+			     igraph_integer_t *target,
+			     igraph_vector_t *capacity,			     
+			     igraph_bool_t directed) {
+  
+  igraph_vector_t edges;
+  long int no_of_nodes=-1;
+  long int no_of_edges=-1;
+  long int tsource=-1;
+  long int ttarget=-1;
+  char prob[21];
+  char c;      
+  int problem_type=0;
+
+#define PROBLEM_EDGE  1
+#define PROBLEM_MAX   2  
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  if (capacity) {
+    igraph_vector_clear(capacity);
+  }
+  
+  while (!feof(instream)) {
+    int read;
+    char str[3];
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    read=fscanf(instream, "%2c", str);
+    if (feof(instream)) {
+      break;
+    }
+    if (read != 1) {
+      IGRAPH_ERROR("parsing dimacs file failed", IGRAPH_PARSEERROR);
+    }
+    switch (str[0]) {
+      long int tmp, tmp2;
+      long int from, to;
+      igraph_real_t cap;
+
+    case 'c':
+      /* comment */
+      break;
+
+    case 'p':
+      if (no_of_nodes != -1) {
+	IGRAPH_ERROR("reading dimacs file failed, double 'p' line", 
+		     IGRAPH_PARSEERROR);
+      }
+      read=fscanf(instream, "%20s %li %li", prob, 
+		  &no_of_nodes, &no_of_edges);
+      if (read != 3) {
+	IGRAPH_ERROR("reading dimacs file failed", IGRAPH_PARSEERROR);
+      }
+      if (!strcmp(prob, "edge")) {
+	/* edge list */
+	problem_type=PROBLEM_EDGE;
+	if (label) {
+	  long int i;
+	  IGRAPH_CHECK(igraph_vector_resize(label, no_of_nodes));
+	  for (i=0; i<no_of_nodes; i++) {
+	    VECTOR(*label)[i]=i+1;
+	  }
+	}
+      } else if (!strcmp(prob, "max")) {
+	/* maximum flow problem */
+	problem_type=PROBLEM_MAX;
+	if (capacity) {
+	  IGRAPH_CHECK(igraph_vector_reserve(capacity, no_of_edges));
+	}
+      } else {
+	IGRAPH_ERROR("Unknown problem type, should be 'edge' or 'max'",
+		     IGRAPH_PARSEERROR);
+      }
+      if (problem) {
+	igraph_strvector_clear(problem);
+	IGRAPH_CHECK(igraph_strvector_add(problem, prob));
+      }
+      IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+      break;
+
+    case 'n':
+      /* for MAX this is either the source or target vertex,
+	 for EDGE this is a vertex label */
+      if (problem_type == PROBLEM_MAX) {
+	str[0]='x';
+	read=fscanf(instream, "%li %1s", &tmp, str);
+	if (str[0]=='s') {
+	  if (tsource != -1) {
+	    IGRAPH_ERROR("reading dimacsfile: multiple source vertex line", 
+			 IGRAPH_PARSEERROR);
+	  } else {
+	    tsource=tmp;
+	  }
+	} else if (str[0]=='t') {
+	  if (ttarget != -1) {
+	    IGRAPH_ERROR("reading dimacsfile: multiple target vertex line", 
+			 IGRAPH_PARSEERROR);
+	  } else {
+	    ttarget=tmp;
+	  }
+	} else {
+	  IGRAPH_ERROR("invalid node descriptor line in dimacs file",
+		       IGRAPH_PARSEERROR);
+	}
+      } else {
+	read=fscanf(instream, "%li %li", &tmp, &tmp2);
+	if (label) {
+	  VECTOR(*label)[tmp]=tmp2;
+	}
+      }
+      
+      break;
+      
+    case 'a':
+      /* This is valid only for MAX, a weighted edge */
+      if (problem_type != PROBLEM_MAX) { 
+	IGRAPH_ERROR("'a' lines are allowed only in MAX problem files", 
+		     IGRAPH_PARSEERROR);
+      }
+      read=fscanf(instream, "%li %li %lf", &from, &to, &cap);
+      if (read != 3) {
+	IGRAPH_ERROR("reading dimacs file", IGRAPH_PARSEERROR);
+      }
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, from-1));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, to-1));
+      if (capacity) {
+	IGRAPH_CHECK(igraph_vector_push_back(capacity, cap));
+      }
+      break;
+      
+    case 'e':
+      /* Edge line, only in EDGE */
+      if (problem_type != PROBLEM_EDGE) {
+	IGRAPH_ERROR("'e' lines are allowed only in EDGE problem files",
+		     IGRAPH_PARSEERROR);
+      }
+      read=fscanf(instream, "%li %li", &from, &to);
+      if (read != 2) {
+	IGRAPH_ERROR("reading dimacs file", IGRAPH_PARSEERROR);
+      }
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, from-1));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, to-1));
+      break;
+
+    default:
+      IGRAPH_ERROR("unknown line type in dimacs file", IGRAPH_PARSEERROR);
+    }
+
+    /* Go to next line */
+    while (!feof(instream) && (c=(char) getc(instream)) != '\n') ;      
+  }
+
+  if (source) {
+    *source=(igraph_integer_t) tsource-1;
+  }
+  if (target) {
+    *target=(igraph_integer_t) ttarget-1;
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     directed));
+  igraph_vector_destroy(&edges);
+
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_read_graph_graphdb_getword(FILE *instream) {
+  int b1, b2;
+  unsigned char c1, c2;
+  b1 = fgetc(instream);
+  b2 = fgetc(instream);
+  if (b1 != EOF) {
+    c1=(unsigned char) b1; c2=(unsigned char) b2;
+    return c1 | (c2<<8);
+  } else {
+    return -1;
+  }
+}
+
+/**
+ * \function igraph_read_graph_graphdb
+ * \brief Read a graph in the binary graph database format.
+ * 
+ * This is a binary format, used in the graph database
+ * for isomorphism testing. From the (now defunct) graph database 
+ * homepage: 
+ * </para>
+ * 
+ * \blockquote <para>
+ * 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.</para>
+ * 
+ * <para>
+ * 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.</para> \endblockquote
+ * 
+ * <para>
+ * Only unlabelled graphs are implemented.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream The stream to read from.
+ * \param directed Logical scalar, whether to create a directed graph.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the 
+ * number of edges.
+ * 
+ * \example examples/simple/igraph_read_graph_graphdb.c
+ */
+
+int igraph_read_graph_graphdb(igraph_t *graph, FILE *instream, 
+			      igraph_bool_t directed) {
+  
+  igraph_vector_t edges;
+  long int nodes;
+  long int i, j;
+  igraph_bool_t end=0;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  nodes=igraph_i_read_graph_graphdb_getword(instream);
+  if (nodes<0) {
+    IGRAPH_ERROR("Can't read from file", IGRAPH_EFILE);
+  }
+  for (i=0; !end && i<nodes; i++) {
+    long int len=igraph_i_read_graph_graphdb_getword(instream);
+    if (len<0) {
+      end=1;
+      break;
+    }
+    for (j=0; ! end && j<len; j++) {
+      long int to=igraph_i_read_graph_graphdb_getword(instream);
+      if (to<0) {
+	end=1; 
+	break;
+      }
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
+    }
+  }
+
+  if (end) {
+    IGRAPH_ERROR("Truncated graphdb file", IGRAPH_EFILE);
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) nodes, 
+			     directed));
+  igraph_vector_destroy(&edges);
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+#include "foreign-gml-header.h"
+
+int igraph_gml_yylex_init_extra (igraph_i_gml_parsedata_t* user_defined,
+				void* scanner);
+int igraph_gml_yylex_destroy (void *scanner );
+int igraph_gml_yyparse (igraph_i_gml_parsedata_t* context);
+void igraph_gml_yyset_in  (FILE * in_str, void* yyscanner );
+
+void igraph_i_gml_destroy_attrs(igraph_vector_ptr_t **ptr) {  
+  long int i;
+  igraph_vector_ptr_t *vec;
+  for (i=0; i<3; i++) {
+    long int j;
+    vec=ptr[i];
+    for (j=0; j<igraph_vector_ptr_size(vec); j++) {
+      igraph_attribute_record_t *atrec=VECTOR(*vec)[j];
+      if (atrec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_vector_t *value=(igraph_vector_t*)atrec->value;
+	if (value != 0) {
+	  igraph_vector_destroy(value);
+	  igraph_Free(value);
+	}
+      } else {
+	igraph_strvector_t *value=(igraph_strvector_t*)atrec->value;
+	if (value != 0) {
+	  igraph_strvector_destroy(value);
+	  igraph_Free(value);
+	}
+      }
+      igraph_Free(atrec->name);
+      igraph_Free(atrec);
+    }
+    igraph_vector_ptr_destroy(vec);
+  }
+}
+
+igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, long int pos) {
+
+  igraph_real_t value=0.0;
+  int type=igraph_gml_tree_type(node, pos);
+  
+  switch (type) {
+  case IGRAPH_I_GML_TREE_INTEGER:
+    value=igraph_gml_tree_get_integer(node, pos);
+    break;
+  case IGRAPH_I_GML_TREE_REAL:
+    value=igraph_gml_tree_get_real(node, pos);
+    break;
+  default:
+    IGRAPH_ERROR("Internal error while parsing GML file", IGRAPH_FAILURE);
+    break;
+  }
+  
+  return value;
+}
+
+const char *igraph_i_gml_tostring(igraph_gml_tree_t *node, long int pos) {
+  
+  int type=igraph_gml_tree_type(node, pos);
+  char tmp[256];
+  const char *p=tmp;
+  long int i;
+  igraph_real_t d;
+
+  switch (type) {
+  case IGRAPH_I_GML_TREE_INTEGER:
+    i=igraph_gml_tree_get_integer(node, pos);
+    snprintf(tmp, sizeof(tmp)/sizeof(char), "%li", i);
+    break;
+  case IGRAPH_I_GML_TREE_REAL:
+    d=igraph_gml_tree_get_real(node, pos);
+    igraph_real_snprintf_precise(tmp, sizeof(tmp)/sizeof(char), d);
+    break;
+  case IGRAPH_I_GML_TREE_STRING:
+    p=igraph_gml_tree_get_string(node, pos);
+    break;
+  default:
+    break;
+  }
+
+  return p;
+}
+
+/**
+ * \function igraph_read_graph_gml
+ * \brief Read a graph in GML format.
+ * 
+ * GML is a simple textual format, see
+ * http://www.fim.uni-passau.de/en/fim/faculty/chairs/theoretische-informatik/projects.html for details.
+ * 
+ * </para><para>
+ * 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:
+ * \olist
+ * \oli Only <code>node</code> and <code>edge</code> 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. 
+ * \oli Top level attributes except for <code>Version</code> and the
+ *      first <code>graph</code> attribute are completely ignored.
+ * \oli Graph attributes except for <code>node</code> and
+ *      <code>edge</code> are completely ignored.
+ * \oli There is no maximum line length. 
+ * \oli There is no maximum keyword length.
+ * \oli Character entities in strings are not interpreted.
+ * \oli We allow <code>inf</code> (infinity) and <code>nan</code>
+ *      (not a number) as a real number. This is case insensitive, so
+ *      <code>nan</code>, <code>NaN</code> and <code>NAN</code> are equal.
+ * \endolist
+ * 
+ * </para><para> Please contact us if you cannot live with these
+ * limitations of the GML parser.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream The stream to read the GML file from. 
+ * \return Error code.
+ * 
+ * Time complexity: should be proportional to the length of the file.
+ * 
+ * \sa \ref igraph_read_graph_graphml() for a more modern format, 
+ * \ref igraph_write_graph_gml() for writing GML files.
+ * 
+ * \example examples/simple/gml.c
+ */
+
+int igraph_read_graph_gml(igraph_t *graph, FILE *instream) {
+  
+  long int i, p;
+  long int no_of_nodes=0, no_of_edges=0;
+  igraph_trie_t trie;
+  igraph_vector_t edges;
+  igraph_bool_t directed=IGRAPH_UNDIRECTED;
+  igraph_gml_tree_t *gtree;
+  long int gidx;
+  igraph_trie_t vattrnames;
+  igraph_trie_t eattrnames;
+  igraph_trie_t gattrnames;
+  igraph_vector_ptr_t gattrs=IGRAPH_VECTOR_PTR_NULL, 
+    vattrs=IGRAPH_VECTOR_PTR_NULL, eattrs=IGRAPH_VECTOR_PTR_NULL;
+  igraph_vector_ptr_t *attrs[3];
+  long int edgeptr=0;
+  igraph_i_gml_parsedata_t context;
+  
+  attrs[0]=&gattrs; attrs[1]=&vattrs; attrs[2]=&eattrs;
+  
+  context.eof=0;
+  context.tree=0;
+
+  igraph_gml_yylex_init_extra(&context, &context.scanner);
+  IGRAPH_FINALLY(igraph_gml_yylex_destroy, context.scanner);
+
+  igraph_gml_yyset_in(instream, context.scanner);
+
+  i=igraph_gml_yyparse(&context);
+  if (i != 0) {
+    if (context.errmsg) {
+      IGRAPH_ERROR(context.errmsg, IGRAPH_PARSEERROR);
+    } else {
+      IGRAPH_ERROR("Cannot read GML file", IGRAPH_PARSEERROR);
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  /* Check version, if present, integer and not '1' then ignored */
+  i=igraph_gml_tree_find(context.tree, "Version", 0);
+  if (i>=0 &&
+      igraph_gml_tree_type(context.tree, i)==IGRAPH_I_GML_TREE_INTEGER &&
+      igraph_gml_tree_get_integer(context.tree, i) != 1) {
+    igraph_gml_tree_destroy(context.tree);
+    IGRAPH_ERROR("Unknown GML version", IGRAPH_UNIMPLEMENTED);
+    /* RETURN HERE!!!! */
+  }
+  
+  /* get the graph */
+  gidx=igraph_gml_tree_find(context.tree, "graph", 0);
+  if (gidx==-1) {
+    IGRAPH_ERROR("No 'graph' object in GML file", IGRAPH_PARSEERROR);
+  }
+  if (igraph_gml_tree_type(context.tree, gidx) !=
+      IGRAPH_I_GML_TREE_TREE) {
+    IGRAPH_ERROR("Invalid type for 'graph' object in GML file", IGRAPH_PARSEERROR);
+  }
+  gtree=igraph_gml_tree_get_tree(context.tree, gidx);
+
+  IGRAPH_FINALLY(igraph_i_gml_destroy_attrs, &attrs);
+  igraph_vector_ptr_init(&gattrs, 0);
+  igraph_vector_ptr_init(&vattrs, 0);
+  igraph_vector_ptr_init(&eattrs, 0);
+
+  IGRAPH_TRIE_INIT_FINALLY(&trie, 0);
+  IGRAPH_TRIE_INIT_FINALLY(&vattrnames, 0);
+  IGRAPH_TRIE_INIT_FINALLY(&eattrnames, 0);
+  IGRAPH_TRIE_INIT_FINALLY(&gattrnames, 0);
+
+  /* Is is directed? */
+  i=igraph_gml_tree_find(gtree, "directed", 0);
+  if (i>=0 && igraph_gml_tree_type(gtree, i)==IGRAPH_I_GML_TREE_INTEGER) {
+    if (igraph_gml_tree_get_integer(gtree, i) == 1) {
+      directed=IGRAPH_DIRECTED;
+    }
+  }
+
+  /* Now we go over all objects in the graph and collect the attribute names and
+     types. Plus we collect node ids. We also do some checks. */
+  for (i=0; i<igraph_gml_tree_length(gtree); i++) {
+    long int j;
+    char cname[100];
+    const char *name=igraph_gml_tree_name(gtree, i);
+    if (!strcmp(name, "node")) {
+      igraph_gml_tree_t *node;
+      igraph_bool_t hasid;
+      no_of_nodes++;
+      if (igraph_gml_tree_type(gtree, i) != IGRAPH_I_GML_TREE_TREE) {
+	IGRAPH_ERROR("'node' is not a list", IGRAPH_PARSEERROR);
+      }
+      node=igraph_gml_tree_get_tree(gtree, i);
+      hasid=0;
+      for (j=0; j<igraph_gml_tree_length(node); j++) {
+	const char *name=igraph_gml_tree_name(node, j);
+	long int trieid, triesize=igraph_trie_size(&vattrnames);
+	IGRAPH_CHECK(igraph_trie_get(&vattrnames, name, &trieid));
+	if (trieid==triesize) {
+	  /* new attribute */
+	  igraph_attribute_record_t *atrec=igraph_Calloc(1, igraph_attribute_record_t);
+	  int type=igraph_gml_tree_type(node, j);
+	  if (!atrec) {
+	    IGRAPH_ERROR("Cannot read GML file", IGRAPH_ENOMEM);
+	  }
+	  IGRAPH_CHECK(igraph_vector_ptr_push_back(&vattrs, atrec));
+	  atrec->name=strdup(name);
+	  if (type==IGRAPH_I_GML_TREE_INTEGER || type==IGRAPH_I_GML_TREE_REAL) {
+	    atrec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+	  } else {
+	    atrec->type=IGRAPH_ATTRIBUTE_STRING;
+	  }
+	} else {
+	  /* already seen, should we update type? */
+	  igraph_attribute_record_t *atrec=VECTOR(vattrs)[trieid];
+	  int type1=atrec->type;
+	  int type2=igraph_gml_tree_type(node, j);
+	  if (type1==IGRAPH_ATTRIBUTE_NUMERIC && type2==IGRAPH_I_GML_TREE_STRING) {
+	    atrec->type=IGRAPH_ATTRIBUTE_STRING;
+	  }
+	}
+	/* check id */
+	if (!hasid && !strcmp(name, "id")) {
+	  long int id;
+	  if (igraph_gml_tree_type(node, j) != IGRAPH_I_GML_TREE_INTEGER) {
+	    IGRAPH_ERROR("Non-integer node id in GML file", IGRAPH_PARSEERROR);
+	  }
+	  id=igraph_gml_tree_get_integer(node, j);
+	  snprintf(cname, sizeof(cname)/sizeof(char)-1, "%li", id);
+	  IGRAPH_CHECK(igraph_trie_get(&trie, cname, &id));
+	  hasid=1;
+	}
+      }
+      if (!hasid) {
+	IGRAPH_ERROR("Node without 'id' while parsing GML file", IGRAPH_PARSEERROR);
+      }
+    } else if (!strcmp(name, "edge")) {
+      igraph_gml_tree_t *edge;
+      igraph_bool_t has_source=0, has_target=0;
+      no_of_edges++;
+      if (igraph_gml_tree_type(gtree, i) != IGRAPH_I_GML_TREE_TREE) {
+	IGRAPH_ERROR("'edge' is not a list", IGRAPH_PARSEERROR);
+      }
+      edge=igraph_gml_tree_get_tree(gtree, i);
+      has_source=has_target=0;
+      for (j=0; j<igraph_gml_tree_length(edge); j++) {
+	const char *name=igraph_gml_tree_name(edge, j);
+	if (!strcmp(name, "source")) {
+	  has_source=1;
+	  if (igraph_gml_tree_type(edge, j) != IGRAPH_I_GML_TREE_INTEGER) {
+	    IGRAPH_ERROR("Non-integer 'source' for an edge in GML file",
+			 IGRAPH_PARSEERROR);
+	  }
+	} else if (!strcmp(name, "target")) {
+	  has_target=1;
+	  if (igraph_gml_tree_type(edge, j) != IGRAPH_I_GML_TREE_INTEGER) {
+	    IGRAPH_ERROR("Non-integer 'source' for an edge in GML file",
+			 IGRAPH_PARSEERROR);
+	  }
+	} else {
+	  long int trieid, triesize=igraph_trie_size(&eattrnames);
+	  IGRAPH_CHECK(igraph_trie_get(&eattrnames, name, &trieid));
+	  if (trieid==triesize) {
+	    /* new attribute */
+	    igraph_attribute_record_t *atrec=igraph_Calloc(1, igraph_attribute_record_t);
+	    int type=igraph_gml_tree_type(edge, j);
+	    if (!atrec) {
+	      IGRAPH_ERROR("Cannot read GML file", IGRAPH_ENOMEM);
+	    }
+	    IGRAPH_CHECK(igraph_vector_ptr_push_back(&eattrs, atrec));
+	    atrec->name=strdup(name);
+	    if (type==IGRAPH_I_GML_TREE_INTEGER || type==IGRAPH_I_GML_TREE_REAL) {
+	      atrec->type=IGRAPH_ATTRIBUTE_NUMERIC;
+	    } else {
+	      atrec->type=IGRAPH_ATTRIBUTE_STRING;
+	    }
+	  } else {
+	    /* already seen, should we update type? */
+	    igraph_attribute_record_t *atrec=VECTOR(eattrs)[trieid];
+	    int type1=atrec->type;
+	    int type2=igraph_gml_tree_type(edge, j);
+	    if (type1==IGRAPH_ATTRIBUTE_NUMERIC && type2==IGRAPH_I_GML_TREE_STRING) {
+	      atrec->type=IGRAPH_ATTRIBUTE_STRING;
+	    }
+	  }
+	}
+      }	/* for */
+      if (!has_source) {
+	IGRAPH_ERROR("No 'source' for edge in GML file", IGRAPH_PARSEERROR);
+      }
+      if (!has_target) {
+	IGRAPH_ERROR("No 'target' for edge in GML file", IGRAPH_PARSEERROR);
+      }
+    } else {
+      /* anything to do? Maybe add as graph attribute.... */
+    }
+  }
+
+  /* check vertex id uniqueness */
+  if (igraph_trie_size(&trie) != no_of_nodes) {
+    IGRAPH_ERROR("Node 'id' not unique", IGRAPH_PARSEERROR);
+  }
+  
+  /* now we allocate the vectors and strvectors for the attributes */
+  for (i=0; i<igraph_vector_ptr_size(&vattrs); i++) {
+    igraph_attribute_record_t *atrec=VECTOR(vattrs)[i];
+    int type=atrec->type;
+    if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
+      atrec->value=p;
+      IGRAPH_CHECK(igraph_vector_init(p, no_of_nodes));
+    } else if (type == IGRAPH_ATTRIBUTE_STRING) {
+      igraph_strvector_t *p=igraph_Calloc(1, igraph_strvector_t);
+      atrec->value=p;
+      IGRAPH_CHECK(igraph_strvector_init(p, no_of_nodes));
+    } else {
+      IGRAPH_WARNING("A composite attribute ignored");
+    }
+  }
+
+  for (i=0; i<igraph_vector_ptr_size(&eattrs); i++) {
+    igraph_attribute_record_t *atrec=VECTOR(eattrs)[i];
+    int type=atrec->type;
+    if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
+      atrec->value=p;
+      IGRAPH_CHECK(igraph_vector_init(p, no_of_edges));
+    } else if (type == IGRAPH_ATTRIBUTE_STRING) {
+      igraph_strvector_t *p=igraph_Calloc(1, igraph_strvector_t);
+      atrec->value=p;
+      IGRAPH_CHECK(igraph_strvector_init(p, no_of_edges));
+    } else {
+      IGRAPH_WARNING("A composite attribute ignored");
+    }
+  }
+
+  /* Ok, now the edges, attributes too */
+  IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*2));
+  p=-1;
+  while ( (p=igraph_gml_tree_find(gtree, "edge", p+1)) != -1) {
+    igraph_gml_tree_t *edge;
+    long int from, to, fromidx=0, toidx=0;
+    char name[100];
+    long int j;
+    edge=igraph_gml_tree_get_tree(gtree, p);
+    for (j=0; j<igraph_gml_tree_length(edge); j++) {
+      const char *n=igraph_gml_tree_name(edge, j);
+      if (!strcmp(n, "source")) {
+	fromidx=igraph_gml_tree_find(edge, "source", 0);
+      } else if (!strcmp(n, "target")) {
+	toidx=igraph_gml_tree_find(edge, "target", 0);
+      } else {
+	long int edgeid=edgeptr/2;
+	long int trieidx;
+	igraph_attribute_record_t *atrec;
+	int type;
+	igraph_trie_get(&eattrnames, n, &trieidx);
+	atrec=VECTOR(eattrs)[trieidx];
+	type=atrec->type;
+	if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	  igraph_vector_t *v=(igraph_vector_t *)atrec->value;
+	  VECTOR(*v)[edgeid]=igraph_i_gml_toreal(edge, j);
+	} else if (type==IGRAPH_ATTRIBUTE_STRING) {
+	  igraph_strvector_t *v=(igraph_strvector_t *)atrec->value;
+	  const char *value=igraph_i_gml_tostring(edge, j);
+	  IGRAPH_CHECK(igraph_strvector_set(v, edgeid, value));
+	}
+      }
+    }
+    from=igraph_gml_tree_get_integer(edge, fromidx);
+    to=igraph_gml_tree_get_integer(edge, toidx);
+    snprintf(name, sizeof(name)/sizeof(char)-1, "%li", from);
+    IGRAPH_CHECK(igraph_trie_get(&trie, name, &from));
+    snprintf(name, sizeof(name)/sizeof(char)-1, "%li", to);
+    IGRAPH_CHECK(igraph_trie_get(&trie, name, &to));
+    if (igraph_trie_size(&trie) != no_of_nodes) {
+      IGRAPH_ERROR("Unknown node id found at an edge", IGRAPH_PARSEERROR);
+    }
+    VECTOR(edges)[edgeptr++]=from;
+    VECTOR(edges)[edgeptr++]=to;
+  }
+
+  /* and add vertex attributes */
+  for (i=0; i<igraph_gml_tree_length(gtree); i++) {
+    const char *n;
+    char name[100];
+    long int j, k;
+    n=igraph_gml_tree_name(gtree, i);
+    if (!strcmp(n, "node")) {
+      igraph_gml_tree_t *node=igraph_gml_tree_get_tree(gtree, i);
+      long int iidx=igraph_gml_tree_find(node, "id", 0);
+      long int id=igraph_gml_tree_get_integer(node, iidx);
+      snprintf(name, sizeof(name)/sizeof(char)-1, "%li", id);
+      igraph_trie_get(&trie, name, &id);
+      for (j=0; j<igraph_gml_tree_length(node); j++) {
+	const char *aname=igraph_gml_tree_name(node, j);
+	igraph_attribute_record_t *atrec;
+	int type;
+	igraph_trie_get(&vattrnames, aname, &k);
+	atrec=VECTOR(vattrs)[k];
+	type=atrec->type;
+	if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	  igraph_vector_t *v=(igraph_vector_t *)atrec->value;
+	  VECTOR(*v)[id]=igraph_i_gml_toreal(node, j);
+	} else if (type==IGRAPH_ATTRIBUTE_STRING) {
+	  igraph_strvector_t *v=(igraph_strvector_t *)atrec->value;
+	  const char *value=igraph_i_gml_tostring(node, j);
+	  IGRAPH_CHECK(igraph_strvector_set(v, id, value));
+	}
+      }
+    }
+  }
+  
+  igraph_gml_tree_destroy(context.tree);
+  
+  igraph_trie_destroy(&trie);
+  igraph_trie_destroy(&gattrnames);
+  igraph_trie_destroy(&vattrnames);
+  igraph_trie_destroy(&eattrnames);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  IGRAPH_CHECK(igraph_empty_attrs(graph, 0, directed, 0)); /* TODO */
+  IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) no_of_nodes,
+				   &vattrs));
+  IGRAPH_CHECK(igraph_add_edges(graph, &edges, &eattrs));
+
+  igraph_i_gml_destroy_attrs(attrs);
+  igraph_vector_destroy(&edges);
+  igraph_gml_yylex_destroy(context.scanner);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/**
+ * \ingroup loadsave
+ * \function igraph_write_graph_edgelist
+ * \brief Writes the edge list of a graph to a file.
+ * 
+ * </para><para>
+ * One edge is written per line, separated by a single space.
+ * For directed graphs edges are written in from, to order.
+ * \param graph The graph object to write.
+ * \param outstream Pointer to a stream, it should be writable.
+ * \return Error code:
+ *         \c IGRAPH_EFILE if there is an error writing the
+ *         file. 
+ * 
+ * Time complexity: O(|E|), the
+ * number of edges in the  graph. It is assumed that writing an
+ * integer to the file requires O(1)
+ * time. 
+ */
+
+int igraph_write_graph_edgelist(const igraph_t *graph, FILE *outstream) {
+
+  igraph_eit_t it;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM), 
+				 &it));
+  IGRAPH_FINALLY(igraph_eit_destroy, &it);
+
+  while (!IGRAPH_EIT_END(it)) {
+    igraph_integer_t from, to;
+    int ret;
+    igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
+    ret=fprintf(outstream, "%li %li\n", 
+		(long int) from,
+		(long int) to);
+    if (ret < 0) {
+      IGRAPH_ERROR("Write error", IGRAPH_EFILE);
+    }
+    IGRAPH_EIT_NEXT(it);
+  }
+  
+  igraph_eit_destroy(&it);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/** 
+ * \ingroup loadsave
+ * \function igraph_write_graph_ncol
+ * \brief Writes the graph to a file in <code>.ncol</code> format
+ * 
+ * </para><para>
+ * <code>.ncol</code> is a format used by LGL, see \ref
+ * igraph_read_graph_ncol() for details. 
+ * 
+ * </para><para>
+ * Note that having multiple or loop edges in an
+ * <code>.ncol</code> file breaks the  LGL software but 
+ * \a igraph does not check for this condition. 
+ * \param graph The graph to write.
+ * \param outstream The stream object to write to, it should be
+ *        writable.
+ * \param names The name of the vertex attribute, if symbolic names
+ *        are written to the file. If not, supply 0 here.
+ * \param weights The name of the edge attribute, if they are also
+ *        written to the file. If you don't want weights, supply 0
+ *        here.
+ * \return Error code:
+ *         \c IGRAPH_EFILE if there is an error writing the
+ *         file. 
+ * 
+ * Time complexity: O(|E|), the
+ * number of edges. All file operations are expected to have time
+ * complexity O(1). 
+ *
+ * \sa \ref igraph_read_graph_ncol(), \ref igraph_write_graph_lgl()
+ */
+
+int igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, 
+			    const char *names, const char *weights) {
+  igraph_eit_t it;
+  igraph_attribute_type_t nametype, weighttype;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM), 
+				 &it));
+  IGRAPH_FINALLY(igraph_eit_destroy, &it);
+
+  /* Check if we have the names attribute */
+  if (names && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
+					    names)) {
+    names=0;
+    IGRAPH_WARNING("names attribute does not exists");
+  } 
+  if (names) {
+    IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &nametype,
+					    IGRAPH_ATTRIBUTE_VERTEX, names));
+  }
+  if (names && nametype != IGRAPH_ATTRIBUTE_NUMERIC && 
+      nametype != IGRAPH_ATTRIBUTE_STRING) {
+    IGRAPH_WARNING("ignoring names attribute, unknown attribute type");
+    names=0;
+  }
+
+  /* Check the weights as well */
+  if (weights && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
+					       weights)) {
+    weights=0;
+    IGRAPH_WARNING("weights attribute does not exists");
+  }
+  if (weights) {
+    IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &weighttype, 
+					    IGRAPH_ATTRIBUTE_EDGE, weights));
+  }
+  if (weights && weighttype != IGRAPH_ATTRIBUTE_NUMERIC) {
+    IGRAPH_WARNING("ignoring weights attribute, unknown attribute type");
+    weights=0;
+  }
+
+  if (names==0 && weights ==0) {
+    /* No names, no weights */
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t from, to;
+      int ret;
+      igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
+      ret=fprintf(outstream, "%li %li\n",
+		  (long int) from,
+		  (long int) to);
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+  } else if (weights==0) {
+    /* No weights, but use names */
+    igraph_strvector_t nvec;
+    IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
+    IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names, 
+							   igraph_vss_all(),
+							   &nvec));
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t edge=IGRAPH_EIT_GET(it);
+      igraph_integer_t from, to;
+      int ret=0;
+      char *str1, *str2;
+      igraph_edge(graph, edge, &from, &to);
+      igraph_strvector_get(&nvec, from, &str1);
+      igraph_strvector_get(&nvec, to, &str2);
+      ret=fprintf(outstream, "%s %s\n", str1, str2);
+      if (ret<0) {
+        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_strvector_destroy(&nvec);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (names==0) {
+    /* No names but weights */
+    igraph_vector_t wvec;
+    IGRAPH_VECTOR_INIT_FINALLY(&wvec, igraph_ecount(graph));
+    IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, weights, 
+							 igraph_ess_all(IGRAPH_EDGEORDER_ID), 
+							 &wvec));
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t edge=IGRAPH_EIT_GET(it);
+      igraph_integer_t from, to;
+      int ret1, ret2, ret3;
+      igraph_edge(graph, edge, &from, &to);
+      ret1=fprintf(outstream, "%li %li ", 
+		   (long int)from, (long int)to);
+      ret2=igraph_real_fprintf_precise(outstream, VECTOR(wvec)[(long int)edge]);
+      ret3=fputc('\n', outstream);
+      if (ret1 < 0 || ret2 < 0 || ret3 == EOF) {
+        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);      
+    }
+    igraph_vector_destroy(&wvec);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    /* Both names and weights */
+    igraph_strvector_t nvec;
+	igraph_vector_t wvec;
+    IGRAPH_VECTOR_INIT_FINALLY(&wvec, igraph_ecount(graph));
+    IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
+    IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, weights, 
+							 igraph_ess_all(IGRAPH_EDGEORDER_ID), 
+							 &wvec));
+    IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names, 
+							   igraph_vss_all(),
+							   &nvec));
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t edge=IGRAPH_EIT_GET(it);
+      igraph_integer_t from, to;
+      int ret=0, ret2=0;
+      char *str1, *str2;
+      igraph_edge(graph, edge, &from, &to);
+      igraph_strvector_get(&nvec, from, &str1);
+      igraph_strvector_get(&nvec, to, &str2);
+      ret=fprintf(outstream, "%s %s ", str1, str2);
+      if (ret<0) {
+        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      ret=igraph_real_fprintf_precise(outstream, VECTOR(wvec)[(long int)edge]);
+      ret2=fputc('\n', outstream);
+      if (ret < 0 || ret2 == EOF) {
+        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_strvector_destroy(&nvec);
+    igraph_vector_destroy(&wvec);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  
+  igraph_eit_destroy(&it);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \ingroup loadsave
+ * \function igraph_write_graph_lgl
+ * \brief Writes the graph to a file in <code>.lgl</code> format
+ *
+ * </para><para>
+ * <code>.lgl</code> is a format used by LGL, see \ref
+ * igraph_read_graph_lgl() for details.
+ *
+ * </para><para>
+ * Note that having multiple or loop edges in an
+ * <code>.lgl</code> file breaks the  LGL software but \a igraph
+ * does not check for this condition. 
+ * \param graph The graph to write. 
+ * \param outstream The stream object to write to, it should be
+ *        writable.
+ * \param names The name of the vertex attribute, if symbolic names
+ *        are written to the file. If not supply 0 here.
+ * \param weights The name of the edge attribute, if they are also
+ *        written to the file. If you don't want weights supply 0
+ *        here.
+ * \param isolates Logical, if TRUE isolated vertices are also written
+ *        to the file. If FALSE they will be omitted.
+ * \return Error code:
+ *         \c IGRAPH_EFILE if there is an error
+ *         writing the file. 
+ *
+ * Time complexity: O(|E|), the
+ * number of edges if \p isolates is
+ * FALSE, O(|V|+|E|) otherwise. All
+ * file operations are expected to have time complexity 
+ * O(1). 
+ *
+ * \sa \ref igraph_read_graph_lgl(), \ref igraph_write_graph_ncol()
+ * 
+ * \example examples/simple/igraph_write_graph_lgl.c
+ */
+
+int igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream,
+			   const char *names, const char *weights,
+			   igraph_bool_t isolates) {
+  igraph_eit_t it;
+  long int actvertex=-1;
+  igraph_attribute_type_t nametype, weighttype;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
+				 &it));
+  IGRAPH_FINALLY(igraph_eit_destroy, &it);
+
+  /* Check if we have the names attribute */
+  if (names && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
+					    names)) {
+    names=0;
+    IGRAPH_WARNING("names attribute does not exists");
+  }
+  if (names) {
+    IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &nametype,
+					    IGRAPH_ATTRIBUTE_VERTEX, names));
+  }
+  if (names && nametype != IGRAPH_ATTRIBUTE_NUMERIC && 
+      nametype != IGRAPH_ATTRIBUTE_STRING) {
+    IGRAPH_WARNING("ignoring names attribute, unknown attribute type");
+    names=0;
+  }
+
+  /* Check the weights as well */
+  if (weights && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
+					      weights)) {
+    weights=0;
+    IGRAPH_WARNING("weights attribute does not exists");
+  }
+  if (weights) {
+    IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &weighttype,
+					    IGRAPH_ATTRIBUTE_EDGE, weights));
+  }
+  if (weights && weighttype != IGRAPH_ATTRIBUTE_NUMERIC && 
+      weighttype != IGRAPH_ATTRIBUTE_STRING) {
+    IGRAPH_WARNING("ignoring weights attribute, unknown attribute type");
+    weights=0;
+  }
+  
+  if (names==0 && weights==0) {
+    /* No names, no weights */
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t from, to;
+      int ret;
+      igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
+      if (from==actvertex) {
+	ret=fprintf(outstream, "%li\n", (long int)to);
+      } else {
+	actvertex=from;
+	ret=fprintf(outstream, "# %li\n%li\n", (long int)from, (long int)to);
+      }
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+  } else if (weights==0) {
+    /* No weights but use names */
+    igraph_strvector_t nvec;
+    IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
+    IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
+							   igraph_vss_all(),
+							   &nvec));
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t edge=IGRAPH_EIT_GET(it);
+      igraph_integer_t from, to;
+      int ret=0;
+      char *str1, *str2;
+      igraph_edge(graph, edge, &from, &to);
+      igraph_strvector_get(&nvec, to, &str2);
+
+      if (from==actvertex) {
+	ret=fprintf(outstream, "%s\n", str2);
+      } else {
+	actvertex=from;
+	igraph_strvector_get(&nvec, from, &str1);
+	ret=fprintf(outstream, "# %s\n%s\n", str1, str2);
+      }
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (names==0) {
+    igraph_strvector_t wvec;
+    IGRAPH_CHECK(igraph_strvector_init(&wvec, igraph_ecount(graph)));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &wvec);
+    IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, weights,
+							 igraph_ess_all(IGRAPH_EDGEORDER_ID),
+							 &wvec));
+    /* No names but weights */
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t edge=IGRAPH_EIT_GET(it);
+      igraph_integer_t from, to;
+      int ret=0;
+      char *str1;
+      igraph_edge(graph, edge, &from, &to);
+      igraph_strvector_get(&wvec, edge, &str1);
+      if (from==actvertex) {
+	ret=fprintf(outstream, "%li %s\n", (long)to, str1);
+      } else {
+	actvertex=from;
+	ret=fprintf(outstream, "# %li\n%li %s\n", (long)from, (long)to, str1);
+      }
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_strvector_destroy(&wvec);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    /* Both names and weights */
+    igraph_strvector_t nvec, wvec;
+    IGRAPH_CHECK(igraph_strvector_init(&wvec, igraph_ecount(graph)));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &wvec);
+    IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
+    IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, weights,
+							 igraph_ess_all(IGRAPH_EDGEORDER_ID),
+							 &wvec));
+    IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names, 
+							   igraph_vss_all(),
+							   &nvec));
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_integer_t edge=IGRAPH_EIT_GET(it);
+      igraph_integer_t from, to;
+      int ret=0;
+      char *str1, *str2, *str3;
+      igraph_edge(graph, edge, &from, &to);
+      igraph_strvector_get(&nvec, to, &str2);
+      igraph_strvector_get(&wvec, edge, &str3);
+      if (from==actvertex) {
+	ret=fprintf(outstream, "%s ", str2);
+      } else {
+	actvertex=from;
+	igraph_strvector_get(&nvec, from, &str1);
+	ret=fprintf(outstream, "# %s\n%s ", str1, str2);
+      }
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      ret=fprintf(outstream, "%s\n", str3);
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_strvector_destroy(&nvec);
+    igraph_strvector_destroy(&wvec);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  if (isolates) {
+    long int nov=igraph_vcount(graph);
+    long int i;
+    int ret=0;
+    igraph_vector_t deg;
+    igraph_strvector_t nvec;
+    char *str;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&deg, 1);
+    IGRAPH_CHECK(igraph_strvector_init(&nvec, 1));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
+    for (i=0; i<nov; i++) {
+      igraph_degree(graph, &deg, igraph_vss_1((igraph_integer_t) i), 
+		    IGRAPH_ALL, IGRAPH_LOOPS);
+      if (VECTOR(deg)[0]==0) {
+ 	if (names==0) { 
+	  ret=fprintf(outstream, "# %li\n", i);
+	} else {
+	  IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
+				 igraph_vss_1((igraph_integer_t) i), &nvec));
+	  igraph_strvector_get(&nvec, 0, &str);
+	  ret=fprintf(outstream, "# %s\n", str);
+	}
+      }
+      if (ret<0) {
+	IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+      }
+    }
+    igraph_strvector_destroy(&nvec);
+    igraph_vector_destroy(&deg);
+    IGRAPH_FINALLY_CLEAN(2);
+  }  
+  
+  igraph_eit_destroy(&it);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/* Order matters here! */
+#define V_ID                0
+#define V_X                 1
+#define V_Y                 2
+#define V_Z                 3
+#define V_SHAPE             4
+#define V_XFACT             5
+#define V_YFACT             6
+#define V_COLOR_RED         7
+#define V_COLOR_GREEN       8
+#define V_COLOR_BLUE        9
+#define V_FRAMECOLOR_RED   10
+#define V_FRAMECOLOR_GREEN 11
+#define V_FRAMECOLOR_BLUE  12
+#define V_LABELCOLOR_RED   13
+#define V_LABELCOLOR_GREEN 14
+#define V_LABELCOLOR_BLUE  15
+#define V_LABELDIST        16
+#define V_LABELDEGREE2     17
+#define V_FRAMEWIDTH       18
+#define V_FONTSIZE         19
+#define V_ROTATION         20
+#define V_RADIUS           21
+#define V_DIAMONDRATIO     22
+#define V_LABELDEGREE      23
+#define V_VERTEXSIZE       24
+#define V_FONT             25
+#define V_URL              26
+#define V_COLOR            27
+#define V_FRAMECOLOR       28
+#define V_LABELCOLOR       29
+#define V_LAST             30
+
+#define E_WEIGHT            0
+#define E_COLOR_RED         1
+#define E_COLOR_GREEN       2
+#define E_COLOR_BLUE        3
+#define E_ARROWSIZE         4
+#define E_EDGEWIDTH         5
+#define E_HOOK1             6
+#define E_HOOK2             7
+#define E_ANGLE1            8
+#define E_ANGLE2            9
+#define E_VELOCITY1        10
+#define E_VELOCITY2        11
+#define E_ARROWPOS         12
+#define E_LABELPOS         13
+#define E_LABELANGLE       14
+#define E_LABELANGLE2      15
+#define E_LABELDEGREE      16
+#define E_FONTSIZE         17
+#define E_ARROWTYPE        18
+#define E_LINEPATTERN      19
+#define E_LABEL            20
+#define E_LABELCOLOR       21
+#define E_COLOR            22
+#define E_LAST             23
+
+int igraph_i_pajek_escape(char* src, char** dest) {
+  long int destlen=0;
+  igraph_bool_t need_escape=0;
+
+  /* Determine whether the string contains characters to be escaped */
+  char *s, *d;
+  for (s=src; *s; s++, destlen++) {
+    if (*s == '\\') {
+      need_escape = 1;
+      destlen++;
+    } else if (*s == '"') {
+      need_escape = 1;
+      destlen++;
+    } else if (!isalnum(*s)) {
+      need_escape = 1;
+    }
+  }
+
+  if (!need_escape) {
+    /* At this point, we know that the string does not contain any chars
+     * that would warrant escaping. Therefore, we simply quote it and
+     * return the quoted string. This is necessary because Pajek uses some
+     * reserved words in its format (like 'c' standing for color) and they
+     * have to be quoted as well.
+     */
+    *dest=igraph_Calloc(destlen+3, char);
+    if (!*dest)
+      IGRAPH_ERROR("Not enough memory", IGRAPH_ENOMEM);
+
+    d = *dest;
+    strcpy(d+1, src);
+    d[0] = d[destlen+1] = '"';
+    d[destlen+2] = 0;
+    return IGRAPH_SUCCESS;
+  }
+
+  *dest=igraph_Calloc(destlen+3, char);
+  if (!*dest)
+    IGRAPH_ERROR("Not enough memory", IGRAPH_ENOMEM);
+
+  d=*dest;
+  *d='"'; d++;
+
+  for (s=src; *s; s++, d++) {
+    switch (*s) {
+    case '\\':
+    case '"':
+      *d = '\\'; d++;
+    default:
+      *d = *s;
+    }
+  }
+  *d='"'; d++; *d=0;
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_write_graph_pajek
+ * \brief Writes a graph to a file in Pajek format.
+ * 
+ * </para><para>
+ * The Pajek vertex and edge parameters (like color) are determined by
+ * the attributes of the vertices and edges, of course this requires
+ * an attribute handler to be installed. The names of the
+ * corresponding vertex and edge attributes are listed at \ref
+ * igraph_read_graph_pajek(), eg. the `\c color' vertex attributes
+ * determines the color (`\c c' in Pajek) parameter.
+ * 
+ * </para><para>
+ * As of version 0.6.1 igraph writes bipartite graphs into Pajek files
+ * correctly, i.e. they will be also bipartite when read into Pajek. 
+ * As Pajek is less flexible for bipartite graphs (the numeric ids of 
+ * 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.
+ * \param graph The graph object to write.
+ * \param outstream The file to write to. It should be opened and
+ * writable. Make sure that you open the file in binary format if you use MS Windows,
+ * otherwise end of line characters will be messed up. (igraph will be able
+ * to read back these messed up files, but Pajek won't.)
+ * \return Error code.
+ *
+ * Time complexity: O(|V|+|E|+|A|), |V| is the number of vertices, |E|
+ * is the number of edges, |A| the number of attributes (vertex +
+ * edge) in the graph if there are attribute handlers installed. 
+ *
+ * \sa \ref igraph_read_graph_pajek() for reading Pajek graphs, \ref
+ * igraph_write_graph_graphml() for writing a graph in GraphML format,
+ * this suites <command>igraph</command> graphs better.
+ * 
+ * \example examples/simple/igraph_write_graph_pajek.c
+ */
+
+int igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, j;
+
+  igraph_attribute_type_t vtypes[V_LAST], etypes[E_LAST];
+  igraph_bool_t write_vertex_attrs=0;  
+
+  /* Same order as the #define's */
+  const char *vnames[] = { "id", "x", "y", "z", "shape", "xfact", "yfact",
+			   "", "", "", "", "", "", "", "", "", 
+			   "labeldist", "labeldegree2", "framewidth",
+			   "fontsize", "rotation", "radius", 
+			   "diamondratio", "labeldegree", "vertexsize", 
+			   "font", "url", "color", "framecolor",
+			   "labelcolor" };
+
+  const char *vnumnames[] = { "xfact", "yfact", "labeldist", 
+			      "labeldegree2", "framewidth", "fontsize",
+			      "rotation", "radius", "diamondratio",
+			      "labeldegree", "vertexsize" };
+  const char *vnumnames2[]= { "x_fact", "y_fact", "lr", "lphi", "bw",
+			      "fos", "phi", "r", "q", "la", "size" };
+  const char *vstrnames[] = { "font", "url", "color", "framecolor", 
+			      "labelcolor" };
+  const char *vstrnames2[]= { "font", "url", "ic", "bc", "lc" };  
+  
+  const char *enames[] = { "weight", "", "", "",
+			   "arrowsize", "edgewidth", "hook1", "hook2", 
+			   "angle1", "angle2", "velocity1", "velocity2",
+			   "arrowpos", "labelpos", "labelangle",
+			   "labelangle2", "labeldegree", "fontsize",
+			   "arrowtype", "linepattern", "label", "labelcolor",
+			   "color" };
+  const char *enumnames[] = { "arrowsize", "edgewidth", "hook1", "hook2",
+			      "angle1", "angle2", "velocity1", "velocity2", 
+			      "arrowpos", "labelpos", "labelangle",
+			      "labelangle2", "labeldegree", "fontsize" };
+  const char *enumnames2[]= { "s", "w", "h1", "h2", "a1", "a2", "k1", "k2", 
+			      "ap", "lp", "lr", "lphi", "la", "fos" };
+  const char *estrnames[] = { "arrowtype", "linepattern", "label",
+			      "labelcolor", "color" };
+  const char *estrnames2[]= { "a", "p", "l", "lc", "c" };
+
+  const char *newline="\x0d\x0a";
+  
+  igraph_es_t es;
+  igraph_eit_t eit;
+
+  igraph_vector_t numv;
+  igraph_strvector_t strv;
+
+  igraph_vector_t ex_numa;
+  igraph_vector_t ex_stra;
+  igraph_vector_t vx_numa;
+  igraph_vector_t vx_stra;
+  
+  char *s, *escaped;
+  
+  igraph_bool_t bipartite=0;
+  igraph_vector_int_t bip_index, bip_index2;
+  igraph_vector_bool_t bvec;
+  long int notop=0, nobottom=0;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&ex_numa, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&ex_stra, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vx_numa, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vx_stra, 0);
+
+  /* Check if graph is bipartite */
+  if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, "type")) {
+    igraph_attribute_type_t type_type;
+    igraph_i_attribute_gettype(graph, &type_type, IGRAPH_ATTRIBUTE_VERTEX,
+			       "type");
+    if (type_type == IGRAPH_ATTRIBUTE_BOOLEAN) {
+      int bptr=0, tptr=0;
+      bipartite = 1; write_vertex_attrs = 1;
+      /* Count top and bottom vertices, we go over them twice, 
+	 because we want to keep their original order */
+      IGRAPH_CHECK(igraph_vector_int_init(&bip_index, no_of_nodes));
+      IGRAPH_FINALLY(igraph_vector_int_destroy, &bip_index);
+      IGRAPH_CHECK(igraph_vector_int_init(&bip_index2, no_of_nodes));
+      IGRAPH_FINALLY(igraph_vector_int_destroy, &bip_index2);
+      IGRAPH_CHECK(igraph_vector_bool_init(&bvec, 1));
+      IGRAPH_FINALLY(igraph_vector_bool_destroy, &bvec);
+      for (i=0; i<no_of_nodes; i++) {
+	IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, 
+		     "type", igraph_vss_1((igraph_integer_t) i), &bvec));
+	if (VECTOR(bvec)[0]) { 
+	  notop++; 
+	} else {
+	  nobottom++;
+	}
+      }
+      for (i=0, bptr=0, tptr=(int) nobottom; i<no_of_nodes; i++) {
+	IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, 
+		     "type", igraph_vss_1((igraph_integer_t) i), &bvec));
+	if (VECTOR(bvec)[0]) { 
+	  VECTOR(bip_index)[tptr] = (int) i;
+	  VECTOR(bip_index2)[i] = tptr;
+	  tptr++;
+	} else {
+	  VECTOR(bip_index)[bptr] = (int) i;
+	  VECTOR(bip_index2)[i] = bptr;
+	  bptr++;
+	}
+      }
+      igraph_vector_bool_destroy(&bvec);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  /* Write header */
+  if (bipartite) {
+    if (fprintf(outstream, "*Vertices %li %li%s", no_of_nodes, nobottom, 
+		newline) < 0) {
+      IGRAPH_ERROR("Cannot write pajek file", IGRAPH_EFILE);
+    }
+  } else {
+    if (fprintf(outstream, "*Vertices %li%s", no_of_nodes, newline) < 0) {
+      IGRAPH_ERROR("Cannot write pajek file", IGRAPH_EFILE);
+    }
+  }
+
+  /* Check the vertex attributes */
+  memset(vtypes, 0, sizeof(vtypes[0])*V_LAST);
+  for (i=0; i<V_LAST; i++) {
+    if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, 
+				    vnames[i])) { 
+      igraph_i_attribute_gettype(graph, &vtypes[i], IGRAPH_ATTRIBUTE_VERTEX, 
+				 vnames[i]);
+      write_vertex_attrs=1;
+    } else {
+      vtypes[i]=(igraph_attribute_type_t) -1;
+    }
+  }
+  for (i=0; i< (long int) (sizeof(vnumnames)/sizeof(const char*)); i++) {
+    igraph_attribute_type_t type;
+    if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, 
+				    vnumnames[i])) {
+      igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_VERTEX, 
+				 vnumnames[i]);
+      if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	IGRAPH_CHECK(igraph_vector_push_back(&vx_numa, i));
+      }
+    }
+  }
+  for (i=0; i< (long int) (sizeof(vstrnames)/sizeof(const char*)); i++) {
+    igraph_attribute_type_t type;
+    if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, 
+				    vstrnames[i])) {
+      igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_VERTEX, 
+				 vstrnames[i]);
+      if (type==IGRAPH_ATTRIBUTE_STRING) {
+	IGRAPH_CHECK(igraph_vector_push_back(&vx_stra, i));
+      }
+    }
+  }
+
+  /* Write vertices */
+  if (write_vertex_attrs) {
+    for (i=0; i<no_of_nodes; i++) {
+      long int id=bipartite ? VECTOR(bip_index)[i] : i;
+      
+      /* vertex id */
+      fprintf(outstream, "%li", i+1);
+      if (vtypes[V_ID] == IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_ID], 
+				   igraph_vss_1((igraph_integer_t) id), &numv);
+	fputs(" \"", outstream);
+	igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+	fputc('"', outstream);
+      } else if (vtypes[V_ID] == IGRAPH_ATTRIBUTE_STRING) {
+	igraph_i_attribute_get_string_vertex_attr(graph, vnames[V_ID],
+				  igraph_vss_1((igraph_integer_t) id), &strv);
+	igraph_strvector_get(&strv, 0, &s);
+	IGRAPH_CHECK(igraph_i_pajek_escape(s, &escaped));
+	fprintf(outstream, " %s", escaped);
+	igraph_Free(escaped);
+      } else {
+	fprintf(outstream, " \"%li\"", id+1);
+      }
+      
+      /* coordinates */
+      if (vtypes[V_X] == IGRAPH_ATTRIBUTE_NUMERIC &&
+	  vtypes[V_Y] == IGRAPH_ATTRIBUTE_NUMERIC) {
+	igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_X], 
+				   igraph_vss_1((igraph_integer_t) id), &numv);
+	fputc(' ', outstream);
+	igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+	igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_Y], 
+				   igraph_vss_1((igraph_integer_t) id), &numv);
+	fputc(' ', outstream);
+	igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+	if (vtypes[V_Z] == IGRAPH_ATTRIBUTE_NUMERIC) {
+	  igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_Z], 
+				   igraph_vss_1((igraph_integer_t) id), &numv);
+	  fputc(' ', outstream);
+	  igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+	}
+      }
+      
+      /* shape */
+      if (vtypes[V_SHAPE] == IGRAPH_ATTRIBUTE_STRING) {
+	igraph_i_attribute_get_string_vertex_attr(graph, vnames[V_SHAPE],
+				  igraph_vss_1((igraph_integer_t) id), &strv);
+	igraph_strvector_get(&strv, 0, &s);
+	IGRAPH_CHECK(igraph_i_pajek_escape(s, &escaped));
+	fprintf(outstream, " %s", escaped);
+	igraph_Free(escaped);
+      }
+      
+      /* numeric parameters */
+      for (j=0; j<igraph_vector_size(&vx_numa); j++) {
+	int idx=(int) VECTOR(vx_numa)[j];
+	igraph_i_attribute_get_numeric_vertex_attr(graph, vnumnames[idx],
+				   igraph_vss_1((igraph_integer_t) id), &numv);
+	fprintf(outstream, " %s ", vnumnames2[idx]);
+	igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+      }
+
+      /* string parameters */
+      for (j=0; j<igraph_vector_size(&vx_stra); j++) {
+	int idx=(int) VECTOR(vx_stra)[j];
+	igraph_i_attribute_get_string_vertex_attr(graph, vstrnames[idx],
+				  igraph_vss_1((igraph_integer_t) id), &strv);
+	igraph_strvector_get(&strv, 0, &s);
+	IGRAPH_CHECK(igraph_i_pajek_escape(s, &escaped));
+	fprintf(outstream, " %s %s", vstrnames2[idx], escaped);
+	igraph_Free(escaped);
+      }      
+      
+      /* trailing newline */
+      fprintf(outstream, "%s", newline);
+    }
+  }
+
+  /* edges header */
+  if (igraph_is_directed(graph)) {
+    fprintf(outstream, "*Arcs%s", newline);
+  } else {
+    fprintf(outstream, "*Edges%s", newline);
+  }
+  
+  IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
+  IGRAPH_FINALLY(igraph_es_destroy, &es);
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+  /* Check edge attributes */
+  for (i=0; i<E_LAST; i++) {
+    if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
+				    enames[i])) {
+      igraph_i_attribute_gettype(graph, &etypes[i], IGRAPH_ATTRIBUTE_EDGE,
+				 enames[i]);
+    } else {
+      etypes[i]=(igraph_attribute_type_t) -1;
+    }
+  }
+  for (i=0; i< (long int) (sizeof(enumnames)/sizeof(const char*)); i++) {
+    igraph_attribute_type_t type;
+    if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, 
+				    enumnames[i])) {
+      igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_EDGE, 
+				 enumnames[i]);
+      if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	IGRAPH_CHECK(igraph_vector_push_back(&ex_numa, i));
+      }
+    }
+  }
+  for (i=0; i< (long int) (sizeof(estrnames)/sizeof(const char*)); i++) {
+    igraph_attribute_type_t type;
+    if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, 
+				    estrnames[i])) {
+      igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_EDGE, 
+				 estrnames[i]);
+      if (type==IGRAPH_ATTRIBUTE_STRING) {
+	IGRAPH_CHECK(igraph_vector_push_back(&ex_stra, i));
+      }
+    }
+  }
+  
+  for (i=0; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) {
+    long int edge=IGRAPH_EIT_GET(eit);
+    igraph_integer_t from, to;
+    igraph_edge(graph, (igraph_integer_t) edge, &from,  &to);
+    if (bipartite) { 
+      from=VECTOR(bip_index2)[from];
+      to  =VECTOR(bip_index2)[to];
+    }
+    fprintf(outstream, "%li %li", (long int) from+1, (long int) to+1);
+    
+    /* Weights */
+    if (etypes[E_WEIGHT] == IGRAPH_ATTRIBUTE_NUMERIC) {
+      igraph_i_attribute_get_numeric_edge_attr(graph, enames[E_WEIGHT],
+			       igraph_ess_1((igraph_integer_t) edge), &numv);
+      fputc(' ', outstream);
+      igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+    }
+    
+    /* numeric parameters */
+    for (j=0; j<igraph_vector_size(&ex_numa); j++) {
+      int idx=(int) VECTOR(ex_numa)[j];
+      igraph_i_attribute_get_numeric_edge_attr(graph, enumnames[idx],
+			       igraph_ess_1((igraph_integer_t) edge), &numv);
+      fprintf(outstream, " %s ", enumnames2[idx]);
+      igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+    }
+    
+    /* string parameters */
+    for (j=0; j<igraph_vector_size(&ex_stra); j++) {
+      int idx=(int) VECTOR(ex_stra)[j];
+      igraph_i_attribute_get_string_edge_attr(graph, estrnames[idx],
+			      igraph_ess_1((igraph_integer_t) edge), &strv);
+      igraph_strvector_get(&strv, 0, &s);
+      IGRAPH_CHECK(igraph_i_pajek_escape(s, &escaped));
+      fprintf(outstream, " %s %s", estrnames2[idx], escaped);
+      igraph_Free(escaped);
+    }
+
+    /* trailing newline */
+    fprintf(outstream, "%s", newline);
+  }
+
+  igraph_eit_destroy(&eit);
+  igraph_es_destroy(&es);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (bipartite) {
+    igraph_vector_int_destroy(&bip_index2);
+    igraph_vector_int_destroy(&bip_index);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  igraph_vector_destroy(&ex_numa);
+  igraph_vector_destroy(&ex_stra);
+  igraph_vector_destroy(&vx_numa);
+  igraph_vector_destroy(&vx_stra);
+  igraph_strvector_destroy(&strv);
+  igraph_vector_destroy(&numv);
+  IGRAPH_FINALLY_CLEAN(6);
+  return 0;
+}
+
+/**
+ * \function igraph_write_graph_dimacs
+ * \brief Write a graph in DIMACS format.
+ * 
+ * This function writes a graph to an output stream in DIMACS format,
+ * describing a maximum flow problem.
+ * See ftp://dimacs.rutgers.edu/pub/netflow/general-info/
+ * 
+ * </para><para>
+ * This file format is discussed in the documentation of \ref
+ * igraph_read_graph_dimacs(), see that for more information.
+ * 
+ * \param graph The graph to write to the stream.
+ * \param outstream The stream.
+ * \param source Integer, the id of the source vertex for the maximum
+ *     flow. 
+ * \param target Integer, the id of the target vertex.
+ * \param capacity Pointer to an initialized vector containing the
+ *     edge capacity values.
+ * \return Error code.
+ * 
+ * Time complexity: O(|E|), the number of edges in the graph.
+ * 
+ * \sa igraph_read_graph_dimacs()
+ */
+
+int igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream,
+			      long int source, long int target,
+			      const igraph_vector_t *capacity) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_eit_t it;
+  long int i=0;
+  int ret, ret1, ret2, ret3;
+
+  if (igraph_vector_size(capacity) != no_of_edges) {
+    IGRAPH_ERROR("invalid capacity vector length", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID),
+				 &it));
+  IGRAPH_FINALLY(igraph_eit_destroy, &it);
+  
+  ret=fprintf(outstream, 
+	      "c created by igraph\np max %li %li\nn %li s\nn %li t\n",
+	      no_of_nodes, no_of_edges, source+1, target+1);
+  if (ret < 0) {
+    IGRAPH_ERROR("Write error", IGRAPH_EFILE);
+  }
+  
+
+  while (!IGRAPH_EIT_END(it)) {
+    igraph_integer_t from, to;
+	igraph_real_t cap;
+    igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
+    cap=VECTOR(*capacity)[i++];
+    ret1=fprintf(outstream, "a %li %li ",
+		(long int) from+1, (long int) to+1);
+    ret2=igraph_real_fprintf_precise(outstream, cap);
+    ret3=fputc('\n', outstream);
+    if (ret1 < 0 || ret2 < 0 || ret3==EOF) {
+      IGRAPH_ERROR("Write error", IGRAPH_EFILE);
+    }
+    IGRAPH_EIT_NEXT(it);
+  }
+  
+  igraph_eit_destroy(&it);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;  
+}
+
+int igraph_i_gml_convert_to_key(const char *orig, char **key) {
+  int no=1;
+  char strno[50];
+  size_t i, len = strlen(orig), newlen = 0, plen = 0;
+
+  /* do we need a prefix? */
+  if (len==0 || !isalpha(orig[0])) { 
+    no++;
+    snprintf(strno, sizeof(strno)-1, "igraph");
+    plen=newlen=strlen(strno);
+  }
+  for (i=0; i<len; i++) {
+    if (isalnum(orig[i])) { newlen++; }
+  }
+  *key=igraph_Calloc(newlen+1, char);
+  if (! *key) {
+    IGRAPH_ERROR("Writing GML file failed", IGRAPH_ENOMEM);
+  }
+  memcpy(*key, strno, plen*sizeof(char));
+  for (i=0; i<len; i++) {
+    if (isalnum(orig[i])) { 
+      (*key)[plen++] = orig[i];
+    }
+  }
+  (*key)[newlen]='\0';
+  
+  return 0;
+}
+
+#define CHECK(cmd) do { ret=cmd; if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE); } while (0)
+
+/** 
+ * \function igraph_write_graph_gml
+ * \brief Write the graph to a stream in GML format 
+ * 
+ * GML is a quite general textual format, see 
+ * http://www.fim.uni-passau.de/en/fim/faculty/chairs/theoretische-informatik/projects.html for details.
+ * 
+ * </para><para> The graph, vertex and edges attributes are written to the
+ * file as well, if they are numeric of string.
+ * 
+ * </para><para> As igraph is more forgiving about attribute names, it might 
+ * be necessary 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. 
+ * 
+ * </para><para> The <quote>id</quote> vertex attribute is treated specially. 
+ * If the <parameter>id</parameter> argument is not 0 then it should be a numeric 
+ * vector with the vertex ids and the <quote>id</quote> vertex attribute is 
+ * ignored (if there is one). If <parameter>id</parameter> is 0 and there is a 
+ * numeric <quote>id</quote> vertex attribute that is used instead. If ids
+ * are not specified in either way then the regular igraph vertex ids are used.
+ * 
+ * </para><para> Note that whichever way vertex ids are specified, their 
+ * uniqueness is not checked.
+ * 
+ * </para><para> If the graph has edge attributes named <quote>source</quote> 
+ * or <quote>target</quote> 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.
+ * \param graph The graph to write to the stream.
+ * \param outstream The stream to write the file to.
+ * \param id Either <code>NULL</code> or a numeric vector with the vertex ids.
+ *        See details above.
+ * \param creator An optional string to write to the stream in the creator line.
+ *        If this is 0 then the current date and time is added.
+ * \return Error code.
+ * 
+ * Time complexity: should be proportional to the number of characters written
+ * to the file.
+ * 
+ * \sa \ref igraph_read_graph_gml() for reading GML files, 
+ * \ref igraph_read_graph_graphml() for a more modern format.
+ * 
+ * \example examples/simple/gml.c
+ */
+
+int igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, 
+			   const igraph_vector_t *id, const char *creator) {
+  int ret;
+  igraph_strvector_t gnames, vnames, enames;
+  igraph_vector_t gtypes, vtypes, etypes;
+  igraph_vector_t numv;
+  igraph_strvector_t strv;
+  igraph_vector_bool_t boolv;
+  long int i;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+
+  igraph_vector_t v_myid;
+  const igraph_vector_t *myid=id;
+
+  time_t curtime=time(0);
+  char *timestr=ctime(&curtime);
+  timestr[strlen(timestr)-1]='\0'; /* nicely remove \n */
+  
+  CHECK(fprintf(outstream, 
+		"Creator \"igraph version %s %s\"\nVersion 1\ngraph\n[\n", 
+		PACKAGE_VERSION, creator ? creator : timestr));
+  
+  IGRAPH_STRVECTOR_INIT_FINALLY(&gnames, 0);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&vnames, 0);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&enames, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&gtypes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
+  IGRAPH_CHECK(igraph_i_attribute_get_info(graph, 
+					   &gnames, &gtypes,
+					   &vnames, &vtypes,
+					   &enames, &etypes));  
+
+  IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
+  IGRAPH_VECTOR_BOOL_INIT_FINALLY(&boolv, 1);
+
+  /* Check whether there is an 'id' node attribute if the supplied is 0 */
+  if (!id) {
+    igraph_bool_t found=0; 
+    for (i=0; i<igraph_vector_size(&vtypes); i++) {
+      char *n;
+      igraph_strvector_get(&vnames, i, &n);
+      if (!strcmp(n, "id") && VECTOR(vtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) { 
+	found=1; break; 
+      }
+    }
+    if (found) {
+      IGRAPH_VECTOR_INIT_FINALLY(&v_myid, no_of_nodes);
+      IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, "id", 
+							      igraph_vss_all(),
+							      &v_myid));
+      myid=&v_myid;
+    }
+  }      
+
+  /* directedness */
+  CHECK(fprintf(outstream, "  directed %i\n", igraph_is_directed(graph) ? 1 : 0));
+
+  /* Graph attributes first */
+  for (i=0; i<igraph_vector_size(&gtypes); i++) {
+    char *name, *newname;
+    igraph_strvector_get(&gnames, i, &name);
+    IGRAPH_CHECK(igraph_i_gml_convert_to_key(name, &newname));
+    if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+      IGRAPH_CHECK(igraph_i_attribute_get_numeric_graph_attr(graph, name, &numv));
+      CHECK(fprintf(outstream, "  %s ", newname));
+      CHECK(igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]));
+      CHECK(fputc('\n', outstream));
+    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+      char *s;
+      IGRAPH_CHECK(igraph_i_attribute_get_string_graph_attr(graph, name, &strv));
+      igraph_strvector_get(&strv, 0, &s);
+      CHECK(fprintf(outstream, "  %s \"%s\"\n", newname, s));
+    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+      IGRAPH_CHECK(igraph_i_attribute_get_bool_graph_attr(graph, name, &boolv));
+      CHECK(fprintf(outstream, "  %s %d\n", newname, VECTOR(boolv)[0] ? 1 : 0));
+      IGRAPH_WARNING("A boolean graph attribute was converted to numeric");
+    } else {
+      IGRAPH_WARNING("A non-numeric, non-string, non-boolean graph attribute ignored");
+    }
+    igraph_Free(newname);
+  } 
+  
+  /* Now come the vertices */
+  for (i=0; i<no_of_nodes; i++) {
+    long int j;
+    CHECK(fprintf(outstream, "  node\n  [\n"));
+    /* id */
+    CHECK(fprintf(outstream, "    id %li\n", myid ? (long int)VECTOR(*myid)[i] : i));
+    /* other attributes */
+    for (j=0; j<igraph_vector_size(&vtypes); j++) {
+      int type=(int) VECTOR(vtypes)[j];
+      char *name, *newname;
+      igraph_strvector_get(&vnames, j, &name);
+      if (!strcmp(name, "id")) { continue; }	
+      IGRAPH_CHECK(igraph_i_gml_convert_to_key(name, &newname));
+      if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, name, 
+				igraph_vss_1((igraph_integer_t) i), &numv));
+	CHECK(fprintf(outstream, "    %s ", newname));
+	CHECK(igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]));
+	CHECK(fputc('\n', outstream));
+      } else if (type==IGRAPH_ATTRIBUTE_STRING) { 
+	char *s;
+	IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, name,
+			       igraph_vss_1((igraph_integer_t) i), &strv));
+	igraph_strvector_get(&strv, 0, &s);
+	CHECK(fprintf(outstream, "    %s \"%s\"\n", newname, s));
+      } else if (type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+	IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, name,
+			     igraph_vss_1((igraph_integer_t) i), &boolv));
+	CHECK(fprintf(outstream, "    %s %d\n", newname, VECTOR(boolv)[0] ? 1 : 0));
+	IGRAPH_WARNING("A boolean vertex attribute was converted to numeric");
+      } else {
+	IGRAPH_WARNING("A non-numeric, non-string, non-boolean edge attribute was ignored");
+      }
+      igraph_Free(newname);
+    }
+    CHECK(fprintf(outstream, "  ]\n"));
+  }
+
+  /* The edges too */
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+    long int to=IGRAPH_TO(graph, i);
+    long int j;
+    CHECK(fprintf(outstream, "  edge\n  [\n"));
+    /* source and target */
+    CHECK(fprintf(outstream, "    source %li\n", 
+		  myid ? (long int)VECTOR(*myid)[from] : from));
+    CHECK(fprintf(outstream, "    target %li\n", 
+		  myid ? (long int)VECTOR(*myid)[to] : to));
+
+    /* other attributes */
+    for (j=0; j<igraph_vector_size(&etypes); j++) {
+      int type=(int) VECTOR(etypes)[j];
+      char *name, *newname;
+      igraph_strvector_get(&enames, j, &name);
+      if (!strcmp(name, "source") || !strcmp(name, "target")) { continue; }	
+      IGRAPH_CHECK(igraph_i_gml_convert_to_key(name, &newname));
+      if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
+	IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, name, 
+			      igraph_ess_1((igraph_integer_t) i), &numv));
+	CHECK(fprintf(outstream, "    %s ", newname));
+	CHECK(igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]));
+	CHECK(fputc('\n', outstream));
+      } else if (type==IGRAPH_ATTRIBUTE_STRING) { 
+	char *s;
+	IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, name,
+			     igraph_ess_1((igraph_integer_t) i), &strv));
+	igraph_strvector_get(&strv, 0, &s);
+	CHECK(fprintf(outstream, "    %s \"%s\"\n", newname, s));
+      } else if (type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+	IGRAPH_CHECK(igraph_i_attribute_get_bool_edge_attr(graph, name,
+			     igraph_ess_1((igraph_integer_t) i), &boolv));
+	CHECK(fprintf(outstream, "    %s %d\n", newname, VECTOR(boolv)[0] ? 1 : 0));
+	IGRAPH_WARNING("A boolean edge attribute was converted to numeric");
+      } else {
+	IGRAPH_WARNING("A non-numeric, non-string, non-boolean edge attribute was ignored");
+      }
+      igraph_Free(newname);
+    }
+    CHECK(fprintf(outstream, "  ]\n"));
+  }
+
+  CHECK(fprintf(outstream, "]\n"));
+
+  if (&v_myid == myid) { 
+    igraph_vector_destroy(&v_myid);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_bool_destroy(&boolv);
+  igraph_strvector_destroy(&strv);
+  igraph_vector_destroy(&numv);
+  igraph_vector_destroy(&etypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&gtypes);
+  igraph_strvector_destroy(&enames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&gnames);
+  IGRAPH_FINALLY_CLEAN(9);
+  
+  return 0;
+}
+
+int igraph_i_dot_escape(const char *orig, char **result) {
+  /* do we have to escape the string at all? */
+  long int i, j, len=(long int) strlen(orig), newlen=0;
+  igraph_bool_t need_quote=0, is_number=1;
+  for (i=0; i<len; i++) {
+	if (isdigit(orig[i])) { newlen++; }
+	else if (orig[i] == '-' && i==0) { newlen++; }
+	else if (orig[i] == '.') {
+	  if (is_number) { newlen++; }
+	  else { need_quote=1; newlen++; }
+	} else if (orig[i] == '_') {
+	  is_number=0; newlen++;
+	} else if (orig[i] == '\\' || orig[i] == '"' || orig[i] == '\n') {
+	  need_quote=1; is_number=0; newlen+=2; /* will be escaped */
+	} else if (isalpha(orig[i])) {
+	  is_number=0; newlen++;
+	} else {
+	  is_number=0; need_quote=1; newlen++;
+	}
+  }
+  if (is_number && orig[len-1] == '.') is_number=0;
+  if (!is_number && isdigit(orig[0])) need_quote=1;
+
+  if (is_number || !need_quote) {
+	*result=strdup(orig);
+	if (!*result) IGRAPH_ERROR("Writing DOT file failed", IGRAPH_ENOMEM);
+  } else {
+	*result=igraph_Calloc(newlen+3, char);
+	(*result)[0]='"';
+	(*result)[newlen+1]='"';
+	(*result)[newlen+2]='\0';
+	for (i=0, j=1; i<len; i++) {
+	  if (orig[i] == '\n') {
+		(*result)[j++] = '\\';
+		(*result)[j++] = 'n';
+		continue;
+	  }
+	  if (orig[i] == '\\' || orig[i] == '"') {
+		(*result)[j++] = '\\';
+	  }
+	  (*result)[j++] = orig[i];
+	}
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_write_graph_dot
+ * \brief Write the graph to a stream in DOT format
+ *
+ * DOT is the format used by the widely known GraphViz software, see
+ * http://www.graphviz.org for details. The grammar of the DOT format
+ * can be found here: http://www.graphviz.org/doc/info/lang.html
+ *
+ * </para><para>This is only a preliminary implementation, only the vertices
+ * and the edges are written but not the attributes or any visualization
+ * information.
+ *
+ * \param graph The graph to write to the stream.
+ * \param outstream The stream to write the file to.
+ *
+ * Time complexity: should be proportional to the number of characters written
+ * to the file.
+ * 
+ * \sa \ref igraph_write_graph_graphml() for a more modern format.
+ * 
+ * \example examples/simple/dot.c
+ */
+int igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) {
+  int ret;
+  long int i, j;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  char edgeop[3];
+  igraph_strvector_t gnames, vnames, enames;
+  igraph_vector_t gtypes, vtypes, etypes;
+  igraph_vector_t numv;
+  igraph_strvector_t strv;
+  igraph_vector_bool_t boolv;
+
+  IGRAPH_STRVECTOR_INIT_FINALLY(&gnames, 0);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&vnames, 0);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&enames, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&gtypes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
+  IGRAPH_CHECK(igraph_i_attribute_get_info(graph, 
+					   &gnames, &gtypes,
+					   &vnames, &vtypes,
+					   &enames, &etypes));  
+
+  IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
+  IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
+  IGRAPH_VECTOR_BOOL_INIT_FINALLY(&boolv, 1);
+
+  CHECK(fprintf(outstream, "/* Created by igraph %s */\n",
+	PACKAGE_VERSION));
+
+  if (igraph_is_directed(graph)) {
+	CHECK(fprintf(outstream, "digraph {\n"));
+	strcpy(edgeop, "->");
+  } else {
+	CHECK(fprintf(outstream, "graph {\n"));
+	strcpy(edgeop, "--");
+  }
+
+  /* Write the graph attributes */
+  if (igraph_vector_size(&gtypes)>0) {
+	CHECK(fprintf(outstream, "  graph [\n"));
+	for (i=0; i<igraph_vector_size(&gtypes); i++) {
+	  char *name, *newname;
+	  igraph_strvector_get(&gnames, i, &name);
+	  IGRAPH_CHECK(igraph_i_dot_escape(name, &newname));
+	  if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
+		IGRAPH_CHECK(igraph_i_attribute_get_numeric_graph_attr(graph, name, &numv));
+		if (VECTOR(numv)[0] == (long)VECTOR(numv)[0]) {
+		  CHECK(fprintf(outstream, "    %s=%ld\n", newname, (long)VECTOR(numv)[0]));
+		} else {
+		  CHECK(fprintf(outstream, "    %s=", newname));
+		  CHECK(igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]));
+		  CHECK(fputc('\n', outstream));
+		}
+	  } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
+		char *s, *news;
+		IGRAPH_CHECK(igraph_i_attribute_get_string_graph_attr(graph, name, &strv));
+		igraph_strvector_get(&strv, 0, &s);
+		IGRAPH_CHECK(igraph_i_dot_escape(s, &news));
+		CHECK(fprintf(outstream, "    %s=%s\n", newname, news));
+		igraph_Free(news);
+	  } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+		IGRAPH_CHECK(igraph_i_attribute_get_bool_graph_attr(graph, name, &boolv));
+		CHECK(fprintf(outstream, "    %s=%d\n", newname, VECTOR(boolv)[0] ? 1 : 0));
+		IGRAPH_WARNING("A boolean graph attribute was converted to numeric");
+	  } else {
+		IGRAPH_WARNING("A non-numeric, non-string, non-boolean graph attribute ignored");
+	  }
+	  igraph_Free(newname);
+	}
+	CHECK(fprintf(outstream, "  ];\n"));
+  }
+
+  /* Write the vertices */
+  if (igraph_vector_size(&vtypes) > 0) {
+	for (i=0; i<no_of_nodes; i++) {
+	  CHECK(fprintf(outstream, "  %ld [\n", i));
+	  for (j=0; j<igraph_vector_size(&vtypes); j++) {
+		char *name, *newname;
+		igraph_strvector_get(&vnames, j, &name);
+		IGRAPH_CHECK(igraph_i_dot_escape(name, &newname));
+		if (VECTOR(vtypes)[j] == IGRAPH_ATTRIBUTE_NUMERIC) {
+		  IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, name, igraph_vss_1((igraph_integer_t) i), &numv));
+		  if (VECTOR(numv)[0] == (long)VECTOR(numv)[0]) {
+			CHECK(fprintf(outstream, "    %s=%ld\n", newname, (long)VECTOR(numv)[0]));
+		  } else {
+		        CHECK(fprintf(outstream, "    %s=", newname));
+			CHECK(igraph_real_fprintf_precise(outstream, 
+						  VECTOR(numv)[0]));
+			CHECK(fputc('\n', outstream));
+		  }
+		} else if (VECTOR(vtypes)[j] == IGRAPH_ATTRIBUTE_STRING) {
+		  char *s, *news;
+		  IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, name, igraph_vss_1((igraph_integer_t) i), &strv));
+		  igraph_strvector_get(&strv, 0, &s);
+		  IGRAPH_CHECK(igraph_i_dot_escape(s, &news));
+		  CHECK(fprintf(outstream, "    %s=%s\n", newname, news));
+		  igraph_Free(news);
+                } else if (VECTOR(vtypes)[j] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+		  IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, name, igraph_vss_1((igraph_integer_t) i), &boolv));
+		  CHECK(fprintf(outstream, "    %s=%d\n", newname, VECTOR(boolv)[0] ? 1 : 0));
+		  IGRAPH_WARNING("A boolean vertex attribute was converted to numeric");
+		} else {
+		  IGRAPH_WARNING("A non-numeric, non-string, non-boolean vertex attribute was ignored");
+		}
+		igraph_Free(newname);
+	  }
+	  CHECK(fprintf(outstream, "  ];\n"));
+	}
+  } else {
+	for (i=0; i<no_of_nodes; i++)
+	  CHECK(fprintf(outstream, "  %ld;\n", i));
+  }
+  CHECK(fprintf(outstream, "\n"));
+
+  /* Write the edges */
+  if (igraph_vector_size(&etypes) > 0) {
+	for (i=0; i<no_of_edges; i++) {
+	  long int from=IGRAPH_FROM(graph, i);
+	  long int to=IGRAPH_TO(graph, i);
+	  CHECK(fprintf(outstream, "  %ld %s %ld [\n", from, edgeop, to));
+	  for (j=0; j<igraph_vector_size(&etypes); j++) {
+		char *name, *newname;
+		igraph_strvector_get(&enames, j, &name);
+		IGRAPH_CHECK(igraph_i_dot_escape(name, &newname));
+		if (VECTOR(etypes)[j] == IGRAPH_ATTRIBUTE_NUMERIC) {
+		  IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, 
+			name, igraph_ess_1((igraph_integer_t) i), &numv));
+		  if (VECTOR(numv)[0] == (long)VECTOR(numv)[0]) {
+			CHECK(fprintf(outstream, "    %s=%ld\n", newname, (long)VECTOR(numv)[0]));
+		  } else {
+		        CHECK(fprintf(outstream, "    %s=", newname));
+			CHECK(igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]));
+			CHECK(fputc('\n', outstream));
+		  }
+		  igraph_Free(newname);
+		} else if (VECTOR(etypes)[j] == IGRAPH_ATTRIBUTE_STRING) {
+		  char *s, *news;
+		  IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, 
+		       name, igraph_ess_1((igraph_integer_t) i), &strv));
+		  igraph_strvector_get(&strv, 0, &s);
+		  IGRAPH_CHECK(igraph_i_dot_escape(s, &news));
+		  CHECK(fprintf(outstream, "    %s=%s\n", newname, news));
+		  igraph_Free(newname);
+		  igraph_Free(news);
+                } else if (VECTOR(etypes)[j] == IGRAPH_ATTRIBUTE_BOOLEAN) {
+		  IGRAPH_CHECK(igraph_i_attribute_get_bool_edge_attr(graph, 
+			     name, igraph_ess_1((igraph_integer_t) i), &boolv));
+		  CHECK(fprintf(outstream, "    %s=%d\n", newname, VECTOR(boolv)[0] ? 1 : 0));
+		  IGRAPH_WARNING("A boolean edge attribute was converted to numeric");
+		} else {
+		  IGRAPH_WARNING("A non-numeric, non-string graph attribute ignored");
+		}
+	  }
+	  CHECK(fprintf(outstream, "  ];\n"));
+	}
+  } else {
+	for (i=0; i<no_of_edges; i++) {
+	  long int from=IGRAPH_FROM(graph, i);
+	  long int to=IGRAPH_TO(graph, i);
+	  CHECK(fprintf(outstream, "  %ld %s %ld;\n", from, edgeop, to));
+	}
+  }
+  CHECK(fprintf(outstream, "}\n"));
+  
+  igraph_vector_bool_destroy(&boolv);
+  igraph_strvector_destroy(&strv);
+  igraph_vector_destroy(&numv);
+  igraph_vector_destroy(&etypes);
+  igraph_vector_destroy(&vtypes);
+  igraph_vector_destroy(&gtypes);
+  igraph_strvector_destroy(&enames);
+  igraph_strvector_destroy(&vnames);
+  igraph_strvector_destroy(&gnames);
+  IGRAPH_FINALLY_CLEAN(9);
+  
+  return 0;
+}
+
+#include "foreign-dl-header.h"
+
+int igraph_dl_yylex_init_extra (igraph_i_dl_parsedata_t* user_defined,
+				void* scanner);
+int igraph_dl_yylex_destroy (void *scanner );
+int igraph_dl_yyparse (igraph_i_dl_parsedata_t* context);
+void igraph_dl_yyset_in  (FILE * in_str, void* yyscanner );
+
+/** 
+ * \function igraph_read_graph_dl
+ * \brief Read a file in the DL format of UCINET
+ * 
+ * This is a simple textual file format used by UCINET. See
+ * http://www.analytictech.com/networks/dataentry.htm for
+ * examples. All the forms described here are supported by
+ * igraph. Vertex names and edge weights are also supported and they
+ * are added as attributes. (If an attribute handler is attached.)
+ * 
+ * </para><para> Note the specification does not mention whether the
+ * format is case sensitive or not. For igraph DL files are case
+ * sensitive, i.e. \c Larry and \c larry are not the same.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param instream The stream to read the DL file from.
+ * \param directed Logical scalar, whether to create a directed file.
+ * \return Error code.
+ * 
+ * Time complexity: linear in terms of the number of edges and
+ * vertices, except for the matrix format, which is quadratic in the
+ * number of vertices. 
+ * 
+ * \example examples/simple/igraph_read_graph_dl.c
+ */
+
+int igraph_read_graph_dl(igraph_t *graph, FILE *instream, 
+			 igraph_bool_t directed) {
+  
+  int i;
+  long int n, n2;
+  const igraph_strvector_t *namevec=0;
+  igraph_vector_ptr_t name, weight;
+  igraph_vector_ptr_t *pname=0, *pweight=0;
+  igraph_attribute_record_t namerec, weightrec;
+  const char *namestr="name", *weightstr="weight";  
+  igraph_i_dl_parsedata_t context;
+
+  context.eof=0;
+  context.mode=0;
+  context.n=-1;
+  context.from=0;
+  context.to=0;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&context.edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&context.weights, 0);
+  IGRAPH_CHECK(igraph_strvector_init(&context.labels, 0));
+  IGRAPH_FINALLY(igraph_strvector_destroy, &context.labels);
+  IGRAPH_TRIE_INIT_FINALLY(&context.trie, /*names=*/ 1);  
+
+  igraph_dl_yylex_init_extra(&context, &context.scanner);
+  IGRAPH_FINALLY(igraph_dl_yylex_destroy, context.scanner);
+
+  igraph_dl_yyset_in(instream, context.scanner);
+  
+  i=igraph_dl_yyparse(&context);
+  if (i != 0) {
+    if (context.errmsg) { 
+      IGRAPH_ERROR(context.errmsg, IGRAPH_PARSEERROR);
+    } else {
+      IGRAPH_ERROR("Cannot read DL file", IGRAPH_PARSEERROR);
+    }
+  }
+
+  /* Extend the weight vector, if needed */
+  n=igraph_vector_size(&context.weights);
+  n2=igraph_vector_size(&context.edges) / 2;
+  if (n != 0) {
+    igraph_vector_resize(&context.weights, n2);
+    for (; n<n2; n++) {
+      VECTOR(context.weights)[n] = IGRAPH_NAN;
+    }
+  }
+
+  /* Check number of vertices */
+  n=(long int) igraph_vector_max(&context.edges);
+  if (n >= context.n) {
+    IGRAPH_WARNING("More vertices than specified in `DL' file");
+    context.n=n;
+  }
+
+  /* OK, everything is ready, create the graph */
+  IGRAPH_CHECK(igraph_empty(graph, 0, directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+
+  /* Labels */
+  if (igraph_strvector_size(&context.labels) != 0) {
+    namevec=(const igraph_strvector_t*) &context.labels;
+  } else if (igraph_trie_size(&context.trie) != 0) {
+    igraph_trie_getkeys(&context.trie, &namevec);
+  }
+  if (namevec) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &name);
+    pname=&name;
+    namerec.name=namestr;
+    namerec.type=IGRAPH_ATTRIBUTE_STRING;
+    namerec.value=namevec;
+    VECTOR(name)[0]=&namerec;
+  }
+
+  /* Weights */
+  if (igraph_vector_size(&context.weights) != 0) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &weight);
+    pweight=&weight;
+    weightrec.name=weightstr;
+    weightrec.type=IGRAPH_ATTRIBUTE_NUMERIC;
+    weightrec.value=&context.weights;
+    VECTOR(weight)[0]=&weightrec;
+  }
+
+  IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) context.n, pname));
+  IGRAPH_CHECK(igraph_add_edges(graph, &context.edges, pweight));
+
+  if (pweight) {
+    igraph_vector_ptr_destroy(pweight);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (pname) {
+    igraph_vector_ptr_destroy(pname);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  /* don't destroy the graph itself but pop it from the finally stack */
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_trie_destroy(&context.trie);
+  igraph_strvector_destroy(&context.labels);
+  igraph_vector_destroy(&context.edges);
+  igraph_vector_destroy(&context.weights);
+  igraph_dl_yylex_destroy(context.scanner);
+  IGRAPH_FINALLY_CLEAN(5);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_write_graph_leda
+ * \brief Write a graph in LEDA native graph format.
+ * 
+ * This function writes a graph to an output stream in LEDA format.
+ * See http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
+ * 
+ * </para><para>
+ * 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.
+ * 
+ * \param graph The graph to write to the stream.
+ * \param outstream The stream.
+ * \param vertex_attr_name The name of the vertex attribute whose values
+ *                         are to be stored in the output or \c NULL if no
+ *                         vertex attribute has to be stored.
+ * \param edge_attr_name   The name of the edge attribute whose values
+ *                         are to be stored in the output or \c NULL if no
+ *                         edge attribute has to be stored.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices and edges in the
+ * graph.
+ * 
+ * \example examples/simple/igraph_write_graph_leda.c
+ */
+
+int igraph_write_graph_leda(const igraph_t *graph, FILE *outstream,
+			      const char* vertex_attr_name,
+                  const char* edge_attr_name) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_eit_t it;
+  long int i=0;
+  int ret;
+  igraph_attribute_type_t vertex_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
+  igraph_attribute_type_t edge_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
+  igraph_integer_t from, to, rev;
+
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
+				 &it));
+  IGRAPH_FINALLY(igraph_eit_destroy, &it);
+
+  /* Check if we have the vertex attribute */
+  if (vertex_attr_name &&
+      !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, vertex_attr_name)) {
+    vertex_attr_name=0;
+    IGRAPH_WARNING("specified vertex attribute does not exist");
+  } 
+  if (vertex_attr_name) {
+    IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &vertex_attr_type,
+					    IGRAPH_ATTRIBUTE_VERTEX, vertex_attr_name));
+    if (vertex_attr_type != IGRAPH_ATTRIBUTE_NUMERIC &&
+        vertex_attr_type != IGRAPH_ATTRIBUTE_STRING) {
+      vertex_attr_name=0; vertex_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
+      IGRAPH_WARNING("specified vertex attribute must be numeric or string");
+    }
+  }
+
+  /* Check if we have the edge attribute */
+  if (edge_attr_name &&
+      !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, edge_attr_name)) {
+    edge_attr_name=0;
+    IGRAPH_WARNING("specified edge attribute does not exist");
+  } 
+  if (edge_attr_name) {
+    IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &edge_attr_type,
+					    IGRAPH_ATTRIBUTE_EDGE, edge_attr_name));
+    if (edge_attr_type != IGRAPH_ATTRIBUTE_NUMERIC &&
+        edge_attr_type != IGRAPH_ATTRIBUTE_STRING) {
+      edge_attr_name=0; edge_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
+      IGRAPH_WARNING("specified edge attribute must be numeric or string");
+    }
+  }
+
+  /* Start writing header */
+  CHECK(fprintf(outstream, "LEDA.GRAPH\n"));
+  
+  switch (vertex_attr_type) {
+    case IGRAPH_ATTRIBUTE_NUMERIC:
+      CHECK(fprintf(outstream, "float\n"));
+      break;
+    case IGRAPH_ATTRIBUTE_STRING:
+      CHECK(fprintf(outstream, "string\n"));
+      break;
+    default:
+      CHECK(fprintf(outstream, "void\n"));
+  }
+  
+  switch (edge_attr_type) {
+    case IGRAPH_ATTRIBUTE_NUMERIC:
+      CHECK(fprintf(outstream, "float\n"));
+      break;
+    case IGRAPH_ATTRIBUTE_STRING:
+      CHECK(fprintf(outstream, "string\n"));
+      break;
+    default:
+      CHECK(fprintf(outstream, "void\n"));
+  }
+
+  CHECK(fprintf(outstream, "%d\n", (igraph_is_directed(graph) ? -1 : -2)));
+
+  /* Start writing vertices */
+  CHECK(fprintf(outstream, "# Vertices\n"));
+  CHECK(fprintf(outstream, "%ld\n", no_of_nodes));
+
+  if (vertex_attr_type == IGRAPH_ATTRIBUTE_NUMERIC) {
+    /* Vertices with numeric attributes */
+    igraph_vector_t values;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&values, no_of_nodes);
+    IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(
+          graph, vertex_attr_name, igraph_vss_all(), &values));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      CHECK(fprintf(outstream, "|{"));
+      CHECK(igraph_real_fprintf_precise(outstream, VECTOR(values)[i]));
+      CHECK(fprintf(outstream, "}|\n"));
+    }
+
+    igraph_vector_destroy(&values);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (vertex_attr_type == IGRAPH_ATTRIBUTE_STRING) {
+    /* Vertices with string attributes */
+    igraph_strvector_t values;
+
+    IGRAPH_CHECK(igraph_strvector_init(&values, no_of_nodes));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &values);
+    
+    IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(
+          graph, vertex_attr_name, igraph_vss_all(), &values));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      const char* str = STR(values, i);
+      if (strchr(str, '\n') != 0) {
+        IGRAPH_ERROR("edge attribute values cannot contain newline characters",
+            IGRAPH_EINVAL);
+      }
+      CHECK(fprintf(outstream, "|{%s}|\n", str));
+    }
+
+    igraph_strvector_destroy(&values);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    /* Vertices with no attributes */
+    for (i = 0; i < no_of_nodes; i++)
+      CHECK(fprintf(outstream, "|{}|\n"));
+  }
+
+  CHECK(fprintf(outstream, "# Edges\n"));
+  CHECK(fprintf(outstream, "%ld\n", no_of_edges));
+
+  if (edge_attr_type == IGRAPH_ATTRIBUTE_NUMERIC) {
+    /* Edges with numeric attributes */
+    igraph_vector_t values;
+    IGRAPH_VECTOR_INIT_FINALLY(&values, no_of_nodes);
+    IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(
+          graph, edge_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values));
+    while (!IGRAPH_EIT_END(it)) {
+      long int eid = IGRAPH_EIT_GET(it);
+      igraph_edge(graph, (igraph_integer_t) eid, &from, &to);
+      igraph_get_eid(graph, &rev, to, from, 1, 0);
+      if (rev == IGRAPH_EIT_GET(it))
+          rev = -1;
+      CHECK(fprintf(outstream, "%ld %ld %ld |{",
+		    (long int) from+1, (long int) to+1,
+		    (long int) rev+1));
+      CHECK(igraph_real_fprintf_precise(outstream, VECTOR(values)[eid]));
+      CHECK(fprintf(outstream, "}|\n"));
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_vector_destroy(&values);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (edge_attr_type == IGRAPH_ATTRIBUTE_STRING) {
+    /* Edges with string attributes */
+    igraph_strvector_t values;
+    IGRAPH_CHECK(igraph_strvector_init(&values, no_of_nodes));
+    IGRAPH_FINALLY(igraph_strvector_destroy, &values);
+    IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(
+          graph, edge_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values));
+    while (!IGRAPH_EIT_END(it)) {
+      long int eid = IGRAPH_EIT_GET(it);
+      const char* str = STR(values, eid);
+      igraph_edge(graph, (igraph_integer_t) eid, &from, &to);
+      igraph_get_eid(graph, &rev, to, from, 1, 0);
+      if (rev == IGRAPH_EIT_GET(it))
+          rev = -1;
+      if (strchr(str, '\n') != 0) {
+        IGRAPH_ERROR("edge attribute values cannot contain newline characters",
+            IGRAPH_EINVAL);
+      }
+      CHECK(fprintf(outstream, "%ld %ld %ld |{%s}|\n",
+                  (long int) from+1, (long int) to+1,
+                  (long int) rev+1, str));
+      IGRAPH_EIT_NEXT(it);
+    }
+    igraph_strvector_destroy(&values);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    /* Edges with no attributes */
+    while (!IGRAPH_EIT_END(it)) {
+      igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
+      igraph_get_eid(graph, &rev, to, from, 1, 0);
+      if (rev == IGRAPH_EIT_GET(it))
+          rev = -1;
+      CHECK(fprintf(outstream, "%ld %ld %ld |{}|\n",
+                  (long int) from+1, (long int) to+1,
+                  (long int) rev+1));
+      IGRAPH_EIT_NEXT(it);
+    }
+  }
+  
+  igraph_eit_destroy(&it);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;  
+}
+
+#undef CHECK
+
+
diff --git a/src/forestfire.c b/src/forestfire.c
new file mode 100644
index 0000000..20577fa
--- /dev/null
+++ b/src/forestfire.c
@@ -0,0 +1,264 @@
+/* -*- 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_games.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_interface.h"
+#include "igraph_constructors.h"
+#include "igraph_dqueue.h"
+#include "config.h"
+
+typedef struct igraph_i_forest_fire_data_t {
+  igraph_vector_t *inneis;
+  igraph_vector_t *outneis;
+  long int no_of_nodes;
+} igraph_i_forest_fire_data_t;
+  
+
+void igraph_i_forest_fire_free(igraph_i_forest_fire_data_t *data) {
+  long int i;
+  for (i=0; i<data->no_of_nodes; i++) {
+    igraph_vector_destroy(data->inneis+i);
+    igraph_vector_destroy(data->outneis+i);
+  }
+}
+
+/**
+ * \function igraph_forest_fire_game
+ * \brief Generates a network according to the \quote forest fire game \endquote
+ * 
+ * The forest fire model intends to reproduce the following network
+ * characteristics, observed in real networks:
+ * \ilist
+ * \ili Heavy-tailed in-degree distribution. 
+ * \ili Heavy-tailed out-degree distribution.
+ * \ili Communities.
+ * \ili Densification power-law. The network is densifying in time,
+ *      according to a power-law rule.
+ * \ili Shrinking diameter. The diameter of the network decreases in
+ *      time.
+ * \endilist
+ * 
+ * </para><para>
+ * The network is generated in the following way. One vertex is added at
+ * a time. This vertex connects to (cites) <code>ambs</code> vertices already
+ * present in the network, chosen uniformly random. Now, for each cited
+ * vertex <code>v</code> we do the following procedure:
+ * \olist
+ * \oli We generate two random number, <code>x</code> and <code>y</code>, that are
+ *   geometrically distributed with means <code>p/(1-p)</code> and
+ *   <code>rp(1-rp)</code>. (<code>p</code> is <code>fw_prob</code>, <code>r</code> is
+ *   <code>bw_factor</code>.) The new vertex cites <code>x</code> outgoing neighbors
+ *   and <code>y</code> incoming neighbors of <code>v</code>, from those which are
+ *   not yet cited by the new vertex. If there are less than <code>x</code> or
+ *   <code>y</code> such vertices available then we cite all of them.
+ * \oli The same procedure is applied to all the newly cited
+ *   vertices.
+ * \endolist
+ * </para><para>
+ * See also:
+ * Jure Leskovec, Jon Kleinberg and Christos Faloutsos. Graphs over time:
+ * densification laws, shrinking diameters and possible explanations.
+ * \emb KDD '05: Proceeding of the eleventh ACM SIGKDD international
+ * conference on Knowledge discovery in data mining \eme, 177--187, 2005.
+ * </para><para>
+ * Note however, that 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
+ * http://cs.stanford.edu/people/jure/pubs/powergrowth-tkdd.pdf , our
+ * implementation is based on this.
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param nodes The number of vertices in the graph.
+ * \param fw_prob The forward burning probability.
+ * \param bw_factor The backward burning ratio. The backward burning
+      probability is calculated as <code>bw.factor*fw.prob</code>.
+ * \param pambs The number of ambassador vertices.
+ * \param directed Whether to create a directed graph.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+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 pambs, igraph_bool_t directed) {
+  
+  igraph_vector_long_t visited;
+  long int no_of_nodes=nodes, actnode, i;
+  igraph_vector_t edges;
+  igraph_vector_t *inneis, *outneis;
+  igraph_i_forest_fire_data_t data;
+  igraph_dqueue_t neiq;
+  long int ambs=pambs;
+  igraph_real_t param_geom_out=1-fw_prob;
+  igraph_real_t param_geom_in=1-fw_prob*bw_factor;
+  
+  if (fw_prob < 0) {
+    IGRAPH_ERROR("Forest fire model: 'fw_prob' should be between non-negative", 
+		 IGRAPH_EINVAL);
+  }
+  if (bw_factor < 0) {
+    IGRAPH_ERROR("Forest fire model: 'bw_factor' should be non-negative",
+		 IGRAPH_EINVAL);
+  }
+  if (ambs < 0) {
+    IGRAPH_ERROR("Number of ambassadors ('ambs') should be non-negative",
+		 IGRAPH_EINVAL);
+  }
+  
+  if (fw_prob == 0 || ambs == 0) {
+    IGRAPH_WARNING("'fw_prob or ambs is zero, creating empty graph");
+    IGRAPH_CHECK(igraph_empty(graph, nodes, directed));
+    return 0;
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  inneis=igraph_Calloc(no_of_nodes, igraph_vector_t);
+  if (!inneis) {
+    IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, inneis);
+  outneis=igraph_Calloc(no_of_nodes, igraph_vector_t);
+  if (!outneis) {
+    IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, outneis);  
+  data.inneis=inneis; 
+  data.outneis=outneis;
+  data.no_of_nodes=no_of_nodes;
+  IGRAPH_FINALLY(igraph_i_forest_fire_free, &data);
+  for (i=0; i<no_of_nodes; i++) {
+    IGRAPH_CHECK(igraph_vector_init(inneis+i, 0));
+    IGRAPH_CHECK(igraph_vector_init(outneis+i, 0));
+  }  
+
+  IGRAPH_CHECK(igraph_vector_long_init(&visited, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &visited);
+  IGRAPH_DQUEUE_INIT_FINALLY(&neiq, 10);
+
+  RNG_BEGIN();
+
+#define ADD_EDGE_TO(nei) \
+      if (VECTOR(visited)[(nei)] != actnode+1) {                     \
+	VECTOR(visited)[(nei)] = actnode+1;                          \
+	IGRAPH_CHECK(igraph_dqueue_push(&neiq, nei));                \
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, actnode));      \
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));          \
+	IGRAPH_CHECK(igraph_vector_push_back(outneis+actnode, nei)); \
+	IGRAPH_CHECK(igraph_vector_push_back(inneis+nei, actnode));  \
+      }
+  
+  IGRAPH_PROGRESS("Forest fire: ", 0.0, NULL);
+  
+  for (actnode=1; actnode < no_of_nodes; actnode++) {
+
+    IGRAPH_PROGRESS("Forest fire: ", 100.0*actnode/no_of_nodes, NULL);
+
+    IGRAPH_ALLOW_INTERRUPTION();    
+    
+    /* We don't want to visit the current vertex */
+    VECTOR(visited)[actnode] = actnode+1;
+
+    /* Choose ambassador(s) */
+    for (i=0; i<ambs; i++) {
+      long int a=RNG_INTEGER(0, actnode-1);
+      ADD_EDGE_TO(a);
+    }
+    
+    while (!igraph_dqueue_empty(&neiq)) {
+      long int actamb=(long int) igraph_dqueue_pop(&neiq);
+      igraph_vector_t *outv=outneis+actamb;
+      igraph_vector_t *inv=inneis+actamb;
+      long int no_in=igraph_vector_size(inv);
+      long int no_out=igraph_vector_size(outv);
+      long int neis_out=(long int) RNG_GEOM(param_geom_out);
+      long int neis_in=(long int) RNG_GEOM(param_geom_in);
+      /* outgoing neighbors */
+      if (neis_out >= no_out) {
+	for (i=0; i<no_out; i++) {
+	  long int nei=(long int) VECTOR(*outv)[i];
+	  ADD_EDGE_TO(nei);
+	}
+      } else {
+	long int oleft=no_out;
+	for (i=0; i<neis_out && oleft > 0; ) {
+	  long int which=RNG_INTEGER(0, oleft-1);
+	  long int nei=(long int) VECTOR(*outv)[which];
+	  VECTOR(*outv)[which] = VECTOR(*outv)[oleft-1];
+	  VECTOR(*outv)[oleft-1] = nei;
+	  if (VECTOR(visited)[nei] != actnode+1) {
+	    ADD_EDGE_TO(nei);
+	    i++;
+	  }
+	  oleft--;
+	}
+      }
+      /* incoming neighbors */
+      if (neis_in >= no_in) {
+	for (i=0; i<no_in; i++) {
+	  long int nei=(long int) VECTOR(*inv)[i];
+	  ADD_EDGE_TO(nei);
+	}
+      } else {
+	long int ileft=no_in;
+	for (i=0; i<neis_in && ileft > 0; ) {
+	  long int which=RNG_INTEGER(0, ileft-1);
+	  long int nei=(long int) VECTOR(*inv)[which];
+	  VECTOR(*inv)[which] = VECTOR(*inv)[ileft-1];
+	  VECTOR(*inv)[ileft-1] = nei;
+	  if (VECTOR(visited)[nei] != actnode+1) {
+	    ADD_EDGE_TO(nei);
+	    i++;
+	  }
+	  ileft--;
+	}
+      }
+      
+    } /* while neiq not empty */
+
+  } /* actnode < no_of_nodes */
+
+#undef ADD_EDGE_TO  
+
+  RNG_END();
+
+  IGRAPH_PROGRESS("Forest fire: ", 100.0, NULL);
+  
+  igraph_dqueue_destroy(&neiq);
+  igraph_vector_long_destroy(&visited);
+  igraph_i_forest_fire_free(&data);
+  igraph_free(outneis);
+  igraph_free(inneis);  
+  IGRAPH_FINALLY_CLEAN(5);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
diff --git a/src/fortran_intrinsics.c b/src/fortran_intrinsics.c
new file mode 100644
index 0000000..0b02f07
--- /dev/null
+++ b/src/fortran_intrinsics.c
@@ -0,0 +1,53 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-12  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 <float.h>
+
+double digitsdbl_(double x) {
+  return (double) DBL_MANT_DIG;
+}
+
+double epsilondbl_(double x) {
+  return DBL_EPSILON;
+}
+
+double hugedbl_(double x) {
+  return DBL_MAX;
+}
+
+double tinydbl_(double x) {
+  return DBL_MIN;
+}
+
+int maxexponentdbl_(double x) {
+  return DBL_MAX_EXP;
+}
+
+int minexponentdbl_(double x) {
+  return DBL_MIN_EXP;
+}
+
+double radixdbl_(double x) {
+  return (double) FLT_RADIX;
+}
+
diff --git a/src/games.c b/src/games.c
new file mode 100644
index 0000000..406c1be
--- /dev/null
+++ b/src/games.c
@@ -0,0 +1,3866 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=8 sw=2 sts=2 et: */
+/* 
+   IGraph R 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
+
+*/
+
+#include "igraph_interface.h"
+#include "igraph_games.h"
+#include "igraph_random.h"
+#include "igraph_memory.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_attributes.h"
+#include "igraph_constructors.h"
+#include "igraph_nongraph.h"
+#include "igraph_conversion.h"
+#include "igraph_psumtree.h"
+#include "igraph_dqueue.h"
+#include "igraph_adjlist.h"
+#include "igraph_iterators.h"
+#include "igraph_progress.h"
+#include "igraph_topology.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+
+#include <math.h>
+
+typedef struct {
+  long int no;
+  igraph_psumtree_t *sumtrees;
+} igraph_i_citing_cited_type_game_struct_t;
+
+void igraph_i_citing_cited_type_game_free (
+			     igraph_i_citing_cited_type_game_struct_t *s);
+/**
+ * \section about_games
+ * 
+ * <para>Games are randomized graph generators. Randomization means that
+ * they generate a different graph every time you call them. </para>
+ */
+
+int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n, 
+			       igraph_integer_t m, 
+			       const igraph_vector_t *outseq, 
+			       igraph_bool_t outpref, 
+			       igraph_bool_t directed, 
+			       const igraph_t *start_from);
+
+int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, 
+					     igraph_integer_t n,
+					     igraph_real_t power,
+					     igraph_integer_t m,
+					     const igraph_vector_t *outseq,
+					     igraph_bool_t outpref,
+					     igraph_real_t A,
+					     igraph_bool_t directed, 
+					     const igraph_t *start_from);
+
+int igraph_i_barabasi_game_psumtree(igraph_t *graph, 
+				    igraph_integer_t n,
+				    igraph_real_t power,
+				    igraph_integer_t m,
+				    const igraph_vector_t *outseq,
+				    igraph_bool_t outpref,
+				    igraph_real_t A,
+				    igraph_bool_t directed,
+				    const igraph_t *start_from);
+
+int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n, 
+			       igraph_integer_t m, 
+			       const igraph_vector_t *outseq, 
+			       igraph_bool_t outpref, 
+			       igraph_bool_t directed, 
+			       const igraph_t *start_from) {
+
+  long int no_of_nodes=n;
+  long int no_of_neighbors=m;
+  long int *bag;
+  long int bagp=0;
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int resp;
+  long int i,j,k;
+  long int bagsize, start_nodes, start_edges, new_edges, no_of_edges;
+
+  start_nodes= start_from ? igraph_vcount(start_from) : 1;
+  start_edges= start_from ? igraph_ecount(start_from) : 0;
+  if (outseq) { 
+    if (igraph_vector_size(outseq)>1) {
+      new_edges=(long int) (igraph_vector_sum(outseq)-VECTOR(*outseq)[0]);
+    } else {
+      new_edges=0;
+    }
+  } else {
+    new_edges=(no_of_nodes-start_nodes) * no_of_neighbors;
+  }
+  no_of_edges=start_edges+new_edges;
+  resp=start_edges*2;
+  bagsize=no_of_nodes + no_of_edges + (outpref ? no_of_edges : 0);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+
+  bag=igraph_Calloc(bagsize, long int);
+  if (bag==0) {
+    IGRAPH_ERROR("barabasi_game failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, bag); 	/* TODO: hack */
+
+  /* The first node(s) in the bag */
+  if (start_from) {
+    igraph_vector_t deg;
+    long int ii, jj, sn=igraph_vcount(start_from);
+    igraph_neimode_t mm= outpref ? IGRAPH_ALL : IGRAPH_IN;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&deg, sn);
+    IGRAPH_CHECK(igraph_degree(start_from, &deg, igraph_vss_all(), mm, 
+			       IGRAPH_LOOPS));
+    for (ii=0; ii<sn; ii++) {
+      long int d=(long int) VECTOR(deg)[ii];
+      for (jj=0; jj<=d; jj++) {
+	bag[bagp++] = ii;
+      }
+    }
+
+    igraph_vector_destroy(&deg);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    bag[bagp++]=0;
+  }
+
+  /* Initialize the edges vector */
+  if (start_from) {
+    IGRAPH_CHECK(igraph_get_edgelist(start_from, &edges, /* bycol= */ 0));
+    igraph_vector_resize(&edges, no_of_edges * 2);
+  }
+  
+  RNG_BEGIN();
+
+  /* and the others */
+  
+  for (i=(start_from ? start_nodes : 1), k=(start_from ? 0 : 1); 
+       i<no_of_nodes; i++, k++) {
+    /* draw edges */
+    if (outseq) { no_of_neighbors=(long int) VECTOR(*outseq)[k]; }
+    for (j=0; j<no_of_neighbors; j++) {
+      long int to=bag[RNG_INTEGER(0, bagp-1)];
+      VECTOR(edges)[resp++] = i;
+      VECTOR(edges)[resp++] = to;
+    }
+    /* update bag */
+    bag[bagp++] = i;
+    for (j=0; j<no_of_neighbors; j++) {
+      bag[bagp++] = (long int) VECTOR(edges)[resp-2*j-1];
+      if (outpref) {
+	bag[bagp++] = i;
+      }
+    }
+  }
+
+  RNG_END();
+
+  igraph_Free(bag);
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, 
+					     igraph_integer_t n,
+					     igraph_real_t power,
+					     igraph_integer_t m,
+					     const igraph_vector_t *outseq,
+					     igraph_bool_t outpref,
+					     igraph_real_t A,
+					     igraph_bool_t directed, 
+					     const igraph_t *start_from) {
+
+  long int no_of_nodes=n;
+  long int no_of_neighbors=m;
+  igraph_vector_t edges;
+  long int i, j, k;
+  igraph_psumtree_t sumtree;
+  long int edgeptr=0;
+  igraph_vector_t degree;
+  long int start_nodes, start_edges, new_edges, no_of_edges;
+
+  start_nodes= start_from ? igraph_vcount(start_from) : 1;
+  start_edges= start_from ? igraph_ecount(start_from) : 0;
+  if (outseq) { 
+    if (igraph_vector_size(outseq)>1) {
+      new_edges=(long int) (igraph_vector_sum(outseq)-VECTOR(*outseq)[0]);
+    } else {
+      new_edges=0;
+    }
+  } else {
+    new_edges=(no_of_nodes-start_nodes) * no_of_neighbors;
+  }
+  no_of_edges=start_edges+new_edges;
+  edgeptr=start_edges*2;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&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);
+  
+  /* first node(s) */
+  if (start_from) {    
+    long int ii, sn=igraph_vcount(start_from);
+    igraph_neimode_t mm=outpref ? IGRAPH_ALL : IGRAPH_IN;
+    IGRAPH_CHECK(igraph_degree(start_from, &degree, igraph_vss_all(), mm,
+			       IGRAPH_LOOPS));
+    IGRAPH_CHECK(igraph_vector_resize(&degree,  no_of_nodes));
+    for (ii=0; ii<sn; ii++) {
+      igraph_psumtree_update(&sumtree, ii, pow(VECTOR(degree)[ii], power)+A);
+    }
+  } else {    
+    igraph_psumtree_update(&sumtree, 0, A);
+  }
+
+  /* Initialize the edges vector */
+  if (start_from) {
+    IGRAPH_CHECK(igraph_get_edgelist(start_from, &edges, /* bycol= */ 0));
+    igraph_vector_resize(&edges, no_of_edges * 2);
+  }
+
+  RNG_BEGIN();
+
+  /* and the rest */
+  for (i=(start_from ? start_nodes : 1), k=(start_from ? 0 : 1); 
+       i<no_of_nodes; i++, k++) {
+    igraph_real_t sum=igraph_psumtree_sum(&sumtree);
+    long int to;
+    if (outseq) {
+      no_of_neighbors=(long int) VECTOR(*outseq)[k];
+    }
+    for (j=0; j<no_of_neighbors; j++) {
+      igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
+      VECTOR(degree)[to]++;
+      VECTOR(edges)[edgeptr++] = i;
+      VECTOR(edges)[edgeptr++] = to;
+    }
+    /* update probabilities */
+    for (j=0; j<no_of_neighbors; j++) {
+      long int nn=(long int) VECTOR(edges)[edgeptr-2*j-1];
+      igraph_psumtree_update(&sumtree, nn, 
+			     pow(VECTOR(degree)[nn], power)+A);
+    }
+    if (outpref) {
+      VECTOR(degree)[i] += no_of_neighbors;
+      igraph_psumtree_update(&sumtree, i, 
+			     pow(VECTOR(degree)[i], power)+A);
+    } else {
+      igraph_psumtree_update(&sumtree, i, A);
+    }
+  }
+  
+  RNG_END();
+
+  igraph_psumtree_destroy(&sumtree);
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_barabasi_game_psumtree(igraph_t *graph, 
+				    igraph_integer_t n,
+				    igraph_real_t power,
+				    igraph_integer_t m,
+				    const igraph_vector_t *outseq,
+				    igraph_bool_t outpref,
+				    igraph_real_t A,
+				    igraph_bool_t directed,
+				    const igraph_t *start_from) {
+
+  long int no_of_nodes=n;
+  long int no_of_neighbors=m;
+  igraph_vector_t edges;
+  long int i, j, k;
+  igraph_psumtree_t sumtree;
+  long int edgeptr=0;
+  igraph_vector_t degree;
+  long int start_nodes, start_edges, new_edges, no_of_edges;
+
+  start_nodes= start_from ? igraph_vcount(start_from) : 1;
+  start_edges= start_from ? igraph_ecount(start_from) : 0;
+  if (outseq) { 
+    if (igraph_vector_size(outseq)>1) {
+      new_edges=(long int) (igraph_vector_sum(outseq)-VECTOR(*outseq)[0]);
+    } else {
+      new_edges=0;
+    }
+  } else {
+    new_edges=(no_of_nodes-start_nodes) * no_of_neighbors;
+  }
+  no_of_edges=start_edges+new_edges;
+  edgeptr=start_edges*2;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&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(s) */
+  if (start_from) {    
+    long int ii, sn=igraph_vcount(start_from);
+    igraph_neimode_t mm=outpref ? IGRAPH_ALL : IGRAPH_IN;
+    IGRAPH_CHECK(igraph_degree(start_from, &degree, igraph_vss_all(), mm,
+			       IGRAPH_LOOPS));
+    IGRAPH_CHECK(igraph_vector_resize(&degree,  no_of_nodes));
+    for (ii=0; ii<sn; ii++) {
+      igraph_psumtree_update(&sumtree, ii, pow(VECTOR(degree)[ii], power)+A);
+    }
+  } else {    
+    igraph_psumtree_update(&sumtree, 0, A);
+  }
+
+  /* Initialize the edges vector */
+  if (start_from) {
+    IGRAPH_CHECK(igraph_get_edgelist(start_from, &edges, /* bycol= */ 0));
+  }  
+
+  /* and the rest */
+  for (i=(start_from ? start_nodes : 1), k=(start_from ? 0 : 1); 
+       i<no_of_nodes; i++, k++) {
+    igraph_real_t sum;
+    long int to;
+    if (outseq) {
+      no_of_neighbors=(long int) VECTOR(*outseq)[k];
+    }
+    if (no_of_neighbors >= i) {
+      /* All existing vertices are cited */
+      for (to=0; to<i; to++) {
+	VECTOR(degree)[to]++;
+	igraph_vector_push_back(&edges, i);
+	igraph_vector_push_back(&edges, to);
+	edgeptr+=2;
+	igraph_psumtree_update(&sumtree, to, pow(VECTOR(degree)[to], power)+A);
+      }
+    } else {
+      for (j=0; j<no_of_neighbors; j++) {
+	sum=igraph_psumtree_sum(&sumtree);
+	igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
+	VECTOR(degree)[to]++;
+	igraph_vector_push_back(&edges, i);
+	igraph_vector_push_back(&edges, to);
+	edgeptr+=2;
+	igraph_psumtree_update(&sumtree, to, 0.0);
+      }
+      /* update probabilities */
+      for (j=0; j<no_of_neighbors; j++) {
+	long int nn=(long int) VECTOR(edges)[edgeptr-2*j-1];
+	igraph_psumtree_update(&sumtree, nn, 
+			       pow(VECTOR(degree)[nn], power)+A);
+      }
+    }
+    if (outpref) {
+      VECTOR(degree)[i] += no_of_neighbors > i ? i : no_of_neighbors;
+      igraph_psumtree_update(&sumtree, i, 
+			     pow(VECTOR(degree)[i], power)+A);
+    } else {
+      igraph_psumtree_update(&sumtree, i, A);
+    }
+  }
+  
+  RNG_END();
+
+  igraph_psumtree_destroy(&sumtree);
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_barabasi_game
+ * \brief Generates a graph based on the Barabási-Albert model.
+ *
+ * \param graph An uninitialized graph object.
+ * \param n The number of vertices in the graph.
+ * \param power Power of the preferential attachment. 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 classic preferential 
+ *        attachment model power=1.
+ * \param m The number of outgoing edges generated for each 
+ *        vertex. (Only if \p outseq is \c NULL.) 
+ * \param outseq Gives the (out-)degrees of the vertices. If this is
+ *        constant, this can be a NULL pointer or an empty (but
+ *        initialized!) vector, in this case \p m contains
+ *        the constant out-degree. The very first vertex has by definition 
+ *        no outgoing edges, so the first number in this vector is 
+ *        ignored.
+ * \param outpref Boolean, if true not only the in- but also the out-degree
+ *        of a vertex increases its citation probability. Ie. the
+ *        citation probability is determined by the total degree of
+ *        the vertices.
+ * \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
+ *        previous versions of the function this parameter was
+ *        implicitly set to one.
+ * \param directed Boolean, whether to generate a directed graph.
+ * \param algo The algorithm to use to generate the network. Possible
+ *        values: 
+ *        \clist
+ *        \cli IGRAPH_BARABASI_BAG
+ *          This is the algorithm that was previously (before version
+ *          0.6) solely implemented in igraph. It works by putting the
+ *          ids of the vertices into a bag (multiset, 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 power=1 and A=1.
+ *        \cli IGRAPH_BARABASI_PSUMTREE
+ *          This algorithm uses a partial prefix-sum tree to generate
+ *          the graph. It does not generate multiple edges and 
+ *          works for any power and A values.
+ *        \cli IGRAPH_BARABASI_PSUMTREE_MULTIPLE
+ *          This algorithm also uses a partial prefix-sum tree to 
+ *          generate the graph. The difference is, that now multiple
+ *          edges are allowed. This method was implemented under the
+ *          name \c igraph_nonlinear_barabasi_game before version 0.6.
+ *        \endclist
+ * \param start_from Either a null pointer, or a graph. In the latter 
+ *        case the graph as a starting configuration. The graph must
+ *        be non-empty, i.e. it must have at least one vertex. If a
+ *        graph is supplied here and the \p outseq argument is also
+ *        given, then \p outseq should only contain information on the
+ *        vertices that are not in the \p start_from graph.
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid \p n,
+ *         \p m or \p outseq parameter.
+ * 
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges.
+ * 
+ * \example examples/simple/igraph_barabasi_game.c
+ * \example examples/simple/igraph_barabasi_game2.c
+ */
+
+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) {
+
+  long int start_nodes= start_from ? igraph_vcount(start_from) : 0;
+  long int newn= start_from ? n-start_nodes : n;
+
+  /* Fix an obscure parameterization */
+  if (outseq && igraph_vector_size(outseq) == 0) {
+    outseq=0;
+  }
+  
+  /* Check arguments */
+
+  if (algo != IGRAPH_BARABASI_BAG && 
+      algo != IGRAPH_BARABASI_PSUMTREE && 
+      algo != IGRAPH_BARABASI_PSUMTREE_MULTIPLE) {
+    IGRAPH_ERROR("Invalid algorithm", IGRAPH_EINVAL);
+  }
+  if (n < 0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  } else if (newn < 0) {
+    IGRAPH_ERROR("Starting graph has too many vertices", IGRAPH_EINVAL);
+  }
+  if (start_from && start_nodes==0) {
+    IGRAPH_ERROR("Cannot start from an empty graph", IGRAPH_EINVAL);
+  }
+  if (outseq != 0 && igraph_vector_size(outseq) != 0 && 
+      igraph_vector_size(outseq) != newn) {
+    IGRAPH_ERROR("Invalid out degree sequence length", IGRAPH_EINVAL);
+  }
+  if ( (outseq == 0 || igraph_vector_size(outseq) == 0) && m<0) {
+    IGRAPH_ERROR("Invalid out degree", IGRAPH_EINVAL);
+  }
+  if (outseq && igraph_vector_min(outseq) < 0) {
+    IGRAPH_ERROR("Negative out degree in sequence", IGRAPH_EINVAL);
+  }
+  if (A <= 0) {
+    IGRAPH_ERROR("Constant attractiveness (A) must be positive",
+		 IGRAPH_EINVAL);
+  }
+  if (algo == IGRAPH_BARABASI_BAG) {
+    if (power != 1) {
+      IGRAPH_ERROR("Power must be one for 'bag' algorithm", IGRAPH_EINVAL);
+    }
+    if (A != 1) {
+      IGRAPH_ERROR("Constant attractiveness (A) must be one for bag algorithm",
+		   IGRAPH_EINVAL);
+    }
+  }
+  if (start_from && directed != igraph_is_directed(start_from)) {
+    IGRAPH_WARNING("Directedness of the start graph and the output graph"
+		   " mismatch");
+  }
+  if (start_from && !igraph_is_directed(start_from) && !outpref) {
+    IGRAPH_ERROR("`outpref' must be true if starting from an undirected "
+		 "graph", IGRAPH_EINVAL);
+  }
+
+  if (algo == IGRAPH_BARABASI_BAG) {
+    return igraph_i_barabasi_game_bag(graph, n, m, outseq, outpref, directed, 
+				      start_from);
+  } else if (algo == IGRAPH_BARABASI_PSUMTREE) {
+    return igraph_i_barabasi_game_psumtree(graph, n, power, m, outseq, 
+					   outpref, A, directed, start_from);
+  } else if (algo == IGRAPH_BARABASI_PSUMTREE_MULTIPLE) {
+    return igraph_i_barabasi_game_psumtree_multiple(graph, n, power, m, 
+						    outseq, outpref, A, 
+						    directed, start_from);
+  }
+					   
+  return 0;
+}
+
+/**
+ * \ingroup internal
+ */
+
+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) {
+
+  long int no_of_nodes=n;
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  igraph_vector_t s=IGRAPH_VECTOR_NULL;
+  int retval=0;  
+
+  if (n<0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (p<0.0 || p>1.0) {
+    IGRAPH_ERROR("Invalid probability given", IGRAPH_EINVAL);
+  }
+  
+  if (p==0.0 || no_of_nodes<=1) {
+    IGRAPH_CHECK(retval=igraph_empty(graph, n, directed));
+  } else if (p==1.0) { 
+    IGRAPH_CHECK(retval=igraph_full(graph, n, directed, loops));
+  } else {
+
+    long int i;
+    double maxedges = n, last;
+    if (directed && loops) 
+      { maxedges *= n; }
+    else if (directed && !loops)
+      { maxedges *= (n-1); }
+    else if (!directed && loops) 
+      { maxedges *= (n+1)/2.0; }
+    else 
+      { maxedges *= (n-1)/2.0; }
+
+    IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&s, (long int) (maxedges*p*1.1)));
+
+    RNG_BEGIN();
+
+    last=RNG_GEOM(p);
+    while (last < maxedges) {
+      IGRAPH_CHECK(igraph_vector_push_back(&s, last));
+      last += RNG_GEOM(p);
+      last += 1;
+    }
+
+    RNG_END();
+
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, igraph_vector_size(&s)*2));
+
+    if (directed && loops) {
+      for (i=0; i<igraph_vector_size(&s); i++) {
+	long int to=(long int) floor(VECTOR(s)[i]/no_of_nodes);
+	long int from=(long int) (VECTOR(s)[i]-((igraph_real_t)to)*no_of_nodes);
+	igraph_vector_push_back(&edges, from);
+	igraph_vector_push_back(&edges, to);
+      }
+    } else if (directed && !loops) {
+      for (i=0; i<igraph_vector_size(&s); i++) {
+	long int to=(long int) floor(VECTOR(s)[i]/no_of_nodes);
+	long int from=(long int) (VECTOR(s)[i]-((igraph_real_t)to)*no_of_nodes);
+	if (from==to) {
+	  to=no_of_nodes-1;
+	}
+	igraph_vector_push_back(&edges, from);
+	igraph_vector_push_back(&edges, to);
+      }
+    } else if (!directed && loops) {
+      for (i=0; i<igraph_vector_size(&s); i++) {
+	long int to=(long int) floor((sqrt(8*VECTOR(s)[i]+1)-1)/2);
+	long int from=(long int) (VECTOR(s)[i]-(((igraph_real_t)to)*(to+1))/2);
+	igraph_vector_push_back(&edges, from);
+	igraph_vector_push_back(&edges, to);
+      }
+    } else /* !directed && !loops */ {
+      for (i=0; i<igraph_vector_size(&s); i++) {
+	long int to=(long int) floor((sqrt(8*VECTOR(s)[i]+1)+1)/2);
+	long int from=(long int) (VECTOR(s)[i]-(((igraph_real_t)to)*(to-1))/2);
+	igraph_vector_push_back(&edges, from);
+	igraph_vector_push_back(&edges, to);
+      }
+    }      
+
+    igraph_vector_destroy(&s);
+    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_CHECK(retval=igraph_create(graph, &edges, n, directed));
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return retval;
+}
+
+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) {
+
+  igraph_integer_t no_of_nodes=n;
+  igraph_integer_t no_of_edges=(igraph_integer_t) m;
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  igraph_vector_t s=IGRAPH_VECTOR_NULL;
+  int retval=0;
+
+  if (n<0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (m<0) {
+    IGRAPH_ERROR("Invalid number of edges", IGRAPH_EINVAL);
+  }
+  
+  if (m==0.0 || no_of_nodes<=1) {
+    IGRAPH_CHECK(retval=igraph_empty(graph, n, directed));
+  } else {
+
+    long int i;    
+    double maxedges = n;
+    if (directed && loops) 
+      { maxedges *= n; }
+    else if (directed && !loops)
+      { maxedges *= (n-1); }
+    else if (!directed && loops) 
+      { maxedges *= (n+1)/2.0; }
+    else 
+      { maxedges *= (n-1)/2.0; }
+    
+    if (no_of_edges > maxedges) {
+      IGRAPH_ERROR("Invalid number (too large) of edges", IGRAPH_EINVAL);
+    }
+
+    if (maxedges == no_of_edges) {
+      retval=igraph_full(graph, n, directed, loops);
+    } else {
+    
+      long int slen;
+      
+      IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+      IGRAPH_CHECK(igraph_random_sample(&s, 0, maxedges-1, 
+					(igraph_integer_t) no_of_edges));
+      
+      IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+      IGRAPH_CHECK(igraph_vector_reserve(&edges, igraph_vector_size(&s)*2));
+
+      slen=igraph_vector_size(&s);
+      if (directed && loops) {
+	for (i=0; i<slen; i++) {
+	  long int to=(long int) floor(VECTOR(s)[i]/no_of_nodes);
+	  long int from=(long int) (VECTOR(s)[i]-((igraph_real_t)to)*no_of_nodes);
+	  igraph_vector_push_back(&edges, from);
+	  igraph_vector_push_back(&edges, to);
+	}
+      } else if (directed && !loops) {
+	for (i=0; i<slen; i++) {
+	  long int from=(long int) floor(VECTOR(s)[i]/(no_of_nodes-1));
+	  long int to=(long int) (VECTOR(s)[i]-((igraph_real_t)from)*(no_of_nodes-1));
+	  if (from==to) {
+	    to=no_of_nodes-1;
+	  }
+	  igraph_vector_push_back(&edges, from);
+	  igraph_vector_push_back(&edges, to);
+	}
+      } else if (!directed && loops) {
+	for (i=0; i<slen; i++) {
+	  long int to=(long int) floor((sqrt(8*VECTOR(s)[i]+1)-1)/2);
+	  long int from=(long int) (VECTOR(s)[i]-(((igraph_real_t)to)*(to+1))/2);
+	  igraph_vector_push_back(&edges, from);
+	  igraph_vector_push_back(&edges, to);
+	}
+      } else /* !directed && !loops */ {
+	for (i=0; i<slen; i++) {
+	  long int to=(long int) floor((sqrt(8*VECTOR(s)[i]+1)+1)/2);
+	  long int from=(long int) (VECTOR(s)[i]-(((igraph_real_t)to)*(to-1))/2);
+	  igraph_vector_push_back(&edges, from);
+	  igraph_vector_push_back(&edges, to);
+	}
+      }  
+
+      igraph_vector_destroy(&s);
+      IGRAPH_FINALLY_CLEAN(1);
+      retval=igraph_create(graph, &edges, n, directed);
+      igraph_vector_destroy(&edges);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+  
+  return retval;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_erdos_renyi_game
+ * \brief Generates a random (Erdos-Renyi) graph.
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param type The type of the random graph, possible values:
+ *        \clist
+ *        \cli IGRAPH_ERDOS_RENYI_GNM
+ *          G(n,m) graph,  
+ *          m edges are
+ *          selected uniformly randomly in a graph with
+ *          n vertices.
+ *        \cli IGRAPH_ERDOS_RENYI_GNP
+ *          G(n,p) graph,
+ *          every possible edge is included in the graph with
+ *          probability p.
+ *        \endclist
+ * \param n The number of vertices in the graph.
+ * \param p_or_m This is the p parameter for
+ *        G(n,p) graphs and the
+ *        m 
+ *        parameter for G(n,m) graphs.
+ * \param directed Logical, whether to generate a directed graph.
+ * \param loops Logical, whether to generate loops (self) edges.
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid
+ *         \p type, \p n,
+ *         \p p or \p m
+ *          parameter.
+ *         \c IGRAPH_ENOMEM: there is not enough
+ *         memory for the operation.
+ * 
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges in the graph.
+ * 
+ * \sa \ref igraph_barabasi_game(), \ref igraph_growing_random_game()
+ * 
+ * \example examples/simple/igraph_erdos_renyi_game.c
+ */
+
+int igraph_erdos_renyi_game(igraph_t *graph, igraph_erdos_renyi_t type,
+			    igraph_integer_t n, igraph_real_t p_or_m,
+			    igraph_bool_t directed, igraph_bool_t loops) {
+  int retval=0;
+  if (type == IGRAPH_ERDOS_RENYI_GNP) {
+    retval=igraph_erdos_renyi_game_gnp(graph, n, p_or_m, directed, loops);
+  } else if (type == IGRAPH_ERDOS_RENYI_GNM) {
+    retval=igraph_erdos_renyi_game_gnm(graph, n, p_or_m, directed, loops);
+  } else {
+    IGRAPH_ERROR("Invalid type", IGRAPH_EINVAL);
+  }
+  
+  return retval;
+}
+
+int igraph_degree_sequence_game_simple(igraph_t *graph, 
+				       const igraph_vector_t *out_seq, 
+				       const igraph_vector_t *in_seq);
+
+int igraph_degree_sequence_game_simple(igraph_t *graph, 
+				       const igraph_vector_t *out_seq, 
+				       const igraph_vector_t *in_seq) {
+
+  long int outsum=0, insum=0;
+  igraph_bool_t directed=(in_seq != 0 && igraph_vector_size(in_seq)!=0);
+  igraph_bool_t degseq_ok;
+  long int no_of_nodes, no_of_edges;
+  long int *bag1=0, *bag2=0;
+  long int bagp1=0, bagp2=0;
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int i,j;
+
+  IGRAPH_CHECK(igraph_is_degree_sequence(out_seq, in_seq, &degseq_ok));
+  if (!degseq_ok) {
+    IGRAPH_ERROR(in_seq ? "No directed graph can realize the given degree sequences" :
+        "No undirected graph can realize the given degree sequence", IGRAPH_EINVAL);
+  }
+  
+  outsum=(long int) igraph_vector_sum(out_seq);
+  if (directed)
+    insum=(long int) igraph_vector_sum(in_seq);
+  
+  no_of_nodes=igraph_vector_size(out_seq);
+  no_of_edges=directed ? outsum : outsum/2;
+
+  bag1=igraph_Calloc(outsum, long int);
+  if (bag1==0) {
+    IGRAPH_ERROR("degree sequence game (simple)", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, bag1); 	/* TODO: hack */
+    
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<VECTOR(*out_seq)[i]; j++) {
+      bag1[bagp1++]=i;
+    }
+  }
+  if (directed) {
+    bag2=igraph_Calloc(insum, long int);
+    if (bag2==0) {
+      IGRAPH_ERROR("degree sequence game (simple)", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(free, bag2);
+    for (i=0; i<no_of_nodes; i++) {
+      for (j=0; j<VECTOR(*in_seq)[i]; j++) {
+	bag2[bagp2++]=i;
+      }
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+
+  RNG_BEGIN();
+
+  if (directed) {
+    for (i=0; i<no_of_edges; i++) {
+      long int from=RNG_INTEGER(0, bagp1-1);
+      long int to=RNG_INTEGER(0, bagp2-1);
+      igraph_vector_push_back(&edges, bag1[from]); /* safe, already reserved */
+      igraph_vector_push_back(&edges, bag2[to]);   /* ditto */
+      bag1[from]=bag1[bagp1-1];
+      bag2[to]=bag2[bagp2-1];
+      bagp1--; bagp2--;
+    }
+  } else {
+    for (i=0; i<no_of_edges; i++) {
+      long int from=RNG_INTEGER(0, bagp1-1);
+      long int to;
+      igraph_vector_push_back(&edges, bag1[from]); /* safe, already reserved */
+      bag1[from]=bag1[bagp1-1];
+      bagp1--;
+      to=RNG_INTEGER(0, bagp1-1);
+      igraph_vector_push_back(&edges, bag1[to]);   /* ditto */
+      bag1[to]=bag1[bagp1-1];
+      bagp1--;
+    }
+  }
+  
+  RNG_END();
+
+  igraph_Free(bag1);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (directed) {
+    igraph_Free(bag2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_degree_sequence_game_no_multiple_undirected(
+    igraph_t *graph, const igraph_vector_t *seq) {
+
+  igraph_vector_t stubs=IGRAPH_VECTOR_NULL;
+  igraph_vector_int_t *neis;
+  igraph_vector_t residual_degrees=IGRAPH_VECTOR_NULL;
+  igraph_set_t incomplete_vertices;
+  igraph_adjlist_t al;
+  igraph_bool_t finished, failed;
+  igraph_integer_t from, to, dummy;
+  long int i, j, k;
+  long int no_of_nodes, outsum=0;
+  igraph_bool_t degseq_ok;
+
+  IGRAPH_CHECK(igraph_is_graphical_degree_sequence(seq, 0, &degseq_ok));
+  if (!degseq_ok) {
+    IGRAPH_ERROR("No simple undirected graph can realize the given degree sequence",
+        IGRAPH_EINVAL);
+  }
+  
+  outsum=(long int) igraph_vector_sum(seq);
+  no_of_nodes=igraph_vector_size(seq);
+
+  /* Allocate required data structures */
+  IGRAPH_CHECK(igraph_adjlist_init_empty(&al, (igraph_integer_t) no_of_nodes));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
+  IGRAPH_VECTOR_INIT_FINALLY(&stubs, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&stubs, outsum));
+  IGRAPH_VECTOR_INIT_FINALLY(&residual_degrees, no_of_nodes);
+  IGRAPH_CHECK(igraph_set_init(&incomplete_vertices, 0));
+  IGRAPH_FINALLY(igraph_set_destroy, &incomplete_vertices);
+
+  /* Start the RNG */
+  RNG_BEGIN();
+
+  /* Outer loop; this will try to construct a graph several times from scratch
+   * until it finally succeeds. */
+  finished = 0;
+  while (!finished) {
+    /* Be optimistic :) */
+    failed = 0;
+
+    /* Clear the adjacency list to get rid of the previous attempt (if any) */
+    igraph_adjlist_clear(&al);
+
+    /* Initialize the residual degrees from the degree sequence */
+    IGRAPH_CHECK(igraph_vector_update(&residual_degrees, seq));
+
+    /* While there are some unconnected stubs left... */
+    while (!finished && !failed) {
+      /* Construct the initial stub vector */
+      igraph_vector_clear(&stubs);
+      for (i = 0; i < no_of_nodes; i++) {
+        for (j = 0; j < VECTOR(residual_degrees)[i]; j++) {
+          igraph_vector_push_back(&stubs, i);
+        }
+      }
+
+      /* Clear the skipped stub counters and the set of incomplete vertices */
+      igraph_vector_null(&residual_degrees);
+      igraph_set_clear(&incomplete_vertices);
+
+      /* Shuffle the stubs in-place */
+      igraph_vector_shuffle(&stubs);
+
+      /* Connect the stubs where possible */
+      k = igraph_vector_size(&stubs);
+      for (i = 0; i < k; ) {
+        from = (igraph_integer_t) VECTOR(stubs)[i++];
+        to = (igraph_integer_t) VECTOR(stubs)[i++];
+
+        if (from > to) {
+          dummy = from; from = to; to = dummy;
+        }
+
+        neis = igraph_adjlist_get(&al, from);
+        if (from == to || igraph_vector_int_binsearch(neis, to, &j)) {
+          /* Edge exists already */
+          VECTOR(residual_degrees)[from]++;
+          VECTOR(residual_degrees)[to]++;
+          IGRAPH_CHECK(igraph_set_add(&incomplete_vertices, from));
+          IGRAPH_CHECK(igraph_set_add(&incomplete_vertices, to));
+        } else {
+          /* Insert the edge */
+          IGRAPH_CHECK(igraph_vector_int_insert(neis, j, to));
+        }
+      }
+
+      finished = igraph_set_empty(&incomplete_vertices);
+
+      if (!finished) {
+        /* We are not done yet; check if the remaining stubs are feasible. This
+         * is done by enumerating all possible pairs and checking whether at
+         * least one feasible pair is found. */
+        i = 0;
+        failed = 1;
+        while (failed && igraph_set_iterate(&incomplete_vertices, &i, &from)) {
+          j = 0;
+          while (igraph_set_iterate(&incomplete_vertices, &j, &to)) {
+            if (from == to) {
+              /* This is used to ensure that each pair is checked once only */
+              break;
+            }
+            if (from > to) {
+              dummy = from; from = to; to = dummy;
+            }
+            neis = igraph_adjlist_get(&al, from);
+            if (!igraph_vector_int_binsearch(neis, to, 0)) {
+              /* Found a suitable pair, so we can continue */
+              failed = 0;
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /* Finish the RNG */
+  RNG_END();
+
+  /* Clean up */
+  igraph_set_destroy(&incomplete_vertices);
+  igraph_vector_destroy(&residual_degrees);
+  igraph_vector_destroy(&stubs);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  /* Create the graph. We cannot use IGRAPH_ALL here for undirected graphs
+   * because we did not add edges in both directions in the adjacency list.
+   * We will use igraph_to_undirected in an extra step. */
+  IGRAPH_CHECK(igraph_adjlist(graph, &al, IGRAPH_OUT, 1));
+  IGRAPH_CHECK(igraph_to_undirected(graph, IGRAPH_TO_UNDIRECTED_EACH, 0));
+
+  /* Clear the adjacency list */
+  igraph_adjlist_destroy(&al);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_degree_sequence_game_no_multiple_directed(igraph_t *graph,
+    const igraph_vector_t *out_seq, const igraph_vector_t *in_seq) {
+  igraph_adjlist_t al;
+  igraph_bool_t deg_seq_ok, failed, finished;
+  igraph_vector_t in_stubs = IGRAPH_VECTOR_NULL;
+  igraph_vector_t out_stubs = IGRAPH_VECTOR_NULL;
+  igraph_vector_int_t *neis;
+  igraph_vector_t residual_in_degrees=IGRAPH_VECTOR_NULL;
+  igraph_vector_t residual_out_degrees=IGRAPH_VECTOR_NULL;
+  igraph_set_t incomplete_in_vertices;
+  igraph_set_t incomplete_out_vertices;
+  igraph_integer_t from, to;
+  long int i, j, k;
+  long int no_of_nodes, outsum;
+
+  IGRAPH_CHECK(igraph_is_graphical_degree_sequence(out_seq, in_seq, &deg_seq_ok));
+  if (!deg_seq_ok) {
+    IGRAPH_ERROR("No simple directed graph can realize the given degree sequence",
+        IGRAPH_EINVAL);
+  }
+  
+  outsum=(long int) igraph_vector_sum(out_seq);
+  no_of_nodes=igraph_vector_size(out_seq);
+
+  /* Allocate required data structures */
+  IGRAPH_CHECK(igraph_adjlist_init_empty(&al, (igraph_integer_t) no_of_nodes));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
+  IGRAPH_VECTOR_INIT_FINALLY(&out_stubs, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&out_stubs, outsum));
+  IGRAPH_VECTOR_INIT_FINALLY(&in_stubs, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&in_stubs, outsum));
+  IGRAPH_VECTOR_INIT_FINALLY(&residual_out_degrees, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&residual_in_degrees, no_of_nodes);
+  IGRAPH_CHECK(igraph_set_init(&incomplete_out_vertices, 0));
+  IGRAPH_FINALLY(igraph_set_destroy, &incomplete_out_vertices);
+  IGRAPH_CHECK(igraph_set_init(&incomplete_in_vertices, 0));
+  IGRAPH_FINALLY(igraph_set_destroy, &incomplete_in_vertices);
+
+  /* Start the RNG */
+  RNG_BEGIN();
+
+  /* Outer loop; this will try to construct a graph several times from scratch
+   * until it finally succeeds. */
+  finished = 0;
+  while (!finished) {
+    /* Be optimistic :) */
+    failed = 0;
+
+    /* Clear the adjacency list to get rid of the previous attempt (if any) */
+    igraph_adjlist_clear(&al);
+
+    /* Initialize the residual degrees from the degree sequences */
+    IGRAPH_CHECK(igraph_vector_update(&residual_out_degrees, out_seq));
+    IGRAPH_CHECK(igraph_vector_update(&residual_in_degrees, in_seq));
+
+    /* While there are some unconnected stubs left... */
+    while (!finished && !failed) {
+      /* Construct the initial stub vectors */
+      igraph_vector_clear(&out_stubs);
+      igraph_vector_clear(&in_stubs);
+      for (i = 0; i < no_of_nodes; i++) {
+        for (j = 0; j < VECTOR(residual_out_degrees)[i]; j++) {
+          igraph_vector_push_back(&out_stubs, i);
+        }
+        for (j = 0; j < VECTOR(residual_in_degrees)[i]; j++) {
+          igraph_vector_push_back(&in_stubs, i);
+        }
+      }
+
+      /* Clear the skipped stub counters and the set of incomplete vertices */
+      igraph_vector_null(&residual_out_degrees);
+      igraph_vector_null(&residual_in_degrees);
+      igraph_set_clear(&incomplete_out_vertices);
+      igraph_set_clear(&incomplete_in_vertices);
+      outsum = 0;
+
+      /* Shuffle the out-stubs in-place */
+      igraph_vector_shuffle(&out_stubs);
+
+      /* Connect the stubs where possible */
+      k = igraph_vector_size(&out_stubs);
+      for (i = 0; i < k; i++) {
+        from = (igraph_integer_t) VECTOR(out_stubs)[i];
+        to = (igraph_integer_t) VECTOR(in_stubs)[i];
+
+        neis = igraph_adjlist_get(&al, from);
+        if (from == to || igraph_vector_int_binsearch(neis, to, &j)) {
+          /* Edge exists already */
+          VECTOR(residual_out_degrees)[from]++;
+          VECTOR(residual_in_degrees)[to]++;
+          IGRAPH_CHECK(igraph_set_add(&incomplete_out_vertices, from));
+          IGRAPH_CHECK(igraph_set_add(&incomplete_in_vertices, to));
+        } else {
+          /* Insert the edge */
+          IGRAPH_CHECK(igraph_vector_int_insert(neis, j, to));
+        }
+      }
+
+      /* Are we finished? */
+      finished = igraph_set_empty(&incomplete_out_vertices);
+
+      if (!finished) {
+        /* We are not done yet; check if the remaining stubs are feasible. This
+         * is done by enumerating all possible pairs and checking whether at
+         * least one feasible pair is found. */
+        i = 0;
+        failed = 1;
+        while (failed && igraph_set_iterate(&incomplete_out_vertices, &i, &from)) {
+          j = 0;
+          while (igraph_set_iterate(&incomplete_in_vertices, &j, &to)) {
+            neis = igraph_adjlist_get(&al, from);
+            if (from != to && !igraph_vector_int_binsearch(neis, to, 0)) {
+              /* Found a suitable pair, so we can continue */
+              failed = 0;
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /* Finish the RNG */
+  RNG_END();
+
+  /* Clean up */
+  igraph_set_destroy(&incomplete_in_vertices);
+  igraph_set_destroy(&incomplete_out_vertices);
+  igraph_vector_destroy(&residual_in_degrees);
+  igraph_vector_destroy(&residual_out_degrees);
+  igraph_vector_destroy(&in_stubs);
+  igraph_vector_destroy(&out_stubs);
+  IGRAPH_FINALLY_CLEAN(6);
+
+  /* Create the graph */
+  IGRAPH_CHECK(igraph_adjlist(graph, &al, IGRAPH_OUT, 1));
+
+  /* Clear the adjacency list */
+  igraph_adjlist_destroy(&al);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return IGRAPH_SUCCESS;
+}
+
+/* This is in gengraph_mr-connected.cpp */
+
+int igraph_degree_sequence_game_vl(igraph_t *graph,
+				   const igraph_vector_t *out_seq,
+				   const igraph_vector_t *in_seq);
+/**
+ * \ingroup generators
+ * \function igraph_degree_sequence_game
+ * \brief Generates a random graph with a given degree sequence 
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param out_deg The degree sequence for an undirected graph (if
+ *        \p in_seq is of length zero), or the out-degree
+ *        sequence of a directed graph (if \p in_deq is not
+ *        of length zero.
+ * \param in_deg It is either a zero-length vector or
+ *        \c NULL (if an undirected 
+ *        graph is generated), or the in-degree sequence.
+ * \param method The method to generate the graph. Possible values: 
+ *        \clist
+ *          \cli IGRAPH_DEGSEQ_SIMPLE
+ *          For undirected graphs, this method puts all vertex ids in a bag
+ *          such that the multiplicity of a vertex in the bag is the same as
+ *          its degree. Then it draws pairs from the bag until the bag becomes
+ *          empty. This method can generate both loop (self) edges and multiple
+ *          edges. For directed graphs, the algorithm is basically the same,
+ *          but two separate bags are used for the in- and out-degrees. 
+ *          \cli IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE
+ *          This method is similar to \c IGRAPH_DEGSEQ_SIMPLE
+ *          but tries to avoid multiple and loop edges and restarts the
+ *          generation from scratch if it gets stuck. It is not guaranteed
+ *          to sample uniformly from the space of all possible graphs with
+ *          the given sequence, but it is relatively fast and it will
+ *          eventually succeed if the provided degree sequence is graphical,
+ *          but there is no upper bound on the number of iterations.
+ *          \cli IGRAPH_DEGSEQ_VL
+ *          This method is a much more sophisticated generator than the
+ *          previous ones. It can sample undirected, connected simple graphs
+ *          uniformly and uses Monte-Carlo methods to randomize the graphs. 
+ *          This generator should be favoured if undirected and connected 
+ *          graphs are to be generated and execution time is not a concern.
+ *          igraph uses the original implementation of Fabien Viger; see
+ *          http://www-rp.lip6.fr/~latapy/FV/generation.html
+ *          and the paper cited on it for the details of the algorithm.
+ *        \endclist
+ * \return Error code: 
+ *          \c IGRAPH_ENOMEM: there is not enough
+ *           memory to perform the operation.
+ *          \c IGRAPH_EINVAL: invalid method parameter, or
+ *           invalid in- and/or out-degree vectors. The degree vectors
+ *           should be non-negative, \p out_deg should sum
+ *           up to an even integer for undirected graphs; the length
+ *           and sum of \p out_deg and
+ *           \p in_deg 
+ *           should match for directed graphs.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number of edges
+ *                  for \c IGRAPH_DEGSEQ_SIMPLE. The time complexity of the
+ *                  other modes is not known.
+ * 
+ * \sa \ref igraph_barabasi_game(), \ref igraph_erdos_renyi_game(),
+ *     \ref igraph_is_degree_sequence(),
+ *     \ref igraph_is_graphical_degree_sequence()
+ * 
+ * \example examples/simple/igraph_degree_sequence_game.c
+ */
+
+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 retval;
+
+  if (in_deg && igraph_vector_empty(in_deg) && !igraph_vector_empty(out_deg)) {
+    in_deg=0;
+  }
+  if (method==IGRAPH_DEGSEQ_SIMPLE) {
+    retval=igraph_degree_sequence_game_simple(graph, out_deg, in_deg);
+  } else if (method==IGRAPH_DEGSEQ_VL) {
+    retval=igraph_degree_sequence_game_vl(graph, out_deg, in_deg);
+  } else if (method==IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE) {
+    if (in_deg == 0 || (igraph_vector_empty(in_deg) && !igraph_vector_empty(out_deg))) {
+      retval=igraph_degree_sequence_game_no_multiple_undirected(graph, out_deg);
+    } else {
+      retval=igraph_degree_sequence_game_no_multiple_directed(graph, out_deg, in_deg);
+    }
+  } else {
+    IGRAPH_ERROR("Invalid degree sequence game method", IGRAPH_EINVAL);
+  }
+
+  return retval;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_growing_random_game
+ * \brief Generates a growing random graph.
+ *
+ * </para><para>
+ * This function simulates a growing random graph. In each discrete
+ * time step a new vertex is added and a number of new edges are also
+ * added. These graphs are known to be different from standard (not
+ * growing) random graphs.
+ * \param graph Uninitialized graph object.
+ * \param n The number of vertices in the graph.
+ * \param m The number of edges to add in a time step (ie. after
+ *        adding a vertex).
+ * \param directed Boolean, whether to generate a directed graph.
+ * \param citation Boolean, if \c TRUE, the edges always
+ *        originate from the most recently added vertex.
+ * \return Error code:
+ *          \c IGRAPH_EINVAL: invalid
+ *          \p n or \p m
+ *          parameter. 
+ *
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges.
+ * 
+ * \example examples/simple/igraph_growing_random_game.c
+ */
+int igraph_growing_random_game(igraph_t *graph, igraph_integer_t n, 
+			       igraph_integer_t m, igraph_bool_t directed,
+			       igraph_bool_t citation) {
+
+  long int no_of_nodes=n;
+  long int no_of_neighbors=m;
+  long int no_of_edges;
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  
+  long int resp=0;
+
+  long int i,j;
+
+  if (n<0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (m<0) {
+    IGRAPH_ERROR("Invalid number of edges per step (m)", IGRAPH_EINVAL);
+  }
+
+  no_of_edges=(no_of_nodes-1) * no_of_neighbors;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);  
+
+  RNG_BEGIN();
+
+  for (i=1; i<no_of_nodes; i++) {
+    for (j=0; j<no_of_neighbors; j++) {
+      if (citation) {
+	long int to=RNG_INTEGER(0, i-1);
+	VECTOR(edges)[resp++] = i;
+	VECTOR(edges)[resp++] = to;
+      } else {
+	long int from=RNG_INTEGER(0, i);
+	long int to=RNG_INTEGER(1,i);
+	VECTOR(edges)[resp++] = from;
+	VECTOR(edges)[resp++] = to;
+      }
+    }
+  }
+
+  RNG_END();
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_callaway_traits_game
+ * \brief Simulate a growing network with vertex types.
+ * 
+ * </para><para>
+ * The different types of vertices prefer to connect other types of
+ * vertices with a given probability.</para><para>
+ * 
+ * </para><para>
+ * 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 \p 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
+ * \p pref_matrix. Then another two vertices are selected and this is
+ * repeated \p edges_per_step times in each time step.
+ * \param graph Pointer to an uninitialized graph.
+ * \param nodes The number of nodes in the graph.
+ * \param types Number of node types.
+ * \param edges_per_step The number of edges to be add per time step.
+ * \param type_dist Vector giving the distribution of the vertex
+ * types.
+ * \param pref_matrix Matrix giving the connection probabilities for
+ * the vertex types.
+ * \param directed Logical, whether to generate a directed graph.
+ * \return Error code. 
+ * 
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(|V|e*log(|V|)), |V| is the number of vertices, e
+ * is \p edges_per_step.
+ */
+
+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) {
+  long int i, j;
+  igraph_vector_t edges;
+  igraph_vector_t cumdist;
+  igraph_real_t maxcum;
+  igraph_vector_t nodetypes;
+
+  /* TODO: parameter checks */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&cumdist, types+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&nodetypes, nodes);
+  
+  VECTOR(cumdist)[0]=0;
+  for (i=0; i<types; i++) {
+    VECTOR(cumdist)[i+1] = VECTOR(cumdist)[i]+VECTOR(*type_dist)[i];
+  }
+  maxcum=igraph_vector_tail(&cumdist);
+
+  RNG_BEGIN();
+
+  for (i=0; i<nodes; i++) {
+    igraph_real_t uni=RNG_UNIF(0, maxcum);
+    long int type;
+    igraph_vector_binsearch(&cumdist, uni, &type);
+    VECTOR(nodetypes)[i]=type-1;
+  }    
+
+  for (i=1; i<nodes; i++) {
+    for (j=0; j<edges_per_step; j++) {
+      long int node1=RNG_INTEGER(0, i);
+      long int node2=RNG_INTEGER(0, i);
+      long int type1=(long int) VECTOR(nodetypes)[node1];
+      long int type2=(long int) VECTOR(nodetypes)[node2];
+/*    printf("unif: %f, %f, types: %li, %li\n", uni1, uni2, type1, type2); */
+      if (RNG_UNIF01() < MATRIX(*pref_matrix, type1, type2)) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, node1));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, node2));
+      }
+    }
+  }
+
+  RNG_END();
+
+  igraph_vector_destroy(&nodetypes);
+  igraph_vector_destroy(&cumdist);
+  IGRAPH_FINALLY_CLEAN(2);
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_establishment_game
+ * \brief Generates a graph with a simple growing model with vertex types.
+ * 
+ * </para><para>
+ * The simulation goes like this: a single vertex is added at each
+ * time step. This new vertex tries to connect to \p k vertices in the
+ * graph. The probability that such a connection is realized depends
+ * on the types of the vertices involved. 
+ * 
+ * \param graph Pointer to an uninitialized graph.
+ * \param nodes The number of vertices in the graph.
+ * \param types The number of vertex types.
+ * \param k The number of connections tried in each time step.
+ * \param type_dist Vector giving the distribution of vertex types.
+ * \param pref_matrix Matrix giving the connection probabilities for
+ * different vertex types.
+ * \param directed Logical, whether to generate a directed graph.
+ * \return Error code.
+ *
+ * Added in version 0.2.</para><para>
+ *
+ * Time complexity: O(|V|*k*log(|V|)), |V| is the number of vertices
+ * and k is the \p k parameter.
+ */
+
+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) {
+  
+  long int i, j;
+  igraph_vector_t edges;
+  igraph_vector_t cumdist;
+  igraph_vector_t potneis;
+  igraph_real_t maxcum;
+  igraph_vector_t nodetypes;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&cumdist, types+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&potneis, k);
+  IGRAPH_VECTOR_INIT_FINALLY(&nodetypes, nodes);
+  
+  VECTOR(cumdist)[0]=0;
+  for (i=0; i<types; i++) {
+    VECTOR(cumdist)[i+1] = VECTOR(cumdist)[i]+VECTOR(*type_dist)[i];
+  }
+  maxcum=igraph_vector_tail(&cumdist);
+
+  RNG_BEGIN();
+
+  for (i=0; i<nodes; i++) {
+    igraph_real_t uni=RNG_UNIF(0, maxcum);
+    long int type;
+    igraph_vector_binsearch(&cumdist, uni, &type);
+    VECTOR(nodetypes)[i]=type-1;
+  }
+
+  for (i=k; i<nodes; i++) {    
+    long int type1=(long int) VECTOR(nodetypes)[i];
+    igraph_random_sample(&potneis, 0, i-1, k);
+    for (j=0; j<k; j++) {
+      long int type2=(long int) VECTOR(nodetypes)[(long int)VECTOR(potneis)[j]];
+      if (RNG_UNIF01() < MATRIX(*pref_matrix, type1, type2)) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, VECTOR(potneis)[j]));
+      }
+    }
+  }
+  
+  RNG_END();
+  
+  igraph_vector_destroy(&nodetypes);
+  igraph_vector_destroy(&potneis);
+  igraph_vector_destroy(&cumdist);
+  IGRAPH_FINALLY_CLEAN(3);
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_recent_degree_game
+ * \brief Stochastic graph generator based on the number of incident edges a node has gained recently
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param n The number of vertices in the graph, this is the same as
+ *        the number of time steps. 
+ * \param power The exponent, the probability that a node gains a
+ *        new edge is proportional to the number of edges it has
+ *        gained recently (in the last \p window time steps) to \p
+ *        power.
+ * \param window Integer constant, the size of the time window to use
+ *        to count the number of recent edges.
+ * \param m Integer constant, the number of edges to add per time
+ *        step if the \p outseq parameter is a null pointer or a
+ *        zero-length vector.
+ * \param outseq The number of edges to add in each time step. This
+ *        argument is ignored if it is a null pointer or a zero length
+ *        vector, is this case the constant \p m parameter is used. 
+ * \param outpref Logical constant, if true the edges originated by a
+ *        vertex also count as recent incident edges. It is false in
+ *        most cases.
+ * \param zero_appeal Constant giving the attractiveness of the
+ *        vertices which haven't gained any edge recently. 
+ * \param directed Logical constant, whether to generate a directed
+ *        graph. 
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|*log(|V|)+|E|), |V| is the number of
+ * vertices, |E| is the number of edges in the graph.
+ *
+ */ 
+
+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) {
+
+  long int no_of_nodes=n;
+  long int no_of_neighbors=m;
+  long int no_of_edges;
+  igraph_vector_t edges;
+  long int i, j;
+  igraph_psumtree_t sumtree;
+  long int edgeptr=0;
+  igraph_vector_t degree;
+  long int time_window=window;
+  igraph_dqueue_t history;
+
+  if (n<0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (outseq != 0 && igraph_vector_size(outseq) != 0 && igraph_vector_size(outseq) != n) {
+    IGRAPH_ERROR("Invalid out degree sequence length", IGRAPH_EINVAL);
+  }
+  if ( (outseq == 0 || igraph_vector_size(outseq) == 0) && m<0) {
+    IGRAPH_ERROR("Invalid out degree", IGRAPH_EINVAL);
+  }
+
+  if (outseq==0 || igraph_vector_size(outseq) == 0) {
+    no_of_neighbors=m;
+    no_of_edges=(no_of_nodes-1)*no_of_neighbors;
+  } else {
+    no_of_edges=0;
+    for (i=1; i<igraph_vector_size(outseq); i++) {
+      no_of_edges+=VECTOR(*outseq)[i];
+    }
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&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);
+  IGRAPH_CHECK(igraph_dqueue_init(&history, 
+				  time_window*(no_of_neighbors+1)+10));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &history);
+  
+  RNG_BEGIN();
+  
+  /* first node */
+  igraph_psumtree_update(&sumtree, 0, zero_appeal);
+  igraph_dqueue_push(&history, -1);
+
+  /* and the rest */
+  for (i=1; i<no_of_nodes; i++) {
+    igraph_real_t sum;
+    long int to;
+    if (outseq != 0 && igraph_vector_size(outseq)!=0) {
+      no_of_neighbors=(long int) VECTOR(*outseq)[i];
+    }
+
+    if (i>=time_window) {
+      while ((j=(long int) igraph_dqueue_pop(&history)) != -1) {
+	VECTOR(degree)[j] -= 1;
+	igraph_psumtree_update(&sumtree, j, 
+			       pow(VECTOR(degree)[j], power)+zero_appeal);
+      }
+    }
+    
+    sum=igraph_psumtree_sum(&sumtree);
+    for (j=0; j<no_of_neighbors; j++) {
+      igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
+      VECTOR(degree)[to]++;
+      VECTOR(edges)[edgeptr++] = i;
+      VECTOR(edges)[edgeptr++] = to;
+      igraph_dqueue_push(&history, to);
+    }
+    igraph_dqueue_push(&history, -1);
+
+    /* update probabilities */
+    for (j=0; j<no_of_neighbors; j++) {
+      long int nn=(long int) VECTOR(edges)[edgeptr-2*j-1];
+      igraph_psumtree_update(&sumtree, nn,
+			     pow(VECTOR(degree)[nn], power)+zero_appeal);
+    }
+    if (outpref) {
+      VECTOR(degree)[i] += no_of_neighbors;
+      igraph_psumtree_update(&sumtree, i, 
+			     pow(VECTOR(degree)[i], power)+zero_appeal);
+    } else {
+      igraph_psumtree_update(&sumtree, i, zero_appeal);
+    }
+  }
+  
+  RNG_END();
+
+  igraph_dqueue_destroy(&history);
+  igraph_psumtree_destroy(&sumtree);
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_barabasi_aging_game
+ * \brief Preferential attachment with aging of vertices
+ * 
+ * </para><para>
+ * In this game, the probability that a node gains a new edge is
+ * given by its (in-)degree (k) and age (l). This probability has a
+ * degree dependent component multiplied by an age dependent
+ * component. The degree dependent part is: \p deg_coef times k to the
+ * power of \p pa_exp plus \p zero_deg_appeal; and the age dependent
+ * part is \p age_coef times l to the power of \p aging_exp plus \p
+ * zero_age_appeal. 
+ * 
+ * </para><para>
+ * The age is based on the number of vertices in the
+ * network and the \p aging_bin argument: vertices grew one unit older
+ * after each \p aging_bin vertices added to the network.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param nodes The number of vertices in the graph.
+ * \param m The number of edges to add in each time step. If the \p
+ *        outseq argument is not a null vector and not a zero-length
+ *        vector. 
+ * \param outseq The number of edges to add in each time step. If it
+ *        is a null pointer or a zero-length vector then it is ignored
+ *        and the \p m argument is used instead.
+ * \param outpref Logical constant, whether the edges
+ *        initiated by a vertex contribute to the probability to gain
+ *        a new edge.
+ * \param pa_exp The exponent of the preferential attachment, a small
+ *        positive number usually, the value 1 yields the classic
+ *        linear preferential attachment.
+ * \param aging_exp The exponent of the aging, this is a negative
+ *        number usually.
+ * \param aging_bin Integer constant, the number of vertices to add
+ *        before vertices in the network grew one unit older.
+ * \param zero_deg_appeal The degree dependent part of the
+ *        attractiveness of the zero degree vertices.
+ * \param zero_age_appeal The age dependent part of the attractiveness
+ *        of the vertices of age zero. This parameter is usually zero.
+ * \param deg_coef The coefficient for the degree.
+ * \param age_coef The coefficient for the age.
+ * \param directed Logical constant, whether to generate a directed
+ *        graph. 
+ * \return Error code.
+ * 
+ * Time complexity: O((|V|+|V|/aging_bin)*log(|V|)+|E|). |V| is the number
+ * of vertices, |E| the number of edges.
+ */
+
+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) {
+  long int no_of_nodes=nodes;
+  long int no_of_neighbors=m;
+  long int binwidth=nodes/aging_bin+1;
+  long int no_of_edges;
+  igraph_vector_t edges;
+  long int i, j, k;
+  igraph_psumtree_t sumtree;
+  long int edgeptr=0;
+  igraph_vector_t degree;
+
+  if (no_of_nodes<0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (outseq != 0 && igraph_vector_size(outseq) != 0 && igraph_vector_size(outseq) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid out degree sequence length", IGRAPH_EINVAL);
+  }
+  if ( (outseq == 0 || igraph_vector_size(outseq) == 0) && m<0) {
+    IGRAPH_ERROR("Invalid out degree", IGRAPH_EINVAL);
+  }
+  if (aging_bin <= 0) { 
+    IGRAPH_ERROR("Invalid aging bin", IGRAPH_EINVAL);
+  }
+
+  if (outseq==0 || igraph_vector_size(outseq) == 0) {
+    no_of_neighbors=m;
+    no_of_edges=(no_of_nodes-1)*no_of_neighbors;
+  } else {
+    no_of_edges=0;
+    for (i=1; i<igraph_vector_size(outseq); i++) {
+      no_of_edges+=VECTOR(*outseq)[i];
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&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, zero_deg_appeal*(1+zero_age_appeal));
+  
+  /* and the rest */
+  for (i=1; i<no_of_nodes; i++) {
+    igraph_real_t sum;
+    long int to;
+    if (outseq != 0 && igraph_vector_size(outseq)!=0) {
+      no_of_neighbors=(long int) VECTOR(*outseq)[i];
+    }
+    sum=igraph_psumtree_sum(&sumtree);
+    for (j=0; j<no_of_neighbors; j++) {
+      igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
+      VECTOR(degree)[to]++;
+      VECTOR(edges)[edgeptr++] = i;
+      VECTOR(edges)[edgeptr++] = to;
+    }
+    /* update probabilities */
+    for (j=0; j<no_of_neighbors; j++) {
+      long int n=(long int) VECTOR(edges)[edgeptr-2*j-1];
+      long int age=(i-n)/binwidth;
+      igraph_psumtree_update(&sumtree, n, 
+			     (deg_coef*pow(VECTOR(degree)[n], pa_exp)
+			      +zero_deg_appeal)*
+			     (age_coef*pow(age+1,aging_exp)+zero_age_appeal));
+    }
+    if (outpref) {
+      VECTOR(degree)[i] += no_of_neighbors;
+      igraph_psumtree_update(&sumtree, i, (zero_age_appeal+1)*
+			     (deg_coef*pow(VECTOR(degree)[i], pa_exp)
+			      +zero_deg_appeal));
+    } else { 
+      igraph_psumtree_update(&sumtree, i, (1+zero_age_appeal)*zero_deg_appeal);
+    }
+
+    /* aging */
+    for (k=1; i-binwidth*k+1 >= 1; k++) {
+      long int shnode=i-binwidth*k;
+      long int deg=(long int) VECTOR(degree)[shnode];
+      long int age=(i-shnode)/binwidth;
+      /* igraph_real_t old=igraph_psumtree_get(&sumtree, shnode); */
+      igraph_psumtree_update(&sumtree, shnode,
+			     (deg_coef*pow(deg, pa_exp)+zero_deg_appeal) * 
+			     (age_coef*pow(age+2, aging_exp)+zero_age_appeal));
+    }
+  }
+  
+  RNG_END();
+  
+  igraph_vector_destroy(&degree);
+  igraph_psumtree_destroy(&sumtree);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_recent_degree_aging_game
+ * \brief Preferential attachment based on the number of edges gained recently, with aging of vertices
+ * 
+ * </para><para>
+ * This game is very similar to \ref igraph_barabasi_aging_game(),
+ * except that instead of the total number of incident edges the
+ * number of edges gained in the last \p time_window time steps are
+ * counted. 
+ * 
+ * </para><para>The degree dependent part of the attractiveness is
+ * given by k to the power of \p pa_exp plus \p zero_appeal; the age
+ * dependent part is l to the power to \p aging_exp. 
+ * k is the number of edges gained in the last \p time_window time
+ * steps, l is the age of the vertex.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param nodes The number of vertices in the graph.
+ * \param m The number of edges to add in each time step. If the \p
+ *        outseq argument is not a null vector or a zero-length vector
+ *        then it is ignored.
+ * \param outseq Vector giving the number of edges to add in each time
+ *        step. If it is a null pointer or a zero-length vector then
+ *        it is ignored and the \p m argument is used.
+ * \param outpref Logical constant, if true the edges initiated by a
+ *        vertex are also counted. Normally it is false.
+ * \param pa_exp The exponent for the preferential attachment. 
+ * \param aging_exp The exponent for the aging, normally it is
+ *        negative: old vertices gain edges with less probability.
+ * \param aging_bin Integer constant, gives the scale of the aging. 
+ *        The age of the vertices is incremented by one after every \p
+ *        aging_bin vertex added.
+ * \param time_window The time window to use to count the number of 
+ *        incident edges for the vertices.
+ * \param zero_appeal The degree dependent part of the attractiveness
+ *        for zero degree vertices.
+ * \param directed Logical constant, whether to create a directed
+ *        graph. 
+ * \return Error code.
+ * 
+ * Time complexity: O((|V|+|V|/aging_bin)*log(|V|)+|E|). |V| is the number
+ * of vertices, |E| the number of edges.
+ */
+
+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 time_window,
+				    igraph_real_t zero_appeal,
+				    igraph_bool_t directed) {
+  
+  long int no_of_nodes=nodes;
+  long int no_of_neighbors=m;
+  long int binwidth=nodes/aging_bin+1;
+  long int no_of_edges;
+  igraph_vector_t edges;
+  long int i, j, k;
+  igraph_psumtree_t sumtree;
+  long int edgeptr=0;
+  igraph_vector_t degree;
+  igraph_dqueue_t history;
+  
+  if (no_of_nodes<0) {
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
+  }
+  if (outseq != 0 && igraph_vector_size(outseq) != 0 && igraph_vector_size(outseq) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid out degree sequence length", IGRAPH_EINVAL);
+  }
+  if ( (outseq == 0 || igraph_vector_size(outseq) == 0) && m<0) {
+    IGRAPH_ERROR("Invalid out degree", IGRAPH_EINVAL);
+  }
+  if (aging_bin <= 0) { 
+    IGRAPH_ERROR("Invalid aging bin", IGRAPH_EINVAL);
+  }
+
+  if (outseq==0 || igraph_vector_size(outseq) == 0) {
+    no_of_neighbors=m;
+    no_of_edges=(no_of_nodes-1)*no_of_neighbors;
+  } else {
+    no_of_edges=0;
+    for (i=1; i<igraph_vector_size(outseq); i++) {
+      no_of_edges+=VECTOR(*outseq)[i];
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&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);
+  IGRAPH_CHECK(igraph_dqueue_init(&history, 
+				  time_window*(no_of_neighbors+1)+10));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &history);
+  
+  RNG_BEGIN();
+  
+  /* first node */
+  igraph_psumtree_update(&sumtree, 0, zero_appeal);
+  igraph_dqueue_push(&history, -1);
+  
+  /* and the rest */
+  for (i=1; i<no_of_nodes; i++) {
+    igraph_real_t sum;
+    long int to;
+    if (outseq != 0 && igraph_vector_size(outseq)!=0) {
+      no_of_neighbors=(long int) VECTOR(*outseq)[i];
+    }
+
+    if (i>=time_window) {
+      while ((j=(long int) igraph_dqueue_pop(&history)) != -1) {
+	long int age=(i-j)/binwidth;
+	VECTOR(degree)[j] -= 1;
+	igraph_psumtree_update(&sumtree, j, 
+			       (pow(VECTOR(degree)[j], pa_exp)+zero_appeal)*
+			       pow(age+1, aging_exp));
+      }
+    }
+
+    sum=igraph_psumtree_sum(&sumtree);
+    for (j=0; j<no_of_neighbors; j++) {
+      igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
+      VECTOR(degree)[to]++;
+      VECTOR(edges)[edgeptr++] = i;
+      VECTOR(edges)[edgeptr++] = to;
+      igraph_dqueue_push(&history, to);
+    }
+    igraph_dqueue_push(&history, -1);
+    
+    /* update probabilities */
+    for (j=0; j<no_of_neighbors; j++) {
+      long int n=(long int) VECTOR(edges)[edgeptr-2*j-1];
+      long int age=(i-n)/binwidth;
+      igraph_psumtree_update(&sumtree, n, 
+			     (pow(VECTOR(degree)[n], pa_exp)+zero_appeal)*
+			     pow(age+1,aging_exp));
+    }
+    if (outpref) {
+      VECTOR(degree)[i] += no_of_neighbors;
+      igraph_psumtree_update(&sumtree, i,
+			     pow(VECTOR(degree)[i], pa_exp)+zero_appeal);
+    } else { 
+      igraph_psumtree_update(&sumtree, i, zero_appeal);
+    }
+
+    /* aging */
+    for (k=1; i-binwidth*k+1 >= 1; k++) {
+      long int shnode=i-binwidth*k;
+      long int deg=(long int) VECTOR(degree)[shnode];
+      long int age=(i-shnode)/binwidth;
+      igraph_psumtree_update(&sumtree, shnode,
+			     (pow(deg, pa_exp)+zero_appeal) *
+			     pow(age+2, aging_exp));
+    }
+  }
+  
+  RNG_END();
+  
+  igraph_dqueue_destroy(&history);
+  igraph_vector_destroy(&degree);
+  igraph_psumtree_destroy(&sumtree);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_grg_game
+ * \brief Generating geometric random graphs.
+ *
+ * A geometric random graph is created by dropping points (=vertices)
+ * randomly to the unit square and then connecting all those pairs
+ * which are less than \c radius apart in Euclidean norm.
+ * 
+ * </para><para>
+ * Original code contributed by Keith Briggs, thanks Keith.
+ * \param graph Pointer to an uninitialized graph object,
+ * \param nodes The number of vertices in the graph.
+ * \param radius The radius within which the vertices will be connected.
+ * \param torus Logical constant, if true periodic boundary conditions
+ *        will be used, ie. the vertices are assumed to be on a torus 
+ *        instead of a square.
+ * \return Error code.
+ * 
+ * Time complexity: TODO, less than O(|V|^2+|E|).
+ * 
+ * \example examples/simple/igraph_grg_game.c
+ */
+				    
+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) {
+  
+  long int i;
+  igraph_vector_t myx, myy, *xx=&myx, *yy=&myy, edges;
+  igraph_real_t r2=radius*radius;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, nodes));
+
+  if (x) { 
+    xx=x;
+    IGRAPH_CHECK(igraph_vector_resize(xx, nodes));
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(xx, nodes);
+  }
+  if (y) {
+    yy=y;
+    IGRAPH_CHECK(igraph_vector_resize(yy, nodes));
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(yy, nodes);
+  }
+  
+  RNG_BEGIN();
+  
+  for (i=0; i<nodes; i++) {
+    VECTOR(*xx)[i]=RNG_UNIF01();
+    VECTOR(*yy)[i]=RNG_UNIF01();
+  }
+  
+  RNG_END();
+
+  igraph_vector_sort(xx);
+
+  if (!torus) {
+    for (i=0; i<nodes; i++) {
+      igraph_real_t xx1=VECTOR(*xx)[i];
+      igraph_real_t yy1=VECTOR(*yy)[i];
+      long int j=i+1;
+      igraph_real_t dx, dy;
+      while ( j<nodes && (dx=VECTOR(*xx)[j] - xx1) < radius) {
+	dy=VECTOR(*yy)[j]-yy1;
+	if (dx*dx+dy*dy < r2) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+	}
+	j++;
+      }
+    }
+  } else { 
+    for (i=0; i<nodes; i++) {
+      igraph_real_t xx1=VECTOR(*xx)[i];
+      igraph_real_t yy1=VECTOR(*yy)[i];
+      long int j=i+1;
+      igraph_real_t dx, dy;
+      while ( j<nodes && (dx=VECTOR(*xx)[j] - xx1) < radius) {
+	dy=fabs(VECTOR(*yy)[j]-yy1);
+	if (dx > 0.5) {
+	  dx=1-dx;
+	}
+	if (dy > 0.5) {
+	  dy=1-dy;
+	}
+	if (dx*dx+dy*dy < r2) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+	}
+	j++;
+      }
+      if (j==nodes) {
+	j=0;      
+	while (j<i && (dx=1-xx1+VECTOR(*xx)[j]) < radius && 
+	       xx1-VECTOR(*xx)[j]>=radius) {
+	  dy=fabs(VECTOR(*yy)[j]-yy1);
+	  if (dy > 0.5) {
+	    dy=1-dy;
+	  }
+	  if (dx*dx+dy*dy < r2) {
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+	  }
+	  j++;
+	}
+      }
+    }
+  }
+  
+  if (!y) {
+    igraph_vector_destroy(yy);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (!x) {
+    igraph_vector_destroy(xx);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, IGRAPH_UNDIRECTED));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+
+void igraph_i_preference_game_free_vids_by_type(igraph_vector_ptr_t *vecs);
+
+void igraph_i_preference_game_free_vids_by_type(igraph_vector_ptr_t *vecs) {
+  int i=0, n;
+  igraph_vector_t *v;
+
+  n = (int) igraph_vector_ptr_size(vecs);
+  for (i=0; i<n; i++) {
+    v = (igraph_vector_t*)VECTOR(*vecs)[i];
+	if (v) igraph_vector_destroy(v);
+  }
+  igraph_vector_ptr_destroy_all(vecs);
+}
+
+/**
+ * \function igraph_preference_game
+ * \brief Generates a graph with vertex types and connection preferences 
+ * 
+ * </para><para>
+ * This is practically the nongrowing variant of \ref
+ * igraph_establishment_game. A given number of vertices are
+ * generated. Every vertex is assigned to a vertex type according to
+ * the given type probabilities. Finally, every
+ * vertex pair is evaluated and an edge is created between them with a
+ * probability depending on the types of the vertices involved.
+ * 
+ * </para><para>
+ * In other words, this function generates a graph according to a
+ * block-model. Vertices are divided into groups (or blocks), and
+ * the probability the two vertices are connected depends on their
+ * groups only.
+ * 
+ * \param graph Pointer to an uninitialized graph.
+ * \param nodes The number of vertices in the graph.
+ * \param types The number of vertex types.
+ * \param type_dist Vector giving the distribution of vertex types. If
+ *   \c NULL, all vertex types will have equal probability. See also the
+ *   \c fixed_sizes argument.
+ * \param fixed_sizes Boolean. If true, then the number of vertices with a 
+ *   given vertex type is fixed and the \c type_dist argument gives these
+ *   numbers for each vertex type. If true, and \c type_dist is \c NULL, 
+ *   then the function tries to make vertex groups of the same size. If this 
+ *   is not possible, then some groups will have an extra vertex.
+ * \param pref_matrix Matrix giving the connection probabilities for
+ *   different vertex types. This should be symmetric if the requested
+ *   graph is undirected.
+ * \param node_type_vec A vector where the individual generated vertex types
+ *   will be stored. If \c NULL , the vertex types won't be saved.
+ * \param directed Logical, whether to generate a directed graph. If undirected
+ *   graphs are requested, only the lower left triangle of the preference
+ *   matrix is considered.
+ * \param loops Logical, whether loop edges are allowed.
+ * \return Error code.
+ *
+ * Added in version 0.3.</para><para>
+ *
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges in the graph.
+ * 
+ * \sa igraph_establishment_game()
+ * 
+ * \example examples/simple/igraph_preference_game.c
+ */
+
+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) {
+  
+  long int i, j;
+  igraph_vector_t edges, s;
+  igraph_vector_t* nodetypes;
+  igraph_vector_ptr_t vids_by_type;
+  igraph_real_t maxcum, maxedges;
+
+  if (types < 1) IGRAPH_ERROR("types must be >= 1", IGRAPH_EINVAL);
+  if (nodes < 0) IGRAPH_ERROR("nodes must be >= 0", IGRAPH_EINVAL);
+  if (type_dist && igraph_vector_size(type_dist) != types) {
+    if (igraph_vector_size(type_dist) > types)
+      IGRAPH_WARNING("length of type_dist > types, type_dist will be trimmed");
+    else
+      IGRAPH_ERROR("type_dist vector too short", IGRAPH_EINVAL);
+  }
+  if (igraph_matrix_nrow(pref_matrix) < types ||
+      igraph_matrix_ncol(pref_matrix) < types)
+    IGRAPH_ERROR("pref_matrix too small", IGRAPH_EINVAL);
+
+  if (fixed_sizes && type_dist) {
+    if (igraph_vector_sum(type_dist) != nodes) {
+      IGRAPH_ERROR("Invalid group sizes, their sum must match the number"
+		   " of vertices", IGRAPH_EINVAL);
+    }
+  }
+
+  if (node_type_vec) {
+    IGRAPH_CHECK(igraph_vector_resize(node_type_vec, nodes));
+    nodetypes = node_type_vec;
+  } else {
+    nodetypes = igraph_Calloc(1, igraph_vector_t);
+    if (nodetypes == 0) {
+      IGRAPH_ERROR("preference_game failed", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, nodetypes);
+    IGRAPH_VECTOR_INIT_FINALLY(nodetypes, nodes);
+  }
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&vids_by_type, types));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &vids_by_type);
+  for (i=0; i<types; i++) {
+	  VECTOR(vids_by_type)[i] = igraph_Calloc(1, igraph_vector_t);
+	  if (VECTOR(vids_by_type)[i] == 0) {
+	    IGRAPH_ERROR("preference_game failed", IGRAPH_ENOMEM);
+	  }
+	  IGRAPH_CHECK(igraph_vector_init(VECTOR(vids_by_type)[i], 0));
+  }
+  IGRAPH_FINALLY_CLEAN(1);   /* removing igraph_vector_ptr_destroy_all */
+  IGRAPH_FINALLY(igraph_i_preference_game_free_vids_by_type, &vids_by_type);
+
+  RNG_BEGIN();
+    
+  if (!fixed_sizes) {
+
+    igraph_vector_t cumdist;
+    IGRAPH_VECTOR_INIT_FINALLY(&cumdist, types+1);
+
+    VECTOR(cumdist)[0]=0;
+    if (type_dist) {
+      for (i=0; i<types; i++) 
+	VECTOR(cumdist)[i+1] = VECTOR(cumdist)[i]+VECTOR(*type_dist)[i];
+    } else {
+      for (i=0; i<types; i++) VECTOR(cumdist)[i+1] = i+1;
+    }
+    maxcum=igraph_vector_tail(&cumdist);
+
+    for (i=0; i<nodes; i++) {
+      long int type1;
+      igraph_real_t uni1=RNG_UNIF(0, maxcum);
+      igraph_vector_binsearch(&cumdist, uni1, &type1);
+      VECTOR(*nodetypes)[i] = type1-1;
+      IGRAPH_CHECK(igraph_vector_push_back(
+	    (igraph_vector_t*)VECTOR(vids_by_type)[type1-1], i));
+    }
+
+    igraph_vector_destroy(&cumdist);
+    IGRAPH_FINALLY_CLEAN(1);
+
+  } else {
+
+    int an=0;
+    if (type_dist) {
+      for (i=0; i<types; i++) {
+	int no=(int) VECTOR(*type_dist)[i];
+	igraph_vector_t *v=VECTOR(vids_by_type)[i];
+	for (j=0; j<no && an < nodes; j++) {
+	  VECTOR(*nodetypes)[an] = i;
+	  IGRAPH_CHECK(igraph_vector_push_back(v, an));
+	  an++;
+	}
+      }
+    } else {
+      int fixno=(int) ceil( (double)nodes / types);
+      for (i=0; i<types; i++) {
+	igraph_vector_t *v=VECTOR(vids_by_type)[i];
+	for (j=0; j<fixno && an < nodes; j++) {
+	  VECTOR(*nodetypes)[an++] = i;
+	  IGRAPH_CHECK(igraph_vector_push_back(v, an));
+	  an++;
+	}
+      }
+    }
+
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+
+  for (i=0; i<types; i++) {
+    for (j=0; j<types; j++) {
+      /* Generating the random subgraph between vertices of type i and j */
+      long int k, l;
+      igraph_real_t p, last;
+      igraph_vector_t *v1, *v2;
+      long int v1_size, v2_size;
+      
+      IGRAPH_ALLOW_INTERRUPTION();
+
+      v1 = (igraph_vector_t*)VECTOR(vids_by_type)[i];
+      v2 = (igraph_vector_t*)VECTOR(vids_by_type)[j];
+      v1_size = igraph_vector_size(v1);
+      v2_size = igraph_vector_size(v2);
+
+      p = MATRIX(*pref_matrix, i, j);
+      igraph_vector_clear(&s);
+      if (i != j) {
+        /* The two vertex sets are disjoint, this is the easier case */
+        if (i > j && !directed) continue;
+        maxedges = v1_size * v2_size;
+      } else {
+        if (directed && loops) maxedges = v1_size * v1_size;
+        else if (directed && !loops) maxedges = v1_size * (v1_size-1);
+        else if (!directed && loops) maxedges = v1_size * (v1_size+1)/2;
+        else maxedges = v1_size * (v1_size-1)/2;
+      }
+
+      IGRAPH_CHECK(igraph_vector_reserve(&s, (long int) (maxedges*p*1.1)));
+        
+      last=RNG_GEOM(p);
+      while (last < maxedges) {
+        IGRAPH_CHECK(igraph_vector_push_back(&s, last));
+        last += RNG_GEOM(p);
+        last += 1;
+      }
+      l = igraph_vector_size(&s);
+        
+      IGRAPH_CHECK(igraph_vector_reserve(&edges, igraph_vector_size(&edges)+l*2));
+      
+      if (i != j) {
+        /* Generating the subgraph between vertices of type i and j */
+        for (k=0; k<l; k++) {
+          long int to=(long int) floor(VECTOR(s)[k]/v1_size);
+          long int from=(long int) (VECTOR(s)[k]-((igraph_real_t)to)*v1_size);
+          igraph_vector_push_back(&edges, VECTOR(*v1)[from]);
+          igraph_vector_push_back(&edges, VECTOR(*v2)[to]);
+        }
+      } else {
+        /* Generating the subgraph among vertices of type i */
+        if (directed && loops) {
+          for (k=0; k<l; k++) {
+            long int to=(long int) floor(VECTOR(s)[k]/v1_size);
+            long int from=(long int) (VECTOR(s)[k]-((igraph_real_t)to)*v1_size);
+            igraph_vector_push_back(&edges, VECTOR(*v1)[from]);
+            igraph_vector_push_back(&edges, VECTOR(*v1)[to]);
+          }
+        } else if (directed && !loops) {
+          for (k=0; k<l; k++) {
+            long int to=(long int) floor(VECTOR(s)[k]/v1_size);
+            long int from=(long int) (VECTOR(s)[k]-((igraph_real_t)to)*v1_size);
+            if (from==to) to=v1_size-1;
+            igraph_vector_push_back(&edges, VECTOR(*v1)[from]); 
+            igraph_vector_push_back(&edges, VECTOR(*v1)[to]);
+          }
+        } else if (!directed && loops) {
+          for (k=0; k<l; k++) {
+            long int to=(long int) floor((sqrt(8*VECTOR(s)[k]+1)-1)/2);
+            long int from=(long int) (VECTOR(s)[k]-(((igraph_real_t)to)*(to+1))/2);
+            igraph_vector_push_back(&edges, VECTOR(*v1)[from]);
+            igraph_vector_push_back(&edges, VECTOR(*v1)[to]);
+          }
+        } else {
+          for (k=0; k<l; k++) {
+            long int to=(long int) floor((sqrt(8*VECTOR(s)[k]+1)+1)/2);
+            long int from=(long int) (VECTOR(s)[k]-(((igraph_real_t)to)*(to-1))/2);
+            igraph_vector_push_back(&edges, VECTOR(*v1)[from]);
+            igraph_vector_push_back(&edges, VECTOR(*v1)[to]);
+          }
+        }
+      }
+    }
+  }
+
+  RNG_END();
+
+  igraph_vector_destroy(&s);
+  igraph_i_preference_game_free_vids_by_type(&vids_by_type);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (node_type_vec == 0) {
+    igraph_vector_destroy(nodetypes);
+    igraph_Free(nodetypes);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_asymmetric_preference_game
+ * \brief Generates a graph with asymmetric vertex types and connection preferences 
+ * 
+ * </para><para>
+ * This is the asymmetric variant of \ref igraph_preference_game() .
+ * A given number of vertices are generated. Every vertex is assigned to an
+ * "incoming" and an "outgoing" vertex type according to the given joint
+ * type probabilities. Finally, every vertex pair is evaluated and a
+ * directed edge is created between them with a probability depending on the
+ * "outgoing" type of the source vertex and the "incoming" type of the target
+ * vertex.
+ * 
+ * \param graph Pointer to an uninitialized graph.
+ * \param nodes The number of vertices in the graph.
+ * \param types The number of vertex types.
+ * \param type_dist_matrix Matrix giving the joint distribution of vertex types.
+ *   If null, incoming and outgoing vertex types are independent and uniformly
+ *   distributed.
+ * \param pref_matrix Matrix giving the connection probabilities for
+ *   different vertex types.
+ * \param node_type_in_vec A vector where the individual generated "incoming"
+ *   vertex types will be stored. If NULL, the vertex types won't be saved.
+ * \param node_type_out_vec A vector where the individual generated "outgoing"
+ *   vertex types will be stored. If NULL, the vertex types won't be saved.
+ * \param loops Logical, whether loop edges are allowed.
+ * \return Error code.
+ *
+ * Added in version 0.3.</para><para>
+ *
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges in the graph.
+ * 
+ * \sa \ref igraph_preference_game()
+ */
+
+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) {
+  
+  long int i, j, k;
+  igraph_vector_t edges, cumdist, s, intersect;
+  igraph_vector_t *nodetypes_in;
+  igraph_vector_t *nodetypes_out;
+  igraph_vector_ptr_t vids_by_intype, vids_by_outtype;
+  igraph_real_t maxcum, maxedges;
+  
+  if (types < 1) IGRAPH_ERROR("types must be >= 1", IGRAPH_EINVAL);
+  if (nodes < 0) IGRAPH_ERROR("nodes must be >= 0", IGRAPH_EINVAL);
+  if (type_dist_matrix) {
+    if (igraph_matrix_nrow(type_dist_matrix) < types ||
+        igraph_matrix_ncol(type_dist_matrix) < types)
+      IGRAPH_ERROR("type_dist_matrix too small", IGRAPH_EINVAL);
+    else if (igraph_matrix_nrow(type_dist_matrix) > types ||
+        igraph_matrix_ncol(type_dist_matrix) > types)
+      IGRAPH_WARNING("type_dist_matrix will be trimmed");
+  }
+  if (igraph_matrix_nrow(pref_matrix) < types ||
+      igraph_matrix_ncol(pref_matrix) < types)
+    IGRAPH_ERROR("pref_matrix too small", IGRAPH_EINVAL);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&cumdist, types*types+1);
+
+  if (node_type_in_vec) {
+    nodetypes_in=node_type_in_vec;
+    IGRAPH_CHECK(igraph_vector_resize(nodetypes_in, nodes));
+  } else {
+    nodetypes_in = igraph_Calloc(1, igraph_vector_t);
+    if (nodetypes_in == 0) {
+      IGRAPH_ERROR("asymmetric_preference_game failed", IGRAPH_ENOMEM);
+    }
+    IGRAPH_VECTOR_INIT_FINALLY(nodetypes_in, nodes);
+  }
+   
+  if (node_type_out_vec) {
+    nodetypes_out=node_type_out_vec;
+    IGRAPH_CHECK(igraph_vector_resize(nodetypes_out, nodes));
+  } else {
+    nodetypes_out = igraph_Calloc(1, igraph_vector_t);
+    if (nodetypes_out == 0) {
+      IGRAPH_ERROR("asymmetric_preference_game failed", IGRAPH_ENOMEM);
+    }
+    IGRAPH_VECTOR_INIT_FINALLY(nodetypes_out, nodes);
+  }
+   
+  IGRAPH_CHECK(igraph_vector_ptr_init(&vids_by_intype, types));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &vids_by_intype);
+  IGRAPH_CHECK(igraph_vector_ptr_init(&vids_by_outtype, types));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &vids_by_outtype);
+  for (i=0; i<types; i++) {
+	  VECTOR(vids_by_intype)[i] = igraph_Calloc(1, igraph_vector_t);
+	  VECTOR(vids_by_outtype)[i] = igraph_Calloc(1, igraph_vector_t);
+	  if (VECTOR(vids_by_intype)[i] == 0 || VECTOR(vids_by_outtype)[i] == 0) {
+	    IGRAPH_ERROR("asymmetric_preference_game failed", IGRAPH_ENOMEM);
+	  }
+	  IGRAPH_CHECK(igraph_vector_init(VECTOR(vids_by_intype)[i], 0));
+	  IGRAPH_CHECK(igraph_vector_init(VECTOR(vids_by_outtype)[i], 0));
+  }
+  IGRAPH_FINALLY_CLEAN(2);   /* removing igraph_vector_ptr_destroy_all */
+  IGRAPH_FINALLY(igraph_i_preference_game_free_vids_by_type, &vids_by_intype);
+  IGRAPH_FINALLY(igraph_i_preference_game_free_vids_by_type, &vids_by_outtype);
+
+  VECTOR(cumdist)[0]=0;
+  if (type_dist_matrix) {
+    for (i=0, k=0; i<types; i++) {
+      for (j=0; j<types; j++, k++) {
+        VECTOR(cumdist)[k+1] = VECTOR(cumdist)[k]+MATRIX(*type_dist_matrix, i, j);
+      }
+    }
+  } else {
+    for (i=0; i<types*types; i++) VECTOR(cumdist)[i+1] = i+1;
+  }
+  maxcum=igraph_vector_tail(&cumdist);
+
+  RNG_BEGIN();
+
+  for (i=0; i<nodes; i++) {
+    long int type1, type2;
+    igraph_real_t uni1=RNG_UNIF(0, maxcum);
+    igraph_vector_binsearch(&cumdist, uni1, &type1);
+    type2 = (type1-1) % (int)types;
+    type1 = (type1-1) / (int)types;
+    VECTOR(*nodetypes_in)[i] = type1; 
+    VECTOR(*nodetypes_out)[i] = type2; 
+    IGRAPH_CHECK(igraph_vector_push_back(
+	    (igraph_vector_t*)VECTOR(vids_by_intype)[type1], i));
+    IGRAPH_CHECK(igraph_vector_push_back(
+	    (igraph_vector_t*)VECTOR(vids_by_outtype)[type2], i));
+  }
+
+  igraph_vector_destroy(&cumdist);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&intersect, 0);
+  for (i=0; i<types; i++) {
+    for (j=0; j<types; j++) {
+      long int kk, l, c;
+      igraph_real_t p, last;
+      igraph_vector_t *v1, *v2;
+      long int v1_size, v2_size;
+
+      IGRAPH_ALLOW_INTERRUPTION();
+      
+      v1 = (igraph_vector_t*)VECTOR(vids_by_outtype)[i];
+      v2 = (igraph_vector_t*)VECTOR(vids_by_intype)[j];
+      v1_size = igraph_vector_size(v1);
+      v2_size = igraph_vector_size(v2);
+
+      maxedges = v1_size * v2_size;
+      if (!loops) {
+        IGRAPH_CHECK(igraph_vector_intersect_sorted(v1, v2, &intersect));
+        c = igraph_vector_size(&intersect);
+        maxedges -= c; 
+      }
+
+      p = MATRIX(*pref_matrix, i, j);
+      igraph_vector_clear(&s);
+      IGRAPH_CHECK(igraph_vector_reserve(&s, (long int) (maxedges*p*1.1)));
+        
+      last=RNG_GEOM(p);
+      while (last < maxedges) {
+        IGRAPH_CHECK(igraph_vector_push_back(&s, last));
+        last += RNG_GEOM(p);
+        last += 1;
+      }
+      l = igraph_vector_size(&s);
+        
+      IGRAPH_CHECK(igraph_vector_reserve(&edges, igraph_vector_size(&edges)+l*2));
+
+      if (!loops && c>0) {
+          for (kk=0; kk<l; kk++) {
+            long int to=(long int) floor(VECTOR(s)[kk]/v1_size);
+            long int from=(long int) (VECTOR(s)[kk]-((igraph_real_t)to)*v1_size);
+            if (VECTOR(*v1)[from] == VECTOR(*v2)[to]) {
+              /* remap loop edges */
+              to = v2_size-1;
+              igraph_vector_binsearch(&intersect, VECTOR(*v1)[from], &c);
+              from = v1_size-1;
+              if (VECTOR(*v1)[from] == VECTOR(*v2)[to]) from--;
+              while (c>0) {
+                c--; from--;
+                if (VECTOR(*v1)[from] == VECTOR(*v2)[to]) from--;
+              }
+            }
+            igraph_vector_push_back(&edges, VECTOR(*v1)[from]); 
+            igraph_vector_push_back(&edges, VECTOR(*v2)[to]);
+          }
+      } else {
+        for (kk=0; kk<l; kk++) {
+          long int to=(long int) floor(VECTOR(s)[kk]/v1_size);
+          long int from=(long int) (VECTOR(s)[kk]-((igraph_real_t)to)*v1_size);
+          igraph_vector_push_back(&edges, VECTOR(*v1)[from]);
+          igraph_vector_push_back(&edges, VECTOR(*v2)[to]);
+        }
+      }
+    }
+  }
+
+  RNG_END();
+  
+  igraph_vector_destroy(&s);
+  igraph_vector_destroy(&intersect);
+  igraph_i_preference_game_free_vids_by_type(&vids_by_intype);
+  igraph_i_preference_game_free_vids_by_type(&vids_by_outtype);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  if (node_type_out_vec == 0) {
+    igraph_vector_destroy(nodetypes_out);
+    igraph_Free(nodetypes_out);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+   
+  if (node_type_in_vec == 0) {
+    igraph_vector_destroy(nodetypes_in);
+    igraph_Free(nodetypes_in);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, 1));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_real_t prob,
+				      igraph_bool_t loops, 
+				      igraph_vector_t *edges);
+
+int igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_real_t prob,
+				      igraph_bool_t loops, 
+				      igraph_vector_t *edges) {
+  
+  int no_verts=igraph_vcount(graph);
+  int no_edges=igraph_ecount(graph);
+  igraph_vector_t eorder, tmp;
+  igraph_vector_int_t first, next, prev, marked;
+  int i, to_rewire, last_other=-1;
+
+  /* Create our special graph representation */
+
+# define ADD_STUB(vertex, stub)	do {				\
+    if (VECTOR(first)[(vertex)]) {				\
+      VECTOR(prev)[(int) VECTOR(first)[(vertex)]-1]=(stub)+1;	\
+    }								\
+    VECTOR(next)[(stub)]=VECTOR(first)[(vertex)];		\
+    VECTOR(prev)[(stub)]=0;					\
+    VECTOR(first)[(vertex)]=(stub)+1;				\
+  } while (0)
+
+# define DEL_STUB(vertex, stub) do {					\
+    if (VECTOR(next)[(stub)]) {						\
+      VECTOR(prev)[VECTOR(next)[(stub)]-1]=VECTOR(prev)[(stub)];	\
+    }									\
+    if (VECTOR(prev)[(stub)]) {						\
+      VECTOR(next)[VECTOR(prev)[(stub)]-1]=VECTOR(next)[(stub)];	\
+    } else {								\
+      VECTOR(first)[(vertex)]=VECTOR(next)[(stub)];			\
+    }									\
+  } while (0)
+  
+# define MARK_NEIGHBORS(vertex) do {				\
+    int xxx_ =VECTOR(first)[(vertex)];				\
+    while (xxx_) {						\
+      int o= (int) VECTOR(*edges)[xxx_ % 2 ? xxx_ : xxx_-2];	\
+      VECTOR(marked)[o]=other+1;				\
+      xxx_=VECTOR(next)[xxx_-1];				\
+    }								\
+  } while (0)
+  
+  IGRAPH_CHECK(igraph_vector_int_init(&first, no_verts));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &first);
+  IGRAPH_CHECK(igraph_vector_int_init(&next, no_edges*2));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &next);  
+  IGRAPH_CHECK(igraph_vector_int_init(&prev, no_edges*2));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &prev);
+  IGRAPH_CHECK(igraph_get_edgelist(graph, edges, /*bycol=*/ 0));
+  IGRAPH_VECTOR_INIT_FINALLY(&eorder, no_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, no_edges);
+  for (i=0; i<no_edges; i++) {
+    int idx1=2*i, idx2=idx1+1, 
+      from=(int) VECTOR(*edges)[idx1], to=(int) VECTOR(*edges)[idx2];
+    VECTOR(tmp)[i]=from;
+    ADD_STUB(from, idx1);
+    ADD_STUB(to, idx2);
+  }
+  IGRAPH_CHECK(igraph_vector_order1(&tmp, &eorder, no_verts));
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_verts));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
+
+  /* Rewire the stubs, part I */
+
+  to_rewire=(int) RNG_GEOM(prob);
+  while (to_rewire < no_edges) {
+    int stub=(int) (2*VECTOR(eorder)[to_rewire]+1);
+    int v=(int) VECTOR(*edges)[stub];
+    int ostub= stub-1;
+    int other= (int) VECTOR(*edges)[ostub];
+    int pot;
+    if (last_other != other) { MARK_NEIGHBORS(other); }
+    /* Do the rewiring */
+    do {
+      if (loops) {
+	pot=(int) RNG_INTEGER(0, no_verts-1);
+      } else {
+	pot=(int) RNG_INTEGER(0, no_verts-2);
+	pot= pot != other ? pot : no_verts-1;
+      }
+    } while (VECTOR(marked)[pot] == other+1 && pot != v);
+    
+    if (pot != v) {
+      DEL_STUB(v, stub);
+      ADD_STUB(pot, stub);
+      VECTOR(marked)[v]=0;
+      VECTOR(marked)[pot]=other+1;
+      VECTOR(*edges)[stub]=pot;
+    }
+    
+    to_rewire += RNG_GEOM(prob)+1;    
+    last_other=other;
+  }
+
+  /* Create the new index, from the potentially rewired stubs */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, no_edges);
+  for (i=0; i<no_edges; i++) {
+    VECTOR(tmp)[i]=VECTOR(*edges)[2*i+1];
+  }
+  IGRAPH_CHECK(igraph_vector_order1(&tmp, &eorder, no_verts));
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Rewire the stubs, part II */
+
+  igraph_vector_int_null(&marked);
+  last_other=-1;
+
+  to_rewire=(int) RNG_GEOM(prob);
+  while (to_rewire < no_edges) {
+    int stub=(int) (2*VECTOR(eorder)[to_rewire]);
+    int v=(int) VECTOR(*edges)[stub];
+    int ostub= stub+1;
+    int other= (int) VECTOR(*edges)[ostub];
+    int pot;
+    if (last_other != other) { MARK_NEIGHBORS(other); }
+    /* Do the rewiring */
+    do {
+      if (loops) {
+	pot=(int) RNG_INTEGER(0, no_verts-1);
+      } else {
+	pot=(int) RNG_INTEGER(0, no_verts-2);
+	pot= pot != other ? pot : no_verts-1;
+      }
+    } while (VECTOR(marked)[pot] == other+1 && pot != v);
+    if (pot != v) {
+      DEL_STUB(v, stub);
+      ADD_STUB(pot, stub);
+      VECTOR(marked)[v]=0;
+      VECTOR(marked)[pot]=other+1;
+      VECTOR(*edges)[stub]=pot;
+    }
+    
+    to_rewire += RNG_GEOM(prob)+1;    
+    last_other=other;
+  }  
+
+  igraph_vector_int_destroy(&marked);
+  igraph_vector_int_destroy(&prev);
+  igraph_vector_int_destroy(&next);
+  igraph_vector_int_destroy(&first);
+  igraph_vector_destroy(&eorder);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+#undef ADD_STUB
+#undef DEL_STUB
+#undef MARK_NEIGHBORS
+
+/**
+ * \function igraph_rewire_edges
+ * \brief Rewire the edges of a graph with constant probability
+ * 
+ * This function rewires the edges of a graph with a constant
+ * probability. More precisely each end point of each edge is rewired
+ * to a uniformly randomly chosen vertex with constant probability \p
+ * prob.
+ * 
+ * </para><para> Note that this function modifies the input \p graph,
+ * call \ref igraph_copy() if you want to keep it.
+ * 
+ * \param graph The input graph, this will be rewired, it can be
+ *    directed or undirected.
+ * \param prob The rewiring probability a constant between zero and
+ *    one (inclusive).
+ * \param loops Boolean, whether loop edges are allowed in the new 
+ *    graph, or not.
+ * \param multiple Boolean, whether multiple edges are allowed in the 
+ *    new graph.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_watts_strogatz_game() uses this function for the
+ * rewiring.
+ * 
+ * Time complexity: O(|V|+|E|).
+ */
+
+int igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, 
+			igraph_bool_t loops, igraph_bool_t multiple) {
+
+  igraph_t newgraph;
+  long int no_of_edges=igraph_ecount(graph);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int endpoints=no_of_edges*2;
+  long int to_rewire;
+  igraph_vector_t edges;
+  
+  if (prob < 0 || prob > 1) {
+    IGRAPH_ERROR("Rewiring probability should be between zero and one",
+		 IGRAPH_EINVAL);
+  }
+
+  if (prob == 0) {
+    /* This is easy, just leave things as they are */
+    return IGRAPH_SUCCESS;
+  }
+    
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, endpoints);
+    
+  RNG_BEGIN();
+
+  if (prob != 0 && no_of_edges > 0) {
+    if (multiple) {      
+      /* If multiple edges are allowed, then there is an easy and fast
+	 method. Each endpoint of an edge is rewired with probability p,
+	 so the "skips" between the really rewired endpoints follow a 
+	 geometric distribution. */
+      IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
+      to_rewire=(long int) RNG_GEOM(prob);
+      while (to_rewire < endpoints) {
+	if (loops) {
+	  VECTOR(edges)[to_rewire] = RNG_INTEGER(0, no_of_nodes-1);
+	} else {
+	  long int opos = to_rewire % 2 ? to_rewire-1 : to_rewire+1;
+	  long int nei= (long int) VECTOR(edges)[opos];
+	  long int r=RNG_INTEGER(0, no_of_nodes-2);
+	  VECTOR(edges)[ to_rewire ] = (r != nei ? r : no_of_nodes-1);
+	}
+	to_rewire += RNG_GEOM(prob)+1;
+      }
+
+    } else {
+      IGRAPH_CHECK(igraph_i_rewire_edges_no_multiple(graph, prob, loops, 
+						     &edges));
+    }
+  }
+  
+  RNG_END();
+
+  IGRAPH_CHECK(igraph_create(&newgraph, &edges, (igraph_integer_t) no_of_nodes, 
+			     igraph_is_directed(graph)));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1); 
+    
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+  IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
+  IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_destroy(graph);
+  *graph=newgraph;
+  
+  return 0;
+}
+
+/**
+ * \function igraph_watts_strogatz_game
+ * \brief The Watts-Strogatz small-world model
+ * 
+ * This function generates a graph according to the Watts-Strogatz
+ * model of small-world networks. The graph is obtained by creating a
+ * circular undirected lattice and then rewire the edges randomly with
+ * a constant probability.
+ * 
+ * </para><para>See also: Duncan J Watts and Steven H Strogatz:
+ * Collective dynamics of <quote>small world</quote> networks, Nature
+ * 393, 440-442, 1998.
+ * \param graph The graph to initialize.
+ * \param dim The dimension of the lattice.
+ * \param size The size of the lattice along each dimension.
+ * \param nei The size of the neighborhood for each vertex. This is
+ *    the same as the \p nei argument of \ref
+ *    igraph_connect_neighborhood(). 
+ * \param p The rewiring probability. A real number between zero and
+ *   one (inclusive). 
+ * \param loops Logical, whether to generate loop edges.
+ * \param multiple Logical, whether to allow multiple edges in the
+ *   generated graph.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_lattice(), \ref igraph_connect_neighborhood() and
+ * \ref igraph_rewire_edges() can be used if more flexibility is
+ * needed, eg. a different type of lattice.
+ * 
+ * Time complexity: O(|V|*d^o+|E|), |V| and |E| are the number of
+ * vertices and edges, d is the average degree, o is the \p nei
+ * argument.
+ */
+
+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) {
+  
+  igraph_vector_t dimvector;
+  long int i;
+
+  if (dim < 1) {
+    IGRAPH_ERROR("WS game: dimension should be at least one", IGRAPH_EINVAL);
+  }
+  if (size < 1) { 
+    IGRAPH_ERROR("WS game: lattice size should be at least one", 
+		 IGRAPH_EINVAL);
+  }
+  if (p < 0 || p > 1) {
+    IGRAPH_ERROR("WS game: rewiring probability should be between 0 and 1",
+		 IGRAPH_EINVAL);
+  }
+
+  /* Create the lattice first */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&dimvector, dim);
+  for (i=0; i<dim; i++) {
+    VECTOR(dimvector)[i] = size;
+  }
+  
+  IGRAPH_CHECK(igraph_lattice(graph, &dimvector, nei, IGRAPH_UNDIRECTED,
+			      0 /* mutual */, 1 /* circular */));
+  igraph_vector_destroy(&dimvector);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  
+  /* Rewire the edges then */
+
+  IGRAPH_CHECK(igraph_rewire_edges(graph, p, loops, multiple));
+
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_lastcit_game
+ * \brief Simulate citation network, based on time passed since the last citation.
+ * 
+ * This is a quite special stochastic graph generator, it models an
+ * evolving graph. In each time step a single vertex is added to the 
+ * network and it cites a number of other vertices (as specified by 
+ * the \p edges_per_step argument). The cited vertices are selected
+ * based on the last time they were cited. Time is measured by the 
+ * addition of vertices and it is binned into \p pagebins bins. 
+ * So if the current time step is \c t and the last citation to a 
+ * given \c i vertex was made in time step \c t0, then \c
+ * (t-t0)/binwidth is calculated where binwidth is \c nodes/pagebins+1,
+ * in the last expression '/' denotes integer division, so the
+ * fraction part is omitted. 
+ * 
+ * </para><para>
+ * The \p preference argument specifies the preferences for the
+ * citation lags, ie. its first elements contains the attractivity 
+ * of the very recently cited vertices, etc. The last element is
+ * special, it contains the attractivity of the vertices which were
+ * never cited. This element should be bigger than zero.
+ * 
+ * </para><para>
+ * Note that this function generates networks with multiple edges if 
+ * \p edges_per_step is bigger than one, call \ref igraph_simplify()
+ * on the result to get rid of these edges.
+ * \param graph Pointer to an uninitialized graph object, the result
+ *     will be stored here.
+ * \param node The number of vertices in the network.
+ * \param edges_per_node The number of edges to add in each time
+ *     step. 
+ * \param pagebins The number of age bins to use.
+ * \param preference Pointer to an initialized vector of length
+ *     \c pagebins+1. This contains the `attractivity' of the various
+ *     age bins, the last element is the attractivity of the vertices 
+ *     which were never cited, and it should be greater than zero.
+ *     It is a good idea to have all positive values in this vector.
+ * \param directed Logical constant, whether to create directed
+ *      networks. 
+ * \return Error code.
+ * 
+ * \sa \ref igraph_barabasi_aging_game().
+ * 
+ * Time complexity: O(|V|*a+|E|*log|V|), |V| is the number of vertices,
+ * |E| is the total number of edges, a is the \p pagebins parameter.
+ */
+  
+int igraph_lastcit_game(igraph_t *graph, 
+			igraph_integer_t nodes, igraph_integer_t edges_per_node, 
+			igraph_integer_t pagebins,
+			const igraph_vector_t *preference,
+			igraph_bool_t directed) {
+
+  long int no_of_nodes=nodes;
+  igraph_psumtree_t sumtree;
+  igraph_vector_t edges;
+  long int i, j, k;
+  long int *lastcit;
+  long int *index;
+  long int agebins=pagebins;
+  long int binwidth=no_of_nodes/agebins+1;
+
+  if (agebins != igraph_vector_size(preference)-1) {
+    IGRAPH_ERROR("`preference' vector should be of length `agebins' plus one",
+		 IGRAPH_EINVAL);
+  }
+  if (agebins <=1 ) {
+    IGRAPH_ERROR("at least two age bins are need for lastcit game",
+		 IGRAPH_EINVAL);
+  }
+  if (VECTOR(*preference)[agebins] <= 0) {
+    IGRAPH_ERROR("the last element of the `preference' vector needs to be positive",
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  lastcit=igraph_Calloc(no_of_nodes, long int);
+  if (!lastcit) {
+    IGRAPH_ERROR("lastcit game failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, lastcit);
+
+  index=igraph_Calloc(no_of_nodes+1, long int);
+  if (!index) {
+    IGRAPH_ERROR("lastcit game failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, index);
+
+  IGRAPH_CHECK(igraph_psumtree_init(&sumtree, nodes));
+  IGRAPH_FINALLY(igraph_psumtree_destroy, &sumtree);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, nodes*edges_per_node));  
+  
+  /* The first node */
+  igraph_psumtree_update(&sumtree, 0, VECTOR(*preference)[agebins]);
+  index[0]=0;
+  index[1]=0;
+
+  RNG_BEGIN();
+
+  for (i=1; i<no_of_nodes; i++) {
+
+    /* Add new edges */
+    for (j=0; j<edges_per_node; j++) {
+      long int to;
+      igraph_real_t sum=igraph_psumtree_sum(&sumtree);
+      igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
+      igraph_vector_push_back(&edges, i);
+      igraph_vector_push_back(&edges, to);
+      lastcit[to]=i+1;
+      igraph_psumtree_update(&sumtree, to, VECTOR(*preference)[0]);
+    }
+
+    /* Add the node itself */
+    igraph_psumtree_update(&sumtree, i, VECTOR(*preference)[agebins]);
+    index[i+1]=index[i]+edges_per_node;
+
+    /* Update the preference of some vertices if they got to another bin.
+       We need to know the citations of some older vertices, this is in the index. */
+    for (k=1; i-binwidth*k >= 1; k++) {
+      long int shnode=i-binwidth*k;
+      long int m=index[shnode], n=index[shnode+1];
+      for (j=2*m; j<2*n; j+=2) {
+	long int cnode=(long int) VECTOR(edges)[j+1];
+	if (lastcit[cnode]==shnode+1) {
+	  igraph_psumtree_update(&sumtree, cnode, VECTOR(*preference)[k]);
+	}
+      }
+    }
+    
+  }
+  
+  RNG_END();
+  
+  igraph_psumtree_destroy(&sumtree);
+  igraph_free(index);
+  igraph_free(lastcit);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_cited_type_game
+ * \brief Simulate a citation based on vertex types.
+ * 
+ * Function to create a network based on some vertex categories. This
+ * function creates a citation network, in each step a single vertex
+ * and \p edges_per_step citating edges are added, nodes with
+ * different categories (may) have different probabilities to get
+ * cited, as given by the \p pref vector.
+ *
+ * </para><para>
+ * Note that this function might generate networks with multiple edges 
+ * if \p edges_per_step is greater than one. You might want to call
+ * \ref igraph_simplify() on the result to remove multiple edges.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param nodes The number of vertices in the network.
+ * \param types Numeric vector giving the categories of the vertices,
+ *     so it should contain \p nodes non-negative integer
+ *     numbers. Types are numbered from zero.
+ * \param pref The attractivity of the different vertex categories in
+ *     a vector. Its length should be the maximum element in \p types
+ *     plus one (types are numbered from zero).
+ * \param edges_per_step Integer constant, the number of edges to add
+ *     in each time step.
+ * \param directed Logical constant, whether to create a directed
+ *     network. 
+ * \return Error code.
+ * 
+ * \sa \ref igraph_citing_cited_type_game() for a bit more general
+ * game. 
+ * 
+ * Time complexity: O((|V|+|E|)log|V|), |V| and |E| are number of
+ * vertices and edges, respectively.
+ */
+
+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) {
+  
+  igraph_vector_t edges;
+  igraph_vector_t cumsum;
+  igraph_real_t sum;
+  long int i,j;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&cumsum, 2);
+  IGRAPH_CHECK(igraph_vector_reserve(&cumsum, nodes+1));
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, nodes*edges_per_step));
+  
+  /* first node */
+  VECTOR(cumsum)[0]=0;
+  sum=VECTOR(cumsum)[1]=VECTOR(*pref)[ (long int) VECTOR(*types)[0] ];
+  
+  RNG_BEGIN();
+
+  for (i=1; i<nodes; i++) {
+    for (j=0; j<edges_per_step; j++) {
+      long int to;
+      igraph_real_t r=RNG_UNIF(0,sum);
+      igraph_vector_binsearch(&cumsum, r, &to);
+        igraph_vector_push_back(&edges, i);
+      igraph_vector_push_back(&edges, to-1);
+    }
+    sum+=VECTOR(*pref)[(long int) VECTOR(*types)[i] ];
+    igraph_vector_push_back(&cumsum, sum);
+  }
+  
+  RNG_END();
+
+  igraph_vector_destroy(&cumsum);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+void igraph_i_citing_cited_type_game_free(igraph_i_citing_cited_type_game_struct_t *s) {
+  long int i;
+  if (!s->sumtrees) { return; }
+  for (i=0; i<s->no; i++) {
+    igraph_psumtree_destroy(&s->sumtrees[i]);
+  }
+}
+
+/**
+ * \function igraph_citing_cited_type_game
+ * \brief Simulate a citation network based on vertex types.
+ *
+ * This game is similar to \ref igraph_cited_type_game() but here the
+ * category of the citing vertex is also considered. 
+ * 
+ * </para><para>
+ * An evolving citation network is modeled here, a single vertex and
+ * its \p edges_per_step citation are added in each time step. The 
+ * odds the a given vertex is cited by the new vertex depends on the 
+ * category of both the citing and the cited vertex and is given in
+ * the \p pref matrix. The categories of the citing vertex correspond
+ * to the rows, the categories of the cited vertex to the columns of
+ * this matrix. Ie. the element in row \c i and column \c j gives the
+ * probability that a \c j vertex is cited, if the category of the
+ * citing vertex is \c i.
+ * 
+ * </para><para>
+ * Note that this function might generate networks with multiple edges 
+ * if \p edges_per_step is greater than one. You might want to call
+ * \ref igraph_simplify() on the result to remove multiple edges.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param nodes The number of vertices in the network.
+ * \param types A numeric matrix of length \p nodes, containing the
+ *    categories of the vertices. The categories are numbered from
+ *    zero.
+ * \param pref The preference matrix, a square matrix is required, 
+ *     both the number of rows and columns should be the maximum
+ *     element in \p types plus one (types are numbered from zero).
+ * \param directed Logical constant, whether to create a directed
+ *     network.
+ * \return Error code.
+ * 
+ * Time complexity: O((|V|+|E|)log|V|), |V| and |E| are number of
+ * vertices and edges, respectively.
+ */
+
+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) {
+
+  igraph_vector_t edges;
+  igraph_i_citing_cited_type_game_struct_t str = { 0, 0 };
+  igraph_psumtree_t *sumtrees;
+  igraph_vector_t sums;
+  long int nocats=igraph_matrix_ncol(pref);
+  long int i, j;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges,0);
+  str.sumtrees=sumtrees=igraph_Calloc(nocats, igraph_psumtree_t);  
+  if (!sumtrees) {
+    IGRAPH_ERROR("Citing-cited type game failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_i_citing_cited_type_game_free, &str);
+  
+  for (i=0; i<nocats; i++) {
+    IGRAPH_CHECK(igraph_psumtree_init(&sumtrees[i], nodes));
+    str.no++;    
+  }
+  IGRAPH_VECTOR_INIT_FINALLY(&sums, nocats);
+					       
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, nodes*edges_per_step));
+
+  /* First node */
+  for (i=0; i<nocats; i++) {
+    long int type=(long int) VECTOR(*types)[0];
+    igraph_psumtree_update(&sumtrees[i], 0, MATRIX(*pref, i, type));
+    VECTOR(sums)[i]=MATRIX(*pref, i, type);
+  }
+
+  RNG_BEGIN();
+    
+  for (i=1; i<nodes; i++) {
+    long int type=(long int) VECTOR(*types)[i];
+    igraph_real_t sum=VECTOR(sums)[type];
+    for (j=0; j<edges_per_step; j++) {
+      long int to;
+      igraph_psumtree_search(&sumtrees[type], &to, RNG_UNIF(0, sum));
+      igraph_vector_push_back(&edges, i);
+      igraph_vector_push_back(&edges, to);
+    }
+    
+    /* add i */
+    for (j=0; j<nocats; j++) {
+      igraph_psumtree_update(&sumtrees[j], i, MATRIX(*pref, j,  type));
+      VECTOR(sums)[j] += MATRIX(*pref, j, type);
+    }
+  }
+
+  RNG_END();
+  
+  igraph_i_citing_cited_type_game_free(&str);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  igraph_create(graph, &edges, nodes, directed);
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+
+
+/**
+ * \ingroup generators
+ * \function igraph_simple_interconnected_islands_game
+ * \brief Generates a random graph made of several interconnected islands, each island being a random graph.
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \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 Error code:
+ *         \c IGRAPH_EINVAL: invalid parameter
+ *         \c IGRAPH_ENOMEM: there is not enough
+ *         memory for the operation.
+ * 
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges in the graph.
+ * 
+ */
+int igraph_simple_interconnected_islands_game(
+                igraph_t        *graph, 
+                igraph_integer_t    islands_n, 
+                igraph_integer_t    islands_size,
+                igraph_real_t       islands_pin, 
+                igraph_integer_t    n_inter) {
+
+    
+    igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+    igraph_vector_t s=IGRAPH_VECTOR_NULL;
+    int retval=0;
+    int nbNodes;
+    double maxpossibleedgesPerIsland;
+    double maxedgesPerIsland;
+    int nbEdgesInterIslands;
+    double maxedges;
+    int startIsland = 0;
+    int endIsland = 0;
+    int i, j, is;
+    double myrand, last;
+
+    if (islands_n<0) {
+        IGRAPH_ERROR("Invalid number of islands", IGRAPH_EINVAL);
+    }
+    if (islands_size<0) {
+        IGRAPH_ERROR("Invalid size for islands", IGRAPH_EINVAL);
+    }
+    if (islands_pin<0 || islands_pin>1) {
+        IGRAPH_ERROR("Invalid probability for islands", IGRAPH_EINVAL);
+    }
+    if ( (n_inter<0) || (n_inter>islands_size) ) {
+        IGRAPH_ERROR("Invalid number of inter-islands links", IGRAPH_EINVAL);
+    }
+
+    // how much memory ?
+    nbNodes = islands_n*islands_size;
+    maxpossibleedgesPerIsland = ((double)islands_size*((double)islands_size-(double)1))/(double)2;
+    maxedgesPerIsland = islands_pin*maxpossibleedgesPerIsland;
+    nbEdgesInterIslands = n_inter*(islands_n*(islands_n-1))/2;
+    maxedges = maxedgesPerIsland*islands_n + nbEdgesInterIslands;
+
+    // debug&tests : printf("total nodes %d, maxedgesperisland %f, maxedgesinterislands %d, maxedges %f\n", nbNodes, maxedgesPerIsland, nbEdgesInterIslands, maxedges);
+
+    // reserve enough place for all the edges, thanks !
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, (long int) maxedges));
+
+    RNG_BEGIN();
+
+    // first create all the islands
+    for (is=1; is<=islands_n; is++) { // for each island
+     
+        // index for start and end of nodes in this island
+        startIsland = islands_size*(is-1); 
+        endIsland = startIsland+islands_size -1;  
+    
+
+        // debug&tests : printf("start %d,end %d\n", startIsland, endIsland);
+
+        // create the random numbers to be used (into s)
+        IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
+        IGRAPH_CHECK(igraph_vector_reserve(&s, (long int) maxedgesPerIsland));
+
+        last=RNG_GEOM(islands_pin);
+        // debug&tests : printf("last=%f \n", last);
+        while (last < maxpossibleedgesPerIsland) { // maxedgesPerIsland
+            IGRAPH_CHECK(igraph_vector_push_back(&s, last));
+            myrand = RNG_GEOM(islands_pin);
+            last += myrand; //RNG_GEOM(islands_pin);
+            //printf("myrand=%f , last=%f \n", myrand, last);
+            last += 1;
+        }
+
+    
+
+        // change this to edges !
+        for (i=0; i<igraph_vector_size(&s); i++) {
+
+	    long int to=(long int) floor((sqrt(8*VECTOR(s)[i]+1)+1)/2);
+	    long int from=(long int) (VECTOR(s)[i]-(((igraph_real_t)to)*(to-1))/2);
+            to += startIsland;
+            from += startIsland;
+            // debug&tests : printf("from %d to %d\n", from, to);
+            igraph_vector_push_back(&edges, from);
+            igraph_vector_push_back(&edges, to);
+        }
+
+        // clear the memory used for random number for this island
+        igraph_vector_destroy(&s);
+        IGRAPH_FINALLY_CLEAN(1);
+
+
+        // create the links with other islands
+        for (i=is+1; i<=islands_n; i++) { // for each other island (not the previous ones)
+                
+            // debug&tests : printf("link islands %d and %d\n", is, i);
+            for (j=0; j<n_inter; j++) { // for each link between islands
+
+	        long int from = (long int) RNG_UNIF(startIsland, endIsland);
+	        long int to = (long int) RNG_UNIF((i-1)*islands_size, i*islands_size);
+                //printf("from %d to %d\n", from, to);
+                igraph_vector_push_back(&edges, from);
+                igraph_vector_push_back(&edges, to);
+            }
+            
+        }
+    }
+
+    RNG_END();
+
+    // actually fill the graph object
+    IGRAPH_CHECK(retval=igraph_create(graph, &edges, nbNodes, 0));
+
+    // an clear remaining things
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    return retval;
+}
+
+
+/**
+ * \ingroup generators
+ * \function igraph_static_fitness_game
+ * \brief 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 i and 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 i to j depends on
+ * the out-fitness of vertex i and the in-fitness of vertex j.
+ *
+ * </para><para>
+ * The generation process goes as follows. We start from N disconnected nodes
+ * (where N is given by the length of the fitness vector). Then we randomly
+ * select two vertices i and j, with probabilities proportional to their
+ * fitnesses. (When the generated graph is directed, i is selected according to
+ * the out-fitnesses and 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.
+ *
+ * </para><para>
+ * It can be shown that the \em 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
+ * \ref igraph_degree_sequence_game instead.
+ *
+ * </para><para>
+ * 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 \ref igraph_static_power_law_game
+ * which generates the fitnesses for you with a given exponent.
+ * 
+ * </para><para>
+ * Reference: Goh K-I, Kahng B, Kim D: Universal behaviour of load distribution
+ * in scale-free networks. Phys Rev Lett 87(27):278701, 2001.
+ *
+ * \param graph        Pointer to an uninitialized graph object.
+ * \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 \c NULL, the generated graph will be undirected.
+ *                     If not \c NULL, this argument specifies the in-fitness
+ *                     of each vertex.
+ * \param no_of_edges  The number of edges in the generated graph.
+ * \param loops        Whether to allow loop edges in the generated graph.
+ * \param multiple     Whether to allow multiple edges in the generated graph.
+ *
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid parameter
+ *         \c IGRAPH_ENOMEM: there is not enough
+ *         memory for the operation.
+ * 
+ * Time complexity: O(|V| + |E| log |E|).
+ */
+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) {
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  igraph_integer_t no_of_nodes;
+  igraph_vector_t cum_fitness_in, cum_fitness_out;
+  igraph_vector_t *p_cum_fitness_in, *p_cum_fitness_out;
+  igraph_real_t x, max_in, max_out;
+  igraph_bool_t is_directed = (fitness_in != 0);
+  float num_steps;
+  long int from, to, pos;
+
+  if (fitness_out == 0) {
+    IGRAPH_ERROR("fitness_out must not be null", IGRAPH_EINVAL);
+  }
+
+  if (no_of_edges < 0) {
+    IGRAPH_ERROR("Invalid number of edges", IGRAPH_EINVAL);
+  }
+
+  no_of_nodes = (int) igraph_vector_size(fitness_out);
+  if (no_of_nodes == 0) {
+    IGRAPH_CHECK(igraph_empty(graph, 0, is_directed));
+    return IGRAPH_SUCCESS;
+  }
+
+  /* Sanity checks for the fitnesses */
+  if (igraph_vector_min(fitness_out) < 0) {
+    IGRAPH_ERROR("Fitness scores must be non-negative", IGRAPH_EINVAL);
+  }
+  if (fitness_in != 0 && igraph_vector_min(fitness_in) < 0) {
+    IGRAPH_ERROR("Fitness scores must be non-negative", IGRAPH_EINVAL);
+  }
+
+  /* Calculate the cumulative fitness scores */
+  IGRAPH_VECTOR_INIT_FINALLY(&cum_fitness_out, no_of_nodes);
+  IGRAPH_CHECK(igraph_vector_cumsum(&cum_fitness_out, fitness_out));
+  max_out = igraph_vector_tail(&cum_fitness_out);
+  p_cum_fitness_out = &cum_fitness_out;
+  if (is_directed) {
+    IGRAPH_VECTOR_INIT_FINALLY(&cum_fitness_in, no_of_nodes);
+    IGRAPH_CHECK(igraph_vector_cumsum(&cum_fitness_in, fitness_in));
+    max_in = igraph_vector_tail(&cum_fitness_in);
+    p_cum_fitness_in = &cum_fitness_in;
+  } else {
+    max_in = max_out;
+    p_cum_fitness_in = &cum_fitness_out;
+  }
+
+  RNG_BEGIN();
+  num_steps = no_of_edges;
+  if (multiple) {
+    /* Generating when multiple edges are allowed */
+
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, 2 * no_of_edges));
+
+    while (no_of_edges > 0) {
+      /* Report progress after every 10000 edges */
+      if (no_of_edges % 10000 == 0) {
+        IGRAPH_PROGRESS("Static fitness game", 100.0*(1 - no_of_edges/num_steps), NULL);
+        IGRAPH_ALLOW_INTERRUPTION();
+      }
+
+      x = RNG_UNIF(0, max_out);
+      igraph_vector_binsearch(p_cum_fitness_out, x, &from);
+      x = RNG_UNIF(0, max_in);
+      igraph_vector_binsearch(p_cum_fitness_in, x, &to);
+
+      /* Skip if loop edge and loops = false */
+      if (!loops && from == to)
+        continue;
+
+      igraph_vector_push_back(&edges, from);
+      igraph_vector_push_back(&edges, to);
+
+      no_of_edges--;
+    }
+
+    /* Create the graph */
+    IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, is_directed));
+    
+    /* Clear the edge list */
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    /* Multiple edges are disallowed */
+    igraph_adjlist_t al;
+    igraph_vector_int_t* neis;
+
+    IGRAPH_CHECK(igraph_adjlist_init_empty(&al, no_of_nodes));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
+    while (no_of_edges > 0) {
+      /* Report progress after every 10000 edges */
+      if (no_of_edges % 10000 == 0) {
+        IGRAPH_PROGRESS("Static fitness game", 100.0*(1 - no_of_edges/num_steps), NULL);
+        IGRAPH_ALLOW_INTERRUPTION();
+      }
+
+      x = RNG_UNIF(0, max_out);
+      igraph_vector_binsearch(p_cum_fitness_out, x, &from);
+      x = RNG_UNIF(0, max_in);
+      igraph_vector_binsearch(p_cum_fitness_in, x, &to);
+      
+      /* Skip if loop edge and loops = false */
+      if (!loops && from == to)
+        continue;
+
+      /* For undirected graphs, ensure that from < to */
+      if (!is_directed && from > to) {
+        pos = from; from = to; to = pos;
+      }
+
+      /* Is there already an edge? If so, try again */
+      neis = igraph_adjlist_get(&al, from);
+      if (igraph_vector_int_binsearch(neis, to, &pos))
+        continue;
+
+      /* Insert the edge */
+      IGRAPH_CHECK(igraph_vector_int_insert(neis, pos, to));
+
+      no_of_edges--;
+    }
+
+    /* Create the graph. We cannot use IGRAPH_ALL here for undirected graphs
+     * because we did not add edges in both directions in the adjacency list.
+     * We will use igraph_to_undirected in an extra step. */
+    IGRAPH_CHECK(igraph_adjlist(graph, &al, IGRAPH_OUT, 1));
+    if (!is_directed)
+      IGRAPH_CHECK(igraph_to_undirected(graph, IGRAPH_TO_UNDIRECTED_EACH, 0));
+
+    /* Clear the adjacency list */
+    igraph_adjlist_destroy(&al);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  RNG_END();
+
+  IGRAPH_PROGRESS("Static fitness game", 100.0, NULL);
+
+  /* Cleanup before we create the graph */
+  if (is_directed) {
+    igraph_vector_destroy(&cum_fitness_in);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_vector_destroy(&cum_fitness_out);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+
+/**
+ * \ingroup generators
+ * \function igraph_static_power_law_game
+ * \brief 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.
+ *
+ * </para><para>
+ * The game simply uses \ref igraph_static_fitness_game with appropriately
+ * constructed fitness vectors. In particular, the fitness of vertex i
+ * is i<superscript>-alpha</superscript>, where alpha = 1/(gamma-1) 
+ * and gamma is the exponent given in the arguments.
+ *
+ * </para><para>
+ * 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 \ref igraph_static_fitness_game is called.
+ *
+ * </para><para>
+ * 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 i is 
+ * (i+i0-1)<superscript>-alpha</superscript>,
+ * where 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.
+ *
+ * </para><para>
+ * References:
+ *
+ * </para><para>
+ * Goh K-I, Kahng B, Kim D: Universal behaviour of load distribution
+ * in scale-free networks. Phys Rev Lett 87(27):278701, 2001.
+ *
+ * </para><para>
+ * Chung F and Lu L: Connected components in a random graph with given
+ * degree sequences. Annals of Combinatorics 6, 125-145, 2002.
+ *
+ * </para><para>
+ * Cho YS, Kim JS, Park J, Kahng B, Kim D: Percolation transitions in
+ * scale-free networks under the Achlioptas process. Phys Rev Lett
+ * 103:135702, 2009.
+ *
+ * \param graph        Pointer to an uninitialized graph object.
+ * \param no_of_nodes  The number of nodes in the generated graph.
+ * \param no_of_edges  The number of edges in the generated graph.
+ * \param exponent_out 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 \c IGRAPH_INFINITY here, you
+ *                     will get back an Erdos-Renyi random network.
+ * \param exponent_in  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        Whether to allow loop edges in the generated graph.
+ * \param multiple     Whether to allow multiple edges in the generated graph.
+ * \param finite_size_correction  Whether to use the proposed finite size
+ *                     correction of Cho et al.
+ *
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid parameter
+ *         \c IGRAPH_ENOMEM: there is not enough
+ *         memory for the operation.
+ * 
+ * Time complexity: O(|V| + |E| log |E|).
+ */
+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) {
+
+  igraph_vector_t fitness_out, fitness_in;
+  igraph_real_t alpha_out = 0.0, alpha_in = 0.0;
+  long int i;
+  igraph_real_t j;
+
+  if (no_of_nodes < 0) {
+    IGRAPH_ERROR("Invalid number of nodes", IGRAPH_EINVAL);
+  }
+
+  /* Calculate alpha_out */
+  if (exponent_out < 2) {
+    IGRAPH_ERROR("out-degree exponent must be >= 2", IGRAPH_EINVAL);
+  } else if (igraph_finite(exponent_out)) {
+    alpha_out = -1.0 / (exponent_out - 1);
+  } else {
+    alpha_out = 0.0;
+  }
+
+  /* Construct the out-fitnesses */
+  IGRAPH_VECTOR_INIT_FINALLY(&fitness_out, no_of_nodes);
+  j = no_of_nodes;
+  if (finite_size_correction && alpha_out < -0.5) {
+    /* See the Cho et al paper, first page first column + footnote 7 */
+    j += pow(no_of_nodes, 1 + 0.5 / alpha_out) *
+         pow(10*sqrt(2)*(1 + alpha_out), -1.0 / alpha_out)-1;
+  }
+  if (j < no_of_nodes)
+    j = no_of_nodes;
+  for (i = 0; i < no_of_nodes; i++, j--) {
+    VECTOR(fitness_out)[i] = pow(j, alpha_out);
+  }
+
+  if (exponent_in >= 0) {
+    if (exponent_in < 2) {
+      IGRAPH_ERROR("in-degree exponent must be >= 2; use negative numbers "
+          "for undirected graphs", IGRAPH_EINVAL);
+    } else if (igraph_finite(exponent_in)) {
+      alpha_in = -1.0 / (exponent_in - 1);
+    } else {
+      alpha_in = 0.0;
+    }
+
+    IGRAPH_VECTOR_INIT_FINALLY(&fitness_in, no_of_nodes);
+    j = no_of_nodes;
+    if (finite_size_correction && alpha_in < -0.5) {
+      /* See the Cho et al paper, first page first column + footnote 7 */
+      j += pow(no_of_nodes, 1 + 0.5 / alpha_in) *
+           pow(10*sqrt(2)*(1 + alpha_in), -1.0 / alpha_in)-1;
+    }
+    if (j < no_of_nodes)
+      j = no_of_nodes;
+    for (i = 0; i < no_of_nodes; i++, j--) {
+      VECTOR(fitness_in)[i] = pow(j, alpha_in);
+    }
+    IGRAPH_CHECK(igraph_vector_shuffle(&fitness_in));
+
+    IGRAPH_CHECK(igraph_static_fitness_game(graph, no_of_edges,
+          &fitness_out, &fitness_in, loops, multiple));
+
+    igraph_vector_destroy(&fitness_in);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    IGRAPH_CHECK(igraph_static_fitness_game(graph, no_of_edges,
+          &fitness_out, 0, loops, multiple));
+  }
+
+  igraph_vector_destroy(&fitness_out);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+
+/**
+ * \ingroup generators
+ * \function igraph_k_regular_game
+ * \brief Generates 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.
+ *
+ * </para><para>
+ * The game simply uses \ref igraph_degree_sequence_game with appropriately
+ * constructed degree sequences.
+ *
+ * \param graph        Pointer to an uninitialized graph object.
+ * \param no_of_nodes  The number of nodes in the generated graph.
+ * \param k            The degree of each vertex in an undirected graph, or
+ *                     the out-degree and in-degree of each vertex in a
+ *                     directed graph.
+ * \param directed     Whether the generated graph will be directed.
+ * \param multiple     Whether to allow multiple edges in the generated graph.
+ *
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid parameter; e.g., negative number of nodes,
+ *                           or odd number of nodes and odd k for undirected
+ *                           graphs.
+ *         \c IGRAPH_ENOMEM: there is not enough memory for the operation.
+ * 
+ * Time complexity: O(|V|+|E|) if \c multiple is true, otherwise not known.
+ */
+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) {
+  igraph_vector_t degseq;
+  igraph_degseq_t mode = multiple ? IGRAPH_DEGSEQ_SIMPLE : IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE;
+
+  /* Note to self: we are not using IGRAPH_DEGSEQ_VL when multiple = false
+   * because the VL method is not really good at generating k-regular graphs.
+   * Actually, that's why we have added SIMPLE_NO_MULTIPLE. */
+
+  if (no_of_nodes < 0) {
+    IGRAPH_ERROR("number of nodes must be non-negative", IGRAPH_EINVAL);
+  }
+  if (k < 0) {
+    IGRAPH_ERROR("degree must be non-negative", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&degseq, no_of_nodes);
+  igraph_vector_fill(&degseq, k);
+  IGRAPH_CHECK(igraph_degree_sequence_game(graph, &degseq, directed ? &degseq : 0, mode));
+
+  igraph_vector_destroy(&degseq);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+
diff --git a/src/gengraph_box_list.cpp b/src/gengraph_box_list.cpp
new file mode 100644
index 0000000..79d2ccd
--- /dev/null
+++ b/src/gengraph_box_list.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#include "gengraph_box_list.h"
+#include <cassert>
+
+namespace gengraph {
+
+void box_list::insert(int v) {
+  register int d = deg[v];
+  if(d<1) return;
+  if(d>dmax) dmax=d;
+  int yo = list[d-1];
+  list[d-1] = v;
+  prev[v] = -1;
+  next[v] = yo;
+  if(yo>=0) prev[yo]=v;
+}
+
+void box_list::pop(int v) {
+  register int p = prev[v];
+  register int n = next[v];
+  if(p<0) {
+    register int d = deg[v];
+    assert(list[d-1]==v);
+    list[d-1] = n;
+    if(d==dmax && n<0) do dmax--; while(dmax>0 && list[dmax-1]<0);
+  }
+  else next[p] = n;
+  if(n>=0) prev[n] = p;
+}
+
+box_list::box_list(int n0, int *deg0) : n(n0), deg(deg0) {
+  next = new int[n];
+  prev = new int[n];
+  dmax = -1;
+  int i;
+  for(i=0; i<n; i++) if(deg[i]>dmax) dmax=deg[i];
+  list = new int[dmax];
+  for(i=0; i<dmax; i++) list[i]=-1;
+  for(i=0; i<n; i++) insert(i);
+}
+
+box_list::~box_list() {
+  delete[] prev;
+  delete[] next;
+  delete[] list;
+}
+
+void box_list::pop_vertex(int v, int **neigh) {
+  int k=deg[v];
+  if(k<1) return;
+  pop(v);
+  int *w = neigh[v];
+  while(k--) {
+    int v2 = *(w++);
+    register int *w2 = neigh[v2];
+    while(*w2 != v) w2++;
+    register int *w3 = neigh[v2]+(deg[v2]-1);
+    assert(w2<=w3);
+    register int tmp = *w3;
+    *w3 = *w2;
+    *w2 = tmp;
+    pop(v2);
+    deg[v2]--;
+    insert(v2);
+  }
+}
+
+} // namespace gengraph
diff --git a/src/gengraph_box_list.h b/src/gengraph_box_list.h
new file mode 100644
index 0000000..0711a07
--- /dev/null
+++ b/src/gengraph_box_list.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+// This class allows to maintain a list of vertices, 
+// sorted by degree (largest degrees first)
+// Operations allowed :
+// - get the vertex having max degree -> Cost = O(1)
+// - remove any vertex from the graph -> Cost = Sum(degrees of neighbours)
+//                                       [ could be O(degree) if optimized ]
+
+#ifndef _BOX_LIST_H
+#define _BOX_LIST_H
+
+namespace gengraph {
+
+class box_list {
+
+private:
+  int n;     // INITIAL number of vertices
+  int dmax;  // CURRENT Maximum degree
+  int *deg;  // CURRENT Degrees (points directly to the deg[] of the graph
+
+  // Vertices are grouped by degree: one double-chained lists for each degree
+  int *list;        // list[d-1] is the head of list of vertices of degree d
+  int *next;        // next[v]/prev[v] are the vertices next/previous to v
+  int *prev;        //   in the list where v belongs
+  void pop(int);    // pop(v) just removes v from its list
+  void insert(int); // insert(v) insert v at the head of its list
+
+public:
+
+  // Ctor. Takes O(n) time.
+  box_list(int n0, int *deg0);
+
+  // Dtor
+  ~box_list();
+
+  // Self-explaining inline routines
+  inline bool is_empty() { return dmax<1; };
+  inline int get_max()   { return list[dmax-1]; };
+  inline int get_one()   { return list[0]; };
+  inline int get_min()   {
+    int i=0;
+    while(list[i]<0) i++;
+    return list[i];
+  };
+  
+  // Remove v from box_list
+  // Also, semi-remove vertex v from graph: all neighbours of v will swap
+  // their last neighbour wit hv, and then decrease their degree, so
+  // that any arc w->v virtually disappear
+  // Actually, adjacency lists are just permuted, and deg[] is changed
+  void pop_vertex(int v, int **neigh);
+};
+
+} // namespace gengraph
+
+#endif //_BOX_LIST_H
diff --git a/src/gengraph_definitions.h b/src/gengraph_definitions.h
new file mode 100644
index 0000000..a0209bf
--- /dev/null
+++ b/src/gengraph_definitions.h
@@ -0,0 +1,191 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef DEFINITIONS_H
+#define DEFINITIONS_H
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+namespace gengraph {
+
+// Max line size in files
+#define FBUFF_SIZE 1000000
+
+// disable lousy VC++ warnings
+#ifdef _ATL_VER_
+#pragma warning(disable : 4127)
+#endif //_ATL_VER_
+
+// Verbose
+#define VERBOSE_NONE 0
+#define VERBOSE_SOME 1
+#define VERBOSE_LOTS 2
+int VERBOSE();
+void SET_VERBOSE(int v);
+
+// Random number generator
+void my_srandom(int);
+int my_random();
+int my_binomial(double pp, int n);
+double my_random01(); // (0,1]
+
+#define MY_RAND_MAX 0x7FFFFFFF
+
+// IPv4 address direct translation into 32-bit uint + special IP defs
+typedef unsigned int ip_addr;
+#define IP_NONE   0x7FFFFFFF
+#define IP_STAR   0x00000000
+#define IP_MYSELF 0x7F000001
+
+// Compatibility
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+//inline double round(double x) throw () { return (floor(0.5+x)); } 
+
+// No assert
+#ifndef _DEBUG
+#ifndef NDEBUG
+#define NDEBUG
+#endif //NDEBUG
+#endif //_DEBUG
+
+// Min & Max
+#ifndef min
+#define defmin(type) inline type min(type a, type b) { return a<b ? a : b; }
+defmin(int)
+defmin(double)
+defmin(unsigned long)
+#endif //min
+#ifndef max
+#define defmax(type) inline type max(type a, type b) { return a>b ? a : b; }
+defmax(int)
+defmax(double)
+defmax(unsigned long)
+#endif //max
+
+// Traceroute Sampling
+#define MODE_USP 0
+#define MODE_ASP 1
+#define MODE_RSP 2
+
+// Debug definitions
+//#define PERFORMANCE_MONITOR
+//#define OPT_ISOLATED
+
+// Max Int
+#ifndef MAX_INT
+#define MAX_INT 0x7FFFFFFF
+#endif //MAX_INT
+
+//Edge type
+typedef struct { int from; int to; } edge;
+
+// Tag Int
+#define TAG_INT 0x40000000
+
+// Oldies ....
+#define S_VECTOR_RAW
+
+//*********************
+// Routine definitions
+//*********************
+
+/* log(1+x)
+inline double logp(double x) {
+  if(fabs(x)<1e-6) return x+0.5*x*x+0.333333333333333*x*x*x;
+  else return log(1.0+x);
+}
+//*/
+
+
+//Fast search or replace
+inline int* fast_rpl(int *m, const int a, const int b) {
+  while(*m!=a) m++;
+  *m = b;
+  return m;
+}
+inline int* fast_search(int *m, const int size, const int a) {
+  int *p = m+size;
+  while(m != p--) if(*p == a) return p;
+  return NULL;
+}
+
+// Lovely percentage print
+// inline void print_percent(double yo, FILE *f = stderr) {
+//   int arf = int(100.0*yo);
+//   if(double(arf)>100.0*yo) arf--;
+//   if(arf<100) fprintf(f," ");
+//   if(arf<10) fprintf(f," ");
+//   fprintf(f,"%d.%d%%",arf,int(1000.0*yo-double(10*arf)));
+// }
+
+// Skips non-numerical chars, then numerical chars, then non-numerical chars.
+inline char skip_int(char* &c) {
+  while(*c<'0' || *c>'9') c++;
+  while(*c>='0' && *c<='9') c++;
+  while(*c!=0 && (*c<'0' || *c>'9')) c++;
+  return *c;
+}
+
+// distance+1 modulo 255 for breadth-first search
+inline unsigned char next_dist(const unsigned char c) { return c==255 ? 1 : c+1; }
+inline unsigned char prev_dist(const unsigned char c) { return c==1 ? 255 : c-1; }
+
+// 1/(RANDMAX+1)
+#define inv_RANDMAX (1.0/(1.0+double(MY_RAND_MAX)))
+
+// random number in ]0,1[, _very_ accurate around 0
+inline double random_float() {
+  int r=my_random();
+  double mul=inv_RANDMAX;
+  while(r<=0x7FFFFF) {
+    r<<=8;
+    r+=(my_random()&0xFF);
+    mul*=(1.0/256.0);
+  }
+  return double(r)*mul;
+}
+
+// Return true with probability p. Very accurate when p is small.
+#define test_proba(p) (random_float()<(p))
+
+// Random bit generator, sparwise.
+static int _random_bits_stored = 0;
+static int _random_bits = 0;
+
+inline int random_bit() {
+  register int a = _random_bits;
+  _random_bits = a >> 1;
+  if(_random_bits_stored--) return a&0x1;
+  a = my_random();
+  _random_bits = a >> 1;
+  _random_bits_stored = 30;
+  return a&0x1;
+}
+
+// Hash Profiling (see hash.h)
+void _hash_prof();
+
+} // namespace gengraph
+
+#endif //DEFINITIONS_H
diff --git a/src/gengraph_degree_sequence.cpp b/src/gengraph_degree_sequence.cpp
new file mode 100644
index 0000000..a9ee706
--- /dev/null
+++ b/src/gengraph_degree_sequence.cpp
@@ -0,0 +1,375 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#include "gengraph_definitions.h"
+#include "gengraph_random.h"
+#include "gengraph_powerlaw.h"
+#include "gengraph_degree_sequence.h"
+#include "gengraph_hash.h"
+
+#include "igraph_statusbar.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <vector>
+
+// using namespace __gnu_cxx;
+using namespace std;
+
+namespace gengraph {
+
+// shuffle an int[] randomly
+void random_permute(int *a, int n);
+
+// sort an array of positive integers in time & place O(n + max)
+void cumul_sort(int *q, int n);
+
+
+void degree_sequence::detach() {
+  deg=NULL;
+}
+
+degree_sequence::~degree_sequence() {
+  if(deg!=NULL) delete[] deg;
+  deg = NULL;
+}
+
+void degree_sequence::make_even(int mini, int maxi) {
+  if(total%2==0) return;
+  if(maxi<0) maxi=0x7FFFFFFF;
+  int i;
+  for(i=0; i<n; i++) {
+    if(deg[i]>mini) { deg[i]--; total--; break; }
+    else if(deg[i]<maxi) { deg[i]++; total++; break; }
+  }
+  if(i==n) {
+    IGRAPH_WARNING("Warning: degree_sequence::make_even() forced one "
+		   "degree to go over degmax");
+    deg[0]++;
+    total++;
+  }
+}
+
+void degree_sequence::shuffle() {
+  random_permute(deg, n);
+}
+
+void degree_sequence::sort() {
+  cumul_sort(deg, n);
+}
+
+void degree_sequence::compute_total() {
+  total = 0;
+  for(int i=0; i<n; i++) total+=deg[i];
+}
+
+degree_sequence::
+degree_sequence(int n0, int *degs) {
+  deg=degs;
+  n=n0;
+  compute_total();
+}
+
+degree_sequence::
+degree_sequence(const igraph_vector_t *out_seq) {
+  n=igraph_vector_size(out_seq);
+  deg = new int[n];
+  for (long int i=0; i<n; i++) {
+    deg[i] = VECTOR(*out_seq)[i];
+  }
+  compute_total();
+}
+
+#ifndef FBUFF_SIZE
+#define FBUFF_SIZE 999
+#endif //FBUFF_SIZE
+
+// degree_sequence::degree_sequence(FILE *f, bool DISTRIB) {
+//   n = 0;
+//   total = 0;
+//   char *buff = new char[FBUFF_SIZE];
+//   char *c;
+//   vector<int> degree;
+//   if(!DISTRIB) {
+//     // Input is a 'raw' degree sequence d0 d1 d2 d3 ...
+//     while(fgets(buff, FBUFF_SIZE, f)) {
+//       int d = strtol(buff, &c, 10);
+//       if(c == buff) continue;
+//       degree.push_back(d);
+//       total += d;
+//     }
+//     n = int(degree.size());
+//     deg = new int[n];
+//     int *yo = deg;
+//     vector<int>::iterator end = degree.end();
+//     for(vector<int>::iterator it=degree.begin(); it!=end; *(yo++) = *(it++));
+//   }
+//   else {  
+//     // Input is a degree distribution : d0 #(degree=d0), d1 #(degree=d1), ...
+//     vector<int> n_with_degree;
+//     int line = 0;
+//     int syntax  = 0;
+//     int ignored = 0;
+//     int first_syntax  = 0;
+//     int first_ignored = 0;
+//     while(fgets(buff, FBUFF_SIZE, f)) {
+//       line++;
+//       int d = strtol(buff, &c, 10);
+//       if(c == buff) { ignored++; first_ignored = line; continue; }
+//       char *cc;
+//       int i = strtol(c, &cc, 10);
+//       if(cc == c) { syntax++; first_syntax = line; continue; }
+//       n += i;
+//       total += i*d;
+//       degree.push_back(d);
+//       n_with_degree.push_back(i);
+//       if( cc != c) {  syntax++; first_syntax = line; }
+//     }
+//     if(VERBOSE()) {
+//       if(ignored > 0) fprintf(stderr,"Ignored %d lines (first was line #%d)\n", ignored, first_ignored);
+//       if(syntax > 0) fprintf(stderr,"Found %d probable syntax errors (first was line #%d)\n", syntax, first_syntax);
+//     }
+//     deg = new int[n];
+//     int *yo = deg;
+//     vector<int>::iterator it_n = n_with_degree.begin();
+//     for(vector<int>::iterator it = degree.begin(); it != degree.end(); it++)
+//       for(int k = *(it_n++); k--; *yo++ = *it);
+//   }
+//   if(VERBOSE()) {
+//     if(total % 2 != 0) fprintf(stderr,"Warning: degree sequence is odd\n");
+//     fprintf(stderr,"Degree sequence created. N=%d, 2M=%d\n", n, total);
+//   }
+// } 
+     
+// n vertices, exponent, min degree, max degree, average degree (optional, default is -1)
+degree_sequence::
+degree_sequence(int _n, double exp, int degmin, int degmax, double z) { 
+
+  n=_n;
+  if(exp==0.0) {
+    // Binomial distribution
+    if(z<0) {
+      igraph_error("Fatal error in degree_sequence Ctor: "
+		   "positive average degree must be specified", __FILE__,
+		   __LINE__, IGRAPH_EINVAL);
+    }
+    if(degmax<0) degmax=n-1;
+    total = int(floor(double(n)*z+0.5));
+    deg = new int[n];
+    KW_RNG::RNG myrand;
+    double p = (z-double(degmin))/double(n);
+    total=0;
+    for(int i=0; i<n; i++) {
+      do deg[i]=1+myrand.binomial(p,n); while(deg[i]>degmax);
+      total+=deg[i];
+    }
+  }
+  else {
+    // Power-law distribution
+    igraph_status("Creating powerlaw sampler...", 0);
+    powerlaw pw(exp, degmin, degmax);
+    if(z==-1.0) {
+      pw.init();
+      igraph_statusf("done. Mean=%f\n", 0, pw.mean());
+    }
+    else {
+      double offset = pw.init_to_mean(z);
+      igraph_statusf("done. Offset=%f, Mean=%f\n", 0, offset, pw.mean());
+    }
+
+    deg = new int[n];
+    total = 0;
+    int i;
+
+    igraph_statusf("Sampling %d random numbers...", 0, n);
+    for(i=0; i<n; i++) {
+      deg[i] = pw.sample();
+      total+= deg[i];
+    }
+    
+    igraph_status("done\nSimple statistics on degrees...", 0);
+    int wanted_total = int(floor(z*n+0.5));
+    sort();
+    igraph_statusf("done : Max=%d, Total=%d.\n", 0, deg[0], total);
+    if(z!=-1.0)  {
+      igraph_statusf("Adjusting total to %d...", 0, wanted_total);
+      int iterations = 0;
+  
+      while(total!=wanted_total) {
+        sort();
+        for(i=0; i<n && total>wanted_total; i++) {
+          total-=deg[i];
+          if(total+degmin<=wanted_total) deg[i]=wanted_total-total;
+          else deg[i]=pw.sample();
+          total += deg[i];
+        }
+        iterations += i;
+        for(i=n-1; i>0 && total<wanted_total; i--) {
+          total-=deg[i];
+          if(total+(deg[0]>>1)>=wanted_total) deg[i]=wanted_total-total;
+          else deg[i]=pw.sample();
+          total += deg[i];
+        }
+        iterations += n-1-i;
+      }
+      igraph_statusf("done(%d iterations).", 0, iterations);
+      igraph_statusf("  Now, degmax = %d\n", 0, dmax());
+    }
+    
+    shuffle();
+  }
+}
+    
+// void degree_sequence::print() {
+//   for(int i=0; i<n; i++) printf("%d\n",deg[i]);
+// }
+
+// void degree_sequence::print_cumul() {
+//   if(n==0) return;
+//   int dmax = deg[0];
+//   int dmin = deg[0];
+//   int i;
+//   for(i=1; i<n; i++) if(dmax<deg[i]) dmax=deg[i];
+//   for(i=1; i<n; i++) if(dmin>deg[i]) dmin=deg[i];
+//   int *dd = new int[dmax-dmin+1];
+//   for(i=dmin; i<=dmax; i++) dd[i-dmin]=0;
+//   if(VERBOSE()) fprintf(stderr,"Computing cumulative distribution...");
+//   for(i=0; i<n; i++) dd[deg[i]-dmin]++;
+//   if(VERBOSE()) fprintf(stderr,"done\n");
+//   for(i=dmin; i<=dmax; i++) if(dd[i-dmin]>0) printf("%d %d\n",i,dd[i-dmin]);
+//   delete[] dd;
+// }
+
+bool degree_sequence::havelhakimi() {
+
+  int i;
+  int dm = dmax()+1;
+  // Sort vertices using basket-sort, in descending degrees
+  int *nb = new int[dm];
+  int *sorted = new int[n];
+  // init basket
+  for(i=0; i<dm; i++) nb[i]=0;
+  // count basket
+  for(i=0; i<n; i++) nb[deg[i]]++;
+  // cumul
+  int c = 0;
+  for(i=dm-1; i>=0; i--) {
+    int t=nb[i];
+    nb[i]=c;
+    c+=t;
+  }                                            
+  // sort
+  for(i=0; i<n; i++) sorted[nb[deg[i]]++]=i;
+
+// Binding process starts
+  int first = 0;  // vertex with biggest residual degree
+  int d = dm-1; // maximum residual degree available
+
+  for(c=total/2; c>0; ) {
+    // We design by 'v' the vertex of highest degree (indexed by first)
+    // look for current degree of v
+    while(nb[d]<=first) d--;
+    // store it in dv
+    int dv = d;
+    // bind it !
+    c -= dv;
+    int dc = d;         // residual degree of vertices we bind to
+    int fc = ++first;   // position of the first vertex with degree dc
+
+    while(dv>0 && dc>0) {
+      int lc = nb[dc];
+      if(lc!=fc) {
+        while(dv>0 && lc>fc) {
+          // binds v with sorted[--lc]
+          dv--;
+          lc--;
+        }
+        fc = nb[dc];
+        nb[dc] = lc;
+      }
+      dc--;
+    }
+    if(dv != 0) { // We couldn't bind entirely v
+      delete[] nb;
+      delete[] sorted;
+      return false;
+    }
+  }
+  delete[] nb;
+  delete[] sorted;
+  return true;
+}
+
+//*************************
+// Subroutines definitions
+//*************************
+
+inline int int_adjust(double x) { return(int(floor(x+random_float()))); }
+
+void random_permute(int *a, int n) {
+  int j,tmp;
+  for(int i=0; i<n-1; i++) {
+    j=i+my_random()%(n-i);
+    tmp=a[i];
+    a[i]=a[j];
+    a[j]=tmp;
+  }
+}
+
+void cumul_sort(int *q, int n) {
+  // looks for the maximum q[i] and minimum 
+  if (n==0) return;
+  int qmax=q[0];
+  int qmin=q[0];
+  int i;
+  for(i=0; i<n; i++) if(q[i]>qmax) qmax=q[i];
+  for(i=0; i<n; i++) if(q[i]<qmin) qmin=q[i];
+
+  // counts #q[i] with given q
+  int *nb = new int[qmax-qmin+1];
+  for(int *onk=nb+(qmax-qmin+1); onk!=nb; *(--onk)=0) { }
+  for(i=0; i<n; i++) nb[q[i]-qmin]++;
+
+  // counts cumulative distribution
+  for(i=qmax-qmin;i>0;i--) nb[i-1]+=nb[i];
+
+  // sort by q[i]
+  int last_q;
+  int tmp;
+  int modifier = qmax-qmin+1;
+  for(int current=0; current<n; current++) {
+    tmp=q[current];
+    if(tmp>=qmin && tmp<=qmax) {
+      last_q=qmin;
+      do {
+        q[current] = last_q+modifier;
+        last_q = tmp;
+        current = --nb[last_q-qmin];
+      } while((tmp=q[current])>=qmin && tmp<=qmax);
+      q[current]=last_q+modifier;
+    }
+  }
+  delete[] nb;
+  for(i=0; i<n; i++) q[i] = q[i]-modifier;
+}
+
+} // namespace gengraph
diff --git a/src/gengraph_degree_sequence.h b/src/gengraph_degree_sequence.h
new file mode 100644
index 0000000..d9bff0a
--- /dev/null
+++ b/src/gengraph_degree_sequence.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef DEGREE_SEQUENCE_H
+#define DEGREE_SEQUENCE_H
+
+#include "igraph_types.h"
+#include "igraph_datatype.h"
+
+namespace gengraph {
+
+class degree_sequence {
+
+private:
+  int n; 
+  int * deg;
+  int total;
+
+public :
+  // #vertices
+  inline int size() { return n; };
+  inline int sum() { return total; };
+  inline int operator[](int i) { return deg[i]; };
+  inline int *seq() { return deg; };
+  inline void assign(int n0, int* d0) { n=n0; deg=d0; };
+  inline int dmax() {
+    int dm = deg[0];
+    for(int i=1; i<n; i++) if(deg[i]>dm) dm=deg[i];
+    return dm;
+  }
+
+  void make_even(int mini=-1, int maxi=-1);
+  void sort();
+  void shuffle();
+  
+  // raw constructor
+  degree_sequence(int n, int *degs);
+
+  // read-from-file constrictor
+  degree_sequence(FILE *f, bool DISTRIB=true);
+
+  // simple power-law constructor : Pk = int((x+k0)^(-exp),x=k..k+1), with k0 so that avg(X)=z
+  degree_sequence(int n, double exp, int degmin, int degmax, double avg_degree=-1.0);
+
+  // igraph constructor
+  degree_sequence(const igraph_vector_t *out_seq);
+
+  // destructor
+  ~degree_sequence();
+
+  // unbind the deg[] vector (so that it doesn't get deleted when the class is destroyed)
+  void detach();
+
+  // compute total number of arcs
+  void compute_total();
+  
+  // raw print (vertex by vertex)
+  void print();
+
+  // distribution print (degree frequency)
+  void print_cumul();
+
+  // is degree sequence realizable ?
+  bool havelhakimi();
+
+};
+
+} // namespace gengraph
+
+#endif //DEGREE_SEQUENCE_H
+
diff --git a/src/gengraph_graph_molloy_hash.cpp b/src/gengraph_graph_molloy_hash.cpp
new file mode 100644
index 0000000..b1825e0
--- /dev/null
+++ b/src/gengraph_graph_molloy_hash.cpp
@@ -0,0 +1,1043 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#include "gengraph_definitions.h"
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+
+#include "gengraph_qsort.h"
+#include "gengraph_hash.h"
+#include "gengraph_degree_sequence.h"
+#include "gengraph_graph_molloy_hash.h"
+
+#include "config.h"
+#include "igraph_math.h"
+#include "igraph_constructors.h"
+#include "igraph_error.h"
+#include "igraph_statusbar.h"
+#include "igraph_progress.h"
+
+namespace gengraph {
+
+//_________________________________________________________________________
+void graph_molloy_hash::compute_neigh() {
+  int *p = links;
+  for(int i=0; i<n; i++) {
+    neigh[i] = p;
+    p += HASH_SIZE(deg[i]);
+  }
+}
+
+//_________________________________________________________________________
+void graph_molloy_hash::compute_size() {
+  size = 0;
+  for(int i=0; i<n; i++) size += HASH_SIZE(deg[i]);
+}
+
+//_________________________________________________________________________
+void graph_molloy_hash::init() {
+  for(int i=0; i<size; i++) links[i]=HASH_NONE;
+}
+  
+//_________________________________________________________________________
+graph_molloy_hash::graph_molloy_hash(degree_sequence &degs) {
+  igraph_status("Allocating memory for graph...", 0);
+  int s = alloc(degs);
+  igraph_statusf("%d bytes allocated successfully\n", 0, s);
+}
+
+//_________________________________________________________________________
+int graph_molloy_hash::alloc(degree_sequence &degs) {
+  n = degs.size();
+  a = degs.sum();
+  assert(a%2 == 0);
+
+  deg = degs.seq();
+  compute_size();
+  deg = new int[n+size];
+  if(deg==NULL) return 0;
+  int i;
+  for(i=0; i<n; i++) deg[i]=degs[i];
+  links = deg+n;
+  init();
+  neigh = new int*[n];
+  if(neigh==NULL) return 0;
+  compute_neigh();
+  return sizeof(int *)*n + sizeof(int)*(n+size);
+}
+
+//_________________________________________________________________________
+graph_molloy_hash::~graph_molloy_hash() {
+  if(deg!=NULL) delete[] deg;
+  if(neigh!=NULL) delete[] neigh;
+  deg = NULL;
+  neigh = NULL;
+}
+
+//_________________________________________________________________________
+graph_molloy_hash::graph_molloy_hash(int *svg) {
+  // Read n
+  n = *(svg++);
+  // Read a
+  a = *(svg++);
+  assert(a%2 == 0);
+  // Read degree sequence
+  degree_sequence dd(n, svg);
+  // Build neigh[] and alloc links[]
+  alloc(dd);
+  dd.detach();
+  // Read links[]
+  restore(svg+n);
+}
+
+//_________________________________________________________________________
+int *graph_molloy_hash::hard_copy() {
+  int *hc = new int[2+n+a/2]; // to store n,a,deg[] and links[]
+  hc[0] = n;
+  hc[1] = a;
+  memcpy(hc+2,deg,sizeof(int)*n);
+  int *p = hc+2+n;
+  int *l = links;
+  for(int i=0; i<n; i++) for(int j=HASH_SIZE(deg[i]); j--; l++) {
+    register int d;
+    if((d = *l)!=HASH_NONE && d>=i) *(p++)=d;
+  }
+  assert(p==hc+2+n+a/2);
+  return hc;
+}
+
+//_________________________________________________________________________
+bool graph_molloy_hash::is_connected() {
+  bool *visited = new bool[n];
+  int *buff = new int[n];
+  int comp_size = depth_search(visited, buff);
+  delete[] visited;
+  delete[] buff;
+  return (comp_size==n);
+}
+
+//_________________________________________________________________________
+int* graph_molloy_hash::backup() {
+  int *b = new int[a/2];
+  int *c = b;
+  int *p = links;
+  for(int i=0; i<n; i++)
+    for(int d=HASH_SIZE(deg[i]); d--; p++) if(*p!=HASH_NONE && *p>i) *(c++)=*p;
+  assert(c==b+(a/2));
+  return b;
+}
+
+//_________________________________________________________________________
+void graph_molloy_hash::restore(int* b) {
+  init();
+  int i;
+  int *dd = new int[n];
+  memcpy(dd,deg,sizeof(int)*n);
+  for(i=0; i<n; i++) deg[i] = 0;
+  for(i=0; i<n-1; i++) {
+    while (deg[i] < dd[i]) {
+      add_edge(i, *b, dd);
+      b++;
+    }
+  }
+  delete[] dd;
+}
+
+//_________________________________________________________________________
+bool graph_molloy_hash::isolated(int v, int K, int *Kbuff, bool *visited) {
+  if(K<2) return false;
+#ifdef OPT_ISOLATED
+  if(K<=deg[v]+1) return false;
+#endif //OPT_ISOLATED
+  int *seen  = Kbuff;
+  int *known = Kbuff;
+  int *max   = Kbuff + K;
+  *(known++) = v;
+  visited[v] = true;
+  bool is_isolated = true;
+  
+  while(known != seen) {
+    v = *(seen++);
+    int *ww = neigh[v];
+    int w;
+    for(int d=HASH_SIZE(deg[v]); d--; ww++) if((w=*ww)!=HASH_NONE && !visited[w]) {
+#ifdef OPT_ISOLATED
+      if(K<=deg[w]+1 || known == max) {
+#else //OPT_ISOLATED
+      if(known == max) {
+#endif //OPT_ISOLATED
+        is_isolated = false;
+        goto end_isolated;
+      }
+      visited[w] = true;
+      *(known++) = w;
+    }
+  }
+end_isolated:
+  // Undo the changes to visited[]...
+  while(known != Kbuff) visited[*(--known)] = false;
+  return is_isolated;
+}
+
+//_________________________________________________________________________
+int graph_molloy_hash::random_edge_swap(int K, int *Kbuff, bool *visited) {
+  // Pick two random vertices a and c
+  int f1 = pick_random_vertex();
+  int f2 = pick_random_vertex();
+  // Check that f1 != f2
+  if(f1==f2) return 0;
+  // Get two random edges (f1,*f1t1) and (f2,*f2t2)
+  int *f1t1 = random_neighbour(f1);
+  int t1 = *f1t1;
+  int *f2t2 = random_neighbour(f2);
+  int t2 = *f2t2;
+  // Check simplicity
+  if(t1==t2 || f1==t2 || f2==t1) return 0;
+  if(is_edge(f1,t2) || is_edge(f2,t1)) return 0;
+  // Swap
+  int *f1t2 = H_rpl(neigh[f1],deg[f1],f1t1,t2);
+  int *f2t1 = H_rpl(neigh[f2],deg[f2],f2t2,t1);
+  int *t1f2 = H_rpl(neigh[t1],deg[t1],f1,f2);
+  int *t2f1 = H_rpl(neigh[t2],deg[t2],f2,f1);
+  // isolation test
+  if(K<=2) return 1;
+  if( !isolated(f1, K, Kbuff, visited) && !isolated(f2, K, Kbuff, visited) )
+    return 1;
+  // undo swap
+  H_rpl(neigh[f1],deg[f1],f1t2,t1);
+  H_rpl(neigh[f2],deg[f2],f2t1,t2);
+  H_rpl(neigh[t1],deg[t1],t1f2,f1);
+  H_rpl(neigh[t2],deg[t2],t2f1,f2);
+  return 0;
+}
+
+//_________________________________________________________________________
+unsigned long graph_molloy_hash::shuffle(unsigned long times, 
+					 unsigned long maxtimes, int type) {
+  igraph_progress("Shuffle", 0, 0);
+  // assert(verify());
+  // counters
+  unsigned long nb_swaps = 0;
+  unsigned long all_swaps = 0;
+  unsigned long cost = 0;
+  // window
+  double T = double(min((unsigned long)(a),times)/10);
+  if(type==OPTIMAL_HEURISTICS) T=double(optimal_window());
+  if(type==BRUTE_FORCE_HEURISTICS) T=double(times*2);
+  // isolation test parameter, and buffers
+  double K = 2.4;
+  int *Kbuff = new int[int(K)+1];
+  bool *visited = new bool[n];
+  for(int i=0; i<n; i++) visited[i] = false;
+  // Used for monitoring , active only if VERBOSE()
+  int failures = 0;
+  int successes = 0;
+  double avg_K = 0;
+  double avg_T = 0;
+  unsigned long next = times;
+  next=0;
+  
+  // Shuffle: while #edge swap attempts validated by connectivity < times ...
+  while(times>nb_swaps && maxtimes>all_swaps) {
+    // Backup graph
+    int *save = backup();
+    // Prepare counters, K, T
+    unsigned long swaps = 0;
+    int K_int = 0;
+    if(type == FINAL_HEURISTICS || type == BRUTE_FORCE_HEURISTICS) K_int=int(K);
+    unsigned long T_int = (unsigned long)(floor(T));
+    if(T_int<1) T_int=1;
+    // compute cost
+    cost += T_int;
+    if(K_int>2) cost += (unsigned long)(K_int)*(unsigned long)(T_int);
+    // Perform T edge swap attempts
+    for(int i=T_int; i>0; i--) {
+      // try one swap
+      swaps += (unsigned long)(random_edge_swap(K_int, Kbuff, visited));
+      all_swaps++;
+      // Verbose
+      if(nb_swaps+swaps>next) {
+        next = (nb_swaps+swaps)+max((unsigned long)(100),(unsigned long)(times/1000));
+        int progress = int(double(nb_swaps+swaps) / double(times));
+        igraph_progress("Shuffle",  progress, 0);
+      }
+    }
+    // test connectivity
+    cost+=(unsigned long)(a/2);
+    bool ok = is_connected();
+    // performance monitor
+    {
+      avg_T += double(T_int); avg_K += double(K_int);
+      if(ok) successes++; else failures++;
+    }
+    // restore graph if needed, and count validated swaps
+    if(ok) nb_swaps += swaps;
+    else {
+      restore(save);
+      next=nb_swaps;
+    }
+    delete[] save;
+    // Adjust K and T following the heuristics.
+    switch(type) {
+      int steps;
+      case GKAN_HEURISTICS:
+        if (ok) T+=1.0; else T*=0.5;
+        break;
+      case FAB_HEURISTICS:
+        steps = 50 / (8+failures+successes);
+	if(steps<1) steps=1;
+	while(steps--) if(ok) T*=1.17182818; else T*=0.9;
+	if(T>double(5*a)) T=double(5*a);
+        break;
+      case FINAL_HEURISTICS:
+        if(ok) { if((K+10.0)*T>5.0*double(a)) K/=1.03; else T*=2; }
+	else { K*=1.35; delete[] Kbuff; Kbuff = new int[int(K)+1]; }
+	break;
+      case OPTIMAL_HEURISTICS:
+        if(ok) T=double(optimal_window());
+	break;
+      case BRUTE_FORCE_HEURISTICS:
+        K*=2; delete[] Kbuff; Kbuff = new int[int(K)+1];
+	break;
+      default:
+        IGRAPH_ERROR("Error in graph_molloy_hash::shuffle(): " 
+		     "Unknown heuristics type", IGRAPH_EINVAL);
+        return 0;
+    }
+  }
+
+  delete[] Kbuff;
+  delete[] visited;
+
+  if (maxtimes <= all_swaps) { 
+    IGRAPH_WARNING("Cannot shuffle graph, maybe there is only a single one?");
+  }
+  
+  // Status report
+  {
+    igraph_status("*** Shuffle Monitor ***\n", 0);
+    igraph_statusf(" - Average cost : %f / validated edge swap\n", 0,
+		   double(cost)/double(nb_swaps));
+    igraph_statusf(" - Connectivity tests : %d (%d successes, %d failures)\n",
+		   0, successes + failures, successes, failures);
+    igraph_statusf(" - Average window : %d\n", 0, 
+		   int(avg_T/double(successes+failures)));
+    if(type==FINAL_HEURISTICS || type==BRUTE_FORCE_HEURISTICS)
+      igraph_statusf(" - Average isolation test width : %f\n", 0,
+		     avg_K/double(successes+failures));
+  }
+  return nb_swaps;
+}
+
+//_________________________________________________________________________
+void graph_molloy_hash::print(FILE *f) {
+  int i,j;
+  for(i=0; i<n; i++) {
+    fprintf(f,"%d",i);
+    for(j=0; j<HASH_SIZE(deg[i]); j++) if(neigh[i][j]!=HASH_NONE) fprintf(f," %d",neigh[i][j]);
+    fprintf(f,"\n");
+  }
+}
+
+int graph_molloy_hash::print(igraph_t *graph) {
+  int i, j;
+  long int ptr=0;
+  igraph_vector_t edges;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, a); // every edge is counted twice....
+
+  for (i=0; i<n; i++) {
+    for (j=0; j<HASH_SIZE(deg[i]); j++) {
+      if (neigh[i][j]!=HASH_NONE) {
+	if (neigh[i][j] > i) {
+	  VECTOR(edges)[ptr++] = i;
+	  VECTOR(edges)[ptr++] = neigh[i][j];
+	}
+      }
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, /*undirected=*/ 0));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+//_________________________________________________________________________
+bool graph_molloy_hash::try_shuffle(int T, int K, int *backup_graph) {
+  // init all
+  int *Kbuff = NULL;
+  bool *visited = NULL;
+  if(K>2) {
+    Kbuff = new int[K];
+    visited = new bool[n];
+    for(int i=0; i<n; i++) visited[i]=false;
+  }
+  int *back = backup_graph;
+  if(back==NULL) back=backup();
+  // perform T edge swap attempts
+  while(T--) random_edge_swap(K, Kbuff, visited);
+  // clean
+  if(visited != NULL) delete[] visited;
+  if(Kbuff   != NULL) delete[] Kbuff;
+  // check & restore
+  bool yo = is_connected();
+  restore(back);
+  if(backup_graph == NULL) delete[] back;
+  return yo;
+}
+
+//_________________________________________________________________________
+#define _TRUST_BERNOULLI_LOWER 0.01
+
+bool bernoulli_param_is_lower(int success, int trials, double param) {
+  if(double(success)>=double(trials)*param) return false;
+  double comb = 1.0;
+  double fact = 1.0;
+  for(int i=0; i<success; i++) {
+    comb *= double(trials-i);
+    fact *= double(i+1);
+  }
+  comb /= fact;
+  comb *= pow(param, double(success))* exp(double(trials-success)*log1p(-param));
+  double sum = comb;
+  while(success && sum < _TRUST_BERNOULLI_LOWER) {
+    comb *= double(success) * (1.0-param) / (double(trials-success) * param);
+    sum += comb;
+    success--;
+  }
+  // fprintf(stderr,"bernoulli test : %d/%d success against p=%f -> %s\n",success, trials, param, (sum < _TRUST_BERNOULLI_LOWER) ? "lower" : "can't say");
+  return (sum < _TRUST_BERNOULLI_LOWER);
+} 
+
+//_________________________________________________________________________
+#define _MIN_SUCCESS_FOR_BERNOULLI_TRUST 100
+double graph_molloy_hash::average_cost(int T, int *backup, double min_cost) {
+  if(T<1) return 1e+99;
+  int successes = 0;
+  int trials = 0;
+  while(successes < _MIN_SUCCESS_FOR_BERNOULLI_TRUST &&
+        !bernoulli_param_is_lower(successes, trials, 1.0/min_cost)) {
+    if(try_shuffle(T,0,backup)) successes++;
+    trials++;
+  }
+  if(successes >= _MIN_SUCCESS_FOR_BERNOULLI_TRUST)
+    return double(trials)/double(successes)*(1.0+double(a/2)/double(T));
+  else
+    return 2.0*min_cost;
+}
+
+//_________________________________________________________________________
+int graph_molloy_hash::optimal_window() {
+  int Tmax;
+  int optimal_T=1;
+  double min_cost=1e+99;
+  int *back=backup();
+  // on cherche une borne sup pour Tmax
+  int been_greater = 0;
+  for(Tmax=1; Tmax<=5*a ;Tmax*=2) {
+    double c = average_cost(Tmax, back, min_cost);
+    if(c > 1.5 * min_cost) break;
+    if(c > 1.2 * min_cost && ++been_greater >= 3) break;
+    if(c < min_cost) {
+      min_cost = c;
+      optimal_T = Tmax;
+    }
+    igraph_statusf("Tmax = %d [%f]", 0, Tmax, min_cost);
+  }
+  // on cree Tmin
+  int Tmin = int(0.5*double(a)/(min_cost-1.0));
+  igraph_statusf("Optimal T is in [%d, %d]\n", 0, Tmin, Tmax);
+  // on cherche autour
+  double span = 2.0;
+  int try_again = 4;
+  while(span>1.05 && optimal_T <= 5*a) {
+    igraph_statusf("Best T [cost]: %d [%f]", 0, optimal_T, min_cost);
+    int T_low  = int(double(optimal_T)/span);
+    int T_high = int(double(optimal_T)*span);
+    double c_low  = average_cost(T_low , back, min_cost);
+    double c_high = average_cost(T_high, back, min_cost);
+    if(c_low<min_cost && c_high<min_cost) {
+      if(try_again--) continue;
+      {
+	igraph_status("Warning: when looking for optimal T,\n", 0);
+        igraph_statusf("Low: %d [%f]  Middle: %d [%f]  High: %d [%f]\n", 0, 
+		       T_low, c_low, optimal_T, min_cost, T_high, c_high);
+      }
+      delete[] back;
+      return optimal_T;
+    }
+    if(c_low<min_cost) { optimal_T = T_low; min_cost = c_low; }
+    else if(c_high<min_cost) { optimal_T = T_high; min_cost = c_high; };
+    span = pow(span,0.618);
+  }  
+  delete[] back;
+  return optimal_T;
+}
+
+//_________________________________________________________________________
+double graph_molloy_hash::eval_K(int quality) {
+  double K = 5.0;
+  double avg_K = 1.0;
+  for(int i=quality; i--; ) {
+    int int_K = int(floor(K+0.5));
+    if(try_shuffle(a/(int_K+1),int_K)) {
+      K*=0.8; /*fprintf(stderr,"+");*/ }
+    else {
+      K*=1.25; /*fprintf(stderr,"-");*/ }
+    if(i<quality/2) avg_K *= K;
+  }
+  return pow(avg_K,1.0/double(quality/2));
+}
+
+//_________________________________________________________________________
+double graph_molloy_hash::effective_K(int K, int quality) {
+  if(K<3) return 0.0;
+  long sum_K = 0;
+  int *Kbuff = new int[K];
+  bool *visited = new bool[n];
+  int i;
+  for(i=0; i<n; i++) visited[i] = false;
+  for(int i=0; i<quality; i++) {
+    // assert(verify());
+    int f1,f2,t1,t2;
+    int *f1t1, *f2t2;
+    do {
+      // Pick two random vertices
+      do {
+        f1 = pick_random_vertex();
+        f2 = pick_random_vertex();
+      } while(f1==f2);
+      // Pick two random neighbours
+      f1t1 = random_neighbour(f1);
+      t1 = *f1t1;
+      f2t2 = random_neighbour(f2);
+      t2 = *f2t2;
+      // test simplicity
+    }
+    while (t1==t2 || f1==t2 || f2==t1 || is_edge(f1,t2) || is_edge(f2,t1));
+    // swap
+    swap_edges(f1,t2,f2,t1);
+    // assert(verify());
+    sum_K += effective_isolated(deg[f1]>deg[t2] ? f1 : t2, K, Kbuff, visited);
+    // assert(verify());
+    sum_K += effective_isolated(deg[f2]>deg[t1] ? f2 : t1, K, Kbuff, visited);
+    // assert(verify());
+    // undo swap
+    swap_edges(f1,t2,f2,t1);
+    // assert(verify());
+  }
+  delete[] Kbuff;
+  delete[] visited;
+  return double(sum_K)/double(2*quality);
+}
+
+//_________________________________________________________________________
+long graph_molloy_hash::effective_isolated(int v, int K, int *Kbuff, bool *visited) {
+  int i;
+  for(i=0; i<K; i++) Kbuff[i]=-1;
+  long count = 0;
+  int left = K;
+  int *KB = Kbuff;
+  //yapido = (my_random()%1000 == 0);
+  depth_isolated(v, count, left, K, KB, visited);
+  while(KB-- != Kbuff) visited[*KB] = false;
+  //if(yapido) fprintf(stderr,"\n");
+  return count;
+}
+
+//_________________________________________________________________________
+void graph_molloy_hash::depth_isolated(int v, long &calls, int &left_to_explore, int dmax, int * &Kbuff, bool *visited) {
+  if(left_to_explore==0) return;
+//  if(yapido) fprintf(stderr,"%d ",deg[v]);
+  if(--left_to_explore == 0) return;
+  if(deg[v]+1>=dmax) {
+    left_to_explore = 0;
+    return;
+  }
+  *(Kbuff++) = v;
+  visited[v] = true;
+//  print();
+//  fflush(stdout);
+  calls++;
+  int *copy = NULL;
+  int *w = neigh[v];
+  if(IS_HASH(deg[v])) {
+    copy = new int[deg[v]];
+    H_copy(copy,w,deg[v]);
+    w = copy;
+  }
+  qsort(deg, w, deg[v]);
+  w+=deg[v];
+  for(int i=deg[v]; i--; ) {
+    if(visited[*--w]) calls++;
+    else depth_isolated(*w, calls, left_to_explore, dmax, Kbuff, visited);
+    if(left_to_explore==0) break;
+  }
+  if(copy!=NULL) delete[] copy;
+}
+
+//_________________________________________________________________________
+int graph_molloy_hash::depth_search(bool *visited, int *buff, int v0) {
+  for(int i=0; i<n; i++) visited[i] = false;
+  int *to_visit = buff;
+  int nb_visited = 1;
+  visited[v0]=true;
+  *(to_visit++)=v0;
+  while(to_visit != buff && nb_visited<n) {
+    int v = *(--to_visit);
+    int *ww = neigh[v];
+    int w;
+    for(int k=HASH_SIZE(deg[v]); k--; ww++) {
+      if(HASH_NONE!=(w=*ww) && !visited[w]) {
+        visited[w]=true;
+        nb_visited++;
+        *(to_visit++)=w;
+      }
+    }
+  }
+  return nb_visited;
+}
+
+//_________________________________________________________________________
+// bool graph_molloy_hash::verify() {
+//   fprintf(stderr,"Warning: graph_molloy_hash::verify() called..\n");
+//   fprintf(stderr,"   try to convert graph into graph_molloy_opt() instead\n");
+//   return true;
+// }
+
+
+/*____________________________________________________________________________
+  Not to use anymore : use graph_molloy_opt class instead
+
+bool graph_molloy_hash::verify() {
+int i;
+  assert(neigh[0]==links);
+  // verify edges count
+  int sum = 0;
+  for(i=0; i<n; i++) sum+=deg[i];
+  assert(sum==a);
+  // verify neigh[] and deg[] compatibility
+  for(i=0; i<n-1; i++) assert(neigh[i]+HASH_SIZE(deg[i])==neigh[i+1]);
+  // verify hash tables : do we see everyone ?
+  for(i=0; i<n; i++) for(int j=HASH_SIZE(deg[i]); j--; )
+    if(neigh[i][j]!=HASH_NONE) assert(H_is(neigh[i],deg[i],neigh[i][j]));
+  degree_sequence dd(n,deg);
+  graph_molloy_opt g(dd);
+  dd.detach();
+  int *bb = backup();
+  g.restore(bb);
+  delete[] bb;
+  return g.verify();
+}
+
+graph_molloy_hash::graph_molloy_hash(FILE *f) { 
+  char *buff = new char[FBUFF_SIZE];
+  // How many vertices ?
+  if(VERBOSE()) fprintf(stderr,"Read file: #vertices=");
+  int i;
+  int n=0;
+  while(fgets(buff,FBUFF_SIZE,f)) if(sscanf(buff,"%d",&i)==1 && i>n) n=i;
+  n++;
+  // degrees ?
+  if(VERBOSE()) fprintf(stderr,"%d, #edges=",n);
+  int *degs = new int[n];
+  rewind(f);
+  while(fgets(buff,FBUFF_SIZE,f)) {
+    int d = 0;
+    if(sscanf(buff,"%d",&i)==1) {
+      char *b = buff;
+      while(skip_int(b)) d++;
+      degs[i]=d;
+    }
+  }
+  // allocate memory
+  degree_sequence dd(n,degs);
+  if(VERBOSE()) fprintf(stderr,"%d\nAllocating memory...",dd.sum());
+  alloc(dd);
+  // add edges
+  if(VERBOSE()) fprintf(stderr,"done\nCreating edges...");
+  rewind(f);
+  for(i=0; i<n; i++) deg[i]=0;
+  int line=0;
+  int j;
+  while(fgets(buff,FBUFF_SIZE,f)) {
+    line++;
+    if(sscanf(buff,"%d",&i)==1) {
+      char *b = buff;
+      while(skip_int(b)) {
+        if(sscanf(b,"%d",&j)!=1) {
+          fprintf(stderr,"\nParse error at line %d, col %d : integer expected\n",line,int(b-buff));
+          exit(6);
+        }
+        if(i<j) add_edge(i,j,dd.seq());
+      }
+    }
+  }
+  if(VERBOSE()) fprintf(stderr,"done\n");
+  delete[] buff;
+}
+
+
+int graph_molloy_hash::max_degree() {
+  int m=0;
+  for(int k=0; k<n; k++) if(deg[k]>m) m=deg[k];
+  return m;
+}
+
+
+bool graph_molloy_hash::havelhakimi() {
+
+  int i;
+  int dmax = max_degree()+1;
+  // Sort vertices using basket-sort, in descending degrees
+  int *nb = new int[dmax];
+  int *sorted = new int[n];
+  // init basket
+  for(i=0; i<dmax; i++) nb[i]=0;
+  // count basket
+  for(i=0; i<n; i++) nb[deg[i]]++;
+  // cumul
+  int c = 0;
+  for(i=dmax-1; i>=0; i--) {
+    int t=nb[i];
+    nb[i]=c;
+    c+=t;
+  }                                            
+  // sort
+  for(i=0; i<n; i++) sorted[nb[deg[i]]++]=i;
+  // Init edge count
+  for(i=0; i<n; i++) deg[i] = 0;
+
+// Binding process starts
+  int first = 0;  // vertex with biggest residual degree
+  int d = dmax-1; // maximum residual degree available
+
+  for(c=a/2; c>0; ) {
+    // pick a vertex. we could pick any, but here we pick the one with biggest degree
+    int v = sorted[first];
+    // look for current degree of v
+    while(nb[d]<=first) d--;
+    // store it in dv
+    int dv = d;
+    // bind it !
+    c -= dv;
+    int dc = d;         // residual degree of vertices we bind to
+    int fc = ++first;   // position of the first vertex with degree dc
+
+    while(dv>0 && dc>0) {
+      int lc = nb[dc];
+      if(lc!=fc) {
+        while(dv>0 && lc>fc) {
+          // binds v with sorted[--lc]
+          dv--;
+          int w = sorted[--lc];
+          add_edge(v,w);
+        }
+        fc = nb[dc];
+        nb[dc] = lc;
+      }
+      dc--;
+    }
+    if(dv != 0) { // We couldn't bind entirely v
+      if(VERBOSE()) {
+        fprintf(stderr,"Error in graph_molloy_hash::havelhakimi() :\n");
+        fprintf(stderr,"Couldn't bind vertex %d entirely (%d edges remaining)\n",v,dv);
+      }
+      delete[] nb;
+      delete[] sorted;
+      return false;
+    }
+  }
+  assert(c==0);
+  delete[] nb;
+  delete[] sorted;
+  return true;
+}
+
+
+bool graph_molloy_hash::make_connected() {
+  assert(verify());
+  if(a/2 < n-1) {
+    // fprintf(stderr,"\ngraph::make_connected() failed : #edges < #vertices-1\n");
+    return false;
+  }
+  int i;
+ 
+// Data struct for the visit :
+// - buff[] contains vertices to visit
+// - dist[V] is V's distance modulo 4 to the root of its comp, or -1 if it hasn't been visited yet
+#define MC_BUFF_SIZE (n+2)
+  int *buff = new int[MC_BUFF_SIZE];
+  unsigned char * dist  = new unsigned char[n];
+#define NOT_VISITED 255
+#define FORBIDDEN   254
+  for(i=n; i>0; dist[--i]=NOT_VISITED);
+
+// Data struct to store components : either surplus trees or surplus edges are stored at buff[]'s end
+// - A Tree is coded by one of its vertices
+// - An edge (a,b) is coded by the TWO ints a and b
+  int *ffub = buff+MC_BUFF_SIZE;
+  edge *edges = (edge *) ffub;
+  int *trees = ffub;
+  int *min_ffub = buff+1+(MC_BUFF_SIZE%2 ? 0 : 1);
+
+// There will be only one "fatty" component, and trees.
+  edge fatty_edge;
+  fatty_edge.from = -1;
+  bool enough_edges = false;
+
+  // start main loop
+  for(int v0=0; v0<n; v0++) if(dist[v0]==NOT_VISITED) {
+    // is v0 an isolated vertex?
+    if(deg[v0]==0) {
+#ifdef VERBOSE
+      fprintf(stderr,"graph_molloy_opt::make_connected() returned FALSE : vertex %d has degree 0\n",v0);
+#endif //VERBOSE
+      delete[] dist;
+      delete[] buff;
+      return false;
+    }
+    dist[v0] = 0; // root
+    int *to_visit = buff;
+    int *current  = buff;
+    *(to_visit++) = v0;
+
+    // explore component connected to v0
+    bool is_a_tree = true;
+    while(current != to_visit) {
+      int v = *(current++);
+      unsigned char current_dist = dist[v];
+      unsigned char next_dist = (current_dist+1) & 0x03;
+      //unsigned char prev_dist = (current_dist-1) & 0x03;
+      int* ww = neigh[v];
+      int w;
+      for(int k=HASH_SIZE(deg[v]); k--; ww++) if((w=*ww)!=HASH_NONE) {
+        if(dist[w]==NOT_VISITED) {
+          // we didn't visit w yet
+  	      dist[w] = next_dist;
+  	      *(to_visit++) = w;
+          if(to_visit>min_ffub) min_ffub+=2; // update limit of ffub's storage
+          //assert(verify());
+        }
+        else if(dist[w]==next_dist || (w!=HASH_NONE && w>v && dist[w]==current_dist)) {
+          // we found a removable edge
+          if(is_a_tree) {
+            // we must first merge with the fatty component
+            is_a_tree = false;
+            if(fatty_edge.from < 0) {
+              // we ARE the first component! fatty is us
+              fatty_edge.from = v;
+              fatty_edge.to   = w;
+            }
+            else {
+              // we connect to fatty
+              swap_edges(fatty_edge.from, fatty_edge.to, v, w);
+              //assert(verify());
+            }
+          }
+          else {
+            // we have removable edges to give!
+            if(trees!=ffub) {
+              // some trees still.. Let's merge with them!
+              assert(trees>=min_ffub);
+              assert(edges==(edge *)ffub);
+              swap_edges(v,w,*trees,neigh[*trees][0]);
+              trees++;
+              //assert(verify());
+            }
+            else if(!enough_edges) {
+              // Store the removable edge for future use
+              if(edges<=(edge *)min_ffub+1)
+                enough_edges = true;
+              else {
+                edges--;
+                edges->from = v;
+                edges->to   = w;
+              }
+            }
+          }
+        }
+      }
+    }
+    // Mark component
+    while(to_visit!=buff) dist[*(--to_visit)] = FORBIDDEN;
+    // Check if it is a tree
+    if(is_a_tree ) {
+      assert(deg[v0]!=0);
+      if(edges!=(edge *)ffub) {
+        // let's bind the tree we found with a removable edge in stock
+        assert(trees == ffub);
+        if(edges<(edge *)min_ffub) edges=(edge *)min_ffub;
+        swap_edges(v0,neigh[v0][0],edges->from,edges->to);
+        edges++;
+        assert(verify());
+    }
+      else {
+        // add the tree to the list of trees
+        assert(trees>min_ffub);
+        *(--trees) = v0;
+        assert(verify());
+      }
+    }
+  }
+  delete[] buff;
+  delete[] dist;
+  return(trees == ffub);
+}
+
+long long graph_molloy_hash::slow_connected_shuffle(long long times) {
+  assert(verify());
+  long long nb_swaps = 0;
+  int T = 1;
+
+  while(times>nb_swaps) {
+    // Backup graph
+    int *save = backup();
+    // Swaps
+    int swaps = 0;
+    for(int i=T; i>0; i--) {
+      // Pick two random vertices a and c
+      int f1 = pick_random_vertex();
+      int f2 = pick_random_vertex();
+      // Check that f1 != f2
+      if(f1==f2) continue;
+      // Get two random edges (f1,*f1t1) and (f2,*f2t2)
+      int *f1t1 = random_neighbour(f1);
+      int t1 = *f1t1;
+      int *f2t2 = random_neighbour(f2);
+      int t2 = *f2t2;
+      // Check simplicity
+      if(t1==t2 || f1==t2 || f2==t1) continue;
+      if(is_edge(f1,t2) || is_edge(f2,t1)) continue;
+      // Swap
+      H_rpl(neigh[f1],deg[f1],f1t1,t2);
+      H_rpl(neigh[f2],deg[f2],f2t2,t1);
+      H_rpl(neigh[t1],deg[t1],f1,f2);
+      H_rpl(neigh[t2],deg[t2],f2,f1);
+      swaps++;
+    }
+    // test connectivity
+    bool ok = is_connected();
+    if(ok) {
+      nb_swaps += swaps;
+    }
+    else {
+      restore(save);
+    }
+    delete[] save;
+  }
+  return nb_swaps;
+}
+
+
+int graph_molloy_hash::width_search(unsigned char *dist, int *buff, int v0) {
+  for(int i=0; i<n; i++) dist[i] = 0;
+  int *to_visit = buff;
+  int *to_add = buff;
+  int nb_visited = 1;
+  dist[v0]=1;
+  *(to_add++)=v0;
+  while(to_visit != to_add && nb_visited<n) {
+    int v = *(to_visit++);
+    int *ww = neigh[v];
+    int w;
+    unsigned char d = next_dist(dist[v]);
+    for(int k=HASH_SIZE(deg[v]); k--; ww++) {
+      if(HASH_NONE!=(w=*ww) && dist[w]==0) {
+        dist[w]=d;
+        nb_visited++;
+        *(to_add++)=w;
+      }
+    }
+  }
+  return nb_visited;
+}
+
+
+  
+int *graph_molloy_hash::vertex_betweenness_rsp(bool trivial_paths) {
+  int i;
+  unsigned char *dist = new unsigned char[n];
+  int *buff = new int[n];
+  int *b = new int[n];
+  int *bb = new int[n];
+  for(i=0; i<n; i++) b[i]=0;
+  for(int v0 = 0; v0<n; v0++) {
+    for(i=0; i<n; i++) bb[i]=0;
+    int nb_vertices = width_search(dist, buff, v0);
+    while(--nb_vertices) {
+      int v=buff[nb_vertices];
+      int d = prev_dist(dist[v]);
+      int *adj = neigh[v];
+      int adj_size = deg[v];
+      int *ww;
+      do ww=H_random(adj,adj_size); while(dist[*ww]!=d);
+      if(trivial_paths || *ww!=v0) bb[*ww] += bb[v]+1;
+      if(trivial_paths) bb[v]++;
+    }
+    for(i=0; i<n; i++) b[i]+=bb[i];
+  }
+  delete[] dist;
+  delete[] buff;
+  delete[] bb;
+  return b;
+}
+
+double *graph_molloy_hash::vertex_betweenness_asp(bool trivial_paths) {
+  int i;
+  unsigned char *dist = new unsigned char[n];
+  int *buff = new int[n];
+  double *b = new double[n];
+  double *bb = new double[n];
+  for(i=0; i<n; i++) b[i]=0.0;
+  for(int v0 = 0; v0<n; v0++) {
+    for(i=0; i<n; i++) bb[i]=0.0;
+    int nb_vertices = width_search(dist, buff, v0);
+    if(!trivial_paths) dist[v0]=2;
+    while(--nb_vertices) {
+      int v=buff[nb_vertices];
+      int d = prev_dist(dist[v]);
+      int nb_father = 0;
+      int *ww = neigh[v];
+      int k;
+      for(k=HASH_SIZE(deg[v]); k--; ww++) if(*ww != HASH_NONE && dist[*ww]==d) nb_father++;
+      if(nb_father!=0) {
+        double badd = (bb[v]+1.0)/double(nb_father);
+        ww = neigh[v];
+        for(k=HASH_SIZE(deg[v]); k--; ww++) if(*ww != HASH_NONE && dist[*ww]==d) bb[*ww]+=badd;
+      }
+      if(trivial_paths) bb[v]+=1.0;
+    }
+    for(i=0; i<n; i++) b[i]+=bb[i];
+  }
+  delete[] dist;
+  delete[] buff;
+  delete[] bb;
+  return b;
+}
+    
+//___________________________________________________________________________________
+//*/
+
+} // namespace gengraph
diff --git a/src/gengraph_graph_molloy_hash.h b/src/gengraph_graph_molloy_hash.h
new file mode 100644
index 0000000..9afa8f1
--- /dev/null
+++ b/src/gengraph_graph_molloy_hash.h
@@ -0,0 +1,198 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef GRAPH_MOLLOY_HASH_H
+#define GRAPH_MOLLOY_HASH_H
+
+#include "gengraph_definitions.h"
+#include "gengraph_hash.h"
+#include "gengraph_degree_sequence.h"
+
+#include <string.h>
+#include <assert.h>
+// This class handles graphs with a constant degree sequence.
+
+#define FINAL_HEURISTICS        0
+#define GKAN_HEURISTICS         1
+#define FAB_HEURISTICS          2
+#define OPTIMAL_HEURISTICS      3
+#define BRUTE_FORCE_HEURISTICS  4
+
+namespace gengraph {
+
+//****************************
+//  class graph_molloy_hash
+//****************************
+
+class graph_molloy_hash {
+
+private:
+  // Number of vertices
+  int n;
+  //Number of arcs ( = #edges * 2 )
+  int a;
+  //Total size of links[]
+  int size;
+  // The degree sequence of the graph
+  int *deg;
+  // The array containing all links
+  int *links;
+  // The array containing pointers to adjacency list of every vertices
+  int **neigh;
+  // Counts total size
+  void compute_size();
+  // Build neigh with deg and links
+  void compute_neigh();
+  // Allocate memory according to degree_sequence (for constructor use only!!)
+  int alloc(degree_sequence &);
+  // Add edge (a,b). Return FALSE if vertex a is already full.
+  // WARNING : only to be used by havelhakimi(), restore() or constructors
+  inline bool add_edge(int a,int b,int *realdeg) {
+    int deg_a = realdeg[a];
+    if(deg_a == deg[a]) return false;
+    // Check that edge was not already inserted
+    assert(fast_search(neigh[a],int((a==n-1 ? links+size : neigh[a+1])-neigh[a]),b)==NULL);
+    assert(fast_search(neigh[b],int((b==n-1 ? links+size : neigh[b+1])-neigh[b]),a)==NULL);
+    assert(deg[a]<deg_a);
+    int deg_b = realdeg[b];
+    if(IS_HASH(deg_a)) *H_add(neigh[a],HASH_EXPAND(deg_a),b)=b;
+    else neigh[a][deg[a]] = b;
+    if(IS_HASH(deg_b)) *H_add(neigh[b],HASH_EXPAND(deg_b),a)=a;
+    else neigh[b][deg[b]] = a;
+    deg[a]++;
+    deg[b]++;
+    // Check that edge was actually inserted
+    assert(fast_search(neigh[a],int((a==n-1 ? links+size : neigh[a+1])-neigh[a]),b)!=NULL);
+    assert(fast_search(neigh[b],int((b==n-1 ? links+size : neigh[b+1])-neigh[b]),a)!=NULL);
+    return true;
+  }
+  // Swap edges
+  inline void swap_edges(int from1, int to1, int from2, int to2) {
+    H_rpl(neigh[from1],deg[from1],to1,to2);
+    H_rpl(neigh[from2],deg[from2],to2,to1);
+    H_rpl(neigh[to1],deg[to1],from1,from2);
+    H_rpl(neigh[to2],deg[to2],from2,from1);
+  }
+  // Backup graph [sizeof(int) bytes per edge]
+  int* backup();
+  // Test if vertex is in an isolated component of size<K
+  bool isolated(int v, int K, int *Kbuff, bool *visited);
+  // Pick random edge, and gives a corresponding vertex
+  inline int pick_random_vertex() { 
+    int v;
+    do v = links[my_random()%size]; while(v==HASH_NONE);
+    return v;
+  }
+  // Pick random neighbour
+  inline int* random_neighbour(const int v) { return H_random(neigh[v],deg[v]); }
+  // Depth-first search.
+  int depth_search(bool *visited, int *buff, int v0=0);
+  // Returns complexity of isolation test
+  long effective_isolated(int v, int K, int *Kbuff, bool *visited);
+  // Depth-Exploration. Returns number of steps done. Stops when encounter vertex of degree > dmax.
+  void depth_isolated(int v, long &calls, int &left_to_explore, int dmax, int * &Kbuff, bool *visited);
+
+
+public:
+  //degree of v
+  inline int degree(const int v) { return deg[v]; };
+  // For debug purposes : verify validity of the graph (symetry, simplicity)
+  bool verify();
+  // Destroy deg[], neigh[] and links[]
+  ~graph_molloy_hash();
+  // Allocate memory for the graph. Create deg and links. No edge is created.
+  graph_molloy_hash(degree_sequence &);
+  // Create graph from hard copy
+  graph_molloy_hash(int *);
+  // Create hard copy of graph
+  int *hard_copy();
+  // Restore from backup
+  void restore(int* back);
+  //Clear hash tables
+  void init();
+  // nb arcs
+  inline int nbarcs() { return a; };
+  // nb vertices
+  inline int nbvertices() { return n; };
+  // print graph in SUCC_LIST mode, in stdout
+  void print(FILE *f = stdout);
+  int print(igraph_t *graph);
+  // Test if graph is connected
+  bool is_connected();
+  // is edge ?
+  inline bool is_edge(int a, int b) {
+    assert(H_is(neigh[a],deg[a],b) == (fast_search(neigh[a],HASH_SIZE(deg[a]),b)!=NULL));
+    assert(H_is(neigh[b],deg[b],a) == (fast_search(neigh[b],HASH_SIZE(deg[b]),a)!=NULL));
+    assert(H_is(neigh[a],deg[a],b) == H_is(neigh[b],deg[b],a));
+    if(deg[a]<deg[b]) return H_is(neigh[a],deg[a],b);
+    else return H_is(neigh[b],deg[b],a);
+  }
+  // Random edge swap ATTEMPT. Return 1 if attempt was a succes, 0 otherwise
+  int random_edge_swap(int K=0, int *Kbuff=NULL, bool *visited=NULL);
+  // Connected Shuffle
+  unsigned long shuffle(unsigned long, unsigned long, int type);
+  // Optimal window for the gkantsidis heuristics
+  int optimal_window();
+  // Average unitary cost per post-validated edge swap, for some window
+  double average_cost(int T, int *back, double min_cost);
+  // Get caracteristic K
+  double eval_K(int quality = 100);
+  // Get effective K
+  double effective_K(int K, int quality = 10000);
+  // Try to shuffle T times. Return true if at the end, the graph was still connected.
+  bool try_shuffle(int T, int K, int *back=NULL);
+
+
+/*_____________________________________________________________________________
+  Not to use anymore : use graph_molloy_opt class instead
+
+private:
+  // breadth-first search. Store the distance (modulo 3)  in dist[]. Returns eplorated component size.
+  int width_search(unsigned char *dist, int *buff, int v0=0);
+
+public:
+  // Create graph
+  graph_molloy_hash(FILE *f);
+  // Bind the graph avoiding multiple edges or self-edges (return false if fail)
+  bool havelhakimi();
+  // Get the graph connected  (return false if fail)
+  bool make_connected();
+  // "Fab" Shuffle (Optimized heuristic of Gkantsidis algo.)
+  long long fab_connected_shuffle(long long);
+  // Naive Shuffle
+  long long slow_connected_shuffle(long long);
+  // Maximum degree
+  int max_degree();
+  // compute vertex betweenness : for each vertex, a unique random shortest path is chosen.
+  // this choice is consistent (if shortest path from a to c goes through b and then d,
+  // then shortest path from a to d goes through b). If(trivial path), also count all the
+  // shortest paths where vertex is an extremity
+  int *vertex_betweenness_rsp(bool trivial_path);
+  // same, but when multiple shortest path are possible, average the weights.
+  double *vertex_betweenness_asp(bool trivial_path);
+//___________________________________________________________________________________
+//*/
+
+};
+
+} // namespace gengraph
+
+#endif //GRAPH_MOLLOY_HASH_H
+
diff --git a/src/gengraph_graph_molloy_optimized.cpp b/src/gengraph_graph_molloy_optimized.cpp
new file mode 100644
index 0000000..ab5be90
--- /dev/null
+++ b/src/gengraph_graph_molloy_optimized.cpp
@@ -0,0 +1,2013 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#include "gengraph_definitions.h"
+#include <cassert>
+#include <cstdio>
+#include <cmath>
+#include <limits>
+
+#include "gengraph_qsort.h"
+#include "gengraph_box_list.h"
+#include "gengraph_vertex_cover.h"
+#include "gengraph_degree_sequence.h"
+#include "gengraph_graph_molloy_optimized.h"
+
+#include "igraph_error.h"
+#include "igraph_statusbar.h"
+#include "igraph_progress.h"
+
+using namespace std;
+
+namespace gengraph {
+
+void graph_molloy_opt::breadth_search(int *dist, int v0, int *buff) {
+  bool tmpbuff = (buff==NULL);
+  if(tmpbuff) buff = new int[n];
+  for(int i=0; i<n; i++) dist[i]=-1;
+  dist[v0]=0;
+  int *visited = buff;
+  int *to_visit = buff;
+  *to_visit++ = v0;
+  while(visited!=to_visit) {
+    int v = *visited++;
+    int *w = neigh[v];
+    int dd = dist[v]+1;
+    for(int d=deg[v]; d--; w++) if(dist[*w]<0) {
+      dist[*w] = dd;
+      *to_visit++ = *w;
+    }
+  }
+  if(tmpbuff) delete[] buff;
+}
+  
+  
+int graph_molloy_opt::max_degree() {
+  int m=0;
+  for(int k=0; k<n; k++) if(deg[k]>m) m=deg[k];
+  return m;
+}
+
+void graph_molloy_opt::compute_neigh() {
+  int *p = links;
+  for(int i=0; i<n; i++) {
+    neigh[i] = p;
+    p += deg[i];
+  }
+}
+
+void graph_molloy_opt::alloc(degree_sequence &degs) {
+  n = degs.size();
+  a = degs.sum();
+  assert(a%2 == 0);
+  deg = new int[n+a];
+  for(int i=0; i<n; i++) deg[i]=degs[i];
+  links = deg+n;
+  neigh = new int*[n];
+  compute_neigh();
+}
+
+graph_molloy_opt::graph_molloy_opt(degree_sequence &degs) {
+  alloc(degs);
+}
+
+// graph_molloy_opt::graph_molloy_opt(FILE *f) { 
+//   char *buff = new char[FBUFF_SIZE];
+//   // How many vertices ?
+//   if(VERBOSE()) fprintf(stderr,"Read file: #vertices=");
+//   int i;
+//   int n=0;
+//   while(fgets(buff,FBUFF_SIZE,f)) if(sscanf(buff,"%d",&i)==1 && i>n) n=i;
+//   n++;
+//   // degrees ?
+//   if(VERBOSE()) fprintf(stderr,"%d, #edges=",n);
+//   int *degs = new int[n];
+//   for(i=0; i<n; i++) degs[i]=0;
+//   rewind(f);
+//   while(fgets(buff,FBUFF_SIZE,f)) {
+//     int d = 0;
+//     if(sscanf(buff,"%d",&i)==1) {
+//       char *b = buff;
+//       while(skip_int(b)) d++;
+//       degs[i]=d;
+//     }
+//   }
+//   // allocate memory
+//   degree_sequence dd(n,degs);
+//   a = dd.sum();
+//   if(VERBOSE()) fprintf(stderr,"%d\nAllocating memory...",a);
+//   alloc(dd);
+//   // add edges
+//   if(VERBOSE()) fprintf(stderr,"done\nCreating edges...");
+//   rewind(f);
+//   int line=0;
+//   int j;
+//   while(fgets(buff,FBUFF_SIZE,f)) {
+//     line++;
+//     if(sscanf(buff,"%d",&i)==1) {
+//       char *b = buff;
+//       while(skip_int(b)) {
+//         if(sscanf(b,"%d",&j)!=1) {
+//           fprintf(stderr,"\nParse error at line %d, col %d : integer expected\n",line,int(b-buff));
+//           exit(6);
+//         }
+//         *(neigh[i]++) = j;
+//       }
+//     }
+//   }
+//   delete[] buff;
+//   compute_neigh();
+//   if(VERBOSE()) fprintf(stderr,"done\n");
+// }
+
+graph_molloy_opt::graph_molloy_opt(int *svg) {
+  // Read n
+  n = *(svg++);
+  // Read a
+  a = *(svg++);
+  assert(a%2 == 0);
+  // Read degree sequence
+  degree_sequence dd(n, svg);
+  // Build neigh[] and alloc links[]
+  alloc(dd);
+  dd.detach();
+  // Read links[]
+  restore(svg+n);
+}
+
+void graph_molloy_opt::detach() {
+  deg = NULL;
+  neigh = NULL;
+}
+
+graph_molloy_opt::~graph_molloy_opt() {
+  if(deg!=NULL) delete[] deg;
+  if(neigh!=NULL) delete[] neigh;
+  detach();
+} 
+
+int* graph_molloy_opt::backup(int *b) {
+  if(b==NULL) b = new int[a/2];
+  int *c = b;
+  for(int i=0; i<n; i++) {
+    int *p = neigh[i];
+    for(int d=deg[i]; d--; p++) { assert(*p!=i); if(*p>=i) *(c++)=*p; }
+  }
+  assert(c==b+(a/2));
+  return b;
+}
+
+int *graph_molloy_opt::hard_copy() {
+  int *hc = new int[2+n+a/2]; // to store n,a,deg[] and links[]
+  hc[0] = n;
+  hc[1] = a;
+  memcpy(hc+2,deg,sizeof(int)*n);
+  int *c = hc+2+n;
+  for(int i=0; i<n; i++) {
+    int *p = neigh[i];
+    for(int d=deg[i]; d--; p++) { assert(*p!=i); if(*p>=i) *(c++)=*p; }
+  }
+  assert(c==hc+2+n+a/2);
+  return hc;
+}
+
+void graph_molloy_opt::restore(int* b) {
+  int i;
+  for(i=0; i<n; i++) deg[i]=0;
+  int *p = links;
+  for(i=0; i<n-1; i++) {
+    p+=deg[i];
+    deg[i] = int(neigh[i+1] - neigh[i]);
+    assert((neigh[i]+deg[i]) == neigh[i+1]);
+    while(p!=neigh[i+1]) {
+      // b points to the current 'j'
+      neigh[*b][deg[*b]++]=i;
+      *(p++) = *(b++);
+    }
+  }
+}
+
+int* graph_molloy_opt::backup_degs(int *b) {
+  if(b==NULL) b = new int[n];
+  memcpy(b,deg,sizeof(int)*n);
+  return b;
+}
+
+void graph_molloy_opt::restore_degs_only(int *b) {
+  memcpy(deg,b,sizeof(int)*n);
+  refresh_nbarcs();
+}
+
+void graph_molloy_opt::restore_degs_and_neigh(int *b) {
+  restore_degs_only(b);
+  compute_neigh();
+}
+
+void graph_molloy_opt::restore_degs(int last_degree) {
+  a = last_degree;
+  deg[n-1]=last_degree;
+  for(int i=n-2; i>=0; i--) a+=(deg[i]=int(neigh[i+1]-neigh[i]));
+  refresh_nbarcs();
+}
+
+void graph_molloy_opt::clean() {
+  int *b = hard_copy();
+  replace(b);
+  delete[] b;
+}
+
+void graph_molloy_opt::replace(int *_hardcopy) {
+  delete[] deg;
+  n = *(_hardcopy++);
+  a = *(_hardcopy++);
+  deg = new int[a+n];
+  memcpy(deg,_hardcopy,sizeof(int)*n);
+  links = deg+n;
+  compute_neigh();
+  restore(_hardcopy+n);
+}
+
+int* graph_molloy_opt::components(int *comp) {
+  int i;
+  // breadth-first search buffer
+  int *buff=new int[n];
+  // comp[i] will contain the index of the component that contains vertex i
+  if(comp==NULL) comp=new int[n];
+  memset(comp,0,sizeof(int)*n);
+  // current component index
+  int curr_comp = 0;
+  // loop over all non-visited vertices...
+  for(int v0=0; v0<n; v0++) if(comp[v0]==0) {
+    curr_comp++;
+    // initiate breadth-first search
+    int *to_visit = buff;
+    int *visited = buff;
+    *(to_visit++) = v0;
+    comp[v0] = curr_comp;
+    // breadth-first search
+    while(visited!=to_visit) {
+      int v = *(visited++);
+      int d = deg[v];
+      for(int *w=neigh[v]; d--; w++) if(comp[*w]==0) {
+	comp[*w] = curr_comp;
+	*(to_visit++) = *w;
+      }
+    }
+  }
+  // compute component sizes and store them in buff[]
+  int nb_comp=0;
+  memset(buff,0,sizeof(int)*n);
+  for(i=0; i<n; i++)
+    if(buff[comp[i]-1]++ == 0 && comp[i] > nb_comp) nb_comp=comp[i];
+  // box-sort sizes
+  int offset = 0;
+  int *box = pre_boxsort(buff,nb_comp,offset);
+  for(i=nb_comp-1; i>=0; i--) buff[i] = --box[buff[i]-offset];
+  delete[] box;
+  // reassign component indexes
+  for(int *c=comp+n; comp!=c--; *c=buff[*c-1]) { }
+  // clean.. at last!
+  delete[] buff;
+  return comp;
+}
+
+void graph_molloy_opt::giant_comp() {
+  int *comp = components();
+  // Clear edges of all vertices that do not belong to comp 0
+  for(int i=0; i<n; i++) if(comp[i]!=0) deg[i]=0;
+  // Clean comp[]
+  delete[] comp;
+}
+
+int graph_molloy_opt::nbvertices_comp() {
+  int *comp = components();
+  // Count all vertices that belong to comp 0
+  int nb = 0;
+  for(int i=0; i<n; i++) if(comp[i]==0) nb++;
+  // Clean comp[]
+  delete[] comp;
+  return nb;
+}
+
+int graph_molloy_opt::nbarcs_comp() {
+  int *comp = components();
+  // Count all vertices that belong to comp 0
+  int nb = 0;
+  for(int i=0; i<n; i++) if(comp[i]==0) nb+=deg[i];
+  // Clean comp[]
+  delete[] comp;
+  return nb;
+}
+
+bool graph_molloy_opt::havelhakimi() {
+
+  int i;
+  int dmax = max_degree()+1;
+  // Sort vertices using basket-sort, in descending degrees
+  int *nb = new int[dmax];
+  int *sorted = new int[n];
+  // init basket
+  for(i=0; i<dmax; i++) nb[i]=0;
+  // count basket
+  for(i=0; i<n; i++) nb[deg[i]]++;
+  // cumul
+  int c = 0;
+  for(i=dmax-1; i>=0; i--) {
+    c+=nb[i];
+    nb[i]=-nb[i]+c;
+  }                                            
+  // sort
+  for(i=0; i<n; i++) sorted[nb[deg[i]]++]=i;
+
+// Binding process starts
+  int first = 0;  // vertex with biggest residual degree
+  int d = dmax-1; // maximum residual degree available
+
+  for(c=a/2; c>0; ) {
+    // pick a vertex. we could pick any, but here we pick the one with biggest degree
+    int v = sorted[first];
+    // look for current degree of v
+    while(nb[d]<=first) d--;
+    // store it in dv
+    int dv = d;
+    // bind it !
+    c -= dv;
+    int dc = d;         // residual degree of vertices we bind to
+    int fc = ++first;   // position of the first vertex with degree dc
+
+    while(dv>0 && dc>0) {
+      int lc = nb[dc];
+      if(lc!=fc) {
+        while(dv>0 && lc>fc) {
+          // binds v with sorted[--lc]
+          dv--;
+          int w = sorted[--lc];
+          *(neigh[v]++) = w;
+          *(neigh[w]++) = v;
+        }
+        fc = nb[dc];
+        nb[dc] = lc;
+      }
+      dc--;
+    }
+    if(dv != 0) { // We couldn't bind entirely v
+      delete[] nb;
+      delete[] sorted;
+      compute_neigh();
+      igraph_errorf("Error in graph_molloy_opt::havelhakimi():"
+		    " Couldn't bind vertex %d entirely "
+		    "(%d edges remaining)", __FILE__, __LINE__, 
+		    IGRAPH_EINTERNAL, v, dv);
+      return false;
+    }
+  }
+  assert(c==0);
+  compute_neigh();
+  delete[] nb;
+  delete[] sorted;
+  return true;
+}
+
+bool graph_molloy_opt::is_connected() {
+  bool *visited = new bool[n];
+  for(int i=n; i>0; visited[--i]=false) { }
+  int *to_visit = new int[n];
+  int *stop = to_visit;
+  int left = n-1;
+  *(to_visit++) = 0;
+  visited[0] = true;
+  while(left>0 && to_visit != stop) {
+    int v = *(--to_visit);
+    int *w = neigh[v];
+    for(int k = deg[v]; k--; w++) if(!visited[*w]) {
+      visited[*w] = true;
+      left--;
+      *(to_visit++) = *w;
+    }
+  }
+  delete[] visited;
+  delete[] stop;
+  assert(left>=0);
+  return (left == 0);
+}
+
+
+bool graph_molloy_opt::make_connected() {
+  //assert(verify());
+  if(a/2 < n-1) {
+    // fprintf(stderr,"\ngraph::make_connected() failed : #edges < #vertices-1\n");
+    return false;
+  }
+  int i;
+ 
+// Data struct for the visit :
+// - buff[] contains vertices to visit
+// - dist[V] is V's distance modulo 4 to the root of its comp, or -1 if it hasn't been visited yet
+#define MC_BUFF_SIZE (n+2)
+  int *buff = new int[MC_BUFF_SIZE];
+  unsigned char * dist  = new unsigned char[n];
+#define NOT_VISITED 255
+#define FORBIDDEN   254
+  for(i=n; i>0; dist[--i]=NOT_VISITED) { }
+
+// Data struct to store components : either surplus trees or surplus edges are stored at buff[]'s end
+// - A Tree is coded by one of its vertices
+// - An edge (a,b) is coded by the TWO ints a and b
+  int *ffub = buff+MC_BUFF_SIZE;
+  edge *edges = (edge *) ffub;
+  int *trees = ffub;
+  int *min_ffub = buff+1+(MC_BUFF_SIZE%2 ? 0 : 1);
+
+// There will be only one "fatty" component, and trees.
+  edge fatty_edge = { -1, -1 };
+  bool enough_edges = false;
+
+  // start main loop
+  for(int v0=0; v0<n; v0++) if(dist[v0]==NOT_VISITED) {
+    // is v0 an isolated vertex?
+    if(deg[v0]==0) {
+      delete[] dist;
+      delete[] buff;
+      igraph_errorf("graph_molloy_opt::make_connected() returned FALSE : "
+		    "vertex %d has degree 0", __FILE__, __LINE__, 
+		    IGRAPH_EINTERNAL, v0);
+      return false;
+    }
+    dist[v0] = 0; // root
+    int *to_visit = buff;
+    int *current  = buff;
+    *(to_visit++) = v0;
+
+    // explore component connected to v0
+    bool is_a_tree = true;
+    while(current != to_visit) {
+      int v = *(current++);
+      unsigned char current_dist = dist[v];
+      unsigned char next_dist = (current_dist+1) & 0x03;
+      //unsigned char prev_dist = (current_dist-1) & 0x03;
+      int* ww = neigh[v];
+      int w;
+      for(int k=deg[v]; k--; ww++) {
+        if(dist[w=*ww]==NOT_VISITED) {
+          // we didn't visit *w yet
+  	      dist[w] = next_dist;
+  	      *(to_visit++) = w;
+          if(to_visit>min_ffub) min_ffub+=2; // update limit of ffub's storage
+          //assert(verify());
+        }
+        else if(dist[w]==next_dist || (w>=v && dist[w]==current_dist)) {
+          // we found a removable edge
+          if(trees!=ffub) {
+            // some trees still.. Let's merge with them!
+            assert(trees>=min_ffub);
+            assert(edges==(edge *)ffub);
+            swap_edges(v,w,*trees,neigh[*trees][0]);
+            trees++;
+            //assert(verify());
+          } else if(is_a_tree) {
+            // we must merge with the fatty component
+            is_a_tree = false;
+            if(fatty_edge.from < 0) {
+              // we ARE the first component! fatty is us
+              fatty_edge.from = v;
+              fatty_edge.to   = w;
+            }
+            else {
+              // we connect to fatty
+              swap_edges(fatty_edge.from, fatty_edge.to, v, w);
+              fatty_edge.to = w;
+              //assert(verify());
+            }
+          } else if(!enough_edges) {
+            // Store the removable edge for future use
+            if(edges<=(edge *)min_ffub+1)
+              enough_edges = true;
+            else {
+              edges--;
+              edges->from = v;
+              edges->to   = w;
+            }
+          }
+        }
+      }
+    }
+    // Mark component
+    while(to_visit!=buff) dist[*(--to_visit)] = FORBIDDEN;
+    // Check if it is a tree
+    if(is_a_tree ) {
+      assert(deg[v0]!=0);
+      if(edges!=(edge *)ffub) {
+        // let's bind the tree we found with a removable edge in stock
+        assert(trees == ffub);
+        if(edges<(edge *)min_ffub) edges=(edge *)min_ffub;
+        swap_edges(v0,neigh[v0][0],edges->from,edges->to);
+        edges++;
+        assert(verify());
+      }
+      else if(fatty_edge.from>=0) {
+        // if there is a fatty component, let's merge with it ! and discard fatty :-/
+        assert(trees == ffub);
+        swap_edges(v0,neigh[v0][0],fatty_edge.from,fatty_edge.to);
+        fatty_edge.from = -1;
+        fatty_edge.to = -1;
+        assert(verify());
+      } else {
+        // add the tree to the list of trees
+        assert(trees>min_ffub);
+        *(--trees) = v0;
+        assert(verify());
+      }
+    }
+  }
+  delete[] buff;
+  delete[] dist;
+  // Should ALWAYS return true : either we have no tree left, or we are a unique, big tree
+  return(trees == ffub || ((trees+1)==ffub && fatty_edge.from<0));
+}
+
+bool graph_molloy_opt::swap_edges_simple(int from1, int to1, int from2, int to2) {
+  if(from1==to1 || from1==from2 || from1==to2 || to1==from2 || to1==to2 || from2==to2) return false;
+  if (is_edge(from1,to2) || is_edge(from2,to1)) return false;
+  swap_edges(from1, to1, from2, to2);
+  return true;
+}
+
+long graph_molloy_opt::fab_connected_shuffle(long times) {
+  //assert(verify());
+  long nb_swaps = 0;
+  double T = double(min(a,times))/10.0;
+  double q1 = 1.131;
+  double q2 = 0.9237;
+  
+  while(times>0) {
+    long iperiod = max(1,long(T));
+    // Backup graph
+    int *save = backup();
+    //assert(verify());
+    // Swaps
+    long swaps = 0;
+    for(long i=iperiod; i>0; i--) {
+      // Pick two random vertices
+      int f1 = links[my_random()%a];
+      int f2 = links[my_random()%a];
+      if(f1==f2) continue;
+      // Pick two random neighbours
+      int *f1t1 = neigh[f1]+my_random()%deg[f1];
+      int *f2t2 = neigh[f2]+my_random()%deg[f2];
+      int t1 = *f1t1;
+      int t2 = *f2t2;
+      // test simplicity
+      if(t1!=t2 && f1!=t2 && f2!=t1 && is_edge(f1,t2) && !is_edge(f2,t1)) {
+        // swap
+        *f1t1 = t2;
+        *f2t2 = t1;
+        fast_rpl(neigh[t1],f1,f2);
+        fast_rpl(neigh[t2],f2,f1);
+        swaps++;
+      }
+    }
+    //assert(verify());
+    // test connectivity
+    if(is_connected()) {
+      nb_swaps += swaps;
+      times -= iperiod;
+      // adjust T
+      T*=q1;
+    }
+    else {
+      restore(save);
+      //assert(verify());
+      T*=q2;
+    }
+    delete[] save;
+  }
+  return nb_swaps;
+}
+
+long graph_molloy_opt::opt_fab_connected_shuffle(long times) {
+  //assert(verify());
+  long nb_swaps = 0;
+  double T = double(min(a,times))/10.0;
+  double q1 = 1.131;
+  double q2 = 0.9237;
+  
+  while(times>0) {
+    long iperiod = max(1,long(T));
+    // Backup graph
+    int *save = backup();
+    //assert(verify());
+    // Swaps
+    long swaps = 0;
+    for(long i=iperiod; i>0; i--) {
+      // Pick two random vertices
+      int f1 = links[my_random()%a];
+      int f2 = links[my_random()%a];
+      if(f1==f2) continue;
+      // Pick two random neighbours
+      int *f1t1 = neigh[f1]+my_random()%deg[f1];
+      int *f2t2 = neigh[f2]+my_random()%deg[f2];
+      int t1 = *f1t1;
+      int t2 = *f2t2;
+      if(
+        // test simplicity
+        t1!=t2 && f1!=t2 && f2!=t1 && is_edge(f1,t2) && !is_edge(f2,t1) &&
+        // test isolated pair
+        (deg[f1]>1 || deg[t2]>1) && (deg[f2]>1 || deg[t1]>1)
+      )
+      {
+        // swap
+        *f1t1 = t2;
+        *f2t2 = t1;
+        fast_rpl(neigh[t1],f1,f2);
+        fast_rpl(neigh[t2],f2,f1);
+        swaps++;
+      }
+    }
+    //assert(verify());
+    // test connectivity
+    if(is_connected()) {
+      nb_swaps += swaps;
+      times -= iperiod;
+      // adjust T
+      T*=q1;
+    }
+    else {
+      restore(save);
+      //assert(verify());
+      T*=q2;
+    }
+    delete[] save;
+  }
+  return nb_swaps;
+}
+
+long graph_molloy_opt::gkantsidis_connected_shuffle(long times) {
+  //assert(verify());
+  long nb_swaps = 0;
+  long T = min(a,times)/10;
+  
+  while(times>0) {
+    // Backup graph
+    int *save = backup();
+    //assert(verify());
+    // Swaps
+    long swaps = 0;
+    for(int i=T; i>0; i--) {
+      // Pick two random vertices
+      int f1 = links[my_random()%a];
+      int f2 = links[my_random()%a];
+      if(f1==f2) continue;
+      // Pick two random neighbours
+      int *f1t1 = neigh[f1]+my_random()%deg[f1];
+      int *f2t2 = neigh[f2]+my_random()%deg[f2];
+      int t1 = *f1t1;
+      int t2 = *f2t2;
+      // test simplicity
+      if(t1!=t2 && f1!=t2 && f2!=t1 && is_edge(f1,t2) && !is_edge(f2,t1)) {
+        // swap
+        *f1t1 = t2;
+        *f2t2 = t1;
+        fast_rpl(neigh[t1],f1,f2);
+        fast_rpl(neigh[t2],f2,f1);
+        swaps++;
+      }
+    }
+    //assert(verify());
+    // test connectivity
+    if(is_connected()) {
+      nb_swaps += swaps;
+      times -= T;
+      // adjust T
+      T++;
+    }
+    else {
+      restore(save);
+      //assert(verify());
+      T/=2; if(T==0) T=1;
+    }
+    delete[] save;
+  }
+  return nb_swaps;
+}
+
+long graph_molloy_opt::slow_connected_shuffle(long times) {
+  //assert(verify());
+  long nb_swaps = 0;
+  
+  while(times--) {
+    // Pick two random vertices
+    int f1 = links[my_random()%a];
+    int f2 = links[my_random()%a];
+    if(f1==f2) continue;
+    // Pick two random neighbours
+    int *f1t1 = neigh[f1]+my_random()%deg[f1];
+    int *f2t2 = neigh[f2]+my_random()%deg[f2];
+    int t1 = *f1t1;
+    int t2 = *f2t2;
+    // test simplicity
+    if(t1!=t2 && f1!=t2 && f2!=t1 && is_edge(f1,t2) && !is_edge(f2,t1)) {
+      // swap
+      *f1t1 = t2;
+      *f2t2 = t1;
+      int *t1f1 = fast_rpl(neigh[t1],f1,f2);
+      int *t2f2 = fast_rpl(neigh[t2],f2,f1);
+      // test connectivity
+      if(is_connected()) nb_swaps++;
+      else {
+        // undo swap
+        *t1f1 = f1; *t2f2 = f2; *f1t1 = t1; *f2t2 = t2;
+      }
+    }
+  }
+  return nb_swaps;
+}
+
+void graph_molloy_opt::print(FILE *f, bool NOZERO) {
+  int i,j;
+  for(i=0; i<n; i++) {
+    if(!NOZERO || deg[i]>0) {
+      fprintf(f,"%d",i);
+      for(j=0; j<deg[i]; j++) fprintf(f," %d",neigh[i][j]);
+      fprintf(f,"\n");
+    }
+  }
+}
+
+long graph_molloy_opt::effective_isolated(int v, int K, int *Kbuff, bool *visited) {
+  int i;
+  for(i=0; i<K; i++) Kbuff[i]=-1;
+  long count = 0;
+  int left = K;
+  int *KB = Kbuff;
+  //yapido = (my_random()%1000 == 0);
+  depth_isolated(v, count, left, K, KB, visited);
+  while(KB-- != Kbuff) visited[*KB] = false;
+  //if(yapido) fprintf(stderr,"\n");
+  return count;
+}
+
+void graph_molloy_opt::depth_isolated(int v, long &calls, int &left_to_explore, int dmax, int * &Kbuff, bool *visited) {
+  if(left_to_explore==0) return;
+//  if(yapido) fprintf(stderr,"%d ",deg[v]);
+  if(--left_to_explore == 0) return;
+  if(deg[v]+1>=dmax) {
+    left_to_explore = 0;
+    return;
+  }
+  *(Kbuff++) = v;
+  visited[v] = true;
+  calls++;
+  int *w = neigh[v];
+  qsort(deg, w, deg[v]);
+  w+=deg[v];
+  for(int i=deg[v]; i--; ) {
+    if(visited[*--w]) calls++;
+    else depth_isolated(*w, calls, left_to_explore, dmax, Kbuff, visited);
+    if(left_to_explore==0) break;
+  }
+}
+
+int graph_molloy_opt::depth_search(bool *visited, int *buff, int v0) {
+  for(int i=0; i<n; i++) visited[i] = false;
+  int *to_visit = buff;
+  int nb_visited = 1;
+  visited[v0]=true;
+  *(to_visit++)=v0;
+  while(to_visit != buff && nb_visited<n) {
+    int v = *(--to_visit);
+    int *ww = neigh[v];
+    int w;
+    for(int k=deg[v]; k--; ww++) if(!visited[w=*ww]) {
+      visited[w]=true;
+      nb_visited++;
+      *(to_visit++)=w;
+    }
+  }
+  return nb_visited;
+}
+
+int graph_molloy_opt::width_search(unsigned char *dist, int *buff, int v0, int toclear) {
+  if(toclear>=0) for(int i=0; i<toclear; i++) dist[buff[i]] = 0;
+  else for(int i=0; i<n; i++) dist[i] = 0;
+  int *to_visit = buff;
+  int *to_add = buff;
+  int nb_visited = 1;
+  dist[v0]=1;
+  *(to_add++)=v0;
+  while(to_visit != to_add && nb_visited<n) {
+    int v = *(to_visit++);
+    int *ww = neigh[v];
+    int w;
+    unsigned char d = next_dist(dist[v]);
+    for(int k=deg[v]; k--; ww++) if(dist[w=*ww]==0) {
+      dist[w]=d;
+      nb_visited++;
+      *(to_add++)=w;
+    }
+  }
+  return nb_visited;
+}  
+
+double graph_molloy_opt::avg_dist(unsigned char *dist, int *buff, int v0, int &nb_visited, int toclear) {
+  nb_visited = width_search(dist,buff,v0,toclear);
+  unsigned char curr_dist=1;
+  assert(curr_dist==dist[v0]);
+  double total_dist=0.0;
+  int current_dist=0;
+  for(int p=0; p<nb_visited; p++) {
+    v0 = buff[p];
+    if(dist[v0]!=curr_dist) {
+      current_dist++;
+      curr_dist = dist[v0];
+    }
+    total_dist += double(current_dist);
+  }
+  nb_visited--;
+  return total_dist / double(nb_visited);
+}  
+
+
+void graph_molloy_opt::add_traceroute_edge(int v, int k, int *newdeg, double **edge_redudancy, double red) {
+  int *ww = neigh[v]+k;
+  int w = *ww;
+  int k2 = 0;
+  // Is neigh[v][k] a new edge ?
+  if(k>=newdeg[v]) {
+    int *p = neigh[v]+(newdeg[v]++);
+    *ww = *p;
+    *p = w;
+    // Now, add the dual edge
+    ww = neigh[w];
+    p = ww+(newdeg[w]);
+    while(ww!=p && *ww != v) { ww++; k2++; }
+    if(ww==p) {
+      // dual edge was not discovered.. search it and add it.
+      while(*ww != v) { ww++; k2++; }
+      *ww = *p;
+      *p = v;
+      newdeg[w]++;
+    }
+  }
+  // if edge redudancy is asked, look for dual edge
+  else if(edge_redudancy!=NULL)
+    for(int *ww = neigh[w]; *(ww++)!=v; k2++) { }
+  // add edge redudancy
+  if(edge_redudancy!=NULL) {
+    edge_redudancy[v][k]  += red;
+    edge_redudancy[w][k2] += red;
+  }
+  assert(newdeg[v]<=deg[v]);
+}
+
+// dist[] MUST be full of zeros !!!!
+int graph_molloy_opt::breadth_path_search(int src, int *buff, double *paths, unsigned char *dist) {
+  unsigned char last_dist = 0;
+  unsigned char curr_dist = 1;
+  int *to_visit = buff;
+  int *visited  = buff;
+  *(to_visit++) = src;
+  paths[src] = 1.0;
+  dist[src]  = curr_dist;
+  int nb_visited = 1;
+  while(visited != to_visit) {
+    int v = *(visited++);
+    if(last_dist==(curr_dist=dist[v])) break;
+    unsigned char nd = next_dist(curr_dist);
+    int *ww = neigh[v];
+    double p = paths[v];
+    for(int k=deg[v]; k--;) {
+      int w=*(ww++);
+      unsigned char d = dist[w];
+      if(d==0) {
+        // not visited yet !
+        *(to_visit++) = w;
+        dist[w] = nd;
+        paths[w]= p;
+        // is it the last one ?
+        if(++nb_visited==n) last_dist=nd;
+      }
+      else if(d==nd) if((paths[w]+=p)==numeric_limits<double>::infinity()) {
+	  IGRAPH_ERROR("Fatal error : too many (>MAX_DOUBLE) possible"
+		       " paths in graph", IGRAPH_EOVERFLOW);
+      }
+    }
+  }
+  assert(to_visit == buff+nb_visited);
+  return nb_visited;
+}
+
+// dist[] MUST be full of zeros !!!!
+void graph_molloy_opt::explore_usp(double *target, int nb_vertices, int *buff, double *paths, unsigned char *dist, int *newdeg, double **edge_redudancy) {
+
+  while(--nb_vertices) {
+    int v = buff[nb_vertices];
+    if(target[v]>0.0) {
+      unsigned char pd = prev_dist(dist[v]);
+      int *ww = neigh[v];
+      int k=0;
+      // pick ONE father at random
+      double father_index = my_random01()*paths[v];
+      double f = 0.0;
+      int father = -1;
+      while(f<father_index) {
+        while(dist[father=ww[k++]]!=pd) { }
+        f+=paths[father];
+      }
+      // increase target[] of father
+      target[father] += target[v];
+      // add edge, if necessary
+      if(newdeg!=NULL) add_traceroute_edge(v,k-1,newdeg,edge_redudancy,target[v]);
+    }
+    // clear dist[]
+    dist[v] = 0;
+  }
+  dist[buff[0]] = 0;
+}
+
+// dist[] MUST be full of zeros !!!!
+void graph_molloy_opt::explore_asp(double *target, int nb_vertices, int *buff, double *paths, unsigned char *dist, int *newdeg, double **edge_redudancy) {
+
+  while(--nb_vertices) {
+    int v = buff[nb_vertices];
+    if(target[v]>0.0) {
+      unsigned char pd = prev_dist(dist[v]);
+      int *ww = neigh[v];
+      int dv = deg[v];
+      double f=target[v]/paths[v];
+      // pick ALL fathers
+      register int father;
+      for(int k=0; k<dv; k++) if(dist[father=ww[k]]==pd) {
+        // increase target[] of father
+        target[father] += paths[father]*f;
+        // add edge, if necessary
+        if(newdeg!=NULL) add_traceroute_edge(v,k,newdeg,edge_redudancy,target[v]);
+      }
+    }
+    // clear dist[]
+    dist[v] = 0;
+  }
+  dist[buff[0]] = 0;
+}
+
+// dist[] MUST be full of zeros !!!!
+void graph_molloy_opt::explore_rsp(double *target, int nb_vertices, int *buff, double *paths, unsigned char *dist, int *newdeg, double** edge_redudancy) {
+
+  while(--nb_vertices) {
+    int v = buff[nb_vertices];
+    if(target[v]>0.0) {
+      unsigned char pd = prev_dist(dist[v]);
+      int *ww = neigh[v];
+      // for all fathers : do we take it ?
+      int paths_left = int(target[v]);
+      double father_index = paths[v];
+      int father;
+      for(int k=0; k<deg[v]; k++) if(dist[father=ww[k]]==pd) {
+        double pf = paths[father];
+        int to_add_to_father = my_binomial(pf/father_index, paths_left);
+        father_index -= pf;
+        if(to_add_to_father>0) {
+          paths_left -= to_add_to_father;
+          // increase target[] of father
+          target[father] += to_add_to_father;
+          // add edge, if necessary
+          if(newdeg!=NULL) add_traceroute_edge(v,k,newdeg,edge_redudancy,target[v]);
+        }
+      }
+    }
+    // clear dist[]
+    dist[v] = 0;
+  }
+  dist[buff[0]] = 0;
+}
+
+double *graph_molloy_opt::vertex_betweenness(int mode, bool trivial_paths) {
+  char MODES[3] = {'U','A','R'};
+  igraph_statusf("Computing vertex betweenness %cSP...", 0, MODES[mode]);
+  
+  // breadth-first search vertex fifo
+  int *buff = new int[n];
+  // breadth-first search path count
+  double *paths = new double[n];
+  // breadth-first search distance vector
+  unsigned char *dist = new unsigned char[n];
+  // global betweenness
+  double *b = new double[n];
+  // local betweenness (for one source)
+  double *target = new double[n];
+  // init all
+  int progress = 0;
+  memset(dist,0,sizeof(unsigned char)*n); 
+  for(double *yo = target+n; (yo--)!=target; *yo=1.0) { }
+  for(double *yo = b+n; (yo--)!=b; *yo=0.0) { }
+  
+  int progress_steps = max(1000,n/10);
+  // Main loop
+  for(int v0 = 0; v0<n; v0++) {
+    // Verbose
+    if(v0>(progress*n) / progress_steps) {
+      progress++;
+      igraph_progressf("Computing vertex betweenness %cSP",
+		       100.0*double(progress)/double(progress_steps), 0,
+		       MODES[mode]);
+    }
+    // Breadth-first search
+    int nb_vertices = breadth_path_search(v0, buff, paths, dist);
+    // initialize target[vertices in component] to 1
+    //for(int *yo = buff+nb_vertices; (yo--)!=buff; target[*yo]=1.0);
+    // backwards-cumulative exploration
+    switch(mode) {
+      case MODE_USP:
+        explore_usp(target, nb_vertices, buff, paths, dist); break;
+      case MODE_ASP:
+        explore_asp(target, nb_vertices, buff, paths, dist); break;
+      case MODE_RSP:
+        explore_rsp(target, nb_vertices, buff, paths, dist); break;
+      default:
+        IGRAPH_WARNING("graph_molloy_opt::vertex_betweenness() "
+		       "called with Invalid Mode");
+    }
+    // add targets[vertices in component] to global betweenness and reset targets[]
+    if(nb_vertices==n) {
+      // cache optimization if all vertices are in component
+      double *bb=b;
+      double *tt_end=target+n;
+      if(trivial_paths) for(double *yo=target; yo!=tt_end; *(bb++)+=*(yo++)){}
+      else { 
+	for(double *yo=target; yo!=tt_end; *(bb++)+=(*(yo++)-1.0)) { }
+	b[*buff]-=(target[*buff]-1.0);
+      }
+      for(double *yo = target; yo!=tt_end; *(yo++)=1.0) { }
+    }
+    else {
+      if(trivial_paths) 
+        for(int *yo = buff+nb_vertices; (yo--)!=buff; b[*yo]+=target[*yo]) { }
+      else
+        for(int *yo = buff+nb_vertices; (--yo)!=buff; b[*yo]+=(target[*yo]-1.0)) { }
+      for(int *yo = buff+nb_vertices; (yo--)!=buff; target[*yo]=1.0) { }
+    }
+  }
+  // Clean all & return
+  delete[] target;
+  delete[] dist;
+  delete[] buff;
+  delete[] paths;
+  igraph_status("Done\n", 0);
+  return b;
+}
+
+double graph_molloy_opt::traceroute_sample(int mode, int nb_src, int *src, int nb_dst, int* dst, double *redudancy, double **edge_redudancy) {
+  // verify & verbose
+  assert(verify());
+  char MODES[3] = {'U','A','R'};
+  igraph_statusf("traceroute %cSP on G(N=%d,M=%d) with %d src and %d dst...",
+		 0, MODES[mode], nbvertices_real(), nbarcs(), nb_src,nb_dst);
+
+  // create dst[] buffer if necessary
+  bool newdist = dst==NULL;
+  if(newdist) dst = new int[n];
+  // breadth-first search vertex fifo
+  int *buff = new int[n];
+  // breadth-first search path count
+  double *paths = new double[n];
+  // breadth-first search distance vector
+  unsigned char *dist = new unsigned char[n];
+  // newdeg[] allows to tag discovered edges
+  int *newdeg = new int[n];
+  // target[v] is > 0 if v is a destination
+  double *target = new double[n];
+
+  // init all
+  int i;
+  memset(dist,0,sizeof(unsigned char)*n); 
+  memset(newdeg,0,sizeof(int)*n); 
+  for(double *yo = target+n; (yo--)!=target; *yo=0.0) { }
+  if(redudancy!=NULL)
+    for(double *yo = redudancy+n; (yo--)!=redudancy; *yo=0.0) { } 
+
+  // src_0 counts the number of sources having degree 0
+  int src_0 = 0;
+  // nopath counts the number of pairs (src,dst) having no possible path
+  int nopath = 0;
+  // nb_paths & total_dist are for the average distance estimator
+  int nb_paths = 0;
+  double total_dist = 0;
+  // s will be the current source
+  int s;
+
+  while(nb_src--) if(deg[s = *(src++)]==0) src_0++; else {
+    // breadth-first search
+    int nb_vertices = breadth_path_search(s,buff,paths,dist);
+    // do we have to pick new destinations ?
+    if(newdist) pick_random_dst(double(nb_dst),NULL,dst);
+    // mark reachable destinations as "targets"
+    for(i=0; i<nb_dst; i++) {
+      if(dist[dst[i]]!=0) target[dst[i]]=1.0;
+      else nopath++;
+    }
+    // compute avg_dist estimator
+    int current_dist = 0;
+    unsigned char curr_dist = 1;
+    for(int p=1; p<nb_vertices; p++) {
+      int v = buff[p];
+      if(dist[v]!=curr_dist) {
+        curr_dist = dist[v];
+        current_dist++;
+      }
+      if(target[v]>0.0) {
+        total_dist += double(current_dist);
+        nb_paths++;
+      }
+    }
+    // substract target[] to redudancy if needed
+    if(redudancy!=NULL) for(i=1; i<nb_vertices; i++) redudancy[buff[i]]-=(target[buff[i]]);
+    // traceroute exploration
+    switch(mode) {
+      case MODE_USP:
+        explore_usp(target, nb_vertices, buff, paths, dist, newdeg, edge_redudancy); break;
+      case MODE_ASP:
+        explore_asp(target, nb_vertices, buff, paths, dist, newdeg, edge_redudancy); break;
+      case MODE_RSP:
+        explore_rsp(target, nb_vertices, buff, paths, dist, newdeg, edge_redudancy); break;
+      default:
+        IGRAPH_WARNING("graph_molloy_opt::traceroute_sample() called "
+		       "with Invalid Mode");
+    }
+    // add target[] to redudancy[] if needed
+    if(redudancy!=NULL) for(i=1; i<nb_vertices; i++) redudancy[buff[i]]+=(target[buff[i]]);
+    // clear target[]
+    for(int *yo = buff+nb_vertices; yo-- != buff; target[*yo]=0.0) { }
+  }
+  // update degrees
+  for(i=0; i<n; i++) deg[i]=newdeg[i];
+  refresh_nbarcs();
+  // clean all
+  delete[] buff;
+  delete[] paths;
+  delete[] dist;
+  delete[] newdeg;
+  delete[] target;
+  if(newdist) delete[] dst;
+  {
+    igraph_statusf("discovered %d vertices and %d edges\n", 0, 
+		   nbvertices_real(), nbarcs());
+    if(src_0)  igraph_warningf("%d sources had degree 0\n", __FILE__, 
+			       __LINE__, -1, src_0);
+    if(nopath) igraph_warningf("%d (src,dst) pairs had no possible path\n",
+			       __FILE__, __LINE__, -1, nopath);
+  }
+  return total_dist/double(nb_paths);
+}  
+
+int graph_molloy_opt::disconnecting_edges() {
+  int removed=0;
+  while(is_connected()) {
+    // replace random edge by loops
+    int i;
+    do i=pick_random_vertex(); while(i<0 || deg[i]<1);
+    int *p=neigh[i]+(my_random()%deg[i]);
+    int j=*p; *p=i;
+    fast_rpl(neigh[j],i,j);
+    removed++;
+  }
+  return removed;
+}   
+
+void graph_molloy_opt::vertex_covering() {
+  vertex_cover(n, links, deg, neigh);
+}
+
+
+// optimisations a faire :
+// 1/ arreter le breadth-first search qd on a vu toutes les dst
+// 2/ faire une seule redescente pour toutes les dst.
+
+double graph_molloy_opt::path_sampling(int *nb_dst, int *dst, double* redudancies, double **edge_redudancies) {
+  assert(verify());
+  // do we have to store the destinations (for one src) in a temp buffer?
+  bool NOMEM = (dst==NULL);
+  if(NOMEM) dst = new int[n];
+  int i;
+  int next_step = n+1;
+  {
+    igraph_status("Sampling paths", 0);
+    next_step = 0;
+  }
+  // breadth-first search buffers buff[] and dist[]
+  int *buff = new int[n];
+  unsigned char *dist = new unsigned char[n];
+  for(i=0; i<n; i++) dist[i]=0;
+  // nb_pos[] counts the number of possible paths to get to a vertex
+  int *nb_pos = new int[n];
+  for(i=0; i<n; i++) nb_pos[i]=0;
+  // newdeg[i] is the number of edges of vertex i "seen" by traceroute
+  int *newdeg = new int[n];
+  for(i=0; i<n; i++) newdeg[i]=0;
+
+  // src_0 counts the number of sources having degree 0
+  int src_0 = 0;
+  // nopath counts the number of pairs (src,dst) having no possible path
+  int nopath = 0;
+  // nb_paths & total_dist are for the average distance estimator
+  int nb_paths = 0;
+  unsigned int total_dist = 0;
+  unsigned int total_dist64 = 0;
+  
+  // s is the source of the breadth-first search
+  for(int s=0; s<n; s++) if(nb_dst[s]>0) {
+    if(deg[s]==0) src_0++; else {
+      if(s>next_step) {
+        next_step = s+(n/1000)+1;
+        igraph_progress("Sampling paths", double(s)/double(n), 0);
+      }
+      int v;
+      // breadth-first search
+      int *to_visit=buff;
+      int *visited=buff;
+      *(to_visit++)=s;
+      dist[s]=1;
+      nb_pos[s]=1;
+      while(visited!=to_visit) {
+        v=*(visited++);
+        unsigned char n_dist = next_dist(dist[v]);
+        int *w0 = neigh[v];
+        for(int *w = w0+deg[v]; w--!=w0; ) {
+          unsigned char d2 = dist[*w];
+          if(d2==0) {
+            dist[*w]=d2=n_dist;
+            *(to_visit++) = *w;
+          }
+          if(d2==n_dist) nb_pos[*w] += nb_pos[v];
+        }
+      }
+      
+      // for every target, pick a random path.
+      int t_index = nb_dst[s];
+      // create dst[] if necessary
+      if(NOMEM) pick_random_src(double(t_index),NULL,dst);
+      while(t_index--) if(dist[v = *(dst++)]==0) nopath++; else {
+#ifdef _DEBUG
+	  igraph_statusf("Sampling path %d -> %d\n", 0, s, v);
+#endif //_DEBUG
+        nb_paths++;
+        // while we haven't reached the source..
+        while(v!=s) {
+          // pick a random father
+          int index = my_random()%nb_pos[v];
+          unsigned char p_dist = prev_dist(dist[v]);
+          int *w = neigh[v];
+          int k=0;
+          int new_father;
+          while(dist[new_father=w[k]]!=p_dist || (index-=nb_pos[new_father])>=0) k++;
+          // add edge
+          add_traceroute_edge(v,k,newdeg,edge_redudancies,1.0);
+	  if(redudancies!=NULL && new_father!=s) redudancies[new_father]+=1.0;
+          // step down to father
+          v = new_father;
+          // increase total distance
+          total_dist++;
+	  if(total_dist==0) total_dist64++;
+        }
+      }
+      // reset (int *)dst if necessary
+      if(NOMEM) dst -= nb_dst[s];
+
+      // clear breadth-first search buffers
+      while(visited!=buff) {
+        v=*(--visited);
+        dist[v]=0;
+        nb_pos[v]=0;
+      }
+    }
+  }
+  // update degrees
+  for(i=0; i<n; i++) deg[i]=newdeg[i];
+  refresh_nbarcs();
+  // clean
+  delete[] newdeg;
+  delete[] buff;
+  delete[] dist;
+  delete[] nb_pos;
+  if(NOMEM) delete[] dst;
+  if(VERBOSE()) {
+    igraph_status("Sampling paths :  Done   \n", 0);
+    if(src_0)  igraph_warningf("%d sources had degree 0", __FILE__, 
+			       __LINE__, -1, src_0);
+    if(nopath) igraph_warningf("%d (src,dst) pairs had no possible path",
+			       __FILE__, __LINE__, -1, nopath);
+  }
+  double tdist = double(total_dist64);
+  if(total_dist64>0) tdist *= 4294967296.0;
+  tdist += double(total_dist);
+  return tdist / double(nb_paths);
+}
+
+int *graph_molloy_opt::vertices_real(int &nb_v) {
+  int *yo;
+  if(nb_v<0) {
+    nb_v=0;
+    for(yo=deg; yo!=deg+n; ) if(*(yo++)>0) nb_v++;
+  }
+  if(nb_v==0) {
+    IGRAPH_WARNING("graph is empty");
+    return NULL;
+  }
+  int *buff=new int[nb_v];
+  yo=buff;
+  for(int i=0; i<n; i++) if(deg[i]>0) *(yo++)=i;
+  if(yo!=buff+nb_v){
+    igraph_warningf("wrong #vertices in graph_molloy_opt::vertices_real(%d)",
+		    __FILE__, __LINE__, -1, nb_v);
+    delete[] buff;
+    return NULL;
+  }
+  else return buff;
+}
+
+int *graph_molloy_opt::pick_random_vertices(int &k, int *output, int nb_v, int *among) {
+  int i;
+  bool CREATED_AMONG = false;
+  if(among==NULL && k>0) {
+    among=vertices_real(nb_v);
+    CREATED_AMONG=true;
+  }
+  if(k>nb_v) {
+    igraph_warningf("Warning : tried to pick %d among %d vertices. "
+		    "Picked only %d", __FILE__, __LINE__, -1, k, nb_v, nb_v);
+    k = nb_v;
+  }
+  if(k>0) {
+    if(output==NULL) output=new int[k];
+    for(i=0; i<k; i++) {
+      int tmp = i+my_random()%(nb_v-i);
+      output[i] = among[tmp];
+      among[tmp] = among[i];
+      among[i] = output[i];
+    }
+  }
+  if(CREATED_AMONG) delete[] among;
+  return output;
+}
+
+int *graph_molloy_opt::pick_random_src(double k, int *nb, int* buff, int nb_v, int* among) {
+  bool AMONG_CREATED=false;
+  if(among==NULL || nb_v<0) {
+    AMONG_CREATED=true;
+    among=vertices_real(nb_v);
+  }
+  int kk = int(floor(0.5 + (k>=1.0 ? k : k*double(nb_v))));
+  if(kk==0) kk=1;
+  int *yo=pick_random_vertices(kk,buff,nb_v,among);
+  if(nb!=NULL) *nb=kk;
+  if(AMONG_CREATED) delete[] among;
+  return yo;
+}
+
+int *graph_molloy_opt::pick_random_dst(double k, int *nb, int* buff, int nb_v, int* among) {
+  bool AMONG_CREATED=false;
+  if(among==NULL || nb_v<0) {
+    AMONG_CREATED=true;
+    among=vertices_real(nb_v);
+  }
+  int kk = int(floor(0.5 + (k>1.0 ? k : k*double(nb_v))));
+  if(kk==0) kk=1;
+  int *yo=pick_random_vertices(kk,buff,nb_v,among);
+  if(nb!=NULL) *nb=kk;
+  if(AMONG_CREATED) delete[] among;
+  return yo;
+}
+
+int graph_molloy_opt::core() {
+  box_list b(n,deg);
+  int v;
+  int removed = 0;
+  while((v=b.get_one())>=0) {
+    b.pop_vertex(v,neigh);
+    deg[v]=0;
+    removed++;
+  }
+  refresh_nbarcs();
+  return removed;
+}
+
+int graph_molloy_opt::try_disconnect(int K, int max_tries) {
+  bool *visited = new bool[n];
+  for(bool *p = visited+n; p!=visited; *(--p)=false) { }
+  int *Kbuff = new int[K];
+  int tries = 0;
+  int next_step = -1;
+  if(VERBOSE()) next_step = 0;
+  bool yo = true;
+  while(yo && tries<max_tries) {
+    if(tries==next_step) {
+      igraph_statusf("Trying to disconnect the graph... "
+		       "%d edges swaps done so far", 0, tries);
+      next_step += 100;
+    }
+    int v1 = pick_random_vertex();
+    int v2 = pick_random_vertex();
+    int w1 = *(random_neighbour(v1));
+    int w2 = *(random_neighbour(v2));
+    if(swap_edges_simple(v1,w1,v2,w2)) {
+      tries++;
+      yo = (!isolated(v1,K,Kbuff,visited) && !isolated(v2,K,Kbuff,visited) && !is_connected());
+      swap_edges(v1,w2,v2,w1);
+    }
+  }
+  delete[] visited;
+  delete[] Kbuff;
+  return tries;
+}
+
+bool graph_molloy_opt::isolated(int v, int K, int *Kbuff, bool *visited) {
+  if(K<2) return false;
+#ifdef OPT_ISOLATED
+  if(K<=deg[v]+1) return false;
+#endif //OPT_ISOLATED
+  int *seen  = Kbuff;
+  int *known = Kbuff;
+  int *max   = Kbuff + (K-1);
+  *(known++) = v;
+  visited[v] = true;
+  bool is_isolated = true;
+  
+  while(known != seen) {
+    v = *(seen++);
+    int *w = neigh[v];
+    for(int d=deg[v]; d--; w++) if(!visited[*w]) {
+#ifdef OPT_ISOLATED
+      if(K<=deg[*w]+1 || known == max) {
+#else //OPT_ISOLATED
+      if(known == max) {
+#endif //OPT_ISOLATED
+        is_isolated = false;
+        goto end_isolated;
+      }
+      visited[*w] = true;
+      *(known++) = *w;
+    }
+  }
+end_isolated:
+  // Undo the changes to visited[]...
+  while(known != Kbuff) visited[*(--known)] = false;
+  return is_isolated;
+}
+
+double graph_molloy_opt::rho(int mode, int nb_src, int *src, int nb_dst, int *dst) {
+  assert(verify());
+
+  // create dst[] buffer if necessary
+  bool newdist = dst==NULL;
+  if(newdist) dst = new int[n];
+  // breadth-first search vertex fifo
+  int *buff = new int[n];
+  // breadth-first search path count
+  double *paths = new double[n];
+  // breadth-first search distance vector
+  unsigned char *dist = new unsigned char[n];
+  // target[v] is > 0 if v is a destination
+  double *target = new double[n];
+  // times_seen count the times we saw each vertex
+  int *times_seen = new int[n];
+
+  // init all
+  int i;
+  memset(dist,0,sizeof(unsigned char)*n); 
+  memset(times_seen,0,sizeof(int)*n); 
+  for(double *yo = target+n; (yo--)!=target; *yo=0.0) { }
+
+  // src_0 counts the number of sources having degree 0
+  int src_0 = 0;
+  // nopath counts the number of pairs (src,dst) having no possible path
+  int nopath = 0;
+  // s will be the current source
+  int s;
+
+  for(int nsrc=0; nsrc<nb_src; nsrc++) if(deg[s = *(src++)]==0) src_0++; else {
+    // breadth-first search
+    int nb_vertices = breadth_path_search(s,buff,paths,dist);
+    // do we have to pick new destinations ?
+    if(newdist) pick_random_dst(double(nb_dst),NULL,dst);
+    // mark reachable destinations as "targets" and substract one time_seen
+    for(i=0; i<nb_dst; i++) {
+      if(dist[dst[i]]!=0) target[dst[i]]=1.0;
+      else nopath++;
+    }
+    // traceroute exploration
+    switch(mode) {
+      case MODE_USP:
+        explore_usp(target, nb_vertices, buff, paths, dist); break;
+      case MODE_ASP:
+        explore_asp(target, nb_vertices, buff, paths, dist); break;
+      case MODE_RSP:
+        explore_rsp(target, nb_vertices, buff, paths, dist); break;
+      default:
+        IGRAPH_WARNING("graph_molloy_opt::rho() called with Invalid Mode");
+    }
+    // remove destinations that weren't discovered by a path coming through
+    for(i=0; i<nb_dst; i++) {
+      int yo=dst[i];
+      if(target[yo]==1.0) target[yo]=0.0;
+    }
+    // add target[] to times_seen[]
+    for(i=1; i<nb_vertices; i++) {
+      int yo = buff[i];
+      if(target[yo]!=0.0) { target[yo]=0.0; times_seen[yo]++; }
+    }
+    // also clear  the source
+    target[buff[0]]=0.0;
+  }
+  // clean all
+  delete[] buff;
+  delete[] paths;
+  delete[] dist;
+  delete[] target;
+  if(newdist) delete[] dst;
+  // compute rho
+  double sum_nij = 0.0;
+  double sum_ni = 0.0;
+  for(i=0; i<n; i++) {
+    double d = double(times_seen[i]);
+    sum_ni += d;
+    sum_nij += d*d;
+  }
+  delete[] times_seen;
+  {
+    igraph_status("done\n", 0);
+    if(src_0)  igraph_warningf("%d sources had degree 0", __FILE__, __LINE__,
+			       -1, src_0);
+    if(nopath) igraph_warningf("%d (src,dst) pairs had no possible path",
+			       __FILE__, __LINE__, -1, nopath);
+  }
+  return (sum_nij-sum_ni)*double(n)*double(nb_src)/(sum_ni*sum_ni*double(nb_src-1));
+}
+
+void graph_molloy_opt::sort() {
+  for(int v=0; v<n; v++) qsort(neigh[v],deg[v]);
+}
+
+int* graph_molloy_opt::sort_vertices(int *buff) {
+  // pre-sort vertices by degrees
+  buff = boxsort(deg,n,buff);
+  // sort vertices having the same degrees
+  int i=0;
+  while(i<n) {
+    int d = deg[buff[i]];
+    int j = i+1;
+    while(j<n && deg[buff[j]]==d) j++;
+    lex_qsort(neigh,buff+i,j-i,d);
+    i=j;
+  }
+  return buff;
+}
+
+int graph_molloy_opt::cycles(int v) {
+return v;
+}
+
+// void graph_molloy_opt::remove_vertex(int v) {
+//   fprintf(stderr,"Warning : graph_molloy_opt::remove_vertex(%d) called",v);
+// }
+
+bool graph_molloy_opt::verify(int mode) {
+  int i,j,k;
+  assert(neigh[0]==links);
+  // verify edges count
+  if((mode & VERIFY_NOARCS) == 0) {
+    int sum = 0;
+    for(i=0; i<n; i++) sum+=deg[i];
+    assert(sum==a);
+  }
+  // verify neigh[] and deg[] compatibility
+  if((mode & VERIFY_NONEIGH) == 0)
+    for(i=0; i<n-1; i++) assert(neigh[i]+deg[i]==neigh[i+1]);
+  // verify vertex range
+  for(i=0; i<a; i++) assert(links[i]>=0 && links[i]<n);
+  // verify simplicity
+//  for(i=0; i<n; i++) for(j=0; j<deg[i]; j++) for(k=j+1; k<deg[i]; k++)
+//    assert(neigh[i][j]!=neigh[i][k]);
+  // verify symmetry
+  for(i=0; i<n; i++) for(j=0; j<deg[i]; j++) {
+    int v = neigh[i][j];
+    int nb = 0;
+    for(k=0; k<deg[v]; k++) if(neigh[v][k]==i) nb++;
+    assert(nb>0);
+  }
+  return true;
+}
+
+/*___________________________________________________________________________________
+  Not to use anymore : use graph_molloy_hash class instead
+
+void graph_molloy_opt::shuffle(long times) {
+  while(times) {
+    int f1 = links[my_random()%a];
+    int f2 = links[my_random()%a];
+    int t1 = neigh[f1][my_random()%deg[f1]];
+    int t2 = neigh[f2][my_random()%deg[f2]];
+    if(swap_edges_simple(f1,t1,f2,t2)) times--;
+  }
+}
+
+
+long graph_molloy_opt::connected_shuffle(long times) {
+  //assert(verify());
+#ifdef PERFORMANCE_MONITOR
+  long failures = 0;
+  long successes = 0;
+  double avg_K = 0.0;
+  long avg_T = 0;
+#endif //PERFORMANCE_MONITOR
+
+  long nb_swaps = 0;
+  long T = min(a,times)/10;
+  double double_K = 1.0;
+  int K = int(double_K);
+  double Q1 = 1.35;
+  double Q2 = 1.01;
+  int *Kbuff = new int[K];
+  bool *visited = new bool[n];
+  for(int i=0; i<n; i++) visited[i] = false;
+
+  while(times>nb_swaps) {
+    // Backup graph
+#ifdef PERFORMANCE_MONITOR
+    avg_K+=double_K;
+    avg_T+=T;
+#endif //PERFORMANCE_MONITOR
+    int *save = backup();
+    //assert(verify());
+    // Swaps
+    long swaps = 0;
+    for(int i=T; i>0; i--) {
+      // Pick two random vertices
+      int f1 = pick_random_vertex();
+      int f2 = pick_random_vertex();
+      if(f1==f2) continue;
+      // Pick two random neighbours
+      int *f1t1 = random_neighbour(f1);
+      int t1 = *f1t1;
+      int *f2t2 = random_neighbour(f2);
+      int t2 = *f2t2;
+      // test simplicity
+      if(t1!=t2 && f1!=t2 && f2!=t1 && !is_edge(f1,t2) && !is_edge(f2,t1)) {
+        // swap
+        *f1t1 = t2;
+        *f2t2 = t1;
+        int *t1f1 = fast_rpl(neigh[t1],f1,f2);
+        int *t2f2 = fast_rpl(neigh[t2],f2,f1);
+        // isolation test
+        if(isolated(f1, K, Kbuff, visited) || isolated(f2, K, Kbuff, visited)) {
+          // undo swap
+          *t1f1 = f1; *t2f2 = f2; *f1t1 = t1; *f2t2 = t2;
+        }
+        else swaps++;
+      }
+    }
+    //assert(verify());
+    // test connectivity
+    bool ok = is_connected();
+#ifdef PERFORMANCE_MONITOR
+    if(ok) successes++; else failures++;
+#endif //PERFORMANCE_MONITOR
+    if(ok) {
+      nb_swaps += swaps;
+      // adjust K and T
+      if((K+10)*T>5*a) {
+        double_K/=Q2;
+        K = int(double_K);
+      }
+      else T*=2;
+    }
+    else {
+      restore(save);
+      //assert(verify());
+      double_K*=Q1;
+      K = int(double_K);
+      delete[] Kbuff;
+      Kbuff = new int[K];
+    }
+    delete[] save;
+  }
+#ifdef PERFORMANCE_MONITOR
+    fprintf(stderr,"\n*** Performance Monitor ***\n");
+    fprintf(stderr," - Connectivity test successes : %ld\n",successes);
+    fprintf(stderr," - Connectivity test failures  : %ld\n",failures);
+    fprintf(stderr," - Average window : %ld\n",avg_T/long(successes+failures));
+    fprintf(stderr," - Average isolation test width : %f\n",avg_K/double(successes+failures));
+#endif //PERFORMANCE_MONITOR
+  return nb_swaps;
+}
+
+bool graph_molloy_opt::try_shuffle(int T, int K) {
+    int i;
+    int *Kbuff = NULL;
+    if(K>0) Kbuff = new int[K];
+    bool *visited = new bool[n];
+    for(i=0; i<n; i++) visited[i]=false;
+    int *back=backup();
+    for(i=T; i>0; i--) {
+      // Pick two random vertices
+      int f1 = pick_random_vertex();
+      int f2 = pick_random_vertex();
+      if(f1==f2) continue;
+      // Pick two random neighbours
+      int *f1t1 = random_neighbour(f1);
+      int t1 = *f1t1;
+      int *f2t2 = random_neighbour(f2);
+      int t2 = *f2t2;
+      // test simplicity
+      if(t1!=t2 && f1!=t2 && f2!=t1 && is_edge(f1,t2) && !is_edge(f2,t1)) {
+        // swap
+        *f1t1 = t2;
+        *f2t2 = t1;
+        int *t1f1 = fast_rpl(neigh[t1],f1,f2);
+        int *t2f2 = fast_rpl(neigh[t2],f2,f1);
+        // isolation test
+        if(isolated(f1, K, Kbuff, visited) || isolated(f2, K, Kbuff, visited)) {
+          // undo swap
+          *t1f1 = f1; *t2f2 = f2; *f1t1 = t1; *f2t2 = t2;
+        }
+      }
+    }
+    delete[] visited;
+    if(Kbuff != NULL) delete[] Kbuff;
+    bool yo = is_connected();
+    restore(back);
+    delete[] back;
+    return yo;
+}
+
+double graph_molloy_opt::window(int K, double ratio) {
+  int steps = 100;
+  double T = double(a*10);
+  double q2 = 0.1;
+  double q1 = pow(q2,(ratio-1.0)/ratio);
+  
+  int failures = 0;
+  int successes = 0;
+  int *Kbuff = new int[K];
+  bool *visited = new bool[n];
+
+  while(successes<10*steps) {
+    int *back=backup();
+    for(int i=int(T); i>0; i--) {
+      // Pick two random vertices
+      int f1 = links[my_random()%a];
+      int f2 = links[my_random()%a];
+      if(f1==f2) continue;
+      // Pick two random neighbours
+      int *f1t1 = neigh[f1]+my_random()%deg[f1];
+      int *f2t2 = neigh[f2]+my_random()%deg[f2];
+      int t1 = *f1t1;
+      int t2 = *f2t2;
+      // test simplicity
+      if(t1!=t2 && f1!=t2 && f2!=t1 && is_edge(f1,t2) && !is_edge(f2,t1)) {
+        // swap
+        *f1t1 = t2;
+        *f2t2 = t1;
+        int *t1f1 = fast_rpl(neigh[t1],f1,f2);
+        int *t2f2 = fast_rpl(neigh[t2],f2,f1);
+        // isolation test
+        if(isolated(f1, K, Kbuff, visited) || isolated(f2, K, Kbuff, visited)) {
+          // undo swap
+          *t1f1 = f1; *t2f2 = f2; *f1t1 = t1; *f2t2 = t2;
+        }
+      }
+    }
+    if(is_connected()) {
+      T *= q1;
+      if(T>double(5*a)) T=double(5*a);
+      successes++;
+      if((successes%steps)==0) {
+        q2 = sqrt(q2);
+        q1 = sqrt(q1);
+      }
+    }
+    else {
+      T*=q2;
+      failures++;
+    }
+    if(VERBOSE()) fprintf(stderr,".");
+    restore(back);
+    delete[] back;
+  }
+  delete[] Kbuff;
+  delete[] visited;
+  if(VERBOSE()) fprintf(stderr,"Failures:%d   Successes:%d\n",failures, successes);
+  return T;
+}
+
+
+double graph_molloy_opt::eval_K(int quality) {
+  double K = 5.0;
+  double avg_K = 1.0;
+  for(int i=quality; i--; ) {
+    int int_K = int(floor(K+0.5));
+    if(try_shuffle(a/(int_K+1),int_K)) {
+      K*=0.8; fprintf(stderr,"+"); }
+    else {
+      K*=1.25; fprintf(stderr,"-"); }
+    if(i<quality/2) avg_K *= K;
+  }
+  return pow(avg_K,1.0/double(quality/2));
+}
+
+
+double graph_molloy_opt::effective_K(int K, int quality) {
+  if(K<3) return 0.0;
+  long sum_K = 0;
+  int *Kbuff = new int[K];
+  bool *visited = new bool[n];
+  int i;
+  for(i=0; i<n; i++) visited[i] = false;
+  for(int i=0; i<quality; i++) {
+//    assert(verify());
+    int f1,f2,t1,t2;
+    int *f1t1, *f2t2;
+    do {
+      // Pick two random vertices
+      do {
+        f1 = pick_random_vertex();
+        f2 = pick_random_vertex();
+      } while(f1==f2);
+      // Pick two random neighbours
+      f1t1 = random_neighbour(f1);
+      t1 = *f1t1;
+      f2t2 = random_neighbour(f2);
+      t2 = *f2t2;
+      // test simplicity
+    }
+    while (t1==t2 || f1==t2 || f2==t1 || is_edge(f1,t2) || is_edge(f2,t1));
+    // swap
+    *f1t1 = t2;
+    *f2t2 = t1;
+    fast_rpl(neigh[t1],f1,f2);
+    fast_rpl(neigh[t2],f2,f1);
+    sum_K += effective_isolated(deg[f1]>deg[t2] ? f1 : t2, K, Kbuff, visited);
+    sum_K += effective_isolated(deg[f2]>deg[t1] ? f2 : t1, K, Kbuff, visited);
+    // undo swap
+    swap_edges(f1,t2,f2,t1);
+//    assert(verify());
+  }
+  delete[] Kbuff;
+  delete[] visited;
+  return double(sum_K)/double(2*quality);
+}
+
+
+//___________________________________________________________________________________
+//*/
+
+
+
+/***** NOT USED ANYMORE (Modif 22/04/2005) ******
+
+long long *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];
+  int *bb = new int[n];
+  int *dd = new int[max_degree()];
+  for(i=0; i<n; i++) b[i]=0;
+  int progress = 0;
+  for(int v0 = 0; v0<n; v0++) {
+    if(VERBOSE()==VERBOSE_LOTS && v0>(progress*n)/1000) {
+      progress++;
+      fprintf(stderr,"\rComputing vertex betweenness USP : %d.%d%% ",progress/10,progress%10);
+    }
+    int nb_vertices = width_search(dist, buff, v0);
+    int nv = nb_vertices;
+    for(i=0; i<nv; i++) bb[buff[i]]=0;
+    while(--nv) {
+      int v = buff[nv];
+      unsigned char d = prev_dist(dist[v]);
+      int n_father = 0;
+      int *ww = neigh[v];
+      for(int k=deg[v]; k--; ww++) if(dist[*ww]==d) dd[n_father++]=*ww;
+      int w = dd[my_random()%n_father];
+      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]]);
+  }
+  delete[] dist;
+  delete[] buff;
+  delete[] bb;
+  delete[] dd;
+  return b;
+}
+
+long long *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];
+  int *bb = new int[n];
+  int *dd = new int[max_degree()];
+  for(i=0; i<n; i++) b[i]=0;
+  int progress = 0;
+  for(int v0 = 0; v0<n; v0++) {
+    if(VERBOSE()==VERBOSE_LOTS && v0>(progress*n)/1000) {
+      progress++;
+      fprintf(stderr,"\rComputing vertex betweenness RSP : %d.%d%% ",progress/10,progress%10);
+    }
+    int nb_vertices = width_search(dist, buff, v0);
+    int nv = nb_vertices;
+    for(i=0; i<nv; i++) bb[buff[i]]=0;
+    while(--nv) {
+      int v = buff[nv];
+      unsigned char d = prev_dist(dist[v]);
+      int n_father = 0;
+      int *ww = neigh[v];
+      for(int k=deg[v]; k--; ww++) if(dist[*ww]==d) dd[n_father++]=*ww;
+      int to_give = bb[v]+1;
+      if(dd[0]==v0) {
+        if(trivial_paths) bb[v0]+= to_give;
+      }
+      else  {
+        while(n_father>1 && to_give>2*n_father) {
+          int o = rng.binomial(1.0/n_father,to_give);
+          to_give -= o;
+          bb[dd[--n_father]]+=o;
+        }
+        if(n_father==1) bb[dd[0]]+=to_give;
+        else {
+          while(to_give--) bb[dd[my_random()%n_father]]++;
+        }
+      }
+      if(trivial_paths) bb[v]++;
+    }
+    for(i=0; i<nb_vertices; i++) b[buff[i]]+=(long long)(bb[buff[i]]);
+  }
+  delete[] dist;
+  delete[] buff;
+  delete[] bb;
+  delete[] dd;
+  return b;
+}
+
+double *graph_molloy_opt::vertex_betweenness_asp(bool trivial_paths) {
+  if(VERBOSE()) fprintf(stderr,"Computing vertex betweenness ASP...");
+  int i;
+  unsigned char *dist = new unsigned char[n];
+  int *buff = new int[n];
+  double *b = new double[n];
+  double *bb = new double[n];
+  int *dd = new int[max_degree()];
+  for(i=0; i<n; i++) b[i]=0.0;
+  int progress = 0;
+  for(int v0 = 0; v0<n; v0++) if(deg[v0]>0) {
+    if(VERBOSE()==VERBOSE_LOTS && v0>(progress*n)/1000) {
+      progress++;
+      fprintf(stderr,"\rComputing vertex betweenness ASP : %d.%d%% ",progress/10,progress%10);
+    }
+    int nb_vertices = width_search(dist, buff, v0);
+    if(!trivial_paths) dist[v0]=2;
+    int nv = nb_vertices;
+    for(i=0; i<nv; i++) bb[buff[i]]=0.0;
+    while(--nv) {
+      int v = buff[nv];
+      unsigned char d = prev_dist(dist[v]);
+      int n_father = 0;
+      int *ww = neigh[v];
+      for(int k=deg[v]; k--; ww++) if(dist[*ww]==d) dd[n_father++]=*ww;
+      if(n_father!=0) {
+        double badd = (bb[v]+1.0)/double(n_father);
+        int *d2 = dd;
+        while(n_father--) bb[*(d2++)]+=badd;
+      }
+      if(trivial_paths) bb[v]+=1.0;
+    }
+    for(i=0; i<nb_vertices; i++) b[buff[i]]+=bb[buff[i]];
+  }
+  delete[] dist;
+  delete[] buff;
+  delete[] bb;
+  delete[] dd;
+  if(VERBOSE()) fprintf(stderr,"done\n");
+  return b;
+}
+
+//*/
+
+} // namespace gengraph
diff --git a/src/gengraph_graph_molloy_optimized.h b/src/gengraph_graph_molloy_optimized.h
new file mode 100644
index 0000000..eb39bd8
--- /dev/null
+++ b/src/gengraph_graph_molloy_optimized.h
@@ -0,0 +1,263 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef GRAPH_MOLLOY_OPT_H
+#define GRAPH_MOLLOY_OPT_H
+
+#include "gengraph_definitions.h"
+#include "gengraph_degree_sequence.h"
+#include "gengraph_qsort.h"
+
+#include <assert.h>
+#include "gengraph_random.h"
+
+namespace gengraph {
+
+// This class handles graphs with a constant degree sequence.
+
+class graph_molloy_opt {
+
+private:
+  // Random generator
+  KW_RNG::RNG rng;
+  // Number of vertices
+  int n;
+  //Number of arcs ( = #edges * 2 )
+  int a;
+  // The degree sequence of the graph
+  int *deg;
+  // The array containing all links
+  int *links;
+  // The array containing pointers to adjacency list of every vertices
+  int **neigh;
+  // Allocate memory according to degree_sequence (for constructor use only!!)
+  void alloc(degree_sequence &);
+  // Compute #edges
+  inline void refresh_nbarcs() {
+    a=0;
+    for(int* d=deg+n; d!=deg; ) a += *(--d);
+  }
+  // Build neigh with deg and links
+  void compute_neigh();
+  // Swap edges. The swap MUST be valid !!!
+  inline void swap_edges(int from1, int to1, int from2, int to2) {
+    fast_rpl(neigh[from1],to1,to2);
+    fast_rpl(neigh[from2],to2,to1);
+    fast_rpl(neigh[to1],from1,from2);
+    fast_rpl(neigh[to2],from2,from1);
+  }
+
+  // Swap edges only if they are simple. return false if unsuccessful.
+  bool swap_edges_simple(int ,int ,int, int);
+  // Test if vertex is in an isolated component of size<K
+  bool isolated(int v, int K, int *Kbuff, bool *visited);
+  // Pick random edge, and gives a corresponding vertex
+  inline int pick_random_vertex() { return links[my_random()%a]; };
+  // Pick random neighbour
+  inline int* random_neighbour(const int v) { return neigh[v]+(my_random()%deg[v]); };
+  // Returns complexity of isolation test
+  long effective_isolated(int v, int K, int *Kbuff, bool *visited);
+  // Depth-Exploration. Returns number of steps done. Stops when encounter vertex of degree > dmax.
+  void depth_isolated(int v, long &calls, int &left_to_explore, int dmax, int * &Kbuff, bool *visited);
+  // breadth-first search. Store the distance (modulo 3)  in dist[]. Returns eplorated component size.
+  int width_search(unsigned char *dist, int *buff, int v0=0, int toclear=-1);
+  // depth-first search.
+  int depth_search(bool *visited, int *buff, int v0=0);
+  // breadth-first search that count the number of shortest paths going from src to each vertex
+  int breadth_path_search(int src, int *buff, double *paths, unsigned char *dist);
+  // Used by traceroute_sample() ONLY
+  void add_traceroute_edge(int, int, int*, double** red=NULL, double t=1.0);
+  // Used by traceroute() and betweenness(). if newdeg[]=NULL, do not discover edges.
+  // breadth_path_search() must have been called to give the corresponding buff[],dist[],paths[] and nb_vertices
+  void explore_usp(double *target, int nb_vertices, int *buff, double *paths, unsigned char *dist, int *newdeg=NULL, double **edge_redudancy=NULL);
+  void explore_asp(double *target, int nb_vertices, int *buff, double *paths, unsigned char *dist, int *newdeg=NULL, double **edge_redudancy=NULL);
+  void explore_rsp(double *target, int nb_vertices, int *buff, double *paths, unsigned char *dist, int *newdeg=NULL, double **edge_redudancy=NULL);
+  // Return component indexes where vertices belong to, starting from 0,
+  // sorted by size (biggest component has index 0)
+  int *components(int *comp=NULL);
+  // pick k random vertices of degree > 0.
+  int *pick_random_vertices(int &k, int *output=NULL, int nb_v=-1, int *among=NULL);
+  
+public:
+  // neigh[]
+  inline int** neighbors() { return neigh; };
+  // deg[]
+  inline int* degrees() { return deg; };
+  //adjacency list of v
+  inline int* operator[](const int v) { return neigh[v]; };
+  //degree of v
+  inline int degree(const int v) { return deg[v]; };
+  //compare adjacency lists
+  inline int compare(const int v, const int w) {
+    return deg[v]==deg[w] ? lex_comp(neigh[v],neigh[w],deg[v]) : (deg[v]>deg[w] ? -1 : 1);
+  };
+  // Detach deg[] and neigh[]
+  void detach();
+  // Destroy deg and links
+  ~graph_molloy_opt();
+  // Create graph from file (stdin not supported unless rewind() possible)
+  graph_molloy_opt(FILE *f);
+  // Allocate memory for the graph. Create deg and links. No edge is created.
+  graph_molloy_opt(degree_sequence &);
+  // Create graph from hard copy
+  graph_molloy_opt(int *);
+  // Create hard copy of graph
+  int *hard_copy();
+  // Remove unused edges, updates neigh[], recreate links[]
+  void clean();
+  // nb arcs
+  inline int nbarcs() { return a; };
+  // last degree
+  inline int last_degree() { return deg[n-1]; };
+  // nb vertices
+  inline int nbvertices() { return n; };
+  // nb vertices having degree > 0
+  inline int nbvertices_real() { 
+    int s=0;
+    for(int *d=deg+n; d--!=deg; ) if(*d) s++;
+    return s;
+  };
+  // return list of vertices with degree > 0. Compute #vertices, if not given.
+  int *vertices_real(int &nb_v);
+  // Keep only giant component
+  void giant_comp();
+  // nb vertices in giant component
+  int nbvertices_comp();
+  // nb arcs in giant component
+  int nbarcs_comp();
+  // print graph in SUCC_LIST mode, in stdout
+  void print(FILE *f=stdout, bool NOZERO=true);
+  // Bind the graph avoiding multiple edges or self-edges (return false if fail)
+  bool havelhakimi();
+  // Get the graph connected  (return false if fail)
+  bool make_connected();
+  // Test if graph is connected
+  bool is_connected();
+  // Maximum degree
+  int max_degree();
+  // breadth-first search. Store the distance (modulo 3)  in dist[].
+  void breadth_search(int *dist, int v0=0, int* buff=NULL);
+  // is edge ?
+  inline bool is_edge(const int a, const int b) {
+    if(deg[b]<deg[a]) return(fast_search(neigh[b],deg[b],a)!=NULL);
+    else return(fast_search(neigh[a],deg[a],b)!=NULL);
+  }
+  // Backup graph [sizeof(int) bytes per edge]
+  int* backup(int *here = NULL);
+  // Restore from backup. Assume that degrees haven't changed
+  void restore(int* back);
+  // Resplace with hard backup.
+  void replace(int* _hardbackup);
+  // Backup degs of graph
+  int* backup_degs(int *here = NULL);
+  // Restore degs from neigh[]. Need last degree, though
+  void restore_degs(int last_degree);
+  // Restore degs[] from backup. Assume that links[] has only been permuted
+  void restore_degs_only(int* backup_degs);
+  // Restore degs[] and neigh[]. Assume that links[] has only been permuted
+  void restore_degs_and_neigh(int* backup_degs);
+// WARNING : the following shuffle() algorithms are slow.
+// Use graph_molloy_hash::connected_shuffle() instead.
+  // "Fab" Shuffle (Optimized heuristic of Gkantsidis algo.)
+  long fab_connected_shuffle(long);
+  // "Optimized-Fab" Shuffle (Optimized heuristic of Gkantsidis algo, with isolated pairs)
+  long opt_fab_connected_shuffle(long);
+  // Gkantsidis Shuffle
+  long gkantsidis_connected_shuffle(long);
+  // Connected Shuffle
+  long slow_connected_shuffle(long);
+  // shortest paths where vertex is an extremity
+  double *vertex_betweenness(int mode, bool trivial_path=false);
+  // Sample the graph with traceroute-like exploration from src[] to dst[].
+  // if dst[]=NULL, pick nb_dst new random destinations for each src
+  double traceroute_sample(int mode, int nb_src, int *src, int nb_dst, int* dst, double *redudancy = NULL, double **edge_redudancy=NULL);
+  // does one breadth-first search and returns the average_distance.
+  double avg_dist(unsigned char *dist, int *buff, int v0, int &nb_vertices, int toclear=-1);
+  // Number of edges needed to disconnect graph (one random instance)
+  int disconnecting_edges();
+  // Compute vertex covering of the graph. Warning : this modifies degs[]
+  void vertex_covering();
+  // Path sampling. Input is nb_dst[] and dst[]. nb_dst[v],dst[v] describe all paths (v,x)
+  double path_sampling(int *nb_dst, int *dst=NULL, double *redudancies=NULL, double **edge_redudancy=NULL); 
+  // keep only core (tree parts are deleted). Returns number of removed vertices.
+  int core();
+  // try to disconnect the graph by swapping edges (with isolation tests)
+  int try_disconnect(int K, int max_tries=10000000);
+  // Eric & Cun-Hui estimator
+  double rho(int mode, int nb_src, int *src, int nb_dst, int *dst=NULL);
+  // sort adjacency lists
+  void sort();
+  // sort the vertices according to their degrees (highest first) and to their adjacency lists (lexicographic)
+  int* sort_vertices(int *buff = NULL);
+  // count cycles passing through vertex v
+  int cycles(int v);
+  // remove vertex (i.e. remove all edges adjacent to vertex)
+  void remove_vertex(int v);
+  // pick k random vertices of degree > 0. If k \in [0,1[, k is understood as a density.
+  int *pick_random_src(double k, int *nb=NULL, int* buff=NULL, int nb_v=-1, int* among=NULL);
+  // pick k random vertices of degree > 0. If k \in [0,1], k is understood as a density.
+  int *pick_random_dst(double k, int *nb=NULL, int* buff=NULL, int nb_v=-1, int* among=NULL);
+
+  // For debug purposes : verify validity of the graph (symetry, simplicity)
+#define VERIFY_NORMAL  0
+#define VERIFY_NONEIGH 1
+#define VERIFY_NOARCS  2
+  bool verify(int mode=VERIFY_NORMAL);
+
+/*___________________________________________________________________________________
+  Not to use anymore : use graph_molloy_hash class instead
+
+
+public:
+  // Shuffle. returns number of swaps done.
+  void shuffle(long);
+  // Connected Shuffle
+  long connected_shuffle(long);
+  // Get caracteristic K
+  double eval_K(int quality = 100);
+  // Get effective K
+  double effective_K(int K, int quality = 10000);
+  // Test window
+  double window(int K, double ratio);
+  // Try to shuffle n times. Return true if at the end, the graph was still connected.
+  bool try_shuffle(int T, int K);
+
+//___________________________________________________________________________________
+//*/
+
+/*___________________________________________________________________________________
+  Not to use anymore : replaced by vertex_betweenness()     22/04/2005
+
+  // shortest paths where vertex is an extremity
+  long long *vertex_betweenness_usp(bool trivial_path);
+  // shortest paths where vertex is an extremity
+  long long *vertex_betweenness_rsp(bool trivial_path);
+  // same, but when multiple shortest path are possible, average the weights.
+  double *vertex_betweenness_asp(bool trivial_path);
+//___________________________________________________________________________________
+//*/
+
+};
+
+} // namespace gengraph
+
+#endif //GRAPH_MOLLOY_OPT_H
+
+
diff --git a/src/gengraph_hash.h b/src/gengraph_hash.h
new file mode 100644
index 0000000..96e6529
--- /dev/null
+++ b/src/gengraph_hash.h
@@ -0,0 +1,278 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef HASH_H
+#define HASH_H
+
+#include <assert.h>
+#include "gengraph_definitions.h"
+
+//_________________________________________________________________________
+// Hash table profiling... Active only if definition below is uncommented
+//_________________________________________________________________________
+//#define _HASH_PROFILE
+
+namespace gengraph {
+
+#ifdef _HASH_PROFILE
+void _hash_add_iter();
+void _hash_add_call();
+void _hash_put_iter();
+void _hash_put_call();
+void _hash_rm_iter();
+void _hash_rm_call();
+void _hash_find_iter();
+void _hash_find_call();
+void _hash_rand_iter();
+void _hash_rand_call();
+void _hash_expand_call();
+void _hash_prof();
+#define _HASH_ADD_ITER()  _hash_add_iter()
+#define _HASH_ADD_CALL()  _hash_add_call()
+#define _HASH_PUT_ITER()  _hash_put_iter()
+#define _HASH_PUT_CALL()  _hash_put_call()
+#define _HASH_RM_ITER()   _hash_rm_iter()
+#define _HASH_RM_CALL()   _hash_rm_call()
+#define _HASH_FIND_ITER() _hash_find_iter()
+#define _HASH_FIND_CALL() _hash_find_call()
+#define _HASH_RAND_ITER() _hash_rand_iter()
+#define _HASH_RAND_CALL() _hash_rand_call()
+#define _HASH_EXP_CALL()  _hash_expand_call()
+#else
+#define _HASH_ADD_ITER()  {}
+#define _HASH_ADD_CALL()  {}
+#define _HASH_PUT_ITER()  {}
+#define _HASH_PUT_CALL()  {}
+#define _HASH_RM_ITER()   {}
+#define _HASH_RM_CALL()   {}
+#define _HASH_FIND_ITER() {}
+#define _HASH_FIND_CALL() {}
+#define _HASH_RAND_ITER() {}
+#define _HASH_RAND_CALL() {}
+#define _HASH_EXP_CALL()  {}
+#endif
+
+//_________________________________________________________________________
+// Hash Table properties. Works best when HASH_SIZE_IS_POWER2 is uncommented
+// but takes 2.25 times the needed space, in average (from 1.5 to 3)
+// If you have memory issues, Try to comment it: tables will take 1.5 times
+// the minimal space
+//_________________________________________________________________________
+
+#define HASH_SIZE_IS_POWER2
+#define MACRO_RATHER_THAN_INLINE
+
+// under HASH_MIN_SIZE, vectors are not hash table (just a simle array)
+#define HASH_MIN_SIZE 100
+#define IS_HASH(x) ((x)>HASH_MIN_SIZE)
+#define HASH_NONE (-1)
+
+#ifdef HASH_SIZE_IS_POWER2
+  inline int HASH_EXPAND(int x) {
+    _HASH_EXP_CALL();
+    x+=x;
+    x |= x>>1;  x |= x>>2;  x |= x>>4;  x |= x>>8;  x |= x>>16;
+    return x+1;
+  }
+  #define HASH_KEY(x,size) ((x*2198737)&((size)-1))
+#endif //HASH_SIZE_IS_POWER2
+
+#ifdef MACRO_RATHER_THAN_INLINE
+  #ifndef HASH_SIZE_IS_POWER2
+    #define HASH_EXPAND(x) ((x)+((x)>>1))
+    #define HASH_UNEXPAND(x) ((((x)<<1)+1)/3)
+    #define HASH_KEY(x,size) ((x)%(size))
+  #endif //HASH_SIZE_IS_POWER2
+  #define HASH_SIZE(x) (IS_HASH(x) ? HASH_EXPAND(x) : (x) )
+  #define HASH_REKEY(k,size) ((k)==0 ? (size)-1 : (k)-1)
+#else //MACRO_RATHER_THAN_INLINE
+  #ifndef HASH_SIZE_IS_POWER2
+    inline int  HASH_KEY(const int x, const int size) {
+      assert(x>=0);
+      return x%size;
+    };
+    inline int  HASH_EXPAND(const int x) {
+      _HASH_EXP_CALL();
+      return x+(x>>1);
+    };
+    inline int  HASH_UNEXPAND(const int x) {
+      return ((x<<1)+1)/3;
+    };
+  #endif //HASH_SIZE_IS_POWER2
+  inline int  HASH_REKEY(const int k, const int s) {
+    assert(k>=0);
+    if(k==0) return s-1;
+    else return k-1;
+  };
+  inline int  HASH_SIZE(const int x) {
+    if(IS_HASH(x)) return HASH_EXPAND(x);
+    else return x;
+  };
+#endif //MACRO_RATHER_THAN_INLINE
+
+inline int HASH_PAIR_KEY(const int x, const int y, const int size) {
+  return HASH_KEY(x*1434879443+y, size);
+}
+
+//_________________________________________________________________________
+// Hash-only functions : table must NOT be Raw. 
+// the argument 'size' is the total size of the hash table
+//_________________________________________________________________________
+
+// copy hash table into raw vector
+inline void H_copy(int *mem, int *h, int size) {
+  for(int i=HASH_EXPAND(size); i--; h++) if(*h != HASH_NONE) *(mem++)=*h;
+}
+
+// Look for the place to add an element. Return NULL if element is already here.
+inline int* H_add(int* h, const int size, int a) {
+  _HASH_ADD_CALL();
+  _HASH_ADD_ITER();
+  int k = HASH_KEY(a, size);
+  if(h[k]==HASH_NONE) return h+k;
+  while(h[k]!=a) {
+    _HASH_ADD_ITER();
+    k=HASH_REKEY(k,size);
+    if(h[k]==HASH_NONE) return h+k;
+  }
+  return NULL;
+}
+
+// would element be well placed in newk ?
+inline bool H_better(const int a, const int size, const int currentk, const int newk) {
+  int k = HASH_KEY(a, size);
+  if(newk<currentk) return (k<currentk && k>=newk);
+  else return (k<currentk || k>=newk);
+}
+ 
+// removes h[k]
+inline void H_rm(int* h, const int size, int k) {
+  _HASH_RM_CALL();
+  int lasthole = k;
+  do {
+    _HASH_RM_ITER();
+    k = HASH_REKEY(k,size);
+    int next = h[k];
+    if(next==HASH_NONE) break;
+    if(H_better(next,size,k,lasthole)) {
+      h[lasthole] = next;
+      lasthole = k;
+    }
+  } while(true);
+  h[lasthole] = HASH_NONE;
+}
+
+//put a
+inline int* H_put(int* h, const int size, const int a) {
+  assert(H_add(h,size,a)!=NULL);
+  _HASH_PUT_CALL();
+  _HASH_PUT_ITER();
+  int k = HASH_KEY(a, size);
+  while(h[k]!=HASH_NONE) {
+    k=HASH_REKEY(k,size);
+    _HASH_PUT_ITER();
+  }
+  h[k]=a;
+  assert(H_add(h,size,a)==NULL);
+  return h+k;
+}
+
+// find A
+inline int H_find(int *h, int size, const int a) {
+  assert(H_add(h,size,a)==NULL);
+  _HASH_FIND_CALL();
+  _HASH_FIND_ITER();
+  int k = HASH_KEY(a, size);
+  while(h[k]!=a) {
+    k=HASH_REKEY(k,size);
+    _HASH_FIND_ITER();
+  }
+  return k;
+}
+
+// Look for the place to add an element. Return NULL if element is already here.
+inline bool H_pair_insert(int* h, const int size, int a, int b) {
+  _HASH_ADD_CALL();
+  _HASH_ADD_ITER();
+  int k = HASH_PAIR_KEY(a, b, size);
+  if(h[2*k]==HASH_NONE) { h[2*k]=a; h[2*k+1]=b; return true; }
+  while(h[2*k]!=a || h[2*k+1]!=b) {
+    _HASH_ADD_ITER();
+    k=HASH_REKEY(k,size);
+    if(h[2*k]==HASH_NONE) { h[2*k]=a; h[2*k+1]=b; return true; }
+  }
+  return false;
+}
+
+
+//_________________________________________________________________________
+// Generic functions : table can be either Hash or Raw. 
+// the argument 'size' is the number of elements
+//_________________________________________________________________________
+
+// Look for an element
+inline bool H_is(int *mem, const int size, const int elem) {
+  if(IS_HASH(size)) return (H_add(mem, HASH_EXPAND(size), elem)==NULL);
+  else return fast_search(mem, size, elem)!=NULL;
+}
+
+//pick random location (containing an element)
+inline int* H_random(int* mem, int size) {
+  if(!IS_HASH(size)) return mem+(my_random()%size);
+  _HASH_RAND_CALL();
+  size = HASH_EXPAND(size);
+  int* yo;
+  do {
+    yo = mem + HASH_KEY(my_random(),size);
+    _HASH_RAND_ITER();
+  } while(*yo==HASH_NONE);
+  return yo;
+}
+
+// replace *k by b
+inline int* H_rpl(int *mem, int size, int* k, const int b) {
+  assert(!H_is(mem,size,b));
+  if(!IS_HASH(size)) {
+    *k=b;
+    return k;
+  }
+  else {
+    size = HASH_EXPAND(size);
+    assert(mem + int(k-mem) == k);
+    H_rm(mem, size, int(k-mem));
+    return H_put(mem, size, b);
+  }
+}
+
+// replace a by b
+inline int* H_rpl(int *mem, int size, const int a, const int b) {
+  assert(H_is(mem,size,a));
+  assert(!H_is(mem,size,b));
+  if(!IS_HASH(size)) return fast_rpl(mem,a,b);
+  else {
+    size = HASH_EXPAND(size);
+    H_rm(mem, size, H_find(mem, size, a));
+    return H_put(mem, size, b);
+  }
+}
+
+} // namespace gengraph
+
+#endif //HASH_H
diff --git a/src/gengraph_header.h b/src/gengraph_header.h
new file mode 100644
index 0000000..60963a3
--- /dev/null
+++ b/src/gengraph_header.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#include "gengraph_definitions.h"
+#include <cstdlib>
+#include <stdio.h>
+
+#include "gengraph_random.h"
+
+namespace gengraph {
+
+static KW_RNG::RNG _my_random;
+int my_random() { return _my_random.rand_int31(); }
+void my_srandom(int x) { _my_random.init(x,!x*13,x*x+1,(x>>16)+(x<<16)); }
+int my_binomial(double pp, int n) { return _my_random.binomial(pp,n); }
+double my_random01() { return _my_random.rand_halfopen01(); }
+
+}
+
+#ifdef _WIN32
+#include <process.h>
+#include <windows.h>
+void set_priority_low() {
+  HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,TRUE,_getpid());
+  SetPriorityClass(hProcess,IDLE_PRIORITY_CLASS);
+}
+#else
+#include <unistd.h>
+#endif
+
+namespace gengraph {
+
+static int VERB;
+int VERBOSE() { return VERB; }
+void SET_VERBOSE(int v) { VERB = v; } 
+
+//Hash profiling
+static unsigned long _hash_rm_i   = 0;
+static unsigned long _hash_rm_c   = 0;
+static unsigned long _hash_add_i  = 0;
+static unsigned long _hash_add_c  = 0;
+static unsigned long _hash_put_i  = 0;
+static unsigned long _hash_put_c  = 0;
+static unsigned long _hash_find_i = 0;
+static unsigned long _hash_find_c = 0;
+static unsigned long _hash_rand_i = 0;
+static unsigned long _hash_rand_c = 0;
+static unsigned long _hash_expand = 0;
+inline void _hash_add_iter()  { _hash_add_i++;  }
+inline void _hash_add_call()  { _hash_add_c++;  }
+inline void _hash_put_iter()  { _hash_put_i++;  }
+inline void _hash_put_call()  { _hash_put_c++;  }
+inline void _hash_rm_iter()   { _hash_rm_i++;   }
+inline void _hash_rm_call()   { _hash_rm_c++;   }
+inline void _hash_find_iter() { _hash_find_i++; }
+inline void _hash_find_call() { _hash_find_c++; }
+inline void _hash_rand_iter() { _hash_rand_i++; }
+inline void _hash_rand_call() { _hash_rand_c++; }
+inline void _hash_expand_call() { _hash_expand++; }
+// void _hash_prof() {
+//   fprintf(stderr,"HASH_ADD : %lu / %lu\n", _hash_add_c , _hash_add_i);
+//   fprintf(stderr,"HASH_PUT : %lu / %lu\n", _hash_put_c , _hash_put_i);
+//   fprintf(stderr,"HASH_FIND: %lu / %lu\n", _hash_find_c, _hash_find_i);
+//   fprintf(stderr,"HASH_RM  : %lu / %lu\n", _hash_rm_c  , _hash_rm_i);
+//   fprintf(stderr,"HASH_RAND: %lu / %lu\n", _hash_rand_c, _hash_rand_i);
+//   fprintf(stderr,"HASH_EXPAND : %lu calls\n", _hash_expand);
+// }
+
+} // namespace gengraph
diff --git a/src/gengraph_mr-connected.cpp b/src/gengraph_mr-connected.cpp
new file mode 100644
index 0000000..b0888bc
--- /dev/null
+++ b/src/gengraph_mr-connected.cpp
@@ -0,0 +1,186 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#include "gengraph_header.h"
+#include "gengraph_graph_molloy_optimized.h"
+#include "gengraph_graph_molloy_hash.h"
+#include "gengraph_degree_sequence.h"
+#include "gengraph_random.h"
+
+#include "igraph_datatype.h"
+#include "igraph_types.h"
+#include "igraph_error.h"
+
+namespace gengraph {
+
+// return negative number if program should exit
+int parse_options(int &argc, char** &argv);
+
+// options
+static const bool MONITOR_TIME = false;
+static const int  SHUFFLE_TYPE = FINAL_HEURISTICS;
+static const bool RAW_DEGREES  = false;
+static const FILE *Fdeg = stdin;
+
+//_________________________________________________________________________
+// int main(int argc, char** argv) {
+
+//   // options
+//   SET_VERBOSE(VERBOSE_NONE);
+//   if(parse_options(argc, argv) < 0) return -1;
+
+//   //Read degree distribution
+//   degree_sequence dd(Fdeg, !RAW_DEGREES);
+  
+//   //Allocate memory
+//   if(VERBOSE()) fprintf(stderr,"Allocate memory for graph...");
+//   graph_molloy_opt g(dd);
+//   dd.~degree_sequence();
+//   //Realize degree sequence
+//   if(VERBOSE()) fprintf(stderr,"done\nRealize degree sequence...");
+//   bool FAILED = !g.havelhakimi();
+//   if(VERBOSE()) fprintf(stderr," %s\n", FAILED ? "Failed" : "Success");
+//   if(FAILED) return 2;
+//   //Merge connected components together
+//   if(VERBOSE()) fprintf(stderr,"Connecting...");
+//   FAILED = !g.make_connected();
+//   if(VERBOSE()) fprintf(stderr," %s\n", FAILED ? "Failed" : "Success");
+//   if(FAILED) return 3;
+//   //Convert graph_molloy_opt to graph_molloy_hash
+//   if(VERBOSE()) fprintf(stderr,"Convert adjacency lists into hash tables...");
+//   int *hc = g.hard_copy();
+//   g.~graph_molloy_opt();
+//   graph_molloy_hash gh(hc);
+//   delete[] hc;
+//   if(VERBOSE()) fprintf(stderr,"Done\n");
+//   //Shuffle
+//   gh.shuffle(5*gh.nbarcs(), SHUFFLE_TYPE);
+//   //Output
+//   gh.print();
+//   if(MONITOR_TIME) {
+//     double t = double(clock()) / double(CLOCKS_PER_SEC);
+//     fprintf(stderr,"Time used: %f\n", t);
+//   }
+//   return 0;
+// }
+
+//_________________________________________________________________________
+// int parse_options(int &argc, char** &argv) {
+  // bool HELP = false;
+  // int argc0 = argc;
+  // argc = 1;
+  // for(int a=1; a<argc0; a++) {
+  //   if(strcmp(argv[a],"-v")==0) SET_VERBOSE(VERBOSE_SOME);
+  //   else if(strcmp(argv[a],"-vv")==0) SET_VERBOSE(VERBOSE_LOTS);
+  //   else if(strcmp(argv[a],"-s")==0) my_srandom(0);
+  //   else if(strcmp(argv[a],"-?")==0 || strcmp(argv[1],"--help")==0 || strcmp(argv[1],"/?")==0) HELP = true;
+  //   else if(strcmp(argv[a],"-t")==0) MONITOR_TIME = true;
+  //   else if(strcmp(argv[a],"-g")==0) SHUFFLE_TYPE = GKAN_HEURISTICS;
+  //   else if(strcmp(argv[a],"-b")==0) SHUFFLE_TYPE = BRUTE_FORCE_HEURISTICS;
+  //   else if(strcmp(argv[a],"-f")==0) SHUFFLE_TYPE = FAB_HEURISTICS;
+  //   else if(strcmp(argv[a],"-o")==0) SHUFFLE_TYPE = OPTIMAL_HEURISTICS;
+  //   else if(strcmp(argv[a],"-raw")==0) RAW_DEGREES=true;
+  //   else // No option present
+  //     argv[argc++] = argv[a];
+  // }
+  // if(!HELP && argc==2) {
+  //   Fdeg = fopen(argv[1],"r");
+  //   if(Fdeg==NULL) {
+  //     fprintf(stderr,"Error : couldn't open file \"%s\" for reading\n",argv[1]);
+  //     return -1;
+  //   }
+  //   argv[1]=argv[0];
+  //   argv++;
+  //   argc--;
+  // }
+  // if(HELP || argc!=1) {
+  //   fprintf(stderr,"Usage : %s [options] [file containing degree distribution]\n",argv[0]);
+  //   fprintf(stderr," -> %s returns a graph in its standard output\n",argv[0]);
+  //   fprintf(stderr,"    If no file is given, %s reads its standard input\n",argv[0]);
+  //   fprintf(stderr,"    [-v] and [-vv] options causes extra verbose.\n");
+  //   fprintf(stderr,"    [-g] option uses the Gkantsidis heuristics.\n");
+  //   fprintf(stderr,"    [-b] option uses the Brute Force heuristics.\n");
+  //   fprintf(stderr,"    [-f] option uses the Modified Gkantsidis heuristics.\n");
+  //   fprintf(stderr,"    [-o] option uses the Optimal Gkantsidis heuristics.\n");
+  //   fprintf(stderr,"    [-t] option monitors computation time\n");
+  //   fprintf(stderr,"    [-s] does a srandom(0) to get a constant random graph\n");
+  //   fprintf(stderr,"    [-raw] is to take raw degree sequences as input\n");
+  //   return -1;
+  // }
+//   return 0;
+// }
+
+
+} // namespace gengraph
+
+using namespace gengraph;
+
+extern "C" {
+
+int igraph_degree_sequence_game_vl(igraph_t *graph,
+				   const igraph_vector_t *out_seq,
+				   const igraph_vector_t *in_seq) {
+  long int sum=igraph_vector_sum(out_seq);
+  if (sum % 2 != 0) {
+    IGRAPH_ERROR("Sum of degrees should be even", IGRAPH_EINVAL);
+  }
+  
+  RNG_BEGIN();
+
+  if (in_seq && igraph_vector_size(in_seq) != 0) {
+    RNG_END();
+    IGRAPH_ERROR("This generator works with undirected graphs only", IGRAPH_EINVAL);
+  }
+
+  degree_sequence *dd = new degree_sequence(out_seq);  
+  
+  graph_molloy_opt *g = new graph_molloy_opt(*dd);
+  delete dd;
+
+  if (!g->havelhakimi()) {
+    delete g;
+    RNG_END();
+    IGRAPH_ERROR("Cannot realize the given degree sequence as an undirected, simple graph",
+		 IGRAPH_EINVAL);
+  }
+  
+  if (!g->make_connected()) {
+    delete g;
+    RNG_END();
+    IGRAPH_ERROR("Cannot make a connected graph from the given degree sequence", 
+		 IGRAPH_EINVAL);
+  }
+  
+  int *hc = g->hard_copy();
+  delete g;
+  graph_molloy_hash *gh = new graph_molloy_hash(hc);
+  delete [] hc;
+
+  gh->shuffle(5*gh->nbarcs(), 100*gh->nbarcs(), SHUFFLE_TYPE);
+  
+  IGRAPH_CHECK(gh->print(graph));
+  delete gh;
+
+  RNG_END();
+  
+  return 0;
+}
+
+}
diff --git a/src/gengraph_powerlaw.cpp b/src/gengraph_powerlaw.cpp
new file mode 100644
index 0000000..f7cb729
--- /dev/null
+++ b/src/gengraph_powerlaw.cpp
@@ -0,0 +1,222 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+// Pascalou ...
+#ifdef pascalou
+#define my_random() random()
+#define MY_RAND_MAX 0x7FFFFFFF
+#else
+#include "gengraph_definitions.h"
+#endif
+
+#include "gengraph_powerlaw.h"
+#include <cstdio>
+#include <cmath>
+#include <cassert>
+
+#include "igraph_error.h"
+
+namespace gengraph {
+
+// Destructor
+powerlaw::~powerlaw() {
+  delete[] table;
+  if(dt!=NULL) delete[] dt;
+}
+
+// Constructor
+powerlaw::powerlaw(double _alpha, int _mini, int _maxi) {
+  alpha = _alpha;
+  mini = _mini;
+  maxi = _maxi;
+  if(alpha<=2.0 && maxi<0)
+    igraph_warningf("powerlaw exponent %f should be > 2 when no "
+		    "Maximum is specified", __FILE__, __LINE__, -1, alpha);
+  if(alpha<=1.0 && maxi>=0)
+    igraph_warningf("powerlaw exponent %f should be > 1", __FILE__, __LINE__,
+		    -1, alpha);
+  if(maxi>=0 && mini>maxi)
+    igraph_warningf("powerlaw max %d should be greater than min %d",
+		    __FILE__, __LINE__, -1, maxi, mini);
+  table = new int[POWERLAW_TABLE];
+  tabulated = 0;
+  dt = NULL;
+}
+
+// Sample
+int powerlaw::sample() {
+  if(proba_big!=0 && test_proba(proba_big)) return int(floor(0.5+big_sample(random_float())));
+  int r=my_random();
+  // table[] contains integer from MY_RAND_MAX downto 0, in blocks. Search block...
+  if(r>(MY_RAND_MAX>>max_dt)) return mini;
+  int k=0;
+  while(k<max_dt) { r<<=1; r+=random_bit(); k++; };
+  int a=0;
+  int b;
+  while((b=dt[k++])<0 || r<table[b]) { 
+    if(b>=0) {
+      a=b+1;
+      if(a==tabulated-1) break;
+      r<<=1;
+      r+=random_bit();
+    }
+  }
+
+  // Now that we found the good block, run a dichotomy on this block [a,b]
+  while(a<b) {
+    int c = (a+b)/2;
+    if(r<table[c]) a=c+1;
+    else b=c;
+  }
+  return mini+a;
+}
+
+// Proba
+double powerlaw::proba(int k) {
+  if(k<mini || (maxi>=0 && k>maxi)) return 0.0;
+  if(k>=mini+tabulated)
+    return proba_big*(big_inv_sample(double(k)-0.5)-big_inv_sample(double(k)+0.5));
+  else {
+    double div = table_mul;
+    int prev_pos_in_table = k-mini-1;
+    if(prev_pos_in_table<0) return (double(MY_RAND_MAX)+1.0-double(table[0]>>max_dt))*div;
+    // what block are we in ?
+    int k=0;
+    while(k<max_dt) { div*=0.5; k++; };
+    while(dt[k]<0 || dt[k]<prev_pos_in_table) { k++; div*=0.5; };
+    double prob2 = double(table[prev_pos_in_table+1]);
+    if(dt[k]==prev_pos_in_table) do prob2*=0.5;while(dt[++k]<0);
+    return (double(table[prev_pos_in_table])-prob2)*div;
+  }
+}
+
+// Relative Error
+double powerlaw::error() {
+  return 1.0/(double(tabulated)*double(tabulated));
+}
+
+// Mean
+double powerlaw::mean() {
+  double sum = 0.0;
+  for(int i=mini+tabulated; --i>=mini; ) sum+=double(i)*proba(i);
+  // add proba_big * integral(big_sample(t),t=0..1)
+  if(proba_big!=0) sum += proba_big*((pow(_a+_b,_exp+1.0)-pow(_b,_exp+1.0))/(_a*(_exp+1.0)) +double(mini)-offset-sum);
+  return sum;
+}
+
+// Median. Returns integer Med such that P(X<=Med) >= 1/2
+int powerlaw::median() {
+  if(proba_big>0.5) return int(floor(0.5+big_sample(1.0-0.5/proba_big)));
+  double sum = 0.0;
+  int i=mini;
+  while(sum<0.5) sum+=proba(i++);
+  return i-1;
+}  
+
+void powerlaw::init_to_offset(double _offset, int _tabulated) {
+  offset = _offset;
+  tabulated = _tabulated;
+  if(maxi>=0 && tabulated > maxi-mini) tabulated=maxi-mini+1;
+  double sum = 0.0;
+  double item = double(tabulated)+offset;
+  // Compute sum of tabulated probabilities
+  for(int i=tabulated; i--; ) sum += pow(item-=1.0, -alpha);
+  // Compute others parameters : proba_big, table_mul, _a, _b, _exp
+  if(maxi>0 && maxi<=mini+tabulated-1) {
+    proba_big = 0;
+    table_mul = inv_RANDMAX;
+  }
+  else {
+    if(maxi<0) _b = 0.0;
+    else _b = pow(double(maxi-mini)+0.5+offset, 1.0-alpha);
+    _a = pow(double(tabulated)-0.5+offset,1.0-alpha) - _b;
+    _exp = 1.0 / (1.0 - alpha);
+    double sum_big = _a*(-_exp);
+    proba_big = sum_big / (sum + sum_big);
+    table_mul = inv_RANDMAX * sum / (sum + sum_big);
+  }
+  // How many delimiters will be necessary for the table ?
+  max_dt = max(0,int(floor(alpha*log(double(tabulated))/log(2.0)))-6);
+  if(dt!=NULL) delete[] dt;
+  dt = new int[max_dt+1];
+  // Create table as decreasing integers from MY_RAND_MAX+1 (in virtual position -1) down to 0
+  // Every time the index crosses a delimiter, numbers get doubled.
+  double ssum = 0;
+  double mul = (double(MY_RAND_MAX)+1.0)*pow(2.0,max_dt)/sum;
+  item = double(tabulated)+offset;
+  int k = max_dt;
+  dt[k--]=tabulated-1;
+  for(int i=tabulated; --i>0; ) {
+    table[i] = int(floor(0.5+ssum));
+    ssum += mul * pow(item-=1.0,-alpha);
+    if(ssum>double(MY_RAND_MAX/2) && k>=0) {
+      while((ssum*=0.5)>double(MY_RAND_MAX/2)) { mul*=0.5; dt[k--]=-1; };
+      mul*=0.5; dt[k--]=i-1;
+    }
+  }
+  table[0] = int(floor(0.5+ssum));
+  max_dt = k+1;
+}
+
+void powerlaw::adjust_offset_mean(double _mean, double err, double factor) {
+  // Set two bounds for offset
+  double ol = offset;
+  double oh = offset;
+  if(mean()<_mean) {
+    do {
+      ol = oh;
+      oh *= factor;
+      init_to_offset(oh, tabulated);
+    } while(mean()<_mean);
+  }
+  else {
+    do {
+      oh = ol;
+      ol /= factor;
+      init_to_offset(ol, tabulated);
+    } while(mean()>_mean);
+  }
+  // Now, dichotomy
+  while(fabs(oh-ol) > err*ol) {
+    double oc = sqrt(oh*ol);
+    init_to_offset(oc, tabulated);
+    if(mean()<_mean) ol = oc;
+    else oh = oc;
+  }
+  init_to_offset(sqrt(ol*oh), tabulated);
+}
+
+double powerlaw::init_to_mean(double _mean) {
+  if(maxi>=0 && _mean >= 0.5*double((mini+maxi))) {
+    igraph_errorf("Fatal error in powerlaw::init_to_mean(%f): "
+		  "Mean must be in ]min, (min+max)/2[ = ]%d, %d[",
+		  __FILE__, __LINE__, IGRAPH_EINVAL, 
+		  _mean, mini, (mini+maxi)/2);
+    return(-1.0);
+  }
+  init_to_offset(_mean-double(mini), 100);
+  adjust_offset_mean(_mean, 0.01, 2);
+  init_to_offset(offset, POWERLAW_TABLE);
+  double eps = 1.0/(double(POWERLAW_TABLE));
+  adjust_offset_mean(_mean, eps*eps, 1.01);
+  return offset;
+}
+
+} // namespace gengraph
diff --git a/src/gengraph_powerlaw.h b/src/gengraph_powerlaw.h
new file mode 100644
index 0000000..8bcc81e
--- /dev/null
+++ b/src/gengraph_powerlaw.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef _POWERLAW_H
+#define _POWERLAW_H
+
+// pascalou
+#ifndef pascalou
+#include "gengraph_definitions.h"
+#endif
+
+// Discrete integer power-law : P(X=min+k) is proportionnal to (k+k0)^-alpha
+// - possibility to determine a range [Min, Max] of possible samples
+// - possibility to automatically compute k0 to obtain a given mean z
+
+namespace gengraph {
+
+#define POWERLAW_TABLE 10000
+
+class powerlaw {
+private:
+  double alpha;  // Exponent
+  int mini; // Minimum sample
+  int maxi; // Maximum sample
+  double offset; // Offset
+  int tabulated; // Number of values to tabulate
+  int *table;    // Table containing cumulative distribution for k=mini..mini+tabulated-1
+  int *dt;        // Table delimiters
+  int max_dt;     // number of delimiters - 1
+  double proba_big;   // Probability to take a non-tabulated value
+  double table_mul;   // equal to (1-proba_big)/(RAND_MAX+1)
+
+  // Sample a non-tabulated value >= mini+tabulated
+  inline double big_sample(double randomfloat) {
+    return double(mini)+pow(_a * randomfloat + _b, _exp)-offset;
+  }
+  inline double big_inv_sample(double s) {
+    return (pow(s-double(mini)+offset,1.0/_exp)-_b)/_a;
+  }
+  double _exp, _a, _b; // Cached values used by big_sample();
+
+  // Dichotomic adjust of offset, so that to_adjust() returns value with
+  // a precision of eps. Note that to_adjust() must be an increasing function of offset.
+  void adjust_offset_mean(double value, double eps, double fac);
+
+public:
+  int sample();      // Return a random integer
+  double proba(int); // Return probability to return integer
+  double error();    // Returns relative numerical error done by this class
+  double mean();     // Returns mean of the sampler
+  int median();      // Returns median of the sampler
+
+  // Initialize the power-law sampler.
+  void init_to_offset(double, int);
+  // Same, but also returns the offset found
+  double init_to_mean(double);
+  double init_to_median(double);
+
+  inline void init() { init_to_offset(double(mini),POWERLAW_TABLE); };
+
+  ~powerlaw();
+  powerlaw(double exponent, int mini, int maxi=-1);
+};
+
+} // namespace gengraph
+
+#endif //_POWERLAW_H
diff --git a/src/gengraph_qsort.h b/src/gengraph_qsort.h
new file mode 100644
index 0000000..7996a37
--- /dev/null
+++ b/src/gengraph_qsort.h
@@ -0,0 +1,402 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef QSORT_H
+#define QSORT_H
+
+#include <assert.h>
+#include <stdio.h>
+
+namespace gengraph {
+
+//___________________________________________________________________________
+// check if every element is zero
+inline bool check_zero(int *mem, int n) {
+  for(int *v = mem+n; v!=mem; ) if(*(--v)!=0) return false;
+  return true;
+}
+
+//___________________________________________________________________________
+//  Sort simple integer arrays in ASCENDING order
+//___________________________________________________________________________
+inline int med3(int a, int b, int c) {
+  if(a<b) {
+    if(c<b) return (a<c) ? c : a;
+    else return b;
+  }
+  else {
+    if(c<a) return (b<c) ? c : b;
+    else return a;
+  }
+}
+
+inline void isort(int *v, int t) {
+  if(t<2) return;
+  for(int i=1; i<t; i++) {
+    register int *w = v+i;
+    int tmp = *w;
+    while(w!=v && *(w-1)>tmp) { *w = *(w-1); w--; }
+    *w = tmp;
+  }
+}
+
+inline int partitionne(int *v, int t, int p) {
+  int i=0;
+  int j=t-1;
+  while(i<j) {
+    while(i<=j && v[i]<p) i++;
+    while(i<=j && v[j]>p) j--;
+    if(i<j) {
+      int tmp=v[i];
+      v[i++]=v[j];
+      v[j--]=tmp;
+    }
+  }
+  if(i==j && v[i]<p) i++;
+  assert(i!=0 && i!=t);
+  return i;
+}
+  
+inline void qsort(int *v, int t) {
+  if(t<15) isort(v,t);
+  else {
+    int x = partitionne(v, t, med3(v[t>>1], v[(t>>2)+2], v[t-(t>>1)-2]));
+    qsort(v,x);
+    qsort(v+x,t-x);
+  }
+}
+
+inline int qsort_median(int *v, int t, int pos) {
+  if(t<10) { isort(v,t); return v[pos]; }
+  int x = partitionne(v, t, med3(v[t>>1], v[(t>>2)+2], v[t-(t>>1)-2]));
+  if(pos<x) return qsort_median(v, x, pos);
+  else return qsort_median(v+x, t-x, pos-x);
+} 
+  
+inline int qsort_median(int *v, int t) { return qsort_median(v,t,t/2); }
+
+//___________________________________________________________________________
+//  Sort simple double arrays in ASCENDING order
+//___________________________________________________________________________
+inline double med3(double a, double b, double c) {
+  if(a<b) {
+    if(c<b) return (a<c) ? c : a;
+    else return b;
+  }
+  else {
+    if(c<a) return (b<c) ? c : b;
+    else return a;
+  }
+}
+
+inline void isort(double *v, int t) {
+  if(t<2) return;
+  for(int i=1; i<t; i++) {
+    register double *w = v+i;
+    double tmp = *w;
+    while(w!=v && *(w-1)>tmp) { *w = *(w-1); w--; }
+    *w = tmp;
+  }
+}
+
+inline int partitionne(double *v, int t, double p) {
+  int i=0;
+  int j=t-1;
+  while(i<j) {
+    while(i<=j && v[i]<p) i++;
+    while(i<=j && v[j]>p) j--;
+    if(i<j) {
+      double tmp=v[i];
+      v[i++]=v[j];
+      v[j--]=tmp;
+    }
+  }
+  if(i==j && v[i]<p) i++;
+  assert(i!=0 && i!=t);
+  return i;
+}
+  
+inline void qsort(double *v, int t) {
+  if(t<15) isort(v,t);
+  else {
+    int x = partitionne(v, t, med3(v[t>>1], v[(t>>2)+2], v[t-(t>>1)-2]));
+    qsort(v,x);
+    qsort(v+x,t-x);
+  }
+}
+
+inline double qsort_median(double *v, int t, int pos) {
+  if(t<10) { isort(v,t); return v[pos]; }
+  int x = partitionne(v, t, med3(v[t>>1], v[(t>>2)+2], v[t-(t>>1)-2]));
+  if(pos<x) return qsort_median(v, x, pos);
+  else return qsort_median(v+x, t-x, pos-x);
+} 
+
+inline double qsort_median(double *v, int t) { return qsort_median(v,t,t/2); }
+
+//___________________________________________________________________________
+// Sort integer arrays according to value stored in mem[], in ASCENDING order
+inline void isort(int *mem, int *v, int t) {
+  if(t<2) return;
+  for(int i=1; i<t; i++) {
+    int vtmp = v[i];
+    int tmp = mem[vtmp];
+    int j;
+    for(j=i; j>0 && tmp<mem[v[j-1]]; j--) v[j]=v[j-1];
+    v[j] = vtmp;
+  }
+}
+
+inline void qsort(int *mem, int *v, int t) {
+  if(t<15) isort(mem,v,t);
+  else {
+    int p = med3(mem[v[t>>1]], mem[v[(t>>2)+3]], mem[v[t-(t>>1)-3]]);
+    int i=0;
+    int j=t-1;
+    while(i<j) {
+      while(i<=j && mem[v[i]]<p)  i++;
+      while(i<=j && mem[v[j]]>p) j--;
+      if(i<j) {
+        int tmp=v[i];
+        v[i++]=v[j];
+        v[j--]=tmp;
+      }
+    }
+    if(i==j && mem[v[i]]<p) i++;
+    assert(i!=0 && i!=t);
+    qsort(mem,v,i);
+    qsort(mem,v+i,t-i);
+  }
+}
+
+//Box-Sort 1..n according to value stored in mem[], in DESCENDING order.
+inline int *pre_boxsort(int *mem, int n, int &offset) {
+  int *yo;
+  // maximum and minimum
+  int mx = mem[0];
+  int mn = mem[0];
+  for(yo=mem+n-1; yo!=mem; yo--) {
+    register int x = *yo;
+    if(x>mx) mx=x;
+    if(x<mn) mn=x;
+  }
+  // box
+  int c = mx-mn+1;
+  int *box = new int[c];
+  for(yo=box+c; yo!=box; *(--yo)=0) { }
+  for(yo=mem+n; yo!=mem; box[*(--yo)-mn]++) { }
+  // cumul sum
+  int sum=0;
+  for(yo=box+c; yo!=box; ) {
+    sum += *(--yo);
+    *yo = sum;
+  }
+  offset = mn;
+  return box;
+}
+
+inline int *boxsort(int *mem, int n, int *buff=NULL) {
+  int i;
+  if(n<=0) return buff;
+  int offset=0;
+  int *box = pre_boxsort(mem,n,offset);
+  // sort
+  if(buff==NULL) buff=new int[n];
+  for(i=0; i<n; i++) buff[--box[mem[i]-offset]]=i;
+  // clean
+  delete[] box;
+  return buff;
+}
+
+// merge two sorted arays in their intersection. Store the result in first array, and return length
+inline int intersect(int *a, int a_len, int *b, int b_len) {
+  if(a_len==0 || b_len==0) return 0;
+  int *asup = a+a_len;
+  int *bsup = b+b_len;
+  int len=0;
+  int *p = a;
+  do {
+    if (*a == *b) p[len++] = *a;
+    do if(++a == asup) return len; while(*a<*b);
+    if (*a == *b) p[len++] = *a;
+    do if(++b == bsup) return len; while(*b<*a);
+  } while(true);
+}
+
+// merge two sorted arays in their union, store result in m
+inline int unify(int *m, int *a, int a_len, int *b, int b_len) {
+  int *asup = a+a_len;
+  int *bsup = b+b_len;
+  int len=0;
+  while(a!=asup && b!=bsup) {
+    if(*a < *b) m[len++] = *(a++);
+    else {
+      if (*a == *b) a++;
+      m[len++] = *(b++);
+    }
+  }
+  while(a!=asup) m[len++]=*(a++);
+  while(b!=asup) m[len++]=*(b++);
+  return len;
+}
+
+// lexicographic compare
+inline int lex_comp(int *v1, int *v2, int n) {
+  int *stop = v1+n;
+  while(v1!=stop && *v1==*v2) { v1++; v2++; };
+  if(v1==stop) return 0; else if(*v1<*v2) return -1; else return 1;
+}
+// lexicographic median of three
+inline int *lex_med3(int *a, int *b, int *c, int s) {
+  int ab = lex_comp(a,b,s);
+  if(ab==0) return a;
+  else {
+    int cb = lex_comp(c,b,s);
+    if(cb==0) return b;
+    int ca = lex_comp(c,a,s);
+    if(ab<0) { if(cb>0) return b; else return (ca>0) ? c : a; }
+    else     { if(cb<0) return b; else return (ca<0) ? c : a; }
+  }
+}
+
+// Lexicographic sort
+inline void lex_isort(int **l, int *v, int t, int s) {
+  if(t<2) return;
+  for(int i=1; i<t; i++) {
+    register int *w = v+i;
+    int tmp = *w;
+    while(w!=v && lex_comp(l[tmp],l[*(w-1)],s)<0) { *w = *(w-1); w--; }
+    *w = tmp;
+  }
+}
+
+#ifdef _STABLE_SORT_ONLY
+#define _CRITICAL_SIZE_QSORT 0x7FFFFFFF
+#warning "lex_qsort will be replaced by lex_isort"
+#else
+#define _CRITICAL_SIZE_QSORT 15
+#endif
+
+inline void lex_qsort(int **l, int *v, int t, int s) {
+
+  if(t<_CRITICAL_SIZE_QSORT) lex_isort(l,v,t,s);
+  else {
+    int *p = lex_med3(l[v[t>>1]], l[v[(t>>2)+2]], l[v[t-(t>>1)-2]], s);
+    int i=0;
+    int j=t-1;
+//    printf("pivot = %d\n",p);
+    while(i<j) {
+//      for(int k=0; k<t; k++) printf("%d ",v[k]);
+      while(i<=j && lex_comp(l[v[i]],p,s)<0) i++;
+      while(i<=j && lex_comp(l[v[j]],p,s)>0) j--;
+      if(i<j) {
+//        printf("  swap %d[%d] with %d[%d]\n",i,v[i],j,v[j]);
+        int tmp=v[i];
+        v[i++]=v[j];
+        v[j--]=tmp;
+      }
+    }
+    if(i==j && lex_comp(l[v[i]],p,s)<0) i++;
+    assert(i!=0 && i!=t);
+    lex_qsort(l,v,i,s);
+    lex_qsort(l,v+i,t-i,s);
+  }
+}
+
+// lexicographic indirect compare
+inline int lex_comp_indirect(int *key, int *v1, int *v2, int n) {
+  int *stop = v1+n;
+  while(v1!=stop && key[*v1]==key[*v2]) { v1++; v2++; };
+  if(v1==stop) return 0; else if(key[*v1]<key[*v2]) return -1; else return 1;
+}
+
+inline int qsort_min(const int a, const int b) { return a<=b ? a : b; }
+
+// mix indirect compare
+inline int mix_comp_indirect(int *key, int a, int b, int **neigh, int *degs)
+{
+  if(key[a]<key[b]) return -1;
+  else if(key[a]>key[b]) return 1;
+  else {
+    int cmp=lex_comp_indirect(key,neigh[a],neigh[b],qsort_min(degs[a],degs[b]));
+    if(cmp==0) {
+      if(degs[a]>degs[b]) return -1;
+      if(degs[a]<degs[b]) return 1;
+    }
+    return cmp;
+  }
+}
+// lexicographic indirect median of three
+inline int mix_med3_indirect(int *key, int a, int b, int c, int **neigh, int *degs) {
+  int ab = mix_comp_indirect(key,a,b,neigh,degs);
+  if(ab==0) return a;
+  else {
+    int cb = mix_comp_indirect(key,c,b,neigh,degs);
+    if(cb==0) return b;
+    int ca = mix_comp_indirect(key,c,a,neigh,degs);
+    if(ab<0) { if(cb>0) return b; else return (ca>0) ? c : a; }
+    else     { if(cb<0) return b; else return (ca<0) ? c : a; }
+  }
+}
+
+// Sort integer arrays in ASCENDING order
+inline void mix_isort_indirect(int *key, int *v, int t, int **neigh, int *degs)
+{
+  if(t<2) return;
+  for(int i=1; i<t; i++) {
+    register int *w = v+i;
+    int tmp = *w;
+    while(w!=v && mix_comp_indirect(key,tmp,*(w-1),neigh,degs)<0) {
+      *w = *(w-1);
+      w--;
+    }
+    *w = tmp;
+  }
+}
+
+inline void mix_qsort_indirect(int *key, int *v, int t, int **neigh, int *degs)
+{
+  if(t<15) mix_isort_indirect(key,v,t,neigh,degs);
+  else {
+    int p = mix_med3_indirect(key, v[t>>1], v[(t>>2)+2], v[t-(t>>1)-2], neigh, degs);
+    int i=0;
+    int j=t-1;
+//    printf("pivot = %d\n",p);
+    while(i<j) {
+//      for(int k=0; k<t; k++) printf("%d ",v[k]);
+      while(i<=j && mix_comp_indirect(key,v[i],p,neigh,degs)<0) i++;
+      while(i<=j && mix_comp_indirect(key,v[j],p,neigh,degs)>0) j--;
+      if(i<j) {
+//        printf("  swap %d[%d] with %d[%d]\n",i,v[i],j,v[j]);
+        int tmp=v[i];
+        v[i++]=v[j];
+        v[j--]=tmp;
+      }
+    }
+    if(i==j && mix_comp_indirect(key,v[i],p,neigh,degs)<0) i++;
+    assert(i!=0 && i!=t);
+    mix_qsort_indirect(key,v,i,neigh,degs);
+    mix_qsort_indirect(key,v+i,t-i,neigh,degs);
+  }
+}
+
+} // namespace gengraph
+
+#endif //QSORT_H
diff --git a/src/gengraph_random.cpp b/src/gengraph_random.cpp
new file mode 100644
index 0000000..d176631
--- /dev/null
+++ b/src/gengraph_random.cpp
@@ -0,0 +1,278 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#define RNG_C
+
+#ifdef RCSID
+static const char rcsid[] = "$Id: random.cpp,v 1.15 2003/05/14 03:04:45 wilder Exp wilder $";
+#endif
+
+//________________________________________________________________________
+// See the header file random.h for a description of the contents of this
+// file as well as references and credits.
+
+#include <cmath>
+#include "gengraph_random.h"
+
+using namespace std;
+using namespace KW_RNG;
+
+//________________________________________________________________________
+// RNG::RNOR generates normal variates with rejection.
+// nfix() generates variates after rejection in RNOR.
+// Despite rejection, this method is much faster than Box-Muller.
+
+// double RNG::nfix(slong h, ulong i)
+// {
+//   const double r = 3.442620f; 	// The starting of the right tail
+//   static double x, y;
+  
+//   for(;;) {
+//     x = h * wn[i];
+
+//     // If i == 0, handle the base strip
+//     if (i==0){
+//       do {
+// 	x = -log(rand_open01()) * 0.2904764;   // .2904764 is 1/r
+// 	y = -log(rand_open01());			
+//       } while (y + y < x * x);
+//       return ((h > 0) ? r + x : -r - x);
+//     }
+    
+//     // If i > 0, handle the wedges of other strips
+//     if (fn[i] + rand_open01() * (fn[i - 1] - fn[i]) < exp(-.5 * x * x) )
+//       return x;
+    
+//     // start all over
+//     h = rand_int32();
+//     i = h & 127;
+//     if ((ulong) abs((sint) h) < kn[i])
+//       return (h * wn[i]);
+//   }
+
+// } // RNG::nfix
+
+// // __________________________________________________________________________
+// // RNG::RNOR generates exponential variates with rejection.
+// // efix() generates variates after rejection in REXP.
+  
+// double RNG::efix(ulong j, ulong i)
+// {
+//   double x;
+//   for (;;)
+//   {
+//     if (i == 0)
+//       return (7.69711 - log(rand_open01()));
+    
+//     x = j * we[i];
+//     if (fe[i] + rand_open01() * (fe[i - 1] - fe[i]) < exp(-x)) 
+//       return (x);
+    
+//     j = rand_int32();
+//     i = (j & 255);
+//     if (j < ke[i])
+//       return (j * we[i]);	
+//   }
+  
+// } // RNG::efix
+
+// // __________________________________________________________________________
+// // This procedure creates the tables used by RNOR and REXP
+
+// void RNG::zigset()
+// {
+//   const double m1 = 2147483648.0; // 2^31
+//   const double m2 = 4294967296.0; // 2^32
+
+//   const double vn = 9.91256303526217e-3;
+//   const double ve = 3.949659822581572e-3;
+
+//   double dn = 3.442619855899, tn = dn;
+//   double de = 7.697117470131487, te = de;
+  
+//   int i;
+  
+//   // Set up tables for RNOR
+//   double q = vn / exp(-.5 * dn * dn);
+//   kn[0] = (ulong) ((dn / q) * m1);
+//   kn[1] = 0;
+//   wn[0] = q / m1;
+//   wn[127] = dn / m1;
+//   fn[0]=1.;
+//   fn[127] = exp(-.5 * dn * dn);		
+//   for(i = 126; i >= 1; i--)
+//   {
+//     dn = sqrt(-2 * log(vn / dn + exp(-.5 * dn * dn)));
+//     kn[i + 1] = (ulong) ((dn / tn) * m1);
+//     tn = dn;
+//     fn[i] = exp(-.5 * dn * dn);        
+//     wn[i] = dn / m1;
+//   }
+  
+//   // Set up tables for REXP
+//   q = ve / exp(-de);
+//   ke[0] = (ulong) ((de / q) * m2);
+//   ke[1] = 0;
+//   we[0] = q / m2;
+//   we[255] = de / m2;
+//   fe[0] = 1.;
+//   fe[255] = exp(-de);		
+//   for (i = 254; i >= 1; i--)
+//   {
+//     de = -log(ve / de + exp(-de));
+//     ke[i+1] = (ulong) ((de / te) * m2);
+//     te = de;
+//     fe[i] = exp(-de);
+//     we[i] = de / m2;
+//   }
+
+// } // RNG::zigset
+
+// // __________________________________________________________________________
+// // Generate a gamma variate with parameters 'shape' and 'scale'
+
+// double RNG::gamma(double shape, double scale)
+// {
+//   if (shape < 1)
+//     return gamma(shape + 1, scale) * pow(rand_open01(), 1.0 / shape);
+
+//   const double d = shape - 1.0 / 3.0;
+//   const double c = 1.0 / sqrt(9.0 * d);
+//   double x, v, u;
+//   for (;;) {
+//     do {
+//       x = RNOR();
+//       v = 1.0 + c * x;
+//     } while (v <= 0.0);
+//     v = v * v * v;
+//     u = rand_open01();
+//     if (u < 1.0 - 0.0331 * x * x * x * x)
+//       return (d * v / scale);
+//     if (log(u) < 0.5 * x * x + d * (1.0 - v + log(v)))
+//       return (d * v / scale);
+//   }
+
+// } // RNG::gamma
+
+// // __________________________________________________________________________
+// // gammalog returns the logarithm of the gamma function.  From Numerical
+// // Recipes.
+
+// double gammalog(double xx)
+// {
+//   static double cof[6]={
+//     76.18009172947146, -86.50532032941677, 24.01409824083091,
+//     -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5};
+  
+//   double x = xx;
+//   double y = xx;
+//   double tmp = x + 5.5;
+//   tmp -= (x + 0.5) * log(tmp);
+//   double ser=1.000000000190015;
+//   for (int j=0; j<=5; j++)
+//     ser += cof[j] / ++y;
+//   return -tmp + log(2.5066282746310005 * ser / x);
+// }
+
+// // __________________________________________________________________________
+// // Generate a Poisson variate 
+// // This is essentially the algorithm from Numerical Recipes
+
+// double RNG::poisson(double lambda)
+// {
+//   static double sq, alxm, g, oldm = -1.0;
+//   double em, t, y;
+  
+//   if (lambda < 12.0) {
+//     if (lambda != oldm) {
+//       oldm = lambda;
+//       g = exp(-lambda);
+//     }
+//     em = -1;
+//     t = 1.0;
+//     do {
+//       ++em;
+//       t *= rand_open01();
+//     } while (t > g);
+//   } else {
+//     if (lambda != oldm) {
+//       oldm = lambda;
+//       sq = sqrt(2.0 * lambda);
+//       alxm = log(lambda);
+//       g = lambda * alxm - gammalog(lambda + 1.0);
+//     }
+//     do {
+//       do {
+// 	y = tan(PI * rand_open01());
+// 	em = sq * y + lambda;
+//       } while (em < 0.0);
+//       em = floor(em);
+//       t = 0.9 * (1.0 + y * y) * exp(em * alxm - gammalog(em + 1.0)-g);
+//     } while (rand_open01() > t);
+//   }
+//   return em;
+
+// } // RNG::poisson
+
+// // __________________________________________________________________________
+// // Generate a binomial variate 
+// // This is essentially the algorithm from Numerical Recipes
+
+// int RNG::binomial(double pp, int n)
+// {
+//   if(n==0) return 0;
+//   if(pp==0.0) return 0;
+//   if(pp==1.0) return n;
+//   double p = (pp<0.5 ? pp : 1.0-pp);
+//   double am = n*p;
+//   int bnl = 0;
+//   if(n<25) {
+//     for(int j=n; j--; ) if(rand_closed01()<p) ++bnl;
+//   }
+//   else if(am<1.0) {
+//     double g = exp(-am);
+//     double t = 1.0;
+//     for (; bnl<n; bnl++) if((t*=rand_closed01())<g) break;
+//   }
+//   else {
+//     double en = n;
+//     double oldg = gammalog(en + 1.0);
+//     double pc = 1.0 - p;
+//     double sq = sqrt(2.0 * am * pc);
+//     double y, em, t;
+//     do {
+//       do {
+//         double angle = PI * rand_halfclosed01();
+//       	y = tan(angle);
+//         em = sq * y + am;
+//       } while (em < 0.0 || em >= en + 1.0);
+//       em = floor(em);
+//       t = 1.2 * sq * (1 + y * y) * exp(oldg - gammalog(em + 1.0) -
+//           gammalog(en - em + 1.0) + em * log(p) + (en - em) * log(pc));
+//     } while (rand_closed01() > t);
+//     bnl = int(em);
+//   }
+//   if (p!=pp) bnl=n-bnl;
+//   return bnl;
+// } // RNG::binomial
+
+// __________________________________________________________________________
+// rng.C
+
diff --git a/src/gengraph_random.h b/src/gengraph_random.h
new file mode 100644
index 0000000..2cfe1af
--- /dev/null
+++ b/src/gengraph_random.h
@@ -0,0 +1,212 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef RNG_H
+#define RNG_H
+
+#include "igraph_random.h"
+#include <iostream>
+using namespace std;
+
+namespace KW_RNG {
+
+typedef signed int  sint;
+typedef unsigned int uint;
+typedef signed long  slong;
+typedef unsigned long ulong;
+
+class RNG
+{
+public:
+  RNG() { }
+  RNG(ulong z_, ulong w_, ulong jsr_, ulong jcong_ ) { 
+    IGRAPH_UNUSED(z_); IGRAPH_UNUSED(w_); IGRAPH_UNUSED(jsr_); 
+    IGRAPH_UNUSED(jcong_);
+  };
+  ~RNG() { }
+
+  void init(ulong z_, ulong w_, ulong jsr_, ulong jcong_ ) {
+    IGRAPH_UNUSED(z_); IGRAPH_UNUSED(w_); IGRAPH_UNUSED(jsr_); 
+    IGRAPH_UNUSED(jcong_);    
+  }
+  long rand_int31() { return RNG_INT31(); }
+  double rand_halfopen01()   // (0,1]
+  { return RNG_UNIF01(); }
+  int binomial(double pp, int n) { return RNG_BINOM(n,pp); }
+};
+
+} // namespace KW_RNG
+
+/* This was the original RNG, but now we use the igraph version */
+
+// __________________________________________________________________________
+// random.h   - a Random Number Generator Class
+// random.cpp - contains the non-inline class methods
+
+// __________________________________________________________________________
+// This C++ code uses the simple, very fast "KISS" (Keep It Simple
+// Stupid) random number generator suggested by George Marsaglia in a
+// Usenet posting from 1999.  He describes it as "one of my favorite
+// generators".  It generates high-quality random numbers that
+// apparently pass all commonly used tests for randomness.  In fact, it
+// generates random numbers by combining the results of three other good
+// random number generators that have different periods and are
+// constructed from completely different algorithms.  It does not have
+// the ultra-long period of some other generators - a "problem" that can
+// be fixed fairly easily - but that seems to be its only potential
+// problem.  The period is about 2^123.
+
+// The ziggurat method of Marsaglia is used to generate exponential and
+// normal variates.  The method as well as source code can be found in
+// the article "The Ziggurat Method for Generating Random Variables" by
+// Marsaglia and Tsang, Journal of Statistical Software 5, 2000.
+
+// The method for generating gamma variables appears in "A Simple Method
+// for Generating Gamma Variables" by Marsaglia and Tsang, ACM
+// Transactions on Mathematical Software, Vol. 26, No 3, Sep 2000, pages
+// 363-372.
+
+// The code for Poisson and Binomial random numbers comes from
+// Numerical Recipes in C.
+
+// Some of this code is unlikely to work correctly as is on 64 bit
+// machines.
+
+// #include <cstdlib>
+// #include <ctime>
+// #ifdef _WIN32
+// #include <process.h>
+// #define getpid _getpid
+// #else
+// #include <unistd.h>
+// #endif
+
+// //#ifdef _WIN32
+//   static const double PI   =  3.1415926535897932;
+//   static const double AD_l =  0.6931471805599453;
+//   static const double AD_a =  5.7133631526454228;
+//   static const double AD_b =  3.4142135623730950;
+//   static const double AD_c = -1.6734053240284925;
+//   static const double AD_p =  0.9802581434685472;
+//   static const double AD_A =  5.6005707569738080;
+//   static const double AD_B =  3.3468106480569850;
+//   static const double AD_H =  0.0026106723602095;
+//   static const double AD_D =  0.0857864376269050;
+// //#endif //_WIN32
+
+// namespace KW_RNG {
+
+// class RNG
+// {
+// private:
+//   ulong z, w, jsr, jcong; // Seeds
+
+//   ulong kn[128], ke[256];
+//   double wn[128],fn[128], we[256],fe[256];
+
+// /*
+// #ifndef _WIN32
+//   static const double PI   =  3.1415926535897932;
+//   static const double AD_l =  0.6931471805599453;
+//   static const double AD_a =  5.7133631526454228;
+//   static const double AD_b =  3.4142135623730950;
+//   static const double AD_c = -1.6734053240284925;
+//   static const double AD_p =  0.9802581434685472;
+//   static const double AD_A =  5.6005707569738080;
+//   static const double AD_B =  3.3468106480569850;
+//   static const double AD_H =  0.0026106723602095;
+//   static const double AD_D =  0.0857864376269050;
+// #endif //_WIN32
+// */
+
+// public:
+//   RNG() { init(); zigset(); }
+//   RNG(ulong z_, ulong w_, ulong jsr_, ulong jcong_ ) :
+//     z(z_), w(w_), jsr(jsr_), jcong(jcong_) { zigset(); }
+//   ~RNG() { }
+
+
+//   inline ulong znew() 
+//     { return (z = 36969 * (z & 65535) + (z >> 16)); }
+//   inline ulong wnew() 
+//     { return (w = 18000 * (w & 65535) + (w >> 16)); }
+//   inline ulong MWC()  
+//     { return (((znew() & 65535) << 16) + wnew()); }
+//   inline ulong SHR3()
+//     { jsr ^= ((jsr & 32767) << 17); jsr ^= (jsr >> 13); return (jsr ^= ((jsr << 5) & 0xFFFFFFFF)); }
+//   inline ulong CONG() 
+//     { return (jcong = (69069 * jcong + 1234567) & 0xFFFFFFFF); }
+//   inline double RNOR() {
+//     slong h = rand_int32();
+//     ulong i = h & 127;
+//     return (((ulong) abs((sint) h) < kn[i]) ? h * wn[i] : nfix(h, i));
+//   }
+//   inline double REXP() {
+//     ulong j = rand_int32();
+//     ulong i = j & 255;
+//     return ((j < ke[i]) ? j * we[i] : efix(j, i));
+//   }
+
+//   double nfix(slong h, ulong i);
+//   double efix(ulong j, ulong i);
+//   void zigset();
+
+//   inline void init()
+//     { ulong yo = time(0) + getpid();
+//       z = w = jsr = jcong = yo; }
+//   inline void init(ulong z_, ulong w_, ulong jsr_, ulong jcong_ )
+//     { z = z_; w = w_; jsr = jsr_; jcong = jcong_; }
+
+//   inline ulong rand_int32()         // [0,2^32-1]
+//     { return ((MWC() ^ CONG()) + SHR3()) & 0xFFFFFFFF; }
+//   inline long rand_int31()          // [0,2^31-1]
+//     { return long(rand_int32() >> 1);}
+//   inline double rand_closed01()     // [0,1]
+//     { return ((double) rand_int32() / 4294967295.0); }
+//   inline double rand_open01()       // (0,1)
+//     { return (((double) rand_int32() + 0.5) / 4294967296.0); }
+//   inline double rand_halfclosed01() // [0,1)
+//     { return ((double) rand_int32() / 4294967296.0); }
+//   inline double rand_halfopen01()   // (0,1]
+//     { return (((double) rand_int32() + 0.5) / 4294967295.5); }
+
+//   // Continuous Distributions
+//   inline double uniform(double x = 0.0, double y = 1.0)
+//     { return rand_closed01() * (y - x) + x; }
+//   inline double normal(double mu = 0.0, double sd = 1.0)
+//     { return RNOR() * sd + mu; }
+//   inline double exponential(double lambda = 1)
+//     { return REXP() / lambda; }
+//   double gamma(double shape = 1, double scale = 1);
+//   double chi_square(double df)
+//     { return gamma(df / 2.0, 0.5); }
+//   double beta(double a1, double a2)
+//     { double x1 = gamma(a1, 1); return (x1 / (x1 + gamma(a2, 1))); }
+
+//   // Discrete Distributions
+//   double poisson(double lambda);
+//   int binomial(double pp, int n);
+
+// }; // class RNG
+
+// } // namespace
+
+#endif // RNG_H
+
diff --git a/src/gengraph_vertex_cover.h b/src/gengraph_vertex_cover.h
new file mode 100644
index 0000000..314915b
--- /dev/null
+++ b/src/gengraph_vertex_cover.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * gengraph - generation of random simple connected graphs with prescribed
+ *            degree sequence
+ *
+ * Copyright (C) 2006  Fabien Viger
+ *
+ * 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/>.
+ */
+#ifndef _VERTEX_COVER_H
+#define _VERTEX_COVER_H
+
+// vertex_cover() builds a list of vertices which covers every edge of the graph
+// Input is a classical adjacency-list graph
+// As an output, vertex_cover() modify the degrees in degs[], so that
+// any vertex with a degree > 0 belongs to the vertex coverage.
+// Moreover, vertex_cover() keeps links[] intact, permuting only the adjacency lists
+
+#include "gengraph_box_list.h"
+
+namespace gengraph { 
+
+void vertex_cover(int n, int *links, int *deg, int **neigh = NULL) {
+  int i;
+  // create and initialize neigh[]
+  if (neigh==NULL) {
+    neigh = new int*[n];
+    neigh[0] = links;
+    for(i=1; i<n; i++) neigh[i]=neigh[i-1]+deg[i];
+  }
+  // create box_list
+  box_list bl(n,deg);
+  do {
+    int v;
+    // remove vertices adjacent to vertices of degree 1
+    while((v=bl.get_one())>=0) bl.pop_vertex(v, neigh);
+    // remove vertex of max degree and its highest-degree neighbour
+    if(!bl.is_empty()) {
+      v=bl.get_max();
+      int *w = neigh[v];
+      register int v2 = *(w++);
+      register int dm = deg[v2];
+      register int k = deg[v]-1;
+      while(k--) if(deg[*(w++)]>dm) { v2 = *(w-1); dm=deg[v2]; };
+      bl.pop_vertex(v, neigh);
+      bl.pop_vertex(v2,neigh);
+    }
+  } while(!bl.is_empty());
+}
+
+} // namespace gengraph
+
+#endif //_VERTEX_COVER_H
diff --git a/src/glet.c b/src/glet.c
new file mode 100644
index 0000000..8b0f627
--- /dev/null
+++ b/src/glet.c
@@ -0,0 +1,860 @@
+/* -*- 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_graphlets.h"
+#include "igraph_memory.h"
+#include "igraph_constructors.h"
+#include "igraph_cliques.h"
+#include "igraph_structural.h"
+#include "igraph_qsort.h"
+#include "igraph_conversion.h"
+
+/**
+ * \section graphlets_intro Introduction
+ * 
+ * <para> 
+ * 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.
+ * </para>
+ * 
+ * <para>
+ * igraph contains three functions for performing the graph 
+ * decomponsition of a graph. The first is \ref igraph_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: 
+ * \ref igraph_graphlets_candidate_basis() and 
+ * \ref igraph_graphlets_project().
+ * </para>
+ */
+
+typedef struct {
+  igraph_vector_int_t *newidvectors;
+  igraph_t *newgraphs;
+  igraph_vector_t *newweights;
+  int nc;
+} igraph_i_subclique_next_free_t;
+
+void igraph_i_subclique_next_free(void *ptr) {
+  igraph_i_subclique_next_free_t *data=ptr;
+  int i;
+  if (data->newidvectors) {
+    for (i=0; i<data->nc; i++) {
+      if (data->newidvectors+i) {
+	igraph_vector_int_destroy(data->newidvectors+i);
+      }
+    }
+    igraph_Free(data->newidvectors);
+  }
+  if (data->newgraphs) {
+    for (i=0; i<data->nc; i++) {
+      if (data->newgraphs+i) {
+	igraph_destroy(data->newgraphs+i);
+      }
+    }
+    igraph_Free(data->newgraphs);
+  }
+  if (data->newweights) {
+    for (i=0; i<data->nc; i++) {
+      if (data->newweights+i) {
+	igraph_vector_destroy(data->newweights+i);
+      }
+    }
+    igraph_Free(data->newweights);
+  }
+}
+
+/**
+ * \function igraph_subclique_next
+ * Calculate subcliques of the cliques found at the previous level
+ *
+ * \param graph Input graph.
+ * \param weight Edge weights.
+ * \param ids The ids of the vertices in the input graph.
+ * \param cliques A list of vectors, vertex ids for cliques.
+ * \param result The result is stored here, a list of graphs is stored
+ *        here.
+ * \param resultids The ids of the vertices in the result graphs is
+ *        stored here.
+ * \param clique_thr The thresholds for the cliques are stored here,
+ *        if not a null pointer.
+ * \param next_thr The next thresholds for the cliques are stored
+ *        here, if not a null pointer.
+ *
+ */
+
+int igraph_subclique_next(const igraph_t *graph,
+                          const igraph_vector_t *weights,
+                          const igraph_vector_int_t *ids,
+                          const igraph_vector_ptr_t *cliques,
+                          igraph_vector_ptr_t *result,
+                          igraph_vector_ptr_t *resultweights,
+                          igraph_vector_ptr_t *resultids,
+                          igraph_vector_t *clique_thr,
+                          igraph_vector_t *next_thr) {
+
+  /* The input is a set of cliques, that were found at a previous level.
+     For each clique, we calculate the next threshold, drop the isolate
+     vertices, and create a new graph from them. */
+
+  igraph_vector_int_t mark, map;
+  igraph_vector_int_t edges;
+  igraph_vector_t neis, newedges;
+  igraph_integer_t c, nc=igraph_vector_ptr_size(cliques);
+  igraph_integer_t no_of_nodes=igraph_vcount(graph);
+  igraph_integer_t no_of_edges=igraph_ecount(graph);
+  igraph_vector_int_t *newidvectors=0;
+  igraph_t *newgraphs=0;
+  igraph_vector_t *newweights=0;
+  igraph_i_subclique_next_free_t freedata={ newidvectors, newgraphs,
+                                            newweights, nc };
+
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid length of weight vector", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_int_size(ids) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid length of ID vector", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_ptr_size(result) != nc) {
+    IGRAPH_ERROR("Invalid graph list size", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_ptr_size(resultweights) != nc) {
+    IGRAPH_ERROR("Invalid weight list size", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_ptr_size(resultids) != nc) {
+    IGRAPH_ERROR("Invalid id vector size", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_FINALLY(igraph_i_subclique_next_free, &freedata);
+  newidvectors=igraph_Calloc(nc, igraph_vector_int_t);
+  if (!newidvectors) {
+    IGRAPH_ERROR("Cannot calculate next cliques", IGRAPH_ENOMEM);
+  }
+  freedata.newidvectors = newidvectors;
+  newweights=igraph_Calloc(nc, igraph_vector_t);
+  if (!newweights) {
+    IGRAPH_ERROR("Cannot calculate next cliques", IGRAPH_ENOMEM);
+  }
+  freedata.newweights = newweights;
+  newgraphs=igraph_Calloc(nc, igraph_t);
+  if (!newgraphs) {
+    IGRAPH_ERROR("Cannot calculate next cliques", IGRAPH_ENOMEM);
+  }
+  freedata.newgraphs = newgraphs;
+
+  igraph_vector_init(&newedges, 100);
+  IGRAPH_FINALLY(igraph_vector_destroy, &newedges);
+  igraph_vector_int_init(&mark, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_destroy, &mark);
+  igraph_vector_int_init(&map, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_destroy, &map);
+  igraph_vector_int_init(&edges, 100);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &edges);
+  igraph_vector_init(&neis, 10);
+  IGRAPH_FINALLY(igraph_vector_destroy, &neis);
+
+  if (clique_thr) { igraph_vector_resize(clique_thr, nc); }
+  if (next_thr)   { igraph_vector_resize(next_thr,   nc); }
+
+  /* Iterate over all cliques. We will create graphs for all
+     subgraphs defined by the cliques. */
+
+  for (c=0; c<nc; c++) {
+    igraph_vector_t *clique=VECTOR(*cliques)[c];
+    igraph_real_t minweight=IGRAPH_INFINITY, nextweight=IGRAPH_INFINITY;
+    igraph_integer_t e, v, clsize=igraph_vector_size(clique);
+    igraph_integer_t noe, nov=0;
+    igraph_vector_int_t *newids=newidvectors+c;
+    igraph_vector_t *neww=newweights+c;
+    igraph_t *newgraph=newgraphs+c;
+    igraph_vector_int_clear(&edges);
+    igraph_vector_clear(&newedges);
+
+    /* --------------------------------------------------- */
+
+    /* Iterate over the vertices of a clique and find the
+       edges within the clique, put them in a list.
+       At the same time, search for the minimum edge weight within
+       the clique and the next edge weight if any. */
+
+    for (v=0; v<clsize; v++) {
+      igraph_integer_t i, neilen, node=VECTOR(*clique)[v];
+      igraph_incident(graph, &neis, node, IGRAPH_ALL);
+      neilen=igraph_vector_size(&neis);
+      VECTOR(mark)[node] = c+1;
+      for (i=0; i<neilen; i++) {
+        igraph_integer_t edge=VECTOR(neis)[i];
+        igraph_integer_t nei=IGRAPH_OTHER(graph, edge, node);
+        if (VECTOR(mark)[nei] == c+1) {
+          igraph_real_t w=VECTOR(*weights)[edge];
+          igraph_vector_int_push_back(&edges, edge);
+          if (w < minweight) {
+            nextweight=minweight;
+            minweight=w;
+          } else if (w > minweight && w < nextweight) {
+            nextweight=w;
+          }
+        }
+      }
+    } /* v < clsize */
+
+    /* --------------------------------------------------- */
+
+    /* OK, we have stored the edges and found the weight of
+       the clique and the next weight to consider */
+
+    if (clique_thr) { VECTOR(*clique_thr)[c] = minweight;  }
+    if (next_thr)   { VECTOR(*next_thr  )[c] = nextweight; }
+
+    /* --------------------------------------------------- */
+
+    /* Now we create the subgraph from the edges above the next
+       threshold, and their incident vertices. */
+
+    igraph_vector_int_init(newids, 0);
+    VECTOR(*resultids)[c] = newids;
+    igraph_vector_init(neww, 0);
+    VECTOR(*resultweights)[c] = neww;
+
+    /* We use mark[] to denote the vertices already mapped to
+       the new graph. If this is -(c+1), then the vertex was
+       mapped, otherwise it was not. The mapping itself is in
+       map[]. */
+
+    noe=igraph_vector_int_size(&edges);
+    for (e=0; e<noe; e++) {
+      igraph_integer_t edge=VECTOR(edges)[e];
+      igraph_integer_t from, to;
+      igraph_real_t w=VECTOR(*weights)[edge];
+      igraph_edge(graph, edge, &from, &to);
+      if (w >= nextweight) {
+        if (VECTOR(mark)[from] == c+1) {
+          VECTOR(map)[from] = nov++;
+          VECTOR(mark)[from] = -(c+1);
+          igraph_vector_int_push_back(newids, VECTOR(*ids)[from]);
+        }
+        if (VECTOR(mark)[to] == c+1) {
+          VECTOR(map)[to] = nov++;
+          VECTOR(mark)[to] = -(c+1);
+          igraph_vector_int_push_back(newids, VECTOR(*ids)[to]);
+        }
+        igraph_vector_push_back(neww, w);
+        igraph_vector_push_back(&newedges, VECTOR(map)[from]);
+        igraph_vector_push_back(&newedges, VECTOR(map)[to]);
+      }
+    }
+
+    igraph_create(newgraph, &newedges, nov, IGRAPH_UNDIRECTED);
+    VECTOR(*result)[c] = newgraph;
+
+    /* --------------------------------------------------- */
+
+  } /* c < nc */
+
+  igraph_vector_destroy(&neis);
+  igraph_vector_int_destroy(&edges);
+  igraph_vector_int_destroy(&mark);
+  igraph_vector_int_destroy(&map);
+  igraph_vector_destroy(&newedges);
+  IGRAPH_FINALLY_CLEAN(6);      /* +1 for the result */
+
+  return 0;
+}
+
+void igraph_i_graphlets_destroy_vectorlist(igraph_vector_ptr_t *vl) {
+  int i, n=igraph_vector_ptr_size(vl);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=(igraph_vector_t*) VECTOR(*vl)[i];
+    if (v) { igraph_vector_destroy(v); }
+  }
+  igraph_vector_ptr_destroy(vl);
+}
+
+void igraph_i_graphlets_destroy_intvectorlist(igraph_vector_ptr_t *vl) {
+  int i, n=igraph_vector_ptr_size(vl);
+  for (i=0; i<n; i++) {
+    igraph_vector_int_t *v=(igraph_vector_int_t*) VECTOR(*vl)[i];
+    if (v) { igraph_vector_int_destroy(v); }
+  }
+  igraph_vector_ptr_destroy(vl);
+}
+
+void igraph_i_graphlets_destroy_graphlist(igraph_vector_ptr_t *vl) {
+  int i, n=igraph_vector_ptr_size(vl);
+  for (i=0; i<n; i++) {
+    igraph_t *v=(igraph_t*) VECTOR(*vl)[i];
+    if (v) { igraph_destroy(v); }
+  }
+  igraph_vector_ptr_destroy(vl);
+}
+
+int igraph_i_graphlets(const igraph_t *graph,
+		       const igraph_vector_t *weights,
+		       igraph_vector_ptr_t *cliques,
+		       igraph_vector_t *thresholds,
+		       const igraph_vector_int_t *ids,
+		       igraph_real_t startthr) {
+
+  /* This version is different from the main function, and is
+     appropriate to use in recursive calls, because it _adds_ the
+     results to 'cliques' and 'thresholds' and uses the supplied
+     'startthr' */
+
+  igraph_vector_ptr_t mycliques;
+  int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t subv;
+  igraph_t subg;
+  int i, nographs, nocliques;
+  igraph_vector_ptr_t newgraphs, newweights, newids;
+  igraph_vector_t clique_thr, next_thr;
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&mycliques, 0));
+  IGRAPH_FINALLY(igraph_i_graphlets_destroy_vectorlist, &mycliques);
+  IGRAPH_VECTOR_INIT_FINALLY(&subv, 0);
+
+  /* We start by finding cliques at the lowest threshold */
+  for (i=0; i<no_of_edges; i++) {
+    if (VECTOR(*weights)[i] >= startthr) {
+      IGRAPH_CHECK(igraph_vector_push_back(&subv, i));
+    }
+  }
+  igraph_subgraph_edges(graph, &subg, igraph_ess_vector(&subv),
+			/*delete_vertices=*/ 0);
+  igraph_maximal_cliques(&subg, &mycliques, /*min_size=*/ 0, /*max_size=*/ 0);
+  nocliques=igraph_vector_ptr_size(&mycliques);
+
+  igraph_vector_destroy(&subv);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Get the next cliques and thresholds */
+  igraph_vector_ptr_init(&newgraphs, nocliques);
+  IGRAPH_FINALLY(igraph_i_graphlets_destroy_graphlist, &newgraphs);
+  igraph_vector_ptr_init(&newweights, nocliques);
+  IGRAPH_FINALLY(igraph_i_graphlets_destroy_vectorlist, &newweights);
+  igraph_vector_ptr_init(&newids, nocliques);
+  IGRAPH_FINALLY(igraph_i_graphlets_destroy_intvectorlist, &newids);
+  IGRAPH_VECTOR_INIT_FINALLY(&next_thr, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&clique_thr, 0);
+
+  igraph_subclique_next(graph, weights, ids, &mycliques,
+			&newgraphs, &newweights, &newids,
+			&clique_thr, &next_thr);
+
+  /* Store cliques at the current level */
+  igraph_vector_append(thresholds, &clique_thr);
+  for (i=0; i<nocliques; i++) {
+    igraph_vector_t *cl=(igraph_vector_t*) VECTOR(mycliques)[i];
+    int j, n=igraph_vector_size(cl);
+    for (j=0; j<n; j++) {
+      int node=VECTOR(*cl)[j];
+      VECTOR(*cl)[j] = VECTOR(*ids)[node];
+    }
+    igraph_vector_sort(cl);
+  }
+  igraph_vector_ptr_append(cliques, &mycliques);
+
+  /* Recursive calls for cliques found */
+  nographs=igraph_vector_ptr_size(&newgraphs);
+  for (i=0; i<nographs; i++) {
+    igraph_t *g=VECTOR(newgraphs)[i];
+    if (igraph_vcount(g) > 1) {
+      igraph_vector_t *w=VECTOR(newweights)[i];
+      igraph_vector_int_t *ids=VECTOR(newids)[i];
+      igraph_i_graphlets(g, w, cliques, thresholds, ids, VECTOR(next_thr)[i]);
+    }
+  }
+
+  igraph_vector_destroy(&clique_thr);
+  igraph_vector_destroy(&next_thr);
+  igraph_i_graphlets_destroy_intvectorlist(&newids);
+  igraph_i_graphlets_destroy_vectorlist(&newweights);
+  igraph_i_graphlets_destroy_graphlist(&newgraphs);
+  igraph_vector_ptr_destroy(&mycliques); /* contents was copied over */
+  IGRAPH_FINALLY_CLEAN(6);
+
+  return 0;
+}
+
+typedef struct {
+  const igraph_vector_ptr_t *cliques;
+  const igraph_vector_t *thresholds;
+} igraph_i_graphlets_filter_t;
+
+int igraph_i_graphlets_filter_cmp(void *data, const void *a, const void *b) {
+  igraph_i_graphlets_filter_t *ddata=(igraph_i_graphlets_filter_t *) data;
+  int *aa=(int*) a;
+  int *bb=(int*) b;
+  igraph_real_t t_a=VECTOR(*ddata->thresholds)[*aa];
+  igraph_real_t t_b=VECTOR(*ddata->thresholds)[*bb];
+  igraph_vector_t *v_a, *v_b;
+  int s_a, s_b;
+
+  if (t_a < t_b) {
+    return -1;
+  } else if (t_a > t_b) {
+    return 1;
+  }
+
+  v_a=(igraph_vector_t*) VECTOR(*ddata->cliques)[*aa];
+  v_b=(igraph_vector_t*) VECTOR(*ddata->cliques)[*bb];
+  s_a=igraph_vector_size(v_a);
+  s_b=igraph_vector_size(v_b);
+
+  if (s_a < s_b) {
+    return -1;
+  } else if (s_a > s_b) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int igraph_i_graphlets_filter(igraph_vector_ptr_t *cliques,
+			      igraph_vector_t *thresholds) {
+
+  /* Filter out non-maximal cliques. Every non-maximal clique is
+     part of a maximal clique, at the same threshold.
+
+     First we order the cliques, according to their threshold, and
+     then according to their size. So when we look for a candidate
+     superset, we only need to check the cliques next in the list,
+     until their threshold is different. */
+
+  int i, iptr, nocliques=igraph_vector_ptr_size(cliques);
+  igraph_vector_int_t order;
+  igraph_i_graphlets_filter_t sortdata = { cliques, thresholds };
+
+  igraph_vector_int_init(&order, nocliques);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &order);
+  for (i=0; i<nocliques; i++) { VECTOR(order)[i]=i; }
+
+  igraph_qsort_r(VECTOR(order), nocliques, sizeof(int), &sortdata,
+		 igraph_i_graphlets_filter_cmp);
+
+  for (i=0; i<nocliques-1; i++) {
+    int ri=VECTOR(order)[i];
+    igraph_vector_t *needle=VECTOR(*cliques)[ri];
+    igraph_real_t thr_i=VECTOR(*thresholds)[ri];
+    int n_i=igraph_vector_size(needle);
+    int j=i+1;
+
+    for (j=i+1; j < nocliques; j++) {
+      int rj=VECTOR(order)[j];
+      igraph_real_t thr_j=VECTOR(*thresholds)[rj];
+      igraph_vector_t *hay;
+      int n_j, pi=0, pj=0;
+
+      /* Done, not found */
+      if (thr_j != thr_i) { break; }
+
+      /* Check size of hay */
+      hay=VECTOR(*cliques)[rj];
+      n_j=igraph_vector_size(hay);
+      if (n_i > n_j) { continue; }
+
+      /* Check if hay is a superset */
+      while (pi < n_i && pj < n_j && n_i-pi <= n_j-pj) {
+	int ei=VECTOR(*needle)[pi];
+	int ej=VECTOR(*hay)[pj];
+	if (ei < ej) {
+	  break;
+	} else if (ei > ej) {
+	  pj++;
+	} else {
+	  pi++; pj++;
+	}
+      }
+      if (pi == n_i) {
+	/* Found, delete immediately */
+	igraph_vector_destroy(needle);
+	VECTOR(*cliques)[ri]=0;
+	break;
+      }
+    }
+  }
+
+  /* Remove null pointers from the list of cliques */
+  for (i=0, iptr=0; i<nocliques; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    if (v) {
+      VECTOR(*cliques)[iptr]=v;
+      VECTOR(*thresholds)[iptr]=VECTOR(*thresholds)[i];
+      iptr++;
+    }
+  }
+  igraph_vector_ptr_resize(cliques, iptr);
+  igraph_vector_resize(thresholds, iptr);
+
+  igraph_vector_int_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_graphlets_candidate_basis
+ * Calculate a candidate graphlets basis
+ *
+ * \param graph The input graph, it must be a simple graph, edge directions are 
+ *        ignored.
+ * \param weights Weights of the edges, a vector.
+ * \param cliques An initialized vector of pointers. 
+ *        The graphlet basis is stored here. Each element of the pointer 
+ *        vector will be a vector of vertex ids. 
+ * \param thresholds An initialized vector, the (highest possible)
+ *        weight thresholds for finding the basis subgraphs are stored
+ *        here.
+ * \return Error code.
+ * 
+ * See also: \ref igraph_graphlets() and \ref igraph_graphlets_project().
+ */
+
+int igraph_graphlets_candidate_basis(const igraph_t *graph,
+				     const igraph_vector_t *weights,
+				     igraph_vector_ptr_t *cliques,
+				     igraph_vector_t *thresholds) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  int no_of_edges=igraph_ecount(graph);
+  igraph_real_t minthr;
+  igraph_vector_int_t ids;
+  igraph_bool_t simple;
+  int i;
+
+  /* Some checks */
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  igraph_is_simple(graph, &simple);
+  if (!simple) {
+    IGRAPH_ERROR("Graphlets work on simple graphs only", IGRAPH_EINVAL);
+  }
+
+  minthr=igraph_vector_min(weights);
+  igraph_vector_ptr_clear(cliques);
+  igraph_vector_clear(thresholds);
+  igraph_vector_int_init(&ids, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &ids);
+  for (i=0; i<no_of_nodes; i++) { VECTOR(ids)[i] = i; }
+
+  igraph_i_graphlets(graph, weights, cliques, thresholds, &ids, minthr);
+
+  igraph_vector_int_destroy(&ids);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_i_graphlets_filter(cliques, thresholds);
+
+  return 0;
+}
+
+int igraph_i_graphlets_project(const igraph_t *graph,
+			       const igraph_vector_t *weights,
+			       const igraph_vector_ptr_t *cliques,
+			       igraph_vector_t *Mu, igraph_bool_t startMu,
+			       int niter, int vid1) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  int no_of_edges=igraph_ecount(graph);
+  int no_cliques=igraph_vector_ptr_size(cliques);
+  igraph_vector_int_t vcl, vclidx, ecl, eclidx, cel, celidx;
+  igraph_vector_t edgelist, newweights, normfact;
+  int i, total_vertices, e, ptr, total_edges;
+  igraph_bool_t simple;
+
+  /* Check arguments */
+  if (no_of_edges != igraph_vector_size(weights)) {
+    IGRAPH_ERROR("Invalid weight vector size", IGRAPH_EINVAL);
+  }
+  if (startMu && igraph_vector_size(Mu) != no_cliques) {
+    IGRAPH_ERROR("Invalid start coefficient vector size", IGRAPH_EINVAL);
+  }
+  if (niter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negative", IGRAPH_EINVAL);
+  }
+  igraph_is_simple(graph, &simple);
+  if (!simple) {
+    IGRAPH_ERROR("Graphlets work on simple graphs only", IGRAPH_EINVAL);
+  }
+
+  if (!startMu) {
+    igraph_vector_resize(Mu, no_cliques);
+    igraph_vector_fill(Mu, 1);
+  }
+
+  /* Count # cliques per vertex. Also, create an index
+     for the edges per clique. */
+  igraph_vector_int_init(&vclidx, no_of_nodes+2);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &vclidx);
+  igraph_vector_int_init(&celidx, no_cliques+3);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &celidx);
+  for (i=0, total_vertices=0, total_edges=0; i<no_cliques; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    int j, n=igraph_vector_size(v);
+    total_vertices += n;
+    total_edges += n*(n-1)/2;
+    VECTOR(celidx)[i+2]=total_edges;
+    for (j=0; j<n; j++) {
+      int vv=VECTOR(*v)[j]-vid1;
+      VECTOR(vclidx)[vv+2] += 1;
+    }
+  }
+  VECTOR(celidx)[i+2]=total_edges;
+
+  /* Finalize index vector */
+  for (i=0; i<=no_cliques; i++) {
+    VECTOR(vclidx)[i+2] += VECTOR(vclidx)[i+1];
+  }
+
+  /* Create vertex-clique list, the cliques for each vertex. */
+  igraph_vector_int_init(&vcl, total_vertices);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &vcl);
+  for (i=0; i<no_cliques; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    int j, n=igraph_vector_size(v);
+    for (j=0; j<n; j++) {
+      int vv=VECTOR(*v)[j]-vid1;
+      int p=VECTOR(vclidx)[vv+1];
+      VECTOR(vcl)[p]=i;
+      VECTOR(vclidx)[vv+1] += 1;
+    }
+  }
+
+  /* Create an edge-clique list, the cliques of each edge */
+  igraph_vector_int_init(&ecl, total_edges);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &ecl);
+  igraph_vector_int_init(&eclidx, no_of_edges+1);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &eclidx);
+  igraph_vector_init(&edgelist, no_of_edges*2);
+  IGRAPH_FINALLY(igraph_vector_destroy, &edgelist);
+  igraph_get_edgelist(graph, &edgelist, /*by_col=*/ 0);
+  for (i=0, e=0, ptr=0; e<no_of_edges; e++) {
+    int from=VECTOR(edgelist)[i++];
+    int to=VECTOR(edgelist)[i++];
+    int from_s=VECTOR(vclidx)[from];
+    int from_e=VECTOR(vclidx)[from+1];
+    int to_s=VECTOR(vclidx)[to];
+    int to_e=VECTOR(vclidx)[to+1];
+    VECTOR(eclidx)[e]=ptr;
+    while (from_s < from_e && to_s < to_e) {
+      int from_v=VECTOR(vcl)[from_s];
+      int to_v=VECTOR(vcl)[to_s];
+      if (from_v==to_v) {
+	VECTOR(ecl)[ptr++] = from_v;
+	from_s++; to_s++;
+      } else if (from_v < to_v) {
+	from_s++;
+      } else {
+	to_s++;
+      }
+    }
+  }
+  VECTOR(eclidx)[e]=ptr;
+
+  igraph_vector_destroy(&edgelist);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Convert the edge-clique list to a clique-edge list */
+  igraph_vector_int_init(&cel, total_edges);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &cel);
+  for (i=0; i<no_of_edges; i++) {
+    int ecl_s=VECTOR(eclidx)[i], ecl_e=VECTOR(eclidx)[i+1], j;
+    for (j=ecl_s; j<ecl_e; j++) {
+      int cl=VECTOR(ecl)[j];
+      int epos=VECTOR(celidx)[cl+1];
+      VECTOR(cel)[epos] = i;
+      VECTOR(celidx)[cl+1] += 1;
+    }
+  }
+
+  /* Normalizing factors for the iteration */
+  igraph_vector_init(&normfact, no_cliques);
+  IGRAPH_FINALLY(igraph_vector_destroy, &normfact);
+  for (i=0; i<no_cliques; i++) {
+    igraph_vector_t *v=VECTOR(*cliques)[i];
+    int n=igraph_vector_size(v);
+    VECTOR(normfact)[i] = n * (n+1) / 2;
+  }
+
+  /* We have the clique-edge list, so do the projection now */
+  igraph_vector_init(&newweights, no_of_edges);
+  IGRAPH_FINALLY(igraph_vector_destroy, &newweights);
+  for (i=0; i<niter; i++) {
+    for (e=0; e<no_of_edges; e++) {
+      int start=VECTOR(eclidx)[e];
+      int end=VECTOR(eclidx)[e+1];
+      VECTOR(newweights)[e]=0.0001;
+      while (start < end) {
+	int clique=VECTOR(ecl)[start++];
+	VECTOR(newweights)[e] += VECTOR(*Mu)[clique];
+      }
+    }
+    for (e=0; e<no_cliques; e++) {
+      igraph_real_t sumratio=0;
+      int start=VECTOR(celidx)[e];
+      int end=VECTOR(celidx)[e+1];
+      while (start < end) {
+	int edge=VECTOR(cel)[start++];
+	sumratio += VECTOR(*weights)[edge] / VECTOR(newweights)[edge];
+      }
+      VECTOR(*Mu)[e] *= sumratio / VECTOR(normfact)[e];
+    }
+  }
+
+  igraph_vector_destroy(&newweights);
+  igraph_vector_destroy(&normfact);
+  igraph_vector_int_destroy(&cel);
+  igraph_vector_int_destroy(&eclidx);
+  igraph_vector_int_destroy(&ecl);
+  igraph_vector_int_destroy(&vcl);
+  igraph_vector_int_destroy(&celidx);
+  igraph_vector_int_destroy(&vclidx);
+  IGRAPH_FINALLY_CLEAN(8);
+
+  return 0;
+}
+
+/**
+ * \function igraph_graphlets_project
+ * Project a graph on a graphlets basis
+ * 
+ * Note that the graph projected does not have to be the same that 
+ * was used to calculate the graphlet basis, but it is assumed that 
+ * it has the same number of vertices, and the vertex ids of the two
+ * graphs match.
+ * \param graph The input graph, it must be a simple graph, edge directions are 
+ *        ignored.
+ * \param weights Weights of the edges in the input graph, a vector.
+ * \param cliques The graphlet basis, a pointer vector, in which each
+ *        element is a vector of vertex ids.
+ * \param Mu An initialized vector, the weights of the graphlets will
+ *        be stored here. This vector is also used to initialize the 
+ *        the weight vector for the iterative algorithm, if the 
+ *        \c startMu argument is true (non-zero).
+ * \param startMu If true (non-zero), then the supplied Mu vector is 
+ *        used as the starting point of the iteration. Otherwise a
+ *        constant 1 vector is used.
+ * \param niter Integer scalar, the number of iterations to perform.
+ * \return Error code.
+ * 
+ * See also: \ref igraph_graphlets() and 
+ * \ref igraph_graphlets_candidate_basis().
+ */
+
+int igraph_graphlets_project(const igraph_t *graph,
+			     const igraph_vector_t *weights,
+			     const igraph_vector_ptr_t *cliques,
+			     igraph_vector_t *Mu, igraph_bool_t startMu,
+			     int niter) {
+
+  return igraph_i_graphlets_project(graph, weights, cliques, Mu, startMu,
+				    niter, /*vid1=*/ 0);
+}
+
+typedef struct igraph_i_graphlets_order_t {
+  const igraph_vector_ptr_t *cliques;
+  const igraph_vector_t *Mu;
+} igraph_i_graphlets_order_t;
+
+int igraph_i_graphlets_order_cmp(void *data, const void *a, const void *b) {
+  igraph_i_graphlets_order_t *ddata=(igraph_i_graphlets_order_t*) data;
+  int *aa=(int*) a;
+  int *bb=(int*) b;
+  igraph_real_t Mu_a = VECTOR(*ddata->Mu)[*aa];
+  igraph_real_t Mu_b = VECTOR(*ddata->Mu)[*bb];
+
+  if (Mu_a < Mu_b) {
+    return 1;
+  } else if (Mu_a > Mu_b) {
+    return -1;
+  } else {
+    return 0;
+  }
+}
+
+/** 
+ * \function igraph_graphlets
+ * Calculate graphlets basis and project the graph on it
+ *
+ * This function simply calls \ref igraph_graphlets_candidate_basis()
+ * and \ref igraph_graphlets_project(), and then orders the graphlets
+ * according to decreasing weights.
+ * \param graph The input graph, it must be a simple graph, edge directions are 
+ *        ignored.
+ * \param weights Weights of the edges, a vector.
+ * \param cliques An initialized vector of pointers. 
+ *        The graphlet basis is stored here. Each element of the pointer 
+ *        vector will be a vector of vertex ids. 
+ * \param Mu An initialized vector, the weights of the graphlets will
+ *        be stored here. 
+ * \param niter Integer scalar, the number of iterations to perform 
+ *        for the projection step.
+ * \return Error code.
+ * 
+ * See also: \ref igraph_graphlets_candidate_basis() and
+ * \ref igraph_graphlets_project().
+ */
+
+int igraph_graphlets(const igraph_t *graph,
+		     const igraph_vector_t *weights,
+		     igraph_vector_ptr_t *cliques,
+		     igraph_vector_t *Mu, int niter) {
+
+  int i, nocliques;
+  igraph_vector_t thresholds;
+  igraph_vector_int_t order;
+  igraph_i_graphlets_order_t sortdata={ cliques, Mu };
+
+  igraph_vector_init(&thresholds, 0);
+  IGRAPH_FINALLY(igraph_vector_destroy, &thresholds);
+  igraph_graphlets_candidate_basis(graph, weights, cliques, &thresholds);
+  igraph_vector_destroy(&thresholds);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_graphlets_project(graph, weights, cliques, Mu, /*startMu=*/ 0, niter);
+
+  nocliques=igraph_vector_ptr_size(cliques);
+  igraph_vector_int_init(&order, nocliques);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &order);
+  for (i=0; i<nocliques; i++) { VECTOR(order)[i]=i; }
+  igraph_qsort_r(VECTOR(order), nocliques, sizeof(int), &sortdata,
+		 igraph_i_graphlets_order_cmp);
+
+  igraph_vector_ptr_index_int(cliques, &order);
+  igraph_vector_index_int(Mu, &order);
+
+  igraph_vector_int_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
diff --git a/src/glpk_support.c b/src/glpk_support.c
new file mode 100644
index 0000000..f2119db
--- /dev/null
+++ b/src/glpk_support.c
@@ -0,0 +1,78 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_GLPK
+
+#include "igraph_types.h"
+#include "igraph_error.h"
+#include "igraph_interrupt_internal.h"
+#include <glpk.h>
+#include <memory.h>
+#include <stdio.h>
+
+void igraph_i_glpk_interruption_hook(glp_tree *tree, void *info) {
+  IGRAPH_UNUSED(tree);
+  IGRAPH_UNUSED(info);
+  IGRAPH_ALLOW_INTERRUPTION_NORETURN();
+}
+
+int igraph_i_glpk_check(int retval, const char* message) {
+  char* code = "none";
+  char message_and_code[4096];
+
+  if (retval == IGRAPH_SUCCESS)
+    return IGRAPH_SUCCESS;
+
+  /* handle errors */
+#define HANDLE_CODE(c) case c: code = #c; retval = IGRAPH_##c; break;
+#define HANDLE_CODE2(c) case c: code = #c; retval = IGRAPH_FAILURE; break;
+  switch (retval) {
+    HANDLE_CODE(GLP_EBOUND);
+    HANDLE_CODE(GLP_EROOT);
+    HANDLE_CODE(GLP_ENOPFS);
+    HANDLE_CODE(GLP_ENODFS);
+    HANDLE_CODE(GLP_EFAIL);
+    HANDLE_CODE(GLP_EMIPGAP);
+    HANDLE_CODE(GLP_ETMLIM);
+    HANDLE_CODE(GLP_ESTOP);
+
+    HANDLE_CODE2(GLP_EBADB);
+    HANDLE_CODE2(GLP_ESING);
+    HANDLE_CODE2(GLP_ECOND);
+    HANDLE_CODE2(GLP_EOBJLL);
+    HANDLE_CODE2(GLP_EOBJUL);
+    HANDLE_CODE2(GLP_EITLIM);
+
+    default:
+      IGRAPH_ERROR("unknown GLPK error", IGRAPH_FAILURE);
+  }
+#undef HANDLE_CODE
+
+  sprintf(message_and_code, "%s (%s)", message, code);
+  IGRAPH_ERROR(message_and_code, retval);
+}
+
+#endif
diff --git a/src/gml_tree.c b/src/gml_tree.c
new file mode 100644
index 0000000..1bcf4fd
--- /dev/null
+++ b/src/gml_tree.c
@@ -0,0 +1,259 @@
+/* 
+   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_gml_tree.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int igraph_gml_tree_init_integer(igraph_gml_tree_t *t, 
+				 const char *name, int namelen,
+				 igraph_integer_t value) {
+
+  igraph_integer_t *p;
+
+  IGRAPH_UNUSED(namelen);
+
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1);
+  IGRAPH_CHECK(igraph_vector_char_init(&t->types, 1));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &t->types);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->children, 1);
+  
+  /* names */
+  VECTOR(t->names)[0] = (void*)name;
+
+  /* types */
+  VECTOR(t->types)[0] = IGRAPH_I_GML_TREE_INTEGER;
+
+  /* children */
+  p=igraph_Calloc(1, igraph_integer_t); 
+  if (!p) { 
+    IGRAPH_ERROR("Cannot create integer GML tree node", IGRAPH_ENOMEM);
+  }
+  *p=value;
+  VECTOR(t->children)[0]=p;
+  
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+int igraph_gml_tree_init_real(igraph_gml_tree_t *t, 
+			      const char *name, int namelen,
+			      igraph_real_t value) {
+
+  igraph_real_t *p;
+
+  IGRAPH_UNUSED(namelen);
+
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1);
+  IGRAPH_CHECK(igraph_vector_char_init(&t->types, 1));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &t->types);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->children, 1);
+  
+  /* names */
+  VECTOR(t->names)[0] = (void*) name;
+
+  /* types */
+  VECTOR(t->types)[0] = IGRAPH_I_GML_TREE_REAL;
+
+  /* children */
+  p=igraph_Calloc(1, igraph_real_t); 
+  if (!p) { 
+    IGRAPH_ERROR("Cannot create real GML tree node", IGRAPH_ENOMEM);
+  }
+  *p=value;
+  VECTOR(t->children)[0]=p;
+  
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+int igraph_gml_tree_init_string(igraph_gml_tree_t *t,
+				const char *name, int namelen,
+				const char *value, int valuelen) {
+
+  IGRAPH_UNUSED(namelen);
+  IGRAPH_UNUSED(valuelen);
+
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1);
+  IGRAPH_CHECK(igraph_vector_char_init(&t->types, 1));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &t->types);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->children, 1);
+
+  /* names */
+  VECTOR(t->names)[0] = (void*) name;
+
+  /* types */
+  VECTOR(t->types)[0] = IGRAPH_I_GML_TREE_STRING;
+
+  /* children */
+  VECTOR(t->children)[0]=(void*)value;
+  
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+int igraph_gml_tree_init_tree(igraph_gml_tree_t *t,
+			      const char *name, int namelen,
+			      igraph_gml_tree_t *value) {
+
+  IGRAPH_UNUSED(namelen);
+
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1);
+  IGRAPH_CHECK(igraph_vector_char_init(&t->types, 1));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &t->types);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->children, 1);
+
+  /* names */
+  VECTOR(t->names)[0] = (void*)name;
+
+  /* types */
+  VECTOR(t->types)[0] = IGRAPH_I_GML_TREE_TREE;
+
+  /* children */
+  VECTOR(t->children)[0]=value;
+
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+  
+}
+
+/* merge is destructive, the _second_ tree is destroyed */
+int igraph_gml_tree_mergedest(igraph_gml_tree_t *t1, igraph_gml_tree_t *t2) {
+  long int i, n=igraph_vector_ptr_size(&t2->children);
+  for (i=0; i<n; i++) {
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(&t1->names, VECTOR(t2->names)[i]));
+    IGRAPH_CHECK(igraph_vector_char_push_back(&t1->types, VECTOR(t2->types)[i]));
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(&t1->children, 
+					     VECTOR(t2->children)[i]));
+  }
+  
+  igraph_vector_ptr_destroy(&t2->names);
+  igraph_vector_char_destroy(&t2->types);
+  igraph_vector_ptr_destroy(&t2->children);
+  return 0;
+}
+
+void igraph_gml_tree_destroy(igraph_gml_tree_t *t) {  
+  
+  long int i, n=igraph_vector_ptr_size(&t->children);
+  for (i=0; i<n; i++) {
+    int type=VECTOR(t->types)[i];
+    switch (type) {
+    case IGRAPH_I_GML_TREE_TREE:
+      igraph_gml_tree_destroy(VECTOR(t->children)[i]);
+      igraph_Free(VECTOR(t->names)[i]);
+      break;
+    case IGRAPH_I_GML_TREE_INTEGER:
+      igraph_Free(VECTOR(t->children)[i]);
+      igraph_Free(VECTOR(t->names)[i]);
+      break;
+    case IGRAPH_I_GML_TREE_REAL:
+      igraph_Free(VECTOR(t->children)[i]);
+      igraph_Free(VECTOR(t->names)[i]);
+      break;
+    case IGRAPH_I_GML_TREE_STRING:
+      igraph_Free(VECTOR(t->children)[i]);
+      igraph_Free(VECTOR(t->names)[i]);
+      break;
+    case IGRAPH_I_GML_TREE_DELETED:
+      break;
+    }
+  }
+  igraph_vector_ptr_destroy(&t->names);
+  igraph_vector_char_destroy(&t->types);
+  igraph_vector_ptr_destroy(&t->children);
+  igraph_Free(t);
+}
+
+long int igraph_gml_tree_length(const igraph_gml_tree_t *t) {
+  return igraph_vector_ptr_size(&t->names);
+}
+
+long int igraph_gml_tree_find(const igraph_gml_tree_t *t,
+			      const char *name, long int from) {
+
+  long int size=igraph_vector_ptr_size(&t->names);
+  while ( from < size && (! VECTOR(t->names)[from] || 
+			  strcmp(VECTOR(t->names)[from], name)) ) {
+    from++;
+  }
+  
+  if (from==size) { from=-1; }
+  return from;
+}
+
+long int igraph_gml_tree_findback(const igraph_gml_tree_t *t,
+				   const char *name, long int from) {
+  while ( from >= 0 && (! VECTOR(t->names)[from] || 
+			strcmp(VECTOR(t->names)[from], name)) ) {
+    from--;
+  }
+  
+  return from;
+}
+
+int igraph_gml_tree_type(const igraph_gml_tree_t *t, long int pos) {
+  return VECTOR(t->types)[pos];
+}
+
+const char *igraph_gml_tree_name(const igraph_gml_tree_t *t, long int pos) {
+  return VECTOR(t->names)[pos];
+}
+
+igraph_integer_t igraph_gml_tree_get_integer(const igraph_gml_tree_t *t, 
+					     long int pos) {
+  igraph_integer_t *i=VECTOR(t->children)[pos];
+  return *i;
+}
+
+igraph_real_t igraph_gml_tree_get_real(const igraph_gml_tree_t *t,
+				       long int pos) {
+  igraph_real_t *d=VECTOR(t->children)[pos];
+  return *d;
+}
+
+const char *igraph_gml_tree_get_string(const igraph_gml_tree_t *t,
+				       long int pos) {
+  const char *s=VECTOR(t->children)[pos];
+  return s;
+}
+
+igraph_gml_tree_t *igraph_gml_tree_get_tree(const igraph_gml_tree_t *t,
+					    long int pos) {
+  igraph_gml_tree_t *tree=VECTOR(t->children)[pos];
+  return tree;
+}
+
+void igraph_gml_tree_delete(igraph_gml_tree_t *t, long int pos) {
+  if (VECTOR(t->types)[pos] == IGRAPH_I_GML_TREE_TREE) {
+    igraph_gml_tree_destroy(VECTOR(t->children)[pos]);
+  }
+  igraph_Free(VECTOR(t->names)[pos]);
+  igraph_Free(VECTOR(t->children)[pos]);
+  VECTOR(t->children)[pos]=0;
+  VECTOR(t->names)[pos]=0;
+  VECTOR(t->types)[pos]=IGRAPH_I_GML_TREE_DELETED;  
+}
diff --git a/src/hacks.c b/src/hacks.c
new file mode 100644
index 0000000..02f059b
--- /dev/null
+++ b/src/hacks.c
@@ -0,0 +1,53 @@
+/* -*- 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 <memory.h>
+#include <string.h>
+#include <stdlib.h>
+#include "igraph_hacks_internal.h"
+
+/* These are implementations of common C functions that may be missing from some
+ * compilers; for instance, icc does not provide stpcpy so we implement it
+ * here. */
+
+/**
+ * Drop-in replacement for strdup.
+ * Used only in compilers that do not have strdup or _strdup
+ */
+char* igraph_i_strdup(const char *s) {
+    size_t n = strlen(s) + 1;
+    char* result = (char*)malloc(sizeof(char) * n);
+    if (result)
+        memcpy(result, s, n);
+    return result;
+}
+
+/**
+ * Drop-in replacement for stpcpy.
+ * Used only in compilers that do not have stpcpy
+ */
+char* igraph_i_stpcpy(char* s1, const char* s2) {
+    char* result = strcpy(s1, s2);
+    return result + strlen(s1);
+}
+
diff --git a/src/heap.c b/src/heap.c
new file mode 100644
index 0000000..1d0929f
--- /dev/null
+++ b/src/heap.c
@@ -0,0 +1,1061 @@
+/* -*- 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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+#include "igraph_math.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+#define PARENT(x)     (((x)+1)/2-1)
+#define LEFTCHILD(x)  (((x)+1)*2-1)
+#define RIGHTCHILD(x) (((x)+1)*2)
+
+/**
+ * \ingroup indheap
+ * \brief Initializes an indexed heap (constructor).
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_indheap_init           (igraph_indheap_t* h, long int alloc_size) {
+ if (alloc_size <= 0 ) { alloc_size=1; }
+ h->stor_begin=igraph_Calloc(alloc_size, igraph_real_t);
+ if (h->stor_begin==0) {
+   h->index_begin=0;
+   IGRAPH_ERROR("indheap init failed", IGRAPH_ENOMEM);
+ }
+ h->index_begin=igraph_Calloc(alloc_size, long int);
+ if (h->index_begin==0) {
+   igraph_Free(h->stor_begin);
+   h->stor_begin=0;
+   IGRAPH_ERROR("indheap init failed", IGRAPH_ENOMEM);
+ }
+ 
+ h->stor_end=h->stor_begin + alloc_size;
+ h->end=h->stor_begin;
+ h->destroy=1;
+ 
+ return 0;  
+}
+
+int igraph_indheap_clear(igraph_indheap_t *h) {
+  h->end=h->stor_begin;
+  return 0;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Initializes and build an indexed heap from a C array (constructor).
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_indheap_init_array     (igraph_indheap_t *h, igraph_real_t* data, long int len) {
+  long int i;
+
+  h->stor_begin=igraph_Calloc(len, igraph_real_t);
+  if (h->stor_begin==0) {
+    h->index_begin=0;
+    IGRAPH_ERROR("indheap init from array failed", IGRAPH_ENOMEM);
+  }
+  h->index_begin=igraph_Calloc(len, long int);
+  if (h->index_begin==0) {
+    igraph_Free(h->stor_begin);
+    h->stor_begin=0;
+    IGRAPH_ERROR("indheap init from array failed", IGRAPH_ENOMEM);
+  }
+  h->stor_end=h->stor_begin+len;
+  h->end=h->stor_end;
+  h->destroy=1;
+
+  memcpy(h->stor_begin, data, (size_t) len*sizeof(igraph_real_t));
+  for (i=0; i<len; i++) {
+    h->index_begin[i]=i+1;
+  }
+
+  igraph_indheap_i_build (h, 0);
+  
+  return 0;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Destroys an initialized indexed heap. 
+ */
+
+void igraph_indheap_destroy        (igraph_indheap_t* h) {  
+  assert(h != 0);
+  if (h->destroy) {
+    if (h->stor_begin != 0) {
+      igraph_Free(h->stor_begin);
+      h->stor_begin=0;
+    }
+    if (h->index_begin != 0) {
+      igraph_Free(h->index_begin);
+      h->index_begin=0;
+    }
+  }
+}
+
+/**
+ * \ingroup indheap
+ * \brief Checks whether a heap is empty.
+ */
+
+igraph_bool_t igraph_indheap_empty          (igraph_indheap_t* h) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  return h->stor_begin == h->end;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Adds an element to an indexed heap.
+ */
+
+int igraph_indheap_push           (igraph_indheap_t* h, igraph_real_t elem) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+	
+  /* full, allocate more storage */
+  if (h->stor_end == h->end) {
+    long int new_size = igraph_indheap_size(h) * 2;
+    if (new_size == 0) { new_size = 1; }
+    IGRAPH_CHECK(igraph_indheap_reserve(h, new_size));
+  }
+	
+  *(h->end) = elem;
+  h->end += 1;
+  *(h->index_begin+igraph_indheap_size(h)-1)=igraph_indheap_size(h)-1;
+
+  /* maintain indheap */
+  igraph_indheap_i_shift_up(h, igraph_indheap_size(h)-1);
+	
+  return 0;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Adds an element to an indexed heap with a given index.
+ */
+
+int igraph_indheap_push_with_index(igraph_indheap_t* h, long int idx, igraph_real_t elem) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+	
+  /* full, allocate more storage */
+  if (h->stor_end == h->end) {
+    long int new_size = igraph_indheap_size(h) * 2;
+    if (new_size == 0) { new_size = 1; }
+    IGRAPH_CHECK(igraph_indheap_reserve(h, new_size));
+  }
+	
+  *(h->end) = elem;
+  h->end += 1;
+  *(h->index_begin+igraph_indheap_size(h)-1)=idx;
+
+  /* maintain indheap */
+  igraph_indheap_i_shift_up(h, igraph_indheap_size(h)-1);
+	
+  return 0;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Modifies an element in an indexed heap.
+ */
+
+int igraph_indheap_modify(igraph_indheap_t* h, long int idx, igraph_real_t elem) {
+  long int i, n;
+
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+
+  n = igraph_indheap_size(h);
+  for (i=0; i<n; i++)
+    if (h->index_begin[i] == idx) {
+	  h->stor_begin[i] = elem;
+	  break;
+	}
+
+  if (i == n) return 0;
+
+  /* maintain indheap */
+  igraph_indheap_i_build(h, 0);
+
+  return 0;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Returns the largest element in an indexed heap.
+ */
+
+igraph_real_t igraph_indheap_max       (igraph_indheap_t* h) {
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+  assert(h->stor_begin != h->end);
+  
+  return h->stor_begin[0];
+}
+
+/**
+ * \ingroup indheap
+ * \brief Removes the largest element from an indexed heap.
+ */
+
+igraph_real_t igraph_indheap_delete_max(igraph_indheap_t* h) {
+  igraph_real_t tmp;
+
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+
+  tmp=h->stor_begin[0];
+  igraph_indheap_i_switch(h, 0, igraph_indheap_size(h)-1);
+  h->end -= 1;
+  igraph_indheap_i_sink(h, 0);
+  
+  return tmp;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Gives the number of elements in an indexed heap.
+ */
+
+long int igraph_indheap_size      (igraph_indheap_t* h) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  return h->end - h->stor_begin;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Reserves more memory for an indexed heap.
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_indheap_reserve        (igraph_indheap_t* h, long int size) {
+  long int actual_size=igraph_indheap_size(h);
+  igraph_real_t *tmp1;
+  long int *tmp2;
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  
+  if (size <= actual_size) { return 0; }
+
+  tmp1=igraph_Calloc(size, igraph_real_t);  
+  if (tmp1==0) {
+    IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp1); 	/* TODO: hack */
+  tmp2=igraph_Calloc(size, long int);
+  if (tmp2==0) {
+    IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp2);
+  memcpy(tmp1, h->stor_begin, (size_t) actual_size*sizeof(igraph_real_t));
+  memcpy(tmp2, h->index_begin, (size_t) actual_size*sizeof(long int));
+  igraph_Free(h->stor_begin);
+  igraph_Free(h->index_begin);
+  
+  h->stor_begin=tmp1;
+  h->index_begin=tmp2;
+  h->stor_end=h->stor_begin + size;
+  h->end=h->stor_begin+actual_size;
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \ingroup indheap
+ * \brief Returns the index of the largest element in an indexed heap.
+ */
+
+long int igraph_indheap_max_index(igraph_indheap_t *h) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  return h->index_begin[0];  
+}
+
+/**
+ * \ingroup indheap
+ * \brief Builds an indexed heap, this function should not be called
+ * directly. 
+ */
+
+void igraph_indheap_i_build(igraph_indheap_t* h, long int head) {
+
+  long int size=igraph_indheap_size(h);
+  if (RIGHTCHILD(head) < size) { 
+    /* both subtrees */
+    igraph_indheap_i_build(h, LEFTCHILD(head) );
+    igraph_indheap_i_build(h, RIGHTCHILD(head));
+    igraph_indheap_i_sink(h, head);
+  } else if (LEFTCHILD(head) < size) {
+    /* only left */
+    igraph_indheap_i_build(h, LEFTCHILD(head));
+    igraph_indheap_i_sink(h, head);
+  } else {
+    /* none */
+  }
+}
+
+/**
+ * \ingroup indheap
+ * \brief Moves an element up in the heap, don't call this function
+ * directly. 
+ */
+
+void igraph_indheap_i_shift_up(igraph_indheap_t *h, long int elem) {
+  
+  if (elem==0 || h->stor_begin[elem] < h->stor_begin[PARENT(elem)]) { 
+    /* at the top */
+  } else {
+    igraph_indheap_i_switch(h, elem, PARENT(elem));
+    igraph_indheap_i_shift_up(h, PARENT(elem));
+  }
+}
+
+/**
+ * \ingroup indheap
+ * \brief Moves an element down in the heap, don't call this function
+ * directly. 
+ */
+
+void igraph_indheap_i_sink(igraph_indheap_t* h, long int head) {
+
+  long int size=igraph_indheap_size(h);
+  if (LEFTCHILD(head) >= size) { 
+    /* no subtrees */
+  } else if (RIGHTCHILD(head) == size ||
+	     h->stor_begin[LEFTCHILD(head)]>=h->stor_begin[RIGHTCHILD(head)]) {
+    /* sink to the left if needed */
+    if (h->stor_begin[head] < h->stor_begin[LEFTCHILD(head)]) {
+      igraph_indheap_i_switch(h, head, LEFTCHILD(head));
+      igraph_indheap_i_sink(h, LEFTCHILD(head));
+    }
+  } else {
+    /* sink to the right */
+    if (h->stor_begin[head] < h->stor_begin[RIGHTCHILD(head)]) {
+      igraph_indheap_i_switch(h, head, RIGHTCHILD(head));
+      igraph_indheap_i_sink(h, RIGHTCHILD(head));
+    }
+  }
+}
+
+/**
+ * \ingroup indheap
+ * \brief Switches two elements in a heap, don't call this function
+ * directly. 
+ */
+
+void igraph_indheap_i_switch(igraph_indheap_t* h, long int e1, long int e2) {
+  if (e1!=e2) {
+    igraph_real_t tmp=h->stor_begin[e1];
+    h->stor_begin[e1]=h->stor_begin[e2];
+    h->stor_begin[e2]=tmp;
+    
+    tmp=h->index_begin[e1];
+    h->index_begin[e1]=h->index_begin[e2];
+    h->index_begin[e2]=(long int) tmp;
+  }
+}
+
+
+/**
+ * \ingroup doubleindheap
+ * \brief Initializes an empty doubly indexed heap object (constructor).
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_d_indheap_init           (igraph_d_indheap_t* h, long int alloc_size) {
+ if (alloc_size <= 0 ) { alloc_size=1; }
+  h->stor_begin=igraph_Calloc(alloc_size, igraph_real_t);
+  if (h->stor_begin==0) {
+    h->index_begin=0;
+    h->index2_begin=0;
+    IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM);
+  }
+  h->stor_end=h->stor_begin + alloc_size;
+  h->end=h->stor_begin;
+  h->destroy=1;
+  h->index_begin=igraph_Calloc(alloc_size, long int);
+  if (h->index_begin==0) {
+    igraph_Free(h->stor_begin);
+    h->stor_begin=0;
+    h->index2_begin=0;
+    IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM);
+  }
+  h->index2_begin=igraph_Calloc(alloc_size, long int);
+  if (h->index2_begin==0) {
+    igraph_Free(h->stor_begin);
+    igraph_Free(h->index_begin);
+    h->stor_begin=0;
+    h->index_begin=0;
+    IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM);
+  }
+  
+  return 0;  
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Destroys an initialized doubly indexed heap object.
+ */
+
+void igraph_d_indheap_destroy        (igraph_d_indheap_t* h) {  
+  assert(h != 0);
+  if (h->destroy) {
+    if (h->stor_begin != 0) {
+      igraph_Free(h->stor_begin);
+      h->stor_begin=0;
+    }
+    if (h->index_begin != 0) {
+      igraph_Free(h->index_begin);
+      h->index_begin=0;
+    }
+    if (h->index2_begin != 0) {
+      igraph_Free(h->index2_begin);
+      h->index2_begin=0;
+    }
+  }
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Decides whether a heap is empty.
+ */
+
+igraph_bool_t igraph_d_indheap_empty          (igraph_d_indheap_t* h) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  return h->stor_begin == h->end;
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Adds an element to the heap.
+ */
+
+int igraph_d_indheap_push           (igraph_d_indheap_t* h, igraph_real_t elem, 
+			      long int idx, long int idx2) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+	
+  /* full, allocate more storage */
+  if (h->stor_end == h->end) {
+    long int new_size = igraph_d_indheap_size(h) * 2;
+    if (new_size == 0) { new_size = 1; }
+    IGRAPH_CHECK(igraph_d_indheap_reserve(h, new_size));
+  }
+	
+  *(h->end) = elem;
+  h->end += 1;
+  *(h->index_begin+igraph_d_indheap_size(h)-1)=idx ;
+  *(h->index2_begin+igraph_d_indheap_size(h)-1)=idx2 ;
+
+  /* maintain d_indheap */
+  igraph_d_indheap_i_shift_up(h, igraph_d_indheap_size(h)-1);
+	
+  return 0;
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Returns the largest element in the heap.
+ */
+
+igraph_real_t igraph_d_indheap_max       (igraph_d_indheap_t* h) {
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+  assert(h->stor_begin != h->end);
+  
+  return h->stor_begin[0];
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Removes the largest element from the heap.
+ */
+
+igraph_real_t igraph_d_indheap_delete_max(igraph_d_indheap_t* h) {
+  igraph_real_t tmp;
+
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+
+  tmp=h->stor_begin[0];
+  igraph_d_indheap_i_switch(h, 0, igraph_d_indheap_size(h)-1);
+  h->end -= 1;
+  igraph_d_indheap_i_sink(h, 0);
+  
+  return tmp;
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Gives the number of elements in the heap.
+ */
+
+long int igraph_d_indheap_size      (igraph_d_indheap_t* h) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  return h->end - h->stor_begin;
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Allocates memory for a heap.
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_d_indheap_reserve        (igraph_d_indheap_t* h, long int size) {
+  long int actual_size=igraph_d_indheap_size(h);
+  igraph_real_t *tmp1;
+  long int *tmp2, *tmp3;
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  
+  if (size <= actual_size) { return 0; }
+
+  tmp1=igraph_Calloc(size, igraph_real_t);
+  if (tmp1==0) {
+    IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp1);	/* TODO: hack */
+  tmp2=igraph_Calloc(size, long int);
+  if (tmp2==0) {
+    IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp2);	/* TODO: hack */
+  tmp3=igraph_Calloc(size, long int);
+  if (tmp3==0) {
+    IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp3); 	/* TODO: hack */
+
+  memcpy(tmp1, h->stor_begin, (size_t) actual_size*sizeof(igraph_real_t));
+  memcpy(tmp2, h->index_begin, (size_t) actual_size*sizeof(long int));
+  memcpy(tmp3, h->index2_begin, (size_t) actual_size*sizeof(long int));
+  igraph_Free(h->stor_begin);
+  igraph_Free(h->index_begin);
+  igraph_Free(h->index2_begin);
+
+  h->stor_begin=tmp1;
+  h->stor_end=h->stor_begin + size;
+  h->end=h->stor_begin+actual_size;
+  h->index_begin=tmp2; 
+  h->index2_begin=tmp3;
+
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Gives the indices of the maximal element in the heap.
+ */
+
+void igraph_d_indheap_max_index(igraph_d_indheap_t *h, long int *idx, long int *idx2) {
+  assert(h != 0);
+  assert(h->stor_begin != 0);
+  (*idx)=h->index_begin[0];
+  (*idx2)=h->index2_begin[0];
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Builds the heap, don't call it directly.
+ */
+
+void igraph_d_indheap_i_build(igraph_d_indheap_t* h, long int head) {
+
+  long int size=igraph_d_indheap_size(h);
+  if (RIGHTCHILD(head) < size) { 
+    /* both subtrees */
+    igraph_d_indheap_i_build(h, LEFTCHILD(head) );
+    igraph_d_indheap_i_build(h, RIGHTCHILD(head));
+    igraph_d_indheap_i_sink(h, head);
+  } else if (LEFTCHILD(head) < size) {
+    /* only left */
+    igraph_d_indheap_i_build(h, LEFTCHILD(head));
+    igraph_d_indheap_i_sink(h, head);
+  } else {
+    /* none */
+  }
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Moves an element up in the heap, don't call it directly.
+ */
+
+void igraph_d_indheap_i_shift_up(igraph_d_indheap_t *h, long int elem) {
+  
+  if (elem==0 || h->stor_begin[elem] < h->stor_begin[PARENT(elem)]) { 
+    /* at the top */
+  } else {
+    igraph_d_indheap_i_switch(h, elem, PARENT(elem));
+    igraph_d_indheap_i_shift_up(h, PARENT(elem));
+  }
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Moves an element down in the heap, don't call it directly.
+ */
+
+void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, long int head) {
+
+  long int size=igraph_d_indheap_size(h);
+  if (LEFTCHILD(head) >= size) { 
+    /* no subtrees */
+  } else if (RIGHTCHILD(head) == size ||
+	     h->stor_begin[LEFTCHILD(head)]>=h->stor_begin[RIGHTCHILD(head)]) {
+    /* sink to the left if needed */
+    if (h->stor_begin[head] < h->stor_begin[LEFTCHILD(head)]) {
+      igraph_d_indheap_i_switch(h, head, LEFTCHILD(head));
+      igraph_d_indheap_i_sink(h, LEFTCHILD(head));
+    }
+  } else {
+    /* sink to the right */
+    if (h->stor_begin[head] < h->stor_begin[RIGHTCHILD(head)]) {
+      igraph_d_indheap_i_switch(h, head, RIGHTCHILD(head));
+      igraph_d_indheap_i_sink(h, RIGHTCHILD(head));
+    }
+  }
+}
+
+/**
+ * \ingroup doubleindheap
+ * \brief Switches two elements in the heap, don't call it directly.
+ */
+
+void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, long int e1, long int e2) {
+  if (e1!=e2) {
+    long int tmpi;
+    igraph_real_t tmp=h->stor_begin[e1];
+    h->stor_begin[e1]=h->stor_begin[e2];
+    h->stor_begin[e2]=tmp;
+    
+    tmpi=h->index_begin[e1];
+    h->index_begin[e1]=h->index_begin[e2];
+    h->index_begin[e2]=tmpi;
+
+    tmpi=h->index2_begin[e1];
+    h->index2_begin[e1]=h->index2_begin[e2];
+    h->index2_begin[e2]=tmpi;
+  }
+}
+
+/*************************************************/
+
+#undef PARENT
+#undef LEFTCHILD
+#undef RIGHTCHILD
+#define PARENT(x)     ((x)/2)
+#define LEFTCHILD(x)  ((x)*2+1)
+#define RIGHTCHILD(x) ((x)*2)
+#define INACTIVE      IGRAPH_INFINITY
+#define UNDEFINED     0.0
+#define INDEXINC      1
+
+void igraph_i_cutheap_switch(igraph_i_cutheap_t *ch, 
+			    long int hidx1, long int hidx2) {
+  if (hidx1 != hidx2) {
+    long int idx1=(long int) VECTOR(ch->index)[hidx1];
+    long int idx2=(long int) VECTOR(ch->index)[hidx2];
+
+    igraph_real_t tmp=VECTOR(ch->heap)[hidx1];
+    VECTOR(ch->heap)[hidx1]=VECTOR(ch->heap)[hidx2];
+    VECTOR(ch->heap)[hidx2]=tmp;
+    
+    VECTOR(ch->index)[hidx1]=idx2;
+    VECTOR(ch->index)[hidx2]=idx1;
+    
+    VECTOR(ch->hptr)[idx1] = hidx2+INDEXINC;
+    VECTOR(ch->hptr)[idx2] = hidx1+INDEXINC;
+  }
+}
+
+void igraph_i_cutheap_sink(igraph_i_cutheap_t *ch, long int hidx) {
+  long int size=igraph_vector_size(&ch->heap);
+  if (LEFTCHILD(hidx) >= size) {
+    /* leaf node */
+  } else if (RIGHTCHILD(hidx) == size ||
+	     VECTOR(ch->heap)[LEFTCHILD(hidx)] >= 
+	     VECTOR(ch->heap)[RIGHTCHILD(hidx)]) {
+    /* sink to the left if needed */
+    if (VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[LEFTCHILD(hidx)]) {
+      igraph_i_cutheap_switch(ch, hidx, LEFTCHILD(hidx));
+      igraph_i_cutheap_sink(ch, LEFTCHILD(hidx));
+    }
+  } else {
+    /* sink to the right */
+    if (VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[RIGHTCHILD(hidx)]) {
+      igraph_i_cutheap_switch(ch, hidx, RIGHTCHILD(hidx));
+      igraph_i_cutheap_sink(ch, RIGHTCHILD(hidx));
+    }
+  }
+}
+
+void igraph_i_cutheap_shift_up(igraph_i_cutheap_t *ch, long int hidx) {
+  if (hidx==0 || VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[PARENT(hidx)]) {
+    /* at the top */
+  } else {
+    igraph_i_cutheap_switch(ch, hidx, PARENT(hidx));
+    igraph_i_cutheap_shift_up(ch, PARENT(hidx));
+  }
+}
+
+int igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_integer_t nodes) {
+  ch->dnodes=nodes;
+  IGRAPH_VECTOR_INIT_FINALLY(&ch->heap, nodes);	/* all zero */
+  IGRAPH_CHECK(igraph_vector_init_seq(&ch->index, 0, nodes-1));
+  IGRAPH_FINALLY(igraph_vector_destroy, &ch->index);
+  IGRAPH_CHECK(igraph_vector_init_seq(&ch->hptr, INDEXINC, nodes+INDEXINC-1));  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+void igraph_i_cutheap_destroy(igraph_i_cutheap_t *ch) {
+  igraph_vector_destroy(&ch->hptr);
+  igraph_vector_destroy(&ch->index);
+  igraph_vector_destroy(&ch->heap);
+}
+
+igraph_bool_t igraph_i_cutheap_empty(igraph_i_cutheap_t *ch) {
+  return igraph_vector_empty(&ch->heap);
+}
+
+/* Number of active vertices */
+
+igraph_integer_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch) {
+  return (igraph_integer_t) igraph_vector_size(&ch->heap);
+}
+
+/* Number of all (defined) vertices */
+
+igraph_integer_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch) {
+  return (igraph_integer_t) (ch->dnodes);
+}
+
+igraph_real_t igraph_i_cutheap_maxvalue(igraph_i_cutheap_t *ch) {
+  return VECTOR(ch->heap)[0];
+}
+
+igraph_integer_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch) {
+  long int size=igraph_vector_size(&ch->heap);
+  igraph_integer_t maxindex=(igraph_integer_t) VECTOR(ch->index)[0];
+  /* put the last element to the top */
+  igraph_i_cutheap_switch(ch, 0, size-1);
+  /* remove the last element */
+  VECTOR(ch->hptr)[(long int) igraph_vector_tail(&ch->index)] = INACTIVE;
+  igraph_vector_pop_back(&ch->heap);
+  igraph_vector_pop_back(&ch->index);
+  igraph_i_cutheap_sink(ch, 0);
+  
+  return maxindex;
+}
+
+/* Update the value of an active vertex, if not active it will be ignored */
+
+int igraph_i_cutheap_update(igraph_i_cutheap_t *ch, igraph_integer_t index,
+			    igraph_real_t add) {
+  igraph_real_t hidx=VECTOR(ch->hptr)[(long int)index];
+  if (hidx != INACTIVE && hidx != UNDEFINED) {
+    long int hidx2=(long int) (hidx-INDEXINC);
+/*     printf("updating vertex %li, heap index %li\n", (long int) index, hidx2); */
+    VECTOR(ch->heap)[hidx2] += add;
+    igraph_i_cutheap_sink(ch, hidx2);
+    igraph_i_cutheap_shift_up(ch, hidx2);
+  }
+  return 0;
+}
+
+/* Reset the value of all vertices to zero and make them active */
+
+int igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, long int vertex) {
+  long int i, j, n=igraph_vector_size(&ch->hptr);
+  /* undefine */
+  VECTOR(ch->hptr)[vertex] = UNDEFINED;
+  ch->dnodes -= 1;
+
+  IGRAPH_CHECK(igraph_vector_resize(&ch->heap, ch->dnodes));
+  igraph_vector_null(&ch->heap);
+
+  IGRAPH_CHECK(igraph_vector_resize(&ch->index, ch->dnodes));
+
+  j=0;
+  for (i=0; i<n; i++) {
+    if (VECTOR(ch->hptr)[i] != UNDEFINED) {
+      VECTOR(ch->index)[j]=i;
+      VECTOR(ch->hptr)[i]=j+INDEXINC;
+      j++;
+    }
+  }
+	     
+  return 0;
+}
+
+/* -------------------------------------------------- */
+/* Two-way indexed heap                               */
+/* -------------------------------------------------- */
+
+#undef PARENT
+#undef LEFTCHILD
+#undef RIGHTCHILD
+#define PARENT(x)     (((x)+1)/2-1)
+#define LEFTCHILD(x)  (((x)+1)*2-1)
+#define RIGHTCHILD(x) (((x)+1)*2)
+
+/* This is a smart indexed heap. In addition to the "normal" indexed heap
+   it allows to access every element through its index in O(1) time. 
+   In other words, for this heap the indexing operation is O(1), the 
+   normal heap does this in O(n) time.... */
+
+void igraph_i_2wheap_switch(igraph_2wheap_t *h,
+			    long int e1, long int e2) {
+  if (e1 != e2) {
+    long int tmp1, tmp2;
+    igraph_real_t tmp3=VECTOR(h->data)[e1];
+    VECTOR(h->data)[e1]=VECTOR(h->data)[e2];
+    VECTOR(h->data)[e2]=tmp3;
+
+    tmp1=VECTOR(h->index)[e1];
+    tmp2=VECTOR(h->index)[e2];
+    
+    VECTOR(h->index2)[tmp1]=e2+2;
+    VECTOR(h->index2)[tmp2]=e1+2;
+
+    VECTOR(h->index)[e1]=tmp2;
+    VECTOR(h->index)[e2]=tmp1;
+  }
+}
+
+void igraph_i_2wheap_shift_up(igraph_2wheap_t *h, 
+			      long int elem) {
+  if (elem==0 || VECTOR(h->data)[elem] < VECTOR(h->data)[PARENT(elem)]) {
+    /* at the top */
+  } else {
+    igraph_i_2wheap_switch(h, elem, PARENT(elem));
+    igraph_i_2wheap_shift_up(h, PARENT(elem));
+  }
+}
+
+void igraph_i_2wheap_sink(igraph_2wheap_t *h,
+			  long int head) {
+  long int size=igraph_2wheap_size(h);
+  if (LEFTCHILD(head) >= size) {
+    /* no subtrees */
+  } else if (RIGHTCHILD(head) == size ||
+	     VECTOR(h->data)[LEFTCHILD(head)]>=VECTOR(h->data)[RIGHTCHILD(head)]) {
+    /* sink to the left if needed */
+    if (VECTOR(h->data)[head] < VECTOR(h->data)[LEFTCHILD(head)]) {
+      igraph_i_2wheap_switch(h, head, LEFTCHILD(head));
+      igraph_i_2wheap_sink(h, LEFTCHILD(head));
+    }
+  } else {
+    /* sink to the right */
+    if (VECTOR(h->data)[head] < VECTOR(h->data)[RIGHTCHILD(head)]) {
+      igraph_i_2wheap_switch(h, head, RIGHTCHILD(head));
+      igraph_i_2wheap_sink(h, RIGHTCHILD(head));
+    }
+  }
+}
+
+/* ------------------ */
+/* These are public   */
+/* ------------------ */
+
+int igraph_2wheap_init(igraph_2wheap_t *h, long int size) {
+  h->size=size;
+  /* We start with the biggest */
+  IGRAPH_CHECK(igraph_vector_long_init(&h->index2, size));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &h->index2);
+  IGRAPH_VECTOR_INIT_FINALLY(&h->data, 0);
+  IGRAPH_CHECK(igraph_vector_long_init(&h->index, 0));
+/* IGRAPH_FINALLY(igraph_vector_long_destroy, &h->index); */
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+void igraph_2wheap_destroy(igraph_2wheap_t *h) {
+  igraph_vector_destroy(&h->data);
+  igraph_vector_long_destroy(&h->index);
+  igraph_vector_long_destroy(&h->index2);
+}
+
+int igraph_2wheap_clear(igraph_2wheap_t *h) {
+  igraph_vector_clear(&h->data);
+  igraph_vector_long_clear(&h->index);
+  igraph_vector_long_null(&h->index2);
+  return 0;
+}
+
+igraph_bool_t igraph_2wheap_empty(const igraph_2wheap_t *h) {
+  return igraph_vector_empty(&h->data);
+}
+
+int igraph_2wheap_push_with_index(igraph_2wheap_t *h, 
+				  long int idx, igraph_real_t elem) {
+
+/*   printf("-> %.2g [%li]\n", elem, idx); */
+
+  long int size=igraph_vector_size(&h->data);
+  IGRAPH_CHECK(igraph_vector_push_back(&h->data, elem));
+  IGRAPH_CHECK(igraph_vector_long_push_back(&h->index, idx));
+  VECTOR(h->index2)[idx] = size+2;
+  
+  /* maintain heap */
+  igraph_i_2wheap_shift_up(h, size);
+  return 0;
+}
+
+long int igraph_2wheap_size(const igraph_2wheap_t *h) {
+  return igraph_vector_size(&h->data);
+}
+
+long int igraph_2wheap_max_size(const igraph_2wheap_t *h) {
+  return h->size;
+}
+
+igraph_real_t igraph_2wheap_max(const igraph_2wheap_t *h) {
+  return VECTOR(h->data)[0];
+}
+
+long int igraph_2wheap_max_index(const igraph_2wheap_t *h) {
+  return VECTOR(h->index)[0];
+}
+
+igraph_bool_t igraph_2wheap_has_elem(const igraph_2wheap_t *h, long int idx) {
+  return VECTOR(h->index2)[idx] != 0;
+}
+
+igraph_bool_t igraph_2wheap_has_active(const igraph_2wheap_t *h, long int idx) {
+  return VECTOR(h->index2)[idx] > 1;
+}
+
+igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, long int idx) {
+  long int i=VECTOR(h->index2)[idx]-2;
+  return VECTOR(h->data)[i];
+}
+
+igraph_real_t igraph_2wheap_delete_max(igraph_2wheap_t *h) {
+  
+  igraph_real_t tmp=VECTOR(h->data)[0];
+  long int tmpidx=VECTOR(h->index)[0];
+  igraph_i_2wheap_switch(h, 0, igraph_2wheap_size(h)-1);
+  igraph_vector_pop_back(&h->data);
+  igraph_vector_long_pop_back(&h->index);
+  VECTOR(h->index2)[tmpidx] = 0;
+  igraph_i_2wheap_sink(h, 0);
+
+/*   printf("<-max %.2g\n", tmp); */
+  
+  return tmp;
+}
+
+igraph_real_t igraph_2wheap_deactivate_max(igraph_2wheap_t *h) {
+  
+  igraph_real_t tmp=VECTOR(h->data)[0];
+  long int tmpidx=VECTOR(h->index)[0];
+  igraph_i_2wheap_switch(h, 0, igraph_2wheap_size(h)-1);
+  igraph_vector_pop_back(&h->data);
+  igraph_vector_long_pop_back(&h->index);
+  VECTOR(h->index2)[tmpidx] = 1;
+  igraph_i_2wheap_sink(h, 0);
+
+  return tmp;
+}
+
+igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, long int *idx) {
+
+  igraph_real_t tmp=VECTOR(h->data)[0];
+  long int tmpidx=VECTOR(h->index)[0];
+  igraph_i_2wheap_switch(h, 0, igraph_2wheap_size(h)-1);
+  igraph_vector_pop_back(&h->data);
+  igraph_vector_long_pop_back(&h->index);
+  VECTOR(h->index2)[tmpidx] = 0;
+  igraph_i_2wheap_sink(h, 0);
+  
+  if (idx) { *idx=tmpidx; }
+  return tmp;
+}
+
+int igraph_2wheap_modify(igraph_2wheap_t *h, long int idx, igraph_real_t elem) {
+  
+  long int pos=VECTOR(h->index2)[idx]-2;
+
+/*   printf("-- %.2g -> %.2g\n", VECTOR(h->data)[pos], elem); */
+  
+  VECTOR(h->data)[pos] = elem;
+  igraph_i_2wheap_sink(h, pos);
+  igraph_i_2wheap_shift_up(h, pos);
+  
+  return 0;
+}
+
+/* Check that the heap is in a consistent state */
+
+int igraph_2wheap_check(igraph_2wheap_t *h) {
+  long int size=igraph_2wheap_size(h);
+  long int i;
+  igraph_bool_t error=0;
+
+  /* Check the heap property */
+  for (i=0; i<size; i++) {
+    if (LEFTCHILD(i) >= size) { break; }
+    if (VECTOR(h->data)[LEFTCHILD(i)] > VECTOR(h->data)[i]) {
+      error=1; break;
+    }
+    if (RIGHTCHILD(i) >= size) { break; }
+    if (VECTOR(h->data)[RIGHTCHILD(i)] > VECTOR(h->data)[i]) { 
+      error=1; break;
+    }
+  }
+  
+  if (error) { 
+    IGRAPH_ERROR("Inconsistent heap", IGRAPH_EINTERNAL);
+  }
+
+  return 0;
+}
diff --git a/src/heap.pmt b/src/heap.pmt
new file mode 100644
index 0000000..5460a28
--- /dev/null
+++ b/src/heap.pmt
@@ -0,0 +1,345 @@
+/* -*- 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_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+#define PARENT(x)     (((x)+1)/2-1)
+#define LEFTCHILD(x)  (((x)+1)*2-1)
+#define RIGHTCHILD(x) (((x)+1)*2)
+  
+/**
+ * \ingroup heap
+ * \function igraph_heap_init
+ * \brief Initializes an empty heap object.
+ *
+ * Creates an empty heap, but allocates size for some elements.
+ * \param h Pointer to an uninitialized heap object.
+ * \param alloc_size Number of elements to allocate memory for.
+ * \return Error code.
+ * 
+ * Time complexity: O(\p alloc_size), assuming memory allocation is a
+ * linear operation.
+ */
+
+int FUNCTION(igraph_heap,init)(TYPE(igraph_heap)* h, long int alloc_size) {
+  if (alloc_size <= 0 ) { alloc_size=1; }
+  h->stor_begin=igraph_Calloc(alloc_size, BASE);
+  if (h->stor_begin==0) {
+    IGRAPH_ERROR("heap init failed", IGRAPH_ENOMEM);
+  }
+  h->stor_end=h->stor_begin + alloc_size;
+  h->end=h->stor_begin;
+  h->destroy=1;
+  
+  return 0;  
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_init_array
+ * \brief Build a heap from an array.
+ * 
+ * Initializes a heap object from an array, the heap is also
+ * built of course (constructor).
+ * \param h Pointer to an uninitialized heap object.
+ * \param data Pointer to an array of base data type.
+ * \param len The length of the array at \p data.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of elements in the heap.
+ */
+
+int FUNCTION(igraph_heap,init_array)(TYPE(igraph_heap) *h, BASE* data, long int len) {
+  h->stor_begin=igraph_Calloc(len, BASE);
+  if (h->stor_begin==0) {
+    IGRAPH_ERROR("heap init from array failed", IGRAPH_ENOMEM);
+  }
+  h->stor_end=h->stor_begin+len;
+  h->end=h->stor_end;
+  h->destroy=1;
+
+  memcpy(h->stor_begin, data, (size_t) len*sizeof(igraph_real_t));
+
+  FUNCTION(igraph_heap,i_build) (h->stor_begin, h->end-h->stor_begin, 0);
+  
+  return 0;
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_destroy
+ * \brief Destroys an initialized heap object.
+ * 
+ * \param h The heap object.
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_heap,destroy)(TYPE(igraph_heap)* h) {  
+  if (h->destroy) {
+    if (h->stor_begin != 0) {
+      igraph_Free(h->stor_begin);
+      h->stor_begin=0;
+    }
+  }
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_empty
+ * \brief Decides whether a heap object is empty.
+ * 
+ * \param h The heap object.
+ * \return \c TRUE if the heap is empty, \c FALSE otherwise.
+ * 
+ * TIme complexity: O(1).
+ */
+
+igraph_bool_t FUNCTION(igraph_heap,empty)(TYPE(igraph_heap)* h) {
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+  return h->stor_begin == h->end;
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_push
+ * \brief Add an element.
+ * 
+ * Adds an element to the heap.
+ * \param h The heap object.
+ * \param elem The element to add.
+ * \return Error code.
+ * 
+ * Time complexity: O(log n), n is the number of elements in the
+ * heap if no reallocation is needed, O(n) otherwise. It is ensured
+ * that n push operations are performed in O(n log n) time.
+ */
+
+int FUNCTION(igraph_heap,push)(TYPE(igraph_heap)* h, BASE elem) {
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+	
+  /* full, allocate more storage */
+  if (h->stor_end == h->end) {
+    long int new_size = FUNCTION(igraph_heap,size)(h) * 2;
+    if (new_size == 0) { new_size = 1; }
+    IGRAPH_CHECK(FUNCTION(igraph_heap,reserve)(h, new_size));
+  }
+	
+  *(h->end) = elem;
+  h->end += 1;
+
+  /* maintain heap */
+  FUNCTION(igraph_heap,i_shift_up)(h->stor_begin, FUNCTION(igraph_heap,size)(h),
+				   FUNCTION(igraph_heap,size)(h)-1);
+  
+  return 0;
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_top
+ * \brief Top element.
+ * 
+ * For maximum heaps this is the largest, for minimum heaps the
+ * smallest element of the heap.
+ * \param h The heap object.
+ * \return The top element.
+ *
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_heap,top)(TYPE(igraph_heap)* h) {
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+  assert(h->stor_begin != h->end);
+  
+  return h->stor_begin[0];
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_delete_top
+ * \brief Return and removes the top element
+ * 
+ * Removes and returns the top element of the heap. For maximum heaps
+ * this is the largest, for minimum heaps the smallest element.
+ * \param h The heap object.
+ * \return The top element.
+ * 
+ * Time complexity: O(log n), n is the number of elements in the
+ * heap.
+ */
+
+BASE FUNCTION(igraph_heap,delete_top)(TYPE(igraph_heap)* h) {
+  BASE tmp;
+
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+
+  tmp=h->stor_begin[0];
+  FUNCTION(igraph_heap,i_switch)(h->stor_begin, 0, FUNCTION(igraph_heap,size)(h)-1);
+  h->end -= 1;
+  FUNCTION(igraph_heap,i_sink)(h->stor_begin, h->end-h->stor_begin, 0);
+  
+  return tmp;
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_size
+ * \brief Number of elements
+ * 
+ * Gives the number of elements in a heap.
+ * \param h The heap object.
+ * \return The number of elements in the heap.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_heap,size)(TYPE(igraph_heap)* h) {
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+  return h->end - h->stor_begin;
+}
+
+/**
+ * \ingroup heap
+ * \function igraph_heap_reserve
+ * \brief Allocate more memory
+ *
+ * Allocates memory for future use. The size of the heap is
+ * unchanged. If the heap is larger than the \p size parameter then
+ * nothing happens.
+ * \param h The heap object.
+ * \param size The number of elements to allocate memory for.
+ * \return Error code.
+ * 
+ * Time complexity: O(\p size) if \p size is larger than the current
+ * number of elements. O(1) otherwise.
+ */
+
+int FUNCTION(igraph_heap,reserve)(TYPE(igraph_heap)* h, long int size) {
+  long int actual_size=FUNCTION(igraph_heap,size)(h);
+  BASE *tmp;
+  assert(h != NULL);
+  assert(h->stor_begin != NULL);
+  
+  if (size <= actual_size) { return 0; }
+  
+  tmp=igraph_Realloc(h->stor_begin, (size_t) size, BASE);
+  if (tmp==0) {
+    IGRAPH_ERROR("heap reserve failed", IGRAPH_ENOMEM);
+  }
+  h->stor_begin=tmp;
+  h->stor_end=h->stor_begin + size;
+  h->end=h->stor_begin+actual_size;
+  
+  return 0;
+}
+
+/**
+ * \ingroup heap
+ * \brief Build a heap, this should not be called directly.
+ */
+
+void FUNCTION(igraph_heap,i_build)(BASE* arr, 
+				   long int size, long int head) {
+
+  if (RIGHTCHILD(head) < size) { 
+    /* both subtrees */
+    FUNCTION(igraph_heap,i_build)(arr, size, LEFTCHILD(head) );
+    FUNCTION(igraph_heap,i_build)(arr, size, RIGHTCHILD(head));
+    FUNCTION(igraph_heap,i_sink)(arr, size, head);
+  } else if (LEFTCHILD(head) < size) {
+    /* only left */
+    FUNCTION(igraph_heap,i_build)(arr, size, LEFTCHILD(head));
+    FUNCTION(igraph_heap,i_sink)(arr, size, head);
+  } else {
+    /* none */
+  }
+}
+
+/**
+ * \ingroup heap
+ * \brief Shift an element upwards in a heap, this should not be
+ * called directly.
+ */
+
+void FUNCTION(igraph_heap,i_shift_up)(BASE* arr, long int size, long int elem) {
+  
+  if (elem==0 || arr[elem] HEAPLESS arr[PARENT(elem)]) { 
+    /* at the top */
+  } else {
+    FUNCTION(igraph_heap,i_switch)(arr, elem, PARENT(elem));
+    FUNCTION(igraph_heap,i_shift_up)(arr, size, PARENT(elem));
+  }
+}
+
+/**
+ * \ingroup heap
+ * \brief Moves an element down in a heap, this function should not be
+ * called directly.
+ */
+
+void FUNCTION(igraph_heap,i_sink)(BASE* arr, long int size, long int head) {
+
+  if (LEFTCHILD(head) >= size) { 
+    /* no subtrees */
+  } else if (RIGHTCHILD(head) == size ||
+	     arr[LEFTCHILD(head)] HEAPMOREEQ arr[RIGHTCHILD(head)]) {
+    /* sink to the left if needed */
+    if (arr[head] HEAPLESS arr[LEFTCHILD(head)]) {
+      FUNCTION(igraph_heap,i_switch)(arr, head, LEFTCHILD(head));
+      FUNCTION(igraph_heap,i_sink)(arr, size, LEFTCHILD(head));
+    }
+  } else {
+    /* sink to the right */
+    if (arr[head] HEAPLESS arr[RIGHTCHILD(head)]) {
+      FUNCTION(igraph_heap,i_switch)(arr, head, RIGHTCHILD(head));
+      FUNCTION(igraph_heap,i_sink)(arr, size, RIGHTCHILD(head));
+    }
+  }
+}
+
+/**
+ * \ingroup heap
+ * \brief Switches two elements in a heap, this function should not be
+ * called directly.
+ */
+
+void FUNCTION(igraph_heap,i_switch)(BASE* arr, long int e1, long int e2) {
+  if (e1!=e2) {
+    BASE tmp=arr[e1];
+    arr[e1]=arr[e2];
+    arr[e2]=tmp;
+  }
+}
diff --git a/src/hrg_dendro.h b/src/hrg_dendro.h
new file mode 100644
index 0000000..0d75c3e
--- /dev/null
+++ b/src/hrg_dendro.h
@@ -0,0 +1,302 @@
+/* -*- 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
+
+*/
+
+// ****************************************************************************************************
+// *** COPYRIGHT NOTICE *******************************************************************************
+// dendro_eq.h - hierarchical random graph (hrg) data structure
+// Copyright (C) 2006-2008 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ****************************************************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu | http://www.santafe.edu/~aaronc/ )
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science AND Santa Fe Institute
+// Created      : 19 April 2006
+// Modified     : 19 May 2007
+//			 : 19 May 2008 (cleaned up for public consumption)
+//
+// ****************************************************************************************************
+// 
+// Maximum likelihood dendrogram data structure. This is the heart of the HRG algorithm: all
+// manipulations are done here and all data is stored here. The data structure uses the separate
+// graph data structure to store the basic adjacency information (in a dangerously mutable way).
+//
+// Note: This version (dendro_eq.h) differs from other versions because it includes methods for 
+//       doing the consensus dendrogram calculation.
+// 
+// ****************************************************************************************************
+
+#ifndef IGRAPH_HRG_DENDRO
+#define IGRAPH_HRG_DENDRO
+
+#include <iostream>
+#include <fstream>
+#include <cstdio>
+#include <cmath>
+
+#include "hrg_graph.h"
+#include "hrg_rbtree.h"
+#include "hrg_splittree_eq.h"
+
+#include "igraph_hrg.h"
+
+using namespace std;
+using namespace fitHRG;
+
+namespace fitHRG {
+
+// ***********************************************************************
+// ******** Basic Structures *********************************************
+
+#ifndef IGRAPH_HRG_LIST
+#define IGRAPH_HRG_LIST
+
+class list {
+public:
+  int x;			// stored elementd in linked-list
+  list*	next;			// pointer to next elementd
+  list::list(): x(-1), next(0) { }
+  list::~list() { }
+};
+#endif
+
+enum {DENDRO, GRAPH, LEFT, RIGHT};
+struct block { double x; int y; };
+struct ipair { int    x; int y; short int t; string sp; };
+struct child { int index; short int type; child* next; };
+
+// ***********************************************************************
+// ******** Cnode Class **************************************************
+
+#ifndef IGRAPH_HRG_CNODE
+#define IGRAPH_HRG_CNODE
+class cnode {
+public:
+  int index;			// array index of this node
+  int degree;			// number of children in list
+  int parent;			// index of parent node
+  double weight;		// sampled posterior weight
+  child* children;		// list of children (and their types)
+  child* lastChild;		// pointer to last child in list
+  cnode(): index(-1), degree(0), parent(-1), weight(0.0), 
+	   children(0), lastChild(0)  { }
+  ~cnode() {
+    child *curr, *prev;
+    curr = children;
+    while (curr != NULL) {
+      prev = curr;
+      curr = curr->next;
+      delete prev;
+      prev = NULL;
+    }
+    lastChild = NULL;
+  }
+};
+#endif
+
+// ***********************************************************************
+// ******** Split Class **************************************************
+
+class split {
+ public:
+  string s;		      // partition assignment of leaf vertices
+  split(): s("") { }
+  ~split() { }
+  void initializeSplit(const int n) { 
+    s = ""; 
+    for (int i=0; i<n; i++) { s += "-"; } 
+  }
+  bool checkSplit() { 
+    if (s.empty() || s.find("-",0) != string::npos) { 
+      return false; 
+    } else { 
+      return true; 
+    } 
+  }
+};
+
+// ***********************************************************************
+// ******** Internal Edge Class ******************************************
+// The usefulness of this data structure is to provide an easy to way
+// maintain the set of internal edges, and the corresponding splits,
+// in the dendrogram D. It allows for the selection of a random
+// internal edge in O(1) time, and it takes O(1) time to update its
+// structure given an internal move. This structure does not provide
+// any means to directly manipulate the splits, but does allow them to
+// be replaced. A split has the form "int.int...int#int.int...int",
+// where all ints on the left side of the # are in the left partition
+// and all ints on the right side of the # marker are in the right
+// partition defined by the split.
+
+class interns {
+private: 
+  ipair* edgelist;   // list of internal edges represented
+  string* splitlist; // split representation of the internal edges
+  int** indexLUT;    // table of indices of internal edges in edgelist
+  int q;	     // number of internal edges
+  int count;         // (for adding edges) edgelist index of new edge to add
+public:
+  interns(const int); 
+  ~interns();
+  
+  // add an internal edge, O(1)  
+  bool addEdge(const int, const int, const short int);
+  // returns the ith edge of edgelist, O(1)
+  ipair* getEdge(const int);
+  // returns a uniformly random internal edge, O(1)
+  ipair* getRandomEdge();
+  // returns the ith split of the splitlist, O(1)
+  string getSplit(const int); 
+  // replace an existing split, O(1)
+  bool replaceSplit(const int, const string);
+  // swaps two edges, O(1)
+  bool swapEdges(const int, const int, const short int, const int, 
+		 const int, const short int);
+};
+
+// ***********************************************************************
+// ******** Tree elementd Class ******************************************
+
+class elementd {
+public:
+  short int type; // either DENDRO or GRAPH
+  double logL;	  // log-likelihood contribution of this internal node
+  double p;       // probability p_i that an edge exists between L and
+		  // R subtrees 
+  int e;	  // number of edges between L and R subtrees
+  int n;	  // number of leafs in subtree rooted here
+  int label;	  // subtree label: smallest leaf index
+  int index;	  // index in containing array
+  
+  elementd *M;			// pointer to parent node
+  elementd *L;			// pointer for L subtree
+  elementd *R;			// pointer for R subtree
+
+  elementd(): type(DENDRO), logL(0.0), p(0.0), e(0), n(0), 
+	      label(-1), index(-1), M(0), L(0), R(0) { }
+  ~elementd() { }
+};
+
+// ***********************************************************************
+// ******** Dendrogram Class *********************************************
+
+class dendro {
+private:
+  elementd* root;     // root of the dendrogram
+  elementd* internal; // array of n-1 internal vertices (the dendrogram D)
+  elementd* leaf;     // array of n   leaf vertices (the graph G)
+  int n;	      // number of leaf vertices to allocate
+  interns* d;	      // list of internal edges of dendrogram D
+  splittree* splithist;	      // histogram of cumulative split weights
+  list** paths;		      // array of path-lists from root to leaf
+  double L;	       // log-likelihood of graph G given dendrogram D
+  rbtree subtreeL, subtreeR;  // trees for computeEdgeCount() function
+  cnode* ctree;	      // (consensus tree) array of internal tree nodes
+  int* cancestor;     // (consensus tree) oldest ancetor's index for
+		      // each leaf
+
+  // insert node i according to binary search property
+  void binarySearchInsert(elementd*, elementd*); 
+  // return path to root from leaf
+  list* binarySearchFind(const double);
+  // build split for this internal edge  
+  string buildSplit(elementd*);
+  // compute number of edges between two internal subtrees
+  int computeEdgeCount(const int, const short int, const int, 
+		       const short int);
+  // (consensus tree) counts children
+  int countChildren(const string);
+  // find internal node of D that is common ancestor of i,j
+  elementd* findCommonAncestor(list**, const int, const int);
+  // return reverse of path to leaf from root
+  list* reversePathToRoot(const int);
+// quicksort functions 
+  void QsortMain(block*, int, int); 
+  int QsortPartition(block*, int, int, int);
+
+public:
+  // underlying G (dangerously accessible)
+  graph* g;
+  
+  // constructor / destructor
+  dendro(); ~dendro();
+  // build dendrogram from g
+  void buildDendrogram();
+  // delete dendrograph in prep for importDendrogramStructure	
+  void clearDendrograph(); 
+  // read dendrogram structure from HRG structure
+  bool importDendrogramStructure(const igraph_hrg_t *hrg); 
+  // (consensus tree) delete splits with less than 0.5 weight
+  void cullSplitHist(); 
+  // return size of consensus split
+  int getConsensusSize(); 
+  // return split tree with consensus splits
+  splittree* getConsensusSplits();
+  // return likelihood of G given D
+  double getLikelihood(); 
+  // store splits in this splittree
+  void getSplitList(splittree*); 
+  // return total weight of splittree
+  double getSplitTotalWeight(); 
+  // make random G from D
+  void makeRandomGraph();
+  // make single MCMC move
+  bool monteCarloMove(double&, bool&, const double);
+  // record consensus tree from splithist
+  void recordConsensusTree(igraph_vector_t *parents, 
+			   igraph_vector_t *weights);
+  // record D structure
+  void recordDendrogramStructure(igraph_hrg_t *hrg);
+  // record G structure to igraph graph
+  void recordGraphStructure(igraph_t *graph); 
+  // force refresh of log-likelihood value
+  void refreshLikelihood(); 
+  // sample dendrogram edge likelihoods and update edge histograms
+  void sampleAdjacencyLikelihoods(); 
+  // reset the dendrograph structures
+  void resetDendrograph();
+  // sample dendrogram's splits and update the split histogram
+  bool sampleSplitLikelihoods(int&);
+  // reset splits histogram
+  void resetAllSplits();
+};
+
+} // namespace fitHRG
+
+#endif
diff --git a/src/hrg_graph.h b/src/hrg_graph.h
new file mode 100644
index 0000000..b7d3fc5
--- /dev/null
+++ b/src/hrg_graph.h
@@ -0,0 +1,167 @@
+/* -*- 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
+
+*/
+
+// ****************************************************************************************************
+// *** COPYRIGHT NOTICE *******************************************************************************
+// graph.h - graph data structure for hierarchical random graphs
+// Copyright (C) 2005-2008 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ****************************************************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu | http://www.santafe.edu/~aaronc/ )
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science AND Santa Fe Institute
+// Created      : 8 November 2005
+// Modified     : 23 December 2007 (cleaned up for public consumption)
+//
+// ****************************************************************************************************
+// 
+// Graph data structure for hierarchical random graphs. The basic structure is an adjacency list of
+// edges; however, many additional pieces of metadata are stored as well. Each node stores its
+// external name, its degree and (if assigned) its group index.
+// 
+// ****************************************************************************************************
+
+#ifndef IGRAPH_HRG_GRAPH
+#define IGRAPH_HRG_GRAPH
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include "hrg_rbtree.h"
+
+using namespace std;
+
+namespace fitHRG {
+
+// ******** Basic Structures *********************************************
+
+#ifndef IGRAPH_HRG_EDGE
+#define IGRAPH_HRG_EDGE
+class edge {
+public:
+  int x;		    // stored integer value  (edge terminator)
+  double* h;		    // (histogram) weights of edge existence
+  double total_weight;	    // (histogram) total weight observed
+  int obs_count;	    // number of observations in histogram
+  edge* next;		    // pointer to next elementd
+  edge(): x(-1), h(0), total_weight(0.0), obs_count(0), next(0)  { }
+ ~edge() { 
+   if (h != NULL) { delete [] h; }
+   h = NULL; 
+ }
+};
+#endif
+
+#ifndef IGRAPH_HRG_VERT
+#define IGRAPH_HRG_VERT
+class vert {
+public:
+ string name;			// (external) name of vertex
+ int degree;			// degree of this vertex
+
+  vert(): name(""), degree(0) { }
+ ~vert() { }
+};
+#endif
+
+// ******** Graph Class with Edge Statistics *****************************
+
+class graph {
+public:
+  graph(const int, bool predict=false);
+ ~graph();
+
+  // add (i,j) to graph
+  bool addLink(const int, const int);
+  // add weight to (i,j)'s histogram
+  bool addAdjacencyObs(const int, const int, const double, const double);
+  // add to obs_count and total_weight
+  void addAdjacencyEnd();
+  // true if (i,j) is already in graph
+  bool doesLinkExist(const int, const int);
+  // returns degree of vertex i
+  int getDegree(const int);
+  // returns name of vertex i
+  string getName(const int);
+  // returns edge list of vertex i
+  edge* getNeighborList(const int);
+  // return ptr to histogram of edge (i,j)
+  double* getAdjacencyHist(const int, const int);
+  // return average value of adjacency A(i,j)
+  double getAdjacencyAverage(const int, const int);
+  // returns bin_resolution
+  double getBinResolution();
+  // returns num_bins
+  int getNumBins();
+  // returns m
+  int numLinks();
+  // returns n
+  int numNodes();
+  // returns total_weight
+  double getTotalWeight();
+  // reset edge (i,j)'s histogram
+  void resetAdjacencyHistogram(const int, const int);
+  // reset all edge histograms
+  void resetAllAdjacencies();
+  // clear all links from graph
+  void resetLinks();
+  // allocate edge histograms
+  void setAdjacencyHistograms(const int);
+  // set name of vertex i
+  bool setName(const int, const string);
+
+private:
+  bool predict;		 // do we need prediction?
+  vert* nodes;		 // list of nodes
+  edge** nodeLink;	 // linked list of neighbors to vertex
+  edge** nodeLinkTail;	 // pointers to tail of neighbor list
+  double*** A;		 // stochastic adjacency matrix for this graph
+  int obs_count;	 // number of observations in A
+  double total_weight;	 // total weight added to A
+  int n;		 // number of vertices
+  int m;		 // number of directed edges
+  int num_bins;		 // number of bins in edge histograms
+  double bin_resolution; // width of histogram bin
+};
+
+} // namespace fitHRG
+
+#endif
diff --git a/src/hrg_graph_simp.h b/src/hrg_graph_simp.h
new file mode 100644
index 0000000..a6d4822
--- /dev/null
+++ b/src/hrg_graph_simp.h
@@ -0,0 +1,162 @@
+/* -*- 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
+
+*/
+
+// ****************************************************************************************************
+// *** COPYRIGHT NOTICE *******************************************************************************
+// graph_simp.h - graph data structure
+// Copyright (C) 2006-2008 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ****************************************************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu | http://www.santafe.edu/~aaronc/ )
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science AND Santa Fe Institute
+// Created      : 21 June 2006
+// Modified     : 23 December 2007 (cleaned up for public consumption)
+//
+// ************************************************************************
+// 
+// Simple graph data structure. The basic structure is an adjacency
+// list of edges, along with degree information for the vertices.
+// 
+// ************************************************************************
+
+#ifndef IGRAPH_HRG_SIMPLEGRAPH
+#define IGRAPH_HRG_SIMPLEGRAPH
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include "hrg_rbtree.h"
+
+using namespace std;
+
+namespace fitHRG {
+
+// ******** Basic Structures *********************************************
+
+#ifndef IGRAPH_HRG_SIMPLEEDGE
+#define IGRAPH_HRG_SIMPLEEDGE
+class simpleEdge {
+public:
+  int x;			// index of edge terminator
+  simpleEdge* next;		// pointer to next elementd
+
+  simpleEdge(): x(-1), next(0) { }
+  ~simpleEdge() { }
+};
+#endif
+
+#ifndef IGRAPH_HRG_SIMPLEVERT
+#define IGRAPH_HRG_SIMPLEVERT
+class simpleVert {
+public:
+  string name;			// (external) name of vertex
+  int degree;			// degree of this vertex
+  int group_true;		// index of vertex's true group
+ 
+  simpleVert(): name(""), degree(0), group_true(-1) { }
+  ~simpleVert() { }
+};
+#endif
+
+#ifndef IGRAPH_HRG_TWOEDGE
+#define IGRAPH_HRG_TWOEDGE
+class twoEdge {
+public:
+  int o;			// index of edge originator
+  int x;			// index of edge terminator
+ 
+  twoEdge(): o(-1), x(-1) { }
+  ~twoEdge() { }
+};
+#endif
+
+// ******** Graph Class with Edge Statistics *****************************
+
+class simpleGraph {
+public:
+  simpleGraph(const int); ~simpleGraph();
+
+  // add group label to vertex i
+  bool addGroup(const int, const int);
+  // add (i,j) to graph
+  bool addLink(const int, const int);
+  // true if (i,j) is already in graph
+  bool doesLinkExist(const int, const int);
+  // returns A(i,j)
+  double getAdjacency(const int, const int);
+  // returns degree of vertex i
+  int getDegree(const int);
+  // returns group label of vertex i
+  int getGroupLabel(const int);
+  // returns name of vertex i
+  string getName(const int);
+  // returns edge list of vertex i
+  simpleEdge* getNeighborList(const int);
+  // return pointer to a node
+  simpleVert* getNode(const int);
+  // returns num_groups
+  int getNumGroups();
+  // returns m
+  int getNumLinks();
+  // returns n
+  int getNumNodes();
+  // set name of vertex i
+  bool setName(const int, const string);
+
+private:
+  simpleVert* nodes;		// list of nodes
+  simpleEdge** nodeLink;	// linked list of neighbors to vertex
+  simpleEdge** nodeLinkTail;	// pointers to tail of neighbor list
+  double** A;			// adjacency matrix for this graph
+  twoEdge* E;			// list of all edges (array)
+  int n;			// number of vertices
+  int m;			// number of directed edges
+  int num_groups;		// number of bins in node histograms
+
+  // quicksort functions
+  void QsortMain(block*, int, int); 
+  int QsortPartition(block*, int, int, int);
+};
+
+} // namespace fitHRG
+
+#endif
diff --git a/src/hrg_rbtree.h b/src/hrg_rbtree.h
new file mode 100644
index 0000000..9cf9c87
--- /dev/null
+++ b/src/hrg_rbtree.h
@@ -0,0 +1,164 @@
+/* -*- 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
+
+*/
+
+// ****************************************************************************************************
+// *** COPYRIGHT NOTICE *******************************************************************************
+// rbtree - red-black tree (self-balancing binary tree data structure)
+// Copyright (C) 2004 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ****************************************************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu | http://www.santafe.edu/~aaronc/ )
+// Collaborators: Cristopher Moore and Mark Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science AND Santa Fe Institute
+// Created      : Spring 2004
+// Modified     : many, many times
+//
+// ****************************************************************************************************
+
+#ifndef IGRAPH_HRG_RBTREE
+#define IGRAPH_HRG_RBTREE
+
+#include <iostream>
+
+using namespace std;
+
+namespace fitHRG {
+
+// ******** Basic Structures *********************************************
+
+#ifndef IGRAPH_HRG_LIST
+#define IGRAPH_HRG_LIST
+
+class list {
+public:
+  int x;			// stored elementd in linked-list
+  list*	next;			// pointer to next elementd
+  list(): x(-1), next(0) { }
+  ~list() { }
+};
+#endif
+
+class keyValuePair {
+public:
+  int x;			// elementrb key (int)
+  int y;			// stored value (int)
+  keyValuePair*	next;		// linked-list pointer
+  keyValuePair(): x(-1), y(-1), next(0) { }
+  ~keyValuePair() { }
+};
+
+// ******** Tree elementrb Class *****************************************
+
+class elementrb {
+public:
+  int key;			// search key (int)
+  int value;			// stored value (int)
+ 
+  bool color;			// F: BLACK, T: RED
+  short int mark;		// marker
+ 
+  elementrb *parent;		// pointer to parent node
+  elementrb *left;		// pointer for left subtree
+  elementrb *right;		// pointer for right subtree
+ 
+  elementrb(): key(-1), value(-1), color(false), mark(0), parent(0),
+	       left(0), right(0) { }
+  ~elementrb() { }
+};
+
+// ******** Red-Black Tree Class *****************************************
+// This vector implementation is a red-black balanced binary tree data
+// structure. It provides find a stored elementrb in time O(log n),
+// find the maximum elementrb in time O(1), delete an elementrb in
+// time O(log n), and insert an elementrb in time O(log n). 
+//
+// Note that the key=0 is assumed to be a special value, and thus you
+// cannot insert such an item. Beware of this limitation.
+
+class rbtree {
+private:
+  elementrb* root;		// binary tree root
+  elementrb* leaf;		// all leaf nodes
+  int support;			// number of nodes in the tree
+
+  void rotateLeft(elementrb *x);    // left-rotation operator
+  void rotateRight(elementrb *y);   // right-rotation operator
+  void insertCleanup(elementrb *z); // house-keeping after insertion
+  void deleteCleanup(elementrb *x); // house-keeping after deletion
+  keyValuePair* returnSubtreeAsList(elementrb *z, keyValuePair *head);
+  void deleteSubTree(elementrb *z); // delete subtree rooted at z
+  elementrb* returnMinKey(elementrb *z); // returns minimum of subtree
+					 // rooted at z 
+  elementrb* returnSuccessor(elementrb *z); // returns successor of z's key
+ 
+public:
+  rbtree(); ~rbtree(); // default constructor/destructor
+
+  // returns value associated with searchKey
+  int returnValue(const int searchKey); 
+  // returns T if searchKey found, and points foundNode at the
+  // corresponding node 
+  elementrb* findItem(const int searchKey); 
+  // insert a new key with stored value
+  void insertItem(int newKey, int newValue);
+  // selete a node with given key
+  void deleteItem(int killKey);
+  // replace value of a node with given key
+  void replaceItem(int key, int newValue);
+  // increment the value of the given key
+  void incrementValue(int key);
+  // delete the entire tree
+  void deleteTree();
+  // return array of keys in tree
+  int* returnArrayOfKeys();
+  // return list of keys in tree
+  list* returnListOfKeys();
+  // return the tree as a list of keyValuePairs
+  keyValuePair* returnTreeAsList();
+  // returns the maximum key in the tree
+  keyValuePair returnMaxKey();
+  // returns the minimum key in the tree
+  keyValuePair returnMinKey();
+  // returns number of items in tree
+  int returnNodecount();
+};
+
+}
+#endif
diff --git a/src/hrg_splittree_eq.h b/src/hrg_splittree_eq.h
new file mode 100644
index 0000000..c038ecd
--- /dev/null
+++ b/src/hrg_splittree_eq.h
@@ -0,0 +1,185 @@
+/* -*- 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
+
+*/
+
+// ****************************************************************************************************
+// *** COPYRIGHT NOTICE *******************************************************************************
+// splittree_eq.h - a binary search tree data structure for storing dendrogram split frequencies
+// Copyright (C) 2006-2008 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ****************************************************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu | http://www.santafe.edu/~aaronc/ )
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science AND Santa Fe Institute
+// Created      : 19 April 2006
+// Modified     : 19 May 2007
+//			 : 20 May 2008 (cleaned up for public consumption)
+//
+// ***********************************************************************
+// 
+// Data structure for storing the split frequences in the sampled
+// dendrograms. Data is stored efficiently as a red-black binary
+// search tree (this is a modified version of the rbtree.h file).
+//
+// ***********************************************************************
+
+#ifndef IGRAPH_HRG_SPLITTREE
+#define IGRAPH_HRG_SPLITTREE
+
+#include <iostream>
+
+using namespace std;
+
+namespace fitHRG {
+
+// ******** Basic Structures *********************************************
+
+#ifndef IGRAPH_HRG_SLIST
+#define IGRAPH_HRG_SLIST
+class slist {
+public:
+  string x;			// stored elementd in linked-list
+  slist* next;			// pointer to next elementd
+  slist(): x(""), next(0) { }
+  ~slist() { }
+};
+#endif
+
+class keyValuePairSplit {
+public:
+  string x;			// elementsp split (string)
+  double y;			// stored weight   (double)
+  int c;			// stored count    (int)
+  keyValuePairSplit* next;	// linked-list pointer
+  keyValuePairSplit(): x(""), y(0.0), c(0), next(0) { }
+  ~keyValuePairSplit() { }
+};
+
+// ******** Tree elementsp Class *****************************************
+
+class elementsp {
+public:
+  string split;		        // split represented as a string
+  double weight;	        // total weight of this split
+  int count;		        // number of observations of this split
+ 
+  bool color;			// F: BLACK, T: RED
+  short int mark;		// marker
+
+  elementsp *parent;		// pointer to parent node
+  elementsp *left;		// pointer for left subtree
+  elementsp *right;		// pointer for right subtree
+ 
+  elementsp(): split(""), weight(0.0), count(0), color(false), mark(0),
+	       parent(0), left(0), right(0) { }
+  ~elementsp() { }
+};
+
+// ******** Red-Black Tree Class *****************************************
+// This vector implementation is a red-black balanced binary tree data
+// structure. It provides find a stored elementsp in time O(log n),
+// find the maximum elementsp in time O(1), delete an elementsp in
+// time O(log n), and insert an elementsp in time O(log n). 
+//
+// Note that the split="" is assumed to be a special value, and thus
+// you cannot insert such an item. Beware of this limitation.
+//
+
+class splittree {
+private:
+  elementsp* root;		// binary tree root
+  elementsp* leaf;		// all leaf nodes
+  int support;			// number of nodes in the tree
+  double total_weight;		// total weight stored
+  int total_count;		// total number of observations stored
+
+  // left-rotation operator
+  void rotateLeft(elementsp*);
+  // right-rotation operator
+  void rotateRight(elementsp*);
+  // house-keeping after insertion
+  void insertCleanup(elementsp*);
+  // house-keeping after deletion
+  void deleteCleanup(elementsp*);
+  keyValuePairSplit* returnSubtreeAsList(elementsp*, keyValuePairSplit*);
+  // delete subtree rooted at z
+  void deleteSubTree(elementsp*);
+  // returns minimum of subtree rooted at z
+  elementsp* returnMinKey(elementsp*);
+  // returns successor of z's key
+  elementsp* returnSuccessor(elementsp*);
+ 
+public:
+  // default constructor/destructor
+  splittree(); ~splittree();
+  // returns value associated with searchKey
+  double returnValue(const string);
+  // returns T if searchKey found, and points foundNode at the
+  // corresponding node 
+  elementsp* findItem(const string);
+  // update total_count and total_weight
+  void finishedThisRound();
+  // insert a new key with stored value
+  bool insertItem(string, double);
+  void clearTree();
+  // delete a node with given key
+  void deleteItem(string);
+  // delete the entire tree
+  void deleteTree();
+  // return array of keys in tree
+  string* returnArrayOfKeys();
+  // return list of keys in tree
+  slist* returnListOfKeys();
+  // return the tree as a list of keyValuePairSplits
+  keyValuePairSplit* returnTreeAsList();
+  // returns the maximum key in the tree
+  keyValuePairSplit returnMaxKey();
+  // returns the minimum key in the tree
+  keyValuePairSplit returnMinKey();
+  // returns number of items in tree
+  int returnNodecount();
+  // returns list of splits with given number of Ms
+  keyValuePairSplit* returnTheseSplits(const int);
+  // returns sum of stored values
+  double returnTotal();
+};
+
+} // namespace fitHRG
+
+#endif
diff --git a/src/igraph_arpack_internal.h b/src/igraph_arpack_internal.h
new file mode 100644
index 0000000..6316af5
--- /dev/null
+++ b/src/igraph_arpack_internal.h
@@ -0,0 +1,219 @@
+/* -*- 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 ARPACK_INTERNAL_H
+#define ARPACK_INTERNAL_H
+
+/* Note: only files calling the arpack routines directly need to
+   include this header.
+*/
+
+#include "igraph_types.h"
+#include "config.h"
+
+#ifndef INTERNAL_ARPACK
+#define igraphdsaupd_	dsaupd_
+#define igraphdseupd_	dseupd_
+#define igraphdsaup2_	dsaup2_
+#define igraphdstats_	dstats_
+#define igraphdsesrt_	dsesrt_
+#define igraphdsortr_	dsortr_
+#define igraphdsortc_   dsortc_
+#define igraphdgetv0_	dgetv0_
+#define igraphdsaitr_	dsaitr_
+#define igraphdsapps_	dsapps_
+#define igraphdsconv_	dsconv_
+#define igraphdseigt_	dseigt_
+#define igraphdsgets_	dsgets_
+#define igraphdstqrb_	dstqrb_
+#define igraphdmout_	dmout_
+#define igraphivout_	ivout_
+#define igraphsecond_	second_
+#define igraphdvout_	dvout_
+#define igraphdnaitr_   dnaitr_
+#define igraphdnapps_   dnapps_
+#define igraphdnaup2_   dnaup2_
+#define igraphdnaupd_   dnaupd_
+#define igraphdnconv_   dnconv_
+#define igraphdlabad_   dlabad_
+#define igraphdlanhs_   dlanhs_
+#define igraphdsortc_   dsortc_
+#define igraphdneigh_   dneigh_
+#define igraphdngets_   dngets_
+#define igraphdstatn_   dstatn_
+#define igraphdlaqrb_   dlaqrb_
+
+#define igraphdsaupd_   dsaupd_
+#define igraphdseupd_   dseupd_
+#define igraphdnaupd_   dnaupd_
+#define igraphdneupd_   dneupd_
+#endif
+
+#ifndef INTERNAL_LAPACK
+#define igraphdlarnv_	dlarnv_
+#define igraphdlascl_	dlascl_
+#define igraphdlartg_	dlartg_
+#define igraphdlaset_	dlaset_
+#define igraphdlae2_	dlae2_
+#define igraphdlaev2_	dlaev2_
+#define igraphdlasr_	dlasr_
+#define igraphdlasrt_	dlasrt_
+#define igraphdgeqr2_	dgeqr2_
+#define igraphdlacpy_	dlacpy_
+#define igraphdorm2r_	dorm2r_
+#define igraphdsteqr_	dsteqr_
+#define igraphdlanst_	dlanst_
+#define igraphdlapy2_	dlapy2_
+#define igraphdlamch_	dlamch_
+#define igraphdlaruv_	dlaruv_
+#define igraphdlarfg_	dlarfg_
+#define igraphdlarf_	dlarf_
+#define igraphdlassq_	dlassq_
+#define igraphdlamc2_	dlamc2_
+#define igraphdlamc1_	dlamc1_
+#define igraphdlamc2_	dlamc2_
+#define igraphdlamc3_	dlamc3_
+#define igraphdlamc4_	dlamc4_
+#define igraphdlamc5_	dlamc5_
+#define igraphdlabad_   dlabad_
+#define igraphdlanhs_   dlanhs_
+#define igraphdtrevc_   dtrevc_
+#define igraphdlanv2_   dlanv2_
+#define igraphdlaln2_   dlaln2_
+#define igraphdladiv_   dladiv_
+#define igraphdtrsen_   dtrsen_
+#define igraphdlahqr_   dlahqr_
+#define igraphdtrsen_   dtrsen_
+#define igraphdlacon_   dlacon_
+#define igraphdtrsyl_   dtrsyl_
+#define igraphdtrexc_   dtrexc_
+#define igraphdlange_   dlange_
+#define igraphdlaexc_   dlaexc_
+#define igraphdlasy2_   dlasy2_
+#define igraphdlarfx_   dlarfx_
+#endif
+
+#if 0				/* internal f2c functions always used */
+#define igraphd_sign	d_sign
+#define igraphetime_	etime_
+#define igraphpow_dd	pow_dd
+#define igraphpow_di	pow_di
+#define igraphs_cmp	s_cmp
+#define igraphs_copy	s_copy
+#define igraphd_lg10_   d_lg10_
+#define igraphi_dnnt_   i_dnnt_
+#endif
+
+#ifdef HAVE_GFORTRAN
+
+int igraphdsaupd_(int *ido, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr,
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info,
+		  int bmat_len, int which_len);
+
+int igraphdseupd_(int *rvec, char *howmny, int *select,
+		  igraph_real_t *d, igraph_real_t *z, int *ldz,
+		  igraph_real_t *sigma, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr,
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info,
+		  int howmny_len, int bmat_len, int which_len);
+
+int igraphdnaupd_(int *ido, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr,
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info,
+		  int bmat_len, int which_len);
+
+int igraphdneupd_(int *rvec, char *howmny, int *select,
+		  igraph_real_t *dr, igraph_real_t *di,
+		  igraph_real_t *z, int *ldz,
+		  igraph_real_t *sigmar, igraph_real_t *sigmai,
+		  igraph_real_t *workev, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr,
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info,
+		  int howmny_len, int bmat_len, int which_len);
+
+int igraphdsortr_(char *which, int *apply, int* n, igraph_real_t *x1,
+		  igraph_real_t *x2,
+		  int which_len);
+
+int igraphdsortc_(char *which, int *apply, int* n, igraph_real_t *xreal,
+		  igraph_real_t *ximag, igraph_real_t *y,
+		  int which_len);
+
+#else
+
+int igraphdsaupd_(int *ido, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr, 
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info);
+
+int igraphdseupd_(int *rvec, char *howmny, int *select,
+		  igraph_real_t *d, igraph_real_t *z, int *ldz,
+		  igraph_real_t *sigma, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr, 
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info);
+
+int igraphdnaupd_(int *ido, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr, 
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info);
+
+int igraphdneupd_(int *rvec, char *howmny, int *select,
+		  igraph_real_t *dr, igraph_real_t *di,
+		  igraph_real_t *z, int *ldz,
+		  igraph_real_t *sigmar, igraph_real_t *sigmai, 
+		  igraph_real_t *workev, char *bmat, int *n,
+		  char *which, int *nev, igraph_real_t *tol,
+		  igraph_real_t *resid, int *ncv, igraph_real_t *v,
+		  int *ldv, int *iparam, int *ipntr, 
+		  igraph_real_t *workd, igraph_real_t *workl,
+		  int *lworkl, int *info);
+
+int igraphdsortr_(char *which, int *apply, int* n, igraph_real_t *x1,
+		  igraph_real_t *x2);
+
+int igraphdsortc_(char *which, int *apply, int* n, igraph_real_t *xreal,
+		  igraph_real_t *ximag, igraph_real_t *y);
+
+#endif
+
+#endif	/* ARPACK_INTERNAL_H */
diff --git a/src/igraph_blas_internal.h b/src/igraph_blas_internal.h
new file mode 100644
index 0000000..06fa4a9
--- /dev/null
+++ b/src/igraph_blas_internal.h
@@ -0,0 +1,55 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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_INTERNAL_H
+#define BLAS_INTERNAL_H
+
+/* Note: only files calling the BLAS routines directly need to
+   include this header.
+*/
+
+#include "igraph_types.h"
+#include "config.h"
+
+#ifndef INTERNAL_BLAS
+#define igraphdaxpy_	daxpy_
+#define igraphdger_	dger_
+#define igraphdcopy_	dcopy_
+#define igraphdscal_	dscal_
+#define igraphdswap_	dswap_
+#define igraphdgemv_	dgemv_
+#define igraphddot_	ddot_
+#define igraphdnrm2_	dnrm2_
+#define igraphlsame_	lsame_
+#define igraphdrot_     drot_
+#define igraphidamax_   idamax_
+#define igraphdtrmm_    dtrmm_
+#define igraphdasum_    dasum_
+#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);
+
+#endif
diff --git a/src/igraph_buckets.c b/src/igraph_buckets.c
new file mode 100644
index 0000000..9d0b2f2
--- /dev/null
+++ b/src/igraph_buckets.c
@@ -0,0 +1,190 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_types.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+
+#include <stdio.h>
+
+/* The igraph_buckets_t data structure can store at most 'size' 
+ * unique integers in 'bsize' buckets. It has the following simple 
+ * operations (in addition to _init() and _destroy():
+ * - _add() adding an element to the given bucket.
+ * - _popmax() removing an element from the bucket with the highest
+ *   id.
+ *   Currently buckets work as stacks, last-in-first-out mode.
+ * - _empty() queries whether the buckets is empty.
+ * 
+ * Internal representation: we use a vector to create single linked
+ * lists, and another vector that points to the starting element of
+ * each bucket. Zero means the end of the chain. So bucket i contains
+ * elements bptr[i], buckets[bptr[i]], buckets[buckets[bptr[i]]],
+ * etc., until a zero is found. 
+ * 
+ * We also keep the total number of elements in the buckets and the
+ * id of the non-empty bucket with the highest id, to facilitate the
+ * _empty() and _popmax() operations.
+ */ 
+
+int igraph_buckets_init(igraph_buckets_t *b, long int bsize, long int size) {
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&b->bptr, bsize);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&b->buckets, size);
+  b->max=-1; b->no=0;
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+void igraph_buckets_destroy(igraph_buckets_t *b) {
+  igraph_vector_long_destroy(&b->bptr);
+  igraph_vector_long_destroy(&b->buckets);
+}
+
+long int igraph_buckets_popmax(igraph_buckets_t *b) {
+  /* Precondition: there is at least a non-empty bucket */
+  /* Search for the highest bucket first */
+  long int max;
+  while ( (max=(long int) VECTOR(b->bptr)[(long int) b->max]) == 0) {
+    b->max --;
+  }
+  VECTOR(b->bptr)[(long int) b->max] = VECTOR(b->buckets)[max-1];
+  b->no--;
+
+  return max-1;
+}
+
+long int igraph_buckets_pop(igraph_buckets_t *b, long int bucket) {
+  long int ret=VECTOR(b->bptr)[bucket]-1;
+  VECTOR(b->bptr)[bucket] = VECTOR(b->buckets)[ret];
+  b->no--;  
+  return ret;
+} 
+
+igraph_bool_t igraph_buckets_empty(const igraph_buckets_t *b) {
+  return (b->no == 0);
+}
+
+igraph_bool_t igraph_buckets_empty_bucket(const igraph_buckets_t *b, 
+					  long int bucket) {
+  return VECTOR(b->bptr)[bucket] == 0;
+}
+
+void igraph_buckets_add(igraph_buckets_t *b, long int bucket,
+			long int elem) {
+  
+  VECTOR(b->buckets)[(long int) elem] = VECTOR(b->bptr)[(long int) bucket];
+  VECTOR(b->bptr)[(long int) bucket] = elem+1;
+  if (bucket > b->max) {
+    b->max = (int) bucket;
+  }
+  b->no++;
+}
+
+void igraph_buckets_clear(igraph_buckets_t *b) {
+  igraph_vector_long_null(&b->bptr);
+  igraph_vector_long_null(&b->buckets);
+  b->max = -1; 
+  b->no = 0;
+}
+
+int igraph_dbuckets_init(igraph_dbuckets_t *b, long int bsize, long int size) {
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&b->bptr, bsize);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&b->next, size);
+  IGRAPH_VECTOR_LONG_INIT_FINALLY(&b->prev, size);  
+  b->max=-1; b->no=0;
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+void igraph_dbuckets_destroy(igraph_dbuckets_t *b) {
+  igraph_vector_long_destroy(&b->bptr);
+  igraph_vector_long_destroy(&b->next);
+  igraph_vector_long_destroy(&b->prev);
+}
+
+void igraph_dbuckets_clear(igraph_dbuckets_t *b) {
+  igraph_vector_long_null(&b->bptr);
+  igraph_vector_long_null(&b->next);
+  igraph_vector_long_null(&b->prev);
+  b->max = -1; 
+  b->no = 0;
+}
+
+long int igraph_dbuckets_popmax(igraph_dbuckets_t *b) {
+  long int max;
+  while ( (max=(long int) VECTOR(b->bptr)[(long int) b->max]) == 0) {
+    b->max --;
+  }
+  return igraph_dbuckets_pop(b, b->max);
+}
+
+long int igraph_dbuckets_pop(igraph_dbuckets_t *b, long int bucket) {
+  long int ret=VECTOR(b->bptr)[bucket]-1;
+  long int next=VECTOR(b->next)[ret];
+  VECTOR(b->bptr)[bucket] = next;
+  if (next != 0) { VECTOR(b->prev)[next-1] = 0; }
+
+  b->no--;
+  return ret;
+}
+
+igraph_bool_t igraph_dbuckets_empty(const igraph_dbuckets_t *b) {
+  return (b->no == 0);
+}
+
+igraph_bool_t igraph_dbuckets_empty_bucket(const igraph_dbuckets_t *b, 
+					   long int bucket) {
+  return VECTOR(b->bptr)[bucket] == 0;
+}
+
+void igraph_dbuckets_add(igraph_dbuckets_t *b, long int bucket,
+			 long int elem) {
+  long int oldfirst=VECTOR(b->bptr)[bucket];
+  VECTOR(b->bptr)[bucket] = elem+1;
+  VECTOR(b->next)[elem] = oldfirst;
+  if (oldfirst != 0) {
+    VECTOR(b->prev)[oldfirst-1] = elem+1;
+  }
+  if (bucket > b->max) {
+    b->max = (int) bucket;
+  }
+  b->no++;
+}
+
+/* Remove an arbitrary element */
+
+void igraph_dbuckets_delete(igraph_dbuckets_t *b, long int bucket,
+			    long int elem) {
+  if (VECTOR(b->bptr)[bucket] == elem+1) {
+    /* First element in bucket */
+    long int next=VECTOR(b->next)[elem];
+    if (next != 0) { VECTOR(b->prev)[next-1] = 0; }
+    VECTOR(b->bptr)[bucket] = next;
+  } else {
+    long int next=VECTOR(b->next)[elem];
+    long int prev=VECTOR(b->prev)[elem];
+    if (next != 0) { VECTOR(b->prev)[next-1] = prev; }
+    if (prev != 0) { VECTOR(b->next)[prev-1] = next; }
+  }
+  b->no--;
+}
diff --git a/src/igraph_error.c b/src/igraph_error.c
new file mode 100644
index 0000000..b32a662
--- /dev/null
+++ b/src/igraph_error.c
@@ -0,0 +1,285 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "config.h"
+#include "igraph_error.h"
+#include "igraph_types.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+
+static IGRAPH_THREAD_LOCAL igraph_error_handler_t *igraph_i_error_handler=0;
+static IGRAPH_THREAD_LOCAL char igraph_i_errormsg_buffer[500];
+static IGRAPH_THREAD_LOCAL char igraph_i_warningmsg_buffer[500];
+
+static const char *igraph_i_error_strings[]=
+  { /*  0 */ "No error",
+    /*  1 */ "Failed",
+    /*  2 */ "Out of memory",
+    /*  3 */ "Parse error",
+    /*  4 */ "Invalid value",
+    /*  5 */ "Already exists",
+    /*  6 */ "Invalid edge vector",
+    /*  7 */ "Invalid vertex id",
+    /*  8 */ "Non-square matrix",
+    /*  9 */ "Invalid mode",
+    /* 10 */ "File operation error",
+    /* 11 */ "Unfold infinite iterator",
+    /* 12 */ "Unimplemented function call",
+    /* 13 */ "Interrupted",
+    /* 14 */ "Numeric procedure did not converge",
+    /* 15 */ "Matrix-vector product failed",
+    /* 16 */ "N must be positive", 
+    /* 17 */ "NEV must be positive",
+    /* 18 */ "NCV must be greater than NEV and less than or equal to N "
+             "(and for the non-symmetric solver NCV-NEV >=2 must also hold)",
+    /* 19 */ "Maximum number of iterations should be positive",
+    /* 20 */ "Invalid WHICH parameter",
+    /* 21 */ "Invalid BMAT parameter",
+    /* 22 */ "WORKL is too small",
+    /* 23 */ "LAPACK error in tridiagonal eigenvalue calculation",
+    /* 24 */ "Starting vector is zero",
+    /* 25 */ "MODE is invalid",
+    /* 26 */ "MODE and BMAT are not compatible",
+    /* 27 */ "ISHIFT must be 0 or 1",
+    /* 28 */ "NEV and WHICH='BE' are incompatible",
+    /* 29 */ "Could not build an Arnoldi factorization",
+    /* 30 */ "No eigenvalues to sufficient accuracy",
+    /* 31 */ "HOWMNY is invalid",
+    /* 32 */ "HOWMNY='S' is not implemented",
+    /* 33 */ "Different number of converged Ritz values",
+    /* 34 */ "Error from calculation of a real Schur form",
+    /* 35 */ "LAPACK (dtrevc) error for calculating eigenvectors",
+    /* 36 */ "Unknown ARPACK error",
+    /* 37 */ "Negative loop detected while calculating shortest paths",
+    /* 38 */ "Internal error, likely a bug in igraph",
+    /* 39 */ "Maximum number of iterations reached",
+    /* 40 */ "No shifts could be applied during a cycle of the "
+             "Implicitly restarted Arnoldi iteration. One possibility "
+             "is to increase the size of NCV relative to NEV",
+    /* 41 */ "The Schur form computed by LAPACK routine dlahqr "
+             "could not be reordered by LAPACK routine dtrsen.",
+    /* 42 */ "Big integer division by zero",
+    /* 43 */ "GLPK Error, GLP_EBOUND",
+    /* 44 */ "GLPK Error, GLP_EROOT",
+    /* 45 */ "GLPK Error, GLP_ENOPFS",
+    /* 46 */ "GLPK Error, GLP_ENODFS",
+    /* 47 */ "GLPK Error, GLP_EFAIL",
+    /* 48 */ "GLPK Error, GLP_EMIPGAP",
+    /* 49 */ "GLPK Error, GLP_ETMLIM",
+    /* 50 */ "GLPK Error, GLP_STOP",
+    /* 51 */ "Internal attribute handler error",
+    /* 52 */ "Unimplemented attribute combination for this type",
+    /* 53 */ "LAPACK call resulted an error",
+    /* 54 */ "Internal DrL error",
+    /* 55 */ "Integer or double overflow",
+    /* 56 */ "Internal GPLK error",
+    /* 57 */ "CPU time exceeded",
+    /* 58 */ "Integer or double underflow"
+};
+
+const char* igraph_strerror(const int igraph_errno) {
+  return igraph_i_error_strings[igraph_errno];
+}
+
+int igraph_error(const char *reason, const char *file, int line,
+		 int igraph_errno) {
+
+  if (igraph_i_error_handler) {
+    igraph_i_error_handler(reason, file, line, igraph_errno);
+#ifndef USING_R
+  }  else {
+    igraph_error_handler_abort(reason, file, line, igraph_errno);
+#endif
+  }
+  return igraph_errno;
+}
+
+int igraph_errorf(const char *reason, const char *file, int line, 
+		  int igraph_errno, ...) {
+  va_list ap;
+  va_start(ap, igraph_errno);
+  vsnprintf(igraph_i_errormsg_buffer, 
+	    sizeof(igraph_i_errormsg_buffer) / sizeof(char), reason, ap);
+  return igraph_error(igraph_i_errormsg_buffer, file, line, igraph_errno);
+}
+
+int igraph_errorvf(const char *reason, const char *file, int line,
+		   int igraph_errno, va_list ap) {
+  vsnprintf(igraph_i_errormsg_buffer, 
+	    sizeof(igraph_i_errormsg_buffer) / sizeof(char), reason, ap);
+  return igraph_error(igraph_i_errormsg_buffer, file, line, igraph_errno);
+}
+
+#ifndef USING_R
+void igraph_error_handler_abort (const char *reason, const char *file,
+				 int line, int igraph_errno) {
+  fprintf(stderr, "Error at %s:%i :%s, %s\n", file, line, reason,
+	  igraph_strerror(igraph_errno));
+  abort();
+}
+#endif
+
+void igraph_error_handler_ignore (const char *reason, const char *file,
+				  int line, int igraph_errno) {
+  IGRAPH_UNUSED(reason); 
+  IGRAPH_UNUSED(file); 
+  IGRAPH_UNUSED(line);
+  IGRAPH_UNUSED(igraph_errno);
+
+  IGRAPH_FINALLY_FREE();
+}
+
+#ifndef USING_R
+void igraph_error_handler_printignore (const char *reason, const char *file,
+				       int line, int igraph_errno) {
+  IGRAPH_FINALLY_FREE();
+  fprintf(stderr, "Error at %s:%i :%s, %s\n", file, line, reason,
+	  igraph_strerror(igraph_errno));
+}
+#endif
+
+igraph_error_handler_t *
+igraph_set_error_handler (igraph_error_handler_t * new_handler)
+{
+  igraph_error_handler_t * previous_handler = igraph_i_error_handler;
+  igraph_i_error_handler = new_handler;
+  return previous_handler;
+}
+
+IGRAPH_THREAD_LOCAL struct igraph_i_protectedPtr igraph_i_finally_stack[100];
+
+/*
+ * Adds another element to the free list
+ */
+
+void IGRAPH_FINALLY_REAL(void (*func)(void*), void* ptr) {
+  int no=igraph_i_finally_stack[0].all;
+  assert (no<100);
+  assert (no>=0);
+  igraph_i_finally_stack[no].ptr=ptr;
+  igraph_i_finally_stack[no].func=func;
+  igraph_i_finally_stack[0].all ++;
+  /* printf("--> Finally stack contains now %d elements\n", igraph_i_finally_stack[0].all); */
+}
+
+void IGRAPH_FINALLY_CLEAN(int minus) { 
+  igraph_i_finally_stack[0].all -= minus;
+  if (igraph_i_finally_stack[0].all < 0) {
+    /* fprintf(stderr, "corrupt finally stack, popping %d elements when only %d left\n", minus, igraph_i_finally_stack[0].all+minus); */
+    igraph_i_finally_stack[0].all = 0;
+  }
+  /* printf("<-- Finally stack contains now %d elements\n", igraph_i_finally_stack[0].all); */
+}
+
+void IGRAPH_FINALLY_FREE(void) {
+  int p;
+/*   printf("[X] Finally stack will be cleaned (contained %d elements)\n", igraph_i_finally_stack[0].all);  */
+  for (p=igraph_i_finally_stack[0].all-1; p>=0; p--) {
+    igraph_i_finally_stack[p].func(igraph_i_finally_stack[p].ptr);
+  }
+  igraph_i_finally_stack[0].all=0;
+}
+
+int IGRAPH_FINALLY_STACK_SIZE(void) {
+  return igraph_i_finally_stack[0].all;
+}
+
+static IGRAPH_THREAD_LOCAL igraph_warning_handler_t *igraph_i_warning_handler=0;
+
+/**
+ * \function igraph_warning_handler_ignore
+ * Ignore all warnings
+ *
+ * This warning handler function simply ignores all warnings.
+ * \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.
+ */
+
+void igraph_warning_handler_ignore (const char *reason, const char *file,
+				   int line, int igraph_errno) {
+  IGRAPH_UNUSED(reason); 
+  IGRAPH_UNUSED(file); 
+  IGRAPH_UNUSED(line);
+  IGRAPH_UNUSED(igraph_errno);
+}
+
+#ifndef USING_R
+
+/**
+ * \function igraph_warning_handler_print
+ * Print all warning to the standard error
+ *
+ * This warning handler function simply prints all warnings to the 
+ * standard error.
+ * \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.
+ */
+
+void igraph_warning_handler_print (const char *reason, const char *file,
+				   int line, int igraph_errno) {
+  IGRAPH_UNUSED(igraph_errno);
+  fprintf(stderr, "Warning: %s in file %s, line %i\n", reason, file, line);
+}
+#endif
+
+int igraph_warning(const char *reason, const char *file, int line,
+		   int igraph_errno) {
+
+  if (igraph_i_warning_handler) {
+    igraph_i_warning_handler(reason, file, line, igraph_errno);
+#ifndef USING_R
+  }  else {
+    igraph_warning_handler_print(reason, file, line, igraph_errno);
+#endif
+  }
+  return igraph_errno;
+}
+
+int igraph_warningf(const char *reason, const char *file, int line, 
+		    int igraph_errno, ...) {
+  va_list ap;
+  va_start(ap, igraph_errno);
+  vsnprintf(igraph_i_warningmsg_buffer, 
+	    sizeof(igraph_i_warningmsg_buffer) / sizeof(char), reason, ap);
+  return igraph_warning(igraph_i_warningmsg_buffer, file, line, 
+			igraph_errno);
+}
+
+igraph_warning_handler_t *
+igraph_set_warning_handler (igraph_warning_handler_t * new_handler)
+{
+  igraph_warning_handler_t * previous_handler = igraph_i_warning_handler;
+  igraph_i_warning_handler = new_handler;
+  return previous_handler;
+}
diff --git a/src/igraph_estack.c b/src/igraph_estack.c
new file mode 100644
index 0000000..b6990c0
--- /dev/null
+++ b/src/igraph_estack.c
@@ -0,0 +1,67 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_estack.h"
+
+int igraph_estack_init(igraph_estack_t *s, long int setsize, 
+		       long int stacksize) {
+  IGRAPH_CHECK(igraph_vector_bool_init(&s->isin, setsize));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &s->isin);
+  IGRAPH_CHECK(igraph_stack_long_init(&s->stack, stacksize));
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+void igraph_estack_destroy(igraph_estack_t *s) {
+  igraph_stack_long_destroy(&s->stack);
+  igraph_vector_bool_destroy(&s->isin);
+}
+
+int igraph_estack_push(igraph_estack_t *s,  long int elem) {
+  if ( !VECTOR(s->isin)[elem] ) {
+    IGRAPH_CHECK(igraph_stack_long_push(&s->stack, elem));
+    VECTOR(s->isin)[elem] = 1;
+  }
+  return 0;
+}
+
+long int igraph_estack_pop(igraph_estack_t *s) {
+  long int elem=igraph_stack_long_pop(&s->stack);
+  VECTOR(s->isin)[elem] = 0;
+  return elem;
+}
+
+igraph_bool_t igraph_estack_iselement(const igraph_estack_t *s, 
+				      long int elem) {
+  return VECTOR(s->isin)[elem];
+}
+
+long int igraph_estack_size(const igraph_estack_t *s) {
+  return igraph_stack_long_size(&s->stack);
+}
+
+#ifndef USING_R
+int igraph_estack_print(const igraph_estack_t *s) {
+  return igraph_stack_long_print(&s->stack);
+}
+#endif
diff --git a/src/igraph_estack.h b/src/igraph_estack.h
new file mode 100644
index 0000000..3c6735e
--- /dev/null
+++ b/src/igraph_estack.h
@@ -0,0 +1,47 @@
+/* -*- 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_ESTACK_H
+#define IGRAPH_ESTACK_H
+
+#include "igraph_stack.h"
+#include "igraph_vector.h"
+
+typedef struct igraph_estack_t {
+  igraph_stack_long_t stack;
+  igraph_vector_bool_t isin;
+} igraph_estack_t;
+
+int igraph_estack_init(igraph_estack_t *s, long int setsize, 
+		       long int stacksize);
+void igraph_estack_destroy(igraph_estack_t *s);
+
+int igraph_estack_push(igraph_estack_t *s,  long int elem);
+long int igraph_estack_pop(igraph_estack_t *s);
+igraph_bool_t igraph_estack_iselement(const igraph_estack_t *s, 
+				      long int elem);
+long int igraph_estack_size(const igraph_estack_t *s);
+
+int igraph_estack_print(const igraph_estack_t *s);
+
+#endif
diff --git a/src/igraph_fixed_vectorlist.c b/src/igraph_fixed_vectorlist.c
new file mode 100644
index 0000000..bb0b4a0
--- /dev/null
+++ b/src/igraph_fixed_vectorlist.c
@@ -0,0 +1,76 @@
+/* -*- 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_types_internal.h"
+#include "igraph_memory.h"
+
+void igraph_fixed_vectorlist_destroy(igraph_fixed_vectorlist_t *l) {
+  long int i, n=igraph_vector_ptr_size(&l->v);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(l->v)[i];
+    if (v) { igraph_vector_destroy(v); }
+  }
+  igraph_vector_ptr_destroy(&l->v);
+  igraph_free(l->vecs);
+}
+
+int igraph_fixed_vectorlist_convert(igraph_fixed_vectorlist_t *l,
+				    const igraph_vector_t *from, 
+				    long int size) {
+
+  igraph_vector_t sizes;
+  long int i, no=igraph_vector_size(from);
+
+  l->vecs=igraph_Calloc(size, igraph_vector_t);
+  if (!l->vecs) {
+    IGRAPH_ERROR("Cannot merge attributes for simplify", 
+		 IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, l->vecs);
+  IGRAPH_CHECK(igraph_vector_ptr_init(&l->v, size));
+  IGRAPH_FINALLY(igraph_fixed_vectorlist_destroy, &l->v);
+  IGRAPH_VECTOR_INIT_FINALLY(&sizes, size);
+
+  for (i=0; i<no; i++) {
+    long int to=(long int) VECTOR(*from)[i];
+    if (to >= 0) { VECTOR(sizes)[to] += 1; }
+  }
+  for (i=0; i<size; i++) {
+    igraph_vector_t *v=&(l->vecs[i]);
+    IGRAPH_CHECK(igraph_vector_init(v, (long int) VECTOR(sizes)[i]));
+    igraph_vector_clear(v);
+    VECTOR(l->v)[i]=v;
+  }
+  for (i=0; i<no; i++) {
+    long int to=(long int) VECTOR(*from)[i];
+    if (to >= 0) { 
+      igraph_vector_t *v=&(l->vecs[to]);
+      igraph_vector_push_back(v, i);
+    }
+  }
+    
+  igraph_vector_destroy(&sizes);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
diff --git a/src/igraph_flow_internal.h b/src/igraph_flow_internal.h
new file mode 100644
index 0000000..822d7ca
--- /dev/null
+++ b/src/igraph_flow_internal.h
@@ -0,0 +1,41 @@
+/* -*- 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_FLOW_INTERNAL_H
+#define IGRAPH_FLOW_INTERNAL_H
+
+#include "igraph_types.h"
+#include "igraph_marked_queue.h"
+#include "igraph_estack.h"
+
+typedef int igraph_provan_shier_pivot_t(const igraph_t *graph,
+					const igraph_marked_queue_t *S,
+					const igraph_estack_t *T,
+					long int source,
+					long int target,
+					long int *v,
+					igraph_vector_t *Isv,
+					void *arg);
+
+#endif
+
diff --git a/src/igraph_glpk_support.h b/src/igraph_glpk_support.h
new file mode 100644
index 0000000..744a569
--- /dev/null
+++ b/src/igraph_glpk_support.h
@@ -0,0 +1,48 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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 IGRAPH_GLPK_SUPPORT_H
+#define IGRAPH_GLPK_SUPPORT_H
+
+#include "config.h"
+
+/* Note: only files calling the GLPK routines directly need to
+   include this header.
+*/
+
+#ifdef HAVE_GLPK
+
+#include <glpk.h>
+
+int igraph_i_glpk_check(int retval, const char* message);
+void igraph_i_glpk_interruption_hook(glp_tree *tree, void *info);
+#define IGRAPH_GLPK_CHECK(func, message) do {\
+  int igraph_i_ret = igraph_i_glpk_check(func, message); \
+  if (IGRAPH_UNLIKELY(igraph_i_ret != 0)) {\
+    return igraph_i_ret; \
+  } } while (0)
+
+#endif
+
+#endif
diff --git a/src/igraph_gml_tree.h b/src/igraph_gml_tree.h
new file mode 100644
index 0000000..70a934d
--- /dev/null
+++ b/src/igraph_gml_tree.h
@@ -0,0 +1,87 @@
+/* 
+   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 REST_GML_TREE_H
+#define REST_GML_TREE_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 "igraph_vector.h"
+#include "igraph_vector_ptr.h"
+
+typedef enum { IGRAPH_I_GML_TREE_TREE=0, 
+	       IGRAPH_I_GML_TREE_INTEGER,
+	       IGRAPH_I_GML_TREE_REAL,
+	       IGRAPH_I_GML_TREE_STRING,
+	       IGRAPH_I_GML_TREE_DELETED } igraph_i_gml_tree_type_t;
+
+typedef struct igraph_gml_tree_t {
+  igraph_vector_ptr_t names;
+  igraph_vector_char_t types;
+  igraph_vector_ptr_t children;
+} igraph_gml_tree_t;
+
+int igraph_gml_tree_init_integer(igraph_gml_tree_t *t, 
+				 const char *name, int namelen,
+				 igraph_integer_t value);
+int igraph_gml_tree_init_real(igraph_gml_tree_t *t, 
+			      const char *name, int namelen,
+			      igraph_real_t value);
+int igraph_gml_tree_init_string(igraph_gml_tree_t *t,
+				const char *name, int namelen,
+				const char *value, int valuelen);
+int igraph_gml_tree_init_tree(igraph_gml_tree_t *t,
+			      const char *name, int namelen,
+			      igraph_gml_tree_t *value);
+void igraph_gml_tree_destroy(igraph_gml_tree_t *t);
+
+void igraph_gml_tree_delete(igraph_gml_tree_t *t, long int pos);
+int igraph_gml_tree_mergedest(igraph_gml_tree_t *t1, igraph_gml_tree_t *t2);
+
+long int igraph_gml_tree_length(const igraph_gml_tree_t *t);
+long int igraph_gml_tree_find(const igraph_gml_tree_t *t,
+			      const char *name, long int from);
+long int igraph_gml_tree_findback(const igraph_gml_tree_t *t,
+				  const char *name, long int from);
+int igraph_gml_tree_type(const igraph_gml_tree_t *t, long int pos);
+const char *igraph_gml_tree_name(const igraph_gml_tree_t *t, long int pos);
+igraph_integer_t igraph_gml_tree_get_integer(const igraph_gml_tree_t *t,
+					     long int pos);
+igraph_real_t igraph_gml_tree_get_real(const igraph_gml_tree_t *t,
+				       long int pos);
+const char *igraph_gml_tree_get_string(const igraph_gml_tree_t *t,
+				       long int pos);
+
+igraph_gml_tree_t *igraph_gml_tree_get_tree(const igraph_gml_tree_t *t,
+					    long int pos);
+#endif
diff --git a/src/igraph_grid.c b/src/igraph_grid.c
new file mode 100644
index 0000000..bb54ff5
--- /dev/null
+++ b/src/igraph_grid.c
@@ -0,0 +1,541 @@
+/* -*- mode: C -*-  */
+/* 
+   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
+   (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_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_memory.h"
+#include "config.h"
+
+#include <math.h>
+
+/* internal function */
+
+int igraph_2dgrid_which(igraph_2dgrid_t *grid, igraph_real_t xc, igraph_real_t yc,
+			long int *x, long int *y) {
+
+  if (xc <= grid->minx) { 
+    *x=0; 
+  } else if (xc >= grid->maxx) {
+    *x=grid->stepsx-1;
+  } else {
+    *x=(long int) floor((xc-(grid->minx))/(grid->deltax));
+  }
+
+  if (yc <= grid->miny) {
+    *y=0;
+  } else if (yc >= grid->maxy) {
+    *y=grid->stepsy-1;
+  } else {
+    *y=(long int) floor((yc-(grid->miny))/(grid->deltay));
+  }
+
+  return 0;
+}
+
+int igraph_2dgrid_init(igraph_2dgrid_t *grid, igraph_matrix_t *coords, 
+		       igraph_real_t minx, igraph_real_t maxx, igraph_real_t deltax,
+		       igraph_real_t miny, igraph_real_t maxy, igraph_real_t deltay) {
+  long int i;
+  
+  grid->coords=coords;
+  grid->minx=minx;
+  grid->maxx=maxx;
+  grid->deltax=deltax;
+  grid->miny=miny;
+  grid->maxy=maxy;
+  grid->deltay=deltay;
+  
+  grid->stepsx=(long int) ceil((maxx-minx)/deltax);
+  grid->stepsy=(long int) ceil((maxy-miny)/deltay);
+
+  IGRAPH_CHECK(igraph_matrix_init(&grid->startidx, 
+				  grid->stepsx, grid->stepsy));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &grid->startidx);
+  IGRAPH_VECTOR_INIT_FINALLY(&grid->next, igraph_matrix_nrow(coords));
+  IGRAPH_VECTOR_INIT_FINALLY(&grid->prev, igraph_matrix_nrow(coords));
+
+  for (i=0; i<igraph_vector_size(&grid->next); i++) {
+    VECTOR(grid->next)[i]=-1;
+  }
+
+  grid->massx=0;
+  grid->massy=0;
+  grid->vertices=0;
+  
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+void igraph_2dgrid_destroy(igraph_2dgrid_t *grid) {
+  igraph_matrix_destroy(&grid->startidx);
+  igraph_vector_destroy(&grid->next);
+  igraph_vector_destroy(&grid->prev);
+}
+
+void igraph_2dgrid_add(igraph_2dgrid_t *grid, long int elem,
+		       igraph_real_t xc, igraph_real_t yc) {
+  long int x, y;
+  long int first;
+
+  MATRIX(*grid->coords, elem, 0)=xc;
+  MATRIX(*grid->coords, elem, 1)=yc;
+
+  /* add to cell */
+  igraph_2dgrid_which(grid, xc, yc, &x, &y);
+  first=(long int) MATRIX(grid->startidx, x, y);
+  VECTOR(grid->prev)[elem]=0;
+  VECTOR(grid->next)[elem]=first;
+  if (first != 0) {
+    VECTOR(grid->prev)[first-1]=elem+1;
+  }
+  MATRIX(grid->startidx, x, y)=elem+1;
+
+  grid->massx += xc;
+  grid->massy += yc;
+  grid->vertices += 1;
+}
+
+void igraph_2dgrid_add2(igraph_2dgrid_t *grid, long int elem) {
+  long int x, y;
+  long int first;
+  igraph_real_t xc, yc;
+
+  xc=MATRIX(*grid->coords, elem, 0);
+  yc=MATRIX(*grid->coords, elem, 1);
+
+  /* add to cell */
+  igraph_2dgrid_which(grid, xc, yc, &x, &y);
+  first=(long int) MATRIX(grid->startidx, x, y);
+  VECTOR(grid->prev)[elem]=0;
+  VECTOR(grid->next)[elem]=first;
+  if (first != 0) {
+    VECTOR(grid->prev)[first-1]=elem+1;
+  }
+  MATRIX(grid->startidx, x, y)=elem+1;
+
+  grid->massx += xc;
+  grid->massy += yc;
+  grid->vertices += 1;
+}
+
+void igraph_2dgrid_move(igraph_2dgrid_t *grid, long int elem, 
+			igraph_real_t xc, igraph_real_t yc) {
+  long int oldx, oldy;
+  long int newx, newy;
+  igraph_real_t oldxc=MATRIX(*grid->coords, elem, 0);
+  igraph_real_t oldyc=MATRIX(*grid->coords, elem, 1);
+  long int first;
+
+  xc=oldxc+xc; yc=oldyc+yc;
+
+  igraph_2dgrid_which(grid, oldxc, oldyc, &oldx, &oldy);
+  igraph_2dgrid_which(grid, xc, yc, &newx, &newy);
+  if (oldx != newx || oldy != newy) {
+    /* remove from this cell */
+    if (VECTOR(grid->prev)[elem] != 0) {
+      VECTOR(grid->next) [ (long int) VECTOR(grid->prev)[elem]-1 ] =
+	VECTOR(grid->next)[elem];
+    } else {
+      MATRIX(grid->startidx, oldx, oldy)=VECTOR(grid->next)[elem];
+    }
+    if (VECTOR(grid->next)[elem] != 0) {
+      VECTOR(grid->prev)[ (long int) VECTOR(grid->next)[elem]-1 ] =
+	VECTOR(grid->prev)[elem];
+    }
+    
+    /* add to this cell */
+    first=(long int) MATRIX(grid->startidx, newx, newy);
+    VECTOR(grid->prev)[elem]=0;
+    VECTOR(grid->next)[elem]=first;
+    if (first != 0) {
+      VECTOR(grid->prev)[first-1]=elem+1;
+    }
+    MATRIX(grid->startidx, newx, newy)=elem+1;
+  }
+  
+  grid->massx += -oldxc+xc;
+  grid->massy += -oldyc+yc;
+
+  MATRIX(*grid->coords, elem, 0)=xc;
+  MATRIX(*grid->coords, elem, 1)=yc;
+  
+}
+
+void igraph_2dgrid_getcenter(const igraph_2dgrid_t *grid, 
+			     igraph_real_t *massx, igraph_real_t *massy) {
+  *massx = (grid->massx)/(grid->vertices);
+  *massy = (grid->massy)/(grid->vertices);
+}
+
+igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, long int elem) {
+  return VECTOR(grid->next)[elem] != -1;
+}
+
+igraph_real_t igraph_2dgrid_dist(const igraph_2dgrid_t *grid, 
+			  long int e1, long int e2) {
+  igraph_real_t x=MATRIX(*grid->coords, e1, 0)-MATRIX(*grid->coords, e2, 0);
+  igraph_real_t y=MATRIX(*grid->coords, e1, 1)-MATRIX(*grid->coords, e2, 1);
+  
+  return sqrt(x*x + y*y);
+}
+
+igraph_real_t igraph_2dgrid_dist2(const igraph_2dgrid_t *grid, 
+			  long int e1, long int e2) {
+  igraph_real_t x=MATRIX(*grid->coords, e1, 0)-MATRIX(*grid->coords, e2, 0);
+  igraph_real_t y=MATRIX(*grid->coords, e1, 1)-MATRIX(*grid->coords, e2, 1);
+  
+  return x*x + y*y;
+}
+
+int igraph_i_2dgrid_addvertices(igraph_2dgrid_t *grid, igraph_vector_t *eids,
+				igraph_integer_t vid, igraph_real_t r, 
+				long int x, long int y) {
+  long int act;
+  igraph_real_t *v=VECTOR(grid->next);
+
+  r=r*r;
+  act=(long int) MATRIX(grid->startidx, x, y);
+  while (act != 0) {
+    if (igraph_2dgrid_dist2(grid, vid, act-1) < r) {
+      IGRAPH_CHECK(igraph_vector_push_back(eids, act-1));
+    }
+    act=(long int) v[act-1];
+  }
+  return 0;
+}
+
+int igraph_2dgrid_neighbors(igraph_2dgrid_t *grid, igraph_vector_t *eids, 
+			    igraph_integer_t vid, igraph_real_t r) {
+  igraph_real_t xc=MATRIX(*grid->coords, (long int)vid, 0);
+  igraph_real_t yc=MATRIX(*grid->coords, (long int)vid, 1);
+  long int x, y;
+  igraph_vector_clear(eids);
+  
+  igraph_2dgrid_which(grid, xc, yc, &x, &y);
+
+  /* this cell */
+  igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y);
+  
+  /* left */
+  if (x!=0) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y);
+  }
+  /* right */
+  if (x!=grid->stepsx-1) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x+1, y);
+  }
+  /* up */
+  if (y!=0) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y-1);
+  }
+  /* down */
+  if (y!=grid->stepsy-1) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y+1);
+  }
+  /* up & left */
+  if (x != 0 && y != 0) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y-1);
+  }
+  /* up & right */
+  if (x != grid->stepsx-1 && y != 0) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x+1, y-1);
+  }
+  /* down & left */
+  if (x != 0 && y != grid->stepsy-1) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y+1);
+  }
+  /* down & right */
+  if (x != grid->stepsx-1 && y != grid->stepsy-1) {
+    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y+1);
+  }
+  
+  return 0;
+}
+
+void igraph_2dgrid_reset(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) {
+  /* Search for the first cell containing a vertex */
+  it->x=0; it->y=0; it->vid=(long int) MATRIX(grid->startidx, 0, 0);
+  while ( it->vid==0 && (it->x < grid->stepsx-1 || it->y<grid->stepsy-1)) {
+    it->x += 1;
+    if (it->x == grid->stepsx) {
+      it->x=0; it->y += 1;
+    }
+    it->vid=(long int) MATRIX(grid->startidx, it->x, it->y);
+  }
+}
+
+igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid, 
+			      igraph_2dgrid_iterator_t *it) {
+  long int ret=it->vid;
+
+  if (ret==0) { return 0; }
+
+  /* First neighbor */
+  it->ncells=-1;
+  if (it->x != grid->stepsx-1) {
+    it->ncells += 1;
+    it->nx[it->ncells]=it->x+1;
+    it->ny[it->ncells]=it->y;
+  }
+  if (it->y != grid->stepsy-1) {
+    it->ncells += 1;
+    it->nx[it->ncells]=it->x;
+    it->ny[it->ncells]=it->y+1;
+  }
+  if (it->ncells==1) {
+    it->ncells += 1;
+    it->nx[it->ncells]=it->x+1;
+    it->ny[it->ncells]=it->y+1;
+  }
+  it->ncells+=1;
+  it->nx[it->ncells]=it->x;
+  it->ny[it->ncells]=it->y;
+  
+  it->nei=(long int) VECTOR(grid->next) [ ret-1 ];
+  while (it->ncells > 0 && it->nei==0 ) {
+    it->ncells -= 1;
+    it->nei=(long int) MATRIX(grid->startidx, it->nx[it->ncells], it->ny[it->ncells]);
+  }
+
+  /* Next vertex */
+  it->vid=(long int) VECTOR(grid->next)[ it->vid-1 ];
+  while ( (it->x < grid->stepsx-1 || it->y<grid->stepsy-1) &&
+	  it->vid == 0) {
+    it->x += 1;
+    if (it->x == grid->stepsx) {
+      it->x=0; it->y += 1;
+    }
+    it->vid=(long int) MATRIX(grid->startidx, it->x, it->y);
+  }
+
+  return (igraph_integer_t) ret;
+}
+
+igraph_integer_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid,
+				 igraph_2dgrid_iterator_t *it) {
+  long int ret=it->nei;
+
+  if (it->nei != 0) {
+    it->nei=(long int) VECTOR(grid->next) [ ret-1 ];
+  }
+  while (it->ncells > 0 && it->nei==0 ) {
+    it->ncells -= 1;
+    it->nei=(long int) MATRIX(grid->startidx, it->nx[it->ncells], it->ny[it->ncells]);
+  }
+ 
+  return (igraph_integer_t) ret;  
+}
+
+/*-----------------------------------------------------------------------*/
+
+int igraph_i_layout_mergegrid_which(igraph_i_layout_mergegrid_t *grid,
+				    igraph_real_t xc, igraph_real_t yc,
+				    long int *x, long int *y) {
+  if (xc <= grid->minx) { 
+    *x=0; 
+  } else if (xc >= grid->maxx) {
+    *x=grid->stepsx-1;
+  } else {
+    *x=(long int) floor((xc-(grid->minx))/(grid->deltax));
+  }
+
+  if (yc <= grid->miny) {
+    *y=0;
+  } else if (yc >= grid->maxy) {
+    *y=grid->stepsy-1;
+  } else {
+    *y=(long int) floor((yc-(grid->miny))/(grid->deltay));
+  }
+
+  return 0;
+}  
+
+int igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t *grid,
+				   igraph_real_t minx, igraph_real_t maxx, long int stepsx,
+				   igraph_real_t miny, igraph_real_t maxy, long int stepsy) {
+  grid->minx=minx;
+  grid->maxx=maxx;
+  grid->stepsx=stepsx;
+  grid->deltax=(maxx-minx)/stepsx;
+  grid->miny=miny;
+  grid->maxy=maxy;
+  grid->stepsy=stepsy;
+  grid->deltay=(maxy-miny)/stepsy;
+  
+  grid->data=igraph_Calloc(stepsx*stepsy, long int);
+  if (grid->data==0) {
+    IGRAPH_ERROR("Cannot create grid", IGRAPH_ENOMEM);
+  }
+  return 0;
+}
+
+void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid) {
+  igraph_Free(grid->data);
+}
+
+#define MAT(i,j) (grid->data[(grid->stepsy)*(j)+(i)])
+#define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2)))
+
+int igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t *grid,
+				       igraph_real_t x, igraph_real_t y, igraph_real_t r, 
+				       long int id) {
+  long int cx, cy;
+  long int i, j;
+
+  igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy);
+  
+  MAT(cx, cy)=id+1;
+
+#define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
+			 grid->miny+(cy+(j))*grid->deltay))
+  
+  for (i=0; cx+i<grid->stepsx && DIST(i,0)<r; i++) {
+    for (j=0; cy+j<grid->stepsy && DIST(i,j)<r; j++) {
+      MAT(cx+i,cy+j)=id+1;
+    }
+  }
+
+#undef DIST
+#define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
+                         grid->miny+(cy-(j)+1)*grid->deltay))
+
+  for (i=0; cx+i<grid->stepsx && DIST(i,0)<r; i++) {
+    for (j=1; cy-j>0 && DIST(i,j)<r; j++) {
+      MAT(cx+i,cy-j)=id+1;
+    }
+  }
+
+#undef DIST
+#define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
+			 grid->miny+(cy+(j))*grid->deltay))
+
+  for (i=1; cx-i>0 && DIST(i,0)<r; i++) {
+    for (j=0; cy+j<grid->stepsy && DIST(i,j)<r; j++) {
+      MAT(cx-i,cy+j)=id+1;
+    }
+  }
+
+#undef DIST
+#define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
+			 grid->miny+(cy-(j)+1)*grid->deltay))
+
+  for (i=1; cx-i>0 && DIST(i,0)<r; i++) {
+    for (j=1; cy-j>0 && DIST(i,j)<r; j++) {
+      MAT(cx-i,cy-j)=id+1;
+    }
+  }  
+
+#undef DIST
+#undef DIST2
+
+  return 0;
+}
+
+long int igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid,
+				       igraph_real_t x, igraph_real_t y) {
+  long int cx, cy;
+  long int res;
+
+  if (x <= grid->minx || x >= grid->maxx ||
+      y <= grid->miny || y >= grid->maxy) {
+    res=-1;
+  } else {
+    igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy);
+    res=MAT(cx, cy)-1;
+  }
+
+  return res;
+}
+
+#define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2)))
+
+long int igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *grid,
+					      igraph_real_t x, igraph_real_t y, igraph_real_t r) {
+  long int cx, cy;
+  long int i,j;
+  long int ret;
+  
+  if (x-r <= grid->minx || x+r >= grid->maxx ||
+      y-r <= grid->miny || y+r >= grid->maxy) {
+    ret=-1;
+  } else {
+    igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy);
+    
+    ret=MAT(cx, cy)-1;
+  
+#define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
+			 grid->miny+(cy+(j))*grid->deltay))
+  
+    for (i=0; ret<0 && cx+i<grid->stepsx && DIST(i,0)<r; i++) {
+      for (j=0; ret<0 && cy+j<grid->stepsy && DIST(i,j)<r; j++) {
+	ret=MAT(cx+i,cy+j)-1;
+      }
+    }
+    
+#undef DIST
+#define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
+                         grid->miny+(cy-(j)+1)*grid->deltay))
+    
+    for (i=0; ret<0 && cx+i<grid->stepsx && DIST(i,0)<r; i++) {
+      for (j=1; ret<0 && cy-j>0 && DIST(i,j)<r; j++) {
+	ret=MAT(cx+i,cy-j)-1;
+      }
+    }
+    
+#undef DIST
+#define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
+			 grid->miny+(cy+(j))*grid->deltay))
+    
+    for (i=1; ret<0 && cx-i>0 && DIST(i,0)<r; i++) {
+      for (j=0; ret<0 && cy+j<grid->stepsy && DIST(i,j)<r; j++) {
+	ret=MAT(cx-i,cy+j)-1;
+      }
+    }
+    
+#undef DIST
+#define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
+			 grid->miny+(cy-(j)+1)*grid->deltay))
+    
+    for (i=1; ret<0 && cx+i>0 && DIST(i,0)<r; i++) {
+      for (j=1; ret<0 && cy+i>0 && DIST(i,j)<r; j++) {
+	ret=MAT(cx-i,cy-j)-1;
+      }
+    }  
+    
+#undef DIST
+    
+  }
+  
+  return ret;
+}
+  
+/* int print_grid(igraph_i_layout_mergegrid_t *grid) { */
+/*   long int i,j; */
+  
+/*   for (i=0; i<grid->stepsx; i++) { */
+/*     for (j=0; j<grid->stepsy; j++) { */
+/*       printf("%li ", MAT(i,j)-1); */
+/*     } */
+/*     printf("\n"); */
+/*   } */
+/* } */
diff --git a/src/igraph_hacks_internal.h b/src/igraph_hacks_internal.h
new file mode 100644
index 0000000..6ebc712
--- /dev/null
+++ b/src/igraph_hacks_internal.h
@@ -0,0 +1,57 @@
+/* -*- 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_HACKS_INTERNAL_H
+#define IGRAPH_HACKS_INTERNAL_H
+
+#include "config.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
+
+#ifndef HAVE_STRDUP
+#  define strdup igraph_i_strdup
+char* igraph_i_strdup(const char *s);
+#endif
+
+#ifndef HAVE_STPCPY
+#  define stpcpy igraph_i_stpcpy
+char* igraph_i_stpcpy(char* s1, const char* s2);
+#else
+#  ifndef HAVE_STPCPY_SIGNATURE
+char* stpcpy(char* s1, const char* s2);
+#  endif
+#endif
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_hashtable.c b/src/igraph_hashtable.c
new file mode 100644
index 0000000..3c4b07a
--- /dev/null
+++ b/src/igraph_hashtable.c
@@ -0,0 +1,128 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "config.h"
+#include <string.h>
+
+int igraph_hashtable_init(igraph_hashtable_t *ht) {
+  IGRAPH_CHECK(igraph_trie_init(&ht->keys, 1));
+  IGRAPH_FINALLY(igraph_trie_destroy, &ht->keys);
+  IGRAPH_CHECK(igraph_strvector_init(&ht->elements, 0));
+  IGRAPH_FINALLY(igraph_trie_destroy, &ht->elements);
+  IGRAPH_CHECK(igraph_strvector_init(&ht->defaults, 0));
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+void igraph_hashtable_destroy(igraph_hashtable_t *ht) {
+  igraph_trie_destroy(&ht->keys);
+  igraph_strvector_destroy(&ht->elements);
+  igraph_strvector_destroy(&ht->defaults);
+}
+
+/* Note: may leave the hash table in an inconsistent state if a new
+   element is added, but this is not a big problem, since while the
+   defaults, or the defaults plus the elements may contain more elements
+   than the keys trie, but the data is always retrieved based on the trie
+*/
+
+int igraph_hashtable_addset(igraph_hashtable_t *ht,
+			    const char *key, const char *def, 
+			    const char *elem){
+  long int size=igraph_trie_size(&ht->keys);
+  long int newid;  
+  IGRAPH_CHECK(igraph_trie_get(&ht->keys, key, &newid));
+
+  if (newid==size) {
+    /* this is a new element */
+    IGRAPH_CHECK(igraph_strvector_resize(&ht->defaults, newid+1));
+    IGRAPH_CHECK(igraph_strvector_resize(&ht->elements, newid+1));
+    IGRAPH_CHECK(igraph_strvector_set(&ht->defaults, newid, def));
+    IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, elem));
+  } else {
+    /* set an already existing element */
+    IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, elem));
+  }
+  
+  return 0;
+}
+
+/* Previous comment also applies here */
+
+int igraph_hashtable_addset2(igraph_hashtable_t *ht,
+			     const char *key, const char *def,
+			     const char *elem, int elemlen) {
+  long int size=igraph_trie_size(&ht->keys);
+  long int newid;
+  char *tmp;
+
+  IGRAPH_CHECK(igraph_trie_get(&ht->keys, key, &newid));
+
+  tmp=igraph_Calloc(elemlen+1, char);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, tmp);
+  strncpy(tmp, elem, elemlen);
+  tmp[elemlen]='\0';
+
+  if (newid==size) {
+    IGRAPH_CHECK(igraph_strvector_resize(&ht->defaults, newid+1));
+    IGRAPH_CHECK(igraph_strvector_resize(&ht->elements, newid+1));
+    IGRAPH_CHECK(igraph_strvector_set(&ht->defaults, newid, def));
+    IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, tmp));    
+  } else {
+    IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, tmp));    
+  }
+
+  igraph_Free(tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_hashtable_get(igraph_hashtable_t *ht,
+			 const char *key, char **elem) {
+  long int newid;
+  IGRAPH_CHECK(igraph_trie_get(&ht->keys, key, &newid));
+  
+  igraph_strvector_get(&ht->elements, newid, elem);
+  
+  return 0;
+}
+
+int igraph_hashtable_reset(igraph_hashtable_t *ht) {
+  igraph_strvector_destroy(&ht->elements);
+  IGRAPH_CHECK(igraph_strvector_copy(&ht->elements, &ht->defaults));
+  return 0;
+}
+
+int igraph_hashtable_getkeys(igraph_hashtable_t *ht, 
+			     const igraph_strvector_t **sv) {
+  return igraph_trie_getkeys(&ht->keys, sv);
+}
diff --git a/src/igraph_heap.c b/src/igraph_heap.c
new file mode 100644
index 0000000..3477405
--- /dev/null
+++ b/src/igraph_heap.c
@@ -0,0 +1,64 @@
+/* -*- 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_types.h"
+#include "igraph_heap.h"
+
+#define BASE_IGRAPH_REAL
+#define HEAP_TYPE_MAX
+#include "igraph_pmt.h"
+#include "heap.pmt"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MAX
+#define HEAP_TYPE_MIN
+#include "igraph_pmt.h"
+#include "heap.pmt"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MIN
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#define HEAP_TYPE_MAX
+#include "igraph_pmt.h"
+#include "heap.pmt"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MAX
+#define HEAP_TYPE_MIN
+#include "igraph_pmt.h"
+#include "heap.pmt"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MIN
+#undef BASE_LONG
+
+#define BASE_CHAR
+#define HEAP_TYPE_MAX
+#include "igraph_pmt.h"
+#include "heap.pmt"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MAX
+#define HEAP_TYPE_MIN
+#include "igraph_pmt.h"
+#include "heap.pmt"
+#include "igraph_pmt_off.h"
+#undef HEAP_TYPE_MIN
+#undef BASE_CHAR
diff --git a/src/igraph_hrg.cc b/src/igraph_hrg.cc
new file mode 100644
index 0000000..a21dbc5
--- /dev/null
+++ b/src/igraph_hrg.cc
@@ -0,0 +1,1025 @@
+/* -*- 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_interface.h"
+#include "igraph_community.h"
+#include "igraph_memory.h"
+#include "igraph_constructors.h"
+#include "igraph_attributes.h"
+#include "igraph_foreign.h"
+#include "igraph_hrg.h"
+#include "igraph_random.h"
+
+#include "hrg_dendro.h"
+#include "hrg_graph.h"
+#include "hrg_graph_simp.h"
+
+using namespace fitHRG;
+
+/**
+ * \section hrg_intro Introduction
+ * 
+ * <para>A hierarchical random graph is an ensemble of undirected
+ * graphs with \c n vertices. It is defined via a binary tree with \c
+ * n leaf and \c 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.
+ * </para>
+ * 
+ * <para>Please read the following two articles for more about
+ * hierarchical random graphs: A. Clauset, C. Moore, and M.E.J. Newman. 
+ * Hierarchical structure and the prediction of missing links in networks.
+ * Nature 453, 98 - 101 (2008); and 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, Lecture Notes in Computer Science
+ * 4503, 1-13. Springer-Verlag, Berlin Heidelberg (2007).
+ * </para>
+ * 
+ * <para>
+ * igraph contains functions for fitting HRG models to a given network
+ * (\ref igraph_hrg_fit), for generating networks from a given HRG
+ * ensemble (\ref igraph_hrg_game, \ref igraph_hrg_sample), converting
+ * an igraph graph to a HRG and back (\ref igraph_hrg_create, \ref
+ * igraph_hrg_dendrogram), for calculating a consensus tree from a
+ * set of sampled HRGs (\ref igraph_hrg_consensus) and for predicting
+ * missing edges in a network based on its HRG models (\ref
+ * igraph_hrg_predict). 
+ * </para>
+ * 
+ * <para>The igraph HRG implementation is heavily based on the code
+ * published by Aaron Clauset, at his website,
+ * http://tuvalu.santafe.edu/~aaronc/hierarchy/
+ * </para>
+ */
+
+namespace fitHRG {
+  struct pblock { double L; int i; int j; };
+}
+
+int markovChainMonteCarlo(dendro *d, unsigned int period, 
+			  igraph_hrg_t *hrg) {
+  
+  igraph_real_t bestL=d->getLikelihood();
+  double  dL;
+  bool    flag_taken;
+  
+  // Because moves in the dendrogram space are chosen (Monte
+  // Carlo) so that we sample dendrograms with probability
+  // proportional to their likelihood, a likelihood-proportional
+  // sampling of the dendrogram models would be equivalent to a
+  // uniform sampling of the walk itself. We would still have to
+  // decide how often to sample the walk (at most once every n
+  // steps is recommended) but for simplicity, the code here
+  // simply runs the MCMC itself. To actually compute something 
+  // over the set of sampled dendrogram models (in a Bayesian
+  // model averaging sense), you'll need to code that yourself.
+  
+  // do 'period' MCMC moves before doing anything else
+  for (unsigned int i=0; i<period; i++) {
+    
+    // make a MCMC move
+    IGRAPH_CHECK(! d->monteCarloMove(dL, flag_taken, 1.0));
+    
+    // get likelihood of this D given G
+    igraph_real_t cl= d->getLikelihood(); 
+    if (cl > bestL) {
+      // store the current best likelihood
+      bestL = cl;
+      // record the HRG structure
+      d->recordDendrogramStructure(hrg);
+    }
+  }
+  // corrects floating-point errors O(n)
+  d->refreshLikelihood();	
+  
+  return 0;
+}
+
+int markovChainMonteCarlo2(dendro *d, int num_samples) {
+  bool flag_taken;
+  double dL, ptest = 1.0/(50.0*(double)(d->g->numNodes()));
+  int sample_num=0, t=1, thresh = 200 * d->g->numNodes();
+  
+  // Since we're sampling uniformly at random over the equilibrium
+  // walk, we just need to do a bunch of MCMC moves and let the
+  // sampling happen on its own.
+  while (sample_num < num_samples) {
+    // Make a single MCMC move
+    d->monteCarloMove(dL, flag_taken, 1.0);
+		
+    // We sample the dendrogram space once every n MCMC moves (on
+    // average). Depending on the flags on the command line, we sample
+    // different aspects of the dendrograph structure.
+    if (t > thresh && RNG_UNIF01() < ptest) {
+      sample_num++;
+      d->sampleSplitLikelihoods(sample_num);
+    }
+		
+    t++;
+
+    // correct floating-point errors O(n)
+    d->refreshLikelihood();	// TODO: less frequently    
+  }
+	
+  return 0;
+}
+
+int MCMCEquilibrium_Find(dendro *d, igraph_hrg_t *hrg) {
+
+  // We want to run the MCMC until we've found equilibrium; we
+  // use the heuristic of the average log-likelihood (which is
+  // exactly the entropy) over X steps being very close to the
+  // average log-likelihood (entropy) over the X steps that
+  // preceded those. In other words, we look for an apparent
+  // local convergence of the entropy measure of the MCMC.
+
+  bool flag_taken;
+  igraph_real_t dL, Likeli;
+  igraph_real_t oldMeanL;
+  igraph_real_t newMeanL=-1e-49;
+  
+  while (1) {
+    oldMeanL = newMeanL;
+    newMeanL = 0.0;
+    for (int i=0; i<65536; i++) {
+      IGRAPH_CHECK(! d->monteCarloMove(dL, flag_taken, 1.0));
+      Likeli = d->getLikelihood();
+      newMeanL += Likeli;
+    }
+    // corrects floating-point errors O(n)
+    d->refreshLikelihood();
+    if (fabs(newMeanL-oldMeanL)/65536.0 < 1.0) { break; }	
+  }
+  
+  // Record the result
+  if (hrg) { d->recordDendrogramStructure(hrg); }
+
+  return 0;
+}
+
+int igraph_i_hrg_getgraph(const igraph_t *igraph,
+			  dendro *d) {
+  
+  int no_of_nodes = igraph_vcount(igraph);
+  int no_of_edges = igraph_ecount(igraph);
+  int i;
+  
+  // Create graph
+  d->g=new graph(no_of_nodes);  
+
+  // Add edges
+  for (i=0; i<no_of_edges; i++) {
+    int from=IGRAPH_FROM(igraph, i);
+    int to=IGRAPH_TO(igraph, i);
+    if (from==to) { continue; }
+    if (!d->g->doesLinkExist(from, to)) { d->g->addLink(from, to); }
+    if (!d->g->doesLinkExist(to, from)) { d->g->addLink(to, from); }
+  }
+  
+  d->buildDendrogram();
+
+  return 0;
+}
+
+int igraph_i_hrg_getsimplegraph(const igraph_t *igraph, 
+				dendro *d, simpleGraph **sg, 
+				int num_bins) {
+
+  int no_of_nodes = igraph_vcount(igraph);
+  int no_of_edges = igraph_ecount(igraph);
+  int i;
+  
+  // Create graphs
+  d->g = new graph(no_of_nodes, true);
+  d->g->setAdjacencyHistograms(num_bins);
+  (*sg) = new simpleGraph(no_of_nodes);
+  
+  for (i=0; i<no_of_edges; i++) {
+    int from=IGRAPH_FROM(igraph, i);
+    int to=IGRAPH_TO(igraph, i);
+    if (from==to) { continue; }
+    if (!d->g->doesLinkExist(from, to)) { d->g->addLink(from, to); }
+    if (!d->g->doesLinkExist(to, from)) { d->g->addLink(to, from); }
+    if (!(*sg)->doesLinkExist(from, to)) { (*sg)->addLink(from, to); }
+    if (!(*sg)->doesLinkExist(to, from)) { (*sg)->addLink(to, from); }
+  }
+
+  d->buildDendrogram();
+  
+  return 0;
+}
+
+/**
+ * \function igraph_hrg_init
+ * Allocate memory for a HRG.
+ * 
+ * This function must be called before passing an \ref igraph_hrg_t to
+ * an igraph function.
+ * \param hrg Pointer to the HRG data structure to initialize.
+ * \param n The number of vertices in the graph that is modeled by
+ *    this HRG. It can be zero, if this is not yet known.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of vertices in the graph.
+ */
+
+int igraph_hrg_init(igraph_hrg_t *hrg, int n) {
+  IGRAPH_VECTOR_INIT_FINALLY(&hrg->left,      n-1);
+  IGRAPH_VECTOR_INIT_FINALLY(&hrg->right,     n-1);
+  IGRAPH_VECTOR_INIT_FINALLY(&hrg->prob,      n-1);  
+  IGRAPH_VECTOR_INIT_FINALLY(&hrg->edges,     n-1);  
+  IGRAPH_VECTOR_INIT_FINALLY(&hrg->vertices,  n-1);  
+  IGRAPH_FINALLY_CLEAN(5);
+  return 0;
+}
+
+/** 
+ * \function igraph_hrg_destroy
+ * Deallocate memory for an HRG.
+ * 
+ * The HRG data structure can be reinitialized again with an \ref
+ * igraph_hrg_destroy call.
+ * \param hrg Pointer to the HRG data structure to deallocate.
+ * 
+ * Time complexity: operating system dependent.
+ */
+
+void igraph_hrg_destroy(igraph_hrg_t *hrg) {
+  igraph_vector_destroy(&hrg->left);
+  igraph_vector_destroy(&hrg->right);
+  igraph_vector_destroy(&hrg->prob);
+  igraph_vector_destroy(&hrg->edges);
+  igraph_vector_destroy(&hrg->vertices);
+}
+
+/**
+ * \function igraph_hrg_size
+ * Returns the size of the HRG, the number of leaf nodes.
+ * 
+ * \param hrg Pointer to the HRG.
+ * \return The number of leaf nodes in the HRG.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_hrg_size(const igraph_hrg_t *hrg) {
+  return igraph_vector_size(&hrg->left)+1;
+}
+
+/**
+ * \function igraph_hrg_resize
+ * Resize a HRG.
+ * 
+ * \param hrg Pointer to an initialized (see \ref igraph_hrg_init)
+ *   HRG.
+ * \param newsize The new size, i.e. the number of leaf nodes.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), n is the new size.
+ */
+
+int igraph_hrg_resize(igraph_hrg_t *hrg, int newsize) {
+  int origsize=igraph_hrg_size(hrg);
+  int ret=0;
+  igraph_error_handler_t *oldhandler =
+    igraph_set_error_handler(igraph_error_handler_ignore);
+
+  ret  = igraph_vector_resize(&hrg->left, newsize-1);
+  ret |= igraph_vector_resize(&hrg->right, newsize-1);
+  ret |= igraph_vector_resize(&hrg->prob, newsize-1);
+  ret |= igraph_vector_resize(&hrg->edges, newsize-1);
+  ret |= igraph_vector_resize(&hrg->vertices, newsize-1);
+
+  igraph_set_error_handler(oldhandler);
+
+  if (ret) { 
+    igraph_vector_resize(&hrg->left, origsize);
+    igraph_vector_resize(&hrg->right, origsize);
+    igraph_vector_resize(&hrg->prob, origsize);
+    igraph_vector_resize(&hrg->edges, origsize);
+    igraph_vector_resize(&hrg->vertices, origsize);
+    IGRAPH_ERROR("Cannot resize HRG", ret);
+  }  
+
+  return 0;
+}
+
+/**
+ * \function igraph_hrg_fit
+ * Fit a hierarchical random graph model to a network
+ * 
+ * \param graph The igraph graph to fit the model to. Edge directions
+ *   are ignored in directed graphs.
+ * \param hrg Pointer to an initialized HRG, the result of the fitting
+ *   is stored here. It can also be used to pass a HRG to the
+ *   function, that can be used as the starting point of the Markov
+ *   Chain Monte Carlo fitting, if the \c start argument is true.
+ * \param start Logical, whether to start the fitting from the given
+ *   HRG. 
+ * \param steps Integer, the number of MCMC steps to take in the
+ *   fitting procedure. If this is zero, then the fitting stop is a
+ *   convergence criteria is fulfilled.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_hrg_fit(const igraph_t *graph, 
+		   igraph_hrg_t *hrg,
+		   igraph_bool_t start,
+		   int steps) {
+  
+  int no_of_nodes=igraph_vcount(graph);
+  dendro *d;
+
+  RNG_BEGIN();
+
+  d = new dendro;  
+
+  // Convert the igraph graph
+  IGRAPH_CHECK(igraph_i_hrg_getgraph(graph, d));
+
+  // If we want to start from HRG
+  if (start) {
+    if (igraph_hrg_size(hrg) != no_of_nodes) {
+      IGRAPH_ERROR("Invalid HRG to start from", IGRAPH_EINVAL);
+    }
+    d->importDendrogramStructure(hrg);
+  } else {
+    IGRAPH_CHECK(igraph_hrg_resize(hrg, no_of_nodes));
+  }
+
+  // Run fixed number of steps, or until convergence
+  if (steps > 0) {
+    IGRAPH_CHECK(markovChainMonteCarlo(d, steps, hrg));
+  } else {
+    IGRAPH_CHECK(MCMCEquilibrium_Find(d, hrg));
+  }
+  
+  delete d;
+
+  RNG_END();
+
+  return 0;
+
+}
+
+/**
+ * \function igraph_hrg_sample
+ * Sample from a hierarchical random graph model
+ * 
+ * Sample from a hierarchical random graph ensemble. The ensemble can
+ * be given as a graph (\c input_graph), or as a HRG object (\c hrg).
+ * If a graph is given, then first an MCMC optimization is performed
+ * to find the optimal fitting model; then the MCMC is used to sample
+ * the graph(s).
+ * \param input_graph An igraph graph, or a null pointer. If not a
+ *   null pointer, then a HRG is first fitted to the graph, possibly
+ *   starting from the given HRG, if the \c start argument is true. If
+ *   is is a null pointer, then the given HRG is used as a starting
+ *   point, to  find the optimum of the Markov chain, before the
+ *   sampling.
+ * \param sample Pointer to an uninitialized graph, or a null
+ *   pointer. If only one sample is requested, and it is not a null
+ *   pointer, then the sample is stored here.
+ * \param samples An initialized vector of pointers. If more than one
+ *   samples are requested, then they are stored here. Note that to
+ *   free this data structure, you need to call \ref igraph_destroy on
+ *   each graph first, then \c free() on all pointers, and finally
+ *   \ref igraph_vector_ptr_destroy.
+ * \param no_samples The number of samples to generate.
+ * \param hrg A HRG. It is modified during the sampling.
+ * \param start Logical, whether to start the MCMC from the given
+ *   HRG.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_hrg_sample(const igraph_t *input_graph,
+		      igraph_t *sample,
+		      igraph_vector_ptr_t *samples,
+		      int no_samples,
+		      igraph_hrg_t *hrg,
+		      igraph_bool_t start) {
+
+  int i;
+  dendro *d;
+
+  if (no_samples < 0) {
+    IGRAPH_ERROR("Number of samples must be non-negative", IGRAPH_EINVAL);
+  }
+
+  if (!sample && !samples) {
+    IGRAPH_ERROR("Give at least one of `sample' and `samples'",
+		 IGRAPH_EINVAL);
+  }
+
+  if (no_samples != 1 && sample) {
+    IGRAPH_ERROR("Number of samples should be one if `sample' is given", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (no_samples > 1 && !samples) {
+    IGRAPH_ERROR("`samples' must be non-null if number of samples "
+		 "is larger than 1", IGRAPH_EINVAL);
+  }
+
+  if (!start && !input_graph) {
+    IGRAPH_ERROR("Input graph must be given if initial HRG is not used", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (!start) {
+    IGRAPH_CHECK(igraph_hrg_resize(hrg, igraph_vcount(input_graph)));
+  }
+
+  if (input_graph && igraph_hrg_size(hrg) != igraph_vcount(input_graph)) {
+    IGRAPH_ERROR("Invalid HRG size, should match number of nodes", 
+		 IGRAPH_EINVAL);
+  }
+
+  RNG_BEGIN();
+
+  d = new dendro;
+
+  // Need to find equilibrium first?
+  if (start) {
+    d->importDendrogramStructure(hrg);
+  } else {
+    IGRAPH_CHECK(MCMCEquilibrium_Find(d, hrg));
+  }
+
+  // TODO: free on error
+
+  if (sample) {
+    // A single graph
+    d->makeRandomGraph();
+    d->recordGraphStructure(sample);
+    if (samples) {
+      igraph_t *G=igraph_Calloc(1, igraph_t);
+      if (!G) { IGRAPH_ERROR("Cannot sample HRG graphs", IGRAPH_ENOMEM); }
+      d->recordGraphStructure(G);
+      IGRAPH_CHECK(igraph_vector_ptr_resize(samples, 1));
+      VECTOR(*samples)[0]=G;
+    }
+  } else {
+    // Sample many     
+    IGRAPH_CHECK(igraph_vector_ptr_resize(samples, no_samples));
+    for (i=0; i<no_samples; i++) {
+      igraph_t *G=igraph_Calloc(1, igraph_t);
+      if (!G) { IGRAPH_ERROR("Cannot sample HRG graphs", IGRAPH_ENOMEM); }
+      d->makeRandomGraph();
+      d->recordGraphStructure(G);
+      VECTOR(*samples)[i]=G;
+    }
+  }
+
+  delete d;
+
+  RNG_END();
+
+  return 0;
+}
+
+/** 
+ * \function igraph_hrg_game
+ * Generate a hierarchical random graph
+ * 
+ * This function is a simple shortcut to \ref igraph_hrg_sample. 
+ * It creates a single graph, from the given HRG.
+ * \param graph Pointer to an uninitialized graph, the new graph is
+ *   created here.
+ * \param hrg The hierarchical random graph model to sample from. It
+ *   is modified during the MCMC process.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_hrg_game(igraph_t *graph,
+		    const igraph_hrg_t *hrg) {
+  return igraph_hrg_sample(/* input_graph= */ 0, /* sample= */ graph, 
+			   /* samples= */ 0, /* no_samples=*/ 1,
+			   /* hrg= */ (igraph_hrg_t*) hrg, 
+			   /* start= */ 1);
+}
+
+/**
+ * \function igraph_hrg_dendrogram
+ * Create a dendrogram from a hierarchical random graph.
+ * 
+ * Creates the igraph graph equivalent of an \ref igraph_hrg_t data
+ * structure. 
+ * \param graph Pointer to an uninitialized graph, the result is
+ *   stored here.
+ * \param hrg The hierarchical random graph to convert.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of vertices in the graph.
+ */
+
+int igraph_hrg_dendrogram(igraph_t *graph,
+			  const igraph_hrg_t *hrg) {
+  
+  int orig_nodes=igraph_hrg_size(hrg);
+  int no_of_nodes=orig_nodes * 2 - 1;
+  int no_of_edges=no_of_nodes-1;
+  igraph_vector_t edges;
+  int i, idx=0;
+  igraph_vector_ptr_t vattrs;
+  igraph_vector_t prob;
+  igraph_attribute_record_t rec = { "probability", 
+				    IGRAPH_ATTRIBUTE_NUMERIC,
+				    &prob };
+  
+  // Probability labels, for leaf nodes they are IGRAPH_NAN
+  IGRAPH_VECTOR_INIT_FINALLY(&prob, no_of_nodes);
+  for (i=0; i<orig_nodes; i++) {
+    VECTOR(prob)[i] = IGRAPH_NAN;
+  }
+  for (i=0; i<orig_nodes-1; i++) {
+    VECTOR(prob)[orig_nodes+i] = VECTOR(hrg->prob)[i];
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2);
+  IGRAPH_CHECK(igraph_vector_ptr_init(&vattrs, 1));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattrs);
+  VECTOR(vattrs)[0] = &rec;
+
+  for (i=0; i<orig_nodes-1; i++) {
+    int left=VECTOR(hrg->left)[i];
+    int right=VECTOR(hrg->right)[i];
+
+    VECTOR(edges)[idx++] = orig_nodes+i;
+    VECTOR(edges)[idx++] = left < 0 ? orig_nodes-left-1 : left;
+    VECTOR(edges)[idx++] = orig_nodes+i;
+    VECTOR(edges)[idx++] = right < 0 ? orig_nodes-right-1 : right;
+  }
+
+  IGRAPH_CHECK(igraph_empty(graph, 0, IGRAPH_DIRECTED));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  IGRAPH_CHECK(igraph_add_vertices(graph, no_of_nodes, &vattrs));
+  IGRAPH_CHECK(igraph_add_edges(graph, &edges, 0));
+
+  igraph_vector_ptr_destroy(&vattrs);
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&prob);
+  IGRAPH_FINALLY_CLEAN(4);	// + 1 for graph
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_hrg_consensus
+ * Calculate a consensus tree for a HRG.
+ * 
+ * The calculation can be started from the given HRG (\c hrg), or (if
+ * \c start is false), a HRG is first fitted to the given graph.
+ * 
+ * \param graph The input graph.
+ * \param parents An initialized vector, the results are stored
+ *   here. For each vertex, the id of its parent vertex is stored, or
+ *   -1, 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.
+ * \param 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 \c parents.
+ * \param hrg A hierarchical random graph. It is used as a starting
+ *   point for the sampling, if the \c start argument is true. It is
+ *   modified along the MCMC.
+ * \param start Logical, whether to use the supplied HRG (in \c hrg)
+ *   as a starting point for the MCMC.
+ * \param num_samples The number of samples to generate for creating
+ *   the consensus tree.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_hrg_consensus(const igraph_t *graph,
+			 igraph_vector_t *parents,
+			 igraph_vector_t *weights,
+			 igraph_hrg_t *hrg,
+			 igraph_bool_t start, 
+			 int num_samples) {
+
+  dendro *d;
+
+  if (start && !hrg) {
+    IGRAPH_ERROR("`hrg' must be given is `start' is true", IGRAPH_EINVAL);
+  }
+
+  RNG_BEGIN();
+  
+  d = new dendro;
+  
+  IGRAPH_CHECK(igraph_i_hrg_getgraph(graph, d));
+
+  if (start) {
+    d->importDendrogramStructure(hrg);
+  } else {
+    if (hrg) { igraph_hrg_resize(hrg, igraph_vcount(graph)); }
+    IGRAPH_CHECK(MCMCEquilibrium_Find(d, hrg));
+  }
+
+  IGRAPH_CHECK(markovChainMonteCarlo2(d, num_samples));
+
+  d->recordConsensusTree(parents, weights);
+
+  delete d;
+  
+  RNG_END();
+
+  return 0;
+}
+
+int MCMCEquilibrium_Sample(dendro *d, int num_samples) {
+
+  // Because moves in the dendrogram space are chosen (Monte
+  // Carlo) so that we sample dendrograms with probability
+  // proportional to their likelihood, a likelihood-proportional
+  // sampling of the dendrogram models would be equivalent to a
+  // uniform sampling of the walk itself. We would still have to
+  // decide how often to sample the walk (at most once every n steps
+  // is recommended) but for simplicity, the code here simply runs the
+  // MCMC itself. To actually compute something over the set of
+  // sampled dendrogram models (in a Bayesian model averaging sense),
+  // you'll need to code that yourself.
+  
+  double dL;
+  bool flag_taken;
+  int sample_num=0;
+  int t=1, thresh=100 * d->g->numNodes();
+  double ptest=1.0/10.0/d->g->numNodes();
+
+  while (sample_num < num_samples) {
+    d->monteCarloMove(dL, flag_taken, 1.0);
+    if (t > thresh && RNG_UNIF01() < ptest) {
+      sample_num++;
+      d->sampleAdjacencyLikelihoods();
+    }
+    d->refreshLikelihood();	// TODO: less frequently
+    t++;
+  }
+  
+  return 0;
+}
+
+int QsortPartition (pblock* array, int left, int right, int index) {
+  pblock p_value, temp;
+  p_value.L = array[index].L;
+  p_value.i = array[index].i;
+  p_value.j = array[index].j;
+  
+  // swap(array[p_value], array[right])
+  temp.L = array[right].L;
+  temp.i = array[right].i;
+  temp.j = array[right].j;
+  array[right].L = array[index].L;
+  array[right].i = array[index].i;
+  array[right].j = array[index].j;
+  array[index].L = temp.L;
+  array[index].i = temp.i;
+  array[index].j = temp.j;
+	
+  int stored = left;
+  for (int i=left; i<right; i++) {
+    if (array[i].L <= p_value.L) {
+      // swap(array[stored], array[i])
+      temp.L = array[i].L;
+      temp.i = array[i].i;
+      temp.j = array[i].j;
+      array[i].L = array[stored].L;
+      array[i].i = array[stored].i;
+      array[i].j = array[stored].j;
+      array[stored].L = temp.L;
+      array[stored].i = temp.i;
+      array[stored].j = temp.j;
+      stored++;
+    }
+  }
+  // swap(array[right], array[stored])
+  temp.L = array[stored].L;
+  temp.i = array[stored].i;
+  temp.j = array[stored].j;
+  array[stored].L = array[right].L;
+  array[stored].i = array[right].i;
+  array[stored].j = array[right].j;
+  array[right].L  = temp.L;
+  array[right].i  = temp.i;
+  array[right].j  = temp.j;
+  
+  return stored;
+}
+
+void QsortMain (pblock* array, int left, int right) {
+  if (right > left) {
+    int pivot = left;
+    int part  = QsortPartition(array, left, right, pivot);
+    QsortMain(array, left,   part-1);
+    QsortMain(array, part+1, right  );
+  }
+  return;
+}
+
+int rankCandidatesByProbability(simpleGraph *sg, dendro *d, 
+				pblock *br_list, int mk) {
+  int mkk=0;
+  int n=sg->getNumNodes();
+  for (int i=0; i<n; i++) {
+    for (int j=i+1; j<n; j++) {
+      if (sg->getAdjacency(i, j) < 0.5) {
+	double temp=d->g->getAdjacencyAverage(i, j);
+	br_list[mkk].L = temp * (1.0 + RNG_UNIF01()/1000.0);
+	br_list[mkk].i = i;
+	br_list[mkk].j = j;
+	mkk++;
+      }
+    }
+  }
+  
+  // Sort the candidates by their average probability
+  QsortMain(br_list, 0, mk-1);  
+
+  return 0;
+}
+
+int recordPredictions(pblock *br_list, igraph_vector_t *edges, 
+		      igraph_vector_t *prob, int mk) {
+    
+  IGRAPH_CHECK(igraph_vector_resize(edges, mk*2));
+  IGRAPH_CHECK(igraph_vector_resize(prob, mk));
+  
+  for (int i=mk-1, idx=0, idx2=0; i>=0; i--) {
+    VECTOR(*edges)[idx++] = br_list[i].i;
+    VECTOR(*edges)[idx++] = br_list[i].j;
+    VECTOR(*prob)[idx2++] = br_list[i].L;
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_hrg_predict
+ * Predict missing edges in a graph, based on HRG models
+ * 
+ * Samples HRG models for a network, and estimated the probability
+ * that an edge was falsely observed as non-existent in the network.
+ * \param graph The input graph.
+ * \param edges The list of missing edges is stored here, the first
+ *   two elements are the first edge, the next two the second edge,
+ *   etc. 
+ * \param prob Vector of probabilies for the existence of missing
+ *   edges, in the order corresponding to \c edges.
+ * \param hrg A HRG, it is used as a starting point if \c start is
+ *   true. It is also modified during the MCMC sampling.
+ * \param start Logical, whether to start the MCMC from the given HRG.
+ * \param num_samples The number of samples to generate.
+ * \param num_bins Controls the resolution of the edge
+ *   probabilities. Higher numbers result higher resolution. 
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_hrg_predict(const igraph_t *graph,
+		       igraph_vector_t *edges,
+		       igraph_vector_t *prob,
+		       igraph_hrg_t *hrg,
+		       igraph_bool_t start, 
+		       int num_samples, 
+		       int num_bins) {
+
+  dendro *d;
+  pblock *br_list;
+  int mk;
+  simpleGraph *sg;
+
+  if (start && !hrg) {
+    IGRAPH_ERROR("`hrg' must be given is `start' is true", IGRAPH_EINVAL);
+  }
+
+  RNG_BEGIN();
+
+  d = new dendro;
+
+  IGRAPH_CHECK(igraph_i_hrg_getsimplegraph(graph, d, &sg, num_bins));
+
+  mk = sg->getNumNodes() * (sg->getNumNodes()-1) / 2 - sg->getNumLinks()/2;
+  br_list = new pblock[mk];
+  for (int i=0; i<mk; i++) { 
+    br_list[i].L = 0.0; 
+    br_list[i].i = -1; 
+    br_list[i].j = -1; 
+  }
+  
+  if (start) {
+    d->importDendrogramStructure(hrg);
+  } else {
+    if (hrg) { igraph_hrg_resize(hrg, igraph_vcount(graph)); }
+    IGRAPH_CHECK(MCMCEquilibrium_Find(d, hrg));
+  }
+
+  IGRAPH_CHECK(MCMCEquilibrium_Sample(d, num_samples));
+  IGRAPH_CHECK(rankCandidatesByProbability(sg, d, br_list, mk));
+  IGRAPH_CHECK(recordPredictions(br_list, edges, prob, mk));
+
+  delete d;
+  delete sg;
+  delete [] br_list;
+
+  RNG_END();
+
+  return 0;
+}
+
+/**
+ * \function igraph_hrg_create
+ * Create a HRG from an igraph graph.
+ * 
+ * \param hrg Pointer to an initialized \ref igraph_hrg_t. The result
+ *    is stored here.
+ * \param graph The igraph graph to convert. It must be a directed
+ *    binary tree, with n-1 internal and n leaf vertices. The root
+ *    vertex must have in-degree zero.
+ * \param prob The vector of probabilities, this is used to label the
+ *    internal nodes of the hierarchical random graph. The values
+ *    corresponding to the leaves are ignored.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of vertices in the tree.
+ */
+
+int igraph_hrg_create(igraph_hrg_t *hrg,
+		      const igraph_t *graph, 
+		      const igraph_vector_t *prob) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  int no_of_internal=(no_of_nodes-1)/2;
+  igraph_vector_t deg, idx;
+  int root=0;
+  int d0=0, d1=0, d2=0;
+  int ii=0, il=0;
+  igraph_vector_t neis;
+  igraph_vector_t path;
+
+  // --------------------------------------------------------
+  // CHECKS
+  // --------------------------------------------------------
+
+  // At least three vertices are required
+  if (no_of_nodes < 3) {
+    IGRAPH_ERROR("HRG tree must have at least three vertices",
+		 IGRAPH_EINVAL);
+  }
+
+  // Prob vector was given
+  if (!prob) {
+    IGRAPH_ERROR("Probability vector must be given for HRG", 
+		 IGRAPH_EINVAL);
+  }
+
+  // Length of prob vector
+  if (igraph_vector_size(prob) != no_of_nodes) {
+    IGRAPH_ERROR("HRG probability vector of wrong size", IGRAPH_EINVAL);
+  }
+
+  // Must be a directed graph
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_ERROR("HRG graph must be directed", IGRAPH_EINVAL);
+  }
+
+  // Number of nodes must be odd
+  if (no_of_nodes % 2 == 0) {
+    IGRAPH_ERROR("Complete HRG graph must have odd number of vertices", 
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, 0);
+
+  // Every vertex, except for the root must have in-degree one.
+  IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(), IGRAPH_IN,
+			     IGRAPH_LOOPS));
+  for (int i=0; i<no_of_nodes; i++) {
+    int d=VECTOR(deg)[i];
+    switch (d) {
+    case 0: d0++; root=i; break;
+    case 1: d1++; break;
+    default:
+      IGRAPH_ERROR("HRG nodes must have in-degree one, except for the "
+		   "root vertex", IGRAPH_EINVAL);
+    }
+  }
+  if (d1 != no_of_nodes-1 || d0 != 1) {
+    IGRAPH_ERROR("HRG nodes must have in-degree one, except for the "
+		 "root vertex", IGRAPH_EINVAL);
+  }
+  
+  // Every internal vertex must have out-degree two,
+  // leaves out-degree zero
+  d0=d1=d2=0;
+  IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(), IGRAPH_OUT, 
+			     IGRAPH_LOOPS));
+  for (int i=0; i<no_of_nodes; i++) {
+    int d=VECTOR(deg)[i];
+    switch (d) {
+    case 0: d0++; break;
+    case 2: d2++; break;
+    default:
+      IGRAPH_ERROR("HRG nodes must have out-degree 2 (internal nodes) or "
+		   "degree 0 (leaves)", IGRAPH_EINVAL);
+    }            
+  }
+  
+  // Number of internal and external nodes is correct
+  // This basically checks that the graph has one component
+  if (d0 != d2+1) {
+    IGRAPH_ERROR("HRG degrees are incorrect, maybe multiple components?",
+		 IGRAPH_EINVAL);
+  }
+  
+  // --------------------------------------------------------
+  // Graph is good, do the conversion
+  // --------------------------------------------------------
+
+  // Create an index, that maps the root node as first, then
+  // the internal nodes, then the leaf nodes
+  IGRAPH_VECTOR_INIT_FINALLY(&idx, no_of_nodes);
+  VECTOR(idx)[root] = - (ii++) - 1;
+  for (int i=0; i<no_of_nodes; i++) {
+    int d=VECTOR(deg)[i];
+    if (i==root) { continue; }
+    if (d==2) { VECTOR(idx)[i] = - (ii++) - 1; }
+    if (d==0) { VECTOR(idx)[i] = (il++); }
+  }
+
+  igraph_hrg_resize(hrg, no_of_internal+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  for (int i=0; i<no_of_nodes; i++) {
+    int ri=VECTOR(idx)[i];
+    if (ri >= 0) { continue; }
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, IGRAPH_OUT));
+    VECTOR(hrg->left )[-ri-1] = VECTOR(idx)[ (int) VECTOR(neis)[0] ];
+    VECTOR(hrg->right)[-ri-1] = VECTOR(idx)[ (int) VECTOR(neis)[1] ];
+    VECTOR(hrg->prob )[-ri-1] = VECTOR(*prob)[i];
+  }
+
+  // Calculate the number of vertices and edges in each subtree
+  igraph_vector_null(&hrg->edges);
+  igraph_vector_null(&hrg->vertices);
+  IGRAPH_VECTOR_INIT_FINALLY(&path, 0);
+  IGRAPH_CHECK(igraph_vector_push_back(&path, VECTOR(idx)[root]));
+  while (!igraph_vector_empty(&path)) {
+    int ri=igraph_vector_tail(&path);
+    int lc=VECTOR(hrg->left)[-ri-1];
+    int rc=VECTOR(hrg->right)[-ri-1];
+    if (lc < 0 && VECTOR(hrg->vertices)[-lc-1]==0) {
+      // Go left
+      IGRAPH_CHECK(igraph_vector_push_back(&path, lc));
+    } else if (rc < 0 && VECTOR(hrg->vertices)[-rc-1]==0) {
+      // Go right
+      IGRAPH_CHECK(igraph_vector_push_back(&path, rc));
+    } else {
+      // Subtrees are done, update node and go up
+      VECTOR(hrg->vertices)[-ri-1] += 
+	lc < 0 ? VECTOR(hrg->vertices)[-lc-1] : 1;
+      VECTOR(hrg->vertices)[-ri-1] += 
+	rc < 0 ? VECTOR(hrg->vertices)[-rc-1] : 1;
+      VECTOR(hrg->edges)[-ri-1] += lc < 0 ? VECTOR(hrg->edges)[-lc-1]+1 : 1;
+      VECTOR(hrg->edges)[-ri-1] += rc < 0 ? VECTOR(hrg->edges)[-rc-1]+1 : 1;
+      igraph_vector_pop_back(&path);
+    }
+  }
+
+  igraph_vector_destroy(&path);
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&idx);
+  igraph_vector_destroy(&deg);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
diff --git a/src/igraph_hrg_types.cc b/src/igraph_hrg_types.cc
new file mode 100644
index 0000000..e4d0fcb
--- /dev/null
+++ b/src/igraph_hrg_types.cc
@@ -0,0 +1,3470 @@
+// ***********************************************************************
+// *** COPYRIGHT NOTICE **************************************************
+// rbtree - red-black tree (self-balancing binary tree data structure)
+// Copyright (C) 2004 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ***********************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu |
+//                                 http://www.santafe.edu/~aaronc/ ) 
+// Collaborators: Cristopher Moore and Mark Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science
+//                AND Santa Fe Institute 
+// Created      : Spring 2004
+// Modified     : many, many times
+//
+// ***********************************************************************
+
+#include "hrg_rbtree.h"
+#include "hrg_dendro.h"
+#include "hrg_graph.h"
+#include "hrg_splittree_eq.h"
+#include "hrg_graph_simp.h"
+
+#include "igraph_hrg.h"
+#include "igraph_constructors.h"
+#include "igraph_random.h"
+
+using namespace fitHRG;
+
+// ******** Red-Black Tree Methods ***************************************
+
+rbtree::rbtree() {
+  root = new elementrb;
+  leaf = new elementrb;
+
+  leaf->parent = root;
+  
+  root->left = leaf;
+  root->right = leaf;
+  support = 0;
+}
+
+rbtree::~rbtree() {
+  if (root != NULL && 
+      (root->left != leaf || root->right != leaf)) { 
+    deleteSubTree(root); 
+  }
+  if (root) delete root;
+  delete leaf;
+  support = 0;
+  root = 0;
+  leaf = 0;
+}
+
+void rbtree::deleteTree() { 
+  if (root != NULL) { deleteSubTree(root); }
+} // does not leak memory
+
+void rbtree::deleteSubTree(elementrb *z) {
+  if (z->left  != leaf) { deleteSubTree(z->left);  }
+  if (z->right != leaf) { deleteSubTree(z->right); }
+  delete z;
+}
+
+// ******** Search Functions *********************************************
+// public search function - if there exists a elementrb in the tree
+// with key=searchKey, it returns TRUE and foundNode is set to point
+// to the found node; otherwise, it sets foundNode=NULL and returns
+// FALSE
+elementrb* rbtree::findItem(const int searchKey) {
+  elementrb *current=root;
+
+  // empty tree; bail out
+  if (current->key==-1) { return NULL; }
+
+  while (current != leaf) {
+    // left-or-right?
+    if (searchKey < current->key) {
+      // try moving down-left
+      if (current->left  != leaf) { 
+	current = current->left;  
+      } else { 
+	//   failure; bail out
+	return NULL; 
+      }	
+    } else {
+      // left-or-right?
+      if (searchKey > current->key) {
+	// try moving down-left
+	if (current->right  != leaf) { 
+	  current = current->right;  
+	} else { 
+	  // failure; bail out
+	  return NULL; 
+	}
+      } else { 
+	// found (searchKey==current->key)
+	return current; 
+      }
+    }
+  }
+  return NULL;
+}
+
+int rbtree::returnValue(const int searchKey) {
+  elementrb* test = findItem(searchKey);
+  if (!test) { return 0; } else { return test->value; }
+}
+
+
+// ******** Return Item Functions ****************************************
+
+int* rbtree::returnArrayOfKeys() {
+  int* array;
+  array = new int [support];
+  bool flag_go = true;
+  int index = 0;
+  elementrb *curr;
+
+  if (support == 1) { 
+    array[0] = root->key; 
+  } else if (support == 2) {
+    array[0] = root->key;
+    if (root->left == leaf) { 
+      array[1] = root->right->key; 
+    } else { 
+      array[1] = root->left->key; 
+    }
+  } else {
+    for (int i=0; i<support; i++) { array[i] = -1; }
+    // non-recursive traversal of tree structure
+    curr = root;
+    curr->mark = 1;
+    while (flag_go) {
+      // - is it time, and is left child the leaf node?
+      if (curr->mark == 1 && curr->left == leaf) {
+	curr->mark = 2;	
+      }
+      // - is it time, and is right child the leaf node?
+      if (curr->mark == 2 && curr->right == leaf) {
+	curr->mark = 3;	
+      }
+      if (curr->mark == 1) {
+	// - go left
+	curr->mark = 2;
+	curr = curr->left;
+	curr->mark = 1;
+      } else if (curr->mark == 2) {
+	// - else go right
+	curr->mark = 3;
+	curr = curr->right;
+	curr->mark = 1;
+      } else {
+	// - else go up a level
+	curr->mark = 0;
+	array[index++] = curr->key;
+	curr = curr->parent;
+	if (curr == NULL) { flag_go = false; }
+      }
+    }
+  }
+	
+  return array;
+}
+
+list* rbtree::returnListOfKeys() {
+  keyValuePair *curr, *prev;
+  list *head=0, *tail=0, *newlist;
+
+  curr = returnTreeAsList();
+  while (curr != NULL) {
+    newlist = new list;
+    newlist->x = curr->x;
+    if (head == NULL) { 
+      head       = newlist; tail = head;    
+    } else { 
+      tail->next = newlist; tail = newlist; 
+    }
+    prev = curr;
+    curr = curr->next;
+    delete prev;
+    prev = NULL;
+  }
+  return head;
+}
+
+keyValuePair* rbtree::returnTreeAsList() {
+  // pre-order traversal
+  keyValuePair  *head, *tail;
+
+  head = new keyValuePair;
+  head->x = root->key;
+  head->y = root->value;
+  tail = head;
+  
+  if (root->left  != leaf) { tail = returnSubtreeAsList(root->left,  tail); }
+  if (root->right != leaf) { tail = returnSubtreeAsList(root->right, tail); }
+  
+  if (head->x == -1) { return NULL; /* empty tree */ } else { return head; }
+}
+
+keyValuePair* rbtree::returnSubtreeAsList(elementrb *z, keyValuePair *head) {
+  keyValuePair *newnode, *tail;
+	
+  newnode = new keyValuePair;
+  newnode->x = z->key;
+  newnode->y = z->value;
+  head->next = newnode;
+  tail = newnode;
+	
+  if (z->left  != leaf) { tail = returnSubtreeAsList(z->left,  tail); }
+  if (z->right != leaf) { tail = returnSubtreeAsList(z->right, tail); }
+	
+  return tail;
+}
+
+keyValuePair rbtree::returnMaxKey() {
+  keyValuePair themax;
+  elementrb *current;
+  current  = root;
+
+  // search to bottom-right corner of tree
+  while (current->right != leaf) { 
+    current  = current->right; 
+  }
+  themax.x = current->key;
+  themax.y = current->value;
+
+  return themax;
+}
+
+keyValuePair rbtree::returnMinKey() {
+  keyValuePair themin;
+  elementrb *current;
+  current = root;
+  // search to bottom-left corner of tree
+  while (current->left != leaf) {
+    current = current->left; 
+  }
+  themin.x = current->key;
+  themin.y = current->value;
+  
+  return themin;
+}
+
+// private functions for deleteItem() (although these could easily be
+// made public, I suppose) 
+elementrb* rbtree::returnMinKey(elementrb *z) {
+  elementrb *current;
+
+  current = z;
+  // search to bottom-right corner of tree
+  while (current->left != leaf) {
+		current = current->left; 
+  }
+  return current;
+}
+
+elementrb* rbtree::returnSuccessor(elementrb *z) {
+  elementrb *current, *w;
+	
+  w = z;
+  // if right-subtree exists, return min of it
+  if (w->right != leaf) {
+    return returnMinKey(w->right); 
+  }
+  // else search up in tree
+  current = w->parent;
+  while ((current!=NULL) && (w==current->right)) {
+    w = current;
+    // move up in tree until find a non-right-child
+    current = current->parent;
+  }
+  return current;
+}
+
+int rbtree::returnNodecount() { return support; }
+
+// ******** Insert Functions *********************************************
+// public insert function
+void rbtree::insertItem(int newKey, int newValue) {
+	
+  // first we check to see if newKey is already present in the tree;
+  // if so, we do nothing; if not, we must find where to insert the
+  // key
+  elementrb *newNode, *current;
+
+  // find newKey in tree; return pointer to it O(log k)
+  current = findItem(newKey);
+  if (current == NULL) {
+    newNode = new elementrb;    // elementrb for the rbtree
+    newNode->key = newKey;
+    newNode->value = newValue;
+    newNode->color = true;	// new nodes are always RED
+    newNode->parent = NULL;	// new node initially has no parent
+    newNode->left = leaf;	// left leaf
+    newNode->right = leaf;	// right leaf
+    support++;			// increment node count in rbtree
+		
+    // must now search for where to insert newNode, i.e., find the
+    // correct parent and set the parent and child to point to each
+    // other properly
+    current = root;
+    if (current->key==-1) {	     // insert as root
+      delete root;		     // delete old root
+      root = newNode;		     // set root to newNode
+      leaf->parent = newNode;	     // set leaf's parent
+      current = leaf;		     // skip next loop
+    }
+		
+    // search for insertion point
+    while (current != leaf) {
+      // left-or-right?
+      if (newKey < current->key) {
+	// try moving down-left
+	if (current->left  != leaf) { 
+	  current = current->left;  
+	} else {
+	  // else found new parent
+	  newNode->parent = current; // set parent
+	  current->left = newNode;   // set child
+	  current = leaf;	     // exit search
+	}
+      } else {
+	// try moving down-right
+	if (current->right != leaf) { 
+	  current = current->right; 
+	} else {
+	  // else found new parent
+	  newNode->parent = current; // set parent
+	  current->right = newNode;  // set child
+	  current = leaf;	     // exit search
+	}
+      }
+    }
+
+    // now do the house-keeping necessary to preserve the red-black
+    // properties 
+    insertCleanup(newNode);
+  }
+  return;
+}
+
+// private house-keeping function for insertion
+void rbtree::insertCleanup(elementrb *z) {
+	
+  // fix now if z is root
+  if (z->parent==NULL) {
+    z->color = false; 
+    return; 
+  }
+
+  elementrb *temp;
+
+  // while z is not root and z's parent is RED
+  while (z->parent!=NULL && z->parent->color) {
+    if (z->parent == z->parent->parent->left) {
+
+      // z's parent is LEFT-CHILD
+
+      temp = z->parent->parent->right;   // grab z's uncle
+      if (temp->color) {
+	z->parent->color = false;        // color z's parent BLACK  (Case 1)
+	temp->color = false;             // color z's uncle BLACK   (Case 1)
+	z->parent->parent->color = true; // color z's grandpar. RED (Case 1)
+	z = z->parent->parent;	         // set z = z's grandparent (Case 1)
+      } else {
+	if (z == z->parent->right) {
+	  // z is RIGHT-CHILD
+	  z = z->parent;	         // set z = z's parent      (Case 2)
+	  rotateLeft(z);	         // perform left-rotation   (Case 2)
+	}
+	z->parent->color = false;        // color z's parent BLACK  (Case 3)
+	z->parent->parent->color = true; // color z's grandpar. RED (Case 3)
+	rotateRight(z->parent->parent);  // perform right-rotation  (Case 3)
+      }
+    } else {
+
+      // z's parent is RIGHT-CHILD      
+
+      temp = z->parent->parent->left;    // grab z's uncle
+      if (temp->color) {
+	z->parent->color = false;        // color z's parent BLACK  (Case 1)
+	temp->color = false;	         // color z's uncle BLACK   (Case 1)
+	z->parent->parent->color = true; // color z's grandpar. RED (Case 1)
+	z = z->parent->parent;	         // set z = z's grandparent (Case 1)
+      } else {
+	if (z == z->parent->left) { 
+	  // z is LEFT-CHILD
+	  z = z->parent;                 // set z = z's parent      (Case 2)
+	  rotateRight(z);                // perform right-rotation  (Case 2)
+	}
+	z->parent->color = false;        // color z's parent BLACK  (Case 3)
+	z->parent->parent->color = true; // color z's grandpar. RED (Case 3)
+	rotateLeft(z->parent->parent);	 // perform left-rotation   (Case 3)
+      }
+    }
+  }
+
+  root->color = false;		         // color the root BLACK
+  return;
+}
+
+// ******** Delete
+// ******** Functions *********************************************
+
+void rbtree::replaceItem(int key, int newValue) {
+  elementrb* ptr;
+  ptr = findItem(key);
+  ptr->value = newValue;
+  return;
+}
+ 
+void rbtree::incrementValue(int key) {
+  elementrb* ptr;
+  ptr = findItem(key);
+  ptr->value = 1+ptr->value;
+  return;
+}
+
+// public delete function
+void rbtree::deleteItem(int killKey) {
+  elementrb *x, *y, *z;
+	
+  z = findItem(killKey);
+  if (z == NULL) { return; } 	  // item not present; bail out
+
+  if (support==1) {		  // attempt to delete the root
+    root->key = -1;		  // restore root node to default state
+    root->value = -1;
+    root->color = false;
+    root->parent = NULL;
+    root->left = leaf;
+    root->right = leaf;
+    support--;			  // set support to zero
+    return;			  // exit - no more work to do
+  }
+	
+  if (z != NULL) {
+    support--;		 	  // decrement node count
+    if ((z->left == leaf) || (z->right==leaf)) {
+      y = z;	                  // case of less than two children, 
+				  // set y to be z
+    } else { 
+      y = returnSuccessor(z);  	  // set y to be z's key-successor
+    } 
+
+    if (y->left!=leaf) {
+      x = y->left;		  // pick y's one child (left-child)
+    } else { 
+      x = y->right;	  	  // (right-child)
+    }
+    x->parent = y->parent;        // make y's child's parent be y's parent
+
+    if (y->parent==NULL) { 
+      root = x;			  // if y is the root, x is now root
+    } else {
+      if (y == y->parent->left) { // decide y's relationship with y's parent
+	y->parent->left  = x;     // replace x as y's parent's left child
+      } else {
+	y->parent->right = x;     // replace x as y's parent's left child
+      }
+    }
+
+    if (y!=z) {			  // insert y into z's spot
+      z->key = y->key;		  // copy y data into z
+      z->value = y->value;
+    }
+
+    // do house-keeping to maintain balance
+    if (y->color==false) { deleteCleanup(x); }
+
+    delete y;
+    y = NULL;
+  }
+		
+  return;
+}
+
+void rbtree::deleteCleanup(elementrb *x) {
+  elementrb *w, *t;
+  
+  // until x is the root, or x is RED
+  while ((x != root) && (x->color==false)) {
+    if (x==x->parent->left) {	  // branch on x being a LEFT-CHILD
+      w = x->parent->right;	  // grab x's sibling
+      if (w->color==true) {	  // if x's sibling is RED
+	w->color = false;	  // color w BLACK (case 1)
+	x->parent->color = true;  // color x's parent RED            (case 1)
+	rotateLeft(x->parent);    // left rotation on x's parent     (case 1)
+	w = x->parent->right;     // make w be x's right sibling     (case 1)
+      }
+      if ((w->left->color==false) && (w->right->color==false)) {
+	w->color = true;	  // color w RED                     (case 2)
+	x = x->parent;		  // examine x's parent              (case 2)
+      } else {
+	if (w->right->color==false) {
+	  w->left->color = false; // color w's left child BLACK	     (case 3)
+	  w->color = true;	  // color w RED                     (case 3)
+	  t = x->parent;	  // store x's parent                (case 3)
+	  rotateRight(w);	  // right rotation on w             (case 3)
+	  x->parent = t;	  // restore x's parent              (case 3)
+	  w = x->parent->right;	  // make w be x's right sibling     (case 3)
+	}
+	w->color = x->parent->color; // w's color := x's parent's    (case 4)
+	x->parent->color = false; // color x's parent BLACK          (case 4)
+	w->right->color	= false;  // color w's right child BLACK     (case 4)
+	rotateLeft(x->parent);    // left rotation on x's parent     (case 4)
+	x = root;                 // finished work. bail out         (case 4)
+      }
+    } else {			    // x is RIGHT-CHILD
+      w = x->parent->left;	    // grab x's sibling
+      if (w->color==true) {	    // if x's sibling is RED
+	w->color = false;	    // color w BLACK                 (case 1)
+	x->parent->color    = true; // color x's parent RED          (case 1)
+	rotateRight(x->parent);	    // right rotation on x's parent  (case 1)
+	w = x->parent->left;        // make w be x's left sibling    (case 1)
+      }
+      if ((w->right->color==false) && (w->left->color==false)) {
+	w->color = true;	    // color w RED                   (case 2)
+	x= x->parent;		    // examine x's parent            (case 2)
+      } else {
+	if (w->left->color==false) {
+	  w->right->color = false;  // color w's right child BLACK   (case 3)
+	  w->color = true;	    // color w RED                   (case 3)
+	  t = x->parent;	    // store x's parent              (case 3)
+	  rotateLeft(w);	    // left rotation on w            (case 3)
+	  x->parent = t;	    // restore x's parent            (case 3)
+	  w = x->parent->left;	    // make w be x's left sibling    (case 3)
+	}
+	w->color = x->parent->color; // w's color := x's parent's    (case 4)
+	x->parent->color    = false; // color x's parent BLACK       (case 4)
+	w->left->color = false;      // color w's left child BLACK   (case 4)
+	rotateRight(x->parent);      // right rotation on x's parent (case 4)
+	x = root;		     // x is now the root            (case 4)
+      }
+    }
+  }
+  x->color = false;		     // color x (the root) BLACK (exit)
+
+  return;
+}
+
+// ******** Rotation Functions ******************************************
+
+void rbtree::rotateLeft(elementrb *x) {
+  elementrb *y;
+  // do pointer-swapping operations for left-rotation
+  y = x->right;		     // grab right child
+  x->right = y->left;	     // make x's RIGHT-CHILD be y's LEFT-CHILD
+  y->left->parent = x;	     // make x be y's LEFT-CHILD's parent
+  y->parent = x->parent;     // make y's new parent be x's old parent
+
+  if (x->parent==NULL) { 
+    root = y;			// if x was root, make y root
+  } else {
+    // if x is LEFT-CHILD, make y be x's parent's
+    if (x == x->parent->left) { 
+      x->parent->left  = y;	// left-child
+    } else { 
+      x->parent->right = y;	//  right-child
+    }
+  }
+  y->left   = x;		// make x be y's LEFT-CHILD
+  x->parent = y;		// make y be x's parent
+ 
+  return;
+}
+
+void rbtree::rotateRight(elementrb *y) {
+  elementrb *x;
+  // do pointer-swapping operations for right-rotation
+  x = y->left;		  // grab left child
+  y->left = x->right;	  // replace left child yith x's right subtree
+  x->right->parent = y;	  // replace y as x's right subtree's parent
+ 
+  x->parent = y->parent;  // make x's new parent be y's old parent
+
+  // if y was root, make x root
+  if (y->parent==NULL) { 
+    root = x; 
+  } else {
+    // if y is RIGHT-CHILD, make x be y's parent's
+    if (y == y->parent->right) {
+      // right-child
+      y->parent->right = x; 
+    } else { 
+      // left-child
+      y->parent->left = x; 
+    }
+  }
+  x->right  = y;		// make y be x's RIGHT-CHILD
+  y->parent = x;		// make x be y's parent
+ 
+  return;
+}
+
+// ***********************************************************************
+// *** COPYRIGHT NOTICE **************************************************
+// dendro.h - hierarchical random graph (hrg) data structure
+// Copyright (C) 2005-2009 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ***********************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu |
+//                                 http://www.santafe.edu/~aaronc/ ) 
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science
+//                AND Santa Fe Institute 
+// Created      : 26 October 2005 - 7 December 2005
+// Modified     : 23 December 2007 (cleaned up for public consumption)
+//
+// ***********************************************************************
+// 
+// Maximum likelihood dendrogram data structure. This is the heart of
+// the HRG algorithm: all manipulations are done here and all data is
+// stored here. The data structure uses the separate graph data
+// structure to store the basic adjacency information (in a
+// dangerously mutable way).
+// 
+// ***********************************************************************
+
+// ******** Dendrogram Methods *******************************************
+
+dendro::dendro(): root(0), internal(0), leaf(0), d(0), splithist(0),
+		  paths(0), ctree(0), cancestor(0), g(0) { }
+dendro::~dendro() {
+  list *curr, *prev;
+  
+  if (g)        { delete    g;         g        =0; } // O(m)
+  if (internal) { delete [] internal;  internal =0; } // O(n)
+  if (leaf)     { delete [] leaf;      leaf     =0; } // O(n)
+  if (d)        { delete    d;         d        =0; } // O(n)
+  if (splithist){ delete    splithist; splithist=0; } // potentially long
+
+  if (paths) { 
+    for (int i=0; i<n; i++) { 
+      curr = paths[i]; 
+      while (curr) { 
+	prev = curr;   
+	curr = curr->next;   
+	delete prev;   
+	prev = 0; 
+      } 
+      paths[i] = 0; 
+    } 
+    delete [] paths; 
+  } 
+  paths=0;
+
+  if (ctree)    { delete [] ctree;     ctree     = 0; } // O(n)
+  if (cancestor){ delete [] cancestor; cancestor = 0; } // O(n)
+}
+
+// *********************************************************************
+
+void dendro::binarySearchInsert(elementd* x, elementd* y) {
+  if (y->p < x->p) {		// go to left subtree
+    if (x->L == NULL) {		// check if left subtree is empty
+      x->L = y;			// make x left child
+      y->M = x;			// make y parent of child
+      return;
+    } else { 
+      binarySearchInsert(x->L, y); 
+    }
+  } else {			// go to right subtree
+    if (x->R == NULL) {		// check if right subtree is empty
+      x->R = y;			// make x right child
+      y->M = x;			// make y parent of child
+      return;
+    } else { 
+      binarySearchInsert(x->R, y); 
+    }
+  }
+  return;
+}
+
+// **********************************************************************
+
+list* dendro::binarySearchFind(const double v) {
+  list *head = NULL, *tail = NULL, *newlist;
+  elementd *current = root;
+  bool flag_stopSearch = false;
+ 
+  while (!flag_stopSearch) {	// continue until we're finished
+    newlist    = new list;	// add this node to the path
+    newlist->x = current->label;
+    if (current == root) { 
+      head = newlist; tail = head;    
+    } else { 
+      tail->next = newlist; tail = newlist; 
+    }
+    if (v < current->p) {	// now try left subtree
+      if (current->L->type == GRAPH) { 
+        flag_stopSearch = true;       
+      } else { 
+        current = current->L; 
+      }
+    } else {			// else try right subtree
+      if (current->R->type == GRAPH) { 
+        flag_stopSearch = true;       
+      } else  { 
+        current = current->R; 
+      }
+    }
+  }
+  return head;
+}
+
+// ***********************************************************************
+
+string dendro::buildSplit(elementd* thisNode) {
+  // A "split" is defined as the bipartition of vertices into the sets
+  // of leaves below the internal vertex in the tree (denoted by "C"),
+  // and those above it (denoted as "M"). For simplicity, we represent
+  // this bipartition as a character string of length n, where the ith
+  // character denotes the partition membership (C,M) of the ith leaf
+  // node.
+
+  bool flag_go = true;
+  const short int k = 1+DENDRO+GRAPH;
+  elementd* curr;
+  split sp;
+
+  sp.initializeSplit(n);      // default split string O(n)
+ 
+  curr = thisNode;	      // - set start node as top this sub-tree
+  curr->type = k+1;	      // - initialize in-order tree traversal
+  while (flag_go) { 
+
+    // - is it time, and is left child a graph node?
+    if (curr->type == k+1 && curr->L->type == GRAPH) {
+      sp.s[curr->L->index] = 'C'; // - mark this leaf
+      curr->type = k+2;
+    }
+
+    // - is it time, and is right child a graph node?
+    if (curr->type == k+2 && curr->R->type == GRAPH) {
+      sp.s[curr->R->index] = 'C'; // - mark this leaf
+      curr->type           = k+3;
+    }
+    if (curr->type == k+1) {	  // - go left
+      curr->type = k+2;
+      curr       = curr->L;
+      curr->type = k+1; }
+    else if (curr->type == k+2) { // - else go right
+      curr->type = k+3;
+      curr       = curr->R;
+      curr->type = k+1; 
+    } else {		  	  // - else go up a level
+      curr->type = DENDRO;
+      if (curr->index == thisNode->index || curr->M == NULL) { 
+	flag_go = false; curr = NULL; 
+      } else { 
+	curr = curr->M; 
+      }
+    }
+  }
+
+  // any leaf that was not already marked must be in the remainder of
+  // the tree
+  for (int i=0; i<n; i++) { if (sp.s[i] != 'C') { sp.s[i] = 'M'; } }
+
+  return sp.s;
+}
+
+// **********************************************************************
+
+void dendro::buildDendrogram() {
+ 
+  /* the initialization of the dendrogram structure goes like this: 
+   * 1) we allocate space for the n-1 internal nodes of the
+   *    dendrogram, and then the n leaf nodes 
+   * 2) we build a random binary tree structure out of the internal
+   *    nodes by assigning each a uniformly random value over [0,1] and
+   *    then inserting it into the tree according to the  
+   *    binary-search rule.
+   * 3) next, we make a random permutation of the n leaf nodes and add
+   *    them to the dendrogram D by replacing the emptpy spots in-order
+   * 4) then, we compute the path from the root to each leaf and store
+   *    that in each leaf (this is prep work for the next step)
+   * 5) finally, we compute the values for nL, nR, e (and thus p) and
+   *    the label for each internal node by allocating each of the m
+   *    edges in g to the appropriate internal node 
+   */
+ 
+  // --- Initialization and memory allocation for data structures 
+  // After allocating the memory for D and G, we need to mark the
+  // nodes for G as being non-internal vertices, and then insert them
+  // into a random binary tree structure. For simplicity, we make the
+  // first internal node in the array the root.
+
+  n = g->numNodes();		  // size of graph
+  leaf = new elementd [n];	  // allocate memory for G, O(n)
+  internal  = new elementd [n-1]; // allocate memory for D, O(n)
+  d = new interns(n-2);	          // allocate memory for internal
+				  // edges of D, O(n) 
+  for (int i=0; i<n; i++) {	  // initialize leaf nodes
+    leaf[i].type   = GRAPH;
+    leaf[i].label  = i;
+    leaf[i].index  = i;
+    leaf[i].n = 1;
+  }
+
+ // initialize internal nodes
+  root = &internal[0];
+  root->label = 0;
+  root->index = 0;
+  root->p = RNG_UNIF01();
+
+  // insert remaining internal vertices, O(n log n)
+  for (int i=1; i<(n-1); i++) {
+    internal[i].label = i;
+    internal[i].index = i;
+    internal[i].p = RNG_UNIF01();
+    binarySearchInsert(root, &internal[i]);
+  }
+ 
+  // --- Hang leaf nodes off end of dendrogram O(n log n)
+  // To impose this random hierarchical relationship on G, we first
+  // take a random permutation of the leaf vertices and then replace
+  // the NULLs at the bottom of the tree in-order with the leafs. As a
+  // hack to ensure that we can find the leafs later using a binary
+  // search, we assign each of them the p value of their parent,
+  // perturbed slightly so as to preserve the binary search property.
+
+  block* array; array = new block [n];
+  for (int i=0; i<n; i++) { array[i].x = RNG_UNIF01();  array[i].y = i; }
+  QsortMain(array, 0, n-1);
+
+  int k=0;			// replace NULLs with leaf nodes, and
+  for (int i=0; i<(n-1); i++) { // maintain binary search property, O(n)
+    if (internal[i].L == NULL) {
+      internal[i].L = &leaf[array[k].y];
+      leaf[array[k].y].M = &internal[i];
+      leaf[array[k++].y].p = internal[i].p - 0.0000000000001;
+    }
+    if (internal[i].R == NULL) {
+      internal[i].R = &leaf[array[k].y];
+      leaf[array[k].y].M = &internal[i];
+      leaf[array[k++].y].p = internal[i].p + 0.0000000000001;
+    }
+  }
+  delete [] array;
+
+  // --- Compute the path from root -> leaf for each leaf O(n log n) 
+  // Using the binary search property, we can find each leaf node in
+  // O(log n) time. The binarySearchFind() function returns the list
+  // of internal node indices that the search crossed, in the order of
+  // root -> ... -> leaf, for use in the subsequent few operations.
+
+  if (paths != NULL) { 
+    list *curr, *prev; 
+    for (int i=0; i<n; i++) { 
+      curr = paths[i]; 
+      while (curr != NULL) { 
+	prev = curr;
+	curr = curr->next;  
+	delete prev;
+	prev = NULL; 
+      } 
+      paths[i] = NULL; 
+    } 
+    delete [] paths; 
+  }
+  paths = NULL;
+  paths = new list* [n];
+  for (int i=0; i<n; i++) { paths[i] = binarySearchFind(leaf[i].p); }
+ 
+  // --- Count e for each internal node O(m)
+  // To count the number of edges that span the L and R subtrees for
+  // each internal node, we use the path information we just
+  // computed. Then, we loop over all edges in G and find the common
+  // ancestor in D of the two endpoints and increment that internal
+  // node's e count. This process takes O(m) time because in a roughly
+  // balanced binary tree (given by our random dendrogram), the vast
+  // majority of vertices take basically constant time to find their
+  // common ancestor. Note that because our adjacency list is
+  // symmetric, we overcount each e by a factor of 2, so we need to
+  // correct this after.
+
+  elementd* ancestor; edge* curr;
+  for (int i=0; i<(n-1); i++) { internal[i].e = 0; internal[i].label = -1; }
+  for (int i=0; i<n; i++) {
+    curr = g->getNeighborList(i);
+    while (curr != NULL) {
+      ancestor = findCommonAncestor(paths, i, curr->x);
+      ancestor->e += 1;
+      curr = curr->next;
+    }
+  }
+  for (int i=0; i<(n-1); i++) { internal[i].e /= 2; }   
+
+  // --- Count n for each internal node O(n log n)
+  // To tabulate the number of leafs in each subtree rooted at an
+  // internal node, we use the path information computed above.
+  for (int i=0; i<n; i++) {
+    ancestor = &leaf[i];
+    ancestor = ancestor->M;
+    while (ancestor != NULL) {
+      ancestor->n++;
+      ancestor = ancestor->M;
+    }
+  }
+ 
+  // --- Label all internal vertices O(n log n)
+  // We want to label each internal vertex with the smallest leaf
+  // index of its children. This will allow us to collapse many
+  // leaf-orderings into a single dendrogram structure that is
+  // independent of child-exhanges (since these have no impact on the
+  // likelihood of the hierarchical structure). To do this, we loop
+  // over the leaf vertices from smallest to largest and walk along
+  // that leaf's path from the root. If we find an unlabeled internal
+  // node, then we mark it with this leaf's index.
+
+  for (int i=0; i<n; i++) {
+    ancestor = &leaf[i];
+    while (ancestor != NULL) {
+      if (ancestor->label == -1 || ancestor->label > leaf[i].label) { 
+	ancestor->label = leaf[i].label; 
+      }
+      ancestor = ancestor->M;
+    }
+  }
+ 
+  // --- Exchange children to enforce order-property O(n)
+  // We state that the order-property requires that an internal node's
+  // label is the smallest index of its left subtree. The dendrogram
+  // so far doesn't reflect this, so we need to step through each
+  // internal vertex and make that adjustment (swapping nL and nR if
+  // we make a change).
+
+  elementd *tempe;
+  for (int i=0; i<(n-1); i++) {
+    if (internal[i].L->label > internal[i].label) {
+      tempe = internal[i].L;
+      internal[i].L = internal[i].R;
+      internal[i].R = tempe;
+    }
+  }
+
+  // --- Tabulate internal dendrogram edges O(n^2)
+  // For the MCMC moves later on, we'll need to be able to choose,
+  // uniformly at random, an internal edge of the dendrogram to
+  // manipulate. There are always n-2 of them, and we can find them
+  // simply by scanning across the internal vertices and observing
+  // which have children that are also internal vertices. Note: very
+  // important that the order property be enforced before this step is
+  // taken; otherwise, the internal edges wont reflect the actual
+  // dendrogram structure.
+ 
+  for (int i=0; i<(n-1); i++) {
+    if (internal[i].L->type == DENDRO) { 
+      d->addEdge(i, internal[i].L->index, LEFT); 
+    }
+    if (internal[i].R->type == DENDRO) { 
+      d->addEdge(i, internal[i].R->index, RIGHT); 
+    }
+  } 
+ 
+  // --- Clear memory for paths O(n log n)
+  // Now that we're finished using the paths, we need to deallocate
+  // them manually.
+
+  list *current, *previous;
+  for (int i=0; i<n; i++) {
+    current = paths[i];
+    while (current) {
+      previous = current; 
+      current = current->next;
+      delete previous;
+      previous = NULL; 
+    }
+    paths[i] = NULL;
+  }
+  delete [] paths;
+  paths = NULL;
+ 
+  // --- Compute p_i for each internal node O(n)
+  // Each internal node's p_i = e_i / (nL_i*nR_i), and now that we
+  // have each of those pieces, we may calculate this value for each
+  // internal node. Given these, we can then calculate the
+  // log-likelihood of the entire dendrogram structure \log(L) =
+  // \sum_{i=1}^{n} ( ( e_i \log[p_i] ) + ( (nL_i*nR_i - e_i)
+  // \log[1-p_i] ) )
+
+  L = 0.0; double dL;
+  int nL_nR, ei;
+  for (int i=0; i<(n-1); i++) {
+    nL_nR = internal[i].L->n*internal[i].R->n;
+    ei = internal[i].e;
+    internal[i].p = (double)(ei) / (double)(nL_nR);
+    if (ei == 0 || ei == nL_nR) { 
+      dL = 0.0; 
+    } else { 
+      dL = ei * log(internal[i].p) + (nL_nR - ei) * log(1.0-internal[i].p); 
+    }
+    internal[i].logL = dL;
+    L += dL;
+  }
+ 
+  for (int i=0; i<(n-1); i++) {
+    if (internal[i].label > internal[i].L->label) {
+      tempe = internal[i].L;
+      internal[i].L = internal[i].R;
+      internal[i].R = tempe;
+    }
+  }
+ 
+  // Dendrogram is now built
+
+  return;
+}
+
+// ***********************************************************************
+
+void dendro::clearDendrograph() {
+  // Clear out the memory and references used by the dendrograph
+  // structure - this is  intended to be called just before an
+  // importDendrogramStructure call so as to avoid memory leaks and
+  // overwriting the references therein. 
+
+  if (g        != NULL) { delete    g;        g        = NULL; } // O(m)
+  if (leaf     != NULL) { delete [] leaf;     leaf     = NULL; } // O(n)
+  if (internal != NULL) { delete [] internal; internal = NULL; } // O(n)
+  if (d        != NULL) { delete    d;     d           = NULL; } // O(n)
+  root = NULL;
+ 
+  return;
+}
+
+// **********************************************************************
+
+int dendro::computeEdgeCount(const int a, const short int atype, 
+			     const int b, const short int btype) {
+  // This function computes the number of edges that cross between the
+  // subtree internal[a] and the subtree internal[b]. To do this, we
+  // use an array A[1..n] integers which take values -1 if A[i] is in
+  // the subtree defined by internal[a], +1 if A[i] is in the subtree
+  // internal[b], and 0 otherwise. Taking the smaller of the two sets,
+  // we then scan over the edges attached  to that set of vertices and
+  // count the number of endpoints we see in the other set.
+ 
+  bool flag_go    = true;
+  int nA, nB;
+  int         count = 0;
+  const short int k = 1+DENDRO+GRAPH;
+
+  elementd* curr;
+ 
+  // First, we push the leaf nodes in the L and R subtrees into
+  // balanced binary tree structures so that we can search them
+  // quickly later on. 
+
+  if (atype == GRAPH) {
+    // default case, subtree A is size 1
+    // insert single node as member of left subtree
+    subtreeL.insertItem(a,-1);
+    nA = 1; // 
+  } else {
+    // explore subtree A, O(|A|)
+    curr  = &internal[a];
+    curr->type = k+1;
+    nA = 0;
+    while (flag_go) {
+      if (curr->index == internal[a].M->index) {
+	internal[a].type = DENDRO;
+	flag_go = false;
+      } else {
+	// - is it time, and is left child a graph node?
+	if (curr->type == k+1 && curr->L->type == GRAPH) {
+	  subtreeL.insertItem(curr->L->index, -1);
+	  curr->type = k+2;
+	  nA++;
+	}
+	// - is it time, and is right child a graph node?
+	if (curr->type == k+2 && curr->R->type == GRAPH) {
+	  subtreeL.insertItem(curr->R->index, -1);
+	  curr->type = k+3;
+	  nA++;
+	}
+	if (curr->type == k+1) {      // - go left
+	  curr->type = k+2;
+	  curr       = curr->L;
+	  curr->type = k+1; }
+	else if (curr->type == k+2) { // - else go right
+	  curr->type = k+3;
+	  curr       = curr->R;
+	  curr->type = k+1; 
+	} else {		      // - else go up a level
+	  curr->type = DENDRO; 
+	  curr       = curr->M;
+	  if (curr == NULL) {
+	    flag_go = false;
+	  }
+	}
+      }
+    }
+  }
+ 
+  if (btype == GRAPH) {
+    // default case, subtree A is size 1
+    // insert node as single member of right subtree
+    subtreeR.insertItem(b,1);
+    nB = 1;
+  } else {
+    flag_go = true;
+    // explore subtree B, O(|B|)
+    curr = &internal[b];
+    curr->type = k+1;
+    nB  = 0;
+    while (flag_go) {
+      if (curr->index == internal[b].M->index) {
+	internal[b].type = DENDRO;
+	flag_go = false;
+      } else {
+	// - is it time, and is left child a graph node?
+	if (curr->type == k+1 && curr->L->type == GRAPH) {
+	  subtreeR.insertItem(curr->L->index, 1);
+	  curr->type = k+2;
+	  nB++;
+	}
+	// - is it time, and is right child a graph node?
+	if (curr->type == k+2 && curr->R->type == GRAPH) {
+	  subtreeR.insertItem(curr->R->index, 1);
+	  curr->type = k+3;
+	  nB++;
+	}
+	if (curr->type == k+1) {      // - look left
+	  curr->type = k+2; 
+	  curr       = curr->L;
+	  curr->type = k+1; }
+	else if (curr->type == k+2) { // - look right
+	  curr->type = k+3;
+	  curr       = curr->R;
+	  curr->type = k+1;
+	} else {		      // - else go up a level
+	  curr->type = DENDRO;
+	  curr       = curr->M;
+	  if (curr == NULL) {
+	    flag_go = false;
+	  }
+	}
+      }
+    }
+  }
+
+  // Now, we take the smaller subtree and ask how many of its
+  // emerging edges have their partner in the other subtree. O(|A| log
+  // |A|) time 
+
+  edge* current;
+  int*  treeList;
+  if (nA < nB) {
+    // subtreeL is smaller
+    treeList = subtreeL.returnArrayOfKeys();
+    for (int i=0; i<nA; i++) {
+      current = g->getNeighborList(treeList[i]);
+      // loop over each of its neighbors v_j
+      while (current != NULL) {
+	// to see if v_j is in A
+	if (subtreeR.findItem(current->x) != NULL) { count++; }
+	current = current->next;
+      }
+      subtreeL.deleteItem(treeList[i]);
+    }
+    delete [] treeList;
+    treeList = subtreeR.returnArrayOfKeys();
+    for (int i=0; i<nB; i++) { subtreeR.deleteItem(treeList[i]); }
+    delete [] treeList;
+  } else {
+    // subtreeR is smaller
+    treeList = subtreeR.returnArrayOfKeys();
+    for (int i=0; i<nB; i++) {
+      current = g->getNeighborList(treeList[i]);
+      // loop over each of its neighbors v_j
+      while (current != NULL) {
+	// to see if v_j is in B
+	if (subtreeL.findItem(current->x) != NULL) { count++; }
+	current = current->next;
+      }
+      subtreeR.deleteItem(treeList[i]);
+    }
+    delete [] treeList;
+    treeList = subtreeL.returnArrayOfKeys();
+    for (int i=0; i<nA; i++) { subtreeL.deleteItem(treeList[i]); }
+    delete [] treeList;
+  }
+
+  return count;
+}
+
+// ***********************************************************************
+
+int dendro::countChildren(const string s) {
+  int len = s.size();
+  int numC = 0;
+  for (int i=0; i<len; i++) {
+    if (s[i] == 'C') { numC++; }
+  }
+  return numC;
+}
+
+// ***********************************************************************
+
+void dendro::cullSplitHist() {
+  string* array;
+  int tot, leng;
+ 
+  array = splithist->returnArrayOfKeys();
+  tot   = splithist->returnTotal();
+  leng  = splithist->returnNodecount();
+  for (int i=0; i<leng; i++) {
+    if ((splithist->returnValue(array[i]) / tot) < 0.5) { 
+      splithist->deleteItem(array[i]); 
+    }
+  }
+  delete [] array; array = NULL;
+ 
+  return;
+}
+
+// **********************************************************************
+
+elementd* dendro::findCommonAncestor(list** paths, const int i, const int j) {
+  list* headOne = paths[i];
+  list* headTwo = paths[j];
+  elementd* lastStep = NULL;
+  while (headOne->x == headTwo->x) {
+    lastStep = &internal[headOne->x];
+    headOne  = headOne->next;
+    headTwo  = headTwo->next;
+    if (headOne == NULL || headTwo == NULL) { break; }
+  }
+  return lastStep; // Returns address of an internal node; do not deallocate
+}
+
+// **********************************************************************
+
+int dendro::getConsensusSize() {
+  string    *array;
+  double     value, tot;
+  int  numSplits, numCons;
+  numSplits = splithist->returnNodecount();
+  array     = splithist->returnArrayOfKeys();
+  tot       = splithist->returnTotal();
+  numCons = 0;
+  for (int i=0; i<numSplits; i++) {
+    value = splithist->returnValue(array[i]);
+    if (value / tot > 0.5) { numCons++; }
+  }
+  delete [] array; array = NULL;
+  return numCons;
+}
+
+// **********************************************************************
+
+splittree* dendro::getConsensusSplits() {
+  string    *array;
+  splittree *consensusTree;
+  double     value, tot;
+  consensusTree  = new splittree;
+  int numSplits;
+ 
+  // We look at all of the splits in our split histogram and add any
+  // one that's in the majority to our consensusTree, which we then
+  // return (note that consensusTree needs to be deallocated by the
+  // user).
+  numSplits = splithist->returnNodecount();
+  array     = splithist->returnArrayOfKeys();
+  tot       = splithist->returnTotal();
+  for (int i=0; i<numSplits; i++) {
+    value = splithist->returnValue(array[i]);
+    if (value / tot > 0.5) { 
+      consensusTree->insertItem(array[i], value / tot); 
+    }
+  }
+  delete [] array; array = NULL;
+  return consensusTree;
+}
+
+// ***********************************************************************
+
+double dendro::getLikelihood() { return L; }
+
+// ***********************************************************************
+
+void dendro::getSplitList(splittree* split_tree) {
+  string sp;
+  for (int i=0; i<(n-1); i++) {
+    sp = d->getSplit(i);
+    if (!sp.empty() && sp[1] != '-') { split_tree->insertItem(sp,0.0); }
+  }
+  return;
+}
+
+// ***********************************************************************
+
+double dendro::getSplitTotalWeight() { 
+  if (splithist) { return splithist->returnTotal(); } else { return 0; }
+}
+
+// ***********************************************************************
+
+bool dendro::importDendrogramStructure(const igraph_hrg_t *hrg) {
+  n=igraph_hrg_size(hrg);
+  
+  // allocate memory for G, O(n)
+  leaf = new elementd[n];
+  // allocate memory for D, O(n)
+  internal = new elementd[n-1];
+  // allocate memory for internal edges of D, O(n)
+  d = new interns(n-2);
+
+  // initialize leaf nodes
+  for (int i=0; i<n; i++) {
+    leaf[i].type  = GRAPH;
+    leaf[i].label = i;
+    leaf[i].index = i;
+    leaf[i].n     = 1;
+  }
+
+  // initialize internal nodes
+  root = &internal[0];
+  root->label=0;
+  for (int i=1; i<n-1; i++) {
+    internal[i].index = i;
+    internal[i].label = -1;
+  }
+
+  // import basic structure from hrg object, O(n)  
+  for (int i=0; i<n-1; i++) {
+    int L=VECTOR(hrg->left)[i];
+    int R=VECTOR(hrg->right)[i];
+    
+    if (L < 0) { 
+      internal[i].L = &internal[-L-1]; 
+      internal[-L-1].M = &internal[i];
+    } else {
+      internal[i].L = &leaf[L];
+      leaf[L].M = &internal[i];
+    }
+    
+    if (R < 0) { 
+      internal[i].R = &internal[-R-1];
+      internal[-R-1].M = &internal[i];
+    } else {
+      internal[i].R = &leaf[R];
+      leaf[R].M = &internal[i];
+    }
+    
+    internal[i].p = VECTOR(hrg->prob)[i];
+    internal[i].e = VECTOR(hrg->edges)[i];
+    internal[i].n = VECTOR(hrg->vertices)[i];
+    internal[i].index = i;
+  }
+  
+  // --- Label all internal vertices O(n log n)
+  elementd *curr;
+  for (int i=0; i<n; i++) {
+    curr=&leaf[i];
+    while (curr) { 
+      if (curr->label == -1 || curr->label > leaf[i].label) {
+	curr->label = leaf[i].label; 
+      } 
+      curr = curr -> M;
+    }
+  }
+  
+  // --- Exchange children to enforce order-property O(n)
+  elementd *tempe;
+  for (int i=0; i<n-1; i++) {
+    if (internal[i].L->label > internal[i].label) {
+      tempe          = internal[i].L;
+      internal[i].L  = internal[i].R;
+      internal[i].R  = tempe;
+    }
+  }
+  
+  // --- Tabulate internal dendrogram edges O(n)
+  for (int i=0; i<(n-1); i++) {
+    if (internal[i].L->type == DENDRO) { 
+      d->addEdge(i, internal[i].L->index, LEFT);  
+    }
+    if (internal[i].R->type == DENDRO) { 
+      d->addEdge(i, internal[i].R->index, RIGHT); 
+    }
+  }
+  
+  // --- Compute p_i for each internal node O(n)
+  // Each internal node's p_i = e_i / (nL_i*nR_i), and now that we
+  // have each of those pieces, we may calculate this value for each
+  // internal node. Given these, we can then calculate the
+  // log-likelihood of the entire dendrogram structure 
+  // \log(L) = \sum_{i=1}^{n} ( ( e_i \log[p_i] ) + 
+  // ( (nL_i*nR_i - e_i) \log[1-p_i] ) )
+  L = 0.0; double dL;
+  int nL_nR, ei;
+  for (int i=0; i<(n-1); i++) {
+    nL_nR = internal[i].L->n*internal[i].R->n;
+    ei    = internal[i].e;
+    if (ei == 0 || ei == nL_nR) { 
+      dL = 0.0; 
+    } else { 
+      dL = (double)(ei) * log(internal[i].p) + 
+	(double)(nL_nR - ei) * log(1.0-internal[i].p); 
+    }
+    internal[i].logL = dL;
+    L += dL;
+  }
+  
+  return true;
+}
+
+// ***********************************************************************
+
+void dendro::makeRandomGraph() {
+  if (g != NULL) { delete g; } g = NULL; g = new graph(n);
+
+  list *curr, *prev; 
+  if (paths) { 
+    for (int i=0; i<n; i++) { 
+      curr = paths[i]; 
+      while (curr != NULL) {
+	prev = curr;   
+	curr = curr->next;
+	delete prev;
+	prev = NULL; 
+      }
+      paths[i] = NULL;
+    }
+    delete [] paths;
+  }
+ // build paths from root O(n d)
+  paths = new list* [n];
+  for (int i=0; i<n; i++) { paths[i] = reversePathToRoot(i); }
+ 
+  elementd* commonAncestor;
+ // O((h+d)*n^2) - h: height of D; d: average degree in G
+  for (int i=0; i<n; i++) {
+    // decide neighbors of v_i
+    for (int j=(i+1); j<n; j++) {
+      commonAncestor = findCommonAncestor(paths,i,j);
+      if (RNG_UNIF01() < commonAncestor->p) { 
+	if (!(g->doesLinkExist(i,j))) { g->addLink(i,j); }
+	if (!(g->doesLinkExist(j,i))) { g->addLink(j,i); }
+      }
+    }
+  }
+ 
+  for (int i=0; i<n; i++) { 
+    curr = paths[i]; 
+    while (curr != NULL) { 
+      prev = curr; 
+      curr = curr->next;
+      delete prev;
+      prev = NULL; 
+    }
+    paths[i] = NULL; 
+  }
+  delete [] paths; // delete paths data structure O(n log n)
+  paths = NULL;
+
+  return;
+}
+
+// **********************************************************************
+
+bool dendro::monteCarloMove(double& delta, bool& ftaken, const double T) {
+  // A single MC move begins with the selection of a random internal
+  // edge (a,b) of the dendrogram. This also determines the three
+  // subtrees i, j, k that we will rearrange, and we choose uniformly
+  // from among the options. 
+  // 
+  // If (a,b) is a left-edge, then we have ((i,j),k), and moves
+  // ((i,j),k) -> ((i,k),j) (alpha move)
+  //           -> (i,(j,k)) + enforce order-property for (j,k) (beta move)
+  // 
+  // If (a,b) is a right-edge, then we have (i,(j,k)), and moves
+  // (i,(j,k)) -> ((i,k),j) (alpha move)
+  //           -> ((i,j),k) (beta move)
+  // 
+  // For each of these moves, we need to know what the change in
+  // likelihood will be, so that we can determine with what
+  // probability we execute the move.
+ 
+  elementd *temp;
+  ipair *tempPair;
+  int x, y, e_x, e_y, n_i, n_j, n_k, n_x, n_y;
+  short int t;
+  double p_x, p_y, L_x, L_y, dLogL;
+  string new_split;
+ 
+  // The remainder of the code executes a single MCMC move, where we
+  // sample the dendrograms proportionally to their likelihoods (i.e.,
+  // temperature=1, if you're comparing it to the usual MCMC
+  // framework).
+
+  delta    = 0.0;
+  ftaken   = false;
+  tempPair = d->getRandomEdge(); // returns address; no need to deallocate
+  x        = tempPair->x;        // copy contents of referenced random edge
+  y        = tempPair->y;        // into local variables
+  t        = tempPair->t;
+ 
+  if (t == LEFT) {
+    if (RNG_UNIF01() < 0.5) { // ## LEFT ALPHA move: ((i,j),k) -> ((i,k),j)
+      // We need to calculate the change in the likelihood (dLogL)
+      // that would result from this move. Most of the information
+      // needed to do this is already available, the exception being
+      // e_ik, the number of edges that span the i and k subtrees. I
+      // use a slow algorithm O(n) to do this, since I don't know of a
+      // better way at this point. (After several attempts to find a
+      // faster method, no luck.)
+
+      n_i = internal[y].L->n;
+      n_j = internal[y].R->n;
+      n_k = internal[x].R->n;
+ 
+      n_y = n_i*n_k;
+      e_y = computeEdgeCount(internal[y].L->index, internal[y].L->type, 
+			     internal[x].R->index, internal[x].R->type);
+      p_y  = (double)(e_y) / (double)(n_y);
+      if (e_y == 0 || e_y == n_y) { 
+	L_y = 0.0; 
+      } else { 
+	L_y = (double)(e_y) * log(p_y) + (double)(n_y - e_y) * log(1.0-p_y); 
+      }
+
+      n_x  = (n_i+n_k)*n_j;
+      e_x  = internal[x].e + internal[y].e - e_y; // e_yj
+      p_x  = (double)(e_x) / (double)(n_x);
+      if (e_x == 0 || e_x == n_x) { 
+	L_x = 0.0; 
+      } else { 
+	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
+      }
+ 
+      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
+      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) {
+
+	// make LEFT ALPHA move
+
+	ftaken = true;
+	d->swapEdges(x, internal[x].R->index, RIGHT, y, 
+		     internal[y].R->index, RIGHT);
+	temp             = internal[x].R; // - swap j and k
+	internal[x].R    = internal[y].R;
+	internal[y].R    = temp;
+	internal[x].R->M = &internal[x];  // - adjust parent pointers
+	internal[y].R->M = &internal[y]; 
+	internal[y].n    = n_i + n_k;     // - update n for [y]
+	internal[x].e    = e_x;	          // - update e_i for [x] and [y]
+	internal[y].e    = e_y; 
+	internal[x].p    = p_x;           // - update p_i for [x] and [y]
+	internal[y].p    = p_y;
+	internal[x].logL = L_x;           // - update L_i for [x] and [y]
+	internal[y].logL = L_y;
+	// - order-property maintained
+	L  += dLogL;		          // - update LogL
+	delta            = dLogL;
+ 
+      }      
+    } else {
+
+      // ## LEFT BETA move:  ((i,j),k) -> (i,(j,k))
+      
+      n_i = internal[y].L->n;
+      n_j = internal[y].R->n;
+      n_k = internal[x].R->n;
+ 
+      n_y  = n_j*n_k;
+      e_y  = computeEdgeCount(internal[y].R->index, internal[y].R->type,
+			      internal[x].R->index, internal[x].R->type);
+      p_y  = (double)(e_y) / (double)(n_y);
+      if (e_y == 0 || e_y == n_y)   { L_y = 0.0; }
+      else { L_y = (double)(e_y) * log(p_y) + 
+	  (double)(n_y - e_y) * log(1.0-p_y); }
+ 
+      n_x  = (n_j+n_k)*n_i;
+      e_x  = internal[x].e + internal[y].e - e_y; // e_yj
+      p_x  = (double)(e_x) / (double)(n_x);
+      if (e_x == 0 || e_x == n_x) { 
+	L_x = 0.0; 
+      } else { 
+	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
+      }
+ 
+      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
+      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) {
+	
+	// make LEFT BETA move
+	
+	ftaken = true;
+	d->swapEdges(y, internal[y].L->index, LEFT, y, 
+		     internal[y].R->index, RIGHT);
+	temp   = internal[y].L;		  // - swap L and R of [y]
+	internal[y].L    = internal[y].R;
+	internal[y].R    = temp; 
+	d->swapEdges(x, internal[x].R->index, RIGHT,
+		     y, internal[y].R->index, RIGHT);
+	temp   = internal[x].R;		  // - swap i and k
+	internal[x].R    = internal[y].R; 
+	internal[y].R    = temp;
+	internal[x].R->M = &internal[x];  // - adjust parent pointers
+	internal[y].R->M = &internal[y]; 
+	d->swapEdges(x, internal[x].L->index, LEFT,
+		     x, internal[x].R->index, RIGHT);
+	temp   = internal[x].L;		  // - swap L and R of [x]
+	internal[x].L    = internal[x].R;
+	internal[x].R    = temp;
+	internal[y].n    = n_j + n_k;     // - update n
+	internal[x].e    = e_x;		  // - update e_i
+	internal[y].e    = e_y;
+	internal[x].p    = p_x;           // - update p_i
+	internal[y].p    = p_y;
+	internal[x].logL = L_x;           // - update logL_i
+	internal[y].logL = L_y;
+	if (internal[y].R->label < internal[y].L->label) {
+	  // - enforce order-property if necessary
+	  d->swapEdges(y, internal[y].L->index, LEFT,
+		       y, internal[y].R->index, RIGHT);
+	  temp = internal[y].L;	
+	  internal[y].L = internal[y].R; 
+	  internal[y].R = temp;
+	} // 
+	internal[y].label = internal[y].L->label;
+	L += dLogL;		   // - update LogL
+	delta = dLogL;
+      }
+    }
+  } else {
+
+    // right-edge: t == RIGHT
+    
+    if (RNG_UNIF01() < 0.5) {
+      
+      // alpha move: (i,(j,k)) -> ((i,k),j)
+      
+      n_i = internal[x].L->n;
+      n_j = internal[y].L->n;
+      n_k = internal[y].R->n;
+ 
+      n_y  = n_i*n_k;
+      e_y  = computeEdgeCount(internal[x].L->index, internal[x].L->type,
+			      internal[y].R->index, internal[y].R->type);
+      p_y  = (double)(e_y) / (double)(n_y);
+      if (e_y == 0 || e_y == n_y)   { 
+	L_y = 0.0; 
+      } else { 
+	L_y = (double)(e_y) * log(p_y) + (double)(n_y - e_y) * log(1.0-p_y); 
+      }
+ 
+      n_x  = (n_i+n_k)*n_j;
+      e_x  = internal[x].e + internal[y].e - e_y; // e_yj
+      p_x  = (double)(e_x) / (double)(n_x);
+      if (e_x == 0 || e_x == n_x) {
+	L_x = 0.0; 
+      } else {
+	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
+      }
+
+      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
+      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) { 
+	
+	// make RIGHT ALPHA move
+	
+	ftaken = true;
+	d->swapEdges(x, internal[x].L->index, LEFT,
+		     x, internal[x].R->index, RIGHT);
+	temp    = internal[x].L;	   // - swap L and R of [x]
+	internal[x].L     = internal[x].R;
+	internal[x].R     = temp; 
+	d->swapEdges(y, internal[y].L->index, LEFT,
+		     x, internal[x].R->index, RIGHT);
+	temp    = internal[y].L;	   // - swap i and j
+	internal[y].L     = internal[x].R;
+	internal[x].R     = temp;
+	internal[x].R->M  = &internal[x];  // - adjust parent pointers
+	internal[y].L->M  = &internal[y];
+	internal[y].n     = n_i + n_k;	   // - update n
+	internal[x].e     = e_x;	   // - update e_i
+	internal[y].e     = e_y;
+	internal[x].p     = p_x;           // - update p_i
+	internal[y].p     = p_y;
+	internal[x].logL  = L_x;           // - update logL_i
+	internal[y].logL  = L_y;
+	internal[y].label = internal[x].label; // - update order property
+	L   += dLogL;			       // - update LogL
+	delta             = dLogL;
+      }
+    } else {
+      
+      // beta move:  (i,(j,k)) -> ((i,j),k)
+      
+      n_i = internal[x].L->n;
+      n_j = internal[y].L->n;
+      n_k = internal[y].R->n;
+ 
+      n_y  = n_i*n_j;
+      e_y  = computeEdgeCount(internal[x].L->index, internal[x].L->type,
+			      internal[y].L->index, internal[y].L->type);
+      p_y  = (double)(e_y) / (double)(n_y);
+      if (e_y == 0 || e_y == n_y)   { 
+	L_y = 0.0; 
+      } else {
+	L_y = (double)(e_y) * log(p_y) + (double)(n_y - e_y) * log(1.0-p_y); 
+      }
+ 
+      n_x  = (n_i+n_j)*n_k;
+      e_x  = internal[x].e + internal[y].e - e_y; // e_yk
+      p_x  = (double)(e_x) / (double)(n_x);
+      if (e_x == 0 || e_x == n_x) { 
+	L_x = 0.0; 
+      } else { 
+	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
+      }
+
+      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
+      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) { 
+	
+	// make RIGHT BETA move
+	
+	ftaken = true;
+	d->swapEdges(x, internal[x].L->index, LEFT, 
+		     x, internal[x].R->index, RIGHT);
+	temp    = internal[x].L;	   // - swap L and R of [x]
+	internal[x].L     = internal[x].R;
+	internal[x].R     = temp; 
+	d->swapEdges(x, internal[x].R->index, RIGHT,
+		     y, internal[y].R->index, RIGHT);
+	temp    = internal[x].R;	   // - swap i and k
+	internal[x].R     = internal[y].R;
+	internal[y].R     = temp;
+	internal[x].R->M  = &internal[x];  // - adjust parent pointers
+	internal[y].R->M  = &internal[y];
+	d->swapEdges(y, internal[y].L->index, LEFT,
+		     y, internal[y].R->index, RIGHT);
+	temp    = internal[y].L;	   // - swap L and R of [y]
+	internal[y].L     = internal[y].R;
+	internal[y].R     = temp; 
+	internal[y].n     = n_i + n_j;	   // - update n
+	internal[x].e     = e_x;	   // - update e_i
+	internal[y].e     = e_y;
+	internal[x].p     = p_x;	   // - update p_i
+	internal[y].p     = p_y;
+	internal[x].logL  = L_x;	   // - update logL_i
+	internal[y].logL  = L_y;
+	internal[y].label = internal[x].label; // - order-property
+	L   += dLogL;			       // - update LogL
+	delta             = dLogL;
+      }
+    }  
+  }
+  return true;
+}
+
+// **********************************************************************
+
+void dendro::refreshLikelihood() {
+  // recalculates the log-likelihood of the dendrogram structure
+  L = 0.0; double dL;
+  int nL_nR, ei;
+  for (int i=0; i<(n-1); i++) {
+    nL_nR = internal[i].L->n*internal[i].R->n;
+    ei    = internal[i].e;
+    internal[i].p = (double)(ei) / (double)(nL_nR);
+    if (ei == 0 || ei == nL_nR) { 
+      dL = 0.0; 
+    } else { 
+      dL = ei * log(internal[i].p) + (nL_nR - ei) * log(1.0-internal[i].p); 
+    }
+    internal[i].logL = dL;
+    L += dL;
+  }
+  return;
+}
+
+// **********************************************************************
+
+void dendro::QsortMain (block* array, int left, int right) {
+  if (right > left) {
+    int pivot = left;
+    int part  = QsortPartition(array, left, right, pivot);
+    QsortMain(array, left,   part-1);
+    QsortMain(array, part+1, right  );
+  }
+  return;
+}
+
+int dendro::QsortPartition (block* array, int left, int right, int index) {
+  block p_value, temp;
+  p_value.x = array[index].x;
+  p_value.y = array[index].y;
+ 
+  // swap(array[p_value], array[right])
+  temp.x = array[right].x;
+  temp.y = array[right].y;
+  array[right].x = array[index].x;
+  array[right].y = array[index].y;
+  array[index].x = temp.x;
+  array[index].y = temp.y;
+ 
+  int stored = left;
+  for (int i=left; i<right; i++) {
+    if (array[i].x <= p_value.x) {
+      // swap(array[stored], array[i])
+      temp.x = array[i].x;
+      temp.y = array[i].y;
+      array[i].x = array[stored].x; 
+      array[i].y = array[stored].y;
+      array[stored].x = temp.x;
+      array[stored].y = temp.y;
+      stored++;
+    }
+  }
+  // swap(array[right], array[stored])
+  temp.x = array[stored].x; 
+  temp.y = array[stored].y;
+  array[stored].x = array[right].x;
+  array[stored].y = array[right].y;
+  array[right].x = temp.x;
+  array[right].y  = temp.y;
+ 
+  return stored;
+}
+
+void dendro::recordConsensusTree(igraph_vector_t *parents, 
+				 igraph_vector_t *weights) {
+  
+  keyValuePairSplit *curr, *prev;
+  child *newChild;
+  int orig_nodes=g->numNodes();
+  
+  // First, cull the split hist so that only splits with weight >= 0.5
+  // remain 
+  cullSplitHist();
+  int treesize = splithist->returnNodecount();
+
+  // Now, initialize the various arrays we use to keep track of the
+  // internal structure of the consensus tree.
+  ctree  = new cnode[treesize];
+  cancestor = new int[n];
+  for (int i=0; i<treesize; i++) { ctree[i].index = i;  }
+  for (int i=0; i<n; i++)        { cancestor[i]   = -1; }
+  int ii = 0;
+ 
+  // To build the majority consensus tree, we do the following: For
+  // each possible number of Ms in the split string (a number that
+  // ranges from n-2 down to 0), and for each split with that number
+  // of Ms, we create a new internal node of the tree, and connect the
+  // oldest ancestor of each C to that node (at most once). Then, we
+  // update our list of oldest ancestors to reflect this new join, and
+  // proceed.
+  for (int i=n-2; i>=0; i--) {
+    // First, we get a list of all the splits with this exactly i Ms
+    curr = splithist->returnTheseSplits(i);
+    
+    // Now we loop over that list
+    while (curr != NULL) {
+      splithist->deleteItem(curr->x);
+      // add weight to this internal node
+      ctree[ii].weight = curr->y; 
+      // examine each letter of this split
+      for (int j=0; j<n; j++) { 
+	if (curr->x[j] == 'C') { 
+	  // - node is child of this internal node
+	  if (cancestor[j] == -1) {
+	    // - first time this leaf has ever been seen
+	    newChild        = new child;
+	    newChild->type  = GRAPH;
+	    newChild->index = j;
+	    newChild->next  = NULL;
+	    // - attach child to list
+	    if (ctree[ii].lastChild == NULL) { 
+	      ctree[ii].children  = newChild;
+	      ctree[ii].lastChild = newChild;
+	      ctree[ii].degree    = 1;
+	    } else {
+	      ctree[ii].lastChild->next = newChild;
+	      ctree[ii].lastChild       = newChild;
+	      ctree[ii].degree   += 1;
+	    }
+	  } else {
+	    // - this leaf has been seen before
+	    // If the parent of the ancestor of this leaf is the
+	    // current internal node then this leaf is already a
+	    // descendant of this internal node, and we can move on;
+	    // otherwise, we need to add that ancestor to this
+	    // internal node's child list, and update various
+	    // relations
+	    if (ctree[cancestor[j]].parent != ii) {
+	      ctree[cancestor[j]].parent = ii;
+	      newChild        = new child;
+	      newChild->type  = DENDRO;
+	      newChild->index = cancestor[j];
+	      newChild->next  = NULL;
+	      // - attach child to list
+	      if (ctree[ii].lastChild == NULL) {
+		ctree[ii].children  = newChild;
+		ctree[ii].lastChild = newChild;
+		ctree[ii].degree    = 1;
+	      } else {
+		ctree[ii].lastChild->next = newChild;
+		ctree[ii].lastChild       = newChild;
+		ctree[ii].degree   += 1;
+	      }
+	    }
+	  }
+	  // note new ancestry for this leaf
+	  cancestor[j] = ii;
+	}
+      }
+      // update internal node index
+      ii++;
+      prev = curr;
+      curr = curr->next;
+      delete prev;
+    }
+  }
+
+  // Return the consensus tree
+  igraph_vector_resize(parents, ii + orig_nodes);
+  if (weights) { igraph_vector_resize(weights, ii); }
+
+  for (int i=0; i<ii; i++) {
+    child *sat, *sit=ctree[i].children;    
+    while (sit) {
+      VECTOR(*parents)[orig_nodes + i] = 
+	ctree[i].parent < 0 ? -1 : orig_nodes + ctree[i].parent;
+      if (sit->type == GRAPH) { 
+	VECTOR(*parents)[sit->index] = orig_nodes + i;
+      }
+      sat=sit;
+      sit=sit->next;
+      delete sat;
+    }
+    if (weights) { VECTOR(*weights)[i] = ctree[i].weight; }
+    ctree[i].children=0;
+  }
+  
+  // Plus the isolate nodes
+  for (int i=0; i<n; i++) {
+    if (cancestor[i] == -1) {
+      VECTOR(*parents)[i] = -1;
+    }
+  }    
+
+
+}
+
+// **********************************************************************
+
+void dendro::recordDendrogramStructure(igraph_hrg_t *hrg) {
+  for (int i=0; i<n-1; i++) {
+    int li=internal[i].L->index;
+    int ri=internal[i].R->index;
+    VECTOR(hrg->left )[i] = internal[i].L->type == DENDRO ? -li-1 : li;
+    VECTOR(hrg->right)[i] = internal[i].R->type == DENDRO ? -ri-1 : ri;
+    VECTOR(hrg->prob )[i] = internal[i].p;
+    VECTOR(hrg->edges)[i] = internal[i].e;
+    VECTOR(hrg->vertices)[i] = internal[i].n;    
+  }
+}
+
+void dendro::recordGraphStructure(igraph_t *graph) {
+  igraph_vector_t edges;
+  int no_of_nodes=g->numNodes();
+  int no_of_edges=g->numLinks() / 2;
+  int idx=0;
+
+  igraph_vector_init(&edges, no_of_edges*2);
+  IGRAPH_FINALLY(igraph_vector_destroy, &edges);
+
+  for (int i=0; i<n; i++) {
+    edge *curr = g->getNeighborList(i);
+    while (curr) {
+      if (i < curr->x) {
+	VECTOR(edges)[idx++] = i;
+	VECTOR(edges)[idx++] = curr->x;
+      }
+      curr = curr->next;
+    }
+  }
+  
+  igraph_create(graph, &edges, no_of_nodes, /* directed= */ 0);
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+}
+
+// **********************************************************************
+
+list* dendro::reversePathToRoot(const int leafIndex) {
+  list *head, *subhead, *newlist;
+  head = subhead = newlist = NULL;
+  elementd *current = &leaf[leafIndex];
+ 
+  // continue until we're finished
+  while (current != NULL) {
+    // add this node to the path
+    newlist = new list;
+    newlist->x = current->index;
+    newlist->next = NULL;
+    if (head == NULL) { 
+      head    = newlist; 
+    } else { 
+      subhead = head;    
+      head = newlist; 
+      head->next = subhead; 
+    }
+    current = current->M;
+  }
+  return head;
+}
+
+// ***********************************************************************
+
+bool dendro::sampleSplitLikelihoods(int &sample_num) {
+  // In order to compute the majority agreement dendrogram at
+  // equilibrium, we need to calculate the leaf partition defined by
+  // each split (internal edge) of the tree. Because splits are only
+  // defined on a Cayley tree, the buildSplit() function returns the
+  // default "--...--"  string for the root and the root's left
+  // child. When tabulating the frequency of splits, one of these
+  // needs to be excluded.
+
+  IGRAPH_UNUSED(sample_num);
+
+  string* array;
+  int     k;
+  double  tot;
+
+  string new_split;
+  // To decompose the tree into its splits, we simply loop over all
+  // the internal nodes and replace the old split for the ith internal
+  // node with its new split. This is a bit time consuming to do
+  // O(n^2), so try not to do this very often. Once the decomposition
+  // is had, we insert them into the split histogram, which tracks the
+  // cumulative weight for each respective split observed.
+ 
+  if (splithist == NULL) { splithist = new splittree; }
+  for (int i=0; i<(n-1); i++) {
+    new_split = buildSplit(&internal[i]);
+    d->replaceSplit(i, new_split);
+    if (!new_split.empty() && new_split[1] != '-') {
+      if (!splithist->insertItem(new_split, 1.0)) { return false; } 
+    }
+  }
+  splithist->finishedThisRound();
+ 
+  // For large graphs, the split histogram can get extremely large, so
+  // we need to employ some measures to prevent it from swamping the
+  // available memory. When the number of splits exceeds  a threshold
+  // (say, a million), we progressively delete splits that have a
+  // weight less than  a rising (k*0.001 of the total weight) fraction
+  // of the splits, on the assumption that losing such weight is
+  // unlikely to effect the ultimate split statistics. This deletion
+  // procedure is slow O(m lg m), but should only happen very rarely.
+
+  int split_max = n*500;
+  int leng;
+  if (splithist->returnNodecount() > split_max) {
+    k=1;
+    while (splithist->returnNodecount() > split_max) {
+      array = splithist->returnArrayOfKeys();
+      tot   = splithist->returnTotal();
+      leng  = splithist->returnNodecount();
+      for (int i=0; i<leng; i++) {
+	if ((splithist->returnValue(array[i]) / tot) < k*0.001) { 
+	  splithist->deleteItem(array[i]); 
+	}
+      }
+      delete [] array; array = NULL;
+      k++;
+    }
+  }
+ 
+  return true;
+}
+
+void dendro::sampleAdjacencyLikelihoods() {
+  // Here, we sample the probability values associated with every
+  // adjacency in A, weighted by their likelihood. The weighted
+  // histogram is stored in the graph data structure, so we simply
+  // need to add an observation to each node-pair that corresponds to
+  // the associated branch point's probability and the dendrogram's
+  // overall likelihood.
+
+  double nn;
+  double norm = ((double)(n) * (double)(n)) / 4.0;
+ 
+  if (L > 0.0) { L = 0.0; }
+  elementd* ancestor;
+  list *currL, *prevL;
+  if (paths != NULL) { 
+    for (int i=0; i<n; i++) { 
+      currL = paths[i]; 
+      while (currL != NULL) { 
+	prevL = currL;
+	currL = currL->next;
+	delete prevL;
+	prevL = NULL; 
+      }
+      paths[i] = NULL; 
+    }
+    delete [] paths;
+  }
+  paths = NULL;
+  paths = new list* [n];
+  for (int i=0; i<n; i++) {
+    // construct paths from root, O(n^2) at worst
+    paths[i] = reversePathToRoot(i); 
+  }
+
+  // add obs for every node-pair, always O(n^2)
+  for (int i=0; i<n; i++) {
+    for (int j=i+1; j<n; j++) {
+      // find internal node, O(n) at worst
+      ancestor = findCommonAncestor(paths, i, j);
+      nn = ((double)(ancestor->L->n) * (double)(ancestor->R->n)) / norm;
+      // add obs of ->p to (i,j) histogram, and
+      g->addAdjacencyObs(i, j, ancestor->p, nn);
+      // add obs of ->p to (j,i) histogram
+      g->addAdjacencyObs(j, i, ancestor->p, nn);
+    }
+  }
+
+  // finish-up: upate total weight in histograms
+  g->addAdjacencyEnd();
+ 
+  return;
+}
+
+void dendro::resetDendrograph() {
+  // Reset the dendrograph structure for the next trial
+  if (leaf      != NULL) { delete [] leaf;     leaf      = NULL; } // O(n)
+  if (internal  != NULL) { delete [] internal; internal  = NULL; } // O(n)
+  if (d         != NULL) { delete d;           d         = NULL; } // O(n)
+  root = NULL;
+  if (paths != NULL) {
+    list *curr, *prev; 
+    for (int i=0; i<n; i++) {
+      curr = paths[i];
+      while (curr != NULL) {
+	prev = curr;
+	curr = curr->next;
+	delete prev;
+	prev = NULL;
+      }
+      paths[i] = NULL;
+    }
+    delete [] paths;
+  } 
+  paths = NULL;
+  L = 1.0;
+        
+  return;
+}
+
+// **********************************************************************
+// *** COPYRIGHT NOTICE *************************************************
+// graph.h - graph data structure for hierarchical random graphs
+// Copyright (C) 2005-2008 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// **********************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu |
+//                                 http://www.santafe.edu/~aaronc/ ) 
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science
+//                AND Santa Fe Institute 
+// Created      : 8 November 2005
+// Modified     : 23 December 2007 (cleaned up for public consumption)
+//
+// ***********************************************************************
+// 
+// Graph data structure for hierarchical random graphs. The basic
+// structure is an adjacency list of edges; however, many additional
+// pieces of metadata are stored as well. Each node stores its
+// external name, its degree and (if assigned) its group index.
+// 
+// ***********************************************************************
+
+// ******** Constructor / Destructor *************************************
+
+graph::graph(const int size, bool predict) : predict(predict)  {
+  n = size;
+  m = 0;
+  nodes = new vert  [n];
+  nodeLink = new edge* [n];
+  nodeLinkTail   = new edge* [n];
+  for (int i=0; i<n; i++) { nodeLink[i] = NULL; nodeLinkTail[i] = NULL; }
+  if (predict) {
+    A = new double** [n];
+    for (int i=0; i<n; i++) {
+      A[i] = new double* [n];
+    }
+    obs_count = 0;
+    total_weight = 0.0;
+    bin_resolution = 0.0;
+    num_bins = 0;
+  }
+}
+
+graph::~graph() {
+  edge *curr, *prev;
+  for (int i=0; i<n; i++) {
+    curr = nodeLink[i];
+    while (curr != NULL) {
+      prev = curr;
+      curr = curr->next;
+      delete prev;
+    }
+  }
+  delete [] nodeLink; nodeLink = NULL;
+  delete [] nodeLinkTail;  nodeLinkTail   = NULL;
+  delete [] nodes; nodes = NULL;
+ 
+  if (predict) {
+    for (int i=0; i<n; i++) {
+      for (int j=0; j<n; j++) { delete [] A[i][j]; }
+      delete [] A[i];
+    }
+    delete [] A; A = NULL;
+  }
+}
+
+// **********************************************************************
+
+bool graph::addLink(const int i, const int j) {
+  // Adds the directed edge (i,j) to the adjacency list for v_i
+  edge* newedge;
+  if (i >= 0 && i < n && j >= 0 && j < n) {
+    newedge  = new edge;
+    newedge->x = j;
+    if (nodeLink[i] == NULL) { 
+      // first neighbor
+      nodeLink[i]  = newedge;
+      nodeLinkTail[i] = newedge;
+      nodes[i].degree = 1;
+    } else {
+      // subsequent neighbor
+      nodeLinkTail[i]->next = newedge;
+      nodeLinkTail[i]       = newedge;
+      nodes[i].degree++;
+    }
+    // increment edge count
+    m++;
+    return true;
+  } else { return false; }
+}
+
+// ***********************************************************************
+
+bool graph::addAdjacencyObs(const int i, const int j, 
+			    const double probability, const double size) {
+  // Adds the observation obs to the histogram of the edge (i,j)
+  // Note: user must manually add observation to edge (j,i) by calling
+  // this function with that argument
+  if (bin_resolution > 0.0 && probability >= 0.0 && probability <= 1.0 
+      && size >= 0.0 && size <= 1.0
+      && i >= 0 && i < n && j >= 0 && j < n) {
+    int index = (int)(probability/bin_resolution + 0.5);
+    if (index < 0) { 
+      index = 0; 
+    } else if (index > num_bins) { 
+      index = num_bins; 
+    }
+    
+    // Add the weight to the proper probability bin
+    if (A[i][j][index] < 0.5) { 
+      A[i][j][index] = 1.0; 
+    } else { 
+      A[i][j][index] += 1.0; 
+    }
+    return true;
+  }
+  return false;
+}
+
+// **********************************************************************
+
+void graph::addAdjacencyEnd() {
+  // We need to also keep a running total of how much weight has been added
+  // to the histogram, and the number of observations in the histogram.
+  if (obs_count==0) { 
+    total_weight  = 1.0; obs_count = 1; 
+  } else {
+    total_weight += 1.0; obs_count++;   
+  }
+  return;
+}
+
+bool graph::doesLinkExist(const int i, const int j) {
+  // This function determines if the edge (i,j) already exists in the
+  // adjacency list of v_i
+  edge* curr;
+  if (i >= 0 && i < n && j >= 0 && j < n) {
+    curr = nodeLink[i];
+    while (curr != NULL) {
+      if (curr->x == j) { 
+	return true; 
+      }
+      curr = curr->next;
+    }
+  }
+  return false;
+}
+
+// **********************************************************************
+
+int graph::getDegree(const int i) { 
+  if (i >= 0 && i < n) { return nodes[i].degree; } else { return -1; } 
+}
+
+string graph::getName(const int i)  { 
+  if (i >= 0 && i < n) { return nodes[i].name; } else { return ""; } 
+}
+
+// NOTE: Returns address; deallocation of returned object is dangerous
+edge* graph::getNeighborList(const int i) { 
+  if (i >= 0 && i < n) { return nodeLink[i]; } else { return NULL; } 
+}
+
+double* graph::getAdjacencyHist(const int i, const int j) {
+  if (i >= 0 && i < n && j >= 0 && j < n) { 
+    return A[i][j]; 
+  } else { 
+    return NULL; 
+  }
+}
+
+// **********************************************************************
+
+double graph::getAdjacencyAverage(const int i, const int j) {
+  double average = 0.0;
+  if (i != j) {
+    for (int k=0; k<num_bins; k++) {
+      if (A[i][j][k] > 0.0) { 
+	average += (A[i][j][k] / total_weight)*((double)(k)*bin_resolution); 
+      }
+    }
+  }
+  return average;
+}
+
+int graph::numLinks() { return m; }
+
+int graph::numNodes() { return n; }
+
+double graph::getBinResolution() { return bin_resolution; }
+
+int graph::getNumBins() { return num_bins; }
+
+double graph::getTotalWeight() { return total_weight; }
+
+// ***********************************************************************
+
+void graph::resetAllAdjacencies() {
+  for (int i=0; i<n; i++) { 
+    for (int j=0; j<n; j++) { 
+      for (int k=0; k<num_bins; k++) { 
+	A[i][j][k] = 0.0; 
+      } 
+    } 
+  }
+  obs_count    = 0;
+  total_weight = 0.0;
+  return;
+}
+
+// **********************************************************************
+
+void graph::resetAdjacencyHistogram(const int i, const int j) {
+  if (i >= 0 && i < n && j >= 0 && j < n) { 
+    for (int k=0; k<num_bins; k++) { 
+      A[i][j][k] = 0.0; 
+    } 
+  }
+  return;
+}
+
+// **********************************************************************
+
+void graph::resetLinks() {
+  edge *curr, *prev;
+  for (int i=0; i<n; i++) {
+    curr = nodeLink[i];
+    while (curr != NULL) {
+      prev = curr;
+      curr = curr->next;
+      delete prev;
+    }
+    nodeLink[i]     = NULL;
+    nodeLinkTail[i] = NULL;
+    nodes[i].degree = 0;
+  }
+  m = 0;
+  return;
+}
+
+// **********************************************************************
+
+void graph::setAdjacencyHistograms(const int bin_count) {
+  // For all possible adjacencies, setup an edge histograms
+  num_bins = bin_count+1;
+  bin_resolution = 1.0 / (double)(bin_count);
+  for (int i=0; i<n; i++) {
+    for (int j=0; j<n; j++) {
+      A[i][j] = new double [num_bins];
+      for (int k=0; k<num_bins; k++) { A[i][j][k] = 0.0; }
+    }
+  }
+  return;
+}
+
+bool graph::setName(const int i, const string text) { 
+  if (i >= 0 && i < n) { 
+    nodes[i].name = text; 
+    return true; 
+  } else { 
+    return false; 
+  } 
+}
+
+// **********************************************************************
+
+interns::interns(const int n)  {
+  q         = n;
+  count     = 0;
+  edgelist  = new ipair  [q];
+  splitlist = new string [q+1];
+  indexLUT  = new int*   [q+1];
+  for (int i=0; i<(q+1); i++) {
+    indexLUT[i]    = new int [2];
+    indexLUT[i][0] = indexLUT[i][1] = -1;
+  }
+}
+interns::~interns() {
+  delete [] edgelist;
+  delete [] splitlist;
+  for (int i=0; i<(q+1); i++) { delete [] indexLUT[i]; }
+  delete [] indexLUT;
+}
+
+// ***********************************************************************
+
+// NOTE: Returns an address to another object -- do not deallocate
+ipair* interns::getEdge(const int i) { return &edgelist[i]; }
+
+// ***********************************************************************
+
+// NOTE: Returns an address to another object -- do not deallocate
+ipair* interns::getRandomEdge() { 
+  return &edgelist[(int)(floor((double)(q)*RNG_UNIF01()))]; 
+}
+
+// ***********************************************************************
+
+string interns::getSplit(const int i) { 
+  if (i >= 0 && i <= q) { 
+    return splitlist[i]; 
+  } else { 
+    return "";
+  } 
+}
+
+// **********************************************************************
+
+bool interns::addEdge(const int new_x, const int new_y, 
+		      const short int new_type) {
+  // This function adds a new edge (i,j,t,sp) to the list of internal
+  // edges. After checking that the inputs fall in the appropriate
+  // range of values, it records the new edgelist index in the
+  // indexLUT and then puts the input values into that edgelist
+  // location.
+
+  if (count < q && new_x >= 0 && new_x < (q+1) && new_y >= 0 &&
+      new_y < (q+2) && (new_type == LEFT || new_type == RIGHT)) {
+    if (new_type == LEFT) { 
+      indexLUT[new_x][0] = count; 
+    } else { 
+      indexLUT[new_x][1] = count; 
+    }
+    edgelist[count].x = new_x;
+    edgelist[count].y = new_y;
+    edgelist[count].t = new_type;
+    count++;
+    return true;
+  } else { 
+    return false; 
+  }
+}
+
+// **********************************************************************
+
+bool interns::replaceSplit(const int i, const string sp) {
+  // When an internal edge is changed, its split must be replaced as
+  // well. This function provides that access; it stores the split
+  // defined by an internal edge (x,y) at the location [y], which
+  // is unique.
+
+  if (i >= 0 && i <= q) { splitlist[i] = sp; return true; }
+  return false;
+}
+
+// ***********************************************************************
+
+bool interns::swapEdges(const int one_x, const int one_y, 
+			const short int one_type, const int two_x, 
+			const int two_y, const short int two_type) {
+  // The moves on the dendrogram always swap edges, either of which
+  // (or both, or neither) can by internal edges. So, this function
+  // mirrors that operation for the internal edgelist and indexLUT.
+ 
+  int index, jndex, temp;
+  bool one_isInternal = false;
+  bool two_isInternal = false;
+ 
+  if (one_x >= 0 && one_x < (q+1) && two_x >= 0 && two_x < (q+1) && 
+      (two_type == LEFT || two_type == RIGHT) && 
+      one_y >= 0 && one_y < (q+2) && two_y >= 0 && 
+      two_y < (q+2) && (one_type == LEFT || one_type == RIGHT)) {
+ 
+    if (one_type == LEFT) { temp = 0; } else { temp = 1; }
+    if (indexLUT[one_x][temp] > -1) { one_isInternal = true; }
+    if (two_type == LEFT) { temp = 0; } else { temp = 1; }
+    if (indexLUT[two_x][temp] > -1) { two_isInternal = true; }
+ 
+    if (one_isInternal && two_isInternal) {
+      if (one_type == LEFT)  { 
+	index = indexLUT[one_x][0]; } else { index = indexLUT[one_x][1]; 
+      }
+      if (two_type == LEFT)  { 
+	jndex = indexLUT[two_x][0]; } else { jndex = indexLUT[two_x][1]; 
+      }
+      temp              = edgelist[index].y;
+      edgelist[index].y = edgelist[jndex].y;
+      edgelist[jndex].y = temp;
+ 
+    } else if (one_isInternal) {
+      if (one_type == LEFT)  { 
+	index = indexLUT[one_x][0]; indexLUT[one_x][0] = -1; 
+      } else { 
+	index = indexLUT[one_x][1]; indexLUT[one_x][1] = -1; 
+      }
+      edgelist[index].x = two_x;
+      edgelist[index].t = two_type;
+      if (two_type == LEFT) { 
+	indexLUT[two_x][0] = index; 
+      } else { 
+	indexLUT[two_x][1] = index; 
+      } // add new
+ 
+    } else if (two_isInternal) {
+      if (two_type == LEFT)  { 
+	index = indexLUT[two_x][0]; indexLUT[two_x][0] = -1;
+      } else { 
+	index = indexLUT[two_x][1]; indexLUT[two_x][1] = -1; 
+      }
+      edgelist[index].x = one_x;
+      edgelist[index].t = one_type;
+      if (one_type == LEFT) { 
+	indexLUT[one_x][0] = index; 
+      } else { 
+	indexLUT[one_x][1] = index; 
+      } // add new
+    } else { 
+      ;
+    } // else neither is internal
+
+    return true;
+  } else { return false; }
+}
+
+// ******** Red-Black Tree Methods ***************************************
+
+splittree::splittree() {
+  root = new elementsp;
+  leaf = new elementsp;
+
+  leaf->parent   = root;
+
+  root->left = leaf;
+  root->right    = leaf;
+  support = 0;
+  total_weight = 0.0;
+  total_count = 0;
+}
+
+splittree::~splittree() {
+  if (root != NULL && (root->left != leaf || root->right != leaf)) { 
+    deleteSubTree(root); root = NULL;
+  }
+  support      = 0;
+  total_weight = 0.0;
+  total_count  = 0;
+  if (root) delete root;
+  delete leaf;
+  root    = NULL;
+  leaf    = NULL;
+}
+
+void splittree::deleteTree() { 
+  if (root != NULL) { deleteSubTree(root); root = NULL; } 
+  return; 
+}
+
+void splittree::deleteSubTree(elementsp *z) {
+  if (z->left  != leaf) { deleteSubTree(z->left); z->left = NULL; }
+  if (z->right != leaf) { deleteSubTree(z->right); z->right = NULL; }
+  delete z;
+  /* No point in setting z to NULL here because z is passed by value */
+  /* z = NULL; */
+  return;
+}
+
+// ******** Reset Functions *********************************************
+
+// O(n lg n)
+void splittree::clearTree() {
+  string *array = returnArrayOfKeys();
+  for (int i=0; i<support; i++) { deleteItem(array[i]); }
+  delete [] array;
+  return;
+}
+
+// ******** Search Functions *********************************************
+// public search function - if there exists a elementsp in the tree
+// with key=searchKey, it returns TRUE and foundNode is set to point
+// to the found node; otherwise, it sets foundNode=NULL and returns
+// FALSE
+elementsp* splittree::findItem(const string searchKey) {
+
+  elementsp *current=root;
+  if (current->split.empty()) { return NULL; } // empty tree; bail out
+  while (current != leaf) {
+    if (searchKey.compare(current->split) < 0) { // left-or-right?
+      // try moving down-left
+      if (current->left  != leaf) {
+	current = current->left;  
+      } else { 
+	// failure; bail out
+	return NULL; 
+      }
+    } else { 
+      if (searchKey.compare(current->split) > 0) {
+	// left-or-right?
+	if (current->right != leaf) { 
+	  // try moving down-left
+	  current = current->right;  
+	}
+	else { 
+	  //   failure; bail out
+	  return NULL; 
+	}
+      } else { 
+	// found (searchKey==current->split)
+	return current; 
+      }
+    }
+  }
+  return NULL;
+}
+
+double splittree::returnValue(const string searchKey) {
+  elementsp* test = findItem(searchKey);
+  if (test == NULL) { return 0.0; } else { return test->weight; }
+}
+
+
+// ******** Return Item Functions ***************************************
+// public function which returns the tree, via pre-order traversal, as
+// a linked list
+
+string* splittree::returnArrayOfKeys() {
+  string* array;
+  array = new string [support];
+  bool flag_go = true;
+  int index = 0;
+  elementsp *curr;
+ 
+  if (support == 1) { 
+    array[0] = root->split; 
+  } else if (support == 2) {
+    array[0] = root->split;
+    if (root->left == leaf) { 
+      array[1] = root->right->split; 
+    } else {
+      array[1] = root->left->split; 
+    }
+  } else {
+    for (int i=0; i<support; i++) { array[i] = -1; }
+    // non-recursive traversal of tree structure
+    curr  = root;
+    curr->mark = 1;
+    while (flag_go) {
+ 
+      // - is it time, and is left child the leaf node?
+      if (curr->mark == 1 && curr->left == leaf) {
+	curr->mark = 2;
+      }
+      // - is it time, and is right child the leaf node?
+      if (curr->mark == 2 && curr->right == leaf) {
+	curr->mark = 3;
+      }
+      if (curr->mark == 1) {		       // - go left
+	curr->mark = 2;
+	curr = curr->left;
+	curr->mark = 1;
+      } else if (curr->mark == 2) {	       // - else go right
+	curr->mark = 3;
+	curr = curr->right;
+	curr->mark = 1;
+      } else {				       // - else go up a level
+	curr->mark = 0;
+	array[index++] = curr->split;
+	curr = curr->parent;
+	if (curr == NULL) { flag_go = false; }
+      }
+    }
+  }
+ 
+  return array;
+}
+
+slist* splittree::returnListOfKeys() {
+  keyValuePairSplit *curr, *prev;
+  slist *head = NULL, *tail = NULL, *newlist;
+
+  curr = returnTreeAsList();
+  while (curr != NULL) {
+    newlist = new slist;
+    newlist->x = curr->x;
+    if (head == NULL) { 
+      head = newlist; tail = head;    
+    } else { 
+      tail->next = newlist; tail = newlist; 
+    }
+    prev = curr;
+    curr = curr->next;
+    delete prev;
+    prev = NULL;
+  }
+  return head;
+}
+
+ // pre-order traversal
+keyValuePairSplit* splittree::returnTreeAsList() {
+  keyValuePairSplit  *head, *tail;
+
+  head    = new keyValuePairSplit;
+  head->x = root->split;
+  head->y = root->weight;
+  head->c = root->count;
+  tail    = head;
+
+  if (root->left  != leaf) { tail = returnSubtreeAsList(root->left,  tail); }
+  if (root->right != leaf) { tail = returnSubtreeAsList(root->right, tail); }
+ 
+  if (head->x.empty()) { return NULL; /* empty tree */ } else { return head; }
+}
+
+keyValuePairSplit* splittree::returnSubtreeAsList(elementsp *z,
+						  keyValuePairSplit *head) {
+  keyValuePairSplit *newnode, *tail;
+ 
+  newnode    = new keyValuePairSplit;
+  newnode->x = z->split;
+  newnode->y = z->weight;
+  newnode->c = z->count;
+  head->next = newnode;
+  tail       = newnode;
+ 
+  if (z->left  != leaf) { tail = returnSubtreeAsList(z->left,  tail); }
+  if (z->right != leaf) { tail = returnSubtreeAsList(z->right, tail); }
+ 
+  return tail;
+}
+
+keyValuePairSplit splittree::returnMaxKey() {
+  keyValuePairSplit themax;
+  elementsp *current;
+  current = root;
+  // search to bottom-right corner of tree
+  while (current->right != leaf) {
+    current = current->right; 
+  }
+  themax.x = current->split;
+  themax.y = current->weight;
+ 
+  return themax;
+}
+
+keyValuePairSplit splittree::returnMinKey() {
+  keyValuePairSplit themin;
+  elementsp *current;
+  current = root;
+  // search to bottom-left corner of tree
+  while (current->left != leaf) {
+    current = current->left; 
+  }
+  themin.x = current->split;
+  themin.y = current->weight;
+ 
+  return themin;
+}
+
+// private functions for deleteItem() (although these could easily be
+// made public, I suppose)
+elementsp* splittree::returnMinKey(elementsp *z) {
+  elementsp *current;
+
+  current = z;
+  // search to bottom-right corner of tree
+  while (current->left != leaf) {
+    current = current->left; 
+  }
+  // return pointer to the minimum
+  return current;
+}
+
+elementsp* splittree::returnSuccessor(elementsp *z) {
+  elementsp *current, *w;
+ 
+  w = z;
+ // if right-subtree exists, return min of it
+  if (w->right != leaf) {
+    return returnMinKey(w->right); 
+  }
+  // else search up in tree
+  // move up in tree until find a non-right-child
+  current = w->parent;
+  while ((current!=NULL) && (w==current->right)) {
+    w = current;
+    current = current->parent;
+  }
+  return current;
+}
+
+int splittree::returnNodecount() { return support; }
+
+keyValuePairSplit* splittree::returnTheseSplits(const int target) {
+  keyValuePairSplit *head, *curr, *prev, *newhead, *newtail, *newpair;
+  int count, len;
+ 
+  head = returnTreeAsList();
+  prev = newhead = newtail = newpair = NULL;
+  curr = head;
+ 
+  while (curr != NULL) {
+    count = 0;
+    len   = curr->x.size();
+    for (int i=0; i<len; i++) { if (curr->x[i] == 'M') { count++; } }
+    if (count == target && curr->x[1] != '*') {
+      newpair       = new keyValuePairSplit;
+      newpair->x    = curr->x;
+      newpair->y    = curr->y;
+      newpair->next = NULL;
+      if (newhead == NULL) { 
+	newhead = newpair; newtail = newpair; 
+      } else {
+	newtail->next = newpair; newtail = newpair; 
+      }
+    }
+    prev = curr;
+    curr = curr->next;
+    delete prev;
+    prev = NULL;
+  }
+ 
+  return newhead;
+}
+
+double splittree::returnTotal() { return total_weight; }
+
+// ******** Insert Functions *********************************************
+
+void splittree::finishedThisRound() {
+  // We need to also keep a running total of how much weight has been
+  // added to the histogram.
+  if (total_count == 0) { 
+    total_weight  = 1.0; total_count = 1; 
+  } else { 
+    total_weight += 1.0; total_count++; 
+  }
+  return;
+} 
+
+// public insert function
+bool splittree::insertItem(string newKey, double newValue) {
+ 
+  // first we check to see if newKey is already present in the tree;
+  // if so, we do nothing; if not, we must find where to insert the
+  // key
+  elementsp *newNode, *current;
+ 
+ // find newKey in tree; return pointer to it O(log k)
+  current = findItem(newKey);
+  if (current != NULL) {
+    current->weight += 1.0;
+    // And finally, we keep track of how many observations went into
+    // the histogram 
+    current->count++;
+    return true;
+  } else {
+    newNode = new elementsp;	// elementsp for the splittree
+    newNode->split = newKey;	//  store newKey
+    newNode->weight = newValue;	//  store newValue
+    newNode->color = true;	//  new nodes are always RED
+    newNode->parent = NULL;	//  new node initially has no parent
+    newNode->left = leaf;	//  left leaf
+    newNode->right = leaf;	//  right leaf
+    newNode->count = 1;
+    support++;			// increment node count in splittree
+ 
+    // must now search for where to insert newNode, i.e., find the
+    // correct parent and set the parent and child to point to each
+    // other properly 
+    current = root;
+    if (current->split.empty()) {	// insert as root
+      delete root;		//   delete old root
+      root = newNode;		//   set root to newNode
+      leaf->parent   = newNode; //   set leaf's parent
+      current = leaf;		//   skip next loop
+    }
+ 
+    // search for insertion point
+    while (current != leaf) {
+      // left-or-right?
+      if (newKey.compare(current->split) < 0) {
+	// try moving down-left
+	if (current->left  != leaf) { 
+	  current = current->left;  
+	} else {
+	  // else found new parent
+	  newNode->parent = current; // set parent
+	  current->left = newNode;   // set child
+	  current = leaf;	     // exit search
+	}
+      } else { // 
+	if (current->right != leaf) { 
+	  // try moving down-right
+	  current = current->right; 
+	} else {
+	  // else found new parent
+	  newNode->parent = current; // set parent
+	  current->right = newNode;  // set child
+	  current = leaf;	     // exit search
+	}
+      }
+    }
+
+    // now do the house-keeping necessary to preserve the red-black
+    // properties 
+    insertCleanup(newNode);
+ 
+  }
+  return true;
+}
+
+// private house-keeping function for insertion
+void splittree::insertCleanup(elementsp *z) {
+ 
+  // fix now if z is root
+  if (z->parent==NULL) {
+    z->color = false; return; 
+  }
+  elementsp *temp;
+  // while z is not root and z's parent is RED
+  while (z->parent!=NULL && z->parent->color) {
+    if (z->parent == z->parent->parent->left) {  // z's parent is LEFT-CHILD
+      temp = z->parent->parent->right;		 // grab z's uncle
+      if (temp->color) {
+	z->parent->color = false;          // color z's parent BLACK (Case 1)
+	temp->color = false;	           // color z's uncle BLACK  (Case 1)
+	z->parent->parent->color = true;   // color z's grandpa  RED (Case 1)
+	z = z->parent->parent;	           // set z = z's grandpa    (Case 1)
+      } else {
+	if (z == z->parent->right) {       // z is RIGHT-CHILD
+	  z = z->parent;                   // set z = z's parent     (Case 2)
+	  rotateLeft(z);                   // perform left-rotation  (Case 2)
+	}
+	z->parent->color = false;          // color z's parent BLACK (Case 3)
+	z->parent->parent->color = true;   // color z's grandpa RED  (Case 3)
+	rotateRight(z->parent->parent);    // perform right-rotation (Case 3)
+      }
+    } else {			           // z's parent is RIGHT-CHILD
+      temp = z->parent->parent->left;      // grab z's uncle
+      if (temp->color) {
+	z->parent->color = false;          // color z's parent BLACK (Case 1)
+	temp->color = false;               // color z's uncle BLACK  (Case 1)
+	z->parent->parent->color = true;   // color z's grandpa RED  (Case 1)
+	z = z->parent->parent;             // set z = z's grandpa    (Case 1)
+      } else {
+	if (z == z->parent->left) {        // z is LEFT-CHILD
+	  z = z->parent;                   // set z = z's parent     (Case 2)
+	  rotateRight(z);                  // perform right-rotation (Case 2)
+	}
+	z->parent->color = false;          // color z's parent BLACK (Case 3)
+	z->parent->parent->color = true;   // color z's grandpa RED  (Case 3)
+	rotateLeft(z->parent->parent);     // perform left-rotation  (Case 3)
+      }
+    }
+  }
+
+  root->color = false; // color the root BLACK
+  return;
+}
+
+// ******** Delete Functions ********************************************
+// public delete function
+void splittree::deleteItem(string killKey) {
+  elementsp *x, *y, *z;
+ 
+  z = findItem(killKey);
+  if (z == NULL) { return; }	// item not present; bail out
+
+  if (support==1) {		// -- attempt to delete the root
+    root->split = "";		// restore root node to default state
+    root->weight = 0.0;		// 
+    root->color = false;	// 
+    root->parent = NULL;	// 
+    root->left = leaf;		// 
+    root->right = leaf;		// 
+    support--;			// set support to zero
+    total_weight = 0.0;		// set total weight to zero
+    total_count--;		// 
+    return;			// exit - no more work to do
+  }
+ 
+  if (z != NULL) {
+    support--;			// decrement node count
+    if ((z->left == leaf) || (z->right==leaf)) { 
+      // case of less than two children
+      y = z; 			 // set y to be z
+    } else { 
+      y = returnSuccessor(z); 	 // set y to be z's key-successor
+    } 
+ 
+    if (y->left!=leaf) { 
+      x = y->left;	 	 // pick y's one child (left-child)
+    } else { 
+      x = y->right;              // (right-child)
+    } 
+    x->parent = y->parent;       // make y's child's parent be y's parent
+
+    if (y->parent==NULL) { 
+      root = x;			 // if y is the root, x is now root
+    } else {
+      if (y == y->parent->left) {// decide y's relationship with y's parent
+	y->parent->left  = x;    // replace x as y's parent's left child
+      } else {
+	y->parent->right = x; }  // replace x as y's parent's left child
+    }
+
+    if (y!=z) {			 // insert y into z's spot
+      z->split = y->split;	 // copy y data into z
+      z->weight = y->weight;	 // 
+      z->count = y->count;	 // 
+    }				 // 
+
+    // do house-keeping to maintain balance
+    if (y->color==false) { deleteCleanup(x); }
+    delete y;			 // deallocate y
+    y = NULL;			 // point y to NULL for safety
+  }				 // 
+ 
+  return;
+}
+
+void splittree::deleteCleanup(elementsp *x) {
+  elementsp *w, *t;
+  // until x is the root, or x is RED
+  while ((x != root) && (x->color==false)) {
+    if (x==x->parent->left) {	     // branch on x being a LEFT-CHILD
+      w = x->parent->right;	     // grab x's sibling
+      if (w->color==true) {	     // if x's sibling is RED
+	w->color = false;	     // color w BLACK                (case 1)
+	x->parent->color = true;     // color x's parent RED         (case 1)
+	rotateLeft(x->parent);       // left rotation on x's parent  (case 1)
+	w = x->parent->right;        // make w be x's right sibling  (case 1)
+      }
+      if ((w->left->color==false) && (w->right->color==false)) {
+	w->color = true;	     // color w RED                  (case 2)
+	x = x->parent;		     // examine x's parent           (case 2)
+      } else {			     // 
+	if (w->right->color==false) {
+	  w->left->color = false;    // color w's left child BLACK   (case 3)
+	  w->color = true;	     // color w RED                  (case 3)
+	  t = x->parent;	     // store x's parent
+	  rotateRight(w);	     // right rotation on w          (case 3)
+	  x->parent = t;	     // restore x's parent
+	  w = x->parent->right;      // make w be x's right sibling  (case 3)
+	} // 
+	w->color = x->parent->color; // w's color := x's parent's    (case 4)
+	x->parent->color    = false; // color x's parent BLACK       (case 4)
+	w->right->color = false;     // color w's right child BLACK  (case 4)
+	rotateLeft(x->parent);       // left rotation on x's parent  (case 4)
+	x = root;		     // finished work. bail out      (case 4)
+      }				     // 
+    } else {			     // x is RIGHT-CHILD
+      w = x->parent->left;	     // grab x's sibling
+      if (w->color==true) {	     // if x's sibling is RED
+	w->color = false;	     // color w BLACK                (case 1)
+	x->parent->color    = true;  // color x's parent RED         (case 1)
+	rotateRight(x->parent);      // right rotation on x's parent (case 1)
+	w = x->parent->left;         // make w be x's left sibling   (case 1)
+      }
+      if ((w->right->color==false) && (w->left->color==false)) {
+	w->color = true;	     // color w RED                  (case 2)
+	x= x->parent;		     // examine x's parent           (case 2)
+      } else { // 
+	if (w->left->color==false) { // 
+	  w->right->color = false;   // color w's right child BLACK  (case 3)
+	  w->color = true;	     // color w RED                  (case 3)
+	  t = x->parent;	     // store x's parent
+	  rotateLeft(w);	     // left rotation on w           (case 3)
+	  x->parent = t;	     // restore x's parent
+	  w = x->parent->left;	     // make w be x's left sibling   (case 3)
+	} // 
+	w->color = x->parent->color; // w's color := x's parent's    (case 4)
+	x->parent->color    = false; // color x's parent BLACK       (case 4)
+	w->left->color = false;      // color w's left child BLACK   (case 4)
+	rotateRight(x->parent);      // right rotation on x's parent (case 4)
+	x = root;                    // x is now the root            (case 4)
+      }
+    }
+  }
+  x->color = false;	   	     // color x (the root) BLACK (exit)
+
+  return;
+}
+
+// ******** Rotation Functions *******************************************
+
+void splittree::rotateLeft(elementsp *x) {
+  elementsp *y;
+  // do pointer-swapping operations for left-rotation
+  y = x->right;		        // grab right child
+  x->right = y->left;	        // make x's RIGHT-CHILD be y's LEFT-CHILD
+  y->left->parent = x;	        // make x be y's LEFT-CHILD's parent
+  y->parent = x->parent;        // make y's new parent be x's old parent
+
+  if (x->parent==NULL) {
+    root = y;		        // if x was root, make y root
+  } else {		        // 
+    if (x == x->parent->left) { // if x is LEFT-CHILD, make y be x's parent's
+      x->parent->left  = y;	// left-child
+    } else {
+      x->parent->right = y;	// right-child
+    }
+  }
+  y->left   = x;		// make x be y's LEFT-CHILD
+  x->parent = y;		// make y be x's parent
+ 
+  return;
+}
+
+void splittree::rotateRight(elementsp *y) {
+  elementsp *x;
+  // do pointer-swapping operations for right-rotation
+  x = y->left;		         // grab left child
+  y->left = x->right;	         // replace left child yith x's right subtree
+  x->right->parent = y;	         // replace y as x's right subtree's parent
+ 
+  x->parent = y->parent;         // make x's new parent be y's old parent
+  if (y->parent==NULL) { 
+    root = x;		 	 // if y was root, make x root
+  } else {
+    if (y == y->parent->right) { // if y is R-CHILD, make x be y's parent's
+      y->parent->right = x;	 // right-child
+    } else { 
+      y->parent->left = x;	 // left-child
+    }
+  }
+  x->right  = y;		 // make y be x's RIGHT-CHILD
+  y->parent = x;		 // make x be y's parent
+ 
+  return;
+}
+
+// ***********************************************************************
+// *** COPYRIGHT NOTICE **************************************************
+// graph_simp.h - graph data structure
+// Copyright (C) 2006-2008 Aaron Clauset
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+// 
+// See http://www.gnu.org/licenses/gpl.txt for more details.
+// 
+// ***********************************************************************
+// Author       : Aaron Clauset  ( aaronc at santafe.edu |
+//                                 http://www.santafe.edu/~aaronc/ ) 
+// Collaborators: Cristopher Moore and Mark E.J. Newman
+// Project      : Hierarchical Random Graphs
+// Location     : University of New Mexico, Dept. of Computer Science
+//                AND Santa Fe Institute 
+// Created      : 21 June 2006
+// Modified     : 23 December 2007 (cleaned up for public consumption)
+//
+// ************************************************************************
+
+// ******** Constructor / Destructor *************************************
+
+simpleGraph::simpleGraph(const int size): n(size), m(0), num_groups(0) {
+  nodes = new simpleVert  [n];
+  nodeLink = new simpleEdge* [n];
+  nodeLinkTail = new simpleEdge* [n];
+  A = new double* [n];
+  for (int i=0; i<n; i++) {
+    nodeLink[i] = NULL; nodeLinkTail[i] = NULL;
+    A[i] = new double [n];
+    for (int j=0; j<n; j++) { A[i][j] = 0.0; }
+  }
+  E = NULL;
+}
+
+simpleGraph::~simpleGraph() {
+  simpleEdge *curr, *prev;
+  for (int i=0; i<n; i++) {
+    curr = nodeLink[i];
+    delete [] A[i];
+    while (curr != NULL) {
+      prev = curr;
+      curr = curr->next;
+      delete prev;
+    }
+  }
+  curr = NULL; prev = NULL;
+  if (E != NULL) { delete [] E; E = NULL; }
+  delete [] A; A = NULL;
+  delete [] nodeLink; nodeLink = NULL;
+  delete [] nodeLinkTail;  nodeLinkTail   = NULL;
+  delete [] nodes; nodes = NULL;
+}
+
+// ***********************************************************************
+
+bool simpleGraph::addGroup(const int i, const int group_index) {
+  if (i >= 0 && i < n) {
+    nodes[i].group_true = group_index;
+    return true;
+  } else { 
+    return false; 
+  }
+}
+
+// ***********************************************************************
+
+bool simpleGraph::addLink(const int i, const int j) {
+  // Adds the directed edge (i,j) to the adjacency list for v_i
+  simpleEdge* newedge;
+  if (i >= 0 && i < n && j >= 0 && j < n) {
+    A[i][j] = 1.0;
+    newedge  = new simpleEdge;
+    newedge->x = j;
+    if (nodeLink[i] == NULL) {	// first neighbor
+      nodeLink[i]  = newedge;
+      nodeLinkTail[i] = newedge;
+      nodes[i].degree = 1;
+    } else {			// subsequent neighbor
+      nodeLinkTail[i]->next = newedge;
+      nodeLinkTail[i]       = newedge;
+      nodes[i].degree++;
+    }
+    m++;			// increment edge count
+    newedge = NULL;
+    return true;
+  } else { return false; }
+}
+
+// ***********************************************************************
+
+bool simpleGraph::doesLinkExist(const int i, const int j) {
+  // This function determines if the edge (i,j) already exists in the
+  // adjacency list of v_i
+  if (i >= 0 && i < n && j >= 0 && j < n) { 
+    if (A[i][j] > 0.1) {
+      return true; 
+    } else { 
+      return false; 
+    } 
+  } else { 
+    return false; 
+  }
+  return false;
+}
+
+// **********************************************************************
+
+double simpleGraph::getAdjacency(const int i, const int j) {
+  if (i >= 0 && i < n && j >= 0 && j < n) { 
+    return A[i][j]; 
+  } else { 
+    return -1.0; 
+  } 
+}
+
+int simpleGraph::getDegree(const int i) { 
+  if (i >= 0 && i < n) {
+    return nodes[i].degree;
+  } else {
+    return -1; 
+  }
+}
+
+int simpleGraph::getGroupLabel(const int i) {
+  if (i >= 0 && i < n) {
+    return nodes[i].group_true;
+  } else {
+    return -1; 
+  }
+}
+
+string simpleGraph::getName(const int i) { 
+  if (i >= 0 && i < n) {
+    return nodes[i].name;
+  } else {
+    return ""; 
+  }
+}
+
+// NOTE: The following three functions return addresses; deallocation
+// of returned object is dangerous 
+simpleEdge* simpleGraph::getNeighborList(const int i) {
+  if (i >= 0 && i < n) {
+    return nodeLink[i];
+  } else {
+    return NULL; 
+  }
+}
+// END-NOTE
+
+// *********************************************************************
+
+int simpleGraph::getNumGroups() { return num_groups; }
+int simpleGraph::getNumLinks()  { return m; }
+int simpleGraph::getNumNodes()  { return n; }
+simpleVert* simpleGraph::getNode(const int i) { 
+  if (i >= 0 && i<n) { 
+    return &nodes[i];
+  } else {
+    return NULL;
+  }
+}
+
+// **********************************************************************
+
+bool simpleGraph::setName(const int i, const string text) {
+  if (i >= 0 && i < n) { 
+    nodes[i].name = text;
+    return true; 
+  } else {
+    return false;
+  }
+}
+
+// **********************************************************************
+
+void simpleGraph::QsortMain (block* array, int left, int right) {
+  if (right > left) {
+    int pivot = left;
+    int part  = QsortPartition(array, left, right, pivot);
+    QsortMain(array, left,   part-1);
+    QsortMain(array, part+1, right  );
+  }
+  return;
+}
+
+int simpleGraph::QsortPartition (block* array, int left, int right,
+				 int index) {
+  block p_value, temp;
+  p_value.x = array[index].x;
+  p_value.y = array[index].y;
+ 
+  // swap(array[p_value], array[right])
+  temp.x = array[right].x;
+  temp.y = array[right].y;
+  array[right].x = array[index].x;
+  array[right].y = array[index].y;
+  array[index].x = temp.x;
+  array[index].y = temp.y;
+ 
+  int stored = left;
+  for (int i=left; i<right; i++) {
+    if (array[i].x <= p_value.x) {
+      // swap(array[stored], array[i])
+      temp.x = array[i].x;
+      temp.y = array[i].y;
+      array[i].x = array[stored].x;
+      array[i].y = array[stored].y;
+      array[stored].x = temp.x;
+      array[stored].y = temp.y;
+      stored++;
+    }
+  }
+  // swap(array[right], array[stored])
+  temp.x = array[stored].x;
+  temp.y = array[stored].y;
+  array[stored].x = array[right].x;
+  array[stored].y = array[right].y;
+  array[right].x = temp.x; 
+  array[right].y = temp.y;
+ 
+  return stored;
+}
+
+// ***********************************************************************
diff --git a/src/igraph_interrupt_internal.h b/src/igraph_interrupt_internal.h
new file mode 100644
index 0000000..9f0934b
--- /dev/null
+++ b/src/igraph_interrupt_internal.h
@@ -0,0 +1,69 @@
+/* -*- 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_INTERRUPT_INTERNAL_H
+#define IGRAPH_INTERRUPT_INTERNAL_H
+
+#include "config.h"
+#include "igraph_interrupt.h"
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+__BEGIN_DECLS
+
+extern IGRAPH_THREAD_LOCAL igraph_interruption_handler_t 
+  *igraph_i_interruption_handler;
+
+/**
+ * \define IGRAPH_ALLOW_INTERRUPTION
+ * \brief 
+ * 
+ * This macro should be called when interruption is allowed.  It calls
+ * \ref igraph_allow_interruption() with the proper parameters and if that returns
+ * anything but \c IGRAPH_SUCCESS then
+ * the macro returns the "calling" function as well, with the proper
+ * error code (\c IGRAPH_INTERRUPTED).
+ */
+
+#define IGRAPH_ALLOW_INTERRUPTION() \
+       do { \
+       if (igraph_i_interruption_handler) { if (igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) return IGRAPH_INTERRUPTED; \
+       } } while (0)
+
+#define IGRAPH_ALLOW_INTERRUPTION_NORETURN() \
+       do { \
+       if (igraph_i_interruption_handler) { igraph_allow_interruption(NULL); } \
+       } while (0)
+
+__END_DECLS
+
+#endif
+
diff --git a/src/igraph_lapack_internal.h b/src/igraph_lapack_internal.h
new file mode 100644
index 0000000..1466b9a
--- /dev/null
+++ b/src/igraph_lapack_internal.h
@@ -0,0 +1,178 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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 LAPACK_INTERNAL_H
+#define LAPACK_INTERNAL_H
+
+/* Note: only files calling the LAPACK routines directly need to
+   include this header.
+*/
+
+#include "igraph_types.h"
+#include "config.h"
+
+#ifndef INTERNAL_LAPACK
+#define igraphdgeevx_   dgeevx_
+#define igraphdgeev_	dgeev_
+#define igraphdgebak_	dgebak_
+#define igraphxerbla_	xerbla_
+#define igraphdgebal_	dgebal_
+#define igraphdisnan_	disnan_
+#define igraphdlaisnan_	dlaisnan_
+#define igraphdgehrd_	dgehrd_
+#define igraphdgehd2_	dgehd2_
+#define igraphdlarf_	dlarf_
+#define igraphiladlc_	iladlc_
+#define igraphiladlr_	iladlr_
+#define igraphdlarfg_	dlarfg_
+#define igraphdlapy2_	dlapy2_
+#define igraphdlahr2_	dlahr2_
+#define igraphdlacpy_	dlacpy_
+#define igraphdlarfb_	dlarfb_
+#define igraphilaenv_	ilaenv_
+#define igraphieeeck_	ieeeck_
+#define igraphiparmq_	iparmq_
+#define igraphdhseqr_	dhseqr_
+#define igraphdlahqr_	dlahqr_
+#define igraphdlabad_	dlabad_
+#define igraphdlanv2_	dlanv2_
+#define igraphdlaqr0_	dlaqr0_
+#define igraphdlaqr3_	dlaqr3_
+#define igraphdlaqr4_	dlaqr4_
+#define igraphdlaqr2_	dlaqr2_
+#define igraphdlaset_	dlaset_
+#define igraphdormhr_	dormhr_
+#define igraphdormqr_	dormqr_
+#define igraphdlarft_	dlarft_
+#define igraphdorm2r_	dorm2r_
+#define igraphdtrexc_	dtrexc_
+#define igraphdlaexc_	dlaexc_
+#define igraphdlange_	dlange_
+#define igraphdlassq_	dlassq_
+#define igraphdlarfx_	dlarfx_
+#define igraphdlartg_	dlartg_
+#define igraphdlasy2_	dlasy2_
+#define igraphdlaqr5_	dlaqr5_
+#define igraphdlaqr1_	dlaqr1_
+#define igraphdlascl_	dlascl_
+#define igraphdorghr_	dorghr_
+#define igraphdorgqr_	dorgqr_
+#define igraphdorg2r_	dorg2r_
+#define igraphdtrevc_	dtrevc_
+#define igraphdlaln2_	dlaln2_
+#define igraphdladiv_	dladiv_
+#define igraphdsyevr_	dsyevr_
+#define igraphdlansy_	dlansy_
+#define igraphdormtr_	dormtr_
+#define igraphdormql_	dormql_
+#define igraphdorm2l_	dorm2l_
+#define igraphdstebz_	dstebz_
+#define igraphdlaebz_	dlaebz_
+#define igraphdstein_	dstein_
+#define igraphdlagtf_	dlagtf_
+#define igraphdlagts_	dlagts_
+#define igraphdlarnv_	dlarnv_
+#define igraphdlaruv_	dlaruv_
+#define igraphdstemr_	dstemr_
+#define igraphdlae2_	dlae2_
+#define igraphdlaev2_	dlaev2_
+#define igraphdlanst_	dlanst_
+#define igraphdlarrc_	dlarrc_
+#define igraphdlarre_	dlarre_
+#define igraphdlarra_	dlarra_
+#define igraphdlarrb_	dlarrb_
+#define igraphdlaneg_	dlaneg_
+#define igraphdlarrd_	dlarrd_
+#define igraphdlarrk_	dlarrk_
+#define igraphdlasq2_	dlasq2_
+#define igraphdlasq3_	dlasq3_
+#define igraphdlasq4_	dlasq4_
+#define igraphdlasq5_	dlasq5_
+#define igraphdlasq6_	dlasq6_
+#define igraphdlasrt_	dlasrt_
+#define igraphdlarrj_	dlarrj_
+#define igraphdlarrr_	dlarrr_
+#define igraphdlarrv_	dlarrv_
+#define igraphdlar1v_	dlar1v_
+#define igraphdlarrf_	dlarrf_
+#define igraphdsterf_	dsterf_
+#define igraphdsytrd_	dsytrd_
+#define igraphdlatrd_	dlatrd_
+#define igraphdsytd2_	dsytd2_
+#define igraphdlanhs_	dlanhs_
+#define igraphdgeqr2_	dgeqr2_
+#define igraphdtrsen_	dtrsen_
+#define igraphdlacn2_	dlacn2_
+#define igraphdtrsyl_	dtrsyl_
+#define igraphdlasr_	dlasr_
+#define igraphdsteqr_	dsteqr_
+#define igraphdgesv_	dgesv_
+#define igraphdgetrf_	dgetrf_
+#define igraphdgetf2_	dgetf2_
+#define igraphdlaswp_	dlaswp_
+#define igraphdgetrs_	dgetrs_
+#define igraphlen_trim_ len_trim_
+#define igraph_dlamc1_  dlamc1_
+#define igraph_dlamc2_  dlamc2_
+#define igraph_dlamc3_  dlamc3_
+#define igraph_dlamc4_  dlamc4_
+#define igraph_dlamc5_  dlamc5_
+#endif
+
+int igraphdgetrf_(int *m, int *n, igraph_real_t *a, int *lda, int *ipiv,
+		  int *info);
+int igraphdgetrs_(char *trans, int *n, int *nrhs, igraph_real_t *a,
+		  int *lda, int *ipiv, igraph_real_t *b, int *ldb,
+		  int *info);
+int igraphdgesv_(int *n, int *nrhs, igraph_real_t *a, int *lda,
+		 int *ipiv, igraph_real_t *b, int *ldb, int *info);
+
+igraph_real_t igraphdlapy2_(igraph_real_t *x, igraph_real_t *y);
+
+int igraphdsyevr_(char *jobz, char *range, char *uplo, int *n, 
+		  igraph_real_t *a, int *lda, igraph_real_t *vl, 
+		  igraph_real_t *vu, int * il, int *iu, 
+		  igraph_real_t *abstol, int *m, igraph_real_t *w, 
+		  igraph_real_t *z, int *ldz, int *isuppz, 
+		  igraph_real_t *work, int *lwork, int *iwork, 
+		  int *liwork, int *info);
+
+int igraphdgeev_(char *jobvl, char *jobvr, int *n, igraph_real_t *a,
+		 int *lda, igraph_real_t *wr, igraph_real_t *wi, 
+		 igraph_real_t *vl, int *ldvl, igraph_real_t *vr, int *ldvr, 
+		 igraph_real_t *work, int *lwork, int *info);
+
+int igraphdgeevx_(char *balanc, char *jobvl, char *jobvr, char *sense, 
+		  int *n, igraph_real_t *a, int *lda, igraph_real_t *wr, 
+		  igraph_real_t *wi, igraph_real_t *vl, int *ldvl, 
+		  igraph_real_t *vr, int *ldvr, int *ilo, int *ihi, 
+		  igraph_real_t *scale, igraph_real_t *abnrm, 
+		  igraph_real_t *rconde, igraph_real_t *rcondv, 
+		  igraph_real_t *work, int *lwork, int *iwork, int *info);
+
+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);
+
+#endif
diff --git a/src/igraph_marked_queue.c b/src/igraph_marked_queue.c
new file mode 100644
index 0000000..bd08840
--- /dev/null
+++ b/src/igraph_marked_queue.c
@@ -0,0 +1,115 @@
+/* -*- 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_marked_queue.h"
+
+#define BATCH_MARKER -1
+
+int igraph_marked_queue_init(igraph_marked_queue_t *q,
+			     long int size) {
+  IGRAPH_CHECK(igraph_dqueue_init(&q->Q, 0));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &q->Q);
+  IGRAPH_CHECK(igraph_vector_long_init(&q->set, size));
+  q->mark=1;
+  q->size=0;
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+void igraph_marked_queue_destroy(igraph_marked_queue_t *q) {
+  igraph_vector_long_destroy(&q->set);
+  igraph_dqueue_destroy(&q->Q);
+}
+
+void igraph_marked_queue_reset(igraph_marked_queue_t *q) {
+  igraph_dqueue_clear(&q->Q);
+  q->size = 0;
+  q->mark += 1;
+  if (q->mark==0) {
+    igraph_vector_long_null(&q->set);
+    q->mark += 1;
+  }
+}
+
+igraph_bool_t igraph_marked_queue_empty(const igraph_marked_queue_t *q) {
+  return q->size == 0;
+}
+
+long int igraph_marked_queue_size(const igraph_marked_queue_t *q) {
+  return q->size;
+}
+
+igraph_bool_t igraph_marked_queue_iselement(const igraph_marked_queue_t *q, 
+					    long int elem) {
+  return (VECTOR(q->set)[elem] == q->mark);
+}
+
+int igraph_marked_queue_push(igraph_marked_queue_t *q, long int elem) {
+  if (VECTOR(q->set)[elem] != q->mark) {
+    IGRAPH_CHECK(igraph_dqueue_push(&q->Q, elem));
+    VECTOR(q->set)[elem] = q->mark;
+    q->size += 1;
+  }
+  return 0;
+}
+
+int igraph_marked_queue_start_batch(igraph_marked_queue_t *q) {
+  IGRAPH_CHECK(igraph_dqueue_push(&q->Q, BATCH_MARKER));
+  return 0;
+}
+
+void igraph_marked_queue_pop_back_batch(igraph_marked_queue_t *q) {
+  long int size=igraph_dqueue_size(&q->Q);
+  long int elem;
+  while (size > 0 && 
+	 (elem=(long int) igraph_dqueue_pop_back(&q->Q)) != BATCH_MARKER) {
+    VECTOR(q->set)[elem]=0;
+    size--;
+    q->size--;
+  }
+}
+
+#ifndef USING_R
+int igraph_marked_queue_print(const igraph_marked_queue_t *q) {
+  IGRAPH_CHECK(igraph_dqueue_print(&q->Q));
+  return 0;
+}
+#endif
+
+int igraph_marked_queue_fprint(const igraph_marked_queue_t *q, FILE *file) {
+  IGRAPH_CHECK(igraph_dqueue_fprint(&q->Q, file));
+  return 0;
+}
+
+int igraph_marked_queue_as_vector(const igraph_marked_queue_t *q, 
+				  igraph_vector_t *vec) {
+  long int i, p, n=igraph_dqueue_size(&q->Q);
+  IGRAPH_CHECK(igraph_vector_resize(vec, q->size));
+  for (i=0, p=0; i<n; i++) {
+    igraph_real_t e=igraph_dqueue_e(&q->Q, i);
+    if (e != BATCH_MARKER) {
+      VECTOR(*vec)[p++]=e;
+    }
+  }
+  return 0;
+}
diff --git a/src/igraph_marked_queue.h b/src/igraph_marked_queue.h
new file mode 100644
index 0000000..bad40b0
--- /dev/null
+++ b/src/igraph_marked_queue.h
@@ -0,0 +1,70 @@
+/* -*- 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_MARKED_QUEUE_H
+#define IGRAPH_MARKED_QUEUE_H
+
+#include "igraph_vector.h"
+#include "igraph_dqueue.h"
+
+#include <stdio.h>
+
+/* This is essentially a double ended queue, with some extra features:
+   (1) The is-element? operation is fast, O(1). This requires that we
+       know a limit for the number of elements in the queue.
+   (2) We can insert elements in batches, and the whole batch can be
+      removed at once.
+
+  Currently only the top-end operations are implemented, so the queue
+  is essentially a stack.
+*/
+
+typedef struct igraph_marked_queue_t {
+  igraph_dqueue_t Q;
+  igraph_vector_long_t set;
+  long int mark;
+  long int size;
+} igraph_marked_queue_t;
+
+int igraph_marked_queue_init(igraph_marked_queue_t *q,
+			     long int size);
+void igraph_marked_queue_destroy(igraph_marked_queue_t *q);
+void igraph_marked_queue_reset(igraph_marked_queue_t *q);
+
+igraph_bool_t igraph_marked_queue_empty(const igraph_marked_queue_t *q);
+long int igraph_marked_queue_size(const igraph_marked_queue_t *q);
+int igraph_marked_queue_print(const igraph_marked_queue_t *q);
+int igraph_marked_queue_fprint(const igraph_marked_queue_t *q, FILE *file);
+
+igraph_bool_t igraph_marked_queue_iselement(const igraph_marked_queue_t *q, 
+					    long int elem);
+
+int igraph_marked_queue_push(igraph_marked_queue_t *q, long int elem);
+
+int igraph_marked_queue_start_batch(igraph_marked_queue_t *q);
+void igraph_marked_queue_pop_back_batch(igraph_marked_queue_t *q);
+
+int igraph_marked_queue_as_vector(const igraph_marked_queue_t *q, 
+				  igraph_vector_t *vec);
+
+#endif
diff --git a/src/igraph_math.h b/src/igraph_math.h
new file mode 100644
index 0000000..4d33329
--- /dev/null
+++ b/src/igraph_math.h
@@ -0,0 +1,82 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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_MATH_H
+#define IGRAPH_MATH_H
+
+#include "config.h"
+#include <math.h>
+#include <stddef.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
+
+/*
+ * Compiler-related hacks, mostly because of Microsoft Visual C++
+ */
+double igraph_i_round(double X);
+int igraph_i_snprintf(char *buffer, size_t count, const char *format, ...);
+
+double igraph_log2(const double a);
+double igraph_log1p(double a);
+long double igraph_fabsl(long double a);
+double igraph_fmin(double a, double b);
+#ifndef HAVE_LOG2
+#define log2(a) igraph_log2(a)
+#endif
+#ifndef HAVE_LOG1P
+#define log1p(a) igraph_log1p(a)
+#endif
+#ifndef HAVE_FABSL
+#define fabsl(a) igraph_fabsl(a)
+#endif
+#ifndef HAVE_FMIN
+#define fmin(a,b) igraph_fmin((a),(b))
+#endif
+#ifndef HAVE_ROUND
+#define round igraph_i_round
+#endif
+
+#ifndef M_PI
+#  define M_PI 3.14159265358979323846
+#endif
+#ifndef M_LN2
+#  define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_SQRT2
+#  define M_SQRT2 1.4142135623730950488016887
+#endif
+
+__END_DECLS
+
+#endif
+
diff --git a/src/igraph_psumtree.c b/src/igraph_psumtree.c
new file mode 100644
index 0000000..3ff539e
--- /dev/null
+++ b/src/igraph_psumtree.c
@@ -0,0 +1,98 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard street, Cambridge, MA 02139 USA
+   Copyright (C) 2006 Elliot Paquette <Elliot.Paquette05 at kzoo.edu>
+   Kalamazoo College, 1200 Academy st, Kalamazoo, MI
+
+   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_types.h"
+#include "igraph_psumtree.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <math.h>
+#include <stdio.h>
+
+double igraph_i_log2(double f) {
+  return log(f) / log(2.0);
+}
+
+int igraph_psumtree_init(igraph_psumtree_t *t, long int size) {
+  t->size=size;
+  t->offset=(long int) (pow(2, ceil(igraph_i_log2(size)))-1);
+  IGRAPH_CHECK(igraph_vector_init((igraph_vector_t *)t, t->offset+t->size));
+  return 0;
+}
+
+void igraph_psumtree_destroy(igraph_psumtree_t *t) {
+  igraph_vector_destroy((igraph_vector_t *)t);
+}
+
+igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, long int idx) {
+  const igraph_vector_t *tree=&t->v;
+  return VECTOR(*tree)[t->offset+idx];
+}
+
+int igraph_psumtree_search(const igraph_psumtree_t *t, long int *idx,
+			   igraph_real_t search) {
+  const igraph_vector_t *tree=&t->v;
+  long int i = 1;
+  long int size = igraph_vector_size(tree);
+  
+  while( 2*i+1 <= size) {
+    if( search <= VECTOR(*tree)[i*2-1] ) {
+      i <<= 1;	
+    } else {
+      search -= VECTOR(*tree)[i*2-1];
+      i <<= 1;
+      i += 1;
+    }
+  }
+  if (2*i <= size) {
+    i=2*i;
+  }
+
+  *idx = i-t->offset-1;
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_psumtree_update(igraph_psumtree_t *t, long int idx, 
+			   igraph_real_t new_value) {
+  const igraph_vector_t *tree=&t->v;
+  igraph_real_t difference;
+  
+  idx = idx + t->offset+1;
+  difference = new_value - VECTOR(*tree)[idx-1];
+  
+  while( idx >= 1 ) {
+    VECTOR(*tree)[idx-1] += difference;
+    idx >>= 1;
+  }
+  return IGRAPH_SUCCESS;	
+}
+
+long int igraph_psumtree_size(const igraph_psumtree_t *t) {
+  return t->size;
+}
+
+igraph_real_t igraph_psumtree_sum(const igraph_psumtree_t *t) {
+  return VECTOR(t->v)[0];
+}
diff --git a/src/igraph_set.c b/src/igraph_set.c
new file mode 100644
index 0000000..fdc438c
--- /dev/null
+++ b/src/igraph_set.c
@@ -0,0 +1,310 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_types.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>     /* memmove */
+
+#define SET(s) ((s).stor_begin)
+
+/**
+ * \ingroup set
+ * \function igraph_set_init
+ * \brief Initializes a set.
+ *
+ * \param set pointer to the set to be initialized
+ * \param size the expected number of elements in the set
+ *
+ * \return error code:
+ *       \c IGRAPH_ENOMEM if there is not enough memory.
+ *
+ * Time complexity: operating system dependent, should be around
+ * O(n), n is the expected size of the set.
+ */
+int igraph_set_init(igraph_set_t *set, int long size) {
+  long int alloc_size = size > 0 ? size : 1;
+  if (size < 0) { size = 0; }
+  set->stor_begin=igraph_Calloc(alloc_size, igraph_integer_t);
+  set->stor_end=set->stor_begin + alloc_size;
+  set->end=set->stor_begin;
+
+  return 0;
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_destroy
+ * \brief Destroys a set object.
+ *
+ * \param set pointer to the set to be destroyed
+ *
+ * Time complexity: operating system dependent.
+ */
+void igraph_set_destroy(igraph_set_t* set) {
+  assert(set != 0);
+  if (set->stor_begin != 0) {
+    igraph_Free(set->stor_begin);
+    set->stor_begin = NULL;
+  }
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_inited
+ * \brief Determines whether a set is initialized or not.
+ *
+ * This function checks whether the internal storage for the members of the
+ * set has been allocated or not, and it assumes that the pointer for the
+ * internal storage area contains \c NULL if the area is not initialized yet.
+ * This only applies if you have allocated an array of sets with \c igraph_Calloc or
+ * if you used the \c IGRAPH_SET_NULL constant to initialize the set.
+ *
+ * \param set The set object.
+ *
+ * Time complexity: O(1)
+ */
+igraph_bool_t igraph_set_inited(igraph_set_t* set) {
+  return (set->stor_begin != 0);
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_reserve
+ * \brief Reserve memory for a set.
+ *
+ * \param set The set object.
+ * \param size the new \em allocated size of the set.
+ *
+ * Time complexity: operating system dependent, should be around
+ * O(n), n is the new allocated size of the set.
+ */
+int igraph_set_reserve(igraph_set_t* set, long int size) {
+  long int actual_size = igraph_set_size(set);
+  igraph_integer_t *tmp;
+  assert(set != NULL);
+  assert(set->stor_begin != NULL);
+  if (size <= actual_size) return 0;
+
+  tmp=igraph_Realloc(set->stor_begin, (size_t) size, igraph_integer_t);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot reserve space for set", IGRAPH_ENOMEM);
+  }
+  set->stor_begin=tmp;
+  set->stor_end=set->stor_begin+size;
+  set->end=set->stor_begin+actual_size;
+
+  return 0;
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_empty
+ * \brief Decides whether the size of the set is zero.
+ *
+ * \param set The set object.
+ * \return Non-zero number if the size of the set is not zero and
+ *         zero otherwise.
+ *
+ * Time complexity: O(1).
+ */
+igraph_bool_t igraph_set_empty(const igraph_set_t* set) {
+  assert(set != NULL);
+  assert(set->stor_begin != NULL);
+  return set->stor_begin == set->end;
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_clear
+ * \brief Removes all elements from a set.
+ * 
+ * </para><para>
+ * This function simply sets the size of the set to zero, it does
+ * not free any allocated memory. For that you have to call
+ * \ref igraph_set_destroy().
+ * \param v The set object.
+ * 
+ * Time complexity: O(1).
+ */
+void igraph_set_clear(igraph_set_t* set) {
+  assert(set != NULL);
+  assert(set->stor_begin != NULL);
+  set->end = set->stor_begin;
+}
+
+
+/**
+ * \ingroup set
+ * \function igraph_vector_set
+ * \brief Gives the size (=length) of the set.
+ * 
+ * \param v The set object
+ * \return The size of the set.
+ *
+ * Time complexity: O(1). 
+ */
+
+long int igraph_set_size(const igraph_set_t* set) {
+  assert(set != NULL);
+  assert(set->stor_begin != NULL);
+  return set->end-set->stor_begin;
+}
+
+
+/**
+ * \ingroup set
+ * \function igraph_set_add
+ * \brief Adds an element to the set.
+ *
+ * \param set The set object.
+ * \param e The element to be added.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM: not enough memory.
+ *
+ * Time complexity: O(log(n)), n is the number of elements in \p set.
+ */
+int igraph_set_add(igraph_set_t* set, igraph_integer_t e) {
+  long int left, right, middle;
+  long int size;
+  assert(set != NULL);
+  assert(set->stor_begin != NULL);
+
+  size = igraph_set_size(set);
+
+  /* search where to insert the new element */
+  left = 0;
+  right = size-1;
+  while (left < right-1) {
+    middle = (left+right)/2;
+    if (SET(*set)[middle] > e) {
+      right = middle;
+    } else if (SET(*set)[middle] < e) {
+      left = middle;
+    } else {
+      left = middle;
+      break;
+    }
+  }
+
+  if (right >= 0 && SET(*set)[left] != e && SET(*set)[right] == e) {
+    left = right;
+  }
+
+  while (left < size && set->stor_begin[left] < e) left++;
+  if (left >= size || set->stor_begin[left] != e) {
+    /* full, allocate more storage */
+    if (set->stor_end == set->end) {
+      long int new_size = size * 2;
+      if (new_size == 0) new_size = 1;
+      IGRAPH_CHECK(igraph_set_reserve(set, new_size));
+    }
+
+    /* Element should be inserted at position 'left' */
+    if (left < size)
+      memmove(set->stor_begin+left+1, set->stor_begin+left, 
+	      (size_t) (size-left)*sizeof(set->stor_begin[0]));
+
+    set->stor_begin[left] = e;
+    set->end += 1;
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_contains
+ * \brief Checks whether a given element is in the set or not.
+ *
+ * \param set The set object.
+ * \param e The element being sought.
+ * \return Positive integer (true) if \p e is found, zero (false) otherwise.
+ *
+ * Time complexity: O(log(n)), n is the number of elements in \p set.
+ */
+int igraph_set_contains(igraph_set_t* set, igraph_integer_t e) {
+  long int left, right, middle;
+
+  assert(set != NULL);
+  assert(set->stor_begin != NULL);
+
+  left = 0;
+  right = igraph_set_size(set)-1;
+
+  /* search for the new element */
+  while (left < right-1) {
+    middle = (left+right)/2;
+    if (SET(*set)[middle] > e) {
+      right = middle;
+    } else if (SET(*set)[middle] < e) {
+      left = middle;
+    } else {
+      left = middle;
+      return 1;
+    }
+  }
+
+  if (SET(*set)[left] != e && SET(*set)[right] == e) return 1;
+  return (SET(*set)[left] == e);
+}
+
+/**
+ * \ingroup set
+ * \function igraph_set_iterate
+ * \brief Iterates through the element to the set.
+ *
+ * Elements are returned in an arbitrary order.
+ *
+ * \param set The set object.
+ * \param state Internal state of the iteration.
+ *   This should be a pointer to a \c long variable
+ *   which must be zero for the first invocation.
+ *   The object should not be adjusted and its value should
+ *   not be used for anything during the iteration.
+ * \param element The next element or \c NULL (if the iteration
+ *   has ended) is returned here.
+ * 
+ * \return Nonzero if there are more elements, zero otherwise.
+ */
+igraph_bool_t igraph_set_iterate(igraph_set_t* set, long int* state,
+				 igraph_integer_t* element) {
+  assert(set != 0);
+  assert(set->stor_begin != 0);
+  assert(state != 0);
+  assert(element != 0);
+
+  if (*state < igraph_set_size(set)) {
+    *element = set->stor_begin[*state];
+    *state = *state+1;
+    return 1;
+  } else {
+    *element = 0;
+    return 0;
+  }
+}
+
diff --git a/src/igraph_stack.c b/src/igraph_stack.c
new file mode 100644
index 0000000..928f748
--- /dev/null
+++ b/src/igraph_stack.c
@@ -0,0 +1,83 @@
+/* -*- 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_types.h"
+#include "igraph_stack.h"
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "stack.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "stack.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "stack.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "stack.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_PTR
+#include "igraph_pmt.h"
+#include "stack.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_PTR
+
+/**
+ * \ingroup stack
+ * \brief Calls free() on all elements of a pointer stack.
+ */
+
+void igraph_stack_ptr_free_all   (igraph_stack_ptr_t* v) {
+  void **ptr;
+  assert(v != 0);
+  assert(v->stor_begin != 0);
+  for (ptr=v->stor_begin; ptr<v->end; ptr++) {
+    igraph_Free(*ptr);
+  }
+}
+
+/**
+ * \ingroup stack
+ * \brief Calls free() on all elements and destroys the stack.
+ */
+
+void igraph_stack_ptr_destroy_all   (igraph_stack_ptr_t* v) { 
+  assert(v != 0);
+  assert(v->stor_begin != 0);
+  igraph_stack_ptr_free_all(v);
+  igraph_stack_ptr_destroy(v);
+}
+
+
diff --git a/src/igraph_strvector.c b/src/igraph_strvector.c
new file mode 100644
index 0000000..0f8d602
--- /dev/null
+++ b/src/igraph_strvector.c
@@ -0,0 +1,590 @@
+/* -*- 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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_strvector.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+/**
+ * \section igraph_strvector_t 
+ * <para>The <type>igraph_strvector_t</type> type is a vector of strings. 
+ * The current implementation is very simple and not too efficient. It
+ * works fine for not too many strings, e.g. the list of attribute
+ * names is returned in a string vector by \ref
+ * igraph_cattribute_list(). Do not expect great performance from this
+ * type.</para>
+ * 
+ * <para>
+ * \example examples/simple/igraph_strvector.c
+ * </para>
+ */
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_init
+ * \brief Initialize
+ *
+ * Reserves memory for the string vector, a string vector must be
+ * first initialized before calling other functions on it.
+ * All elements of the string vector are set to the empty string.
+ * \param sv Pointer to an initialized string vector.
+ * \param len The (initial) length of the string vector.
+ * \return Error code.
+ * 
+ * Time complexity: O(\p len).
+ */
+
+int igraph_strvector_init(igraph_strvector_t *sv, long int len) {
+  long int i;
+  sv->data=igraph_Calloc(len, char*);
+  if (sv->data==0) {
+    IGRAPH_ERROR("strvector init failed", IGRAPH_ENOMEM);
+  }
+  for (i=0; i<len; i++) {
+    sv->data[i]=igraph_Calloc(1, char);
+    if (sv->data[i]==0) {
+      igraph_strvector_destroy(sv);
+      IGRAPH_ERROR("strvector init failed", IGRAPH_ENOMEM);
+    }
+    sv->data[i][0]='\0';
+  }
+  sv->len=len;
+
+  return 0;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_destroy
+ * \brief Free allocated memory
+ * 
+ * Destroy a string vector. It may be reinitialized with \ref
+ * igraph_strvector_init() later.
+ * \param sv The string vector.
+ * 
+ * Time complexity: O(l), the total length of the strings, maybe less
+ * depending on the memory manager.
+ */
+
+void igraph_strvector_destroy(igraph_strvector_t *sv) {
+  long int i;
+  assert(sv != 0);
+  if (sv->data != 0) {
+    for (i=0; i<sv->len; i++) {
+      if (sv->data[i] != 0) {
+	igraph_Free(sv->data[i]);
+      }
+    }
+    igraph_Free(sv->data);
+  }
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_get
+ * \brief Indexing
+ * 
+ * Query an element of a string vector. See also the \ref STR macro
+ * for an easier way.
+ * \param sv The input string vector.
+ * \param idx The index of the element to query. 
+ * \param Pointer to a <type>char*</type>, the address of the string
+ *   is stored here.
+ *
+ * Time complexity: O(1).
+ */
+
+void igraph_strvector_get(const igraph_strvector_t *sv, long int idx, 
+			  char **value) {
+  assert(sv != 0);
+  assert(sv->data != 0);
+  assert(sv->data[idx] != 0);
+  *value = sv->data[idx];
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_set
+ * \brief Set an element
+ *
+ * The provided \p value is copied into the \p idx position in the
+ * string vector.
+ * \param sv The string vector.
+ * \param idx The position to set.
+ * \param value The new value.
+ * \return Error code.
+ * 
+ * Time complexity: O(l), the length of the new string. Maybe more,
+ * depending on the memory management, if reallocation is needed.
+ */
+
+int igraph_strvector_set(igraph_strvector_t *sv, long int idx, 
+			 const char *value) {
+  assert(sv != 0);
+  assert(sv->data != 0);
+  if (sv->data[idx] == 0) {
+    sv->data[idx] = igraph_Calloc(strlen(value)+1, char);
+    if (sv->data[idx]==0) {
+      IGRAPH_ERROR("strvector set failed", IGRAPH_ENOMEM);
+    }
+  } else {
+    char *tmp=igraph_Realloc(sv->data[idx], strlen(value)+1, char);
+    if (tmp==0) { 
+      IGRAPH_ERROR("strvector set failed", IGRAPH_ENOMEM);
+    }
+    sv->data[idx]=tmp;
+  }
+  strcpy(sv->data[idx], value);
+  
+  return 0;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_set2
+ * \brief Sets an element
+ *
+ * This is almost the same as \ref igraph_strvector_set, but the new
+ * value is not a zero terminated string, but its length is given.
+ * \param sv The string vector.
+ * \param idx The position to set.
+ * \param value The new value.
+ * \param len The length of the new value.
+ * \return Error code.
+ * 
+ * Time complexity: O(l), the length of the new string. Maybe more,
+ * depending on the memory management, if reallocation is needed.
+ */
+int igraph_strvector_set2(igraph_strvector_t *sv, long int idx, 
+			  const char *value, int len) {
+  assert(sv != 0);
+  assert(sv->data != 0);
+  if (sv->data[idx] == 0) {
+    sv->data[idx] = igraph_Calloc(len+1, char);
+    if (sv->data[idx]==0) {
+      IGRAPH_ERROR("strvector set failed", IGRAPH_ENOMEM);
+    }
+  } else {
+    char *tmp=igraph_Realloc(sv->data[idx], (size_t) len+1, char);
+    if (tmp==0) { 
+      IGRAPH_ERROR("strvector set failed", IGRAPH_ENOMEM);
+    }
+    sv->data[idx]=tmp;
+  }
+  memcpy(sv->data[idx], value, (size_t) len*sizeof(char));
+  sv->data[idx][len]='\0';
+  
+  return 0;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_remove_section
+ * \brief Removes a section from a string vector.
+ * \todo repair realloc
+ */
+
+void igraph_strvector_remove_section(igraph_strvector_t *v, long int from, 
+				    long int to) {
+  long int i;
+/*   char **tmp; */
+  
+  assert(v != 0);
+  assert(v->data != 0);
+
+  for (i=from; i<to; i++) {
+    if (v->data[i] != 0) {
+      igraph_Free(v->data[i]);
+    }
+  }
+  for (i=0; i<v->len-to; i++) {
+    v->data[from+i]=v->data[to+i];
+  }
+  
+  v->len -= (to-from);
+
+  /* try to make it smaller */
+/*   tmp=igraph_Realloc(v->data, v->len, char*); */
+/*   if (tmp!=0) { */
+/*     v->data=tmp; */
+/*   } */
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_remove
+ * \brief Removes a single element from a string vector.
+ * 
+ * The string will be one shorter.
+ * \param The string vector.
+ * \param elem The index of the element to remove.
+ * 
+ * Time complexity: O(n), the length of the string.
+ */
+
+void igraph_strvector_remove(igraph_strvector_t *v, long int elem) {
+  assert(v != 0);
+  assert(v->data != 0);
+  igraph_strvector_remove_section(v, elem, elem+1);
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_move_interval
+ * \brief Copies an interval of a string vector.
+ */
+
+void igraph_strvector_move_interval(igraph_strvector_t *v, long int begin, 
+				   long int end, long int to) {
+  long int i;
+  assert(v != 0);
+  assert(v->data != 0);
+  for (i=to; i<to+end-begin; i++) {
+    if (v->data[i] != 0) {
+      igraph_Free(v->data[i]);
+    }
+  }
+  for (i=0; i<end-begin; i++) {
+    if (v->data[begin+i] != 0) {
+      size_t len=strlen(v->data[begin+i])+1;
+      v->data[to+i]=igraph_Calloc(len, char);
+      memcpy(v->data[to+i], v->data[begin+i], sizeof(char)*len);
+    }
+  }
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_copy
+ * \brief Initialization by copying.
+ *
+ * Initializes a string vector by copying another string vector.
+ * \param to Pointer to an uninitialized string vector.
+ * \param from The other string vector, to be copied.
+ * \return Error code.
+ * 
+ * Time complexity: O(l), the total length of the strings in \p from.
+ */
+
+int igraph_strvector_copy(igraph_strvector_t *to, 
+			  const igraph_strvector_t *from) {
+  long int i;
+  char *str;
+  assert(from != 0);
+/*   assert(from->data != 0); */
+  to->data=igraph_Calloc(from->len, char*);
+  if (to->data==0) { 
+    IGRAPH_ERROR("Cannot copy string vector", IGRAPH_ENOMEM);
+  }
+  to->len=from->len;
+  
+  for (i=0; i<from->len; i++) {
+    int ret;
+    igraph_strvector_get(from, i, &str);
+    ret=igraph_strvector_set(to, i, str);
+    if (ret != 0) {
+      igraph_strvector_destroy(to);
+      IGRAPH_ERROR("cannot copy string vector", ret);
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_strvector_append
+ * Concatenate two string vectors.
+ * 
+ * \param to The first string vector, the result is stored here.
+ * \param from The second string vector, it is kept unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(n+l2), n is the number of strings in the new
+ * string vector, l2 is the total length of strings in the \p from
+ * string vector.
+ */
+
+int igraph_strvector_append(igraph_strvector_t *to,
+			    const igraph_strvector_t *from) {
+  long int len1=igraph_strvector_size(to), len2=igraph_strvector_size(from);
+  long int i;
+  igraph_bool_t error=0;
+  IGRAPH_CHECK(igraph_strvector_resize(to, len1+len2));
+  for (i=0; i<len2; i++) {
+    if (from->data[i][0] != '\0') {
+      igraph_Free(to->data[len1+i]);
+      to->data[len1+i] = strdup(from->data[i]);
+      if (!to->data[len1+i]) {
+	error=1; 
+	break;
+      }
+    }
+  }
+  if (error) {
+    igraph_strvector_resize(to, len1);
+    IGRAPH_ERROR("Cannot append string vector", IGRAPH_ENOMEM);
+  }
+  return 0;
+} 
+
+/**
+ * \function igraph_strvector_clear
+ * Remove all elements
+ * 
+ * After this operation the string vector will be empty.
+ * \param sv The string vector.
+ * 
+ * Time complexity: O(l), the total length of strings, maybe less,
+ * depending on the memory manager.
+ */
+
+void igraph_strvector_clear(igraph_strvector_t *sv) {
+  long int i, n=igraph_strvector_size(sv);
+  char **tmp;
+
+  for (i=0; i<n; i++) {
+    igraph_Free(sv->data[i]);
+  }
+  sv->len=0;
+  /* try to give back some memory */
+  tmp=igraph_Realloc(sv->data, 1, char*);
+  if (tmp != 0) {
+    sv->data=tmp;
+  }
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_resize
+ * \brief Resize
+ *
+ * If the new size is bigger then empty strings are added, if it is
+ * smaller then the unneeded elements are removed.
+ * \param v The string vector.
+ * \param newsize The new size.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of strings if the vector is made
+ * bigger, O(l), the total length of the deleted strings if it is made
+ * smaller, maybe less, depending on memory management.
+ */
+
+int igraph_strvector_resize(igraph_strvector_t* v, long int newsize) {
+  long int toadd=newsize-v->len, i, j;
+  char **tmp;
+  long int reallocsize=newsize;
+  if (reallocsize==0) { reallocsize=1; }
+  
+  assert(v != 0);
+  assert(v->data != 0);
+/*   printf("resize %li to %li\n", v->len, newsize); */
+  if (newsize < v->len) { 
+    for (i=newsize; i<v->len; i++) {
+      igraph_Free(v->data[i]);
+    }
+    /* try to give back some space */
+    tmp=igraph_Realloc(v->data, (size_t) reallocsize, char*);
+/*     printf("resize %li to %li, %p\n", v->len, newsize, tmp); */
+    if (tmp != 0) {
+      v->data=tmp;
+    }
+  } else if (newsize > v->len) {
+    igraph_bool_t error=0;
+    tmp=igraph_Realloc(v->data, (size_t) reallocsize, char*);
+    if (tmp==0) {
+      IGRAPH_ERROR("cannot resize string vector", IGRAPH_ENOMEM);
+    }
+    v->data = tmp;
+    
+    for (i=0; i<toadd; i++) {
+      v->data[v->len+i] = igraph_Calloc(1, char);
+      if (v->data[v->len+i] == 0) {
+	error=1;
+	break;
+      }
+      v->data[v->len+i][0]='\0';
+    }
+    if (error) {
+      /* There was an error, free everything we've allocated so far */
+      for (j=0; j<i; j++) {
+	if (v->data[v->len+i] != 0) {
+	  igraph_Free(v->data[v->len+i]);
+	}
+      }
+      /* Try to give back space */
+      tmp=igraph_Realloc(v->data, (size_t) (v->len), char*);
+      if (tmp != 0) {
+	v->data=tmp;
+      }
+      IGRAPH_ERROR("Cannot resize string vector", IGRAPH_ENOMEM);
+    }
+  }
+  v->len = newsize;
+  
+  return 0;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_size
+ * \brief Gives the size of a string vector.
+ * 
+ * \param sv The string vector.
+ * \return The length of the string vector.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int igraph_strvector_size(const igraph_strvector_t *sv) {
+  assert(sv != 0);
+  assert(sv->data != 0);
+  return sv->len;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_add
+ * \brief Adds an element to the back of a string vector.
+ * 
+ * \param v The string vector. 
+ * \param value The string to add, it will be copied.
+ * \return Error code.
+ * 
+ * Time complexity: O(n+l), n is the total number of strings, l is the
+ * length of the new string.
+ */
+
+int igraph_strvector_add(igraph_strvector_t *v, const char *value) {
+  long int s=igraph_strvector_size(v);
+  char **tmp;
+  assert(v != 0);
+  assert(v->data != 0);
+  tmp=igraph_Realloc(v->data, (size_t) s+1, char*);
+  if (tmp == 0) {
+    IGRAPH_ERROR("cannot add string to string vector", IGRAPH_ENOMEM);
+  }
+  v->data=tmp;
+  v->data[s]=igraph_Calloc(strlen(value)+1, char);
+  if (v->data[s]==0) {
+    IGRAPH_ERROR("cannot add string to string vector", IGRAPH_ENOMEM);
+  }
+  strcpy(v->data[s], value);
+  v->len += 1;
+
+  return 0;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_permdelete
+ * \brief Removes elements from a string vector (for internal use)
+ */
+
+void igraph_strvector_permdelete(igraph_strvector_t *v, const igraph_vector_t *index,
+				long int nremove) {
+  long int i;
+  char **tmp;
+  assert(v != 0);
+  assert(v->data != 0);
+
+  for (i=0; i<igraph_strvector_size(v); i++) {
+    if (VECTOR(*index)[i] != 0) {
+      v->data[ (long int) VECTOR(*index)[i]-1 ] = v->data[i];
+    } else {
+      igraph_Free(v->data[i]);
+    }
+  }
+  /* Try to make it shorter */  
+  tmp=igraph_Realloc(v->data, v->len-nremove ? 
+		     (size_t) (v->len-nremove) : 1, char*);
+  if (tmp != 0) {
+    v->data=tmp;
+  }
+  v->len -= nremove;
+}
+
+/**
+ * \ingroup strvector
+ * \function igraph_strvector_remove_negidx
+ * \brief Removes elements from a string vector (for internal use)
+ */
+
+void igraph_strvector_remove_negidx(igraph_strvector_t *v, const igraph_vector_t *neg,
+				   long int nremove) {
+  long int i, idx=0;
+  char **tmp;
+  assert(v != 0);
+  assert(v->data != 0);
+  for (i=0; i<igraph_strvector_size(v); i++) {
+    if (VECTOR(*neg)[i] >= 0) {
+      v->data[idx++] = v->data[i];
+    } else {
+      igraph_Free(v->data[i]);
+    }
+  }
+  /* Try to give back some memory */
+  tmp=igraph_Realloc(v->data, v->len-nremove ? 
+		     (size_t) (v->len-nremove) : 1, char*);
+  if (tmp != 0) {
+    v->data=tmp;
+  }
+  v->len -= nremove;
+}
+
+int igraph_strvector_print(const igraph_strvector_t *v, FILE *file,
+			   const char *sep) {
+
+  long int i, n=igraph_strvector_size(v);
+  if (n!=0) {
+    fprintf(file, "%s", STR(*v, 0));
+  }
+  for (i=1; i<n; i++) {
+    fprintf(file, "%s%s", sep, STR(*v, i));
+  }
+  return 0;
+
+}
+
+int igraph_strvector_index(const igraph_strvector_t *v, 
+                           igraph_strvector_t *newv,
+                           const igraph_vector_t *idx) {
+  
+  long int i, newlen=igraph_vector_size(idx);
+  IGRAPH_CHECK(igraph_strvector_resize(newv, newlen));
+
+  for (i=0; i<newlen; i++) {
+    long int j=(long int) VECTOR(*idx)[i];
+    char *str;
+    igraph_strvector_get(v, j, &str);
+    igraph_strvector_set(newv, i, str);
+  }
+  
+  return 0;
+}
diff --git a/src/igraph_trie.c b/src/igraph_trie.c
new file mode 100644
index 0000000..34381ba
--- /dev/null
+++ b/src/igraph_trie.c
@@ -0,0 +1,389 @@
+/* -*- 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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+/**
+ * \ingroup igraphtrie
+ * \brief Creates a trie node (not to be called directly)
+ * \return Error code: errors by igraph_strvector_init(),
+ *         igraph_vector_ptr_init() and igraph_vector_init() might be returned.
+ */
+
+int igraph_i_trie_init_node(igraph_trie_node_t *t) { 
+  IGRAPH_STRVECTOR_INIT_FINALLY(&t->strs, 0);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->children, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&t->values, 0);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}  
+
+void igraph_i_trie_destroy_node(igraph_trie_node_t *t, igraph_bool_t sfree);
+
+/**
+ * \ingroup igraphtrie
+ * \brief Creates a trie.
+ * \return Error code: errors by igraph_strvector_init(),
+ *         igraph_vector_ptr_init() and igraph_vector_init() might be returned.
+ */
+
+int igraph_trie_init(igraph_trie_t *t, igraph_bool_t storekeys) {
+  t->maxvalue=-1;
+  t->storekeys=storekeys;
+  IGRAPH_CHECK(igraph_i_trie_init_node( (igraph_trie_node_t *)t ));
+  IGRAPH_FINALLY(igraph_i_trie_destroy_node, t);
+  if (storekeys) {
+    IGRAPH_CHECK(igraph_strvector_init(&t->keys, 0));
+  }
+
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Destroys a node of a trie (not to be called directly).
+ */
+
+void igraph_i_trie_destroy_node(igraph_trie_node_t *t, igraph_bool_t sfree) {
+  long int i;
+  igraph_strvector_destroy(&t->strs);
+  for (i=0; i<igraph_vector_ptr_size(&t->children); i++) {
+    igraph_trie_node_t *child=VECTOR(t->children)[i];
+    if (child != 0) {
+      igraph_i_trie_destroy_node(child, 1);
+    }
+  }
+  igraph_vector_ptr_destroy(&t->children);
+  igraph_vector_destroy(&t->values);
+  if (sfree) { igraph_Free(t); }
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Destroys a trie (frees allocated memory).
+ */
+
+void igraph_trie_destroy(igraph_trie_t *t) {
+  if (t->storekeys) {
+    igraph_strvector_destroy(&t->keys);
+  }
+  igraph_i_trie_destroy_node( (igraph_trie_node_t*) t, 0);
+}
+
+
+/**
+ * \ingroup igraphtrie
+ * \brief Internal helping function for igraph_trie_t
+ */
+
+long int igraph_i_strdiff(const char *str, const char *key) {
+
+  long int diff=0;
+  while (key[diff] != '\0' && str[diff] != '\0' && str[diff]==key[diff]) {
+    diff++;
+  }
+  return diff;
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Search/insert in a trie (not to be called directly).
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_trie_get_node(igraph_trie_node_t *t, const char *key, 
+			 igraph_real_t newvalue, long int *id) {
+  char *str;
+  long int i;
+  igraph_bool_t add;
+
+  /* If newvalue is negative, we don't add the node if nonexistent, only check
+   * for its existence */
+  add = (newvalue>=0);
+
+  for (i=0; i<igraph_strvector_size(&t->strs); i++) {
+    long int diff;
+    igraph_strvector_get(&t->strs, i, &str);
+    diff=igraph_i_strdiff(str, key);
+    
+    if (diff == 0) {
+
+      /* ------------------------------------ */
+      /* No match, next */
+
+    } else if (str[diff]=='\0' && key[diff]=='\0') {
+
+      /* ------------------------------------ */
+      /* They are exactly the same */
+      if (VECTOR(t->values)[i] != -1) {
+	*id=(long int) VECTOR(t->values)[i];
+	return 0;
+      } else {
+	VECTOR(t->values)[i]=newvalue;
+	*id=(long int) newvalue;
+	return 0;
+      }
+
+    } else if (str[diff]=='\0') {
+
+      /* ------------------------------------ */
+      /* str is prefix of key, follow its link if there is one */
+      igraph_trie_node_t *node=VECTOR(t->children)[i];
+      if (node != 0) {
+	return igraph_trie_get_node(node, key+diff, newvalue, id);
+      } else if (add) {
+	igraph_trie_node_t *node=igraph_Calloc(1, igraph_trie_node_t);
+	if (node==0) {
+	  IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
+	}
+	IGRAPH_STRVECTOR_INIT_FINALLY(&node->strs, 1);
+	IGRAPH_VECTOR_PTR_INIT_FINALLY(&node->children, 1);
+	IGRAPH_VECTOR_INIT_FINALLY(&node->values, 1);
+	IGRAPH_CHECK(igraph_strvector_set(&node->strs, 0, key+diff));
+	VECTOR(node->children)[0]=0;
+	VECTOR(node->values)[0]=newvalue;
+
+	VECTOR(t->children)[i]=node;
+
+	*id=(long int) newvalue;
+	IGRAPH_FINALLY_CLEAN(3);
+	return 0;
+      } else {
+	*id=-1;
+	return 0;
+      }
+
+    } else if (key[diff]=='\0' && add) {
+
+      /* ------------------------------------ */
+      /* key is prefix of str, the node has to be cut */
+      char *str2;
+      
+      igraph_trie_node_t *node=igraph_Calloc(1, igraph_trie_node_t);
+      if (node==0) {
+	IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
+      }
+      IGRAPH_STRVECTOR_INIT_FINALLY(&node->strs, 1);
+      IGRAPH_VECTOR_PTR_INIT_FINALLY(&node->children, 1);
+      IGRAPH_VECTOR_INIT_FINALLY(&node->values, 1);
+      IGRAPH_CHECK(igraph_strvector_set(&node->strs, 0, str+diff));
+      
+      VECTOR(node->children)[0]=VECTOR(t->children)[i];
+      VECTOR(node->values)[0]=VECTOR(t->values)[i];
+
+      str2=strdup(str);
+      if (str2 == 0) {
+	IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
+      }
+      str2[diff]='\0';
+      IGRAPH_FINALLY(free, str2);
+      IGRAPH_CHECK(igraph_strvector_set(&t->strs, i, str2));
+      free(str2);
+      IGRAPH_FINALLY_CLEAN(4);
+      
+      VECTOR(t->values)[i]=newvalue;
+      VECTOR(t->children)[i]=node;
+      
+      *id=(long int) newvalue;
+      return 0;
+
+    } else if (add) {
+
+      /* ------------------------------------ */
+      /* the first diff characters match */
+      char *str2;
+
+      igraph_trie_node_t *node=igraph_Calloc(1, igraph_trie_node_t);
+      if (node==0) {
+	IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
+      }
+      IGRAPH_STRVECTOR_INIT_FINALLY(&node->strs, 2);
+      IGRAPH_VECTOR_PTR_INIT_FINALLY(&node->children, 2);
+      IGRAPH_VECTOR_INIT_FINALLY(&node->values, 2);
+      IGRAPH_CHECK(igraph_strvector_set(&node->strs, 0, str+diff));
+      IGRAPH_CHECK(igraph_strvector_set(&node->strs, 1, key+diff));
+      VECTOR(node->children)[0]=VECTOR(t->children)[i];
+      VECTOR(node->children)[1]=0;
+      VECTOR(node->values)[0]=VECTOR(t->values)[i];
+      VECTOR(node->values)[1]=newvalue;
+
+      str2=strdup(str);
+      if (str2 == 0) {
+	IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
+      }
+      str2[diff]='\0';
+      IGRAPH_FINALLY(free, str2);
+      IGRAPH_CHECK(igraph_strvector_set(&t->strs, i, str2));
+      free(str2);
+      IGRAPH_FINALLY_CLEAN(4);
+
+      VECTOR(t->values)[i]=-1;
+      VECTOR(t->children)[i]=node;
+      
+      *id=(long int) newvalue;
+      return 0;
+    } else {
+      
+      /* ------------------------------------------------- */
+      /* No match, but we requested not to add the new key */
+      *id=-1;
+      return 0;
+    }
+  }
+
+  /* ------------------------------------ */
+  /* Nothing matches */
+
+  if (add) {
+    IGRAPH_CHECK(igraph_vector_ptr_reserve(&t->children, 
+					   igraph_vector_ptr_size(&t->children)+1));
+    IGRAPH_CHECK(igraph_vector_reserve(&t->values, igraph_vector_size(&t->values)+1));
+    IGRAPH_CHECK(igraph_strvector_add(&t->strs, key));
+
+    igraph_vector_ptr_push_back(&t->children, 0); /* allocated */
+    igraph_vector_push_back(&t->values, newvalue); /* allocated */
+    *id=(long int) newvalue;
+  } else {
+    *id=-1;
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Search/insert in a trie.
+ */
+
+int igraph_trie_get(igraph_trie_t *t, const char *key, long int *id) {
+  if (!t->storekeys) {
+    IGRAPH_CHECK(igraph_trie_get_node( (igraph_trie_node_t*) t, 
+				       key, t->maxvalue+1, id));
+    if (*id > t->maxvalue) {
+      t->maxvalue=*id;
+    }
+    return 0;
+  } else {
+    int ret;
+    igraph_error_handler_t *oldhandler;
+    oldhandler=igraph_set_error_handler(igraph_error_handler_ignore);
+    /* Add it to the string vector first, we can undo this later */
+    ret=igraph_strvector_add(&t->keys, key);
+    if (ret != 0) {
+      igraph_set_error_handler(oldhandler);
+      IGRAPH_ERROR("cannot get element from trie", ret);
+    }
+    ret = igraph_trie_get_node( (igraph_trie_node_t*) t,
+				key, t->maxvalue+1, id);
+    if (ret != 0) {
+      igraph_strvector_resize(&t->keys, igraph_strvector_size(&t->keys)-1);
+      igraph_set_error_handler(oldhandler);
+      IGRAPH_ERROR("cannot get element from trie", ret);
+    }
+    
+    /* everything is fine */
+    if (*id > t->maxvalue) {
+      t->maxvalue=*id;
+    } else {
+      igraph_strvector_resize(&t->keys, igraph_strvector_size(&t->keys)-1);
+    }
+    igraph_set_error_handler(oldhandler);    
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Search/insert in a trie (for internal use).
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_trie_get2(igraph_trie_t *t, const char *key, long int length,
+		     long int *id) {
+  char *tmp=igraph_Calloc(length+1, char);
+
+  if (tmp==0) {
+    IGRAPH_ERROR("Cannot get from trie", IGRAPH_ENOMEM);
+  }
+  
+  strncpy(tmp, key, length);
+  tmp[length]='\0';
+  IGRAPH_FINALLY(free, tmp);
+  IGRAPH_CHECK(igraph_trie_get(t, tmp, id));
+  igraph_Free(tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Search in a trie.
+ * This variant does not add \c key to the trie if it does not exist.
+ * In this case, a negative id is returned.
+ */
+
+int igraph_trie_check(igraph_trie_t *t, const char *key, long int *id) {
+  IGRAPH_CHECK(igraph_trie_get_node( (igraph_trie_node_t*) t, 
+				     key, -1, id));
+  return 0;
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Get an element of a trie based on its index.
+ */
+
+void igraph_trie_idx(igraph_trie_t *t, long int idx, char **str) {
+  igraph_strvector_get(&t->keys, idx, str);
+}
+
+/**
+ * \ingroup igraphtrie
+ * \brief Returns the size of a trie.
+ */
+
+long int igraph_trie_size(igraph_trie_t *t) {
+  return t->maxvalue+1;
+}
+
+/* Hmmm, very dirty.... */
+
+int igraph_trie_getkeys(igraph_trie_t *t, const igraph_strvector_t **strv) {
+  *strv=&t->keys;
+  return 0;
+}
diff --git a/src/igraph_types_internal.h b/src/igraph_types_internal.h
new file mode 100644
index 0000000..87aa967
--- /dev/null
+++ b/src/igraph_types_internal.h
@@ -0,0 +1,395 @@
+/* -*- 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_TYPES_INTERNAL_H
+#define IGRAPH_TYPES_INTERNAL_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_matrix.h"
+#include "igraph_stack.h"
+#include "igraph_strvector.h"
+#include "igraph_vector.h"
+#include "igraph_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Indexed heap                                       */
+/* -------------------------------------------------- */
+
+/**
+ * Indexed heap data type.
+ * \ingroup internal
+ */
+
+typedef struct s_indheap {
+  igraph_real_t* stor_begin;
+  igraph_real_t* stor_end;
+  igraph_real_t* end;
+  int destroy;
+  long int* index_begin;
+} igraph_indheap_t;
+
+#define IGRAPH_INDHEAP_NULL { 0,0,0,0,0 }
+
+int igraph_indheap_init           (igraph_indheap_t* h, long int size);
+int igraph_indheap_init_array     (igraph_indheap_t *t, igraph_real_t* data, long int len);
+void igraph_indheap_destroy        (igraph_indheap_t* h);
+int igraph_indheap_clear(igraph_indheap_t *h);
+igraph_bool_t igraph_indheap_empty          (igraph_indheap_t* h);
+int igraph_indheap_push           (igraph_indheap_t* h, igraph_real_t elem);
+int igraph_indheap_push_with_index(igraph_indheap_t* h, long int idx, igraph_real_t elem);
+int igraph_indheap_modify(igraph_indheap_t* h, long int idx, igraph_real_t elem);
+igraph_real_t igraph_indheap_max       (igraph_indheap_t* h);
+igraph_real_t igraph_indheap_delete_max(igraph_indheap_t* h);
+long int igraph_indheap_size      (igraph_indheap_t* h);
+int igraph_indheap_reserve        (igraph_indheap_t* h, long int size);
+long int igraph_indheap_max_index(igraph_indheap_t *h);
+
+void igraph_indheap_i_build(igraph_indheap_t* h, long int head);
+void igraph_indheap_i_shift_up(igraph_indheap_t* h, long int elem);
+void igraph_indheap_i_sink(igraph_indheap_t* h, long int head);
+void igraph_indheap_i_switch(igraph_indheap_t* h, long int e1, long int e2);
+
+/* -------------------------------------------------- */
+/* Doubly indexed heap                                */
+/* -------------------------------------------------- */
+
+/* This is a heap containing double elements and 
+   two indices, its intended usage is the storage of
+   weighted edges.
+*/
+
+/**
+ * Doubly indexed heap data type.
+ * \ingroup internal
+ */
+
+typedef struct s_indheap_d {
+  igraph_real_t* stor_begin;
+  igraph_real_t* stor_end;
+  igraph_real_t* end;
+  int destroy;
+  long int* index_begin;
+  long int* index2_begin;
+} igraph_d_indheap_t;
+
+
+#define IGRAPH_D_INDHEAP_NULL { 0,0,0,0,0,0 }
+
+int igraph_d_indheap_init           (igraph_d_indheap_t* h, long int size);
+void igraph_d_indheap_destroy        (igraph_d_indheap_t* h);
+igraph_bool_t igraph_d_indheap_empty          (igraph_d_indheap_t* h);
+int igraph_d_indheap_push           (igraph_d_indheap_t* h, igraph_real_t elem, 
+			      long int idx, long int idx2);
+igraph_real_t igraph_d_indheap_max       (igraph_d_indheap_t* h);
+igraph_real_t igraph_d_indheap_delete_max(igraph_d_indheap_t* h);
+long int igraph_d_indheap_size      (igraph_d_indheap_t* h);
+int igraph_d_indheap_reserve        (igraph_d_indheap_t* h, long int size);
+void igraph_d_indheap_max_index(igraph_d_indheap_t *h, long int *idx, long int *idx2);
+
+void igraph_d_indheap_i_build(igraph_d_indheap_t* h, long int head);
+void igraph_d_indheap_i_shift_up(igraph_d_indheap_t* h, long int elem);
+void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, long int head);
+void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, long int e1, long int e2);
+
+/* -------------------------------------------------- */
+/* Two-way indexed heap                               */
+/* -------------------------------------------------- */
+
+/* This is a smart indexed heap. In addition to the "normal" indexed heap
+   it allows to access every element through its index in O(1) time. 
+   In other words, for this heap the _modify operation is O(1), the 
+   normal heap does this in O(n) time.... */
+
+typedef struct igraph_2wheap_t {
+  long int size;
+  igraph_vector_t data;
+  igraph_vector_long_t index;
+  igraph_vector_long_t index2;
+} igraph_2wheap_t;
+
+int igraph_2wheap_init(igraph_2wheap_t *h, long int size);
+void igraph_2wheap_destroy(igraph_2wheap_t *h);
+int igraph_2wheap_clear(igraph_2wheap_t *h);
+int igraph_2wheap_push_with_index(igraph_2wheap_t *h, 
+				  long int idx, igraph_real_t elem);
+igraph_bool_t igraph_2wheap_empty(const igraph_2wheap_t *h);
+long int igraph_2wheap_size(const igraph_2wheap_t *h);
+long int igraph_2wheap_max_size(const igraph_2wheap_t *h);
+igraph_real_t igraph_2wheap_max(const igraph_2wheap_t *h);
+long int igraph_2wheap_max_index(const igraph_2wheap_t *h);
+igraph_real_t igraph_2wheap_deactivate_max(igraph_2wheap_t *h);
+igraph_bool_t igraph_2wheap_has_elem(const igraph_2wheap_t *h, long int idx);
+igraph_bool_t igraph_2wheap_has_active(const igraph_2wheap_t *h, long int idx);
+igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, long int idx);
+igraph_real_t igraph_2wheap_delete_max(igraph_2wheap_t *h);
+igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, long int *idx);
+int igraph_2wheap_modify(igraph_2wheap_t *h, long int idx, igraph_real_t elem);
+int igraph_2wheap_check(igraph_2wheap_t *h);
+
+/**
+ * Trie data type
+ * \ingroup internal
+ */
+
+typedef struct s_igraph_trie_node {
+  igraph_strvector_t strs;
+  igraph_vector_ptr_t children;
+  igraph_vector_t values;
+} igraph_trie_node_t;
+
+typedef struct s_igraph_trie {
+  igraph_strvector_t strs;
+  igraph_vector_ptr_t children;
+  igraph_vector_t values;
+  long int maxvalue;
+  igraph_bool_t storekeys;
+  igraph_strvector_t keys;
+} igraph_trie_t;
+
+#define IGRAPH_TRIE_NULL { IGRAPH_STRVECTOR_NULL, IGRAPH_VECTOR_PTR_NULL, \
+                           IGRAPH_VECTOR_NULL, 0, 0, IGRAPH_STRVECTOR_NULL }
+#define IGRAPH_TRIE_INIT_FINALLY(tr, sk) \
+  do { IGRAPH_CHECK(igraph_trie_init(tr, sk)); \
+  IGRAPH_FINALLY(igraph_trie_destroy, tr); } while (0)
+
+int igraph_trie_init(igraph_trie_t *t, igraph_bool_t storekeys);
+void igraph_trie_destroy(igraph_trie_t *t);
+int igraph_trie_get(igraph_trie_t *t, const char *key, long int *id);
+int igraph_trie_check(igraph_trie_t *t, const char *key, long int *id);
+int igraph_trie_get2(igraph_trie_t *t, const char *key, long int length, 
+		     long int *id);
+void igraph_trie_idx(igraph_trie_t *t, long int idx, char **str);
+int igraph_trie_getkeys(igraph_trie_t *t, const igraph_strvector_t **strv);
+long int igraph_trie_size(igraph_trie_t *t);
+
+/**
+ * 2d grid containing points
+ */
+
+typedef struct igraph_2dgrid_t {
+  igraph_matrix_t *coords;
+  igraph_real_t minx, maxx, deltax;
+  igraph_real_t miny, maxy, deltay;
+  long int stepsx, stepsy;
+  igraph_matrix_t startidx;
+  igraph_vector_t next;
+  igraph_vector_t prev;
+  igraph_real_t massx, massy;		/* The sum of the coordinates */
+  long int vertices;		/* Number of active vertices  */
+} igraph_2dgrid_t;
+
+int igraph_2dgrid_init(igraph_2dgrid_t *grid, igraph_matrix_t *coords, 
+		       igraph_real_t minx, igraph_real_t maxx, igraph_real_t deltax,
+		       igraph_real_t miny, igraph_real_t maxy, igraph_real_t deltay);
+void igraph_2dgrid_destroy(igraph_2dgrid_t *grid);
+void igraph_2dgrid_add(igraph_2dgrid_t *grid, long int elem, 
+		       igraph_real_t xc, igraph_real_t yc);
+void igraph_2dgrid_add2(igraph_2dgrid_t *grid, long int elem);
+void igraph_2dgrid_move(igraph_2dgrid_t *grid, long int elem, 
+			igraph_real_t xc, igraph_real_t yc);
+void igraph_2dgrid_getcenter(const igraph_2dgrid_t *grid, 
+			     igraph_real_t *massx, igraph_real_t *massy);
+igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, long int elem);
+igraph_real_t igraph_2dgrid_dist(const igraph_2dgrid_t *grid, 
+			  long int e1, long int e2);
+int igraph_2dgrid_neighbors(igraph_2dgrid_t *grid, igraph_vector_t *eids, 
+			    igraph_integer_t vid, igraph_real_t r);
+
+typedef struct igraph_2dgrid_iterator_t {
+  long int vid, x, y;
+  long int nei;
+  long int nx[4], ny[4], ncells;
+} igraph_2dgrid_iterator_t;
+
+void igraph_2dgrid_reset(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it);
+igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid, 
+			      igraph_2dgrid_iterator_t *it);
+igraph_integer_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid,
+				 igraph_2dgrid_iterator_t *it);
+
+/* Another type of grid, each cell is owned by exactly one graph */
+
+typedef struct igraph_i_layout_mergegrid_t {
+  long int *data;
+  long int stepsx, stepsy;
+  igraph_real_t minx, maxx, deltax;
+  igraph_real_t miny, maxy, deltay;
+} igraph_i_layout_mergegrid_t;
+
+int igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t *grid,
+				   igraph_real_t minx, igraph_real_t maxx, long int stepsx,
+				   igraph_real_t miny, igraph_real_t maxy, long int stepsy);
+void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid);
+
+int igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t *grid,
+				       igraph_real_t x, igraph_real_t y, igraph_real_t r,
+				       long int id);
+
+long int igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid,
+				       igraph_real_t x, igraph_real_t y);
+
+long int igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *g,
+					      igraph_real_t x, igraph_real_t y, igraph_real_t r);
+
+/* string -> string hash table */
+
+typedef struct igraph_hashtable_t {
+  igraph_trie_t keys;
+  igraph_strvector_t elements;
+  igraph_strvector_t defaults;
+} igraph_hashtable_t;
+
+int igraph_hashtable_init(igraph_hashtable_t *ht);
+void igraph_hashtable_destroy(igraph_hashtable_t *ht);
+int igraph_hashtable_addset(igraph_hashtable_t *ht,
+			    const char *key, const char *def, 
+			    const char *elem);
+int igraph_hashtable_addset2(igraph_hashtable_t *ht,
+			     const char *key, const char *def,
+			     const char *elem, int elemlen);
+int igraph_hashtable_get(igraph_hashtable_t *ht,
+			 const char *key, char **elem);
+int igraph_hashtable_getkeys(igraph_hashtable_t *ht, 
+			     const igraph_strvector_t **sv);
+int igraph_hashtable_reset(igraph_hashtable_t *ht);
+
+/* Buckets, needed for the maximum flow algorithm */
+
+typedef struct igraph_buckets_t {
+  igraph_vector_long_t bptr;
+  igraph_vector_long_t buckets;
+  igraph_integer_t max, no;
+} igraph_buckets_t;
+
+int igraph_buckets_init(igraph_buckets_t *b, long int bsize, long int size);
+void igraph_buckets_destroy(igraph_buckets_t *b);
+void igraph_buckets_clear(igraph_buckets_t *b);
+long int igraph_buckets_popmax(igraph_buckets_t *b);
+long int igraph_buckets_pop(igraph_buckets_t *b, long int bucket);
+igraph_bool_t igraph_buckets_empty(const igraph_buckets_t *b);
+igraph_bool_t igraph_buckets_empty_bucket(const igraph_buckets_t *b, 
+					  long int bucket);
+void igraph_buckets_add(igraph_buckets_t *b, long int bucket,
+			long int elem);
+
+typedef struct igraph_dbuckets_t {
+  igraph_vector_long_t bptr;
+  igraph_vector_long_t next, prev;
+  igraph_integer_t max, no;
+} igraph_dbuckets_t;
+
+int igraph_dbuckets_init(igraph_dbuckets_t *b, long int bsize, long int size);
+void igraph_dbuckets_destroy(igraph_dbuckets_t *b);
+void igraph_dbuckets_clear(igraph_dbuckets_t *b);
+long int igraph_dbuckets_popmax(igraph_dbuckets_t *b);
+long int igraph_dbuckets_pop(igraph_dbuckets_t *b, long int bucket);
+igraph_bool_t igraph_dbuckets_empty(const igraph_dbuckets_t *b);
+igraph_bool_t igraph_dbuckets_empty_bucket(const igraph_dbuckets_t *b, 
+					   long int bucket);
+void igraph_dbuckets_add(igraph_dbuckets_t *b, long int bucket,
+			 long int elem);
+void igraph_dbuckets_delete(igraph_dbuckets_t *b, long int bucket,
+			    long int elem);
+
+/* Special maximum heap, needed for the minimum cut algorithm */
+
+typedef struct igraph_i_cutheap_t {
+  igraph_vector_t heap;
+  igraph_vector_t index;
+  igraph_vector_t hptr;
+  long int dnodes;
+} igraph_i_cutheap_t;
+
+int igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_integer_t nodes);
+void igraph_i_cutheap_destroy(igraph_i_cutheap_t *ch);
+igraph_bool_t igraph_i_cutheap_empty(igraph_i_cutheap_t *ch);
+igraph_integer_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch);
+igraph_integer_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch);
+igraph_real_t igraph_i_cutheap_maxvalue(igraph_i_cutheap_t *ch);
+igraph_integer_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch);
+int igraph_i_cutheap_update(igraph_i_cutheap_t *ch, igraph_integer_t index,
+			    igraph_real_t add);
+int igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, long int vertex);
+
+/* -------------------------------------------------- */
+/* Flexible set                                       */
+/* -------------------------------------------------- */
+
+/** 
+ * Set containing integer numbers regardless of the order
+ * \ingroup types
+ */
+
+typedef struct s_set {
+  igraph_integer_t* stor_begin;
+  igraph_integer_t* stor_end;
+  igraph_integer_t* end;
+} igraph_set_t;
+
+#define IGRAPH_SET_NULL { 0,0,0 }
+#define IGRAPH_SET_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_set_init(v, size)); \
+  IGRAPH_FINALLY(igraph_set_destroy, v); } while (0)
+
+int igraph_set_init      (igraph_set_t* set, long int size);
+void igraph_set_destroy   (igraph_set_t* set);
+igraph_bool_t igraph_set_inited   (igraph_set_t* set);
+int igraph_set_reserve   (igraph_set_t* set, long int size);
+igraph_bool_t igraph_set_empty     (const igraph_set_t* set);
+void igraph_set_clear      (igraph_set_t* set);
+long int igraph_set_size      (const igraph_set_t* set);
+int igraph_set_add (igraph_set_t* v, igraph_integer_t e);
+igraph_bool_t igraph_set_contains (igraph_set_t* set, igraph_integer_t e);
+igraph_bool_t igraph_set_iterate (igraph_set_t* set, long int* state,
+				  igraph_integer_t* element);
+
+/* -------------------------------------------------- */
+/* Vectorlist, fixed length                           */
+/* -------------------------------------------------- */
+
+typedef struct igraph_fixed_vectorlist_t {
+  igraph_vector_t *vecs;
+  igraph_vector_ptr_t v;
+  long int length;
+} igraph_fixed_vectorlist_t;
+
+void igraph_fixed_vectorlist_destroy(igraph_fixed_vectorlist_t *l);
+int igraph_fixed_vectorlist_convert(igraph_fixed_vectorlist_t *l,
+				    const igraph_vector_t *from,
+				    long int size);
+
+__END_DECLS
+
+#endif
diff --git a/src/infomap.cc b/src/infomap.cc
new file mode 100644
index 0000000..ec7ee30
--- /dev/null
+++ b/src/infomap.cc
@@ -0,0 +1,317 @@
+/* -*- 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
+
+   ----
+   The original version of this file was written by Martin Rosvall
+   email: martin.rosvall at physics.umu.se
+   homePage: http://www.tp.umu.se/~rosvall/
+
+   It was integrated in igraph by Emmanuel Navarro
+   email: navarro at irit.fr
+   homePage: http://www.irit.fr/~Emmanuel.Navarro/
+*/
+
+#include <cmath>
+#include "igraph_interface.h"
+#include "igraph_community.h"
+#include "igraph_interrupt_internal.h"
+
+
+#include "infomap_Node.h"
+#include "infomap_Greedy.h"
+
+/****************************************************************************/
+int infomap_partition(FlowGraph * fgraph, bool rcall) {
+  Greedy * greedy;
+
+  // save the original graph
+  FlowGraph * cpy_fgraph = new FlowGraph(fgraph);
+  IGRAPH_FINALLY(delete_FlowGraph, cpy_fgraph);
+  
+  int Nnode = cpy_fgraph->Nnode; 
+  // "real" number of vertex, ie. number of vertex of the graph	
+
+  int iteration = 0;
+  double outer_oldCodeLength, newCodeLength;
+  
+  int *initial_move = NULL;
+  bool initial_move_done = true;
+  
+  do { // Main loop
+    outer_oldCodeLength = fgraph->codeLength;
+    
+    if (iteration > 0) {
+      /**********************************************************************/
+      //  FIRST PART: re-split the network (if need)
+      // ===========================================
+      
+      // intial_move indicate current clustering
+      initial_move = new int[Nnode];    
+      // new_cluster_id --> old_cluster_id (save curent clustering state)
+      
+      IGRAPH_FINALLY(operator delete [], initial_move);
+      initial_move_done = false;
+      
+      int *subMoveTo = NULL; // enventual new partitionment of original graph
+			
+      if ((iteration % 2 == 0) && (fgraph->Nnode > 1)) { 
+	// 0/ Submodule movements : partition each module of the 
+	// current partition (rec. call)
+	
+	subMoveTo = new int[Nnode];       
+	// vid_cpy_fgraph  --> new_cluster_id (new partition)
+
+	IGRAPH_FINALLY(operator delete [], subMoveTo);
+				
+	int subModIndex = 0;
+
+	for (int i=0 ; i < fgraph->Nnode ; i++) {
+	  // partition each non trivial module
+	  int sub_Nnode = fgraph->node[i]->members.size();
+	  if (sub_Nnode > 1) { // If the module is not trivial
+	    int *sub_members  = new int[sub_Nnode];      // id_sub --> id
+	    IGRAPH_FINALLY(operator delete [], sub_members); 
+	    
+	    for (int j=0 ; j < sub_Nnode ; j++)
+	      sub_members[j] = fgraph->node[i]->members[j];
+	    
+	    // extraction of the subgraph
+	    FlowGraph *sub_fgraph = new FlowGraph(cpy_fgraph, sub_Nnode, 
+						  sub_members);
+	    IGRAPH_FINALLY(delete_FlowGraph, sub_fgraph);
+	    sub_fgraph->initiate();
+	    
+	    // recursif call of partitionment on the subgraph
+	    infomap_partition(sub_fgraph, true);
+	    
+	    // Record membership changes
+	    for (int j=0; j < sub_fgraph->Nnode; j++) {
+	      int Nmembers = sub_fgraph->node[j]->members.size();
+	      for (int k=0; k<Nmembers; k++) {
+		subMoveTo[sub_members[sub_fgraph->node[j]->members[k]]] = 
+		  subModIndex;
+	      }
+	      initial_move[subModIndex] = i;
+	      subModIndex++;
+	    }
+	    
+	    delete sub_fgraph;
+	    IGRAPH_FINALLY_CLEAN(1);
+	    delete [] sub_members;
+	    IGRAPH_FINALLY_CLEAN(1);
+	  } else{
+	    subMoveTo[fgraph->node[i]->members[0]] = subModIndex;
+	    initial_move[subModIndex] = i;
+	    subModIndex++;
+	  }
+	}
+      } else {
+	// 1/ Single-node movements : allows each node to move (again)
+	// save current modules
+	for (int i=0; i < fgraph->Nnode; i++) { // for each module
+	  int Nmembers = fgraph->node[i]->members.size(); // Module size
+	  for (int j=0;j<Nmembers;j++) { // for each vertex (of the module)
+	    initial_move[fgraph->node[i]->members[j]] = i;
+	  }
+	}
+      }
+      
+      fgraph->back_to(cpy_fgraph);
+      if (subMoveTo) {
+	Greedy *cpy_greedy = new Greedy(fgraph);
+	IGRAPH_FINALLY(delete_Greedy, cpy_greedy);
+	
+	cpy_greedy->setMove(subMoveTo);
+	cpy_greedy->apply(false);
+	
+	delete_Greedy(cpy_greedy);
+	IGRAPH_FINALLY_CLEAN(1);
+	delete [] subMoveTo;
+	IGRAPH_FINALLY_CLEAN(1);
+      }
+    }
+    /**********************************************************************/
+    //  SECOND PART: greedy optimizing it self
+    // ===========================================
+    double oldCodeLength;
+    
+    do {
+      // greedy optimizing object creation
+      greedy = new Greedy(fgraph);
+      IGRAPH_FINALLY(delete_Greedy, greedy);
+      
+      // Initial move to apply ?
+      if (!initial_move_done && initial_move) {
+	initial_move_done = true;
+	greedy->setMove(initial_move);
+      }
+      
+      oldCodeLength = greedy->codeLength;
+      bool moved = true;
+      int Nloops = 0;
+      //int count = 0;
+      double inner_oldCodeLength = 1000;
+      
+      while (moved) { // main greedy optimizing loop
+	inner_oldCodeLength = greedy->codeLength;
+	moved = greedy->optimize();
+
+	Nloops++;
+	//count++;
+	
+	if (fabs(greedy->codeLength - inner_oldCodeLength) < 1.0e-10) 
+	  // if the move does'n reduce the codelenght -> exit !
+	  moved = false;
+	
+	//if (count == 10) {
+	//	greedy->tune();
+	//	count = 0;
+	//}
+      }
+      
+      // transform the network to network of modules:
+      greedy->apply(true);
+      newCodeLength = greedy->codeLength;
+      
+      // destroy greedy object
+      delete greedy;
+      IGRAPH_FINALLY_CLEAN(1);
+      
+    } while (oldCodeLength - newCodeLength >  1.0e-10); 
+    // while there is some improvement
+		
+    if (iteration > 0) {
+      delete [] initial_move;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    
+    iteration++;
+    if (!rcall) IGRAPH_ALLOW_INTERRUPTION();
+  } while (outer_oldCodeLength - newCodeLength > 1.0e-10);
+  
+  delete cpy_fgraph;
+  IGRAPH_FINALLY_CLEAN(1);
+  return IGRAPH_SUCCESS;
+}
+
+
+/** 
+ * \function igraph_community_infomap
+ * \brief Find community structure that minimizes the expected
+ * description length of a random walker trajectory.
+ * 
+ * Implementation of the InfoMap community detection algorithm.of
+ * Martin Rosvall and Carl T. Bergstrom.
+ * 
+ * See :
+ * Visualization of the math and the map generator: www.mapequation.org
+ * [2] The original paper: M. Rosvall and C. T. Bergstrom, Maps of
+ * information flow reveal community structure in complex networks, PNAS
+ * 105, 1118 (2008) [http://dx.doi.org/10.1073/pnas.0706851105 ,
+ * http://arxiv.org/abs/0707.0609 ]
+ * [3] A more detailed paper: M. Rosvall, D. Axelsson, and C. T. Bergstrom,
+ * The map equation, Eur. Phys. J. Special Topics 178, 13 (2009).
+ * [http://dx.doi.org/10.1140/epjst/e2010-01179-1 ,
+ * http://arxiv.org/abs/0906.1405 ]
+
+ * </para><para>
+ * The original C++ implementation of Martin Rosvall is used, 
+ * see http://www.tp.umu.se/~rosvall/downloads/infomap_undir.tgz .
+ * Intergation in igraph has be done by Emmanuel Navarro (who is grateful to 
+  * Martin Rosvall and Carl T. Bergstrom for providing this source code.)
+ *
+ * </para><para>
+ * Note that the graph must not contain isolated vertices.
+ * 
+ * </para><para>
+ * If you want to specify a random seed (as in original
+ * implementation) you can use \ref igraph_rng_seed().
+ * 
+ * \param graph The input graph.
+ * \param e_weights Numeric vector giving the weights of the edges. 
+ *     If it is a NULL pointer then all edges will have equal
+ *     weights. The weights are expected to be positive.
+ * \param v_weights Numeric vector giving the weights of the vertices. 
+ *     If it is a NULL pointer then all vertices will have equal
+ *     weights. The weights are expected to be positive.
+ * \param nb_trials The number of attempts to partition the network
+ *     (can be any integer value equal or larger than 1).
+ * \param membership Pointer to a vector. The membership vector is
+ *    stored here. 
+ * \param codelength Pointer to a real. If not NULL the code length of the
+ *     partition is stored here.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_community_spinglass(), \ref
+ * igraph_community_edge_betweenness(), \ref igraph_community_walktrap(). 
+ * 
+ * Time complexity: TODO.
+ */
+int igraph_community_infomap(const igraph_t * graph,
+                             const igraph_vector_t *e_weights,
+                             const igraph_vector_t *v_weights,
+                             int nb_trials,
+                             igraph_vector_t *membership,
+                             igraph_real_t *codelength) {
+
+  FlowGraph * fgraph = new FlowGraph(graph, e_weights, v_weights);
+  IGRAPH_FINALLY(delete_FlowGraph, fgraph);
+	
+  // compute stationary distribution
+  fgraph->initiate();
+	
+  FlowGraph * cpy_fgraph ;
+  double shortestCodeLength = 1000.0;
+  
+  // create membership vector
+  int Nnode = fgraph->Nnode;
+  IGRAPH_CHECK(igraph_vector_resize(membership, Nnode));
+  
+  for (int trial = 0; trial < nb_trials; trial++) {
+    cpy_fgraph = new FlowGraph(fgraph);
+    IGRAPH_FINALLY(delete_FlowGraph, cpy_fgraph);
+    
+    //partition the network
+    IGRAPH_CHECK(infomap_partition(cpy_fgraph, false));
+    
+    // if better than the better...
+    if (cpy_fgraph->codeLength < shortestCodeLength) {
+      shortestCodeLength = cpy_fgraph->codeLength;
+      // ... store the partition
+      for (int i=0 ; i < cpy_fgraph->Nnode ; i++) {
+	int Nmembers = cpy_fgraph->node[i]->members.size();
+	for (int k=0; k < Nmembers; k++) {
+	  //cluster[ cpy_fgraph->node[i]->members[k] ] = i;
+	  VECTOR(*membership)[cpy_fgraph->node[i]->members[k]] = i;
+	}
+      }
+    }
+    
+    delete_FlowGraph(cpy_fgraph);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  *codelength = (igraph_real_t) shortestCodeLength/log(2.0);
+  
+  delete fgraph;
+  IGRAPH_FINALLY_CLEAN(1);
+  return IGRAPH_SUCCESS;
+}
diff --git a/src/infomap_FlowGraph.cc b/src/infomap_FlowGraph.cc
new file mode 100644
index 0000000..af59f07
--- /dev/null
+++ b/src/infomap_FlowGraph.cc
@@ -0,0 +1,403 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include "infomap_FlowGraph.h"
+
+#define plogp( x ) ( (x) > 0.0 ? (x)*log(x) : 0.0 )
+
+void FlowGraph::init(int n, const igraph_vector_t *v_weights) {
+  alpha = 0.15;
+  beta  = 1.0 - alpha;
+  Nnode = n;
+  node = new Node*[Nnode];
+  if (v_weights) {
+    for (int i=0;i<Nnode;i++) {
+      node[i] = new Node(i, (double)VECTOR(*v_weights)[i]);
+    }
+  } else {
+    for (int i=0;i<Nnode;i++) { node[i] = new Node(i, 1.0); }
+  }
+}
+
+FlowGraph::FlowGraph(int n) {
+  init(n, NULL);
+}
+
+FlowGraph::FlowGraph(int n, const igraph_vector_t *v_weights) {
+  init(n, v_weights);
+}
+
+/* Build the graph from igraph_t object
+ */
+FlowGraph::FlowGraph(const igraph_t * graph, 
+		     const igraph_vector_t *e_weights, 
+		     const igraph_vector_t *v_weights) {
+
+  int n = (int)igraph_vcount(graph);
+  init(n, v_weights);
+	
+  int directed = (int) igraph_is_directed(graph);
+  
+  double linkWeight = 1.0;
+  igraph_integer_t from, to;
+  
+  long int Nlinks = (long int) igraph_ecount(graph); 
+  if (!directed) Nlinks = Nlinks * 2 ;
+  for (int i=0; i<Nlinks; i++) {
+    if (!directed) { // not directed
+      if (i%2==0) {
+	linkWeight = e_weights ? (double)VECTOR(*e_weights)[i/2] : 1.0;
+	igraph_edge(graph, i/2    , &from, &to);
+      } else { 
+	igraph_edge(graph, (i-1)/2, &to,   &from); 
+      }
+    } else {         // directed
+      linkWeight = e_weights ? (double)VECTOR(*e_weights)[i] : 1.0;
+      igraph_edge(graph, i, &from, &to);
+    }
+    
+    // Populate node from igraph_graph
+    if (linkWeight > 0.0) {
+      if (from != to) {
+	node[(int) from]->outLinks.push_back(make_pair((int)to, linkWeight));
+	node[(int) to]->inLinks.push_back(make_pair((int) from, linkWeight));
+      }
+    }
+  }
+}
+
+FlowGraph::FlowGraph(FlowGraph * fgraph) {
+  int n = fgraph->Nnode;
+  init(n, NULL);
+  for (int i=0; i<n; i++) {
+    cpyNode(node[i], fgraph->node[i]);
+  }
+  
+  //XXX: quid de danglings et Ndanglings?
+  
+  alpha = fgraph->alpha ;
+  beta  = fgraph->beta ;
+  
+  exit = fgraph->exit;
+  exitFlow = fgraph->exitFlow;
+  exit_log_exit = fgraph->exit_log_exit;
+  size_log_size = fgraph->size_log_size ;
+  nodeSize_log_nodeSize = fgraph->nodeSize_log_nodeSize;
+  
+  codeLength = fgraph->codeLength;
+}
+
+/** construct a graph by extracting a subgraph from the given graph
+ */
+FlowGraph::FlowGraph(FlowGraph * fgraph, int sub_Nnode, int * sub_members) {
+  init(sub_Nnode, NULL);
+    
+  //XXX: use set of integer to ensure that elements are sorted
+  set<int> sub_mem;
+  for (int j=0 ; j<sub_Nnode ; j++) { sub_mem.insert(sub_members[j]); }
+  set<int>::iterator it_mem = sub_mem.begin();
+	
+  vector<int> sub_renumber = vector<int>(fgraph->Nnode);         
+  // id --> sub_id
+
+  for (int j=0; j<fgraph->Nnode; j++) { sub_renumber[j] = -1; }
+
+
+  for (int j=0; j<sub_Nnode; j++) {
+    //int orig_nr = sub_members[j];
+    int orig_nr = (*it_mem);
+
+    node[j]->teleportWeight = fgraph->node[orig_nr]->teleportWeight;
+    node[j]->selfLink       = fgraph->node[orig_nr]->selfLink; 
+    // Take care of self-link
+
+    int orig_NoutLinks = fgraph->node[orig_nr]->outLinks.size();
+    int orig_NinLinks  = fgraph->node[orig_nr]->inLinks.size();
+    
+    sub_renumber[orig_nr] = j;
+    
+    for (int k=0; k<orig_NoutLinks; k++) {
+      int to = fgraph->node[orig_nr]->outLinks[k].first;
+      int to_newnr = sub_renumber[to];
+      double link_weight = fgraph->node[orig_nr]->outLinks[k].second;
+      
+      if (to < orig_nr) { 
+	// we add links if the destination (to) has already be seen 
+	// (ie. smaller than current id) => orig
+
+	if (sub_mem.find(to) != sub_mem.end()) {
+	  // printf("%2d | %4d to %4d\n", j, orig_nr, to);
+	  // printf("from %4d (%4d:%1.5f) to %4d (%4d)\n", j, orig_nr, 
+	  //        node[j]->selfLink, to_newnr, to);
+	  node[j]->outLinks.push_back(make_pair(to_newnr, link_weight));
+	  node[to_newnr]->inLinks.push_back(make_pair(j, link_weight));
+	}
+      }
+    }
+		
+    for (int k=0; k<orig_NinLinks; k++) {
+      int to = fgraph->node[orig_nr]->inLinks[k].first;
+      int to_newnr = sub_renumber[to];
+      double link_weight = fgraph->node[orig_nr]->inLinks[k].second;
+      if (to < orig_nr) {
+	if (sub_mem.find(to) != sub_mem.end()) {
+	  node[j]->inLinks.push_back(make_pair(to_newnr,link_weight));
+	  node[to_newnr]->outLinks.push_back(make_pair(j,link_weight));
+	}
+      }
+    }
+    it_mem++;
+  }
+}
+
+
+FlowGraph::~FlowGraph() {
+  //printf("delete FlowGraph !\n");
+  for (int i=0;i<Nnode;i++) {
+    delete node[i];
+  }
+  delete [] node;
+}
+
+void delete_FlowGraph(FlowGraph *fgraph) {
+  delete fgraph;
+}
+
+
+/** Swap the graph with the one given
+    the graph is "re" calibrate
+    but NOT the given one.
+ */
+void FlowGraph::swap(FlowGraph * fgraph) {
+  Node ** node_tmp = fgraph->node;
+  int Nnode_tmp    = fgraph->Nnode;
+  
+  fgraph->node = node;
+  fgraph->Nnode = Nnode;
+  
+  node = node_tmp;
+  Nnode = Nnode_tmp;
+  
+  calibrate();
+}
+
+/** Initialisation of the graph, compute the flow inside the graph
+ *   - count danglings nodes
+ *   - normalized edge weights
+ *   - Call eigenvector() to compute steady state distribution
+ *   - call calibrate to compute codelenght
+ */
+void FlowGraph::initiate() {
+  // Take care of dangling nodes, normalize outLinks, and calculate
+  // total teleport weight
+  Ndanglings = 0;
+  double totTeleportWeight = 0.0;
+  for (int i=0;i<Nnode;i++) totTeleportWeight += node[i]->teleportWeight;
+  
+  for (int i=0;i<Nnode;i++) {
+    node[i]->teleportWeight /= totTeleportWeight; 
+    // normalize teleportation weight
+
+    if (node[i]->outLinks.empty() && (node[i]->selfLink <= 0.0)) {
+      danglings.push_back(i);
+      Ndanglings++;
+    } else { // Normalize the weights
+      int NoutLinks = node[i]->outLinks.size();
+      double sum = node[i]->selfLink; // Take care of self-links
+      for (int j=0;j < NoutLinks; j++) sum += node[i]->outLinks[j].second;
+      node[i]->selfLink /= sum;
+      for (int j=0;j < NoutLinks; j++) node[i]->outLinks[j].second /= sum;
+    }
+  }
+  
+  // Calculate steady state matrix
+  eigenvector();
+  
+  // Update links to represent flow
+  for (int i=0; i<Nnode; i++) {
+    node[i]->selfLink = beta * node[i]->size * node[i]->selfLink;
+    //            (1 - \tau) *     \pi_i     *      P_{ii}
+    
+    if (!node[i]->outLinks.empty()) {
+      int NoutLinks = node[i]->outLinks.size();
+      for (int j=0;j < NoutLinks; j++) {
+	node[i]->outLinks[j].second = beta * node[i]->size *
+	  node[i]->outLinks[j].second;
+	//                      (1 - \tau) *     \pi_i     *          P_{ij}
+      }
+      
+      // Update values for corresponding inlink
+      for (int j=0; j < NoutLinks; j++) {
+	int NinLinks = node[node[i]->outLinks[j].first]->inLinks.size();
+	for (int k=0; k < NinLinks; k++) {
+	  if (node[node[i]->outLinks[j].first]->inLinks[k].first == i) {
+	    node[node[i]->outLinks[j].first]->inLinks[k].second = 
+	      node[i]->outLinks[j].second;
+	    k = NinLinks;
+	  }
+	}
+      }
+    }
+  }
+  
+  // To be able to handle dangling nodes efficiently
+  for (int i=0;i<Nnode;i++)
+    if (node[i]->outLinks.empty() && (node[i]->selfLink <= 0.0)) {
+      node[i]->danglingSize = node[i]->size;
+    } else {
+      node[i]->danglingSize = 0.0;
+    }
+
+  nodeSize_log_nodeSize = 0.0 ;
+  // The exit flow from each node at initiation
+  for (int i=0;i<Nnode;i++) {
+    node[i]->exit = node[i]->size // Proba to be on i
+      - (alpha * node[i]->size + beta * node[i]->danglingSize) * 
+      node[i]->teleportWeight // Proba teleport back to i
+      - node[i]->selfLink;  // Proba stay on i
+
+    // node[i]->exit == q_{i\exit}
+    nodeSize_log_nodeSize += plogp(node[i]->size);
+  }
+
+  calibrate();
+}
+
+
+/* Compute steady state distribution (ie. PageRank) over the network
+ * (for all i update node[i]->size)
+ */
+void FlowGraph::eigenvector() {
+  vector<double> size_tmp = vector<double>(Nnode,1.0/Nnode);
+
+  int Niterations = 0;
+  double danglingSize;
+  
+  double sqdiff = 1.0;
+  double sqdiff_old;
+  double sum;
+  do {
+    // Calculate dangling size
+    danglingSize = 0.0;
+    for (int i=0;i<Ndanglings;i++) {
+      danglingSize += size_tmp[danglings[i]];
+    }
+    
+    // Flow from teleportation
+    for (int i=0;i<Nnode;i++)
+      node[i]->size = (alpha + beta*danglingSize) * node[i]->teleportWeight;
+    
+    // Flow from network steps
+    for (int i=0;i<Nnode;i++) {
+      node[i]->size += beta * node[i]->selfLink * size_tmp[i];
+      int Nlinks = node[i]->outLinks.size();
+      for (int j=0; j < Nlinks; j++)
+	node[node[i]->outLinks[j].first]->size += beta * 
+	  node[i]->outLinks[j].second * size_tmp[i];
+    }
+    
+    // Normalize
+    sum = 0.0;
+    for (int i=0;i<Nnode;i++) {
+      sum += node[i]->size;
+    }
+    sqdiff_old = sqdiff;
+    sqdiff = 0.0;
+    for (int i=0;i<Nnode;i++) {
+      node[i]->size /= sum;
+      sqdiff += fabs(node[i]->size - size_tmp[i]);
+      size_tmp[i] = node[i]->size;
+    }
+    Niterations++;
+    
+    if (sqdiff == sqdiff_old) {
+      alpha += 1.0e-10;
+      beta = 1.0-alpha;
+    }
+    
+  } while ((Niterations < 200) && (sqdiff > 1.0e-15 || Niterations < 50));
+  
+  danglingSize = 0.0;
+  for (int i=0;i<Ndanglings;i++) {
+    danglingSize += size_tmp[danglings[i]];
+  }
+  // cout << "done! (the error is " << sqdiff << " after " << Niterations
+  //      << " iterations)" << endl;
+}
+
+
+/* Compute the codeLength of the given network 
+ * note: (in **node, one node == one module)
+ */
+void FlowGraph::calibrate() {
+  exit_log_exit = 0.0;
+  exitFlow = 0.0;
+  size_log_size = 0.0;
+  
+  for (int i=0; i<Nnode; i++) { // For each module
+    // own node/module codebook
+    size_log_size         += plogp(node[i]->exit + node[i]->size);
+    
+    // use of index codebook
+    exitFlow      += node[i]->exit; 
+    exit_log_exit += plogp(node[i]->exit);
+  }
+
+  exit = plogp(exitFlow);
+  
+  codeLength = exit - 2.0*exit_log_exit + size_log_size -
+    nodeSize_log_nodeSize;
+}
+
+
+/* Restore the data from the given FlowGraph object
+ */
+void FlowGraph::back_to(FlowGraph * fgraph) {
+  // delete current nodes
+  for (int i=0 ; i<Nnode ; i++) { delete node[i]; }
+  delete [] node;
+  
+  Nnode = fgraph->Nnode;
+
+  // copy original ones
+  node = new Node*[Nnode];
+  for (int i=0;i<Nnode;i++) {
+    node[i] = new Node();
+    cpyNode(node[i], fgraph->node[i]);
+  }
+  
+  // restore atributs
+  alpha = fgraph->alpha ;
+  beta  = fgraph->beta ;
+  
+  exit = fgraph->exit;
+  exitFlow = fgraph->exitFlow;
+  exit_log_exit = fgraph->exit_log_exit;
+  size_log_size = fgraph->size_log_size ;
+  nodeSize_log_nodeSize = fgraph->nodeSize_log_nodeSize;
+  
+  codeLength = fgraph->codeLength;
+}
+
+
diff --git a/src/infomap_FlowGraph.h b/src/infomap_FlowGraph.h
new file mode 100644
index 0000000..c7fb046
--- /dev/null
+++ b/src/infomap_FlowGraph.h
@@ -0,0 +1,78 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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 FLOWGRAPH_H
+#define FLOWGRAPH_H
+
+#include <vector>
+#include <set>
+
+#include "igraph_interface.h"
+
+#include "infomap_Node.h"
+
+class FlowGraph{ 
+ private:
+  void init(int n, const igraph_vector_t *nodeWeights);
+
+ public:
+  FlowGraph(int n);
+  FlowGraph(int n, const igraph_vector_t *nodeWeights);
+  FlowGraph(FlowGraph * fgraph);
+  FlowGraph(FlowGraph * fgraph, int sub_Nnode, int * sub_members);
+
+  FlowGraph(const igraph_t * graph, const igraph_vector_t *e_weights,
+	    const igraph_vector_t *v_weights);
+
+  ~FlowGraph();
+
+  void swap(FlowGraph * fgraph);
+
+  void initiate();
+  void eigenvector();
+  void calibrate();
+
+  void back_to(FlowGraph * fgraph);
+
+  /*************************************************************************/
+  Node **node;
+  int  Nnode;
+
+  double alpha,beta;
+
+  int Ndanglings;
+  vector<int> danglings; // id of dangling nodes
+
+  double exit;                  // 
+  double exitFlow;              // 
+  double exit_log_exit;         // 
+  double size_log_size;         // 
+  double nodeSize_log_nodeSize; // \sum_{v in V} p log(p)
+
+  double codeLength;
+};
+
+void delete_FlowGraph(FlowGraph *fgraph);
+
+#endif
diff --git a/src/infomap_Greedy.cc b/src/infomap_Greedy.cc
new file mode 100644
index 0000000..5e9f59d
--- /dev/null
+++ b/src/infomap_Greedy.cc
@@ -0,0 +1,609 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include "infomap_Greedy.h"
+#include <iterator>
+#define plogp( x ) ( (x) > 0.0 ? (x)*log(x) : 0.0 )
+
+Greedy::Greedy(FlowGraph * fgraph){
+  graph = fgraph;
+  Nnode = graph->Nnode;
+	
+  alpha = graph->alpha;// teleportation probability
+  beta = 1.0 - alpha;  // probability to take normal step
+
+  Nempty = 0;
+  vector<int>(Nnode).swap(mod_empty);
+  
+  vector<int>(Nnode).swap(node_index);
+  vector<double>(Nnode).swap(mod_exit);
+  vector<double>(Nnode).swap(mod_size);
+  vector<double>(Nnode).swap(mod_danglingSize);
+  vector<double>(Nnode).swap(mod_teleportWeight);
+  vector<int>(Nnode).swap(mod_members);
+  
+  nodeSize_log_nodeSize = graph->nodeSize_log_nodeSize;
+  exit_log_exit         = graph->exit_log_exit;
+  size_log_size         = graph->size_log_size;
+  exitFlow              = graph->exitFlow;
+  
+  Node ** node = graph->node;
+  for (int i=0; i<Nnode; i++) { // For each module
+    node_index[i]         = i;
+    mod_exit[i]           = node[i]->exit;
+    mod_size[i]           = node[i]->size;
+
+    mod_danglingSize[i]   = node[i]->danglingSize;
+    mod_teleportWeight[i] = node[i]->teleportWeight;
+    mod_members[i]        = node[i]->members.size();
+  }
+  
+  exit = plogp(exitFlow);
+  
+  codeLength = exit - 2.0*exit_log_exit + size_log_size - 
+    nodeSize_log_nodeSize;
+}
+
+Greedy::~Greedy() {
+}
+
+void delete_Greedy(Greedy *greedy) {
+  delete greedy;
+}
+
+
+/** Greedy optimizing (as in Blodel and Al.) :
+ * for each vertex (selected in a random order) compute the best possible move within neighborhood
+ */
+bool Greedy::optimize() {
+  bool moved = false;
+  Node ** node = graph->node;
+	
+  RNG_BEGIN();
+	
+  // Generate random enumeration of nodes
+  vector<int> randomOrder(Nnode);
+  for (int i=0; i<Nnode; i++) { randomOrder[i] = i; }
+  
+  for (int i=0; i<Nnode-1; i++) {
+    //int randPos = i ; //XXX
+    int randPos = RNG_INTEGER(i, Nnode-1);
+    // swap i & randPos
+    int tmp              = randomOrder[i];
+    randomOrder[i]       = randomOrder[randPos];
+    randomOrder[randPos] = tmp;
+  }
+  
+  unsigned int offset = 1;
+  vector<unsigned int> redirect(Nnode,0);
+  vector<pair<int,pair<double,double> > > flowNtoM(Nnode);
+  
+  for (int k=0; k<Nnode; k++) {
+    
+    // Pick nodes in random order
+    int flip = randomOrder[k];
+    int oldM = node_index[flip];
+    
+    // Reset offset when int overflows
+    if (offset > INT_MAX) {
+      for (int j=0;j<Nnode;j++)
+	redirect[j] = 0;
+      offset = 1;
+    }
+    // Size of vector with module links
+    int NmodLinks = 0;
+    // For all outLinks
+    int NoutLinks = node[flip]->outLinks.size();
+    if (NoutLinks == 0) { //dangling node, add node to calculate flow below
+      redirect[oldM] = offset + NmodLinks;
+      flowNtoM[NmodLinks].first = oldM;
+      flowNtoM[NmodLinks].second.first = 0.0;
+      flowNtoM[NmodLinks].second.second = 0.0;
+      NmodLinks++;
+    } else {
+      for (int j=0; j<NoutLinks; j++) {
+	int nb_M       = node_index[node[flip]->outLinks[j].first]; 
+	// index destination du lien
+	double nb_flow = node[flip]->outLinks[j].second;           
+	// wgt du lien
+	if (redirect[nb_M] >= offset) {
+	  flowNtoM[redirect[nb_M] - offset].second.first += nb_flow;
+	} else {
+	  redirect[nb_M] = offset + NmodLinks;
+	  flowNtoM[NmodLinks].first = nb_M;
+	  flowNtoM[NmodLinks].second.first = nb_flow;
+	  flowNtoM[NmodLinks].second.second = 0.0;
+	  NmodLinks++;
+	}
+      }
+    }
+    // For all inLinks
+    int NinLinks = node[flip]->inLinks.size();
+    for (int j=0; j<NinLinks; j++) {
+      int nb_M = node_index[node[flip]->inLinks[j].first];
+      double nb_flow = node[flip]->inLinks[j].second;
+      
+      if (redirect[nb_M] >= offset) {
+	flowNtoM[redirect[nb_M] - offset].second.second += nb_flow;
+      } else{
+	redirect[nb_M] = offset + NmodLinks;
+	flowNtoM[NmodLinks].first = nb_M;
+	flowNtoM[NmodLinks].second.first = 0.0;
+	flowNtoM[NmodLinks].second.second = nb_flow;
+	NmodLinks++;
+      }
+    }
+    
+    // For teleportation and dangling nodes
+    for (int j=0;j<NmodLinks;j++) {
+      int newM = flowNtoM[j].first;
+      if (newM == oldM) {
+	flowNtoM[j].second.first  += 
+	  (alpha*node[flip]->size + beta*node[flip]->danglingSize)*
+	  (mod_teleportWeight[oldM]-node[flip]->teleportWeight);
+	flowNtoM[j].second.second += 
+	  (alpha*(mod_size[oldM] - node[flip]->size) + 
+	   beta*(mod_danglingSize[oldM] - node[flip]->danglingSize)) * 
+	  node[flip]->teleportWeight;
+      } else {
+	flowNtoM[j].second.first  += 
+	  (alpha*node[flip]->size + beta*node[flip]->danglingSize) * 
+	  mod_teleportWeight[newM];
+	flowNtoM[j].second.second += 
+	  (alpha*mod_size[newM]   + beta*mod_danglingSize[newM]  ) * 
+	  node[flip]->teleportWeight;
+      }
+    }
+
+    // Calculate flow to/from own module (default value if no link to 
+    // own module)
+    double outFlowOldM = 
+      (alpha*node[flip]->size + beta*node[flip]->danglingSize) * 
+      (mod_teleportWeight[oldM] - node[flip]->teleportWeight) ;
+    double inFlowOldM  = 
+      (alpha*(mod_size[oldM] - node[flip]->size) + 
+       beta*(mod_danglingSize[oldM] - node[flip]->danglingSize)) * 
+      node[flip]->teleportWeight;
+    if (redirect[oldM] >= offset) {
+      outFlowOldM = flowNtoM[redirect[oldM] - offset].second.first;
+      inFlowOldM  = flowNtoM[redirect[oldM] - offset].second.second;
+    }
+
+    // Option to move to empty module (if node not already alone)
+    if (mod_members[oldM] > static_cast<int>(node[flip]->members.size())) {
+      if (Nempty > 0) {
+	flowNtoM[NmodLinks].first = mod_empty[Nempty-1];
+	flowNtoM[NmodLinks].second.first = 0.0;
+	flowNtoM[NmodLinks].second.second = 0.0;
+	NmodLinks++;
+      }
+    }
+    
+    // Randomize link order for optimized search
+    for (int j=0;j<NmodLinks-1;j++) {
+      //int randPos = j ; // XXX
+      int randPos = RNG_INTEGER(j, NmodLinks-1);
+      int tmp_M = flowNtoM[j].first;
+      double tmp_outFlow = flowNtoM[j].second.first;
+      double tmp_inFlow = flowNtoM[j].second.second;
+      flowNtoM[j].first = flowNtoM[randPos].first;
+      flowNtoM[j].second.first = flowNtoM[randPos].second.first;
+      flowNtoM[j].second.second = flowNtoM[randPos].second.second;
+      flowNtoM[randPos].first = tmp_M;
+      flowNtoM[randPos].second.first = tmp_outFlow;
+      flowNtoM[randPos].second.second = tmp_inFlow;
+    }
+    
+    int bestM = oldM;
+    double best_outFlow = 0.0;
+    double best_inFlow = 0.0;
+    double best_delta = 0.0;
+    
+    // Find the move that minimizes the description length
+    for (int j=0; j<NmodLinks; j++) {
+      
+      int newM = flowNtoM[j].first;
+      double outFlowNewM = flowNtoM[j].second.first;
+      double inFlowNewM  = flowNtoM[j].second.second;
+      
+      if (newM != oldM) {
+	
+	double delta_exit = plogp(exitFlow + outFlowOldM + inFlowOldM - 
+				  outFlowNewM - inFlowNewM) - exit;
+
+	double delta_exit_log_exit = - plogp(mod_exit[oldM]) - 
+	  plogp(mod_exit[newM])	+ 
+	  plogp(mod_exit[oldM] - node[flip]->exit + outFlowOldM + inFlowOldM)
+	  + plogp(mod_exit[newM] + node[flip]->exit - outFlowNewM - 
+		  inFlowNewM);
+
+	double delta_size_log_size = - plogp(mod_exit[oldM] + mod_size[oldM])
+	  - plogp(mod_exit[newM] + mod_size[newM])
+	  + plogp(mod_exit[oldM] + mod_size[oldM] - node[flip]->exit -
+		  node[flip]->size + outFlowOldM + inFlowOldM)
+	  + plogp(mod_exit[newM] + mod_size[newM] + node[flip]->exit + 
+		  node[flip]->size - outFlowNewM - inFlowNewM);
+
+	double deltaL = delta_exit - 2.0*delta_exit_log_exit +
+	  delta_size_log_size;
+                
+	if (deltaL - best_delta < -1e-10) {
+	  bestM = newM;
+	  best_outFlow = outFlowNewM;
+	  best_inFlow = inFlowNewM;
+	  best_delta = deltaL;
+	}
+      }
+    }
+    
+    // Make best possible move
+    if (bestM != oldM) {
+      //Update empty module vector
+      if (mod_members[bestM] == 0) {
+	Nempty--;
+      }
+      if (mod_members[oldM] == static_cast<int>(node[flip]->members.size())) {
+	mod_empty[Nempty] = oldM;
+	Nempty++;
+      }
+      
+      exitFlow -= mod_exit[oldM] + mod_exit[bestM];
+      
+      exit_log_exit -= plogp(mod_exit[oldM]) + plogp(mod_exit[bestM]);
+      size_log_size -= plogp(mod_exit[oldM] + mod_size[oldM]) +
+	plogp(mod_exit[bestM] + mod_size[bestM]);
+
+      mod_exit[oldM]            -= node[flip]->exit - outFlowOldM -
+	                           inFlowOldM;
+      mod_size[oldM]            -= node[flip]->size;
+      mod_danglingSize[oldM]    -= node[flip]->danglingSize;
+      mod_teleportWeight[oldM]  -= node[flip]->teleportWeight;
+      mod_members[oldM]         -= node[flip]->members.size();
+      
+      mod_exit[bestM]           += node[flip]->exit - best_outFlow -
+	                           best_inFlow;
+      mod_size[bestM]           += node[flip]->size;
+      mod_danglingSize[bestM]   += node[flip]->danglingSize;
+      mod_teleportWeight[bestM] += node[flip]->teleportWeight;
+      mod_members[bestM]        += node[flip]->members.size();
+      
+      exitFlow += mod_exit[oldM] + mod_exit[bestM];
+
+      // Update terms in map equation
+
+      exit_log_exit += plogp(mod_exit[oldM]) + plogp(mod_exit[bestM]);
+      size_log_size += plogp(mod_exit[oldM] + mod_size[oldM]) +
+	plogp(mod_exit[bestM] + mod_size[bestM]);
+      exit = plogp(exitFlow);
+
+      // Update code length
+
+      codeLength = exit - 2.0*exit_log_exit + size_log_size -
+	nodeSize_log_nodeSize;
+
+      node_index[flip] = bestM;
+      moved = true;
+    }
+    offset += Nnode;
+  }
+
+  RNG_END();
+
+  return moved;
+}
+
+/** Apply the move to the given network
+ */
+void Greedy::apply(bool sort) {
+//void Greedy::level(Node ***node_tmp, bool sort) {
+	
+  //old fct prepare(sort)
+  vector<int> modSnode;  // will give ids of no-empty modules (nodes)
+  int Nmod = 0;
+  if (sort) {
+    multimap<double,int> Msize;
+    for (int i=0; i<Nnode; i++) {
+      if (mod_members[i] > 0) {
+	Nmod++;
+	Msize.insert(pair<const double, int>(mod_size[i],i));
+      }
+    }
+    for (multimap<double,int>::reverse_iterator it = Msize.rbegin(); 
+	 it != Msize.rend(); it++) {
+      modSnode.push_back(it->second);
+    }
+  } else {
+    for (int i=0;i<Nnode;i++) {
+      if (mod_members[i] > 0) {
+	Nmod++;
+	modSnode.push_back(i);
+      }
+    }
+  }
+  //modSnode[id_when_no_empty_node] = id_in_mod_tbl
+
+  // Create the new graph
+  FlowGraph * tmp_fgraph = new FlowGraph(Nmod);
+  IGRAPH_FINALLY(delete_FlowGraph, tmp_fgraph);
+  Node ** node_tmp = tmp_fgraph->node ;
+  
+  Node ** node = graph->node;
+  
+  vector<int> nodeInMod = vector<int>(Nnode);
+  
+  // creation of new nodes
+  for (int i=0;i<Nmod;i++) {
+    //node_tmp[i] = new Node();
+    vector<int>().swap(node_tmp[i]->members); // clear membership
+    node_tmp[i]->exit           =           mod_exit[modSnode[i]];
+    node_tmp[i]->size           =           mod_size[modSnode[i]];
+    node_tmp[i]->danglingSize   =   mod_danglingSize[modSnode[i]];
+    node_tmp[i]->teleportWeight = mod_teleportWeight[modSnode[i]];
+    
+    nodeInMod[modSnode[i]]      = i;
+  }
+  //nodeInMode[id_in_mod_tbl] = id_when_no_empty_node
+  
+  // Calculate outflow of links to different modules
+  vector<map<int,double> > outFlowNtoM(Nmod);
+  map<int,double>::iterator it_M;
+  
+  for (int i=0;i<Nnode;i++) {
+    int i_M = nodeInMod[node_index[i]]; //final id of the module of the node i
+    // add node members to the module
+    copy( node[i]->members.begin(), node[i]->members.end(), 
+	  back_inserter( node_tmp[i_M]->members ) );
+
+    int NoutLinks = node[i]->outLinks.size();
+    for (int j=0; j<NoutLinks; j++) {
+      int nb         = node[i]->outLinks[j].first;
+      int nb_M       = nodeInMod[node_index[nb]];
+      double nb_flow = node[i]->outLinks[j].second;
+      if (nb != i) {
+	it_M = outFlowNtoM[i_M].find(nb_M);
+	if (it_M != outFlowNtoM[i_M].end()) {
+	  it_M->second += nb_flow;
+	} else {
+	  outFlowNtoM[i_M].insert(make_pair(nb_M,nb_flow));
+	}
+      }
+    }
+  }
+  
+  // Create outLinks at new level
+  for (int i=0;i<Nmod;i++) {
+    for (it_M = outFlowNtoM[i].begin(); it_M != outFlowNtoM[i].end(); it_M++) {
+      if (it_M->first != i) {
+	node_tmp[i]->outLinks.push_back(make_pair(it_M->first,it_M->second));
+      }
+    }
+  }
+
+  // Calculate inflow of links from different modules
+  vector<map<int,double> > inFlowNtoM(Nmod);
+  
+  for (int i=0;i<Nnode;i++) {
+    int i_M = nodeInMod[node_index[i]];
+    int NinLinks = node[i]->inLinks.size();
+    for (int j=0;j<NinLinks;j++) {
+      int nb         = node[i]->inLinks[j].first;
+      int nb_M       = nodeInMod[node_index[nb]];
+      double nb_flow = node[i]->inLinks[j].second;
+      if (nb != i) {
+	it_M = inFlowNtoM[i_M].find(nb_M);
+	if (it_M != inFlowNtoM[i_M].end()) {
+	  it_M->second += nb_flow;
+	} else {
+	  inFlowNtoM[i_M].insert(make_pair(nb_M,nb_flow));
+	}
+      }
+    }
+  }
+
+  // Create inLinks at new level
+  for (int i=0;i<Nmod;i++) {
+    for (it_M = inFlowNtoM[i].begin(); it_M != inFlowNtoM[i].end(); it_M++) {
+      if (it_M->first != i) {
+	node_tmp[i]->inLinks.push_back(make_pair(it_M->first,it_M->second));
+      }
+    }
+  }
+  
+  // Option to move to empty module
+  vector<int>().swap(mod_empty);
+  Nempty = 0;
+
+  //swap node between tmp_graph and graph, then destroy tmp_fgraph
+  graph->swap(tmp_fgraph);
+  Nnode = Nmod;
+  
+  delete tmp_fgraph;
+  IGRAPH_FINALLY_CLEAN(1);
+}
+
+
+/**
+ * RAZ et recalcul : 
+ *  - mod_exit
+ *  - mod_size
+ *  - mod_danglingSize
+ *  - mod_teleportWeight
+ *  - mod_members
+ *  and
+ *  - exit_log_exit
+ *  - size_log_size
+ *  - exitFlow
+ *  - exit
+ *  - codeLength
+ * according to **node / node[i]->index
+ */
+void Greedy::tune(void) {
+
+  exit_log_exit = 0.0;
+  size_log_size = 0.0;
+  exitFlow = 0.0;
+  
+  for (int i=0;i<Nnode;i++) {
+    mod_exit[i] = 0.0;
+    mod_size[i] = 0.0;
+    mod_danglingSize[i] = 0.0;
+    mod_teleportWeight[i] = 0.0;
+    mod_members[i] = 0;
+  }
+  
+  Node ** node = graph->node;
+  // Update all values except contribution from teleportation
+  for (int i=0; i < Nnode; i++) {
+    int i_M = node_index[i]; // module id of node i
+    int Nlinks = node[i]->outLinks.size();
+    
+    mod_size[i_M]           += node[i]->size;
+    mod_danglingSize[i_M]   += node[i]->danglingSize;
+    mod_teleportWeight[i_M] += node[i]->teleportWeight;
+    mod_members[i_M]++;
+    
+    for (int j=0;j<Nlinks;j++) {
+      int neighbor      = node[i]->outLinks[j].first;
+      double neighbor_w = node[i]->outLinks[j].second;
+      int neighbor_M    = node_index[neighbor];
+      if (i_M != neighbor_M) // neighbor in an other module
+	mod_exit[i_M] += neighbor_w;
+    }
+  }
+  
+  // Update contribution from teleportation
+  for (int i=0;i<Nnode;i++) {
+    mod_exit[i] += (alpha*mod_size[i] + beta*mod_danglingSize[i]) * 
+      (1.0 - mod_teleportWeight[i]);
+  }
+
+  for (int i=0;i<Nnode;i++) {
+    exit_log_exit += plogp(mod_exit[i]);
+    size_log_size += plogp(mod_exit[i] + mod_size[i]);
+    exitFlow += mod_exit[i];
+  }
+  exit = plogp(exitFlow);
+  
+  codeLength = exit - 2.0*exit_log_exit + size_log_size - 
+    nodeSize_log_nodeSize;
+}
+
+
+/* Compute the new CodeSize if modules are merged as indicated by moveTo
+ */
+void Greedy::setMove(int *moveTo) {
+  //void Greedy::determMove(int *moveTo) {
+  Node ** node = graph->node;
+  //printf("setMove nNode:%d \n", Nnode);
+  for (int i=0 ; i<Nnode ; i++) { // pour chaque module
+    int oldM = i;
+    int newM = moveTo[i];
+    //printf("old -> new : %d -> %d \n", oldM, newM);
+    if (newM != oldM) {
+      
+      // Si je comprend bien :
+      // outFlow... : c'est le "flow" de i-> autre sommet du meme module
+      // inFlow... : c'est le "flow" depuis un autre sommet du meme module --> i
+      double outFlowOldM = (alpha*node[i]->size + beta*node[i]->danglingSize)*
+	(mod_teleportWeight[oldM]-node[i]->teleportWeight);
+      double inFlowOldM  = (alpha*(mod_size[oldM]-node[i]->size) + 
+			    beta*(mod_danglingSize[oldM] - 
+				  node[i]->danglingSize)) * 
+	node[i]->teleportWeight;
+      double outFlowNewM = (alpha*node[i]->size + beta*node[i]->danglingSize)
+	* mod_teleportWeight[newM];
+      double inFlowNewM  = (alpha*mod_size[newM] + 
+			    beta*mod_danglingSize[newM]) * 
+	node[i]->teleportWeight;
+
+      // For all outLinks
+      int NoutLinks = node[i]->outLinks.size();
+      for (int j=0; j<NoutLinks; j++) {
+	int nb_M = node_index[node[i]->outLinks[j].first];
+	double nb_flow = node[i]->outLinks[j].second;
+	if (nb_M == oldM) {
+	  outFlowOldM += nb_flow;
+	}
+	else if (nb_M == newM) {
+	  outFlowNewM += nb_flow;
+	}
+      }
+      
+      // For all inLinks
+      int NinLinks = node[i]->inLinks.size();
+      for (int j=0; j<NinLinks; j++) {
+	int nb_M = node_index[node[i]->inLinks[j].first];
+	double nb_flow = node[i]->inLinks[j].second;
+	if (nb_M == oldM) {
+	  inFlowOldM += nb_flow;
+	} else if (nb_M == newM) {
+	  inFlowNewM += nb_flow;
+	}
+      }
+      
+      // Update empty module vector
+      // RAZ de mod_empty et Nempty ds calibrate()
+      if (mod_members[newM] == 0) { 
+	// si le nouveau etait vide, on a un vide de moins...
+	Nempty--;
+      }
+      if (mod_members[oldM] == static_cast<int>(node[i]->members.size())) {
+	// si l'ancien avait la taille de celui qui bouge, un vide de plus
+	mod_empty[Nempty] = oldM;
+	Nempty++;
+      }
+      
+      exitFlow -= mod_exit[oldM] + mod_exit[newM];
+      exit_log_exit -= plogp(mod_exit[oldM]) + plogp(mod_exit[newM]);
+      size_log_size -= plogp(mod_exit[oldM] + mod_size[oldM]) +
+	plogp(mod_exit[newM] + mod_size[newM]);
+      
+      mod_exit[oldM] -= node[i]->exit - outFlowOldM - inFlowOldM;
+      mod_size[oldM] -= node[i]->size;
+      mod_danglingSize[oldM] -= node[i]->danglingSize;
+      mod_teleportWeight[oldM] -= node[i]->teleportWeight;
+      mod_members[oldM] -= node[i]->members.size();
+      mod_exit[newM] += node[i]->exit - outFlowNewM - inFlowNewM;
+      mod_size[newM] += node[i]->size;
+      mod_danglingSize[newM] += node[i]->danglingSize;
+      mod_teleportWeight[newM] += node[i]->teleportWeight;
+      mod_members[newM] += node[i]->members.size();
+      
+      exitFlow += mod_exit[oldM] + mod_exit[newM];
+      exit_log_exit += plogp(mod_exit[oldM]) + plogp(mod_exit[newM]);
+      size_log_size += plogp(mod_exit[oldM] + mod_size[oldM]) + 
+	plogp(mod_exit[newM] + mod_size[newM]);
+      exit = plogp(exitFlow);
+      
+      codeLength = exit - 2.0*exit_log_exit + size_log_size - 
+	nodeSize_log_nodeSize;
+      
+      node_index[i] = newM;
+      
+    }
+    
+  }
+}
+
+
diff --git a/src/infomap_Greedy.h b/src/infomap_Greedy.h
new file mode 100644
index 0000000..a0c9228
--- /dev/null
+++ b/src/infomap_Greedy.h
@@ -0,0 +1,85 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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 GREEDY_H
+#define GREEDY_H
+
+#include <vector>
+#include <map>
+#include <utility>
+#include <climits>
+
+#include "igraph_random.h"
+
+#include "infomap_Node.h"
+#include "infomap_FlowGraph.h"
+
+class Greedy {
+ public:
+  Greedy(FlowGraph * fgraph); 
+  // initialise les attributs par rapport au graph
+
+  ~Greedy();
+
+   void setMove(int *moveTo);
+  //virtual void determMove(int *moveTo);
+  
+  bool optimize();
+  //virtual void move(bool &moved);
+
+  void apply(bool sort);
+  //virtual void level(Node ***, bool sort);
+
+  void tune(void);
+
+  /**************************************************************************/
+
+  FlowGraph * graph;
+  int Nnode; 
+  
+  double exit;
+  double exitFlow;
+  double exit_log_exit;
+  double size_log_size;
+  double nodeSize_log_nodeSize;
+  
+  double codeLength;
+ 
+  double alpha,beta;  
+  // local copy of fgraph alpha, beta (=alpha -  Nnode = graph->Nnode;1)
+
+  vector<int> node_index;  // module number of each node
+
+  int Nempty;
+  vector<int> mod_empty;
+
+  vector<double> mod_exit;  // version tmp de node
+  vector<double> mod_size;
+  vector<double> mod_danglingSize;
+  vector<double> mod_teleportWeight;
+  vector<int> mod_members;
+};
+
+void delete_Greedy(Greedy *greedy);
+#endif
diff --git a/src/infomap_Node.cc b/src/infomap_Node.cc
new file mode 100644
index 0000000..42bbde7
--- /dev/null
+++ b/src/infomap_Node.cc
@@ -0,0 +1,69 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include "infomap_Node.h"
+
+Node::Node(){ 
+  exit = 0.0;
+  size = 0.0;
+  selfLink = 0.0;
+}
+
+Node::Node(int nodenr, double tpweight){
+  teleportWeight = tpweight;
+  exit = 0.0;
+  size = 0.0;
+  selfLink = 0.0;
+  members.push_back(nodenr); // members = [nodenr]
+}
+
+void cpyNode(Node *newNode, Node *oldNode){
+  newNode->exit = oldNode->exit;
+  newNode->size = oldNode->size;
+  newNode->teleportWeight = oldNode->teleportWeight;
+  newNode->danglingSize   = oldNode->danglingSize;
+  
+  int Nmembers = oldNode->members.size();
+  newNode->members = vector<int>(Nmembers);
+  for (int i=0;i<Nmembers;i++)
+    newNode->members[i] = oldNode->members[i];
+  
+  newNode->selfLink = oldNode->selfLink;
+  
+  int NoutLinks = oldNode->outLinks.size();
+  newNode->outLinks = vector<pair<int,double> >(NoutLinks);
+  for (int i=0;i<NoutLinks;i++){
+    newNode->outLinks[i].first = oldNode->outLinks[i].first;
+    newNode->outLinks[i].second = oldNode->outLinks[i].second;
+  }
+  
+  int NinLinks = oldNode->inLinks.size();
+  newNode->inLinks = vector<pair<int,double> >(NinLinks);
+  for (int i=0;i<NinLinks;i++){
+    newNode->inLinks[i].first = oldNode->inLinks[i].first;
+    newNode->inLinks[i].second = oldNode->inLinks[i].second;
+  }
+  
+}
+
diff --git a/src/infomap_Node.h b/src/infomap_Node.h
new file mode 100644
index 0000000..a265e2f
--- /dev/null
+++ b/src/infomap_Node.h
@@ -0,0 +1,55 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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 NODE_H
+#define NODE_H
+
+#include <vector>
+#include <utility>
+
+#include "igraph_interface.h"
+
+class Node;
+using namespace std;
+
+class Node{
+ public:
+  
+  Node();
+  Node(int modulenr,double tpweight);
+
+  vector<int> members;
+  vector< pair<int,double> > inLinks;
+  vector< pair<int,double> > outLinks;
+  double selfLink;
+
+  double teleportWeight;
+  double danglingSize;
+  double exit;
+  double size;
+};
+
+void cpyNode(Node *newNode, Node *oldNode);
+
+#endif
diff --git a/src/interrupt.c b/src/interrupt.c
new file mode 100644
index 0000000..8ba719b
--- /dev/null
+++ b/src/interrupt.c
@@ -0,0 +1,47 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_interrupt.h"
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+IGRAPH_THREAD_LOCAL igraph_interruption_handler_t 
+  *igraph_i_interruption_handler=0;
+
+int igraph_allow_interruption(void* data) {
+  if (igraph_i_interruption_handler) {
+    return igraph_i_interruption_handler(data);
+  }
+  return IGRAPH_SUCCESS;
+}
+
+igraph_interruption_handler_t *
+igraph_set_interruption_handler (igraph_interruption_handler_t * new_handler)
+{
+  igraph_interruption_handler_t * previous_handler = igraph_i_interruption_handler;
+  igraph_i_interruption_handler = new_handler;
+  return previous_handler;
+}
diff --git a/src/iterators.c b/src/iterators.c
new file mode 100644
index 0000000..e9f84b1
--- /dev/null
+++ b/src/iterators.c
@@ -0,0 +1,1903 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_iterators.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_interface.h"
+#include "config.h"
+
+#include <string.h>
+#include <stdarg.h>
+
+/**
+ * \section about_iterators About selectors, iterators
+ *
+ * <para>Everything about vertices and vertex selectors also applies
+ * to edges and edge selectors unless explicitly noted otherwise.</para>
+ *
+ * <para>The vertex (and edge) selector notion was introduced in igraph 0.2.
+ * It is a way to reference a sequence of vertices or edges
+ * independently of the graph.</para>
+ *
+ * <para>While this might sound quite mysterious, it is actually very
+ * simple. For example, all vertices of a graph can be selected by
+ * \ref igraph_vs_all() and the graph independence means that
+ * \ref igraph_vs_all() is not parametrized by a graph object. That is,
+ * \ref igraph_vs_all() is the general \em concept of selecting all vertices
+ * of a graph. A vertex selector is then a way to specify the class of vertices
+ * to be visited. The selector might specify that all vertices of a graph or
+ * all the neighbours of a vertex are to be visited. A vertex selector is a
+ * way of saying that you want to visit a bunch of vertices, as opposed to a
+ * vertex iterator which is a concrete plan for visiting each of the
+ * chosen vertices of a specific graph.</para>
+ *
+ * <para>To determine the actual vertex IDs implied by a vertex selector, you
+ * need to apply the concept of selecting vertices to a specific graph object.
+ * This can be accomplished by instantiating a vertex iterator using a
+ * specific vertex selection concept and a specific graph object. The notion
+ * of vertex iterators can be thought of in the following way. Given a
+ * specific graph object and the class of vertices to be visited, a vertex
+ * iterator is a road map, plan or route for how to visit the chosen
+ * vertices.</para>
+ * 
+ * <para>Some vertex selectors have \em immediate versions. These have the
+ * prefix \c igraph_vss instead of \c igraph_vs, e.g. \ref igraph_vss_all()
+ * instead of \ref igraph_vs_all(). The immediate versions are to be used in
+ * the parameter list of the igraph functions, such as \ref igraph_degree().
+ * These functions are not associated with any \type igraph_vs_t object, so
+ * they have no separate constructors and destructors
+ * (destroy functions).</para>
+ */ 
+
+/**
+ * \section about_vertex_selectors
+ * 
+ * <para>Vertex selectors are created by vertex selector constructors,
+ * can be instantiated with \ref igraph_vit_create(), and are
+ * destroyed with \ref igraph_vs_destroy().</para>
+ */
+
+/**
+ * \function igraph_vs_all
+ * \brief Vertex set, all vertices of a graph.
+ * 
+ * \param vs Pointer to an uninitialized \type igraph_vs_t object.
+ * \return Error code.
+ * \sa \ref igraph_vss_all(), \ref igraph_vs_destroy()
+ *
+ * This selector includes all vertices of a given graph in
+ * increasing vertex id order.
+ * 
+ * </para><para>
+ * Time complexity: O(1).
+ */
+
+int igraph_vs_all(igraph_vs_t *vs) {
+  vs->type=IGRAPH_VS_ALL;
+  return 0;
+}
+
+/**
+ * \function igraph_vss_all
+ * \brief All vertices of a graph (immediate version).
+ *
+ * Immediate vertex selector for all vertices in a graph. It can
+ * be used conveniently when some vertex property (eg. betweenness,
+ * degree, etc.) should be calculated for all vertices.
+ *
+ * \return A vertex selector for all vertices in a graph.
+ * \sa \ref igraph_vs_all()
+ *
+ * Time complexity: O(1).
+ */
+
+igraph_vs_t igraph_vss_all(void) {
+  igraph_vs_t allvs;
+  allvs.type=IGRAPH_VS_ALL;
+  return allvs;  
+}
+
+/**
+ * \function igraph_vs_adj
+ * \brief Adjacent vertices of a vertex.
+ * 
+ * All neighboring vertices of a given vertex are selected by this
+ * selector. The \c mode argument controls the type of the neighboring 
+ * vertices to be selected. The vertices are visited in increasing vertex
+ * ID order, as of igraph version 0.4.
+ * 
+ * \param vs Pointer to an uninitialized vertex selector object.
+ * \param vid Vertex ID, the center of the neighborhood.
+ * \param mode Decides the type of the neighborhood for directed
+ *        graphs. This parameter is ignored for undirected graphs.
+ *        Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          All vertices to which there is a directed edge from \c vid. That
+ *          is, all the out-neighbors of \c vid.
+ *        \cli IGRAPH_IN
+ *          All vertices from which there is a directed edge to \c vid. In
+ *          other words, all the in-neighbors of \c vid.
+ *        \cli IGRAPH_ALL
+ *          All vertices to which or from which there is a directed edge
+ *          from/to \c vid. That is, all the neighbors of \c vid considered
+ *          as if the graph is undirected.
+ *        \endclist
+ * \return Error code.
+ * \sa \ref igraph_vs_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_vs_adj(igraph_vs_t *vs, 
+		  igraph_integer_t vid, igraph_neimode_t mode) {
+  vs->type=IGRAPH_VS_ADJ;
+  vs->data.adj.vid=vid;
+  vs->data.adj.mode=mode;
+  return 0;
+}
+
+/**
+ * \function igraph_vs_nonadj
+ * \brief Non-adjacent vertices of a vertex.
+ * 
+ * All non-neighboring vertices of a given vertex. The \p mode
+ * argument controls the type of neighboring vertices \em not to
+ * select. Instead of selecting immediate neighbors of \c vid as is done by
+ * \ref igraph_vs_adj(), the current function selects vertices that are \em not
+ * immediate neighbors of \c vid.
+ *
+ * \param vs Pointer to an uninitialized vertex selector object.
+ * \param vid Vertex ID, the \quote center \endquote of the
+ *        non-neighborhood.
+ * \param mode The type of neighborhood not to select in directed
+ *        graphs. Possible values:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          All vertices will be selected except those to which there is a
+ *          directed edge from \c vid. That is, we select all vertices
+ *          excluding the out-neighbors of \c vid.
+ *        \cli IGRAPH_IN
+ *          All vertices will be selected except those from which there is a
+ *          directed edge to \c vid. In other words, we select all vertices
+ *          but the in-neighbors of \c vid.
+ *        \cli IGRAPH_ALL
+ *          All vertices will be selected except those from or to which there
+ *          is a directed edge to or from \c vid. That is, we select all
+ *          vertices of \c vid except for its immediate neighbors.
+ *        \endclist
+ * \return Error code.
+ * \sa \ref igraph_vs_destroy()
+ *
+ * Time complexity: O(1).
+ * 
+ * \example examples/simple/igraph_vs_nonadj.c
+ */
+
+int igraph_vs_nonadj(igraph_vs_t *vs, igraph_integer_t vid, 
+		     igraph_neimode_t mode) {
+  vs->type=IGRAPH_VS_NONADJ;
+  vs->data.adj.vid=vid;
+  vs->data.adj.mode=mode;
+  return 0;
+}
+
+/**
+ * \function igraph_vs_none
+ * \brief Empty vertex set.
+ * 
+ * Creates an empty vertex selector. 
+ *
+ * \param vs Pointer to an uninitialized vertex selector object.
+ * \return Error code.
+ * \sa \ref igraph_vss_none(), \ref igraph_vs_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_vs_none(igraph_vs_t *vs) {
+  vs->type=IGRAPH_VS_NONE;
+  return 0;
+}
+
+/**
+ * \function igraph_vss_none
+ * \brief Empty vertex set (immediate version).
+ *
+ * The immediate version of the empty vertex selector.
+ * 
+ * \return An empty vertex selector.
+ * \sa \ref igraph_vs_none()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_vs_t igraph_vss_none(void) {
+  igraph_vs_t nonevs;
+  nonevs.type=IGRAPH_VS_NONE;
+  return nonevs;
+}
+
+/**
+ * \function igraph_vs_1
+ * \brief Vertex set with a single vertex.
+ * 
+ * This vertex selector selects a single vertex.
+ *
+ * \param vs Pointer to an uninitialized vertex selector object.
+ * \param vid The vertex id to be selected.
+ * \return Error Code.
+ * \sa \ref igraph_vss_1(), \ref igraph_vs_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_vs_1(igraph_vs_t *vs, igraph_integer_t vid) {
+  vs->type=IGRAPH_VS_1;
+  vs->data.vid=vid;
+  return 0;
+}
+
+/**
+ * \function igraph_vss_1
+ * \brief Vertex set with a single vertex (immediate version).
+ * 
+ * The immediate version of the single-vertex selector.
+ * 
+ * \param vid The vertex to be selected.
+ * \return A vertex selector containing a single vertex.
+ * \sa \ref igraph_vs_1()
+ *
+ * Time complexity: O(1).
+ */
+
+igraph_vs_t igraph_vss_1(igraph_integer_t vid) {
+  igraph_vs_t onevs;
+  onevs.type=IGRAPH_VS_1;
+  onevs.data.vid=vid;
+  return onevs;
+}
+
+/**
+ * \function igraph_vs_vector
+ * \brief Vertex set based on a vector.
+ * 
+ * This function makes it possible to handle a \type vector_t
+ * temporarily as a vertex selector. The vertex selector should be
+ * thought of like a \em view to the vector. If you make changes to
+ * the vector that also affects the vertex selector. Destroying the
+ * vertex selector does not destroy the vector. (Of course.) Do not
+ * destroy the vector before destroying the vertex selector, or you
+ * might get strange behavior.
+ * 
+ * \param vs Pointer to an uninitialized vertex selector.
+ * \param v Pointer to a \type igraph_vector_t object.
+ * \return Error code.
+ * \sa \ref igraph_vss_vector(), \ref igraph_vs_destroy()
+ * 
+ * Time complexity: O(1).
+ * 
+ * \example examples/simple/igraph_vs_vector.c
+ */
+
+int igraph_vs_vector(igraph_vs_t *vs,
+		     const igraph_vector_t *v) {
+  vs->type=IGRAPH_VS_VECTORPTR;
+  vs->data.vecptr=v;
+  return 0;
+}
+
+/**
+ * \function igraph_vss_vector
+ * \brief Vertex set based on a vector (immediate version).
+ * 
+ * This is the immediate version of \ref igraph_vs_vector. 
+ * 
+ * \param v Pointer to a \type igraph_vector_t object.
+ * \return A vertex selector object containing the vertices in the
+ *         vector. 
+ * \sa \ref igraph_vs_vector()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_vs_t igraph_vss_vector(const igraph_vector_t *v) {
+  igraph_vs_t vecvs;
+  vecvs.type=IGRAPH_VS_VECTORPTR;
+  vecvs.data.vecptr=v;
+  return vecvs;
+}
+
+/**
+ * \function igraph_vs_vector_small
+ * \brief Create a vertex set by giving its elements.
+ *
+ * This function can be used to create a vertex selector with a couple
+ * of vertices. Do not forget to include a <code>-1</code> after the
+ * last vertex id. The behavior of the function is undefined if you
+ * don't use a <code>-1</code> properly.
+ * 
+ * </para><para>
+ * Note that the vertex ids supplied will be parsed as
+ * <code>int</code>'s so you cannot supply arbitrarily large (too
+ * large for int) vertex ids here. 
+ * 
+ * \param vs Pointer to an uninitialized vertex selector object.
+ * \param ... Additional parameters, these will be the vertex ids to
+ *        be included in the vertex selector. Supply a <code>-1</code>
+ *        after the last vertex id.
+ * \return Error code.
+ * \sa \ref igraph_vs_destroy()
+ *
+ * Time complexity: O(n), the number of vertex ids supplied.
+ */
+
+int igraph_vs_vector_small(igraph_vs_t *vs, ...) {
+  va_list ap;
+  long int i, n=0;
+  vs->type=IGRAPH_VS_VECTOR;
+  vs->data.vecptr=igraph_Calloc(1, igraph_vector_t);
+  if (vs->data.vecptr==0) {
+    IGRAPH_ERROR("Cannot create vertex selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)vs->data.vecptr);
+  
+  va_start(ap, vs);
+  while (1) {
+    int num = va_arg(ap, int);
+    if (num == -1) {
+      break;
+    }
+    n++;
+  }
+  va_end(ap);
+
+  IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)vs->data.vecptr, n);
+  
+  va_start(ap, vs);
+  for (i=0; i<n; i++) {
+    VECTOR(*vs->data.vecptr)[i]=(igraph_real_t) va_arg(ap, int);
+  }
+  va_end(ap);  
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;  
+}
+
+/**
+ * \function igraph_vs_vector_copy
+ * \brief Vertex set based on a vector, with copying.
+ * 
+ * This function makes it possible to handle a \type vector_t
+ * permanently as a vertex selector. The vertex selector creates a
+ * copy of the original vector, so the vector can safely be destroyed
+ * after creating the vertex selector. Changing the original vector
+ * will not affect the vertex selector. The vertex selector is
+ * responsible for deleting the copy made by itself.
+ * 
+ * \param vs Pointer to an uninitialized vertex selector.
+ * \param v Pointer to a \type igraph_vector_t object.
+ * \return Error code.
+ * \sa \ref igraph_vs_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_vs_vector_copy(igraph_vs_t *vs,
+			  const igraph_vector_t *v) {
+  vs->type=IGRAPH_VS_VECTOR;
+  vs->data.vecptr=igraph_Calloc(1, igraph_vector_t);
+  if (vs->data.vecptr==0) {
+    IGRAPH_ERROR("Cannot create vertex selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)vs->data.vecptr);
+  IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*)vs->data.vecptr, v));
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_vs_seq
+ * \brief Vertex set, an interval of vertices.
+ * 
+ * Creates a vertex selector containing all vertices with vertex id
+ * equal to or bigger than \c from and equal to or smaller than \c
+ * to.
+ * 
+ * \param vs Pointer to an uninitialized vertex selector object.
+ * \param from The first vertex id to be included in the vertex
+ *        selector. 
+ * \param to The last vertex id to be included in the vertex
+ *        selector. 
+ * \return Error code.
+ * \sa \ref igraph_vss_seq(), \ref igraph_vs_destroy()
+ * 
+ * Time complexity: O(1).
+ * 
+ * \example examples/simple/igraph_vs_seq.c
+ */
+
+int igraph_vs_seq(igraph_vs_t *vs, 
+		  igraph_integer_t from, igraph_integer_t to) {
+  vs->type=IGRAPH_VS_SEQ;
+  vs->data.seq.from=from;
+  vs->data.seq.to=to+1;
+  return 0;
+}
+
+/**
+ * \function igraph_vss_seq
+ * \brief An interval of vertices (immediate version).
+ * 
+ * The immediate version of \ref igraph_vs_seq().
+ * 
+ * \param from The first vertex id to be included in the vertex
+ *        selector. 
+ * \param to The last vertex id to be included in the vertex
+ *        selector. 
+ * \return Error code.
+ * \sa \ref igraph_vs_seq()
+ *
+ * Time complexity: O(1).
+ */
+
+igraph_vs_t igraph_vss_seq(igraph_integer_t from, igraph_integer_t to) {
+  igraph_vs_t vs;
+  vs.type=IGRAPH_VS_SEQ;
+  vs.data.seq.from=from;
+  vs.data.seq.to=to+1;
+  return vs;
+}
+
+/**
+ * \function igraph_vs_destroy
+ * \brief Destroy a vertex set.
+ * 
+ * This function should be called for all vertex selectors when they
+ * are not needed. The memory allocated for the vertex selector will
+ * be deallocated. Do not call this function on vertex selectors
+ * created with the immediate versions of the vertex selector
+ * constructors (starting with <code>igraph_vss</code>).
+ * 
+ * \param vs Pointer to a vertex selector object.
+ * 
+ * Time complexity: operating system dependent, usually O(1).
+ */
+
+void igraph_vs_destroy(igraph_vs_t *vs) {
+  switch (vs->type) {
+  case IGRAPH_VS_ALL:
+  case IGRAPH_VS_ADJ:
+  case IGRAPH_VS_NONE:
+  case IGRAPH_VS_1:
+  case IGRAPH_VS_VECTORPTR:
+  case IGRAPH_VS_SEQ:
+  case IGRAPH_VS_NONADJ:
+    break;
+  case IGRAPH_VS_VECTOR:
+    igraph_vector_destroy((igraph_vector_t*)vs->data.vecptr);
+    igraph_Free(vs->data.vecptr);
+    break;
+  default:
+    break;
+  }
+}
+
+/**
+ * \function igraph_vs_is_all
+ * \brief Check whether all vertices are included.
+ * 
+ * This function checks whether the vertex selector object was created
+ * by \ref igraph_vs_all() or \ref igraph_vss_all(). Note that the
+ * vertex selector might contain all vertices in a given graph but if
+ * it wasn't created by the two constructors mentioned here the return
+ * value will be FALSE.
+ * 
+ * \param vs Pointer to a vertex selector object.
+ * \return TRUE (1) if the vertex selector contains all vertices and
+ *         FALSE (0) otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t igraph_vs_is_all(const igraph_vs_t *vs) {
+  return vs->type == IGRAPH_VS_ALL;
+}
+
+int igraph_vs_as_vector(const igraph_t *graph, igraph_vs_t vs, 
+			igraph_vector_t *v) {
+  igraph_vit_t vit;
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vs, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  IGRAPH_CHECK(igraph_vit_as_vector(&vit, v));
+
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+} 
+
+/**
+ * \function igraph_vs_copy
+ * \brief Creates a copy of a vertex selector.
+ * \param src The selector being copied.
+ * \param dest An uninitialized selector that will contain the copy.
+ */
+int igraph_vs_copy(igraph_vs_t* dest, const igraph_vs_t* src) {
+  memcpy(dest, src, sizeof(igraph_vs_t));
+  switch (dest->type) {
+    case IGRAPH_VS_VECTOR:
+      dest->data.vecptr = igraph_Calloc(1,igraph_vector_t);
+      if (!dest->data.vecptr)
+        IGRAPH_ERROR("Cannot copy vertex selector", IGRAPH_ENOMEM);
+      IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*)dest->data.vecptr,
+        (igraph_vector_t*)src->data.vecptr));
+      break;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_vs_type
+ * \brief Returns the type of the vertex selector.
+ */
+int igraph_vs_type(const igraph_vs_t *vs) { return vs->type; }
+
+/**
+ * \function igraph_vs_size
+ * \brief Returns the size of the vertex selector.
+ *
+ * The size of the vertex selector is the number of vertices it will
+ * yield when it is iterated over.
+ *
+ * \param graph The graph over which we will iterate.
+ * \param result The result will be returned here.
+ */
+int igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs,
+  igraph_integer_t *result) {
+  igraph_vector_t vec;
+  igraph_bool_t *seen;
+  long i;
+
+  switch (vs->type) {
+    case IGRAPH_VS_NONE:
+      *result = 0; return 0;
+
+    case IGRAPH_VS_1:
+      *result = 0;
+      if (vs->data.vid < igraph_vcount(graph) && vs->data.vid >= 0) *result=1;
+      return 0;
+
+    case IGRAPH_VS_SEQ:
+      *result = vs->data.seq.to - vs->data.seq.from;
+      return 0;
+
+    case IGRAPH_VS_ALL:
+      *result = igraph_vcount(graph); return 0;
+
+    case IGRAPH_VS_ADJ:
+    IGRAPH_VECTOR_INIT_FINALLY(&vec, 0);
+    IGRAPH_CHECK(igraph_neighbors(graph,&vec,vs->data.adj.vid,vs->data.adj.mode));
+    *result=(igraph_integer_t) igraph_vector_size(&vec);
+    igraph_vector_destroy(&vec);
+    IGRAPH_FINALLY_CLEAN(1);
+    return 0;
+    
+    case IGRAPH_VS_NONADJ:
+    IGRAPH_VECTOR_INIT_FINALLY(&vec, 0);
+    IGRAPH_CHECK(igraph_neighbors(graph,&vec,vs->data.adj.vid,vs->data.adj.mode));
+    *result=igraph_vcount(graph);
+    seen=igraph_Calloc(*result, igraph_bool_t);
+    if (seen==0) {
+      IGRAPH_ERROR("Cannot calculate selector length", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, seen);
+    for (i=0; i<igraph_vector_size(&vec); i++) {
+      if (!seen[(long int)VECTOR(vec)[i]]) {
+        (*result)--;
+	      seen[(long int)VECTOR(vec)[i]] = 1;
+      }
+    }
+    igraph_free(seen);
+    igraph_vector_destroy(&vec);
+    IGRAPH_FINALLY_CLEAN(2);
+    return 0;
+    
+    case IGRAPH_VS_VECTOR:
+    case IGRAPH_VS_VECTORPTR:
+      *result = (igraph_integer_t) igraph_vector_size((igraph_vector_t*)vs->data.vecptr);
+    return 0;
+  }
+
+  IGRAPH_ERROR("Cannot calculate selector length, invalid selector type",
+    IGRAPH_EINVAL);
+}
+
+/***************************************************/
+
+/**
+ * \function igraph_vit_create
+ * \brief Creates a vertex iterator from a vertex selector.
+ * 
+ * This function instantiates a vertex selector object with a given
+ * graph. This is the step when the actual vertex ids are created from
+ * the \em logical notion of the vertex selector based on the graph. 
+ * Eg. a vertex selector created with \ref igraph_vs_all() contains
+ * knowledge that \em all vertices are included in a (yet indefinite)
+ * graph. When instantiating it a vertex iterator object is created,
+ * this contains the actual vertex ids in the graph supplied as a
+ * parameter. 
+ * 
+ * </para><para>
+ * The same vertex selector object can be used to instantiate any
+ * number vertex iterators.
+ *
+ * \param graph An \type igraph_t object, a graph. 
+ * \param vs A vertex selector object. 
+ * \param vit Pointer to an uninitialized vertex iterator object.
+ * \return Error code.
+ * \sa \ref igraph_vit_destroy().
+ * 
+ * Time complexity: it depends on the vertex selector type. O(1) for
+ * vertex selectors created with \ref igraph_vs_all(), \ref
+ * igraph_vs_none(), \ref igraph_vs_1, \ref igraph_vs_vector, \ref
+ * igraph_vs_seq(), \ref igraph_vs_vector(), \ref
+ * igraph_vs_vector_small(). O(d) for \ref igraph_vs_adj(), d is the
+ * number of vertex ids to be included in the iterator. O(|V|) for 
+ * \ref igraph_vs_nonadj(), |V| is the number of vertices in the graph.
+ */
+
+int igraph_vit_create(const igraph_t *graph, 
+		      igraph_vs_t vs, igraph_vit_t *vit) {
+  igraph_vector_t vec;
+  igraph_bool_t *seen;
+  long int i, j, n;
+
+  switch (vs.type) {
+  case IGRAPH_VS_ALL:
+    vit->type=IGRAPH_VIT_SEQ;
+    vit->pos=0;
+    vit->start=0;
+    vit->end=igraph_vcount(graph);
+    break;
+  case IGRAPH_VS_ADJ:
+    vit->type=IGRAPH_VIT_VECTOR;
+    vit->pos=0;
+    vit->start=0;
+    vit->vec=igraph_Calloc(1, igraph_vector_t);
+    if (vit->vec == 0) {
+      IGRAPH_ERROR("Cannot create iterator", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (igraph_vector_t*) vit->vec);
+    IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)vit->vec, 0);
+    IGRAPH_CHECK(igraph_neighbors(graph, (igraph_vector_t*)vit->vec, 
+				  vs.data.adj.vid, vs.data.adj.mode));
+    vit->end=igraph_vector_size(vit->vec);
+    IGRAPH_FINALLY_CLEAN(2);
+    break;
+  case IGRAPH_VS_NONADJ:
+    vit->type=IGRAPH_VIT_VECTOR;
+    vit->pos=0;
+    vit->start=0;
+    vit->vec=igraph_Calloc(1, igraph_vector_t);
+    if (vit->vec == 0) {
+      IGRAPH_ERROR("Cannot create iterator", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (igraph_vector_t*) vit->vec);
+    IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t *) vit->vec, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&vec, 0);
+    IGRAPH_CHECK(igraph_neighbors(graph, &vec, 
+				  vs.data.adj.vid, vs.data.adj.mode));
+    n=igraph_vcount(graph);
+    seen=igraph_Calloc(n, igraph_bool_t);
+    if (seen==0) {
+      IGRAPH_ERROR("Cannot create iterator", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, seen);
+    for (i=0; i<igraph_vector_size(&vec); i++) {
+      if (! seen [ (long int) VECTOR(vec)[i] ] ) {
+	n--;
+	seen[ (long int) VECTOR(vec)[i] ] = 1;
+      }
+    }
+    IGRAPH_CHECK(igraph_vector_resize((igraph_vector_t*)vit->vec, n));
+    for (i=0, j=0; j<n; i++) {
+      if (!seen[i]) {
+	VECTOR(*vit->vec)[j++] = i;
+      }
+    }
+    
+    igraph_Free(seen);
+    igraph_vector_destroy(&vec);
+    vit->end=n;
+    IGRAPH_FINALLY_CLEAN(4);
+    break;
+  case IGRAPH_VS_NONE:
+    vit->type=IGRAPH_VIT_SEQ;
+    vit->pos=0;
+    vit->start=0;
+    vit->end=0;
+    break;
+  case IGRAPH_VS_1:
+    vit->type=IGRAPH_VIT_SEQ;
+    vit->pos=vs.data.vid;
+    vit->start=vs.data.vid;
+    vit->end=vs.data.vid+1;
+    if (vit->pos >= igraph_vcount(graph)) {
+      IGRAPH_ERROR("Cannot create iterator, invalid vertex id",IGRAPH_EINVVID);
+    }
+    break;
+  case IGRAPH_VS_VECTORPTR:
+  case IGRAPH_VS_VECTOR:
+    vit->type=IGRAPH_VIT_VECTORPTR;
+    vit->pos=0;
+    vit->start=0;
+    vit->vec=vs.data.vecptr;
+    vit->end=igraph_vector_size(vit->vec);
+    if (!igraph_vector_isininterval(vit->vec, 0, igraph_vcount(graph)-1)) {
+      IGRAPH_ERROR("Cannot create iterator, invalid vertex id",IGRAPH_EINVVID);
+    }
+    break;
+  case IGRAPH_VS_SEQ:
+    vit->type=IGRAPH_VIT_SEQ;
+    vit->pos=vs.data.seq.from;
+    vit->start=vs.data.seq.from;
+    vit->end=vs.data.seq.to;
+    break;
+  default:
+    IGRAPH_ERROR("Cannot create iterator, invalid selector", IGRAPH_EINVAL);
+    break;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_vit_destroy
+ * \brief Destroys a vertex iterator.
+ * 
+ * </para><para>
+ * Deallocates memory allocated for a vertex iterator. 
+ * 
+ * \param vit Pointer to an initialized vertex iterator object.
+ * \sa \ref igraph_vit_create()
+ * 
+ * Time complexity: operating system dependent, usually O(1).
+ */
+
+void igraph_vit_destroy(const igraph_vit_t *vit) {
+  switch (vit->type) {
+  case IGRAPH_VIT_SEQ:
+  case IGRAPH_VIT_VECTORPTR:
+    break;
+  case IGRAPH_VIT_VECTOR:
+    igraph_vector_destroy((igraph_vector_t*)vit->vec);
+    igraph_free((igraph_vector_t*)vit->vec);
+    break;
+  default:
+/*     IGRAPH_ERROR("Cannot destroy iterator, unknown type", IGRAPH_EINVAL); */
+    break;
+  }
+}
+
+int igraph_vit_as_vector(const igraph_vit_t *vit, igraph_vector_t *v) {
+
+  long int i;
+
+  IGRAPH_CHECK(igraph_vector_resize(v, IGRAPH_VIT_SIZE(*vit)));
+  
+  switch (vit->type) {
+  case IGRAPH_VIT_SEQ: 
+    for (i=0; i<IGRAPH_VIT_SIZE(*vit); i++) {
+      VECTOR(*v)[i] = vit->start+i;
+    }
+    break;
+  case IGRAPH_VIT_VECTOR:
+  case IGRAPH_VIT_VECTORPTR:
+    for (i=0; i<IGRAPH_VIT_SIZE(*vit); i++) {
+      VECTOR(*v)[i] = VECTOR(*vit->vec)[i];
+    }
+    break;
+  default:
+    IGRAPH_ERROR("Cannot convert to vector, unknown iterator type", 
+		 IGRAPH_EINVAL);
+    break;
+  }
+  
+  return 0;
+}
+
+/*******************************************************/
+
+/**
+ * \function igraph_es_all
+ * \brief Edge set, all edges.
+ *
+ * \param es Pointer to an uninitialized edge selector object.
+ * \param order Constant giving the order in which the edges will be
+ *        included in the selector. Possible values:
+ *        \c IGRAPH_EDGEORDER_ID, edge id order.
+ *        \c IGRAPH_EDGEORDER_FROM, vertex id order, the id of the
+ *           \em source vertex counts for directed graphs. The order
+ *           of the incident edges of a given vertex is arbitrary.
+ *        \c IGRAPH_EDGEORDER_TO, vertex id order, the id of the \em
+ *           target vertex counts for directed graphs. The order
+ *           of the incident edges of a given vertex is arbitrary.
+ *        For undirected graph the latter two is the same. 
+ * \return Error code.
+ * \sa \ref igraph_ess_all(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_es_all(igraph_es_t *es, 
+		  igraph_edgeorder_type_t order) {
+  switch (order) {
+  case IGRAPH_EDGEORDER_ID:
+    es->type=IGRAPH_ES_ALL;
+    break;
+  case IGRAPH_EDGEORDER_FROM:
+    es->type=IGRAPH_ES_ALLFROM;
+    break;
+  case IGRAPH_EDGEORDER_TO:
+    es->type=IGRAPH_ES_ALLTO;
+    break;
+  default:
+    IGRAPH_ERROR("Invalid edge order, cannot create selector", IGRAPH_EINVAL);
+    break;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_ess_all
+ * \brief Edge set, all edges (immediate version)
+ * 
+ * The immediate version of the all-vertices selector.
+ * 
+ * \param order Constant giving the order of the edges in the edge
+ *        selector. See \ref igraph_es_all() for the possible values.
+ * \return The edge selector. 
+ * \sa \ref igraph_es_all()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_es_t igraph_ess_all(igraph_edgeorder_type_t order) {
+  igraph_es_t es;
+  igraph_es_all(&es, order); /* cannot fail */
+  return es;  
+}
+
+/**
+ * \function igraph_es_adj
+ * \brief Adjacent edges of a vertex.
+ *
+ * This function was superseded by \ref igraph_es_incident() in igraph 0.6.
+ * Please use \ref igraph_es_incident() instead of this function.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+int igraph_es_adj(igraph_es_t *es, 
+		  igraph_integer_t vid, igraph_neimode_t mode) {
+  IGRAPH_WARNING("igraph_es_adj is deprecated, use igraph_es_incident");
+  return igraph_es_incident(es, vid, mode);
+}
+
+/**
+ * \function igraph_es_incident
+ * \brief Edges incident on a given vertex.
+ * 
+ * \param es Pointer to an uninitialized edge selector object.
+ * \param vid Vertex id, of which the incident edges will be
+ *        selected.
+ * \param mode Constant giving the type of the incident edges to
+ *        select. This is ignored for undirected graphs. Possible values:
+ *        \c IGRAPH_OUT, outgoing edges;
+ *        \c IGRAPH_IN, incoming edges;
+ *        \c IGRAPH_ALL, all edges.
+ * \return Error code.
+ * \sa \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ * 
+ * \example examples/simple/igraph_es_adj.c
+ */
+
+int igraph_es_incident(igraph_es_t *es, 
+		  igraph_integer_t vid, igraph_neimode_t mode) {
+  es->type=IGRAPH_ES_INCIDENT;
+  es->data.incident.vid=vid;
+  es->data.incident.mode=mode;
+  return 0;
+}
+
+/**
+ * \function igraph_es_none
+ * \brief Empty edge selector.
+ * 
+ * \param es Pointer to an uninitialized edge selector object to
+ * initialize.
+ * \return Error code.
+ * \sa \ref igraph_ess_none(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_es_none(igraph_es_t *es) {
+  es->type=IGRAPH_ES_NONE;
+  return 0;
+}
+
+/**
+ * \function igraph_ess_none
+ * \brief Immediate empty edge selector.
+ * 
+ * </para><para>
+ * Immediate version of the empty edge selector.
+ * 
+ * \return Initialized empty edge selector.
+ * \sa \ref igraph_es_none()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_es_t igraph_ess_none(void) {
+  igraph_es_t es;
+  es.type=IGRAPH_ES_NONE;
+  return es;
+}
+
+/**
+ * \function igraph_es_1
+ * \brief Edge selector containing a single edge.
+ * 
+ * \param es Pointer to an uninitialized edge selector object.
+ * \param eid Edge id of the edge to select.
+ * \return Error code.
+ * \sa \ref igraph_ess_1(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_es_1(igraph_es_t *es, igraph_integer_t eid) {
+  es->type=IGRAPH_ES_1;
+  es->data.eid=eid;
+  return 0;
+}
+
+/**
+ * \function igraph_ess_1
+ * \brief Immediate version of the single edge edge selector.
+ * 
+ * \param eid The id of the edge.
+ * \return The edge selector.
+ * \sa \ref igraph_es_1()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_es_t igraph_ess_1(igraph_integer_t eid) {
+  igraph_es_t es;
+  es.type=IGRAPH_ES_1;
+  es.data.eid=eid;
+  return es;
+}
+
+/**
+ * \function igraph_es_vector
+ * \brief Handle a vector as an edge selector.
+ * 
+ * </para><para>
+ * Creates an edge selector which serves as a view to a vector
+ * containing edge ids. Do not destroy the vector before destroying
+ * the view. 
+ * 
+ * Many views can be created to the same vector.
+ * 
+ * \param es Pointer to an uninitialized edge selector.
+ * \param v Vector containing edge ids.
+ * \return Error code.
+ * \sa \ref igraph_ess_vector(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_es_vector(igraph_es_t *es,
+		     const igraph_vector_t *v) {
+  es->type=IGRAPH_ES_VECTORPTR;
+  es->data.vecptr=v;
+  return 0;
+}
+
+/**
+ * \function igraph_es_vector_copy
+ * \brief Edge set, based on a vector, with copying.
+ * 
+ *
+ * This function makes it possible to handle a \type vector_t
+ * permanently as an edge selector. The edge selector creates a
+ * copy of the original vector, so the vector can safely be destroyed
+ * after creating the edge selector. Changing the original vector
+ * will not affect the edge selector. The edge selector is
+ * responsible for deleting the copy made by itself.
+ * 
+ * \param es Pointer to an uninitialized edge selector.
+ * \param v Pointer to a \type igraph_vector_t object.
+ * \return Error code.
+ * \sa \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_es_vector_copy(igraph_es_t *es, const igraph_vector_t *v) {
+  es->type=IGRAPH_ES_VECTOR;
+  es->data.vecptr=igraph_Calloc(1, igraph_vector_t);
+  if (es->data.vecptr==0) {
+    IGRAPH_ERROR("Cannot create edge selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)es->data.vecptr);
+  IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*)es->data.vecptr, v));
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_ess_vector
+ * \brief Immediate vector view edge selector.
+ * 
+ * </para><para>
+ * This is the immediate version of the vector of edge ids edge
+ * selector. 
+ * 
+ * \param v The vector of edge ids.
+ * \return Edge selector, initialized.
+ * \sa \ref igraph_es_vector()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_es_t igraph_ess_vector(const igraph_vector_t *v) {
+  igraph_es_t es;
+  es.type=IGRAPH_ES_VECTORPTR;
+  es.data.vecptr=v;
+  return es;
+}
+
+/**
+ * \function igraph_es_fromto
+ * \brief Edge selector, all edges between two vertex sets.
+ * 
+ * </para><para>
+ * This function is not implemented yet.
+ * 
+ * \param es Pointer to an uninitialized edge selector.
+ * \param from Vertex selector, their outgoing edges will be
+ *        selected. 
+ * \param to Vertex selector, their incoming edges will be selected
+ *        from the previous selection.
+ * \return Error code.
+ * \sa \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ * 
+ * \example examples/simple/igraph_es_fromto.c
+ */
+
+int igraph_es_fromto(igraph_es_t *es,
+		     igraph_vs_t from, igraph_vs_t to) {
+  
+  IGRAPH_UNUSED(es); IGRAPH_UNUSED(from); IGRAPH_UNUSED(to);
+  IGRAPH_ERROR("igraph_es_fromto not implemented yet", IGRAPH_UNIMPLEMENTED);
+  /* TODO */
+  return 0;
+}
+
+/**
+ * \function igraph_es_seq
+ * \brief Edge selector, a sequence of edge ids.
+ * 
+ * All edge ids between <code>from</code> and <code>to</code> will be
+ * included in the edge selection.
+ * 
+ * \param es Pointer to an uninitialized edge selector object.
+ * \param from The first edge id to be included.
+ * \param to The last edge id to be included.
+ * \return Error code.
+ * \sa \ref igraph_ess_seq(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_es_seq(igraph_es_t *es, 
+		  igraph_integer_t from, igraph_integer_t to) {
+  es->type=IGRAPH_ES_SEQ;
+  es->data.seq.from=from;
+  es->data.seq.to=to;
+  return 0;
+}
+
+/**
+ * \function igraph_ess_seq
+ * \brief Immediate version of the sequence edge selector.
+ * 
+ * \param from The first edge id to include.
+ * \param to The last edge id to include.
+ * \return The initialized edge selector.
+ * \sa \ref igraph_es_seq()
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_es_t igraph_ess_seq(igraph_integer_t from, igraph_integer_t to) {
+  igraph_es_t es;
+  es.type=IGRAPH_ES_SEQ;
+  es.data.seq.from=from;
+  es.data.seq.to=to;
+  return es;
+}
+
+/**
+ * \function igraph_es_pairs
+ * \brief Edge selector, multiple edges defined by their endpoints in a vector.
+ * 
+ * The edges between the given pairs of vertices will be included in the
+ * edge selection. The vertex pairs must be defined in the vector <code>v</code>,
+ * the first element of the vector is the first vertex of the first edge
+ * to be selected, the second element is the second vertex of the first
+ * edge, the third element is the first vertex of the second edge and
+ * so on.
+ * 
+ * \param es Pointer to an uninitialized edge selector object.
+ * \param v The vector containing the endpoints of the edges.
+ * \param directed Whether the graph is directed or not.
+ * \return Error code.
+ * \sa \ref igraph_es_pairs_small(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(n), the number of edges being selected.
+ * 
+ * \example examples/simple/igraph_es_pairs.c
+ */
+
+int igraph_es_pairs(igraph_es_t *es, const igraph_vector_t *v, 
+		    igraph_bool_t directed) {
+  es->type=IGRAPH_ES_PAIRS;
+  es->data.path.mode=directed;
+  es->data.path.ptr=igraph_Calloc(1, igraph_vector_t);
+  if (es->data.path.ptr==0) {
+    IGRAPH_ERROR("Cannot create edge selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*) es->data.path.ptr);
+  
+  IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*) es->data.path.ptr, v));
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_es_pairs_small
+ * \brief Edge selector, multiple edges defined by their endpoints as arguments.
+ * 
+ * The edges between the given pairs of vertices will be included in the
+ * edge selection. The vertex pairs must be given as the arguments of the
+ * function call, the third argument is the first vertex of the first edge,
+ * the fourth argument is the second vertex of the first edge, the fifth
+ * is the first vertex of the second edge and so on. The last element of the
+ * argument list must be -1 to denote the end of the argument list.
+ * 
+ * \param es Pointer to an uninitialized edge selector object.
+ * \param directed Whether the graph is directed or not.
+ * \return Error code.
+ * \sa \ref igraph_es_pairs(), \ref igraph_es_destroy()
+ * 
+ * Time complexity: O(n), the number of edges being selected.
+ */
+
+int igraph_es_pairs_small(igraph_es_t *es, igraph_bool_t directed, ...) {
+  va_list ap;
+  long int i, n=0;
+  es->type=IGRAPH_ES_PAIRS;
+  es->data.path.mode=directed;
+  es->data.path.ptr=igraph_Calloc(1, igraph_vector_t);
+  if (es->data.path.ptr==0) {
+    IGRAPH_ERROR("Cannot create edge selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)es->data.path.ptr);
+  
+  va_start(ap, directed);
+  while (1) {
+    int num = va_arg(ap, int);
+    if (num == -1) {
+      break;
+    }
+    n++;
+  }
+  va_end(ap);
+
+  IGRAPH_VECTOR_INIT_FINALLY( (igraph_vector_t*) es->data.path.ptr, n);
+  
+  va_start(ap, directed);
+  for (i=0; i<n; i++) {
+    VECTOR(*es->data.path.ptr)[i]=(igraph_real_t) va_arg(ap, int);
+  }
+  va_end(ap);
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+int igraph_es_multipairs(igraph_es_t *es, const igraph_vector_t *v,
+			 igraph_bool_t directed) {
+  es->type=IGRAPH_ES_MULTIPAIRS;
+  es->data.path.mode=directed;
+  es->data.path.ptr=igraph_Calloc(1, igraph_vector_t);
+  if (es->data.path.ptr==0) {
+    IGRAPH_ERROR("Cannot create edge selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*) es->data.path.ptr);
+  
+  IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*) es->data.path.ptr, v));
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \example examples/simple/igraph_es_path.c
+ */
+
+int igraph_es_path(igraph_es_t *es, const igraph_vector_t *v, 
+		   igraph_bool_t directed) {
+  es->type=IGRAPH_ES_PATH;
+  es->data.path.mode=directed;
+  es->data.path.ptr=igraph_Calloc(1, igraph_vector_t);
+  if (es->data.path.ptr==0) {
+    IGRAPH_ERROR("Cannot create edge selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*) es->data.path.ptr);
+  
+  IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*) es->data.path.ptr, v));
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_es_path_small(igraph_es_t *es, igraph_bool_t directed, ...) {
+  va_list ap;
+  long int i, n=0;
+  es->type=IGRAPH_ES_PATH;
+  es->data.path.mode=directed;
+  es->data.path.ptr=igraph_Calloc(1, igraph_vector_t);
+  if (es->data.path.ptr==0) {
+    IGRAPH_ERROR("Cannot create edge selector", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)es->data.path.ptr);
+  
+  va_start(ap, directed);
+  while (1) {
+    int num = va_arg(ap, int);
+    if (num == -1) {
+      break;
+    }
+    n++;
+  }
+  va_end(ap);
+
+  IGRAPH_VECTOR_INIT_FINALLY( (igraph_vector_t*) es->data.path.ptr, n);
+  
+  va_start(ap, directed);
+  for (i=0; i<n; i++) {
+    VECTOR(*es->data.path.ptr)[i]=(igraph_real_t) va_arg(ap, int);
+  }
+  va_end(ap);
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_es_destroy
+ * \brief Destroys an edge selector object.
+ * 
+ * </para><para>
+ * Call this function on an edge selector when it is not needed any
+ * more. Do \em not call this function on edge selectors created by
+ * immediate constructors, those don't need to be destroyed.
+ * 
+ * \param es Pointer to an edge selector object.
+ * 
+ * Time complexity: operating system dependent, usually O(1).
+ */
+
+void igraph_es_destroy(igraph_es_t *es) {
+  switch (es->type) { 
+  case IGRAPH_ES_ALL:
+  case IGRAPH_ES_ALLFROM:
+  case IGRAPH_ES_ALLTO:
+  case IGRAPH_ES_INCIDENT:
+  case IGRAPH_ES_NONE:
+  case IGRAPH_ES_1:
+  case IGRAPH_ES_VECTORPTR:
+  case IGRAPH_ES_SEQ:
+    break;
+  case IGRAPH_ES_VECTOR:
+    igraph_vector_destroy((igraph_vector_t*)es->data.vecptr);
+    igraph_Free(es->data.vecptr);
+    break;
+  case IGRAPH_ES_PAIRS:
+  case IGRAPH_ES_PATH:
+  case IGRAPH_ES_MULTIPAIRS:
+    igraph_vector_destroy((igraph_vector_t*)es->data.path.ptr);
+    igraph_Free(es->data.path.ptr);
+    break;
+  default:
+    break;
+  }
+}
+
+/**
+ * \function igraph_es_is_all
+ * \brief Check whether an edge selector includes all edges.
+ * 
+ * \param es Pointer to an edge selector object.
+ * \return TRUE (1) if <code>es</code> was created with \ref
+ * igraph_es_all() or \ref igraph_ess_all(), and FALSE (0) otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t igraph_es_is_all(const igraph_es_t *es) {
+  return es->type == IGRAPH_ES_ALL;
+}
+
+/**
+ * \function igraph_es_copy
+ * \brief Creates a copy of an edge selector.
+ * \param src The selector being copied.
+ * \param dest An uninitialized selector that will contain the copy.
+ * \sa \ref igraph_es_destroy()
+ */
+int igraph_es_copy(igraph_es_t* dest, const igraph_es_t* src) {
+  memcpy(dest, src, sizeof(igraph_es_t));
+  switch (dest->type) {
+    case IGRAPH_ES_VECTOR:
+      dest->data.vecptr = igraph_Calloc(1,igraph_vector_t);
+      if (!dest->data.vecptr)
+        IGRAPH_ERROR("Cannot copy edge selector", IGRAPH_ENOMEM);
+      IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*)dest->data.vecptr,
+        (igraph_vector_t*)src->data.vecptr));
+      break;
+    case IGRAPH_ES_PATH:
+    case IGRAPH_ES_PAIRS:
+    case IGRAPH_ES_MULTIPAIRS:
+      dest->data.path.ptr = igraph_Calloc(1,igraph_vector_t);
+      if (!dest->data.path.ptr)
+        IGRAPH_ERROR("Cannot copy edge selector", IGRAPH_ENOMEM);
+      IGRAPH_CHECK(igraph_vector_copy((igraph_vector_t*)dest->data.path.ptr,
+        (igraph_vector_t*)src->data.path.ptr));
+      break;
+  }
+  return 0;
+}
+
+int igraph_es_as_vector(const igraph_t *graph, igraph_es_t es, 
+			igraph_vector_t *v) {
+  igraph_eit_t eit;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+  IGRAPH_CHECK(igraph_eit_as_vector(&eit, v));
+  
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+} 
+
+/**
+ * \function igraph_es_type
+ * \brief Returns the type of the edge selector.
+ */
+int igraph_es_type(const igraph_es_t *es) { return es->type; }
+
+int igraph_i_es_pairs_size(const igraph_t *graph, 
+		       const igraph_es_t *es, igraph_integer_t *result);
+int igraph_i_es_path_size(const igraph_t *graph, 
+		       const igraph_es_t *es, igraph_integer_t *result);
+int igraph_i_es_multipairs_size(const igraph_t *graph, 
+		       const igraph_es_t *es, igraph_integer_t *result);
+
+/**
+ * \function igraph_es_size
+ * \brief Returns the size of the edge selector.
+ *
+ * The size of the edge selector is the number of edges it will
+ * yield when it is iterated over.
+ *
+ * \param graph The graph over which we will iterate.
+ * \param result The result will be returned here.
+ */
+int igraph_es_size(const igraph_t *graph, const igraph_es_t *es,
+  igraph_integer_t *result) {
+  igraph_vector_t v;
+
+  switch (es->type) {
+    case IGRAPH_ES_ALL:
+      *result = igraph_ecount(graph);
+      return 0;
+
+    case IGRAPH_ES_ALLFROM:
+      *result = igraph_ecount(graph);
+      return 0;
+
+    case IGRAPH_ES_ALLTO:
+      *result = igraph_ecount(graph);
+      return 0;
+
+    case IGRAPH_ES_INCIDENT:
+      IGRAPH_VECTOR_INIT_FINALLY(&v, 0);
+      IGRAPH_CHECK(igraph_incident(graph, &v,
+				 es->data.incident.vid, es->data.incident.mode));
+      *result = (igraph_integer_t) igraph_vector_size(&v);
+      igraph_vector_destroy(&v);
+      IGRAPH_FINALLY_CLEAN(1);
+      return 0;
+
+    case IGRAPH_ES_NONE:
+      *result = 0;
+      return 0;
+
+    case IGRAPH_ES_1:
+      if (es->data.eid < igraph_ecount(graph) && es->data.eid >= 0)
+        *result = 1;
+      else
+        *result = 0;
+      return 0;
+
+    case IGRAPH_ES_VECTOR:
+    case IGRAPH_ES_VECTORPTR:
+      *result = (igraph_integer_t) igraph_vector_size((igraph_vector_t*)es->data.vecptr);
+      return 0;
+
+    case IGRAPH_ES_SEQ:
+      *result = es->data.seq.to - es->data.seq.from;
+      return 0;
+
+    case IGRAPH_ES_PAIRS:
+      IGRAPH_CHECK(igraph_i_es_pairs_size(graph, es, result));
+      return 0;
+
+    case IGRAPH_ES_PATH:
+      IGRAPH_CHECK(igraph_i_es_path_size(graph, es, result));
+      return 0;
+
+    case IGRAPH_ES_MULTIPAIRS:
+      IGRAPH_CHECK(igraph_i_es_multipairs_size(graph, es, result));
+      return 0;
+
+	  default:
+      IGRAPH_ERROR("Cannot calculate selector length, invalid selector type",
+      IGRAPH_EINVAL);
+  }
+
+  return 0;
+}
+
+int igraph_i_es_pairs_size(const igraph_t *graph, 
+		       const igraph_es_t *es, igraph_integer_t *result) {
+  long int n=igraph_vector_size(es->data.path.ptr);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+
+  if (n % 2 != 0) {
+    IGRAPH_ERROR("Cannot calculate edge selector length from odd number of vertices",
+		 IGRAPH_EINVAL);
+  }
+  if (!igraph_vector_isininterval(es->data.path.ptr, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot calculate edge selector length", IGRAPH_EINVVID);
+  }
+
+  *result = (igraph_integer_t) (n/2);
+  /* Check for the existence of all edges */
+  for (i=0; i<*result; i++) {
+    long int from=(long int) VECTOR(*es->data.path.ptr)[2*i];
+    long int to=(long int) VECTOR(*es->data.path.ptr)[2*i+1];
+    igraph_integer_t eid;
+    IGRAPH_CHECK(igraph_get_eid(graph, &eid, (igraph_integer_t) from, 
+				(igraph_integer_t) to, es->data.path.mode, 
+				/*error=*/ 1));
+  }
+  
+  return 0;
+}
+
+int igraph_i_es_path_size(const igraph_t *graph, 
+		      const igraph_es_t *es, igraph_integer_t *result) {
+  long int n=igraph_vector_size(es->data.path.ptr);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+
+  if (!igraph_vector_isininterval(es->data.path.ptr, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot calculate selector length", IGRAPH_EINVVID);
+  }
+  
+  if (n<=1) *result=0; else *result=(igraph_integer_t) (n-1);
+  for (i=0; i<*result; i++) {
+    long int from=(long int) VECTOR(*es->data.path.ptr)[i];
+    long int to=(long int) VECTOR(*es->data.path.ptr)[i+1];
+    igraph_integer_t eid;
+    IGRAPH_CHECK(igraph_get_eid(graph, &eid, (igraph_integer_t) from, 
+				(igraph_integer_t) to, es->data.path.mode,
+				/*error=*/ 1));
+  }
+
+  return 0;
+}
+
+int igraph_i_es_multipairs_size(const igraph_t *graph, 
+		       const igraph_es_t *es, igraph_integer_t *result) {
+  IGRAPH_UNUSED(graph); IGRAPH_UNUSED(es); IGRAPH_UNUSED(result);
+  IGRAPH_ERROR("Cannot calculate edge selector length", IGRAPH_UNIMPLEMENTED);
+}
+
+/**************************************************/
+
+int igraph_i_eit_create_allfromto(const igraph_t *graph,
+				  igraph_eit_t *eit, 
+				  igraph_neimode_t mode);
+int igraph_i_eit_pairs(const igraph_t *graph, 
+		       igraph_es_t es, igraph_eit_t *eit);
+int igraph_i_eit_multipairs(const igraph_t *graph,
+			    igraph_es_t es, igraph_eit_t *eit);
+int igraph_i_eit_path(const igraph_t *graph, 
+		      igraph_es_t es, igraph_eit_t *eit);
+
+int igraph_i_eit_create_allfromto(const igraph_t *graph,
+				  igraph_eit_t *eit, 
+				  igraph_neimode_t mode) {
+  igraph_vector_t *vec;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+
+  vec=igraph_Calloc(1, igraph_vector_t);
+  if (vec==0) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, vec);
+  IGRAPH_VECTOR_INIT_FINALLY(vec, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(vec, igraph_ecount(graph)));
+  
+  if (igraph_is_directed(graph)) {
+    igraph_vector_t adj;
+    IGRAPH_VECTOR_INIT_FINALLY(&adj, 0);
+    for (i=0; i<no_of_nodes; i++) {
+      igraph_incident(graph, &adj, (igraph_integer_t) i, mode);
+      igraph_vector_append(vec, &adj);
+    }
+    igraph_vector_destroy(&adj);
+    IGRAPH_FINALLY_CLEAN(1);
+
+  } else {
+
+    igraph_vector_t adj;
+    igraph_bool_t *added;
+    long int j;
+    IGRAPH_VECTOR_INIT_FINALLY(&adj, 0);
+    added=igraph_Calloc(igraph_ecount(graph), igraph_bool_t);
+    if (added==0) {
+      IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, added);      
+    for (i=0; i<no_of_nodes; i++) {
+      igraph_incident(graph, &adj, (igraph_integer_t) i, IGRAPH_ALL);
+      for (j=0; j<igraph_vector_size(&adj); j++) {
+	if (!added[ (long int)VECTOR(adj)[j] ]) {
+	  igraph_vector_push_back(vec, VECTOR(adj)[j]);
+	  added[ (long int)VECTOR(adj)[j] ]+=1;
+	}
+      }
+    }
+    igraph_vector_destroy(&adj);
+    igraph_Free(added);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  eit->type=IGRAPH_EIT_VECTOR;
+  eit->pos=0;
+  eit->start=0;
+  eit->vec=vec;
+  eit->end=igraph_vector_size(eit->vec);
+
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+int igraph_i_eit_pairs(const igraph_t *graph, 
+		       igraph_es_t es, igraph_eit_t *eit) {
+  long int n=igraph_vector_size(es.data.path.ptr);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+
+  if (n % 2 != 0) {
+    IGRAPH_ERROR("Cannot create edge iterator from odd number of vertices",
+		 IGRAPH_EINVAL);
+  }
+  if (!igraph_vector_isininterval(es.data.path.ptr, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_EINVVID);
+  }
+
+  eit->type=IGRAPH_EIT_VECTOR;
+  eit->pos=0;
+  eit->start=0;
+  eit->end=n/2;
+  eit->vec=igraph_Calloc(1, igraph_vector_t);
+  if (eit->vec==0) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)eit->vec);
+  IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)eit->vec, n/2);
+  
+  for (i=0; i<igraph_vector_size(eit->vec); i++) {
+    long int from=(long int) VECTOR(*es.data.path.ptr)[2*i];
+    long int to=(long int) VECTOR(*es.data.path.ptr)[2*i+1];
+    igraph_integer_t eid;
+    IGRAPH_CHECK(igraph_get_eid(graph, &eid, (igraph_integer_t) from, 
+				(igraph_integer_t) to, es.data.path.mode, 
+				/*error=*/ 1));
+    VECTOR(*eit->vec)[i]=eid;
+  }
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+int igraph_i_eit_multipairs(const igraph_t *graph,
+			    igraph_es_t es, igraph_eit_t *eit) {
+  long int n=igraph_vector_size(es.data.path.ptr);
+  long int no_of_nodes=igraph_vcount(graph);
+  
+  if (n % 2 != 0) {
+    IGRAPH_ERROR("Cannot create edge iterator from odd number of vertices",
+		 IGRAPH_EINVAL);
+  }
+  if (!igraph_vector_isininterval(es.data.path.ptr, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_EINVVID);
+  }
+
+  eit->type=IGRAPH_EIT_VECTOR;
+  eit->pos=0;
+  eit->start=0;
+  eit->end=n/2;
+  eit->vec=igraph_Calloc(1, igraph_vector_t);
+  if (eit->vec==0) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)eit->vec);
+  IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)eit->vec, n/2);
+  
+  IGRAPH_CHECK(igraph_get_eids_multi(graph, (igraph_vector_t *) eit->vec,
+				     /*pairs=*/ es.data.path.ptr, /*path=*/ 0, 
+				     es.data.path.mode, /*error=*/ 1));
+  
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+int igraph_i_eit_path(const igraph_t *graph, 
+		      igraph_es_t es, igraph_eit_t *eit) {
+  long int n=igraph_vector_size(es.data.path.ptr);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, len;
+
+  if (!igraph_vector_isininterval(es.data.path.ptr, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_EINVVID);
+  }
+  
+  if (n<=1) { 
+    len=0;
+  } else {
+    len=n-1;
+  }
+
+  eit->type=IGRAPH_EIT_VECTOR;
+  eit->pos=0;
+  eit->start=0;
+  eit->end=len;
+  eit->vec=igraph_Calloc(1, igraph_vector_t);
+  if (eit->vec==0) {
+    IGRAPH_ERROR("Cannot create edge iterator", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, (igraph_vector_t*)eit->vec);
+
+  IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t *)eit->vec, len);
+  
+  for (i=0; i<len; i++) {
+    long int from=(long int) VECTOR(*es.data.path.ptr)[i];
+    long int to=(long int) VECTOR(*es.data.path.ptr)[i+1];
+    igraph_integer_t eid;
+    IGRAPH_CHECK(igraph_get_eid(graph, &eid, (igraph_integer_t) from, 
+				(igraph_integer_t) to, es.data.path.mode, 
+				/*error=*/ 1));
+    VECTOR(*eit->vec)[i]=eid;
+  }
+
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_eit_create
+ * \brief Creates an edge iterator from an edge selector.
+ * 
+ * </para><para>
+ * This function creates an edge iterator based on an edge selector
+ * and a graph. 
+ * 
+ * </para><para>
+ * The same edge selector can be used to create many edge iterators,
+ * also for different graphs.
+ * 
+ * \param graph An \type igraph_t object for which the edge selector
+ *        will be instantiated.
+ * \param es The edge selector to instantiate.
+ * \param eit Pointer to an uninitialized edge iterator. 
+ * \return Error code.
+ * \sa \ref igraph_eit_destroy()
+ * 
+ * Time complexity: depends on the type of the edge selector. For edge
+ * selectors created by \ref igraph_es_all(), \ref igraph_es_none(),
+ * \ref igraph_es_1(), igraph_es_vector(), igraph_es_seq() it is
+ * O(1). For \ref igraph_es_incident() it is O(d) where d is the number of
+ * incident edges of the vertex.
+ */
+
+int igraph_eit_create(const igraph_t *graph, 
+		      igraph_es_t es, igraph_eit_t *eit) {
+  switch (es.type) {
+  case IGRAPH_ES_ALL:
+    eit->type=IGRAPH_EIT_SEQ;
+    eit->pos=0;
+    eit->start=0;
+    eit->end=igraph_ecount(graph);
+    break;
+  case IGRAPH_ES_ALLFROM:
+    IGRAPH_CHECK(igraph_i_eit_create_allfromto(graph, eit, IGRAPH_OUT));
+    break;
+  case IGRAPH_ES_ALLTO:
+    IGRAPH_CHECK(igraph_i_eit_create_allfromto(graph, eit, IGRAPH_IN));
+    break;
+  case IGRAPH_ES_INCIDENT:
+    eit->type=IGRAPH_EIT_VECTOR;
+    eit->pos=0;
+    eit->start=0;
+    eit->vec=igraph_Calloc(1, igraph_vector_t);
+    if (eit->vec == 0) {
+      IGRAPH_ERROR("Cannot create iterator", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, (igraph_vector_t*) eit->vec);
+    IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)eit->vec, 0);
+    IGRAPH_CHECK(igraph_incident(graph, (igraph_vector_t*)eit->vec, 
+				 es.data.incident.vid, es.data.incident.mode));
+    eit->end=igraph_vector_size(eit->vec);
+    IGRAPH_FINALLY_CLEAN(2);
+    break;
+  case IGRAPH_ES_NONE:
+    eit->type=IGRAPH_EIT_SEQ;
+    eit->pos=0;
+    eit->start=0;
+    eit->end=0;
+    break;
+  case IGRAPH_ES_1:
+    eit->type=IGRAPH_EIT_SEQ;
+    eit->pos=es.data.eid;
+    eit->start=es.data.eid;
+    eit->end=es.data.eid+1;
+    if (eit->pos >= igraph_ecount(graph)) {
+      IGRAPH_ERROR("Cannot create iterator, invalid edge id", IGRAPH_EINVVID);
+    }
+    break;
+  case IGRAPH_ES_VECTOR:
+  case IGRAPH_ES_VECTORPTR:
+    eit->type=IGRAPH_EIT_VECTORPTR;
+    eit->pos=0;
+    eit->start=0;
+    eit->vec=es.data.vecptr;
+    eit->end=igraph_vector_size(eit->vec);
+    if (!igraph_vector_isininterval(eit->vec, 0, igraph_ecount(graph)-1)) {
+      IGRAPH_ERROR("Cannot create iterator, invalid edge id",IGRAPH_EINVVID);
+    }
+    break;
+  case IGRAPH_ES_SEQ:
+    eit->type=IGRAPH_EIT_SEQ;
+    eit->pos=es.data.seq.from;
+    eit->start=es.data.seq.from;
+    eit->end=es.data.seq.to;
+    break;
+  case IGRAPH_ES_PAIRS:
+    IGRAPH_CHECK(igraph_i_eit_pairs(graph, es, eit));
+    break;
+  case IGRAPH_ES_MULTIPAIRS:
+    IGRAPH_CHECK(igraph_i_eit_multipairs(graph, es, eit));
+    break;
+  case IGRAPH_ES_PATH:
+    IGRAPH_CHECK(igraph_i_eit_path(graph, es, eit));
+    break;
+  default:
+    IGRAPH_ERROR("Cannot create iterator, invalid selector", IGRAPH_EINVAL);
+    break;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_eit_destroy
+ * \brief Destroys an edge iterator.
+ * 
+ * \param eit Pointer to an edge iterator to destroy.
+ * \sa \ref igraph_eit_create()
+ * 
+ * Time complexity: operating system dependent, usually O(1).
+ */
+
+void igraph_eit_destroy(const igraph_eit_t *eit) {
+  switch (eit->type) {
+  case IGRAPH_EIT_SEQ:
+  case IGRAPH_EIT_VECTORPTR:
+    break;
+  case IGRAPH_EIT_VECTOR:
+    igraph_vector_destroy((igraph_vector_t*)eit->vec);
+    igraph_free((igraph_vector_t*)eit->vec);
+    break;
+  default:
+/*     IGRAPH_ERROR("Cannot destroy iterator, unknown type", IGRAPH_EINVAL); */
+    break;
+  }
+}
+
+int igraph_eit_as_vector(const igraph_eit_t *eit, igraph_vector_t *v) {
+
+  long int i;
+
+  IGRAPH_CHECK(igraph_vector_resize(v, IGRAPH_EIT_SIZE(*eit)));
+  
+  switch (eit->type) {
+  case IGRAPH_EIT_SEQ: 
+    for (i=0; i<IGRAPH_EIT_SIZE(*eit); i++) {
+      VECTOR(*v)[i] = eit->start+i;
+    }
+    break;
+  case IGRAPH_EIT_VECTOR:
+  case IGRAPH_EIT_VECTORPTR:
+    for (i=0; i<IGRAPH_EIT_SIZE(*eit); i++) {
+      VECTOR(*v)[i] = VECTOR(*eit->vec)[i];
+    }
+    break;
+  default:
+    IGRAPH_ERROR("Cannot convert to vector, unknown iterator type", 
+		 IGRAPH_EINVAL);
+    break;
+  }
+  
+  return 0;
+}
diff --git a/src/lad.c b/src/lad.c
new file mode 100644
index 0000000..bc2b1e6
--- /dev/null
+++ b/src/lad.c
@@ -0,0 +1,1568 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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
+
+*/
+
+/*
+  The contents of this file was originally taken from the LAD 
+  homepage: http://liris.cnrs.fr/csolnon/LAD.html and then 
+  modified to fit better into igraph.
+
+  Unfortunately LAD seems to have no version numbers. The files
+  were apparently last changed on the 29th of June, 2010.
+  
+  The original copyright message follows here. The CeCILL-B V1 license
+  is GPL compatible, because instead of V1, one can freely choose to 
+  use V2, and V2 is explicitly GPL compatible.
+*/
+
+/* This software has been written by Christine Solnon.
+   It is distributed under the CeCILL-B FREE SOFTWARE LICENSE
+   see http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html 
+   for more details
+*/
+
+/* Several modifications had to be made to the original LAD implementation
+   to make it compile with non-C99-compliant compilers such as MSVC. In
+   particular, I had to remove all the variable-sized arrays.
+   -- Tamas Nepusz, 11 July 2013
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <limits.h>
+
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_vector.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_memory.h"
+#include "igraph_matrix.h"
+#include "igraph_interrupt_internal.h"
+
+/* define boolean type as char */
+#define true 1
+#define false 0
+#define bool char
+
+/* helper to allocate an array of given size */
+#define ALLOC_ARRAY(VAR, SIZE, TYPE) { \
+  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);  \
+}
+
+/* ---------------------------------------------------------*/
+/* Coming from graph.c                                      */
+/* ---------------------------------------------------------*/
+
+typedef struct{
+  long int nbVertices; /* Number of vertices */
+  igraph_vector_t nbSucc;
+  igraph_adjlist_t succ;
+  igraph_matrix_char_t isEdge;
+} Tgraph;
+
+int igraph_i_lad_createGraph(const igraph_t *igraph, Tgraph* graph) {
+  long int i, j, n;
+  long int no_of_nodes=igraph_vcount(igraph);
+  igraph_vector_int_t *neis;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->nbSucc, no_of_nodes);
+  IGRAPH_CHECK(igraph_degree(igraph, &graph->nbSucc, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS));
+  
+  graph->nbVertices = no_of_nodes;
+
+  IGRAPH_CHECK(igraph_adjlist_init(igraph, &graph->succ, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &graph->succ);
+  IGRAPH_CHECK(igraph_matrix_char_init(&graph->isEdge, 
+				       no_of_nodes, no_of_nodes));
+  IGRAPH_FINALLY(igraph_matrix_char_destroy, &graph->isEdge);
+	
+  for (i=0; i<no_of_nodes; i++) {
+    neis=igraph_adjlist_get(&graph->succ, i);
+    n=igraph_vector_int_size(neis);
+    for (j=0; j<n; j++) {
+      int v=(int)VECTOR(*neis)[j];
+      if (MATRIX(graph->isEdge, i, v)) {
+	IGRAPH_ERROR("LAD functions only work on simple graphs, "
+		     "simplify your graph", IGRAPH_EINVAL);
+      }
+      MATRIX(graph->isEdge, i, v) = 1;
+    }
+  }
+
+  return 0;
+}
+
+/* ---------------------------------------------------------*/
+/* Coming from domains.c                                    */
+/* ---------------------------------------------------------*/
+
+typedef struct{
+  igraph_vector_int_t nbVal;    /* nbVal[u] = number of values in D[u] */
+  igraph_vector_int_t firstVal; /* firstVal[u] = pos in val of the
+				   first value of D[u] */
+  igraph_vector_int_t val;      /* val[firstVal[u]..firstVal[u]+nbVal[u]-1] = 
+				   values of D[u] */
+  igraph_matrix_int_t posInVal; 
+  /* If v in D[u] then firstVal[u] <= posInVal[u][v] < firstVal[u]+nbVal[u] 
+     and val[posInVal[u][v]] = v
+     otherwise posInVal[u][v] >= firstVal[u]+nbVal[u] */
+  int valSize;    /* size of val */
+  igraph_matrix_int_t firstMatch; 
+  /* firstMatch[u][v] = pos in match of the first vertex 
+     of the covering matching of G_(u, v) */
+  igraph_vector_int_t matching; 
+  /* matching[firstMatch[u][v]..firstMatch[u][v]+nbSucc[u]-1]
+     = covering matching of G_(u, v) */
+  int nextOutToFilter; /* position in toFilter of the next pattern node whose
+			  domain should be filtered (-1 if no domain to 
+			  filter) */
+  int lastInToFilter; /* position in toFilter of the last pattern node whose 
+			 domain should be filtered */
+  igraph_vector_int_t toFilter;  /* contain all pattern nodes whose 
+				    domain should be filtered */
+  igraph_vector_char_t markedToFilter;  /* markedToFilter[u]=true if u
+					   is in toFilter; false otherwise */
+  igraph_vector_int_t globalMatchingP; /* globalMatchingP[u] = node of Gt
+					  matched to u in globalAllDiff(Np) */
+  igraph_vector_int_t globalMatchingT; 
+  /* globalMatchingT[v] = node of Gp matched to v in globalAllDiff(Np)
+     or -1 if v is not matched */
+} Tdomain;
+
+bool igraph_i_lad_toFilterEmpty(Tdomain* D) {
+  /* return true if there is no more nodes in toFilter */
+  return (D->nextOutToFilter < 0);
+}
+
+void igraph_i_lad_resetToFilter(Tdomain *D) {
+  /* empty to filter and unmark the vertices that are marked to be filtered */
+  igraph_vector_char_null(&D->markedToFilter);
+  D->nextOutToFilter = -1;
+}
+
+
+int igraph_i_lad_nextToFilter(Tdomain* D, int size) {
+  /* precondition: emptyToFilter = false 
+     remove a node from toFilter (FIFO)
+     unmark this node and return it */
+  int u = VECTOR(D->toFilter)[D->nextOutToFilter];
+  VECTOR(D->markedToFilter)[u] = false;
+  if (D->nextOutToFilter == D->lastInToFilter) {
+    /* u was the last node in tofilter */
+    D->nextOutToFilter = -1;
+  } else if (D->nextOutToFilter == size-1) {
+    D->nextOutToFilter = 0;
+  } else {
+    D->nextOutToFilter++;
+  }
+  return u;
+}
+
+void igraph_i_lad_addToFilter(int u, Tdomain* D, int size) {
+  /* if u is not marked, then add it to toFilter and mark it */
+  if (VECTOR(D->markedToFilter)[u]) { return; }
+  VECTOR(D->markedToFilter)[u] = true;
+  if (D->nextOutToFilter < 0) {
+    D->lastInToFilter = 0;
+    D->nextOutToFilter = 0;
+  } else if (D->lastInToFilter == size-1) {
+    D->lastInToFilter = 0;
+  } else {
+    D->lastInToFilter++;
+  }
+  VECTOR(D->toFilter)[D->lastInToFilter] = u;
+}
+
+bool igraph_i_lad_isInD(int u, int v, Tdomain* D) {
+  /* returns true if v belongs to D(u); false otherwise */
+  return (MATRIX(D->posInVal, u, v) < 
+	  VECTOR(D->firstVal)[u] + VECTOR(D->nbVal)[u]);
+}
+
+int igraph_i_lad_augmentingPath(int u, Tdomain* D, int nbV, bool* result) {
+  /* return true if there exists an augmenting path starting from u and 
+     ending on a free vertex v in the bipartite directed graph G=(U,
+     V, E) such that U=pattern nodes, V=target nodes, and 
+     E={(u, v), v in D(u)} U {(v, u), D->globalMatchingP[u]=v}
+     update D-globalMatchingP and D->globalMatchingT consequently */
+  int *fifo, *pred;
+  bool *marked;
+  int nextIn = 0;
+  int nextOut = 0;
+  int i, v, v2, u2, j;
+
+  /* Allocate memory */
+  ALLOC_ARRAY(fifo, nbV, int);
+  ALLOC_ARRAY(pred, nbV, int);
+  ALLOC_ARRAY(marked, nbV, bool);
+
+  for (i=0; i < VECTOR(D->nbVal)[u]; i++) {
+    v = VECTOR(D->val)[ VECTOR(D->firstVal)[u]+i ];  /* v in D(u) */
+    if (VECTOR(D->globalMatchingT)[v] < 0) { 
+      /* v is free => augmenting path found */
+      VECTOR(D->globalMatchingP)[u]=v;
+      VECTOR(D->globalMatchingT)[v]=u;
+      *result = true;
+      goto cleanup;
+    }
+    /* v is not free => add it to fifo */
+    pred[v] = u;
+    fifo[nextIn++] = v;
+    marked[v] = true;
+  }
+  while (nextOut < nextIn) {
+    u2 = VECTOR(D->globalMatchingT)[fifo[nextOut++]];
+    for (i=0; i < VECTOR(D->nbVal)[u2]; i++) {
+      v = VECTOR(D->val)[ VECTOR(D->firstVal)[u2]+i ]; /* v in D(u2) */
+      if (VECTOR(D->globalMatchingT)[v] < 0) { 
+	/* v is free => augmenting path found */
+	j=0;
+	while (u2 != u) { /* update global matching wrt path */
+	  if (j>100) { IGRAPH_ERROR("LAD failed", IGRAPH_EINTERNAL); }
+	  j++;
+	  v2 = VECTOR(D->globalMatchingP)[u2];
+	  VECTOR(D->globalMatchingP)[u2]=v;
+	  VECTOR(D->globalMatchingT)[v]=u2;
+	  v = v2;
+	  u2 = pred[v];
+	}
+	VECTOR(D->globalMatchingP)[u]=v;
+	VECTOR(D->globalMatchingT)[v]=u;
+	*result = true;
+	goto cleanup;
+      }
+      if (!marked[v]) { /* v is not free and not marked => add it to fifo */
+	pred[v] = u2;
+	fifo[nextIn++] = v;
+	marked[v] = true;
+      }
+    }
+  }
+
+cleanup:
+  igraph_free(fifo);
+  igraph_free(pred);
+  igraph_free(marked);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+int igraph_i_lad_removeAllValuesButOne(int u, int v, Tdomain* D, Tgraph* Gp,
+					Tgraph* Gt, bool* result) {
+  /* remove all values but v from D(u) and add all successors of u in
+     toFilter return false if an inconsistency is detected wrt to
+     global all diff */
+  int j, oldPos, newPos;
+  igraph_vector_int_t *uneis=igraph_adjlist_get(&Gp->succ, u);
+  int n=(int) igraph_vector_int_size(uneis);
+  /* add all successors of u in toFilter */
+  for (j=0; j<n; j++) {
+    igraph_i_lad_addToFilter((int) VECTOR(*uneis)[j], D, 
+			     (int) (Gp->nbVertices));
+  }
+  /* remove all values but v from D[u] */
+  oldPos = MATRIX(D->posInVal, u, v);
+  newPos = VECTOR(D->firstVal)[u];
+  VECTOR(D->val)[oldPos] = VECTOR(D->val)[newPos];
+  VECTOR(D->val)[newPos] = v;
+  MATRIX(D->posInVal, u, VECTOR(D->val)[newPos]) = newPos;
+  MATRIX(D->posInVal, u, VECTOR(D->val)[oldPos]) = oldPos;
+  VECTOR(D->nbVal)[u] = 1;
+  /* update global matchings that support the global all different
+     constraint */
+  if (VECTOR(D->globalMatchingP)[u] != v) {
+    VECTOR(D->globalMatchingT)[ VECTOR(D->globalMatchingP)[u] ]=-1;
+    VECTOR(D->globalMatchingP)[u] = -1;
+    IGRAPH_CHECK(igraph_i_lad_augmentingPath(u, D, (int) (Gt->nbVertices), result));
+  } else {
+    *result = true;
+  }
+  return 0;
+}
+
+
+int igraph_i_lad_removeValue(int u, int v, Tdomain* D, Tgraph* Gp,
+			      Tgraph* Gt, bool* result) {
+  /* remove v from D(u) and add all successors of u in toFilter
+     return false if an inconsistency is detected wrt global all diff */
+  int j;
+  igraph_vector_int_t *uneis=igraph_adjlist_get(&Gp->succ, u);
+  int n=(int) igraph_vector_int_size(uneis);
+  int oldPos, newPos;
+
+  /* add all successors of u in toFilter */
+  for (j=0; j<n; j++) {
+    igraph_i_lad_addToFilter((int) VECTOR(*uneis)[j], D,
+			     (int) (Gp->nbVertices));
+  }
+  /* remove v from D[u] */
+  oldPos = MATRIX(D->posInVal, u, v);
+  VECTOR(D->nbVal)[u]--;
+  newPos = VECTOR(D->firstVal)[u] + VECTOR(D->nbVal)[u];
+  VECTOR(D->val)[oldPos] = VECTOR(D->val)[newPos];
+  VECTOR(D->val)[newPos] = v;
+  MATRIX(D->posInVal, u, VECTOR(D->val)[oldPos]) = oldPos;
+  MATRIX(D->posInVal, u, VECTOR(D->val)[newPos]) = newPos;
+  /* update global matchings that support the global all different
+     constraint */
+  if (VECTOR(D->globalMatchingP)[u] == v) {
+    VECTOR(D->globalMatchingP)[u] = -1;
+    VECTOR(D->globalMatchingT)[v] = -1;
+    IGRAPH_CHECK(igraph_i_lad_augmentingPath(u, D, (int) (Gt->nbVertices), result));
+  } else {
+    *result = true;
+  }
+  return 0;
+}
+
+
+int igraph_i_lad_matchVertices(int nb, igraph_vector_int_t* toBeMatched,
+			       bool induced, Tdomain* D, Tgraph* Gp,
+			       Tgraph* Gt, int *invalid) {
+  /* for each u in toBeMatched[0..nb-1], match u to
+     D->val[D->firstVal[u] and filter domains of other non matched
+     vertices wrt FC(Edges) and FC(diff) (this is not mandatory, as
+     LAD is stronger than FC(Edges) and GAC(allDiff) is stronger than
+     FC(diff), but this speeds up the solution process). 
+     return false if an inconsistency is detected by FC(Edges) or
+     FC(diff); true otherwise; */
+  int j, u, v, u2, oldNbVal;
+  igraph_vector_int_t *vneis;
+  bool result;
+
+  while (nb>0) {
+    u = VECTOR(*toBeMatched)[--nb];
+    v = VECTOR(D->val)[ VECTOR(D->firstVal)[u] ]; 
+    vneis = igraph_adjlist_get(&Gt->succ, v);
+    /* match u to v */
+    for (u2=0; u2<Gp->nbVertices; u2++) {
+      if (u != u2) {
+	oldNbVal = VECTOR(D->nbVal)[u2];
+	if (igraph_i_lad_isInD(u2, v, D)) {
+	  IGRAPH_CHECK(igraph_i_lad_removeValue(u2, v, D, Gp, Gt, &result));
+	  if (!result) {
+	    *invalid = 1 ; return 0;
+	  }
+	}
+	if (MATRIX(Gp->isEdge, u, u2)) { 
+	  /* remove from D[u2] vertices which are not adjacent to v */
+	  j = VECTOR(D->firstVal)[u2]; 
+	  while (j < VECTOR(D->firstVal)[u2] + VECTOR(D->nbVal)[u2]) {
+	    if (MATRIX(Gt->isEdge, v, VECTOR(D->val)[j])) { 
+	      j++; 
+	    } else {
+	      IGRAPH_CHECK(igraph_i_lad_removeValue(u2, VECTOR(D->val)[j], D, Gp, Gt, &result));
+	      if (!result) {
+		*invalid = 1; return 0;
+	      }
+	    }
+	  }
+	} else if (induced) {
+	  /* (u, u2) is not an edge => remove neighbors of v from D[u2] */
+	  if (VECTOR(D->nbVal)[u2] < VECTOR(Gt->nbSucc)[v]) {
+	    j = VECTOR(D->firstVal)[u2]; 
+	    while (j < VECTOR(D->firstVal)[u2] + VECTOR(D->nbVal)[u2]) {
+	      if (!MATRIX(Gt->isEdge, v, VECTOR(D->val)[j])) {
+		j++;
+	      } else {
+		IGRAPH_CHECK(igraph_i_lad_removeValue(u2, VECTOR(D->val)[j], D, Gp, Gt, &result));
+		if (!result) {
+		  *invalid = 1; return 0;
+	        }
+	      }
+	    }
+	  } else {
+	    for (j=0; j<VECTOR(Gt->nbSucc)[v]; j++) {
+	      if (igraph_i_lad_isInD(u2, (int) VECTOR(*vneis)[j], D)) {
+		IGRAPH_CHECK(igraph_i_lad_removeValue(u2, (int) VECTOR(*vneis)[j], D, Gp, Gt, &result));
+		if (!result) {
+		  *invalid = 1; return 0; 
+		}
+	      }
+	    }
+	  }
+	}
+	if (VECTOR(D->nbVal)[u2] == 0) {
+	  *invalid = 1; /* D[u2] is empty */
+	  return 0;
+	}
+	if ((VECTOR(D->nbVal)[u2] == 1) && (oldNbVal > 1)) { 
+	  VECTOR(*toBeMatched)[nb++]=u2; 
+	}
+      }			
+    }
+  }
+  *invalid = 0;
+  return 0;
+}
+
+
+bool igraph_i_lad_matchVertex(int u, bool induced, Tdomain* D, Tgraph* Gp, 
+			      Tgraph *Gt) {
+  int invalid;
+  /* match u to D->val[D->firstVal[u]] and filter domains of other non
+     matched vertices wrt FC(Edges) and FC(diff) (this is not
+     mandatory, as LAD is stronger than FC(Edges) and GAC(allDiff) 
+     is stronger than FC(diff), but this speeds up the solution process).
+     return false if an inconsistency is detected by FC(Edges) or
+     FC(diff); true otherwise; */
+  igraph_vector_int_t toBeMatched;
+  igraph_vector_int_init(&toBeMatched, Gp->nbVertices);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &toBeMatched);
+  VECTOR(toBeMatched)[0]=u;
+  igraph_i_lad_matchVertices(1, &toBeMatched, induced, D, Gp, Gt, 
+			     &invalid);
+  igraph_vector_int_destroy(&toBeMatched);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return invalid ? false : true;
+}
+
+
+int igraph_i_lad_qcompare (void const *a, void const *b) {
+  /* function used by the qsort function */
+  int pa = *((int*)a) - *((int*)b);
+  return pa;
+}
+
+bool igraph_i_lad_compare(int size_mu, int* mu, int size_mv, int* mv) {
+  /* return true if for every element u of mu there exists
+     a different element v of mv such that u <= v; 
+     return false otherwise */
+  int i, j;
+  qsort(mu, (size_t) size_mu, sizeof(int), igraph_i_lad_qcompare);
+  qsort(mv, (size_t) size_mv, sizeof(int), igraph_i_lad_qcompare);
+  i = size_mv-1;
+  for (j=size_mu-1; j>=0; j--) {
+    if (mu[j]>mv[i]) { return false; }
+    i--;
+  }
+  return true;
+}
+
+int igraph_i_lad_initDomains(bool initialDomains, 
+			     igraph_vector_ptr_t *domains, Tdomain* D,
+			     Tgraph* Gp, Tgraph* Gt, int *empty) {
+  /* for every pattern node u, initialize D(u) with every vertex v 
+     such that for every neighbor u' of u there exists a different 
+     neighbor v' of v such that degree(u) <= degree(v)
+     if initialDomains, then filter initial domains wrt
+     compatibilities given in file 
+     return false if a domain is empty and true otherwise */
+  int *val;
+  bool *dom;
+  int *mu, *mv;
+  int matchingSize, u, v, i, j;
+  igraph_vector_t *vec;
+  igraph_vector_t *Gp_uneis;
+  igraph_vector_t *Gt_vneis;
+
+  val = igraph_Calloc(Gp->nbVertices*Gt->nbVertices, int);
+  if (val == 0) {
+    IGRAPH_ERROR("cannot allocated 'val' array in igraph_i_lad_initDomains", IGRAPH_ENOMEM);
+  }
+
+  dom = igraph_Calloc(Gt->nbVertices, bool);
+  if (dom == 0) {
+    igraph_free(val);
+    IGRAPH_ERROR("cannot allocated 'dom' array in igraph_i_lad_initDomains", IGRAPH_ENOMEM);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_int_init(&D->globalMatchingP, Gp->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->globalMatchingP);
+  igraph_vector_int_fill(&D->globalMatchingP, -1L);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&D->globalMatchingT, Gt->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->globalMatchingT);
+  igraph_vector_int_fill(&D->globalMatchingT, -1L);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&D->nbVal, Gp->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->nbVal);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&D->firstVal, Gp->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->firstVal);
+
+  IGRAPH_CHECK(igraph_matrix_int_init(&D->posInVal, 
+				      Gp->nbVertices, Gt->nbVertices));
+  IGRAPH_FINALLY(igraph_matrix_int_destroy, &D->posInVal);
+
+  IGRAPH_CHECK(igraph_matrix_int_init(&D->firstMatch,
+				      Gp->nbVertices, Gt->nbVertices));
+  IGRAPH_FINALLY(igraph_matrix_int_destroy, &D->firstMatch);
+
+  IGRAPH_CHECK(igraph_vector_char_init(&D->markedToFilter, Gp->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &D->markedToFilter);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&D->toFilter, Gp->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->toFilter);
+
+  D->valSize = 0;
+  matchingSize = 0;
+	
+  for (u=0; u<Gp->nbVertices; u++) {
+    igraph_vector_int_t *Gp_uneis=igraph_adjlist_get(&Gp->succ, u);
+    if (initialDomains) { 
+      /* read the list of target vertices which are compatible with u */
+      vec=VECTOR(*domains)[u];
+      i=(int) igraph_vector_size(vec);
+      memset(dom, false, sizeof(bool)*(size_t)(Gt->nbVertices));
+      for (j=0; j<i; j++) {
+	v=(int) VECTOR(*vec)[j];
+	dom[v] = true;
+      }
+    }
+    VECTOR(D->markedToFilter)[u] = true;
+    VECTOR(D->toFilter)[u] = u;
+    VECTOR(D->nbVal)[u] = 0;
+    VECTOR(D->firstVal)[u] = D->valSize;
+    for (v=0; v<Gt->nbVertices; v++) {
+      igraph_vector_int_t *Gt_vneis=igraph_adjlist_get(&Gt->succ, v);
+      if ((initialDomains) && (!dom[v])) { /* v not in D(u) */
+	MATRIX(D->posInVal, u, v) = (int) (VECTOR(D->firstVal)[u] + 
+					   Gt->nbVertices);
+      } else {
+	MATRIX(D->firstMatch, u, v) = matchingSize;
+	matchingSize += VECTOR(Gp->nbSucc)[u];
+	if (VECTOR(Gp->nbSucc)[u] <= VECTOR(Gt->nbSucc)[v]) {
+	  mu = igraph_Calloc((long int) VECTOR(Gp->nbSucc)[u], int);
+	  if (mu == 0) {
+	    igraph_free(val); igraph_free(dom);
+	    IGRAPH_ERROR("cannot allocate 'mu' array in igraph_i_lad_initDomains", IGRAPH_ENOMEM);
+	  }
+	  mv = igraph_Calloc((long int) VECTOR(Gt->nbSucc)[v], int);
+	  if (mv == 0) {
+	    igraph_free(mu); igraph_free(val); igraph_free(dom);
+	    IGRAPH_ERROR("cannot allocate 'mv' array in igraph_i_lad_initDomains", IGRAPH_ENOMEM);
+	  }
+	  for (i=0; i<VECTOR(Gp->nbSucc)[u]; i++) { 
+	    mu[i]=(int) VECTOR(Gp->nbSucc)[(long int) VECTOR(*Gp_uneis)[i]];
+	  }
+	  for (i=0; i<VECTOR(Gt->nbSucc)[v]; i++) { 
+	    mv[i]=(int) VECTOR(Gt->nbSucc)[(long int) VECTOR(*Gt_vneis)[i]];
+	  }
+	  if (igraph_i_lad_compare((int) VECTOR(Gp->nbSucc)[u], mu, 
+				   (int) VECTOR(Gt->nbSucc)[v], mv)==1) {
+	    val[D->valSize] = v;
+	    VECTOR(D->nbVal)[u]++;
+	    MATRIX(D->posInVal, u, v) = D->valSize++;
+	  } else {  /* v not in D(u) */
+	    MATRIX(D->posInVal, u, v) = 
+	      (int)(VECTOR(D->firstVal)[u] + Gt->nbVertices);
+	  }
+	  igraph_free(mu); mu = 0;
+	  igraph_free(mv); mv = 0;
+	} else {  /* v not in D(u) */
+	  MATRIX(D->posInVal, u, v) = 
+	    (int) (VECTOR(D->firstVal)[u] + Gt->nbVertices);
+	}
+      }
+    }
+    if (VECTOR(D->nbVal)[u] == 0) { 
+      *empty = 1;  /* empty domain */
+      igraph_free(val);
+      igraph_free(dom);
+      return 0;
+    }
+  }
+  IGRAPH_CHECK(igraph_vector_int_init(&D->val, D->valSize));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->val);
+  for (i=0; i<D->valSize; i++) { VECTOR(D->val)[i] = val[i]; }
+
+  IGRAPH_CHECK(igraph_vector_int_init(&D->matching, matchingSize));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &D->matching);
+  igraph_vector_int_fill(&D->matching, -1);
+
+  D->nextOutToFilter = 0;
+  D->lastInToFilter = (int) (Gp->nbVertices-1);
+  *empty=0;
+
+  igraph_free(val);
+  igraph_free(dom);
+  return 0;
+}
+
+/* ---------------------------------------------------------*/
+/* Coming from allDiff.c                                    */
+/* ---------------------------------------------------------*/
+
+#define white 0
+#define grey 1
+#define black 2
+#define toBeDeleted 3
+#define deleted 4
+
+void igraph_i_lad_addToDelete(int u, int* list, int* nb, int* marked) {
+  if (marked[u]<toBeDeleted) {
+    list[(*nb)++]=u;
+    marked[u]=toBeDeleted; 
+  }
+}
+
+int igraph_i_lad_updateMatching(int sizeOfU, int sizeOfV, 
+				igraph_vector_int_t *degree, 
+				igraph_vector_int_t *firstAdj, 
+				igraph_vector_int_t *adj, 
+				igraph_vector_int_t * matchedWithU, 
+				int *invalid) {
+  /* input:
+     sizeOfU = number of vertices in U
+     sizeOfV = number of vertices in V
+     degree[u] = number of vertices of V which are adjacent to u
+     firstAdj[u] = pos in adj of the first vertex of V adjacent to u
+     adj[firstAdj[u]..firstAdj[u]+sizeOfU[u]-1] = vertices of V adjacent to u
+     
+     input/output:
+     matchedWithU[u] = vertex of V matched with u
+	
+     returns true if there exists a matching that covers U, i.e., if
+     for every u in 0..nbU-1, there exists a different v in 0..nb-1
+     such that v is adjacent to u; returns false otherwise */
+	
+  int *matchedWithV; /* matchedWithV[matchedWithU[u]]=u */
+  int *nbPred; /* nbPred[i] = nb of predecessors of the ith
+		  vertex of V in the DAG */
+  int *pred; /* pred[i][j] = jth predecessor the ith
+		 vertex of V in the DAG */
+  int *nbSucc; /* nbSucc[i] = nb of successors of the ith
+		  vertex of U in the DAG */
+  int *succ; /* succ[i][j] = jth successor of the ith
+		 vertex of U in the DAG */
+  int *listV, *listU, *listDV, *listDU;
+  int nbV, nbU, nbDV, nbDU;
+  int i, j, k, stop, u, v, w;
+  int *markedV, *markedU;
+  /* markedX[i]=white if X[i] is not in the DAG
+     markedX[i]=grey if X[i] has been added to the DAG, but not its successors
+     markedX[i]=black if X[i] and its successors have been added to the DAG
+     markedX[i]=toBeDeleted if X[i] must be deleted from the DAG
+     markedX[i]=deleted if X[i] has been deleted from the DAG */
+  int nbUnmatched = 0; /* number of vertices of U that are not matched */
+  int *unmatched;      /* vertices of U that are not matched */
+  int *posInUnmatched; /* unmatched[posInUnmatched[u]]=u */
+  igraph_vector_int_t path;
+
+  if (sizeOfU>sizeOfV) {
+    *invalid = 1; /* trivial case of infeasibility */
+    return 0; 
+  }
+	
+  ALLOC_ARRAY(matchedWithV, sizeOfV, int);
+  ALLOC_ARRAY(nbPred, sizeOfV, int);
+  ALLOC_ARRAY(pred, sizeOfV*sizeOfU, int);
+  ALLOC_ARRAY(nbSucc, sizeOfU, int);
+  ALLOC_ARRAY(succ, sizeOfU*sizeOfV, int);
+  ALLOC_ARRAY(listV, sizeOfV, int);
+  ALLOC_ARRAY(listU, sizeOfU, int);
+  ALLOC_ARRAY(listDV, sizeOfV, int);
+  ALLOC_ARRAY(listDU, sizeOfU, int);
+  ALLOC_ARRAY(markedV, sizeOfV, int);
+  ALLOC_ARRAY(markedU, sizeOfU, int);
+  ALLOC_ARRAY(unmatched, sizeOfU, int);
+  ALLOC_ARRAY(posInUnmatched, sizeOfU, int);
+
+  IGRAPH_CHECK(igraph_vector_int_init(&path, 0));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &path);
+
+  /* initialize matchedWithV and unmatched */
+  memset(matchedWithV, -1, (size_t)sizeOfV*sizeof(int));
+  for (u=0; u<sizeOfU; u++) {
+    if (VECTOR(*matchedWithU)[u] >= 0) {
+      matchedWithV[VECTOR(*matchedWithU)[u]]=u;
+    } else {
+      posInUnmatched[u]=nbUnmatched;
+      unmatched[nbUnmatched++]=u;
+    }
+  }
+  /* try to match unmatched vertices of U with free vertices of V */
+  j=0;
+  while (j<nbUnmatched) {
+    u = unmatched[j];
+    for (i=VECTOR(*firstAdj)[u]; 
+	 ((i < VECTOR(*firstAdj)[u] + VECTOR(*degree)[u]) && 
+	  (matchedWithV[VECTOR(*adj)[i]] >= 0)); i++) { }
+    if (i == VECTOR(*firstAdj)[u] + VECTOR(*degree)[u]) { 
+      j++; /* no free vertex for u */
+    } else {
+      v=VECTOR(*adj)[i]; /* v is free => match u with v */
+      VECTOR(*matchedWithU)[u]=v; 
+      matchedWithV[v]=u; 
+      unmatched[j]=unmatched[--nbUnmatched];
+      posInUnmatched[unmatched[j]]=j;
+    }
+  }
+	
+  while (nbUnmatched > 0) { 
+    /* Try to increase the number of matched vertices */
+    /* step 1 : build the DAG */
+    memset(markedU, white, (size_t) sizeOfU*sizeof(int));
+    memset(nbSucc, 0, (size_t) sizeOfU*sizeof(int));
+    memset(markedV, white, (size_t) sizeOfV*sizeof(int));
+    memset(nbPred, 0, (size_t) sizeOfV*sizeof(int));
+    /* first layer of the DAG from the free nodes of U */
+    nbV=0;
+    for (j=0; j<nbUnmatched; j++) {
+      u=unmatched[j]; /* u is a free node of U */
+      markedU[u]=black;
+      for (i = VECTOR(*firstAdj)[u]; 
+	   i < VECTOR(*firstAdj)[u] + VECTOR(*degree)[u]; i++) {
+	v=VECTOR(*adj)[i]; /* add edge (u, v) to the DAG */
+	pred[v*sizeOfU + (nbPred[v]++)]=u;
+	succ[u*sizeOfV + (nbSucc[u]++)]=v;
+	if (markedV[v]==white) { /* first time v is added to the DAG*/
+	  markedV[v]=grey; 
+	  listV[nbV++]=v;
+	}
+      } 
+    }
+    stop=0;
+    while ((stop==0) && (nbV>0)) {
+      /* build next layer from nodes of V to nodes of U */
+      nbU=0;
+      for (i=0; i<nbV; i++) {
+	v=listV[i];
+	markedV[v]=black;
+	u=matchedWithV[v]; 
+	if (markedU[u]==white) { /* edge (v, u) belongs to the DAG */
+	  markedU[u]=grey; 
+	  listU[nbU++]=u;
+	}
+      }
+      /* build next layer from nodes of U to nodes of V */
+      nbV=0;
+      for (j=0; j<nbU; j++) {
+	u=listU[j];
+	markedU[u]=black;
+	for (i = VECTOR(*firstAdj)[u]; 
+	     i < VECTOR(*firstAdj)[u] + VECTOR(*degree)[u];i++) {
+	  v=VECTOR(*adj)[i]; 
+	  if (markedV[v]!=black) { /* add edge (u, v) to the DAG */
+	    pred[v*sizeOfU + (nbPred[v]++)]=u;
+	    succ[u*sizeOfV + (nbSucc[u]++)]=v;
+	    if (markedV[v]==white) { /* first time v is added to the DAG */
+	      markedV[v]=grey; 
+	      listV[nbV++]=v;
+	    }
+	    if (matchedWithV[v]==-1) { /* we have found a free node ! */
+	      stop=1; 
+	    }
+	  }
+	}
+      }
+    }
+    if (nbV==0) {
+      *invalid = 1;
+      /* I know it's ugly. */
+      goto cleanup;
+    }
+		
+    /* step 2: look for augmenting paths */
+    for (k=0; k<nbV; k++) { 
+      v=listV[k];
+      if ((matchedWithV[v]==-1) && (nbPred[v]>0)) {
+	/* v is the final node of an augmenting path */
+	IGRAPH_CHECK(igraph_vector_int_resize(&path, 1));
+	VECTOR(path)[0]=v;
+	nbDV=0; 
+	nbDU=0;
+	igraph_i_lad_addToDelete(v, listDV, &nbDV, markedV);
+	do{
+	  u=pred[v*sizeOfU + 0]; /* (u, v) belongs to the augmenting path */
+	  IGRAPH_CHECK(igraph_vector_int_push_back(&path, u));
+	  igraph_i_lad_addToDelete(u, listDU, &nbDU, markedU);
+	  if (VECTOR(*matchedWithU)[u]!=-1) {
+	    /* u is not the initial node of the augmenting path */
+	    v=VECTOR(*matchedWithU)[u]; /* (v, u) belongs to the
+					   augmenting path */
+	    IGRAPH_CHECK(igraph_vector_int_push_back(&path, v));
+	    igraph_i_lad_addToDelete(v, listDV, &nbDV, markedV);
+	  }
+	} while (VECTOR(*matchedWithU)[u]!=-1);
+				
+	/* delete nodes of listDV and listDU */
+	while ((nbDV>0) || (nbDU>0)) {
+	  while (nbDV>0) { /* delete v */
+	    v=listDV[--nbDV]; markedV[v]=deleted;
+	    u=matchedWithV[v];
+	    if (u!=-1) { 
+	      igraph_i_lad_addToDelete(u, listDU, &nbDU, markedU); 
+	    }
+	    for (i=0; i<nbPred[v]; i++) {
+	      u=pred[v*sizeOfU + i]; /* delete edge (u, v) */
+	      for (j=0; ((j<nbSucc[u]) && (v!=succ[u*sizeOfV + j])); j++) { }
+	      succ[u*sizeOfV + j]=succ[u*sizeOfV + (--nbSucc[u])];
+	      if (nbSucc[u]==0) {
+		igraph_i_lad_addToDelete(u, listDU, &nbDU, markedU);
+	      }
+	    }
+	  }
+	  while (nbDU>0) { /* delete u */
+	    u = listDU[--nbDU]; markedU[u]=deleted;
+	    v=VECTOR(*matchedWithU)[u];
+	    if (v!=-1) { 
+	      igraph_i_lad_addToDelete(v, listDV, &nbDV, markedV);
+	    }
+	    j=0;
+	    for (i=0; i<nbSucc[u]; i++) { /* delete edge (u, v) */
+	      v=succ[u*sizeOfV + i];
+	      for (j=0; ((j<nbPred[v]) && (u!=pred[v*sizeOfU + j])); j++) { }
+	      pred[v*sizeOfU + j]=pred[v*sizeOfU + (--nbPred[v])];
+	      if (nbPred[v]==0) {
+		igraph_i_lad_addToDelete(v, listDV, &nbDV, markedV);
+	      }
+	    }
+	  }
+	}
+	/* Remove the last node of the augmenting path from the set of
+	   unmatched vertices */
+	u=VECTOR(path)[igraph_vector_int_size(&path)-1]; 
+	i=posInUnmatched[u];
+	unmatched[i]=unmatched[--nbUnmatched];
+	posInUnmatched[unmatched[i]]=i;
+	/* Update the matching wrt the augmenting path */
+	while (igraph_vector_int_size(&path)>1) {
+	  u=igraph_vector_int_pop_back(&path);
+	  v=igraph_vector_int_pop_back(&path);
+	  w=matchedWithV[v]; /* match v with u instead of v with w */
+	  VECTOR(*matchedWithU)[u]=v; 
+	  matchedWithV[v]=u;
+	}
+      }
+    }
+  }
+  *invalid=0;
+
+cleanup:
+  /* Free the allocated arrays */
+  igraph_vector_int_destroy(&path);
+  igraph_free(posInUnmatched);
+  igraph_free(unmatched);
+  igraph_free(markedU);
+  igraph_free(markedV);
+  igraph_free(listDU);
+  igraph_free(listDV);
+  igraph_free(listU);
+  igraph_free(listV);
+  igraph_free(succ);
+  igraph_free(nbSucc);
+  igraph_free(pred);
+  igraph_free(nbPred);
+  igraph_free(matchedWithV);
+  IGRAPH_FINALLY_CLEAN(14);
+  return 0;
+}
+
+void igraph_i_lad_DFS(int nbU, int nbV, int u, bool* marked, int* nbSucc, 
+		      int* succ, igraph_vector_int_t * matchedWithU,
+		      int* order, int* nb) {
+  /* perform a depth first search, starting from u, in the bipartite
+     graph Go=(U, V, E) such that 
+     U = vertices of Gp
+     V = vertices of Gt
+     E = { (u, matchedWithU[u]) / u is a vertex of Gp } U
+         { (v, u) / v is a vertex of D[u] which is not matched to v}
+
+     Given a vertex v of Gt, nbSucc[v]=number of successors of v and
+     succ[v]=list of successors of v. order[nb^out+1..nb^in] contains
+     the vertices discovered by the DFS */
+  int i;
+  int v=VECTOR(*matchedWithU)[u]; /* the only one predecessor of v is u */
+  marked[u]=true;
+  if (v >= 0) {
+    for (i=0; i<nbSucc[v]; i++) {
+      if (!marked[succ[v*nbU + i]]) {
+        igraph_i_lad_DFS(nbU, nbV, succ[v*nbU + i], marked, nbSucc, succ,
+			 matchedWithU, order, nb);
+      }
+    }
+  }
+  /* we have finished with u => number it */
+  order[*nb]=u; (*nb)--;
+}
+
+int igraph_i_lad_SCC(int nbU, int nbV, int* numV, int* numU, 
+		      int* nbSucc, int* succ,
+		      int* nbPred, int* pred,
+		      igraph_vector_int_t * matchedWithU,
+		      igraph_vector_int_t * matchedWithV) {
+  /* postrelation: numV[v]==numU[u] iff they belong to the same
+     strongly connected component in the bipartite graph Go=(U, V, E)
+     such that 
+     U = vertices of Gp
+     V = vertices of Gt
+     E = { (u, matchedWithU[u]) / u is a vertex of Gp } U
+         { (v, u) / v is a vertex of D[u] which is not matched to v}
+
+     Given a vertex v of Gt, nbSucc[v]=number of sucessors of v and
+     succ[v]=list of successors of v */
+  int *order;
+  bool *marked;
+  int *fifo;
+  int u, v, i, j, k, nbSCC, nb;
+
+  /* Allocate memory */
+  ALLOC_ARRAY(order, nbU, int);
+  ALLOC_ARRAY(marked, nbU, bool);
+  ALLOC_ARRAY(fifo, nbV, int);
+
+  /* Order vertices of Gp wrt DFS */
+  nb=nbU-1;
+  for (u=0; u<nbU; u++) {
+    if (!marked[u]) {
+      igraph_i_lad_DFS(nbU, nbV, u, marked, nbSucc, succ, matchedWithU, 
+		       order, &nb);
+    }
+  }
+	
+  /* traversal starting from order[0], then order[1], ... */
+  nbSCC=0;
+  memset(numU, -1, (size_t) nbU*sizeof(int));
+  memset(numV, -1, (size_t) nbV*sizeof(int));
+  for (i=0; i<nbU; i++) {
+    u=order[i];
+    v=VECTOR(*matchedWithU)[u];
+    if (v == -1) {
+      continue;
+    }
+    if (numV[v]==-1) { /* v belongs to a new SCC */
+      nbSCC++;
+      k=1; fifo[0]=v;
+      numV[v]=nbSCC;
+      while (k>0) {
+	v=fifo[--k];
+	u=VECTOR(*matchedWithV)[v];
+	if (u!=-1) {
+	  numU[u]=nbSCC;
+	  for (j=0; j<nbPred[u]; j++) {
+	    v=pred[u*nbV+j];
+	    if (numV[v]==-1) {
+	      numV[v]=nbSCC;
+	      fifo[k++]=v;
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  /* Free memory */
+  igraph_free(fifo);
+  igraph_free(marked);
+  igraph_free(order);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+
+int igraph_i_lad_ensureGACallDiff(bool induced, Tgraph* Gp, Tgraph* Gt, 
+				  Tdomain* D, int *invalid) {
+  /* precondition: D->globalMatchingP is an all different matching of
+     the pattern vertices 
+     postcondition: filter domains wrt GAC(allDiff)
+     return false if an inconsistency is detected; true otherwise
+	
+     Build the bipartite directed graph Go=(U, V, E) such that
+     E = { (u, v) / u is a vertex of Gp which is matched to v (i.e.,
+            v=D->globalMatchingP[u])} U 
+         { (v, u) / v is a vertex of Gt which is in D(u) but is not
+	   matched to u} */
+  int *nbPred;                 /* nbPred[u] = nb of predecessors of u in Go */
+  int *pred;                                /* pred[u][i] = ith
+					       predecessor of u in Go */
+  int *nbSucc;                 /* nbSucc[v] = nb of successors of v in Go */
+  int *succ;                                /* succ[v][i] = ith
+					       successor of v in Go */
+  int u, v, i, w, oldNbVal, nbToMatch;  
+  int *numV, *numU;
+  igraph_vector_int_t toMatch;
+  bool *used;
+  int *list;
+  int nb=0;
+  bool result;
+
+  /* Allocate memory */
+  ALLOC_ARRAY(nbPred, Gp->nbVertices, int);
+  ALLOC_ARRAY(pred, Gp->nbVertices*Gt->nbVertices, int);
+  ALLOC_ARRAY(nbSucc, Gt->nbVertices, int);
+  ALLOC_ARRAY(succ, Gt->nbVertices*Gp->nbVertices, int);
+  ALLOC_ARRAY(numV, Gt->nbVertices, int);
+  ALLOC_ARRAY(numU, Gp->nbVertices, int);
+  ALLOC_ARRAY(used, Gp->nbVertices*Gt->nbVertices, bool);
+  ALLOC_ARRAY(list, Gt->nbVertices, int);
+  IGRAPH_CHECK(igraph_vector_int_init(&toMatch, Gp->nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &toMatch);
+
+  for (u=0; u<Gp->nbVertices; u++) {
+    for (i=0; i < VECTOR(D->nbVal)[u]; i++) {
+      v=VECTOR(D->val)[ VECTOR(D->firstVal)[u]+i ]; /* v in D(u) */
+      used[u*Gt->nbVertices+v]=false;
+      if (v != VECTOR(D->globalMatchingP)[u]) {
+	pred[u*Gt->nbVertices + (nbPred[u]++)]=v; 
+	succ[v*Gp->nbVertices + (nbSucc[v]++)]=u; 
+      }
+    }
+  }
+	
+  /* mark as used all edges of paths starting from free vertices */
+  for (v=0; v<Gt->nbVertices; v++) {
+    if (VECTOR(D->globalMatchingT)[v] < 0) { /* v is free */
+      list[nb++]=v;
+      numV[v]=true;
+    }
+  }
+  while (nb>0) {
+    v=list[--nb];
+    for (i=0; i<nbSucc[v]; i++) {
+      u=succ[v*Gp->nbVertices + i];
+      used[u*Gt->nbVertices+v]=true;
+      if (numU[u]==false) {
+	numU[u]=true;
+	w=VECTOR(D->globalMatchingP)[u];
+	used[u*Gt->nbVertices+w]=true;
+	if (numV[w]==false) {
+	  list[nb++]=w;
+	  numV[w]=true;
+	}
+      }
+    }
+  }
+	
+  /* look for strongly connected components in Go */
+  IGRAPH_CHECK(
+	  igraph_i_lad_SCC((int)(Gp->nbVertices), (int)(Gt->nbVertices), numV, numU,
+	      nbSucc, succ, nbPred, pred, &D->globalMatchingP, &D->globalMatchingT));
+	
+  /* remove v from D[u] if (u, v) is not marked as used 
+                        and u and v are not in the same SCC 
+                        and D->globalMatchingP[u] != v */
+  nbToMatch = 0;
+  for (u=0; u<Gp->nbVertices; u++) {
+    oldNbVal = VECTOR(D->nbVal)[u];
+    for (i=0; i < VECTOR(D->nbVal)[u]; i++) {
+      v=VECTOR(D->val)[ VECTOR(D->firstVal)[u]+i ]; /* v in D(u) */
+      if ((!used[u*Gt->nbVertices+v]) && (numV[v]!=numU[u]) &&
+	  (VECTOR(D->globalMatchingP)[u]!=v)) {
+	IGRAPH_CHECK(igraph_i_lad_removeValue(u, v, D, Gp, Gt, &result));
+	if (!result) {
+	  *invalid = 1;
+	  /* Yes, this is ugly. */
+	  goto cleanup;
+	}
+      }
+    }
+    if (VECTOR(D->nbVal)[u] == 0) {
+      *invalid = 1; 
+      /* Yes, this is ugly. */
+      goto cleanup;
+    }
+    if ((oldNbVal>1) && (VECTOR(D->nbVal)[u]==1)) {
+      VECTOR(toMatch)[nbToMatch++] = u; 
+    }
+  }
+  IGRAPH_CHECK(igraph_i_lad_matchVertices(nbToMatch, &toMatch, induced, 
+					  D, Gp, Gt, invalid));
+
+cleanup:
+  igraph_vector_int_destroy(&toMatch);
+  igraph_free(list);
+  igraph_free(used);
+  igraph_free(numU);
+  igraph_free(numV);
+  igraph_free(succ);
+  igraph_free(nbSucc);
+  igraph_free(pred);
+  igraph_free(nbPred);
+  IGRAPH_FINALLY_CLEAN(9);
+  
+  return 0;
+}
+
+/* ---------------------------------------------------------*/
+/* Coming from lad.c                                        */
+/* ---------------------------------------------------------*/
+
+int igraph_i_lad_checkLAD(int u, int v, Tdomain* D, Tgraph* Gp, Tgraph* Gt,
+	bool *result) {
+  /* return true if G_(u, v) has a adj(u)-covering matching; false
+     otherwise */
+  int u2, v2, i, j;
+  int nbMatched = 0;
+  igraph_vector_int_t *Gp_uneis=igraph_adjlist_get(&Gp->succ, u);
+	
+  int *num, *numInv;
+  igraph_vector_int_t nbComp;
+  igraph_vector_int_t firstComp;
+  igraph_vector_int_t comp;
+  int nbNum=0;
+  int posInComp=0;
+  igraph_vector_int_t matchedWithU;
+  int invalid;
+
+  /* special case when u has only 1 adjacent node => no need to call
+     Hopcroft and Karp */
+  if (VECTOR(Gp->nbSucc)[u]==1) {
+    u2 = (int) VECTOR(*Gp_uneis)[0]; /* u2 is the only node adjacent to u */
+    v2 = VECTOR(D->matching)[ MATRIX(D->firstMatch, u, v) ];
+    if ((v2 != -1) && (igraph_i_lad_isInD(u2, v2, D))) {
+      *result = true;
+      return 0;
+    }
+    /* look for a support of edge (u, u2) for v */
+    for (i=VECTOR(D->firstVal)[u2]; 
+	 i < VECTOR(D->firstVal)[u2] + VECTOR(D->nbVal)[u2]; i++) {
+      if (MATRIX(Gt->isEdge, v, VECTOR(D->val)[i])) {
+	VECTOR(D->matching)[ MATRIX(D->firstMatch, u, v) ] = 
+	  VECTOR(D->val)[i];
+	*result = true;
+	return 0;
+      }
+    }
+    *result = false;
+    return 0;
+  }
+
+  /* general case (when u has more than 1 adjacent node) */
+  for (i=0; i<VECTOR(Gp->nbSucc)[u]; i++) { 
+    /* remove from the matching of G_(u, v) edges which no longer
+       belong to G_(u, v) */
+    u2 = (int) VECTOR(*Gp_uneis)[i];
+    v2 = VECTOR(D->matching)[ MATRIX(D->firstMatch, u, v)+i];
+    if ((v2 != -1) && (igraph_i_lad_isInD(u2, v2, D))) { nbMatched++; }
+  }
+  if (nbMatched == VECTOR(Gp->nbSucc)[u]) { 
+    *result = true;
+    return 0;
+  } /* The matching still covers adj(u) */
+	
+  /* Allocate memory */
+  ALLOC_ARRAY(num, Gt->nbVertices, int);
+  ALLOC_ARRAY(numInv, Gt->nbVertices, int);
+
+  /* Build the bipartite graph
+     let U be the set of nodes adjacent to u
+     let V be the set of nodes that are adjacent to v, and that belong
+     to domains of nodes of U */
+  /* nbComp[u]=number of elements of V that are compatible with u */
+  IGRAPH_CHECK(igraph_vector_int_init(&nbComp, (long int) VECTOR(Gp->nbSucc)[u]));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &nbComp);
+  IGRAPH_CHECK(igraph_vector_int_init(&firstComp, (long int) VECTOR(Gp->nbSucc)[u]));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &firstComp);
+  /* comp[firstComp[u]..firstComp[u]+nbComp[u]-1] = nodes of Gt that
+     are compatible with u */
+  IGRAPH_CHECK(igraph_vector_int_init(&comp, (long int) (VECTOR(Gp->nbSucc)[u] * 
+					    Gt->nbVertices)));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &comp);
+  IGRAPH_CHECK(igraph_vector_int_init(&matchedWithU, (long int) VECTOR(Gp->nbSucc)[u]));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &matchedWithU);
+  memset(num, -1, (size_t) (Gt->nbVertices) * sizeof(int));
+  for (i=0; i<VECTOR(Gp->nbSucc)[u]; i++) {
+    u2 = (int) VECTOR(*Gp_uneis)[i]; /* u2 is adjacent to u */
+    /* search for all nodes v2 in D[u2] which are adjacent to v */
+    VECTOR(nbComp)[i]=0;
+    VECTOR(firstComp)[i]=posInComp;
+    if (VECTOR(D->nbVal)[u2] > VECTOR(Gt->nbSucc)[v]) {
+      for (j=VECTOR(D->firstVal)[u2]; 
+	   j < VECTOR(D->firstVal)[u2] + VECTOR(D->nbVal)[u2]; j++) {
+	v2 = VECTOR(D->val)[j]; /* v2 belongs to D[u2] */
+	if (MATRIX(Gt->isEdge, v, v2)) { /* v2 is a successor of v */
+	  if (num[v2]<0) { /* v2 has not yet been added to V */
+	    num[v2]=nbNum;
+	    numInv[nbNum++]=v2;
+	  } 
+	  VECTOR(comp)[posInComp++]=num[v2];
+	  VECTOR(nbComp)[i]++;
+	}
+      }
+    } else {
+      igraph_vector_int_t *Gt_vneis=igraph_adjlist_get(&Gt->succ, v);
+      for (j=0; j<VECTOR(Gt->nbSucc)[v]; j++) {
+	v2 = (int) VECTOR(*Gt_vneis)[j]; /* v2 is a successor of v */
+	if (igraph_i_lad_isInD(u2, v2, D)) { /* v2 belongs to D[u2] */
+	  if (num[v2]<0) { /* v2 has not yet been added to V */
+	    num[v2]=nbNum;
+	    numInv[nbNum++]=v2;
+	  } 
+	  VECTOR(comp)[posInComp++]=num[v2];
+	  VECTOR(nbComp)[i]++;
+	}
+      }			
+    }
+    if (VECTOR(nbComp)[i]==0) { 
+      *result = false; /* u2 has no compatible vertex in succ[v] */
+      goto cleanup;
+    }
+    /* u2 is matched to v2 in the matching that supports (u, v) */
+    v2 = VECTOR(D->matching)[ MATRIX(D->firstMatch, u, v)+i]; 
+    if ((v2 != -1) && (igraph_i_lad_isInD(u2, v2, D))) {
+      VECTOR(matchedWithU)[i]=num[v2];
+    } else { 
+      VECTOR(matchedWithU)[i]=-1;
+    }
+  }
+  /* Call Hopcroft Karp to update the matching */
+  IGRAPH_CHECK(
+    igraph_i_lad_updateMatching((int) VECTOR(Gp->nbSucc)[u], nbNum, &nbComp, 
+			        &firstComp, &comp, &matchedWithU, &invalid)
+  );
+  if (invalid) { 
+    *result = false;
+    goto cleanup; 
+  }
+  for (i=0; i<VECTOR(Gp->nbSucc)[u]; i++) {
+    VECTOR(D->matching)[ MATRIX(D->firstMatch, u, v)+i] =
+      numInv[ VECTOR(matchedWithU)[i] ];
+  }
+  *result = true;
+
+cleanup:
+  igraph_free(numInv);
+  igraph_free(num);
+  igraph_vector_int_destroy(&matchedWithU);
+  igraph_vector_int_destroy(&comp);
+  igraph_vector_int_destroy(&firstComp);
+  igraph_vector_int_destroy(&nbComp);
+  IGRAPH_FINALLY_CLEAN(6);
+
+  return 0;
+}
+
+/* ---------------------------------------------------------*/
+/* Coming from main.c                                      */
+/* ---------------------------------------------------------*/
+
+int igraph_i_lad_filter(bool induced, Tdomain* D, Tgraph* Gp, Tgraph* Gt,
+	bool *result) {
+  /* filter domains of all vertices in D->toFilter wrt LAD and ensure
+     GAC(allDiff) 
+     return false if some domain becomes empty; true otherwise */
+  int u, v, i, oldNbVal;
+  int invalid;
+  bool result2;
+  while (!igraph_i_lad_toFilterEmpty(D)) {
+    while (!igraph_i_lad_toFilterEmpty(D)) {
+      u=igraph_i_lad_nextToFilter(D, (int) (Gp->nbVertices));
+      oldNbVal = VECTOR(D->nbVal)[u];
+      i = VECTOR(D->firstVal)[u]; 
+      while (i < VECTOR(D->firstVal)[u] + VECTOR(D->nbVal)[u]) {
+	/* for every target node v in D(u), check if G_(u, v) has a
+	   covering matching */
+	v=VECTOR(D->val)[i]; 
+	IGRAPH_CHECK(igraph_i_lad_checkLAD(u, v, D, Gp, Gt, &result2));
+	if (result2) {
+	  i++;
+	} else { 
+	  IGRAPH_CHECK(igraph_i_lad_removeValue(u, v, D, Gp, Gt, &result2));
+	  if (!result2) { *result = false; return 0; }
+	}
+      }
+      if ((VECTOR(D->nbVal)[u]==1) && (oldNbVal>1) && 
+	  (!igraph_i_lad_matchVertex(u, induced, D, Gp, Gt))) { 
+	*result = false; return 0;
+      }
+      if (VECTOR(D->nbVal)[u]==0) { *result = false; return 0; }
+    }
+    igraph_i_lad_ensureGACallDiff(induced, Gp, Gt, D, &invalid);
+    if (invalid) { *result = false; return 0; }
+  }
+  *result = true;
+  return 0;
+}
+
+
+
+int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced, 
+		       Tdomain* D, Tgraph* Gp, Tgraph* Gt, 
+		       int *invalid, igraph_bool_t *iso, 
+		       igraph_vector_t *map, igraph_vector_ptr_t *maps, 
+		       int *nbNodes, int *nbFail, int *nbSol, 
+		       clock_t *begin) {
+  /* 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 
+     return false if CPU time limit exceeded before the search is
+     completed, return true otherwise */
+	
+  int u, v, minDom, i; 
+  int* nbVal;
+  int* globalMatching;
+  clock_t end=clock();
+  igraph_vector_t *vec;
+  int* val;
+  bool result;
+
+  (*nbNodes)++;
+
+  if ( (double)(end - *begin) / CLOCKS_PER_SEC >= timeLimit) {
+    /* CPU time limit exceeded */
+    IGRAPH_ERROR("LAD CPU time exceeded", IGRAPH_CPUTIME);
+  }
+
+  /* Allocate memory */
+  ALLOC_ARRAY(nbVal, Gp->nbVertices, int);
+  ALLOC_ARRAY(globalMatching, Gp->nbVertices, int);
+
+  IGRAPH_CHECK(igraph_i_lad_filter(induced, D, Gp, Gt, &result));
+  if (!result) { 
+    /* filtering has detected an inconsistency */
+    (*nbFail)++;
+    igraph_i_lad_resetToFilter(D);
+    *invalid=0;
+    goto cleanup;
+  }	
+	
+  /* The current node of the search tree is consistent wrt to LAD and
+     GAC(allDiff) Save domain sizes and global all different matching 
+     and search for the non matched vertex minDom with smallest domain */
+  minDom=-1;
+  for (u=0; u<Gp->nbVertices; u++) {
+    nbVal[u]=VECTOR(D->nbVal)[u];
+    if ((nbVal[u]>1) && ((minDom<0) || (nbVal[u]<nbVal[minDom]))) { 
+      minDom=u; 
+    }
+    globalMatching[u] = VECTOR(D->globalMatchingP)[u];
+  }
+	
+  if (minDom==-1) { 
+    /* All vertices are matched => Solution found */
+    if (iso) { *iso = 1; }
+    (*nbSol)++;
+    if (map && igraph_vector_size(map)==0) {
+      IGRAPH_CHECK(igraph_vector_resize(map, Gp->nbVertices));
+      for (u=0; u<Gp->nbVertices; u++) {
+	VECTOR(*map)[u] = VECTOR(D->val)[ VECTOR(D->firstVal)[u] ];
+      }
+    }
+    if (maps) {
+      vec=igraph_Calloc(1, igraph_vector_t);
+      if (!vec) { IGRAPH_ERROR("LAD failed", IGRAPH_ENOMEM); }
+      IGRAPH_FINALLY(igraph_free, vec);
+      IGRAPH_CHECK(igraph_vector_init(vec, Gp->nbVertices));
+      IGRAPH_FINALLY(igraph_vector_destroy, vec);
+      for (u=0; u<Gp->nbVertices; u++) {
+	VECTOR(*vec)[u] = VECTOR(D->val)[ VECTOR(D->firstVal)[u] ];
+      }
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(maps, vec));
+      IGRAPH_FINALLY_CLEAN(2);
+    }
+    igraph_i_lad_resetToFilter(D);
+    *invalid=0;
+    goto cleanup;
+  }
+	
+  /* save the domain of minDom to iterate on its values */
+  ALLOC_ARRAY(val, VECTOR(D->nbVal)[minDom], int);
+  for (i=0; i < VECTOR(D->nbVal)[minDom]; i++) {
+    val[i]=VECTOR(D->val)[ VECTOR(D->firstVal)[minDom]+i ]; 
+  }
+	
+  /* branch on minDom=v, for every target node v in D(u) */
+  for(i=0; ((i<nbVal[minDom]) && ((firstSol==0)||(*nbSol==0))); i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    v = val[i];
+    IGRAPH_CHECK(igraph_i_lad_removeAllValuesButOne(minDom, v, D, Gp, Gt, &result));
+    if (!result || (!igraph_i_lad_matchVertex(minDom, induced, D, Gp, Gt))) {
+      (*nbFail)++; 
+      (*nbNodes)++;
+      igraph_i_lad_resetToFilter(D);
+    } else {
+      IGRAPH_CHECK(igraph_i_lad_solve(timeLimit, firstSol, induced,
+				      D, Gp, Gt, invalid, iso, map, maps, 
+				      nbNodes, nbFail, nbSol, begin));
+    }
+    /* restore domain sizes and global all different matching */
+    igraph_vector_int_fill(&D->globalMatchingT, -1);
+    for (u=0; u<Gp->nbVertices; u++) {
+      VECTOR(D->nbVal)[u] = nbVal[u];
+      VECTOR(D->globalMatchingP)[u] = globalMatching[u];
+      VECTOR(D->globalMatchingT)[globalMatching[u]] = u;
+    }
+  }
+  *invalid=0;
+
+  igraph_free(val);
+  IGRAPH_FINALLY_CLEAN(1);
+
+cleanup:
+  igraph_free(globalMatching);
+  igraph_free(nbVal);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_subisomorphic_lad
+ * Check subgraph isomorphism with the LAD algorithm
+ *
+ * Check whether \p pattern is isomorphic to a subgraph os \p target.
+ * The original LAD implementation by Christine Solnon was used as the 
+ * basis of this code. 
+ * 
+ * </para><para>
+ * See more about at http://liris.cnrs.fr/csolnon/LAD.html and in
+ * Christine Solnon: AllDifferent-based Filtering for Subgraph
+ * Isomorphism. Artificial Intelligence, 174(12-13):850-864, August
+ * 2010, Elsevier
+ * 
+ * \param pattern The smaller graph, it can be directed or undirected.
+ * \param target The bigger graph, it can be directed or undirected. 
+ * \param domains A pointer vector, or a null pointer. If a pointer
+ *    vector, then it must contain pointers to \c igraph_vector_t
+ *    objects and the length of the vector must match the number of
+ *    vertices in the \p pattern graph. For each vertex, the ids of
+ *    the compatible vertices in the target graph are listed.
+ * \param iso Pointer to a boolean, or a null pointer. If not a null
+ *    pointer, then the boolean is set to TRUE (1) if a subgraph
+ *    isomorphism is found, and to FALSE (0) otherwise.
+ * \param map Pointer to a vector or a null pointer. If not a null
+ *    pointer and a subgraph isomorphism is found, the matching
+ *    vertices from the target graph are listed here, for each vertex
+ *    (in vertex id order) from the pattern graph.
+ * \param maps Pointer vector or a null pointer. If not a null
+ *    pointer, then all subgraph isomorphisms are stored in the
+ *    pointer vector, in \c igraph_vector_t objects.
+ * \param induced Boolean, whether to search for induced matching
+ *    subgraphs.
+ * \param time_limit Processor time limit in seconds. Supply zero
+ *    here for no limit. If the time limit is over, then the function
+ *    signals an error.
+ * \return Error code
+ * 
+ * \sa \ref igraph_subisomorphic_vf2() for the VF2 algorithm.
+ * 
+ * Time complexity: exponential.
+ * 
+ * \example examples/simple/igraph_subisomorphic_lad.c
+ */
+
+int igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t *target, 
+			     igraph_vector_ptr_t *domains,
+			     igraph_bool_t *iso, igraph_vector_t *map, 
+			     igraph_vector_ptr_t *maps, 
+			     igraph_bool_t induced, int time_limit) {
+
+  bool firstSol = maps == 0;
+  bool initialDomains = domains != 0;
+  Tgraph Gp, Gt;
+  Tdomain D;
+  int invalidDomain;
+  int u, nbToMatch = 0;
+  igraph_vector_int_t toMatch;
+  /* Number of nodes in the search tree */
+  int nbNodes=0;
+  /* number of failed nodes in the search tree */
+  int nbFail=0;
+  /* number of solutions found */
+  int nbSol=0;
+  /* reusable structure to get CPU time usage */
+  clock_t begin=clock();
+
+  if (!iso && !map && !maps) {
+    IGRAPH_ERROR("Please give least one of `iso', `map' or `maps'", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (time_limit<=0) { time_limit = INT_MAX; }
+    
+  igraph_i_lad_createGraph(pattern, &Gp);
+  igraph_i_lad_createGraph(target, &Gt);
+  
+  if (iso)  { *iso = 0; }
+  if (map)  { igraph_vector_clear(map); } 
+  if (maps) { igraph_vector_ptr_clear(maps); }
+
+  if (Gp.nbVertices > Gt.nbVertices) { goto exit3; }
+  
+  IGRAPH_CHECK(igraph_i_lad_initDomains(initialDomains, domains, &D, &Gp, 
+					&Gt, &invalidDomain));
+  if (invalidDomain) { goto exit2; }
+  
+  IGRAPH_CHECK(igraph_i_lad_updateMatching((int) (Gp.nbVertices), 
+					   (int) (Gt.nbVertices),
+					   &D.nbVal, &D.firstVal, &D.val, 
+					   &D.globalMatchingP, 
+					   &invalidDomain));
+  if (invalidDomain) { goto exit; }
+
+  IGRAPH_CHECK(igraph_i_lad_ensureGACallDiff((char) induced, &Gp, &Gt, &D, 
+					     &invalidDomain));
+  if (invalidDomain) { goto exit; }
+
+  for (u=0; u<Gp.nbVertices; u++) {
+    VECTOR(D.globalMatchingT)[ VECTOR(D.globalMatchingP)[u] ] = u;
+  }
+
+  IGRAPH_CHECK(igraph_vector_int_init(&toMatch, Gp.nbVertices));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &toMatch);
+  
+  for (u=0; u<Gp.nbVertices; u++) {
+    if (VECTOR(D.nbVal)[u] == 1) { VECTOR(toMatch)[nbToMatch++] = u; }
+  }
+  IGRAPH_CHECK(igraph_i_lad_matchVertices(nbToMatch, &toMatch, (char) induced, 
+					  &D, &Gp, &Gt, &invalidDomain));
+  igraph_vector_int_destroy(&toMatch);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (invalidDomain) { goto exit; }
+	
+  IGRAPH_CHECK(igraph_i_lad_solve(time_limit, firstSol, (char) induced, &D, 
+				  &Gp, &Gt, &invalidDomain, iso, map, maps, 
+				  &nbNodes, &nbFail, &nbSol, &begin));
+
+ exit:
+  
+  igraph_vector_int_destroy(&D.val);
+  igraph_vector_int_destroy(&D.matching);
+  IGRAPH_FINALLY_CLEAN(2);
+
+ exit2:
+  
+  igraph_vector_int_destroy(&D.globalMatchingP);
+  igraph_vector_int_destroy(&D.globalMatchingT);
+  igraph_vector_int_destroy(&D.nbVal);
+  igraph_vector_int_destroy(&D.firstVal);
+  igraph_matrix_int_destroy(&D.posInVal);
+  igraph_matrix_int_destroy(&D.firstMatch);
+  igraph_vector_char_destroy(&D.markedToFilter);
+  igraph_vector_int_destroy(&D.toFilter);
+  IGRAPH_FINALLY_CLEAN(8);
+
+ exit3:
+
+  igraph_matrix_char_destroy(&Gt.isEdge);
+  igraph_adjlist_destroy(&Gt.succ);
+  igraph_vector_destroy(&Gt.nbSucc);
+  igraph_matrix_char_destroy(&Gp.isEdge);
+  igraph_adjlist_destroy(&Gp.succ);
+  igraph_vector_destroy(&Gp.nbSucc);
+  IGRAPH_FINALLY_CLEAN(6);
+
+  return 0;
+}
diff --git a/src/lapack.c b/src/lapack.c
new file mode 100644
index 0000000..ea3a811
--- /dev/null
+++ b/src/lapack.c
@@ -0,0 +1,924 @@
+/* -*- 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_lapack.h"
+#include "igraph_lapack_internal.h"
+
+/**
+ * \function igraph_lapack_dgetrf
+ * LU factorization of a general M-by-N matrix
+ * 
+ * The factorization has the form   
+ *      A = P * L * U   
+ * where P is a permutation matrix, L is lower triangular with unit   
+ * diagonal elements (lower trapezoidal if m > n), and U is upper   
+ * triangular (upper trapezoidal if m < n).   
+ * \param a The input/output matrix. On entry, the M-by-N matrix to be
+ *      factored. On exit, the factors L and U from the factorization 
+ *      A = P * L * U; the unit diagonal elements of L are not
+ *      stored.
+ * \param ipiv An integer vector, the pivot indices are stored here,
+ *      unless it is a null pointer. Row i of the matrix was
+ *      interchanged with row ipiv[i].
+ * \param info LAPACK error code. Zero on successful exit. If positive
+ *      and i, then U(i,i) is exactly zero. The factorization has been
+ *      completed, but the factor U is exactly singular, and division
+ *      by zero will occur if it is used to solve a system of
+ *      equations. If LAPACK returns an error, i.e. a negative info
+ *      value, then an igraph error is generated as well.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_lapack_dgetrf(igraph_matrix_t *a, igraph_vector_int_t *ipiv, 
+			 int *info) {
+  int m=(int) igraph_matrix_nrow(a);
+  int n=(int) igraph_matrix_ncol(a);
+  int lda=m > 0 ? m : 1;
+  igraph_vector_int_t *myipiv=ipiv, vipiv;
+
+  if (!ipiv) {
+    IGRAPH_CHECK(igraph_vector_int_init(&vipiv, m<n ? m : n));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &vipiv);
+    myipiv=&vipiv;
+  }
+
+  igraphdgetrf_(&m, &n, VECTOR(a->data), &lda, VECTOR(*myipiv), info);
+
+  if (*info > 0) {
+    IGRAPH_WARNING("LU: factor is exactly singular");
+  } else if (*info < 0) {
+    switch(*info) { 
+    case -1:
+      IGRAPH_ERROR("Invalid number of rows", IGRAPH_ELAPACK);
+      break;
+    case -2:
+      IGRAPH_ERROR("Invalid number of columns", IGRAPH_ELAPACK);
+      break;
+    case -3:
+      IGRAPH_ERROR("Invalid input matrix", IGRAPH_ELAPACK);
+      break;
+    case -4:
+      IGRAPH_ERROR("Invalid LDA parameter", IGRAPH_ELAPACK);
+      break;
+    case -5:
+      IGRAPH_ERROR("Invalid pivot vector", IGRAPH_ELAPACK);
+      break;
+    case -6:
+      IGRAPH_ERROR("Invalid info argument", IGRAPH_ELAPACK);
+      break;
+    default:
+      IGRAPH_ERROR("Unknown LAPACK error", IGRAPH_ELAPACK);
+      break;
+    }
+  }
+
+  if (!ipiv) {
+    igraph_vector_int_destroy(&vipiv);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_lapack_dgetrs
+ * Solve general system of linear equations using LU factorization
+ * 
+ * This function calls LAPACK to solve a system of linear equations   
+ *      A * X = B  or  A' * X = B   
+ * with a general N-by-N matrix A using the LU factorization
+ * computed by \ref igraph_lapack_dgetrf.
+ * \param transpose Logical scalar, whether to transpose the input
+ *      matrix.
+ * \param a A matrix containing the L and U factors from the
+ *      factorization A = P*L*U.
+ * \param ipiv An integer vector, the pivot indices from \ref
+ *      igraph_lapack_dgetrf must be given here.
+ * \param b The right hand side matrix must be given here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_lapack_dgetrs(igraph_bool_t transpose, const igraph_matrix_t *a,
+			 igraph_vector_int_t *ipiv, igraph_matrix_t *b) {
+  char trans = transpose ? 'T' : 'N';
+  int n=(int) igraph_matrix_nrow(a);
+  int nrhs=(int) igraph_matrix_ncol(b);
+  int lda= n > 0 ? n : 1;
+  int ldb= n > 0 ? n : 1;
+  int info;
+
+  if (n != igraph_matrix_ncol(a)) {
+    IGRAPH_ERROR("Cannot LU solve matrix", IGRAPH_NONSQUARE);
+  }
+  if (n != igraph_matrix_nrow(b)) {
+    IGRAPH_ERROR("Cannot LU solve matrix, RHS of wrong size", IGRAPH_EINVAL);
+  }
+
+  igraphdgetrs_(&trans, &n, &nrhs, VECTOR(a->data), &lda, VECTOR(*ipiv),
+		VECTOR(b->data), &ldb, &info);
+
+  if (info < 0) {
+    switch(info) { 
+    case -1:
+      IGRAPH_ERROR("Invalid transpose argument", IGRAPH_ELAPACK);
+      break;
+    case -2:
+      IGRAPH_ERROR("Invalid number of rows/columns", IGRAPH_ELAPACK);
+      break;
+    case -3:
+      IGRAPH_ERROR("Invalid number of RHS vectors", IGRAPH_ELAPACK);
+      break;
+    case -4:
+      IGRAPH_ERROR("Invalid LU matrix", IGRAPH_ELAPACK);
+      break;
+    case -5: 
+      IGRAPH_ERROR("Invalid LDA parameter", IGRAPH_ELAPACK);
+      break;
+    case -6:
+      IGRAPH_ERROR("Invalid pivot vector", IGRAPH_ELAPACK);
+      break;
+    case -7:
+      IGRAPH_ERROR("Invalid RHS matrix", IGRAPH_ELAPACK);
+      break;
+    case -8:
+      IGRAPH_ERROR("Invalid LDB parameter", IGRAPH_ELAPACK);
+      break;
+    case -9:
+      IGRAPH_ERROR("Invalid info argument", IGRAPH_ELAPACK);
+      break;
+    default:
+      IGRAPH_ERROR("Unknown LAPACK error", IGRAPH_ELAPACK);
+      break;
+    }
+  }
+		
+  return 0;
+}
+
+/**
+ * \function igraph_lapack_dgesv
+ * Solve system of linear equations with LU factorization
+ * 
+ * This function computes the solution to a real system of linear
+ * equations A * X = B, where A is an N-by-N matrix and X and B are
+ * N-by-NRHS matrices.
+ * 
+ * </para><para>The LU decomposition with partial pivoting and row
+ * interchanges is used to factor A as   
+ *    A = P * L * U,   
+ * where P is a permutation matrix, L is unit lower triangular, and U is   
+ * upper triangular.  The factored form of A is then used to solve the   
+ * system of equations A * X = B.
+ * \param a Matrix. On entry the N-by-N coefficient matrix, on exit,
+ *        the factors L and U from the factorization A=P*L*U; the unit
+ *        diagonal elements of L are not stored.
+ * \param ipiv An integer vector or a null pointer. If not a null
+ *        pointer, then the pivot indices that define the permutation
+ *        matrix P, are stored here. Row i of the matrix was
+ *        interchanged with row IPIV(i).
+ * \param b Matrix, on entry the right hand side matrix should be
+ *        stored here. On exit, if there was no error, and the info
+ *        argument is zero, then it contains the solution matrix X.
+ * \param info The LAPACK info code. If it is positive, then 
+ *        U(info,info) is exactly zero. In this case the factorization   
+ *        has been completed, but the factor U is exactly   
+ *        singular, so the solution could not be computed. 
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_lapack_dgesv.c
+ */
+
+int igraph_lapack_dgesv(igraph_matrix_t *a, igraph_vector_int_t *ipiv,
+			igraph_matrix_t *b, int *info) {
+
+  int n=(int) igraph_matrix_nrow(a);
+  int nrhs=(int) igraph_matrix_ncol(b);
+  int lda= n > 0 ? n : 1;
+  int ldb= n > 0 ? n : 1;
+  igraph_vector_int_t *myipiv=ipiv, vipiv;
+
+  if (n != igraph_matrix_ncol(a)) {
+    IGRAPH_ERROR("Cannot LU solve matrix", IGRAPH_NONSQUARE);
+  }
+  if (n != igraph_matrix_nrow(b)) {
+    IGRAPH_ERROR("Cannot LU solve matrix, RHS of wrong size", IGRAPH_EINVAL);
+  }
+
+  if (!ipiv) {
+    IGRAPH_CHECK(igraph_vector_int_init(&vipiv, n));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &vipiv);
+    myipiv=&vipiv;
+  }
+  
+  igraphdgesv_(&n, &nrhs, VECTOR(a->data), &lda, VECTOR(*myipiv),
+	       VECTOR(b->data), &ldb, info);
+
+  if (*info > 0) {
+    IGRAPH_WARNING("LU: factor is exactly singular");
+  } else if (*info < 0) {
+    switch(*info) { 
+    case -1:
+      IGRAPH_ERROR("Invalid number of rows/column", IGRAPH_ELAPACK);
+      break;
+    case -2:
+      IGRAPH_ERROR("Invalid number of RHS vectors", IGRAPH_ELAPACK);
+      break;
+    case -3:
+      IGRAPH_ERROR("Invalid input matrix", IGRAPH_ELAPACK);
+      break;
+    case -4:
+      IGRAPH_ERROR("Invalid LDA parameter", IGRAPH_ELAPACK);
+      break;
+    case -5:
+      IGRAPH_ERROR("Invalid pivot vector", IGRAPH_ELAPACK);
+      break;
+    case -6:
+      IGRAPH_ERROR("Invalid RHS matrix", IGRAPH_ELAPACK);
+      break;
+    case -7:
+      IGRAPH_ERROR("Invalid LDB parameter", IGRAPH_ELAPACK);
+      break;
+    case -8:
+      IGRAPH_ERROR("Invalid info argument", IGRAPH_ELAPACK);
+      break;
+    default:
+      IGRAPH_ERROR("Unknown LAPACK error", IGRAPH_ELAPACK);
+      break;
+    }
+  }
+		
+  if (!ipiv) {
+    igraph_vector_int_destroy(&vipiv);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_lapack_dsyevr
+ * Selected eigenvalues and optionally eigenvectors of a symmetric matrix
+ * 
+ * Calls the DSYEVR LAPACK function to compute selected eigenvalues
+ * and, optionally, eigenvectors of a real symmetric matrix A.
+ * Eigenvalues and eigenvectors can be selected by specifying either
+ * a range of values or a range of indices for the desired eigenvalues.   
+ *
+ * </para><para>See more in the LAPACK documentation.
+ * \param A Matrix, on entry it contains the symmetric input
+ *        matrix. Only the leading N-by-N upper triangular part is
+ *        used for the computation.
+ * \param which Constant that gives which eigenvalues (and possibly
+ *        the corresponding eigenvectors) to calculate. Possible
+ *        values are \c IGRAPH_LAPACK_DSYEV_ALL, all eigenvalues;
+ *        \c IGRAPH_LAPACK_DSYEV_INTERVAL, all eigenvalues in the
+ *        half-open interval (vl,vu];
+ *        \c IGRAPH_LAPACK_DSYEV_SELECT, the il-th through iu-th
+ *        eigenvalues.
+ * \param vl If \p which is \c IGRAPH_LAPACK_DSYEV_INTERVAL, then 
+ *        this is the lower bound of the interval to be searched for
+ *        eigenvalues. See also the \p vestimate argument.
+ * \param vu If \p which is \c IGRAPH_LAPACK_DSYEV_INTERVAL, then
+ *        this is the upper bound of the interval to be searched for
+ *        eigenvalues. See also the \p vestimate argument.
+ * \param vestimate An upper bound for the number of eigenvalues in
+ *        the (vl,vu] interval, if \p which is \c
+ *        IGRAPH_LAPACK_DSYEV_INTERVAL. Memory is allocated only for
+ *        the given number of eigenvalues (and eigenvectors), so this
+ *        upper bound must be correct.
+ * \param il The index of the smallest eigenvalue to return, if \p
+ *        which is \c IGRAPH_LAPACK_DSYEV_SELECT.
+ * \param iu The index of the largets eigenvalue to return, if \p 
+ *        which is \c IGRAPH_LAPACK_DSYEV_SELECT.
+ * \param abstol The absolute error tolerance for the eigevalues. An
+ *        approximate eigenvalue is accepted as converged when it is
+ *        determined to lie in an interval [a,b] of width less than or
+ *        equal to abstol + EPS * max(|a|,|b|), where EPS is the
+ *        machine precision.
+ * \param values An initialized vector, the eigenvalues are stored
+ *        here, unless it is a null pointer. It will be resized as
+ *        needed.
+ * \param vectors An initialized matrix, the eigenvectors are stored
+ *        in its columns, unless it is a null pointer. It will be
+ *        resized as needed.
+ * \param support An integer vector. If not a null pointer, then it
+ *        will be resized to (2*max(1,M)) (M is a the total number of
+ *        eigenvalues found). Then the support of the eigenvectors in
+ *        \p vectors is stored here, i.e., the indices   
+ *        indicating the nonzero elements in \p vectors. 
+ *        The i-th eigenvector is nonzero only in elements
+ *        support(2*i-1) through support(2*i).
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_lapack_dsyevr.c
+ */
+
+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) {
+
+  igraph_matrix_t Acopy;
+  char jobz = vectors ? 'V' : 'N', range, uplo='U';
+  int n=(int) igraph_matrix_nrow(A), lda=n, ldz=n;
+  int m, info; 
+  igraph_vector_t *myvalues=values, vvalues;
+  igraph_vector_int_t *mysupport=support, vsupport;
+  igraph_vector_t work;
+  igraph_vector_int_t iwork;
+  int lwork=-1, liwork=-1;
+
+  if (n != igraph_matrix_ncol(A)) {
+    IGRAPH_ERROR("Cannot find eigenvalues/vectors", IGRAPH_NONSQUARE);
+  }
+  if (which==IGRAPH_LAPACK_DSYEV_INTERVAL && 
+      (vestimate < 1 || vestimate > n)) {
+    IGRAPH_ERROR("Estimated (upper bound) number of eigenvalues must be "
+		 "between 1 and n", IGRAPH_EINVAL);
+  }
+  if (which==IGRAPH_LAPACK_DSYEV_SELECT && iu-il < 0) {
+    IGRAPH_ERROR("Invalid 'il' and/or 'iu' values", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&work, 1);
+  IGRAPH_CHECK(igraph_vector_int_init(&iwork, 1));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &iwork);
+
+  if (!values) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vvalues, 0);
+    myvalues=&vvalues;
+  }
+  if (!support) {
+    IGRAPH_CHECK(igraph_vector_int_init(&vsupport, 0));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &vsupport);
+    mysupport=&vsupport;
+  }
+  
+  switch (which) {
+  case IGRAPH_LAPACK_DSYEV_ALL:
+    range = 'A';
+    IGRAPH_CHECK(igraph_vector_resize(myvalues, n));
+    IGRAPH_CHECK(igraph_vector_int_resize(mysupport, 2*n));
+    if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, n)); }
+    break;
+  case IGRAPH_LAPACK_DSYEV_INTERVAL:
+    range = 'V';
+    IGRAPH_CHECK(igraph_vector_resize(myvalues, vestimate));
+    IGRAPH_CHECK(igraph_vector_int_resize(mysupport, 2*vestimate));
+    if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors,n, vestimate)); }
+   break;
+  case IGRAPH_LAPACK_DSYEV_SELECT:
+    range = 'I';
+    IGRAPH_CHECK(igraph_vector_resize(myvalues, iu-il+1));
+    IGRAPH_CHECK(igraph_vector_int_resize(mysupport, 2*(iu-il+1)));
+    if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, iu-il+1)); }
+    break;
+  }
+  
+  igraphdsyevr_(&jobz, &range, &uplo, &n, &MATRIX(Acopy,0,0), &lda,
+		&vl, &vu, &il, &iu, &abstol, &m, VECTOR(*myvalues), 
+		vectors ? &MATRIX(*vectors,0,0) : 0, &ldz, VECTOR(*mysupport),
+		VECTOR(work), &lwork, VECTOR(iwork), &liwork, &info);
+  
+  lwork=(int) VECTOR(work)[0];
+  liwork=VECTOR(iwork)[0];
+  IGRAPH_CHECK(igraph_vector_resize(&work, lwork));
+  IGRAPH_CHECK(igraph_vector_int_resize(&iwork, liwork));
+
+  igraphdsyevr_(&jobz, &range, &uplo, &n, &MATRIX(Acopy,0,0), &lda,
+		&vl, &vu, &il, &iu, &abstol, &m, VECTOR(*myvalues), 
+		vectors ? &MATRIX(*vectors,0,0) : 0, &ldz, VECTOR(*mysupport),
+		VECTOR(work), &lwork, VECTOR(iwork), &liwork, &info);
+
+  if (values) { 
+    IGRAPH_CHECK(igraph_vector_resize(values, m));
+  }
+  if (vectors) { 
+    IGRAPH_CHECK(igraph_matrix_resize(vectors, n, m));
+  }
+  if (support) {
+    IGRAPH_CHECK(igraph_vector_int_resize(support, m));
+  }
+
+  if (!support) {
+    igraph_vector_int_destroy(&vsupport);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (!values) {
+    igraph_vector_destroy(&vvalues);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_int_destroy(&iwork);
+  igraph_vector_destroy(&work);
+  igraph_matrix_destroy(&Acopy);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_lapack_dgeev
+ * Eigenvalues and optionally eigenvectors of a non-symmetric matrix
+ * 
+ * This function calls LAPACK to compute, for an N-by-N real
+ * nonsymmetric matrix A, the eigenvalues and, optionally, the left
+ * and/or right eigenvectors.
+ * 
+ * </para><para>
+ * The right eigenvector v(j) of A satisfies   
+ *                    A * v(j) = lambda(j) * v(j)   
+ * where lambda(j) is its eigenvalue.   
+ * The left eigenvector u(j) of A satisfies   
+ *                u(j)**H * A = lambda(j) * u(j)**H   
+ * where u(j)**H denotes the conjugate transpose of u(j).   
+ *
+ * </para><para>
+ * The computed eigenvectors are normalized to have Euclidean norm   
+ * equal to 1 and largest component real.   
+ * 
+ * \param A matrix. On entry it contains the N-by-N input matrix.
+ * \param valuesreal Pointer to an initialized vector, or a null
+ *        pointer. If not a null pointer, then the real parts of the
+ *        eigenvalues are stored here. The vector will be resized as
+ *        needed.
+ * \param valuesimag Pointer to an initialized vector, or a null
+ *        pointer. If not a null pointer, then the imaginary parts of
+ *        the eigenvalues are stored here. The vector will be resized
+ *        as needed.
+ * \param vectorsleft Pointer to an initialized matrix, or a null
+ *        pointer. If not a null pointer, then the left eigenvectors
+ *        are stored in the columns of the matrix. The matrix will be
+ *        resized as needed.
+ * \param vectorsright Pointer to an initialized matrix, or a null
+ *        pointer. If not a null pointer, then the right eigenvectors
+ *        are stored in the columns of the matrix. The matrix will be
+ *        resized as needed.
+ * \param info This argument is used for two purposes. As an input
+ *        argument it gives whether an igraph error should be
+ *        generated if the QR algorithm fails to compute all
+ *        eigenvalues. If \p info is non-zero, then an error is
+ *        generated, otherwise only a warning is given.
+ *        On exit it contains the LAPACK error code. 
+ *        Zero means successful exit.
+ *        A negative values means that some of the arguments had an
+ *        illegal value, this always triggers an igraph error. An i
+ *        positive  value means that the QR algorithm failed to
+ *        compute all the eigenvalues, and no eigenvectors have been
+ *        computed; element i+1:N of \p valuesreal and \p valuesimag
+ *        contain eigenvalues which have converged. This case only
+ *        generates an igraph error, if \p info was non-zero on entry.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_lapack_dgeev.c
+ */
+
+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) {
+
+  char jobvl= vectorsleft  ? 'V' : 'N';
+  char jobvr= vectorsright ? 'V' : 'N';
+  int n=(int) igraph_matrix_nrow(A);
+  int lda=n, ldvl=n, ldvr=n, lwork=-1;
+  igraph_vector_t work;
+  igraph_vector_t *myreal=valuesreal, *myimag=valuesimag, vreal, vimag;
+  igraph_matrix_t Acopy;
+  int error=*info;
+
+  if (igraph_matrix_ncol(A) != n) { 
+    IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_NONSQUARE);
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&work, 1);
+  
+  if (!valuesreal) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vreal, n);
+    myreal=&vreal;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(myreal, n));
+  }
+  if (!valuesimag) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vimag, n);
+    myimag=&vimag;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(myimag, n));
+  }
+  if (vectorsleft) { 
+    IGRAPH_CHECK(igraph_matrix_resize(vectorsleft, n, n));
+  }
+  if (vectorsright) {
+    IGRAPH_CHECK(igraph_matrix_resize(vectorsright, n, n));
+  }
+
+  igraphdgeev_(&jobvl, &jobvr, &n, &MATRIX(Acopy,0,0), &lda, 
+	       VECTOR(*myreal), VECTOR(*myimag), 
+	       vectorsleft  ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl,
+	       vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr,
+	       VECTOR(work), &lwork, info);
+
+  lwork=(int) VECTOR(work)[0];
+  IGRAPH_CHECK(igraph_vector_resize(&work, lwork));
+  
+  igraphdgeev_(&jobvl, &jobvr, &n, &MATRIX(Acopy,0,0), &lda, 
+	       VECTOR(*myreal), VECTOR(*myimag), 
+	       vectorsleft  ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl,
+	       vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr,
+	       VECTOR(work), &lwork, info);  
+
+  if (*info < 0) {
+      IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK);
+  } else if (*info > 0) {    
+    if (error) {
+      IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK);
+    } else {
+      IGRAPH_WARNING("Cannot calculate eigenvalues (dgeev)");
+    }
+  }
+
+  if (!valuesimag) {
+    igraph_vector_destroy(&vimag);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (!valuesreal) { 
+    igraph_vector_destroy(&vreal);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_destroy(&work);
+  igraph_matrix_destroy(&Acopy);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_lapack_dgeevx
+ * Eigenvalues/vectors of nonsymmetric matrices, expert mode
+ * 
+ * This function calculates the eigenvalues and optionally the left
+ * and/or right eigenvectors of a nonsymmetric N-by-N real matrix.
+ * 
+ * </para><para>
+ * Optionally also, it computes a balancing transformation to improve   
+ * the conditioning of the eigenvalues and eigenvectors (\p ilo, \pihi,   
+ * \p scale, and \p abnrm), reciprocal condition numbers for the
+ * eigenvalues (\p rconde), and reciprocal condition numbers for the
+ * right eigenvectors (\p rcondv).   
+ * 
+ * </para><para>
+ * The right eigenvector v(j) of A satisfies   
+ *                   A * v(j) = lambda(j) * v(j)   
+ * where lambda(j) is its eigenvalue.   
+ * The left eigenvector u(j) of A satisfies   
+ *               u(j)**H * A = lambda(j) * u(j)**H   
+ * where u(j)**H denotes the conjugate transpose of u(j).   
+ *
+ * </para><para>
+ * The computed eigenvectors are normalized to have Euclidean norm   
+ * equal to 1 and largest component real.   
+ *
+ * </para><para>
+ * Balancing a matrix means permuting the rows and columns to make it   
+ * more nearly upper triangular, and applying a diagonal similarity   
+ * transformation D * A * D**(-1), where D is a diagonal matrix, to   
+ * make its rows and columns closer in norm and the condition numbers   
+ * of its eigenvalues and eigenvectors smaller.  The computed   
+ * reciprocal condition numbers correspond to the balanced matrix.   
+ * Permuting rows and columns will not change the condition numbers   
+ * (in exact arithmetic) but diagonal scaling will.  For further   
+ * explanation of balancing, see section 4.10.2 of the LAPACK   
+ * Users' Guide.   
+ * 
+ * \param balance Scalar that indicated, whether the input matrix
+ *   should be balanced. Possible values:
+ *   \clist
+ *     \cli IGRAPH_LAPACK_DGEEVX_BALANCE_NONE 
+ *          no not diagonally scale or permute. 
+ *     \cli IGRAPH_LAPACK_DGEEVX_BALANCE_PERM 
+ *          perform permutations to make the matrix more nearly upper
+ *          triangular. Do not diagonally scale.
+ *     \cli IGRAPH_LAPACK_DGEEVX_BALANCE_SCALE
+ *          diagonally scale the matrix, i.e. replace A by
+ *          D*A*D**(-1), where D is a diagonal matrix, chosen to make
+ *          the rows and columns of A more equal in norm. Do not
+ *          permute.
+ *     \cli IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH
+ *          both diagonally scale and permute A.
+ *   \endclist
+ * \param A The input matrix, must be square.
+ * \param valuesreal An initialized vector, or a NULL pointer. If not
+ *   a NULL pointer, then the real parts of the eigenvalues are stored
+ *   here. The vector will be resized, as needed.
+ * \param valuesimag An initialized vector, or a NULL pointer. If not
+ *   a NULL pointer, then the imaginary parts of the eigenvalues are stored
+ *   here. The vector will be resized, as needed.
+ * \param vectorsleft An initialized matrix or a NULL pointer. If not
+ *   a null pointer, then the left eigenvectors are stored here. The
+ *   order corresponds to the eigenvalues and the eigenvectors are
+ *   stored in a compressed form. If the j-th eigenvalue is real then 
+ *   column j contains the corresponding eigenvector. If the j-th and
+ *   (j+1)-th eigenvalues form a complex conjugate pair, then the j-th
+ *   and (j+1)-th columns contain their corresponding eigenvectors.
+ * \param vectorsright An initialized matrix or a NULL pointer. If not
+ *   a null pointer, then the right eigenvectors are stored here. The
+ *   format is the same, as for the \p vectorsleft argument.
+ * \param ilo 
+ * \param ihi \p ilo and \p ihi are integer values determined when A was   
+ *   balanced.  The balanced A(i,j) = 0 if I>J and   
+ *   J=1,...,ilo-1 or I=ihi+1,...,N.
+ * \param scale Pointer to an initialized vector or a NULL pointer. If
+ *   not a NULL pointer, then details of the permutations and scaling
+ *   factors applied when balancing \param A, are stored here. 
+ *   If P(j) is the index of the row and column   
+ *   interchanged with row and column j, and D(j) is the scaling   
+ *   factor applied to row and column j, then
+ *   \clist
+ *      \cli scale(J) = P(J),    for J = 1,...,ilo-1   
+ *      \cli scale(J) = D(J),    for J = ilo,...,ihi   
+ *      \cli scale(J) = P(J)     for J = ihi+1,...,N.   
+ *   \endclist
+ *   The order in which the interchanges are made is N to \p ihi+1,
+ *   then 1 to \p ilo-1.   
+ * \param abnrm Pointer to a real variable, the one-norm of the
+ *   balanced matrix is stored here. (The one-norm is the maximum of
+ *   the sum of absolute values of elements in any column.)
+ * \param rconde An initialized vector or a NULL pointer. If not a
+ *   null pointer, then the reciprocal condition numbers of the
+ *   eigenvalues are stored here.
+ * \param rcondv An initialized vector or a NULL pointer. If not a
+ *   null pointer, then the reciprocal condition numbers of the right
+ *   eigenvectors are stored here.
+ * \param info This argument is used for two purposes. As an input
+ *        argument it gives whether an igraph error should be
+ *        generated if the QR algorithm fails to compute all
+ *        eigenvalues. If \p info is non-zero, then an error is
+ *        generated, otherwise only a warning is given.
+ *        On exit it contains the LAPACK error code. 
+ *        Zero means successful exit.
+ *        A negative values means that some of the arguments had an
+ *        illegal value, this always triggers an igraph error. An i
+ *        positive  value means that the QR algorithm failed to
+ *        compute all the eigenvalues, and no eigenvectors have been
+ *        computed; element i+1:N of \p valuesreal and \p valuesimag
+ *        contain eigenvalues which have converged. This case only
+ *        generated an igraph error, if \p info was non-zero on entry.
+ * \return Error code.
+ * 
+ * Time complexity: TODO
+ * 
+ * \example examples/simple/igraph_lapack_dgeevx.c
+ */
+
+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) {
+
+  char balanc;
+  char jobvl= vectorsleft  ? 'V' : 'N';
+  char jobvr= vectorsright ? 'V' : 'N';
+  char sense;
+  int n=(int) igraph_matrix_nrow(A);
+  int lda=n, ldvl=n, ldvr=n, lwork=-1;
+  igraph_vector_t work;
+  igraph_vector_int_t iwork;
+  igraph_matrix_t Acopy;
+  int error=*info;
+  igraph_vector_t *myreal=valuesreal, *myimag=valuesimag, vreal, vimag;
+  igraph_vector_t *myscale=scale, vscale;
+
+  if (igraph_matrix_ncol(A) != n) { 
+    IGRAPH_ERROR("Cannot calculate eigenvalues (dgeevx)", IGRAPH_NONSQUARE);
+  }
+  
+  switch (balance) {
+  case IGRAPH_LAPACK_DGEEVX_BALANCE_NONE:
+    balanc='N';
+    break;
+  case IGRAPH_LAPACK_DGEEVX_BALANCE_PERM:
+    balanc='P';
+    break;
+  case IGRAPH_LAPACK_DGEEVX_BALANCE_SCALE:
+    balanc='S';
+    break;
+  case IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH:
+    balanc='B';
+    break;
+  default:
+    IGRAPH_ERROR("Invalid 'balance' argument", IGRAPH_EINVAL);
+    break;
+  }
+
+  if (!rconde && !rcondv) {
+    sense='N';
+  } else if (rconde && !rcondv) {
+    sense='E';
+  } else if (!rconde && rcondv) {
+    sense='V';
+  } else {
+    sense='B';
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&work, 1);
+  IGRAPH_CHECK(igraph_vector_int_init(&iwork, n));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &iwork);
+  
+  if (!valuesreal) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vreal, n);
+    myreal=&vreal;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(myreal, n));
+  }
+  if (!valuesimag) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vimag, n);
+    myimag=&vimag;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(myimag, n));
+  }
+  if (!scale) {
+    IGRAPH_VECTOR_INIT_FINALLY(&vscale, n);
+    myscale=&vscale;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(scale, n));
+  }
+  if (vectorsleft) { 
+    IGRAPH_CHECK(igraph_matrix_resize(vectorsleft, n, n));
+  }
+  if (vectorsright) {
+    IGRAPH_CHECK(igraph_matrix_resize(vectorsright, n, n));
+  }
+
+  igraphdgeevx_(&balanc, &jobvl, &jobvr, &sense, &n, &MATRIX(Acopy,0,0), 
+		&lda, VECTOR(*myreal), VECTOR(*myimag), 
+		vectorsleft  ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl,
+		vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr,
+		ilo, ihi, VECTOR(*myscale), abnrm, 
+		rconde ? VECTOR(*rconde) : 0, 
+		rcondv ? VECTOR(*rcondv) : 0, 
+		VECTOR(work), &lwork, VECTOR(iwork), info);
+		
+  lwork=(int) VECTOR(work)[0];
+  IGRAPH_CHECK(igraph_vector_resize(&work, lwork));
+  
+  igraphdgeevx_(&balanc, &jobvl, &jobvr, &sense, &n, &MATRIX(Acopy,0,0), 
+		&lda, VECTOR(*myreal), VECTOR(*myimag), 
+		vectorsleft  ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl,
+		vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr,
+		ilo, ihi, VECTOR(*myscale), abnrm, 
+		rconde ? VECTOR(*rconde) : 0, 
+		rcondv ? VECTOR(*rcondv) : 0, 
+		VECTOR(work), &lwork, VECTOR(iwork), info);
+		
+  if (*info < 0) {
+      IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK);
+  } else if (*info > 0) {    
+    if (error) {
+      IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK);
+    } else {
+      IGRAPH_WARNING("Cannot calculate eigenvalues (dgeev)");
+    }
+  }
+
+  if (!scale) {
+    igraph_vector_destroy(&vscale);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (!valuesimag) {
+    igraph_vector_destroy(&vimag);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (!valuesreal) {
+    igraph_vector_destroy(&vreal);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_int_destroy(&iwork);
+  igraph_vector_destroy(&work);
+  igraph_matrix_destroy(&Acopy);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+int igraph_lapack_dgehrd(const igraph_matrix_t *A, 
+			 int ilo, int ihi, 
+			 igraph_matrix_t *result) {
+  
+  int n=(int) igraph_matrix_nrow(A);
+  int lda=n;
+  int lwork=-1;
+  igraph_vector_t work;
+  igraph_real_t optwork;
+  igraph_vector_t tau;
+  igraph_matrix_t Acopy;
+  int info=0;
+  int i;
+  
+  if (igraph_matrix_ncol(A) != n) { 
+    IGRAPH_ERROR("Hessenberg reduction failed", IGRAPH_NONSQUARE);
+  }
+
+  if (ilo < 1 || ihi > n || ilo > ihi) { 
+    IGRAPH_ERROR("Invalid `ilo' and/or `ihi'", IGRAPH_EINVAL);
+  }
+
+  if (n <= 1) { 
+    IGRAPH_CHECK(igraph_matrix_update(result, A));
+    return 0;
+  }  
+
+  IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy);
+  IGRAPH_VECTOR_INIT_FINALLY(&tau, n-1);
+
+  igraphdgehrd_(&n, &ilo, &ihi, &MATRIX(Acopy, 0, 0), &lda, VECTOR(tau),
+		&optwork, &lwork, &info);
+
+  if (info != 0) { 
+    IGRAPH_ERROR("Internal Hessenberg transformation error", 
+		 IGRAPH_EINTERNAL);
+  }
+  
+  lwork=(int) optwork;
+  IGRAPH_VECTOR_INIT_FINALLY(&work, lwork);
+
+  igraphdgehrd_(&n, &ilo, &ihi, &MATRIX(Acopy, 0, 0), &lda, VECTOR(tau),
+		VECTOR(work), &lwork, &info);
+
+  if (info != 0) { 
+    IGRAPH_ERROR("Internal Hessenberg transformation error", 
+		 IGRAPH_EINTERNAL);
+  }
+
+  igraph_vector_destroy(&work);
+  igraph_vector_destroy(&tau);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  IGRAPH_CHECK(igraph_matrix_update(result, &Acopy));
+
+  igraph_matrix_destroy(&Acopy);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  for (i=0; i<n-2; i++) {
+    int j;
+    for (j=i+2; j<n; j++) {
+      MATRIX(*result, j, i) = 0.0;
+    }
+  }
+  
+  return 0;
+}
diff --git a/src/lapack/arpack.inc b/src/lapack/arpack.inc
new file mode 100644
index 0000000..1d949fb
--- /dev/null
+++ b/src/lapack/arpack.inc
@@ -0,0 +1 @@
+ARPACK = lapack/dnaupd.c lapack/dnaup2.c lapack/dgetv0.c lapack/dvout.c lapack/second.c lapack/dmout.c lapack/dnaitr.c lapack/ivout.c lapack/dnapps.c lapack/dnconv.c lapack/dneigh.c lapack/dlaqrb.c lapack/dngets.c lapack/dsortc.c lapack/dstatn.c lapack/dneupd.c lapack/dsaupd.c lapack/dsaup2.c lapack/dsaitr.c lapack/dsapps.c lapack/dsconv.c lapack/dseigt.c lapack/dstqrb.c lapack/dsgets.c lapack/dsortr.c lapack/dstats.c lapack/dseupd.c lapack/dsesrt.c 
diff --git a/src/lapack/blas.inc b/src/lapack/blas.inc
new file mode 100644
index 0000000..132604f
--- /dev/null
+++ b/src/lapack/blas.inc
@@ -0,0 +1 @@
+BLAS = lapack/dscal.c lapack/dswap.c lapack/lsame.c lapack/idamax.c lapack/daxpy.c lapack/dgemv.c lapack/dger.c lapack/dnrm2.c lapack/dgemm.c lapack/dcopy.c lapack/dtrmm.c lapack/dtrmv.c lapack/drot.c lapack/ddot.c lapack/dasum.c lapack/dsymv.c lapack/dsyr2k.c lapack/dsyr2.c lapack/dtrsm.c 
diff --git a/src/lapack/dasum.c b/src/lapack/dasum.c
new file mode 100644
index 0000000..8a20a6d
--- /dev/null
+++ b/src/lapack/dasum.c
@@ -0,0 +1,89 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+doublereal igraphdasum_(integer *n, doublereal *dx, integer *incx)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+    doublereal ret_val, d__1, d__2, d__3, d__4, d__5, d__6;
+
+    /* Local variables */
+    integer i__, m, mp1;
+    doublereal dtemp;
+    integer nincx;
+
+
+/*  Purpose   
+    =======   
+
+       DASUM takes the sum of the absolute values.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 3/93 to return if incx .le. 0.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dx;
+
+    /* Function Body */
+    ret_val = 0.;
+    dtemp = 0.;
+    if (*n <= 0 || *incx <= 0) {
+	return ret_val;
+    }
+    if (*incx == 1) {
+/*        code for increment equal to 1   
+
+
+          clean-up loop */
+
+	m = *n % 6;
+	if (m != 0) {
+	    i__1 = m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		dtemp += (d__1 = dx[i__], abs(d__1));
+	    }
+	    if (*n < 6) {
+		ret_val = dtemp;
+		return ret_val;
+	    }
+	}
+	mp1 = m + 1;
+	i__1 = *n;
+	for (i__ = mp1; i__ <= i__1; i__ += 6) {
+	    dtemp = dtemp + (d__1 = dx[i__], abs(d__1)) + (d__2 = dx[i__ + 1],
+		     abs(d__2)) + (d__3 = dx[i__ + 2], abs(d__3)) + (d__4 = 
+		    dx[i__ + 3], abs(d__4)) + (d__5 = dx[i__ + 4], abs(d__5)) 
+		    + (d__6 = dx[i__ + 5], abs(d__6));
+	}
+    } else {
+
+/*        code for increment not equal to 1 */
+
+	nincx = *n * *incx;
+	i__1 = nincx;
+	i__2 = *incx;
+	for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+	    dtemp += (d__1 = dx[i__], abs(d__1));
+	}
+    }
+    ret_val = dtemp;
+    return ret_val;
+} /* igraphdasum_ */
+
diff --git a/src/lapack/daxpy.c b/src/lapack/daxpy.c
new file mode 100644
index 0000000..be069d2
--- /dev/null
+++ b/src/lapack/daxpy.c
@@ -0,0 +1,97 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdaxpy_(integer *n, doublereal *da, doublereal *dx, 
+	integer *incx, doublereal *dy, integer *incy)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Local variables */
+    integer i__, m, ix, iy, mp1;
+
+
+/*  Purpose   
+    =======   
+
+       DAXPY constant times a vector plus a vector.   
+       uses unrolled loops for increments equal to one.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dy;
+    --dx;
+
+    /* Function Body */
+    if (*n <= 0) {
+	return 0;
+    }
+    if (*da == 0.) {
+	return 0;
+    }
+    if (*incx == 1 && *incy == 1) {
+
+/*        code for both increments equal to 1   
+
+
+          clean-up loop */
+
+	m = *n % 4;
+	if (m != 0) {
+	    i__1 = m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		dy[i__] += *da * dx[i__];
+	    }
+	}
+	if (*n < 4) {
+	    return 0;
+	}
+	mp1 = m + 1;
+	i__1 = *n;
+	for (i__ = mp1; i__ <= i__1; i__ += 4) {
+	    dy[i__] += *da * dx[i__];
+	    dy[i__ + 1] += *da * dx[i__ + 1];
+	    dy[i__ + 2] += *da * dx[i__ + 2];
+	    dy[i__ + 3] += *da * dx[i__ + 3];
+	}
+    } else {
+
+/*        code for unequal increments or equal increments   
+            not equal to 1 */
+
+	ix = 1;
+	iy = 1;
+	if (*incx < 0) {
+	    ix = (-(*n) + 1) * *incx + 1;
+	}
+	if (*incy < 0) {
+	    iy = (-(*n) + 1) * *incy + 1;
+	}
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    dy[iy] += *da * dx[ix];
+	    ix += *incx;
+	    iy += *incy;
+	}
+    }
+    return 0;
+} /* igraphdaxpy_ */
+
diff --git a/src/lapack/dcopy.c b/src/lapack/dcopy.c
new file mode 100644
index 0000000..239e4bc
--- /dev/null
+++ b/src/lapack/dcopy.c
@@ -0,0 +1,97 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdcopy_(integer *n, doublereal *dx, integer *incx, 
+	doublereal *dy, integer *incy)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Local variables */
+    integer i__, m, ix, iy, mp1;
+
+
+/*  Purpose   
+    =======   
+
+       DCOPY copies a vector, x, to a vector, y.   
+       uses unrolled loops for increments equal to one.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dy;
+    --dx;
+
+    /* Function Body */
+    if (*n <= 0) {
+	return 0;
+    }
+    if (*incx == 1 && *incy == 1) {
+
+/*        code for both increments equal to 1   
+
+
+          clean-up loop */
+
+	m = *n % 7;
+	if (m != 0) {
+	    i__1 = m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		dy[i__] = dx[i__];
+	    }
+	    if (*n < 7) {
+		return 0;
+	    }
+	}
+	mp1 = m + 1;
+	i__1 = *n;
+	for (i__ = mp1; i__ <= i__1; i__ += 7) {
+	    dy[i__] = dx[i__];
+	    dy[i__ + 1] = dx[i__ + 1];
+	    dy[i__ + 2] = dx[i__ + 2];
+	    dy[i__ + 3] = dx[i__ + 3];
+	    dy[i__ + 4] = dx[i__ + 4];
+	    dy[i__ + 5] = dx[i__ + 5];
+	    dy[i__ + 6] = dx[i__ + 6];
+	}
+    } else {
+
+/*        code for unequal increments or equal increments   
+            not equal to 1 */
+
+	ix = 1;
+	iy = 1;
+	if (*incx < 0) {
+	    ix = (-(*n) + 1) * *incx + 1;
+	}
+	if (*incy < 0) {
+	    iy = (-(*n) + 1) * *incy + 1;
+	}
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    dy[iy] = dx[ix];
+	    ix += *incx;
+	    iy += *incy;
+	}
+    }
+    return 0;
+} /* igraphdcopy_ */
+
diff --git a/src/lapack/ddot.c b/src/lapack/ddot.c
new file mode 100644
index 0000000..046a811
--- /dev/null
+++ b/src/lapack/ddot.c
@@ -0,0 +1,99 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+doublereal igraphddot_(integer *n, doublereal *dx, integer *incx, doublereal *dy, 
+	integer *incy)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal ret_val;
+
+    /* Local variables */
+    integer i__, m, ix, iy, mp1;
+    doublereal dtemp;
+
+
+/*  Purpose   
+    =======   
+
+       DDOT forms the dot product of two vectors.   
+       uses unrolled loops for increments equal to one.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dy;
+    --dx;
+
+    /* Function Body */
+    ret_val = 0.;
+    dtemp = 0.;
+    if (*n <= 0) {
+	return ret_val;
+    }
+    if (*incx == 1 && *incy == 1) {
+
+/*        code for both increments equal to 1   
+
+
+          clean-up loop */
+
+	m = *n % 5;
+	if (m != 0) {
+	    i__1 = m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		dtemp += dx[i__] * dy[i__];
+	    }
+	    if (*n < 5) {
+		ret_val = dtemp;
+		return ret_val;
+	    }
+	}
+	mp1 = m + 1;
+	i__1 = *n;
+	for (i__ = mp1; i__ <= i__1; i__ += 5) {
+	    dtemp = dtemp + dx[i__] * dy[i__] + dx[i__ + 1] * dy[i__ + 1] + 
+		    dx[i__ + 2] * dy[i__ + 2] + dx[i__ + 3] * dy[i__ + 3] + 
+		    dx[i__ + 4] * dy[i__ + 4];
+	}
+    } else {
+
+/*        code for unequal increments or equal increments   
+            not equal to 1 */
+
+	ix = 1;
+	iy = 1;
+	if (*incx < 0) {
+	    ix = (-(*n) + 1) * *incx + 1;
+	}
+	if (*incy < 0) {
+	    iy = (-(*n) + 1) * *incy + 1;
+	}
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    dtemp += dx[ix] * dy[iy];
+	    ix += *incx;
+	    iy += *incy;
+	}
+    }
+    ret_val = dtemp;
+    return ret_val;
+} /* igraphddot_ */
+
diff --git a/src/lapack/dgebak.c b/src/lapack/dgebak.c
new file mode 100644
index 0000000..e2f1e66
--- /dev/null
+++ b/src/lapack/dgebak.c
@@ -0,0 +1,223 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdgebak_(char *job, char *side, integer *n, integer *ilo, 
+	integer *ihi, doublereal *scale, integer *m, doublereal *v, integer *
+	ldv, integer *info)
+{
+    /* System generated locals */
+    integer v_dim1, v_offset, i__1;
+
+    /* Local variables */
+    integer i__, k;
+    doublereal s;
+    integer ii;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdswap_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    logical leftv;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical rightv;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DGEBAK forms the right or left eigenvectors of a real general matrix   
+    by backward transformation on the computed eigenvectors of the   
+    balanced matrix output by DGEBAL.   
+
+    Arguments   
+    =========   
+
+    JOB     (input) CHARACTER*1   
+            Specifies the type of backward transformation required:   
+            = 'N', do nothing, return immediately;   
+            = 'P', do backward transformation for permutation only;   
+            = 'S', do backward transformation for scaling only;   
+            = 'B', do backward transformations for both permutation and   
+                   scaling.   
+            JOB must be the same as the argument JOB supplied to DGEBAL.   
+
+    SIDE    (input) CHARACTER*1   
+            = 'R':  V contains right eigenvectors;   
+            = 'L':  V contains left eigenvectors.   
+
+    N       (input) INTEGER   
+            The number of rows of the matrix V.  N >= 0.   
+
+    ILO     (input) INTEGER   
+    IHI     (input) INTEGER   
+            The integers ILO and IHI determined by DGEBAL.   
+            1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0.   
+
+    SCALE   (input) DOUBLE PRECISION array, dimension (N)   
+            Details of the permutation and scaling factors, as returned   
+            by DGEBAL.   
+
+    M       (input) INTEGER   
+            The number of columns of the matrix V.  M >= 0.   
+
+    V       (input/output) DOUBLE PRECISION array, dimension (LDV,M)   
+            On entry, the matrix of right or left eigenvectors to be   
+            transformed, as returned by DHSEIN or DTREVC.   
+            On exit, V is overwritten by the transformed eigenvectors.   
+
+    LDV     (input) INTEGER   
+            The leading dimension of the array V. LDV >= max(1,N).   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+
+    =====================================================================   
+
+
+       Decode and Test the input parameters   
+
+       Parameter adjustments */
+    --scale;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+
+    /* Function Body */
+    rightv = igraphlsame_(side, "R");
+    leftv = igraphlsame_(side, "L");
+
+    *info = 0;
+    if (! igraphlsame_(job, "N") && ! igraphlsame_(job, "P") && ! igraphlsame_(job, "S") 
+	    && ! igraphlsame_(job, "B")) {
+	*info = -1;
+    } else if (! rightv && ! leftv) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -3;
+    } else if (*ilo < 1 || *ilo > max(1,*n)) {
+	*info = -4;
+    } else if (*ihi < min(*ilo,*n) || *ihi > *n) {
+	*info = -5;
+    } else if (*m < 0) {
+	*info = -7;
+    } else if (*ldv < max(1,*n)) {
+	*info = -9;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEBAK", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+    if (*m == 0) {
+	return 0;
+    }
+    if (igraphlsame_(job, "N")) {
+	return 0;
+    }
+
+    if (*ilo == *ihi) {
+	goto L30;
+    }
+
+/*     Backward balance */
+
+    if (igraphlsame_(job, "S") || igraphlsame_(job, "B")) {
+
+	if (rightv) {
+	    i__1 = *ihi;
+	    for (i__ = *ilo; i__ <= i__1; ++i__) {
+		s = scale[i__];
+		igraphdscal_(m, &s, &v[i__ + v_dim1], ldv);
+/* L10: */
+	    }
+	}
+
+	if (leftv) {
+	    i__1 = *ihi;
+	    for (i__ = *ilo; i__ <= i__1; ++i__) {
+		s = 1. / scale[i__];
+		igraphdscal_(m, &s, &v[i__ + v_dim1], ldv);
+/* L20: */
+	    }
+	}
+
+    }
+
+/*     Backward permutation   
+
+       For  I = ILO-1 step -1 until 1,   
+                IHI+1 step 1 until N do -- */
+
+L30:
+    if (igraphlsame_(job, "P") || igraphlsame_(job, "B")) {
+	if (rightv) {
+	    i__1 = *n;
+	    for (ii = 1; ii <= i__1; ++ii) {
+		i__ = ii;
+		if (i__ >= *ilo && i__ <= *ihi) {
+		    goto L40;
+		}
+		if (i__ < *ilo) {
+		    i__ = *ilo - ii;
+		}
+		k = (integer) scale[i__];
+		if (k == i__) {
+		    goto L40;
+		}
+		igraphdswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv);
+L40:
+		;
+	    }
+	}
+
+	if (leftv) {
+	    i__1 = *n;
+	    for (ii = 1; ii <= i__1; ++ii) {
+		i__ = ii;
+		if (i__ >= *ilo && i__ <= *ihi) {
+		    goto L50;
+		}
+		if (i__ < *ilo) {
+		    i__ = *ilo - ii;
+		}
+		k = (integer) scale[i__];
+		if (k == i__) {
+		    goto L50;
+		}
+		igraphdswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv);
+L50:
+		;
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DGEBAK */
+
+} /* igraphdgebak_ */
+
diff --git a/src/lapack/dgebal.c b/src/lapack/dgebal.c
new file mode 100644
index 0000000..ad90dd8
--- /dev/null
+++ b/src/lapack/dgebal.c
@@ -0,0 +1,399 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdgebal_(char *job, integer *n, doublereal *a, integer *
+	lda, integer *ilo, integer *ihi, doublereal *scale, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    doublereal c__, f, g;
+    integer i__, j, k, l, m;
+    doublereal r__, s, ca, ra;
+    integer ica, ira, iexc;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdswap_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    doublereal sfmin1, sfmin2, sfmax1, sfmax2;
+    extern doublereal igraphdlamch_(char *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    extern logical igraphdisnan_(doublereal *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical noconv;
+
+
+/*  -- LAPACK routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    DGEBAL balances a general real matrix A.  This involves, first,   
+    permuting A by a similarity transformation to isolate eigenvalues   
+    in the first 1 to ILO-1 and last IHI+1 to N elements on the   
+    diagonal; and second, applying a diagonal similarity transformation   
+    to rows and columns ILO to IHI to make the rows and columns as   
+    close in norm as possible.  Both steps are optional.   
+
+    Balancing may reduce the 1-norm of the matrix, and improve the   
+    accuracy of the computed eigenvalues and/or eigenvectors.   
+
+    Arguments   
+    =========   
+
+    JOB     (input) CHARACTER*1   
+            Specifies the operations to be performed on A:   
+            = 'N':  none:  simply set ILO = 1, IHI = N, SCALE(I) = 1.0   
+                    for i = 1,...,N;   
+            = 'P':  permute only;   
+            = 'S':  scale only;   
+            = 'B':  both permute and scale.   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the input matrix A.   
+            On exit,  A is overwritten by the balanced matrix.   
+            If JOB = 'N', A is not referenced.   
+            See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    ILO     (output) INTEGER   
+    IHI     (output) INTEGER   
+            ILO and IHI are set to integers such that on exit   
+            A(i,j) = 0 if i > j and j = 1,...,ILO-1 or I = IHI+1,...,N.   
+            If JOB = 'N' or 'S', ILO = 1 and IHI = N.   
+
+    SCALE   (output) DOUBLE PRECISION array, dimension (N)   
+            Details of the permutations and scaling factors applied to   
+            A.  If P(j) is the index of the row and column interchanged   
+            with row and column j and D(j) is the scaling factor   
+            applied to row and column j, then   
+            SCALE(j) = P(j)    for j = 1,...,ILO-1   
+                     = D(j)    for j = ILO,...,IHI   
+                     = P(j)    for j = IHI+1,...,N.   
+            The order in which the interchanges are made is N to IHI+1,   
+            then 1 to ILO-1.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit.   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+
+    Further Details   
+    ===============   
+
+    The permutations consist of row and column interchanges which put   
+    the matrix in the form   
+
+               ( T1   X   Y  )   
+       P A P = (  0   B   Z  )   
+               (  0   0   T2 )   
+
+    where T1 and T2 are upper triangular matrices whose eigenvalues lie   
+    along the diagonal.  The column indices ILO and IHI mark the starting   
+    and ending columns of the submatrix B. Balancing consists of applying   
+    a diagonal similarity transformation inv(D) * B * D to make the   
+    1-norms of each row of B and its corresponding column nearly equal.   
+    The output matrix is   
+
+       ( T1     X*D          Y    )   
+       (  0  inv(D)*B*D  inv(D)*Z ).   
+       (  0      0           T2   )   
+
+    Information about the permutations P and the diagonal matrix D is   
+    returned in the vector SCALE.   
+
+    This subroutine is based on the EISPACK routine BALANC.   
+
+    Modified by Tzu-Yi Chen, Computer Science Division, University of   
+      California at Berkeley, USA   
+
+    =====================================================================   
+
+
+       Test the input parameters   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --scale;
+
+    /* Function Body */
+    *info = 0;
+    if (! igraphlsame_(job, "N") && ! igraphlsame_(job, "P") && ! igraphlsame_(job, "S") 
+	    && ! igraphlsame_(job, "B")) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*n)) {
+	*info = -4;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEBAL", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+    k = 1;
+    l = *n;
+
+    if (*n == 0) {
+	goto L210;
+    }
+
+    if (igraphlsame_(job, "N")) {
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    scale[i__] = 1.;
+/* L10: */
+	}
+	goto L210;
+    }
+
+    if (igraphlsame_(job, "S")) {
+	goto L120;
+    }
+
+/*     Permutation to isolate eigenvalues if possible */
+
+    goto L50;
+
+/*     Row and column exchange. */
+
+L20:
+    scale[m] = (doublereal) j;
+    if (j == m) {
+	goto L30;
+    }
+
+    igraphdswap_(&l, &a[j * a_dim1 + 1], &c__1, &a[m * a_dim1 + 1], &c__1);
+    i__1 = *n - k + 1;
+    igraphdswap_(&i__1, &a[j + k * a_dim1], lda, &a[m + k * a_dim1], lda);
+
+L30:
+    switch (iexc) {
+	case 1:  goto L40;
+	case 2:  goto L80;
+    }
+
+/*     Search for rows isolating an eigenvalue and push them down. */
+
+L40:
+    if (l == 1) {
+	goto L210;
+    }
+    --l;
+
+L50:
+    for (j = l; j >= 1; --j) {
+
+	i__1 = l;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    if (i__ == j) {
+		goto L60;
+	    }
+	    if (a[j + i__ * a_dim1] != 0.) {
+		goto L70;
+	    }
+L60:
+	    ;
+	}
+
+	m = l;
+	iexc = 1;
+	goto L20;
+L70:
+	;
+    }
+
+    goto L90;
+
+/*     Search for columns isolating an eigenvalue and push them left. */
+
+L80:
+    ++k;
+
+L90:
+    i__1 = l;
+    for (j = k; j <= i__1; ++j) {
+
+	i__2 = l;
+	for (i__ = k; i__ <= i__2; ++i__) {
+	    if (i__ == j) {
+		goto L100;
+	    }
+	    if (a[i__ + j * a_dim1] != 0.) {
+		goto L110;
+	    }
+L100:
+	    ;
+	}
+
+	m = k;
+	iexc = 2;
+	goto L20;
+L110:
+	;
+    }
+
+L120:
+    i__1 = l;
+    for (i__ = k; i__ <= i__1; ++i__) {
+	scale[i__] = 1.;
+/* L130: */
+    }
+
+    if (igraphlsame_(job, "P")) {
+	goto L210;
+    }
+
+/*     Balance the submatrix in rows K to L.   
+
+       Iterative loop for norm reduction */
+
+    sfmin1 = igraphdlamch_("S") / igraphdlamch_("P");
+    sfmax1 = 1. / sfmin1;
+    sfmin2 = sfmin1 * 2.;
+    sfmax2 = 1. / sfmin2;
+L140:
+    noconv = FALSE_;
+
+    i__1 = l;
+    for (i__ = k; i__ <= i__1; ++i__) {
+	c__ = 0.;
+	r__ = 0.;
+
+	i__2 = l;
+	for (j = k; j <= i__2; ++j) {
+	    if (j == i__) {
+		goto L150;
+	    }
+	    c__ += (d__1 = a[j + i__ * a_dim1], abs(d__1));
+	    r__ += (d__1 = a[i__ + j * a_dim1], abs(d__1));
+L150:
+	    ;
+	}
+	ica = igraphidamax_(&l, &a[i__ * a_dim1 + 1], &c__1);
+	ca = (d__1 = a[ica + i__ * a_dim1], abs(d__1));
+	i__2 = *n - k + 1;
+	ira = igraphidamax_(&i__2, &a[i__ + k * a_dim1], lda);
+	ra = (d__1 = a[i__ + (ira + k - 1) * a_dim1], abs(d__1));
+
+/*        Guard against zero C or R due to underflow. */
+
+	if (c__ == 0. || r__ == 0.) {
+	    goto L200;
+	}
+	g = r__ / 2.;
+	f = 1.;
+	s = c__ + r__;
+L160:
+/* Computing MAX */
+	d__1 = max(f,c__);
+/* Computing MIN */
+	d__2 = min(r__,g);
+	if (c__ >= g || max(d__1,ca) >= sfmax2 || min(d__2,ra) <= sfmin2) {
+	    goto L170;
+	}
+	d__1 = c__ + f + ca + r__ + g + ra;
+	if (igraphdisnan_(&d__1)) {
+
+/*           Exit if NaN to avoid infinite loop */
+
+	    *info = -3;
+	    i__2 = -(*info);
+	    igraphxerbla_("DGEBAL", &i__2, (ftnlen)6);
+	    return 0;
+	}
+	f *= 2.;
+	c__ *= 2.;
+	ca *= 2.;
+	r__ /= 2.;
+	g /= 2.;
+	ra /= 2.;
+	goto L160;
+
+L170:
+	g = c__ / 2.;
+L180:
+/* Computing MIN */
+	d__1 = min(f,c__), d__1 = min(d__1,g);
+	if (g < r__ || max(r__,ra) >= sfmax2 || min(d__1,ca) <= sfmin2) {
+	    goto L190;
+	}
+	f /= 2.;
+	c__ /= 2.;
+	g /= 2.;
+	ca /= 2.;
+	r__ *= 2.;
+	ra *= 2.;
+	goto L180;
+
+/*        Now balance. */
+
+L190:
+	if (c__ + r__ >= s * .95) {
+	    goto L200;
+	}
+	if (f < 1. && scale[i__] < 1.) {
+	    if (f * scale[i__] <= sfmin1) {
+		goto L200;
+	    }
+	}
+	if (f > 1. && scale[i__] > 1.) {
+	    if (scale[i__] >= sfmax1 / f) {
+		goto L200;
+	    }
+	}
+	g = 1. / f;
+	scale[i__] *= f;
+	noconv = TRUE_;
+
+	i__2 = *n - k + 1;
+	igraphdscal_(&i__2, &g, &a[i__ + k * a_dim1], lda);
+	igraphdscal_(&l, &f, &a[i__ * a_dim1 + 1], &c__1);
+
+L200:
+	;
+    }
+
+    if (noconv) {
+	goto L140;
+    }
+
+L210:
+    *ilo = k;
+    *ihi = l;
+
+    return 0;
+
+/*     End of DGEBAL */
+
+} /* igraphdgebal_ */
+
diff --git a/src/lapack/dgeev.c b/src/lapack/dgeev.c
new file mode 100644
index 0000000..07844bd
--- /dev/null
+++ b/src/lapack/dgeev.c
@@ -0,0 +1,552 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__0 = 0;
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdgeev_(char *jobvl, char *jobvr, integer *n, doublereal *
+	a, integer *lda, doublereal *wr, doublereal *wi, doublereal *vl, 
+	integer *ldvl, doublereal *vr, integer *ldvr, doublereal *work, 
+	integer *lwork, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, 
+	    i__2, i__3;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, k;
+    doublereal r__, cs, sn;
+    integer ihi;
+    doublereal scl;
+    integer ilo;
+    doublereal dum[1], eps;
+    integer ibal;
+    char side[1];
+    doublereal anrm;
+    integer ierr, itau;
+    extern /* Subroutine */ int igraphdrot_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *);
+    integer iwrk, nout;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    extern logical igraphlsame_(char *, char *);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlabad_(doublereal *, doublereal *), igraphdgebak_(
+	    char *, char *, integer *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *), 
+	    igraphdgebal_(char *, integer *, doublereal *, integer *, integer *, 
+	    integer *, doublereal *, integer *);
+    logical scalea;
+    extern doublereal igraphdlamch_(char *);
+    doublereal cscale;
+    extern doublereal igraphdlange_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *);
+    extern /* Subroutine */ int igraphdgehrd_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *), igraphdlascl_(char *, integer *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlartg_(doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *), igraphxerbla_(char *, integer *, ftnlen);
+    logical select[1];
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    doublereal bignum;
+    extern /* Subroutine */ int igraphdorghr_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *), igraphdhseqr_(char *, char *, integer *, integer *, integer 
+	    *, doublereal *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, integer *), igraphdtrevc_(char *, char *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, integer *, integer *, doublereal *, integer *);
+    integer minwrk, maxwrk;
+    logical wantvl;
+    doublereal smlnum;
+    integer hswork;
+    logical lquery, wantvr;
+
+
+/*  -- LAPACK driver routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DGEEV computes for an N-by-N real nonsymmetric matrix A, the   
+    eigenvalues and, optionally, the left and/or right eigenvectors.   
+
+    The right eigenvector v(j) of A satisfies   
+                     A * v(j) = lambda(j) * v(j)   
+    where lambda(j) is its eigenvalue.   
+    The left eigenvector u(j) of A satisfies   
+                  u(j)**T * A = lambda(j) * u(j)**T   
+    where u(j)**T denotes the transpose of u(j).   
+
+    The computed eigenvectors are normalized to have Euclidean norm   
+    equal to 1 and largest component real.   
+
+    Arguments   
+    =========   
+
+    JOBVL   (input) CHARACTER*1   
+            = 'N': left eigenvectors of A are not computed;   
+            = 'V': left eigenvectors of A are computed.   
+
+    JOBVR   (input) CHARACTER*1   
+            = 'N': right eigenvectors of A are not computed;   
+            = 'V': right eigenvectors of A are computed.   
+
+    N       (input) INTEGER   
+            The order of the matrix A. N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the N-by-N matrix A.   
+            On exit, A has been overwritten.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    WR      (output) DOUBLE PRECISION array, dimension (N)   
+    WI      (output) DOUBLE PRECISION array, dimension (N)   
+            WR and WI contain the real and imaginary parts,   
+            respectively, of the computed eigenvalues.  Complex   
+            conjugate pairs of eigenvalues appear consecutively   
+            with the eigenvalue having the positive imaginary part   
+            first.   
+
+    VL      (output) DOUBLE PRECISION array, dimension (LDVL,N)   
+            If JOBVL = 'V', the left eigenvectors u(j) are stored one   
+            after another in the columns of VL, in the same order   
+            as their eigenvalues.   
+            If JOBVL = 'N', VL is not referenced.   
+            If the j-th eigenvalue is real, then u(j) = VL(:,j),   
+            the j-th column of VL.   
+            If the j-th and (j+1)-st eigenvalues form a complex   
+            conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and   
+            u(j+1) = VL(:,j) - i*VL(:,j+1).   
+
+    LDVL    (input) INTEGER   
+            The leading dimension of the array VL.  LDVL >= 1; if   
+            JOBVL = 'V', LDVL >= N.   
+
+    VR      (output) DOUBLE PRECISION array, dimension (LDVR,N)   
+            If JOBVR = 'V', the right eigenvectors v(j) are stored one   
+            after another in the columns of VR, in the same order   
+            as their eigenvalues.   
+            If JOBVR = 'N', VR is not referenced.   
+            If the j-th eigenvalue is real, then v(j) = VR(:,j),   
+            the j-th column of VR.   
+            If the j-th and (j+1)-st eigenvalues form a complex   
+            conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and   
+            v(j+1) = VR(:,j) - i*VR(:,j+1).   
+
+    LDVR    (input) INTEGER   
+            The leading dimension of the array VR.  LDVR >= 1; if   
+            JOBVR = 'V', LDVR >= N.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.  LWORK >= max(1,3*N), and   
+            if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N.  For good   
+            performance, LWORK must generally be larger.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+            > 0:  if INFO = i, the QR algorithm failed to compute all the   
+                  eigenvalues, and no eigenvectors have been computed;   
+                  elements i+1:N of WR and WI contain eigenvalues which   
+                  have converged.   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --wr;
+    --wi;
+    vl_dim1 = *ldvl;
+    vl_offset = 1 + vl_dim1;
+    vl -= vl_offset;
+    vr_dim1 = *ldvr;
+    vr_offset = 1 + vr_dim1;
+    vr -= vr_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    lquery = *lwork == -1;
+    wantvl = igraphlsame_(jobvl, "V");
+    wantvr = igraphlsame_(jobvr, "V");
+    if (! wantvl && ! igraphlsame_(jobvl, "N")) {
+	*info = -1;
+    } else if (! wantvr && ! igraphlsame_(jobvr, "N")) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -3;
+    } else if (*lda < max(1,*n)) {
+	*info = -5;
+    } else if (*ldvl < 1 || wantvl && *ldvl < *n) {
+	*info = -9;
+    } else if (*ldvr < 1 || wantvr && *ldvr < *n) {
+	*info = -11;
+    }
+
+/*     Compute workspace   
+        (Note: Comments in the code beginning "Workspace:" describe the   
+         minimal amount of workspace needed at that point in the code,   
+         as well as the preferred amount for good performance.   
+         NB refers to the optimal block size for the immediately   
+         following subroutine, as returned by ILAENV.   
+         HSWORK refers to the workspace preferred by DHSEQR, as   
+         calculated below. HSWORK is computed assuming ILO=1 and IHI=N,   
+         the worst case.) */
+
+    if (*info == 0) {
+	if (*n == 0) {
+	    minwrk = 1;
+	    maxwrk = 1;
+	} else {
+	    maxwrk = (*n << 1) + *n * igraphilaenv_(&c__1, "DGEHRD", " ", n, &c__1, 
+		    n, &c__0, (ftnlen)6, (ftnlen)1);
+	    if (wantvl) {
+		minwrk = *n << 2;
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * igraphilaenv_(&c__1, 
+			"DORGHR", " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)
+			1);
+		maxwrk = max(i__1,i__2);
+		igraphdhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[
+			1], &vl[vl_offset], ldvl, &work[1], &c_n1, info);
+		hswork = (integer) work[1];
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = *
+			n + hswork;
+		maxwrk = max(i__1,i__2);
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n << 2;
+		maxwrk = max(i__1,i__2);
+	    } else if (wantvr) {
+		minwrk = *n << 2;
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * igraphilaenv_(&c__1, 
+			"DORGHR", " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)
+			1);
+		maxwrk = max(i__1,i__2);
+		igraphdhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[
+			1], &vr[vr_offset], ldvr, &work[1], &c_n1, info);
+		hswork = (integer) work[1];
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = *
+			n + hswork;
+		maxwrk = max(i__1,i__2);
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n << 2;
+		maxwrk = max(i__1,i__2);
+	    } else {
+		minwrk = *n * 3;
+		igraphdhseqr_("E", "N", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[
+			1], &vr[vr_offset], ldvr, &work[1], &c_n1, info);
+		hswork = (integer) work[1];
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = *
+			n + hswork;
+		maxwrk = max(i__1,i__2);
+	    }
+	    maxwrk = max(maxwrk,minwrk);
+	}
+	work[1] = (doublereal) maxwrk;
+
+	if (*lwork < minwrk && ! lquery) {
+	    *info = -13;
+	}
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEEV ", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+/*     Get machine constants */
+
+    eps = igraphdlamch_("P");
+    smlnum = igraphdlamch_("S");
+    bignum = 1. / smlnum;
+    igraphdlabad_(&smlnum, &bignum);
+    smlnum = sqrt(smlnum) / eps;
+    bignum = 1. / smlnum;
+
+/*     Scale A if max element outside range [SMLNUM,BIGNUM] */
+
+    anrm = igraphdlange_("M", n, n, &a[a_offset], lda, dum);
+    scalea = FALSE_;
+    if (anrm > 0. && anrm < smlnum) {
+	scalea = TRUE_;
+	cscale = smlnum;
+    } else if (anrm > bignum) {
+	scalea = TRUE_;
+	cscale = bignum;
+    }
+    if (scalea) {
+	igraphdlascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, &
+		ierr);
+    }
+
+/*     Balance the matrix   
+       (Workspace: need N) */
+
+    ibal = 1;
+    igraphdgebal_("B", n, &a[a_offset], lda, &ilo, &ihi, &work[ibal], &ierr);
+
+/*     Reduce to upper Hessenberg form   
+       (Workspace: need 3*N, prefer 2*N+N*NB) */
+
+    itau = ibal + *n;
+    iwrk = itau + *n;
+    i__1 = *lwork - iwrk + 1;
+    igraphdgehrd_(n, &ilo, &ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1,
+	     &ierr);
+
+    if (wantvl) {
+
+/*        Want left eigenvectors   
+          Copy Householder vectors to VL */
+
+	*(unsigned char *)side = 'L';
+	igraphdlacpy_("L", n, n, &a[a_offset], lda, &vl[vl_offset], ldvl)
+		;
+
+/*        Generate orthogonal matrix in VL   
+          (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB) */
+
+	i__1 = *lwork - iwrk + 1;
+	igraphdorghr_(n, &ilo, &ihi, &vl[vl_offset], ldvl, &work[itau], &work[iwrk],
+		 &i__1, &ierr);
+
+/*        Perform QR iteration, accumulating Schur vectors in VL   
+          (Workspace: need N+1, prefer N+HSWORK (see comments) ) */
+
+	iwrk = itau;
+	i__1 = *lwork - iwrk + 1;
+	igraphdhseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], &
+		vl[vl_offset], ldvl, &work[iwrk], &i__1, info);
+
+	if (wantvr) {
+
+/*           Want left and right eigenvectors   
+             Copy Schur vectors to VR */
+
+	    *(unsigned char *)side = 'B';
+	    igraphdlacpy_("F", n, n, &vl[vl_offset], ldvl, &vr[vr_offset], ldvr);
+	}
+
+    } else if (wantvr) {
+
+/*        Want right eigenvectors   
+          Copy Householder vectors to VR */
+
+	*(unsigned char *)side = 'R';
+	igraphdlacpy_("L", n, n, &a[a_offset], lda, &vr[vr_offset], ldvr)
+		;
+
+/*        Generate orthogonal matrix in VR   
+          (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB) */
+
+	i__1 = *lwork - iwrk + 1;
+	igraphdorghr_(n, &ilo, &ihi, &vr[vr_offset], ldvr, &work[itau], &work[iwrk],
+		 &i__1, &ierr);
+
+/*        Perform QR iteration, accumulating Schur vectors in VR   
+          (Workspace: need N+1, prefer N+HSWORK (see comments) ) */
+
+	iwrk = itau;
+	i__1 = *lwork - iwrk + 1;
+	igraphdhseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], &
+		vr[vr_offset], ldvr, &work[iwrk], &i__1, info);
+
+    } else {
+
+/*        Compute eigenvalues only   
+          (Workspace: need N+1, prefer N+HSWORK (see comments) ) */
+
+	iwrk = itau;
+	i__1 = *lwork - iwrk + 1;
+	igraphdhseqr_("E", "N", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], &
+		vr[vr_offset], ldvr, &work[iwrk], &i__1, info);
+    }
+
+/*     If INFO > 0 from DHSEQR, then quit */
+
+    if (*info > 0) {
+	goto L50;
+    }
+
+    if (wantvl || wantvr) {
+
+/*        Compute left and/or right eigenvectors   
+          (Workspace: need 4*N) */
+
+	igraphdtrevc_(side, "B", select, n, &a[a_offset], lda, &vl[vl_offset], ldvl,
+		 &vr[vr_offset], ldvr, n, &nout, &work[iwrk], &ierr);
+    }
+
+    if (wantvl) {
+
+/*        Undo balancing of left eigenvectors   
+          (Workspace: need N) */
+
+	igraphdgebak_("B", "L", n, &ilo, &ihi, &work[ibal], n, &vl[vl_offset], ldvl,
+		 &ierr);
+
+/*        Normalize left eigenvectors and make largest component real */
+
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    if (wi[i__] == 0.) {
+		scl = 1. / igraphdnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1);
+	    } else if (wi[i__] > 0.) {
+		d__1 = igraphdnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &vl[(i__ + 1) * vl_dim1 + 1], &c__1);
+		scl = 1. / igraphdlapy2_(&d__1, &d__2);
+		igraphdscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vl[(i__ + 1) * vl_dim1 + 1], &c__1);
+		i__2 = *n;
+		for (k = 1; k <= i__2; ++k) {
+/* Computing 2nd power */
+		    d__1 = vl[k + i__ * vl_dim1];
+/* Computing 2nd power */
+		    d__2 = vl[k + (i__ + 1) * vl_dim1];
+		    work[iwrk + k - 1] = d__1 * d__1 + d__2 * d__2;
+/* L10: */
+		}
+		k = igraphidamax_(n, &work[iwrk], &c__1);
+		igraphdlartg_(&vl[k + i__ * vl_dim1], &vl[k + (i__ + 1) * vl_dim1], 
+			&cs, &sn, &r__);
+		igraphdrot_(n, &vl[i__ * vl_dim1 + 1], &c__1, &vl[(i__ + 1) * 
+			vl_dim1 + 1], &c__1, &cs, &sn);
+		vl[k + (i__ + 1) * vl_dim1] = 0.;
+	    }
+/* L20: */
+	}
+    }
+
+    if (wantvr) {
+
+/*        Undo balancing of right eigenvectors   
+          (Workspace: need N) */
+
+	igraphdgebak_("B", "R", n, &ilo, &ihi, &work[ibal], n, &vr[vr_offset], ldvr,
+		 &ierr);
+
+/*        Normalize right eigenvectors and make largest component real */
+
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    if (wi[i__] == 0.) {
+		scl = 1. / igraphdnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1);
+	    } else if (wi[i__] > 0.) {
+		d__1 = igraphdnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &vr[(i__ + 1) * vr_dim1 + 1], &c__1);
+		scl = 1. / igraphdlapy2_(&d__1, &d__2);
+		igraphdscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vr[(i__ + 1) * vr_dim1 + 1], &c__1);
+		i__2 = *n;
+		for (k = 1; k <= i__2; ++k) {
+/* Computing 2nd power */
+		    d__1 = vr[k + i__ * vr_dim1];
+/* Computing 2nd power */
+		    d__2 = vr[k + (i__ + 1) * vr_dim1];
+		    work[iwrk + k - 1] = d__1 * d__1 + d__2 * d__2;
+/* L30: */
+		}
+		k = igraphidamax_(n, &work[iwrk], &c__1);
+		igraphdlartg_(&vr[k + i__ * vr_dim1], &vr[k + (i__ + 1) * vr_dim1], 
+			&cs, &sn, &r__);
+		igraphdrot_(n, &vr[i__ * vr_dim1 + 1], &c__1, &vr[(i__ + 1) * 
+			vr_dim1 + 1], &c__1, &cs, &sn);
+		vr[k + (i__ + 1) * vr_dim1] = 0.;
+	    }
+/* L40: */
+	}
+    }
+
+/*     Undo scaling if necessary */
+
+L50:
+    if (scalea) {
+	i__1 = *n - *info;
+/* Computing MAX */
+	i__3 = *n - *info;
+	i__2 = max(i__3,1);
+	igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[*info + 
+		1], &i__2, &ierr);
+	i__1 = *n - *info;
+/* Computing MAX */
+	i__3 = *n - *info;
+	i__2 = max(i__3,1);
+	igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[*info + 
+		1], &i__2, &ierr);
+	if (*info > 0) {
+	    i__1 = ilo - 1;
+	    igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[1], 
+		    n, &ierr);
+	    i__1 = ilo - 1;
+	    igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[1], 
+		    n, &ierr);
+	}
+    }
+
+    work[1] = (doublereal) maxwrk;
+    return 0;
+
+/*     End of DGEEV */
+
+} /* igraphdgeev_ */
+
diff --git a/src/lapack/dgeevx.c b/src/lapack/dgeevx.c
new file mode 100644
index 0000000..9b1c400
--- /dev/null
+++ b/src/lapack/dgeevx.c
@@ -0,0 +1,687 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__0 = 0;
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdgeevx_(char *balanc, char *jobvl, char *jobvr, char *
+	sense, integer *n, doublereal *a, integer *lda, doublereal *wr, 
+	doublereal *wi, doublereal *vl, integer *ldvl, doublereal *vr, 
+	integer *ldvr, integer *ilo, integer *ihi, doublereal *scale, 
+	doublereal *abnrm, doublereal *rconde, doublereal *rcondv, doublereal 
+	*work, integer *lwork, integer *iwork, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, 
+	    i__2, i__3;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, k;
+    doublereal r__, cs, sn;
+    char job[1];
+    doublereal scl, dum[1], eps;
+    char side[1];
+    doublereal anrm;
+    integer ierr, itau;
+    extern /* Subroutine */ int igraphdrot_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *);
+    integer iwrk, nout;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    integer icond;
+    extern logical igraphlsame_(char *, char *);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlabad_(doublereal *, doublereal *), igraphdgebak_(
+	    char *, char *, integer *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *), 
+	    igraphdgebal_(char *, integer *, doublereal *, integer *, integer *, 
+	    integer *, doublereal *, integer *);
+    logical scalea;
+    extern doublereal igraphdlamch_(char *);
+    doublereal cscale;
+    extern doublereal igraphdlange_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *);
+    extern /* Subroutine */ int igraphdgehrd_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *), igraphdlascl_(char *, integer *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlartg_(doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *), igraphxerbla_(char *, integer *, ftnlen);
+    logical select[1];
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    doublereal bignum;
+    extern /* Subroutine */ int igraphdorghr_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *), igraphdhseqr_(char *, char *, integer *, integer *, integer 
+	    *, doublereal *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, integer *), igraphdtrevc_(char *, char *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, integer *, integer *, doublereal *, integer *), igraphdtrsna_(char *, char *, logical *, integer *, doublereal 
+	    *, integer *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *, integer *);
+    integer minwrk, maxwrk;
+    logical wantvl, wntsnb;
+    integer hswork;
+    logical wntsne;
+    doublereal smlnum;
+    logical lquery, wantvr, wntsnn, wntsnv;
+
+
+/*  -- LAPACK driver routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DGEEVX computes for an N-by-N real nonsymmetric matrix A, the   
+    eigenvalues and, optionally, the left and/or right eigenvectors.   
+
+    Optionally also, it computes a balancing transformation to improve   
+    the conditioning of the eigenvalues and eigenvectors (ILO, IHI,   
+    SCALE, and ABNRM), reciprocal condition numbers for the eigenvalues   
+    (RCONDE), and reciprocal condition numbers for the right   
+    eigenvectors (RCONDV).   
+
+    The right eigenvector v(j) of A satisfies   
+                     A * v(j) = lambda(j) * v(j)   
+    where lambda(j) is its eigenvalue.   
+    The left eigenvector u(j) of A satisfies   
+                  u(j)**T * A = lambda(j) * u(j)**T   
+    where u(j)**T denotes the transpose of u(j).   
+
+    The computed eigenvectors are normalized to have Euclidean norm   
+    equal to 1 and largest component real.   
+
+    Balancing a matrix means permuting the rows and columns to make it   
+    more nearly upper triangular, and applying a diagonal similarity   
+    transformation D * A * D**(-1), where D is a diagonal matrix, to   
+    make its rows and columns closer in norm and the condition numbers   
+    of its eigenvalues and eigenvectors smaller.  The computed   
+    reciprocal condition numbers correspond to the balanced matrix.   
+    Permuting rows and columns will not change the condition numbers   
+    (in exact arithmetic) but diagonal scaling will.  For further   
+    explanation of balancing, see section 4.10.2 of the LAPACK   
+    Users' Guide.   
+
+    Arguments   
+    =========   
+
+    BALANC  (input) CHARACTER*1   
+            Indicates how the input matrix should be diagonally scaled   
+            and/or permuted to improve the conditioning of its   
+            eigenvalues.   
+            = 'N': Do not diagonally scale or permute;   
+            = 'P': Perform permutations to make the matrix more nearly   
+                   upper triangular. Do not diagonally scale;   
+            = 'S': Diagonally scale the matrix, i.e. replace A by   
+                   D*A*D**(-1), where D is a diagonal matrix chosen   
+                   to make the rows and columns of A more equal in   
+                   norm. Do not permute;   
+            = 'B': Both diagonally scale and permute A.   
+
+            Computed reciprocal condition numbers will be for the matrix   
+            after balancing and/or permuting. Permuting does not change   
+            condition numbers (in exact arithmetic), but balancing does.   
+
+    JOBVL   (input) CHARACTER*1   
+            = 'N': left eigenvectors of A are not computed;   
+            = 'V': left eigenvectors of A are computed.   
+            If SENSE = 'E' or 'B', JOBVL must = 'V'.   
+
+    JOBVR   (input) CHARACTER*1   
+            = 'N': right eigenvectors of A are not computed;   
+            = 'V': right eigenvectors of A are computed.   
+            If SENSE = 'E' or 'B', JOBVR must = 'V'.   
+
+    SENSE   (input) CHARACTER*1   
+            Determines which reciprocal condition numbers are computed.   
+            = 'N': None are computed;   
+            = 'E': Computed for eigenvalues only;   
+            = 'V': Computed for right eigenvectors only;   
+            = 'B': Computed for eigenvalues and right eigenvectors.   
+
+            If SENSE = 'E' or 'B', both left and right eigenvectors   
+            must also be computed (JOBVL = 'V' and JOBVR = 'V').   
+
+    N       (input) INTEGER   
+            The order of the matrix A. N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the N-by-N matrix A.   
+            On exit, A has been overwritten.  If JOBVL = 'V' or   
+            JOBVR = 'V', A contains the real Schur form of the balanced   
+            version of the input matrix A.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    WR      (output) DOUBLE PRECISION array, dimension (N)   
+    WI      (output) DOUBLE PRECISION array, dimension (N)   
+            WR and WI contain the real and imaginary parts,   
+            respectively, of the computed eigenvalues.  Complex   
+            conjugate pairs of eigenvalues will appear consecutively   
+            with the eigenvalue having the positive imaginary part   
+            first.   
+
+    VL      (output) DOUBLE PRECISION array, dimension (LDVL,N)   
+            If JOBVL = 'V', the left eigenvectors u(j) are stored one   
+            after another in the columns of VL, in the same order   
+            as their eigenvalues.   
+            If JOBVL = 'N', VL is not referenced.   
+            If the j-th eigenvalue is real, then u(j) = VL(:,j),   
+            the j-th column of VL.   
+            If the j-th and (j+1)-st eigenvalues form a complex   
+            conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and   
+            u(j+1) = VL(:,j) - i*VL(:,j+1).   
+
+    LDVL    (input) INTEGER   
+            The leading dimension of the array VL.  LDVL >= 1; if   
+            JOBVL = 'V', LDVL >= N.   
+
+    VR      (output) DOUBLE PRECISION array, dimension (LDVR,N)   
+            If JOBVR = 'V', the right eigenvectors v(j) are stored one   
+            after another in the columns of VR, in the same order   
+            as their eigenvalues.   
+            If JOBVR = 'N', VR is not referenced.   
+            If the j-th eigenvalue is real, then v(j) = VR(:,j),   
+            the j-th column of VR.   
+            If the j-th and (j+1)-st eigenvalues form a complex   
+            conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and   
+            v(j+1) = VR(:,j) - i*VR(:,j+1).   
+
+    LDVR    (input) INTEGER   
+            The leading dimension of the array VR.  LDVR >= 1, and if   
+            JOBVR = 'V', LDVR >= N.   
+
+    ILO     (output) INTEGER   
+    IHI     (output) INTEGER   
+            ILO and IHI are integer values determined when A was   
+            balanced.  The balanced A(i,j) = 0 if I > J and   
+            J = 1,...,ILO-1 or I = IHI+1,...,N.   
+
+    SCALE   (output) DOUBLE PRECISION array, dimension (N)   
+            Details of the permutations and scaling factors applied   
+            when balancing A.  If P(j) is the index of the row and column   
+            interchanged with row and column j, and D(j) is the scaling   
+            factor applied to row and column j, then   
+            SCALE(J) = P(J),    for J = 1,...,ILO-1   
+                     = D(J),    for J = ILO,...,IHI   
+                     = P(J)     for J = IHI+1,...,N.   
+            The order in which the interchanges are made is N to IHI+1,   
+            then 1 to ILO-1.   
+
+    ABNRM   (output) DOUBLE PRECISION   
+            The one-norm of the balanced matrix (the maximum   
+            of the sum of absolute values of elements of any column).   
+
+    RCONDE  (output) DOUBLE PRECISION array, dimension (N)   
+            RCONDE(j) is the reciprocal condition number of the j-th   
+            eigenvalue.   
+
+    RCONDV  (output) DOUBLE PRECISION array, dimension (N)   
+            RCONDV(j) is the reciprocal condition number of the j-th   
+            right eigenvector.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.   If SENSE = 'N' or 'E',   
+            LWORK >= max(1,2*N), and if JOBVL = 'V' or JOBVR = 'V',   
+            LWORK >= 3*N.  If SENSE = 'V' or 'B', LWORK >= N*(N+6).   
+            For good performance, LWORK must generally be larger.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    IWORK   (workspace) INTEGER array, dimension (2*N-2)   
+            If SENSE = 'N' or 'E', not referenced.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+            > 0:  if INFO = i, the QR algorithm failed to compute all the   
+                  eigenvalues, and no eigenvectors or condition numbers   
+                  have been computed; elements 1:ILO-1 and i+1:N of WR   
+                  and WI contain eigenvalues which have converged.   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --wr;
+    --wi;
+    vl_dim1 = *ldvl;
+    vl_offset = 1 + vl_dim1;
+    vl -= vl_offset;
+    vr_dim1 = *ldvr;
+    vr_offset = 1 + vr_dim1;
+    vr -= vr_offset;
+    --scale;
+    --rconde;
+    --rcondv;
+    --work;
+    --iwork;
+
+    /* Function Body */
+    *info = 0;
+    lquery = *lwork == -1;
+    wantvl = igraphlsame_(jobvl, "V");
+    wantvr = igraphlsame_(jobvr, "V");
+    wntsnn = igraphlsame_(sense, "N");
+    wntsne = igraphlsame_(sense, "E");
+    wntsnv = igraphlsame_(sense, "V");
+    wntsnb = igraphlsame_(sense, "B");
+    if (! (igraphlsame_(balanc, "N") || igraphlsame_(balanc, "S") || igraphlsame_(balanc, "P") 
+	    || igraphlsame_(balanc, "B"))) {
+	*info = -1;
+    } else if (! wantvl && ! igraphlsame_(jobvl, "N")) {
+	*info = -2;
+    } else if (! wantvr && ! igraphlsame_(jobvr, "N")) {
+	*info = -3;
+    } else if (! (wntsnn || wntsne || wntsnb || wntsnv) || (wntsne || wntsnb) 
+	    && ! (wantvl && wantvr)) {
+	*info = -4;
+    } else if (*n < 0) {
+	*info = -5;
+    } else if (*lda < max(1,*n)) {
+	*info = -7;
+    } else if (*ldvl < 1 || wantvl && *ldvl < *n) {
+	*info = -11;
+    } else if (*ldvr < 1 || wantvr && *ldvr < *n) {
+	*info = -13;
+    }
+
+/*     Compute workspace   
+        (Note: Comments in the code beginning "Workspace:" describe the   
+         minimal amount of workspace needed at that point in the code,   
+         as well as the preferred amount for good performance.   
+         NB refers to the optimal block size for the immediately   
+         following subroutine, as returned by ILAENV.   
+         HSWORK refers to the workspace preferred by DHSEQR, as   
+         calculated below. HSWORK is computed assuming ILO=1 and IHI=N,   
+         the worst case.) */
+
+    if (*info == 0) {
+	if (*n == 0) {
+	    minwrk = 1;
+	    maxwrk = 1;
+	} else {
+	    maxwrk = *n + *n * igraphilaenv_(&c__1, "DGEHRD", " ", n, &c__1, n, &
+		    c__0, (ftnlen)6, (ftnlen)1);
+
+	    if (wantvl) {
+		igraphdhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[
+			1], &vl[vl_offset], ldvl, &work[1], &c_n1, info);
+	    } else if (wantvr) {
+		igraphdhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[
+			1], &vr[vr_offset], ldvr, &work[1], &c_n1, info);
+	    } else {
+		if (wntsnn) {
+		    igraphdhseqr_("E", "N", n, &c__1, n, &a[a_offset], lda, &wr[1], 
+			    &wi[1], &vr[vr_offset], ldvr, &work[1], &c_n1, 
+			    info);
+		} else {
+		    igraphdhseqr_("S", "N", n, &c__1, n, &a[a_offset], lda, &wr[1], 
+			    &wi[1], &vr[vr_offset], ldvr, &work[1], &c_n1, 
+			    info);
+		}
+	    }
+	    hswork = (integer) work[1];
+
+	    if (! wantvl && ! wantvr) {
+		minwrk = *n << 1;
+		if (! wntsnn) {
+/* Computing MAX */
+		    i__1 = minwrk, i__2 = *n * *n + *n * 6;
+		    minwrk = max(i__1,i__2);
+		}
+		maxwrk = max(maxwrk,hswork);
+		if (! wntsnn) {
+/* Computing MAX */
+		    i__1 = maxwrk, i__2 = *n * *n + *n * 6;
+		    maxwrk = max(i__1,i__2);
+		}
+	    } else {
+		minwrk = *n * 3;
+		if (! wntsnn && ! wntsne) {
+/* Computing MAX */
+		    i__1 = minwrk, i__2 = *n * *n + *n * 6;
+		    minwrk = max(i__1,i__2);
+		}
+		maxwrk = max(maxwrk,hswork);
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n + (*n - 1) * igraphilaenv_(&c__1, "DORGHR",
+			 " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)1);
+		maxwrk = max(i__1,i__2);
+		if (! wntsnn && ! wntsne) {
+/* Computing MAX */
+		    i__1 = maxwrk, i__2 = *n * *n + *n * 6;
+		    maxwrk = max(i__1,i__2);
+		}
+/* Computing MAX */
+		i__1 = maxwrk, i__2 = *n * 3;
+		maxwrk = max(i__1,i__2);
+	    }
+	    maxwrk = max(maxwrk,minwrk);
+	}
+	work[1] = (doublereal) maxwrk;
+
+	if (*lwork < minwrk && ! lquery) {
+	    *info = -21;
+	}
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEEVX", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+/*     Get machine constants */
+
+    eps = igraphdlamch_("P");
+    smlnum = igraphdlamch_("S");
+    bignum = 1. / smlnum;
+    igraphdlabad_(&smlnum, &bignum);
+    smlnum = sqrt(smlnum) / eps;
+    bignum = 1. / smlnum;
+
+/*     Scale A if max element outside range [SMLNUM,BIGNUM] */
+
+    icond = 0;
+    anrm = igraphdlange_("M", n, n, &a[a_offset], lda, dum);
+    scalea = FALSE_;
+    if (anrm > 0. && anrm < smlnum) {
+	scalea = TRUE_;
+	cscale = smlnum;
+    } else if (anrm > bignum) {
+	scalea = TRUE_;
+	cscale = bignum;
+    }
+    if (scalea) {
+	igraphdlascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, &
+		ierr);
+    }
+
+/*     Balance the matrix and compute ABNRM */
+
+    igraphdgebal_(balanc, n, &a[a_offset], lda, ilo, ihi, &scale[1], &ierr);
+    *abnrm = igraphdlange_("1", n, n, &a[a_offset], lda, dum);
+    if (scalea) {
+	dum[0] = *abnrm;
+	igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &c__1, &c__1, dum, &c__1, &
+		ierr);
+	*abnrm = dum[0];
+    }
+
+/*     Reduce to upper Hessenberg form   
+       (Workspace: need 2*N, prefer N+N*NB) */
+
+    itau = 1;
+    iwrk = itau + *n;
+    i__1 = *lwork - iwrk + 1;
+    igraphdgehrd_(n, ilo, ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1, &
+	    ierr);
+
+    if (wantvl) {
+
+/*        Want left eigenvectors   
+          Copy Householder vectors to VL */
+
+	*(unsigned char *)side = 'L';
+	igraphdlacpy_("L", n, n, &a[a_offset], lda, &vl[vl_offset], ldvl)
+		;
+
+/*        Generate orthogonal matrix in VL   
+          (Workspace: need 2*N-1, prefer N+(N-1)*NB) */
+
+	i__1 = *lwork - iwrk + 1;
+	igraphdorghr_(n, ilo, ihi, &vl[vl_offset], ldvl, &work[itau], &work[iwrk], &
+		i__1, &ierr);
+
+/*        Perform QR iteration, accumulating Schur vectors in VL   
+          (Workspace: need 1, prefer HSWORK (see comments) ) */
+
+	iwrk = itau;
+	i__1 = *lwork - iwrk + 1;
+	igraphdhseqr_("S", "V", n, ilo, ihi, &a[a_offset], lda, &wr[1], &wi[1], &vl[
+		vl_offset], ldvl, &work[iwrk], &i__1, info);
+
+	if (wantvr) {
+
+/*           Want left and right eigenvectors   
+             Copy Schur vectors to VR */
+
+	    *(unsigned char *)side = 'B';
+	    igraphdlacpy_("F", n, n, &vl[vl_offset], ldvl, &vr[vr_offset], ldvr);
+	}
+
+    } else if (wantvr) {
+
+/*        Want right eigenvectors   
+          Copy Householder vectors to VR */
+
+	*(unsigned char *)side = 'R';
+	igraphdlacpy_("L", n, n, &a[a_offset], lda, &vr[vr_offset], ldvr)
+		;
+
+/*        Generate orthogonal matrix in VR   
+          (Workspace: need 2*N-1, prefer N+(N-1)*NB) */
+
+	i__1 = *lwork - iwrk + 1;
+	igraphdorghr_(n, ilo, ihi, &vr[vr_offset], ldvr, &work[itau], &work[iwrk], &
+		i__1, &ierr);
+
+/*        Perform QR iteration, accumulating Schur vectors in VR   
+          (Workspace: need 1, prefer HSWORK (see comments) ) */
+
+	iwrk = itau;
+	i__1 = *lwork - iwrk + 1;
+	igraphdhseqr_("S", "V", n, ilo, ihi, &a[a_offset], lda, &wr[1], &wi[1], &vr[
+		vr_offset], ldvr, &work[iwrk], &i__1, info);
+
+    } else {
+
+/*        Compute eigenvalues only   
+          If condition numbers desired, compute Schur form */
+
+	if (wntsnn) {
+	    *(unsigned char *)job = 'E';
+	} else {
+	    *(unsigned char *)job = 'S';
+	}
+
+/*        (Workspace: need 1, prefer HSWORK (see comments) ) */
+
+	iwrk = itau;
+	i__1 = *lwork - iwrk + 1;
+	igraphdhseqr_(job, "N", n, ilo, ihi, &a[a_offset], lda, &wr[1], &wi[1], &vr[
+		vr_offset], ldvr, &work[iwrk], &i__1, info);
+    }
+
+/*     If INFO > 0 from DHSEQR, then quit */
+
+    if (*info > 0) {
+	goto L50;
+    }
+
+    if (wantvl || wantvr) {
+
+/*        Compute left and/or right eigenvectors   
+          (Workspace: need 3*N) */
+
+	igraphdtrevc_(side, "B", select, n, &a[a_offset], lda, &vl[vl_offset], ldvl,
+		 &vr[vr_offset], ldvr, n, &nout, &work[iwrk], &ierr);
+    }
+
+/*     Compute condition numbers if desired   
+       (Workspace: need N*N+6*N unless SENSE = 'E') */
+
+    if (! wntsnn) {
+	igraphdtrsna_(sense, "A", select, n, &a[a_offset], lda, &vl[vl_offset], 
+		ldvl, &vr[vr_offset], ldvr, &rconde[1], &rcondv[1], n, &nout, 
+		&work[iwrk], n, &iwork[1], &icond);
+    }
+
+    if (wantvl) {
+
+/*        Undo balancing of left eigenvectors */
+
+	igraphdgebak_(balanc, "L", n, ilo, ihi, &scale[1], n, &vl[vl_offset], ldvl, 
+		&ierr);
+
+/*        Normalize left eigenvectors and make largest component real */
+
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    if (wi[i__] == 0.) {
+		scl = 1. / igraphdnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1);
+	    } else if (wi[i__] > 0.) {
+		d__1 = igraphdnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &vl[(i__ + 1) * vl_dim1 + 1], &c__1);
+		scl = 1. / igraphdlapy2_(&d__1, &d__2);
+		igraphdscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vl[(i__ + 1) * vl_dim1 + 1], &c__1);
+		i__2 = *n;
+		for (k = 1; k <= i__2; ++k) {
+/* Computing 2nd power */
+		    d__1 = vl[k + i__ * vl_dim1];
+/* Computing 2nd power */
+		    d__2 = vl[k + (i__ + 1) * vl_dim1];
+		    work[k] = d__1 * d__1 + d__2 * d__2;
+/* L10: */
+		}
+		k = igraphidamax_(n, &work[1], &c__1);
+		igraphdlartg_(&vl[k + i__ * vl_dim1], &vl[k + (i__ + 1) * vl_dim1], 
+			&cs, &sn, &r__);
+		igraphdrot_(n, &vl[i__ * vl_dim1 + 1], &c__1, &vl[(i__ + 1) * 
+			vl_dim1 + 1], &c__1, &cs, &sn);
+		vl[k + (i__ + 1) * vl_dim1] = 0.;
+	    }
+/* L20: */
+	}
+    }
+
+    if (wantvr) {
+
+/*        Undo balancing of right eigenvectors */
+
+	igraphdgebak_(balanc, "R", n, ilo, ihi, &scale[1], n, &vr[vr_offset], ldvr, 
+		&ierr);
+
+/*        Normalize right eigenvectors and make largest component real */
+
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    if (wi[i__] == 0.) {
+		scl = 1. / igraphdnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1);
+	    } else if (wi[i__] > 0.) {
+		d__1 = igraphdnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &vr[(i__ + 1) * vr_dim1 + 1], &c__1);
+		scl = 1. / igraphdlapy2_(&d__1, &d__2);
+		igraphdscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1);
+		igraphdscal_(n, &scl, &vr[(i__ + 1) * vr_dim1 + 1], &c__1);
+		i__2 = *n;
+		for (k = 1; k <= i__2; ++k) {
+/* Computing 2nd power */
+		    d__1 = vr[k + i__ * vr_dim1];
+/* Computing 2nd power */
+		    d__2 = vr[k + (i__ + 1) * vr_dim1];
+		    work[k] = d__1 * d__1 + d__2 * d__2;
+/* L30: */
+		}
+		k = igraphidamax_(n, &work[1], &c__1);
+		igraphdlartg_(&vr[k + i__ * vr_dim1], &vr[k + (i__ + 1) * vr_dim1], 
+			&cs, &sn, &r__);
+		igraphdrot_(n, &vr[i__ * vr_dim1 + 1], &c__1, &vr[(i__ + 1) * 
+			vr_dim1 + 1], &c__1, &cs, &sn);
+		vr[k + (i__ + 1) * vr_dim1] = 0.;
+	    }
+/* L40: */
+	}
+    }
+
+/*     Undo scaling if necessary */
+
+L50:
+    if (scalea) {
+	i__1 = *n - *info;
+/* Computing MAX */
+	i__3 = *n - *info;
+	i__2 = max(i__3,1);
+	igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[*info + 
+		1], &i__2, &ierr);
+	i__1 = *n - *info;
+/* Computing MAX */
+	i__3 = *n - *info;
+	i__2 = max(i__3,1);
+	igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[*info + 
+		1], &i__2, &ierr);
+	if (*info == 0) {
+	    if ((wntsnv || wntsnb) && icond == 0) {
+		igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, n, &c__1, &rcondv[
+			1], n, &ierr);
+	    }
+	} else {
+	    i__1 = *ilo - 1;
+	    igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[1], 
+		    n, &ierr);
+	    i__1 = *ilo - 1;
+	    igraphdlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[1], 
+		    n, &ierr);
+	}
+    }
+
+    work[1] = (doublereal) maxwrk;
+    return 0;
+
+/*     End of DGEEVX */
+
+} /* igraphdgeevx_ */
+
diff --git a/src/lapack/dgehd2.c b/src/lapack/dgehd2.c
new file mode 100644
index 0000000..9475440
--- /dev/null
+++ b/src/lapack/dgehd2.c
@@ -0,0 +1,180 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdgehd2_(integer *n, integer *ilo, integer *ihi, 
+	doublereal *a, integer *lda, doublereal *tau, doublereal *work, 
+	integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__;
+    doublereal aii;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *), igraphdlarfg_(integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *), igraphxerbla_(char *, integer *,
+	     ftnlen);
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DGEHD2 reduces a real general matrix A to upper Hessenberg form H by   
+    an orthogonal similarity transformation:  Q**T * A * Q = H .   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    ILO     (input) INTEGER   
+    IHI     (input) INTEGER   
+            It is assumed that A is already upper triangular in rows   
+            and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally   
+            set by a previous call to DGEBAL; otherwise they should be   
+            set to 1 and N respectively. See Further Details.   
+            1 <= ILO <= IHI <= max(1,N).   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the n by n general matrix to be reduced.   
+            On exit, the upper triangle and the first subdiagonal of A   
+            are overwritten with the upper Hessenberg matrix H, and the   
+            elements below the first subdiagonal, with the array TAU,   
+            represent the orthogonal matrix Q as a product of elementary   
+            reflectors. See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (N-1)   
+            The scalar factors of the elementary reflectors (see Further   
+            Details).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (N)   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit.   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+
+    Further Details   
+    ===============   
+
+    The matrix Q is represented as a product of (ihi-ilo) elementary   
+    reflectors   
+
+       Q = H(ilo) H(ilo+1) . . . H(ihi-1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on   
+    exit in A(i+2:ihi,i), and tau in TAU(i).   
+
+    The contents of A are illustrated by the following example, with   
+    n = 7, ilo = 2 and ihi = 6:   
+
+    on entry,                        on exit,   
+
+    ( a   a   a   a   a   a   a )    (  a   a   h   h   h   h   a )   
+    (     a   a   a   a   a   a )    (      a   h   h   h   h   a )   
+    (     a   a   a   a   a   a )    (      h   h   h   h   h   h )   
+    (     a   a   a   a   a   a )    (      v2  h   h   h   h   h )   
+    (     a   a   a   a   a   a )    (      v2  v3  h   h   h   h )   
+    (     a   a   a   a   a   a )    (      v2  v3  v4  h   h   h )   
+    (                         a )    (                          a )   
+
+    where a denotes an element of the original matrix A, h denotes a   
+    modified element of the upper Hessenberg matrix H, and vi denotes an   
+    element of the vector defining H(i).   
+
+    =====================================================================   
+
+
+       Test the input parameters   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    if (*n < 0) {
+	*info = -1;
+    } else if (*ilo < 1 || *ilo > max(1,*n)) {
+	*info = -2;
+    } else if (*ihi < min(*ilo,*n) || *ihi > *n) {
+	*info = -3;
+    } else if (*lda < max(1,*n)) {
+	*info = -5;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEHD2", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+    i__1 = *ihi - 1;
+    for (i__ = *ilo; i__ <= i__1; ++i__) {
+
+/*        Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) */
+
+	i__2 = *ihi - i__;
+/* Computing MIN */
+	i__3 = i__ + 2;
+	igraphdlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + i__ * 
+		a_dim1], &c__1, &tau[i__]);
+	aii = a[i__ + 1 + i__ * a_dim1];
+	a[i__ + 1 + i__ * a_dim1] = 1.;
+
+/*        Apply H(i) to A(1:ihi,i+1:ihi) from the right */
+
+	i__2 = *ihi - i__;
+	igraphdlarf_("Right", ihi, &i__2, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[
+		i__], &a[(i__ + 1) * a_dim1 + 1], lda, &work[1]);
+
+/*        Apply H(i) to A(i+1:ihi,i+1:n) from the left */
+
+	i__2 = *ihi - i__;
+	i__3 = *n - i__;
+	igraphdlarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[
+		i__], &a[i__ + 1 + (i__ + 1) * a_dim1], lda, &work[1]);
+
+	a[i__ + 1 + i__ * a_dim1] = aii;
+/* L10: */
+    }
+
+    return 0;
+
+/*     End of DGEHD2 */
+
+} /* igraphdgehd2_ */
+
diff --git a/src/lapack/dgehrd.c b/src/lapack/dgehrd.c
new file mode 100644
index 0000000..a614a73
--- /dev/null
+++ b/src/lapack/dgehrd.c
@@ -0,0 +1,329 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__3 = 3;
+static integer c__2 = 2;
+static integer c__65 = 65;
+static doublereal c_b25 = -1.;
+static doublereal c_b26 = 1.;
+
+/* Subroutine */ int igraphdgehrd_(integer *n, integer *ilo, integer *ihi, 
+	doublereal *a, integer *lda, doublereal *tau, doublereal *work, 
+	integer *lwork, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3, i__4;
+
+    /* Local variables */
+    integer i__, j;
+    doublereal t[4160]	/* was [65][64] */;
+    integer ib;
+    doublereal ei;
+    integer nb, nh, nx, iws;
+    extern /* Subroutine */ int igraphdgemm_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    integer nbmin, iinfo;
+    extern /* Subroutine */ int igraphdtrmm_(char *, char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdaxpy_(
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *), igraphdgehd2_(integer *, integer *, integer *, doublereal *,
+	     integer *, doublereal *, doublereal *, integer *), igraphdlahr2_(
+	    integer *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlarfb_(char *, char *, char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    integer ldwork, lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.3.1)                                  --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2009                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DGEHRD reduces a real general matrix A to upper Hessenberg form H by   
+    an orthogonal similarity transformation:  Q**T * A * Q = H .   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    ILO     (input) INTEGER   
+    IHI     (input) INTEGER   
+            It is assumed that A is already upper triangular in rows   
+            and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally   
+            set by a previous call to DGEBAL; otherwise they should be   
+            set to 1 and N respectively. See Further Details.   
+            1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the N-by-N general matrix to be reduced.   
+            On exit, the upper triangle and the first subdiagonal of A   
+            are overwritten with the upper Hessenberg matrix H, and the   
+            elements below the first subdiagonal, with the array TAU,   
+            represent the orthogonal matrix Q as a product of elementary   
+            reflectors. See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (N-1)   
+            The scalar factors of the elementary reflectors (see Further   
+            Details). Elements 1:ILO-1 and IHI:N-1 of TAU are set to   
+            zero.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (LWORK)   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The length of the array WORK.  LWORK >= max(1,N).   
+            For optimum performance LWORK >= N*NB, where NB is the   
+            optimal blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+
+    Further Details   
+    ===============   
+
+    The matrix Q is represented as a product of (ihi-ilo) elementary   
+    reflectors   
+
+       Q = H(ilo) H(ilo+1) . . . H(ihi-1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on   
+    exit in A(i+2:ihi,i), and tau in TAU(i).   
+
+    The contents of A are illustrated by the following example, with   
+    n = 7, ilo = 2 and ihi = 6:   
+
+    on entry,                        on exit,   
+
+    ( a   a   a   a   a   a   a )    (  a   a   h   h   h   h   a )   
+    (     a   a   a   a   a   a )    (      a   h   h   h   h   a )   
+    (     a   a   a   a   a   a )    (      h   h   h   h   h   h )   
+    (     a   a   a   a   a   a )    (      v2  h   h   h   h   h )   
+    (     a   a   a   a   a   a )    (      v2  v3  h   h   h   h )   
+    (     a   a   a   a   a   a )    (      v2  v3  v4  h   h   h )   
+    (                         a )    (                          a )   
+
+    where a denotes an element of the original matrix A, h denotes a   
+    modified element of the upper Hessenberg matrix H, and vi denotes an   
+    element of the vector defining H(i).   
+
+    This file is a slight modification of LAPACK-3.0's DGEHRD   
+    subroutine incorporating improvements proposed by Quintana-Orti and   
+    Van de Geijn (2006). (See DLAHR2.)   
+
+    =====================================================================   
+
+
+       Test the input parameters   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+/* Computing MIN */
+    i__1 = 64, i__2 = igraphilaenv_(&c__1, "DGEHRD", " ", n, ilo, ihi, &c_n1, (
+	    ftnlen)6, (ftnlen)1);
+    nb = min(i__1,i__2);
+    lwkopt = *n * nb;
+    work[1] = (doublereal) lwkopt;
+    lquery = *lwork == -1;
+    if (*n < 0) {
+	*info = -1;
+    } else if (*ilo < 1 || *ilo > max(1,*n)) {
+	*info = -2;
+    } else if (*ihi < min(*ilo,*n) || *ihi > *n) {
+	*info = -3;
+    } else if (*lda < max(1,*n)) {
+	*info = -5;
+    } else if (*lwork < max(1,*n) && ! lquery) {
+	*info = -8;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEHRD", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Set elements 1:ILO-1 and IHI:N-1 of TAU to zero */
+
+    i__1 = *ilo - 1;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	tau[i__] = 0.;
+/* L10: */
+    }
+    i__1 = *n - 1;
+    for (i__ = max(1,*ihi); i__ <= i__1; ++i__) {
+	tau[i__] = 0.;
+/* L20: */
+    }
+
+/*     Quick return if possible */
+
+    nh = *ihi - *ilo + 1;
+    if (nh <= 1) {
+	work[1] = 1.;
+	return 0;
+    }
+
+/*     Determine the block size   
+
+   Computing MIN */
+    i__1 = 64, i__2 = igraphilaenv_(&c__1, "DGEHRD", " ", n, ilo, ihi, &c_n1, (
+	    ftnlen)6, (ftnlen)1);
+    nb = min(i__1,i__2);
+    nbmin = 2;
+    iws = 1;
+    if (nb > 1 && nb < nh) {
+
+/*        Determine when to cross over from blocked to unblocked code   
+          (last block is always handled by unblocked code)   
+
+   Computing MAX */
+	i__1 = nb, i__2 = igraphilaenv_(&c__3, "DGEHRD", " ", n, ilo, ihi, &c_n1, (
+		ftnlen)6, (ftnlen)1);
+	nx = max(i__1,i__2);
+	if (nx < nh) {
+
+/*           Determine if workspace is large enough for blocked code */
+
+	    iws = *n * nb;
+	    if (*lwork < iws) {
+
+/*              Not enough workspace to use optimal NB:  determine the   
+                minimum value of NB, and reduce NB or force use of   
+                unblocked code   
+
+   Computing MAX */
+		i__1 = 2, i__2 = igraphilaenv_(&c__2, "DGEHRD", " ", n, ilo, ihi, &
+			c_n1, (ftnlen)6, (ftnlen)1);
+		nbmin = max(i__1,i__2);
+		if (*lwork >= *n * nbmin) {
+		    nb = *lwork / *n;
+		} else {
+		    nb = 1;
+		}
+	    }
+	}
+    }
+    ldwork = *n;
+
+    if (nb < nbmin || nb >= nh) {
+
+/*        Use unblocked code below */
+
+	i__ = *ilo;
+
+    } else {
+
+/*        Use blocked code */
+
+	i__1 = *ihi - 1 - nx;
+	i__2 = nb;
+	for (i__ = *ilo; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+/* Computing MIN */
+	    i__3 = nb, i__4 = *ihi - i__;
+	    ib = min(i__3,i__4);
+
+/*           Reduce columns i:i+ib-1 to Hessenberg form, returning the   
+             matrices V and T of the block reflector H = I - V*T*V**T   
+             which performs the reduction, and also the matrix Y = A*V*T */
+
+	    igraphdlahr2_(ihi, &i__, &ib, &a[i__ * a_dim1 + 1], lda, &tau[i__], t, &
+		    c__65, &work[1], &ldwork);
+
+/*           Apply the block reflector H to A(1:ihi,i+ib:ihi) from the   
+             right, computing  A := A - Y * V**T. V(i+ib,ib-1) must be set   
+             to 1 */
+
+	    ei = a[i__ + ib + (i__ + ib - 1) * a_dim1];
+	    a[i__ + ib + (i__ + ib - 1) * a_dim1] = 1.;
+	    i__3 = *ihi - i__ - ib + 1;
+	    igraphdgemm_("No transpose", "Transpose", ihi, &i__3, &ib, &c_b25, &
+		    work[1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, &
+		    c_b26, &a[(i__ + ib) * a_dim1 + 1], lda);
+	    a[i__ + ib + (i__ + ib - 1) * a_dim1] = ei;
+
+/*           Apply the block reflector H to A(1:i,i+1:i+ib-1) from the   
+             right */
+
+	    i__3 = ib - 1;
+	    igraphdtrmm_("Right", "Lower", "Transpose", "Unit", &i__, &i__3, &c_b26,
+		     &a[i__ + 1 + i__ * a_dim1], lda, &work[1], &ldwork);
+	    i__3 = ib - 2;
+	    for (j = 0; j <= i__3; ++j) {
+		igraphdaxpy_(&i__, &c_b25, &work[ldwork * j + 1], &c__1, &a[(i__ + 
+			j + 1) * a_dim1 + 1], &c__1);
+/* L30: */
+	    }
+
+/*           Apply the block reflector H to A(i+1:ihi,i+ib:n) from the   
+             left */
+
+	    i__3 = *ihi - i__;
+	    i__4 = *n - i__ - ib + 1;
+	    igraphdlarfb_("Left", "Transpose", "Forward", "Columnwise", &i__3, &
+		    i__4, &ib, &a[i__ + 1 + i__ * a_dim1], lda, t, &c__65, &a[
+		    i__ + 1 + (i__ + ib) * a_dim1], lda, &work[1], &ldwork);
+/* L40: */
+	}
+    }
+
+/*     Use unblocked code to reduce the rest of the matrix */
+
+    igraphdgehd2_(n, &i__, ihi, &a[a_offset], lda, &tau[1], &work[1], &iinfo);
+    work[1] = (doublereal) iws;
+
+    return 0;
+
+/*     End of DGEHRD */
+
+} /* igraphdgehrd_ */
+
diff --git a/src/lapack/dgemm.c b/src/lapack/dgemm.c
new file mode 100644
index 0000000..0fc164f
--- /dev/null
+++ b/src/lapack/dgemm.c
@@ -0,0 +1,378 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdgemm_(char *transa, char *transb, integer *m, integer *
+	n, integer *k, doublereal *alpha, doublereal *a, integer *lda, 
+	doublereal *b, integer *ldb, doublereal *beta, doublereal *c__, 
+	integer *ldc)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, 
+	    i__3;
+
+    /* Local variables */
+    integer i__, j, l, info;
+    logical nota, notb;
+    doublereal temp;
+    integer ncola;
+    extern logical igraphlsame_(char *, char *);
+    integer nrowa, nrowb;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  Purpose   
+    =======   
+
+    DGEMM  performs one of the matrix-matrix operations   
+
+       C := alpha*op( A )*op( B ) + beta*C,   
+
+    where  op( X ) is one of   
+
+       op( X ) = X   or   op( X ) = X**T,   
+
+    alpha and beta are scalars, and A, B and C are matrices, with op( A )   
+    an m by k matrix,  op( B )  a  k by n matrix and  C an m by n matrix.   
+
+    Arguments   
+    ==========   
+
+    TRANSA - CHARACTER*1.   
+             On entry, TRANSA specifies the form of op( A ) to be used in   
+             the matrix multiplication as follows:   
+
+                TRANSA = 'N' or 'n',  op( A ) = A.   
+
+                TRANSA = 'T' or 't',  op( A ) = A**T.   
+
+                TRANSA = 'C' or 'c',  op( A ) = A**T.   
+
+             Unchanged on exit.   
+
+    TRANSB - CHARACTER*1.   
+             On entry, TRANSB specifies the form of op( B ) to be used in   
+             the matrix multiplication as follows:   
+
+                TRANSB = 'N' or 'n',  op( B ) = B.   
+
+                TRANSB = 'T' or 't',  op( B ) = B**T.   
+
+                TRANSB = 'C' or 'c',  op( B ) = B**T.   
+
+             Unchanged on exit.   
+
+    M      - INTEGER.   
+             On entry,  M  specifies  the number  of rows  of the  matrix   
+             op( A )  and of the  matrix  C.  M  must  be at least  zero.   
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry,  N  specifies the number  of columns of the matrix   
+             op( B ) and the number of columns of the matrix C. N must be   
+             at least zero.   
+             Unchanged on exit.   
+
+    K      - INTEGER.   
+             On entry,  K  specifies  the number of columns of the matrix   
+             op( A ) and the number of rows of the matrix op( B ). K must   
+             be at least  zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry, ALPHA specifies the scalar alpha.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is   
+             k  when  TRANSA = 'N' or 'n',  and is  m  otherwise.   
+             Before entry with  TRANSA = 'N' or 'n',  the leading  m by k   
+             part of the array  A  must contain the matrix  A,  otherwise   
+             the leading  k by m  part of the array  A  must contain  the   
+             matrix A.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program. When  TRANSA = 'N' or 'n' then   
+             LDA must be at least  max( 1, m ), otherwise  LDA must be at   
+             least  max( 1, k ).   
+             Unchanged on exit.   
+
+    B      - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is   
+             n  when  TRANSB = 'N' or 'n',  and is  k  otherwise.   
+             Before entry with  TRANSB = 'N' or 'n',  the leading  k by n   
+             part of the array  B  must contain the matrix  B,  otherwise   
+             the leading  n by k  part of the array  B  must contain  the   
+             matrix B.   
+             Unchanged on exit.   
+
+    LDB    - INTEGER.   
+             On entry, LDB specifies the first dimension of B as declared   
+             in the calling (sub) program. When  TRANSB = 'N' or 'n' then   
+             LDB must be at least  max( 1, k ), otherwise  LDB must be at   
+             least  max( 1, n ).   
+             Unchanged on exit.   
+
+    BETA   - DOUBLE PRECISION.   
+             On entry,  BETA  specifies the scalar  beta.  When  BETA  is   
+             supplied as zero then C need not be set on input.   
+             Unchanged on exit.   
+
+    C      - DOUBLE PRECISION array of DIMENSION ( LDC, n ).   
+             Before entry, the leading  m by n  part of the array  C must   
+             contain the matrix  C,  except when  beta  is zero, in which   
+             case C need not be set on entry.   
+             On exit, the array  C  is overwritten by the  m by n  matrix   
+             ( alpha*op( A )*op( B ) + beta*C ).   
+
+    LDC    - INTEGER.   
+             On entry, LDC specifies the first dimension of C as declared   
+             in  the  calling  (sub)  program.   LDC  must  be  at  least   
+             max( 1, m ).   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 3 Blas routine.   
+
+    -- Written on 8-February-1989.   
+       Jack Dongarra, Argonne National Laboratory.   
+       Iain Duff, AERE Harwell.   
+       Jeremy Du Croz, Numerical Algorithms Group Ltd.   
+       Sven Hammarling, Numerical Algorithms Group Ltd.   
+
+    =====================================================================   
+
+
+       Set  NOTA  and  NOTB  as  true if  A  and  B  respectively are not   
+       transposed and set  NROWA, NCOLA and  NROWB  as the number of rows   
+       and  columns of  A  and the  number of  rows  of  B  respectively.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+
+    /* Function Body */
+    nota = igraphlsame_(transa, "N");
+    notb = igraphlsame_(transb, "N");
+    if (nota) {
+	nrowa = *m;
+	ncola = *k;
+    } else {
+	nrowa = *k;
+	ncola = *m;
+    }
+    if (notb) {
+	nrowb = *k;
+    } else {
+	nrowb = *n;
+    }
+
+/*     Test the input parameters. */
+
+    info = 0;
+    if (! nota && ! igraphlsame_(transa, "C") && ! igraphlsame_(
+	    transa, "T")) {
+	info = 1;
+    } else if (! notb && ! igraphlsame_(transb, "C") && ! 
+	    igraphlsame_(transb, "T")) {
+	info = 2;
+    } else if (*m < 0) {
+	info = 3;
+    } else if (*n < 0) {
+	info = 4;
+    } else if (*k < 0) {
+	info = 5;
+    } else if (*lda < max(1,nrowa)) {
+	info = 8;
+    } else if (*ldb < max(1,nrowb)) {
+	info = 10;
+    } else if (*ldc < max(1,*m)) {
+	info = 13;
+    }
+    if (info != 0) {
+	igraphxerbla_("DGEMM ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*m == 0 || *n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) {
+	return 0;
+    }
+
+/*     And if  alpha.eq.zero. */
+
+    if (*alpha == 0.) {
+	if (*beta == 0.) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    c__[i__ + j * c_dim1] = 0.;
+/* L10: */
+		}
+/* L20: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L30: */
+		}
+/* L40: */
+	    }
+	}
+	return 0;
+    }
+
+/*     Start the operations. */
+
+    if (notb) {
+	if (nota) {
+
+/*           Form  C := alpha*A*B + beta*C. */
+
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (*beta == 0.) {
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = 0.;
+/* L50: */
+		    }
+		} else if (*beta != 1.) {
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L60: */
+		    }
+		}
+		i__2 = *k;
+		for (l = 1; l <= i__2; ++l) {
+		    if (b[l + j * b_dim1] != 0.) {
+			temp = *alpha * b[l + j * b_dim1];
+			i__3 = *m;
+			for (i__ = 1; i__ <= i__3; ++i__) {
+			    c__[i__ + j * c_dim1] += temp * a[i__ + l * 
+				    a_dim1];
+/* L70: */
+			}
+		    }
+/* L80: */
+		}
+/* L90: */
+	    }
+	} else {
+
+/*           Form  C := alpha*A**T*B + beta*C */
+
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    temp = 0.;
+		    i__3 = *k;
+		    for (l = 1; l <= i__3; ++l) {
+			temp += a[l + i__ * a_dim1] * b[l + j * b_dim1];
+/* L100: */
+		    }
+		    if (*beta == 0.) {
+			c__[i__ + j * c_dim1] = *alpha * temp;
+		    } else {
+			c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[
+				i__ + j * c_dim1];
+		    }
+/* L110: */
+		}
+/* L120: */
+	    }
+	}
+    } else {
+	if (nota) {
+
+/*           Form  C := alpha*A*B**T + beta*C */
+
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (*beta == 0.) {
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = 0.;
+/* L130: */
+		    }
+		} else if (*beta != 1.) {
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L140: */
+		    }
+		}
+		i__2 = *k;
+		for (l = 1; l <= i__2; ++l) {
+		    if (b[j + l * b_dim1] != 0.) {
+			temp = *alpha * b[j + l * b_dim1];
+			i__3 = *m;
+			for (i__ = 1; i__ <= i__3; ++i__) {
+			    c__[i__ + j * c_dim1] += temp * a[i__ + l * 
+				    a_dim1];
+/* L150: */
+			}
+		    }
+/* L160: */
+		}
+/* L170: */
+	    }
+	} else {
+
+/*           Form  C := alpha*A**T*B**T + beta*C */
+
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    temp = 0.;
+		    i__3 = *k;
+		    for (l = 1; l <= i__3; ++l) {
+			temp += a[l + i__ * a_dim1] * b[j + l * b_dim1];
+/* L180: */
+		    }
+		    if (*beta == 0.) {
+			c__[i__ + j * c_dim1] = *alpha * temp;
+		    } else {
+			c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[
+				i__ + j * c_dim1];
+		    }
+/* L190: */
+		}
+/* L200: */
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DGEMM . */
+
+} /* igraphdgemm_ */
+
diff --git a/src/lapack/dgemv.c b/src/lapack/dgemv.c
new file mode 100644
index 0000000..21ae33e
--- /dev/null
+++ b/src/lapack/dgemv.c
@@ -0,0 +1,302 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdgemv_(char *trans, integer *m, integer *n, doublereal *
+	alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, 
+	doublereal *beta, doublereal *y, integer *incy)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, ix, iy, jx, jy, kx, ky, info;
+    doublereal temp;
+    integer lenx, leny;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  Purpose   
+    =======   
+
+    DGEMV  performs one of the matrix-vector operations   
+
+       y := alpha*A*x + beta*y,   or   y := alpha*A**T*x + beta*y,   
+
+    where alpha and beta are scalars, x and y are vectors and A is an   
+    m by n matrix.   
+
+    Arguments   
+    ==========   
+
+    TRANS  - CHARACTER*1.   
+             On entry, TRANS specifies the operation to be performed as   
+             follows:   
+
+                TRANS = 'N' or 'n'   y := alpha*A*x + beta*y.   
+
+                TRANS = 'T' or 't'   y := alpha*A**T*x + beta*y.   
+
+                TRANS = 'C' or 'c'   y := alpha*A**T*x + beta*y.   
+
+             Unchanged on exit.   
+
+    M      - INTEGER.   
+             On entry, M specifies the number of rows of the matrix A.   
+             M must be at least zero.   
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the number of columns of the matrix A.   
+             N must be at least zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry, ALPHA specifies the scalar alpha.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, n ).   
+             Before entry, the leading m by n part of the array A must   
+             contain the matrix of coefficients.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program. LDA must be at least   
+             max( 1, m ).   
+             Unchanged on exit.   
+
+    X      - DOUBLE PRECISION array of DIMENSION at least   
+             ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n'   
+             and at least   
+             ( 1 + ( m - 1 )*abs( INCX ) ) otherwise.   
+             Before entry, the incremented array X must contain the   
+             vector x.   
+             Unchanged on exit.   
+
+    INCX   - INTEGER.   
+             On entry, INCX specifies the increment for the elements of   
+             X. INCX must not be zero.   
+             Unchanged on exit.   
+
+    BETA   - DOUBLE PRECISION.   
+             On entry, BETA specifies the scalar beta. When BETA is   
+             supplied as zero then Y need not be set on input.   
+             Unchanged on exit.   
+
+    Y      - DOUBLE PRECISION array of DIMENSION at least   
+             ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'   
+             and at least   
+             ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.   
+             Before entry with BETA non-zero, the incremented array Y   
+             must contain the vector y. On exit, Y is overwritten by the   
+             updated vector y.   
+
+    INCY   - INTEGER.   
+             On entry, INCY specifies the increment for the elements of   
+             Y. INCY must not be zero.   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 2 Blas routine.   
+    The vector and matrix arguments are not referenced when N = 0, or M = 0   
+
+    -- Written on 22-October-1986.   
+       Jack Dongarra, Argonne National Lab.   
+       Jeremy Du Croz, Nag Central Office.   
+       Sven Hammarling, Nag Central Office.   
+       Richard Hanson, Sandia National Labs.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --x;
+    --y;
+
+    /* Function Body */
+    info = 0;
+    if (! igraphlsame_(trans, "N") && ! igraphlsame_(trans, "T") && ! igraphlsame_(trans, "C")
+	    ) {
+	info = 1;
+    } else if (*m < 0) {
+	info = 2;
+    } else if (*n < 0) {
+	info = 3;
+    } else if (*lda < max(1,*m)) {
+	info = 6;
+    } else if (*incx == 0) {
+	info = 8;
+    } else if (*incy == 0) {
+	info = 11;
+    }
+    if (info != 0) {
+	igraphxerbla_("DGEMV ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*m == 0 || *n == 0 || *alpha == 0. && *beta == 1.) {
+	return 0;
+    }
+
+/*     Set  LENX  and  LENY, the lengths of the vectors x and y, and set   
+       up the start points in  X  and  Y. */
+
+    if (igraphlsame_(trans, "N")) {
+	lenx = *n;
+	leny = *m;
+    } else {
+	lenx = *m;
+	leny = *n;
+    }
+    if (*incx > 0) {
+	kx = 1;
+    } else {
+	kx = 1 - (lenx - 1) * *incx;
+    }
+    if (*incy > 0) {
+	ky = 1;
+    } else {
+	ky = 1 - (leny - 1) * *incy;
+    }
+
+/*     Start the operations. In this version the elements of A are   
+       accessed sequentially with one pass through A.   
+
+       First form  y := beta*y. */
+
+    if (*beta != 1.) {
+	if (*incy == 1) {
+	    if (*beta == 0.) {
+		i__1 = leny;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[i__] = 0.;
+/* L10: */
+		}
+	    } else {
+		i__1 = leny;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[i__] = *beta * y[i__];
+/* L20: */
+		}
+	    }
+	} else {
+	    iy = ky;
+	    if (*beta == 0.) {
+		i__1 = leny;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[iy] = 0.;
+		    iy += *incy;
+/* L30: */
+		}
+	    } else {
+		i__1 = leny;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[iy] = *beta * y[iy];
+		    iy += *incy;
+/* L40: */
+		}
+	    }
+	}
+    }
+    if (*alpha == 0.) {
+	return 0;
+    }
+    if (igraphlsame_(trans, "N")) {
+
+/*        Form  y := alpha*A*x + y. */
+
+	jx = kx;
+	if (*incy == 1) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (x[jx] != 0.) {
+		    temp = *alpha * x[jx];
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			y[i__] += temp * a[i__ + j * a_dim1];
+/* L50: */
+		    }
+		}
+		jx += *incx;
+/* L60: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (x[jx] != 0.) {
+		    temp = *alpha * x[jx];
+		    iy = ky;
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			y[iy] += temp * a[i__ + j * a_dim1];
+			iy += *incy;
+/* L70: */
+		    }
+		}
+		jx += *incx;
+/* L80: */
+	    }
+	}
+    } else {
+
+/*        Form  y := alpha*A**T*x + y. */
+
+	jy = ky;
+	if (*incx == 1) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		temp = 0.;
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    temp += a[i__ + j * a_dim1] * x[i__];
+/* L90: */
+		}
+		y[jy] += *alpha * temp;
+		jy += *incy;
+/* L100: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		temp = 0.;
+		ix = kx;
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    temp += a[i__ + j * a_dim1] * x[ix];
+		    ix += *incx;
+/* L110: */
+		}
+		y[jy] += *alpha * temp;
+		jy += *incy;
+/* L120: */
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DGEMV . */
+
+} /* igraphdgemv_ */
+
diff --git a/src/lapack/dgeqr2.c b/src/lapack/dgeqr2.c
new file mode 100644
index 0000000..e492035
--- /dev/null
+++ b/src/lapack/dgeqr2.c
@@ -0,0 +1,150 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdgeqr2_(integer *m, integer *n, doublereal *a, integer *
+	lda, doublereal *tau, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, k;
+    doublereal aii;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *), igraphdlarfg_(integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *), igraphxerbla_(char *, integer *,
+	     ftnlen);
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DGEQR2 computes a QR factorization of a real m by n matrix A:   
+    A = Q * R.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the m by n matrix A.   
+            On exit, the elements on and above the diagonal of the array   
+            contain the min(m,n) by n upper trapezoidal matrix R (R is   
+            upper triangular if m >= n); the elements below the diagonal,   
+            with the array TAU, represent the orthogonal matrix Q as a   
+            product of elementary reflectors (see Further Details).   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (min(M,N))   
+            The scalar factors of the elementary reflectors (see Further   
+            Details).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (N)   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+
+    Further Details   
+    ===============   
+
+    The matrix Q is represented as a product of elementary reflectors   
+
+       Q = H(1) H(2) . . . H(k), where k = min(m,n).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i),   
+    and tau in TAU(i).   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    if (*m < 0) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*m)) {
+	*info = -4;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGEQR2", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+    k = min(*m,*n);
+
+    i__1 = k;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+
+/*        Generate elementary reflector H(i) to annihilate A(i+1:m,i) */
+
+	i__2 = *m - i__ + 1;
+/* Computing MIN */
+	i__3 = i__ + 1;
+	igraphdlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * a_dim1]
+		, &c__1, &tau[i__]);
+	if (i__ < *n) {
+
+/*           Apply H(i) to A(i:m,i+1:n) from the left */
+
+	    aii = a[i__ + i__ * a_dim1];
+	    a[i__ + i__ * a_dim1] = 1.;
+	    i__2 = *m - i__ + 1;
+	    i__3 = *n - i__;
+	    igraphdlarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, &tau[
+		    i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]);
+	    a[i__ + i__ * a_dim1] = aii;
+	}
+/* L10: */
+    }
+    return 0;
+
+/*     End of DGEQR2 */
+
+} /* igraphdgeqr2_ */
+
diff --git a/src/lapack/dger.c b/src/lapack/dger.c
new file mode 100644
index 0000000..3317f57
--- /dev/null
+++ b/src/lapack/dger.c
@@ -0,0 +1,185 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdger_(integer *m, integer *n, doublereal *alpha, 
+	doublereal *x, integer *incx, doublereal *y, integer *incy, 
+	doublereal *a, integer *lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, ix, jy, kx, info;
+    doublereal temp;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  Purpose   
+    =======   
+
+    DGER   performs the rank 1 operation   
+
+       A := alpha*x*y**T + A,   
+
+    where alpha is a scalar, x is an m element vector, y is an n element   
+    vector and A is an m by n matrix.   
+
+    Arguments   
+    ==========   
+
+    M      - INTEGER.   
+             On entry, M specifies the number of rows of the matrix A.   
+             M must be at least zero.   
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the number of columns of the matrix A.   
+             N must be at least zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry, ALPHA specifies the scalar alpha.   
+             Unchanged on exit.   
+
+    X      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( m - 1 )*abs( INCX ) ).   
+             Before entry, the incremented array X must contain the m   
+             element vector x.   
+             Unchanged on exit.   
+
+    INCX   - INTEGER.   
+             On entry, INCX specifies the increment for the elements of   
+             X. INCX must not be zero.   
+             Unchanged on exit.   
+
+    Y      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( n - 1 )*abs( INCY ) ).   
+             Before entry, the incremented array Y must contain the n   
+             element vector y.   
+             Unchanged on exit.   
+
+    INCY   - INTEGER.   
+             On entry, INCY specifies the increment for the elements of   
+             Y. INCY must not be zero.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, n ).   
+             Before entry, the leading m by n part of the array A must   
+             contain the matrix of coefficients. On exit, A is   
+             overwritten by the updated matrix.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program. LDA must be at least   
+             max( 1, m ).   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 2 Blas routine.   
+
+    -- Written on 22-October-1986.   
+       Jack Dongarra, Argonne National Lab.   
+       Jeremy Du Croz, Nag Central Office.   
+       Sven Hammarling, Nag Central Office.   
+       Richard Hanson, Sandia National Labs.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    --x;
+    --y;
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    info = 0;
+    if (*m < 0) {
+	info = 1;
+    } else if (*n < 0) {
+	info = 2;
+    } else if (*incx == 0) {
+	info = 5;
+    } else if (*incy == 0) {
+	info = 7;
+    } else if (*lda < max(1,*m)) {
+	info = 9;
+    }
+    if (info != 0) {
+	igraphxerbla_("DGER  ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*m == 0 || *n == 0 || *alpha == 0.) {
+	return 0;
+    }
+
+/*     Start the operations. In this version the elements of A are   
+       accessed sequentially with one pass through A. */
+
+    if (*incy > 0) {
+	jy = 1;
+    } else {
+	jy = 1 - (*n - 1) * *incy;
+    }
+    if (*incx == 1) {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    if (y[jy] != 0.) {
+		temp = *alpha * y[jy];
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    a[i__ + j * a_dim1] += x[i__] * temp;
+/* L10: */
+		}
+	    }
+	    jy += *incy;
+/* L20: */
+	}
+    } else {
+	if (*incx > 0) {
+	    kx = 1;
+	} else {
+	    kx = 1 - (*m - 1) * *incx;
+	}
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    if (y[jy] != 0.) {
+		temp = *alpha * y[jy];
+		ix = kx;
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    a[i__ + j * a_dim1] += x[ix] * temp;
+		    ix += *incx;
+/* L30: */
+		}
+	    }
+	    jy += *incy;
+/* L40: */
+	}
+    }
+
+    return 0;
+
+/*     End of DGER  . */
+
+} /* igraphdger_ */
+
diff --git a/src/lapack/dgesv.c b/src/lapack/dgesv.c
new file mode 100644
index 0000000..c8370c6
--- /dev/null
+++ b/src/lapack/dgesv.c
@@ -0,0 +1,131 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdgesv_(integer *n, integer *nrhs, doublereal *a, integer 
+	*lda, integer *ipiv, doublereal *b, integer *ldb, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, i__1;
+
+    /* Local variables */
+    extern /* Subroutine */ int igraphdgetrf_(integer *, integer *, doublereal *, 
+	    integer *, integer *, integer *), igraphxerbla_(char *, integer *, 
+	    ftnlen), igraphdgetrs_(char *, integer *, integer *, doublereal *, 
+	    integer *, integer *, doublereal *, integer *, integer *);
+
+
+/*  -- LAPACK driver routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DGESV computes the solution to a real system of linear equations   
+       A * X = B,   
+    where A is an N-by-N matrix and X and B are N-by-NRHS matrices.   
+
+    The LU decomposition with partial pivoting and row interchanges is   
+    used to factor A as   
+       A = P * L * U,   
+    where P is a permutation matrix, L is unit lower triangular, and U is   
+    upper triangular.  The factored form of A is then used to solve the   
+    system of equations A * X = B.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The number of linear equations, i.e., the order of the   
+            matrix A.  N >= 0.   
+
+    NRHS    (input) INTEGER   
+            The number of right hand sides, i.e., the number of columns   
+            of the matrix B.  NRHS >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the N-by-N coefficient matrix A.   
+            On exit, the factors L and U from the factorization   
+            A = P*L*U; the unit diagonal elements of L are not stored.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    IPIV    (output) INTEGER array, dimension (N)   
+            The pivot indices that define the permutation matrix P;   
+            row i of the matrix was interchanged with row IPIV(i).   
+
+    B       (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS)   
+            On entry, the N-by-NRHS matrix of right hand side matrix B.   
+            On exit, if INFO = 0, the N-by-NRHS solution matrix X.   
+
+    LDB     (input) INTEGER   
+            The leading dimension of the array B.  LDB >= max(1,N).   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  if INFO = i, U(i,i) is exactly zero.  The factorization   
+                  has been completed, but the factor U is exactly   
+                  singular, so the solution could not be computed.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --ipiv;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+
+    /* Function Body */
+    *info = 0;
+    if (*n < 0) {
+	*info = -1;
+    } else if (*nrhs < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*n)) {
+	*info = -4;
+    } else if (*ldb < max(1,*n)) {
+	*info = -7;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGESV ", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Compute the LU factorization of A. */
+
+    igraphdgetrf_(n, n, &a[a_offset], lda, &ipiv[1], info);
+    if (*info == 0) {
+
+/*        Solve the system A*X = B, overwriting B with X. */
+
+	igraphdgetrs_("No transpose", n, nrhs, &a[a_offset], lda, &ipiv[1], &b[
+		b_offset], ldb, info);
+    }
+    return 0;
+
+/*     End of DGESV */
+
+} /* igraphdgesv_ */
+
diff --git a/src/lapack/dgetf2.c b/src/lapack/dgetf2.c
new file mode 100644
index 0000000..7c1c24e
--- /dev/null
+++ b/src/lapack/dgetf2.c
@@ -0,0 +1,179 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b8 = -1.;
+
+/* Subroutine */ int igraphdgetf2_(integer *m, integer *n, doublereal *a, integer *
+	lda, integer *ipiv, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__, j, jp;
+    extern /* Subroutine */ int igraphdger_(integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *), igraphdscal_(integer *, doublereal *, doublereal *, integer 
+	    *);
+    doublereal sfmin;
+    extern /* Subroutine */ int igraphdswap_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    extern doublereal igraphdlamch_(char *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DGETF2 computes an LU factorization of a general m-by-n matrix A   
+    using partial pivoting with row interchanges.   
+
+    The factorization has the form   
+       A = P * L * U   
+    where P is a permutation matrix, L is lower triangular with unit   
+    diagonal elements (lower trapezoidal if m > n), and U is upper   
+    triangular (upper trapezoidal if m < n).   
+
+    This is the right-looking Level 2 BLAS version of the algorithm.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the m by n matrix to be factored.   
+            On exit, the factors L and U from the factorization   
+            A = P*L*U; the unit diagonal elements of L are not stored.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+    IPIV    (output) INTEGER array, dimension (min(M,N))   
+            The pivot indices; for 1 <= i <= min(M,N), row i of the   
+            matrix was interchanged with row IPIV(i).   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -k, the k-th argument had an illegal value   
+            > 0: if INFO = k, U(k,k) is exactly zero. The factorization   
+                 has been completed, but the factor U is exactly   
+                 singular, and division by zero will occur if it is used   
+                 to solve a system of equations.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --ipiv;
+
+    /* Function Body */
+    *info = 0;
+    if (*m < 0) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*m)) {
+	*info = -4;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGETF2", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+
+/*     Compute machine safe minimum */
+
+    sfmin = igraphdlamch_("S");
+
+    i__1 = min(*m,*n);
+    for (j = 1; j <= i__1; ++j) {
+
+/*        Find pivot and test for singularity. */
+
+	i__2 = *m - j + 1;
+	jp = j - 1 + igraphidamax_(&i__2, &a[j + j * a_dim1], &c__1);
+	ipiv[j] = jp;
+	if (a[jp + j * a_dim1] != 0.) {
+
+/*           Apply the interchange to columns 1:N. */
+
+	    if (jp != j) {
+		igraphdswap_(n, &a[j + a_dim1], lda, &a[jp + a_dim1], lda);
+	    }
+
+/*           Compute elements J+1:M of J-th column. */
+
+	    if (j < *m) {
+		if ((d__1 = a[j + j * a_dim1], abs(d__1)) >= sfmin) {
+		    i__2 = *m - j;
+		    d__1 = 1. / a[j + j * a_dim1];
+		    igraphdscal_(&i__2, &d__1, &a[j + 1 + j * a_dim1], &c__1);
+		} else {
+		    i__2 = *m - j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			a[j + i__ + j * a_dim1] /= a[j + j * a_dim1];
+/* L20: */
+		    }
+		}
+	    }
+
+	} else if (*info == 0) {
+
+	    *info = j;
+	}
+
+	if (j < min(*m,*n)) {
+
+/*           Update trailing submatrix. */
+
+	    i__2 = *m - j;
+	    i__3 = *n - j;
+	    igraphdger_(&i__2, &i__3, &c_b8, &a[j + 1 + j * a_dim1], &c__1, &a[j + (
+		    j + 1) * a_dim1], lda, &a[j + 1 + (j + 1) * a_dim1], lda);
+	}
+/* L10: */
+    }
+    return 0;
+
+/*     End of DGETF2 */
+
+} /* igraphdgetf2_ */
+
diff --git a/src/lapack/dgetrf.c b/src/lapack/dgetrf.c
new file mode 100644
index 0000000..b01f4fd
--- /dev/null
+++ b/src/lapack/dgetrf.c
@@ -0,0 +1,206 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static doublereal c_b16 = 1.;
+static doublereal c_b19 = -1.;
+
+/* Subroutine */ int igraphdgetrf_(integer *m, integer *n, doublereal *a, integer *
+	lda, integer *ipiv, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5;
+
+    /* Local variables */
+    integer i__, j, jb, nb;
+    extern /* Subroutine */ int igraphdgemm_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    integer iinfo;
+    extern /* Subroutine */ int igraphdtrsm_(char *, char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdgetf2_(
+	    integer *, integer *, doublereal *, integer *, integer *, integer 
+	    *), igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphdlaswp_(integer *, doublereal *, integer *, 
+	    integer *, integer *, integer *, integer *);
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DGETRF computes an LU factorization of a general M-by-N matrix A   
+    using partial pivoting with row interchanges.   
+
+    The factorization has the form   
+       A = P * L * U   
+    where P is a permutation matrix, L is lower triangular with unit   
+    diagonal elements (lower trapezoidal if m > n), and U is upper   
+    triangular (upper trapezoidal if m < n).   
+
+    This is the right-looking Level 3 BLAS version of the algorithm.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the M-by-N matrix to be factored.   
+            On exit, the factors L and U from the factorization   
+            A = P*L*U; the unit diagonal elements of L are not stored.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+    IPIV    (output) INTEGER array, dimension (min(M,N))   
+            The pivot indices; for 1 <= i <= min(M,N), row i of the   
+            matrix was interchanged with row IPIV(i).   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  if INFO = i, U(i,i) is exactly zero. The factorization   
+                  has been completed, but the factor U is exactly   
+                  singular, and division by zero will occur if it is used   
+                  to solve a system of equations.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --ipiv;
+
+    /* Function Body */
+    *info = 0;
+    if (*m < 0) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*m)) {
+	*info = -4;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGETRF", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+
+/*     Determine the block size for this environment. */
+
+    nb = igraphilaenv_(&c__1, "DGETRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)
+	    1);
+    if (nb <= 1 || nb >= min(*m,*n)) {
+
+/*        Use unblocked code. */
+
+	igraphdgetf2_(m, n, &a[a_offset], lda, &ipiv[1], info);
+    } else {
+
+/*        Use blocked code. */
+
+	i__1 = min(*m,*n);
+	i__2 = nb;
+	for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) {
+/* Computing MIN */
+	    i__3 = min(*m,*n) - j + 1;
+	    jb = min(i__3,nb);
+
+/*           Factor diagonal and subdiagonal blocks and test for exact   
+             singularity. */
+
+	    i__3 = *m - j + 1;
+	    igraphdgetf2_(&i__3, &jb, &a[j + j * a_dim1], lda, &ipiv[j], &iinfo);
+
+/*           Adjust INFO and the pivot indices. */
+
+	    if (*info == 0 && iinfo > 0) {
+		*info = iinfo + j - 1;
+	    }
+/* Computing MIN */
+	    i__4 = *m, i__5 = j + jb - 1;
+	    i__3 = min(i__4,i__5);
+	    for (i__ = j; i__ <= i__3; ++i__) {
+		ipiv[i__] = j - 1 + ipiv[i__];
+/* L10: */
+	    }
+
+/*           Apply interchanges to columns 1:J-1. */
+
+	    i__3 = j - 1;
+	    i__4 = j + jb - 1;
+	    igraphdlaswp_(&i__3, &a[a_offset], lda, &j, &i__4, &ipiv[1], &c__1);
+
+	    if (j + jb <= *n) {
+
+/*              Apply interchanges to columns J+JB:N. */
+
+		i__3 = *n - j - jb + 1;
+		i__4 = j + jb - 1;
+		igraphdlaswp_(&i__3, &a[(j + jb) * a_dim1 + 1], lda, &j, &i__4, &
+			ipiv[1], &c__1);
+
+/*              Compute block row of U. */
+
+		i__3 = *n - j - jb + 1;
+		igraphdtrsm_("Left", "Lower", "No transpose", "Unit", &jb, &i__3, &
+			c_b16, &a[j + j * a_dim1], lda, &a[j + (j + jb) * 
+			a_dim1], lda);
+		if (j + jb <= *m) {
+
+/*                 Update trailing submatrix. */
+
+		    i__3 = *m - j - jb + 1;
+		    i__4 = *n - j - jb + 1;
+		    igraphdgemm_("No transpose", "No transpose", &i__3, &i__4, &jb, 
+			    &c_b19, &a[j + jb + j * a_dim1], lda, &a[j + (j + 
+			    jb) * a_dim1], lda, &c_b16, &a[j + jb + (j + jb) *
+			     a_dim1], lda);
+		}
+	    }
+/* L20: */
+	}
+    }
+    return 0;
+
+/*     End of DGETRF */
+
+} /* igraphdgetrf_ */
+
diff --git a/src/lapack/dgetrs.c b/src/lapack/dgetrs.c
new file mode 100644
index 0000000..4a0ea03
--- /dev/null
+++ b/src/lapack/dgetrs.c
@@ -0,0 +1,172 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b12 = 1.;
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdgetrs_(char *trans, integer *n, integer *nrhs, 
+	doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer *
+	ldb, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, i__1;
+
+    /* Local variables */
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdtrsm_(char *, char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphxerbla_(
+	    char *, integer *, ftnlen), igraphdlaswp_(integer *, doublereal *, 
+	    integer *, integer *, integer *, integer *, integer *);
+    logical notran;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DGETRS solves a system of linear equations   
+       A * X = B  or  A**T * X = B   
+    with a general N-by-N matrix A using the LU factorization computed   
+    by DGETRF.   
+
+    Arguments   
+    =========   
+
+    TRANS   (input) CHARACTER*1   
+            Specifies the form of the system of equations:   
+            = 'N':  A * X = B  (No transpose)   
+            = 'T':  A**T* X = B  (Transpose)   
+            = 'C':  A**T* X = B  (Conjugate transpose = Transpose)   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    NRHS    (input) INTEGER   
+            The number of right hand sides, i.e., the number of columns   
+            of the matrix B.  NRHS >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The factors L and U from the factorization A = P*L*U   
+            as computed by DGETRF.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    IPIV    (input) INTEGER array, dimension (N)   
+            The pivot indices from DGETRF; for 1<=i<=N, row i of the   
+            matrix was interchanged with row IPIV(i).   
+
+    B       (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS)   
+            On entry, the right hand side matrix B.   
+            On exit, the solution matrix X.   
+
+    LDB     (input) INTEGER   
+            The leading dimension of the array B.  LDB >= max(1,N).   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --ipiv;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+
+    /* Function Body */
+    *info = 0;
+    notran = igraphlsame_(trans, "N");
+    if (! notran && ! igraphlsame_(trans, "T") && ! igraphlsame_(
+	    trans, "C")) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*nrhs < 0) {
+	*info = -3;
+    } else if (*lda < max(1,*n)) {
+	*info = -5;
+    } else if (*ldb < max(1,*n)) {
+	*info = -8;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DGETRS", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0 || *nrhs == 0) {
+	return 0;
+    }
+
+    if (notran) {
+
+/*        Solve A * X = B.   
+
+          Apply row interchanges to the right hand sides. */
+
+	igraphdlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c__1);
+
+/*        Solve L*X = B, overwriting B with X. */
+
+	igraphdtrsm_("Left", "Lower", "No transpose", "Unit", n, nrhs, &c_b12, &a[
+		a_offset], lda, &b[b_offset], ldb);
+
+/*        Solve U*X = B, overwriting B with X. */
+
+	igraphdtrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b12, &
+		a[a_offset], lda, &b[b_offset], ldb);
+    } else {
+
+/*        Solve A**T * X = B.   
+
+          Solve U**T *X = B, overwriting B with X. */
+
+	igraphdtrsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b12, &a[
+		a_offset], lda, &b[b_offset], ldb);
+
+/*        Solve L**T *X = B, overwriting B with X. */
+
+	igraphdtrsm_("Left", "Lower", "Transpose", "Unit", n, nrhs, &c_b12, &a[
+		a_offset], lda, &b[b_offset], ldb);
+
+/*        Apply row interchanges to the solution vectors. */
+
+	igraphdlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c_n1);
+    }
+
+    return 0;
+
+/*     End of DGETRS */
+
+} /* igraphdgetrs_ */
+
diff --git a/src/lapack/dgetv0.c b/src/lapack/dgetv0.c
new file mode 100644
index 0000000..996d1e6
--- /dev/null
+++ b/src/lapack/dgetv0.c
@@ -0,0 +1,480 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b24 = 1.;
+static doublereal c_b26 = 0.;
+static doublereal c_b29 = -1.;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dgetv0   
+
+   \Description:   
+    Generate a random initial residual vector for the Arnoldi process.   
+    Force the residual vector to be in the range of the operator OP.   
+
+   \Usage:   
+    call dgetv0   
+       ( IDO, BMAT, ITRY, INITV, N, J, V, LDV, RESID, RNORM,   
+         IPNTR, WORKD, IERR )   
+
+   \Arguments   
+    IDO     Integer.  (INPUT/OUTPUT)   
+            Reverse communication flag.  IDO must be zero on the first   
+            call to dgetv0.   
+            -------------------------------------------------------------   
+            IDO =  0: first call to the reverse communication interface   
+            IDO = -1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+                      This is for the initialization phase to force the   
+                      starting vector into the range of OP.   
+            IDO =  2: compute  Y = B * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+            IDO = 99: done   
+            -------------------------------------------------------------   
+
+    BMAT    Character*1.  (INPUT)   
+            BMAT specifies the type of the matrix B in the (generalized)   
+            eigenvalue problem A*x = lambda*B*x.   
+            B = 'I' -> standard eigenvalue problem A*x = lambda*x   
+            B = 'G' -> generalized eigenvalue problem A*x = lambda*B*x   
+
+    ITRY    Integer.  (INPUT)   
+            ITRY counts the number of times that dgetv0 is called.   
+            It should be set to 1 on the initial call to dgetv0.   
+
+    INITV   Logical variable.  (INPUT)   
+            .TRUE.  => the initial residual vector is given in RESID.   
+            .FALSE. => generate a random initial residual vector.   
+
+    N       Integer.  (INPUT)   
+            Dimension of the problem.   
+
+    J       Integer.  (INPUT)   
+            Index of the residual vector to be generated, with respect to   
+            the Arnoldi process.  J > 1 in case of a "restart".   
+
+    V       Double precision N by J array.  (INPUT)   
+            The first J-1 columns of V contain the current Arnoldi basis   
+            if this is a "restart".   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    RESID   Double precision array of length N.  (INPUT/OUTPUT)   
+            Initial residual vector to be generated.  If RESID is   
+            provided, force RESID into the range of the operator OP.   
+
+    RNORM   Double precision scalar.  (OUTPUT)   
+            B-norm of the generated residual.   
+
+    IPNTR   Integer array of length 3.  (OUTPUT)   
+
+    WORKD   Double precision work array of length 2*N.  (REVERSE COMMUNICATION).   
+            On exit, WORK(1:N) = B*RESID to be used in SSAITR.   
+
+    IERR    Integer.  (OUTPUT)   
+            =  0: Normal exit.   
+            = -1: Cannot generate a nontrivial restarted residual vector   
+                  in the range of the operator OP.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+
+   \Routines called:   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine for vector output.   
+       dlarnv  LAPACK routine for generating a random vector.   
+       dgemv   Level 2 BLAS routine for matrix vector multiplication.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+       ddot    Level 1 BLAS that computes the scalar product of two vectors.   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \SCCS Information: @(#)   
+   FILE: getv0.F   SID: 2.6   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdgetv0_(integer *ido, char *bmat, integer *itry, logical 
+	*initv, integer *n, integer *j, doublereal *v, integer *ldv, 
+	doublereal *resid, doublereal *rnorm, integer *ipntr, doublereal *
+	workd, integer *ierr)
+{
+    /* Initialized data */
+
+    IGRAPH_F77_SAVE logical inits = TRUE_;
+
+    /* System generated locals */
+    integer v_dim1, v_offset, i__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    real t0, t1, t2, t3;
+    integer jj, nbx;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    IGRAPH_F77_SAVE integer iter;
+    IGRAPH_F77_SAVE logical orth;
+    integer nopx;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    IGRAPH_F77_SAVE integer iseed[4];
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *);
+    integer idist;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    IGRAPH_F77_SAVE logical first;
+    real tmvbx;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen);
+    integer mgetv0=0;
+    real tgetv0;
+    IGRAPH_F77_SAVE doublereal rnorm0;
+    extern /* Subroutine */ int igraphsecond_(real *);
+    integer logfil=0, ndigit;
+    extern /* Subroutine */ int igraphdlarnv_(integer *, integer *, integer *, 
+	    doublereal *);
+    IGRAPH_F77_SAVE integer msglvl;
+    real tmvopx;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %------------------------%   
+       | Local Scalars & Arrays |   
+       %------------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------%   
+       | Data Statements |   
+       %-----------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    --ipntr;
+
+    /* Function Body   
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+
+       %-----------------------------------%   
+       | Initialize the seed of the LAPACK |   
+       | random number generator           |   
+       %-----------------------------------% */
+
+    if (inits) {
+	iseed[0] = 1;
+	iseed[1] = 3;
+	iseed[2] = 5;
+	iseed[3] = 7;
+	inits = FALSE_;
+    }
+
+    if (*ido == 0) {
+
+/*        %-------------------------------%   
+          | Initialize timing statistics  |   
+          | & message level for debugging |   
+          %-------------------------------% */
+
+	igraphsecond_(&t0);
+	msglvl = mgetv0;
+
+	*ierr = 0;
+	iter = 0;
+	first = FALSE_;
+	orth = FALSE_;
+
+/*        %-----------------------------------------------------%   
+          | Possibly generate a random starting vector in RESID |   
+          | Use a LAPACK random number generator used by the    |   
+          | matrix generation routines.                         |   
+          |    idist = 1: uniform (0,1)  distribution;          |   
+          |    idist = 2: uniform (-1,1) distribution;          |   
+          |    idist = 3: normal  (0,1)  distribution;          |   
+          %-----------------------------------------------------% */
+
+	if (! (*initv)) {
+	    idist = 2;
+	    igraphdlarnv_(&idist, iseed, n, &resid[1]);
+	}
+
+/*        %----------------------------------------------------------%   
+          | Force the starting vector into the range of OP to handle |   
+          | the generalized problem when B is possibly (singular).   |   
+          %----------------------------------------------------------% */
+
+	igraphsecond_(&t2);
+	if (*(unsigned char *)bmat == 'G') {
+	    ++nopx;
+	    ipntr[1] = 1;
+	    ipntr[2] = *n + 1;
+	    igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
+	    *ido = -1;
+	    goto L9000;
+	}
+    }
+
+/*     %-----------------------------------------%   
+       | Back from computing OP*(initial-vector) |   
+       %-----------------------------------------% */
+
+    if (first) {
+	goto L20;
+    }
+
+/*     %-----------------------------------------------%   
+       | Back from computing B*(orthogonalized-vector) |   
+       %-----------------------------------------------% */
+
+    if (orth) {
+	goto L40;
+    }
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvopx += t3 - t2;
+    }
+
+/*     %------------------------------------------------------%   
+       | Starting vector is now in the range of OP; r = OP*r; |   
+       | Compute B-norm of starting vector.                   |   
+       %------------------------------------------------------% */
+
+    igraphsecond_(&t2);
+    first = TRUE_;
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &workd[*n + 1], &c__1, &resid[1], &c__1);
+	ipntr[1] = *n + 1;
+	ipntr[2] = 1;
+	*ido = 2;
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
+    }
+
+L20:
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    first = FALSE_;
+    if (*(unsigned char *)bmat == 'G') {
+	rnorm0 = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1);
+	rnorm0 = sqrt((abs(rnorm0)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	rnorm0 = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+    *rnorm = rnorm0;
+
+/*     %---------------------------------------------%   
+       | Exit if this is the very first Arnoldi step |   
+       %---------------------------------------------% */
+
+    if (*j == 1) {
+	goto L50;
+    }
+
+/*     %----------------------------------------------------------------   
+       | Otherwise need to B-orthogonalize the starting vector against |   
+       | the current Arnoldi basis using Gram-Schmidt with iter. ref.  |   
+       | This is the case where an invariant subspace is encountered   |   
+       | in the middle of the Arnoldi factorization.                   |   
+       |                                                               |   
+       |       s = V^{T}*B*r;   r = r - V*s;                           |   
+       |                                                               |   
+       | Stopping criteria used for iter. ref. is discussed in         |   
+       | Parlett's book, page 107 and in Gragg & Reichel TOMS paper.   |   
+       %---------------------------------------------------------------% */
+
+    orth = TRUE_;
+L30:
+
+    i__1 = *j - 1;
+    igraphdgemv_("T", n, &i__1, &c_b24, &v[v_offset], ldv, &workd[1], &c__1, &c_b26,
+	     &workd[*n + 1], &c__1);
+    i__1 = *j - 1;
+    igraphdgemv_("N", n, &i__1, &c_b29, &v[v_offset], ldv, &workd[*n + 1], &c__1, &
+	    c_b24, &resid[1], &c__1);
+
+/*     %----------------------------------------------------------%   
+       | Compute the B-norm of the orthogonalized starting vector |   
+       %----------------------------------------------------------% */
+
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[*n + 1], &c__1);
+	ipntr[1] = *n + 1;
+	ipntr[2] = 1;
+	*ido = 2;
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
+    }
+
+L40:
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    if (*(unsigned char *)bmat == 'G') {
+	*rnorm = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1);
+	*rnorm = sqrt((abs(*rnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	*rnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+/*     %--------------------------------------%   
+       | Check for further orthogonalization. |   
+       %--------------------------------------% */
+
+    if (msglvl > 2) {
+	igraphdvout_(&logfil, &c__1, &rnorm0, &ndigit, "_getv0: re-orthonalization"
+		" ; rnorm0 is", (ftnlen)38);
+	igraphdvout_(&logfil, &c__1, rnorm, &ndigit, "_getv0: re-orthonalization ;"
+		" rnorm is", (ftnlen)37);
+    }
+
+    if (*rnorm > rnorm0 * .717f) {
+	goto L50;
+    }
+
+    ++iter;
+    if (iter <= 1) {
+
+/*        %-----------------------------------%   
+          | Perform iterative refinement step |   
+          %-----------------------------------% */
+
+	rnorm0 = *rnorm;
+	goto L30;
+    } else {
+
+/*        %------------------------------------%   
+          | Iterative refinement step "failed" |   
+          %------------------------------------% */
+
+	i__1 = *n;
+	for (jj = 1; jj <= i__1; ++jj) {
+	    resid[jj] = 0.;
+/* L45: */
+	}
+	*rnorm = 0.;
+	*ierr = -1;
+    }
+
+L50:
+
+    if (msglvl > 0) {
+	igraphdvout_(&logfil, &c__1, rnorm, &ndigit, "_getv0: B-norm of initial / "
+		"restarted starting vector", (ftnlen)53);
+    }
+    if (msglvl > 2) {
+	igraphdvout_(&logfil, n, &resid[1], &ndigit, "_getv0: initial / restarted "
+		"starting vector", (ftnlen)43);
+    }
+    *ido = 99;
+
+    igraphsecond_(&t1);
+    tgetv0 += t1 - t0;
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dgetv0 |   
+       %---------------% */
+
+} /* igraphdgetv0_ */
+
diff --git a/src/lapack/dhseqr.c b/src/lapack/dhseqr.c
new file mode 100644
index 0000000..6dbb65e
--- /dev/null
+++ b/src/lapack/dhseqr.c
@@ -0,0 +1,471 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b11 = 0.;
+static doublereal c_b12 = 1.;
+static integer c__12 = 12;
+static integer c__2 = 2;
+static integer c__49 = 49;
+
+/* Subroutine */ int igraphdhseqr_(char *job, char *compz, integer *n, integer *ilo,
+	 integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, 
+	doublereal *wi, doublereal *z__, integer *ldz, doublereal *work, 
+	integer *lwork, integer *info)
+{
+    /* System generated locals */
+    address a__1[2];
+    integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2[2], i__3;
+    doublereal d__1;
+    char ch__1[2];
+
+    /* Builtin functions   
+       Subroutine */ int s_cat(char *, char **, integer *, integer *, ftnlen);
+
+    /* Local variables */
+    integer i__;
+    doublereal hl[2401]	/* was [49][49] */;
+    integer kbot, nmin;
+    extern logical igraphlsame_(char *, char *);
+    logical initz;
+    doublereal workl[49];
+    logical wantt, wantz;
+    extern /* Subroutine */ int igraphdlaqr0_(logical *, logical *, integer *, 
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *, integer *), igraphdlahqr_(logical *, logical *,
+	     integer *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *), igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlaset_(char *, integer *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical lquery;
+
+
+/*  -- LAPACK computational routine (version 3.2.2) --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+       June 2010   
+
+       Purpose   
+       =======   
+
+       DHSEQR computes the eigenvalues of a Hessenberg matrix H   
+       and, optionally, the matrices T and Z from the Schur decomposition   
+       H = Z T Z**T, where T is an upper quasi-triangular matrix (the   
+       Schur form), and Z is the orthogonal matrix of Schur vectors.   
+
+       Optionally Z may be postmultiplied into an input orthogonal   
+       matrix Q so that this routine can give the Schur factorization   
+       of a matrix A which has been reduced to the Hessenberg form H   
+       by the orthogonal matrix Q:  A = Q*H*Q**T = (QZ)*T*(QZ)**T.   
+
+       Arguments   
+       =========   
+
+       JOB   (input) CHARACTER*1   
+             = 'E':  compute eigenvalues only;   
+             = 'S':  compute eigenvalues and the Schur form T.   
+
+       COMPZ (input) CHARACTER*1   
+             = 'N':  no Schur vectors are computed;   
+             = 'I':  Z is initialized to the unit matrix and the matrix Z   
+                     of Schur vectors of H is returned;   
+             = 'V':  Z must contain an orthogonal matrix Q on entry, and   
+                     the product Q*Z is returned.   
+
+       N     (input) INTEGER   
+             The order of the matrix H.  N .GE. 0.   
+
+       ILO   (input) INTEGER   
+       IHI   (input) INTEGER   
+             It is assumed that H is already upper triangular in rows   
+             and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally   
+             set by a previous call to DGEBAL, and then passed to DGEHRD   
+             when the matrix output by DGEBAL is reduced to Hessenberg   
+             form. Otherwise ILO and IHI should be set to 1 and N   
+             respectively.  If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N.   
+             If N = 0, then ILO = 1 and IHI = 0.   
+
+       H     (input/output) DOUBLE PRECISION array, dimension (LDH,N)   
+             On entry, the upper Hessenberg matrix H.   
+             On exit, if INFO = 0 and JOB = 'S', then H contains the   
+             upper quasi-triangular matrix T from the Schur decomposition   
+             (the Schur form); 2-by-2 diagonal blocks (corresponding to   
+             complex conjugate pairs of eigenvalues) are returned in   
+             standard form, with H(i,i) = H(i+1,i+1) and   
+             H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and JOB = 'E', the   
+             contents of H are unspecified on exit.  (The output value of   
+             H when INFO.GT.0 is given under the description of INFO   
+             below.)   
+
+             Unlike earlier versions of DHSEQR, this subroutine may   
+             explicitly H(i,j) = 0 for i.GT.j and j = 1, 2, ... ILO-1   
+             or j = IHI+1, IHI+2, ... N.   
+
+       LDH   (input) INTEGER   
+             The leading dimension of the array H. LDH .GE. max(1,N).   
+
+       WR    (output) DOUBLE PRECISION array, dimension (N)   
+       WI    (output) DOUBLE PRECISION array, dimension (N)   
+             The real and imaginary parts, respectively, of the computed   
+             eigenvalues. If two eigenvalues are computed as a complex   
+             conjugate pair, they are stored in consecutive elements of   
+             WR and WI, say the i-th and (i+1)th, with WI(i) .GT. 0 and   
+             WI(i+1) .LT. 0. If JOB = 'S', the eigenvalues are stored in   
+             the same order as on the diagonal of the Schur form returned   
+             in H, with WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2   
+             diagonal block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and   
+             WI(i+1) = -WI(i).   
+
+       Z     (input/output) DOUBLE PRECISION array, dimension (LDZ,N)   
+             If COMPZ = 'N', Z is not referenced.   
+             If COMPZ = 'I', on entry Z need not be set and on exit,   
+             if INFO = 0, Z contains the orthogonal matrix Z of the Schur   
+             vectors of H.  If COMPZ = 'V', on entry Z must contain an   
+             N-by-N matrix Q, which is assumed to be equal to the unit   
+             matrix except for the submatrix Z(ILO:IHI,ILO:IHI). On exit,   
+             if INFO = 0, Z contains Q*Z.   
+             Normally Q is the orthogonal matrix generated by DORGHR   
+             after the call to DGEHRD which formed the Hessenberg matrix   
+             H. (The output value of Z when INFO.GT.0 is given under   
+             the description of INFO below.)   
+
+       LDZ   (input) INTEGER   
+             The leading dimension of the array Z.  if COMPZ = 'I' or   
+             COMPZ = 'V', then LDZ.GE.MAX(1,N).  Otherwize, LDZ.GE.1.   
+
+       WORK  (workspace/output) DOUBLE PRECISION array, dimension (LWORK)   
+             On exit, if INFO = 0, WORK(1) returns an estimate of   
+             the optimal value for LWORK.   
+
+       LWORK (input) INTEGER   
+             The dimension of the array WORK.  LWORK .GE. max(1,N)   
+             is sufficient and delivers very good and sometimes   
+             optimal performance.  However, LWORK as large as 11*N   
+             may be required for optimal performance.  A workspace   
+             query is recommended to determine the optimal workspace   
+             size.   
+
+             If LWORK = -1, then DHSEQR does a workspace query.   
+             In this case, DHSEQR checks the input parameters and   
+             estimates the optimal workspace size for the given   
+             values of N, ILO and IHI.  The estimate is returned   
+             in WORK(1).  No error message related to LWORK is   
+             issued by XERBLA.  Neither H nor Z are accessed.   
+
+
+       INFO  (output) INTEGER   
+               =  0:  successful exit   
+             .LT. 0:  if INFO = -i, the i-th argument had an illegal   
+                      value   
+             .GT. 0:  if INFO = i, DHSEQR failed to compute all of   
+                  the eigenvalues.  Elements 1:ilo-1 and i+1:n of WR   
+                  and WI contain those eigenvalues which have been   
+                  successfully computed.  (Failures are rare.)   
+
+                  If INFO .GT. 0 and JOB = 'E', then on exit, the   
+                  remaining unconverged eigenvalues are the eigen-   
+                  values of the upper Hessenberg matrix rows and   
+                  columns ILO through INFO of the final, output   
+                  value of H.   
+
+                  If INFO .GT. 0 and JOB   = 'S', then on exit   
+
+             (*)  (initial value of H)*U  = U*(final value of H)   
+
+                  where U is an orthogonal matrix.  The final   
+                  value of H is upper Hessenberg and quasi-triangular   
+                  in rows and columns INFO+1 through IHI.   
+
+                  If INFO .GT. 0 and COMPZ = 'V', then on exit   
+
+                    (final value of Z)  =  (initial value of Z)*U   
+
+                  where U is the orthogonal matrix in (*) (regard-   
+                  less of the value of JOB.)   
+
+                  If INFO .GT. 0 and COMPZ = 'I', then on exit   
+                        (final value of Z)  = U   
+                  where U is the orthogonal matrix in (*) (regard-   
+                  less of the value of JOB.)   
+
+                  If INFO .GT. 0 and COMPZ = 'N', then Z is not   
+                  accessed.   
+
+       ================================================================   
+               Default values supplied by   
+               ILAENV(ISPEC,'DHSEQR',JOB(:1)//COMPZ(:1),N,ILO,IHI,LWORK).   
+               It is suggested that these defaults be adjusted in order   
+               to attain best performance in each particular   
+               computational environment.   
+
+              ISPEC=12: The DLAHQR vs DLAQR0 crossover point.   
+                        Default: 75. (Must be at least 11.)   
+
+              ISPEC=13: Recommended deflation window size.   
+                        This depends on ILO, IHI and NS.  NS is the   
+                        number of simultaneous shifts returned   
+                        by ILAENV(ISPEC=15).  (See ISPEC=15 below.)   
+                        The default for (IHI-ILO+1).LE.500 is NS.   
+                        The default for (IHI-ILO+1).GT.500 is 3*NS/2.   
+
+              ISPEC=14: Nibble crossover point. (See IPARMQ for   
+                        details.)  Default: 14% of deflation window   
+                        size.   
+
+              ISPEC=15: Number of simultaneous shifts in a multishift   
+                        QR iteration.   
+
+                        If IHI-ILO+1 is ...   
+
+                        greater than      ...but less    ... the   
+                        or equal to ...      than        default is   
+
+                             1               30          NS =   2(+)   
+                            30               60          NS =   4(+)   
+                            60              150          NS =  10(+)   
+                           150              590          NS =  **   
+                           590             3000          NS =  64   
+                          3000             6000          NS = 128   
+                          6000             infinity      NS = 256   
+
+                    (+)  By default some or all matrices of this order   
+                         are passed to the implicit double shift routine   
+                         DLAHQR and this parameter is ignored.  See   
+                         ISPEC=12 above and comments in IPARMQ for   
+                         details.   
+
+                   (**)  The asterisks (**) indicate an ad-hoc   
+                         function of N increasing from 10 to 64.   
+
+              ISPEC=16: Select structured matrix multiply.   
+                        If the number of simultaneous shifts (specified   
+                        by ISPEC=15) is less than 14, then the default   
+                        for ISPEC=16 is 0.  Otherwise the default for   
+                        ISPEC=16 is 2.   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+       References:   
+         K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+         Algorithm Part I: Maintaining Well Focused Shifts, and Level 3   
+         Performance, SIAM Journal of Matrix Analysis, volume 23, pages   
+         929--947, 2002.   
+
+         K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+         Algorithm Part II: Aggressive Early Deflation, SIAM Journal   
+         of Matrix Analysis, volume 23, pages 948--973, 2002.   
+
+       ================================================================   
+
+       ==== Matrices of order NTINY or smaller must be processed by   
+       .    DLAHQR because of insufficient subdiagonal scratch space.   
+       .    (This is a hard limit.) ====   
+
+       ==== NL allocates some local workspace to help small matrices   
+       .    through a rare DLAHQR failure.  NL .GT. NTINY = 11 is   
+       .    required and NL .LE. NMIN = ILAENV(ISPEC=12,...) is recom-   
+       .    mended.  (The default value of NMIN is 75.)  Using NL = 49   
+       .    allows up to six simultaneous shifts and a 16-by-16   
+       .    deflation window.  ====   
+
+       ==== Decode and check the input parameters. ====   
+
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --wr;
+    --wi;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --work;
+
+    /* Function Body */
+    wantt = igraphlsame_(job, "S");
+    initz = igraphlsame_(compz, "I");
+    wantz = initz || igraphlsame_(compz, "V");
+    work[1] = (doublereal) max(1,*n);
+    lquery = *lwork == -1;
+
+    *info = 0;
+    if (! igraphlsame_(job, "E") && ! wantt) {
+	*info = -1;
+    } else if (! igraphlsame_(compz, "N") && ! wantz) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -3;
+    } else if (*ilo < 1 || *ilo > max(1,*n)) {
+	*info = -4;
+    } else if (*ihi < min(*ilo,*n) || *ihi > *n) {
+	*info = -5;
+    } else if (*ldh < max(1,*n)) {
+	*info = -7;
+    } else if (*ldz < 1 || wantz && *ldz < max(1,*n)) {
+	*info = -11;
+    } else if (*lwork < max(1,*n) && ! lquery) {
+	*info = -13;
+    }
+
+    if (*info != 0) {
+
+/*        ==== Quick return in case of invalid argument. ==== */
+
+	i__1 = -(*info);
+	igraphxerbla_("DHSEQR", &i__1, (ftnlen)6);
+	return 0;
+
+    } else if (*n == 0) {
+
+/*        ==== Quick return in case N = 0; nothing to do. ==== */
+
+	return 0;
+
+    } else if (lquery) {
+
+/*        ==== Quick return in case of a workspace query ==== */
+
+	igraphdlaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], &wi[
+		1], ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, info);
+/*        ==== Ensure reported workspace size is backward-compatible with   
+          .    previous LAPACK versions. ====   
+   Computing MAX */
+	d__1 = (doublereal) max(1,*n);
+	work[1] = max(d__1,work[1]);
+	return 0;
+
+    } else {
+
+/*        ==== copy eigenvalues isolated by DGEBAL ==== */
+
+	i__1 = *ilo - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    wr[i__] = h__[i__ + i__ * h_dim1];
+	    wi[i__] = 0.;
+/* L10: */
+	}
+	i__1 = *n;
+	for (i__ = *ihi + 1; i__ <= i__1; ++i__) {
+	    wr[i__] = h__[i__ + i__ * h_dim1];
+	    wi[i__] = 0.;
+/* L20: */
+	}
+
+/*        ==== Initialize Z, if requested ==== */
+
+	if (initz) {
+	    igraphdlaset_("A", n, n, &c_b11, &c_b12, &z__[z_offset], ldz)
+		    ;
+	}
+
+/*        ==== Quick return if possible ==== */
+
+	if (*ilo == *ihi) {
+	    wr[*ilo] = h__[*ilo + *ilo * h_dim1];
+	    wi[*ilo] = 0.;
+	    return 0;
+	}
+
+/*        ==== DLAHQR/DLAQR0 crossover point ====   
+
+   Writing concatenation */
+	i__2[0] = 1, a__1[0] = job;
+	i__2[1] = 1, a__1[1] = compz;
+	s_cat(ch__1, a__1, i__2, &c__2, (ftnlen)2);
+	nmin = igraphilaenv_(&c__12, "DHSEQR", ch__1, n, ilo, ihi, lwork, (ftnlen)6,
+		 (ftnlen)2);
+	nmin = max(11,nmin);
+
+/*        ==== DLAQR0 for big matrices; DLAHQR for small ones ==== */
+
+	if (*n > nmin) {
+	    igraphdlaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], 
+		    &wi[1], ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, 
+		    info);
+	} else {
+
+/*           ==== Small matrix ==== */
+
+	    igraphdlahqr_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], 
+		    &wi[1], ilo, ihi, &z__[z_offset], ldz, info);
+
+	    if (*info > 0) {
+
+/*              ==== A rare DLAHQR failure!  DLAQR0 sometimes succeeds   
+                .    when DLAHQR fails. ==== */
+
+		kbot = *info;
+
+		if (*n >= 49) {
+
+/*                 ==== Larger matrices have enough subdiagonal scratch   
+                   .    space to call DLAQR0 directly. ==== */
+
+		    igraphdlaqr0_(&wantt, &wantz, n, ilo, &kbot, &h__[h_offset], 
+			    ldh, &wr[1], &wi[1], ilo, ihi, &z__[z_offset], 
+			    ldz, &work[1], lwork, info);
+
+		} else {
+
+/*                 ==== Tiny matrices don't have enough subdiagonal   
+                   .    scratch space to benefit from DLAQR0.  Hence,   
+                   .    tiny matrices must be copied into a larger   
+                   .    array before calling DLAQR0. ==== */
+
+		    igraphdlacpy_("A", n, n, &h__[h_offset], ldh, hl, &c__49);
+		    hl[*n + 1 + *n * 49 - 50] = 0.;
+		    i__1 = 49 - *n;
+		    igraphdlaset_("A", &c__49, &i__1, &c_b11, &c_b11, &hl[(*n + 1) *
+			     49 - 49], &c__49);
+		    igraphdlaqr0_(&wantt, &wantz, &c__49, ilo, &kbot, hl, &c__49, &
+			    wr[1], &wi[1], ilo, ihi, &z__[z_offset], ldz, 
+			    workl, &c__49, info);
+		    if (wantt || *info != 0) {
+			igraphdlacpy_("A", n, n, hl, &c__49, &h__[h_offset], ldh);
+		    }
+		}
+	    }
+	}
+
+/*        ==== Clear out the trash, if necessary. ==== */
+
+	if ((wantt || *info != 0) && *n > 2) {
+	    i__1 = *n - 2;
+	    i__3 = *n - 2;
+	    igraphdlaset_("L", &i__1, &i__3, &c_b11, &c_b11, &h__[h_dim1 + 3], ldh);
+	}
+
+/*        ==== Ensure reported workspace size is backward-compatible with   
+          .    previous LAPACK versions. ====   
+
+   Computing MAX */
+	d__1 = (doublereal) max(1,*n);
+	work[1] = max(d__1,work[1]);
+    }
+
+/*     ==== End of DHSEQR ==== */
+
+    return 0;
+} /* igraphdhseqr_ */
+
diff --git a/src/lapack/disnan.c b/src/lapack/disnan.c
new file mode 100644
index 0000000..098d84f
--- /dev/null
+++ b/src/lapack/disnan.c
@@ -0,0 +1,48 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+logical igraphdisnan_(doublereal *din)
+{
+    /* System generated locals */
+    logical ret_val;
+
+    /* Local variables */
+    extern logical igraphdlaisnan_(doublereal *, doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    DISNAN returns .TRUE. if its argument is NaN, and .FALSE.   
+    otherwise.  To be replaced by the Fortran 2003 intrinsic in the   
+    future.   
+
+    Arguments   
+    =========   
+
+    DIN     (input) DOUBLE PRECISION   
+            Input to test for NaN.   
+
+    ===================================================================== */
+
+    ret_val = igraphdlaisnan_(din, din);
+    return ret_val;
+} /* igraphdisnan_ */
+
diff --git a/src/lapack/dlabad.c b/src/lapack/dlabad.c
new file mode 100644
index 0000000..263fc38
--- /dev/null
+++ b/src/lapack/dlabad.c
@@ -0,0 +1,68 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlabad_(doublereal *small, doublereal *large)
+{
+    /* Builtin functions */
+    double d_lg10(doublereal *), sqrt(doublereal);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLABAD takes as input the values computed by DLAMCH for underflow and   
+    overflow, and returns the square root of each of these values if the   
+    log of LARGE is sufficiently large.  This subroutine is intended to   
+    identify machines with a large exponent range, such as the Crays, and   
+    redefine the underflow and overflow limits to be the square roots of   
+    the values computed by DLAMCH.  This subroutine is needed because   
+    DLAMCH does not compensate for poor arithmetic in the upper half of   
+    the exponent range, as is found on a Cray.   
+
+    Arguments   
+    =========   
+
+    SMALL   (input/output) DOUBLE PRECISION   
+            On entry, the underflow threshold as computed by DLAMCH.   
+            On exit, if LOG10(LARGE) is sufficiently large, the square   
+            root of SMALL, otherwise unchanged.   
+
+    LARGE   (input/output) DOUBLE PRECISION   
+            On entry, the overflow threshold as computed by DLAMCH.   
+            On exit, if LOG10(LARGE) is sufficiently large, the square   
+            root of LARGE, otherwise unchanged.   
+
+    =====================================================================   
+
+
+       If it looks like we're on a Cray, take the square root of   
+       SMALL and LARGE to avoid overflow and underflow problems. */
+
+    if (d_lg10(large) > 2e3) {
+	*small = sqrt(*small);
+	*large = sqrt(*large);
+    }
+
+    return 0;
+
+/*     End of DLABAD */
+
+} /* igraphdlabad_ */
+
diff --git a/src/lapack/dlacn2.c b/src/lapack/dlacn2.c
new file mode 100644
index 0000000..67fd1b0
--- /dev/null
+++ b/src/lapack/dlacn2.c
@@ -0,0 +1,253 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b11 = 1.;
+
+/* Subroutine */ int igraphdlacn2_(integer *n, doublereal *v, doublereal *x, 
+	integer *isgn, doublereal *est, integer *kase, integer *isave)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1;
+
+    /* Builtin functions */
+    double d_sign(doublereal *, doublereal *);
+    integer i_dnnt(doublereal *);
+
+    /* Local variables */
+    integer i__;
+    doublereal temp;
+    extern doublereal igraphdasum_(integer *, doublereal *, integer *);
+    integer jlast;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    doublereal altsgn, estold;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLACN2 estimates the 1-norm of a square, real matrix A.   
+    Reverse communication is used for evaluating matrix-vector products.   
+
+    Arguments   
+    =========   
+
+    N      (input) INTEGER   
+           The order of the matrix.  N >= 1.   
+
+    V      (workspace) DOUBLE PRECISION array, dimension (N)   
+           On the final return, V = A*W,  where  EST = norm(V)/norm(W)   
+           (W is not returned).   
+
+    X      (input/output) DOUBLE PRECISION array, dimension (N)   
+           On an intermediate return, X should be overwritten by   
+                 A * X,   if KASE=1,   
+                 A**T * X,  if KASE=2,   
+           and DLACN2 must be re-called with all the other parameters   
+           unchanged.   
+
+    ISGN   (workspace) INTEGER array, dimension (N)   
+
+    EST    (input/output) DOUBLE PRECISION   
+           On entry with KASE = 1 or 2 and ISAVE(1) = 3, EST should be   
+           unchanged from the previous call to DLACN2.   
+           On exit, EST is an estimate (a lower bound) for norm(A).   
+
+    KASE   (input/output) INTEGER   
+           On the initial call to DLACN2, KASE should be 0.   
+           On an intermediate return, KASE will be 1 or 2, indicating   
+           whether X should be overwritten by A * X  or A**T * X.   
+           On the final return from DLACN2, KASE will again be 0.   
+
+    ISAVE  (input/output) INTEGER array, dimension (3)   
+           ISAVE is used to save variables between calls to DLACN2   
+
+    Further Details   
+    ======= =======   
+
+    Contributed by Nick Higham, University of Manchester.   
+    Originally named SONEST, dated March 16, 1988.   
+
+    Reference: N.J. Higham, "FORTRAN codes for estimating the one-norm of   
+    a real or complex matrix, with applications to condition estimation",   
+    ACM Trans. Math. Soft., vol. 14, no. 4, pp. 381-396, December 1988.   
+
+    This is a thread safe version of DLACON, which uses the array ISAVE   
+    in place of a SAVE statement, as follows:   
+
+       DLACON     DLACN2   
+        JUMP     ISAVE(1)   
+        J        ISAVE(2)   
+        ITER     ISAVE(3)   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --isave;
+    --isgn;
+    --x;
+    --v;
+
+    /* Function Body */
+    if (*kase == 0) {
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    x[i__] = 1. / (doublereal) (*n);
+/* L10: */
+	}
+	*kase = 1;
+	isave[1] = 1;
+	return 0;
+    }
+
+    switch (isave[1]) {
+	case 1:  goto L20;
+	case 2:  goto L40;
+	case 3:  goto L70;
+	case 4:  goto L110;
+	case 5:  goto L140;
+    }
+
+/*     ................ ENTRY   (ISAVE( 1 ) = 1)   
+       FIRST ITERATION.  X HAS BEEN OVERWRITTEN BY A*X. */
+
+L20:
+    if (*n == 1) {
+	v[1] = x[1];
+	*est = abs(v[1]);
+/*        ... QUIT */
+	goto L150;
+    }
+    *est = igraphdasum_(n, &x[1], &c__1);
+
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	x[i__] = d_sign(&c_b11, &x[i__]);
+	isgn[i__] = i_dnnt(&x[i__]);
+/* L30: */
+    }
+    *kase = 2;
+    isave[1] = 2;
+    return 0;
+
+/*     ................ ENTRY   (ISAVE( 1 ) = 2)   
+       FIRST ITERATION.  X HAS BEEN OVERWRITTEN BY TRANSPOSE(A)*X. */
+
+L40:
+    isave[2] = igraphidamax_(n, &x[1], &c__1);
+    isave[3] = 2;
+
+/*     MAIN LOOP - ITERATIONS 2,3,...,ITMAX. */
+
+L50:
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	x[i__] = 0.;
+/* L60: */
+    }
+    x[isave[2]] = 1.;
+    *kase = 1;
+    isave[1] = 3;
+    return 0;
+
+/*     ................ ENTRY   (ISAVE( 1 ) = 3)   
+       X HAS BEEN OVERWRITTEN BY A*X. */
+
+L70:
+    igraphdcopy_(n, &x[1], &c__1, &v[1], &c__1);
+    estold = *est;
+    *est = igraphdasum_(n, &v[1], &c__1);
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	d__1 = d_sign(&c_b11, &x[i__]);
+	if (i_dnnt(&d__1) != isgn[i__]) {
+	    goto L90;
+	}
+/* L80: */
+    }
+/*     REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. */
+    goto L120;
+
+L90:
+/*     TEST FOR CYCLING. */
+    if (*est <= estold) {
+	goto L120;
+    }
+
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	x[i__] = d_sign(&c_b11, &x[i__]);
+	isgn[i__] = i_dnnt(&x[i__]);
+/* L100: */
+    }
+    *kase = 2;
+    isave[1] = 4;
+    return 0;
+
+/*     ................ ENTRY   (ISAVE( 1 ) = 4)   
+       X HAS BEEN OVERWRITTEN BY TRANSPOSE(A)*X. */
+
+L110:
+    jlast = isave[2];
+    isave[2] = igraphidamax_(n, &x[1], &c__1);
+    if (x[jlast] != (d__1 = x[isave[2]], abs(d__1)) && isave[3] < 5) {
+	++isave[3];
+	goto L50;
+    }
+
+/*     ITERATION COMPLETE.  FINAL STAGE. */
+
+L120:
+    altsgn = 1.;
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	x[i__] = altsgn * ((doublereal) (i__ - 1) / (doublereal) (*n - 1) + 
+		1.);
+	altsgn = -altsgn;
+/* L130: */
+    }
+    *kase = 1;
+    isave[1] = 5;
+    return 0;
+
+/*     ................ ENTRY   (ISAVE( 1 ) = 5)   
+       X HAS BEEN OVERWRITTEN BY A*X. */
+
+L140:
+    temp = igraphdasum_(n, &x[1], &c__1) / (doublereal) (*n * 3) * 2.;
+    if (temp > *est) {
+	igraphdcopy_(n, &x[1], &c__1, &v[1], &c__1);
+	*est = temp;
+    }
+
+L150:
+    *kase = 0;
+    return 0;
+
+/*     End of DLACN2 */
+
+} /* igraphdlacn2_ */
+
diff --git a/src/lapack/dlacpy.c b/src/lapack/dlacpy.c
new file mode 100644
index 0000000..b442b17
--- /dev/null
+++ b/src/lapack/dlacpy.c
@@ -0,0 +1,115 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlacpy_(char *uplo, integer *m, integer *n, doublereal *
+	a, integer *lda, doublereal *b, integer *ldb)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j;
+    extern logical igraphlsame_(char *, char *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLACPY copies all or part of a two-dimensional matrix A to another   
+    matrix B.   
+
+    Arguments   
+    =========   
+
+    UPLO    (input) CHARACTER*1   
+            Specifies the part of the matrix A to be copied to B.   
+            = 'U':      Upper triangular part   
+            = 'L':      Lower triangular part   
+            Otherwise:  All of the matrix A   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The m by n matrix A.  If UPLO = 'U', only the upper triangle   
+            or trapezoid is accessed; if UPLO = 'L', only the lower   
+            triangle or trapezoid is accessed.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+    B       (output) DOUBLE PRECISION array, dimension (LDB,N)   
+            On exit, B = A in the locations specified by UPLO.   
+
+    LDB     (input) INTEGER   
+            The leading dimension of the array B.  LDB >= max(1,M).   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+
+    /* Function Body */
+    if (igraphlsame_(uplo, "U")) {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = min(j,*m);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		b[i__ + j * b_dim1] = a[i__ + j * a_dim1];
+/* L10: */
+	    }
+/* L20: */
+	}
+    } else if (igraphlsame_(uplo, "L")) {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = j; i__ <= i__2; ++i__) {
+		b[i__ + j * b_dim1] = a[i__ + j * a_dim1];
+/* L30: */
+	    }
+/* L40: */
+	}
+    } else {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		b[i__ + j * b_dim1] = a[i__ + j * a_dim1];
+/* L50: */
+	    }
+/* L60: */
+	}
+    }
+    return 0;
+
+/*     End of DLACPY */
+
+} /* igraphdlacpy_ */
+
diff --git a/src/lapack/dladiv.c b/src/lapack/dladiv.c
new file mode 100644
index 0000000..e7b6c76
--- /dev/null
+++ b/src/lapack/dladiv.c
@@ -0,0 +1,72 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdladiv_(doublereal *a, doublereal *b, doublereal *c__, 
+	doublereal *d__, doublereal *p, doublereal *q)
+{
+    doublereal e, f;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLADIV performs complex division in  real arithmetic   
+
+                          a + i*b   
+               p + i*q = ---------   
+                          c + i*d   
+
+    The algorithm is due to Robert L. Smith and can be found   
+    in D. Knuth, The art of Computer Programming, Vol.2, p.195   
+
+    Arguments   
+    =========   
+
+    A       (input) DOUBLE PRECISION   
+    B       (input) DOUBLE PRECISION   
+    C       (input) DOUBLE PRECISION   
+    D       (input) DOUBLE PRECISION   
+            The scalars a, b, c, and d in the above expression.   
+
+    P       (output) DOUBLE PRECISION   
+    Q       (output) DOUBLE PRECISION   
+            The scalars p and q in the above expression.   
+
+    ===================================================================== */
+
+
+    if (abs(*d__) < abs(*c__)) {
+	e = *d__ / *c__;
+	f = *c__ + *d__ * e;
+	*p = (*a + *b * e) / f;
+	*q = (*b - *a * e) / f;
+    } else {
+	e = *c__ / *d__;
+	f = *d__ + *c__ * e;
+	*p = (*b + *a * e) / f;
+	*q = (-(*a) + *b * e) / f;
+    }
+
+    return 0;
+
+/*     End of DLADIV */
+
+} /* igraphdladiv_ */
+
diff --git a/src/lapack/dlae2.c b/src/lapack/dlae2.c
new file mode 100644
index 0000000..a8d975d
--- /dev/null
+++ b/src/lapack/dlae2.c
@@ -0,0 +1,134 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlae2_(doublereal *a, doublereal *b, doublereal *c__, 
+	doublereal *rt1, doublereal *rt2)
+{
+    /* System generated locals */
+    doublereal d__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    doublereal ab, df, tb, sm, rt, adf, acmn, acmx;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLAE2  computes the eigenvalues of a 2-by-2 symmetric matrix   
+       [  A   B  ]   
+       [  B   C  ].   
+    On return, RT1 is the eigenvalue of larger absolute value, and RT2   
+    is the eigenvalue of smaller absolute value.   
+
+    Arguments   
+    =========   
+
+    A       (input) DOUBLE PRECISION   
+            The (1,1) element of the 2-by-2 matrix.   
+
+    B       (input) DOUBLE PRECISION   
+            The (1,2) and (2,1) elements of the 2-by-2 matrix.   
+
+    C       (input) DOUBLE PRECISION   
+            The (2,2) element of the 2-by-2 matrix.   
+
+    RT1     (output) DOUBLE PRECISION   
+            The eigenvalue of larger absolute value.   
+
+    RT2     (output) DOUBLE PRECISION   
+            The eigenvalue of smaller absolute value.   
+
+    Further Details   
+    ===============   
+
+    RT1 is accurate to a few ulps barring over/underflow.   
+
+    RT2 may be inaccurate if there is massive cancellation in the   
+    determinant A*C-B*B; higher precision or correctly rounded or   
+    correctly truncated arithmetic would be needed to compute RT2   
+    accurately in all cases.   
+
+    Overflow is possible only if RT1 is within a factor of 5 of overflow.   
+    Underflow is harmless if the input data is 0 or exceeds   
+       underflow_threshold / macheps.   
+
+   =====================================================================   
+
+
+       Compute the eigenvalues */
+
+    sm = *a + *c__;
+    df = *a - *c__;
+    adf = abs(df);
+    tb = *b + *b;
+    ab = abs(tb);
+    if (abs(*a) > abs(*c__)) {
+	acmx = *a;
+	acmn = *c__;
+    } else {
+	acmx = *c__;
+	acmn = *a;
+    }
+    if (adf > ab) {
+/* Computing 2nd power */
+	d__1 = ab / adf;
+	rt = adf * sqrt(d__1 * d__1 + 1.);
+    } else if (adf < ab) {
+/* Computing 2nd power */
+	d__1 = adf / ab;
+	rt = ab * sqrt(d__1 * d__1 + 1.);
+    } else {
+
+/*        Includes case AB=ADF=0 */
+
+	rt = ab * sqrt(2.);
+    }
+    if (sm < 0.) {
+	*rt1 = (sm - rt) * .5;
+
+/*        Order of execution important.   
+          To get fully accurate smaller eigenvalue,   
+          next line needs to be executed in higher precision. */
+
+	*rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b;
+    } else if (sm > 0.) {
+	*rt1 = (sm + rt) * .5;
+
+/*        Order of execution important.   
+          To get fully accurate smaller eigenvalue,   
+          next line needs to be executed in higher precision. */
+
+	*rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b;
+    } else {
+
+/*        Includes case RT1 = RT2 = 0 */
+
+	*rt1 = rt * .5;
+	*rt2 = rt * -.5;
+    }
+    return 0;
+
+/*     End of DLAE2 */
+
+} /* igraphdlae2_ */
+
diff --git a/src/lapack/dlaebz.c b/src/lapack/dlaebz.c
new file mode 100644
index 0000000..f63b1ce
--- /dev/null
+++ b/src/lapack/dlaebz.c
@@ -0,0 +1,612 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaebz_(integer *ijob, integer *nitmax, integer *n, 
+	integer *mmax, integer *minp, integer *nbmin, doublereal *abstol, 
+	doublereal *reltol, doublereal *pivmin, doublereal *d__, doublereal *
+	e, doublereal *e2, integer *nval, doublereal *ab, doublereal *c__, 
+	integer *mout, integer *nab, doublereal *work, integer *iwork, 
+	integer *info)
+{
+    /* System generated locals */
+    integer nab_dim1, nab_offset, ab_dim1, ab_offset, i__1, i__2, i__3, i__4, 
+	    i__5, i__6;
+    doublereal d__1, d__2, d__3, d__4;
+
+    /* Local variables */
+    integer j, kf, ji, kl, jp, jit;
+    doublereal tmp1, tmp2;
+    integer itmp1, itmp2, kfnew, klnew;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLAEBZ contains the iteration loops which compute and use the   
+    function N(w), which is the count of eigenvalues of a symmetric   
+    tridiagonal matrix T less than or equal to its argument  w.  It   
+    performs a choice of two types of loops:   
+
+    IJOB=1, followed by   
+    IJOB=2: It takes as input a list of intervals and returns a list of   
+            sufficiently small intervals whose union contains the same   
+            eigenvalues as the union of the original intervals.   
+            The input intervals are (AB(j,1),AB(j,2)], j=1,...,MINP.   
+            The output interval (AB(j,1),AB(j,2)] will contain   
+            eigenvalues NAB(j,1)+1,...,NAB(j,2), where 1 <= j <= MOUT.   
+
+    IJOB=3: It performs a binary search in each input interval   
+            (AB(j,1),AB(j,2)] for a point  w(j)  such that   
+            N(w(j))=NVAL(j), and uses  C(j)  as the starting point of   
+            the search.  If such a w(j) is found, then on output   
+            AB(j,1)=AB(j,2)=w.  If no such w(j) is found, then on output   
+            (AB(j,1),AB(j,2)] will be a small interval containing the   
+            point where N(w) jumps through NVAL(j), unless that point   
+            lies outside the initial interval.   
+
+    Note that the intervals are in all cases half-open intervals,   
+    i.e., of the form  (a,b] , which includes  b  but not  a .   
+
+    To avoid underflow, the matrix should be scaled so that its largest   
+    element is no greater than  overflow**(1/2) * underflow**(1/4)   
+    in absolute value.  To assure the most accurate computation   
+    of small eigenvalues, the matrix should be scaled to be   
+    not much smaller than that, either.   
+
+    See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal   
+    Matrix", Report CS41, Computer Science Dept., Stanford   
+    University, July 21, 1966   
+
+    Note: the arguments are, in general, *not* checked for unreasonable   
+    values.   
+
+    Arguments   
+    =========   
+
+    IJOB    (input) INTEGER   
+            Specifies what is to be done:   
+            = 1:  Compute NAB for the initial intervals.   
+            = 2:  Perform bisection iteration to find eigenvalues of T.   
+            = 3:  Perform bisection iteration to invert N(w), i.e.,   
+                  to find a point which has a specified number of   
+                  eigenvalues of T to its left.   
+            Other values will cause DLAEBZ to return with INFO=-1.   
+
+    NITMAX  (input) INTEGER   
+            The maximum number of "levels" of bisection to be   
+            performed, i.e., an interval of width W will not be made   
+            smaller than 2^(-NITMAX) * W.  If not all intervals   
+            have converged after NITMAX iterations, then INFO is set   
+            to the number of non-converged intervals.   
+
+    N       (input) INTEGER   
+            The dimension n of the tridiagonal matrix T.  It must be at   
+            least 1.   
+
+    MMAX    (input) INTEGER   
+            The maximum number of intervals.  If more than MMAX intervals   
+            are generated, then DLAEBZ will quit with INFO=MMAX+1.   
+
+    MINP    (input) INTEGER   
+            The initial number of intervals.  It may not be greater than   
+            MMAX.   
+
+    NBMIN   (input) INTEGER   
+            The smallest number of intervals that should be processed   
+            using a vector loop.  If zero, then only the scalar loop   
+            will be used.   
+
+    ABSTOL  (input) DOUBLE PRECISION   
+            The minimum (absolute) width of an interval.  When an   
+            interval is narrower than ABSTOL, or than RELTOL times the   
+            larger (in magnitude) endpoint, then it is considered to be   
+            sufficiently small, i.e., converged.  This must be at least   
+            zero.   
+
+    RELTOL  (input) DOUBLE PRECISION   
+            The minimum relative width of an interval.  When an interval   
+            is narrower than ABSTOL, or than RELTOL times the larger (in   
+            magnitude) endpoint, then it is considered to be   
+            sufficiently small, i.e., converged.  Note: this should   
+            always be at least radix*machine epsilon.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum absolute value of a "pivot" in the Sturm   
+            sequence loop.  This *must* be at least  max |e(j)**2| *   
+            safe_min  and at least safe_min, where safe_min is at least   
+            the smallest number that can divide one without overflow.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The diagonal elements of the tridiagonal matrix T.   
+
+    E       (input) DOUBLE PRECISION array, dimension (N)   
+            The offdiagonal elements of the tridiagonal matrix T in   
+            positions 1 through N-1.  E(N) is arbitrary.   
+
+    E2      (input) DOUBLE PRECISION array, dimension (N)   
+            The squares of the offdiagonal elements of the tridiagonal   
+            matrix T.  E2(N) is ignored.   
+
+    NVAL    (input/output) INTEGER array, dimension (MINP)   
+            If IJOB=1 or 2, not referenced.   
+            If IJOB=3, the desired values of N(w).  The elements of NVAL   
+            will be reordered to correspond with the intervals in AB.   
+            Thus, NVAL(j) on output will not, in general be the same as   
+            NVAL(j) on input, but it will correspond with the interval   
+            (AB(j,1),AB(j,2)] on output.   
+
+    AB      (input/output) DOUBLE PRECISION array, dimension (MMAX,2)   
+            The endpoints of the intervals.  AB(j,1) is  a(j), the left   
+            endpoint of the j-th interval, and AB(j,2) is b(j), the   
+            right endpoint of the j-th interval.  The input intervals   
+            will, in general, be modified, split, and reordered by the   
+            calculation.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (MMAX)   
+            If IJOB=1, ignored.   
+            If IJOB=2, workspace.   
+            If IJOB=3, then on input C(j) should be initialized to the   
+            first search point in the binary search.   
+
+    MOUT    (output) INTEGER   
+            If IJOB=1, the number of eigenvalues in the intervals.   
+            If IJOB=2 or 3, the number of intervals output.   
+            If IJOB=3, MOUT will equal MINP.   
+
+    NAB     (input/output) INTEGER array, dimension (MMAX,2)   
+            If IJOB=1, then on output NAB(i,j) will be set to N(AB(i,j)).   
+            If IJOB=2, then on input, NAB(i,j) should be set.  It must   
+               satisfy the condition:   
+               N(AB(i,1)) <= NAB(i,1) <= NAB(i,2) <= N(AB(i,2)),   
+               which means that in interval i only eigenvalues   
+               NAB(i,1)+1,...,NAB(i,2) will be considered.  Usually,   
+               NAB(i,j)=N(AB(i,j)), from a previous call to DLAEBZ with   
+               IJOB=1.   
+               On output, NAB(i,j) will contain   
+               max(na(k),min(nb(k),N(AB(i,j)))), where k is the index of   
+               the input interval that the output interval   
+               (AB(j,1),AB(j,2)] came from, and na(k) and nb(k) are the   
+               the input values of NAB(k,1) and NAB(k,2).   
+            If IJOB=3, then on output, NAB(i,j) contains N(AB(i,j)),   
+               unless N(w) > NVAL(i) for all search points  w , in which   
+               case NAB(i,1) will not be modified, i.e., the output   
+               value will be the same as the input value (modulo   
+               reorderings -- see NVAL and AB), or unless N(w) < NVAL(i)   
+               for all search points  w , in which case NAB(i,2) will   
+               not be modified.  Normally, NAB should be set to some   
+               distinctive value(s) before DLAEBZ is called.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (MMAX)   
+            Workspace.   
+
+    IWORK   (workspace) INTEGER array, dimension (MMAX)   
+            Workspace.   
+
+    INFO    (output) INTEGER   
+            = 0:       All intervals converged.   
+            = 1--MMAX: The last INFO intervals did not converge.   
+            = MMAX+1:  More than MMAX intervals were generated.   
+
+    Further Details   
+    ===============   
+
+        This routine is intended to be called only by other LAPACK   
+    routines, thus the interface is less user-friendly.  It is intended   
+    for two purposes:   
+
+    (a) finding eigenvalues.  In this case, DLAEBZ should have one or   
+        more initial intervals set up in AB, and DLAEBZ should be called   
+        with IJOB=1.  This sets up NAB, and also counts the eigenvalues.   
+        Intervals with no eigenvalues would usually be thrown out at   
+        this point.  Also, if not all the eigenvalues in an interval i   
+        are desired, NAB(i,1) can be increased or NAB(i,2) decreased.   
+        For example, set NAB(i,1)=NAB(i,2)-1 to get the largest   
+        eigenvalue.  DLAEBZ is then called with IJOB=2 and MMAX   
+        no smaller than the value of MOUT returned by the call with   
+        IJOB=1.  After this (IJOB=2) call, eigenvalues NAB(i,1)+1   
+        through NAB(i,2) are approximately AB(i,1) (or AB(i,2)) to the   
+        tolerance specified by ABSTOL and RELTOL.   
+
+    (b) finding an interval (a',b'] containing eigenvalues w(f),...,w(l).   
+        In this case, start with a Gershgorin interval  (a,b).  Set up   
+        AB to contain 2 search intervals, both initially (a,b).  One   
+        NVAL element should contain  f-1  and the other should contain  l   
+        , while C should contain a and b, resp.  NAB(i,1) should be -1   
+        and NAB(i,2) should be N+1, to flag an error if the desired   
+        interval does not lie in (a,b).  DLAEBZ is then called with   
+        IJOB=3.  On exit, if w(f-1) < w(f), then one of the intervals --   
+        j -- will have AB(j,1)=AB(j,2) and NAB(j,1)=NAB(j,2)=f-1, while   
+        if, to the specified tolerance, w(f-k)=...=w(f+r), k > 0 and r   
+        >= 0, then the interval will have  N(AB(j,1))=NAB(j,1)=f-k and   
+        N(AB(j,2))=NAB(j,2)=f+r.  The cases w(l) < w(l+1) and   
+        w(l-r)=...=w(l+k) are handled similarly.   
+
+    =====================================================================   
+
+
+       Check for Errors   
+
+       Parameter adjustments */
+    nab_dim1 = *mmax;
+    nab_offset = 1 + nab_dim1;
+    nab -= nab_offset;
+    ab_dim1 = *mmax;
+    ab_offset = 1 + ab_dim1;
+    ab -= ab_offset;
+    --d__;
+    --e;
+    --e2;
+    --nval;
+    --c__;
+    --work;
+    --iwork;
+
+    /* Function Body */
+    *info = 0;
+    if (*ijob < 1 || *ijob > 3) {
+	*info = -1;
+	return 0;
+    }
+
+/*     Initialize NAB */
+
+    if (*ijob == 1) {
+
+/*        Compute the number of eigenvalues in the initial intervals. */
+
+	*mout = 0;
+	i__1 = *minp;
+	for (ji = 1; ji <= i__1; ++ji) {
+	    for (jp = 1; jp <= 2; ++jp) {
+		tmp1 = d__[1] - ab[ji + jp * ab_dim1];
+		if (abs(tmp1) < *pivmin) {
+		    tmp1 = -(*pivmin);
+		}
+		nab[ji + jp * nab_dim1] = 0;
+		if (tmp1 <= 0.) {
+		    nab[ji + jp * nab_dim1] = 1;
+		}
+
+		i__2 = *n;
+		for (j = 2; j <= i__2; ++j) {
+		    tmp1 = d__[j] - e2[j - 1] / tmp1 - ab[ji + jp * ab_dim1];
+		    if (abs(tmp1) < *pivmin) {
+			tmp1 = -(*pivmin);
+		    }
+		    if (tmp1 <= 0.) {
+			++nab[ji + jp * nab_dim1];
+		    }
+/* L10: */
+		}
+/* L20: */
+	    }
+	    *mout = *mout + nab[ji + (nab_dim1 << 1)] - nab[ji + nab_dim1];
+/* L30: */
+	}
+	return 0;
+    }
+
+/*     Initialize for loop   
+
+       KF and KL have the following meaning:   
+          Intervals 1,...,KF-1 have converged.   
+          Intervals KF,...,KL  still need to be refined. */
+
+    kf = 1;
+    kl = *minp;
+
+/*     If IJOB=2, initialize C.   
+       If IJOB=3, use the user-supplied starting point. */
+
+    if (*ijob == 2) {
+	i__1 = *minp;
+	for (ji = 1; ji <= i__1; ++ji) {
+	    c__[ji] = (ab[ji + ab_dim1] + ab[ji + (ab_dim1 << 1)]) * .5;
+/* L40: */
+	}
+    }
+
+/*     Iteration loop */
+
+    i__1 = *nitmax;
+    for (jit = 1; jit <= i__1; ++jit) {
+
+/*        Loop over intervals */
+
+	if (kl - kf + 1 >= *nbmin && *nbmin > 0) {
+
+/*           Begin of Parallel Version of the loop */
+
+	    i__2 = kl;
+	    for (ji = kf; ji <= i__2; ++ji) {
+
+/*              Compute N(c), the number of eigenvalues less than c */
+
+		work[ji] = d__[1] - c__[ji];
+		iwork[ji] = 0;
+		if (work[ji] <= *pivmin) {
+		    iwork[ji] = 1;
+/* Computing MIN */
+		    d__1 = work[ji], d__2 = -(*pivmin);
+		    work[ji] = min(d__1,d__2);
+		}
+
+		i__3 = *n;
+		for (j = 2; j <= i__3; ++j) {
+		    work[ji] = d__[j] - e2[j - 1] / work[ji] - c__[ji];
+		    if (work[ji] <= *pivmin) {
+			++iwork[ji];
+/* Computing MIN */
+			d__1 = work[ji], d__2 = -(*pivmin);
+			work[ji] = min(d__1,d__2);
+		    }
+/* L50: */
+		}
+/* L60: */
+	    }
+
+	    if (*ijob <= 2) {
+
+/*              IJOB=2: Choose all intervals containing eigenvalues. */
+
+		klnew = kl;
+		i__2 = kl;
+		for (ji = kf; ji <= i__2; ++ji) {
+
+/*                 Insure that N(w) is monotone   
+
+   Computing MIN   
+   Computing MAX */
+		    i__5 = nab[ji + nab_dim1], i__6 = iwork[ji];
+		    i__3 = nab[ji + (nab_dim1 << 1)], i__4 = max(i__5,i__6);
+		    iwork[ji] = min(i__3,i__4);
+
+/*                 Update the Queue -- add intervals if both halves   
+                   contain eigenvalues. */
+
+		    if (iwork[ji] == nab[ji + (nab_dim1 << 1)]) {
+
+/*                    No eigenvalue in the upper interval:   
+                      just use the lower interval. */
+
+			ab[ji + (ab_dim1 << 1)] = c__[ji];
+
+		    } else if (iwork[ji] == nab[ji + nab_dim1]) {
+
+/*                    No eigenvalue in the lower interval:   
+                      just use the upper interval. */
+
+			ab[ji + ab_dim1] = c__[ji];
+		    } else {
+			++klnew;
+			if (klnew <= *mmax) {
+
+/*                       Eigenvalue in both intervals -- add upper to   
+                         queue. */
+
+			    ab[klnew + (ab_dim1 << 1)] = ab[ji + (ab_dim1 << 
+				    1)];
+			    nab[klnew + (nab_dim1 << 1)] = nab[ji + (nab_dim1 
+				    << 1)];
+			    ab[klnew + ab_dim1] = c__[ji];
+			    nab[klnew + nab_dim1] = iwork[ji];
+			    ab[ji + (ab_dim1 << 1)] = c__[ji];
+			    nab[ji + (nab_dim1 << 1)] = iwork[ji];
+			} else {
+			    *info = *mmax + 1;
+			}
+		    }
+/* L70: */
+		}
+		if (*info != 0) {
+		    return 0;
+		}
+		kl = klnew;
+	    } else {
+
+/*              IJOB=3: Binary search.  Keep only the interval containing   
+                        w   s.t. N(w) = NVAL */
+
+		i__2 = kl;
+		for (ji = kf; ji <= i__2; ++ji) {
+		    if (iwork[ji] <= nval[ji]) {
+			ab[ji + ab_dim1] = c__[ji];
+			nab[ji + nab_dim1] = iwork[ji];
+		    }
+		    if (iwork[ji] >= nval[ji]) {
+			ab[ji + (ab_dim1 << 1)] = c__[ji];
+			nab[ji + (nab_dim1 << 1)] = iwork[ji];
+		    }
+/* L80: */
+		}
+	    }
+
+	} else {
+
+/*           End of Parallel Version of the loop   
+
+             Begin of Serial Version of the loop */
+
+	    klnew = kl;
+	    i__2 = kl;
+	    for (ji = kf; ji <= i__2; ++ji) {
+
+/*              Compute N(w), the number of eigenvalues less than w */
+
+		tmp1 = c__[ji];
+		tmp2 = d__[1] - tmp1;
+		itmp1 = 0;
+		if (tmp2 <= *pivmin) {
+		    itmp1 = 1;
+/* Computing MIN */
+		    d__1 = tmp2, d__2 = -(*pivmin);
+		    tmp2 = min(d__1,d__2);
+		}
+
+		i__3 = *n;
+		for (j = 2; j <= i__3; ++j) {
+		    tmp2 = d__[j] - e2[j - 1] / tmp2 - tmp1;
+		    if (tmp2 <= *pivmin) {
+			++itmp1;
+/* Computing MIN */
+			d__1 = tmp2, d__2 = -(*pivmin);
+			tmp2 = min(d__1,d__2);
+		    }
+/* L90: */
+		}
+
+		if (*ijob <= 2) {
+
+/*                 IJOB=2: Choose all intervals containing eigenvalues.   
+
+                   Insure that N(w) is monotone   
+
+   Computing MIN   
+   Computing MAX */
+		    i__5 = nab[ji + nab_dim1];
+		    i__3 = nab[ji + (nab_dim1 << 1)], i__4 = max(i__5,itmp1);
+		    itmp1 = min(i__3,i__4);
+
+/*                 Update the Queue -- add intervals if both halves   
+                   contain eigenvalues. */
+
+		    if (itmp1 == nab[ji + (nab_dim1 << 1)]) {
+
+/*                    No eigenvalue in the upper interval:   
+                      just use the lower interval. */
+
+			ab[ji + (ab_dim1 << 1)] = tmp1;
+
+		    } else if (itmp1 == nab[ji + nab_dim1]) {
+
+/*                    No eigenvalue in the lower interval:   
+                      just use the upper interval. */
+
+			ab[ji + ab_dim1] = tmp1;
+		    } else if (klnew < *mmax) {
+
+/*                    Eigenvalue in both intervals -- add upper to queue. */
+
+			++klnew;
+			ab[klnew + (ab_dim1 << 1)] = ab[ji + (ab_dim1 << 1)];
+			nab[klnew + (nab_dim1 << 1)] = nab[ji + (nab_dim1 << 
+				1)];
+			ab[klnew + ab_dim1] = tmp1;
+			nab[klnew + nab_dim1] = itmp1;
+			ab[ji + (ab_dim1 << 1)] = tmp1;
+			nab[ji + (nab_dim1 << 1)] = itmp1;
+		    } else {
+			*info = *mmax + 1;
+			return 0;
+		    }
+		} else {
+
+/*                 IJOB=3: Binary search.  Keep only the interval   
+                           containing  w  s.t. N(w) = NVAL */
+
+		    if (itmp1 <= nval[ji]) {
+			ab[ji + ab_dim1] = tmp1;
+			nab[ji + nab_dim1] = itmp1;
+		    }
+		    if (itmp1 >= nval[ji]) {
+			ab[ji + (ab_dim1 << 1)] = tmp1;
+			nab[ji + (nab_dim1 << 1)] = itmp1;
+		    }
+		}
+/* L100: */
+	    }
+	    kl = klnew;
+
+	}
+
+/*        Check for convergence */
+
+	kfnew = kf;
+	i__2 = kl;
+	for (ji = kf; ji <= i__2; ++ji) {
+	    tmp1 = (d__1 = ab[ji + (ab_dim1 << 1)] - ab[ji + ab_dim1], abs(
+		    d__1));
+/* Computing MAX */
+	    d__3 = (d__1 = ab[ji + (ab_dim1 << 1)], abs(d__1)), d__4 = (d__2 =
+		     ab[ji + ab_dim1], abs(d__2));
+	    tmp2 = max(d__3,d__4);
+/* Computing MAX */
+	    d__1 = max(*abstol,*pivmin), d__2 = *reltol * tmp2;
+	    if (tmp1 < max(d__1,d__2) || nab[ji + nab_dim1] >= nab[ji + (
+		    nab_dim1 << 1)]) {
+
+/*              Converged -- Swap with position KFNEW,   
+                             then increment KFNEW */
+
+		if (ji > kfnew) {
+		    tmp1 = ab[ji + ab_dim1];
+		    tmp2 = ab[ji + (ab_dim1 << 1)];
+		    itmp1 = nab[ji + nab_dim1];
+		    itmp2 = nab[ji + (nab_dim1 << 1)];
+		    ab[ji + ab_dim1] = ab[kfnew + ab_dim1];
+		    ab[ji + (ab_dim1 << 1)] = ab[kfnew + (ab_dim1 << 1)];
+		    nab[ji + nab_dim1] = nab[kfnew + nab_dim1];
+		    nab[ji + (nab_dim1 << 1)] = nab[kfnew + (nab_dim1 << 1)];
+		    ab[kfnew + ab_dim1] = tmp1;
+		    ab[kfnew + (ab_dim1 << 1)] = tmp2;
+		    nab[kfnew + nab_dim1] = itmp1;
+		    nab[kfnew + (nab_dim1 << 1)] = itmp2;
+		    if (*ijob == 3) {
+			itmp1 = nval[ji];
+			nval[ji] = nval[kfnew];
+			nval[kfnew] = itmp1;
+		    }
+		}
+		++kfnew;
+	    }
+/* L110: */
+	}
+	kf = kfnew;
+
+/*        Choose Midpoints */
+
+	i__2 = kl;
+	for (ji = kf; ji <= i__2; ++ji) {
+	    c__[ji] = (ab[ji + ab_dim1] + ab[ji + (ab_dim1 << 1)]) * .5;
+/* L120: */
+	}
+
+/*        If no more intervals to refine, quit. */
+
+	if (kf > kl) {
+	    goto L140;
+	}
+/* L130: */
+    }
+
+/*     Converged */
+
+L140:
+/* Computing MAX */
+    i__1 = kl + 1 - kf;
+    *info = max(i__1,0);
+    *mout = kl;
+
+    return 0;
+
+/*     End of DLAEBZ */
+
+} /* igraphdlaebz_ */
+
diff --git a/src/lapack/dlaev2.c b/src/lapack/dlaev2.c
new file mode 100644
index 0000000..6d9c217
--- /dev/null
+++ b/src/lapack/dlaev2.c
@@ -0,0 +1,180 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaev2_(doublereal *a, doublereal *b, doublereal *c__, 
+	doublereal *rt1, doublereal *rt2, doublereal *cs1, doublereal *sn1)
+{
+    /* System generated locals */
+    doublereal d__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    doublereal ab, df, cs, ct, tb, sm, tn, rt, adf, acs;
+    integer sgn1, sgn2;
+    doublereal acmn, acmx;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix   
+       [  A   B  ]   
+       [  B   C  ].   
+    On return, RT1 is the eigenvalue of larger absolute value, RT2 is the   
+    eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right   
+    eigenvector for RT1, giving the decomposition   
+
+       [ CS1  SN1 ] [  A   B  ] [ CS1 -SN1 ]  =  [ RT1  0  ]   
+       [-SN1  CS1 ] [  B   C  ] [ SN1  CS1 ]     [  0  RT2 ].   
+
+    Arguments   
+    =========   
+
+    A       (input) DOUBLE PRECISION   
+            The (1,1) element of the 2-by-2 matrix.   
+
+    B       (input) DOUBLE PRECISION   
+            The (1,2) element and the conjugate of the (2,1) element of   
+            the 2-by-2 matrix.   
+
+    C       (input) DOUBLE PRECISION   
+            The (2,2) element of the 2-by-2 matrix.   
+
+    RT1     (output) DOUBLE PRECISION   
+            The eigenvalue of larger absolute value.   
+
+    RT2     (output) DOUBLE PRECISION   
+            The eigenvalue of smaller absolute value.   
+
+    CS1     (output) DOUBLE PRECISION   
+    SN1     (output) DOUBLE PRECISION   
+            The vector (CS1, SN1) is a unit right eigenvector for RT1.   
+
+    Further Details   
+    ===============   
+
+    RT1 is accurate to a few ulps barring over/underflow.   
+
+    RT2 may be inaccurate if there is massive cancellation in the   
+    determinant A*C-B*B; higher precision or correctly rounded or   
+    correctly truncated arithmetic would be needed to compute RT2   
+    accurately in all cases.   
+
+    CS1 and SN1 are accurate to a few ulps barring over/underflow.   
+
+    Overflow is possible only if RT1 is within a factor of 5 of overflow.   
+    Underflow is harmless if the input data is 0 or exceeds   
+       underflow_threshold / macheps.   
+
+   =====================================================================   
+
+
+       Compute the eigenvalues */
+
+    sm = *a + *c__;
+    df = *a - *c__;
+    adf = abs(df);
+    tb = *b + *b;
+    ab = abs(tb);
+    if (abs(*a) > abs(*c__)) {
+	acmx = *a;
+	acmn = *c__;
+    } else {
+	acmx = *c__;
+	acmn = *a;
+    }
+    if (adf > ab) {
+/* Computing 2nd power */
+	d__1 = ab / adf;
+	rt = adf * sqrt(d__1 * d__1 + 1.);
+    } else if (adf < ab) {
+/* Computing 2nd power */
+	d__1 = adf / ab;
+	rt = ab * sqrt(d__1 * d__1 + 1.);
+    } else {
+
+/*        Includes case AB=ADF=0 */
+
+	rt = ab * sqrt(2.);
+    }
+    if (sm < 0.) {
+	*rt1 = (sm - rt) * .5;
+	sgn1 = -1;
+
+/*        Order of execution important.   
+          To get fully accurate smaller eigenvalue,   
+          next line needs to be executed in higher precision. */
+
+	*rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b;
+    } else if (sm > 0.) {
+	*rt1 = (sm + rt) * .5;
+	sgn1 = 1;
+
+/*        Order of execution important.   
+          To get fully accurate smaller eigenvalue,   
+          next line needs to be executed in higher precision. */
+
+	*rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b;
+    } else {
+
+/*        Includes case RT1 = RT2 = 0 */
+
+	*rt1 = rt * .5;
+	*rt2 = rt * -.5;
+	sgn1 = 1;
+    }
+
+/*     Compute the eigenvector */
+
+    if (df >= 0.) {
+	cs = df + rt;
+	sgn2 = 1;
+    } else {
+	cs = df - rt;
+	sgn2 = -1;
+    }
+    acs = abs(cs);
+    if (acs > ab) {
+	ct = -tb / cs;
+	*sn1 = 1. / sqrt(ct * ct + 1.);
+	*cs1 = ct * *sn1;
+    } else {
+	if (ab == 0.) {
+	    *cs1 = 1.;
+	    *sn1 = 0.;
+	} else {
+	    tn = -cs / tb;
+	    *cs1 = 1. / sqrt(tn * tn + 1.);
+	    *sn1 = tn * *cs1;
+	}
+    }
+    if (sgn1 == sgn2) {
+	tn = *cs1;
+	*cs1 = -(*sn1);
+	*sn1 = tn;
+    }
+    return 0;
+
+/*     End of DLAEV2 */
+
+} /* igraphdlaev2_ */
+
diff --git a/src/lapack/dlaexc.c b/src/lapack/dlaexc.c
new file mode 100644
index 0000000..d0e962a
--- /dev/null
+++ b/src/lapack/dlaexc.c
@@ -0,0 +1,443 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__4 = 4;
+static logical c_false = FALSE_;
+static integer c_n1 = -1;
+static integer c__2 = 2;
+static integer c__3 = 3;
+
+/* Subroutine */ int igraphdlaexc_(logical *wantq, integer *n, doublereal *t, 
+	integer *ldt, doublereal *q, integer *ldq, integer *j1, integer *n1, 
+	integer *n2, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer q_dim1, q_offset, t_dim1, t_offset, i__1;
+    doublereal d__1, d__2, d__3;
+
+    /* Local variables */
+    doublereal d__[16]	/* was [4][4] */;
+    integer k;
+    doublereal u[3], x[4]	/* was [2][2] */;
+    integer j2, j3, j4;
+    doublereal u1[3], u2[3];
+    integer nd;
+    doublereal cs, t11, t22, t33, sn, wi1, wi2, wr1, wr2, eps, tau, tau1, 
+	    tau2;
+    integer ierr;
+    doublereal temp;
+    extern /* Subroutine */ int igraphdrot_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *);
+    doublereal scale, dnorm, xnorm;
+    extern /* Subroutine */ int igraphdlanv2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *), igraphdlasy2_(
+	    logical *, logical *, integer *, integer *, integer *, doublereal 
+	    *, integer *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *);
+    extern doublereal igraphdlamch_(char *), igraphdlange_(char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *);
+    extern /* Subroutine */ int igraphdlarfg_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *), igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlartg_(doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *), igraphdlarfx_(char *, integer *, integer *, doublereal *,
+	     doublereal *, doublereal *, integer *, doublereal *);
+    doublereal thresh, smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    DLAEXC swaps adjacent diagonal blocks T11 and T22 of order 1 or 2 in   
+    an upper quasi-triangular matrix T by an orthogonal similarity   
+    transformation.   
+
+    T must be in Schur canonical form, that is, block upper triangular   
+    with 1-by-1 and 2-by-2 diagonal blocks; each 2-by-2 diagonal block   
+    has its diagonal elemnts equal and its off-diagonal elements of   
+    opposite sign.   
+
+    Arguments   
+    =========   
+
+    WANTQ   (input) LOGICAL   
+            = .TRUE. : accumulate the transformation in the matrix Q;   
+            = .FALSE.: do not accumulate the transformation.   
+
+    N       (input) INTEGER   
+            The order of the matrix T. N >= 0.   
+
+    T       (input/output) DOUBLE PRECISION array, dimension (LDT,N)   
+            On entry, the upper quasi-triangular matrix T, in Schur   
+            canonical form.   
+            On exit, the updated matrix T, again in Schur canonical form.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= max(1,N).   
+
+    Q       (input/output) DOUBLE PRECISION array, dimension (LDQ,N)   
+            On entry, if WANTQ is .TRUE., the orthogonal matrix Q.   
+            On exit, if WANTQ is .TRUE., the updated matrix Q.   
+            If WANTQ is .FALSE., Q is not referenced.   
+
+    LDQ     (input) INTEGER   
+            The leading dimension of the array Q.   
+            LDQ >= 1; and if WANTQ is .TRUE., LDQ >= N.   
+
+    J1      (input) INTEGER   
+            The index of the first row of the first block T11.   
+
+    N1      (input) INTEGER   
+            The order of the first block T11. N1 = 0, 1 or 2.   
+
+    N2      (input) INTEGER   
+            The order of the second block T22. N2 = 0, 1 or 2.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (N)   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            = 1: the transformed matrix T would be too far from Schur   
+                 form; the blocks are not swapped and T and Q are   
+                 unchanged.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+
+/*     Quick return if possible */
+
+    if (*n == 0 || *n1 == 0 || *n2 == 0) {
+	return 0;
+    }
+    if (*j1 + *n1 > *n) {
+	return 0;
+    }
+
+    j2 = *j1 + 1;
+    j3 = *j1 + 2;
+    j4 = *j1 + 3;
+
+    if (*n1 == 1 && *n2 == 1) {
+
+/*        Swap two 1-by-1 blocks. */
+
+	t11 = t[*j1 + *j1 * t_dim1];
+	t22 = t[j2 + j2 * t_dim1];
+
+/*        Determine the transformation to perform the interchange. */
+
+	d__1 = t22 - t11;
+	igraphdlartg_(&t[*j1 + j2 * t_dim1], &d__1, &cs, &sn, &temp);
+
+/*        Apply transformation to the matrix T. */
+
+	if (j3 <= *n) {
+	    i__1 = *n - *j1 - 1;
+	    igraphdrot_(&i__1, &t[*j1 + j3 * t_dim1], ldt, &t[j2 + j3 * t_dim1], 
+		    ldt, &cs, &sn);
+	}
+	i__1 = *j1 - 1;
+	igraphdrot_(&i__1, &t[*j1 * t_dim1 + 1], &c__1, &t[j2 * t_dim1 + 1], &c__1, 
+		&cs, &sn);
+
+	t[*j1 + *j1 * t_dim1] = t22;
+	t[j2 + j2 * t_dim1] = t11;
+
+	if (*wantq) {
+
+/*           Accumulate transformation in the matrix Q. */
+
+	    igraphdrot_(n, &q[*j1 * q_dim1 + 1], &c__1, &q[j2 * q_dim1 + 1], &c__1, 
+		    &cs, &sn);
+	}
+
+    } else {
+
+/*        Swapping involves at least one 2-by-2 block.   
+
+          Copy the diagonal block of order N1+N2 to the local array D   
+          and compute its norm. */
+
+	nd = *n1 + *n2;
+	igraphdlacpy_("Full", &nd, &nd, &t[*j1 + *j1 * t_dim1], ldt, d__, &c__4);
+	dnorm = igraphdlange_("Max", &nd, &nd, d__, &c__4, &work[1]);
+
+/*        Compute machine-dependent threshold for test for accepting   
+          swap. */
+
+	eps = igraphdlamch_("P");
+	smlnum = igraphdlamch_("S") / eps;
+/* Computing MAX */
+	d__1 = eps * 10. * dnorm;
+	thresh = max(d__1,smlnum);
+
+/*        Solve T11*X - X*T22 = scale*T12 for X. */
+
+	igraphdlasy2_(&c_false, &c_false, &c_n1, n1, n2, d__, &c__4, &d__[*n1 + 1 + 
+		(*n1 + 1 << 2) - 5], &c__4, &d__[(*n1 + 1 << 2) - 4], &c__4, &
+		scale, x, &c__2, &xnorm, &ierr);
+
+/*        Swap the adjacent diagonal blocks. */
+
+	k = *n1 + *n1 + *n2 - 3;
+	switch (k) {
+	    case 1:  goto L10;
+	    case 2:  goto L20;
+	    case 3:  goto L30;
+	}
+
+L10:
+
+/*        N1 = 1, N2 = 2: generate elementary reflector H so that:   
+
+          ( scale, X11, X12 ) H = ( 0, 0, * ) */
+
+	u[0] = scale;
+	u[1] = x[0];
+	u[2] = x[2];
+	igraphdlarfg_(&c__3, &u[2], u, &c__1, &tau);
+	u[2] = 1.;
+	t11 = t[*j1 + *j1 * t_dim1];
+
+/*        Perform swap provisionally on diagonal block in D. */
+
+	igraphdlarfx_("L", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]);
+	igraphdlarfx_("R", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]);
+
+/*        Test whether to reject swap.   
+
+   Computing MAX */
+	d__2 = abs(d__[2]), d__3 = abs(d__[6]), d__2 = max(d__2,d__3), d__3 = 
+		(d__1 = d__[10] - t11, abs(d__1));
+	if (max(d__2,d__3) > thresh) {
+	    goto L50;
+	}
+
+/*        Accept swap: apply transformation to the entire matrix T. */
+
+	i__1 = *n - *j1 + 1;
+	igraphdlarfx_("L", &c__3, &i__1, u, &tau, &t[*j1 + *j1 * t_dim1], ldt, &
+		work[1]);
+	igraphdlarfx_("R", &j2, &c__3, u, &tau, &t[*j1 * t_dim1 + 1], ldt, &work[1]);
+
+	t[j3 + *j1 * t_dim1] = 0.;
+	t[j3 + j2 * t_dim1] = 0.;
+	t[j3 + j3 * t_dim1] = t11;
+
+	if (*wantq) {
+
+/*           Accumulate transformation in the matrix Q. */
+
+	    igraphdlarfx_("R", n, &c__3, u, &tau, &q[*j1 * q_dim1 + 1], ldq, &work[
+		    1]);
+	}
+	goto L40;
+
+L20:
+
+/*        N1 = 2, N2 = 1: generate elementary reflector H so that:   
+
+          H (  -X11 ) = ( * )   
+            (  -X21 ) = ( 0 )   
+            ( scale ) = ( 0 ) */
+
+	u[0] = -x[0];
+	u[1] = -x[1];
+	u[2] = scale;
+	igraphdlarfg_(&c__3, u, &u[1], &c__1, &tau);
+	u[0] = 1.;
+	t33 = t[j3 + j3 * t_dim1];
+
+/*        Perform swap provisionally on diagonal block in D. */
+
+	igraphdlarfx_("L", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]);
+	igraphdlarfx_("R", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]);
+
+/*        Test whether to reject swap.   
+
+   Computing MAX */
+	d__2 = abs(d__[1]), d__3 = abs(d__[2]), d__2 = max(d__2,d__3), d__3 = 
+		(d__1 = d__[0] - t33, abs(d__1));
+	if (max(d__2,d__3) > thresh) {
+	    goto L50;
+	}
+
+/*        Accept swap: apply transformation to the entire matrix T. */
+
+	igraphdlarfx_("R", &j3, &c__3, u, &tau, &t[*j1 * t_dim1 + 1], ldt, &work[1]);
+	i__1 = *n - *j1;
+	igraphdlarfx_("L", &c__3, &i__1, u, &tau, &t[*j1 + j2 * t_dim1], ldt, &work[
+		1]);
+
+	t[*j1 + *j1 * t_dim1] = t33;
+	t[j2 + *j1 * t_dim1] = 0.;
+	t[j3 + *j1 * t_dim1] = 0.;
+
+	if (*wantq) {
+
+/*           Accumulate transformation in the matrix Q. */
+
+	    igraphdlarfx_("R", n, &c__3, u, &tau, &q[*j1 * q_dim1 + 1], ldq, &work[
+		    1]);
+	}
+	goto L40;
+
+L30:
+
+/*        N1 = 2, N2 = 2: generate elementary reflectors H(1) and H(2) so   
+          that:   
+
+          H(2) H(1) (  -X11  -X12 ) = (  *  * )   
+                    (  -X21  -X22 )   (  0  * )   
+                    ( scale    0  )   (  0  0 )   
+                    (    0  scale )   (  0  0 ) */
+
+	u1[0] = -x[0];
+	u1[1] = -x[1];
+	u1[2] = scale;
+	igraphdlarfg_(&c__3, u1, &u1[1], &c__1, &tau1);
+	u1[0] = 1.;
+
+	temp = -tau1 * (x[2] + u1[1] * x[3]);
+	u2[0] = -temp * u1[1] - x[3];
+	u2[1] = -temp * u1[2];
+	u2[2] = scale;
+	igraphdlarfg_(&c__3, u2, &u2[1], &c__1, &tau2);
+	u2[0] = 1.;
+
+/*        Perform swap provisionally on diagonal block in D. */
+
+	igraphdlarfx_("L", &c__3, &c__4, u1, &tau1, d__, &c__4, &work[1])
+		;
+	igraphdlarfx_("R", &c__4, &c__3, u1, &tau1, d__, &c__4, &work[1])
+		;
+	igraphdlarfx_("L", &c__3, &c__4, u2, &tau2, &d__[1], &c__4, &work[1]);
+	igraphdlarfx_("R", &c__4, &c__3, u2, &tau2, &d__[4], &c__4, &work[1]);
+
+/*        Test whether to reject swap.   
+
+   Computing MAX */
+	d__1 = abs(d__[2]), d__2 = abs(d__[6]), d__1 = max(d__1,d__2), d__2 = 
+		abs(d__[3]), d__1 = max(d__1,d__2), d__2 = abs(d__[7]);
+	if (max(d__1,d__2) > thresh) {
+	    goto L50;
+	}
+
+/*        Accept swap: apply transformation to the entire matrix T. */
+
+	i__1 = *n - *j1 + 1;
+	igraphdlarfx_("L", &c__3, &i__1, u1, &tau1, &t[*j1 + *j1 * t_dim1], ldt, &
+		work[1]);
+	igraphdlarfx_("R", &j4, &c__3, u1, &tau1, &t[*j1 * t_dim1 + 1], ldt, &work[
+		1]);
+	i__1 = *n - *j1 + 1;
+	igraphdlarfx_("L", &c__3, &i__1, u2, &tau2, &t[j2 + *j1 * t_dim1], ldt, &
+		work[1]);
+	igraphdlarfx_("R", &j4, &c__3, u2, &tau2, &t[j2 * t_dim1 + 1], ldt, &work[1]
+		);
+
+	t[j3 + *j1 * t_dim1] = 0.;
+	t[j3 + j2 * t_dim1] = 0.;
+	t[j4 + *j1 * t_dim1] = 0.;
+	t[j4 + j2 * t_dim1] = 0.;
+
+	if (*wantq) {
+
+/*           Accumulate transformation in the matrix Q. */
+
+	    igraphdlarfx_("R", n, &c__3, u1, &tau1, &q[*j1 * q_dim1 + 1], ldq, &
+		    work[1]);
+	    igraphdlarfx_("R", n, &c__3, u2, &tau2, &q[j2 * q_dim1 + 1], ldq, &work[
+		    1]);
+	}
+
+L40:
+
+	if (*n2 == 2) {
+
+/*           Standardize new 2-by-2 block T11 */
+
+	    igraphdlanv2_(&t[*j1 + *j1 * t_dim1], &t[*j1 + j2 * t_dim1], &t[j2 + *
+		    j1 * t_dim1], &t[j2 + j2 * t_dim1], &wr1, &wi1, &wr2, &
+		    wi2, &cs, &sn);
+	    i__1 = *n - *j1 - 1;
+	    igraphdrot_(&i__1, &t[*j1 + (*j1 + 2) * t_dim1], ldt, &t[j2 + (*j1 + 2) 
+		    * t_dim1], ldt, &cs, &sn);
+	    i__1 = *j1 - 1;
+	    igraphdrot_(&i__1, &t[*j1 * t_dim1 + 1], &c__1, &t[j2 * t_dim1 + 1], &
+		    c__1, &cs, &sn);
+	    if (*wantq) {
+		igraphdrot_(n, &q[*j1 * q_dim1 + 1], &c__1, &q[j2 * q_dim1 + 1], &
+			c__1, &cs, &sn);
+	    }
+	}
+
+	if (*n1 == 2) {
+
+/*           Standardize new 2-by-2 block T22 */
+
+	    j3 = *j1 + *n2;
+	    j4 = j3 + 1;
+	    igraphdlanv2_(&t[j3 + j3 * t_dim1], &t[j3 + j4 * t_dim1], &t[j4 + j3 * 
+		    t_dim1], &t[j4 + j4 * t_dim1], &wr1, &wi1, &wr2, &wi2, &
+		    cs, &sn);
+	    if (j3 + 2 <= *n) {
+		i__1 = *n - j3 - 1;
+		igraphdrot_(&i__1, &t[j3 + (j3 + 2) * t_dim1], ldt, &t[j4 + (j3 + 2)
+			 * t_dim1], ldt, &cs, &sn);
+	    }
+	    i__1 = j3 - 1;
+	    igraphdrot_(&i__1, &t[j3 * t_dim1 + 1], &c__1, &t[j4 * t_dim1 + 1], &
+		    c__1, &cs, &sn);
+	    if (*wantq) {
+		igraphdrot_(n, &q[j3 * q_dim1 + 1], &c__1, &q[j4 * q_dim1 + 1], &
+			c__1, &cs, &sn);
+	    }
+	}
+
+    }
+    return 0;
+
+/*     Exit with INFO = 1 if swap was rejected. */
+
+L50:
+    *info = 1;
+    return 0;
+
+/*     End of DLAEXC */
+
+} /* igraphdlaexc_ */
+
diff --git a/src/lapack/dlagtf.c b/src/lapack/dlagtf.c
new file mode 100644
index 0000000..38eb65c
--- /dev/null
+++ b/src/lapack/dlagtf.c
@@ -0,0 +1,210 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlagtf_(integer *n, doublereal *a, doublereal *lambda, 
+	doublereal *b, doublereal *c__, doublereal *tol, doublereal *d__, 
+	integer *in, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    integer k;
+    doublereal tl, eps, piv1, piv2, temp, mult, scale1, scale2;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLAGTF factorizes the matrix (T - lambda*I), where T is an n by n   
+    tridiagonal matrix and lambda is a scalar, as   
+
+       T - lambda*I = PLU,   
+
+    where P is a permutation matrix, L is a unit lower tridiagonal matrix   
+    with at most one non-zero sub-diagonal elements per column and U is   
+    an upper triangular matrix with at most two non-zero super-diagonal   
+    elements per column.   
+
+    The factorization is obtained by Gaussian elimination with partial   
+    pivoting and implicit row scaling.   
+
+    The parameter LAMBDA is included in the routine so that DLAGTF may   
+    be used, in conjunction with DLAGTS, to obtain eigenvectors of T by   
+    inverse iteration.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix T.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, A must contain the diagonal elements of T.   
+
+            On exit, A is overwritten by the n diagonal elements of the   
+            upper triangular matrix U of the factorization of T.   
+
+    LAMBDA  (input) DOUBLE PRECISION   
+            On entry, the scalar lambda.   
+
+    B       (input/output) DOUBLE PRECISION array, dimension (N-1)   
+            On entry, B must contain the (n-1) super-diagonal elements of   
+            T.   
+
+            On exit, B is overwritten by the (n-1) super-diagonal   
+            elements of the matrix U of the factorization of T.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (N-1)   
+            On entry, C must contain the (n-1) sub-diagonal elements of   
+            T.   
+
+            On exit, C is overwritten by the (n-1) sub-diagonal elements   
+            of the matrix L of the factorization of T.   
+
+    TOL     (input) DOUBLE PRECISION   
+            On entry, a relative tolerance used to indicate whether or   
+            not the matrix (T - lambda*I) is nearly singular. TOL should   
+            normally be chose as approximately the largest relative error   
+            in the elements of T. For example, if the elements of T are   
+            correct to about 4 significant figures, then TOL should be   
+            set to about 5*10**(-4). If TOL is supplied as less than eps,   
+            where eps is the relative machine precision, then the value   
+            eps is used in place of TOL.   
+
+    D       (output) DOUBLE PRECISION array, dimension (N-2)   
+            On exit, D is overwritten by the (n-2) second super-diagonal   
+            elements of the matrix U of the factorization of T.   
+
+    IN      (output) INTEGER array, dimension (N)   
+            On exit, IN contains details of the permutation matrix P. If   
+            an interchange occurred at the kth step of the elimination,   
+            then IN(k) = 1, otherwise IN(k) = 0. The element IN(n)   
+            returns the smallest positive integer j such that   
+
+               abs( u(j,j) ).le. norm( (T - lambda*I)(j) )*TOL,   
+
+            where norm( A(j) ) denotes the sum of the absolute values of   
+            the jth row of the matrix A. If no such j exists then IN(n)   
+            is returned as zero. If IN(n) is returned as positive, then a   
+            diagonal element of U is small, indicating that   
+            (T - lambda*I) is singular or nearly singular,   
+
+    INFO    (output) INTEGER   
+            = 0   : successful exit   
+            .lt. 0: if INFO = -k, the kth argument had an illegal value   
+
+   =====================================================================   
+
+
+       Parameter adjustments */
+    --in;
+    --d__;
+    --c__;
+    --b;
+    --a;
+
+    /* Function Body */
+    *info = 0;
+    if (*n < 0) {
+	*info = -1;
+	i__1 = -(*info);
+	igraphxerbla_("DLAGTF", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+    if (*n == 0) {
+	return 0;
+    }
+
+    a[1] -= *lambda;
+    in[*n] = 0;
+    if (*n == 1) {
+	if (a[1] == 0.) {
+	    in[1] = 1;
+	}
+	return 0;
+    }
+
+    eps = igraphdlamch_("Epsilon");
+
+    tl = max(*tol,eps);
+    scale1 = abs(a[1]) + abs(b[1]);
+    i__1 = *n - 1;
+    for (k = 1; k <= i__1; ++k) {
+	a[k + 1] -= *lambda;
+	scale2 = (d__1 = c__[k], abs(d__1)) + (d__2 = a[k + 1], abs(d__2));
+	if (k < *n - 1) {
+	    scale2 += (d__1 = b[k + 1], abs(d__1));
+	}
+	if (a[k] == 0.) {
+	    piv1 = 0.;
+	} else {
+	    piv1 = (d__1 = a[k], abs(d__1)) / scale1;
+	}
+	if (c__[k] == 0.) {
+	    in[k] = 0;
+	    piv2 = 0.;
+	    scale1 = scale2;
+	    if (k < *n - 1) {
+		d__[k] = 0.;
+	    }
+	} else {
+	    piv2 = (d__1 = c__[k], abs(d__1)) / scale2;
+	    if (piv2 <= piv1) {
+		in[k] = 0;
+		scale1 = scale2;
+		c__[k] /= a[k];
+		a[k + 1] -= c__[k] * b[k];
+		if (k < *n - 1) {
+		    d__[k] = 0.;
+		}
+	    } else {
+		in[k] = 1;
+		mult = a[k] / c__[k];
+		a[k] = c__[k];
+		temp = a[k + 1];
+		a[k + 1] = b[k] - mult * temp;
+		if (k < *n - 1) {
+		    d__[k] = b[k + 1];
+		    b[k + 1] = -mult * d__[k];
+		}
+		b[k] = temp;
+		c__[k] = mult;
+	    }
+	}
+	if (max(piv1,piv2) <= tl && in[*n] == 0) {
+	    in[*n] = k;
+	}
+/* L10: */
+    }
+    if ((d__1 = a[*n], abs(d__1)) <= scale1 * tl && in[*n] == 0) {
+	in[*n] = *n;
+    }
+
+    return 0;
+
+/*     End of DLAGTF */
+
+} /* igraphdlagtf_ */
+
diff --git a/src/lapack/dlagts.c b/src/lapack/dlagts.c
new file mode 100644
index 0000000..0c99499
--- /dev/null
+++ b/src/lapack/dlagts.c
@@ -0,0 +1,337 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlagts_(integer *job, integer *n, doublereal *a, 
+	doublereal *b, doublereal *c__, doublereal *d__, integer *in, 
+	doublereal *y, doublereal *tol, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2, d__3, d__4, d__5;
+
+    /* Builtin functions */
+    double d_sign(doublereal *, doublereal *);
+
+    /* Local variables */
+    integer k;
+    doublereal ak, eps, temp, pert, absak, sfmin;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    doublereal bignum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLAGTS may be used to solve one of the systems of equations   
+
+       (T - lambda*I)*x = y   or   (T - lambda*I)**T*x = y,   
+
+    where T is an n by n tridiagonal matrix, for x, following the   
+    factorization of (T - lambda*I) as   
+
+       (T - lambda*I) = P*L*U ,   
+
+    by routine DLAGTF. The choice of equation to be solved is   
+    controlled by the argument JOB, and in each case there is an option   
+    to perturb zero or very small diagonal elements of U, this option   
+    being intended for use in applications such as inverse iteration.   
+
+    Arguments   
+    =========   
+
+    JOB     (input) INTEGER   
+            Specifies the job to be performed by DLAGTS as follows:   
+            =  1: The equations  (T - lambda*I)x = y  are to be solved,   
+                  but diagonal elements of U are not to be perturbed.   
+            = -1: The equations  (T - lambda*I)x = y  are to be solved   
+                  and, if overflow would otherwise occur, the diagonal   
+                  elements of U are to be perturbed. See argument TOL   
+                  below.   
+            =  2: The equations  (T - lambda*I)**Tx = y  are to be solved,   
+                  but diagonal elements of U are not to be perturbed.   
+            = -2: The equations  (T - lambda*I)**Tx = y  are to be solved   
+                  and, if overflow would otherwise occur, the diagonal   
+                  elements of U are to be perturbed. See argument TOL   
+                  below.   
+
+    N       (input) INTEGER   
+            The order of the matrix T.   
+
+    A       (input) DOUBLE PRECISION array, dimension (N)   
+            On entry, A must contain the diagonal elements of U as   
+            returned from DLAGTF.   
+
+    B       (input) DOUBLE PRECISION array, dimension (N-1)   
+            On entry, B must contain the first super-diagonal elements of   
+            U as returned from DLAGTF.   
+
+    C       (input) DOUBLE PRECISION array, dimension (N-1)   
+            On entry, C must contain the sub-diagonal elements of L as   
+            returned from DLAGTF.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N-2)   
+            On entry, D must contain the second super-diagonal elements   
+            of U as returned from DLAGTF.   
+
+    IN      (input) INTEGER array, dimension (N)   
+            On entry, IN must contain details of the matrix P as returned   
+            from DLAGTF.   
+
+    Y       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the right hand side vector y.   
+            On exit, Y is overwritten by the solution vector x.   
+
+    TOL     (input/output) DOUBLE PRECISION   
+            On entry, with  JOB .lt. 0, TOL should be the minimum   
+            perturbation to be made to very small diagonal elements of U.   
+            TOL should normally be chosen as about eps*norm(U), where eps   
+            is the relative machine precision, but if TOL is supplied as   
+            non-positive, then it is reset to eps*max( abs( u(i,j) ) ).   
+            If  JOB .gt. 0  then TOL is not referenced.   
+
+            On exit, TOL is changed as described above, only if TOL is   
+            non-positive on entry. Otherwise TOL is unchanged.   
+
+    INFO    (output) INTEGER   
+            = 0   : successful exit   
+            .lt. 0: if INFO = -i, the i-th argument had an illegal value   
+            .gt. 0: overflow would occur when computing the INFO(th)   
+                    element of the solution vector x. This can only occur   
+                    when JOB is supplied as positive and either means   
+                    that a diagonal element of U is very small, or that   
+                    the elements of the right-hand side vector y are very   
+                    large.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --y;
+    --in;
+    --d__;
+    --c__;
+    --b;
+    --a;
+
+    /* Function Body */
+    *info = 0;
+    if (abs(*job) > 2 || *job == 0) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DLAGTS", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+    if (*n == 0) {
+	return 0;
+    }
+
+    eps = igraphdlamch_("Epsilon");
+    sfmin = igraphdlamch_("Safe minimum");
+    bignum = 1. / sfmin;
+
+    if (*job < 0) {
+	if (*tol <= 0.) {
+	    *tol = abs(a[1]);
+	    if (*n > 1) {
+/* Computing MAX */
+		d__1 = *tol, d__2 = abs(a[2]), d__1 = max(d__1,d__2), d__2 = 
+			abs(b[1]);
+		*tol = max(d__1,d__2);
+	    }
+	    i__1 = *n;
+	    for (k = 3; k <= i__1; ++k) {
+/* Computing MAX */
+		d__4 = *tol, d__5 = (d__1 = a[k], abs(d__1)), d__4 = max(d__4,
+			d__5), d__5 = (d__2 = b[k - 1], abs(d__2)), d__4 = 
+			max(d__4,d__5), d__5 = (d__3 = d__[k - 2], abs(d__3));
+		*tol = max(d__4,d__5);
+/* L10: */
+	    }
+	    *tol *= eps;
+	    if (*tol == 0.) {
+		*tol = eps;
+	    }
+	}
+    }
+
+    if (abs(*job) == 1) {
+	i__1 = *n;
+	for (k = 2; k <= i__1; ++k) {
+	    if (in[k - 1] == 0) {
+		y[k] -= c__[k - 1] * y[k - 1];
+	    } else {
+		temp = y[k - 1];
+		y[k - 1] = y[k];
+		y[k] = temp - c__[k - 1] * y[k];
+	    }
+/* L20: */
+	}
+	if (*job == 1) {
+	    for (k = *n; k >= 1; --k) {
+		if (k <= *n - 2) {
+		    temp = y[k] - b[k] * y[k + 1] - d__[k] * y[k + 2];
+		} else if (k == *n - 1) {
+		    temp = y[k] - b[k] * y[k + 1];
+		} else {
+		    temp = y[k];
+		}
+		ak = a[k];
+		absak = abs(ak);
+		if (absak < 1.) {
+		    if (absak < sfmin) {
+			if (absak == 0. || abs(temp) * sfmin > absak) {
+			    *info = k;
+			    return 0;
+			} else {
+			    temp *= bignum;
+			    ak *= bignum;
+			}
+		    } else if (abs(temp) > absak * bignum) {
+			*info = k;
+			return 0;
+		    }
+		}
+		y[k] = temp / ak;
+/* L30: */
+	    }
+	} else {
+	    for (k = *n; k >= 1; --k) {
+		if (k <= *n - 2) {
+		    temp = y[k] - b[k] * y[k + 1] - d__[k] * y[k + 2];
+		} else if (k == *n - 1) {
+		    temp = y[k] - b[k] * y[k + 1];
+		} else {
+		    temp = y[k];
+		}
+		ak = a[k];
+		pert = d_sign(tol, &ak);
+L40:
+		absak = abs(ak);
+		if (absak < 1.) {
+		    if (absak < sfmin) {
+			if (absak == 0. || abs(temp) * sfmin > absak) {
+			    ak += pert;
+			    pert *= 2;
+			    goto L40;
+			} else {
+			    temp *= bignum;
+			    ak *= bignum;
+			}
+		    } else if (abs(temp) > absak * bignum) {
+			ak += pert;
+			pert *= 2;
+			goto L40;
+		    }
+		}
+		y[k] = temp / ak;
+/* L50: */
+	    }
+	}
+    } else {
+
+/*        Come to here if  JOB = 2 or -2 */
+
+	if (*job == 2) {
+	    i__1 = *n;
+	    for (k = 1; k <= i__1; ++k) {
+		if (k >= 3) {
+		    temp = y[k] - b[k - 1] * y[k - 1] - d__[k - 2] * y[k - 2];
+		} else if (k == 2) {
+		    temp = y[k] - b[k - 1] * y[k - 1];
+		} else {
+		    temp = y[k];
+		}
+		ak = a[k];
+		absak = abs(ak);
+		if (absak < 1.) {
+		    if (absak < sfmin) {
+			if (absak == 0. || abs(temp) * sfmin > absak) {
+			    *info = k;
+			    return 0;
+			} else {
+			    temp *= bignum;
+			    ak *= bignum;
+			}
+		    } else if (abs(temp) > absak * bignum) {
+			*info = k;
+			return 0;
+		    }
+		}
+		y[k] = temp / ak;
+/* L60: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (k = 1; k <= i__1; ++k) {
+		if (k >= 3) {
+		    temp = y[k] - b[k - 1] * y[k - 1] - d__[k - 2] * y[k - 2];
+		} else if (k == 2) {
+		    temp = y[k] - b[k - 1] * y[k - 1];
+		} else {
+		    temp = y[k];
+		}
+		ak = a[k];
+		pert = d_sign(tol, &ak);
+L70:
+		absak = abs(ak);
+		if (absak < 1.) {
+		    if (absak < sfmin) {
+			if (absak == 0. || abs(temp) * sfmin > absak) {
+			    ak += pert;
+			    pert *= 2;
+			    goto L70;
+			} else {
+			    temp *= bignum;
+			    ak *= bignum;
+			}
+		    } else if (abs(temp) > absak * bignum) {
+			ak += pert;
+			pert *= 2;
+			goto L70;
+		    }
+		}
+		y[k] = temp / ak;
+/* L80: */
+	    }
+	}
+
+	for (k = *n; k >= 2; --k) {
+	    if (in[k - 1] == 0) {
+		y[k - 1] -= c__[k - 1] * y[k];
+	    } else {
+		temp = y[k - 1];
+		y[k - 1] = y[k];
+		y[k] = temp - c__[k - 1] * y[k];
+	    }
+/* L90: */
+	}
+    }
+
+/*     End of DLAGTS */
+
+    return 0;
+} /* igraphdlagts_ */
+
diff --git a/src/lapack/dlahqr.c b/src/lapack/dlahqr.c
new file mode 100644
index 0000000..25539cb
--- /dev/null
+++ b/src/lapack/dlahqr.c
@@ -0,0 +1,614 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdlahqr_(logical *wantt, logical *wantz, integer *n, 
+	integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal 
+	*wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, 
+	integer *ldz, integer *info)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3;
+    doublereal d__1, d__2, d__3, d__4;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, k, l, m;
+    doublereal s, v[3];
+    integer i1, i2;
+    doublereal t1, t2, t3, v2, v3, aa, ab, ba, bb, h11, h12, h21, h22, cs;
+    integer nh;
+    doublereal sn;
+    integer nr;
+    doublereal tr;
+    integer nz;
+    doublereal det, h21s;
+    integer its;
+    doublereal ulp, sum, tst, rt1i, rt2i, rt1r, rt2r;
+    extern /* Subroutine */ int igraphdrot_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *), igraphdcopy_(
+	    integer *, doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlanv2_(doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *), igraphdlabad_(doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlarfg_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *);
+    doublereal safmin, safmax, rtdisc, smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+       November 2006   
+
+
+       Purpose   
+       =======   
+
+       DLAHQR is an auxiliary routine called by DHSEQR to update the   
+       eigenvalues and Schur decomposition already computed by DHSEQR, by   
+       dealing with the Hessenberg submatrix in rows and columns ILO to   
+       IHI.   
+
+       Arguments   
+       =========   
+
+       WANTT   (input) LOGICAL   
+            = .TRUE. : the full Schur form T is required;   
+            = .FALSE.: only eigenvalues are required.   
+
+       WANTZ   (input) LOGICAL   
+            = .TRUE. : the matrix of Schur vectors Z is required;   
+            = .FALSE.: Schur vectors are not required.   
+
+       N       (input) INTEGER   
+            The order of the matrix H.  N >= 0.   
+
+       ILO     (input) INTEGER   
+       IHI     (input) INTEGER   
+            It is assumed that H is already upper quasi-triangular in   
+            rows and columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless   
+            ILO = 1). DLAHQR works primarily with the Hessenberg   
+            submatrix in rows and columns ILO to IHI, but applies   
+            transformations to all of H if WANTT is .TRUE..   
+            1 <= ILO <= max(1,IHI); IHI <= N.   
+
+       H       (input/output) DOUBLE PRECISION array, dimension (LDH,N)   
+            On entry, the upper Hessenberg matrix H.   
+            On exit, if INFO is zero and if WANTT is .TRUE., H is upper   
+            quasi-triangular in rows and columns ILO:IHI, with any   
+            2-by-2 diagonal blocks in standard form. If INFO is zero   
+            and WANTT is .FALSE., the contents of H are unspecified on   
+            exit.  The output state of H if INFO is nonzero is given   
+            below under the description of INFO.   
+
+       LDH     (input) INTEGER   
+            The leading dimension of the array H. LDH >= max(1,N).   
+
+       WR      (output) DOUBLE PRECISION array, dimension (N)   
+       WI      (output) DOUBLE PRECISION array, dimension (N)   
+            The real and imaginary parts, respectively, of the computed   
+            eigenvalues ILO to IHI are stored in the corresponding   
+            elements of WR and WI. If two eigenvalues are computed as a   
+            complex conjugate pair, they are stored in consecutive   
+            elements of WR and WI, say the i-th and (i+1)th, with   
+            WI(i) > 0 and WI(i+1) < 0. If WANTT is .TRUE., the   
+            eigenvalues are stored in the same order as on the diagonal   
+            of the Schur form returned in H, with WR(i) = H(i,i), and, if   
+            H(i:i+1,i:i+1) is a 2-by-2 diagonal block,   
+            WI(i) = sqrt(H(i+1,i)*H(i,i+1)) and WI(i+1) = -WI(i).   
+
+       ILOZ    (input) INTEGER   
+       IHIZ    (input) INTEGER   
+            Specify the rows of Z to which transformations must be   
+            applied if WANTZ is .TRUE..   
+            1 <= ILOZ <= ILO; IHI <= IHIZ <= N.   
+
+       Z       (input/output) DOUBLE PRECISION array, dimension (LDZ,N)   
+            If WANTZ is .TRUE., on entry Z must contain the current   
+            matrix Z of transformations accumulated by DHSEQR, and on   
+            exit Z has been updated; transformations are applied only to   
+            the submatrix Z(ILOZ:IHIZ,ILO:IHI).   
+            If WANTZ is .FALSE., Z is not referenced.   
+
+       LDZ     (input) INTEGER   
+            The leading dimension of the array Z. LDZ >= max(1,N).   
+
+       INFO    (output) INTEGER   
+             =   0: successful exit   
+            .GT. 0: If INFO = i, DLAHQR failed to compute all the   
+                    eigenvalues ILO to IHI in a total of 30 iterations   
+                    per eigenvalue; elements i+1:ihi of WR and WI   
+                    contain those eigenvalues which have been   
+                    successfully computed.   
+
+                    If INFO .GT. 0 and WANTT is .FALSE., then on exit,   
+                    the remaining unconverged eigenvalues are the   
+                    eigenvalues of the upper Hessenberg matrix rows   
+                    and columns ILO thorugh INFO of the final, output   
+                    value of H.   
+
+                    If INFO .GT. 0 and WANTT is .TRUE., then on exit   
+            (*)       (initial value of H)*U  = U*(final value of H)   
+                    where U is an orthognal matrix.    The final   
+                    value of H is upper Hessenberg and triangular in   
+                    rows and columns INFO+1 through IHI.   
+
+                    If INFO .GT. 0 and WANTZ is .TRUE., then on exit   
+                        (final value of Z)  = (initial value of Z)*U   
+                    where U is the orthogonal matrix in (*)   
+                    (regardless of the value of WANTT.)   
+
+       Further Details   
+       ===============   
+
+       02-96 Based on modifications by   
+       David Day, Sandia National Laboratory, USA   
+
+       12-04 Further modifications by   
+       Ralph Byers, University of Kansas, USA   
+       This is a modified version of DLAHQR from LAPACK version 3.0.   
+       It is (1) more robust against overflow and underflow and   
+       (2) adopts the more conservative Ahues & Tisseur stopping   
+       criterion (LAWN 122, 1997).   
+
+       =========================================================   
+
+
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --wr;
+    --wi;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+
+    /* Function Body */
+    *info = 0;
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+    if (*ilo == *ihi) {
+	wr[*ilo] = h__[*ilo + *ilo * h_dim1];
+	wi[*ilo] = 0.;
+	return 0;
+    }
+
+/*     ==== clear out the trash ==== */
+    i__1 = *ihi - 3;
+    for (j = *ilo; j <= i__1; ++j) {
+	h__[j + 2 + j * h_dim1] = 0.;
+	h__[j + 3 + j * h_dim1] = 0.;
+/* L10: */
+    }
+    if (*ilo <= *ihi - 2) {
+	h__[*ihi + (*ihi - 2) * h_dim1] = 0.;
+    }
+
+    nh = *ihi - *ilo + 1;
+    nz = *ihiz - *iloz + 1;
+
+/*     Set machine-dependent constants for the stopping criterion. */
+
+    safmin = igraphdlamch_("SAFE MINIMUM");
+    safmax = 1. / safmin;
+    igraphdlabad_(&safmin, &safmax);
+    ulp = igraphdlamch_("PRECISION");
+    smlnum = safmin * ((doublereal) nh / ulp);
+
+/*     I1 and I2 are the indices of the first row and last column of H   
+       to which transformations must be applied. If eigenvalues only are   
+       being computed, I1 and I2 are set inside the main loop. */
+
+    if (*wantt) {
+	i1 = 1;
+	i2 = *n;
+    }
+
+/*     The main loop begins here. I is the loop index and decreases from   
+       IHI to ILO in steps of 1 or 2. Each iteration of the loop works   
+       with the active submatrix in rows and columns L to I.   
+       Eigenvalues I+1 to IHI have already converged. Either L = ILO or   
+       H(L,L-1) is negligible so that the matrix splits. */
+
+    i__ = *ihi;
+L20:
+    l = *ilo;
+    if (i__ < *ilo) {
+	goto L160;
+    }
+
+/*     Perform QR iterations on rows and columns ILO to I until a   
+       submatrix of order 1 or 2 splits off at the bottom because a   
+       subdiagonal element has become negligible. */
+
+    for (its = 0; its <= 30; ++its) {
+
+/*        Look for a single small subdiagonal element. */
+
+	i__1 = l + 1;
+	for (k = i__; k >= i__1; --k) {
+	    if ((d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)) <= smlnum) {
+		goto L40;
+	    }
+	    tst = (d__1 = h__[k - 1 + (k - 1) * h_dim1], abs(d__1)) + (d__2 = 
+		    h__[k + k * h_dim1], abs(d__2));
+	    if (tst == 0.) {
+		if (k - 2 >= *ilo) {
+		    tst += (d__1 = h__[k - 1 + (k - 2) * h_dim1], abs(d__1));
+		}
+		if (k + 1 <= *ihi) {
+		    tst += (d__1 = h__[k + 1 + k * h_dim1], abs(d__1));
+		}
+	    }
+/*           ==== The following is a conservative small subdiagonal   
+             .    deflation  criterion due to Ahues & Tisseur (LAWN 122,   
+             .    1997). It has better mathematical foundation and   
+             .    improves accuracy in some cases.  ==== */
+	    if ((d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)) <= ulp * tst) {
+/* Computing MAX */
+		d__3 = (d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)), d__4 = (
+			d__2 = h__[k - 1 + k * h_dim1], abs(d__2));
+		ab = max(d__3,d__4);
+/* Computing MIN */
+		d__3 = (d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)), d__4 = (
+			d__2 = h__[k - 1 + k * h_dim1], abs(d__2));
+		ba = min(d__3,d__4);
+/* Computing MAX */
+		d__3 = (d__1 = h__[k + k * h_dim1], abs(d__1)), d__4 = (d__2 =
+			 h__[k - 1 + (k - 1) * h_dim1] - h__[k + k * h_dim1], 
+			abs(d__2));
+		aa = max(d__3,d__4);
+/* Computing MIN */
+		d__3 = (d__1 = h__[k + k * h_dim1], abs(d__1)), d__4 = (d__2 =
+			 h__[k - 1 + (k - 1) * h_dim1] - h__[k + k * h_dim1], 
+			abs(d__2));
+		bb = min(d__3,d__4);
+		s = aa + ab;
+/* Computing MAX */
+		d__1 = smlnum, d__2 = ulp * (bb * (aa / s));
+		if (ba * (ab / s) <= max(d__1,d__2)) {
+		    goto L40;
+		}
+	    }
+/* L30: */
+	}
+L40:
+	l = k;
+	if (l > *ilo) {
+
+/*           H(L,L-1) is negligible */
+
+	    h__[l + (l - 1) * h_dim1] = 0.;
+	}
+
+/*        Exit from loop if a submatrix of order 1 or 2 has split off. */
+
+	if (l >= i__ - 1) {
+	    goto L150;
+	}
+
+/*        Now the active submatrix is in rows and columns L to I. If   
+          eigenvalues only are being computed, only the active submatrix   
+          need be transformed. */
+
+	if (! (*wantt)) {
+	    i1 = l;
+	    i2 = i__;
+	}
+
+	if (its == 10) {
+
+/*           Exceptional shift. */
+
+	    s = (d__1 = h__[l + 1 + l * h_dim1], abs(d__1)) + (d__2 = h__[l + 
+		    2 + (l + 1) * h_dim1], abs(d__2));
+	    h11 = s * .75 + h__[l + l * h_dim1];
+	    h12 = s * -.4375;
+	    h21 = s;
+	    h22 = h11;
+	} else if (its == 20) {
+
+/*           Exceptional shift. */
+
+	    s = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1)) + (d__2 = 
+		    h__[i__ - 1 + (i__ - 2) * h_dim1], abs(d__2));
+	    h11 = s * .75 + h__[i__ + i__ * h_dim1];
+	    h12 = s * -.4375;
+	    h21 = s;
+	    h22 = h11;
+	} else {
+
+/*           Prepare to use Francis' double shift   
+             (i.e. 2nd degree generalized Rayleigh quotient) */
+
+	    h11 = h__[i__ - 1 + (i__ - 1) * h_dim1];
+	    h21 = h__[i__ + (i__ - 1) * h_dim1];
+	    h12 = h__[i__ - 1 + i__ * h_dim1];
+	    h22 = h__[i__ + i__ * h_dim1];
+	}
+	s = abs(h11) + abs(h12) + abs(h21) + abs(h22);
+	if (s == 0.) {
+	    rt1r = 0.;
+	    rt1i = 0.;
+	    rt2r = 0.;
+	    rt2i = 0.;
+	} else {
+	    h11 /= s;
+	    h21 /= s;
+	    h12 /= s;
+	    h22 /= s;
+	    tr = (h11 + h22) / 2.;
+	    det = (h11 - tr) * (h22 - tr) - h12 * h21;
+	    rtdisc = sqrt((abs(det)));
+	    if (det >= 0.) {
+
+/*              ==== complex conjugate shifts ==== */
+
+		rt1r = tr * s;
+		rt2r = rt1r;
+		rt1i = rtdisc * s;
+		rt2i = -rt1i;
+	    } else {
+
+/*              ==== real shifts (use only one of them)  ==== */
+
+		rt1r = tr + rtdisc;
+		rt2r = tr - rtdisc;
+		if ((d__1 = rt1r - h22, abs(d__1)) <= (d__2 = rt2r - h22, abs(
+			d__2))) {
+		    rt1r *= s;
+		    rt2r = rt1r;
+		} else {
+		    rt2r *= s;
+		    rt1r = rt2r;
+		}
+		rt1i = 0.;
+		rt2i = 0.;
+	    }
+	}
+
+/*        Look for two consecutive small subdiagonal elements. */
+
+	i__1 = l;
+	for (m = i__ - 2; m >= i__1; --m) {
+/*           Determine the effect of starting the double-shift QR   
+             iteration at row M, and see if this would make H(M,M-1)   
+             negligible.  (The following uses scaling to avoid   
+             overflows and most underflows.) */
+
+	    h21s = h__[m + 1 + m * h_dim1];
+	    s = (d__1 = h__[m + m * h_dim1] - rt2r, abs(d__1)) + abs(rt2i) + 
+		    abs(h21s);
+	    h21s = h__[m + 1 + m * h_dim1] / s;
+	    v[0] = h21s * h__[m + (m + 1) * h_dim1] + (h__[m + m * h_dim1] - 
+		    rt1r) * ((h__[m + m * h_dim1] - rt2r) / s) - rt1i * (rt2i 
+		    / s);
+	    v[1] = h21s * (h__[m + m * h_dim1] + h__[m + 1 + (m + 1) * h_dim1]
+		     - rt1r - rt2r);
+	    v[2] = h21s * h__[m + 2 + (m + 1) * h_dim1];
+	    s = abs(v[0]) + abs(v[1]) + abs(v[2]);
+	    v[0] /= s;
+	    v[1] /= s;
+	    v[2] /= s;
+	    if (m == l) {
+		goto L60;
+	    }
+	    if ((d__1 = h__[m + (m - 1) * h_dim1], abs(d__1)) * (abs(v[1]) + 
+		    abs(v[2])) <= ulp * abs(v[0]) * ((d__2 = h__[m - 1 + (m - 
+		    1) * h_dim1], abs(d__2)) + (d__3 = h__[m + m * h_dim1], 
+		    abs(d__3)) + (d__4 = h__[m + 1 + (m + 1) * h_dim1], abs(
+		    d__4)))) {
+		goto L60;
+	    }
+/* L50: */
+	}
+L60:
+
+/*        Double-shift QR step */
+
+	i__1 = i__ - 1;
+	for (k = m; k <= i__1; ++k) {
+
+/*           The first iteration of this loop determines a reflection G   
+             from the vector V and applies it from left and right to H,   
+             thus creating a nonzero bulge below the subdiagonal.   
+
+             Each subsequent iteration determines a reflection G to   
+             restore the Hessenberg form in the (K-1)th column, and thus   
+             chases the bulge one step toward the bottom of the active   
+             submatrix. NR is the order of G.   
+
+   Computing MIN */
+	    i__2 = 3, i__3 = i__ - k + 1;
+	    nr = min(i__2,i__3);
+	    if (k > m) {
+		igraphdcopy_(&nr, &h__[k + (k - 1) * h_dim1], &c__1, v, &c__1);
+	    }
+	    igraphdlarfg_(&nr, v, &v[1], &c__1, &t1);
+	    if (k > m) {
+		h__[k + (k - 1) * h_dim1] = v[0];
+		h__[k + 1 + (k - 1) * h_dim1] = 0.;
+		if (k < i__ - 1) {
+		    h__[k + 2 + (k - 1) * h_dim1] = 0.;
+		}
+	    } else if (m > l) {
+/*               ==== Use the following instead of   
+                 .    H( K, K-1 ) = -H( K, K-1 ) to   
+                 .    avoid a bug when v(2) and v(3)   
+                 .    underflow. ==== */
+		h__[k + (k - 1) * h_dim1] *= 1. - t1;
+	    }
+	    v2 = v[1];
+	    t2 = t1 * v2;
+	    if (nr == 3) {
+		v3 = v[2];
+		t3 = t1 * v3;
+
+/*              Apply G from the left to transform the rows of the matrix   
+                in columns K to I2. */
+
+		i__2 = i2;
+		for (j = k; j <= i__2; ++j) {
+		    sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1] 
+			    + v3 * h__[k + 2 + j * h_dim1];
+		    h__[k + j * h_dim1] -= sum * t1;
+		    h__[k + 1 + j * h_dim1] -= sum * t2;
+		    h__[k + 2 + j * h_dim1] -= sum * t3;
+/* L70: */
+		}
+
+/*              Apply G from the right to transform the columns of the   
+                matrix in rows I1 to min(K+3,I).   
+
+   Computing MIN */
+		i__3 = k + 3;
+		i__2 = min(i__3,i__);
+		for (j = i1; j <= i__2; ++j) {
+		    sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1]
+			     + v3 * h__[j + (k + 2) * h_dim1];
+		    h__[j + k * h_dim1] -= sum * t1;
+		    h__[j + (k + 1) * h_dim1] -= sum * t2;
+		    h__[j + (k + 2) * h_dim1] -= sum * t3;
+/* L80: */
+		}
+
+		if (*wantz) {
+
+/*                 Accumulate transformations in the matrix Z */
+
+		    i__2 = *ihiz;
+		    for (j = *iloz; j <= i__2; ++j) {
+			sum = z__[j + k * z_dim1] + v2 * z__[j + (k + 1) * 
+				z_dim1] + v3 * z__[j + (k + 2) * z_dim1];
+			z__[j + k * z_dim1] -= sum * t1;
+			z__[j + (k + 1) * z_dim1] -= sum * t2;
+			z__[j + (k + 2) * z_dim1] -= sum * t3;
+/* L90: */
+		    }
+		}
+	    } else if (nr == 2) {
+
+/*              Apply G from the left to transform the rows of the matrix   
+                in columns K to I2. */
+
+		i__2 = i2;
+		for (j = k; j <= i__2; ++j) {
+		    sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1];
+		    h__[k + j * h_dim1] -= sum * t1;
+		    h__[k + 1 + j * h_dim1] -= sum * t2;
+/* L100: */
+		}
+
+/*              Apply G from the right to transform the columns of the   
+                matrix in rows I1 to min(K+3,I). */
+
+		i__2 = i__;
+		for (j = i1; j <= i__2; ++j) {
+		    sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1]
+			    ;
+		    h__[j + k * h_dim1] -= sum * t1;
+		    h__[j + (k + 1) * h_dim1] -= sum * t2;
+/* L110: */
+		}
+
+		if (*wantz) {
+
+/*                 Accumulate transformations in the matrix Z */
+
+		    i__2 = *ihiz;
+		    for (j = *iloz; j <= i__2; ++j) {
+			sum = z__[j + k * z_dim1] + v2 * z__[j + (k + 1) * 
+				z_dim1];
+			z__[j + k * z_dim1] -= sum * t1;
+			z__[j + (k + 1) * z_dim1] -= sum * t2;
+/* L120: */
+		    }
+		}
+	    }
+/* L130: */
+	}
+
+/* L140: */
+    }
+
+/*     Failure to converge in remaining number of iterations */
+
+    *info = i__;
+    return 0;
+
+L150:
+
+    if (l == i__) {
+
+/*        H(I,I-1) is negligible: one eigenvalue has converged. */
+
+	wr[i__] = h__[i__ + i__ * h_dim1];
+	wi[i__] = 0.;
+    } else if (l == i__ - 1) {
+
+/*        H(I-1,I-2) is negligible: a pair of eigenvalues have converged.   
+
+          Transform the 2-by-2 submatrix to standard Schur form,   
+          and compute and store the eigenvalues. */
+
+	igraphdlanv2_(&h__[i__ - 1 + (i__ - 1) * h_dim1], &h__[i__ - 1 + i__ * 
+		h_dim1], &h__[i__ + (i__ - 1) * h_dim1], &h__[i__ + i__ * 
+		h_dim1], &wr[i__ - 1], &wi[i__ - 1], &wr[i__], &wi[i__], &cs, 
+		&sn);
+
+	if (*wantt) {
+
+/*           Apply the transformation to the rest of H. */
+
+	    if (i2 > i__) {
+		i__1 = i2 - i__;
+		igraphdrot_(&i__1, &h__[i__ - 1 + (i__ + 1) * h_dim1], ldh, &h__[
+			i__ + (i__ + 1) * h_dim1], ldh, &cs, &sn);
+	    }
+	    i__1 = i__ - i1 - 1;
+	    igraphdrot_(&i__1, &h__[i1 + (i__ - 1) * h_dim1], &c__1, &h__[i1 + i__ *
+		     h_dim1], &c__1, &cs, &sn);
+	}
+	if (*wantz) {
+
+/*           Apply the transformation to Z. */
+
+	    igraphdrot_(&nz, &z__[*iloz + (i__ - 1) * z_dim1], &c__1, &z__[*iloz + 
+		    i__ * z_dim1], &c__1, &cs, &sn);
+	}
+    }
+
+/*     return to start of the main loop with new value of I. */
+
+    i__ = l - 1;
+    goto L20;
+
+L160:
+    return 0;
+
+/*     End of DLAHQR */
+
+} /* igraphdlahqr_ */
+
diff --git a/src/lapack/dlahr2.c b/src/lapack/dlahr2.c
new file mode 100644
index 0000000..6e60e9b
--- /dev/null
+++ b/src/lapack/dlahr2.c
@@ -0,0 +1,310 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b4 = -1.;
+static doublereal c_b5 = 1.;
+static integer c__1 = 1;
+static doublereal c_b38 = 0.;
+
+/* Subroutine */ int igraphdlahr2_(integer *n, integer *k, integer *nb, doublereal *
+	a, integer *lda, doublereal *tau, doublereal *t, integer *ldt, 
+	doublereal *y, integer *ldy)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, t_dim1, t_offset, y_dim1, y_offset, i__1, i__2, 
+	    i__3;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__;
+    doublereal ei;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *), igraphdgemm_(char *, char *, integer *, integer *, integer *
+	    , doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *), igraphdgemv_(
+	    char *, integer *, integer *, doublereal *, doublereal *, integer 
+	    *, doublereal *, integer *, doublereal *, doublereal *, integer *), igraphdcopy_(integer *, doublereal *, integer *, doublereal *,
+	     integer *), igraphdtrmm_(char *, char *, char *, char *, integer *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *), igraphdaxpy_(integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *), 
+	    igraphdtrmv_(char *, char *, char *, integer *, doublereal *, integer *,
+	     doublereal *, integer *), igraphdlarfg_(
+	    integer *, doublereal *, doublereal *, integer *, doublereal *), 
+	    igraphdlacpy_(char *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1)                        --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2009                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLAHR2 reduces the first NB columns of A real general n-BY-(n-k+1)   
+    matrix A so that elements below the k-th subdiagonal are zero. The   
+    reduction is performed by an orthogonal similarity transformation   
+    Q**T * A * Q. The routine returns the matrices V and T which determine   
+    Q as a block reflector I - V*T*V**T, and also the matrix Y = A * V * T.   
+
+    This is an auxiliary routine called by DGEHRD.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix A.   
+
+    K       (input) INTEGER   
+            The offset for the reduction. Elements below the k-th   
+            subdiagonal in the first NB columns are reduced to zero.   
+            K < N.   
+
+    NB      (input) INTEGER   
+            The number of columns to be reduced.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N-K+1)   
+            On entry, the n-by-(n-k+1) general matrix A.   
+            On exit, the elements on and above the k-th subdiagonal in   
+            the first NB columns are overwritten with the corresponding   
+            elements of the reduced matrix; the elements below the k-th   
+            subdiagonal, with the array TAU, represent the matrix Q as a   
+            product of elementary reflectors. The other columns of A are   
+            unchanged. See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (NB)   
+            The scalar factors of the elementary reflectors. See Further   
+            Details.   
+
+    T       (output) DOUBLE PRECISION array, dimension (LDT,NB)   
+            The upper triangular matrix T.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T.  LDT >= NB.   
+
+    Y       (output) DOUBLE PRECISION array, dimension (LDY,NB)   
+            The n-by-nb matrix Y.   
+
+    LDY     (input) INTEGER   
+            The leading dimension of the array Y. LDY >= N.   
+
+    Further Details   
+    ===============   
+
+    The matrix Q is represented as a product of nb elementary reflectors   
+
+       Q = H(1) H(2) . . . H(nb).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i+k-1) = 0, v(i+k) = 1; v(i+k+1:n) is stored on exit in   
+    A(i+k+1:n,i), and tau in TAU(i).   
+
+    The elements of the vectors v together form the (n-k+1)-by-nb matrix   
+    V which is needed, with T and Y, to apply the transformation to the   
+    unreduced part of the matrix, using an update of the form:   
+    A := (I - V*T*V**T) * (A - Y*V**T).   
+
+    The contents of A on exit are illustrated by the following example   
+    with n = 7, k = 3 and nb = 2:   
+
+       ( a   a   a   a   a )   
+       ( a   a   a   a   a )   
+       ( a   a   a   a   a )   
+       ( h   h   a   a   a )   
+       ( v1  h   a   a   a )   
+       ( v1  v2  a   a   a )   
+       ( v1  v2  a   a   a )   
+
+    where a denotes an element of the original matrix A, h denotes a   
+    modified element of the upper Hessenberg matrix H, and vi denotes an   
+    element of the vector defining H(i).   
+
+    This subroutine is a slight modification of LAPACK-3.0's DLAHRD   
+    incorporating improvements proposed by Quintana-Orti and Van de   
+    Gejin. Note that the entries of A(1:K,2:NB) differ from those   
+    returned by the original LAPACK-3.0's DLAHRD routine. (This   
+    subroutine is not backward compatible with LAPACK-3.0's DLAHRD.)   
+
+    References   
+    ==========   
+
+    Gregorio Quintana-Orti and Robert van de Geijn, "Improving the   
+    performance of reduction to Hessenberg form," ACM Transactions on   
+    Mathematical Software, 32(2):180-194, June 2006.   
+
+    =====================================================================   
+
+
+       Quick return if possible   
+
+       Parameter adjustments */
+    --tau;
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    y_dim1 = *ldy;
+    y_offset = 1 + y_dim1;
+    y -= y_offset;
+
+    /* Function Body */
+    if (*n <= 1) {
+	return 0;
+    }
+
+    i__1 = *nb;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	if (i__ > 1) {
+
+/*           Update A(K+1:N,I)   
+
+             Update I-th column of A - Y * V**T */
+
+	    i__2 = *n - *k;
+	    i__3 = i__ - 1;
+	    igraphdgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b4, &y[*k + 1 + y_dim1], 
+		    ldy, &a[*k + i__ - 1 + a_dim1], lda, &c_b5, &a[*k + 1 + 
+		    i__ * a_dim1], &c__1);
+
+/*           Apply I - V * T**T * V**T to this column (call it b) from the   
+             left, using the last column of T as workspace   
+
+             Let  V = ( V1 )   and   b = ( b1 )   (first I-1 rows)   
+                      ( V2 )             ( b2 )   
+
+             where V1 is unit lower triangular   
+
+             w := V1**T * b1 */
+
+	    i__2 = i__ - 1;
+	    igraphdcopy_(&i__2, &a[*k + 1 + i__ * a_dim1], &c__1, &t[*nb * t_dim1 + 
+		    1], &c__1);
+	    i__2 = i__ - 1;
+	    igraphdtrmv_("Lower", "Transpose", "UNIT", &i__2, &a[*k + 1 + a_dim1], 
+		    lda, &t[*nb * t_dim1 + 1], &c__1);
+
+/*           w := w + V2**T * b2 */
+
+	    i__2 = *n - *k - i__ + 1;
+	    i__3 = i__ - 1;
+	    igraphdgemv_("Transpose", &i__2, &i__3, &c_b5, &a[*k + i__ + a_dim1], 
+		    lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b5, &t[*nb * 
+		    t_dim1 + 1], &c__1);
+
+/*           w := T**T * w */
+
+	    i__2 = i__ - 1;
+	    igraphdtrmv_("Upper", "Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt,
+		     &t[*nb * t_dim1 + 1], &c__1);
+
+/*           b2 := b2 - V2*w */
+
+	    i__2 = *n - *k - i__ + 1;
+	    i__3 = i__ - 1;
+	    igraphdgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b4, &a[*k + i__ + a_dim1],
+		     lda, &t[*nb * t_dim1 + 1], &c__1, &c_b5, &a[*k + i__ + 
+		    i__ * a_dim1], &c__1);
+
+/*           b1 := b1 - V1*w */
+
+	    i__2 = i__ - 1;
+	    igraphdtrmv_("Lower", "NO TRANSPOSE", "UNIT", &i__2, &a[*k + 1 + a_dim1]
+		    , lda, &t[*nb * t_dim1 + 1], &c__1);
+	    i__2 = i__ - 1;
+	    igraphdaxpy_(&i__2, &c_b4, &t[*nb * t_dim1 + 1], &c__1, &a[*k + 1 + i__ 
+		    * a_dim1], &c__1);
+
+	    a[*k + i__ - 1 + (i__ - 1) * a_dim1] = ei;
+	}
+
+/*        Generate the elementary reflector H(I) to annihilate   
+          A(K+I+1:N,I) */
+
+	i__2 = *n - *k - i__ + 1;
+/* Computing MIN */
+	i__3 = *k + i__ + 1;
+	igraphdlarfg_(&i__2, &a[*k + i__ + i__ * a_dim1], &a[min(i__3,*n) + i__ * 
+		a_dim1], &c__1, &tau[i__]);
+	ei = a[*k + i__ + i__ * a_dim1];
+	a[*k + i__ + i__ * a_dim1] = 1.;
+
+/*        Compute  Y(K+1:N,I) */
+
+	i__2 = *n - *k;
+	i__3 = *n - *k - i__ + 1;
+	igraphdgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b5, &a[*k + 1 + (i__ + 1) * 
+		a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b38, &y[*
+		k + 1 + i__ * y_dim1], &c__1);
+	i__2 = *n - *k - i__ + 1;
+	i__3 = i__ - 1;
+	igraphdgemv_("Transpose", &i__2, &i__3, &c_b5, &a[*k + i__ + a_dim1], lda, &
+		a[*k + i__ + i__ * a_dim1], &c__1, &c_b38, &t[i__ * t_dim1 + 
+		1], &c__1);
+	i__2 = *n - *k;
+	i__3 = i__ - 1;
+	igraphdgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b4, &y[*k + 1 + y_dim1], ldy, 
+		&t[i__ * t_dim1 + 1], &c__1, &c_b5, &y[*k + 1 + i__ * y_dim1],
+		 &c__1);
+	i__2 = *n - *k;
+	igraphdscal_(&i__2, &tau[i__], &y[*k + 1 + i__ * y_dim1], &c__1);
+
+/*        Compute T(1:I,I) */
+
+	i__2 = i__ - 1;
+	d__1 = -tau[i__];
+	igraphdscal_(&i__2, &d__1, &t[i__ * t_dim1 + 1], &c__1);
+	i__2 = i__ - 1;
+	igraphdtrmv_("Upper", "No Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, 
+		&t[i__ * t_dim1 + 1], &c__1)
+		;
+	t[i__ + i__ * t_dim1] = tau[i__];
+
+/* L10: */
+    }
+    a[*k + *nb + *nb * a_dim1] = ei;
+
+/*     Compute Y(1:K,1:NB) */
+
+    igraphdlacpy_("ALL", k, nb, &a[(a_dim1 << 1) + 1], lda, &y[y_offset], ldy);
+    igraphdtrmm_("RIGHT", "Lower", "NO TRANSPOSE", "UNIT", k, nb, &c_b5, &a[*k + 1 
+	    + a_dim1], lda, &y[y_offset], ldy);
+    if (*n > *k + *nb) {
+	i__1 = *n - *k - *nb;
+	igraphdgemm_("NO TRANSPOSE", "NO TRANSPOSE", k, nb, &i__1, &c_b5, &a[(*nb + 
+		2) * a_dim1 + 1], lda, &a[*k + 1 + *nb + a_dim1], lda, &c_b5, 
+		&y[y_offset], ldy);
+    }
+    igraphdtrmm_("RIGHT", "Upper", "NO TRANSPOSE", "NON-UNIT", k, nb, &c_b5, &t[
+	    t_offset], ldt, &y[y_offset], ldy);
+
+    return 0;
+
+/*     End of DLAHR2 */
+
+} /* igraphdlahr2_ */
+
diff --git a/src/lapack/dlaisnan.c b/src/lapack/dlaisnan.c
new file mode 100644
index 0000000..32fd3c4
--- /dev/null
+++ b/src/lapack/dlaisnan.c
@@ -0,0 +1,57 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+logical igraphdlaisnan_(doublereal *din1, doublereal *din2)
+{
+    /* System generated locals */
+    logical ret_val;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    This routine is not for general use.  It exists solely to avoid   
+    over-optimization in DISNAN.   
+
+    DLAISNAN checks for NaNs by comparing its two arguments for   
+    inequality.  NaN is the only floating-point value where NaN != NaN   
+    returns .TRUE.  To check for NaNs, pass the same variable as both   
+    arguments.   
+
+    A compiler must assume that the two arguments are   
+    not the same variable, and the test will not be optimized away.   
+    Interprocedural or whole-program optimization may delete this   
+    test.  The ISNAN functions will be replaced by the correct   
+    Fortran 03 intrinsic once the intrinsic is widely available.   
+
+    Arguments   
+    =========   
+
+    DIN1    (input) DOUBLE PRECISION   
+
+    DIN2    (input) DOUBLE PRECISION   
+            Two numbers to compare for inequality.   
+
+    ===================================================================== */
+
+    ret_val = *din1 != *din2;
+    return ret_val;
+} /* igraphdlaisnan_ */
+
diff --git a/src/lapack/dlaln2.c b/src/lapack/dlaln2.c
new file mode 100644
index 0000000..ea75030
--- /dev/null
+++ b/src/lapack/dlaln2.c
@@ -0,0 +1,556 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaln2_(logical *ltrans, integer *na, integer *nw, 
+	doublereal *smin, doublereal *ca, doublereal *a, integer *lda, 
+	doublereal *d1, doublereal *d2, doublereal *b, integer *ldb, 
+	doublereal *wr, doublereal *wi, doublereal *x, integer *ldx, 
+	doublereal *scale, doublereal *xnorm, integer *info)
+{
+    /* Initialized data */
+
+    static logical zswap[4] = { FALSE_,FALSE_,TRUE_,TRUE_ };
+    static logical rswap[4] = { FALSE_,TRUE_,FALSE_,TRUE_ };
+    static integer ipivot[16]	/* was [4][4] */ = { 1,2,3,4,2,1,4,3,3,4,1,2,
+	    4,3,2,1 };
+
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, x_dim1, x_offset;
+    doublereal d__1, d__2, d__3, d__4, d__5, d__6;
+    IGRAPH_F77_SAVE doublereal equiv_0[4], equiv_1[4];
+
+    /* Local variables */
+    integer j;
+#define ci (equiv_0)
+#define cr (equiv_1)
+    doublereal bi1, bi2, br1, br2, xi1, xi2, xr1, xr2, ci21, ci22, cr21, cr22,
+	     li21, csi, ui11, lr21, ui12, ui22;
+#define civ (equiv_0)
+    doublereal csr, ur11, ur12, ur22;
+#define crv (equiv_1)
+    doublereal bbnd, cmax, ui11r, ui12s, temp, ur11r, ur12s, u22abs;
+    integer icmax;
+    doublereal bnorm, cnorm, smini;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdladiv_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *);
+    doublereal bignum, smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLALN2 solves a system of the form  (ca A - w D ) X = s B   
+    or (ca A**T - w D) X = s B   with possible scaling ("s") and   
+    perturbation of A.  (A**T means A-transpose.)   
+
+    A is an NA x NA real matrix, ca is a real scalar, D is an NA x NA   
+    real diagonal matrix, w is a real or complex value, and X and B are   
+    NA x 1 matrices -- real if w is real, complex if w is complex.  NA   
+    may be 1 or 2.   
+
+    If w is complex, X and B are represented as NA x 2 matrices,   
+    the first column of each being the real part and the second   
+    being the imaginary part.   
+
+    "s" is a scaling factor (.LE. 1), computed by DLALN2, which is   
+    so chosen that X can be computed without overflow.  X is further   
+    scaled if necessary to assure that norm(ca A - w D)*norm(X) is less   
+    than overflow.   
+
+    If both singular values of (ca A - w D) are less than SMIN,   
+    SMIN*identity will be used instead of (ca A - w D).  If only one   
+    singular value is less than SMIN, one element of (ca A - w D) will be   
+    perturbed enough to make the smallest singular value roughly SMIN.   
+    If both singular values are at least SMIN, (ca A - w D) will not be   
+    perturbed.  In any case, the perturbation will be at most some small   
+    multiple of max( SMIN, ulp*norm(ca A - w D) ).  The singular values   
+    are computed by infinity-norm approximations, and thus will only be   
+    correct to a factor of 2 or so.   
+
+    Note: all input quantities are assumed to be smaller than overflow   
+    by a reasonable factor.  (See BIGNUM.)   
+
+    Arguments   
+    ==========   
+
+    LTRANS  (input) LOGICAL   
+            =.TRUE.:  A-transpose will be used.   
+            =.FALSE.: A will be used (not transposed.)   
+
+    NA      (input) INTEGER   
+            The size of the matrix A.  It may (only) be 1 or 2.   
+
+    NW      (input) INTEGER   
+            1 if "w" is real, 2 if "w" is complex.  It may only be 1   
+            or 2.   
+
+    SMIN    (input) DOUBLE PRECISION   
+            The desired lower bound on the singular values of A.  This   
+            should be a safe distance away from underflow or overflow,   
+            say, between (underflow/machine precision) and  (machine   
+            precision * overflow ).  (See BIGNUM and ULP.)   
+
+    CA      (input) DOUBLE PRECISION   
+            The coefficient c, which A is multiplied by.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,NA)   
+            The NA x NA matrix A.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of A.  It must be at least NA.   
+
+    D1      (input) DOUBLE PRECISION   
+            The 1,1 element in the diagonal matrix D.   
+
+    D2      (input) DOUBLE PRECISION   
+            The 2,2 element in the diagonal matrix D.  Not used if NW=1.   
+
+    B       (input) DOUBLE PRECISION array, dimension (LDB,NW)   
+            The NA x NW matrix B (right-hand side).  If NW=2 ("w" is   
+            complex), column 1 contains the real part of B and column 2   
+            contains the imaginary part.   
+
+    LDB     (input) INTEGER   
+            The leading dimension of B.  It must be at least NA.   
+
+    WR      (input) DOUBLE PRECISION   
+            The real part of the scalar "w".   
+
+    WI      (input) DOUBLE PRECISION   
+            The imaginary part of the scalar "w".  Not used if NW=1.   
+
+    X       (output) DOUBLE PRECISION array, dimension (LDX,NW)   
+            The NA x NW matrix X (unknowns), as computed by DLALN2.   
+            If NW=2 ("w" is complex), on exit, column 1 will contain   
+            the real part of X and column 2 will contain the imaginary   
+            part.   
+
+    LDX     (input) INTEGER   
+            The leading dimension of X.  It must be at least NA.   
+
+    SCALE   (output) DOUBLE PRECISION   
+            The scale factor that B must be multiplied by to insure   
+            that overflow does not occur when computing X.  Thus,   
+            (ca A - w D) X  will be SCALE*B, not B (ignoring   
+            perturbations of A.)  It will be at most 1.   
+
+    XNORM   (output) DOUBLE PRECISION   
+            The infinity-norm of X, when X is regarded as an NA x NW   
+            real matrix.   
+
+    INFO    (output) INTEGER   
+            An error flag.  It will be set to zero if no error occurs,   
+            a negative number if an argument is in error, or a positive   
+            number if  ca A - w D  had to be perturbed.   
+            The possible values are:   
+            = 0: No error occurred, and (ca A - w D) did not have to be   
+                   perturbed.   
+            = 1: (ca A - w D) had to be perturbed to make its smallest   
+                 (or only) singular value greater than SMIN.   
+            NOTE: In the interests of speed, this routine does not   
+                  check the inputs for errors.   
+
+   =====================================================================   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+    x_dim1 = *ldx;
+    x_offset = 1 + x_dim1;
+    x -= x_offset;
+
+    /* Function Body   
+
+       Compute BIGNUM */
+
+    smlnum = 2. * igraphdlamch_("Safe minimum");
+    bignum = 1. / smlnum;
+    smini = max(*smin,smlnum);
+
+/*     Don't check for input errors */
+
+    *info = 0;
+
+/*     Standard Initializations */
+
+    *scale = 1.;
+
+    if (*na == 1) {
+
+/*        1 x 1  (i.e., scalar) system   C X = B */
+
+	if (*nw == 1) {
+
+/*           Real 1x1 system.   
+
+             C = ca A - w D */
+
+	    csr = *ca * a[a_dim1 + 1] - *wr * *d1;
+	    cnorm = abs(csr);
+
+/*           If | C | < SMINI, use C = SMINI */
+
+	    if (cnorm < smini) {
+		csr = smini;
+		cnorm = smini;
+		*info = 1;
+	    }
+
+/*           Check scaling for  X = B / C */
+
+	    bnorm = (d__1 = b[b_dim1 + 1], abs(d__1));
+	    if (cnorm < 1. && bnorm > 1.) {
+		if (bnorm > bignum * cnorm) {
+		    *scale = 1. / bnorm;
+		}
+	    }
+
+/*           Compute X */
+
+	    x[x_dim1 + 1] = b[b_dim1 + 1] * *scale / csr;
+	    *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1));
+	} else {
+
+/*           Complex 1x1 system (w is complex)   
+
+             C = ca A - w D */
+
+	    csr = *ca * a[a_dim1 + 1] - *wr * *d1;
+	    csi = -(*wi) * *d1;
+	    cnorm = abs(csr) + abs(csi);
+
+/*           If | C | < SMINI, use C = SMINI */
+
+	    if (cnorm < smini) {
+		csr = smini;
+		csi = 0.;
+		cnorm = smini;
+		*info = 1;
+	    }
+
+/*           Check scaling for  X = B / C */
+
+	    bnorm = (d__1 = b[b_dim1 + 1], abs(d__1)) + (d__2 = b[(b_dim1 << 
+		    1) + 1], abs(d__2));
+	    if (cnorm < 1. && bnorm > 1.) {
+		if (bnorm > bignum * cnorm) {
+		    *scale = 1. / bnorm;
+		}
+	    }
+
+/*           Compute X */
+
+	    d__1 = *scale * b[b_dim1 + 1];
+	    d__2 = *scale * b[(b_dim1 << 1) + 1];
+	    igraphdladiv_(&d__1, &d__2, &csr, &csi, &x[x_dim1 + 1], &x[(x_dim1 << 1)
+		     + 1]);
+	    *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1)) + (d__2 = x[(x_dim1 << 
+		    1) + 1], abs(d__2));
+	}
+
+    } else {
+
+/*        2x2 System   
+
+          Compute the real part of  C = ca A - w D  (or  ca A**T - w D ) */
+
+	cr[0] = *ca * a[a_dim1 + 1] - *wr * *d1;
+	cr[3] = *ca * a[(a_dim1 << 1) + 2] - *wr * *d2;
+	if (*ltrans) {
+	    cr[2] = *ca * a[a_dim1 + 2];
+	    cr[1] = *ca * a[(a_dim1 << 1) + 1];
+	} else {
+	    cr[1] = *ca * a[a_dim1 + 2];
+	    cr[2] = *ca * a[(a_dim1 << 1) + 1];
+	}
+
+	if (*nw == 1) {
+
+/*           Real 2x2 system  (w is real)   
+
+             Find the largest element in C */
+
+	    cmax = 0.;
+	    icmax = 0;
+
+	    for (j = 1; j <= 4; ++j) {
+		if ((d__1 = crv[j - 1], abs(d__1)) > cmax) {
+		    cmax = (d__1 = crv[j - 1], abs(d__1));
+		    icmax = j;
+		}
+/* L10: */
+	    }
+
+/*           If norm(C) < SMINI, use SMINI*identity. */
+
+	    if (cmax < smini) {
+/* Computing MAX */
+		d__3 = (d__1 = b[b_dim1 + 1], abs(d__1)), d__4 = (d__2 = b[
+			b_dim1 + 2], abs(d__2));
+		bnorm = max(d__3,d__4);
+		if (smini < 1. && bnorm > 1.) {
+		    if (bnorm > bignum * smini) {
+			*scale = 1. / bnorm;
+		    }
+		}
+		temp = *scale / smini;
+		x[x_dim1 + 1] = temp * b[b_dim1 + 1];
+		x[x_dim1 + 2] = temp * b[b_dim1 + 2];
+		*xnorm = temp * bnorm;
+		*info = 1;
+		return 0;
+	    }
+
+/*           Gaussian elimination with complete pivoting. */
+
+	    ur11 = crv[icmax - 1];
+	    cr21 = crv[ipivot[(icmax << 2) - 3] - 1];
+	    ur12 = crv[ipivot[(icmax << 2) - 2] - 1];
+	    cr22 = crv[ipivot[(icmax << 2) - 1] - 1];
+	    ur11r = 1. / ur11;
+	    lr21 = ur11r * cr21;
+	    ur22 = cr22 - ur12 * lr21;
+
+/*           If smaller pivot < SMINI, use SMINI */
+
+	    if (abs(ur22) < smini) {
+		ur22 = smini;
+		*info = 1;
+	    }
+	    if (rswap[icmax - 1]) {
+		br1 = b[b_dim1 + 2];
+		br2 = b[b_dim1 + 1];
+	    } else {
+		br1 = b[b_dim1 + 1];
+		br2 = b[b_dim1 + 2];
+	    }
+	    br2 -= lr21 * br1;
+/* Computing MAX */
+	    d__2 = (d__1 = br1 * (ur22 * ur11r), abs(d__1)), d__3 = abs(br2);
+	    bbnd = max(d__2,d__3);
+	    if (bbnd > 1. && abs(ur22) < 1.) {
+		if (bbnd >= bignum * abs(ur22)) {
+		    *scale = 1. / bbnd;
+		}
+	    }
+
+	    xr2 = br2 * *scale / ur22;
+	    xr1 = *scale * br1 * ur11r - xr2 * (ur11r * ur12);
+	    if (zswap[icmax - 1]) {
+		x[x_dim1 + 1] = xr2;
+		x[x_dim1 + 2] = xr1;
+	    } else {
+		x[x_dim1 + 1] = xr1;
+		x[x_dim1 + 2] = xr2;
+	    }
+/* Computing MAX */
+	    d__1 = abs(xr1), d__2 = abs(xr2);
+	    *xnorm = max(d__1,d__2);
+
+/*           Further scaling if  norm(A) norm(X) > overflow */
+
+	    if (*xnorm > 1. && cmax > 1.) {
+		if (*xnorm > bignum / cmax) {
+		    temp = cmax / bignum;
+		    x[x_dim1 + 1] = temp * x[x_dim1 + 1];
+		    x[x_dim1 + 2] = temp * x[x_dim1 + 2];
+		    *xnorm = temp * *xnorm;
+		    *scale = temp * *scale;
+		}
+	    }
+	} else {
+
+/*           Complex 2x2 system  (w is complex)   
+
+             Find the largest element in C */
+
+	    ci[0] = -(*wi) * *d1;
+	    ci[1] = 0.;
+	    ci[2] = 0.;
+	    ci[3] = -(*wi) * *d2;
+	    cmax = 0.;
+	    icmax = 0;
+
+	    for (j = 1; j <= 4; ++j) {
+		if ((d__1 = crv[j - 1], abs(d__1)) + (d__2 = civ[j - 1], abs(
+			d__2)) > cmax) {
+		    cmax = (d__1 = crv[j - 1], abs(d__1)) + (d__2 = civ[j - 1]
+			    , abs(d__2));
+		    icmax = j;
+		}
+/* L20: */
+	    }
+
+/*           If norm(C) < SMINI, use SMINI*identity. */
+
+	    if (cmax < smini) {
+/* Computing MAX */
+		d__5 = (d__1 = b[b_dim1 + 1], abs(d__1)) + (d__2 = b[(b_dim1 
+			<< 1) + 1], abs(d__2)), d__6 = (d__3 = b[b_dim1 + 2], 
+			abs(d__3)) + (d__4 = b[(b_dim1 << 1) + 2], abs(d__4));
+		bnorm = max(d__5,d__6);
+		if (smini < 1. && bnorm > 1.) {
+		    if (bnorm > bignum * smini) {
+			*scale = 1. / bnorm;
+		    }
+		}
+		temp = *scale / smini;
+		x[x_dim1 + 1] = temp * b[b_dim1 + 1];
+		x[x_dim1 + 2] = temp * b[b_dim1 + 2];
+		x[(x_dim1 << 1) + 1] = temp * b[(b_dim1 << 1) + 1];
+		x[(x_dim1 << 1) + 2] = temp * b[(b_dim1 << 1) + 2];
+		*xnorm = temp * bnorm;
+		*info = 1;
+		return 0;
+	    }
+
+/*           Gaussian elimination with complete pivoting. */
+
+	    ur11 = crv[icmax - 1];
+	    ui11 = civ[icmax - 1];
+	    cr21 = crv[ipivot[(icmax << 2) - 3] - 1];
+	    ci21 = civ[ipivot[(icmax << 2) - 3] - 1];
+	    ur12 = crv[ipivot[(icmax << 2) - 2] - 1];
+	    ui12 = civ[ipivot[(icmax << 2) - 2] - 1];
+	    cr22 = crv[ipivot[(icmax << 2) - 1] - 1];
+	    ci22 = civ[ipivot[(icmax << 2) - 1] - 1];
+	    if (icmax == 1 || icmax == 4) {
+
+/*              Code when off-diagonals of pivoted C are real */
+
+		if (abs(ur11) > abs(ui11)) {
+		    temp = ui11 / ur11;
+/* Computing 2nd power */
+		    d__1 = temp;
+		    ur11r = 1. / (ur11 * (d__1 * d__1 + 1.));
+		    ui11r = -temp * ur11r;
+		} else {
+		    temp = ur11 / ui11;
+/* Computing 2nd power */
+		    d__1 = temp;
+		    ui11r = -1. / (ui11 * (d__1 * d__1 + 1.));
+		    ur11r = -temp * ui11r;
+		}
+		lr21 = cr21 * ur11r;
+		li21 = cr21 * ui11r;
+		ur12s = ur12 * ur11r;
+		ui12s = ur12 * ui11r;
+		ur22 = cr22 - ur12 * lr21;
+		ui22 = ci22 - ur12 * li21;
+	    } else {
+
+/*              Code when diagonals of pivoted C are real */
+
+		ur11r = 1. / ur11;
+		ui11r = 0.;
+		lr21 = cr21 * ur11r;
+		li21 = ci21 * ur11r;
+		ur12s = ur12 * ur11r;
+		ui12s = ui12 * ur11r;
+		ur22 = cr22 - ur12 * lr21 + ui12 * li21;
+		ui22 = -ur12 * li21 - ui12 * lr21;
+	    }
+	    u22abs = abs(ur22) + abs(ui22);
+
+/*           If smaller pivot < SMINI, use SMINI */
+
+	    if (u22abs < smini) {
+		ur22 = smini;
+		ui22 = 0.;
+		*info = 1;
+	    }
+	    if (rswap[icmax - 1]) {
+		br2 = b[b_dim1 + 1];
+		br1 = b[b_dim1 + 2];
+		bi2 = b[(b_dim1 << 1) + 1];
+		bi1 = b[(b_dim1 << 1) + 2];
+	    } else {
+		br1 = b[b_dim1 + 1];
+		br2 = b[b_dim1 + 2];
+		bi1 = b[(b_dim1 << 1) + 1];
+		bi2 = b[(b_dim1 << 1) + 2];
+	    }
+	    br2 = br2 - lr21 * br1 + li21 * bi1;
+	    bi2 = bi2 - li21 * br1 - lr21 * bi1;
+/* Computing MAX */
+	    d__1 = (abs(br1) + abs(bi1)) * (u22abs * (abs(ur11r) + abs(ui11r))
+		    ), d__2 = abs(br2) + abs(bi2);
+	    bbnd = max(d__1,d__2);
+	    if (bbnd > 1. && u22abs < 1.) {
+		if (bbnd >= bignum * u22abs) {
+		    *scale = 1. / bbnd;
+		    br1 = *scale * br1;
+		    bi1 = *scale * bi1;
+		    br2 = *scale * br2;
+		    bi2 = *scale * bi2;
+		}
+	    }
+
+	    igraphdladiv_(&br2, &bi2, &ur22, &ui22, &xr2, &xi2);
+	    xr1 = ur11r * br1 - ui11r * bi1 - ur12s * xr2 + ui12s * xi2;
+	    xi1 = ui11r * br1 + ur11r * bi1 - ui12s * xr2 - ur12s * xi2;
+	    if (zswap[icmax - 1]) {
+		x[x_dim1 + 1] = xr2;
+		x[x_dim1 + 2] = xr1;
+		x[(x_dim1 << 1) + 1] = xi2;
+		x[(x_dim1 << 1) + 2] = xi1;
+	    } else {
+		x[x_dim1 + 1] = xr1;
+		x[x_dim1 + 2] = xr2;
+		x[(x_dim1 << 1) + 1] = xi1;
+		x[(x_dim1 << 1) + 2] = xi2;
+	    }
+/* Computing MAX */
+	    d__1 = abs(xr1) + abs(xi1), d__2 = abs(xr2) + abs(xi2);
+	    *xnorm = max(d__1,d__2);
+
+/*           Further scaling if  norm(A) norm(X) > overflow */
+
+	    if (*xnorm > 1. && cmax > 1.) {
+		if (*xnorm > bignum / cmax) {
+		    temp = cmax / bignum;
+		    x[x_dim1 + 1] = temp * x[x_dim1 + 1];
+		    x[x_dim1 + 2] = temp * x[x_dim1 + 2];
+		    x[(x_dim1 << 1) + 1] = temp * x[(x_dim1 << 1) + 1];
+		    x[(x_dim1 << 1) + 2] = temp * x[(x_dim1 << 1) + 2];
+		    *xnorm = temp * *xnorm;
+		    *scale = temp * *scale;
+		}
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DLALN2 */
+
+} /* igraphdlaln2_ */
+
+#undef crv
+#undef civ
+#undef cr
+#undef ci
+
+
diff --git a/src/lapack/dlamch.c b/src/lapack/dlamch.c
new file mode 100644
index 0000000..fb30aec
--- /dev/null
+++ b/src/lapack/dlamch.c
@@ -0,0 +1,169 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b2 = 0.;
+
+doublereal igraphdlamch_(char *cmach)
+{
+    /* System generated locals */
+    doublereal ret_val;
+
+    /* Local variables */
+    extern doublereal radixdbl_(doublereal *), digitsdbl_(doublereal *), 
+	    epsilondbl_(doublereal *);
+    doublereal rnd, eps, rmach;
+    extern logical igraphlsame_(char *, char *);
+    doublereal small, sfmin;
+    extern integer minexponentdbl_(doublereal *), maxexponentdbl_(doublereal *
+	    );
+    extern doublereal hugedbl_(doublereal *), tinydbl_(doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.0) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       Based on LAPACK DLAMCH but with Fortran 95 query functions   
+       See: http://www.cs.utk.edu/~luszczek/lapack/lamch.html   
+       and  http://www.netlib.org/lapack-dev/lapack-coding/program-style.html#id2537289   
+       July 2010   
+
+
+    Purpose   
+    =======   
+
+    DLAMCH determines double precision machine parameters.   
+
+    Arguments   
+    =========   
+
+    CMACH   (input) CHARACTER*1   
+            Specifies the value to be returned by DLAMCH:   
+            = 'E' or 'e',   DLAMCH := eps   
+            = 'S' or 's ,   DLAMCH := sfmin   
+            = 'B' or 'b',   DLAMCH := base   
+            = 'P' or 'p',   DLAMCH := eps*base   
+            = 'N' or 'n',   DLAMCH := t   
+            = 'R' or 'r',   DLAMCH := rnd   
+            = 'M' or 'm',   DLAMCH := emin   
+            = 'U' or 'u',   DLAMCH := rmin   
+            = 'L' or 'l',   DLAMCH := emax   
+            = 'O' or 'o',   DLAMCH := rmax   
+
+            where   
+
+            eps   = relative machine precision   
+            sfmin = safe minimum, such that 1/sfmin does not overflow   
+            base  = base of the machine   
+            prec  = eps*base   
+            t     = number of (base) digits in the mantissa   
+            rnd   = 1.0 when rounding occurs in addition, 0.0 otherwise   
+            emin  = minimum exponent before (gradual) underflow   
+            rmin  = underflow threshold - base**(emin-1)   
+            emax  = largest exponent before overflow   
+            rmax  = overflow threshold  - (base**emax)*(1-eps)   
+
+   =====================================================================   
+
+
+
+       Assume rounding, not chopping. Always. */
+
+    rnd = 1.;
+
+    if (1. == rnd) {
+	eps = epsilondbl_(&c_b2) * .5f;
+    } else {
+	eps = epsilondbl_(&c_b2);
+    }
+
+    if (igraphlsame_(cmach, "E")) {
+	rmach = eps;
+    } else if (igraphlsame_(cmach, "S")) {
+	sfmin = tinydbl_(&c_b2);
+	small = 1. / hugedbl_(&c_b2);
+	if (small >= sfmin) {
+
+/*           Use SMALL plus a bit, to avoid the possibility of rounding   
+             causing overflow when computing  1/sfmin. */
+
+	    sfmin = small * (eps + 1.);
+	}
+	rmach = sfmin;
+    } else if (igraphlsame_(cmach, "B")) {
+	rmach = radixdbl_(&c_b2);
+    } else if (igraphlsame_(cmach, "P")) {
+	rmach = eps * radixdbl_(&c_b2);
+    } else if (igraphlsame_(cmach, "N")) {
+	rmach = digitsdbl_(&c_b2);
+    } else if (igraphlsame_(cmach, "R")) {
+	rmach = rnd;
+    } else if (igraphlsame_(cmach, "M")) {
+	rmach = (doublereal) minexponentdbl_(&c_b2);
+    } else if (igraphlsame_(cmach, "U")) {
+	rmach = tinydbl_(&c_b2);
+    } else if (igraphlsame_(cmach, "L")) {
+	rmach = (doublereal) maxexponentdbl_(&c_b2);
+    } else if (igraphlsame_(cmach, "O")) {
+	rmach = hugedbl_(&c_b2);
+    } else {
+	rmach = 0.;
+    }
+
+    ret_val = rmach;
+    return ret_val;
+
+/*     End of DLAMCH */
+
+} /* igraphdlamch_   
+
+   *********************************************************************** */
+
+doublereal igraphdlamc3_(doublereal *a, doublereal *b)
+{
+    /* System generated locals */
+    doublereal ret_val;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.0) --   
+       Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..   
+       November 2010   
+
+
+    Purpose   
+    =======   
+
+    DLAMC3  is intended to force  A  and  B  to be stored prior to doing   
+    the addition of  A  and  B ,  for use in situations where optimizers   
+    might hold one of these in a register.   
+
+    Arguments   
+    =========   
+
+    A       (input) DOUBLE PRECISION   
+    B       (input) DOUBLE PRECISION   
+            The values A and B.   
+
+   ===================================================================== */
+
+
+    ret_val = *a + *b;
+
+    return ret_val;
+
+/*     End of DLAMC3 */
+
+} /* igraphdlamc3_ */
+
diff --git a/src/lapack/dlaneg.c b/src/lapack/dlaneg.c
new file mode 100644
index 0000000..fde7e0b
--- /dev/null
+++ b/src/lapack/dlaneg.c
@@ -0,0 +1,206 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+integer igraphdlaneg_(integer *n, doublereal *d__, doublereal *lld, doublereal *
+	sigma, doublereal *pivmin, integer *r__)
+{
+    /* System generated locals */
+    integer ret_val, i__1, i__2, i__3, i__4;
+
+    /* Local variables */
+    integer j;
+    doublereal p, t;
+    integer bj;
+    doublereal tmp;
+    integer neg1, neg2;
+    doublereal bsav, gamma, dplus;
+    extern logical igraphdisnan_(doublereal *);
+    integer negcnt;
+    logical sawnan;
+    doublereal dminus;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    DLANEG computes the Sturm count, the number of negative pivots   
+    encountered while factoring tridiagonal T - sigma I = L D L^T.   
+    This implementation works directly on the factors without forming   
+    the tridiagonal matrix T.  The Sturm count is also the number of   
+    eigenvalues of T less than sigma.   
+
+    This routine is called from DLARRB.   
+
+    The current routine does not use the PIVMIN parameter but rather   
+    requires IEEE-754 propagation of Infinities and NaNs.  This   
+    routine also has no input range restrictions but does require   
+    default exception handling such that x/0 produces Inf when x is   
+    non-zero, and Inf/Inf produces NaN.  For more information, see:   
+
+      Marques, Riedy, and Voemel, "Benefits of IEEE-754 Features in   
+      Modern Symmetric Tridiagonal Eigensolvers," SIAM Journal on   
+      Scientific Computing, v28, n5, 2006.  DOI 10.1137/050641624   
+      (Tech report version in LAWN 172 with the same title.)   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The N diagonal elements of the diagonal matrix D.   
+
+    LLD     (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (N-1) elements L(i)*L(i)*D(i).   
+
+    SIGMA   (input) DOUBLE PRECISION   
+            Shift amount in T - sigma I = L D L^T.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot in the Sturm sequence.  May be used   
+            when zero pivots are encountered on non-IEEE-754   
+            architectures.   
+
+    R       (input) INTEGER   
+            The twist index for the twisted factorization that is used   
+            for the negcount.   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+       Jason Riedy, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+       Some architectures propagate Infinities and NaNs very slowly, so   
+       the code computes counts in BLKLEN chunks.  Then a NaN can   
+       propagate at most BLKLEN columns before being detected.  This is   
+       not a general tuning parameter; it needs only to be just large   
+       enough that the overhead is tiny in common cases.   
+       Parameter adjustments */
+    --lld;
+    --d__;
+
+    /* Function Body */
+    negcnt = 0;
+/*     I) upper part: L D L^T - SIGMA I = L+ D+ L+^T */
+    t = -(*sigma);
+    i__1 = *r__ - 1;
+    for (bj = 1; bj <= i__1; bj += 128) {
+	neg1 = 0;
+	bsav = t;
+/* Computing MIN */
+	i__3 = bj + 127, i__4 = *r__ - 1;
+	i__2 = min(i__3,i__4);
+	for (j = bj; j <= i__2; ++j) {
+	    dplus = d__[j] + t;
+	    if (dplus < 0.) {
+		++neg1;
+	    }
+	    tmp = t / dplus;
+	    t = tmp * lld[j] - *sigma;
+/* L21: */
+	}
+	sawnan = igraphdisnan_(&t);
+/*     Run a slower version of the above loop if a NaN is detected.   
+       A NaN should occur only with a zero pivot after an infinite   
+       pivot.  In that case, substituting 1 for T/DPLUS is the   
+       correct limit. */
+	if (sawnan) {
+	    neg1 = 0;
+	    t = bsav;
+/* Computing MIN */
+	    i__3 = bj + 127, i__4 = *r__ - 1;
+	    i__2 = min(i__3,i__4);
+	    for (j = bj; j <= i__2; ++j) {
+		dplus = d__[j] + t;
+		if (dplus < 0.) {
+		    ++neg1;
+		}
+		tmp = t / dplus;
+		if (igraphdisnan_(&tmp)) {
+		    tmp = 1.;
+		}
+		t = tmp * lld[j] - *sigma;
+/* L22: */
+	    }
+	}
+	negcnt += neg1;
+/* L210: */
+    }
+
+/*     II) lower part: L D L^T - SIGMA I = U- D- U-^T */
+    p = d__[*n] - *sigma;
+    i__1 = *r__;
+    for (bj = *n - 1; bj >= i__1; bj += -128) {
+	neg2 = 0;
+	bsav = p;
+/* Computing MAX */
+	i__3 = bj - 127;
+	i__2 = max(i__3,*r__);
+	for (j = bj; j >= i__2; --j) {
+	    dminus = lld[j] + p;
+	    if (dminus < 0.) {
+		++neg2;
+	    }
+	    tmp = p / dminus;
+	    p = tmp * d__[j] - *sigma;
+/* L23: */
+	}
+	sawnan = igraphdisnan_(&p);
+/*     As above, run a slower version that substitutes 1 for Inf/Inf. */
+
+	if (sawnan) {
+	    neg2 = 0;
+	    p = bsav;
+/* Computing MAX */
+	    i__3 = bj - 127;
+	    i__2 = max(i__3,*r__);
+	    for (j = bj; j >= i__2; --j) {
+		dminus = lld[j] + p;
+		if (dminus < 0.) {
+		    ++neg2;
+		}
+		tmp = p / dminus;
+		if (igraphdisnan_(&tmp)) {
+		    tmp = 1.;
+		}
+		p = tmp * d__[j] - *sigma;
+/* L24: */
+	    }
+	}
+	negcnt += neg2;
+/* L230: */
+    }
+
+/*     III) Twist index   
+         T was shifted by SIGMA initially. */
+    gamma = t + *sigma + p;
+    if (gamma < 0.) {
+	++negcnt;
+    }
+    ret_val = negcnt;
+    return ret_val;
+} /* igraphdlaneg_ */
+
diff --git a/src/lapack/dlange.c b/src/lapack/dlange.c
new file mode 100644
index 0000000..57221aa
--- /dev/null
+++ b/src/lapack/dlange.c
@@ -0,0 +1,185 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+doublereal igraphdlange_(char *norm, integer *m, integer *n, doublereal *a, integer 
+	*lda, doublereal *work)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+    doublereal ret_val, d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j;
+    doublereal sum, scale;
+    extern logical igraphlsame_(char *, char *);
+    doublereal value;
+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLANGE  returns the value of the one norm,  or the Frobenius norm, or   
+    the  infinity norm,  or the  element of  largest absolute value  of a   
+    real matrix A.   
+
+    Description   
+    ===========   
+
+    DLANGE returns the value   
+
+       DLANGE = ( max(abs(A(i,j))), NORM = 'M' or 'm'   
+                (   
+                ( norm1(A),         NORM = '1', 'O' or 'o'   
+                (   
+                ( normI(A),         NORM = 'I' or 'i'   
+                (   
+                ( normF(A),         NORM = 'F', 'f', 'E' or 'e'   
+
+    where  norm1  denotes the  one norm of a matrix (maximum column sum),   
+    normI  denotes the  infinity norm  of a matrix  (maximum row sum) and   
+    normF  denotes the  Frobenius norm of a matrix (square root of sum of   
+    squares).  Note that  max(abs(A(i,j)))  is not a consistent matrix norm.   
+
+    Arguments   
+    =========   
+
+    NORM    (input) CHARACTER*1   
+            Specifies the value to be returned in DLANGE as described   
+            above.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.  When M = 0,   
+            DLANGE is set to zero.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.  When N = 0,   
+            DLANGE is set to zero.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The m by n matrix A.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(M,1).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)),   
+            where LWORK >= M when NORM = 'I'; otherwise, WORK is not   
+            referenced.   
+
+   =====================================================================   
+
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --work;
+
+    /* Function Body */
+    if (min(*m,*n) == 0) {
+	value = 0.;
+    } else if (igraphlsame_(norm, "M")) {
+
+/*        Find max(abs(A(i,j))). */
+
+	value = 0.;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+/* Computing MAX */
+		d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs(d__1));
+		value = max(d__2,d__3);
+/* L10: */
+	    }
+/* L20: */
+	}
+    } else if (igraphlsame_(norm, "O") || *(unsigned char *)
+	    norm == '1') {
+
+/*        Find norm1(A). */
+
+	value = 0.;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = 0.;
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		sum += (d__1 = a[i__ + j * a_dim1], abs(d__1));
+/* L30: */
+	    }
+	    value = max(value,sum);
+/* L40: */
+	}
+    } else if (igraphlsame_(norm, "I")) {
+
+/*        Find normI(A). */
+
+	i__1 = *m;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    work[i__] = 0.;
+/* L50: */
+	}
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1));
+/* L60: */
+	    }
+/* L70: */
+	}
+	value = 0.;
+	i__1 = *m;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing MAX */
+	    d__1 = value, d__2 = work[i__];
+	    value = max(d__1,d__2);
+/* L80: */
+	}
+    } else if (igraphlsame_(norm, "F") || igraphlsame_(norm, "E")) {
+
+/*        Find normF(A). */
+
+	scale = 0.;
+	sum = 1.;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    igraphdlassq_(m, &a[j * a_dim1 + 1], &c__1, &scale, &sum);
+/* L90: */
+	}
+	value = scale * sqrt(sum);
+    }
+
+    ret_val = value;
+    return ret_val;
+
+/*     End of DLANGE */
+
+} /* igraphdlange_ */
+
diff --git a/src/lapack/dlanhs.c b/src/lapack/dlanhs.c
new file mode 100644
index 0000000..2eba517
--- /dev/null
+++ b/src/lapack/dlanhs.c
@@ -0,0 +1,191 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+doublereal igraphdlanhs_(char *norm, integer *n, doublereal *a, integer *lda, 
+	doublereal *work)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3, i__4;
+    doublereal ret_val, d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j;
+    doublereal sum, scale;
+    extern logical igraphlsame_(char *, char *);
+    doublereal value;
+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLANHS  returns the value of the one norm,  or the Frobenius norm, or   
+    the  infinity norm,  or the  element of  largest absolute value  of a   
+    Hessenberg matrix A.   
+
+    Description   
+    ===========   
+
+    DLANHS returns the value   
+
+       DLANHS = ( max(abs(A(i,j))), NORM = 'M' or 'm'   
+                (   
+                ( norm1(A),         NORM = '1', 'O' or 'o'   
+                (   
+                ( normI(A),         NORM = 'I' or 'i'   
+                (   
+                ( normF(A),         NORM = 'F', 'f', 'E' or 'e'   
+
+    where  norm1  denotes the  one norm of a matrix (maximum column sum),   
+    normI  denotes the  infinity norm  of a matrix  (maximum row sum) and   
+    normF  denotes the  Frobenius norm of a matrix (square root of sum of   
+    squares).  Note that  max(abs(A(i,j)))  is not a consistent matrix norm.   
+
+    Arguments   
+    =========   
+
+    NORM    (input) CHARACTER*1   
+            Specifies the value to be returned in DLANHS as described   
+            above.   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.  When N = 0, DLANHS is   
+            set to zero.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The n by n upper Hessenberg matrix A; the part of A below the   
+            first sub-diagonal is not referenced.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(N,1).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)),   
+            where LWORK >= N when NORM = 'I'; otherwise, WORK is not   
+            referenced.   
+
+   =====================================================================   
+
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --work;
+
+    /* Function Body */
+    if (*n == 0) {
+	value = 0.;
+    } else if (igraphlsame_(norm, "M")) {
+
+/*        Find max(abs(A(i,j))). */
+
+	value = 0.;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MIN */
+	    i__3 = *n, i__4 = j + 1;
+	    i__2 = min(i__3,i__4);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+/* Computing MAX */
+		d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs(d__1));
+		value = max(d__2,d__3);
+/* L10: */
+	    }
+/* L20: */
+	}
+    } else if (igraphlsame_(norm, "O") || *(unsigned char *)
+	    norm == '1') {
+
+/*        Find norm1(A). */
+
+	value = 0.;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = 0.;
+/* Computing MIN */
+	    i__3 = *n, i__4 = j + 1;
+	    i__2 = min(i__3,i__4);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		sum += (d__1 = a[i__ + j * a_dim1], abs(d__1));
+/* L30: */
+	    }
+	    value = max(value,sum);
+/* L40: */
+	}
+    } else if (igraphlsame_(norm, "I")) {
+
+/*        Find normI(A). */
+
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    work[i__] = 0.;
+/* L50: */
+	}
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MIN */
+	    i__3 = *n, i__4 = j + 1;
+	    i__2 = min(i__3,i__4);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1));
+/* L60: */
+	    }
+/* L70: */
+	}
+	value = 0.;
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing MAX */
+	    d__1 = value, d__2 = work[i__];
+	    value = max(d__1,d__2);
+/* L80: */
+	}
+    } else if (igraphlsame_(norm, "F") || igraphlsame_(norm, "E")) {
+
+/*        Find normF(A). */
+
+	scale = 0.;
+	sum = 1.;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MIN */
+	    i__3 = *n, i__4 = j + 1;
+	    i__2 = min(i__3,i__4);
+	    igraphdlassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum);
+/* L90: */
+	}
+	value = scale * sqrt(sum);
+    }
+
+    ret_val = value;
+    return ret_val;
+
+/*     End of DLANHS */
+
+} /* igraphdlanhs_ */
+
diff --git a/src/lapack/dlanst.c b/src/lapack/dlanst.c
new file mode 100644
index 0000000..b3ef7e0
--- /dev/null
+++ b/src/lapack/dlanst.c
@@ -0,0 +1,152 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+doublereal igraphdlanst_(char *norm, integer *n, doublereal *d__, doublereal *e)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal ret_val, d__1, d__2, d__3, d__4, d__5;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal sum, scale;
+    extern logical igraphlsame_(char *, char *);
+    doublereal anorm;
+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLANST  returns the value of the one norm,  or the Frobenius norm, or   
+    the  infinity norm,  or the  element of  largest absolute value  of a   
+    real symmetric tridiagonal matrix A.   
+
+    Description   
+    ===========   
+
+    DLANST returns the value   
+
+       DLANST = ( max(abs(A(i,j))), NORM = 'M' or 'm'   
+                (   
+                ( norm1(A),         NORM = '1', 'O' or 'o'   
+                (   
+                ( normI(A),         NORM = 'I' or 'i'   
+                (   
+                ( normF(A),         NORM = 'F', 'f', 'E' or 'e'   
+
+    where  norm1  denotes the  one norm of a matrix (maximum column sum),   
+    normI  denotes the  infinity norm  of a matrix  (maximum row sum) and   
+    normF  denotes the  Frobenius norm of a matrix (square root of sum of   
+    squares).  Note that  max(abs(A(i,j)))  is not a consistent matrix norm.   
+
+    Arguments   
+    =========   
+
+    NORM    (input) CHARACTER*1   
+            Specifies the value to be returned in DLANST as described   
+            above.   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.  When N = 0, DLANST is   
+            set to zero.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The diagonal elements of A.   
+
+    E       (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (n-1) sub-diagonal or super-diagonal elements of A.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --e;
+    --d__;
+
+    /* Function Body */
+    if (*n <= 0) {
+	anorm = 0.;
+    } else if (igraphlsame_(norm, "M")) {
+
+/*        Find max(abs(A(i,j))). */
+
+	anorm = (d__1 = d__[*n], abs(d__1));
+	i__1 = *n - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing MAX */
+	    d__2 = anorm, d__3 = (d__1 = d__[i__], abs(d__1));
+	    anorm = max(d__2,d__3);
+/* Computing MAX */
+	    d__2 = anorm, d__3 = (d__1 = e[i__], abs(d__1));
+	    anorm = max(d__2,d__3);
+/* L10: */
+	}
+    } else if (igraphlsame_(norm, "O") || *(unsigned char *)
+	    norm == '1' || igraphlsame_(norm, "I")) {
+
+/*        Find norm1(A). */
+
+	if (*n == 1) {
+	    anorm = abs(d__[1]);
+	} else {
+/* Computing MAX */
+	    d__3 = abs(d__[1]) + abs(e[1]), d__4 = (d__1 = e[*n - 1], abs(
+		    d__1)) + (d__2 = d__[*n], abs(d__2));
+	    anorm = max(d__3,d__4);
+	    i__1 = *n - 1;
+	    for (i__ = 2; i__ <= i__1; ++i__) {
+/* Computing MAX */
+		d__4 = anorm, d__5 = (d__1 = d__[i__], abs(d__1)) + (d__2 = e[
+			i__], abs(d__2)) + (d__3 = e[i__ - 1], abs(d__3));
+		anorm = max(d__4,d__5);
+/* L20: */
+	    }
+	}
+    } else if (igraphlsame_(norm, "F") || igraphlsame_(norm, "E")) {
+
+/*        Find normF(A). */
+
+	scale = 0.;
+	sum = 1.;
+	if (*n > 1) {
+	    i__1 = *n - 1;
+	    igraphdlassq_(&i__1, &e[1], &c__1, &scale, &sum);
+	    sum *= 2;
+	}
+	igraphdlassq_(n, &d__[1], &c__1, &scale, &sum);
+	anorm = scale * sqrt(sum);
+    }
+
+    ret_val = anorm;
+    return ret_val;
+
+/*     End of DLANST */
+
+} /* igraphdlanst_ */
+
diff --git a/src/lapack/dlansy.c b/src/lapack/dlansy.c
new file mode 100644
index 0000000..5c15520
--- /dev/null
+++ b/src/lapack/dlansy.c
@@ -0,0 +1,225 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+doublereal igraphdlansy_(char *norm, char *uplo, integer *n, doublereal *a, integer 
+	*lda, doublereal *work)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+    doublereal ret_val, d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j;
+    doublereal sum, absa, scale;
+    extern logical igraphlsame_(char *, char *);
+    doublereal value;
+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLANSY  returns the value of the one norm,  or the Frobenius norm, or   
+    the  infinity norm,  or the  element of  largest absolute value  of a   
+    real symmetric matrix A.   
+
+    Description   
+    ===========   
+
+    DLANSY returns the value   
+
+       DLANSY = ( max(abs(A(i,j))), NORM = 'M' or 'm'   
+                (   
+                ( norm1(A),         NORM = '1', 'O' or 'o'   
+                (   
+                ( normI(A),         NORM = 'I' or 'i'   
+                (   
+                ( normF(A),         NORM = 'F', 'f', 'E' or 'e'   
+
+    where  norm1  denotes the  one norm of a matrix (maximum column sum),   
+    normI  denotes the  infinity norm  of a matrix  (maximum row sum) and   
+    normF  denotes the  Frobenius norm of a matrix (square root of sum of   
+    squares).  Note that  max(abs(A(i,j)))  is not a consistent matrix norm.   
+
+    Arguments   
+    =========   
+
+    NORM    (input) CHARACTER*1   
+            Specifies the value to be returned in DLANSY as described   
+            above.   
+
+    UPLO    (input) CHARACTER*1   
+            Specifies whether the upper or lower triangular part of the   
+            symmetric matrix A is to be referenced.   
+            = 'U':  Upper triangular part of A is referenced   
+            = 'L':  Lower triangular part of A is referenced   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.  When N = 0, DLANSY is   
+            set to zero.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The symmetric matrix A.  If UPLO = 'U', the leading n by n   
+            upper triangular part of A contains the upper triangular part   
+            of the matrix A, and the strictly lower triangular part of A   
+            is not referenced.  If UPLO = 'L', the leading n by n lower   
+            triangular part of A contains the lower triangular part of   
+            the matrix A, and the strictly upper triangular part of A is   
+            not referenced.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(N,1).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)),   
+            where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise,   
+            WORK is not referenced.   
+
+   =====================================================================   
+
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --work;
+
+    /* Function Body */
+    if (*n == 0) {
+	value = 0.;
+    } else if (igraphlsame_(norm, "M")) {
+
+/*        Find max(abs(A(i,j))). */
+
+	value = 0.;
+	if (igraphlsame_(uplo, "U")) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = j;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+/* Computing MAX */
+		    d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs(
+			    d__1));
+		    value = max(d__2,d__3);
+/* L10: */
+		}
+/* L20: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *n;
+		for (i__ = j; i__ <= i__2; ++i__) {
+/* Computing MAX */
+		    d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs(
+			    d__1));
+		    value = max(d__2,d__3);
+/* L30: */
+		}
+/* L40: */
+	    }
+	}
+    } else if (igraphlsame_(norm, "I") || igraphlsame_(norm, "O") || *(unsigned char *)norm == '1') {
+
+/*        Find normI(A) ( = norm1(A), since A is symmetric). */
+
+	value = 0.;
+	if (igraphlsame_(uplo, "U")) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		sum = 0.;
+		i__2 = j - 1;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    absa = (d__1 = a[i__ + j * a_dim1], abs(d__1));
+		    sum += absa;
+		    work[i__] += absa;
+/* L50: */
+		}
+		work[j] = sum + (d__1 = a[j + j * a_dim1], abs(d__1));
+/* L60: */
+	    }
+	    i__1 = *n;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing MAX */
+		d__1 = value, d__2 = work[i__];
+		value = max(d__1,d__2);
+/* L70: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		work[i__] = 0.;
+/* L80: */
+	    }
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		sum = work[j] + (d__1 = a[j + j * a_dim1], abs(d__1));
+		i__2 = *n;
+		for (i__ = j + 1; i__ <= i__2; ++i__) {
+		    absa = (d__1 = a[i__ + j * a_dim1], abs(d__1));
+		    sum += absa;
+		    work[i__] += absa;
+/* L90: */
+		}
+		value = max(value,sum);
+/* L100: */
+	    }
+	}
+    } else if (igraphlsame_(norm, "F") || igraphlsame_(norm, "E")) {
+
+/*        Find normF(A). */
+
+	scale = 0.;
+	sum = 1.;
+	if (igraphlsame_(uplo, "U")) {
+	    i__1 = *n;
+	    for (j = 2; j <= i__1; ++j) {
+		i__2 = j - 1;
+		igraphdlassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum);
+/* L110: */
+	    }
+	} else {
+	    i__1 = *n - 1;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *n - j;
+		igraphdlassq_(&i__2, &a[j + 1 + j * a_dim1], &c__1, &scale, &sum);
+/* L120: */
+	    }
+	}
+	sum *= 2;
+	i__1 = *lda + 1;
+	igraphdlassq_(n, &a[a_offset], &i__1, &scale, &sum);
+	value = scale * sqrt(sum);
+    }
+
+    ret_val = value;
+    return ret_val;
+
+/*     End of DLANSY */
+
+} /* igraphdlansy_ */
+
diff --git a/src/lapack/dlanv2.c b/src/lapack/dlanv2.c
new file mode 100644
index 0000000..5b4a241
--- /dev/null
+++ b/src/lapack/dlanv2.c
@@ -0,0 +1,225 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b4 = 1.;
+
+/* Subroutine */ int igraphdlanv2_(doublereal *a, doublereal *b, doublereal *c__, 
+	doublereal *d__, doublereal *rt1r, doublereal *rt1i, doublereal *rt2r,
+	 doublereal *rt2i, doublereal *cs, doublereal *sn)
+{
+    /* System generated locals */
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double d_sign(doublereal *, doublereal *), sqrt(doublereal);
+
+    /* Local variables */
+    doublereal p, z__, aa, bb, cc, dd, cs1, sn1, sab, sac, eps, tau, temp, 
+	    scale, bcmax, bcmis, sigma;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *), igraphdlamch_(char *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    DLANV2 computes the Schur factorization of a real 2-by-2 nonsymmetric   
+    matrix in standard form:   
+
+         [ A  B ] = [ CS -SN ] [ AA  BB ] [ CS  SN ]   
+         [ C  D ]   [ SN  CS ] [ CC  DD ] [-SN  CS ]   
+
+    where either   
+    1) CC = 0 so that AA and DD are real eigenvalues of the matrix, or   
+    2) AA = DD and BB*CC < 0, so that AA + or - sqrt(BB*CC) are complex   
+    conjugate eigenvalues.   
+
+    Arguments   
+    =========   
+
+    A       (input/output) DOUBLE PRECISION   
+    B       (input/output) DOUBLE PRECISION   
+    C       (input/output) DOUBLE PRECISION   
+    D       (input/output) DOUBLE PRECISION   
+            On entry, the elements of the input matrix.   
+            On exit, they are overwritten by the elements of the   
+            standardised Schur form.   
+
+    RT1R    (output) DOUBLE PRECISION   
+    RT1I    (output) DOUBLE PRECISION   
+    RT2R    (output) DOUBLE PRECISION   
+    RT2I    (output) DOUBLE PRECISION   
+            The real and imaginary parts of the eigenvalues. If the   
+            eigenvalues are a complex conjugate pair, RT1I > 0.   
+
+    CS      (output) DOUBLE PRECISION   
+    SN      (output) DOUBLE PRECISION   
+            Parameters of the rotation matrix.   
+
+    Further Details   
+    ===============   
+
+    Modified by V. Sima, Research Institute for Informatics, Bucharest,   
+    Romania, to reduce the risk of cancellation errors,   
+    when computing real eigenvalues, and to ensure, if possible, that   
+    abs(RT1R) >= abs(RT2R).   
+
+    ===================================================================== */
+
+
+    eps = igraphdlamch_("P");
+    if (*c__ == 0.) {
+	*cs = 1.;
+	*sn = 0.;
+	goto L10;
+
+    } else if (*b == 0.) {
+
+/*        Swap rows and columns */
+
+	*cs = 0.;
+	*sn = 1.;
+	temp = *d__;
+	*d__ = *a;
+	*a = temp;
+	*b = -(*c__);
+	*c__ = 0.;
+	goto L10;
+    } else if (*a - *d__ == 0. && d_sign(&c_b4, b) != d_sign(&c_b4, c__)) {
+	*cs = 1.;
+	*sn = 0.;
+	goto L10;
+    } else {
+
+	temp = *a - *d__;
+	p = temp * .5;
+/* Computing MAX */
+	d__1 = abs(*b), d__2 = abs(*c__);
+	bcmax = max(d__1,d__2);
+/* Computing MIN */
+	d__1 = abs(*b), d__2 = abs(*c__);
+	bcmis = min(d__1,d__2) * d_sign(&c_b4, b) * d_sign(&c_b4, c__);
+/* Computing MAX */
+	d__1 = abs(p);
+	scale = max(d__1,bcmax);
+	z__ = p / scale * p + bcmax / scale * bcmis;
+
+/*        If Z is of the order of the machine accuracy, postpone the   
+          decision on the nature of eigenvalues */
+
+	if (z__ >= eps * 4.) {
+
+/*           Real eigenvalues. Compute A and D. */
+
+	    d__1 = sqrt(scale) * sqrt(z__);
+	    z__ = p + d_sign(&d__1, &p);
+	    *a = *d__ + z__;
+	    *d__ -= bcmax / z__ * bcmis;
+
+/*           Compute B and the rotation matrix */
+
+	    tau = igraphdlapy2_(c__, &z__);
+	    *cs = z__ / tau;
+	    *sn = *c__ / tau;
+	    *b -= *c__;
+	    *c__ = 0.;
+	} else {
+
+/*           Complex eigenvalues, or real (almost) equal eigenvalues.   
+             Make diagonal elements equal. */
+
+	    sigma = *b + *c__;
+	    tau = igraphdlapy2_(&sigma, &temp);
+	    *cs = sqrt((abs(sigma) / tau + 1.) * .5);
+	    *sn = -(p / (tau * *cs)) * d_sign(&c_b4, &sigma);
+
+/*           Compute [ AA  BB ] = [ A  B ] [ CS -SN ]   
+                     [ CC  DD ]   [ C  D ] [ SN  CS ] */
+
+	    aa = *a * *cs + *b * *sn;
+	    bb = -(*a) * *sn + *b * *cs;
+	    cc = *c__ * *cs + *d__ * *sn;
+	    dd = -(*c__) * *sn + *d__ * *cs;
+
+/*           Compute [ A  B ] = [ CS  SN ] [ AA  BB ]   
+                     [ C  D ]   [-SN  CS ] [ CC  DD ] */
+
+	    *a = aa * *cs + cc * *sn;
+	    *b = bb * *cs + dd * *sn;
+	    *c__ = -aa * *sn + cc * *cs;
+	    *d__ = -bb * *sn + dd * *cs;
+
+	    temp = (*a + *d__) * .5;
+	    *a = temp;
+	    *d__ = temp;
+
+	    if (*c__ != 0.) {
+		if (*b != 0.) {
+		    if (d_sign(&c_b4, b) == d_sign(&c_b4, c__)) {
+
+/*                    Real eigenvalues: reduce to upper triangular form */
+
+			sab = sqrt((abs(*b)));
+			sac = sqrt((abs(*c__)));
+			d__1 = sab * sac;
+			p = d_sign(&d__1, c__);
+			tau = 1. / sqrt((d__1 = *b + *c__, abs(d__1)));
+			*a = temp + p;
+			*d__ = temp - p;
+			*b -= *c__;
+			*c__ = 0.;
+			cs1 = sab * tau;
+			sn1 = sac * tau;
+			temp = *cs * cs1 - *sn * sn1;
+			*sn = *cs * sn1 + *sn * cs1;
+			*cs = temp;
+		    }
+		} else {
+		    *b = -(*c__);
+		    *c__ = 0.;
+		    temp = *cs;
+		    *cs = -(*sn);
+		    *sn = temp;
+		}
+	    }
+	}
+
+    }
+
+L10:
+
+/*     Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). */
+
+    *rt1r = *a;
+    *rt2r = *d__;
+    if (*c__ == 0.) {
+	*rt1i = 0.;
+	*rt2i = 0.;
+    } else {
+	*rt1i = sqrt((abs(*b))) * sqrt((abs(*c__)));
+	*rt2i = -(*rt1i);
+    }
+    return 0;
+
+/*     End of DLANV2 */
+
+} /* igraphdlanv2_ */
+
diff --git a/src/lapack/dlapy2.c b/src/lapack/dlapy2.c
new file mode 100644
index 0000000..4c40e45
--- /dev/null
+++ b/src/lapack/dlapy2.c
@@ -0,0 +1,65 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+doublereal igraphdlapy2_(doublereal *x, doublereal *y)
+{
+    /* System generated locals */
+    doublereal ret_val, d__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    doublereal w, z__, xabs, yabs;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLAPY2 returns sqrt(x**2+y**2), taking care not to cause unnecessary   
+    overflow.   
+
+    Arguments   
+    =========   
+
+    X       (input) DOUBLE PRECISION   
+    Y       (input) DOUBLE PRECISION   
+            X and Y specify the values x and y.   
+
+    ===================================================================== */
+
+
+    xabs = abs(*x);
+    yabs = abs(*y);
+    w = max(xabs,yabs);
+    z__ = min(xabs,yabs);
+    if (z__ == 0.) {
+	ret_val = w;
+    } else {
+/* Computing 2nd power */
+	d__1 = z__ / w;
+	ret_val = w * sqrt(d__1 * d__1 + 1.);
+    }
+    return ret_val;
+
+/*     End of DLAPY2 */
+
+} /* igraphdlapy2_ */
+
diff --git a/src/lapack/dlaqr0.c b/src/lapack/dlaqr0.c
new file mode 100644
index 0000000..0233a4c
--- /dev/null
+++ b/src/lapack/dlaqr0.c
@@ -0,0 +1,746 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__13 = 13;
+static integer c__15 = 15;
+static integer c_n1 = -1;
+static integer c__12 = 12;
+static integer c__14 = 14;
+static integer c__16 = 16;
+static logical c_false = FALSE_;
+static integer c__1 = 1;
+static integer c__3 = 3;
+
+/* Subroutine */ int igraphdlaqr0_(logical *wantt, logical *wantz, integer *n, 
+	integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal 
+	*wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, 
+	integer *ldz, doublereal *work, integer *lwork, integer *info)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5;
+    doublereal d__1, d__2, d__3, d__4;
+
+    /* Local variables */
+    integer i__, k;
+    doublereal aa, bb, cc, dd;
+    integer ld;
+    doublereal cs;
+    integer nh, it, ks, kt;
+    doublereal sn;
+    integer ku, kv, ls, ns;
+    doublereal ss;
+    integer nw, inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, kbot, 
+	    nmin;
+    doublereal swap;
+    integer ktop;
+    doublereal zdum[1]	/* was [1][1] */;
+    integer kacc22, itmax, nsmax, nwmax, kwtop;
+    extern /* Subroutine */ int igraphdlanv2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *), igraphdlaqr3_(
+	    logical *, logical *, integer *, integer *, integer *, integer *, 
+	    doublereal *, integer *, integer *, integer *, doublereal *, 
+	    integer *, integer *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *), 
+	    igraphdlaqr4_(logical *, logical *, integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *, 
+	    integer *), igraphdlaqr5_(logical *, logical *, integer *, integer *, 
+	    integer *, integer *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *, 
+	    integer *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *);
+    integer nibble;
+    extern /* Subroutine */ int igraphdlahqr_(logical *, logical *, integer *, 
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *), igraphdlacpy_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    char jbcmpz[2];
+    integer nwupbd;
+    logical sorted;
+    integer lwkopt;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+       November 2006   
+
+
+       Purpose   
+       =======   
+
+       DLAQR0 computes the eigenvalues of a Hessenberg matrix H   
+       and, optionally, the matrices T and Z from the Schur decomposition   
+       H = Z T Z**T, where T is an upper quasi-triangular matrix (the   
+       Schur form), and Z is the orthogonal matrix of Schur vectors.   
+
+       Optionally Z may be postmultiplied into an input orthogonal   
+       matrix Q so that this routine can give the Schur factorization   
+       of a matrix A which has been reduced to the Hessenberg form H   
+       by the orthogonal matrix Q:  A = Q*H*Q**T = (QZ)*T*(QZ)**T.   
+
+       Arguments   
+       =========   
+
+       WANTT   (input) LOGICAL   
+            = .TRUE. : the full Schur form T is required;   
+            = .FALSE.: only eigenvalues are required.   
+
+       WANTZ   (input) LOGICAL   
+            = .TRUE. : the matrix of Schur vectors Z is required;   
+            = .FALSE.: Schur vectors are not required.   
+
+       N     (input) INTEGER   
+             The order of the matrix H.  N .GE. 0.   
+
+       ILO   (input) INTEGER   
+       IHI   (input) INTEGER   
+             It is assumed that H is already upper triangular in rows   
+             and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1,   
+             H(ILO,ILO-1) is zero. ILO and IHI are normally set by a   
+             previous call to DGEBAL, and then passed to DGEHRD when the   
+             matrix output by DGEBAL is reduced to Hessenberg form.   
+             Otherwise, ILO and IHI should be set to 1 and N,   
+             respectively.  If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N.   
+             If N = 0, then ILO = 1 and IHI = 0.   
+
+       H     (input/output) DOUBLE PRECISION array, dimension (LDH,N)   
+             On entry, the upper Hessenberg matrix H.   
+             On exit, if INFO = 0 and WANTT is .TRUE., then H contains   
+             the upper quasi-triangular matrix T from the Schur   
+             decomposition (the Schur form); 2-by-2 diagonal blocks   
+             (corresponding to complex conjugate pairs of eigenvalues)   
+             are returned in standard form, with H(i,i) = H(i+1,i+1)   
+             and H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and WANTT is   
+             .FALSE., then the contents of H are unspecified on exit.   
+             (The output value of H when INFO.GT.0 is given under the   
+             description of INFO below.)   
+
+             This subroutine may explicitly set H(i,j) = 0 for i.GT.j and   
+             j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N.   
+
+       LDH   (input) INTEGER   
+             The leading dimension of the array H. LDH .GE. max(1,N).   
+
+       WR    (output) DOUBLE PRECISION array, dimension (IHI)   
+       WI    (output) DOUBLE PRECISION array, dimension (IHI)   
+             The real and imaginary parts, respectively, of the computed   
+             eigenvalues of H(ILO:IHI,ILO:IHI) are stored in WR(ILO:IHI)   
+             and WI(ILO:IHI). If two eigenvalues are computed as a   
+             complex conjugate pair, they are stored in consecutive   
+             elements of WR and WI, say the i-th and (i+1)th, with   
+             WI(i) .GT. 0 and WI(i+1) .LT. 0. If WANTT is .TRUE., then   
+             the eigenvalues are stored in the same order as on the   
+             diagonal of the Schur form returned in H, with   
+             WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal   
+             block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and   
+             WI(i+1) = -WI(i).   
+
+       ILOZ     (input) INTEGER   
+       IHIZ     (input) INTEGER   
+             Specify the rows of Z to which transformations must be   
+             applied if WANTZ is .TRUE..   
+             1 .LE. ILOZ .LE. ILO; IHI .LE. IHIZ .LE. N.   
+
+       Z     (input/output) DOUBLE PRECISION array, dimension (LDZ,IHI)   
+             If WANTZ is .FALSE., then Z is not referenced.   
+             If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is   
+             replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the   
+             orthogonal Schur factor of H(ILO:IHI,ILO:IHI).   
+             (The output value of Z when INFO.GT.0 is given under   
+             the description of INFO below.)   
+
+       LDZ   (input) INTEGER   
+             The leading dimension of the array Z.  if WANTZ is .TRUE.   
+             then LDZ.GE.MAX(1,IHIZ).  Otherwize, LDZ.GE.1.   
+
+       WORK  (workspace/output) DOUBLE PRECISION array, dimension LWORK   
+             On exit, if LWORK = -1, WORK(1) returns an estimate of   
+             the optimal value for LWORK.   
+
+       LWORK (input) INTEGER   
+             The dimension of the array WORK.  LWORK .GE. max(1,N)   
+             is sufficient, but LWORK typically as large as 6*N may   
+             be required for optimal performance.  A workspace query   
+             to determine the optimal workspace size is recommended.   
+
+             If LWORK = -1, then DLAQR0 does a workspace query.   
+             In this case, DLAQR0 checks the input parameters and   
+             estimates the optimal workspace size for the given   
+             values of N, ILO and IHI.  The estimate is returned   
+             in WORK(1).  No error message related to LWORK is   
+             issued by XERBLA.  Neither H nor Z are accessed.   
+
+
+       INFO  (output) INTEGER   
+               =  0:  successful exit   
+             .GT. 0:  if INFO = i, DLAQR0 failed to compute all of   
+                  the eigenvalues.  Elements 1:ilo-1 and i+1:n of WR   
+                  and WI contain those eigenvalues which have been   
+                  successfully computed.  (Failures are rare.)   
+
+                  If INFO .GT. 0 and WANT is .FALSE., then on exit,   
+                  the remaining unconverged eigenvalues are the eigen-   
+                  values of the upper Hessenberg matrix rows and   
+                  columns ILO through INFO of the final, output   
+                  value of H.   
+
+                  If INFO .GT. 0 and WANTT is .TRUE., then on exit   
+
+             (*)  (initial value of H)*U  = U*(final value of H)   
+
+                  where U is an orthogonal matrix.  The final   
+                  value of H is upper Hessenberg and quasi-triangular   
+                  in rows and columns INFO+1 through IHI.   
+
+                  If INFO .GT. 0 and WANTZ is .TRUE., then on exit   
+
+                    (final value of Z(ILO:IHI,ILOZ:IHIZ)   
+                     =  (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U   
+
+                  where U is the orthogonal matrix in (*) (regard-   
+                  less of the value of WANTT.)   
+
+                  If INFO .GT. 0 and WANTZ is .FALSE., then Z is not   
+                  accessed.   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+       References:   
+         K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+         Algorithm Part I: Maintaining Well Focused Shifts, and Level 3   
+         Performance, SIAM Journal of Matrix Analysis, volume 23, pages   
+         929--947, 2002.   
+
+         K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+         Algorithm Part II: Aggressive Early Deflation, SIAM Journal   
+         of Matrix Analysis, volume 23, pages 948--973, 2002.   
+
+       ================================================================   
+
+       ==== Matrices of order NTINY or smaller must be processed by   
+       .    DLAHQR because of insufficient subdiagonal scratch space.   
+       .    (This is a hard limit.) ====   
+
+       ==== Exceptional deflation windows:  try to cure rare   
+       .    slow convergence by varying the size of the   
+       .    deflation window after KEXNW iterations. ====   
+
+       ==== Exceptional shifts: try to cure rare slow convergence   
+       .    with ad-hoc exceptional shifts every KEXSH iterations.   
+       .    ====   
+
+       ==== The constants WILK1 and WILK2 are used to form the   
+       .    exceptional shifts. ====   
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --wr;
+    --wi;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+
+/*     ==== Quick return for N = 0: nothing to do. ==== */
+
+    if (*n == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    if (*n <= 11) {
+
+/*        ==== Tiny matrices must use DLAHQR. ==== */
+
+	lwkopt = 1;
+	if (*lwork != -1) {
+	    igraphdlahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], &
+		    wi[1], iloz, ihiz, &z__[z_offset], ldz, info);
+	}
+    } else {
+
+/*        ==== Use small bulge multi-shift QR with aggressive early   
+          .    deflation on larger-than-tiny matrices. ====   
+
+          ==== Hope for the best. ==== */
+
+	*info = 0;
+
+/*        ==== Set up job flags for ILAENV. ==== */
+
+	if (*wantt) {
+	    *(unsigned char *)jbcmpz = 'S';
+	} else {
+	    *(unsigned char *)jbcmpz = 'E';
+	}
+	if (*wantz) {
+	    *(unsigned char *)&jbcmpz[1] = 'V';
+	} else {
+	    *(unsigned char *)&jbcmpz[1] = 'N';
+	}
+
+/*        ==== NWR = recommended deflation window size.  At this   
+          .    point,  N .GT. NTINY = 11, so there is enough   
+          .    subdiagonal workspace for NWR.GE.2 as required.   
+          .    (In fact, there is enough subdiagonal space for   
+          .    NWR.GE.3.) ==== */
+
+	nwr = igraphilaenv_(&c__13, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6,
+		 (ftnlen)2);
+	nwr = max(2,nwr);
+/* Computing MIN */
+	i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2);
+	nwr = min(i__1,nwr);
+
+/*        ==== NSR = recommended number of simultaneous shifts.   
+          .    At this point N .GT. NTINY = 11, so there is at   
+          .    enough subdiagonal workspace for NSR to be even   
+          .    and greater than or equal to two as required. ==== */
+
+	nsr = igraphilaenv_(&c__15, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6,
+		 (ftnlen)2);
+/* Computing MIN */
+	i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - 
+		*ilo;
+	nsr = min(i__1,i__2);
+/* Computing MAX */
+	i__1 = 2, i__2 = nsr - nsr % 2;
+	nsr = max(i__1,i__2);
+
+/*        ==== Estimate optimal workspace ====   
+
+          ==== Workspace query call to DLAQR3 ==== */
+
+	i__1 = nwr + 1;
+	igraphdlaqr3_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, 
+		ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], &h__[
+		h_offset], ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], 
+		ldh, &work[1], &c_n1);
+
+/*        ==== Optimal workspace = MAX(DLAQR5, DLAQR3) ====   
+
+   Computing MAX */
+	i__1 = nsr * 3 / 2, i__2 = (integer) work[1];
+	lwkopt = max(i__1,i__2);
+
+/*        ==== Quick return in case of workspace query. ==== */
+
+	if (*lwork == -1) {
+	    work[1] = (doublereal) lwkopt;
+	    return 0;
+	}
+
+/*        ==== DLAHQR/DLAQR0 crossover point ==== */
+
+	nmin = igraphilaenv_(&c__12, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)
+		6, (ftnlen)2);
+	nmin = max(11,nmin);
+
+/*        ==== Nibble crossover point ==== */
+
+	nibble = igraphilaenv_(&c__14, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (
+		ftnlen)6, (ftnlen)2);
+	nibble = max(0,nibble);
+
+/*        ==== Accumulate reflections during ttswp?  Use block   
+          .    2-by-2 structure during matrix-matrix multiply? ==== */
+
+	kacc22 = igraphilaenv_(&c__16, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (
+		ftnlen)6, (ftnlen)2);
+	kacc22 = max(0,kacc22);
+	kacc22 = min(2,kacc22);
+
+/*        ==== NWMAX = the largest possible deflation window for   
+          .    which there is sufficient workspace. ====   
+
+   Computing MIN */
+	i__1 = (*n - 1) / 3, i__2 = *lwork / 2;
+	nwmax = min(i__1,i__2);
+	nw = nwmax;
+
+/*        ==== NSMAX = the Largest number of simultaneous shifts   
+          .    for which there is sufficient workspace. ====   
+
+   Computing MIN */
+	i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3;
+	nsmax = min(i__1,i__2);
+	nsmax -= nsmax % 2;
+
+/*        ==== NDFL: an iteration count restarted at deflation. ==== */
+
+	ndfl = 1;
+
+/*        ==== ITMAX = iteration limit ====   
+
+   Computing MAX */
+	i__1 = 10, i__2 = *ihi - *ilo + 1;
+	itmax = max(i__1,i__2) * 30;
+
+/*        ==== Last row and column in the active block ==== */
+
+	kbot = *ihi;
+
+/*        ==== Main Loop ==== */
+
+	i__1 = itmax;
+	for (it = 1; it <= i__1; ++it) {
+
+/*           ==== Done when KBOT falls below ILO ==== */
+
+	    if (kbot < *ilo) {
+		goto L90;
+	    }
+
+/*           ==== Locate active block ==== */
+
+	    i__2 = *ilo + 1;
+	    for (k = kbot; k >= i__2; --k) {
+		if (h__[k + (k - 1) * h_dim1] == 0.) {
+		    goto L20;
+		}
+/* L10: */
+	    }
+	    k = *ilo;
+L20:
+	    ktop = k;
+
+/*           ==== Select deflation window size:   
+             .    Typical Case:   
+             .      If possible and advisable, nibble the entire   
+             .      active block.  If not, use size MIN(NWR,NWMAX)   
+             .      or MIN(NWR+1,NWMAX) depending upon which has   
+             .      the smaller corresponding subdiagonal entry   
+             .      (a heuristic).   
+             .   
+             .    Exceptional Case:   
+             .      If there have been no deflations in KEXNW or   
+             .      more iterations, then vary the deflation window   
+             .      size.   At first, because, larger windows are,   
+             .      in general, more powerful than smaller ones,   
+             .      rapidly increase the window to the maximum possible.   
+             .      Then, gradually reduce the window size. ==== */
+
+	    nh = kbot - ktop + 1;
+	    nwupbd = min(nh,nwmax);
+	    if (ndfl < 5) {
+		nw = min(nwupbd,nwr);
+	    } else {
+/* Computing MIN */
+		i__2 = nwupbd, i__3 = nw << 1;
+		nw = min(i__2,i__3);
+	    }
+	    if (nw < nwmax) {
+		if (nw >= nh - 1) {
+		    nw = nh;
+		} else {
+		    kwtop = kbot - nw + 1;
+		    if ((d__1 = h__[kwtop + (kwtop - 1) * h_dim1], abs(d__1)) 
+			    > (d__2 = h__[kwtop - 1 + (kwtop - 2) * h_dim1], 
+			    abs(d__2))) {
+			++nw;
+		    }
+		}
+	    }
+	    if (ndfl < 5) {
+		ndec = -1;
+	    } else if (ndec >= 0 || nw >= nwupbd) {
+		++ndec;
+		if (nw - ndec < 2) {
+		    ndec = 0;
+		}
+		nw -= ndec;
+	    }
+
+/*           ==== Aggressive early deflation:   
+             .    split workspace under the subdiagonal into   
+             .      - an nw-by-nw work array V in the lower   
+             .        left-hand-corner,   
+             .      - an NW-by-at-least-NW-but-more-is-better   
+             .        (NW-by-NHO) horizontal work array along   
+             .        the bottom edge,   
+             .      - an at-least-NW-but-more-is-better (NHV-by-NW)   
+             .        vertical work array along the left-hand-edge.   
+             .        ==== */
+
+	    kv = *n - nw + 1;
+	    kt = nw + 1;
+	    nho = *n - nw - 1 - kt + 1;
+	    kwv = nw + 2;
+	    nve = *n - nw - kwv + 1;
+
+/*           ==== Aggressive early deflation ==== */
+
+	    igraphdlaqr3_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, 
+		    iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1],
+		     &h__[kv + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], 
+		    ldh, &nve, &h__[kwv + h_dim1], ldh, &work[1], lwork);
+
+/*           ==== Adjust KBOT accounting for new deflations. ==== */
+
+	    kbot -= ld;
+
+/*           ==== KS points to the shifts. ==== */
+
+	    ks = kbot - ls + 1;
+
+/*           ==== Skip an expensive QR sweep if there is a (partly   
+             .    heuristic) reason to expect that many eigenvalues   
+             .    will deflate without it.  Here, the QR sweep is   
+             .    skipped if many eigenvalues have just been deflated   
+             .    or if the remaining active block is small. */
+
+	    if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min(
+		    nmin,nwmax)) {
+
+/*              ==== NS = nominal number of simultaneous shifts.   
+                .    This may be lowered (slightly) if DLAQR3   
+                .    did not provide that many shifts. ====   
+
+   Computing MIN   
+   Computing MAX */
+		i__4 = 2, i__5 = kbot - ktop;
+		i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5);
+		ns = min(i__2,i__3);
+		ns -= ns % 2;
+
+/*              ==== If there have been no deflations   
+                .    in a multiple of KEXSH iterations,   
+                .    then try exceptional shifts.   
+                .    Otherwise use shifts provided by   
+                .    DLAQR3 above or from the eigenvalues   
+                .    of a trailing principal submatrix. ==== */
+
+		if (ndfl % 6 == 0) {
+		    ks = kbot - ns + 1;
+/* Computing MAX */
+		    i__3 = ks + 1, i__4 = ktop + 2;
+		    i__2 = max(i__3,i__4);
+		    for (i__ = kbot; i__ >= i__2; i__ += -2) {
+			ss = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1))
+				 + (d__2 = h__[i__ - 1 + (i__ - 2) * h_dim1], 
+				abs(d__2));
+			aa = ss * .75 + h__[i__ + i__ * h_dim1];
+			bb = ss;
+			cc = ss * -.4375;
+			dd = aa;
+			igraphdlanv2_(&aa, &bb, &cc, &dd, &wr[i__ - 1], &wi[i__ - 1]
+				, &wr[i__], &wi[i__], &cs, &sn);
+/* L30: */
+		    }
+		    if (ks == ktop) {
+			wr[ks + 1] = h__[ks + 1 + (ks + 1) * h_dim1];
+			wi[ks + 1] = 0.;
+			wr[ks] = wr[ks + 1];
+			wi[ks] = wi[ks + 1];
+		    }
+		} else {
+
+/*                 ==== Got NS/2 or fewer shifts? Use DLAQR4 or   
+                   .    DLAHQR on a trailing principal submatrix to   
+                   .    get more. (Since NS.LE.NSMAX.LE.(N+6)/9,   
+                   .    there is enough space below the subdiagonal   
+                   .    to fit an NS-by-NS scratch array.) ==== */
+
+		    if (kbot - ks + 1 <= ns / 2) {
+			ks = kbot - ns + 1;
+			kt = *n - ns + 1;
+			igraphdlacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, &
+				h__[kt + h_dim1], ldh);
+			if (ns > nmin) {
+			    igraphdlaqr4_(&c_false, &c_false, &ns, &c__1, &ns, &h__[
+				    kt + h_dim1], ldh, &wr[ks], &wi[ks], &
+				    c__1, &c__1, zdum, &c__1, &work[1], lwork,
+				     &inf);
+			} else {
+			    igraphdlahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[
+				    kt + h_dim1], ldh, &wr[ks], &wi[ks], &
+				    c__1, &c__1, zdum, &c__1, &inf);
+			}
+			ks += inf;
+
+/*                    ==== In case of a rare QR failure use   
+                      .    eigenvalues of the trailing 2-by-2   
+                      .    principal submatrix.  ==== */
+
+			if (ks >= kbot) {
+			    aa = h__[kbot - 1 + (kbot - 1) * h_dim1];
+			    cc = h__[kbot + (kbot - 1) * h_dim1];
+			    bb = h__[kbot - 1 + kbot * h_dim1];
+			    dd = h__[kbot + kbot * h_dim1];
+			    igraphdlanv2_(&aa, &bb, &cc, &dd, &wr[kbot - 1], &wi[
+				    kbot - 1], &wr[kbot], &wi[kbot], &cs, &sn)
+				    ;
+			    ks = kbot - 1;
+			}
+		    }
+
+		    if (kbot - ks + 1 > ns) {
+
+/*                    ==== Sort the shifts (Helps a little)   
+                      .    Bubble sort keeps complex conjugate   
+                      .    pairs together. ==== */
+
+			sorted = FALSE_;
+			i__2 = ks + 1;
+			for (k = kbot; k >= i__2; --k) {
+			    if (sorted) {
+				goto L60;
+			    }
+			    sorted = TRUE_;
+			    i__3 = k - 1;
+			    for (i__ = ks; i__ <= i__3; ++i__) {
+				if ((d__1 = wr[i__], abs(d__1)) + (d__2 = wi[
+					i__], abs(d__2)) < (d__3 = wr[i__ + 1]
+					, abs(d__3)) + (d__4 = wi[i__ + 1], 
+					abs(d__4))) {
+				    sorted = FALSE_;
+
+				    swap = wr[i__];
+				    wr[i__] = wr[i__ + 1];
+				    wr[i__ + 1] = swap;
+
+				    swap = wi[i__];
+				    wi[i__] = wi[i__ + 1];
+				    wi[i__ + 1] = swap;
+				}
+/* L40: */
+			    }
+/* L50: */
+			}
+L60:
+			;
+		    }
+
+/*                 ==== Shuffle shifts into pairs of real shifts   
+                   .    and pairs of complex conjugate shifts   
+                   .    assuming complex conjugate shifts are   
+                   .    already adjacent to one another. (Yes,   
+                   .    they are.)  ==== */
+
+		    i__2 = ks + 2;
+		    for (i__ = kbot; i__ >= i__2; i__ += -2) {
+			if (wi[i__] != -wi[i__ - 1]) {
+
+			    swap = wr[i__];
+			    wr[i__] = wr[i__ - 1];
+			    wr[i__ - 1] = wr[i__ - 2];
+			    wr[i__ - 2] = swap;
+
+			    swap = wi[i__];
+			    wi[i__] = wi[i__ - 1];
+			    wi[i__ - 1] = wi[i__ - 2];
+			    wi[i__ - 2] = swap;
+			}
+/* L70: */
+		    }
+		}
+
+/*              ==== If there are only two shifts and both are   
+                .    real, then use only one.  ==== */
+
+		if (kbot - ks + 1 == 2) {
+		    if (wi[kbot] == 0.) {
+			if ((d__1 = wr[kbot] - h__[kbot + kbot * h_dim1], abs(
+				d__1)) < (d__2 = wr[kbot - 1] - h__[kbot + 
+				kbot * h_dim1], abs(d__2))) {
+			    wr[kbot - 1] = wr[kbot];
+			} else {
+			    wr[kbot] = wr[kbot - 1];
+			}
+		    }
+		}
+
+/*              ==== Use up to NS of the the smallest magnatiude   
+                .    shifts.  If there aren't NS shifts available,   
+                .    then use them all, possibly dropping one to   
+                .    make the number of shifts even. ====   
+
+   Computing MIN */
+		i__2 = ns, i__3 = kbot - ks + 1;
+		ns = min(i__2,i__3);
+		ns -= ns % 2;
+		ks = kbot - ns + 1;
+
+/*              ==== Small-bulge multi-shift QR sweep:   
+                .    split workspace under the subdiagonal into   
+                .    - a KDU-by-KDU work array U in the lower   
+                .      left-hand-corner,   
+                .    - a KDU-by-at-least-KDU-but-more-is-better   
+                .      (KDU-by-NHo) horizontal work array WH along   
+                .      the bottom edge,   
+                .    - and an at-least-KDU-but-more-is-better-by-KDU   
+                .      (NVE-by-KDU) vertical work WV arrow along   
+                .      the left-hand-edge. ==== */
+
+		kdu = ns * 3 - 3;
+		ku = *n - kdu + 1;
+		kwh = kdu + 1;
+		nho = *n - kdu - 3 - (kdu + 1) + 1;
+		kwv = kdu + 4;
+		nve = *n - kdu - kwv + 1;
+
+/*              ==== Small-bulge multi-shift QR sweep ==== */
+
+		igraphdlaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &wr[ks], 
+			&wi[ks], &h__[h_offset], ldh, iloz, ihiz, &z__[
+			z_offset], ldz, &work[1], &c__3, &h__[ku + h_dim1], 
+			ldh, &nve, &h__[kwv + h_dim1], ldh, &nho, &h__[ku + 
+			kwh * h_dim1], ldh);
+	    }
+
+/*           ==== Note progress (or the lack of it). ==== */
+
+	    if (ld > 0) {
+		ndfl = 1;
+	    } else {
+		++ndfl;
+	    }
+
+/*           ==== End of main loop ====   
+   L80: */
+	}
+
+/*        ==== Iteration limit exceeded.  Set INFO to show where   
+          .    the problem occurred and exit. ==== */
+
+	*info = kbot;
+L90:
+	;
+    }
+
+/*     ==== Return the optimal value of LWORK. ==== */
+
+    work[1] = (doublereal) lwkopt;
+
+/*     ==== End of DLAQR0 ==== */
+
+    return 0;
+} /* igraphdlaqr0_ */
+
diff --git a/src/lapack/dlaqr1.c b/src/lapack/dlaqr1.c
new file mode 100644
index 0000000..b8297f7
--- /dev/null
+++ b/src/lapack/dlaqr1.c
@@ -0,0 +1,116 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaqr1_(integer *n, doublereal *h__, integer *ldh, 
+	doublereal *sr1, doublereal *si1, doublereal *sr2, doublereal *si2, 
+	doublereal *v)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset;
+    doublereal d__1, d__2, d__3;
+
+    /* Local variables */
+    doublereal s, h21s, h31s;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+       November 2006   
+
+
+         Given a 2-by-2 or 3-by-3 matrix H, DLAQR1 sets v to a   
+         scalar multiple of the first column of the product   
+
+         (*)  K = (H - (sr1 + i*si1)*I)*(H - (sr2 + i*si2)*I)   
+
+         scaling to avoid overflows and most underflows. It   
+         is assumed that either   
+
+                 1) sr1 = sr2 and si1 = -si2   
+             or   
+                 2) si1 = si2 = 0.   
+
+         This is useful for starting double implicit shift bulges   
+         in the QR algorithm.   
+
+
+         N      (input) integer   
+                Order of the matrix H. N must be either 2 or 3.   
+
+         H      (input) DOUBLE PRECISION array of dimension (LDH,N)   
+                The 2-by-2 or 3-by-3 matrix H in (*).   
+
+         LDH    (input) integer   
+                The leading dimension of H as declared in   
+                the calling procedure.  LDH.GE.N   
+
+         SR1    (input) DOUBLE PRECISION   
+         SI1    The shifts in (*).   
+         SR2   
+         SI2   
+
+         V      (output) DOUBLE PRECISION array of dimension N   
+                A scalar multiple of the first column of the   
+                matrix K in (*).   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --v;
+
+    /* Function Body */
+    if (*n == 2) {
+	s = (d__1 = h__[h_dim1 + 1] - *sr2, abs(d__1)) + abs(*si2) + (d__2 = 
+		h__[h_dim1 + 2], abs(d__2));
+	if (s == 0.) {
+	    v[1] = 0.;
+	    v[2] = 0.;
+	} else {
+	    h21s = h__[h_dim1 + 2] / s;
+	    v[1] = h21s * h__[(h_dim1 << 1) + 1] + (h__[h_dim1 + 1] - *sr1) * 
+		    ((h__[h_dim1 + 1] - *sr2) / s) - *si1 * (*si2 / s);
+	    v[2] = h21s * (h__[h_dim1 + 1] + h__[(h_dim1 << 1) + 2] - *sr1 - *
+		    sr2);
+	}
+    } else {
+	s = (d__1 = h__[h_dim1 + 1] - *sr2, abs(d__1)) + abs(*si2) + (d__2 = 
+		h__[h_dim1 + 2], abs(d__2)) + (d__3 = h__[h_dim1 + 3], abs(
+		d__3));
+	if (s == 0.) {
+	    v[1] = 0.;
+	    v[2] = 0.;
+	    v[3] = 0.;
+	} else {
+	    h21s = h__[h_dim1 + 2] / s;
+	    h31s = h__[h_dim1 + 3] / s;
+	    v[1] = (h__[h_dim1 + 1] - *sr1) * ((h__[h_dim1 + 1] - *sr2) / s) 
+		    - *si1 * (*si2 / s) + h__[(h_dim1 << 1) + 1] * h21s + h__[
+		    h_dim1 * 3 + 1] * h31s;
+	    v[2] = h21s * (h__[h_dim1 + 1] + h__[(h_dim1 << 1) + 2] - *sr1 - *
+		    sr2) + h__[h_dim1 * 3 + 2] * h31s;
+	    v[3] = h31s * (h__[h_dim1 + 1] + h__[h_dim1 * 3 + 3] - *sr1 - *
+		    sr2) + h21s * h__[(h_dim1 << 1) + 3];
+	}
+    }
+    return 0;
+} /* igraphdlaqr1_ */
+
diff --git a/src/lapack/dlaqr2.c b/src/lapack/dlaqr2.c
new file mode 100644
index 0000000..995e8e4
--- /dev/null
+++ b/src/lapack/dlaqr2.c
@@ -0,0 +1,683 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static doublereal c_b12 = 0.;
+static doublereal c_b13 = 1.;
+static logical c_true = TRUE_;
+
+/* Subroutine */ int igraphdlaqr2_(logical *wantt, logical *wantz, integer *n, 
+	integer *ktop, integer *kbot, integer *nw, doublereal *h__, integer *
+	ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, 
+	integer *ns, integer *nd, doublereal *sr, doublereal *si, doublereal *
+	v, integer *ldv, integer *nh, doublereal *t, integer *ldt, integer *
+	nv, doublereal *wv, integer *ldwv, doublereal *work, integer *lwork)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, 
+	    wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4;
+    doublereal d__1, d__2, d__3, d__4, d__5, d__6;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, k;
+    doublereal s, aa, bb, cc, dd, cs, sn;
+    integer jw;
+    doublereal evi, evk, foo;
+    integer kln;
+    doublereal tau, ulp;
+    integer lwk1, lwk2;
+    doublereal beta;
+    integer kend, kcol, info, ifst, ilst, ltop, krow;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *), igraphdgemm_(char *, char *, integer *, integer *
+	    , integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    logical bulge;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    integer infqr, kwtop;
+    extern /* Subroutine */ int igraphdlanv2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *), igraphdlabad_(
+	    doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdgehrd_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *), igraphdlarfg_(integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *), igraphdlahqr_(logical *, logical *, integer *,
+	     integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *), igraphdlacpy_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    doublereal safmin;
+    extern /* Subroutine */ int igraphdlaset_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *);
+    doublereal safmax;
+    extern /* Subroutine */ int igraphdtrexc_(char *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *, integer *, 
+	    doublereal *, integer *), igraphdormhr_(char *, char *, integer 
+	    *, integer *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    integer *);
+    logical sorted;
+    doublereal smlnum;
+    integer lwkopt;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2)                        --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+    -- June 2010                                                       --   
+
+
+       This subroutine is identical to DLAQR3 except that it avoids   
+       recursion by calling DLAHQR instead of DLAQR4.   
+
+
+       ******************************************************************   
+       Aggressive early deflation:   
+
+       This subroutine accepts as input an upper Hessenberg matrix   
+       H and performs an orthogonal similarity transformation   
+       designed to detect and deflate fully converged eigenvalues from   
+       a trailing principal submatrix.  On output H has been over-   
+       written by a new Hessenberg matrix that is a perturbation of   
+       an orthogonal similarity transformation of H.  It is to be   
+       hoped that the final version of H has many zero subdiagonal   
+       entries.   
+
+       ******************************************************************   
+       WANTT   (input) LOGICAL   
+            If .TRUE., then the Hessenberg matrix H is fully updated   
+            so that the quasi-triangular Schur factor may be   
+            computed (in cooperation with the calling subroutine).   
+            If .FALSE., then only enough of H is updated to preserve   
+            the eigenvalues.   
+
+       WANTZ   (input) LOGICAL   
+            If .TRUE., then the orthogonal matrix Z is updated so   
+            so that the orthogonal Schur factor may be computed   
+            (in cooperation with the calling subroutine).   
+            If .FALSE., then Z is not referenced.   
+
+       N       (input) INTEGER   
+            The order of the matrix H and (if WANTZ is .TRUE.) the   
+            order of the orthogonal matrix Z.   
+
+       KTOP    (input) INTEGER   
+            It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0.   
+            KBOT and KTOP together determine an isolated block   
+            along the diagonal of the Hessenberg matrix.   
+
+       KBOT    (input) INTEGER   
+            It is assumed without a check that either   
+            KBOT = N or H(KBOT+1,KBOT)=0.  KBOT and KTOP together   
+            determine an isolated block along the diagonal of the   
+            Hessenberg matrix.   
+
+       NW      (input) INTEGER   
+            Deflation window size.  1 .LE. NW .LE. (KBOT-KTOP+1).   
+
+       H       (input/output) DOUBLE PRECISION array, dimension (LDH,N)   
+            On input the initial N-by-N section of H stores the   
+            Hessenberg matrix undergoing aggressive early deflation.   
+            On output H has been transformed by an orthogonal   
+            similarity transformation, perturbed, and the returned   
+            to Hessenberg form that (it is to be hoped) has some   
+            zero subdiagonal entries.   
+
+       LDH     (input) integer   
+            Leading dimension of H just as declared in the calling   
+            subroutine.  N .LE. LDH   
+
+       ILOZ    (input) INTEGER   
+       IHIZ    (input) INTEGER   
+            Specify the rows of Z to which transformations must be   
+            applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N.   
+
+       Z       (input/output) DOUBLE PRECISION array, dimension (LDZ,N)   
+            IF WANTZ is .TRUE., then on output, the orthogonal   
+            similarity transformation mentioned above has been   
+            accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right.   
+            If WANTZ is .FALSE., then Z is unreferenced.   
+
+       LDZ     (input) integer   
+            The leading dimension of Z just as declared in the   
+            calling subroutine.  1 .LE. LDZ.   
+
+       NS      (output) integer   
+            The number of unconverged (ie approximate) eigenvalues   
+            returned in SR and SI that may be used as shifts by the   
+            calling subroutine.   
+
+       ND      (output) integer   
+            The number of converged eigenvalues uncovered by this   
+            subroutine.   
+
+       SR      (output) DOUBLE PRECISION array, dimension (KBOT)   
+       SI      (output) DOUBLE PRECISION array, dimension (KBOT)   
+            On output, the real and imaginary parts of approximate   
+            eigenvalues that may be used for shifts are stored in   
+            SR(KBOT-ND-NS+1) through SR(KBOT-ND) and   
+            SI(KBOT-ND-NS+1) through SI(KBOT-ND), respectively.   
+            The real and imaginary parts of converged eigenvalues   
+            are stored in SR(KBOT-ND+1) through SR(KBOT) and   
+            SI(KBOT-ND+1) through SI(KBOT), respectively.   
+
+       V       (workspace) DOUBLE PRECISION array, dimension (LDV,NW)   
+            An NW-by-NW work array.   
+
+       LDV     (input) integer scalar   
+            The leading dimension of V just as declared in the   
+            calling subroutine.  NW .LE. LDV   
+
+       NH      (input) integer scalar   
+            The number of columns of T.  NH.GE.NW.   
+
+       T       (workspace) DOUBLE PRECISION array, dimension (LDT,NW)   
+
+       LDT     (input) integer   
+            The leading dimension of T just as declared in the   
+            calling subroutine.  NW .LE. LDT   
+
+       NV      (input) integer   
+            The number of rows of work array WV available for   
+            workspace.  NV.GE.NW.   
+
+       WV      (workspace) DOUBLE PRECISION array, dimension (LDWV,NW)   
+
+       LDWV    (input) integer   
+            The leading dimension of W just as declared in the   
+            calling subroutine.  NW .LE. LDV   
+
+       WORK    (workspace) DOUBLE PRECISION array, dimension (LWORK)   
+            On exit, WORK(1) is set to an estimate of the optimal value   
+            of LWORK for the given values of N, NW, KTOP and KBOT.   
+
+       LWORK   (input) integer   
+            The dimension of the work array WORK.  LWORK = 2*NW   
+            suffices, but greater efficiency may result from larger   
+            values of LWORK.   
+
+            If LWORK = -1, then a workspace query is assumed; DLAQR2   
+            only estimates the optimal workspace size for the given   
+            values of N, NW, KTOP and KBOT.  The estimate is returned   
+            in WORK(1).  No error message related to LWORK is issued   
+            by XERBLA.  Neither H nor Z are accessed.   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+
+       ==== Estimate optimal workspace. ====   
+
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --sr;
+    --si;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    wv_dim1 = *ldwv;
+    wv_offset = 1 + wv_dim1;
+    wv -= wv_offset;
+    --work;
+
+    /* Function Body   
+   Computing MIN */
+    i__1 = *nw, i__2 = *kbot - *ktop + 1;
+    jw = min(i__1,i__2);
+    if (jw <= 2) {
+	lwkopt = 1;
+    } else {
+
+/*        ==== Workspace query call to DGEHRD ==== */
+
+	i__1 = jw - 1;
+	igraphdgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], &
+		c_n1, &info);
+	lwk1 = (integer) work[1];
+
+/*        ==== Workspace query call to DORMHR ==== */
+
+	i__1 = jw - 1;
+	igraphdormhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1],
+		 &v[v_offset], ldv, &work[1], &c_n1, &info);
+	lwk2 = (integer) work[1];
+
+/*        ==== Optimal workspace ==== */
+
+	lwkopt = jw + max(lwk1,lwk2);
+    }
+
+/*     ==== Quick return in case of workspace query. ==== */
+
+    if (*lwork == -1) {
+	work[1] = (doublereal) lwkopt;
+	return 0;
+    }
+
+/*     ==== Nothing to do ...   
+       ... for an empty active block ... ==== */
+    *ns = 0;
+    *nd = 0;
+    work[1] = 1.;
+    if (*ktop > *kbot) {
+	return 0;
+    }
+/*     ... nor for an empty deflation window. ==== */
+    if (*nw < 1) {
+	return 0;
+    }
+
+/*     ==== Machine constants ==== */
+
+    safmin = igraphdlamch_("SAFE MINIMUM");
+    safmax = 1. / safmin;
+    igraphdlabad_(&safmin, &safmax);
+    ulp = igraphdlamch_("PRECISION");
+    smlnum = safmin * ((doublereal) (*n) / ulp);
+
+/*     ==== Setup deflation window ====   
+
+   Computing MIN */
+    i__1 = *nw, i__2 = *kbot - *ktop + 1;
+    jw = min(i__1,i__2);
+    kwtop = *kbot - jw + 1;
+    if (kwtop == *ktop) {
+	s = 0.;
+    } else {
+	s = h__[kwtop + (kwtop - 1) * h_dim1];
+    }
+
+    if (*kbot == kwtop) {
+
+/*        ==== 1-by-1 deflation window: not much to do ==== */
+
+	sr[kwtop] = h__[kwtop + kwtop * h_dim1];
+	si[kwtop] = 0.;
+	*ns = 1;
+	*nd = 0;
+/* Computing MAX */
+	d__2 = smlnum, d__3 = ulp * (d__1 = h__[kwtop + kwtop * h_dim1], abs(
+		d__1));
+	if (abs(s) <= max(d__2,d__3)) {
+	    *ns = 0;
+	    *nd = 1;
+	    if (kwtop > *ktop) {
+		h__[kwtop + (kwtop - 1) * h_dim1] = 0.;
+	    }
+	}
+	work[1] = 1.;
+	return 0;
+    }
+
+/*     ==== Convert to spike-triangular form.  (In case of a   
+       .    rare QR failure, this routine continues to do   
+       .    aggressive early deflation using that part of   
+       .    the deflation window that converged using INFQR   
+       .    here and there to keep track.) ==== */
+
+    igraphdlacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], 
+	    ldt);
+    i__1 = jw - 1;
+    i__2 = *ldh + 1;
+    i__3 = *ldt + 1;
+    igraphdcopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], &
+	    i__3);
+
+    igraphdlaset_("A", &jw, &jw, &c_b12, &c_b13, &v[v_offset], ldv);
+    igraphdlahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[kwtop], 
+	    &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr);
+
+/*     ==== DTREXC needs a clean margin near the diagonal ==== */
+
+    i__1 = jw - 3;
+    for (j = 1; j <= i__1; ++j) {
+	t[j + 2 + j * t_dim1] = 0.;
+	t[j + 3 + j * t_dim1] = 0.;
+/* L10: */
+    }
+    if (jw > 2) {
+	t[jw + (jw - 2) * t_dim1] = 0.;
+    }
+
+/*     ==== Deflation detection loop ==== */
+
+    *ns = jw;
+    ilst = infqr + 1;
+L20:
+    if (ilst <= *ns) {
+	if (*ns == 1) {
+	    bulge = FALSE_;
+	} else {
+	    bulge = t[*ns + (*ns - 1) * t_dim1] != 0.;
+	}
+
+/*        ==== Small spike tip test for deflation ==== */
+
+	if (! bulge) {
+
+/*           ==== Real eigenvalue ==== */
+
+	    foo = (d__1 = t[*ns + *ns * t_dim1], abs(d__1));
+	    if (foo == 0.) {
+		foo = abs(s);
+	    }
+/* Computing MAX */
+	    d__2 = smlnum, d__3 = ulp * foo;
+	    if ((d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)) <= max(d__2,d__3))
+		     {
+
+/*              ==== Deflatable ==== */
+
+		--(*ns);
+	    } else {
+
+/*              ==== Undeflatable.   Move it up out of the way.   
+                .    (DTREXC can not fail in this case.) ==== */
+
+		ifst = *ns;
+		igraphdtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst,
+			 &ilst, &work[1], &info);
+		++ilst;
+	    }
+	} else {
+
+/*           ==== Complex conjugate pair ==== */
+
+	    foo = (d__3 = t[*ns + *ns * t_dim1], abs(d__3)) + sqrt((d__1 = t[*
+		    ns + (*ns - 1) * t_dim1], abs(d__1))) * sqrt((d__2 = t[*
+		    ns - 1 + *ns * t_dim1], abs(d__2)));
+	    if (foo == 0.) {
+		foo = abs(s);
+	    }
+/* Computing MAX */
+	    d__3 = (d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)), d__4 = (d__2 =
+		     s * v[(*ns - 1) * v_dim1 + 1], abs(d__2));
+/* Computing MAX */
+	    d__5 = smlnum, d__6 = ulp * foo;
+	    if (max(d__3,d__4) <= max(d__5,d__6)) {
+
+/*              ==== Deflatable ==== */
+
+		*ns += -2;
+	    } else {
+
+/*              ==== Undeflatable. Move them up out of the way.   
+                .    Fortunately, DTREXC does the right thing with   
+                .    ILST in case of a rare exchange failure. ==== */
+
+		ifst = *ns;
+		igraphdtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst,
+			 &ilst, &work[1], &info);
+		ilst += 2;
+	    }
+	}
+
+/*        ==== End deflation detection loop ==== */
+
+	goto L20;
+    }
+
+/*        ==== Return to Hessenberg form ==== */
+
+    if (*ns == 0) {
+	s = 0.;
+    }
+
+    if (*ns < jw) {
+
+/*        ==== sorting diagonal blocks of T improves accuracy for   
+          .    graded matrices.  Bubble sort deals well with   
+          .    exchange failures. ==== */
+
+	sorted = FALSE_;
+	i__ = *ns + 1;
+L30:
+	if (sorted) {
+	    goto L50;
+	}
+	sorted = TRUE_;
+
+	kend = i__ - 1;
+	i__ = infqr + 1;
+	if (i__ == *ns) {
+	    k = i__ + 1;
+	} else if (t[i__ + 1 + i__ * t_dim1] == 0.) {
+	    k = i__ + 1;
+	} else {
+	    k = i__ + 2;
+	}
+L40:
+	if (k <= kend) {
+	    if (k == i__ + 1) {
+		evi = (d__1 = t[i__ + i__ * t_dim1], abs(d__1));
+	    } else {
+		evi = (d__3 = t[i__ + i__ * t_dim1], abs(d__3)) + sqrt((d__1 =
+			 t[i__ + 1 + i__ * t_dim1], abs(d__1))) * sqrt((d__2 =
+			 t[i__ + (i__ + 1) * t_dim1], abs(d__2)));
+	    }
+
+	    if (k == kend) {
+		evk = (d__1 = t[k + k * t_dim1], abs(d__1));
+	    } else if (t[k + 1 + k * t_dim1] == 0.) {
+		evk = (d__1 = t[k + k * t_dim1], abs(d__1));
+	    } else {
+		evk = (d__3 = t[k + k * t_dim1], abs(d__3)) + sqrt((d__1 = t[
+			k + 1 + k * t_dim1], abs(d__1))) * sqrt((d__2 = t[k + 
+			(k + 1) * t_dim1], abs(d__2)));
+	    }
+
+	    if (evi >= evk) {
+		i__ = k;
+	    } else {
+		sorted = FALSE_;
+		ifst = i__;
+		ilst = k;
+		igraphdtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst,
+			 &ilst, &work[1], &info);
+		if (info == 0) {
+		    i__ = ilst;
+		} else {
+		    i__ = k;
+		}
+	    }
+	    if (i__ == kend) {
+		k = i__ + 1;
+	    } else if (t[i__ + 1 + i__ * t_dim1] == 0.) {
+		k = i__ + 1;
+	    } else {
+		k = i__ + 2;
+	    }
+	    goto L40;
+	}
+	goto L30;
+L50:
+	;
+    }
+
+/*     ==== Restore shift/eigenvalue array from T ==== */
+
+    i__ = jw;
+L60:
+    if (i__ >= infqr + 1) {
+	if (i__ == infqr + 1) {
+	    sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1];
+	    si[kwtop + i__ - 1] = 0.;
+	    --i__;
+	} else if (t[i__ + (i__ - 1) * t_dim1] == 0.) {
+	    sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1];
+	    si[kwtop + i__ - 1] = 0.;
+	    --i__;
+	} else {
+	    aa = t[i__ - 1 + (i__ - 1) * t_dim1];
+	    cc = t[i__ + (i__ - 1) * t_dim1];
+	    bb = t[i__ - 1 + i__ * t_dim1];
+	    dd = t[i__ + i__ * t_dim1];
+	    igraphdlanv2_(&aa, &bb, &cc, &dd, &sr[kwtop + i__ - 2], &si[kwtop + i__ 
+		    - 2], &sr[kwtop + i__ - 1], &si[kwtop + i__ - 1], &cs, &
+		    sn);
+	    i__ += -2;
+	}
+	goto L60;
+    }
+
+    if (*ns < jw || s == 0.) {
+	if (*ns > 1 && s != 0.) {
+
+/*           ==== Reflect spike back into lower triangle ==== */
+
+	    igraphdcopy_(ns, &v[v_offset], ldv, &work[1], &c__1);
+	    beta = work[1];
+	    igraphdlarfg_(ns, &beta, &work[2], &c__1, &tau);
+	    work[1] = 1.;
+
+	    i__1 = jw - 2;
+	    i__2 = jw - 2;
+	    igraphdlaset_("L", &i__1, &i__2, &c_b12, &c_b12, &t[t_dim1 + 3], ldt);
+
+	    igraphdlarf_("L", ns, &jw, &work[1], &c__1, &tau, &t[t_offset], ldt, &
+		    work[jw + 1]);
+	    igraphdlarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, &
+		    work[jw + 1]);
+	    igraphdlarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, &
+		    work[jw + 1]);
+
+	    i__1 = *lwork - jw;
+	    igraphdgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1]
+		    , &i__1, &info);
+	}
+
+/*        ==== Copy updated reduced window into place ==== */
+
+	if (kwtop > 1) {
+	    h__[kwtop + (kwtop - 1) * h_dim1] = s * v[v_dim1 + 1];
+	}
+	igraphdlacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1]
+		, ldh);
+	i__1 = jw - 1;
+	i__2 = *ldt + 1;
+	i__3 = *ldh + 1;
+	igraphdcopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1],
+		 &i__3);
+
+/*        ==== Accumulate orthogonal matrix in order update   
+          .    H and Z, if requested.  ==== */
+
+	if (*ns > 1 && s != 0.) {
+	    i__1 = *lwork - jw;
+	    igraphdormhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1],
+		     &v[v_offset], ldv, &work[jw + 1], &i__1, &info);
+	}
+
+/*        ==== Update vertical slab in H ==== */
+
+	if (*wantt) {
+	    ltop = 1;
+	} else {
+	    ltop = *ktop;
+	}
+	i__1 = kwtop - 1;
+	i__2 = *nv;
+	for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += 
+		i__2) {
+/* Computing MIN */
+	    i__3 = *nv, i__4 = kwtop - krow;
+	    kln = min(i__3,i__4);
+	    igraphdgemm_("N", "N", &kln, &jw, &jw, &c_b13, &h__[krow + kwtop * 
+		    h_dim1], ldh, &v[v_offset], ldv, &c_b12, &wv[wv_offset], 
+		    ldwv);
+	    igraphdlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * 
+		    h_dim1], ldh);
+/* L70: */
+	}
+
+/*        ==== Update horizontal slab in H ==== */
+
+	if (*wantt) {
+	    i__2 = *n;
+	    i__1 = *nh;
+	    for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; 
+		    kcol += i__1) {
+/* Computing MIN */
+		i__3 = *nh, i__4 = *n - kcol + 1;
+		kln = min(i__3,i__4);
+		igraphdgemm_("C", "N", &jw, &kln, &jw, &c_b13, &v[v_offset], ldv, &
+			h__[kwtop + kcol * h_dim1], ldh, &c_b12, &t[t_offset],
+			 ldt);
+		igraphdlacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol *
+			 h_dim1], ldh);
+/* L80: */
+	    }
+	}
+
+/*        ==== Update vertical slab in Z ==== */
+
+	if (*wantz) {
+	    i__1 = *ihiz;
+	    i__2 = *nv;
+	    for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow +=
+		     i__2) {
+/* Computing MIN */
+		i__3 = *nv, i__4 = *ihiz - krow + 1;
+		kln = min(i__3,i__4);
+		igraphdgemm_("N", "N", &kln, &jw, &jw, &c_b13, &z__[krow + kwtop * 
+			z_dim1], ldz, &v[v_offset], ldv, &c_b12, &wv[
+			wv_offset], ldwv);
+		igraphdlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + 
+			kwtop * z_dim1], ldz);
+/* L90: */
+	    }
+	}
+    }
+
+/*     ==== Return the number of deflations ... ==== */
+
+    *nd = jw - *ns;
+
+/*     ==== ... and the number of shifts. (Subtracting   
+       .    INFQR from the spike length takes care   
+       .    of the case of a rare QR failure while   
+       .    calculating eigenvalues of the deflation   
+       .    window.)  ==== */
+
+    *ns -= infqr;
+
+/*      ==== Return optimal workspace. ==== */
+
+    work[1] = (doublereal) lwkopt;
+
+/*     ==== End of DLAQR2 ==== */
+
+    return 0;
+} /* igraphdlaqr2_ */
+
diff --git a/src/lapack/dlaqr3.c b/src/lapack/dlaqr3.c
new file mode 100644
index 0000000..a743441
--- /dev/null
+++ b/src/lapack/dlaqr3.c
@@ -0,0 +1,701 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static logical c_true = TRUE_;
+static doublereal c_b17 = 0.;
+static doublereal c_b18 = 1.;
+static integer c__12 = 12;
+
+/* Subroutine */ int igraphdlaqr3_(logical *wantt, logical *wantz, integer *n, 
+	integer *ktop, integer *kbot, integer *nw, doublereal *h__, integer *
+	ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, 
+	integer *ns, integer *nd, doublereal *sr, doublereal *si, doublereal *
+	v, integer *ldv, integer *nh, doublereal *t, integer *ldt, integer *
+	nv, doublereal *wv, integer *ldwv, doublereal *work, integer *lwork)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, 
+	    wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4;
+    doublereal d__1, d__2, d__3, d__4, d__5, d__6;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, k;
+    doublereal s, aa, bb, cc, dd, cs, sn;
+    integer jw;
+    doublereal evi, evk, foo;
+    integer kln;
+    doublereal tau, ulp;
+    integer lwk1, lwk2, lwk3;
+    doublereal beta;
+    integer kend, kcol, info, nmin, ifst, ilst, ltop, krow;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *), igraphdgemm_(char *, char *, integer *, integer *
+	    , integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    logical bulge;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    integer infqr, kwtop;
+    extern /* Subroutine */ int igraphdlanv2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *), igraphdlaqr4_(
+	    logical *, logical *, integer *, integer *, integer *, doublereal 
+	    *, integer *, doublereal *, doublereal *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, integer *), 
+	    igraphdlabad_(doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdgehrd_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *), igraphdlarfg_(integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *), igraphdlahqr_(logical *, logical *, integer *,
+	     integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *), igraphdlacpy_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    doublereal safmin;
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    doublereal safmax;
+    extern /* Subroutine */ int igraphdlaset_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *), 
+	    igraphdtrexc_(char *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, integer *, integer *, doublereal *, integer *),
+	     igraphdormhr_(char *, char *, integer *, integer *, integer *, integer 
+	    *, doublereal *, integer *, doublereal *, doublereal *, integer *,
+	     doublereal *, integer *, integer *);
+    logical sorted;
+    doublereal smlnum;
+    integer lwkopt;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2)                        --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+    -- June 2010                                                       --   
+
+
+       ******************************************************************   
+       Aggressive early deflation:   
+
+       This subroutine accepts as input an upper Hessenberg matrix   
+       H and performs an orthogonal similarity transformation   
+       designed to detect and deflate fully converged eigenvalues from   
+       a trailing principal submatrix.  On output H has been over-   
+       written by a new Hessenberg matrix that is a perturbation of   
+       an orthogonal similarity transformation of H.  It is to be   
+       hoped that the final version of H has many zero subdiagonal   
+       entries.   
+
+       ******************************************************************   
+       WANTT   (input) LOGICAL   
+            If .TRUE., then the Hessenberg matrix H is fully updated   
+            so that the quasi-triangular Schur factor may be   
+            computed (in cooperation with the calling subroutine).   
+            If .FALSE., then only enough of H is updated to preserve   
+            the eigenvalues.   
+
+       WANTZ   (input) LOGICAL   
+            If .TRUE., then the orthogonal matrix Z is updated so   
+            so that the orthogonal Schur factor may be computed   
+            (in cooperation with the calling subroutine).   
+            If .FALSE., then Z is not referenced.   
+
+       N       (input) INTEGER   
+            The order of the matrix H and (if WANTZ is .TRUE.) the   
+            order of the orthogonal matrix Z.   
+
+       KTOP    (input) INTEGER   
+            It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0.   
+            KBOT and KTOP together determine an isolated block   
+            along the diagonal of the Hessenberg matrix.   
+
+       KBOT    (input) INTEGER   
+            It is assumed without a check that either   
+            KBOT = N or H(KBOT+1,KBOT)=0.  KBOT and KTOP together   
+            determine an isolated block along the diagonal of the   
+            Hessenberg matrix.   
+
+       NW      (input) INTEGER   
+            Deflation window size.  1 .LE. NW .LE. (KBOT-KTOP+1).   
+
+       H       (input/output) DOUBLE PRECISION array, dimension (LDH,N)   
+            On input the initial N-by-N section of H stores the   
+            Hessenberg matrix undergoing aggressive early deflation.   
+            On output H has been transformed by an orthogonal   
+            similarity transformation, perturbed, and the returned   
+            to Hessenberg form that (it is to be hoped) has some   
+            zero subdiagonal entries.   
+
+       LDH     (input) integer   
+            Leading dimension of H just as declared in the calling   
+            subroutine.  N .LE. LDH   
+
+       ILOZ    (input) INTEGER   
+       IHIZ    (input) INTEGER   
+            Specify the rows of Z to which transformations must be   
+            applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N.   
+
+       Z       (input/output) DOUBLE PRECISION array, dimension (LDZ,N)   
+            IF WANTZ is .TRUE., then on output, the orthogonal   
+            similarity transformation mentioned above has been   
+            accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right.   
+            If WANTZ is .FALSE., then Z is unreferenced.   
+
+       LDZ     (input) integer   
+            The leading dimension of Z just as declared in the   
+            calling subroutine.  1 .LE. LDZ.   
+
+       NS      (output) integer   
+            The number of unconverged (ie approximate) eigenvalues   
+            returned in SR and SI that may be used as shifts by the   
+            calling subroutine.   
+
+       ND      (output) integer   
+            The number of converged eigenvalues uncovered by this   
+            subroutine.   
+
+       SR      (output) DOUBLE PRECISION array, dimension (KBOT)   
+       SI      (output) DOUBLE PRECISION array, dimension (KBOT)   
+            On output, the real and imaginary parts of approximate   
+            eigenvalues that may be used for shifts are stored in   
+            SR(KBOT-ND-NS+1) through SR(KBOT-ND) and   
+            SI(KBOT-ND-NS+1) through SI(KBOT-ND), respectively.   
+            The real and imaginary parts of converged eigenvalues   
+            are stored in SR(KBOT-ND+1) through SR(KBOT) and   
+            SI(KBOT-ND+1) through SI(KBOT), respectively.   
+
+       V       (workspace) DOUBLE PRECISION array, dimension (LDV,NW)   
+            An NW-by-NW work array.   
+
+       LDV     (input) integer scalar   
+            The leading dimension of V just as declared in the   
+            calling subroutine.  NW .LE. LDV   
+
+       NH      (input) integer scalar   
+            The number of columns of T.  NH.GE.NW.   
+
+       T       (workspace) DOUBLE PRECISION array, dimension (LDT,NW)   
+
+       LDT     (input) integer   
+            The leading dimension of T just as declared in the   
+            calling subroutine.  NW .LE. LDT   
+
+       NV      (input) integer   
+            The number of rows of work array WV available for   
+            workspace.  NV.GE.NW.   
+
+       WV      (workspace) DOUBLE PRECISION array, dimension (LDWV,NW)   
+
+       LDWV    (input) integer   
+            The leading dimension of W just as declared in the   
+            calling subroutine.  NW .LE. LDV   
+
+       WORK    (workspace) DOUBLE PRECISION array, dimension (LWORK)   
+            On exit, WORK(1) is set to an estimate of the optimal value   
+            of LWORK for the given values of N, NW, KTOP and KBOT.   
+
+       LWORK   (input) integer   
+            The dimension of the work array WORK.  LWORK = 2*NW   
+            suffices, but greater efficiency may result from larger   
+            values of LWORK.   
+
+            If LWORK = -1, then a workspace query is assumed; DLAQR3   
+            only estimates the optimal workspace size for the given   
+            values of N, NW, KTOP and KBOT.  The estimate is returned   
+            in WORK(1).  No error message related to LWORK is issued   
+            by XERBLA.  Neither H nor Z are accessed.   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+
+       ==== Estimate optimal workspace. ====   
+
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --sr;
+    --si;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    wv_dim1 = *ldwv;
+    wv_offset = 1 + wv_dim1;
+    wv -= wv_offset;
+    --work;
+
+    /* Function Body   
+   Computing MIN */
+    i__1 = *nw, i__2 = *kbot - *ktop + 1;
+    jw = min(i__1,i__2);
+    if (jw <= 2) {
+	lwkopt = 1;
+    } else {
+
+/*        ==== Workspace query call to DGEHRD ==== */
+
+	i__1 = jw - 1;
+	igraphdgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], &
+		c_n1, &info);
+	lwk1 = (integer) work[1];
+
+/*        ==== Workspace query call to DORMHR ==== */
+
+	i__1 = jw - 1;
+	igraphdormhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1],
+		 &v[v_offset], ldv, &work[1], &c_n1, &info);
+	lwk2 = (integer) work[1];
+
+/*        ==== Workspace query call to DLAQR4 ==== */
+
+	igraphdlaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[1], 
+		&si[1], &c__1, &jw, &v[v_offset], ldv, &work[1], &c_n1, &
+		infqr);
+	lwk3 = (integer) work[1];
+
+/*        ==== Optimal workspace ====   
+
+   Computing MAX */
+	i__1 = jw + max(lwk1,lwk2);
+	lwkopt = max(i__1,lwk3);
+    }
+
+/*     ==== Quick return in case of workspace query. ==== */
+
+    if (*lwork == -1) {
+	work[1] = (doublereal) lwkopt;
+	return 0;
+    }
+
+/*     ==== Nothing to do ...   
+       ... for an empty active block ... ==== */
+    *ns = 0;
+    *nd = 0;
+    work[1] = 1.;
+    if (*ktop > *kbot) {
+	return 0;
+    }
+/*     ... nor for an empty deflation window. ==== */
+    if (*nw < 1) {
+	return 0;
+    }
+
+/*     ==== Machine constants ==== */
+
+    safmin = igraphdlamch_("SAFE MINIMUM");
+    safmax = 1. / safmin;
+    igraphdlabad_(&safmin, &safmax);
+    ulp = igraphdlamch_("PRECISION");
+    smlnum = safmin * ((doublereal) (*n) / ulp);
+
+/*     ==== Setup deflation window ====   
+
+   Computing MIN */
+    i__1 = *nw, i__2 = *kbot - *ktop + 1;
+    jw = min(i__1,i__2);
+    kwtop = *kbot - jw + 1;
+    if (kwtop == *ktop) {
+	s = 0.;
+    } else {
+	s = h__[kwtop + (kwtop - 1) * h_dim1];
+    }
+
+    if (*kbot == kwtop) {
+
+/*        ==== 1-by-1 deflation window: not much to do ==== */
+
+	sr[kwtop] = h__[kwtop + kwtop * h_dim1];
+	si[kwtop] = 0.;
+	*ns = 1;
+	*nd = 0;
+/* Computing MAX */
+	d__2 = smlnum, d__3 = ulp * (d__1 = h__[kwtop + kwtop * h_dim1], abs(
+		d__1));
+	if (abs(s) <= max(d__2,d__3)) {
+	    *ns = 0;
+	    *nd = 1;
+	    if (kwtop > *ktop) {
+		h__[kwtop + (kwtop - 1) * h_dim1] = 0.;
+	    }
+	}
+	work[1] = 1.;
+	return 0;
+    }
+
+/*     ==== Convert to spike-triangular form.  (In case of a   
+       .    rare QR failure, this routine continues to do   
+       .    aggressive early deflation using that part of   
+       .    the deflation window that converged using INFQR   
+       .    here and there to keep track.) ==== */
+
+    igraphdlacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], 
+	    ldt);
+    i__1 = jw - 1;
+    i__2 = *ldh + 1;
+    i__3 = *ldt + 1;
+    igraphdcopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], &
+	    i__3);
+
+    igraphdlaset_("A", &jw, &jw, &c_b17, &c_b18, &v[v_offset], ldv);
+    nmin = igraphilaenv_(&c__12, "DLAQR3", "SV", &jw, &c__1, &jw, lwork, (ftnlen)6, 
+	    (ftnlen)2);
+    if (jw > nmin) {
+	igraphdlaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[
+		kwtop], &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &work[1], 
+		lwork, &infqr);
+    } else {
+	igraphdlahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[
+		kwtop], &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr);
+    }
+
+/*     ==== DTREXC needs a clean margin near the diagonal ==== */
+
+    i__1 = jw - 3;
+    for (j = 1; j <= i__1; ++j) {
+	t[j + 2 + j * t_dim1] = 0.;
+	t[j + 3 + j * t_dim1] = 0.;
+/* L10: */
+    }
+    if (jw > 2) {
+	t[jw + (jw - 2) * t_dim1] = 0.;
+    }
+
+/*     ==== Deflation detection loop ==== */
+
+    *ns = jw;
+    ilst = infqr + 1;
+L20:
+    if (ilst <= *ns) {
+	if (*ns == 1) {
+	    bulge = FALSE_;
+	} else {
+	    bulge = t[*ns + (*ns - 1) * t_dim1] != 0.;
+	}
+
+/*        ==== Small spike tip test for deflation ==== */
+
+	if (! bulge) {
+
+/*           ==== Real eigenvalue ==== */
+
+	    foo = (d__1 = t[*ns + *ns * t_dim1], abs(d__1));
+	    if (foo == 0.) {
+		foo = abs(s);
+	    }
+/* Computing MAX */
+	    d__2 = smlnum, d__3 = ulp * foo;
+	    if ((d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)) <= max(d__2,d__3))
+		     {
+
+/*              ==== Deflatable ==== */
+
+		--(*ns);
+	    } else {
+
+/*              ==== Undeflatable.   Move it up out of the way.   
+                .    (DTREXC can not fail in this case.) ==== */
+
+		ifst = *ns;
+		igraphdtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst,
+			 &ilst, &work[1], &info);
+		++ilst;
+	    }
+	} else {
+
+/*           ==== Complex conjugate pair ==== */
+
+	    foo = (d__3 = t[*ns + *ns * t_dim1], abs(d__3)) + sqrt((d__1 = t[*
+		    ns + (*ns - 1) * t_dim1], abs(d__1))) * sqrt((d__2 = t[*
+		    ns - 1 + *ns * t_dim1], abs(d__2)));
+	    if (foo == 0.) {
+		foo = abs(s);
+	    }
+/* Computing MAX */
+	    d__3 = (d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)), d__4 = (d__2 =
+		     s * v[(*ns - 1) * v_dim1 + 1], abs(d__2));
+/* Computing MAX */
+	    d__5 = smlnum, d__6 = ulp * foo;
+	    if (max(d__3,d__4) <= max(d__5,d__6)) {
+
+/*              ==== Deflatable ==== */
+
+		*ns += -2;
+	    } else {
+
+/*              ==== Undeflatable. Move them up out of the way.   
+                .    Fortunately, DTREXC does the right thing with   
+                .    ILST in case of a rare exchange failure. ==== */
+
+		ifst = *ns;
+		igraphdtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst,
+			 &ilst, &work[1], &info);
+		ilst += 2;
+	    }
+	}
+
+/*        ==== End deflation detection loop ==== */
+
+	goto L20;
+    }
+
+/*        ==== Return to Hessenberg form ==== */
+
+    if (*ns == 0) {
+	s = 0.;
+    }
+
+    if (*ns < jw) {
+
+/*        ==== sorting diagonal blocks of T improves accuracy for   
+          .    graded matrices.  Bubble sort deals well with   
+          .    exchange failures. ==== */
+
+	sorted = FALSE_;
+	i__ = *ns + 1;
+L30:
+	if (sorted) {
+	    goto L50;
+	}
+	sorted = TRUE_;
+
+	kend = i__ - 1;
+	i__ = infqr + 1;
+	if (i__ == *ns) {
+	    k = i__ + 1;
+	} else if (t[i__ + 1 + i__ * t_dim1] == 0.) {
+	    k = i__ + 1;
+	} else {
+	    k = i__ + 2;
+	}
+L40:
+	if (k <= kend) {
+	    if (k == i__ + 1) {
+		evi = (d__1 = t[i__ + i__ * t_dim1], abs(d__1));
+	    } else {
+		evi = (d__3 = t[i__ + i__ * t_dim1], abs(d__3)) + sqrt((d__1 =
+			 t[i__ + 1 + i__ * t_dim1], abs(d__1))) * sqrt((d__2 =
+			 t[i__ + (i__ + 1) * t_dim1], abs(d__2)));
+	    }
+
+	    if (k == kend) {
+		evk = (d__1 = t[k + k * t_dim1], abs(d__1));
+	    } else if (t[k + 1 + k * t_dim1] == 0.) {
+		evk = (d__1 = t[k + k * t_dim1], abs(d__1));
+	    } else {
+		evk = (d__3 = t[k + k * t_dim1], abs(d__3)) + sqrt((d__1 = t[
+			k + 1 + k * t_dim1], abs(d__1))) * sqrt((d__2 = t[k + 
+			(k + 1) * t_dim1], abs(d__2)));
+	    }
+
+	    if (evi >= evk) {
+		i__ = k;
+	    } else {
+		sorted = FALSE_;
+		ifst = i__;
+		ilst = k;
+		igraphdtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst,
+			 &ilst, &work[1], &info);
+		if (info == 0) {
+		    i__ = ilst;
+		} else {
+		    i__ = k;
+		}
+	    }
+	    if (i__ == kend) {
+		k = i__ + 1;
+	    } else if (t[i__ + 1 + i__ * t_dim1] == 0.) {
+		k = i__ + 1;
+	    } else {
+		k = i__ + 2;
+	    }
+	    goto L40;
+	}
+	goto L30;
+L50:
+	;
+    }
+
+/*     ==== Restore shift/eigenvalue array from T ==== */
+
+    i__ = jw;
+L60:
+    if (i__ >= infqr + 1) {
+	if (i__ == infqr + 1) {
+	    sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1];
+	    si[kwtop + i__ - 1] = 0.;
+	    --i__;
+	} else if (t[i__ + (i__ - 1) * t_dim1] == 0.) {
+	    sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1];
+	    si[kwtop + i__ - 1] = 0.;
+	    --i__;
+	} else {
+	    aa = t[i__ - 1 + (i__ - 1) * t_dim1];
+	    cc = t[i__ + (i__ - 1) * t_dim1];
+	    bb = t[i__ - 1 + i__ * t_dim1];
+	    dd = t[i__ + i__ * t_dim1];
+	    igraphdlanv2_(&aa, &bb, &cc, &dd, &sr[kwtop + i__ - 2], &si[kwtop + i__ 
+		    - 2], &sr[kwtop + i__ - 1], &si[kwtop + i__ - 1], &cs, &
+		    sn);
+	    i__ += -2;
+	}
+	goto L60;
+    }
+
+    if (*ns < jw || s == 0.) {
+	if (*ns > 1 && s != 0.) {
+
+/*           ==== Reflect spike back into lower triangle ==== */
+
+	    igraphdcopy_(ns, &v[v_offset], ldv, &work[1], &c__1);
+	    beta = work[1];
+	    igraphdlarfg_(ns, &beta, &work[2], &c__1, &tau);
+	    work[1] = 1.;
+
+	    i__1 = jw - 2;
+	    i__2 = jw - 2;
+	    igraphdlaset_("L", &i__1, &i__2, &c_b17, &c_b17, &t[t_dim1 + 3], ldt);
+
+	    igraphdlarf_("L", ns, &jw, &work[1], &c__1, &tau, &t[t_offset], ldt, &
+		    work[jw + 1]);
+	    igraphdlarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, &
+		    work[jw + 1]);
+	    igraphdlarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, &
+		    work[jw + 1]);
+
+	    i__1 = *lwork - jw;
+	    igraphdgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1]
+		    , &i__1, &info);
+	}
+
+/*        ==== Copy updated reduced window into place ==== */
+
+	if (kwtop > 1) {
+	    h__[kwtop + (kwtop - 1) * h_dim1] = s * v[v_dim1 + 1];
+	}
+	igraphdlacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1]
+		, ldh);
+	i__1 = jw - 1;
+	i__2 = *ldt + 1;
+	i__3 = *ldh + 1;
+	igraphdcopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1],
+		 &i__3);
+
+/*        ==== Accumulate orthogonal matrix in order update   
+          .    H and Z, if requested.  ==== */
+
+	if (*ns > 1 && s != 0.) {
+	    i__1 = *lwork - jw;
+	    igraphdormhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1],
+		     &v[v_offset], ldv, &work[jw + 1], &i__1, &info);
+	}
+
+/*        ==== Update vertical slab in H ==== */
+
+	if (*wantt) {
+	    ltop = 1;
+	} else {
+	    ltop = *ktop;
+	}
+	i__1 = kwtop - 1;
+	i__2 = *nv;
+	for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += 
+		i__2) {
+/* Computing MIN */
+	    i__3 = *nv, i__4 = kwtop - krow;
+	    kln = min(i__3,i__4);
+	    igraphdgemm_("N", "N", &kln, &jw, &jw, &c_b18, &h__[krow + kwtop * 
+		    h_dim1], ldh, &v[v_offset], ldv, &c_b17, &wv[wv_offset], 
+		    ldwv);
+	    igraphdlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * 
+		    h_dim1], ldh);
+/* L70: */
+	}
+
+/*        ==== Update horizontal slab in H ==== */
+
+	if (*wantt) {
+	    i__2 = *n;
+	    i__1 = *nh;
+	    for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; 
+		    kcol += i__1) {
+/* Computing MIN */
+		i__3 = *nh, i__4 = *n - kcol + 1;
+		kln = min(i__3,i__4);
+		igraphdgemm_("C", "N", &jw, &kln, &jw, &c_b18, &v[v_offset], ldv, &
+			h__[kwtop + kcol * h_dim1], ldh, &c_b17, &t[t_offset],
+			 ldt);
+		igraphdlacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol *
+			 h_dim1], ldh);
+/* L80: */
+	    }
+	}
+
+/*        ==== Update vertical slab in Z ==== */
+
+	if (*wantz) {
+	    i__1 = *ihiz;
+	    i__2 = *nv;
+	    for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow +=
+		     i__2) {
+/* Computing MIN */
+		i__3 = *nv, i__4 = *ihiz - krow + 1;
+		kln = min(i__3,i__4);
+		igraphdgemm_("N", "N", &kln, &jw, &jw, &c_b18, &z__[krow + kwtop * 
+			z_dim1], ldz, &v[v_offset], ldv, &c_b17, &wv[
+			wv_offset], ldwv);
+		igraphdlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + 
+			kwtop * z_dim1], ldz);
+/* L90: */
+	    }
+	}
+    }
+
+/*     ==== Return the number of deflations ... ==== */
+
+    *nd = jw - *ns;
+
+/*     ==== ... and the number of shifts. (Subtracting   
+       .    INFQR from the spike length takes care   
+       .    of the case of a rare QR failure while   
+       .    calculating eigenvalues of the deflation   
+       .    window.)  ==== */
+
+    *ns -= infqr;
+
+/*      ==== Return optimal workspace. ==== */
+
+    work[1] = (doublereal) lwkopt;
+
+/*     ==== End of DLAQR3 ==== */
+
+    return 0;
+} /* igraphdlaqr3_ */
+
diff --git a/src/lapack/dlaqr4.c b/src/lapack/dlaqr4.c
new file mode 100644
index 0000000..69fed0c
--- /dev/null
+++ b/src/lapack/dlaqr4.c
@@ -0,0 +1,742 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__13 = 13;
+static integer c__15 = 15;
+static integer c_n1 = -1;
+static integer c__12 = 12;
+static integer c__14 = 14;
+static integer c__16 = 16;
+static logical c_false = FALSE_;
+static integer c__1 = 1;
+static integer c__3 = 3;
+
+/* Subroutine */ int igraphdlaqr4_(logical *wantt, logical *wantz, integer *n, 
+	integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal 
+	*wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, 
+	integer *ldz, doublereal *work, integer *lwork, integer *info)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5;
+    doublereal d__1, d__2, d__3, d__4;
+
+    /* Local variables */
+    integer i__, k;
+    doublereal aa, bb, cc, dd;
+    integer ld;
+    doublereal cs;
+    integer nh, it, ks, kt;
+    doublereal sn;
+    integer ku, kv, ls, ns;
+    doublereal ss;
+    integer nw, inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, kbot, 
+	    nmin;
+    doublereal swap;
+    integer ktop;
+    doublereal zdum[1]	/* was [1][1] */;
+    integer kacc22, itmax, nsmax, nwmax, kwtop;
+    extern /* Subroutine */ int igraphdlaqr2_(logical *, logical *, integer *, 
+	    integer *, integer *, integer *, doublereal *, integer *, integer 
+	    *, integer *, doublereal *, integer *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, integer *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdlanv2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *), igraphdlaqr5_(
+	    logical *, logical *, integer *, integer *, integer *, integer *, 
+	    integer *, doublereal *, doublereal *, doublereal *, integer *, 
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *, doublereal *, integer *);
+    integer nibble;
+    extern /* Subroutine */ int igraphdlahqr_(logical *, logical *, integer *, 
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *), igraphdlacpy_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    char jbcmpz[2];
+    integer nwupbd;
+    logical sorted;
+    integer lwkopt;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+       Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..   
+       November 2006   
+
+
+       This subroutine implements one level of recursion for DLAQR0.   
+       It is a complete implementation of the small bulge multi-shift   
+       QR algorithm.  It may be called by DLAQR0 and, for large enough   
+       deflation window size, it may be called by DLAQR3.  This   
+       subroutine is identical to DLAQR0 except that it calls DLAQR2   
+       instead of DLAQR3.   
+
+       Purpose   
+       =======   
+
+       DLAQR4 computes the eigenvalues of a Hessenberg matrix H   
+       and, optionally, the matrices T and Z from the Schur decomposition   
+       H = Z T Z**T, where T is an upper quasi-triangular matrix (the   
+       Schur form), and Z is the orthogonal matrix of Schur vectors.   
+
+       Optionally Z may be postmultiplied into an input orthogonal   
+       matrix Q so that this routine can give the Schur factorization   
+       of a matrix A which has been reduced to the Hessenberg form H   
+       by the orthogonal matrix Q:  A = Q*H*Q**T = (QZ)*T*(QZ)**T.   
+
+       Arguments   
+       =========   
+
+       WANTT   (input) LOGICAL   
+            = .TRUE. : the full Schur form T is required;   
+            = .FALSE.: only eigenvalues are required.   
+
+       WANTZ   (input) LOGICAL   
+            = .TRUE. : the matrix of Schur vectors Z is required;   
+            = .FALSE.: Schur vectors are not required.   
+
+       N     (input) INTEGER   
+             The order of the matrix H.  N .GE. 0.   
+
+       ILO   (input) INTEGER   
+       IHI   (input) INTEGER   
+             It is assumed that H is already upper triangular in rows   
+             and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1,   
+             H(ILO,ILO-1) is zero. ILO and IHI are normally set by a   
+             previous call to DGEBAL, and then passed to DGEHRD when the   
+             matrix output by DGEBAL is reduced to Hessenberg form.   
+             Otherwise, ILO and IHI should be set to 1 and N,   
+             respectively.  If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N.   
+             If N = 0, then ILO = 1 and IHI = 0.   
+
+       H     (input/output) DOUBLE PRECISION array, dimension (LDH,N)   
+             On entry, the upper Hessenberg matrix H.   
+             On exit, if INFO = 0 and WANTT is .TRUE., then H contains   
+             the upper quasi-triangular matrix T from the Schur   
+             decomposition (the Schur form); 2-by-2 diagonal blocks   
+             (corresponding to complex conjugate pairs of eigenvalues)   
+             are returned in standard form, with H(i,i) = H(i+1,i+1)   
+             and H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and WANTT is   
+             .FALSE., then the contents of H are unspecified on exit.   
+             (The output value of H when INFO.GT.0 is given under the   
+             description of INFO below.)   
+
+             This subroutine may explicitly set H(i,j) = 0 for i.GT.j and   
+             j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N.   
+
+       LDH   (input) INTEGER   
+             The leading dimension of the array H. LDH .GE. max(1,N).   
+
+       WR    (output) DOUBLE PRECISION array, dimension (IHI)   
+       WI    (output) DOUBLE PRECISION array, dimension (IHI)   
+             The real and imaginary parts, respectively, of the computed   
+             eigenvalues of H(ILO:IHI,ILO:IHI) are stored in WR(ILO:IHI)   
+             and WI(ILO:IHI). If two eigenvalues are computed as a   
+             complex conjugate pair, they are stored in consecutive   
+             elements of WR and WI, say the i-th and (i+1)th, with   
+             WI(i) .GT. 0 and WI(i+1) .LT. 0. If WANTT is .TRUE., then   
+             the eigenvalues are stored in the same order as on the   
+             diagonal of the Schur form returned in H, with   
+             WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal   
+             block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and   
+             WI(i+1) = -WI(i).   
+
+       ILOZ     (input) INTEGER   
+       IHIZ     (input) INTEGER   
+             Specify the rows of Z to which transformations must be   
+             applied if WANTZ is .TRUE..   
+             1 .LE. ILOZ .LE. ILO; IHI .LE. IHIZ .LE. N.   
+
+       Z     (input/output) DOUBLE PRECISION array, dimension (LDZ,IHI)   
+             If WANTZ is .FALSE., then Z is not referenced.   
+             If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is   
+             replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the   
+             orthogonal Schur factor of H(ILO:IHI,ILO:IHI).   
+             (The output value of Z when INFO.GT.0 is given under   
+             the description of INFO below.)   
+
+       LDZ   (input) INTEGER   
+             The leading dimension of the array Z.  if WANTZ is .TRUE.   
+             then LDZ.GE.MAX(1,IHIZ).  Otherwize, LDZ.GE.1.   
+
+       WORK  (workspace/output) DOUBLE PRECISION array, dimension LWORK   
+             On exit, if LWORK = -1, WORK(1) returns an estimate of   
+             the optimal value for LWORK.   
+
+       LWORK (input) INTEGER   
+             The dimension of the array WORK.  LWORK .GE. max(1,N)   
+             is sufficient, but LWORK typically as large as 6*N may   
+             be required for optimal performance.  A workspace query   
+             to determine the optimal workspace size is recommended.   
+
+             If LWORK = -1, then DLAQR4 does a workspace query.   
+             In this case, DLAQR4 checks the input parameters and   
+             estimates the optimal workspace size for the given   
+             values of N, ILO and IHI.  The estimate is returned   
+             in WORK(1).  No error message related to LWORK is   
+             issued by XERBLA.  Neither H nor Z are accessed.   
+
+
+       INFO  (output) INTEGER   
+               =  0:  successful exit   
+             .GT. 0:  if INFO = i, DLAQR4 failed to compute all of   
+                  the eigenvalues.  Elements 1:ilo-1 and i+1:n of WR   
+                  and WI contain those eigenvalues which have been   
+                  successfully computed.  (Failures are rare.)   
+
+                  If INFO .GT. 0 and WANT is .FALSE., then on exit,   
+                  the remaining unconverged eigenvalues are the eigen-   
+                  values of the upper Hessenberg matrix rows and   
+                  columns ILO through INFO of the final, output   
+                  value of H.   
+
+                  If INFO .GT. 0 and WANTT is .TRUE., then on exit   
+
+             (*)  (initial value of H)*U  = U*(final value of H)   
+
+                  where U is an orthogonal matrix.  The final   
+                  value of H is upper Hessenberg and quasi-triangular   
+                  in rows and columns INFO+1 through IHI.   
+
+                  If INFO .GT. 0 and WANTZ is .TRUE., then on exit   
+
+                    (final value of Z(ILO:IHI,ILOZ:IHIZ)   
+                     =  (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U   
+
+                  where U is the orthogonal matrix in (*) (regard-   
+                  less of the value of WANTT.)   
+
+                  If INFO .GT. 0 and WANTZ is .FALSE., then Z is not   
+                  accessed.   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+       References:   
+         K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+         Algorithm Part I: Maintaining Well Focused Shifts, and Level 3   
+         Performance, SIAM Journal of Matrix Analysis, volume 23, pages   
+         929--947, 2002.   
+
+         K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+         Algorithm Part II: Aggressive Early Deflation, SIAM Journal   
+         of Matrix Analysis, volume 23, pages 948--973, 2002.   
+
+       ================================================================   
+
+       ==== Matrices of order NTINY or smaller must be processed by   
+       .    DLAHQR because of insufficient subdiagonal scratch space.   
+       .    (This is a hard limit.) ====   
+
+       ==== Exceptional deflation windows:  try to cure rare   
+       .    slow convergence by varying the size of the   
+       .    deflation window after KEXNW iterations. ====   
+
+       ==== Exceptional shifts: try to cure rare slow convergence   
+       .    with ad-hoc exceptional shifts every KEXSH iterations.   
+       .    ====   
+
+       ==== The constants WILK1 and WILK2 are used to form the   
+       .    exceptional shifts. ====   
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --wr;
+    --wi;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+
+/*     ==== Quick return for N = 0: nothing to do. ==== */
+
+    if (*n == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    if (*n <= 11) {
+
+/*        ==== Tiny matrices must use DLAHQR. ==== */
+
+	lwkopt = 1;
+	if (*lwork != -1) {
+	    igraphdlahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], &
+		    wi[1], iloz, ihiz, &z__[z_offset], ldz, info);
+	}
+    } else {
+
+/*        ==== Use small bulge multi-shift QR with aggressive early   
+          .    deflation on larger-than-tiny matrices. ====   
+
+          ==== Hope for the best. ==== */
+
+	*info = 0;
+
+/*        ==== Set up job flags for ILAENV. ==== */
+
+	if (*wantt) {
+	    *(unsigned char *)jbcmpz = 'S';
+	} else {
+	    *(unsigned char *)jbcmpz = 'E';
+	}
+	if (*wantz) {
+	    *(unsigned char *)&jbcmpz[1] = 'V';
+	} else {
+	    *(unsigned char *)&jbcmpz[1] = 'N';
+	}
+
+/*        ==== NWR = recommended deflation window size.  At this   
+          .    point,  N .GT. NTINY = 11, so there is enough   
+          .    subdiagonal workspace for NWR.GE.2 as required.   
+          .    (In fact, there is enough subdiagonal space for   
+          .    NWR.GE.3.) ==== */
+
+	nwr = igraphilaenv_(&c__13, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6,
+		 (ftnlen)2);
+	nwr = max(2,nwr);
+/* Computing MIN */
+	i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2);
+	nwr = min(i__1,nwr);
+
+/*        ==== NSR = recommended number of simultaneous shifts.   
+          .    At this point N .GT. NTINY = 11, so there is at   
+          .    enough subdiagonal workspace for NSR to be even   
+          .    and greater than or equal to two as required. ==== */
+
+	nsr = igraphilaenv_(&c__15, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6,
+		 (ftnlen)2);
+/* Computing MIN */
+	i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - 
+		*ilo;
+	nsr = min(i__1,i__2);
+/* Computing MAX */
+	i__1 = 2, i__2 = nsr - nsr % 2;
+	nsr = max(i__1,i__2);
+
+/*        ==== Estimate optimal workspace ====   
+
+          ==== Workspace query call to DLAQR2 ==== */
+
+	i__1 = nwr + 1;
+	igraphdlaqr2_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, 
+		ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], &h__[
+		h_offset], ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], 
+		ldh, &work[1], &c_n1);
+
+/*        ==== Optimal workspace = MAX(DLAQR5, DLAQR2) ====   
+
+   Computing MAX */
+	i__1 = nsr * 3 / 2, i__2 = (integer) work[1];
+	lwkopt = max(i__1,i__2);
+
+/*        ==== Quick return in case of workspace query. ==== */
+
+	if (*lwork == -1) {
+	    work[1] = (doublereal) lwkopt;
+	    return 0;
+	}
+
+/*        ==== DLAHQR/DLAQR0 crossover point ==== */
+
+	nmin = igraphilaenv_(&c__12, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)
+		6, (ftnlen)2);
+	nmin = max(11,nmin);
+
+/*        ==== Nibble crossover point ==== */
+
+	nibble = igraphilaenv_(&c__14, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (
+		ftnlen)6, (ftnlen)2);
+	nibble = max(0,nibble);
+
+/*        ==== Accumulate reflections during ttswp?  Use block   
+          .    2-by-2 structure during matrix-matrix multiply? ==== */
+
+	kacc22 = igraphilaenv_(&c__16, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (
+		ftnlen)6, (ftnlen)2);
+	kacc22 = max(0,kacc22);
+	kacc22 = min(2,kacc22);
+
+/*        ==== NWMAX = the largest possible deflation window for   
+          .    which there is sufficient workspace. ====   
+
+   Computing MIN */
+	i__1 = (*n - 1) / 3, i__2 = *lwork / 2;
+	nwmax = min(i__1,i__2);
+	nw = nwmax;
+
+/*        ==== NSMAX = the Largest number of simultaneous shifts   
+          .    for which there is sufficient workspace. ====   
+
+   Computing MIN */
+	i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3;
+	nsmax = min(i__1,i__2);
+	nsmax -= nsmax % 2;
+
+/*        ==== NDFL: an iteration count restarted at deflation. ==== */
+
+	ndfl = 1;
+
+/*        ==== ITMAX = iteration limit ====   
+
+   Computing MAX */
+	i__1 = 10, i__2 = *ihi - *ilo + 1;
+	itmax = max(i__1,i__2) * 30;
+
+/*        ==== Last row and column in the active block ==== */
+
+	kbot = *ihi;
+
+/*        ==== Main Loop ==== */
+
+	i__1 = itmax;
+	for (it = 1; it <= i__1; ++it) {
+
+/*           ==== Done when KBOT falls below ILO ==== */
+
+	    if (kbot < *ilo) {
+		goto L90;
+	    }
+
+/*           ==== Locate active block ==== */
+
+	    i__2 = *ilo + 1;
+	    for (k = kbot; k >= i__2; --k) {
+		if (h__[k + (k - 1) * h_dim1] == 0.) {
+		    goto L20;
+		}
+/* L10: */
+	    }
+	    k = *ilo;
+L20:
+	    ktop = k;
+
+/*           ==== Select deflation window size:   
+             .    Typical Case:   
+             .      If possible and advisable, nibble the entire   
+             .      active block.  If not, use size MIN(NWR,NWMAX)   
+             .      or MIN(NWR+1,NWMAX) depending upon which has   
+             .      the smaller corresponding subdiagonal entry   
+             .      (a heuristic).   
+             .   
+             .    Exceptional Case:   
+             .      If there have been no deflations in KEXNW or   
+             .      more iterations, then vary the deflation window   
+             .      size.   At first, because, larger windows are,   
+             .      in general, more powerful than smaller ones,   
+             .      rapidly increase the window to the maximum possible.   
+             .      Then, gradually reduce the window size. ==== */
+
+	    nh = kbot - ktop + 1;
+	    nwupbd = min(nh,nwmax);
+	    if (ndfl < 5) {
+		nw = min(nwupbd,nwr);
+	    } else {
+/* Computing MIN */
+		i__2 = nwupbd, i__3 = nw << 1;
+		nw = min(i__2,i__3);
+	    }
+	    if (nw < nwmax) {
+		if (nw >= nh - 1) {
+		    nw = nh;
+		} else {
+		    kwtop = kbot - nw + 1;
+		    if ((d__1 = h__[kwtop + (kwtop - 1) * h_dim1], abs(d__1)) 
+			    > (d__2 = h__[kwtop - 1 + (kwtop - 2) * h_dim1], 
+			    abs(d__2))) {
+			++nw;
+		    }
+		}
+	    }
+	    if (ndfl < 5) {
+		ndec = -1;
+	    } else if (ndec >= 0 || nw >= nwupbd) {
+		++ndec;
+		if (nw - ndec < 2) {
+		    ndec = 0;
+		}
+		nw -= ndec;
+	    }
+
+/*           ==== Aggressive early deflation:   
+             .    split workspace under the subdiagonal into   
+             .      - an nw-by-nw work array V in the lower   
+             .        left-hand-corner,   
+             .      - an NW-by-at-least-NW-but-more-is-better   
+             .        (NW-by-NHO) horizontal work array along   
+             .        the bottom edge,   
+             .      - an at-least-NW-but-more-is-better (NHV-by-NW)   
+             .        vertical work array along the left-hand-edge.   
+             .        ==== */
+
+	    kv = *n - nw + 1;
+	    kt = nw + 1;
+	    nho = *n - nw - 1 - kt + 1;
+	    kwv = nw + 2;
+	    nve = *n - nw - kwv + 1;
+
+/*           ==== Aggressive early deflation ==== */
+
+	    igraphdlaqr2_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, 
+		    iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1],
+		     &h__[kv + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], 
+		    ldh, &nve, &h__[kwv + h_dim1], ldh, &work[1], lwork);
+
+/*           ==== Adjust KBOT accounting for new deflations. ==== */
+
+	    kbot -= ld;
+
+/*           ==== KS points to the shifts. ==== */
+
+	    ks = kbot - ls + 1;
+
+/*           ==== Skip an expensive QR sweep if there is a (partly   
+             .    heuristic) reason to expect that many eigenvalues   
+             .    will deflate without it.  Here, the QR sweep is   
+             .    skipped if many eigenvalues have just been deflated   
+             .    or if the remaining active block is small. */
+
+	    if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min(
+		    nmin,nwmax)) {
+
+/*              ==== NS = nominal number of simultaneous shifts.   
+                .    This may be lowered (slightly) if DLAQR2   
+                .    did not provide that many shifts. ====   
+
+   Computing MIN   
+   Computing MAX */
+		i__4 = 2, i__5 = kbot - ktop;
+		i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5);
+		ns = min(i__2,i__3);
+		ns -= ns % 2;
+
+/*              ==== If there have been no deflations   
+                .    in a multiple of KEXSH iterations,   
+                .    then try exceptional shifts.   
+                .    Otherwise use shifts provided by   
+                .    DLAQR2 above or from the eigenvalues   
+                .    of a trailing principal submatrix. ==== */
+
+		if (ndfl % 6 == 0) {
+		    ks = kbot - ns + 1;
+/* Computing MAX */
+		    i__3 = ks + 1, i__4 = ktop + 2;
+		    i__2 = max(i__3,i__4);
+		    for (i__ = kbot; i__ >= i__2; i__ += -2) {
+			ss = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1))
+				 + (d__2 = h__[i__ - 1 + (i__ - 2) * h_dim1], 
+				abs(d__2));
+			aa = ss * .75 + h__[i__ + i__ * h_dim1];
+			bb = ss;
+			cc = ss * -.4375;
+			dd = aa;
+			igraphdlanv2_(&aa, &bb, &cc, &dd, &wr[i__ - 1], &wi[i__ - 1]
+				, &wr[i__], &wi[i__], &cs, &sn);
+/* L30: */
+		    }
+		    if (ks == ktop) {
+			wr[ks + 1] = h__[ks + 1 + (ks + 1) * h_dim1];
+			wi[ks + 1] = 0.;
+			wr[ks] = wr[ks + 1];
+			wi[ks] = wi[ks + 1];
+		    }
+		} else {
+
+/*                 ==== Got NS/2 or fewer shifts? Use DLAHQR   
+                   .    on a trailing principal submatrix to   
+                   .    get more. (Since NS.LE.NSMAX.LE.(N+6)/9,   
+                   .    there is enough space below the subdiagonal   
+                   .    to fit an NS-by-NS scratch array.) ==== */
+
+		    if (kbot - ks + 1 <= ns / 2) {
+			ks = kbot - ns + 1;
+			kt = *n - ns + 1;
+			igraphdlacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, &
+				h__[kt + h_dim1], ldh);
+			igraphdlahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[kt 
+				+ h_dim1], ldh, &wr[ks], &wi[ks], &c__1, &
+				c__1, zdum, &c__1, &inf);
+			ks += inf;
+
+/*                    ==== In case of a rare QR failure use   
+                      .    eigenvalues of the trailing 2-by-2   
+                      .    principal submatrix.  ==== */
+
+			if (ks >= kbot) {
+			    aa = h__[kbot - 1 + (kbot - 1) * h_dim1];
+			    cc = h__[kbot + (kbot - 1) * h_dim1];
+			    bb = h__[kbot - 1 + kbot * h_dim1];
+			    dd = h__[kbot + kbot * h_dim1];
+			    igraphdlanv2_(&aa, &bb, &cc, &dd, &wr[kbot - 1], &wi[
+				    kbot - 1], &wr[kbot], &wi[kbot], &cs, &sn)
+				    ;
+			    ks = kbot - 1;
+			}
+		    }
+
+		    if (kbot - ks + 1 > ns) {
+
+/*                    ==== Sort the shifts (Helps a little)   
+                      .    Bubble sort keeps complex conjugate   
+                      .    pairs together. ==== */
+
+			sorted = FALSE_;
+			i__2 = ks + 1;
+			for (k = kbot; k >= i__2; --k) {
+			    if (sorted) {
+				goto L60;
+			    }
+			    sorted = TRUE_;
+			    i__3 = k - 1;
+			    for (i__ = ks; i__ <= i__3; ++i__) {
+				if ((d__1 = wr[i__], abs(d__1)) + (d__2 = wi[
+					i__], abs(d__2)) < (d__3 = wr[i__ + 1]
+					, abs(d__3)) + (d__4 = wi[i__ + 1], 
+					abs(d__4))) {
+				    sorted = FALSE_;
+
+				    swap = wr[i__];
+				    wr[i__] = wr[i__ + 1];
+				    wr[i__ + 1] = swap;
+
+				    swap = wi[i__];
+				    wi[i__] = wi[i__ + 1];
+				    wi[i__ + 1] = swap;
+				}
+/* L40: */
+			    }
+/* L50: */
+			}
+L60:
+			;
+		    }
+
+/*                 ==== Shuffle shifts into pairs of real shifts   
+                   .    and pairs of complex conjugate shifts   
+                   .    assuming complex conjugate shifts are   
+                   .    already adjacent to one another. (Yes,   
+                   .    they are.)  ==== */
+
+		    i__2 = ks + 2;
+		    for (i__ = kbot; i__ >= i__2; i__ += -2) {
+			if (wi[i__] != -wi[i__ - 1]) {
+
+			    swap = wr[i__];
+			    wr[i__] = wr[i__ - 1];
+			    wr[i__ - 1] = wr[i__ - 2];
+			    wr[i__ - 2] = swap;
+
+			    swap = wi[i__];
+			    wi[i__] = wi[i__ - 1];
+			    wi[i__ - 1] = wi[i__ - 2];
+			    wi[i__ - 2] = swap;
+			}
+/* L70: */
+		    }
+		}
+
+/*              ==== If there are only two shifts and both are   
+                .    real, then use only one.  ==== */
+
+		if (kbot - ks + 1 == 2) {
+		    if (wi[kbot] == 0.) {
+			if ((d__1 = wr[kbot] - h__[kbot + kbot * h_dim1], abs(
+				d__1)) < (d__2 = wr[kbot - 1] - h__[kbot + 
+				kbot * h_dim1], abs(d__2))) {
+			    wr[kbot - 1] = wr[kbot];
+			} else {
+			    wr[kbot] = wr[kbot - 1];
+			}
+		    }
+		}
+
+/*              ==== Use up to NS of the the smallest magnatiude   
+                .    shifts.  If there aren't NS shifts available,   
+                .    then use them all, possibly dropping one to   
+                .    make the number of shifts even. ====   
+
+   Computing MIN */
+		i__2 = ns, i__3 = kbot - ks + 1;
+		ns = min(i__2,i__3);
+		ns -= ns % 2;
+		ks = kbot - ns + 1;
+
+/*              ==== Small-bulge multi-shift QR sweep:   
+                .    split workspace under the subdiagonal into   
+                .    - a KDU-by-KDU work array U in the lower   
+                .      left-hand-corner,   
+                .    - a KDU-by-at-least-KDU-but-more-is-better   
+                .      (KDU-by-NHo) horizontal work array WH along   
+                .      the bottom edge,   
+                .    - and an at-least-KDU-but-more-is-better-by-KDU   
+                .      (NVE-by-KDU) vertical work WV arrow along   
+                .      the left-hand-edge. ==== */
+
+		kdu = ns * 3 - 3;
+		ku = *n - kdu + 1;
+		kwh = kdu + 1;
+		nho = *n - kdu - 3 - (kdu + 1) + 1;
+		kwv = kdu + 4;
+		nve = *n - kdu - kwv + 1;
+
+/*              ==== Small-bulge multi-shift QR sweep ==== */
+
+		igraphdlaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &wr[ks], 
+			&wi[ks], &h__[h_offset], ldh, iloz, ihiz, &z__[
+			z_offset], ldz, &work[1], &c__3, &h__[ku + h_dim1], 
+			ldh, &nve, &h__[kwv + h_dim1], ldh, &nho, &h__[ku + 
+			kwh * h_dim1], ldh);
+	    }
+
+/*           ==== Note progress (or the lack of it). ==== */
+
+	    if (ld > 0) {
+		ndfl = 1;
+	    } else {
+		++ndfl;
+	    }
+
+/*           ==== End of main loop ====   
+   L80: */
+	}
+
+/*        ==== Iteration limit exceeded.  Set INFO to show where   
+          .    the problem occurred and exit. ==== */
+
+	*info = kbot;
+L90:
+	;
+    }
+
+/*     ==== Return the optimal value of LWORK. ==== */
+
+    work[1] = (doublereal) lwkopt;
+
+/*     ==== End of DLAQR4 ==== */
+
+    return 0;
+} /* igraphdlaqr4_ */
+
diff --git a/src/lapack/dlaqr5.c b/src/lapack/dlaqr5.c
new file mode 100644
index 0000000..27a572d
--- /dev/null
+++ b/src/lapack/dlaqr5.c
@@ -0,0 +1,1012 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b7 = 0.;
+static doublereal c_b8 = 1.;
+static integer c__3 = 3;
+static integer c__1 = 1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdlaqr5_(logical *wantt, logical *wantz, integer *kacc22, 
+	integer *n, integer *ktop, integer *kbot, integer *nshfts, doublereal 
+	*sr, doublereal *si, doublereal *h__, integer *ldh, integer *iloz, 
+	integer *ihiz, doublereal *z__, integer *ldz, doublereal *v, integer *
+	ldv, doublereal *u, integer *ldu, integer *nv, doublereal *wv, 
+	integer *ldwv, integer *nh, doublereal *wh, integer *ldwh)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, u_dim1, u_offset, v_dim1, v_offset, wh_dim1, 
+	    wh_offset, wv_dim1, wv_offset, z_dim1, z_offset, i__1, i__2, i__3,
+	     i__4, i__5, i__6, i__7;
+    doublereal d__1, d__2, d__3, d__4, d__5;
+
+    /* Local variables */
+    integer i__, j, k, m, i2, j2, i4, j4, k1;
+    doublereal h11, h12, h21, h22;
+    integer m22, ns, nu;
+    doublereal vt[3], scl;
+    integer kdu, kms;
+    doublereal ulp;
+    integer knz, kzs;
+    doublereal tst1, tst2, beta;
+    logical blk22, bmp22;
+    integer mend, jcol, jlen, jbot, mbot;
+    doublereal swap;
+    integer jtop, jrow, mtop;
+    doublereal alpha;
+    logical accum;
+    extern /* Subroutine */ int igraphdgemm_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    integer ndcol, incol, krcol, nbmps;
+    extern /* Subroutine */ int igraphdtrmm_(char *, char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdlaqr1_(
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *), igraphdlabad_(doublereal *, 
+	    doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlarfg_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *), igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *);
+    doublereal safmin;
+    extern /* Subroutine */ int igraphdlaset_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *);
+    doublereal safmax, refsum;
+    integer mstart;
+    doublereal smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.0) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2010   
+
+
+       This auxiliary subroutine called by DLAQR0 performs a   
+       single small-bulge multi-shift QR sweep.   
+
+        WANTT  (input) logical scalar   
+               WANTT = .true. if the quasi-triangular Schur factor   
+               is being computed.  WANTT is set to .false. otherwise.   
+
+        WANTZ  (input) logical scalar   
+               WANTZ = .true. if the orthogonal Schur factor is being   
+               computed.  WANTZ is set to .false. otherwise.   
+
+        KACC22 (input) integer with value 0, 1, or 2.   
+               Specifies the computation mode of far-from-diagonal   
+               orthogonal updates.   
+          = 0: DLAQR5 does not accumulate reflections and does not   
+               use matrix-matrix multiply to update far-from-diagonal   
+               matrix entries.   
+          = 1: DLAQR5 accumulates reflections and uses matrix-matrix   
+               multiply to update the far-from-diagonal matrix entries.   
+          = 2: DLAQR5 accumulates reflections, uses matrix-matrix   
+               multiply to update the far-from-diagonal matrix entries,   
+               and takes advantage of 2-by-2 block structure during   
+               matrix multiplies.   
+
+        N      (input) integer scalar   
+               N is the order of the Hessenberg matrix H upon which this   
+               subroutine operates.   
+
+        KTOP   (input) integer scalar   
+        KBOT   (input) integer scalar   
+               These are the first and last rows and columns of an   
+               isolated diagonal block upon which the QR sweep is to be   
+               applied. It is assumed without a check that   
+                         either KTOP = 1  or   H(KTOP,KTOP-1) = 0   
+               and   
+                         either KBOT = N  or   H(KBOT+1,KBOT) = 0.   
+
+        NSHFTS (input) integer scalar   
+               NSHFTS gives the number of simultaneous shifts.  NSHFTS   
+               must be positive and even.   
+
+        SR     (input/output) DOUBLE PRECISION array of size (NSHFTS)   
+        SI     (input/output) DOUBLE PRECISION array of size (NSHFTS)   
+               SR contains the real parts and SI contains the imaginary   
+               parts of the NSHFTS shifts of origin that define the   
+               multi-shift QR sweep.  On output SR and SI may be   
+               reordered.   
+
+        H      (input/output) DOUBLE PRECISION array of size (LDH,N)   
+               On input H contains a Hessenberg matrix.  On output a   
+               multi-shift QR sweep with shifts SR(J)+i*SI(J) is applied   
+               to the isolated diagonal block in rows and columns KTOP   
+               through KBOT.   
+
+        LDH    (input) integer scalar   
+               LDH is the leading dimension of H just as declared in the   
+               calling procedure.  LDH.GE.MAX(1,N).   
+
+        ILOZ   (input) INTEGER   
+        IHIZ   (input) INTEGER   
+               Specify the rows of Z to which transformations must be   
+               applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N   
+
+        Z      (input/output) DOUBLE PRECISION array of size (LDZ,IHI)   
+               If WANTZ = .TRUE., then the QR Sweep orthogonal   
+               similarity transformation is accumulated into   
+               Z(ILOZ:IHIZ,ILO:IHI) from the right.   
+               If WANTZ = .FALSE., then Z is unreferenced.   
+
+        LDZ    (input) integer scalar   
+               LDA is the leading dimension of Z just as declared in   
+               the calling procedure. LDZ.GE.N.   
+
+        V      (workspace) DOUBLE PRECISION array of size (LDV,NSHFTS/2)   
+
+        LDV    (input) integer scalar   
+               LDV is the leading dimension of V as declared in the   
+               calling procedure.  LDV.GE.3.   
+
+        U      (workspace) DOUBLE PRECISION array of size   
+               (LDU,3*NSHFTS-3)   
+
+        LDU    (input) integer scalar   
+               LDU is the leading dimension of U just as declared in the   
+               in the calling subroutine.  LDU.GE.3*NSHFTS-3.   
+
+        NH     (input) integer scalar   
+               NH is the number of columns in array WH available for   
+               workspace. NH.GE.1.   
+
+        WH     (workspace) DOUBLE PRECISION array of size (LDWH,NH)   
+
+        LDWH   (input) integer scalar   
+               Leading dimension of WH just as declared in the   
+               calling procedure.  LDWH.GE.3*NSHFTS-3.   
+
+        NV     (input) integer scalar   
+               NV is the number of rows in WV agailable for workspace.   
+               NV.GE.1.   
+
+        WV     (workspace) DOUBLE PRECISION array of size   
+               (LDWV,3*NSHFTS-3)   
+
+        LDWV   (input) integer scalar   
+               LDWV is the leading dimension of WV as declared in the   
+               in the calling subroutine.  LDWV.GE.NV.   
+
+       ================================================================   
+       Based on contributions by   
+          Karen Braman and Ralph Byers, Department of Mathematics,   
+          University of Kansas, USA   
+
+       ================================================================   
+       Reference:   
+
+       K. Braman, R. Byers and R. Mathias, The Multi-Shift QR   
+       Algorithm Part I: Maintaining Well Focused Shifts, and   
+       Level 3 Performance, SIAM Journal of Matrix Analysis,   
+       volume 23, pages 929--947, 2002.   
+
+       ================================================================   
+
+
+       ==== If there are no shifts, then there is nothing to do. ====   
+
+       Parameter adjustments */
+    --sr;
+    --si;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    u_dim1 = *ldu;
+    u_offset = 1 + u_dim1;
+    u -= u_offset;
+    wv_dim1 = *ldwv;
+    wv_offset = 1 + wv_dim1;
+    wv -= wv_offset;
+    wh_dim1 = *ldwh;
+    wh_offset = 1 + wh_dim1;
+    wh -= wh_offset;
+
+    /* Function Body */
+    if (*nshfts < 2) {
+	return 0;
+    }
+
+/*     ==== If the active block is empty or 1-by-1, then there   
+       .    is nothing to do. ==== */
+
+    if (*ktop >= *kbot) {
+	return 0;
+    }
+
+/*     ==== Shuffle shifts into pairs of real shifts and pairs   
+       .    of complex conjugate shifts assuming complex   
+       .    conjugate shifts are already adjacent to one   
+       .    another. ==== */
+
+    i__1 = *nshfts - 2;
+    for (i__ = 1; i__ <= i__1; i__ += 2) {
+	if (si[i__] != -si[i__ + 1]) {
+
+	    swap = sr[i__];
+	    sr[i__] = sr[i__ + 1];
+	    sr[i__ + 1] = sr[i__ + 2];
+	    sr[i__ + 2] = swap;
+
+	    swap = si[i__];
+	    si[i__] = si[i__ + 1];
+	    si[i__ + 1] = si[i__ + 2];
+	    si[i__ + 2] = swap;
+	}
+/* L10: */
+    }
+
+/*     ==== NSHFTS is supposed to be even, but if it is odd,   
+       .    then simply reduce it by one.  The shuffle above   
+       .    ensures that the dropped shift is real and that   
+       .    the remaining shifts are paired. ==== */
+
+    ns = *nshfts - *nshfts % 2;
+
+/*     ==== Machine constants for deflation ==== */
+
+    safmin = igraphdlamch_("SAFE MINIMUM");
+    safmax = 1. / safmin;
+    igraphdlabad_(&safmin, &safmax);
+    ulp = igraphdlamch_("PRECISION");
+    smlnum = safmin * ((doublereal) (*n) / ulp);
+
+/*     ==== Use accumulated reflections to update far-from-diagonal   
+       .    entries ? ==== */
+
+    accum = *kacc22 == 1 || *kacc22 == 2;
+
+/*     ==== If so, exploit the 2-by-2 block structure? ==== */
+
+    blk22 = ns > 2 && *kacc22 == 2;
+
+/*     ==== clear trash ==== */
+
+    if (*ktop + 2 <= *kbot) {
+	h__[*ktop + 2 + *ktop * h_dim1] = 0.;
+    }
+
+/*     ==== NBMPS = number of 2-shift bulges in the chain ==== */
+
+    nbmps = ns / 2;
+
+/*     ==== KDU = width of slab ==== */
+
+    kdu = nbmps * 6 - 3;
+
+/*     ==== Create and chase chains of NBMPS bulges ==== */
+
+    i__1 = *kbot - 2;
+    i__2 = nbmps * 3 - 2;
+    for (incol = (1 - nbmps) * 3 + *ktop - 1; i__2 < 0 ? incol >= i__1 : 
+	    incol <= i__1; incol += i__2) {
+	ndcol = incol + kdu;
+	if (accum) {
+	    igraphdlaset_("ALL", &kdu, &kdu, &c_b7, &c_b8, &u[u_offset], ldu);
+	}
+
+/*        ==== Near-the-diagonal bulge chase.  The following loop   
+          .    performs the near-the-diagonal part of a small bulge   
+          .    multi-shift QR sweep.  Each 6*NBMPS-2 column diagonal   
+          .    chunk extends from column INCOL to column NDCOL   
+          .    (including both column INCOL and column NDCOL). The   
+          .    following loop chases a 3*NBMPS column long chain of   
+          .    NBMPS bulges 3*NBMPS-2 columns to the right.  (INCOL   
+          .    may be less than KTOP and and NDCOL may be greater than   
+          .    KBOT indicating phantom columns from which to chase   
+          .    bulges before they are actually introduced or to which   
+          .    to chase bulges beyond column KBOT.)  ====   
+
+   Computing MIN */
+	i__4 = incol + nbmps * 3 - 3, i__5 = *kbot - 2;
+	i__3 = min(i__4,i__5);
+	for (krcol = incol; krcol <= i__3; ++krcol) {
+
+/*           ==== Bulges number MTOP to MBOT are active double implicit   
+             .    shift bulges.  There may or may not also be small   
+             .    2-by-2 bulge, if there is room.  The inactive bulges   
+             .    (if any) must wait until the active bulges have moved   
+             .    down the diagonal to make room.  The phantom matrix   
+             .    paradigm described above helps keep track.  ====   
+
+   Computing MAX */
+	    i__4 = 1, i__5 = (*ktop - 1 - krcol + 2) / 3 + 1;
+	    mtop = max(i__4,i__5);
+/* Computing MIN */
+	    i__4 = nbmps, i__5 = (*kbot - krcol) / 3;
+	    mbot = min(i__4,i__5);
+	    m22 = mbot + 1;
+	    bmp22 = mbot < nbmps && krcol + (m22 - 1) * 3 == *kbot - 2;
+
+/*           ==== Generate reflections to chase the chain right   
+             .    one column.  (The minimum value of K is KTOP-1.) ==== */
+
+	    i__4 = mbot;
+	    for (m = mtop; m <= i__4; ++m) {
+		k = krcol + (m - 1) * 3;
+		if (k == *ktop - 1) {
+		    igraphdlaqr1_(&c__3, &h__[*ktop + *ktop * h_dim1], ldh, &sr[(m 
+			    << 1) - 1], &si[(m << 1) - 1], &sr[m * 2], &si[m *
+			     2], &v[m * v_dim1 + 1]);
+		    alpha = v[m * v_dim1 + 1];
+		    igraphdlarfg_(&c__3, &alpha, &v[m * v_dim1 + 2], &c__1, &v[m * 
+			    v_dim1 + 1]);
+		} else {
+		    beta = h__[k + 1 + k * h_dim1];
+		    v[m * v_dim1 + 2] = h__[k + 2 + k * h_dim1];
+		    v[m * v_dim1 + 3] = h__[k + 3 + k * h_dim1];
+		    igraphdlarfg_(&c__3, &beta, &v[m * v_dim1 + 2], &c__1, &v[m * 
+			    v_dim1 + 1]);
+
+/*                 ==== A Bulge may collapse because of vigilant   
+                   .    deflation or destructive underflow.  In the   
+                   .    underflow case, try the two-small-subdiagonals   
+                   .    trick to try to reinflate the bulge.  ==== */
+
+		    if (h__[k + 3 + k * h_dim1] != 0. || h__[k + 3 + (k + 1) *
+			     h_dim1] != 0. || h__[k + 3 + (k + 2) * h_dim1] ==
+			     0.) {
+
+/*                    ==== Typical case: not collapsed (yet). ==== */
+
+			h__[k + 1 + k * h_dim1] = beta;
+			h__[k + 2 + k * h_dim1] = 0.;
+			h__[k + 3 + k * h_dim1] = 0.;
+		    } else {
+
+/*                    ==== Atypical case: collapsed.  Attempt to   
+                      .    reintroduce ignoring H(K+1,K) and H(K+2,K).   
+                      .    If the fill resulting from the new   
+                      .    reflector is too large, then abandon it.   
+                      .    Otherwise, use the new one. ==== */
+
+			igraphdlaqr1_(&c__3, &h__[k + 1 + (k + 1) * h_dim1], ldh, &
+				sr[(m << 1) - 1], &si[(m << 1) - 1], &sr[m * 
+				2], &si[m * 2], vt);
+			alpha = vt[0];
+			igraphdlarfg_(&c__3, &alpha, &vt[1], &c__1, vt);
+			refsum = vt[0] * (h__[k + 1 + k * h_dim1] + vt[1] * 
+				h__[k + 2 + k * h_dim1]);
+
+			if ((d__1 = h__[k + 2 + k * h_dim1] - refsum * vt[1], 
+				abs(d__1)) + (d__2 = refsum * vt[2], abs(d__2)
+				) > ulp * ((d__3 = h__[k + k * h_dim1], abs(
+				d__3)) + (d__4 = h__[k + 1 + (k + 1) * h_dim1]
+				, abs(d__4)) + (d__5 = h__[k + 2 + (k + 2) * 
+				h_dim1], abs(d__5)))) {
+
+/*                       ==== Starting a new bulge here would   
+                         .    create non-negligible fill.  Use   
+                         .    the old one with trepidation. ==== */
+
+			    h__[k + 1 + k * h_dim1] = beta;
+			    h__[k + 2 + k * h_dim1] = 0.;
+			    h__[k + 3 + k * h_dim1] = 0.;
+			} else {
+
+/*                       ==== Stating a new bulge here would   
+                         .    create only negligible fill.   
+                         .    Replace the old reflector with   
+                         .    the new one. ==== */
+
+			    h__[k + 1 + k * h_dim1] -= refsum;
+			    h__[k + 2 + k * h_dim1] = 0.;
+			    h__[k + 3 + k * h_dim1] = 0.;
+			    v[m * v_dim1 + 1] = vt[0];
+			    v[m * v_dim1 + 2] = vt[1];
+			    v[m * v_dim1 + 3] = vt[2];
+			}
+		    }
+		}
+/* L20: */
+	    }
+
+/*           ==== Generate a 2-by-2 reflection, if needed. ==== */
+
+	    k = krcol + (m22 - 1) * 3;
+	    if (bmp22) {
+		if (k == *ktop - 1) {
+		    igraphdlaqr1_(&c__2, &h__[k + 1 + (k + 1) * h_dim1], ldh, &sr[(
+			    m22 << 1) - 1], &si[(m22 << 1) - 1], &sr[m22 * 2],
+			     &si[m22 * 2], &v[m22 * v_dim1 + 1]);
+		    beta = v[m22 * v_dim1 + 1];
+		    igraphdlarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 
+			    * v_dim1 + 1]);
+		} else {
+		    beta = h__[k + 1 + k * h_dim1];
+		    v[m22 * v_dim1 + 2] = h__[k + 2 + k * h_dim1];
+		    igraphdlarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 
+			    * v_dim1 + 1]);
+		    h__[k + 1 + k * h_dim1] = beta;
+		    h__[k + 2 + k * h_dim1] = 0.;
+		}
+	    }
+
+/*           ==== Multiply H by reflections from the left ==== */
+
+	    if (accum) {
+		jbot = min(ndcol,*kbot);
+	    } else if (*wantt) {
+		jbot = *n;
+	    } else {
+		jbot = *kbot;
+	    }
+	    i__4 = jbot;
+	    for (j = max(*ktop,krcol); j <= i__4; ++j) {
+/* Computing MIN */
+		i__5 = mbot, i__6 = (j - krcol + 2) / 3;
+		mend = min(i__5,i__6);
+		i__5 = mend;
+		for (m = mtop; m <= i__5; ++m) {
+		    k = krcol + (m - 1) * 3;
+		    refsum = v[m * v_dim1 + 1] * (h__[k + 1 + j * h_dim1] + v[
+			    m * v_dim1 + 2] * h__[k + 2 + j * h_dim1] + v[m * 
+			    v_dim1 + 3] * h__[k + 3 + j * h_dim1]);
+		    h__[k + 1 + j * h_dim1] -= refsum;
+		    h__[k + 2 + j * h_dim1] -= refsum * v[m * v_dim1 + 2];
+		    h__[k + 3 + j * h_dim1] -= refsum * v[m * v_dim1 + 3];
+/* L30: */
+		}
+/* L40: */
+	    }
+	    if (bmp22) {
+		k = krcol + (m22 - 1) * 3;
+/* Computing MAX */
+		i__4 = k + 1;
+		i__5 = jbot;
+		for (j = max(i__4,*ktop); j <= i__5; ++j) {
+		    refsum = v[m22 * v_dim1 + 1] * (h__[k + 1 + j * h_dim1] + 
+			    v[m22 * v_dim1 + 2] * h__[k + 2 + j * h_dim1]);
+		    h__[k + 1 + j * h_dim1] -= refsum;
+		    h__[k + 2 + j * h_dim1] -= refsum * v[m22 * v_dim1 + 2];
+/* L50: */
+		}
+	    }
+
+/*           ==== Multiply H by reflections from the right.   
+             .    Delay filling in the last row until the   
+             .    vigilant deflation check is complete. ==== */
+
+	    if (accum) {
+		jtop = max(*ktop,incol);
+	    } else if (*wantt) {
+		jtop = 1;
+	    } else {
+		jtop = *ktop;
+	    }
+	    i__5 = mbot;
+	    for (m = mtop; m <= i__5; ++m) {
+		if (v[m * v_dim1 + 1] != 0.) {
+		    k = krcol + (m - 1) * 3;
+/* Computing MIN */
+		    i__6 = *kbot, i__7 = k + 3;
+		    i__4 = min(i__6,i__7);
+		    for (j = jtop; j <= i__4; ++j) {
+			refsum = v[m * v_dim1 + 1] * (h__[j + (k + 1) * 
+				h_dim1] + v[m * v_dim1 + 2] * h__[j + (k + 2) 
+				* h_dim1] + v[m * v_dim1 + 3] * h__[j + (k + 
+				3) * h_dim1]);
+			h__[j + (k + 1) * h_dim1] -= refsum;
+			h__[j + (k + 2) * h_dim1] -= refsum * v[m * v_dim1 + 
+				2];
+			h__[j + (k + 3) * h_dim1] -= refsum * v[m * v_dim1 + 
+				3];
+/* L60: */
+		    }
+
+		    if (accum) {
+
+/*                    ==== Accumulate U. (If necessary, update Z later   
+                      .    with with an efficient matrix-matrix   
+                      .    multiply.) ==== */
+
+			kms = k - incol;
+/* Computing MAX */
+			i__4 = 1, i__6 = *ktop - incol;
+			i__7 = kdu;
+			for (j = max(i__4,i__6); j <= i__7; ++j) {
+			    refsum = v[m * v_dim1 + 1] * (u[j + (kms + 1) * 
+				    u_dim1] + v[m * v_dim1 + 2] * u[j + (kms 
+				    + 2) * u_dim1] + v[m * v_dim1 + 3] * u[j 
+				    + (kms + 3) * u_dim1]);
+			    u[j + (kms + 1) * u_dim1] -= refsum;
+			    u[j + (kms + 2) * u_dim1] -= refsum * v[m * 
+				    v_dim1 + 2];
+			    u[j + (kms + 3) * u_dim1] -= refsum * v[m * 
+				    v_dim1 + 3];
+/* L70: */
+			}
+		    } else if (*wantz) {
+
+/*                    ==== U is not accumulated, so update Z   
+                      .    now by multiplying by reflections   
+                      .    from the right. ==== */
+
+			i__7 = *ihiz;
+			for (j = *iloz; j <= i__7; ++j) {
+			    refsum = v[m * v_dim1 + 1] * (z__[j + (k + 1) * 
+				    z_dim1] + v[m * v_dim1 + 2] * z__[j + (k 
+				    + 2) * z_dim1] + v[m * v_dim1 + 3] * z__[
+				    j + (k + 3) * z_dim1]);
+			    z__[j + (k + 1) * z_dim1] -= refsum;
+			    z__[j + (k + 2) * z_dim1] -= refsum * v[m * 
+				    v_dim1 + 2];
+			    z__[j + (k + 3) * z_dim1] -= refsum * v[m * 
+				    v_dim1 + 3];
+/* L80: */
+			}
+		    }
+		}
+/* L90: */
+	    }
+
+/*           ==== Special case: 2-by-2 reflection (if needed) ==== */
+
+	    k = krcol + (m22 - 1) * 3;
+	    if (bmp22) {
+		if (v[m22 * v_dim1 + 1] != 0.) {
+/* Computing MIN */
+		    i__7 = *kbot, i__4 = k + 3;
+		    i__5 = min(i__7,i__4);
+		    for (j = jtop; j <= i__5; ++j) {
+			refsum = v[m22 * v_dim1 + 1] * (h__[j + (k + 1) * 
+				h_dim1] + v[m22 * v_dim1 + 2] * h__[j + (k + 
+				2) * h_dim1]);
+			h__[j + (k + 1) * h_dim1] -= refsum;
+			h__[j + (k + 2) * h_dim1] -= refsum * v[m22 * v_dim1 
+				+ 2];
+/* L100: */
+		    }
+
+		    if (accum) {
+			kms = k - incol;
+/* Computing MAX */
+			i__5 = 1, i__7 = *ktop - incol;
+			i__4 = kdu;
+			for (j = max(i__5,i__7); j <= i__4; ++j) {
+			    refsum = v[m22 * v_dim1 + 1] * (u[j + (kms + 1) * 
+				    u_dim1] + v[m22 * v_dim1 + 2] * u[j + (
+				    kms + 2) * u_dim1]);
+			    u[j + (kms + 1) * u_dim1] -= refsum;
+			    u[j + (kms + 2) * u_dim1] -= refsum * v[m22 * 
+				    v_dim1 + 2];
+/* L110: */
+			}
+		    } else if (*wantz) {
+			i__4 = *ihiz;
+			for (j = *iloz; j <= i__4; ++j) {
+			    refsum = v[m22 * v_dim1 + 1] * (z__[j + (k + 1) * 
+				    z_dim1] + v[m22 * v_dim1 + 2] * z__[j + (
+				    k + 2) * z_dim1]);
+			    z__[j + (k + 1) * z_dim1] -= refsum;
+			    z__[j + (k + 2) * z_dim1] -= refsum * v[m22 * 
+				    v_dim1 + 2];
+/* L120: */
+			}
+		    }
+		}
+	    }
+
+/*           ==== Vigilant deflation check ==== */
+
+	    mstart = mtop;
+	    if (krcol + (mstart - 1) * 3 < *ktop) {
+		++mstart;
+	    }
+	    mend = mbot;
+	    if (bmp22) {
+		++mend;
+	    }
+	    if (krcol == *kbot - 2) {
+		++mend;
+	    }
+	    i__4 = mend;
+	    for (m = mstart; m <= i__4; ++m) {
+/* Computing MIN */
+		i__5 = *kbot - 1, i__7 = krcol + (m - 1) * 3;
+		k = min(i__5,i__7);
+
+/*              ==== The following convergence test requires that   
+                .    the tradition small-compared-to-nearby-diagonals   
+                .    criterion and the Ahues & Tisseur (LAWN 122, 1997)   
+                .    criteria both be satisfied.  The latter improves   
+                .    accuracy in some examples. Falling back on an   
+                .    alternate convergence criterion when TST1 or TST2   
+                .    is zero (as done here) is traditional but probably   
+                .    unnecessary. ==== */
+
+		if (h__[k + 1 + k * h_dim1] != 0.) {
+		    tst1 = (d__1 = h__[k + k * h_dim1], abs(d__1)) + (d__2 = 
+			    h__[k + 1 + (k + 1) * h_dim1], abs(d__2));
+		    if (tst1 == 0.) {
+			if (k >= *ktop + 1) {
+			    tst1 += (d__1 = h__[k + (k - 1) * h_dim1], abs(
+				    d__1));
+			}
+			if (k >= *ktop + 2) {
+			    tst1 += (d__1 = h__[k + (k - 2) * h_dim1], abs(
+				    d__1));
+			}
+			if (k >= *ktop + 3) {
+			    tst1 += (d__1 = h__[k + (k - 3) * h_dim1], abs(
+				    d__1));
+			}
+			if (k <= *kbot - 2) {
+			    tst1 += (d__1 = h__[k + 2 + (k + 1) * h_dim1], 
+				    abs(d__1));
+			}
+			if (k <= *kbot - 3) {
+			    tst1 += (d__1 = h__[k + 3 + (k + 1) * h_dim1], 
+				    abs(d__1));
+			}
+			if (k <= *kbot - 4) {
+			    tst1 += (d__1 = h__[k + 4 + (k + 1) * h_dim1], 
+				    abs(d__1));
+			}
+		    }
+/* Computing MAX */
+		    d__2 = smlnum, d__3 = ulp * tst1;
+		    if ((d__1 = h__[k + 1 + k * h_dim1], abs(d__1)) <= max(
+			    d__2,d__3)) {
+/* Computing MAX */
+			d__3 = (d__1 = h__[k + 1 + k * h_dim1], abs(d__1)), 
+				d__4 = (d__2 = h__[k + (k + 1) * h_dim1], abs(
+				d__2));
+			h12 = max(d__3,d__4);
+/* Computing MIN */
+			d__3 = (d__1 = h__[k + 1 + k * h_dim1], abs(d__1)), 
+				d__4 = (d__2 = h__[k + (k + 1) * h_dim1], abs(
+				d__2));
+			h21 = min(d__3,d__4);
+/* Computing MAX */
+			d__3 = (d__1 = h__[k + 1 + (k + 1) * h_dim1], abs(
+				d__1)), d__4 = (d__2 = h__[k + k * h_dim1] - 
+				h__[k + 1 + (k + 1) * h_dim1], abs(d__2));
+			h11 = max(d__3,d__4);
+/* Computing MIN */
+			d__3 = (d__1 = h__[k + 1 + (k + 1) * h_dim1], abs(
+				d__1)), d__4 = (d__2 = h__[k + k * h_dim1] - 
+				h__[k + 1 + (k + 1) * h_dim1], abs(d__2));
+			h22 = min(d__3,d__4);
+			scl = h11 + h12;
+			tst2 = h22 * (h11 / scl);
+
+/* Computing MAX */
+			d__1 = smlnum, d__2 = ulp * tst2;
+			if (tst2 == 0. || h21 * (h12 / scl) <= max(d__1,d__2))
+				 {
+			    h__[k + 1 + k * h_dim1] = 0.;
+			}
+		    }
+		}
+/* L130: */
+	    }
+
+/*           ==== Fill in the last row of each bulge. ====   
+
+   Computing MIN */
+	    i__4 = nbmps, i__5 = (*kbot - krcol - 1) / 3;
+	    mend = min(i__4,i__5);
+	    i__4 = mend;
+	    for (m = mtop; m <= i__4; ++m) {
+		k = krcol + (m - 1) * 3;
+		refsum = v[m * v_dim1 + 1] * v[m * v_dim1 + 3] * h__[k + 4 + (
+			k + 3) * h_dim1];
+		h__[k + 4 + (k + 1) * h_dim1] = -refsum;
+		h__[k + 4 + (k + 2) * h_dim1] = -refsum * v[m * v_dim1 + 2];
+		h__[k + 4 + (k + 3) * h_dim1] -= refsum * v[m * v_dim1 + 3];
+/* L140: */
+	    }
+
+/*           ==== End of near-the-diagonal bulge chase. ====   
+
+   L150: */
+	}
+
+/*        ==== Use U (if accumulated) to update far-from-diagonal   
+          .    entries in H.  If required, use U to update Z as   
+          .    well. ==== */
+
+	if (accum) {
+	    if (*wantt) {
+		jtop = 1;
+		jbot = *n;
+	    } else {
+		jtop = *ktop;
+		jbot = *kbot;
+	    }
+	    if (! blk22 || incol < *ktop || ndcol > *kbot || ns <= 2) {
+
+/*              ==== Updates not exploiting the 2-by-2 block   
+                .    structure of U.  K1 and NU keep track of   
+                .    the location and size of U in the special   
+                .    cases of introducing bulges and chasing   
+                .    bulges off the bottom.  In these special   
+                .    cases and in case the number of shifts   
+                .    is NS = 2, there is no 2-by-2 block   
+                .    structure to exploit.  ====   
+
+   Computing MAX */
+		i__3 = 1, i__4 = *ktop - incol;
+		k1 = max(i__3,i__4);
+/* Computing MAX */
+		i__3 = 0, i__4 = ndcol - *kbot;
+		nu = kdu - max(i__3,i__4) - k1 + 1;
+
+/*              ==== Horizontal Multiply ==== */
+
+		i__3 = jbot;
+		i__4 = *nh;
+		for (jcol = min(ndcol,*kbot) + 1; i__4 < 0 ? jcol >= i__3 : 
+			jcol <= i__3; jcol += i__4) {
+/* Computing MIN */
+		    i__5 = *nh, i__7 = jbot - jcol + 1;
+		    jlen = min(i__5,i__7);
+		    igraphdgemm_("C", "N", &nu, &jlen, &nu, &c_b8, &u[k1 + k1 * 
+			    u_dim1], ldu, &h__[incol + k1 + jcol * h_dim1], 
+			    ldh, &c_b7, &wh[wh_offset], ldwh);
+		    igraphdlacpy_("ALL", &nu, &jlen, &wh[wh_offset], ldwh, &h__[
+			    incol + k1 + jcol * h_dim1], ldh);
+/* L160: */
+		}
+
+/*              ==== Vertical multiply ==== */
+
+		i__4 = max(*ktop,incol) - 1;
+		i__3 = *nv;
+		for (jrow = jtop; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; 
+			jrow += i__3) {
+/* Computing MIN */
+		    i__5 = *nv, i__7 = max(*ktop,incol) - jrow;
+		    jlen = min(i__5,i__7);
+		    igraphdgemm_("N", "N", &jlen, &nu, &nu, &c_b8, &h__[jrow + (
+			    incol + k1) * h_dim1], ldh, &u[k1 + k1 * u_dim1], 
+			    ldu, &c_b7, &wv[wv_offset], ldwv);
+		    igraphdlacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &h__[
+			    jrow + (incol + k1) * h_dim1], ldh);
+/* L170: */
+		}
+
+/*              ==== Z multiply (also vertical) ==== */
+
+		if (*wantz) {
+		    i__3 = *ihiz;
+		    i__4 = *nv;
+		    for (jrow = *iloz; i__4 < 0 ? jrow >= i__3 : jrow <= i__3;
+			     jrow += i__4) {
+/* Computing MIN */
+			i__5 = *nv, i__7 = *ihiz - jrow + 1;
+			jlen = min(i__5,i__7);
+			igraphdgemm_("N", "N", &jlen, &nu, &nu, &c_b8, &z__[jrow + (
+				incol + k1) * z_dim1], ldz, &u[k1 + k1 * 
+				u_dim1], ldu, &c_b7, &wv[wv_offset], ldwv);
+			igraphdlacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &z__[
+				jrow + (incol + k1) * z_dim1], ldz)
+				;
+/* L180: */
+		    }
+		}
+	    } else {
+
+/*              ==== Updates exploiting U's 2-by-2 block structure.   
+                .    (I2, I4, J2, J4 are the last rows and columns   
+                .    of the blocks.) ==== */
+
+		i2 = (kdu + 1) / 2;
+		i4 = kdu;
+		j2 = i4 - i2;
+		j4 = kdu;
+
+/*              ==== KZS and KNZ deal with the band of zeros   
+                .    along the diagonal of one of the triangular   
+                .    blocks. ==== */
+
+		kzs = j4 - j2 - (ns + 1);
+		knz = ns + 1;
+
+/*              ==== Horizontal multiply ==== */
+
+		i__4 = jbot;
+		i__3 = *nh;
+		for (jcol = min(ndcol,*kbot) + 1; i__3 < 0 ? jcol >= i__4 : 
+			jcol <= i__4; jcol += i__3) {
+/* Computing MIN */
+		    i__5 = *nh, i__7 = jbot - jcol + 1;
+		    jlen = min(i__5,i__7);
+
+/*                 ==== Copy bottom of H to top+KZS of scratch ====   
+                    (The first KZS rows get multiplied by zero.) ==== */
+
+		    igraphdlacpy_("ALL", &knz, &jlen, &h__[incol + 1 + j2 + jcol * 
+			    h_dim1], ldh, &wh[kzs + 1 + wh_dim1], ldwh);
+
+/*                 ==== Multiply by U21**T ==== */
+
+		    igraphdlaset_("ALL", &kzs, &jlen, &c_b7, &c_b7, &wh[wh_offset], 
+			    ldwh);
+		    igraphdtrmm_("L", "U", "C", "N", &knz, &jlen, &c_b8, &u[j2 + 1 
+			    + (kzs + 1) * u_dim1], ldu, &wh[kzs + 1 + wh_dim1]
+			    , ldwh);
+
+/*                 ==== Multiply top of H by U11**T ==== */
+
+		    igraphdgemm_("C", "N", &i2, &jlen, &j2, &c_b8, &u[u_offset], 
+			    ldu, &h__[incol + 1 + jcol * h_dim1], ldh, &c_b8, 
+			    &wh[wh_offset], ldwh);
+
+/*                 ==== Copy top of H to bottom of WH ==== */
+
+		    igraphdlacpy_("ALL", &j2, &jlen, &h__[incol + 1 + jcol * h_dim1]
+			    , ldh, &wh[i2 + 1 + wh_dim1], ldwh);
+
+/*                 ==== Multiply by U21**T ==== */
+
+		    igraphdtrmm_("L", "L", "C", "N", &j2, &jlen, &c_b8, &u[(i2 + 1) 
+			    * u_dim1 + 1], ldu, &wh[i2 + 1 + wh_dim1], ldwh);
+
+/*                 ==== Multiply by U22 ==== */
+
+		    i__5 = i4 - i2;
+		    i__7 = j4 - j2;
+		    igraphdgemm_("C", "N", &i__5, &jlen, &i__7, &c_b8, &u[j2 + 1 + (
+			    i2 + 1) * u_dim1], ldu, &h__[incol + 1 + j2 + 
+			    jcol * h_dim1], ldh, &c_b8, &wh[i2 + 1 + wh_dim1],
+			     ldwh);
+
+/*                 ==== Copy it back ==== */
+
+		    igraphdlacpy_("ALL", &kdu, &jlen, &wh[wh_offset], ldwh, &h__[
+			    incol + 1 + jcol * h_dim1], ldh);
+/* L190: */
+		}
+
+/*              ==== Vertical multiply ==== */
+
+		i__3 = max(incol,*ktop) - 1;
+		i__4 = *nv;
+		for (jrow = jtop; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; 
+			jrow += i__4) {
+/* Computing MIN */
+		    i__5 = *nv, i__7 = max(incol,*ktop) - jrow;
+		    jlen = min(i__5,i__7);
+
+/*                 ==== Copy right of H to scratch (the first KZS   
+                   .    columns get multiplied by zero) ==== */
+
+		    igraphdlacpy_("ALL", &jlen, &knz, &h__[jrow + (incol + 1 + j2) *
+			     h_dim1], ldh, &wv[(kzs + 1) * wv_dim1 + 1], ldwv);
+
+/*                 ==== Multiply by U21 ==== */
+
+		    igraphdlaset_("ALL", &jlen, &kzs, &c_b7, &c_b7, &wv[wv_offset], 
+			    ldwv);
+		    igraphdtrmm_("R", "U", "N", "N", &jlen, &knz, &c_b8, &u[j2 + 1 
+			    + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) * 
+			    wv_dim1 + 1], ldwv);
+
+/*                 ==== Multiply by U11 ==== */
+
+		    igraphdgemm_("N", "N", &jlen, &i2, &j2, &c_b8, &h__[jrow + (
+			    incol + 1) * h_dim1], ldh, &u[u_offset], ldu, &
+			    c_b8, &wv[wv_offset], ldwv);
+
+/*                 ==== Copy left of H to right of scratch ==== */
+
+		    igraphdlacpy_("ALL", &jlen, &j2, &h__[jrow + (incol + 1) * 
+			    h_dim1], ldh, &wv[(i2 + 1) * wv_dim1 + 1], ldwv);
+
+/*                 ==== Multiply by U21 ==== */
+
+		    i__5 = i4 - i2;
+		    igraphdtrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b8, &u[(i2 + 
+			    1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * wv_dim1 + 1]
+			    , ldwv);
+
+/*                 ==== Multiply by U22 ==== */
+
+		    i__5 = i4 - i2;
+		    i__7 = j4 - j2;
+		    igraphdgemm_("N", "N", &jlen, &i__5, &i__7, &c_b8, &h__[jrow + (
+			    incol + 1 + j2) * h_dim1], ldh, &u[j2 + 1 + (i2 + 
+			    1) * u_dim1], ldu, &c_b8, &wv[(i2 + 1) * wv_dim1 
+			    + 1], ldwv);
+
+/*                 ==== Copy it back ==== */
+
+		    igraphdlacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, &h__[
+			    jrow + (incol + 1) * h_dim1], ldh);
+/* L200: */
+		}
+
+/*              ==== Multiply Z (also vertical) ==== */
+
+		if (*wantz) {
+		    i__4 = *ihiz;
+		    i__3 = *nv;
+		    for (jrow = *iloz; i__3 < 0 ? jrow >= i__4 : jrow <= i__4;
+			     jrow += i__3) {
+/* Computing MIN */
+			i__5 = *nv, i__7 = *ihiz - jrow + 1;
+			jlen = min(i__5,i__7);
+
+/*                    ==== Copy right of Z to left of scratch (first   
+                      .     KZS columns get multiplied by zero) ==== */
+
+			igraphdlacpy_("ALL", &jlen, &knz, &z__[jrow + (incol + 1 + 
+				j2) * z_dim1], ldz, &wv[(kzs + 1) * wv_dim1 + 
+				1], ldwv);
+
+/*                    ==== Multiply by U12 ==== */
+
+			igraphdlaset_("ALL", &jlen, &kzs, &c_b7, &c_b7, &wv[
+				wv_offset], ldwv);
+			igraphdtrmm_("R", "U", "N", "N", &jlen, &knz, &c_b8, &u[j2 
+				+ 1 + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) 
+				* wv_dim1 + 1], ldwv);
+
+/*                    ==== Multiply by U11 ==== */
+
+			igraphdgemm_("N", "N", &jlen, &i2, &j2, &c_b8, &z__[jrow + (
+				incol + 1) * z_dim1], ldz, &u[u_offset], ldu, 
+				&c_b8, &wv[wv_offset], ldwv);
+
+/*                    ==== Copy left of Z to right of scratch ==== */
+
+			igraphdlacpy_("ALL", &jlen, &j2, &z__[jrow + (incol + 1) * 
+				z_dim1], ldz, &wv[(i2 + 1) * wv_dim1 + 1], 
+				ldwv);
+
+/*                    ==== Multiply by U21 ==== */
+
+			i__5 = i4 - i2;
+			igraphdtrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b8, &u[(
+				i2 + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * 
+				wv_dim1 + 1], ldwv);
+
+/*                    ==== Multiply by U22 ==== */
+
+			i__5 = i4 - i2;
+			i__7 = j4 - j2;
+			igraphdgemm_("N", "N", &jlen, &i__5, &i__7, &c_b8, &z__[
+				jrow + (incol + 1 + j2) * z_dim1], ldz, &u[j2 
+				+ 1 + (i2 + 1) * u_dim1], ldu, &c_b8, &wv[(i2 
+				+ 1) * wv_dim1 + 1], ldwv);
+
+/*                    ==== Copy the result back to Z ==== */
+
+			igraphdlacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, &
+				z__[jrow + (incol + 1) * z_dim1], ldz);
+/* L210: */
+		    }
+		}
+	    }
+	}
+/* L220: */
+    }
+
+/*     ==== End of DLAQR5 ==== */
+
+    return 0;
+} /* igraphdlaqr5_ */
+
diff --git a/src/lapack/dlaqrb.c b/src/lapack/dlaqrb.c
new file mode 100644
index 0000000..a843cbf
--- /dev/null
+++ b/src/lapack/dlaqrb.c
@@ -0,0 +1,602 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dlaqrb   
+
+   \Description:   
+    Compute the eigenvalues and the Schur decomposition of an upper   
+    Hessenberg submatrix in rows and columns ILO to IHI.  Only the   
+    last component of the Schur vectors are computed.   
+
+    This is mostly a modification of the LAPACK routine dlahqr.   
+
+   \Usage:   
+    call dlaqrb   
+       ( WANTT, N, ILO, IHI, H, LDH, WR, WI,  Z, INFO )   
+
+   \Arguments   
+    WANTT   Logical variable.  (INPUT)   
+            = .TRUE. : the full Schur form T is required;   
+            = .FALSE.: only eigenvalues are required.   
+
+    N       Integer.  (INPUT)   
+            The order of the matrix H.  N >= 0.   
+
+    ILO     Integer.  (INPUT)   
+    IHI     Integer.  (INPUT)   
+            It is assumed that H is already upper quasi-triangular in   
+            rows and columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless   
+            ILO = 1). SLAQRB works primarily with the Hessenberg   
+            submatrix in rows and columns ILO to IHI, but applies   
+            transformations to all of H if WANTT is .TRUE..   
+            1 <= ILO <= max(1,IHI); IHI <= N.   
+
+    H       Double precision array, dimension (LDH,N).  (INPUT/OUTPUT)   
+            On entry, the upper Hessenberg matrix H.   
+            On exit, if WANTT is .TRUE., H is upper quasi-triangular in   
+            rows and columns ILO:IHI, with any 2-by-2 diagonal blocks in   
+            standard form. If WANTT is .FALSE., the contents of H are   
+            unspecified on exit.   
+
+    LDH     Integer.  (INPUT)   
+            The leading dimension of the array H. LDH >= max(1,N).   
+
+    WR      Double precision array, dimension (N).  (OUTPUT)   
+    WI      Double precision array, dimension (N).  (OUTPUT)   
+            The real and imaginary parts, respectively, of the computed   
+            eigenvalues ILO to IHI are stored in the corresponding   
+            elements of WR and WI. If two eigenvalues are computed as a   
+            complex conjugate pair, they are stored in consecutive   
+            elements of WR and WI, say the i-th and (i+1)th, with   
+            WI(i) > 0 and WI(i+1) < 0. If WANTT is .TRUE., the   
+            eigenvalues are stored in the same order as on the diagonal   
+            of the Schur form returned in H, with WR(i) = H(i,i), and, if   
+            H(i:i+1,i:i+1) is a 2-by-2 diagonal block,   
+            WI(i) = sqrt(H(i+1,i)*H(i,i+1)) and WI(i+1) = -WI(i).   
+
+    Z       Double precision array, dimension (N).  (OUTPUT)   
+            On exit Z contains the last components of the Schur vectors.   
+
+    INFO    Integer.  (OUPUT)   
+            = 0: successful exit   
+            > 0: SLAQRB failed to compute all the eigenvalues ILO to IHI   
+                 in a total of 30*(IHI-ILO+1) iterations; if INFO = i,   
+                 elements i+1:ihi of WR and WI contain those eigenvalues   
+                 which have been successfully computed.   
+
+   \Remarks   
+    1. None.   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       dlabad  LAPACK routine that computes machine constants.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlanhs  LAPACK routine that computes various norms of a matrix.   
+       dlanv2  LAPACK routine that computes the Schur factorization of   
+               2 by 2 nonsymmetric matrix in standard form.   
+       dlarfg  LAPACK Householder reflection construction routine.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+       drot    Level 1 BLAS that applies a rotation to a 2 by 2 matrix.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.4'   
+                 Modified from the LAPACK routine dlahqr so that only the   
+                 last component of the Schur vectors are computed.   
+
+   \SCCS Information: @(#)   
+   FILE: laqrb.F   SID: 2.2   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \Remarks   
+       1. None   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdlaqrb_(logical *wantt, integer *n, integer *ilo, 
+	integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, 
+	doublereal *wi, doublereal *z__, integer *info)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, i__1, i__2, i__3, i__4;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    integer i__, j, k, l, m;
+    doublereal s, v[3];
+    integer i1, i2;
+    doublereal t1, t2, t3, v1, v2, v3, h00, h10, h11, h12, h21, h22, h33, h44;
+    integer nh;
+    doublereal cs;
+    integer nr;
+    doublereal sn, h33s, h44s;
+    integer itn, its;
+    doublereal ulp, sum, tst1, h43h34, unfl, ovfl;
+    extern /* Subroutine */ int igraphdrot_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *);
+    doublereal work[1];
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdlanv2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *), igraphdlabad_(
+	    doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlarfg_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *);
+    extern doublereal igraphdlanhs_(char *, integer *, doublereal *, integer *, 
+	    doublereal *);
+    doublereal smlnum;
+
+
+/*     %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %------------------------%   
+       | Local Scalars & Arrays |   
+       %------------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --wr;
+    --wi;
+    --z__;
+
+    /* Function Body */
+    *info = 0;
+
+/*     %--------------------------%   
+       | Quick return if possible |   
+       %--------------------------% */
+
+    if (*n == 0) {
+	return 0;
+    }
+    if (*ilo == *ihi) {
+	wr[*ilo] = h__[*ilo + *ilo * h_dim1];
+	wi[*ilo] = 0.;
+	return 0;
+    }
+
+/*     %---------------------------------------------%   
+       | Initialize the vector of last components of |   
+       | the Schur vectors for accumulation.         |   
+       %---------------------------------------------% */
+
+    i__1 = *n - 1;
+    for (j = 1; j <= i__1; ++j) {
+	z__[j] = 0.;
+/* L5: */
+    }
+    z__[*n] = 1.;
+
+    nh = *ihi - *ilo + 1;
+
+/*     %-------------------------------------------------------------%   
+       | Set machine-dependent constants for the stopping criterion. |   
+       | If norm(H) <= sqrt(OVFL), overflow should not occur.        |   
+       %-------------------------------------------------------------% */
+
+    unfl = igraphdlamch_("safe minimum");
+    ovfl = 1. / unfl;
+    igraphdlabad_(&unfl, &ovfl);
+    ulp = igraphdlamch_("precision");
+    smlnum = unfl * (nh / ulp);
+
+/*     %---------------------------------------------------------------%   
+       | I1 and I2 are the indices of the first row and last column    |   
+       | of H to which transformations must be applied. If eigenvalues |   
+       | only are computed, I1 and I2 are set inside the main loop.    |   
+       | Zero out H(J+2,J) = ZERO for J=1:N if WANTT = .TRUE.          |   
+       | else H(J+2,J) for J=ILO:IHI-ILO-1 if WANTT = .FALSE.          |   
+       %---------------------------------------------------------------% */
+
+    if (*wantt) {
+	i1 = 1;
+	i2 = *n;
+	i__1 = i2 - 2;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    h__[i1 + i__ + 1 + i__ * h_dim1] = 0.;
+/* L8: */
+	}
+    } else {
+	i__1 = *ihi - *ilo - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    h__[*ilo + i__ + 1 + (*ilo + i__ - 1) * h_dim1] = 0.;
+/* L9: */
+	}
+    }
+
+/*     %---------------------------------------------------%   
+       | ITN is the total number of QR iterations allowed. |   
+       %---------------------------------------------------% */
+
+    itn = nh * 30;
+
+/*     ------------------------------------------------------------------   
+       The main loop begins here. I is the loop index and decreases from   
+       IHI to ILO in steps of 1 or 2. Each iteration of the loop works   
+       with the active submatrix in rows and columns L to I.   
+       Eigenvalues I+1 to IHI have already converged. Either L = ILO or   
+       H(L,L-1) is negligible so that the matrix splits.   
+       ------------------------------------------------------------------ */
+
+    i__ = *ihi;
+L10:
+    l = *ilo;
+    if (i__ < *ilo) {
+	goto L150;
+    }
+/*     %--------------------------------------------------------------%   
+       | Perform QR iterations on rows and columns ILO to I until a   |   
+       | submatrix of order 1 or 2 splits off at the bottom because a |   
+       | subdiagonal element has become negligible.                   |   
+       %--------------------------------------------------------------% */
+    i__1 = itn;
+    for (its = 0; its <= i__1; ++its) {
+
+/*        %----------------------------------------------%   
+          | Look for a single small subdiagonal element. |   
+          %----------------------------------------------% */
+
+	i__2 = l + 1;
+	for (k = i__; k >= i__2; --k) {
+	    tst1 = (d__1 = h__[k - 1 + (k - 1) * h_dim1], abs(d__1)) + (d__2 =
+		     h__[k + k * h_dim1], abs(d__2));
+	    if (tst1 == 0.) {
+		i__3 = i__ - l + 1;
+		tst1 = igraphdlanhs_("1", &i__3, &h__[l + l * h_dim1], ldh, work);
+	    }
+/* Computing MAX */
+	    d__2 = ulp * tst1;
+	    if ((d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)) <= max(d__2,
+		    smlnum)) {
+		goto L30;
+	    }
+/* L20: */
+	}
+L30:
+	l = k;
+	if (l > *ilo) {
+
+/*           %------------------------%   
+             | H(L,L-1) is negligible |   
+             %------------------------% */
+
+	    h__[l + (l - 1) * h_dim1] = 0.;
+	}
+
+/*        %-------------------------------------------------------------%   
+          | Exit from loop if a submatrix of order 1 or 2 has split off |   
+          %-------------------------------------------------------------% */
+
+	if (l >= i__ - 1) {
+	    goto L140;
+	}
+
+/*        %---------------------------------------------------------%   
+          | Now the active submatrix is in rows and columns L to I. |   
+          | If eigenvalues only are being computed, only the active |   
+          | submatrix need be transformed.                          |   
+          %---------------------------------------------------------% */
+
+	if (! (*wantt)) {
+	    i1 = l;
+	    i2 = i__;
+	}
+
+	if (its == 10 || its == 20) {
+
+/*           %-------------------%   
+             | Exceptional shift |   
+             %-------------------% */
+
+	    s = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1)) + (d__2 = 
+		    h__[i__ - 1 + (i__ - 2) * h_dim1], abs(d__2));
+	    h44 = s * .75;
+	    h33 = h44;
+	    h43h34 = s * -.4375 * s;
+
+	} else {
+
+/*           %-----------------------------------------%   
+             | Prepare to use Wilkinson's double shift |   
+             %-----------------------------------------% */
+
+	    h44 = h__[i__ + i__ * h_dim1];
+	    h33 = h__[i__ - 1 + (i__ - 1) * h_dim1];
+	    h43h34 = h__[i__ + (i__ - 1) * h_dim1] * h__[i__ - 1 + i__ * 
+		    h_dim1];
+	}
+
+/*        %-----------------------------------------------------%   
+          | Look for two consecutive small subdiagonal elements |   
+          %-----------------------------------------------------% */
+
+	i__2 = l;
+	for (m = i__ - 2; m >= i__2; --m) {
+
+/*           %---------------------------------------------------------%   
+             | Determine the effect of starting the double-shift QR    |   
+             | iteration at row M, and see if this would make H(M,M-1) |   
+             | negligible.                                             |   
+             %---------------------------------------------------------% */
+
+	    h11 = h__[m + m * h_dim1];
+	    h22 = h__[m + 1 + (m + 1) * h_dim1];
+	    h21 = h__[m + 1 + m * h_dim1];
+	    h12 = h__[m + (m + 1) * h_dim1];
+	    h44s = h44 - h11;
+	    h33s = h33 - h11;
+	    v1 = (h33s * h44s - h43h34) / h21 + h12;
+	    v2 = h22 - h11 - h33s - h44s;
+	    v3 = h__[m + 2 + (m + 1) * h_dim1];
+	    s = abs(v1) + abs(v2) + abs(v3);
+	    v1 /= s;
+	    v2 /= s;
+	    v3 /= s;
+	    v[0] = v1;
+	    v[1] = v2;
+	    v[2] = v3;
+	    if (m == l) {
+		goto L50;
+	    }
+	    h00 = h__[m - 1 + (m - 1) * h_dim1];
+	    h10 = h__[m + (m - 1) * h_dim1];
+	    tst1 = abs(v1) * (abs(h00) + abs(h11) + abs(h22));
+	    if (abs(h10) * (abs(v2) + abs(v3)) <= ulp * tst1) {
+		goto L50;
+	    }
+/* L40: */
+	}
+L50:
+
+/*        %----------------------%   
+          | Double-shift QR step |   
+          %----------------------% */
+
+	i__2 = i__ - 1;
+	for (k = m; k <= i__2; ++k) {
+
+/*           ------------------------------------------------------------   
+             The first iteration of this loop determines a reflection G   
+             from the vector V and applies it from left and right to H,   
+             thus creating a nonzero bulge below the subdiagonal.   
+
+             Each subsequent iteration determines a reflection G to   
+             restore the Hessenberg form in the (K-1)th column, and thus   
+             chases the bulge one step toward the bottom of the active   
+             submatrix. NR is the order of G.   
+             ------------------------------------------------------------   
+
+   Computing MIN */
+	    i__3 = 3, i__4 = i__ - k + 1;
+	    nr = min(i__3,i__4);
+	    if (k > m) {
+		igraphdcopy_(&nr, &h__[k + (k - 1) * h_dim1], &c__1, v, &c__1);
+	    }
+	    igraphdlarfg_(&nr, v, &v[1], &c__1, &t1);
+	    if (k > m) {
+		h__[k + (k - 1) * h_dim1] = v[0];
+		h__[k + 1 + (k - 1) * h_dim1] = 0.;
+		if (k < i__ - 1) {
+		    h__[k + 2 + (k - 1) * h_dim1] = 0.;
+		}
+	    } else if (m > l) {
+		h__[k + (k - 1) * h_dim1] = -h__[k + (k - 1) * h_dim1];
+	    }
+	    v2 = v[1];
+	    t2 = t1 * v2;
+	    if (nr == 3) {
+		v3 = v[2];
+		t3 = t1 * v3;
+
+/*              %------------------------------------------------%   
+                | Apply G from the left to transform the rows of |   
+                | the matrix in columns K to I2.                 |   
+                %------------------------------------------------% */
+
+		i__3 = i2;
+		for (j = k; j <= i__3; ++j) {
+		    sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1] 
+			    + v3 * h__[k + 2 + j * h_dim1];
+		    h__[k + j * h_dim1] -= sum * t1;
+		    h__[k + 1 + j * h_dim1] -= sum * t2;
+		    h__[k + 2 + j * h_dim1] -= sum * t3;
+/* L60: */
+		}
+
+/*              %----------------------------------------------------%   
+                | Apply G from the right to transform the columns of |   
+                | the matrix in rows I1 to min(K+3,I).               |   
+                %----------------------------------------------------%   
+
+   Computing MIN */
+		i__4 = k + 3;
+		i__3 = min(i__4,i__);
+		for (j = i1; j <= i__3; ++j) {
+		    sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1]
+			     + v3 * h__[j + (k + 2) * h_dim1];
+		    h__[j + k * h_dim1] -= sum * t1;
+		    h__[j + (k + 1) * h_dim1] -= sum * t2;
+		    h__[j + (k + 2) * h_dim1] -= sum * t3;
+/* L70: */
+		}
+
+/*              %----------------------------------%   
+                | Accumulate transformations for Z |   
+                %----------------------------------% */
+
+		sum = z__[k] + v2 * z__[k + 1] + v3 * z__[k + 2];
+		z__[k] -= sum * t1;
+		z__[k + 1] -= sum * t2;
+		z__[k + 2] -= sum * t3;
+	    } else if (nr == 2) {
+
+/*              %------------------------------------------------%   
+                | Apply G from the left to transform the rows of |   
+                | the matrix in columns K to I2.                 |   
+                %------------------------------------------------% */
+
+		i__3 = i2;
+		for (j = k; j <= i__3; ++j) {
+		    sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1];
+		    h__[k + j * h_dim1] -= sum * t1;
+		    h__[k + 1 + j * h_dim1] -= sum * t2;
+/* L90: */
+		}
+
+/*              %----------------------------------------------------%   
+                | Apply G from the right to transform the columns of |   
+                | the matrix in rows I1 to min(K+3,I).               |   
+                %----------------------------------------------------% */
+
+		i__3 = i__;
+		for (j = i1; j <= i__3; ++j) {
+		    sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1]
+			    ;
+		    h__[j + k * h_dim1] -= sum * t1;
+		    h__[j + (k + 1) * h_dim1] -= sum * t2;
+/* L100: */
+		}
+
+/*              %----------------------------------%   
+                | Accumulate transformations for Z |   
+                %----------------------------------% */
+
+		sum = z__[k] + v2 * z__[k + 1];
+		z__[k] -= sum * t1;
+		z__[k + 1] -= sum * t2;
+	    }
+/* L120: */
+	}
+/* L130: */
+    }
+
+/*     %-------------------------------------------------------%   
+       | Failure to converge in remaining number of iterations |   
+       %-------------------------------------------------------% */
+
+    *info = i__;
+    return 0;
+L140:
+    if (l == i__) {
+
+/*        %------------------------------------------------------%   
+          | H(I,I-1) is negligible: one eigenvalue has converged |   
+          %------------------------------------------------------% */
+
+	wr[i__] = h__[i__ + i__ * h_dim1];
+	wi[i__] = 0.;
+    } else if (l == i__ - 1) {
+
+/*        %--------------------------------------------------------%   
+          | H(I-1,I-2) is negligible;                              |   
+          | a pair of eigenvalues have converged.                  |   
+          |                                                        |   
+          | Transform the 2-by-2 submatrix to standard Schur form, |   
+          | and compute and store the eigenvalues.                 |   
+          %--------------------------------------------------------% */
+
+	igraphdlanv2_(&h__[i__ - 1 + (i__ - 1) * h_dim1], &h__[i__ - 1 + i__ * 
+		h_dim1], &h__[i__ + (i__ - 1) * h_dim1], &h__[i__ + i__ * 
+		h_dim1], &wr[i__ - 1], &wi[i__ - 1], &wr[i__], &wi[i__], &cs, 
+		&sn);
+	if (*wantt) {
+
+/*           %-----------------------------------------------------%   
+             | Apply the transformation to the rest of H and to Z, |   
+             | as required.                                        |   
+             %-----------------------------------------------------% */
+
+	    if (i2 > i__) {
+		i__1 = i2 - i__;
+		igraphdrot_(&i__1, &h__[i__ - 1 + (i__ + 1) * h_dim1], ldh, &h__[
+			i__ + (i__ + 1) * h_dim1], ldh, &cs, &sn);
+	    }
+	    i__1 = i__ - i1 - 1;
+	    igraphdrot_(&i__1, &h__[i1 + (i__ - 1) * h_dim1], &c__1, &h__[i1 + i__ *
+		     h_dim1], &c__1, &cs, &sn);
+	    sum = cs * z__[i__ - 1] + sn * z__[i__];
+	    z__[i__] = cs * z__[i__] - sn * z__[i__ - 1];
+	    z__[i__ - 1] = sum;
+	}
+    }
+
+/*     %---------------------------------------------------------%   
+       | Decrement number of remaining iterations, and return to |   
+       | start of the main loop with new value of I.             |   
+       %---------------------------------------------------------% */
+
+    itn -= its;
+    i__ = l - 1;
+    goto L10;
+L150:
+    return 0;
+
+/*     %---------------%   
+       | End of dlaqrb |   
+       %---------------% */
+
+} /* igraphdlaqrb_ */
+
diff --git a/src/lapack/dlaqtr.c b/src/lapack/dlaqtr.c
new file mode 100644
index 0000000..ea7202f
--- /dev/null
+++ b/src/lapack/dlaqtr.c
@@ -0,0 +1,816 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static logical c_false = FALSE_;
+static integer c__2 = 2;
+static doublereal c_b21 = 1.;
+static doublereal c_b25 = 0.;
+static logical c_true = TRUE_;
+
+/* Subroutine */ int igraphdlaqtr_(logical *ltran, logical *lreal, integer *n, 
+	doublereal *t, integer *ldt, doublereal *b, doublereal *w, doublereal 
+	*scale, doublereal *x, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer t_dim1, t_offset, i__1, i__2;
+    doublereal d__1, d__2, d__3, d__4, d__5, d__6;
+
+    /* Local variables */
+    doublereal d__[4]	/* was [2][2] */;
+    integer i__, j, k;
+    doublereal v[4]	/* was [2][2] */, z__;
+    integer j1, j2, n1, n2;
+    doublereal si, xj, sr, rec, eps, tjj, tmp;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    integer ierr;
+    doublereal smin, xmax;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    extern doublereal igraphdasum_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdaxpy_(integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    integer jnext;
+    doublereal sminw, xnorm;
+    extern /* Subroutine */ int igraphdlaln2_(logical *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, doublereal *,
+	     doublereal *, doublereal *, integer *, doublereal *, doublereal *
+	    , doublereal *, integer *, doublereal *, doublereal *, integer *);
+    extern doublereal igraphdlamch_(char *), igraphdlange_(char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    doublereal scaloc;
+    extern /* Subroutine */ int igraphdladiv_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *);
+    doublereal bignum;
+    logical notran;
+    doublereal smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLAQTR solves the real quasi-triangular system   
+
+                 op(T)*p = scale*c,               if LREAL = .TRUE.   
+
+    or the complex quasi-triangular systems   
+
+               op(T + iB)*(p+iq) = scale*(c+id),  if LREAL = .FALSE.   
+
+    in real arithmetic, where T is upper quasi-triangular.   
+    If LREAL = .FALSE., then the first diagonal block of T must be   
+    1 by 1, B is the specially structured matrix   
+
+                   B = [ b(1) b(2) ... b(n) ]   
+                       [       w            ]   
+                       [           w        ]   
+                       [              .     ]   
+                       [                 w  ]   
+
+    op(A) = A or A**T, A**T denotes the transpose of   
+    matrix A.   
+
+    On input, X = [ c ].  On output, X = [ p ].   
+                  [ d ]                  [ q ]   
+
+    This subroutine is designed for the condition number estimation   
+    in routine DTRSNA.   
+
+    Arguments   
+    =========   
+
+    LTRAN   (input) LOGICAL   
+            On entry, LTRAN specifies the option of conjugate transpose:   
+               = .FALSE.,    op(T+i*B) = T+i*B,   
+               = .TRUE.,     op(T+i*B) = (T+i*B)**T.   
+
+    LREAL   (input) LOGICAL   
+            On entry, LREAL specifies the input matrix structure:   
+               = .FALSE.,    the input is complex   
+               = .TRUE.,     the input is real   
+
+    N       (input) INTEGER   
+            On entry, N specifies the order of T+i*B. N >= 0.   
+
+    T       (input) DOUBLE PRECISION array, dimension (LDT,N)   
+            On entry, T contains a matrix in Schur canonical form.   
+            If LREAL = .FALSE., then the first diagonal block of T mu   
+            be 1 by 1.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the matrix T. LDT >= max(1,N).   
+
+    B       (input) DOUBLE PRECISION array, dimension (N)   
+            On entry, B contains the elements to form the matrix   
+            B as described above.   
+            If LREAL = .TRUE., B is not referenced.   
+
+    W       (input) DOUBLE PRECISION   
+            On entry, W is the diagonal element of the matrix B.   
+            If LREAL = .TRUE., W is not referenced.   
+
+    SCALE   (output) DOUBLE PRECISION   
+            On exit, SCALE is the scale factor.   
+
+    X       (input/output) DOUBLE PRECISION array, dimension (2*N)   
+            On entry, X contains the right hand side of the system.   
+            On exit, X is overwritten by the solution.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (N)   
+
+    INFO    (output) INTEGER   
+            On exit, INFO is set to   
+               0: successful exit.   
+                 1: the some diagonal 1 by 1 block has been perturbed by   
+                    a small number SMIN to keep nonsingularity.   
+                 2: the some diagonal 2 by 2 block has been perturbed by   
+                    a small number in DLALN2 to keep nonsingularity.   
+            NOTE: In the interests of speed, this routine does not   
+                  check the inputs for errors.   
+
+   =====================================================================   
+
+
+       Do not test the input parameters for errors   
+
+       Parameter adjustments */
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    --b;
+    --x;
+    --work;
+
+    /* Function Body */
+    notran = ! (*ltran);
+    *info = 0;
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+/*     Set constants to control overflow */
+
+    eps = igraphdlamch_("P");
+    smlnum = igraphdlamch_("S") / eps;
+    bignum = 1. / smlnum;
+
+    xnorm = igraphdlange_("M", n, n, &t[t_offset], ldt, d__);
+    if (! (*lreal)) {
+/* Computing MAX */
+	d__1 = xnorm, d__2 = abs(*w), d__1 = max(d__1,d__2), d__2 = igraphdlange_(
+		"M", n, &c__1, &b[1], n, d__);
+	xnorm = max(d__1,d__2);
+    }
+/* Computing MAX */
+    d__1 = smlnum, d__2 = eps * xnorm;
+    smin = max(d__1,d__2);
+
+/*     Compute 1-norm of each column of strictly upper triangular   
+       part of T to control overflow in triangular solver. */
+
+    work[1] = 0.;
+    i__1 = *n;
+    for (j = 2; j <= i__1; ++j) {
+	i__2 = j - 1;
+	work[j] = igraphdasum_(&i__2, &t[j * t_dim1 + 1], &c__1);
+/* L10: */
+    }
+
+    if (! (*lreal)) {
+	i__1 = *n;
+	for (i__ = 2; i__ <= i__1; ++i__) {
+	    work[i__] += (d__1 = b[i__], abs(d__1));
+/* L20: */
+	}
+    }
+
+    n2 = *n << 1;
+    n1 = *n;
+    if (! (*lreal)) {
+	n1 = n2;
+    }
+    k = igraphidamax_(&n1, &x[1], &c__1);
+    xmax = (d__1 = x[k], abs(d__1));
+    *scale = 1.;
+
+    if (xmax > bignum) {
+	*scale = bignum / xmax;
+	igraphdscal_(&n1, scale, &x[1], &c__1);
+	xmax = bignum;
+    }
+
+    if (*lreal) {
+
+	if (notran) {
+
+/*           Solve T*p = scale*c */
+
+	    jnext = *n;
+	    for (j = *n; j >= 1; --j) {
+		if (j > jnext) {
+		    goto L30;
+		}
+		j1 = j;
+		j2 = j;
+		jnext = j - 1;
+		if (j > 1) {
+		    if (t[j + (j - 1) * t_dim1] != 0.) {
+			j1 = j - 1;
+			jnext = j - 2;
+		    }
+		}
+
+		if (j1 == j2) {
+
+/*                 Meet 1 by 1 diagonal block   
+
+                   Scale to avoid overflow when computing   
+                       x(j) = b(j)/T(j,j) */
+
+		    xj = (d__1 = x[j1], abs(d__1));
+		    tjj = (d__1 = t[j1 + j1 * t_dim1], abs(d__1));
+		    tmp = t[j1 + j1 * t_dim1];
+		    if (tjj < smin) {
+			tmp = smin;
+			tjj = smin;
+			*info = 1;
+		    }
+
+		    if (xj == 0.) {
+			goto L30;
+		    }
+
+		    if (tjj < 1.) {
+			if (xj > bignum * tjj) {
+			    rec = 1. / xj;
+			    igraphdscal_(n, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+		    x[j1] /= tmp;
+		    xj = (d__1 = x[j1], abs(d__1));
+
+/*                 Scale x if necessary to avoid overflow when adding a   
+                   multiple of column j1 of T. */
+
+		    if (xj > 1.) {
+			rec = 1. / xj;
+			if (work[j1] > (bignum - xmax) * rec) {
+			    igraphdscal_(n, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			}
+		    }
+		    if (j1 > 1) {
+			i__1 = j1 - 1;
+			d__1 = -x[j1];
+			igraphdaxpy_(&i__1, &d__1, &t[j1 * t_dim1 + 1], &c__1, &x[1]
+				, &c__1);
+			i__1 = j1 - 1;
+			k = igraphidamax_(&i__1, &x[1], &c__1);
+			xmax = (d__1 = x[k], abs(d__1));
+		    }
+
+		} else {
+
+/*                 Meet 2 by 2 diagonal block   
+
+                   Call 2 by 2 linear system solve, to take   
+                   care of possible overflow by scaling factor. */
+
+		    d__[0] = x[j1];
+		    d__[1] = x[j2];
+		    igraphdlaln2_(&c_false, &c__2, &c__1, &smin, &c_b21, &t[j1 + j1 
+			    * t_dim1], ldt, &c_b21, &c_b21, d__, &c__2, &
+			    c_b25, &c_b25, v, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 2;
+		    }
+
+		    if (scaloc != 1.) {
+			igraphdscal_(n, &scaloc, &x[1], &c__1);
+			*scale *= scaloc;
+		    }
+		    x[j1] = v[0];
+		    x[j2] = v[1];
+
+/*                 Scale V(1,1) (= X(J1)) and/or V(2,1) (=X(J2))   
+                   to avoid overflow in updating right-hand side.   
+
+   Computing MAX */
+		    d__1 = abs(v[0]), d__2 = abs(v[1]);
+		    xj = max(d__1,d__2);
+		    if (xj > 1.) {
+			rec = 1. / xj;
+/* Computing MAX */
+			d__1 = work[j1], d__2 = work[j2];
+			if (max(d__1,d__2) > (bignum - xmax) * rec) {
+			    igraphdscal_(n, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			}
+		    }
+
+/*                 Update right-hand side */
+
+		    if (j1 > 1) {
+			i__1 = j1 - 1;
+			d__1 = -x[j1];
+			igraphdaxpy_(&i__1, &d__1, &t[j1 * t_dim1 + 1], &c__1, &x[1]
+				, &c__1);
+			i__1 = j1 - 1;
+			d__1 = -x[j2];
+			igraphdaxpy_(&i__1, &d__1, &t[j2 * t_dim1 + 1], &c__1, &x[1]
+				, &c__1);
+			i__1 = j1 - 1;
+			k = igraphidamax_(&i__1, &x[1], &c__1);
+			xmax = (d__1 = x[k], abs(d__1));
+		    }
+
+		}
+
+L30:
+		;
+	    }
+
+	} else {
+
+/*           Solve T**T*p = scale*c */
+
+	    jnext = 1;
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (j < jnext) {
+		    goto L40;
+		}
+		j1 = j;
+		j2 = j;
+		jnext = j + 1;
+		if (j < *n) {
+		    if (t[j + 1 + j * t_dim1] != 0.) {
+			j2 = j + 1;
+			jnext = j + 2;
+		    }
+		}
+
+		if (j1 == j2) {
+
+/*                 1 by 1 diagonal block   
+
+                   Scale if necessary to avoid overflow in forming the   
+                   right-hand side element by inner product. */
+
+		    xj = (d__1 = x[j1], abs(d__1));
+		    if (xmax > 1.) {
+			rec = 1. / xmax;
+			if (work[j1] > (bignum - xj) * rec) {
+			    igraphdscal_(n, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+
+		    i__2 = j1 - 1;
+		    x[j1] -= igraphddot_(&i__2, &t[j1 * t_dim1 + 1], &c__1, &x[1], &
+			    c__1);
+
+		    xj = (d__1 = x[j1], abs(d__1));
+		    tjj = (d__1 = t[j1 + j1 * t_dim1], abs(d__1));
+		    tmp = t[j1 + j1 * t_dim1];
+		    if (tjj < smin) {
+			tmp = smin;
+			tjj = smin;
+			*info = 1;
+		    }
+
+		    if (tjj < 1.) {
+			if (xj > bignum * tjj) {
+			    rec = 1. / xj;
+			    igraphdscal_(n, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+		    x[j1] /= tmp;
+/* Computing MAX */
+		    d__2 = xmax, d__3 = (d__1 = x[j1], abs(d__1));
+		    xmax = max(d__2,d__3);
+
+		} else {
+
+/*                 2 by 2 diagonal block   
+
+                   Scale if necessary to avoid overflow in forming the   
+                   right-hand side elements by inner product.   
+
+   Computing MAX */
+		    d__3 = (d__1 = x[j1], abs(d__1)), d__4 = (d__2 = x[j2], 
+			    abs(d__2));
+		    xj = max(d__3,d__4);
+		    if (xmax > 1.) {
+			rec = 1. / xmax;
+/* Computing MAX */
+			d__1 = work[j2], d__2 = work[j1];
+			if (max(d__1,d__2) > (bignum - xj) * rec) {
+			    igraphdscal_(n, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+
+		    i__2 = j1 - 1;
+		    d__[0] = x[j1] - igraphddot_(&i__2, &t[j1 * t_dim1 + 1], &c__1, 
+			    &x[1], &c__1);
+		    i__2 = j1 - 1;
+		    d__[1] = x[j2] - igraphddot_(&i__2, &t[j2 * t_dim1 + 1], &c__1, 
+			    &x[1], &c__1);
+
+		    igraphdlaln2_(&c_true, &c__2, &c__1, &smin, &c_b21, &t[j1 + j1 *
+			     t_dim1], ldt, &c_b21, &c_b21, d__, &c__2, &c_b25,
+			     &c_b25, v, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 2;
+		    }
+
+		    if (scaloc != 1.) {
+			igraphdscal_(n, &scaloc, &x[1], &c__1);
+			*scale *= scaloc;
+		    }
+		    x[j1] = v[0];
+		    x[j2] = v[1];
+/* Computing MAX */
+		    d__3 = (d__1 = x[j1], abs(d__1)), d__4 = (d__2 = x[j2], 
+			    abs(d__2)), d__3 = max(d__3,d__4);
+		    xmax = max(d__3,xmax);
+
+		}
+L40:
+		;
+	    }
+	}
+
+    } else {
+
+/* Computing MAX */
+	d__1 = eps * abs(*w);
+	sminw = max(d__1,smin);
+	if (notran) {
+
+/*           Solve (T + iB)*(p+iq) = c+id */
+
+	    jnext = *n;
+	    for (j = *n; j >= 1; --j) {
+		if (j > jnext) {
+		    goto L70;
+		}
+		j1 = j;
+		j2 = j;
+		jnext = j - 1;
+		if (j > 1) {
+		    if (t[j + (j - 1) * t_dim1] != 0.) {
+			j1 = j - 1;
+			jnext = j - 2;
+		    }
+		}
+
+		if (j1 == j2) {
+
+/*                 1 by 1 diagonal block   
+
+                   Scale if necessary to avoid overflow in division */
+
+		    z__ = *w;
+		    if (j1 == 1) {
+			z__ = b[1];
+		    }
+		    xj = (d__1 = x[j1], abs(d__1)) + (d__2 = x[*n + j1], abs(
+			    d__2));
+		    tjj = (d__1 = t[j1 + j1 * t_dim1], abs(d__1)) + abs(z__);
+		    tmp = t[j1 + j1 * t_dim1];
+		    if (tjj < sminw) {
+			tmp = sminw;
+			tjj = sminw;
+			*info = 1;
+		    }
+
+		    if (xj == 0.) {
+			goto L70;
+		    }
+
+		    if (tjj < 1.) {
+			if (xj > bignum * tjj) {
+			    rec = 1. / xj;
+			    igraphdscal_(&n2, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+		    igraphdladiv_(&x[j1], &x[*n + j1], &tmp, &z__, &sr, &si);
+		    x[j1] = sr;
+		    x[*n + j1] = si;
+		    xj = (d__1 = x[j1], abs(d__1)) + (d__2 = x[*n + j1], abs(
+			    d__2));
+
+/*                 Scale x if necessary to avoid overflow when adding a   
+                   multiple of column j1 of T. */
+
+		    if (xj > 1.) {
+			rec = 1. / xj;
+			if (work[j1] > (bignum - xmax) * rec) {
+			    igraphdscal_(&n2, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			}
+		    }
+
+		    if (j1 > 1) {
+			i__1 = j1 - 1;
+			d__1 = -x[j1];
+			igraphdaxpy_(&i__1, &d__1, &t[j1 * t_dim1 + 1], &c__1, &x[1]
+				, &c__1);
+			i__1 = j1 - 1;
+			d__1 = -x[*n + j1];
+			igraphdaxpy_(&i__1, &d__1, &t[j1 * t_dim1 + 1], &c__1, &x[*
+				n + 1], &c__1);
+
+			x[1] += b[j1] * x[*n + j1];
+			x[*n + 1] -= b[j1] * x[j1];
+
+			xmax = 0.;
+			i__1 = j1 - 1;
+			for (k = 1; k <= i__1; ++k) {
+/* Computing MAX */
+			    d__3 = xmax, d__4 = (d__1 = x[k], abs(d__1)) + (
+				    d__2 = x[k + *n], abs(d__2));
+			    xmax = max(d__3,d__4);
+/* L50: */
+			}
+		    }
+
+		} else {
+
+/*                 Meet 2 by 2 diagonal block */
+
+		    d__[0] = x[j1];
+		    d__[1] = x[j2];
+		    d__[2] = x[*n + j1];
+		    d__[3] = x[*n + j2];
+		    d__1 = -(*w);
+		    igraphdlaln2_(&c_false, &c__2, &c__2, &sminw, &c_b21, &t[j1 + 
+			    j1 * t_dim1], ldt, &c_b21, &c_b21, d__, &c__2, &
+			    c_b25, &d__1, v, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 2;
+		    }
+
+		    if (scaloc != 1.) {
+			i__1 = *n << 1;
+			igraphdscal_(&i__1, &scaloc, &x[1], &c__1);
+			*scale = scaloc * *scale;
+		    }
+		    x[j1] = v[0];
+		    x[j2] = v[1];
+		    x[*n + j1] = v[2];
+		    x[*n + j2] = v[3];
+
+/*                 Scale X(J1), .... to avoid overflow in   
+                   updating right hand side.   
+
+   Computing MAX */
+		    d__1 = abs(v[0]) + abs(v[2]), d__2 = abs(v[1]) + abs(v[3])
+			    ;
+		    xj = max(d__1,d__2);
+		    if (xj > 1.) {
+			rec = 1. / xj;
+/* Computing MAX */
+			d__1 = work[j1], d__2 = work[j2];
+			if (max(d__1,d__2) > (bignum - xmax) * rec) {
+			    igraphdscal_(&n2, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			}
+		    }
+
+/*                 Update the right-hand side. */
+
+		    if (j1 > 1) {
+			i__1 = j1 - 1;
+			d__1 = -x[j1];
+			igraphdaxpy_(&i__1, &d__1, &t[j1 * t_dim1 + 1], &c__1, &x[1]
+				, &c__1);
+			i__1 = j1 - 1;
+			d__1 = -x[j2];
+			igraphdaxpy_(&i__1, &d__1, &t[j2 * t_dim1 + 1], &c__1, &x[1]
+				, &c__1);
+
+			i__1 = j1 - 1;
+			d__1 = -x[*n + j1];
+			igraphdaxpy_(&i__1, &d__1, &t[j1 * t_dim1 + 1], &c__1, &x[*
+				n + 1], &c__1);
+			i__1 = j1 - 1;
+			d__1 = -x[*n + j2];
+			igraphdaxpy_(&i__1, &d__1, &t[j2 * t_dim1 + 1], &c__1, &x[*
+				n + 1], &c__1);
+
+			x[1] = x[1] + b[j1] * x[*n + j1] + b[j2] * x[*n + j2];
+			x[*n + 1] = x[*n + 1] - b[j1] * x[j1] - b[j2] * x[j2];
+
+			xmax = 0.;
+			i__1 = j1 - 1;
+			for (k = 1; k <= i__1; ++k) {
+/* Computing MAX */
+			    d__3 = (d__1 = x[k], abs(d__1)) + (d__2 = x[k + *
+				    n], abs(d__2));
+			    xmax = max(d__3,xmax);
+/* L60: */
+			}
+		    }
+
+		}
+L70:
+		;
+	    }
+
+	} else {
+
+/*           Solve (T + iB)**T*(p+iq) = c+id */
+
+	    jnext = 1;
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (j < jnext) {
+		    goto L80;
+		}
+		j1 = j;
+		j2 = j;
+		jnext = j + 1;
+		if (j < *n) {
+		    if (t[j + 1 + j * t_dim1] != 0.) {
+			j2 = j + 1;
+			jnext = j + 2;
+		    }
+		}
+
+		if (j1 == j2) {
+
+/*                 1 by 1 diagonal block   
+
+                   Scale if necessary to avoid overflow in forming the   
+                   right-hand side element by inner product. */
+
+		    xj = (d__1 = x[j1], abs(d__1)) + (d__2 = x[j1 + *n], abs(
+			    d__2));
+		    if (xmax > 1.) {
+			rec = 1. / xmax;
+			if (work[j1] > (bignum - xj) * rec) {
+			    igraphdscal_(&n2, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+
+		    i__2 = j1 - 1;
+		    x[j1] -= igraphddot_(&i__2, &t[j1 * t_dim1 + 1], &c__1, &x[1], &
+			    c__1);
+		    i__2 = j1 - 1;
+		    x[*n + j1] -= igraphddot_(&i__2, &t[j1 * t_dim1 + 1], &c__1, &x[
+			    *n + 1], &c__1);
+		    if (j1 > 1) {
+			x[j1] -= b[j1] * x[*n + 1];
+			x[*n + j1] += b[j1] * x[1];
+		    }
+		    xj = (d__1 = x[j1], abs(d__1)) + (d__2 = x[j1 + *n], abs(
+			    d__2));
+
+		    z__ = *w;
+		    if (j1 == 1) {
+			z__ = b[1];
+		    }
+
+/*                 Scale if necessary to avoid overflow in   
+                   complex division */
+
+		    tjj = (d__1 = t[j1 + j1 * t_dim1], abs(d__1)) + abs(z__);
+		    tmp = t[j1 + j1 * t_dim1];
+		    if (tjj < sminw) {
+			tmp = sminw;
+			tjj = sminw;
+			*info = 1;
+		    }
+
+		    if (tjj < 1.) {
+			if (xj > bignum * tjj) {
+			    rec = 1. / xj;
+			    igraphdscal_(&n2, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+		    d__1 = -z__;
+		    igraphdladiv_(&x[j1], &x[*n + j1], &tmp, &d__1, &sr, &si);
+		    x[j1] = sr;
+		    x[j1 + *n] = si;
+/* Computing MAX */
+		    d__3 = (d__1 = x[j1], abs(d__1)) + (d__2 = x[j1 + *n], 
+			    abs(d__2));
+		    xmax = max(d__3,xmax);
+
+		} else {
+
+/*                 2 by 2 diagonal block   
+
+                   Scale if necessary to avoid overflow in forming the   
+                   right-hand side element by inner product.   
+
+   Computing MAX */
+		    d__5 = (d__1 = x[j1], abs(d__1)) + (d__2 = x[*n + j1], 
+			    abs(d__2)), d__6 = (d__3 = x[j2], abs(d__3)) + (
+			    d__4 = x[*n + j2], abs(d__4));
+		    xj = max(d__5,d__6);
+		    if (xmax > 1.) {
+			rec = 1. / xmax;
+/* Computing MAX */
+			d__1 = work[j1], d__2 = work[j2];
+			if (max(d__1,d__2) > (bignum - xj) / xmax) {
+			    igraphdscal_(&n2, &rec, &x[1], &c__1);
+			    *scale *= rec;
+			    xmax *= rec;
+			}
+		    }
+
+		    i__2 = j1 - 1;
+		    d__[0] = x[j1] - igraphddot_(&i__2, &t[j1 * t_dim1 + 1], &c__1, 
+			    &x[1], &c__1);
+		    i__2 = j1 - 1;
+		    d__[1] = x[j2] - igraphddot_(&i__2, &t[j2 * t_dim1 + 1], &c__1, 
+			    &x[1], &c__1);
+		    i__2 = j1 - 1;
+		    d__[2] = x[*n + j1] - igraphddot_(&i__2, &t[j1 * t_dim1 + 1], &
+			    c__1, &x[*n + 1], &c__1);
+		    i__2 = j1 - 1;
+		    d__[3] = x[*n + j2] - igraphddot_(&i__2, &t[j2 * t_dim1 + 1], &
+			    c__1, &x[*n + 1], &c__1);
+		    d__[0] -= b[j1] * x[*n + 1];
+		    d__[1] -= b[j2] * x[*n + 1];
+		    d__[2] += b[j1] * x[1];
+		    d__[3] += b[j2] * x[1];
+
+		    igraphdlaln2_(&c_true, &c__2, &c__2, &sminw, &c_b21, &t[j1 + j1 
+			    * t_dim1], ldt, &c_b21, &c_b21, d__, &c__2, &
+			    c_b25, w, v, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 2;
+		    }
+
+		    if (scaloc != 1.) {
+			igraphdscal_(&n2, &scaloc, &x[1], &c__1);
+			*scale = scaloc * *scale;
+		    }
+		    x[j1] = v[0];
+		    x[j2] = v[1];
+		    x[*n + j1] = v[2];
+		    x[*n + j2] = v[3];
+/* Computing MAX */
+		    d__5 = (d__1 = x[j1], abs(d__1)) + (d__2 = x[*n + j1], 
+			    abs(d__2)), d__6 = (d__3 = x[j2], abs(d__3)) + (
+			    d__4 = x[*n + j2], abs(d__4)), d__5 = max(d__5,
+			    d__6);
+		    xmax = max(d__5,xmax);
+
+		}
+
+L80:
+		;
+	    }
+
+	}
+
+    }
+
+    return 0;
+
+/*     End of DLAQTR */
+
+} /* igraphdlaqtr_ */
+
diff --git a/src/lapack/dlar1v.c b/src/lapack/dlar1v.c
new file mode 100644
index 0000000..6c5ea46
--- /dev/null
+++ b/src/lapack/dlar1v.c
@@ -0,0 +1,429 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlar1v_(integer *n, integer *b1, integer *bn, doublereal 
+	*lambda, doublereal *d__, doublereal *l, doublereal *ld, doublereal *
+	lld, doublereal *pivmin, doublereal *gaptol, doublereal *z__, logical 
+	*wantnc, integer *negcnt, doublereal *ztz, doublereal *mingma, 
+	integer *r__, integer *isuppz, doublereal *nrminv, doublereal *resid, 
+	doublereal *rqcorr, doublereal *work)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal s;
+    integer r1, r2;
+    doublereal eps, tmp;
+    integer neg1, neg2, indp, inds;
+    doublereal dplus;
+    extern doublereal igraphdlamch_(char *);
+    extern logical igraphdisnan_(doublereal *);
+    integer indlpl, indumn;
+    doublereal dminus;
+    logical sawnan1, sawnan2;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLAR1V computes the (scaled) r-th column of the inverse of   
+    the sumbmatrix in rows B1 through BN of the tridiagonal matrix   
+    L D L**T - sigma I. When sigma is close to an eigenvalue, the   
+    computed vector is an accurate eigenvector. Usually, r corresponds   
+    to the index where the eigenvector is largest in magnitude.   
+    The following steps accomplish this computation :   
+    (a) Stationary qd transform,  L D L**T - sigma I = L(+) D(+) L(+)**T,   
+    (b) Progressive qd transform, L D L**T - sigma I = U(-) D(-) U(-)**T,   
+    (c) Computation of the diagonal elements of the inverse of   
+        L D L**T - sigma I by combining the above transforms, and choosing   
+        r as the index where the diagonal of the inverse is (one of the)   
+        largest in magnitude.   
+    (d) Computation of the (scaled) r-th column of the inverse using the   
+        twisted factorization obtained by combining the top part of the   
+        the stationary and the bottom part of the progressive transform.   
+
+    Arguments   
+    =========   
+
+    N        (input) INTEGER   
+             The order of the matrix L D L**T.   
+
+    B1       (input) INTEGER   
+             First index of the submatrix of L D L**T.   
+
+    BN       (input) INTEGER   
+             Last index of the submatrix of L D L**T.   
+
+    LAMBDA    (input) DOUBLE PRECISION   
+             The shift. In order to compute an accurate eigenvector,   
+             LAMBDA should be a good approximation to an eigenvalue   
+             of L D L**T.   
+
+    L        (input) DOUBLE PRECISION array, dimension (N-1)   
+             The (n-1) subdiagonal elements of the unit bidiagonal matrix   
+             L, in elements 1 to N-1.   
+
+    D        (input) DOUBLE PRECISION array, dimension (N)   
+             The n diagonal elements of the diagonal matrix D.   
+
+    LD       (input) DOUBLE PRECISION array, dimension (N-1)   
+             The n-1 elements L(i)*D(i).   
+
+    LLD      (input) DOUBLE PRECISION array, dimension (N-1)   
+             The n-1 elements L(i)*L(i)*D(i).   
+
+    PIVMIN   (input) DOUBLE PRECISION   
+             The minimum pivot in the Sturm sequence.   
+
+    GAPTOL   (input) DOUBLE PRECISION   
+             Tolerance that indicates when eigenvector entries are negligible   
+             w.r.t. their contribution to the residual.   
+
+    Z        (input/output) DOUBLE PRECISION array, dimension (N)   
+             On input, all entries of Z must be set to 0.   
+             On output, Z contains the (scaled) r-th column of the   
+             inverse. The scaling is such that Z(R) equals 1.   
+
+    WANTNC   (input) LOGICAL   
+             Specifies whether NEGCNT has to be computed.   
+
+    NEGCNT   (output) INTEGER   
+             If WANTNC is .TRUE. then NEGCNT = the number of pivots < pivmin   
+             in the  matrix factorization L D L**T, and NEGCNT = -1 otherwise.   
+
+    ZTZ      (output) DOUBLE PRECISION   
+             The square of the 2-norm of Z.   
+
+    MINGMA   (output) DOUBLE PRECISION   
+             The reciprocal of the largest (in magnitude) diagonal   
+             element of the inverse of L D L**T - sigma I.   
+
+    R        (input/output) INTEGER   
+             The twist index for the twisted factorization used to   
+             compute Z.   
+             On input, 0 <= R <= N. If R is input as 0, R is set to   
+             the index where (L D L**T - sigma I)^{-1} is largest   
+             in magnitude. If 1 <= R <= N, R is unchanged.   
+             On output, R contains the twist index used to compute Z.   
+             Ideally, R designates the position of the maximum entry in the   
+             eigenvector.   
+
+    ISUPPZ   (output) INTEGER array, dimension (2)   
+             The support of the vector in Z, i.e., the vector Z is   
+             nonzero only in elements ISUPPZ(1) through ISUPPZ( 2 ).   
+
+    NRMINV   (output) DOUBLE PRECISION   
+             NRMINV = 1/SQRT( ZTZ )   
+
+    RESID    (output) DOUBLE PRECISION   
+             The residual of the FP vector.   
+             RESID = ABS( MINGMA )/SQRT( ZTZ )   
+
+    RQCORR   (output) DOUBLE PRECISION   
+             The Rayleigh Quotient correction to LAMBDA.   
+             RQCORR = MINGMA*TMP   
+
+    WORK     (workspace) DOUBLE PRECISION array, dimension (4*N)   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --work;
+    --isuppz;
+    --z__;
+    --lld;
+    --ld;
+    --l;
+    --d__;
+
+    /* Function Body */
+    eps = igraphdlamch_("Precision");
+    if (*r__ == 0) {
+	r1 = *b1;
+	r2 = *bn;
+    } else {
+	r1 = *r__;
+	r2 = *r__;
+    }
+/*     Storage for LPLUS */
+    indlpl = 0;
+/*     Storage for UMINUS */
+    indumn = *n;
+    inds = (*n << 1) + 1;
+    indp = *n * 3 + 1;
+    if (*b1 == 1) {
+	work[inds] = 0.;
+    } else {
+	work[inds + *b1 - 1] = lld[*b1 - 1];
+    }
+
+/*     Compute the stationary transform (using the differential form)   
+       until the index R2. */
+
+    sawnan1 = FALSE_;
+    neg1 = 0;
+    s = work[inds + *b1 - 1] - *lambda;
+    i__1 = r1 - 1;
+    for (i__ = *b1; i__ <= i__1; ++i__) {
+	dplus = d__[i__] + s;
+	work[indlpl + i__] = ld[i__] / dplus;
+	if (dplus < 0.) {
+	    ++neg1;
+	}
+	work[inds + i__] = s * work[indlpl + i__] * l[i__];
+	s = work[inds + i__] - *lambda;
+/* L50: */
+    }
+    sawnan1 = igraphdisnan_(&s);
+    if (sawnan1) {
+	goto L60;
+    }
+    i__1 = r2 - 1;
+    for (i__ = r1; i__ <= i__1; ++i__) {
+	dplus = d__[i__] + s;
+	work[indlpl + i__] = ld[i__] / dplus;
+	work[inds + i__] = s * work[indlpl + i__] * l[i__];
+	s = work[inds + i__] - *lambda;
+/* L51: */
+    }
+    sawnan1 = igraphdisnan_(&s);
+
+L60:
+    if (sawnan1) {
+/*        Runs a slower version of the above loop if a NaN is detected */
+	neg1 = 0;
+	s = work[inds + *b1 - 1] - *lambda;
+	i__1 = r1 - 1;
+	for (i__ = *b1; i__ <= i__1; ++i__) {
+	    dplus = d__[i__] + s;
+	    if (abs(dplus) < *pivmin) {
+		dplus = -(*pivmin);
+	    }
+	    work[indlpl + i__] = ld[i__] / dplus;
+	    if (dplus < 0.) {
+		++neg1;
+	    }
+	    work[inds + i__] = s * work[indlpl + i__] * l[i__];
+	    if (work[indlpl + i__] == 0.) {
+		work[inds + i__] = lld[i__];
+	    }
+	    s = work[inds + i__] - *lambda;
+/* L70: */
+	}
+	i__1 = r2 - 1;
+	for (i__ = r1; i__ <= i__1; ++i__) {
+	    dplus = d__[i__] + s;
+	    if (abs(dplus) < *pivmin) {
+		dplus = -(*pivmin);
+	    }
+	    work[indlpl + i__] = ld[i__] / dplus;
+	    work[inds + i__] = s * work[indlpl + i__] * l[i__];
+	    if (work[indlpl + i__] == 0.) {
+		work[inds + i__] = lld[i__];
+	    }
+	    s = work[inds + i__] - *lambda;
+/* L71: */
+	}
+    }
+
+/*     Compute the progressive transform (using the differential form)   
+       until the index R1 */
+
+    sawnan2 = FALSE_;
+    neg2 = 0;
+    work[indp + *bn - 1] = d__[*bn] - *lambda;
+    i__1 = r1;
+    for (i__ = *bn - 1; i__ >= i__1; --i__) {
+	dminus = lld[i__] + work[indp + i__];
+	tmp = d__[i__] / dminus;
+	if (dminus < 0.) {
+	    ++neg2;
+	}
+	work[indumn + i__] = l[i__] * tmp;
+	work[indp + i__ - 1] = work[indp + i__] * tmp - *lambda;
+/* L80: */
+    }
+    tmp = work[indp + r1 - 1];
+    sawnan2 = igraphdisnan_(&tmp);
+    if (sawnan2) {
+/*        Runs a slower version of the above loop if a NaN is detected */
+	neg2 = 0;
+	i__1 = r1;
+	for (i__ = *bn - 1; i__ >= i__1; --i__) {
+	    dminus = lld[i__] + work[indp + i__];
+	    if (abs(dminus) < *pivmin) {
+		dminus = -(*pivmin);
+	    }
+	    tmp = d__[i__] / dminus;
+	    if (dminus < 0.) {
+		++neg2;
+	    }
+	    work[indumn + i__] = l[i__] * tmp;
+	    work[indp + i__ - 1] = work[indp + i__] * tmp - *lambda;
+	    if (tmp == 0.) {
+		work[indp + i__ - 1] = d__[i__] - *lambda;
+	    }
+/* L100: */
+	}
+    }
+
+/*     Find the index (from R1 to R2) of the largest (in magnitude)   
+       diagonal element of the inverse */
+
+    *mingma = work[inds + r1 - 1] + work[indp + r1 - 1];
+    if (*mingma < 0.) {
+	++neg1;
+    }
+    if (*wantnc) {
+	*negcnt = neg1 + neg2;
+    } else {
+	*negcnt = -1;
+    }
+    if (abs(*mingma) == 0.) {
+	*mingma = eps * work[inds + r1 - 1];
+    }
+    *r__ = r1;
+    i__1 = r2 - 1;
+    for (i__ = r1; i__ <= i__1; ++i__) {
+	tmp = work[inds + i__] + work[indp + i__];
+	if (tmp == 0.) {
+	    tmp = eps * work[inds + i__];
+	}
+	if (abs(tmp) <= abs(*mingma)) {
+	    *mingma = tmp;
+	    *r__ = i__ + 1;
+	}
+/* L110: */
+    }
+
+/*     Compute the FP vector: solve N^T v = e_r */
+
+    isuppz[1] = *b1;
+    isuppz[2] = *bn;
+    z__[*r__] = 1.;
+    *ztz = 1.;
+
+/*     Compute the FP vector upwards from R */
+
+    if (! sawnan1 && ! sawnan2) {
+	i__1 = *b1;
+	for (i__ = *r__ - 1; i__ >= i__1; --i__) {
+	    z__[i__] = -(work[indlpl + i__] * z__[i__ + 1]);
+	    if (((d__1 = z__[i__], abs(d__1)) + (d__2 = z__[i__ + 1], abs(
+		    d__2))) * (d__3 = ld[i__], abs(d__3)) < *gaptol) {
+		z__[i__] = 0.;
+		isuppz[1] = i__ + 1;
+		goto L220;
+	    }
+	    *ztz += z__[i__] * z__[i__];
+/* L210: */
+	}
+L220:
+	;
+    } else {
+/*        Run slower loop if NaN occurred. */
+	i__1 = *b1;
+	for (i__ = *r__ - 1; i__ >= i__1; --i__) {
+	    if (z__[i__ + 1] == 0.) {
+		z__[i__] = -(ld[i__ + 1] / ld[i__]) * z__[i__ + 2];
+	    } else {
+		z__[i__] = -(work[indlpl + i__] * z__[i__ + 1]);
+	    }
+	    if (((d__1 = z__[i__], abs(d__1)) + (d__2 = z__[i__ + 1], abs(
+		    d__2))) * (d__3 = ld[i__], abs(d__3)) < *gaptol) {
+		z__[i__] = 0.;
+		isuppz[1] = i__ + 1;
+		goto L240;
+	    }
+	    *ztz += z__[i__] * z__[i__];
+/* L230: */
+	}
+L240:
+	;
+    }
+/*     Compute the FP vector downwards from R in blocks of size BLKSIZ */
+    if (! sawnan1 && ! sawnan2) {
+	i__1 = *bn - 1;
+	for (i__ = *r__; i__ <= i__1; ++i__) {
+	    z__[i__ + 1] = -(work[indumn + i__] * z__[i__]);
+	    if (((d__1 = z__[i__], abs(d__1)) + (d__2 = z__[i__ + 1], abs(
+		    d__2))) * (d__3 = ld[i__], abs(d__3)) < *gaptol) {
+		z__[i__ + 1] = 0.;
+		isuppz[2] = i__;
+		goto L260;
+	    }
+	    *ztz += z__[i__ + 1] * z__[i__ + 1];
+/* L250: */
+	}
+L260:
+	;
+    } else {
+/*        Run slower loop if NaN occurred. */
+	i__1 = *bn - 1;
+	for (i__ = *r__; i__ <= i__1; ++i__) {
+	    if (z__[i__] == 0.) {
+		z__[i__ + 1] = -(ld[i__ - 1] / ld[i__]) * z__[i__ - 1];
+	    } else {
+		z__[i__ + 1] = -(work[indumn + i__] * z__[i__]);
+	    }
+	    if (((d__1 = z__[i__], abs(d__1)) + (d__2 = z__[i__ + 1], abs(
+		    d__2))) * (d__3 = ld[i__], abs(d__3)) < *gaptol) {
+		z__[i__ + 1] = 0.;
+		isuppz[2] = i__;
+		goto L280;
+	    }
+	    *ztz += z__[i__ + 1] * z__[i__ + 1];
+/* L270: */
+	}
+L280:
+	;
+    }
+
+/*     Compute quantities for convergence test */
+
+    tmp = 1. / *ztz;
+    *nrminv = sqrt(tmp);
+    *resid = abs(*mingma) * *nrminv;
+    *rqcorr = *mingma * tmp;
+
+
+    return 0;
+
+/*     End of DLAR1V */
+
+} /* igraphdlar1v_ */
+
diff --git a/src/lapack/dlarf.c b/src/lapack/dlarf.c
new file mode 100644
index 0000000..44a0d86
--- /dev/null
+++ b/src/lapack/dlarf.c
@@ -0,0 +1,181 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b4 = 1.;
+static doublereal c_b5 = 0.;
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdlarf_(char *side, integer *m, integer *n, doublereal *v,
+	 integer *incv, doublereal *tau, doublereal *c__, integer *ldc, 
+	doublereal *work)
+{
+    /* System generated locals */
+    integer c_dim1, c_offset;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__;
+    logical applyleft;
+    extern /* Subroutine */ int igraphdger_(integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *);
+    integer lastc, lastv;
+    extern integer igraphiladlc_(integer *, integer *, doublereal *, integer *), 
+	    igraphiladlr_(integer *, integer *, doublereal *, integer *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLARF applies a real elementary reflector H to a real m by n matrix   
+    C, from either the left or the right. H is represented in the form   
+
+          H = I - tau * v * v**T   
+
+    where tau is a real scalar and v is a real vector.   
+
+    If tau = 0, then H is taken to be the unit matrix.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': form  H * C   
+            = 'R': form  C * H   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C.   
+
+    V       (input) DOUBLE PRECISION array, dimension   
+                       (1 + (M-1)*abs(INCV)) if SIDE = 'L'   
+                    or (1 + (N-1)*abs(INCV)) if SIDE = 'R'   
+            The vector v in the representation of H. V is not used if   
+            TAU = 0.   
+
+    INCV    (input) INTEGER   
+            The increment between elements of v. INCV <> 0.   
+
+    TAU     (input) DOUBLE PRECISION   
+            The value tau in the representation of H.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the m by n matrix C.   
+            On exit, C is overwritten by the matrix H * C if SIDE = 'L',   
+            or C * H if SIDE = 'R'.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension   
+                           (N) if SIDE = 'L'   
+                        or (M) if SIDE = 'R'   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --v;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    applyleft = igraphlsame_(side, "L");
+    lastv = 0;
+    lastc = 0;
+    if (*tau != 0.) {
+/*     Set up variables for scanning V.  LASTV begins pointing to the end   
+       of V. */
+	if (applyleft) {
+	    lastv = *m;
+	} else {
+	    lastv = *n;
+	}
+	if (*incv > 0) {
+	    i__ = (lastv - 1) * *incv + 1;
+	} else {
+	    i__ = 1;
+	}
+/*     Look for the last non-zero row in V. */
+	while(lastv > 0 && v[i__] == 0.) {
+	    --lastv;
+	    i__ -= *incv;
+	}
+	if (applyleft) {
+/*     Scan for the last non-zero column in C(1:lastv,:). */
+	    lastc = igraphiladlc_(&lastv, n, &c__[c_offset], ldc);
+	} else {
+/*     Scan for the last non-zero row in C(:,1:lastv). */
+	    lastc = igraphiladlr_(m, &lastv, &c__[c_offset], ldc);
+	}
+    }
+/*     Note that lastc.eq.0 renders the BLAS operations null; no special   
+       case is needed at this level. */
+    if (applyleft) {
+
+/*        Form  H * C */
+
+	if (lastv > 0) {
+
+/*           w(1:lastc,1) := C(1:lastv,1:lastc)**T * v(1:lastv,1) */
+
+	    igraphdgemv_("Transpose", &lastv, &lastc, &c_b4, &c__[c_offset], ldc, &
+		    v[1], incv, &c_b5, &work[1], &c__1);
+
+/*           C(1:lastv,1:lastc) := C(...) - v(1:lastv,1) * w(1:lastc,1)**T */
+
+	    d__1 = -(*tau);
+	    igraphdger_(&lastv, &lastc, &d__1, &v[1], incv, &work[1], &c__1, &c__[
+		    c_offset], ldc);
+	}
+    } else {
+
+/*        Form  C * H */
+
+	if (lastv > 0) {
+
+/*           w(1:lastc,1) := C(1:lastc,1:lastv) * v(1:lastv,1) */
+
+	    igraphdgemv_("No transpose", &lastc, &lastv, &c_b4, &c__[c_offset], ldc,
+		     &v[1], incv, &c_b5, &work[1], &c__1);
+
+/*           C(1:lastc,1:lastv) := C(...) - w(1:lastc,1) * v(1:lastv,1)**T */
+
+	    d__1 = -(*tau);
+	    igraphdger_(&lastc, &lastv, &d__1, &work[1], &c__1, &v[1], incv, &c__[
+		    c_offset], ldc);
+	}
+    }
+    return 0;
+
+/*     End of DLARF */
+
+} /* igraphdlarf_ */
+
diff --git a/src/lapack/dlarfb.c b/src/lapack/dlarfb.c
new file mode 100644
index 0000000..37c7a98
--- /dev/null
+++ b/src/lapack/dlarfb.c
@@ -0,0 +1,787 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b14 = 1.;
+static doublereal c_b25 = -1.;
+
+/* Subroutine */ int igraphdlarfb_(char *side, char *trans, char *direct, char *
+	storev, integer *m, integer *n, integer *k, doublereal *v, integer *
+	ldv, doublereal *t, integer *ldt, doublereal *c__, integer *ldc, 
+	doublereal *work, integer *ldwork)
+{
+    /* System generated locals */
+    integer c_dim1, c_offset, t_dim1, t_offset, v_dim1, v_offset, work_dim1, 
+	    work_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j;
+    extern /* Subroutine */ int igraphdgemm_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    extern logical igraphlsame_(char *, char *);
+    integer lastc;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdtrmm_(char *, char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    integer lastv;
+    extern integer igraphiladlc_(integer *, integer *, doublereal *, integer *), 
+	    igraphiladlr_(integer *, integer *, doublereal *, integer *);
+    char transt[1];
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLARFB applies a real block reflector H or its transpose H**T to a   
+    real m by n matrix C, from either the left or the right.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply H or H**T from the Left   
+            = 'R': apply H or H**T from the Right   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N': apply H (No transpose)   
+            = 'T': apply H**T (Transpose)   
+
+    DIRECT  (input) CHARACTER*1   
+            Indicates how H is formed from a product of elementary   
+            reflectors   
+            = 'F': H = H(1) H(2) . . . H(k) (Forward)   
+            = 'B': H = H(k) . . . H(2) H(1) (Backward)   
+
+    STOREV  (input) CHARACTER*1   
+            Indicates how the vectors which define the elementary   
+            reflectors are stored:   
+            = 'C': Columnwise   
+            = 'R': Rowwise   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C.   
+
+    K       (input) INTEGER   
+            The order of the matrix T (= the number of elementary   
+            reflectors whose product defines the block reflector).   
+
+    V       (input) DOUBLE PRECISION array, dimension   
+                                  (LDV,K) if STOREV = 'C'   
+                                  (LDV,M) if STOREV = 'R' and SIDE = 'L'   
+                                  (LDV,N) if STOREV = 'R' and SIDE = 'R'   
+            The matrix V. See Further Details.   
+
+    LDV     (input) INTEGER   
+            The leading dimension of the array V.   
+            If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M);   
+            if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N);   
+            if STOREV = 'R', LDV >= K.   
+
+    T       (input) DOUBLE PRECISION array, dimension (LDT,K)   
+            The triangular k by k matrix T in the representation of the   
+            block reflector.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= K.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the m by n matrix C.   
+            On exit, C is overwritten by H*C or H**T*C or C*H or C*H**T.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (LDWORK,K)   
+
+    LDWORK  (input) INTEGER   
+            The leading dimension of the array WORK.   
+            If SIDE = 'L', LDWORK >= max(1,N);   
+            if SIDE = 'R', LDWORK >= max(1,M).   
+
+    Further Details   
+    ===============   
+
+    The shape of the matrix V and the storage of the vectors which define   
+    the H(i) is best illustrated by the following example with n = 5 and   
+    k = 3. The elements equal to 1 are not stored; the corresponding   
+    array elements are modified but restored on exit. The rest of the   
+    array is not used.   
+
+    DIRECT = 'F' and STOREV = 'C':         DIRECT = 'F' and STOREV = 'R':   
+
+                 V = (  1       )                 V = (  1 v1 v1 v1 v1 )   
+                     ( v1  1    )                     (     1 v2 v2 v2 )   
+                     ( v1 v2  1 )                     (        1 v3 v3 )   
+                     ( v1 v2 v3 )   
+                     ( v1 v2 v3 )   
+
+    DIRECT = 'B' and STOREV = 'C':         DIRECT = 'B' and STOREV = 'R':   
+
+                 V = ( v1 v2 v3 )                 V = ( v1 v1  1       )   
+                     ( v1 v2 v3 )                     ( v2 v2 v2  1    )   
+                     (  1 v2 v3 )                     ( v3 v3 v3 v3  1 )   
+                     (     1 v3 )   
+                     (        1 )   
+
+    =====================================================================   
+
+
+       Quick return if possible   
+
+       Parameter adjustments */
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    work_dim1 = *ldwork;
+    work_offset = 1 + work_dim1;
+    work -= work_offset;
+
+    /* Function Body */
+    if (*m <= 0 || *n <= 0) {
+	return 0;
+    }
+
+    if (igraphlsame_(trans, "N")) {
+	*(unsigned char *)transt = 'T';
+    } else {
+	*(unsigned char *)transt = 'N';
+    }
+
+    if (igraphlsame_(storev, "C")) {
+
+	if (igraphlsame_(direct, "F")) {
+
+/*           Let  V =  ( V1 )    (first K rows)   
+                       ( V2 )   
+             where  V1  is unit lower triangular. */
+
+	    if (igraphlsame_(side, "L")) {
+
+/*              Form  H * C  or  H**T * C  where  C = ( C1 )   
+                                                      ( C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlr_(m, k, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlc_(&lastv, n, &c__[c_offset], ldc);
+
+/*              W := C**T * V  =  (C1**T * V1 + C2**T * V2)  (stored in WORK)   
+
+                W := C1**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 
+			    + 1], &c__1);
+/* L10: */
+		}
+
+/*              W := W * V1 */
+
+		igraphdtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C2**T *V2 */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("Transpose", "No transpose", &lastc, k, &i__1, &
+			    c_b14, &c__[*k + 1 + c_dim1], ldc, &v[*k + 1 + 
+			    v_dim1], ldv, &c_b14, &work[work_offset], ldwork);
+		}
+
+/*              W := W * T**T  or  W * T */
+
+		igraphdtrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, &
+			c_b14, &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - V * W**T */
+
+		if (lastv > *k) {
+
+/*                 C2 := C2 - V2 * W**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "Transpose", &i__1, &lastc, k, &
+			    c_b25, &v[*k + 1 + v_dim1], ldv, &work[
+			    work_offset], ldwork, &c_b14, &c__[*k + 1 + 
+			    c_dim1], ldc);
+		}
+
+/*              W := W * V1**T */
+
+		igraphdtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+
+/*              C1 := C1 - W**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[j + i__ * c_dim1] -= work[i__ + j * work_dim1];
+/* L20: */
+		    }
+/* L30: */
+		}
+
+	    } else if (igraphlsame_(side, "R")) {
+
+/*              Form  C * H  or  C * H**T  where  C = ( C1  C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlr_(n, k, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlr_(m, &lastv, &c__[c_offset], ldc);
+
+/*              W := C * V  =  (C1*V1 + C2*V2)  (stored in WORK)   
+
+                W := C1 */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * 
+			    work_dim1 + 1], &c__1);
+/* L40: */
+		}
+
+/*              W := W * V1 */
+
+		igraphdtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C2 * V2 */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "No transpose", &lastc, k, &i__1, &
+			    c_b14, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[*k + 
+			    1 + v_dim1], ldv, &c_b14, &work[work_offset], 
+			    ldwork);
+		}
+
+/*              W := W * T  or  W * T**T */
+
+		igraphdtrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b14,
+			 &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - W * V**T */
+
+		if (lastv > *k) {
+
+/*                 C2 := C2 - W * V2**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "Transpose", &lastc, &i__1, k, &
+			    c_b25, &work[work_offset], ldwork, &v[*k + 1 + 
+			    v_dim1], ldv, &c_b14, &c__[(*k + 1) * c_dim1 + 1],
+			     ldc);
+		}
+
+/*              W := W * V1**T */
+
+		igraphdtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+
+/*              C1 := C1 - W */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] -= work[i__ + j * work_dim1];
+/* L50: */
+		    }
+/* L60: */
+		}
+	    }
+
+	} else {
+
+/*           Let  V =  ( V1 )   
+                       ( V2 )    (last K rows)   
+             where  V2  is unit upper triangular. */
+
+	    if (igraphlsame_(side, "L")) {
+
+/*              Form  H * C  or  H**T * C  where  C = ( C1 )   
+                                                      ( C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlr_(m, k, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlc_(&lastv, n, &c__[c_offset], ldc);
+
+/*              W := C**T * V  =  (C1**T * V1 + C2**T * V2)  (stored in WORK)   
+
+                W := C2**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[
+			    j * work_dim1 + 1], &c__1);
+/* L70: */
+		}
+
+/*              W := W * V2 */
+
+		igraphdtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[lastv - *k + 1 + v_dim1], ldv, &work[
+			work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C1**T*V1 */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("Transpose", "No transpose", &lastc, k, &i__1, &
+			    c_b14, &c__[c_offset], ldc, &v[v_offset], ldv, &
+			    c_b14, &work[work_offset], ldwork);
+		}
+
+/*              W := W * T**T  or  W * T */
+
+		igraphdtrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, &
+			c_b14, &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - V * W**T */
+
+		if (lastv > *k) {
+
+/*                 C1 := C1 - V1 * W**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "Transpose", &i__1, &lastc, k, &
+			    c_b25, &v[v_offset], ldv, &work[work_offset], 
+			    ldwork, &c_b14, &c__[c_offset], ldc);
+		}
+
+/*              W := W * V2**T */
+
+		igraphdtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[lastv - *k + 1 + v_dim1], ldv, &work[
+			work_offset], ldwork);
+
+/*              C2 := C2 - W**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[lastv - *k + j + i__ * c_dim1] -= work[i__ + j * 
+				work_dim1];
+/* L80: */
+		    }
+/* L90: */
+		}
+
+	    } else if (igraphlsame_(side, "R")) {
+
+/*              Form  C * H  or  C * H**T  where  C = ( C1  C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlr_(n, k, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlr_(m, &lastv, &c__[c_offset], ldc);
+
+/*              W := C * V  =  (C1*V1 + C2*V2)  (stored in WORK)   
+
+                W := C2 */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[(*n - *k + j) * c_dim1 + 1], &c__1, &
+			    work[j * work_dim1 + 1], &c__1);
+/* L100: */
+		}
+
+/*              W := W * V2 */
+
+		igraphdtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[lastv - *k + 1 + v_dim1], ldv, &work[
+			work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C1 * V1 */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "No transpose", &lastc, k, &i__1, &
+			    c_b14, &c__[c_offset], ldc, &v[v_offset], ldv, &
+			    c_b14, &work[work_offset], ldwork);
+		}
+
+/*              W := W * T  or  W * T**T */
+
+		igraphdtrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b14,
+			 &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - W * V**T */
+
+		if (lastv > *k) {
+
+/*                 C1 := C1 - W * V1**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "Transpose", &lastc, &i__1, k, &
+			    c_b25, &work[work_offset], ldwork, &v[v_offset], 
+			    ldv, &c_b14, &c__[c_offset], ldc);
+		}
+
+/*              W := W * V2**T */
+
+		igraphdtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[lastv - *k + 1 + v_dim1], ldv, &work[
+			work_offset], ldwork);
+
+/*              C2 := C2 - W */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + (lastv - *k + j) * c_dim1] -= work[i__ + j *
+				 work_dim1];
+/* L110: */
+		    }
+/* L120: */
+		}
+	    }
+	}
+
+    } else if (igraphlsame_(storev, "R")) {
+
+	if (igraphlsame_(direct, "F")) {
+
+/*           Let  V =  ( V1  V2 )    (V1: first K columns)   
+             where  V1  is unit upper triangular. */
+
+	    if (igraphlsame_(side, "L")) {
+
+/*              Form  H * C  or  H**T * C  where  C = ( C1 )   
+                                                      ( C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlc_(k, m, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlc_(&lastv, n, &c__[c_offset], ldc);
+
+/*              W := C**T * V**T  =  (C1**T * V1**T + C2**T * V2**T) (stored in WORK)   
+
+                W := C1**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 
+			    + 1], &c__1);
+/* L130: */
+		}
+
+/*              W := W * V1**T */
+
+		igraphdtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C2**T*V2**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("Transpose", "Transpose", &lastc, k, &i__1, &c_b14,
+			     &c__[*k + 1 + c_dim1], ldc, &v[(*k + 1) * v_dim1 
+			    + 1], ldv, &c_b14, &work[work_offset], ldwork);
+		}
+
+/*              W := W * T**T  or  W * T */
+
+		igraphdtrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, &
+			c_b14, &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - V**T * W**T */
+
+		if (lastv > *k) {
+
+/*                 C2 := C2 - V2**T * W**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("Transpose", "Transpose", &i__1, &lastc, k, &c_b25,
+			     &v[(*k + 1) * v_dim1 + 1], ldv, &work[
+			    work_offset], ldwork, &c_b14, &c__[*k + 1 + 
+			    c_dim1], ldc);
+		}
+
+/*              W := W * V1 */
+
+		igraphdtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+
+/*              C1 := C1 - W**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[j + i__ * c_dim1] -= work[i__ + j * work_dim1];
+/* L140: */
+		    }
+/* L150: */
+		}
+
+	    } else if (igraphlsame_(side, "R")) {
+
+/*              Form  C * H  or  C * H**T  where  C = ( C1  C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlc_(k, n, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlr_(m, &lastv, &c__[c_offset], ldc);
+
+/*              W := C * V**T  =  (C1*V1**T + C2*V2**T)  (stored in WORK)   
+
+                W := C1 */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * 
+			    work_dim1 + 1], &c__1);
+/* L160: */
+		}
+
+/*              W := W * V1**T */
+
+		igraphdtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C2 * V2**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "Transpose", &lastc, k, &i__1, &
+			    c_b14, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[(*k + 
+			    1) * v_dim1 + 1], ldv, &c_b14, &work[work_offset],
+			     ldwork);
+		}
+
+/*              W := W * T  or  W * T**T */
+
+		igraphdtrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b14,
+			 &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - W * V */
+
+		if (lastv > *k) {
+
+/*                 C2 := C2 - W * V2 */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "No transpose", &lastc, &i__1, k, &
+			    c_b25, &work[work_offset], ldwork, &v[(*k + 1) * 
+			    v_dim1 + 1], ldv, &c_b14, &c__[(*k + 1) * c_dim1 
+			    + 1], ldc);
+		}
+
+/*              W := W * V1 */
+
+		igraphdtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[v_offset], ldv, &work[work_offset], ldwork);
+
+/*              C1 := C1 - W */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] -= work[i__ + j * work_dim1];
+/* L170: */
+		    }
+/* L180: */
+		}
+
+	    }
+
+	} else {
+
+/*           Let  V =  ( V1  V2 )    (V2: last K columns)   
+             where  V2  is unit lower triangular. */
+
+	    if (igraphlsame_(side, "L")) {
+
+/*              Form  H * C  or  H**T * C  where  C = ( C1 )   
+                                                      ( C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlc_(k, m, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlc_(&lastv, n, &c__[c_offset], ldc);
+
+/*              W := C**T * V**T  =  (C1**T * V1**T + C2**T * V2**T) (stored in WORK)   
+
+                W := C2**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[
+			    j * work_dim1 + 1], &c__1);
+/* L190: */
+		}
+
+/*              W := W * V2**T */
+
+		igraphdtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[
+			work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C1**T * V1**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("Transpose", "Transpose", &lastc, k, &i__1, &c_b14,
+			     &c__[c_offset], ldc, &v[v_offset], ldv, &c_b14, &
+			    work[work_offset], ldwork);
+		}
+
+/*              W := W * T**T  or  W * T */
+
+		igraphdtrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, &
+			c_b14, &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - V**T * W**T */
+
+		if (lastv > *k) {
+
+/*                 C1 := C1 - V1**T * W**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("Transpose", "Transpose", &i__1, &lastc, k, &c_b25,
+			     &v[v_offset], ldv, &work[work_offset], ldwork, &
+			    c_b14, &c__[c_offset], ldc);
+		}
+
+/*              W := W * V2 */
+
+		igraphdtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[
+			work_offset], ldwork);
+
+/*              C2 := C2 - W**T */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[lastv - *k + j + i__ * c_dim1] -= work[i__ + j * 
+				work_dim1];
+/* L200: */
+		    }
+/* L210: */
+		}
+
+	    } else if (igraphlsame_(side, "R")) {
+
+/*              Form  C * H  or  C * H**T  where  C = ( C1  C2 )   
+
+   Computing MAX */
+		i__1 = *k, i__2 = igraphiladlc_(k, n, &v[v_offset], ldv);
+		lastv = max(i__1,i__2);
+		lastc = igraphiladlr_(m, &lastv, &c__[c_offset], ldc);
+
+/*              W := C * V**T  =  (C1*V1**T + C2*V2**T)  (stored in WORK)   
+
+                W := C2 */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    igraphdcopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1,
+			     &work[j * work_dim1 + 1], &c__1);
+/* L220: */
+		}
+
+/*              W := W * V2**T */
+
+		igraphdtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, &
+			c_b14, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[
+			work_offset], ldwork);
+		if (lastv > *k) {
+
+/*                 W := W + C1 * V1**T */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "Transpose", &lastc, k, &i__1, &
+			    c_b14, &c__[c_offset], ldc, &v[v_offset], ldv, &
+			    c_b14, &work[work_offset], ldwork);
+		}
+
+/*              W := W * T  or  W * T**T */
+
+		igraphdtrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b14,
+			 &t[t_offset], ldt, &work[work_offset], ldwork);
+
+/*              C := C - W * V */
+
+		if (lastv > *k) {
+
+/*                 C1 := C1 - W * V1 */
+
+		    i__1 = lastv - *k;
+		    igraphdgemm_("No transpose", "No transpose", &lastc, &i__1, k, &
+			    c_b25, &work[work_offset], ldwork, &v[v_offset], 
+			    ldv, &c_b14, &c__[c_offset], ldc);
+		}
+
+/*              W := W * V2 */
+
+		igraphdtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, &
+			c_b14, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[
+			work_offset], ldwork);
+
+/*              C1 := C1 - W */
+
+		i__1 = *k;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = lastc;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + (lastv - *k + j) * c_dim1] -= work[i__ + j *
+				 work_dim1];
+/* L230: */
+		    }
+/* L240: */
+		}
+
+	    }
+
+	}
+    }
+
+    return 0;
+
+/*     End of DLARFB */
+
+} /* igraphdlarfb_ */
+
diff --git a/src/lapack/dlarfg.c b/src/lapack/dlarfg.c
new file mode 100644
index 0000000..8f16bd4
--- /dev/null
+++ b/src/lapack/dlarfg.c
@@ -0,0 +1,156 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarfg_(integer *n, doublereal *alpha, doublereal *x, 
+	integer *incx, doublereal *tau)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1;
+
+    /* Builtin functions */
+    double d_sign(doublereal *, doublereal *);
+
+    /* Local variables */
+    integer j, knt;
+    doublereal beta;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    doublereal xnorm;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *), igraphdlamch_(char *);
+    doublereal safmin, rsafmn;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLARFG generates a real elementary reflector H of order n, such   
+    that   
+
+          H * ( alpha ) = ( beta ),   H**T * H = I.   
+              (   x   )   (   0  )   
+
+    where alpha and beta are scalars, and x is an (n-1)-element real   
+    vector. H is represented in the form   
+
+          H = I - tau * ( 1 ) * ( 1 v**T ) ,   
+                        ( v )   
+
+    where tau is a real scalar and v is a real (n-1)-element   
+    vector.   
+
+    If the elements of x are all zero, then tau = 0 and H is taken to be   
+    the unit matrix.   
+
+    Otherwise  1 <= tau <= 2.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the elementary reflector.   
+
+    ALPHA   (input/output) DOUBLE PRECISION   
+            On entry, the value alpha.   
+            On exit, it is overwritten with the value beta.   
+
+    X       (input/output) DOUBLE PRECISION array, dimension   
+                           (1+(N-2)*abs(INCX))   
+            On entry, the vector x.   
+            On exit, it is overwritten with the vector v.   
+
+    INCX    (input) INTEGER   
+            The increment between elements of X. INCX > 0.   
+
+    TAU     (output) DOUBLE PRECISION   
+            The value tau.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --x;
+
+    /* Function Body */
+    if (*n <= 1) {
+	*tau = 0.;
+	return 0;
+    }
+
+    i__1 = *n - 1;
+    xnorm = igraphdnrm2_(&i__1, &x[1], incx);
+
+    if (xnorm == 0.) {
+
+/*        H  =  I */
+
+	*tau = 0.;
+    } else {
+
+/*        general case */
+
+	d__1 = igraphdlapy2_(alpha, &xnorm);
+	beta = -d_sign(&d__1, alpha);
+	safmin = igraphdlamch_("S") / igraphdlamch_("E");
+	knt = 0;
+	if (abs(beta) < safmin) {
+
+/*           XNORM, BETA may be inaccurate; scale X and recompute them */
+
+	    rsafmn = 1. / safmin;
+L10:
+	    ++knt;
+	    i__1 = *n - 1;
+	    igraphdscal_(&i__1, &rsafmn, &x[1], incx);
+	    beta *= rsafmn;
+	    *alpha *= rsafmn;
+	    if (abs(beta) < safmin) {
+		goto L10;
+	    }
+
+/*           New BETA is at most 1, at least SAFMIN */
+
+	    i__1 = *n - 1;
+	    xnorm = igraphdnrm2_(&i__1, &x[1], incx);
+	    d__1 = igraphdlapy2_(alpha, &xnorm);
+	    beta = -d_sign(&d__1, alpha);
+	}
+	*tau = (beta - *alpha) / beta;
+	i__1 = *n - 1;
+	d__1 = 1. / (*alpha - beta);
+	igraphdscal_(&i__1, &d__1, &x[1], incx);
+
+/*        If ALPHA is subnormal, it may lose relative accuracy */
+
+	i__1 = knt;
+	for (j = 1; j <= i__1; ++j) {
+	    beta *= safmin;
+/* L20: */
+	}
+	*alpha = beta;
+    }
+
+    return 0;
+
+/*     End of DLARFG */
+
+} /* igraphdlarfg_ */
+
diff --git a/src/lapack/dlarft.c b/src/lapack/dlarft.c
new file mode 100644
index 0000000..4339010
--- /dev/null
+++ b/src/lapack/dlarft.c
@@ -0,0 +1,345 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b10 = 0.;
+
+/* Subroutine */ int igraphdlarft_(char *direct, char *storev, integer *n, integer *
+	k, doublereal *v, integer *ldv, doublereal *tau, doublereal *t, 
+	integer *ldt)
+{
+    /* System generated locals */
+    integer t_dim1, t_offset, v_dim1, v_offset, i__1, i__2, i__3;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__, j, prevlastv;
+    doublereal vii;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *);
+    integer lastv;
+    extern /* Subroutine */ int igraphdtrmv_(char *, char *, char *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLARFT forms the triangular factor T of a real block reflector H   
+    of order n, which is defined as a product of k elementary reflectors.   
+
+    If DIRECT = 'F', H = H(1) H(2) . . . H(k) and T is upper triangular;   
+
+    If DIRECT = 'B', H = H(k) . . . H(2) H(1) and T is lower triangular.   
+
+    If STOREV = 'C', the vector which defines the elementary reflector   
+    H(i) is stored in the i-th column of the array V, and   
+
+       H  =  I - V * T * V**T   
+
+    If STOREV = 'R', the vector which defines the elementary reflector   
+    H(i) is stored in the i-th row of the array V, and   
+
+       H  =  I - V**T * T * V   
+
+    Arguments   
+    =========   
+
+    DIRECT  (input) CHARACTER*1   
+            Specifies the order in which the elementary reflectors are   
+            multiplied to form the block reflector:   
+            = 'F': H = H(1) H(2) . . . H(k) (Forward)   
+            = 'B': H = H(k) . . . H(2) H(1) (Backward)   
+
+    STOREV  (input) CHARACTER*1   
+            Specifies how the vectors which define the elementary   
+            reflectors are stored (see also Further Details):   
+            = 'C': columnwise   
+            = 'R': rowwise   
+
+    N       (input) INTEGER   
+            The order of the block reflector H. N >= 0.   
+
+    K       (input) INTEGER   
+            The order of the triangular factor T (= the number of   
+            elementary reflectors). K >= 1.   
+
+    V       (input/output) DOUBLE PRECISION array, dimension   
+                                 (LDV,K) if STOREV = 'C'   
+                                 (LDV,N) if STOREV = 'R'   
+            The matrix V. See further details.   
+
+    LDV     (input) INTEGER   
+            The leading dimension of the array V.   
+            If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K.   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i).   
+
+    T       (output) DOUBLE PRECISION array, dimension (LDT,K)   
+            The k by k triangular factor T of the block reflector.   
+            If DIRECT = 'F', T is upper triangular; if DIRECT = 'B', T is   
+            lower triangular. The rest of the array is not used.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= K.   
+
+    Further Details   
+    ===============   
+
+    The shape of the matrix V and the storage of the vectors which define   
+    the H(i) is best illustrated by the following example with n = 5 and   
+    k = 3. The elements equal to 1 are not stored; the corresponding   
+    array elements are modified but restored on exit. The rest of the   
+    array is not used.   
+
+    DIRECT = 'F' and STOREV = 'C':         DIRECT = 'F' and STOREV = 'R':   
+
+                 V = (  1       )                 V = (  1 v1 v1 v1 v1 )   
+                     ( v1  1    )                     (     1 v2 v2 v2 )   
+                     ( v1 v2  1 )                     (        1 v3 v3 )   
+                     ( v1 v2 v3 )   
+                     ( v1 v2 v3 )   
+
+    DIRECT = 'B' and STOREV = 'C':         DIRECT = 'B' and STOREV = 'R':   
+
+                 V = ( v1 v2 v3 )                 V = ( v1 v1  1       )   
+                     ( v1 v2 v3 )                     ( v2 v2 v2  1    )   
+                     (  1 v2 v3 )                     ( v3 v3 v3 v3  1 )   
+                     (     1 v3 )   
+                     (        1 )   
+
+    =====================================================================   
+
+
+       Quick return if possible   
+
+       Parameter adjustments */
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    --tau;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+
+    /* Function Body */
+    if (*n == 0) {
+	return 0;
+    }
+
+    if (igraphlsame_(direct, "F")) {
+	prevlastv = *n;
+	i__1 = *k;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    prevlastv = max(i__,prevlastv);
+	    if (tau[i__] == 0.) {
+
+/*              H(i)  =  I */
+
+		i__2 = i__;
+		for (j = 1; j <= i__2; ++j) {
+		    t[j + i__ * t_dim1] = 0.;
+/* L10: */
+		}
+	    } else {
+
+/*              general case */
+
+		vii = v[i__ + i__ * v_dim1];
+		v[i__ + i__ * v_dim1] = 1.;
+		if (igraphlsame_(storev, "C")) {
+/*                 Skip any trailing zeros. */
+		    lastv = *n;
+L14:
+		    if (v[lastv + i__ * v_dim1] != 0.) {
+			goto L15;
+		    }
+		    if (lastv == i__ + 1) {
+			goto L15;
+		    }
+		    --lastv;
+		    goto L14;
+L15:
+/*                 DO LASTV = N, I+1, -1   
+                      IF( V( LASTV, I ).NE.ZERO ) EXIT   
+                   END DO */
+		    j = min(lastv,prevlastv);
+
+/*                 T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**T * V(i:j,i) */
+
+		    i__2 = j - i__ + 1;
+		    i__3 = i__ - 1;
+		    d__1 = -tau[i__];
+		    igraphdgemv_("Transpose", &i__2, &i__3, &d__1, &v[i__ + v_dim1],
+			     ldv, &v[i__ + i__ * v_dim1], &c__1, &c_b10, &t[
+			    i__ * t_dim1 + 1], &c__1);
+		} else {
+/*                 Skip any trailing zeros. */
+		    lastv = *n;
+L16:
+		    if (v[i__ + lastv * v_dim1] != 0.) {
+			goto L17;
+		    }
+		    if (lastv == i__ + 1) {
+			goto L17;
+		    }
+		    --lastv;
+		    goto L16;
+L17:
+/*                 DO LASTV = N, I+1, -1   
+                      IF( V( I, LASTV ).NE.ZERO ) EXIT   
+                   END DO */
+		    j = min(lastv,prevlastv);
+
+/*                 T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**T */
+
+		    i__2 = i__ - 1;
+		    i__3 = j - i__ + 1;
+		    d__1 = -tau[i__];
+		    igraphdgemv_("No transpose", &i__2, &i__3, &d__1, &v[i__ * 
+			    v_dim1 + 1], ldv, &v[i__ + i__ * v_dim1], ldv, &
+			    c_b10, &t[i__ * t_dim1 + 1], &c__1);
+		}
+		v[i__ + i__ * v_dim1] = vii;
+
+/*              T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */
+
+		i__2 = i__ - 1;
+		igraphdtrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[
+			t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1);
+		t[i__ + i__ * t_dim1] = tau[i__];
+		if (i__ > 1) {
+		    prevlastv = max(prevlastv,lastv);
+		} else {
+		    prevlastv = lastv;
+		}
+	    }
+/* L20: */
+	}
+    } else {
+	prevlastv = 1;
+	for (i__ = *k; i__ >= 1; --i__) {
+	    if (tau[i__] == 0.) {
+
+/*              H(i)  =  I */
+
+		i__1 = *k;
+		for (j = i__; j <= i__1; ++j) {
+		    t[j + i__ * t_dim1] = 0.;
+/* L30: */
+		}
+	    } else {
+
+/*              general case */
+
+		if (i__ < *k) {
+		    if (igraphlsame_(storev, "C")) {
+			vii = v[*n - *k + i__ + i__ * v_dim1];
+			v[*n - *k + i__ + i__ * v_dim1] = 1.;
+/*                    Skip any leading zeros. */
+			lastv = 1;
+L34:
+			if (v[lastv + i__ * v_dim1] != 0.) {
+			    goto L35;
+			}
+			if (lastv == i__ - 1) {
+			    goto L35;
+			}
+			++lastv;
+			goto L34;
+L35:
+/*                    DO LASTV = 1, I-1   
+                         IF( V( LASTV, I ).NE.ZERO ) EXIT   
+                      END DO */
+			j = max(lastv,prevlastv);
+
+/*                    T(i+1:k,i) :=   
+                              - tau(i) * V(j:n-k+i,i+1:k)**T * V(j:n-k+i,i) */
+
+			i__1 = *n - *k + i__ - j + 1;
+			i__2 = *k - i__;
+			d__1 = -tau[i__];
+			igraphdgemv_("Transpose", &i__1, &i__2, &d__1, &v[j + (i__ 
+				+ 1) * v_dim1], ldv, &v[j + i__ * v_dim1], &
+				c__1, &c_b10, &t[i__ + 1 + i__ * t_dim1], &
+				c__1);
+			v[*n - *k + i__ + i__ * v_dim1] = vii;
+		    } else {
+			vii = v[i__ + (*n - *k + i__) * v_dim1];
+			v[i__ + (*n - *k + i__) * v_dim1] = 1.;
+/*                    Skip any leading zeros. */
+			lastv = 1;
+/* L36: */
+			if (v[i__ + lastv * v_dim1] != 0.) {
+			    goto L37;
+			}
+			if (lastv == i__ - 1) {
+			    goto L37;
+			}
+			++lastv;
+L37:
+/*                    DO LASTV = 1, I-1   
+                         IF( V( I, LASTV ).NE.ZERO ) EXIT   
+                      END DO */
+			j = max(lastv,prevlastv);
+
+/*                    T(i+1:k,i) :=   
+                              - tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**T */
+
+			i__1 = *k - i__;
+			i__2 = *n - *k + i__ - j + 1;
+			d__1 = -tau[i__];
+			igraphdgemv_("No transpose", &i__1, &i__2, &d__1, &v[i__ + 
+				1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], 
+				ldv, &c_b10, &t[i__ + 1 + i__ * t_dim1], &
+				c__1);
+			v[i__ + (*n - *k + i__) * v_dim1] = vii;
+		    }
+
+/*                 T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */
+
+		    i__1 = *k - i__;
+		    igraphdtrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ 
+			    + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ *
+			     t_dim1], &c__1)
+			    ;
+		    if (i__ > 1) {
+			prevlastv = min(prevlastv,lastv);
+		    } else {
+			prevlastv = lastv;
+		    }
+		}
+		t[i__ + i__ * t_dim1] = tau[i__];
+	    }
+/* L40: */
+	}
+    }
+    return 0;
+
+/*     End of DLARFT */
+
+} /* igraphdlarft_ */
+
diff --git a/src/lapack/dlarfx.c b/src/lapack/dlarfx.c
new file mode 100644
index 0000000..0cae25f
--- /dev/null
+++ b/src/lapack/dlarfx.c
@@ -0,0 +1,718 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdlarfx_(char *side, integer *m, integer *n, doublereal *
+	v, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work)
+{
+    /* System generated locals */
+    integer c_dim1, c_offset, i__1;
+
+    /* Local variables */
+    integer j;
+    doublereal t1, t2, t3, t4, t5, t6, t7, t8, t9, v1, v2, v3, v4, v5, v6, v7,
+	     v8, v9, t10, v10, sum;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *);
+    extern logical igraphlsame_(char *, char *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLARFX applies a real elementary reflector H to a real m by n   
+    matrix C, from either the left or the right. H is represented in the   
+    form   
+
+          H = I - tau * v * v**T   
+
+    where tau is a real scalar and v is a real vector.   
+
+    If tau = 0, then H is taken to be the unit matrix   
+
+    This version uses inline code if H has order < 11.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': form  H * C   
+            = 'R': form  C * H   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C.   
+
+    V       (input) DOUBLE PRECISION array, dimension (M) if SIDE = 'L'   
+                                       or (N) if SIDE = 'R'   
+            The vector v in the representation of H.   
+
+    TAU     (input) DOUBLE PRECISION   
+            The value tau in the representation of H.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the m by n matrix C.   
+            On exit, C is overwritten by the matrix H * C if SIDE = 'L',   
+            or C * H if SIDE = 'R'.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDA >= (1,M).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension   
+                        (N) if SIDE = 'L'   
+                        or (M) if SIDE = 'R'   
+            WORK is not referenced if H has order < 11.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --v;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    if (*tau == 0.) {
+	return 0;
+    }
+    if (igraphlsame_(side, "L")) {
+
+/*        Form  H * C, where H has order m. */
+
+	switch (*m) {
+	    case 1:  goto L10;
+	    case 2:  goto L30;
+	    case 3:  goto L50;
+	    case 4:  goto L70;
+	    case 5:  goto L90;
+	    case 6:  goto L110;
+	    case 7:  goto L130;
+	    case 8:  goto L150;
+	    case 9:  goto L170;
+	    case 10:  goto L190;
+	}
+
+/*        Code for general M */
+
+	igraphdlarf_(side, m, n, &v[1], &c__1, tau, &c__[c_offset], ldc, &work[1]);
+	goto L410;
+L10:
+
+/*        Special code for 1 x 1 Householder */
+
+	t1 = 1. - *tau * v[1] * v[1];
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    c__[j * c_dim1 + 1] = t1 * c__[j * c_dim1 + 1];
+/* L20: */
+	}
+	goto L410;
+L30:
+
+/*        Special code for 2 x 2 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+/* L40: */
+	}
+	goto L410;
+L50:
+
+/*        Special code for 3 x 3 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+/* L60: */
+	}
+	goto L410;
+L70:
+
+/*        Special code for 4 x 4 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+/* L80: */
+	}
+	goto L410;
+L90:
+
+/*        Special code for 5 x 5 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[
+		    j * c_dim1 + 5];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+	    c__[j * c_dim1 + 5] -= sum * t5;
+/* L100: */
+	}
+	goto L410;
+L110:
+
+/*        Special code for 6 x 6 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[
+		    j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+	    c__[j * c_dim1 + 5] -= sum * t5;
+	    c__[j * c_dim1 + 6] -= sum * t6;
+/* L120: */
+	}
+	goto L410;
+L130:
+
+/*        Special code for 7 x 7 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[
+		    j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * 
+		    c_dim1 + 7];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+	    c__[j * c_dim1 + 5] -= sum * t5;
+	    c__[j * c_dim1 + 6] -= sum * t6;
+	    c__[j * c_dim1 + 7] -= sum * t7;
+/* L140: */
+	}
+	goto L410;
+L150:
+
+/*        Special code for 8 x 8 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	v8 = v[8];
+	t8 = *tau * v8;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[
+		    j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * 
+		    c_dim1 + 7] + v8 * c__[j * c_dim1 + 8];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+	    c__[j * c_dim1 + 5] -= sum * t5;
+	    c__[j * c_dim1 + 6] -= sum * t6;
+	    c__[j * c_dim1 + 7] -= sum * t7;
+	    c__[j * c_dim1 + 8] -= sum * t8;
+/* L160: */
+	}
+	goto L410;
+L170:
+
+/*        Special code for 9 x 9 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	v8 = v[8];
+	t8 = *tau * v8;
+	v9 = v[9];
+	t9 = *tau * v9;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[
+		    j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * 
+		    c_dim1 + 7] + v8 * c__[j * c_dim1 + 8] + v9 * c__[j * 
+		    c_dim1 + 9];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+	    c__[j * c_dim1 + 5] -= sum * t5;
+	    c__[j * c_dim1 + 6] -= sum * t6;
+	    c__[j * c_dim1 + 7] -= sum * t7;
+	    c__[j * c_dim1 + 8] -= sum * t8;
+	    c__[j * c_dim1 + 9] -= sum * t9;
+/* L180: */
+	}
+	goto L410;
+L190:
+
+/*        Special code for 10 x 10 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	v8 = v[8];
+	t8 = *tau * v8;
+	v9 = v[9];
+	t9 = *tau * v9;
+	v10 = v[10];
+	t10 = *tau * v10;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * 
+		    c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[
+		    j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * 
+		    c_dim1 + 7] + v8 * c__[j * c_dim1 + 8] + v9 * c__[j * 
+		    c_dim1 + 9] + v10 * c__[j * c_dim1 + 10];
+	    c__[j * c_dim1 + 1] -= sum * t1;
+	    c__[j * c_dim1 + 2] -= sum * t2;
+	    c__[j * c_dim1 + 3] -= sum * t3;
+	    c__[j * c_dim1 + 4] -= sum * t4;
+	    c__[j * c_dim1 + 5] -= sum * t5;
+	    c__[j * c_dim1 + 6] -= sum * t6;
+	    c__[j * c_dim1 + 7] -= sum * t7;
+	    c__[j * c_dim1 + 8] -= sum * t8;
+	    c__[j * c_dim1 + 9] -= sum * t9;
+	    c__[j * c_dim1 + 10] -= sum * t10;
+/* L200: */
+	}
+	goto L410;
+    } else {
+
+/*        Form  C * H, where H has order n. */
+
+	switch (*n) {
+	    case 1:  goto L210;
+	    case 2:  goto L230;
+	    case 3:  goto L250;
+	    case 4:  goto L270;
+	    case 5:  goto L290;
+	    case 6:  goto L310;
+	    case 7:  goto L330;
+	    case 8:  goto L350;
+	    case 9:  goto L370;
+	    case 10:  goto L390;
+	}
+
+/*        Code for general N */
+
+	igraphdlarf_(side, m, n, &v[1], &c__1, tau, &c__[c_offset], ldc, &work[1]);
+	goto L410;
+L210:
+
+/*        Special code for 1 x 1 Householder */
+
+	t1 = 1. - *tau * v[1] * v[1];
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    c__[j + c_dim1] = t1 * c__[j + c_dim1];
+/* L220: */
+	}
+	goto L410;
+L230:
+
+/*        Special code for 2 x 2 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+/* L240: */
+	}
+	goto L410;
+L250:
+
+/*        Special code for 3 x 3 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+/* L260: */
+	}
+	goto L410;
+L270:
+
+/*        Special code for 4 x 4 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+/* L280: */
+	}
+	goto L410;
+L290:
+
+/*        Special code for 5 x 5 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * 
+		    c__[j + c_dim1 * 5];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+	    c__[j + c_dim1 * 5] -= sum * t5;
+/* L300: */
+	}
+	goto L410;
+L310:
+
+/*        Special code for 6 x 6 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * 
+		    c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+	    c__[j + c_dim1 * 5] -= sum * t5;
+	    c__[j + c_dim1 * 6] -= sum * t6;
+/* L320: */
+	}
+	goto L410;
+L330:
+
+/*        Special code for 7 x 7 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * 
+		    c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[
+		    j + c_dim1 * 7];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+	    c__[j + c_dim1 * 5] -= sum * t5;
+	    c__[j + c_dim1 * 6] -= sum * t6;
+	    c__[j + c_dim1 * 7] -= sum * t7;
+/* L340: */
+	}
+	goto L410;
+L350:
+
+/*        Special code for 8 x 8 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	v8 = v[8];
+	t8 = *tau * v8;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * 
+		    c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[
+		    j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+	    c__[j + c_dim1 * 5] -= sum * t5;
+	    c__[j + c_dim1 * 6] -= sum * t6;
+	    c__[j + c_dim1 * 7] -= sum * t7;
+	    c__[j + (c_dim1 << 3)] -= sum * t8;
+/* L360: */
+	}
+	goto L410;
+L370:
+
+/*        Special code for 9 x 9 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	v8 = v[8];
+	t8 = *tau * v8;
+	v9 = v[9];
+	t9 = *tau * v9;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * 
+		    c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[
+		    j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)] + v9 * c__[
+		    j + c_dim1 * 9];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+	    c__[j + c_dim1 * 5] -= sum * t5;
+	    c__[j + c_dim1 * 6] -= sum * t6;
+	    c__[j + c_dim1 * 7] -= sum * t7;
+	    c__[j + (c_dim1 << 3)] -= sum * t8;
+	    c__[j + c_dim1 * 9] -= sum * t9;
+/* L380: */
+	}
+	goto L410;
+L390:
+
+/*        Special code for 10 x 10 Householder */
+
+	v1 = v[1];
+	t1 = *tau * v1;
+	v2 = v[2];
+	t2 = *tau * v2;
+	v3 = v[3];
+	t3 = *tau * v3;
+	v4 = v[4];
+	t4 = *tau * v4;
+	v5 = v[5];
+	t5 = *tau * v5;
+	v6 = v[6];
+	t6 = *tau * v6;
+	v7 = v[7];
+	t7 = *tau * v7;
+	v8 = v[8];
+	t8 = *tau * v8;
+	v9 = v[9];
+	t9 = *tau * v9;
+	v10 = v[10];
+	t10 = *tau * v10;
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * 
+		    c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * 
+		    c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[
+		    j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)] + v9 * c__[
+		    j + c_dim1 * 9] + v10 * c__[j + c_dim1 * 10];
+	    c__[j + c_dim1] -= sum * t1;
+	    c__[j + (c_dim1 << 1)] -= sum * t2;
+	    c__[j + c_dim1 * 3] -= sum * t3;
+	    c__[j + (c_dim1 << 2)] -= sum * t4;
+	    c__[j + c_dim1 * 5] -= sum * t5;
+	    c__[j + c_dim1 * 6] -= sum * t6;
+	    c__[j + c_dim1 * 7] -= sum * t7;
+	    c__[j + (c_dim1 << 3)] -= sum * t8;
+	    c__[j + c_dim1 * 9] -= sum * t9;
+	    c__[j + c_dim1 * 10] -= sum * t10;
+/* L400: */
+	}
+	goto L410;
+    }
+L410:
+    return 0;
+
+/*     End of DLARFX */
+
+} /* igraphdlarfx_ */
+
diff --git a/src/lapack/dlarnv.c b/src/lapack/dlarnv.c
new file mode 100644
index 0000000..7521317
--- /dev/null
+++ b/src/lapack/dlarnv.c
@@ -0,0 +1,132 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarnv_(integer *idist, integer *iseed, integer *n, 
+	doublereal *x)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+
+    /* Builtin functions */
+    double log(doublereal), sqrt(doublereal), cos(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal u[128];
+    integer il, iv, il2;
+    extern /* Subroutine */ int igraphdlaruv_(integer *, integer *, doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLARNV returns a vector of n random real numbers from a uniform or   
+    normal distribution.   
+
+    Arguments   
+    =========   
+
+    IDIST   (input) INTEGER   
+            Specifies the distribution of the random numbers:   
+            = 1:  uniform (0,1)   
+            = 2:  uniform (-1,1)   
+            = 3:  normal (0,1)   
+
+    ISEED   (input/output) INTEGER array, dimension (4)   
+            On entry, the seed of the random number generator; the array   
+            elements must be between 0 and 4095, and ISEED(4) must be   
+            odd.   
+            On exit, the seed is updated.   
+
+    N       (input) INTEGER   
+            The number of random numbers to be generated.   
+
+    X       (output) DOUBLE PRECISION array, dimension (N)   
+            The generated random numbers.   
+
+    Further Details   
+    ===============   
+
+    This routine calls the auxiliary routine DLARUV to generate random   
+    real numbers from a uniform (0,1) distribution, in batches of up to   
+    128 using vectorisable code. The Box-Muller method is used to   
+    transform numbers from a uniform to a normal distribution.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --x;
+    --iseed;
+
+    /* Function Body */
+    i__1 = *n;
+    for (iv = 1; iv <= i__1; iv += 64) {
+/* Computing MIN */
+	i__2 = 64, i__3 = *n - iv + 1;
+	il = min(i__2,i__3);
+	if (*idist == 3) {
+	    il2 = il << 1;
+	} else {
+	    il2 = il;
+	}
+
+/*        Call DLARUV to generate IL2 numbers from a uniform (0,1)   
+          distribution (IL2 <= LV) */
+
+	igraphdlaruv_(&iseed[1], &il2, u);
+
+	if (*idist == 1) {
+
+/*           Copy generated numbers */
+
+	    i__2 = il;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		x[iv + i__ - 1] = u[i__ - 1];
+/* L10: */
+	    }
+	} else if (*idist == 2) {
+
+/*           Convert generated numbers to uniform (-1,1) distribution */
+
+	    i__2 = il;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		x[iv + i__ - 1] = u[i__ - 1] * 2. - 1.;
+/* L20: */
+	    }
+	} else if (*idist == 3) {
+
+/*           Convert generated numbers to normal (0,1) distribution */
+
+	    i__2 = il;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		x[iv + i__ - 1] = sqrt(log(u[(i__ << 1) - 2]) * -2.) * cos(u[(
+			i__ << 1) - 1] * 6.2831853071795864769252867663);
+/* L30: */
+	    }
+	}
+/* L40: */
+    }
+    return 0;
+
+/*     End of DLARNV */
+
+} /* igraphdlarnv_ */
+
diff --git a/src/lapack/dlarra.c b/src/lapack/dlarra.c
new file mode 100644
index 0000000..f5a5f56
--- /dev/null
+++ b/src/lapack/dlarra.c
@@ -0,0 +1,146 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarra_(integer *n, doublereal *d__, doublereal *e, 
+	doublereal *e2, doublereal *spltol, doublereal *tnrm, integer *nsplit,
+	 integer *isplit, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal tmp1, eabs;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    Compute the splitting points with threshold SPLTOL.   
+    DLARRA sets any "small" off-diagonal elements to zero.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix. N > 0.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            On entry, the N diagonal elements of the tridiagonal   
+            matrix T.   
+
+    E       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the first (N-1) entries contain the subdiagonal   
+            elements of the tridiagonal matrix T; E(N) need not be set.   
+            On exit, the entries E( ISPLIT( I ) ), 1 <= I <= NSPLIT,   
+            are set to zero, the other entries of E are untouched.   
+
+    E2      (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the first (N-1) entries contain the SQUARES of the   
+            subdiagonal elements of the tridiagonal matrix T;   
+            E2(N) need not be set.   
+            On exit, the entries E2( ISPLIT( I ) ),   
+            1 <= I <= NSPLIT, have been set to zero   
+
+    SPLTOL  (input) DOUBLE PRECISION   
+            The threshold for splitting. Two criteria can be used:   
+            SPLTOL<0 : criterion based on absolute off-diagonal value   
+            SPLTOL>0 : criterion that preserves relative accuracy   
+
+    TNRM    (input) DOUBLE PRECISION   
+            The norm of the matrix.   
+
+    NSPLIT  (output) INTEGER   
+            The number of blocks T splits into. 1 <= NSPLIT <= N.   
+
+    ISPLIT  (output) INTEGER array, dimension (N)   
+            The splitting points, at which T breaks up into blocks.   
+            The first block consists of rows/columns 1 to ISPLIT(1),   
+            the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),   
+            etc., and the NSPLIT-th consists of rows/columns   
+            ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.   
+
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --isplit;
+    --e2;
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+/*     Compute splitting points */
+    *nsplit = 1;
+    if (*spltol < 0.) {
+/*        Criterion based on absolute off-diagonal value */
+	tmp1 = abs(*spltol) * *tnrm;
+	i__1 = *n - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    eabs = (d__1 = e[i__], abs(d__1));
+	    if (eabs <= tmp1) {
+		e[i__] = 0.;
+		e2[i__] = 0.;
+		isplit[*nsplit] = i__;
+		++(*nsplit);
+	    }
+/* L9: */
+	}
+    } else {
+/*        Criterion that guarantees relative accuracy */
+	i__1 = *n - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    eabs = (d__1 = e[i__], abs(d__1));
+	    if (eabs <= *spltol * sqrt((d__1 = d__[i__], abs(d__1))) * sqrt((
+		    d__2 = d__[i__ + 1], abs(d__2)))) {
+		e[i__] = 0.;
+		e2[i__] = 0.;
+		isplit[*nsplit] = i__;
+		++(*nsplit);
+	    }
+/* L10: */
+	}
+    }
+    isplit[*nsplit] = *n;
+    return 0;
+
+/*     End of DLARRA */
+
+} /* igraphdlarra_ */
+
diff --git a/src/lapack/dlarrb.c b/src/lapack/dlarrb.c
new file mode 100644
index 0000000..fb78bdf
--- /dev/null
+++ b/src/lapack/dlarrb.c
@@ -0,0 +1,338 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarrb_(integer *n, doublereal *d__, doublereal *lld, 
+	integer *ifirst, integer *ilast, doublereal *rtol1, doublereal *rtol2,
+	 integer *offset, doublereal *w, doublereal *wgap, doublereal *werr, 
+	doublereal *work, integer *iwork, doublereal *pivmin, doublereal *
+	spdiam, integer *twist, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double log(doublereal);
+
+    /* Local variables */
+    integer i__, k, r__, i1, ii, ip;
+    doublereal gap, mid, tmp, back, lgap, rgap, left;
+    integer iter, nint, prev, next;
+    doublereal cvrgd, right, width;
+    extern integer igraphdlaneg_(integer *, doublereal *, doublereal *, doublereal *
+	    , doublereal *, integer *);
+    integer negcnt;
+    doublereal mnwdth;
+    integer olnint, maxitr;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    Given the relatively robust representation(RRR) L D L^T, DLARRB   
+    does "limited" bisection to refine the eigenvalues of L D L^T,   
+    W( IFIRST-OFFSET ) through W( ILAST-OFFSET ), to more accuracy. Initial   
+    guesses for these eigenvalues are input in W, the corresponding estimate   
+    of the error in these guesses and their gaps are input in WERR   
+    and WGAP, respectively. During bisection, intervals   
+    [left, right] are maintained by storing their mid-points and   
+    semi-widths in the arrays W and WERR respectively.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The N diagonal elements of the diagonal matrix D.   
+
+    LLD     (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (N-1) elements L(i)*L(i)*D(i).   
+
+    IFIRST  (input) INTEGER   
+            The index of the first eigenvalue to be computed.   
+
+    ILAST   (input) INTEGER   
+            The index of the last eigenvalue to be computed.   
+
+    RTOL1   (input) DOUBLE PRECISION   
+    RTOL2   (input) DOUBLE PRECISION   
+            Tolerance for the convergence of the bisection intervals.   
+            An interval [LEFT,RIGHT] has converged if   
+            RIGHT-LEFT.LT.MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) )   
+            where GAP is the (estimated) distance to the nearest   
+            eigenvalue.   
+
+    OFFSET  (input) INTEGER   
+            Offset for the arrays W, WGAP and WERR, i.e., the IFIRST-OFFSET   
+            through ILAST-OFFSET elements of these arrays are to be used.   
+
+    W       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On input, W( IFIRST-OFFSET ) through W( ILAST-OFFSET ) are   
+            estimates of the eigenvalues of L D L^T indexed IFIRST throug   
+            ILAST.   
+            On output, these estimates are refined.   
+
+    WGAP    (input/output) DOUBLE PRECISION array, dimension (N-1)   
+            On input, the (estimated) gaps between consecutive   
+            eigenvalues of L D L^T, i.e., WGAP(I-OFFSET) is the gap between   
+            eigenvalues I and I+1. Note that if IFIRST.EQ.ILAST   
+            then WGAP(IFIRST-OFFSET) must be set to ZERO.   
+            On output, these gaps are refined.   
+
+    WERR    (input/output) DOUBLE PRECISION array, dimension (N)   
+            On input, WERR( IFIRST-OFFSET ) through WERR( ILAST-OFFSET ) are   
+            the errors in the estimates of the corresponding elements in W.   
+            On output, these errors are refined.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (2*N)   
+            Workspace.   
+
+    IWORK   (workspace) INTEGER array, dimension (2*N)   
+            Workspace.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot in the Sturm sequence.   
+
+    SPDIAM  (input) DOUBLE PRECISION   
+            The spectral diameter of the matrix.   
+
+    TWIST   (input) INTEGER   
+            The twist index for the twisted factorization that is used   
+            for the negcount.   
+            TWIST = N: Compute negcount from L D L^T - LAMBDA I = L+ D+ L+^T   
+            TWIST = 1: Compute negcount from L D L^T - LAMBDA I = U- D- U-^T   
+            TWIST = R: Compute negcount from L D L^T - LAMBDA I = N(r) D(r) N(r)   
+
+    INFO    (output) INTEGER   
+            Error flag.   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+
+       Parameter adjustments */
+    --iwork;
+    --work;
+    --werr;
+    --wgap;
+    --w;
+    --lld;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+
+    maxitr = (integer) ((log(*spdiam + *pivmin) - log(*pivmin)) / log(2.)) + 
+	    2;
+    mnwdth = *pivmin * 2.;
+
+    r__ = *twist;
+    if (r__ < 1 || r__ > *n) {
+	r__ = *n;
+    }
+
+/*     Initialize unconverged intervals in [ WORK(2*I-1), WORK(2*I) ].   
+       The Sturm Count, Count( WORK(2*I-1) ) is arranged to be I-1, while   
+       Count( WORK(2*I) ) is stored in IWORK( 2*I ). The integer IWORK( 2*I-1 )   
+       for an unconverged interval is set to the index of the next unconverged   
+       interval, and is -1 or 0 for a converged interval. Thus a linked   
+       list of unconverged intervals is set up. */
+
+    i1 = *ifirst;
+/*     The number of unconverged intervals */
+    nint = 0;
+/*     The last unconverged interval found */
+    prev = 0;
+    rgap = wgap[i1 - *offset];
+    i__1 = *ilast;
+    for (i__ = i1; i__ <= i__1; ++i__) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+	left = w[ii] - werr[ii];
+	right = w[ii] + werr[ii];
+	lgap = rgap;
+	rgap = wgap[ii];
+	gap = min(lgap,rgap);
+/*        Make sure that [LEFT,RIGHT] contains the desired eigenvalue   
+          Compute negcount from dstqds facto L+D+L+^T = L D L^T - LEFT   
+
+          Do while( NEGCNT(LEFT).GT.I-1 ) */
+
+	back = werr[ii];
+L20:
+	negcnt = igraphdlaneg_(n, &d__[1], &lld[1], &left, pivmin, &r__);
+	if (negcnt > i__ - 1) {
+	    left -= back;
+	    back *= 2.;
+	    goto L20;
+	}
+
+/*        Do while( NEGCNT(RIGHT).LT.I )   
+          Compute negcount from dstqds facto L+D+L+^T = L D L^T - RIGHT */
+
+	back = werr[ii];
+L50:
+	negcnt = igraphdlaneg_(n, &d__[1], &lld[1], &right, pivmin, &r__);
+	if (negcnt < i__) {
+	    right += back;
+	    back *= 2.;
+	    goto L50;
+	}
+	width = (d__1 = left - right, abs(d__1)) * .5;
+/* Computing MAX */
+	d__1 = abs(left), d__2 = abs(right);
+	tmp = max(d__1,d__2);
+/* Computing MAX */
+	d__1 = *rtol1 * gap, d__2 = *rtol2 * tmp;
+	cvrgd = max(d__1,d__2);
+	if (width <= cvrgd || width <= mnwdth) {
+/*           This interval has already converged and does not need refinement.   
+             (Note that the gaps might change through refining the   
+              eigenvalues, however, they can only get bigger.)   
+             Remove it from the list. */
+	    iwork[k - 1] = -1;
+/*           Make sure that I1 always points to the first unconverged interval */
+	    if (i__ == i1 && i__ < *ilast) {
+		i1 = i__ + 1;
+	    }
+	    if (prev >= i1 && i__ <= *ilast) {
+		iwork[(prev << 1) - 1] = i__ + 1;
+	    }
+	} else {
+/*           unconverged interval found */
+	    prev = i__;
+	    ++nint;
+	    iwork[k - 1] = i__ + 1;
+	    iwork[k] = negcnt;
+	}
+	work[k - 1] = left;
+	work[k] = right;
+/* L75: */
+    }
+
+/*     Do while( NINT.GT.0 ), i.e. there are still unconverged intervals   
+       and while (ITER.LT.MAXITR) */
+
+    iter = 0;
+L80:
+    prev = i1 - 1;
+    i__ = i1;
+    olnint = nint;
+    i__1 = olnint;
+    for (ip = 1; ip <= i__1; ++ip) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+	rgap = wgap[ii];
+	lgap = rgap;
+	if (ii > 1) {
+	    lgap = wgap[ii - 1];
+	}
+	gap = min(lgap,rgap);
+	next = iwork[k - 1];
+	left = work[k - 1];
+	right = work[k];
+	mid = (left + right) * .5;
+/*        semiwidth of interval */
+	width = right - mid;
+/* Computing MAX */
+	d__1 = abs(left), d__2 = abs(right);
+	tmp = max(d__1,d__2);
+/* Computing MAX */
+	d__1 = *rtol1 * gap, d__2 = *rtol2 * tmp;
+	cvrgd = max(d__1,d__2);
+	if (width <= cvrgd || width <= mnwdth || iter == maxitr) {
+/*           reduce number of unconverged intervals */
+	    --nint;
+/*           Mark interval as converged. */
+	    iwork[k - 1] = 0;
+	    if (i1 == i__) {
+		i1 = next;
+	    } else {
+/*              Prev holds the last unconverged interval previously examined */
+		if (prev >= i1) {
+		    iwork[(prev << 1) - 1] = next;
+		}
+	    }
+	    i__ = next;
+	    goto L100;
+	}
+	prev = i__;
+
+/*        Perform one bisection step */
+
+	negcnt = igraphdlaneg_(n, &d__[1], &lld[1], &mid, pivmin, &r__);
+	if (negcnt <= i__ - 1) {
+	    work[k - 1] = mid;
+	} else {
+	    work[k] = mid;
+	}
+	i__ = next;
+L100:
+	;
+    }
+    ++iter;
+/*     do another loop if there are still unconverged intervals   
+       However, in the last iteration, all intervals are accepted   
+       since this is the best we can do. */
+    if (nint > 0 && iter <= maxitr) {
+	goto L80;
+    }
+
+
+/*     At this point, all the intervals have converged */
+    i__1 = *ilast;
+    for (i__ = *ifirst; i__ <= i__1; ++i__) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+/*        All intervals marked by '0' have been refined. */
+	if (iwork[k - 1] == 0) {
+	    w[ii] = (work[k - 1] + work[k]) * .5;
+	    werr[ii] = work[k] - w[ii];
+	}
+/* L110: */
+    }
+
+    i__1 = *ilast;
+    for (i__ = *ifirst + 1; i__ <= i__1; ++i__) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+/* Computing MAX */
+	d__1 = 0., d__2 = w[ii] - werr[ii] - w[ii - 1] - werr[ii - 1];
+	wgap[ii - 1] = max(d__1,d__2);
+/* L111: */
+    }
+    return 0;
+
+/*     End of DLARRB */
+
+} /* igraphdlarrb_ */
+
diff --git a/src/lapack/dlarrc.c b/src/lapack/dlarrc.c
new file mode 100644
index 0000000..40681d1
--- /dev/null
+++ b/src/lapack/dlarrc.c
@@ -0,0 +1,173 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarrc_(char *jobt, integer *n, doublereal *vl, 
+	doublereal *vu, doublereal *d__, doublereal *e, doublereal *pivmin, 
+	integer *eigcnt, integer *lcnt, integer *rcnt, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__;
+    doublereal sl, su, tmp, tmp2;
+    logical matt;
+    extern logical igraphlsame_(char *, char *);
+    doublereal lpivot, rpivot;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    Find the number of eigenvalues of the symmetric tridiagonal matrix T   
+    that are in the interval (VL,VU] if JOBT = 'T', and of L D L^T   
+    if JOBT = 'L'.   
+
+    Arguments   
+    =========   
+
+    JOBT    (input) CHARACTER*1   
+            = 'T':  Compute Sturm count for matrix T.   
+            = 'L':  Compute Sturm count for matrix L D L^T.   
+
+    N       (input) INTEGER   
+            The order of the matrix. N > 0.   
+
+    VL      (input) DOUBLE PRECISION   
+    VU      (input) DOUBLE PRECISION   
+            The lower and upper bounds for the eigenvalues.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            JOBT = 'T': The N diagonal elements of the tridiagonal matrix T.   
+            JOBT = 'L': The N diagonal elements of the diagonal matrix D.   
+
+    E       (input) DOUBLE PRECISION array, dimension (N)   
+            JOBT = 'T': The N-1 offdiagonal elements of the matrix T.   
+            JOBT = 'L': The N-1 offdiagonal elements of the matrix L.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot in the Sturm sequence for T.   
+
+    EIGCNT  (output) INTEGER   
+            The number of eigenvalues of the symmetric tridiagonal matrix T   
+            that are in the interval (VL,VU]   
+
+    LCNT    (output) INTEGER   
+    RCNT    (output) INTEGER   
+            The left and right negcounts of the interval.   
+
+    INFO    (output) INTEGER   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+    *lcnt = 0;
+    *rcnt = 0;
+    *eigcnt = 0;
+    matt = igraphlsame_(jobt, "T");
+    if (matt) {
+/*        Sturm sequence count on T */
+	lpivot = d__[1] - *vl;
+	rpivot = d__[1] - *vu;
+	if (lpivot <= 0.) {
+	    ++(*lcnt);
+	}
+	if (rpivot <= 0.) {
+	    ++(*rcnt);
+	}
+	i__1 = *n - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing 2nd power */
+	    d__1 = e[i__];
+	    tmp = d__1 * d__1;
+	    lpivot = d__[i__ + 1] - *vl - tmp / lpivot;
+	    rpivot = d__[i__ + 1] - *vu - tmp / rpivot;
+	    if (lpivot <= 0.) {
+		++(*lcnt);
+	    }
+	    if (rpivot <= 0.) {
+		++(*rcnt);
+	    }
+/* L10: */
+	}
+    } else {
+/*        Sturm sequence count on L D L^T */
+	sl = -(*vl);
+	su = -(*vu);
+	i__1 = *n - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    lpivot = d__[i__] + sl;
+	    rpivot = d__[i__] + su;
+	    if (lpivot <= 0.) {
+		++(*lcnt);
+	    }
+	    if (rpivot <= 0.) {
+		++(*rcnt);
+	    }
+	    tmp = e[i__] * d__[i__] * e[i__];
+
+	    tmp2 = tmp / lpivot;
+	    if (tmp2 == 0.) {
+		sl = tmp - *vl;
+	    } else {
+		sl = sl * tmp2 - *vl;
+	    }
+
+	    tmp2 = tmp / rpivot;
+	    if (tmp2 == 0.) {
+		su = tmp - *vu;
+	    } else {
+		su = su * tmp2 - *vu;
+	    }
+/* L20: */
+	}
+	lpivot = d__[*n] + sl;
+	rpivot = d__[*n] + su;
+	if (lpivot <= 0.) {
+	    ++(*lcnt);
+	}
+	if (rpivot <= 0.) {
+	    ++(*rcnt);
+	}
+    }
+    *eigcnt = *rcnt - *lcnt;
+    return 0;
+
+/*     end of DLARRC */
+
+} /* igraphdlarrc_ */
+
diff --git a/src/lapack/dlarrd.c b/src/lapack/dlarrd.c
new file mode 100644
index 0000000..554bc22
--- /dev/null
+++ b/src/lapack/dlarrd.c
@@ -0,0 +1,777 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__3 = 3;
+static integer c__2 = 2;
+static integer c__0 = 0;
+
+/* Subroutine */ int igraphdlarrd_(char *range, char *order, integer *n, doublereal 
+	*vl, doublereal *vu, integer *il, integer *iu, doublereal *gers, 
+	doublereal *reltol, doublereal *d__, doublereal *e, doublereal *e2, 
+	doublereal *pivmin, integer *nsplit, integer *isplit, integer *m, 
+	doublereal *w, doublereal *werr, doublereal *wl, doublereal *wu, 
+	integer *iblock, integer *indexw, doublereal *work, integer *iwork, 
+	integer *info)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double log(doublereal);
+
+    /* Local variables */
+    integer i__, j, ib, ie, je, nb;
+    doublereal gl;
+    integer im, in;
+    doublereal gu;
+    integer iw, jee;
+    doublereal eps;
+    integer nwl;
+    doublereal wlu, wul;
+    integer nwu;
+    doublereal tmp1, tmp2;
+    integer iend, jblk, ioff, iout, itmp1, itmp2, jdisc;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo;
+    doublereal atoli;
+    integer iwoff, itmax;
+    doublereal wkill, rtoli, uflow, tnorm;
+    extern doublereal igraphdlamch_(char *);
+    integer ibegin;
+    extern /* Subroutine */ int igraphdlaebz_(integer *, integer *, integer *, 
+	    integer *, integer *, integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, integer *,
+	     doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *);
+    integer irange, idiscl, idumma[1];
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    integer idiscu;
+    logical ncnvrg, toofew;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.0)                        --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2010   
+
+
+    Purpose   
+    =======   
+
+    DLARRD computes the eigenvalues of a symmetric tridiagonal   
+    matrix T to suitable accuracy. This is an auxiliary code to be   
+    called from DSTEMR.   
+    The user may ask for all eigenvalues, all eigenvalues   
+    in the half-open interval (VL, VU], or the IL-th through IU-th   
+    eigenvalues.   
+
+    To avoid overflow, the matrix must be scaled so that its   
+    largest element is no greater than overflow**(1/2) *   
+    underflow**(1/4) in absolute value, and for greatest   
+    accuracy, it should not be much smaller than that.   
+
+    See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal   
+    Matrix", Report CS41, Computer Science Dept., Stanford   
+    University, July 21, 1966.   
+
+    Arguments   
+    =========   
+
+    RANGE   (input) CHARACTER*1   
+            = 'A': ("All")   all eigenvalues will be found.   
+            = 'V': ("Value") all eigenvalues in the half-open interval   
+                             (VL, VU] will be found.   
+            = 'I': ("Index") the IL-th through IU-th eigenvalues (of the   
+                             entire matrix) will be found.   
+
+    ORDER   (input) CHARACTER*1   
+            = 'B': ("By Block") the eigenvalues will be grouped by   
+                                split-off block (see IBLOCK, ISPLIT) and   
+                                ordered from smallest to largest within   
+                                the block.   
+            = 'E': ("Entire matrix")   
+                                the eigenvalues for the entire matrix   
+                                will be ordered from smallest to   
+                                largest.   
+
+    N       (input) INTEGER   
+            The order of the tridiagonal matrix T.  N >= 0.   
+
+    VL      (input) DOUBLE PRECISION   
+    VU      (input) DOUBLE PRECISION   
+            If RANGE='V', the lower and upper bounds of the interval to   
+            be searched for eigenvalues.  Eigenvalues less than or equal   
+            to VL, or greater than VU, will not be returned.  VL < VU.   
+            Not referenced if RANGE = 'A' or 'I'.   
+
+    IL      (input) INTEGER   
+    IU      (input) INTEGER   
+            If RANGE='I', the indices (in ascending order) of the   
+            smallest and largest eigenvalues to be returned.   
+            1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.   
+            Not referenced if RANGE = 'A' or 'V'.   
+
+    GERS    (input) DOUBLE PRECISION array, dimension (2*N)   
+            The N Gerschgorin intervals (the i-th Gerschgorin interval   
+            is (GERS(2*i-1), GERS(2*i)).   
+
+    RELTOL  (input) DOUBLE PRECISION   
+            The minimum relative width of an interval.  When an interval   
+            is narrower than RELTOL times the larger (in   
+            magnitude) endpoint, then it is considered to be   
+            sufficiently small, i.e., converged.  Note: this should   
+            always be at least radix*machine epsilon.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The n diagonal elements of the tridiagonal matrix T.   
+
+    E       (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (n-1) off-diagonal elements of the tridiagonal matrix T.   
+
+    E2      (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (n-1) squared off-diagonal elements of the tridiagonal matrix T.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot allowed in the Sturm sequence for T.   
+
+    NSPLIT  (input) INTEGER   
+            The number of diagonal blocks in the matrix T.   
+            1 <= NSPLIT <= N.   
+
+    ISPLIT  (input) INTEGER array, dimension (N)   
+            The splitting points, at which T breaks up into submatrices.   
+            The first submatrix consists of rows/columns 1 to ISPLIT(1),   
+            the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),   
+            etc., and the NSPLIT-th consists of rows/columns   
+            ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.   
+            (Only the first NSPLIT elements will actually be used, but   
+            since the user cannot know a priori what value NSPLIT will   
+            have, N words must be reserved for ISPLIT.)   
+
+    M       (output) INTEGER   
+            The actual number of eigenvalues found. 0 <= M <= N.   
+            (See also the description of INFO=2,3.)   
+
+    W       (output) DOUBLE PRECISION array, dimension (N)   
+            On exit, the first M elements of W will contain the   
+            eigenvalue approximations. DLARRD computes an interval   
+            I_j = (a_j, b_j] that includes eigenvalue j. The eigenvalue   
+            approximation is given as the interval midpoint   
+            W(j)= ( a_j + b_j)/2. The corresponding error is bounded by   
+            WERR(j) = abs( a_j - b_j)/2   
+
+    WERR    (output) DOUBLE PRECISION array, dimension (N)   
+            The error bound on the corresponding eigenvalue approximation   
+            in W.   
+
+    WL      (output) DOUBLE PRECISION   
+    WU      (output) DOUBLE PRECISION   
+            The interval (WL, WU] contains all the wanted eigenvalues.   
+            If RANGE='V', then WL=VL and WU=VU.   
+            If RANGE='A', then WL and WU are the global Gerschgorin bounds   
+                          on the spectrum.   
+            If RANGE='I', then WL and WU are computed by DLAEBZ from the   
+                          index range specified.   
+
+    IBLOCK  (output) INTEGER array, dimension (N)   
+            At each row/column j where E(j) is zero or small, the   
+            matrix T is considered to split into a block diagonal   
+            matrix.  On exit, if INFO = 0, IBLOCK(i) specifies to which   
+            block (from 1 to the number of blocks) the eigenvalue W(i)   
+            belongs.  (DLARRD may use the remaining N-M elements as   
+            workspace.)   
+
+    INDEXW  (output) INTEGER array, dimension (N)   
+            The indices of the eigenvalues within each block (submatrix);   
+            for example, INDEXW(i)= j and IBLOCK(i)=k imply that the   
+            i-th eigenvalue W(i) is the j-th eigenvalue in block k.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (4*N)   
+
+    IWORK   (workspace) INTEGER array, dimension (3*N)   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  some or all of the eigenvalues failed to converge or   
+                  were not computed:   
+                  =1 or 3: Bisection failed to converge for some   
+                          eigenvalues; these eigenvalues are flagged by a   
+                          negative block number.  The effect is that the   
+                          eigenvalues may not be as accurate as the   
+                          absolute and relative tolerances.  This is   
+                          generally caused by unexpectedly inaccurate   
+                          arithmetic.   
+                  =2 or 3: RANGE='I' only: Not all of the eigenvalues   
+                          IL:IU were found.   
+                          Effect: M < IU+1-IL   
+                          Cause:  non-monotonic arithmetic, causing the   
+                                  Sturm sequence to be non-monotonic.   
+                          Cure:   recalculate, using RANGE='A', and pick   
+                                  out eigenvalues IL:IU.  In some cases,   
+                                  increasing the PARAMETER "FUDGE" may   
+                                  make things work.   
+                  = 4:    RANGE='I', and the Gershgorin interval   
+                          initially used was too small.  No eigenvalues   
+                          were computed.   
+                          Probable cause: your machine has sloppy   
+                                          floating-point arithmetic.   
+                          Cure: Increase the PARAMETER "FUDGE",   
+                                recompile, and try again.   
+
+    Internal Parameters   
+    ===================   
+
+    FUDGE   DOUBLE PRECISION, default = 2   
+            A "fudge factor" to widen the Gershgorin intervals.  Ideally,   
+            a value of 1 should work, but on machines with sloppy   
+            arithmetic, this needs to be larger.  The default for   
+            publicly released versions should be large enough to handle   
+            the worst machine around.  Note that this has no effect   
+            on accuracy of the solution.   
+
+    Based on contributions by   
+       W. Kahan, University of California, Berkeley, USA   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --iwork;
+    --work;
+    --indexw;
+    --iblock;
+    --werr;
+    --w;
+    --isplit;
+    --e2;
+    --e;
+    --d__;
+    --gers;
+
+    /* Function Body */
+    *info = 0;
+
+/*     Decode RANGE */
+
+    if (igraphlsame_(range, "A")) {
+	irange = 1;
+    } else if (igraphlsame_(range, "V")) {
+	irange = 2;
+    } else if (igraphlsame_(range, "I")) {
+	irange = 3;
+    } else {
+	irange = 0;
+    }
+
+/*     Check for Errors */
+
+    if (irange <= 0) {
+	*info = -1;
+    } else if (! (igraphlsame_(order, "B") || igraphlsame_(order, 
+	    "E"))) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -3;
+    } else if (irange == 2) {
+	if (*vl >= *vu) {
+	    *info = -5;
+	}
+    } else if (irange == 3 && (*il < 1 || *il > max(1,*n))) {
+	*info = -6;
+    } else if (irange == 3 && (*iu < min(*n,*il) || *iu > *n)) {
+	*info = -7;
+    }
+
+    if (*info != 0) {
+	return 0;
+    }
+/*     Initialize error flags */
+    *info = 0;
+    ncnvrg = FALSE_;
+    toofew = FALSE_;
+/*     Quick return if possible */
+    *m = 0;
+    if (*n == 0) {
+	return 0;
+    }
+/*     Simplification: */
+    if (irange == 3 && *il == 1 && *iu == *n) {
+	irange = 1;
+    }
+/*     Get machine constants */
+    eps = igraphdlamch_("P");
+    uflow = igraphdlamch_("U");
+/*     Special Case when N=1   
+       Treat case of 1x1 matrix for quick return */
+    if (*n == 1) {
+	if (irange == 1 || irange == 2 && d__[1] > *vl && d__[1] <= *vu || 
+		irange == 3 && *il == 1 && *iu == 1) {
+	    *m = 1;
+	    w[1] = d__[1];
+/*           The computation error of the eigenvalue is zero */
+	    werr[1] = 0.;
+	    iblock[1] = 1;
+	    indexw[1] = 1;
+	}
+	return 0;
+    }
+/*     NB is the minimum vector length for vector bisection, or 0   
+       if only scalar is to be done. */
+    nb = igraphilaenv_(&c__1, "DSTEBZ", " ", n, &c_n1, &c_n1, &c_n1, (ftnlen)6, (
+	    ftnlen)1);
+    if (nb <= 1) {
+	nb = 0;
+    }
+/*     Find global spectral radius */
+    gl = d__[1];
+    gu = d__[1];
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing MIN */
+	d__1 = gl, d__2 = gers[(i__ << 1) - 1];
+	gl = min(d__1,d__2);
+/* Computing MAX */
+	d__1 = gu, d__2 = gers[i__ * 2];
+	gu = max(d__1,d__2);
+/* L5: */
+    }
+/*     Compute global Gerschgorin bounds and spectral diameter   
+   Computing MAX */
+    d__1 = abs(gl), d__2 = abs(gu);
+    tnorm = max(d__1,d__2);
+    gl = gl - tnorm * 2. * eps * *n - *pivmin * 4.;
+    gu = gu + tnorm * 2. * eps * *n + *pivmin * 4.;
+/*     [JAN/28/2009] remove the line below since SPDIAM variable not use   
+       SPDIAM = GU - GL   
+       Input arguments for DLAEBZ:   
+       The relative tolerance.  An interval (a,b] lies within   
+       "relative tolerance" if  b-a < RELTOL*max(|a|,|b|), */
+    rtoli = *reltol;
+/*     Set the absolute tolerance for interval convergence to zero to force   
+       interval convergence based on relative size of the interval.   
+       This is dangerous because intervals might not converge when RELTOL is   
+       small. But at least a very small number should be selected so that for   
+       strongly graded matrices, the code can get relatively accurate   
+       eigenvalues. */
+    atoli = uflow * 4. + *pivmin * 4.;
+    if (irange == 3) {
+/*        RANGE='I': Compute an interval containing eigenvalues   
+          IL through IU. The initial interval [GL,GU] from the global   
+          Gerschgorin bounds GL and GU is refined by DLAEBZ. */
+	itmax = (integer) ((log(tnorm + *pivmin) - log(*pivmin)) / log(2.)) + 
+		2;
+	work[*n + 1] = gl;
+	work[*n + 2] = gl;
+	work[*n + 3] = gu;
+	work[*n + 4] = gu;
+	work[*n + 5] = gl;
+	work[*n + 6] = gu;
+	iwork[1] = -1;
+	iwork[2] = -1;
+	iwork[3] = *n + 1;
+	iwork[4] = *n + 1;
+	iwork[5] = *il - 1;
+	iwork[6] = *iu;
+
+	igraphdlaebz_(&c__3, &itmax, n, &c__2, &c__2, &nb, &atoli, &rtoli, pivmin, &
+		d__[1], &e[1], &e2[1], &iwork[5], &work[*n + 1], &work[*n + 5]
+		, &iout, &iwork[1], &w[1], &iblock[1], &iinfo);
+	if (iinfo != 0) {
+	    *info = iinfo;
+	    return 0;
+	}
+/*        On exit, output intervals may not be ordered by ascending negcount */
+	if (iwork[6] == *iu) {
+	    *wl = work[*n + 1];
+	    wlu = work[*n + 3];
+	    nwl = iwork[1];
+	    *wu = work[*n + 4];
+	    wul = work[*n + 2];
+	    nwu = iwork[4];
+	} else {
+	    *wl = work[*n + 2];
+	    wlu = work[*n + 4];
+	    nwl = iwork[2];
+	    *wu = work[*n + 3];
+	    wul = work[*n + 1];
+	    nwu = iwork[3];
+	}
+/*        On exit, the interval [WL, WLU] contains a value with negcount NWL,   
+          and [WUL, WU] contains a value with negcount NWU. */
+	if (nwl < 0 || nwl >= *n || nwu < 1 || nwu > *n) {
+	    *info = 4;
+	    return 0;
+	}
+    } else if (irange == 2) {
+	*wl = *vl;
+	*wu = *vu;
+    } else if (irange == 1) {
+	*wl = gl;
+	*wu = gu;
+    }
+/*     Find Eigenvalues -- Loop Over blocks and recompute NWL and NWU.   
+       NWL accumulates the number of eigenvalues .le. WL,   
+       NWU accumulates the number of eigenvalues .le. WU */
+    *m = 0;
+    iend = 0;
+    *info = 0;
+    nwl = 0;
+    nwu = 0;
+
+    i__1 = *nsplit;
+    for (jblk = 1; jblk <= i__1; ++jblk) {
+	ioff = iend;
+	ibegin = ioff + 1;
+	iend = isplit[jblk];
+	in = iend - ioff;
+
+	if (in == 1) {
+/*           1x1 block */
+	    if (*wl >= d__[ibegin] - *pivmin) {
+		++nwl;
+	    }
+	    if (*wu >= d__[ibegin] - *pivmin) {
+		++nwu;
+	    }
+	    if (irange == 1 || *wl < d__[ibegin] - *pivmin && *wu >= d__[
+		    ibegin] - *pivmin) {
+		++(*m);
+		w[*m] = d__[ibegin];
+		werr[*m] = 0.;
+/*              The gap for a single block doesn't matter for the later   
+                algorithm and is assigned an arbitrary large value */
+		iblock[*m] = jblk;
+		indexw[*m] = 1;
+	    }
+/*        Disabled 2x2 case because of a failure on the following matrix   
+          RANGE = 'I', IL = IU = 4   
+            Original Tridiagonal, d = [   
+             -0.150102010615740E+00   
+             -0.849897989384260E+00   
+             -0.128208148052635E-15   
+              0.128257718286320E-15   
+            ];   
+            e = [   
+             -0.357171383266986E+00   
+             -0.180411241501588E-15   
+             -0.175152352710251E-15   
+            ];   
+
+           ELSE IF( IN.EQ.2 ) THEN   
+   *           2x2 block   
+              DISC = SQRT( (HALF*(D(IBEGIN)-D(IEND)))**2 + E(IBEGIN)**2 )   
+              TMP1 = HALF*(D(IBEGIN)+D(IEND))   
+              L1 = TMP1 - DISC   
+              IF( WL.GE. L1-PIVMIN )   
+       $         NWL = NWL + 1   
+              IF( WU.GE. L1-PIVMIN )   
+       $         NWU = NWU + 1   
+              IF( IRANGE.EQ.ALLRNG .OR. ( WL.LT.L1-PIVMIN .AND. WU.GE.   
+       $          L1-PIVMIN ) ) THEN   
+                 M = M + 1   
+                 W( M ) = L1   
+   *              The uncertainty of eigenvalues of a 2x2 matrix is very small   
+                 WERR( M ) = EPS * ABS( W( M ) ) * TWO   
+                 IBLOCK( M ) = JBLK   
+                 INDEXW( M ) = 1   
+              ENDIF   
+              L2 = TMP1 + DISC   
+              IF( WL.GE. L2-PIVMIN )   
+       $         NWL = NWL + 1   
+              IF( WU.GE. L2-PIVMIN )   
+       $         NWU = NWU + 1   
+              IF( IRANGE.EQ.ALLRNG .OR. ( WL.LT.L2-PIVMIN .AND. WU.GE.   
+       $          L2-PIVMIN ) ) THEN   
+                 M = M + 1   
+                 W( M ) = L2   
+   *              The uncertainty of eigenvalues of a 2x2 matrix is very small   
+                 WERR( M ) = EPS * ABS( W( M ) ) * TWO   
+                 IBLOCK( M ) = JBLK   
+                 INDEXW( M ) = 2   
+              ENDIF */
+	} else {
+/*           General Case - block of size IN >= 2   
+             Compute local Gerschgorin interval and use it as the initial   
+             interval for DLAEBZ */
+	    gu = d__[ibegin];
+	    gl = d__[ibegin];
+	    tmp1 = 0.;
+	    i__2 = iend;
+	    for (j = ibegin; j <= i__2; ++j) {
+/* Computing MIN */
+		d__1 = gl, d__2 = gers[(j << 1) - 1];
+		gl = min(d__1,d__2);
+/* Computing MAX */
+		d__1 = gu, d__2 = gers[j * 2];
+		gu = max(d__1,d__2);
+/* L40: */
+	    }
+/*           [JAN/28/2009]   
+             change SPDIAM by TNORM in lines 2 and 3 thereafter   
+             line 1: remove computation of SPDIAM (not useful anymore)   
+             SPDIAM = GU - GL   
+             GL = GL - FUDGE*SPDIAM*EPS*IN - FUDGE*PIVMIN   
+             GU = GU + FUDGE*SPDIAM*EPS*IN + FUDGE*PIVMIN */
+	    gl = gl - tnorm * 2. * eps * in - *pivmin * 2.;
+	    gu = gu + tnorm * 2. * eps * in + *pivmin * 2.;
+
+	    if (irange > 1) {
+		if (gu < *wl) {
+/*                 the local block contains none of the wanted eigenvalues */
+		    nwl += in;
+		    nwu += in;
+		    goto L70;
+		}
+/*              refine search interval if possible, only range (WL,WU] matters */
+		gl = max(gl,*wl);
+		gu = min(gu,*wu);
+		if (gl >= gu) {
+		    goto L70;
+		}
+	    }
+/*           Find negcount of initial interval boundaries GL and GU */
+	    work[*n + 1] = gl;
+	    work[*n + in + 1] = gu;
+	    igraphdlaebz_(&c__1, &c__0, &in, &in, &c__1, &nb, &atoli, &rtoli, 
+		    pivmin, &d__[ibegin], &e[ibegin], &e2[ibegin], idumma, &
+		    work[*n + 1], &work[*n + (in << 1) + 1], &im, &iwork[1], &
+		    w[*m + 1], &iblock[*m + 1], &iinfo);
+	    if (iinfo != 0) {
+		*info = iinfo;
+		return 0;
+	    }
+
+	    nwl += iwork[1];
+	    nwu += iwork[in + 1];
+	    iwoff = *m - iwork[1];
+/*           Compute Eigenvalues */
+	    itmax = (integer) ((log(gu - gl + *pivmin) - log(*pivmin)) / log(
+		    2.)) + 2;
+	    igraphdlaebz_(&c__2, &itmax, &in, &in, &c__1, &nb, &atoli, &rtoli, 
+		    pivmin, &d__[ibegin], &e[ibegin], &e2[ibegin], idumma, &
+		    work[*n + 1], &work[*n + (in << 1) + 1], &iout, &iwork[1],
+		     &w[*m + 1], &iblock[*m + 1], &iinfo);
+	    if (iinfo != 0) {
+		*info = iinfo;
+		return 0;
+	    }
+
+/*           Copy eigenvalues into W and IBLOCK   
+             Use -JBLK for block number for unconverged eigenvalues.   
+             Loop over the number of output intervals from DLAEBZ */
+	    i__2 = iout;
+	    for (j = 1; j <= i__2; ++j) {
+/*              eigenvalue approximation is middle point of interval */
+		tmp1 = (work[j + *n] + work[j + in + *n]) * .5;
+/*              semi length of error interval */
+		tmp2 = (d__1 = work[j + *n] - work[j + in + *n], abs(d__1)) * 
+			.5;
+		if (j > iout - iinfo) {
+/*                 Flag non-convergence. */
+		    ncnvrg = TRUE_;
+		    ib = -jblk;
+		} else {
+		    ib = jblk;
+		}
+		i__3 = iwork[j + in] + iwoff;
+		for (je = iwork[j] + 1 + iwoff; je <= i__3; ++je) {
+		    w[je] = tmp1;
+		    werr[je] = tmp2;
+		    indexw[je] = je - iwoff;
+		    iblock[je] = ib;
+/* L50: */
+		}
+/* L60: */
+	    }
+
+	    *m += im;
+	}
+L70:
+	;
+    }
+/*     If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU   
+       If NWL+1 < IL or NWU > IU, discard extra eigenvalues. */
+    if (irange == 3) {
+	idiscl = *il - 1 - nwl;
+	idiscu = nwu - *iu;
+
+	if (idiscl > 0) {
+	    im = 0;
+	    i__1 = *m;
+	    for (je = 1; je <= i__1; ++je) {
+/*              Remove some of the smallest eigenvalues from the left so that   
+                at the end IDISCL =0. Move all eigenvalues up to the left. */
+		if (w[je] <= wlu && idiscl > 0) {
+		    --idiscl;
+		} else {
+		    ++im;
+		    w[im] = w[je];
+		    werr[im] = werr[je];
+		    indexw[im] = indexw[je];
+		    iblock[im] = iblock[je];
+		}
+/* L80: */
+	    }
+	    *m = im;
+	}
+	if (idiscu > 0) {
+/*           Remove some of the largest eigenvalues from the right so that   
+             at the end IDISCU =0. Move all eigenvalues up to the left. */
+	    im = *m + 1;
+	    for (je = *m; je >= 1; --je) {
+		if (w[je] >= wul && idiscu > 0) {
+		    --idiscu;
+		} else {
+		    --im;
+		    w[im] = w[je];
+		    werr[im] = werr[je];
+		    indexw[im] = indexw[je];
+		    iblock[im] = iblock[je];
+		}
+/* L81: */
+	    }
+	    jee = 0;
+	    i__1 = *m;
+	    for (je = im; je <= i__1; ++je) {
+		++jee;
+		w[jee] = w[je];
+		werr[jee] = werr[je];
+		indexw[jee] = indexw[je];
+		iblock[jee] = iblock[je];
+/* L82: */
+	    }
+	    *m = *m - im + 1;
+	}
+	if (idiscl > 0 || idiscu > 0) {
+/*           Code to deal with effects of bad arithmetic. (If N(w) is   
+             monotone non-decreasing, this should never happen.)   
+             Some low eigenvalues to be discarded are not in (WL,WLU],   
+             or high eigenvalues to be discarded are not in (WUL,WU]   
+             so just kill off the smallest IDISCL/largest IDISCU   
+             eigenvalues, by marking the corresponding IBLOCK = 0 */
+	    if (idiscl > 0) {
+		wkill = *wu;
+		i__1 = idiscl;
+		for (jdisc = 1; jdisc <= i__1; ++jdisc) {
+		    iw = 0;
+		    i__2 = *m;
+		    for (je = 1; je <= i__2; ++je) {
+			if (iblock[je] != 0 && (w[je] < wkill || iw == 0)) {
+			    iw = je;
+			    wkill = w[je];
+			}
+/* L90: */
+		    }
+		    iblock[iw] = 0;
+/* L100: */
+		}
+	    }
+	    if (idiscu > 0) {
+		wkill = *wl;
+		i__1 = idiscu;
+		for (jdisc = 1; jdisc <= i__1; ++jdisc) {
+		    iw = 0;
+		    i__2 = *m;
+		    for (je = 1; je <= i__2; ++je) {
+			if (iblock[je] != 0 && (w[je] >= wkill || iw == 0)) {
+			    iw = je;
+			    wkill = w[je];
+			}
+/* L110: */
+		    }
+		    iblock[iw] = 0;
+/* L120: */
+		}
+	    }
+/*           Now erase all eigenvalues with IBLOCK set to zero */
+	    im = 0;
+	    i__1 = *m;
+	    for (je = 1; je <= i__1; ++je) {
+		if (iblock[je] != 0) {
+		    ++im;
+		    w[im] = w[je];
+		    werr[im] = werr[je];
+		    indexw[im] = indexw[je];
+		    iblock[im] = iblock[je];
+		}
+/* L130: */
+	    }
+	    *m = im;
+	}
+	if (idiscl < 0 || idiscu < 0) {
+	    toofew = TRUE_;
+	}
+    }
+
+    if (irange == 1 && *m != *n || irange == 3 && *m != *iu - *il + 1) {
+	toofew = TRUE_;
+    }
+/*     If ORDER='B', do nothing the eigenvalues are already sorted by   
+          block.   
+       If ORDER='E', sort the eigenvalues from smallest to largest */
+    if (igraphlsame_(order, "E") && *nsplit > 1) {
+	i__1 = *m - 1;
+	for (je = 1; je <= i__1; ++je) {
+	    ie = 0;
+	    tmp1 = w[je];
+	    i__2 = *m;
+	    for (j = je + 1; j <= i__2; ++j) {
+		if (w[j] < tmp1) {
+		    ie = j;
+		    tmp1 = w[j];
+		}
+/* L140: */
+	    }
+	    if (ie != 0) {
+		tmp2 = werr[ie];
+		itmp1 = iblock[ie];
+		itmp2 = indexw[ie];
+		w[ie] = w[je];
+		werr[ie] = werr[je];
+		iblock[ie] = iblock[je];
+		indexw[ie] = indexw[je];
+		w[je] = tmp1;
+		werr[je] = tmp2;
+		iblock[je] = itmp1;
+		indexw[je] = itmp2;
+	    }
+/* L150: */
+	}
+    }
+
+    *info = 0;
+    if (ncnvrg) {
+	++(*info);
+    }
+    if (toofew) {
+	*info += 2;
+    }
+    return 0;
+
+/*     End of DLARRD */
+
+} /* igraphdlarrd_ */
+
diff --git a/src/lapack/dlarre.c b/src/lapack/dlarre.c
new file mode 100644
index 0000000..3474b51
--- /dev/null
+++ b/src/lapack/dlarre.c
@@ -0,0 +1,848 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdlarre_(char *range, integer *n, doublereal *vl, 
+	doublereal *vu, integer *il, integer *iu, doublereal *d__, doublereal 
+	*e, doublereal *e2, doublereal *rtol1, doublereal *rtol2, doublereal *
+	spltol, integer *nsplit, integer *isplit, integer *m, doublereal *w, 
+	doublereal *werr, doublereal *wgap, integer *iblock, integer *indexw, 
+	doublereal *gers, doublereal *pivmin, doublereal *work, integer *
+	iwork, integer *info)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal), log(doublereal);
+
+    /* Local variables */
+    integer i__, j;
+    doublereal s1, s2;
+    integer mb;
+    doublereal gl;
+    integer in, mm;
+    doublereal gu;
+    integer cnt;
+    doublereal eps, tau, tmp, rtl;
+    integer cnt1, cnt2;
+    doublereal tmp1, eabs;
+    integer iend, jblk;
+    doublereal eold;
+    integer indl;
+    doublereal dmax__, emax;
+    integer wend, idum, indu;
+    doublereal rtol;
+    integer iseed[4];
+    doublereal avgap, sigma;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    logical norep;
+    extern /* Subroutine */ int igraphdlasq2_(integer *, doublereal *, integer *);
+    extern doublereal igraphdlamch_(char *);
+    integer ibegin;
+    logical forceb;
+    integer irange;
+    doublereal sgndef;
+    extern /* Subroutine */ int igraphdlarra_(integer *, doublereal *, doublereal *,
+	     doublereal *, doublereal *, doublereal *, integer *, integer *, 
+	    integer *), igraphdlarrb_(integer *, doublereal *, doublereal *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, integer *,
+	     doublereal *, doublereal *, integer *, integer *), igraphdlarrc_(char *
+	    , integer *, doublereal *, doublereal *, doublereal *, doublereal 
+	    *, doublereal *, integer *, integer *, integer *, integer *);
+    integer wbegin;
+    extern /* Subroutine */ int igraphdlarrd_(char *, char *, integer *, doublereal 
+	    *, doublereal *, integer *, integer *, doublereal *, doublereal *,
+	     doublereal *, doublereal *, doublereal *, doublereal *, integer *
+	    , integer *, integer *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *);
+    doublereal safmin, spdiam;
+    extern /* Subroutine */ int igraphdlarrk_(integer *, integer *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, integer *);
+    logical usedqd;
+    doublereal clwdth, isleft;
+    extern /* Subroutine */ int igraphdlarnv_(integer *, integer *, integer *, 
+	    doublereal *);
+    doublereal isrght, bsrtol, dpivot;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    To find the desired eigenvalues of a given real symmetric   
+    tridiagonal matrix T, DLARRE sets any "small" off-diagonal   
+    elements to zero, and for each unreduced block T_i, it finds   
+    (a) a suitable shift at one end of the block's spectrum,   
+    (b) the base representation, T_i - sigma_i I = L_i D_i L_i^T, and   
+    (c) eigenvalues of each L_i D_i L_i^T.   
+    The representations and eigenvalues found are then used by   
+    DSTEMR to compute the eigenvectors of T.   
+    The accuracy varies depending on whether bisection is used to   
+    find a few eigenvalues or the dqds algorithm (subroutine DLASQ2) to   
+    conpute all and then discard any unwanted one.   
+    As an added benefit, DLARRE also outputs the n   
+    Gerschgorin intervals for the matrices L_i D_i L_i^T.   
+
+    Arguments   
+    =========   
+
+    RANGE   (input) CHARACTER*1   
+            = 'A': ("All")   all eigenvalues will be found.   
+            = 'V': ("Value") all eigenvalues in the half-open interval   
+                             (VL, VU] will be found.   
+            = 'I': ("Index") the IL-th through IU-th eigenvalues (of the   
+                             entire matrix) will be found.   
+
+    N       (input) INTEGER   
+            The order of the matrix. N > 0.   
+
+    VL      (input/output) DOUBLE PRECISION   
+    VU      (input/output) DOUBLE PRECISION   
+            If RANGE='V', the lower and upper bounds for the eigenvalues.   
+            Eigenvalues less than or equal to VL, or greater than VU,   
+            will not be returned.  VL < VU.   
+            If RANGE='I' or ='A', DLARRE computes bounds on the desired   
+            part of the spectrum.   
+
+    IL      (input) INTEGER   
+    IU      (input) INTEGER   
+            If RANGE='I', the indices (in ascending order) of the   
+            smallest and largest eigenvalues to be returned.   
+            1 <= IL <= IU <= N.   
+
+    D       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the N diagonal elements of the tridiagonal   
+            matrix T.   
+            On exit, the N diagonal elements of the diagonal   
+            matrices D_i.   
+
+    E       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the first (N-1) entries contain the subdiagonal   
+            elements of the tridiagonal matrix T; E(N) need not be set.   
+            On exit, E contains the subdiagonal elements of the unit   
+            bidiagonal matrices L_i. The entries E( ISPLIT( I ) ),   
+            1 <= I <= NSPLIT, contain the base points sigma_i on output.   
+
+    E2      (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the first (N-1) entries contain the SQUARES of the   
+            subdiagonal elements of the tridiagonal matrix T;   
+            E2(N) need not be set.   
+            On exit, the entries E2( ISPLIT( I ) ),   
+            1 <= I <= NSPLIT, have been set to zero   
+
+    RTOL1   (input) DOUBLE PRECISION   
+    RTOL2   (input) DOUBLE PRECISION   
+             Parameters for bisection.   
+             An interval [LEFT,RIGHT] has converged if   
+             RIGHT-LEFT.LT.MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) )   
+
+    SPLTOL  (input) DOUBLE PRECISION   
+            The threshold for splitting.   
+
+    NSPLIT  (output) INTEGER   
+            The number of blocks T splits into. 1 <= NSPLIT <= N.   
+
+    ISPLIT  (output) INTEGER array, dimension (N)   
+            The splitting points, at which T breaks up into blocks.   
+            The first block consists of rows/columns 1 to ISPLIT(1),   
+            the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),   
+            etc., and the NSPLIT-th consists of rows/columns   
+            ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.   
+
+    M       (output) INTEGER   
+            The total number of eigenvalues (of all L_i D_i L_i^T)   
+            found.   
+
+    W       (output) DOUBLE PRECISION array, dimension (N)   
+            The first M elements contain the eigenvalues. The   
+            eigenvalues of each of the blocks, L_i D_i L_i^T, are   
+            sorted in ascending order ( DLARRE may use the   
+            remaining N-M elements as workspace).   
+
+    WERR    (output) DOUBLE PRECISION array, dimension (N)   
+            The error bound on the corresponding eigenvalue in W.   
+
+    WGAP    (output) DOUBLE PRECISION array, dimension (N)   
+            The separation from the right neighbor eigenvalue in W.   
+            The gap is only with respect to the eigenvalues of the same block   
+            as each block has its own representation tree.   
+            Exception: at the right end of a block we store the left gap   
+
+    IBLOCK  (output) INTEGER array, dimension (N)   
+            The indices of the blocks (submatrices) associated with the   
+            corresponding eigenvalues in W; IBLOCK(i)=1 if eigenvalue   
+            W(i) belongs to the first block from the top, =2 if W(i)   
+            belongs to the second block, etc.   
+
+    INDEXW  (output) INTEGER array, dimension (N)   
+            The indices of the eigenvalues within each block (submatrix);   
+            for example, INDEXW(i)= 10 and IBLOCK(i)=2 imply that the   
+            i-th eigenvalue W(i) is the 10-th eigenvalue in block 2   
+
+    GERS    (output) DOUBLE PRECISION array, dimension (2*N)   
+            The N Gerschgorin intervals (the i-th Gerschgorin interval   
+            is (GERS(2*i-1), GERS(2*i)).   
+
+    PIVMIN  (output) DOUBLE PRECISION   
+            The minimum pivot in the Sturm sequence for T.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (6*N)   
+            Workspace.   
+
+    IWORK   (workspace) INTEGER array, dimension (5*N)   
+            Workspace.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            > 0:  A problem occured in DLARRE.   
+            < 0:  One of the called subroutines signaled an internal problem.   
+                  Needs inspection of the corresponding parameter IINFO   
+                  for further information.   
+
+            =-1:  Problem in DLARRD.   
+            = 2:  No base representation could be found in MAXTRY iterations.   
+                  Increasing MAXTRY and recompilation might be a remedy.   
+            =-3:  Problem in DLARRB when computing the refined root   
+                  representation for DLASQ2.   
+            =-4:  Problem in DLARRB when preforming bisection on the   
+                  desired part of the spectrum.   
+            =-5:  Problem in DLASQ2.   
+            =-6:  Problem in DLASQ2.   
+
+    Further Details   
+    The base representations are required to suffer very little   
+    element growth and consequently define all their eigenvalues to   
+    high relative accuracy.   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --iwork;
+    --work;
+    --gers;
+    --indexw;
+    --iblock;
+    --wgap;
+    --werr;
+    --w;
+    --isplit;
+    --e2;
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+
+/*     Decode RANGE */
+
+    if (igraphlsame_(range, "A")) {
+	irange = 1;
+    } else if (igraphlsame_(range, "V")) {
+	irange = 3;
+    } else if (igraphlsame_(range, "I")) {
+	irange = 2;
+    }
+    *m = 0;
+/*     Get machine constants */
+    safmin = igraphdlamch_("S");
+    eps = igraphdlamch_("P");
+/*     Set parameters */
+    rtl = sqrt(eps);
+    bsrtol = sqrt(eps);
+/*     Treat case of 1x1 matrix for quick return */
+    if (*n == 1) {
+	if (irange == 1 || irange == 3 && d__[1] > *vl && d__[1] <= *vu || 
+		irange == 2 && *il == 1 && *iu == 1) {
+	    *m = 1;
+	    w[1] = d__[1];
+/*           The computation error of the eigenvalue is zero */
+	    werr[1] = 0.;
+	    wgap[1] = 0.;
+	    iblock[1] = 1;
+	    indexw[1] = 1;
+	    gers[1] = d__[1];
+	    gers[2] = d__[1];
+	}
+/*        store the shift for the initial RRR, which is zero in this case */
+	e[1] = 0.;
+	return 0;
+    }
+/*     General case: tridiagonal matrix of order > 1   
+
+       Init WERR, WGAP. Compute Gerschgorin intervals and spectral diameter.   
+       Compute maximum off-diagonal entry and pivmin. */
+    gl = d__[1];
+    gu = d__[1];
+    eold = 0.;
+    emax = 0.;
+    e[*n] = 0.;
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	werr[i__] = 0.;
+	wgap[i__] = 0.;
+	eabs = (d__1 = e[i__], abs(d__1));
+	if (eabs >= emax) {
+	    emax = eabs;
+	}
+	tmp1 = eabs + eold;
+	gers[(i__ << 1) - 1] = d__[i__] - tmp1;
+/* Computing MIN */
+	d__1 = gl, d__2 = gers[(i__ << 1) - 1];
+	gl = min(d__1,d__2);
+	gers[i__ * 2] = d__[i__] + tmp1;
+/* Computing MAX */
+	d__1 = gu, d__2 = gers[i__ * 2];
+	gu = max(d__1,d__2);
+	eold = eabs;
+/* L5: */
+    }
+/*     The minimum pivot allowed in the Sturm sequence for T   
+   Computing MAX   
+   Computing 2nd power */
+    d__3 = emax;
+    d__1 = 1., d__2 = d__3 * d__3;
+    *pivmin = safmin * max(d__1,d__2);
+/*     Compute spectral diameter. The Gerschgorin bounds give an   
+       estimate that is wrong by at most a factor of SQRT(2) */
+    spdiam = gu - gl;
+/*     Compute splitting points */
+    igraphdlarra_(n, &d__[1], &e[1], &e2[1], spltol, &spdiam, nsplit, &isplit[1], &
+	    iinfo);
+/*     Can force use of bisection instead of faster DQDS.   
+       Option left in the code for future multisection work. */
+    forceb = FALSE_;
+/*     Initialize USEDQD, DQDS should be used for ALLRNG unless someone   
+       explicitly wants bisection. */
+    usedqd = irange == 1 && ! forceb;
+    if (irange == 1 && ! forceb) {
+/*        Set interval [VL,VU] that contains all eigenvalues */
+	*vl = gl;
+	*vu = gu;
+    } else {
+/*        We call DLARRD to find crude approximations to the eigenvalues   
+          in the desired range. In case IRANGE = INDRNG, we also obtain the   
+          interval (VL,VU] that contains all the wanted eigenvalues.   
+          An interval [LEFT,RIGHT] has converged if   
+          RIGHT-LEFT.LT.RTOL*MAX(ABS(LEFT),ABS(RIGHT))   
+          DLARRD needs a WORK of size 4*N, IWORK of size 3*N */
+	igraphdlarrd_(range, "B", n, vl, vu, il, iu, &gers[1], &bsrtol, &d__[1], &e[
+		1], &e2[1], pivmin, nsplit, &isplit[1], &mm, &w[1], &werr[1], 
+		vl, vu, &iblock[1], &indexw[1], &work[1], &iwork[1], &iinfo);
+	if (iinfo != 0) {
+	    *info = -1;
+	    return 0;
+	}
+/*        Make sure that the entries M+1 to N in W, WERR, IBLOCK, INDEXW are 0 */
+	i__1 = *n;
+	for (i__ = mm + 1; i__ <= i__1; ++i__) {
+	    w[i__] = 0.;
+	    werr[i__] = 0.;
+	    iblock[i__] = 0;
+	    indexw[i__] = 0;
+/* L14: */
+	}
+    }
+/* **   
+       Loop over unreduced blocks */
+    ibegin = 1;
+    wbegin = 1;
+    i__1 = *nsplit;
+    for (jblk = 1; jblk <= i__1; ++jblk) {
+	iend = isplit[jblk];
+	in = iend - ibegin + 1;
+/*        1 X 1 block */
+	if (in == 1) {
+	    if (irange == 1 || irange == 3 && d__[ibegin] > *vl && d__[ibegin]
+		     <= *vu || irange == 2 && iblock[wbegin] == jblk) {
+		++(*m);
+		w[*m] = d__[ibegin];
+		werr[*m] = 0.;
+/*              The gap for a single block doesn't matter for the later   
+                algorithm and is assigned an arbitrary large value */
+		wgap[*m] = 0.;
+		iblock[*m] = jblk;
+		indexw[*m] = 1;
+		++wbegin;
+	    }
+/*           E( IEND ) holds the shift for the initial RRR */
+	    e[iend] = 0.;
+	    ibegin = iend + 1;
+	    goto L170;
+	}
+
+/*        Blocks of size larger than 1x1   
+
+          E( IEND ) will hold the shift for the initial RRR, for now set it =0 */
+	e[iend] = 0.;
+
+/*        Find local outer bounds GL,GU for the block */
+	gl = d__[ibegin];
+	gu = d__[ibegin];
+	i__2 = iend;
+	for (i__ = ibegin; i__ <= i__2; ++i__) {
+/* Computing MIN */
+	    d__1 = gers[(i__ << 1) - 1];
+	    gl = min(d__1,gl);
+/* Computing MAX */
+	    d__1 = gers[i__ * 2];
+	    gu = max(d__1,gu);
+/* L15: */
+	}
+	spdiam = gu - gl;
+	if (! (irange == 1 && ! forceb)) {
+/*           Count the number of eigenvalues in the current block. */
+	    mb = 0;
+	    i__2 = mm;
+	    for (i__ = wbegin; i__ <= i__2; ++i__) {
+		if (iblock[i__] == jblk) {
+		    ++mb;
+		} else {
+		    goto L21;
+		}
+/* L20: */
+	    }
+L21:
+	    if (mb == 0) {
+/*              No eigenvalue in the current block lies in the desired range   
+                E( IEND ) holds the shift for the initial RRR */
+		e[iend] = 0.;
+		ibegin = iend + 1;
+		goto L170;
+	    } else {
+/*              Decide whether dqds or bisection is more efficient */
+		usedqd = (doublereal) mb > in * .5 && ! forceb;
+		wend = wbegin + mb - 1;
+/*              Calculate gaps for the current block   
+                In later stages, when representations for individual   
+                eigenvalues are different, we use SIGMA = E( IEND ). */
+		sigma = 0.;
+		i__2 = wend - 1;
+		for (i__ = wbegin; i__ <= i__2; ++i__) {
+/* Computing MAX */
+		    d__1 = 0., d__2 = w[i__ + 1] - werr[i__ + 1] - (w[i__] + 
+			    werr[i__]);
+		    wgap[i__] = max(d__1,d__2);
+/* L30: */
+		}
+/* Computing MAX */
+		d__1 = 0., d__2 = *vu - sigma - (w[wend] + werr[wend]);
+		wgap[wend] = max(d__1,d__2);
+/*              Find local index of the first and last desired evalue. */
+		indl = indexw[wbegin];
+		indu = indexw[wend];
+	    }
+	}
+	if (irange == 1 && ! forceb || usedqd) {
+/*           Case of DQDS   
+             Find approximations to the extremal eigenvalues of the block */
+	    igraphdlarrk_(&in, &c__1, &gl, &gu, &d__[ibegin], &e2[ibegin], pivmin, &
+		    rtl, &tmp, &tmp1, &iinfo);
+	    if (iinfo != 0) {
+		*info = -1;
+		return 0;
+	    }
+/* Computing MAX */
+	    d__2 = gl, d__3 = tmp - tmp1 - eps * 100. * (d__1 = tmp - tmp1, 
+		    abs(d__1));
+	    isleft = max(d__2,d__3);
+	    igraphdlarrk_(&in, &in, &gl, &gu, &d__[ibegin], &e2[ibegin], pivmin, &
+		    rtl, &tmp, &tmp1, &iinfo);
+	    if (iinfo != 0) {
+		*info = -1;
+		return 0;
+	    }
+/* Computing MIN */
+	    d__2 = gu, d__3 = tmp + tmp1 + eps * 100. * (d__1 = tmp + tmp1, 
+		    abs(d__1));
+	    isrght = min(d__2,d__3);
+/*           Improve the estimate of the spectral diameter */
+	    spdiam = isrght - isleft;
+	} else {
+/*           Case of bisection   
+             Find approximations to the wanted extremal eigenvalues   
+   Computing MAX */
+	    d__2 = gl, d__3 = w[wbegin] - werr[wbegin] - eps * 100. * (d__1 = 
+		    w[wbegin] - werr[wbegin], abs(d__1));
+	    isleft = max(d__2,d__3);
+/* Computing MIN */
+	    d__2 = gu, d__3 = w[wend] + werr[wend] + eps * 100. * (d__1 = w[
+		    wend] + werr[wend], abs(d__1));
+	    isrght = min(d__2,d__3);
+	}
+/*        Decide whether the base representation for the current block   
+          L_JBLK D_JBLK L_JBLK^T = T_JBLK - sigma_JBLK I   
+          should be on the left or the right end of the current block.   
+          The strategy is to shift to the end which is "more populated"   
+          Furthermore, decide whether to use DQDS for the computation of   
+          the eigenvalue approximations at the end of DLARRE or bisection.   
+          dqds is chosen if all eigenvalues are desired or the number of   
+          eigenvalues to be computed is large compared to the blocksize. */
+	if (irange == 1 && ! forceb) {
+/*           If all the eigenvalues have to be computed, we use dqd */
+	    usedqd = TRUE_;
+/*           INDL is the local index of the first eigenvalue to compute */
+	    indl = 1;
+	    indu = in;
+/*           MB =  number of eigenvalues to compute */
+	    mb = in;
+	    wend = wbegin + mb - 1;
+/*           Define 1/4 and 3/4 points of the spectrum */
+	    s1 = isleft + spdiam * .25;
+	    s2 = isrght - spdiam * .25;
+	} else {
+/*           DLARRD has computed IBLOCK and INDEXW for each eigenvalue   
+             approximation.   
+             choose sigma */
+	    if (usedqd) {
+		s1 = isleft + spdiam * .25;
+		s2 = isrght - spdiam * .25;
+	    } else {
+		tmp = min(isrght,*vu) - max(isleft,*vl);
+		s1 = max(isleft,*vl) + tmp * .25;
+		s2 = min(isrght,*vu) - tmp * .25;
+	    }
+	}
+/*        Compute the negcount at the 1/4 and 3/4 points */
+	if (mb > 1) {
+	    igraphdlarrc_("T", &in, &s1, &s2, &d__[ibegin], &e[ibegin], pivmin, &
+		    cnt, &cnt1, &cnt2, &iinfo);
+	}
+	if (mb == 1) {
+	    sigma = gl;
+	    sgndef = 1.;
+	} else if (cnt1 - indl >= indu - cnt2) {
+	    if (irange == 1 && ! forceb) {
+		sigma = max(isleft,gl);
+	    } else if (usedqd) {
+/*              use Gerschgorin bound as shift to get pos def matrix   
+                for dqds */
+		sigma = isleft;
+	    } else {
+/*              use approximation of the first desired eigenvalue of the   
+                block as shift */
+		sigma = max(isleft,*vl);
+	    }
+	    sgndef = 1.;
+	} else {
+	    if (irange == 1 && ! forceb) {
+		sigma = min(isrght,gu);
+	    } else if (usedqd) {
+/*              use Gerschgorin bound as shift to get neg def matrix   
+                for dqds */
+		sigma = isrght;
+	    } else {
+/*              use approximation of the first desired eigenvalue of the   
+                block as shift */
+		sigma = min(isrght,*vu);
+	    }
+	    sgndef = -1.;
+	}
+/*        An initial SIGMA has been chosen that will be used for computing   
+          T - SIGMA I = L D L^T   
+          Define the increment TAU of the shift in case the initial shift   
+          needs to be refined to obtain a factorization with not too much   
+          element growth. */
+	if (usedqd) {
+/*           The initial SIGMA was to the outer end of the spectrum   
+             the matrix is definite and we need not retreat. */
+	    tau = spdiam * eps * *n + *pivmin * 2.;
+/* Computing MAX */
+	    d__1 = tau, d__2 = eps * 2. * abs(sigma);
+	    tau = max(d__1,d__2);
+	} else {
+	    if (mb > 1) {
+		clwdth = w[wend] + werr[wend] - w[wbegin] - werr[wbegin];
+		avgap = (d__1 = clwdth / (doublereal) (wend - wbegin), abs(
+			d__1));
+		if (sgndef == 1.) {
+/* Computing MAX */
+		    d__1 = wgap[wbegin];
+		    tau = max(d__1,avgap) * .5;
+/* Computing MAX */
+		    d__1 = tau, d__2 = werr[wbegin];
+		    tau = max(d__1,d__2);
+		} else {
+/* Computing MAX */
+		    d__1 = wgap[wend - 1];
+		    tau = max(d__1,avgap) * .5;
+/* Computing MAX */
+		    d__1 = tau, d__2 = werr[wend];
+		    tau = max(d__1,d__2);
+		}
+	    } else {
+		tau = werr[wbegin];
+	    }
+	}
+
+	for (idum = 1; idum <= 6; ++idum) {
+/*           Compute L D L^T factorization of tridiagonal matrix T - sigma I.   
+             Store D in WORK(1:IN), L in WORK(IN+1:2*IN), and reciprocals of   
+             pivots in WORK(2*IN+1:3*IN) */
+	    dpivot = d__[ibegin] - sigma;
+	    work[1] = dpivot;
+	    dmax__ = abs(work[1]);
+	    j = ibegin;
+	    i__2 = in - 1;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		work[(in << 1) + i__] = 1. / work[i__];
+		tmp = e[j] * work[(in << 1) + i__];
+		work[in + i__] = tmp;
+		dpivot = d__[j + 1] - sigma - tmp * e[j];
+		work[i__ + 1] = dpivot;
+/* Computing MAX */
+		d__1 = dmax__, d__2 = abs(dpivot);
+		dmax__ = max(d__1,d__2);
+		++j;
+/* L70: */
+	    }
+/*           check for element growth */
+	    if (dmax__ > spdiam * 64.) {
+		norep = TRUE_;
+	    } else {
+		norep = FALSE_;
+	    }
+	    if (usedqd && ! norep) {
+/*              Ensure the definiteness of the representation   
+                All entries of D (of L D L^T) must have the same sign */
+		i__2 = in;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    tmp = sgndef * work[i__];
+		    if (tmp < 0.) {
+			norep = TRUE_;
+		    }
+/* L71: */
+		}
+	    }
+	    if (norep) {
+/*              Note that in the case of IRANGE=ALLRNG, we use the Gerschgorin   
+                shift which makes the matrix definite. So we should end up   
+                here really only in the case of IRANGE = VALRNG or INDRNG. */
+		if (idum == 5) {
+		    if (sgndef == 1.) {
+/*                    The fudged Gerschgorin shift should succeed */
+			sigma = gl - spdiam * 2. * eps * *n - *pivmin * 4.;
+		    } else {
+			sigma = gu + spdiam * 2. * eps * *n + *pivmin * 4.;
+		    }
+		} else {
+		    sigma -= sgndef * tau;
+		    tau *= 2.;
+		}
+	    } else {
+/*              an initial RRR is found */
+		goto L83;
+	    }
+/* L80: */
+	}
+/*        if the program reaches this point, no base representation could be   
+          found in MAXTRY iterations. */
+	*info = 2;
+	return 0;
+L83:
+/*        At this point, we have found an initial base representation   
+          T - SIGMA I = L D L^T with not too much element growth.   
+          Store the shift. */
+	e[iend] = sigma;
+/*        Store D and L. */
+	igraphdcopy_(&in, &work[1], &c__1, &d__[ibegin], &c__1);
+	i__2 = in - 1;
+	igraphdcopy_(&i__2, &work[in + 1], &c__1, &e[ibegin], &c__1);
+	if (mb > 1) {
+
+/*           Perturb each entry of the base representation by a small   
+             (but random) relative amount to overcome difficulties with   
+             glued matrices. */
+
+	    for (i__ = 1; i__ <= 4; ++i__) {
+		iseed[i__ - 1] = 1;
+/* L122: */
+	    }
+	    i__2 = (in << 1) - 1;
+	    igraphdlarnv_(&c__2, iseed, &i__2, &work[1]);
+	    i__2 = in - 1;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		d__[ibegin + i__ - 1] *= eps * 8. * work[i__] + 1.;
+		e[ibegin + i__ - 1] *= eps * 8. * work[in + i__] + 1.;
+/* L125: */
+	    }
+	    d__[iend] *= eps * 4. * work[in] + 1.;
+
+	}
+
+/*        Don't update the Gerschgorin intervals because keeping track   
+          of the updates would be too much work in DLARRV.   
+          We update W instead and use it to locate the proper Gerschgorin   
+          intervals.   
+          Compute the required eigenvalues of L D L' by bisection or dqds */
+	if (! usedqd) {
+/*           If DLARRD has been used, shift the eigenvalue approximations   
+             according to their representation. This is necessary for   
+             a uniform DLARRV since dqds computes eigenvalues of the   
+             shifted representation. In DLARRV, W will always hold the   
+             UNshifted eigenvalue approximation. */
+	    i__2 = wend;
+	    for (j = wbegin; j <= i__2; ++j) {
+		w[j] -= sigma;
+		werr[j] += (d__1 = w[j], abs(d__1)) * eps;
+/* L134: */
+	    }
+/*           call DLARRB to reduce eigenvalue error of the approximations   
+             from DLARRD */
+	    i__2 = iend - 1;
+	    for (i__ = ibegin; i__ <= i__2; ++i__) {
+/* Computing 2nd power */
+		d__1 = e[i__];
+		work[i__] = d__[i__] * (d__1 * d__1);
+/* L135: */
+	    }
+/*           use bisection to find EV from INDL to INDU */
+	    i__2 = indl - 1;
+	    igraphdlarrb_(&in, &d__[ibegin], &work[ibegin], &indl, &indu, rtol1, 
+		    rtol2, &i__2, &w[wbegin], &wgap[wbegin], &werr[wbegin], &
+		    work[(*n << 1) + 1], &iwork[1], pivmin, &spdiam, &in, &
+		    iinfo);
+	    if (iinfo != 0) {
+		*info = -4;
+		return 0;
+	    }
+/*           DLARRB computes all gaps correctly except for the last one   
+             Record distance to VU/GU   
+   Computing MAX */
+	    d__1 = 0., d__2 = *vu - sigma - (w[wend] + werr[wend]);
+	    wgap[wend] = max(d__1,d__2);
+	    i__2 = indu;
+	    for (i__ = indl; i__ <= i__2; ++i__) {
+		++(*m);
+		iblock[*m] = jblk;
+		indexw[*m] = i__;
+/* L138: */
+	    }
+	} else {
+/*           Call dqds to get all eigs (and then possibly delete unwanted   
+             eigenvalues).   
+             Note that dqds finds the eigenvalues of the L D L^T representation   
+             of T to high relative accuracy. High relative accuracy   
+             might be lost when the shift of the RRR is subtracted to obtain   
+             the eigenvalues of T. However, T is not guaranteed to define its   
+             eigenvalues to high relative accuracy anyway.   
+             Set RTOL to the order of the tolerance used in DLASQ2   
+             This is an ESTIMATED error, the worst case bound is 4*N*EPS   
+             which is usually too large and requires unnecessary work to be   
+             done by bisection when computing the eigenvectors */
+	    rtol = log((doublereal) in) * 4. * eps;
+	    j = ibegin;
+	    i__2 = in - 1;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		work[(i__ << 1) - 1] = (d__1 = d__[j], abs(d__1));
+		work[i__ * 2] = e[j] * e[j] * work[(i__ << 1) - 1];
+		++j;
+/* L140: */
+	    }
+	    work[(in << 1) - 1] = (d__1 = d__[iend], abs(d__1));
+	    work[in * 2] = 0.;
+	    igraphdlasq2_(&in, &work[1], &iinfo);
+	    if (iinfo != 0) {
+/*              If IINFO = -5 then an index is part of a tight cluster   
+                and should be changed. The index is in IWORK(1) and the   
+                gap is in WORK(N+1) */
+		*info = -5;
+		return 0;
+	    } else {
+/*              Test that all eigenvalues are positive as expected */
+		i__2 = in;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    if (work[i__] < 0.) {
+			*info = -6;
+			return 0;
+		    }
+/* L149: */
+		}
+	    }
+	    if (sgndef > 0.) {
+		i__2 = indu;
+		for (i__ = indl; i__ <= i__2; ++i__) {
+		    ++(*m);
+		    w[*m] = work[in - i__ + 1];
+		    iblock[*m] = jblk;
+		    indexw[*m] = i__;
+/* L150: */
+		}
+	    } else {
+		i__2 = indu;
+		for (i__ = indl; i__ <= i__2; ++i__) {
+		    ++(*m);
+		    w[*m] = -work[i__];
+		    iblock[*m] = jblk;
+		    indexw[*m] = i__;
+/* L160: */
+		}
+	    }
+	    i__2 = *m;
+	    for (i__ = *m - mb + 1; i__ <= i__2; ++i__) {
+/*              the value of RTOL below should be the tolerance in DLASQ2 */
+		werr[i__] = rtol * (d__1 = w[i__], abs(d__1));
+/* L165: */
+	    }
+	    i__2 = *m - 1;
+	    for (i__ = *m - mb + 1; i__ <= i__2; ++i__) {
+/*              compute the right gap between the intervals   
+   Computing MAX */
+		d__1 = 0., d__2 = w[i__ + 1] - werr[i__ + 1] - (w[i__] + werr[
+			i__]);
+		wgap[i__] = max(d__1,d__2);
+/* L166: */
+	    }
+/* Computing MAX */
+	    d__1 = 0., d__2 = *vu - sigma - (w[*m] + werr[*m]);
+	    wgap[*m] = max(d__1,d__2);
+	}
+/*        proceed with next block */
+	ibegin = iend + 1;
+	wbegin = wend + 1;
+L170:
+	;
+    }
+
+    return 0;
+
+/*     end of DLARRE */
+
+} /* igraphdlarre_ */
+
diff --git a/src/lapack/dlarrf.c b/src/lapack/dlarrf.c
new file mode 100644
index 0000000..68159db
--- /dev/null
+++ b/src/lapack/dlarrf.c
@@ -0,0 +1,419 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdlarrf_(integer *n, doublereal *d__, doublereal *l, 
+	doublereal *ld, integer *clstrt, integer *clend, doublereal *w, 
+	doublereal *wgap, doublereal *werr, doublereal *spdiam, doublereal *
+	clgapl, doublereal *clgapr, doublereal *pivmin, doublereal *sigma, 
+	doublereal *dplus, doublereal *lplus, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal s, bestshift, smlgrowth, eps, tmp, max1, max2, rrr1, rrr2, 
+	    znm2, growthbound, fail, fact, oldp;
+    integer indx;
+    doublereal prod;
+    integer ktry;
+    doublereal fail2, avgap, ldmax, rdmax;
+    integer shift;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    logical dorrr1;
+    extern doublereal igraphdlamch_(char *);
+    doublereal ldelta;
+    logical nofail;
+    doublereal mingap, lsigma, rdelta;
+    extern logical igraphdisnan_(doublereal *);
+    logical forcer;
+    doublereal rsigma, clwdth;
+    logical sawnan1, sawnan2, tryrrr1;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+   *   
+
+    Purpose   
+    =======   
+
+    Given the initial representation L D L^T and its cluster of close   
+    eigenvalues (in a relative measure), W( CLSTRT ), W( CLSTRT+1 ), ...   
+    W( CLEND ), DLARRF finds a new relatively robust representation   
+    L D L^T - SIGMA I = L(+) D(+) L(+)^T such that at least one of the   
+    eigenvalues of L(+) D(+) L(+)^T is relatively isolated.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix (subblock, if the matrix splitted).   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The N diagonal elements of the diagonal matrix D.   
+
+    L       (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (N-1) subdiagonal elements of the unit bidiagonal   
+            matrix L.   
+
+    LD      (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (N-1) elements L(i)*D(i).   
+
+    CLSTRT  (input) INTEGER   
+            The index of the first eigenvalue in the cluster.   
+
+    CLEND   (input) INTEGER   
+            The index of the last eigenvalue in the cluster.   
+
+    W       (input) DOUBLE PRECISION array, dimension   
+            dimension is >=  (CLEND-CLSTRT+1)   
+            The eigenvalue APPROXIMATIONS of L D L^T in ascending order.   
+            W( CLSTRT ) through W( CLEND ) form the cluster of relatively   
+            close eigenalues.   
+
+    WGAP    (input/output) DOUBLE PRECISION array, dimension   
+            dimension is >=  (CLEND-CLSTRT+1)   
+            The separation from the right neighbor eigenvalue in W.   
+
+    WERR    (input) DOUBLE PRECISION array, dimension   
+            dimension is  >=  (CLEND-CLSTRT+1)   
+            WERR contain the semiwidth of the uncertainty   
+            interval of the corresponding eigenvalue APPROXIMATION in W   
+
+    SPDIAM  (input) DOUBLE PRECISION   
+            estimate of the spectral diameter obtained from the   
+            Gerschgorin intervals   
+
+    CLGAPL  (input) DOUBLE PRECISION   
+
+    CLGAPR  (input) DOUBLE PRECISION   
+            absolute gap on each end of the cluster.   
+            Set by the calling routine to protect against shifts too close   
+            to eigenvalues outside the cluster.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot allowed in the Sturm sequence.   
+
+    SIGMA   (output) DOUBLE PRECISION   
+            The shift used to form L(+) D(+) L(+)^T.   
+
+    DPLUS   (output) DOUBLE PRECISION array, dimension (N)   
+            The N diagonal elements of the diagonal matrix D(+).   
+
+    LPLUS   (output) DOUBLE PRECISION array, dimension (N-1)   
+            The first (N-1) elements of LPLUS contain the subdiagonal   
+            elements of the unit bidiagonal matrix L(+).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (2*N)   
+            Workspace.   
+
+    INFO    (output) INTEGER   
+            Signals processing OK (=0) or failure (=1)   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --work;
+    --lplus;
+    --dplus;
+    --werr;
+    --wgap;
+    --w;
+    --ld;
+    --l;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+    fact = 2.;
+    eps = igraphdlamch_("Precision");
+    shift = 0;
+    forcer = FALSE_;
+/*     Note that we cannot guarantee that for any of the shifts tried,   
+       the factorization has a small or even moderate element growth.   
+       There could be Ritz values at both ends of the cluster and despite   
+       backing off, there are examples where all factorizations tried   
+       (in IEEE mode, allowing zero pivots & infinities) have INFINITE   
+       element growth.   
+       For this reason, we should use PIVMIN in this subroutine so that at   
+       least the L D L^T factorization exists. It can be checked afterwards   
+       whether the element growth caused bad residuals/orthogonality.   
+       Decide whether the code should accept the best among all   
+       representations despite large element growth or signal INFO=1 */
+    nofail = TRUE_;
+
+/*     Compute the average gap length of the cluster */
+    clwdth = (d__1 = w[*clend] - w[*clstrt], abs(d__1)) + werr[*clend] + werr[
+	    *clstrt];
+    avgap = clwdth / (doublereal) (*clend - *clstrt);
+    mingap = min(*clgapl,*clgapr);
+/*     Initial values for shifts to both ends of cluster   
+   Computing MIN */
+    d__1 = w[*clstrt], d__2 = w[*clend];
+    lsigma = min(d__1,d__2) - werr[*clstrt];
+/* Computing MAX */
+    d__1 = w[*clstrt], d__2 = w[*clend];
+    rsigma = max(d__1,d__2) + werr[*clend];
+/*     Use a small fudge to make sure that we really shift to the outside */
+    lsigma -= abs(lsigma) * 4. * eps;
+    rsigma += abs(rsigma) * 4. * eps;
+/*     Compute upper bounds for how much to back off the initial shifts */
+    ldmax = mingap * .25 + *pivmin * 2.;
+    rdmax = mingap * .25 + *pivmin * 2.;
+/* Computing MAX */
+    d__1 = avgap, d__2 = wgap[*clstrt];
+    ldelta = max(d__1,d__2) / fact;
+/* Computing MAX */
+    d__1 = avgap, d__2 = wgap[*clend - 1];
+    rdelta = max(d__1,d__2) / fact;
+
+/*     Initialize the record of the best representation found */
+
+    s = igraphdlamch_("S");
+    smlgrowth = 1. / s;
+    fail = (doublereal) (*n - 1) * mingap / (*spdiam * eps);
+    fail2 = (doublereal) (*n - 1) * mingap / (*spdiam * sqrt(eps));
+    bestshift = lsigma;
+
+/*     while (KTRY <= KTRYMAX) */
+    ktry = 0;
+    growthbound = *spdiam * 8.;
+L5:
+    sawnan1 = FALSE_;
+    sawnan2 = FALSE_;
+/*     Ensure that we do not back off too much of the initial shifts */
+    ldelta = min(ldmax,ldelta);
+    rdelta = min(rdmax,rdelta);
+/*     Compute the element growth when shifting to both ends of the cluster   
+       accept the shift if there is no element growth at one of the two ends   
+       Left end */
+    s = -lsigma;
+    dplus[1] = d__[1] + s;
+    if (abs(dplus[1]) < *pivmin) {
+	dplus[1] = -(*pivmin);
+/*        Need to set SAWNAN1 because refined RRR test should not be used   
+          in this case */
+	sawnan1 = TRUE_;
+    }
+    max1 = abs(dplus[1]);
+    i__1 = *n - 1;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	lplus[i__] = ld[i__] / dplus[i__];
+	s = s * lplus[i__] * l[i__] - lsigma;
+	dplus[i__ + 1] = d__[i__ + 1] + s;
+	if ((d__1 = dplus[i__ + 1], abs(d__1)) < *pivmin) {
+	    dplus[i__ + 1] = -(*pivmin);
+/*           Need to set SAWNAN1 because refined RRR test should not be used   
+             in this case */
+	    sawnan1 = TRUE_;
+	}
+/* Computing MAX */
+	d__2 = max1, d__3 = (d__1 = dplus[i__ + 1], abs(d__1));
+	max1 = max(d__2,d__3);
+/* L6: */
+    }
+    sawnan1 = sawnan1 || igraphdisnan_(&max1);
+    if (forcer || max1 <= growthbound && ! sawnan1) {
+	*sigma = lsigma;
+	shift = 1;
+	goto L100;
+    }
+/*     Right end */
+    s = -rsigma;
+    work[1] = d__[1] + s;
+    if (abs(work[1]) < *pivmin) {
+	work[1] = -(*pivmin);
+/*        Need to set SAWNAN2 because refined RRR test should not be used   
+          in this case */
+	sawnan2 = TRUE_;
+    }
+    max2 = abs(work[1]);
+    i__1 = *n - 1;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	work[*n + i__] = ld[i__] / work[i__];
+	s = s * work[*n + i__] * l[i__] - rsigma;
+	work[i__ + 1] = d__[i__ + 1] + s;
+	if ((d__1 = work[i__ + 1], abs(d__1)) < *pivmin) {
+	    work[i__ + 1] = -(*pivmin);
+/*           Need to set SAWNAN2 because refined RRR test should not be used   
+             in this case */
+	    sawnan2 = TRUE_;
+	}
+/* Computing MAX */
+	d__2 = max2, d__3 = (d__1 = work[i__ + 1], abs(d__1));
+	max2 = max(d__2,d__3);
+/* L7: */
+    }
+    sawnan2 = sawnan2 || igraphdisnan_(&max2);
+    if (forcer || max2 <= growthbound && ! sawnan2) {
+	*sigma = rsigma;
+	shift = 2;
+	goto L100;
+    }
+/*     If we are at this point, both shifts led to too much element growth   
+       Record the better of the two shifts (provided it didn't lead to NaN) */
+    if (sawnan1 && sawnan2) {
+/*        both MAX1 and MAX2 are NaN */
+	goto L50;
+    } else {
+	if (! sawnan1) {
+	    indx = 1;
+	    if (max1 <= smlgrowth) {
+		smlgrowth = max1;
+		bestshift = lsigma;
+	    }
+	}
+	if (! sawnan2) {
+	    if (sawnan1 || max2 <= max1) {
+		indx = 2;
+	    }
+	    if (max2 <= smlgrowth) {
+		smlgrowth = max2;
+		bestshift = rsigma;
+	    }
+	}
+    }
+/*     If we are here, both the left and the right shift led to   
+       element growth. If the element growth is moderate, then   
+       we may still accept the representation, if it passes a   
+       refined test for RRR. This test supposes that no NaN occurred.   
+       Moreover, we use the refined RRR test only for isolated clusters. */
+    if (clwdth < mingap / 128. && min(max1,max2) < fail2 && ! sawnan1 && ! 
+	    sawnan2) {
+	dorrr1 = TRUE_;
+    } else {
+	dorrr1 = FALSE_;
+    }
+    tryrrr1 = TRUE_;
+    if (tryrrr1 && dorrr1) {
+	if (indx == 1) {
+	    tmp = (d__1 = dplus[*n], abs(d__1));
+	    znm2 = 1.;
+	    prod = 1.;
+	    oldp = 1.;
+	    for (i__ = *n - 1; i__ >= 1; --i__) {
+		if (prod <= eps) {
+		    prod = dplus[i__ + 1] * work[*n + i__ + 1] / (dplus[i__] *
+			     work[*n + i__]) * oldp;
+		} else {
+		    prod *= (d__1 = work[*n + i__], abs(d__1));
+		}
+		oldp = prod;
+/* Computing 2nd power */
+		d__1 = prod;
+		znm2 += d__1 * d__1;
+/* Computing MAX */
+		d__2 = tmp, d__3 = (d__1 = dplus[i__] * prod, abs(d__1));
+		tmp = max(d__2,d__3);
+/* L15: */
+	    }
+	    rrr1 = tmp / (*spdiam * sqrt(znm2));
+	    if (rrr1 <= 8.) {
+		*sigma = lsigma;
+		shift = 1;
+		goto L100;
+	    }
+	} else if (indx == 2) {
+	    tmp = (d__1 = work[*n], abs(d__1));
+	    znm2 = 1.;
+	    prod = 1.;
+	    oldp = 1.;
+	    for (i__ = *n - 1; i__ >= 1; --i__) {
+		if (prod <= eps) {
+		    prod = work[i__ + 1] * lplus[i__ + 1] / (work[i__] * 
+			    lplus[i__]) * oldp;
+		} else {
+		    prod *= (d__1 = lplus[i__], abs(d__1));
+		}
+		oldp = prod;
+/* Computing 2nd power */
+		d__1 = prod;
+		znm2 += d__1 * d__1;
+/* Computing MAX */
+		d__2 = tmp, d__3 = (d__1 = work[i__] * prod, abs(d__1));
+		tmp = max(d__2,d__3);
+/* L16: */
+	    }
+	    rrr2 = tmp / (*spdiam * sqrt(znm2));
+	    if (rrr2 <= 8.) {
+		*sigma = rsigma;
+		shift = 2;
+		goto L100;
+	    }
+	}
+    }
+L50:
+    if (ktry < 1) {
+/*        If we are here, both shifts failed also the RRR test.   
+          Back off to the outside   
+   Computing MAX */
+	d__1 = lsigma - ldelta, d__2 = lsigma - ldmax;
+	lsigma = max(d__1,d__2);
+/* Computing MIN */
+	d__1 = rsigma + rdelta, d__2 = rsigma + rdmax;
+	rsigma = min(d__1,d__2);
+	ldelta *= 2.;
+	rdelta *= 2.;
+	++ktry;
+	goto L5;
+    } else {
+/*        None of the representations investigated satisfied our   
+          criteria. Take the best one we found. */
+	if (smlgrowth < fail || nofail) {
+	    lsigma = bestshift;
+	    rsigma = bestshift;
+	    forcer = TRUE_;
+	    goto L5;
+	} else {
+	    *info = 1;
+	    return 0;
+	}
+    }
+L100:
+    if (shift == 1) {
+    } else if (shift == 2) {
+/*        store new L and D back into DPLUS, LPLUS */
+	igraphdcopy_(n, &work[1], &c__1, &dplus[1], &c__1);
+	i__1 = *n - 1;
+	igraphdcopy_(&i__1, &work[*n + 1], &c__1, &lplus[1], &c__1);
+    }
+    return 0;
+
+/*     End of DLARRF */
+
+} /* igraphdlarrf_ */
+
diff --git a/src/lapack/dlarrj.c b/src/lapack/dlarrj.c
new file mode 100644
index 0000000..b4047c7
--- /dev/null
+++ b/src/lapack/dlarrj.c
@@ -0,0 +1,328 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarrj_(integer *n, doublereal *d__, doublereal *e2, 
+	integer *ifirst, integer *ilast, doublereal *rtol, integer *offset, 
+	doublereal *w, doublereal *werr, doublereal *work, integer *iwork, 
+	doublereal *pivmin, doublereal *spdiam, integer *info)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double log(doublereal);
+
+    /* Local variables */
+    integer i__, j, k, p;
+    doublereal s;
+    integer i1, i2, ii;
+    doublereal fac, mid;
+    integer cnt;
+    doublereal tmp, left;
+    integer iter, nint, prev, next, savi1;
+    doublereal right, width, dplus;
+    integer olnint, maxitr;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    Given the initial eigenvalue approximations of T, DLARRJ   
+    does  bisection to refine the eigenvalues of T,   
+    W( IFIRST-OFFSET ) through W( ILAST-OFFSET ), to more accuracy. Initial   
+    guesses for these eigenvalues are input in W, the corresponding estimate   
+    of the error in these guesses in WERR. During bisection, intervals   
+    [left, right] are maintained by storing their mid-points and   
+    semi-widths in the arrays W and WERR respectively.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The N diagonal elements of T.   
+
+    E2      (input) DOUBLE PRECISION array, dimension (N-1)   
+            The Squares of the (N-1) subdiagonal elements of T.   
+
+    IFIRST  (input) INTEGER   
+            The index of the first eigenvalue to be computed.   
+
+    ILAST   (input) INTEGER   
+            The index of the last eigenvalue to be computed.   
+
+    RTOL    (input) DOUBLE PRECISION   
+            Tolerance for the convergence of the bisection intervals.   
+            An interval [LEFT,RIGHT] has converged if   
+            RIGHT-LEFT.LT.RTOL*MAX(|LEFT|,|RIGHT|).   
+
+    OFFSET  (input) INTEGER   
+            Offset for the arrays W and WERR, i.e., the IFIRST-OFFSET   
+            through ILAST-OFFSET elements of these arrays are to be used.   
+
+    W       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On input, W( IFIRST-OFFSET ) through W( ILAST-OFFSET ) are   
+            estimates of the eigenvalues of L D L^T indexed IFIRST through   
+            ILAST.   
+            On output, these estimates are refined.   
+
+    WERR    (input/output) DOUBLE PRECISION array, dimension (N)   
+            On input, WERR( IFIRST-OFFSET ) through WERR( ILAST-OFFSET ) are   
+            the errors in the estimates of the corresponding elements in W.   
+            On output, these errors are refined.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (2*N)   
+            Workspace.   
+
+    IWORK   (workspace) INTEGER array, dimension (2*N)   
+            Workspace.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot in the Sturm sequence for T.   
+
+    SPDIAM  (input) DOUBLE PRECISION   
+            The spectral diameter of T.   
+
+    INFO    (output) INTEGER   
+            Error flag.   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+
+       Parameter adjustments */
+    --iwork;
+    --work;
+    --werr;
+    --w;
+    --e2;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+
+    maxitr = (integer) ((log(*spdiam + *pivmin) - log(*pivmin)) / log(2.)) + 
+	    2;
+
+/*     Initialize unconverged intervals in [ WORK(2*I-1), WORK(2*I) ].   
+       The Sturm Count, Count( WORK(2*I-1) ) is arranged to be I-1, while   
+       Count( WORK(2*I) ) is stored in IWORK( 2*I ). The integer IWORK( 2*I-1 )   
+       for an unconverged interval is set to the index of the next unconverged   
+       interval, and is -1 or 0 for a converged interval. Thus a linked   
+       list of unconverged intervals is set up. */
+
+    i1 = *ifirst;
+    i2 = *ilast;
+/*     The number of unconverged intervals */
+    nint = 0;
+/*     The last unconverged interval found */
+    prev = 0;
+    i__1 = i2;
+    for (i__ = i1; i__ <= i__1; ++i__) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+	left = w[ii] - werr[ii];
+	mid = w[ii];
+	right = w[ii] + werr[ii];
+	width = right - mid;
+/* Computing MAX */
+	d__1 = abs(left), d__2 = abs(right);
+	tmp = max(d__1,d__2);
+/*        The following test prevents the test of converged intervals */
+	if (width < *rtol * tmp) {
+/*           This interval has already converged and does not need refinement.   
+             (Note that the gaps might change through refining the   
+              eigenvalues, however, they can only get bigger.)   
+             Remove it from the list. */
+	    iwork[k - 1] = -1;
+/*           Make sure that I1 always points to the first unconverged interval */
+	    if (i__ == i1 && i__ < i2) {
+		i1 = i__ + 1;
+	    }
+	    if (prev >= i1 && i__ <= i2) {
+		iwork[(prev << 1) - 1] = i__ + 1;
+	    }
+	} else {
+/*           unconverged interval found */
+	    prev = i__;
+/*           Make sure that [LEFT,RIGHT] contains the desired eigenvalue   
+
+             Do while( CNT(LEFT).GT.I-1 ) */
+
+	    fac = 1.;
+L20:
+	    cnt = 0;
+	    s = left;
+	    dplus = d__[1] - s;
+	    if (dplus < 0.) {
+		++cnt;
+	    }
+	    i__2 = *n;
+	    for (j = 2; j <= i__2; ++j) {
+		dplus = d__[j] - s - e2[j - 1] / dplus;
+		if (dplus < 0.) {
+		    ++cnt;
+		}
+/* L30: */
+	    }
+	    if (cnt > i__ - 1) {
+		left -= werr[ii] * fac;
+		fac *= 2.;
+		goto L20;
+	    }
+
+/*           Do while( CNT(RIGHT).LT.I ) */
+
+	    fac = 1.;
+L50:
+	    cnt = 0;
+	    s = right;
+	    dplus = d__[1] - s;
+	    if (dplus < 0.) {
+		++cnt;
+	    }
+	    i__2 = *n;
+	    for (j = 2; j <= i__2; ++j) {
+		dplus = d__[j] - s - e2[j - 1] / dplus;
+		if (dplus < 0.) {
+		    ++cnt;
+		}
+/* L60: */
+	    }
+	    if (cnt < i__) {
+		right += werr[ii] * fac;
+		fac *= 2.;
+		goto L50;
+	    }
+	    ++nint;
+	    iwork[k - 1] = i__ + 1;
+	    iwork[k] = cnt;
+	}
+	work[k - 1] = left;
+	work[k] = right;
+/* L75: */
+    }
+    savi1 = i1;
+
+/*     Do while( NINT.GT.0 ), i.e. there are still unconverged intervals   
+       and while (ITER.LT.MAXITR) */
+
+    iter = 0;
+L80:
+    prev = i1 - 1;
+    i__ = i1;
+    olnint = nint;
+    i__1 = olnint;
+    for (p = 1; p <= i__1; ++p) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+	next = iwork[k - 1];
+	left = work[k - 1];
+	right = work[k];
+	mid = (left + right) * .5;
+/*        semiwidth of interval */
+	width = right - mid;
+/* Computing MAX */
+	d__1 = abs(left), d__2 = abs(right);
+	tmp = max(d__1,d__2);
+	if (width < *rtol * tmp || iter == maxitr) {
+/*           reduce number of unconverged intervals */
+	    --nint;
+/*           Mark interval as converged. */
+	    iwork[k - 1] = 0;
+	    if (i1 == i__) {
+		i1 = next;
+	    } else {
+/*              Prev holds the last unconverged interval previously examined */
+		if (prev >= i1) {
+		    iwork[(prev << 1) - 1] = next;
+		}
+	    }
+	    i__ = next;
+	    goto L100;
+	}
+	prev = i__;
+
+/*        Perform one bisection step */
+
+	cnt = 0;
+	s = mid;
+	dplus = d__[1] - s;
+	if (dplus < 0.) {
+	    ++cnt;
+	}
+	i__2 = *n;
+	for (j = 2; j <= i__2; ++j) {
+	    dplus = d__[j] - s - e2[j - 1] / dplus;
+	    if (dplus < 0.) {
+		++cnt;
+	    }
+/* L90: */
+	}
+	if (cnt <= i__ - 1) {
+	    work[k - 1] = mid;
+	} else {
+	    work[k] = mid;
+	}
+	i__ = next;
+L100:
+	;
+    }
+    ++iter;
+/*     do another loop if there are still unconverged intervals   
+       However, in the last iteration, all intervals are accepted   
+       since this is the best we can do. */
+    if (nint > 0 && iter <= maxitr) {
+	goto L80;
+    }
+
+
+/*     At this point, all the intervals have converged */
+    i__1 = *ilast;
+    for (i__ = savi1; i__ <= i__1; ++i__) {
+	k = i__ << 1;
+	ii = i__ - *offset;
+/*        All intervals marked by '0' have been refined. */
+	if (iwork[k - 1] == 0) {
+	    w[ii] = (work[k - 1] + work[k]) * .5;
+	    werr[ii] = work[k] - w[ii];
+	}
+/* L110: */
+    }
+
+    return 0;
+
+/*     End of DLARRJ */
+
+} /* igraphdlarrj_ */
+
diff --git a/src/lapack/dlarrk.c b/src/lapack/dlarrk.c
new file mode 100644
index 0000000..bbad1fd
--- /dev/null
+++ b/src/lapack/dlarrk.c
@@ -0,0 +1,181 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarrk_(integer *n, integer *iw, doublereal *gl, 
+	doublereal *gu, doublereal *d__, doublereal *e2, doublereal *pivmin, 
+	doublereal *reltol, doublereal *w, doublereal *werr, integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double log(doublereal);
+
+    /* Local variables */
+    integer i__, it;
+    doublereal mid, eps, tmp1, tmp2, left, atoli, right;
+    integer itmax;
+    doublereal rtoli, tnorm;
+    extern doublereal igraphdlamch_(char *);
+    integer negcnt;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLARRK computes one eigenvalue of a symmetric tridiagonal   
+    matrix T to suitable accuracy. This is an auxiliary code to be   
+    called from DSTEMR.   
+
+    To avoid overflow, the matrix must be scaled so that its   
+    largest element is no greater than overflow**(1/2) *   
+    underflow**(1/4) in absolute value, and for greatest   
+    accuracy, it should not be much smaller than that.   
+
+    See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal   
+    Matrix", Report CS41, Computer Science Dept., Stanford   
+    University, July 21, 1966.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the tridiagonal matrix T.  N >= 0.   
+
+    IW      (input) INTEGER   
+            The index of the eigenvalues to be returned.   
+
+    GL      (input) DOUBLE PRECISION   
+    GU      (input) DOUBLE PRECISION   
+            An upper and a lower bound on the eigenvalue.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The n diagonal elements of the tridiagonal matrix T.   
+
+    E2      (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (n-1) squared off-diagonal elements of the tridiagonal matrix T.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot allowed in the Sturm sequence for T.   
+
+    RELTOL  (input) DOUBLE PRECISION   
+            The minimum relative width of an interval.  When an interval   
+            is narrower than RELTOL times the larger (in   
+            magnitude) endpoint, then it is considered to be   
+            sufficiently small, i.e., converged.  Note: this should   
+            always be at least radix*machine epsilon.   
+
+    W       (output) DOUBLE PRECISION   
+
+    WERR    (output) DOUBLE PRECISION   
+            The error bound on the corresponding eigenvalue approximation   
+            in W.   
+
+    INFO    (output) INTEGER   
+            = 0:       Eigenvalue converged   
+            = -1:      Eigenvalue did NOT converge   
+
+    Internal Parameters   
+    ===================   
+
+    FUDGE   DOUBLE PRECISION, default = 2   
+            A "fudge factor" to widen the Gershgorin intervals.   
+
+    =====================================================================   
+
+
+       Get machine constants   
+       Parameter adjustments */
+    --e2;
+    --d__;
+
+    /* Function Body */
+    eps = igraphdlamch_("P");
+/* Computing MAX */
+    d__1 = abs(*gl), d__2 = abs(*gu);
+    tnorm = max(d__1,d__2);
+    rtoli = *reltol;
+    atoli = *pivmin * 4.;
+    itmax = (integer) ((log(tnorm + *pivmin) - log(*pivmin)) / log(2.)) + 2;
+    *info = -1;
+    left = *gl - tnorm * 2. * eps * *n - *pivmin * 4.;
+    right = *gu + tnorm * 2. * eps * *n + *pivmin * 4.;
+    it = 0;
+L10:
+
+/*     Check if interval converged or maximum number of iterations reached */
+
+    tmp1 = (d__1 = right - left, abs(d__1));
+/* Computing MAX */
+    d__1 = abs(right), d__2 = abs(left);
+    tmp2 = max(d__1,d__2);
+/* Computing MAX */
+    d__1 = max(atoli,*pivmin), d__2 = rtoli * tmp2;
+    if (tmp1 < max(d__1,d__2)) {
+	*info = 0;
+	goto L30;
+    }
+    if (it > itmax) {
+	goto L30;
+    }
+
+/*     Count number of negative pivots for mid-point */
+
+    ++it;
+    mid = (left + right) * .5;
+    negcnt = 0;
+    tmp1 = d__[1] - mid;
+    if (abs(tmp1) < *pivmin) {
+	tmp1 = -(*pivmin);
+    }
+    if (tmp1 <= 0.) {
+	++negcnt;
+    }
+
+    i__1 = *n;
+    for (i__ = 2; i__ <= i__1; ++i__) {
+	tmp1 = d__[i__] - e2[i__ - 1] / tmp1 - mid;
+	if (abs(tmp1) < *pivmin) {
+	    tmp1 = -(*pivmin);
+	}
+	if (tmp1 <= 0.) {
+	    ++negcnt;
+	}
+/* L20: */
+    }
+    if (negcnt >= *iw) {
+	right = mid;
+    } else {
+	left = mid;
+    }
+    goto L10;
+L30:
+
+/*     Converged or maximum number of iterations reached */
+
+    *w = (left + right) * .5;
+    *werr = (d__1 = right - left, abs(d__1)) * .5;
+    return 0;
+
+/*     End of DLARRK */
+
+} /* igraphdlarrk_ */
+
diff --git a/src/lapack/dlarrr.c b/src/lapack/dlarrr.c
new file mode 100644
index 0000000..a159585
--- /dev/null
+++ b/src/lapack/dlarrr.c
@@ -0,0 +1,164 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlarrr_(integer *n, doublereal *d__, doublereal *e, 
+	integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal eps, tmp, tmp2, rmin;
+    extern doublereal igraphdlamch_(char *);
+    doublereal offdig, safmin;
+    logical yesrel;
+    doublereal smlnum, offdig2;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+
+    Purpose   
+    =======   
+
+    Perform tests to decide whether the symmetric tridiagonal matrix T   
+    warrants expensive computations which guarantee high relative accuracy   
+    in the eigenvalues.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix. N > 0.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The N diagonal elements of the tridiagonal matrix T.   
+
+    E       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the first (N-1) entries contain the subdiagonal   
+            elements of the tridiagonal matrix T; E(N) is set to ZERO.   
+
+    INFO    (output) INTEGER   
+            INFO = 0(default) : the matrix warrants computations preserving   
+                                relative accuracy.   
+            INFO = 1          : the matrix warrants computations guaranteeing   
+                                only absolute accuracy.   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       As a default, do NOT go for relative-accuracy preserving computations.   
+       Parameter adjustments */
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 1;
+    safmin = igraphdlamch_("Safe minimum");
+    eps = igraphdlamch_("Precision");
+    smlnum = safmin / eps;
+    rmin = sqrt(smlnum);
+/*     Tests for relative accuracy   
+
+       Test for scaled diagonal dominance   
+       Scale the diagonal entries to one and check whether the sum of the   
+       off-diagonals is less than one   
+
+       The sdd relative error bounds have a 1/(1- 2*x) factor in them,   
+       x = max(OFFDIG + OFFDIG2), so when x is close to 1/2, no relative   
+       accuracy is promised.  In the notation of the code fragment below,   
+       1/(1 - (OFFDIG + OFFDIG2)) is the condition number.   
+       We don't think it is worth going into "sdd mode" unless the relative   
+       condition number is reasonable, not 1/macheps.   
+       The threshold should be compatible with other thresholds used in the   
+       code. We set  OFFDIG + OFFDIG2 <= .999 =: RELCOND, it corresponds   
+       to losing at most 3 decimal digits: 1 / (1 - (OFFDIG + OFFDIG2)) <= 1000   
+       instead of the current OFFDIG + OFFDIG2 < 1 */
+
+    yesrel = TRUE_;
+    offdig = 0.;
+    tmp = sqrt((abs(d__[1])));
+    if (tmp < rmin) {
+	yesrel = FALSE_;
+    }
+    if (! yesrel) {
+	goto L11;
+    }
+    i__1 = *n;
+    for (i__ = 2; i__ <= i__1; ++i__) {
+	tmp2 = sqrt((d__1 = d__[i__], abs(d__1)));
+	if (tmp2 < rmin) {
+	    yesrel = FALSE_;
+	}
+	if (! yesrel) {
+	    goto L11;
+	}
+	offdig2 = (d__1 = e[i__ - 1], abs(d__1)) / (tmp * tmp2);
+	if (offdig + offdig2 >= .999) {
+	    yesrel = FALSE_;
+	}
+	if (! yesrel) {
+	    goto L11;
+	}
+	tmp = tmp2;
+	offdig = offdig2;
+/* L10: */
+    }
+L11:
+    if (yesrel) {
+	*info = 0;
+	return 0;
+    } else {
+    }
+
+
+/*     *** MORE TO BE IMPLEMENTED ***   
+
+
+       Test if the lower bidiagonal matrix L from T = L D L^T   
+       (zero shift facto) is well conditioned   
+
+
+       Test if the upper bidiagonal matrix U from T = U D U^T   
+       (zero shift facto) is well conditioned.   
+       In this case, the matrix needs to be flipped and, at the end   
+       of the eigenvector computation, the flip needs to be applied   
+       to the computed eigenvectors (and the support) */
+
+
+    return 0;
+
+/*     END OF DLARRR */
+
+} /* igraphdlarrr_ */
+
diff --git a/src/lapack/dlarrv.c b/src/lapack/dlarrv.c
new file mode 100644
index 0000000..d07b2cc
--- /dev/null
+++ b/src/lapack/dlarrv.c
@@ -0,0 +1,973 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b5 = 0.;
+static integer c__1 = 1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdlarrv_(integer *n, doublereal *vl, doublereal *vu, 
+	doublereal *d__, doublereal *l, doublereal *pivmin, integer *isplit, 
+	integer *m, integer *dol, integer *dou, doublereal *minrgp, 
+	doublereal *rtol1, doublereal *rtol2, doublereal *w, doublereal *werr,
+	 doublereal *wgap, integer *iblock, integer *indexw, doublereal *gers,
+	 doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, 
+	integer *iwork, integer *info)
+{
+    /* System generated locals */
+    integer z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5;
+    doublereal d__1, d__2;
+    logical L__1;
+
+    /* Builtin functions */
+    double log(doublereal);
+
+    /* Local variables */
+    integer minwsize, i__, j, k, p, q, miniwsize, ii;
+    doublereal gl;
+    integer im, in;
+    doublereal gu, gap, eps, tau, tol, tmp;
+    integer zto;
+    doublereal ztz;
+    integer iend, jblk;
+    doublereal lgap;
+    integer done;
+    doublereal rgap, left;
+    integer wend, iter;
+    doublereal bstw;
+    integer itmp1;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    integer indld;
+    doublereal fudge;
+    integer idone;
+    doublereal sigma;
+    integer iinfo, iindr;
+    doublereal resid;
+    logical eskip;
+    doublereal right;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    integer nclus, zfrom;
+    doublereal rqtol;
+    integer iindc1, iindc2;
+    extern /* Subroutine */ int igraphdlar1v_(integer *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, logical *,
+	     integer *, doublereal *, doublereal *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *);
+    logical stp2ii;
+    doublereal lambda;
+    extern doublereal igraphdlamch_(char *);
+    integer ibegin, indeig;
+    logical needbs;
+    integer indlld;
+    doublereal sgndef, mingma;
+    extern /* Subroutine */ int igraphdlarrb_(integer *, doublereal *, doublereal *,
+	     integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, integer *,
+	     doublereal *, doublereal *, integer *, integer *);
+    integer oldien, oldncl, wbegin;
+    doublereal spdiam;
+    integer negcnt;
+    extern /* Subroutine */ int igraphdlarrf_(integer *, doublereal *, doublereal *,
+	     doublereal *, integer *, integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, integer *);
+    integer oldcls;
+    doublereal savgap;
+    integer ndepth;
+    doublereal ssigma;
+    extern /* Subroutine */ int igraphdlaset_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *);
+    logical usedbs;
+    integer iindwk, offset;
+    doublereal gaptol;
+    integer newcls, oldfst, indwrk, windex, oldlst;
+    logical usedrq;
+    integer newfst, newftt, parity, windmn, windpl, isupmn, newlst, zusedl;
+    doublereal bstres;
+    integer newsiz, zusedu, zusedw;
+    doublereal nrminv, rqcorr;
+    logical tryrqc;
+    integer isupmx;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLARRV computes the eigenvectors of the tridiagonal matrix   
+    T = L D L**T given L, D and APPROXIMATIONS to the eigenvalues of L D L**T.   
+    The input eigenvalues should have been computed by DLARRE.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix.  N >= 0.   
+
+    VL      (input) DOUBLE PRECISION   
+    VU      (input) DOUBLE PRECISION   
+            Lower and upper bounds of the interval that contains the desired   
+            eigenvalues. VL < VU. Needed to compute gaps on the left or right   
+            end of the extremal eigenvalues in the desired RANGE.   
+
+    D       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the N diagonal elements of the diagonal matrix D.   
+            On exit, D may be overwritten.   
+
+    L       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the (N-1) subdiagonal elements of the unit   
+            bidiagonal matrix L are in elements 1 to N-1 of L   
+            (if the matrix is not splitted.) At the end of each block   
+            is stored the corresponding shift as given by DLARRE.   
+            On exit, L is overwritten.   
+
+    PIVMIN  (input) DOUBLE PRECISION   
+            The minimum pivot allowed in the Sturm sequence.   
+
+    ISPLIT  (input) INTEGER array, dimension (N)   
+            The splitting points, at which T breaks up into blocks.   
+            The first block consists of rows/columns 1 to   
+            ISPLIT( 1 ), the second of rows/columns ISPLIT( 1 )+1   
+            through ISPLIT( 2 ), etc.   
+
+    M       (input) INTEGER   
+            The total number of input eigenvalues.  0 <= M <= N.   
+
+    DOL     (input) INTEGER   
+    DOU     (input) INTEGER   
+            If the user wants to compute only selected eigenvectors from all   
+            the eigenvalues supplied, he can specify an index range DOL:DOU.   
+            Or else the setting DOL=1, DOU=M should be applied.   
+            Note that DOL and DOU refer to the order in which the eigenvalues   
+            are stored in W.   
+            If the user wants to compute only selected eigenpairs, then   
+            the columns DOL-1 to DOU+1 of the eigenvector space Z contain the   
+            computed eigenvectors. All other columns of Z are set to zero.   
+
+    MINRGP  (input) DOUBLE PRECISION   
+
+    RTOL1   (input) DOUBLE PRECISION   
+    RTOL2   (input) DOUBLE PRECISION   
+             Parameters for bisection.   
+             An interval [LEFT,RIGHT] has converged if   
+             RIGHT-LEFT.LT.MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) )   
+
+    W       (input/output) DOUBLE PRECISION array, dimension (N)   
+            The first M elements of W contain the APPROXIMATE eigenvalues for   
+            which eigenvectors are to be computed.  The eigenvalues   
+            should be grouped by split-off block and ordered from   
+            smallest to largest within the block ( The output array   
+            W from DLARRE is expected here ). Furthermore, they are with   
+            respect to the shift of the corresponding root representation   
+            for their block. On exit, W holds the eigenvalues of the   
+            UNshifted matrix.   
+
+    WERR    (input/output) DOUBLE PRECISION array, dimension (N)   
+            The first M elements contain the semiwidth of the uncertainty   
+            interval of the corresponding eigenvalue in W   
+
+    WGAP    (input/output) DOUBLE PRECISION array, dimension (N)   
+            The separation from the right neighbor eigenvalue in W.   
+
+    IBLOCK  (input) INTEGER array, dimension (N)   
+            The indices of the blocks (submatrices) associated with the   
+            corresponding eigenvalues in W; IBLOCK(i)=1 if eigenvalue   
+            W(i) belongs to the first block from the top, =2 if W(i)   
+            belongs to the second block, etc.   
+
+    INDEXW  (input) INTEGER array, dimension (N)   
+            The indices of the eigenvalues within each block (submatrix);   
+            for example, INDEXW(i)= 10 and IBLOCK(i)=2 imply that the   
+            i-th eigenvalue W(i) is the 10-th eigenvalue in the second block.   
+
+    GERS    (input) DOUBLE PRECISION array, dimension (2*N)   
+            The N Gerschgorin intervals (the i-th Gerschgorin interval   
+            is (GERS(2*i-1), GERS(2*i)). The Gerschgorin intervals should   
+            be computed from the original UNshifted matrix.   
+
+    Z       (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M) )   
+            If INFO = 0, the first M columns of Z contain the   
+            orthonormal eigenvectors of the matrix T   
+            corresponding to the input eigenvalues, with the i-th   
+            column of Z holding the eigenvector associated with W(i).   
+            Note: the user must ensure that at least max(1,M) columns are   
+            supplied in the array Z.   
+
+    LDZ     (input) INTEGER   
+            The leading dimension of the array Z.  LDZ >= 1, and if   
+            JOBZ = 'V', LDZ >= max(1,N).   
+
+    ISUPPZ  (output) INTEGER array, dimension ( 2*max(1,M) )   
+            The support of the eigenvectors in Z, i.e., the indices   
+            indicating the nonzero elements in Z. The I-th eigenvector   
+            is nonzero only in elements ISUPPZ( 2*I-1 ) through   
+            ISUPPZ( 2*I ).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (12*N)   
+
+    IWORK   (workspace) INTEGER array, dimension (7*N)   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+
+            > 0:  A problem occured in DLARRV.   
+            < 0:  One of the called subroutines signaled an internal problem.   
+                  Needs inspection of the corresponding parameter IINFO   
+                  for further information.   
+
+            =-1:  Problem in DLARRB when refining a child's eigenvalues.   
+            =-2:  Problem in DLARRF when computing the RRR of a child.   
+                  When a child is inside a tight cluster, it can be difficult   
+                  to find an RRR. A partial remedy from the user's point of   
+                  view is to make the parameter MINRGP smaller and recompile.   
+                  However, as the orthogonality of the computed vectors is   
+                  proportional to 1/MINRGP, the user should be aware that   
+                  he might be trading in precision when he decreases MINRGP.   
+            =-3:  Problem in DLARRB when refining a single eigenvalue   
+                  after the Rayleigh correction was rejected.   
+            = 5:  The Rayleigh Quotient Iteration failed to converge to   
+                  full accuracy in MAXITR steps.   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+       The first N entries of WORK are reserved for the eigenvalues   
+       Parameter adjustments */
+    --d__;
+    --l;
+    --isplit;
+    --w;
+    --werr;
+    --wgap;
+    --iblock;
+    --indexw;
+    --gers;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --isuppz;
+    --work;
+    --iwork;
+
+    /* Function Body */
+    indld = *n + 1;
+    indlld = (*n << 1) + 1;
+    indwrk = *n * 3 + 1;
+    minwsize = *n * 12;
+    i__1 = minwsize;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	work[i__] = 0.;
+/* L5: */
+    }
+/*     IWORK(IINDR+1:IINDR+N) hold the twist indices R for the   
+       factorization used to compute the FP vector */
+    iindr = 0;
+/*     IWORK(IINDC1+1:IINC2+N) are used to store the clusters of the current   
+       layer and the one above. */
+    iindc1 = *n;
+    iindc2 = *n << 1;
+    iindwk = *n * 3 + 1;
+    miniwsize = *n * 7;
+    i__1 = miniwsize;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	iwork[i__] = 0;
+/* L10: */
+    }
+    zusedl = 1;
+    if (*dol > 1) {
+/*        Set lower bound for use of Z */
+	zusedl = *dol - 1;
+    }
+    zusedu = *m;
+    if (*dou < *m) {
+/*        Set lower bound for use of Z */
+	zusedu = *dou + 1;
+    }
+/*     The width of the part of Z that is used */
+    zusedw = zusedu - zusedl + 1;
+    igraphdlaset_("Full", n, &zusedw, &c_b5, &c_b5, &z__[zusedl * z_dim1 + 1], ldz);
+    eps = igraphdlamch_("Precision");
+    rqtol = eps * 2.;
+
+/*     Set expert flags for standard code. */
+    tryrqc = TRUE_;
+    if (*dol == 1 && *dou == *m) {
+    } else {
+/*        Only selected eigenpairs are computed. Since the other evalues   
+          are not refined by RQ iteration, bisection has to compute to full   
+          accuracy. */
+	*rtol1 = eps * 4.;
+	*rtol2 = eps * 4.;
+    }
+/*     The entries WBEGIN:WEND in W, WERR, WGAP correspond to the   
+       desired eigenvalues. The support of the nonzero eigenvector   
+       entries is contained in the interval IBEGIN:IEND.   
+       Remark that if k eigenpairs are desired, then the eigenvectors   
+       are stored in k contiguous columns of Z.   
+       DONE is the number of eigenvectors already computed */
+    done = 0;
+    ibegin = 1;
+    wbegin = 1;
+    i__1 = iblock[*m];
+    for (jblk = 1; jblk <= i__1; ++jblk) {
+	iend = isplit[jblk];
+	sigma = l[iend];
+/*        Find the eigenvectors of the submatrix indexed IBEGIN   
+          through IEND. */
+	wend = wbegin - 1;
+L15:
+	if (wend < *m) {
+	    if (iblock[wend + 1] == jblk) {
+		++wend;
+		goto L15;
+	    }
+	}
+	if (wend < wbegin) {
+	    ibegin = iend + 1;
+	    goto L170;
+	} else if (wend < *dol || wbegin > *dou) {
+	    ibegin = iend + 1;
+	    wbegin = wend + 1;
+	    goto L170;
+	}
+/*        Find local spectral diameter of the block */
+	gl = gers[(ibegin << 1) - 1];
+	gu = gers[ibegin * 2];
+	i__2 = iend;
+	for (i__ = ibegin + 1; i__ <= i__2; ++i__) {
+/* Computing MIN */
+	    d__1 = gers[(i__ << 1) - 1];
+	    gl = min(d__1,gl);
+/* Computing MAX */
+	    d__1 = gers[i__ * 2];
+	    gu = max(d__1,gu);
+/* L20: */
+	}
+	spdiam = gu - gl;
+/*        OLDIEN is the last index of the previous block */
+	oldien = ibegin - 1;
+/*        Calculate the size of the current block */
+	in = iend - ibegin + 1;
+/*        The number of eigenvalues in the current block */
+	im = wend - wbegin + 1;
+/*        This is for a 1x1 block */
+	if (ibegin == iend) {
+	    ++done;
+	    z__[ibegin + wbegin * z_dim1] = 1.;
+	    isuppz[(wbegin << 1) - 1] = ibegin;
+	    isuppz[wbegin * 2] = ibegin;
+	    w[wbegin] += sigma;
+	    work[wbegin] = w[wbegin];
+	    ibegin = iend + 1;
+	    ++wbegin;
+	    goto L170;
+	}
+/*        The desired (shifted) eigenvalues are stored in W(WBEGIN:WEND)   
+          Note that these can be approximations, in this case, the corresp.   
+          entries of WERR give the size of the uncertainty interval.   
+          The eigenvalue approximations will be refined when necessary as   
+          high relative accuracy is required for the computation of the   
+          corresponding eigenvectors. */
+	igraphdcopy_(&im, &w[wbegin], &c__1, &work[wbegin], &c__1);
+/*        We store in W the eigenvalue approximations w.r.t. the original   
+          matrix T. */
+	i__2 = im;
+	for (i__ = 1; i__ <= i__2; ++i__) {
+	    w[wbegin + i__ - 1] += sigma;
+/* L30: */
+	}
+/*        NDEPTH is the current depth of the representation tree */
+	ndepth = 0;
+/*        PARITY is either 1 or 0 */
+	parity = 1;
+/*        NCLUS is the number of clusters for the next level of the   
+          representation tree, we start with NCLUS = 1 for the root */
+	nclus = 1;
+	iwork[iindc1 + 1] = 1;
+	iwork[iindc1 + 2] = im;
+/*        IDONE is the number of eigenvectors already computed in the current   
+          block */
+	idone = 0;
+/*        loop while( IDONE.LT.IM )   
+          generate the representation tree for the current block and   
+          compute the eigenvectors */
+L40:
+	if (idone < im) {
+/*           This is a crude protection against infinitely deep trees */
+	    if (ndepth > *m) {
+		*info = -2;
+		return 0;
+	    }
+/*           breadth first processing of the current level of the representation   
+             tree: OLDNCL = number of clusters on current level */
+	    oldncl = nclus;
+/*           reset NCLUS to count the number of child clusters */
+	    nclus = 0;
+
+	    parity = 1 - parity;
+	    if (parity == 0) {
+		oldcls = iindc1;
+		newcls = iindc2;
+	    } else {
+		oldcls = iindc2;
+		newcls = iindc1;
+	    }
+/*           Process the clusters on the current level */
+	    i__2 = oldncl;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		j = oldcls + (i__ << 1);
+/*              OLDFST, OLDLST = first, last index of current cluster.   
+                                 cluster indices start with 1 and are relative   
+                                 to WBEGIN when accessing W, WGAP, WERR, Z */
+		oldfst = iwork[j - 1];
+		oldlst = iwork[j];
+		if (ndepth > 0) {
+/*                 Retrieve relatively robust representation (RRR) of cluster   
+                   that has been computed at the previous level   
+                   The RRR is stored in Z and overwritten once the eigenvectors   
+                   have been computed or when the cluster is refined */
+		    if (*dol == 1 && *dou == *m) {
+/*                    Get representation from location of the leftmost evalue   
+                      of the cluster */
+			j = wbegin + oldfst - 1;
+		    } else {
+			if (wbegin + oldfst - 1 < *dol) {
+/*                       Get representation from the left end of Z array */
+			    j = *dol - 1;
+			} else if (wbegin + oldfst - 1 > *dou) {
+/*                       Get representation from the right end of Z array */
+			    j = *dou;
+			} else {
+			    j = wbegin + oldfst - 1;
+			}
+		    }
+		    igraphdcopy_(&in, &z__[ibegin + j * z_dim1], &c__1, &d__[ibegin]
+			    , &c__1);
+		    i__3 = in - 1;
+		    igraphdcopy_(&i__3, &z__[ibegin + (j + 1) * z_dim1], &c__1, &l[
+			    ibegin], &c__1);
+		    sigma = z__[iend + (j + 1) * z_dim1];
+/*                 Set the corresponding entries in Z to zero */
+		    igraphdlaset_("Full", &in, &c__2, &c_b5, &c_b5, &z__[ibegin + j 
+			    * z_dim1], ldz);
+		}
+/*              Compute DL and DLL of current RRR */
+		i__3 = iend - 1;
+		for (j = ibegin; j <= i__3; ++j) {
+		    tmp = d__[j] * l[j];
+		    work[indld - 1 + j] = tmp;
+		    work[indlld - 1 + j] = tmp * l[j];
+/* L50: */
+		}
+		if (ndepth > 0) {
+/*                 P and Q are index of the first and last eigenvalue to compute   
+                   within the current block */
+		    p = indexw[wbegin - 1 + oldfst];
+		    q = indexw[wbegin - 1 + oldlst];
+/*                 Offset for the arrays WORK, WGAP and WERR, i.e., the P-OFFSET   
+                   through the Q-OFFSET elements of these arrays are to be used.   
+                    OFFSET = P-OLDFST */
+		    offset = indexw[wbegin] - 1;
+/*                 perform limited bisection (if necessary) to get approximate   
+                   eigenvalues to the precision needed. */
+		    igraphdlarrb_(&in, &d__[ibegin], &work[indlld + ibegin - 1], &p,
+			     &q, rtol1, rtol2, &offset, &work[wbegin], &wgap[
+			    wbegin], &werr[wbegin], &work[indwrk], &iwork[
+			    iindwk], pivmin, &spdiam, &in, &iinfo);
+		    if (iinfo != 0) {
+			*info = -1;
+			return 0;
+		    }
+/*                 We also recompute the extremal gaps. W holds all eigenvalues   
+                   of the unshifted matrix and must be used for computation   
+                   of WGAP, the entries of WORK might stem from RRRs with   
+                   different shifts. The gaps from WBEGIN-1+OLDFST to   
+                   WBEGIN-1+OLDLST are correctly computed in DLARRB.   
+                   However, we only allow the gaps to become greater since   
+                   this is what should happen when we decrease WERR */
+		    if (oldfst > 1) {
+/* Computing MAX */
+			d__1 = wgap[wbegin + oldfst - 2], d__2 = w[wbegin + 
+				oldfst - 1] - werr[wbegin + oldfst - 1] - w[
+				wbegin + oldfst - 2] - werr[wbegin + oldfst - 
+				2];
+			wgap[wbegin + oldfst - 2] = max(d__1,d__2);
+		    }
+		    if (wbegin + oldlst - 1 < wend) {
+/* Computing MAX */
+			d__1 = wgap[wbegin + oldlst - 1], d__2 = w[wbegin + 
+				oldlst] - werr[wbegin + oldlst] - w[wbegin + 
+				oldlst - 1] - werr[wbegin + oldlst - 1];
+			wgap[wbegin + oldlst - 1] = max(d__1,d__2);
+		    }
+/*                 Each time the eigenvalues in WORK get refined, we store   
+                   the newly found approximation with all shifts applied in W */
+		    i__3 = oldlst;
+		    for (j = oldfst; j <= i__3; ++j) {
+			w[wbegin + j - 1] = work[wbegin + j - 1] + sigma;
+/* L53: */
+		    }
+		}
+/*              Process the current node. */
+		newfst = oldfst;
+		i__3 = oldlst;
+		for (j = oldfst; j <= i__3; ++j) {
+		    if (j == oldlst) {
+/*                    we are at the right end of the cluster, this is also the   
+                      boundary of the child cluster */
+			newlst = j;
+		    } else if (wgap[wbegin + j - 1] >= *minrgp * (d__1 = work[
+			    wbegin + j - 1], abs(d__1))) {
+/*                    the right relative gap is big enough, the child cluster   
+                      (NEWFST,..,NEWLST) is well separated from the following */
+			newlst = j;
+		    } else {
+/*                    inside a child cluster, the relative gap is not   
+                      big enough. */
+			goto L140;
+		    }
+/*                 Compute size of child cluster found */
+		    newsiz = newlst - newfst + 1;
+/*                 NEWFTT is the place in Z where the new RRR or the computed   
+                   eigenvector is to be stored */
+		    if (*dol == 1 && *dou == *m) {
+/*                    Store representation at location of the leftmost evalue   
+                      of the cluster */
+			newftt = wbegin + newfst - 1;
+		    } else {
+			if (wbegin + newfst - 1 < *dol) {
+/*                       Store representation at the left end of Z array */
+			    newftt = *dol - 1;
+			} else if (wbegin + newfst - 1 > *dou) {
+/*                       Store representation at the right end of Z array */
+			    newftt = *dou;
+			} else {
+			    newftt = wbegin + newfst - 1;
+			}
+		    }
+		    if (newsiz > 1) {
+
+/*                    Current child is not a singleton but a cluster.   
+                      Compute and store new representation of child.   
+
+
+                      Compute left and right cluster gap.   
+
+                      LGAP and RGAP are not computed from WORK because   
+                      the eigenvalue approximations may stem from RRRs   
+                      different shifts. However, W hold all eigenvalues   
+                      of the unshifted matrix. Still, the entries in WGAP   
+                      have to be computed from WORK since the entries   
+                      in W might be of the same order so that gaps are not   
+                      exhibited correctly for very close eigenvalues. */
+			if (newfst == 1) {
+/* Computing MAX */
+			    d__1 = 0., d__2 = w[wbegin] - werr[wbegin] - *vl;
+			    lgap = max(d__1,d__2);
+			} else {
+			    lgap = wgap[wbegin + newfst - 2];
+			}
+			rgap = wgap[wbegin + newlst - 1];
+
+/*                    Compute left- and rightmost eigenvalue of child   
+                      to high precision in order to shift as close   
+                      as possible and obtain as large relative gaps   
+                      as possible */
+
+			for (k = 1; k <= 2; ++k) {
+			    if (k == 1) {
+				p = indexw[wbegin - 1 + newfst];
+			    } else {
+				p = indexw[wbegin - 1 + newlst];
+			    }
+			    offset = indexw[wbegin] - 1;
+			    igraphdlarrb_(&in, &d__[ibegin], &work[indlld + ibegin 
+				    - 1], &p, &p, &rqtol, &rqtol, &offset, &
+				    work[wbegin], &wgap[wbegin], &werr[wbegin]
+				    , &work[indwrk], &iwork[iindwk], pivmin, &
+				    spdiam, &in, &iinfo);
+/* L55: */
+			}
+
+			if (wbegin + newlst - 1 < *dol || wbegin + newfst - 1 
+				> *dou) {
+/*                       if the cluster contains no desired eigenvalues   
+                         skip the computation of that branch of the rep. tree   
+
+                         We could skip before the refinement of the extremal   
+                         eigenvalues of the child, but then the representation   
+                         tree could be different from the one when nothing is   
+                         skipped. For this reason we skip at this place. */
+			    idone = idone + newlst - newfst + 1;
+			    goto L139;
+			}
+
+/*                    Compute RRR of child cluster.   
+                      Note that the new RRR is stored in Z   
+
+                      DLARRF needs LWORK = 2*N */
+			igraphdlarrf_(&in, &d__[ibegin], &l[ibegin], &work[indld + 
+				ibegin - 1], &newfst, &newlst, &work[wbegin], 
+				&wgap[wbegin], &werr[wbegin], &spdiam, &lgap, 
+				&rgap, pivmin, &tau, &z__[ibegin + newftt * 
+				z_dim1], &z__[ibegin + (newftt + 1) * z_dim1],
+				 &work[indwrk], &iinfo);
+			if (iinfo == 0) {
+/*                       a new RRR for the cluster was found by DLARRF   
+                         update shift and store it */
+			    ssigma = sigma + tau;
+			    z__[iend + (newftt + 1) * z_dim1] = ssigma;
+/*                       WORK() are the midpoints and WERR() the semi-width   
+                         Note that the entries in W are unchanged. */
+			    i__4 = newlst;
+			    for (k = newfst; k <= i__4; ++k) {
+				fudge = eps * 3. * (d__1 = work[wbegin + k - 
+					1], abs(d__1));
+				work[wbegin + k - 1] -= tau;
+				fudge += eps * 4. * (d__1 = work[wbegin + k - 
+					1], abs(d__1));
+/*                          Fudge errors */
+				werr[wbegin + k - 1] += fudge;
+/*                          Gaps are not fudged. Provided that WERR is small   
+                            when eigenvalues are close, a zero gap indicates   
+                            that a new representation is needed for resolving   
+                            the cluster. A fudge could lead to a wrong decision   
+                            of judging eigenvalues 'separated' which in   
+                            reality are not. This could have a negative impact   
+                            on the orthogonality of the computed eigenvectors.   
+   L116: */
+			    }
+			    ++nclus;
+			    k = newcls + (nclus << 1);
+			    iwork[k - 1] = newfst;
+			    iwork[k] = newlst;
+			} else {
+			    *info = -2;
+			    return 0;
+			}
+		    } else {
+
+/*                    Compute eigenvector of singleton */
+
+			iter = 0;
+
+			tol = log((doublereal) in) * 4. * eps;
+
+			k = newfst;
+			windex = wbegin + k - 1;
+/* Computing MAX */
+			i__4 = windex - 1;
+			windmn = max(i__4,1);
+/* Computing MIN */
+			i__4 = windex + 1;
+			windpl = min(i__4,*m);
+			lambda = work[windex];
+			++done;
+/*                    Check if eigenvector computation is to be skipped */
+			if (windex < *dol || windex > *dou) {
+			    eskip = TRUE_;
+			    goto L125;
+			} else {
+			    eskip = FALSE_;
+			}
+			left = work[windex] - werr[windex];
+			right = work[windex] + werr[windex];
+			indeig = indexw[windex];
+/*                    Note that since we compute the eigenpairs for a child,   
+                      all eigenvalue approximations are w.r.t the same shift.   
+                      In this case, the entries in WORK should be used for   
+                      computing the gaps since they exhibit even very small   
+                      differences in the eigenvalues, as opposed to the   
+                      entries in W which might "look" the same. */
+			if (k == 1) {
+/*                       In the case RANGE='I' and with not much initial   
+                         accuracy in LAMBDA and VL, the formula   
+                         LGAP = MAX( ZERO, (SIGMA - VL) + LAMBDA )   
+                         can lead to an overestimation of the left gap and   
+                         thus to inadequately early RQI 'convergence'.   
+                         Prevent this by forcing a small left gap.   
+   Computing MAX */
+			    d__1 = abs(left), d__2 = abs(right);
+			    lgap = eps * max(d__1,d__2);
+			} else {
+			    lgap = wgap[windmn];
+			}
+			if (k == im) {
+/*                       In the case RANGE='I' and with not much initial   
+                         accuracy in LAMBDA and VU, the formula   
+                         can lead to an overestimation of the right gap and   
+                         thus to inadequately early RQI 'convergence'.   
+                         Prevent this by forcing a small right gap.   
+   Computing MAX */
+			    d__1 = abs(left), d__2 = abs(right);
+			    rgap = eps * max(d__1,d__2);
+			} else {
+			    rgap = wgap[windex];
+			}
+			gap = min(lgap,rgap);
+			if (k == 1 || k == im) {
+/*                       The eigenvector support can become wrong   
+                         because significant entries could be cut off due to a   
+                         large GAPTOL parameter in LAR1V. Prevent this. */
+			    gaptol = 0.;
+			} else {
+			    gaptol = gap * eps;
+			}
+			isupmn = in;
+			isupmx = 1;
+/*                    Update WGAP so that it holds the minimum gap   
+                      to the left or the right. This is crucial in the   
+                      case where bisection is used to ensure that the   
+                      eigenvalue is refined up to the required precision.   
+                      The correct value is restored afterwards. */
+			savgap = wgap[windex];
+			wgap[windex] = gap;
+/*                    We want to use the Rayleigh Quotient Correction   
+                      as often as possible since it converges quadratically   
+                      when we are close enough to the desired eigenvalue.   
+                      However, the Rayleigh Quotient can have the wrong sign   
+                      and lead us away from the desired eigenvalue. In this   
+                      case, the best we can do is to use bisection. */
+			usedbs = FALSE_;
+			usedrq = FALSE_;
+/*                    Bisection is initially turned off unless it is forced */
+			needbs = ! tryrqc;
+L120:
+/*                    Check if bisection should be used to refine eigenvalue */
+			if (needbs) {
+/*                       Take the bisection as new iterate */
+			    usedbs = TRUE_;
+			    itmp1 = iwork[iindr + windex];
+			    offset = indexw[wbegin] - 1;
+			    d__1 = eps * 2.;
+			    igraphdlarrb_(&in, &d__[ibegin], &work[indlld + ibegin 
+				    - 1], &indeig, &indeig, &c_b5, &d__1, &
+				    offset, &work[wbegin], &wgap[wbegin], &
+				    werr[wbegin], &work[indwrk], &iwork[
+				    iindwk], pivmin, &spdiam, &itmp1, &iinfo);
+			    if (iinfo != 0) {
+				*info = -3;
+				return 0;
+			    }
+			    lambda = work[windex];
+/*                       Reset twist index from inaccurate LAMBDA to   
+                         force computation of true MINGMA */
+			    iwork[iindr + windex] = 0;
+			}
+/*                    Given LAMBDA, compute the eigenvector. */
+			L__1 = ! usedbs;
+			igraphdlar1v_(&in, &c__1, &in, &lambda, &d__[ibegin], &l[
+				ibegin], &work[indld + ibegin - 1], &work[
+				indlld + ibegin - 1], pivmin, &gaptol, &z__[
+				ibegin + windex * z_dim1], &L__1, &negcnt, &
+				ztz, &mingma, &iwork[iindr + windex], &isuppz[
+				(windex << 1) - 1], &nrminv, &resid, &rqcorr, 
+				&work[indwrk]);
+			if (iter == 0) {
+			    bstres = resid;
+			    bstw = lambda;
+			} else if (resid < bstres) {
+			    bstres = resid;
+			    bstw = lambda;
+			}
+/* Computing MIN */
+			i__4 = isupmn, i__5 = isuppz[(windex << 1) - 1];
+			isupmn = min(i__4,i__5);
+/* Computing MAX */
+			i__4 = isupmx, i__5 = isuppz[windex * 2];
+			isupmx = max(i__4,i__5);
+			++iter;
+/*                    sin alpha <= |resid|/gap   
+                      Note that both the residual and the gap are   
+                      proportional to the matrix, so ||T|| doesn't play   
+                      a role in the quotient   
+
+                      Convergence test for Rayleigh-Quotient iteration   
+                      (omitted when Bisection has been used) */
+
+			if (resid > tol * gap && abs(rqcorr) > rqtol * abs(
+				lambda) && ! usedbs) {
+/*                       We need to check that the RQCORR update doesn't   
+                         move the eigenvalue away from the desired one and   
+                         towards a neighbor. -> protection with bisection */
+			    if (indeig <= negcnt) {
+/*                          The wanted eigenvalue lies to the left */
+				sgndef = -1.;
+			    } else {
+/*                          The wanted eigenvalue lies to the right */
+				sgndef = 1.;
+			    }
+/*                       We only use the RQCORR if it improves the   
+                         the iterate reasonably. */
+			    if (rqcorr * sgndef >= 0. && lambda + rqcorr <= 
+				    right && lambda + rqcorr >= left) {
+				usedrq = TRUE_;
+/*                          Store new midpoint of bisection interval in WORK */
+				if (sgndef == 1.) {
+/*                             The current LAMBDA is on the left of the true   
+                               eigenvalue */
+				    left = lambda;
+/*                             We prefer to assume that the error estimate   
+                               is correct. We could make the interval not   
+                               as a bracket but to be modified if the RQCORR   
+                               chooses to. In this case, the RIGHT side should   
+                               be modified as follows:   
+                                RIGHT = MAX(RIGHT, LAMBDA + RQCORR) */
+				} else {
+/*                             The current LAMBDA is on the right of the true   
+                               eigenvalue */
+				    right = lambda;
+/*                             See comment about assuming the error estimate is   
+                               correct above.   
+                                LEFT = MIN(LEFT, LAMBDA + RQCORR) */
+				}
+				work[windex] = (right + left) * .5;
+/*                          Take RQCORR since it has the correct sign and   
+                            improves the iterate reasonably */
+				lambda += rqcorr;
+/*                          Update width of error interval */
+				werr[windex] = (right - left) * .5;
+			    } else {
+				needbs = TRUE_;
+			    }
+			    if (right - left < rqtol * abs(lambda)) {
+/*                             The eigenvalue is computed to bisection accuracy   
+                               compute eigenvector and stop */
+				usedbs = TRUE_;
+				goto L120;
+			    } else if (iter < 10) {
+				goto L120;
+			    } else if (iter == 10) {
+				needbs = TRUE_;
+				goto L120;
+			    } else {
+				*info = 5;
+				return 0;
+			    }
+			} else {
+			    stp2ii = FALSE_;
+			    if (usedrq && usedbs && bstres <= resid) {
+				lambda = bstw;
+				stp2ii = TRUE_;
+			    }
+			    if (stp2ii) {
+/*                          improve error angle by second step */
+				L__1 = ! usedbs;
+				igraphdlar1v_(&in, &c__1, &in, &lambda, &d__[ibegin]
+					, &l[ibegin], &work[indld + ibegin - 
+					1], &work[indlld + ibegin - 1], 
+					pivmin, &gaptol, &z__[ibegin + windex 
+					* z_dim1], &L__1, &negcnt, &ztz, &
+					mingma, &iwork[iindr + windex], &
+					isuppz[(windex << 1) - 1], &nrminv, &
+					resid, &rqcorr, &work[indwrk]);
+			    }
+			    work[windex] = lambda;
+			}
+
+/*                    Compute FP-vector support w.r.t. whole matrix */
+
+			isuppz[(windex << 1) - 1] += oldien;
+			isuppz[windex * 2] += oldien;
+			zfrom = isuppz[(windex << 1) - 1];
+			zto = isuppz[windex * 2];
+			isupmn += oldien;
+			isupmx += oldien;
+/*                    Ensure vector is ok if support in the RQI has changed */
+			if (isupmn < zfrom) {
+			    i__4 = zfrom - 1;
+			    for (ii = isupmn; ii <= i__4; ++ii) {
+				z__[ii + windex * z_dim1] = 0.;
+/* L122: */
+			    }
+			}
+			if (isupmx > zto) {
+			    i__4 = isupmx;
+			    for (ii = zto + 1; ii <= i__4; ++ii) {
+				z__[ii + windex * z_dim1] = 0.;
+/* L123: */
+			    }
+			}
+			i__4 = zto - zfrom + 1;
+			igraphdscal_(&i__4, &nrminv, &z__[zfrom + windex * z_dim1], 
+				&c__1);
+L125:
+/*                    Update W */
+			w[windex] = lambda + sigma;
+/*                    Recompute the gaps on the left and right   
+                      But only allow them to become larger and not   
+                      smaller (which can only happen through "bad"   
+                      cancellation and doesn't reflect the theory   
+                      where the initial gaps are underestimated due   
+                      to WERR being too crude.) */
+			if (! eskip) {
+			    if (k > 1) {
+/* Computing MAX */
+				d__1 = wgap[windmn], d__2 = w[windex] - werr[
+					windex] - w[windmn] - werr[windmn];
+				wgap[windmn] = max(d__1,d__2);
+			    }
+			    if (windex < wend) {
+/* Computing MAX */
+				d__1 = savgap, d__2 = w[windpl] - werr[windpl]
+					 - w[windex] - werr[windex];
+				wgap[windex] = max(d__1,d__2);
+			    }
+			}
+			++idone;
+		    }
+/*                 here ends the code for the current child */
+
+L139:
+/*                 Proceed to any remaining child nodes */
+		    newfst = j + 1;
+L140:
+		    ;
+		}
+/* L150: */
+	    }
+	    ++ndepth;
+	    goto L40;
+	}
+	ibegin = iend + 1;
+	wbegin = wend + 1;
+L170:
+	;
+    }
+
+    return 0;
+
+/*     End of DLARRV */
+
+} /* igraphdlarrv_ */
+
diff --git a/src/lapack/dlartg.c b/src/lapack/dlartg.c
new file mode 100644
index 0000000..3a2c24b
--- /dev/null
+++ b/src/lapack/dlartg.c
@@ -0,0 +1,176 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlartg_(doublereal *f, doublereal *g, doublereal *cs, 
+	doublereal *sn, doublereal *r__)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double log(doublereal), pow_di(doublereal *, integer *), sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    doublereal f1, g1, eps, scale;
+    integer count;
+    doublereal safmn2, safmx2;
+    extern doublereal igraphdlamch_(char *);
+    doublereal safmin;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLARTG generate a plane rotation so that   
+
+       [  CS  SN  ]  .  [ F ]  =  [ R ]   where CS**2 + SN**2 = 1.   
+       [ -SN  CS  ]     [ G ]     [ 0 ]   
+
+    This is a slower, more accurate version of the BLAS1 routine DROTG,   
+    with the following other differences:   
+       F and G are unchanged on return.   
+       If G=0, then CS=1 and SN=0.   
+       If F=0 and (G .ne. 0), then CS=0 and SN=1 without doing any   
+          floating point operations (saves work in DBDSQR when   
+          there are zeros on the diagonal).   
+
+    If F exceeds G in magnitude, CS will be positive.   
+
+    Arguments   
+    =========   
+
+    F       (input) DOUBLE PRECISION   
+            The first component of vector to be rotated.   
+
+    G       (input) DOUBLE PRECISION   
+            The second component of vector to be rotated.   
+
+    CS      (output) DOUBLE PRECISION   
+            The cosine of the rotation.   
+
+    SN      (output) DOUBLE PRECISION   
+            The sine of the rotation.   
+
+    R       (output) DOUBLE PRECISION   
+            The nonzero component of the rotated vector.   
+
+    This version has a few statements commented out for thread safety   
+    (machine parameters are computed on each entry). 10 feb 03, SJH.   
+
+    =====================================================================   
+
+       LOGICAL            FIRST   
+       SAVE               FIRST, SAFMX2, SAFMIN, SAFMN2   
+       DATA               FIRST / .TRUE. /   
+
+       IF( FIRST ) THEN */
+    safmin = igraphdlamch_("S");
+    eps = igraphdlamch_("E");
+    d__1 = igraphdlamch_("B");
+    i__1 = (integer) (log(safmin / eps) / log(igraphdlamch_("B")) / 2.);
+    safmn2 = pow_di(&d__1, &i__1);
+    safmx2 = 1. / safmn2;
+/*        FIRST = .FALSE.   
+       END IF */
+    if (*g == 0.) {
+	*cs = 1.;
+	*sn = 0.;
+	*r__ = *f;
+    } else if (*f == 0.) {
+	*cs = 0.;
+	*sn = 1.;
+	*r__ = *g;
+    } else {
+	f1 = *f;
+	g1 = *g;
+/* Computing MAX */
+	d__1 = abs(f1), d__2 = abs(g1);
+	scale = max(d__1,d__2);
+	if (scale >= safmx2) {
+	    count = 0;
+L10:
+	    ++count;
+	    f1 *= safmn2;
+	    g1 *= safmn2;
+/* Computing MAX */
+	    d__1 = abs(f1), d__2 = abs(g1);
+	    scale = max(d__1,d__2);
+	    if (scale >= safmx2) {
+		goto L10;
+	    }
+/* Computing 2nd power */
+	    d__1 = f1;
+/* Computing 2nd power */
+	    d__2 = g1;
+	    *r__ = sqrt(d__1 * d__1 + d__2 * d__2);
+	    *cs = f1 / *r__;
+	    *sn = g1 / *r__;
+	    i__1 = count;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		*r__ *= safmx2;
+/* L20: */
+	    }
+	} else if (scale <= safmn2) {
+	    count = 0;
+L30:
+	    ++count;
+	    f1 *= safmx2;
+	    g1 *= safmx2;
+/* Computing MAX */
+	    d__1 = abs(f1), d__2 = abs(g1);
+	    scale = max(d__1,d__2);
+	    if (scale <= safmn2) {
+		goto L30;
+	    }
+/* Computing 2nd power */
+	    d__1 = f1;
+/* Computing 2nd power */
+	    d__2 = g1;
+	    *r__ = sqrt(d__1 * d__1 + d__2 * d__2);
+	    *cs = f1 / *r__;
+	    *sn = g1 / *r__;
+	    i__1 = count;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		*r__ *= safmn2;
+/* L40: */
+	    }
+	} else {
+/* Computing 2nd power */
+	    d__1 = f1;
+/* Computing 2nd power */
+	    d__2 = g1;
+	    *r__ = sqrt(d__1 * d__1 + d__2 * d__2);
+	    *cs = f1 / *r__;
+	    *sn = g1 / *r__;
+	}
+	if (abs(*f) > abs(*g) && *cs < 0.) {
+	    *cs = -(*cs);
+	    *sn = -(*sn);
+	    *r__ = -(*r__);
+	}
+    }
+    return 0;
+
+/*     End of DLARTG */
+
+} /* igraphdlartg_ */
+
diff --git a/src/lapack/dlaruv.c b/src/lapack/dlaruv.c
new file mode 100644
index 0000000..e3488e1
--- /dev/null
+++ b/src/lapack/dlaruv.c
@@ -0,0 +1,178 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaruv_(integer *iseed, integer *n, doublereal *x)
+{
+    /* Initialized data */
+
+    static integer mm[512]	/* was [128][4] */ = { 494,2637,255,2008,1253,
+	    3344,4084,1739,3143,3468,688,1657,1238,3166,1292,3422,1270,2016,
+	    154,2862,697,1706,491,931,1444,444,3577,3944,2184,1661,3482,657,
+	    3023,3618,1267,1828,164,3798,3087,2400,2870,3876,1905,1593,1797,
+	    1234,3460,328,2861,1950,617,2070,3331,769,1558,2412,2800,189,287,
+	    2045,1227,2838,209,2770,3654,3993,192,2253,3491,2889,2857,2094,
+	    1818,688,1407,634,3231,815,3524,1914,516,164,303,2144,3480,119,
+	    3357,837,2826,2332,2089,3780,1700,3712,150,2000,3375,1621,3090,
+	    3765,1149,3146,33,3082,2741,359,3316,1749,185,2784,2202,2199,1364,
+	    1244,2020,3160,2785,2772,1217,1822,1245,2252,3904,2774,997,2573,
+	    1148,545,322,789,1440,752,2859,123,1848,643,2405,2638,2344,46,
+	    3814,913,3649,339,3808,822,2832,3078,3633,2970,637,2249,2081,4019,
+	    1478,242,481,2075,4058,622,3376,812,234,641,4005,1122,3135,2640,
+	    2302,40,1832,2247,2034,2637,1287,1691,496,1597,2394,2584,1843,336,
+	    1472,2407,433,2096,1761,2810,566,442,41,1238,1086,603,840,3168,
+	    1499,1084,3438,2408,1589,2391,288,26,512,1456,171,1677,2657,2270,
+	    2587,2961,1970,1817,676,1410,3723,2803,3185,184,663,499,3784,1631,
+	    1925,3912,1398,1349,1441,2224,2411,1907,3192,2786,382,37,759,2948,
+	    1862,3802,2423,2051,2295,1332,1832,2405,3638,3661,327,3660,716,
+	    1842,3987,1368,1848,2366,2508,3754,1766,3572,2893,307,1297,3966,
+	    758,2598,3406,2922,1038,2934,2091,2451,1580,1958,2055,1507,1078,
+	    3273,17,854,2916,3971,2889,3831,2621,1541,893,736,3992,787,2125,
+	    2364,2460,257,1574,3912,1216,3248,3401,2124,2762,149,2245,166,466,
+	    4018,1399,190,2879,153,2320,18,712,2159,2318,2091,3443,1510,449,
+	    1956,2201,3137,3399,1321,2271,3667,2703,629,2365,2431,1113,3922,
+	    2554,184,2099,3228,4012,1921,3452,3901,572,3309,3171,817,3039,
+	    1696,1256,3715,2077,3019,1497,1101,717,51,981,1978,1813,3881,76,
+	    3846,3694,1682,124,1660,3997,479,1141,886,3514,1301,3604,1888,
+	    1836,1990,2058,692,1194,20,3285,2046,2107,3508,3525,3801,2549,
+	    1145,2253,305,3301,1065,3133,2913,3285,1241,1197,3729,2501,1673,
+	    541,2753,949,2361,1165,4081,2725,3305,3069,3617,3733,409,2157,
+	    1361,3973,1865,2525,1409,3445,3577,77,3761,2149,1449,3005,225,85,
+	    3673,3117,3089,1349,2057,413,65,1845,697,3085,3441,1573,3689,2941,
+	    929,533,2841,4077,721,2821,2249,2397,2817,245,1913,1997,3121,997,
+	    1833,2877,1633,981,2009,941,2449,197,2441,285,1473,2741,3129,909,
+	    2801,421,4073,2813,2337,1429,1177,1901,81,1669,2633,2269,129,1141,
+	    249,3917,2481,3941,2217,2749,3041,1877,345,2861,1809,3141,2825,
+	    157,2881,3637,1465,2829,2161,3365,361,2685,3745,2325,3609,3821,
+	    3537,517,3017,2141,1537 };
+
+    /* System generated locals */
+    integer i__1;
+
+    /* Local variables */
+    integer i__, i1, i2, i3, i4, it1, it2, it3, it4;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLARUV returns a vector of n random real numbers from a uniform (0,1)   
+    distribution (n <= 128).   
+
+    This is an auxiliary routine called by DLARNV and ZLARNV.   
+
+    Arguments   
+    =========   
+
+    ISEED   (input/output) INTEGER array, dimension (4)   
+            On entry, the seed of the random number generator; the array   
+            elements must be between 0 and 4095, and ISEED(4) must be   
+            odd.   
+            On exit, the seed is updated.   
+
+    N       (input) INTEGER   
+            The number of random numbers to be generated. N <= 128.   
+
+    X       (output) DOUBLE PRECISION array, dimension (N)   
+            The generated random numbers.   
+
+    Further Details   
+    ===============   
+
+    This routine uses a multiplicative congruential method with modulus   
+    2**48 and multiplier 33952834046453 (see G.S.Fishman,   
+    'Multiplicative congruential random number generators with modulus   
+    2**b: an exhaustive analysis for b = 32 and a partial analysis for   
+    b = 48', Math. Comp. 189, pp 331-344, 1990).   
+
+    48-bit integers are stored in 4 integer array elements with 12 bits   
+    per element. Hence the routine is portable across machines with   
+    integers of 32 bits or more.   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --iseed;
+    --x;
+
+    /* Function Body */
+
+    i1 = iseed[1];
+    i2 = iseed[2];
+    i3 = iseed[3];
+    i4 = iseed[4];
+
+    i__1 = min(*n,128);
+    for (i__ = 1; i__ <= i__1; ++i__) {
+
+L20:
+
+/*        Multiply the seed by i-th power of the multiplier modulo 2**48 */
+
+	it4 = i4 * mm[i__ + 383];
+	it3 = it4 / 4096;
+	it4 -= it3 << 12;
+	it3 = it3 + i3 * mm[i__ + 383] + i4 * mm[i__ + 255];
+	it2 = it3 / 4096;
+	it3 -= it2 << 12;
+	it2 = it2 + i2 * mm[i__ + 383] + i3 * mm[i__ + 255] + i4 * mm[i__ + 
+		127];
+	it1 = it2 / 4096;
+	it2 -= it1 << 12;
+	it1 = it1 + i1 * mm[i__ + 383] + i2 * mm[i__ + 255] + i3 * mm[i__ + 
+		127] + i4 * mm[i__ - 1];
+	it1 %= 4096;
+
+/*        Convert 48-bit integer to a real number in the interval (0,1) */
+
+	x[i__] = ((doublereal) it1 + ((doublereal) it2 + ((doublereal) it3 + (
+		doublereal) it4 * 2.44140625e-4) * 2.44140625e-4) * 
+		2.44140625e-4) * 2.44140625e-4;
+
+	if (x[i__] == 1.) {
+/*           If a real number has n bits of precision, and the first   
+             n bits of the 48-bit integer above happen to be all 1 (which   
+             will occur about once every 2**n calls), then X( I ) will   
+             be rounded to exactly 1.0.   
+             Since X( I ) is not supposed to return exactly 0.0 or 1.0,   
+             the statistically correct thing to do in this situation is   
+             simply to iterate again.   
+             N.B. the case X( I ) = 0.0 should not be possible. */
+	    i1 += 2;
+	    i2 += 2;
+	    i3 += 2;
+	    i4 += 2;
+	    goto L20;
+	}
+
+/* L10: */
+    }
+
+/*     Return final value of seed */
+
+    iseed[1] = it1;
+    iseed[2] = it2;
+    iseed[3] = it3;
+    iseed[4] = it4;
+    return 0;
+
+/*     End of DLARUV */
+
+} /* igraphdlaruv_ */
+
diff --git a/src/lapack/dlascl.c b/src/lapack/dlascl.c
new file mode 100644
index 0000000..1950466
--- /dev/null
+++ b/src/lapack/dlascl.c
@@ -0,0 +1,340 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlascl_(char *type__, integer *kl, integer *ku, 
+	doublereal *cfrom, doublereal *cto, integer *m, integer *n, 
+	doublereal *a, integer *lda, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5;
+
+    /* Local variables */
+    integer i__, j, k1, k2, k3, k4;
+    doublereal mul, cto1;
+    logical done;
+    doublereal ctoc;
+    extern logical igraphlsame_(char *, char *);
+    integer itype;
+    doublereal cfrom1;
+    extern doublereal igraphdlamch_(char *);
+    doublereal cfromc;
+    extern logical igraphdisnan_(doublereal *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    doublereal bignum, smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.0) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2010   
+
+
+    Purpose   
+    =======   
+
+    DLASCL multiplies the M by N real matrix A by the real scalar   
+    CTO/CFROM.  This is done without over/underflow as long as the final   
+    result CTO*A(I,J)/CFROM does not over/underflow. TYPE specifies that   
+    A may be full, upper triangular, lower triangular, upper Hessenberg,   
+    or banded.   
+
+    Arguments   
+    =========   
+
+    TYPE    (input) CHARACTER*1   
+            TYPE indices the storage type of the input matrix.   
+            = 'G':  A is a full matrix.   
+            = 'L':  A is a lower triangular matrix.   
+            = 'U':  A is an upper triangular matrix.   
+            = 'H':  A is an upper Hessenberg matrix.   
+            = 'B':  A is a symmetric band matrix with lower bandwidth KL   
+                    and upper bandwidth KU and with the only the lower   
+                    half stored.   
+            = 'Q':  A is a symmetric band matrix with lower bandwidth KL   
+                    and upper bandwidth KU and with the only the upper   
+                    half stored.   
+            = 'Z':  A is a band matrix with lower bandwidth KL and upper   
+                    bandwidth KU. See DGBTRF for storage details.   
+
+    KL      (input) INTEGER   
+            The lower bandwidth of A.  Referenced only if TYPE = 'B',   
+            'Q' or 'Z'.   
+
+    KU      (input) INTEGER   
+            The upper bandwidth of A.  Referenced only if TYPE = 'B',   
+            'Q' or 'Z'.   
+
+    CFROM   (input) DOUBLE PRECISION   
+    CTO     (input) DOUBLE PRECISION   
+            The matrix A is multiplied by CTO/CFROM. A(I,J) is computed   
+            without over/underflow if the final result CTO*A(I,J)/CFROM   
+            can be represented without over/underflow.  CFROM must be   
+            nonzero.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            The matrix to be multiplied by CTO/CFROM.  See TYPE for the   
+            storage type.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+    INFO    (output) INTEGER   
+            0  - successful exit   
+            <0 - if INFO = -i, the i-th argument had an illegal value.   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    *info = 0;
+
+    if (igraphlsame_(type__, "G")) {
+	itype = 0;
+    } else if (igraphlsame_(type__, "L")) {
+	itype = 1;
+    } else if (igraphlsame_(type__, "U")) {
+	itype = 2;
+    } else if (igraphlsame_(type__, "H")) {
+	itype = 3;
+    } else if (igraphlsame_(type__, "B")) {
+	itype = 4;
+    } else if (igraphlsame_(type__, "Q")) {
+	itype = 5;
+    } else if (igraphlsame_(type__, "Z")) {
+	itype = 6;
+    } else {
+	itype = -1;
+    }
+
+    if (itype == -1) {
+	*info = -1;
+    } else if (*cfrom == 0. || igraphdisnan_(cfrom)) {
+	*info = -4;
+    } else if (igraphdisnan_(cto)) {
+	*info = -5;
+    } else if (*m < 0) {
+	*info = -6;
+    } else if (*n < 0 || itype == 4 && *n != *m || itype == 5 && *n != *m) {
+	*info = -7;
+    } else if (itype <= 3 && *lda < max(1,*m)) {
+	*info = -9;
+    } else if (itype >= 4) {
+/* Computing MAX */
+	i__1 = *m - 1;
+	if (*kl < 0 || *kl > max(i__1,0)) {
+	    *info = -2;
+	} else /* if(complicated condition) */ {
+/* Computing MAX */
+	    i__1 = *n - 1;
+	    if (*ku < 0 || *ku > max(i__1,0) || (itype == 4 || itype == 5) && 
+		    *kl != *ku) {
+		*info = -3;
+	    } else if (itype == 4 && *lda < *kl + 1 || itype == 5 && *lda < *
+		    ku + 1 || itype == 6 && *lda < (*kl << 1) + *ku + 1) {
+		*info = -9;
+	    }
+	}
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DLASCL", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0 || *m == 0) {
+	return 0;
+    }
+
+/*     Get machine parameters */
+
+    smlnum = igraphdlamch_("S");
+    bignum = 1. / smlnum;
+
+    cfromc = *cfrom;
+    ctoc = *cto;
+
+L10:
+    cfrom1 = cfromc * smlnum;
+    if (cfrom1 == cfromc) {
+/*        CFROMC is an inf.  Multiply by a correctly signed zero for   
+          finite CTOC, or a NaN if CTOC is infinite. */
+	mul = ctoc / cfromc;
+	done = TRUE_;
+	cto1 = ctoc;
+    } else {
+	cto1 = ctoc / bignum;
+	if (cto1 == ctoc) {
+/*           CTOC is either 0 or an inf.  In both cases, CTOC itself   
+             serves as the correct multiplication factor. */
+	    mul = ctoc;
+	    done = TRUE_;
+	    cfromc = 1.;
+	} else if (abs(cfrom1) > abs(ctoc) && ctoc != 0.) {
+	    mul = smlnum;
+	    done = FALSE_;
+	    cfromc = cfrom1;
+	} else if (abs(cto1) > abs(cfromc)) {
+	    mul = bignum;
+	    done = FALSE_;
+	    ctoc = cto1;
+	} else {
+	    mul = ctoc / cfromc;
+	    done = TRUE_;
+	}
+    }
+
+    if (itype == 0) {
+
+/*        Full matrix */
+
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L20: */
+	    }
+/* L30: */
+	}
+
+    } else if (itype == 1) {
+
+/*        Lower triangular matrix */
+
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = j; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L40: */
+	    }
+/* L50: */
+	}
+
+    } else if (itype == 2) {
+
+/*        Upper triangular matrix */
+
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = min(j,*m);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L60: */
+	    }
+/* L70: */
+	}
+
+    } else if (itype == 3) {
+
+/*        Upper Hessenberg matrix */
+
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MIN */
+	    i__3 = j + 1;
+	    i__2 = min(i__3,*m);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L80: */
+	    }
+/* L90: */
+	}
+
+    } else if (itype == 4) {
+
+/*        Lower half of a symmetric band matrix */
+
+	k3 = *kl + 1;
+	k4 = *n + 1;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MIN */
+	    i__3 = k3, i__4 = k4 - j;
+	    i__2 = min(i__3,i__4);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L100: */
+	    }
+/* L110: */
+	}
+
+    } else if (itype == 5) {
+
+/*        Upper half of a symmetric band matrix */
+
+	k1 = *ku + 2;
+	k3 = *ku + 1;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MAX */
+	    i__2 = k1 - j;
+	    i__3 = k3;
+	    for (i__ = max(i__2,1); i__ <= i__3; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L120: */
+	    }
+/* L130: */
+	}
+
+    } else if (itype == 6) {
+
+/*        Band matrix */
+
+	k1 = *kl + *ku + 2;
+	k2 = *kl + 1;
+	k3 = (*kl << 1) + *ku + 1;
+	k4 = *kl + *ku + 1 + *m;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MAX */
+	    i__3 = k1 - j;
+/* Computing MIN */
+	    i__4 = k3, i__5 = k4 - j;
+	    i__2 = min(i__4,i__5);
+	    for (i__ = max(i__3,k2); i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] *= mul;
+/* L140: */
+	    }
+/* L150: */
+	}
+
+    }
+
+    if (! done) {
+	goto L10;
+    }
+
+    return 0;
+
+/*     End of DLASCL */
+
+} /* igraphdlascl_ */
+
diff --git a/src/lapack/dlaset.c b/src/lapack/dlaset.c
new file mode 100644
index 0000000..de4067a
--- /dev/null
+++ b/src/lapack/dlaset.c
@@ -0,0 +1,142 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaset_(char *uplo, integer *m, integer *n, doublereal *
+	alpha, doublereal *beta, doublereal *a, integer *lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, j;
+    extern logical igraphlsame_(char *, char *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLASET initializes an m-by-n matrix A to BETA on the diagonal and   
+    ALPHA on the offdiagonals.   
+
+    Arguments   
+    =========   
+
+    UPLO    (input) CHARACTER*1   
+            Specifies the part of the matrix A to be set.   
+            = 'U':      Upper triangular part is set; the strictly lower   
+                        triangular part of A is not changed.   
+            = 'L':      Lower triangular part is set; the strictly upper   
+                        triangular part of A is not changed.   
+            Otherwise:  All of the matrix A is set.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  N >= 0.   
+
+    ALPHA   (input) DOUBLE PRECISION   
+            The constant to which the offdiagonal elements are to be set.   
+
+    BETA    (input) DOUBLE PRECISION   
+            The constant to which the diagonal elements are to be set.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On exit, the leading m-by-n submatrix of A is set as follows:   
+
+            if UPLO = 'U', A(i,j) = ALPHA, 1<=i<=j-1, 1<=j<=n,   
+            if UPLO = 'L', A(i,j) = ALPHA, j+1<=i<=m, 1<=j<=n,   
+            otherwise,     A(i,j) = ALPHA, 1<=i<=m, 1<=j<=n, i.ne.j,   
+
+            and, for all UPLO, A(i,i) = BETA, 1<=i<=min(m,n).   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+   =====================================================================   
+
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    if (igraphlsame_(uplo, "U")) {
+
+/*        Set the strictly upper triangular or trapezoidal part of the   
+          array to ALPHA. */
+
+	i__1 = *n;
+	for (j = 2; j <= i__1; ++j) {
+/* Computing MIN */
+	    i__3 = j - 1;
+	    i__2 = min(i__3,*m);
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] = *alpha;
+/* L10: */
+	    }
+/* L20: */
+	}
+
+    } else if (igraphlsame_(uplo, "L")) {
+
+/*        Set the strictly lower triangular or trapezoidal part of the   
+          array to ALPHA. */
+
+	i__1 = min(*m,*n);
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = j + 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] = *alpha;
+/* L30: */
+	    }
+/* L40: */
+	}
+
+    } else {
+
+/*        Set the leading m-by-n submatrix to ALPHA. */
+
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] = *alpha;
+/* L50: */
+	    }
+/* L60: */
+	}
+    }
+
+/*     Set the first min(M,N) diagonal elements to BETA. */
+
+    i__1 = min(*m,*n);
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	a[i__ + i__ * a_dim1] = *beta;
+/* L70: */
+    }
+
+    return 0;
+
+/*     End of DLASET */
+
+} /* igraphdlaset_ */
+
diff --git a/src/lapack/dlasq2.c b/src/lapack/dlasq2.c
new file mode 100644
index 0000000..8516124
--- /dev/null
+++ b/src/lapack/dlasq2.c
@@ -0,0 +1,588 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__2 = 2;
+static integer c__10 = 10;
+static integer c__3 = 3;
+static integer c__4 = 4;
+static integer c__11 = 11;
+
+/* Subroutine */ int igraphdlasq2_(integer *n, doublereal *z__, integer *info)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    doublereal d__, e, g;
+    integer k;
+    doublereal s, t;
+    integer i0, i4, n0;
+    doublereal dn;
+    integer pp;
+    doublereal dn1, dn2, dee, eps, tau, tol;
+    integer ipn4;
+    doublereal tol2;
+    logical ieee;
+    integer nbig;
+    doublereal dmin__, emin, emax;
+    integer kmin, ndiv, iter;
+    doublereal qmin, temp, qmax, zmax;
+    integer splt;
+    doublereal dmin1, dmin2;
+    integer nfail;
+    doublereal desig, trace, sigma;
+    integer iinfo, ttype;
+    extern /* Subroutine */ int igraphdlasq3_(integer *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, doublereal *, doublereal *,
+	     integer *, integer *, integer *, logical *, integer *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    doublereal deemin;
+    integer iwhila, iwhilb;
+    doublereal oldemn, safmin;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphdlasrt_(char *, integer *, doublereal *, 
+	    integer *);
+
+
+/*  -- LAPACK routine (version 3.2)                                    --   
+
+    -- Contributed by Osni Marques of the Lawrence Berkeley National   --   
+    -- Laboratory and Beresford Parlett of the Univ. of California at  --   
+    -- Berkeley                                                        --   
+    -- November 2008                                                   --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    DLASQ2 computes all the eigenvalues of the symmetric positive   
+    definite tridiagonal matrix associated with the qd array Z to high   
+    relative accuracy are computed to high relative accuracy, in the   
+    absence of denormalization, underflow and overflow.   
+
+    To see the relation of Z to the tridiagonal matrix, let L be a   
+    unit lower bidiagonal matrix with subdiagonals Z(2,4,6,,..) and   
+    let U be an upper bidiagonal matrix with 1's above and diagonal   
+    Z(1,3,5,,..). The tridiagonal is L*U or, if you prefer, the   
+    symmetric tridiagonal to which it is similar.   
+
+    Note : DLASQ2 defines a logical variable, IEEE, which is true   
+    on machines which follow ieee-754 floating-point standard in their   
+    handling of infinities and NaNs, and false otherwise. This variable   
+    is passed to DLASQ3.   
+
+    Arguments   
+    =========   
+
+    N     (input) INTEGER   
+          The number of rows and columns in the matrix. N >= 0.   
+
+    Z     (input/output) DOUBLE PRECISION array, dimension ( 4*N )   
+          On entry Z holds the qd array. On exit, entries 1 to N hold   
+          the eigenvalues in decreasing order, Z( 2*N+1 ) holds the   
+          trace, and Z( 2*N+2 ) holds the sum of the eigenvalues. If   
+          N > 2, then Z( 2*N+3 ) holds the iteration count, Z( 2*N+4 )   
+          holds NDIVS/NIN^2, and Z( 2*N+5 ) holds the percentage of   
+          shifts that failed.   
+
+    INFO  (output) INTEGER   
+          = 0: successful exit   
+          < 0: if the i-th argument is a scalar and had an illegal   
+               value, then INFO = -i, if the i-th argument is an   
+               array and the j-entry had an illegal value, then   
+               INFO = -(i*100+j)   
+          > 0: the algorithm failed   
+                = 1, a split was marked by a positive value in E   
+                = 2, current block of Z not diagonalized after 30*N   
+                     iterations (in inner while loop)   
+                = 3, termination criterion of outer while loop not met   
+                     (program created more than N unreduced blocks)   
+
+    Further Details   
+    ===============   
+    Local Variables: I0:N0 defines a current unreduced segment of Z.   
+    The shifts are accumulated in SIGMA. Iteration count is in ITER.   
+    Ping-pong is controlled by PP (alternates between 0 and 1).   
+
+    =====================================================================   
+
+
+       Test the input arguments.   
+       (in case DLASQ2 is not called by DLASQ1)   
+
+       Parameter adjustments */
+    --z__;
+
+    /* Function Body */
+    *info = 0;
+    eps = igraphdlamch_("Precision");
+    safmin = igraphdlamch_("Safe minimum");
+    tol = eps * 100.;
+/* Computing 2nd power */
+    d__1 = tol;
+    tol2 = d__1 * d__1;
+
+    if (*n < 0) {
+	*info = -1;
+	igraphxerbla_("DLASQ2", &c__1, (ftnlen)6);
+	return 0;
+    } else if (*n == 0) {
+	return 0;
+    } else if (*n == 1) {
+
+/*        1-by-1 case. */
+
+	if (z__[1] < 0.) {
+	    *info = -201;
+	    igraphxerbla_("DLASQ2", &c__2, (ftnlen)6);
+	}
+	return 0;
+    } else if (*n == 2) {
+
+/*        2-by-2 case. */
+
+	if (z__[2] < 0. || z__[3] < 0.) {
+	    *info = -2;
+	    igraphxerbla_("DLASQ2", &c__2, (ftnlen)6);
+	    return 0;
+	} else if (z__[3] > z__[1]) {
+	    d__ = z__[3];
+	    z__[3] = z__[1];
+	    z__[1] = d__;
+	}
+	z__[5] = z__[1] + z__[2] + z__[3];
+	if (z__[2] > z__[3] * tol2) {
+	    t = (z__[1] - z__[3] + z__[2]) * .5;
+	    s = z__[3] * (z__[2] / t);
+	    if (s <= t) {
+		s = z__[3] * (z__[2] / (t * (sqrt(s / t + 1.) + 1.)));
+	    } else {
+		s = z__[3] * (z__[2] / (t + sqrt(t) * sqrt(t + s)));
+	    }
+	    t = z__[1] + (s + z__[2]);
+	    z__[3] *= z__[1] / t;
+	    z__[1] = t;
+	}
+	z__[2] = z__[3];
+	z__[6] = z__[2] + z__[1];
+	return 0;
+    }
+
+/*     Check for negative data and compute sums of q's and e's. */
+
+    z__[*n * 2] = 0.;
+    emin = z__[2];
+    qmax = 0.;
+    zmax = 0.;
+    d__ = 0.;
+    e = 0.;
+
+    i__1 = *n - 1 << 1;
+    for (k = 1; k <= i__1; k += 2) {
+	if (z__[k] < 0.) {
+	    *info = -(k + 200);
+	    igraphxerbla_("DLASQ2", &c__2, (ftnlen)6);
+	    return 0;
+	} else if (z__[k + 1] < 0.) {
+	    *info = -(k + 201);
+	    igraphxerbla_("DLASQ2", &c__2, (ftnlen)6);
+	    return 0;
+	}
+	d__ += z__[k];
+	e += z__[k + 1];
+/* Computing MAX */
+	d__1 = qmax, d__2 = z__[k];
+	qmax = max(d__1,d__2);
+/* Computing MIN */
+	d__1 = emin, d__2 = z__[k + 1];
+	emin = min(d__1,d__2);
+/* Computing MAX */
+	d__1 = max(qmax,zmax), d__2 = z__[k + 1];
+	zmax = max(d__1,d__2);
+/* L10: */
+    }
+    if (z__[(*n << 1) - 1] < 0.) {
+	*info = -((*n << 1) + 199);
+	igraphxerbla_("DLASQ2", &c__2, (ftnlen)6);
+	return 0;
+    }
+    d__ += z__[(*n << 1) - 1];
+/* Computing MAX */
+    d__1 = qmax, d__2 = z__[(*n << 1) - 1];
+    qmax = max(d__1,d__2);
+    zmax = max(qmax,zmax);
+
+/*     Check for diagonality. */
+
+    if (e == 0.) {
+	i__1 = *n;
+	for (k = 2; k <= i__1; ++k) {
+	    z__[k] = z__[(k << 1) - 1];
+/* L20: */
+	}
+	igraphdlasrt_("D", n, &z__[1], &iinfo);
+	z__[(*n << 1) - 1] = d__;
+	return 0;
+    }
+
+    trace = d__ + e;
+
+/*     Check for zero data. */
+
+    if (trace == 0.) {
+	z__[(*n << 1) - 1] = 0.;
+	return 0;
+    }
+
+/*     Check whether the machine is IEEE conformable. */
+
+    ieee = igraphilaenv_(&c__10, "DLASQ2", "N", &c__1, &c__2, &c__3, &c__4, (ftnlen)
+	    6, (ftnlen)1) == 1 && igraphilaenv_(&c__11, "DLASQ2", "N", &c__1, &c__2,
+	     &c__3, &c__4, (ftnlen)6, (ftnlen)1) == 1;
+
+/*     Rearrange data for locality: Z=(q1,qq1,e1,ee1,q2,qq2,e2,ee2,...). */
+
+    for (k = *n << 1; k >= 2; k += -2) {
+	z__[k * 2] = 0.;
+	z__[(k << 1) - 1] = z__[k];
+	z__[(k << 1) - 2] = 0.;
+	z__[(k << 1) - 3] = z__[k - 1];
+/* L30: */
+    }
+
+    i0 = 1;
+    n0 = *n;
+
+/*     Reverse the qd-array, if warranted. */
+
+    if (z__[(i0 << 2) - 3] * 1.5 < z__[(n0 << 2) - 3]) {
+	ipn4 = i0 + n0 << 2;
+	i__1 = i0 + n0 - 1 << 1;
+	for (i4 = i0 << 2; i4 <= i__1; i4 += 4) {
+	    temp = z__[i4 - 3];
+	    z__[i4 - 3] = z__[ipn4 - i4 - 3];
+	    z__[ipn4 - i4 - 3] = temp;
+	    temp = z__[i4 - 1];
+	    z__[i4 - 1] = z__[ipn4 - i4 - 5];
+	    z__[ipn4 - i4 - 5] = temp;
+/* L40: */
+	}
+    }
+
+/*     Initial split checking via dqd and Li's test. */
+
+    pp = 0;
+
+    for (k = 1; k <= 2; ++k) {
+
+	d__ = z__[(n0 << 2) + pp - 3];
+	i__1 = (i0 << 2) + pp;
+	for (i4 = (n0 - 1 << 2) + pp; i4 >= i__1; i4 += -4) {
+	    if (z__[i4 - 1] <= tol2 * d__) {
+		z__[i4 - 1] = -0.;
+		d__ = z__[i4 - 3];
+	    } else {
+		d__ = z__[i4 - 3] * (d__ / (d__ + z__[i4 - 1]));
+	    }
+/* L50: */
+	}
+
+/*        dqd maps Z to ZZ plus Li's test. */
+
+	emin = z__[(i0 << 2) + pp + 1];
+	d__ = z__[(i0 << 2) + pp - 3];
+	i__1 = (n0 - 1 << 2) + pp;
+	for (i4 = (i0 << 2) + pp; i4 <= i__1; i4 += 4) {
+	    z__[i4 - (pp << 1) - 2] = d__ + z__[i4 - 1];
+	    if (z__[i4 - 1] <= tol2 * d__) {
+		z__[i4 - 1] = -0.;
+		z__[i4 - (pp << 1) - 2] = d__;
+		z__[i4 - (pp << 1)] = 0.;
+		d__ = z__[i4 + 1];
+	    } else if (safmin * z__[i4 + 1] < z__[i4 - (pp << 1) - 2] && 
+		    safmin * z__[i4 - (pp << 1) - 2] < z__[i4 + 1]) {
+		temp = z__[i4 + 1] / z__[i4 - (pp << 1) - 2];
+		z__[i4 - (pp << 1)] = z__[i4 - 1] * temp;
+		d__ *= temp;
+	    } else {
+		z__[i4 - (pp << 1)] = z__[i4 + 1] * (z__[i4 - 1] / z__[i4 - (
+			pp << 1) - 2]);
+		d__ = z__[i4 + 1] * (d__ / z__[i4 - (pp << 1) - 2]);
+	    }
+/* Computing MIN */
+	    d__1 = emin, d__2 = z__[i4 - (pp << 1)];
+	    emin = min(d__1,d__2);
+/* L60: */
+	}
+	z__[(n0 << 2) - pp - 2] = d__;
+
+/*        Now find qmax. */
+
+	qmax = z__[(i0 << 2) - pp - 2];
+	i__1 = (n0 << 2) - pp - 2;
+	for (i4 = (i0 << 2) - pp + 2; i4 <= i__1; i4 += 4) {
+/* Computing MAX */
+	    d__1 = qmax, d__2 = z__[i4];
+	    qmax = max(d__1,d__2);
+/* L70: */
+	}
+
+/*        Prepare for the next iteration on K. */
+
+	pp = 1 - pp;
+/* L80: */
+    }
+
+/*     Initialise variables to pass to DLASQ3. */
+
+    ttype = 0;
+    dmin1 = 0.;
+    dmin2 = 0.;
+    dn = 0.;
+    dn1 = 0.;
+    dn2 = 0.;
+    g = 0.;
+    tau = 0.;
+
+    iter = 2;
+    nfail = 0;
+    ndiv = n0 - i0 << 1;
+
+    i__1 = *n + 1;
+    for (iwhila = 1; iwhila <= i__1; ++iwhila) {
+	if (n0 < 1) {
+	    goto L170;
+	}
+
+/*        While array unfinished do   
+
+          E(N0) holds the value of SIGMA when submatrix in I0:N0   
+          splits from the rest of the array, but is negated. */
+
+	desig = 0.;
+	if (n0 == *n) {
+	    sigma = 0.;
+	} else {
+	    sigma = -z__[(n0 << 2) - 1];
+	}
+	if (sigma < 0.) {
+	    *info = 1;
+	    return 0;
+	}
+
+/*        Find last unreduced submatrix's top index I0, find QMAX and   
+          EMIN. Find Gershgorin-type bound if Q's much greater than E's. */
+
+	emax = 0.;
+	if (n0 > i0) {
+	    emin = (d__1 = z__[(n0 << 2) - 5], abs(d__1));
+	} else {
+	    emin = 0.;
+	}
+	qmin = z__[(n0 << 2) - 3];
+	qmax = qmin;
+	for (i4 = n0 << 2; i4 >= 8; i4 += -4) {
+	    if (z__[i4 - 5] <= 0.) {
+		goto L100;
+	    }
+	    if (qmin >= emax * 4.) {
+/* Computing MIN */
+		d__1 = qmin, d__2 = z__[i4 - 3];
+		qmin = min(d__1,d__2);
+/* Computing MAX */
+		d__1 = emax, d__2 = z__[i4 - 5];
+		emax = max(d__1,d__2);
+	    }
+/* Computing MAX */
+	    d__1 = qmax, d__2 = z__[i4 - 7] + z__[i4 - 5];
+	    qmax = max(d__1,d__2);
+/* Computing MIN */
+	    d__1 = emin, d__2 = z__[i4 - 5];
+	    emin = min(d__1,d__2);
+/* L90: */
+	}
+	i4 = 4;
+
+L100:
+	i0 = i4 / 4;
+	pp = 0;
+
+	if (n0 - i0 > 1) {
+	    dee = z__[(i0 << 2) - 3];
+	    deemin = dee;
+	    kmin = i0;
+	    i__2 = (n0 << 2) - 3;
+	    for (i4 = (i0 << 2) + 1; i4 <= i__2; i4 += 4) {
+		dee = z__[i4] * (dee / (dee + z__[i4 - 2]));
+		if (dee <= deemin) {
+		    deemin = dee;
+		    kmin = (i4 + 3) / 4;
+		}
+/* L110: */
+	    }
+	    if (kmin - i0 << 1 < n0 - kmin && deemin <= z__[(n0 << 2) - 3] * 
+		    .5) {
+		ipn4 = i0 + n0 << 2;
+		pp = 2;
+		i__2 = i0 + n0 - 1 << 1;
+		for (i4 = i0 << 2; i4 <= i__2; i4 += 4) {
+		    temp = z__[i4 - 3];
+		    z__[i4 - 3] = z__[ipn4 - i4 - 3];
+		    z__[ipn4 - i4 - 3] = temp;
+		    temp = z__[i4 - 2];
+		    z__[i4 - 2] = z__[ipn4 - i4 - 2];
+		    z__[ipn4 - i4 - 2] = temp;
+		    temp = z__[i4 - 1];
+		    z__[i4 - 1] = z__[ipn4 - i4 - 5];
+		    z__[ipn4 - i4 - 5] = temp;
+		    temp = z__[i4];
+		    z__[i4] = z__[ipn4 - i4 - 4];
+		    z__[ipn4 - i4 - 4] = temp;
+/* L120: */
+		}
+	    }
+	}
+
+/*        Put -(initial shift) into DMIN.   
+
+   Computing MAX */
+	d__1 = 0., d__2 = qmin - sqrt(qmin) * 2. * sqrt(emax);
+	dmin__ = -max(d__1,d__2);
+
+/*        Now I0:N0 is unreduced.   
+          PP = 0 for ping, PP = 1 for pong.   
+          PP = 2 indicates that flipping was applied to the Z array and   
+                 and that the tests for deflation upon entry in DLASQ3   
+                 should not be performed. */
+
+	nbig = (n0 - i0 + 1) * 30;
+	i__2 = nbig;
+	for (iwhilb = 1; iwhilb <= i__2; ++iwhilb) {
+	    if (i0 > n0) {
+		goto L150;
+	    }
+
+/*           While submatrix unfinished take a good dqds step. */
+
+	    igraphdlasq3_(&i0, &n0, &z__[1], &pp, &dmin__, &sigma, &desig, &qmax, &
+		    nfail, &iter, &ndiv, &ieee, &ttype, &dmin1, &dmin2, &dn, &
+		    dn1, &dn2, &g, &tau);
+
+	    pp = 1 - pp;
+
+/*           When EMIN is very small check for splits. */
+
+	    if (pp == 0 && n0 - i0 >= 3) {
+		if (z__[n0 * 4] <= tol2 * qmax || z__[(n0 << 2) - 1] <= tol2 *
+			 sigma) {
+		    splt = i0 - 1;
+		    qmax = z__[(i0 << 2) - 3];
+		    emin = z__[(i0 << 2) - 1];
+		    oldemn = z__[i0 * 4];
+		    i__3 = n0 - 3 << 2;
+		    for (i4 = i0 << 2; i4 <= i__3; i4 += 4) {
+			if (z__[i4] <= tol2 * z__[i4 - 3] || z__[i4 - 1] <= 
+				tol2 * sigma) {
+			    z__[i4 - 1] = -sigma;
+			    splt = i4 / 4;
+			    qmax = 0.;
+			    emin = z__[i4 + 3];
+			    oldemn = z__[i4 + 4];
+			} else {
+/* Computing MAX */
+			    d__1 = qmax, d__2 = z__[i4 + 1];
+			    qmax = max(d__1,d__2);
+/* Computing MIN */
+			    d__1 = emin, d__2 = z__[i4 - 1];
+			    emin = min(d__1,d__2);
+/* Computing MIN */
+			    d__1 = oldemn, d__2 = z__[i4];
+			    oldemn = min(d__1,d__2);
+			}
+/* L130: */
+		    }
+		    z__[(n0 << 2) - 1] = emin;
+		    z__[n0 * 4] = oldemn;
+		    i0 = splt + 1;
+		}
+	    }
+
+/* L140: */
+	}
+
+	*info = 2;
+	return 0;
+
+/*        end IWHILB */
+
+L150:
+
+/* L160: */
+	;
+    }
+
+    *info = 3;
+    return 0;
+
+/*     end IWHILA */
+
+L170:
+
+/*     Move q's to the front. */
+
+    i__1 = *n;
+    for (k = 2; k <= i__1; ++k) {
+	z__[k] = z__[(k << 2) - 3];
+/* L180: */
+    }
+
+/*     Sort and compute sum of eigenvalues. */
+
+    igraphdlasrt_("D", n, &z__[1], &iinfo);
+
+    e = 0.;
+    for (k = *n; k >= 1; --k) {
+	e += z__[k];
+/* L190: */
+    }
+
+/*     Store trace, sum(eigenvalues) and information on performance. */
+
+    z__[(*n << 1) + 1] = trace;
+    z__[(*n << 1) + 2] = e;
+    z__[(*n << 1) + 3] = (doublereal) iter;
+/* Computing 2nd power */
+    i__1 = *n;
+    z__[(*n << 1) + 4] = (doublereal) ndiv / (doublereal) (i__1 * i__1);
+    z__[(*n << 1) + 5] = nfail * 100. / (doublereal) iter;
+    return 0;
+
+/*     End of DLASQ2 */
+
+} /* igraphdlasq2_ */
+
diff --git a/src/lapack/dlasq3.c b/src/lapack/dlasq3.c
new file mode 100644
index 0000000..e42c5c7
--- /dev/null
+++ b/src/lapack/dlasq3.c
@@ -0,0 +1,348 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlasq3_(integer *i0, integer *n0, doublereal *z__, 
+	integer *pp, doublereal *dmin__, doublereal *sigma, doublereal *desig,
+	 doublereal *qmax, integer *nfail, integer *iter, integer *ndiv, 
+	logical *ieee, integer *ttype, doublereal *dmin1, doublereal *dmin2, 
+	doublereal *dn, doublereal *dn1, doublereal *dn2, doublereal *g, 
+	doublereal *tau)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    doublereal s, t;
+    integer j4, nn;
+    doublereal eps, tol;
+    integer n0in, ipn4;
+    doublereal tol2, temp;
+    extern /* Subroutine */ int igraphdlasq4_(integer *, integer *, doublereal *, 
+	    integer *, integer *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, integer *,
+	     doublereal *), igraphdlasq5_(integer *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, doublereal *, doublereal *,
+	     doublereal *, doublereal *, doublereal *, logical *), igraphdlasq6_(
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern logical igraphdisnan_(doublereal *);
+
+
+/*  -- LAPACK routine (version 3.2.2)                                    --   
+
+    -- Contributed by Osni Marques of the Lawrence Berkeley National   --   
+    -- Laboratory and Beresford Parlett of the Univ. of California at  --   
+    -- Berkeley                                                        --   
+    -- June 2010                                                       --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    DLASQ3 checks for deflation, computes a shift (TAU) and calls dqds.   
+    In case of failure it changes shifts, and tries again until output   
+    is positive.   
+
+    Arguments   
+    =========   
+
+    I0     (input) INTEGER   
+           First index.   
+
+    N0     (input/output) INTEGER   
+           Last index.   
+
+    Z      (input) DOUBLE PRECISION array, dimension ( 4*N )   
+           Z holds the qd array.   
+
+    PP     (input/output) INTEGER   
+           PP=0 for ping, PP=1 for pong.   
+           PP=2 indicates that flipping was applied to the Z array   
+           and that the initial tests for deflation should not be   
+           performed.   
+
+    DMIN   (output) DOUBLE PRECISION   
+           Minimum value of d.   
+
+    SIGMA  (output) DOUBLE PRECISION   
+           Sum of shifts used in current segment.   
+
+    DESIG  (input/output) DOUBLE PRECISION   
+           Lower order part of SIGMA   
+
+    QMAX   (input) DOUBLE PRECISION   
+           Maximum value of q.   
+
+    NFAIL  (output) INTEGER   
+           Number of times shift was too big.   
+
+    ITER   (output) INTEGER   
+           Number of iterations.   
+
+    NDIV   (output) INTEGER   
+           Number of divisions.   
+
+    IEEE   (input) LOGICAL   
+           Flag for IEEE or non IEEE arithmetic (passed to DLASQ5).   
+
+    TTYPE  (input/output) INTEGER   
+           Shift type.   
+
+    DMIN1  (input/output) DOUBLE PRECISION   
+
+    DMIN2  (input/output) DOUBLE PRECISION   
+
+    DN     (input/output) DOUBLE PRECISION   
+
+    DN1    (input/output) DOUBLE PRECISION   
+
+    DN2    (input/output) DOUBLE PRECISION   
+
+    G      (input/output) DOUBLE PRECISION   
+
+    TAU    (input/output) DOUBLE PRECISION   
+
+           These are passed as arguments in order to save their values   
+           between calls to DLASQ3.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --z__;
+
+    /* Function Body */
+    n0in = *n0;
+    eps = igraphdlamch_("Precision");
+    tol = eps * 100.;
+/* Computing 2nd power */
+    d__1 = tol;
+    tol2 = d__1 * d__1;
+
+/*     Check for deflation. */
+
+L10:
+
+    if (*n0 < *i0) {
+	return 0;
+    }
+    if (*n0 == *i0) {
+	goto L20;
+    }
+    nn = (*n0 << 2) + *pp;
+    if (*n0 == *i0 + 1) {
+	goto L40;
+    }
+
+/*     Check whether E(N0-1) is negligible, 1 eigenvalue. */
+
+    if (z__[nn - 5] > tol2 * (*sigma + z__[nn - 3]) && z__[nn - (*pp << 1) - 
+	    4] > tol2 * z__[nn - 7]) {
+	goto L30;
+    }
+
+L20:
+
+    z__[(*n0 << 2) - 3] = z__[(*n0 << 2) + *pp - 3] + *sigma;
+    --(*n0);
+    goto L10;
+
+/*     Check  whether E(N0-2) is negligible, 2 eigenvalues. */
+
+L30:
+
+    if (z__[nn - 9] > tol2 * *sigma && z__[nn - (*pp << 1) - 8] > tol2 * z__[
+	    nn - 11]) {
+	goto L50;
+    }
+
+L40:
+
+    if (z__[nn - 3] > z__[nn - 7]) {
+	s = z__[nn - 3];
+	z__[nn - 3] = z__[nn - 7];
+	z__[nn - 7] = s;
+    }
+    if (z__[nn - 5] > z__[nn - 3] * tol2) {
+	t = (z__[nn - 7] - z__[nn - 3] + z__[nn - 5]) * .5;
+	s = z__[nn - 3] * (z__[nn - 5] / t);
+	if (s <= t) {
+	    s = z__[nn - 3] * (z__[nn - 5] / (t * (sqrt(s / t + 1.) + 1.)));
+	} else {
+	    s = z__[nn - 3] * (z__[nn - 5] / (t + sqrt(t) * sqrt(t + s)));
+	}
+	t = z__[nn - 7] + (s + z__[nn - 5]);
+	z__[nn - 3] *= z__[nn - 7] / t;
+	z__[nn - 7] = t;
+    }
+    z__[(*n0 << 2) - 7] = z__[nn - 7] + *sigma;
+    z__[(*n0 << 2) - 3] = z__[nn - 3] + *sigma;
+    *n0 += -2;
+    goto L10;
+
+L50:
+    if (*pp == 2) {
+	*pp = 0;
+    }
+
+/*     Reverse the qd-array, if warranted. */
+
+    if (*dmin__ <= 0. || *n0 < n0in) {
+	if (z__[(*i0 << 2) + *pp - 3] * 1.5 < z__[(*n0 << 2) + *pp - 3]) {
+	    ipn4 = *i0 + *n0 << 2;
+	    i__1 = *i0 + *n0 - 1 << 1;
+	    for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+		temp = z__[j4 - 3];
+		z__[j4 - 3] = z__[ipn4 - j4 - 3];
+		z__[ipn4 - j4 - 3] = temp;
+		temp = z__[j4 - 2];
+		z__[j4 - 2] = z__[ipn4 - j4 - 2];
+		z__[ipn4 - j4 - 2] = temp;
+		temp = z__[j4 - 1];
+		z__[j4 - 1] = z__[ipn4 - j4 - 5];
+		z__[ipn4 - j4 - 5] = temp;
+		temp = z__[j4];
+		z__[j4] = z__[ipn4 - j4 - 4];
+		z__[ipn4 - j4 - 4] = temp;
+/* L60: */
+	    }
+	    if (*n0 - *i0 <= 4) {
+		z__[(*n0 << 2) + *pp - 1] = z__[(*i0 << 2) + *pp - 1];
+		z__[(*n0 << 2) - *pp] = z__[(*i0 << 2) - *pp];
+	    }
+/* Computing MIN */
+	    d__1 = *dmin2, d__2 = z__[(*n0 << 2) + *pp - 1];
+	    *dmin2 = min(d__1,d__2);
+/* Computing MIN */
+	    d__1 = z__[(*n0 << 2) + *pp - 1], d__2 = z__[(*i0 << 2) + *pp - 1]
+		    , d__1 = min(d__1,d__2), d__2 = z__[(*i0 << 2) + *pp + 3];
+	    z__[(*n0 << 2) + *pp - 1] = min(d__1,d__2);
+/* Computing MIN */
+	    d__1 = z__[(*n0 << 2) - *pp], d__2 = z__[(*i0 << 2) - *pp], d__1 =
+		     min(d__1,d__2), d__2 = z__[(*i0 << 2) - *pp + 4];
+	    z__[(*n0 << 2) - *pp] = min(d__1,d__2);
+/* Computing MAX */
+	    d__1 = *qmax, d__2 = z__[(*i0 << 2) + *pp - 3], d__1 = max(d__1,
+		    d__2), d__2 = z__[(*i0 << 2) + *pp + 1];
+	    *qmax = max(d__1,d__2);
+	    *dmin__ = -0.;
+	}
+    }
+
+/*     Choose a shift. */
+
+    igraphdlasq4_(i0, n0, &z__[1], pp, &n0in, dmin__, dmin1, dmin2, dn, dn1, dn2, 
+	    tau, ttype, g);
+
+/*     Call dqds until DMIN > 0. */
+
+L70:
+
+    igraphdlasq5_(i0, n0, &z__[1], pp, tau, dmin__, dmin1, dmin2, dn, dn1, dn2, 
+	    ieee);
+
+    *ndiv += *n0 - *i0 + 2;
+    ++(*iter);
+
+/*     Check status. */
+
+    if (*dmin__ >= 0. && *dmin1 > 0.) {
+
+/*        Success. */
+
+	goto L90;
+
+    } else if (*dmin__ < 0. && *dmin1 > 0. && z__[(*n0 - 1 << 2) - *pp] < tol 
+	    * (*sigma + *dn1) && abs(*dn) < tol * *sigma) {
+
+/*        Convergence hidden by negative DN. */
+
+	z__[(*n0 - 1 << 2) - *pp + 2] = 0.;
+	*dmin__ = 0.;
+	goto L90;
+    } else if (*dmin__ < 0.) {
+
+/*        TAU too big. Select new TAU and try again. */
+
+	++(*nfail);
+	if (*ttype < -22) {
+
+/*           Failed twice. Play it safe. */
+
+	    *tau = 0.;
+	} else if (*dmin1 > 0.) {
+
+/*           Late failure. Gives excellent shift. */
+
+	    *tau = (*tau + *dmin__) * (1. - eps * 2.);
+	    *ttype += -11;
+	} else {
+
+/*           Early failure. Divide by 4. */
+
+	    *tau *= .25;
+	    *ttype += -12;
+	}
+	goto L70;
+    } else if (igraphdisnan_(dmin__)) {
+
+/*        NaN. */
+
+	if (*tau == 0.) {
+	    goto L80;
+	} else {
+	    *tau = 0.;
+	    goto L70;
+	}
+    } else {
+
+/*        Possible underflow. Play it safe. */
+
+	goto L80;
+    }
+
+/*     Risk of underflow. */
+
+L80:
+    igraphdlasq6_(i0, n0, &z__[1], pp, dmin__, dmin1, dmin2, dn, dn1, dn2);
+    *ndiv += *n0 - *i0 + 2;
+    ++(*iter);
+    *tau = 0.;
+
+L90:
+    if (*tau < *sigma) {
+	*desig += *tau;
+	t = *sigma + *desig;
+	*desig -= t - *sigma;
+    } else {
+	t = *sigma + *tau;
+	*desig = *sigma - (t - *tau) + *desig;
+    }
+    *sigma = t;
+
+    return 0;
+
+/*     End of DLASQ3 */
+
+} /* igraphdlasq3_ */
+
diff --git a/src/lapack/dlasq4.c b/src/lapack/dlasq4.c
new file mode 100644
index 0000000..6172517
--- /dev/null
+++ b/src/lapack/dlasq4.c
@@ -0,0 +1,395 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlasq4_(integer *i0, integer *n0, doublereal *z__, 
+	integer *pp, integer *n0in, doublereal *dmin__, doublereal *dmin1, 
+	doublereal *dmin2, doublereal *dn, doublereal *dn1, doublereal *dn2, 
+	doublereal *tau, integer *ttype, doublereal *g)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    doublereal s, a2, b1, b2;
+    integer i4, nn, np;
+    doublereal gam, gap1, gap2;
+
+
+/*  -- LAPACK routine (version 3.3.1)                                    --   
+
+    -- Contributed by Osni Marques of the Lawrence Berkeley National   --   
+    -- Laboratory and Beresford Parlett of the Univ. of California at  --   
+    -- Berkeley                                                        --   
+    -- November 2008                                                   --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    DLASQ4 computes an approximation TAU to the smallest eigenvalue   
+    using values of d from the previous transform.   
+
+    Arguments   
+    =========   
+
+    I0    (input) INTEGER   
+          First index.   
+
+    N0    (input) INTEGER   
+          Last index.   
+
+    Z     (input) DOUBLE PRECISION array, dimension ( 4*N )   
+          Z holds the qd array.   
+
+    PP    (input) INTEGER   
+          PP=0 for ping, PP=1 for pong.   
+
+    NOIN  (input) INTEGER   
+          The value of N0 at start of EIGTEST.   
+
+    DMIN  (input) DOUBLE PRECISION   
+          Minimum value of d.   
+
+    DMIN1 (input) DOUBLE PRECISION   
+          Minimum value of d, excluding D( N0 ).   
+
+    DMIN2 (input) DOUBLE PRECISION   
+          Minimum value of d, excluding D( N0 ) and D( N0-1 ).   
+
+    DN    (input) DOUBLE PRECISION   
+          d(N)   
+
+    DN1   (input) DOUBLE PRECISION   
+          d(N-1)   
+
+    DN2   (input) DOUBLE PRECISION   
+          d(N-2)   
+
+    TAU   (output) DOUBLE PRECISION   
+          This is the shift.   
+
+    TTYPE (output) INTEGER   
+          Shift type.   
+
+    G     (input/output) REAL   
+          G is passed as an argument in order to save its value between   
+          calls to DLASQ4.   
+
+    Further Details   
+    ===============   
+    CNST1 = 9/16   
+
+    =====================================================================   
+
+
+       A negative DMIN forces the shift to take that absolute value   
+       TTYPE records the type of shift.   
+
+       Parameter adjustments */
+    --z__;
+
+    /* Function Body */
+    if (*dmin__ <= 0.) {
+	*tau = -(*dmin__);
+	*ttype = -1;
+	return 0;
+    }
+
+    nn = (*n0 << 2) + *pp;
+    if (*n0in == *n0) {
+
+/*        No eigenvalues deflated. */
+
+	if (*dmin__ == *dn || *dmin__ == *dn1) {
+
+	    b1 = sqrt(z__[nn - 3]) * sqrt(z__[nn - 5]);
+	    b2 = sqrt(z__[nn - 7]) * sqrt(z__[nn - 9]);
+	    a2 = z__[nn - 7] + z__[nn - 5];
+
+/*           Cases 2 and 3. */
+
+	    if (*dmin__ == *dn && *dmin1 == *dn1) {
+		gap2 = *dmin2 - a2 - *dmin2 * .25;
+		if (gap2 > 0. && gap2 > b2) {
+		    gap1 = a2 - *dn - b2 / gap2 * b2;
+		} else {
+		    gap1 = a2 - *dn - (b1 + b2);
+		}
+		if (gap1 > 0. && gap1 > b1) {
+/* Computing MAX */
+		    d__1 = *dn - b1 / gap1 * b1, d__2 = *dmin__ * .5;
+		    s = max(d__1,d__2);
+		    *ttype = -2;
+		} else {
+		    s = 0.;
+		    if (*dn > b1) {
+			s = *dn - b1;
+		    }
+		    if (a2 > b1 + b2) {
+/* Computing MIN */
+			d__1 = s, d__2 = a2 - (b1 + b2);
+			s = min(d__1,d__2);
+		    }
+/* Computing MAX */
+		    d__1 = s, d__2 = *dmin__ * .333;
+		    s = max(d__1,d__2);
+		    *ttype = -3;
+		}
+	    } else {
+
+/*              Case 4. */
+
+		*ttype = -4;
+		s = *dmin__ * .25;
+		if (*dmin__ == *dn) {
+		    gam = *dn;
+		    a2 = 0.;
+		    if (z__[nn - 5] > z__[nn - 7]) {
+			return 0;
+		    }
+		    b2 = z__[nn - 5] / z__[nn - 7];
+		    np = nn - 9;
+		} else {
+		    np = nn - (*pp << 1);
+		    b2 = z__[np - 2];
+		    gam = *dn1;
+		    if (z__[np - 4] > z__[np - 2]) {
+			return 0;
+		    }
+		    a2 = z__[np - 4] / z__[np - 2];
+		    if (z__[nn - 9] > z__[nn - 11]) {
+			return 0;
+		    }
+		    b2 = z__[nn - 9] / z__[nn - 11];
+		    np = nn - 13;
+		}
+
+/*              Approximate contribution to norm squared from I < NN-1. */
+
+		a2 += b2;
+		i__1 = (*i0 << 2) - 1 + *pp;
+		for (i4 = np; i4 >= i__1; i4 += -4) {
+		    if (b2 == 0.) {
+			goto L20;
+		    }
+		    b1 = b2;
+		    if (z__[i4] > z__[i4 - 2]) {
+			return 0;
+		    }
+		    b2 *= z__[i4] / z__[i4 - 2];
+		    a2 += b2;
+		    if (max(b2,b1) * 100. < a2 || .563 < a2) {
+			goto L20;
+		    }
+/* L10: */
+		}
+L20:
+		a2 *= 1.05;
+
+/*              Rayleigh quotient residual bound. */
+
+		if (a2 < .563) {
+		    s = gam * (1. - sqrt(a2)) / (a2 + 1.);
+		}
+	    }
+	} else if (*dmin__ == *dn2) {
+
+/*           Case 5. */
+
+	    *ttype = -5;
+	    s = *dmin__ * .25;
+
+/*           Compute contribution to norm squared from I > NN-2. */
+
+	    np = nn - (*pp << 1);
+	    b1 = z__[np - 2];
+	    b2 = z__[np - 6];
+	    gam = *dn2;
+	    if (z__[np - 8] > b2 || z__[np - 4] > b1) {
+		return 0;
+	    }
+	    a2 = z__[np - 8] / b2 * (z__[np - 4] / b1 + 1.);
+
+/*           Approximate contribution to norm squared from I < NN-2. */
+
+	    if (*n0 - *i0 > 2) {
+		b2 = z__[nn - 13] / z__[nn - 15];
+		a2 += b2;
+		i__1 = (*i0 << 2) - 1 + *pp;
+		for (i4 = nn - 17; i4 >= i__1; i4 += -4) {
+		    if (b2 == 0.) {
+			goto L40;
+		    }
+		    b1 = b2;
+		    if (z__[i4] > z__[i4 - 2]) {
+			return 0;
+		    }
+		    b2 *= z__[i4] / z__[i4 - 2];
+		    a2 += b2;
+		    if (max(b2,b1) * 100. < a2 || .563 < a2) {
+			goto L40;
+		    }
+/* L30: */
+		}
+L40:
+		a2 *= 1.05;
+	    }
+
+	    if (a2 < .563) {
+		s = gam * (1. - sqrt(a2)) / (a2 + 1.);
+	    }
+	} else {
+
+/*           Case 6, no information to guide us. */
+
+	    if (*ttype == -6) {
+		*g += (1. - *g) * .333;
+	    } else if (*ttype == -18) {
+		*g = .083250000000000005;
+	    } else {
+		*g = .25;
+	    }
+	    s = *g * *dmin__;
+	    *ttype = -6;
+	}
+
+    } else if (*n0in == *n0 + 1) {
+
+/*        One eigenvalue just deflated. Use DMIN1, DN1 for DMIN and DN. */
+
+	if (*dmin1 == *dn1 && *dmin2 == *dn2) {
+
+/*           Cases 7 and 8. */
+
+	    *ttype = -7;
+	    s = *dmin1 * .333;
+	    if (z__[nn - 5] > z__[nn - 7]) {
+		return 0;
+	    }
+	    b1 = z__[nn - 5] / z__[nn - 7];
+	    b2 = b1;
+	    if (b2 == 0.) {
+		goto L60;
+	    }
+	    i__1 = (*i0 << 2) - 1 + *pp;
+	    for (i4 = (*n0 << 2) - 9 + *pp; i4 >= i__1; i4 += -4) {
+		a2 = b1;
+		if (z__[i4] > z__[i4 - 2]) {
+		    return 0;
+		}
+		b1 *= z__[i4] / z__[i4 - 2];
+		b2 += b1;
+		if (max(b1,a2) * 100. < b2) {
+		    goto L60;
+		}
+/* L50: */
+	    }
+L60:
+	    b2 = sqrt(b2 * 1.05);
+/* Computing 2nd power */
+	    d__1 = b2;
+	    a2 = *dmin1 / (d__1 * d__1 + 1.);
+	    gap2 = *dmin2 * .5 - a2;
+	    if (gap2 > 0. && gap2 > b2 * a2) {
+/* Computing MAX */
+		d__1 = s, d__2 = a2 * (1. - a2 * 1.01 * (b2 / gap2) * b2);
+		s = max(d__1,d__2);
+	    } else {
+/* Computing MAX */
+		d__1 = s, d__2 = a2 * (1. - b2 * 1.01);
+		s = max(d__1,d__2);
+		*ttype = -8;
+	    }
+	} else {
+
+/*           Case 9. */
+
+	    s = *dmin1 * .25;
+	    if (*dmin1 == *dn1) {
+		s = *dmin1 * .5;
+	    }
+	    *ttype = -9;
+	}
+
+    } else if (*n0in == *n0 + 2) {
+
+/*        Two eigenvalues deflated. Use DMIN2, DN2 for DMIN and DN.   
+
+          Cases 10 and 11. */
+
+	if (*dmin2 == *dn2 && z__[nn - 5] * 2. < z__[nn - 7]) {
+	    *ttype = -10;
+	    s = *dmin2 * .333;
+	    if (z__[nn - 5] > z__[nn - 7]) {
+		return 0;
+	    }
+	    b1 = z__[nn - 5] / z__[nn - 7];
+	    b2 = b1;
+	    if (b2 == 0.) {
+		goto L80;
+	    }
+	    i__1 = (*i0 << 2) - 1 + *pp;
+	    for (i4 = (*n0 << 2) - 9 + *pp; i4 >= i__1; i4 += -4) {
+		if (z__[i4] > z__[i4 - 2]) {
+		    return 0;
+		}
+		b1 *= z__[i4] / z__[i4 - 2];
+		b2 += b1;
+		if (b1 * 100. < b2) {
+		    goto L80;
+		}
+/* L70: */
+	    }
+L80:
+	    b2 = sqrt(b2 * 1.05);
+/* Computing 2nd power */
+	    d__1 = b2;
+	    a2 = *dmin2 / (d__1 * d__1 + 1.);
+	    gap2 = z__[nn - 7] + z__[nn - 9] - sqrt(z__[nn - 11]) * sqrt(z__[
+		    nn - 9]) - a2;
+	    if (gap2 > 0. && gap2 > b2 * a2) {
+/* Computing MAX */
+		d__1 = s, d__2 = a2 * (1. - a2 * 1.01 * (b2 / gap2) * b2);
+		s = max(d__1,d__2);
+	    } else {
+/* Computing MAX */
+		d__1 = s, d__2 = a2 * (1. - b2 * 1.01);
+		s = max(d__1,d__2);
+	    }
+	} else {
+	    s = *dmin2 * .25;
+	    *ttype = -11;
+	}
+    } else if (*n0in > *n0 + 2) {
+
+/*        Case 12, more than two eigenvalues deflated. No information. */
+
+	s = 0.;
+	*ttype = -12;
+    }
+
+    *tau = s;
+    return 0;
+
+/*     End of DLASQ4 */
+
+} /* igraphdlasq4_ */
+
diff --git a/src/lapack/dlasq5.c b/src/lapack/dlasq5.c
new file mode 100644
index 0000000..ce69819
--- /dev/null
+++ b/src/lapack/dlasq5.c
@@ -0,0 +1,229 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlasq5_(integer *i0, integer *n0, doublereal *z__, 
+	integer *pp, doublereal *tau, doublereal *dmin__, doublereal *dmin1, 
+	doublereal *dmin2, doublereal *dn, doublereal *dnm1, doublereal *dnm2,
+	 logical *ieee)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    doublereal d__;
+    integer j4, j4p2;
+    doublereal emin, temp;
+
+
+/*  -- LAPACK routine (version 3.2)                                    --   
+
+    -- Contributed by Osni Marques of the Lawrence Berkeley National   --   
+    -- Laboratory and Beresford Parlett of the Univ. of California at  --   
+    -- Berkeley                                                        --   
+    -- November 2008                                                   --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    DLASQ5 computes one dqds transform in ping-pong form, one   
+    version for IEEE machines another for non IEEE machines.   
+
+    Arguments   
+    =========   
+
+    I0    (input) INTEGER   
+          First index.   
+
+    N0    (input) INTEGER   
+          Last index.   
+
+    Z     (input) DOUBLE PRECISION array, dimension ( 4*N )   
+          Z holds the qd array. EMIN is stored in Z(4*N0) to avoid   
+          an extra argument.   
+
+    PP    (input) INTEGER   
+          PP=0 for ping, PP=1 for pong.   
+
+    TAU   (input) DOUBLE PRECISION   
+          This is the shift.   
+
+    DMIN  (output) DOUBLE PRECISION   
+          Minimum value of d.   
+
+    DMIN1 (output) DOUBLE PRECISION   
+          Minimum value of d, excluding D( N0 ).   
+
+    DMIN2 (output) DOUBLE PRECISION   
+          Minimum value of d, excluding D( N0 ) and D( N0-1 ).   
+
+    DN    (output) DOUBLE PRECISION   
+          d(N0), the last value of d.   
+
+    DNM1  (output) DOUBLE PRECISION   
+          d(N0-1).   
+
+    DNM2  (output) DOUBLE PRECISION   
+          d(N0-2).   
+
+    IEEE  (input) LOGICAL   
+          Flag for IEEE or non IEEE arithmetic.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --z__;
+
+    /* Function Body */
+    if (*n0 - *i0 - 1 <= 0) {
+	return 0;
+    }
+
+    j4 = (*i0 << 2) + *pp - 3;
+    emin = z__[j4 + 4];
+    d__ = z__[j4] - *tau;
+    *dmin__ = d__;
+    *dmin1 = -z__[j4];
+
+    if (*ieee) {
+
+/*        Code for IEEE arithmetic. */
+
+	if (*pp == 0) {
+	    i__1 = *n0 - 3 << 2;
+	    for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+		z__[j4 - 2] = d__ + z__[j4 - 1];
+		temp = z__[j4 + 1] / z__[j4 - 2];
+		d__ = d__ * temp - *tau;
+		*dmin__ = min(*dmin__,d__);
+		z__[j4] = z__[j4 - 1] * temp;
+/* Computing MIN */
+		d__1 = z__[j4];
+		emin = min(d__1,emin);
+/* L10: */
+	    }
+	} else {
+	    i__1 = *n0 - 3 << 2;
+	    for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+		z__[j4 - 3] = d__ + z__[j4];
+		temp = z__[j4 + 2] / z__[j4 - 3];
+		d__ = d__ * temp - *tau;
+		*dmin__ = min(*dmin__,d__);
+		z__[j4 - 1] = z__[j4] * temp;
+/* Computing MIN */
+		d__1 = z__[j4 - 1];
+		emin = min(d__1,emin);
+/* L20: */
+	    }
+	}
+
+/*        Unroll last two steps. */
+
+	*dnm2 = d__;
+	*dmin2 = *dmin__;
+	j4 = (*n0 - 2 << 2) - *pp;
+	j4p2 = j4 + (*pp << 1) - 1;
+	z__[j4 - 2] = *dnm2 + z__[j4p2];
+	z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]);
+	*dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]) - *tau;
+	*dmin__ = min(*dmin__,*dnm1);
+
+	*dmin1 = *dmin__;
+	j4 += 4;
+	j4p2 = j4 + (*pp << 1) - 1;
+	z__[j4 - 2] = *dnm1 + z__[j4p2];
+	z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]);
+	*dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]) - *tau;
+	*dmin__ = min(*dmin__,*dn);
+
+    } else {
+
+/*        Code for non IEEE arithmetic. */
+
+	if (*pp == 0) {
+	    i__1 = *n0 - 3 << 2;
+	    for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+		z__[j4 - 2] = d__ + z__[j4 - 1];
+		if (d__ < 0.) {
+		    return 0;
+		} else {
+		    z__[j4] = z__[j4 + 1] * (z__[j4 - 1] / z__[j4 - 2]);
+		    d__ = z__[j4 + 1] * (d__ / z__[j4 - 2]) - *tau;
+		}
+		*dmin__ = min(*dmin__,d__);
+/* Computing MIN */
+		d__1 = emin, d__2 = z__[j4];
+		emin = min(d__1,d__2);
+/* L30: */
+	    }
+	} else {
+	    i__1 = *n0 - 3 << 2;
+	    for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+		z__[j4 - 3] = d__ + z__[j4];
+		if (d__ < 0.) {
+		    return 0;
+		} else {
+		    z__[j4 - 1] = z__[j4 + 2] * (z__[j4] / z__[j4 - 3]);
+		    d__ = z__[j4 + 2] * (d__ / z__[j4 - 3]) - *tau;
+		}
+		*dmin__ = min(*dmin__,d__);
+/* Computing MIN */
+		d__1 = emin, d__2 = z__[j4 - 1];
+		emin = min(d__1,d__2);
+/* L40: */
+	    }
+	}
+
+/*        Unroll last two steps. */
+
+	*dnm2 = d__;
+	*dmin2 = *dmin__;
+	j4 = (*n0 - 2 << 2) - *pp;
+	j4p2 = j4 + (*pp << 1) - 1;
+	z__[j4 - 2] = *dnm2 + z__[j4p2];
+	if (*dnm2 < 0.) {
+	    return 0;
+	} else {
+	    z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]);
+	    *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]) - *tau;
+	}
+	*dmin__ = min(*dmin__,*dnm1);
+
+	*dmin1 = *dmin__;
+	j4 += 4;
+	j4p2 = j4 + (*pp << 1) - 1;
+	z__[j4 - 2] = *dnm1 + z__[j4p2];
+	if (*dnm1 < 0.) {
+	    return 0;
+	} else {
+	    z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]);
+	    *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]) - *tau;
+	}
+	*dmin__ = min(*dmin__,*dn);
+
+    }
+
+    z__[j4 + 2] = *dn;
+    z__[(*n0 << 2) - *pp] = emin;
+    return 0;
+
+/*     End of DLASQ5 */
+
+} /* igraphdlasq5_ */
+
diff --git a/src/lapack/dlasq6.c b/src/lapack/dlasq6.c
new file mode 100644
index 0000000..571ae1b
--- /dev/null
+++ b/src/lapack/dlasq6.c
@@ -0,0 +1,199 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlasq6_(integer *i0, integer *n0, doublereal *z__, 
+	integer *pp, doublereal *dmin__, doublereal *dmin1, doublereal *dmin2,
+	 doublereal *dn, doublereal *dnm1, doublereal *dnm2)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    doublereal d__;
+    integer j4, j4p2;
+    doublereal emin, temp;
+    extern doublereal igraphdlamch_(char *);
+    doublereal safmin;
+
+
+/*  -- LAPACK routine (version 3.2)                                    --   
+
+    -- Contributed by Osni Marques of the Lawrence Berkeley National   --   
+    -- Laboratory and Beresford Parlett of the Univ. of California at  --   
+    -- Berkeley                                                        --   
+    -- November 2008                                                   --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    DLASQ6 computes one dqd (shift equal to zero) transform in   
+    ping-pong form, with protection against underflow and overflow.   
+
+    Arguments   
+    =========   
+
+    I0    (input) INTEGER   
+          First index.   
+
+    N0    (input) INTEGER   
+          Last index.   
+
+    Z     (input) DOUBLE PRECISION array, dimension ( 4*N )   
+          Z holds the qd array. EMIN is stored in Z(4*N0) to avoid   
+          an extra argument.   
+
+    PP    (input) INTEGER   
+          PP=0 for ping, PP=1 for pong.   
+
+    DMIN  (output) DOUBLE PRECISION   
+          Minimum value of d.   
+
+    DMIN1 (output) DOUBLE PRECISION   
+          Minimum value of d, excluding D( N0 ).   
+
+    DMIN2 (output) DOUBLE PRECISION   
+          Minimum value of d, excluding D( N0 ) and D( N0-1 ).   
+
+    DN    (output) DOUBLE PRECISION   
+          d(N0), the last value of d.   
+
+    DNM1  (output) DOUBLE PRECISION   
+          d(N0-1).   
+
+    DNM2  (output) DOUBLE PRECISION   
+          d(N0-2).   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --z__;
+
+    /* Function Body */
+    if (*n0 - *i0 - 1 <= 0) {
+	return 0;
+    }
+
+    safmin = igraphdlamch_("Safe minimum");
+    j4 = (*i0 << 2) + *pp - 3;
+    emin = z__[j4 + 4];
+    d__ = z__[j4];
+    *dmin__ = d__;
+
+    if (*pp == 0) {
+	i__1 = *n0 - 3 << 2;
+	for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+	    z__[j4 - 2] = d__ + z__[j4 - 1];
+	    if (z__[j4 - 2] == 0.) {
+		z__[j4] = 0.;
+		d__ = z__[j4 + 1];
+		*dmin__ = d__;
+		emin = 0.;
+	    } else if (safmin * z__[j4 + 1] < z__[j4 - 2] && safmin * z__[j4 
+		    - 2] < z__[j4 + 1]) {
+		temp = z__[j4 + 1] / z__[j4 - 2];
+		z__[j4] = z__[j4 - 1] * temp;
+		d__ *= temp;
+	    } else {
+		z__[j4] = z__[j4 + 1] * (z__[j4 - 1] / z__[j4 - 2]);
+		d__ = z__[j4 + 1] * (d__ / z__[j4 - 2]);
+	    }
+	    *dmin__ = min(*dmin__,d__);
+/* Computing MIN */
+	    d__1 = emin, d__2 = z__[j4];
+	    emin = min(d__1,d__2);
+/* L10: */
+	}
+    } else {
+	i__1 = *n0 - 3 << 2;
+	for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) {
+	    z__[j4 - 3] = d__ + z__[j4];
+	    if (z__[j4 - 3] == 0.) {
+		z__[j4 - 1] = 0.;
+		d__ = z__[j4 + 2];
+		*dmin__ = d__;
+		emin = 0.;
+	    } else if (safmin * z__[j4 + 2] < z__[j4 - 3] && safmin * z__[j4 
+		    - 3] < z__[j4 + 2]) {
+		temp = z__[j4 + 2] / z__[j4 - 3];
+		z__[j4 - 1] = z__[j4] * temp;
+		d__ *= temp;
+	    } else {
+		z__[j4 - 1] = z__[j4 + 2] * (z__[j4] / z__[j4 - 3]);
+		d__ = z__[j4 + 2] * (d__ / z__[j4 - 3]);
+	    }
+	    *dmin__ = min(*dmin__,d__);
+/* Computing MIN */
+	    d__1 = emin, d__2 = z__[j4 - 1];
+	    emin = min(d__1,d__2);
+/* L20: */
+	}
+    }
+
+/*     Unroll last two steps. */
+
+    *dnm2 = d__;
+    *dmin2 = *dmin__;
+    j4 = (*n0 - 2 << 2) - *pp;
+    j4p2 = j4 + (*pp << 1) - 1;
+    z__[j4 - 2] = *dnm2 + z__[j4p2];
+    if (z__[j4 - 2] == 0.) {
+	z__[j4] = 0.;
+	*dnm1 = z__[j4p2 + 2];
+	*dmin__ = *dnm1;
+	emin = 0.;
+    } else if (safmin * z__[j4p2 + 2] < z__[j4 - 2] && safmin * z__[j4 - 2] < 
+	    z__[j4p2 + 2]) {
+	temp = z__[j4p2 + 2] / z__[j4 - 2];
+	z__[j4] = z__[j4p2] * temp;
+	*dnm1 = *dnm2 * temp;
+    } else {
+	z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]);
+	*dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]);
+    }
+    *dmin__ = min(*dmin__,*dnm1);
+
+    *dmin1 = *dmin__;
+    j4 += 4;
+    j4p2 = j4 + (*pp << 1) - 1;
+    z__[j4 - 2] = *dnm1 + z__[j4p2];
+    if (z__[j4 - 2] == 0.) {
+	z__[j4] = 0.;
+	*dn = z__[j4p2 + 2];
+	*dmin__ = *dn;
+	emin = 0.;
+    } else if (safmin * z__[j4p2 + 2] < z__[j4 - 2] && safmin * z__[j4 - 2] < 
+	    z__[j4p2 + 2]) {
+	temp = z__[j4p2 + 2] / z__[j4 - 2];
+	z__[j4] = z__[j4p2] * temp;
+	*dn = *dnm1 * temp;
+    } else {
+	z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]);
+	*dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]);
+    }
+    *dmin__ = min(*dmin__,*dn);
+
+    z__[j4 + 2] = *dn;
+    z__[(*n0 << 2) - *pp] = emin;
+    return 0;
+
+/*     End of DLASQ6 */
+
+} /* igraphdlasq6_ */
+
diff --git a/src/lapack/dlasr.c b/src/lapack/dlasr.c
new file mode 100644
index 0000000..59bc1ea
--- /dev/null
+++ b/src/lapack/dlasr.c
@@ -0,0 +1,439 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlasr_(char *side, char *pivot, char *direct, integer *m,
+	 integer *n, doublereal *c__, doublereal *s, doublereal *a, integer *
+	lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, info;
+    doublereal temp;
+    extern logical igraphlsame_(char *, char *);
+    doublereal ctemp, stemp;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLASR applies a sequence of plane rotations to a real matrix A,   
+    from either the left or the right.   
+
+    When SIDE = 'L', the transformation takes the form   
+
+       A := P*A   
+
+    and when SIDE = 'R', the transformation takes the form   
+
+       A := A*P**T   
+
+    where P is an orthogonal matrix consisting of a sequence of z plane   
+    rotations, with z = M when SIDE = 'L' and z = N when SIDE = 'R',   
+    and P**T is the transpose of P.   
+
+    When DIRECT = 'F' (Forward sequence), then   
+
+       P = P(z-1) * ... * P(2) * P(1)   
+
+    and when DIRECT = 'B' (Backward sequence), then   
+
+       P = P(1) * P(2) * ... * P(z-1)   
+
+    where P(k) is a plane rotation matrix defined by the 2-by-2 rotation   
+
+       R(k) = (  c(k)  s(k) )   
+            = ( -s(k)  c(k) ).   
+
+    When PIVOT = 'V' (Variable pivot), the rotation is performed   
+    for the plane (k,k+1), i.e., P(k) has the form   
+
+       P(k) = (  1                                            )   
+              (       ...                                     )   
+              (              1                                )   
+              (                   c(k)  s(k)                  )   
+              (                  -s(k)  c(k)                  )   
+              (                                1              )   
+              (                                     ...       )   
+              (                                            1  )   
+
+    where R(k) appears as a rank-2 modification to the identity matrix in   
+    rows and columns k and k+1.   
+
+    When PIVOT = 'T' (Top pivot), the rotation is performed for the   
+    plane (1,k+1), so P(k) has the form   
+
+       P(k) = (  c(k)                    s(k)                 )   
+              (         1                                     )   
+              (              ...                              )   
+              (                     1                         )   
+              ( -s(k)                    c(k)                 )   
+              (                                 1             )   
+              (                                      ...      )   
+              (                                             1 )   
+
+    where R(k) appears in rows and columns 1 and k+1.   
+
+    Similarly, when PIVOT = 'B' (Bottom pivot), the rotation is   
+    performed for the plane (k,z), giving P(k) the form   
+
+       P(k) = ( 1                                             )   
+              (      ...                                      )   
+              (             1                                 )   
+              (                  c(k)                    s(k) )   
+              (                         1                     )   
+              (                              ...              )   
+              (                                     1         )   
+              (                 -s(k)                    c(k) )   
+
+    where R(k) appears in rows and columns k and z.  The rotations are   
+    performed without ever forming P(k) explicitly.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            Specifies whether the plane rotation matrix P is applied to   
+            A on the left or the right.   
+            = 'L':  Left, compute A := P*A   
+            = 'R':  Right, compute A:= A*P**T   
+
+    PIVOT   (input) CHARACTER*1   
+            Specifies the plane for which P(k) is a plane rotation   
+            matrix.   
+            = 'V':  Variable pivot, the plane (k,k+1)   
+            = 'T':  Top pivot, the plane (1,k+1)   
+            = 'B':  Bottom pivot, the plane (k,z)   
+
+    DIRECT  (input) CHARACTER*1   
+            Specifies whether P is a forward or backward sequence of   
+            plane rotations.   
+            = 'F':  Forward, P = P(z-1)*...*P(2)*P(1)   
+            = 'B':  Backward, P = P(1)*P(2)*...*P(z-1)   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.  If m <= 1, an immediate   
+            return is effected.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.  If n <= 1, an   
+            immediate return is effected.   
+
+    C       (input) DOUBLE PRECISION array, dimension   
+                    (M-1) if SIDE = 'L'   
+                    (N-1) if SIDE = 'R'   
+            The cosines c(k) of the plane rotations.   
+
+    S       (input) DOUBLE PRECISION array, dimension   
+                    (M-1) if SIDE = 'L'   
+                    (N-1) if SIDE = 'R'   
+            The sines s(k) of the plane rotations.  The 2-by-2 plane   
+            rotation part of the matrix P(k), R(k), has the form   
+            R(k) = (  c(k)  s(k) )   
+                   ( -s(k)  c(k) ).   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            The M-by-N matrix A.  On exit, A is overwritten by P*A if   
+            SIDE = 'R' or by A*P**T if SIDE = 'L'.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,M).   
+
+    =====================================================================   
+
+
+       Test the input parameters   
+
+       Parameter adjustments */
+    --c__;
+    --s;
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    info = 0;
+    if (! (igraphlsame_(side, "L") || igraphlsame_(side, "R"))) {
+	info = 1;
+    } else if (! (igraphlsame_(pivot, "V") || igraphlsame_(pivot, 
+	    "T") || igraphlsame_(pivot, "B"))) {
+	info = 2;
+    } else if (! (igraphlsame_(direct, "F") || igraphlsame_(direct, 
+	    "B"))) {
+	info = 3;
+    } else if (*m < 0) {
+	info = 4;
+    } else if (*n < 0) {
+	info = 5;
+    } else if (*lda < max(1,*m)) {
+	info = 9;
+    }
+    if (info != 0) {
+	igraphxerbla_("DLASR ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+    if (igraphlsame_(side, "L")) {
+
+/*        Form  P * A */
+
+	if (igraphlsame_(pivot, "V")) {
+	    if (igraphlsame_(direct, "F")) {
+		i__1 = *m - 1;
+		for (j = 1; j <= i__1; ++j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__2 = *n;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    temp = a[j + 1 + i__ * a_dim1];
+			    a[j + 1 + i__ * a_dim1] = ctemp * temp - stemp * 
+				    a[j + i__ * a_dim1];
+			    a[j + i__ * a_dim1] = stemp * temp + ctemp * a[j 
+				    + i__ * a_dim1];
+/* L10: */
+			}
+		    }
+/* L20: */
+		}
+	    } else if (igraphlsame_(direct, "B")) {
+		for (j = *m - 1; j >= 1; --j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__1 = *n;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    temp = a[j + 1 + i__ * a_dim1];
+			    a[j + 1 + i__ * a_dim1] = ctemp * temp - stemp * 
+				    a[j + i__ * a_dim1];
+			    a[j + i__ * a_dim1] = stemp * temp + ctemp * a[j 
+				    + i__ * a_dim1];
+/* L30: */
+			}
+		    }
+/* L40: */
+		}
+	    }
+	} else if (igraphlsame_(pivot, "T")) {
+	    if (igraphlsame_(direct, "F")) {
+		i__1 = *m;
+		for (j = 2; j <= i__1; ++j) {
+		    ctemp = c__[j - 1];
+		    stemp = s[j - 1];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__2 = *n;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    temp = a[j + i__ * a_dim1];
+			    a[j + i__ * a_dim1] = ctemp * temp - stemp * a[
+				    i__ * a_dim1 + 1];
+			    a[i__ * a_dim1 + 1] = stemp * temp + ctemp * a[
+				    i__ * a_dim1 + 1];
+/* L50: */
+			}
+		    }
+/* L60: */
+		}
+	    } else if (igraphlsame_(direct, "B")) {
+		for (j = *m; j >= 2; --j) {
+		    ctemp = c__[j - 1];
+		    stemp = s[j - 1];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__1 = *n;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    temp = a[j + i__ * a_dim1];
+			    a[j + i__ * a_dim1] = ctemp * temp - stemp * a[
+				    i__ * a_dim1 + 1];
+			    a[i__ * a_dim1 + 1] = stemp * temp + ctemp * a[
+				    i__ * a_dim1 + 1];
+/* L70: */
+			}
+		    }
+/* L80: */
+		}
+	    }
+	} else if (igraphlsame_(pivot, "B")) {
+	    if (igraphlsame_(direct, "F")) {
+		i__1 = *m - 1;
+		for (j = 1; j <= i__1; ++j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__2 = *n;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    temp = a[j + i__ * a_dim1];
+			    a[j + i__ * a_dim1] = stemp * a[*m + i__ * a_dim1]
+				     + ctemp * temp;
+			    a[*m + i__ * a_dim1] = ctemp * a[*m + i__ * 
+				    a_dim1] - stemp * temp;
+/* L90: */
+			}
+		    }
+/* L100: */
+		}
+	    } else if (igraphlsame_(direct, "B")) {
+		for (j = *m - 1; j >= 1; --j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__1 = *n;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    temp = a[j + i__ * a_dim1];
+			    a[j + i__ * a_dim1] = stemp * a[*m + i__ * a_dim1]
+				     + ctemp * temp;
+			    a[*m + i__ * a_dim1] = ctemp * a[*m + i__ * 
+				    a_dim1] - stemp * temp;
+/* L110: */
+			}
+		    }
+/* L120: */
+		}
+	    }
+	}
+    } else if (igraphlsame_(side, "R")) {
+
+/*        Form A * P**T */
+
+	if (igraphlsame_(pivot, "V")) {
+	    if (igraphlsame_(direct, "F")) {
+		i__1 = *n - 1;
+		for (j = 1; j <= i__1; ++j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    temp = a[i__ + (j + 1) * a_dim1];
+			    a[i__ + (j + 1) * a_dim1] = ctemp * temp - stemp *
+				     a[i__ + j * a_dim1];
+			    a[i__ + j * a_dim1] = stemp * temp + ctemp * a[
+				    i__ + j * a_dim1];
+/* L130: */
+			}
+		    }
+/* L140: */
+		}
+	    } else if (igraphlsame_(direct, "B")) {
+		for (j = *n - 1; j >= 1; --j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    temp = a[i__ + (j + 1) * a_dim1];
+			    a[i__ + (j + 1) * a_dim1] = ctemp * temp - stemp *
+				     a[i__ + j * a_dim1];
+			    a[i__ + j * a_dim1] = stemp * temp + ctemp * a[
+				    i__ + j * a_dim1];
+/* L150: */
+			}
+		    }
+/* L160: */
+		}
+	    }
+	} else if (igraphlsame_(pivot, "T")) {
+	    if (igraphlsame_(direct, "F")) {
+		i__1 = *n;
+		for (j = 2; j <= i__1; ++j) {
+		    ctemp = c__[j - 1];
+		    stemp = s[j - 1];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    temp = a[i__ + j * a_dim1];
+			    a[i__ + j * a_dim1] = ctemp * temp - stemp * a[
+				    i__ + a_dim1];
+			    a[i__ + a_dim1] = stemp * temp + ctemp * a[i__ + 
+				    a_dim1];
+/* L170: */
+			}
+		    }
+/* L180: */
+		}
+	    } else if (igraphlsame_(direct, "B")) {
+		for (j = *n; j >= 2; --j) {
+		    ctemp = c__[j - 1];
+		    stemp = s[j - 1];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    temp = a[i__ + j * a_dim1];
+			    a[i__ + j * a_dim1] = ctemp * temp - stemp * a[
+				    i__ + a_dim1];
+			    a[i__ + a_dim1] = stemp * temp + ctemp * a[i__ + 
+				    a_dim1];
+/* L190: */
+			}
+		    }
+/* L200: */
+		}
+	    }
+	} else if (igraphlsame_(pivot, "B")) {
+	    if (igraphlsame_(direct, "F")) {
+		i__1 = *n - 1;
+		for (j = 1; j <= i__1; ++j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    temp = a[i__ + j * a_dim1];
+			    a[i__ + j * a_dim1] = stemp * a[i__ + *n * a_dim1]
+				     + ctemp * temp;
+			    a[i__ + *n * a_dim1] = ctemp * a[i__ + *n * 
+				    a_dim1] - stemp * temp;
+/* L210: */
+			}
+		    }
+/* L220: */
+		}
+	    } else if (igraphlsame_(direct, "B")) {
+		for (j = *n - 1; j >= 1; --j) {
+		    ctemp = c__[j];
+		    stemp = s[j];
+		    if (ctemp != 1. || stemp != 0.) {
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    temp = a[i__ + j * a_dim1];
+			    a[i__ + j * a_dim1] = stemp * a[i__ + *n * a_dim1]
+				     + ctemp * temp;
+			    a[i__ + *n * a_dim1] = ctemp * a[i__ + *n * 
+				    a_dim1] - stemp * temp;
+/* L230: */
+			}
+		    }
+/* L240: */
+		}
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DLASR */
+
+} /* igraphdlasr_ */
+
diff --git a/src/lapack/dlasrt.c b/src/lapack/dlasrt.c
new file mode 100644
index 0000000..54b02b1
--- /dev/null
+++ b/src/lapack/dlasrt.c
@@ -0,0 +1,272 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlasrt_(char *id, integer *n, doublereal *d__, integer *
+	info)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+
+    /* Local variables */
+    integer i__, j;
+    doublereal d1, d2, d3;
+    integer dir;
+    doublereal tmp;
+    integer endd;
+    extern logical igraphlsame_(char *, char *);
+    integer stack[64]	/* was [2][32] */;
+    doublereal dmnmx;
+    integer start;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    integer stkpnt;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    Sort the numbers in D in increasing order (if ID = 'I') or   
+    in decreasing order (if ID = 'D' ).   
+
+    Use Quick Sort, reverting to Insertion sort on arrays of   
+    size <= 20. Dimension of STACK limits N to about 2**32.   
+
+    Arguments   
+    =========   
+
+    ID      (input) CHARACTER*1   
+            = 'I': sort D in increasing order;   
+            = 'D': sort D in decreasing order.   
+
+    N       (input) INTEGER   
+            The length of the array D.   
+
+    D       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the array to be sorted.   
+            On exit, D has been sorted into increasing order   
+            (D(1) <= ... <= D(N) ) or into decreasing order   
+            (D(1) >= ... >= D(N) ), depending on ID.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input paramters.   
+
+       Parameter adjustments */
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+    dir = -1;
+    if (igraphlsame_(id, "D")) {
+	dir = 0;
+    } else if (igraphlsame_(id, "I")) {
+	dir = 1;
+    }
+    if (dir == -1) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DLASRT", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n <= 1) {
+	return 0;
+    }
+
+    stkpnt = 1;
+    stack[0] = 1;
+    stack[1] = *n;
+L10:
+    start = stack[(stkpnt << 1) - 2];
+    endd = stack[(stkpnt << 1) - 1];
+    --stkpnt;
+    if (endd - start <= 20 && endd - start > 0) {
+
+/*        Do Insertion sort on D( START:ENDD ) */
+
+	if (dir == 0) {
+
+/*           Sort into decreasing order */
+
+	    i__1 = endd;
+	    for (i__ = start + 1; i__ <= i__1; ++i__) {
+		i__2 = start + 1;
+		for (j = i__; j >= i__2; --j) {
+		    if (d__[j] > d__[j - 1]) {
+			dmnmx = d__[j];
+			d__[j] = d__[j - 1];
+			d__[j - 1] = dmnmx;
+		    } else {
+			goto L30;
+		    }
+/* L20: */
+		}
+L30:
+		;
+	    }
+
+	} else {
+
+/*           Sort into increasing order */
+
+	    i__1 = endd;
+	    for (i__ = start + 1; i__ <= i__1; ++i__) {
+		i__2 = start + 1;
+		for (j = i__; j >= i__2; --j) {
+		    if (d__[j] < d__[j - 1]) {
+			dmnmx = d__[j];
+			d__[j] = d__[j - 1];
+			d__[j - 1] = dmnmx;
+		    } else {
+			goto L50;
+		    }
+/* L40: */
+		}
+L50:
+		;
+	    }
+
+	}
+
+    } else if (endd - start > 20) {
+
+/*        Partition D( START:ENDD ) and stack parts, largest one first   
+
+          Choose partition entry as median of 3 */
+
+	d1 = d__[start];
+	d2 = d__[endd];
+	i__ = (start + endd) / 2;
+	d3 = d__[i__];
+	if (d1 < d2) {
+	    if (d3 < d1) {
+		dmnmx = d1;
+	    } else if (d3 < d2) {
+		dmnmx = d3;
+	    } else {
+		dmnmx = d2;
+	    }
+	} else {
+	    if (d3 < d2) {
+		dmnmx = d2;
+	    } else if (d3 < d1) {
+		dmnmx = d3;
+	    } else {
+		dmnmx = d1;
+	    }
+	}
+
+	if (dir == 0) {
+
+/*           Sort into decreasing order */
+
+	    i__ = start - 1;
+	    j = endd + 1;
+L60:
+L70:
+	    --j;
+	    if (d__[j] < dmnmx) {
+		goto L70;
+	    }
+L80:
+	    ++i__;
+	    if (d__[i__] > dmnmx) {
+		goto L80;
+	    }
+	    if (i__ < j) {
+		tmp = d__[i__];
+		d__[i__] = d__[j];
+		d__[j] = tmp;
+		goto L60;
+	    }
+	    if (j - start > endd - j - 1) {
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = start;
+		stack[(stkpnt << 1) - 1] = j;
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = j + 1;
+		stack[(stkpnt << 1) - 1] = endd;
+	    } else {
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = j + 1;
+		stack[(stkpnt << 1) - 1] = endd;
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = start;
+		stack[(stkpnt << 1) - 1] = j;
+	    }
+	} else {
+
+/*           Sort into increasing order */
+
+	    i__ = start - 1;
+	    j = endd + 1;
+L90:
+L100:
+	    --j;
+	    if (d__[j] > dmnmx) {
+		goto L100;
+	    }
+L110:
+	    ++i__;
+	    if (d__[i__] < dmnmx) {
+		goto L110;
+	    }
+	    if (i__ < j) {
+		tmp = d__[i__];
+		d__[i__] = d__[j];
+		d__[j] = tmp;
+		goto L90;
+	    }
+	    if (j - start > endd - j - 1) {
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = start;
+		stack[(stkpnt << 1) - 1] = j;
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = j + 1;
+		stack[(stkpnt << 1) - 1] = endd;
+	    } else {
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = j + 1;
+		stack[(stkpnt << 1) - 1] = endd;
+		++stkpnt;
+		stack[(stkpnt << 1) - 2] = start;
+		stack[(stkpnt << 1) - 1] = j;
+	    }
+	}
+    }
+    if (stkpnt > 0) {
+	goto L10;
+    }
+    return 0;
+
+/*     End of DLASRT */
+
+} /* igraphdlasrt_ */
+
diff --git a/src/lapack/dlassq.c b/src/lapack/dlassq.c
new file mode 100644
index 0000000..d76270d
--- /dev/null
+++ b/src/lapack/dlassq.c
@@ -0,0 +1,106 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlassq_(integer *n, doublereal *x, integer *incx, 
+	doublereal *scale, doublereal *sumsq)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+    doublereal d__1;
+
+    /* Local variables */
+    integer ix;
+    doublereal absxi;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLASSQ  returns the values  scl  and  smsq  such that   
+
+       ( scl**2 )*smsq = x( 1 )**2 +...+ x( n )**2 + ( scale**2 )*sumsq,   
+
+    where  x( i ) = X( 1 + ( i - 1 )*INCX ). The value of  sumsq  is   
+    assumed to be non-negative and  scl  returns the value   
+
+       scl = max( scale, abs( x( i ) ) ).   
+
+    scale and sumsq must be supplied in SCALE and SUMSQ and   
+    scl and smsq are overwritten on SCALE and SUMSQ respectively.   
+
+    The routine makes only one pass through the vector x.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The number of elements to be used from the vector X.   
+
+    X       (input) DOUBLE PRECISION array, dimension (N)   
+            The vector for which a scaled sum of squares is computed.   
+               x( i )  = X( 1 + ( i - 1 )*INCX ), 1 <= i <= n.   
+
+    INCX    (input) INTEGER   
+            The increment between successive values of the vector X.   
+            INCX > 0.   
+
+    SCALE   (input/output) DOUBLE PRECISION   
+            On entry, the value  scale  in the equation above.   
+            On exit, SCALE is overwritten with  scl , the scaling factor   
+            for the sum of squares.   
+
+    SUMSQ   (input/output) DOUBLE PRECISION   
+            On entry, the value  sumsq  in the equation above.   
+            On exit, SUMSQ is overwritten with  smsq , the basic sum of   
+            squares from which  scl  has been factored out.   
+
+   =====================================================================   
+
+
+       Parameter adjustments */
+    --x;
+
+    /* Function Body */
+    if (*n > 0) {
+	i__1 = (*n - 1) * *incx + 1;
+	i__2 = *incx;
+	for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) {
+	    if (x[ix] != 0.) {
+		absxi = (d__1 = x[ix], abs(d__1));
+		if (*scale < absxi) {
+/* Computing 2nd power */
+		    d__1 = *scale / absxi;
+		    *sumsq = *sumsq * (d__1 * d__1) + 1;
+		    *scale = absxi;
+		} else {
+/* Computing 2nd power */
+		    d__1 = absxi / *scale;
+		    *sumsq += d__1 * d__1;
+		}
+	    }
+/* L10: */
+	}
+    }
+    return 0;
+
+/*     End of DLASSQ */
+
+} /* igraphdlassq_ */
+
diff --git a/src/lapack/dlaswp.c b/src/lapack/dlaswp.c
new file mode 100644
index 0000000..d7ba680
--- /dev/null
+++ b/src/lapack/dlaswp.c
@@ -0,0 +1,152 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdlaswp_(integer *n, doublereal *a, integer *lda, integer 
+	*k1, integer *k2, integer *ipiv, integer *incx)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3, i__4;
+
+    /* Local variables */
+    integer i__, j, k, i1, i2, n32, ip, ix, ix0, inc;
+    doublereal temp;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLASWP performs a series of row interchanges on the matrix A.   
+    One row interchange is initiated for each of rows K1 through K2 of A.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the matrix of column dimension N to which the row   
+            interchanges will be applied.   
+            On exit, the permuted matrix.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+
+    K1      (input) INTEGER   
+            The first element of IPIV for which a row interchange will   
+            be done.   
+
+    K2      (input) INTEGER   
+            The last element of IPIV for which a row interchange will   
+            be done.   
+
+    IPIV    (input) INTEGER array, dimension (K2*abs(INCX))   
+            The vector of pivot indices.  Only the elements in positions   
+            K1 through K2 of IPIV are accessed.   
+            IPIV(K) = L implies rows K and L are to be interchanged.   
+
+    INCX    (input) INTEGER   
+            The increment between successive values of IPIV.  If IPIV   
+            is negative, the pivots are applied in reverse order.   
+
+    Further Details   
+    ===============   
+
+    Modified by   
+     R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA   
+
+   =====================================================================   
+
+
+       Interchange row I with row IPIV(I) for each of rows K1 through K2.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --ipiv;
+
+    /* Function Body */
+    if (*incx > 0) {
+	ix0 = *k1;
+	i1 = *k1;
+	i2 = *k2;
+	inc = 1;
+    } else if (*incx < 0) {
+	ix0 = (1 - *k2) * *incx + 1;
+	i1 = *k2;
+	i2 = *k1;
+	inc = -1;
+    } else {
+	return 0;
+    }
+
+    n32 = *n / 32 << 5;
+    if (n32 != 0) {
+	i__1 = n32;
+	for (j = 1; j <= i__1; j += 32) {
+	    ix = ix0;
+	    i__2 = i2;
+	    i__3 = inc;
+	    for (i__ = i1; i__3 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__3) 
+		    {
+		ip = ipiv[ix];
+		if (ip != i__) {
+		    i__4 = j + 31;
+		    for (k = j; k <= i__4; ++k) {
+			temp = a[i__ + k * a_dim1];
+			a[i__ + k * a_dim1] = a[ip + k * a_dim1];
+			a[ip + k * a_dim1] = temp;
+/* L10: */
+		    }
+		}
+		ix += *incx;
+/* L20: */
+	    }
+/* L30: */
+	}
+    }
+    if (n32 != *n) {
+	++n32;
+	ix = ix0;
+	i__1 = i2;
+	i__3 = inc;
+	for (i__ = i1; i__3 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__3) {
+	    ip = ipiv[ix];
+	    if (ip != i__) {
+		i__2 = *n;
+		for (k = n32; k <= i__2; ++k) {
+		    temp = a[i__ + k * a_dim1];
+		    a[i__ + k * a_dim1] = a[ip + k * a_dim1];
+		    a[ip + k * a_dim1] = temp;
+/* L40: */
+		}
+	    }
+	    ix += *incx;
+/* L50: */
+	}
+    }
+
+    return 0;
+
+/*     End of DLASWP */
+
+} /* igraphdlaswp_ */
+
diff --git a/src/lapack/dlasy2.c b/src/lapack/dlasy2.c
new file mode 100644
index 0000000..78635f2
--- /dev/null
+++ b/src/lapack/dlasy2.c
@@ -0,0 +1,460 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__4 = 4;
+static integer c__1 = 1;
+static integer c__16 = 16;
+static integer c__0 = 0;
+
+/* Subroutine */ int igraphdlasy2_(logical *ltranl, logical *ltranr, integer *isgn, 
+	integer *n1, integer *n2, doublereal *tl, integer *ldtl, doublereal *
+	tr, integer *ldtr, doublereal *b, integer *ldb, doublereal *scale, 
+	doublereal *x, integer *ldx, doublereal *xnorm, integer *info)
+{
+    /* Initialized data */
+
+    static integer locu12[4] = { 3,4,1,2 };
+    static integer locl21[4] = { 2,1,4,3 };
+    static integer locu22[4] = { 4,3,2,1 };
+    static logical xswpiv[4] = { FALSE_,FALSE_,TRUE_,TRUE_ };
+    static logical bswpiv[4] = { FALSE_,TRUE_,FALSE_,TRUE_ };
+
+    /* System generated locals */
+    integer b_dim1, b_offset, tl_dim1, tl_offset, tr_dim1, tr_offset, x_dim1, 
+	    x_offset;
+    doublereal d__1, d__2, d__3, d__4, d__5, d__6, d__7, d__8;
+
+    /* Local variables */
+    integer i__, j, k;
+    doublereal x2[2], l21, u11, u12;
+    integer ip, jp;
+    doublereal u22, t16[16]	/* was [4][4] */, gam, bet, eps, sgn, tmp[4], 
+	    tau1, btmp[4], smin;
+    integer ipiv;
+    doublereal temp;
+    integer jpiv[4];
+    doublereal xmax;
+    integer ipsv, jpsv;
+    logical bswap;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdswap_(integer *, doublereal *, integer 
+	    *, doublereal *, integer *);
+    logical xswap;
+    extern doublereal igraphdlamch_(char *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    doublereal smlnum;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DLASY2 solves for the N1 by N2 matrix X, 1 <= N1,N2 <= 2, in   
+
+           op(TL)*X + ISGN*X*op(TR) = SCALE*B,   
+
+    where TL is N1 by N1, TR is N2 by N2, B is N1 by N2, and ISGN = 1 or   
+    -1.  op(T) = T or T**T, where T**T denotes the transpose of T.   
+
+    Arguments   
+    =========   
+
+    LTRANL  (input) LOGICAL   
+            On entry, LTRANL specifies the op(TL):   
+               = .FALSE., op(TL) = TL,   
+               = .TRUE., op(TL) = TL**T.   
+
+    LTRANR  (input) LOGICAL   
+            On entry, LTRANR specifies the op(TR):   
+              = .FALSE., op(TR) = TR,   
+              = .TRUE., op(TR) = TR**T.   
+
+    ISGN    (input) INTEGER   
+            On entry, ISGN specifies the sign of the equation   
+            as described before. ISGN may only be 1 or -1.   
+
+    N1      (input) INTEGER   
+            On entry, N1 specifies the order of matrix TL.   
+            N1 may only be 0, 1 or 2.   
+
+    N2      (input) INTEGER   
+            On entry, N2 specifies the order of matrix TR.   
+            N2 may only be 0, 1 or 2.   
+
+    TL      (input) DOUBLE PRECISION array, dimension (LDTL,2)   
+            On entry, TL contains an N1 by N1 matrix.   
+
+    LDTL    (input) INTEGER   
+            The leading dimension of the matrix TL. LDTL >= max(1,N1).   
+
+    TR      (input) DOUBLE PRECISION array, dimension (LDTR,2)   
+            On entry, TR contains an N2 by N2 matrix.   
+
+    LDTR    (input) INTEGER   
+            The leading dimension of the matrix TR. LDTR >= max(1,N2).   
+
+    B       (input) DOUBLE PRECISION array, dimension (LDB,2)   
+            On entry, the N1 by N2 matrix B contains the right-hand   
+            side of the equation.   
+
+    LDB     (input) INTEGER   
+            The leading dimension of the matrix B. LDB >= max(1,N1).   
+
+    SCALE   (output) DOUBLE PRECISION   
+            On exit, SCALE contains the scale factor. SCALE is chosen   
+            less than or equal to 1 to prevent the solution overflowing.   
+
+    X       (output) DOUBLE PRECISION array, dimension (LDX,2)   
+            On exit, X contains the N1 by N2 solution.   
+
+    LDX     (input) INTEGER   
+            The leading dimension of the matrix X. LDX >= max(1,N1).   
+
+    XNORM   (output) DOUBLE PRECISION   
+            On exit, XNORM is the infinity-norm of the solution.   
+
+    INFO    (output) INTEGER   
+            On exit, INFO is set to   
+               0: successful exit.   
+               1: TL and TR have too close eigenvalues, so TL or   
+                  TR is perturbed to get a nonsingular equation.   
+            NOTE: In the interests of speed, this routine does not   
+                  check the inputs for errors.   
+
+   =====================================================================   
+
+       Parameter adjustments */
+    tl_dim1 = *ldtl;
+    tl_offset = 1 + tl_dim1;
+    tl -= tl_offset;
+    tr_dim1 = *ldtr;
+    tr_offset = 1 + tr_dim1;
+    tr -= tr_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+    x_dim1 = *ldx;
+    x_offset = 1 + x_dim1;
+    x -= x_offset;
+
+    /* Function Body   
+
+       Do not check the input parameters for errors */
+
+    *info = 0;
+
+/*     Quick return if possible */
+
+    if (*n1 == 0 || *n2 == 0) {
+	return 0;
+    }
+
+/*     Set constants to control overflow */
+
+    eps = igraphdlamch_("P");
+    smlnum = igraphdlamch_("S") / eps;
+    sgn = (doublereal) (*isgn);
+
+    k = *n1 + *n1 + *n2 - 2;
+    switch (k) {
+	case 1:  goto L10;
+	case 2:  goto L20;
+	case 3:  goto L30;
+	case 4:  goto L50;
+    }
+
+/*     1 by 1: TL11*X + SGN*X*TR11 = B11 */
+
+L10:
+    tau1 = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1];
+    bet = abs(tau1);
+    if (bet <= smlnum) {
+	tau1 = smlnum;
+	bet = smlnum;
+	*info = 1;
+    }
+
+    *scale = 1.;
+    gam = (d__1 = b[b_dim1 + 1], abs(d__1));
+    if (smlnum * gam > bet) {
+	*scale = 1. / gam;
+    }
+
+    x[x_dim1 + 1] = b[b_dim1 + 1] * *scale / tau1;
+    *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1));
+    return 0;
+
+/*     1 by 2:   
+       TL11*[X11 X12] + ISGN*[X11 X12]*op[TR11 TR12]  = [B11 B12]   
+                                         [TR21 TR22] */
+
+L20:
+
+/* Computing MAX   
+   Computing MAX */
+    d__7 = (d__1 = tl[tl_dim1 + 1], abs(d__1)), d__8 = (d__2 = tr[tr_dim1 + 1]
+	    , abs(d__2)), d__7 = max(d__7,d__8), d__8 = (d__3 = tr[(tr_dim1 <<
+	     1) + 1], abs(d__3)), d__7 = max(d__7,d__8), d__8 = (d__4 = tr[
+	    tr_dim1 + 2], abs(d__4)), d__7 = max(d__7,d__8), d__8 = (d__5 = 
+	    tr[(tr_dim1 << 1) + 2], abs(d__5));
+    d__6 = eps * max(d__7,d__8);
+    smin = max(d__6,smlnum);
+    tmp[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1];
+    tmp[3] = tl[tl_dim1 + 1] + sgn * tr[(tr_dim1 << 1) + 2];
+    if (*ltranr) {
+	tmp[1] = sgn * tr[tr_dim1 + 2];
+	tmp[2] = sgn * tr[(tr_dim1 << 1) + 1];
+    } else {
+	tmp[1] = sgn * tr[(tr_dim1 << 1) + 1];
+	tmp[2] = sgn * tr[tr_dim1 + 2];
+    }
+    btmp[0] = b[b_dim1 + 1];
+    btmp[1] = b[(b_dim1 << 1) + 1];
+    goto L40;
+
+/*     2 by 1:   
+            op[TL11 TL12]*[X11] + ISGN* [X11]*TR11  = [B11]   
+              [TL21 TL22] [X21]         [X21]         [B21] */
+
+L30:
+/* Computing MAX   
+   Computing MAX */
+    d__7 = (d__1 = tr[tr_dim1 + 1], abs(d__1)), d__8 = (d__2 = tl[tl_dim1 + 1]
+	    , abs(d__2)), d__7 = max(d__7,d__8), d__8 = (d__3 = tl[(tl_dim1 <<
+	     1) + 1], abs(d__3)), d__7 = max(d__7,d__8), d__8 = (d__4 = tl[
+	    tl_dim1 + 2], abs(d__4)), d__7 = max(d__7,d__8), d__8 = (d__5 = 
+	    tl[(tl_dim1 << 1) + 2], abs(d__5));
+    d__6 = eps * max(d__7,d__8);
+    smin = max(d__6,smlnum);
+    tmp[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1];
+    tmp[3] = tl[(tl_dim1 << 1) + 2] + sgn * tr[tr_dim1 + 1];
+    if (*ltranl) {
+	tmp[1] = tl[(tl_dim1 << 1) + 1];
+	tmp[2] = tl[tl_dim1 + 2];
+    } else {
+	tmp[1] = tl[tl_dim1 + 2];
+	tmp[2] = tl[(tl_dim1 << 1) + 1];
+    }
+    btmp[0] = b[b_dim1 + 1];
+    btmp[1] = b[b_dim1 + 2];
+L40:
+
+/*     Solve 2 by 2 system using complete pivoting.   
+       Set pivots less than SMIN to SMIN. */
+
+    ipiv = igraphidamax_(&c__4, tmp, &c__1);
+    u11 = tmp[ipiv - 1];
+    if (abs(u11) <= smin) {
+	*info = 1;
+	u11 = smin;
+    }
+    u12 = tmp[locu12[ipiv - 1] - 1];
+    l21 = tmp[locl21[ipiv - 1] - 1] / u11;
+    u22 = tmp[locu22[ipiv - 1] - 1] - u12 * l21;
+    xswap = xswpiv[ipiv - 1];
+    bswap = bswpiv[ipiv - 1];
+    if (abs(u22) <= smin) {
+	*info = 1;
+	u22 = smin;
+    }
+    if (bswap) {
+	temp = btmp[1];
+	btmp[1] = btmp[0] - l21 * temp;
+	btmp[0] = temp;
+    } else {
+	btmp[1] -= l21 * btmp[0];
+    }
+    *scale = 1.;
+    if (smlnum * 2. * abs(btmp[1]) > abs(u22) || smlnum * 2. * abs(btmp[0]) > 
+	    abs(u11)) {
+/* Computing MAX */
+	d__1 = abs(btmp[0]), d__2 = abs(btmp[1]);
+	*scale = .5 / max(d__1,d__2);
+	btmp[0] *= *scale;
+	btmp[1] *= *scale;
+    }
+    x2[1] = btmp[1] / u22;
+    x2[0] = btmp[0] / u11 - u12 / u11 * x2[1];
+    if (xswap) {
+	temp = x2[1];
+	x2[1] = x2[0];
+	x2[0] = temp;
+    }
+    x[x_dim1 + 1] = x2[0];
+    if (*n1 == 1) {
+	x[(x_dim1 << 1) + 1] = x2[1];
+	*xnorm = (d__1 = x[x_dim1 + 1], abs(d__1)) + (d__2 = x[(x_dim1 << 1) 
+		+ 1], abs(d__2));
+    } else {
+	x[x_dim1 + 2] = x2[1];
+/* Computing MAX */
+	d__3 = (d__1 = x[x_dim1 + 1], abs(d__1)), d__4 = (d__2 = x[x_dim1 + 2]
+		, abs(d__2));
+	*xnorm = max(d__3,d__4);
+    }
+    return 0;
+
+/*     2 by 2:   
+       op[TL11 TL12]*[X11 X12] +ISGN* [X11 X12]*op[TR11 TR12] = [B11 B12]   
+         [TL21 TL22] [X21 X22]        [X21 X22]   [TR21 TR22]   [B21 B22]   
+
+       Solve equivalent 4 by 4 system using complete pivoting.   
+       Set pivots less than SMIN to SMIN. */
+
+L50:
+/* Computing MAX */
+    d__5 = (d__1 = tr[tr_dim1 + 1], abs(d__1)), d__6 = (d__2 = tr[(tr_dim1 << 
+	    1) + 1], abs(d__2)), d__5 = max(d__5,d__6), d__6 = (d__3 = tr[
+	    tr_dim1 + 2], abs(d__3)), d__5 = max(d__5,d__6), d__6 = (d__4 = 
+	    tr[(tr_dim1 << 1) + 2], abs(d__4));
+    smin = max(d__5,d__6);
+/* Computing MAX */
+    d__5 = smin, d__6 = (d__1 = tl[tl_dim1 + 1], abs(d__1)), d__5 = max(d__5,
+	    d__6), d__6 = (d__2 = tl[(tl_dim1 << 1) + 1], abs(d__2)), d__5 = 
+	    max(d__5,d__6), d__6 = (d__3 = tl[tl_dim1 + 2], abs(d__3)), d__5 =
+	     max(d__5,d__6), d__6 = (d__4 = tl[(tl_dim1 << 1) + 2], abs(d__4))
+	    ;
+    smin = max(d__5,d__6);
+/* Computing MAX */
+    d__1 = eps * smin;
+    smin = max(d__1,smlnum);
+    btmp[0] = 0.;
+    igraphdcopy_(&c__16, btmp, &c__0, t16, &c__1);
+    t16[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1];
+    t16[5] = tl[(tl_dim1 << 1) + 2] + sgn * tr[tr_dim1 + 1];
+    t16[10] = tl[tl_dim1 + 1] + sgn * tr[(tr_dim1 << 1) + 2];
+    t16[15] = tl[(tl_dim1 << 1) + 2] + sgn * tr[(tr_dim1 << 1) + 2];
+    if (*ltranl) {
+	t16[4] = tl[tl_dim1 + 2];
+	t16[1] = tl[(tl_dim1 << 1) + 1];
+	t16[14] = tl[tl_dim1 + 2];
+	t16[11] = tl[(tl_dim1 << 1) + 1];
+    } else {
+	t16[4] = tl[(tl_dim1 << 1) + 1];
+	t16[1] = tl[tl_dim1 + 2];
+	t16[14] = tl[(tl_dim1 << 1) + 1];
+	t16[11] = tl[tl_dim1 + 2];
+    }
+    if (*ltranr) {
+	t16[8] = sgn * tr[(tr_dim1 << 1) + 1];
+	t16[13] = sgn * tr[(tr_dim1 << 1) + 1];
+	t16[2] = sgn * tr[tr_dim1 + 2];
+	t16[7] = sgn * tr[tr_dim1 + 2];
+    } else {
+	t16[8] = sgn * tr[tr_dim1 + 2];
+	t16[13] = sgn * tr[tr_dim1 + 2];
+	t16[2] = sgn * tr[(tr_dim1 << 1) + 1];
+	t16[7] = sgn * tr[(tr_dim1 << 1) + 1];
+    }
+    btmp[0] = b[b_dim1 + 1];
+    btmp[1] = b[b_dim1 + 2];
+    btmp[2] = b[(b_dim1 << 1) + 1];
+    btmp[3] = b[(b_dim1 << 1) + 2];
+
+/*     Perform elimination */
+
+    for (i__ = 1; i__ <= 3; ++i__) {
+	xmax = 0.;
+	for (ip = i__; ip <= 4; ++ip) {
+	    for (jp = i__; jp <= 4; ++jp) {
+		if ((d__1 = t16[ip + (jp << 2) - 5], abs(d__1)) >= xmax) {
+		    xmax = (d__1 = t16[ip + (jp << 2) - 5], abs(d__1));
+		    ipsv = ip;
+		    jpsv = jp;
+		}
+/* L60: */
+	    }
+/* L70: */
+	}
+	if (ipsv != i__) {
+	    igraphdswap_(&c__4, &t16[ipsv - 1], &c__4, &t16[i__ - 1], &c__4);
+	    temp = btmp[i__ - 1];
+	    btmp[i__ - 1] = btmp[ipsv - 1];
+	    btmp[ipsv - 1] = temp;
+	}
+	if (jpsv != i__) {
+	    igraphdswap_(&c__4, &t16[(jpsv << 2) - 4], &c__1, &t16[(i__ << 2) - 4], 
+		    &c__1);
+	}
+	jpiv[i__ - 1] = jpsv;
+	if ((d__1 = t16[i__ + (i__ << 2) - 5], abs(d__1)) < smin) {
+	    *info = 1;
+	    t16[i__ + (i__ << 2) - 5] = smin;
+	}
+	for (j = i__ + 1; j <= 4; ++j) {
+	    t16[j + (i__ << 2) - 5] /= t16[i__ + (i__ << 2) - 5];
+	    btmp[j - 1] -= t16[j + (i__ << 2) - 5] * btmp[i__ - 1];
+	    for (k = i__ + 1; k <= 4; ++k) {
+		t16[j + (k << 2) - 5] -= t16[j + (i__ << 2) - 5] * t16[i__ + (
+			k << 2) - 5];
+/* L80: */
+	    }
+/* L90: */
+	}
+/* L100: */
+    }
+    if (abs(t16[15]) < smin) {
+	t16[15] = smin;
+    }
+    *scale = 1.;
+    if (smlnum * 8. * abs(btmp[0]) > abs(t16[0]) || smlnum * 8. * abs(btmp[1])
+	     > abs(t16[5]) || smlnum * 8. * abs(btmp[2]) > abs(t16[10]) || 
+	    smlnum * 8. * abs(btmp[3]) > abs(t16[15])) {
+/* Computing MAX */
+	d__1 = abs(btmp[0]), d__2 = abs(btmp[1]), d__1 = max(d__1,d__2), d__2 
+		= abs(btmp[2]), d__1 = max(d__1,d__2), d__2 = abs(btmp[3]);
+	*scale = .125 / max(d__1,d__2);
+	btmp[0] *= *scale;
+	btmp[1] *= *scale;
+	btmp[2] *= *scale;
+	btmp[3] *= *scale;
+    }
+    for (i__ = 1; i__ <= 4; ++i__) {
+	k = 5 - i__;
+	temp = 1. / t16[k + (k << 2) - 5];
+	tmp[k - 1] = btmp[k - 1] * temp;
+	for (j = k + 1; j <= 4; ++j) {
+	    tmp[k - 1] -= temp * t16[k + (j << 2) - 5] * tmp[j - 1];
+/* L110: */
+	}
+/* L120: */
+    }
+    for (i__ = 1; i__ <= 3; ++i__) {
+	if (jpiv[4 - i__ - 1] != 4 - i__) {
+	    temp = tmp[4 - i__ - 1];
+	    tmp[4 - i__ - 1] = tmp[jpiv[4 - i__ - 1] - 1];
+	    tmp[jpiv[4 - i__ - 1] - 1] = temp;
+	}
+/* L130: */
+    }
+    x[x_dim1 + 1] = tmp[0];
+    x[x_dim1 + 2] = tmp[1];
+    x[(x_dim1 << 1) + 1] = tmp[2];
+    x[(x_dim1 << 1) + 2] = tmp[3];
+/* Computing MAX */
+    d__1 = abs(tmp[0]) + abs(tmp[2]), d__2 = abs(tmp[1]) + abs(tmp[3]);
+    *xnorm = max(d__1,d__2);
+    return 0;
+
+/*     End of DLASY2 */
+
+} /* igraphdlasy2_ */
+
diff --git a/src/lapack/dlatrd.c b/src/lapack/dlatrd.c
new file mode 100644
index 0000000..a7539f7
--- /dev/null
+++ b/src/lapack/dlatrd.c
@@ -0,0 +1,341 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b5 = -1.;
+static doublereal c_b6 = 1.;
+static integer c__1 = 1;
+static doublereal c_b16 = 0.;
+
+/* Subroutine */ int igraphdlatrd_(char *uplo, integer *n, integer *nb, doublereal *
+	a, integer *lda, doublereal *e, doublereal *tau, doublereal *w, 
+	integer *ldw)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, w_dim1, w_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, iw;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    doublereal alpha;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *), igraphdaxpy_(integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *), 
+	    igraphdsymv_(char *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *), igraphdlarfg_(integer *, doublereal *, doublereal *, integer *,
+	     doublereal *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DLATRD reduces NB rows and columns of a real symmetric matrix A to   
+    symmetric tridiagonal form by an orthogonal similarity   
+    transformation Q**T * A * Q, and returns the matrices V and W which are   
+    needed to apply the transformation to the unreduced part of A.   
+
+    If UPLO = 'U', DLATRD reduces the last NB rows and columns of a   
+    matrix, of which the upper triangle is supplied;   
+    if UPLO = 'L', DLATRD reduces the first NB rows and columns of a   
+    matrix, of which the lower triangle is supplied.   
+
+    This is an auxiliary routine called by DSYTRD.   
+
+    Arguments   
+    =========   
+
+    UPLO    (input) CHARACTER*1   
+            Specifies whether the upper or lower triangular part of the   
+            symmetric matrix A is stored:   
+            = 'U': Upper triangular   
+            = 'L': Lower triangular   
+
+    N       (input) INTEGER   
+            The order of the matrix A.   
+
+    NB      (input) INTEGER   
+            The number of rows and columns to be reduced.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the symmetric matrix A.  If UPLO = 'U', the leading   
+            n-by-n upper triangular part of A contains the upper   
+            triangular part of the matrix A, and the strictly lower   
+            triangular part of A is not referenced.  If UPLO = 'L', the   
+            leading n-by-n lower triangular part of A contains the lower   
+            triangular part of the matrix A, and the strictly upper   
+            triangular part of A is not referenced.   
+            On exit:   
+            if UPLO = 'U', the last NB columns have been reduced to   
+              tridiagonal form, with the diagonal elements overwriting   
+              the diagonal elements of A; the elements above the diagonal   
+              with the array TAU, represent the orthogonal matrix Q as a   
+              product of elementary reflectors;   
+            if UPLO = 'L', the first NB columns have been reduced to   
+              tridiagonal form, with the diagonal elements overwriting   
+              the diagonal elements of A; the elements below the diagonal   
+              with the array TAU, represent the  orthogonal matrix Q as a   
+              product of elementary reflectors.   
+            See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= (1,N).   
+
+    E       (output) DOUBLE PRECISION array, dimension (N-1)   
+            If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal   
+            elements of the last NB columns of the reduced matrix;   
+            if UPLO = 'L', E(1:nb) contains the subdiagonal elements of   
+            the first NB columns of the reduced matrix.   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (N-1)   
+            The scalar factors of the elementary reflectors, stored in   
+            TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'.   
+            See Further Details.   
+
+    W       (output) DOUBLE PRECISION array, dimension (LDW,NB)   
+            The n-by-nb matrix W required to update the unreduced part   
+            of A.   
+
+    LDW     (input) INTEGER   
+            The leading dimension of the array W. LDW >= max(1,N).   
+
+    Further Details   
+    ===============   
+
+    If UPLO = 'U', the matrix Q is represented as a product of elementary   
+    reflectors   
+
+       Q = H(n) H(n-1) . . . H(n-nb+1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i),   
+    and tau in TAU(i-1).   
+
+    If UPLO = 'L', the matrix Q is represented as a product of elementary   
+    reflectors   
+
+       Q = H(1) H(2) . . . H(nb).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i),   
+    and tau in TAU(i).   
+
+    The elements of the vectors v together form the n-by-nb matrix V   
+    which is needed, with W, to apply the transformation to the unreduced   
+    part of the matrix, using a symmetric rank-2k update of the form:   
+    A := A - V*W**T - W*V**T.   
+
+    The contents of A on exit are illustrated by the following examples   
+    with n = 5 and nb = 2:   
+
+    if UPLO = 'U':                       if UPLO = 'L':   
+
+      (  a   a   a   v4  v5 )              (  d                  )   
+      (      a   a   v4  v5 )              (  1   d              )   
+      (          a   1   v5 )              (  v1  1   a          )   
+      (              d   1  )              (  v1  v2  a   a      )   
+      (                  d  )              (  v1  v2  a   a   a  )   
+
+    where d denotes a diagonal element of the reduced matrix, a denotes   
+    an element of the original matrix that is unchanged, and vi denotes   
+    an element of the vector defining H(i).   
+
+    =====================================================================   
+
+
+       Quick return if possible   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --e;
+    --tau;
+    w_dim1 = *ldw;
+    w_offset = 1 + w_dim1;
+    w -= w_offset;
+
+    /* Function Body */
+    if (*n <= 0) {
+	return 0;
+    }
+
+    if (igraphlsame_(uplo, "U")) {
+
+/*        Reduce last NB columns of upper triangle */
+
+	i__1 = *n - *nb + 1;
+	for (i__ = *n; i__ >= i__1; --i__) {
+	    iw = i__ - *n + *nb;
+	    if (i__ < *n) {
+
+/*              Update A(1:i,i) */
+
+		i__2 = *n - i__;
+		igraphdgemv_("No transpose", &i__, &i__2, &c_b5, &a[(i__ + 1) * 
+			a_dim1 + 1], lda, &w[i__ + (iw + 1) * w_dim1], ldw, &
+			c_b6, &a[i__ * a_dim1 + 1], &c__1);
+		i__2 = *n - i__;
+		igraphdgemv_("No transpose", &i__, &i__2, &c_b5, &w[(iw + 1) * 
+			w_dim1 + 1], ldw, &a[i__ + (i__ + 1) * a_dim1], lda, &
+			c_b6, &a[i__ * a_dim1 + 1], &c__1);
+	    }
+	    if (i__ > 1) {
+
+/*              Generate elementary reflector H(i) to annihilate   
+                A(1:i-2,i) */
+
+		i__2 = i__ - 1;
+		igraphdlarfg_(&i__2, &a[i__ - 1 + i__ * a_dim1], &a[i__ * a_dim1 + 
+			1], &c__1, &tau[i__ - 1]);
+		e[i__ - 1] = a[i__ - 1 + i__ * a_dim1];
+		a[i__ - 1 + i__ * a_dim1] = 1.;
+
+/*              Compute W(1:i-1,i) */
+
+		i__2 = i__ - 1;
+		igraphdsymv_("Upper", &i__2, &c_b6, &a[a_offset], lda, &a[i__ * 
+			a_dim1 + 1], &c__1, &c_b16, &w[iw * w_dim1 + 1], &
+			c__1);
+		if (i__ < *n) {
+		    i__2 = i__ - 1;
+		    i__3 = *n - i__;
+		    igraphdgemv_("Transpose", &i__2, &i__3, &c_b6, &w[(iw + 1) * 
+			    w_dim1 + 1], ldw, &a[i__ * a_dim1 + 1], &c__1, &
+			    c_b16, &w[i__ + 1 + iw * w_dim1], &c__1);
+		    i__2 = i__ - 1;
+		    i__3 = *n - i__;
+		    igraphdgemv_("No transpose", &i__2, &i__3, &c_b5, &a[(i__ + 1) *
+			     a_dim1 + 1], lda, &w[i__ + 1 + iw * w_dim1], &
+			    c__1, &c_b6, &w[iw * w_dim1 + 1], &c__1);
+		    i__2 = i__ - 1;
+		    i__3 = *n - i__;
+		    igraphdgemv_("Transpose", &i__2, &i__3, &c_b6, &a[(i__ + 1) * 
+			    a_dim1 + 1], lda, &a[i__ * a_dim1 + 1], &c__1, &
+			    c_b16, &w[i__ + 1 + iw * w_dim1], &c__1);
+		    i__2 = i__ - 1;
+		    i__3 = *n - i__;
+		    igraphdgemv_("No transpose", &i__2, &i__3, &c_b5, &w[(iw + 1) * 
+			    w_dim1 + 1], ldw, &w[i__ + 1 + iw * w_dim1], &
+			    c__1, &c_b6, &w[iw * w_dim1 + 1], &c__1);
+		}
+		i__2 = i__ - 1;
+		igraphdscal_(&i__2, &tau[i__ - 1], &w[iw * w_dim1 + 1], &c__1);
+		i__2 = i__ - 1;
+		alpha = tau[i__ - 1] * -.5 * igraphddot_(&i__2, &w[iw * w_dim1 + 1],
+			 &c__1, &a[i__ * a_dim1 + 1], &c__1);
+		i__2 = i__ - 1;
+		igraphdaxpy_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &w[iw * 
+			w_dim1 + 1], &c__1);
+	    }
+
+/* L10: */
+	}
+    } else {
+
+/*        Reduce first NB columns of lower triangle */
+
+	i__1 = *nb;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+
+/*           Update A(i:n,i) */
+
+	    i__2 = *n - i__ + 1;
+	    i__3 = i__ - 1;
+	    igraphdgemv_("No transpose", &i__2, &i__3, &c_b5, &a[i__ + a_dim1], lda,
+		     &w[i__ + w_dim1], ldw, &c_b6, &a[i__ + i__ * a_dim1], &
+		    c__1);
+	    i__2 = *n - i__ + 1;
+	    i__3 = i__ - 1;
+	    igraphdgemv_("No transpose", &i__2, &i__3, &c_b5, &w[i__ + w_dim1], ldw,
+		     &a[i__ + a_dim1], lda, &c_b6, &a[i__ + i__ * a_dim1], &
+		    c__1);
+	    if (i__ < *n) {
+
+/*              Generate elementary reflector H(i) to annihilate   
+                A(i+2:n,i) */
+
+		i__2 = *n - i__;
+/* Computing MIN */
+		i__3 = i__ + 2;
+		igraphdlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + 
+			i__ * a_dim1], &c__1, &tau[i__]);
+		e[i__] = a[i__ + 1 + i__ * a_dim1];
+		a[i__ + 1 + i__ * a_dim1] = 1.;
+
+/*              Compute W(i+1:n,i) */
+
+		i__2 = *n - i__;
+		igraphdsymv_("Lower", &i__2, &c_b6, &a[i__ + 1 + (i__ + 1) * a_dim1]
+			, lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b16, &w[
+			i__ + 1 + i__ * w_dim1], &c__1);
+		i__2 = *n - i__;
+		i__3 = i__ - 1;
+		igraphdgemv_("Transpose", &i__2, &i__3, &c_b6, &w[i__ + 1 + w_dim1],
+			 ldw, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b16, &w[
+			i__ * w_dim1 + 1], &c__1);
+		i__2 = *n - i__;
+		i__3 = i__ - 1;
+		igraphdgemv_("No transpose", &i__2, &i__3, &c_b5, &a[i__ + 1 + 
+			a_dim1], lda, &w[i__ * w_dim1 + 1], &c__1, &c_b6, &w[
+			i__ + 1 + i__ * w_dim1], &c__1);
+		i__2 = *n - i__;
+		i__3 = i__ - 1;
+		igraphdgemv_("Transpose", &i__2, &i__3, &c_b6, &a[i__ + 1 + a_dim1],
+			 lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b16, &w[
+			i__ * w_dim1 + 1], &c__1);
+		i__2 = *n - i__;
+		i__3 = i__ - 1;
+		igraphdgemv_("No transpose", &i__2, &i__3, &c_b5, &w[i__ + 1 + 
+			w_dim1], ldw, &w[i__ * w_dim1 + 1], &c__1, &c_b6, &w[
+			i__ + 1 + i__ * w_dim1], &c__1);
+		i__2 = *n - i__;
+		igraphdscal_(&i__2, &tau[i__], &w[i__ + 1 + i__ * w_dim1], &c__1);
+		i__2 = *n - i__;
+		alpha = tau[i__] * -.5 * igraphddot_(&i__2, &w[i__ + 1 + i__ * 
+			w_dim1], &c__1, &a[i__ + 1 + i__ * a_dim1], &c__1);
+		i__2 = *n - i__;
+		igraphdaxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &w[
+			i__ + 1 + i__ * w_dim1], &c__1);
+	    }
+
+/* L20: */
+	}
+    }
+
+    return 0;
+
+/*     End of DLATRD */
+
+} /* igraphdlatrd_ */
+
diff --git a/src/lapack/dmout.c b/src/lapack/dmout.c
new file mode 100644
index 0000000..b09dcc9
--- /dev/null
+++ b/src/lapack/dmout.c
@@ -0,0 +1,393 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__3 = 3;
+
+/* -----------------------------------------------------------------------   
+    Routine:    DMOUT   
+
+    Purpose:    Real matrix output routine.   
+
+    Usage:      CALL DMOUT (LOUT, M, N, A, LDA, IDIGIT, IFMT)   
+
+    Arguments   
+       M      - Number of rows of A.  (Input)   
+       N      - Number of columns of A.  (Input)   
+       A      - Real M by N matrix to be printed.  (Input)   
+       LDA    - Leading dimension of A exactly as specified in the   
+                dimension statement of the calling program.  (Input)   
+       IFMT   - Format to be used in printing matrix A.  (Input)   
+       IDIGIT - Print up to IABS(IDIGIT) decimal digits per number.  (In)   
+                If IDIGIT .LT. 0, printing is done with 72 columns.   
+                If IDIGIT .GT. 0, printing is done with 132 columns.   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdmout_(integer *lout, integer *m, integer *n, doublereal 
+	*a, integer *lda, integer *idigit, char *ifmt, ftnlen ifmt_len)
+{
+    /* Initialized data */
+
+    static char icol[1*3] = "C" "o" "l";
+
+    /* Format strings */
+    static char fmt_9999[] = "(/1x,a,/1x,a)";
+    static char fmt_9998[] = "(10x,10(4x,3a1,i4,1x))";
+    static char fmt_9994[] = "(1x,\002 Row\002,i4,\002:\002,1x,1p,10d12.3)";
+    static char fmt_9997[] = "(10x,8(5x,3a1,i4,2x))";
+    static char fmt_9993[] = "(1x,\002 Row\002,i4,\002:\002,1x,1p,8d14.5)";
+    static char fmt_9996[] = "(10x,6(7x,3a1,i4,4x))";
+    static char fmt_9992[] = "(1x,\002 Row\002,i4,\002:\002,1x,1p,6d18.9)";
+    static char fmt_9995[] = "(10x,5(9x,3a1,i4,6x))";
+    static char fmt_9991[] = "(1x,\002 Row\002,i4,\002:\002,1x,1p,5d22.13)";
+    static char fmt_9990[] = "(1x,\002 \002)";
+
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Builtin functions */
+    integer i_len(char *, ftnlen), s_wsfe(cilist *), do_fio(integer *, char *,
+	     ftnlen), e_wsfe(void);
+
+    /* Local variables */
+    integer i__, j, k1, k2, lll;
+    char line[80];
+    integer ndigit;
+
+    /* Fortran I/O blocks */
+    static cilist io___5 = { 0, 0, 0, fmt_9999, 0 };
+    static cilist io___9 = { 0, 0, 0, fmt_9998, 0 };
+    static cilist io___10 = { 0, 0, 0, fmt_9994, 0 };
+    static cilist io___12 = { 0, 0, 0, fmt_9997, 0 };
+    static cilist io___13 = { 0, 0, 0, fmt_9993, 0 };
+    static cilist io___14 = { 0, 0, 0, fmt_9996, 0 };
+    static cilist io___15 = { 0, 0, 0, fmt_9992, 0 };
+    static cilist io___16 = { 0, 0, 0, fmt_9995, 0 };
+    static cilist io___17 = { 0, 0, 0, fmt_9991, 0 };
+    static cilist io___18 = { 0, 0, 0, fmt_9998, 0 };
+    static cilist io___19 = { 0, 0, 0, fmt_9994, 0 };
+    static cilist io___20 = { 0, 0, 0, fmt_9997, 0 };
+    static cilist io___21 = { 0, 0, 0, fmt_9993, 0 };
+    static cilist io___22 = { 0, 0, 0, fmt_9996, 0 };
+    static cilist io___23 = { 0, 0, 0, fmt_9992, 0 };
+    static cilist io___24 = { 0, 0, 0, fmt_9995, 0 };
+    static cilist io___25 = { 0, 0, 0, fmt_9991, 0 };
+    static cilist io___26 = { 0, 0, 0, fmt_9990, 0 };
+
+
+/*     ...   
+       ... SPECIFICATIONS FOR ARGUMENTS   
+       ...   
+       ... SPECIFICATIONS FOR LOCAL VARIABLES   
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body   
+       ...   
+       ... FIRST EXECUTABLE STATEMENT   
+
+   Computing MIN */
+    i__1 = i_len(ifmt, ifmt_len);
+    lll = min(i__1,80);
+    i__1 = lll;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	*(unsigned char *)&line[i__ - 1] = '-';
+/* L10: */
+    }
+
+    for (i__ = lll + 1; i__ <= 80; ++i__) {
+	*(unsigned char *)&line[i__ - 1] = ' ';
+/* L20: */
+    }
+
+    io___5.ciunit = *lout;
+    s_wsfe(&io___5);
+    do_fio(&c__1, ifmt, ifmt_len);
+    do_fio(&c__1, line, lll);
+    e_wsfe();
+
+    if (*m <= 0 || *n <= 0 || *lda <= 0) {
+	return 0;
+    }
+    ndigit = *idigit;
+    if (*idigit == 0) {
+	ndigit = 4;
+    }
+
+/* =======================================================================   
+               CODE FOR OUTPUT USING 72 COLUMNS FORMAT   
+   ======================================================================= */
+
+    if (*idigit < 0) {
+	ndigit = -(*idigit);
+	if (ndigit <= 4) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 5) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 4;
+		k2 = min(i__2,i__3);
+		io___9.ciunit = *lout;
+		s_wsfe(&io___9);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___10.ciunit = *lout;
+		    s_wsfe(&io___10);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L30: */
+		}
+/* L40: */
+	    }
+
+	} else if (ndigit <= 6) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 4) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 3;
+		k2 = min(i__2,i__3);
+		io___12.ciunit = *lout;
+		s_wsfe(&io___12);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___13.ciunit = *lout;
+		    s_wsfe(&io___13);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L50: */
+		}
+/* L60: */
+	    }
+
+	} else if (ndigit <= 10) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 3) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 2;
+		k2 = min(i__2,i__3);
+		io___14.ciunit = *lout;
+		s_wsfe(&io___14);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___15.ciunit = *lout;
+		    s_wsfe(&io___15);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L70: */
+		}
+/* L80: */
+	    }
+
+	} else {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 2) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 1;
+		k2 = min(i__2,i__3);
+		io___16.ciunit = *lout;
+		s_wsfe(&io___16);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___17.ciunit = *lout;
+		    s_wsfe(&io___17);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L90: */
+		}
+/* L100: */
+	    }
+	}
+
+/* =======================================================================   
+               CODE FOR OUTPUT USING 132 COLUMNS FORMAT   
+   ======================================================================= */
+
+    } else {
+	if (ndigit <= 4) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 10) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 9;
+		k2 = min(i__2,i__3);
+		io___18.ciunit = *lout;
+		s_wsfe(&io___18);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___19.ciunit = *lout;
+		    s_wsfe(&io___19);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L110: */
+		}
+/* L120: */
+	    }
+
+	} else if (ndigit <= 6) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 8) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 7;
+		k2 = min(i__2,i__3);
+		io___20.ciunit = *lout;
+		s_wsfe(&io___20);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___21.ciunit = *lout;
+		    s_wsfe(&io___21);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L130: */
+		}
+/* L140: */
+	    }
+
+	} else if (ndigit <= 10) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 6) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 5;
+		k2 = min(i__2,i__3);
+		io___22.ciunit = *lout;
+		s_wsfe(&io___22);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___23.ciunit = *lout;
+		    s_wsfe(&io___23);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L150: */
+		}
+/* L160: */
+	    }
+
+	} else {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 5) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 4;
+		k2 = min(i__2,i__3);
+		io___24.ciunit = *lout;
+		s_wsfe(&io___24);
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__3, icol, (ftnlen)1);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+		i__2 = *m;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    io___25.ciunit = *lout;
+		    s_wsfe(&io___25);
+		    do_fio(&c__1, (char *)&i__, (ftnlen)sizeof(integer));
+		    i__3 = k2;
+		    for (j = k1; j <= i__3; ++j) {
+			do_fio(&c__1, (char *)&a[i__ + j * a_dim1], (ftnlen)
+				sizeof(doublereal));
+		    }
+		    e_wsfe();
+/* L170: */
+		}
+/* L180: */
+	    }
+	}
+    }
+    io___26.ciunit = *lout;
+    s_wsfe(&io___26);
+    e_wsfe();
+
+
+    return 0;
+} /* igraphdmout_ */
+
diff --git a/src/lapack/dnaitr.c b/src/lapack/dnaitr.c
new file mode 100644
index 0000000..8b06daa
--- /dev/null
+++ b/src/lapack/dnaitr.c
@@ -0,0 +1,950 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static logical c_false = FALSE_;
+static doublereal c_b25 = 1.;
+static doublereal c_b47 = 0.;
+static doublereal c_b50 = -1.;
+static integer c__2 = 2;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dnaitr   
+
+   \Description:   
+    Reverse communication interface for applying NP additional steps to   
+    a K step nonsymmetric Arnoldi factorization.   
+
+    Input:  OP*V_{k}  -  V_{k}*H = r_{k}*e_{k}^T   
+
+            with (V_{k}^T)*B*V_{k} = I, (V_{k}^T)*B*r_{k} = 0.   
+
+    Output: OP*V_{k+p}  -  V_{k+p}*H = r_{k+p}*e_{k+p}^T   
+
+            with (V_{k+p}^T)*B*V_{k+p} = I, (V_{k+p}^T)*B*r_{k+p} = 0.   
+
+    where OP and B are as in dnaupd.  The B-norm of r_{k+p} is also   
+    computed and returned.   
+
+   \Usage:   
+    call dnaitr   
+       ( IDO, BMAT, N, K, NP, NB, RESID, RNORM, V, LDV, H, LDH,   
+         IPNTR, WORKD, INFO )   
+
+   \Arguments   
+    IDO     Integer.  (INPUT/OUTPUT)   
+            Reverse communication flag.   
+            -------------------------------------------------------------   
+            IDO =  0: first call to the reverse communication interface   
+            IDO = -1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORK for X,   
+                      IPNTR(2) is the pointer into WORK for Y.   
+                      This is for the restart phase to force the new   
+                      starting vector into the range of OP.   
+            IDO =  1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORK for X,   
+                      IPNTR(2) is the pointer into WORK for Y,   
+                      IPNTR(3) is the pointer into WORK for B * X.   
+            IDO =  2: compute  Y = B * X  where   
+                      IPNTR(1) is the pointer into WORK for X,   
+                      IPNTR(2) is the pointer into WORK for Y.   
+            IDO = 99: done   
+            -------------------------------------------------------------   
+            When the routine is used in the "shift-and-invert" mode, the   
+            vector B * Q is already available and do not need to be   
+            recompute in forming OP * Q.   
+
+    BMAT    Character*1.  (INPUT)   
+            BMAT specifies the type of the matrix B that defines the   
+            semi-inner product for the operator OP.  See dnaupd.   
+            B = 'I' -> standard eigenvalue problem A*x = lambda*x   
+            B = 'G' -> generalized eigenvalue problem A*x = lambda*M**x   
+
+    N       Integer.  (INPUT)   
+            Dimension of the eigenproblem.   
+
+    K       Integer.  (INPUT)   
+            Current size of V and H.   
+
+    NP      Integer.  (INPUT)   
+            Number of additional Arnoldi steps to take.   
+
+    NB      Integer.  (INPUT)   
+            Blocksize to be used in the recurrence.   
+            Only work for NB = 1 right now.  The goal is to have a   
+            program that implement both the block and non-block method.   
+
+    RESID   Double precision array of length N.  (INPUT/OUTPUT)   
+            On INPUT:  RESID contains the residual vector r_{k}.   
+            On OUTPUT: RESID contains the residual vector r_{k+p}.   
+
+    RNORM   Double precision scalar.  (INPUT/OUTPUT)   
+            B-norm of the starting residual on input.   
+            B-norm of the updated residual r_{k+p} on output.   
+
+    V       Double precision N by K+NP array.  (INPUT/OUTPUT)   
+            On INPUT:  V contains the Arnoldi vectors in the first K   
+            columns.   
+            On OUTPUT: V contains the new NP Arnoldi vectors in the next   
+            NP columns.  The first K columns are unchanged.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    H       Double precision (K+NP) by (K+NP) array.  (INPUT/OUTPUT)   
+            H is used to store the generated upper Hessenberg matrix.   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    IPNTR   Integer array of length 3.  (OUTPUT)   
+            Pointer to mark the starting locations in the WORK for   
+            vectors used by the Arnoldi iteration.   
+            -------------------------------------------------------------   
+            IPNTR(1): pointer to the current operand vector X.   
+            IPNTR(2): pointer to the current result vector Y.   
+            IPNTR(3): pointer to the vector B * X when used in the   
+                      shift-and-invert mode.  X is the current operand.   
+            -------------------------------------------------------------   
+
+    WORKD   Double precision work array of length 3*N.  (REVERSE COMMUNICATION)   
+            Distributed array to be used in the basic Arnoldi iteration   
+            for reverse communication.  The calling program should not   
+            use WORKD as temporary workspace during the iteration !!!!!!   
+            On input, WORKD(1:N) = B*RESID and is used to save some   
+            computation at the first step.   
+
+    INFO    Integer.  (OUTPUT)   
+            = 0: Normal exit.   
+            > 0: Size of the spanning invariant subspace of OP found.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+
+   \Routines called:   
+       dgetv0  ARPACK routine to generate the initial vector.   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dmout   ARPACK utility routine that prints matrices   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlabad  LAPACK routine that computes machine constants.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlascl  LAPACK routine for careful scaling of a matrix.   
+       dlanhs  LAPACK routine that computes various norms of a matrix.   
+       dgemv   Level 2 BLAS routine for matrix vector multiplication.   
+       daxpy   Level 1 BLAS that computes a vector triad.   
+       dscal   Level 1 BLAS that scales a vector.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       ddot    Level 1 BLAS that computes the scalar product of two vectors.   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.4'   
+
+   \SCCS Information: @(#)   
+   FILE: naitr.F   SID: 2.4   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \Remarks   
+    The algorithm implemented is:   
+
+    restart = .false.   
+    Given V_{k} = [v_{1}, ..., v_{k}], r_{k};   
+    r_{k} contains the initial residual vector even for k = 0;   
+    Also assume that rnorm = || B*r_{k} || and B*r_{k} are already   
+    computed by the calling program.   
+
+    betaj = rnorm ; p_{k+1} = B*r_{k} ;   
+    For  j = k+1, ..., k+np  Do   
+       1) if ( betaj < tol ) stop or restart depending on j.   
+          ( At present tol is zero )   
+          if ( restart ) generate a new starting vector.   
+       2) v_{j} = r(j-1)/betaj;  V_{j} = [V_{j-1}, v_{j}];   
+          p_{j} = p_{j}/betaj   
+       3) r_{j} = OP*v_{j} where OP is defined as in dnaupd   
+          For shift-invert mode p_{j} = B*v_{j} is already available.   
+          wnorm = || OP*v_{j} ||   
+       4) Compute the j-th step residual vector.   
+          w_{j} =  V_{j}^T * B * OP * v_{j}   
+          r_{j} =  OP*v_{j} - V_{j} * w_{j}   
+          H(:,j) = w_{j};   
+          H(j,j-1) = rnorm   
+          rnorm = || r_(j) ||   
+          If (rnorm > 0.717*wnorm) accept step and go back to 1)   
+       5) Re-orthogonalization step:   
+          s = V_{j}'*B*r_{j}   
+          r_{j} = r_{j} - V_{j}*s;  rnorm1 = || r_{j} ||   
+          alphaj = alphaj + s_{j};   
+       6) Iterative refinement step:   
+          If (rnorm1 > 0.717*rnorm) then   
+             rnorm = rnorm1   
+             accept step and go back to 1)   
+          Else   
+             rnorm = rnorm1   
+             If this is the first time in step 6), go to 5)   
+             Else r_{j} lies in the span of V_{j} numerically.   
+                Set r_{j} = 0 and rnorm = 0; go to 1)   
+          EndIf   
+    End Do   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdnaitr_(integer *ido, char *bmat, integer *n, integer *k,
+	 integer *np, integer *nb, doublereal *resid, doublereal *rnorm, 
+	doublereal *v, integer *ldv, doublereal *h__, integer *ldh, integer *
+	ipntr, doublereal *workd, integer *info)
+{
+    /* Initialized data */
+
+    IGRAPH_F77_SAVE logical first = TRUE_;
+
+    /* System generated locals */
+    integer h_dim1, h_offset, v_dim1, v_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    IGRAPH_F77_SAVE integer j;
+    real t0, t1, t2, t3, t4, t5;
+    integer jj;
+    IGRAPH_F77_SAVE integer ipj, irj;
+    integer nbx;
+    IGRAPH_F77_SAVE integer ivj;
+    IGRAPH_F77_SAVE doublereal ulp;
+    doublereal tst1;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    IGRAPH_F77_SAVE integer ierr, iter;
+    IGRAPH_F77_SAVE doublereal unfl, ovfl;
+    integer nopx;
+    IGRAPH_F77_SAVE integer itry;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    doublereal temp1;
+    IGRAPH_F77_SAVE logical orth1, orth2, step3, step4;
+    IGRAPH_F77_SAVE doublereal betaj;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *), igraphdgemv_(char *, integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *);
+    integer infol;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdaxpy_(integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *), igraphdmout_(integer 
+	    *, integer *, integer *, doublereal *, integer *, integer *, char 
+	    *, ftnlen);
+    doublereal xtemp[2];
+    real tmvbx;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen);
+    IGRAPH_F77_SAVE doublereal wnorm;
+    extern /* Subroutine */ int igraphivout_(integer *, integer *, integer *, 
+	    integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *, 
+	    logical *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *), igraphdlabad_(doublereal *, doublereal *);
+    IGRAPH_F77_SAVE doublereal rnorm1;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlascl_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *);
+    extern doublereal igraphdlanhs_(char *, integer *, doublereal *, integer *, 
+	    doublereal *);
+    extern /* Subroutine */ int igraphsecond_(real *);
+    integer logfil=0, ndigit, nitref, mnaitr=0;
+    real titref, tnaitr;
+    IGRAPH_F77_SAVE integer msglvl;
+    IGRAPH_F77_SAVE doublereal smlnum;
+    integer nrorth;
+    IGRAPH_F77_SAVE logical rstart;
+    integer nrstrt;
+    real tmvopx;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %-----------------------%   
+       | Local Array Arguments |   
+       %-----------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------%   
+       | Data statements |   
+       %-----------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --ipntr;
+
+    /* Function Body   
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    if (first) {
+
+/*        %-----------------------------------------%   
+          | Set machine-dependent constants for the |   
+          | the splitting and deflation criterion.  |   
+          | If norm(H) <= sqrt(OVFL),               |   
+          | overflow should not occur.              |   
+          | REFERENCE: LAPACK subroutine dlahqr     |   
+          %-----------------------------------------% */
+
+	unfl = igraphdlamch_("safe minimum");
+	ovfl = 1. / unfl;
+	igraphdlabad_(&unfl, &ovfl);
+	ulp = igraphdlamch_("precision");
+	smlnum = unfl * (*n / ulp);
+	first = FALSE_;
+    }
+
+    if (*ido == 0) {
+
+/*        %-------------------------------%   
+          | Initialize timing statistics  |   
+          | & message level for debugging |   
+          %-------------------------------% */
+
+	igraphsecond_(&t0);
+	msglvl = mnaitr;
+
+/*        %------------------------------%   
+          | Initial call to this routine |   
+          %------------------------------% */
+
+	*info = 0;
+	step3 = FALSE_;
+	step4 = FALSE_;
+	rstart = FALSE_;
+	orth1 = FALSE_;
+	orth2 = FALSE_;
+	j = *k + 1;
+	ipj = 1;
+	irj = ipj + *n;
+	ivj = irj + *n;
+    }
+
+/*     %-------------------------------------------------%   
+       | When in reverse communication mode one of:      |   
+       | STEP3, STEP4, ORTH1, ORTH2, RSTART              |   
+       | will be .true. when ....                        |   
+       | STEP3: return from computing OP*v_{j}.          |   
+       | STEP4: return from computing B-norm of OP*v_{j} |   
+       | ORTH1: return from computing B-norm of r_{j+1}  |   
+       | ORTH2: return from computing B-norm of          |   
+       |        correction to the residual vector.       |   
+       | RSTART: return from OP computations needed by   |   
+       |         dgetv0.                                 |   
+       %-------------------------------------------------% */
+
+    if (step3) {
+	goto L50;
+    }
+    if (step4) {
+	goto L60;
+    }
+    if (orth1) {
+	goto L70;
+    }
+    if (orth2) {
+	goto L90;
+    }
+    if (rstart) {
+	goto L30;
+    }
+
+/*     %-----------------------------%   
+       | Else this is the first step |   
+       %-----------------------------%   
+
+       %--------------------------------------------------------------%   
+       |                                                              |   
+       |        A R N O L D I     I T E R A T I O N     L O O P       |   
+       |                                                              |   
+       | Note:  B*r_{j-1} is already in WORKD(1:N)=WORKD(IPJ:IPJ+N-1) |   
+       %--------------------------------------------------------------% */
+L1000:
+
+    if (msglvl > 1) {
+	igraphivout_(&logfil, &c__1, &j, &ndigit, "_naitr: generating Arnoldi vect"
+		"or number", (ftnlen)40);
+	igraphdvout_(&logfil, &c__1, rnorm, &ndigit, "_naitr: B-norm of the curren"
+		"t residual is", (ftnlen)41);
+    }
+
+/*        %---------------------------------------------------%   
+          | STEP 1: Check if the B norm of j-th residual      |   
+          | vector is zero. Equivalent to determing whether   |   
+          | an exact j-step Arnoldi factorization is present. |   
+          %---------------------------------------------------% */
+
+    betaj = *rnorm;
+    if (*rnorm > 0.) {
+	goto L40;
+    }
+
+/*           %---------------------------------------------------%   
+             | Invariant subspace found, generate a new starting |   
+             | vector which is orthogonal to the current Arnoldi |   
+             | basis and continue the iteration.                 |   
+             %---------------------------------------------------% */
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &j, &ndigit, "_naitr: ****** RESTART AT STEP "
+		"******", (ftnlen)37);
+    }
+
+/*           %---------------------------------------------%   
+             | ITRY is the loop variable that controls the |   
+             | maximum amount of times that a restart is   |   
+             | attempted. NRSTRT is used by stat.h         |   
+             %---------------------------------------------% */
+
+    betaj = 0.;
+    ++nrstrt;
+    itry = 1;
+L20:
+    rstart = TRUE_;
+    *ido = 0;
+L30:
+
+/*           %--------------------------------------%   
+             | If in reverse communication mode and |   
+             | RSTART = .true. flow returns here.   |   
+             %--------------------------------------% */
+
+    igraphdgetv0_(ido, bmat, &itry, &c_false, n, &j, &v[v_offset], ldv, &resid[1], 
+	    rnorm, &ipntr[1], &workd[1], &ierr);
+    if (*ido != 99) {
+	goto L9000;
+    }
+    if (ierr < 0) {
+	++itry;
+	if (itry <= 3) {
+	    goto L20;
+	}
+
+/*              %------------------------------------------------%   
+                | Give up after several restart attempts.        |   
+                | Set INFO to the size of the invariant subspace |   
+                | which spans OP and exit.                       |   
+                %------------------------------------------------% */
+
+	*info = j - 1;
+	igraphsecond_(&t1);
+	tnaitr += t1 - t0;
+	*ido = 99;
+	goto L9000;
+    }
+
+L40:
+
+/*        %---------------------------------------------------------%   
+          | STEP 2:  v_{j} = r_{j-1}/rnorm and p_{j} = p_{j}/rnorm  |   
+          | Note that p_{j} = B*r_{j-1}. In order to avoid overflow |   
+          | when reciprocating a small RNORM, test against lower    |   
+          | machine bound.                                          |   
+          %---------------------------------------------------------% */
+
+    igraphdcopy_(n, &resid[1], &c__1, &v[j * v_dim1 + 1], &c__1);
+    if (*rnorm >= unfl) {
+	temp1 = 1. / *rnorm;
+	igraphdscal_(n, &temp1, &v[j * v_dim1 + 1], &c__1);
+	igraphdscal_(n, &temp1, &workd[ipj], &c__1);
+    } else {
+
+/*            %-----------------------------------------%   
+              | To scale both v_{j} and p_{j} carefully |   
+              | use LAPACK routine SLASCL               |   
+              %-----------------------------------------% */
+
+	igraphdlascl_("General", &i__, &i__, rnorm, &c_b25, n, &c__1, &v[j * v_dim1 
+		+ 1], n, &infol);
+	igraphdlascl_("General", &i__, &i__, rnorm, &c_b25, n, &c__1, &workd[ipj], 
+		n, &infol);
+    }
+
+/*        %------------------------------------------------------%   
+          | STEP 3:  r_{j} = OP*v_{j}; Note that p_{j} = B*v_{j} |   
+          | Note that this is not quite yet r_{j}. See STEP 4    |   
+          %------------------------------------------------------% */
+
+    step3 = TRUE_;
+    ++nopx;
+    igraphsecond_(&t2);
+    igraphdcopy_(n, &v[j * v_dim1 + 1], &c__1, &workd[ivj], &c__1);
+    ipntr[1] = ivj;
+    ipntr[2] = irj;
+    ipntr[3] = ipj;
+    *ido = 1;
+
+/*        %-----------------------------------%   
+          | Exit in order to compute OP*v_{j} |   
+          %-----------------------------------% */
+
+    goto L9000;
+L50:
+
+/*        %----------------------------------%   
+          | Back from reverse communication; |   
+          | WORKD(IRJ:IRJ+N-1) := OP*v_{j}   |   
+          | if step3 = .true.                |   
+          %----------------------------------% */
+
+    igraphsecond_(&t3);
+    tmvopx += t3 - t2;
+    step3 = FALSE_;
+
+/*        %------------------------------------------%   
+          | Put another copy of OP*v_{j} into RESID. |   
+          %------------------------------------------% */
+
+    igraphdcopy_(n, &workd[irj], &c__1, &resid[1], &c__1);
+
+/*        %---------------------------------------%   
+          | STEP 4:  Finish extending the Arnoldi |   
+          |          factorization to length j.   |   
+          %---------------------------------------% */
+
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	step4 = TRUE_;
+	ipntr[1] = irj;
+	ipntr[2] = ipj;
+	*ido = 2;
+
+/*           %-------------------------------------%   
+             | Exit in order to compute B*OP*v_{j} |   
+             %-------------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+    }
+L60:
+
+/*        %----------------------------------%   
+          | Back from reverse communication; |   
+          | WORKD(IPJ:IPJ+N-1) := B*OP*v_{j} |   
+          | if step4 = .true.                |   
+          %----------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    step4 = FALSE_;
+
+/*        %-------------------------------------%   
+          | The following is needed for STEP 5. |   
+          | Compute the B-norm of OP*v_{j}.     |   
+          %-------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	wnorm = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+	wnorm = sqrt((abs(wnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	wnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+/*        %-----------------------------------------%   
+          | Compute the j-th residual corresponding |   
+          | to the j step factorization.            |   
+          | Use Classical Gram Schmidt and compute: |   
+          | w_{j} <-  V_{j}^T * B * OP * v_{j}      |   
+          | r_{j} <-  OP*v_{j} - V_{j} * w_{j}      |   
+          %-----------------------------------------%   
+
+
+          %------------------------------------------%   
+          | Compute the j Fourier coefficients w_{j} |   
+          | WORKD(IPJ:IPJ+N-1) contains B*OP*v_{j}.  |   
+          %------------------------------------------% */
+
+    igraphdgemv_("T", n, &j, &c_b25, &v[v_offset], ldv, &workd[ipj], &c__1, &c_b47, 
+	    &h__[j * h_dim1 + 1], &c__1);
+
+/*        %--------------------------------------%   
+          | Orthogonalize r_{j} against V_{j}.   |   
+          | RESID contains OP*v_{j}. See STEP 3. |   
+          %--------------------------------------% */
+
+    igraphdgemv_("N", n, &j, &c_b50, &v[v_offset], ldv, &h__[j * h_dim1 + 1], &c__1,
+	     &c_b25, &resid[1], &c__1);
+
+    if (j > 1) {
+	h__[j + (j - 1) * h_dim1] = betaj;
+    }
+
+    igraphsecond_(&t4);
+
+    orth1 = TRUE_;
+
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[irj], &c__1);
+	ipntr[1] = irj;
+	ipntr[2] = ipj;
+	*ido = 2;
+
+/*           %----------------------------------%   
+             | Exit in order to compute B*r_{j} |   
+             %----------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+    }
+L70:
+
+/*        %---------------------------------------------------%   
+          | Back from reverse communication if ORTH1 = .true. |   
+          | WORKD(IPJ:IPJ+N-1) := B*r_{j}.                    |   
+          %---------------------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    orth1 = FALSE_;
+
+/*        %------------------------------%   
+          | Compute the B-norm of r_{j}. |   
+          %------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	*rnorm = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+	*rnorm = sqrt((abs(*rnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	*rnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+/*        %-----------------------------------------------------------%   
+          | STEP 5: Re-orthogonalization / Iterative refinement phase |   
+          | Maximum NITER_ITREF tries.                                |   
+          |                                                           |   
+          |          s      = V_{j}^T * B * r_{j}                     |   
+          |          r_{j}  = r_{j} - V_{j}*s                         |   
+          |          alphaj = alphaj + s_{j}                          |   
+          |                                                           |   
+          | The stopping criteria used for iterative refinement is    |   
+          | discussed in Parlett's book SEP, page 107 and in Gragg &  |   
+          | Reichel ACM TOMS paper; Algorithm 686, Dec. 1990.         |   
+          | Determine if we need to correct the residual. The goal is |   
+          | to enforce ||v(:,1:j)^T * r_{j}|| .le. eps * || r_{j} ||  |   
+          | The following test determines whether the sine of the     |   
+          | angle between  OP*x and the computed residual is less     |   
+          | than or equal to 0.717.                                   |   
+          %-----------------------------------------------------------% */
+
+    if (*rnorm > wnorm * .717f) {
+	goto L100;
+    }
+    iter = 0;
+    ++nrorth;
+
+/*        %---------------------------------------------------%   
+          | Enter the Iterative refinement phase. If further  |   
+          | refinement is necessary, loop back here. The loop |   
+          | variable is ITER. Perform a step of Classical     |   
+          | Gram-Schmidt using all the Arnoldi vectors V_{j}  |   
+          %---------------------------------------------------% */
+
+L80:
+
+    if (msglvl > 2) {
+	xtemp[0] = wnorm;
+	xtemp[1] = *rnorm;
+	igraphdvout_(&logfil, &c__2, xtemp, &ndigit, "_naitr: re-orthonalization; "
+		"wnorm and rnorm are", (ftnlen)47);
+	igraphdvout_(&logfil, &j, &h__[j * h_dim1 + 1], &ndigit, "_naitr: j-th col"
+		"umn of H", (ftnlen)24);
+    }
+
+/*        %----------------------------------------------------%   
+          | Compute V_{j}^T * B * r_{j}.                       |   
+          | WORKD(IRJ:IRJ+J-1) = v(:,1:J)'*WORKD(IPJ:IPJ+N-1). |   
+          %----------------------------------------------------% */
+
+    igraphdgemv_("T", n, &j, &c_b25, &v[v_offset], ldv, &workd[ipj], &c__1, &c_b47, 
+	    &workd[irj], &c__1);
+
+/*        %---------------------------------------------%   
+          | Compute the correction to the residual:     |   
+          | r_{j} = r_{j} - V_{j} * WORKD(IRJ:IRJ+J-1). |   
+          | The correction to H is v(:,1:J)*H(1:J,1:J)  |   
+          | + v(:,1:J)*WORKD(IRJ:IRJ+J-1)*e'_j.         |   
+          %---------------------------------------------% */
+
+    igraphdgemv_("N", n, &j, &c_b50, &v[v_offset], ldv, &workd[irj], &c__1, &c_b25, 
+	    &resid[1], &c__1);
+    igraphdaxpy_(&j, &c_b25, &workd[irj], &c__1, &h__[j * h_dim1 + 1], &c__1);
+
+    orth2 = TRUE_;
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[irj], &c__1);
+	ipntr[1] = irj;
+	ipntr[2] = ipj;
+	*ido = 2;
+
+/*           %-----------------------------------%   
+             | Exit in order to compute B*r_{j}. |   
+             | r_{j} is the corrected residual.  |   
+             %-----------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+    }
+L90:
+
+/*        %---------------------------------------------------%   
+          | Back from reverse communication if ORTH2 = .true. |   
+          %---------------------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+/*        %-----------------------------------------------------%   
+          | Compute the B-norm of the corrected residual r_{j}. |   
+          %-----------------------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	rnorm1 = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+	rnorm1 = sqrt((abs(rnorm1)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	rnorm1 = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+    if (msglvl > 0 && iter > 0) {
+	igraphivout_(&logfil, &c__1, &j, &ndigit, "_naitr: Iterative refinement fo"
+		"r Arnoldi residual", (ftnlen)49);
+	if (msglvl > 2) {
+	    xtemp[0] = *rnorm;
+	    xtemp[1] = rnorm1;
+	    igraphdvout_(&logfil, &c__2, xtemp, &ndigit, "_naitr: iterative refine"
+		    "ment ; rnorm and rnorm1 are", (ftnlen)51);
+	}
+    }
+
+/*        %-----------------------------------------%   
+          | Determine if we need to perform another |   
+          | step of re-orthogonalization.           |   
+          %-----------------------------------------% */
+
+    if (rnorm1 > *rnorm * .717f) {
+
+/*           %---------------------------------------%   
+             | No need for further refinement.       |   
+             | The cosine of the angle between the   |   
+             | corrected residual vector and the old |   
+             | residual vector is greater than 0.717 |   
+             | In other words the corrected residual |   
+             | and the old residual vector share an  |   
+             | angle of less than arcCOS(0.717)      |   
+             %---------------------------------------% */
+
+	*rnorm = rnorm1;
+
+    } else {
+
+/*           %-------------------------------------------%   
+             | Another step of iterative refinement step |   
+             | is required. NITREF is used by stat.h     |   
+             %-------------------------------------------% */
+
+	++nitref;
+	*rnorm = rnorm1;
+	++iter;
+	if (iter <= 1) {
+	    goto L80;
+	}
+
+/*           %-------------------------------------------------%   
+             | Otherwise RESID is numerically in the span of V |   
+             %-------------------------------------------------% */
+
+	i__1 = *n;
+	for (jj = 1; jj <= i__1; ++jj) {
+	    resid[jj] = 0.;
+/* L95: */
+	}
+	*rnorm = 0.;
+    }
+
+/*        %----------------------------------------------%   
+          | Branch here directly if iterative refinement |   
+          | wasn't necessary or after at most NITER_REF  |   
+          | steps of iterative refinement.               |   
+          %----------------------------------------------% */
+
+L100:
+
+    rstart = FALSE_;
+    orth2 = FALSE_;
+
+    igraphsecond_(&t5);
+    titref += t5 - t4;
+
+/*        %------------------------------------%   
+          | STEP 6: Update  j = j+1;  Continue |   
+          %------------------------------------% */
+
+    ++j;
+    if (j > *k + *np) {
+	igraphsecond_(&t1);
+	tnaitr += t1 - t0;
+	*ido = 99;
+	i__1 = *k + *np - 1;
+	for (i__ = max(1,*k); i__ <= i__1; ++i__) {
+
+/*              %--------------------------------------------%   
+                | Check for splitting and deflation.         |   
+                | Use a standard test as in the QR algorithm |   
+                | REFERENCE: LAPACK subroutine dlahqr        |   
+                %--------------------------------------------% */
+
+	    tst1 = (d__1 = h__[i__ + i__ * h_dim1], abs(d__1)) + (d__2 = h__[
+		    i__ + 1 + (i__ + 1) * h_dim1], abs(d__2));
+	    if (tst1 == 0.) {
+		i__2 = *k + *np;
+		tst1 = igraphdlanhs_("1", &i__2, &h__[h_offset], ldh, &workd[*n + 1]
+			);
+	    }
+/* Computing MAX */
+	    d__2 = ulp * tst1;
+	    if ((d__1 = h__[i__ + 1 + i__ * h_dim1], abs(d__1)) <= max(d__2,
+		    smlnum)) {
+		h__[i__ + 1 + i__ * h_dim1] = 0.;
+	    }
+/* L110: */
+	}
+
+	if (msglvl > 2) {
+	    i__1 = *k + *np;
+	    i__2 = *k + *np;
+	    igraphdmout_(&logfil, &i__1, &i__2, &h__[h_offset], ldh, &ndigit, "_na"
+		    "itr: Final upper Hessenberg matrix H of order K+NP", (
+		    ftnlen)53);
+	}
+
+	goto L9000;
+    }
+
+/*        %--------------------------------------------------------%   
+          | Loop back to extend the factorization by another step. |   
+          %--------------------------------------------------------% */
+
+    goto L1000;
+
+/*     %---------------------------------------------------------------%   
+       |                                                               |   
+       |  E N D     O F     M A I N     I T E R A T I O N     L O O P  |   
+       |                                                               |   
+       %---------------------------------------------------------------% */
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dnaitr |   
+       %---------------% */
+
+} /* igraphdnaitr_ */
+
diff --git a/src/lapack/dnapps.c b/src/lapack/dnapps.c
new file mode 100644
index 0000000..66ba2a9
--- /dev/null
+++ b/src/lapack/dnapps.c
@@ -0,0 +1,795 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b5 = 0.;
+static doublereal c_b6 = 1.;
+static integer c__1 = 1;
+static doublereal c_b43 = -1.;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dnapps   
+
+   \Description:   
+    Given the Arnoldi factorization   
+
+       A*V_{k} - V_{k}*H_{k} = r_{k+p}*e_{k+p}^T,   
+
+    apply NP implicit shifts resulting in   
+
+       A*(V_{k}*Q) - (V_{k}*Q)*(Q^T* H_{k}*Q) = r_{k+p}*e_{k+p}^T * Q   
+
+    where Q is an orthogonal matrix which is the product of rotations   
+    and reflections resulting from the NP bulge chage sweeps.   
+    The updated Arnoldi factorization becomes:   
+
+       A*VNEW_{k} - VNEW_{k}*HNEW_{k} = rnew_{k}*e_{k}^T.   
+
+   \Usage:   
+    call dnapps   
+       ( N, KEV, NP, SHIFTR, SHIFTI, V, LDV, H, LDH, RESID, Q, LDQ,   
+         WORKL, WORKD )   
+
+   \Arguments   
+    N       Integer.  (INPUT)   
+            Problem size, i.e. size of matrix A.   
+
+    KEV     Integer.  (INPUT/OUTPUT)   
+            KEV+NP is the size of the input matrix H.   
+            KEV is the size of the updated matrix HNEW.  KEV is only   
+            updated on ouput when fewer than NP shifts are applied in   
+            order to keep the conjugate pair together.   
+
+    NP      Integer.  (INPUT)   
+            Number of implicit shifts to be applied.   
+
+    SHIFTR, Double precision array of length NP.  (INPUT)   
+    SHIFTI  Real and imaginary part of the shifts to be applied.   
+            Upon, entry to dnapps, the shifts must be sorted so that the   
+            conjugate pairs are in consecutive locations.   
+
+    V       Double precision N by (KEV+NP) array.  (INPUT/OUTPUT)   
+            On INPUT, V contains the current KEV+NP Arnoldi vectors.   
+            On OUTPUT, V contains the updated KEV Arnoldi vectors   
+            in the first KEV columns of V.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    H       Double precision (KEV+NP) by (KEV+NP) array.  (INPUT/OUTPUT)   
+            On INPUT, H contains the current KEV+NP by KEV+NP upper   
+            Hessenber matrix of the Arnoldi factorization.   
+            On OUTPUT, H contains the updated KEV by KEV upper Hessenberg   
+            matrix in the KEV leading submatrix.   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    RESID   Double precision array of length N.  (INPUT/OUTPUT)   
+            On INPUT, RESID contains the the residual vector r_{k+p}.   
+            On OUTPUT, RESID is the update residual vector rnew_{k}   
+            in the first KEV locations.   
+
+    Q       Double precision KEV+NP by KEV+NP work array.  (WORKSPACE)   
+            Work array used to accumulate the rotations and reflections   
+            during the bulge chase sweep.   
+
+    LDQ     Integer.  (INPUT)   
+            Leading dimension of Q exactly as declared in the calling   
+            program.   
+
+    WORKL   Double precision work array of length (KEV+NP).  (WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.   
+
+    WORKD   Double precision work array of length 2*N.  (WORKSPACE)   
+            Distributed array used in the application of the accumulated   
+            orthogonal matrix Q.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+
+   \Routines called:   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dmout   ARPACK utility routine that prints matrices.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlabad  LAPACK routine that computes machine constants.   
+       dlacpy  LAPACK matrix copy routine.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlanhs  LAPACK routine that computes various norms of a matrix.   
+       dlapy2  LAPACK routine to compute sqrt(x**2+y**2) carefully.   
+       dlarf   LAPACK routine that applies Householder reflection to   
+               a matrix.   
+       dlarfg  LAPACK Householder reflection construction routine.   
+       dlartg  LAPACK Givens rotation construction routine.   
+       dlaset  LAPACK matrix initialization routine.   
+       dgemv   Level 2 BLAS routine for matrix vector multiplication.   
+       daxpy   Level 1 BLAS that computes a vector triad.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       dscal   Level 1 BLAS that scales a vector.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: napps.F   SID: 2.3   DATE OF SID: 4/20/96   RELEASE: 2   
+
+   \Remarks   
+    1. In this version, each shift is applied to all the sublocks of   
+       the Hessenberg matrix H and not just to the submatrix that it   
+       comes from. Deflation as in LAPACK routine dlahqr (QR algorithm   
+       for upper Hessenberg matrices ) is used.   
+       The subdiagonals of H are enforced to be non-negative.   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdnapps_(integer *n, integer *kev, integer *np, 
+	doublereal *shiftr, doublereal *shifti, doublereal *v, integer *ldv, 
+	doublereal *h__, integer *ldh, doublereal *resid, doublereal *q, 
+	integer *ldq, doublereal *workl, doublereal *workd)
+{
+    /* Initialized data */
+
+    IGRAPH_F77_SAVE logical first = TRUE_;
+
+    /* System generated locals */
+    integer h_dim1, h_offset, v_dim1, v_offset, q_dim1, q_offset, i__1, i__2, 
+	    i__3, i__4;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    doublereal c__, f, g;
+    integer i__, j;
+    doublereal r__, s, t, u[3];
+    real t0, t1;
+    doublereal h11, h12, h21, h22, h32;
+    integer jj, ir, nr;
+    doublereal tau;
+    IGRAPH_F77_SAVE doublereal ulp;
+    doublereal tst1;
+    integer iend;
+    IGRAPH_F77_SAVE doublereal unfl, ovfl;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *), igraphdlarf_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *);
+    logical cconj;
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *), igraphdcopy_(integer *, 
+	    doublereal *, integer *, doublereal *, integer *), igraphdaxpy_(integer 
+	    *, doublereal *, doublereal *, integer *, doublereal *, integer *)
+	    , igraphdmout_(integer *, integer *, integer *, doublereal *, integer *,
+	     integer *, char *, ftnlen), igraphdvout_(integer *, integer *, 
+	    doublereal *, integer *, char *, ftnlen), igraphivout_(integer *, 
+	    integer *, integer *, integer *, char *, ftnlen);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlabad_(doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlarfg_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *);
+    doublereal sigmai;
+    extern doublereal igraphdlanhs_(char *, integer *, doublereal *, integer *, 
+	    doublereal *);
+    extern /* Subroutine */ int igraphsecond_(real *), igraphdlacpy_(char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *), igraphdlaset_(char *, integer *, integer *, doublereal *, 
+	    doublereal *, doublereal *, integer *), igraphdlartg_(
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *);
+    integer logfil=0, ndigit;
+    doublereal sigmar;
+    integer mnapps=0, msglvl;
+    real tnapps;
+    integer istart;
+    IGRAPH_F77_SAVE doublereal smlnum;
+    integer kplusp;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %------------------------%   
+       | Local Scalars & Arrays |   
+       %------------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %----------------------%   
+       | Intrinsics Functions |   
+       %----------------------%   
+
+
+       %----------------%   
+       | Data statments |   
+       %----------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    --workl;
+    --shifti;
+    --shiftr;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+
+    /* Function Body   
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    if (first) {
+
+/*        %-----------------------------------------------%   
+          | Set machine-dependent constants for the       |   
+          | stopping criterion. If norm(H) <= sqrt(OVFL), |   
+          | overflow should not occur.                    |   
+          | REFERENCE: LAPACK subroutine dlahqr           |   
+          %-----------------------------------------------% */
+
+	unfl = igraphdlamch_("safe minimum");
+	ovfl = 1. / unfl;
+	igraphdlabad_(&unfl, &ovfl);
+	ulp = igraphdlamch_("precision");
+	smlnum = unfl * (*n / ulp);
+	first = FALSE_;
+    }
+
+/*     %-------------------------------%   
+       | Initialize timing statistics  |   
+       | & message level for debugging |   
+       %-------------------------------% */
+
+    igraphsecond_(&t0);
+    msglvl = mnapps;
+    kplusp = *kev + *np;
+
+/*     %--------------------------------------------%   
+       | Initialize Q to the identity to accumulate |   
+       | the rotations and reflections              |   
+       %--------------------------------------------% */
+
+    igraphdlaset_("All", &kplusp, &kplusp, &c_b5, &c_b6, &q[q_offset], ldq);
+
+/*     %----------------------------------------------%   
+       | Quick return if there are no shifts to apply |   
+       %----------------------------------------------% */
+
+    if (*np == 0) {
+	goto L9000;
+    }
+
+/*     %----------------------------------------------%   
+       | Chase the bulge with the application of each |   
+       | implicit shift. Each shift is applied to the |   
+       | whole matrix including each block.           |   
+       %----------------------------------------------% */
+
+    cconj = FALSE_;
+    i__1 = *np;
+    for (jj = 1; jj <= i__1; ++jj) {
+	sigmar = shiftr[jj];
+	sigmai = shifti[jj];
+
+	if (msglvl > 2) {
+	    igraphivout_(&logfil, &c__1, &jj, &ndigit, "_napps: shift number.", (
+		    ftnlen)21);
+	    igraphdvout_(&logfil, &c__1, &sigmar, &ndigit, "_napps: The real part "
+		    "of the shift ", (ftnlen)35);
+	    igraphdvout_(&logfil, &c__1, &sigmai, &ndigit, "_napps: The imaginary "
+		    "part of the shift ", (ftnlen)40);
+	}
+
+/*        %-------------------------------------------------%   
+          | The following set of conditionals is necessary  |   
+          | in order that complex conjugate pairs of shifts |   
+          | are applied together or not at all.             |   
+          %-------------------------------------------------% */
+
+	if (cconj) {
+
+/*           %-----------------------------------------%   
+             | cconj = .true. means the previous shift |   
+             | had non-zero imaginary part.            |   
+             %-----------------------------------------% */
+
+	    cconj = FALSE_;
+	    goto L110;
+	} else if (jj < *np && abs(sigmai) > 0.) {
+
+/*           %------------------------------------%   
+             | Start of a complex conjugate pair. |   
+             %------------------------------------% */
+
+	    cconj = TRUE_;
+	} else if (jj == *np && abs(sigmai) > 0.) {
+
+/*           %----------------------------------------------%   
+             | The last shift has a nonzero imaginary part. |   
+             | Don't apply it; thus the order of the        |   
+             | compressed H is order KEV+1 since only np-1  |   
+             | were applied.                                |   
+             %----------------------------------------------% */
+
+	    ++(*kev);
+	    goto L110;
+	}
+	istart = 1;
+L20:
+
+/*        %--------------------------------------------------%   
+          | if sigmai = 0 then                               |   
+          |    Apply the jj-th shift ...                     |   
+          | else                                             |   
+          |    Apply the jj-th and (jj+1)-th together ...    |   
+          |    (Note that jj < np at this point in the code) |   
+          | end                                              |   
+          | to the current block of H. The next do loop      |   
+          | determines the current block ;                   |   
+          %--------------------------------------------------% */
+
+	i__2 = kplusp - 1;
+	for (i__ = istart; i__ <= i__2; ++i__) {
+
+/*           %----------------------------------------%   
+             | Check for splitting and deflation. Use |   
+             | a standard test as in the QR algorithm |   
+             | REFERENCE: LAPACK subroutine dlahqr    |   
+             %----------------------------------------% */
+
+	    tst1 = (d__1 = h__[i__ + i__ * h_dim1], abs(d__1)) + (d__2 = h__[
+		    i__ + 1 + (i__ + 1) * h_dim1], abs(d__2));
+	    if (tst1 == 0.) {
+		i__3 = kplusp - jj + 1;
+		tst1 = igraphdlanhs_("1", &i__3, &h__[h_offset], ldh, &workl[1]);
+	    }
+/* Computing MAX */
+	    d__2 = ulp * tst1;
+	    if ((d__1 = h__[i__ + 1 + i__ * h_dim1], abs(d__1)) <= max(d__2,
+		    smlnum)) {
+		if (msglvl > 0) {
+		    igraphivout_(&logfil, &c__1, &i__, &ndigit, "_napps: matrix sp"
+			    "litting at row/column no.", (ftnlen)42);
+		    igraphivout_(&logfil, &c__1, &jj, &ndigit, "_napps: matrix spl"
+			    "itting with shift number.", (ftnlen)43);
+		    igraphdvout_(&logfil, &c__1, &h__[i__ + 1 + i__ * h_dim1], &
+			    ndigit, "_napps: off diagonal element.", (ftnlen)
+			    29);
+		}
+		iend = i__;
+		h__[i__ + 1 + i__ * h_dim1] = 0.;
+		goto L40;
+	    }
+/* L30: */
+	}
+	iend = kplusp;
+L40:
+
+	if (msglvl > 2) {
+	    igraphivout_(&logfil, &c__1, &istart, &ndigit, "_napps: Start of curre"
+		    "nt block ", (ftnlen)31);
+	    igraphivout_(&logfil, &c__1, &iend, &ndigit, "_napps: End of current b"
+		    "lock ", (ftnlen)29);
+	}
+
+/*        %------------------------------------------------%   
+          | No reason to apply a shift to block of order 1 |   
+          %------------------------------------------------% */
+
+	if (istart == iend) {
+	    goto L100;
+	}
+
+/*        %------------------------------------------------------%   
+          | If istart + 1 = iend then no reason to apply a       |   
+          | complex conjugate pair of shifts on a 2 by 2 matrix. |   
+          %------------------------------------------------------% */
+
+	if (istart + 1 == iend && abs(sigmai) > 0.) {
+	    goto L100;
+	}
+
+	h11 = h__[istart + istart * h_dim1];
+	h21 = h__[istart + 1 + istart * h_dim1];
+	if (abs(sigmai) <= 0.) {
+
+/*           %---------------------------------------------%   
+             | Real-valued shift ==> apply single shift QR |   
+             %---------------------------------------------% */
+
+	    f = h11 - sigmar;
+	    g = h21;
+
+	    i__2 = iend - 1;
+	    for (i__ = istart; i__ <= i__2; ++i__) {
+
+/*              %-----------------------------------------------------%   
+                | Contruct the plane rotation G to zero out the bulge |   
+                %-----------------------------------------------------% */
+
+		igraphdlartg_(&f, &g, &c__, &s, &r__);
+		if (i__ > istart) {
+
+/*                 %-------------------------------------------%   
+                   | The following ensures that h(1:iend-1,1), |   
+                   | the first iend-2 off diagonal of elements |   
+                   | H, remain non negative.                   |   
+                   %-------------------------------------------% */
+
+		    if (r__ < 0.) {
+			r__ = -r__;
+			c__ = -c__;
+			s = -s;
+		    }
+		    h__[i__ + (i__ - 1) * h_dim1] = r__;
+		    h__[i__ + 1 + (i__ - 1) * h_dim1] = 0.;
+		}
+
+/*              %---------------------------------------------%   
+                | Apply rotation to the left of H;  H <- G'*H |   
+                %---------------------------------------------% */
+
+		i__3 = kplusp;
+		for (j = i__; j <= i__3; ++j) {
+		    t = c__ * h__[i__ + j * h_dim1] + s * h__[i__ + 1 + j * 
+			    h_dim1];
+		    h__[i__ + 1 + j * h_dim1] = -s * h__[i__ + j * h_dim1] + 
+			    c__ * h__[i__ + 1 + j * h_dim1];
+		    h__[i__ + j * h_dim1] = t;
+/* L50: */
+		}
+
+/*              %---------------------------------------------%   
+                | Apply rotation to the right of H;  H <- H*G |   
+                %---------------------------------------------%   
+
+   Computing MIN */
+		i__4 = i__ + 2;
+		i__3 = min(i__4,iend);
+		for (j = 1; j <= i__3; ++j) {
+		    t = c__ * h__[j + i__ * h_dim1] + s * h__[j + (i__ + 1) * 
+			    h_dim1];
+		    h__[j + (i__ + 1) * h_dim1] = -s * h__[j + i__ * h_dim1] 
+			    + c__ * h__[j + (i__ + 1) * h_dim1];
+		    h__[j + i__ * h_dim1] = t;
+/* L60: */
+		}
+
+/*              %----------------------------------------------------%   
+                | Accumulate the rotation in the matrix Q;  Q <- Q*G |   
+                %----------------------------------------------------%   
+
+   Computing MIN */
+		i__4 = j + jj;
+		i__3 = min(i__4,kplusp);
+		for (j = 1; j <= i__3; ++j) {
+		    t = c__ * q[j + i__ * q_dim1] + s * q[j + (i__ + 1) * 
+			    q_dim1];
+		    q[j + (i__ + 1) * q_dim1] = -s * q[j + i__ * q_dim1] + 
+			    c__ * q[j + (i__ + 1) * q_dim1];
+		    q[j + i__ * q_dim1] = t;
+/* L70: */
+		}
+
+/*              %---------------------------%   
+                | Prepare for next rotation |   
+                %---------------------------% */
+
+		if (i__ < iend - 1) {
+		    f = h__[i__ + 1 + i__ * h_dim1];
+		    g = h__[i__ + 2 + i__ * h_dim1];
+		}
+/* L80: */
+	    }
+
+/*           %-----------------------------------%   
+             | Finished applying the real shift. |   
+             %-----------------------------------% */
+
+	} else {
+
+/*           %----------------------------------------------------%   
+             | Complex conjugate shifts ==> apply double shift QR |   
+             %----------------------------------------------------% */
+
+	    h12 = h__[istart + (istart + 1) * h_dim1];
+	    h22 = h__[istart + 1 + (istart + 1) * h_dim1];
+	    h32 = h__[istart + 2 + (istart + 1) * h_dim1];
+
+/*           %---------------------------------------------------------%   
+             | Compute 1st column of (H - shift*I)*(H - conj(shift)*I) |   
+             %---------------------------------------------------------% */
+
+	    s = sigmar * 2.f;
+	    t = igraphdlapy2_(&sigmar, &sigmai);
+	    u[0] = (h11 * (h11 - s) + t * t) / h21 + h12;
+	    u[1] = h11 + h22 - s;
+	    u[2] = h32;
+
+	    i__2 = iend - 1;
+	    for (i__ = istart; i__ <= i__2; ++i__) {
+
+/* Computing MIN */
+		i__3 = 3, i__4 = iend - i__ + 1;
+		nr = min(i__3,i__4);
+
+/*              %-----------------------------------------------------%   
+                | Construct Householder reflector G to zero out u(1). |   
+                | G is of the form I - tau*( 1 u )' * ( 1 u' ).       |   
+                %-----------------------------------------------------% */
+
+		igraphdlarfg_(&nr, u, &u[1], &c__1, &tau);
+
+		if (i__ > istart) {
+		    h__[i__ + (i__ - 1) * h_dim1] = u[0];
+		    h__[i__ + 1 + (i__ - 1) * h_dim1] = 0.;
+		    if (i__ < iend - 1) {
+			h__[i__ + 2 + (i__ - 1) * h_dim1] = 0.;
+		    }
+		}
+		u[0] = 1.;
+
+/*              %--------------------------------------%   
+                | Apply the reflector to the left of H |   
+                %--------------------------------------% */
+
+		i__3 = kplusp - i__ + 1;
+		igraphdlarf_("Left", &nr, &i__3, u, &c__1, &tau, &h__[i__ + i__ * 
+			h_dim1], ldh, &workl[1]);
+
+/*              %---------------------------------------%   
+                | Apply the reflector to the right of H |   
+                %---------------------------------------%   
+
+   Computing MIN */
+		i__3 = i__ + 3;
+		ir = min(i__3,iend);
+		igraphdlarf_("Right", &ir, &nr, u, &c__1, &tau, &h__[i__ * h_dim1 + 
+			1], ldh, &workl[1]);
+
+/*              %-----------------------------------------------------%   
+                | Accumulate the reflector in the matrix Q;  Q <- Q*G |   
+                %-----------------------------------------------------% */
+
+		igraphdlarf_("Right", &kplusp, &nr, u, &c__1, &tau, &q[i__ * q_dim1 
+			+ 1], ldq, &workl[1]);
+
+/*              %----------------------------%   
+                | Prepare for next reflector |   
+                %----------------------------% */
+
+		if (i__ < iend - 1) {
+		    u[0] = h__[i__ + 1 + i__ * h_dim1];
+		    u[1] = h__[i__ + 2 + i__ * h_dim1];
+		    if (i__ < iend - 2) {
+			u[2] = h__[i__ + 3 + i__ * h_dim1];
+		    }
+		}
+
+/* L90: */
+	    }
+
+/*           %--------------------------------------------%   
+             | Finished applying a complex pair of shifts |   
+             | to the current block                       |   
+             %--------------------------------------------% */
+
+	}
+
+L100:
+
+/*        %---------------------------------------------------------%   
+          | Apply the same shift to the next block if there is any. |   
+          %---------------------------------------------------------% */
+
+	istart = iend + 1;
+	if (iend < kplusp) {
+	    goto L20;
+	}
+
+/*        %---------------------------------------------%   
+          | Loop back to the top to get the next shift. |   
+          %---------------------------------------------% */
+
+L110:
+	;
+    }
+
+/*     %--------------------------------------------------%   
+       | Perform a similarity transformation that makes   |   
+       | sure that H will have non negative sub diagonals |   
+       %--------------------------------------------------% */
+
+    i__1 = *kev;
+    for (j = 1; j <= i__1; ++j) {
+	if (h__[j + 1 + j * h_dim1] < 0.) {
+	    i__2 = kplusp - j + 1;
+	    igraphdscal_(&i__2, &c_b43, &h__[j + 1 + j * h_dim1], ldh);
+/* Computing MIN */
+	    i__3 = j + 2;
+	    i__2 = min(i__3,kplusp);
+	    igraphdscal_(&i__2, &c_b43, &h__[(j + 1) * h_dim1 + 1], &c__1);
+/* Computing MIN */
+	    i__3 = j + *np + 1;
+	    i__2 = min(i__3,kplusp);
+	    igraphdscal_(&i__2, &c_b43, &q[(j + 1) * q_dim1 + 1], &c__1);
+	}
+/* L120: */
+    }
+
+    i__1 = *kev;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+
+/*        %--------------------------------------------%   
+          | Final check for splitting and deflation.   |   
+          | Use a standard test as in the QR algorithm |   
+          | REFERENCE: LAPACK subroutine dlahqr        |   
+          %--------------------------------------------% */
+
+	tst1 = (d__1 = h__[i__ + i__ * h_dim1], abs(d__1)) + (d__2 = h__[i__ 
+		+ 1 + (i__ + 1) * h_dim1], abs(d__2));
+	if (tst1 == 0.) {
+	    tst1 = igraphdlanhs_("1", kev, &h__[h_offset], ldh, &workl[1]);
+	}
+/* Computing MAX */
+	d__1 = ulp * tst1;
+	if (h__[i__ + 1 + i__ * h_dim1] <= max(d__1,smlnum)) {
+	    h__[i__ + 1 + i__ * h_dim1] = 0.;
+	}
+/* L130: */
+    }
+
+/*     %-------------------------------------------------%   
+       | Compute the (kev+1)-st column of (V*Q) and      |   
+       | temporarily store the result in WORKD(N+1:2*N). |   
+       | This is needed in the residual update since we  |   
+       | cannot GUARANTEE that the corresponding entry   |   
+       | of H would be zero as in exact arithmetic.      |   
+       %-------------------------------------------------% */
+
+    if (h__[*kev + 1 + *kev * h_dim1] > 0.) {
+	igraphdgemv_("N", n, &kplusp, &c_b6, &v[v_offset], ldv, &q[(*kev + 1) * 
+		q_dim1 + 1], &c__1, &c_b5, &workd[*n + 1], &c__1);
+    }
+
+/*     %----------------------------------------------------------%   
+       | Compute column 1 to kev of (V*Q) in backward order       |   
+       | taking advantage of the upper Hessenberg structure of Q. |   
+       %----------------------------------------------------------% */
+
+    i__1 = *kev;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	i__2 = kplusp - i__ + 1;
+	igraphdgemv_("N", n, &i__2, &c_b6, &v[v_offset], ldv, &q[(*kev - i__ + 1) * 
+		q_dim1 + 1], &c__1, &c_b5, &workd[1], &c__1);
+	igraphdcopy_(n, &workd[1], &c__1, &v[(kplusp - i__ + 1) * v_dim1 + 1], &
+		c__1);
+/* L140: */
+    }
+
+/*     %-------------------------------------------------%   
+       |  Move v(:,kplusp-kev+1:kplusp) into v(:,1:kev). |   
+       %-------------------------------------------------% */
+
+    igraphdlacpy_("A", n, kev, &v[(kplusp - *kev + 1) * v_dim1 + 1], ldv, &v[
+	    v_offset], ldv);
+
+/*     %--------------------------------------------------------------%   
+       | Copy the (kev+1)-st column of (V*Q) in the appropriate place |   
+       %--------------------------------------------------------------% */
+
+    if (h__[*kev + 1 + *kev * h_dim1] > 0.) {
+	igraphdcopy_(n, &workd[*n + 1], &c__1, &v[(*kev + 1) * v_dim1 + 1], &c__1);
+    }
+
+/*     %-------------------------------------%   
+       | Update the residual vector:         |   
+       |    r <- sigmak*r + betak*v(:,kev+1) |   
+       | where                               |   
+       |    sigmak = (e_{kplusp}'*Q)*e_{kev} |   
+       |    betak = e_{kev+1}'*H*e_{kev}     |   
+       %-------------------------------------% */
+
+    igraphdscal_(n, &q[kplusp + *kev * q_dim1], &resid[1], &c__1);
+    if (h__[*kev + 1 + *kev * h_dim1] > 0.) {
+	igraphdaxpy_(n, &h__[*kev + 1 + *kev * h_dim1], &v[(*kev + 1) * v_dim1 + 1],
+		 &c__1, &resid[1], &c__1);
+    }
+
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, &c__1, &q[kplusp + *kev * q_dim1], &ndigit, "_napps:"
+		" sigmak = (e_{kev+p}^T*Q)*e_{kev}", (ftnlen)40);
+	igraphdvout_(&logfil, &c__1, &h__[*kev + 1 + *kev * h_dim1], &ndigit, "_na"
+		"pps: betak = e_{kev+1}^T*H*e_{kev}", (ftnlen)37);
+	igraphivout_(&logfil, &c__1, kev, &ndigit, "_napps: Order of the final Hes"
+		"senberg matrix ", (ftnlen)45);
+	if (msglvl > 2) {
+	    igraphdmout_(&logfil, kev, kev, &h__[h_offset], ldh, &ndigit, "_napps:"
+		    " updated Hessenberg matrix H for next iteration", (ftnlen)
+		    54);
+	}
+
+    }
+
+L9000:
+    igraphsecond_(&t1);
+    tnapps += t1 - t0;
+
+    return 0;
+
+/*     %---------------%   
+       | End of dnapps |   
+       %---------------% */
+
+} /* igraphdnapps_ */
+
diff --git a/src/lapack/dnaup2.c b/src/lapack/dnaup2.c
new file mode 100644
index 0000000..a8aa601
--- /dev/null
+++ b/src/lapack/dnaup2.c
@@ -0,0 +1,978 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b3 = .66666666666666663;
+static integer c__1 = 1;
+static integer c__0 = 0;
+static integer c__4 = 4;
+static logical c_true = TRUE_;
+static integer c__2 = 2;
+
+/* \BeginDoc   
+
+   \Name: dnaup2   
+
+   \Description:   
+    Intermediate level interface called by dnaupd.   
+
+   \Usage:   
+    call dnaup2   
+       ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD,   
+         ISHIFT, MXITER, V, LDV, H, LDH, RITZR, RITZI, BOUNDS,   
+         Q, LDQ, WORKL, IPNTR, WORKD, INFO )   
+
+   \Arguments   
+
+    IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dnaupd.   
+    MODE, ISHIFT, MXITER: see the definition of IPARAM in dnaupd.   
+
+    NP      Integer.  (INPUT/OUTPUT)   
+            Contains the number of implicit shifts to apply during   
+            each Arnoldi iteration.   
+            If ISHIFT=1, NP is adjusted dynamically at each iteration   
+            to accelerate convergence and prevent stagnation.   
+            This is also roughly equal to the number of matrix-vector   
+            products (involving the operator OP) per Arnoldi iteration.   
+            The logic for adjusting is contained within the current   
+            subroutine.   
+            If ISHIFT=0, NP is the number of shifts the user needs   
+            to provide via reverse comunication. 0 < NP < NCV-NEV.   
+            NP may be less than NCV-NEV for two reasons. The first, is   
+            to keep complex conjugate pairs of "wanted" Ritz values   
+            together. The second, is that a leading block of the current   
+            upper Hessenberg matrix has split off and contains "unwanted"   
+            Ritz values.   
+            Upon termination of the IRA iteration, NP contains the number   
+            of "converged" wanted Ritz values.   
+
+    IUPD    Integer.  (INPUT)   
+            IUPD .EQ. 0: use explicit restart instead implicit update.   
+            IUPD .NE. 0: use implicit update.   
+
+    V       Double precision N by (NEV+NP) array.  (INPUT/OUTPUT)   
+            The Arnoldi basis vectors are returned in the first NEV   
+            columns of V.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    H       Double precision (NEV+NP) by (NEV+NP) array.  (OUTPUT)   
+            H is used to store the generated upper Hessenberg matrix   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    RITZR,  Double precision arrays of length NEV+NP.  (OUTPUT)   
+    RITZI   RITZR(1:NEV) (resp. RITZI(1:NEV)) contains the real (resp.   
+            imaginary) part of the computed Ritz values of OP.   
+
+    BOUNDS  Double precision array of length NEV+NP.  (OUTPUT)   
+            BOUNDS(1:NEV) contain the error bounds corresponding to   
+            the computed Ritz values.   
+
+    Q       Double precision (NEV+NP) by (NEV+NP) array.  (WORKSPACE)   
+            Private (replicated) work array used to accumulate the   
+            rotation in the shift application step.   
+
+    LDQ     Integer.  (INPUT)   
+            Leading dimension of Q exactly as declared in the calling   
+            program.   
+
+    WORKL   Double precision work array of length at least   
+            (NEV+NP)**2 + 3*(NEV+NP).  (INPUT/WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.  It is used in shifts calculation, shifts   
+            application and convergence checking.   
+
+            On exit, the last 3*(NEV+NP) locations of WORKL contain   
+            the Ritz values (real,imaginary) and associated Ritz   
+            estimates of the current Hessenberg matrix.  They are   
+            listed in the same order as returned from dneigh.   
+
+            If ISHIFT .EQ. O and IDO .EQ. 3, the first 2*NP locations   
+            of WORKL are used in reverse communication to hold the user   
+            supplied shifts.   
+
+    IPNTR   Integer array of length 3.  (OUTPUT)   
+            Pointer to mark the starting locations in the WORKD for   
+            vectors used by the Arnoldi iteration.   
+            -------------------------------------------------------------   
+            IPNTR(1): pointer to the current operand vector X.   
+            IPNTR(2): pointer to the current result vector Y.   
+            IPNTR(3): pointer to the vector B * X when used in the   
+                      shift-and-invert mode.  X is the current operand.   
+            -------------------------------------------------------------   
+
+    WORKD   Double precision work array of length 3*N.  (WORKSPACE)   
+            Distributed array to be used in the basic Arnoldi iteration   
+            for reverse communication.  The user should not use WORKD   
+            as temporary workspace during the iteration !!!!!!!!!!   
+            See Data Distribution Note in DNAUPD.   
+
+    INFO    Integer.  (INPUT/OUTPUT)   
+            If INFO .EQ. 0, a randomly initial residual vector is used.   
+            If INFO .NE. 0, RESID contains the initial residual vector,   
+                            possibly from a previous run.   
+            Error flag on output.   
+            =     0: Normal return.   
+            =     1: Maximum number of iterations taken.   
+                     All possible eigenvalues of OP has been found.   
+                     NP returns the number of converged Ritz values.   
+            =     2: No shifts could be applied.   
+            =    -8: Error return from LAPACK eigenvalue calculation;   
+                     This should never happen.   
+            =    -9: Starting vector is zero.   
+            = -9999: Could not build an Arnoldi factorization.   
+                     Size that was built in returned in NP.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+
+   \Routines called:   
+       dgetv0  ARPACK initial vector generation routine.   
+       dnaitr  ARPACK Arnoldi factorization routine.   
+       dnapps  ARPACK application of implicit shifts routine.   
+       dnconv  ARPACK convergence of Ritz values routine.   
+       dneigh  ARPACK compute Ritz values and error bounds routine.   
+       dngets  ARPACK reorder Ritz values and error bounds routine.   
+       dsortc  ARPACK sorting routine.   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dmout   ARPACK utility routine that prints matrices   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlapy2  LAPACK routine to compute sqrt(x**2+y**2) carefully.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       ddot    Level 1 BLAS that computes the scalar product of two vectors.   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+       dswap   Level 1 BLAS that swaps two vectors.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \SCCS Information: @(#)   
+   FILE: naup2.F   SID: 2.4   DATE OF SID: 7/30/96   RELEASE: 2   
+
+   \Remarks   
+       1. None   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdnaup2_(integer *ido, char *bmat, integer *n, char *
+	which, integer *nev, integer *np, doublereal *tol, doublereal *resid, 
+	integer *mode, integer *iupd, integer *ishift, integer *mxiter, 
+	doublereal *v, integer *ldv, doublereal *h__, integer *ldh, 
+	doublereal *ritzr, doublereal *ritzi, doublereal *bounds, doublereal *
+	q, integer *ldq, doublereal *workl, integer *ipntr, doublereal *workd,
+	 integer *info)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, q_dim1, q_offset, v_dim1, v_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double pow_dd(doublereal *, doublereal *);
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+    /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
+    double sqrt(doublereal);
+
+    /* Local variables */
+    IGRAPH_F77_SAVE integer j;
+    IGRAPH_F77_SAVE real t0, t1, t2, t3;
+    IGRAPH_F77_SAVE integer kp[4], np0, nbx, nev0;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    IGRAPH_F77_SAVE doublereal eps23;
+    IGRAPH_F77_SAVE integer ierr, iter;
+    IGRAPH_F77_SAVE doublereal temp;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    IGRAPH_F77_SAVE logical getv0, cnorm;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    IGRAPH_F77_SAVE integer nconv;
+    extern /* Subroutine */ int igraphdmout_(integer *, integer *, integer *, 
+	    doublereal *, integer *, integer *, char *, ftnlen);
+    IGRAPH_F77_SAVE logical initv;
+    IGRAPH_F77_SAVE doublereal rnorm;
+    IGRAPH_F77_SAVE real tmvbx;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *
+	    , logical *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    IGRAPH_F77_SAVE integer mnaup2=0;
+    IGRAPH_F77_SAVE real tnaup2;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdneigh_(doublereal *, integer *, doublereal *,
+	     integer *, doublereal *, doublereal *, doublereal *, doublereal *
+	    , integer *, doublereal *, integer *);
+    IGRAPH_F77_SAVE integer nevbef;
+    extern /* Subroutine */ int igraphsecond_(real *);
+    IGRAPH_F77_SAVE integer logfil=0, ndigit;
+    extern /* Subroutine */ int igraphdnaitr_(integer *, char *, integer *, integer 
+	    *, integer *, integer *, doublereal *, doublereal *, doublereal *,
+	     integer *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *);
+    IGRAPH_F77_SAVE logical update;
+    extern /* Subroutine */ int igraphdngets_(integer *, char *, integer *, integer 
+	    *, doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *), igraphdnapps_(integer *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, doublereal *,
+	     integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    doublereal *), igraphdnconv_(integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, integer *), igraphdsortc_(char *, logical *,
+	     integer *, doublereal *, doublereal *, doublereal *);
+    IGRAPH_F77_SAVE logical ushift;
+    IGRAPH_F77_SAVE char wprime[2];
+    IGRAPH_F77_SAVE integer msglvl, nptemp, numcnv, kplusp;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %-----------------------%   
+       | Local array arguments |   
+       %-----------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    --workl;
+    --bounds;
+    --ritzi;
+    --ritzr;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+    --ipntr;
+
+    /* Function Body */
+    if (*ido == 0) {
+
+	igraphsecond_(&t0);
+
+	msglvl = mnaup2;
+
+/*        %-------------------------------------%   
+          | Get the machine dependent constant. |   
+          %-------------------------------------% */
+
+	eps23 = igraphdlamch_("Epsilon-Machine");
+	eps23 = pow_dd(&eps23, &c_b3);
+
+	nev0 = *nev;
+	np0 = *np;
+
+/*        %-------------------------------------%   
+          | kplusp is the bound on the largest  |   
+          |        Lanczos factorization built. |   
+          | nconv is the current number of      |   
+          |        "converged" eigenvlues.      |   
+          | iter is the counter on the current  |   
+          |      iteration step.                |   
+          %-------------------------------------% */
+
+	kplusp = *nev + *np;
+	nconv = 0;
+	iter = 0;
+
+/*        %---------------------------------------%   
+          | Set flags for computing the first NEV |   
+          | steps of the Arnoldi factorization.   |   
+          %---------------------------------------% */
+
+	getv0 = TRUE_;
+	update = FALSE_;
+	ushift = FALSE_;
+	cnorm = FALSE_;
+
+	if (*info != 0) {
+
+/*           %--------------------------------------------%   
+             | User provides the initial residual vector. |   
+             %--------------------------------------------% */
+
+	    initv = TRUE_;
+	    *info = 0;
+	} else {
+	    initv = FALSE_;
+	}
+    }
+
+/*     %---------------------------------------------%   
+       | Get a possibly random starting vector and   |   
+       | force it into the range of the operator OP. |   
+       %---------------------------------------------%   
+
+   L10: */
+
+    if (getv0) {
+	igraphdgetv0_(ido, bmat, &c__1, &initv, n, &c__1, &v[v_offset], ldv, &resid[
+		1], &rnorm, &ipntr[1], &workd[1], info);
+
+	if (*ido != 99) {
+	    goto L9000;
+	}
+
+	if (rnorm == 0.) {
+
+/*           %-----------------------------------------%   
+             | The initial vector is zero. Error exit. |   
+             %-----------------------------------------% */
+
+	    *info = -9;
+	    goto L1100;
+	}
+	getv0 = FALSE_;
+	*ido = 0;
+    }
+
+/*     %-----------------------------------%   
+       | Back from reverse communication : |   
+       | continue with update step         |   
+       %-----------------------------------% */
+
+    if (update) {
+	goto L20;
+    }
+
+/*     %-------------------------------------------%   
+       | Back from computing user specified shifts |   
+       %-------------------------------------------% */
+
+    if (ushift) {
+	goto L50;
+    }
+
+/*     %-------------------------------------%   
+       | Back from computing residual norm   |   
+       | at the end of the current iteration |   
+       %-------------------------------------% */
+
+    if (cnorm) {
+	goto L100;
+    }
+
+/*     %----------------------------------------------------------%   
+       | Compute the first NEV steps of the Arnoldi factorization |   
+       %----------------------------------------------------------% */
+
+    igraphdnaitr_(ido, bmat, n, &c__0, nev, mode, &resid[1], &rnorm, &v[v_offset], 
+	    ldv, &h__[h_offset], ldh, &ipntr[1], &workd[1], info);
+
+/*     %---------------------------------------------------%   
+       | ido .ne. 99 implies use of reverse communication  |   
+       | to compute operations involving OP and possibly B |   
+       %---------------------------------------------------% */
+
+    if (*ido != 99) {
+	goto L9000;
+    }
+
+    if (*info > 0) {
+	*np = *info;
+	*mxiter = iter;
+	*info = -9999;
+	goto L1200;
+    }
+
+/*     %--------------------------------------------------------------%   
+       |                                                              |   
+       |           M A I N  ARNOLDI  I T E R A T I O N  L O O P       |   
+       |           Each iteration implicitly restarts the Arnoldi     |   
+       |           factorization in place.                            |   
+       |                                                              |   
+       %--------------------------------------------------------------% */
+
+L1000:
+
+    ++iter;
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &iter, &ndigit, "_naup2: **** Start of major "
+		"iteration number ****", (ftnlen)49);
+    }
+
+/*        %-----------------------------------------------------------%   
+          | Compute NP additional steps of the Arnoldi factorization. |   
+          | Adjust NP since NEV might have been updated by last call  |   
+          | to the shift application routine dnapps.                  |   
+          %-----------------------------------------------------------% */
+
+    *np = kplusp - *nev;
+
+    if (msglvl > 1) {
+	igraphivout_(&logfil, &c__1, nev, &ndigit, "_naup2: The length of the curr"
+		"ent Arnoldi factorization", (ftnlen)55);
+	igraphivout_(&logfil, &c__1, np, &ndigit, "_naup2: Extend the Arnoldi fact"
+		"orization by", (ftnlen)43);
+    }
+
+/*        %-----------------------------------------------------------%   
+          | Compute NP additional steps of the Arnoldi factorization. |   
+          %-----------------------------------------------------------% */
+
+    *ido = 0;
+L20:
+    update = TRUE_;
+
+    igraphdnaitr_(ido, bmat, n, nev, np, mode, &resid[1], &rnorm, &v[v_offset], ldv,
+	     &h__[h_offset], ldh, &ipntr[1], &workd[1], info);
+
+/*        %---------------------------------------------------%   
+          | ido .ne. 99 implies use of reverse communication  |   
+          | to compute operations involving OP and possibly B |   
+          %---------------------------------------------------% */
+
+    if (*ido != 99) {
+	goto L9000;
+    }
+
+    if (*info > 0) {
+	*np = *info;
+	*mxiter = iter;
+	*info = -9999;
+	goto L1200;
+    }
+    update = FALSE_;
+
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_naup2: Corresponding B-nor"
+		"m of the residual", (ftnlen)44);
+    }
+
+/*        %--------------------------------------------------------%   
+          | Compute the eigenvalues and corresponding error bounds |   
+          | of the current upper Hessenberg matrix.                |   
+          %--------------------------------------------------------% */
+
+    igraphdneigh_(&rnorm, &kplusp, &h__[h_offset], ldh, &ritzr[1], &ritzi[1], &
+	    bounds[1], &q[q_offset], ldq, &workl[1], &ierr);
+
+    if (ierr != 0) {
+	*info = -8;
+	goto L1200;
+    }
+
+/*        %----------------------------------------------------%   
+          | Make a copy of eigenvalues and corresponding error |   
+          | bounds obtained from dneigh.                       |   
+          %----------------------------------------------------%   
+
+   Computing 2nd power */
+    i__1 = kplusp;
+    igraphdcopy_(&kplusp, &ritzr[1], &c__1, &workl[i__1 * i__1 + 1], &c__1);
+/* Computing 2nd power */
+    i__1 = kplusp;
+    igraphdcopy_(&kplusp, &ritzi[1], &c__1, &workl[i__1 * i__1 + kplusp + 1], &c__1)
+	    ;
+/* Computing 2nd power */
+    i__1 = kplusp;
+    igraphdcopy_(&kplusp, &bounds[1], &c__1, &workl[i__1 * i__1 + (kplusp << 1) + 1]
+	    , &c__1);
+
+/*        %---------------------------------------------------%   
+          | Select the wanted Ritz values and their bounds    |   
+          | to be used in the convergence test.               |   
+          | The wanted part of the spectrum and corresponding |   
+          | error bounds are in the last NEV loc. of RITZR,   |   
+          | RITZI and BOUNDS respectively. The variables NEV  |   
+          | and NP may be updated if the NEV-th wanted Ritz   |   
+          | value has a non zero imaginary part. In this case |   
+          | NEV is increased by one and NP decreased by one.  |   
+          | NOTE: The last two arguments of dngets are no     |   
+          | longer used as of version 2.1.                    |   
+          %---------------------------------------------------% */
+
+    *nev = nev0;
+    *np = np0;
+    numcnv = *nev;
+    igraphdngets_(ishift, which, nev, np, &ritzr[1], &ritzi[1], &bounds[1], &workl[
+	    1], &workl[*np + 1]);
+    if (*nev == nev0 + 1) {
+	numcnv = nev0 + 1;
+    }
+
+/*        %-------------------%   
+          | Convergence test. |   
+          %-------------------% */
+
+    igraphdcopy_(nev, &bounds[*np + 1], &c__1, &workl[(*np << 1) + 1], &c__1);
+    igraphdnconv_(nev, &ritzr[*np + 1], &ritzi[*np + 1], &workl[(*np << 1) + 1], 
+	    tol, &nconv);
+
+    if (msglvl > 2) {
+	kp[0] = *nev;
+	kp[1] = *np;
+	kp[2] = numcnv;
+	kp[3] = nconv;
+	igraphivout_(&logfil, &c__4, kp, &ndigit, "_naup2: NEV, NP, NUMCNV, NCONV "
+		"are", (ftnlen)34);
+	igraphdvout_(&logfil, &kplusp, &ritzr[1], &ndigit, "_naup2: Real part of t"
+		"he eigenvalues of H", (ftnlen)41);
+	igraphdvout_(&logfil, &kplusp, &ritzi[1], &ndigit, "_naup2: Imaginary part"
+		" of the eigenvalues of H", (ftnlen)46);
+	igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_naup2: Ritz estimate"
+		"s of the current NCV Ritz values", (ftnlen)53);
+    }
+
+/*        %---------------------------------------------------------%   
+          | Count the number of unwanted Ritz values that have zero |   
+          | Ritz estimates. If any Ritz estimates are equal to zero |   
+          | then a leading block of H of order equal to at least    |   
+          | the number of Ritz values with zero Ritz estimates has  |   
+          | split off. None of these Ritz values may be removed by  |   
+          | shifting. Decrease NP the number of shifts to apply. If |   
+          | no shifts may be applied, then prepare to exit          |   
+          %---------------------------------------------------------% */
+
+    nptemp = *np;
+    i__1 = nptemp;
+    for (j = 1; j <= i__1; ++j) {
+	if (bounds[j] == 0.) {
+	    --(*np);
+	    ++(*nev);
+	}
+/* L30: */
+    }
+
+    if (nconv >= numcnv || iter > *mxiter || *np == 0) {
+
+	if (msglvl > 4) {
+/* Computing 2nd power */
+	    i__1 = kplusp;
+	    igraphdvout_(&logfil, &kplusp, &workl[i__1 * i__1 + 1], &ndigit, "_nau"
+		    "p2: Real part of the eig computed by _neigh:", (ftnlen)48)
+		    ;
+/* Computing 2nd power */
+	    i__1 = kplusp;
+	    igraphdvout_(&logfil, &kplusp, &workl[i__1 * i__1 + kplusp + 1], &
+		    ndigit, "_naup2: Imag part of the eig computed by _neigh:"
+		    , (ftnlen)48);
+/* Computing 2nd power */
+	    i__1 = kplusp;
+	    igraphdvout_(&logfil, &kplusp, &workl[i__1 * i__1 + (kplusp << 1) + 1], 
+		    &ndigit, "_naup2: Ritz eistmates computed by _neigh:", (
+		    ftnlen)42);
+	}
+
+/*           %------------------------------------------------%   
+             | Prepare to exit. Put the converged Ritz values |   
+             | and corresponding bounds in RITZ(1:NCONV) and  |   
+             | BOUNDS(1:NCONV) respectively. Then sort. Be    |   
+             | careful when NCONV > NP                        |   
+             %------------------------------------------------%   
+
+             %------------------------------------------%   
+             |  Use h( 3,1 ) as storage to communicate  |   
+             |  rnorm to _neupd if needed               |   
+             %------------------------------------------% */
+	h__[h_dim1 + 3] = rnorm;
+
+/*           %----------------------------------------------%   
+             | To be consistent with dngets, we first do a  |   
+             | pre-processing sort in order to keep complex |   
+             | conjugate pairs together.  This is similar   |   
+             | to the pre-processing sort used in dngets    |   
+             | except that the sort is done in the opposite |   
+             | order.                                       |   
+             %----------------------------------------------% */
+
+	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "SR", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "LR", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
+	}
+
+	igraphdsortc_(wprime, &c_true, &kplusp, &ritzr[1], &ritzi[1], &bounds[1]);
+
+/*           %----------------------------------------------%   
+             | Now sort Ritz values so that converged Ritz  |   
+             | values appear within the first NEV locations |   
+             | of ritzr, ritzi and bounds, and the most     |   
+             | desired one appears at the front.            |   
+             %----------------------------------------------% */
+
+	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "SR", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "LR", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "SI", (ftnlen)2, (ftnlen)2);
+	}
+	if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
+	    s_copy(wprime, "LI", (ftnlen)2, (ftnlen)2);
+	}
+
+	igraphdsortc_(wprime, &c_true, &kplusp, &ritzr[1], &ritzi[1], &bounds[1]);
+
+/*           %--------------------------------------------------%   
+             | Scale the Ritz estimate of each Ritz value       |   
+             | by 1 / max(eps23,magnitude of the Ritz value).   |   
+             %--------------------------------------------------% */
+
+	i__1 = nev0;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MAX */
+	    d__1 = eps23, d__2 = igraphdlapy2_(&ritzr[j], &ritzi[j]);
+	    temp = max(d__1,d__2);
+	    bounds[j] /= temp;
+/* L35: */
+	}
+
+/*           %----------------------------------------------------%   
+             | Sort the Ritz values according to the scaled Ritz  |   
+             | esitmates.  This will push all the converged ones  |   
+             | towards the front of ritzr, ritzi, bounds          |   
+             | (in the case when NCONV < NEV.)                    |   
+             %----------------------------------------------------% */
+
+	s_copy(wprime, "LR", (ftnlen)2, (ftnlen)2);
+	igraphdsortc_(wprime, &c_true, &nev0, &bounds[1], &ritzr[1], &ritzi[1]);
+
+/*           %----------------------------------------------%   
+             | Scale the Ritz estimate back to its original |   
+             | value.                                       |   
+             %----------------------------------------------% */
+
+	i__1 = nev0;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MAX */
+	    d__1 = eps23, d__2 = igraphdlapy2_(&ritzr[j], &ritzi[j]);
+	    temp = max(d__1,d__2);
+	    bounds[j] *= temp;
+/* L40: */
+	}
+
+/*           %------------------------------------------------%   
+             | Sort the converged Ritz values again so that   |   
+             | the "threshold" value appears at the front of  |   
+             | ritzr, ritzi and bound.                        |   
+             %------------------------------------------------% */
+
+	igraphdsortc_(which, &c_true, &nconv, &ritzr[1], &ritzi[1], &bounds[1]);
+
+	if (msglvl > 1) {
+	    igraphdvout_(&logfil, &kplusp, &ritzr[1], &ndigit, "_naup2: Sorted rea"
+		    "l part of the eigenvalues", (ftnlen)43);
+	    igraphdvout_(&logfil, &kplusp, &ritzi[1], &ndigit, "_naup2: Sorted ima"
+		    "ginary part of the eigenvalues", (ftnlen)48);
+	    igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_naup2: Sorted ri"
+		    "tz estimates.", (ftnlen)30);
+	}
+
+/*           %------------------------------------%   
+             | Max iterations have been exceeded. |   
+             %------------------------------------% */
+
+	if (iter > *mxiter && nconv < numcnv) {
+	    *info = 1;
+	}
+
+/*           %---------------------%   
+             | No shifts to apply. |   
+             %---------------------% */
+
+	if (*np == 0 && nconv < numcnv) {
+	    *info = 2;
+	}
+
+	*np = nconv;
+	goto L1100;
+
+    } else if (nconv < numcnv && *ishift == 1) {
+
+/*           %-------------------------------------------------%   
+             | Do not have all the requested eigenvalues yet.  |   
+             | To prevent possible stagnation, adjust the size |   
+             | of NEV.                                         |   
+             %-------------------------------------------------% */
+
+	nevbef = *nev;
+/* Computing MIN */
+	i__1 = nconv, i__2 = *np / 2;
+	*nev += min(i__1,i__2);
+	if (*nev == 1 && kplusp >= 6) {
+	    *nev = kplusp / 2;
+	} else if (*nev == 1 && kplusp > 3) {
+	    *nev = 2;
+	}
+	*np = kplusp - *nev;
+
+/*           %---------------------------------------%   
+             | If the size of NEV was just increased |   
+             | resort the eigenvalues.               |   
+             %---------------------------------------% */
+
+	if (nevbef < *nev) {
+	    igraphdngets_(ishift, which, nev, np, &ritzr[1], &ritzi[1], &bounds[1], 
+		    &workl[1], &workl[*np + 1]);
+	}
+
+    }
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_naup2: no. of \"converge"
+		"d\" Ritz values at this iter.", (ftnlen)52);
+	if (msglvl > 1) {
+	    kp[0] = *nev;
+	    kp[1] = *np;
+	    igraphivout_(&logfil, &c__2, kp, &ndigit, "_naup2: NEV and NP are", (
+		    ftnlen)22);
+	    igraphdvout_(&logfil, nev, &ritzr[*np + 1], &ndigit, "_naup2: \"wante"
+		    "d\" Ritz values -- real part", (ftnlen)41);
+	    igraphdvout_(&logfil, nev, &ritzi[*np + 1], &ndigit, "_naup2: \"wante"
+		    "d\" Ritz values -- imag part", (ftnlen)41);
+	    igraphdvout_(&logfil, nev, &bounds[*np + 1], &ndigit, "_naup2: Ritz es"
+		    "timates of the \"wanted\" values ", (ftnlen)46);
+	}
+    }
+
+    if (*ishift == 0) {
+
+/*           %-------------------------------------------------------%   
+             | User specified shifts: reverse comminucation to       |   
+             | compute the shifts. They are returned in the first    |   
+             | 2*NP locations of WORKL.                              |   
+             %-------------------------------------------------------% */
+
+	ushift = TRUE_;
+	*ido = 3;
+	goto L9000;
+    }
+
+L50:
+
+/*        %------------------------------------%   
+          | Back from reverse communication;   |   
+          | User specified shifts are returned |   
+          | in WORKL(1:2*NP)                   |   
+          %------------------------------------% */
+
+    ushift = FALSE_;
+
+    if (*ishift == 0) {
+
+/*            %----------------------------------%   
+              | Move the NP shifts from WORKL to |   
+              | RITZR, RITZI to free up WORKL    |   
+              | for non-exact shift case.        |   
+              %----------------------------------% */
+
+	igraphdcopy_(np, &workl[1], &c__1, &ritzr[1], &c__1);
+	igraphdcopy_(np, &workl[*np + 1], &c__1, &ritzi[1], &c__1);
+    }
+
+    if (msglvl > 2) {
+	igraphivout_(&logfil, &c__1, np, &ndigit, "_naup2: The number of shifts to"
+		" apply ", (ftnlen)38);
+	igraphdvout_(&logfil, np, &ritzr[1], &ndigit, "_naup2: Real part of the sh"
+		"ifts", (ftnlen)31);
+	igraphdvout_(&logfil, np, &ritzi[1], &ndigit, "_naup2: Imaginary part of t"
+		"he shifts", (ftnlen)36);
+	if (*ishift == 1) {
+	    igraphdvout_(&logfil, np, &bounds[1], &ndigit, "_naup2: Ritz estimates"
+		    " of the shifts", (ftnlen)36);
+	}
+    }
+
+/*        %---------------------------------------------------------%   
+          | Apply the NP implicit shifts by QR bulge chasing.       |   
+          | Each shift is applied to the whole upper Hessenberg     |   
+          | matrix H.                                               |   
+          | The first 2*N locations of WORKD are used as workspace. |   
+          %---------------------------------------------------------% */
+
+    igraphdnapps_(n, nev, np, &ritzr[1], &ritzi[1], &v[v_offset], ldv, &h__[
+	    h_offset], ldh, &resid[1], &q[q_offset], ldq, &workl[1], &workd[1]
+	    );
+
+/*        %---------------------------------------------%   
+          | Compute the B-norm of the updated residual. |   
+          | Keep B*RESID in WORKD(1:N) to be used in    |   
+          | the first step of the next call to dnaitr.  |   
+          %---------------------------------------------% */
+
+    cnorm = TRUE_;
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[*n + 1], &c__1);
+	ipntr[1] = *n + 1;
+	ipntr[2] = 1;
+	*ido = 2;
+
+/*           %----------------------------------%   
+             | Exit in order to compute B*RESID |   
+             %----------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
+    }
+
+L100:
+
+/*        %----------------------------------%   
+          | Back from reverse communication; |   
+          | WORKD(1:N) := B*RESID            |   
+          %----------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    if (*(unsigned char *)bmat == 'G') {
+	rnorm = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1);
+	rnorm = sqrt((abs(rnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	rnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+    cnorm = FALSE_;
+
+    if (msglvl > 2) {
+	igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_naup2: B-norm of residual "
+		"for compressed factorization", (ftnlen)55);
+	igraphdmout_(&logfil, nev, nev, &h__[h_offset], ldh, &ndigit, "_naup2: Com"
+		"pressed upper Hessenberg matrix H", (ftnlen)44);
+    }
+
+    goto L1000;
+
+/*     %---------------------------------------------------------------%   
+       |                                                               |   
+       |  E N D     O F     M A I N     I T E R A T I O N     L O O P  |   
+       |                                                               |   
+       %---------------------------------------------------------------% */
+
+L1100:
+
+    *mxiter = iter;
+    *nev = numcnv;
+
+L1200:
+    *ido = 99;
+
+/*     %------------%   
+       | Error Exit |   
+       %------------% */
+
+    igraphsecond_(&t1);
+    tnaup2 = t1 - t0;
+
+L9000:
+
+/*     %---------------%   
+       | End of dnaup2 |   
+       %---------------% */
+
+    return 0;
+} /* igraphdnaup2_ */
+
diff --git a/src/lapack/dnaupd.c b/src/lapack/dnaupd.c
new file mode 100644
index 0000000..2f1fd3d
--- /dev/null
+++ b/src/lapack/dnaupd.c
@@ -0,0 +1,794 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* \BeginDoc   
+
+   \Name: dnaupd   
+
+   \Description:   
+    Reverse communication interface for the Implicitly Restarted Arnoldi   
+    iteration. This subroutine computes approximations to a few eigenpairs   
+    of a linear operator "OP" with respect to a semi-inner product defined by   
+    a symmetric positive semi-definite real matrix B. B may be the identity   
+    matrix. NOTE: If the linear operator "OP" is real and symmetric   
+    with respect to the real positive semi-definite symmetric matrix B,   
+    i.e. B*OP = (OP')*B, then subroutine ssaupd should be used instead.   
+
+    The computed approximate eigenvalues are called Ritz values and   
+    the corresponding approximate eigenvectors are called Ritz vectors.   
+
+    dnaupd is usually called iteratively to solve one of the   
+    following problems:   
+
+    Mode 1:  A*x = lambda*x.   
+             ===> OP = A  and  B = I.   
+
+    Mode 2:  A*x = lambda*M*x, M symmetric positive definite   
+             ===> OP = inv[M]*A  and  B = M.   
+             ===> (If M can be factored see remark 3 below)   
+
+    Mode 3:  A*x = lambda*M*x, M symmetric semi-definite   
+             ===> OP = Real_Part{ inv[A - sigma*M]*M }  and  B = M.   
+             ===> shift-and-invert mode (in real arithmetic)   
+             If OP*x = amu*x, then   
+             amu = 1/2 * [ 1/(lambda-sigma) + 1/(lambda-conjg(sigma)) ].   
+             Note: If sigma is real, i.e. imaginary part of sigma is zero;   
+                   Real_Part{ inv[A - sigma*M]*M } == inv[A - sigma*M]*M   
+                   amu == 1/(lambda-sigma).   
+
+    Mode 4:  A*x = lambda*M*x, M symmetric semi-definite   
+             ===> OP = Imaginary_Part{ inv[A - sigma*M]*M }  and  B = M.   
+             ===> shift-and-invert mode (in real arithmetic)   
+             If OP*x = amu*x, then   
+             amu = 1/2i * [ 1/(lambda-sigma) - 1/(lambda-conjg(sigma)) ].   
+
+    Both mode 3 and 4 give the same enhancement to eigenvalues close to   
+    the (complex) shift sigma.  However, as lambda goes to infinity,   
+    the operator OP in mode 4 dampens the eigenvalues more strongly than   
+    does OP defined in mode 3.   
+
+    NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v   
+          should be accomplished either by a direct method   
+          using a sparse matrix factorization and solving   
+
+             [A - sigma*M]*w = v  or M*w = v,   
+
+          or through an iterative method for solving these   
+          systems.  If an iterative method is used, the   
+          convergence test must be more stringent than   
+          the accuracy requirements for the eigenvalue   
+          approximations.   
+
+   \Usage:   
+    call dnaupd   
+       ( IDO, BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM,   
+         IPNTR, WORKD, WORKL, LWORKL, INFO )   
+
+   \Arguments   
+    IDO     Integer.  (INPUT/OUTPUT)   
+            Reverse communication flag.  IDO must be zero on the first   
+            call to dnaupd.  IDO will be set internally to   
+            indicate the type of operation to be performed.  Control is   
+            then given back to the calling routine which has the   
+            responsibility to carry out the requested operation and call   
+            dnaupd with the result.  The operand is given in   
+            WORKD(IPNTR(1)), the result must be put in WORKD(IPNTR(2)).   
+            -------------------------------------------------------------   
+            IDO =  0: first call to the reverse communication interface   
+            IDO = -1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+                      This is for the initialization phase to force the   
+                      starting vector into the range of OP.   
+            IDO =  1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+                      In mode 3 and 4, the vector B * X is already   
+                      available in WORKD(ipntr(3)).  It does not   
+                      need to be recomputed in forming OP * X.   
+            IDO =  2: compute  Y = B * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+            IDO =  3: compute the IPARAM(8) real and imaginary parts   
+                      of the shifts where INPTR(14) is the pointer   
+                      into WORKL for placing the shifts. See Remark   
+                      5 below.   
+            IDO = 99: done   
+            -------------------------------------------------------------   
+
+    BMAT    Character*1.  (INPUT)   
+            BMAT specifies the type of the matrix B that defines the   
+            semi-inner product for the operator OP.   
+            BMAT = 'I' -> standard eigenvalue problem A*x = lambda*x   
+            BMAT = 'G' -> generalized eigenvalue problem A*x = lambda*B*x   
+
+    N       Integer.  (INPUT)   
+            Dimension of the eigenproblem.   
+
+    WHICH   Character*2.  (INPUT)   
+            'LM' -> want the NEV eigenvalues of largest magnitude.   
+            'SM' -> want the NEV eigenvalues of smallest magnitude.   
+            'LR' -> want the NEV eigenvalues of largest real part.   
+            'SR' -> want the NEV eigenvalues of smallest real part.   
+            'LI' -> want the NEV eigenvalues of largest imaginary part.   
+            'SI' -> want the NEV eigenvalues of smallest imaginary part.   
+
+    NEV     Integer.  (INPUT)   
+            Number of eigenvalues of OP to be computed. 0 < NEV < N-1.   
+
+    TOL     Double precision scalar.  (INPUT)   
+            Stopping criterion: the relative accuracy of the Ritz value   
+            is considered acceptable if BOUNDS(I) .LE. TOL*ABS(RITZ(I))   
+            where ABS(RITZ(I)) is the magnitude when RITZ(I) is complex.   
+            DEFAULT = DLAMCH('EPS')  (machine precision as computed   
+                      by the LAPACK auxiliary subroutine DLAMCH).   
+
+    RESID   Double precision array of length N.  (INPUT/OUTPUT)   
+            On INPUT:   
+            If INFO .EQ. 0, a random initial residual vector is used.   
+            If INFO .NE. 0, RESID contains the initial residual vector,   
+                            possibly from a previous run.   
+            On OUTPUT:   
+            RESID contains the final residual vector.   
+
+    NCV     Integer.  (INPUT)   
+            Number of columns of the matrix V. NCV must satisfy the two   
+            inequalities 2 <= NCV-NEV and NCV <= N.   
+            This will indicate how many Arnoldi vectors are generated   
+            at each iteration.  After the startup phase in which NEV   
+            Arnoldi vectors are generated, the algorithm generates   
+            approximately NCV-NEV Arnoldi vectors at each subsequent update   
+            iteration. Most of the cost in generating each Arnoldi vector is   
+            in the matrix-vector operation OP*x.   
+            NOTE: 2 <= NCV-NEV in order that complex conjugate pairs of Ritz   
+            values are kept together. (See remark 4 below)   
+
+    V       Double precision array N by NCV.  (OUTPUT)   
+            Contains the final set of Arnoldi basis vectors.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling program.   
+
+    IPARAM  Integer array of length 11.  (INPUT/OUTPUT)   
+            IPARAM(1) = ISHIFT: method for selecting the implicit shifts.   
+            The shifts selected at each iteration are used to restart   
+            the Arnoldi iteration in an implicit fashion.   
+            -------------------------------------------------------------   
+            ISHIFT = 0: the shifts are provided by the user via   
+                        reverse communication.  The real and imaginary   
+                        parts of the NCV eigenvalues of the Hessenberg   
+                        matrix H are returned in the part of the WORKL   
+                        array corresponding to RITZR and RITZI. See remark   
+                        5 below.   
+            ISHIFT = 1: exact shifts with respect to the current   
+                        Hessenberg matrix H.  This is equivalent to   
+                        restarting the iteration with a starting vector   
+                        that is a linear combination of approximate Schur   
+                        vectors associated with the "wanted" Ritz values.   
+            -------------------------------------------------------------   
+
+            IPARAM(2) = No longer referenced.   
+
+            IPARAM(3) = MXITER   
+            On INPUT:  maximum number of Arnoldi update iterations allowed.   
+            On OUTPUT: actual number of Arnoldi update iterations taken.   
+
+            IPARAM(4) = NB: blocksize to be used in the recurrence.   
+            The code currently works only for NB = 1.   
+
+            IPARAM(5) = NCONV: number of "converged" Ritz values.   
+            This represents the number of Ritz values that satisfy   
+            the convergence criterion.   
+
+            IPARAM(6) = IUPD   
+            No longer referenced. Implicit restarting is ALWAYS used.   
+
+            IPARAM(7) = MODE   
+            On INPUT determines what type of eigenproblem is being solved.   
+            Must be 1,2,3,4; See under \Description of dnaupd for the   
+            four modes available.   
+
+            IPARAM(8) = NP   
+            When ido = 3 and the user provides shifts through reverse   
+            communication (IPARAM(1)=0), dnaupd returns NP, the number   
+            of shifts the user is to provide. 0 < NP <=NCV-NEV. See Remark   
+            5 below.   
+
+            IPARAM(9) = NUMOP, IPARAM(10) = NUMOPB, IPARAM(11) = NUMREO,   
+            OUTPUT: NUMOP  = total number of OP*x operations,   
+                    NUMOPB = total number of B*x operations if BMAT='G',   
+                    NUMREO = total number of steps of re-orthogonalization.   
+
+    IPNTR   Integer array of length 14.  (OUTPUT)   
+            Pointer to mark the starting locations in the WORKD and WORKL   
+            arrays for matrices/vectors used by the Arnoldi iteration.   
+            -------------------------------------------------------------   
+            IPNTR(1): pointer to the current operand vector X in WORKD.   
+            IPNTR(2): pointer to the current result vector Y in WORKD.   
+            IPNTR(3): pointer to the vector B * X in WORKD when used in   
+                      the shift-and-invert mode.   
+            IPNTR(4): pointer to the next available location in WORKL   
+                      that is untouched by the program.   
+            IPNTR(5): pointer to the NCV by NCV upper Hessenberg matrix   
+                      H in WORKL.   
+            IPNTR(6): pointer to the real part of the ritz value array   
+                      RITZR in WORKL.   
+            IPNTR(7): pointer to the imaginary part of the ritz value array   
+                      RITZI in WORKL.   
+            IPNTR(8): pointer to the Ritz estimates in array WORKL associated   
+                      with the Ritz values located in RITZR and RITZI in WORKL.   
+
+            IPNTR(14): pointer to the NP shifts in WORKL. See Remark 5 below.   
+
+            Note: IPNTR(9:13) is only referenced by dneupd. See Remark 2 below.   
+
+            IPNTR(9):  pointer to the real part of the NCV RITZ values of the   
+                       original system.   
+            IPNTR(10): pointer to the imaginary part of the NCV RITZ values of   
+                       the original system.   
+            IPNTR(11): pointer to the NCV corresponding error bounds.   
+            IPNTR(12): pointer to the NCV by NCV upper quasi-triangular   
+                       Schur matrix for H.   
+            IPNTR(13): pointer to the NCV by NCV matrix of eigenvectors   
+                       of the upper Hessenberg matrix H. Only referenced by   
+                       dneupd if RVEC = .TRUE. See Remark 2 below.   
+            -------------------------------------------------------------   
+
+    WORKD   Double precision work array of length 3*N.  (REVERSE COMMUNICATION)   
+            Distributed array to be used in the basic Arnoldi iteration   
+            for reverse communication.  The user should not use WORKD   
+            as temporary workspace during the iteration. Upon termination   
+            WORKD(1:N) contains B*RESID(1:N). If an invariant subspace   
+            associated with the converged Ritz values is desired, see remark   
+            2 below, subroutine dneupd uses this output.   
+            See Data Distribution Note below.   
+
+    WORKL   Double precision work array of length LWORKL.  (OUTPUT/WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.  See Data Distribution Note below.   
+
+    LWORKL  Integer.  (INPUT)   
+            LWORKL must be at least 3*NCV**2 + 6*NCV.   
+
+    INFO    Integer.  (INPUT/OUTPUT)   
+            If INFO .EQ. 0, a randomly initial residual vector is used.   
+            If INFO .NE. 0, RESID contains the initial residual vector,   
+                            possibly from a previous run.   
+            Error flag on output.   
+            =  0: Normal exit.   
+            =  1: Maximum number of iterations taken.   
+                  All possible eigenvalues of OP has been found. IPARAM(5)   
+                  returns the number of wanted converged Ritz values.   
+            =  2: No longer an informational error. Deprecated starting   
+                  with release 2 of ARPACK.   
+            =  3: No shifts could be applied during a cycle of the   
+                  Implicitly restarted Arnoldi iteration. One possibility   
+                  is to increase the size of NCV relative to NEV.   
+                  See remark 4 below.   
+            = -1: N must be positive.   
+            = -2: NEV must be positive.   
+            = -3: NCV-NEV >= 2 and less than or equal to N.   
+            = -4: The maximum number of Arnoldi update iteration   
+                  must be greater than zero.   
+            = -5: WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI'   
+            = -6: BMAT must be one of 'I' or 'G'.   
+            = -7: Length of private work array is not sufficient.   
+            = -8: Error return from LAPACK eigenvalue calculation;   
+            = -9: Starting vector is zero.   
+            = -10: IPARAM(7) must be 1,2,3,4.   
+            = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatable.   
+            = -12: IPARAM(1) must be equal to 0 or 1.   
+            = -9999: Could not build an Arnoldi factorization.   
+                     IPARAM(5) returns the size of the current Arnoldi   
+                     factorization.   
+
+   \Remarks   
+    1. The computed Ritz values are approximate eigenvalues of OP. The   
+       selection of WHICH should be made with this in mind when   
+       Mode = 3 and 4.  After convergence, approximate eigenvalues of the   
+       original problem may be obtained with the ARPACK subroutine dneupd.   
+
+    2. If a basis for the invariant subspace corresponding to the converged Ritz   
+       values is needed, the user must call dneupd immediately following   
+       completion of dnaupd. This is new starting with release 2 of ARPACK.   
+
+    3. If M can be factored into a Cholesky factorization M = LL'   
+       then Mode = 2 should not be selected.  Instead one should use   
+       Mode = 1 with  OP = inv(L)*A*inv(L').  Appropriate triangular   
+       linear systems should be solved with L and L' rather   
+       than computing inverses.  After convergence, an approximate   
+       eigenvector z of the original problem is recovered by solving   
+       L'z = x  where x is a Ritz vector of OP.   
+
+    4. At present there is no a-priori analysis to guide the selection   
+       of NCV relative to NEV.  The only formal requrement is that NCV > NEV + 2.   
+       However, it is recommended that NCV .ge. 2*NEV+1.  If many problems of   
+       the same type are to be solved, one should experiment with increasing   
+       NCV while keeping NEV fixed for a given test problem.  This will   
+       usually decrease the required number of OP*x operations but it   
+       also increases the work and storage required to maintain the orthogonal   
+       basis vectors.  The optimal "cross-over" with respect to CPU time   
+       is problem dependent and must be determined empirically.   
+       See Chapter 8 of Reference 2 for further information.   
+
+    5. When IPARAM(1) = 0, and IDO = 3, the user needs to provide the   
+       NP = IPARAM(8) real and imaginary parts of the shifts in locations   
+           real part                  imaginary part   
+           -----------------------    --------------   
+       1   WORKL(IPNTR(14))           WORKL(IPNTR(14)+NP)   
+       2   WORKL(IPNTR(14)+1)         WORKL(IPNTR(14)+NP+1)   
+                          .                          .   
+                          .                          .   
+                          .                          .   
+       NP  WORKL(IPNTR(14)+NP-1)      WORKL(IPNTR(14)+2*NP-1).   
+
+       Only complex conjugate pairs of shifts may be applied and the pairs   
+       must be placed in consecutive locations. The real part of the   
+       eigenvalues of the current upper Hessenberg matrix are located in   
+       WORKL(IPNTR(6)) through WORKL(IPNTR(6)+NCV-1) and the imaginary part   
+       in WORKL(IPNTR(7)) through WORKL(IPNTR(7)+NCV-1). They are ordered   
+       according to the order defined by WHICH. The complex conjugate   
+       pairs are kept together and the associated Ritz estimates are located in   
+       WORKL(IPNTR(8)), WORKL(IPNTR(8)+1), ... , WORKL(IPNTR(8)+NCV-1).   
+
+   -----------------------------------------------------------------------   
+
+   \Data Distribution Note:   
+
+    Fortran-D syntax:   
+    ================   
+    Double precision resid(n), v(ldv,ncv), workd(3*n), workl(lworkl)   
+    decompose  d1(n), d2(n,ncv)   
+    align      resid(i) with d1(i)   
+    align      v(i,j)   with d2(i,j)   
+    align      workd(i) with d1(i)     range (1:n)   
+    align      workd(i) with d1(i-n)   range (n+1:2*n)   
+    align      workd(i) with d1(i-2*n) range (2*n+1:3*n)   
+    distribute d1(block), d2(block,:)   
+    replicated workl(lworkl)   
+
+    Cray MPP syntax:   
+    ===============   
+    Double precision  resid(n), v(ldv,ncv), workd(n,3), workl(lworkl)   
+    shared     resid(block), v(block,:), workd(block,:)   
+    replicated workl(lworkl)   
+
+    CM2/CM5 syntax:   
+    ==============   
+
+   -----------------------------------------------------------------------   
+
+       include   'ex-nonsym.doc'   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+    3. B.N. Parlett & Y. Saad, "Complex Shift and Invert Strategies for   
+       Real Matrices", Linear Algebra and its Applications, vol 88/89,   
+       pp 575-595, (1987).   
+
+   \Routines called:   
+       dnaup2  ARPACK routine that implements the Implicitly Restarted   
+               Arnoldi Iteration.   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlamch  LAPACK routine that determines machine constants.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/16/93: Version '1.1'   
+
+   \SCCS Information: @(#)   
+   FILE: naupd.F   SID: 2.5   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \Remarks   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdnaupd_(integer *ido, char *bmat, integer *n, char *
+	which, integer *nev, doublereal *tol, doublereal *resid, integer *ncv,
+	 doublereal *v, integer *ldv, integer *iparam, integer *ipntr, 
+	doublereal *workd, doublereal *workl, integer *lworkl, integer *info)
+{
+    /* Format strings */
+    static char fmt_1000[] = "(//,5x,\002==================================="
+	    "==========\002,/5x,\002= Nonsymmetric implicit Arnoldi update co"
+	    "de =\002,/5x,\002= Version Number: \002,\002 2.4\002,21x,\002 "
+	    "=\002,/5x,\002= Version Date:   \002,\002 07/31/96\002,16x,\002 ="
+	    "\002,/5x,\002=============================================\002,/"
+	    "5x,\002= Summary of timing statistics              =\002,/5x,"
+	    "\002=============================================\002,//)";
+    static char fmt_1100[] = "(5x,\002Total number update iterations        "
+	    "     = \002,i5,/5x,\002Total number of OP*x operations          "
+	    "  = \002,i5,/5x,\002Total number of B*x operations             = "
+	    "\002,i5,/5x,\002Total number of reorthogonalization steps  = "
+	    "\002,i5,/5x,\002Total number of iterative refinement steps = "
+	    "\002,i5,/5x,\002Total number of restart steps              = "
+	    "\002,i5,/5x,\002Total time in user OP*x operation          = "
+	    "\002,f12.6,/5x,\002Total time in user B*x operation           ="
+	    " \002,f12.6,/5x,\002Total time in Arnoldi update routine       = "
+	    "\002,f12.6,/5x,\002Total time in naup2 routine                ="
+	    " \002,f12.6,/5x,\002Total time in basic Arnoldi iteration loop = "
+	    "\002,f12.6,/5x,\002Total time in reorthogonalization phase    ="
+	    " \002,f12.6,/5x,\002Total time in (re)start vector generation  = "
+	    "\002,f12.6,/5x,\002Total time in Hessenberg eig. subproblem   ="
+	    " \002,f12.6,/5x,\002Total time in getting the shifts           = "
+	    "\002,f12.6,/5x,\002Total time in applying the shifts          ="
+	    " \002,f12.6,/5x,\002Total time in convergence testing          = "
+	    "\002,f12.6,/5x,\002Total time in computing final Ritz vectors ="
+	    " \002,f12.6/)";
+
+    /* System generated locals */
+    integer v_dim1, v_offset, i__1, i__2;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen), s_wsfe(cilist *), e_wsfe(
+	    void), do_fio(integer *, char *, ftnlen);
+
+    /* Local variables */
+    integer j;
+    real t0, t1;
+    IGRAPH_F77_SAVE integer nb, ih, iq, np, iw, ldh, ldq;
+    integer nbx;
+    IGRAPH_F77_SAVE integer nev0, mode;
+    integer ierr;
+    IGRAPH_F77_SAVE integer iupd, next;
+    integer nopx;
+    IGRAPH_F77_SAVE integer levec;
+    real trvec, tmvbx;
+    IGRAPH_F77_SAVE integer ritzi;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen);
+    IGRAPH_F77_SAVE integer ritzr;
+    extern /* Subroutine */ int igraphdnaup2_(integer *, char *, integer *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, doublereal *,
+	     doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    real tnaup2, tgetv0;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphsecond_(real *);
+    integer logfil=0, ndigit;
+    real tneigh;
+    integer mnaupd=0;
+    IGRAPH_F77_SAVE integer ishift;
+    integer nitref;
+    IGRAPH_F77_SAVE integer bounds;
+    real tnaupd;
+    extern /* Subroutine */ int igraphdstatn_(void);
+    real titref, tnaitr;
+    IGRAPH_F77_SAVE integer msglvl;
+    real tngets, tnapps, tnconv;
+    IGRAPH_F77_SAVE integer mxiter;
+    integer nrorth, nrstrt;
+    real tmvopx;
+
+    /* Fortran I/O blocks */
+    static cilist io___30 = { 0, 6, 0, fmt_1000, 0 };
+    static cilist io___31 = { 0, 6, 0, fmt_1100, 0 };
+
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    --iparam;
+    --ipntr;
+    --workl;
+
+    /* Function Body */
+    if (*ido == 0) {
+
+/*        %-------------------------------%   
+          | Initialize timing statistics  |   
+          | & message level for debugging |   
+          %-------------------------------% */
+
+	igraphdstatn_();
+	igraphsecond_(&t0);
+	msglvl = mnaupd;
+
+/*        %----------------%   
+          | Error checking |   
+          %----------------% */
+
+	ierr = 0;
+	ishift = iparam[1];
+	levec = iparam[2];
+	mxiter = iparam[3];
+	nb = iparam[4];
+
+/*        %--------------------------------------------%   
+          | Revision 2 performs only implicit restart. |   
+          %--------------------------------------------% */
+
+	iupd = 1;
+	mode = iparam[7];
+
+	if (*n <= 0) {
+	    ierr = -1;
+	} else if (*nev <= 0) {
+	    ierr = -2;
+	} else if (*ncv <= *nev + 1 || *ncv > *n) {
+	    ierr = -3;
+	} else if (mxiter <= 0) {
+	    ierr = -4;
+	} else if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(
+		which, "SM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "LR", 
+		(ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "SR", (ftnlen)2, (
+		ftnlen)2) != 0 && s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) != 
+		0 && s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) != 0) {
+	    ierr = -5;
+	} else if (*(unsigned char *)bmat != 'I' && *(unsigned char *)bmat != 
+		'G') {
+	    ierr = -6;
+	} else /* if(complicated condition) */ {
+/* Computing 2nd power */
+	    i__1 = *ncv;
+	    if (*lworkl < i__1 * i__1 * 3 + *ncv * 6) {
+		ierr = -7;
+	    } else if (mode < 1 || mode > 5) {
+		ierr = -10;
+	    } else if (mode == 1 && *(unsigned char *)bmat == 'G') {
+		ierr = -11;
+	    } else if (ishift < 0 || ishift > 1) {
+		ierr = -12;
+	    }
+	}
+
+/*        %------------%   
+          | Error Exit |   
+          %------------% */
+
+	if (ierr != 0) {
+	    *info = ierr;
+	    *ido = 99;
+	    goto L9000;
+	}
+
+/*        %------------------------%   
+          | Set default parameters |   
+          %------------------------% */
+
+	if (nb <= 0) {
+	    nb = 1;
+	}
+	if (*tol <= 0.) {
+	    *tol = igraphdlamch_("EpsMach");
+	}
+
+/*        %----------------------------------------------%   
+          | NP is the number of additional steps to      |   
+          | extend the length NEV Lanczos factorization. |   
+          | NEV0 is the local variable designating the   |   
+          | size of the invariant subspace desired.      |   
+          %----------------------------------------------% */
+
+	np = *ncv - *nev;
+	nev0 = *nev;
+
+/*        %-----------------------------%   
+          | Zero out internal workspace |   
+          %-----------------------------%   
+
+   Computing 2nd power */
+	i__2 = *ncv;
+	i__1 = i__2 * i__2 * 3 + *ncv * 6;
+	for (j = 1; j <= i__1; ++j) {
+	    workl[j] = 0.;
+/* L10: */
+	}
+
+/*        %-------------------------------------------------------------%   
+          | Pointer into WORKL for address of H, RITZ, BOUNDS, Q        |   
+          | etc... and the remaining workspace.                         |   
+          | Also update pointer to be used on output.                   |   
+          | Memory is laid out as follows:                              |   
+          | workl(1:ncv*ncv) := generated Hessenberg matrix             |   
+          | workl(ncv*ncv+1:ncv*ncv+2*ncv) := real and imaginary        |   
+          |                                   parts of ritz values      |   
+          | workl(ncv*ncv+2*ncv+1:ncv*ncv+3*ncv) := error bounds        |   
+          | workl(ncv*ncv+3*ncv+1:2*ncv*ncv+3*ncv) := rotation matrix Q |   
+          | workl(2*ncv*ncv+3*ncv+1:3*ncv*ncv+6*ncv) := workspace       |   
+          | The final workspace is needed by subroutine dneigh called   |   
+          | by dnaup2. Subroutine dneigh calls LAPACK routines for      |   
+          | calculating eigenvalues and the last row of the eigenvector |   
+          | matrix.                                                     |   
+          %-------------------------------------------------------------% */
+
+	ldh = *ncv;
+	ldq = *ncv;
+	ih = 1;
+	ritzr = ih + ldh * *ncv;
+	ritzi = ritzr + *ncv;
+	bounds = ritzi + *ncv;
+	iq = bounds + *ncv;
+	iw = iq + ldq * *ncv;
+/* Computing 2nd power */
+	i__1 = *ncv;
+	next = iw + i__1 * i__1 + *ncv * 3;
+
+	ipntr[4] = next;
+	ipntr[5] = ih;
+	ipntr[6] = ritzr;
+	ipntr[7] = ritzi;
+	ipntr[8] = bounds;
+	ipntr[14] = iw;
+
+    }
+
+/*     %-------------------------------------------------------%   
+       | Carry out the Implicitly restarted Arnoldi Iteration. |   
+       %-------------------------------------------------------% */
+
+    igraphdnaup2_(ido, bmat, n, which, &nev0, &np, tol, &resid[1], &mode, &iupd, &
+	    ishift, &mxiter, &v[v_offset], ldv, &workl[ih], &ldh, &workl[
+	    ritzr], &workl[ritzi], &workl[bounds], &workl[iq], &ldq, &workl[
+	    iw], &ipntr[1], &workd[1], info);
+
+/*     %--------------------------------------------------%   
+       | ido .ne. 99 implies use of reverse communication |   
+       | to compute operations involving OP or shifts.    |   
+       %--------------------------------------------------% */
+
+    if (*ido == 3) {
+	iparam[8] = np;
+    }
+    if (*ido != 99) {
+	goto L9000;
+    }
+
+    iparam[3] = mxiter;
+    iparam[5] = np;
+    iparam[9] = nopx;
+    iparam[10] = nbx;
+    iparam[11] = nrorth;
+
+/*     %------------------------------------%   
+       | Exit if there was an informational |   
+       | error within dnaup2.               |   
+       %------------------------------------% */
+
+    if (*info < 0) {
+	goto L9000;
+    }
+    if (*info == 2) {
+	*info = 3;
+    }
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &mxiter, &ndigit, "_naupd: Number of update i"
+		"terations taken", (ftnlen)41);
+	igraphivout_(&logfil, &c__1, &np, &ndigit, "_naupd: Number of wanted \"con"
+		"verged\" Ritz values", (ftnlen)48);
+	igraphdvout_(&logfil, &np, &workl[ritzr], &ndigit, "_naupd: Real part of t"
+		"he final Ritz values", (ftnlen)42);
+	igraphdvout_(&logfil, &np, &workl[ritzi], &ndigit, "_naupd: Imaginary part"
+		" of the final Ritz values", (ftnlen)47);
+	igraphdvout_(&logfil, &np, &workl[bounds], &ndigit, "_naupd: Associated Ri"
+		"tz estimates", (ftnlen)33);
+    }
+
+    igraphsecond_(&t1);
+    tnaupd = t1 - t0;
+
+    if (msglvl > 0) {
+
+/*        %--------------------------------------------------------%   
+          | Version Number & Version Date are defined in version.h |   
+          %--------------------------------------------------------% */
+
+	s_wsfe(&io___30);
+	e_wsfe();
+	s_wsfe(&io___31);
+	do_fio(&c__1, (char *)&mxiter, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nopx, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nbx, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nrorth, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nitref, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nrstrt, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&tmvopx, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tmvbx, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tnaupd, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tnaup2, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tnaitr, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&titref, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tgetv0, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tneigh, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tngets, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tnapps, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tnconv, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&trvec, (ftnlen)sizeof(real));
+	e_wsfe();
+    }
+
+L9000:
+
+    return 0;
+
+/*     %---------------%   
+       | End of dnaupd |   
+       %---------------% */
+
+} /* igraphdnaupd_ */
+
diff --git a/src/lapack/dnconv.c b/src/lapack/dnconv.c
new file mode 100644
index 0000000..bba560f
--- /dev/null
+++ b/src/lapack/dnconv.c
@@ -0,0 +1,178 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b3 = .66666666666666663;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dnconv   
+
+   \Description:   
+    Convergence testing for the nonsymmetric Arnoldi eigenvalue routine.   
+
+   \Usage:   
+    call dnconv   
+       ( N, RITZR, RITZI, BOUNDS, TOL, NCONV )   
+
+   \Arguments   
+    N       Integer.  (INPUT)   
+            Number of Ritz values to check for convergence.   
+
+    RITZR,  Double precision arrays of length N.  (INPUT)   
+    RITZI   Real and imaginary parts of the Ritz values to be checked   
+            for convergence.   
+    BOUNDS  Double precision array of length N.  (INPUT)   
+            Ritz estimates for the Ritz values in RITZR and RITZI.   
+
+    TOL     Double precision scalar.  (INPUT)   
+            Desired backward error for a Ritz value to be considered   
+            "converged".   
+
+    NCONV   Integer scalar.  (OUTPUT)   
+            Number of "converged" Ritz values.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       second  ARPACK utility routine for timing.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlapy2  LAPACK routine to compute sqrt(x**2+y**2) carefully.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: nconv.F   SID: 2.3   DATE OF SID: 4/20/96   RELEASE: 2   
+
+   \Remarks   
+       1. xxxx   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdnconv_(integer *n, doublereal *ritzr, doublereal *ritzi,
+	 doublereal *bounds, doublereal *tol, integer *nconv)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double pow_dd(doublereal *, doublereal *);
+
+    /* Local variables */
+    integer i__;
+    real t0, t1;
+    doublereal eps23, temp;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *), igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphsecond_(real *);
+    real tnconv;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       %-------------------------------------------------------------%   
+       | Convergence test: unlike in the symmetric code, I am not    |   
+       | using things like refined error bounds and gap condition    |   
+       | because I don't know the exact equivalent concept.          |   
+       |                                                             |   
+       | Instead the i-th Ritz value is considered "converged" when: |   
+       |                                                             |   
+       |     bounds(i) .le. ( TOL * | ritz | )                       |   
+       |                                                             |   
+       | for some appropriate choice of norm.                        |   
+       %-------------------------------------------------------------%   
+
+       Parameter adjustments */
+    --bounds;
+    --ritzi;
+    --ritzr;
+
+    /* Function Body */
+    igraphsecond_(&t0);
+
+/*     %---------------------------------%   
+       | Get machine dependent constant. |   
+       %---------------------------------% */
+
+    eps23 = igraphdlamch_("Epsilon-Machine");
+    eps23 = pow_dd(&eps23, &c_b3);
+
+    *nconv = 0;
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+/* Computing MAX */
+	d__1 = eps23, d__2 = igraphdlapy2_(&ritzr[i__], &ritzi[i__]);
+	temp = max(d__1,d__2);
+	if (bounds[i__] <= *tol * temp) {
+	    ++(*nconv);
+	}
+/* L20: */
+    }
+
+    igraphsecond_(&t1);
+    tnconv += t1 - t0;
+
+    return 0;
+
+/*     %---------------%   
+       | End of dnconv |   
+       %---------------% */
+
+} /* igraphdnconv_ */
+
diff --git a/src/lapack/dneigh.c b/src/lapack/dneigh.c
new file mode 100644
index 0000000..4f8acc1
--- /dev/null
+++ b/src/lapack/dneigh.c
@@ -0,0 +1,377 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static logical c_true = TRUE_;
+static integer c__1 = 1;
+static doublereal c_b18 = 1.;
+static doublereal c_b20 = 0.;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dneigh   
+
+   \Description:   
+    Compute the eigenvalues of the current upper Hessenberg matrix   
+    and the corresponding Ritz estimates given the current residual norm.   
+
+   \Usage:   
+    call dneigh   
+       ( RNORM, N, H, LDH, RITZR, RITZI, BOUNDS, Q, LDQ, WORKL, IERR )   
+
+   \Arguments   
+    RNORM   Double precision scalar.  (INPUT)   
+            Residual norm corresponding to the current upper Hessenberg   
+            matrix H.   
+
+    N       Integer.  (INPUT)   
+            Size of the matrix H.   
+
+    H       Double precision N by N array.  (INPUT)   
+            H contains the current upper Hessenberg matrix.   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    RITZR,  Double precision arrays of length N.  (OUTPUT)   
+    RITZI   On output, RITZR(1:N) (resp. RITZI(1:N)) contains the real   
+            (respectively imaginary) parts of the eigenvalues of H.   
+
+    BOUNDS  Double precision array of length N.  (OUTPUT)   
+            On output, BOUNDS contains the Ritz estimates associated with   
+            the eigenvalues RITZR and RITZI.  This is equal to RNORM   
+            times the last components of the eigenvectors corresponding   
+            to the eigenvalues in RITZR and RITZI.   
+
+    Q       Double precision N by N array.  (WORKSPACE)   
+            Workspace needed to store the eigenvectors of H.   
+
+    LDQ     Integer.  (INPUT)   
+            Leading dimension of Q exactly as declared in the calling   
+            program.   
+
+    WORKL   Double precision work array of length N**2 + 3*N.  (WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.  This is needed to keep the full Schur form   
+            of H and also in the calculation of the eigenvectors of H.   
+
+    IERR    Integer.  (OUTPUT)   
+            Error exit flag from dlaqrb or dtrevc.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       dlaqrb  ARPACK routine to compute the real Schur form of an   
+               upper Hessenberg matrix and last row of the Schur vectors.   
+       second  ARPACK utility routine for timing.   
+       dmout   ARPACK utility routine that prints matrices   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlacpy  LAPACK matrix copy routine.   
+       dlapy2  LAPACK routine to compute sqrt(x**2+y**2) carefully.   
+       dtrevc  LAPACK routine to compute the eigenvectors of a matrix   
+               in upper quasi-triangular form   
+       dgemv   Level 2 BLAS routine for matrix vector multiplication.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+       dscal   Level 1 BLAS that scales a vector.   
+
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: neigh.F   SID: 2.3   DATE OF SID: 4/20/96   RELEASE: 2   
+
+   \Remarks   
+       None   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdneigh_(doublereal *rnorm, integer *n, doublereal *h__, 
+	integer *ldh, doublereal *ritzr, doublereal *ritzi, doublereal *
+	bounds, doublereal *q, integer *ldq, doublereal *workl, integer *ierr)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, q_dim1, q_offset, i__1;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    integer i__;
+    real t0, t1;
+    doublereal vl[1], temp;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    integer iconj;
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *), igraphdmout_(integer *, 
+	    integer *, integer *, doublereal *, integer *, integer *, char *, 
+	    ftnlen), igraphdvout_(integer *, integer *, doublereal *, integer *, 
+	    char *, ftnlen);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlaqrb_(logical *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *);
+    integer mneigh=0;
+    extern /* Subroutine */ int igraphsecond_(real *), igraphdlacpy_(char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *);
+    integer logfil=0, ndigit;
+    logical select[1];
+    real tneigh;
+    extern /* Subroutine */ int igraphdtrevc_(char *, char *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, integer *, integer *, doublereal *, integer *);
+    integer msglvl;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %------------------------%   
+       | Local Scalars & Arrays |   
+       %------------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+
+       %-------------------------------%   
+       | Initialize timing statistics  |   
+       | & message level for debugging |   
+       %-------------------------------%   
+
+       Parameter adjustments */
+    --workl;
+    --bounds;
+    --ritzi;
+    --ritzr;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+
+    /* Function Body */
+    igraphsecond_(&t0);
+    msglvl = mneigh;
+
+    if (msglvl > 2) {
+	igraphdmout_(&logfil, n, n, &h__[h_offset], ldh, &ndigit, "_neigh: Enterin"
+		"g upper Hessenberg matrix H ", (ftnlen)43);
+    }
+
+/*     %-----------------------------------------------------------%   
+       | 1. Compute the eigenvalues, the last components of the    |   
+       |    corresponding Schur vectors and the full Schur form T  |   
+       |    of the current upper Hessenberg matrix H.              |   
+       | dlaqrb returns the full Schur form of H in WORKL(1:N**2)  |   
+       | and the last components of the Schur vectors in BOUNDS.   |   
+       %-----------------------------------------------------------% */
+
+    igraphdlacpy_("All", n, n, &h__[h_offset], ldh, &workl[1], n);
+    igraphdlaqrb_(&c_true, n, &c__1, n, &workl[1], n, &ritzr[1], &ritzi[1], &bounds[
+	    1], ierr);
+    if (*ierr != 0) {
+	goto L9000;
+    }
+
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, n, &bounds[1], &ndigit, "_neigh: last row of the Sch"
+		"ur matrix for H", (ftnlen)42);
+    }
+
+/*     %-----------------------------------------------------------%   
+       | 2. Compute the eigenvectors of the full Schur form T and  |   
+       |    apply the last components of the Schur vectors to get  |   
+       |    the last components of the corresponding eigenvectors. |   
+       | Remember that if the i-th and (i+1)-st eigenvalues are    |   
+       | complex conjugate pairs, then the real & imaginary part   |   
+       | of the eigenvector components are split across adjacent   |   
+       | columns of Q.                                             |   
+       %-----------------------------------------------------------% */
+
+    igraphdtrevc_("R", "A", select, n, &workl[1], n, vl, n, &q[q_offset], ldq, n, n,
+	     &workl[*n * *n + 1], ierr);
+
+    if (*ierr != 0) {
+	goto L9000;
+    }
+
+/*     %------------------------------------------------%   
+       | Scale the returning eigenvectors so that their |   
+       | euclidean norms are all one. LAPACK subroutine |   
+       | dtrevc returns each eigenvector normalized so  |   
+       | that the element of largest magnitude has      |   
+       | magnitude 1; here the magnitude of a complex   |   
+       | number (x,y) is taken to be |x| + |y|.         |   
+       %------------------------------------------------% */
+
+    iconj = 0;
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	if ((d__1 = ritzi[i__], abs(d__1)) <= 0.) {
+
+/*           %----------------------%   
+             | Real eigenvalue case |   
+             %----------------------% */
+
+	    temp = igraphdnrm2_(n, &q[i__ * q_dim1 + 1], &c__1);
+	    d__1 = 1. / temp;
+	    igraphdscal_(n, &d__1, &q[i__ * q_dim1 + 1], &c__1);
+	} else {
+
+/*           %-------------------------------------------%   
+             | Complex conjugate pair case. Note that    |   
+             | since the real and imaginary part of      |   
+             | the eigenvector are stored in consecutive |   
+             | columns, we further normalize by the      |   
+             | square root of two.                       |   
+             %-------------------------------------------% */
+
+	    if (iconj == 0) {
+		d__1 = igraphdnrm2_(n, &q[i__ * q_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &q[(i__ + 1) * q_dim1 + 1], &c__1);
+		temp = igraphdlapy2_(&d__1, &d__2);
+		d__1 = 1. / temp;
+		igraphdscal_(n, &d__1, &q[i__ * q_dim1 + 1], &c__1);
+		d__1 = 1. / temp;
+		igraphdscal_(n, &d__1, &q[(i__ + 1) * q_dim1 + 1], &c__1);
+		iconj = 1;
+	    } else {
+		iconj = 0;
+	    }
+	}
+/* L10: */
+    }
+
+    igraphdgemv_("T", n, n, &c_b18, &q[q_offset], ldq, &bounds[1], &c__1, &c_b20, &
+	    workl[1], &c__1);
+
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, n, &workl[1], &ndigit, "_neigh: Last row of the eige"
+		"nvector matrix for H", (ftnlen)48);
+    }
+
+/*     %----------------------------%   
+       | Compute the Ritz estimates |   
+       %----------------------------% */
+
+    iconj = 0;
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	if ((d__1 = ritzi[i__], abs(d__1)) <= 0.) {
+
+/*           %----------------------%   
+             | Real eigenvalue case |   
+             %----------------------% */
+
+	    bounds[i__] = *rnorm * (d__1 = workl[i__], abs(d__1));
+	} else {
+
+/*           %-------------------------------------------%   
+             | Complex conjugate pair case. Note that    |   
+             | since the real and imaginary part of      |   
+             | the eigenvector are stored in consecutive |   
+             | columns, we need to take the magnitude    |   
+             | of the last components of the two vectors |   
+             %-------------------------------------------% */
+
+	    if (iconj == 0) {
+		bounds[i__] = *rnorm * igraphdlapy2_(&workl[i__], &workl[i__ + 1]);
+		bounds[i__ + 1] = bounds[i__];
+		iconj = 1;
+	    } else {
+		iconj = 0;
+	    }
+	}
+/* L20: */
+    }
+
+    if (msglvl > 2) {
+	igraphdvout_(&logfil, n, &ritzr[1], &ndigit, "_neigh: Real part of the eig"
+		"envalues of H", (ftnlen)41);
+	igraphdvout_(&logfil, n, &ritzi[1], &ndigit, "_neigh: Imaginary part of th"
+		"e eigenvalues of H", (ftnlen)46);
+	igraphdvout_(&logfil, n, &bounds[1], &ndigit, "_neigh: Ritz estimates for "
+		"the eigenvalues of H", (ftnlen)47);
+    }
+
+    igraphsecond_(&t1);
+    tneigh += t1 - t0;
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dneigh |   
+       %---------------% */
+
+} /* igraphdneigh_ */
+
diff --git a/src/lapack/dneupd.c b/src/lapack/dneupd.c
new file mode 100644
index 0000000..01f0b1b
--- /dev/null
+++ b/src/lapack/dneupd.c
@@ -0,0 +1,1195 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b3 = .66666666666666663;
+static integer c__1 = 1;
+static doublereal c_b44 = 0.;
+static doublereal c_b45 = 1.;
+static logical c_true = TRUE_;
+static doublereal c_b71 = -1.;
+
+/* \BeginDoc   
+
+   \Name: dneupd   
+
+   \Description:   
+
+    This subroutine returns the converged approximations to eigenvalues   
+    of A*z = lambda*B*z and (optionally):   
+
+        (1) The corresponding approximate eigenvectors;   
+
+        (2) An orthonormal basis for the associated approximate   
+            invariant subspace;   
+
+        (3) Both.   
+
+    There is negligible additional cost to obtain eigenvectors.  An orthonormal   
+    basis is always computed.  There is an additional storage cost of n*nev   
+    if both are requested (in this case a separate array Z must be supplied).   
+
+    The approximate eigenvalues and eigenvectors of  A*z = lambda*B*z   
+    are derived from approximate eigenvalues and eigenvectors of   
+    of the linear operator OP prescribed by the MODE selection in the   
+    call to DNAUPD.  DNAUPD must be called before this routine is called.   
+    These approximate eigenvalues and vectors are commonly called Ritz   
+    values and Ritz vectors respectively.  They are referred to as such   
+    in the comments that follow.  The computed orthonormal basis for the   
+    invariant subspace corresponding to these Ritz values is referred to as a   
+    Schur basis.   
+
+    See documentation in the header of the subroutine DNAUPD for   
+    definition of OP as well as other terms and the relation of computed   
+    Ritz values and Ritz vectors of OP with respect to the given problem   
+    A*z = lambda*B*z.  For a brief description, see definitions of   
+    IPARAM(7), MODE and WHICH in the documentation of DNAUPD.   
+
+   \Usage:   
+    call dneupd   
+       ( RVEC, HOWMNY, SELECT, DR, DI, Z, LDZ, SIGMAR, SIGMAI, WORKEV, BMAT,   
+         N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR, WORKD, WORKL,   
+         LWORKL, INFO )   
+
+   \Arguments:   
+    RVEC    LOGICAL  (INPUT)   
+            Specifies whether a basis for the invariant subspace corresponding   
+            to the converged Ritz value approximations for the eigenproblem   
+            A*z = lambda*B*z is computed.   
+
+               RVEC = .FALSE.     Compute Ritz values only.   
+
+               RVEC = .TRUE.      Compute the Ritz vectors or Schur vectors.   
+                                  See Remarks below.   
+
+    HOWMNY  Character*1  (INPUT)   
+            Specifies the form of the basis for the invariant subspace   
+            corresponding to the converged Ritz values that is to be computed.   
+
+            = 'A': Compute NEV Ritz vectors;   
+            = 'P': Compute NEV Schur vectors;   
+            = 'S': compute some of the Ritz vectors, specified   
+                   by the logical array SELECT.   
+
+    SELECT  Logical array of dimension NCV.  (INPUT)   
+            If HOWMNY = 'S', SELECT specifies the Ritz vectors to be   
+            computed. To select the Ritz vector corresponding to a   
+            Ritz value (DR(j), DI(j)), SELECT(j) must be set to .TRUE..   
+            If HOWMNY = 'A' or 'P', SELECT is used as internal workspace.   
+
+    DR      Double precision array of dimension NEV+1.  (OUTPUT)   
+            If IPARAM(7) = 1,2 or 3 and SIGMAI=0.0  then on exit: DR contains   
+            the real part of the Ritz  approximations to the eigenvalues of   
+            A*z = lambda*B*z.   
+            If IPARAM(7) = 3, 4 and SIGMAI is not equal to zero, then on exit:   
+            DR contains the real part of the Ritz values of OP computed by   
+            DNAUPD. A further computation must be performed by the user   
+            to transform the Ritz values computed for OP by DNAUPD to those   
+            of the original system A*z = lambda*B*z. See remark 3 below.   
+
+    DI      Double precision array of dimension NEV+1.  (OUTPUT)   
+            On exit, DI contains the imaginary part of the Ritz value   
+            approximations to the eigenvalues of A*z = lambda*B*z associated   
+            with DR.   
+
+            NOTE: When Ritz values are complex, they will come in complex   
+                  conjugate pairs.  If eigenvectors are requested, the   
+                  corresponding Ritz vectors will also come in conjugate   
+                  pairs and the real and imaginary parts of these are   
+                  represented in two consecutive columns of the array Z   
+                  (see below).   
+
+    Z       Double precision N by NEV+1 array if RVEC = .TRUE. and HOWMNY = 'A'. (OUTPUT)   
+            On exit, if RVEC = .TRUE. and HOWMNY = 'A', then the columns of   
+            Z represent approximate eigenvectors (Ritz vectors) corresponding   
+            to the NCONV=IPARAM(5) Ritz values for eigensystem   
+            A*z = lambda*B*z.   
+
+            The complex Ritz vector associated with the Ritz value   
+            with positive imaginary part is stored in two consecutive   
+            columns.  The first column holds the real part of the Ritz   
+            vector and the second column holds the imaginary part.  The   
+            Ritz vector associated with the Ritz value with negative   
+            imaginary part is simply the complex conjugate of the Ritz vector   
+            associated with the positive imaginary part.   
+
+            If  RVEC = .FALSE. or HOWMNY = 'P', then Z is not referenced.   
+
+            NOTE: If if RVEC = .TRUE. and a Schur basis is not required,   
+            the array Z may be set equal to first NEV+1 columns of the Arnoldi   
+            basis array V computed by DNAUPD.  In this case the Arnoldi basis   
+            will be destroyed and overwritten with the eigenvector basis.   
+
+    LDZ     Integer.  (INPUT)   
+            The leading dimension of the array Z.  If Ritz vectors are   
+            desired, then  LDZ >= max( 1, N ).  In any case,  LDZ >= 1.   
+
+    SIGMAR  Double precision  (INPUT)   
+            If IPARAM(7) = 3 or 4, represents the real part of the shift.   
+            Not referenced if IPARAM(7) = 1 or 2.   
+
+    SIGMAI  Double precision  (INPUT)   
+            If IPARAM(7) = 3 or 4, represents the imaginary part of the shift.   
+            Not referenced if IPARAM(7) = 1 or 2. See remark 3 below.   
+
+    WORKEV  Double precision work array of dimension 3*NCV.  (WORKSPACE)   
+
+    **** The remaining arguments MUST be the same as for the   ****   
+    **** call to DNAUPD that was just completed.               ****   
+
+    NOTE: The remaining arguments   
+
+             BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR,   
+             WORKD, WORKL, LWORKL, INFO   
+
+           must be passed directly to DNEUPD following the last call   
+           to DNAUPD.  These arguments MUST NOT BE MODIFIED between   
+           the the last call to DNAUPD and the call to DNEUPD.   
+
+    Three of these parameters (V, WORKL, INFO) are also output parameters:   
+
+    V       Double precision N by NCV array.  (INPUT/OUTPUT)   
+
+            Upon INPUT: the NCV columns of V contain the Arnoldi basis   
+                        vectors for OP as constructed by DNAUPD .   
+
+            Upon OUTPUT: If RVEC = .TRUE. the first NCONV=IPARAM(5) columns   
+                         contain approximate Schur vectors that span the   
+                         desired invariant subspace.  See Remark 2 below.   
+
+            NOTE: If the array Z has been set equal to first NEV+1 columns   
+            of the array V and RVEC=.TRUE. and HOWMNY= 'A', then the   
+            Arnoldi basis held by V has been overwritten by the desired   
+            Ritz vectors.  If a separate array Z has been passed then   
+            the first NCONV=IPARAM(5) columns of V will contain approximate   
+            Schur vectors that span the desired invariant subspace.   
+
+    WORKL   Double precision work array of length LWORKL.  (OUTPUT/WORKSPACE)   
+            WORKL(1:ncv*ncv+3*ncv) contains information obtained in   
+            dnaupd.  They are not changed by dneupd.   
+            WORKL(ncv*ncv+3*ncv+1:3*ncv*ncv+6*ncv) holds the   
+            real and imaginary part of the untransformed Ritz values,   
+            the upper quasi-triangular matrix for H, and the   
+            associated matrix representation of the invariant subspace for H.   
+
+            Note: IPNTR(9:13) contains the pointer into WORKL for addresses   
+            of the above information computed by dneupd.   
+            -------------------------------------------------------------   
+            IPNTR(9):  pointer to the real part of the NCV RITZ values of the   
+                       original system.   
+            IPNTR(10): pointer to the imaginary part of the NCV RITZ values of   
+                       the original system.   
+            IPNTR(11): pointer to the NCV corresponding error bounds.   
+            IPNTR(12): pointer to the NCV by NCV upper quasi-triangular   
+                       Schur matrix for H.   
+            IPNTR(13): pointer to the NCV by NCV matrix of eigenvectors   
+                       of the upper Hessenberg matrix H. Only referenced by   
+                       dneupd if RVEC = .TRUE. See Remark 2 below.   
+            -------------------------------------------------------------   
+
+    INFO    Integer.  (OUTPUT)   
+            Error flag on output.   
+
+            =  0: Normal exit.   
+
+            =  1: The Schur form computed by LAPACK routine dlahqr   
+                  could not be reordered by LAPACK routine dtrsen.   
+                  Re-enter subroutine dneupd with IPARAM(5)=NCV and   
+                  increase the size of the arrays DR and DI to have   
+                  dimension at least dimension NCV and allocate at least NCV   
+                  columns for Z. NOTE: Not necessary if Z and V share   
+                  the same space. Please notify the authors if this error   
+                  occurs.   
+
+            = -1: N must be positive.   
+            = -2: NEV must be positive.   
+            = -3: NCV-NEV >= 2 and less than or equal to N.   
+            = -5: WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI'   
+            = -6: BMAT must be one of 'I' or 'G'.   
+            = -7: Length of private work WORKL array is not sufficient.   
+            = -8: Error return from calculation of a real Schur form.   
+                  Informational error from LAPACK routine dlahqr.   
+            = -9: Error return from calculation of eigenvectors.   
+                  Informational error from LAPACK routine dtrevc.   
+            = -10: IPARAM(7) must be 1,2,3,4.   
+            = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatible.   
+            = -12: HOWMNY = 'S' not yet implemented   
+            = -13: HOWMNY must be one of 'A' or 'P' if RVEC = .true.   
+            = -14: DNAUPD did not find any eigenvalues to sufficient   
+                   accuracy.   
+
+   \BeginLib   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+    3. B.N. Parlett & Y. Saad, "Complex Shift and Invert Strategies for   
+       Real Matrices", Linear Algebra and its Applications, vol 88/89,   
+       pp 575-595, (1987).   
+
+   \Routines called:   
+       ivout   ARPACK utility routine that prints integers.   
+       dmout   ARPACK utility routine that prints matrices   
+       dvout   ARPACK utility routine that prints vectors.   
+       dgeqr2  LAPACK routine that computes the QR factorization of   
+               a matrix.   
+       dlacpy  LAPACK matrix copy routine.   
+       dlahqr  LAPACK routine to compute the real Schur form of an   
+               upper Hessenberg matrix.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlapy2  LAPACK routine to compute sqrt(x**2+y**2) carefully.   
+       dlaset  LAPACK matrix initialization routine.   
+       dorm2r  LAPACK routine that applies an orthogonal matrix in   
+               factored form.   
+       dtrevc  LAPACK routine to compute the eigenvectors of a matrix   
+               in upper quasi-triangular form.   
+       dtrsen  LAPACK routine that re-orders the Schur form.   
+       dtrmm   Level 3 BLAS matrix times an upper triangular matrix.   
+       dger    Level 2 BLAS rank one update to a matrix.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       ddot    Level 1 BLAS that computes the scalar product of two vectors.   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+       dscal   Level 1 BLAS that scales a vector.   
+
+   \Remarks   
+
+    1. Currently only HOWMNY = 'A' and 'P' are implemented.   
+
+       Let X' denote the transpose of X.   
+
+    2. Schur vectors are an orthogonal representation for the basis of   
+       Ritz vectors. Thus, their numerical properties are often superior.   
+       If RVEC = .TRUE. then the relationship   
+               A * V(:,1:IPARAM(5)) = V(:,1:IPARAM(5)) * T, and   
+       V(:,1:IPARAM(5))' * V(:,1:IPARAM(5)) = I are approximately satisfied.   
+       Here T is the leading submatrix of order IPARAM(5) of the real   
+       upper quasi-triangular matrix stored workl(ipntr(12)). That is,   
+       T is block upper triangular with 1-by-1 and 2-by-2 diagonal blocks;   
+       each 2-by-2 diagonal block has its diagonal elements equal and its   
+       off-diagonal elements of opposite sign.  Corresponding to each 2-by-2   
+       diagonal block is a complex conjugate pair of Ritz values. The real   
+       Ritz values are stored on the diagonal of T.   
+
+    3. If IPARAM(7) = 3 or 4 and SIGMAI is not equal zero, then the user must   
+       form the IPARAM(5) Rayleigh quotients in order to transform the Ritz   
+       values computed by DNAUPD for OP to those of A*z = lambda*B*z.   
+       Set RVEC = .true. and HOWMNY = 'A', and   
+       compute   
+             Z(:,I)' * A * Z(:,I) if DI(I) = 0.   
+       If DI(I) is not equal to zero and DI(I+1) = - D(I),   
+       then the desired real and imaginary parts of the Ritz value are   
+             Z(:,I)' * A * Z(:,I) +  Z(:,I+1)' * A * Z(:,I+1),   
+             Z(:,I)' * A * Z(:,I+1) -  Z(:,I+1)' * A * Z(:,I), respectively.   
+       Another possibility is to set RVEC = .true. and HOWMNY = 'P' and   
+       compute V(:,1:IPARAM(5))' * A * V(:,1:IPARAM(5)) and then an upper   
+       quasi-triangular matrix of order IPARAM(5) is computed. See remark   
+       2 above.   
+
+   \Authors   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Chao Yang                    Houston, Texas   
+       Dept. of Computational &   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \SCCS Information: @(#)   
+   FILE: neupd.F   SID: 2.5   DATE OF SID: 7/31/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+   Subroutine */ int igraphdneupd_(logical *rvec, char *howmny, logical *select, 
+	doublereal *dr, doublereal *di, doublereal *z__, integer *ldz, 
+	doublereal *sigmar, doublereal *sigmai, doublereal *workev, char *
+	bmat, integer *n, char *which, integer *nev, doublereal *tol, 
+	doublereal *resid, integer *ncv, doublereal *v, integer *ldv, integer 
+	*iparam, integer *ipntr, doublereal *workd, doublereal *workl, 
+	integer *lworkl, integer *info)
+{
+    /* System generated locals */
+    integer v_dim1, v_offset, z_dim1, z_offset, i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double pow_dd(doublereal *, doublereal *);
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+    /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    integer j, k, ih;
+    doublereal vl[1]	/* was [1][1] */;
+    integer ibd, ldh, ldq, iri;
+    doublereal sep;
+    integer irr, wri, wrr;
+    extern /* Subroutine */ int igraphdger_(integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    integer mode;
+    doublereal eps23;
+    integer ierr;
+    doublereal temp;
+    integer iwev;
+    char type__[6];
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    doublereal temp1;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    integer ihbds, iconj;
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *);
+    doublereal conds;
+    logical reord;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    integer nconv;
+    extern /* Subroutine */ int igraphdtrmm_(char *, char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    doublereal thres;
+    extern /* Subroutine */ int igraphdmout_(integer *, integer *, integer *, 
+	    doublereal *, integer *, integer *, char *, ftnlen);
+    integer iwork[1];
+    doublereal rnorm;
+    integer ritzi;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen);
+    integer ritzr;
+    extern /* Subroutine */ int igraphdgeqr2_(integer *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdorm2r_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    extern doublereal igraphdlamch_(char *);
+    integer iheigi, iheigr;
+    extern /* Subroutine */ int igraphdlahqr_(logical *, logical *, integer *, 
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *), igraphdlacpy_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *), igraphdlaset_(char *, 
+	    integer *, integer *, doublereal *, doublereal *, doublereal *, 
+	    integer *);
+    integer logfil=0, ndigit;
+    extern /* Subroutine */ int igraphdtrevc_(char *, char *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, integer *, integer *, doublereal *, integer *);
+    integer mneupd=0, bounds;
+    extern /* Subroutine */ int igraphdtrsen_(char *, char *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, doublereal *, doublereal *,
+	     integer *, integer *, integer *, integer *);
+    integer msglvl, ktrord, invsub, iuptri, outncv;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       %------------------------%   
+       | Set default parameters |   
+       %------------------------%   
+
+       Parameter adjustments */
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --workd;
+    --resid;
+    --di;
+    --dr;
+    --workev;
+    --select;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    --iparam;
+    --ipntr;
+    --workl;
+
+    /* Function Body */
+    msglvl = mneupd;
+    mode = iparam[7];
+    nconv = iparam[5];
+    *info = 0;
+
+/*     %---------------------------------%   
+       | Get machine dependent constant. |   
+       %---------------------------------% */
+
+    eps23 = igraphdlamch_("Epsilon-Machine");
+    eps23 = pow_dd(&eps23, &c_b3);
+
+/*     %--------------%   
+       | Quick return |   
+       %--------------% */
+
+    ierr = 0;
+
+    if (nconv <= 0) {
+	ierr = -14;
+    } else if (*n <= 0) {
+	ierr = -1;
+    } else if (*nev <= 0) {
+	ierr = -2;
+    } else if (*ncv <= *nev + 1 || *ncv > *n) {
+	ierr = -3;
+    } else if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, 
+	    "SM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "LR", (ftnlen)2, 
+	    (ftnlen)2) != 0 && s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) != 0 
+	    && s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, 
+	    "SI", (ftnlen)2, (ftnlen)2) != 0) {
+	ierr = -5;
+    } else if (*(unsigned char *)bmat != 'I' && *(unsigned char *)bmat != 'G')
+	     {
+	ierr = -6;
+    } else /* if(complicated condition) */ {
+/* Computing 2nd power */
+	i__1 = *ncv;
+	if (*lworkl < i__1 * i__1 * 3 + *ncv * 6) {
+	    ierr = -7;
+	} else if (*(unsigned char *)howmny != 'A' && *(unsigned char *)
+		howmny != 'P' && *(unsigned char *)howmny != 'S' && *rvec) {
+	    ierr = -13;
+	} else if (*(unsigned char *)howmny == 'S') {
+	    ierr = -12;
+	}
+    }
+
+    if (mode == 1 || mode == 2) {
+	s_copy(type__, "REGULR", (ftnlen)6, (ftnlen)6);
+    } else if (mode == 3 && *sigmai == 0.) {
+	s_copy(type__, "SHIFTI", (ftnlen)6, (ftnlen)6);
+    } else if (mode == 3) {
+	s_copy(type__, "REALPT", (ftnlen)6, (ftnlen)6);
+    } else if (mode == 4) {
+	s_copy(type__, "IMAGPT", (ftnlen)6, (ftnlen)6);
+    } else {
+	ierr = -10;
+    }
+    if (mode == 1 && *(unsigned char *)bmat == 'G') {
+	ierr = -11;
+    }
+
+/*     %------------%   
+       | Error Exit |   
+       %------------% */
+
+    if (ierr != 0) {
+	*info = ierr;
+	goto L9000;
+    }
+
+/*     %--------------------------------------------------------%   
+       | Pointer into WORKL for address of H, RITZ, BOUNDS, Q   |   
+       | etc... and the remaining workspace.                    |   
+       | Also update pointer to be used on output.              |   
+       | Memory is laid out as follows:                         |   
+       | workl(1:ncv*ncv) := generated Hessenberg matrix        |   
+       | workl(ncv*ncv+1:ncv*ncv+2*ncv) := real and imaginary   |   
+       |                                   parts of ritz values |   
+       | workl(ncv*ncv+2*ncv+1:ncv*ncv+3*ncv) := error bounds   |   
+       %--------------------------------------------------------%   
+
+       %-----------------------------------------------------------%   
+       | The following is used and set by DNEUPD.                  |   
+       | workl(ncv*ncv+3*ncv+1:ncv*ncv+4*ncv) := The untransformed |   
+       |                             real part of the Ritz values. |   
+       | workl(ncv*ncv+4*ncv+1:ncv*ncv+5*ncv) := The untransformed |   
+       |                        imaginary part of the Ritz values. |   
+       | workl(ncv*ncv+5*ncv+1:ncv*ncv+6*ncv) := The untransformed |   
+       |                           error bounds of the Ritz values |   
+       | workl(ncv*ncv+6*ncv+1:2*ncv*ncv+6*ncv) := Holds the upper |   
+       |                             quasi-triangular matrix for H |   
+       | workl(2*ncv*ncv+6*ncv+1: 3*ncv*ncv+6*ncv) := Holds the    |   
+       |       associated matrix representation of the invariant   |   
+       |       subspace for H.                                     |   
+       | GRAND total of NCV * ( 3 * NCV + 6 ) locations.           |   
+       %-----------------------------------------------------------% */
+
+    ih = ipntr[5];
+    ritzr = ipntr[6];
+    ritzi = ipntr[7];
+    bounds = ipntr[8];
+    ldh = *ncv;
+    ldq = *ncv;
+    iheigr = bounds + ldh;
+    iheigi = iheigr + ldh;
+    ihbds = iheigi + ldh;
+    iuptri = ihbds + ldh;
+    invsub = iuptri + ldh * *ncv;
+    ipntr[9] = iheigr;
+    ipntr[10] = iheigi;
+    ipntr[11] = ihbds;
+    ipntr[12] = iuptri;
+    ipntr[13] = invsub;
+    wrr = 1;
+    wri = *ncv + 1;
+    iwev = wri + *ncv;
+
+/*     %-----------------------------------------%   
+       | irr points to the REAL part of the Ritz |   
+       |     values computed by _neigh before    |   
+       |     exiting _naup2.                     |   
+       | iri points to the IMAGINARY part of the |   
+       |     Ritz values computed by _neigh      |   
+       |     before exiting _naup2.              |   
+       | ibd points to the Ritz estimates        |   
+       |     computed by _neigh before exiting   |   
+       |     _naup2.                             |   
+       %-----------------------------------------% */
+
+    irr = ipntr[14] + *ncv * *ncv;
+    iri = irr + *ncv;
+    ibd = iri + *ncv;
+
+/*     %------------------------------------%   
+       | RNORM is B-norm of the RESID(1:N). |   
+       %------------------------------------% */
+
+    rnorm = workl[ih + 2];
+    workl[ih + 2] = 0.;
+
+    if (*rvec) {
+
+/*        %-------------------------------------------%   
+          | Get converged Ritz value on the boundary. |   
+          | Note: converged Ritz values have been     |   
+          | placed in the first NCONV locations in    |   
+          | workl(ritzr) and workl(ritzi).  They have |   
+          | been sorted (in _naup2) according to the  |   
+          | WHICH selection criterion.                |   
+          %-------------------------------------------% */
+
+	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(which, 
+		"SM", (ftnlen)2, (ftnlen)2) == 0) {
+	    thres = igraphdlapy2_(&workl[ritzr], &workl[ritzi]);
+	} else if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
+	    thres = workl[ritzr];
+	} else if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
+	    thres = (d__1 = workl[ritzi], abs(d__1));
+	}
+
+	if (msglvl > 2) {
+	    igraphdvout_(&logfil, &c__1, &thres, &ndigit, "_neupd: Threshold eigen"
+		    "value used for re-ordering", (ftnlen)49);
+	}
+
+/*        %----------------------------------------------------------%   
+          | Check to see if all converged Ritz values appear at the  |   
+          | top of the upper quasi-triangular matrix computed by     |   
+          | _neigh in _naup2.  This is done in the following way:    |   
+          |                                                          |   
+          | 1) For each Ritz value obtained from _neigh, compare it  |   
+          |    with the threshold Ritz value computed above to       |   
+          |    determine whether it is a wanted one.                 |   
+          |                                                          |   
+          | 2) If it is wanted, then check the corresponding Ritz    |   
+          |    estimate to see if it has converged.  If it has, set  |   
+          |    correponding entry in the logical array SELECT to     |   
+          |    .TRUE..                                               |   
+          |                                                          |   
+          | If SELECT(j) = .TRUE. and j > NCONV, then there is a     |   
+          | converged Ritz value that does not appear at the top of  |   
+          | the upper quasi-triangular matrix computed by _neigh in  |   
+          | _naup2.  Reordering is needed.                           |   
+          %----------------------------------------------------------% */
+
+	reord = FALSE_;
+	ktrord = 0;
+	i__1 = *ncv - 1;
+	for (j = 0; j <= i__1; ++j) {
+	    select[j + 1] = FALSE_;
+	    if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+		if (igraphdlapy2_(&workl[irr + j], &workl[iri + j]) >= thres) {
+/* Computing MAX */
+		    d__1 = eps23, d__2 = igraphdlapy2_(&workl[irr + j], &workl[iri 
+			    + j]);
+		    temp1 = max(d__1,d__2);
+		    if (workl[ibd + j] <= *tol * temp1) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+		if (igraphdlapy2_(&workl[irr + j], &workl[iri + j]) <= thres) {
+/* Computing MAX */
+		    d__1 = eps23, d__2 = igraphdlapy2_(&workl[irr + j], &workl[iri 
+			    + j]);
+		    temp1 = max(d__1,d__2);
+		    if (workl[ibd + j] <= *tol * temp1) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
+		if (workl[irr + j] >= thres) {
+/* Computing MAX */
+		    d__1 = eps23, d__2 = igraphdlapy2_(&workl[irr + j], &workl[iri 
+			    + j]);
+		    temp1 = max(d__1,d__2);
+		    if (workl[ibd + j] <= *tol * temp1) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
+		if (workl[irr + j] <= thres) {
+/* Computing MAX */
+		    d__1 = eps23, d__2 = igraphdlapy2_(&workl[irr + j], &workl[iri 
+			    + j]);
+		    temp1 = max(d__1,d__2);
+		    if (workl[ibd + j] <= *tol * temp1) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
+		if ((d__1 = workl[iri + j], abs(d__1)) >= thres) {
+/* Computing MAX */
+		    d__1 = eps23, d__2 = igraphdlapy2_(&workl[irr + j], &workl[iri 
+			    + j]);
+		    temp1 = max(d__1,d__2);
+		    if (workl[ibd + j] <= *tol * temp1) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
+		if ((d__1 = workl[iri + j], abs(d__1)) <= thres) {
+/* Computing MAX */
+		    d__1 = eps23, d__2 = igraphdlapy2_(&workl[irr + j], &workl[iri 
+			    + j]);
+		    temp1 = max(d__1,d__2);
+		    if (workl[ibd + j] <= *tol * temp1) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    }
+	    if (j + 1 > nconv) {
+		reord = select[j + 1] || reord;
+	    }
+	    if (select[j + 1]) {
+		++ktrord;
+	    }
+/* L10: */
+	}
+
+	if (msglvl > 2) {
+	    igraphivout_(&logfil, &c__1, &ktrord, &ndigit, "_neupd: Number of spec"
+		    "ified eigenvalues", (ftnlen)39);
+	    igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_neupd: Number of \"con"
+		    "verged\" eigenvalues", (ftnlen)41);
+	}
+
+/*        %-----------------------------------------------------------%   
+          | Call LAPACK routine dlahqr to compute the real Schur form |   
+          | of the upper Hessenberg matrix returned by DNAUPD.        |   
+          | Make a copy of the upper Hessenberg matrix.               |   
+          | Initialize the Schur vector matrix Q to the identity.     |   
+          %-----------------------------------------------------------% */
+
+	i__1 = ldh * *ncv;
+	igraphdcopy_(&i__1, &workl[ih], &c__1, &workl[iuptri], &c__1);
+	igraphdlaset_("All", ncv, ncv, &c_b44, &c_b45, &workl[invsub], &ldq);
+	igraphdlahqr_(&c_true, &c_true, ncv, &c__1, ncv, &workl[iuptri], &ldh, &
+		workl[iheigr], &workl[iheigi], &c__1, ncv, &workl[invsub], &
+		ldq, &ierr);
+	igraphdcopy_(ncv, &workl[invsub + *ncv - 1], &ldq, &workl[ihbds], &c__1);
+
+	if (ierr != 0) {
+	    *info = -8;
+	    goto L9000;
+	}
+
+	if (msglvl > 1) {
+	    igraphdvout_(&logfil, ncv, &workl[iheigr], &ndigit, "_neupd: Real part"
+		    " of the eigenvalues of H", (ftnlen)41);
+	    igraphdvout_(&logfil, ncv, &workl[iheigi], &ndigit, "_neupd: Imaginary"
+		    " part of the Eigenvalues of H", (ftnlen)46);
+	    igraphdvout_(&logfil, ncv, &workl[ihbds], &ndigit, "_neupd: Last row o"
+		    "f the Schur vector matrix", (ftnlen)43);
+	    if (msglvl > 3) {
+		igraphdmout_(&logfil, ncv, ncv, &workl[iuptri], &ldh, &ndigit, 
+			"_neupd: The upper quasi-triangular matrix ", (ftnlen)
+			42);
+	    }
+	}
+
+	if (reord) {
+
+/*           %-----------------------------------------------------%   
+             | Reorder the computed upper quasi-triangular matrix. |   
+             %-----------------------------------------------------% */
+
+	    igraphdtrsen_("None", "V", &select[1], ncv, &workl[iuptri], &ldh, &
+		    workl[invsub], &ldq, &workl[iheigr], &workl[iheigi], &
+		    nconv, &conds, &sep, &workl[ihbds], ncv, iwork, &c__1, &
+		    ierr);
+
+	    if (ierr == 1) {
+		*info = 1;
+		goto L9000;
+	    }
+
+	    if (msglvl > 2) {
+		igraphdvout_(&logfil, ncv, &workl[iheigr], &ndigit, "_neupd: Real "
+			"part of the eigenvalues of H--reordered", (ftnlen)52);
+		igraphdvout_(&logfil, ncv, &workl[iheigi], &ndigit, "_neupd: Imag "
+			"part of the eigenvalues of H--reordered", (ftnlen)52);
+		if (msglvl > 3) {
+		    igraphdmout_(&logfil, ncv, ncv, &workl[iuptri], &ldq, &ndigit, 
+			    "_neupd: Quasi-triangular matrix after re-orderi"
+			    "ng", (ftnlen)49);
+		}
+	    }
+
+	}
+
+/*        %---------------------------------------%   
+          | Copy the last row of the Schur vector |   
+          | into workl(ihbds).  This will be used |   
+          | to compute the Ritz estimates of      |   
+          | converged Ritz values.                |   
+          %---------------------------------------% */
+
+	igraphdcopy_(ncv, &workl[invsub + *ncv - 1], &ldq, &workl[ihbds], &c__1);
+
+/*        %----------------------------------------------------%   
+          | Place the computed eigenvalues of H into DR and DI |   
+          | if a spectral transformation was not used.         |   
+          %----------------------------------------------------% */
+
+	if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) == 0) {
+	    igraphdcopy_(&nconv, &workl[iheigr], &c__1, &dr[1], &c__1);
+	    igraphdcopy_(&nconv, &workl[iheigi], &c__1, &di[1], &c__1);
+	}
+
+/*        %----------------------------------------------------------%   
+          | Compute the QR factorization of the matrix representing  |   
+          | the wanted invariant subspace located in the first NCONV |   
+          | columns of workl(invsub,ldq).                            |   
+          %----------------------------------------------------------% */
+
+	igraphdgeqr2_(ncv, &nconv, &workl[invsub], &ldq, &workev[1], &workev[*ncv + 
+		1], &ierr);
+
+/*        %---------------------------------------------------------%   
+          | * Postmultiply V by Q using dorm2r.                     |   
+          | * Copy the first NCONV columns of VQ into Z.            |   
+          | * Postmultiply Z by R.                                  |   
+          | The N by NCONV matrix Z is now a matrix representation  |   
+          | of the approximate invariant subspace associated with   |   
+          | the Ritz values in workl(iheigr) and workl(iheigi)      |   
+          | The first NCONV columns of V are now approximate Schur  |   
+          | vectors associated with the real upper quasi-triangular |   
+          | matrix of order NCONV in workl(iuptri)                  |   
+          %---------------------------------------------------------% */
+
+	igraphdorm2r_("Right", "Notranspose", n, ncv, &nconv, &workl[invsub], &ldq, 
+		&workev[1], &v[v_offset], ldv, &workd[*n + 1], &ierr);
+	igraphdlacpy_("All", n, &nconv, &v[v_offset], ldv, &z__[z_offset], ldz);
+
+	i__1 = nconv;
+	for (j = 1; j <= i__1; ++j) {
+
+/*           %---------------------------------------------------%   
+             | Perform both a column and row scaling if the      |   
+             | diagonal element of workl(invsub,ldq) is negative |   
+             | I'm lazy and don't take advantage of the upper    |   
+             | quasi-triangular form of workl(iuptri,ldq)        |   
+             | Note that since Q is orthogonal, R is a diagonal  |   
+             | matrix consisting of plus or minus ones           |   
+             %---------------------------------------------------% */
+
+	    if (workl[invsub + (j - 1) * ldq + j - 1] < 0.) {
+		igraphdscal_(&nconv, &c_b71, &workl[iuptri + j - 1], &ldq);
+		igraphdscal_(&nconv, &c_b71, &workl[iuptri + (j - 1) * ldq], &c__1);
+	    }
+
+/* L20: */
+	}
+
+	if (*(unsigned char *)howmny == 'A') {
+
+/*           %--------------------------------------------%   
+             | Compute the NCONV wanted eigenvectors of T |   
+             | located in workl(iuptri,ldq).              |   
+             %--------------------------------------------% */
+
+	    i__1 = *ncv;
+	    for (j = 1; j <= i__1; ++j) {
+		if (j <= nconv) {
+		    select[j] = TRUE_;
+		} else {
+		    select[j] = FALSE_;
+		}
+/* L30: */
+	    }
+
+	    igraphdtrevc_("Right", "Select", &select[1], ncv, &workl[iuptri], &ldq, 
+		    vl, &c__1, &workl[invsub], &ldq, ncv, &outncv, &workev[1],
+		     &ierr);
+
+	    if (ierr != 0) {
+		*info = -9;
+		goto L9000;
+	    }
+
+/*           %------------------------------------------------%   
+             | Scale the returning eigenvectors so that their |   
+             | Euclidean norms are all one. LAPACK subroutine |   
+             | dtrevc returns each eigenvector normalized so  |   
+             | that the element of largest magnitude has      |   
+             | magnitude 1;                                   |   
+             %------------------------------------------------% */
+
+	    iconj = 0;
+	    i__1 = nconv;
+	    for (j = 1; j <= i__1; ++j) {
+
+		if (workl[iheigi + j - 1] == 0.) {
+
+/*                 %----------------------%   
+                   | real eigenvalue case |   
+                   %----------------------% */
+
+		    temp = igraphdnrm2_(ncv, &workl[invsub + (j - 1) * ldq], &c__1);
+		    d__1 = 1. / temp;
+		    igraphdscal_(ncv, &d__1, &workl[invsub + (j - 1) * ldq], &c__1);
+
+		} else {
+
+/*                 %-------------------------------------------%   
+                   | Complex conjugate pair case. Note that    |   
+                   | since the real and imaginary part of      |   
+                   | the eigenvector are stored in consecutive |   
+                   | columns, we further normalize by the      |   
+                   | square root of two.                       |   
+                   %-------------------------------------------% */
+
+		    if (iconj == 0) {
+			d__1 = igraphdnrm2_(ncv, &workl[invsub + (j - 1) * ldq], &
+				c__1);
+			d__2 = igraphdnrm2_(ncv, &workl[invsub + j * ldq], &c__1);
+			temp = igraphdlapy2_(&d__1, &d__2);
+			d__1 = 1. / temp;
+			igraphdscal_(ncv, &d__1, &workl[invsub + (j - 1) * ldq], &
+				c__1);
+			d__1 = 1. / temp;
+			igraphdscal_(ncv, &d__1, &workl[invsub + j * ldq], &c__1);
+			iconj = 1;
+		    } else {
+			iconj = 0;
+		    }
+
+		}
+
+/* L40: */
+	    }
+
+	    igraphdgemv_("T", ncv, &nconv, &c_b45, &workl[invsub], &ldq, &workl[
+		    ihbds], &c__1, &c_b44, &workev[1], &c__1);
+
+	    iconj = 0;
+	    i__1 = nconv;
+	    for (j = 1; j <= i__1; ++j) {
+		if (workl[iheigi + j - 1] != 0.) {
+
+/*                 %-------------------------------------------%   
+                   | Complex conjugate pair case. Note that    |   
+                   | since the real and imaginary part of      |   
+                   | the eigenvector are stored in consecutive |   
+                   %-------------------------------------------% */
+
+		    if (iconj == 0) {
+			workev[j] = igraphdlapy2_(&workev[j], &workev[j + 1]);
+			workev[j + 1] = workev[j];
+			iconj = 1;
+		    } else {
+			iconj = 0;
+		    }
+		}
+/* L45: */
+	    }
+
+	    if (msglvl > 2) {
+		igraphdcopy_(ncv, &workl[invsub + *ncv - 1], &ldq, &workl[ihbds], &
+			c__1);
+		igraphdvout_(&logfil, ncv, &workl[ihbds], &ndigit, "_neupd: Last r"
+			"ow of the eigenvector matrix for T", (ftnlen)48);
+		if (msglvl > 3) {
+		    igraphdmout_(&logfil, ncv, ncv, &workl[invsub], &ldq, &ndigit, 
+			    "_neupd: The eigenvector matrix for T", (ftnlen)
+			    36);
+		}
+	    }
+
+/*           %---------------------------------------%   
+             | Copy Ritz estimates into workl(ihbds) |   
+             %---------------------------------------% */
+
+	    igraphdcopy_(&nconv, &workev[1], &c__1, &workl[ihbds], &c__1);
+
+/*           %---------------------------------------------------------%   
+             | Compute the QR factorization of the eigenvector matrix  |   
+             | associated with leading portion of T in the first NCONV |   
+             | columns of workl(invsub,ldq).                           |   
+             %---------------------------------------------------------% */
+
+	    igraphdgeqr2_(ncv, &nconv, &workl[invsub], &ldq, &workev[1], &workev[*
+		    ncv + 1], &ierr);
+
+/*           %----------------------------------------------%   
+             | * Postmultiply Z by Q.                       |   
+             | * Postmultiply Z by R.                       |   
+             | The N by NCONV matrix Z is now contains the  |   
+             | Ritz vectors associated with the Ritz values |   
+             | in workl(iheigr) and workl(iheigi).          |   
+             %----------------------------------------------% */
+
+	    igraphdorm2r_("Right", "Notranspose", n, ncv, &nconv, &workl[invsub], &
+		    ldq, &workev[1], &z__[z_offset], ldz, &workd[*n + 1], &
+		    ierr);
+
+	    igraphdtrmm_("Right", "Upper", "No transpose", "Non-unit", n, &nconv, &
+		    c_b45, &workl[invsub], &ldq, &z__[z_offset], ldz);
+
+	}
+
+    } else {
+
+/*        %------------------------------------------------------%   
+          | An approximate invariant subspace is not needed.     |   
+          | Place the Ritz values computed DNAUPD into DR and DI |   
+          %------------------------------------------------------% */
+
+	igraphdcopy_(&nconv, &workl[ritzr], &c__1, &dr[1], &c__1);
+	igraphdcopy_(&nconv, &workl[ritzi], &c__1, &di[1], &c__1);
+	igraphdcopy_(&nconv, &workl[ritzr], &c__1, &workl[iheigr], &c__1);
+	igraphdcopy_(&nconv, &workl[ritzi], &c__1, &workl[iheigi], &c__1);
+	igraphdcopy_(&nconv, &workl[bounds], &c__1, &workl[ihbds], &c__1);
+    }
+
+/*     %------------------------------------------------%   
+       | Transform the Ritz values and possibly vectors |   
+       | and corresponding error bounds of OP to those  |   
+       | of A*x = lambda*B*x.                           |   
+       %------------------------------------------------% */
+
+    if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) == 0) {
+
+	if (*rvec) {
+	    igraphdscal_(ncv, &rnorm, &workl[ihbds], &c__1);
+	}
+
+    } else {
+
+/*        %---------------------------------------%   
+          |   A spectral transformation was used. |   
+          | * Determine the Ritz estimates of the |   
+          |   Ritz values in the original system. |   
+          %---------------------------------------% */
+
+	if (s_cmp(type__, "SHIFTI", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    if (*rvec) {
+		igraphdscal_(ncv, &rnorm, &workl[ihbds], &c__1);
+	    }
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+		temp = igraphdlapy2_(&workl[iheigr + k - 1], &workl[iheigi + k - 1])
+			;
+		workl[ihbds + k - 1] = (d__1 = workl[ihbds + k - 1], abs(d__1)
+			) / temp / temp;
+/* L50: */
+	    }
+
+	} else if (s_cmp(type__, "REALPT", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+/* L60: */
+	    }
+
+	} else if (s_cmp(type__, "IMAGPT", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+/* L70: */
+	    }
+
+	}
+
+/*        %-----------------------------------------------------------%   
+          | *  Transform the Ritz values back to the original system. |   
+          |    For TYPE = 'SHIFTI' the transformation is              |   
+          |             lambda = 1/theta + sigma                      |   
+          |    For TYPE = 'REALPT' or 'IMAGPT' the user must from     |   
+          |    Rayleigh quotients or a projection. See remark 3 above.|   
+          | NOTES:                                                    |   
+          | *The Ritz vectors are not affected by the transformation. |   
+          %-----------------------------------------------------------% */
+
+	if (s_cmp(type__, "SHIFTI", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+		temp = igraphdlapy2_(&workl[iheigr + k - 1], &workl[iheigi + k - 1])
+			;
+		workl[iheigr + k - 1] = workl[iheigr + k - 1] / temp / temp + 
+			*sigmar;
+		workl[iheigi + k - 1] = -workl[iheigi + k - 1] / temp / temp 
+			+ *sigmai;
+/* L80: */
+	    }
+
+	    igraphdcopy_(&nconv, &workl[iheigr], &c__1, &dr[1], &c__1);
+	    igraphdcopy_(&nconv, &workl[iheigi], &c__1, &di[1], &c__1);
+
+	} else if (s_cmp(type__, "REALPT", (ftnlen)6, (ftnlen)6) == 0 || 
+		s_cmp(type__, "IMAGPT", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    igraphdcopy_(&nconv, &workl[iheigr], &c__1, &dr[1], &c__1);
+	    igraphdcopy_(&nconv, &workl[iheigi], &c__1, &di[1], &c__1);
+
+	}
+
+    }
+
+    if (s_cmp(type__, "SHIFTI", (ftnlen)6, (ftnlen)6) == 0 && msglvl > 1) {
+	igraphdvout_(&logfil, &nconv, &dr[1], &ndigit, "_neupd: Untransformed real"
+		" part of the Ritz valuess.", (ftnlen)52);
+	igraphdvout_(&logfil, &nconv, &di[1], &ndigit, "_neupd: Untransformed imag"
+		" part of the Ritz valuess.", (ftnlen)52);
+	igraphdvout_(&logfil, &nconv, &workl[ihbds], &ndigit, "_neupd: Ritz estima"
+		"tes of untransformed Ritz values.", (ftnlen)52);
+    } else if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) == 0 && msglvl > 
+	    1) {
+	igraphdvout_(&logfil, &nconv, &dr[1], &ndigit, "_neupd: Real parts of conv"
+		"erged Ritz values.", (ftnlen)44);
+	igraphdvout_(&logfil, &nconv, &di[1], &ndigit, "_neupd: Imag parts of conv"
+		"erged Ritz values.", (ftnlen)44);
+	igraphdvout_(&logfil, &nconv, &workl[ihbds], &ndigit, "_neupd: Associated "
+		"Ritz estimates.", (ftnlen)34);
+    }
+
+/*     %-------------------------------------------------%   
+       | Eigenvector Purification step. Formally perform |   
+       | one of inverse subspace iteration. Only used    |   
+       | for MODE = 2.                                   |   
+       %-------------------------------------------------% */
+
+    if (*rvec && *(unsigned char *)howmny == 'A' && s_cmp(type__, "SHIFTI", (
+	    ftnlen)6, (ftnlen)6) == 0) {
+
+/*        %------------------------------------------------%   
+          | Purify the computed Ritz vectors by adding a   |   
+          | little bit of the residual vector:             |   
+          |                      T                         |   
+          |          resid(:)*( e    s ) / theta           |   
+          |                      NCV                       |   
+          | where H s = s theta. Remember that when theta  |   
+          | has nonzero imaginary part, the corresponding  |   
+          | Ritz vector is stored across two columns of Z. |   
+          %------------------------------------------------% */
+
+	iconj = 0;
+	i__1 = nconv;
+	for (j = 1; j <= i__1; ++j) {
+	    if (workl[iheigi + j - 1] == 0.) {
+		workev[j] = workl[invsub + (j - 1) * ldq + *ncv - 1] / workl[
+			iheigr + j - 1];
+	    } else if (iconj == 0) {
+		temp = igraphdlapy2_(&workl[iheigr + j - 1], &workl[iheigi + j - 1])
+			;
+		workev[j] = (workl[invsub + (j - 1) * ldq + *ncv - 1] * workl[
+			iheigr + j - 1] + workl[invsub + j * ldq + *ncv - 1] *
+			 workl[iheigi + j - 1]) / temp / temp;
+		workev[j + 1] = (workl[invsub + j * ldq + *ncv - 1] * workl[
+			iheigr + j - 1] - workl[invsub + (j - 1) * ldq + *ncv 
+			- 1] * workl[iheigi + j - 1]) / temp / temp;
+		iconj = 1;
+	    } else {
+		iconj = 0;
+	    }
+/* L110: */
+	}
+
+/*        %---------------------------------------%   
+          | Perform a rank one update to Z and    |   
+          | purify all the Ritz vectors together. |   
+          %---------------------------------------% */
+
+	igraphdger_(n, &nconv, &c_b45, &resid[1], &c__1, &workev[1], &c__1, &z__[
+		z_offset], ldz);
+
+    }
+
+L9000:
+
+    return 0;
+
+/*     %---------------%   
+       | End of DNEUPD |   
+       %---------------% */
+
+} /* igraphdneupd_ */
+
diff --git a/src/lapack/dngets.c b/src/lapack/dngets.c
new file mode 100644
index 0000000..b5ee51c
--- /dev/null
+++ b/src/lapack/dngets.c
@@ -0,0 +1,275 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static logical c_true = TRUE_;
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dngets   
+
+   \Description:   
+    Given the eigenvalues of the upper Hessenberg matrix H,   
+    computes the NP shifts AMU that are zeros of the polynomial of   
+    degree NP which filters out components of the unwanted eigenvectors   
+    corresponding to the AMU's based on some given criteria.   
+
+    NOTE: call this even in the case of user specified shifts in order   
+    to sort the eigenvalues, and error bounds of H for later use.   
+
+   \Usage:   
+    call dngets   
+       ( ISHIFT, WHICH, KEV, NP, RITZR, RITZI, BOUNDS, SHIFTR, SHIFTI )   
+
+   \Arguments   
+    ISHIFT  Integer.  (INPUT)   
+            Method for selecting the implicit shifts at each iteration.   
+            ISHIFT = 0: user specified shifts   
+            ISHIFT = 1: exact shift with respect to the matrix H.   
+
+    WHICH   Character*2.  (INPUT)   
+            Shift selection criteria.   
+            'LM' -> want the KEV eigenvalues of largest magnitude.   
+            'SM' -> want the KEV eigenvalues of smallest magnitude.   
+            'LR' -> want the KEV eigenvalues of largest real part.   
+            'SR' -> want the KEV eigenvalues of smallest real part.   
+            'LI' -> want the KEV eigenvalues of largest imaginary part.   
+            'SI' -> want the KEV eigenvalues of smallest imaginary part.   
+
+    KEV      Integer.  (INPUT/OUTPUT)   
+             INPUT: KEV+NP is the size of the matrix H.   
+             OUTPUT: Possibly increases KEV by one to keep complex conjugate   
+             pairs together.   
+
+    NP       Integer.  (INPUT/OUTPUT)   
+             Number of implicit shifts to be computed.   
+             OUTPUT: Possibly decreases NP by one to keep complex conjugate   
+             pairs together.   
+
+    RITZR,  Double precision array of length KEV+NP.  (INPUT/OUTPUT)   
+    RITZI   On INPUT, RITZR and RITZI contain the real and imaginary   
+            parts of the eigenvalues of H.   
+            On OUTPUT, RITZR and RITZI are sorted so that the unwanted   
+            eigenvalues are in the first NP locations and the wanted   
+            portion is in the last KEV locations.  When exact shifts are   
+            selected, the unwanted part corresponds to the shifts to   
+            be applied. Also, if ISHIFT .eq. 1, the unwanted eigenvalues   
+            are further sorted so that the ones with largest Ritz values   
+            are first.   
+
+    BOUNDS  Double precision array of length KEV+NP.  (INPUT/OUTPUT)   
+            Error bounds corresponding to the ordering in RITZ.   
+
+    SHIFTR, SHIFTI  *** USE deprecated as of version 2.1. ***   
+
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       dsortc  ARPACK sorting routine.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: ngets.F   SID: 2.3   DATE OF SID: 4/20/96   RELEASE: 2   
+
+   \Remarks   
+       1. xxxx   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdngets_(integer *ishift, char *which, integer *kev, 
+	integer *np, doublereal *ritzr, doublereal *ritzi, doublereal *bounds,
+	 doublereal *shiftr, doublereal *shifti)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    real t0, t1;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen), igraphsecond_(real *);
+    integer logfil=0, ndigit, mngets=0;
+    extern /* Subroutine */ int igraphdsortc_(char *, logical *, integer *, 
+	    doublereal *, doublereal *, doublereal *);
+    integer msglvl;
+    real tngets;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %----------------------%   
+       | Intrinsics Functions |   
+       %----------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       %-------------------------------%   
+       | Initialize timing statistics  |   
+       | & message level for debugging |   
+       %-------------------------------%   
+
+       Parameter adjustments */
+    --bounds;
+    --ritzi;
+    --ritzr;
+    --shiftr;
+    --shifti;
+
+    /* Function Body */
+    igraphsecond_(&t0);
+    msglvl = mngets;
+
+/*     %----------------------------------------------------%   
+       | LM, SM, LR, SR, LI, SI case.                       |   
+       | Sort the eigenvalues of H into the desired order   |   
+       | and apply the resulting order to BOUNDS.           |   
+       | The eigenvalues are sorted so that the wanted part |   
+       | are always in the last KEV locations.              |   
+       | We first do a pre-processing sort in order to keep |   
+       | complex conjugate pairs together                   |   
+       %----------------------------------------------------% */
+
+    if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+	i__1 = *kev + *np;
+	igraphdsortc_("LR", &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+    } else if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+	i__1 = *kev + *np;
+	igraphdsortc_("SR", &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+    } else if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
+	i__1 = *kev + *np;
+	igraphdsortc_("LM", &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+    } else if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
+	i__1 = *kev + *np;
+	igraphdsortc_("SM", &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+    } else if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
+	i__1 = *kev + *np;
+	igraphdsortc_("LM", &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+    } else if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
+	i__1 = *kev + *np;
+	igraphdsortc_("SM", &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+    }
+
+    i__1 = *kev + *np;
+    igraphdsortc_(which, &c_true, &i__1, &ritzr[1], &ritzi[1], &bounds[1]);
+
+/*     %-------------------------------------------------------%   
+       | Increase KEV by one if the ( ritzr(np),ritzi(np) )    |   
+       | = ( ritzr(np+1),-ritzi(np+1) ) and ritz(np) .ne. zero |   
+       | Accordingly decrease NP by one. In other words keep   |   
+       | complex conjugate pairs together.                     |   
+       %-------------------------------------------------------% */
+
+    if (ritzr[*np + 1] - ritzr[*np] == 0. && ritzi[*np + 1] + ritzi[*np] == 
+	    0.) {
+	--(*np);
+	++(*kev);
+    }
+
+    if (*ishift == 1) {
+
+/*        %-------------------------------------------------------%   
+          | Sort the unwanted Ritz values used as shifts so that  |   
+          | the ones with largest Ritz estimates are first        |   
+          | This will tend to minimize the effects of the         |   
+          | forward instability of the iteration when they shifts |   
+          | are applied in subroutine dnapps.                     |   
+          | Be careful and use 'SR' since we want to sort BOUNDS! |   
+          %-------------------------------------------------------% */
+
+	igraphdsortc_("SR", &c_true, np, &bounds[1], &ritzr[1], &ritzi[1]);
+    }
+
+    igraphsecond_(&t1);
+    tngets += t1 - t0;
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, kev, &ndigit, "_ngets: KEV is", (ftnlen)14);
+	igraphivout_(&logfil, &c__1, np, &ndigit, "_ngets: NP is", (ftnlen)13);
+	i__1 = *kev + *np;
+	igraphdvout_(&logfil, &i__1, &ritzr[1], &ndigit, "_ngets: Eigenvalues of c"
+		"urrent H matrix -- real part", (ftnlen)52);
+	i__1 = *kev + *np;
+	igraphdvout_(&logfil, &i__1, &ritzi[1], &ndigit, "_ngets: Eigenvalues of c"
+		"urrent H matrix -- imag part", (ftnlen)52);
+	i__1 = *kev + *np;
+	igraphdvout_(&logfil, &i__1, &bounds[1], &ndigit, "_ngets: Ritz estimates "
+		"of the current KEV+NP Ritz values", (ftnlen)56);
+    }
+
+    return 0;
+
+/*     %---------------%   
+       | End of dngets |   
+       %---------------% */
+
+} /* igraphdngets_ */
+
diff --git a/src/lapack/dnrm2.c b/src/lapack/dnrm2.c
new file mode 100644
index 0000000..264f4b6
--- /dev/null
+++ b/src/lapack/dnrm2.c
@@ -0,0 +1,88 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+doublereal igraphdnrm2_(integer *n, doublereal *x, integer *incx)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+    doublereal ret_val, d__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer ix;
+    doublereal ssq, norm, scale, absxi;
+
+
+/*  Purpose   
+    =======   
+
+    DNRM2 returns the euclidean norm of a vector via the function   
+    name, so that   
+
+       DNRM2 := sqrt( x'*x )   
+
+    Further Details   
+    ===============   
+
+    -- This version written on 25-October-1982.   
+       Modified on 14-October-1993 to inline the call to DLASSQ.   
+       Sven Hammarling, Nag Ltd.   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --x;
+
+    /* Function Body */
+    if (*n < 1 || *incx < 1) {
+	norm = 0.;
+    } else if (*n == 1) {
+	norm = abs(x[1]);
+    } else {
+	scale = 0.;
+	ssq = 1.;
+/*        The following loop is equivalent to this call to the LAPACK   
+          auxiliary routine:   
+          CALL DLASSQ( N, X, INCX, SCALE, SSQ ) */
+
+	i__1 = (*n - 1) * *incx + 1;
+	i__2 = *incx;
+	for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) {
+	    if (x[ix] != 0.) {
+		absxi = (d__1 = x[ix], abs(d__1));
+		if (scale < absxi) {
+/* Computing 2nd power */
+		    d__1 = scale / absxi;
+		    ssq = ssq * (d__1 * d__1) + 1.;
+		    scale = absxi;
+		} else {
+/* Computing 2nd power */
+		    d__1 = absxi / scale;
+		    ssq += d__1 * d__1;
+		}
+	    }
+/* L10: */
+	}
+	norm = scale * sqrt(ssq);
+    }
+
+    ret_val = norm;
+    return ret_val;
+
+/*     End of DNRM2. */
+
+} /* igraphdnrm2_ */
+
diff --git a/src/lapack/dorg2r.c b/src/lapack/dorg2r.c
new file mode 100644
index 0000000..d45eb46
--- /dev/null
+++ b/src/lapack/dorg2r.c
@@ -0,0 +1,163 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdorg2r_(integer *m, integer *n, integer *k, doublereal *
+	a, integer *lda, doublereal *tau, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__, j, l;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *), igraphdlarf_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *), igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DORG2R generates an m by n real matrix Q with orthonormal columns,   
+    which is defined as the first n columns of a product of k elementary   
+    reflectors of order m   
+
+          Q  =  H(1) H(2) . . . H(k)   
+
+    as returned by DGEQRF.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix Q. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix Q. M >= N >= 0.   
+
+    K       (input) INTEGER   
+            The number of elementary reflectors whose product defines the   
+            matrix Q. N >= K >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the i-th column must contain the vector which   
+            defines the elementary reflector H(i), for i = 1,2,...,k, as   
+            returned by DGEQRF in the first k columns of its array   
+            argument A.   
+            On exit, the m-by-n matrix Q.   
+
+    LDA     (input) INTEGER   
+            The first dimension of the array A. LDA >= max(1,M).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEQRF.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (N)   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument has an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    if (*m < 0) {
+	*info = -1;
+    } else if (*n < 0 || *n > *m) {
+	*info = -2;
+    } else if (*k < 0 || *k > *n) {
+	*info = -3;
+    } else if (*lda < max(1,*m)) {
+	*info = -5;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORG2R", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n <= 0) {
+	return 0;
+    }
+
+/*     Initialise columns k+1:n to columns of the unit matrix */
+
+    i__1 = *n;
+    for (j = *k + 1; j <= i__1; ++j) {
+	i__2 = *m;
+	for (l = 1; l <= i__2; ++l) {
+	    a[l + j * a_dim1] = 0.;
+/* L10: */
+	}
+	a[j + j * a_dim1] = 1.;
+/* L20: */
+    }
+
+    for (i__ = *k; i__ >= 1; --i__) {
+
+/*        Apply H(i) to A(i:m,i:n) from the left */
+
+	if (i__ < *n) {
+	    a[i__ + i__ * a_dim1] = 1.;
+	    i__1 = *m - i__ + 1;
+	    i__2 = *n - i__;
+	    igraphdlarf_("Left", &i__1, &i__2, &a[i__ + i__ * a_dim1], &c__1, &tau[
+		    i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]);
+	}
+	if (i__ < *m) {
+	    i__1 = *m - i__;
+	    d__1 = -tau[i__];
+	    igraphdscal_(&i__1, &d__1, &a[i__ + 1 + i__ * a_dim1], &c__1);
+	}
+	a[i__ + i__ * a_dim1] = 1. - tau[i__];
+
+/*        Set A(1:i-1,i) to zero */
+
+	i__1 = i__ - 1;
+	for (l = 1; l <= i__1; ++l) {
+	    a[l + i__ * a_dim1] = 0.;
+/* L30: */
+	}
+/* L40: */
+    }
+    return 0;
+
+/*     End of DORG2R */
+
+} /* igraphdorg2r_ */
+
diff --git a/src/lapack/dorghr.c b/src/lapack/dorghr.c
new file mode 100644
index 0000000..47cdcf2
--- /dev/null
+++ b/src/lapack/dorghr.c
@@ -0,0 +1,203 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdorghr_(integer *n, integer *ilo, integer *ihi, 
+	doublereal *a, integer *lda, doublereal *tau, doublereal *work, 
+	integer *lwork, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, nb, nh, iinfo;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphdorgqr_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    integer *);
+    integer lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DORGHR generates a real orthogonal matrix Q which is defined as the   
+    product of IHI-ILO elementary reflectors of order N, as returned by   
+    DGEHRD:   
+
+    Q = H(ilo) H(ilo+1) . . . H(ihi-1).   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix Q. N >= 0.   
+
+    ILO     (input) INTEGER   
+    IHI     (input) INTEGER   
+            ILO and IHI must have the same values as in the previous call   
+            of DGEHRD. Q is equal to the unit matrix except in the   
+            submatrix Q(ilo+1:ihi,ilo+1:ihi).   
+            1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the vectors which define the elementary reflectors,   
+            as returned by DGEHRD.   
+            On exit, the N-by-N orthogonal matrix Q.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A. LDA >= max(1,N).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (N-1)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEHRD.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK. LWORK >= IHI-ILO.   
+            For optimum performance LWORK >= (IHI-ILO)*NB, where NB is   
+            the optimal blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    nh = *ihi - *ilo;
+    lquery = *lwork == -1;
+    if (*n < 0) {
+	*info = -1;
+    } else if (*ilo < 1 || *ilo > max(1,*n)) {
+	*info = -2;
+    } else if (*ihi < min(*ilo,*n) || *ihi > *n) {
+	*info = -3;
+    } else if (*lda < max(1,*n)) {
+	*info = -5;
+    } else if (*lwork < max(1,nh) && ! lquery) {
+	*info = -8;
+    }
+
+    if (*info == 0) {
+	nb = igraphilaenv_(&c__1, "DORGQR", " ", &nh, &nh, &nh, &c_n1, (ftnlen)6, (
+		ftnlen)1);
+	lwkopt = max(1,nh) * nb;
+	work[1] = (doublereal) lwkopt;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORGHR", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+/*     Shift the vectors which define the elementary reflectors one   
+       column to the right, and set the first ilo and the last n-ihi   
+       rows and columns to those of the unit matrix */
+
+    i__1 = *ilo + 1;
+    for (j = *ihi; j >= i__1; --j) {
+	i__2 = j - 1;
+	for (i__ = 1; i__ <= i__2; ++i__) {
+	    a[i__ + j * a_dim1] = 0.;
+/* L10: */
+	}
+	i__2 = *ihi;
+	for (i__ = j + 1; i__ <= i__2; ++i__) {
+	    a[i__ + j * a_dim1] = a[i__ + (j - 1) * a_dim1];
+/* L20: */
+	}
+	i__2 = *n;
+	for (i__ = *ihi + 1; i__ <= i__2; ++i__) {
+	    a[i__ + j * a_dim1] = 0.;
+/* L30: */
+	}
+/* L40: */
+    }
+    i__1 = *ilo;
+    for (j = 1; j <= i__1; ++j) {
+	i__2 = *n;
+	for (i__ = 1; i__ <= i__2; ++i__) {
+	    a[i__ + j * a_dim1] = 0.;
+/* L50: */
+	}
+	a[j + j * a_dim1] = 1.;
+/* L60: */
+    }
+    i__1 = *n;
+    for (j = *ihi + 1; j <= i__1; ++j) {
+	i__2 = *n;
+	for (i__ = 1; i__ <= i__2; ++i__) {
+	    a[i__ + j * a_dim1] = 0.;
+/* L70: */
+	}
+	a[j + j * a_dim1] = 1.;
+/* L80: */
+    }
+
+    if (nh > 0) {
+
+/*        Generate Q(ilo+1:ihi,ilo+1:ihi) */
+
+	igraphdorgqr_(&nh, &nh, &nh, &a[*ilo + 1 + (*ilo + 1) * a_dim1], lda, &tau[*
+		ilo], &work[1], lwork, &iinfo);
+    }
+    work[1] = (doublereal) lwkopt;
+    return 0;
+
+/*     End of DORGHR */
+
+} /* igraphdorghr_ */
+
diff --git a/src/lapack/dorgqr.c b/src/lapack/dorgqr.c
new file mode 100644
index 0000000..b8086df
--- /dev/null
+++ b/src/lapack/dorgqr.c
@@ -0,0 +1,269 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__3 = 3;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdorgqr_(integer *m, integer *n, integer *k, doublereal *
+	a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, 
+	integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo;
+    extern /* Subroutine */ int igraphdorg2r_(integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *), 
+	    igraphdlarfb_(char *, char *, char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), igraphdlarft_(char *, char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *), igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    integer ldwork, lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DORGQR generates an M-by-N real matrix Q with orthonormal columns,   
+    which is defined as the first N columns of a product of K elementary   
+    reflectors of order M   
+
+          Q  =  H(1) H(2) . . . H(k)   
+
+    as returned by DGEQRF.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix Q. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix Q. M >= N >= 0.   
+
+    K       (input) INTEGER   
+            The number of elementary reflectors whose product defines the   
+            matrix Q. N >= K >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the i-th column must contain the vector which   
+            defines the elementary reflector H(i), for i = 1,2,...,k, as   
+            returned by DGEQRF in the first k columns of its array   
+            argument A.   
+            On exit, the M-by-N matrix Q.   
+
+    LDA     (input) INTEGER   
+            The first dimension of the array A. LDA >= max(1,M).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEQRF.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK. LWORK >= max(1,N).   
+            For optimum performance LWORK >= N*NB, where NB is the   
+            optimal blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument has an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    nb = igraphilaenv_(&c__1, "DORGQR", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1);
+    lwkopt = max(1,*n) * nb;
+    work[1] = (doublereal) lwkopt;
+    lquery = *lwork == -1;
+    if (*m < 0) {
+	*info = -1;
+    } else if (*n < 0 || *n > *m) {
+	*info = -2;
+    } else if (*k < 0 || *k > *n) {
+	*info = -3;
+    } else if (*lda < max(1,*m)) {
+	*info = -5;
+    } else if (*lwork < max(1,*n) && ! lquery) {
+	*info = -8;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORGQR", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n <= 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    nbmin = 2;
+    nx = 0;
+    iws = *n;
+    if (nb > 1 && nb < *k) {
+
+/*        Determine when to cross over from blocked to unblocked code.   
+
+   Computing MAX */
+	i__1 = 0, i__2 = igraphilaenv_(&c__3, "DORGQR", " ", m, n, k, &c_n1, (
+		ftnlen)6, (ftnlen)1);
+	nx = max(i__1,i__2);
+	if (nx < *k) {
+
+/*           Determine if workspace is large enough for blocked code. */
+
+	    ldwork = *n;
+	    iws = ldwork * nb;
+	    if (*lwork < iws) {
+
+/*              Not enough workspace to use optimal NB:  reduce NB and   
+                determine the minimum value of NB. */
+
+		nb = *lwork / ldwork;
+/* Computing MAX */
+		i__1 = 2, i__2 = igraphilaenv_(&c__2, "DORGQR", " ", m, n, k, &c_n1,
+			 (ftnlen)6, (ftnlen)1);
+		nbmin = max(i__1,i__2);
+	    }
+	}
+    }
+
+    if (nb >= nbmin && nb < *k && nx < *k) {
+
+/*        Use blocked code after the last block.   
+          The first kk columns are handled by the block method. */
+
+	ki = (*k - nx - 1) / nb * nb;
+/* Computing MIN */
+	i__1 = *k, i__2 = ki + nb;
+	kk = min(i__1,i__2);
+
+/*        Set A(1:kk,kk+1:n) to zero. */
+
+	i__1 = *n;
+	for (j = kk + 1; j <= i__1; ++j) {
+	    i__2 = kk;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		a[i__ + j * a_dim1] = 0.;
+/* L10: */
+	    }
+/* L20: */
+	}
+    } else {
+	kk = 0;
+    }
+
+/*     Use unblocked code for the last or only block. */
+
+    if (kk < *n) {
+	i__1 = *m - kk;
+	i__2 = *n - kk;
+	i__3 = *k - kk;
+	igraphdorg2r_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, &
+		tau[kk + 1], &work[1], &iinfo);
+    }
+
+    if (kk > 0) {
+
+/*        Use blocked code */
+
+	i__1 = -nb;
+	for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) {
+/* Computing MIN */
+	    i__2 = nb, i__3 = *k - i__ + 1;
+	    ib = min(i__2,i__3);
+	    if (i__ + ib <= *n) {
+
+/*              Form the triangular factor of the block reflector   
+                H = H(i) H(i+1) . . . H(i+ib-1) */
+
+		i__2 = *m - i__ + 1;
+		igraphdlarft_("Forward", "Columnwise", &i__2, &ib, &a[i__ + i__ * 
+			a_dim1], lda, &tau[i__], &work[1], &ldwork);
+
+/*              Apply H to A(i:m,i+ib:n) from the left */
+
+		i__2 = *m - i__ + 1;
+		i__3 = *n - i__ - ib + 1;
+		igraphdlarfb_("Left", "No transpose", "Forward", "Columnwise", &
+			i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[
+			1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, &
+			work[ib + 1], &ldwork);
+	    }
+
+/*           Apply H to rows i:m of current block */
+
+	    i__2 = *m - i__ + 1;
+	    igraphdorg2r_(&i__2, &ib, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], &
+		    work[1], &iinfo);
+
+/*           Set rows 1:i-1 of current block to zero */
+
+	    i__2 = i__ + ib - 1;
+	    for (j = i__; j <= i__2; ++j) {
+		i__3 = i__ - 1;
+		for (l = 1; l <= i__3; ++l) {
+		    a[l + j * a_dim1] = 0.;
+/* L30: */
+		}
+/* L40: */
+	    }
+/* L50: */
+	}
+    }
+
+    work[1] = (doublereal) iws;
+    return 0;
+
+/*     End of DORGQR */
+
+} /* igraphdorgqr_ */
+
diff --git a/src/lapack/dorm2l.c b/src/lapack/dorm2l.c
new file mode 100644
index 0000000..5d4346f
--- /dev/null
+++ b/src/lapack/dorm2l.c
@@ -0,0 +1,217 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdorm2l_(char *side, char *trans, integer *m, integer *n, 
+	integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal *
+	c__, integer *ldc, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, i1, i2, i3, mi, ni, nq;
+    doublereal aii;
+    logical left;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical notran;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DORM2L overwrites the general real m by n matrix C with   
+
+          Q * C  if SIDE = 'L' and TRANS = 'N', or   
+
+          Q**T * C  if SIDE = 'L' and TRANS = 'T', or   
+
+          C * Q  if SIDE = 'R' and TRANS = 'N', or   
+
+          C * Q**T if SIDE = 'R' and TRANS = 'T',   
+
+    where Q is a real orthogonal matrix defined as the product of k   
+    elementary reflectors   
+
+          Q = H(k) . . . H(2) H(1)   
+
+    as returned by DGEQLF. Q is of order m if SIDE = 'L' and of order n   
+    if SIDE = 'R'.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply Q or Q**T from the Left   
+            = 'R': apply Q or Q**T from the Right   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N': apply Q  (No transpose)   
+            = 'T': apply Q**T (Transpose)   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C. N >= 0.   
+
+    K       (input) INTEGER   
+            The number of elementary reflectors whose product defines   
+            the matrix Q.   
+            If SIDE = 'L', M >= K >= 0;   
+            if SIDE = 'R', N >= K >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,K)   
+            The i-th column must contain the vector which defines the   
+            elementary reflector H(i), for i = 1,2,...,k, as returned by   
+            DGEQLF in the last k columns of its array argument A.   
+            A is modified by the routine but restored on exit.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+            If SIDE = 'L', LDA >= max(1,M);   
+            if SIDE = 'R', LDA >= max(1,N).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEQLF.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the m by n matrix C.   
+            On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension   
+                                     (N) if SIDE = 'L',   
+                                     (M) if SIDE = 'R'   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    left = igraphlsame_(side, "L");
+    notran = igraphlsame_(trans, "N");
+
+/*     NQ is the order of Q */
+
+    if (left) {
+	nq = *m;
+    } else {
+	nq = *n;
+    }
+    if (! left && ! igraphlsame_(side, "R")) {
+	*info = -1;
+    } else if (! notran && ! igraphlsame_(trans, "T")) {
+	*info = -2;
+    } else if (*m < 0) {
+	*info = -3;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*k < 0 || *k > nq) {
+	*info = -5;
+    } else if (*lda < max(1,nq)) {
+	*info = -7;
+    } else if (*ldc < max(1,*m)) {
+	*info = -10;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORM2L", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0 || *k == 0) {
+	return 0;
+    }
+
+    if (left && notran || ! left && ! notran) {
+	i1 = 1;
+	i2 = *k;
+	i3 = 1;
+    } else {
+	i1 = *k;
+	i2 = 1;
+	i3 = -1;
+    }
+
+    if (left) {
+	ni = *n;
+    } else {
+	mi = *m;
+    }
+
+    i__1 = i2;
+    i__2 = i3;
+    for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+	if (left) {
+
+/*           H(i) is applied to C(1:m-k+i,1:n) */
+
+	    mi = *m - *k + i__;
+	} else {
+
+/*           H(i) is applied to C(1:m,1:n-k+i) */
+
+	    ni = *n - *k + i__;
+	}
+
+/*        Apply H(i) */
+
+	aii = a[nq - *k + i__ + i__ * a_dim1];
+	a[nq - *k + i__ + i__ * a_dim1] = 1.;
+	igraphdlarf_(side, &mi, &ni, &a[i__ * a_dim1 + 1], &c__1, &tau[i__], &c__[
+		c_offset], ldc, &work[1]);
+	a[nq - *k + i__ + i__ * a_dim1] = aii;
+/* L10: */
+    }
+    return 0;
+
+/*     End of DORM2L */
+
+} /* igraphdorm2l_ */
+
diff --git a/src/lapack/dorm2r.c b/src/lapack/dorm2r.c
new file mode 100644
index 0000000..8effa9f
--- /dev/null
+++ b/src/lapack/dorm2r.c
@@ -0,0 +1,221 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphdorm2r_(char *side, char *trans, integer *m, integer *n, 
+	integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal *
+	c__, integer *ldc, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, i1, i2, i3, ic, jc, mi, ni, nq;
+    doublereal aii;
+    logical left;
+    extern /* Subroutine */ int igraphdlarf_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical notran;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DORM2R overwrites the general real m by n matrix C with   
+
+          Q * C  if SIDE = 'L' and TRANS = 'N', or   
+
+          Q**T* C  if SIDE = 'L' and TRANS = 'T', or   
+
+          C * Q  if SIDE = 'R' and TRANS = 'N', or   
+
+          C * Q**T if SIDE = 'R' and TRANS = 'T',   
+
+    where Q is a real orthogonal matrix defined as the product of k   
+    elementary reflectors   
+
+          Q = H(1) H(2) . . . H(k)   
+
+    as returned by DGEQRF. Q is of order m if SIDE = 'L' and of order n   
+    if SIDE = 'R'.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply Q or Q**T from the Left   
+            = 'R': apply Q or Q**T from the Right   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N': apply Q  (No transpose)   
+            = 'T': apply Q**T (Transpose)   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C. N >= 0.   
+
+    K       (input) INTEGER   
+            The number of elementary reflectors whose product defines   
+            the matrix Q.   
+            If SIDE = 'L', M >= K >= 0;   
+            if SIDE = 'R', N >= K >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,K)   
+            The i-th column must contain the vector which defines the   
+            elementary reflector H(i), for i = 1,2,...,k, as returned by   
+            DGEQRF in the first k columns of its array argument A.   
+            A is modified by the routine but restored on exit.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+            If SIDE = 'L', LDA >= max(1,M);   
+            if SIDE = 'R', LDA >= max(1,N).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEQRF.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the m by n matrix C.   
+            On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension   
+                                     (N) if SIDE = 'L',   
+                                     (M) if SIDE = 'R'   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    left = igraphlsame_(side, "L");
+    notran = igraphlsame_(trans, "N");
+
+/*     NQ is the order of Q */
+
+    if (left) {
+	nq = *m;
+    } else {
+	nq = *n;
+    }
+    if (! left && ! igraphlsame_(side, "R")) {
+	*info = -1;
+    } else if (! notran && ! igraphlsame_(trans, "T")) {
+	*info = -2;
+    } else if (*m < 0) {
+	*info = -3;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*k < 0 || *k > nq) {
+	*info = -5;
+    } else if (*lda < max(1,nq)) {
+	*info = -7;
+    } else if (*ldc < max(1,*m)) {
+	*info = -10;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORM2R", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0 || *k == 0) {
+	return 0;
+    }
+
+    if (left && ! notran || ! left && notran) {
+	i1 = 1;
+	i2 = *k;
+	i3 = 1;
+    } else {
+	i1 = *k;
+	i2 = 1;
+	i3 = -1;
+    }
+
+    if (left) {
+	ni = *n;
+	jc = 1;
+    } else {
+	mi = *m;
+	ic = 1;
+    }
+
+    i__1 = i2;
+    i__2 = i3;
+    for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+	if (left) {
+
+/*           H(i) is applied to C(i:m,1:n) */
+
+	    mi = *m - i__ + 1;
+	    ic = i__;
+	} else {
+
+/*           H(i) is applied to C(1:m,i:n) */
+
+	    ni = *n - i__ + 1;
+	    jc = i__;
+	}
+
+/*        Apply H(i) */
+
+	aii = a[i__ + i__ * a_dim1];
+	a[i__ + i__ * a_dim1] = 1.;
+	igraphdlarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], &c__1, &tau[i__], &c__[
+		ic + jc * c_dim1], ldc, &work[1]);
+	a[i__ + i__ * a_dim1] = aii;
+/* L10: */
+    }
+    return 0;
+
+/*     End of DORM2R */
+
+} /* igraphdorm2r_ */
+
diff --git a/src/lapack/dormhr.c b/src/lapack/dormhr.c
new file mode 100644
index 0000000..c18c5a4
--- /dev/null
+++ b/src/lapack/dormhr.c
@@ -0,0 +1,247 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdormhr_(char *side, char *trans, integer *m, integer *n, 
+	integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal *
+	tau, doublereal *c__, integer *ldc, doublereal *work, integer *lwork, 
+	integer *info)
+{
+    /* System generated locals */
+    address a__1[2];
+    integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2;
+    char ch__1[2];
+
+    /* Builtin functions   
+       Subroutine */ int s_cat(char *, char **, integer *, integer *, ftnlen);
+
+    /* Local variables */
+    integer i1, i2, nb, mi, nh, ni, nq, nw;
+    logical left;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphdormqr_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *);
+    integer lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DORMHR overwrites the general real M-by-N matrix C with   
+
+                    SIDE = 'L'     SIDE = 'R'   
+    TRANS = 'N':      Q * C          C * Q   
+    TRANS = 'T':      Q**T * C       C * Q**T   
+
+    where Q is a real orthogonal matrix of order nq, with nq = m if   
+    SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of   
+    IHI-ILO elementary reflectors, as returned by DGEHRD:   
+
+    Q = H(ilo) H(ilo+1) . . . H(ihi-1).   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply Q or Q**T from the Left;   
+            = 'R': apply Q or Q**T from the Right.   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N':  No transpose, apply Q;   
+            = 'T':  Transpose, apply Q**T.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C. N >= 0.   
+
+    ILO     (input) INTEGER   
+    IHI     (input) INTEGER   
+            ILO and IHI must have the same values as in the previous call   
+            of DGEHRD. Q is equal to the unit matrix except in the   
+            submatrix Q(ilo+1:ihi,ilo+1:ihi).   
+            If SIDE = 'L', then 1 <= ILO <= IHI <= M, if M > 0, and   
+            ILO = 1 and IHI = 0, if M = 0;   
+            if SIDE = 'R', then 1 <= ILO <= IHI <= N, if N > 0, and   
+            ILO = 1 and IHI = 0, if N = 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension   
+                                 (LDA,M) if SIDE = 'L'   
+                                 (LDA,N) if SIDE = 'R'   
+            The vectors which define the elementary reflectors, as   
+            returned by DGEHRD.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+            LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'.   
+
+    TAU     (input) DOUBLE PRECISION array, dimension   
+                                 (M-1) if SIDE = 'L'   
+                                 (N-1) if SIDE = 'R'   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEHRD.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the M-by-N matrix C.   
+            On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.   
+            If SIDE = 'L', LWORK >= max(1,N);   
+            if SIDE = 'R', LWORK >= max(1,M).   
+            For optimum performance LWORK >= N*NB if SIDE = 'L', and   
+            LWORK >= M*NB if SIDE = 'R', where NB is the optimal   
+            blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    nh = *ihi - *ilo;
+    left = igraphlsame_(side, "L");
+    lquery = *lwork == -1;
+
+/*     NQ is the order of Q and NW is the minimum dimension of WORK */
+
+    if (left) {
+	nq = *m;
+	nw = *n;
+    } else {
+	nq = *n;
+	nw = *m;
+    }
+    if (! left && ! igraphlsame_(side, "R")) {
+	*info = -1;
+    } else if (! igraphlsame_(trans, "N") && ! igraphlsame_(trans, 
+	    "T")) {
+	*info = -2;
+    } else if (*m < 0) {
+	*info = -3;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*ilo < 1 || *ilo > max(1,nq)) {
+	*info = -5;
+    } else if (*ihi < min(*ilo,nq) || *ihi > nq) {
+	*info = -6;
+    } else if (*lda < max(1,nq)) {
+	*info = -8;
+    } else if (*ldc < max(1,*m)) {
+	*info = -11;
+    } else if (*lwork < max(1,nw) && ! lquery) {
+	*info = -13;
+    }
+
+    if (*info == 0) {
+	if (left) {
+/* Writing concatenation */
+	    i__1[0] = 1, a__1[0] = side;
+	    i__1[1] = 1, a__1[1] = trans;
+	    s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2);
+	    nb = igraphilaenv_(&c__1, "DORMQR", ch__1, &nh, n, &nh, &c_n1, (ftnlen)
+		    6, (ftnlen)2);
+	} else {
+/* Writing concatenation */
+	    i__1[0] = 1, a__1[0] = side;
+	    i__1[1] = 1, a__1[1] = trans;
+	    s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2);
+	    nb = igraphilaenv_(&c__1, "DORMQR", ch__1, m, &nh, &nh, &c_n1, (ftnlen)
+		    6, (ftnlen)2);
+	}
+	lwkopt = max(1,nw) * nb;
+	work[1] = (doublereal) lwkopt;
+    }
+
+    if (*info != 0) {
+	i__2 = -(*info);
+	igraphxerbla_("DORMHR", &i__2, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0 || nh == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    if (left) {
+	mi = nh;
+	ni = *n;
+	i1 = *ilo + 1;
+	i2 = 1;
+    } else {
+	mi = *m;
+	ni = nh;
+	i1 = 1;
+	i2 = *ilo + 1;
+    }
+
+    igraphdormqr_(side, trans, &mi, &ni, &nh, &a[*ilo + 1 + *ilo * a_dim1], lda, &
+	    tau[*ilo], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo);
+
+    work[1] = (doublereal) lwkopt;
+    return 0;
+
+/*     End of DORMHR */
+
+} /* igraphdormhr_ */
+
diff --git a/src/lapack/dormql.c b/src/lapack/dormql.c
new file mode 100644
index 0000000..5c59fb0
--- /dev/null
+++ b/src/lapack/dormql.c
@@ -0,0 +1,313 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__2 = 2;
+static integer c__65 = 65;
+
+/* Subroutine */ int igraphdormql_(char *side, char *trans, integer *m, integer *n, 
+	integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal *
+	c__, integer *ldc, doublereal *work, integer *lwork, integer *info)
+{
+    /* System generated locals */
+    address a__1[2];
+    integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, 
+	    i__5;
+    char ch__1[2];
+
+    /* Builtin functions   
+       Subroutine */ int s_cat(char *, char **, integer *, integer *, ftnlen);
+
+    /* Local variables */
+    integer i__;
+    doublereal t[4160]	/* was [65][64] */;
+    integer i1, i2, i3, ib, nb, mi, ni, nq, nw, iws;
+    logical left;
+    extern logical igraphlsame_(char *, char *);
+    integer nbmin, iinfo;
+    extern /* Subroutine */ int igraphdorm2l_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *), igraphdlarfb_(char 
+	    *, char *, char *, char *, integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *), igraphdlarft_(char *, char *, integer *, integer *, doublereal 
+	    *, integer *, doublereal *, doublereal *, integer *), igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    logical notran;
+    integer ldwork, lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DORMQL overwrites the general real M-by-N matrix C with   
+
+                    SIDE = 'L'     SIDE = 'R'   
+    TRANS = 'N':      Q * C          C * Q   
+    TRANS = 'T':      Q**T * C       C * Q**T   
+
+    where Q is a real orthogonal matrix defined as the product of k   
+    elementary reflectors   
+
+          Q = H(k) . . . H(2) H(1)   
+
+    as returned by DGEQLF. Q is of order M if SIDE = 'L' and of order N   
+    if SIDE = 'R'.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply Q or Q**T from the Left;   
+            = 'R': apply Q or Q**T from the Right.   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N':  No transpose, apply Q;   
+            = 'T':  Transpose, apply Q**T.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C. N >= 0.   
+
+    K       (input) INTEGER   
+            The number of elementary reflectors whose product defines   
+            the matrix Q.   
+            If SIDE = 'L', M >= K >= 0;   
+            if SIDE = 'R', N >= K >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,K)   
+            The i-th column must contain the vector which defines the   
+            elementary reflector H(i), for i = 1,2,...,k, as returned by   
+            DGEQLF in the last k columns of its array argument A.   
+            A is modified by the routine but restored on exit.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+            If SIDE = 'L', LDA >= max(1,M);   
+            if SIDE = 'R', LDA >= max(1,N).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEQLF.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the M-by-N matrix C.   
+            On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.   
+            If SIDE = 'L', LWORK >= max(1,N);   
+            if SIDE = 'R', LWORK >= max(1,M).   
+            For optimum performance LWORK >= N*NB if SIDE = 'L', and   
+            LWORK >= M*NB if SIDE = 'R', where NB is the optimal   
+            blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    left = igraphlsame_(side, "L");
+    notran = igraphlsame_(trans, "N");
+    lquery = *lwork == -1;
+
+/*     NQ is the order of Q and NW is the minimum dimension of WORK */
+
+    if (left) {
+	nq = *m;
+	nw = max(1,*n);
+    } else {
+	nq = *n;
+	nw = max(1,*m);
+    }
+    if (! left && ! igraphlsame_(side, "R")) {
+	*info = -1;
+    } else if (! notran && ! igraphlsame_(trans, "T")) {
+	*info = -2;
+    } else if (*m < 0) {
+	*info = -3;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*k < 0 || *k > nq) {
+	*info = -5;
+    } else if (*lda < max(1,nq)) {
+	*info = -7;
+    } else if (*ldc < max(1,*m)) {
+	*info = -10;
+    }
+
+    if (*info == 0) {
+	if (*m == 0 || *n == 0) {
+	    lwkopt = 1;
+	} else {
+
+/*           Determine the block size.  NB may be at most NBMAX, where   
+             NBMAX is used to define the local array T.   
+
+   Computing MIN   
+   Writing concatenation */
+	    i__3[0] = 1, a__1[0] = side;
+	    i__3[1] = 1, a__1[1] = trans;
+	    s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2);
+	    i__1 = 64, i__2 = igraphilaenv_(&c__1, "DORMQL", ch__1, m, n, k, &c_n1, 
+		    (ftnlen)6, (ftnlen)2);
+	    nb = min(i__1,i__2);
+	    lwkopt = nw * nb;
+	}
+	work[1] = (doublereal) lwkopt;
+
+	if (*lwork < nw && ! lquery) {
+	    *info = -12;
+	}
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORMQL", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+
+    nbmin = 2;
+    ldwork = nw;
+    if (nb > 1 && nb < *k) {
+	iws = nw * nb;
+	if (*lwork < iws) {
+	    nb = *lwork / ldwork;
+/* Computing MAX   
+   Writing concatenation */
+	    i__3[0] = 1, a__1[0] = side;
+	    i__3[1] = 1, a__1[1] = trans;
+	    s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2);
+	    i__1 = 2, i__2 = igraphilaenv_(&c__2, "DORMQL", ch__1, m, n, k, &c_n1, (
+		    ftnlen)6, (ftnlen)2);
+	    nbmin = max(i__1,i__2);
+	}
+    } else {
+	iws = nw;
+    }
+
+    if (nb < nbmin || nb >= *k) {
+
+/*        Use unblocked code */
+
+	igraphdorm2l_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[
+		c_offset], ldc, &work[1], &iinfo);
+    } else {
+
+/*        Use blocked code */
+
+	if (left && notran || ! left && ! notran) {
+	    i1 = 1;
+	    i2 = *k;
+	    i3 = nb;
+	} else {
+	    i1 = (*k - 1) / nb * nb + 1;
+	    i2 = 1;
+	    i3 = -nb;
+	}
+
+	if (left) {
+	    ni = *n;
+	} else {
+	    mi = *m;
+	}
+
+	i__1 = i2;
+	i__2 = i3;
+	for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+/* Computing MIN */
+	    i__4 = nb, i__5 = *k - i__ + 1;
+	    ib = min(i__4,i__5);
+
+/*           Form the triangular factor of the block reflector   
+             H = H(i+ib-1) . . . H(i+1) H(i) */
+
+	    i__4 = nq - *k + i__ + ib - 1;
+	    igraphdlarft_("Backward", "Columnwise", &i__4, &ib, &a[i__ * a_dim1 + 1]
+		    , lda, &tau[i__], t, &c__65);
+	    if (left) {
+
+/*              H or H**T is applied to C(1:m-k+i+ib-1,1:n) */
+
+		mi = *m - *k + i__ + ib - 1;
+	    } else {
+
+/*              H or H**T is applied to C(1:m,1:n-k+i+ib-1) */
+
+		ni = *n - *k + i__ + ib - 1;
+	    }
+
+/*           Apply H or H**T */
+
+	    igraphdlarfb_(side, trans, "Backward", "Columnwise", &mi, &ni, &ib, &a[
+		    i__ * a_dim1 + 1], lda, t, &c__65, &c__[c_offset], ldc, &
+		    work[1], &ldwork);
+/* L10: */
+	}
+    }
+    work[1] = (doublereal) lwkopt;
+    return 0;
+
+/*     End of DORMQL */
+
+} /* igraphdormql_ */
+
diff --git a/src/lapack/dormqr.c b/src/lapack/dormqr.c
new file mode 100644
index 0000000..b6214d0
--- /dev/null
+++ b/src/lapack/dormqr.c
@@ -0,0 +1,313 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__2 = 2;
+static integer c__65 = 65;
+
+/* Subroutine */ int igraphdormqr_(char *side, char *trans, integer *m, integer *n, 
+	integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal *
+	c__, integer *ldc, doublereal *work, integer *lwork, integer *info)
+{
+    /* System generated locals */
+    address a__1[2];
+    integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, 
+	    i__5;
+    char ch__1[2];
+
+    /* Builtin functions   
+       Subroutine */ int s_cat(char *, char **, integer *, integer *, ftnlen);
+
+    /* Local variables */
+    integer i__;
+    doublereal t[4160]	/* was [65][64] */;
+    integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws;
+    logical left;
+    extern logical igraphlsame_(char *, char *);
+    integer nbmin, iinfo;
+    extern /* Subroutine */ int igraphdorm2r_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *), igraphdlarfb_(char 
+	    *, char *, char *, char *, integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *), igraphdlarft_(char *, char *, integer *, integer *, doublereal 
+	    *, integer *, doublereal *, doublereal *, integer *), igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    logical notran;
+    integer ldwork, lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DORMQR overwrites the general real M-by-N matrix C with   
+
+                    SIDE = 'L'     SIDE = 'R'   
+    TRANS = 'N':      Q * C          C * Q   
+    TRANS = 'T':      Q**T * C       C * Q**T   
+
+    where Q is a real orthogonal matrix defined as the product of k   
+    elementary reflectors   
+
+          Q = H(1) H(2) . . . H(k)   
+
+    as returned by DGEQRF. Q is of order M if SIDE = 'L' and of order N   
+    if SIDE = 'R'.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply Q or Q**T from the Left;   
+            = 'R': apply Q or Q**T from the Right.   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N':  No transpose, apply Q;   
+            = 'T':  Transpose, apply Q**T.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C. N >= 0.   
+
+    K       (input) INTEGER   
+            The number of elementary reflectors whose product defines   
+            the matrix Q.   
+            If SIDE = 'L', M >= K >= 0;   
+            if SIDE = 'R', N >= K >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,K)   
+            The i-th column must contain the vector which defines the   
+            elementary reflector H(i), for i = 1,2,...,k, as returned by   
+            DGEQRF in the first k columns of its array argument A.   
+            A is modified by the routine but restored on exit.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+            If SIDE = 'L', LDA >= max(1,M);   
+            if SIDE = 'R', LDA >= max(1,N).   
+
+    TAU     (input) DOUBLE PRECISION array, dimension (K)   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DGEQRF.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the M-by-N matrix C.   
+            On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.   
+            If SIDE = 'L', LWORK >= max(1,N);   
+            if SIDE = 'R', LWORK >= max(1,M).   
+            For optimum performance LWORK >= N*NB if SIDE = 'L', and   
+            LWORK >= M*NB if SIDE = 'R', where NB is the optimal   
+            blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    left = igraphlsame_(side, "L");
+    notran = igraphlsame_(trans, "N");
+    lquery = *lwork == -1;
+
+/*     NQ is the order of Q and NW is the minimum dimension of WORK */
+
+    if (left) {
+	nq = *m;
+	nw = *n;
+    } else {
+	nq = *n;
+	nw = *m;
+    }
+    if (! left && ! igraphlsame_(side, "R")) {
+	*info = -1;
+    } else if (! notran && ! igraphlsame_(trans, "T")) {
+	*info = -2;
+    } else if (*m < 0) {
+	*info = -3;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*k < 0 || *k > nq) {
+	*info = -5;
+    } else if (*lda < max(1,nq)) {
+	*info = -7;
+    } else if (*ldc < max(1,*m)) {
+	*info = -10;
+    } else if (*lwork < max(1,nw) && ! lquery) {
+	*info = -12;
+    }
+
+    if (*info == 0) {
+
+/*        Determine the block size.  NB may be at most NBMAX, where NBMAX   
+          is used to define the local array T.   
+
+   Computing MIN   
+   Writing concatenation */
+	i__3[0] = 1, a__1[0] = side;
+	i__3[1] = 1, a__1[1] = trans;
+	s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2);
+	i__1 = 64, i__2 = igraphilaenv_(&c__1, "DORMQR", ch__1, m, n, k, &c_n1, (
+		ftnlen)6, (ftnlen)2);
+	nb = min(i__1,i__2);
+	lwkopt = max(1,nw) * nb;
+	work[1] = (doublereal) lwkopt;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DORMQR", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0 || *k == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    nbmin = 2;
+    ldwork = nw;
+    if (nb > 1 && nb < *k) {
+	iws = nw * nb;
+	if (*lwork < iws) {
+	    nb = *lwork / ldwork;
+/* Computing MAX   
+   Writing concatenation */
+	    i__3[0] = 1, a__1[0] = side;
+	    i__3[1] = 1, a__1[1] = trans;
+	    s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2);
+	    i__1 = 2, i__2 = igraphilaenv_(&c__2, "DORMQR", ch__1, m, n, k, &c_n1, (
+		    ftnlen)6, (ftnlen)2);
+	    nbmin = max(i__1,i__2);
+	}
+    } else {
+	iws = nw;
+    }
+
+    if (nb < nbmin || nb >= *k) {
+
+/*        Use unblocked code */
+
+	igraphdorm2r_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[
+		c_offset], ldc, &work[1], &iinfo);
+    } else {
+
+/*        Use blocked code */
+
+	if (left && ! notran || ! left && notran) {
+	    i1 = 1;
+	    i2 = *k;
+	    i3 = nb;
+	} else {
+	    i1 = (*k - 1) / nb * nb + 1;
+	    i2 = 1;
+	    i3 = -nb;
+	}
+
+	if (left) {
+	    ni = *n;
+	    jc = 1;
+	} else {
+	    mi = *m;
+	    ic = 1;
+	}
+
+	i__1 = i2;
+	i__2 = i3;
+	for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+/* Computing MIN */
+	    i__4 = nb, i__5 = *k - i__ + 1;
+	    ib = min(i__4,i__5);
+
+/*           Form the triangular factor of the block reflector   
+             H = H(i) H(i+1) . . . H(i+ib-1) */
+
+	    i__4 = nq - i__ + 1;
+	    igraphdlarft_("Forward", "Columnwise", &i__4, &ib, &a[i__ + i__ * 
+		    a_dim1], lda, &tau[i__], t, &c__65)
+		    ;
+	    if (left) {
+
+/*              H or H**T is applied to C(i:m,1:n) */
+
+		mi = *m - i__ + 1;
+		ic = i__;
+	    } else {
+
+/*              H or H**T is applied to C(1:m,i:n) */
+
+		ni = *n - i__ + 1;
+		jc = i__;
+	    }
+
+/*           Apply H or H**T */
+
+	    igraphdlarfb_(side, trans, "Forward", "Columnwise", &mi, &ni, &ib, &a[
+		    i__ + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * 
+		    c_dim1], ldc, &work[1], &ldwork);
+/* L10: */
+	}
+    }
+    work[1] = (doublereal) lwkopt;
+    return 0;
+
+/*     End of DORMQR */
+
+} /* igraphdormqr_ */
+
diff --git a/src/lapack/dormtr.c b/src/lapack/dormtr.c
new file mode 100644
index 0000000..f1ee198
--- /dev/null
+++ b/src/lapack/dormtr.c
@@ -0,0 +1,287 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdormtr_(char *side, char *uplo, char *trans, integer *m, 
+	integer *n, doublereal *a, integer *lda, doublereal *tau, doublereal *
+	c__, integer *ldc, doublereal *work, integer *lwork, integer *info)
+{
+    /* System generated locals */
+    address a__1[2];
+    integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2, i__3;
+    char ch__1[2];
+
+    /* Builtin functions   
+       Subroutine */ int s_cat(char *, char **, integer *, integer *, ftnlen);
+
+    /* Local variables */
+    integer i1, i2, nb, mi, ni, nq, nw;
+    logical left;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo;
+    logical upper;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphdormql_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *), 
+	    igraphdormqr_(char *, char *, integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *, 
+	    doublereal *, integer *, integer *);
+    integer lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DORMTR overwrites the general real M-by-N matrix C with   
+
+                    SIDE = 'L'     SIDE = 'R'   
+    TRANS = 'N':      Q * C          C * Q   
+    TRANS = 'T':      Q**T * C       C * Q**T   
+
+    where Q is a real orthogonal matrix of order nq, with nq = m if   
+    SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of   
+    nq-1 elementary reflectors, as returned by DSYTRD:   
+
+    if UPLO = 'U', Q = H(nq-1) . . . H(2) H(1);   
+
+    if UPLO = 'L', Q = H(1) H(2) . . . H(nq-1).   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'L': apply Q or Q**T from the Left;   
+            = 'R': apply Q or Q**T from the Right.   
+
+    UPLO    (input) CHARACTER*1   
+            = 'U': Upper triangle of A contains elementary reflectors   
+                   from DSYTRD;   
+            = 'L': Lower triangle of A contains elementary reflectors   
+                   from DSYTRD.   
+
+    TRANS   (input) CHARACTER*1   
+            = 'N':  No transpose, apply Q;   
+            = 'T':  Transpose, apply Q**T.   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix C. M >= 0.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix C. N >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension   
+                                 (LDA,M) if SIDE = 'L'   
+                                 (LDA,N) if SIDE = 'R'   
+            The vectors which define the elementary reflectors, as   
+            returned by DSYTRD.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.   
+            LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'.   
+
+    TAU     (input) DOUBLE PRECISION array, dimension   
+                                 (M-1) if SIDE = 'L'   
+                                 (N-1) if SIDE = 'R'   
+            TAU(i) must contain the scalar factor of the elementary   
+            reflector H(i), as returned by DSYTRD.   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the M-by-N matrix C.   
+            On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M).   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.   
+            If SIDE = 'L', LWORK >= max(1,N);   
+            if SIDE = 'R', LWORK >= max(1,M).   
+            For optimum performance LWORK >= N*NB if SIDE = 'L', and   
+            LWORK >= M*NB if SIDE = 'R', where NB is the optimal   
+            blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    =====================================================================   
+
+
+       Test the input arguments   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --tau;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    left = igraphlsame_(side, "L");
+    upper = igraphlsame_(uplo, "U");
+    lquery = *lwork == -1;
+
+/*     NQ is the order of Q and NW is the minimum dimension of WORK */
+
+    if (left) {
+	nq = *m;
+	nw = *n;
+    } else {
+	nq = *n;
+	nw = *m;
+    }
+    if (! left && ! igraphlsame_(side, "R")) {
+	*info = -1;
+    } else if (! upper && ! igraphlsame_(uplo, "L")) {
+	*info = -2;
+    } else if (! igraphlsame_(trans, "N") && ! igraphlsame_(trans, 
+	    "T")) {
+	*info = -3;
+    } else if (*m < 0) {
+	*info = -4;
+    } else if (*n < 0) {
+	*info = -5;
+    } else if (*lda < max(1,nq)) {
+	*info = -7;
+    } else if (*ldc < max(1,*m)) {
+	*info = -10;
+    } else if (*lwork < max(1,nw) && ! lquery) {
+	*info = -12;
+    }
+
+    if (*info == 0) {
+	if (upper) {
+	    if (left) {
+/* Writing concatenation */
+		i__1[0] = 1, a__1[0] = side;
+		i__1[1] = 1, a__1[1] = trans;
+		s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2);
+		i__2 = *m - 1;
+		i__3 = *m - 1;
+		nb = igraphilaenv_(&c__1, "DORMQL", ch__1, &i__2, n, &i__3, &c_n1, (
+			ftnlen)6, (ftnlen)2);
+	    } else {
+/* Writing concatenation */
+		i__1[0] = 1, a__1[0] = side;
+		i__1[1] = 1, a__1[1] = trans;
+		s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2);
+		i__2 = *n - 1;
+		i__3 = *n - 1;
+		nb = igraphilaenv_(&c__1, "DORMQL", ch__1, m, &i__2, &i__3, &c_n1, (
+			ftnlen)6, (ftnlen)2);
+	    }
+	} else {
+	    if (left) {
+/* Writing concatenation */
+		i__1[0] = 1, a__1[0] = side;
+		i__1[1] = 1, a__1[1] = trans;
+		s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2);
+		i__2 = *m - 1;
+		i__3 = *m - 1;
+		nb = igraphilaenv_(&c__1, "DORMQR", ch__1, &i__2, n, &i__3, &c_n1, (
+			ftnlen)6, (ftnlen)2);
+	    } else {
+/* Writing concatenation */
+		i__1[0] = 1, a__1[0] = side;
+		i__1[1] = 1, a__1[1] = trans;
+		s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2);
+		i__2 = *n - 1;
+		i__3 = *n - 1;
+		nb = igraphilaenv_(&c__1, "DORMQR", ch__1, m, &i__2, &i__3, &c_n1, (
+			ftnlen)6, (ftnlen)2);
+	    }
+	}
+	lwkopt = max(1,nw) * nb;
+	work[1] = (doublereal) lwkopt;
+    }
+
+    if (*info != 0) {
+	i__2 = -(*info);
+	igraphxerbla_("DORMTR", &i__2, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*m == 0 || *n == 0 || nq == 1) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    if (left) {
+	mi = *m - 1;
+	ni = *n;
+    } else {
+	mi = *m;
+	ni = *n - 1;
+    }
+
+    if (upper) {
+
+/*        Q was determined by a call to DSYTRD with UPLO = 'U' */
+
+	i__2 = nq - 1;
+	igraphdormql_(side, trans, &mi, &ni, &i__2, &a[(a_dim1 << 1) + 1], lda, &
+		tau[1], &c__[c_offset], ldc, &work[1], lwork, &iinfo);
+    } else {
+
+/*        Q was determined by a call to DSYTRD with UPLO = 'L' */
+
+	if (left) {
+	    i1 = 2;
+	    i2 = 1;
+	} else {
+	    i1 = 1;
+	    i2 = 2;
+	}
+	i__2 = nq - 1;
+	igraphdormqr_(side, trans, &mi, &ni, &i__2, &a[a_dim1 + 2], lda, &tau[1], &
+		c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo);
+    }
+    work[1] = (doublereal) lwkopt;
+    return 0;
+
+/*     End of DORMTR */
+
+} /* igraphdormtr_ */
+
diff --git a/src/lapack/drot.c b/src/lapack/drot.c
new file mode 100644
index 0000000..5ef66a5
--- /dev/null
+++ b/src/lapack/drot.c
@@ -0,0 +1,81 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdrot_(integer *n, doublereal *dx, integer *incx, 
+	doublereal *dy, integer *incy, doublereal *c__, doublereal *s)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Local variables */
+    integer i__, ix, iy;
+    doublereal dtemp;
+
+
+/*  Purpose   
+    =======   
+
+       DROT applies a plane rotation.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dy;
+    --dx;
+
+    /* Function Body */
+    if (*n <= 0) {
+	return 0;
+    }
+    if (*incx == 1 && *incy == 1) {
+
+/*       code for both increments equal to 1 */
+
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    dtemp = *c__ * dx[i__] + *s * dy[i__];
+	    dy[i__] = *c__ * dy[i__] - *s * dx[i__];
+	    dx[i__] = dtemp;
+	}
+    } else {
+
+/*       code for unequal increments or equal increments not equal   
+           to 1 */
+
+	ix = 1;
+	iy = 1;
+	if (*incx < 0) {
+	    ix = (-(*n) + 1) * *incx + 1;
+	}
+	if (*incy < 0) {
+	    iy = (-(*n) + 1) * *incy + 1;
+	}
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    dtemp = *c__ * dx[ix] + *s * dy[iy];
+	    dy[iy] = *c__ * dy[iy] - *s * dx[ix];
+	    dx[ix] = dtemp;
+	    ix += *incx;
+	    iy += *incy;
+	}
+    }
+    return 0;
+} /* igraphdrot_ */
+
diff --git a/src/lapack/dsaitr.c b/src/lapack/dsaitr.c
new file mode 100644
index 0000000..2dfddb4
--- /dev/null
+++ b/src/lapack/dsaitr.c
@@ -0,0 +1,950 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static logical c_false = FALSE_;
+static doublereal c_b24 = 1.;
+static doublereal c_b49 = 0.;
+static doublereal c_b57 = -1.;
+static integer c__2 = 2;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsaitr   
+
+   \Description:   
+    Reverse communication interface for applying NP additional steps to   
+    a K step symmetric Arnoldi factorization.   
+
+    Input:  OP*V_{k}  -  V_{k}*H = r_{k}*e_{k}^T   
+
+            with (V_{k}^T)*B*V_{k} = I, (V_{k}^T)*B*r_{k} = 0.   
+
+    Output: OP*V_{k+p}  -  V_{k+p}*H = r_{k+p}*e_{k+p}^T   
+
+            with (V_{k+p}^T)*B*V_{k+p} = I, (V_{k+p}^T)*B*r_{k+p} = 0.   
+
+    where OP and B are as in dsaupd.  The B-norm of r_{k+p} is also   
+    computed and returned.   
+
+   \Usage:   
+    call dsaitr   
+       ( IDO, BMAT, N, K, NP, MODE, RESID, RNORM, V, LDV, H, LDH,   
+         IPNTR, WORKD, INFO )   
+
+   \Arguments   
+    IDO     Integer.  (INPUT/OUTPUT)   
+            Reverse communication flag.   
+            -------------------------------------------------------------   
+            IDO =  0: first call to the reverse communication interface   
+            IDO = -1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORK for X,   
+                      IPNTR(2) is the pointer into WORK for Y.   
+                      This is for the restart phase to force the new   
+                      starting vector into the range of OP.   
+            IDO =  1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORK for X,   
+                      IPNTR(2) is the pointer into WORK for Y,   
+                      IPNTR(3) is the pointer into WORK for B * X.   
+            IDO =  2: compute  Y = B * X  where   
+                      IPNTR(1) is the pointer into WORK for X,   
+                      IPNTR(2) is the pointer into WORK for Y.   
+            IDO = 99: done   
+            -------------------------------------------------------------   
+            When the routine is used in the "shift-and-invert" mode, the   
+            vector B * Q is already available and does not need to be   
+            recomputed in forming OP * Q.   
+
+    BMAT    Character*1.  (INPUT)   
+            BMAT specifies the type of matrix B that defines the   
+            semi-inner product for the operator OP.  See dsaupd.   
+            B = 'I' -> standard eigenvalue problem A*x = lambda*x   
+            B = 'G' -> generalized eigenvalue problem A*x = lambda*M*x   
+
+    N       Integer.  (INPUT)   
+            Dimension of the eigenproblem.   
+
+    K       Integer.  (INPUT)   
+            Current order of H and the number of columns of V.   
+
+    NP      Integer.  (INPUT)   
+            Number of additional Arnoldi steps to take.   
+
+    MODE    Integer.  (INPUT)   
+            Signifies which form for "OP". If MODE=2 then   
+            a reduction in the number of B matrix vector multiplies   
+            is possible since the B-norm of OP*x is equivalent to   
+            the inv(B)-norm of A*x.   
+
+    RESID   Double precision array of length N.  (INPUT/OUTPUT)   
+            On INPUT:  RESID contains the residual vector r_{k}.   
+            On OUTPUT: RESID contains the residual vector r_{k+p}.   
+
+    RNORM   Double precision scalar.  (INPUT/OUTPUT)   
+            On INPUT the B-norm of r_{k}.   
+            On OUTPUT the B-norm of the updated residual r_{k+p}.   
+
+    V       Double precision N by K+NP array.  (INPUT/OUTPUT)   
+            On INPUT:  V contains the Arnoldi vectors in the first K   
+            columns.   
+            On OUTPUT: V contains the new NP Arnoldi vectors in the next   
+            NP columns.  The first K columns are unchanged.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    H       Double precision (K+NP) by 2 array.  (INPUT/OUTPUT)   
+            H is used to store the generated symmetric tridiagonal matrix   
+            with the subdiagonal in the first column starting at H(2,1)   
+            and the main diagonal in the second column.   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    IPNTR   Integer array of length 3.  (OUTPUT)   
+            Pointer to mark the starting locations in the WORK for   
+            vectors used by the Arnoldi iteration.   
+            -------------------------------------------------------------   
+            IPNTR(1): pointer to the current operand vector X.   
+            IPNTR(2): pointer to the current result vector Y.   
+            IPNTR(3): pointer to the vector B * X when used in the   
+                      shift-and-invert mode.  X is the current operand.   
+            -------------------------------------------------------------   
+
+    WORKD   Double precision work array of length 3*N.  (REVERSE COMMUNICATION)   
+            Distributed array to be used in the basic Arnoldi iteration   
+            for reverse communication.  The calling program should not   
+            use WORKD as temporary workspace during the iteration !!!!!!   
+            On INPUT, WORKD(1:N) = B*RESID where RESID is associated   
+            with the K step Arnoldi factorization. Used to save some   
+            computation at the first step.   
+            On OUTPUT, WORKD(1:N) = B*RESID where RESID is associated   
+            with the K+NP step Arnoldi factorization.   
+
+    INFO    Integer.  (OUTPUT)   
+            = 0: Normal exit.   
+            > 0: Size of an invariant subspace of OP is found that is   
+                 less than K + NP.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       dgetv0  ARPACK routine to generate the initial vector.   
+       ivout   ARPACK utility routine that prints integers.   
+       dmout   ARPACK utility routine that prints matrices.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlascl  LAPACK routine for careful scaling of a matrix.   
+       dgemv   Level 2 BLAS routine for matrix vector multiplication.   
+       daxpy   Level 1 BLAS that computes a vector triad.   
+       dscal   Level 1 BLAS that scales a vector.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       ddot    Level 1 BLAS that computes the scalar product of two vectors.   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/93: Version ' 2.4'   
+
+   \SCCS Information: @(#)   
+   FILE: saitr.F   SID: 2.6   DATE OF SID: 8/28/96   RELEASE: 2   
+
+   \Remarks   
+    The algorithm implemented is:   
+
+    restart = .false.   
+    Given V_{k} = [v_{1}, ..., v_{k}], r_{k};   
+    r_{k} contains the initial residual vector even for k = 0;   
+    Also assume that rnorm = || B*r_{k} || and B*r_{k} are already   
+    computed by the calling program.   
+
+    betaj = rnorm ; p_{k+1} = B*r_{k} ;   
+    For  j = k+1, ..., k+np  Do   
+       1) if ( betaj < tol ) stop or restart depending on j.   
+          if ( restart ) generate a new starting vector.   
+       2) v_{j} = r(j-1)/betaj;  V_{j} = [V_{j-1}, v_{j}];   
+          p_{j} = p_{j}/betaj   
+       3) r_{j} = OP*v_{j} where OP is defined as in dsaupd   
+          For shift-invert mode p_{j} = B*v_{j} is already available.   
+          wnorm = || OP*v_{j} ||   
+       4) Compute the j-th step residual vector.   
+          w_{j} =  V_{j}^T * B * OP * v_{j}   
+          r_{j} =  OP*v_{j} - V_{j} * w_{j}   
+          alphaj <- j-th component of w_{j}   
+          rnorm = || r_{j} ||   
+          betaj+1 = rnorm   
+          If (rnorm > 0.717*wnorm) accept step and go back to 1)   
+       5) Re-orthogonalization step:   
+          s = V_{j}'*B*r_{j}   
+          r_{j} = r_{j} - V_{j}*s;  rnorm1 = || r_{j} ||   
+          alphaj = alphaj + s_{j};   
+       6) Iterative refinement step:   
+          If (rnorm1 > 0.717*rnorm) then   
+             rnorm = rnorm1   
+             accept step and go back to 1)   
+          Else   
+             rnorm = rnorm1   
+             If this is the first time in step 6), go to 5)   
+             Else r_{j} lies in the span of V_{j} numerically.   
+                Set r_{j} = 0 and rnorm = 0; go to 1)   
+          EndIf   
+    End Do   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsaitr_(integer *ido, char *bmat, integer *n, integer *k,
+	 integer *np, integer *mode, doublereal *resid, doublereal *rnorm, 
+	doublereal *v, integer *ldv, doublereal *h__, integer *ldh, integer *
+	ipntr, doublereal *workd, integer *info)
+{
+    /* Initialized data */
+
+    IGRAPH_F77_SAVE logical first = TRUE_;
+
+    /* System generated locals */
+    integer h_dim1, h_offset, v_dim1, v_offset, i__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__;
+    IGRAPH_F77_SAVE integer j;
+    real t0, t1, t2, t3, t4, t5;
+    integer jj;
+    IGRAPH_F77_SAVE integer ipj, irj;
+    integer nbx;
+    IGRAPH_F77_SAVE integer ivj;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    IGRAPH_F77_SAVE integer ierr, iter;
+    integer nopx;
+    IGRAPH_F77_SAVE integer itry;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    doublereal temp1;
+    IGRAPH_F77_SAVE logical orth1, orth2, step3, step4;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *), igraphdgemv_(char *, integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *);
+    integer infol;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    doublereal xtemp[2];
+    real tmvbx;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen);
+    IGRAPH_F77_SAVE doublereal wnorm;
+    extern /* Subroutine */ int igraphivout_(integer *, integer *, integer *, 
+	    integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *, 
+	    logical *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *);
+    IGRAPH_F77_SAVE doublereal rnorm1;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlascl_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *), igraphsecond_(real *);
+    integer logfil=0;
+    IGRAPH_F77_SAVE doublereal safmin;
+    integer ndigit, nitref;
+    real titref;
+    integer msaitr=0;
+    IGRAPH_F77_SAVE integer msglvl;
+    real tsaitr;
+    integer nrorth;
+    IGRAPH_F77_SAVE logical rstart;
+    integer nrstrt;
+    real tmvopx;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %-----------------------%   
+       | Local Array Arguments |   
+       %-----------------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %-----------------%   
+       | Data statements |   
+       %-----------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    --ipntr;
+
+    /* Function Body   
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    if (first) {
+	first = FALSE_;
+
+/*        %--------------------------------%   
+          | safmin = safe minimum is such  |   
+          | that 1/sfmin does not overflow |   
+          %--------------------------------% */
+
+	safmin = igraphdlamch_("safmin");
+    }
+
+    if (*ido == 0) {
+
+/*        %-------------------------------%   
+          | Initialize timing statistics  |   
+          | & message level for debugging |   
+          %-------------------------------% */
+
+	igraphsecond_(&t0);
+	msglvl = msaitr;
+
+/*        %------------------------------%   
+          | Initial call to this routine |   
+          %------------------------------% */
+
+	*info = 0;
+	step3 = FALSE_;
+	step4 = FALSE_;
+	rstart = FALSE_;
+	orth1 = FALSE_;
+	orth2 = FALSE_;
+
+/*        %--------------------------------%   
+          | Pointer to the current step of |   
+          | the factorization to build     |   
+          %--------------------------------% */
+
+	j = *k + 1;
+
+/*        %------------------------------------------%   
+          | Pointers used for reverse communication  |   
+          | when using WORKD.                        |   
+          %------------------------------------------% */
+
+	ipj = 1;
+	irj = ipj + *n;
+	ivj = irj + *n;
+    }
+
+/*     %-------------------------------------------------%   
+       | When in reverse communication mode one of:      |   
+       | STEP3, STEP4, ORTH1, ORTH2, RSTART              |   
+       | will be .true.                                  |   
+       | STEP3: return from computing OP*v_{j}.          |   
+       | STEP4: return from computing B-norm of OP*v_{j} |   
+       | ORTH1: return from computing B-norm of r_{j+1}  |   
+       | ORTH2: return from computing B-norm of          |   
+       |        correction to the residual vector.       |   
+       | RSTART: return from OP computations needed by   |   
+       |         dgetv0.                                 |   
+       %-------------------------------------------------% */
+
+    if (step3) {
+	goto L50;
+    }
+    if (step4) {
+	goto L60;
+    }
+    if (orth1) {
+	goto L70;
+    }
+    if (orth2) {
+	goto L90;
+    }
+    if (rstart) {
+	goto L30;
+    }
+
+/*     %------------------------------%   
+       | Else this is the first step. |   
+       %------------------------------%   
+
+       %--------------------------------------------------------------%   
+       |                                                              |   
+       |        A R N O L D I     I T E R A T I O N     L O O P       |   
+       |                                                              |   
+       | Note:  B*r_{j-1} is already in WORKD(1:N)=WORKD(IPJ:IPJ+N-1) |   
+       %--------------------------------------------------------------% */
+
+L1000:
+
+    if (msglvl > 2) {
+	igraphivout_(&logfil, &c__1, &j, &ndigit, "_saitr: generating Arnoldi vect"
+		"or no.", (ftnlen)37);
+	igraphdvout_(&logfil, &c__1, rnorm, &ndigit, "_saitr: B-norm of the curren"
+		"t residual =", (ftnlen)40);
+    }
+
+/*        %---------------------------------------------------------%   
+          | Check for exact zero. Equivalent to determing whether a |   
+          | j-step Arnoldi factorization is present.                |   
+          %---------------------------------------------------------% */
+
+    if (*rnorm > 0.) {
+	goto L40;
+    }
+
+/*           %---------------------------------------------------%   
+             | Invariant subspace found, generate a new starting |   
+             | vector which is orthogonal to the current Arnoldi |   
+             | basis and continue the iteration.                 |   
+             %---------------------------------------------------% */
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &j, &ndigit, "_saitr: ****** restart at step "
+		"******", (ftnlen)37);
+    }
+
+/*           %---------------------------------------------%   
+             | ITRY is the loop variable that controls the |   
+             | maximum amount of times that a restart is   |   
+             | attempted. NRSTRT is used by stat.h         |   
+             %---------------------------------------------% */
+
+    ++nrstrt;
+    itry = 1;
+L20:
+    rstart = TRUE_;
+    *ido = 0;
+L30:
+
+/*           %--------------------------------------%   
+             | If in reverse communication mode and |   
+             | RSTART = .true. flow returns here.   |   
+             %--------------------------------------% */
+
+    igraphdgetv0_(ido, bmat, &itry, &c_false, n, &j, &v[v_offset], ldv, &resid[1], 
+	    rnorm, &ipntr[1], &workd[1], &ierr);
+    if (*ido != 99) {
+	goto L9000;
+    }
+    if (ierr < 0) {
+	++itry;
+	if (itry <= 3) {
+	    goto L20;
+	}
+
+/*              %------------------------------------------------%   
+                | Give up after several restart attempts.        |   
+                | Set INFO to the size of the invariant subspace |   
+                | which spans OP and exit.                       |   
+                %------------------------------------------------% */
+
+	*info = j - 1;
+	igraphsecond_(&t1);
+	tsaitr += t1 - t0;
+	*ido = 99;
+	goto L9000;
+    }
+
+L40:
+
+/*        %---------------------------------------------------------%   
+          | STEP 2:  v_{j} = r_{j-1}/rnorm and p_{j} = p_{j}/rnorm  |   
+          | Note that p_{j} = B*r_{j-1}. In order to avoid overflow |   
+          | when reciprocating a small RNORM, test against lower    |   
+          | machine bound.                                          |   
+          %---------------------------------------------------------% */
+
+    igraphdcopy_(n, &resid[1], &c__1, &v[j * v_dim1 + 1], &c__1);
+    if (*rnorm >= safmin) {
+	temp1 = 1. / *rnorm;
+	igraphdscal_(n, &temp1, &v[j * v_dim1 + 1], &c__1);
+	igraphdscal_(n, &temp1, &workd[ipj], &c__1);
+    } else {
+
+/*            %-----------------------------------------%   
+              | To scale both v_{j} and p_{j} carefully |   
+              | use LAPACK routine SLASCL               |   
+              %-----------------------------------------% */
+
+	igraphdlascl_("General", &i__, &i__, rnorm, &c_b24, n, &c__1, &v[j * v_dim1 
+		+ 1], n, &infol);
+	igraphdlascl_("General", &i__, &i__, rnorm, &c_b24, n, &c__1, &workd[ipj], 
+		n, &infol);
+    }
+
+/*        %------------------------------------------------------%   
+          | STEP 3:  r_{j} = OP*v_{j}; Note that p_{j} = B*v_{j} |   
+          | Note that this is not quite yet r_{j}. See STEP 4    |   
+          %------------------------------------------------------% */
+
+    step3 = TRUE_;
+    ++nopx;
+    igraphsecond_(&t2);
+    igraphdcopy_(n, &v[j * v_dim1 + 1], &c__1, &workd[ivj], &c__1);
+    ipntr[1] = ivj;
+    ipntr[2] = irj;
+    ipntr[3] = ipj;
+    *ido = 1;
+
+/*        %-----------------------------------%   
+          | Exit in order to compute OP*v_{j} |   
+          %-----------------------------------% */
+
+    goto L9000;
+L50:
+
+/*        %-----------------------------------%   
+          | Back from reverse communication;  |   
+          | WORKD(IRJ:IRJ+N-1) := OP*v_{j}.   |   
+          %-----------------------------------% */
+
+    igraphsecond_(&t3);
+    tmvopx += t3 - t2;
+
+    step3 = FALSE_;
+
+/*        %------------------------------------------%   
+          | Put another copy of OP*v_{j} into RESID. |   
+          %------------------------------------------% */
+
+    igraphdcopy_(n, &workd[irj], &c__1, &resid[1], &c__1);
+
+/*        %-------------------------------------------%   
+          | STEP 4:  Finish extending the symmetric   |   
+          |          Arnoldi to length j. If MODE = 2 |   
+          |          then B*OP = B*inv(B)*A = A and   |   
+          |          we don't need to compute B*OP.   |   
+          | NOTE: If MODE = 2 WORKD(IVJ:IVJ+N-1) is   |   
+          | assumed to have A*v_{j}.                  |   
+          %-------------------------------------------% */
+
+    if (*mode == 2) {
+	goto L65;
+    }
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	step4 = TRUE_;
+	ipntr[1] = irj;
+	ipntr[2] = ipj;
+	*ido = 2;
+
+/*           %-------------------------------------%   
+             | Exit in order to compute B*OP*v_{j} |   
+             %-------------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+    }
+L60:
+
+/*        %-----------------------------------%   
+          | Back from reverse communication;  |   
+          | WORKD(IPJ:IPJ+N-1) := B*OP*v_{j}. |   
+          %-----------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    step4 = FALSE_;
+
+/*        %-------------------------------------%   
+          | The following is needed for STEP 5. |   
+          | Compute the B-norm of OP*v_{j}.     |   
+          %-------------------------------------% */
+
+L65:
+    if (*mode == 2) {
+
+/*           %----------------------------------%   
+             | Note that the B-norm of OP*v_{j} |   
+             | is the inv(B)-norm of A*v_{j}.   |   
+             %----------------------------------% */
+
+	wnorm = igraphddot_(n, &resid[1], &c__1, &workd[ivj], &c__1);
+	wnorm = sqrt((abs(wnorm)));
+    } else if (*(unsigned char *)bmat == 'G') {
+	wnorm = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+	wnorm = sqrt((abs(wnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	wnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+/*        %-----------------------------------------%   
+          | Compute the j-th residual corresponding |   
+          | to the j step factorization.            |   
+          | Use Classical Gram Schmidt and compute: |   
+          | w_{j} <-  V_{j}^T * B * OP * v_{j}      |   
+          | r_{j} <-  OP*v_{j} - V_{j} * w_{j}      |   
+          %-----------------------------------------%   
+
+
+          %------------------------------------------%   
+          | Compute the j Fourier coefficients w_{j} |   
+          | WORKD(IPJ:IPJ+N-1) contains B*OP*v_{j}.  |   
+          %------------------------------------------% */
+
+    if (*mode != 2) {
+	igraphdgemv_("T", n, &j, &c_b24, &v[v_offset], ldv, &workd[ipj], &c__1, &
+		c_b49, &workd[irj], &c__1);
+    } else if (*mode == 2) {
+	igraphdgemv_("T", n, &j, &c_b24, &v[v_offset], ldv, &workd[ivj], &c__1, &
+		c_b49, &workd[irj], &c__1);
+    }
+
+/*        %--------------------------------------%   
+          | Orthgonalize r_{j} against V_{j}.    |   
+          | RESID contains OP*v_{j}. See STEP 3. |   
+          %--------------------------------------% */
+
+    igraphdgemv_("N", n, &j, &c_b57, &v[v_offset], ldv, &workd[irj], &c__1, &c_b24, 
+	    &resid[1], &c__1);
+
+/*        %--------------------------------------%   
+          | Extend H to have j rows and columns. |   
+          %--------------------------------------% */
+
+    h__[j + (h_dim1 << 1)] = workd[irj + j - 1];
+    if (j == 1 || rstart) {
+	h__[j + h_dim1] = 0.;
+    } else {
+	h__[j + h_dim1] = *rnorm;
+    }
+    igraphsecond_(&t4);
+
+    orth1 = TRUE_;
+    iter = 0;
+
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[irj], &c__1);
+	ipntr[1] = irj;
+	ipntr[2] = ipj;
+	*ido = 2;
+
+/*           %----------------------------------%   
+             | Exit in order to compute B*r_{j} |   
+             %----------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+    }
+L70:
+
+/*        %---------------------------------------------------%   
+          | Back from reverse communication if ORTH1 = .true. |   
+          | WORKD(IPJ:IPJ+N-1) := B*r_{j}.                    |   
+          %---------------------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    orth1 = FALSE_;
+
+/*        %------------------------------%   
+          | Compute the B-norm of r_{j}. |   
+          %------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	*rnorm = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+	*rnorm = sqrt((abs(*rnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	*rnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+/*        %-----------------------------------------------------------%   
+          | STEP 5: Re-orthogonalization / Iterative refinement phase |   
+          | Maximum NITER_ITREF tries.                                |   
+          |                                                           |   
+          |          s      = V_{j}^T * B * r_{j}                     |   
+          |          r_{j}  = r_{j} - V_{j}*s                         |   
+          |          alphaj = alphaj + s_{j}                          |   
+          |                                                           |   
+          | The stopping criteria used for iterative refinement is    |   
+          | discussed in Parlett's book SEP, page 107 and in Gragg &  |   
+          | Reichel ACM TOMS paper; Algorithm 686, Dec. 1990.         |   
+          | Determine if we need to correct the residual. The goal is |   
+          | to enforce ||v(:,1:j)^T * r_{j}|| .le. eps * || r_{j} ||  |   
+          %-----------------------------------------------------------% */
+
+    if (*rnorm > wnorm * .717f) {
+	goto L100;
+    }
+    ++nrorth;
+
+/*        %---------------------------------------------------%   
+          | Enter the Iterative refinement phase. If further  |   
+          | refinement is necessary, loop back here. The loop |   
+          | variable is ITER. Perform a step of Classical     |   
+          | Gram-Schmidt using all the Arnoldi vectors V_{j}  |   
+          %---------------------------------------------------% */
+
+L80:
+
+    if (msglvl > 2) {
+	xtemp[0] = wnorm;
+	xtemp[1] = *rnorm;
+	igraphdvout_(&logfil, &c__2, xtemp, &ndigit, "_saitr: re-orthonalization ;"
+		" wnorm and rnorm are", (ftnlen)48);
+    }
+
+/*        %----------------------------------------------------%   
+          | Compute V_{j}^T * B * r_{j}.                       |   
+          | WORKD(IRJ:IRJ+J-1) = v(:,1:J)'*WORKD(IPJ:IPJ+N-1). |   
+          %----------------------------------------------------% */
+
+    igraphdgemv_("T", n, &j, &c_b24, &v[v_offset], ldv, &workd[ipj], &c__1, &c_b49, 
+	    &workd[irj], &c__1);
+
+/*        %----------------------------------------------%   
+          | Compute the correction to the residual:      |   
+          | r_{j} = r_{j} - V_{j} * WORKD(IRJ:IRJ+J-1).  |   
+          | The correction to H is v(:,1:J)*H(1:J,1:J) + |   
+          | v(:,1:J)*WORKD(IRJ:IRJ+J-1)*e'_j, but only   |   
+          | H(j,j) is updated.                           |   
+          %----------------------------------------------% */
+
+    igraphdgemv_("N", n, &j, &c_b57, &v[v_offset], ldv, &workd[irj], &c__1, &c_b24, 
+	    &resid[1], &c__1);
+
+    if (j == 1 || rstart) {
+	h__[j + h_dim1] = 0.;
+    }
+    h__[j + (h_dim1 << 1)] += workd[irj + j - 1];
+
+    orth2 = TRUE_;
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[irj], &c__1);
+	ipntr[1] = irj;
+	ipntr[2] = ipj;
+	*ido = 2;
+
+/*           %-----------------------------------%   
+             | Exit in order to compute B*r_{j}. |   
+             | r_{j} is the corrected residual.  |   
+             %-----------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+    }
+L90:
+
+/*        %---------------------------------------------------%   
+          | Back from reverse communication if ORTH2 = .true. |   
+          %---------------------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+/*        %-----------------------------------------------------%   
+          | Compute the B-norm of the corrected residual r_{j}. |   
+          %-----------------------------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	rnorm1 = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1);
+	rnorm1 = sqrt((abs(rnorm1)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	rnorm1 = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+
+    if (msglvl > 0 && iter > 0) {
+	igraphivout_(&logfil, &c__1, &j, &ndigit, "_saitr: Iterative refinement fo"
+		"r Arnoldi residual", (ftnlen)49);
+	if (msglvl > 2) {
+	    xtemp[0] = *rnorm;
+	    xtemp[1] = rnorm1;
+	    igraphdvout_(&logfil, &c__2, xtemp, &ndigit, "_saitr: iterative refine"
+		    "ment ; rnorm and rnorm1 are", (ftnlen)51);
+	}
+    }
+
+/*        %-----------------------------------------%   
+          | Determine if we need to perform another |   
+          | step of re-orthogonalization.           |   
+          %-----------------------------------------% */
+
+    if (rnorm1 > *rnorm * .717f) {
+
+/*           %--------------------------------%   
+             | No need for further refinement |   
+             %--------------------------------% */
+
+	*rnorm = rnorm1;
+
+    } else {
+
+/*           %-------------------------------------------%   
+             | Another step of iterative refinement step |   
+             | is required. NITREF is used by stat.h     |   
+             %-------------------------------------------% */
+
+	++nitref;
+	*rnorm = rnorm1;
+	++iter;
+	if (iter <= 1) {
+	    goto L80;
+	}
+
+/*           %-------------------------------------------------%   
+             | Otherwise RESID is numerically in the span of V |   
+             %-------------------------------------------------% */
+
+	i__1 = *n;
+	for (jj = 1; jj <= i__1; ++jj) {
+	    resid[jj] = 0.;
+/* L95: */
+	}
+	*rnorm = 0.;
+    }
+
+/*        %----------------------------------------------%   
+          | Branch here directly if iterative refinement |   
+          | wasn't necessary or after at most NITER_REF  |   
+          | steps of iterative refinement.               |   
+          %----------------------------------------------% */
+
+L100:
+
+    rstart = FALSE_;
+    orth2 = FALSE_;
+
+    igraphsecond_(&t5);
+    titref += t5 - t4;
+
+/*        %----------------------------------------------------------%   
+          | Make sure the last off-diagonal element is non negative  |   
+          | If not perform a similarity transformation on H(1:j,1:j) |   
+          | and scale v(:,j) by -1.                                  |   
+          %----------------------------------------------------------% */
+
+    if (h__[j + h_dim1] < 0.) {
+	h__[j + h_dim1] = -h__[j + h_dim1];
+	if (j < *k + *np) {
+	    igraphdscal_(n, &c_b57, &v[(j + 1) * v_dim1 + 1], &c__1);
+	} else {
+	    igraphdscal_(n, &c_b57, &resid[1], &c__1);
+	}
+    }
+
+/*        %------------------------------------%   
+          | STEP 6: Update  j = j+1;  Continue |   
+          %------------------------------------% */
+
+    ++j;
+    if (j > *k + *np) {
+	igraphsecond_(&t1);
+	tsaitr += t1 - t0;
+	*ido = 99;
+
+	if (msglvl > 1) {
+	    i__1 = *k + *np;
+	    igraphdvout_(&logfil, &i__1, &h__[(h_dim1 << 1) + 1], &ndigit, "_saitr"
+		    ": main diagonal of matrix H of step K+NP.", (ftnlen)47);
+	    if (*k + *np > 1) {
+		i__1 = *k + *np - 1;
+		igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_saitr: s"
+			"ub diagonal of matrix H of step K+NP.", (ftnlen)46);
+	    }
+	}
+
+	goto L9000;
+    }
+
+/*        %--------------------------------------------------------%   
+          | Loop back to extend the factorization by another step. |   
+          %--------------------------------------------------------% */
+
+    goto L1000;
+
+/*     %---------------------------------------------------------------%   
+       |                                                               |   
+       |  E N D     O F     M A I N     I T E R A T I O N     L O O P  |   
+       |                                                               |   
+       %---------------------------------------------------------------% */
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dsaitr |   
+       %---------------% */
+
+} /* igraphdsaitr_ */
+
diff --git a/src/lapack/dsapps.c b/src/lapack/dsapps.c
new file mode 100644
index 0000000..40b5e05
--- /dev/null
+++ b/src/lapack/dsapps.c
@@ -0,0 +1,621 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b4 = 0.;
+static doublereal c_b5 = 1.;
+static integer c__1 = 1;
+static doublereal c_b20 = -1.;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsapps   
+
+   \Description:   
+    Given the Arnoldi factorization   
+
+       A*V_{k} - V_{k}*H_{k} = r_{k+p}*e_{k+p}^T,   
+
+    apply NP shifts implicitly resulting in   
+
+       A*(V_{k}*Q) - (V_{k}*Q)*(Q^T* H_{k}*Q) = r_{k+p}*e_{k+p}^T * Q   
+
+    where Q is an orthogonal matrix of order KEV+NP. Q is the product of   
+    rotations resulting from the NP bulge chasing sweeps.  The updated Arnoldi   
+    factorization becomes:   
+
+       A*VNEW_{k} - VNEW_{k}*HNEW_{k} = rnew_{k}*e_{k}^T.   
+
+   \Usage:   
+    call dsapps   
+       ( N, KEV, NP, SHIFT, V, LDV, H, LDH, RESID, Q, LDQ, WORKD )   
+
+   \Arguments   
+    N       Integer.  (INPUT)   
+            Problem size, i.e. dimension of matrix A.   
+
+    KEV     Integer.  (INPUT)   
+            INPUT: KEV+NP is the size of the input matrix H.   
+            OUTPUT: KEV is the size of the updated matrix HNEW.   
+
+    NP      Integer.  (INPUT)   
+            Number of implicit shifts to be applied.   
+
+    SHIFT   Double precision array of length NP.  (INPUT)   
+            The shifts to be applied.   
+
+    V       Double precision N by (KEV+NP) array.  (INPUT/OUTPUT)   
+            INPUT: V contains the current KEV+NP Arnoldi vectors.   
+            OUTPUT: VNEW = V(1:n,1:KEV); the updated Arnoldi vectors   
+            are in the first KEV columns of V.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    H       Double precision (KEV+NP) by 2 array.  (INPUT/OUTPUT)   
+            INPUT: H contains the symmetric tridiagonal matrix of the   
+            Arnoldi factorization with the subdiagonal in the 1st column   
+            starting at H(2,1) and the main diagonal in the 2nd column.   
+            OUTPUT: H contains the updated tridiagonal matrix in the   
+            KEV leading submatrix.   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    RESID   Double precision array of length (N).  (INPUT/OUTPUT)   
+            INPUT: RESID contains the the residual vector r_{k+p}.   
+            OUTPUT: RESID is the updated residual vector rnew_{k}.   
+
+    Q       Double precision KEV+NP by KEV+NP work array.  (WORKSPACE)   
+            Work array used to accumulate the rotations during the bulge   
+            chase sweep.   
+
+    LDQ     Integer.  (INPUT)   
+            Leading dimension of Q exactly as declared in the calling   
+            program.   
+
+    WORKD   Double precision work array of length 2*N.  (WORKSPACE)   
+            Distributed array used in the application of the accumulated   
+            orthogonal matrix Q.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+
+   \Routines called:   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlartg  LAPACK Givens rotation construction routine.   
+       dlacpy  LAPACK matrix copy routine.   
+       dlaset  LAPACK matrix initialization routine.   
+       dgemv   Level 2 BLAS routine for matrix vector multiplication.   
+       daxpy   Level 1 BLAS that computes a vector triad.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+       dscal   Level 1 BLAS that scales a vector.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/16/93: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: sapps.F   SID: 2.5   DATE OF SID: 4/19/96   RELEASE: 2   
+
+   \Remarks   
+    1. In this version, each shift is applied to all the subblocks of   
+       the tridiagonal matrix H and not just to the submatrix that it   
+       comes from. This routine assumes that the subdiagonal elements   
+       of H that are stored in h(1:kev+np,1) are nonegative upon input   
+       and enforce this condition upon output. This version incorporates   
+       deflation. See code for documentation.   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsapps_(integer *n, integer *kev, integer *np, 
+	doublereal *shift, doublereal *v, integer *ldv, doublereal *h__, 
+	integer *ldh, doublereal *resid, doublereal *q, integer *ldq, 
+	doublereal *workd)
+{
+    /* Initialized data */
+
+    IGRAPH_F77_SAVE logical first = TRUE_;
+
+    /* System generated locals */
+    integer h_dim1, h_offset, q_dim1, q_offset, v_dim1, v_offset, i__1, i__2, 
+	    i__3, i__4;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    doublereal c__, f, g;
+    integer i__, j;
+    doublereal r__, s, a1, a2, a3, a4;
+    real t0, t1;
+    integer jj;
+    doublereal big;
+    integer iend, itop;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *), igraphdgemv_(char *, integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *), igraphdcopy_(integer *, doublereal *, 
+	    integer *, doublereal *, integer *), igraphdaxpy_(integer *, doublereal 
+	    *, doublereal *, integer *, doublereal *, integer *), igraphdvout_(
+	    integer *, integer *, doublereal *, integer *, char *, ftnlen), 
+	    igraphivout_(integer *, integer *, integer *, integer *, char *, ftnlen)
+	    ;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphsecond_(real *), igraphdlacpy_(char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *), igraphdlartg_(doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *), igraphdlaset_(char *, integer *, integer *,
+	     doublereal *, doublereal *, doublereal *, integer *);
+    IGRAPH_F77_SAVE doublereal epsmch;
+    integer logfil=0, ndigit, msapps=0, msglvl, istart;
+    real tsapps;
+    integer kplusp;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %----------------------%   
+       | Intrinsics Functions |   
+       %----------------------%   
+
+
+       %----------------%   
+       | Data statments |   
+       %----------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    --shift;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+
+    /* Function Body   
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    if (first) {
+	epsmch = igraphdlamch_("Epsilon-Machine");
+	first = FALSE_;
+    }
+    itop = 1;
+
+/*     %-------------------------------%   
+       | Initialize timing statistics  |   
+       | & message level for debugging |   
+       %-------------------------------% */
+
+    igraphsecond_(&t0);
+    msglvl = msapps;
+
+    kplusp = *kev + *np;
+
+/*     %----------------------------------------------%   
+       | Initialize Q to the identity matrix of order |   
+       | kplusp used to accumulate the rotations.     |   
+       %----------------------------------------------% */
+
+    igraphdlaset_("All", &kplusp, &kplusp, &c_b4, &c_b5, &q[q_offset], ldq);
+
+/*     %----------------------------------------------%   
+       | Quick return if there are no shifts to apply |   
+       %----------------------------------------------% */
+
+    if (*np == 0) {
+	goto L9000;
+    }
+
+/*     %----------------------------------------------------------%   
+       | Apply the np shifts implicitly. Apply each shift to the  |   
+       | whole matrix and not just to the submatrix from which it |   
+       | comes.                                                   |   
+       %----------------------------------------------------------% */
+
+    i__1 = *np;
+    for (jj = 1; jj <= i__1; ++jj) {
+
+	istart = itop;
+
+/*        %----------------------------------------------------------%   
+          | Check for splitting and deflation. Currently we consider |   
+          | an off-diagonal element h(i+1,1) negligible if           |   
+          |         h(i+1,1) .le. epsmch*( |h(i,2)| + |h(i+1,2)| )   |   
+          | for i=1:KEV+NP-1.                                        |   
+          | If above condition tests true then we set h(i+1,1) = 0.  |   
+          | Note that h(1:KEV+NP,1) are assumed to be non negative.  |   
+          %----------------------------------------------------------% */
+
+L20:
+
+/*        %------------------------------------------------%   
+          | The following loop exits early if we encounter |   
+          | a negligible off diagonal element.             |   
+          %------------------------------------------------% */
+
+	i__2 = kplusp - 1;
+	for (i__ = istart; i__ <= i__2; ++i__) {
+	    big = (d__1 = h__[i__ + (h_dim1 << 1)], abs(d__1)) + (d__2 = h__[
+		    i__ + 1 + (h_dim1 << 1)], abs(d__2));
+	    if (h__[i__ + 1 + h_dim1] <= epsmch * big) {
+		if (msglvl > 0) {
+		    igraphivout_(&logfil, &c__1, &i__, &ndigit, "_sapps: deflation"
+			    " at row/column no.", (ftnlen)35);
+		    igraphivout_(&logfil, &c__1, &jj, &ndigit, "_sapps: occured be"
+			    "fore shift number.", (ftnlen)36);
+		    igraphdvout_(&logfil, &c__1, &h__[i__ + 1 + h_dim1], &ndigit, 
+			    "_sapps: the corresponding off diagonal element", 
+			    (ftnlen)46);
+		}
+		h__[i__ + 1 + h_dim1] = 0.;
+		iend = i__;
+		goto L40;
+	    }
+/* L30: */
+	}
+	iend = kplusp;
+L40:
+
+	if (istart < iend) {
+
+/*           %--------------------------------------------------------%   
+             | Construct the plane rotation G'(istart,istart+1,theta) |   
+             | that attempts to drive h(istart+1,1) to zero.          |   
+             %--------------------------------------------------------% */
+
+	    f = h__[istart + (h_dim1 << 1)] - shift[jj];
+	    g = h__[istart + 1 + h_dim1];
+	    igraphdlartg_(&f, &g, &c__, &s, &r__);
+
+/*            %-------------------------------------------------------%   
+              | Apply rotation to the left and right of H;            |   
+              | H <- G' * H * G,  where G = G(istart,istart+1,theta). |   
+              | This will create a "bulge".                           |   
+              %-------------------------------------------------------% */
+
+	    a1 = c__ * h__[istart + (h_dim1 << 1)] + s * h__[istart + 1 + 
+		    h_dim1];
+	    a2 = c__ * h__[istart + 1 + h_dim1] + s * h__[istart + 1 + (
+		    h_dim1 << 1)];
+	    a4 = c__ * h__[istart + 1 + (h_dim1 << 1)] - s * h__[istart + 1 + 
+		    h_dim1];
+	    a3 = c__ * h__[istart + 1 + h_dim1] - s * h__[istart + (h_dim1 << 
+		    1)];
+	    h__[istart + (h_dim1 << 1)] = c__ * a1 + s * a2;
+	    h__[istart + 1 + (h_dim1 << 1)] = c__ * a4 - s * a3;
+	    h__[istart + 1 + h_dim1] = c__ * a3 + s * a4;
+
+/*            %----------------------------------------------------%   
+              | Accumulate the rotation in the matrix Q;  Q <- Q*G |   
+              %----------------------------------------------------%   
+
+   Computing MIN */
+	    i__3 = istart + jj;
+	    i__2 = min(i__3,kplusp);
+	    for (j = 1; j <= i__2; ++j) {
+		a1 = c__ * q[j + istart * q_dim1] + s * q[j + (istart + 1) * 
+			q_dim1];
+		q[j + (istart + 1) * q_dim1] = -s * q[j + istart * q_dim1] + 
+			c__ * q[j + (istart + 1) * q_dim1];
+		q[j + istart * q_dim1] = a1;
+/* L60: */
+	    }
+
+
+/*            %----------------------------------------------%   
+              | The following loop chases the bulge created. |   
+              | Note that the previous rotation may also be  |   
+              | done within the following loop. But it is    |   
+              | kept separate to make the distinction among  |   
+              | the bulge chasing sweeps and the first plane |   
+              | rotation designed to drive h(istart+1,1) to  |   
+              | zero.                                        |   
+              %----------------------------------------------% */
+
+	    i__2 = iend - 1;
+	    for (i__ = istart + 1; i__ <= i__2; ++i__) {
+
+/*               %----------------------------------------------%   
+                 | Construct the plane rotation G'(i,i+1,theta) |   
+                 | that zeros the i-th bulge that was created   |   
+                 | by G(i-1,i,theta). g represents the bulge.   |   
+                 %----------------------------------------------% */
+
+		f = h__[i__ + h_dim1];
+		g = s * h__[i__ + 1 + h_dim1];
+
+/*               %----------------------------------%   
+                 | Final update with G(i-1,i,theta) |   
+                 %----------------------------------% */
+
+		h__[i__ + 1 + h_dim1] = c__ * h__[i__ + 1 + h_dim1];
+		igraphdlartg_(&f, &g, &c__, &s, &r__);
+
+/*               %-------------------------------------------%   
+                 | The following ensures that h(1:iend-1,1), |   
+                 | the first iend-2 off diagonal of elements |   
+                 | H, remain non negative.                   |   
+                 %-------------------------------------------% */
+
+		if (r__ < 0.) {
+		    r__ = -r__;
+		    c__ = -c__;
+		    s = -s;
+		}
+
+/*               %--------------------------------------------%   
+                 | Apply rotation to the left and right of H; |   
+                 | H <- G * H * G',  where G = G(i,i+1,theta) |   
+                 %--------------------------------------------% */
+
+		h__[i__ + h_dim1] = r__;
+
+		a1 = c__ * h__[i__ + (h_dim1 << 1)] + s * h__[i__ + 1 + 
+			h_dim1];
+		a2 = c__ * h__[i__ + 1 + h_dim1] + s * h__[i__ + 1 + (h_dim1 
+			<< 1)];
+		a3 = c__ * h__[i__ + 1 + h_dim1] - s * h__[i__ + (h_dim1 << 1)
+			];
+		a4 = c__ * h__[i__ + 1 + (h_dim1 << 1)] - s * h__[i__ + 1 + 
+			h_dim1];
+
+		h__[i__ + (h_dim1 << 1)] = c__ * a1 + s * a2;
+		h__[i__ + 1 + (h_dim1 << 1)] = c__ * a4 - s * a3;
+		h__[i__ + 1 + h_dim1] = c__ * a3 + s * a4;
+
+/*               %----------------------------------------------------%   
+                 | Accumulate the rotation in the matrix Q;  Q <- Q*G |   
+                 %----------------------------------------------------%   
+
+   Computing MIN */
+		i__4 = j + jj;
+		i__3 = min(i__4,kplusp);
+		for (j = 1; j <= i__3; ++j) {
+		    a1 = c__ * q[j + i__ * q_dim1] + s * q[j + (i__ + 1) * 
+			    q_dim1];
+		    q[j + (i__ + 1) * q_dim1] = -s * q[j + i__ * q_dim1] + 
+			    c__ * q[j + (i__ + 1) * q_dim1];
+		    q[j + i__ * q_dim1] = a1;
+/* L50: */
+		}
+
+/* L70: */
+	    }
+
+	}
+
+/*        %--------------------------%   
+          | Update the block pointer |   
+          %--------------------------% */
+
+	istart = iend + 1;
+
+/*        %------------------------------------------%   
+          | Make sure that h(iend,1) is non-negative |   
+          | If not then set h(iend,1) <-- -h(iend,1) |   
+          | and negate the last column of Q.         |   
+          | We have effectively carried out a        |   
+          | similarity on transformation H           |   
+          %------------------------------------------% */
+
+	if (h__[iend + h_dim1] < 0.) {
+	    h__[iend + h_dim1] = -h__[iend + h_dim1];
+	    igraphdscal_(&kplusp, &c_b20, &q[iend * q_dim1 + 1], &c__1);
+	}
+
+/*        %--------------------------------------------------------%   
+          | Apply the same shift to the next block if there is any |   
+          %--------------------------------------------------------% */
+
+	if (iend < kplusp) {
+	    goto L20;
+	}
+
+/*        %-----------------------------------------------------%   
+          | Check if we can increase the the start of the block |   
+          %-----------------------------------------------------% */
+
+	i__2 = kplusp - 1;
+	for (i__ = itop; i__ <= i__2; ++i__) {
+	    if (h__[i__ + 1 + h_dim1] > 0.) {
+		goto L90;
+	    }
+	    ++itop;
+/* L80: */
+	}
+
+/*        %-----------------------------------%   
+          | Finished applying the jj-th shift |   
+          %-----------------------------------% */
+
+L90:
+	;
+    }
+
+/*     %------------------------------------------%   
+       | All shifts have been applied. Check for  |   
+       | more possible deflation that might occur |   
+       | after the last shift is applied.         |   
+       %------------------------------------------% */
+
+    i__1 = kplusp - 1;
+    for (i__ = itop; i__ <= i__1; ++i__) {
+	big = (d__1 = h__[i__ + (h_dim1 << 1)], abs(d__1)) + (d__2 = h__[i__ 
+		+ 1 + (h_dim1 << 1)], abs(d__2));
+	if (h__[i__ + 1 + h_dim1] <= epsmch * big) {
+	    if (msglvl > 0) {
+		igraphivout_(&logfil, &c__1, &i__, &ndigit, "_sapps: deflation at "
+			"row/column no.", (ftnlen)35);
+		igraphdvout_(&logfil, &c__1, &h__[i__ + 1 + h_dim1], &ndigit, "_sa"
+			"pps: the corresponding off diagonal element", (ftnlen)
+			46);
+	    }
+	    h__[i__ + 1 + h_dim1] = 0.;
+	}
+/* L100: */
+    }
+
+/*     %-------------------------------------------------%   
+       | Compute the (kev+1)-st column of (V*Q) and      |   
+       | temporarily store the result in WORKD(N+1:2*N). |   
+       | This is not necessary if h(kev+1,1) = 0.         |   
+       %-------------------------------------------------% */
+
+    if (h__[*kev + 1 + h_dim1] > 0.) {
+	igraphdgemv_("N", n, &kplusp, &c_b5, &v[v_offset], ldv, &q[(*kev + 1) * 
+		q_dim1 + 1], &c__1, &c_b4, &workd[*n + 1], &c__1);
+    }
+
+/*     %-------------------------------------------------------%   
+       | Compute column 1 to kev of (V*Q) in backward order    |   
+       | taking advantage that Q is an upper triangular matrix |   
+       | with lower bandwidth np.                              |   
+       | Place results in v(:,kplusp-kev:kplusp) temporarily.  |   
+       %-------------------------------------------------------% */
+
+    i__1 = *kev;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	i__2 = kplusp - i__ + 1;
+	igraphdgemv_("N", n, &i__2, &c_b5, &v[v_offset], ldv, &q[(*kev - i__ + 1) * 
+		q_dim1 + 1], &c__1, &c_b4, &workd[1], &c__1);
+	igraphdcopy_(n, &workd[1], &c__1, &v[(kplusp - i__ + 1) * v_dim1 + 1], &
+		c__1);
+/* L130: */
+    }
+
+/*     %-------------------------------------------------%   
+       |  Move v(:,kplusp-kev+1:kplusp) into v(:,1:kev). |   
+       %-------------------------------------------------% */
+
+    igraphdlacpy_("All", n, kev, &v[(*np + 1) * v_dim1 + 1], ldv, &v[v_offset], ldv);
+
+/*     %--------------------------------------------%   
+       | Copy the (kev+1)-st column of (V*Q) in the |   
+       | appropriate place if h(kev+1,1) .ne. zero. |   
+       %--------------------------------------------% */
+
+    if (h__[*kev + 1 + h_dim1] > 0.) {
+	igraphdcopy_(n, &workd[*n + 1], &c__1, &v[(*kev + 1) * v_dim1 + 1], &c__1);
+    }
+
+/*     %-------------------------------------%   
+       | Update the residual vector:         |   
+       |    r <- sigmak*r + betak*v(:,kev+1) |   
+       | where                               |   
+       |    sigmak = (e_{kev+p}'*Q)*e_{kev}  |   
+       |    betak = e_{kev+1}'*H*e_{kev}     |   
+       %-------------------------------------% */
+
+    igraphdscal_(n, &q[kplusp + *kev * q_dim1], &resid[1], &c__1);
+    if (h__[*kev + 1 + h_dim1] > 0.) {
+	igraphdaxpy_(n, &h__[*kev + 1 + h_dim1], &v[(*kev + 1) * v_dim1 + 1], &c__1,
+		 &resid[1], &c__1);
+    }
+
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, &c__1, &q[kplusp + *kev * q_dim1], &ndigit, "_sapps:"
+		" sigmak of the updated residual vector", (ftnlen)45);
+	igraphdvout_(&logfil, &c__1, &h__[*kev + 1 + h_dim1], &ndigit, "_sapps: be"
+		"tak of the updated residual vector", (ftnlen)44);
+	igraphdvout_(&logfil, kev, &h__[(h_dim1 << 1) + 1], &ndigit, "_sapps: upda"
+		"ted main diagonal of H for next iteration", (ftnlen)53);
+	if (*kev > 1) {
+	    i__1 = *kev - 1;
+	    igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_sapps: updat"
+		    "ed sub diagonal of H for next iteration", (ftnlen)52);
+	}
+    }
+
+    igraphsecond_(&t1);
+    tsapps += t1 - t0;
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dsapps |   
+       %---------------% */
+
+} /* igraphdsapps_ */
+
diff --git a/src/lapack/dsaup2.c b/src/lapack/dsaup2.c
new file mode 100644
index 0000000..d8a615f
--- /dev/null
+++ b/src/lapack/dsaup2.c
@@ -0,0 +1,976 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b3 = .66666666666666663;
+static integer c__1 = 1;
+static integer c__0 = 0;
+static integer c__3 = 3;
+static logical c_true = TRUE_;
+static integer c__2 = 2;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsaup2   
+
+   \Description:   
+    Intermediate level interface called by dsaupd.   
+
+   \Usage:   
+    call dsaup2   
+       ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD,   
+         ISHIFT, MXITER, V, LDV, H, LDH, RITZ, BOUNDS, Q, LDQ, WORKL,   
+         IPNTR, WORKD, INFO )   
+
+   \Arguments   
+
+    IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dsaupd.   
+    MODE, ISHIFT, MXITER: see the definition of IPARAM in dsaupd.   
+
+    NP      Integer.  (INPUT/OUTPUT)   
+            Contains the number of implicit shifts to apply during   
+            each Arnoldi/Lanczos iteration.   
+            If ISHIFT=1, NP is adjusted dynamically at each iteration   
+            to accelerate convergence and prevent stagnation.   
+            This is also roughly equal to the number of matrix-vector   
+            products (involving the operator OP) per Arnoldi iteration.   
+            The logic for adjusting is contained within the current   
+            subroutine.   
+            If ISHIFT=0, NP is the number of shifts the user needs   
+            to provide via reverse comunication. 0 < NP < NCV-NEV.   
+            NP may be less than NCV-NEV since a leading block of the current   
+            upper Tridiagonal matrix has split off and contains "unwanted"   
+            Ritz values.   
+            Upon termination of the IRA iteration, NP contains the number   
+            of "converged" wanted Ritz values.   
+
+    IUPD    Integer.  (INPUT)   
+            IUPD .EQ. 0: use explicit restart instead implicit update.   
+            IUPD .NE. 0: use implicit update.   
+
+    V       Double precision N by (NEV+NP) array.  (INPUT/OUTPUT)   
+            The Lanczos basis vectors.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    H       Double precision (NEV+NP) by 2 array.  (OUTPUT)   
+            H is used to store the generated symmetric tridiagonal matrix   
+            The subdiagonal is stored in the first column of H starting   
+            at H(2,1).  The main diagonal is stored in the second column   
+            of H starting at H(1,2). If dsaup2 converges store the   
+            B-norm of the final residual vector in H(1,1).   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    RITZ    Double precision array of length NEV+NP.  (OUTPUT)   
+            RITZ(1:NEV) contains the computed Ritz values of OP.   
+
+    BOUNDS  Double precision array of length NEV+NP.  (OUTPUT)   
+            BOUNDS(1:NEV) contain the error bounds corresponding to RITZ.   
+
+    Q       Double precision (NEV+NP) by (NEV+NP) array.  (WORKSPACE)   
+            Private (replicated) work array used to accumulate the   
+            rotation in the shift application step.   
+
+    LDQ     Integer.  (INPUT)   
+            Leading dimension of Q exactly as declared in the calling   
+            program.   
+
+    WORKL   Double precision array of length at least 3*(NEV+NP).  (INPUT/WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.  It is used in the computation of the   
+            tridiagonal eigenvalue problem, the calculation and   
+            application of the shifts and convergence checking.   
+            If ISHIFT .EQ. O and IDO .EQ. 3, the first NP locations   
+            of WORKL are used in reverse communication to hold the user   
+            supplied shifts.   
+
+    IPNTR   Integer array of length 3.  (OUTPUT)   
+            Pointer to mark the starting locations in the WORKD for   
+            vectors used by the Lanczos iteration.   
+            -------------------------------------------------------------   
+            IPNTR(1): pointer to the current operand vector X.   
+            IPNTR(2): pointer to the current result vector Y.   
+            IPNTR(3): pointer to the vector B * X when used in one of   
+                      the spectral transformation modes.  X is the current   
+                      operand.   
+            -------------------------------------------------------------   
+
+    WORKD   Double precision work array of length 3*N.  (REVERSE COMMUNICATION)   
+            Distributed array to be used in the basic Lanczos iteration   
+            for reverse communication.  The user should not use WORKD   
+            as temporary workspace during the iteration !!!!!!!!!!   
+            See Data Distribution Note in dsaupd.   
+
+    INFO    Integer.  (INPUT/OUTPUT)   
+            If INFO .EQ. 0, a randomly initial residual vector is used.   
+            If INFO .NE. 0, RESID contains the initial residual vector,   
+                            possibly from a previous run.   
+            Error flag on output.   
+            =     0: Normal return.   
+            =     1: All possible eigenvalues of OP has been found.   
+                     NP returns the size of the invariant subspace   
+                     spanning the operator OP.   
+            =     2: No shifts could be applied.   
+            =    -8: Error return from trid. eigenvalue calculation;   
+                     This should never happen.   
+            =    -9: Starting vector is zero.   
+            = -9999: Could not build an Lanczos factorization.   
+                     Size that was built in returned in NP.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+    3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall,   
+       1980.   
+    4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program",   
+       Computer Physics Communications, 53 (1989), pp 169-179.   
+    5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to   
+       Implement the Spectral Transformation", Math. Comp., 48 (1987),   
+       pp 663-673.   
+    6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos   
+       Algorithm for Solving Sparse Symmetric Generalized Eigenproblems",   
+       SIAM J. Matr. Anal. Apps.,  January (1993).   
+    7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines   
+       for Updating the QR decomposition", ACM TOMS, December 1990,   
+       Volume 16 Number 4, pp 369-377.   
+
+   \Routines called:   
+       dgetv0  ARPACK initial vector generation routine.   
+       dsaitr  ARPACK Lanczos factorization routine.   
+       dsapps  ARPACK application of implicit shifts routine.   
+       dsconv  ARPACK convergence of Ritz values routine.   
+       dseigt  ARPACK compute Ritz values and error bounds routine.   
+       dsgets  ARPACK reorder Ritz values and error bounds routine.   
+       dsortr  ARPACK sorting routine.   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+       ddot    Level 1 BLAS that computes the scalar product of two vectors.   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+       dscal   Level 1 BLAS that scales a vector.   
+       dswap   Level 1 BLAS that swaps two vectors.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/15/93: Version ' 2.4'   
+       xx/xx/95: Version ' 2.4'.  (R.B. Lehoucq)   
+
+   \SCCS Information: @(#)   
+   FILE: saup2.F   SID: 2.6   DATE OF SID: 8/16/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsaup2_(integer *ido, char *bmat, integer *n, char *
+	which, integer *nev, integer *np, doublereal *tol, doublereal *resid, 
+	integer *mode, integer *iupd, integer *ishift, integer *mxiter, 
+	doublereal *v, integer *ldv, doublereal *h__, integer *ldh, 
+	doublereal *ritz, doublereal *bounds, doublereal *q, integer *ldq, 
+	doublereal *workl, integer *ipntr, doublereal *workd, integer *info)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, q_dim1, q_offset, v_dim1, v_offset, i__1, i__2, 
+	    i__3;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double pow_dd(doublereal *, doublereal *);
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+    /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer j;
+    real t0, t1, t2, t3;
+    integer kp[3];
+    IGRAPH_F77_SAVE integer np0;
+    integer nbx;
+    IGRAPH_F77_SAVE integer nev0;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    IGRAPH_F77_SAVE doublereal eps23;
+    integer ierr;
+    IGRAPH_F77_SAVE integer iter;
+    doublereal temp;
+    integer nevd2;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    IGRAPH_F77_SAVE logical getv0;
+    integer nevm2;
+    IGRAPH_F77_SAVE logical cnorm;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdswap_(integer *, doublereal *, integer 
+	    *, doublereal *, integer *);
+    IGRAPH_F77_SAVE integer nconv;
+    IGRAPH_F77_SAVE logical initv;
+    IGRAPH_F77_SAVE doublereal rnorm;
+    real tmvbx;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *
+	    , logical *, integer *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *);
+    integer msaup2=0;
+    real tsaup2;
+    extern doublereal igraphdlamch_(char *);
+    integer nevbef;
+    extern /* Subroutine */ int igraphsecond_(real *);
+    integer logfil=0, ndigit;
+    extern /* Subroutine */ int igraphdseigt_(doublereal *, integer *, doublereal *,
+	     integer *, doublereal *, doublereal *, doublereal *, integer *);
+    IGRAPH_F77_SAVE logical update;
+    extern /* Subroutine */ int igraphdsaitr_(integer *, char *, integer *, integer 
+	    *, integer *, integer *, doublereal *, doublereal *, doublereal *,
+	     integer *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *), igraphdsgets_(integer *, char *, integer *, integer 
+	    *, doublereal *, doublereal *, doublereal *), igraphdsapps_(
+	    integer *, integer *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *), igraphdsconv_(integer *, doublereal *, 
+	    doublereal *, doublereal *, integer *);
+    IGRAPH_F77_SAVE logical ushift;
+    char wprime[2];
+    IGRAPH_F77_SAVE integer msglvl;
+    integer nptemp;
+    extern /* Subroutine */ int igraphdsortr_(char *, logical *, integer *, 
+	    doublereal *, doublereal *);
+    IGRAPH_F77_SAVE integer kplusp;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    --workl;
+    --bounds;
+    --ritz;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+    --ipntr;
+
+    /* Function Body */
+    if (*ido == 0) {
+
+/*        %-------------------------------%   
+          | Initialize timing statistics  |   
+          | & message level for debugging |   
+          %-------------------------------% */
+
+	igraphsecond_(&t0);
+	msglvl = msaup2;
+
+/*        %---------------------------------%   
+          | Set machine dependent constant. |   
+          %---------------------------------% */
+
+	eps23 = igraphdlamch_("Epsilon-Machine");
+	eps23 = pow_dd(&eps23, &c_b3);
+
+/*        %-------------------------------------%   
+          | nev0 and np0 are integer variables  |   
+          | hold the initial values of NEV & NP |   
+          %-------------------------------------% */
+
+	nev0 = *nev;
+	np0 = *np;
+
+/*        %-------------------------------------%   
+          | kplusp is the bound on the largest  |   
+          |        Lanczos factorization built. |   
+          | nconv is the current number of      |   
+          |        "converged" eigenvlues.      |   
+          | iter is the counter on the current  |   
+          |      iteration step.                |   
+          %-------------------------------------% */
+
+	kplusp = nev0 + np0;
+	nconv = 0;
+	iter = 0;
+
+/*        %--------------------------------------------%   
+          | Set flags for computing the first NEV steps |   
+          | of the Lanczos factorization.              |   
+          %--------------------------------------------% */
+
+	getv0 = TRUE_;
+	update = FALSE_;
+	ushift = FALSE_;
+	cnorm = FALSE_;
+
+	if (*info != 0) {
+
+/*        %--------------------------------------------%   
+          | User provides the initial residual vector. |   
+          %--------------------------------------------% */
+
+	    initv = TRUE_;
+	    *info = 0;
+	} else {
+	    initv = FALSE_;
+	}
+    }
+
+/*     %---------------------------------------------%   
+       | Get a possibly random starting vector and   |   
+       | force it into the range of the operator OP. |   
+       %---------------------------------------------%   
+
+   L10: */
+
+    if (getv0) {
+	igraphdgetv0_(ido, bmat, &c__1, &initv, n, &c__1, &v[v_offset], ldv, &resid[
+		1], &rnorm, &ipntr[1], &workd[1], info);
+
+	if (*ido != 99) {
+	    goto L9000;
+	}
+
+	if (rnorm == 0.) {
+
+/*           %-----------------------------------------%   
+             | The initial vector is zero. Error exit. |   
+             %-----------------------------------------% */
+
+	    *info = -9;
+	    goto L1200;
+	}
+	getv0 = FALSE_;
+	*ido = 0;
+    }
+
+/*     %------------------------------------------------------------%   
+       | Back from reverse communication: continue with update step |   
+       %------------------------------------------------------------% */
+
+    if (update) {
+	goto L20;
+    }
+
+/*     %-------------------------------------------%   
+       | Back from computing user specified shifts |   
+       %-------------------------------------------% */
+
+    if (ushift) {
+	goto L50;
+    }
+
+/*     %-------------------------------------%   
+       | Back from computing residual norm   |   
+       | at the end of the current iteration |   
+       %-------------------------------------% */
+
+    if (cnorm) {
+	goto L100;
+    }
+
+/*     %----------------------------------------------------------%   
+       | Compute the first NEV steps of the Lanczos factorization |   
+       %----------------------------------------------------------% */
+
+    igraphdsaitr_(ido, bmat, n, &c__0, &nev0, mode, &resid[1], &rnorm, &v[v_offset],
+	     ldv, &h__[h_offset], ldh, &ipntr[1], &workd[1], info);
+
+/*     %---------------------------------------------------%   
+       | ido .ne. 99 implies use of reverse communication  |   
+       | to compute operations involving OP and possibly B |   
+       %---------------------------------------------------% */
+
+    if (*ido != 99) {
+	goto L9000;
+    }
+
+    if (*info > 0) {
+
+/*        %-----------------------------------------------------%   
+          | dsaitr was unable to build an Lanczos factorization |   
+          | of length NEV0. INFO is returned with the size of   |   
+          | the factorization built. Exit main loop.            |   
+          %-----------------------------------------------------% */
+
+	*np = *info;
+	*mxiter = iter;
+	*info = -9999;
+	goto L1200;
+    }
+
+/*     %--------------------------------------------------------------%   
+       |                                                              |   
+       |           M A I N  LANCZOS  I T E R A T I O N  L O O P       |   
+       |           Each iteration implicitly restarts the Lanczos     |   
+       |           factorization in place.                            |   
+       |                                                              |   
+       %--------------------------------------------------------------% */
+
+L1000:
+
+    ++iter;
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &iter, &ndigit, "_saup2: **** Start of major "
+		"iteration number ****", (ftnlen)49);
+    }
+    if (msglvl > 1) {
+	igraphivout_(&logfil, &c__1, nev, &ndigit, "_saup2: The length of the curr"
+		"ent Lanczos factorization", (ftnlen)55);
+	igraphivout_(&logfil, &c__1, np, &ndigit, "_saup2: Extend the Lanczos fact"
+		"orization by", (ftnlen)43);
+    }
+
+/*        %------------------------------------------------------------%   
+          | Compute NP additional steps of the Lanczos factorization. |   
+          %------------------------------------------------------------% */
+
+    *ido = 0;
+L20:
+    update = TRUE_;
+
+    igraphdsaitr_(ido, bmat, n, nev, np, mode, &resid[1], &rnorm, &v[v_offset], ldv,
+	     &h__[h_offset], ldh, &ipntr[1], &workd[1], info);
+
+/*        %---------------------------------------------------%   
+          | ido .ne. 99 implies use of reverse communication  |   
+          | to compute operations involving OP and possibly B |   
+          %---------------------------------------------------% */
+
+    if (*ido != 99) {
+	goto L9000;
+    }
+
+    if (*info > 0) {
+
+/*           %-----------------------------------------------------%   
+             | dsaitr was unable to build an Lanczos factorization |   
+             | of length NEV0+NP0. INFO is returned with the size  |   
+             | of the factorization built. Exit main loop.         |   
+             %-----------------------------------------------------% */
+
+	*np = *info;
+	*mxiter = iter;
+	*info = -9999;
+	goto L1200;
+    }
+    update = FALSE_;
+
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_saup2: Current B-norm of r"
+		"esidual for factorization", (ftnlen)52);
+    }
+
+/*        %--------------------------------------------------------%   
+          | Compute the eigenvalues and corresponding error bounds |   
+          | of the current symmetric tridiagonal matrix.           |   
+          %--------------------------------------------------------% */
+
+    igraphdseigt_(&rnorm, &kplusp, &h__[h_offset], ldh, &ritz[1], &bounds[1], &
+	    workl[1], &ierr);
+
+    if (ierr != 0) {
+	*info = -8;
+	goto L1200;
+    }
+
+/*        %----------------------------------------------------%   
+          | Make a copy of eigenvalues and corresponding error |   
+          | bounds obtained from _seigt.                       |   
+          %----------------------------------------------------% */
+
+    igraphdcopy_(&kplusp, &ritz[1], &c__1, &workl[kplusp + 1], &c__1);
+    igraphdcopy_(&kplusp, &bounds[1], &c__1, &workl[(kplusp << 1) + 1], &c__1);
+
+/*        %---------------------------------------------------%   
+          | Select the wanted Ritz values and their bounds    |   
+          | to be used in the convergence test.               |   
+          | The selection is based on the requested number of |   
+          | eigenvalues instead of the current NEV and NP to  |   
+          | prevent possible misconvergence.                  |   
+          | * Wanted Ritz values := RITZ(NP+1:NEV+NP)         |   
+          | * Shifts := RITZ(1:NP) := WORKL(1:NP)             |   
+          %---------------------------------------------------% */
+
+    *nev = nev0;
+    *np = np0;
+    igraphdsgets_(ishift, which, nev, np, &ritz[1], &bounds[1], &workl[1]);
+
+/*        %-------------------%   
+          | Convergence test. |   
+          %-------------------% */
+
+    igraphdcopy_(nev, &bounds[*np + 1], &c__1, &workl[*np + 1], &c__1);
+    igraphdsconv_(nev, &ritz[*np + 1], &workl[*np + 1], tol, &nconv);
+
+    if (msglvl > 2) {
+	kp[0] = *nev;
+	kp[1] = *np;
+	kp[2] = nconv;
+	igraphivout_(&logfil, &c__3, kp, &ndigit, "_saup2: NEV, NP, NCONV are", (
+		ftnlen)26);
+	igraphdvout_(&logfil, &kplusp, &ritz[1], &ndigit, "_saup2: The eigenvalues"
+		" of H", (ftnlen)28);
+	igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_saup2: Ritz estimate"
+		"s of the current NCV Ritz values", (ftnlen)53);
+    }
+
+/*        %---------------------------------------------------------%   
+          | Count the number of unwanted Ritz values that have zero |   
+          | Ritz estimates. If any Ritz estimates are equal to zero |   
+          | then a leading block of H of order equal to at least    |   
+          | the number of Ritz values with zero Ritz estimates has  |   
+          | split off. None of these Ritz values may be removed by  |   
+          | shifting. Decrease NP the number of shifts to apply. If |   
+          | no shifts may be applied, then prepare to exit          |   
+          %---------------------------------------------------------% */
+
+    nptemp = *np;
+    i__1 = nptemp;
+    for (j = 1; j <= i__1; ++j) {
+	if (bounds[j] == 0.) {
+	    --(*np);
+	    ++(*nev);
+	}
+/* L30: */
+    }
+
+    if (nconv >= nev0 || iter > *mxiter || *np == 0) {
+
+/*           %------------------------------------------------%   
+             | Prepare to exit. Put the converged Ritz values |   
+             | and corresponding bounds in RITZ(1:NCONV) and  |   
+             | BOUNDS(1:NCONV) respectively. Then sort. Be    |   
+             | careful when NCONV > NP since we don't want to |   
+             | swap overlapping locations.                    |   
+             %------------------------------------------------% */
+
+	if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*              %-----------------------------------------------------%   
+                | Both ends of the spectrum are requested.            |   
+                | Sort the eigenvalues into algebraically decreasing  |   
+                | order first then swap low end of the spectrum next  |   
+                | to high end in appropriate locations.               |   
+                | NOTE: when np < floor(nev/2) be careful not to swap |   
+                | overlapping locations.                              |   
+                %-----------------------------------------------------% */
+
+	    s_copy(wprime, "SA", (ftnlen)2, (ftnlen)2);
+	    igraphdsortr_(wprime, &c_true, &kplusp, &ritz[1], &bounds[1])
+		    ;
+	    nevd2 = *nev / 2;
+	    nevm2 = *nev - nevd2;
+	    if (*nev > 1) {
+		i__1 = min(nevd2,*np);
+/* Computing MAX */
+		i__2 = kplusp - nevd2 + 1, i__3 = kplusp - *np + 1;
+		igraphdswap_(&i__1, &ritz[nevm2 + 1], &c__1, &ritz[max(i__2,i__3)], 
+			&c__1);
+		i__1 = min(nevd2,*np);
+/* Computing MAX */
+		i__2 = kplusp - nevd2 + 1, i__3 = kplusp - *np;
+		igraphdswap_(&i__1, &bounds[nevm2 + 1], &c__1, &bounds[max(i__2,
+			i__3) + 1], &c__1);
+	    }
+
+	} else {
+
+/*              %--------------------------------------------------%   
+                | LM, SM, LA, SA case.                             |   
+                | Sort the eigenvalues of H into the an order that |   
+                | is opposite to WHICH, and apply the resulting    |   
+                | order to BOUNDS.  The eigenvalues are sorted so  |   
+                | that the wanted part are always within the first |   
+                | NEV locations.                                   |   
+                %--------------------------------------------------% */
+
+	    if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+		s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
+	    }
+	    if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+		s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
+	    }
+	    if (s_cmp(which, "LA", (ftnlen)2, (ftnlen)2) == 0) {
+		s_copy(wprime, "SA", (ftnlen)2, (ftnlen)2);
+	    }
+	    if (s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) == 0) {
+		s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2);
+	    }
+
+	    igraphdsortr_(wprime, &c_true, &kplusp, &ritz[1], &bounds[1])
+		    ;
+
+	}
+
+/*           %--------------------------------------------------%   
+             | Scale the Ritz estimate of each Ritz value       |   
+             | by 1 / max(eps23,magnitude of the Ritz value).   |   
+             %--------------------------------------------------% */
+
+	i__1 = nev0;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MAX */
+	    d__2 = eps23, d__3 = (d__1 = ritz[j], abs(d__1));
+	    temp = max(d__2,d__3);
+	    bounds[j] /= temp;
+/* L35: */
+	}
+
+/*           %----------------------------------------------------%   
+             | Sort the Ritz values according to the scaled Ritz  |   
+             | esitmates.  This will push all the converged ones  |   
+             | towards the front of ritzr, ritzi, bounds          |   
+             | (in the case when NCONV < NEV.)                    |   
+             %----------------------------------------------------% */
+
+	s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2);
+	igraphdsortr_(wprime, &c_true, &nev0, &bounds[1], &ritz[1]);
+
+/*           %----------------------------------------------%   
+             | Scale the Ritz estimate back to its original |   
+             | value.                                       |   
+             %----------------------------------------------% */
+
+	i__1 = nev0;
+	for (j = 1; j <= i__1; ++j) {
+/* Computing MAX */
+	    d__2 = eps23, d__3 = (d__1 = ritz[j], abs(d__1));
+	    temp = max(d__2,d__3);
+	    bounds[j] *= temp;
+/* L40: */
+	}
+
+/*           %--------------------------------------------------%   
+             | Sort the "converged" Ritz values again so that   |   
+             | the "threshold" values and their associated Ritz |   
+             | estimates appear at the appropriate position in  |   
+             | ritz and bound.                                  |   
+             %--------------------------------------------------% */
+
+	if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*              %------------------------------------------------%   
+                | Sort the "converged" Ritz values in increasing |   
+                | order.  The "threshold" values are in the      |   
+                | middle.                                        |   
+                %------------------------------------------------% */
+
+	    s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2);
+	    igraphdsortr_(wprime, &c_true, &nconv, &ritz[1], &bounds[1]);
+
+	} else {
+
+/*              %----------------------------------------------%   
+                | In LM, SM, LA, SA case, sort the "converged" |   
+                | Ritz values according to WHICH so that the   |   
+                | "threshold" value appears at the front of    |   
+                | ritz.                                        |   
+                %----------------------------------------------% */
+	    igraphdsortr_(which, &c_true, &nconv, &ritz[1], &bounds[1]);
+
+	}
+
+/*           %------------------------------------------%   
+             |  Use h( 1,1 ) as storage to communicate  |   
+             |  rnorm to _seupd if needed               |   
+             %------------------------------------------% */
+
+	h__[h_dim1 + 1] = rnorm;
+
+	if (msglvl > 1) {
+	    igraphdvout_(&logfil, &kplusp, &ritz[1], &ndigit, "_saup2: Sorted Ritz"
+		    " values.", (ftnlen)27);
+	    igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_saup2: Sorted ri"
+		    "tz estimates.", (ftnlen)30);
+	}
+
+/*           %------------------------------------%   
+             | Max iterations have been exceeded. |   
+             %------------------------------------% */
+
+	if (iter > *mxiter && nconv < *nev) {
+	    *info = 1;
+	}
+
+/*           %---------------------%   
+             | No shifts to apply. |   
+             %---------------------% */
+
+	if (*np == 0 && nconv < nev0) {
+	    *info = 2;
+	}
+
+	*np = nconv;
+	goto L1100;
+
+    } else if (nconv < *nev && *ishift == 1) {
+
+/*           %---------------------------------------------------%   
+             | Do not have all the requested eigenvalues yet.    |   
+             | To prevent possible stagnation, adjust the number |   
+             | of Ritz values and the shifts.                    |   
+             %---------------------------------------------------% */
+
+	nevbef = *nev;
+/* Computing MIN */
+	i__1 = nconv, i__2 = *np / 2;
+	*nev += min(i__1,i__2);
+	if (*nev == 1 && kplusp >= 6) {
+	    *nev = kplusp / 2;
+	} else if (*nev == 1 && kplusp > 2) {
+	    *nev = 2;
+	}
+	*np = kplusp - *nev;
+
+/*           %---------------------------------------%   
+             | If the size of NEV was just increased |   
+             | resort the eigenvalues.               |   
+             %---------------------------------------% */
+
+	if (nevbef < *nev) {
+	    igraphdsgets_(ishift, which, nev, np, &ritz[1], &bounds[1], &workl[1]);
+	}
+
+    }
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_saup2: no. of \"converge"
+		"d\" Ritz values at this iter.", (ftnlen)52);
+	if (msglvl > 1) {
+	    kp[0] = *nev;
+	    kp[1] = *np;
+	    igraphivout_(&logfil, &c__2, kp, &ndigit, "_saup2: NEV and NP are", (
+		    ftnlen)22);
+	    igraphdvout_(&logfil, nev, &ritz[*np + 1], &ndigit, "_saup2: \"wante"
+		    "d\" Ritz values.", (ftnlen)29);
+	    igraphdvout_(&logfil, nev, &bounds[*np + 1], &ndigit, "_saup2: Ritz es"
+		    "timates of the \"wanted\" values ", (ftnlen)46);
+	}
+    }
+
+    if (*ishift == 0) {
+
+/*           %-----------------------------------------------------%   
+             | User specified shifts: reverse communication to     |   
+             | compute the shifts. They are returned in the first  |   
+             | NP locations of WORKL.                              |   
+             %-----------------------------------------------------% */
+
+	ushift = TRUE_;
+	*ido = 3;
+	goto L9000;
+    }
+
+L50:
+
+/*        %------------------------------------%   
+          | Back from reverse communication;   |   
+          | User specified shifts are returned |   
+          | in WORKL(1:*NP)                   |   
+          %------------------------------------% */
+
+    ushift = FALSE_;
+
+
+/*        %---------------------------------------------------------%   
+          | Move the NP shifts to the first NP locations of RITZ to |   
+          | free up WORKL.  This is for the non-exact shift case;   |   
+          | in the exact shift case, dsgets already handles this.   |   
+          %---------------------------------------------------------% */
+
+    if (*ishift == 0) {
+	igraphdcopy_(np, &workl[1], &c__1, &ritz[1], &c__1);
+    }
+
+    if (msglvl > 2) {
+	igraphivout_(&logfil, &c__1, np, &ndigit, "_saup2: The number of shifts to"
+		" apply ", (ftnlen)38);
+	igraphdvout_(&logfil, np, &workl[1], &ndigit, "_saup2: shifts selected", (
+		ftnlen)23);
+	if (*ishift == 1) {
+	    igraphdvout_(&logfil, np, &bounds[1], &ndigit, "_saup2: corresponding "
+		    "Ritz estimates", (ftnlen)36);
+	}
+    }
+
+/*        %---------------------------------------------------------%   
+          | Apply the NP0 implicit shifts by QR bulge chasing.      |   
+          | Each shift is applied to the entire tridiagonal matrix. |   
+          | The first 2*N locations of WORKD are used as workspace. |   
+          | After dsapps is done, we have a Lanczos                 |   
+          | factorization of length NEV.                            |   
+          %---------------------------------------------------------% */
+
+    igraphdsapps_(n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, &
+	    resid[1], &q[q_offset], ldq, &workd[1]);
+
+/*        %---------------------------------------------%   
+          | Compute the B-norm of the updated residual. |   
+          | Keep B*RESID in WORKD(1:N) to be used in    |   
+          | the first step of the next call to dsaitr.  |   
+          %---------------------------------------------% */
+
+    cnorm = TRUE_;
+    igraphsecond_(&t2);
+    if (*(unsigned char *)bmat == 'G') {
+	++nbx;
+	igraphdcopy_(n, &resid[1], &c__1, &workd[*n + 1], &c__1);
+	ipntr[1] = *n + 1;
+	ipntr[2] = 1;
+	*ido = 2;
+
+/*           %----------------------------------%   
+             | Exit in order to compute B*RESID |   
+             %----------------------------------% */
+
+	goto L9000;
+    } else if (*(unsigned char *)bmat == 'I') {
+	igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
+    }
+
+L100:
+
+/*        %----------------------------------%   
+          | Back from reverse communication; |   
+          | WORKD(1:N) := B*RESID            |   
+          %----------------------------------% */
+
+    if (*(unsigned char *)bmat == 'G') {
+	igraphsecond_(&t3);
+	tmvbx += t3 - t2;
+    }
+
+    if (*(unsigned char *)bmat == 'G') {
+	rnorm = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1);
+	rnorm = sqrt((abs(rnorm)));
+    } else if (*(unsigned char *)bmat == 'I') {
+	rnorm = igraphdnrm2_(n, &resid[1], &c__1);
+    }
+    cnorm = FALSE_;
+/* L130: */
+
+    if (msglvl > 2) {
+	igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_saup2: B-norm of residual "
+		"for NEV factorization", (ftnlen)48);
+	igraphdvout_(&logfil, nev, &h__[(h_dim1 << 1) + 1], &ndigit, "_saup2: main"
+		" diagonal of compressed H matrix", (ftnlen)44);
+	i__1 = *nev - 1;
+	igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_saup2: subdiagon"
+		"al of compressed H matrix", (ftnlen)42);
+    }
+
+    goto L1000;
+
+/*     %---------------------------------------------------------------%   
+       |                                                               |   
+       |  E N D     O F     M A I N     I T E R A T I O N     L O O P  |   
+       |                                                               |   
+       %---------------------------------------------------------------% */
+
+L1100:
+
+    *mxiter = iter;
+    *nev = nconv;
+
+L1200:
+    *ido = 99;
+
+/*     %------------%   
+       | Error exit |   
+       %------------% */
+
+    igraphsecond_(&t1);
+    tsaup2 = t1 - t0;
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dsaup2 |   
+       %---------------% */
+
+} /* igraphdsaup2_ */
+
diff --git a/src/lapack/dsaupd.c b/src/lapack/dsaupd.c
new file mode 100644
index 0000000..f72a92e
--- /dev/null
+++ b/src/lapack/dsaupd.c
@@ -0,0 +1,792 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsaupd   
+
+   \Description:   
+
+    Reverse communication interface for the Implicitly Restarted Arnoldi   
+    Iteration.  For symmetric problems this reduces to a variant of the Lanczos   
+    method.  This method has been designed to compute approximations to a   
+    few eigenpairs of a linear operator OP that is real and symmetric   
+    with respect to a real positive semi-definite symmetric matrix B,   
+    i.e.   
+
+         B*OP = (OP')*B.   
+
+    Another way to express this condition is   
+
+         < x,OPy > = < OPx,y >  where < z,w > = z'Bw  .   
+
+    In the standard eigenproblem B is the identity matrix.   
+    ( A' denotes transpose of A)   
+
+    The computed approximate eigenvalues are called Ritz values and   
+    the corresponding approximate eigenvectors are called Ritz vectors.   
+
+    dsaupd is usually called iteratively to solve one of the   
+    following problems:   
+
+    Mode 1:  A*x = lambda*x, A symmetric   
+             ===> OP = A  and  B = I.   
+
+    Mode 2:  A*x = lambda*M*x, A symmetric, M symmetric positive definite   
+             ===> OP = inv[M]*A  and  B = M.   
+             ===> (If M can be factored see remark 3 below)   
+
+    Mode 3:  K*x = lambda*M*x, K symmetric, M symmetric positive semi-definite   
+             ===> OP = (inv[K - sigma*M])*M  and  B = M.   
+             ===> Shift-and-Invert mode   
+
+    Mode 4:  K*x = lambda*KG*x, K symmetric positive semi-definite,   
+             KG symmetric indefinite   
+             ===> OP = (inv[K - sigma*KG])*K  and  B = K.   
+             ===> Buckling mode   
+
+    Mode 5:  A*x = lambda*M*x, A symmetric, M symmetric positive semi-definite   
+             ===> OP = inv[A - sigma*M]*[A + sigma*M]  and  B = M.   
+             ===> Cayley transformed mode   
+
+    NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v   
+          should be accomplished either by a direct method   
+          using a sparse matrix factorization and solving   
+
+             [A - sigma*M]*w = v  or M*w = v,   
+
+          or through an iterative method for solving these   
+          systems.  If an iterative method is used, the   
+          convergence test must be more stringent than   
+          the accuracy requirements for the eigenvalue   
+          approximations.   
+
+   \Usage:   
+    call dsaupd   
+       ( IDO, BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM,   
+         IPNTR, WORKD, WORKL, LWORKL, INFO )   
+
+   \Arguments   
+    IDO     Integer.  (INPUT/OUTPUT)   
+            Reverse communication flag.  IDO must be zero on the first   
+            call to dsaupd.  IDO will be set internally to   
+            indicate the type of operation to be performed.  Control is   
+            then given back to the calling routine which has the   
+            responsibility to carry out the requested operation and call   
+            dsaupd with the result.  The operand is given in   
+            WORKD(IPNTR(1)), the result must be put in WORKD(IPNTR(2)).   
+            (If Mode = 2 see remark 5 below)   
+            -------------------------------------------------------------   
+            IDO =  0: first call to the reverse communication interface   
+            IDO = -1: compute  Y = OP * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+                      This is for the initialization phase to force the   
+                      starting vector into the range of OP.   
+            IDO =  1: compute  Y = OP * X where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+                      In mode 3,4 and 5, the vector B * X is already   
+                      available in WORKD(ipntr(3)).  It does not   
+                      need to be recomputed in forming OP * X.   
+            IDO =  2: compute  Y = B * X  where   
+                      IPNTR(1) is the pointer into WORKD for X,   
+                      IPNTR(2) is the pointer into WORKD for Y.   
+            IDO =  3: compute the IPARAM(8) shifts where   
+                      IPNTR(11) is the pointer into WORKL for   
+                      placing the shifts. See remark 6 below.   
+            IDO = 99: done   
+            -------------------------------------------------------------   
+
+    BMAT    Character*1.  (INPUT)   
+            BMAT specifies the type of the matrix B that defines the   
+            semi-inner product for the operator OP.   
+            B = 'I' -> standard eigenvalue problem A*x = lambda*x   
+            B = 'G' -> generalized eigenvalue problem A*x = lambda*B*x   
+
+    N       Integer.  (INPUT)   
+            Dimension of the eigenproblem.   
+
+    WHICH   Character*2.  (INPUT)   
+            Specify which of the Ritz values of OP to compute.   
+
+            'LA' - compute the NEV largest (algebraic) eigenvalues.   
+            'SA' - compute the NEV smallest (algebraic) eigenvalues.   
+            'LM' - compute the NEV largest (in magnitude) eigenvalues.   
+            'SM' - compute the NEV smallest (in magnitude) eigenvalues.   
+            'BE' - compute NEV eigenvalues, half from each end of the   
+                   spectrum.  When NEV is odd, compute one more from the   
+                   high end than from the low end.   
+             (see remark 1 below)   
+
+    NEV     Integer.  (INPUT)   
+            Number of eigenvalues of OP to be computed. 0 < NEV < N.   
+
+    TOL     Double precision scalar.  (INPUT)   
+            Stopping criterion: the relative accuracy of the Ritz value   
+            is considered acceptable if BOUNDS(I) .LE. TOL*ABS(RITZ(I)).   
+            If TOL .LE. 0. is passed a default is set:   
+            DEFAULT = DLAMCH('EPS')  (machine precision as computed   
+                      by the LAPACK auxiliary subroutine DLAMCH).   
+
+    RESID   Double precision array of length N.  (INPUT/OUTPUT)   
+            On INPUT:   
+            If INFO .EQ. 0, a random initial residual vector is used.   
+            If INFO .NE. 0, RESID contains the initial residual vector,   
+                            possibly from a previous run.   
+            On OUTPUT:   
+            RESID contains the final residual vector.   
+
+    NCV     Integer.  (INPUT)   
+            Number of columns of the matrix V (less than or equal to N).   
+            This will indicate how many Lanczos vectors are generated   
+            at each iteration.  After the startup phase in which NEV   
+            Lanczos vectors are generated, the algorithm generates   
+            NCV-NEV Lanczos vectors at each subsequent update iteration.   
+            Most of the cost in generating each Lanczos vector is in the   
+            matrix-vector product OP*x. (See remark 4 below).   
+
+    V       Double precision N by NCV array.  (OUTPUT)   
+            The NCV columns of V contain the Lanczos basis vectors.   
+
+    LDV     Integer.  (INPUT)   
+            Leading dimension of V exactly as declared in the calling   
+            program.   
+
+    IPARAM  Integer array of length 11.  (INPUT/OUTPUT)   
+            IPARAM(1) = ISHIFT: method for selecting the implicit shifts.   
+            The shifts selected at each iteration are used to restart   
+            the Arnoldi iteration in an implicit fashion.   
+            -------------------------------------------------------------   
+            ISHIFT = 0: the shifts are provided by the user via   
+                        reverse communication.  The NCV eigenvalues of   
+                        the current tridiagonal matrix T are returned in   
+                        the part of WORKL array corresponding to RITZ.   
+                        See remark 6 below.   
+            ISHIFT = 1: exact shifts with respect to the reduced   
+                        tridiagonal matrix T.  This is equivalent to   
+                        restarting the iteration with a starting vector   
+                        that is a linear combination of Ritz vectors   
+                        associated with the "wanted" Ritz values.   
+            -------------------------------------------------------------   
+
+            IPARAM(2) = LEVEC   
+            No longer referenced. See remark 2 below.   
+
+            IPARAM(3) = MXITER   
+            On INPUT:  maximum number of Arnoldi update iterations allowed.   
+            On OUTPUT: actual number of Arnoldi update iterations taken.   
+
+            IPARAM(4) = NB: blocksize to be used in the recurrence.   
+            The code currently works only for NB = 1.   
+
+            IPARAM(5) = NCONV: number of "converged" Ritz values.   
+            This represents the number of Ritz values that satisfy   
+            the convergence criterion.   
+
+            IPARAM(6) = IUPD   
+            No longer referenced. Implicit restarting is ALWAYS used.   
+
+            IPARAM(7) = MODE   
+            On INPUT determines what type of eigenproblem is being solved.   
+            Must be 1,2,3,4,5; See under \Description of dsaupd for the   
+            five modes available.   
+
+            IPARAM(8) = NP   
+            When ido = 3 and the user provides shifts through reverse   
+            communication (IPARAM(1)=0), dsaupd returns NP, the number   
+            of shifts the user is to provide. 0 < NP <=NCV-NEV. See Remark   
+            6 below.   
+
+            IPARAM(9) = NUMOP, IPARAM(10) = NUMOPB, IPARAM(11) = NUMREO,   
+            OUTPUT: NUMOP  = total number of OP*x operations,   
+                    NUMOPB = total number of B*x operations if BMAT='G',   
+                    NUMREO = total number of steps of re-orthogonalization.   
+
+    IPNTR   Integer array of length 11.  (OUTPUT)   
+            Pointer to mark the starting locations in the WORKD and WORKL   
+            arrays for matrices/vectors used by the Lanczos iteration.   
+            -------------------------------------------------------------   
+            IPNTR(1): pointer to the current operand vector X in WORKD.   
+            IPNTR(2): pointer to the current result vector Y in WORKD.   
+            IPNTR(3): pointer to the vector B * X in WORKD when used in   
+                      the shift-and-invert mode.   
+            IPNTR(4): pointer to the next available location in WORKL   
+                      that is untouched by the program.   
+            IPNTR(5): pointer to the NCV by 2 tridiagonal matrix T in WORKL.   
+            IPNTR(6): pointer to the NCV RITZ values array in WORKL.   
+            IPNTR(7): pointer to the Ritz estimates in array WORKL associated   
+                      with the Ritz values located in RITZ in WORKL.   
+            IPNTR(11): pointer to the NP shifts in WORKL. See Remark 6 below.   
+
+            Note: IPNTR(8:10) is only referenced by dseupd. See Remark 2.   
+            IPNTR(8): pointer to the NCV RITZ values of the original system.   
+            IPNTR(9): pointer to the NCV corresponding error bounds.   
+            IPNTR(10): pointer to the NCV by NCV matrix of eigenvectors   
+                       of the tridiagonal matrix T. Only referenced by   
+                       dseupd if RVEC = .TRUE. See Remarks.   
+            -------------------------------------------------------------   
+
+    WORKD   Double precision work array of length 3*N.  (REVERSE COMMUNICATION)   
+            Distributed array to be used in the basic Arnoldi iteration   
+            for reverse communication.  The user should not use WORKD   
+            as temporary workspace during the iteration. Upon termination   
+            WORKD(1:N) contains B*RESID(1:N). If the Ritz vectors are desired   
+            subroutine dseupd uses this output.   
+            See Data Distribution Note below.   
+
+    WORKL   Double precision work array of length LWORKL.  (OUTPUT/WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.  See Data Distribution Note below.   
+
+    LWORKL  Integer.  (INPUT)   
+            LWORKL must be at least NCV**2 + 8*NCV .   
+
+    INFO    Integer.  (INPUT/OUTPUT)   
+            If INFO .EQ. 0, a randomly initial residual vector is used.   
+            If INFO .NE. 0, RESID contains the initial residual vector,   
+                            possibly from a previous run.   
+            Error flag on output.   
+            =  0: Normal exit.   
+            =  1: Maximum number of iterations taken.   
+                  All possible eigenvalues of OP has been found. IPARAM(5)   
+                  returns the number of wanted converged Ritz values.   
+            =  2: No longer an informational error. Deprecated starting   
+                  with release 2 of ARPACK.   
+            =  3: No shifts could be applied during a cycle of the   
+                  Implicitly restarted Arnoldi iteration. One possibility   
+                  is to increase the size of NCV relative to NEV.   
+                  See remark 4 below.   
+            = -1: N must be positive.   
+            = -2: NEV must be positive.   
+            = -3: NCV must be greater than NEV and less than or equal to N.   
+            = -4: The maximum number of Arnoldi update iterations allowed   
+                  must be greater than zero.   
+            = -5: WHICH must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'.   
+            = -6: BMAT must be one of 'I' or 'G'.   
+            = -7: Length of private work array WORKL is not sufficient.   
+            = -8: Error return from trid. eigenvalue calculation;   
+                  Informatinal error from LAPACK routine dsteqr.   
+            = -9: Starting vector is zero.   
+            = -10: IPARAM(7) must be 1,2,3,4,5.   
+            = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatable.   
+            = -12: IPARAM(1) must be equal to 0 or 1.   
+            = -13: NEV and WHICH = 'BE' are incompatable.   
+            = -9999: Could not build an Arnoldi factorization.   
+                     IPARAM(5) returns the size of the current Arnoldi   
+                     factorization. The user is advised to check that   
+                     enough workspace and array storage has been allocated.   
+
+
+   \Remarks   
+    1. The converged Ritz values are always returned in ascending   
+       algebraic order.  The computed Ritz values are approximate   
+       eigenvalues of OP.  The selection of WHICH should be made   
+       with this in mind when Mode = 3,4,5.  After convergence,   
+       approximate eigenvalues of the original problem may be obtained   
+       with the ARPACK subroutine dseupd.   
+
+    2. If the Ritz vectors corresponding to the converged Ritz values   
+       are needed, the user must call dseupd immediately following completion   
+       of dsaupd. This is new starting with version 2.1 of ARPACK.   
+
+    3. If M can be factored into a Cholesky factorization M = LL'   
+       then Mode = 2 should not be selected.  Instead one should use   
+       Mode = 1 with  OP = inv(L)*A*inv(L').  Appropriate triangular   
+       linear systems should be solved with L and L' rather   
+       than computing inverses.  After convergence, an approximate   
+       eigenvector z of the original problem is recovered by solving   
+       L'z = x  where x is a Ritz vector of OP.   
+
+    4. At present there is no a-priori analysis to guide the selection   
+       of NCV relative to NEV.  The only formal requrement is that NCV > NEV.   
+       However, it is recommended that NCV .ge. 2*NEV.  If many problems of   
+       the same type are to be solved, one should experiment with increasing   
+       NCV while keeping NEV fixed for a given test problem.  This will   
+       usually decrease the required number of OP*x operations but it   
+       also increases the work and storage required to maintain the orthogonal   
+       basis vectors.   The optimal "cross-over" with respect to CPU time   
+       is problem dependent and must be determined empirically.   
+
+    5. If IPARAM(7) = 2 then in the Reverse commuication interface the user   
+       must do the following. When IDO = 1, Y = OP * X is to be computed.   
+       When IPARAM(7) = 2 OP = inv(B)*A. After computing A*X the user   
+       must overwrite X with A*X. Y is then the solution to the linear set   
+       of equations B*Y = A*X.   
+
+    6. When IPARAM(1) = 0, and IDO = 3, the user needs to provide the   
+       NP = IPARAM(8) shifts in locations:   
+       1   WORKL(IPNTR(11))   
+       2   WORKL(IPNTR(11)+1)   
+                          .   
+                          .   
+                          .   
+       NP  WORKL(IPNTR(11)+NP-1).   
+
+       The eigenvalues of the current tridiagonal matrix are located in   
+       WORKL(IPNTR(6)) through WORKL(IPNTR(6)+NCV-1). They are in the   
+       order defined by WHICH. The associated Ritz estimates are located in   
+       WORKL(IPNTR(8)), WORKL(IPNTR(8)+1), ... , WORKL(IPNTR(8)+NCV-1).   
+
+   -----------------------------------------------------------------------   
+
+   \Data Distribution Note:   
+
+    Fortran-D syntax:   
+    ================   
+    REAL       RESID(N), V(LDV,NCV), WORKD(3*N), WORKL(LWORKL)   
+    DECOMPOSE  D1(N), D2(N,NCV)   
+    ALIGN      RESID(I) with D1(I)   
+    ALIGN      V(I,J)   with D2(I,J)   
+    ALIGN      WORKD(I) with D1(I)     range (1:N)   
+    ALIGN      WORKD(I) with D1(I-N)   range (N+1:2*N)   
+    ALIGN      WORKD(I) with D1(I-2*N) range (2*N+1:3*N)   
+    DISTRIBUTE D1(BLOCK), D2(BLOCK,:)   
+    REPLICATED WORKL(LWORKL)   
+
+    Cray MPP syntax:   
+    ===============   
+    REAL       RESID(N), V(LDV,NCV), WORKD(N,3), WORKL(LWORKL)   
+    SHARED     RESID(BLOCK), V(BLOCK,:), WORKD(BLOCK,:)   
+    REPLICATED WORKL(LWORKL)   
+
+
+   \BeginLib   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+    3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall,   
+       1980.   
+    4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program",   
+       Computer Physics Communications, 53 (1989), pp 169-179.   
+    5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to   
+       Implement the Spectral Transformation", Math. Comp., 48 (1987),   
+       pp 663-673.   
+    6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos   
+       Algorithm for Solving Sparse Symmetric Generalized Eigenproblems",   
+       SIAM J. Matr. Anal. Apps.,  January (1993).   
+    7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines   
+       for Updating the QR decomposition", ACM TOMS, December 1990,   
+       Volume 16 Number 4, pp 369-377.   
+    8. R.B. Lehoucq, D.C. Sorensen, "Implementation of Some Spectral   
+       Transformations in a k-Step Arnoldi Method". In Preparation.   
+
+   \Routines called:   
+       dsaup2  ARPACK routine that implements the Implicitly Restarted   
+               Arnoldi Iteration.   
+       dstats  ARPACK routine that initialize timing and other statistics   
+               variables.   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dlamch  LAPACK routine that determines machine constants.   
+
+   \Authors   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/15/93: Version ' 2.4'   
+
+   \SCCS Information: @(#)   
+   FILE: saupd.F   SID: 2.7   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \Remarks   
+       1. None   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsaupd_(integer *ido, char *bmat, integer *n, char *
+	which, integer *nev, doublereal *tol, doublereal *resid, integer *ncv,
+	 doublereal *v, integer *ldv, integer *iparam, integer *ipntr, 
+	doublereal *workd, doublereal *workl, integer *lworkl, integer *info)
+{
+    /* Format strings */
+    static char fmt_1000[] = "(//,5x,\002==================================="
+	    "=======\002,/5x,\002= Symmetric implicit Arnoldi update code "
+	    "=\002,/5x,\002= Version Number:\002,\002 2.4\002,19x,\002 =\002,"
+	    "/5x,\002= Version Date:  \002,\002 07/31/96\002,14x,\002 =\002,/"
+	    "5x,\002==========================================\002,/5x,\002= "
+	    "Summary of timing statistics           =\002,/5x,\002==========="
+	    "===============================\002,//)";
+    static char fmt_1100[] = "(5x,\002Total number update iterations        "
+	    "     = \002,i5,/5x,\002Total number of OP*x operations          "
+	    "  = \002,i5,/5x,\002Total number of B*x operations             = "
+	    "\002,i5,/5x,\002Total number of reorthogonalization steps  = "
+	    "\002,i5,/5x,\002Total number of iterative refinement steps = "
+	    "\002,i5,/5x,\002Total number of restart steps              = "
+	    "\002,i5,/5x,\002Total time in user OP*x operation          = "
+	    "\002,f12.6,/5x,\002Total time in user B*x operation           ="
+	    " \002,f12.6,/5x,\002Total time in Arnoldi update routine       = "
+	    "\002,f12.6,/5x,\002Total time in saup2 routine                ="
+	    " \002,f12.6,/5x,\002Total time in basic Arnoldi iteration loop = "
+	    "\002,f12.6,/5x,\002Total time in reorthogonalization phase    ="
+	    " \002,f12.6,/5x,\002Total time in (re)start vector generation  = "
+	    "\002,f12.6,/5x,\002Total time in trid eigenvalue subproblem   ="
+	    " \002,f12.6,/5x,\002Total time in getting the shifts           = "
+	    "\002,f12.6,/5x,\002Total time in applying the shifts          ="
+	    " \002,f12.6,/5x,\002Total time in convergence testing          = "
+	    "\002,f12.6)";
+
+    /* System generated locals */
+    integer v_dim1, v_offset, i__1, i__2;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen), s_wsfe(cilist *), e_wsfe(
+	    void), do_fio(integer *, char *, ftnlen);
+
+    /* Local variables */
+    integer j;
+    real t0, t1;
+    IGRAPH_F77_SAVE integer nb, ih, iq, np, iw, ldh, ldq;
+    integer nbx;
+    IGRAPH_F77_SAVE integer nev0, mode, ierr, iupd, next;
+    integer nopx;
+    IGRAPH_F77_SAVE integer ritz;
+    real tmvbx;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen), igraphdsaup2_(integer *, char *, integer *
+	    , char *, integer *, integer *, doublereal *, doublereal *, 
+	    integer *, integer *, integer *, integer *, doublereal *, integer 
+	    *, doublereal *, integer *, doublereal *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    real tgetv0, tsaup2;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphsecond_(real *);
+    integer logfil=0, ndigit;
+    IGRAPH_F77_SAVE integer ishift;
+    integer nitref, msaupd=0;
+    IGRAPH_F77_SAVE integer bounds;
+    real titref, tseigt, tsaupd;
+    extern /* Subroutine */ int igraphdstats_(void);
+    IGRAPH_F77_SAVE integer msglvl;
+    real tsaitr;
+    IGRAPH_F77_SAVE integer mxiter;
+    real tsgets, tsapps;
+    integer nrorth;
+    real tsconv;
+    integer nrstrt;
+    real tmvopx;
+
+    /* Fortran I/O blocks */
+    static cilist io___28 = { 0, 6, 0, fmt_1000, 0 };
+    static cilist io___29 = { 0, 6, 0, fmt_1100, 0 };
+
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    --iparam;
+    --ipntr;
+    --workl;
+
+    /* Function Body */
+    if (*ido == 0) {
+
+/*        %-------------------------------%   
+          | Initialize timing statistics  |   
+          | & message level for debugging |   
+          %-------------------------------% */
+
+	igraphdstats_();
+	igraphsecond_(&t0);
+	msglvl = msaupd;
+
+	ierr = 0;
+	ishift = iparam[1];
+	mxiter = iparam[3];
+	nb = iparam[4];
+
+/*        %--------------------------------------------%   
+          | Revision 2 performs only implicit restart. |   
+          %--------------------------------------------% */
+
+	iupd = 1;
+	mode = iparam[7];
+
+/*        %----------------%   
+          | Error checking |   
+          %----------------% */
+
+	if (*n <= 0) {
+	    ierr = -1;
+	} else if (*nev <= 0) {
+	    ierr = -2;
+	} else if (*ncv <= *nev || *ncv > *n) {
+	    ierr = -3;
+	}
+
+/*        %----------------------------------------------%   
+          | NP is the number of additional steps to      |   
+          | extend the length NEV Lanczos factorization. |   
+          %----------------------------------------------% */
+
+	np = *ncv - *nev;
+
+	if (mxiter <= 0) {
+	    ierr = -4;
+	}
+	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, 
+		"SM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "LA", (
+		ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "SA", (ftnlen)2, (
+		ftnlen)2) != 0 && s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) != 
+		0) {
+	    ierr = -5;
+	}
+	if (*(unsigned char *)bmat != 'I' && *(unsigned char *)bmat != 'G') {
+	    ierr = -6;
+	}
+
+/* Computing 2nd power */
+	i__1 = *ncv;
+	if (*lworkl < i__1 * i__1 + (*ncv << 3)) {
+	    ierr = -7;
+	}
+	if (mode < 1 || mode > 5) {
+	    ierr = -10;
+	} else if (mode == 1 && *(unsigned char *)bmat == 'G') {
+	    ierr = -11;
+	} else if (ishift < 0 || ishift > 1) {
+	    ierr = -12;
+	} else if (*nev == 1 && s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0)
+		 {
+	    ierr = -13;
+	}
+
+/*        %------------%   
+          | Error Exit |   
+          %------------% */
+
+	if (ierr != 0) {
+	    *info = ierr;
+	    *ido = 99;
+	    goto L9000;
+	}
+
+/*        %------------------------%   
+          | Set default parameters |   
+          %------------------------% */
+
+	if (nb <= 0) {
+	    nb = 1;
+	}
+	if (*tol <= 0.) {
+	    *tol = igraphdlamch_("EpsMach");
+	}
+
+/*        %----------------------------------------------%   
+          | NP is the number of additional steps to      |   
+          | extend the length NEV Lanczos factorization. |   
+          | NEV0 is the local variable designating the   |   
+          | size of the invariant subspace desired.      |   
+          %----------------------------------------------% */
+
+	np = *ncv - *nev;
+	nev0 = *nev;
+
+/*        %-----------------------------%   
+          | Zero out internal workspace |   
+          %-----------------------------%   
+
+   Computing 2nd power */
+	i__2 = *ncv;
+	i__1 = i__2 * i__2 + (*ncv << 3);
+	for (j = 1; j <= i__1; ++j) {
+	    workl[j] = 0.;
+/* L10: */
+	}
+
+/*        %-------------------------------------------------------%   
+          | Pointer into WORKL for address of H, RITZ, BOUNDS, Q  |   
+          | etc... and the remaining workspace.                   |   
+          | Also update pointer to be used on output.             |   
+          | Memory is laid out as follows:                        |   
+          | workl(1:2*ncv) := generated tridiagonal matrix        |   
+          | workl(2*ncv+1:2*ncv+ncv) := ritz values               |   
+          | workl(3*ncv+1:3*ncv+ncv) := computed error bounds     |   
+          | workl(4*ncv+1:4*ncv+ncv*ncv) := rotation matrix Q     |   
+          | workl(4*ncv+ncv*ncv+1:7*ncv+ncv*ncv) := workspace     |   
+          %-------------------------------------------------------% */
+
+	ldh = *ncv;
+	ldq = *ncv;
+	ih = 1;
+	ritz = ih + (ldh << 1);
+	bounds = ritz + *ncv;
+	iq = bounds + *ncv;
+/* Computing 2nd power */
+	i__1 = *ncv;
+	iw = iq + i__1 * i__1;
+	next = iw + *ncv * 3;
+
+	ipntr[4] = next;
+	ipntr[5] = ih;
+	ipntr[6] = ritz;
+	ipntr[7] = bounds;
+	ipntr[11] = iw;
+    }
+
+/*     %-------------------------------------------------------%   
+       | Carry out the Implicitly restarted Lanczos Iteration. |   
+       %-------------------------------------------------------% */
+
+    igraphdsaup2_(ido, bmat, n, which, &nev0, &np, tol, &resid[1], &mode, &iupd, &
+	    ishift, &mxiter, &v[v_offset], ldv, &workl[ih], &ldh, &workl[ritz]
+	    , &workl[bounds], &workl[iq], &ldq, &workl[iw], &ipntr[1], &workd[
+	    1], info);
+
+/*     %--------------------------------------------------%   
+       | ido .ne. 99 implies use of reverse communication |   
+       | to compute operations involving OP or shifts.    |   
+       %--------------------------------------------------% */
+
+    if (*ido == 3) {
+	iparam[8] = np;
+    }
+    if (*ido != 99) {
+	goto L9000;
+    }
+
+    iparam[3] = mxiter;
+    iparam[5] = np;
+    iparam[9] = nopx;
+    iparam[10] = nbx;
+    iparam[11] = nrorth;
+
+/*     %------------------------------------%   
+       | Exit if there was an informational |   
+       | error within dsaup2.               |   
+       %------------------------------------% */
+
+    if (*info < 0) {
+	goto L9000;
+    }
+    if (*info == 2) {
+	*info = 3;
+    }
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, &mxiter, &ndigit, "_saupd: number of update i"
+		"terations taken", (ftnlen)41);
+	igraphivout_(&logfil, &c__1, &np, &ndigit, "_saupd: number of \"converge"
+		"d\" Ritz values", (ftnlen)41);
+	igraphdvout_(&logfil, &np, &workl[ritz], &ndigit, "_saupd: final Ritz valu"
+		"es", (ftnlen)25);
+	igraphdvout_(&logfil, &np, &workl[bounds], &ndigit, "_saupd: corresponding"
+		" error bounds", (ftnlen)34);
+    }
+
+    igraphsecond_(&t1);
+    tsaupd = t1 - t0;
+
+    if (msglvl > 0) {
+
+/*        %--------------------------------------------------------%   
+          | Version Number & Version Date are defined in version.h |   
+          %--------------------------------------------------------% */
+
+	s_wsfe(&io___28);
+	e_wsfe();
+	s_wsfe(&io___29);
+	do_fio(&c__1, (char *)&mxiter, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nopx, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nbx, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nrorth, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nitref, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&nrstrt, (ftnlen)sizeof(integer));
+	do_fio(&c__1, (char *)&tmvopx, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tmvbx, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tsaupd, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tsaup2, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tsaitr, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&titref, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tgetv0, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tseigt, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tsgets, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tsapps, (ftnlen)sizeof(real));
+	do_fio(&c__1, (char *)&tsconv, (ftnlen)sizeof(real));
+	e_wsfe();
+    }
+
+L9000:
+
+    return 0;
+
+/*     %---------------%   
+       | End of dsaupd |   
+       %---------------% */
+
+} /* igraphdsaupd_ */
+
diff --git a/src/lapack/dscal.c b/src/lapack/dscal.c
new file mode 100644
index 0000000..28d99aa
--- /dev/null
+++ b/src/lapack/dscal.c
@@ -0,0 +1,86 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdscal_(integer *n, doublereal *da, doublereal *dx, 
+	integer *incx)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+
+    /* Local variables */
+    integer i__, m, mp1, nincx;
+
+
+/*  Purpose   
+    =======   
+
+       DSCAL scales a vector by a constant.   
+       uses unrolled loops for increment equal to one.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 3/93 to return if incx .le. 0.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dx;
+
+    /* Function Body */
+    if (*n <= 0 || *incx <= 0) {
+	return 0;
+    }
+    if (*incx == 1) {
+
+/*        code for increment equal to 1   
+
+
+          clean-up loop */
+
+	m = *n % 5;
+	if (m != 0) {
+	    i__1 = m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		dx[i__] = *da * dx[i__];
+	    }
+	    if (*n < 5) {
+		return 0;
+	    }
+	}
+	mp1 = m + 1;
+	i__1 = *n;
+	for (i__ = mp1; i__ <= i__1; i__ += 5) {
+	    dx[i__] = *da * dx[i__];
+	    dx[i__ + 1] = *da * dx[i__ + 1];
+	    dx[i__ + 2] = *da * dx[i__ + 2];
+	    dx[i__ + 3] = *da * dx[i__ + 3];
+	    dx[i__ + 4] = *da * dx[i__ + 4];
+	}
+    } else {
+
+/*        code for increment not equal to 1 */
+
+	nincx = *n * *incx;
+	i__1 = nincx;
+	i__2 = *incx;
+	for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
+	    dx[i__] = *da * dx[i__];
+	}
+    }
+    return 0;
+} /* igraphdscal_ */
+
diff --git a/src/lapack/dsconv.c b/src/lapack/dsconv.c
new file mode 100644
index 0000000..7f88c06
--- /dev/null
+++ b/src/lapack/dsconv.c
@@ -0,0 +1,168 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b3 = .66666666666666663;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsconv   
+
+   \Description:   
+    Convergence testing for the symmetric Arnoldi eigenvalue routine.   
+
+   \Usage:   
+    call dsconv   
+       ( N, RITZ, BOUNDS, TOL, NCONV )   
+
+   \Arguments   
+    N       Integer.  (INPUT)   
+            Number of Ritz values to check for convergence.   
+
+    RITZ    Double precision array of length N.  (INPUT)   
+            The Ritz values to be checked for convergence.   
+
+    BOUNDS  Double precision array of length N.  (INPUT)   
+            Ritz estimates associated with the Ritz values in RITZ.   
+
+    TOL     Double precision scalar.  (INPUT)   
+            Desired relative accuracy for a Ritz value to be considered   
+            "converged".   
+
+    NCONV   Integer scalar.  (OUTPUT)   
+            Number of "converged" Ritz values.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Routines called:   
+       second  ARPACK utility routine for timing.   
+       dlamch  LAPACK routine that determines machine constants.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \SCCS Information: @(#)   
+   FILE: sconv.F   SID: 2.4   DATE OF SID: 4/19/96   RELEASE: 2   
+
+   \Remarks   
+       1. Starting with version 2.4, this routine no longer uses the   
+          Parlett strategy using the gap conditions.   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsconv_(integer *n, doublereal *ritz, doublereal *bounds,
+	 doublereal *tol, integer *nconv)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double pow_dd(doublereal *, doublereal *);
+
+    /* Local variables */
+    integer i__;
+    real t0, t1;
+    doublereal eps23, temp;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphsecond_(real *);
+    real tsconv;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %-------------------%   
+       | External routines |   
+       %-------------------%   
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    --bounds;
+    --ritz;
+
+    /* Function Body */
+    igraphsecond_(&t0);
+
+    eps23 = igraphdlamch_("Epsilon-Machine");
+    eps23 = pow_dd(&eps23, &c_b3);
+
+    *nconv = 0;
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+
+/*        %-----------------------------------------------------%   
+          | The i-th Ritz value is considered "converged"       |   
+          | when: bounds(i) .le. TOL*max(eps23, abs(ritz(i)))   |   
+          %-----------------------------------------------------%   
+
+   Computing MAX */
+	d__2 = eps23, d__3 = (d__1 = ritz[i__], abs(d__1));
+	temp = max(d__2,d__3);
+	if (bounds[i__] <= *tol * temp) {
+	    ++(*nconv);
+	}
+
+/* L10: */
+    }
+
+    igraphsecond_(&t1);
+    tsconv += t1 - t0;
+
+    return 0;
+
+/*     %---------------%   
+       | End of dsconv |   
+       %---------------% */
+
+} /* igraphdsconv_ */
+
diff --git a/src/lapack/dseigt.c b/src/lapack/dseigt.c
new file mode 100644
index 0000000..c56e629
--- /dev/null
+++ b/src/lapack/dseigt.c
@@ -0,0 +1,221 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dseigt   
+
+   \Description:   
+    Compute the eigenvalues of the current symmetric tridiagonal matrix   
+    and the corresponding error bounds given the current residual norm.   
+
+   \Usage:   
+    call dseigt   
+       ( RNORM, N, H, LDH, EIG, BOUNDS, WORKL, IERR )   
+
+   \Arguments   
+    RNORM   Double precision scalar.  (INPUT)   
+            RNORM contains the residual norm corresponding to the current   
+            symmetric tridiagonal matrix H.   
+
+    N       Integer.  (INPUT)   
+            Size of the symmetric tridiagonal matrix H.   
+
+    H       Double precision N by 2 array.  (INPUT)   
+            H contains the symmetric tridiagonal matrix with the   
+            subdiagonal in the first column starting at H(2,1) and the   
+            main diagonal in second column.   
+
+    LDH     Integer.  (INPUT)   
+            Leading dimension of H exactly as declared in the calling   
+            program.   
+
+    EIG     Double precision array of length N.  (OUTPUT)   
+            On output, EIG contains the N eigenvalues of H possibly   
+            unsorted.  The BOUNDS arrays are returned in the   
+            same sorted order as EIG.   
+
+    BOUNDS  Double precision array of length N.  (OUTPUT)   
+            On output, BOUNDS contains the error estimates corresponding   
+            to the eigenvalues EIG.  This is equal to RNORM times the   
+            last components of the eigenvectors corresponding to the   
+            eigenvalues in EIG.   
+
+    WORKL   Double precision work array of length 3*N.  (WORKSPACE)   
+            Private (replicated) array on each PE or array allocated on   
+            the front end.   
+
+    IERR    Integer.  (OUTPUT)   
+            Error exit flag from dstqrb.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       dstqrb  ARPACK routine that computes the eigenvalues and the   
+               last components of the eigenvectors of a symmetric   
+               and tridiagonal matrix.   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.4'   
+
+   \SCCS Information: @(#)   
+   FILE: seigt.F   SID: 2.4   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \Remarks   
+       None   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdseigt_(doublereal *rnorm, integer *n, doublereal *h__, 
+	integer *ldh, doublereal *eig, doublereal *bounds, doublereal *workl, 
+	integer *ierr)
+{
+    /* System generated locals */
+    integer h_dim1, h_offset, i__1;
+    doublereal d__1;
+
+    /* Local variables */
+    integer k;
+    real t0, t1;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdvout_(integer *, integer *, doublereal 
+	    *, integer *, char *, ftnlen), igraphsecond_(real *);
+    integer logfil=0, ndigit, mseigt=0;
+    extern /* Subroutine */ int igraphdstqrb_(integer *, doublereal *, doublereal *,
+	     doublereal *, doublereal *, integer *);
+    real tseigt;
+    integer msglvl;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       %-------------------------------%   
+       | Initialize timing statistics  |   
+       | & message level for debugging |   
+       %-------------------------------%   
+
+       Parameter adjustments */
+    --workl;
+    --bounds;
+    --eig;
+    h_dim1 = *ldh;
+    h_offset = 1 + h_dim1;
+    h__ -= h_offset;
+
+    /* Function Body */
+    igraphsecond_(&t0);
+    msglvl = mseigt;
+
+    if (msglvl > 0) {
+	igraphdvout_(&logfil, n, &h__[(h_dim1 << 1) + 1], &ndigit, "_seigt: main d"
+		"iagonal of matrix H", (ftnlen)33);
+	if (*n > 1) {
+	    i__1 = *n - 1;
+	    igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_seigt: sub d"
+		    "iagonal of matrix H", (ftnlen)32);
+	}
+    }
+
+    igraphdcopy_(n, &h__[(h_dim1 << 1) + 1], &c__1, &eig[1], &c__1);
+    i__1 = *n - 1;
+    igraphdcopy_(&i__1, &h__[h_dim1 + 2], &c__1, &workl[1], &c__1);
+    igraphdstqrb_(n, &eig[1], &workl[1], &bounds[1], &workl[*n + 1], ierr);
+    if (*ierr != 0) {
+	goto L9000;
+    }
+    if (msglvl > 1) {
+	igraphdvout_(&logfil, n, &bounds[1], &ndigit, "_seigt: last row of the eig"
+		"envector matrix for H", (ftnlen)48);
+    }
+
+/*     %-----------------------------------------------%   
+       | Finally determine the error bounds associated |   
+       | with the n Ritz values of H.                  |   
+       %-----------------------------------------------% */
+
+    i__1 = *n;
+    for (k = 1; k <= i__1; ++k) {
+	bounds[k] = *rnorm * (d__1 = bounds[k], abs(d__1));
+/* L30: */
+    }
+
+    igraphsecond_(&t1);
+    tseigt += t1 - t0;
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dseigt |   
+       %---------------% */
+
+} /* igraphdseigt_ */
+
diff --git a/src/lapack/dsesrt.c b/src/lapack/dsesrt.c
new file mode 100644
index 0000000..c761a80
--- /dev/null
+++ b/src/lapack/dsesrt.c
@@ -0,0 +1,288 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsesrt   
+
+   \Description:   
+    Sort the array X in the order specified by WHICH and optionally   
+    apply the permutation to the columns of the matrix A.   
+
+   \Usage:   
+    call dsesrt   
+       ( WHICH, APPLY, N, X, NA, A, LDA)   
+
+   \Arguments   
+    WHICH   Character*2.  (Input)   
+            'LM' -> X is sorted into increasing order of magnitude.   
+            'SM' -> X is sorted into decreasing order of magnitude.   
+            'LA' -> X is sorted into increasing order of algebraic.   
+            'SA' -> X is sorted into decreasing order of algebraic.   
+
+    APPLY   Logical.  (Input)   
+            APPLY = .TRUE.  -> apply the sorted order to A.   
+            APPLY = .FALSE. -> do not apply the sorted order to A.   
+
+    N       Integer.  (INPUT)   
+            Dimension of the array X.   
+
+    X      Double precision array of length N.  (INPUT/OUTPUT)   
+            The array to be sorted.   
+
+    NA      Integer.  (INPUT)   
+            Number of rows of the matrix A.   
+
+    A      Double precision array of length NA by N.  (INPUT/OUTPUT)   
+
+    LDA     Integer.  (INPUT)   
+            Leading dimension of A.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Routines   
+       dswap  Level 1 BLAS that swaps the contents of two vectors.   
+
+   \Authors   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/15/93: Version ' 2.1'.   
+                 Adapted from the sort routine in LANSO and   
+                 the ARPACK code dsortr   
+
+   \SCCS Information: @(#)   
+   FILE: sesrt.F   SID: 2.3   DATE OF SID: 4/19/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsesrt_(char *which, logical *apply, integer *n, 
+	doublereal *x, integer *na, doublereal *a, integer *lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    integer i__, j, igap;
+    doublereal temp;
+    extern /* Subroutine */ int igraphdswap_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+
+
+/*     %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1 * 0;
+    a -= a_offset;
+
+    /* Function Body */
+    igap = *n / 2;
+
+    if (s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X is sorted into decreasing order of algebraic. */
+
+L10:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L20:
+
+	    if (j < 0) {
+		goto L30;
+	    }
+
+	    if (x[j] < x[j + igap]) {
+		temp = x[j];
+		x[j] = x[j + igap];
+		x[j + igap] = temp;
+		if (*apply) {
+		    igraphdswap_(na, &a[j * a_dim1 + 1], &c__1, &a[(j + igap) * 
+			    a_dim1 + 1], &c__1);
+		}
+	    } else {
+		goto L30;
+	    }
+	    j -= igap;
+	    goto L20;
+L30:
+	    ;
+	}
+	igap /= 2;
+	goto L10;
+
+    } else if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X is sorted into decreasing order of magnitude. */
+
+L40:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L50:
+
+	    if (j < 0) {
+		goto L60;
+	    }
+
+	    if ((d__1 = x[j], abs(d__1)) < (d__2 = x[j + igap], abs(d__2))) {
+		temp = x[j];
+		x[j] = x[j + igap];
+		x[j + igap] = temp;
+		if (*apply) {
+		    igraphdswap_(na, &a[j * a_dim1 + 1], &c__1, &a[(j + igap) * 
+			    a_dim1 + 1], &c__1);
+		}
+	    } else {
+		goto L60;
+	    }
+	    j -= igap;
+	    goto L50;
+L60:
+	    ;
+	}
+	igap /= 2;
+	goto L40;
+
+    } else if (s_cmp(which, "LA", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X is sorted into increasing order of algebraic. */
+
+L70:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L80:
+
+	    if (j < 0) {
+		goto L90;
+	    }
+
+	    if (x[j] > x[j + igap]) {
+		temp = x[j];
+		x[j] = x[j + igap];
+		x[j + igap] = temp;
+		if (*apply) {
+		    igraphdswap_(na, &a[j * a_dim1 + 1], &c__1, &a[(j + igap) * 
+			    a_dim1 + 1], &c__1);
+		}
+	    } else {
+		goto L90;
+	    }
+	    j -= igap;
+	    goto L80;
+L90:
+	    ;
+	}
+	igap /= 2;
+	goto L70;
+
+    } else if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X is sorted into increasing order of magnitude. */
+
+L100:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L110:
+
+	    if (j < 0) {
+		goto L120;
+	    }
+
+	    if ((d__1 = x[j], abs(d__1)) > (d__2 = x[j + igap], abs(d__2))) {
+		temp = x[j];
+		x[j] = x[j + igap];
+		x[j + igap] = temp;
+		if (*apply) {
+		    igraphdswap_(na, &a[j * a_dim1 + 1], &c__1, &a[(j + igap) * 
+			    a_dim1 + 1], &c__1);
+		}
+	    } else {
+		goto L120;
+	    }
+	    j -= igap;
+	    goto L110;
+L120:
+	    ;
+	}
+	igap /= 2;
+	goto L100;
+    }
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dsesrt |   
+       %---------------% */
+
+} /* igraphdsesrt_ */
+
diff --git a/src/lapack/dseupd.c b/src/lapack/dseupd.c
new file mode 100644
index 0000000..cd51132
--- /dev/null
+++ b/src/lapack/dseupd.c
@@ -0,0 +1,1046 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b21 = .66666666666666663;
+static integer c__1 = 1;
+static integer c__2 = 2;
+static logical c_true = TRUE_;
+static doublereal c_b119 = 1.;
+
+/* \BeginDoc   
+
+   \Name: dseupd   
+
+   \Description:   
+
+    This subroutine returns the converged approximations to eigenvalues   
+    of A*z = lambda*B*z and (optionally):   
+
+        (1) the corresponding approximate eigenvectors,   
+
+        (2) an orthonormal (Lanczos) basis for the associated approximate   
+            invariant subspace,   
+
+        (3) Both.   
+
+    There is negligible additional cost to obtain eigenvectors.  An orthonormal   
+    (Lanczos) basis is always computed.  There is an additional storage cost   
+    of n*nev if both are requested (in this case a separate array Z must be   
+    supplied).   
+
+    These quantities are obtained from the Lanczos factorization computed   
+    by DSAUPD for the linear operator OP prescribed by the MODE selection   
+    (see IPARAM(7) in DSAUPD documentation.)  DSAUPD must be called before   
+    this routine is called. These approximate eigenvalues and vectors are   
+    commonly called Ritz values and Ritz vectors respectively.  They are   
+    referred to as such in the comments that follow.   The computed orthonormal   
+    basis for the invariant subspace corresponding to these Ritz values is   
+    referred to as a Lanczos basis.   
+
+    See documentation in the header of the subroutine DSAUPD for a definition   
+    of OP as well as other terms and the relation of computed Ritz values   
+    and vectors of OP with respect to the given problem  A*z = lambda*B*z.   
+
+    The approximate eigenvalues of the original problem are returned in   
+    ascending algebraic order.  The user may elect to call this routine   
+    once for each desired Ritz vector and store it peripherally if desired.   
+    There is also the option of computing a selected set of these vectors   
+    with a single call.   
+
+   \Usage:   
+    call dseupd   
+       ( RVEC, HOWMNY, SELECT, D, Z, LDZ, SIGMA, BMAT, N, WHICH, NEV, TOL,   
+         RESID, NCV, V, LDV, IPARAM, IPNTR, WORKD, WORKL, LWORKL, INFO )   
+
+    RVEC    LOGICAL  (INPUT)   
+            Specifies whether Ritz vectors corresponding to the Ritz value   
+            approximations to the eigenproblem A*z = lambda*B*z are computed.   
+
+               RVEC = .FALSE.     Compute Ritz values only.   
+
+               RVEC = .TRUE.      Compute Ritz vectors.   
+
+    HOWMNY  Character*1  (INPUT)   
+            Specifies how many Ritz vectors are wanted and the form of Z   
+            the matrix of Ritz vectors. See remark 1 below.   
+            = 'A': compute NEV Ritz vectors;   
+            = 'S': compute some of the Ritz vectors, specified   
+                   by the logical array SELECT.   
+
+    SELECT  Logical array of dimension NEV.  (INPUT)   
+            If HOWMNY = 'S', SELECT specifies the Ritz vectors to be   
+            computed. To select the Ritz vector corresponding to a   
+            Ritz value D(j), SELECT(j) must be set to .TRUE..   
+            If HOWMNY = 'A' , SELECT is not referenced.   
+
+    D       Double precision array of dimension NEV.  (OUTPUT)   
+            On exit, D contains the Ritz value approximations to the   
+            eigenvalues of A*z = lambda*B*z. The values are returned   
+            in ascending order. If IPARAM(7) = 3,4,5 then D represents   
+            the Ritz values of OP computed by dsaupd transformed to   
+            those of the original eigensystem A*z = lambda*B*z. If   
+            IPARAM(7) = 1,2 then the Ritz values of OP are the same   
+            as the those of A*z = lambda*B*z.   
+
+    Z       Double precision N by NEV array if HOWMNY = 'A'.  (OUTPUT)   
+            On exit, Z contains the B-orthonormal Ritz vectors of the   
+            eigensystem A*z = lambda*B*z corresponding to the Ritz   
+            value approximations.   
+            If  RVEC = .FALSE. then Z is not referenced.   
+            NOTE: The array Z may be set equal to first NEV columns of the   
+            Arnoldi/Lanczos basis array V computed by DSAUPD.   
+
+    LDZ     Integer.  (INPUT)   
+            The leading dimension of the array Z.  If Ritz vectors are   
+            desired, then  LDZ .ge.  max( 1, N ).  In any case,  LDZ .ge. 1.   
+
+    SIGMA   Double precision  (INPUT)   
+            If IPARAM(7) = 3,4,5 represents the shift. Not referenced if   
+            IPARAM(7) = 1 or 2.   
+
+
+    **** The remaining arguments MUST be the same as for the   ****   
+    **** call to DNAUPD that was just completed.               ****   
+
+    NOTE: The remaining arguments   
+
+             BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR,   
+             WORKD, WORKL, LWORKL, INFO   
+
+           must be passed directly to DSEUPD following the last call   
+           to DSAUPD.  These arguments MUST NOT BE MODIFIED between   
+           the the last call to DSAUPD and the call to DSEUPD.   
+
+    Two of these parameters (WORKL, INFO) are also output parameters:   
+
+    WORKL   Double precision work array of length LWORKL.  (OUTPUT/WORKSPACE)   
+            WORKL(1:4*ncv) contains information obtained in   
+            dsaupd.  They are not changed by dseupd.   
+            WORKL(4*ncv+1:ncv*ncv+8*ncv) holds the   
+            untransformed Ritz values, the computed error estimates,   
+            and the associated eigenvector matrix of H.   
+
+            Note: IPNTR(8:10) contains the pointer into WORKL for addresses   
+            of the above information computed by dseupd.   
+            -------------------------------------------------------------   
+            IPNTR(8): pointer to the NCV RITZ values of the original system.   
+            IPNTR(9): pointer to the NCV corresponding error bounds.   
+            IPNTR(10): pointer to the NCV by NCV matrix of eigenvectors   
+                       of the tridiagonal matrix T. Only referenced by   
+                       dseupd if RVEC = .TRUE. See Remarks.   
+            -------------------------------------------------------------   
+
+    INFO    Integer.  (OUTPUT)   
+            Error flag on output.   
+            =  0: Normal exit.   
+            = -1: N must be positive.   
+            = -2: NEV must be positive.   
+            = -3: NCV must be greater than NEV and less than or equal to N.   
+            = -5: WHICH must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'.   
+            = -6: BMAT must be one of 'I' or 'G'.   
+            = -7: Length of private work WORKL array is not sufficient.   
+            = -8: Error return from trid. eigenvalue calculation;   
+                  Information error from LAPACK routine dsteqr.   
+            = -9: Starting vector is zero.   
+            = -10: IPARAM(7) must be 1,2,3,4,5.   
+            = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatible.   
+            = -12: NEV and WHICH = 'BE' are incompatible.   
+            = -14: DSAUPD did not find any eigenvalues to sufficient   
+                   accuracy.   
+            = -15: HOWMNY must be one of 'A' or 'S' if RVEC = .true.   
+            = -16: HOWMNY = 'S' not yet implemented   
+
+   \BeginLib   
+
+   \References:   
+    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in   
+       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),   
+       pp 357-385.   
+    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly   
+       Restarted Arnoldi Iteration", Rice University Technical Report   
+       TR95-13, Department of Computational and Applied Mathematics.   
+    3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall,   
+       1980.   
+    4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program",   
+       Computer Physics Communications, 53 (1989), pp 169-179.   
+    5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to   
+       Implement the Spectral Transformation", Math. Comp., 48 (1987),   
+       pp 663-673.   
+    6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos   
+       Algorithm for Solving Sparse Symmetric Generalized Eigenproblems",   
+       SIAM J. Matr. Anal. Apps.,  January (1993).   
+    7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines   
+       for Updating the QR decomposition", ACM TOMS, December 1990,   
+       Volume 16 Number 4, pp 369-377.   
+
+   \Remarks   
+    1. The converged Ritz values are always returned in increasing   
+       (algebraic) order.   
+
+    2. Currently only HOWMNY = 'A' is implemented. It is included at this   
+       stage for the user who wants to incorporate it.   
+
+   \Routines called:   
+       dsesrt  ARPACK routine that sorts an array X, and applies the   
+               corresponding permutation to a matrix A.   
+       dsortr  dsortr  ARPACK sorting routine.   
+       ivout   ARPACK utility routine that prints integers.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dgeqr2  LAPACK routine that computes the QR factorization of   
+               a matrix.   
+       dlacpy  LAPACK matrix copy routine.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dorm2r  LAPACK routine that applies an orthogonal matrix in   
+               factored form.   
+       dsteqr  LAPACK routine that computes eigenvalues and eigenvectors   
+               of a tridiagonal matrix.   
+       dger    Level 2 BLAS rank one update to a matrix.   
+       dcopy   Level 1 BLAS that copies one vector to another .   
+       dnrm2   Level 1 BLAS that computes the norm of a vector.   
+       dscal   Level 1 BLAS that scales a vector.   
+       dswap   Level 1 BLAS that swaps the contents of two vectors.   
+   \Authors   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Chao Yang                    Houston, Texas   
+       Dept. of Computational &   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/15/93: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: seupd.F   SID: 2.7   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+   Subroutine */ int igraphdseupd_(logical *rvec, char *howmny, logical *select, 
+	doublereal *d__, doublereal *z__, integer *ldz, doublereal *sigma, 
+	char *bmat, integer *n, char *which, integer *nev, doublereal *tol, 
+	doublereal *resid, integer *ncv, doublereal *v, integer *ldv, integer 
+	*iparam, integer *ipntr, doublereal *workd, doublereal *workl, 
+	integer *lworkl, integer *info)
+{
+    /* System generated locals */
+    integer v_dim1, v_offset, z_dim1, z_offset, i__1;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+    /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
+    double pow_dd(doublereal *, doublereal *);
+
+    /* Local variables */
+    integer j, k, ih, iq, iw;
+    doublereal kv[2];
+    integer ibd, ihb, ihd, ldh, ilg, ldq, ism, irz;
+    extern /* Subroutine */ int igraphdger_(integer *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    integer mode;
+    doublereal eps23;
+    integer ierr;
+    doublereal temp;
+    integer next;
+    char type__[6];
+    integer ritz;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    logical reord;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    integer nconv;
+    doublereal rnorm;
+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
+	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
+	    , integer *, char *, ftnlen), igraphdgeqr2_(integer *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *);
+    doublereal bnorm2;
+    extern /* Subroutine */ int igraphdorm2r_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    doublereal thres1, thres2;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *);
+    integer logfil=0, ndigit, bounds, mseupd=0;
+    extern /* Subroutine */ int igraphdsteqr_(char *, integer *, doublereal *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *);
+    integer msglvl, ktrord;
+    extern /* Subroutine */ int igraphdsesrt_(char *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphdsortr_(char *, logical *, integer *, doublereal *, doublereal *);
+    doublereal tempbnd;
+    integer leftptr, rghtptr;
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %--------------%   
+       | Local Arrays |   
+       %--------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       %------------------------%   
+       | Set default parameters |   
+       %------------------------%   
+
+       Parameter adjustments */
+    --workd;
+    --resid;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --d__;
+    --select;
+    v_dim1 = *ldv;
+    v_offset = 1 + v_dim1;
+    v -= v_offset;
+    --iparam;
+    --ipntr;
+    --workl;
+
+    /* Function Body */
+    msglvl = mseupd;
+    mode = iparam[7];
+    nconv = iparam[5];
+    *info = 0;
+
+/*     %--------------%   
+       | Quick return |   
+       %--------------% */
+
+    if (nconv == 0) {
+	goto L9000;
+    }
+    ierr = 0;
+
+    if (nconv <= 0) {
+	ierr = -14;
+    }
+    if (*n <= 0) {
+	ierr = -1;
+    }
+    if (*nev <= 0) {
+	ierr = -2;
+    }
+    if (*ncv <= *nev || *ncv > *n) {
+	ierr = -3;
+    }
+    if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "SM", (
+	    ftnlen)2, (ftnlen)2) != 0 && s_cmp(which, "LA", (ftnlen)2, (
+	    ftnlen)2) != 0 && s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) != 0 &&
+	     s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) != 0) {
+	ierr = -5;
+    }
+    if (*(unsigned char *)bmat != 'I' && *(unsigned char *)bmat != 'G') {
+	ierr = -6;
+    }
+    if (*(unsigned char *)howmny != 'A' && *(unsigned char *)howmny != 'P' && 
+	    *(unsigned char *)howmny != 'S' && *rvec) {
+	ierr = -15;
+    }
+    if (*rvec && *(unsigned char *)howmny == 'S') {
+	ierr = -16;
+    }
+
+/* Computing 2nd power */
+    i__1 = *ncv;
+    if (*rvec && *lworkl < i__1 * i__1 + (*ncv << 3)) {
+	ierr = -7;
+    }
+
+    if (mode == 1 || mode == 2) {
+	s_copy(type__, "REGULR", (ftnlen)6, (ftnlen)6);
+    } else if (mode == 3) {
+	s_copy(type__, "SHIFTI", (ftnlen)6, (ftnlen)6);
+    } else if (mode == 4) {
+	s_copy(type__, "BUCKLE", (ftnlen)6, (ftnlen)6);
+    } else if (mode == 5) {
+	s_copy(type__, "CAYLEY", (ftnlen)6, (ftnlen)6);
+    } else {
+	ierr = -10;
+    }
+    if (mode == 1 && *(unsigned char *)bmat == 'G') {
+	ierr = -11;
+    }
+    if (*nev == 1 && s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) {
+	ierr = -12;
+    }
+
+/*     %------------%   
+       | Error Exit |   
+       %------------% */
+
+    if (ierr != 0) {
+	*info = ierr;
+	goto L9000;
+    }
+
+/*     %-------------------------------------------------------%   
+       | Pointer into WORKL for address of H, RITZ, BOUNDS, Q  |   
+       | etc... and the remaining workspace.                   |   
+       | Also update pointer to be used on output.             |   
+       | Memory is laid out as follows:                        |   
+       | workl(1:2*ncv) := generated tridiagonal matrix H      |   
+       |       The subdiagonal is stored in workl(2:ncv).      |   
+       |       The dead spot is workl(1) but upon exiting      |   
+       |       dsaupd stores the B-norm of the last residual   |   
+       |       vector in workl(1). We use this !!!             |   
+       | workl(2*ncv+1:2*ncv+ncv) := ritz values               |   
+       |       The wanted values are in the first NCONV spots. |   
+       | workl(3*ncv+1:3*ncv+ncv) := computed Ritz estimates   |   
+       |       The wanted values are in the first NCONV spots. |   
+       | NOTE: workl(1:4*ncv) is set by dsaupd and is not      |   
+       |       modified by dseupd.                             |   
+       %-------------------------------------------------------%   
+
+       %-------------------------------------------------------%   
+       | The following is used and set by dseupd.              |   
+       | workl(4*ncv+1:4*ncv+ncv) := used as workspace during  |   
+       |       computation of the eigenvectors of H. Stores    |   
+       |       the diagonal of H. Upon EXIT contains the NCV   |   
+       |       Ritz values of the original system. The first   |   
+       |       NCONV spots have the wanted values. If MODE =   |   
+       |       1 or 2 then will equal workl(2*ncv+1:3*ncv).    |   
+       | workl(5*ncv+1:5*ncv+ncv) := used as workspace during  |   
+       |       computation of the eigenvectors of H. Stores    |   
+       |       the subdiagonal of H. Upon EXIT contains the    |   
+       |       NCV corresponding Ritz estimates of the         |   
+       |       original system. The first NCONV spots have the |   
+       |       wanted values. If MODE = 1,2 then will equal    |   
+       |       workl(3*ncv+1:4*ncv).                           |   
+       | workl(6*ncv+1:6*ncv+ncv*ncv) := orthogonal Q that is  |   
+       |       the eigenvector matrix for H as returned by     |   
+       |       dsteqr. Not referenced if RVEC = .False.        |   
+       |       Ordering follows that of workl(4*ncv+1:5*ncv)   |   
+       | workl(6*ncv+ncv*ncv+1:6*ncv+ncv*ncv+2*ncv) :=         |   
+       |       Workspace. Needed by dsteqr and by dseupd.      |   
+       | GRAND total of NCV*(NCV+8) locations.                 |   
+       %-------------------------------------------------------% */
+
+
+    ih = ipntr[5];
+    ritz = ipntr[6];
+    bounds = ipntr[7];
+    ldh = *ncv;
+    ldq = *ncv;
+    ihd = bounds + ldh;
+    ihb = ihd + ldh;
+    iq = ihb + ldh;
+    iw = iq + ldh * *ncv;
+    next = iw + (*ncv << 1);
+    ipntr[4] = next;
+    ipntr[8] = ihd;
+    ipntr[9] = ihb;
+    ipntr[10] = iq;
+
+/*     %----------------------------------------%   
+       | irz points to the Ritz values computed |   
+       |     by _seigt before exiting _saup2.   |   
+       | ibd points to the Ritz estimates       |   
+       |     computed by _seigt before exiting  |   
+       |     _saup2.                            |   
+       %----------------------------------------% */
+
+    irz = ipntr[11] + *ncv;
+    ibd = irz + *ncv;
+
+
+/*     %---------------------------------%   
+       | Set machine dependent constant. |   
+       %---------------------------------% */
+
+    eps23 = igraphdlamch_("Epsilon-Machine");
+    eps23 = pow_dd(&eps23, &c_b21);
+
+/*     %---------------------------------------%   
+       | RNORM is B-norm of the RESID(1:N).    |   
+       | BNORM2 is the 2 norm of B*RESID(1:N). |   
+       | Upon exit of dsaupd WORKD(1:N) has    |   
+       | B*RESID(1:N).                         |   
+       %---------------------------------------% */
+
+    rnorm = workl[ih];
+    if (*(unsigned char *)bmat == 'I') {
+	bnorm2 = rnorm;
+    } else if (*(unsigned char *)bmat == 'G') {
+	bnorm2 = igraphdnrm2_(n, &workd[1], &c__1);
+    }
+
+    if (*rvec) {
+
+/*        %------------------------------------------------%   
+          | Get the converged Ritz value on the boundary.  |   
+          | This value will be used to dermine whether we  |   
+          | need to reorder the eigenvalues and            |   
+          | eigenvectors comupted by _steqr, and is        |   
+          | referred to as the "threshold" value.          |   
+          |                                                |   
+          | A Ritz value gamma is said to be a wanted      |   
+          | one, if                                        |   
+          | abs(gamma) .ge. threshold, when WHICH = 'LM';  |   
+          | abs(gamma) .le. threshold, when WHICH = 'SM';  |   
+          | gamma      .ge. threshold, when WHICH = 'LA';  |   
+          | gamma      .le. threshold, when WHICH = 'SA';  |   
+          | gamma .le. thres1 .or. gamma .ge. thres2       |   
+          |                            when WHICH = 'BE';  |   
+          |                                                |   
+          | Note: converged Ritz values and associated     |   
+          | Ritz estimates have been placed in the first   |   
+          | NCONV locations in workl(ritz) and             |   
+          | workl(bounds) respectively. They have been     |   
+          | sorted (in _saup2) according to the WHICH      |   
+          | selection criterion. (Except in the case       |   
+          | WHICH = 'BE', they are sorted in an increasing |   
+          | order.)                                        |   
+          %------------------------------------------------% */
+
+	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(which, 
+		"SM", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(which, "LA", (
+		ftnlen)2, (ftnlen)2) == 0 || s_cmp(which, "SA", (ftnlen)2, (
+		ftnlen)2) == 0) {
+
+	    thres1 = workl[ritz];
+
+	    if (msglvl > 2) {
+		igraphdvout_(&logfil, &c__1, &thres1, &ndigit, "_seupd: Threshold "
+			"eigenvalue used for re-ordering", (ftnlen)49);
+	    }
+
+	} else if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*            %------------------------------------------------%   
+              | Ritz values returned from _saup2 have been     |   
+              | sorted in increasing order.  Thus two          |   
+              | "threshold" values (one for the small end, one |   
+              | for the large end) are in the middle.          |   
+              %------------------------------------------------% */
+
+	    ism = max(*nev,nconv) / 2;
+	    ilg = ism + 1;
+	    thres1 = workl[ism];
+	    thres2 = workl[ilg];
+
+	    if (msglvl > 2) {
+		kv[0] = thres1;
+		kv[1] = thres2;
+		igraphdvout_(&logfil, &c__2, kv, &ndigit, "_seupd: Threshold eigen"
+			"values used for re-ordering", (ftnlen)50);
+	    }
+
+	}
+
+/*        %----------------------------------------------------------%   
+          | Check to see if all converged Ritz values appear within  |   
+          | the first NCONV diagonal elements returned from _seigt.  |   
+          | This is done in the following way:                       |   
+          |                                                          |   
+          | 1) For each Ritz value obtained from _seigt, compare it  |   
+          |    with the threshold Ritz value computed above to       |   
+          |    determine whether it is a wanted one.                 |   
+          |                                                          |   
+          | 2) If it is wanted, then check the corresponding Ritz    |   
+          |    estimate to see if it has converged.  If it has, set  |   
+          |    correponding entry in the logical array SELECT to     |   
+          |    .TRUE..                                               |   
+          |                                                          |   
+          | If SELECT(j) = .TRUE. and j > NCONV, then there is a     |   
+          | converged Ritz value that does not appear at the top of  |   
+          | the diagonal matrix computed by _seigt in _saup2.        |   
+          | Reordering is needed.                                    |   
+          %----------------------------------------------------------% */
+
+	reord = FALSE_;
+	ktrord = 0;
+	i__1 = *ncv - 1;
+	for (j = 0; j <= i__1; ++j) {
+	    select[j + 1] = FALSE_;
+	    if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+		if ((d__1 = workl[irz + j], abs(d__1)) >= abs(thres1)) {
+/* Computing MAX */
+		    d__2 = eps23, d__3 = (d__1 = workl[irz + j], abs(d__1));
+		    tempbnd = max(d__2,d__3);
+		    if (workl[ibd + j] <= *tol * tempbnd) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+		if ((d__1 = workl[irz + j], abs(d__1)) <= abs(thres1)) {
+/* Computing MAX */
+		    d__2 = eps23, d__3 = (d__1 = workl[irz + j], abs(d__1));
+		    tempbnd = max(d__2,d__3);
+		    if (workl[ibd + j] <= *tol * tempbnd) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "LA", (ftnlen)2, (ftnlen)2) == 0) {
+		if (workl[irz + j] >= thres1) {
+/* Computing MAX */
+		    d__2 = eps23, d__3 = (d__1 = workl[irz + j], abs(d__1));
+		    tempbnd = max(d__2,d__3);
+		    if (workl[ibd + j] <= *tol * tempbnd) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) == 0) {
+		if (workl[irz + j] <= thres1) {
+/* Computing MAX */
+		    d__2 = eps23, d__3 = (d__1 = workl[irz + j], abs(d__1));
+		    tempbnd = max(d__2,d__3);
+		    if (workl[ibd + j] <= *tol * tempbnd) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    } else if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) {
+		if (workl[irz + j] <= thres1 || workl[irz + j] >= thres2) {
+/* Computing MAX */
+		    d__2 = eps23, d__3 = (d__1 = workl[irz + j], abs(d__1));
+		    tempbnd = max(d__2,d__3);
+		    if (workl[ibd + j] <= *tol * tempbnd) {
+			select[j + 1] = TRUE_;
+		    }
+		}
+	    }
+	    if (j + 1 > nconv) {
+		reord = select[j + 1] || reord;
+	    }
+	    if (select[j + 1]) {
+		++ktrord;
+	    }
+/* L10: */
+	}
+/*        %-------------------------------------------%   
+          | If KTRORD .ne. NCONV, something is wrong. |   
+          %-------------------------------------------% */
+
+	if (msglvl > 2) {
+	    igraphivout_(&logfil, &c__1, &ktrord, &ndigit, "_seupd: Number of spec"
+		    "ified eigenvalues", (ftnlen)39);
+	    igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_seupd: Number of \"con"
+		    "verged\" eigenvalues", (ftnlen)41);
+	}
+
+/*        %-----------------------------------------------------------%   
+          | Call LAPACK routine _steqr to compute the eigenvalues and |   
+          | eigenvectors of the final symmetric tridiagonal matrix H. |   
+          | Initialize the eigenvector matrix Q to the identity.      |   
+          %-----------------------------------------------------------% */
+
+	i__1 = *ncv - 1;
+	igraphdcopy_(&i__1, &workl[ih + 1], &c__1, &workl[ihb], &c__1);
+	igraphdcopy_(ncv, &workl[ih + ldh], &c__1, &workl[ihd], &c__1);
+
+	igraphdsteqr_("Identity", ncv, &workl[ihd], &workl[ihb], &workl[iq], &ldq, &
+		workl[iw], &ierr);
+
+	if (ierr != 0) {
+	    *info = -8;
+	    goto L9000;
+	}
+
+	if (msglvl > 1) {
+	    igraphdcopy_(ncv, &workl[iq + *ncv - 1], &ldq, &workl[iw], &c__1);
+	    igraphdvout_(&logfil, ncv, &workl[ihd], &ndigit, "_seupd: NCV Ritz val"
+		    "ues of the final H matrix", (ftnlen)45);
+	    igraphdvout_(&logfil, ncv, &workl[iw], &ndigit, "_seupd: last row of t"
+		    "he eigenvector matrix for H", (ftnlen)48);
+	}
+
+	if (reord) {
+
+/*           %---------------------------------------------%   
+             | Reordered the eigenvalues and eigenvectors  |   
+             | computed by _steqr so that the "converged"  |   
+             | eigenvalues appear in the first NCONV       |   
+             | positions of workl(ihd), and the associated |   
+             | eigenvectors appear in the first NCONV      |   
+             | columns.                                    |   
+             %---------------------------------------------% */
+
+	    leftptr = 1;
+	    rghtptr = *ncv;
+
+	    if (*ncv == 1) {
+		goto L30;
+	    }
+
+L20:
+	    if (select[leftptr]) {
+
+/*              %-------------------------------------------%   
+                | Search, from the left, for the first Ritz |   
+                | value that has not converged.             |   
+                %-------------------------------------------% */
+
+		++leftptr;
+
+	    } else if (! select[rghtptr]) {
+
+/*              %----------------------------------------------%   
+                | Search, from the right, the first Ritz value |   
+                | that has converged.                          |   
+                %----------------------------------------------% */
+
+		--rghtptr;
+
+	    } else {
+
+/*              %----------------------------------------------%   
+                | Swap the Ritz value on the left that has not |   
+                | converged with the Ritz value on the right   |   
+                | that has converged.  Swap the associated     |   
+                | eigenvector of the tridiagonal matrix H as   |   
+                | well.                                        |   
+                %----------------------------------------------% */
+
+		temp = workl[ihd + leftptr - 1];
+		workl[ihd + leftptr - 1] = workl[ihd + rghtptr - 1];
+		workl[ihd + rghtptr - 1] = temp;
+		igraphdcopy_(ncv, &workl[iq + *ncv * (leftptr - 1)], &c__1, &workl[
+			iw], &c__1);
+		igraphdcopy_(ncv, &workl[iq + *ncv * (rghtptr - 1)], &c__1, &workl[
+			iq + *ncv * (leftptr - 1)], &c__1);
+		igraphdcopy_(ncv, &workl[iw], &c__1, &workl[iq + *ncv * (rghtptr - 
+			1)], &c__1);
+		++leftptr;
+		--rghtptr;
+
+	    }
+
+	    if (leftptr < rghtptr) {
+		goto L20;
+	    }
+
+L30:
+	    ;
+	}
+
+	if (msglvl > 2) {
+	    igraphdvout_(&logfil, ncv, &workl[ihd], &ndigit, "_seupd: The eigenval"
+		    "ues of H--reordered", (ftnlen)39);
+	}
+
+/*        %----------------------------------------%   
+          | Load the converged Ritz values into D. |   
+          %----------------------------------------% */
+
+	igraphdcopy_(&nconv, &workl[ihd], &c__1, &d__[1], &c__1);
+
+    } else {
+
+/*        %-----------------------------------------------------%   
+          | Ritz vectors not required. Load Ritz values into D. |   
+          %-----------------------------------------------------% */
+
+	igraphdcopy_(&nconv, &workl[ritz], &c__1, &d__[1], &c__1);
+	igraphdcopy_(ncv, &workl[ritz], &c__1, &workl[ihd], &c__1);
+
+    }
+
+/*     %------------------------------------------------------------------%   
+       | Transform the Ritz values and possibly vectors and corresponding |   
+       | Ritz estimates of OP to those of A*x=lambda*B*x. The Ritz values |   
+       | (and corresponding data) are returned in ascending order.        |   
+       %------------------------------------------------------------------% */
+
+    if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) == 0) {
+
+/*        %---------------------------------------------------------%   
+          | Ascending sort of wanted Ritz values, vectors and error |   
+          | bounds. Not necessary if only Ritz values are desired.  |   
+          %---------------------------------------------------------% */
+
+	if (*rvec) {
+	    igraphdsesrt_("LA", rvec, &nconv, &d__[1], ncv, &workl[iq], &ldq);
+	} else {
+	    igraphdcopy_(ncv, &workl[bounds], &c__1, &workl[ihb], &c__1);
+	}
+
+    } else {
+
+/*        %-------------------------------------------------------------%   
+          | *  Make a copy of all the Ritz values.                      |   
+          | *  Transform the Ritz values back to the original system.   |   
+          |    For TYPE = 'SHIFTI' the transformation is                |   
+          |             lambda = 1/theta + sigma                        |   
+          |    For TYPE = 'BUCKLE' the transformation is                |   
+          |             lambda = sigma * theta / ( theta - 1 )          |   
+          |    For TYPE = 'CAYLEY' the transformation is                |   
+          |             lambda = sigma * (theta + 1) / (theta - 1 )     |   
+          |    where the theta are the Ritz values returned by dsaupd.  |   
+          | NOTES:                                                      |   
+          | *The Ritz vectors are not affected by the transformation.   |   
+          |  They are only reordered.                                   |   
+          %-------------------------------------------------------------% */
+
+	igraphdcopy_(ncv, &workl[ihd], &c__1, &workl[iw], &c__1);
+	if (s_cmp(type__, "SHIFTI", (ftnlen)6, (ftnlen)6) == 0) {
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+		workl[ihd + k - 1] = 1. / workl[ihd + k - 1] + *sigma;
+/* L40: */
+	    }
+	} else if (s_cmp(type__, "BUCKLE", (ftnlen)6, (ftnlen)6) == 0) {
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+		workl[ihd + k - 1] = *sigma * workl[ihd + k - 1] / (workl[ihd 
+			+ k - 1] - 1.);
+/* L50: */
+	    }
+	} else if (s_cmp(type__, "CAYLEY", (ftnlen)6, (ftnlen)6) == 0) {
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+		workl[ihd + k - 1] = *sigma * (workl[ihd + k - 1] + 1.) / (
+			workl[ihd + k - 1] - 1.);
+/* L60: */
+	    }
+	}
+
+/*        %-------------------------------------------------------------%   
+          | *  Store the wanted NCONV lambda values into D.             |   
+          | *  Sort the NCONV wanted lambda in WORKL(IHD:IHD+NCONV-1)   |   
+          |    into ascending order and apply sort to the NCONV theta   |   
+          |    values in the transformed system. We'll need this to     |   
+          |    compute Ritz estimates in the original system.           |   
+          | *  Finally sort the lambda's into ascending order and apply |   
+          |    to Ritz vectors if wanted. Else just sort lambda's into  |   
+          |    ascending order.                                         |   
+          | NOTES:                                                      |   
+          | *workl(iw:iw+ncv-1) contain the theta ordered so that they  |   
+          |  match the ordering of the lambda. We'll use them again for |   
+          |  Ritz vector purification.                                  |   
+          %-------------------------------------------------------------% */
+
+	igraphdcopy_(&nconv, &workl[ihd], &c__1, &d__[1], &c__1);
+	igraphdsortr_("LA", &c_true, &nconv, &workl[ihd], &workl[iw]);
+	if (*rvec) {
+	    igraphdsesrt_("LA", rvec, &nconv, &d__[1], ncv, &workl[iq], &ldq);
+	} else {
+	    igraphdcopy_(ncv, &workl[bounds], &c__1, &workl[ihb], &c__1);
+	    d__1 = bnorm2 / rnorm;
+	    igraphdscal_(ncv, &d__1, &workl[ihb], &c__1);
+	    igraphdsortr_("LA", &c_true, &nconv, &d__[1], &workl[ihb]);
+	}
+
+    }
+
+/*     %------------------------------------------------%   
+       | Compute the Ritz vectors. Transform the wanted |   
+       | eigenvectors of the symmetric tridiagonal H by |   
+       | the Lanczos basis matrix V.                    |   
+       %------------------------------------------------% */
+
+    if (*rvec && *(unsigned char *)howmny == 'A') {
+
+/*        %----------------------------------------------------------%   
+          | Compute the QR factorization of the matrix representing  |   
+          | the wanted invariant subspace located in the first NCONV |   
+          | columns of workl(iq,ldq).                                |   
+          %----------------------------------------------------------% */
+
+	igraphdgeqr2_(ncv, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb],
+		 &ierr);
+
+
+/*        %--------------------------------------------------------%   
+          | * Postmultiply V by Q.                                 |   
+          | * Copy the first NCONV columns of VQ into Z.           |   
+          | The N by NCONV matrix Z is now a matrix representation |   
+          | of the approximate invariant subspace associated with  |   
+          | the Ritz values in workl(ihd).                         |   
+          %--------------------------------------------------------% */
+
+	igraphdorm2r_("Right", "Notranspose", n, ncv, &nconv, &workl[iq], &ldq, &
+		workl[iw + *ncv], &v[v_offset], ldv, &workd[*n + 1], &ierr);
+	igraphdlacpy_("All", n, &nconv, &v[v_offset], ldv, &z__[z_offset], ldz);
+
+/*        %-----------------------------------------------------%   
+          | In order to compute the Ritz estimates for the Ritz |   
+          | values in both systems, need the last row of the    |   
+          | eigenvector matrix. Remember, it's in factored form |   
+          %-----------------------------------------------------% */
+
+	i__1 = *ncv - 1;
+	for (j = 1; j <= i__1; ++j) {
+	    workl[ihb + j - 1] = 0.;
+/* L65: */
+	}
+	workl[ihb + *ncv - 1] = 1.;
+	igraphdorm2r_("Left", "Transpose", ncv, &c__1, &nconv, &workl[iq], &ldq, &
+		workl[iw + *ncv], &workl[ihb], ncv, &temp, &ierr);
+
+    } else if (*rvec && *(unsigned char *)howmny == 'S') {
+
+/*     Not yet implemented. See remark 2 above. */
+
+    }
+
+    if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) == 0 && *rvec) {
+
+	i__1 = *ncv;
+	for (j = 1; j <= i__1; ++j) {
+	    workl[ihb + j - 1] = rnorm * (d__1 = workl[ihb + j - 1], abs(d__1)
+		    );
+/* L70: */
+	}
+
+    } else if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) != 0 && *rvec) {
+
+/*        %-------------------------------------------------%   
+          | *  Determine Ritz estimates of the theta.       |   
+          |    If RVEC = .true. then compute Ritz estimates |   
+          |               of the theta.                     |   
+          |    If RVEC = .false. then copy Ritz estimates   |   
+          |              as computed by dsaupd.             |   
+          | *  Determine Ritz estimates of the lambda.      |   
+          %-------------------------------------------------% */
+
+	igraphdscal_(ncv, &bnorm2, &workl[ihb], &c__1);
+	if (s_cmp(type__, "SHIFTI", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+/* Computing 2nd power */
+		d__2 = workl[iw + k - 1];
+		workl[ihb + k - 1] = (d__1 = workl[ihb + k - 1], abs(d__1)) / 
+			(d__2 * d__2);
+/* L80: */
+	    }
+
+	} else if (s_cmp(type__, "BUCKLE", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+/* Computing 2nd power */
+		d__2 = workl[iw + k - 1] - 1.;
+		workl[ihb + k - 1] = *sigma * (d__1 = workl[ihb + k - 1], abs(
+			d__1)) / (d__2 * d__2);
+/* L90: */
+	    }
+
+	} else if (s_cmp(type__, "CAYLEY", (ftnlen)6, (ftnlen)6) == 0) {
+
+	    i__1 = *ncv;
+	    for (k = 1; k <= i__1; ++k) {
+		workl[ihb + k - 1] = (d__1 = workl[ihb + k - 1] / workl[iw + 
+			k - 1] * (workl[iw + k - 1] - 1.), abs(d__1));
+/* L100: */
+	    }
+
+	}
+
+    }
+
+    if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) != 0 && msglvl > 1) {
+	igraphdvout_(&logfil, &nconv, &d__[1], &ndigit, "_seupd: Untransformed con"
+		"verged Ritz values", (ftnlen)43);
+	igraphdvout_(&logfil, &nconv, &workl[ihb], &ndigit, "_seupd: Ritz estimate"
+		"s of the untransformed Ritz values", (ftnlen)55);
+    } else if (msglvl > 1) {
+	igraphdvout_(&logfil, &nconv, &d__[1], &ndigit, "_seupd: Converged Ritz va"
+		"lues", (ftnlen)29);
+	igraphdvout_(&logfil, &nconv, &workl[ihb], &ndigit, "_seupd: Associated Ri"
+		"tz estimates", (ftnlen)33);
+    }
+
+/*     %-------------------------------------------------%   
+       | Ritz vector purification step. Formally perform |   
+       | one of inverse subspace iteration. Only used    |   
+       | for MODE = 3,4,5. See reference 7               |   
+       %-------------------------------------------------% */
+
+    if (*rvec && (s_cmp(type__, "SHIFTI", (ftnlen)6, (ftnlen)6) == 0 || s_cmp(
+	    type__, "CAYLEY", (ftnlen)6, (ftnlen)6) == 0)) {
+
+	i__1 = nconv - 1;
+	for (k = 0; k <= i__1; ++k) {
+	    workl[iw + k] = workl[iq + k * ldq + *ncv - 1] / workl[iw + k];
+/* L110: */
+	}
+
+    } else if (*rvec && s_cmp(type__, "BUCKLE", (ftnlen)6, (ftnlen)6) == 0) {
+
+	i__1 = nconv - 1;
+	for (k = 0; k <= i__1; ++k) {
+	    workl[iw + k] = workl[iq + k * ldq + *ncv - 1] / (workl[iw + k] - 
+		    1.);
+/* L120: */
+	}
+
+    }
+
+    if (s_cmp(type__, "REGULR", (ftnlen)6, (ftnlen)6) != 0) {
+	igraphdger_(n, &nconv, &c_b119, &resid[1], &c__1, &workl[iw], &c__1, &z__[
+		z_offset], ldz);
+    }
+
+L9000:
+
+    return 0;
+
+/*     %---------------%   
+       | End of dseupd |   
+       %---------------% */
+
+} /* igraphdseupd_ */
+
diff --git a/src/lapack/dsgets.c b/src/lapack/dsgets.c
new file mode 100644
index 0000000..94d1a1e
--- /dev/null
+++ b/src/lapack/dsgets.c
@@ -0,0 +1,259 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static logical c_true = TRUE_;
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsgets   
+
+   \Description:   
+    Given the eigenvalues of the symmetric tridiagonal matrix H,   
+    computes the NP shifts AMU that are zeros of the polynomial of   
+    degree NP which filters out components of the unwanted eigenvectors   
+    corresponding to the AMU's based on some given criteria.   
+
+    NOTE: This is called even in the case of user specified shifts in   
+    order to sort the eigenvalues, and error bounds of H for later use.   
+
+   \Usage:   
+    call dsgets   
+       ( ISHIFT, WHICH, KEV, NP, RITZ, BOUNDS, SHIFTS )   
+
+   \Arguments   
+    ISHIFT  Integer.  (INPUT)   
+            Method for selecting the implicit shifts at each iteration.   
+            ISHIFT = 0: user specified shifts   
+            ISHIFT = 1: exact shift with respect to the matrix H.   
+
+    WHICH   Character*2.  (INPUT)   
+            Shift selection criteria.   
+            'LM' -> KEV eigenvalues of largest magnitude are retained.   
+            'SM' -> KEV eigenvalues of smallest magnitude are retained.   
+            'LA' -> KEV eigenvalues of largest value are retained.   
+            'SA' -> KEV eigenvalues of smallest value are retained.   
+            'BE' -> KEV eigenvalues, half from each end of the spectrum.   
+                    If KEV is odd, compute one more from the high end.   
+
+    KEV      Integer.  (INPUT)   
+            KEV+NP is the size of the matrix H.   
+
+    NP      Integer.  (INPUT)   
+            Number of implicit shifts to be computed.   
+
+    RITZ    Double precision array of length KEV+NP.  (INPUT/OUTPUT)   
+            On INPUT, RITZ contains the eigenvalues of H.   
+            On OUTPUT, RITZ are sorted so that the unwanted eigenvalues   
+            are in the first NP locations and the wanted part is in   
+            the last KEV locations.  When exact shifts are selected, the   
+            unwanted part corresponds to the shifts to be applied.   
+
+    BOUNDS  Double precision array of length KEV+NP.  (INPUT/OUTPUT)   
+            Error bounds corresponding to the ordering in RITZ.   
+
+    SHIFTS  Double precision array of length NP.  (INPUT/OUTPUT)   
+            On INPUT:  contains the user specified shifts if ISHIFT = 0.   
+            On OUTPUT: contains the shifts sorted into decreasing order   
+            of magnitude with respect to the Ritz estimates contained in   
+            BOUNDS. If ISHIFT = 0, SHIFTS is not modified on exit.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       dsortr  ARPACK utility sorting routine.   
+       ivout   ARPACK utility routine that prints integers.   
+       second  ARPACK utility routine for timing.   
+       dvout   ARPACK utility routine that prints vectors.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+       dswap   Level 1 BLAS that swaps the contents of two vectors.   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/93: Version ' 2.1'   
+
+   \SCCS Information: @(#)   
+   FILE: sgets.F   SID: 2.4   DATE OF SID: 4/19/96   RELEASE: 2   
+
+   \Remarks   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsgets_(integer *ishift, char *which, integer *kev, 
+	integer *np, doublereal *ritz, doublereal *bounds, doublereal *shifts)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    real t0, t1;
+    integer kevd2;
+    extern /* Subroutine */ int igraphdswap_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdcopy_(integer *, doublereal *, integer 
+	    *, doublereal *, integer *), igraphdvout_(integer *, integer *, 
+	    doublereal *, integer *, char *, ftnlen), igraphivout_(integer *, 
+	    integer *, integer *, integer *, char *, ftnlen), igraphsecond_(real *);
+    integer logfil=0, ndigit, msgets=0, msglvl;
+    real tsgets;
+    extern /* Subroutine */ int igraphdsortr_(char *, logical *, integer *, 
+	    doublereal *, doublereal *);
+
+
+/*     %----------------------------------------------------%   
+       | Include files for debugging and timing information |   
+       %----------------------------------------------------%   
+
+
+       %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %------------%   
+       | Parameters |   
+       %------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %----------------------%   
+       | External Subroutines |   
+       %----------------------%   
+
+
+       %---------------------%   
+       | Intrinsic Functions |   
+       %---------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------%   
+
+       %-------------------------------%   
+       | Initialize timing statistics  |   
+       | & message level for debugging |   
+       %-------------------------------%   
+
+       Parameter adjustments */
+    --shifts;
+    --bounds;
+    --ritz;
+
+    /* Function Body */
+    igraphsecond_(&t0);
+    msglvl = msgets;
+
+    if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %-----------------------------------------------------%   
+          | Both ends of the spectrum are requested.            |   
+          | Sort the eigenvalues into algebraically increasing  |   
+          | order first then swap high end of the spectrum next |   
+          | to low end in appropriate locations.                |   
+          | NOTE: when np < floor(kev/2) be careful not to swap |   
+          | overlapping locations.                              |   
+          %-----------------------------------------------------% */
+
+	i__1 = *kev + *np;
+	igraphdsortr_("LA", &c_true, &i__1, &ritz[1], &bounds[1]);
+	kevd2 = *kev / 2;
+	if (*kev > 1) {
+	    i__1 = min(kevd2,*np);
+	    igraphdswap_(&i__1, &ritz[1], &c__1, &ritz[max(kevd2,*np) + 1], &c__1);
+	    i__1 = min(kevd2,*np);
+	    igraphdswap_(&i__1, &bounds[1], &c__1, &bounds[max(kevd2,*np) + 1], &
+		    c__1);
+	}
+
+    } else {
+
+/*        %----------------------------------------------------%   
+          | LM, SM, LA, SA case.                               |   
+          | Sort the eigenvalues of H into the desired order   |   
+          | and apply the resulting order to BOUNDS.           |   
+          | The eigenvalues are sorted so that the wanted part |   
+          | are always in the last KEV locations.               |   
+          %----------------------------------------------------% */
+
+	i__1 = *kev + *np;
+	igraphdsortr_(which, &c_true, &i__1, &ritz[1], &bounds[1]);
+    }
+
+    if (*ishift == 1 && *np > 0) {
+
+/*        %-------------------------------------------------------%   
+          | Sort the unwanted Ritz values used as shifts so that  |   
+          | the ones with largest Ritz estimates are first.       |   
+          | This will tend to minimize the effects of the         |   
+          | forward instability of the iteration when the shifts  |   
+          | are applied in subroutine dsapps.                     |   
+          %-------------------------------------------------------% */
+
+	igraphdsortr_("SM", &c_true, np, &bounds[1], &ritz[1]);
+	igraphdcopy_(np, &ritz[1], &c__1, &shifts[1], &c__1);
+    }
+
+    igraphsecond_(&t1);
+    tsgets += t1 - t0;
+
+    if (msglvl > 0) {
+	igraphivout_(&logfil, &c__1, kev, &ndigit, "_sgets: KEV is", (ftnlen)14);
+	igraphivout_(&logfil, &c__1, np, &ndigit, "_sgets: NP is", (ftnlen)13);
+	i__1 = *kev + *np;
+	igraphdvout_(&logfil, &i__1, &ritz[1], &ndigit, "_sgets: Eigenvalues of cu"
+		"rrent H matrix", (ftnlen)39);
+	i__1 = *kev + *np;
+	igraphdvout_(&logfil, &i__1, &bounds[1], &ndigit, "_sgets: Associated Ritz"
+		" estimates", (ftnlen)33);
+    }
+
+    return 0;
+
+/*     %---------------%   
+       | End of dsgets |   
+       %---------------% */
+
+} /* igraphdsgets_ */
+
diff --git a/src/lapack/dsortc.c b/src/lapack/dsortc.c
new file mode 100644
index 0000000..6090877
--- /dev/null
+++ b/src/lapack/dsortc.c
@@ -0,0 +1,406 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsortc   
+
+   \Description:   
+    Sorts the complex array in XREAL and XIMAG into the order   
+    specified by WHICH and optionally applies the permutation to the   
+    real array Y. It is assumed that if an element of XIMAG is   
+    nonzero, then its negative is also an element. In other words,   
+    both members of a complex conjugate pair are to be sorted and the   
+    pairs are kept adjacent to each other.   
+
+   \Usage:   
+    call dsortc   
+       ( WHICH, APPLY, N, XREAL, XIMAG, Y )   
+
+   \Arguments   
+    WHICH   Character*2.  (Input)   
+            'LM' -> sort XREAL,XIMAG into increasing order of magnitude.   
+            'SM' -> sort XREAL,XIMAG into decreasing order of magnitude.   
+            'LR' -> sort XREAL into increasing order of algebraic.   
+            'SR' -> sort XREAL into decreasing order of algebraic.   
+            'LI' -> sort XIMAG into increasing order of magnitude.   
+            'SI' -> sort XIMAG into decreasing order of magnitude.   
+            NOTE: If an element of XIMAG is non-zero, then its negative   
+                  is also an element.   
+
+    APPLY   Logical.  (Input)   
+            APPLY = .TRUE.  -> apply the sorted order to array Y.   
+            APPLY = .FALSE. -> do not apply the sorted order to array Y.   
+
+    N       Integer.  (INPUT)   
+            Size of the arrays.   
+
+    XREAL,  Double precision array of length N.  (INPUT/OUTPUT)   
+    XIMAG   Real and imaginary part of the array to be sorted.   
+
+    Y       Double precision array of length N.  (INPUT/OUTPUT)   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       xx/xx/92: Version ' 2.1'   
+                 Adapted from the sort routine in LANSO.   
+
+   \SCCS Information: @(#)   
+   FILE: sortc.F   SID: 2.3   DATE OF SID: 4/20/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsortc_(char *which, logical *apply, integer *n, 
+	doublereal *xreal, doublereal *ximag, doublereal *y)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    integer i__, j, igap;
+    doublereal temp, temp1, temp2;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+
+
+/*     %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %--------------------%   
+       | External Functions |   
+       %--------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    igap = *n / 2;
+
+    if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %------------------------------------------------------%   
+          | Sort XREAL,XIMAG into increasing order of magnitude. |   
+          %------------------------------------------------------% */
+
+L10:
+	if (igap == 0) {
+	    goto L9000;
+	}
+
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L20:
+
+	    if (j < 0) {
+		goto L30;
+	    }
+
+	    temp1 = igraphdlapy2_(&xreal[j], &ximag[j]);
+	    temp2 = igraphdlapy2_(&xreal[j + igap], &ximag[j + igap]);
+
+	    if (temp1 > temp2) {
+		temp = xreal[j];
+		xreal[j] = xreal[j + igap];
+		xreal[j + igap] = temp;
+
+		temp = ximag[j];
+		ximag[j] = ximag[j + igap];
+		ximag[j + igap] = temp;
+
+		if (*apply) {
+		    temp = y[j];
+		    y[j] = y[j + igap];
+		    y[j + igap] = temp;
+		}
+	    } else {
+		goto L30;
+	    }
+	    j -= igap;
+	    goto L20;
+L30:
+	    ;
+	}
+	igap /= 2;
+	goto L10;
+
+    } else if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %------------------------------------------------------%   
+          | Sort XREAL,XIMAG into decreasing order of magnitude. |   
+          %------------------------------------------------------% */
+
+L40:
+	if (igap == 0) {
+	    goto L9000;
+	}
+
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L50:
+
+	    if (j < 0) {
+		goto L60;
+	    }
+
+	    temp1 = igraphdlapy2_(&xreal[j], &ximag[j]);
+	    temp2 = igraphdlapy2_(&xreal[j + igap], &ximag[j + igap]);
+
+	    if (temp1 < temp2) {
+		temp = xreal[j];
+		xreal[j] = xreal[j + igap];
+		xreal[j + igap] = temp;
+
+		temp = ximag[j];
+		ximag[j] = ximag[j + igap];
+		ximag[j + igap] = temp;
+
+		if (*apply) {
+		    temp = y[j];
+		    y[j] = y[j + igap];
+		    y[j + igap] = temp;
+		}
+	    } else {
+		goto L60;
+	    }
+	    j -= igap;
+	    goto L50;
+L60:
+	    ;
+	}
+	igap /= 2;
+	goto L40;
+
+    } else if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %------------------------------------------------%   
+          | Sort XREAL into increasing order of algebraic. |   
+          %------------------------------------------------% */
+
+L70:
+	if (igap == 0) {
+	    goto L9000;
+	}
+
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L80:
+
+	    if (j < 0) {
+		goto L90;
+	    }
+
+	    if (xreal[j] > xreal[j + igap]) {
+		temp = xreal[j];
+		xreal[j] = xreal[j + igap];
+		xreal[j + igap] = temp;
+
+		temp = ximag[j];
+		ximag[j] = ximag[j + igap];
+		ximag[j + igap] = temp;
+
+		if (*apply) {
+		    temp = y[j];
+		    y[j] = y[j + igap];
+		    y[j + igap] = temp;
+		}
+	    } else {
+		goto L90;
+	    }
+	    j -= igap;
+	    goto L80;
+L90:
+	    ;
+	}
+	igap /= 2;
+	goto L70;
+
+    } else if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %------------------------------------------------%   
+          | Sort XREAL into decreasing order of algebraic. |   
+          %------------------------------------------------% */
+
+L100:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L110:
+
+	    if (j < 0) {
+		goto L120;
+	    }
+
+	    if (xreal[j] < xreal[j + igap]) {
+		temp = xreal[j];
+		xreal[j] = xreal[j + igap];
+		xreal[j + igap] = temp;
+
+		temp = ximag[j];
+		ximag[j] = ximag[j + igap];
+		ximag[j + igap] = temp;
+
+		if (*apply) {
+		    temp = y[j];
+		    y[j] = y[j + igap];
+		    y[j + igap] = temp;
+		}
+	    } else {
+		goto L120;
+	    }
+	    j -= igap;
+	    goto L110;
+L120:
+	    ;
+	}
+	igap /= 2;
+	goto L100;
+
+    } else if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %------------------------------------------------%   
+          | Sort XIMAG into increasing order of magnitude. |   
+          %------------------------------------------------% */
+
+L130:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L140:
+
+	    if (j < 0) {
+		goto L150;
+	    }
+
+	    if ((d__1 = ximag[j], abs(d__1)) > (d__2 = ximag[j + igap], abs(
+		    d__2))) {
+		temp = xreal[j];
+		xreal[j] = xreal[j + igap];
+		xreal[j + igap] = temp;
+
+		temp = ximag[j];
+		ximag[j] = ximag[j + igap];
+		ximag[j + igap] = temp;
+
+		if (*apply) {
+		    temp = y[j];
+		    y[j] = y[j + igap];
+		    y[j + igap] = temp;
+		}
+	    } else {
+		goto L150;
+	    }
+	    j -= igap;
+	    goto L140;
+L150:
+	    ;
+	}
+	igap /= 2;
+	goto L130;
+
+    } else if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        %------------------------------------------------%   
+          | Sort XIMAG into decreasing order of magnitude. |   
+          %------------------------------------------------% */
+
+L160:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L170:
+
+	    if (j < 0) {
+		goto L180;
+	    }
+
+	    if ((d__1 = ximag[j], abs(d__1)) < (d__2 = ximag[j + igap], abs(
+		    d__2))) {
+		temp = xreal[j];
+		xreal[j] = xreal[j + igap];
+		xreal[j + igap] = temp;
+
+		temp = ximag[j];
+		ximag[j] = ximag[j + igap];
+		ximag[j + igap] = temp;
+
+		if (*apply) {
+		    temp = y[j];
+		    y[j] = y[j + igap];
+		    y[j + igap] = temp;
+		}
+	    } else {
+		goto L180;
+	    }
+	    j -= igap;
+	    goto L170;
+L180:
+	    ;
+	}
+	igap /= 2;
+	goto L160;
+    }
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dsortc |   
+       %---------------% */
+
+} /* igraphdsortc_ */
+
diff --git a/src/lapack/dsortr.c b/src/lapack/dsortr.c
new file mode 100644
index 0000000..8870dc4
--- /dev/null
+++ b/src/lapack/dsortr.c
@@ -0,0 +1,268 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dsortr   
+
+   \Description:   
+    Sort the array X1 in the order specified by WHICH and optionally   
+    applies the permutation to the array X2.   
+
+   \Usage:   
+    call dsortr   
+       ( WHICH, APPLY, N, X1, X2 )   
+
+   \Arguments   
+    WHICH   Character*2.  (Input)   
+            'LM' -> X1 is sorted into increasing order of magnitude.   
+            'SM' -> X1 is sorted into decreasing order of magnitude.   
+            'LA' -> X1 is sorted into increasing order of algebraic.   
+            'SA' -> X1 is sorted into decreasing order of algebraic.   
+
+    APPLY   Logical.  (Input)   
+            APPLY = .TRUE.  -> apply the sorted order to X2.   
+            APPLY = .FALSE. -> do not apply the sorted order to X2.   
+
+    N       Integer.  (INPUT)   
+            Size of the arrays.   
+
+    X1      Double precision array of length N.  (INPUT/OUTPUT)   
+            The array to be sorted.   
+
+    X2      Double precision array of length N.  (INPUT/OUTPUT)   
+            Only referenced if APPLY = .TRUE.   
+
+   \EndDoc   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \Revision history:   
+       12/16/93: Version ' 2.1'.   
+                 Adapted from the sort routine in LANSO.   
+
+   \SCCS Information: @(#)   
+   FILE: sortr.F   SID: 2.3   DATE OF SID: 4/19/96   RELEASE: 2   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdsortr_(char *which, logical *apply, integer *n, 
+	doublereal *x1, doublereal *x2)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    integer i__, j, igap;
+    doublereal temp;
+
+
+/*     %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+       %---------------%   
+       | Local Scalars |   
+       %---------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    igap = *n / 2;
+
+    if (s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X1 is sorted into decreasing order of algebraic. */
+
+L10:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L20:
+
+	    if (j < 0) {
+		goto L30;
+	    }
+
+	    if (x1[j] < x1[j + igap]) {
+		temp = x1[j];
+		x1[j] = x1[j + igap];
+		x1[j + igap] = temp;
+		if (*apply) {
+		    temp = x2[j];
+		    x2[j] = x2[j + igap];
+		    x2[j + igap] = temp;
+		}
+	    } else {
+		goto L30;
+	    }
+	    j -= igap;
+	    goto L20;
+L30:
+	    ;
+	}
+	igap /= 2;
+	goto L10;
+
+    } else if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X1 is sorted into decreasing order of magnitude. */
+
+L40:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L50:
+
+	    if (j < 0) {
+		goto L60;
+	    }
+
+	    if ((d__1 = x1[j], abs(d__1)) < (d__2 = x1[j + igap], abs(d__2))) 
+		    {
+		temp = x1[j];
+		x1[j] = x1[j + igap];
+		x1[j + igap] = temp;
+		if (*apply) {
+		    temp = x2[j];
+		    x2[j] = x2[j + igap];
+		    x2[j + igap] = temp;
+		}
+	    } else {
+		goto L60;
+	    }
+	    j -= igap;
+	    goto L50;
+L60:
+	    ;
+	}
+	igap /= 2;
+	goto L40;
+
+    } else if (s_cmp(which, "LA", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X1 is sorted into increasing order of algebraic. */
+
+L70:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L80:
+
+	    if (j < 0) {
+		goto L90;
+	    }
+
+	    if (x1[j] > x1[j + igap]) {
+		temp = x1[j];
+		x1[j] = x1[j + igap];
+		x1[j + igap] = temp;
+		if (*apply) {
+		    temp = x2[j];
+		    x2[j] = x2[j + igap];
+		    x2[j + igap] = temp;
+		}
+	    } else {
+		goto L90;
+	    }
+	    j -= igap;
+	    goto L80;
+L90:
+	    ;
+	}
+	igap /= 2;
+	goto L70;
+
+    } else if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
+
+/*        X1 is sorted into increasing order of magnitude. */
+
+L100:
+	if (igap == 0) {
+	    goto L9000;
+	}
+	i__1 = *n - 1;
+	for (i__ = igap; i__ <= i__1; ++i__) {
+	    j = i__ - igap;
+L110:
+
+	    if (j < 0) {
+		goto L120;
+	    }
+
+	    if ((d__1 = x1[j], abs(d__1)) > (d__2 = x1[j + igap], abs(d__2))) 
+		    {
+		temp = x1[j];
+		x1[j] = x1[j + igap];
+		x1[j + igap] = temp;
+		if (*apply) {
+		    temp = x2[j];
+		    x2[j] = x2[j + igap];
+		    x2[j + igap] = temp;
+		}
+	    } else {
+		goto L120;
+	    }
+	    j -= igap;
+	    goto L110;
+L120:
+	    ;
+	}
+	igap /= 2;
+	goto L100;
+    }
+
+L9000:
+    return 0;
+
+/*     %---------------%   
+       | End of dsortr |   
+       %---------------% */
+
+} /* igraphdsortr_ */
+
diff --git a/src/lapack/dstatn.c b/src/lapack/dstatn.c
new file mode 100644
index 0000000..70df288
--- /dev/null
+++ b/src/lapack/dstatn.c
@@ -0,0 +1,83 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+
+/*     %---------------------------------------------%   
+       | Initialize statistic and timing information |   
+       | for nonsymmetric Arnoldi code.              |   
+       %---------------------------------------------%   
+
+   \Author   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \SCCS Information: @(#)   
+   FILE: statn.F   SID: 2.4   DATE OF SID: 4/20/96   RELEASE: 2   
+
+   Subroutine */ int igraphdstatn_(void)
+{
+    integer nbx, nopx;
+    real trvec, tmvbx, tnaup2, tgetv0, tneigh;
+    integer nitref;
+    real tnaupd, titref, tnaitr, tngets, tnapps, tnconv;
+    integer nrorth, nrstrt;
+    real tmvopx;
+
+
+/*     %--------------------------------%   
+       | See stat.doc for documentation |   
+       %--------------------------------%   
+
+
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+
+    nopx = 0;
+    nbx = 0;
+    nrorth = 0;
+    nitref = 0;
+    nrstrt = 0;
+
+    tnaupd = 0.f;
+    tnaup2 = 0.f;
+    tnaitr = 0.f;
+    tneigh = 0.f;
+    tngets = 0.f;
+    tnapps = 0.f;
+    tnconv = 0.f;
+    titref = 0.f;
+    tgetv0 = 0.f;
+    trvec = 0.f;
+
+/*     %----------------------------------------------------%   
+       | User time including reverse communication overhead |   
+       %----------------------------------------------------% */
+
+    tmvopx = 0.f;
+    tmvbx = 0.f;
+
+    return 0;
+
+
+/*     %---------------%   
+       | End of dstatn |   
+       %---------------% */
+
+} /* igraphdstatn_ */
+
diff --git a/src/lapack/dstats.c b/src/lapack/dstats.c
new file mode 100644
index 0000000..c5d95cd
--- /dev/null
+++ b/src/lapack/dstats.c
@@ -0,0 +1,64 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+
+/* \SCCS Information: @(#)   
+   FILE: stats.F   SID: 2.1   DATE OF SID: 4/19/96   RELEASE: 2   
+       %---------------------------------------------%   
+       | Initialize statistic and timing information |   
+       | for symmetric Arnoldi code.                 |   
+       %---------------------------------------------%   
+   Subroutine */ int igraphdstats_(void)
+{
+    integer nbx, nopx;
+    real trvec, tmvbx, tgetv0, tsaup2;
+    integer nitref;
+    real titref, tseigt, tsaupd, tsaitr, tsgets, tsapps;
+    integer nrorth;
+    real tsconv;
+    integer nrstrt;
+    real tmvopx;
+
+/*     %--------------------------------%   
+       | See stat.doc for documentation |   
+       %--------------------------------%   
+       %-----------------------%   
+       | Executable Statements |   
+       %-----------------------% */
+    nopx = 0;
+    nbx = 0;
+    nrorth = 0;
+    nitref = 0;
+    nrstrt = 0;
+    tsaupd = 0.f;
+    tsaup2 = 0.f;
+    tsaitr = 0.f;
+    tseigt = 0.f;
+    tsgets = 0.f;
+    tsapps = 0.f;
+    tsconv = 0.f;
+    titref = 0.f;
+    tgetv0 = 0.f;
+    trvec = 0.f;
+/*     %----------------------------------------------------%   
+       | User time including reverse communication overhead |   
+       %----------------------------------------------------% */
+    tmvopx = 0.f;
+    tmvbx = 0.f;
+    return 0;
+
+/*     End of dstats */
+
+} /* igraphdstats_ */
+
diff --git a/src/lapack/dstebz.c b/src/lapack/dstebz.c
new file mode 100644
index 0000000..3b7894c
--- /dev/null
+++ b/src/lapack/dstebz.c
@@ -0,0 +1,758 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__3 = 3;
+static integer c__2 = 2;
+static integer c__0 = 0;
+
+/* Subroutine */ int igraphdstebz_(char *range, char *order, integer *n, doublereal 
+	*vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, 
+	doublereal *d__, doublereal *e, integer *m, integer *nsplit, 
+	doublereal *w, integer *iblock, integer *isplit, doublereal *work, 
+	integer *iwork, integer *info)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+    doublereal d__1, d__2, d__3, d__4, d__5;
+
+    /* Builtin functions */
+    double sqrt(doublereal), log(doublereal);
+
+    /* Local variables */
+    integer j, ib, jb, ie, je, nb;
+    doublereal gl;
+    integer im, in;
+    doublereal gu;
+    integer iw;
+    doublereal wl, wu;
+    integer nwl;
+    doublereal ulp, wlu, wul;
+    integer nwu;
+    doublereal tmp1, tmp2;
+    integer iend, ioff, iout, itmp1, jdisc;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo;
+    doublereal atoli;
+    integer iwoff;
+    doublereal bnorm;
+    integer itmax;
+    doublereal wkill, rtoli, tnorm;
+    extern doublereal igraphdlamch_(char *);
+    integer ibegin;
+    extern /* Subroutine */ int igraphdlaebz_(integer *, integer *, integer *, 
+	    integer *, integer *, integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, integer *,
+	     doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *);
+    integer irange, idiscl;
+    doublereal safemn;
+    integer idumma[1];
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    integer idiscu, iorder;
+    logical ncnvrg;
+    doublereal pivmin;
+    logical toofew;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+       8-18-00:  Increase FUDGE factor for T3E (eca)   
+
+
+    Purpose   
+    =======   
+
+    DSTEBZ computes the eigenvalues of a symmetric tridiagonal   
+    matrix T.  The user may ask for all eigenvalues, all eigenvalues   
+    in the half-open interval (VL, VU], or the IL-th through IU-th   
+    eigenvalues.   
+
+    To avoid overflow, the matrix must be scaled so that its   
+    largest element is no greater than overflow**(1/2) *   
+    underflow**(1/4) in absolute value, and for greatest   
+    accuracy, it should not be much smaller than that.   
+
+    See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal   
+    Matrix", Report CS41, Computer Science Dept., Stanford   
+    University, July 21, 1966.   
+
+    Arguments   
+    =========   
+
+    RANGE   (input) CHARACTER*1   
+            = 'A': ("All")   all eigenvalues will be found.   
+            = 'V': ("Value") all eigenvalues in the half-open interval   
+                             (VL, VU] will be found.   
+            = 'I': ("Index") the IL-th through IU-th eigenvalues (of the   
+                             entire matrix) will be found.   
+
+    ORDER   (input) CHARACTER*1   
+            = 'B': ("By Block") the eigenvalues will be grouped by   
+                                split-off block (see IBLOCK, ISPLIT) and   
+                                ordered from smallest to largest within   
+                                the block.   
+            = 'E': ("Entire matrix")   
+                                the eigenvalues for the entire matrix   
+                                will be ordered from smallest to   
+                                largest.   
+
+    N       (input) INTEGER   
+            The order of the tridiagonal matrix T.  N >= 0.   
+
+    VL      (input) DOUBLE PRECISION   
+    VU      (input) DOUBLE PRECISION   
+            If RANGE='V', the lower and upper bounds of the interval to   
+            be searched for eigenvalues.  Eigenvalues less than or equal   
+            to VL, or greater than VU, will not be returned.  VL < VU.   
+            Not referenced if RANGE = 'A' or 'I'.   
+
+    IL      (input) INTEGER   
+    IU      (input) INTEGER   
+            If RANGE='I', the indices (in ascending order) of the   
+            smallest and largest eigenvalues to be returned.   
+            1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.   
+            Not referenced if RANGE = 'A' or 'V'.   
+
+    ABSTOL  (input) DOUBLE PRECISION   
+            The absolute tolerance for the eigenvalues.  An eigenvalue   
+            (or cluster) is considered to be located if it has been   
+            determined to lie in an interval whose width is ABSTOL or   
+            less.  If ABSTOL is less than or equal to zero, then ULP*|T|   
+            will be used, where |T| means the 1-norm of T.   
+
+            Eigenvalues will be computed most accurately when ABSTOL is   
+            set to twice the underflow threshold 2*DLAMCH('S'), not zero.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The n diagonal elements of the tridiagonal matrix T.   
+
+    E       (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (n-1) off-diagonal elements of the tridiagonal matrix T.   
+
+    M       (output) INTEGER   
+            The actual number of eigenvalues found. 0 <= M <= N.   
+            (See also the description of INFO=2,3.)   
+
+    NSPLIT  (output) INTEGER   
+            The number of diagonal blocks in the matrix T.   
+            1 <= NSPLIT <= N.   
+
+    W       (output) DOUBLE PRECISION array, dimension (N)   
+            On exit, the first M elements of W will contain the   
+            eigenvalues.  (DSTEBZ may use the remaining N-M elements as   
+            workspace.)   
+
+    IBLOCK  (output) INTEGER array, dimension (N)   
+            At each row/column j where E(j) is zero or small, the   
+            matrix T is considered to split into a block diagonal   
+            matrix.  On exit, if INFO = 0, IBLOCK(i) specifies to which   
+            block (from 1 to the number of blocks) the eigenvalue W(i)   
+            belongs.  (DSTEBZ may use the remaining N-M elements as   
+            workspace.)   
+
+    ISPLIT  (output) INTEGER array, dimension (N)   
+            The splitting points, at which T breaks up into submatrices.   
+            The first submatrix consists of rows/columns 1 to ISPLIT(1),   
+            the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),   
+            etc., and the NSPLIT-th consists of rows/columns   
+            ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.   
+            (Only the first NSPLIT elements will actually be used, but   
+            since the user cannot know a priori what value NSPLIT will   
+            have, N words must be reserved for ISPLIT.)   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (4*N)   
+
+    IWORK   (workspace) INTEGER array, dimension (3*N)   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  some or all of the eigenvalues failed to converge or   
+                  were not computed:   
+                  =1 or 3: Bisection failed to converge for some   
+                          eigenvalues; these eigenvalues are flagged by a   
+                          negative block number.  The effect is that the   
+                          eigenvalues may not be as accurate as the   
+                          absolute and relative tolerances.  This is   
+                          generally caused by unexpectedly inaccurate   
+                          arithmetic.   
+                  =2 or 3: RANGE='I' only: Not all of the eigenvalues   
+                          IL:IU were found.   
+                          Effect: M < IU+1-IL   
+                          Cause:  non-monotonic arithmetic, causing the   
+                                  Sturm sequence to be non-monotonic.   
+                          Cure:   recalculate, using RANGE='A', and pick   
+                                  out eigenvalues IL:IU.  In some cases,   
+                                  increasing the PARAMETER "FUDGE" may   
+                                  make things work.   
+                  = 4:    RANGE='I', and the Gershgorin interval   
+                          initially used was too small.  No eigenvalues   
+                          were computed.   
+                          Probable cause: your machine has sloppy   
+                                          floating-point arithmetic.   
+                          Cure: Increase the PARAMETER "FUDGE",   
+                                recompile, and try again.   
+
+    Internal Parameters   
+    ===================   
+
+    RELFAC  DOUBLE PRECISION, default = 2.0e0   
+            The relative tolerance.  An interval (a,b] lies within   
+            "relative tolerance" if  b-a < RELFAC*ulp*max(|a|,|b|),   
+            where "ulp" is the machine precision (distance from 1 to   
+            the next larger floating point number.)   
+
+    FUDGE   DOUBLE PRECISION, default = 2   
+            A "fudge factor" to widen the Gershgorin intervals.  Ideally,   
+            a value of 1 should work, but on machines with sloppy   
+            arithmetic, this needs to be larger.  The default for   
+            publicly released versions should be large enough to handle   
+            the worst machine around.  Note that this has no effect   
+            on accuracy of the solution.   
+
+    =====================================================================   
+
+
+       Parameter adjustments */
+    --iwork;
+    --work;
+    --isplit;
+    --iblock;
+    --w;
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+
+/*     Decode RANGE */
+
+    if (igraphlsame_(range, "A")) {
+	irange = 1;
+    } else if (igraphlsame_(range, "V")) {
+	irange = 2;
+    } else if (igraphlsame_(range, "I")) {
+	irange = 3;
+    } else {
+	irange = 0;
+    }
+
+/*     Decode ORDER */
+
+    if (igraphlsame_(order, "B")) {
+	iorder = 2;
+    } else if (igraphlsame_(order, "E")) {
+	iorder = 1;
+    } else {
+	iorder = 0;
+    }
+
+/*     Check for Errors */
+
+    if (irange <= 0) {
+	*info = -1;
+    } else if (iorder <= 0) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -3;
+    } else if (irange == 2) {
+	if (*vl >= *vu) {
+	    *info = -5;
+	}
+    } else if (irange == 3 && (*il < 1 || *il > max(1,*n))) {
+	*info = -6;
+    } else if (irange == 3 && (*iu < min(*n,*il) || *iu > *n)) {
+	*info = -7;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DSTEBZ", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Initialize error flags */
+
+    *info = 0;
+    ncnvrg = FALSE_;
+    toofew = FALSE_;
+
+/*     Quick return if possible */
+
+    *m = 0;
+    if (*n == 0) {
+	return 0;
+    }
+
+/*     Simplifications: */
+
+    if (irange == 3 && *il == 1 && *iu == *n) {
+	irange = 1;
+    }
+
+/*     Get machine constants   
+       NB is the minimum vector length for vector bisection, or 0   
+       if only scalar is to be done. */
+
+    safemn = igraphdlamch_("S");
+    ulp = igraphdlamch_("P");
+    rtoli = ulp * 2.;
+    nb = igraphilaenv_(&c__1, "DSTEBZ", " ", n, &c_n1, &c_n1, &c_n1, (ftnlen)6, (
+	    ftnlen)1);
+    if (nb <= 1) {
+	nb = 0;
+    }
+
+/*     Special Case when N=1 */
+
+    if (*n == 1) {
+	*nsplit = 1;
+	isplit[1] = 1;
+	if (irange == 2 && (*vl >= d__[1] || *vu < d__[1])) {
+	    *m = 0;
+	} else {
+	    w[1] = d__[1];
+	    iblock[1] = 1;
+	    *m = 1;
+	}
+	return 0;
+    }
+
+/*     Compute Splitting Points */
+
+    *nsplit = 1;
+    work[*n] = 0.;
+    pivmin = 1.;
+
+    i__1 = *n;
+    for (j = 2; j <= i__1; ++j) {
+/* Computing 2nd power */
+	d__1 = e[j - 1];
+	tmp1 = d__1 * d__1;
+/* Computing 2nd power */
+	d__2 = ulp;
+	if ((d__1 = d__[j] * d__[j - 1], abs(d__1)) * (d__2 * d__2) + safemn 
+		> tmp1) {
+	    isplit[*nsplit] = j - 1;
+	    ++(*nsplit);
+	    work[j - 1] = 0.;
+	} else {
+	    work[j - 1] = tmp1;
+	    pivmin = max(pivmin,tmp1);
+	}
+/* L10: */
+    }
+    isplit[*nsplit] = *n;
+    pivmin *= safemn;
+
+/*     Compute Interval and ATOLI */
+
+    if (irange == 3) {
+
+/*        RANGE='I': Compute the interval containing eigenvalues   
+                     IL through IU.   
+
+          Compute Gershgorin interval for entire (split) matrix   
+          and use it as the initial interval */
+
+	gu = d__[1];
+	gl = d__[1];
+	tmp1 = 0.;
+
+	i__1 = *n - 1;
+	for (j = 1; j <= i__1; ++j) {
+	    tmp2 = sqrt(work[j]);
+/* Computing MAX */
+	    d__1 = gu, d__2 = d__[j] + tmp1 + tmp2;
+	    gu = max(d__1,d__2);
+/* Computing MIN */
+	    d__1 = gl, d__2 = d__[j] - tmp1 - tmp2;
+	    gl = min(d__1,d__2);
+	    tmp1 = tmp2;
+/* L20: */
+	}
+
+/* Computing MAX */
+	d__1 = gu, d__2 = d__[*n] + tmp1;
+	gu = max(d__1,d__2);
+/* Computing MIN */
+	d__1 = gl, d__2 = d__[*n] - tmp1;
+	gl = min(d__1,d__2);
+/* Computing MAX */
+	d__1 = abs(gl), d__2 = abs(gu);
+	tnorm = max(d__1,d__2);
+	gl = gl - tnorm * 2.1 * ulp * *n - pivmin * 4.2000000000000002;
+	gu = gu + tnorm * 2.1 * ulp * *n + pivmin * 2.1;
+
+/*        Compute Iteration parameters */
+
+	itmax = (integer) ((log(tnorm + pivmin) - log(pivmin)) / log(2.)) + 2;
+	if (*abstol <= 0.) {
+	    atoli = ulp * tnorm;
+	} else {
+	    atoli = *abstol;
+	}
+
+	work[*n + 1] = gl;
+	work[*n + 2] = gl;
+	work[*n + 3] = gu;
+	work[*n + 4] = gu;
+	work[*n + 5] = gl;
+	work[*n + 6] = gu;
+	iwork[1] = -1;
+	iwork[2] = -1;
+	iwork[3] = *n + 1;
+	iwork[4] = *n + 1;
+	iwork[5] = *il - 1;
+	iwork[6] = *iu;
+
+	igraphdlaebz_(&c__3, &itmax, n, &c__2, &c__2, &nb, &atoli, &rtoli, &pivmin, 
+		&d__[1], &e[1], &work[1], &iwork[5], &work[*n + 1], &work[*n 
+		+ 5], &iout, &iwork[1], &w[1], &iblock[1], &iinfo);
+
+	if (iwork[6] == *iu) {
+	    wl = work[*n + 1];
+	    wlu = work[*n + 3];
+	    nwl = iwork[1];
+	    wu = work[*n + 4];
+	    wul = work[*n + 2];
+	    nwu = iwork[4];
+	} else {
+	    wl = work[*n + 2];
+	    wlu = work[*n + 4];
+	    nwl = iwork[2];
+	    wu = work[*n + 3];
+	    wul = work[*n + 1];
+	    nwu = iwork[3];
+	}
+
+	if (nwl < 0 || nwl >= *n || nwu < 1 || nwu > *n) {
+	    *info = 4;
+	    return 0;
+	}
+    } else {
+
+/*        RANGE='A' or 'V' -- Set ATOLI   
+
+   Computing MAX */
+	d__3 = abs(d__[1]) + abs(e[1]), d__4 = (d__1 = d__[*n], abs(d__1)) + (
+		d__2 = e[*n - 1], abs(d__2));
+	tnorm = max(d__3,d__4);
+
+	i__1 = *n - 1;
+	for (j = 2; j <= i__1; ++j) {
+/* Computing MAX */
+	    d__4 = tnorm, d__5 = (d__1 = d__[j], abs(d__1)) + (d__2 = e[j - 1]
+		    , abs(d__2)) + (d__3 = e[j], abs(d__3));
+	    tnorm = max(d__4,d__5);
+/* L30: */
+	}
+
+	if (*abstol <= 0.) {
+	    atoli = ulp * tnorm;
+	} else {
+	    atoli = *abstol;
+	}
+
+	if (irange == 2) {
+	    wl = *vl;
+	    wu = *vu;
+	} else {
+	    wl = 0.;
+	    wu = 0.;
+	}
+    }
+
+/*     Find Eigenvalues -- Loop Over Blocks and recompute NWL and NWU.   
+       NWL accumulates the number of eigenvalues .le. WL,   
+       NWU accumulates the number of eigenvalues .le. WU */
+
+    *m = 0;
+    iend = 0;
+    *info = 0;
+    nwl = 0;
+    nwu = 0;
+
+    i__1 = *nsplit;
+    for (jb = 1; jb <= i__1; ++jb) {
+	ioff = iend;
+	ibegin = ioff + 1;
+	iend = isplit[jb];
+	in = iend - ioff;
+
+	if (in == 1) {
+
+/*           Special Case -- IN=1 */
+
+	    if (irange == 1 || wl >= d__[ibegin] - pivmin) {
+		++nwl;
+	    }
+	    if (irange == 1 || wu >= d__[ibegin] - pivmin) {
+		++nwu;
+	    }
+	    if (irange == 1 || wl < d__[ibegin] - pivmin && wu >= d__[ibegin] 
+		    - pivmin) {
+		++(*m);
+		w[*m] = d__[ibegin];
+		iblock[*m] = jb;
+	    }
+	} else {
+
+/*           General Case -- IN > 1   
+
+             Compute Gershgorin Interval   
+             and use it as the initial interval */
+
+	    gu = d__[ibegin];
+	    gl = d__[ibegin];
+	    tmp1 = 0.;
+
+	    i__2 = iend - 1;
+	    for (j = ibegin; j <= i__2; ++j) {
+		tmp2 = (d__1 = e[j], abs(d__1));
+/* Computing MAX */
+		d__1 = gu, d__2 = d__[j] + tmp1 + tmp2;
+		gu = max(d__1,d__2);
+/* Computing MIN */
+		d__1 = gl, d__2 = d__[j] - tmp1 - tmp2;
+		gl = min(d__1,d__2);
+		tmp1 = tmp2;
+/* L40: */
+	    }
+
+/* Computing MAX */
+	    d__1 = gu, d__2 = d__[iend] + tmp1;
+	    gu = max(d__1,d__2);
+/* Computing MIN */
+	    d__1 = gl, d__2 = d__[iend] - tmp1;
+	    gl = min(d__1,d__2);
+/* Computing MAX */
+	    d__1 = abs(gl), d__2 = abs(gu);
+	    bnorm = max(d__1,d__2);
+	    gl = gl - bnorm * 2.1 * ulp * in - pivmin * 2.1;
+	    gu = gu + bnorm * 2.1 * ulp * in + pivmin * 2.1;
+
+/*           Compute ATOLI for the current submatrix */
+
+	    if (*abstol <= 0.) {
+/* Computing MAX */
+		d__1 = abs(gl), d__2 = abs(gu);
+		atoli = ulp * max(d__1,d__2);
+	    } else {
+		atoli = *abstol;
+	    }
+
+	    if (irange > 1) {
+		if (gu < wl) {
+		    nwl += in;
+		    nwu += in;
+		    goto L70;
+		}
+		gl = max(gl,wl);
+		gu = min(gu,wu);
+		if (gl >= gu) {
+		    goto L70;
+		}
+	    }
+
+/*           Set Up Initial Interval */
+
+	    work[*n + 1] = gl;
+	    work[*n + in + 1] = gu;
+	    igraphdlaebz_(&c__1, &c__0, &in, &in, &c__1, &nb, &atoli, &rtoli, &
+		    pivmin, &d__[ibegin], &e[ibegin], &work[ibegin], idumma, &
+		    work[*n + 1], &work[*n + (in << 1) + 1], &im, &iwork[1], &
+		    w[*m + 1], &iblock[*m + 1], &iinfo);
+
+	    nwl += iwork[1];
+	    nwu += iwork[in + 1];
+	    iwoff = *m - iwork[1];
+
+/*           Compute Eigenvalues */
+
+	    itmax = (integer) ((log(gu - gl + pivmin) - log(pivmin)) / log(2.)
+		    ) + 2;
+	    igraphdlaebz_(&c__2, &itmax, &in, &in, &c__1, &nb, &atoli, &rtoli, &
+		    pivmin, &d__[ibegin], &e[ibegin], &work[ibegin], idumma, &
+		    work[*n + 1], &work[*n + (in << 1) + 1], &iout, &iwork[1],
+		     &w[*m + 1], &iblock[*m + 1], &iinfo);
+
+/*           Copy Eigenvalues Into W and IBLOCK   
+             Use -JB for block number for unconverged eigenvalues. */
+
+	    i__2 = iout;
+	    for (j = 1; j <= i__2; ++j) {
+		tmp1 = (work[j + *n] + work[j + in + *n]) * .5;
+
+/*              Flag non-convergence. */
+
+		if (j > iout - iinfo) {
+		    ncnvrg = TRUE_;
+		    ib = -jb;
+		} else {
+		    ib = jb;
+		}
+		i__3 = iwork[j + in] + iwoff;
+		for (je = iwork[j] + 1 + iwoff; je <= i__3; ++je) {
+		    w[je] = tmp1;
+		    iblock[je] = ib;
+/* L50: */
+		}
+/* L60: */
+	    }
+
+	    *m += im;
+	}
+L70:
+	;
+    }
+
+/*     If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU   
+       If NWL+1 < IL or NWU > IU, discard extra eigenvalues. */
+
+    if (irange == 3) {
+	im = 0;
+	idiscl = *il - 1 - nwl;
+	idiscu = nwu - *iu;
+
+	if (idiscl > 0 || idiscu > 0) {
+	    i__1 = *m;
+	    for (je = 1; je <= i__1; ++je) {
+		if (w[je] <= wlu && idiscl > 0) {
+		    --idiscl;
+		} else if (w[je] >= wul && idiscu > 0) {
+		    --idiscu;
+		} else {
+		    ++im;
+		    w[im] = w[je];
+		    iblock[im] = iblock[je];
+		}
+/* L80: */
+	    }
+	    *m = im;
+	}
+	if (idiscl > 0 || idiscu > 0) {
+
+/*           Code to deal with effects of bad arithmetic:   
+             Some low eigenvalues to be discarded are not in (WL,WLU],   
+             or high eigenvalues to be discarded are not in (WUL,WU]   
+             so just kill off the smallest IDISCL/largest IDISCU   
+             eigenvalues, by simply finding the smallest/largest   
+             eigenvalue(s).   
+
+             (If N(w) is monotone non-decreasing, this should never   
+                 happen.) */
+
+	    if (idiscl > 0) {
+		wkill = wu;
+		i__1 = idiscl;
+		for (jdisc = 1; jdisc <= i__1; ++jdisc) {
+		    iw = 0;
+		    i__2 = *m;
+		    for (je = 1; je <= i__2; ++je) {
+			if (iblock[je] != 0 && (w[je] < wkill || iw == 0)) {
+			    iw = je;
+			    wkill = w[je];
+			}
+/* L90: */
+		    }
+		    iblock[iw] = 0;
+/* L100: */
+		}
+	    }
+	    if (idiscu > 0) {
+
+		wkill = wl;
+		i__1 = idiscu;
+		for (jdisc = 1; jdisc <= i__1; ++jdisc) {
+		    iw = 0;
+		    i__2 = *m;
+		    for (je = 1; je <= i__2; ++je) {
+			if (iblock[je] != 0 && (w[je] > wkill || iw == 0)) {
+			    iw = je;
+			    wkill = w[je];
+			}
+/* L110: */
+		    }
+		    iblock[iw] = 0;
+/* L120: */
+		}
+	    }
+	    im = 0;
+	    i__1 = *m;
+	    for (je = 1; je <= i__1; ++je) {
+		if (iblock[je] != 0) {
+		    ++im;
+		    w[im] = w[je];
+		    iblock[im] = iblock[je];
+		}
+/* L130: */
+	    }
+	    *m = im;
+	}
+	if (idiscl < 0 || idiscu < 0) {
+	    toofew = TRUE_;
+	}
+    }
+
+/*     If ORDER='B', do nothing -- the eigenvalues are already sorted   
+          by block.   
+       If ORDER='E', sort the eigenvalues from smallest to largest */
+
+    if (iorder == 1 && *nsplit > 1) {
+	i__1 = *m - 1;
+	for (je = 1; je <= i__1; ++je) {
+	    ie = 0;
+	    tmp1 = w[je];
+	    i__2 = *m;
+	    for (j = je + 1; j <= i__2; ++j) {
+		if (w[j] < tmp1) {
+		    ie = j;
+		    tmp1 = w[j];
+		}
+/* L140: */
+	    }
+
+	    if (ie != 0) {
+		itmp1 = iblock[ie];
+		w[ie] = w[je];
+		iblock[ie] = iblock[je];
+		w[je] = tmp1;
+		iblock[je] = itmp1;
+	    }
+/* L150: */
+	}
+    }
+
+    *info = 0;
+    if (ncnvrg) {
+	++(*info);
+    }
+    if (toofew) {
+	*info += 2;
+    }
+    return 0;
+
+/*     End of DSTEBZ */
+
+} /* igraphdstebz_ */
+
diff --git a/src/lapack/dstein.c b/src/lapack/dstein.c
new file mode 100644
index 0000000..e4a3156
--- /dev/null
+++ b/src/lapack/dstein.c
@@ -0,0 +1,436 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__2 = 2;
+static integer c__1 = 1;
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdstein_(integer *n, doublereal *d__, doublereal *e, 
+	integer *m, doublereal *w, integer *iblock, integer *isplit, 
+	doublereal *z__, integer *ldz, doublereal *work, integer *iwork, 
+	integer *ifail, integer *info)
+{
+    /* System generated locals */
+    integer z_dim1, z_offset, i__1, i__2, i__3;
+    doublereal d__1, d__2, d__3, d__4, d__5;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, b1, j1, bn;
+    doublereal xj, scl, eps, sep, nrm, tol;
+    integer its;
+    doublereal xjm, ztr, eps1;
+    integer jblk, nblk;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    integer jmax;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    integer iseed[4], gpind, iinfo;
+    extern doublereal igraphdasum_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdaxpy_(integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *);
+    doublereal ortol;
+    integer indrv1, indrv2, indrv3, indrv4, indrv5;
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlagtf_(integer *, doublereal *, doublereal *,
+	     doublereal *, doublereal *, doublereal *, doublereal *, integer *
+	    , integer *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen), igraphdlagts_(
+	    integer *, integer *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, integer *, doublereal *, doublereal *, integer *);
+    integer nrmchk;
+    extern /* Subroutine */ int igraphdlarnv_(integer *, integer *, integer *, 
+	    doublereal *);
+    integer blksiz;
+    doublereal onenrm, dtpcrt, pertol;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DSTEIN computes the eigenvectors of a real symmetric tridiagonal   
+    matrix T corresponding to specified eigenvalues, using inverse   
+    iteration.   
+
+    The maximum number of iterations allowed for each eigenvector is   
+    specified by an internal parameter MAXITS (currently set to 5).   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix.  N >= 0.   
+
+    D       (input) DOUBLE PRECISION array, dimension (N)   
+            The n diagonal elements of the tridiagonal matrix T.   
+
+    E       (input) DOUBLE PRECISION array, dimension (N-1)   
+            The (n-1) subdiagonal elements of the tridiagonal matrix   
+            T, in elements 1 to N-1.   
+
+    M       (input) INTEGER   
+            The number of eigenvectors to be found.  0 <= M <= N.   
+
+    W       (input) DOUBLE PRECISION array, dimension (N)   
+            The first M elements of W contain the eigenvalues for   
+            which eigenvectors are to be computed.  The eigenvalues   
+            should be grouped by split-off block and ordered from   
+            smallest to largest within the block.  ( The output array   
+            W from DSTEBZ with ORDER = 'B' is expected here. )   
+
+    IBLOCK  (input) INTEGER array, dimension (N)   
+            The submatrix indices associated with the corresponding   
+            eigenvalues in W; IBLOCK(i)=1 if eigenvalue W(i) belongs to   
+            the first submatrix from the top, =2 if W(i) belongs to   
+            the second submatrix, etc.  ( The output array IBLOCK   
+            from DSTEBZ is expected here. )   
+
+    ISPLIT  (input) INTEGER array, dimension (N)   
+            The splitting points, at which T breaks up into submatrices.   
+            The first submatrix consists of rows/columns 1 to   
+            ISPLIT( 1 ), the second of rows/columns ISPLIT( 1 )+1   
+            through ISPLIT( 2 ), etc.   
+            ( The output array ISPLIT from DSTEBZ is expected here. )   
+
+    Z       (output) DOUBLE PRECISION array, dimension (LDZ, M)   
+            The computed eigenvectors.  The eigenvector associated   
+            with the eigenvalue W(i) is stored in the i-th column of   
+            Z.  Any vector which fails to converge is set to its current   
+            iterate after MAXITS iterations.   
+
+    LDZ     (input) INTEGER   
+            The leading dimension of the array Z.  LDZ >= max(1,N).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (5*N)   
+
+    IWORK   (workspace) INTEGER array, dimension (N)   
+
+    IFAIL   (output) INTEGER array, dimension (M)   
+            On normal exit, all elements of IFAIL are zero.   
+            If one or more eigenvectors fail to converge after   
+            MAXITS iterations, then their indices are stored in   
+            array IFAIL.   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit.   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+            > 0: if INFO = i, then i eigenvectors failed to converge   
+                 in MAXITS iterations.  Their indices are stored in   
+                 array IFAIL.   
+
+    Internal Parameters   
+    ===================   
+
+    MAXITS  INTEGER, default = 5   
+            The maximum number of iterations performed.   
+
+    EXTRA   INTEGER, default = 2   
+            The number of iterations performed after norm growth   
+            criterion is satisfied, should be at least 1.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    --d__;
+    --e;
+    --w;
+    --iblock;
+    --isplit;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --work;
+    --iwork;
+    --ifail;
+
+    /* Function Body */
+    *info = 0;
+    i__1 = *m;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	ifail[i__] = 0;
+/* L10: */
+    }
+
+    if (*n < 0) {
+	*info = -1;
+    } else if (*m < 0 || *m > *n) {
+	*info = -4;
+    } else if (*ldz < max(1,*n)) {
+	*info = -9;
+    } else {
+	i__1 = *m;
+	for (j = 2; j <= i__1; ++j) {
+	    if (iblock[j] < iblock[j - 1]) {
+		*info = -6;
+		goto L30;
+	    }
+	    if (iblock[j] == iblock[j - 1] && w[j] < w[j - 1]) {
+		*info = -5;
+		goto L30;
+	    }
+/* L20: */
+	}
+L30:
+	;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DSTEIN", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0 || *m == 0) {
+	return 0;
+    } else if (*n == 1) {
+	z__[z_dim1 + 1] = 1.;
+	return 0;
+    }
+
+/*     Get machine constants. */
+
+    eps = igraphdlamch_("Precision");
+
+/*     Initialize seed for random number generator DLARNV. */
+
+    for (i__ = 1; i__ <= 4; ++i__) {
+	iseed[i__ - 1] = 1;
+/* L40: */
+    }
+
+/*     Initialize pointers. */
+
+    indrv1 = 0;
+    indrv2 = indrv1 + *n;
+    indrv3 = indrv2 + *n;
+    indrv4 = indrv3 + *n;
+    indrv5 = indrv4 + *n;
+
+/*     Compute eigenvectors of matrix blocks. */
+
+    j1 = 1;
+    i__1 = iblock[*m];
+    for (nblk = 1; nblk <= i__1; ++nblk) {
+
+/*        Find starting and ending indices of block nblk. */
+
+	if (nblk == 1) {
+	    b1 = 1;
+	} else {
+	    b1 = isplit[nblk - 1] + 1;
+	}
+	bn = isplit[nblk];
+	blksiz = bn - b1 + 1;
+	if (blksiz == 1) {
+	    goto L60;
+	}
+	gpind = b1;
+
+/*        Compute reorthogonalization criterion and stopping criterion. */
+
+	onenrm = (d__1 = d__[b1], abs(d__1)) + (d__2 = e[b1], abs(d__2));
+/* Computing MAX */
+	d__3 = onenrm, d__4 = (d__1 = d__[bn], abs(d__1)) + (d__2 = e[bn - 1],
+		 abs(d__2));
+	onenrm = max(d__3,d__4);
+	i__2 = bn - 1;
+	for (i__ = b1 + 1; i__ <= i__2; ++i__) {
+/* Computing MAX */
+	    d__4 = onenrm, d__5 = (d__1 = d__[i__], abs(d__1)) + (d__2 = e[
+		    i__ - 1], abs(d__2)) + (d__3 = e[i__], abs(d__3));
+	    onenrm = max(d__4,d__5);
+/* L50: */
+	}
+	ortol = onenrm * .001;
+
+	dtpcrt = sqrt(.1 / blksiz);
+
+/*        Loop through eigenvalues of block nblk. */
+
+L60:
+	jblk = 0;
+	i__2 = *m;
+	for (j = j1; j <= i__2; ++j) {
+	    if (iblock[j] != nblk) {
+		j1 = j;
+		goto L160;
+	    }
+	    ++jblk;
+	    xj = w[j];
+
+/*           Skip all the work if the block size is one. */
+
+	    if (blksiz == 1) {
+		work[indrv1 + 1] = 1.;
+		goto L120;
+	    }
+
+/*           If eigenvalues j and j-1 are too close, add a relatively   
+             small perturbation. */
+
+	    if (jblk > 1) {
+		eps1 = (d__1 = eps * xj, abs(d__1));
+		pertol = eps1 * 10.;
+		sep = xj - xjm;
+		if (sep < pertol) {
+		    xj = xjm + pertol;
+		}
+	    }
+
+	    its = 0;
+	    nrmchk = 0;
+
+/*           Get random starting vector. */
+
+	    igraphdlarnv_(&c__2, iseed, &blksiz, &work[indrv1 + 1]);
+
+/*           Copy the matrix T so it won't be destroyed in factorization. */
+
+	    igraphdcopy_(&blksiz, &d__[b1], &c__1, &work[indrv4 + 1], &c__1);
+	    i__3 = blksiz - 1;
+	    igraphdcopy_(&i__3, &e[b1], &c__1, &work[indrv2 + 2], &c__1);
+	    i__3 = blksiz - 1;
+	    igraphdcopy_(&i__3, &e[b1], &c__1, &work[indrv3 + 1], &c__1);
+
+/*           Compute LU factors with partial pivoting  ( PT = LU ) */
+
+	    tol = 0.;
+	    igraphdlagtf_(&blksiz, &work[indrv4 + 1], &xj, &work[indrv2 + 2], &work[
+		    indrv3 + 1], &tol, &work[indrv5 + 1], &iwork[1], &iinfo);
+
+/*           Update iteration count. */
+
+L70:
+	    ++its;
+	    if (its > 5) {
+		goto L100;
+	    }
+
+/*           Normalize and scale the righthand side vector Pb.   
+
+   Computing MAX */
+	    d__2 = eps, d__3 = (d__1 = work[indrv4 + blksiz], abs(d__1));
+	    scl = blksiz * onenrm * max(d__2,d__3) / igraphdasum_(&blksiz, &work[
+		    indrv1 + 1], &c__1);
+	    igraphdscal_(&blksiz, &scl, &work[indrv1 + 1], &c__1);
+
+/*           Solve the system LU = Pb. */
+
+	    igraphdlagts_(&c_n1, &blksiz, &work[indrv4 + 1], &work[indrv2 + 2], &
+		    work[indrv3 + 1], &work[indrv5 + 1], &iwork[1], &work[
+		    indrv1 + 1], &tol, &iinfo);
+
+/*           Reorthogonalize by modified Gram-Schmidt if eigenvalues are   
+             close enough. */
+
+	    if (jblk == 1) {
+		goto L90;
+	    }
+	    if ((d__1 = xj - xjm, abs(d__1)) > ortol) {
+		gpind = j;
+	    }
+	    if (gpind != j) {
+		i__3 = j - 1;
+		for (i__ = gpind; i__ <= i__3; ++i__) {
+		    ztr = -igraphddot_(&blksiz, &work[indrv1 + 1], &c__1, &z__[b1 + 
+			    i__ * z_dim1], &c__1);
+		    igraphdaxpy_(&blksiz, &ztr, &z__[b1 + i__ * z_dim1], &c__1, &
+			    work[indrv1 + 1], &c__1);
+/* L80: */
+		}
+	    }
+
+/*           Check the infinity norm of the iterate. */
+
+L90:
+	    jmax = igraphidamax_(&blksiz, &work[indrv1 + 1], &c__1);
+	    nrm = (d__1 = work[indrv1 + jmax], abs(d__1));
+
+/*           Continue for additional iterations after norm reaches   
+             stopping criterion. */
+
+	    if (nrm < dtpcrt) {
+		goto L70;
+	    }
+	    ++nrmchk;
+	    if (nrmchk < 3) {
+		goto L70;
+	    }
+
+	    goto L110;
+
+/*           If stopping criterion was not satisfied, update info and   
+             store eigenvector number in array ifail. */
+
+L100:
+	    ++(*info);
+	    ifail[*info] = j;
+
+/*           Accept iterate as jth eigenvector. */
+
+L110:
+	    scl = 1. / igraphdnrm2_(&blksiz, &work[indrv1 + 1], &c__1);
+	    jmax = igraphidamax_(&blksiz, &work[indrv1 + 1], &c__1);
+	    if (work[indrv1 + jmax] < 0.) {
+		scl = -scl;
+	    }
+	    igraphdscal_(&blksiz, &scl, &work[indrv1 + 1], &c__1);
+L120:
+	    i__3 = *n;
+	    for (i__ = 1; i__ <= i__3; ++i__) {
+		z__[i__ + j * z_dim1] = 0.;
+/* L130: */
+	    }
+	    i__3 = blksiz;
+	    for (i__ = 1; i__ <= i__3; ++i__) {
+		z__[b1 + i__ - 1 + j * z_dim1] = work[indrv1 + i__];
+/* L140: */
+	    }
+
+/*           Save the shift to check eigenvalue spacing at next   
+             iteration. */
+
+	    xjm = xj;
+
+/* L150: */
+	}
+L160:
+	;
+    }
+
+    return 0;
+
+/*     End of DSTEIN */
+
+} /* igraphdstein_ */
+
diff --git a/src/lapack/dstemr.c b/src/lapack/dstemr.c
new file mode 100644
index 0000000..2e6c8f0
--- /dev/null
+++ b/src/lapack/dstemr.c
@@ -0,0 +1,713 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b18 = .001;
+
+/* Subroutine */ int igraphdstemr_(char *jobz, char *range, integer *n, doublereal *
+	d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, 
+	integer *iu, integer *m, doublereal *w, doublereal *z__, integer *ldz,
+	 integer *nzc, integer *isuppz, logical *tryrac, doublereal *work, 
+	integer *lwork, integer *iwork, integer *liwork, integer *info)
+{
+    /* System generated locals */
+    integer z_dim1, z_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j;
+    doublereal r1, r2;
+    integer jj;
+    doublereal cs;
+    integer in;
+    doublereal sn, wl, wu;
+    integer iil, iiu;
+    doublereal eps, tmp;
+    integer indd, iend, jblk, wend;
+    doublereal rmin, rmax;
+    integer itmp;
+    doublereal tnrm;
+    extern /* Subroutine */ int igraphdlae2_(doublereal *, doublereal *, doublereal 
+	    *, doublereal *, doublereal *);
+    integer inde2, itmp2;
+    doublereal rtol1, rtol2;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    doublereal scale;
+    integer indgp;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo, iindw, ilast;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdswap_(integer *, doublereal *, integer 
+	    *, doublereal *, integer *);
+    integer lwmin;
+    logical wantz;
+    extern /* Subroutine */ int igraphdlaev2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    logical alleig;
+    integer ibegin;
+    logical indeig;
+    integer iindbl;
+    logical valeig;
+    extern /* Subroutine */ int igraphdlarrc_(char *, integer *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, integer *,
+	     integer *, integer *, integer *), igraphdlarre_(char *, 
+	    integer *, doublereal *, doublereal *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, integer *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, integer *);
+    integer wbegin;
+    doublereal safmin;
+    extern /* Subroutine */ int igraphdlarrj_(integer *, doublereal *, doublereal *,
+	     integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, doublereal *, integer *, doublereal *, doublereal *,
+	     integer *), igraphxerbla_(char *, integer *, ftnlen);
+    doublereal bignum;
+    integer inderr, iindwk, indgrs, offset;
+    extern doublereal igraphdlanst_(char *, integer *, doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlarrr_(integer *, doublereal *, doublereal *,
+	     integer *), igraphdlarrv_(integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, integer *, integer *, 
+	    integer *, integer *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *), igraphdlasrt_(char *, integer *, doublereal *, 
+	    integer *);
+    doublereal thresh;
+    integer iinspl, ifirst, indwrk, liwmin, nzcmin;
+    doublereal pivmin;
+    integer nsplit;
+    doublereal smlnum;
+    logical lquery, zquery;
+
+
+/*  -- LAPACK computational routine (version 3.2.2)                                  --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- June 2010                                                       --   
+
+
+    Purpose   
+    =======   
+
+    DSTEMR computes selected eigenvalues and, optionally, eigenvectors   
+    of a real symmetric tridiagonal matrix T. Any such unreduced matrix has   
+    a well defined set of pairwise different real eigenvalues, the corresponding   
+    real eigenvectors are pairwise orthogonal.   
+
+    The spectrum may be computed either completely or partially by specifying   
+    either an interval (VL,VU] or a range of indices IL:IU for the desired   
+    eigenvalues.   
+
+    Depending on the number of desired eigenvalues, these are computed either   
+    by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are   
+    computed by the use of various suitable L D L^T factorizations near clusters   
+    of close eigenvalues (referred to as RRRs, Relatively Robust   
+    Representations). An informal sketch of the algorithm follows.   
+
+    For each unreduced block (submatrix) of T,   
+       (a) Compute T - sigma I  = L D L^T, so that L and D   
+           define all the wanted eigenvalues to high relative accuracy.   
+           This means that small relative changes in the entries of D and L   
+           cause only small relative changes in the eigenvalues and   
+           eigenvectors. The standard (unfactored) representation of the   
+           tridiagonal matrix T does not have this property in general.   
+       (b) Compute the eigenvalues to suitable accuracy.   
+           If the eigenvectors are desired, the algorithm attains full   
+           accuracy of the computed eigenvalues only right before   
+           the corresponding vectors have to be computed, see steps c) and d).   
+       (c) For each cluster of close eigenvalues, select a new   
+           shift close to the cluster, find a new factorization, and refine   
+           the shifted eigenvalues to suitable accuracy.   
+       (d) For each eigenvalue with a large enough relative separation compute   
+           the corresponding eigenvector by forming a rank revealing twisted   
+           factorization. Go back to (c) for any clusters that remain.   
+
+    For more details, see:   
+    - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations   
+      to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"   
+      Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.   
+    - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and   
+      Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,   
+      2004.  Also LAPACK Working Note 154.   
+    - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric   
+      tridiagonal eigenvalue/eigenvector problem",   
+      Computer Science Division Technical Report No. UCB/CSD-97-971,   
+      UC Berkeley, May 1997.   
+
+    Further Details   
+    1.DSTEMR works only on machines which follow IEEE-754   
+    floating-point standard in their handling of infinities and NaNs.   
+    This permits the use of efficient inner loops avoiding a check for   
+    zero divisors.   
+
+    Arguments   
+    =========   
+
+    JOBZ    (input) CHARACTER*1   
+            = 'N':  Compute eigenvalues only;   
+            = 'V':  Compute eigenvalues and eigenvectors.   
+
+    RANGE   (input) CHARACTER*1   
+            = 'A': all eigenvalues will be found.   
+            = 'V': all eigenvalues in the half-open interval (VL,VU]   
+                   will be found.   
+            = 'I': the IL-th through IU-th eigenvalues will be found.   
+
+    N       (input) INTEGER   
+            The order of the matrix.  N >= 0.   
+
+    D       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the N diagonal elements of the tridiagonal matrix   
+            T. On exit, D is overwritten.   
+
+    E       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the (N-1) subdiagonal elements of the tridiagonal   
+            matrix T in elements 1 to N-1 of E. E(N) need not be set on   
+            input, but is used internally as workspace.   
+            On exit, E is overwritten.   
+
+    VL      (input) DOUBLE PRECISION   
+    VU      (input) DOUBLE PRECISION   
+            If RANGE='V', the lower and upper bounds of the interval to   
+            be searched for eigenvalues. VL < VU.   
+            Not referenced if RANGE = 'A' or 'I'.   
+
+    IL      (input) INTEGER   
+    IU      (input) INTEGER   
+            If RANGE='I', the indices (in ascending order) of the   
+            smallest and largest eigenvalues to be returned.   
+            1 <= IL <= IU <= N, if N > 0.   
+            Not referenced if RANGE = 'A' or 'V'.   
+
+    M       (output) INTEGER   
+            The total number of eigenvalues found.  0 <= M <= N.   
+            If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.   
+
+    W       (output) DOUBLE PRECISION array, dimension (N)   
+            The first M elements contain the selected eigenvalues in   
+            ascending order.   
+
+    Z       (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M) )   
+            If JOBZ = 'V', and if INFO = 0, then the first M columns of Z   
+            contain the orthonormal eigenvectors of the matrix T   
+            corresponding to the selected eigenvalues, with the i-th   
+            column of Z holding the eigenvector associated with W(i).   
+            If JOBZ = 'N', then Z is not referenced.   
+            Note: the user must ensure that at least max(1,M) columns are   
+            supplied in the array Z; if RANGE = 'V', the exact value of M   
+            is not known in advance and can be computed with a workspace   
+            query by setting NZC = -1, see below.   
+
+    LDZ     (input) INTEGER   
+            The leading dimension of the array Z.  LDZ >= 1, and if   
+            JOBZ = 'V', then LDZ >= max(1,N).   
+
+    NZC     (input) INTEGER   
+            The number of eigenvectors to be held in the array Z.   
+            If RANGE = 'A', then NZC >= max(1,N).   
+            If RANGE = 'V', then NZC >= the number of eigenvalues in (VL,VU].   
+            If RANGE = 'I', then NZC >= IU-IL+1.   
+            If NZC = -1, then a workspace query is assumed; the   
+            routine calculates the number of columns of the array Z that   
+            are needed to hold the eigenvectors.   
+            This value is returned as the first entry of the Z array, and   
+            no error message related to NZC is issued by XERBLA.   
+
+    ISUPPZ  (output) INTEGER ARRAY, dimension ( 2*max(1,M) )   
+            The support of the eigenvectors in Z, i.e., the indices   
+            indicating the nonzero elements in Z. The i-th computed eigenvector   
+            is nonzero only in elements ISUPPZ( 2*i-1 ) through   
+            ISUPPZ( 2*i ). This is relevant in the case when the matrix   
+            is split. ISUPPZ is only accessed when JOBZ is 'V' and N > 0.   
+
+    TRYRAC  (input/output) LOGICAL   
+            If TRYRAC.EQ..TRUE., indicates that the code should check whether   
+            the tridiagonal matrix defines its eigenvalues to high relative   
+            accuracy.  If so, the code uses relative-accuracy preserving   
+            algorithms that might be (a bit) slower depending on the matrix.   
+            If the matrix does not define its eigenvalues to high relative   
+            accuracy, the code can uses possibly faster algorithms.   
+            If TRYRAC.EQ..FALSE., the code is not required to guarantee   
+            relatively accurate eigenvalues and can use the fastest possible   
+            techniques.   
+            On exit, a .TRUE. TRYRAC will be set to .FALSE. if the matrix   
+            does not define its eigenvalues to high relative accuracy.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (LWORK)   
+            On exit, if INFO = 0, WORK(1) returns the optimal   
+            (and minimal) LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK. LWORK >= max(1,18*N)   
+            if JOBZ = 'V', and LWORK >= max(1,12*N) if JOBZ = 'N'.   
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    IWORK   (workspace/output) INTEGER array, dimension (LIWORK)   
+            On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.   
+
+    LIWORK  (input) INTEGER   
+            The dimension of the array IWORK.  LIWORK >= max(1,10*N)   
+            if the eigenvectors are desired, and LIWORK >= max(1,8*N)   
+            if only the eigenvalues are to be computed.   
+            If LIWORK = -1, then a workspace query is assumed; the   
+            routine only calculates the optimal size of the IWORK array,   
+            returns this value as the first entry of the IWORK array, and   
+            no error message related to LIWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            On exit, INFO   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  if INFO = 1X, internal error in DLARRE,   
+                  if INFO = 2X, internal error in DLARRV.   
+                  Here, the digit X = ABS( IINFO ) < 10, where IINFO is   
+                  the nonzero error code returned by DLARRE or   
+                  DLARRV, respectively.   
+
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Beresford Parlett, University of California, Berkeley, USA   
+       Jim Demmel, University of California, Berkeley, USA   
+       Inderjit Dhillon, University of Texas, Austin, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Christof Voemel, University of California, Berkeley, USA   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    --d__;
+    --e;
+    --w;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --isuppz;
+    --work;
+    --iwork;
+
+    /* Function Body */
+    wantz = igraphlsame_(jobz, "V");
+    alleig = igraphlsame_(range, "A");
+    valeig = igraphlsame_(range, "V");
+    indeig = igraphlsame_(range, "I");
+
+    lquery = *lwork == -1 || *liwork == -1;
+    zquery = *nzc == -1;
+/*     DSTEMR needs WORK of size 6*N, IWORK of size 3*N.   
+       In addition, DLARRE needs WORK of size 6*N, IWORK of size 5*N.   
+       Furthermore, DLARRV needs WORK of size 12*N, IWORK of size 7*N. */
+    if (wantz) {
+	lwmin = *n * 18;
+	liwmin = *n * 10;
+    } else {
+/*        need less workspace if only the eigenvalues are wanted */
+	lwmin = *n * 12;
+	liwmin = *n << 3;
+    }
+    wl = 0.;
+    wu = 0.;
+    iil = 0;
+    iiu = 0;
+    if (valeig) {
+/*        We do not reference VL, VU in the cases RANGE = 'I','A'   
+          The interval (WL, WU] contains all the wanted eigenvalues.   
+          It is either given by the user or computed in DLARRE. */
+	wl = *vl;
+	wu = *vu;
+    } else if (indeig) {
+/*        We do not reference IL, IU in the cases RANGE = 'V','A' */
+	iil = *il;
+	iiu = *iu;
+    }
+
+    *info = 0;
+    if (! (wantz || igraphlsame_(jobz, "N"))) {
+	*info = -1;
+    } else if (! (alleig || valeig || indeig)) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -3;
+    } else if (valeig && *n > 0 && wu <= wl) {
+	*info = -7;
+    } else if (indeig && (iil < 1 || iil > *n)) {
+	*info = -8;
+    } else if (indeig && (iiu < iil || iiu > *n)) {
+	*info = -9;
+    } else if (*ldz < 1 || wantz && *ldz < *n) {
+	*info = -13;
+    } else if (*lwork < lwmin && ! lquery) {
+	*info = -17;
+    } else if (*liwork < liwmin && ! lquery) {
+	*info = -19;
+    }
+
+/*     Get machine constants. */
+
+    safmin = igraphdlamch_("Safe minimum");
+    eps = igraphdlamch_("Precision");
+    smlnum = safmin / eps;
+    bignum = 1. / smlnum;
+    rmin = sqrt(smlnum);
+/* Computing MIN */
+    d__1 = sqrt(bignum), d__2 = 1. / sqrt(sqrt(safmin));
+    rmax = min(d__1,d__2);
+
+    if (*info == 0) {
+	work[1] = (doublereal) lwmin;
+	iwork[1] = liwmin;
+
+	if (wantz && alleig) {
+	    nzcmin = *n;
+	} else if (wantz && valeig) {
+	    igraphdlarrc_("T", n, vl, vu, &d__[1], &e[1], &safmin, &nzcmin, &itmp, &
+		    itmp2, info);
+	} else if (wantz && indeig) {
+	    nzcmin = iiu - iil + 1;
+	} else {
+/*           WANTZ .EQ. FALSE. */
+	    nzcmin = 0;
+	}
+	if (zquery && *info == 0) {
+	    z__[z_dim1 + 1] = (doublereal) nzcmin;
+	} else if (*nzc < nzcmin && ! zquery) {
+	    *info = -14;
+	}
+    }
+    if (*info != 0) {
+
+	i__1 = -(*info);
+	igraphxerbla_("DSTEMR", &i__1, (ftnlen)6);
+
+	return 0;
+    } else if (lquery || zquery) {
+	return 0;
+    }
+
+/*     Handle N = 0, 1, and 2 cases immediately */
+
+    *m = 0;
+    if (*n == 0) {
+	return 0;
+    }
+
+    if (*n == 1) {
+	if (alleig || indeig) {
+	    *m = 1;
+	    w[1] = d__[1];
+	} else {
+	    if (wl < d__[1] && wu >= d__[1]) {
+		*m = 1;
+		w[1] = d__[1];
+	    }
+	}
+	if (wantz && ! zquery) {
+	    z__[z_dim1 + 1] = 1.;
+	    isuppz[1] = 1;
+	    isuppz[2] = 1;
+	}
+	return 0;
+    }
+
+    if (*n == 2) {
+	if (! wantz) {
+	    igraphdlae2_(&d__[1], &e[1], &d__[2], &r1, &r2);
+	} else if (wantz && ! zquery) {
+	    igraphdlaev2_(&d__[1], &e[1], &d__[2], &r1, &r2, &cs, &sn);
+	}
+	if (alleig || valeig && r2 > wl && r2 <= wu || indeig && iil == 1) {
+	    ++(*m);
+	    w[*m] = r2;
+	    if (wantz && ! zquery) {
+		z__[*m * z_dim1 + 1] = -sn;
+		z__[*m * z_dim1 + 2] = cs;
+/*              Note: At most one of SN and CS can be zero. */
+		if (sn != 0.) {
+		    if (cs != 0.) {
+			isuppz[(*m << 1) - 1] = 1;
+			isuppz[*m * 2] = 2;
+		    } else {
+			isuppz[(*m << 1) - 1] = 1;
+			isuppz[*m * 2] = 1;
+		    }
+		} else {
+		    isuppz[(*m << 1) - 1] = 2;
+		    isuppz[*m * 2] = 2;
+		}
+	    }
+	}
+	if (alleig || valeig && r1 > wl && r1 <= wu || indeig && iiu == 2) {
+	    ++(*m);
+	    w[*m] = r1;
+	    if (wantz && ! zquery) {
+		z__[*m * z_dim1 + 1] = cs;
+		z__[*m * z_dim1 + 2] = sn;
+/*              Note: At most one of SN and CS can be zero. */
+		if (sn != 0.) {
+		    if (cs != 0.) {
+			isuppz[(*m << 1) - 1] = 1;
+			isuppz[*m * 2] = 2;
+		    } else {
+			isuppz[(*m << 1) - 1] = 1;
+			isuppz[*m * 2] = 1;
+		    }
+		} else {
+		    isuppz[(*m << 1) - 1] = 2;
+		    isuppz[*m * 2] = 2;
+		}
+	    }
+	}
+	return 0;
+    }
+/*     Continue with general N */
+    indgrs = 1;
+    inderr = (*n << 1) + 1;
+    indgp = *n * 3 + 1;
+    indd = (*n << 2) + 1;
+    inde2 = *n * 5 + 1;
+    indwrk = *n * 6 + 1;
+
+    iinspl = 1;
+    iindbl = *n + 1;
+    iindw = (*n << 1) + 1;
+    iindwk = *n * 3 + 1;
+
+/*     Scale matrix to allowable range, if necessary.   
+       The allowable range is related to the PIVMIN parameter; see the   
+       comments in DLARRD.  The preference for scaling small values   
+       up is heuristic; we expect users' matrices not to be close to the   
+       RMAX threshold. */
+
+    scale = 1.;
+    tnrm = igraphdlanst_("M", n, &d__[1], &e[1]);
+    if (tnrm > 0. && tnrm < rmin) {
+	scale = rmin / tnrm;
+    } else if (tnrm > rmax) {
+	scale = rmax / tnrm;
+    }
+    if (scale != 1.) {
+	igraphdscal_(n, &scale, &d__[1], &c__1);
+	i__1 = *n - 1;
+	igraphdscal_(&i__1, &scale, &e[1], &c__1);
+	tnrm *= scale;
+	if (valeig) {
+/*           If eigenvalues in interval have to be found,   
+             scale (WL, WU] accordingly */
+	    wl *= scale;
+	    wu *= scale;
+	}
+    }
+
+/*     Compute the desired eigenvalues of the tridiagonal after splitting   
+       into smaller subblocks if the corresponding off-diagonal elements   
+       are small   
+       THRESH is the splitting parameter for DLARRE   
+       A negative THRESH forces the old splitting criterion based on the   
+       size of the off-diagonal. A positive THRESH switches to splitting   
+       which preserves relative accuracy. */
+
+    if (*tryrac) {
+/*        Test whether the matrix warrants the more expensive relative approach. */
+	igraphdlarrr_(n, &d__[1], &e[1], &iinfo);
+    } else {
+/*        The user does not care about relative accurately eigenvalues */
+	iinfo = -1;
+    }
+/*     Set the splitting criterion */
+    if (iinfo == 0) {
+	thresh = eps;
+    } else {
+	thresh = -eps;
+/*        relative accuracy is desired but T does not guarantee it */
+	*tryrac = FALSE_;
+    }
+
+    if (*tryrac) {
+/*        Copy original diagonal, needed to guarantee relative accuracy */
+	igraphdcopy_(n, &d__[1], &c__1, &work[indd], &c__1);
+    }
+/*     Store the squares of the offdiagonal values of T */
+    i__1 = *n - 1;
+    for (j = 1; j <= i__1; ++j) {
+/* Computing 2nd power */
+	d__1 = e[j];
+	work[inde2 + j - 1] = d__1 * d__1;
+/* L5: */
+    }
+/*     Set the tolerance parameters for bisection */
+    if (! wantz) {
+/*        DLARRE computes the eigenvalues to full precision. */
+	rtol1 = eps * 4.;
+	rtol2 = eps * 4.;
+    } else {
+/*        DLARRE computes the eigenvalues to less than full precision.   
+          DLARRV will refine the eigenvalue approximations, and we can   
+          need less accurate initial bisection in DLARRE.   
+          Note: these settings do only affect the subset case and DLARRE */
+	rtol1 = sqrt(eps);
+/* Computing MAX */
+	d__1 = sqrt(eps) * .005, d__2 = eps * 4.;
+	rtol2 = max(d__1,d__2);
+    }
+    igraphdlarre_(range, n, &wl, &wu, &iil, &iiu, &d__[1], &e[1], &work[inde2], &
+	    rtol1, &rtol2, &thresh, &nsplit, &iwork[iinspl], m, &w[1], &work[
+	    inderr], &work[indgp], &iwork[iindbl], &iwork[iindw], &work[
+	    indgrs], &pivmin, &work[indwrk], &iwork[iindwk], &iinfo);
+    if (iinfo != 0) {
+	*info = abs(iinfo) + 10;
+	return 0;
+    }
+/*     Note that if RANGE .NE. 'V', DLARRE computes bounds on the desired   
+       part of the spectrum. All desired eigenvalues are contained in   
+       (WL,WU] */
+    if (wantz) {
+
+/*        Compute the desired eigenvectors corresponding to the computed   
+          eigenvalues */
+
+	igraphdlarrv_(n, &wl, &wu, &d__[1], &e[1], &pivmin, &iwork[iinspl], m, &
+		c__1, m, &c_b18, &rtol1, &rtol2, &w[1], &work[inderr], &work[
+		indgp], &iwork[iindbl], &iwork[iindw], &work[indgrs], &z__[
+		z_offset], ldz, &isuppz[1], &work[indwrk], &iwork[iindwk], &
+		iinfo);
+	if (iinfo != 0) {
+	    *info = abs(iinfo) + 20;
+	    return 0;
+	}
+    } else {
+/*        DLARRE computes eigenvalues of the (shifted) root representation   
+          DLARRV returns the eigenvalues of the unshifted matrix.   
+          However, if the eigenvectors are not desired by the user, we need   
+          to apply the corresponding shifts from DLARRE to obtain the   
+          eigenvalues of the original matrix. */
+	i__1 = *m;
+	for (j = 1; j <= i__1; ++j) {
+	    itmp = iwork[iindbl + j - 1];
+	    w[j] += e[iwork[iinspl + itmp - 1]];
+/* L20: */
+	}
+    }
+
+    if (*tryrac) {
+/*        Refine computed eigenvalues so that they are relatively accurate   
+          with respect to the original matrix T. */
+	ibegin = 1;
+	wbegin = 1;
+	i__1 = iwork[iindbl + *m - 1];
+	for (jblk = 1; jblk <= i__1; ++jblk) {
+	    iend = iwork[iinspl + jblk - 1];
+	    in = iend - ibegin + 1;
+	    wend = wbegin - 1;
+/*           check if any eigenvalues have to be refined in this block */
+L36:
+	    if (wend < *m) {
+		if (iwork[iindbl + wend] == jblk) {
+		    ++wend;
+		    goto L36;
+		}
+	    }
+	    if (wend < wbegin) {
+		ibegin = iend + 1;
+		goto L39;
+	    }
+	    offset = iwork[iindw + wbegin - 1] - 1;
+	    ifirst = iwork[iindw + wbegin - 1];
+	    ilast = iwork[iindw + wend - 1];
+	    rtol2 = eps * 4.;
+	    igraphdlarrj_(&in, &work[indd + ibegin - 1], &work[inde2 + ibegin - 1], 
+		    &ifirst, &ilast, &rtol2, &offset, &w[wbegin], &work[
+		    inderr + wbegin - 1], &work[indwrk], &iwork[iindwk], &
+		    pivmin, &tnrm, &iinfo);
+	    ibegin = iend + 1;
+	    wbegin = wend + 1;
+L39:
+	    ;
+	}
+    }
+
+/*     If matrix was scaled, then rescale eigenvalues appropriately. */
+
+    if (scale != 1.) {
+	d__1 = 1. / scale;
+	igraphdscal_(m, &d__1, &w[1], &c__1);
+    }
+
+/*     If eigenvalues are not in increasing order, then sort them,   
+       possibly along with eigenvectors. */
+
+    if (nsplit > 1) {
+	if (! wantz) {
+	    igraphdlasrt_("I", m, &w[1], &iinfo);
+	    if (iinfo != 0) {
+		*info = 3;
+		return 0;
+	    }
+	} else {
+	    i__1 = *m - 1;
+	    for (j = 1; j <= i__1; ++j) {
+		i__ = 0;
+		tmp = w[j];
+		i__2 = *m;
+		for (jj = j + 1; jj <= i__2; ++jj) {
+		    if (w[jj] < tmp) {
+			i__ = jj;
+			tmp = w[jj];
+		    }
+/* L50: */
+		}
+		if (i__ != 0) {
+		    w[i__] = w[j];
+		    w[j] = tmp;
+		    if (wantz) {
+			igraphdswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[j * 
+				z_dim1 + 1], &c__1);
+			itmp = isuppz[(i__ << 1) - 1];
+			isuppz[(i__ << 1) - 1] = isuppz[(j << 1) - 1];
+			isuppz[(j << 1) - 1] = itmp;
+			itmp = isuppz[i__ * 2];
+			isuppz[i__ * 2] = isuppz[j * 2];
+			isuppz[j * 2] = itmp;
+		    }
+		}
+/* L60: */
+	    }
+	}
+    }
+
+
+    work[1] = (doublereal) lwmin;
+    iwork[1] = liwmin;
+    return 0;
+
+/*     End of DSTEMR */
+
+} /* igraphdstemr_ */
+
diff --git a/src/lapack/dsteqr.c b/src/lapack/dsteqr.c
new file mode 100644
index 0000000..1ce1ccb
--- /dev/null
+++ b/src/lapack/dsteqr.c
@@ -0,0 +1,607 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static doublereal c_b9 = 0.;
+static doublereal c_b10 = 1.;
+static integer c__0 = 0;
+static integer c__1 = 1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdsteqr_(char *compz, integer *n, doublereal *d__, 
+	doublereal *e, doublereal *z__, integer *ldz, doublereal *work, 
+	integer *info)
+{
+    /* System generated locals */
+    integer z_dim1, z_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal), d_sign(doublereal *, doublereal *);
+
+    /* Local variables */
+    doublereal b, c__, f, g;
+    integer i__, j, k, l, m;
+    doublereal p, r__, s;
+    integer l1, ii, mm, lm1, mm1, nm1;
+    doublereal rt1, rt2, eps;
+    integer lsv;
+    doublereal tst, eps2;
+    integer lend, jtot;
+    extern /* Subroutine */ int igraphdlae2_(doublereal *, doublereal *, doublereal 
+	    *, doublereal *, doublereal *);
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdlasr_(char *, char *, char *, integer *, 
+	    integer *, doublereal *, doublereal *, doublereal *, integer *);
+    doublereal anorm;
+    extern /* Subroutine */ int igraphdswap_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdlaev2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *);
+    integer lendm1, lendp1;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *), igraphdlamch_(char *);
+    integer iscale;
+    extern /* Subroutine */ int igraphdlascl_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *), igraphdlaset_(char *, integer *, integer 
+	    *, doublereal *, doublereal *, doublereal *, integer *);
+    doublereal safmin;
+    extern /* Subroutine */ int igraphdlartg_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *);
+    doublereal safmax;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    extern doublereal igraphdlanst_(char *, integer *, doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlasrt_(char *, integer *, doublereal *, 
+	    integer *);
+    integer lendsv;
+    doublereal ssfmin;
+    integer nmaxit, icompz;
+    doublereal ssfmax;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DSTEQR computes all eigenvalues and, optionally, eigenvectors of a   
+    symmetric tridiagonal matrix using the implicit QL or QR method.   
+    The eigenvectors of a full or band symmetric matrix can also be found   
+    if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to   
+    tridiagonal form.   
+
+    Arguments   
+    =========   
+
+    COMPZ   (input) CHARACTER*1   
+            = 'N':  Compute eigenvalues only.   
+            = 'V':  Compute eigenvalues and eigenvectors of the original   
+                    symmetric matrix.  On entry, Z must contain the   
+                    orthogonal matrix used to reduce the original matrix   
+                    to tridiagonal form.   
+            = 'I':  Compute eigenvalues and eigenvectors of the   
+                    tridiagonal matrix.  Z is initialized to the identity   
+                    matrix.   
+
+    N       (input) INTEGER   
+            The order of the matrix.  N >= 0.   
+
+    D       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the diagonal elements of the tridiagonal matrix.   
+            On exit, if INFO = 0, the eigenvalues in ascending order.   
+
+    E       (input/output) DOUBLE PRECISION array, dimension (N-1)   
+            On entry, the (n-1) subdiagonal elements of the tridiagonal   
+            matrix.   
+            On exit, E has been destroyed.   
+
+    Z       (input/output) DOUBLE PRECISION array, dimension (LDZ, N)   
+            On entry, if  COMPZ = 'V', then Z contains the orthogonal   
+            matrix used in the reduction to tridiagonal form.   
+            On exit, if INFO = 0, then if  COMPZ = 'V', Z contains the   
+            orthonormal eigenvectors of the original symmetric matrix,   
+            and if COMPZ = 'I', Z contains the orthonormal eigenvectors   
+            of the symmetric tridiagonal matrix.   
+            If COMPZ = 'N', then Z is not referenced.   
+
+    LDZ     (input) INTEGER   
+            The leading dimension of the array Z.  LDZ >= 1, and if   
+            eigenvectors are desired, then  LDZ >= max(1,N).   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2))   
+            If COMPZ = 'N', then WORK is not referenced.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  the algorithm has failed to find all the eigenvalues in   
+                  a total of 30*N iterations; if INFO = i, then i   
+                  elements of E have not converged to zero; on exit, D   
+                  and E contain the elements of a symmetric tridiagonal   
+                  matrix which is orthogonally similar to the original   
+                  matrix.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    --d__;
+    --e;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+
+    if (igraphlsame_(compz, "N")) {
+	icompz = 0;
+    } else if (igraphlsame_(compz, "V")) {
+	icompz = 1;
+    } else if (igraphlsame_(compz, "I")) {
+	icompz = 2;
+    } else {
+	icompz = -1;
+    }
+    if (icompz < 0) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) {
+	*info = -6;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DSTEQR", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+    if (*n == 1) {
+	if (icompz == 2) {
+	    z__[z_dim1 + 1] = 1.;
+	}
+	return 0;
+    }
+
+/*     Determine the unit roundoff and over/underflow thresholds. */
+
+    eps = igraphdlamch_("E");
+/* Computing 2nd power */
+    d__1 = eps;
+    eps2 = d__1 * d__1;
+    safmin = igraphdlamch_("S");
+    safmax = 1. / safmin;
+    ssfmax = sqrt(safmax) / 3.;
+    ssfmin = sqrt(safmin) / eps2;
+
+/*     Compute the eigenvalues and eigenvectors of the tridiagonal   
+       matrix. */
+
+    if (icompz == 2) {
+	igraphdlaset_("Full", n, n, &c_b9, &c_b10, &z__[z_offset], ldz);
+    }
+
+    nmaxit = *n * 30;
+    jtot = 0;
+
+/*     Determine where the matrix splits and choose QL or QR iteration   
+       for each block, according to whether top or bottom diagonal   
+       element is smaller. */
+
+    l1 = 1;
+    nm1 = *n - 1;
+
+L10:
+    if (l1 > *n) {
+	goto L160;
+    }
+    if (l1 > 1) {
+	e[l1 - 1] = 0.;
+    }
+    if (l1 <= nm1) {
+	i__1 = nm1;
+	for (m = l1; m <= i__1; ++m) {
+	    tst = (d__1 = e[m], abs(d__1));
+	    if (tst == 0.) {
+		goto L30;
+	    }
+	    if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m 
+		    + 1], abs(d__2))) * eps) {
+		e[m] = 0.;
+		goto L30;
+	    }
+/* L20: */
+	}
+    }
+    m = *n;
+
+L30:
+    l = l1;
+    lsv = l;
+    lend = m;
+    lendsv = lend;
+    l1 = m + 1;
+    if (lend == l) {
+	goto L10;
+    }
+
+/*     Scale submatrix in rows and columns L to LEND */
+
+    i__1 = lend - l + 1;
+    anorm = igraphdlanst_("M", &i__1, &d__[l], &e[l]);
+    iscale = 0;
+    if (anorm == 0.) {
+	goto L10;
+    }
+    if (anorm > ssfmax) {
+	iscale = 1;
+	i__1 = lend - l + 1;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, 
+		info);
+	i__1 = lend - l;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, 
+		info);
+    } else if (anorm < ssfmin) {
+	iscale = 2;
+	i__1 = lend - l + 1;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, 
+		info);
+	i__1 = lend - l;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, 
+		info);
+    }
+
+/*     Choose between QL and QR iteration */
+
+    if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) {
+	lend = lsv;
+	l = lendsv;
+    }
+
+    if (lend > l) {
+
+/*        QL Iteration   
+
+          Look for small subdiagonal element. */
+
+L40:
+	if (l != lend) {
+	    lendm1 = lend - 1;
+	    i__1 = lendm1;
+	    for (m = l; m <= i__1; ++m) {
+/* Computing 2nd power */
+		d__2 = (d__1 = e[m], abs(d__1));
+		tst = d__2 * d__2;
+		if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m 
+			+ 1], abs(d__2)) + safmin) {
+		    goto L60;
+		}
+/* L50: */
+	    }
+	}
+
+	m = lend;
+
+L60:
+	if (m < lend) {
+	    e[m] = 0.;
+	}
+	p = d__[l];
+	if (m == l) {
+	    goto L80;
+	}
+
+/*        If remaining matrix is 2-by-2, use DLAE2 or SLAEV2   
+          to compute its eigensystem. */
+
+	if (m == l + 1) {
+	    if (icompz > 0) {
+		igraphdlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s);
+		work[l] = c__;
+		work[*n - 1 + l] = s;
+		igraphdlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], &
+			z__[l * z_dim1 + 1], ldz);
+	    } else {
+		igraphdlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2);
+	    }
+	    d__[l] = rt1;
+	    d__[l + 1] = rt2;
+	    e[l] = 0.;
+	    l += 2;
+	    if (l <= lend) {
+		goto L40;
+	    }
+	    goto L140;
+	}
+
+	if (jtot == nmaxit) {
+	    goto L140;
+	}
+	++jtot;
+
+/*        Form shift. */
+
+	g = (d__[l + 1] - p) / (e[l] * 2.);
+	r__ = igraphdlapy2_(&g, &c_b10);
+	g = d__[m] - p + e[l] / (g + d_sign(&r__, &g));
+
+	s = 1.;
+	c__ = 1.;
+	p = 0.;
+
+/*        Inner loop */
+
+	mm1 = m - 1;
+	i__1 = l;
+	for (i__ = mm1; i__ >= i__1; --i__) {
+	    f = s * e[i__];
+	    b = c__ * e[i__];
+	    igraphdlartg_(&g, &f, &c__, &s, &r__);
+	    if (i__ != m - 1) {
+		e[i__ + 1] = r__;
+	    }
+	    g = d__[i__ + 1] - p;
+	    r__ = (d__[i__] - g) * s + c__ * 2. * b;
+	    p = s * r__;
+	    d__[i__ + 1] = g + p;
+	    g = c__ * r__ - b;
+
+/*           If eigenvectors are desired, then save rotations. */
+
+	    if (icompz > 0) {
+		work[i__] = c__;
+		work[*n - 1 + i__] = -s;
+	    }
+
+/* L70: */
+	}
+
+/*        If eigenvectors are desired, then apply saved rotations. */
+
+	if (icompz > 0) {
+	    mm = m - l + 1;
+	    igraphdlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l 
+		    * z_dim1 + 1], ldz);
+	}
+
+	d__[l] -= p;
+	e[l] = g;
+	goto L40;
+
+/*        Eigenvalue found. */
+
+L80:
+	d__[l] = p;
+
+	++l;
+	if (l <= lend) {
+	    goto L40;
+	}
+	goto L140;
+
+    } else {
+
+/*        QR Iteration   
+
+          Look for small superdiagonal element. */
+
+L90:
+	if (l != lend) {
+	    lendp1 = lend + 1;
+	    i__1 = lendp1;
+	    for (m = l; m >= i__1; --m) {
+/* Computing 2nd power */
+		d__2 = (d__1 = e[m - 1], abs(d__1));
+		tst = d__2 * d__2;
+		if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m 
+			- 1], abs(d__2)) + safmin) {
+		    goto L110;
+		}
+/* L100: */
+	    }
+	}
+
+	m = lend;
+
+L110:
+	if (m > lend) {
+	    e[m - 1] = 0.;
+	}
+	p = d__[l];
+	if (m == l) {
+	    goto L130;
+	}
+
+/*        If remaining matrix is 2-by-2, use DLAE2 or SLAEV2   
+          to compute its eigensystem. */
+
+	if (m == l - 1) {
+	    if (icompz > 0) {
+		igraphdlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s)
+			;
+		work[m] = c__;
+		work[*n - 1 + m] = s;
+		igraphdlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], &
+			z__[(l - 1) * z_dim1 + 1], ldz);
+	    } else {
+		igraphdlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2);
+	    }
+	    d__[l - 1] = rt1;
+	    d__[l] = rt2;
+	    e[l - 1] = 0.;
+	    l += -2;
+	    if (l >= lend) {
+		goto L90;
+	    }
+	    goto L140;
+	}
+
+	if (jtot == nmaxit) {
+	    goto L140;
+	}
+	++jtot;
+
+/*        Form shift. */
+
+	g = (d__[l - 1] - p) / (e[l - 1] * 2.);
+	r__ = igraphdlapy2_(&g, &c_b10);
+	g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g));
+
+	s = 1.;
+	c__ = 1.;
+	p = 0.;
+
+/*        Inner loop */
+
+	lm1 = l - 1;
+	i__1 = lm1;
+	for (i__ = m; i__ <= i__1; ++i__) {
+	    f = s * e[i__];
+	    b = c__ * e[i__];
+	    igraphdlartg_(&g, &f, &c__, &s, &r__);
+	    if (i__ != m) {
+		e[i__ - 1] = r__;
+	    }
+	    g = d__[i__] - p;
+	    r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b;
+	    p = s * r__;
+	    d__[i__] = g + p;
+	    g = c__ * r__ - b;
+
+/*           If eigenvectors are desired, then save rotations. */
+
+	    if (icompz > 0) {
+		work[i__] = c__;
+		work[*n - 1 + i__] = s;
+	    }
+
+/* L120: */
+	}
+
+/*        If eigenvectors are desired, then apply saved rotations. */
+
+	if (icompz > 0) {
+	    mm = l - m + 1;
+	    igraphdlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m 
+		    * z_dim1 + 1], ldz);
+	}
+
+	d__[l] -= p;
+	e[lm1] = g;
+	goto L90;
+
+/*        Eigenvalue found. */
+
+L130:
+	d__[l] = p;
+
+	--l;
+	if (l >= lend) {
+	    goto L90;
+	}
+	goto L140;
+
+    }
+
+/*     Undo scaling if necessary */
+
+L140:
+    if (iscale == 1) {
+	i__1 = lendsv - lsv + 1;
+	igraphdlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], 
+		n, info);
+	i__1 = lendsv - lsv;
+	igraphdlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, 
+		info);
+    } else if (iscale == 2) {
+	i__1 = lendsv - lsv + 1;
+	igraphdlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], 
+		n, info);
+	i__1 = lendsv - lsv;
+	igraphdlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, 
+		info);
+    }
+
+/*     Check for no convergence to an eigenvalue after a total   
+       of N*MAXIT iterations. */
+
+    if (jtot < nmaxit) {
+	goto L10;
+    }
+    i__1 = *n - 1;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	if (e[i__] != 0.) {
+	    ++(*info);
+	}
+/* L150: */
+    }
+    goto L190;
+
+/*     Order eigenvalues and eigenvectors. */
+
+L160:
+    if (icompz == 0) {
+
+/*        Use Quick Sort */
+
+	igraphdlasrt_("I", n, &d__[1], info);
+
+    } else {
+
+/*        Use Selection Sort to minimize swaps of eigenvectors */
+
+	i__1 = *n;
+	for (ii = 2; ii <= i__1; ++ii) {
+	    i__ = ii - 1;
+	    k = i__;
+	    p = d__[i__];
+	    i__2 = *n;
+	    for (j = ii; j <= i__2; ++j) {
+		if (d__[j] < p) {
+		    k = j;
+		    p = d__[j];
+		}
+/* L170: */
+	    }
+	    if (k != i__) {
+		d__[k] = d__[i__];
+		d__[i__] = p;
+		igraphdswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1],
+			 &c__1);
+	    }
+/* L180: */
+	}
+    }
+
+L190:
+    return 0;
+
+/*     End of DSTEQR */
+
+} /* igraphdsteqr_ */
+
diff --git a/src/lapack/dsterf.c b/src/lapack/dsterf.c
new file mode 100644
index 0000000..556e263
--- /dev/null
+++ b/src/lapack/dsterf.c
@@ -0,0 +1,453 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__0 = 0;
+static integer c__1 = 1;
+static doublereal c_b33 = 1.;
+
+/* Subroutine */ int igraphdsterf_(integer *n, doublereal *d__, doublereal *e, 
+	integer *info)
+{
+    /* System generated locals */
+    integer i__1;
+    doublereal d__1, d__2, d__3;
+
+    /* Builtin functions */
+    double sqrt(doublereal), d_sign(doublereal *, doublereal *);
+
+    /* Local variables */
+    doublereal c__;
+    integer i__, l, m;
+    doublereal p, r__, s;
+    integer l1;
+    doublereal bb, rt1, rt2, eps, rte;
+    integer lsv;
+    doublereal eps2, oldc;
+    integer lend;
+    doublereal rmax;
+    integer jtot;
+    extern /* Subroutine */ int igraphdlae2_(doublereal *, doublereal *, doublereal 
+	    *, doublereal *, doublereal *);
+    doublereal gamma, alpha, sigma, anorm;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *), igraphdlamch_(char *);
+    integer iscale;
+    extern /* Subroutine */ int igraphdlascl_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *);
+    doublereal oldgam, safmin;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    doublereal safmax;
+    extern doublereal igraphdlanst_(char *, integer *, doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlasrt_(char *, integer *, doublereal *, 
+	    integer *);
+    integer lendsv;
+    doublereal ssfmin;
+    integer nmaxit;
+    doublereal ssfmax;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DSTERF computes all eigenvalues of a symmetric tridiagonal matrix   
+    using the Pal-Walker-Kahan variant of the QL or QR algorithm.   
+
+    Arguments   
+    =========   
+
+    N       (input) INTEGER   
+            The order of the matrix.  N >= 0.   
+
+    D       (input/output) DOUBLE PRECISION array, dimension (N)   
+            On entry, the n diagonal elements of the tridiagonal matrix.   
+            On exit, if INFO = 0, the eigenvalues in ascending order.   
+
+    E       (input/output) DOUBLE PRECISION array, dimension (N-1)   
+            On entry, the (n-1) subdiagonal elements of the tridiagonal   
+            matrix.   
+            On exit, E has been destroyed.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  the algorithm failed to find all of the eigenvalues in   
+                  a total of 30*N iterations; if INFO = i, then i   
+                  elements of E have not converged to zero.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+
+/*     Quick return if possible */
+
+    if (*n < 0) {
+	*info = -1;
+	i__1 = -(*info);
+	igraphxerbla_("DSTERF", &i__1, (ftnlen)6);
+	return 0;
+    }
+    if (*n <= 1) {
+	return 0;
+    }
+
+/*     Determine the unit roundoff for this environment. */
+
+    eps = igraphdlamch_("E");
+/* Computing 2nd power */
+    d__1 = eps;
+    eps2 = d__1 * d__1;
+    safmin = igraphdlamch_("S");
+    safmax = 1. / safmin;
+    ssfmax = sqrt(safmax) / 3.;
+    ssfmin = sqrt(safmin) / eps2;
+    rmax = igraphdlamch_("O");
+
+/*     Compute the eigenvalues of the tridiagonal matrix. */
+
+    nmaxit = *n * 30;
+    sigma = 0.;
+    jtot = 0;
+
+/*     Determine where the matrix splits and choose QL or QR iteration   
+       for each block, according to whether top or bottom diagonal   
+       element is smaller. */
+
+    l1 = 1;
+
+L10:
+    if (l1 > *n) {
+	goto L170;
+    }
+    if (l1 > 1) {
+	e[l1 - 1] = 0.;
+    }
+    i__1 = *n - 1;
+    for (m = l1; m <= i__1; ++m) {
+	if ((d__3 = e[m], abs(d__3)) <= sqrt((d__1 = d__[m], abs(d__1))) * 
+		sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) {
+	    e[m] = 0.;
+	    goto L30;
+	}
+/* L20: */
+    }
+    m = *n;
+
+L30:
+    l = l1;
+    lsv = l;
+    lend = m;
+    lendsv = lend;
+    l1 = m + 1;
+    if (lend == l) {
+	goto L10;
+    }
+
+/*     Scale submatrix in rows and columns L to LEND */
+
+    i__1 = lend - l + 1;
+    anorm = igraphdlanst_("M", &i__1, &d__[l], &e[l]);
+    iscale = 0;
+    if (anorm == 0.) {
+	goto L10;
+    }
+    if (anorm > ssfmax) {
+	iscale = 1;
+	i__1 = lend - l + 1;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, 
+		info);
+	i__1 = lend - l;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, 
+		info);
+    } else if (anorm < ssfmin) {
+	iscale = 2;
+	i__1 = lend - l + 1;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, 
+		info);
+	i__1 = lend - l;
+	igraphdlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, 
+		info);
+    }
+
+    i__1 = lend - 1;
+    for (i__ = l; i__ <= i__1; ++i__) {
+/* Computing 2nd power */
+	d__1 = e[i__];
+	e[i__] = d__1 * d__1;
+/* L40: */
+    }
+
+/*     Choose between QL and QR iteration */
+
+    if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) {
+	lend = lsv;
+	l = lendsv;
+    }
+
+    if (lend >= l) {
+
+/*        QL Iteration   
+
+          Look for small subdiagonal element. */
+
+L50:
+	if (l != lend) {
+	    i__1 = lend - 1;
+	    for (m = l; m <= i__1; ++m) {
+		if ((d__2 = e[m], abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m 
+			+ 1], abs(d__1))) {
+		    goto L70;
+		}
+/* L60: */
+	    }
+	}
+	m = lend;
+
+L70:
+	if (m < lend) {
+	    e[m] = 0.;
+	}
+	p = d__[l];
+	if (m == l) {
+	    goto L90;
+	}
+
+/*        If remaining matrix is 2 by 2, use DLAE2 to compute its   
+          eigenvalues. */
+
+	if (m == l + 1) {
+	    rte = sqrt(e[l]);
+	    igraphdlae2_(&d__[l], &rte, &d__[l + 1], &rt1, &rt2);
+	    d__[l] = rt1;
+	    d__[l + 1] = rt2;
+	    e[l] = 0.;
+	    l += 2;
+	    if (l <= lend) {
+		goto L50;
+	    }
+	    goto L150;
+	}
+
+	if (jtot == nmaxit) {
+	    goto L150;
+	}
+	++jtot;
+
+/*        Form shift. */
+
+	rte = sqrt(e[l]);
+	sigma = (d__[l + 1] - p) / (rte * 2.);
+	r__ = igraphdlapy2_(&sigma, &c_b33);
+	sigma = p - rte / (sigma + d_sign(&r__, &sigma));
+
+	c__ = 1.;
+	s = 0.;
+	gamma = d__[m] - sigma;
+	p = gamma * gamma;
+
+/*        Inner loop */
+
+	i__1 = l;
+	for (i__ = m - 1; i__ >= i__1; --i__) {
+	    bb = e[i__];
+	    r__ = p + bb;
+	    if (i__ != m - 1) {
+		e[i__ + 1] = s * r__;
+	    }
+	    oldc = c__;
+	    c__ = p / r__;
+	    s = bb / r__;
+	    oldgam = gamma;
+	    alpha = d__[i__];
+	    gamma = c__ * (alpha - sigma) - s * oldgam;
+	    d__[i__ + 1] = oldgam + (alpha - gamma);
+	    if (c__ != 0.) {
+		p = gamma * gamma / c__;
+	    } else {
+		p = oldc * bb;
+	    }
+/* L80: */
+	}
+
+	e[l] = s * p;
+	d__[l] = sigma + gamma;
+	goto L50;
+
+/*        Eigenvalue found. */
+
+L90:
+	d__[l] = p;
+
+	++l;
+	if (l <= lend) {
+	    goto L50;
+	}
+	goto L150;
+
+    } else {
+
+/*        QR Iteration   
+
+          Look for small superdiagonal element. */
+
+L100:
+	i__1 = lend + 1;
+	for (m = l; m >= i__1; --m) {
+	    if ((d__2 = e[m - 1], abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m 
+		    - 1], abs(d__1))) {
+		goto L120;
+	    }
+/* L110: */
+	}
+	m = lend;
+
+L120:
+	if (m > lend) {
+	    e[m - 1] = 0.;
+	}
+	p = d__[l];
+	if (m == l) {
+	    goto L140;
+	}
+
+/*        If remaining matrix is 2 by 2, use DLAE2 to compute its   
+          eigenvalues. */
+
+	if (m == l - 1) {
+	    rte = sqrt(e[l - 1]);
+	    igraphdlae2_(&d__[l], &rte, &d__[l - 1], &rt1, &rt2);
+	    d__[l] = rt1;
+	    d__[l - 1] = rt2;
+	    e[l - 1] = 0.;
+	    l += -2;
+	    if (l >= lend) {
+		goto L100;
+	    }
+	    goto L150;
+	}
+
+	if (jtot == nmaxit) {
+	    goto L150;
+	}
+	++jtot;
+
+/*        Form shift. */
+
+	rte = sqrt(e[l - 1]);
+	sigma = (d__[l - 1] - p) / (rte * 2.);
+	r__ = igraphdlapy2_(&sigma, &c_b33);
+	sigma = p - rte / (sigma + d_sign(&r__, &sigma));
+
+	c__ = 1.;
+	s = 0.;
+	gamma = d__[m] - sigma;
+	p = gamma * gamma;
+
+/*        Inner loop */
+
+	i__1 = l - 1;
+	for (i__ = m; i__ <= i__1; ++i__) {
+	    bb = e[i__];
+	    r__ = p + bb;
+	    if (i__ != m) {
+		e[i__ - 1] = s * r__;
+	    }
+	    oldc = c__;
+	    c__ = p / r__;
+	    s = bb / r__;
+	    oldgam = gamma;
+	    alpha = d__[i__ + 1];
+	    gamma = c__ * (alpha - sigma) - s * oldgam;
+	    d__[i__] = oldgam + (alpha - gamma);
+	    if (c__ != 0.) {
+		p = gamma * gamma / c__;
+	    } else {
+		p = oldc * bb;
+	    }
+/* L130: */
+	}
+
+	e[l - 1] = s * p;
+	d__[l] = sigma + gamma;
+	goto L100;
+
+/*        Eigenvalue found. */
+
+L140:
+	d__[l] = p;
+
+	--l;
+	if (l >= lend) {
+	    goto L100;
+	}
+	goto L150;
+
+    }
+
+/*     Undo scaling if necessary */
+
+L150:
+    if (iscale == 1) {
+	i__1 = lendsv - lsv + 1;
+	igraphdlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], 
+		n, info);
+    }
+    if (iscale == 2) {
+	i__1 = lendsv - lsv + 1;
+	igraphdlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], 
+		n, info);
+    }
+
+/*     Check for no convergence to an eigenvalue after a total   
+       of N*MAXIT iterations. */
+
+    if (jtot < nmaxit) {
+	goto L10;
+    }
+    i__1 = *n - 1;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	if (e[i__] != 0.) {
+	    ++(*info);
+	}
+/* L160: */
+    }
+    goto L180;
+
+/*     Sort eigenvalues in increasing order. */
+
+L170:
+    igraphdlasrt_("I", n, &d__[1], info);
+
+L180:
+    return 0;
+
+/*     End of DSTERF */
+
+} /* igraphdsterf_ */
+
diff --git a/src/lapack/dstqrb.c b/src/lapack/dstqrb.c
new file mode 100644
index 0000000..e200f85
--- /dev/null
+++ b/src/lapack/dstqrb.c
@@ -0,0 +1,691 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__0 = 0;
+static integer c__1 = 1;
+static doublereal c_b31 = 1.;
+
+/* -----------------------------------------------------------------------   
+   \BeginDoc   
+
+   \Name: dstqrb   
+
+   \Description:   
+    Computes all eigenvalues and the last component of the eigenvectors   
+    of a symmetric tridiagonal matrix using the implicit QL or QR method.   
+
+    This is mostly a modification of the LAPACK routine dsteqr.   
+    See Remarks.   
+
+   \Usage:   
+    call dstqrb   
+       ( N, D, E, Z, WORK, INFO )   
+
+   \Arguments   
+    N       Integer.  (INPUT)   
+            The number of rows and columns in the matrix.  N >= 0.   
+
+    D       Double precision array, dimension (N).  (INPUT/OUTPUT)   
+            On entry, D contains the diagonal elements of the   
+            tridiagonal matrix.   
+            On exit, D contains the eigenvalues, in ascending order.   
+            If an error exit is made, the eigenvalues are correct   
+            for indices 1,2,...,INFO-1, but they are unordered and   
+            may not be the smallest eigenvalues of the matrix.   
+
+    E       Double precision array, dimension (N-1).  (INPUT/OUTPUT)   
+            On entry, E contains the subdiagonal elements of the   
+            tridiagonal matrix in positions 1 through N-1.   
+            On exit, E has been destroyed.   
+
+    Z       Double precision array, dimension (N).  (OUTPUT)   
+            On exit, Z contains the last row of the orthonormal   
+            eigenvector matrix of the symmetric tridiagonal matrix.   
+            If an error exit is made, Z contains the last row of the   
+            eigenvector matrix associated with the stored eigenvalues.   
+
+    WORK    Double precision array, dimension (max(1,2*N-2)).  (WORKSPACE)   
+            Workspace used in accumulating the transformation for   
+            computing the last components of the eigenvectors.   
+
+    INFO    Integer.  (OUTPUT)   
+            = 0:  normal return.   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+            > 0:  if INFO = +i, the i-th eigenvalue has not converged   
+                                after a total of  30*N  iterations.   
+
+   \Remarks   
+    1. None.   
+
+   -----------------------------------------------------------------------   
+
+   \BeginLib   
+
+   \Local variables:   
+       xxxxxx  real   
+
+   \Routines called:   
+       daxpy   Level 1 BLAS that computes a vector triad.   
+       dcopy   Level 1 BLAS that copies one vector to another.   
+       dswap   Level 1 BLAS that swaps the contents of two vectors.   
+       lsame   LAPACK character comparison routine.   
+       dlae2   LAPACK routine that computes the eigenvalues of a 2-by-2   
+               symmetric matrix.   
+       dlaev2  LAPACK routine that eigendecomposition of a 2-by-2 symmetric   
+               matrix.   
+       dlamch  LAPACK routine that determines machine constants.   
+       dlanst  LAPACK routine that computes the norm of a matrix.   
+       dlapy2  LAPACK routine to compute sqrt(x**2+y**2) carefully.   
+       dlartg  LAPACK Givens rotation construction routine.   
+       dlascl  LAPACK routine for careful scaling of a matrix.   
+       dlaset  LAPACK matrix initialization routine.   
+       dlasr   LAPACK routine that applies an orthogonal transformation to   
+               a matrix.   
+       dlasrt  LAPACK sorting routine.   
+       dsteqr  LAPACK routine that computes eigenvalues and eigenvectors   
+               of a symmetric tridiagonal matrix.   
+       xerbla  LAPACK error handler routine.   
+
+   \Authors   
+       Danny Sorensen               Phuong Vu   
+       Richard Lehoucq              CRPC / Rice University   
+       Dept. of Computational &     Houston, Texas   
+       Applied Mathematics   
+       Rice University   
+       Houston, Texas   
+
+   \SCCS Information: @(#)   
+   FILE: stqrb.F   SID: 2.5   DATE OF SID: 8/27/96   RELEASE: 2   
+
+   \Remarks   
+       1. Starting with version 2.5, this routine is a modified version   
+          of LAPACK version 2.0 subroutine SSTEQR. No lines are deleted,   
+          only commeted out and new lines inserted.   
+          All lines commented out have "c$$$" at the beginning.   
+          Note that the LAPACK version 1.0 subroutine SSTEQR contained   
+          bugs.   
+
+   \EndLib   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdstqrb_(integer *n, doublereal *d__, doublereal *e, 
+	doublereal *z__, doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal), d_sign(doublereal *, doublereal *);
+
+    /* Local variables */
+    doublereal b, c__, f, g;
+    integer i__, j, k, l, m;
+    doublereal p, r__, s;
+    integer l1, ii, mm, lm1, mm1, nm1;
+    doublereal rt1, rt2, eps;
+    integer lsv;
+    doublereal tst, eps2;
+    integer lend, jtot;
+    extern /* Subroutine */ int igraphdlae2_(doublereal *, doublereal *, doublereal 
+	    *, doublereal *, doublereal *), igraphdlasr_(char *, char *, char *, 
+	    integer *, integer *, doublereal *, doublereal *, doublereal *, 
+	    integer *);
+    doublereal anorm;
+    extern /* Subroutine */ int igraphdlaev2_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *, doublereal *, 
+	    doublereal *);
+    integer lendm1, lendp1;
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *), igraphdlamch_(char *);
+    integer iscale;
+    extern /* Subroutine */ int igraphdlascl_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, integer *);
+    doublereal safmin;
+    extern /* Subroutine */ int igraphdlartg_(doublereal *, doublereal *, 
+	    doublereal *, doublereal *, doublereal *);
+    doublereal safmax;
+    extern doublereal igraphdlanst_(char *, integer *, doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlasrt_(char *, integer *, doublereal *, 
+	    integer *);
+    integer lendsv, nmaxit, icompz;
+    doublereal ssfmax, ssfmin;
+
+
+/*     %------------------%   
+       | Scalar Arguments |   
+       %------------------%   
+
+
+       %-----------------%   
+       | Array Arguments |   
+       %-----------------%   
+
+
+
+       test the input parameters.   
+
+       Parameter adjustments */
+    --work;
+    --z__;
+    --e;
+    --d__;
+
+    /* Function Body */
+    *info = 0;
+
+/* $$$      IF( LSAME( COMPZ, 'N' ) ) THEN   
+   $$$         ICOMPZ = 0   
+   $$$      ELSE IF( LSAME( COMPZ, 'V' ) ) THEN   
+   $$$         ICOMPZ = 1   
+   $$$      ELSE IF( LSAME( COMPZ, 'I' ) ) THEN   
+   $$$         ICOMPZ = 2   
+   $$$      ELSE   
+   $$$         ICOMPZ = -1   
+   $$$      END IF   
+   $$$      IF( ICOMPZ.LT.0 ) THEN   
+   $$$         INFO = -1   
+   $$$      ELSE IF( N.LT.0 ) THEN   
+   $$$         INFO = -2   
+   $$$      ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1,   
+   $$$     $         N ) ) ) THEN   
+   $$$         INFO = -6   
+   $$$      END IF   
+   $$$      IF( INFO.NE.0 ) THEN   
+   $$$         CALL XERBLA( 'SSTEQR', -INFO )   
+   $$$         RETURN   
+   $$$      END IF   
+
+      *** New starting with version 2.5 *** */
+
+    icompz = 2;
+/*    *************************************   
+
+       quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+    if (*n == 1) {
+	if (icompz == 2) {
+	    z__[1] = 1.;
+	}
+	return 0;
+    }
+
+/*     determine the unit roundoff and over/underflow thresholds. */
+
+    eps = igraphdlamch_("e");
+/* Computing 2nd power */
+    d__1 = eps;
+    eps2 = d__1 * d__1;
+    safmin = igraphdlamch_("s");
+    safmax = 1. / safmin;
+    ssfmax = sqrt(safmax) / 3.;
+    ssfmin = sqrt(safmin) / eps2;
+
+/*     compute the eigenvalues and eigenvectors of the tridiagonal   
+       matrix.   
+
+   $$      if( icompz.eq.2 )   
+   $$$     $   call dlaset( 'full', n, n, zero, one, z, ldz )   
+
+       *** New starting with version 2.5 *** */
+
+    if (icompz == 2) {
+	i__1 = *n - 1;
+	for (j = 1; j <= i__1; ++j) {
+	    z__[j] = 0.;
+/* L5: */
+	}
+	z__[*n] = 1.;
+    }
+/*     ************************************* */
+
+    nmaxit = *n * 30;
+    jtot = 0;
+
+/*     determine where the matrix splits and choose ql or qr iteration   
+       for each block, according to whether top or bottom diagonal   
+       element is smaller. */
+
+    l1 = 1;
+    nm1 = *n - 1;
+
+L10:
+    if (l1 > *n) {
+	goto L160;
+    }
+    if (l1 > 1) {
+	e[l1 - 1] = 0.;
+    }
+    if (l1 <= nm1) {
+	i__1 = nm1;
+	for (m = l1; m <= i__1; ++m) {
+	    tst = (d__1 = e[m], abs(d__1));
+	    if (tst == 0.) {
+		goto L30;
+	    }
+	    if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m 
+		    + 1], abs(d__2))) * eps) {
+		e[m] = 0.;
+		goto L30;
+	    }
+/* L20: */
+	}
+    }
+    m = *n;
+
+L30:
+    l = l1;
+    lsv = l;
+    lend = m;
+    lendsv = lend;
+    l1 = m + 1;
+    if (lend == l) {
+	goto L10;
+    }
+
+/*     scale submatrix in rows and columns l to lend */
+
+    i__1 = lend - l + 1;
+    anorm = igraphdlanst_("i", &i__1, &d__[l], &e[l]);
+    iscale = 0;
+    if (anorm == 0.) {
+	goto L10;
+    }
+    if (anorm > ssfmax) {
+	iscale = 1;
+	i__1 = lend - l + 1;
+	igraphdlascl_("g", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, 
+		info);
+	i__1 = lend - l;
+	igraphdlascl_("g", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, 
+		info);
+    } else if (anorm < ssfmin) {
+	iscale = 2;
+	i__1 = lend - l + 1;
+	igraphdlascl_("g", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, 
+		info);
+	i__1 = lend - l;
+	igraphdlascl_("g", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, 
+		info);
+    }
+
+/*     choose between ql and qr iteration */
+
+    if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) {
+	lend = lsv;
+	l = lendsv;
+    }
+
+    if (lend > l) {
+
+/*        ql iteration   
+
+          look for small subdiagonal element. */
+
+L40:
+	if (l != lend) {
+	    lendm1 = lend - 1;
+	    i__1 = lendm1;
+	    for (m = l; m <= i__1; ++m) {
+/* Computing 2nd power */
+		d__2 = (d__1 = e[m], abs(d__1));
+		tst = d__2 * d__2;
+		if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m 
+			+ 1], abs(d__2)) + safmin) {
+		    goto L60;
+		}
+/* L50: */
+	    }
+	}
+
+	m = lend;
+
+L60:
+	if (m < lend) {
+	    e[m] = 0.;
+	}
+	p = d__[l];
+	if (m == l) {
+	    goto L80;
+	}
+
+/*        if remaining matrix is 2-by-2, use dlae2 or dlaev2   
+          to compute its eigensystem. */
+
+	if (m == l + 1) {
+	    if (icompz > 0) {
+		igraphdlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s);
+		work[l] = c__;
+		work[*n - 1 + l] = s;
+/* $$$               call dlasr( 'r', 'v', 'b', n, 2, work( l ),   
+   $$$     $                     work( n-1+l ), z( 1, l ), ldz )   
+
+                *** New starting with version 2.5 *** */
+
+		tst = z__[l + 1];
+		z__[l + 1] = c__ * tst - s * z__[l];
+		z__[l] = s * tst + c__ * z__[l];
+/*              ************************************* */
+	    } else {
+		igraphdlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2);
+	    }
+	    d__[l] = rt1;
+	    d__[l + 1] = rt2;
+	    e[l] = 0.;
+	    l += 2;
+	    if (l <= lend) {
+		goto L40;
+	    }
+	    goto L140;
+	}
+
+	if (jtot == nmaxit) {
+	    goto L140;
+	}
+	++jtot;
+
+/*        form shift. */
+
+	g = (d__[l + 1] - p) / (e[l] * 2.);
+	r__ = igraphdlapy2_(&g, &c_b31);
+	g = d__[m] - p + e[l] / (g + d_sign(&r__, &g));
+
+	s = 1.;
+	c__ = 1.;
+	p = 0.;
+
+/*        inner loop */
+
+	mm1 = m - 1;
+	i__1 = l;
+	for (i__ = mm1; i__ >= i__1; --i__) {
+	    f = s * e[i__];
+	    b = c__ * e[i__];
+	    igraphdlartg_(&g, &f, &c__, &s, &r__);
+	    if (i__ != m - 1) {
+		e[i__ + 1] = r__;
+	    }
+	    g = d__[i__ + 1] - p;
+	    r__ = (d__[i__] - g) * s + c__ * 2. * b;
+	    p = s * r__;
+	    d__[i__ + 1] = g + p;
+	    g = c__ * r__ - b;
+
+/*           if eigenvectors are desired, then save rotations. */
+
+	    if (icompz > 0) {
+		work[i__] = c__;
+		work[*n - 1 + i__] = -s;
+	    }
+
+/* L70: */
+	}
+
+/*        if eigenvectors are desired, then apply saved rotations. */
+
+	if (icompz > 0) {
+	    mm = m - l + 1;
+/* $$$            call dlasr( 'r', 'v', 'b', n, mm, work( l ), work( n-1+l ),   
+   $$$     $                  z( 1, l ), ldz )   
+
+               *** New starting with version 2.5 *** */
+
+	    igraphdlasr_("r", "v", "b", &c__1, &mm, &work[l], &work[*n - 1 + l], &
+		    z__[l], &c__1);
+/*             ************************************* */
+	}
+
+	d__[l] -= p;
+	e[l] = g;
+	goto L40;
+
+/*        eigenvalue found. */
+
+L80:
+	d__[l] = p;
+
+	++l;
+	if (l <= lend) {
+	    goto L40;
+	}
+	goto L140;
+
+    } else {
+
+/*        qr iteration   
+
+          look for small superdiagonal element. */
+
+L90:
+	if (l != lend) {
+	    lendp1 = lend + 1;
+	    i__1 = lendp1;
+	    for (m = l; m >= i__1; --m) {
+/* Computing 2nd power */
+		d__2 = (d__1 = e[m - 1], abs(d__1));
+		tst = d__2 * d__2;
+		if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m 
+			- 1], abs(d__2)) + safmin) {
+		    goto L110;
+		}
+/* L100: */
+	    }
+	}
+
+	m = lend;
+
+L110:
+	if (m > lend) {
+	    e[m - 1] = 0.;
+	}
+	p = d__[l];
+	if (m == l) {
+	    goto L130;
+	}
+
+/*        if remaining matrix is 2-by-2, use dlae2 or dlaev2   
+          to compute its eigensystem. */
+
+	if (m == l - 1) {
+	    if (icompz > 0) {
+		igraphdlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s)
+			;
+/* $$$               work( m ) = c   
+   $$$               work( n-1+m ) = s   
+   $$$               call dlasr( 'r', 'v', 'f', n, 2, work( m ),   
+   $$$     $                     work( n-1+m ), z( 1, l-1 ), ldz )   
+
+                 *** New starting with version 2.5 *** */
+
+		tst = z__[l];
+		z__[l] = c__ * tst - s * z__[l - 1];
+		z__[l - 1] = s * tst + c__ * z__[l - 1];
+/*               ************************************* */
+	    } else {
+		igraphdlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2);
+	    }
+	    d__[l - 1] = rt1;
+	    d__[l] = rt2;
+	    e[l - 1] = 0.;
+	    l += -2;
+	    if (l >= lend) {
+		goto L90;
+	    }
+	    goto L140;
+	}
+
+	if (jtot == nmaxit) {
+	    goto L140;
+	}
+	++jtot;
+
+/*        form shift. */
+
+	g = (d__[l - 1] - p) / (e[l - 1] * 2.);
+	r__ = igraphdlapy2_(&g, &c_b31);
+	g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g));
+
+	s = 1.;
+	c__ = 1.;
+	p = 0.;
+
+/*        inner loop */
+
+	lm1 = l - 1;
+	i__1 = lm1;
+	for (i__ = m; i__ <= i__1; ++i__) {
+	    f = s * e[i__];
+	    b = c__ * e[i__];
+	    igraphdlartg_(&g, &f, &c__, &s, &r__);
+	    if (i__ != m) {
+		e[i__ - 1] = r__;
+	    }
+	    g = d__[i__] - p;
+	    r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b;
+	    p = s * r__;
+	    d__[i__] = g + p;
+	    g = c__ * r__ - b;
+
+/*           if eigenvectors are desired, then save rotations. */
+
+	    if (icompz > 0) {
+		work[i__] = c__;
+		work[*n - 1 + i__] = s;
+	    }
+
+/* L120: */
+	}
+
+/*        if eigenvectors are desired, then apply saved rotations. */
+
+	if (icompz > 0) {
+	    mm = l - m + 1;
+/* $$$            call dlasr( 'r', 'v', 'f', n, mm, work( m ), work( n-1+m ),   
+   $$$     $                  z( 1, m ), ldz )   
+
+             *** New starting with version 2.5 *** */
+
+	    igraphdlasr_("r", "v", "f", &c__1, &mm, &work[m], &work[*n - 1 + m], &
+		    z__[m], &c__1);
+/*           ************************************* */
+	}
+
+	d__[l] -= p;
+	e[lm1] = g;
+	goto L90;
+
+/*        eigenvalue found. */
+
+L130:
+	d__[l] = p;
+
+	--l;
+	if (l >= lend) {
+	    goto L90;
+	}
+	goto L140;
+
+    }
+
+/*     undo scaling if necessary */
+
+L140:
+    if (iscale == 1) {
+	i__1 = lendsv - lsv + 1;
+	igraphdlascl_("g", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], 
+		n, info);
+	i__1 = lendsv - lsv;
+	igraphdlascl_("g", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, 
+		info);
+    } else if (iscale == 2) {
+	i__1 = lendsv - lsv + 1;
+	igraphdlascl_("g", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], 
+		n, info);
+	i__1 = lendsv - lsv;
+	igraphdlascl_("g", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, 
+		info);
+    }
+
+/*     check for no convergence to an eigenvalue after a total   
+       of n*maxit iterations. */
+
+    if (jtot < nmaxit) {
+	goto L10;
+    }
+    i__1 = *n - 1;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	if (e[i__] != 0.) {
+	    ++(*info);
+	}
+/* L150: */
+    }
+    goto L190;
+
+/*     order eigenvalues and eigenvectors. */
+
+L160:
+    if (icompz == 0) {
+
+/*        use quick sort */
+
+	igraphdlasrt_("i", n, &d__[1], info);
+
+    } else {
+
+/*        use selection sort to minimize swaps of eigenvectors */
+
+	i__1 = *n;
+	for (ii = 2; ii <= i__1; ++ii) {
+	    i__ = ii - 1;
+	    k = i__;
+	    p = d__[i__];
+	    i__2 = *n;
+	    for (j = ii; j <= i__2; ++j) {
+		if (d__[j] < p) {
+		    k = j;
+		    p = d__[j];
+		}
+/* L170: */
+	    }
+	    if (k != i__) {
+		d__[k] = d__[i__];
+		d__[i__] = p;
+/* $$$               call dswap( n, z( 1, i ), 1, z( 1, k ), 1 )   
+             *** New starting with version 2.5 *** */
+
+		p = z__[k];
+		z__[k] = z__[i__];
+		z__[i__] = p;
+/*           ************************************* */
+	    }
+/* L180: */
+	}
+    }
+
+L190:
+    return 0;
+
+/*     %---------------%   
+       | End of dstqrb |   
+       %---------------% */
+
+} /* igraphdstqrb_ */
+
diff --git a/src/lapack/dswap.c b/src/lapack/dswap.c
new file mode 100644
index 0000000..e25e850
--- /dev/null
+++ b/src/lapack/dswap.c
@@ -0,0 +1,104 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdswap_(integer *n, doublereal *dx, integer *incx, 
+	doublereal *dy, integer *incy)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Local variables */
+    integer i__, m, ix, iy, mp1;
+    doublereal dtemp;
+
+
+/*  Purpose   
+    =======   
+
+       interchanges two vectors.   
+       uses unrolled loops for increments equal one.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dy;
+    --dx;
+
+    /* Function Body */
+    if (*n <= 0) {
+	return 0;
+    }
+    if (*incx == 1 && *incy == 1) {
+
+/*       code for both increments equal to 1   
+
+
+         clean-up loop */
+
+	m = *n % 3;
+	if (m != 0) {
+	    i__1 = m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		dtemp = dx[i__];
+		dx[i__] = dy[i__];
+		dy[i__] = dtemp;
+	    }
+	    if (*n < 3) {
+		return 0;
+	    }
+	}
+	mp1 = m + 1;
+	i__1 = *n;
+	for (i__ = mp1; i__ <= i__1; i__ += 3) {
+	    dtemp = dx[i__];
+	    dx[i__] = dy[i__];
+	    dy[i__] = dtemp;
+	    dtemp = dx[i__ + 1];
+	    dx[i__ + 1] = dy[i__ + 1];
+	    dy[i__ + 1] = dtemp;
+	    dtemp = dx[i__ + 2];
+	    dx[i__ + 2] = dy[i__ + 2];
+	    dy[i__ + 2] = dtemp;
+	}
+    } else {
+
+/*       code for unequal increments or equal increments not equal   
+           to 1 */
+
+	ix = 1;
+	iy = 1;
+	if (*incx < 0) {
+	    ix = (-(*n) + 1) * *incx + 1;
+	}
+	if (*incy < 0) {
+	    iy = (-(*n) + 1) * *incy + 1;
+	}
+	i__1 = *n;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+	    dtemp = dx[ix];
+	    dx[ix] = dy[iy];
+	    dy[iy] = dtemp;
+	    ix += *incx;
+	    iy += *incy;
+	}
+    }
+    return 0;
+} /* igraphdswap_ */
+
diff --git a/src/lapack/dsyevr.c b/src/lapack/dsyevr.c
new file mode 100644
index 0000000..83b6250
--- /dev/null
+++ b/src/lapack/dsyevr.c
@@ -0,0 +1,644 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__10 = 10;
+static integer c__1 = 1;
+static integer c__2 = 2;
+static integer c__3 = 3;
+static integer c__4 = 4;
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdsyevr_(char *jobz, char *range, char *uplo, integer *n, 
+	doublereal *a, integer *lda, doublereal *vl, doublereal *vu, integer *
+	il, integer *iu, doublereal *abstol, integer *m, doublereal *w, 
+	doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, 
+	integer *lwork, integer *iwork, integer *liwork, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, z_dim1, z_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, nb, jj;
+    doublereal eps, vll, vuu, tmp1;
+    integer indd, inde;
+    doublereal anrm;
+    integer imax;
+    doublereal rmin, rmax;
+    integer inddd, indee;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    doublereal sigma;
+    extern logical igraphlsame_(char *, char *);
+    integer iinfo;
+    char order[1];
+    integer indwk;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *), igraphdswap_(integer *, doublereal *, integer 
+	    *, doublereal *, integer *);
+    integer lwmin;
+    logical lower, wantz;
+    extern doublereal igraphdlamch_(char *);
+    logical alleig, indeig;
+    integer iscale, ieeeok, indibl, indifl;
+    logical valeig;
+    doublereal safmin;
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    doublereal abstll, bignum;
+    integer indtau, indisp;
+    extern /* Subroutine */ int igraphdstein_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *, integer *), 
+	    igraphdsterf_(integer *, doublereal *, doublereal *, integer *);
+    integer indiwo, indwkn;
+    extern doublereal igraphdlansy_(char *, char *, integer *, doublereal *, 
+	    integer *, doublereal *);
+    extern /* Subroutine */ int igraphdstebz_(char *, char *, integer *, doublereal 
+	    *, doublereal *, integer *, integer *, doublereal *, doublereal *,
+	     doublereal *, integer *, integer *, doublereal *, integer *, 
+	    integer *, doublereal *, integer *, integer *), 
+	    igraphdstemr_(char *, char *, integer *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *, integer *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, integer *, integer *, 
+	    logical *, doublereal *, integer *, integer *, integer *, integer 
+	    *);
+    integer liwmin;
+    logical tryrac;
+    extern /* Subroutine */ int igraphdormtr_(char *, char *, char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *);
+    integer llwrkn, llwork, nsplit;
+    doublereal smlnum;
+    extern /* Subroutine */ int igraphdsytrd_(char *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, doublereal *, doublereal *,
+	     integer *, integer *);
+    integer lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK driver routine (version 3.2.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       June 2010   
+
+
+    Purpose   
+    =======   
+
+    DSYEVR computes selected eigenvalues and, optionally, eigenvectors   
+    of a real symmetric matrix A.  Eigenvalues and eigenvectors can be   
+    selected by specifying either a range of values or a range of   
+    indices for the desired eigenvalues.   
+
+    DSYEVR first reduces the matrix A to tridiagonal form T with a call   
+    to DSYTRD.  Then, whenever possible, DSYEVR calls DSTEMR to compute   
+    the eigenspectrum using Relatively Robust Representations.  DSTEMR   
+    computes eigenvalues by the dqds algorithm, while orthogonal   
+    eigenvectors are computed from various "good" L D L^T representations   
+    (also known as Relatively Robust Representations). Gram-Schmidt   
+    orthogonalization is avoided as far as possible. More specifically,   
+    the various steps of the algorithm are as follows.   
+
+    For each unreduced block (submatrix) of T,   
+       (a) Compute T - sigma I  = L D L^T, so that L and D   
+           define all the wanted eigenvalues to high relative accuracy.   
+           This means that small relative changes in the entries of D and L   
+           cause only small relative changes in the eigenvalues and   
+           eigenvectors. The standard (unfactored) representation of the   
+           tridiagonal matrix T does not have this property in general.   
+       (b) Compute the eigenvalues to suitable accuracy.   
+           If the eigenvectors are desired, the algorithm attains full   
+           accuracy of the computed eigenvalues only right before   
+           the corresponding vectors have to be computed, see steps c) and d).   
+       (c) For each cluster of close eigenvalues, select a new   
+           shift close to the cluster, find a new factorization, and refine   
+           the shifted eigenvalues to suitable accuracy.   
+       (d) For each eigenvalue with a large enough relative separation compute   
+           the corresponding eigenvector by forming a rank revealing twisted   
+           factorization. Go back to (c) for any clusters that remain.   
+
+    The desired accuracy of the output can be specified by the input   
+    parameter ABSTOL.   
+
+    For more details, see DSTEMR's documentation and:   
+    - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations   
+      to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"   
+      Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.   
+    - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and   
+      Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,   
+      2004.  Also LAPACK Working Note 154.   
+    - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric   
+      tridiagonal eigenvalue/eigenvector problem",   
+      Computer Science Division Technical Report No. UCB/CSD-97-971,   
+      UC Berkeley, May 1997.   
+
+
+    Note 1 : DSYEVR calls DSTEMR when the full spectrum is requested   
+    on machines which conform to the ieee-754 floating point standard.   
+    DSYEVR calls DSTEBZ and SSTEIN on non-ieee machines and   
+    when partial spectrum requests are made.   
+
+    Normal execution of DSTEMR may create NaNs and infinities and   
+    hence may abort due to a floating point exception in environments   
+    which do not handle NaNs and infinities in the ieee standard default   
+    manner.   
+
+    Arguments   
+    =========   
+
+    JOBZ    (input) CHARACTER*1   
+            = 'N':  Compute eigenvalues only;   
+            = 'V':  Compute eigenvalues and eigenvectors.   
+
+    RANGE   (input) CHARACTER*1   
+            = 'A': all eigenvalues will be found.   
+            = 'V': all eigenvalues in the half-open interval (VL,VU]   
+                   will be found.   
+            = 'I': the IL-th through IU-th eigenvalues will be found.   
+   ********* For RANGE = 'V' or 'I' and IU - IL < N - 1, DSTEBZ and   
+   ********* DSTEIN are called   
+
+    UPLO    (input) CHARACTER*1   
+            = 'U':  Upper triangle of A is stored;   
+            = 'L':  Lower triangle of A is stored.   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA, N)   
+            On entry, the symmetric matrix A.  If UPLO = 'U', the   
+            leading N-by-N upper triangular part of A contains the   
+            upper triangular part of the matrix A.  If UPLO = 'L',   
+            the leading N-by-N lower triangular part of A contains   
+            the lower triangular part of the matrix A.   
+            On exit, the lower triangle (if UPLO='L') or the upper   
+            triangle (if UPLO='U') of A, including the diagonal, is   
+            destroyed.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    VL      (input) DOUBLE PRECISION   
+    VU      (input) DOUBLE PRECISION   
+            If RANGE='V', the lower and upper bounds of the interval to   
+            be searched for eigenvalues. VL < VU.   
+            Not referenced if RANGE = 'A' or 'I'.   
+
+    IL      (input) INTEGER   
+    IU      (input) INTEGER   
+            If RANGE='I', the indices (in ascending order) of the   
+            smallest and largest eigenvalues to be returned.   
+            1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.   
+            Not referenced if RANGE = 'A' or 'V'.   
+
+    ABSTOL  (input) DOUBLE PRECISION   
+            The absolute error tolerance for the eigenvalues.   
+            An approximate eigenvalue is accepted as converged   
+            when it is determined to lie in an interval [a,b]   
+            of width less than or equal to   
+
+                    ABSTOL + EPS *   max( |a|,|b| ) ,   
+
+            where EPS is the machine precision.  If ABSTOL is less than   
+            or equal to zero, then  EPS*|T|  will be used in its place,   
+            where |T| is the 1-norm of the tridiagonal matrix obtained   
+            by reducing A to tridiagonal form.   
+
+            See "Computing Small Singular Values of Bidiagonal Matrices   
+            with Guaranteed High Relative Accuracy," by Demmel and   
+            Kahan, LAPACK Working Note #3.   
+
+            If high relative accuracy is important, set ABSTOL to   
+            DLAMCH( 'Safe minimum' ).  Doing so will guarantee that   
+            eigenvalues are computed to high relative accuracy when   
+            possible in future releases.  The current code does not   
+            make any guarantees about high relative accuracy, but   
+            future releases will. See J. Barlow and J. Demmel,   
+            "Computing Accurate Eigensystems of Scaled Diagonally   
+            Dominant Matrices", LAPACK Working Note #7, for a discussion   
+            of which matrices define their eigenvalues to high relative   
+            accuracy.   
+
+    M       (output) INTEGER   
+            The total number of eigenvalues found.  0 <= M <= N.   
+            If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.   
+
+    W       (output) DOUBLE PRECISION array, dimension (N)   
+            The first M elements contain the selected eigenvalues in   
+            ascending order.   
+
+    Z       (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M))   
+            If JOBZ = 'V', then if INFO = 0, the first M columns of Z   
+            contain the orthonormal eigenvectors of the matrix A   
+            corresponding to the selected eigenvalues, with the i-th   
+            column of Z holding the eigenvector associated with W(i).   
+            If JOBZ = 'N', then Z is not referenced.   
+            Note: the user must ensure that at least max(1,M) columns are   
+            supplied in the array Z; if RANGE = 'V', the exact value of M   
+            is not known in advance and an upper bound must be used.   
+            Supplying N columns is always safe.   
+
+    LDZ     (input) INTEGER   
+            The leading dimension of the array Z.  LDZ >= 1, and if   
+            JOBZ = 'V', LDZ >= max(1,N).   
+
+    ISUPPZ  (output) INTEGER array, dimension ( 2*max(1,M) )   
+            The support of the eigenvectors in Z, i.e., the indices   
+            indicating the nonzero elements in Z. The i-th eigenvector   
+            is nonzero only in elements ISUPPZ( 2*i-1 ) through   
+            ISUPPZ( 2*i ).   
+   ********* Implemented only for RANGE = 'A' or 'I' and IU - IL = N - 1   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.  LWORK >= max(1,26*N).   
+            For optimal efficiency, LWORK >= (NB+6)*N,   
+            where NB is the max of the blocksize for DSYTRD and DORMTR   
+            returned by ILAENV.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    IWORK   (workspace/output) INTEGER array, dimension (MAX(1,LIWORK))   
+            On exit, if INFO = 0, IWORK(1) returns the optimal LWORK.   
+
+    LIWORK  (input) INTEGER   
+            The dimension of the array IWORK.  LIWORK >= max(1,10*N).   
+
+            If LIWORK = -1, then a workspace query is assumed; the   
+            routine only calculates the optimal size of the IWORK array,   
+            returns this value as the first entry of the IWORK array, and   
+            no error message related to LIWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            > 0:  Internal error   
+
+    Further Details   
+    ===============   
+
+    Based on contributions by   
+       Inderjit Dhillon, IBM Almaden, USA   
+       Osni Marques, LBNL/NERSC, USA   
+       Ken Stanley, Computer Science Division, University of   
+         California at Berkeley, USA   
+       Jason Riedy, Computer Science Division, University of   
+         California at Berkeley, USA   
+
+   =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --w;
+    z_dim1 = *ldz;
+    z_offset = 1 + z_dim1;
+    z__ -= z_offset;
+    --isuppz;
+    --work;
+    --iwork;
+
+    /* Function Body */
+    ieeeok = igraphilaenv_(&c__10, "DSYEVR", "N", &c__1, &c__2, &c__3, &c__4, (
+	    ftnlen)6, (ftnlen)1);
+
+    lower = igraphlsame_(uplo, "L");
+    wantz = igraphlsame_(jobz, "V");
+    alleig = igraphlsame_(range, "A");
+    valeig = igraphlsame_(range, "V");
+    indeig = igraphlsame_(range, "I");
+
+    lquery = *lwork == -1 || *liwork == -1;
+
+/* Computing MAX */
+    i__1 = 1, i__2 = *n * 26;
+    lwmin = max(i__1,i__2);
+/* Computing MAX */
+    i__1 = 1, i__2 = *n * 10;
+    liwmin = max(i__1,i__2);
+
+    *info = 0;
+    if (! (wantz || igraphlsame_(jobz, "N"))) {
+	*info = -1;
+    } else if (! (alleig || valeig || indeig)) {
+	*info = -2;
+    } else if (! (lower || igraphlsame_(uplo, "U"))) {
+	*info = -3;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*lda < max(1,*n)) {
+	*info = -6;
+    } else {
+	if (valeig) {
+	    if (*n > 0 && *vu <= *vl) {
+		*info = -8;
+	    }
+	} else if (indeig) {
+	    if (*il < 1 || *il > max(1,*n)) {
+		*info = -9;
+	    } else if (*iu < min(*n,*il) || *iu > *n) {
+		*info = -10;
+	    }
+	}
+    }
+    if (*info == 0) {
+	if (*ldz < 1 || wantz && *ldz < *n) {
+	    *info = -15;
+	} else if (*lwork < lwmin && ! lquery) {
+	    *info = -18;
+	} else if (*liwork < liwmin && ! lquery) {
+	    *info = -20;
+	}
+    }
+
+    if (*info == 0) {
+	nb = igraphilaenv_(&c__1, "DSYTRD", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6,
+		 (ftnlen)1);
+/* Computing MAX */
+	i__1 = nb, i__2 = igraphilaenv_(&c__1, "DORMTR", uplo, n, &c_n1, &c_n1, &
+		c_n1, (ftnlen)6, (ftnlen)1);
+	nb = max(i__1,i__2);
+/* Computing MAX */
+	i__1 = (nb + 1) * *n;
+	lwkopt = max(i__1,lwmin);
+	work[1] = (doublereal) lwkopt;
+	iwork[1] = liwmin;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DSYEVR", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    *m = 0;
+    if (*n == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    if (*n == 1) {
+	work[1] = 7.;
+	if (alleig || indeig) {
+	    *m = 1;
+	    w[1] = a[a_dim1 + 1];
+	} else {
+	    if (*vl < a[a_dim1 + 1] && *vu >= a[a_dim1 + 1]) {
+		*m = 1;
+		w[1] = a[a_dim1 + 1];
+	    }
+	}
+	if (wantz) {
+	    z__[z_dim1 + 1] = 1.;
+	    isuppz[1] = 1;
+	    isuppz[2] = 1;
+	}
+	return 0;
+    }
+
+/*     Get machine constants. */
+
+    safmin = igraphdlamch_("Safe minimum");
+    eps = igraphdlamch_("Precision");
+    smlnum = safmin / eps;
+    bignum = 1. / smlnum;
+    rmin = sqrt(smlnum);
+/* Computing MIN */
+    d__1 = sqrt(bignum), d__2 = 1. / sqrt(sqrt(safmin));
+    rmax = min(d__1,d__2);
+
+/*     Scale matrix to allowable range, if necessary. */
+
+    iscale = 0;
+    abstll = *abstol;
+    if (valeig) {
+	vll = *vl;
+	vuu = *vu;
+    }
+    anrm = igraphdlansy_("M", uplo, n, &a[a_offset], lda, &work[1]);
+    if (anrm > 0. && anrm < rmin) {
+	iscale = 1;
+	sigma = rmin / anrm;
+    } else if (anrm > rmax) {
+	iscale = 1;
+	sigma = rmax / anrm;
+    }
+    if (iscale == 1) {
+	if (lower) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *n - j + 1;
+		igraphdscal_(&i__2, &sigma, &a[j + j * a_dim1], &c__1);
+/* L10: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		igraphdscal_(&j, &sigma, &a[j * a_dim1 + 1], &c__1);
+/* L20: */
+	    }
+	}
+	if (*abstol > 0.) {
+	    abstll = *abstol * sigma;
+	}
+	if (valeig) {
+	    vll = *vl * sigma;
+	    vuu = *vu * sigma;
+	}
+    }
+/*     Initialize indices into workspaces.  Note: The IWORK indices are   
+       used only if DSTERF or DSTEMR fail.   
+       WORK(INDTAU:INDTAU+N-1) stores the scalar factors of the   
+       elementary reflectors used in DSYTRD. */
+    indtau = 1;
+/*     WORK(INDD:INDD+N-1) stores the tridiagonal's diagonal entries. */
+    indd = indtau + *n;
+/*     WORK(INDE:INDE+N-1) stores the off-diagonal entries of the   
+       tridiagonal matrix from DSYTRD. */
+    inde = indd + *n;
+/*     WORK(INDDD:INDDD+N-1) is a copy of the diagonal entries over   
+       -written by DSTEMR (the DSTERF path copies the diagonal to W). */
+    inddd = inde + *n;
+/*     WORK(INDEE:INDEE+N-1) is a copy of the off-diagonal entries over   
+       -written while computing the eigenvalues in DSTERF and DSTEMR. */
+    indee = inddd + *n;
+/*     INDWK is the starting offset of the left-over workspace, and   
+       LLWORK is the remaining workspace size. */
+    indwk = indee + *n;
+    llwork = *lwork - indwk + 1;
+/*     IWORK(INDIBL:INDIBL+M-1) corresponds to IBLOCK in DSTEBZ and   
+       stores the block indices of each of the M<=N eigenvalues. */
+    indibl = 1;
+/*     IWORK(INDISP:INDISP+NSPLIT-1) corresponds to ISPLIT in DSTEBZ and   
+       stores the starting and finishing indices of each block. */
+    indisp = indibl + *n;
+/*     IWORK(INDIFL:INDIFL+N-1) stores the indices of eigenvectors   
+       that corresponding to eigenvectors that fail to converge in   
+       DSTEIN.  This information is discarded; if any fail, the driver   
+       returns INFO > 0. */
+    indifl = indisp + *n;
+/*     INDIWO is the offset of the remaining integer workspace. */
+    indiwo = indisp + *n;
+
+/*     Call DSYTRD to reduce symmetric matrix to tridiagonal form. */
+
+    igraphdsytrd_(uplo, n, &a[a_offset], lda, &work[indd], &work[inde], &work[
+	    indtau], &work[indwk], &llwork, &iinfo);
+
+/*     If all eigenvalues are desired   
+       then call DSTERF or DSTEMR and DORMTR. */
+
+    if ((alleig || indeig && *il == 1 && *iu == *n) && ieeeok == 1) {
+	if (! wantz) {
+	    igraphdcopy_(n, &work[indd], &c__1, &w[1], &c__1);
+	    i__1 = *n - 1;
+	    igraphdcopy_(&i__1, &work[inde], &c__1, &work[indee], &c__1);
+	    igraphdsterf_(n, &w[1], &work[indee], info);
+	} else {
+	    i__1 = *n - 1;
+	    igraphdcopy_(&i__1, &work[inde], &c__1, &work[indee], &c__1);
+	    igraphdcopy_(n, &work[indd], &c__1, &work[inddd], &c__1);
+
+	    if (*abstol <= *n * 2. * eps) {
+		tryrac = TRUE_;
+	    } else {
+		tryrac = FALSE_;
+	    }
+	    igraphdstemr_(jobz, "A", n, &work[inddd], &work[indee], vl, vu, il, iu, 
+		    m, &w[1], &z__[z_offset], ldz, n, &isuppz[1], &tryrac, &
+		    work[indwk], lwork, &iwork[1], liwork, info);
+
+
+
+/*        Apply orthogonal matrix used in reduction to tridiagonal   
+          form to eigenvectors returned by DSTEIN. */
+
+	    if (wantz && *info == 0) {
+		indwkn = inde;
+		llwrkn = *lwork - indwkn + 1;
+		igraphdormtr_("L", uplo, "N", n, m, &a[a_offset], lda, &work[indtau]
+			, &z__[z_offset], ldz, &work[indwkn], &llwrkn, &iinfo);
+	    }
+	}
+
+
+	if (*info == 0) {
+/*           Everything worked.  Skip DSTEBZ/DSTEIN.  IWORK(:) are   
+             undefined. */
+	    *m = *n;
+	    goto L30;
+	}
+	*info = 0;
+    }
+
+/*     Otherwise, call DSTEBZ and, if eigenvectors are desired, DSTEIN.   
+       Also call DSTEBZ and DSTEIN if DSTEMR fails. */
+
+    if (wantz) {
+	*(unsigned char *)order = 'B';
+    } else {
+	*(unsigned char *)order = 'E';
+    }
+    igraphdstebz_(range, order, n, &vll, &vuu, il, iu, &abstll, &work[indd], &work[
+	    inde], m, &nsplit, &w[1], &iwork[indibl], &iwork[indisp], &work[
+	    indwk], &iwork[indiwo], info);
+
+    if (wantz) {
+	igraphdstein_(n, &work[indd], &work[inde], m, &w[1], &iwork[indibl], &iwork[
+		indisp], &z__[z_offset], ldz, &work[indwk], &iwork[indiwo], &
+		iwork[indifl], info);
+
+/*        Apply orthogonal matrix used in reduction to tridiagonal   
+          form to eigenvectors returned by DSTEIN. */
+
+	indwkn = inde;
+	llwrkn = *lwork - indwkn + 1;
+	igraphdormtr_("L", uplo, "N", n, m, &a[a_offset], lda, &work[indtau], &z__[
+		z_offset], ldz, &work[indwkn], &llwrkn, &iinfo);
+    }
+
+/*     If matrix was scaled, then rescale eigenvalues appropriately.   
+
+    Jump here if DSTEMR/DSTEIN succeeded. */
+L30:
+    if (iscale == 1) {
+	if (*info == 0) {
+	    imax = *m;
+	} else {
+	    imax = *info - 1;
+	}
+	d__1 = 1. / sigma;
+	igraphdscal_(&imax, &d__1, &w[1], &c__1);
+    }
+
+/*     If eigenvalues are not in order, then sort them, along with   
+       eigenvectors.  Note: We do not sort the IFAIL portion of IWORK.   
+       It may not be initialized (if DSTEMR/DSTEIN succeeded), and we do   
+       not return this detailed information to the user. */
+
+    if (wantz) {
+	i__1 = *m - 1;
+	for (j = 1; j <= i__1; ++j) {
+	    i__ = 0;
+	    tmp1 = w[j];
+	    i__2 = *m;
+	    for (jj = j + 1; jj <= i__2; ++jj) {
+		if (w[jj] < tmp1) {
+		    i__ = jj;
+		    tmp1 = w[jj];
+		}
+/* L40: */
+	    }
+
+	    if (i__ != 0) {
+		w[i__] = w[j];
+		w[j] = tmp1;
+		igraphdswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[j * z_dim1 + 1],
+			 &c__1);
+	    }
+/* L50: */
+	}
+    }
+
+/*     Set WORK(1) to optimal workspace size. */
+
+    work[1] = (doublereal) lwkopt;
+    iwork[1] = liwmin;
+
+    return 0;
+
+/*     End of DSYEVR */
+
+} /* igraphdsyevr_ */
+
diff --git a/src/lapack/dsymv.c b/src/lapack/dsymv.c
new file mode 100644
index 0000000..7b34a99
--- /dev/null
+++ b/src/lapack/dsymv.c
@@ -0,0 +1,303 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdsymv_(char *uplo, integer *n, doublereal *alpha, 
+	doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal 
+	*beta, doublereal *y, integer *incy)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, ix, iy, jx, jy, kx, ky, info;
+    doublereal temp1, temp2;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  Purpose   
+    =======   
+
+    DSYMV  performs the matrix-vector  operation   
+
+       y := alpha*A*x + beta*y,   
+
+    where alpha and beta are scalars, x and y are n element vectors and   
+    A is an n by n symmetric matrix.   
+
+    Arguments   
+    ==========   
+
+    UPLO   - CHARACTER*1.   
+             On entry, UPLO specifies whether the upper or lower   
+             triangular part of the array A is to be referenced as   
+             follows:   
+
+                UPLO = 'U' or 'u'   Only the upper triangular part of A   
+                                    is to be referenced.   
+
+                UPLO = 'L' or 'l'   Only the lower triangular part of A   
+                                    is to be referenced.   
+
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the order of the matrix A.   
+             N must be at least zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry, ALPHA specifies the scalar alpha.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, n ).   
+             Before entry with  UPLO = 'U' or 'u', the leading n by n   
+             upper triangular part of the array A must contain the upper   
+             triangular part of the symmetric matrix and the strictly   
+             lower triangular part of A is not referenced.   
+             Before entry with UPLO = 'L' or 'l', the leading n by n   
+             lower triangular part of the array A must contain the lower   
+             triangular part of the symmetric matrix and the strictly   
+             upper triangular part of A is not referenced.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program. LDA must be at least   
+             max( 1, n ).   
+             Unchanged on exit.   
+
+    X      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( n - 1 )*abs( INCX ) ).   
+             Before entry, the incremented array X must contain the n   
+             element vector x.   
+             Unchanged on exit.   
+
+    INCX   - INTEGER.   
+             On entry, INCX specifies the increment for the elements of   
+             X. INCX must not be zero.   
+             Unchanged on exit.   
+
+    BETA   - DOUBLE PRECISION.   
+             On entry, BETA specifies the scalar beta. When BETA is   
+             supplied as zero then Y need not be set on input.   
+             Unchanged on exit.   
+
+    Y      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( n - 1 )*abs( INCY ) ).   
+             Before entry, the incremented array Y must contain the n   
+             element vector y. On exit, Y is overwritten by the updated   
+             vector y.   
+
+    INCY   - INTEGER.   
+             On entry, INCY specifies the increment for the elements of   
+             Y. INCY must not be zero.   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 2 Blas routine.   
+    The vector and matrix arguments are not referenced when N = 0, or M = 0   
+
+    -- Written on 22-October-1986.   
+       Jack Dongarra, Argonne National Lab.   
+       Jeremy Du Croz, Nag Central Office.   
+       Sven Hammarling, Nag Central Office.   
+       Richard Hanson, Sandia National Labs.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --x;
+    --y;
+
+    /* Function Body */
+    info = 0;
+    if (! igraphlsame_(uplo, "U") && ! igraphlsame_(uplo, "L")) {
+	info = 1;
+    } else if (*n < 0) {
+	info = 2;
+    } else if (*lda < max(1,*n)) {
+	info = 5;
+    } else if (*incx == 0) {
+	info = 7;
+    } else if (*incy == 0) {
+	info = 10;
+    }
+    if (info != 0) {
+	igraphxerbla_("DSYMV ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*n == 0 || *alpha == 0. && *beta == 1.) {
+	return 0;
+    }
+
+/*     Set up the start points in  X  and  Y. */
+
+    if (*incx > 0) {
+	kx = 1;
+    } else {
+	kx = 1 - (*n - 1) * *incx;
+    }
+    if (*incy > 0) {
+	ky = 1;
+    } else {
+	ky = 1 - (*n - 1) * *incy;
+    }
+
+/*     Start the operations. In this version the elements of A are   
+       accessed sequentially with one pass through the triangular part   
+       of A.   
+
+       First form  y := beta*y. */
+
+    if (*beta != 1.) {
+	if (*incy == 1) {
+	    if (*beta == 0.) {
+		i__1 = *n;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[i__] = 0.;
+/* L10: */
+		}
+	    } else {
+		i__1 = *n;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[i__] = *beta * y[i__];
+/* L20: */
+		}
+	    }
+	} else {
+	    iy = ky;
+	    if (*beta == 0.) {
+		i__1 = *n;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[iy] = 0.;
+		    iy += *incy;
+/* L30: */
+		}
+	    } else {
+		i__1 = *n;
+		for (i__ = 1; i__ <= i__1; ++i__) {
+		    y[iy] = *beta * y[iy];
+		    iy += *incy;
+/* L40: */
+		}
+	    }
+	}
+    }
+    if (*alpha == 0.) {
+	return 0;
+    }
+    if (igraphlsame_(uplo, "U")) {
+
+/*        Form  y  when A is stored in upper triangle. */
+
+	if (*incx == 1 && *incy == 1) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		temp1 = *alpha * x[j];
+		temp2 = 0.;
+		i__2 = j - 1;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    y[i__] += temp1 * a[i__ + j * a_dim1];
+		    temp2 += a[i__ + j * a_dim1] * x[i__];
+/* L50: */
+		}
+		y[j] = y[j] + temp1 * a[j + j * a_dim1] + *alpha * temp2;
+/* L60: */
+	    }
+	} else {
+	    jx = kx;
+	    jy = ky;
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		temp1 = *alpha * x[jx];
+		temp2 = 0.;
+		ix = kx;
+		iy = ky;
+		i__2 = j - 1;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    y[iy] += temp1 * a[i__ + j * a_dim1];
+		    temp2 += a[i__ + j * a_dim1] * x[ix];
+		    ix += *incx;
+		    iy += *incy;
+/* L70: */
+		}
+		y[jy] = y[jy] + temp1 * a[j + j * a_dim1] + *alpha * temp2;
+		jx += *incx;
+		jy += *incy;
+/* L80: */
+	    }
+	}
+    } else {
+
+/*        Form  y  when A is stored in lower triangle. */
+
+	if (*incx == 1 && *incy == 1) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		temp1 = *alpha * x[j];
+		temp2 = 0.;
+		y[j] += temp1 * a[j + j * a_dim1];
+		i__2 = *n;
+		for (i__ = j + 1; i__ <= i__2; ++i__) {
+		    y[i__] += temp1 * a[i__ + j * a_dim1];
+		    temp2 += a[i__ + j * a_dim1] * x[i__];
+/* L90: */
+		}
+		y[j] += *alpha * temp2;
+/* L100: */
+	    }
+	} else {
+	    jx = kx;
+	    jy = ky;
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		temp1 = *alpha * x[jx];
+		temp2 = 0.;
+		y[jy] += temp1 * a[j + j * a_dim1];
+		ix = jx;
+		iy = jy;
+		i__2 = *n;
+		for (i__ = j + 1; i__ <= i__2; ++i__) {
+		    ix += *incx;
+		    iy += *incy;
+		    y[iy] += temp1 * a[i__ + j * a_dim1];
+		    temp2 += a[i__ + j * a_dim1] * x[ix];
+/* L110: */
+		}
+		y[jy] += *alpha * temp2;
+		jx += *incx;
+		jy += *incy;
+/* L120: */
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DSYMV . */
+
+} /* igraphdsymv_ */
+
diff --git a/src/lapack/dsyr2.c b/src/lapack/dsyr2.c
new file mode 100644
index 0000000..2aadcdf
--- /dev/null
+++ b/src/lapack/dsyr2.c
@@ -0,0 +1,264 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdsyr2_(char *uplo, integer *n, doublereal *alpha, 
+	doublereal *x, integer *incx, doublereal *y, integer *incy, 
+	doublereal *a, integer *lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, ix, iy, jx, jy, kx, ky, info;
+    doublereal temp1, temp2;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  Purpose   
+    =======   
+
+    DSYR2  performs the symmetric rank 2 operation   
+
+       A := alpha*x*y**T + alpha*y*x**T + A,   
+
+    where alpha is a scalar, x and y are n element vectors and A is an n   
+    by n symmetric matrix.   
+
+    Arguments   
+    ==========   
+
+    UPLO   - CHARACTER*1.   
+             On entry, UPLO specifies whether the upper or lower   
+             triangular part of the array A is to be referenced as   
+             follows:   
+
+                UPLO = 'U' or 'u'   Only the upper triangular part of A   
+                                    is to be referenced.   
+
+                UPLO = 'L' or 'l'   Only the lower triangular part of A   
+                                    is to be referenced.   
+
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the order of the matrix A.   
+             N must be at least zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry, ALPHA specifies the scalar alpha.   
+             Unchanged on exit.   
+
+    X      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( n - 1 )*abs( INCX ) ).   
+             Before entry, the incremented array X must contain the n   
+             element vector x.   
+             Unchanged on exit.   
+
+    INCX   - INTEGER.   
+             On entry, INCX specifies the increment for the elements of   
+             X. INCX must not be zero.   
+             Unchanged on exit.   
+
+    Y      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( n - 1 )*abs( INCY ) ).   
+             Before entry, the incremented array Y must contain the n   
+             element vector y.   
+             Unchanged on exit.   
+
+    INCY   - INTEGER.   
+             On entry, INCY specifies the increment for the elements of   
+             Y. INCY must not be zero.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, n ).   
+             Before entry with  UPLO = 'U' or 'u', the leading n by n   
+             upper triangular part of the array A must contain the upper   
+             triangular part of the symmetric matrix and the strictly   
+             lower triangular part of A is not referenced. On exit, the   
+             upper triangular part of the array A is overwritten by the   
+             upper triangular part of the updated matrix.   
+             Before entry with UPLO = 'L' or 'l', the leading n by n   
+             lower triangular part of the array A must contain the lower   
+             triangular part of the symmetric matrix and the strictly   
+             upper triangular part of A is not referenced. On exit, the   
+             lower triangular part of the array A is overwritten by the   
+             lower triangular part of the updated matrix.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program. LDA must be at least   
+             max( 1, n ).   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 2 Blas routine.   
+
+    -- Written on 22-October-1986.   
+       Jack Dongarra, Argonne National Lab.   
+       Jeremy Du Croz, Nag Central Office.   
+       Sven Hammarling, Nag Central Office.   
+       Richard Hanson, Sandia National Labs.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    --x;
+    --y;
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    info = 0;
+    if (! igraphlsame_(uplo, "U") && ! igraphlsame_(uplo, "L")) {
+	info = 1;
+    } else if (*n < 0) {
+	info = 2;
+    } else if (*incx == 0) {
+	info = 5;
+    } else if (*incy == 0) {
+	info = 7;
+    } else if (*lda < max(1,*n)) {
+	info = 9;
+    }
+    if (info != 0) {
+	igraphxerbla_("DSYR2 ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*n == 0 || *alpha == 0.) {
+	return 0;
+    }
+
+/*     Set up the start points in X and Y if the increments are not both   
+       unity. */
+
+    if (*incx != 1 || *incy != 1) {
+	if (*incx > 0) {
+	    kx = 1;
+	} else {
+	    kx = 1 - (*n - 1) * *incx;
+	}
+	if (*incy > 0) {
+	    ky = 1;
+	} else {
+	    ky = 1 - (*n - 1) * *incy;
+	}
+	jx = kx;
+	jy = ky;
+    }
+
+/*     Start the operations. In this version the elements of A are   
+       accessed sequentially with one pass through the triangular part   
+       of A. */
+
+    if (igraphlsame_(uplo, "U")) {
+
+/*        Form  A  when A is stored in the upper triangle. */
+
+	if (*incx == 1 && *incy == 1) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (x[j] != 0. || y[j] != 0.) {
+		    temp1 = *alpha * y[j];
+		    temp2 = *alpha * x[j];
+		    i__2 = j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[i__] * 
+				temp1 + y[i__] * temp2;
+/* L10: */
+		    }
+		}
+/* L20: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (x[jx] != 0. || y[jy] != 0.) {
+		    temp1 = *alpha * y[jy];
+		    temp2 = *alpha * x[jx];
+		    ix = kx;
+		    iy = ky;
+		    i__2 = j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[ix] * 
+				temp1 + y[iy] * temp2;
+			ix += *incx;
+			iy += *incy;
+/* L30: */
+		    }
+		}
+		jx += *incx;
+		jy += *incy;
+/* L40: */
+	    }
+	}
+    } else {
+
+/*        Form  A  when A is stored in the lower triangle. */
+
+	if (*incx == 1 && *incy == 1) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (x[j] != 0. || y[j] != 0.) {
+		    temp1 = *alpha * y[j];
+		    temp2 = *alpha * x[j];
+		    i__2 = *n;
+		    for (i__ = j; i__ <= i__2; ++i__) {
+			a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[i__] * 
+				temp1 + y[i__] * temp2;
+/* L50: */
+		    }
+		}
+/* L60: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (x[jx] != 0. || y[jy] != 0.) {
+		    temp1 = *alpha * y[jy];
+		    temp2 = *alpha * x[jx];
+		    ix = jx;
+		    iy = jy;
+		    i__2 = *n;
+		    for (i__ = j; i__ <= i__2; ++i__) {
+			a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[ix] * 
+				temp1 + y[iy] * temp2;
+			ix += *incx;
+			iy += *incy;
+/* L70: */
+		    }
+		}
+		jx += *incx;
+		jy += *incy;
+/* L80: */
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DSYR2 . */
+
+} /* igraphdsyr2_ */
+
diff --git a/src/lapack/dsyr2k.c b/src/lapack/dsyr2k.c
new file mode 100644
index 0000000..4987150
--- /dev/null
+++ b/src/lapack/dsyr2k.c
@@ -0,0 +1,396 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdsyr2k_(char *uplo, char *trans, integer *n, integer *k, 
+	doublereal *alpha, doublereal *a, integer *lda, doublereal *b, 
+	integer *ldb, doublereal *beta, doublereal *c__, integer *ldc)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, 
+	    i__3;
+
+    /* Local variables */
+    integer i__, j, l, info;
+    doublereal temp1, temp2;
+    extern logical igraphlsame_(char *, char *);
+    integer nrowa;
+    logical upper;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+
+
+/*  Purpose   
+    =======   
+
+    DSYR2K  performs one of the symmetric rank 2k operations   
+
+       C := alpha*A*B**T + alpha*B*A**T + beta*C,   
+
+    or   
+
+       C := alpha*A**T*B + alpha*B**T*A + beta*C,   
+
+    where  alpha and beta  are scalars, C is an  n by n  symmetric matrix   
+    and  A and B  are  n by k  matrices  in the  first  case  and  k by n   
+    matrices in the second case.   
+
+    Arguments   
+    ==========   
+
+    UPLO   - CHARACTER*1.   
+             On  entry,   UPLO  specifies  whether  the  upper  or  lower   
+             triangular  part  of the  array  C  is to be  referenced  as   
+             follows:   
+
+                UPLO = 'U' or 'u'   Only the  upper triangular part of  C   
+                                    is to be referenced.   
+
+                UPLO = 'L' or 'l'   Only the  lower triangular part of  C   
+                                    is to be referenced.   
+
+             Unchanged on exit.   
+
+    TRANS  - CHARACTER*1.   
+             On entry,  TRANS  specifies the operation to be performed as   
+             follows:   
+
+                TRANS = 'N' or 'n'   C := alpha*A*B**T + alpha*B*A**T +   
+                                          beta*C.   
+
+                TRANS = 'T' or 't'   C := alpha*A**T*B + alpha*B**T*A +   
+                                          beta*C.   
+
+                TRANS = 'C' or 'c'   C := alpha*A**T*B + alpha*B**T*A +   
+                                          beta*C.   
+
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry,  N specifies the order of the matrix C.  N must be   
+             at least zero.   
+             Unchanged on exit.   
+
+    K      - INTEGER.   
+             On entry with  TRANS = 'N' or 'n',  K  specifies  the number   
+             of  columns  of the  matrices  A and B,  and on  entry  with   
+             TRANS = 'T' or 't' or 'C' or 'c',  K  specifies  the  number   
+             of rows of the matrices  A and B.  K must be at least  zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry, ALPHA specifies the scalar alpha.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is   
+             k  when  TRANS = 'N' or 'n',  and is  n  otherwise.   
+             Before entry with  TRANS = 'N' or 'n',  the  leading  n by k   
+             part of the array  A  must contain the matrix  A,  otherwise   
+             the leading  k by n  part of the array  A  must contain  the   
+             matrix A.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in  the  calling  (sub)  program.   When  TRANS = 'N' or 'n'   
+             then  LDA must be at least  max( 1, n ), otherwise  LDA must   
+             be at least  max( 1, k ).   
+             Unchanged on exit.   
+
+    B      - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is   
+             k  when  TRANS = 'N' or 'n',  and is  n  otherwise.   
+             Before entry with  TRANS = 'N' or 'n',  the  leading  n by k   
+             part of the array  B  must contain the matrix  B,  otherwise   
+             the leading  k by n  part of the array  B  must contain  the   
+             matrix B.   
+             Unchanged on exit.   
+
+    LDB    - INTEGER.   
+             On entry, LDB specifies the first dimension of B as declared   
+             in  the  calling  (sub)  program.   When  TRANS = 'N' or 'n'   
+             then  LDB must be at least  max( 1, n ), otherwise  LDB must   
+             be at least  max( 1, k ).   
+             Unchanged on exit.   
+
+    BETA   - DOUBLE PRECISION.   
+             On entry, BETA specifies the scalar beta.   
+             Unchanged on exit.   
+
+    C      - DOUBLE PRECISION array of DIMENSION ( LDC, n ).   
+             Before entry  with  UPLO = 'U' or 'u',  the leading  n by n   
+             upper triangular part of the array C must contain the upper   
+             triangular part  of the  symmetric matrix  and the strictly   
+             lower triangular part of C is not referenced.  On exit, the   
+             upper triangular part of the array  C is overwritten by the   
+             upper triangular part of the updated matrix.   
+             Before entry  with  UPLO = 'L' or 'l',  the leading  n by n   
+             lower triangular part of the array C must contain the lower   
+             triangular part  of the  symmetric matrix  and the strictly   
+             upper triangular part of C is not referenced.  On exit, the   
+             lower triangular part of the array  C is overwritten by the   
+             lower triangular part of the updated matrix.   
+
+    LDC    - INTEGER.   
+             On entry, LDC specifies the first dimension of C as declared   
+             in  the  calling  (sub)  program.   LDC  must  be  at  least   
+             max( 1, n ).   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 3 Blas routine.   
+
+
+    -- Written on 8-February-1989.   
+       Jack Dongarra, Argonne National Laboratory.   
+       Iain Duff, AERE Harwell.   
+       Jeremy Du Croz, Numerical Algorithms Group Ltd.   
+       Sven Hammarling, Numerical Algorithms Group Ltd.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+
+    /* Function Body */
+    if (igraphlsame_(trans, "N")) {
+	nrowa = *n;
+    } else {
+	nrowa = *k;
+    }
+    upper = igraphlsame_(uplo, "U");
+
+    info = 0;
+    if (! upper && ! igraphlsame_(uplo, "L")) {
+	info = 1;
+    } else if (! igraphlsame_(trans, "N") && ! igraphlsame_(trans, 
+	    "T") && ! igraphlsame_(trans, "C")) {
+	info = 2;
+    } else if (*n < 0) {
+	info = 3;
+    } else if (*k < 0) {
+	info = 4;
+    } else if (*lda < max(1,nrowa)) {
+	info = 7;
+    } else if (*ldb < max(1,nrowa)) {
+	info = 9;
+    } else if (*ldc < max(1,*n)) {
+	info = 12;
+    }
+    if (info != 0) {
+	igraphxerbla_("DSYR2K", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) {
+	return 0;
+    }
+
+/*     And when  alpha.eq.zero. */
+
+    if (*alpha == 0.) {
+	if (upper) {
+	    if (*beta == 0.) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = 0.;
+/* L10: */
+		    }
+/* L20: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L30: */
+		    }
+/* L40: */
+		}
+	    }
+	} else {
+	    if (*beta == 0.) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = *n;
+		    for (i__ = j; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = 0.;
+/* L50: */
+		    }
+/* L60: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = *n;
+		    for (i__ = j; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L70: */
+		    }
+/* L80: */
+		}
+	    }
+	}
+	return 0;
+    }
+
+/*     Start the operations. */
+
+    if (igraphlsame_(trans, "N")) {
+
+/*        Form  C := alpha*A*B**T + alpha*B*A**T + C. */
+
+	if (upper) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (*beta == 0.) {
+		    i__2 = j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = 0.;
+/* L90: */
+		    }
+		} else if (*beta != 1.) {
+		    i__2 = j;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L100: */
+		    }
+		}
+		i__2 = *k;
+		for (l = 1; l <= i__2; ++l) {
+		    if (a[j + l * a_dim1] != 0. || b[j + l * b_dim1] != 0.) {
+			temp1 = *alpha * b[j + l * b_dim1];
+			temp2 = *alpha * a[j + l * a_dim1];
+			i__3 = j;
+			for (i__ = 1; i__ <= i__3; ++i__) {
+			    c__[i__ + j * c_dim1] = c__[i__ + j * c_dim1] + a[
+				    i__ + l * a_dim1] * temp1 + b[i__ + l * 
+				    b_dim1] * temp2;
+/* L110: */
+			}
+		    }
+/* L120: */
+		}
+/* L130: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (*beta == 0.) {
+		    i__2 = *n;
+		    for (i__ = j; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = 0.;
+/* L140: */
+		    }
+		} else if (*beta != 1.) {
+		    i__2 = *n;
+		    for (i__ = j; i__ <= i__2; ++i__) {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1];
+/* L150: */
+		    }
+		}
+		i__2 = *k;
+		for (l = 1; l <= i__2; ++l) {
+		    if (a[j + l * a_dim1] != 0. || b[j + l * b_dim1] != 0.) {
+			temp1 = *alpha * b[j + l * b_dim1];
+			temp2 = *alpha * a[j + l * a_dim1];
+			i__3 = *n;
+			for (i__ = j; i__ <= i__3; ++i__) {
+			    c__[i__ + j * c_dim1] = c__[i__ + j * c_dim1] + a[
+				    i__ + l * a_dim1] * temp1 + b[i__ + l * 
+				    b_dim1] * temp2;
+/* L160: */
+			}
+		    }
+/* L170: */
+		}
+/* L180: */
+	    }
+	}
+    } else {
+
+/*        Form  C := alpha*A**T*B + alpha*B**T*A + C. */
+
+	if (upper) {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = j;
+		for (i__ = 1; i__ <= i__2; ++i__) {
+		    temp1 = 0.;
+		    temp2 = 0.;
+		    i__3 = *k;
+		    for (l = 1; l <= i__3; ++l) {
+			temp1 += a[l + i__ * a_dim1] * b[l + j * b_dim1];
+			temp2 += b[l + i__ * b_dim1] * a[l + j * a_dim1];
+/* L190: */
+		    }
+		    if (*beta == 0.) {
+			c__[i__ + j * c_dim1] = *alpha * temp1 + *alpha * 
+				temp2;
+		    } else {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] 
+				+ *alpha * temp1 + *alpha * temp2;
+		    }
+/* L200: */
+		}
+/* L210: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		i__2 = *n;
+		for (i__ = j; i__ <= i__2; ++i__) {
+		    temp1 = 0.;
+		    temp2 = 0.;
+		    i__3 = *k;
+		    for (l = 1; l <= i__3; ++l) {
+			temp1 += a[l + i__ * a_dim1] * b[l + j * b_dim1];
+			temp2 += b[l + i__ * b_dim1] * a[l + j * a_dim1];
+/* L220: */
+		    }
+		    if (*beta == 0.) {
+			c__[i__ + j * c_dim1] = *alpha * temp1 + *alpha * 
+				temp2;
+		    } else {
+			c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] 
+				+ *alpha * temp1 + *alpha * temp2;
+		    }
+/* L230: */
+		}
+/* L240: */
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DSYR2K. */
+
+} /* igraphdsyr2k_ */
+
diff --git a/src/lapack/dsytd2.c b/src/lapack/dsytd2.c
new file mode 100644
index 0000000..ce6a395
--- /dev/null
+++ b/src/lapack/dsytd2.c
@@ -0,0 +1,292 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static doublereal c_b8 = 0.;
+static doublereal c_b14 = -1.;
+
+/* Subroutine */ int igraphdsytd2_(char *uplo, integer *n, doublereal *a, integer *
+	lda, doublereal *d__, doublereal *e, doublereal *tau, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    doublereal taui;
+    extern /* Subroutine */ int igraphdsyr2_(char *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    doublereal alpha;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdaxpy_(integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    logical upper;
+    extern /* Subroutine */ int igraphdsymv_(char *, integer *, doublereal *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, integer *), igraphdlarfg_(integer *, doublereal *,
+	     doublereal *, integer *, doublereal *), igraphxerbla_(char *, integer *
+	    , ftnlen);
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DSYTD2 reduces a real symmetric matrix A to symmetric tridiagonal   
+    form T by an orthogonal similarity transformation: Q**T * A * Q = T.   
+
+    Arguments   
+    =========   
+
+    UPLO    (input) CHARACTER*1   
+            Specifies whether the upper or lower triangular part of the   
+            symmetric matrix A is stored:   
+            = 'U':  Upper triangular   
+            = 'L':  Lower triangular   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the symmetric matrix A.  If UPLO = 'U', the leading   
+            n-by-n upper triangular part of A contains the upper   
+            triangular part of the matrix A, and the strictly lower   
+            triangular part of A is not referenced.  If UPLO = 'L', the   
+            leading n-by-n lower triangular part of A contains the lower   
+            triangular part of the matrix A, and the strictly upper   
+            triangular part of A is not referenced.   
+            On exit, if UPLO = 'U', the diagonal and first superdiagonal   
+            of A are overwritten by the corresponding elements of the   
+            tridiagonal matrix T, and the elements above the first   
+            superdiagonal, with the array TAU, represent the orthogonal   
+            matrix Q as a product of elementary reflectors; if UPLO   
+            = 'L', the diagonal and first subdiagonal of A are over-   
+            written by the corresponding elements of the tridiagonal   
+            matrix T, and the elements below the first subdiagonal, with   
+            the array TAU, represent the orthogonal matrix Q as a product   
+            of elementary reflectors. See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    D       (output) DOUBLE PRECISION array, dimension (N)   
+            The diagonal elements of the tridiagonal matrix T:   
+            D(i) = A(i,i).   
+
+    E       (output) DOUBLE PRECISION array, dimension (N-1)   
+            The off-diagonal elements of the tridiagonal matrix T:   
+            E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'.   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (N-1)   
+            The scalar factors of the elementary reflectors (see Further   
+            Details).   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value.   
+
+    Further Details   
+    ===============   
+
+    If UPLO = 'U', the matrix Q is represented as a product of elementary   
+    reflectors   
+
+       Q = H(n-1) . . . H(2) H(1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in   
+    A(1:i-1,i+1), and tau in TAU(i).   
+
+    If UPLO = 'L', the matrix Q is represented as a product of elementary   
+    reflectors   
+
+       Q = H(1) H(2) . . . H(n-1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i),   
+    and tau in TAU(i).   
+
+    The contents of A on exit are illustrated by the following examples   
+    with n = 5:   
+
+    if UPLO = 'U':                       if UPLO = 'L':   
+
+      (  d   e   v2  v3  v4 )              (  d                  )   
+      (      d   e   v3  v4 )              (  e   d              )   
+      (          d   e   v4 )              (  v1  e   d          )   
+      (              d   e  )              (  v1  v2  e   d      )   
+      (                  d  )              (  v1  v2  v3  e   d  )   
+
+    where d and e denote diagonal and off-diagonal elements of T, and vi   
+    denotes an element of the vector defining H(i).   
+
+    =====================================================================   
+
+
+       Test the input parameters   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --d__;
+    --e;
+    --tau;
+
+    /* Function Body */
+    *info = 0;
+    upper = igraphlsame_(uplo, "U");
+    if (! upper && ! igraphlsame_(uplo, "L")) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*n)) {
+	*info = -4;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DSYTD2", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n <= 0) {
+	return 0;
+    }
+
+    if (upper) {
+
+/*        Reduce the upper triangle of A */
+
+	for (i__ = *n - 1; i__ >= 1; --i__) {
+
+/*           Generate elementary reflector H(i) = I - tau * v * v**T   
+             to annihilate A(1:i-1,i+1) */
+
+	    igraphdlarfg_(&i__, &a[i__ + (i__ + 1) * a_dim1], &a[(i__ + 1) * a_dim1 
+		    + 1], &c__1, &taui);
+	    e[i__] = a[i__ + (i__ + 1) * a_dim1];
+
+	    if (taui != 0.) {
+
+/*              Apply H(i) from both sides to A(1:i,1:i) */
+
+		a[i__ + (i__ + 1) * a_dim1] = 1.;
+
+/*              Compute  x := tau * A * v  storing x in TAU(1:i) */
+
+		igraphdsymv_(uplo, &i__, &taui, &a[a_offset], lda, &a[(i__ + 1) * 
+			a_dim1 + 1], &c__1, &c_b8, &tau[1], &c__1);
+
+/*              Compute  w := x - 1/2 * tau * (x**T * v) * v */
+
+		alpha = taui * -.5 * igraphddot_(&i__, &tau[1], &c__1, &a[(i__ + 1) 
+			* a_dim1 + 1], &c__1);
+		igraphdaxpy_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &tau[
+			1], &c__1);
+
+/*              Apply the transformation as a rank-2 update:   
+                   A := A - v * w**T - w * v**T */
+
+		igraphdsyr2_(uplo, &i__, &c_b14, &a[(i__ + 1) * a_dim1 + 1], &c__1, 
+			&tau[1], &c__1, &a[a_offset], lda);
+
+		a[i__ + (i__ + 1) * a_dim1] = e[i__];
+	    }
+	    d__[i__ + 1] = a[i__ + 1 + (i__ + 1) * a_dim1];
+	    tau[i__] = taui;
+/* L10: */
+	}
+	d__[1] = a[a_dim1 + 1];
+    } else {
+
+/*        Reduce the lower triangle of A */
+
+	i__1 = *n - 1;
+	for (i__ = 1; i__ <= i__1; ++i__) {
+
+/*           Generate elementary reflector H(i) = I - tau * v * v**T   
+             to annihilate A(i+2:n,i) */
+
+	    i__2 = *n - i__;
+/* Computing MIN */
+	    i__3 = i__ + 2;
+	    igraphdlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + i__ *
+		     a_dim1], &c__1, &taui);
+	    e[i__] = a[i__ + 1 + i__ * a_dim1];
+
+	    if (taui != 0.) {
+
+/*              Apply H(i) from both sides to A(i+1:n,i+1:n) */
+
+		a[i__ + 1 + i__ * a_dim1] = 1.;
+
+/*              Compute  x := tau * A * v  storing y in TAU(i:n-1) */
+
+		i__2 = *n - i__;
+		igraphdsymv_(uplo, &i__2, &taui, &a[i__ + 1 + (i__ + 1) * a_dim1], 
+			lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b8, &tau[
+			i__], &c__1);
+
+/*              Compute  w := x - 1/2 * tau * (x**T * v) * v */
+
+		i__2 = *n - i__;
+		alpha = taui * -.5 * igraphddot_(&i__2, &tau[i__], &c__1, &a[i__ + 
+			1 + i__ * a_dim1], &c__1);
+		i__2 = *n - i__;
+		igraphdaxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[
+			i__], &c__1);
+
+/*              Apply the transformation as a rank-2 update:   
+                   A := A - v * w**T - w * v**T */
+
+		i__2 = *n - i__;
+		igraphdsyr2_(uplo, &i__2, &c_b14, &a[i__ + 1 + i__ * a_dim1], &c__1,
+			 &tau[i__], &c__1, &a[i__ + 1 + (i__ + 1) * a_dim1], 
+			lda);
+
+		a[i__ + 1 + i__ * a_dim1] = e[i__];
+	    }
+	    d__[i__] = a[i__ + i__ * a_dim1];
+	    tau[i__] = taui;
+/* L20: */
+	}
+	d__[*n] = a[*n + *n * a_dim1];
+    }
+
+    return 0;
+
+/*     End of DSYTD2 */
+
+} /* igraphdsytd2_ */
+
diff --git a/src/lapack/dsytrd.c b/src/lapack/dsytrd.c
new file mode 100644
index 0000000..9eecefd
--- /dev/null
+++ b/src/lapack/dsytrd.c
@@ -0,0 +1,348 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c_n1 = -1;
+static integer c__3 = 3;
+static integer c__2 = 2;
+static doublereal c_b22 = -1.;
+static doublereal c_b23 = 1.;
+
+/* Subroutine */ int igraphdsytrd_(char *uplo, integer *n, doublereal *a, integer *
+	lda, doublereal *d__, doublereal *e, doublereal *tau, doublereal *
+	work, integer *lwork, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, j, nb, kk, nx, iws;
+    extern logical igraphlsame_(char *, char *);
+    integer nbmin, iinfo;
+    logical upper;
+    extern /* Subroutine */ int igraphdsytd2_(char *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, doublereal *, integer *), igraphdsyr2k_(char *, char *, integer *, integer *, doublereal 
+	    *, doublereal *, integer *, doublereal *, integer *, doublereal *,
+	     doublereal *, integer *), igraphdlatrd_(char *, 
+	    integer *, integer *, doublereal *, integer *, doublereal *, 
+	    doublereal *, doublereal *, integer *), igraphxerbla_(char *, 
+	    integer *, ftnlen);
+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *, ftnlen, ftnlen);
+    integer ldwork, lwkopt;
+    logical lquery;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DSYTRD reduces a real symmetric matrix A to real symmetric   
+    tridiagonal form T by an orthogonal similarity transformation:   
+    Q**T * A * Q = T.   
+
+    Arguments   
+    =========   
+
+    UPLO    (input) CHARACTER*1   
+            = 'U':  Upper triangle of A is stored;   
+            = 'L':  Lower triangle of A is stored.   
+
+    N       (input) INTEGER   
+            The order of the matrix A.  N >= 0.   
+
+    A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
+            On entry, the symmetric matrix A.  If UPLO = 'U', the leading   
+            N-by-N upper triangular part of A contains the upper   
+            triangular part of the matrix A, and the strictly lower   
+            triangular part of A is not referenced.  If UPLO = 'L', the   
+            leading N-by-N lower triangular part of A contains the lower   
+            triangular part of the matrix A, and the strictly upper   
+            triangular part of A is not referenced.   
+            On exit, if UPLO = 'U', the diagonal and first superdiagonal   
+            of A are overwritten by the corresponding elements of the   
+            tridiagonal matrix T, and the elements above the first   
+            superdiagonal, with the array TAU, represent the orthogonal   
+            matrix Q as a product of elementary reflectors; if UPLO   
+            = 'L', the diagonal and first subdiagonal of A are over-   
+            written by the corresponding elements of the tridiagonal   
+            matrix T, and the elements below the first subdiagonal, with   
+            the array TAU, represent the orthogonal matrix Q as a product   
+            of elementary reflectors. See Further Details.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A.  LDA >= max(1,N).   
+
+    D       (output) DOUBLE PRECISION array, dimension (N)   
+            The diagonal elements of the tridiagonal matrix T:   
+            D(i) = A(i,i).   
+
+    E       (output) DOUBLE PRECISION array, dimension (N-1)   
+            The off-diagonal elements of the tridiagonal matrix T:   
+            E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'.   
+
+    TAU     (output) DOUBLE PRECISION array, dimension (N-1)   
+            The scalar factors of the elementary reflectors (see Further   
+            Details).   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.  LWORK >= 1.   
+            For optimum performance LWORK >= N*NB, where NB is the   
+            optimal blocksize.   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    Further Details   
+    ===============   
+
+    If UPLO = 'U', the matrix Q is represented as a product of elementary   
+    reflectors   
+
+       Q = H(n-1) . . . H(2) H(1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in   
+    A(1:i-1,i+1), and tau in TAU(i).   
+
+    If UPLO = 'L', the matrix Q is represented as a product of elementary   
+    reflectors   
+
+       Q = H(1) H(2) . . . H(n-1).   
+
+    Each H(i) has the form   
+
+       H(i) = I - tau * v * v**T   
+
+    where tau is a real scalar, and v is a real vector with   
+    v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i),   
+    and tau in TAU(i).   
+
+    The contents of A on exit are illustrated by the following examples   
+    with n = 5:   
+
+    if UPLO = 'U':                       if UPLO = 'L':   
+
+      (  d   e   v2  v3  v4 )              (  d                  )   
+      (      d   e   v3  v4 )              (  e   d              )   
+      (          d   e   v4 )              (  v1  e   d          )   
+      (              d   e  )              (  v1  v2  e   d      )   
+      (                  d  )              (  v1  v2  v3  e   d  )   
+
+    where d and e denote diagonal and off-diagonal elements of T, and vi   
+    denotes an element of the vector defining H(i).   
+
+    =====================================================================   
+
+
+       Test the input parameters   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --d__;
+    --e;
+    --tau;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    upper = igraphlsame_(uplo, "U");
+    lquery = *lwork == -1;
+    if (! upper && ! igraphlsame_(uplo, "L")) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*lda < max(1,*n)) {
+	*info = -4;
+    } else if (*lwork < 1 && ! lquery) {
+	*info = -9;
+    }
+
+    if (*info == 0) {
+
+/*        Determine the block size. */
+
+	nb = igraphilaenv_(&c__1, "DSYTRD", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6,
+		 (ftnlen)1);
+	lwkopt = *n * nb;
+	work[1] = (doublereal) lwkopt;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DSYTRD", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	work[1] = 1.;
+	return 0;
+    }
+
+    nx = *n;
+    iws = 1;
+    if (nb > 1 && nb < *n) {
+
+/*        Determine when to cross over from blocked to unblocked code   
+          (last block is always handled by unblocked code).   
+
+   Computing MAX */
+	i__1 = nb, i__2 = igraphilaenv_(&c__3, "DSYTRD", uplo, n, &c_n1, &c_n1, &
+		c_n1, (ftnlen)6, (ftnlen)1);
+	nx = max(i__1,i__2);
+	if (nx < *n) {
+
+/*           Determine if workspace is large enough for blocked code. */
+
+	    ldwork = *n;
+	    iws = ldwork * nb;
+	    if (*lwork < iws) {
+
+/*              Not enough workspace to use optimal NB:  determine the   
+                minimum value of NB, and reduce NB or force use of   
+                unblocked code by setting NX = N.   
+
+   Computing MAX */
+		i__1 = *lwork / ldwork;
+		nb = max(i__1,1);
+		nbmin = igraphilaenv_(&c__2, "DSYTRD", uplo, n, &c_n1, &c_n1, &c_n1,
+			 (ftnlen)6, (ftnlen)1);
+		if (nb < nbmin) {
+		    nx = *n;
+		}
+	    }
+	} else {
+	    nx = *n;
+	}
+    } else {
+	nb = 1;
+    }
+
+    if (upper) {
+
+/*        Reduce the upper triangle of A.   
+          Columns 1:kk are handled by the unblocked method. */
+
+	kk = *n - (*n - nx + nb - 1) / nb * nb;
+	i__1 = kk + 1;
+	i__2 = -nb;
+	for (i__ = *n - nb + 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += 
+		i__2) {
+
+/*           Reduce columns i:i+nb-1 to tridiagonal form and form the   
+             matrix W which is needed to update the unreduced part of   
+             the matrix */
+
+	    i__3 = i__ + nb - 1;
+	    igraphdlatrd_(uplo, &i__3, &nb, &a[a_offset], lda, &e[1], &tau[1], &
+		    work[1], &ldwork);
+
+/*           Update the unreduced submatrix A(1:i-1,1:i-1), using an   
+             update of the form:  A := A - V*W**T - W*V**T */
+
+	    i__3 = i__ - 1;
+	    igraphdsyr2k_(uplo, "No transpose", &i__3, &nb, &c_b22, &a[i__ * a_dim1 
+		    + 1], lda, &work[1], &ldwork, &c_b23, &a[a_offset], lda);
+
+/*           Copy superdiagonal elements back into A, and diagonal   
+             elements into D */
+
+	    i__3 = i__ + nb - 1;
+	    for (j = i__; j <= i__3; ++j) {
+		a[j - 1 + j * a_dim1] = e[j - 1];
+		d__[j] = a[j + j * a_dim1];
+/* L10: */
+	    }
+/* L20: */
+	}
+
+/*        Use unblocked code to reduce the last or only block */
+
+	igraphdsytd2_(uplo, &kk, &a[a_offset], lda, &d__[1], &e[1], &tau[1], &iinfo);
+    } else {
+
+/*        Reduce the lower triangle of A */
+
+	i__2 = *n - nx;
+	i__1 = nb;
+	for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) {
+
+/*           Reduce columns i:i+nb-1 to tridiagonal form and form the   
+             matrix W which is needed to update the unreduced part of   
+             the matrix */
+
+	    i__3 = *n - i__ + 1;
+	    igraphdlatrd_(uplo, &i__3, &nb, &a[i__ + i__ * a_dim1], lda, &e[i__], &
+		    tau[i__], &work[1], &ldwork);
+
+/*           Update the unreduced submatrix A(i+ib:n,i+ib:n), using   
+             an update of the form:  A := A - V*W**T - W*V**T */
+
+	    i__3 = *n - i__ - nb + 1;
+	    igraphdsyr2k_(uplo, "No transpose", &i__3, &nb, &c_b22, &a[i__ + nb + 
+		    i__ * a_dim1], lda, &work[nb + 1], &ldwork, &c_b23, &a[
+		    i__ + nb + (i__ + nb) * a_dim1], lda);
+
+/*           Copy subdiagonal elements back into A, and diagonal   
+             elements into D */
+
+	    i__3 = i__ + nb - 1;
+	    for (j = i__; j <= i__3; ++j) {
+		a[j + 1 + j * a_dim1] = e[j];
+		d__[j] = a[j + j * a_dim1];
+/* L30: */
+	    }
+/* L40: */
+	}
+
+/*        Use unblocked code to reduce the last or only block */
+
+	i__1 = *n - i__ + 1;
+	igraphdsytd2_(uplo, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], 
+		&tau[i__], &iinfo);
+    }
+
+    work[1] = (doublereal) lwkopt;
+    return 0;
+
+/*     End of DSYTRD */
+
+} /* igraphdsytrd_ */
+
diff --git a/src/lapack/dtrevc.c b/src/lapack/dtrevc.c
new file mode 100644
index 0000000..630b6e7
--- /dev/null
+++ b/src/lapack/dtrevc.c
@@ -0,0 +1,1212 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static logical c_false = FALSE_;
+static integer c__1 = 1;
+static doublereal c_b22 = 1.;
+static doublereal c_b25 = 0.;
+static integer c__2 = 2;
+static logical c_true = TRUE_;
+
+/* Subroutine */ int igraphdtrevc_(char *side, char *howmny, logical *select, 
+	integer *n, doublereal *t, integer *ldt, doublereal *vl, integer *
+	ldvl, doublereal *vr, integer *ldvr, integer *mm, integer *m, 
+	doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer t_dim1, t_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, 
+	    i__2, i__3;
+    doublereal d__1, d__2, d__3, d__4;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, k;
+    doublereal x[4]	/* was [2][2] */;
+    integer j1, j2, n2, ii, ki, ip, is;
+    doublereal wi, wr, rec, ulp, beta, emax;
+    logical pair;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    logical allv;
+    integer ierr;
+    doublereal unfl, ovfl, smin;
+    logical over;
+    doublereal vmax;
+    integer jnxt;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    doublereal scale;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphdgemv_(char *, integer *, integer *, 
+	    doublereal *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, doublereal *, integer *);
+    doublereal remax;
+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
+	    doublereal *, integer *);
+    logical leftv, bothv;
+    extern /* Subroutine */ int igraphdaxpy_(integer *, doublereal *, doublereal *, 
+	    integer *, doublereal *, integer *);
+    doublereal vcrit;
+    logical somev;
+    doublereal xnorm;
+    extern /* Subroutine */ int igraphdlaln2_(logical *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, doublereal *,
+	     doublereal *, doublereal *, integer *, doublereal *, doublereal *
+	    , doublereal *, integer *, doublereal *, doublereal *, integer *),
+	     igraphdlabad_(doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern integer igraphidamax_(integer *, doublereal *, integer *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    doublereal bignum;
+    logical rightv;
+    doublereal smlnum;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DTREVC computes some or all of the right and/or left eigenvectors of   
+    a real upper quasi-triangular matrix T.   
+    Matrices of this type are produced by the Schur factorization of   
+    a real general matrix:  A = Q*T*Q**T, as computed by DHSEQR.   
+
+    The right eigenvector x and the left eigenvector y of T corresponding   
+    to an eigenvalue w are defined by:   
+
+       T*x = w*x,     (y**T)*T = w*(y**T)   
+
+    where y**T denotes the transpose of y.   
+    The eigenvalues are not input to this routine, but are read directly   
+    from the diagonal blocks of T.   
+
+    This routine returns the matrices X and/or Y of right and left   
+    eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an   
+    input matrix.  If Q is the orthogonal factor that reduces a matrix   
+    A to Schur form T, then Q*X and Q*Y are the matrices of right and   
+    left eigenvectors of A.   
+
+    Arguments   
+    =========   
+
+    SIDE    (input) CHARACTER*1   
+            = 'R':  compute right eigenvectors only;   
+            = 'L':  compute left eigenvectors only;   
+            = 'B':  compute both right and left eigenvectors.   
+
+    HOWMNY  (input) CHARACTER*1   
+            = 'A':  compute all right and/or left eigenvectors;   
+            = 'B':  compute all right and/or left eigenvectors,   
+                    backtransformed by the matrices in VR and/or VL;   
+            = 'S':  compute selected right and/or left eigenvectors,   
+                    as indicated by the logical array SELECT.   
+
+    SELECT  (input/output) LOGICAL array, dimension (N)   
+            If HOWMNY = 'S', SELECT specifies the eigenvectors to be   
+            computed.   
+            If w(j) is a real eigenvalue, the corresponding real   
+            eigenvector is computed if SELECT(j) is .TRUE..   
+            If w(j) and w(j+1) are the real and imaginary parts of a   
+            complex eigenvalue, the corresponding complex eigenvector is   
+            computed if either SELECT(j) or SELECT(j+1) is .TRUE., and   
+            on exit SELECT(j) is set to .TRUE. and SELECT(j+1) is set to   
+            .FALSE..   
+            Not referenced if HOWMNY = 'A' or 'B'.   
+
+    N       (input) INTEGER   
+            The order of the matrix T. N >= 0.   
+
+    T       (input) DOUBLE PRECISION array, dimension (LDT,N)   
+            The upper quasi-triangular matrix T in Schur canonical form.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= max(1,N).   
+
+    VL      (input/output) DOUBLE PRECISION array, dimension (LDVL,MM)   
+            On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must   
+            contain an N-by-N matrix Q (usually the orthogonal matrix Q   
+            of Schur vectors returned by DHSEQR).   
+            On exit, if SIDE = 'L' or 'B', VL contains:   
+            if HOWMNY = 'A', the matrix Y of left eigenvectors of T;   
+            if HOWMNY = 'B', the matrix Q*Y;   
+            if HOWMNY = 'S', the left eigenvectors of T specified by   
+                             SELECT, stored consecutively in the columns   
+                             of VL, in the same order as their   
+                             eigenvalues.   
+            A complex eigenvector corresponding to a complex eigenvalue   
+            is stored in two consecutive columns, the first holding the   
+            real part, and the second the imaginary part.   
+            Not referenced if SIDE = 'R'.   
+
+    LDVL    (input) INTEGER   
+            The leading dimension of the array VL.  LDVL >= 1, and if   
+            SIDE = 'L' or 'B', LDVL >= N.   
+
+    VR      (input/output) DOUBLE PRECISION array, dimension (LDVR,MM)   
+            On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must   
+            contain an N-by-N matrix Q (usually the orthogonal matrix Q   
+            of Schur vectors returned by DHSEQR).   
+            On exit, if SIDE = 'R' or 'B', VR contains:   
+            if HOWMNY = 'A', the matrix X of right eigenvectors of T;   
+            if HOWMNY = 'B', the matrix Q*X;   
+            if HOWMNY = 'S', the right eigenvectors of T specified by   
+                             SELECT, stored consecutively in the columns   
+                             of VR, in the same order as their   
+                             eigenvalues.   
+            A complex eigenvector corresponding to a complex eigenvalue   
+            is stored in two consecutive columns, the first holding the   
+            real part and the second the imaginary part.   
+            Not referenced if SIDE = 'L'.   
+
+    LDVR    (input) INTEGER   
+            The leading dimension of the array VR.  LDVR >= 1, and if   
+            SIDE = 'R' or 'B', LDVR >= N.   
+
+    MM      (input) INTEGER   
+            The number of columns in the arrays VL and/or VR. MM >= M.   
+
+    M       (output) INTEGER   
+            The number of columns in the arrays VL and/or VR actually   
+            used to store the eigenvectors.   
+            If HOWMNY = 'A' or 'B', M is set to N.   
+            Each selected real eigenvector occupies one column and each   
+            selected complex eigenvector occupies two columns.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (3*N)   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+
+    Further Details   
+    ===============   
+
+    The algorithm used in this program is basically backward (forward)   
+    substitution, with scaling to make the the code robust against   
+    possible overflow.   
+
+    Each eigenvector is normalized so that the element of largest   
+    magnitude has magnitude 1; here the magnitude of a complex number   
+    (x,y) is taken to be |x| + |y|.   
+
+    =====================================================================   
+
+
+       Decode and test the input parameters   
+
+       Parameter adjustments */
+    --select;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    vl_dim1 = *ldvl;
+    vl_offset = 1 + vl_dim1;
+    vl -= vl_offset;
+    vr_dim1 = *ldvr;
+    vr_offset = 1 + vr_dim1;
+    vr -= vr_offset;
+    --work;
+
+    /* Function Body */
+    bothv = igraphlsame_(side, "B");
+    rightv = igraphlsame_(side, "R") || bothv;
+    leftv = igraphlsame_(side, "L") || bothv;
+
+    allv = igraphlsame_(howmny, "A");
+    over = igraphlsame_(howmny, "B");
+    somev = igraphlsame_(howmny, "S");
+
+    *info = 0;
+    if (! rightv && ! leftv) {
+	*info = -1;
+    } else if (! allv && ! over && ! somev) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*ldt < max(1,*n)) {
+	*info = -6;
+    } else if (*ldvl < 1 || leftv && *ldvl < *n) {
+	*info = -8;
+    } else if (*ldvr < 1 || rightv && *ldvr < *n) {
+	*info = -10;
+    } else {
+
+/*        Set M to the number of columns required to store the selected   
+          eigenvectors, standardize the array SELECT if necessary, and   
+          test MM. */
+
+	if (somev) {
+	    *m = 0;
+	    pair = FALSE_;
+	    i__1 = *n;
+	    for (j = 1; j <= i__1; ++j) {
+		if (pair) {
+		    pair = FALSE_;
+		    select[j] = FALSE_;
+		} else {
+		    if (j < *n) {
+			if (t[j + 1 + j * t_dim1] == 0.) {
+			    if (select[j]) {
+				++(*m);
+			    }
+			} else {
+			    pair = TRUE_;
+			    if (select[j] || select[j + 1]) {
+				select[j] = TRUE_;
+				*m += 2;
+			    }
+			}
+		    } else {
+			if (select[*n]) {
+			    ++(*m);
+			}
+		    }
+		}
+/* L10: */
+	    }
+	} else {
+	    *m = *n;
+	}
+
+	if (*mm < *m) {
+	    *info = -11;
+	}
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DTREVC", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+/*     Set the constants to control overflow. */
+
+    unfl = igraphdlamch_("Safe minimum");
+    ovfl = 1. / unfl;
+    igraphdlabad_(&unfl, &ovfl);
+    ulp = igraphdlamch_("Precision");
+    smlnum = unfl * (*n / ulp);
+    bignum = (1. - ulp) / smlnum;
+
+/*     Compute 1-norm of each column of strictly upper triangular   
+       part of T to control overflow in triangular solver. */
+
+    work[1] = 0.;
+    i__1 = *n;
+    for (j = 2; j <= i__1; ++j) {
+	work[j] = 0.;
+	i__2 = j - 1;
+	for (i__ = 1; i__ <= i__2; ++i__) {
+	    work[j] += (d__1 = t[i__ + j * t_dim1], abs(d__1));
+/* L20: */
+	}
+/* L30: */
+    }
+
+/*     Index IP is used to specify the real or complex eigenvalue:   
+         IP = 0, real eigenvalue,   
+              1, first of conjugate complex pair: (wr,wi)   
+             -1, second of conjugate complex pair: (wr,wi) */
+
+    n2 = *n << 1;
+
+    if (rightv) {
+
+/*        Compute right eigenvectors. */
+
+	ip = 0;
+	is = *m;
+	for (ki = *n; ki >= 1; --ki) {
+
+	    if (ip == 1) {
+		goto L130;
+	    }
+	    if (ki == 1) {
+		goto L40;
+	    }
+	    if (t[ki + (ki - 1) * t_dim1] == 0.) {
+		goto L40;
+	    }
+	    ip = -1;
+
+L40:
+	    if (somev) {
+		if (ip == 0) {
+		    if (! select[ki]) {
+			goto L130;
+		    }
+		} else {
+		    if (! select[ki - 1]) {
+			goto L130;
+		    }
+		}
+	    }
+
+/*           Compute the KI-th eigenvalue (WR,WI). */
+
+	    wr = t[ki + ki * t_dim1];
+	    wi = 0.;
+	    if (ip != 0) {
+		wi = sqrt((d__1 = t[ki + (ki - 1) * t_dim1], abs(d__1))) * 
+			sqrt((d__2 = t[ki - 1 + ki * t_dim1], abs(d__2)));
+	    }
+/* Computing MAX */
+	    d__1 = ulp * (abs(wr) + abs(wi));
+	    smin = max(d__1,smlnum);
+
+	    if (ip == 0) {
+
+/*              Real right eigenvector */
+
+		work[ki + *n] = 1.;
+
+/*              Form right-hand side */
+
+		i__1 = ki - 1;
+		for (k = 1; k <= i__1; ++k) {
+		    work[k + *n] = -t[k + ki * t_dim1];
+/* L50: */
+		}
+
+/*              Solve the upper quasi-triangular system:   
+                   (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. */
+
+		jnxt = ki - 1;
+		for (j = ki - 1; j >= 1; --j) {
+		    if (j > jnxt) {
+			goto L60;
+		    }
+		    j1 = j;
+		    j2 = j;
+		    jnxt = j - 1;
+		    if (j > 1) {
+			if (t[j + (j - 1) * t_dim1] != 0.) {
+			    j1 = j - 1;
+			    jnxt = j - 2;
+			}
+		    }
+
+		    if (j1 == j2) {
+
+/*                    1-by-1 diagonal block */
+
+			igraphdlaln2_(&c_false, &c__1, &c__1, &smin, &c_b22, &t[j + 
+				j * t_dim1], ldt, &c_b22, &c_b22, &work[j + *
+				n], n, &wr, &c_b25, x, &c__2, &scale, &xnorm, 
+				&ierr);
+
+/*                    Scale X(1,1) to avoid overflow when updating   
+                      the right-hand side. */
+
+			if (xnorm > 1.) {
+			    if (work[j] > bignum / xnorm) {
+				x[0] /= xnorm;
+				scale /= xnorm;
+			    }
+			}
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    igraphdscal_(&ki, &scale, &work[*n + 1], &c__1);
+			}
+			work[j + *n] = x[0];
+
+/*                    Update right-hand side */
+
+			i__1 = j - 1;
+			d__1 = -x[0];
+			igraphdaxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[
+				*n + 1], &c__1);
+
+		    } else {
+
+/*                    2-by-2 diagonal block */
+
+			igraphdlaln2_(&c_false, &c__2, &c__1, &smin, &c_b22, &t[j - 
+				1 + (j - 1) * t_dim1], ldt, &c_b22, &c_b22, &
+				work[j - 1 + *n], n, &wr, &c_b25, x, &c__2, &
+				scale, &xnorm, &ierr);
+
+/*                    Scale X(1,1) and X(2,1) to avoid overflow when   
+                      updating the right-hand side. */
+
+			if (xnorm > 1.) {
+/* Computing MAX */
+			    d__1 = work[j - 1], d__2 = work[j];
+			    beta = max(d__1,d__2);
+			    if (beta > bignum / xnorm) {
+				x[0] /= xnorm;
+				x[1] /= xnorm;
+				scale /= xnorm;
+			    }
+			}
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    igraphdscal_(&ki, &scale, &work[*n + 1], &c__1);
+			}
+			work[j - 1 + *n] = x[0];
+			work[j + *n] = x[1];
+
+/*                    Update right-hand side */
+
+			i__1 = j - 2;
+			d__1 = -x[0];
+			igraphdaxpy_(&i__1, &d__1, &t[(j - 1) * t_dim1 + 1], &c__1, 
+				&work[*n + 1], &c__1);
+			i__1 = j - 2;
+			d__1 = -x[1];
+			igraphdaxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[
+				*n + 1], &c__1);
+		    }
+L60:
+		    ;
+		}
+
+/*              Copy the vector x or Q*x to VR and normalize. */
+
+		if (! over) {
+		    igraphdcopy_(&ki, &work[*n + 1], &c__1, &vr[is * vr_dim1 + 1], &
+			    c__1);
+
+		    ii = igraphidamax_(&ki, &vr[is * vr_dim1 + 1], &c__1);
+		    remax = 1. / (d__1 = vr[ii + is * vr_dim1], abs(d__1));
+		    igraphdscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1);
+
+		    i__1 = *n;
+		    for (k = ki + 1; k <= i__1; ++k) {
+			vr[k + is * vr_dim1] = 0.;
+/* L70: */
+		    }
+		} else {
+		    if (ki > 1) {
+			i__1 = ki - 1;
+			igraphdgemv_("N", n, &i__1, &c_b22, &vr[vr_offset], ldvr, &
+				work[*n + 1], &c__1, &work[ki + *n], &vr[ki * 
+				vr_dim1 + 1], &c__1);
+		    }
+
+		    ii = igraphidamax_(n, &vr[ki * vr_dim1 + 1], &c__1);
+		    remax = 1. / (d__1 = vr[ii + ki * vr_dim1], abs(d__1));
+		    igraphdscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1);
+		}
+
+	    } else {
+
+/*              Complex right eigenvector.   
+
+                Initial solve   
+                  [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0.   
+                  [ (T(KI,KI-1)   T(KI,KI)   )               ] */
+
+		if ((d__1 = t[ki - 1 + ki * t_dim1], abs(d__1)) >= (d__2 = t[
+			ki + (ki - 1) * t_dim1], abs(d__2))) {
+		    work[ki - 1 + *n] = 1.;
+		    work[ki + n2] = wi / t[ki - 1 + ki * t_dim1];
+		} else {
+		    work[ki - 1 + *n] = -wi / t[ki + (ki - 1) * t_dim1];
+		    work[ki + n2] = 1.;
+		}
+		work[ki + *n] = 0.;
+		work[ki - 1 + n2] = 0.;
+
+/*              Form right-hand side */
+
+		i__1 = ki - 2;
+		for (k = 1; k <= i__1; ++k) {
+		    work[k + *n] = -work[ki - 1 + *n] * t[k + (ki - 1) * 
+			    t_dim1];
+		    work[k + n2] = -work[ki + n2] * t[k + ki * t_dim1];
+/* L80: */
+		}
+
+/*              Solve upper quasi-triangular system:   
+                (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) */
+
+		jnxt = ki - 2;
+		for (j = ki - 2; j >= 1; --j) {
+		    if (j > jnxt) {
+			goto L90;
+		    }
+		    j1 = j;
+		    j2 = j;
+		    jnxt = j - 1;
+		    if (j > 1) {
+			if (t[j + (j - 1) * t_dim1] != 0.) {
+			    j1 = j - 1;
+			    jnxt = j - 2;
+			}
+		    }
+
+		    if (j1 == j2) {
+
+/*                    1-by-1 diagonal block */
+
+			igraphdlaln2_(&c_false, &c__1, &c__2, &smin, &c_b22, &t[j + 
+				j * t_dim1], ldt, &c_b22, &c_b22, &work[j + *
+				n], n, &wr, &wi, x, &c__2, &scale, &xnorm, &
+				ierr);
+
+/*                    Scale X(1,1) and X(1,2) to avoid overflow when   
+                      updating the right-hand side. */
+
+			if (xnorm > 1.) {
+			    if (work[j] > bignum / xnorm) {
+				x[0] /= xnorm;
+				x[2] /= xnorm;
+				scale /= xnorm;
+			    }
+			}
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    igraphdscal_(&ki, &scale, &work[*n + 1], &c__1);
+			    igraphdscal_(&ki, &scale, &work[n2 + 1], &c__1);
+			}
+			work[j + *n] = x[0];
+			work[j + n2] = x[2];
+
+/*                    Update the right-hand side */
+
+			i__1 = j - 1;
+			d__1 = -x[0];
+			igraphdaxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[
+				*n + 1], &c__1);
+			i__1 = j - 1;
+			d__1 = -x[2];
+			igraphdaxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[
+				n2 + 1], &c__1);
+
+		    } else {
+
+/*                    2-by-2 diagonal block */
+
+			igraphdlaln2_(&c_false, &c__2, &c__2, &smin, &c_b22, &t[j - 
+				1 + (j - 1) * t_dim1], ldt, &c_b22, &c_b22, &
+				work[j - 1 + *n], n, &wr, &wi, x, &c__2, &
+				scale, &xnorm, &ierr);
+
+/*                    Scale X to avoid overflow when updating   
+                      the right-hand side. */
+
+			if (xnorm > 1.) {
+/* Computing MAX */
+			    d__1 = work[j - 1], d__2 = work[j];
+			    beta = max(d__1,d__2);
+			    if (beta > bignum / xnorm) {
+				rec = 1. / xnorm;
+				x[0] *= rec;
+				x[2] *= rec;
+				x[1] *= rec;
+				x[3] *= rec;
+				scale *= rec;
+			    }
+			}
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    igraphdscal_(&ki, &scale, &work[*n + 1], &c__1);
+			    igraphdscal_(&ki, &scale, &work[n2 + 1], &c__1);
+			}
+			work[j - 1 + *n] = x[0];
+			work[j + *n] = x[1];
+			work[j - 1 + n2] = x[2];
+			work[j + n2] = x[3];
+
+/*                    Update the right-hand side */
+
+			i__1 = j - 2;
+			d__1 = -x[0];
+			igraphdaxpy_(&i__1, &d__1, &t[(j - 1) * t_dim1 + 1], &c__1, 
+				&work[*n + 1], &c__1);
+			i__1 = j - 2;
+			d__1 = -x[1];
+			igraphdaxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[
+				*n + 1], &c__1);
+			i__1 = j - 2;
+			d__1 = -x[2];
+			igraphdaxpy_(&i__1, &d__1, &t[(j - 1) * t_dim1 + 1], &c__1, 
+				&work[n2 + 1], &c__1);
+			i__1 = j - 2;
+			d__1 = -x[3];
+			igraphdaxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[
+				n2 + 1], &c__1);
+		    }
+L90:
+		    ;
+		}
+
+/*              Copy the vector x or Q*x to VR and normalize. */
+
+		if (! over) {
+		    igraphdcopy_(&ki, &work[*n + 1], &c__1, &vr[(is - 1) * vr_dim1 
+			    + 1], &c__1);
+		    igraphdcopy_(&ki, &work[n2 + 1], &c__1, &vr[is * vr_dim1 + 1], &
+			    c__1);
+
+		    emax = 0.;
+		    i__1 = ki;
+		    for (k = 1; k <= i__1; ++k) {
+/* Computing MAX */
+			d__3 = emax, d__4 = (d__1 = vr[k + (is - 1) * vr_dim1]
+				, abs(d__1)) + (d__2 = vr[k + is * vr_dim1], 
+				abs(d__2));
+			emax = max(d__3,d__4);
+/* L100: */
+		    }
+
+		    remax = 1. / emax;
+		    igraphdscal_(&ki, &remax, &vr[(is - 1) * vr_dim1 + 1], &c__1);
+		    igraphdscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1);
+
+		    i__1 = *n;
+		    for (k = ki + 1; k <= i__1; ++k) {
+			vr[k + (is - 1) * vr_dim1] = 0.;
+			vr[k + is * vr_dim1] = 0.;
+/* L110: */
+		    }
+
+		} else {
+
+		    if (ki > 2) {
+			i__1 = ki - 2;
+			igraphdgemv_("N", n, &i__1, &c_b22, &vr[vr_offset], ldvr, &
+				work[*n + 1], &c__1, &work[ki - 1 + *n], &vr[(
+				ki - 1) * vr_dim1 + 1], &c__1);
+			i__1 = ki - 2;
+			igraphdgemv_("N", n, &i__1, &c_b22, &vr[vr_offset], ldvr, &
+				work[n2 + 1], &c__1, &work[ki + n2], &vr[ki * 
+				vr_dim1 + 1], &c__1);
+		    } else {
+			igraphdscal_(n, &work[ki - 1 + *n], &vr[(ki - 1) * vr_dim1 
+				+ 1], &c__1);
+			igraphdscal_(n, &work[ki + n2], &vr[ki * vr_dim1 + 1], &
+				c__1);
+		    }
+
+		    emax = 0.;
+		    i__1 = *n;
+		    for (k = 1; k <= i__1; ++k) {
+/* Computing MAX */
+			d__3 = emax, d__4 = (d__1 = vr[k + (ki - 1) * vr_dim1]
+				, abs(d__1)) + (d__2 = vr[k + ki * vr_dim1], 
+				abs(d__2));
+			emax = max(d__3,d__4);
+/* L120: */
+		    }
+		    remax = 1. / emax;
+		    igraphdscal_(n, &remax, &vr[(ki - 1) * vr_dim1 + 1], &c__1);
+		    igraphdscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1);
+		}
+	    }
+
+	    --is;
+	    if (ip != 0) {
+		--is;
+	    }
+L130:
+	    if (ip == 1) {
+		ip = 0;
+	    }
+	    if (ip == -1) {
+		ip = 1;
+	    }
+/* L140: */
+	}
+    }
+
+    if (leftv) {
+
+/*        Compute left eigenvectors. */
+
+	ip = 0;
+	is = 1;
+	i__1 = *n;
+	for (ki = 1; ki <= i__1; ++ki) {
+
+	    if (ip == -1) {
+		goto L250;
+	    }
+	    if (ki == *n) {
+		goto L150;
+	    }
+	    if (t[ki + 1 + ki * t_dim1] == 0.) {
+		goto L150;
+	    }
+	    ip = 1;
+
+L150:
+	    if (somev) {
+		if (! select[ki]) {
+		    goto L250;
+		}
+	    }
+
+/*           Compute the KI-th eigenvalue (WR,WI). */
+
+	    wr = t[ki + ki * t_dim1];
+	    wi = 0.;
+	    if (ip != 0) {
+		wi = sqrt((d__1 = t[ki + (ki + 1) * t_dim1], abs(d__1))) * 
+			sqrt((d__2 = t[ki + 1 + ki * t_dim1], abs(d__2)));
+	    }
+/* Computing MAX */
+	    d__1 = ulp * (abs(wr) + abs(wi));
+	    smin = max(d__1,smlnum);
+
+	    if (ip == 0) {
+
+/*              Real left eigenvector. */
+
+		work[ki + *n] = 1.;
+
+/*              Form right-hand side */
+
+		i__2 = *n;
+		for (k = ki + 1; k <= i__2; ++k) {
+		    work[k + *n] = -t[ki + k * t_dim1];
+/* L160: */
+		}
+
+/*              Solve the quasi-triangular system:   
+                   (T(KI+1:N,KI+1:N) - WR)**T*X = SCALE*WORK */
+
+		vmax = 1.;
+		vcrit = bignum;
+
+		jnxt = ki + 1;
+		i__2 = *n;
+		for (j = ki + 1; j <= i__2; ++j) {
+		    if (j < jnxt) {
+			goto L170;
+		    }
+		    j1 = j;
+		    j2 = j;
+		    jnxt = j + 1;
+		    if (j < *n) {
+			if (t[j + 1 + j * t_dim1] != 0.) {
+			    j2 = j + 1;
+			    jnxt = j + 2;
+			}
+		    }
+
+		    if (j1 == j2) {
+
+/*                    1-by-1 diagonal block   
+
+                      Scale if necessary to avoid overflow when forming   
+                      the right-hand side. */
+
+			if (work[j] > vcrit) {
+			    rec = 1. / vmax;
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &rec, &work[ki + *n], &c__1);
+			    vmax = 1.;
+			    vcrit = bignum;
+			}
+
+			i__3 = j - ki - 1;
+			work[j + *n] -= igraphddot_(&i__3, &t[ki + 1 + j * t_dim1], 
+				&c__1, &work[ki + 1 + *n], &c__1);
+
+/*                    Solve (T(J,J)-WR)**T*X = WORK */
+
+			igraphdlaln2_(&c_false, &c__1, &c__1, &smin, &c_b22, &t[j + 
+				j * t_dim1], ldt, &c_b22, &c_b22, &work[j + *
+				n], n, &wr, &c_b25, x, &c__2, &scale, &xnorm, 
+				&ierr);
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &scale, &work[ki + *n], &c__1);
+			}
+			work[j + *n] = x[0];
+/* Computing MAX */
+			d__2 = (d__1 = work[j + *n], abs(d__1));
+			vmax = max(d__2,vmax);
+			vcrit = bignum / vmax;
+
+		    } else {
+
+/*                    2-by-2 diagonal block   
+
+                      Scale if necessary to avoid overflow when forming   
+                      the right-hand side.   
+
+   Computing MAX */
+			d__1 = work[j], d__2 = work[j + 1];
+			beta = max(d__1,d__2);
+			if (beta > vcrit) {
+			    rec = 1. / vmax;
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &rec, &work[ki + *n], &c__1);
+			    vmax = 1.;
+			    vcrit = bignum;
+			}
+
+			i__3 = j - ki - 1;
+			work[j + *n] -= igraphddot_(&i__3, &t[ki + 1 + j * t_dim1], 
+				&c__1, &work[ki + 1 + *n], &c__1);
+
+			i__3 = j - ki - 1;
+			work[j + 1 + *n] -= igraphddot_(&i__3, &t[ki + 1 + (j + 1) *
+				 t_dim1], &c__1, &work[ki + 1 + *n], &c__1);
+
+/*                    Solve   
+                        [T(J,J)-WR   T(J,J+1)     ]**T * X = SCALE*( WORK1 )   
+                        [T(J+1,J)    T(J+1,J+1)-WR]                ( WORK2 ) */
+
+			igraphdlaln2_(&c_true, &c__2, &c__1, &smin, &c_b22, &t[j + 
+				j * t_dim1], ldt, &c_b22, &c_b22, &work[j + *
+				n], n, &wr, &c_b25, x, &c__2, &scale, &xnorm, 
+				&ierr);
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &scale, &work[ki + *n], &c__1);
+			}
+			work[j + *n] = x[0];
+			work[j + 1 + *n] = x[1];
+
+/* Computing MAX */
+			d__3 = (d__1 = work[j + *n], abs(d__1)), d__4 = (d__2 
+				= work[j + 1 + *n], abs(d__2)), d__3 = max(
+				d__3,d__4);
+			vmax = max(d__3,vmax);
+			vcrit = bignum / vmax;
+
+		    }
+L170:
+		    ;
+		}
+
+/*              Copy the vector x or Q*x to VL and normalize. */
+
+		if (! over) {
+		    i__2 = *n - ki + 1;
+		    igraphdcopy_(&i__2, &work[ki + *n], &c__1, &vl[ki + is * 
+			    vl_dim1], &c__1);
+
+		    i__2 = *n - ki + 1;
+		    ii = igraphidamax_(&i__2, &vl[ki + is * vl_dim1], &c__1) + ki - 
+			    1;
+		    remax = 1. / (d__1 = vl[ii + is * vl_dim1], abs(d__1));
+		    i__2 = *n - ki + 1;
+		    igraphdscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1);
+
+		    i__2 = ki - 1;
+		    for (k = 1; k <= i__2; ++k) {
+			vl[k + is * vl_dim1] = 0.;
+/* L180: */
+		    }
+
+		} else {
+
+		    if (ki < *n) {
+			i__2 = *n - ki;
+			igraphdgemv_("N", n, &i__2, &c_b22, &vl[(ki + 1) * vl_dim1 
+				+ 1], ldvl, &work[ki + 1 + *n], &c__1, &work[
+				ki + *n], &vl[ki * vl_dim1 + 1], &c__1);
+		    }
+
+		    ii = igraphidamax_(n, &vl[ki * vl_dim1 + 1], &c__1);
+		    remax = 1. / (d__1 = vl[ii + ki * vl_dim1], abs(d__1));
+		    igraphdscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1);
+
+		}
+
+	    } else {
+
+/*              Complex left eigenvector.   
+
+                 Initial solve:   
+                   ((T(KI,KI)    T(KI,KI+1) )**T - (WR - I* WI))*X = 0.   
+                   ((T(KI+1,KI) T(KI+1,KI+1))                ) */
+
+		if ((d__1 = t[ki + (ki + 1) * t_dim1], abs(d__1)) >= (d__2 = 
+			t[ki + 1 + ki * t_dim1], abs(d__2))) {
+		    work[ki + *n] = wi / t[ki + (ki + 1) * t_dim1];
+		    work[ki + 1 + n2] = 1.;
+		} else {
+		    work[ki + *n] = 1.;
+		    work[ki + 1 + n2] = -wi / t[ki + 1 + ki * t_dim1];
+		}
+		work[ki + 1 + *n] = 0.;
+		work[ki + n2] = 0.;
+
+/*              Form right-hand side */
+
+		i__2 = *n;
+		for (k = ki + 2; k <= i__2; ++k) {
+		    work[k + *n] = -work[ki + *n] * t[ki + k * t_dim1];
+		    work[k + n2] = -work[ki + 1 + n2] * t[ki + 1 + k * t_dim1]
+			    ;
+/* L190: */
+		}
+
+/*              Solve complex quasi-triangular system:   
+                ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 */
+
+		vmax = 1.;
+		vcrit = bignum;
+
+		jnxt = ki + 2;
+		i__2 = *n;
+		for (j = ki + 2; j <= i__2; ++j) {
+		    if (j < jnxt) {
+			goto L200;
+		    }
+		    j1 = j;
+		    j2 = j;
+		    jnxt = j + 1;
+		    if (j < *n) {
+			if (t[j + 1 + j * t_dim1] != 0.) {
+			    j2 = j + 1;
+			    jnxt = j + 2;
+			}
+		    }
+
+		    if (j1 == j2) {
+
+/*                    1-by-1 diagonal block   
+
+                      Scale if necessary to avoid overflow when   
+                      forming the right-hand side elements. */
+
+			if (work[j] > vcrit) {
+			    rec = 1. / vmax;
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &rec, &work[ki + *n], &c__1);
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &rec, &work[ki + n2], &c__1);
+			    vmax = 1.;
+			    vcrit = bignum;
+			}
+
+			i__3 = j - ki - 2;
+			work[j + *n] -= igraphddot_(&i__3, &t[ki + 2 + j * t_dim1], 
+				&c__1, &work[ki + 2 + *n], &c__1);
+			i__3 = j - ki - 2;
+			work[j + n2] -= igraphddot_(&i__3, &t[ki + 2 + j * t_dim1], 
+				&c__1, &work[ki + 2 + n2], &c__1);
+
+/*                    Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2 */
+
+			d__1 = -wi;
+			igraphdlaln2_(&c_false, &c__1, &c__2, &smin, &c_b22, &t[j + 
+				j * t_dim1], ldt, &c_b22, &c_b22, &work[j + *
+				n], n, &wr, &d__1, x, &c__2, &scale, &xnorm, &
+				ierr);
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &scale, &work[ki + *n], &c__1);
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &scale, &work[ki + n2], &c__1);
+			}
+			work[j + *n] = x[0];
+			work[j + n2] = x[2];
+/* Computing MAX */
+			d__3 = (d__1 = work[j + *n], abs(d__1)), d__4 = (d__2 
+				= work[j + n2], abs(d__2)), d__3 = max(d__3,
+				d__4);
+			vmax = max(d__3,vmax);
+			vcrit = bignum / vmax;
+
+		    } else {
+
+/*                    2-by-2 diagonal block   
+
+                      Scale if necessary to avoid overflow when forming   
+                      the right-hand side elements.   
+
+   Computing MAX */
+			d__1 = work[j], d__2 = work[j + 1];
+			beta = max(d__1,d__2);
+			if (beta > vcrit) {
+			    rec = 1. / vmax;
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &rec, &work[ki + *n], &c__1);
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &rec, &work[ki + n2], &c__1);
+			    vmax = 1.;
+			    vcrit = bignum;
+			}
+
+			i__3 = j - ki - 2;
+			work[j + *n] -= igraphddot_(&i__3, &t[ki + 2 + j * t_dim1], 
+				&c__1, &work[ki + 2 + *n], &c__1);
+
+			i__3 = j - ki - 2;
+			work[j + n2] -= igraphddot_(&i__3, &t[ki + 2 + j * t_dim1], 
+				&c__1, &work[ki + 2 + n2], &c__1);
+
+			i__3 = j - ki - 2;
+			work[j + 1 + *n] -= igraphddot_(&i__3, &t[ki + 2 + (j + 1) *
+				 t_dim1], &c__1, &work[ki + 2 + *n], &c__1);
+
+			i__3 = j - ki - 2;
+			work[j + 1 + n2] -= igraphddot_(&i__3, &t[ki + 2 + (j + 1) *
+				 t_dim1], &c__1, &work[ki + 2 + n2], &c__1);
+
+/*                    Solve 2-by-2 complex linear equation   
+                        ([T(j,j)   T(j,j+1)  ]**T-(wr-i*wi)*I)*X = SCALE*B   
+                        ([T(j+1,j) T(j+1,j+1)]               ) */
+
+			d__1 = -wi;
+			igraphdlaln2_(&c_true, &c__2, &c__2, &smin, &c_b22, &t[j + 
+				j * t_dim1], ldt, &c_b22, &c_b22, &work[j + *
+				n], n, &wr, &d__1, x, &c__2, &scale, &xnorm, &
+				ierr);
+
+/*                    Scale if necessary */
+
+			if (scale != 1.) {
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &scale, &work[ki + *n], &c__1);
+			    i__3 = *n - ki + 1;
+			    igraphdscal_(&i__3, &scale, &work[ki + n2], &c__1);
+			}
+			work[j + *n] = x[0];
+			work[j + n2] = x[2];
+			work[j + 1 + *n] = x[1];
+			work[j + 1 + n2] = x[3];
+/* Computing MAX */
+			d__1 = abs(x[0]), d__2 = abs(x[2]), d__1 = max(d__1,
+				d__2), d__2 = abs(x[1]), d__1 = max(d__1,d__2)
+				, d__2 = abs(x[3]), d__1 = max(d__1,d__2);
+			vmax = max(d__1,vmax);
+			vcrit = bignum / vmax;
+
+		    }
+L200:
+		    ;
+		}
+
+/*              Copy the vector x or Q*x to VL and normalize. */
+
+		if (! over) {
+		    i__2 = *n - ki + 1;
+		    igraphdcopy_(&i__2, &work[ki + *n], &c__1, &vl[ki + is * 
+			    vl_dim1], &c__1);
+		    i__2 = *n - ki + 1;
+		    igraphdcopy_(&i__2, &work[ki + n2], &c__1, &vl[ki + (is + 1) * 
+			    vl_dim1], &c__1);
+
+		    emax = 0.;
+		    i__2 = *n;
+		    for (k = ki; k <= i__2; ++k) {
+/* Computing MAX */
+			d__3 = emax, d__4 = (d__1 = vl[k + is * vl_dim1], abs(
+				d__1)) + (d__2 = vl[k + (is + 1) * vl_dim1], 
+				abs(d__2));
+			emax = max(d__3,d__4);
+/* L220: */
+		    }
+		    remax = 1. / emax;
+		    i__2 = *n - ki + 1;
+		    igraphdscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1);
+		    i__2 = *n - ki + 1;
+		    igraphdscal_(&i__2, &remax, &vl[ki + (is + 1) * vl_dim1], &c__1)
+			    ;
+
+		    i__2 = ki - 1;
+		    for (k = 1; k <= i__2; ++k) {
+			vl[k + is * vl_dim1] = 0.;
+			vl[k + (is + 1) * vl_dim1] = 0.;
+/* L230: */
+		    }
+		} else {
+		    if (ki < *n - 1) {
+			i__2 = *n - ki - 1;
+			igraphdgemv_("N", n, &i__2, &c_b22, &vl[(ki + 2) * vl_dim1 
+				+ 1], ldvl, &work[ki + 2 + *n], &c__1, &work[
+				ki + *n], &vl[ki * vl_dim1 + 1], &c__1);
+			i__2 = *n - ki - 1;
+			igraphdgemv_("N", n, &i__2, &c_b22, &vl[(ki + 2) * vl_dim1 
+				+ 1], ldvl, &work[ki + 2 + n2], &c__1, &work[
+				ki + 1 + n2], &vl[(ki + 1) * vl_dim1 + 1], &
+				c__1);
+		    } else {
+			igraphdscal_(n, &work[ki + *n], &vl[ki * vl_dim1 + 1], &
+				c__1);
+			igraphdscal_(n, &work[ki + 1 + n2], &vl[(ki + 1) * vl_dim1 
+				+ 1], &c__1);
+		    }
+
+		    emax = 0.;
+		    i__2 = *n;
+		    for (k = 1; k <= i__2; ++k) {
+/* Computing MAX */
+			d__3 = emax, d__4 = (d__1 = vl[k + ki * vl_dim1], abs(
+				d__1)) + (d__2 = vl[k + (ki + 1) * vl_dim1], 
+				abs(d__2));
+			emax = max(d__3,d__4);
+/* L240: */
+		    }
+		    remax = 1. / emax;
+		    igraphdscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1);
+		    igraphdscal_(n, &remax, &vl[(ki + 1) * vl_dim1 + 1], &c__1);
+
+		}
+
+	    }
+
+	    ++is;
+	    if (ip != 0) {
+		++is;
+	    }
+L250:
+	    if (ip == -1) {
+		ip = 0;
+	    }
+	    if (ip == 1) {
+		ip = -1;
+	    }
+
+/* L260: */
+	}
+
+    }
+
+    return 0;
+
+/*     End of DTREVC */
+
+} /* igraphdtrevc_ */
+
diff --git a/src/lapack/dtrexc.c b/src/lapack/dtrexc.c
new file mode 100644
index 0000000..96bb5ba
--- /dev/null
+++ b/src/lapack/dtrexc.c
@@ -0,0 +1,389 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__2 = 2;
+
+/* Subroutine */ int igraphdtrexc_(char *compq, integer *n, doublereal *t, integer *
+	ldt, doublereal *q, integer *ldq, integer *ifst, integer *ilst, 
+	doublereal *work, integer *info)
+{
+    /* System generated locals */
+    integer q_dim1, q_offset, t_dim1, t_offset, i__1;
+
+    /* Local variables */
+    integer nbf, nbl, here;
+    extern logical igraphlsame_(char *, char *);
+    logical wantq;
+    extern /* Subroutine */ int igraphdlaexc_(logical *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *, integer *, integer 
+	    *, doublereal *, integer *), igraphxerbla_(char *, integer *, ftnlen);
+    integer nbnext;
+
+
+/*  -- LAPACK routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    DTREXC reorders the real Schur factorization of a real matrix   
+    A = Q*T*Q**T, so that the diagonal block of T with row index IFST is   
+    moved to row ILST.   
+
+    The real Schur form T is reordered by an orthogonal similarity   
+    transformation Z**T*T*Z, and optionally the matrix Q of Schur vectors   
+    is updated by postmultiplying it with Z.   
+
+    T must be in Schur canonical form (as returned by DHSEQR), that is,   
+    block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each   
+    2-by-2 diagonal block has its diagonal elements equal and its   
+    off-diagonal elements of opposite sign.   
+
+    Arguments   
+    =========   
+
+    COMPQ   (input) CHARACTER*1   
+            = 'V':  update the matrix Q of Schur vectors;   
+            = 'N':  do not update Q.   
+
+    N       (input) INTEGER   
+            The order of the matrix T. N >= 0.   
+
+    T       (input/output) DOUBLE PRECISION array, dimension (LDT,N)   
+            On entry, the upper quasi-triangular matrix T, in Schur   
+            Schur canonical form.   
+            On exit, the reordered upper quasi-triangular matrix, again   
+            in Schur canonical form.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= max(1,N).   
+
+    Q       (input/output) DOUBLE PRECISION array, dimension (LDQ,N)   
+            On entry, if COMPQ = 'V', the matrix Q of Schur vectors.   
+            On exit, if COMPQ = 'V', Q has been postmultiplied by the   
+            orthogonal transformation matrix Z which reorders T.   
+            If COMPQ = 'N', Q is not referenced.   
+
+    LDQ     (input) INTEGER   
+            The leading dimension of the array Q.  LDQ >= max(1,N).   
+
+    IFST    (input/output) INTEGER   
+    ILST    (input/output) INTEGER   
+            Specify the reordering of the diagonal blocks of T.   
+            The block with row index IFST is moved to row ILST, by a   
+            sequence of transpositions between adjacent blocks.   
+            On exit, if IFST pointed on entry to the second row of a   
+            2-by-2 block, it is changed to point to the first row; ILST   
+            always points to the first row of the block in its final   
+            position (which may differ from its input value by +1 or -1).   
+            1 <= IFST <= N; 1 <= ILST <= N.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (N)   
+
+    INFO    (output) INTEGER   
+            = 0:  successful exit   
+            < 0:  if INFO = -i, the i-th argument had an illegal value   
+            = 1:  two adjacent blocks were too close to swap (the problem   
+                  is very ill-conditioned); T may have been partially   
+                  reordered, and ILST points to the first row of the   
+                  current position of the block being moved.   
+
+    =====================================================================   
+
+
+       Decode and test the input arguments.   
+
+       Parameter adjustments */
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+    --work;
+
+    /* Function Body */
+    *info = 0;
+    wantq = igraphlsame_(compq, "V");
+    if (! wantq && ! igraphlsame_(compq, "N")) {
+	*info = -1;
+    } else if (*n < 0) {
+	*info = -2;
+    } else if (*ldt < max(1,*n)) {
+	*info = -4;
+    } else if (*ldq < 1 || wantq && *ldq < max(1,*n)) {
+	*info = -6;
+    } else if (*ifst < 1 || *ifst > *n) {
+	*info = -7;
+    } else if (*ilst < 1 || *ilst > *n) {
+	*info = -8;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DTREXC", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n <= 1) {
+	return 0;
+    }
+
+/*     Determine the first row of specified block   
+       and find out it is 1 by 1 or 2 by 2. */
+
+    if (*ifst > 1) {
+	if (t[*ifst + (*ifst - 1) * t_dim1] != 0.) {
+	    --(*ifst);
+	}
+    }
+    nbf = 1;
+    if (*ifst < *n) {
+	if (t[*ifst + 1 + *ifst * t_dim1] != 0.) {
+	    nbf = 2;
+	}
+    }
+
+/*     Determine the first row of the final block   
+       and find out it is 1 by 1 or 2 by 2. */
+
+    if (*ilst > 1) {
+	if (t[*ilst + (*ilst - 1) * t_dim1] != 0.) {
+	    --(*ilst);
+	}
+    }
+    nbl = 1;
+    if (*ilst < *n) {
+	if (t[*ilst + 1 + *ilst * t_dim1] != 0.) {
+	    nbl = 2;
+	}
+    }
+
+    if (*ifst == *ilst) {
+	return 0;
+    }
+
+    if (*ifst < *ilst) {
+
+/*        Update ILST */
+
+	if (nbf == 2 && nbl == 1) {
+	    --(*ilst);
+	}
+	if (nbf == 1 && nbl == 2) {
+	    ++(*ilst);
+	}
+
+	here = *ifst;
+
+L10:
+
+/*        Swap block with next one below */
+
+	if (nbf == 1 || nbf == 2) {
+
+/*           Current block either 1 by 1 or 2 by 2 */
+
+	    nbnext = 1;
+	    if (here + nbf + 1 <= *n) {
+		if (t[here + nbf + 1 + (here + nbf) * t_dim1] != 0.) {
+		    nbnext = 2;
+		}
+	    }
+	    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &here, &
+		    nbf, &nbnext, &work[1], info);
+	    if (*info != 0) {
+		*ilst = here;
+		return 0;
+	    }
+	    here += nbnext;
+
+/*           Test if 2 by 2 block breaks into two 1 by 1 blocks */
+
+	    if (nbf == 2) {
+		if (t[here + 1 + here * t_dim1] == 0.) {
+		    nbf = 3;
+		}
+	    }
+
+	} else {
+
+/*           Current block consists of two 1 by 1 blocks each of which   
+             must be swapped individually */
+
+	    nbnext = 1;
+	    if (here + 3 <= *n) {
+		if (t[here + 3 + (here + 2) * t_dim1] != 0.) {
+		    nbnext = 2;
+		}
+	    }
+	    i__1 = here + 1;
+	    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, &
+		    c__1, &nbnext, &work[1], info);
+	    if (*info != 0) {
+		*ilst = here;
+		return 0;
+	    }
+	    if (nbnext == 1) {
+
+/*              Swap two 1 by 1 blocks, no problems possible */
+
+		igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			here, &c__1, &nbnext, &work[1], info);
+		++here;
+	    } else {
+
+/*              Recompute NBNEXT in case 2 by 2 split */
+
+		if (t[here + 2 + (here + 1) * t_dim1] == 0.) {
+		    nbnext = 1;
+		}
+		if (nbnext == 2) {
+
+/*                 2 by 2 Block did not split */
+
+		    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    here, &c__1, &nbnext, &work[1], info);
+		    if (*info != 0) {
+			*ilst = here;
+			return 0;
+		    }
+		    here += 2;
+		} else {
+
+/*                 2 by 2 Block did split */
+
+		    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    here, &c__1, &c__1, &work[1], info);
+		    i__1 = here + 1;
+		    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    i__1, &c__1, &c__1, &work[1], info);
+		    here += 2;
+		}
+	    }
+	}
+	if (here < *ilst) {
+	    goto L10;
+	}
+
+    } else {
+
+	here = *ifst;
+L20:
+
+/*        Swap block with next one above */
+
+	if (nbf == 1 || nbf == 2) {
+
+/*           Current block either 1 by 1 or 2 by 2 */
+
+	    nbnext = 1;
+	    if (here >= 3) {
+		if (t[here - 1 + (here - 2) * t_dim1] != 0.) {
+		    nbnext = 2;
+		}
+	    }
+	    i__1 = here - nbnext;
+	    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, &
+		    nbnext, &nbf, &work[1], info);
+	    if (*info != 0) {
+		*ilst = here;
+		return 0;
+	    }
+	    here -= nbnext;
+
+/*           Test if 2 by 2 block breaks into two 1 by 1 blocks */
+
+	    if (nbf == 2) {
+		if (t[here + 1 + here * t_dim1] == 0.) {
+		    nbf = 3;
+		}
+	    }
+
+	} else {
+
+/*           Current block consists of two 1 by 1 blocks each of which   
+             must be swapped individually */
+
+	    nbnext = 1;
+	    if (here >= 3) {
+		if (t[here - 1 + (here - 2) * t_dim1] != 0.) {
+		    nbnext = 2;
+		}
+	    }
+	    i__1 = here - nbnext;
+	    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, &
+		    nbnext, &c__1, &work[1], info);
+	    if (*info != 0) {
+		*ilst = here;
+		return 0;
+	    }
+	    if (nbnext == 1) {
+
+/*              Swap two 1 by 1 blocks, no problems possible */
+
+		igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			here, &nbnext, &c__1, &work[1], info);
+		--here;
+	    } else {
+
+/*              Recompute NBNEXT in case 2 by 2 split */
+
+		if (t[here + (here - 1) * t_dim1] == 0.) {
+		    nbnext = 1;
+		}
+		if (nbnext == 2) {
+
+/*                 2 by 2 Block did not split */
+
+		    i__1 = here - 1;
+		    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    i__1, &c__2, &c__1, &work[1], info);
+		    if (*info != 0) {
+			*ilst = here;
+			return 0;
+		    }
+		    here += -2;
+		} else {
+
+/*                 2 by 2 Block did split */
+
+		    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    here, &c__1, &c__1, &work[1], info);
+		    i__1 = here - 1;
+		    igraphdlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    i__1, &c__1, &c__1, &work[1], info);
+		    here += -2;
+		}
+	    }
+	}
+	if (here > *ilst) {
+	    goto L20;
+	}
+    }
+    *ilst = here;
+
+    return 0;
+
+/*     End of DTREXC */
+
+} /* igraphdtrexc_ */
+
diff --git a/src/lapack/dtrmm.c b/src/lapack/dtrmm.c
new file mode 100644
index 0000000..3b69e9a
--- /dev/null
+++ b/src/lapack/dtrmm.c
@@ -0,0 +1,442 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdtrmm_(char *side, char *uplo, char *transa, char *diag, 
+	integer *m, integer *n, doublereal *alpha, doublereal *a, integer *
+	lda, doublereal *b, integer *ldb)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, j, k, info;
+    doublereal temp;
+    logical lside;
+    extern logical igraphlsame_(char *, char *);
+    integer nrowa;
+    logical upper;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical nounit;
+
+
+/*  Purpose   
+    =======   
+
+    DTRMM  performs one of the matrix-matrix operations   
+
+       B := alpha*op( A )*B,   or   B := alpha*B*op( A ),   
+
+    where  alpha  is a scalar,  B  is an m by n matrix,  A  is a unit, or   
+    non-unit,  upper or lower triangular matrix  and  op( A )  is one  of   
+
+       op( A ) = A   or   op( A ) = A**T.   
+
+    Arguments   
+    ==========   
+
+    SIDE   - CHARACTER*1.   
+             On entry,  SIDE specifies whether  op( A ) multiplies B from   
+             the left or right as follows:   
+
+                SIDE = 'L' or 'l'   B := alpha*op( A )*B.   
+
+                SIDE = 'R' or 'r'   B := alpha*B*op( A ).   
+
+             Unchanged on exit.   
+
+    UPLO   - CHARACTER*1.   
+             On entry, UPLO specifies whether the matrix A is an upper or   
+             lower triangular matrix as follows:   
+
+                UPLO = 'U' or 'u'   A is an upper triangular matrix.   
+
+                UPLO = 'L' or 'l'   A is a lower triangular matrix.   
+
+             Unchanged on exit.   
+
+    TRANSA - CHARACTER*1.   
+             On entry, TRANSA specifies the form of op( A ) to be used in   
+             the matrix multiplication as follows:   
+
+                TRANSA = 'N' or 'n'   op( A ) = A.   
+
+                TRANSA = 'T' or 't'   op( A ) = A**T.   
+
+                TRANSA = 'C' or 'c'   op( A ) = A**T.   
+
+             Unchanged on exit.   
+
+    DIAG   - CHARACTER*1.   
+             On entry, DIAG specifies whether or not A is unit triangular   
+             as follows:   
+
+                DIAG = 'U' or 'u'   A is assumed to be unit triangular.   
+
+                DIAG = 'N' or 'n'   A is not assumed to be unit   
+                                    triangular.   
+
+             Unchanged on exit.   
+
+    M      - INTEGER.   
+             On entry, M specifies the number of rows of B. M must be at   
+             least zero.   
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the number of columns of B.  N must be   
+             at least zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry,  ALPHA specifies the scalar  alpha. When  alpha is   
+             zero then  A is not referenced and  B need not be set before   
+             entry.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m   
+             when  SIDE = 'L' or 'l'  and is  n  when  SIDE = 'R' or 'r'.   
+             Before entry  with  UPLO = 'U' or 'u',  the  leading  k by k   
+             upper triangular part of the array  A must contain the upper   
+             triangular matrix  and the strictly lower triangular part of   
+             A is not referenced.   
+             Before entry  with  UPLO = 'L' or 'l',  the  leading  k by k   
+             lower triangular part of the array  A must contain the lower   
+             triangular matrix  and the strictly upper triangular part of   
+             A is not referenced.   
+             Note that when  DIAG = 'U' or 'u',  the diagonal elements of   
+             A  are not referenced either,  but are assumed to be  unity.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program.  When  SIDE = 'L' or 'l'  then   
+             LDA  must be at least  max( 1, m ),  when  SIDE = 'R' or 'r'   
+             then LDA must be at least max( 1, n ).   
+             Unchanged on exit.   
+
+    B      - DOUBLE PRECISION array of DIMENSION ( LDB, n ).   
+             Before entry,  the leading  m by n part of the array  B must   
+             contain the matrix  B,  and  on exit  is overwritten  by the   
+             transformed matrix.   
+
+    LDB    - INTEGER.   
+             On entry, LDB specifies the first dimension of B as declared   
+             in  the  calling  (sub)  program.   LDB  must  be  at  least   
+             max( 1, m ).   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 3 Blas routine.   
+
+    -- Written on 8-February-1989.   
+       Jack Dongarra, Argonne National Laboratory.   
+       Iain Duff, AERE Harwell.   
+       Jeremy Du Croz, Numerical Algorithms Group Ltd.   
+       Sven Hammarling, Numerical Algorithms Group Ltd.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+
+    /* Function Body */
+    lside = igraphlsame_(side, "L");
+    if (lside) {
+	nrowa = *m;
+    } else {
+	nrowa = *n;
+    }
+    nounit = igraphlsame_(diag, "N");
+    upper = igraphlsame_(uplo, "U");
+
+    info = 0;
+    if (! lside && ! igraphlsame_(side, "R")) {
+	info = 1;
+    } else if (! upper && ! igraphlsame_(uplo, "L")) {
+	info = 2;
+    } else if (! igraphlsame_(transa, "N") && ! igraphlsame_(transa,
+	     "T") && ! igraphlsame_(transa, "C")) {
+	info = 3;
+    } else if (! igraphlsame_(diag, "U") && ! igraphlsame_(diag, 
+	    "N")) {
+	info = 4;
+    } else if (*m < 0) {
+	info = 5;
+    } else if (*n < 0) {
+	info = 6;
+    } else if (*lda < max(1,nrowa)) {
+	info = 9;
+    } else if (*ldb < max(1,*m)) {
+	info = 11;
+    }
+    if (info != 0) {
+	igraphxerbla_("DTRMM ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+
+/*     And when  alpha.eq.zero. */
+
+    if (*alpha == 0.) {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		b[i__ + j * b_dim1] = 0.;
+/* L10: */
+	    }
+/* L20: */
+	}
+	return 0;
+    }
+
+/*     Start the operations. */
+
+    if (lside) {
+	if (igraphlsame_(transa, "N")) {
+
+/*           Form  B := alpha*A*B. */
+
+	    if (upper) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = *m;
+		    for (k = 1; k <= i__2; ++k) {
+			if (b[k + j * b_dim1] != 0.) {
+			    temp = *alpha * b[k + j * b_dim1];
+			    i__3 = k - 1;
+			    for (i__ = 1; i__ <= i__3; ++i__) {
+				b[i__ + j * b_dim1] += temp * a[i__ + k * 
+					a_dim1];
+/* L30: */
+			    }
+			    if (nounit) {
+				temp *= a[k + k * a_dim1];
+			    }
+			    b[k + j * b_dim1] = temp;
+			}
+/* L40: */
+		    }
+/* L50: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    for (k = *m; k >= 1; --k) {
+			if (b[k + j * b_dim1] != 0.) {
+			    temp = *alpha * b[k + j * b_dim1];
+			    b[k + j * b_dim1] = temp;
+			    if (nounit) {
+				b[k + j * b_dim1] *= a[k + k * a_dim1];
+			    }
+			    i__2 = *m;
+			    for (i__ = k + 1; i__ <= i__2; ++i__) {
+				b[i__ + j * b_dim1] += temp * a[i__ + k * 
+					a_dim1];
+/* L60: */
+			    }
+			}
+/* L70: */
+		    }
+/* L80: */
+		}
+	    }
+	} else {
+
+/*           Form  B := alpha*A**T*B. */
+
+	    if (upper) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    for (i__ = *m; i__ >= 1; --i__) {
+			temp = b[i__ + j * b_dim1];
+			if (nounit) {
+			    temp *= a[i__ + i__ * a_dim1];
+			}
+			i__2 = i__ - 1;
+			for (k = 1; k <= i__2; ++k) {
+			    temp += a[k + i__ * a_dim1] * b[k + j * b_dim1];
+/* L90: */
+			}
+			b[i__ + j * b_dim1] = *alpha * temp;
+/* L100: */
+		    }
+/* L110: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			temp = b[i__ + j * b_dim1];
+			if (nounit) {
+			    temp *= a[i__ + i__ * a_dim1];
+			}
+			i__3 = *m;
+			for (k = i__ + 1; k <= i__3; ++k) {
+			    temp += a[k + i__ * a_dim1] * b[k + j * b_dim1];
+/* L120: */
+			}
+			b[i__ + j * b_dim1] = *alpha * temp;
+/* L130: */
+		    }
+/* L140: */
+		}
+	    }
+	}
+    } else {
+	if (igraphlsame_(transa, "N")) {
+
+/*           Form  B := alpha*B*A. */
+
+	    if (upper) {
+		for (j = *n; j >= 1; --j) {
+		    temp = *alpha;
+		    if (nounit) {
+			temp *= a[j + j * a_dim1];
+		    }
+		    i__1 = *m;
+		    for (i__ = 1; i__ <= i__1; ++i__) {
+			b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];
+/* L150: */
+		    }
+		    i__1 = j - 1;
+		    for (k = 1; k <= i__1; ++k) {
+			if (a[k + j * a_dim1] != 0.) {
+			    temp = *alpha * a[k + j * a_dim1];
+			    i__2 = *m;
+			    for (i__ = 1; i__ <= i__2; ++i__) {
+				b[i__ + j * b_dim1] += temp * b[i__ + k * 
+					b_dim1];
+/* L160: */
+			    }
+			}
+/* L170: */
+		    }
+/* L180: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    temp = *alpha;
+		    if (nounit) {
+			temp *= a[j + j * a_dim1];
+		    }
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];
+/* L190: */
+		    }
+		    i__2 = *n;
+		    for (k = j + 1; k <= i__2; ++k) {
+			if (a[k + j * a_dim1] != 0.) {
+			    temp = *alpha * a[k + j * a_dim1];
+			    i__3 = *m;
+			    for (i__ = 1; i__ <= i__3; ++i__) {
+				b[i__ + j * b_dim1] += temp * b[i__ + k * 
+					b_dim1];
+/* L200: */
+			    }
+			}
+/* L210: */
+		    }
+/* L220: */
+		}
+	    }
+	} else {
+
+/*           Form  B := alpha*B*A**T. */
+
+	    if (upper) {
+		i__1 = *n;
+		for (k = 1; k <= i__1; ++k) {
+		    i__2 = k - 1;
+		    for (j = 1; j <= i__2; ++j) {
+			if (a[j + k * a_dim1] != 0.) {
+			    temp = *alpha * a[j + k * a_dim1];
+			    i__3 = *m;
+			    for (i__ = 1; i__ <= i__3; ++i__) {
+				b[i__ + j * b_dim1] += temp * b[i__ + k * 
+					b_dim1];
+/* L230: */
+			    }
+			}
+/* L240: */
+		    }
+		    temp = *alpha;
+		    if (nounit) {
+			temp *= a[k + k * a_dim1];
+		    }
+		    if (temp != 1.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];
+/* L250: */
+			}
+		    }
+/* L260: */
+		}
+	    } else {
+		for (k = *n; k >= 1; --k) {
+		    i__1 = *n;
+		    for (j = k + 1; j <= i__1; ++j) {
+			if (a[j + k * a_dim1] != 0.) {
+			    temp = *alpha * a[j + k * a_dim1];
+			    i__2 = *m;
+			    for (i__ = 1; i__ <= i__2; ++i__) {
+				b[i__ + j * b_dim1] += temp * b[i__ + k * 
+					b_dim1];
+/* L270: */
+			    }
+			}
+/* L280: */
+		    }
+		    temp = *alpha;
+		    if (nounit) {
+			temp *= a[k + k * a_dim1];
+		    }
+		    if (temp != 1.) {
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];
+/* L290: */
+			}
+		    }
+/* L300: */
+		}
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DTRMM . */
+
+} /* igraphdtrmm_ */
+
diff --git a/src/lapack/dtrmv.c b/src/lapack/dtrmv.c
new file mode 100644
index 0000000..ef13f10
--- /dev/null
+++ b/src/lapack/dtrmv.c
@@ -0,0 +1,335 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdtrmv_(char *uplo, char *trans, char *diag, integer *n, 
+	doublereal *a, integer *lda, doublereal *x, integer *incx)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+
+    /* Local variables */
+    integer i__, j, ix, jx, kx, info;
+    doublereal temp;
+    extern logical igraphlsame_(char *, char *);
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical nounit;
+
+
+/*  Purpose   
+    =======   
+
+    DTRMV  performs one of the matrix-vector operations   
+
+       x := A*x,   or   x := A**T*x,   
+
+    where x is an n element vector and  A is an n by n unit, or non-unit,   
+    upper or lower triangular matrix.   
+
+    Arguments   
+    ==========   
+
+    UPLO   - CHARACTER*1.   
+             On entry, UPLO specifies whether the matrix is an upper or   
+             lower triangular matrix as follows:   
+
+                UPLO = 'U' or 'u'   A is an upper triangular matrix.   
+
+                UPLO = 'L' or 'l'   A is a lower triangular matrix.   
+
+             Unchanged on exit.   
+
+    TRANS  - CHARACTER*1.   
+             On entry, TRANS specifies the operation to be performed as   
+             follows:   
+
+                TRANS = 'N' or 'n'   x := A*x.   
+
+                TRANS = 'T' or 't'   x := A**T*x.   
+
+                TRANS = 'C' or 'c'   x := A**T*x.   
+
+             Unchanged on exit.   
+
+    DIAG   - CHARACTER*1.   
+             On entry, DIAG specifies whether or not A is unit   
+             triangular as follows:   
+
+                DIAG = 'U' or 'u'   A is assumed to be unit triangular.   
+
+                DIAG = 'N' or 'n'   A is not assumed to be unit   
+                                    triangular.   
+
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the order of the matrix A.   
+             N must be at least zero.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, n ).   
+             Before entry with  UPLO = 'U' or 'u', the leading n by n   
+             upper triangular part of the array A must contain the upper   
+             triangular matrix and the strictly lower triangular part of   
+             A is not referenced.   
+             Before entry with UPLO = 'L' or 'l', the leading n by n   
+             lower triangular part of the array A must contain the lower   
+             triangular matrix and the strictly upper triangular part of   
+             A is not referenced.   
+             Note that when  DIAG = 'U' or 'u', the diagonal elements of   
+             A are not referenced either, but are assumed to be unity.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program. LDA must be at least   
+             max( 1, n ).   
+             Unchanged on exit.   
+
+    X      - DOUBLE PRECISION array of dimension at least   
+             ( 1 + ( n - 1 )*abs( INCX ) ).   
+             Before entry, the incremented array X must contain the n   
+             element vector x. On exit, X is overwritten with the   
+             tranformed vector x.   
+
+    INCX   - INTEGER.   
+             On entry, INCX specifies the increment for the elements of   
+             X. INCX must not be zero.   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 2 Blas routine.   
+    The vector and matrix arguments are not referenced when N = 0, or M = 0   
+
+    -- Written on 22-October-1986.   
+       Jack Dongarra, Argonne National Lab.   
+       Jeremy Du Croz, Nag Central Office.   
+       Sven Hammarling, Nag Central Office.   
+       Richard Hanson, Sandia National Labs.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --x;
+
+    /* Function Body */
+    info = 0;
+    if (! igraphlsame_(uplo, "U") && ! igraphlsame_(uplo, "L")) {
+	info = 1;
+    } else if (! igraphlsame_(trans, "N") && ! igraphlsame_(trans, 
+	    "T") && ! igraphlsame_(trans, "C")) {
+	info = 2;
+    } else if (! igraphlsame_(diag, "U") && ! igraphlsame_(diag, 
+	    "N")) {
+	info = 3;
+    } else if (*n < 0) {
+	info = 4;
+    } else if (*lda < max(1,*n)) {
+	info = 6;
+    } else if (*incx == 0) {
+	info = 8;
+    }
+    if (info != 0) {
+	igraphxerbla_("DTRMV ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+    nounit = igraphlsame_(diag, "N");
+
+/*     Set up the start point in X if the increment is not unity. This   
+       will be  ( N - 1 )*INCX  too small for descending loops. */
+
+    if (*incx <= 0) {
+	kx = 1 - (*n - 1) * *incx;
+    } else if (*incx != 1) {
+	kx = 1;
+    }
+
+/*     Start the operations. In this version the elements of A are   
+       accessed sequentially with one pass through A. */
+
+    if (igraphlsame_(trans, "N")) {
+
+/*        Form  x := A*x. */
+
+	if (igraphlsame_(uplo, "U")) {
+	    if (*incx == 1) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    if (x[j] != 0.) {
+			temp = x[j];
+			i__2 = j - 1;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    x[i__] += temp * a[i__ + j * a_dim1];
+/* L10: */
+			}
+			if (nounit) {
+			    x[j] *= a[j + j * a_dim1];
+			}
+		    }
+/* L20: */
+		}
+	    } else {
+		jx = kx;
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    if (x[jx] != 0.) {
+			temp = x[jx];
+			ix = kx;
+			i__2 = j - 1;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    x[ix] += temp * a[i__ + j * a_dim1];
+			    ix += *incx;
+/* L30: */
+			}
+			if (nounit) {
+			    x[jx] *= a[j + j * a_dim1];
+			}
+		    }
+		    jx += *incx;
+/* L40: */
+		}
+	    }
+	} else {
+	    if (*incx == 1) {
+		for (j = *n; j >= 1; --j) {
+		    if (x[j] != 0.) {
+			temp = x[j];
+			i__1 = j + 1;
+			for (i__ = *n; i__ >= i__1; --i__) {
+			    x[i__] += temp * a[i__ + j * a_dim1];
+/* L50: */
+			}
+			if (nounit) {
+			    x[j] *= a[j + j * a_dim1];
+			}
+		    }
+/* L60: */
+		}
+	    } else {
+		kx += (*n - 1) * *incx;
+		jx = kx;
+		for (j = *n; j >= 1; --j) {
+		    if (x[jx] != 0.) {
+			temp = x[jx];
+			ix = kx;
+			i__1 = j + 1;
+			for (i__ = *n; i__ >= i__1; --i__) {
+			    x[ix] += temp * a[i__ + j * a_dim1];
+			    ix -= *incx;
+/* L70: */
+			}
+			if (nounit) {
+			    x[jx] *= a[j + j * a_dim1];
+			}
+		    }
+		    jx -= *incx;
+/* L80: */
+		}
+	    }
+	}
+    } else {
+
+/*        Form  x := A**T*x. */
+
+	if (igraphlsame_(uplo, "U")) {
+	    if (*incx == 1) {
+		for (j = *n; j >= 1; --j) {
+		    temp = x[j];
+		    if (nounit) {
+			temp *= a[j + j * a_dim1];
+		    }
+		    for (i__ = j - 1; i__ >= 1; --i__) {
+			temp += a[i__ + j * a_dim1] * x[i__];
+/* L90: */
+		    }
+		    x[j] = temp;
+/* L100: */
+		}
+	    } else {
+		jx = kx + (*n - 1) * *incx;
+		for (j = *n; j >= 1; --j) {
+		    temp = x[jx];
+		    ix = jx;
+		    if (nounit) {
+			temp *= a[j + j * a_dim1];
+		    }
+		    for (i__ = j - 1; i__ >= 1; --i__) {
+			ix -= *incx;
+			temp += a[i__ + j * a_dim1] * x[ix];
+/* L110: */
+		    }
+		    x[jx] = temp;
+		    jx -= *incx;
+/* L120: */
+		}
+	    }
+	} else {
+	    if (*incx == 1) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    temp = x[j];
+		    if (nounit) {
+			temp *= a[j + j * a_dim1];
+		    }
+		    i__2 = *n;
+		    for (i__ = j + 1; i__ <= i__2; ++i__) {
+			temp += a[i__ + j * a_dim1] * x[i__];
+/* L130: */
+		    }
+		    x[j] = temp;
+/* L140: */
+		}
+	    } else {
+		jx = kx;
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    temp = x[jx];
+		    ix = jx;
+		    if (nounit) {
+			temp *= a[j + j * a_dim1];
+		    }
+		    i__2 = *n;
+		    for (i__ = j + 1; i__ <= i__2; ++i__) {
+			ix += *incx;
+			temp += a[i__ + j * a_dim1] * x[ix];
+/* L150: */
+		    }
+		    x[jx] = temp;
+		    jx += *incx;
+/* L160: */
+		}
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DTRMV . */
+
+} /* igraphdtrmv_ */
+
diff --git a/src/lapack/dtrsen.c b/src/lapack/dtrsen.c
new file mode 100644
index 0000000..cf36d54
--- /dev/null
+++ b/src/lapack/dtrsen.c
@@ -0,0 +1,514 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c_n1 = -1;
+
+/* Subroutine */ int igraphdtrsen_(char *job, char *compq, logical *select, integer 
+	*n, doublereal *t, integer *ldt, doublereal *q, integer *ldq, 
+	doublereal *wr, doublereal *wi, integer *m, doublereal *s, doublereal 
+	*sep, doublereal *work, integer *lwork, integer *iwork, integer *
+	liwork, integer *info)
+{
+    /* System generated locals */
+    integer q_dim1, q_offset, t_dim1, t_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer k, n1, n2, kk, nn, ks;
+    doublereal est;
+    integer kase;
+    logical pair;
+    integer ierr;
+    logical swap;
+    doublereal scale;
+    extern logical igraphlsame_(char *, char *);
+    integer isave[3], lwmin;
+    logical wantq, wants;
+    doublereal rnorm;
+    extern /* Subroutine */ int igraphdlacn2_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *, integer *, integer *);
+    extern doublereal igraphdlange_(char *, integer *, integer *, doublereal *, 
+	    integer *, doublereal *);
+    extern /* Subroutine */ int igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphxerbla_(char *, integer *, ftnlen);
+    logical wantbh;
+    extern /* Subroutine */ int igraphdtrexc_(char *, integer *, doublereal *, 
+	    integer *, doublereal *, integer *, integer *, integer *, 
+	    doublereal *, integer *);
+    integer liwmin;
+    logical wantsp, lquery;
+    extern /* Subroutine */ int igraphdtrsyl_(char *, char *, integer *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *);
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DTRSEN reorders the real Schur factorization of a real matrix   
+    A = Q*T*Q**T, so that a selected cluster of eigenvalues appears in   
+    the leading diagonal blocks of the upper quasi-triangular matrix T,   
+    and the leading columns of Q form an orthonormal basis of the   
+    corresponding right invariant subspace.   
+
+    Optionally the routine computes the reciprocal condition numbers of   
+    the cluster of eigenvalues and/or the invariant subspace.   
+
+    T must be in Schur canonical form (as returned by DHSEQR), that is,   
+    block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each   
+    2-by-2 diagonal block has its diagonal elemnts equal and its   
+    off-diagonal elements of opposite sign.   
+
+    Arguments   
+    =========   
+
+    JOB     (input) CHARACTER*1   
+            Specifies whether condition numbers are required for the   
+            cluster of eigenvalues (S) or the invariant subspace (SEP):   
+            = 'N': none;   
+            = 'E': for eigenvalues only (S);   
+            = 'V': for invariant subspace only (SEP);   
+            = 'B': for both eigenvalues and invariant subspace (S and   
+                   SEP).   
+
+    COMPQ   (input) CHARACTER*1   
+            = 'V': update the matrix Q of Schur vectors;   
+            = 'N': do not update Q.   
+
+    SELECT  (input) LOGICAL array, dimension (N)   
+            SELECT specifies the eigenvalues in the selected cluster. To   
+            select a real eigenvalue w(j), SELECT(j) must be set to   
+            .TRUE.. To select a complex conjugate pair of eigenvalues   
+            w(j) and w(j+1), corresponding to a 2-by-2 diagonal block,   
+            either SELECT(j) or SELECT(j+1) or both must be set to   
+            .TRUE.; a complex conjugate pair of eigenvalues must be   
+            either both included in the cluster or both excluded.   
+
+    N       (input) INTEGER   
+            The order of the matrix T. N >= 0.   
+
+    T       (input/output) DOUBLE PRECISION array, dimension (LDT,N)   
+            On entry, the upper quasi-triangular matrix T, in Schur   
+            canonical form.   
+            On exit, T is overwritten by the reordered matrix T, again in   
+            Schur canonical form, with the selected eigenvalues in the   
+            leading diagonal blocks.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= max(1,N).   
+
+    Q       (input/output) DOUBLE PRECISION array, dimension (LDQ,N)   
+            On entry, if COMPQ = 'V', the matrix Q of Schur vectors.   
+            On exit, if COMPQ = 'V', Q has been postmultiplied by the   
+            orthogonal transformation matrix which reorders T; the   
+            leading M columns of Q form an orthonormal basis for the   
+            specified invariant subspace.   
+            If COMPQ = 'N', Q is not referenced.   
+
+    LDQ     (input) INTEGER   
+            The leading dimension of the array Q.   
+            LDQ >= 1; and if COMPQ = 'V', LDQ >= N.   
+
+    WR      (output) DOUBLE PRECISION array, dimension (N)   
+    WI      (output) DOUBLE PRECISION array, dimension (N)   
+            The real and imaginary parts, respectively, of the reordered   
+            eigenvalues of T. The eigenvalues are stored in the same   
+            order as on the diagonal of T, with WR(i) = T(i,i) and, if   
+            T(i:i+1,i:i+1) is a 2-by-2 diagonal block, WI(i) > 0 and   
+            WI(i+1) = -WI(i). Note that if a complex eigenvalue is   
+            sufficiently ill-conditioned, then its value may differ   
+            significantly from its value before reordering.   
+
+    M       (output) INTEGER   
+            The dimension of the specified invariant subspace.   
+            0 < = M <= N.   
+
+    S       (output) DOUBLE PRECISION   
+            If JOB = 'E' or 'B', S is a lower bound on the reciprocal   
+            condition number for the selected cluster of eigenvalues.   
+            S cannot underestimate the true reciprocal condition number   
+            by more than a factor of sqrt(N). If M = 0 or N, S = 1.   
+            If JOB = 'N' or 'V', S is not referenced.   
+
+    SEP     (output) DOUBLE PRECISION   
+            If JOB = 'V' or 'B', SEP is the estimated reciprocal   
+            condition number of the specified invariant subspace. If   
+            M = 0 or N, SEP = norm(T).   
+            If JOB = 'N' or 'E', SEP is not referenced.   
+
+    WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
+            On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
+
+    LWORK   (input) INTEGER   
+            The dimension of the array WORK.   
+            If JOB = 'N', LWORK >= max(1,N);   
+            if JOB = 'E', LWORK >= max(1,M*(N-M));   
+            if JOB = 'V' or 'B', LWORK >= max(1,2*M*(N-M)).   
+
+            If LWORK = -1, then a workspace query is assumed; the routine   
+            only calculates the optimal size of the WORK array, returns   
+            this value as the first entry of the WORK array, and no error   
+            message related to LWORK is issued by XERBLA.   
+
+    IWORK   (workspace) INTEGER array, dimension (MAX(1,LIWORK))   
+            On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.   
+
+    LIWORK  (input) INTEGER   
+            The dimension of the array IWORK.   
+            If JOB = 'N' or 'E', LIWORK >= 1;   
+            if JOB = 'V' or 'B', LIWORK >= max(1,M*(N-M)).   
+
+            If LIWORK = -1, then a workspace query is assumed; the   
+            routine only calculates the optimal size of the IWORK array,   
+            returns this value as the first entry of the IWORK array, and   
+            no error message related to LIWORK is issued by XERBLA.   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+            = 1: reordering of T failed because some eigenvalues are too   
+                 close to separate (the problem is very ill-conditioned);   
+                 T may have been partially reordered, and WR and WI   
+                 contain the eigenvalues in the same order as in T; S and   
+                 SEP (if requested) are set to zero.   
+
+    Further Details   
+    ===============   
+
+    DTRSEN first collects the selected eigenvalues by computing an   
+    orthogonal transformation Z to move them to the top left corner of T.   
+    In other words, the selected eigenvalues are the eigenvalues of T11   
+    in:   
+
+            Z**T * T * Z = ( T11 T12 ) n1   
+                           (  0  T22 ) n2   
+                              n1  n2   
+
+    where N = n1+n2 and Z**T means the transpose of Z. The first n1 columns   
+    of Z span the specified invariant subspace of T.   
+
+    If T has been obtained from the real Schur factorization of a matrix   
+    A = Q*T*Q**T, then the reordered real Schur factorization of A is given   
+    by A = (Q*Z)*(Z**T*T*Z)*(Q*Z)**T, and the first n1 columns of Q*Z span   
+    the corresponding invariant subspace of A.   
+
+    The reciprocal condition number of the average of the eigenvalues of   
+    T11 may be returned in S. S lies between 0 (very badly conditioned)   
+    and 1 (very well conditioned). It is computed as follows. First we   
+    compute R so that   
+
+                           P = ( I  R ) n1   
+                               ( 0  0 ) n2   
+                                 n1 n2   
+
+    is the projector on the invariant subspace associated with T11.   
+    R is the solution of the Sylvester equation:   
+
+                          T11*R - R*T22 = T12.   
+
+    Let F-norm(M) denote the Frobenius-norm of M and 2-norm(M) denote   
+    the two-norm of M. Then S is computed as the lower bound   
+
+                        (1 + F-norm(R)**2)**(-1/2)   
+
+    on the reciprocal of 2-norm(P), the true reciprocal condition number.   
+    S cannot underestimate 1 / 2-norm(P) by more than a factor of   
+    sqrt(N).   
+
+    An approximate error bound for the computed average of the   
+    eigenvalues of T11 is   
+
+                           EPS * norm(T) / S   
+
+    where EPS is the machine precision.   
+
+    The reciprocal condition number of the right invariant subspace   
+    spanned by the first n1 columns of Z (or of Q*Z) is returned in SEP.   
+    SEP is defined as the separation of T11 and T22:   
+
+                       sep( T11, T22 ) = sigma-min( C )   
+
+    where sigma-min(C) is the smallest singular value of the   
+    n1*n2-by-n1*n2 matrix   
+
+       C  = kprod( I(n2), T11 ) - kprod( transpose(T22), I(n1) )   
+
+    I(m) is an m by m identity matrix, and kprod denotes the Kronecker   
+    product. We estimate sigma-min(C) by the reciprocal of an estimate of   
+    the 1-norm of inverse(C). The true reciprocal 1-norm of inverse(C)   
+    cannot differ from sigma-min(C) by more than a factor of sqrt(n1*n2).   
+
+    When SEP is small, small changes in T can cause large changes in   
+    the invariant subspace. An approximate bound on the maximum angular   
+    error in the computed right invariant subspace is   
+
+                        EPS * norm(T) / SEP   
+
+    =====================================================================   
+
+
+       Decode and test the input parameters   
+
+       Parameter adjustments */
+    --select;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    q_dim1 = *ldq;
+    q_offset = 1 + q_dim1;
+    q -= q_offset;
+    --wr;
+    --wi;
+    --work;
+    --iwork;
+
+    /* Function Body */
+    wantbh = igraphlsame_(job, "B");
+    wants = igraphlsame_(job, "E") || wantbh;
+    wantsp = igraphlsame_(job, "V") || wantbh;
+    wantq = igraphlsame_(compq, "V");
+
+    *info = 0;
+    lquery = *lwork == -1;
+    if (! igraphlsame_(job, "N") && ! wants && ! wantsp) {
+	*info = -1;
+    } else if (! igraphlsame_(compq, "N") && ! wantq) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*ldt < max(1,*n)) {
+	*info = -6;
+    } else if (*ldq < 1 || wantq && *ldq < *n) {
+	*info = -8;
+    } else {
+
+/*        Set M to the dimension of the specified invariant subspace,   
+          and test LWORK and LIWORK. */
+
+	*m = 0;
+	pair = FALSE_;
+	i__1 = *n;
+	for (k = 1; k <= i__1; ++k) {
+	    if (pair) {
+		pair = FALSE_;
+	    } else {
+		if (k < *n) {
+		    if (t[k + 1 + k * t_dim1] == 0.) {
+			if (select[k]) {
+			    ++(*m);
+			}
+		    } else {
+			pair = TRUE_;
+			if (select[k] || select[k + 1]) {
+			    *m += 2;
+			}
+		    }
+		} else {
+		    if (select[*n]) {
+			++(*m);
+		    }
+		}
+	    }
+/* L10: */
+	}
+
+	n1 = *m;
+	n2 = *n - *m;
+	nn = n1 * n2;
+
+	if (wantsp) {
+/* Computing MAX */
+	    i__1 = 1, i__2 = nn << 1;
+	    lwmin = max(i__1,i__2);
+	    liwmin = max(1,nn);
+	} else if (igraphlsame_(job, "N")) {
+	    lwmin = max(1,*n);
+	    liwmin = 1;
+	} else if (igraphlsame_(job, "E")) {
+	    lwmin = max(1,nn);
+	    liwmin = 1;
+	}
+
+	if (*lwork < lwmin && ! lquery) {
+	    *info = -15;
+	} else if (*liwork < liwmin && ! lquery) {
+	    *info = -17;
+	}
+    }
+
+    if (*info == 0) {
+	work[1] = (doublereal) lwmin;
+	iwork[1] = liwmin;
+    }
+
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DTRSEN", &i__1, (ftnlen)6);
+	return 0;
+    } else if (lquery) {
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*m == *n || *m == 0) {
+	if (wants) {
+	    *s = 1.;
+	}
+	if (wantsp) {
+	    *sep = igraphdlange_("1", n, n, &t[t_offset], ldt, &work[1]);
+	}
+	goto L40;
+    }
+
+/*     Collect the selected blocks at the top-left corner of T. */
+
+    ks = 0;
+    pair = FALSE_;
+    i__1 = *n;
+    for (k = 1; k <= i__1; ++k) {
+	if (pair) {
+	    pair = FALSE_;
+	} else {
+	    swap = select[k];
+	    if (k < *n) {
+		if (t[k + 1 + k * t_dim1] != 0.) {
+		    pair = TRUE_;
+		    swap = swap || select[k + 1];
+		}
+	    }
+	    if (swap) {
+		++ks;
+
+/*              Swap the K-th block to position KS. */
+
+		ierr = 0;
+		kk = k;
+		if (k != ks) {
+		    igraphdtrexc_(compq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
+			    kk, &ks, &work[1], &ierr);
+		}
+		if (ierr == 1 || ierr == 2) {
+
+/*                 Blocks too close to swap: exit. */
+
+		    *info = 1;
+		    if (wants) {
+			*s = 0.;
+		    }
+		    if (wantsp) {
+			*sep = 0.;
+		    }
+		    goto L40;
+		}
+		if (pair) {
+		    ++ks;
+		}
+	    }
+	}
+/* L20: */
+    }
+
+    if (wants) {
+
+/*        Solve Sylvester equation for R:   
+
+             T11*R - R*T22 = scale*T12 */
+
+	igraphdlacpy_("F", &n1, &n2, &t[(n1 + 1) * t_dim1 + 1], ldt, &work[1], &n1);
+	igraphdtrsyl_("N", "N", &c_n1, &n1, &n2, &t[t_offset], ldt, &t[n1 + 1 + (n1 
+		+ 1) * t_dim1], ldt, &work[1], &n1, &scale, &ierr);
+
+/*        Estimate the reciprocal of the condition number of the cluster   
+          of eigenvalues. */
+
+	rnorm = igraphdlange_("F", &n1, &n2, &work[1], &n1, &work[1]);
+	if (rnorm == 0.) {
+	    *s = 1.;
+	} else {
+	    *s = scale / (sqrt(scale * scale / rnorm + rnorm) * sqrt(rnorm));
+	}
+    }
+
+    if (wantsp) {
+
+/*        Estimate sep(T11,T22). */
+
+	est = 0.;
+	kase = 0;
+L30:
+	igraphdlacn2_(&nn, &work[nn + 1], &work[1], &iwork[1], &est, &kase, isave);
+	if (kase != 0) {
+	    if (kase == 1) {
+
+/*              Solve  T11*R - R*T22 = scale*X. */
+
+		igraphdtrsyl_("N", "N", &c_n1, &n1, &n2, &t[t_offset], ldt, &t[n1 + 
+			1 + (n1 + 1) * t_dim1], ldt, &work[1], &n1, &scale, &
+			ierr);
+	    } else {
+
+/*              Solve T11**T*R - R*T22**T = scale*X. */
+
+		igraphdtrsyl_("T", "T", &c_n1, &n1, &n2, &t[t_offset], ldt, &t[n1 + 
+			1 + (n1 + 1) * t_dim1], ldt, &work[1], &n1, &scale, &
+			ierr);
+	    }
+	    goto L30;
+	}
+
+	*sep = scale / est;
+    }
+
+L40:
+
+/*     Store the output eigenvalues in WR and WI. */
+
+    i__1 = *n;
+    for (k = 1; k <= i__1; ++k) {
+	wr[k] = t[k + k * t_dim1];
+	wi[k] = 0.;
+/* L50: */
+    }
+    i__1 = *n - 1;
+    for (k = 1; k <= i__1; ++k) {
+	if (t[k + 1 + k * t_dim1] != 0.) {
+	    wi[k] = sqrt((d__1 = t[k + (k + 1) * t_dim1], abs(d__1))) * sqrt((
+		    d__2 = t[k + 1 + k * t_dim1], abs(d__2)));
+	    wi[k + 1] = -wi[k];
+	}
+/* L60: */
+    }
+
+    work[1] = (doublereal) lwmin;
+    iwork[1] = liwmin;
+
+    return 0;
+
+/*     End of DTRSEN */
+
+} /* igraphdtrsen_ */
+
diff --git a/src/lapack/dtrsm.c b/src/lapack/dtrsm.c
new file mode 100644
index 0000000..b72193b
--- /dev/null
+++ b/src/lapack/dtrsm.c
@@ -0,0 +1,479 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphdtrsm_(char *side, char *uplo, char *transa, char *diag, 
+	integer *m, integer *n, doublereal *alpha, doublereal *a, integer *
+	lda, doublereal *b, integer *ldb)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3;
+
+    /* Local variables */
+    integer i__, j, k, info;
+    doublereal temp;
+    logical lside;
+    extern logical igraphlsame_(char *, char *);
+    integer nrowa;
+    logical upper;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    logical nounit;
+
+
+/*  Purpose   
+    =======   
+
+    DTRSM  solves one of the matrix equations   
+
+       op( A )*X = alpha*B,   or   X*op( A ) = alpha*B,   
+
+    where alpha is a scalar, X and B are m by n matrices, A is a unit, or   
+    non-unit,  upper or lower triangular matrix  and  op( A )  is one  of   
+
+       op( A ) = A   or   op( A ) = A**T.   
+
+    The matrix X is overwritten on B.   
+
+    Arguments   
+    ==========   
+
+    SIDE   - CHARACTER*1.   
+             On entry, SIDE specifies whether op( A ) appears on the left   
+             or right of X as follows:   
+
+                SIDE = 'L' or 'l'   op( A )*X = alpha*B.   
+
+                SIDE = 'R' or 'r'   X*op( A ) = alpha*B.   
+
+             Unchanged on exit.   
+
+    UPLO   - CHARACTER*1.   
+             On entry, UPLO specifies whether the matrix A is an upper or   
+             lower triangular matrix as follows:   
+
+                UPLO = 'U' or 'u'   A is an upper triangular matrix.   
+
+                UPLO = 'L' or 'l'   A is a lower triangular matrix.   
+
+             Unchanged on exit.   
+
+    TRANSA - CHARACTER*1.   
+             On entry, TRANSA specifies the form of op( A ) to be used in   
+             the matrix multiplication as follows:   
+
+                TRANSA = 'N' or 'n'   op( A ) = A.   
+
+                TRANSA = 'T' or 't'   op( A ) = A**T.   
+
+                TRANSA = 'C' or 'c'   op( A ) = A**T.   
+
+             Unchanged on exit.   
+
+    DIAG   - CHARACTER*1.   
+             On entry, DIAG specifies whether or not A is unit triangular   
+             as follows:   
+
+                DIAG = 'U' or 'u'   A is assumed to be unit triangular.   
+
+                DIAG = 'N' or 'n'   A is not assumed to be unit   
+                                    triangular.   
+
+             Unchanged on exit.   
+
+    M      - INTEGER.   
+             On entry, M specifies the number of rows of B. M must be at   
+             least zero.   
+             Unchanged on exit.   
+
+    N      - INTEGER.   
+             On entry, N specifies the number of columns of B.  N must be   
+             at least zero.   
+             Unchanged on exit.   
+
+    ALPHA  - DOUBLE PRECISION.   
+             On entry,  ALPHA specifies the scalar  alpha. When  alpha is   
+             zero then  A is not referenced and  B need not be set before   
+             entry.   
+             Unchanged on exit.   
+
+    A      - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m   
+             when  SIDE = 'L' or 'l'  and is  n  when  SIDE = 'R' or 'r'.   
+             Before entry  with  UPLO = 'U' or 'u',  the  leading  k by k   
+             upper triangular part of the array  A must contain the upper   
+             triangular matrix  and the strictly lower triangular part of   
+             A is not referenced.   
+             Before entry  with  UPLO = 'L' or 'l',  the  leading  k by k   
+             lower triangular part of the array  A must contain the lower   
+             triangular matrix  and the strictly upper triangular part of   
+             A is not referenced.   
+             Note that when  DIAG = 'U' or 'u',  the diagonal elements of   
+             A  are not referenced either,  but are assumed to be  unity.   
+             Unchanged on exit.   
+
+    LDA    - INTEGER.   
+             On entry, LDA specifies the first dimension of A as declared   
+             in the calling (sub) program.  When  SIDE = 'L' or 'l'  then   
+             LDA  must be at least  max( 1, m ),  when  SIDE = 'R' or 'r'   
+             then LDA must be at least max( 1, n ).   
+             Unchanged on exit.   
+
+    B      - DOUBLE PRECISION array of DIMENSION ( LDB, n ).   
+             Before entry,  the leading  m by n part of the array  B must   
+             contain  the  right-hand  side  matrix  B,  and  on exit  is   
+             overwritten by the solution matrix  X.   
+
+    LDB    - INTEGER.   
+             On entry, LDB specifies the first dimension of B as declared   
+             in  the  calling  (sub)  program.   LDB  must  be  at  least   
+             max( 1, m ).   
+             Unchanged on exit.   
+
+    Further Details   
+    ===============   
+
+    Level 3 Blas routine.   
+
+
+    -- Written on 8-February-1989.   
+       Jack Dongarra, Argonne National Laboratory.   
+       Iain Duff, AERE Harwell.   
+       Jeremy Du Croz, Numerical Algorithms Group Ltd.   
+       Sven Hammarling, Numerical Algorithms Group Ltd.   
+
+    =====================================================================   
+
+
+       Test the input parameters.   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+
+    /* Function Body */
+    lside = igraphlsame_(side, "L");
+    if (lside) {
+	nrowa = *m;
+    } else {
+	nrowa = *n;
+    }
+    nounit = igraphlsame_(diag, "N");
+    upper = igraphlsame_(uplo, "U");
+
+    info = 0;
+    if (! lside && ! igraphlsame_(side, "R")) {
+	info = 1;
+    } else if (! upper && ! igraphlsame_(uplo, "L")) {
+	info = 2;
+    } else if (! igraphlsame_(transa, "N") && ! igraphlsame_(transa,
+	     "T") && ! igraphlsame_(transa, "C")) {
+	info = 3;
+    } else if (! igraphlsame_(diag, "U") && ! igraphlsame_(diag, 
+	    "N")) {
+	info = 4;
+    } else if (*m < 0) {
+	info = 5;
+    } else if (*n < 0) {
+	info = 6;
+    } else if (*lda < max(1,nrowa)) {
+	info = 9;
+    } else if (*ldb < max(1,*m)) {
+	info = 11;
+    }
+    if (info != 0) {
+	igraphxerbla_("DTRSM ", &info, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible. */
+
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+
+/*     And when  alpha.eq.zero. */
+
+    if (*alpha == 0.) {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__2 = *m;
+	    for (i__ = 1; i__ <= i__2; ++i__) {
+		b[i__ + j * b_dim1] = 0.;
+/* L10: */
+	    }
+/* L20: */
+	}
+	return 0;
+    }
+
+/*     Start the operations. */
+
+    if (lside) {
+	if (igraphlsame_(transa, "N")) {
+
+/*           Form  B := alpha*inv( A )*B. */
+
+	    if (upper) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    if (*alpha != 1.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1]
+				    ;
+/* L30: */
+			}
+		    }
+		    for (k = *m; k >= 1; --k) {
+			if (b[k + j * b_dim1] != 0.) {
+			    if (nounit) {
+				b[k + j * b_dim1] /= a[k + k * a_dim1];
+			    }
+			    i__2 = k - 1;
+			    for (i__ = 1; i__ <= i__2; ++i__) {
+				b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[
+					i__ + k * a_dim1];
+/* L40: */
+			    }
+			}
+/* L50: */
+		    }
+/* L60: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    if (*alpha != 1.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1]
+				    ;
+/* L70: */
+			}
+		    }
+		    i__2 = *m;
+		    for (k = 1; k <= i__2; ++k) {
+			if (b[k + j * b_dim1] != 0.) {
+			    if (nounit) {
+				b[k + j * b_dim1] /= a[k + k * a_dim1];
+			    }
+			    i__3 = *m;
+			    for (i__ = k + 1; i__ <= i__3; ++i__) {
+				b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[
+					i__ + k * a_dim1];
+/* L80: */
+			    }
+			}
+/* L90: */
+		    }
+/* L100: */
+		}
+	    }
+	} else {
+
+/*           Form  B := alpha*inv( A**T )*B. */
+
+	    if (upper) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    i__2 = *m;
+		    for (i__ = 1; i__ <= i__2; ++i__) {
+			temp = *alpha * b[i__ + j * b_dim1];
+			i__3 = i__ - 1;
+			for (k = 1; k <= i__3; ++k) {
+			    temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1];
+/* L110: */
+			}
+			if (nounit) {
+			    temp /= a[i__ + i__ * a_dim1];
+			}
+			b[i__ + j * b_dim1] = temp;
+/* L120: */
+		    }
+/* L130: */
+		}
+	    } else {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    for (i__ = *m; i__ >= 1; --i__) {
+			temp = *alpha * b[i__ + j * b_dim1];
+			i__2 = *m;
+			for (k = i__ + 1; k <= i__2; ++k) {
+			    temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1];
+/* L140: */
+			}
+			if (nounit) {
+			    temp /= a[i__ + i__ * a_dim1];
+			}
+			b[i__ + j * b_dim1] = temp;
+/* L150: */
+		    }
+/* L160: */
+		}
+	    }
+	}
+    } else {
+	if (igraphlsame_(transa, "N")) {
+
+/*           Form  B := alpha*B*inv( A ). */
+
+	    if (upper) {
+		i__1 = *n;
+		for (j = 1; j <= i__1; ++j) {
+		    if (*alpha != 1.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1]
+				    ;
+/* L170: */
+			}
+		    }
+		    i__2 = j - 1;
+		    for (k = 1; k <= i__2; ++k) {
+			if (a[k + j * a_dim1] != 0.) {
+			    i__3 = *m;
+			    for (i__ = 1; i__ <= i__3; ++i__) {
+				b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[
+					i__ + k * b_dim1];
+/* L180: */
+			    }
+			}
+/* L190: */
+		    }
+		    if (nounit) {
+			temp = 1. / a[j + j * a_dim1];
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];
+/* L200: */
+			}
+		    }
+/* L210: */
+		}
+	    } else {
+		for (j = *n; j >= 1; --j) {
+		    if (*alpha != 1.) {
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1]
+				    ;
+/* L220: */
+			}
+		    }
+		    i__1 = *n;
+		    for (k = j + 1; k <= i__1; ++k) {
+			if (a[k + j * a_dim1] != 0.) {
+			    i__2 = *m;
+			    for (i__ = 1; i__ <= i__2; ++i__) {
+				b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[
+					i__ + k * b_dim1];
+/* L230: */
+			    }
+			}
+/* L240: */
+		    }
+		    if (nounit) {
+			temp = 1. / a[j + j * a_dim1];
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];
+/* L250: */
+			}
+		    }
+/* L260: */
+		}
+	    }
+	} else {
+
+/*           Form  B := alpha*B*inv( A**T ). */
+
+	    if (upper) {
+		for (k = *n; k >= 1; --k) {
+		    if (nounit) {
+			temp = 1. / a[k + k * a_dim1];
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];
+/* L270: */
+			}
+		    }
+		    i__1 = k - 1;
+		    for (j = 1; j <= i__1; ++j) {
+			if (a[j + k * a_dim1] != 0.) {
+			    temp = a[j + k * a_dim1];
+			    i__2 = *m;
+			    for (i__ = 1; i__ <= i__2; ++i__) {
+				b[i__ + j * b_dim1] -= temp * b[i__ + k * 
+					b_dim1];
+/* L280: */
+			    }
+			}
+/* L290: */
+		    }
+		    if (*alpha != 1.) {
+			i__1 = *m;
+			for (i__ = 1; i__ <= i__1; ++i__) {
+			    b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1]
+				    ;
+/* L300: */
+			}
+		    }
+/* L310: */
+		}
+	    } else {
+		i__1 = *n;
+		for (k = 1; k <= i__1; ++k) {
+		    if (nounit) {
+			temp = 1. / a[k + k * a_dim1];
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];
+/* L320: */
+			}
+		    }
+		    i__2 = *n;
+		    for (j = k + 1; j <= i__2; ++j) {
+			if (a[j + k * a_dim1] != 0.) {
+			    temp = a[j + k * a_dim1];
+			    i__3 = *m;
+			    for (i__ = 1; i__ <= i__3; ++i__) {
+				b[i__ + j * b_dim1] -= temp * b[i__ + k * 
+					b_dim1];
+/* L330: */
+			    }
+			}
+/* L340: */
+		    }
+		    if (*alpha != 1.) {
+			i__2 = *m;
+			for (i__ = 1; i__ <= i__2; ++i__) {
+			    b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1]
+				    ;
+/* L350: */
+			}
+		    }
+/* L360: */
+		}
+	    }
+	}
+    }
+
+    return 0;
+
+/*     End of DTRSM . */
+
+} /* igraphdtrsm_ */
+
diff --git a/src/lapack/dtrsna.c b/src/lapack/dtrsna.c
new file mode 100644
index 0000000..85140b1
--- /dev/null
+++ b/src/lapack/dtrsna.c
@@ -0,0 +1,590 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static logical c_true = TRUE_;
+static logical c_false = FALSE_;
+
+/* Subroutine */ int igraphdtrsna_(char *job, char *howmny, logical *select, 
+	integer *n, doublereal *t, integer *ldt, doublereal *vl, integer *
+	ldvl, doublereal *vr, integer *ldvr, doublereal *s, doublereal *sep, 
+	integer *mm, integer *m, doublereal *work, integer *ldwork, integer *
+	iwork, integer *info)
+{
+    /* System generated locals */
+    integer t_dim1, t_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, 
+	    work_dim1, work_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    integer i__, j, k, n2;
+    doublereal cs;
+    integer nn, ks;
+    doublereal sn, mu, eps, est;
+    integer kase;
+    doublereal cond;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    logical pair;
+    integer ierr;
+    doublereal dumm, prod;
+    integer ifst;
+    doublereal lnrm;
+    integer ilst;
+    doublereal rnrm;
+    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
+    doublereal prod1, prod2, scale, delta;
+    extern logical igraphlsame_(char *, char *);
+    integer isave[3];
+    logical wants;
+    doublereal dummy[1];
+    extern /* Subroutine */ int igraphdlacn2_(integer *, doublereal *, doublereal *,
+	     integer *, doublereal *, integer *, integer *);
+    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
+    extern /* Subroutine */ int igraphdlabad_(doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *);
+    extern /* Subroutine */ int igraphdlacpy_(char *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *), 
+	    igraphxerbla_(char *, integer *, ftnlen);
+    doublereal bignum;
+    logical wantbh;
+    extern /* Subroutine */ int igraphdlaqtr_(logical *, logical *, integer *, 
+	    doublereal *, integer *, doublereal *, doublereal *, doublereal *,
+	     doublereal *, doublereal *, integer *), igraphdtrexc_(char *, integer *
+	    , doublereal *, integer *, doublereal *, integer *, integer *, 
+	    integer *, doublereal *, integer *);
+    logical somcon;
+    doublereal smlnum;
+    logical wantsp;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+       Modified to call DLACN2 in place of DLACON, 5 Feb 03, SJH.   
+
+
+    Purpose   
+    =======   
+
+    DTRSNA estimates reciprocal condition numbers for specified   
+    eigenvalues and/or right eigenvectors of a real upper   
+    quasi-triangular matrix T (or of any matrix Q*T*Q**T with Q   
+    orthogonal).   
+
+    T must be in Schur canonical form (as returned by DHSEQR), that is,   
+    block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each   
+    2-by-2 diagonal block has its diagonal elements equal and its   
+    off-diagonal elements of opposite sign.   
+
+    Arguments   
+    =========   
+
+    JOB     (input) CHARACTER*1   
+            Specifies whether condition numbers are required for   
+            eigenvalues (S) or eigenvectors (SEP):   
+            = 'E': for eigenvalues only (S);   
+            = 'V': for eigenvectors only (SEP);   
+            = 'B': for both eigenvalues and eigenvectors (S and SEP).   
+
+    HOWMNY  (input) CHARACTER*1   
+            = 'A': compute condition numbers for all eigenpairs;   
+            = 'S': compute condition numbers for selected eigenpairs   
+                   specified by the array SELECT.   
+
+    SELECT  (input) LOGICAL array, dimension (N)   
+            If HOWMNY = 'S', SELECT specifies the eigenpairs for which   
+            condition numbers are required. To select condition numbers   
+            for the eigenpair corresponding to a real eigenvalue w(j),   
+            SELECT(j) must be set to .TRUE.. To select condition numbers   
+            corresponding to a complex conjugate pair of eigenvalues w(j)   
+            and w(j+1), either SELECT(j) or SELECT(j+1) or both, must be   
+            set to .TRUE..   
+            If HOWMNY = 'A', SELECT is not referenced.   
+
+    N       (input) INTEGER   
+            The order of the matrix T. N >= 0.   
+
+    T       (input) DOUBLE PRECISION array, dimension (LDT,N)   
+            The upper quasi-triangular matrix T, in Schur canonical form.   
+
+    LDT     (input) INTEGER   
+            The leading dimension of the array T. LDT >= max(1,N).   
+
+    VL      (input) DOUBLE PRECISION array, dimension (LDVL,M)   
+            If JOB = 'E' or 'B', VL must contain left eigenvectors of T   
+            (or of any Q*T*Q**T with Q orthogonal), corresponding to the   
+            eigenpairs specified by HOWMNY and SELECT. The eigenvectors   
+            must be stored in consecutive columns of VL, as returned by   
+            DHSEIN or DTREVC.   
+            If JOB = 'V', VL is not referenced.   
+
+    LDVL    (input) INTEGER   
+            The leading dimension of the array VL.   
+            LDVL >= 1; and if JOB = 'E' or 'B', LDVL >= N.   
+
+    VR      (input) DOUBLE PRECISION array, dimension (LDVR,M)   
+            If JOB = 'E' or 'B', VR must contain right eigenvectors of T   
+            (or of any Q*T*Q**T with Q orthogonal), corresponding to the   
+            eigenpairs specified by HOWMNY and SELECT. The eigenvectors   
+            must be stored in consecutive columns of VR, as returned by   
+            DHSEIN or DTREVC.   
+            If JOB = 'V', VR is not referenced.   
+
+    LDVR    (input) INTEGER   
+            The leading dimension of the array VR.   
+            LDVR >= 1; and if JOB = 'E' or 'B', LDVR >= N.   
+
+    S       (output) DOUBLE PRECISION array, dimension (MM)   
+            If JOB = 'E' or 'B', the reciprocal condition numbers of the   
+            selected eigenvalues, stored in consecutive elements of the   
+            array. For a complex conjugate pair of eigenvalues two   
+            consecutive elements of S are set to the same value. Thus   
+            S(j), SEP(j), and the j-th columns of VL and VR all   
+            correspond to the same eigenpair (but not in general the   
+            j-th eigenpair, unless all eigenpairs are selected).   
+            If JOB = 'V', S is not referenced.   
+
+    SEP     (output) DOUBLE PRECISION array, dimension (MM)   
+            If JOB = 'V' or 'B', the estimated reciprocal condition   
+            numbers of the selected eigenvectors, stored in consecutive   
+            elements of the array. For a complex eigenvector two   
+            consecutive elements of SEP are set to the same value. If   
+            the eigenvalues cannot be reordered to compute SEP(j), SEP(j)   
+            is set to 0; this can only occur when the true value would be   
+            very small anyway.   
+            If JOB = 'E', SEP is not referenced.   
+
+    MM      (input) INTEGER   
+            The number of elements in the arrays S (if JOB = 'E' or 'B')   
+             and/or SEP (if JOB = 'V' or 'B'). MM >= M.   
+
+    M       (output) INTEGER   
+            The number of elements of the arrays S and/or SEP actually   
+            used to store the estimated condition numbers.   
+            If HOWMNY = 'A', M is set to N.   
+
+    WORK    (workspace) DOUBLE PRECISION array, dimension (LDWORK,N+6)   
+            If JOB = 'E', WORK is not referenced.   
+
+    LDWORK  (input) INTEGER   
+            The leading dimension of the array WORK.   
+            LDWORK >= 1; and if JOB = 'V' or 'B', LDWORK >= N.   
+
+    IWORK   (workspace) INTEGER array, dimension (2*(N-1))   
+            If JOB = 'E', IWORK is not referenced.   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+
+    Further Details   
+    ===============   
+
+    The reciprocal of the condition number of an eigenvalue lambda is   
+    defined as   
+
+            S(lambda) = |v**T*u| / (norm(u)*norm(v))   
+
+    where u and v are the right and left eigenvectors of T corresponding   
+    to lambda; v**T denotes the transpose of v, and norm(u)   
+    denotes the Euclidean norm. These reciprocal condition numbers always   
+    lie between zero (very badly conditioned) and one (very well   
+    conditioned). If n = 1, S(lambda) is defined to be 1.   
+
+    An approximate error bound for a computed eigenvalue W(i) is given by   
+
+                        EPS * norm(T) / S(i)   
+
+    where EPS is the machine precision.   
+
+    The reciprocal of the condition number of the right eigenvector u   
+    corresponding to lambda is defined as follows. Suppose   
+
+                T = ( lambda  c  )   
+                    (   0    T22 )   
+
+    Then the reciprocal condition number is   
+
+            SEP( lambda, T22 ) = sigma-min( T22 - lambda*I )   
+
+    where sigma-min denotes the smallest singular value. We approximate   
+    the smallest singular value by the reciprocal of an estimate of the   
+    one-norm of the inverse of T22 - lambda*I. If n = 1, SEP(1) is   
+    defined to be abs(T(1,1)).   
+
+    An approximate error bound for a computed right eigenvector VR(i)   
+    is given by   
+
+                        EPS * norm(T) / SEP(i)   
+
+    =====================================================================   
+
+
+       Decode and test the input parameters   
+
+       Parameter adjustments */
+    --select;
+    t_dim1 = *ldt;
+    t_offset = 1 + t_dim1;
+    t -= t_offset;
+    vl_dim1 = *ldvl;
+    vl_offset = 1 + vl_dim1;
+    vl -= vl_offset;
+    vr_dim1 = *ldvr;
+    vr_offset = 1 + vr_dim1;
+    vr -= vr_offset;
+    --s;
+    --sep;
+    work_dim1 = *ldwork;
+    work_offset = 1 + work_dim1;
+    work -= work_offset;
+    --iwork;
+
+    /* Function Body */
+    wantbh = igraphlsame_(job, "B");
+    wants = igraphlsame_(job, "E") || wantbh;
+    wantsp = igraphlsame_(job, "V") || wantbh;
+
+    somcon = igraphlsame_(howmny, "S");
+
+    *info = 0;
+    if (! wants && ! wantsp) {
+	*info = -1;
+    } else if (! igraphlsame_(howmny, "A") && ! somcon) {
+	*info = -2;
+    } else if (*n < 0) {
+	*info = -4;
+    } else if (*ldt < max(1,*n)) {
+	*info = -6;
+    } else if (*ldvl < 1 || wants && *ldvl < *n) {
+	*info = -8;
+    } else if (*ldvr < 1 || wants && *ldvr < *n) {
+	*info = -10;
+    } else {
+
+/*        Set M to the number of eigenpairs for which condition numbers   
+          are required, and test MM. */
+
+	if (somcon) {
+	    *m = 0;
+	    pair = FALSE_;
+	    i__1 = *n;
+	    for (k = 1; k <= i__1; ++k) {
+		if (pair) {
+		    pair = FALSE_;
+		} else {
+		    if (k < *n) {
+			if (t[k + 1 + k * t_dim1] == 0.) {
+			    if (select[k]) {
+				++(*m);
+			    }
+			} else {
+			    pair = TRUE_;
+			    if (select[k] || select[k + 1]) {
+				*m += 2;
+			    }
+			}
+		    } else {
+			if (select[*n]) {
+			    ++(*m);
+			}
+		    }
+		}
+/* L10: */
+	    }
+	} else {
+	    *m = *n;
+	}
+
+	if (*mm < *m) {
+	    *info = -13;
+	} else if (*ldwork < 1 || wantsp && *ldwork < *n) {
+	    *info = -16;
+	}
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DTRSNA", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    if (*n == 0) {
+	return 0;
+    }
+
+    if (*n == 1) {
+	if (somcon) {
+	    if (! select[1]) {
+		return 0;
+	    }
+	}
+	if (wants) {
+	    s[1] = 1.;
+	}
+	if (wantsp) {
+	    sep[1] = (d__1 = t[t_dim1 + 1], abs(d__1));
+	}
+	return 0;
+    }
+
+/*     Get machine constants */
+
+    eps = igraphdlamch_("P");
+    smlnum = igraphdlamch_("S") / eps;
+    bignum = 1. / smlnum;
+    igraphdlabad_(&smlnum, &bignum);
+
+    ks = 0;
+    pair = FALSE_;
+    i__1 = *n;
+    for (k = 1; k <= i__1; ++k) {
+
+/*        Determine whether T(k,k) begins a 1-by-1 or 2-by-2 block. */
+
+	if (pair) {
+	    pair = FALSE_;
+	    goto L60;
+	} else {
+	    if (k < *n) {
+		pair = t[k + 1 + k * t_dim1] != 0.;
+	    }
+	}
+
+/*        Determine whether condition numbers are required for the k-th   
+          eigenpair. */
+
+	if (somcon) {
+	    if (pair) {
+		if (! select[k] && ! select[k + 1]) {
+		    goto L60;
+		}
+	    } else {
+		if (! select[k]) {
+		    goto L60;
+		}
+	    }
+	}
+
+	++ks;
+
+	if (wants) {
+
+/*           Compute the reciprocal condition number of the k-th   
+             eigenvalue. */
+
+	    if (! pair) {
+
+/*              Real eigenvalue. */
+
+		prod = igraphddot_(n, &vr[ks * vr_dim1 + 1], &c__1, &vl[ks * 
+			vl_dim1 + 1], &c__1);
+		rnrm = igraphdnrm2_(n, &vr[ks * vr_dim1 + 1], &c__1);
+		lnrm = igraphdnrm2_(n, &vl[ks * vl_dim1 + 1], &c__1);
+		s[ks] = abs(prod) / (rnrm * lnrm);
+	    } else {
+
+/*              Complex eigenvalue. */
+
+		prod1 = igraphddot_(n, &vr[ks * vr_dim1 + 1], &c__1, &vl[ks * 
+			vl_dim1 + 1], &c__1);
+		prod1 += igraphddot_(n, &vr[(ks + 1) * vr_dim1 + 1], &c__1, &vl[(ks 
+			+ 1) * vl_dim1 + 1], &c__1);
+		prod2 = igraphddot_(n, &vl[ks * vl_dim1 + 1], &c__1, &vr[(ks + 1) * 
+			vr_dim1 + 1], &c__1);
+		prod2 -= igraphddot_(n, &vl[(ks + 1) * vl_dim1 + 1], &c__1, &vr[ks *
+			 vr_dim1 + 1], &c__1);
+		d__1 = igraphdnrm2_(n, &vr[ks * vr_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &vr[(ks + 1) * vr_dim1 + 1], &c__1);
+		rnrm = igraphdlapy2_(&d__1, &d__2);
+		d__1 = igraphdnrm2_(n, &vl[ks * vl_dim1 + 1], &c__1);
+		d__2 = igraphdnrm2_(n, &vl[(ks + 1) * vl_dim1 + 1], &c__1);
+		lnrm = igraphdlapy2_(&d__1, &d__2);
+		cond = igraphdlapy2_(&prod1, &prod2) / (rnrm * lnrm);
+		s[ks] = cond;
+		s[ks + 1] = cond;
+	    }
+	}
+
+	if (wantsp) {
+
+/*           Estimate the reciprocal condition number of the k-th   
+             eigenvector.   
+
+             Copy the matrix T to the array WORK and swap the diagonal   
+             block beginning at T(k,k) to the (1,1) position. */
+
+	    igraphdlacpy_("Full", n, n, &t[t_offset], ldt, &work[work_offset], 
+		    ldwork);
+	    ifst = k;
+	    ilst = 1;
+	    igraphdtrexc_("No Q", n, &work[work_offset], ldwork, dummy, &c__1, &
+		    ifst, &ilst, &work[(*n + 1) * work_dim1 + 1], &ierr);
+
+	    if (ierr == 1 || ierr == 2) {
+
+/*              Could not swap because blocks not well separated */
+
+		scale = 1.;
+		est = bignum;
+	    } else {
+
+/*              Reordering successful */
+
+		if (work[work_dim1 + 2] == 0.) {
+
+/*                 Form C = T22 - lambda*I in WORK(2:N,2:N). */
+
+		    i__2 = *n;
+		    for (i__ = 2; i__ <= i__2; ++i__) {
+			work[i__ + i__ * work_dim1] -= work[work_dim1 + 1];
+/* L20: */
+		    }
+		    n2 = 1;
+		    nn = *n - 1;
+		} else {
+
+/*                 Triangularize the 2 by 2 block by unitary   
+                   transformation U = [  cs   i*ss ]   
+                                      [ i*ss   cs  ].   
+                   such that the (1,1) position of WORK is complex   
+                   eigenvalue lambda with positive imaginary part. (2,2)   
+                   position of WORK is the complex eigenvalue lambda   
+                   with negative imaginary  part. */
+
+		    mu = sqrt((d__1 = work[(work_dim1 << 1) + 1], abs(d__1))) 
+			    * sqrt((d__2 = work[work_dim1 + 2], abs(d__2)));
+		    delta = igraphdlapy2_(&mu, &work[work_dim1 + 2]);
+		    cs = mu / delta;
+		    sn = -work[work_dim1 + 2] / delta;
+
+/*                 Form   
+
+                   C**T = WORK(2:N,2:N) + i*[rwork(1) ..... rwork(n-1) ]   
+                                            [   mu                     ]   
+                                            [         ..               ]   
+                                            [             ..           ]   
+                                            [                  mu      ]   
+                   where C**T is transpose of matrix C,   
+                   and RWORK is stored starting in the N+1-st column of   
+                   WORK. */
+
+		    i__2 = *n;
+		    for (j = 3; j <= i__2; ++j) {
+			work[j * work_dim1 + 2] = cs * work[j * work_dim1 + 2]
+				;
+			work[j + j * work_dim1] -= work[work_dim1 + 1];
+/* L30: */
+		    }
+		    work[(work_dim1 << 1) + 2] = 0.;
+
+		    work[(*n + 1) * work_dim1 + 1] = mu * 2.;
+		    i__2 = *n - 1;
+		    for (i__ = 2; i__ <= i__2; ++i__) {
+			work[i__ + (*n + 1) * work_dim1] = sn * work[(i__ + 1)
+				 * work_dim1 + 1];
+/* L40: */
+		    }
+		    n2 = 2;
+		    nn = *n - 1 << 1;
+		}
+
+/*              Estimate norm(inv(C**T)) */
+
+		est = 0.;
+		kase = 0;
+L50:
+		igraphdlacn2_(&nn, &work[(*n + 2) * work_dim1 + 1], &work[(*n + 4) *
+			 work_dim1 + 1], &iwork[1], &est, &kase, isave);
+		if (kase != 0) {
+		    if (kase == 1) {
+			if (n2 == 1) {
+
+/*                       Real eigenvalue: solve C**T*x = scale*c. */
+
+			    i__2 = *n - 1;
+			    igraphdlaqtr_(&c_true, &c_true, &i__2, &work[(work_dim1 
+				    << 1) + 2], ldwork, dummy, &dumm, &scale, 
+				    &work[(*n + 4) * work_dim1 + 1], &work[(*
+				    n + 6) * work_dim1 + 1], &ierr);
+			} else {
+
+/*                       Complex eigenvalue: solve   
+                         C**T*(p+iq) = scale*(c+id) in real arithmetic. */
+
+			    i__2 = *n - 1;
+			    igraphdlaqtr_(&c_true, &c_false, &i__2, &work[(
+				    work_dim1 << 1) + 2], ldwork, &work[(*n + 
+				    1) * work_dim1 + 1], &mu, &scale, &work[(*
+				    n + 4) * work_dim1 + 1], &work[(*n + 6) * 
+				    work_dim1 + 1], &ierr);
+			}
+		    } else {
+			if (n2 == 1) {
+
+/*                       Real eigenvalue: solve C*x = scale*c. */
+
+			    i__2 = *n - 1;
+			    igraphdlaqtr_(&c_false, &c_true, &i__2, &work[(
+				    work_dim1 << 1) + 2], ldwork, dummy, &
+				    dumm, &scale, &work[(*n + 4) * work_dim1 
+				    + 1], &work[(*n + 6) * work_dim1 + 1], &
+				    ierr);
+			} else {
+
+/*                       Complex eigenvalue: solve   
+                         C*(p+iq) = scale*(c+id) in real arithmetic. */
+
+			    i__2 = *n - 1;
+			    igraphdlaqtr_(&c_false, &c_false, &i__2, &work[(
+				    work_dim1 << 1) + 2], ldwork, &work[(*n + 
+				    1) * work_dim1 + 1], &mu, &scale, &work[(*
+				    n + 4) * work_dim1 + 1], &work[(*n + 6) * 
+				    work_dim1 + 1], &ierr);
+
+			}
+		    }
+
+		    goto L50;
+		}
+	    }
+
+	    sep[ks] = scale / max(est,smlnum);
+	    if (pair) {
+		sep[ks + 1] = sep[ks];
+	    }
+	}
+
+	if (pair) {
+	    ++ks;
+	}
+
+L60:
+	;
+    }
+    return 0;
+
+/*     End of DTRSNA */
+
+} /* igraphdtrsna_ */
+
diff --git a/src/lapack/dtrsyl.c b/src/lapack/dtrsyl.c
new file mode 100644
index 0000000..475aaa1
--- /dev/null
+++ b/src/lapack/dtrsyl.c
@@ -0,0 +1,1302 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static logical c_false = FALSE_;
+static integer c__2 = 2;
+static doublereal c_b26 = 1.;
+static doublereal c_b30 = 0.;
+static logical c_true = TRUE_;
+
+/* Subroutine */ int igraphdtrsyl_(char *trana, char *tranb, integer *isgn, integer 
+	*m, integer *n, doublereal *a, integer *lda, doublereal *b, integer *
+	ldb, doublereal *c__, integer *ldc, doublereal *scale, integer *info)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, 
+	    i__3, i__4;
+    doublereal d__1, d__2;
+
+    /* Local variables */
+    integer j, k, l;
+    doublereal x[4]	/* was [2][2] */;
+    integer k1, k2, l1, l2;
+    doublereal a11, db, da11, vec[4]	/* was [2][2] */, dum[1], eps, sgn;
+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
+	    integer *);
+    integer ierr;
+    doublereal smin, suml, sumr;
+    extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, 
+	    integer *);
+    extern logical igraphlsame_(char *, char *);
+    integer knext, lnext;
+    doublereal xnorm;
+    extern /* Subroutine */ int igraphdlaln2_(logical *, integer *, integer *, 
+	    doublereal *, doublereal *, doublereal *, integer *, doublereal *,
+	     doublereal *, doublereal *, integer *, doublereal *, doublereal *
+	    , doublereal *, integer *, doublereal *, doublereal *, integer *),
+	     igraphdlasy2_(logical *, logical *, integer *, integer *, integer *, 
+	    doublereal *, integer *, doublereal *, integer *, doublereal *, 
+	    integer *, doublereal *, doublereal *, integer *, doublereal *, 
+	    integer *), igraphdlabad_(doublereal *, doublereal *);
+    extern doublereal igraphdlamch_(char *), igraphdlange_(char *, integer *, 
+	    integer *, doublereal *, integer *, doublereal *);
+    doublereal scaloc;
+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);
+    doublereal bignum;
+    logical notrna, notrnb;
+    doublereal smlnum;
+
+
+/*  -- LAPACK routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    DTRSYL solves the real Sylvester matrix equation:   
+
+       op(A)*X + X*op(B) = scale*C or   
+       op(A)*X - X*op(B) = scale*C,   
+
+    where op(A) = A or A**T, and  A and B are both upper quasi-   
+    triangular. A is M-by-M and B is N-by-N; the right hand side C and   
+    the solution X are M-by-N; and scale is an output scale factor, set   
+    <= 1 to avoid overflow in X.   
+
+    A and B must be in Schur canonical form (as returned by DHSEQR), that   
+    is, block upper triangular with 1-by-1 and 2-by-2 diagonal blocks;   
+    each 2-by-2 diagonal block has its diagonal elements equal and its   
+    off-diagonal elements of opposite sign.   
+
+    Arguments   
+    =========   
+
+    TRANA   (input) CHARACTER*1   
+            Specifies the option op(A):   
+            = 'N': op(A) = A    (No transpose)   
+            = 'T': op(A) = A**T (Transpose)   
+            = 'C': op(A) = A**H (Conjugate transpose = Transpose)   
+
+    TRANB   (input) CHARACTER*1   
+            Specifies the option op(B):   
+            = 'N': op(B) = B    (No transpose)   
+            = 'T': op(B) = B**T (Transpose)   
+            = 'C': op(B) = B**H (Conjugate transpose = Transpose)   
+
+    ISGN    (input) INTEGER   
+            Specifies the sign in the equation:   
+            = +1: solve op(A)*X + X*op(B) = scale*C   
+            = -1: solve op(A)*X - X*op(B) = scale*C   
+
+    M       (input) INTEGER   
+            The order of the matrix A, and the number of rows in the   
+            matrices X and C. M >= 0.   
+
+    N       (input) INTEGER   
+            The order of the matrix B, and the number of columns in the   
+            matrices X and C. N >= 0.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,M)   
+            The upper quasi-triangular matrix A, in Schur canonical form.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A. LDA >= max(1,M).   
+
+    B       (input) DOUBLE PRECISION array, dimension (LDB,N)   
+            The upper quasi-triangular matrix B, in Schur canonical form.   
+
+    LDB     (input) INTEGER   
+            The leading dimension of the array B. LDB >= max(1,N).   
+
+    C       (input/output) DOUBLE PRECISION array, dimension (LDC,N)   
+            On entry, the M-by-N right hand side matrix C.   
+            On exit, C is overwritten by the solution matrix X.   
+
+    LDC     (input) INTEGER   
+            The leading dimension of the array C. LDC >= max(1,M)   
+
+    SCALE   (output) DOUBLE PRECISION   
+            The scale factor, scale, set <= 1 to avoid overflow in X.   
+
+    INFO    (output) INTEGER   
+            = 0: successful exit   
+            < 0: if INFO = -i, the i-th argument had an illegal value   
+            = 1: A and B have common or very close eigenvalues; perturbed   
+                 values were used to solve the equation (but the matrices   
+                 A and B are unchanged).   
+
+    =====================================================================   
+
+
+       Decode and Test input parameters   
+
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    b_dim1 = *ldb;
+    b_offset = 1 + b_dim1;
+    b -= b_offset;
+    c_dim1 = *ldc;
+    c_offset = 1 + c_dim1;
+    c__ -= c_offset;
+
+    /* Function Body */
+    notrna = igraphlsame_(trana, "N");
+    notrnb = igraphlsame_(tranb, "N");
+
+    *info = 0;
+    if (! notrna && ! igraphlsame_(trana, "T") && ! igraphlsame_(
+	    trana, "C")) {
+	*info = -1;
+    } else if (! notrnb && ! igraphlsame_(tranb, "T") && ! 
+	    igraphlsame_(tranb, "C")) {
+	*info = -2;
+    } else if (*isgn != 1 && *isgn != -1) {
+	*info = -3;
+    } else if (*m < 0) {
+	*info = -4;
+    } else if (*n < 0) {
+	*info = -5;
+    } else if (*lda < max(1,*m)) {
+	*info = -7;
+    } else if (*ldb < max(1,*n)) {
+	*info = -9;
+    } else if (*ldc < max(1,*m)) {
+	*info = -11;
+    }
+    if (*info != 0) {
+	i__1 = -(*info);
+	igraphxerbla_("DTRSYL", &i__1, (ftnlen)6);
+	return 0;
+    }
+
+/*     Quick return if possible */
+
+    *scale = 1.;
+    if (*m == 0 || *n == 0) {
+	return 0;
+    }
+
+/*     Set constants to control overflow */
+
+    eps = igraphdlamch_("P");
+    smlnum = igraphdlamch_("S");
+    bignum = 1. / smlnum;
+    igraphdlabad_(&smlnum, &bignum);
+    smlnum = smlnum * (doublereal) (*m * *n) / eps;
+    bignum = 1. / smlnum;
+
+/* Computing MAX */
+    d__1 = smlnum, d__2 = eps * igraphdlange_("M", m, m, &a[a_offset], lda, dum), d__1 = max(d__1,d__2), d__2 = eps * igraphdlange_("M", n, n, 
+	    &b[b_offset], ldb, dum);
+    smin = max(d__1,d__2);
+
+    sgn = (doublereal) (*isgn);
+
+    if (notrna && notrnb) {
+
+/*        Solve    A*X + ISGN*X*B = scale*C.   
+
+          The (K,L)th block of X is determined starting from   
+          bottom-left corner column by column by   
+
+           A(K,K)*X(K,L) + ISGN*X(K,L)*B(L,L) = C(K,L) - R(K,L)   
+
+          Where   
+                    M                         L-1   
+          R(K,L) = SUM [A(K,I)*X(I,L)] + ISGN*SUM [X(K,J)*B(J,L)].   
+                  I=K+1                       J=1   
+
+          Start column loop (index = L)   
+          L1 (L2) : column index of the first (first) row of X(K,L). */
+
+	lnext = 1;
+	i__1 = *n;
+	for (l = 1; l <= i__1; ++l) {
+	    if (l < lnext) {
+		goto L60;
+	    }
+	    if (l == *n) {
+		l1 = l;
+		l2 = l;
+	    } else {
+		if (b[l + 1 + l * b_dim1] != 0.) {
+		    l1 = l;
+		    l2 = l + 1;
+		    lnext = l + 2;
+		} else {
+		    l1 = l;
+		    l2 = l;
+		    lnext = l + 1;
+		}
+	    }
+
+/*           Start row loop (index = K)   
+             K1 (K2): row index of the first (last) row of X(K,L). */
+
+	    knext = *m;
+	    for (k = *m; k >= 1; --k) {
+		if (k > knext) {
+		    goto L50;
+		}
+		if (k == 1) {
+		    k1 = k;
+		    k2 = k;
+		} else {
+		    if (a[k + (k - 1) * a_dim1] != 0.) {
+			k1 = k - 1;
+			k2 = k;
+			knext = k - 2;
+		    } else {
+			k1 = k;
+			k2 = k;
+			knext = k - 1;
+		    }
+		}
+
+		if (l1 == l2 && k1 == k2) {
+		    i__2 = *m - k1;
+/* Computing MIN */
+		    i__3 = k1 + 1;
+/* Computing MIN */
+		    i__4 = k1 + 1;
+		    suml = igraphddot_(&i__2, &a[k1 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l1 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+		    scaloc = 1.;
+
+		    a11 = a[k1 + k1 * a_dim1] + sgn * b[l1 + l1 * b_dim1];
+		    da11 = abs(a11);
+		    if (da11 <= smin) {
+			a11 = smin;
+			da11 = smin;
+			*info = 1;
+		    }
+		    db = abs(vec[0]);
+		    if (da11 < 1. && db > 1.) {
+			if (db > bignum * da11) {
+			    scaloc = 1. / db;
+			}
+		    }
+		    x[0] = vec[0] * scaloc / a11;
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L10: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+
+		} else if (l1 == l2 && k1 != k2) {
+
+		    i__2 = *m - k2;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+/* Computing MIN */
+		    i__4 = k2 + 1;
+		    suml = igraphddot_(&i__2, &a[k1 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l1 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = *m - k2;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+/* Computing MIN */
+		    i__4 = k2 + 1;
+		    suml = igraphddot_(&i__2, &a[k2 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l1 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k2 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    d__1 = -sgn * b[l1 + l1 * b_dim1];
+		    igraphdlaln2_(&c_false, &c__2, &c__1, &smin, &c_b26, &a[k1 + k1 
+			    * a_dim1], lda, &c_b26, &c_b26, vec, &c__2, &d__1,
+			     &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L20: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k2 + l1 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 == k2) {
+
+		    i__2 = *m - k1;
+/* Computing MIN */
+		    i__3 = k1 + 1;
+/* Computing MIN */
+		    i__4 = k1 + 1;
+		    suml = igraphddot_(&i__2, &a[k1 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l1 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = sgn * (c__[k1 + l1 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    i__2 = *m - k1;
+/* Computing MIN */
+		    i__3 = k1 + 1;
+/* Computing MIN */
+		    i__4 = k1 + 1;
+		    suml = igraphddot_(&i__2, &a[k1 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l2 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + c_dim1], ldc, &b[l2 * 
+			    b_dim1 + 1], &c__1);
+		    vec[1] = sgn * (c__[k1 + l2 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    d__1 = -sgn * a[k1 + k1 * a_dim1];
+		    igraphdlaln2_(&c_true, &c__2, &c__1, &smin, &c_b26, &b[l1 + l1 *
+			     b_dim1], ldb, &c_b26, &c_b26, vec, &c__2, &d__1, 
+			    &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L30: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 != k2) {
+
+		    i__2 = *m - k2;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+/* Computing MIN */
+		    i__4 = k2 + 1;
+		    suml = igraphddot_(&i__2, &a[k1 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l1 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = *m - k2;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+/* Computing MIN */
+		    i__4 = k2 + 1;
+		    suml = igraphddot_(&i__2, &a[k1 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l2 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + c_dim1], ldc, &b[l2 * 
+			    b_dim1 + 1], &c__1);
+		    vec[2] = c__[k1 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = *m - k2;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+/* Computing MIN */
+		    i__4 = k2 + 1;
+		    suml = igraphddot_(&i__2, &a[k2 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l1 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k2 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = *m - k2;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+/* Computing MIN */
+		    i__4 = k2 + 1;
+		    suml = igraphddot_(&i__2, &a[k2 + min(i__3,*m) * a_dim1], lda, &
+			    c__[min(i__4,*m) + l2 * c_dim1], &c__1);
+		    i__2 = l1 - 1;
+		    sumr = igraphddot_(&i__2, &c__[k2 + c_dim1], ldc, &b[l2 * 
+			    b_dim1 + 1], &c__1);
+		    vec[3] = c__[k2 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    igraphdlasy2_(&c_false, &c_false, isgn, &c__2, &c__2, &a[k1 + 
+			    k1 * a_dim1], lda, &b[l1 + l1 * b_dim1], ldb, vec,
+			     &c__2, &scaloc, x, &c__2, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L40: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[2];
+		    c__[k2 + l1 * c_dim1] = x[1];
+		    c__[k2 + l2 * c_dim1] = x[3];
+		}
+
+L50:
+		;
+	    }
+
+L60:
+	    ;
+	}
+
+    } else if (! notrna && notrnb) {
+
+/*        Solve    A**T *X + ISGN*X*B = scale*C.   
+
+          The (K,L)th block of X is determined starting from   
+          upper-left corner column by column by   
+
+            A(K,K)**T*X(K,L) + ISGN*X(K,L)*B(L,L) = C(K,L) - R(K,L)   
+
+          Where   
+                     K-1                          L-1   
+            R(K,L) = SUM [A(I,K)**T*X(I,L)] +ISGN*SUM [X(K,J)*B(J,L)]   
+                     I=1                          J=1   
+
+          Start column loop (index = L)   
+          L1 (L2): column index of the first (last) row of X(K,L) */
+
+	lnext = 1;
+	i__1 = *n;
+	for (l = 1; l <= i__1; ++l) {
+	    if (l < lnext) {
+		goto L120;
+	    }
+	    if (l == *n) {
+		l1 = l;
+		l2 = l;
+	    } else {
+		if (b[l + 1 + l * b_dim1] != 0.) {
+		    l1 = l;
+		    l2 = l + 1;
+		    lnext = l + 2;
+		} else {
+		    l1 = l;
+		    l2 = l;
+		    lnext = l + 1;
+		}
+	    }
+
+/*           Start row loop (index = K)   
+             K1 (K2): row index of the first (last) row of X(K,L) */
+
+	    knext = 1;
+	    i__2 = *m;
+	    for (k = 1; k <= i__2; ++k) {
+		if (k < knext) {
+		    goto L110;
+		}
+		if (k == *m) {
+		    k1 = k;
+		    k2 = k;
+		} else {
+		    if (a[k + 1 + k * a_dim1] != 0.) {
+			k1 = k;
+			k2 = k + 1;
+			knext = k + 2;
+		    } else {
+			k1 = k;
+			k2 = k;
+			knext = k + 1;
+		    }
+		}
+
+		if (l1 == l2 && k1 == k2) {
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+		    scaloc = 1.;
+
+		    a11 = a[k1 + k1 * a_dim1] + sgn * b[l1 + l1 * b_dim1];
+		    da11 = abs(a11);
+		    if (da11 <= smin) {
+			a11 = smin;
+			da11 = smin;
+			*info = 1;
+		    }
+		    db = abs(vec[0]);
+		    if (da11 < 1. && db > 1.) {
+			if (db > bignum * da11) {
+			    scaloc = 1. / db;
+			}
+		    }
+		    x[0] = vec[0] * scaloc / a11;
+
+		    if (scaloc != 1.) {
+			i__3 = *n;
+			for (j = 1; j <= i__3; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L70: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+
+		} else if (l1 == l2 && k1 != k2) {
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k2 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k2 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    d__1 = -sgn * b[l1 + l1 * b_dim1];
+		    igraphdlaln2_(&c_true, &c__2, &c__1, &smin, &c_b26, &a[k1 + k1 *
+			     a_dim1], lda, &c_b26, &c_b26, vec, &c__2, &d__1, 
+			    &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__3 = *n;
+			for (j = 1; j <= i__3; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L80: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k2 + l1 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 == k2) {
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = sgn * (c__[k1 + l1 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k1 * a_dim1 + 1], &c__1, &c__[l2 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k1 + c_dim1], ldc, &b[l2 * 
+			    b_dim1 + 1], &c__1);
+		    vec[1] = sgn * (c__[k1 + l2 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    d__1 = -sgn * a[k1 + k1 * a_dim1];
+		    igraphdlaln2_(&c_true, &c__2, &c__1, &smin, &c_b26, &b[l1 + l1 *
+			     b_dim1], ldb, &c_b26, &c_b26, vec, &c__2, &d__1, 
+			    &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__3 = *n;
+			for (j = 1; j <= i__3; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L90: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 != k2) {
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k1 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k1 * a_dim1 + 1], &c__1, &c__[l2 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k1 + c_dim1], ldc, &b[l2 * 
+			    b_dim1 + 1], &c__1);
+		    vec[2] = c__[k1 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k2 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k2 + c_dim1], ldc, &b[l1 * 
+			    b_dim1 + 1], &c__1);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__3 = k1 - 1;
+		    suml = igraphddot_(&i__3, &a[k2 * a_dim1 + 1], &c__1, &c__[l2 * 
+			    c_dim1 + 1], &c__1);
+		    i__3 = l1 - 1;
+		    sumr = igraphddot_(&i__3, &c__[k2 + c_dim1], ldc, &b[l2 * 
+			    b_dim1 + 1], &c__1);
+		    vec[3] = c__[k2 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    igraphdlasy2_(&c_true, &c_false, isgn, &c__2, &c__2, &a[k1 + k1 
+			    * a_dim1], lda, &b[l1 + l1 * b_dim1], ldb, vec, &
+			    c__2, &scaloc, x, &c__2, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__3 = *n;
+			for (j = 1; j <= i__3; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L100: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[2];
+		    c__[k2 + l1 * c_dim1] = x[1];
+		    c__[k2 + l2 * c_dim1] = x[3];
+		}
+
+L110:
+		;
+	    }
+L120:
+	    ;
+	}
+
+    } else if (! notrna && ! notrnb) {
+
+/*        Solve    A**T*X + ISGN*X*B**T = scale*C.   
+
+          The (K,L)th block of X is determined starting from   
+          top-right corner column by column by   
+
+             A(K,K)**T*X(K,L) + ISGN*X(K,L)*B(L,L)**T = C(K,L) - R(K,L)   
+
+          Where   
+                       K-1                            N   
+              R(K,L) = SUM [A(I,K)**T*X(I,L)] + ISGN*SUM [X(K,J)*B(L,J)**T].   
+                       I=1                          J=L+1   
+
+          Start column loop (index = L)   
+          L1 (L2): column index of the first (last) row of X(K,L) */
+
+	lnext = *n;
+	for (l = *n; l >= 1; --l) {
+	    if (l > lnext) {
+		goto L180;
+	    }
+	    if (l == 1) {
+		l1 = l;
+		l2 = l;
+	    } else {
+		if (b[l + (l - 1) * b_dim1] != 0.) {
+		    l1 = l - 1;
+		    l2 = l;
+		    lnext = l - 2;
+		} else {
+		    l1 = l;
+		    l2 = l;
+		    lnext = l - 1;
+		}
+	    }
+
+/*           Start row loop (index = K)   
+             K1 (K2): row index of the first (last) row of X(K,L) */
+
+	    knext = 1;
+	    i__1 = *m;
+	    for (k = 1; k <= i__1; ++k) {
+		if (k < knext) {
+		    goto L170;
+		}
+		if (k == *m) {
+		    k1 = k;
+		    k2 = k;
+		} else {
+		    if (a[k + 1 + k * a_dim1] != 0.) {
+			k1 = k;
+			k2 = k + 1;
+			knext = k + 2;
+		    } else {
+			k1 = k;
+			k2 = k;
+			knext = k + 1;
+		    }
+		}
+
+		if (l1 == l2 && k1 == k2) {
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l1;
+/* Computing MIN */
+		    i__3 = l1 + 1;
+/* Computing MIN */
+		    i__4 = l1 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__4,*n) * b_dim1], ldb);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+		    scaloc = 1.;
+
+		    a11 = a[k1 + k1 * a_dim1] + sgn * b[l1 + l1 * b_dim1];
+		    da11 = abs(a11);
+		    if (da11 <= smin) {
+			a11 = smin;
+			da11 = smin;
+			*info = 1;
+		    }
+		    db = abs(vec[0]);
+		    if (da11 < 1. && db > 1.) {
+			if (db > bignum * da11) {
+			    scaloc = 1. / db;
+			}
+		    }
+		    x[0] = vec[0] * scaloc / a11;
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L130: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+
+		} else if (l1 == l2 && k1 != k2) {
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__4,*n) * b_dim1], ldb);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k2 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k2 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__4,*n) * b_dim1], ldb);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    d__1 = -sgn * b[l1 + l1 * b_dim1];
+		    igraphdlaln2_(&c_true, &c__2, &c__1, &smin, &c_b26, &a[k1 + k1 *
+			     a_dim1], lda, &c_b26, &c_b26, vec, &c__2, &d__1, 
+			    &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L140: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k2 + l1 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 == k2) {
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__4,*n) * b_dim1], ldb);
+		    vec[0] = sgn * (c__[k1 + l1 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k1 * a_dim1 + 1], &c__1, &c__[l2 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l2 + min(i__4,*n) * b_dim1], ldb);
+		    vec[1] = sgn * (c__[k1 + l2 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    d__1 = -sgn * a[k1 + k1 * a_dim1];
+		    igraphdlaln2_(&c_false, &c__2, &c__1, &smin, &c_b26, &b[l1 + l1 
+			    * b_dim1], ldb, &c_b26, &c_b26, vec, &c__2, &d__1,
+			     &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L150: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 != k2) {
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k1 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__4,*n) * b_dim1], ldb);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k1 * a_dim1 + 1], &c__1, &c__[l2 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k1 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l2 + min(i__4,*n) * b_dim1], ldb);
+		    vec[2] = c__[k1 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k2 * a_dim1 + 1], &c__1, &c__[l1 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k2 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__4,*n) * b_dim1], ldb);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__2 = k1 - 1;
+		    suml = igraphddot_(&i__2, &a[k2 * a_dim1 + 1], &c__1, &c__[l2 * 
+			    c_dim1 + 1], &c__1);
+		    i__2 = *n - l2;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+/* Computing MIN */
+		    i__4 = l2 + 1;
+		    sumr = igraphddot_(&i__2, &c__[k2 + min(i__3,*n) * c_dim1], ldc,
+			     &b[l2 + min(i__4,*n) * b_dim1], ldb);
+		    vec[3] = c__[k2 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    igraphdlasy2_(&c_true, &c_true, isgn, &c__2, &c__2, &a[k1 + k1 *
+			     a_dim1], lda, &b[l1 + l1 * b_dim1], ldb, vec, &
+			    c__2, &scaloc, x, &c__2, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__2 = *n;
+			for (j = 1; j <= i__2; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L160: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[2];
+		    c__[k2 + l1 * c_dim1] = x[1];
+		    c__[k2 + l2 * c_dim1] = x[3];
+		}
+
+L170:
+		;
+	    }
+L180:
+	    ;
+	}
+
+    } else if (notrna && ! notrnb) {
+
+/*        Solve    A*X + ISGN*X*B**T = scale*C.   
+
+          The (K,L)th block of X is determined starting from   
+          bottom-right corner column by column by   
+
+              A(K,K)*X(K,L) + ISGN*X(K,L)*B(L,L)**T = C(K,L) - R(K,L)   
+
+          Where   
+                        M                          N   
+              R(K,L) = SUM [A(K,I)*X(I,L)] + ISGN*SUM [X(K,J)*B(L,J)**T].   
+                      I=K+1                      J=L+1   
+
+          Start column loop (index = L)   
+          L1 (L2): column index of the first (last) row of X(K,L) */
+
+	lnext = *n;
+	for (l = *n; l >= 1; --l) {
+	    if (l > lnext) {
+		goto L240;
+	    }
+	    if (l == 1) {
+		l1 = l;
+		l2 = l;
+	    } else {
+		if (b[l + (l - 1) * b_dim1] != 0.) {
+		    l1 = l - 1;
+		    l2 = l;
+		    lnext = l - 2;
+		} else {
+		    l1 = l;
+		    l2 = l;
+		    lnext = l - 1;
+		}
+	    }
+
+/*           Start row loop (index = K)   
+             K1 (K2): row index of the first (last) row of X(K,L) */
+
+	    knext = *m;
+	    for (k = *m; k >= 1; --k) {
+		if (k > knext) {
+		    goto L230;
+		}
+		if (k == 1) {
+		    k1 = k;
+		    k2 = k;
+		} else {
+		    if (a[k + (k - 1) * a_dim1] != 0.) {
+			k1 = k - 1;
+			k2 = k;
+			knext = k - 2;
+		    } else {
+			k1 = k;
+			k2 = k;
+			knext = k - 1;
+		    }
+		}
+
+		if (l1 == l2 && k1 == k2) {
+		    i__1 = *m - k1;
+/* Computing MIN */
+		    i__2 = k1 + 1;
+/* Computing MIN */
+		    i__3 = k1 + 1;
+		    suml = igraphddot_(&i__1, &a[k1 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l1 * c_dim1], &c__1);
+		    i__1 = *n - l1;
+/* Computing MIN */
+		    i__2 = l1 + 1;
+/* Computing MIN */
+		    i__3 = l1 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k1 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__3,*n) * b_dim1], ldb);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+		    scaloc = 1.;
+
+		    a11 = a[k1 + k1 * a_dim1] + sgn * b[l1 + l1 * b_dim1];
+		    da11 = abs(a11);
+		    if (da11 <= smin) {
+			a11 = smin;
+			da11 = smin;
+			*info = 1;
+		    }
+		    db = abs(vec[0]);
+		    if (da11 < 1. && db > 1.) {
+			if (db > bignum * da11) {
+			    scaloc = 1. / db;
+			}
+		    }
+		    x[0] = vec[0] * scaloc / a11;
+
+		    if (scaloc != 1.) {
+			i__1 = *n;
+			for (j = 1; j <= i__1; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L190: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+
+		} else if (l1 == l2 && k1 != k2) {
+
+		    i__1 = *m - k2;
+/* Computing MIN */
+		    i__2 = k2 + 1;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+		    suml = igraphddot_(&i__1, &a[k1 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l1 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k1 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__3,*n) * b_dim1], ldb);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__1 = *m - k2;
+/* Computing MIN */
+		    i__2 = k2 + 1;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+		    suml = igraphddot_(&i__1, &a[k2 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l1 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k2 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__3,*n) * b_dim1], ldb);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    d__1 = -sgn * b[l1 + l1 * b_dim1];
+		    igraphdlaln2_(&c_false, &c__2, &c__1, &smin, &c_b26, &a[k1 + k1 
+			    * a_dim1], lda, &c_b26, &c_b26, vec, &c__2, &d__1,
+			     &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__1 = *n;
+			for (j = 1; j <= i__1; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L200: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k2 + l1 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 == k2) {
+
+		    i__1 = *m - k1;
+/* Computing MIN */
+		    i__2 = k1 + 1;
+/* Computing MIN */
+		    i__3 = k1 + 1;
+		    suml = igraphddot_(&i__1, &a[k1 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l1 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k1 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__3,*n) * b_dim1], ldb);
+		    vec[0] = sgn * (c__[k1 + l1 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    i__1 = *m - k1;
+/* Computing MIN */
+		    i__2 = k1 + 1;
+/* Computing MIN */
+		    i__3 = k1 + 1;
+		    suml = igraphddot_(&i__1, &a[k1 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l2 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k1 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l2 + min(i__3,*n) * b_dim1], ldb);
+		    vec[1] = sgn * (c__[k1 + l2 * c_dim1] - (suml + sgn * 
+			    sumr));
+
+		    d__1 = -sgn * a[k1 + k1 * a_dim1];
+		    igraphdlaln2_(&c_false, &c__2, &c__1, &smin, &c_b26, &b[l1 + l1 
+			    * b_dim1], ldb, &c_b26, &c_b26, vec, &c__2, &d__1,
+			     &c_b30, x, &c__2, &scaloc, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__1 = *n;
+			for (j = 1; j <= i__1; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L210: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[1];
+
+		} else if (l1 != l2 && k1 != k2) {
+
+		    i__1 = *m - k2;
+/* Computing MIN */
+		    i__2 = k2 + 1;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+		    suml = igraphddot_(&i__1, &a[k1 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l1 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k1 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__3,*n) * b_dim1], ldb);
+		    vec[0] = c__[k1 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__1 = *m - k2;
+/* Computing MIN */
+		    i__2 = k2 + 1;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+		    suml = igraphddot_(&i__1, &a[k1 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l2 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k1 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l2 + min(i__3,*n) * b_dim1], ldb);
+		    vec[2] = c__[k1 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    i__1 = *m - k2;
+/* Computing MIN */
+		    i__2 = k2 + 1;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+		    suml = igraphddot_(&i__1, &a[k2 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l1 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k2 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l1 + min(i__3,*n) * b_dim1], ldb);
+		    vec[1] = c__[k2 + l1 * c_dim1] - (suml + sgn * sumr);
+
+		    i__1 = *m - k2;
+/* Computing MIN */
+		    i__2 = k2 + 1;
+/* Computing MIN */
+		    i__3 = k2 + 1;
+		    suml = igraphddot_(&i__1, &a[k2 + min(i__2,*m) * a_dim1], lda, &
+			    c__[min(i__3,*m) + l2 * c_dim1], &c__1);
+		    i__1 = *n - l2;
+/* Computing MIN */
+		    i__2 = l2 + 1;
+/* Computing MIN */
+		    i__3 = l2 + 1;
+		    sumr = igraphddot_(&i__1, &c__[k2 + min(i__2,*n) * c_dim1], ldc,
+			     &b[l2 + min(i__3,*n) * b_dim1], ldb);
+		    vec[3] = c__[k2 + l2 * c_dim1] - (suml + sgn * sumr);
+
+		    igraphdlasy2_(&c_false, &c_true, isgn, &c__2, &c__2, &a[k1 + k1 
+			    * a_dim1], lda, &b[l1 + l1 * b_dim1], ldb, vec, &
+			    c__2, &scaloc, x, &c__2, &xnorm, &ierr);
+		    if (ierr != 0) {
+			*info = 1;
+		    }
+
+		    if (scaloc != 1.) {
+			i__1 = *n;
+			for (j = 1; j <= i__1; ++j) {
+			    igraphdscal_(m, &scaloc, &c__[j * c_dim1 + 1], &c__1);
+/* L220: */
+			}
+			*scale *= scaloc;
+		    }
+		    c__[k1 + l1 * c_dim1] = x[0];
+		    c__[k1 + l2 * c_dim1] = x[2];
+		    c__[k2 + l1 * c_dim1] = x[1];
+		    c__[k2 + l2 * c_dim1] = x[3];
+		}
+
+L230:
+		;
+	    }
+L240:
+	    ;
+	}
+
+    }
+
+    return 0;
+
+/*     End of DTRSYL */
+
+} /* igraphdtrsyl_ */
+
diff --git a/src/lapack/dvout.c b/src/lapack/dvout.c
new file mode 100644
index 0000000..2a88442
--- /dev/null
+++ b/src/lapack/dvout.c
@@ -0,0 +1,277 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+    Routine:    DVOUT   
+
+    Purpose:    Real vector output routine.   
+
+    Usage:      CALL DVOUT (LOUT, N, SX, IDIGIT, IFMT)   
+
+    Arguments   
+       N      - Length of array SX.  (Input)   
+       SX     - Real array to be printed.  (Input)   
+       IFMT   - Format to be used in printing array SX.  (Input)   
+       IDIGIT - Print up to IABS(IDIGIT) decimal digits per number.  (In)   
+                If IDIGIT .LT. 0, printing is done with 72 columns.   
+                If IDIGIT .GT. 0, printing is done with 132 columns.   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphdvout_(integer *lout, integer *n, doublereal *sx, 
+	integer *idigit, char *ifmt, ftnlen ifmt_len)
+{
+
+    /* Format strings */
+    static char fmt_9999[] = "(/1x,a,/1x,a)";
+    static char fmt_9998[] = "(1x,i4,\002 - \002,i4,\002:\002,1p,10d12.3)";
+    static char fmt_9997[] = "(1x,i4,\002 - \002,i4,\002:\002,1x,1p,8d14.5)";
+    static char fmt_9996[] = "(1x,i4,\002 - \002,i4,\002:\002,1x,1p,6d18.9)";
+    static char fmt_9995[] = "(1x,i4,\002 - \002,i4,\002:\002,1x,1p,5d24.13)";
+    static char fmt_9994[] = "(1x,\002 \002)";
+
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+
+    /* Builtin functions */
+    integer i_len(char *, ftnlen), s_wsfe(cilist *), do_fio(integer *, char *,
+	     ftnlen), e_wsfe(void);
+
+    /* Local variables */
+    integer i__, k1, k2, lll;
+    char line[80];
+    integer ndigit;
+
+    /* Fortran I/O blocks */
+    static cilist io___4 = { 0, 0, 0, fmt_9999, 0 };
+    static cilist io___8 = { 0, 0, 0, fmt_9998, 0 };
+    static cilist io___9 = { 0, 0, 0, fmt_9997, 0 };
+    static cilist io___10 = { 0, 0, 0, fmt_9996, 0 };
+    static cilist io___11 = { 0, 0, 0, fmt_9995, 0 };
+    static cilist io___12 = { 0, 0, 0, fmt_9998, 0 };
+    static cilist io___13 = { 0, 0, 0, fmt_9997, 0 };
+    static cilist io___14 = { 0, 0, 0, fmt_9996, 0 };
+    static cilist io___15 = { 0, 0, 0, fmt_9995, 0 };
+    static cilist io___16 = { 0, 0, 0, fmt_9994, 0 };
+
+
+/*     ...   
+       ... SPECIFICATIONS FOR ARGUMENTS   
+       ...   
+       ... SPECIFICATIONS FOR LOCAL VARIABLES   
+       ...   
+       ... FIRST EXECUTABLE STATEMENT   
+
+
+       Parameter adjustments */
+    --sx;
+
+    /* Function Body   
+   Computing MIN */
+    i__1 = i_len(ifmt, ifmt_len);
+    lll = min(i__1,80);
+    i__1 = lll;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	*(unsigned char *)&line[i__ - 1] = '-';
+/* L10: */
+    }
+
+    for (i__ = lll + 1; i__ <= 80; ++i__) {
+	*(unsigned char *)&line[i__ - 1] = ' ';
+/* L20: */
+    }
+
+    io___4.ciunit = *lout;
+    s_wsfe(&io___4);
+    do_fio(&c__1, ifmt, ifmt_len);
+    do_fio(&c__1, line, lll);
+    e_wsfe();
+
+    if (*n <= 0) {
+	return 0;
+    }
+    ndigit = *idigit;
+    if (*idigit == 0) {
+	ndigit = 4;
+    }
+
+/* =======================================================================   
+               CODE FOR OUTPUT USING 72 COLUMNS FORMAT   
+   ======================================================================= */
+
+    if (*idigit < 0) {
+	ndigit = -(*idigit);
+	if (ndigit <= 4) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 5) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 4;
+		k2 = min(i__2,i__3);
+		io___8.ciunit = *lout;
+		s_wsfe(&io___8);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L30: */
+	    }
+	} else if (ndigit <= 6) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 4) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 3;
+		k2 = min(i__2,i__3);
+		io___9.ciunit = *lout;
+		s_wsfe(&io___9);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L40: */
+	    }
+	} else if (ndigit <= 10) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 3) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 2;
+		k2 = min(i__2,i__3);
+		io___10.ciunit = *lout;
+		s_wsfe(&io___10);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L50: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 2) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 1;
+		k2 = min(i__2,i__3);
+		io___11.ciunit = *lout;
+		s_wsfe(&io___11);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L60: */
+	    }
+	}
+
+/* =======================================================================   
+               CODE FOR OUTPUT USING 132 COLUMNS FORMAT   
+   ======================================================================= */
+
+    } else {
+	if (ndigit <= 4) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 10) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 9;
+		k2 = min(i__2,i__3);
+		io___12.ciunit = *lout;
+		s_wsfe(&io___12);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L70: */
+	    }
+	} else if (ndigit <= 6) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 8) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 7;
+		k2 = min(i__2,i__3);
+		io___13.ciunit = *lout;
+		s_wsfe(&io___13);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L80: */
+	    }
+	} else if (ndigit <= 10) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 6) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 5;
+		k2 = min(i__2,i__3);
+		io___14.ciunit = *lout;
+		s_wsfe(&io___14);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L90: */
+	    }
+	} else {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 5) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 4;
+		k2 = min(i__2,i__3);
+		io___15.ciunit = *lout;
+		s_wsfe(&io___15);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&sx[i__], (ftnlen)sizeof(doublereal)
+			    );
+		}
+		e_wsfe();
+/* L100: */
+	    }
+	}
+    }
+    io___16.ciunit = *lout;
+    s_wsfe(&io___16);
+    e_wsfe();
+    return 0;
+} /* igraphdvout_ */
+
diff --git a/src/lapack/idamax.c b/src/lapack/idamax.c
new file mode 100644
index 0000000..41f4fa0
--- /dev/null
+++ b/src/lapack/idamax.c
@@ -0,0 +1,82 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+integer igraphidamax_(integer *n, doublereal *dx, integer *incx)
+{
+    /* System generated locals */
+    integer ret_val, i__1;
+    doublereal d__1;
+
+    /* Local variables */
+    integer i__, ix;
+    doublereal dmax__;
+
+
+/*  Purpose   
+    =======   
+
+       IDAMAX finds the index of element having max. absolute value.   
+
+    Further Details   
+    ===============   
+
+       jack dongarra, linpack, 3/11/78.   
+       modified 3/93 to return if incx .le. 0.   
+       modified 12/3/93, array(1) declarations changed to array(*)   
+
+    =====================================================================   
+
+       Parameter adjustments */
+    --dx;
+
+    /* Function Body */
+    ret_val = 0;
+    if (*n < 1 || *incx <= 0) {
+	return ret_val;
+    }
+    ret_val = 1;
+    if (*n == 1) {
+	return ret_val;
+    }
+    if (*incx == 1) {
+
+/*        code for increment equal to 1 */
+
+	dmax__ = abs(dx[1]);
+	i__1 = *n;
+	for (i__ = 2; i__ <= i__1; ++i__) {
+	    if ((d__1 = dx[i__], abs(d__1)) > dmax__) {
+		ret_val = i__;
+		dmax__ = (d__1 = dx[i__], abs(d__1));
+	    }
+	}
+    } else {
+
+/*        code for increment not equal to 1 */
+
+	ix = 1;
+	dmax__ = abs(dx[1]);
+	ix += *incx;
+	i__1 = *n;
+	for (i__ = 2; i__ <= i__1; ++i__) {
+	    if ((d__1 = dx[ix], abs(d__1)) > dmax__) {
+		ret_val = i__;
+		dmax__ = (d__1 = dx[ix], abs(d__1));
+	    }
+	    ix += *incx;
+	}
+    }
+    return ret_val;
+} /* igraphidamax_ */
+
diff --git a/src/lapack/ieeeck.c b/src/lapack/ieeeck.c
new file mode 100644
index 0000000..5ecb436
--- /dev/null
+++ b/src/lapack/ieeeck.c
@@ -0,0 +1,164 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+integer igraphieeeck_(integer *ispec, real *zero, real *one)
+{
+    /* System generated locals */
+    integer ret_val;
+
+    /* Local variables */
+    real nan1, nan2, nan3, nan4, nan5, nan6, neginf, posinf, negzro, newzro;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    IEEECK is called from the ILAENV to verify that Infinity and   
+    possibly NaN arithmetic is safe (i.e. will not trap).   
+
+    Arguments   
+    =========   
+
+    ISPEC   (input) INTEGER   
+            Specifies whether to test just for inifinity arithmetic   
+            or whether to test for infinity and NaN arithmetic.   
+            = 0: Verify infinity arithmetic only.   
+            = 1: Verify infinity and NaN arithmetic.   
+
+    ZERO    (input) REAL   
+            Must contain the value 0.0   
+            This is passed to prevent the compiler from optimizing   
+            away this code.   
+
+    ONE     (input) REAL   
+            Must contain the value 1.0   
+            This is passed to prevent the compiler from optimizing   
+            away this code.   
+
+    RETURN VALUE:  INTEGER   
+            = 0:  Arithmetic failed to produce the correct answers   
+            = 1:  Arithmetic produced the correct answers   
+
+    ===================================================================== */
+
+    ret_val = 1;
+
+    posinf = *one / *zero;
+    if (posinf <= *one) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    neginf = -(*one) / *zero;
+    if (neginf >= *zero) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    negzro = *one / (neginf + *one);
+    if (negzro != *zero) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    neginf = *one / negzro;
+    if (neginf >= *zero) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    newzro = negzro + *zero;
+    if (newzro != *zero) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    posinf = *one / newzro;
+    if (posinf <= *one) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    neginf *= posinf;
+    if (neginf >= *zero) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    posinf *= posinf;
+    if (posinf <= *one) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+
+
+
+/*     Return if we were only asked to check infinity arithmetic */
+
+    if (*ispec == 0) {
+	return ret_val;
+    }
+
+    nan1 = posinf + neginf;
+
+    nan2 = posinf / neginf;
+
+    nan3 = posinf / posinf;
+
+    nan4 = posinf * *zero;
+
+    nan5 = neginf * negzro;
+
+    nan6 = nan5 * *zero;
+
+    if (nan1 == nan1) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    if (nan2 == nan2) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    if (nan3 == nan3) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    if (nan4 == nan4) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    if (nan5 == nan5) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    if (nan6 == nan6) {
+	ret_val = 0;
+	return ret_val;
+    }
+
+    return ret_val;
+} /* igraphieeeck_ */
+
diff --git a/src/lapack/iladlc.c b/src/lapack/iladlc.c
new file mode 100644
index 0000000..f3cc5d6
--- /dev/null
+++ b/src/lapack/iladlc.c
@@ -0,0 +1,79 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+integer igraphiladlc_(integer *m, integer *n, doublereal *a, integer *lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, ret_val, i__1;
+
+    /* Local variables */
+    integer i__;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.2)                        --   
+
+    -- June 2010                                                       --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    ILADLC scans A for its last non-zero column.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The m by n matrix A.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A. LDA >= max(1,M).   
+
+    =====================================================================   
+
+
+       Quick test for the common case where one corner is non-zero.   
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    if (*n == 0) {
+	ret_val = *n;
+    } else if (a[*n * a_dim1 + 1] != 0. || a[*m + *n * a_dim1] != 0.) {
+	ret_val = *n;
+    } else {
+/*     Now scan each column from the end, returning with the first non-zero. */
+	for (ret_val = *n; ret_val >= 1; --ret_val) {
+	    i__1 = *m;
+	    for (i__ = 1; i__ <= i__1; ++i__) {
+		if (a[i__ + ret_val * a_dim1] != 0.) {
+		    return ret_val;
+		}
+	    }
+	}
+    }
+    return ret_val;
+} /* igraphiladlc_ */
+
diff --git a/src/lapack/iladlr.c b/src/lapack/iladlr.c
new file mode 100644
index 0000000..0a4e091
--- /dev/null
+++ b/src/lapack/iladlr.c
@@ -0,0 +1,78 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+integer igraphiladlr_(integer *m, integer *n, doublereal *a, integer *lda)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, ret_val, i__1;
+
+    /* Local variables */
+    integer i__, j;
+
+
+/*  -- LAPACK auxiliary routine (version 3.3.1)                        --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+    -- April 2011                                                      --   
+
+
+    Purpose   
+    =======   
+
+    ILADLR scans A for its last non-zero row.   
+
+    Arguments   
+    =========   
+
+    M       (input) INTEGER   
+            The number of rows of the matrix A.   
+
+    N       (input) INTEGER   
+            The number of columns of the matrix A.   
+
+    A       (input) DOUBLE PRECISION array, dimension (LDA,N)   
+            The m by n matrix A.   
+
+    LDA     (input) INTEGER   
+            The leading dimension of the array A. LDA >= max(1,M).   
+
+    =====================================================================   
+
+
+       Quick test for the common case where one corner is non-zero.   
+       Parameter adjustments */
+    a_dim1 = *lda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+
+    /* Function Body */
+    if (*m == 0) {
+	ret_val = *m;
+    } else if (a[*m + a_dim1] != 0. || a[*m + *n * a_dim1] != 0.) {
+	ret_val = *m;
+    } else {
+/*     Scan up each column tracking the last zero row seen. */
+	ret_val = 0;
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+	    i__ = *m;
+	    while(a[i__ + j * a_dim1] != 0. && i__ >= 1) {
+		--i__;
+	    }
+	    ret_val = max(ret_val,i__);
+	}
+    }
+    return ret_val;
+} /* igraphiladlr_ */
+
diff --git a/src/lapack/ilaenv.c b/src/lapack/ilaenv.c
new file mode 100644
index 0000000..ca08fed
--- /dev/null
+++ b/src/lapack/ilaenv.c
@@ -0,0 +1,644 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static real c_b163 = 0.f;
+static real c_b164 = 1.f;
+static integer c__0 = 0;
+
+integer igraphilaenv_(integer *ispec, char *name__, char *opts, integer *n1, 
+	integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen 
+	opts_len)
+{
+    /* System generated locals */
+    integer ret_val;
+
+    /* Builtin functions   
+       Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
+    integer s_cmp(char *, char *, ftnlen, ftnlen);
+
+    /* Local variables */
+    integer i__;
+    char c1[1], c2[2], c3[3], c4[2];
+    integer ic, nb, iz, nx;
+    logical cname;
+    integer nbmin;
+    logical sname;
+    extern integer igraphieeeck_(integer *, real *, real *);
+    char subnam[6];
+    extern integer igraphiparmq_(integer *, char *, char *, integer *, integer *, 
+	    integer *, integer *);
+
+
+/*  -- LAPACK auxiliary routine (version 3.2.1)                        --   
+
+    -- April 2009                                                      --   
+
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+
+
+    Purpose   
+    =======   
+
+    ILAENV is called from the LAPACK routines to choose problem-dependent   
+    parameters for the local environment.  See ISPEC for a description of   
+    the parameters.   
+
+    ILAENV returns an INTEGER   
+    if ILAENV >= 0: ILAENV returns the value of the parameter specified by ISPEC   
+    if ILAENV < 0:  if ILAENV = -k, the k-th argument had an illegal value.   
+
+    This version provides a set of parameters which should give good,   
+    but not optimal, performance on many of the currently available   
+    computers.  Users are encouraged to modify this subroutine to set   
+    the tuning parameters for their particular machine using the option   
+    and problem size information in the arguments.   
+
+    This routine will not function correctly if it is converted to all   
+    lower case.  Converting it to all upper case is allowed.   
+
+    Arguments   
+    =========   
+
+    ISPEC   (input) INTEGER   
+            Specifies the parameter to be returned as the value of   
+            ILAENV.   
+            = 1: the optimal blocksize; if this value is 1, an unblocked   
+                 algorithm will give the best performance.   
+            = 2: the minimum block size for which the block routine   
+                 should be used; if the usable block size is less than   
+                 this value, an unblocked routine should be used.   
+            = 3: the crossover point (in a block routine, for N less   
+                 than this value, an unblocked routine should be used)   
+            = 4: the number of shifts, used in the nonsymmetric   
+                 eigenvalue routines (DEPRECATED)   
+            = 5: the minimum column dimension for blocking to be used;   
+                 rectangular blocks must have dimension at least k by m,   
+                 where k is given by ILAENV(2,...) and m by ILAENV(5,...)   
+            = 6: the crossover point for the SVD (when reducing an m by n   
+                 matrix to bidiagonal form, if max(m,n)/min(m,n) exceeds   
+                 this value, a QR factorization is used first to reduce   
+                 the matrix to a triangular form.)   
+            = 7: the number of processors   
+            = 8: the crossover point for the multishift QR method   
+                 for nonsymmetric eigenvalue problems (DEPRECATED)   
+            = 9: maximum size of the subproblems at the bottom of the   
+                 computation tree in the divide-and-conquer algorithm   
+                 (used by xGELSD and xGESDD)   
+            =10: ieee NaN arithmetic can be trusted not to trap   
+            =11: infinity arithmetic can be trusted not to trap   
+            12 <= ISPEC <= 16:   
+                 xHSEQR or one of its subroutines,   
+                 see IPARMQ for detailed explanation   
+
+    NAME    (input) CHARACTER*(*)   
+            The name of the calling subroutine, in either upper case or   
+            lower case.   
+
+    OPTS    (input) CHARACTER*(*)   
+            The character options to the subroutine NAME, concatenated   
+            into a single character string.  For example, UPLO = 'U',   
+            TRANS = 'T', and DIAG = 'N' for a triangular routine would   
+            be specified as OPTS = 'UTN'.   
+
+    N1      (input) INTEGER   
+    N2      (input) INTEGER   
+    N3      (input) INTEGER   
+    N4      (input) INTEGER   
+            Problem dimensions for the subroutine NAME; these may not all   
+            be required.   
+
+    Further Details   
+    ===============   
+
+    The following conventions have been used when calling ILAENV from the   
+    LAPACK routines:   
+    1)  OPTS is a concatenation of all of the character options to   
+        subroutine NAME, in the same order that they appear in the   
+        argument list for NAME, even if they are not used in determining   
+        the value of the parameter specified by ISPEC.   
+    2)  The problem dimensions N1, N2, N3, N4 are specified in the order   
+        that they appear in the argument list for NAME.  N1 is used   
+        first, N2 second, and so on, and unused problem dimensions are   
+        passed a value of -1.   
+    3)  The parameter value returned by ILAENV is checked for validity in   
+        the calling subroutine.  For example, ILAENV is used to retrieve   
+        the optimal blocksize for STRTRI as follows:   
+
+        NB = ILAENV( 1, 'STRTRI', UPLO // DIAG, N, -1, -1, -1 )   
+        IF( NB.LE.1 ) NB = MAX( 1, N )   
+
+    ===================================================================== */
+
+
+    switch (*ispec) {
+	case 1:  goto L10;
+	case 2:  goto L10;
+	case 3:  goto L10;
+	case 4:  goto L80;
+	case 5:  goto L90;
+	case 6:  goto L100;
+	case 7:  goto L110;
+	case 8:  goto L120;
+	case 9:  goto L130;
+	case 10:  goto L140;
+	case 11:  goto L150;
+	case 12:  goto L160;
+	case 13:  goto L160;
+	case 14:  goto L160;
+	case 15:  goto L160;
+	case 16:  goto L160;
+    }
+
+/*     Invalid value for ISPEC */
+
+    ret_val = -1;
+    return ret_val;
+
+L10:
+
+/*     Convert NAME to upper case if the first character is lower case. */
+
+    ret_val = 1;
+    s_copy(subnam, name__, (ftnlen)6, name_len);
+    ic = *(unsigned char *)subnam;
+    iz = 'Z';
+    if (iz == 90 || iz == 122) {
+
+/*        ASCII character set */
+
+	if (ic >= 97 && ic <= 122) {
+	    *(unsigned char *)subnam = (char) (ic - 32);
+	    for (i__ = 2; i__ <= 6; ++i__) {
+		ic = *(unsigned char *)&subnam[i__ - 1];
+		if (ic >= 97 && ic <= 122) {
+		    *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32);
+		}
+/* L20: */
+	    }
+	}
+
+    } else if (iz == 233 || iz == 169) {
+
+/*        EBCDIC character set */
+
+	if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= 162 && 
+		ic <= 169) {
+	    *(unsigned char *)subnam = (char) (ic + 64);
+	    for (i__ = 2; i__ <= 6; ++i__) {
+		ic = *(unsigned char *)&subnam[i__ - 1];
+		if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= 
+			162 && ic <= 169) {
+		    *(unsigned char *)&subnam[i__ - 1] = (char) (ic + 64);
+		}
+/* L30: */
+	    }
+	}
+
+    } else if (iz == 218 || iz == 250) {
+
+/*        Prime machines:  ASCII+128 */
+
+	if (ic >= 225 && ic <= 250) {
+	    *(unsigned char *)subnam = (char) (ic - 32);
+	    for (i__ = 2; i__ <= 6; ++i__) {
+		ic = *(unsigned char *)&subnam[i__ - 1];
+		if (ic >= 225 && ic <= 250) {
+		    *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32);
+		}
+/* L40: */
+	    }
+	}
+    }
+
+    *(unsigned char *)c1 = *(unsigned char *)subnam;
+    sname = *(unsigned char *)c1 == 'S' || *(unsigned char *)c1 == 'D';
+    cname = *(unsigned char *)c1 == 'C' || *(unsigned char *)c1 == 'Z';
+    if (! (cname || sname)) {
+	return ret_val;
+    }
+    s_copy(c2, subnam + 1, (ftnlen)2, (ftnlen)2);
+    s_copy(c3, subnam + 3, (ftnlen)3, (ftnlen)3);
+    s_copy(c4, c3 + 1, (ftnlen)2, (ftnlen)2);
+
+    switch (*ispec) {
+	case 1:  goto L50;
+	case 2:  goto L60;
+	case 3:  goto L70;
+    }
+
+L50:
+
+/*     ISPEC = 1:  block size   
+
+       In these examples, separate code is provided for setting NB for   
+       real and complex.  We assume that NB will take the same value in   
+       single or double precision. */
+
+    nb = 1;
+
+    if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 64;
+	    } else {
+		nb = 64;
+	    }
+	} else if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, 
+		"RQF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)
+		3, (ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) 
+		== 0) {
+	    if (sname) {
+		nb = 32;
+	    } else {
+		nb = 32;
+	    }
+	} else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 32;
+	    } else {
+		nb = 32;
+	    }
+	} else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 32;
+	    } else {
+		nb = 32;
+	    }
+	} else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 64;
+	    } else {
+		nb = 64;
+	    }
+	}
+    } else if (s_cmp(c2, "PO", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 64;
+	    } else {
+		nb = 64;
+	    }
+	}
+    } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 64;
+	    } else {
+		nb = 64;
+	    }
+	} else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    nb = 32;
+	} else if (sname && s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) {
+	    nb = 64;
+	}
+    } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    nb = 64;
+	} else if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    nb = 32;
+	} else if (s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) {
+	    nb = 64;
+	}
+    } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) {
+	if (*(unsigned char *)c3 == 'G') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nb = 32;
+	    }
+	} else if (*(unsigned char *)c3 == 'M') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nb = 32;
+	    }
+	}
+    } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) {
+	if (*(unsigned char *)c3 == 'G') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nb = 32;
+	    }
+	} else if (*(unsigned char *)c3 == 'M') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nb = 32;
+	    }
+	}
+    } else if (s_cmp(c2, "GB", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		if (*n4 <= 64) {
+		    nb = 1;
+		} else {
+		    nb = 32;
+		}
+	    } else {
+		if (*n4 <= 64) {
+		    nb = 1;
+		} else {
+		    nb = 32;
+		}
+	    }
+	}
+    } else if (s_cmp(c2, "PB", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		if (*n2 <= 64) {
+		    nb = 1;
+		} else {
+		    nb = 32;
+		}
+	    } else {
+		if (*n2 <= 64) {
+		    nb = 1;
+		} else {
+		    nb = 32;
+		}
+	    }
+	}
+    } else if (s_cmp(c2, "TR", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 64;
+	    } else {
+		nb = 64;
+	    }
+	}
+    } else if (s_cmp(c2, "LA", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "UUM", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nb = 64;
+	    } else {
+		nb = 64;
+	    }
+	}
+    } else if (sname && s_cmp(c2, "ST", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "EBZ", (ftnlen)3, (ftnlen)3) == 0) {
+	    nb = 1;
+	}
+    }
+    ret_val = nb;
+    return ret_val;
+
+L60:
+
+/*     ISPEC = 2:  minimum block size */
+
+    nbmin = 2;
+    if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", (
+		ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, (
+		ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0)
+		 {
+	    if (sname) {
+		nbmin = 2;
+	    } else {
+		nbmin = 2;
+	    }
+	} else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nbmin = 2;
+	    } else {
+		nbmin = 2;
+	    }
+	} else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nbmin = 2;
+	    } else {
+		nbmin = 2;
+	    }
+	} else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nbmin = 2;
+	    } else {
+		nbmin = 2;
+	    }
+	}
+    } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nbmin = 8;
+	    } else {
+		nbmin = 8;
+	    }
+	} else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    nbmin = 2;
+	}
+    } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    nbmin = 2;
+	}
+    } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) {
+	if (*(unsigned char *)c3 == 'G') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nbmin = 2;
+	    }
+	} else if (*(unsigned char *)c3 == 'M') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nbmin = 2;
+	    }
+	}
+    } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) {
+	if (*(unsigned char *)c3 == 'G') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nbmin = 2;
+	    }
+	} else if (*(unsigned char *)c3 == 'M') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nbmin = 2;
+	    }
+	}
+    }
+    ret_val = nbmin;
+    return ret_val;
+
+L70:
+
+/*     ISPEC = 3:  crossover point */
+
+    nx = 0;
+    if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", (
+		ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, (
+		ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0)
+		 {
+	    if (sname) {
+		nx = 128;
+	    } else {
+		nx = 128;
+	    }
+	} else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nx = 128;
+	    } else {
+		nx = 128;
+	    }
+	} else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    if (sname) {
+		nx = 128;
+	    } else {
+		nx = 128;
+	    }
+	}
+    } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) {
+	if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    nx = 32;
+	}
+    } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) {
+	if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) {
+	    nx = 32;
+	}
+    } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) {
+	if (*(unsigned char *)c3 == 'G') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nx = 128;
+	    }
+	}
+    } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) {
+	if (*(unsigned char *)c3 == 'G') {
+	    if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", 
+		    (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, (
+		    ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) ==
+		     0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(
+		    c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", (
+		    ftnlen)2, (ftnlen)2) == 0) {
+		nx = 128;
+	    }
+	}
+    }
+    ret_val = nx;
+    return ret_val;
+
+L80:
+
+/*     ISPEC = 4:  number of shifts (used by xHSEQR) */
+
+    ret_val = 6;
+    return ret_val;
+
+L90:
+
+/*     ISPEC = 5:  minimum column dimension (not used) */
+
+    ret_val = 2;
+    return ret_val;
+
+L100:
+
+/*     ISPEC = 6:  crossover point for SVD (used by xGELSS and xGESVD) */
+
+    ret_val = (integer) ((real) min(*n1,*n2) * 1.6f);
+    return ret_val;
+
+L110:
+
+/*     ISPEC = 7:  number of processors (not used) */
+
+    ret_val = 1;
+    return ret_val;
+
+L120:
+
+/*     ISPEC = 8:  crossover point for multishift (used by xHSEQR) */
+
+    ret_val = 50;
+    return ret_val;
+
+L130:
+
+/*     ISPEC = 9:  maximum size of the subproblems at the bottom of the   
+                   computation tree in the divide-and-conquer algorithm   
+                   (used by xGELSD and xGESDD) */
+
+    ret_val = 25;
+    return ret_val;
+
+L140:
+
+/*     ISPEC = 10: ieee NaN arithmetic can be trusted not to trap   
+
+       ILAENV = 0 */
+    ret_val = 1;
+    if (ret_val == 1) {
+	ret_val = igraphieeeck_(&c__1, &c_b163, &c_b164);
+    }
+    return ret_val;
+
+L150:
+
+/*     ISPEC = 11: infinity arithmetic can be trusted not to trap   
+
+       ILAENV = 0 */
+    ret_val = 1;
+    if (ret_val == 1) {
+	ret_val = igraphieeeck_(&c__0, &c_b163, &c_b164);
+    }
+    return ret_val;
+
+L160:
+
+/*     12 <= ISPEC <= 16: xHSEQR or one of its subroutines. */
+
+    ret_val = igraphiparmq_(ispec, name__, opts, n1, n2, n3, n4)
+	    ;
+    return ret_val;
+
+/*     End of ILAENV */
+
+} /* igraphilaenv_ */
+
diff --git a/src/lapack/iparmq.c b/src/lapack/iparmq.c
new file mode 100644
index 0000000..640eb85
--- /dev/null
+++ b/src/lapack/iparmq.c
@@ -0,0 +1,275 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+integer igraphiparmq_(integer *ispec, char *name__, char *opts, integer *n, integer 
+	*ilo, integer *ihi, integer *lwork)
+{
+    /* System generated locals */
+    integer ret_val, i__1, i__2;
+    real r__1;
+
+    /* Builtin functions */
+    double log(doublereal);
+    integer i_nint(real *);
+
+    /* Local variables */
+    integer nh, ns;
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+         This program sets problem and machine dependent parameters   
+         useful for xHSEQR and its subroutines. It is called whenever   
+         ILAENV is called with 12 <= ISPEC <= 16   
+
+    Arguments   
+    =========   
+
+         ISPEC  (input) integer scalar   
+                ISPEC specifies which tunable parameter IPARMQ should   
+                return.   
+
+                ISPEC=12: (INMIN)  Matrices of order nmin or less   
+                          are sent directly to xLAHQR, the implicit   
+                          double shift QR algorithm.  NMIN must be   
+                          at least 11.   
+
+                ISPEC=13: (INWIN)  Size of the deflation window.   
+                          This is best set greater than or equal to   
+                          the number of simultaneous shifts NS.   
+                          Larger matrices benefit from larger deflation   
+                          windows.   
+
+                ISPEC=14: (INIBL) Determines when to stop nibbling and   
+                          invest in an (expensive) multi-shift QR sweep.   
+                          If the aggressive early deflation subroutine   
+                          finds LD converged eigenvalues from an order   
+                          NW deflation window and LD.GT.(NW*NIBBLE)/100,   
+                          then the next QR sweep is skipped and early   
+                          deflation is applied immediately to the   
+                          remaining active diagonal block.  Setting   
+                          IPARMQ(ISPEC=14) = 0 causes TTQRE to skip a   
+                          multi-shift QR sweep whenever early deflation   
+                          finds a converged eigenvalue.  Setting   
+                          IPARMQ(ISPEC=14) greater than or equal to 100   
+                          prevents TTQRE from skipping a multi-shift   
+                          QR sweep.   
+
+                ISPEC=15: (NSHFTS) The number of simultaneous shifts in   
+                          a multi-shift QR iteration.   
+
+                ISPEC=16: (IACC22) IPARMQ is set to 0, 1 or 2 with the   
+                          following meanings.   
+                          0:  During the multi-shift QR sweep,   
+                              xLAQR5 does not accumulate reflections and   
+                              does not use matrix-matrix multiply to   
+                              update the far-from-diagonal matrix   
+                              entries.   
+                          1:  During the multi-shift QR sweep,   
+                              xLAQR5 and/or xLAQRaccumulates reflections and uses   
+                              matrix-matrix multiply to update the   
+                              far-from-diagonal matrix entries.   
+                          2:  During the multi-shift QR sweep.   
+                              xLAQR5 accumulates reflections and takes   
+                              advantage of 2-by-2 block structure during   
+                              matrix-matrix multiplies.   
+                          (If xTRMM is slower than xGEMM, then   
+                          IPARMQ(ISPEC=16)=1 may be more efficient than   
+                          IPARMQ(ISPEC=16)=2 despite the greater level of   
+                          arithmetic work implied by the latter choice.)   
+
+         NAME    (input) character string   
+                 Name of the calling subroutine   
+
+         OPTS    (input) character string   
+                 This is a concatenation of the string arguments to   
+                 TTQRE.   
+
+         N       (input) integer scalar   
+                 N is the order of the Hessenberg matrix H.   
+
+         ILO     (input) INTEGER   
+         IHI     (input) INTEGER   
+                 It is assumed that H is already upper triangular   
+                 in rows and columns 1:ILO-1 and IHI+1:N.   
+
+         LWORK   (input) integer scalar   
+                 The amount of workspace available.   
+
+    Further Details   
+    ===============   
+
+         Little is known about how best to choose these parameters.   
+         It is possible to use different values of the parameters   
+         for each of CHSEQR, DHSEQR, SHSEQR and ZHSEQR.   
+
+         It is probably best to choose different parameters for   
+         different matrices and different parameters at different   
+         times during the iteration, but this has not been   
+         implemented --- yet.   
+
+
+         The best choices of most of the parameters depend   
+         in an ill-understood way on the relative execution   
+         rate of xLAQR3 and xLAQR5 and on the nature of each   
+         particular eigenvalue problem.  Experiment may be the   
+         only practical way to determine which choices are most   
+         effective.   
+
+         Following is a list of default values supplied by IPARMQ.   
+         These defaults may be adjusted in order to attain better   
+         performance in any particular computational environment.   
+
+         IPARMQ(ISPEC=12) The xLAHQR vs xLAQR0 crossover point.   
+                          Default: 75. (Must be at least 11.)   
+
+         IPARMQ(ISPEC=13) Recommended deflation window size.   
+                          This depends on ILO, IHI and NS, the   
+                          number of simultaneous shifts returned   
+                          by IPARMQ(ISPEC=15).  The default for   
+                          (IHI-ILO+1).LE.500 is NS.  The default   
+                          for (IHI-ILO+1).GT.500 is 3*NS/2.   
+
+         IPARMQ(ISPEC=14) Nibble crossover point.  Default: 14.   
+
+         IPARMQ(ISPEC=15) Number of simultaneous shifts, NS.   
+                          a multi-shift QR iteration.   
+
+                          If IHI-ILO+1 is ...   
+
+                          greater than      ...but less    ... the   
+                          or equal to ...      than        default is   
+
+                                  0               30       NS =   2+   
+                                 30               60       NS =   4+   
+                                 60              150       NS =  10   
+                                150              590       NS =  **   
+                                590             3000       NS =  64   
+                               3000             6000       NS = 128   
+                               6000             infinity   NS = 256   
+
+                      (+)  By default matrices of this order are   
+                           passed to the implicit double shift routine   
+                           xLAHQR.  See IPARMQ(ISPEC=12) above.   These   
+                           values of NS are used only in case of a rare   
+                           xLAHQR failure.   
+
+                      (**) The asterisks (**) indicate an ad-hoc   
+                           function increasing from 10 to 64.   
+
+         IPARMQ(ISPEC=16) Select structured matrix multiply.   
+                          (See ISPEC=16 above for details.)   
+                          Default: 3.   
+
+       ================================================================ */
+    if (*ispec == 15 || *ispec == 13 || *ispec == 16) {
+
+/*        ==== Set the number simultaneous shifts ==== */
+
+	nh = *ihi - *ilo + 1;
+	ns = 2;
+	if (nh >= 30) {
+	    ns = 4;
+	}
+	if (nh >= 60) {
+	    ns = 10;
+	}
+	if (nh >= 150) {
+/* Computing MAX */
+	    r__1 = log((real) nh) / log(2.f);
+	    i__1 = 10, i__2 = nh / i_nint(&r__1);
+	    ns = max(i__1,i__2);
+	}
+	if (nh >= 590) {
+	    ns = 64;
+	}
+	if (nh >= 3000) {
+	    ns = 128;
+	}
+	if (nh >= 6000) {
+	    ns = 256;
+	}
+/* Computing MAX */
+	i__1 = 2, i__2 = ns - ns % 2;
+	ns = max(i__1,i__2);
+    }
+
+    if (*ispec == 12) {
+
+
+/*        ===== Matrices of order smaller than NMIN get sent   
+          .     to xLAHQR, the classic double shift algorithm.   
+          .     This must be at least 11. ==== */
+
+	ret_val = 75;
+
+    } else if (*ispec == 14) {
+
+/*        ==== INIBL: skip a multi-shift qr iteration and   
+          .    whenever aggressive early deflation finds   
+          .    at least (NIBBLE*(window size)/100) deflations. ==== */
+
+	ret_val = 14;
+
+    } else if (*ispec == 15) {
+
+/*        ==== NSHFTS: The number of simultaneous shifts ===== */
+
+	ret_val = ns;
+
+    } else if (*ispec == 13) {
+
+/*        ==== NW: deflation window size.  ==== */
+
+	if (nh <= 500) {
+	    ret_val = ns;
+	} else {
+	    ret_val = ns * 3 / 2;
+	}
+
+    } else if (*ispec == 16) {
+
+/*        ==== IACC22: Whether to accumulate reflections   
+          .     before updating the far-from-diagonal elements   
+          .     and whether to use 2-by-2 block structure while   
+          .     doing it.  A small amount of work could be saved   
+          .     by making this choice dependent also upon the   
+          .     NH=IHI-ILO+1. */
+
+	ret_val = 0;
+	if (ns >= 14) {
+	    ret_val = 1;
+	}
+	if (ns >= 14) {
+	    ret_val = 2;
+	}
+
+    } else {
+/*        ===== invalid value of ispec ===== */
+	ret_val = -1;
+
+    }
+
+/*     ==== End of IPARMQ ==== */
+
+    return ret_val;
+} /* igraphiparmq_ */
+
diff --git a/src/lapack/ivout.c b/src/lapack/ivout.c
new file mode 100644
index 0000000..135d7d9
--- /dev/null
+++ b/src/lapack/ivout.c
@@ -0,0 +1,278 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* -----------------------------------------------------------------------   
+    Routine:    IVOUT   
+
+    Purpose:    Integer vector output routine.   
+
+    Usage:      CALL IVOUT (LOUT, N, IX, IDIGIT, IFMT)   
+
+    Arguments   
+       N      - Length of array IX. (Input)   
+       IX     - Integer array to be printed. (Input)   
+       IFMT   - Format to be used in printing array IX. (Input)   
+       IDIGIT - Print up to ABS(IDIGIT) decimal digits / number. (Input)   
+                If IDIGIT .LT. 0, printing is done with 72 columns.   
+                If IDIGIT .GT. 0, printing is done with 132 columns.   
+
+   -----------------------------------------------------------------------   
+
+   Subroutine */ int igraphivout_(integer *lout, integer *n, integer *ix, integer *
+	idigit, char *ifmt, ftnlen ifmt_len)
+{
+    /* Format strings */
+    static char fmt_2000[] = "(/1x,a/1x,a)";
+    static char fmt_1000[] = "(1x,i4,\002 - \002,i4,\002:\002,20(1x,i5))";
+    static char fmt_1001[] = "(1x,i4,\002 - \002,i4,\002:\002,15(1x,i7))";
+    static char fmt_1002[] = "(1x,i4,\002 - \002,i4,\002:\002,10(1x,i11))";
+    static char fmt_1003[] = "(1x,i4,\002 - \002,i4,\002:\002,7(1x,i15))";
+    static char fmt_1004[] = "(1x,\002 \002)";
+
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+
+    /* Builtin functions */
+    integer i_len(char *, ftnlen), s_wsfe(cilist *), do_fio(integer *, char *,
+	     ftnlen), e_wsfe(void);
+
+    /* Local variables */
+    integer i__, k1, k2, lll;
+    char line[80];
+    integer ndigit;
+
+    /* Fortran I/O blocks */
+    static cilist io___4 = { 0, 0, 0, fmt_2000, 0 };
+    static cilist io___8 = { 0, 0, 0, fmt_1000, 0 };
+    static cilist io___9 = { 0, 0, 0, fmt_1001, 0 };
+    static cilist io___10 = { 0, 0, 0, fmt_1002, 0 };
+    static cilist io___11 = { 0, 0, 0, fmt_1003, 0 };
+    static cilist io___12 = { 0, 0, 0, fmt_1000, 0 };
+    static cilist io___13 = { 0, 0, 0, fmt_1001, 0 };
+    static cilist io___14 = { 0, 0, 0, fmt_1002, 0 };
+    static cilist io___15 = { 0, 0, 0, fmt_1003, 0 };
+    static cilist io___16 = { 0, 0, 0, fmt_1004, 0 };
+
+
+/*     ...   
+       ... SPECIFICATIONS FOR ARGUMENTS   
+       ...   
+       ... SPECIFICATIONS FOR LOCAL VARIABLES   
+       ...   
+       ... SPECIFICATIONS INTRINSICS   
+
+
+       Parameter adjustments */
+    --ix;
+
+    /* Function Body   
+   Computing MIN */
+    i__1 = i_len(ifmt, ifmt_len);
+    lll = min(i__1,80);
+    i__1 = lll;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	*(unsigned char *)&line[i__ - 1] = '-';
+/* L1: */
+    }
+
+    for (i__ = lll + 1; i__ <= 80; ++i__) {
+	*(unsigned char *)&line[i__ - 1] = ' ';
+/* L2: */
+    }
+
+    io___4.ciunit = *lout;
+    s_wsfe(&io___4);
+    do_fio(&c__1, ifmt, ifmt_len);
+    do_fio(&c__1, line, lll);
+    e_wsfe();
+
+    if (*n <= 0) {
+	return 0;
+    }
+    ndigit = *idigit;
+    if (*idigit == 0) {
+	ndigit = 4;
+    }
+
+/* =======================================================================   
+               CODE FOR OUTPUT USING 72 COLUMNS FORMAT   
+   ======================================================================= */
+
+    if (*idigit < 0) {
+
+	ndigit = -(*idigit);
+	if (ndigit <= 4) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 10) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 9;
+		k2 = min(i__2,i__3);
+		io___8.ciunit = *lout;
+		s_wsfe(&io___8);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L10: */
+	    }
+
+	} else if (ndigit <= 6) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 7) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 6;
+		k2 = min(i__2,i__3);
+		io___9.ciunit = *lout;
+		s_wsfe(&io___9);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L30: */
+	    }
+
+	} else if (ndigit <= 10) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 5) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 4;
+		k2 = min(i__2,i__3);
+		io___10.ciunit = *lout;
+		s_wsfe(&io___10);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L50: */
+	    }
+
+	} else {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 3) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 2;
+		k2 = min(i__2,i__3);
+		io___11.ciunit = *lout;
+		s_wsfe(&io___11);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L70: */
+	    }
+	}
+
+/* =======================================================================   
+               CODE FOR OUTPUT USING 132 COLUMNS FORMAT   
+   ======================================================================= */
+
+    } else {
+
+	if (ndigit <= 4) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 20) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 19;
+		k2 = min(i__2,i__3);
+		io___12.ciunit = *lout;
+		s_wsfe(&io___12);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L90: */
+	    }
+
+	} else if (ndigit <= 6) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 15) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 14;
+		k2 = min(i__2,i__3);
+		io___13.ciunit = *lout;
+		s_wsfe(&io___13);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L110: */
+	    }
+
+	} else if (ndigit <= 10) {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 10) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 9;
+		k2 = min(i__2,i__3);
+		io___14.ciunit = *lout;
+		s_wsfe(&io___14);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L130: */
+	    }
+
+	} else {
+	    i__1 = *n;
+	    for (k1 = 1; k1 <= i__1; k1 += 7) {
+/* Computing MIN */
+		i__2 = *n, i__3 = k1 + 6;
+		k2 = min(i__2,i__3);
+		io___15.ciunit = *lout;
+		s_wsfe(&io___15);
+		do_fio(&c__1, (char *)&k1, (ftnlen)sizeof(integer));
+		do_fio(&c__1, (char *)&k2, (ftnlen)sizeof(integer));
+		i__2 = k2;
+		for (i__ = k1; i__ <= i__2; ++i__) {
+		    do_fio(&c__1, (char *)&ix[i__], (ftnlen)sizeof(integer));
+		}
+		e_wsfe();
+/* L150: */
+	    }
+	}
+    }
+    io___16.ciunit = *lout;
+    s_wsfe(&io___16);
+    e_wsfe();
+
+
+    return 0;
+} /* igraphivout_ */
+
diff --git a/src/lapack/lapack.inc b/src/lapack/lapack.inc
new file mode 100644
index 0000000..57a75fe
--- /dev/null
+++ b/src/lapack/lapack.inc
@@ -0,0 +1,2 @@
+LAPACK = lapack/dgeev.c lapack/dgebak.c lapack/xerbla.c lapack/dgebal.c lapack/disnan.c lapack/dlaisnan.c  lapack/dgehrd.c lapack/dgehd2.c lapack/dlarf.c lapack/iladlc.c lapack/iladlr.c lapack/dlarfg.c lapack/dlapy2.c lapack/dlahr2.c lapack/dlacpy.c lapack/dlarfb.c lapack/ilaenv.c lapack/ieeeck.c lapack/iparmq.c lapack/dhseqr.c lapack/dlahqr.c lapack/dlabad.c lapack/dlanv2.c lapack/dlaqr0.c lapack/dlaqr3.c lapack/dlaqr4.c lapack/dlaqr2.c lapack/dlaset.c lapack/dormhr.c lapack/dormqr.c la [...]
+
diff --git a/src/lapack/len_trim.c b/src/lapack/len_trim.c
new file mode 100644
index 0000000..b6b9d47
--- /dev/null
+++ b/src/lapack/len_trim.c
@@ -0,0 +1,36 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+
+/*  -- LEN_TRIM is Fortran 95, so we use a replacement here */
+
+integer igraphlen_trim__(char *s, ftnlen s_len)
+{
+    /* System generated locals */
+    integer ret_val;
+
+    /* Builtin functions */
+    integer i_len(char *, ftnlen);
+
+
+
+
+    for (ret_val = i_len(s, s_len); ret_val >= 1; --ret_val) {
+	if (*(unsigned char *)&s[ret_val - 1] != ' ') {
+	    return ret_val;
+	}
+    }
+    return ret_val;
+} /* igraphlen_trim__ */
+
diff --git a/src/lapack/lsame.c b/src/lapack/lsame.c
new file mode 100644
index 0000000..eedf20c
--- /dev/null
+++ b/src/lapack/lsame.c
@@ -0,0 +1,111 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+logical igraphlsame_(char *ca, char *cb)
+{
+    /* System generated locals */
+    logical ret_val;
+
+    /* Local variables */
+    integer inta, intb, zcode;
+
+
+/*  -- LAPACK auxiliary routine (version 3.1) --   
+       Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    LSAME returns .TRUE. if CA is the same letter as CB regardless of   
+    case.   
+
+    Arguments   
+    =========   
+
+    CA      (input) CHARACTER*1   
+
+    CB      (input) CHARACTER*1   
+            CA and CB specify the single characters to be compared.   
+
+   =====================================================================   
+
+
+       Test if the characters are equal */
+
+    ret_val = *(unsigned char *)ca == *(unsigned char *)cb;
+    if (ret_val) {
+	return ret_val;
+    }
+
+/*     Now test for equivalence if both characters are alphabetic. */
+
+    zcode = 'Z';
+
+/*     Use 'Z' rather than 'A' so that ASCII can be detected on Prime   
+       machines, on which ICHAR returns a value with bit 8 set.   
+       ICHAR('A') on Prime machines returns 193 which is the same as   
+       ICHAR('A') on an EBCDIC machine. */
+
+    inta = *(unsigned char *)ca;
+    intb = *(unsigned char *)cb;
+
+    if (zcode == 90 || zcode == 122) {
+
+/*        ASCII is assumed - ZCODE is the ASCII code of either lower or   
+          upper case 'Z'. */
+
+	if (inta >= 97 && inta <= 122) {
+	    inta += -32;
+	}
+	if (intb >= 97 && intb <= 122) {
+	    intb += -32;
+	}
+
+    } else if (zcode == 233 || zcode == 169) {
+
+/*        EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or   
+          upper case 'Z'. */
+
+	if (inta >= 129 && inta <= 137 || inta >= 145 && inta <= 153 || inta 
+		>= 162 && inta <= 169) {
+	    inta += 64;
+	}
+	if (intb >= 129 && intb <= 137 || intb >= 145 && intb <= 153 || intb 
+		>= 162 && intb <= 169) {
+	    intb += 64;
+	}
+
+    } else if (zcode == 218 || zcode == 250) {
+
+/*        ASCII is assumed, on Prime machines - ZCODE is the ASCII code   
+          plus 128 of either lower or upper case 'Z'. */
+
+	if (inta >= 225 && inta <= 250) {
+	    inta += -32;
+	}
+	if (intb >= 225 && intb <= 250) {
+	    intb += -32;
+	}
+    }
+    ret_val = inta == intb;
+
+/*     RETURN   
+
+       End of LSAME */
+
+    return ret_val;
+} /* igraphlsame_ */
+
diff --git a/src/lapack/second.c b/src/lapack/second.c
new file mode 100644
index 0000000..d2aa662
--- /dev/null
+++ b/src/lapack/second.c
@@ -0,0 +1,42 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Subroutine */ int igraphsecond_(real *t)
+{
+    real t1;
+    extern doublereal etime_(real *);
+    real tarray[2];
+
+
+
+/*  -- LAPACK auxiliary routine (preliminary version) --   
+       Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,   
+       Courant Institute, Argonne National Lab, and Rice University   
+       July 26, 1991   
+
+    Purpose   
+    =======   
+
+    SECOND returns the user time for a process in seconds.   
+    This version gets the time from the system function ETIME. */
+
+
+    t1 = etime_(tarray);
+    *t = tarray[0];
+    return 0;
+
+/*     End of SECOND */
+
+} /* igraphsecond_ */
+
diff --git a/src/lapack/xerbla.c b/src/lapack/xerbla.c
new file mode 100644
index 0000000..56af3cf
--- /dev/null
+++ b/src/lapack/xerbla.c
@@ -0,0 +1,78 @@
+/*  -- translated by f2c (version 20100827).
+   You must link the resulting object file with libf2c:
+	on Microsoft Windows system, link with libf2c.lib;
+	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+	or, if you install libf2c.a in a standard place, with -lf2c -lm
+	-- in that order, at the end of the command line, as in
+		cc *.o -lf2c -lm
+	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+		http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+
+/* Subroutine */ int igraphxerbla_(char *srname, integer *info, ftnlen srname_len)
+{
+    /* Format strings */
+    static char fmt_9999[] = "(\002 ** On entry to \002,a,\002 parameter num"
+	    "ber \002,i2,\002 had \002,\002an illegal value\002)";
+
+    /* Builtin functions */
+    integer s_wsfe(cilist *), do_fio(integer *, char *, ftnlen), e_wsfe(void);
+    /* Subroutine */ int s_stop(char *, ftnlen);
+
+    /* Local variables */
+    extern integer igraphlen_trim__(char *, ftnlen);
+
+    /* Fortran I/O blocks */
+    static cilist io___1 = { 0, 6, 0, fmt_9999, 0 };
+
+
+
+/*  -- LAPACK auxiliary routine (version 3.2) --   
+    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
+    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
+       November 2006   
+
+
+    Purpose   
+    =======   
+
+    XERBLA  is an error handler for the LAPACK routines.   
+    It is called by an LAPACK routine if an input parameter has an   
+    invalid value.  A message is printed and execution stops.   
+
+    Installers may consider modifying the STOP statement in order to   
+    call system-specific exception-handling facilities.   
+
+    Arguments   
+    =========   
+
+    SRNAME  (input) CHARACTER*(*)   
+            The name of the routine which called XERBLA.   
+
+    INFO    (input) INTEGER   
+            The position of the invalid parameter in the parameter list   
+            of the calling routine.   
+
+   ===================================================================== */
+
+
+    s_wsfe(&io___1);
+    do_fio(&c__1, srname, igraphlen_trim__(srname, srname_len));
+    do_fio(&c__1, (char *)&(*info), (ftnlen)sizeof(integer));
+    e_wsfe();
+
+    s_stop("", (ftnlen)0);
+
+
+/*     End of XERBLA */
+
+    return 0;
+} /* igraphxerbla_ */
+
diff --git a/src/layout.c b/src/layout.c
new file mode 100644
index 0000000..d531d7d
--- /dev/null
+++ b/src/layout.c
@@ -0,0 +1,3193 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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
+
+*/
+
+#include "igraph_layout.h"
+#include "igraph_random.h"
+#include "igraph_memory.h"
+#include "igraph_iterators.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_paths.h"
+#include "igraph_structural.h"
+#include "igraph_visitor.h"
+#include "igraph_topology.h"
+#include "igraph_components.h"
+#include "igraph_types_internal.h"
+#include "igraph_dqueue.h"
+#include "igraph_arpack.h"
+#include "igraph_blas.h"
+#include "igraph_centrality.h"
+#include "igraph_eigen.h"
+#include "config.h"
+#include <math.h>
+#include "igraph_math.h"
+
+
+/**
+ * \section about_layouts
+ * 
+ * <para>Layout generator functions (or at least most of them) try to place the
+ * vertices and edges of a graph on a 2D plane or in 3D space in a way
+ * which visually pleases the human eye.</para>
+ *
+ * <para>They take a graph object and a number of parameters as arguments
+ * and return an \type igraph_matrix_t, in which each row gives the
+ * coordinates of a vertex.</para>
+ */
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_random
+ * \brief Places the vertices uniform randomly on a plane.
+ * 
+ * \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.
+ * \return Error code. The current implementation always returns with
+ * success. 
+ * 
+ * Time complexity: O(|V|), the
+ * number of vertices. 
+ */
+
+int igraph_layout_random(const igraph_t *graph, igraph_matrix_t *res) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
+
+  RNG_BEGIN();
+
+  for (i=0; i<no_of_nodes; i++) {
+    MATRIX(*res, i, 0)=RNG_UNIF(-1, 1);
+    MATRIX(*res, i, 1)=RNG_UNIF(-1, 1);
+  }
+
+  RNG_END();
+  
+  return 0;
+}
+
+/**
+ * \function igraph_layout_random_3d
+ * \brief Random layout in 3D
+ * 
+ * \param graph The graph to place.
+ * \param res Pointer to an initialized matrix object. It will be
+ * resized to hold the result.
+ * \return Error code. The current implementation always returns with
+ * success. 
+ *
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(|V|), the number of vertices.
+ */
+
+int igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3));
+  
+  RNG_BEGIN();
+  
+  for (i=0; i<no_of_nodes; i++) {
+    MATRIX(*res, i, 0)=RNG_UNIF(-1, 1);
+    MATRIX(*res, i, 1)=RNG_UNIF(-1, 1);
+    MATRIX(*res, i, 2)=RNG_UNIF(-1, 1);
+  }
+  
+  RNG_END();
+  
+  return 0;
+}
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_circle
+ * \brief Places the vertices uniformly on a circle, in the order of vertex ids.
+ * 
+ * \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.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), the
+ * number of vertices. 
+ */
+
+int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));  
+
+  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);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_layout_star
+ * Generate a star-like layout
+ * 
+ * \param graph The input graph.
+ * \param res Pointer to an initialized matrix object. This will
+ *        contain the result and will be resized as needed.
+ * \param center The id of the vertex to put in the center.
+ * \param order A numeric vector giving the order of the vertices 
+ *      (including the center vertex!). If a null pointer, then the
+ *      vertices are placed in increasing vertex id order.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|), linear in the number of vertices.
+ * 
+ * \sa \ref igraph_layout_circle() and other layout generators.
+ */
+
+int igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res,
+		       igraph_integer_t center, const igraph_vector_t *order) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int c=center;
+  long int i;
+  igraph_real_t step;
+  igraph_real_t phi;
+
+  if (order && igraph_vector_size(order) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid order vector length", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
+
+  if (no_of_nodes==1) {
+    MATRIX(*res, 0, 0) = MATRIX(*res, 0, 1) = 0.0; 
+  } else {
+    for (i=0, step=2*M_PI/(no_of_nodes-1), phi=0; 
+	 i<no_of_nodes; i++) {
+      long int node = order ? (long int) VECTOR(*order)[i] : i;
+      if (node != c) { 
+	MATRIX(*res, node, 0) = cos(phi);
+	MATRIX(*res, node, 1) = sin(phi);
+	phi += step;
+      } else {
+	MATRIX(*res, node, 0) = MATRIX(*res, node, 1) = 0.0;
+      }
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_layout_sphere
+ * \brief Places vertices (more or less) uniformly on a sphere.
+ *
+ * </para><para> 
+ * The algorithm was described in the following paper:
+ * Distributing many points on a sphere by E.B. Saff and
+ * A.B.J. Kuijlaars, \emb Mathematical Intelligencer \eme 19.1 (1997)
+ * 5--11.  
+ * 
+ * \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.
+ * \return Error code. The current implementation always returns with
+ * success. 
+ * 
+ * Added in version 0.2.</para><para>
+ *
+ * Time complexity: O(|V|), the number of vertices in the graph.
+ */
+
+int igraph_layout_sphere(const igraph_t *graph, igraph_matrix_t *res) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  igraph_real_t h;
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3));
+
+  if (no_of_nodes != 0) {
+    MATRIX(*res, 0, 0)=M_PI;
+    MATRIX(*res, 0, 1)=0;
+  }
+  for (i=1; i<no_of_nodes-1; i++) {
+    h = -1 + 2*i/(double)(no_of_nodes-1);
+    MATRIX(*res, i, 0) = acos(h);
+    MATRIX(*res, i, 1) = fmod((MATRIX(*res, i-1, 1) +
+			       3.6/sqrt(no_of_nodes*(1-h*h))), 2*M_PI);
+    IGRAPH_ALLOW_INTERRUPTION();
+  }
+  if (no_of_nodes >=2) {
+    MATRIX(*res, no_of_nodes-1, 0)=0;
+    MATRIX(*res, no_of_nodes-1, 1)=0;
+  }
+
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_real_t x=cos(MATRIX(*res, i, 1))*sin(MATRIX(*res, i, 0));
+    igraph_real_t y=sin(MATRIX(*res, i, 1))*sin(MATRIX(*res, i, 0));
+    igraph_real_t z=cos(MATRIX(*res, i, 0));
+    MATRIX(*res, i, 0)=x;
+    MATRIX(*res, i, 1)=y;
+    MATRIX(*res, i, 2)=z;
+    IGRAPH_ALLOW_INTERRUPTION();
+  }
+  
+  return 0;
+}
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_grid
+ * \brief Places the vertices on a regular grid on the plane.
+ *
+ * \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 width The number of vertices in a single row of the grid.
+ *        When zero or negative, the width of the grid will be the
+ *        square root of the number of vertices, rounded up if needed.
+ * \return Error code. The current implementation always returns with
+ *         success. 
+ * 
+ * Time complexity: O(|V|), the number of vertices. 
+ */
+int igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, long int width) {
+  long int i, no_of_nodes=igraph_vcount(graph);
+  igraph_real_t x, y;
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));  
+
+  if (width <= 0) {
+    width = (long int) ceil(sqrt(no_of_nodes));
+  }
+
+  x = y = 0;
+  for (i = 0; i < no_of_nodes; i++) {
+    MATRIX(*res, i, 0) = x++;
+    MATRIX(*res, i, 1) = y;
+    if (x == width) {
+      x = 0; y++;
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_grid_3d
+ * \brief Places the vertices on a regular grid in the 3D space.
+ *
+ * \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 width  The number of vertices in a single row of the grid. When
+ *               zero or negative, the width is determined automatically.
+ * \param height The number of vertices in a single column of the grid. When
+ *               zero or negative, the height is determined automatically.
+ *
+ * \return Error code. The current implementation always returns with
+ *         success. 
+ * 
+ * Time complexity: O(|V|), the number of vertices. 
+ */
+int igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res,
+    long int width, long int height) {
+  long int i, no_of_nodes=igraph_vcount(graph);
+  igraph_real_t x, y, z;
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3));  
+
+  if (width <= 0 && height <= 0) {
+    width = height = (long int) ceil(pow(no_of_nodes, 1.0 / 3));
+  } else if (width <= 0) {
+    width = (long int) ceil(sqrt(no_of_nodes / (double)height));
+  } else if (height <= 0) {
+    height = (long int) ceil(sqrt(no_of_nodes / (double)width));
+  }
+
+  x = y = z = 0;
+  for (i = 0; i < no_of_nodes; i++) {
+    MATRIX(*res, i, 0) = x++;
+    MATRIX(*res, i, 1) = y;
+    MATRIX(*res, i, 2) = z;
+    if (x == width) {
+      x = 0; y++;
+      if (y == height) {
+        y = 0; z++;
+      }
+    }
+  }
+  
+  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) {
+
+  IGRAPH_UNUSED(graph); IGRAPH_UNUSED(res); IGRAPH_UNUSED(mass);
+  IGRAPH_UNUSED(equil); IGRAPH_UNUSED(k); IGRAPH_UNUSED(repeqdis);
+  IGRAPH_UNUSED(kfr); IGRAPH_UNUSED(repulse);
+  IGRAPH_ERROR("Springs layout not implemented", IGRAPH_UNIMPLEMENTED);
+  /* TODO */
+  return 0;
+}
+
+void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y);
+
+void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y) {
+  igraph_real_t len=sqrt((*x)*(*x) + (*y)*(*y));
+  if (len != 0) {
+    *x /= len;
+    *y /= len;
+  }
+}
+
+/**
+ * \function igraph_layout_lgl
+ * \brief Force based layout algorithm for large graphs.
+ * 
+ * </para><para>
+ * This is a layout generator similar to the Large Graph Layout
+ * algorithm and program
+ * (http://lgl.sourceforge.net/). But unlike LGL, this
+ * version uses a Fruchterman-Reingold style simulated annealing
+ * algorithm for placing the vertices. The speedup is achieved by
+ * placing the vertices on a grid and calculating the repulsion only
+ * for vertices which are closer to each other than a limit. 
+ * 
+ * \param graph The (initialized) graph object to place.
+ * \param res Pointer to an initialized matrix object to hold the
+ *   result. It will be resized if needed.
+ * \param maxit The maximum number of cooling iterations to perform
+ *   for each layout step. A reasonable default is 150.
+ * \param maxdelta The maximum length of the move allowed for a vertex
+ *   in a single iteration. A reasonable default is the number of
+ *   vertices.
+ * \param area This parameter gives the area of the square on which
+ *   the vertices will be placed. A reasonable default value is the
+ *   number of vertices squared.
+ * \param coolexp The cooling exponent. A reasonable default value is
+ *   1.5.
+ * \param repulserad Determines the radius at which vertex-vertex 
+ *   repulsion cancels out attraction of adjacent vertices. A
+ *   reasonable default value is \p area times the number of vertices.
+ * \param cellsize The size of the grid cells, one side of the
+ *   square. A reasonable default value 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 proot The root vertex, this is placed first, its neighbors
+ *   in the first iteration, second neighbors in the second, etc. If
+ *   negative then a random vertex is chosen.
+ * \return Error code.
+ * 
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: ideally O(dia*maxit*(|V|+|E|)), |V| is the number
+ * of vertices, 
+ * dia is the diameter of the graph, worst case complexity is still 
+ * O(dia*maxit*(|V|^2+|E|)), this is the case when all vertices happen to be
+ * in the same grid cell. 
+ */
+
+int igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res,
+		      igraph_integer_t maxit, igraph_real_t maxdelta, 
+		      igraph_real_t area, igraph_real_t coolexp,
+		      igraph_real_t repulserad, igraph_real_t cellsize, 
+		      igraph_integer_t proot) {
+  
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_t mst;
+  long int root;
+  long int no_of_layers, actlayer=0;
+  igraph_vector_t vids;
+  igraph_vector_t layers;
+  igraph_vector_t parents;
+  igraph_vector_t edges;
+  igraph_2dgrid_t grid;  
+  igraph_vector_t eids;
+  igraph_vector_t forcex;
+  igraph_vector_t forcey;
+
+  igraph_real_t frk=sqrt(area/no_of_nodes);
+  igraph_real_t H_n=0;
+
+  IGRAPH_CHECK(igraph_minimum_spanning_tree_unweighted(graph, &mst));
+  IGRAPH_FINALLY(igraph_destroy, &mst);
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
+  
+  /* Determine the root vertex, random pick right now */
+  if (proot < 0) {
+    root=RNG_INTEGER(0, no_of_nodes-1);
+  } else {
+    root=proot;
+  }
+
+  /* Assign the layers */
+  IGRAPH_VECTOR_INIT_FINALLY(&vids, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&layers, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&parents, 0);
+  IGRAPH_CHECK(igraph_i_bfs(&mst, (igraph_integer_t) root, IGRAPH_ALL, &vids, 
+			    &layers, &parents));
+  no_of_layers=igraph_vector_size(&layers)-1;
+  
+  /* We don't need the mst any more */
+  igraph_destroy(&mst);
+  igraph_empty(&mst, 0, IGRAPH_UNDIRECTED); /* to make finalization work */
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges));
+  IGRAPH_VECTOR_INIT_FINALLY(&eids, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&forcex, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&forcey, no_of_nodes);
+
+  /* Place the vertices randomly */
+  IGRAPH_CHECK(igraph_layout_random(graph, res));
+  igraph_matrix_scale(res, 1e6);
+  
+  /* This is the grid for calculating the vertices near to a given vertex */  
+  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 the root vertex */
+  igraph_2dgrid_add(&grid, root, 0, 0);
+
+  for (actlayer=1; actlayer<no_of_layers; actlayer++) {
+    H_n += 1.0/actlayer;
+  }
+
+  for (actlayer=1; actlayer<no_of_layers; actlayer++) {
+
+    igraph_real_t c=1;
+    long int i, j;
+    igraph_real_t massx, massy;
+    igraph_real_t px, py;
+    igraph_real_t sx, sy;
+
+    long int it=0;
+    igraph_real_t epsilon=10e-6;
+    igraph_real_t maxchange=epsilon+1;
+    long int pairs;
+    igraph_real_t sconst=sqrt(area/M_PI) / H_n; 
+    igraph_2dgrid_iterator_t vidit;
+
+/*     printf("Layer %li:\n", actlayer); */
+    
+    /*-----------------------------------------*/
+    /* Step 1: place the next layer on spheres */
+    /*-----------------------------------------*/
+
+    RNG_BEGIN();
+
+    j=(long int) VECTOR(layers)[actlayer];
+    for (i=(long int) VECTOR(layers)[actlayer-1]; 
+	 i<VECTOR(layers)[actlayer]; i++) {
+
+      long int vid=(long int) VECTOR(vids)[i];
+      long int par=(long int) VECTOR(parents)[vid];
+      IGRAPH_ALLOW_INTERRUPTION();
+      igraph_2dgrid_getcenter(&grid, &massx, &massy);
+      igraph_i_norm2d(&massx, &massy);
+      px=MATRIX(*res, vid, 0)-MATRIX(*res, par, 0);
+      py=MATRIX(*res, vid, 1)-MATRIX(*res, par, 1);
+      igraph_i_norm2d(&px, &py);
+      sx=c*(massx+px)+MATRIX(*res, vid, 0);
+      sy=c*(massy+py)+MATRIX(*res, vid, 1);
+
+      /* The neighbors of 'vid' */
+      while (j < VECTOR(layers)[actlayer+1] && 
+	     VECTOR(parents)[(long int)VECTOR(vids)[j]]==vid) {
+	igraph_real_t rx, ry;
+	if (actlayer==1) {
+	  igraph_real_t phi=2*M_PI/(VECTOR(layers)[2]-1)*(j-1);
+	  rx=cos(phi);
+	  ry=sin(phi);
+	} else {
+	  rx=RNG_UNIF(-1,1);
+	  ry=RNG_UNIF(-1,1);
+	}
+	igraph_i_norm2d(&rx, &ry);
+	rx = rx / actlayer * sconst;
+	ry = ry / actlayer * sconst;
+	igraph_2dgrid_add(&grid, (long int) VECTOR(vids)[j], sx+rx, sy+ry);
+	j++; 
+      }
+    }
+
+    RNG_END();
+    
+    /*-----------------------------------------*/
+    /* Step 2: add the edges of the next layer */
+    /*-----------------------------------------*/
+
+    for (j=(long int) VECTOR(layers)[actlayer]; 
+	 j<VECTOR(layers)[actlayer+1]; j++) {
+      long int vid=(long int) VECTOR(vids)[j];
+      long int k;
+      IGRAPH_ALLOW_INTERRUPTION();
+      IGRAPH_CHECK(igraph_incident(graph, &eids, (igraph_integer_t) vid, 
+				   IGRAPH_ALL));
+      for (k=0;k<igraph_vector_size(&eids);k++) {
+	long int eid=(long int) VECTOR(eids)[k];
+	igraph_integer_t from, to;
+	igraph_edge(graph, (igraph_integer_t) eid, &from, &to);
+	if ((from != vid && igraph_2dgrid_in(&grid, from)) ||
+	    (to   != vid && igraph_2dgrid_in(&grid, to))) {
+	  igraph_vector_push_back(&edges, eid);
+	}
+      }
+    }
+
+    /*-----------------------------------------*/
+    /* Step 3: let the springs spring          */
+    /*-----------------------------------------*/
+    
+    maxchange=epsilon+1;
+    while (it < maxit && maxchange > epsilon) {
+      long int jj;
+      igraph_real_t t=maxdelta*pow((maxit-it)/(double)maxit, coolexp);
+      long int vid, nei;
+
+	  IGRAPH_PROGRESS("Large graph layout",
+	    100.0*((actlayer-1.0)/(no_of_layers-1.0)+((float)it)/(maxit*(no_of_layers-1.0))),
+		0);
+
+      /* init */
+      igraph_vector_null(&forcex);
+      igraph_vector_null(&forcey);
+      maxchange=0;
+      
+      /* attractive "forces" along the edges */
+      for (jj=0; jj<igraph_vector_size(&edges); jj++) {
+	igraph_integer_t from, to;
+	igraph_real_t xd, yd, dist, force;
+	IGRAPH_ALLOW_INTERRUPTION();
+	igraph_edge(graph, (igraph_integer_t) VECTOR(edges)[jj], &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;
+	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;
+      }
+      
+      /* repulsive "forces" of the vertices nearby */
+      pairs=0;
+      igraph_2dgrid_reset(&grid, &vidit);
+      while ( (vid=igraph_2dgrid_next(&grid, &vidit)-1) != -1) {
+	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) {
+	    pairs++;
+	    if (dist==0) { dist=epsilon; };
+	    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;	    
+	  }
+	}
+      }
+      
+/*       printf("verties: %li iterations: %li\n",  */
+/* 	     (long int) VECTOR(layers)[actlayer+1], pairs); */
+      
+      /* apply the changes */
+      for (jj=0; jj<VECTOR(layers)[actlayer+1]; jj++) {
+	long int vvid=(long int) VECTOR(vids)[jj];
+	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);
+	if (fx > maxchange) { maxchange=fx; }
+	if (fy > maxchange) { maxchange=fy; }
+      }
+      it++;
+/*       printf("%li iterations, maxchange: %f\n", it, (double)maxchange); */
+    }
+  }
+
+  IGRAPH_PROGRESS("Large graph layout", 100.0, 0);
+  igraph_destroy(&mst);
+  igraph_vector_destroy(&vids);
+  igraph_vector_destroy(&layers);
+  igraph_vector_destroy(&parents);
+  igraph_vector_destroy(&edges);
+  igraph_2dgrid_destroy(&grid);
+  igraph_vector_destroy(&eids);
+  igraph_vector_destroy(&forcex);
+  igraph_vector_destroy(&forcey);
+  IGRAPH_FINALLY_CLEAN(9);
+  return 0;
+
+}
+
+/**
+ * \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 */
+  long int level;         /* Level of the node */
+  igraph_real_t offset;     /* X offset from parent node */
+  long int left_contour;  /* Next left node of the contour
+		      of the subtree rooted at this node */
+  long int right_contour; /* Next right node of the contour
+		      of the subtree rooted at this node */
+  igraph_real_t offset_follow_lc;  /* X offset when following the left contour */
+  igraph_real_t offset_follow_rc;  /* X offset when following the right contour */
+};
+
+int igraph_i_layout_reingold_tilford_postorder(struct igraph_i_reingold_tilford_vertex *vdata,
+                                               long int node, long int vcount);
+int igraph_i_layout_reingold_tilford_calc_coords(struct igraph_i_reingold_tilford_vertex *vdata,
+                                                 igraph_matrix_t *res, long int node,
+												 long int vcount, igraph_real_t xpos);
+
+int igraph_i_layout_reingold_tilford(const igraph_t *graph, 
+				     igraph_matrix_t *res, 
+				     igraph_neimode_t mode, 
+				     long int root);
+int igraph_i_layout_reingold_tilford(const igraph_t *graph, 
+				     igraph_matrix_t *res, igraph_neimode_t mode, 
+				     long int root) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, n, j;
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  igraph_adjlist_t allneis;
+  igraph_vector_int_t *neis;
+  struct igraph_i_reingold_tilford_vertex *vdata;
+    
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, mode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+  
+  vdata=igraph_Calloc(no_of_nodes, struct igraph_i_reingold_tilford_vertex);
+  if (vdata==0) {
+    IGRAPH_ERROR("igraph_layout_reingold_tilford failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, vdata);
+
+  for (i=0; i<no_of_nodes; i++) {
+    vdata[i].parent=-1;
+    vdata[i].level=-1;
+    vdata[i].offset=0.0;
+    vdata[i].left_contour=-1;
+    vdata[i].right_contour=-1;
+    vdata[i].offset_follow_lc=0.0;
+    vdata[i].offset_follow_rc=0.0;
+  }
+  vdata[root].parent=root;
+  vdata[root].level=0;
+  MATRIX(*res, root, 1) = 0;
+  
+  /* Step 1: assign Y coordinates based on BFS and setup parents vector */
+  IGRAPH_CHECK(igraph_dqueue_push(&q, root));
+  IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+  while (!igraph_dqueue_empty(&q)) {
+    long int actnode=(long int) igraph_dqueue_pop(&q);
+    long int actdist=(long int) igraph_dqueue_pop(&q);
+    neis=igraph_adjlist_get(&allneis, actnode);
+    n=igraph_vector_int_size(neis);
+    for (j=0; j<n; j++) {
+      long int neighbor=(long int) VECTOR(*neis)[j];
+      if (vdata[neighbor].parent >= 0) { continue; }
+      MATRIX(*res, neighbor, 1)=actdist+1;
+      IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+      IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+      vdata[neighbor].parent = actnode;
+      vdata[neighbor].level = actdist+1;
+    }
+  }
+  
+  /* Step 2: postorder tree traversal, determines the appropriate X
+   * offsets for every node */
+  igraph_i_layout_reingold_tilford_postorder(vdata, root, no_of_nodes);
+  
+  /* Step 3: calculate real coordinates based on X offsets */
+  igraph_i_layout_reingold_tilford_calc_coords(vdata, res, root, no_of_nodes, vdata[root].offset);
+  
+  igraph_dqueue_destroy(&q);
+  igraph_adjlist_destroy(&allneis);
+  igraph_free(vdata);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  IGRAPH_PROGRESS("Reingold-Tilford tree layout", 100.0, NULL);
+  
+  return 0;
+}
+
+int igraph_i_layout_reingold_tilford_calc_coords(struct igraph_i_reingold_tilford_vertex *vdata,
+                                                 igraph_matrix_t *res, long int node,
+												 long int vcount, igraph_real_t xpos) {
+  long int i;
+  MATRIX(*res, node, 0) = xpos;
+  for (i=0; i<vcount; i++) {
+    if (i == node) continue;
+    if (vdata[i].parent == node) {
+      igraph_i_layout_reingold_tilford_calc_coords(vdata, res, i, vcount,
+						   xpos+vdata[i].offset);
+    }
+  }
+  return 0;
+}
+
+int igraph_i_layout_reingold_tilford_postorder(struct igraph_i_reingold_tilford_vertex *vdata,
+                                               long int node, long int vcount) {
+  long int i, j, childcount, leftroot, leftrootidx;
+  igraph_real_t avg;
+  
+  /* printf("Starting visiting node %d\n", node); */
+  
+  /* Check whether this node is a leaf node */
+  childcount=0;
+  for (i=0; i<vcount; i++) {
+    if (i == node) continue;
+    if (vdata[i].parent == node) {
+      /* Node i is a child, so visit it recursively */
+      childcount++;
+      igraph_i_layout_reingold_tilford_postorder(vdata, i, vcount);
+    }
+  }
+  
+  if (childcount == 0) return 0;
+  
+  /* Here we can assume that all of the subtrees have been placed and their
+   * left and right contours are calculated. Let's place them next to each
+   * other as close as we can.
+   * We will take each subtree in an arbitrary order. The root of the
+   * first one will be placed at offset 0, the next ones will be placed
+   * as close to each other as possible. leftroot stores the root of the
+   * rightmost subtree of the already placed subtrees - its right contour
+   * will be checked against the left contour of the next subtree */
+  leftroot=leftrootidx=-1;
+  avg=0.0;
+  /*printf("Visited node %d and arranged its subtrees\n", node);*/
+  for (i=0, j=0; i<vcount; i++) {
+    if (i == node) continue;
+    if (vdata[i].parent == node) {
+      /*printf("  Placing child %d on level %d\n", i, vdata[i].level);*/
+      if (leftroot >= 0) {
+        /* Now we will follow the right contour of leftroot and the
+         * left contour of the subtree rooted at i */
+        long lnode, rnode;
+        igraph_real_t loffset, roffset, minsep, rootsep;
+        lnode = leftroot; rnode = i;
+        minsep = 1;
+        rootsep = vdata[leftroot].offset + minsep;
+        loffset = 0; roffset = minsep;
+        /*printf("    Contour: [%d, %d], offsets: [%lf, %lf], rootsep: %lf\n",
+               lnode, rnode, loffset, roffset, rootsep);*/
+        while ((lnode >= 0) && (rnode >= 0)) {
+          /* Step to the next level on the right contour of the left subtree */
+          if (vdata[lnode].right_contour >= 0) {
+            loffset += vdata[lnode].offset_follow_rc;
+            lnode = vdata[lnode].right_contour;
+          } else {
+            /* Left subtree ended there. The right contour of the left subtree
+             * will continue to the next step on the right subtree. */
+            if (vdata[rnode].left_contour >= 0) {
+              /*printf("      Left subtree ended, continuing left subtree's left and right contour on right subtree (node %ld)\n", vdata[rnode].left_contour);*/
+              vdata[lnode].left_contour = vdata[rnode].left_contour;
+              vdata[lnode].right_contour = vdata[rnode].left_contour;
+              vdata[lnode].offset_follow_lc = vdata[lnode].offset_follow_rc =
+                (roffset-loffset)+vdata[rnode].offset_follow_lc;
+              /*printf("      vdata[lnode].offset_follow_* = %.4f\n", vdata[lnode].offset_follow_lc);*/
+            }
+            lnode = -1;
+          }
+          /* Step to the next level on the left contour of the right subtree */
+          if (vdata[rnode].left_contour >= 0) {
+            roffset += vdata[rnode].offset_follow_lc;
+            rnode = vdata[rnode].left_contour;
+          } else {
+            /* Right subtree ended here. The left contour of the right
+             * subtree will continue to the next step on the left subtree.
+             * Note that lnode has already been advanced here */
+            if (lnode >= 0) {
+              /*printf("      Right subtree ended, continuing right subtree's left and right contour on left subtree (node %ld)\n", lnode);*/
+              vdata[rnode].left_contour = lnode;
+              vdata[rnode].right_contour = lnode;
+              vdata[rnode].offset_follow_lc = vdata[rnode].offset_follow_rc =
+                (loffset-roffset);  /* loffset has also been increased earlier */
+              /*printf("      vdata[rnode].offset_follow_* = %.4f\n", vdata[rnode].offset_follow_lc);*/
+            }
+            rnode = -1;
+          }
+          /*printf("    Contour: [%d, %d], offsets: [%lf, %lf], rootsep: %lf\n", 
+                 lnode, rnode, loffset, roffset, rootsep);*/
+      
+          /* Push subtrees away if necessary */
+          if ((lnode >= 0) && (rnode >= 0) && (roffset - loffset < minsep)) {
+            /*printf("    Pushing right subtree away by %lf\n", minsep-roffset+loffset);*/
+            rootsep += minsep-roffset+loffset;
+            roffset = loffset+minsep;
+          }
+        }
+
+        /*printf("  Offset of subtree with root node %d will be %lf\n", i, rootsep);*/
+        vdata[i].offset = rootsep;
+        vdata[node].right_contour = i;
+        vdata[node].offset_follow_rc = rootsep;
+        avg = (avg*j)/(j+1) + rootsep/(j+1);
+        leftrootidx=j;
+        leftroot=i;
+      } else {
+        leftrootidx=j;
+        leftroot=i;
+        vdata[node].left_contour=i;
+        vdata[node].right_contour=i;
+        vdata[node].offset_follow_lc = 0.0;
+        vdata[node].offset_follow_rc = 0.0;
+        avg = vdata[i].offset; 
+      }
+      j++;
+    }
+  }
+  /*printf("Shifting node to be centered above children. Shift amount: %lf\n", avg);*/
+  vdata[node].offset_follow_lc -= avg;
+  vdata[node].offset_follow_rc -= avg;
+  for (i=0, j=0; i<vcount; i++) {
+    if (i == node) continue;
+    if (vdata[i].parent == node) vdata[i].offset -= avg;
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_layout_reingold_tilford
+ * \brief Reingold-Tilford layout for tree graphs
+ * 
+ * </para><para>
+ * 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, see:
+ * 
+ * </para><para>
+ * Reingold, E and Tilford, J: Tidier drawing of trees.
+ * IEEE Trans. Softw. Eng., SE-7(2):223--228, 1981
+ *
+ * </para><para>
+ * If the given graph is not a tree, a breadth-first search is executed
+ * first to obtain a possible spanning tree.
+ * 
+ * \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 mode Specifies which edges to consider when building the tree.
+ *   If it is \c IGRAPH_OUT then only the outgoing, if it is \c IGRAPH_IN
+ *   then only the incoming edges of a parent are considered. If it is 
+ *   \c IGRAPH_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 \p roots parameter.
+ * \param roots 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 a null pointer of a pointer to an empty vector, then the root
+ *   vertices are automatically calculated based on topological sorting,
+ *   performed with the opposite mode than the \p mode argument.
+ *   After the vertices have been sorted, one is selected from each component.
+ * \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 not a null pointer and the \p roots argument is also given 
+ *   (and it is not a null pointer of an empty vector).
+ * \return Error code.
+ *
+ * Added in version 0.2.
+ * 
+ * \sa \ref igraph_layout_reingold_tilford_circular().
+ * 
+ * \example examples/simple/igraph_layout_reingold_tilford.c
+ */
+
+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) {
+
+  long int no_of_nodes_orig=igraph_vcount(graph);
+  long int no_of_nodes=no_of_nodes_orig;
+  long int real_root;
+  igraph_t extended;
+  const igraph_t *pextended=graph;
+  igraph_vector_t myroots;
+  const igraph_vector_t *proots=roots;
+  igraph_neimode_t mode2;
+  
+  /* TODO: possible speedup could be achieved if we use a table for storing
+   * the children of each node in the tree. (Now the implementation uses a
+   * single array containing the parent of each node and a node's children
+   * are determined by looking for other nodes that have this node as parent)
+   */
+
+  if (!igraph_is_directed(graph)) {
+    mode=IGRAPH_ALL;
+  }
+  if (mode==IGRAPH_IN) {
+    mode2=IGRAPH_OUT;
+  } else if (mode==IGRAPH_OUT) {
+    mode2=IGRAPH_IN;
+  } else {
+    mode2=mode;
+  }
+
+  if ( (!roots || igraph_vector_size(roots)==0) && 
+       rootlevel && igraph_vector_size(rootlevel) != 0 ) {
+    IGRAPH_WARNING("Reingold-Tilford layout: 'rootlevel' ignored");
+  }
+
+  /* ----------------------------------------------------------------------- */
+  /* If root vertices are not given, then do a topological sort and take 
+     the last element from every component for directed graphs, or select the
+     vertex with the maximum degree from each component for undirected graphs */
+
+  if (!roots || igraph_vector_size(roots)==0) {
+    
+    igraph_vector_t order, membership;
+    igraph_integer_t no_comps;
+    long int i, noseen=0;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&myroots, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);
+    IGRAPH_VECTOR_INIT_FINALLY(&membership, no_of_nodes);
+
+    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));
+    } else {
+      IGRAPH_CHECK(igraph_sort_vertex_ids_by_degree(graph, &order,
+            igraph_vss_all(), IGRAPH_ALL, 0, IGRAPH_ASCENDING, 0));
+      IGRAPH_CHECK(igraph_clusters(graph, &membership, /*csize=*/ 0, 
+        &no_comps, IGRAPH_WEAK));
+    }
+    
+    IGRAPH_CHECK(igraph_vector_resize(&myroots, no_comps));
+    igraph_vector_null(&myroots);
+    proots=&myroots;
+    for (i=no_of_nodes-1; noseen < no_comps && i>=0; i--) {
+      long int v=(long int) VECTOR(order)[i];
+      long int mem=(long int) VECTOR(membership)[v];
+      if (VECTOR(myroots)[mem]==0) {
+        noseen += 1;
+        VECTOR(myroots)[mem]=v+1;
+      }
+    }
+
+    for (i=0; i<no_comps; i++) {
+      VECTOR(myroots)[i] -= 1;
+    }
+
+    igraph_vector_destroy(&membership);
+    igraph_vector_destroy(&order);
+    IGRAPH_FINALLY_CLEAN(2);
+
+  } else if (rootlevel && igraph_vector_size(rootlevel) > 0 &&
+	     igraph_vector_size(roots) > 1) {
+
+  /* ----------------------------------------------------------------------- */
+  /* Many roots were given to us, check 'rootlevel' */
+
+    long int plus_levels=0;
+    long int i;
+    
+    if (igraph_vector_size(roots) != igraph_vector_size(rootlevel)) {
+      IGRAPH_ERROR("Reingold-Tilford: 'roots' and 'rootlevel' lengths differ",
+		   IGRAPH_EINVAL);
+    }
+
+    /* check if there is one which is not zero */
+    for (i=0; i<igraph_vector_size(roots); i++) {
+      plus_levels += VECTOR(*rootlevel)[i];
+    }
+
+    /* make copy of graph, add vertices/edges */
+    if (plus_levels != 0) {
+      igraph_vector_t newedges;
+      long int edgeptr=0;
+
+      pextended=&extended;
+      IGRAPH_CHECK(igraph_copy(&extended, graph));
+      IGRAPH_FINALLY(igraph_destroy, &extended);
+      IGRAPH_CHECK(igraph_add_vertices(&extended, 
+				       (igraph_integer_t) plus_levels, 0));
+
+      IGRAPH_VECTOR_INIT_FINALLY(&newedges, plus_levels*2);
+
+      for (i=0; i<igraph_vector_size(roots); i++) {
+	long int rl=(long int) VECTOR(*rootlevel)[i];
+	long int rn=(long int) VECTOR(*roots)[i];
+	long int j;
+
+	if (rl==0) { continue; }
+
+	VECTOR(newedges)[edgeptr++] = no_of_nodes;
+	VECTOR(newedges)[edgeptr++] = rn;
+	
+	for (j=0; j<rl-1; j++) {
+	  VECTOR(newedges)[edgeptr++] = no_of_nodes+1;
+	  VECTOR(newedges)[edgeptr++] = no_of_nodes;
+	  no_of_nodes++;
+	}
+
+	VECTOR(*roots)[i]=no_of_nodes++;
+      }
+      
+      /* Opposite direction if mode=="in" */
+      if (mode==IGRAPH_IN) {
+	for (i=0; i<igraph_vector_size(&newedges); i+=2) {
+	  igraph_real_t tmp=VECTOR(newedges)[i];
+	  VECTOR(newedges)[i] = VECTOR(newedges)[i+1];
+	  VECTOR(newedges)[i+1] = tmp;
+	}
+      }
+
+      IGRAPH_CHECK(igraph_add_edges(&extended, &newedges, 0));
+      igraph_vector_destroy(&newedges);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+  
+  /* ----------------------------------------------------------------------- */
+  /* Ok, we have the root vertices now. 
+     Possibly we need to add some edges to make the graph connected. */
+
+  if (igraph_vector_size(proots)==1) {
+    real_root=(long int) VECTOR(*proots)[0];
+    if (real_root<0 || real_root>=no_of_nodes) {
+      IGRAPH_ERROR("invalid vertex id", IGRAPH_EINVVID);
+    }
+  } else {
+    igraph_vector_t newedges;
+    long int no_of_newedges=igraph_vector_size(proots);
+    long int i;
+    real_root=no_of_nodes;
+    
+    /* Make copy if needed */
+    if (pextended == graph) {
+      pextended=&extended;
+      IGRAPH_CHECK(igraph_copy(&extended, graph));
+      IGRAPH_FINALLY(igraph_destroy, &extended);
+    }
+
+    IGRAPH_VECTOR_INIT_FINALLY(&newedges, no_of_newedges*2);
+    IGRAPH_CHECK(igraph_add_vertices(&extended, 1, 0));
+    for (i=0; i<no_of_newedges; i++) {
+      VECTOR(newedges)[2*i] = no_of_nodes;
+      VECTOR(newedges)[2*i+1] = VECTOR(*proots)[i];
+    }
+    IGRAPH_CHECK(igraph_add_edges(&extended, &newedges, 0));
+    
+    no_of_nodes++;
+    igraph_vector_destroy(&newedges);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  /* ----------------------------------------------------------------------- */
+  /* Layout */
+
+  IGRAPH_CHECK(igraph_i_layout_reingold_tilford(pextended, res, mode, real_root));
+  
+  /* Remove the new vertices from the layout */
+  if (no_of_nodes != no_of_nodes_orig) {
+    if (no_of_nodes-1 == no_of_nodes_orig) {
+      IGRAPH_CHECK(igraph_matrix_remove_row(res, no_of_nodes_orig));
+    } else {
+      igraph_matrix_t tmp;
+      long int i;
+      IGRAPH_MATRIX_INIT_FINALLY(&tmp, no_of_nodes_orig, 2);
+      for (i=0; i<no_of_nodes_orig; i++) {
+	MATRIX(tmp, i, 0) = MATRIX(*res, i, 0);
+	MATRIX(tmp, i, 1) = MATRIX(*res, i, 1);
+      }
+      IGRAPH_CHECK(igraph_matrix_update(res, &tmp));
+      igraph_matrix_destroy(&tmp);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+  
+  if (pextended != graph) {
+    igraph_destroy(&extended);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  /* Remove the roots vector if it was created by us */
+  if (proots != roots) {
+    igraph_vector_destroy(&myroots);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_layout_reingold_tilford_circular
+ * \brief Circular Reingold-Tilford layout for trees
+ * 
+ * </para><para>
+ * This layout is almost the same as \ref igraph_layout_reingold_tilford(), but 
+ * the tree is drawn in a circular way, with the root vertex in the center.
+ * 
+ * \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 mode Specifies which edges to consider when building the tree.
+ *   If it is \c IGRAPH_OUT then only the outgoing, if it is \c IGRAPH_IN
+ *   then only the incoming edges of a parent are considered. If it is 
+ *   \c IGRAPH_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 \p roots parameter.
+ * \param roots 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 a null pointer of a pointer to an empty vector, then the root
+ *   vertices are automatically calculated based on topological sorting,
+ *   performed with the opposite mode than the \p mode argument.
+ *   After the vertices have been sorted, one is selected from each component.
+ * \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 not a null pointer and the \p roots argument is also given 
+ *   (and it is not a null pointer of an empty vector). Note that if you supply
+ *   a null pointer here and the graph has multiple components, all of the root
+ *   vertices will be mapped to the origin of the coordinate system, which does
+ *   not really make sense.
+ * \return Error code.
+ *
+ * \sa \ref igraph_layout_reingold_tilford().
+ */
+
+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) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  igraph_real_t ratio=2*M_PI*(no_of_nodes-1.0)/no_of_nodes;
+  igraph_real_t minx, maxx;
+
+  IGRAPH_CHECK(igraph_layout_reingold_tilford(graph, res, mode, roots, rootlevel));
+
+  if (no_of_nodes == 0) return 0;
+
+  minx = maxx = MATRIX(*res, 0, 0);
+  for (i=1; i<no_of_nodes; i++) {
+    if (MATRIX(*res, i, 0) > maxx) maxx=MATRIX(*res, i, 0);
+	if (MATRIX(*res, i, 0) < minx) minx=MATRIX(*res, i, 0);
+  }
+  ratio /= (maxx-minx);
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_real_t phi=(MATRIX(*res, i, 0)-minx)*ratio;
+    igraph_real_t r=MATRIX(*res, i, 1);
+    MATRIX(*res, i, 0) = r*cos(phi);
+    MATRIX(*res, i, 1) = r*sin(phi);
+  }
+  
+  return 0;
+}
+
+#define COULOMBS_CONSTANT 8987500000.0
+
+
+igraph_real_t igraph_i_distance_between(const igraph_matrix_t *c, long int a, 
+					long int b);
+
+int igraph_i_determine_electric_axal_forces(const igraph_matrix_t *pos,
+					    igraph_real_t *x,
+					    igraph_real_t *y,
+					    igraph_real_t directed_force,
+					    igraph_real_t distance,
+					    long int other_node,
+					    long int this_node);
+
+int igraph_i_apply_electrical_force(const igraph_matrix_t *pos,
+				    igraph_vector_t *pending_forces_x,
+				    igraph_vector_t *pending_forces_y,
+				    long int other_node, long int this_node,
+				    igraph_real_t node_charge, 
+				    igraph_real_t distance);
+
+int igraph_i_determine_spring_axal_forces(const igraph_matrix_t *pos,
+					  igraph_real_t *x, igraph_real_t *y,
+					  igraph_real_t directed_force,
+					  igraph_real_t distance,
+					  int spring_length,
+					  long int other_node, 
+					  long int this_node);
+
+int igraph_i_apply_spring_force(const igraph_matrix_t *pos, 
+				igraph_vector_t *pending_forces_x,
+				igraph_vector_t *pending_forces_y,
+				long int other_node,
+				long int this_node, int spring_length,
+				igraph_real_t spring_constant);
+
+int igraph_i_move_nodes(igraph_matrix_t *pos, 
+			const igraph_vector_t *pending_forces_x, 
+			const igraph_vector_t *pending_forces_y,
+			igraph_real_t node_mass,
+			igraph_real_t max_sa_movement);
+
+igraph_real_t igraph_i_distance_between(const igraph_matrix_t *c, long int a, 
+					long int b) {
+  igraph_real_t diffx=MATRIX(*c, a, 0)-MATRIX(*c, b, 0);
+  igraph_real_t diffy=MATRIX(*c, a, 1)-MATRIX(*c, b, 1);
+  return sqrt( diffx*diffx + diffy*diffy );
+} 
+
+int igraph_i_determine_electric_axal_forces(const igraph_matrix_t *pos,
+					    igraph_real_t *x,
+					    igraph_real_t *y,
+					    igraph_real_t directed_force,
+					    igraph_real_t distance,
+					    long int other_node,
+					    long int this_node) {
+  
+  // We know what the directed force is.  We now need to translate it
+  // into the appropriate x and y components.
+  // First, assume: 
+  //                 other_node
+  //                    /|
+  //  directed_force  /  |
+  //                /    | y
+  //              /______|
+  //    this_node     x         
+  //
+  // other_node.x > this_node.x
+  // other_node.y > this_node.y
+  // the force will be on this_node away from other_node
+  
+  // the proportion (distance/y_distance) is equal to the proportion
+  // (directed_force/y_force), as the two triangles are similar.
+  // therefore, the magnitude of y_force = (directed_force*y_distance)/distance
+  // the sign of y_force is negative, away from other_node
+  
+  igraph_real_t x_distance, y_distance;
+  y_distance = MATRIX(*pos, other_node, 1)-MATRIX(*pos, this_node, 1);
+  if (y_distance < 0) { y_distance = -y_distance; }
+  *y = -1 * ((directed_force * y_distance) / distance);
+
+  // the x component works in exactly the same way.
+  x_distance = MATRIX(*pos, other_node, 0)-MATRIX(*pos, this_node, 0);
+  if (x_distance < 0) { x_distance = -x_distance; }
+  *x = -1 * ((directed_force * x_distance) / distance);
+  
+   // Now we need to reverse the polarity of our answers based on the falsness
+   // of our assumptions.
+  if (MATRIX(*pos, other_node, 0) < MATRIX(*pos, this_node, 0)) {
+    *x = *x * -1;
+  }
+  if (MATRIX(*pos, other_node, 1) < MATRIX(*pos, this_node, 1)) {
+    *y = *y * -1;
+  }
+  
+  return 0;
+}
+  
+int igraph_i_apply_electrical_force(const igraph_matrix_t *pos,
+				    igraph_vector_t *pending_forces_x,
+				    igraph_vector_t *pending_forces_y,
+				    long int other_node, long int this_node,
+				    igraph_real_t node_charge, 
+				    igraph_real_t distance) {
+
+  igraph_real_t directed_force = COULOMBS_CONSTANT * 
+    ((node_charge * node_charge)/(distance * distance));
+  
+  igraph_real_t x_force, y_force;
+  igraph_i_determine_electric_axal_forces(pos, &x_force, &y_force, 
+					  directed_force, distance, 
+					  other_node, this_node);
+
+  VECTOR(*pending_forces_x)[this_node] += x_force;
+  VECTOR(*pending_forces_y)[this_node] += y_force;
+  VECTOR(*pending_forces_x)[other_node] -= x_force;
+  VECTOR(*pending_forces_y)[other_node] -= y_force;
+
+  return 0;
+}
+
+int igraph_i_determine_spring_axal_forces(const igraph_matrix_t *pos,
+					  igraph_real_t *x, igraph_real_t *y,
+					  igraph_real_t directed_force,
+					  igraph_real_t distance,
+					  int spring_length,
+					  long int other_node, long int this_node) {
+
+  // if the spring is just the right size, the forces will be 0, so we can
+  // skip the computation.
+  //
+  // if the spring is too long, our forces will be identical to those computed
+  // by determine_electrical_axal_forces() (this_node will be pulled toward
+  // other_node).
+  //
+  // if the spring is too short, our forces will be the opposite of those
+  // computed by determine_electrical_axal_forces() (this_node will be pushed
+  // away from other_node)
+  //
+  // finally, since both nodes are movable, only one-half of the total force
+  // should be applied to each node, so half the forces for our answer.
+  
+  if (distance == spring_length) {
+    *x = 0.0;
+    *y = 0.0;
+  } else {
+    igraph_i_determine_electric_axal_forces(pos, x, y, directed_force, distance, 
+					    other_node, this_node);
+    if (distance < spring_length) {
+      *x = -1 * *x;
+      *y = -1 * *y;
+    }
+    *x = 0.5 * *x;
+    *y = 0.5 * *y;
+  }
+  
+  return 0;
+}
+
+int igraph_i_apply_spring_force(const igraph_matrix_t *pos, 
+				igraph_vector_t *pending_forces_x,
+				igraph_vector_t *pending_forces_y,
+				long int other_node,
+				long int this_node, int spring_length,
+				igraph_real_t spring_constant) {
+
+  // determined using Hooke's Law:
+  //   force = -kx
+  // where:
+  //   k = spring constant
+  //   x = displacement from ideal length in meters
+  
+  igraph_real_t distance, displacement, directed_force, x_force, y_force;
+  distance = igraph_i_distance_between(pos, other_node, this_node);
+  // let's protect ourselves from division by zero by ignoring two nodes that
+  // happen to be in the same place.  Since we separate all nodes before we
+  // work on any of them, this will only happen in extremely rare circumstances,
+  // and when it does, electrical force will probably push one or both of them
+   // one way or another anyway.
+  if (distance == 0.0) {
+    return 0;
+  }
+  
+  displacement = distance - spring_length;
+  if (displacement < 0) {
+    displacement = -displacement;
+  }
+  directed_force = -1 * spring_constant * displacement;
+  // remember, this is force directed away from the spring;
+  // a negative number is back towards the spring (or, in our case, back towards
+   // the other node)
+  
+  // get the force that should be applied to >this< node
+  igraph_i_determine_spring_axal_forces(pos, &x_force, &y_force, 
+					directed_force, distance, spring_length,
+					other_node, this_node);
+  
+  VECTOR(*pending_forces_x)[this_node] += x_force;
+  VECTOR(*pending_forces_y)[this_node] += y_force;
+  VECTOR(*pending_forces_x)[other_node] -= x_force;
+  VECTOR(*pending_forces_y)[other_node] -= y_force;
+
+  return 0;
+}
+
+int igraph_i_move_nodes(igraph_matrix_t *pos, 
+			const igraph_vector_t *pending_forces_x, 
+			const igraph_vector_t *pending_forces_y,
+			igraph_real_t node_mass,
+			igraph_real_t max_sa_movement) {
+  
+  // Since each iteration is isolated, time is constant at 1.
+  // Therefore:
+  //   Force effects acceleration.
+  //   acceleration (d(velocity)/time) = velocity
+  //   velocity (d(displacement)/time) = displacement
+  //   displacement = acceleration
+  
+  // determined using Newton's second law:
+  //   sum(F) = ma
+  // therefore:
+  //   acceleration = force / mass
+  //   velocity     = force / mass
+  //   displacement = force / mass
+
+  long int this_node, no_of_nodes=igraph_vector_size(pending_forces_x);
+
+  for (this_node=0; this_node < no_of_nodes; this_node++) {
+
+    igraph_real_t x_movement, y_movement;
+
+    x_movement = VECTOR(*pending_forces_x)[this_node] / node_mass;
+    if (x_movement > max_sa_movement) {
+      x_movement = max_sa_movement;
+    } else if (x_movement < -max_sa_movement) {
+      x_movement = -max_sa_movement;
+    }
+
+    y_movement = VECTOR(*pending_forces_y)[this_node] / node_mass;
+    if (y_movement > max_sa_movement) {
+      y_movement = max_sa_movement;
+    } else if (y_movement < -max_sa_movement) {
+      y_movement = -max_sa_movement;
+    }
+
+    MATRIX(*pos, this_node, 0) += x_movement;
+    MATRIX(*pos, this_node, 1) += y_movement;
+
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_layout_graphopt
+ * \brief Optimizes vertex layout via the graphopt algorithm.
+ * 
+ * </para><para>
+ * This 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 unnecessary steps is the node charge (see below) 
+ * is zero.
+ * 
+ * </para><para>
+ * 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.)
+ * 
+ * </para><para>
+ * See also http://www.schmuhl.org/graphopt/ for the original graphopt.
+ * \param graph The input graph.
+ * \param res Pointer to an initialized matrix, the result will be stored here
+ *    and its initial contents is used the starting point of the simulation
+ *    if the \p use_seed argument is true. Note that in this case the 
+ *    matrix should have the proper size, otherwise a warning is issued and 
+ *    the supplied values are ignored. If no starting positions are given 
+ *    (or they are invalid) then a random staring position is used. 
+ *    The matrix will be resized if needed.
+ * \param niter Integer constant, 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 \p res argument. The original graphopt default if 500.
+ * \param node_charge The charge of the vertices, used to calculate electric
+ *    repulsion. The original graphopt default is 0.001.
+ * \param node_mass The mass of the vertices, used for the spring forces.
+ *    The original graphopt defaults to 30.
+ * \param spring_length The length of the springs, an integer number.
+ *    The original graphopt defaults to zero.
+ * \param spring_constant The spring constant, the original graphopt defaults 
+ *    to one.
+ * \param max_sa_movement Real constant, it gives the maximum amount of movement 
+ *    allowed in a single step along a single axis. The original graphopt 
+ *    default is 5.
+ * \param use_seed Logical scalar, whether to use the positions in \p res as
+ *    a starting configuration. See also \p res above.
+ * \return Error code.
+ * 
+ * Time complexity: O(n (|V|^2+|E|) ), n is the number of iterations, 
+ * |V| is the number of vertices, |E| the number
+ * of edges. If \p node_charge is zero then it is only O(n|E|).
+ */
+
+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) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  int my_spring_length=(int) spring_length;
+  igraph_vector_t pending_forces_x, pending_forces_y;
+  /* Set a flag to calculate (or not) the electrical forces that the nodes */
+  /* apply on each other based on if both node types' charges are zero. */
+  igraph_bool_t apply_electric_charges= (node_charge!=0);
+  
+  long int this_node, other_node, edge;
+  igraph_real_t distance;
+  long int i;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&pending_forces_x, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&pending_forces_y, no_of_nodes);
+  
+  if (use_seed) {
+    if (igraph_matrix_nrow(res) != no_of_nodes ||
+	igraph_matrix_ncol(res) != 2) {
+      IGRAPH_WARNING("Invalid size for initial matrix, starting from random layout");
+      IGRAPH_CHECK(igraph_layout_random(graph, res));
+    }
+  } else {
+    IGRAPH_CHECK(igraph_layout_random(graph, res));
+  }
+
+  IGRAPH_PROGRESS("Graphopt layout", 0, NULL);
+  for(i=niter;i>0;i--) {
+    /* Report progress in approx. every 100th step */
+    if (i%10 == 0) {
+      IGRAPH_PROGRESS("Graphopt layout", 100.0-100.0*i/niter, NULL);
+    }
+    
+    /* Clear pending forces on all nodes */
+    igraph_vector_null(&pending_forces_x);
+    igraph_vector_null(&pending_forces_y);
+    
+    // Apply electrical force applied by all other nodes
+    if (apply_electric_charges) {
+      // Iterate through all nodes
+      for (this_node = 0; this_node < no_of_nodes; this_node++) {
+	IGRAPH_ALLOW_INTERRUPTION();
+	for (other_node = this_node + 1; 
+	     other_node < no_of_nodes; 
+	     other_node++) {
+	  distance = igraph_i_distance_between(res, this_node, other_node);
+	  // let's protect ourselves from division by zero by ignoring
+	  // two nodes that happen to be in the same place.  Since we 
+	  // separate all nodes before we work on any of them, this 
+	  // will only happen in extremely rare circumstances, and when
+	  // it does, springs will probably pull them apart anyway.
+	  // also, if we are more than 50 away, the electric force 
+	  // will be negligible.  
+	  // ***** may not always be desirable ****
+	  if ((distance != 0.0) && (distance < 500.0)) {
+	    //	  if (distance != 0.0) {
+	    // Apply electrical force from node(counter2) on 
+	    // node(counter)
+	    igraph_i_apply_electrical_force(res, &pending_forces_x, 
+					    &pending_forces_y, 
+					    other_node, this_node, 
+					    node_charge,
+					    distance);
+	  }
+	}
+      }
+    }
+      
+    // Apply force from springs
+    for (edge = 0; edge < no_of_edges; edge++) {
+      long int tthis_node=IGRAPH_FROM(graph, edge);
+      long int oother_node=IGRAPH_TO(graph, edge);
+      // Apply spring force on both nodes
+      igraph_i_apply_spring_force(res, &pending_forces_x, &pending_forces_y,
+				  oother_node, tthis_node, my_spring_length, 
+				  spring_constant);
+    }
+  
+    // Effect the movement of the nodes based on all pending forces
+    igraph_i_move_nodes(res, &pending_forces_x, &pending_forces_y, node_mass,
+			max_sa_movement);
+  }
+  IGRAPH_PROGRESS("Graphopt layout", 100, NULL);
+
+  igraph_vector_destroy(&pending_forces_y);
+  igraph_vector_destroy(&pending_forces_x);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+int igraph_i_layout_merge_dla(igraph_i_layout_mergegrid_t *grid, 
+			      long int actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r,
+			      igraph_real_t cx, igraph_real_t cy, igraph_real_t startr, 
+			      igraph_real_t killr);
+
+int igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_real_t *x, 
+			      igraph_real_t *y, igraph_real_t *r);
+int igraph_i_layout_sphere_3d(igraph_matrix_t *coords, igraph_real_t *x,
+			      igraph_real_t *y, igraph_real_t *z,
+			      igraph_real_t *r);
+
+/**
+ * \function igraph_layout_merge_dla
+ * \brief Merge multiple layouts by using a DLA algorithm
+ * 
+ * </para><para>
+ * First each layout is covered by a circle. Then the layout of the
+ * largest graph is placed at the origin. Then the other layouts are
+ * placed by the DLA algorithm, larger ones first and smaller ones
+ * last.
+ * \param thegraphs Pointer vector containing the graph object of
+ *        which the layouts will be merged.
+ * \param coords Pointer vector containing matrix objects with the 2d
+ *        layouts of the graphs in \p thegraphs.
+ * \param res Pointer to an initialized matrix object, the result will
+ *        be stored here. It will be resized if needed.
+ * \return Error code.
+ * 
+ * Added in version 0.2. This function is experimental.
+ * 
+ * </para><para>
+ * Time complexity: TODO.
+ */
+
+int igraph_layout_merge_dla(igraph_vector_ptr_t *thegraphs,
+			    igraph_vector_ptr_t *coords, 
+			    igraph_matrix_t *res) {
+  long int graphs=igraph_vector_ptr_size(coords);
+  igraph_vector_t sizes;
+  igraph_vector_t x, y, r;
+  igraph_vector_t nx, ny, nr;
+  long int allnodes=0;
+  long int i, j;
+  long int actg;
+  igraph_i_layout_mergegrid_t grid;
+  long int jpos=0;
+  igraph_real_t minx, maxx, miny, maxy;
+  igraph_real_t area=0;
+  igraph_real_t maxr=0;
+  long int respos;
+
+  /* Graphs are currently not used, only the coordinates */
+  IGRAPH_UNUSED(thegraphs);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&sizes, graphs);
+  IGRAPH_VECTOR_INIT_FINALLY(&x, graphs);
+  IGRAPH_VECTOR_INIT_FINALLY(&y, graphs);
+  IGRAPH_VECTOR_INIT_FINALLY(&r, graphs);
+  IGRAPH_VECTOR_INIT_FINALLY(&nx, graphs);
+  IGRAPH_VECTOR_INIT_FINALLY(&ny, graphs);
+  IGRAPH_VECTOR_INIT_FINALLY(&nr, graphs);
+
+  RNG_BEGIN();
+  
+  for (i=0; i<igraph_vector_ptr_size(coords); i++) {
+    igraph_matrix_t *mat=VECTOR(*coords)[i];
+    long int size=igraph_matrix_nrow(mat);
+
+    if (igraph_matrix_ncol(mat) != 2) {
+      IGRAPH_ERROR("igraph_layout_merge_dla works for 2D layouts only",
+                   IGRAPH_EINVAL);
+    }
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    allnodes += size;
+    VECTOR(sizes)[i]=size;
+    VECTOR(r)[i]=pow(size, .75);
+    area+=VECTOR(r)[i] * VECTOR(r)[i];
+    if (VECTOR(r)[i] > maxr) {
+      maxr=VECTOR(r)[i];
+    }
+
+    igraph_i_layout_sphere_2d(mat,
+			      igraph_vector_e_ptr(&nx, i),
+			      igraph_vector_e_ptr(&ny, i),
+			      igraph_vector_e_ptr(&nr, i));
+    
+  }
+  igraph_vector_order2(&sizes);	/* largest first */
+
+  /* 0. create grid */
+  minx=miny=-sqrt(5*area);
+  maxx=maxy=sqrt(5*area);
+  igraph_i_layout_mergegrid_init(&grid, minx, maxx, 200,
+				 miny, maxy, 200);
+  IGRAPH_FINALLY(igraph_i_layout_mergegrid_destroy, &grid);
+
+/*   fprintf(stderr, "Ok, starting DLA\n"); */
+  
+  /* 1. place the largest  */
+  actg=(long int) VECTOR(sizes)[jpos++];
+  igraph_i_layout_merge_place_sphere(&grid, 0, 0, VECTOR(r)[actg], actg);
+  
+  IGRAPH_PROGRESS("Merging layouts via DLA", 0.0, NULL);
+  while (jpos<graphs) {
+    IGRAPH_ALLOW_INTERRUPTION();
+/*     fprintf(stderr, "comp: %li", jpos); */
+    IGRAPH_PROGRESS("Merging layouts via DLA", (100.0*jpos)/graphs, NULL);
+    
+    actg=(long int) VECTOR(sizes)[jpos++];
+    /* 2. random walk, TODO: tune parameters */
+    igraph_i_layout_merge_dla(&grid, actg, 
+			      igraph_vector_e_ptr(&x, actg),
+			      igraph_vector_e_ptr(&y, actg), 
+			      VECTOR(r)[actg], 0, 0,
+			      maxx, maxx+5);
+    
+    /* 3. place sphere */
+    igraph_i_layout_merge_place_sphere(&grid, VECTOR(x)[actg], VECTOR(y)[actg],
+				       VECTOR(r)[actg], actg);
+  }
+  IGRAPH_PROGRESS("Merging layouts via DLA", 100.0, NULL);
+
+  /* Create the result */
+  IGRAPH_CHECK(igraph_matrix_resize(res, allnodes, 2));
+  respos=0;
+  for (i=0; i<graphs; i++) {
+    long int size=igraph_matrix_nrow(VECTOR(*coords)[i]);
+    igraph_real_t xx=VECTOR(x)[i];
+    igraph_real_t yy=VECTOR(y)[i];
+    igraph_real_t rr=VECTOR(r)[i]/VECTOR(nr)[i];
+    igraph_matrix_t *mat=VECTOR(*coords)[i];
+    IGRAPH_ALLOW_INTERRUPTION();
+    if (VECTOR(nr)[i]==0) { rr=1; }
+    for (j=0; j<size; j++) {
+      MATRIX(*res, respos, 0)=rr*(MATRIX(*mat, j, 0)-VECTOR(nx)[i]);
+      MATRIX(*res, respos, 1)=rr*(MATRIX(*mat, j, 1)-VECTOR(ny)[i]);
+      MATRIX(*res, respos, 0)+=xx;
+      MATRIX(*res, respos, 1)+=yy;
+      ++respos;
+    }
+  }
+
+  RNG_END();
+ 
+  igraph_i_layout_mergegrid_destroy(&grid);
+  igraph_vector_destroy(&sizes);
+  igraph_vector_destroy(&x);
+  igraph_vector_destroy(&y);
+  igraph_vector_destroy(&r);
+  igraph_vector_destroy(&nx);
+  igraph_vector_destroy(&ny);
+  igraph_vector_destroy(&nr);
+  IGRAPH_FINALLY_CLEAN(8);
+  return 0;
+}
+
+int igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y,
+			      igraph_real_t *r) {
+  long int nodes=igraph_matrix_nrow(coords);
+  long int i;
+  igraph_real_t xmin, xmax, ymin, ymax;
+  
+  xmin=xmax=MATRIX(*coords,0,0);
+  ymin=ymax=MATRIX(*coords,0,1);
+  for (i=1; i<nodes; i++) {
+
+    if (MATRIX(*coords,i,0) < xmin) {
+      xmin=MATRIX(*coords,i,0);
+    } else if (MATRIX(*coords,i,0)>xmax) {
+      xmax=MATRIX(*coords,i,0);
+    }
+
+    if (MATRIX(*coords,i,1) < ymin) {
+      ymin=MATRIX(*coords,i,1);
+    } else if (MATRIX(*coords,i,1)>ymax) {
+      ymax=MATRIX(*coords,i,1);
+    }
+    
+  }
+
+  *x=(xmin+xmax)/2;
+  *y=(ymin+ymax)/2;
+  *r=sqrt( (xmax-xmin)*(xmax-xmin)+(ymax-ymin)*(ymax-ymin) ) / 2;
+
+  return 0;
+}
+
+int igraph_i_layout_sphere_3d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y,
+			      igraph_real_t *z, igraph_real_t *r) {
+  long int nodes=igraph_matrix_nrow(coords);
+  long int i;
+  igraph_real_t xmin, xmax, ymin, ymax, zmin, zmax;
+  
+  xmin=xmax=MATRIX(*coords,0,0);
+  ymin=ymax=MATRIX(*coords,0,1);
+  zmin=zmax=MATRIX(*coords,0,2);
+  for (i=1; i<nodes; i++) {
+    
+    if (MATRIX(*coords,i,0) < xmin) {
+      xmin=MATRIX(*coords,i,0);
+    } else if (MATRIX(*coords,i,0)>xmax) {
+      xmax=MATRIX(*coords,i,0);
+    }
+
+    if (MATRIX(*coords,i,1) < ymin) {
+      ymin=MATRIX(*coords,i,1);
+    } else if (MATRIX(*coords,i,1)>ymax) {
+      ymax=MATRIX(*coords,i,1);
+    }
+    
+    if (MATRIX(*coords,i,2) < zmin) {
+      zmin=MATRIX(*coords,i,2);
+    } else if (MATRIX(*coords,i,2)>zmax) {
+      zmax=MATRIX(*coords,i,2);
+    }
+
+  }
+  
+  *x=(xmin+xmax)/2;
+  *y=(ymin+ymax)/2;
+  *z=(zmin+zmax)/2;
+  *r=sqrt( (xmax-xmin)*(xmax-xmin)+(ymax-ymin)*(ymax-ymin)+
+	   (zmax-zmin)*(zmax-zmin) ) / 2;
+  
+  return 0;
+}
+
+#define DIST(x,y) (sqrt(pow((x)-cx,2)+pow((y)-cy,2)))
+
+int igraph_i_layout_merge_dla(igraph_i_layout_mergegrid_t *grid, 
+			      long int actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r,
+			      igraph_real_t cx, igraph_real_t cy, igraph_real_t startr, 
+			      igraph_real_t killr) {
+  long int sp=-1;
+  igraph_real_t angle, len;
+  long int steps=0;
+
+  /* The graph is not used, only its coordinates */
+  IGRAPH_UNUSED(actg);
+
+  while (sp < 0) {
+    /* start particle */
+    do {
+      steps++;
+      angle=RNG_UNIF(0,2*M_PI);
+      len=RNG_UNIF(.5*startr, startr);
+      *x=cx+len*cos(angle);
+      *y=cy+len*sin(angle);
+      sp=igraph_i_layout_mergegrid_get_sphere(grid, *x, *y, r);
+    } while (sp >= 0);
+
+    while (sp < 0 && DIST(*x,*y)<killr) {
+      igraph_real_t nx, ny;
+      steps++;
+      angle=RNG_UNIF(0,2*M_PI);
+      len=RNG_UNIF(0, startr/100);
+      nx= *x + len * cos(angle);
+      ny= *y + len * sin(angle);      
+      sp=igraph_i_layout_mergegrid_get_sphere(grid, nx, ny, r);
+      if (sp < 0) {
+	*x = nx; *y = ny;
+      }
+    }
+  }
+
+/*   fprintf(stderr, "%li ", steps); */
+  return 0;
+}
+
+int igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from,
+			     int n, void *extra);
+
+int igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t *res,
+                               igraph_matrix_t *dist, long int dim);
+
+int igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from,
+    int n, void *extra) {
+  igraph_matrix_t* matrix = (igraph_matrix_t*)extra;
+  IGRAPH_UNUSED(n);
+  igraph_blas_dgemv_array(0, 1, matrix, from, 0, to);
+  return 0;
+}
+
+/* MDS layout for a connected graph, with no error checking on the
+ * input parameters. The distance matrix will be modified in-place. */
+int igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t *res,
+                               igraph_matrix_t *dist, long int dim) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int nev = dim;
+  igraph_matrix_t vectors;
+  igraph_vector_t values, row_means;
+  igraph_real_t grand_mean;
+  long int i, j, k;
+  igraph_eigen_which_t which;
+
+  /* Handle the trivial cases */
+  if (no_of_nodes == 1) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, 1, dim));
+    igraph_matrix_fill(res, 0);
+    return IGRAPH_SUCCESS;
+  }
+  if (no_of_nodes == 2) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, 2, dim));
+    igraph_matrix_fill(res, 0);
+    for (j = 0; j < dim; j++)
+      MATRIX(*res, 1, j) = 1;
+    return IGRAPH_SUCCESS;
+  }
+
+  /* Initialize some stuff */
+  IGRAPH_VECTOR_INIT_FINALLY(&values, no_of_nodes);
+  IGRAPH_CHECK(igraph_matrix_init(&vectors, no_of_nodes, dim));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &vectors);
+
+  /* Take the square of the distance matrix */
+  for (i = 0; i < no_of_nodes; i++) {
+    for (j = 0; j < no_of_nodes; j++) {
+      MATRIX(*dist, i, j) *= MATRIX(*dist, i, j);
+    }
+  }
+
+  /* Double centering of the distance matrix */
+  IGRAPH_VECTOR_INIT_FINALLY(&row_means, no_of_nodes);
+  igraph_vector_fill(&values, 1.0 / no_of_nodes);
+  igraph_blas_dgemv(0, 1, dist, &values, 0, &row_means);
+  grand_mean = igraph_vector_sum(&row_means) / no_of_nodes;
+  igraph_matrix_add_constant(dist, grand_mean);
+  for (i = 0; i < no_of_nodes; i++) {
+    for (j = 0; j < no_of_nodes; j++) {
+      MATRIX(*dist, i, j) -= VECTOR(row_means)[i] + VECTOR(row_means)[j];
+      MATRIX(*dist, i, j) *= -0.5;
+    }
+  }
+  igraph_vector_destroy(&row_means);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Calculate the top `dim` eigenvectors. */
+  which.pos = IGRAPH_EIGEN_LA;
+  which.howmany = (int) nev;
+  IGRAPH_CHECK(igraph_eigen_matrix_symmetric(/*A=*/ 0, /*sA=*/ 0, 
+			       /*fun=*/ igraph_i_layout_mds_step,
+			       /*n=*/ (int) no_of_nodes, /*extra=*/ dist, 
+			       /*algorithm=*/ IGRAPH_EIGEN_LAPACK,
+			       &which, /*options=*/ 0, /*storage=*/ 0,
+			       &values, &vectors));
+
+  /* Calculate and normalize the final coordinates */
+  for (j = 0; j < nev; j++) {
+    VECTOR(values)[j] = sqrt(fabs(VECTOR(values)[j]));
+  }
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, dim));
+  for (i = 0; i < no_of_nodes; i++) {
+    for (j = 0, k=nev-1; j < nev; j++, k--) {
+      MATRIX(*res, i, k) = VECTOR(values)[j] * MATRIX(vectors, i, j);
+    }
+  }
+
+  igraph_matrix_destroy(&vectors);
+  igraph_vector_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_layout_mds
+ * \brief Place the vertices on a plane using multidimensional scaling.
+ * 
+ * </para><para>
+ * This layout requires a distance matrix, where the intersection of
+ * row i and column j specifies the desired distance between vertex i
+ * and vertex j. The algorithm will try to place the vertices in a
+ * space having a given number of dimensions in a way that approximates
+ * the distance relations prescribed in the distance matrix. igraph
+ * uses the classical multidimensional scaling by Torgerson; for more
+ * details, see Cox & Cox: Multidimensional Scaling (1994), Chapman
+ * and Hall, London.
+ *
+ * </para><para>
+ * If the input graph is disconnected, igraph will decompose it
+ * first into its subgraphs, lay out the subgraphs one by one
+ * using the appropriate submatrices of the distance matrix, and
+ * then merge the layouts using \ref igraph_layout_merge_dla.
+ * Since \ref igraph_layout_merge_dla works for 2D layouts only,
+ * you cannot run the MDS layout on disconnected graphs for
+ * more than two dimensions.
+ *
+ * \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 dist The distance matrix. It must be symmetric and this
+ *        function does not check whether the matrix is indeed
+ *        symmetric. Results are unspecified if you pass a non-symmetric
+ *        matrix here. You can set this parameter to null; in this
+ *        case, the shortest path lengths between vertices will be
+ *        used as distances.
+ * \param dim The number of dimensions in the embedding space. For
+ *        2D layouts, supply 2 here.
+ * \param options This argument is currently ignored, it was used for 
+ *        ARPACK, but LAPACK is used now for calculating the eigenvectors.
+ * \return Error code.
+ * 
+ * Added in version 0.6.
+ * 
+ * </para><para>
+ * Time complexity: usually around O(|V|^2 dim).
+ */
+
+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) {
+  long int i, no_of_nodes=igraph_vcount(graph);
+  igraph_matrix_t m;
+  igraph_bool_t conn;
+
+  RNG_BEGIN();
+
+  /* Check the distance matrix */
+  if (dist && (igraph_matrix_nrow(dist) != no_of_nodes ||
+      igraph_matrix_ncol(dist) != no_of_nodes)) {
+    IGRAPH_ERROR("invalid distance matrix size", IGRAPH_EINVAL);
+  }
+
+  /* Check the number of dimensions */
+  if (dim <= 1) {
+    IGRAPH_ERROR("dim must be positive", IGRAPH_EINVAL);
+  }
+  if (dim > no_of_nodes) {
+    IGRAPH_ERROR("dim must be less than the number of nodes", IGRAPH_EINVAL);
+  }
+
+  /* Copy or obtain the distance matrix */
+  if (dist == 0) {
+    IGRAPH_CHECK(igraph_matrix_init(&m, no_of_nodes, no_of_nodes));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &m);
+    IGRAPH_CHECK(igraph_shortest_paths(graph, &m,
+          igraph_vss_all(), igraph_vss_all(), IGRAPH_ALL));
+  } else {
+    IGRAPH_CHECK(igraph_matrix_copy(&m, dist));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &m);
+    /* Make sure that the diagonal contains zeroes only */
+    for (i = 0; i < no_of_nodes; i++)
+      MATRIX(m, i, i) = 0.0;
+  }
+
+  /* Check whether the graph is connected */
+  IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
+  if (conn) {
+    /* Yes, it is, just do the MDS */
+    IGRAPH_CHECK(igraph_i_layout_mds_single(graph, res, &m, dim));
+  } else {
+    /* The graph is not connected, lay out the components one by one */
+    igraph_vector_ptr_t layouts;
+    igraph_vector_t comp, vertex_order;
+    igraph_t subgraph;
+    igraph_matrix_t *layout;
+    igraph_matrix_t dist_submatrix;
+    igraph_bool_t *seen_vertices;
+    long int j, n, processed_vertex_count = 0;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&comp, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&vertex_order, no_of_nodes);
+
+    IGRAPH_CHECK(igraph_vector_ptr_init(&layouts, 0));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &layouts);
+    igraph_vector_ptr_set_item_destructor(&layouts, (igraph_finally_func_t*)igraph_matrix_destroy);
+
+    IGRAPH_CHECK(igraph_matrix_init(&dist_submatrix, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &dist_submatrix);
+
+    seen_vertices = igraph_Calloc(no_of_nodes, igraph_bool_t);
+    if (seen_vertices == 0)
+      IGRAPH_ERROR("cannot calculate MDS layout", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(igraph_free, seen_vertices);
+
+    for (i = 0; i < no_of_nodes; i++) {
+      if (seen_vertices[i])
+        continue;
+
+      /* This is a vertex whose component we did not lay out so far */
+      IGRAPH_CHECK(igraph_subcomponent(graph, &comp, i, IGRAPH_ALL));
+      /* Take the subgraph */
+      IGRAPH_CHECK(igraph_induced_subgraph(graph, &subgraph, igraph_vss_vector(&comp),
+                                           IGRAPH_SUBGRAPH_AUTO));
+      IGRAPH_FINALLY(igraph_destroy, &subgraph);
+      /* Calculate the submatrix of the distances */
+      IGRAPH_CHECK(igraph_matrix_select_rows_cols(&m, &dist_submatrix,
+            &comp, &comp));
+      /* Allocate a new matrix for storing the layout */
+      layout = igraph_Calloc(1, igraph_matrix_t);
+      if (layout == 0)
+        IGRAPH_ERROR("cannot calculate MDS layout", IGRAPH_ENOMEM);
+      IGRAPH_FINALLY(igraph_free, layout);
+      IGRAPH_CHECK(igraph_matrix_init(layout, 0, 0));
+      IGRAPH_FINALLY(igraph_matrix_destroy, layout);
+      /* Lay out the subgraph */
+      IGRAPH_CHECK(igraph_i_layout_mds_single(&subgraph, layout, &dist_submatrix, dim));
+      /* Store the layout */
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(&layouts, layout));
+      IGRAPH_FINALLY_CLEAN(2);  /* ownership of layout taken by layouts */
+      /* Free the newly created subgraph */
+      igraph_destroy(&subgraph);
+      IGRAPH_FINALLY_CLEAN(1);
+      /* Mark all the vertices in the component as visited */
+      n = igraph_vector_size(&comp);
+      for (j = 0; j < n; j++) {
+        seen_vertices[(long int)VECTOR(comp)[j]] = 1;
+        VECTOR(vertex_order)[(long int)VECTOR(comp)[j]] = processed_vertex_count++;
+      }
+    }
+    /* Merge the layouts - reusing dist_submatrix here */
+    IGRAPH_CHECK(igraph_layout_merge_dla(0, &layouts, &dist_submatrix));
+    /* Reordering the rows of res to match the original graph */
+    IGRAPH_CHECK(igraph_matrix_select_rows(&dist_submatrix, res, &vertex_order));
+
+    igraph_free(seen_vertices);
+    igraph_matrix_destroy(&dist_submatrix);
+    igraph_vector_ptr_destroy_all(&layouts);
+    igraph_vector_destroy(&vertex_order);
+    igraph_vector_destroy(&comp);
+    IGRAPH_FINALLY_CLEAN(5);
+  }
+
+  RNG_END();
+
+  igraph_matrix_destroy(&m);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_layout_bipartite
+ * Simple 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, by calling \ref
+ * igraph_layout_sugiyama().
+ * 
+ * \param graph The input graph.
+ * \param types A boolean vector containing ones and zeros, the vertex
+ *     types. Its length must match the number of vertices in the graph.
+ * \param res Pointer to an initialized matrix, the result, the x and
+ *     y coordinates are stored here.
+ * \param hgap The preferred minimum horizontal gap between vertices
+ *     in the same layer (i.e. vertices of the same type).
+ * \param vgap  The distance between layers.
+ * \param maxiter 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 Error code.
+ * 
+ * \sa \ref igraph_layout_sugiyama().
+ */
+
+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) {
+
+  long int i, no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t layers;
+
+  if (igraph_vector_bool_size(types) != no_of_nodes) { 
+    IGRAPH_ERROR("Invalid vertex type vector size", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&layers, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(layers)[i] = 1 - VECTOR(*types)[i];
+  }
+
+  IGRAPH_CHECK(igraph_layout_sugiyama(graph, res, /*extd_graph=*/ 0, 
+				      /*extd_to_orig_eids=*/ 0, &layers, hgap,
+				      vgap, maxiter, /*weights=*/ 0));
+  
+  igraph_vector_destroy(&layers);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
diff --git a/src/matching.c b/src/matching.c
new file mode 100644
index 0000000..840340d
--- /dev/null
+++ b/src/matching.c
@@ -0,0 +1,991 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2012  Tamas Nepusz <ntamas at gmail.com>
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+#include <assert.h>
+#include <math.h>
+#include "config.h"
+#include "igraph_adjlist.h"
+#include "igraph_constructors.h"
+#include "igraph_conversion.h"
+#include "igraph_dqueue.h"
+#include "igraph_flow.h"
+#include "igraph_interface.h"
+#include "igraph_matching.h"
+#include "igraph_structural.h"
+
+/* #define MATCHING_DEBUG */
+
+#ifdef _MSC_VER
+/* MSVC does not support variadic macros */
+#include <stdarg.h>
+static void debug(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+#ifdef MATCHING_DEBUG
+  vfprintf(stderr, fmt, args);
+#endif
+  va_end(args);
+}
+#else
+#  ifdef MATCHING_DEBUG
+#    define debug(...) fprintf(stderr, __VA_ARGS__)
+#  else
+#    define debug(...) 
+#  endif
+#endif
+
+/**
+ * \function igraph_is_matching
+ * Checks whether the given matching is valid for the given graph.
+ *
+ * This function checks a matching vector and verifies whether its length
+ * matches the number of vertices in the given graph, its values are between
+ * -1 (inclusive) and the number of vertices (exclusive), 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.
+ *
+ * \param graph The input graph. It can be directed but the edge directions
+ *              will be ignored.
+ * \param types If the graph is bipartite and you are interested in bipartite
+ *              matchings only, pass the vertex types here. If the graph is
+ *              non-bipartite, simply pass \c NULL.
+ * \param matching The matching itself. It must be a vector where element i
+ *                 contains the ID of the vertex that vertex i is matched to,
+ *                 or -1 if vertex i is unmatched.
+ * \param result Pointer to a boolean variable, the result will be returned
+ *               here.
+ *
+ * \sa \ref igraph_is_maximal_matching() if you are also interested in whether
+ *     the matching is maximal (i.e. non-extendable).
+ *
+ * Time complexity: O(|V|+|E|) where |V| is the number of vertices and
+ * |E| is the number of edges.
+ * 
+ * \example examples/simple/igraph_maximum_bipartite_matching.c
+ */
+int igraph_is_matching(const igraph_t* graph,
+    const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,
+    igraph_bool_t* result) {
+  long int i, j, no_of_nodes = igraph_vcount(graph);
+  igraph_bool_t conn;
+
+  /* Checking match vector length */
+  if (igraph_vector_long_size(matching) != no_of_nodes) {
+    *result = 0; return IGRAPH_SUCCESS;
+  }
+
+  for (i = 0; i < no_of_nodes; i++) {
+    j = VECTOR(*matching)[i];
+
+    /* Checking range of each element in the match vector */
+    if (j < -1 || j >= no_of_nodes) {
+      *result = 0; return IGRAPH_SUCCESS;
+    }
+    /* When i is unmatched, we're done */
+    if (j == -1)
+      continue;
+    /* Matches must be mutual */
+    if (VECTOR(*matching)[j] != i) {
+      *result = 0; return IGRAPH_SUCCESS;
+    }
+    /* Matched vertices must be connected */
+    IGRAPH_CHECK(igraph_are_connected(graph, (igraph_integer_t) i, 
+				      (igraph_integer_t) j, &conn));
+    if (!conn) {
+      /* Try the other direction -- for directed graphs */
+      IGRAPH_CHECK(igraph_are_connected(graph, (igraph_integer_t) j, 
+					(igraph_integer_t) i, &conn));
+      if (!conn) {
+        *result = 0; return IGRAPH_SUCCESS;
+      }
+    }
+  }
+
+  if (types != 0) {
+    /* Matched vertices must be of different types */
+    for (i = 0; i < no_of_nodes; i++) {
+      j = VECTOR(*matching)[i];
+      if (j == -1)
+        continue;
+      if (VECTOR(*types)[i] == VECTOR(*types)[j]) {
+        *result = 0; return IGRAPH_SUCCESS;
+      }
+    }
+  }
+
+  *result = 1;
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_is_maximal_matching
+ * Checks whether a matching in a graph 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.
+ *
+ * \param graph The input graph. It can be directed but the edge directions
+ *              will be ignored.
+ * \param types If the graph is bipartite and you are interested in bipartite
+ *              matchings only, pass the vertex types here. If the graph is
+ *              non-bipartite, simply pass \c NULL.
+ * \param matching The matching itself. It must be a vector where element i
+ *                 contains the ID of the vertex that vertex i is matched to,
+ *                 or -1 if vertex i is unmatched.
+ * \param result Pointer to a boolean variable, the result will be returned
+ *               here.
+ *
+ * \sa \ref igraph_is_matching() if you are only interested in whether a
+ *     matching vector is valid for a given graph.
+ *
+ * Time complexity: O(|V|+|E|) where |V| is the number of vertices and
+ * |E| is the number of edges.
+ * 
+ * \example examples/simple/igraph_maximum_bipartite_matching.c
+ */
+int igraph_is_maximal_matching(const igraph_t* graph,
+    const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,
+    igraph_bool_t* result) {
+  long int i, j, n, no_of_nodes = igraph_vcount(graph);
+  igraph_vector_t neis;
+  igraph_bool_t valid;
+
+  IGRAPH_CHECK(igraph_is_matching(graph, types, matching, &valid));
+  if (!valid) {
+    *result = 0; return IGRAPH_SUCCESS;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  valid = 1;
+  for (i = 0; i < no_of_nodes; i++) {
+    j = VECTOR(*matching)[i];
+    if (j != -1)
+      continue;
+
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i,
+				  IGRAPH_ALL));
+    n = igraph_vector_size(&neis);
+    for (j = 0; j < n; j++) {
+      if (VECTOR(*matching)[(long int)VECTOR(neis)[j]] == -1) {
+        if (types == 0 ||
+            VECTOR(*types)[i] != VECTOR(*types)[(long int)VECTOR(neis)[j]]) {
+          valid = 0; break;
+        }
+      }
+    }
+  }
+
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  *result = valid;
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_maximum_bipartite_matching_unweighted(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
+    igraph_vector_long_t* matching);
+int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
+    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
+    const igraph_vector_t* weights, igraph_real_t eps);
+
+#define MATCHED(v) (VECTOR(match)[v] != -1)
+#define UNMATCHED(v) (!MATCHED(v))
+
+/**
+ * \function igraph_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.
+ *
+ * </para><para>
+ * Maximum matchings in bipartite graphs are found by the push-relabel algorithm
+ * with greedy initialization and a global relabeling after every n/2 steps where
+ * n is the number of vertices in the graph.
+ *
+ * </para><para>
+ * References: Cherkassky BV, Goldberg AV, Martin P, Setubal JC and Stolfi J:
+ * Augment or push: A computational study of bipartite matching and
+ * unit-capacity flow algorithms. ACM Journal of Experimental Algorithmics 3,
+ * 1998.
+ *
+ * </para><para>
+ * Kaya K, Langguth J, Manne F and Ucar B: Experiments on push-relabel-based
+ * maximum cardinality matching algorithms for bipartite graphs. Technical
+ * Report TR/PA/11/33 of the Centre Europeen de Recherche et de Formation
+ * Avancee en Calcul Scientifique, 2011.
+ *
+ * \param graph The input graph. It can be directed but the edge directions
+ *              will be ignored.
+ * \param types Boolean vector giving the vertex types of the graph.
+ * \param matching_size The size of the matching (i.e. the number of matched
+ *                      vertex pairs will be returned here). It may be \c NULL
+ *                      if you don't need this.
+ * \param matching_weight The weight of the matching if the edges are weighted,
+ *                        or the size of the matching again if the edges are
+ *                        unweighted. It may be \c NULL if you don't need this.
+ * \param matching The matching itself. It must be a vector where element i
+ *                 contains the ID of the vertex that vertex i is matched to,
+ *                 or -1 if vertex i is unmatched.
+ * \param weights A null pointer (=no edge weights), or a vector giving the
+ *                weights of the edges. Note that the algorithm is stable
+ *                only for integer weights.
+ * \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
+ *            \c eps. This is required to avoid the accumulation of numerical
+ *            errors. It is advised to pass a value derived from the
+ *            \c DBL_EPSILON constant in \c float.h here. If you are
+ *            running the algorithm with no \c weights vector, this argument
+ *            is ignored.
+ * \return Error code.
+ *
+ * Time complexity: O(sqrt(|V|) |E|) for unweighted graphs (according to the
+ * technical report referenced above), O(|V||E|) for weighted graphs.
+ * 
+ * \example examples/simple/igraph_maximum_bipartite_matching.c
+ */
+int igraph_maximum_bipartite_matching(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
+    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
+    const igraph_vector_t* weights, igraph_real_t eps) {
+
+  /* Sanity checks */
+  if (igraph_vector_bool_size(types) < igraph_vcount(graph)) {
+    IGRAPH_ERROR("types vector too short", IGRAPH_EINVAL);
+  }
+  if (weights && igraph_vector_size(weights) < igraph_ecount(graph)) {
+    IGRAPH_ERROR("weights vector too short", IGRAPH_EINVAL);
+  }
+
+  if (weights == 0) {
+    IGRAPH_CHECK(igraph_i_maximum_bipartite_matching_unweighted(graph, types,
+        matching_size, matching));
+    if (matching_weight != 0) {
+      *matching_weight = *matching_size;
+    }
+    return IGRAPH_SUCCESS;
+  } else {
+    return igraph_i_maximum_bipartite_matching_weighted(graph, types,
+        matching_size, matching_weight, matching, weights, eps);
+  }
+}
+
+int igraph_i_maximum_bipartite_matching_unweighted_relabel(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_vector_t* labels,
+    igraph_vector_long_t* matching, igraph_bool_t smaller_set);
+
+/**
+ * Finding maximum bipartite matchings on bipartite graphs using the
+ * push-relabel algorithm.
+ *
+ * The implementation follows the pseudocode in Algorithm 1 of the
+ * following paper:
+ * 
+ * Kaya K, Langguth J, Manne F and Ucar B: Experiments on push-relabel-based
+ * maximum cardinality matching algorithms for bipartite graphs. Technical
+ * Report TR/PA/11/33 of CERFACS (Centre Européen de Recherche et de Formation
+ * Avancée en Calcul Scientifique).
+ * http://www.cerfacs.fr/algor/reports/2011/TR_PA_11_33.pdf
+ */
+int igraph_i_maximum_bipartite_matching_unweighted(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
+    igraph_vector_long_t* matching) {
+  long int i, j, k, n, no_of_nodes = igraph_vcount(graph);
+  long int num_matched;             /* number of matched vertex pairs */
+  igraph_vector_long_t match;       /* will store the matching */
+  igraph_vector_t labels;           /* will store the labels */
+  igraph_vector_t neis;             /* used to retrieve the neighbors of a node */
+  igraph_dqueue_long_t q;           /* a FIFO for push ordering */
+  igraph_bool_t smaller_set;        /* denotes which part of the bipartite graph is smaller */
+  long int label_changed = 0;       /* Counter to decide when to run a global relabeling */
+  long int relabeling_freq = no_of_nodes / 2;
+
+  /* We will use:
+   * - FIFO push ordering
+   * - global relabeling frequency: n/2 steps where n is the number of nodes
+   * - simple greedy matching for initialization
+   */
+
+  /* (1) Initialize data structures */
+  IGRAPH_CHECK(igraph_vector_long_init(&match, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &match);
+  IGRAPH_VECTOR_INIT_FINALLY(&labels, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0));
+  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
+
+  /* (2) Initially, every node is unmatched */
+  igraph_vector_long_fill(&match, -1);
+
+  /* (3) Find an initial matching in a greedy manner.
+   *     At the same time, find which side of the graph is smaller. */
+  num_matched = 0; j = 0;
+  for (i = 0; i < no_of_nodes; i++) {
+    if (VECTOR(*types)[i])
+      j++;
+    if (MATCHED(i))
+      continue;
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i,
+				  IGRAPH_ALL));
+    n = igraph_vector_size(&neis);
+    for (j = 0; j < n; j++) {
+      k = (long int) VECTOR(neis)[j];
+      if (UNMATCHED(k)) {
+        /* We match vertex i to vertex VECTOR(neis)[j] */
+        VECTOR(match)[k] = i;
+        VECTOR(match)[i] = k;
+        num_matched++;
+        break;
+      }
+    }
+  }
+  smaller_set = (j <= no_of_nodes/2);
+
+  /* (4) Set the initial labeling -- lines 1 and 2 in the tech report */
+  IGRAPH_CHECK(igraph_i_maximum_bipartite_matching_unweighted_relabel(
+      graph, types, &labels, &match, smaller_set));
+
+  /* (5) Fill the push queue with the unmatched nodes from the smaller set. */
+  for (i = 0; i < no_of_nodes; i++) {
+    if (UNMATCHED(i) && VECTOR(*types)[i] == smaller_set)
+      IGRAPH_CHECK(igraph_dqueue_long_push(&q, i));
+  }
+
+  /* (6) Main loop from the referenced tech report -- lines 4--13 */
+  label_changed = 0;
+  while (!igraph_dqueue_long_empty(&q)) {
+    long int v = igraph_dqueue_long_pop(&q);             /* Line 13 */
+    long int u = -1, label_u = 2 * no_of_nodes;
+    long int w;
+
+    if (label_changed >= relabeling_freq) {
+      /* Run global relabeling */
+      IGRAPH_CHECK(igraph_i_maximum_bipartite_matching_unweighted_relabel(
+            graph, types, &labels, &match, smaller_set));
+      label_changed = 0;
+    }
+
+    debug("Considering vertex %ld\n", v);
+
+    /* Line 5: find row u among the neighbors of v s.t. label(u) is minimal */
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, 
+				  IGRAPH_ALL));
+    n = igraph_vector_size(&neis);
+    for (i = 0; i < n; i++) {
+      if (VECTOR(labels)[(long int)VECTOR(neis)[i]] < label_u) {
+        u = (long int) VECTOR(neis)[i];
+        label_u = (long int) VECTOR(labels)[u];
+        label_changed++;
+      }
+    }
+
+    debug("  Neighbor with smallest label: %ld (label=%ld)\n", u, label_u);
+
+    if (label_u < no_of_nodes) {                         /* Line 6 */
+      VECTOR(labels)[v] = VECTOR(labels)[u] + 1;         /* Line 7 */
+      if (MATCHED(u)) {                                  /* Line 8 */
+        w = VECTOR(match)[u];
+        debug("  Vertex %ld is matched to %ld, performing a double push\n", u, w);
+        if (w != v) {
+          VECTOR(match)[u] = -1; VECTOR(match)[w] = -1;  /* Line 9 */
+          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));  /* Line 10 */
+          debug("  Unmatching & activating vertex %ld\n", w);
+          num_matched--;
+        }
+      }
+      VECTOR(match)[u] = v; VECTOR(match)[v] = u;      /* Line 11 */
+      num_matched++;
+      VECTOR(labels)[u] += 2;                          /* Line 12 */
+      label_changed++;
+    }
+  }
+
+  /* Fill the output parameters */
+  if (matching != 0) {
+    IGRAPH_CHECK(igraph_vector_long_update(matching, &match));
+  }
+  if (matching_size != 0) {
+    *matching_size = (igraph_integer_t) num_matched;
+  }
+
+  /* Release everything */
+  igraph_dqueue_long_destroy(&q);
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&labels);
+  igraph_vector_long_destroy(&match);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_maximum_bipartite_matching_unweighted_relabel(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_vector_t* labels,
+    igraph_vector_long_t* match, igraph_bool_t smaller_set) {
+  long int i, j, n, no_of_nodes = igraph_vcount(graph), matched_to;
+  igraph_dqueue_long_t q;
+  igraph_vector_t neis;
+
+  debug("Running global relabeling.\n");
+
+  /* Set all the labels to no_of_nodes first */
+  igraph_vector_fill(labels, no_of_nodes);
+
+  /* Allocate vector for neighbors */
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  /* Create a FIFO for the BFS and initialize it with the unmatched rows
+   * (i.e. members of the larger set) */
+  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0));
+  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
+  for (i = 0; i < no_of_nodes; i++) {
+    if (VECTOR(*types)[i] != smaller_set && VECTOR(*match)[i] == -1) {
+      IGRAPH_CHECK(igraph_dqueue_long_push(&q, i));
+      VECTOR(*labels)[i] = 0;
+    }
+  }
+
+  /* Run the BFS */
+  while (!igraph_dqueue_long_empty(&q)) {
+    long int v = igraph_dqueue_long_pop(&q);
+    long int w;
+
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v,
+				  IGRAPH_ALL));
+
+    n = igraph_vector_size(&neis);
+    for (j = 0; j < n; j++) {
+      w = (long int) VECTOR(neis)[j];
+      if (VECTOR(*labels)[w] == no_of_nodes) {
+        VECTOR(*labels)[w] = VECTOR(*labels)[v] + 1;
+        matched_to = VECTOR(*match)[w];
+        if (matched_to != -1 && VECTOR(*labels)[matched_to] == no_of_nodes) {
+          IGRAPH_CHECK(igraph_dqueue_long_push(&q, matched_to));
+          VECTOR(*labels)[matched_to] = VECTOR(*labels)[w] + 1;
+        }
+      }
+    }
+  }
+
+  igraph_dqueue_long_destroy(&q);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Finding maximum bipartite matchings on bipartite graphs using the
+ * Hungarian algorithm (a.k.a. Kuhn-Munkres algorithm).
+ *
+ * The algorithm uses a maximum cardinality matching on a subset of
+ * tight edges as a starting point. This is achieved by
+ * \c igraph_i_maximum_bipartite_matching_unweighted on the restricted
+ * graph.
+ *
+ * The algorithm works reliably only if the weights are integers. The
+ * \c eps parameter should specity a very small number; if the slack on
+ * an edge falls below \c eps, it will be considered tight. If all your
+ * weights are integers, you can safely set \c eps to zero.
+ */
+int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
+    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
+    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
+    const igraph_vector_t* weights, igraph_real_t eps) {
+  long int i, j, k, n, no_of_nodes, no_of_edges;
+  igraph_integer_t u, v, w, msize;
+  igraph_t newgraph;
+  igraph_vector_long_t match;       /* will store the matching */
+  igraph_vector_t slack;            /* will store the slack on each edge */
+  igraph_vector_t parent;           /* parent vertices during a BFS */
+  igraph_vector_t vec1, vec2;       /* general temporary vectors */
+  igraph_vector_t labels;           /* will store the labels */
+  igraph_dqueue_long_t q;           /* a FIFO for BST */
+  igraph_bool_t smaller_set;        /* denotes which part of the bipartite graph is smaller */
+  long int smaller_set_size;        /* size of the smaller set */
+  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 *neis2;
+  igraph_inclist_t inclist;         /* incidence list of the original graph */ 
+
+  /* The Hungarian algorithm is originally for complete bipartite graphs.
+   * For non-complete bipartite graphs, a phantom edge of weight zero must be
+   * added between every pair of non-connected vertices. We don't do this
+   * explicitly of course. See the comments below about how phantom edges
+   * are taken into account. */
+
+  no_of_nodes = igraph_vcount(graph);
+  no_of_edges = igraph_ecount(graph);
+  if (eps < 0) {
+    IGRAPH_WARNING("negative epsilon given, clamping to zero");
+    eps = 0;
+  }
+
+  /* (1) Initialize data structures */
+  IGRAPH_CHECK(igraph_vector_long_init(&match, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &match);
+  IGRAPH_CHECK(igraph_vector_init(&slack, no_of_edges));
+  IGRAPH_FINALLY(igraph_vector_destroy, &slack);
+  IGRAPH_VECTOR_INIT_FINALLY(&vec1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&vec2, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&labels, no_of_nodes);
+  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0));
+  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
+  IGRAPH_VECTOR_INIT_FINALLY(&parent, no_of_nodes);
+  IGRAPH_CHECK(igraph_adjlist_init_empty(&tight_phantom_edges, 
+					 (igraph_integer_t) no_of_nodes));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &tight_phantom_edges);
+  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+
+  /* (2) Find which set is the smaller one */
+  j = 0;
+  for (i = 0; i < no_of_nodes; i++) {
+    if (VECTOR(*types)[i] == 0)
+      j++;
+  }
+  smaller_set = (j > no_of_nodes / 2);
+  smaller_set_size = smaller_set ? (no_of_nodes - j) : j;
+
+  /* (3) Calculate the initial labeling and the set of tight edges. Use the
+   *     smaller set only. Here we can assume that there are no phantom edges
+   *     among the tight ones. */
+  dual = 0;
+  for (i = 0; i < no_of_nodes; i++) {
+    igraph_real_t max_weight = 0;
+
+    if (VECTOR(*types)[i] != smaller_set) {
+      VECTOR(labels)[i] = 0;
+      continue;
+    }
+
+    neis = igraph_inclist_get(&inclist, i);
+    n = igraph_vector_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];
+        max_weight = VECTOR(*weights)[k];
+      }
+    }
+
+    VECTOR(labels)[i] = max_weight;
+    dual += max_weight;
+  }
+
+  igraph_vector_clear(&vec1);
+  IGRAPH_CHECK(igraph_get_edgelist(graph, &vec2, 0));
+#define IS_TIGHT(i) (VECTOR(slack)[i] <= eps)
+  for (i = 0, j = 0; i < no_of_edges; i++, j+=2) {
+    u = (igraph_integer_t) VECTOR(vec2)[j];
+    v = (igraph_integer_t) VECTOR(vec2)[j+1];
+    VECTOR(slack)[i] = VECTOR(labels)[u] + VECTOR(labels)[v] - VECTOR(*weights)[i];
+    if (IS_TIGHT(i)) {
+      IGRAPH_CHECK(igraph_vector_push_back(&vec1, u));
+      IGRAPH_CHECK(igraph_vector_push_back(&vec1, v));
+    }
+  }
+  igraph_vector_clear(&vec2);
+
+  /* (4) Construct a temporary graph on which the initial maximum matching
+   *     will be calculated (only on the subset of tight edges) */
+  IGRAPH_CHECK(igraph_create(&newgraph, &vec1,
+			     (igraph_integer_t) no_of_nodes, 0));
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+  IGRAPH_CHECK(igraph_maximum_bipartite_matching(&newgraph, types, &msize, 0, &match, 0, 0));
+  igraph_destroy(&newgraph);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* (5) Main loop until the matching becomes maximal */
+  while (msize < smaller_set_size) {
+    igraph_real_t min_slack, min_slack_2;
+    igraph_integer_t min_slack_u, min_slack_v;
+
+    /* (7) Fill the push queue with the unmatched nodes from the smaller set. */
+    igraph_vector_clear(&vec1);
+    igraph_vector_clear(&vec2);
+    igraph_vector_fill(&parent, -1);
+    for (i = 0; i < no_of_nodes; i++) {
+      if (UNMATCHED(i) && VECTOR(*types)[i] == smaller_set) {
+        IGRAPH_CHECK(igraph_dqueue_long_push(&q, i));
+        VECTOR(parent)[i] = i;
+        IGRAPH_CHECK(igraph_vector_push_back(&vec1, i));
+      }
+    }
+
+#ifdef MATCHING_DEBUG
+    debug("Matching:");
+    igraph_vector_long_print(&match);
+    debug("Unmatched vertices are marked by non-negative numbers:\n");
+    igraph_vector_print(&parent);
+    debug("Labeling:");
+    igraph_vector_print(&labels);
+    debug("Slacks:");
+    igraph_vector_print(&slack);
+#endif
+
+    /* (8) Run the BFS */
+    alternating_path_endpoint = -1;
+    while (!igraph_dqueue_long_empty(&q)) {
+      v = (int) igraph_dqueue_long_pop(&q);
+
+      debug("Considering vertex %ld\n", (long int)v);
+
+      /* v is always in the smaller set. Find the neighbors of v, which
+       * are all in the larger set. Find the pairs of these nodes in
+       * the smaller set and push them to the queue. Mark the traversed
+       * nodes as seen.
+       *
+       * Here we have to be careful as there are two types of incident
+       * edges on v: real edges and phantom ones. Real edges are
+       * given by igraph_inclist_get. Phantom edges are not given so we
+       * (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);
+      for (i = 0; i < n; i++) {
+        j = (long int) VECTOR(*neis)[i];
+        /* We only care about tight edges */
+        if (!IS_TIGHT(j))
+          continue;
+        /* Have we seen the other endpoint already? */
+        u = IGRAPH_OTHER(graph, j, v);
+        if (VECTOR(parent)[u] >= 0)
+          continue;
+        debug("  Reached vertex %ld via edge %ld\n", (long)u, (long)j);
+        VECTOR(parent)[u] = v;
+        IGRAPH_CHECK(igraph_vector_push_back(&vec2, u));
+        w = (int) VECTOR(match)[u];
+        if (w == -1) {
+          /* u is unmatched and it is in the larger set. Therefore, we
+           * could improve the matching by following the parents back
+           * from u to the root.
+           */
+          alternating_path_endpoint = u;
+          break;  /* since we don't need any more endpoints that come from v */
+        } else {
+          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));
+          VECTOR(parent)[w] = u;
+        }
+        IGRAPH_CHECK(igraph_vector_push_back(&vec1, w));
+      }
+
+      /* Now do the same with the phantom edges */
+      neis2 = igraph_adjlist_get(&tight_phantom_edges, v);
+      n = igraph_vector_int_size(neis2);
+      for (i = 0; i < n; i++) {
+        u = (igraph_integer_t) VECTOR(*neis2)[i];
+        /* Have we seen u already? */
+        if (VECTOR(parent)[u] >= 0)
+          continue;
+        /* Check if the edge is really tight; it might have happened that the
+         * edge became non-tight in the meanwhile. We do not remove these from
+         * tight_phantom_edges at the moment, so we check them once again here.
+         */
+        if (fabs(VECTOR(labels)[(long int)v] + VECTOR(labels)[(long int)u]) > eps)
+          continue;
+        debug("  Reached vertex %ld via tight phantom edge\n", (long)u);
+        VECTOR(parent)[u] = v;
+        IGRAPH_CHECK(igraph_vector_push_back(&vec2, u));
+        w = (int) VECTOR(match)[u];
+        if (w == -1) {
+          /* u is unmatched and it is in the larger set. Therefore, we
+           * could improve the matching by following the parents back
+           * from u to the root.
+           */
+          alternating_path_endpoint = u;
+          break;  /* since we don't need any more endpoints that come from v */
+        } else {
+          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));
+          VECTOR(parent)[w] = u;
+        }
+        IGRAPH_CHECK(igraph_vector_push_back(&vec1, w));
+      }
+    }
+
+    /* Okay; did we have an alternating path? */
+    if (alternating_path_endpoint != -1) {
+#ifdef MATCHING_DEBUG
+      debug("BFS parent tree:");
+      igraph_vector_print(&parent);
+#endif
+      /* Increase the size of the matching with the alternating path. */
+      v = alternating_path_endpoint;
+      u = (igraph_integer_t) VECTOR(parent)[v];
+      debug("Extending matching with alternating path ending in %ld.\n", (long int)v);
+
+      while (u != v) {
+        w = (int) VECTOR(match)[v];
+        if (w != -1)
+          VECTOR(match)[w] = -1;
+        VECTOR(match)[v] = u;
+
+        VECTOR(match)[v] = u;
+        w = (int) VECTOR(match)[u];
+        if (w != -1)
+          VECTOR(match)[w] = -1;
+        VECTOR(match)[u] = v;
+
+        v = (igraph_integer_t) VECTOR(parent)[u];
+	u = (igraph_integer_t) VECTOR(parent)[v];
+      }
+
+      msize++;
+
+#ifdef MATCHING_DEBUG
+      debug("New matching after update:");
+      igraph_vector_long_print(&match);
+      debug("Matching size is now: %ld\n", (long)msize);
+#endif
+      continue;
+    }
+
+#ifdef MATCHING_DEBUG
+    debug("Vertices reachable from unmatched ones via tight edges:\n");
+    igraph_vector_print(&vec1);
+    igraph_vector_print(&vec2);
+#endif
+
+    /* At this point, vec1 contains the nodes in the smaller set (A)
+     * reachable from unmatched nodes in A via tight edges only, while vec2
+     * contains the nodes in the larger set (B) reachable from unmatched
+     * nodes in A via tight edges only. Also, parent[i] >= 0 if node i
+     * is reachable */
+
+    /* Check the edges between reachable nodes in A and unreachable
+     * nodes in B, and find the minimum slack on them.
+     *
+     * Since the weights are positive, we do no harm if we first
+     * assume that there are no "real" edges between the two sets
+     * mentioned above and determine an upper bound for min_slack
+     * based on this. */
+    min_slack = IGRAPH_INFINITY;
+    min_slack_u = min_slack_v = 0;
+    n = igraph_vector_size(&vec1);
+    for (i = 0; i < no_of_nodes; i++) {
+      if (VECTOR(*types)[i] == smaller_set)
+        continue;
+      if (VECTOR(labels)[i] < min_slack) {
+        min_slack = VECTOR(labels)[i];
+        min_slack_v = (igraph_integer_t) i;
+      }
+    }
+    min_slack_2 = IGRAPH_INFINITY;
+    for (i = 0; i < n; i++) {
+      u = (igraph_integer_t) VECTOR(vec1)[i];
+      /* u is surely from the smaller set, but we are interested in it
+       * only if it is reachable from an unmatched vertex */
+      if (VECTOR(parent)[u] < 0)
+        continue;
+      if (VECTOR(labels)[u] < min_slack_2) {
+        min_slack_2 = VECTOR(labels)[u];
+        min_slack_u = u;
+      }
+    }
+    min_slack += min_slack_2;
+    debug("Starting approximation for min_slack = %.4f (based on vertex pair %ld--%ld)\n",
+        min_slack, (long int)min_slack_u, (long int)min_slack_v);
+
+    n = igraph_vector_size(&vec1);
+    for (i = 0; i < n; i++) {
+      u = (igraph_integer_t) VECTOR(vec1)[i];
+      /* u is a reachable node in A; get its incident edges.
+       *
+       * There are two types of incident edges: 1) real edges,
+       * 2) phantom edges. Phantom edges were treated earlier
+       * 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);
+      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 */
+        v = IGRAPH_OTHER(graph, VECTOR(*neis)[j], u);
+        debug("  Edge %ld -- %ld (ID=%ld)\n", (long int)u, (long int)v, (long int)VECTOR(*neis)[j]);
+        if (VECTOR(parent)[v] >= 0) {
+          /* v was reached, so we are not interested in it */
+          debug("    %ld was reached, so we are not interested in it\n", (long int)v);
+          continue;
+        }
+        /* v is the ID of the edge from now on */
+        v = (igraph_integer_t) VECTOR(*neis)[j];
+        if (VECTOR(slack)[v] < min_slack) {
+          min_slack = VECTOR(slack)[v];
+          min_slack_u = u;
+          min_slack_v = IGRAPH_OTHER(graph, v, u);
+        }
+        debug("    Slack of this edge: %.4f, min slack is now: %.4f\n",
+            VECTOR(slack)[v], min_slack);
+      }
+    }
+    debug("Minimum slack: %.4f on edge %d--%d\n", min_slack, (int)min_slack_u, (int)min_slack_v);
+
+    if (min_slack > 0) {
+      /* Decrease the label of reachable nodes in A by min_slack.
+       * Also update the dual solution */
+      n = igraph_vector_size(&vec1);
+      for (i = 0; i < n; i++) {
+        u = (igraph_integer_t) VECTOR(vec1)[i];
+        VECTOR(labels)[u] -= min_slack;
+        neis = igraph_inclist_get(&inclist, u);
+        k = igraph_vector_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,
+              (long)IGRAPH_OTHER(graph, VECTOR(*neis)[j], u), min_slack);
+          VECTOR(slack)[(long int)VECTOR(*neis)[j]] -= min_slack;
+        }
+        dual -= min_slack;
+      }
+
+      /* Increase the label of reachable nodes in B by min_slack.
+       * Also update the dual solution */
+      n = igraph_vector_size(&vec2);
+      for (i = 0; i < n; i++) {
+        u = (igraph_integer_t) VECTOR(vec2)[i];
+        VECTOR(labels)[u] += min_slack;
+        neis = igraph_inclist_get(&inclist, u);
+        k = igraph_vector_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,
+              (long)IGRAPH_OTHER(graph, (long)VECTOR(*neis)[j], u), min_slack);
+          VECTOR(slack)[(long int)VECTOR(*neis)[j]] += min_slack;
+        }
+        dual += min_slack;
+      }
+    }
+
+    /* Update the set of tight phantom edges.
+     * Note that we must do it even if min_slack is zero; the reason is that
+     * it can happen that min_slack is zero in the first step if there are
+     * isolated nodes in the input graph.
+     *
+     * TODO: this is O(n^2) here. Can we do it faster? */
+    for (u = 0; u < no_of_nodes; u++) {
+      if (VECTOR(*types)[u] != smaller_set)
+        continue;
+
+      for (v = 0; v < no_of_nodes; v++) {
+        if (VECTOR(*types)[v] == smaller_set)
+          continue;
+
+        if (VECTOR(labels)[(long int)u] + VECTOR(labels)[(long int)v] <= eps) {
+          /* Tight phantom edge found. Note that we don't have to check whether
+           * u and v are connected; if they were, then the slack of this edge
+           * would be negative. */
+          neis2 = igraph_adjlist_get(&tight_phantom_edges, u);
+          if (!igraph_vector_int_binsearch(neis2, v, &i)) {
+            debug("New tight phantom edge: %ld -- %ld\n", (long)u, (long)v);
+            IGRAPH_CHECK(igraph_vector_int_insert(neis2, i, v));
+          }
+        }
+      }
+    }
+
+#ifdef MATCHING_DEBUG
+    debug("New labels:");
+    igraph_vector_print(&labels);
+    debug("Slacks after updating with min_slack:");
+    igraph_vector_print(&slack);
+#endif
+  }
+
+  /* Cleanup: remove phantom edges from the matching */
+  for (i = 0; i < no_of_nodes; i++) {
+    if (VECTOR(*types)[i] != smaller_set)
+      continue;
+
+    if (VECTOR(match)[i] != -1) {
+      j = VECTOR(match)[i];
+      neis2 = igraph_adjlist_get(&tight_phantom_edges, i);
+      if (igraph_vector_int_binsearch(neis2, j, 0)) {
+        VECTOR(match)[i] = VECTOR(match)[j] = -1;
+        msize--;
+      }
+    }
+  }
+
+  /* Fill the output parameters */
+  if (matching != 0) {
+    IGRAPH_CHECK(igraph_vector_long_update(matching, &match));
+  }
+  if (matching_size != 0) {
+    *matching_size = msize;
+  }
+  if (matching_weight != 0) {
+    *matching_weight = 0;
+    for (i = 0; i < no_of_edges; i++) {
+      if (IS_TIGHT(i)) {
+        IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) i, &u, &v));
+        if (VECTOR(match)[u] == v)
+          *matching_weight += VECTOR(*weights)[i];
+      }
+    }
+  }
+
+  /* Release everything */
+#undef IS_TIGHT
+  igraph_inclist_destroy(&inclist);
+  igraph_adjlist_destroy(&tight_phantom_edges);
+  igraph_vector_destroy(&parent);
+  igraph_dqueue_long_destroy(&q);
+  igraph_vector_destroy(&labels);
+  igraph_vector_destroy(&vec1);
+  igraph_vector_destroy(&vec2);
+  igraph_vector_destroy(&slack);
+  igraph_vector_long_destroy(&match);
+  IGRAPH_FINALLY_CLEAN(9);
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_maximum_matching(const igraph_t* graph, igraph_integer_t* matching_size,
+    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
+    const igraph_vector_t* weights) {
+  IGRAPH_UNUSED(graph);
+  IGRAPH_UNUSED(matching_size);
+  IGRAPH_UNUSED(matching_weight);
+  IGRAPH_UNUSED(matching);
+  IGRAPH_UNUSED(weights);
+  IGRAPH_ERROR("maximum matching on general graphs not implemented yet",
+      IGRAPH_UNIMPLEMENTED);
+}
+
+#ifdef MATCHING_DEBUG
+#undef MATCHING_DEBUG
+#endif
+
+
diff --git a/src/math.c b/src/math.c
new file mode 100644
index 0000000..c526682
--- /dev/null
+++ b/src/math.c
@@ -0,0 +1,248 @@
+/* -*- 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 <math.h>
+#include <float.h>
+#include <stdarg.h>
+#include "config.h"
+#include "igraph_math.h"
+#include "igraph_types.h"
+
+#ifdef _MSC_VER
+#  define isinf(x) (!_finite(x) && !_isnan(x))
+#endif
+
+int igraph_finite(double x)
+{
+#ifdef isfinite 
+    return isfinite(x);
+#elif HAVE_ISFINITE == 1
+    return isfinite(x);
+#elif HAVE_FINITE == 1
+    return finite(x);
+#else
+/* neither finite nor isfinite work. Do we really need the AIX exception? */
+# ifdef _AIX
+#  include <fp.h>
+     return FINITE(x);
+# else
+    return (!isnan(x) & (x != IGRAPH_POSINFINITY) & (x != IGRAPH_NEGINFINITY));
+# endif
+#endif
+}
+
+double igraph_log2(const double a) {
+  return log(a)/log(2.0);
+}
+
+int igraph_chebyshev_init(const double *dos, int nos, double eta)
+{
+    int i, ii;
+    double err;
+
+    if (nos < 1)
+	return 0;
+
+    err = 0.0;
+    i = 0;			/* just to avoid compiler warnings */
+    for (ii=1; ii<=nos; ii++) {
+	i = nos - ii;
+	err += fabs(dos[i]);
+	if (err > eta) {
+	    return i;
+	}
+    }
+    return i;
+}
+
+double igraph_chebyshev_eval(double x, const double *a, const int n)
+{
+    double b0, b1, b2, twox;
+    int i;
+
+    if (n < 1 || n > 1000) IGRAPH_NAN;
+
+    if (x < -1.1 || x > 1.1) IGRAPH_NAN;
+
+    twox = x * 2;
+    b2 = b1 = 0;
+    b0 = 0;
+    for (i = 1; i <= n; i++) {
+	b2 = b1;
+	b1 = b0;
+	b0 = twox * b1 - b2 + a[n - i];
+    }
+    return (b0 - b2) * 0.5;
+}
+
+double igraph_log1p(double x)
+{
+    /* series for log1p on the interval -.375 to .375
+     *				     with weighted error   6.35e-32
+     *				      log weighted error  31.20
+     *			    significant figures required  30.93
+     *				 decimal places required  32.01
+     */
+    static const double alnrcs[43] = {
+	+.10378693562743769800686267719098e+1,
+	-.13364301504908918098766041553133e+0,
+	+.19408249135520563357926199374750e-1,
+	-.30107551127535777690376537776592e-2,
+	+.48694614797154850090456366509137e-3,
+	-.81054881893175356066809943008622e-4,
+	+.13778847799559524782938251496059e-4,
+	-.23802210894358970251369992914935e-5,
+	+.41640416213865183476391859901989e-6,
+	-.73595828378075994984266837031998e-7,
+	+.13117611876241674949152294345011e-7,
+	-.23546709317742425136696092330175e-8,
+	+.42522773276034997775638052962567e-9,
+	-.77190894134840796826108107493300e-10,
+	+.14075746481359069909215356472191e-10,
+	-.25769072058024680627537078627584e-11,
+	+.47342406666294421849154395005938e-12,
+	-.87249012674742641745301263292675e-13,
+	+.16124614902740551465739833119115e-13,
+	-.29875652015665773006710792416815e-14,
+	+.55480701209082887983041321697279e-15,
+	-.10324619158271569595141333961932e-15,
+	+.19250239203049851177878503244868e-16,
+	-.35955073465265150011189707844266e-17,
+	+.67264542537876857892194574226773e-18,
+	-.12602624168735219252082425637546e-18,
+	+.23644884408606210044916158955519e-19,
+	-.44419377050807936898878389179733e-20,
+	+.83546594464034259016241293994666e-21,
+	-.15731559416479562574899253521066e-21,
+	+.29653128740247422686154369706666e-22,
+	-.55949583481815947292156013226666e-23,
+	+.10566354268835681048187284138666e-23,
+	-.19972483680670204548314999466666e-24,
+	+.37782977818839361421049855999999e-25,
+	-.71531586889081740345038165333333e-26,
+	+.13552488463674213646502024533333e-26,
+	-.25694673048487567430079829333333e-27,
+	+.48747756066216949076459519999999e-28,
+	-.92542112530849715321132373333333e-29,
+	+.17578597841760239233269760000000e-29,
+	-.33410026677731010351377066666666e-30,
+	+.63533936180236187354180266666666e-31,
+    };
+
+    static IGRAPH_THREAD_LOCAL int nlnrel = 0;
+    static IGRAPH_THREAD_LOCAL double xmin = 0.0;
+
+    if (xmin == 0.0) xmin = -1 + sqrt(DBL_EPSILON);/*was sqrt(d1mach(4)); */
+    if (nlnrel == 0) /* initialize chebychev coefficients */
+	nlnrel = igraph_chebyshev_init(alnrcs, 43, DBL_EPSILON/20);/*was .1*d1mach(3)*/
+
+    if (x == 0.) return 0.;/* speed */
+    if (x == -1) return(IGRAPH_NEGINFINITY);
+    if (x  < -1) return(IGRAPH_NAN);
+
+    if (fabs(x) <= .375) {
+        /* Improve on speed (only);
+	   again give result accurate to IEEE double precision: */
+	if(fabs(x) < .5 * DBL_EPSILON)
+	    return x;
+
+	if( (0 < x && x < 1e-8) || (-1e-9 < x && x < 0))
+	    return x * (1 - .5 * x);
+	/* else */
+	return x * (1 - x * igraph_chebyshev_eval(x / .375, alnrcs, nlnrel));
+    }
+    /* else */
+/*     if (x < xmin) { */
+/* 	/\* answer less than half precision because x too near -1 *\/ */
+/*         ML_ERROR(ME_PRECISION, "log1p"); */
+/*     } */
+    return log(1 + x);
+}
+
+long double igraph_fabsl(long double a) { 
+  if (a<0) {
+    return -a;
+  } else {
+    return a;
+  }
+}
+
+double igraph_fmin(double a, double b) { 
+  if (b<a) {
+    return b;
+  } else {
+    return a;
+  }
+}
+
+double igraph_i_round(double X) {
+  
+  /* NaN */
+  if (X != X) { return X; }
+
+  if (X < 0.0) { 
+    return floor(X);
+  }
+
+  return ceil(X);
+}
+
+#ifdef _MSC_VER
+/**
+ * Internal function, replacement for snprintf
+ * Used only in case of the Microsoft Visual C compiler which does not
+ * provide a proper sprintf implementation.
+ * 
+ * This implementation differs from the standard in the value returned
+ * when the number of characters needed by the output, excluding the
+ * terminating '\0' is larger than count
+ */
+int igraph_i_snprintf(char *buffer, size_t count, const char *format, ...) {
+    int n;
+    va_list args;
+    if (count > 0) {
+	va_start(args, format);
+        n = _vsnprintf(buffer, count, format, args);
+        buffer[count-1] = 0;
+        va_end(args);
+    } else n=0;
+    return n;
+}
+
+#endif
+
+int igraph_is_nan(double x) {
+  return isnan(x);
+}
+
+int igraph_is_inf(double x) {
+  return isinf(x) != 0;
+}
+
+int igraph_is_posinf(double x) {
+  return isinf(x) == 1;
+}
+
+int igraph_is_neginf(double x) {
+  return isinf(x) == -1;
+}
diff --git a/src/matrix.c b/src/matrix.c
new file mode 100644
index 0000000..d8f93cf
--- /dev/null
+++ b/src/matrix.c
@@ -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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_matrix.h"
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "matrix.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "matrix.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "matrix.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "matrix.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "matrix.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_COMPLEX
+#include "igraph_pmt.h"
+#include "matrix.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_COMPLEX
+
+#ifndef USING_R
+int igraph_matrix_complex_print(const igraph_matrix_complex_t *m) {
+
+  long int nr=igraph_matrix_complex_nrow(m);
+  long int nc=igraph_matrix_complex_ncol(m);
+  long int i, j;
+  for (i=0; i<nr; i++) {
+    for (j=0; j<nc; j++) {
+      igraph_complex_t z=MATRIX(*m, i, j);
+      if (j!=0) { putchar(' '); }
+      printf("%g%+gi", IGRAPH_REAL(z), IGRAPH_IMAG(z));
+    }
+    printf("\n");
+  }
+  
+  return 0;
+}
+#endif
+
+int igraph_matrix_complex_fprint(const igraph_matrix_complex_t *m, 
+				 FILE *file) {
+
+  long int nr=igraph_matrix_complex_nrow(m);
+  long int nc=igraph_matrix_complex_ncol(m);
+  long int i, j;
+  for (i=0; i<nr; i++) {
+    for (j=0; j<nc; j++) {
+      igraph_complex_t z=MATRIX(*m, i, j);
+      if (j!=0) { fputc(' ', file); }
+      fprintf(file, "%g%+gi", IGRAPH_REAL(z), IGRAPH_IMAG(z));
+    }
+    fprintf(file, "\n");
+  }
+  
+  return 0;
+}
+
+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);
+  IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol));
+  IGRAPH_CHECK(igraph_vector_complex_real(&v->data, &real->data));
+  return 0;
+}
+
+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);
+  IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol));
+  IGRAPH_CHECK(igraph_vector_complex_imag(&v->data, &imag->data));
+  return 0;
+}
+
+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, 
+					      &imag->data));
+  return 0;
+}
+
+int igraph_matrix_complex_create(igraph_matrix_complex_t *v,
+				 const igraph_matrix_t *real,
+				 const igraph_matrix_t *imag) {
+  IGRAPH_CHECK(igraph_vector_complex_create(&v->data, &real->data,
+					    &imag->data));
+  return 0;
+}
+
+int igraph_matrix_complex_create_polar(igraph_matrix_complex_t *v,
+				       const igraph_matrix_t *r,
+				       const igraph_matrix_t *theta) {
+  IGRAPH_CHECK(igraph_vector_complex_create_polar(&v->data, &r->data,
+						  &theta->data));
+  return 0;
+}
+
+igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs,
+				      const igraph_matrix_t *rhs,
+				      igraph_real_t tol) {
+  return igraph_vector_e_tol(&lhs->data, &rhs->data, tol);
+}
diff --git a/src/matrix.pmt b/src/matrix.pmt
new file mode 100644
index 0000000..b9a37d5
--- /dev/null
+++ b/src/matrix.pmt
@@ -0,0 +1,1607 @@
+/* -*- 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
+
+*/
+
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+/** 
+ * \section about_igraph_matrix_t_objects About \type igraph_matrix_t objects
+ * 
+ * <para>This type is just an interface to \type igraph_vector_t.</para>
+ *
+ * <para>The \type igraph_matrix_t type usually stores n
+ * elements in O(n) space, but not always. See the documentation of
+ * the vector type.</para>
+ */
+
+/**
+ * \section igraph_matrix_constructor_and_destructor Matrix constructors and
+ * destructors
+ */
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_init
+ * \brief Initializes a matrix.
+ * 
+ * </para><para>
+ * Every matrix needs to be initialized before using it. This is done
+ * by calling this function. A matrix has to be destroyed if it is not
+ * needed any more; see \ref igraph_matrix_destroy().
+ * \param m Pointer to a not yet initialized matrix object to be
+ *        initialized. 
+ * \param nrow The number of rows in the matrix.
+ * \param ncol The number of columns in the matrix.
+ * \return Error code.
+ *
+ * Time complexity: usually O(n), 
+ * n is the
+ * number of elements in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,init)(TYPE(igraph_matrix) *m, long int nrow, long int ncol) {
+  int ret1;
+  ret1=FUNCTION(igraph_vector,init)(&m->data, nrow*ncol);
+  m->nrow=nrow;
+  m->ncol=ncol;
+  return ret1;
+}
+
+/** 
+ * \ingroup matrix
+ * \function igraph_matrix_destroy
+ * \brief Destroys a matrix object.
+ * 
+ * </para><para>
+ * This function frees all the memory allocated for a matrix
+ * object. The destroyed object needs to be reinitialized before using
+ * it again.
+ * \param m The matrix to destroy.
+ * 
+ * Time complexity: operating system dependent.
+ */ 
+
+void FUNCTION(igraph_matrix,destroy)(TYPE(igraph_matrix) *m) {
+  FUNCTION(igraph_vector,destroy)(&m->data);
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_capacity
+ * \brief Returns the number of elements allocated for a matrix.
+ * 
+ * Note that this might be different from the size of the matrix (as 
+ * queried by \ref igraph_matrix_size(), and specifies how many elements 
+ * the matrix can hold, without reallocation.
+ * \param v Pointer to the (previously initialized) matrix object
+ *          to query.
+ * \return The allocated capacity.
+ * 
+ * \sa \ref igraph_matrix_size(), \ref igraph_matrix_nrow(),
+ * \ref igraph_matrix_ncol(). 
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_matrix,capacity)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,capacity)(&m->data);
+}
+
+
+/**
+ * \section igraph_matrix_accessing_elements Accessing elements of a matrix
+ */
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_resize
+ * \brief Resizes a matrix.
+ *
+ * </para><para>
+ * This function resizes a matrix by adding more elements to it.
+ * The matrix contains arbitrary data after resizing it.
+ * That is, after calling this function you cannot expect that element
+ * (i,j) in the matrix remains the
+ * same as before.  
+ * \param m Pointer to an already initialized matrix object.
+ * \param nrow The number of rows in the resized matrix.
+ * \param ncol The number of columns in the resized matrix.
+ * \return Error code.
+ * 
+ * Time complexity: O(1) if the
+ * matrix gets smaller, usually O(n)
+ * if it gets larger, n is the 
+ * number of elements in the resized matrix.
+ */
+
+int FUNCTION(igraph_matrix,resize)(TYPE(igraph_matrix) *m, long int nrow, long int ncol) {
+  FUNCTION(igraph_vector,resize)(&m->data, nrow*ncol);
+  m->nrow=nrow;
+  m->ncol=ncol;
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_resize_min
+ * \brief Deallocates unused memory for a matrix.
+ * 
+ * </para><para>
+ * Note that this function might fail if there is not enough memory
+ * available. 
+ * 
+ * </para><para>
+ * Also note, that this function leaves the matrix intact, i.e. 
+ * it does not destroy any of the elements. However, usually it involves 
+ * copying the matrix in memory.
+ * \param m Pointer to an initialized matrix.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_matrix_resize().
+ * 
+ * Time complexity: operating system dependent.
+ */
+
+int FUNCTION(igraph_matrix,resize_min)(TYPE(igraph_matrix) *m) {
+  TYPE(igraph_vector) tmp;
+  long int size=FUNCTION(igraph_matrix,size)(m);
+  long int capacity=FUNCTION(igraph_matrix,capacity)(m);
+  if (size == capacity) { return 0; }
+  
+  IGRAPH_CHECK(FUNCTION(igraph_vector,init)(&tmp, size));
+  FUNCTION(igraph_vector,update)(&tmp, &m->data);
+  FUNCTION(igraph_vector,destroy)(&m->data);
+  m->data = tmp;
+  
+  return 0;
+}
+
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_size
+ * \brief The number of elements in a matrix.
+ * 
+ * \param m Pointer to an initialized matrix object.
+ * \return The size of the matrix.
+ *
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_matrix,size)(const TYPE(igraph_matrix) *m) {
+  return (m->nrow) * (m->ncol);
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_nrow
+ * \brief The number of rows in a matrix.
+ * 
+ * \param m Pointer to an initialized matrix object.
+ * \return The number of rows in the matrix.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_matrix,nrow)(const TYPE(igraph_matrix) *m) {
+  return m->nrow;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_ncol
+ * \brief The number of columns in a matrix.
+ * 
+ * \param m Pointer to an initialized matrix object.
+ * \return The number of columns in the matrix.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_matrix,ncol)(const TYPE(igraph_matrix) *m) {
+  return m->ncol;
+}
+
+/** 
+ * \ingroup matrix
+ * \function igraph_matrix_copy_to
+ * \brief Copies a matrix to a regular C array.
+ *
+ * </para><para>
+ * The matrix is copied columnwise, as this is the format most
+ * programs and languages use.
+ * The C array should be of sufficient size; there are (of course) no
+ * range checks.
+ * \param m Pointer to an initialized matrix object.
+ * \param to Pointer to a C array; the place to copy the data to.
+ * \return Error code.
+ *
+ * Time complexity: O(n),
+ * n is the number of 
+ * elements in the matrix.
+ */
+
+void FUNCTION(igraph_matrix,copy_to)(const TYPE(igraph_matrix) *m, BASE *to) {
+  FUNCTION(igraph_vector,copy_to)(&m->data, to);
+}
+
+/** 
+ * \ingroup matrix
+ * \function igraph_matrix_null
+ * \brief Sets all elements in a matrix to zero.
+ * 
+ * \param m Pointer to an initialized matrix object.
+ * 
+ * Time complexity: O(n),
+ * n is the number of  elements in
+ * the matrix. 
+ */
+
+void FUNCTION(igraph_matrix,null)(TYPE(igraph_matrix) *m) {
+  FUNCTION(igraph_vector,null)(&m->data);
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_add_cols
+ * \brief Adds columns to a matrix.
+ * \param m The matrix object.
+ * \param n The number of columns to add.
+ * \return Error code, \c IGRAPH_ENOMEM if there is
+ *   not enough memory to perform the operation.
+ *
+ * Time complexity: linear with the number of elements of the new,
+ * resized matrix.
+ */
+
+int FUNCTION(igraph_matrix,add_cols)(TYPE(igraph_matrix) *m, long int n) {
+  FUNCTION(igraph_matrix,resize)(m, m->nrow, m->ncol+n);
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_add_rows
+ * \brief Adds rows to a matrix.
+ * \param m The matrix object.
+ * \param n The number of rows to add.
+ * \return Error code, \c IGRAPH_ENOMEM if there
+ *   isn't enough memory for the operation.
+ * 
+ * Time complexity: linear with the number of elements of the new,
+ * resized matrix.
+ */
+
+int FUNCTION(igraph_matrix,add_rows)(TYPE(igraph_matrix) *m, long int n) {
+  long int i;
+  FUNCTION(igraph_vector,resize)(&m->data, (m->ncol)*(m->nrow+n));
+  for (i=m->ncol-1; i>=0; i--) {
+    FUNCTION(igraph_vector,move_interval2)(&m->data, (m->nrow)*i, (m->nrow)*(i+1),
+					  (m->nrow+n)*i);
+  }
+  m->nrow += n;
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_remove_col
+ * \brief Removes a column from a matrix.
+ * 
+ * \param m The matrix object.
+ * \param col The column to remove.
+ * \return Error code, always returns with success. 
+ * 
+ * Time complexity: linear with the number of elements of the new,
+ * resized matrix.
+ */
+
+int FUNCTION(igraph_matrix,remove_col)(TYPE(igraph_matrix) *m, long int col) {
+  FUNCTION(igraph_vector,remove_section)(&m->data, (m->nrow)*col, (m->nrow)*(col+1));
+  m->ncol--;
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_permdelete_rows
+ * \brief Removes rows from a matrix (for internal use).
+ * 
+ * Time complexity: linear with the number of elements of the original
+ * matrix. 
+ */
+
+int FUNCTION(igraph_matrix,permdelete_rows)(TYPE(igraph_matrix) *m, long int *index, long int nremove) {
+  long int i, j;
+  for (j=0; j<m->nrow; j++) {
+    if (index[j] != 0) {
+      for (i=0; i<m->ncol; i++) {
+        MATRIX(*m, index[j]-1, i) = MATRIX(*m, j, i);
+      }
+    }
+  }
+  /* Remove unnecessary elements from the end of each column */
+  for (i=0; i<m->ncol; i++)
+    FUNCTION(igraph_vector,remove_section)(&m->data,
+      (i+1)*(m->nrow-nremove), (i+1)*(m->nrow-nremove)+nremove);
+  FUNCTION(igraph_matrix,resize)(m, m->nrow-nremove, m->ncol);
+
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_delete_rows_neg
+ * \brief Removes columns from a matrix (for internal use).
+ * 
+ * Time complexity: linear with the number of elements of the original
+ * matrix. 
+ */
+
+int FUNCTION(igraph_matrix,delete_rows_neg)(TYPE(igraph_matrix) *m, 
+					    const igraph_vector_t *neg, long int nremove) {
+  long int i, j, idx=0;
+  for (i=0; i<m->ncol; i++) {
+    for (j=0; j<m->nrow; j++) {
+      if (VECTOR(*neg)[j] >= 0) {
+	MATRIX(*m, idx++, i) = MATRIX(*m, j, i);
+      } 
+    }
+    idx=0;
+  }
+  FUNCTION(igraph_matrix,resize)(m, m->nrow-nremove, m->ncol);
+
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_matrix_copy
+ * \brief Copies a matrix.
+ *
+ * </para><para>
+ * Creates a matrix object by copying from an existing matrix.
+ * \param to Pointer to an uninitialized matrix object.
+ * \param from The initialized matrix object to copy.
+ * \return Error code, \c IGRAPH_ENOMEM if there
+ *   isn't enough memory to allocate the new matrix.
+ * 
+ * Time complexity: O(n), the number
+ * of elements in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,copy)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from) {
+  to->nrow = from->nrow;
+  to->ncol = from->ncol;
+  return FUNCTION(igraph_vector,copy)(&to->data, &from->data);
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_matrix_max
+ * 
+ * Returns the maximal element of a matrix.
+ * \param m The matrix object.
+ * \return The maximum element. For empty matrix the returned value is
+ * undefined. 
+ * 
+ * Added in version 0.2.</para><para>
+ *
+ * Time complexity: O(n), the number of elements in the matrix.
+ */
+
+igraph_real_t FUNCTION(igraph_matrix,max)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,max)(&m->data);
+}
+
+#endif
+
+/**
+ * \function igraph_matrix_scale
+ * 
+ * Multiplies each element of the matrix by a constant.
+ * \param m The matrix.
+ * \param by The constant.
+ *
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(n), the number of elements in the matrix.
+ */
+
+void FUNCTION(igraph_matrix,scale)(TYPE(igraph_matrix) *m, BASE by) {
+  FUNCTION(igraph_vector,scale)(&m->data, by);
+}
+
+/**
+ * \function igraph_matrix_select_rows
+ * \brief Select some rows of a matrix.
+ * 
+ * This function selects some rows of a matrix and returns them in a
+ * new matrix. The result matrix should be initialized before calling
+ * the function.
+ * \param m The input matrix.
+ * \param res The result matrix. It should be initialized and will be
+ *    resized as needed.
+ * \param rows Vector; it contains the row indices (starting with
+ *    zero) to extract. Note that no range checking is performed.
+ * \return Error code.
+ * 
+ * Time complexity: O(nm), n is the number of rows, m the number of
+ * columns of the result matrix.
+ */
+
+int FUNCTION(igraph_matrix,select_rows)(const TYPE(igraph_matrix) *m, 
+					TYPE(igraph_matrix) *res, 
+					const igraph_vector_t *rows) {
+  long int norows=igraph_vector_size(rows);
+  long int i, j, ncols=FUNCTION(igraph_matrix,ncol)(m);
+  
+  IGRAPH_CHECK(FUNCTION(igraph_matrix,resize)(res, norows, ncols));
+  for (i=0; i<norows; i++) {
+    for (j=0; j<ncols; j++) {
+      MATRIX(*res, i, j) = MATRIX(*m, (long int)VECTOR(*rows)[i], j);
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_select_rows_cols
+ * \brief Select some rows and columns of a matrix.
+ * 
+ * This function selects some rows and columns of a matrix and returns
+ * them in a new matrix. The result matrix should be initialized before
+ * calling the function.
+ * \param m The input matrix.
+ * \param res The result matrix. It should be initialized and will be
+ *    resized as needed.
+ * \param rows Vector; it contains the row indices (starting with
+ *    zero) to extract. Note that no range checking is performed.
+ * \param cols Vector; it contains the column indices (starting with
+ *    zero) to extract. Note that no range checking is performed.
+ * \return Error code.
+ * 
+ * Time complexity: O(nm), n is the number of rows, m the number of
+ * columns of the result matrix.
+ */
+
+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) {
+  long int nrows=igraph_vector_size(rows);
+  long int ncols=igraph_vector_size(cols);
+  long int i, j;
+  
+  IGRAPH_CHECK(FUNCTION(igraph_matrix,resize)(res, nrows, ncols));
+  for (i=0; i<nrows; i++) {
+    for (j=0; j<ncols; j++) {
+      MATRIX(*res, i, j) = MATRIX(*m, (long int)VECTOR(*rows)[i],
+	                                  (long int)VECTOR(*cols)[j]);
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_get_col
+ * \brief Select a column.
+ * 
+ * Extract a column of a matrix and return it as a vector.
+ * \param m The input matrix.
+ * \param res The result will we stored in this vector. It should be
+ *   initialized and will be resized as needed.
+ * \param index The index of the column to select.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of rows in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,get_col)(const TYPE(igraph_matrix) *m, 
+				    TYPE(igraph_vector) *res,
+				    long int index) {
+  long int nrow=FUNCTION(igraph_matrix,nrow)(m);
+
+  if (index>=m->ncol) {
+    IGRAPH_ERROR("Index out of range for selecting matrix column", IGRAPH_EINVAL);
+  }
+  IGRAPH_CHECK(FUNCTION(igraph_vector,get_interval)(&m->data, res, 
+						    nrow*index, nrow*(index+1)));
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_sum
+ * \brief Sum of elements.
+ * 
+ * Returns the sum of the elements of a matrix.
+ * \param m The input matrix.
+ * \return The sum of the elements.
+ * 
+ * Time complexity: O(mn), the number of elements in the matrix.
+ */
+
+BASE FUNCTION(igraph_matrix,sum)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,sum)(&m->data);
+}
+
+/**
+ * \function igraph_matrix_all_e
+ * \brief Are all elements equal?
+ * 
+ * \param lhs The first matrix.
+ * \param rhs The second matrix.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    equal to the corresponding elements in \p rhs. Returns \c 0
+ *    (=false) if the dimensions of the matrices don't match.
+ * 
+ * Time complexity: O(nm), the size of the matrices.
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,all_e)(const TYPE(igraph_matrix) *lhs, 
+					    const TYPE(igraph_matrix) *rhs) {
+  return lhs->ncol==rhs->ncol && lhs->nrow==rhs->nrow &&
+    FUNCTION(igraph_vector,all_e)(&lhs->data, &rhs->data);
+}
+
+igraph_bool_t 
+FUNCTION(igraph_matrix,is_equal)(const TYPE(igraph_matrix) *lhs, 
+				 const TYPE(igraph_matrix) *rhs) {
+  return FUNCTION(igraph_matrix,all_e)(lhs, rhs);
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_matrix_all_l
+ * \brief Are all elements less?
+ * 
+ * \param lhs The first matrix.
+ * \param rhs The second matrix.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    less than the corresponding elements in \p rhs. Returns \c 0
+ *    (=false) if the dimensions of the matrices don't match.
+ * 
+ * Time complexity: O(nm), the size of the matrices.
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,all_l)(const TYPE(igraph_matrix) *lhs, 
+					    const TYPE(igraph_matrix) *rhs) {
+  return lhs->ncol==rhs->ncol && lhs->nrow==rhs->nrow &&
+    FUNCTION(igraph_vector,all_l)(&lhs->data, &rhs->data);
+}
+
+/**
+ * \function igraph_matrix_all_g
+ * \brief Are all elements greater?
+ * 
+ * \param lhs The first matrix.
+ * \param rhs The second matrix.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    greater than the corresponding elements in \p rhs. Returns \c 0
+ *    (=false) if the dimensions of the matrices don't match.
+ * 
+ * Time complexity: O(nm), the size of the matrices.
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,all_g)(const TYPE(igraph_matrix) *lhs, 
+					    const TYPE(igraph_matrix) *rhs) {
+  return lhs->ncol==rhs->ncol && lhs->nrow==rhs->nrow &&
+    FUNCTION(igraph_vector,all_g)(&lhs->data, &rhs->data);
+}
+
+/**
+ * \function igraph_matrix_all_le
+ * \brief Are all elements less or equal?
+ * 
+ * \param lhs The first matrix.
+ * \param rhs The second matrix.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    less than or equal to the corresponding elements in \p
+ *    rhs. Returns \c 0 (=false) if the dimensions of the matrices
+ *    don't match.
+ * 
+ * Time complexity: O(nm), the size of the matrices.
+ */
+
+igraph_bool_t 
+FUNCTION(igraph_matrix,all_le)(const TYPE(igraph_matrix) *lhs, 
+			       const TYPE(igraph_matrix) *rhs) {
+  return lhs->ncol==rhs->ncol && lhs->nrow==rhs->nrow &&
+    FUNCTION(igraph_vector,all_le)(&lhs->data, &rhs->data);
+}
+
+/**
+ * \function igraph_matrix_all_ge
+ * \brief Are all elements greater or equal?
+ * 
+ * \param lhs The first matrix.
+ * \param rhs The second matrix.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    greater than or equal to the corresponding elements in \p
+ *    rhs. Returns \c 0 (=false) if the dimensions of the matrices
+ *    don't match.
+ * 
+ * Time complexity: O(nm), the size of the matrices.
+ */
+
+igraph_bool_t 
+FUNCTION(igraph_matrix,all_ge)(const TYPE(igraph_matrix) *lhs, 
+			       const TYPE(igraph_matrix) *rhs) {
+  return lhs->ncol==rhs->ncol && lhs->nrow==rhs->nrow &&
+    FUNCTION(igraph_vector,all_ge)(&lhs->data, &rhs->data);
+}
+
+#endif
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_matrix_maxdifference
+ * \brief Maximum absolute difference between two matrices.
+ * 
+ * Calculate the maximum absolute difference of two matrices. Both matrices
+ * must be non-empty. If their dimensions differ then a warning is given and
+ * the comparison is performed by vectors columnwise from both matrices.
+ * The remaining elements in the larger vector are ignored.
+ * \param m1 The first matrix.
+ * \param m2 The second matrix.
+ * \return The element with the largest absolute value in \c m1 - \c m2.
+ * 
+ * Time complexity: O(mn), the elements in the smaller matrix.
+ */
+
+BASE FUNCTION(igraph_matrix,maxdifference)(const TYPE(igraph_matrix) *m1,
+					   const TYPE(igraph_matrix) *m2) {
+  long int col1=FUNCTION(igraph_matrix,ncol)(m1);
+  long int col2=FUNCTION(igraph_matrix,ncol)(m2);
+  long int row1=FUNCTION(igraph_matrix,nrow)(m1);
+  long int row2=FUNCTION(igraph_matrix,nrow)(m2);
+  if (col1 != col2 || row1 != row2) {
+    IGRAPH_WARNING("Comparing non-conformant matrices");
+  }
+  return FUNCTION(igraph_vector,maxdifference)(&m1->data, &m2->data);
+}
+
+#endif
+
+/**
+ * \function igraph_matrix_transpose
+ * \brief Transpose a matrix.
+ * 
+ * Calculate the transpose of a matrix. Note that the function
+ * reallocates the memory used for the matrix.
+ * \param m The input (and output) matrix.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,transpose)(TYPE(igraph_matrix) *m) {
+  long int nrow=m->nrow;
+  long int ncol=m->ncol;
+  if (nrow>1 && ncol>1) {
+    TYPE(igraph_vector) newdata;
+    long int i, size=nrow*ncol, mod=size-1;
+    FUNCTION(igraph_vector,init)(&newdata, size);
+    IGRAPH_FINALLY(FUNCTION(igraph_vector,destroy), &newdata);
+    for (i=0; i<size; i++) {
+      VECTOR(newdata)[i] = VECTOR(m->data)[ (i*nrow) % mod ];
+    }
+    VECTOR(newdata)[size-1]=VECTOR(m->data)[size-1];
+    FUNCTION(igraph_vector,destroy)(&m->data);
+    IGRAPH_FINALLY_CLEAN(1);
+    m->data=newdata;
+  }
+  m->nrow=ncol;
+  m->ncol=nrow;
+  
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_e
+ * Extract an element from a matrix.
+ * 
+ * Use this if you need a function for some reason and cannot use the
+ * \ref MATRIX macro. Note that no range checking is performed.
+ * \param m The input matrix.
+ * \param row The row index.
+ * \param col The column index.
+ * \return The element in the given row and column.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_matrix,e)(const TYPE(igraph_matrix) *m, 
+			       long int row, long int col) {
+  return MATRIX(*m, row, col);
+}
+
+/**
+ * \function igraph_matrix_e_ptr
+ * Pointer to an element of a matrix.
+ * 
+ * The function returns a pointer to an element. No range checking is
+ * performed. 
+ * \param m The input matrix.
+ * \param row The row index.
+ * \param col The column index.
+ * \return Pointer to the element in the given row and column.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE* FUNCTION(igraph_matrix,e_ptr)(const TYPE(igraph_matrix) *m,
+				    long int row, long int col) {
+  return &MATRIX(*m, row, col);
+}
+
+/**
+ * \function igraph_matrix_set
+ * Set an element.
+ * 
+ * Set an element of a matrix. No range checking is performed.
+ * \param m The input matrix.
+ * \param row The row index.
+ * \param col The column index.
+ * \param value The new value of the element.
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_matrix,set)(TYPE(igraph_matrix)* m, long int row, long int col,
+				 BASE value) {
+  MATRIX(*m, row, col) = value;
+}
+
+/**
+ * \function igraph_matrix_fill
+ * Fill with an element.
+ * 
+ * Set the matrix to a constant matrix.
+ * \param m The input matrix.
+ * \param e The element to set.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+void FUNCTION(igraph_matrix,fill)(TYPE(igraph_matrix) *m, BASE e) {
+  FUNCTION(igraph_vector,fill)(&m->data, e);
+}
+
+/**
+ * \function igraph_matrix_update
+ * Update from another matrix.
+ * 
+ * This function replicates \p from in the matrix \p to. 
+ * Note that \p to must be already initialized.
+ * \param to The result matrix.
+ * \param from The matrix to replicate; it is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,update)(TYPE(igraph_matrix) *to, 
+				   const TYPE(igraph_matrix) *from) {
+
+  IGRAPH_CHECK(FUNCTION(igraph_matrix,resize)(to, from->nrow, from->ncol));
+  FUNCTION(igraph_vector,update)(&to->data, &from->data);
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_rbind
+ * Combine two matrices rowwise.
+ *
+ * This function places the rows of \p from below the rows of \c to
+ * and stores the result in \p to. The number of columns in the two
+ * matrices must match.
+ * \param to The upper matrix; the result is also stored here.
+ * \param from The lower matrix. It is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the newly created
+ * matrix.
+ */
+
+int FUNCTION(igraph_matrix,rbind)(TYPE(igraph_matrix) *to,
+				  const TYPE(igraph_matrix) *from) {
+  long int tocols=to->ncol, fromcols=from->ncol;
+  long int torows=to->nrow, fromrows=from->nrow;
+  long int offset, c, r, index, offset2;
+  if (tocols != fromcols) {
+    IGRAPH_ERROR("Cannot do rbind, number of columns do not match", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(&to->data, 
+					      tocols * (fromrows+torows)));
+  to->nrow += fromrows;
+
+  offset=(tocols-1) * fromrows;
+  index=tocols*torows-1;
+  for (c=tocols-1; c>0; c--) {
+    for (r=0; r<torows; r++, index--) {
+      VECTOR(to->data)[index+offset] = VECTOR(to->data)[index];
+    }
+    offset -= fromrows;
+  }
+  
+  offset=torows; offset2=0;
+  for (c=0; c<tocols; c++) {
+    memcpy(VECTOR(to->data)+offset, VECTOR(from->data)+offset2,
+	   sizeof(BASE) * (size_t) fromrows);
+    offset+=fromrows+torows;
+    offset2+=fromrows;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_cbind
+ * Combine matrices columnwise.
+ * 
+ * This function places the columns of \p from on the right of \p to,
+ * and stores the result in \p to.
+ * \param to The left matrix; the result is stored here too.
+ * \param from The right matrix. It is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements on the new matrix.
+ */
+
+int FUNCTION(igraph_matrix,cbind)(TYPE(igraph_matrix) *to,
+				  const TYPE(igraph_matrix) *from) {
+  
+  long int tocols=to->ncol, fromcols=from->ncol;
+  long int torows=to->nrow, fromrows=from->nrow;
+  if (torows != fromrows) {
+    IGRAPH_ERROR("Cannot do rbind, number of rows do not match", IGRAPH_EINVAL);
+  }
+  IGRAPH_CHECK(FUNCTION(igraph_matrix,resize)(to, torows, tocols+fromcols));
+  FUNCTION(igraph_vector,copy_to)(&from->data, VECTOR(to->data)+tocols*torows);
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_swap
+ * Swap two matrices.
+ * 
+ * The contents of the two matrices will be swapped. They must have the
+ * same dimensions.
+ * \param m1 The first matrix.
+ * \param m2 The second matrix.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the matrices.
+ */
+
+int FUNCTION(igraph_matrix,swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2) {
+  if (m1->nrow != m2->nrow || m1->ncol != m2->ncol) {
+    IGRAPH_ERROR("Cannot swap non-conformant matrices", IGRAPH_EINVAL);
+  }
+  return FUNCTION(igraph_vector,swap)(&m1->data, &m2->data);
+}
+
+/**
+ * \function igraph_matrix_get_row
+ * Extract a row.
+ * 
+ * Extract a row from a matrix and return it as a vector.
+ * \param m The input matrix.
+ * \param res Pointer to an initialized vector; it will be resized if
+ *   needed.
+ * \param index The index of the row to select.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of columns in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,get_row)(const TYPE(igraph_matrix) *m, 
+				    TYPE(igraph_vector) *res, long int index) {
+  long int rows=m->nrow, cols=m->ncol;
+  long int i, j;
+  
+  if (index >= rows) {
+    IGRAPH_ERROR("Index out of range for selecting matrix row", IGRAPH_EINVAL);
+  }
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(res, cols));
+  
+  for (i=index, j=0; j<cols; i+=rows, j++) {
+    VECTOR(*res)[j] = VECTOR(m->data)[i];
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_set_row
+ * Set a row from a vector.
+ * 
+ * Sets the elements of a row with the given vector. This has the effect of
+ * setting row \c index to have the elements in the vector \c v. The length of
+ * the vector and the number of columns in the matrix must match,
+ * otherwise an error is triggered.
+ * \param m The input matrix.
+ * \param v The vector containing the new elements of the row.
+ * \param index Index of the row to set.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of columns in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,set_row)(TYPE(igraph_matrix) *m,
+				    const TYPE(igraph_vector) *v, long int index) {
+  long int rows=m->nrow, cols=m->ncol;
+  long int i, j;
+  
+  if (index >= rows) {
+    IGRAPH_ERROR("Index out of range for selecting matrix row", IGRAPH_EINVAL);
+  }
+  if (FUNCTION(igraph_vector,size)(v) != cols) {
+    IGRAPH_ERROR("Cannot set matrix row, invalid vector length", IGRAPH_EINVAL);
+  }
+  for (i=index, j=0; j<cols; i+=rows, j++) {
+    VECTOR(m->data)[i]=VECTOR(*v)[j];
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_set_col
+ * Set a column from a vector.
+ *
+ * Sets the elements of a column with the given vector. In effect, column
+ * \c index will be set with elements from the vector \c v. The length of
+ * the vector and the number of rows in the matrix must match,
+ * otherwise an error is triggered.
+ * \param m The input matrix.
+ * \param v The vector containing the new elements of the column.
+ * \param index Index of the column to set.
+ * \return Error code.
+ * 
+ * Time complexity: O(m), the number of rows in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,set_col)(TYPE(igraph_matrix) *m,
+				    const TYPE(igraph_vector) *v, long int index) {
+  long int rows=m->nrow, cols=m->ncol;
+  long int i, j;
+  
+  if (index >= cols) {
+    IGRAPH_ERROR("Index out of range for setting matrix column", IGRAPH_EINVAL);
+  }
+  if (FUNCTION(igraph_vector,size)(v) != rows) {
+    IGRAPH_ERROR("Cannot set matrix column, invalid vector length", IGRAPH_EINVAL);
+  }
+  for (i=index*rows, j=0; j<rows; i++, j++) {
+    VECTOR(m->data)[i]=VECTOR(*v)[j];
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_swap_rows
+ * Swap two rows.
+ * 
+ * Swap two rows in the matrix.
+ * \param m The input matrix.
+ * \param i The index of the first row.
+ * \param j The index of the second row.
+ * \return Error code.
+ *
+ * Time complexity: O(n), the number of columns.
+ */
+
+int FUNCTION(igraph_matrix,swap_rows)(TYPE(igraph_matrix) *m, 
+				      long int i, long int j) {
+  long int ncol=m->ncol, nrow=m->nrow;
+  long int n=nrow*ncol;
+  long int index1, index2;
+  if (i>=nrow || j>=nrow) {
+    IGRAPH_ERROR("Cannot swap rows, index out of range", IGRAPH_EINVAL);
+  }
+  if (i==j) { return 0; }
+  for (index1=i, index2=j; index1<n; index1+=nrow, index2+=nrow) {
+    BASE tmp;
+    tmp=VECTOR(m->data)[index1];
+    VECTOR(m->data)[index1]=VECTOR(m->data)[index2];
+    VECTOR(m->data)[index2]=tmp;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_swap_cols
+ * Swap two columns.
+ * 
+ * Swap two columns in the matrix.
+ * \param m The input matrix.
+ * \param i The index of the first column.
+ * \param j The index of the second column.
+ * \return Error code.
+ *
+ * Time complexity: O(m), the number of rows.
+ */
+
+int FUNCTION(igraph_matrix,swap_cols)(TYPE(igraph_matrix) *m, 
+				      long int i, long int j) {
+  long int ncol=m->ncol, nrow=m->nrow;
+  long int k, index1, index2;
+  if (i>=ncol || j >= ncol) {
+    IGRAPH_ERROR("Cannot swap columns, index out of range", IGRAPH_EINVAL);
+  }
+  if (i==j) { return 0; }
+  for (index1=i*nrow, index2=j*nrow, k=0; k<nrow; k++, index1++, index2++) {
+    BASE tmp=VECTOR(m->data)[index1];
+    VECTOR(m->data)[index1]=VECTOR(m->data)[index2];
+    VECTOR(m->data)[index2]=tmp;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_add_constant
+ * Add a constant to every element.
+ * 
+ * \param m The input matrix.
+ * \param plud The constant to add.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+void FUNCTION(igraph_matrix,add_constant)(TYPE(igraph_matrix) *m, BASE plus) {
+  FUNCTION(igraph_vector,add_constant)(&m->data, plus);
+}
+
+/**
+ * \function igraph_matrix_add
+ * Add two matrices.
+ * 
+ * Add \p m2 to \p m1, and store the result in \p m1. The dimensions of the
+ * matrices must match.
+ * \param m1 The first matrix; the result will be stored here.
+ * \param m2 The second matrix; it is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,add)(TYPE(igraph_matrix) *m1, 
+				const TYPE(igraph_matrix) *m2) {
+  if (m1->nrow != m2->nrow || m1->ncol != m2->ncol) {
+    IGRAPH_ERROR("Cannot add non-conformant matrices", IGRAPH_EINVAL);
+  }
+  return FUNCTION(igraph_vector,add)(&m1->data, &m2->data);
+}
+
+/**
+ * \function igraph_matrix_sub
+ * Difference of two matrices.
+ * 
+ * Subtract \p m2 from \p m1 and store the result in \p m1.
+ * The dimensions of the two matrices must match.
+ * \param m1 The first matrix; the result is stored here.
+ * \param m2 The second matrix; it is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,sub)(TYPE(igraph_matrix) *m1, 
+				const TYPE(igraph_matrix) *m2) {
+  if (m1->nrow != m2->nrow || m1->ncol != m2->ncol) {
+    IGRAPH_ERROR("Cannot subtract non-conformant matrices", IGRAPH_EINVAL);
+  }
+  return FUNCTION(igraph_vector,sub)(&m1->data, &m2->data);
+}
+
+/**
+ * \function igraph_matrix_mul_elements
+ * Elementwise multiplication.
+ * 
+ * Multiply \p m1 by \p m2 elementwise and store the result in \p m1.
+ * The dimensions of the two matrices must match.
+ * \param m1 The first matrix; the result is stored here.
+ * \param m2 The second matrix; it is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,mul_elements)(TYPE(igraph_matrix) *m1, 
+					 const TYPE(igraph_matrix) *m2) {
+  if (m1->nrow != m2->nrow || m1->ncol != m2->ncol) {
+    IGRAPH_ERROR("Cannot multiply non-conformant matrices", IGRAPH_EINVAL);
+  }
+  return FUNCTION(igraph_vector,mul)(&m1->data, &m2->data);
+}
+
+/**
+ * \function igraph_matrix_div_elements
+ * Elementwise division.
+ * 
+ * Divide \p m1 by \p m2 elementwise and store the result in \p m1.
+ * The dimensions of the two matrices must match.
+ * \param m1 The dividend. The result is store here.
+ * \param m2 The divisor. It is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,div_elements)(TYPE(igraph_matrix) *m1, 
+					 const TYPE(igraph_matrix) *m2) {
+  if (m1->nrow != m2->nrow || m1->ncol != m2->ncol) {
+    IGRAPH_ERROR("Cannot divide non-conformant matrices", IGRAPH_EINVAL);
+  }
+  return FUNCTION(igraph_vector,div)(&m1->data, &m2->data);
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_matrix_min
+ * Minimum element.
+ * 
+ * Returns the smallest element of a non-empty matrix. 
+ * \param m The input matrix.
+ * \return The smallest element.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+igraph_real_t FUNCTION(igraph_matrix,min)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,min)(&m->data);
+}
+
+/**
+ * \function igraph_matrix_which_min
+ * Indices of the minimum.
+ * 
+ * Gives the indices of the (first) smallest element in a non-empty
+ * matrix.
+ * \param m The matrix.
+ * \param i Pointer to a <type>long int</type>. The row index of the 
+ *   minimum is stored here.
+ * \param j Pointer to a <type>long int</type>. The column index of
+ *   the minimum is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,which_min)(const TYPE(igraph_matrix) *m,
+				      long int *i, long int *j) {
+  long int vmin=FUNCTION(igraph_vector,which_min)(&m->data);
+  *i = vmin % m->nrow;
+  *j = vmin / m->nrow;
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_which_max
+ * Indices of the maximum.
+ * 
+ * Gives the indices of the (first) largest element in a non-empty
+ * matrix.
+ * \param m The matrix.
+ * \param i Pointer to a <type>long int</type>. The row index of the 
+ *   maximum is stored here.
+ * \param j Pointer to a <type>long int</type>. The column index of
+ *   the maximum is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,which_max)(const TYPE(igraph_matrix) *m,
+				      long int *i, long int *j) {
+  long int vmax=FUNCTION(igraph_vector,which_max)(&m->data);
+  *i = vmax % m->nrow;
+  *j = vmax / m->nrow;
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_minmax
+ * Minimum and maximum
+ * 
+ * The maximum and minimum elements of a non-empty matrix.
+ * \param m The input matrix.
+ * \param min Pointer to a base type. The minimum is stored here.
+ * \param max Pointer to a base type. The maximum is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,minmax)(const TYPE(igraph_matrix) *m,
+				   BASE *min, BASE *max) {
+  return FUNCTION(igraph_vector,minmax)(&m->data, min, max);
+}
+
+/**
+ * \function igraph_matrix_which_minmax
+ * Indices of the minimum and maximum
+ * 
+ * Find the positions of the smallest and largest elements of a
+ * non-empty matrix.
+ * \param m The input matrix.
+ * \param imin Pointer to a <type>long int</type>, the row index of
+ *   the minimum is stored here.
+ * \param jmin Pointer to a <type>long int</type>, the column index of
+ *   the minimum is stored here.
+ * \param imax Pointer to a <type>long int</type>, the row index of
+ *   the maximum is stored here.
+ * \param jmax Pointer to a <type>long int</type>, the column index of
+ *   the maximum is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+int FUNCTION(igraph_matrix,which_minmax)(const TYPE(igraph_matrix) *m,
+					 long int *imin, long int *jmin,
+					 long int *imax, long int *jmax) {
+  long int vmin, vmax;
+  FUNCTION(igraph_vector,which_minmax)(&m->data, &vmin, &vmax);
+  *imin = vmin % m->nrow;
+  *jmin = vmin / m->nrow;
+  *imax = vmax % m->nrow;
+  *jmax = vmax / m->nrow;
+  return 0;
+}
+
+#endif
+
+/**
+ * \function igraph_matrix_isnull
+ * Check for a null matrix.
+ * 
+ * Checks whether all elements are zero.
+ * \param m The input matrix.
+ * \return Boolean, \c TRUE is \p m contains only zeros and \c FALSE
+ *   otherwise.
+ *
+ * Time complexity: O(mn), the number of elements.
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,isnull)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,isnull)(&m->data);
+}
+
+/**
+ * \function igraph_matrix_empty
+ * Check for an empty matrix.
+ * 
+ * It is possible to have a matrix with zero rows or zero columns, or
+ * even both. This functions checks for these.
+ * \param m The input matrix.
+ * \return Boolean, \c TRUE if the matrix contains zero elements, and
+ *    \c FALSE otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,empty)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,empty)(&m->data);
+}
+
+/**
+ * \function igraph_matrix_is_symmetric
+ * Check for symmetric matrix.
+ * 
+ * A non-square matrix is not symmetric by definition.
+ * \param m The input matrix.
+ * \return Boolean, \c TRUE if the matrix is square and symmetric, \c
+ *    FALSE otherwise.
+ * 
+ * Time complexity: O(mn), the number of elements. O(1) for non-square
+ * matrices. 
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,is_symmetric)(const TYPE(igraph_matrix) *m) {
+  
+  long int n=m->nrow;
+  long int r,c;
+  if (m->ncol != n) {
+    return 0;
+  }
+  for (r=1; r<n; r++) {
+    for (c=0; c<r; c++) {
+      BASE a1=MATRIX(*m, r, c);
+      BASE a2=MATRIX(*m, c, r);
+#ifdef EQ      
+      if (!EQ(a1,a2)) { return 0; }
+#else
+      if (a1 != a2) { return 0; }
+#endif
+    }
+  }
+  return 1;
+}
+
+/**
+ * \function igraph_matrix_prod
+ * Product of the elements.
+ * 
+ * Note this function can result in overflow easily, even for not too
+ * big matrices.
+ * \param m The input matrix.
+ * \return The product of the elements.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+BASE FUNCTION(igraph_matrix,prod)(const TYPE(igraph_matrix) *m) {
+  return FUNCTION(igraph_vector,prod)(&m->data);
+}
+
+/**
+ * \function igraph_matrix_rowsum
+ * Rowwise sum.
+ * 
+ * Calculate the sum of the elements in each row.
+ * \param m The input matrix.
+ * \param res Pointer to an initialized vector; the result is stored
+ *   here. It will be resized if necessary.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,rowsum)(const TYPE(igraph_matrix) *m,
+				   TYPE(igraph_vector) *res) {
+  long int nrow=m->nrow, ncol=m->ncol;
+  long int r, c;
+  BASE sum;
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(res, nrow));
+  for (r=0; r<nrow; r++) {
+    sum=ZERO;
+    for (c=0; c<ncol; c++) {
+#ifdef SUM
+      SUM(sum, sum, MATRIX(*m, r, c));
+#else
+      sum += MATRIX(*m, r, c);
+#endif
+    }
+    VECTOR(*res)[r]=sum;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_colsum
+ * Columnwise sum.
+ * 
+ * Calculate the sum of the elements in each column.
+ * \param m The input matrix.
+ * \param res Pointer to an initialized vector; the result is stored
+ *   here. It will be resized if necessary.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,colsum)(const TYPE(igraph_matrix) *m,
+				   TYPE(igraph_vector) *res) {
+  long int nrow=m->nrow, ncol=m->ncol;
+  long int r, c;
+  BASE sum;
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(res, ncol));
+  for (c=0; c<ncol; c++) {
+    sum=ZERO;
+    for (r=0; r<nrow; r++) {
+#ifdef SUM
+      SUM(sum, sum, MATRIX(*m, r, c));
+#else
+      sum += MATRIX(*m, r, c);
+#endif
+    }
+    VECTOR(*res)[c]=sum;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_contains
+ * Search for an element.
+ * 
+ * Search for the given element in the matrix.
+ * \param m The input matrix.
+ * \param e The element to search for.
+ * \return Boolean, \c TRUE if the matrix contains \p e, \c FALSE
+ * otherwise.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+igraph_bool_t FUNCTION(igraph_matrix,contains)(const TYPE(igraph_matrix) *m,
+					       BASE e) {
+  return FUNCTION(igraph_vector,contains)(&m->data, e);
+}
+
+/**
+ * \function igraph_matrix_search
+ * Search from a given position.
+ * 
+ * Search for an element in a matrix and start the search from the
+ * given position. The search is performed columnwise.
+ * \param m The input matrix.
+ * \param from The position to search from, the positions are
+ *    enumerated columnwise.
+ * \param what The element to search for.
+ * \param pos Pointer to a <type>long int</type>. If the element is
+ *    found, then this is set to the position of its first appearance.
+ * \param row Pointer to a <type>long int</type>. If the element is
+ *    found, then this is set to its row index.
+ * \param col Pointer to a <type>long int</type>. If the element is
+ *    found, then this is set to its column index.
+ * \return Boolean, \c TRUE if the element is found, \c FALSE
+ *    otherwise.
+ * 
+ * Time complexity: O(mn), the number of elements.
+ */
+
+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) {
+  igraph_bool_t find=FUNCTION(igraph_vector,search)(&m->data, from, what, pos);
+  if (find) {
+    *row = *pos % m->nrow;
+    *col = *pos / m->nrow;
+  }
+  return find;
+}
+
+/**
+ * \function igraph_matrix_remove_row
+ * Remove a row.
+ * 
+ * A row is removed from the matrix. 
+ * \param m The input matrix.
+ * \param row The index of the row to remove.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the matrix.
+ */
+
+int FUNCTION(igraph_matrix,remove_row)(TYPE(igraph_matrix) *m, long int row) {
+  
+  long int c, r, index=row+1, leap=1, n=m->nrow * m->ncol;
+  if (row >= m->nrow) {
+    IGRAPH_ERROR("Cannot remove row, index out of range", IGRAPH_EINVAL);
+  }  
+  
+  for (c=0; c<m->ncol; c++) {    
+    for (r=0; r<m->nrow-1 && index < n; r++) {
+      VECTOR(m->data)[index-leap] = VECTOR(m->data)[index];
+      index++;
+    }
+    leap++;
+    index++;
+  }
+  m->nrow--;
+  FUNCTION(igraph_vector,resize)(&m->data, m->nrow * m->ncol);
+  return 0;
+}
+
+/**
+ * \function igraph_matrix_select_cols
+ * \brief Select some columns of a matrix.
+ * 
+ * This function selects some columns of a matrix and returns them in a
+ * new matrix. The result matrix should be initialized before calling
+ * the function.
+ * \param m The input matrix.
+ * \param res The result matrix. It should be initialized and will be
+ *    resized as needed.
+ * \param cols Vector; it contains the column indices (starting with
+ *    zero) to extract. Note that no range checking is performed.
+ * \return Error code.
+ * 
+ * Time complexity: O(nm), n is the number of rows, m the number of
+ * columns of the result matrix.
+ */
+
+int FUNCTION(igraph_matrix,select_cols)(const TYPE(igraph_matrix) *m,
+					TYPE(igraph_matrix) *res, 
+					const igraph_vector_t *cols) {
+  long int ncols=igraph_vector_size(cols);
+  long int nrows=m->nrow;
+  long int i, j;
+  
+  IGRAPH_CHECK(FUNCTION(igraph_matrix,resize)(res, nrows, ncols));
+  for (i=0; i<nrows; i++) {
+    for (j=0; j<ncols; j++) {
+      MATRIX(*res, i, j) = MATRIX(*m, i, (long int)VECTOR(*cols)[j]);
+    }
+  }
+  return 0;
+}
+
+#ifdef OUT_FORMAT
+
+#ifndef USING_R
+int FUNCTION(igraph_matrix,print)(const TYPE(igraph_matrix) *m) {
+
+  long int nr=FUNCTION(igraph_matrix,nrow)(m);
+  long int nc=FUNCTION(igraph_matrix,ncol)(m);
+  long int i, j;
+  for (i=0; i<nr; i++) {
+    for (j=0; j<nc; j++) {
+      if (j!=0) { putchar(' '); }
+      printf(OUT_FORMAT, MATRIX(*m, i, j));
+    }
+    printf("\n");
+  }
+  
+  return 0;
+}
+
+int FUNCTION(igraph_matrix,printf)(const TYPE(igraph_matrix) *m,
+																	 const char *format) {
+  long int nr=FUNCTION(igraph_matrix,nrow)(m);
+  long int nc=FUNCTION(igraph_matrix,ncol)(m);
+  long int i, j;
+  for (i=0; i<nr; i++) {
+    for (j=0; j<nc; j++) {
+      if (j!=0) { putchar(' '); }
+      printf(format, MATRIX(*m, i, j));
+    }
+    printf("\n");
+  }
+
+  return 0;
+}
+
+#endif
+
+int FUNCTION(igraph_matrix,fprint)(const TYPE(igraph_matrix) *m,
+				   FILE *file) {
+
+  long int nr=FUNCTION(igraph_matrix,nrow)(m);
+  long int nc=FUNCTION(igraph_matrix,ncol)(m);
+  long int i, j;
+  for (i=0; i<nr; i++) {
+    for (j=0; j<nc; j++) {
+      if (j!=0) { fputc(' ', file); }
+      fprintf(file, OUT_FORMAT, MATRIX(*m, i, j));
+    }
+    fprintf(file, "\n");
+  }
+  
+  return 0;
+}
+
+#endif
diff --git a/src/maximal_cliques.c b/src/maximal_cliques.c
new file mode 100644
index 0000000..3a966bb
--- /dev/null
+++ b/src/maximal_cliques.c
@@ -0,0 +1,406 @@
+/* -*- 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_cliques.h"
+#include "igraph_constants.h"
+#include "igraph_interface.h"
+#include "igraph_community.h"
+#include "igraph_adjlist.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_memory.h"
+#include "igraph_progress.h"
+#include "igraph_math.h"
+
+#define CONCAT2x(a,b) a ## b 
+#define CONCAT2(a,b) CONCAT2x(a,b)
+#define FUNCTION(name,sfx) CONCAT2(name,sfx)
+
+int igraph_i_maximal_cliques_reorder_adjlists(
+			      const igraph_vector_int_t *PX,
+			      int PS, int PE, int XS, int XE,
+			      const igraph_vector_int_t *pos,
+			      igraph_adjlist_t *adjlist);
+
+int igraph_i_maximal_cliques_select_pivot(const igraph_vector_int_t *PX,
+					  int PS, int PE, int XS, int XE,
+					  const igraph_vector_int_t *pos,
+					  const igraph_adjlist_t *adjlist,
+					  int *pivot,
+					  igraph_vector_int_t *nextv,
+					  int oldPS, int oldXE);
+
+int igraph_i_maximal_cliques_down(igraph_vector_int_t *PX,
+				  int PS, int PE, int XS, int XE,
+				  igraph_vector_int_t *pos, 
+				  igraph_adjlist_t *adjlist, int mynextv, 
+				  igraph_vector_int_t *R, 
+				  int *newPS, int *newXE);
+
+int igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, int PS, int *PE, 
+				int *XS, int XE, igraph_vector_int_t *pos,
+				igraph_adjlist_t *adjlist, int v, 
+				igraph_vector_int_t *H);
+
+int igraph_i_maximal_cliques_up(igraph_vector_int_t *PX, int PS, int PE, 
+				int XS, int XE, igraph_vector_int_t *pos, 
+				igraph_adjlist_t *adjlist,
+				igraph_vector_int_t *R, 
+				igraph_vector_int_t *H);
+
+#define PRINT_PX do {						       \
+    int j;							       \
+    printf("PX=");						       \
+    for (j=0; j<PS; j++) {					       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf("( ");						       \
+    for (; j<=PE; j++) {					       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf("| ");						       \
+    for (; j<=XE; j++) {					       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf(") ");						       \
+    for (; j<igraph_vector_int_size(PX); j++) {			       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf("\n");						       \
+  } while (0);
+
+#define PRINT_PX1 do {						       \
+    int j;							       \
+    printf("PX=");						       \
+    for (j=0; j<PS; j++) {					       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf("( ");						       \
+    for (; j<=*PE; j++) {					       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf("| ");						       \
+    for (; j<=XE; j++) {					       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf(") ");						       \
+    for (; j<igraph_vector_int_size(PX); j++) {			       \
+      printf("%i ", VECTOR(*PX)[j]);				       \
+    }								       \
+    printf("\n");						       \
+  } while (0)
+
+int igraph_i_maximal_cliques_reorder_adjlists(
+			      const igraph_vector_int_t *PX,
+			      int PS, int PE, int XS, int XE,
+			      const igraph_vector_int_t *pos,
+			      igraph_adjlist_t *adjlist) {
+  int j;
+  int sPS=PS+1, sPE=PE+1;
+
+  for (j=PS; j<=XE; j++) {
+    int av=VECTOR(*PX)[j];
+    igraph_vector_int_t *avneis=igraph_adjlist_get(adjlist, av);
+    int *avp=VECTOR(*avneis);
+    int avlen=igraph_vector_int_size(avneis);
+    int *ave=avp+avlen;
+    int *avnei=avp, *pp=avp;
+
+    for (; avnei < ave; avnei++) {
+      int avneipos=VECTOR(*pos)[(int)(*avnei)];
+      if (avneipos >= sPS && avneipos <= sPE) {
+	if (pp != avnei) {
+	  int tmp=*avnei;
+	  *avnei = *pp;
+	  *pp = tmp;
+	}
+	pp++;
+      }
+    }
+  }
+  return 0;
+}
+
+int igraph_i_maximal_cliques_select_pivot(const igraph_vector_int_t *PX,
+					  int PS, int PE, int XS, int XE,
+					  const igraph_vector_int_t *pos,
+					  const igraph_adjlist_t *adjlist,
+					  int *pivot,
+					  igraph_vector_int_t *nextv,
+					  int oldPS, int oldXE) {
+  igraph_vector_int_t *pivotvectneis;
+  int i, pivotvectlen, j, usize=-1;
+  int soldPS=oldPS+1, soldXE=oldXE+1, sPS=PS+1, sPE=PE+1;
+
+  /* Choose a pivotvect, and bring up P vertices at the same time */
+  for (i=PS; i<=XE; i++) {
+    int av=VECTOR(*PX)[i];
+    igraph_vector_int_t *avneis=igraph_adjlist_get(adjlist, av);
+    int *avp=VECTOR(*avneis);
+    int avlen=igraph_vector_int_size(avneis);
+    int *ave=avp+avlen;
+    int *avnei=avp, *pp=avp;
+
+    for (; avnei < ave; avnei++) {
+      int avneipos=VECTOR(*pos)[(int)(*avnei)];
+      if (avneipos < soldPS || avneipos > soldXE) { break; }
+      if (avneipos >= sPS && avneipos <= sPE) {
+	if (pp != avnei) {
+	  int tmp=*avnei;
+	  *avnei = *pp;
+	  *pp = tmp;
+	}
+	pp++;
+      }
+    }
+    if ((j=pp-avp) > usize) { *pivot = av; usize=j; }
+  }
+
+  igraph_vector_int_push_back(nextv, -1);
+  pivotvectneis=igraph_adjlist_get(adjlist, *pivot);
+  pivotvectlen=igraph_vector_int_size(pivotvectneis);
+
+  for (j=PS; j <= PE; j++) {
+    int vcand=VECTOR(*PX)[j];
+    igraph_bool_t nei=0;
+    int k=0;
+    for (k=0; k < pivotvectlen; k++) {
+      int unv=VECTOR(*pivotvectneis)[k];
+      int unvpos=VECTOR(*pos)[unv];
+      if (unvpos < sPS || unvpos > sPE) { break; }
+      if (unv == vcand) { nei=1; break; }
+    }
+    if (!nei) { igraph_vector_int_push_back(nextv, vcand); }
+  }
+
+  return 0;
+}
+
+#define SWAP(p1,p2) do {			\
+    int v1=VECTOR(*PX)[p1];			\
+    int v2=VECTOR(*PX)[p2];			\
+    VECTOR(*PX)[p1] = v2;			\
+    VECTOR(*PX)[p2] = v1;			\
+    VECTOR(*pos)[v1] = (p2)+1;			\
+    VECTOR(*pos)[v2] = (p1)+1;			\
+  } while (0)
+
+int igraph_i_maximal_cliques_down(igraph_vector_int_t *PX,
+				  int PS, int PE, int XS, int XE,
+				  igraph_vector_int_t *pos, 
+				  igraph_adjlist_t *adjlist, int mynextv, 
+				  igraph_vector_int_t *R, 
+				  int *newPS, int *newXE) {
+
+  igraph_vector_int_t *vneis=igraph_adjlist_get(adjlist, mynextv);
+  int j, vneislen=igraph_vector_int_size(vneis);
+  int sPS=PS+1, sPE=PE+1, sXS=XS+1, sXE=XE+1;
+
+  *newPS=PE+1; *newXE=XS-1;
+  for (j=0; j<vneislen; j++) {
+    int vnei=VECTOR(*vneis)[j];
+    int vneipos=VECTOR(*pos)[vnei];
+    if (vneipos >= sPS && vneipos <= sPE) {
+      (*newPS)--;
+      SWAP(vneipos-1, *newPS);
+    } else if (vneipos >= sXS && vneipos <= sXE) {
+      (*newXE)++;
+      SWAP(vneipos-1, *newXE);
+    }
+  }
+
+  igraph_vector_int_push_back(R, mynextv);
+  
+  return 0;
+}
+
+#undef SWAP
+
+int igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, int PS, int *PE, 
+				int *XS, int XE, igraph_vector_int_t *pos,
+				igraph_adjlist_t *adjlist, int v, 
+				igraph_vector_int_t *H) {
+
+  int vpos=VECTOR(*pos)[v]-1;
+  int tmp=VECTOR(*PX)[*PE];
+  VECTOR(*PX)[vpos]=tmp;
+  VECTOR(*PX)[*PE]=v;
+  VECTOR(*pos)[v]=(*PE)+1;
+  VECTOR(*pos)[tmp]=vpos+1;
+  (*PE)--; (*XS)--;
+  igraph_vector_int_push_back(H, v);
+
+  return 0;
+}
+
+int igraph_i_maximal_cliques_up(igraph_vector_int_t *PX, int PS, int PE, 
+				int XS, int XE, igraph_vector_int_t *pos, 
+				igraph_adjlist_t *adjlist,
+				igraph_vector_int_t *R, 
+				igraph_vector_int_t *H) {
+  int vv;
+  igraph_vector_int_pop_back(R);
+
+  while ((vv=igraph_vector_int_pop_back(H)) != -1) {
+    int vvpos=VECTOR(*pos)[vv];
+    int tmp=VECTOR(*PX)[XS];
+    VECTOR(*PX)[XS]=vv;
+    VECTOR(*PX)[vvpos-1]=tmp;
+    VECTOR(*pos)[vv]=XS+1;
+    VECTOR(*pos)[tmp]=vvpos;
+    PE++; XS++;
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_maximal_cliques
+ * \brief Find all maximal cliques of a graph
+ *
+ * </para><para>
+ * A maximal clique is a clique which can't be extended any more by
+ * adding a new vertex to it.
+ *
+ * </para><para>
+ * If you are only interested in the size of the largest clique in the
+ * graph, use \ref igraph_clique_number() instead.
+ *
+ * </para><para>
+ * The current implementation uses a modified Bron-Kerbosch
+ * algorithm to find the maximal cliques, see: David Eppstein,
+ * Maarten Löffler, Darren Strash: Listing All Maximal Cliques in
+ * Sparse Graphs in Near-Optimal Time. Algorithms and Computation,
+ * Lecture Notes in Computer Science Volume 6506, 2010, pp 403-414.
+ *
+ * </para><para>The implementation of this function changed between
+ * igraph 0.5 and 0.6 and also between 0.6 and 0.7, so the order of
+ * the cliques and the order of vertices within the cliques will
+ * almost surely be different between these three versions.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   objects which contain the indices of vertices involved in a clique.
+ *   The pointer vector will be resized if needed but note that the
+ *   objects in the pointer vector will not be freed. Note that vertices
+ *   of a clique may be returned in arbitrary order.
+ * \param min_size Integer giving the minimum size of the cliques to be
+ *   returned. If negative or zero, no lower bound will be used.
+ * \param max_size Integer giving the maximum size of the cliques to be
+ *   returned. If negative or zero, no upper bound will be used.
+ * \return Error code.
+ *
+ * \sa \ref igraph_maximal_independent_vertex_sets(), \ref
+ * igraph_clique_number() 
+ * 
+ * Time complexity: O(d(n-d)3^(d/3)) worst case, d is the degeneracy
+ * of the graph, this is typically small for sparse graphs.
+ * 
+ * \example examples/simple/igraph_maximal_cliques.c
+ */
+
+int igraph_maximal_cliques(const igraph_t *graph, 
+			   igraph_vector_ptr_t *res,
+			   igraph_integer_t min_size, 
+			   igraph_integer_t max_size);
+
+#define IGRAPH_MC_ORIG
+#include "maximal_cliques_template.h"
+#undef IGRAPH_MC_ORIG
+
+/**
+ * \function igraph_maximal_cliques_count
+ * Count the number of maximal cliques in a graph
+ * 
+ * </para><para>
+ * The current implementation uses a modified Bron-Kerbosch
+ * algorithm to find the maximal cliques, see: David Eppstein,
+ * Maarten Löffler, Darren Strash: Listing All Maximal Cliques in
+ * Sparse Graphs in Near-Optimal Time. Algorithms and Computation,
+ * Lecture Notes in Computer Science Volume 6506, 2010, pp 403-414.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   objects which contain the indices of vertices involved in a clique.
+ *   The pointer vector will be resized if needed but note that the
+ *   objects in the pointer vector will not be freed. Note that vertices
+ *   of a clique may be returned in arbitrary order.
+ * \param min_size Integer giving the minimum size of the cliques to be
+ *   returned. If negative or zero, no lower bound will be used.
+ * \param max_size Integer giving the maximum size of the cliques to be
+ *   returned. If negative or zero, no upper bound will be used.
+ * \return Error code.
+ *
+ * \sa \ref igraph_maximal_cliques().
+ * 
+ * Time complexity: O(d(n-d)3^(d/3)) worst case, d is the degeneracy
+ * of the graph, this is typically small for sparse graphs.
+ * 
+ * \example examples/simple/igraph_maximal_cliques.c
+ */
+
+int igraph_maximal_cliques_count(const igraph_t *graph,
+				 igraph_integer_t *res,
+				 igraph_integer_t min_size,
+				 igraph_integer_t max_size);
+
+#define IGRAPH_MC_COUNT
+#include "maximal_cliques_template.h"
+#undef IGRAPH_MC_COUNT
+
+/**
+ * \function igraph_maximal_cliques_file
+ * Find maximal cliques and write them to a file
+ * 
+ * TODO
+ */ 
+
+int igraph_maximal_cliques_file(const igraph_t *graph,
+				FILE *outfile,
+				igraph_integer_t min_size, 
+				igraph_integer_t max_size);
+
+#define IGRAPH_MC_FILE
+#include "maximal_cliques_template.h"
+#undef IGRAPH_MC_FILE
+
+/**
+ * \function igraph_maximal_cliques_subset
+ * Maximal cliques for a subset of initial vertices
+ *
+ * TODO
+ */
+
+int igraph_maximal_cliques_subset(const igraph_t *graph,
+				  igraph_vector_int_t *subset,
+				  igraph_vector_ptr_t *res,
+				  igraph_integer_t *no,
+				  FILE *outfile,
+				  igraph_integer_t min_size,
+				  igraph_integer_t max_size);
+
+#define IGRAPH_MC_FULL
+#include "maximal_cliques_template.h"
+#undef IGRAPH_MC_FULL
+
diff --git a/src/maximal_cliques_template.h b/src/maximal_cliques_template.h
new file mode 100644
index 0000000..6978465
--- /dev/null
+++ b/src/maximal_cliques_template.h
@@ -0,0 +1,346 @@
+/* -*- 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
+
+*/
+
+#ifdef IGRAPH_MC_ORIG
+#define RESTYPE igraph_vector_ptr_t *res
+#define RESNAME res
+#define SUFFIX
+#define RECORD do {							\
+    igraph_vector_t *cl=igraph_Calloc(1, igraph_vector_t);		\
+    int j;								\
+    if (!cl) {								\
+      IGRAPH_ERROR("Cannot list maximal cliques", IGRAPH_ENOMEM);	\
+    }									\
+    igraph_vector_ptr_push_back(res, cl);				\
+    igraph_vector_init(cl, clsize);					\
+    for (j=0; j<clsize; j++) { VECTOR(*cl)[j] = VECTOR(*R)[j]; }	\
+  } while (0)
+#define FINALLY do {					\
+    igraph_vector_ptr_clear(res);			\
+    IGRAPH_FINALLY(igraph_i_maximal_cliques_free, res);	\
+  } while (0)
+#define FOR_LOOP_OVER_VERTICES for (i=0; i<no_of_nodes; i++) {
+#define FOR_LOOP_OVER_VERTICES_PREPARE
+#endif
+
+#ifdef IGRAPH_MC_COUNT
+#define RESTYPE igraph_integer_t *res
+#define RESNAME res
+#define SUFFIX _count
+#define RECORD (*res)++
+#define FINALLY *res=0;
+#define FOR_LOOP_OVER_VERTICES for (i=0; i<no_of_nodes; i++) {
+#define FOR_LOOP_OVER_VERTICES_PREPARE
+#endif
+
+#ifdef IGRAPH_MC_FILE
+#define RESTYPE FILE *res
+#define RESNAME res
+#define SUFFIX _file
+#define RECORD igraph_vector_int_fprint(R, res)
+#define FINALLY
+#define FOR_LOOP_OVER_VERTICES for (i=0; i<no_of_nodes; i++) {
+#define FOR_LOOP_OVER_VERTICES_PREPARE
+#endif
+
+#ifdef IGRAPH_MC_FULL
+#define RESTYPE					\
+    igraph_vector_int_t *subset,	        \
+    igraph_vector_ptr_t *res,			\
+    igraph_integer_t *no,			\
+    FILE *outfile
+#define RESNAME subset, res, no, outfile
+#define SUFFIX _subset
+#define RECORD do {							\
+  if (res) {								\
+    igraph_vector_t *cl=igraph_Calloc(1, igraph_vector_t);		\
+    int j;								\
+    if (!cl) {								\
+      IGRAPH_ERROR("Cannot list maximal cliques", IGRAPH_ENOMEM);	\
+    }									\
+    igraph_vector_ptr_push_back(res, cl);				\
+    igraph_vector_init(cl, clsize);					\
+    for (j=0; j<clsize; j++) { VECTOR(*cl)[j] = VECTOR(*R)[j]; }	\
+  }									\
+  if (no) { (*no)++; }						        \
+  if (outfile) { igraph_vector_int_fprint(R, outfile); }		\
+} while (0)
+#define FINALLY do {						\
+  if (res) {							\
+    igraph_vector_ptr_clear(res);				\
+    IGRAPH_FINALLY(igraph_i_maximal_cliques_free_full, res);	\
+  }								\
+  if (no) { *no=0; }						\
+  } while (0)
+#define FOR_LOOP_OVER_VERTICES					\
+  nn= subset ? igraph_vector_int_size(subset) : no_of_nodes;	\
+    for (ii=0; ii<nn; ii++) {
+#define FOR_LOOP_OVER_VERTICES_PREPARE do {  \
+    i= subset ? VECTOR(*subset)[ii] : ii;    \
+} while (0)
+#endif
+
+#ifdef IGRAPH_MC_ORIG
+void igraph_i_maximal_cliques_free(void *ptr) {
+  igraph_vector_ptr_t *res=(igraph_vector_ptr_t*) ptr;
+  int i, n=igraph_vector_ptr_size(res);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*res)[i];
+    if (v) {
+      igraph_Free(v);
+      igraph_vector_destroy(v);
+    }
+  }
+  igraph_vector_ptr_clear(res);
+}
+#endif
+
+#ifdef IGRAPH_MC_FULL
+void igraph_i_maximal_cliques_free_full(void *ptr) {
+  if (ptr) {
+    igraph_vector_ptr_t *res=(igraph_vector_ptr_t*) ptr;
+    int i, n=igraph_vector_ptr_size(res);
+    for (i=0; i<n; i++) {
+      igraph_vector_t *v=VECTOR(*res)[i];
+      if (v) {
+	igraph_Free(v);
+	igraph_vector_destroy(v);
+      }
+    }
+    igraph_vector_ptr_clear(res);
+  }
+}
+#endif
+
+int FUNCTION(igraph_i_maximal_cliques_bk,SUFFIX)(
+				igraph_vector_int_t *PX, int PS, int PE, 
+				int XS, int XE, int oldPS, int oldXE,
+				igraph_vector_int_t *R,
+				igraph_vector_int_t *pos,
+				igraph_adjlist_t *adjlist,
+				RESTYPE,
+				igraph_vector_int_t *nextv,
+				igraph_vector_int_t *H,
+				int min_size, int max_size) {
+
+  igraph_vector_int_push_back(H, -1); /* boundary */
+  
+  if (PS > PE && XS > XE) {
+    /* Found a maximum clique, report it */
+    int clsize=igraph_vector_int_size(R);
+    if (min_size <= clsize && (clsize <= max_size || max_size <= 0)) {
+      RECORD;
+    }
+  } else if (PS <= PE) {
+    /* Select a pivot element */
+    int pivot, mynextv;
+    igraph_i_maximal_cliques_select_pivot(PX, PS, PE, XS, XE, pos,
+					  adjlist, &pivot, nextv,
+					  oldPS, oldXE);
+    while ((mynextv=igraph_vector_int_pop_back(nextv)) != -1) {
+      int newPS, newXE;
+
+      /* Going down, prepare */
+      igraph_i_maximal_cliques_down(PX, PS, PE, XS, XE, pos, adjlist,
+				    mynextv, R, &newPS, &newXE);
+      /* Recursive call */
+      FUNCTION(igraph_i_maximal_cliques_bk,SUFFIX)(
+				  PX, newPS, PE, XS, newXE, PS, XE, R,
+				  pos, adjlist, RESNAME, nextv, H,
+				  min_size, max_size);
+      /* Putting v from P to X */
+      if (igraph_vector_int_tail(nextv) != -1) {
+	igraph_i_maximal_cliques_PX(PX, PS, &PE, &XS, XE, pos, adjlist,
+				    mynextv, H);
+      }
+    }
+  }
+  
+  /* Putting back vertices from X to P, see notes in H */
+  igraph_i_maximal_cliques_up(PX, PS, PE, XS, XE, pos, adjlist, R, H);
+
+  return 0;
+}
+
+int FUNCTION(igraph_maximal_cliques,SUFFIX)(
+			   const igraph_t *graph,
+			   RESTYPE,
+			   igraph_integer_t min_size, 
+			   igraph_integer_t max_size) {
+
+  /* Implementation details. TODO */
+
+  igraph_vector_int_t PX, R, H, pos, nextv;
+  igraph_vector_t coreness, order;
+  igraph_vector_int_t rank;	/* TODO: this is not needed */
+  int i, ii, nn, no_of_nodes=igraph_vcount(graph);
+  igraph_adjlist_t adjlist, fulladjlist;
+  igraph_real_t pgreset=round(no_of_nodes / 100.0), pg=pgreset, pgc=0;
+  IGRAPH_UNUSED(nn);
+
+  if (igraph_is_directed(graph)) {
+    IGRAPH_WARNING("Edge directions are ignored for maximal clique "
+		   "calculation");
+  }
+
+  igraph_vector_init(&order, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_destroy, &order);
+  igraph_vector_int_init(&rank, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &rank);
+  igraph_vector_init(&coreness, no_of_nodes);
+  igraph_coreness(graph, &coreness, /*mode=*/ IGRAPH_ALL);
+  IGRAPH_FINALLY(igraph_vector_destroy, &coreness);
+  igraph_vector_qsort_ind(&coreness, &order, /*descending=*/ 0);
+  for (ii=0; ii<no_of_nodes; ii++) {
+    int v=VECTOR(order)[ii];
+    VECTOR(rank)[v] = ii;
+  }
+
+  igraph_vector_destroy(&coreness);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL);
+
+  igraph_adjlist_simplify(&adjlist);
+  igraph_adjlist_init(graph, &fulladjlist, IGRAPH_ALL);
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &fulladjlist);
+  igraph_adjlist_simplify(&fulladjlist);
+  igraph_vector_int_init(&PX, 20);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &PX);
+  igraph_vector_int_init(&R,  20);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &R);
+  igraph_vector_int_init(&H, 100);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &H);
+  igraph_vector_int_init(&pos, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &pos);
+  igraph_vector_int_init(&nextv, 100);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &nextv);
+
+  FINALLY;
+
+  FOR_LOOP_OVER_VERTICES
+    int v;
+    int vrank;
+    igraph_vector_int_t *vneis;
+    int vdeg;
+    int Pptr, Xptr, PS, PE, XS, XE;
+    int j;
+
+    FOR_LOOP_OVER_VERTICES_PREPARE;
+
+    v=VECTOR(order)[i];
+    vrank=VECTOR(rank)[v];
+    vneis=igraph_adjlist_get(&fulladjlist, v);
+    vdeg=igraph_vector_int_size(vneis);
+    Pptr=0; Xptr=vdeg-1; PS=0; XE=vdeg-1;
+
+    pg--;
+    if (pg <= 0) {
+      IGRAPH_PROGRESS("Maximal cliques: ", pgc++, NULL);
+      pg=pgreset;
+    }
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    igraph_vector_int_resize(&PX, vdeg);
+    igraph_vector_int_resize(&R , 1);
+    igraph_vector_int_resize(&H , 1);
+    igraph_vector_int_null(&pos); /* TODO: makes it quadratic? */
+    igraph_vector_int_resize(&nextv, 1);
+
+    VECTOR(H)[0] = -1;		/* marks the end of the recursion */
+    VECTOR(nextv)[0] = -1;
+
+    /* ================================================================*/
+    /* P <- G(v[i]) intersect { v[i+1], ..., v[n-1] }
+       X <- G(v[i]) intersect { v[0], ..., v[i-1] } */
+    
+    VECTOR(R)[0] = v;
+    for (j=0; j<vdeg; j++) {
+      int vx=VECTOR(*vneis)[j];
+      if (VECTOR(rank)[vx] > vrank) {
+	VECTOR(PX)[Pptr] = vx;
+	VECTOR(pos)[vx] = Pptr+1;
+	Pptr++;
+      } else if (VECTOR(rank)[vx] < vrank) {
+	VECTOR(PX)[Xptr] = vx;
+	VECTOR(pos)[vx] = Xptr+1;
+	Xptr--;
+      }
+    }
+
+    PE = Pptr-1; XS = Xptr+1;	/* end of P, start of X in PX */
+
+    /* Create an adjacency list that is specific to the 
+       v vertex. It only contains 'v' and its neighbors. Moreover, we 
+       only deal with the vertices in P and X (and R). */
+    igraph_vector_int_update(igraph_adjlist_get(&adjlist, v), 
+			     igraph_adjlist_get(&fulladjlist, v));
+    for (j=0; j<=vdeg-1; j++) {
+      int vv=VECTOR(PX)[j];
+      igraph_vector_int_t *fadj=igraph_adjlist_get(&fulladjlist, vv);
+      igraph_vector_int_t *radj=igraph_adjlist_get(&adjlist, vv);
+      int k, fn=igraph_vector_int_size(fadj);
+      igraph_vector_int_clear(radj);
+      for (k=0; k<fn; k++) {
+	int nei=VECTOR(*fadj)[k];
+	int neipos=VECTOR(pos)[nei]-1;
+	if (neipos >= PS && neipos <= XE) {
+	  igraph_vector_int_push_back(radj, nei);
+	}
+      }
+    }
+
+    /* Reorder the adjacency lists, according to P and X. */
+    igraph_i_maximal_cliques_reorder_adjlists(&PX, PS, PE, XS, XE, &pos,
+					      &adjlist);
+
+    FUNCTION(igraph_i_maximal_cliques_bk,SUFFIX)(
+				&PX, PS, PE, XS, XE, PS, XE, &R, &pos,
+				&adjlist, RESNAME, &nextv, &H, min_size,
+				max_size);
+  }
+
+  IGRAPH_PROGRESS("Maximal cliques: ", 100.0, NULL);
+
+  igraph_vector_int_destroy(&nextv);
+  igraph_vector_int_destroy(&pos);
+  igraph_vector_int_destroy(&H);
+  igraph_vector_int_destroy(&R);
+  igraph_vector_int_destroy(&PX);
+  igraph_adjlist_destroy(&fulladjlist);
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_int_destroy(&rank);
+  igraph_vector_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(10);	/* + res */
+
+  return 0;
+}
+
+#undef RESTYPE
+#undef RESNAME
+#undef SUFFIX
+#undef RECORD
+#undef FINALLY
+#undef FOR_LOOP_OVER_VERTICES
+#undef FOR_LOOP_OVER_VERTICES_PREPARE
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..bb0424f
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,75 @@
+/* -*- 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
+
+*/
+
+#include "igraph_memory.h"
+#include "config.h"
+
+/**
+ * \function igraph_free
+ * Deallocate memory that was allocated by igraph functions
+ * 
+ * Some igraph functions return a pointer vector (igraph_vector_ptr_t)
+ * containing pointers to other igraph or other data types. These data
+ * types are dynamically allocated and have to be deallocated
+ * manually, if the user does not need them any more. This can be done
+ * by calling igraph_free on them.
+ * 
+ * </para><para>
+ * Here is a complete example on how to use \c igraph_free properly.
+ * <programlisting>
+ * <![CDATA[#include <igraph.h>
+ * 
+ * int main(void)
+ * {
+ *    igraph_t graph;
+ *    igraph_vector_ptr_t seps;
+ *    long int i;
+ * 
+ *    igraph_famous(&graph, "tutte");
+ *    igraph_vector_ptr_init(&seps, 0);
+ *    igraph_minimum_size_separators(&graph, &seps);
+ *    
+ *    for (i=0; i<igraph_vector_ptr_size(&seps); i++) {
+ *      igraph_vector_t *v=VECTOR(seps)[i];
+ *      igraph_vector_print(v);
+ *      igraph_vector_destroy(v);
+ *      igraph_free(v);
+ *    }
+ *
+ *    igraph_vector_ptr_destroy(&seps);
+ *    igraph_destroy(&graph);
+ *    return 0;
+ * }]]>
+ * </programlisting>
+ * 
+ * 
+ * \param p Pointer to the piece of memory to be deallocated.
+ * \return Error code, currently always zero, meaning success.
+ * 
+ * Time complexity: platform dependent, ideally it should be O(1).
+ */
+
+int igraph_free(void *p) {
+  igraph_Free(p);
+  return 0;
+}
diff --git a/src/microscopic_update.c b/src/microscopic_update.c
new file mode 100644
index 0000000..b589ecb
--- /dev/null
+++ b/src/microscopic_update.c
@@ -0,0 +1,1191 @@
+/* -*- mode: C -*-  */
+/*
+  Microscopic update rules for dealing with agent-level strategy revision.
+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
+#include "igraph_iterators.h"
+#include "igraph_interface.h"
+#include "igraph_microscopic_update.h"
+#include "igraph_nongraph.h"
+#include "igraph_random.h"
+
+#include <assert.h>
+
+/*
+ * Internal use only.
+ * Compute the cumulative proportionate values of a vector. The vector is
+ * assumed to hold values associated with edges.
+ *
+ * \param graph The graph object representing the game network. No error
+ *        checks will be performed on this graph. You are responsible for
+ *        ensuring that this is a valid graph for the particular
+ *        microscopic update rule at hand.
+ * \param U A vector of edge values for which we want to compute cumulative
+ *        proportionate values. So U[i] is the value of the edge with ID i.
+ *        With a local perspective, we would only compute cumulative
+ *        proportionate values for some combination of U. This vector could
+ *        be, for example, a vector of weights for edges in \p graph. It is
+ *        assumed that each value of U is nonnegative; it is your
+ *        responsibility to ensure this. Furthermore, this vector must have a
+ *        length the same as the number of edges in \p graph; you are
+ *        responsible for ensuring this condition holds.
+ * \param V Pointer to an uninitialized vector. The cumulative proportionate
+ *        values will be computed and stored here. No error checks will be
+ *        performed on this parameter.
+ * \param islocal Boolean; this flag controls which perspective to use. If
+ *        true then we use the local perspective; otherwise we use the global
+ *        perspective. In the context of this function, the local perspective
+ *        for a vertex v consists of all edges incident on v. In contrast, the
+ *        global perspective for v consists of all edges in \p graph.
+ * \param vid The vertex to use if we are considering a local perspective,
+ *        i.e. if \p islocal is true. This vertex will be ignored if
+ *        \p islocal is false. That is, if \p islocal is false then it is safe
+ *        pass the value -1 here. On the other hand, if \p islocal is true then
+ *        it is assumed that this is indeed a vertex of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for \p vid. This
+ *        is only relevant if we are considering the local perspective, i.e. if
+ *        \p islocal is true. If we are considering the global perspective,
+ *        then this parameter would be ignored. In other words, if \p islocal
+ *        is false then it is safe to pass the value \p IGRAPH_ALL here. If
+ *        \p graph is undirected, then we use all the immediate neighbours of
+ *        \p vid. Thus if you know that \p graph is undirected, then it is
+ *        safe to pass the value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of \p vid. This option is only relevant
+ *          when \p graph is a digraph and we are considering the local
+ *          perspective.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of \p vid. Again this option is only relevant
+ *          when \p graph is a directed graph and we are considering the local
+ *          perspective.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of \p vid. This option is only
+ *          relevant if \p graph is a digraph and we are considering a local
+ *          perspective. Also use this value if \p graph is undirected or we
+ *          are considering the global perspective.
+ *        \endclist
+ * \return Codes:
+ *         \clist
+ *         \cli IGRAPH_EINVAL
+ *           This error code is returned in the following case: The vector
+ *           \p U, or some combination of its values, sums to zero.
+ *         \cli IGRAPH_SUCCESS
+ *           This signal is returned if the cumulative proportionate values
+ *           were successfully computed.
+ *         \endclist
+ *
+ * Time complexity: O(2n) where n is the number of edges in the perspective
+ * of \p vid.
+ */
+
+int igraph_ecumulative_proportionate_values(const igraph_t *graph,
+                                            const igraph_vector_t *U,
+                                            igraph_vector_t *V,
+                                            igraph_bool_t islocal,
+                                            igraph_integer_t vid,
+                                            igraph_neimode_t mode) {
+  igraph_eit_t A;   /* all edges in v's perspective */
+  igraph_es_t es;
+  igraph_integer_t e;
+  igraph_real_t C;  /* cumulative probability */
+  igraph_real_t P;  /* probability */
+  igraph_real_t S;  /* sum of values */
+  long int i;
+
+  /* Set the perspective. Let v be the vertex under consideration. The local */
+  /* perspective for v consists of edges incident on it. In contrast, the */
+  /* global perspective for v are all edges in the given graph. Hence in the */
+  /* global perspective, we will ignore the given vertex and the given */
+  /* neighbourhood type, but instead consider all edges in the given graph. */
+  if (islocal)
+    IGRAPH_CHECK(igraph_es_incident(&es, vid, mode));
+  else
+    IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
+  IGRAPH_FINALLY(igraph_es_destroy, &es);
+
+  /* Sum up all the values of vector U in the perspective for v. This sum */
+  /* will be used in normalizing each value. */
+  /* NOTE: Here we assume that each value to be summed is nonnegative, */
+  /* and at least one of the values is nonzero. The behaviour resulting */
+  /* from all values being zero would be division by zero later on when */
+  /* we normalize each value. We check to see that the values sum to zero. */
+  /* NOTE: In this function, the order in which we iterate through the */
+  /* edges of interest should be the same as the order in which we do so */
+  /* in the caller function. If the caller function doesn't care about the */
+  /* order of values in the resulting vector V, then there's no need to take */
+  /* special notice of that order. But in some cases the order of values in */
+  /* V is taken into account, for example, in the Moran process. */
+  S = 0.0;
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &A));
+  IGRAPH_FINALLY(igraph_eit_destroy, &A);
+  while (!IGRAPH_EIT_END(A)) {
+    e = (igraph_integer_t)IGRAPH_EIT_GET(A);
+    S += (igraph_real_t)VECTOR(*U)[e];
+    IGRAPH_EIT_NEXT(A);
+  }
+  /* avoid division by zero later on */
+  if (S == (igraph_real_t)0.0) {
+    igraph_eit_destroy(&A);
+    igraph_es_destroy(&es);
+    IGRAPH_FINALLY_CLEAN(2);
+    IGRAPH_ERROR("Vector of values sums to zero", IGRAPH_EINVAL);
+  }
+
+  /* Get cumulative probability and relative value for each edge in the */
+  /* perspective of v. The vector V holds the cumulative proportionate */
+  /* values of all edges in v's perspective. The value V[0] is the */
+  /* cumulative proportionate value of the first edge in the edge iterator */
+  /* A. The value V[1] is the cumulative proportionate value of the second */
+  /* edge in the iterator A. And so on. */
+  C = 0.0;
+  i = 0;
+  IGRAPH_EIT_RESET(A);
+  IGRAPH_VECTOR_INIT_FINALLY(V, IGRAPH_EIT_SIZE(A));
+  while (!IGRAPH_EIT_END(A)) {
+    e = (igraph_integer_t)IGRAPH_EIT_GET(A);
+    /* NOTE: Beware of division by zero here. This can happen if the vector */
+    /* of values, or the combination of interest, sums to zero. */
+    P = (igraph_real_t)VECTOR(*U)[e] / S;
+    C += P;
+    VECTOR(*V)[i] = C;
+    i++;
+    IGRAPH_EIT_NEXT(A);
+  }
+
+  igraph_eit_destroy(&A);
+  igraph_es_destroy(&es);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return IGRAPH_SUCCESS;
+}
+
+/*
+ * Internal use only.
+ * Compute the cumulative proportionate values of a vector. The vector is
+ * assumed to hold values associated with vertices.
+ *
+ * \param graph The graph object representing the game network. No error
+ *        checks will be performed on this graph. You are responsible for
+ *        ensuring that this is a valid graph for the particular
+ *        microscopic update rule at hand.
+ * \param U A vector of vertex values for which we want to compute cumulative
+ *        proportionate values. The vector could be, for example, a vector of
+ *        fitness for vertices of \p graph. It is assumed that each value of U
+ *        is nonnegative; it is your responsibility to ensure this. Also U, or
+ *        a combination of interest, is assumed to sum to a positive value;
+ *        this condition will be checked.
+ * \param V Pointer to an uninitialized vector. The cumulative proportionate
+ *        values will be computed and stored here. No error checks will be
+ *        performed on this parameter.
+ * \param islocal Boolean; this flag controls which perspective to use. If
+ *        true then we use the local perspective; otherwise we use the global
+ *        perspective. The local perspective for a vertex v is the set of all
+ *        immediate neighbours of v. In contrast, the global perspective
+ *        for v is the vertex set of \p graph.
+ * \param vid The vertex to use if we are considering a local perspective,
+ *        i.e. if \p islocal is true. This vertex will be ignored if
+ *        \p islocal is false. That is, if \p islocal is false then it is safe
+ *        pass the value -1 here. On the other hand, if \p islocal is true then
+ *        it is assumed that this is indeed a vertex of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for \p vid. This
+ *        is only relevant if we are considering the local perspective, i.e. if
+ *        \p islocal is true. If we are considering the global perspective,
+ *        then this parameter would be ignored. In other words, if \p islocal
+ *        is false then it is safe to pass the value \p IGRAPH_ALL here. If
+ *        \p graph is undirected, then we use all the immediate neighbours of
+ *        \p vid. Thus if you know that \p graph is undirected, then it is
+ *        safe to pass the value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of \p vid. This option is only relevant
+ *          when \p graph is a digraph and we are considering the local
+ *          perspective.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of \p vid. Again this option is only relevant
+ *          when \p graph is a directed graph and we are considering the local
+ *          perspective.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of \p vid. This option is only
+ *          relevant if \p graph is a digraph and we are considering a local
+ *          perspective. Also use this value if \p graph is undirected or we
+ *          are considering the global perspective.
+ *        \endclist
+ * \return Codes:
+ *         \clist
+ *         \cli IGRAPH_EINVAL
+ *           This error code is returned in the following case: The vector
+ *           \p U, or some combination of its values, sums to zero.
+ *         \cli IGRAPH_SUCCESS
+ *           This signal is returned if the cumulative proportionate values
+ *           were successfully computed.
+ *         \endclist
+ *
+ * Time complexity: O(2n) where n is the number of vertices in the
+ * perspective of vid.
+ */
+
+int igraph_vcumulative_proportionate_values(const igraph_t *graph,
+                                                  const igraph_vector_t *U,
+                                                  igraph_vector_t *V,
+                                                  igraph_bool_t islocal,
+                                                  igraph_integer_t vid,
+                                                  igraph_neimode_t mode) {
+  igraph_integer_t v;
+  igraph_real_t C;  /* cumulative probability */
+  igraph_real_t P;  /* probability */
+  igraph_real_t S;  /* sum of values */
+  igraph_vit_t A;   /* all vertices in v's perspective */
+  igraph_vs_t vs;
+  long int i;
+
+  /* Set the perspective. Let v be the vertex under consideration; it might */
+  /* be that we want to update v's strategy. The local perspective for v */
+  /* consists of its immediate neighbours. In contrast, the global */
+  /* perspective for v are all the vertices in the given graph. Hence in the */
+  /* global perspective, we will ignore the given vertex and the given */
+  /* neighbourhood type, but instead consider all vertices in the given */
+  /* graph. */
+  if (islocal)
+    IGRAPH_CHECK(igraph_vs_adj(&vs, vid, mode));
+  else
+    IGRAPH_CHECK(igraph_vs_all(&vs));
+  IGRAPH_FINALLY(igraph_vs_destroy, &vs);
+
+  /* Sum up all the values of vector U in the perspective for v. This */
+  /* sum will be used in normalizing each value. If we are using a local */
+  /* perspective, then we also need to consider the quantity of v in */
+  /* computing the sum. */
+  /* NOTE: Here we assume that each value to be summed is nonnegative, */
+  /* and at least one of the values is nonzero. The behaviour resulting */
+  /* from all values being zero would be division by zero later on when */
+  /* we normalize each value. We check to see that the values sum to zero. */
+  /* NOTE: In this function, the order in which we iterate through the */
+  /* vertices of interest should be the same as the order in which we do so */
+  /* in the caller function. If the caller function doesn't care about the */
+  /* order of values in the resulting vector V, then there's no need to take */
+  /* special notice of that order. But in some cases the order of values in */
+  /* V is taken into account, for example, in roulette wheel selection. */
+  S = 0.0;
+  IGRAPH_CHECK(igraph_vit_create(graph, vs, &A));
+  IGRAPH_FINALLY(igraph_vit_destroy, &A);
+  while (!IGRAPH_VIT_END(A)) {
+    v = (igraph_integer_t)IGRAPH_VIT_GET(A);
+    S += (igraph_real_t)VECTOR(*U)[v];
+    IGRAPH_VIT_NEXT(A);
+  }
+  if (islocal)
+    S += (igraph_real_t)VECTOR(*U)[vid];
+  /* avoid division by zero later on */
+  if (S == (igraph_real_t)0.0) {
+    igraph_vit_destroy(&A);
+    igraph_vs_destroy(&vs);
+    IGRAPH_FINALLY_CLEAN(2);
+    IGRAPH_ERROR("Vector of values sums to zero", IGRAPH_EINVAL);
+  }
+
+  /* Get cumulative probability and relative value for each vertex in the */
+  /* perspective of v. The vector V holds the cumulative proportionate */
+  /* values of all vertices in v's perspective. The value V[0] is the */
+  /* cumulative proportionate value of the first vertex in the vertex */
+  /* iterator A. The value V[1] is the cumulative proportionate value of */
+  /* the second vertex in the iterator A. And so on. If we are using the */
+  /* local perspective, then we also need to consider the cumulative */
+  /* proportionate value of v. In the case of the local perspective, we */
+  /* don't need to compute and store v's cumulative proportionate value, */
+  /* but we pretend that such value is appended to the vector V. */
+  C = 0.0;
+  i = 0;
+  IGRAPH_VIT_RESET(A);
+  IGRAPH_VECTOR_INIT_FINALLY(V, IGRAPH_VIT_SIZE(A));
+  while (!IGRAPH_VIT_END(A)) {
+    v = (igraph_integer_t)IGRAPH_VIT_GET(A);
+    /* NOTE: Beware of division by zero here. This can happen if the vector */
+    /* of values, or a combination of interest, sums to zero. */
+    P = (igraph_real_t)VECTOR(*U)[v] / S;
+    C += P;
+    VECTOR(*V)[i] = C;
+    i++;
+    IGRAPH_VIT_NEXT(A);
+  }
+
+  igraph_vit_destroy(&A);
+  igraph_vs_destroy(&vs);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return IGRAPH_SUCCESS;
+}
+
+/*
+ * Internal use only.
+ * A set of standard tests to be performed prior to strategy updates. The
+ * tests contained in this function are common to many strategy revision
+ * functions in this file. This function is meant to be invoked from within
+ * a specific strategy update function in order to perform certain common
+ * tests, including sanity checks and conditions under which no strategy
+ * updates are necessary.
+ *
+ * \param graph The graph object representing the game network. This cannot
+ *        be the empty or trivial graph, but must have at least two vertices
+ *        and one edge. If \p graph has one vertex, then no strategy update
+ *        would take place. Furthermore, if \p graph has at least two vertices
+ *        but zero edges, then strategy update would also not take place.
+ * \param vid The vertex whose strategy is to be updated. It is assumed that
+ *        \p vid represents a vertex in \p graph. No checking is performed and
+ *        it is your responsibility to ensure that \p vid is indeed a vertex
+ *        of \p graph. If an isolated vertex is provided, i.e. the input
+ *        vertex has degree 0, then no strategy update would take place and
+ *        \p vid would retain its current strategy. Strategy update would also
+ *        not take place if the local neighbourhood of \p vid are its
+ *        in-neighbours (respectively out-neighbours), but \p vid has zero
+ *        in-neighbours (respectively out-neighbours). Loops are ignored in
+ *        computing the degree (in, out, all) of \p vid.
+ * \param quantities A vector of quantities providing the quantity of each
+ *        vertex in \p graph. Think of each entry of the vector as being
+ *        generated by a function such as the fitness function for the game.
+ *        So if the vector represents fitness quantities, then each vector
+ *        entry is the fitness of some vertex. The length of this vector must
+ *        be the same as the number of vertices in the vertex set of \p graph.
+ * \param strategies A vector of the current strategies for the vertex
+ *        population. Each strategy is identified with a nonnegative integer,
+ *        whose interpretation depends on the payoff matrix of the game.
+ *        Generally we use the strategy ID as a row or column index of the
+ *        payoff matrix. The length of this vector must be the same as the
+ *        number of vertices in the vertex set of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for \p vid. If
+ *        \p graph is undirected, then we use all the immediate neighbours of
+ *        \p vid. Thus if you know that \p graph is undirected, then it is safe
+ *        to pass the value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of \p vid. This option is only relevant
+ *          when \p graph is a directed graph.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of \p vid. Again this option is only relevant
+ *          when \p graph is a directed graph.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of \p vid. This option is only
+ *          relevant if \p graph is a digraph. Also use this value if
+ *          \p graph is undirected.
+ *        \endclist
+ * \param updates Boolean; at the end of this test suite, this flag
+ *        indicates whether to proceed with strategy revision. If true then
+ *        strategy revision should proceed; otherwise there is no need to
+ *        continue with revising a vertex's strategy. A caller function that
+ *        invokes this function would use the value of \p updates to
+ *        determine whether to proceed with strategy revision.
+ * \param islocal Boolean; this flag controls which perspective to use. If
+ *        true then we use the local perspective; otherwise we use the global
+ *        perspective. The local perspective for \p vid is the set of all
+ *        immediate neighbours of \p vid. In contrast, the global perspective
+ *        for \p vid is the vertex set of \p graph.
+ * \return Codes:
+ *         \clist
+ *         \cli IGRAPH_EINVAL
+ *           This error code is returned in each of the following cases:
+ *           (1) Any of the parameters \p graph, \p quantities, or
+ *           \p strategies is a null pointer. (2) The vector \p quantities
+ *           or \p strategies has a length different from the number of
+ *           vertices in \p graph. (3) The parameter \p graph is the empty
+ *           or null graph, i.e. the graph with zero vertices and edges.
+ *         \cli IGRAPH_SUCCESS
+ *           This signal is returned if no errors were raised. You should use
+ *           the value of the boolean \p updates to decide whether to go
+ *           ahead with updating a vertex's strategy.
+ *         \endclist
+ */
+
+int igraph_microscopic_standard_tests(const igraph_t *graph,
+                                      igraph_integer_t vid,
+                                      const igraph_vector_t *quantities,
+                                      const igraph_vector_t *strategies,
+                                      igraph_neimode_t mode,
+				      igraph_bool_t *updates, 
+				      igraph_bool_t islocal) {
+
+  igraph_integer_t nvert;
+  igraph_vector_t degv;
+  *updates=1;
+
+  /* sanity checks */
+  if (graph == NULL) {
+    IGRAPH_ERROR("Graph is a null pointer", IGRAPH_EINVAL);
+  }
+  if (quantities == NULL) {
+    IGRAPH_ERROR("Quantities vector is a null pointer", IGRAPH_EINVAL);
+  }
+  if (strategies == NULL) {
+    IGRAPH_ERROR("Strategies vector is a null pointer", IGRAPH_EINVAL);
+  }
+
+  /* the empty graph */
+  nvert=igraph_vcount(graph);
+  if (nvert < 1) {
+    IGRAPH_ERROR("Graph cannot be the empty graph", IGRAPH_EINVAL);
+  }
+  /* invalid vector length */
+  if (nvert != (igraph_integer_t)igraph_vector_size(quantities)) {
+    IGRAPH_ERROR("Size of quantities vector different from number of vertices",
+                 IGRAPH_EINVAL);
+  }
+  if (nvert != (igraph_integer_t)igraph_vector_size(strategies)) {
+    IGRAPH_ERROR("Size of strategies vector different from number of vertices",
+                 IGRAPH_EINVAL);
+  }
+
+  /* Various conditions under which no strategy updates will take place. That
+   * is, the vertex retains its current strategy.
+   */
+  /* given graph has < 2 vertices */
+  if (nvert < 2) {
+    *updates=0;
+  }
+  /* graph has >= 2 vertices, but no edges */
+  if (igraph_ecount(graph) < 1) {
+    *updates=0;
+  }
+
+  /* Test for vertex isolation, depending on the perspective given. For
+   * undirected graphs, a given vertex v is isolated if its degree is zero.
+   * If we are considering in-neighbours (respectively out-neighbours), then
+   * we say that v is isolated if its in-degree (respectively out-degree) is
+   * zero. In general, this vertex isolation test is only relevant if we are
+   * using a local perspective, i.e. if we only consider the immediate
+   * neighbours (local perspective) of v as opposed to all vertices in the
+   * vertex set of the graph (global perspective).
+   */
+  if (islocal) {
+    /* Moving on ahead with vertex isolation test, since local perspective */
+    /* is requested. */
+    IGRAPH_VECTOR_INIT_FINALLY(&degv, 1);
+    IGRAPH_CHECK(igraph_degree(graph, &degv, igraph_vss_1(vid),
+			       mode, IGRAPH_NO_LOOPS));
+    if (VECTOR(degv)[0] < 1)
+      *updates = 0;
+    igraph_vector_destroy(&degv);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup spatialgames
+ * \function igraph_deterministic_optimal_imitation
+ * \brief Adopt a strategy via deterministic optimal imitation.
+ *
+ * A simple deterministic imitation strategy where a vertex revises its
+ * strategy to that which yields a local optimal. Here "local" is with
+ * respect to the immediate neighbours of the vertex. The vertex retains its
+ * current strategy where this strategy yields a locally optimal quantity.
+ * The quantity in this case could be a measure such as fitness.
+ *
+ * \param graph The graph object representing the game network. This cannot
+ *        be the empty or trivial graph, but must have at least two vertices
+ *        and one edge. If \p graph has one vertex, then no strategy update
+ *        would take place. Furthermore, if \p graph has at least two vertices
+ *        but zero edges, then strategy update would also not take place.
+ * \param vid The vertex whose strategy is to be updated. It is assumed that
+ *        \p vid represents a vertex in \p graph. No checking is performed and
+ *        it is your responsibility to ensure that \p vid is indeed a vertex
+ *        of \p graph. If an isolated vertex is provided, i.e. the input
+ *        vertex has degree 0, then no strategy update would take place and
+ *        \p vid would retain its current strategy. Strategy update would also
+ *        not take place if the local neighbourhood of \p vid are its
+ *        in-neighbours (respectively out-neighbours), but \p vid has zero
+ *        in-neighbours (respectively out-neighbours). Loops are ignored in
+ *        computing the degree (in, out, all) of \p vid.
+ * \param optimality Logical; controls the type of optimality to be used.
+ *        Supported values are:
+ *        \clist
+ *        \cli IGRAPH_MAXIMUM
+ *          Use maximum deterministic imitation, where the strategy of the
+ *          vertex with maximum quantity (e.g. fitness) would be adopted. We
+ *          update the strategy of \p vid to that which yields a local
+ *          maximum.
+ *        \cli IGRAPH_MINIMUM
+ *          Use minimum deterministic imitation. That is, the strategy of the
+ *          vertex with minimum quantity would be imitated. In other words,
+ *          update to the strategy that yields a local minimum.
+ *        \endclist
+ * \param quantities A vector of quantities providing the quantity of each
+ *        vertex in \p graph. Think of each entry of the vector as being
+ *        generated by a function such as the fitness function for the game.
+ *        So if the vector represents fitness quantities, then each vector
+ *        entry is the fitness of some vertex. The length of this vector must
+ *        be the same as the number of vertices in the vertex set of \p graph.
+ * \param strategies A vector of the current strategies for the vertex
+ *        population. The updated strategy for \p vid would be stored here.
+ *        Each strategy is identified with a nonnegative integer, whose
+ *        interpretation depends on the payoff matrix of the game. Generally
+ *        we use the strategy ID as a row or column index of the payoff
+ *        matrix. The length of this vector must be the same as the number of
+ *        vertices in the vertex set of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for \p vid. If
+ *        \p graph is undirected, then we use all the immediate neighbours of
+ *        \p vid. Thus if you know that \p graph is undirected, then it is safe
+ *        to pass the value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of \p vid. This option is only relevant
+ *          when \p graph is a directed graph.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of \p vid. Again this option is only relevant
+ *          when \p graph is a directed graph.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of \p vid. This option is only
+ *          relevant if \p graph is a digraph. Also use this value if
+ *          \p graph is undirected.
+ *        \endclist
+ * \return The error code \p IGRAPH_EINVAL is returned in each of the
+ *         following cases: (1) Any of the parameters \p graph, \p quantities,
+ *         or \p strategies is a null pointer. (2) The vector \p quantities
+ *         or \p strategies has a length different from the number of vertices
+ *         in \p graph. (3) The parameter \p graph is the empty or null graph,
+ *         i.e. the graph with zero vertices and edges.
+ *
+ * Time complexity: O(2d), where d is the degree of the vertex \p vid.
+ *
+ * \example examples/simple/igraph_deterministic_optimal_imitation.c
+ */
+
+int igraph_deterministic_optimal_imitation(const igraph_t *graph,
+                                           igraph_integer_t vid,
+                                           igraph_optimal_t optimality,
+                                           const igraph_vector_t *quantities,
+                                           igraph_vector_t *strategies,
+                                           igraph_neimode_t mode) {
+  igraph_integer_t i, k, v;
+  igraph_real_t q;
+  igraph_vector_t adj;
+  igraph_bool_t updates;
+
+  IGRAPH_CHECK(igraph_microscopic_standard_tests(graph, vid, quantities,
+                                                 strategies, mode, &updates,
+                                                 /*is local?*/ 1));
+  if (!updates) { return IGRAPH_SUCCESS; } /* Nothing to do */
+  
+  /* Choose a locally optimal strategy to imitate. This can be either maximum
+   * or minimum deterministic imitation. By now we know that the given vertex v
+   * has degree >= 1 and at least 1 edge. Then within its immediate
+   * neighbourhood adj(v) and including v itself, there exists a vertex whose
+   * strategy yields a local optimal quantity.
+   */
+  /* Random permutation of adj(v). This ensures that if there are multiple */
+  /* candidates with an optimal strategy, then we choose one such candidate */
+  /* at random. */
+  IGRAPH_VECTOR_INIT_FINALLY(&adj, 0);
+  IGRAPH_CHECK(igraph_neighbors(graph, &adj, vid, mode));
+  IGRAPH_CHECK(igraph_vector_shuffle(&adj));
+  /* maximum deterministic imitation */
+  i = vid;
+  q = (igraph_real_t)VECTOR(*quantities)[vid];
+  if (optimality == IGRAPH_MAXIMUM) {
+    for (k = 0; k < igraph_vector_size(&adj); k++) {
+      v = (igraph_integer_t) VECTOR(adj)[k];
+      if ((igraph_real_t)VECTOR(*quantities)[v] > q) {
+	i = v;
+	q = (igraph_real_t)VECTOR(*quantities)[v];
+      }
+    }
+  } else { /* minimum deterministic imitation */
+    for (k = 0; k < igraph_vector_size(&adj); k++) {
+      v = (igraph_integer_t) VECTOR(adj)[k];
+      if ((igraph_real_t)VECTOR(*quantities)[v] < q) {
+	i = v;
+	q = (igraph_real_t)VECTOR(*quantities)[v];
+      }
+    }
+  }
+  /* Now i is a vertex with a locally optimal quantity, the value of which */
+  /* is q. Update the strategy of vid to that of i. */
+  VECTOR(*strategies)[vid] = VECTOR(*strategies)[i];
+  igraph_vector_destroy(&adj);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup spatialgames
+ * \function igraph_moran_process
+ * \brief The Moran process in a network setting.
+ *
+ * This is an extension of the classic Moran process to a network setting.
+ * The Moran process is a model of haploid (asexual) reproduction within a
+ * population having a fixed size. In the network setting, the Moran process
+ * operates on a weighted graph. At each time step a vertex a is chosen for
+ * reproduction and another vertex b is chosen for death. Vertex a gives birth
+ * to an identical clone c, which replaces b. Vertex c is a clone of a in that
+ * c inherits both the current quantity (e.g. fitness) and current strategy
+ * of a.
+ *
+ * </para><para>
+ * The graph G representing the game network is assumed to be simple,
+ * i.e. free of loops and without multiple edges. If, on the other hand, G has
+ * a loop incident on some vertex v, then it is possible that when v is chosen
+ * for reproduction it would forgo this opportunity. In particular, when v is
+ * chosen for reproduction and v is also chosen for death, the clone of v
+ * would be v itself with its current vertex ID. In effect v forgoes its
+ * chance for reproduction.
+ *
+ * \param graph The graph object representing the game network. This cannot
+ *        be the empty or trivial graph, but must have at least two vertices
+ *        and one edge. The Moran process will not take place in each of the
+ *        following cases: (1) If \p graph has one vertex. (2) If \p graph has
+ *        at least two vertices but zero edges.
+ * \param weights A vector of all edge weights for \p graph. Thus weights[i]
+ *        means the weight of the edge with edge ID i. For the purpose of the
+ *        Moran process, each weight is assumed to be positive; it is your
+ *        responsibility to ensure this condition holds. The length of this
+ *        vector must be the same as the number of edges in \p graph.
+ * \param quantities A vector of quantities providing the quantity of each
+ *        vertex in \p graph. The quantity of the new clone will be stored
+ *        here. Think of each entry of the vector as being generated by a
+ *        function such as the fitness function for the game. So if the vector
+ *        represents fitness quantities, then each vector entry is the fitness
+ *        of some vertex. The length of this vector must be the same as the
+ *        number of vertices in the vertex set of \p graph. For the purpose of
+ *        the Moran process, each vector entry is assumed to be nonnegative;
+ *        no checks will be performed for this. It is your responsibility to
+ *        ensure that at least one entry is positive. Furthermore, this vector
+ *        cannot be a vector of zeros; this condition will be checked.
+ * \param strategies A vector of the current strategies for the vertex
+ *        population. The strategy of the new clone will be stored here. Each
+ *        strategy is identified with a nonnegative integer, whose
+ *        interpretation depends on the payoff matrix of the game. Generally
+ *        we use the strategy ID as a row or column index of the payoff
+ *        matrix. The length of this vector must be the same as the number of
+ *        vertices in the vertex set of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for the vertex a
+ *        chosen for reproduction. This is only relevant if \p graph is
+ *        directed. If \p graph is undirected, then it is safe to pass the
+ *        value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of a. This option is only relevant when
+ *          \p graph is directed.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of a. Again this option is only relevant
+ *          when \p graph is directed.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of a. This option is only
+ *          relevant if \p graph is directed. Also use this value if
+ *          \p graph is undirected.
+ *        \endclist
+ * \return The error code \p IGRAPH_EINVAL is returned in each of the following
+ *         cases: (1) Any of the parameters \p graph, \p weights,
+ *         \p quantities or \p strategies is a null pointer. (2) The vector
+ *         \p quantities or \p strategies has a length different from the
+ *         number of vertices in \p graph. (3) The vector \p weights has a
+ *         length different from the number of edges in \p graph. (4) The
+ *         parameter \p graph is the empty or null graph, i.e. the graph with
+ *         zero vertices and edges. (5) The vector \p weights, or the
+ *         combination of interest, sums to zero. (6) The vector \p quantities,
+ *         or the combination of interest, sums to zero.
+ *
+ * Time complexity: depends on the random number generator, but is usually
+ * O(n) where n is the number of vertices in \p graph.
+ *
+ * </para><para>
+ * References:
+ * \clist
+ * \cli (Lieberman et al. 2005)
+ *   E. Lieberman, C. Hauert, and M. A. Nowak. Evolutionary dynamics on
+ *   graphs. \emb Nature, \eme 433(7023):312--316, 2005.
+ * \cli (Moran 1958)
+ *   P. A. P. Moran. Random processes in genetics. \emb Mathematical
+ *   Proceedings of the Cambridge Philosophical Society, \eme 54(1):60--71,
+ *   1958.
+ * \endclist
+ *
+ * \example examples/simple/igraph_moran_process.c
+ */
+
+int igraph_moran_process(const igraph_t *graph,
+                         const igraph_vector_t *weights,
+                         igraph_vector_t *quantities,
+                         igraph_vector_t *strategies,
+                         igraph_neimode_t mode) {
+  igraph_bool_t updates;
+  igraph_integer_t a = -1;  /* vertex chosen for reproduction */
+  igraph_integer_t b = -1;  /* vertex chosen for death */
+  igraph_integer_t e, nedge, u, v;
+  igraph_real_t r;          /* random number */
+  igraph_vector_t deg;
+  igraph_vector_t V;        /* vector of cumulative proportionate values */
+  igraph_vit_t vA;          /* vertex list */
+  igraph_eit_t eA;          /* edge list */
+  igraph_vs_t vs;
+  igraph_es_t es;
+  long int i;
+
+  /* don't test for vertex isolation, hence vid = -1 and islocal = 0 */
+  IGRAPH_CHECK(igraph_microscopic_standard_tests(graph, /*vid*/ -1,
+                                                 quantities, strategies, mode,
+                                                 &updates, /*is local?*/ 0));
+  if (!updates)
+    return IGRAPH_SUCCESS;  /* nothing more to do */
+  if (weights == NULL)
+    IGRAPH_ERROR("Weights vector is a null pointer", IGRAPH_EINVAL);
+  nedge = igraph_ecount(graph);
+  if (nedge != (igraph_integer_t)igraph_vector_size(weights)) {
+    IGRAPH_ERROR("Size of weights vector different from number of edges",
+                 IGRAPH_EINVAL);
+  }
+
+  /* Cumulative proportionate quantities. We are using the global */
+  /* perspective, hence islocal = 0, vid = -1 and mode = IGRAPH_ALL. */
+  IGRAPH_CHECK(igraph_vcumulative_proportionate_values(graph, quantities, &V,
+                                                       /*is local?*/ 0,
+                                                       /*vid*/ -1,
+                                                       /*mode*/ IGRAPH_ALL));
+
+  /* Choose a vertex for reproduction from among all vertices in the graph. */
+  /* The vertex is chosen proportionate to its quantity and such that its */
+  /* degree is >= 1. In case we are considering in-neighbours (respectively */
+  /* out-neighbours), the chosen vertex must have in-degree (respectively */
+  /* out-degree) >= 1. All loops will be ignored. At this point, we know */
+  /* that the graph has at least one edge, which may be directed or not. */
+  /* Furthermore the quantities of all vertices sum to a positive value. */
+  /* Hence at least one vertex will be chosen for reproduction. */
+  IGRAPH_CHECK(igraph_vs_all(&vs));
+  IGRAPH_FINALLY(igraph_vs_destroy, &vs);
+  IGRAPH_CHECK(igraph_vit_create(graph, vs, &vA));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vA);
+  RNG_BEGIN();
+  r = RNG_UNIF01();
+  RNG_END();
+  i = 0;
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, 1);
+  while (!IGRAPH_VIT_END(vA)) {
+    u = (igraph_integer_t)IGRAPH_VIT_GET(vA);
+    IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_1(u), mode,
+                               IGRAPH_NO_LOOPS));
+    if (VECTOR(deg)[0] < 1) {
+      i++;
+      IGRAPH_VIT_NEXT(vA);
+      continue;
+    }
+    if (r <= VECTOR(V)[i]) {
+      /* we have found our candidate vertex for reproduction */
+      a = u;
+      break;
+    }
+    i++;
+    IGRAPH_VIT_NEXT(vA);
+  }
+  /* By now we should have chosen a vertex for reproduction. Check this. */
+  assert(a >= 0);
+
+  /* Cumulative proportionate weights. We are using the local perspective */
+  /* with respect to vertex a, which has been chosen for reproduction. */
+  /* The degree of a is deg(a) >= 1 with respect to the mode "mode", which */
+  /* can flag either the in-degree, out-degree or all degree of a. But it */
+  /* still might happen that the edge weights of interest would sum to zero. */
+  /* An error would be raised in that case. */
+  igraph_vector_destroy(&V);
+  IGRAPH_CHECK(igraph_ecumulative_proportionate_values(graph, weights, &V,
+                                                       /*is local?*/ 1,
+                                                       /*vertex*/ a, mode));
+
+  /* Choose a vertex for death from among all vertices in a's perspective. */
+  /* Let E be all the edges in the perspective of a. If (u,v) \in E is any */
+  /* such edge, then we have a = u or a = v. That is, any edge in E has a */
+  /* for one of its endpoints. As G is assumed to be a simple graph, then */
+  /* exactly one of u or v is the vertex a. Without loss of generality, we */
+  /* assume that each edge in E has the form (a, v_i). Then the vertex v_j */
+  /* chosen for death is chosen proportionate to the weight of the edge */
+  /* (a, v_j). */
+  IGRAPH_CHECK(igraph_es_incident(&es, a, mode));
+  IGRAPH_FINALLY(igraph_es_destroy, &es);
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eA));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eA);
+  RNG_BEGIN();
+  r = RNG_UNIF01();
+  RNG_END();
+  i = 0;
+  while (!IGRAPH_EIT_END(eA)) {
+    e = (igraph_integer_t)IGRAPH_EIT_GET(eA);
+    if (r <= VECTOR(V)[i]) {
+      /* We have found our candidate vertex for death; call this vertex b. */
+      /* As G is simple, then a =/= b. Check the latter condition. */
+      IGRAPH_CHECK(igraph_edge(graph, /*edge ID*/ e,
+                               /*tail vertex*/ &u, /*head vertex*/ &v));
+      if (a == u)
+        b = v;
+      else
+        b = u;
+      assert(a != b);  /* always true if G is simple */
+      break;
+    }
+    i++;
+    IGRAPH_EIT_NEXT(eA);
+  }
+
+  /* By now a vertex a is chosen for reproduction and a vertex b is chosen */
+  /* for death. Check that b has indeed been chosen. Clone vertex a and kill */
+  /* vertex b. Let the clone c have the vertex ID of b, and the strategy and */
+  /* quantity of a. */
+  assert(b >= 0);
+  VECTOR(*quantities)[b] = VECTOR(*quantities)[a];
+  VECTOR(*strategies)[b] = VECTOR(*strategies)[a];
+
+  igraph_vector_destroy(&deg);
+  igraph_vector_destroy(&V);
+  igraph_vit_destroy(&vA);
+  igraph_eit_destroy(&eA);
+  igraph_vs_destroy(&vs);
+  igraph_es_destroy(&es);
+  IGRAPH_FINALLY_CLEAN(6);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup spatialgames
+ * \function igraph_roulette_wheel_imitation
+ * \brief Adopt a strategy via roulette wheel selection.
+ *
+ * A simple stochastic imitation strategy where a vertex revises its
+ * strategy to that of a vertex u chosen proportionate to u's quantity
+ * (e.g. fitness). This is a special case of stochastic imitation, where a
+ * candidate is not chosen uniformly at random but proportionate to its
+ * quantity.
+ *
+ * \param graph The graph object representing the game network. This cannot
+ *        be the empty or trivial graph, but must have at least two vertices
+ *        and one edge. If \p graph has one vertex, then no strategy update
+ *        would take place. Furthermore, if \p graph has at least two vertices
+ *        but zero edges, then strategy update would also not take place.
+ * \param vid The vertex whose strategy is to be updated. It is assumed that
+ *        \p vid represents a vertex in \p graph. No checking is performed and
+ *        it is your responsibility to ensure that \p vid is indeed a vertex
+ *        of \p graph. If an isolated vertex is provided, i.e. the input
+ *        vertex has degree 0, then no strategy update would take place and
+ *        \p vid would retain its current strategy. Strategy update would also
+ *        not take place if the local neighbourhood of \p vid are its
+ *        in-neighbours (respectively out-neighbours), but \p vid has zero
+ *        in-neighbours (respectively out-neighbours). Loops are ignored in
+ *        computing the degree (in, out, all) of \p vid.
+ * \param islocal Boolean; this flag controls which perspective to use in
+ *        computing the relative quantity. If true then we use the local
+ *        perspective; otherwise we use the global perspective. The local
+ *        perspective for \p vid is the set of all immediate neighbours of
+ *        \p vid. In contrast, the global perspective for \p vid is the
+ *        vertex set of \p graph.
+ * \param quantities A vector of quantities providing the quantity of each
+ *        vertex in \p graph. Think of each entry of the vector as being
+ *        generated by a function such as the fitness function for the game.
+ *        So if the vector represents fitness quantities, then each vector
+ *        entry is the fitness of some vertex. The length of this vector must
+ *        be the same as the number of vertices in the vertex set of \p graph.
+ *        For the purpose of roulette wheel selection, each vector entry is
+ *        assumed to be nonnegative; no checks will be performed for this. It
+ *        is your responsibility to ensure that at least one entry is nonzero.
+ *        Furthermore, this vector cannot be a vector of zeros; this condition
+ *        will be checked.
+ * \param strategies A vector of the current strategies for the vertex
+ *        population. The updated strategy for \p vid would be stored here.
+ *        Each strategy is identified with a nonnegative integer, whose
+ *        interpretation depends on the payoff matrix of the game. Generally
+ *        we use the strategy ID as a row or column index of the payoff
+ *        matrix. The length of this vector must be the same as the number of
+ *        vertices in the vertex set of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for \p vid. This
+ *        is only relevant if we are considering the local perspective, i.e. if
+ *        \p islocal is true. If we are considering the global perspective,
+ *        then it is safe to pass the value \p IGRAPH_ALL here. If \p graph is
+ *        undirected, then we use all the immediate neighbours of \p vid. Thus
+ *        if you know that \p graph is undirected, then it is safe to pass the
+ *        value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of \p vid. This option is only relevant
+ *          when \p graph is a digraph and we are considering the local
+ *          perspective.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of \p vid. Again this option is only relevant
+ *          when \p graph is a directed graph and we are considering the local
+ *          perspective.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of \p vid. This option is only
+ *          relevant if \p graph is a digraph. Also use this value if
+ *          \p graph is undirected or we are considering the global
+ *          perspective.
+ *        \endclist
+ * \return The error code \p IGRAPH_EINVAL is returned in each of the following
+ *         cases: (1) Any of the parameters \p graph, \p quantities, or
+ *         \p strategies is a null pointer. (2) The vector \p quantities or
+ *         \p strategies has a length different from the number of vertices
+ *         in \p graph. (3) The parameter \p graph is the empty or null graph,
+ *         i.e. the graph with zero vertices and edges. (4) The vector
+ *         \p quantities sums to zero.
+ *
+ * Time complexity: O(n) where n is the number of vertices in the perspective
+ * to consider. If we consider the global perspective, then n is the number
+ * of vertices in the vertex set of \p graph. On the other hand, for the local
+ * perspective n is the degree of \p vid, excluding loops.
+ *
+ * </para><para>
+ * Reference:
+ * \clist
+ * \cli (Yu & Gen 2010)
+ *   X. Yu and M. Gen. \emb Introduction to Evolutionary Algorithms. \eme
+ *   Springer, 2010, pages 18--20.
+ * \endclist
+ *
+ * \example examples/simple/igraph_roulette_wheel_imitation.c
+ */
+
+int igraph_roulette_wheel_imitation(const igraph_t *graph,
+                                    igraph_integer_t vid,
+                                    igraph_bool_t islocal,
+                                    const igraph_vector_t *quantities,
+                                    igraph_vector_t *strategies,
+                                    igraph_neimode_t mode) {
+  igraph_bool_t updates;
+  igraph_integer_t u;
+  igraph_real_t r;    /* random number */
+  igraph_vector_t V;  /* vector of cumulative proportionate quantities */
+  igraph_vit_t A;     /* all vertices in v's perspective */
+  igraph_vs_t vs;
+  long int i;
+
+  IGRAPH_CHECK(igraph_microscopic_standard_tests(graph, vid, quantities,
+                                                 strategies, mode, &updates,
+                                                 islocal));
+  if (!updates)
+    return IGRAPH_SUCCESS;  /* nothing further to do */
+
+  /* set the perspective */
+  if (islocal)
+    IGRAPH_CHECK(igraph_vs_adj(&vs, vid, mode));
+  else
+    IGRAPH_CHECK(igraph_vs_all(&vs));
+  IGRAPH_FINALLY(igraph_vs_destroy, &vs);
+  IGRAPH_CHECK(igraph_vit_create(graph, vs, &A));
+  IGRAPH_FINALLY(igraph_vit_destroy, &A);
+
+  IGRAPH_CHECK(igraph_vcumulative_proportionate_values(graph, quantities, &V,
+                                                       islocal, vid, mode));
+
+  /* Finally, choose a vertex u to imitate. The vertex u is chosen */
+  /* proportionate to its quantity. In the case of a local perspective, we */
+  /* pretend that v's cumulative proportionate quantity has been appended to */
+  /* the vector V. Let V be of length n so that V[n-1] is the last element */
+  /* of V, and let r be a real number chosen uniformly at random from the */
+  /* unit interval [0,1]. If r > V[i] for all i < n, then v defaults to */
+  /* retaining its current strategy. Similarly in the case of the global */
+  /* perspective, if r > V[i] for all i < n - 1 then v would adopt the */
+  /* strategy of the vertex whose cumulative proportionate quantity is */
+  /* V[n-1]. */
+  /* NOTE: Here we assume that the order in which we iterate through the */
+  /* vertices in A is the same as the order in which we do so in the */
+  /* invoked function igraph_vcumulative_proportionate_values(). */
+  /* Otherwise we would incorrectly associate each V[i] with a vertex in A. */
+  RNG_BEGIN();
+  r = RNG_UNIF01();
+  RNG_END();
+  i = 0;
+  while (!IGRAPH_VIT_END(A)) {
+    if (r <= VECTOR(V)[i]) {
+      /* We have found our candidate vertex for imitation. Update strategy */
+      /* of v to that of u, and exit the selection loop. */
+      u = (igraph_integer_t)IGRAPH_VIT_GET(A);
+      VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];
+      break;
+    }
+    i++;
+    IGRAPH_VIT_NEXT(A);
+  }
+
+  /* By now, vertex v should either retain its current strategy or it has */
+  /* adopted the strategy of a vertex in its perspective. Nothing else to */
+  /* do, but clean up. */
+  igraph_vector_destroy(&V);
+  igraph_vit_destroy(&A);
+  igraph_vs_destroy(&vs);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup spatialgames
+ * \function igraph_stochastic_imitation
+ * \brief Adopt a strategy via stochastic imitation with uniform selection.
+ *
+ * A simple stochastic imitation strategy where a vertex revises its
+ * strategy to that of a vertex chosen uniformly at random from its local
+ * neighbourhood. This is called stochastic imitation via uniform selection,
+ * where the strategy to imitate is chosen via some random process. For the
+ * purposes of this function, we use uniform selection from a pool of
+ * candidates.
+ *
+ * \param graph The graph object representing the game network. This cannot
+ *        be the empty or trivial graph, but must have at least two vertices
+ *        and one edge. If \p graph has one vertex, then no strategy update
+ *        would take place. Furthermore, if \p graph has at least two vertices
+ *        but zero edges, then strategy update would also not take place.
+ * \param vid The vertex whose strategy is to be updated. It is assumed that
+ *        \p vid represents a vertex in \p graph. No checking is performed and
+ *        it is your responsibility to ensure that \p vid is indeed a vertex
+ *        of \p graph. If an isolated vertex is provided, i.e. the input
+ *        vertex has degree 0, then no strategy update would take place and
+ *        \p vid would retain its current strategy. Strategy update would also
+ *        not take place if the local neighbourhood of \p vid are its
+ *        in-neighbours (respectively out-neighbours), but \p vid has zero
+ *        in-neighbours (respectively out-neighbours). Loops are ignored in
+ *        computing the degree (in, out, all) of \p vid.
+ * \param algo This flag controls which algorithm to use in stochastic
+ *        imitation. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_IMITATE_AUGMENTED
+ *          Augmented imitation. Vertex \p vid imitates the strategy of the
+ *          chosen vertex u provided that doing so would increase the
+ *          quantity (e.g. fitness) of \p vid. Augmented imitation can be
+ *          thought of as "imitate if better".
+ *        \cli IGRAPH_IMITATE_BLIND
+ *          Blind imitation. Vertex \p vid blindly imitates the strategy of
+ *          the chosen vertex u, regardless of whether doing so would
+ *          increase or decrease the quantity of \p vid.
+ *        \cli IGRAPH_IMITATE_CONTRACTED
+ *          Contracted imitation. Here vertex \p vid imitates the strategy of
+ *          the chosen vertex u if doing so would decrease the quantity of
+ *          \p vid. Think of contracted imitation as "imitate if worse".
+ *        \endclist
+ * \param quantities A vector of quantities providing the quantity of each
+ *        vertex in \p graph. Think of each entry of the vector as being
+ *        generated by a function such as the fitness function for the game.
+ *        So if the vector represents fitness quantities, then each vector
+ *        entry is the fitness of some vertex. The length of this vector must
+ *        be the same as the number of vertices in the vertex set of \p graph.
+ * \param strategies A vector of the current strategies for the vertex
+ *        population. The updated strategy for \p vid would be stored here.
+ *        Each strategy is identified with a nonnegative integer, whose
+ *        interpretation depends on the payoff matrix of the game. Generally
+ *        we use the strategy ID as a row or column index of the payoff
+ *        matrix. The length of this vector must be the same as the number of
+ *        vertices in the vertex set of \p graph.
+ * \param mode Defines the sort of neighbourhood to consider for \p vid. If
+ *        \p graph is undirected, then we use all the immediate neighbours of
+ *        \p vid. Thus if you know that \p graph is undirected, then it is safe
+ *        to pass the value \p IGRAPH_ALL here. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_OUT
+ *          Use the out-neighbours of \p vid. This option is only relevant
+ *          when \p graph is a directed graph.
+ *        \cli IGRAPH_IN
+ *          Use the in-neighbours of \p vid. Again this option is only relevant
+ *          when \p graph is a directed graph.
+ *        \cli IGRAPH_ALL
+ *          Use both the in- and out-neighbours of \p vid. This option is only
+ *          relevant if \p graph is a digraph. Also use this value if
+ *          \p graph is undirected.
+ *        \endclist
+ * \return The error code \p IGRAPH_EINVAL is returned in each of the following
+ *         cases: (1) Any of the parameters \p graph, \p quantities, or
+ *         \p strategies is a null pointer. (2) The vector \p quantities or
+ *         \p strategies has a length different from the number of vertices
+ *         in \p graph. (3) The parameter \p graph is the empty or null graph,
+ *         i.e. the graph with zero vertices and edges. (4) The parameter
+ *         \p algo refers to an unsupported stochastic imitation algorithm.
+ *
+ * Time complexity: depends on the uniform random number generator, but should
+ * usually be O(1).
+ *
+ * \example examples/simple/igraph_stochastic_imitation.c
+ */
+
+int igraph_stochastic_imitation(const igraph_t *graph,
+                                igraph_integer_t vid,
+                                igraph_imitate_algorithm_t algo,
+                                const igraph_vector_t *quantities,
+                                igraph_vector_t *strategies,
+                                igraph_neimode_t mode) {
+  igraph_bool_t updates;
+  igraph_integer_t u;
+  igraph_vector_t adj;
+  int i;
+
+  /* sanity checks */
+  if (algo != IGRAPH_IMITATE_AUGMENTED &&
+      algo != IGRAPH_IMITATE_BLIND &&
+      algo != IGRAPH_IMITATE_CONTRACTED) {
+    IGRAPH_ERROR("Unsupported stochastic imitation algorithm",
+                 IGRAPH_EINVAL);
+  }
+  IGRAPH_CHECK(igraph_microscopic_standard_tests(graph, vid, quantities,
+                                                 strategies, mode, &updates,
+                                                 /*is local?*/ 1));
+  if (!updates)
+    return IGRAPH_SUCCESS;  /* nothing more to do */
+
+  /* immediate neighbours of v */
+  IGRAPH_VECTOR_INIT_FINALLY(&adj, 0);
+  IGRAPH_CHECK(igraph_neighbors(graph, &adj, vid, mode));
+
+  /* Blind imitation. Let v be the vertex whose strategy we want to revise. */
+  /* Choose a vertex u uniformly at random from the immediate neighbours of */
+  /* v, including v itself. Then blindly update the strategy of v to that of */
+  /* u, irrespective of whether doing so would increase or decrease the */
+  /* quantity (e.g. fitness) of v. Here v retains its current strategy if */
+  /* the chosen vertex u is indeed v itself. */
+  if (algo == IGRAPH_IMITATE_BLIND) {
+    IGRAPH_CHECK(igraph_vector_push_back(&adj, vid));
+    RNG_BEGIN();
+    i = (int) RNG_INTEGER(0, igraph_vector_size(&adj) - 1);
+    RNG_END();
+    u = (igraph_integer_t) VECTOR(adj)[i];
+    VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];
+  }
+  /* Augmented imitation. Let v be the vertex whose strategy we want to */
+  /* revise. Let f be the quantity function for the game. Choose a vertex u */
+  /* uniformly at random from the immediate neighbours of v; do not include */
+  /* v. Then v imitates the strategy of u if f(u) > f(v). Otherwise v */
+  /* retains its current strategy. */
+  else if (algo == IGRAPH_IMITATE_AUGMENTED) {
+    RNG_BEGIN();
+    i = (int) RNG_INTEGER(0, igraph_vector_size(&adj) - 1);
+    RNG_END();
+    u = (igraph_integer_t) VECTOR(adj)[i];
+    if (VECTOR(*quantities)[u] > VECTOR(*quantities)[vid])
+      VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];
+  }
+  /* Contracted imitation. Let v be the vertex whose strategy we want to */
+  /* update and let f be the quantity function for the game. Choose a vertex */
+  /* u uniformly at random from the immediate neighbours of v, excluding v */
+  /* itself. Then v imitates the strategy of u provided that f(u) < f(v). */
+  /* Otherwise v retains its current strategy. */
+  else if (algo == IGRAPH_IMITATE_CONTRACTED) {
+    RNG_BEGIN();
+    i = (int) RNG_INTEGER(0, igraph_vector_size(&adj) - 1);
+    RNG_END();
+    u = (igraph_integer_t) VECTOR(adj)[i];
+    if (VECTOR(*quantities)[u] < VECTOR(*quantities)[vid])
+      VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];
+  }
+
+  /* clean up */
+  igraph_vector_destroy(&adj);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
diff --git a/src/mixing.c b/src/mixing.c
new file mode 100644
index 0000000..011c00c
--- /dev/null
+++ b/src/mixing.c
@@ -0,0 +1,298 @@
+/* -*- 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
+
+*/
+
+#include "igraph_mixing.h"
+#include "igraph_interface.h"
+
+/**
+ * \function igraph_assortativity_nominal
+ * Assortativity of a graph based on vertex categories
+ * 
+ * Assuming the vertices of the input graph belong to different
+ * categories, this function calculates the assortativity coefficient of
+ * the graph. The assortativity coefficient is between minus one and one
+ * and it is one if all connections stay within categories, it is
+ * minus one, if the network is perfectly disassortative. For a
+ * randomly connected network it is (asymptotically) zero.
+ * 
+ * </para><para>See equation (2) in M. E. J. Newman: Mixing patterns
+ * in networks, Phys. Rev. E 67, 026126 (2003)
+ * (http://arxiv.org/abs/cond-mat/0209450) for the proper
+ * definition. 
+ * 
+ * \param graph The input graph, it can be directed or undirected.
+ * \param types Vector giving the vertex types. They are assumed to be
+ *    integer numbers, starting with zero.
+ * \param res Pointer to a real variable, the result is stored here.
+ * \param directed Boolean, it gives whether to consider edge
+ *    directions in a directed graph. It is ignored for undirected
+ *    graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|E|+t), |E| is the number of edges, t is the
+ * number of vertex types.
+ * 
+ * \sa \ref igraph_assortativity if the vertex types are defines by
+ * numeric values (e.g. vertex degree), instead of categories. 
+ * 
+ * \example examples/simple/assortativity.c
+ */
+
+int igraph_assortativity_nominal(const igraph_t *graph, 
+				 const igraph_vector_t *types,
+				 igraph_real_t *res,
+				 igraph_bool_t directed) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int no_of_types;
+  igraph_vector_t ai, bi, eii;
+  long int e, i;
+  igraph_real_t sumaibi=0.0, sumeii=0.0;
+
+  if (igraph_vector_size(types) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `types' vector length", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_min(types) < 0) {
+    IGRAPH_ERROR("Invalid `types' vector", IGRAPH_EINVAL);
+  }
+
+  directed = directed && igraph_is_directed(graph);
+
+  no_of_types=(long int) igraph_vector_max(types)+1;
+  IGRAPH_VECTOR_INIT_FINALLY(&ai, no_of_types);
+  IGRAPH_VECTOR_INIT_FINALLY(&bi, no_of_types);
+  IGRAPH_VECTOR_INIT_FINALLY(&eii, no_of_types);
+
+  for (e=0; e<no_of_edges; e++) {
+    long int from=IGRAPH_FROM(graph, e);
+    long int to=IGRAPH_TO(graph, e);
+    long int from_type = (long int) VECTOR(*types)[from];
+    long int to_type = (long int) VECTOR(*types)[to];
+    
+    VECTOR(ai)[from_type] += 1;
+    VECTOR(bi)[to_type] += 1;
+    if (from_type == to_type) {
+      VECTOR(eii)[from_type] += 1;
+    }
+    if (!directed) {
+      if (from_type == to_type) {
+	VECTOR(eii)[from_type] += 1;
+      }  
+      VECTOR(ai)[to_type] += 1;
+      VECTOR(bi)[from_type] += 1;
+    }
+  }
+  
+  for (i=0; i<no_of_types; i++) {
+    sumaibi += (VECTOR(ai)[i]/no_of_edges) * (VECTOR(bi)[i]/no_of_edges);
+    sumeii  += (VECTOR(eii)[i]/no_of_edges);
+  }
+  
+  if (!directed) { 
+    sumaibi /= 4.0;
+    sumeii  /= 2.0;
+  }
+
+  *res = (sumeii - sumaibi) / (1.0 - sumaibi);
+  
+  igraph_vector_destroy(&eii);
+  igraph_vector_destroy(&bi);
+  igraph_vector_destroy(&ai);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+    
+/** 
+ * \function igraph_assortativity
+ * Assortativity based on numeric properties of vertices
+ * 
+ * This function calculates the assortativity coefficient of the input
+ * graph. This coefficient is basically the correlation between the
+ * actual connectivity patterns of the vertices and the pattern
+ * expected from the distribution of the vertex types. 
+ * 
+ * </para><para>See equation (21) in M. E. J. Newman: Mixing patterns
+ * in networks, Phys. Rev. E 67, 026126 (2003)
+ * (http://arxiv.org/abs/cond-mat/0209450) for the proper
+ * definition. The actual calculation is performed using equation (26)
+ * in the same paper for directed graphs, and equation (4) in
+ * M. E. J. Newman: Assortative mixing in networks,
+ * Phys. Rev. Lett. 89, 208701 (2002)
+ * (http://arxiv.org/abs/cond-mat/0205405/) for undirected graphs.
+ * 
+ * \param graph The input graph, it can be directed or undirected.
+ * \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 a null pointer 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 a null pointer and undirected
+ *     assortativity coefficient is being calculated.
+ * \param res Pointer to a real variable, the result is stored here.
+ * \param directed Boolean, whether to consider edge directions for
+ *     directed graphs. It is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|E|), linear in the number of edges of the
+ * graph.
+ * 
+ * \sa \ref igraph_assortativity_nominal() if you have discrete vertex
+ * categories instead of numeric labels, and \ref
+ * igraph_assortativity_degree() for the special case of assortativity
+ * based on vertex degree.
+ * 
+ * \example examples/simple/assortativity.c
+ */
+
+int igraph_assortativity(const igraph_t *graph,
+			 const igraph_vector_t *types1,
+			 const igraph_vector_t *types2,
+			 igraph_real_t *res,
+			 igraph_bool_t directed) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int e;
+
+  directed = directed && igraph_is_directed(graph);
+
+  if (!directed && types2) { 
+    IGRAPH_WARNING("Only `types1' is used for undirected case");
+  }
+
+  if (igraph_vector_size(types1) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `types1' vector length", IGRAPH_EINVAL);
+  }
+
+  if (types2 && igraph_vector_size(types2) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `types2' vector length", IGRAPH_EINVAL);
+  }
+
+  if (!directed) {
+    igraph_real_t num1=0.0, num2=0.0, den1=0.0;
+  
+    for (e=0; e<no_of_edges; e++) {
+      long int from=IGRAPH_FROM(graph, e);
+      long int to=IGRAPH_TO(graph, e);
+      igraph_real_t from_type=VECTOR(*types1)[from];
+      igraph_real_t to_type=VECTOR(*types1)[to];
+      
+      num1 += from_type * to_type;
+      num2 += from_type + to_type;
+      den1 += from_type * from_type + to_type * to_type;
+    }
+    
+    num1 /= no_of_edges;
+    den1 /= no_of_edges * 2;
+    num2 /= no_of_edges * 2;
+    num2 = num2 * num2;
+    
+    *res = (num1-num2) / (den1-num2);
+
+  } else {
+    igraph_real_t num1=0.0, num2=0.0, num3=0.0,
+      den1=0.0, den2=0.0;
+    igraph_real_t num, den;
+
+    if (!types2) { types2=types1; }
+    
+    for (e=0; e<no_of_edges; e++) {
+      long int from=IGRAPH_FROM(graph, e);
+      long int to=IGRAPH_TO(graph, e);
+      igraph_real_t from_type=VECTOR(*types1)[from];
+      igraph_real_t to_type=VECTOR(*types2)[to];
+      
+      num1 += from_type * to_type;
+      num2 += from_type;
+      num3 += to_type;
+      den1 += from_type * from_type;
+      den2 += to_type * to_type;
+    }
+    
+    num = num1 - num2*num3/no_of_edges;
+    den = sqrt(den1 - num2*num2/no_of_edges) * 
+      sqrt(den2 - num3*num3/no_of_edges);
+    
+    *res = num /den;
+  }
+      
+  return 0;
+}
+
+/**
+ * \function igraph_assortativity_degree
+ * Assortativity of a graph based on vertex degree
+ * 
+ * Assortativity based on vertex degree, please see the discussion at
+ * the documentation of \ref igraph_assortativity() for details. 
+ * 
+ * \param graph The input graph, it can be directed or undirected.
+ * \param res Pointer to a real variable, the result is stored here.
+ * \param directed Boolean, whether to consider edge directions for
+ *     directed graphs. This argument is ignored for undirected
+ *     graphs. Supply 1 (=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 Error code.
+ * 
+ * Time complexity: O(|E|+|V|), |E| is the number of edges, |V| is
+ * the number of vertices.
+ * 
+ * \sa \ref igraph_assortativity() for the general function
+ * calculating assortativity for any kind of numeric vertex values.
+ * 
+ * \example examples/simple/assortativity.c
+ */
+
+int igraph_assortativity_degree(const igraph_t *graph,
+				igraph_real_t *res, 
+				igraph_bool_t directed) {
+
+  directed = directed && igraph_is_directed(graph);
+
+  if (directed) {
+    igraph_vector_t indegree, outdegree;
+    igraph_vector_init(&indegree, 0);
+    igraph_vector_init(&outdegree, 0);
+    igraph_degree(graph, &indegree, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1);
+    igraph_degree(graph, &outdegree, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1);
+    igraph_vector_add_constant(&indegree, -1);
+    igraph_vector_add_constant(&outdegree, -1);
+    igraph_assortativity(graph, &outdegree, &indegree, res, /*directed=*/ 1);
+    igraph_vector_destroy(&indegree);
+    igraph_vector_destroy(&outdegree);
+  } else {
+    igraph_vector_t degree;
+    igraph_vector_init(&degree, 0);
+    igraph_degree(graph, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
+    igraph_vector_add_constant(&degree, -1);
+    igraph_assortativity(graph, &degree, 0, res, /*directed=*/ 0);
+    igraph_vector_destroy(&degree);
+  }
+  
+  return 0;
+}
diff --git a/src/motifs.c b/src/motifs.c
new file mode 100644
index 0000000..57c665e
--- /dev/null
+++ b/src/motifs.c
@@ -0,0 +1,1088 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_motifs.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_adjlist.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_interface.h"
+#include "igraph_nongraph.h"
+#include "igraph_structural.h"
+#include "igraph_stack.h"
+#include "config.h"
+
+#include <string.h>
+
+extern unsigned int igraph_i_isoclass_3[];
+extern unsigned int igraph_i_isoclass_4[];
+extern unsigned int igraph_i_isoclass_3u[];
+extern unsigned int igraph_i_isoclass_4u[];
+extern unsigned int igraph_i_isoclass2_3[];
+extern unsigned int igraph_i_isoclass2_4[];
+extern unsigned int igraph_i_isoclass2_3u[];
+extern unsigned int igraph_i_isoclass2_4u[];
+extern unsigned int igraph_i_isoclass_3_idx[];
+extern unsigned int igraph_i_isoclass_4_idx[];
+extern unsigned int igraph_i_isoclass_3u_idx[];
+extern unsigned int igraph_i_isoclass_4u_idx[];
+
+/**
+ * Callback function for igraph_motifs_randesu that counts the motifs by
+ * isomorphism class in a histogram.
+ */
+igraph_bool_t igraph_i_motifs_randesu_update_hist(const igraph_t *graph,
+    igraph_vector_t *vids, int isoclass, void* extra) {
+  igraph_vector_t *hist = (igraph_vector_t*)extra;
+  IGRAPH_UNUSED(graph); IGRAPH_UNUSED(vids);
+  VECTOR(*hist)[isoclass]++;
+  return 0;
+}
+
+/**
+ * \function igraph_motifs_randesu
+ * \brief Count the number of motifs in a graph
+ * 
+ * </para><para>
+ * Motifs are small connected subgraphs of a given structure in a
+ * graph. It is argued that the motif profile (ie. the number of
+ * different motifs in the graph) is characteristic for different
+ * types of networks and network function is related to the motifs in
+ * the graph.
+ * 
+ * </para><para>
+ * This function is able to find the different motifs of size three
+ * and four (ie. the number of different subgraphs with three and four
+ * vertices) in the network.
+ * 
+ * </para><para>
+ * In a big network the total number of motifs can be very large, so
+ * it takes a lot of time to find all of them, a sampling method can
+ * be used. This function is capable of doing sampling via the
+ * \c cut_prob argument. This argument gives the probability that
+ * a branch of the motif search tree will not be explored. See
+ * S. Wernicke and F. Rasche: FANMOD: a tool for fast network motif
+ * detection, Bioinformatics 22(9), 1152--1153, 2006 for details.
+ * 
+ * </para><para>
+ * Set the \c cut_prob argument to a zero vector for finding all
+ * motifs. 
+ * 
+ * </para><para> 
+ * Directed motifs will be counted in directed graphs and undirected
+ * motifs in undirected graphs.
+ *
+ * \param graph The graph to find the motifs in.
+ * \param hist The result of the computation, it gives the number of
+ *        motifs found for each isomorphism class. See
+ *        \ref igraph_isoclass() for help about isomorphism classes.
+ *        Note that this function does \em not count isomorphism
+ *        classes that are not connected and will report NaN (more
+ *        precisely \c IGRAPH_NAN) for them.
+ * \param size The size of the motifs to search for. Only three and
+ *        four are implemented currently. The limitation is not in the
+ *        motif finding code, but the graph isomorphism code.
+ * \param cut_prob Vector of probabilities for cutting the search tree
+ *        at a given level. The first element is the first level, etc.
+ *        Supply all zeros here (of length \c size) to find all motifs 
+ *        in a graph.
+ * \return Error code.
+ * \sa \ref igraph_motifs_randesu_estimate() for estimating the number
+ * of motifs in a graph, this can help to set the \c cut_prob
+ * parameter; \ref igraph_motifs_randesu_no() to calculate the total
+ * number of motifs of a given size in a graph;
+ * \ref igraph_motifs_randesu_callback() for calling a callback function
+ * for every motif found.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_motifs_randesu.c
+ */
+int igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *hist, 
+			  int size, const igraph_vector_t *cut_prob) {
+  int histlen;
+
+  if (size != 3 && size != 4) {
+    IGRAPH_ERROR("Only 3 and 4 vertex motifs are implemented",
+		 IGRAPH_EINVAL);
+  }
+  if (size==3) {
+    histlen = igraph_is_directed(graph) ? 16 : 4;
+  } else {
+    histlen = igraph_is_directed(graph) ? 218 : 11;
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(hist, histlen));
+  igraph_vector_null(hist);
+
+  IGRAPH_CHECK(igraph_motifs_randesu_callback(graph, size, cut_prob,
+	&igraph_i_motifs_randesu_update_hist, hist));
+
+  if (size == 3) {
+    if (igraph_is_directed(graph)) {
+      VECTOR(*hist)[0] = VECTOR(*hist)[1] = VECTOR(*hist)[3] = IGRAPH_NAN;
+    } else {
+      VECTOR(*hist)[0] = VECTOR(*hist)[1] = IGRAPH_NAN;
+    }
+  } else if (size == 4) {
+    if (igraph_is_directed(graph)) {
+      int not_connected[] = { 0, 1, 2, 4, 5, 6, 9, 10, 11, 15, 22, 23, 27,
+			      28, 33, 34, 39, 62, 120 };
+      int i, n=sizeof(not_connected) / sizeof(int);
+      for (i=0; i<n; i++) {
+	VECTOR(*hist)[not_connected[i]] = IGRAPH_NAN;
+      }
+    } else {
+      VECTOR(*hist)[0] = VECTOR(*hist)[1] = VECTOR(*hist)[2] = 
+      VECTOR(*hist)[3] = VECTOR(*hist)[5] = IGRAPH_NAN;
+    }
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_motifs_randesu_callback
+ * \brief Finds motifs in a graph and calls a function for each of them
+ * 
+ * </para><para>
+ * Similarly to \ref igraph_motifs_randesu(), this function is able to find the
+ * different motifs of size three and four (ie. the number of different
+ * subgraphs with three and four vertices) in the network. However, instead of
+ * counting them, the function will call a callback function for each motif
+ * found to allow further tests or post-processing.
+ * 
+ * </para><para>
+ * The \c cut_prob argument also allows sampling the motifs, just like for
+ * \ref igraph_motifs_randesu(). Set the \c cut_prob argument to a zero vector
+ * for finding all motifs. 
+ * 
+ * \param graph The graph to find the motifs in.
+ * \param size The size of the motifs to search for. Only three and
+ *        four are implemented currently. The limitation is not in the
+ *        motif finding code, but the graph isomorphism code.
+ * \param cut_prob Vector of probabilities for cutting the search tree
+ *        at a given level. The first element is the first level, etc.
+ *        Supply all zeros here (of length \c size) to find all motifs 
+ *        in a graph.
+ * \param callback A pointer to a function of type \ref igraph_motifs_handler_t.
+ *        This function will be called whenever a new motif is found.
+ * \param extra Extra argument to pass to the callback function.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_motifs_randesu.c
+ */
+
+int igraph_motifs_randesu_callback(const igraph_t *graph, int size,
+		const igraph_vector_t *cut_prob, igraph_motifs_handler_t *callback,
+		void* extra) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_adjlist_t allneis, alloutneis;
+  igraph_vector_int_t *neis;
+  long int father;
+  long int i, j, s;
+  long int motifs=0;
+
+  igraph_vector_t vids;		/* this is G */
+  igraph_vector_t adjverts;	/* this is V_E */
+  igraph_stack_t stack;		/* this is S */
+  long int *added;
+  char *subg;
+  
+  unsigned int *arr_idx, *arr_code;
+  int code=0;
+  unsigned char mul, idx;
+  
+  igraph_bool_t terminate = 0;
+
+  if (size != 3 && size != 4) {
+    IGRAPH_ERROR("Only 3 and 4 vertex motifs are implemented",
+		 IGRAPH_EINVAL);
+  }
+  if (size==3) {
+    mul=3;
+    if (igraph_is_directed(graph)) {
+      arr_idx=igraph_i_isoclass_3_idx;
+      arr_code=igraph_i_isoclass2_3;
+    } else {
+      arr_idx=igraph_i_isoclass_3u_idx;
+      arr_code=igraph_i_isoclass2_3u;
+    }
+  } else {
+    mul=4;
+    if (igraph_is_directed(graph)) {
+      arr_idx=igraph_i_isoclass_4_idx;
+      arr_code=igraph_i_isoclass2_4;
+    } else {
+      arr_idx=igraph_i_isoclass_4u_idx;
+      arr_code=igraph_i_isoclass2_4u;
+    }
+  }
+
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot find motifs", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+
+  subg=igraph_Calloc(no_of_nodes, char);
+  if (subg==0) {
+    IGRAPH_ERROR("Cannot find motifs", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, subg);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);  
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &alloutneis, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &alloutneis);  
+
+  IGRAPH_VECTOR_INIT_FINALLY(&vids, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&adjverts, 0);
+  IGRAPH_CHECK(igraph_stack_init(&stack, 0));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+
+  RNG_BEGIN();
+
+  for (father=0; father<no_of_nodes; father++) {
+    long int level;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    if (VECTOR(*cut_prob)[0] == 1 ||
+	RNG_UNIF01() < VECTOR(*cut_prob)[0]) {
+      continue;
+    }
+    
+    /* init G */
+    igraph_vector_clear(&vids); level=0;
+    IGRAPH_CHECK(igraph_vector_push_back(&vids, father));
+    subg[father]=1; added[father] += 1; level += 1;
+    
+    /* init V_E */
+    igraph_vector_clear(&adjverts);
+    neis=igraph_adjlist_get(&allneis, father);
+    s=igraph_vector_int_size(neis);
+    for (i=0; i<s; i++) {
+      long int nei=(long int) VECTOR(*neis)[i];
+      if (!added[nei] && nei > father) {
+	IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei));
+	IGRAPH_CHECK(igraph_vector_push_back(&adjverts, father));
+      }
+      added[nei] += 1;
+    }
+    
+    /* init S */
+    igraph_stack_clear(&stack);
+
+    while (level > 1 || !igraph_vector_empty(&adjverts)) {
+      igraph_real_t cp=VECTOR(*cut_prob)[level];
+
+      if (level==size-1) {
+	s=igraph_vector_size(&adjverts)/2;
+	for (i=0; i<s; i++) {
+	  long int k, s2;
+	  long int last;
+
+	  if (cp!=0 && RNG_UNIF01() < cp) { continue; }
+	  motifs+=1;
+	  
+	  last=(long int) VECTOR(adjverts)[2*i];
+	  IGRAPH_CHECK(igraph_vector_push_back(&vids, last));
+	  subg[last]=(char) size;
+
+	  code=0; idx=0;
+	  for (k=0; k<size; k++) {
+	    long int from=(long int) VECTOR(vids)[k];
+ 	    neis=igraph_adjlist_get(&alloutneis, from);
+	    s2=igraph_vector_int_size(neis);
+	    for (j=0; j<s2; j++) {
+	      long int nei=(long int) VECTOR(*neis)[j];
+	      if (subg[nei] && k != subg[nei]-1) {
+		idx=(unsigned char) (mul*k+(subg[nei]-1));
+		code |= arr_idx[idx];
+	      }
+	    }
+	  }
+
+	  if (callback(graph, &vids, (int) arr_code[code], extra)) {
+	    terminate = 1;
+	    break;
+	  }
+	  igraph_vector_pop_back(&vids);
+	  subg[last]=0;
+	}
+      }
+
+      /* did the callback function asked us to terminate the search? */
+      if (terminate)
+	break;
+
+      /* can we step down? */
+      if (level < size-1 && 
+	  !igraph_vector_empty(&adjverts)) {
+	/* we might step down */
+	long int neifather=(long int) igraph_vector_pop_back(&adjverts);
+	long int nei=(long int) igraph_vector_pop_back(&adjverts);
+
+	if (cp==0 || RNG_UNIF01() > cp) {
+	  /* yes, step down */
+	  IGRAPH_CHECK(igraph_vector_push_back(&vids, nei));
+	  subg[nei] = (char) level+1; added[nei] += 1; level += 1;
+
+	  IGRAPH_CHECK(igraph_stack_push(&stack, neifather));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, nei));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, level));
+	  
+	  neis=igraph_adjlist_get(&allneis, nei);
+	  s=igraph_vector_int_size(neis);
+	  for (i=0; i<s; i++) {
+	    long int nei2=(long int) VECTOR(*neis)[i];
+	    if (!added[nei2] && nei2 > father) {
+	      IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei2));
+	      IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei));
+	    }
+	    added[nei2] += 1;
+	  }
+	}
+      } else {
+	/* no, step back */
+	long int nei, neifather;
+	while (!igraph_stack_empty(&stack) &&
+	       level==igraph_stack_top(&stack)-1) {
+	  igraph_stack_pop(&stack);
+	  nei=(long int) igraph_stack_pop(&stack);
+	  neifather=(long int) igraph_stack_pop(&stack);
+	  igraph_vector_push_back(&adjverts, nei);
+	  igraph_vector_push_back(&adjverts, neifather);
+	}
+
+	nei=(long int) igraph_vector_pop_back(&vids);
+	subg[nei]=0; added[nei] -= 1; level -= 1;
+	neis=igraph_adjlist_get(&allneis, nei);
+	s=igraph_vector_int_size(neis);
+	for (i=0; i<s; i++) {
+	  added[ (long int) VECTOR(*neis)[i] ] -= 1;
+	}
+	while (!igraph_vector_empty(&adjverts) && 
+	       igraph_vector_tail(&adjverts)==nei) {
+	  igraph_vector_pop_back(&adjverts);
+	  igraph_vector_pop_back(&adjverts);
+	}
+      }
+      
+    } /* while */
+
+    /* did the callback function asked us to terminate the search? */
+    if (terminate)
+      break;
+
+    /* clear the added vector */
+    added[father] -= 1;
+    subg[father] = 0;
+    neis=igraph_adjlist_get(&allneis, father);
+    s=igraph_vector_int_size(neis);
+    for (i=0; i<s; i++) {
+      added[ (long int) VECTOR(*neis)[i] ] -= 1;
+    }
+
+  } /* for father */
+
+  RNG_END();
+
+  igraph_Free(added);
+  igraph_Free(subg);
+  igraph_vector_destroy(&vids);
+  igraph_vector_destroy(&adjverts);
+  igraph_adjlist_destroy(&alloutneis);
+  igraph_adjlist_destroy(&allneis);
+  igraph_stack_destroy(&stack);
+  IGRAPH_FINALLY_CLEAN(7);
+  return 0;
+}
+
+/**
+ * \function igraph_motifs_randesu_estimate
+ * \brief Estimate the total number of motifs in a graph
+ * 
+ * </para><para>
+ * This function is useful for large graphs for which it is not
+ * feasible to count all the different motifs, because there is very
+ * many of them.
+ *
+ * </para><para>
+ * The total number of motifs is estimated by taking a sample of
+ * vertices and counts all motifs in which these vertices are
+ * included. (There is also a \c cut_prob parameter which gives the
+ * probabilities to cut a branch of the search tree.)
+ *
+ * </para><para> 
+ * Directed motifs will be counted in directed graphs and undirected
+ * motifs in undirected graphs.
+ *
+ * \param graph The graph object to study.
+ * \param est Pointer to an integer type, the result will be stored
+ *        here.
+ * \param size The size of the motif to look for.
+ * \param cut_prob Vector giving the probabilities to cut a branch of
+ *        the search tree and omit counting the motifs in that branch.
+ *        It contains a probability for each level. Supply \c size
+ *        zeros here to count all the motifs in the sample.
+ * \param sample_size The number of vertices to use as the
+ *        sample. This parameter is only used if the \c parsample
+ *        argument is a null pointer.
+ * \param parsample Either pointer to an initialized vector or a null
+ *        pointer. If a vector then the vertex ids in the vector are
+ *        used as a sample. If a null pointer then the \c sample_size
+ *        argument is used to create a sample of vertices drawn with
+ *        uniform probability.
+ * \return Error code.
+ * \sa \ref igraph_motifs_randesu(), \ref igraph_motifs_randesu_no().
+ * 
+ * Time complexity: TODO.
+ */
+
+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 *parsample) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t neis;
+    
+  igraph_vector_t vids;		/* this is G */
+  igraph_vector_t adjverts;	/* this is V_E */
+  igraph_stack_t stack;		/* this is S */
+  long int *added;
+  igraph_vector_t *sample;
+  long int sam;
+  long int i;
+
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot find motifs", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&vids, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&adjverts, 0);
+  IGRAPH_CHECK(igraph_stack_init(&stack, 0));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  if (parsample==0) {
+    sample=igraph_Calloc(1, igraph_vector_t);
+    if (sample==0) {
+      IGRAPH_ERROR("Cannot estimate motifs", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, sample);
+    IGRAPH_VECTOR_INIT_FINALLY(sample, 0);  
+    IGRAPH_CHECK(igraph_random_sample(sample, 0, no_of_nodes-1, sample_size));
+  } else {
+    sample=(igraph_vector_t*)parsample;
+    sample_size=(igraph_integer_t) igraph_vector_size(sample);
+  }
+
+  *est=0;
+
+  RNG_BEGIN();
+
+  for (sam=0; sam<sample_size; sam++) {
+    long int father=(long int) VECTOR(*sample)[sam];
+    long int level, s;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    if (VECTOR(*cut_prob)[0] == 1 ||
+	RNG_UNIF01() < VECTOR(*cut_prob)[0]) {
+      continue;
+    }
+
+    /* init G */
+    igraph_vector_clear(&vids); level=0;
+    IGRAPH_CHECK(igraph_vector_push_back(&vids, father));
+    added[father] += 1; level += 1;
+    
+    /* init V_E */
+    igraph_vector_clear(&adjverts);
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) father,
+				  IGRAPH_ALL));
+    s=igraph_vector_size(&neis);
+    for (i=0; i<s; i++) {
+      long int nei=(long int) VECTOR(neis)[i];
+      if (!added[nei] && nei > father) {
+	IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei));
+	IGRAPH_CHECK(igraph_vector_push_back(&adjverts, father));
+      }
+      added[nei] += 1;
+    }
+    
+    /* init S */
+    igraph_stack_clear(&stack);
+
+    while (level > 1 || !igraph_vector_empty(&adjverts)) {
+      igraph_real_t cp=VECTOR(*cut_prob)[level];
+      
+      if (level==size-1) {
+	s=igraph_vector_size(&adjverts)/2;
+	for (i=0; i<s; i++) {
+	  if (cp!=0 && RNG_UNIF01() < cp) { continue; }
+	  (*est) += 1;
+	}
+      }
+
+      if (level < size-1 && 
+	  !igraph_vector_empty(&adjverts)) {
+	/* We might step down */
+	long int neifather=(long int) igraph_vector_pop_back(&adjverts);
+	long int nei=(long int) igraph_vector_pop_back(&adjverts);
+	
+	if (cp==0 || RNG_UNIF01() > cp) {
+	  /* Yes, step down */
+	  IGRAPH_CHECK(igraph_vector_push_back(&vids, nei));
+	  added[nei] += 1; level += 1;
+
+	  IGRAPH_CHECK(igraph_stack_push(&stack, neifather));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, nei));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, level));
+
+	  IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) nei, 
+					IGRAPH_ALL));
+	  s=igraph_vector_size(&neis);
+	  for (i=0; i<s; i++) {
+	    long int nei2=(long int) VECTOR(neis)[i];
+	    if (!added[nei2] && nei2 > father) {
+	      IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei2));
+	    IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei));
+	    }
+	    added[nei2] += 1;
+	  }
+	}
+      } else {
+	/* no, step back */
+	long int nei, neifather;
+	while (!igraph_stack_empty(&stack) &&
+	       level==igraph_stack_top(&stack)-1) {
+	  igraph_stack_pop(&stack);
+	  nei=(long int) igraph_stack_pop(&stack);
+	  neifather=(long int) igraph_stack_pop(&stack);
+	  igraph_vector_push_back(&adjverts, nei);
+	  igraph_vector_push_back(&adjverts, neifather);
+	}
+
+	nei=(long int) igraph_vector_pop_back(&vids);
+	added[nei] -= 1; level -= 1;
+	IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) nei,
+				      IGRAPH_ALL));
+	s=igraph_vector_size(&neis);
+	for (i=0; i<s; i++) {
+	  added[ (long int) VECTOR(neis)[i] ] -= 1;
+	}
+	while (!igraph_vector_empty(&adjverts) && 
+	       igraph_vector_tail(&adjverts)==nei) {
+	  igraph_vector_pop_back(&adjverts);
+	  igraph_vector_pop_back(&adjverts);
+	}
+      }
+      
+    } /* while */
+
+    /* clear the added vector */
+    added[father] -= 1;
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) father, 
+				  IGRAPH_ALL));
+    s=igraph_vector_size(&neis);
+    for (i=0; i<s; i++) {
+      added[ (long int) VECTOR(neis)[i] ] -= 1;
+    }
+
+  } /* for father */
+
+  RNG_END();
+
+  (*est) *= ((double)no_of_nodes/sample_size);
+
+  if (parsample==0) {
+    igraph_vector_destroy(sample);
+    igraph_Free(sample);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  igraph_Free(added);
+  igraph_vector_destroy(&vids);
+  igraph_vector_destroy(&adjverts);
+  igraph_stack_destroy(&stack);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(5);
+  return 0;
+}
+
+/**
+ * \function igraph_motifs_randesu_no
+ * \brief Count the total number of motifs in a graph
+ *
+ * </para><para> 
+ * This function counts the total number of motifs in a graph without
+ * assigning isomorphism classes to them. 
+ *
+ * </para><para> 
+ * Directed motifs will be counted in directed graphs and undirected
+ * motifs in undirected graphs.
+ *
+ * \param graph The graph object to study.
+ * \param no Pointer to an integer type, the result will be stored
+ *        here. 
+ * \param size The size of the motifs to count.
+ * \param cut_prob Vector giving the probabilities that a branch of
+ *        the search tree will be cut at a given level.
+ * \return Error code.
+ * \sa \ref igraph_motifs_randesu(), \ref
+ *     igraph_motifs_randesu_estimate(). 
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no,
+			     int size, const igraph_vector_t *cut_prob) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t neis;
+    
+  igraph_vector_t vids;		/* this is G */
+  igraph_vector_t adjverts;	/* this is V_E */
+  igraph_stack_t stack;		/* this is S */
+  long int *added;
+  long int father;
+  long int i;
+
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot find motifs", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&vids, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&adjverts, 0);
+  IGRAPH_CHECK(igraph_stack_init(&stack, 0));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  *no=0;
+
+  RNG_BEGIN();
+
+  for (father=0; father<no_of_nodes; father++) {
+    long int level, s;
+
+    IGRAPH_ALLOW_INTERRUPTION();    
+
+    if (VECTOR(*cut_prob)[0] == 1 ||
+	RNG_UNIF01() < VECTOR(*cut_prob)[0]) {
+      continue;
+    }
+
+    /* init G */
+    igraph_vector_clear(&vids); level=0;
+    IGRAPH_CHECK(igraph_vector_push_back(&vids, father));
+    added[father] += 1; level += 1;
+    
+    /* init V_E */
+    igraph_vector_clear(&adjverts);
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) father,
+				  IGRAPH_ALL));
+    s=igraph_vector_size(&neis);
+    for (i=0; i<s; i++) {
+      long int nei=(long int) VECTOR(neis)[i];
+      if (!added[nei] && nei > father) {
+	IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei));
+	IGRAPH_CHECK(igraph_vector_push_back(&adjverts, father));
+      }
+      added[nei] += 1;
+    }
+    
+    /* init S */
+    igraph_stack_clear(&stack);
+
+    while (level > 1 || !igraph_vector_empty(&adjverts)) {
+      igraph_real_t cp=VECTOR(*cut_prob)[level];
+      
+      if (level==size-1) {
+	s=igraph_vector_size(&adjverts)/2;
+	for (i=0; i<s; i++) {
+	  if (cp!=0 && RNG_UNIF01() < cp) { continue; }
+	  (*no) += 1;
+	}
+      }
+
+      if (level < size-1 && 
+	  !igraph_vector_empty(&adjverts)) {
+	/* We might step down */
+	long int neifather=(long int) igraph_vector_pop_back(&adjverts);
+	long int nei=(long int) igraph_vector_pop_back(&adjverts);
+
+	if (cp==0 || RNG_UNIF01() > cp) {
+	  /* Yes, step down */
+	  IGRAPH_CHECK(igraph_vector_push_back(&vids, nei));
+	  added[nei] += 1; level += 1;
+	  
+	  IGRAPH_CHECK(igraph_stack_push(&stack, neifather));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, nei));
+	  IGRAPH_CHECK(igraph_stack_push(&stack, level));
+	  
+	  IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) nei,
+					IGRAPH_ALL));
+	  s=igraph_vector_size(&neis);
+	  for (i=0; i<s; i++) {
+	    long int nei2=(long int) VECTOR(neis)[i];
+	    if (!added[nei2] && nei2 > father) {
+	      IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei2));
+	      IGRAPH_CHECK(igraph_vector_push_back(&adjverts, nei));
+	    }
+	    added[nei2] += 1;
+	  }
+	}
+      } else {
+	/* no, step back */
+	long int nei, neifather;
+	while (!igraph_stack_empty(&stack) &&
+	       level==igraph_stack_top(&stack)-1) {
+	  igraph_stack_pop(&stack);
+	  nei=(long int) igraph_stack_pop(&stack);
+	  neifather=(long int) igraph_stack_pop(&stack);
+	  igraph_vector_push_back(&adjverts, nei);
+	  igraph_vector_push_back(&adjverts, neifather);
+	}
+
+	nei=(long int) igraph_vector_pop_back(&vids);
+	added[nei] -= 1; level -= 1;
+	IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) nei,
+				      IGRAPH_ALL));
+	s=igraph_vector_size(&neis);
+	for (i=0; i<s; i++) {
+	  added[ (long int) VECTOR(neis)[i] ] -= 1;
+	}
+	while (!igraph_vector_empty(&adjverts) && 
+	       igraph_vector_tail(&adjverts)==nei) {
+	  igraph_vector_pop_back(&adjverts);
+	  igraph_vector_pop_back(&adjverts);
+	}
+      }
+      
+    } /* while */
+
+    /* clear the added vector */
+    added[father] -= 1;
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) father,
+				  IGRAPH_ALL));
+    s=igraph_vector_size(&neis);
+    for (i=0; i<s; i++) {
+      added[ (long int) VECTOR(neis)[i] ] -= 1;
+    }
+
+  } /* for father */
+
+  RNG_END();
+
+  igraph_Free(added);
+  igraph_vector_destroy(&vids);
+  igraph_vector_destroy(&adjverts);
+  igraph_stack_destroy(&stack);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(5);
+  return 0;
+}
+
+/**
+ * \function igraph_dyad_census
+ * \brief Calculating the dyad census as defined by Holland and Leinhardt
+ * 
+ * </para><para>
+ * Dyad census means classifying each pair of vertices of a directed
+ * graph into three categories: mutual, there is an edge from \c a to
+ * \c b and also from \c b to \c a; asymmetric, there is an edge
+ * either from \c a to \c b or from \c b to \c a but not the other way
+ * and null, no edges between \c a and \c b.
+ * 
+ * </para><para>
+ * Holland, P.W. and Leinhardt, S.  (1970).  A Method for Detecting
+ * Structure in Sociometric Data.  American Journal of Sociology,
+ * 70, 492-513. 
+ * \param graph The input graph, a warning is given if undirected as 
+ *    the results are undefined for undirected graphs.
+ * \param mut Pointer to an integer, the number of mutual dyads is
+ *    stored here.
+ * \param asym Pointer to an integer, the number of asymmetric dyads
+ *    is stored here.
+ * \param null Pointer to an integer, the number of null dyads is
+ *    stored here.
+ * \return Error code.
+ *
+ * \sa \ref igraph_reciprocity(), \ref igraph_triad_census().
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges.
+ */
+
+int igraph_dyad_census(const igraph_t *graph, igraph_integer_t *mut,
+		       igraph_integer_t *asym, igraph_integer_t *null) {
+  
+  igraph_integer_t nonrec=0, rec=0;
+  igraph_vector_t inneis, outneis;
+  igraph_integer_t vc=igraph_vcount(graph);
+	long int i;
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_WARNING("Dyad census called on undirected graph");
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&inneis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&outneis, 0);
+
+  for (i=0; i<vc; i++) {
+    long int ip, op;
+    igraph_neighbors(graph, &inneis, i, IGRAPH_IN);
+    igraph_neighbors(graph, &outneis, i, IGRAPH_OUT);
+
+    ip=op=0;
+    while (ip < igraph_vector_size(&inneis) &&
+					 op < igraph_vector_size(&outneis)) {
+      if (VECTOR(inneis)[ip] < VECTOR(outneis)[op]) {
+				nonrec += 1;
+				ip++;
+      } else if (VECTOR(inneis)[ip] > VECTOR(outneis)[op]) {
+				nonrec += 1;
+				op++;
+      } else {
+				rec += 1;
+				ip++;
+				op++;
+      }
+    }
+    nonrec += (igraph_vector_size(&inneis)-ip) +
+      (igraph_vector_size(&outneis)-op);
+  }
+
+  igraph_vector_destroy(&inneis);
+  igraph_vector_destroy(&outneis);
+  IGRAPH_FINALLY_CLEAN(2);
+
+	*mut = rec / 2;
+	*asym = nonrec / 2;
+	if (vc % 2) { 
+		*null = vc * ((vc-1)/2);
+	} else {
+		*null = (vc/2) * (vc-1);
+	}
+	if (*null < vc) {
+		IGRAPH_WARNING("Integer overflow, returning zero");
+		*null = IGRAPH_NAN;
+	} else {
+		*null = *null-(*mut)-(*asym);
+	}
+
+  return 0;
+}
+
+/**
+ * \function igraph_triad_census_24
+ * TODO
+ */
+
+int igraph_triad_census_24(const igraph_t *graph, igraph_integer_t *res2,
+			   igraph_integer_t *res4) {
+  
+  long int vc=igraph_vcount(graph);
+  igraph_vector_long_t seen;
+  igraph_vector_int_t *neis, *neis2;
+  long int i, j, k, s, neilen, neilen2, ign;
+  igraph_adjlist_t adjlist;
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&seen, vc));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &seen);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  *res2=*res4=0;
+
+  for (i=0; i<vc; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    neis=igraph_adjlist_get(&adjlist, i);
+    neilen=igraph_vector_int_size(neis);
+    /* mark neighbors of i & i itself */
+    VECTOR(seen)[i]=i+1;
+    ign=0;
+    for (j=0; j<neilen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      if (VECTOR(seen)[nei]==i+1 || VECTOR(seen)[nei]==-(i+1)) {
+	/* multiple edges or loop edge */
+	VECTOR(seen)[nei]=-(i+1);
+	ign++;
+      } else {
+	VECTOR(seen)[nei]=i+1;
+      }
+    }
+    
+    for (j=0; j<neilen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      if (nei<=i || (j>0 && nei==VECTOR(*neis)[j-1])) { continue; }
+      neis2=igraph_adjlist_get(&adjlist, nei);
+      neilen2=igraph_vector_int_size(neis2);
+      s=0;
+      for (k=0; k<neilen2; k++) {
+	long int nei2=(long int) VECTOR(*neis2)[k];
+	if (k>0 && nei2==VECTOR(*neis2)[k-1]) { continue; }	
+	if (VECTOR(seen)[nei2] != i+1 && VECTOR(seen)[nei2] != -(i+1)) {
+	  s++;
+	}
+      }
+      if (VECTOR(seen)[nei] > 0) {
+	*res2 += vc-s-neilen+ign-1;
+      } else {
+	*res4 += vc-s-neilen+ign-1;
+      }
+    }
+  }
+
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_long_destroy(&seen);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_triad_census
+ * \brief Triad census, as defined by Davis and Leinhardt
+ * 
+ * </para><para>
+ * Calculating the triad census means classifying every triple of
+ * vertices in a directed graph. A triple can be in one of 16 states:
+ * \clist
+ * \cli 003 
+ *      A, B, C, the empty graph.
+ * \cli 012 
+ *      A->B, C, a graph with a single directed edge.
+ * \cli 102 
+ *      A<->B, C, a graph with a mutual connection between two vertices.
+ * \cli 021D 
+ *      A<-B->C, the binary out-tree.
+ * \cli 021U 
+ *      A->B<-C, the binary in-tree.
+ * \cli 021C 
+ *      A->B->C, the directed line.
+ * \cli 111D 
+ *      A<->B<-C.
+ * \cli 111U 
+ *      A<->B->C.
+ * \cli 030T 
+ *      A->B<-C, A->C.
+ * \cli 030C 
+ *      A<-B<-C, A->C.
+ * \cli 201 
+ *      A<->B<->C.
+ * \cli 120D 
+ *      A<-B->C, A<->C.
+ * \cli 120U 
+ *      A->B<-C, A<->C.
+ * \cli 120C 
+ *      A->B->C, A<->C.
+ * \cli 210 
+ *      A->B<->C, A<->C.
+ * \cli 300 
+ *      A<->B<->C, A<->C, the complete graph.
+ * \endclist
+ *
+ * </para><para>
+ * 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.
+ * 
+ * </para><para>
+ * This function calls \ref igraph_motifs_randesu() which is an
+ * implementation of the FANMOD motif finder tool, see \ref
+ * igraph_motifs_randesu() for details. Note that the order of the
+ * triads is not the same for \ref igraph_triad_census() and \ref
+ * igraph_motifs_randesu().
+ * 
+ * \param graph The input graph. A warning is given for undirected
+ *   graphs, as the result is undefined for those.
+ * \param res Pointer to an initialized vector, the result is stored
+ *   here in the same order as given in the list above. Note that this
+ *   order is different than the one used by \ref igraph_motifs_randesu().
+ * \return Error code.
+ * 
+ * \sa \ref igraph_motifs_randesu(), \ref igraph_dyad_census().
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_triad_census(const igraph_t *graph, igraph_vector_t *res) {
+
+  igraph_vector_t cut_prob;
+  igraph_integer_t m2, m4;
+  igraph_vector_t tmp;
+  igraph_integer_t vc=igraph_vcount(graph);
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_WARNING("Triad census called on an undirected graph");
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&cut_prob, 3); /* all zeros */
+  IGRAPH_CHECK(igraph_vector_resize(res, 16));
+  IGRAPH_CHECK(igraph_motifs_randesu(graph, &tmp, 3, &cut_prob));
+  
+  IGRAPH_CHECK(igraph_triad_census_24(graph, &m2, &m4));
+  VECTOR(tmp)[0]=0;
+  VECTOR(tmp)[1]=m2;
+  VECTOR(tmp)[3]=m4;
+  VECTOR(tmp)[0]=vc*(vc-1)*(vc-2)/6 - igraph_vector_sum(&tmp);
+  
+  /* Reorder */
+  VECTOR(*res)[0] = VECTOR(tmp)[0];
+  VECTOR(*res)[1] = VECTOR(tmp)[1];
+  VECTOR(*res)[2] = VECTOR(tmp)[3];
+  VECTOR(*res)[3] = VECTOR(tmp)[6];
+  VECTOR(*res)[4] = VECTOR(tmp)[2];
+  VECTOR(*res)[5] = VECTOR(tmp)[4];
+  VECTOR(*res)[6] = VECTOR(tmp)[5];
+  VECTOR(*res)[7] = VECTOR(tmp)[9];
+  VECTOR(*res)[8] = VECTOR(tmp)[7];
+  VECTOR(*res)[9] = VECTOR(tmp)[11];
+  VECTOR(*res)[10] = VECTOR(tmp)[10];
+  VECTOR(*res)[11] = VECTOR(tmp)[8];
+  VECTOR(*res)[12] = VECTOR(tmp)[13];
+  VECTOR(*res)[13] = VECTOR(tmp)[12];
+  VECTOR(*res)[14] = VECTOR(tmp)[14];
+  VECTOR(*res)[15] = VECTOR(tmp)[15];
+  
+  igraph_vector_destroy(&cut_prob);
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(2);  
+  
+  return 0;
+}
+
diff --git a/src/operators.c b/src/operators.c
new file mode 100644
index 0000000..122edaa
--- /dev/null
+++ b/src/operators.c
@@ -0,0 +1,1215 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_operators.h"
+#include "igraph_error.h"
+#include "igraph_memory.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_interface.h"
+#include "igraph_constructors.h"
+#include "igraph_adjlist.h"
+#include "igraph_attributes.h"
+#include "igraph_conversion.h"
+#include "igraph_qsort.h"
+#include <limits.h>
+#include "config.h"
+
+/**
+ * \function igraph_disjoint_union
+ * \brief Creates the union of two disjoint graphs
+ *
+ * </para><para>
+ * First the vertices of the second graph will be relabeled with new
+ * vertex ids to have two disjoint sets of vertex ids, then the union
+ * of the two graphs will be formed.
+ * If the two graphs have |V1| and |V2| vertices and |E1| and |E2|
+ * edges respectively then the new graph will have |V1|+|V2| vertices
+ * and |E1|+|E2| edges. 
+ *
+ * </para><para>
+ * Both graphs need to have the same directedness, ie. either both
+ * directed or both undirected.
+ * 
+ * </para><para>
+ * The current version of this function cannot handle graph, vertex
+ * and edge attributes, they will be lost.
+ *
+ * \param res  Pointer to an uninitialized graph object, the result
+ *        will stored here.
+ * \param left The first graph.
+ * \param right The second graph.
+ * \return Error code.
+ * \sa \ref igraph_disjoint_union_many() for creating the disjoint union
+ * of more than two graphs, \ref igraph_union() for non-disjoint
+ * union.
+ * 
+ * Time complexity: O(|V1|+|V2|+|E1|+|E2|).
+ * 
+ * \example examples/simple/igraph_disjoint_union.c
+ */
+
+int igraph_disjoint_union(igraph_t *res, const igraph_t *left, 
+			  const igraph_t *right) {
+
+  long int no_of_nodes_left=igraph_vcount(left);
+  long int no_of_nodes_right=igraph_vcount(right);
+  long int no_of_edges_left=igraph_ecount(left);
+  long int no_of_edges_right=igraph_ecount(right);
+  igraph_vector_t edges;
+  igraph_bool_t directed_left=igraph_is_directed(left);
+  igraph_integer_t from, to;
+  long int i;
+  
+  if (directed_left != igraph_is_directed(right)) {
+    IGRAPH_ERROR("Cannot union directed and undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, 
+				     2*(no_of_edges_left+no_of_edges_right)));
+  for (i=0; i<no_of_edges_left; i++) {
+    igraph_edge(left, (igraph_integer_t) i, &from, &to);
+    igraph_vector_push_back(&edges, from);
+    igraph_vector_push_back(&edges, to);
+  }
+  for (i=0; i<no_of_edges_right; i++) {
+    igraph_edge(right, (igraph_integer_t) i, &from, &to);
+    igraph_vector_push_back(&edges, from+no_of_nodes_left);
+    igraph_vector_push_back(&edges, to+no_of_nodes_left);
+  }
+  
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) 
+			     (no_of_nodes_left+no_of_nodes_right), 
+			     directed_left));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_disjoint_union_many
+ * \brief The disjint union of many graphs.
+ *
+ * </para><para>
+ * First the vertices in the graphs will be relabeled with new vertex
+ * ids to have pairwise disjoint vertex id sets and then the union of
+ * the graphs is formed.
+ * The number of vertices and edges in the result is the total number
+ * of vertices and edges in the graphs.
+ * 
+ * </para><para>
+ * Both graphs need to have the same directedness, ie. either both
+ * directed or both undirected.
+ * 
+ * </para><para>
+ * The current version of this function cannot handle graph, vertex
+ * and edge attributes, they will be lost.
+ *
+ * \param res Pointer to an uninitialized graph object, the result of
+ *        the operation will be stored here.
+ * \param graphs Pointer vector, contains pointers to initialized
+ *        graph objects.
+ * \return Error code.
+ * \sa \ref igraph_disjoint_union() for an easier syntax if you have
+ * only two graphs, \ref igraph_union_many() for non-disjoint union.
+ *
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges in the result.
+ */
+
+int igraph_disjoint_union_many(igraph_t *res, 
+			       const igraph_vector_ptr_t *graphs) {
+  long int no_of_graphs=igraph_vector_ptr_size(graphs);
+  igraph_bool_t directed=1;
+  igraph_vector_t edges;
+  long int no_of_edges=0;
+  long int shift=0;
+  igraph_t *graph;
+  long int i, j;
+  igraph_integer_t from, to;
+  
+  if (no_of_graphs != 0) {
+    graph=VECTOR(*graphs)[0];
+    directed=igraph_is_directed(graph);
+    for (i=0; i<no_of_graphs; i++) {      
+      graph=VECTOR(*graphs)[i];
+      no_of_edges += igraph_ecount(graph);
+      if (directed != igraph_is_directed(graph)) {
+	IGRAPH_ERROR("Cannot union directed and undirected graphs", 
+		     IGRAPH_EINVAL);
+      }
+    }
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, 2*no_of_edges));
+  
+  for (i=0; i<no_of_graphs; i++) {
+    long int ec;
+    graph=VECTOR(*graphs)[i];    
+    ec=igraph_ecount(graph);
+    for (j=0; j<ec; j++) {
+      igraph_edge(graph, (igraph_integer_t) j, &from, &to);
+      igraph_vector_push_back(&edges, from+shift);
+      igraph_vector_push_back(&edges, to+shift);
+    }
+    shift += igraph_vcount(graph);
+  }
+  
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) shift, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_i_order_edgelist_cmp(void *edges, const void *e1, 
+				const void *e2) {
+  igraph_vector_t *edgelist=edges;
+  long int edge1=(*(const long int*) e1) * 2;
+  long int edge2=(*(const long int*) e2) * 2;
+  long int from1=VECTOR(*edgelist)[edge1];
+  long int from2=VECTOR(*edgelist)[edge2];
+  if (from1 < from2) {
+    return -1;
+  } else if (from1 > from2) { 
+    return 1;
+  } else {
+    long int to1=VECTOR(*edgelist)[edge1+1];
+    long int to2=VECTOR(*edgelist)[edge2+1];
+    if (to1 < to2) { 
+      return -1;
+    } else if (to1 > to2) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+}
+
+#define IGRAPH_MODE_UNION        1
+#define IGRAPH_MODE_INTERSECTION 2
+
+int igraph_i_merge(igraph_t *res, int mode, 
+		   const igraph_t *left, const igraph_t *right, 
+		   igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
+  
+  long int no_of_nodes_left=igraph_vcount(left);
+  long int no_of_nodes_right=igraph_vcount(right);
+  long int no_of_nodes;
+  long int no_edges_left=igraph_ecount(left);
+  long int no_edges_right=igraph_ecount(right);
+  igraph_bool_t directed=igraph_is_directed(left);
+  igraph_vector_t edges;
+  igraph_vector_t edges1, edges2;
+  igraph_vector_long_t order1, order2;
+  long int i, j, eptr=0;
+  long int idx1, idx2, edge1=-1, edge2=-1, from1=-1, from2=-1, to1=-1, to2=-1;
+  igraph_bool_t l;
+
+  if (directed != igraph_is_directed(right)) {
+    IGRAPH_ERROR("Cannot make union or intersection of directed "
+		 "and undirected graph", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges1, no_edges_left*2);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges2, no_edges_right*2);
+  IGRAPH_CHECK(igraph_vector_long_init(&order1, no_edges_left));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &order1);
+  IGRAPH_CHECK(igraph_vector_long_init(&order2, no_edges_right));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &order2);
+  
+  if (edge_map1) { 
+    switch (mode) {
+    case IGRAPH_MODE_UNION:
+      IGRAPH_CHECK(igraph_vector_resize(edge_map1, no_edges_left));
+      break;
+    case IGRAPH_MODE_INTERSECTION:
+      igraph_vector_clear(edge_map1);
+      break;
+    }
+  }
+  if (edge_map2) { 
+    switch (mode) {
+    case IGRAPH_MODE_UNION:
+      IGRAPH_CHECK(igraph_vector_resize(edge_map2, no_edges_right));
+      break;
+    case IGRAPH_MODE_INTERSECTION:
+      igraph_vector_clear(edge_map2);
+      break;
+    }
+  }
+
+  no_of_nodes=no_of_nodes_left > no_of_nodes_right ?
+    no_of_nodes_left : no_of_nodes_right;
+
+  /* We merge the two edge lists. We need to sort them first.
+     For undirected graphs, we also need to make sure that 
+     for every edge, that larger (non-smaller) vertex id is in the
+     second column. */
+
+  IGRAPH_CHECK(igraph_get_edgelist(left, &edges1, /*bycol=*/ 0));
+  IGRAPH_CHECK(igraph_get_edgelist(right, &edges2, /*bycol=*/ 0));
+  if (!directed) {
+    for (i=0, j=0; i<no_edges_left; i++, j+=2) {
+      if (VECTOR(edges1)[j] > VECTOR(edges1)[j+1]) {
+	long int tmp=VECTOR(edges1)[j];
+	VECTOR(edges1)[j]=VECTOR(edges1)[j+1];
+	VECTOR(edges1)[j+1]=tmp;
+      }
+    }
+    for (i=0, j=0; i<no_edges_right; i++, j+=2) {
+      if (VECTOR(edges2)[j] > VECTOR(edges2)[j+1]) {
+	long int tmp=VECTOR(edges2)[j];
+	VECTOR(edges2)[j]=VECTOR(edges2)[j+1];
+	VECTOR(edges2)[j+1]=tmp;
+      }
+    }
+  }
+
+  for (i=0; i<no_edges_left; i++) {
+    VECTOR(order1)[i]=i;
+  }
+  for (i=0; i<no_edges_right; i++) {
+    VECTOR(order2)[i]=i;
+  }
+
+  igraph_qsort_r(VECTOR(order1), no_edges_left, sizeof(VECTOR(order1)[0]),
+		 &edges1, igraph_i_order_edgelist_cmp);
+  igraph_qsort_r(VECTOR(order2), no_edges_right, sizeof(VECTOR(order2)[0]),
+		 &edges2, igraph_i_order_edgelist_cmp);
+
+#define INC1() if ( (++idx1) < no_edges_left) {			 \
+    edge1 = VECTOR(order1)[idx1];				 \
+    from1 = VECTOR(edges1)[2*edge1];				 \
+    to1 = VECTOR(edges1)[2*edge1+1];				 \
+  }
+#define INC2() if ( (++idx2) < no_edges_right) {		 \
+    edge2 = VECTOR(order2)[idx2];				 \
+    from2 = VECTOR(edges2)[2*edge2];				 \
+    to2 = VECTOR(edges2)[2*edge2+1];				 \
+  }
+
+  idx1 = idx2 = -1;
+  INC1();
+  INC2();
+  
+#define CONT() switch (mode) {				\
+ case IGRAPH_MODE_UNION:				\
+   l = idx1 < no_edges_left || idx2 < no_edges_right;	\
+   break;						\
+ case IGRAPH_MODE_INTERSECTION:				\
+   l = idx1 < no_edges_left && idx2 < no_edges_right;	\
+   break;						\
+  }
+
+  CONT();
+  while (l) {
+    if (idx2 >= no_edges_right || 
+	(idx1 < no_edges_left && from1 < from2) || 
+	(idx1 < no_edges_left && from1 == from2 && to1 < to2)) {
+      /* Edge from first graph */
+      if (mode==IGRAPH_MODE_UNION) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, from1));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, to1));
+	if (edge_map1) { VECTOR(*edge_map1)[edge1]=eptr; }
+	eptr++;
+      }
+      INC1();
+    } else if (idx1 >= no_edges_left ||
+	       (idx2 < no_edges_right && from2 < from1) ||
+	       (idx2 < no_edges_right && from1 == from2 && to2 < to1)) {
+      /* Edge from second graph */
+      if (mode==IGRAPH_MODE_UNION) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, from2));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, to2));
+	if (edge_map2) { VECTOR(*edge_map2)[edge2]=eptr; }
+	eptr++;
+      }
+      INC2();
+    } else {
+      /* Edge from both */
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, from1));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, to1));
+      if (mode==IGRAPH_MODE_UNION) {
+	if (edge_map1) { VECTOR(*edge_map1)[edge1]=eptr; }
+	if (edge_map2) { VECTOR(*edge_map2)[edge2]=eptr; }
+      } else if (mode==IGRAPH_MODE_INTERSECTION) {
+	if (edge_map1) { 
+	  IGRAPH_CHECK(igraph_vector_push_back(edge_map1, edge1));
+	}
+	if (edge_map2) {
+	  IGRAPH_CHECK(igraph_vector_push_back(edge_map2, edge2));
+	}
+      }
+      eptr++;
+      INC1();
+      INC2();
+    }
+    CONT();
+  }
+  
+#undef INC1
+#undef INC2
+
+  igraph_vector_long_destroy(&order2);
+  igraph_vector_long_destroy(&order1);
+  igraph_vector_destroy(&edges2);
+  igraph_vector_destroy(&edges1);
+  IGRAPH_FINALLY_CLEAN(4);
+  
+  IGRAPH_CHECK(igraph_create(res, &edges, no_of_nodes, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_intersection
+ * \brief Collect the common edges from two graphs.
+ * 
+ * </para><para>
+ * The result graph contains only edges present both in the first and
+ * the second graph. The number of vertices in the result graph is the
+ * same as the larger from the two arguments.
+ * 
+ * \param res Pointer to an uninitialized graph object. This will
+ * contain the result of the operation.
+ * \param left The first operand, a graph object.
+ * \param right The second operand, a graph object.
+ * \param edge_map1 Null pointer, or an initialized \type igraph_vector_t.
+ *    If the latter, then a mapping from the edges of the result graph, to
+ *    the edges of the \p left input graph is stored here.
+ * \param edge_map2 Null pointer, or an \type igraph_vector_t. The same 
+ *    as \p edge_map1, but for the \p right input graph.
+ * \return Error code.
+ * \sa \ref igraph_intersection_many() to calculate the intersection
+ * of many graphs at once, \ref igraph_union(), \ref
+ * igraph_difference() for other operators.
+ * 
+ * Time complexity: O(|V|+|E|), |V| is the number of nodes, |E|
+ * is the number of edges in the smaller graph of the two. (The one 
+ * containing less vertices is considered smaller.)
+ * 
+ * \example examples/simple/igraph_intersection.c
+ */
+
+int igraph_intersection(igraph_t *res,
+			const igraph_t *left, const igraph_t *right, 
+			igraph_vector_t *edge_map1, 
+			igraph_vector_t *edge_map2) {
+  return igraph_i_merge(res, IGRAPH_MODE_INTERSECTION, left, right, 
+			edge_map1, edge_map2);
+}
+
+void igraph_i_union_many_free(igraph_vector_ptr_t *v) {
+  long int i, n=igraph_vector_ptr_size(v);
+  for (i=0; i<n; i++) { 
+    if (VECTOR(*v)[i] != 0) {
+      igraph_vector_destroy(VECTOR(*v)[i]);
+      igraph_Free(VECTOR(*v)[i]);
+    }
+  }
+  igraph_vector_ptr_destroy(v);
+}
+
+void igraph_i_union_many_free2(igraph_vector_ptr_t *v) {
+  long int i, n=igraph_vector_ptr_size(v);
+  for (i=0; i<n; i++) { 
+    if (VECTOR(*v)[i] != 0) {
+      igraph_vector_long_destroy(VECTOR(*v)[i]);
+      igraph_Free(VECTOR(*v)[i]);
+    }
+  }
+  igraph_vector_ptr_destroy(v);
+}
+
+void igraph_i_union_many_free3(igraph_vector_ptr_t *v) {
+  long int i, n=igraph_vector_ptr_size(v);
+  for (i=0; i<n; i++) { 
+    if (VECTOR(*v)[i] != 0) {
+      igraph_vector_destroy(VECTOR(*v)[i]);
+      igraph_Free(VECTOR(*v)[i]);
+    }
+  }
+}
+
+/**
+ * \function igraph_intersection_many
+ * \brief The intersection of more than two graphs.
+ * 
+ * </para><para> 
+ * This function calculates the intersection of the graphs stored in
+ * the \c graphs argument. Only those edges will be included in the
+ * result graph which are part of every graph in \c graphs.
+ *
+ * </para><para>
+ * The number of vertices in the result graph will be the maximum
+ * number of vertices in the argument graphs.
+ *
+ * \param res Pointer to an uninitialized graph object, the result of
+ *        the operation will be stored here.
+ * \param graphs Pointer vector, contains pointers to graphs objects,
+ *        the operands of the intersection operator.
+ * \param edgemaps If not a null pointer, then it must be an initialized 
+ *        pointer vector and the mappings of edges from the graphs to the
+ *        result graph will be stored here, in the same order as
+ *        \p graphs. Each mapping is stored in a separate 
+ *        \type igraph_vector_t object. For the edges that are not in
+ *        the intersection, -1 is stored.
+ * \return Error code.
+ * \sa \ref igraph_intersection() for the intersection of two graphs, 
+ * \ref igraph_union_many(), \ref igraph_union() and \ref
+ * igraph_difference() for other operators.
+ * 
+ * Time complexity: O(|V|+|E|), |V| is the number of vertices,
+ * |E| is the number of edges in the smallest graph (ie. the graph having
+ * the less vertices).
+ */
+
+int igraph_intersection_many(igraph_t *res, 
+			     const igraph_vector_ptr_t *graphs, 
+			     igraph_vector_ptr_t *edgemaps) {
+
+  long int no_of_graphs=igraph_vector_ptr_size(graphs);
+  long int no_of_nodes=0;
+  igraph_bool_t directed=1;
+  igraph_vector_t edges;
+  igraph_vector_ptr_t edge_vects, order_vects;
+  long int i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto=-1;
+  igraph_vector_long_t no_edges;
+  igraph_bool_t allne= no_of_graphs == 0 ? 0 : 1, allsame=0;
+  long int idx=0;
+  
+  /* Check directedness */
+  if (no_of_graphs != 0) {
+    directed=igraph_is_directed(VECTOR(*graphs)[0]);
+  }
+  for (i=1; i<no_of_graphs; i++) {
+    if (directed != igraph_is_directed(VECTOR(*graphs)[i])) {
+      IGRAPH_ERROR("Cannot intersect directed and undirected graphs",
+		   IGRAPH_EINVAL);
+    }
+  }
+
+  if (edgemaps) {
+    IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs));
+    igraph_vector_ptr_null(edgemaps);
+    IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges);
+
+  /* Calculate number of nodes, query number of edges */
+  for (i=0; i<no_of_graphs; i++) {
+    long int n=igraph_vcount(VECTOR(*graphs)[i]);
+    if (n > no_of_nodes) { no_of_nodes=n; }
+    VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]);
+    allne = allne && VECTOR(no_edges)[i] > 0;
+  }
+
+  if (edgemaps) {
+    for (i=0; i<no_of_graphs; i++) {
+      VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t);
+      if (!VECTOR(*edgemaps)[i]) {
+	IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM);
+      }
+      IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i],
+				      VECTOR(no_edges)[i]));
+      igraph_vector_fill(VECTOR(*edgemaps)[i], -1);
+    }
+  }
+
+  /* Allocate memory for the edge lists and their index vectors */
+  if (no_of_graphs != 0) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs));
+    IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects);
+    IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs));
+    IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects);
+  }
+  for (i=0; i<no_of_graphs; i++) {
+    VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t);
+    VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t);
+    if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { 
+      IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM);
+    }
+    IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i],
+				    2 * VECTOR(no_edges)[i]));
+    IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], 
+					 VECTOR(no_edges)[i]));
+  }
+
+  /* Query and sort the edge lists */
+  for (i=0; i<no_of_graphs; i++) {
+    long int k, j, n=VECTOR(no_edges)[i];
+    igraph_vector_t *edges=VECTOR(edge_vects)[i];
+    igraph_vector_long_t *order=VECTOR(order_vects)[i];
+    IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0));
+    if (!directed) {
+      for (k=0, j=0; k<n; k++, j+=2) {
+	if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) {
+	  long int tmp=VECTOR(*edges)[j];
+	  VECTOR(*edges)[j]=VECTOR(*edges)[j+1];
+	  VECTOR(*edges)[j+1]=tmp;
+	}
+      }
+    }
+    for (k=0; k<n; k++) { VECTOR(*order)[k]=k; }
+    igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, 
+		   igraph_i_order_edgelist_cmp);
+  }
+
+  /* Do the merge. We work from the end of the edge lists, 
+     because then we don't have to keep track of where we are right
+     now in the edge and order lists. We find the "largest" edge,
+     and if it is present in all graphs, then we copy it to the
+     result. We remove all instances of this edge.  */
+
+  while (allne) {
+
+    /* Look for the smallest tail element */
+    for (j=0, tailfrom=LONG_MAX, tailto=LONG_MAX; j<no_of_graphs; j++) {
+      long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
+      igraph_vector_t *ev=VECTOR(edge_vects)[j];
+      long int from=VECTOR(*ev)[2*edge];
+      long int to=VECTOR(*ev)[2*edge+1];
+      if (from < tailfrom || (from == tailfrom && to < tailto)) {
+	tailfrom = from; tailto = to;
+      }
+    }
+    
+    /* OK, now remove all elements from the tail(s) that are bigger
+       than the smallest tail element. */
+    for (j=0, allsame=1; j<no_of_graphs; j++) { 
+      long int from=-1, to=-1;
+      while (1) {
+	long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
+	igraph_vector_t *ev=VECTOR(edge_vects)[j];
+	from=VECTOR(*ev)[2*edge];
+	to=VECTOR(*ev)[2*edge+1];
+	if (from > tailfrom || (from==tailfrom && to > tailto)) {
+	  igraph_vector_long_pop_back(VECTOR(order_vects)[j]);
+	  if (igraph_vector_long_empty(VECTOR(order_vects)[j])) {
+	    allne=0;
+	    break;
+	  }
+	} else {
+	  break;
+	}
+      }
+      if (from != tailfrom || to != tailto) { allsame=0; }
+    } 
+
+    /* Add the edge, if the smallest tail element was present 
+       in all graphs. */
+    if (allsame) { 
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto));
+    }
+
+    /* Drop edges matching the smalles tail elements
+       from the order vectors, build edge maps */
+    if (allne) {
+      for (j=0; j<no_of_graphs; j++) {
+	long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
+	igraph_vector_t *ev=VECTOR(edge_vects)[j];
+	long int from=VECTOR(*ev)[2*edge];
+	long int to=VECTOR(*ev)[2*edge+1];
+	if (from == tailfrom && to == tailto) {
+	  igraph_vector_long_pop_back(VECTOR(order_vects)[j]);
+	  if (igraph_vector_long_empty(VECTOR(order_vects)[j])) {
+	    allne=0;
+	  }
+	  if (edgemaps && allsame) {
+	    igraph_vector_t *map=VECTOR(*edgemaps)[j];
+	    VECTOR(*map)[edge]=idx;
+	  }
+	}
+      }
+      if (allsame) { idx++; }
+    }
+
+  } /* while allne */
+
+  if (no_of_graphs > 0) {
+    igraph_i_union_many_free2(&order_vects);
+    igraph_i_union_many_free(&edge_vects);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  
+  igraph_vector_long_destroy(&no_edges);
+  IGRAPH_FINALLY_CLEAN(1);  
+
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); }    
+
+  return 0;
+}
+
+/**
+ * \function igraph_union
+ * \brief Calculates the union of two graphs.
+ * 
+ * </para><para>
+ * The number of vertices in the result is that of the larger graph
+ * from the two arguments. The result graph contains edges which are
+ * present in at least one of the operand graphs.
+ * 
+ * \param res Pointer to an uninitialized graph object, the result
+ *        will be stored here.
+ * \param left The first graph.
+ * \param right The second graph.
+ * \param edge_map1 Pointer to an initialized vector or a null pointer. 
+ *     If not a null pointer, it will contain a mapping from the edges 
+ *     of the first argument graph (\p left) to the edges of the
+ *     result graph. 
+ * \param edge_map2 The same as \p edge_map1, but for the second
+ *     graph, \p right.
+ * \return Error code.
+ * \sa \ref igraph_union_many() for the union of many graphs, 
+ * \ref igraph_intersection() and \ref igraph_difference() for other
+ * operators. 
+ * 
+ * Time complexity: O(|V|+|E|), |V| is the number of
+ * vertices, |E| the number of edges in the result graph.
+ * 
+ * \example examples/simple/igraph_union.c
+ */
+
+int igraph_union(igraph_t *res, 
+		 const igraph_t *left, const igraph_t *right, 
+		 igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
+  return igraph_i_merge(res, IGRAPH_MODE_UNION, left, right, 
+			edge_map1, edge_map2);
+}
+	
+/**
+ * \function igraph_union_many
+ * \brief Creates the union of many graphs.
+ * 
+ * </para><para> 
+ * The result graph will contain as many vertices as the largest graph
+ * among the arguments does, and an edge will be included in it if it
+ * is part of at least one operand graph.
+ * 
+ * </para><para>
+ * The directedness of the operand graphs must be the same.
+ * 
+ * \param res Pointer to an uninitialized graph object, this will
+ *        contain the result.
+ * \param graphs Pointer vector, contains pointers to the operands of
+ *        the union operator, graph objects of course.
+ * \param edgemaps If not a null pointer, then it must be an initialized 
+ *        pointer vector and the mappings of edges from the graphs to the 
+ *        result graph will be stored here, in the same order as 
+ *        \p graphs. Each mapping is stored in a separate 
+ *        \type igraph_vector_t object.
+ * \return Error code.
+ * \sa \ref igraph_union() for the union of two graphs, \ref
+ * igraph_intersection_many(), \ref igraph_intersection() and \ref
+ * igraph_difference for other operators.
+ * 
+ * 
+ * Time complexity: O(|V|+|E|), |V| is the number of vertices
+ * in largest graph and |E| is the number of edges in the result graph.
+ * 
+ * \example examples/simple/igraph_union.c
+ */
+
+int igraph_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs, 
+		      igraph_vector_ptr_t *edgemaps) {
+  
+  long int no_of_graphs=igraph_vector_ptr_size(graphs);
+  long int no_of_nodes=0;
+  igraph_bool_t directed=1;
+  igraph_vector_t edges;
+  igraph_vector_ptr_t edge_vects, order_vects;
+  igraph_vector_long_t no_edges;
+  long int i, j, tailfrom= no_of_graphs > 0 ? 0 : -1, tailto=-1;
+  long int idx=0;  
+  
+  /* Check directedness */
+  if (no_of_graphs != 0) {
+    directed=igraph_is_directed(VECTOR(*graphs)[0]);
+    no_of_nodes=igraph_vcount(VECTOR(*graphs)[0]);
+  }
+  for (i=1; i<no_of_graphs; i++) {
+    if (directed != igraph_is_directed(VECTOR(*graphs)[i])) {
+      IGRAPH_ERROR("Cannot union directed and undirected graphs",
+		   IGRAPH_EINVAL);
+    }
+  }
+
+  if (edgemaps) {
+    IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs));
+    igraph_vector_ptr_null(edgemaps);
+    IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges);
+
+  /* Calculate number of nodes, query number of edges */
+  for (i=0; i<no_of_graphs; i++) {
+    long int n=igraph_vcount(VECTOR(*graphs)[i]);
+    if (n > no_of_nodes) {
+      no_of_nodes=n;
+    }
+    VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]);
+  }
+
+  if (edgemaps) {
+    for (i=0; i<no_of_graphs; i++) {
+      VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t);
+      if (!VECTOR(*edgemaps)[i]) {
+	IGRAPH_ERROR("Cannot union graphs", IGRAPH_ENOMEM);
+      }
+      IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i],
+				      VECTOR(no_edges)[i]));
+    }
+  }
+
+  /* Allocate memory for the edge lists and their index vectors */
+  if (no_of_graphs != 0) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs));
+    IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects);
+    IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs));
+    IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects);
+  }
+  for (i=0; i<no_of_graphs; i++) {
+    VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t);
+    VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t);
+    if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { 
+      IGRAPH_ERROR("Cannot union graphs", IGRAPH_ENOMEM);
+    }
+    IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i],
+				    2 * VECTOR(no_edges)[i]));
+    IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], 
+					 VECTOR(no_edges)[i]));
+  }
+
+  /* Query and sort the edge lists */
+  for (i=0; i<no_of_graphs; i++) {
+    long int k, j, n=VECTOR(no_edges)[i];
+    igraph_vector_t *edges=VECTOR(edge_vects)[i];
+    igraph_vector_long_t *order=VECTOR(order_vects)[i];
+    IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0));
+    if (!directed) {
+      for (k=0, j=0; k<n; k++, j+=2) {
+	if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) {
+	  long int tmp=VECTOR(*edges)[j];
+	  VECTOR(*edges)[j]=VECTOR(*edges)[j+1];
+	  VECTOR(*edges)[j+1]=tmp;
+	}
+      }
+    }
+    for (k=0; k<n; k++) { VECTOR(*order)[k]=k; }
+    igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, 
+		   igraph_i_order_edgelist_cmp);
+  }
+
+  while (tailfrom >= 0) {
+
+    /* Get the largest tail element */
+    tailfrom = tailto = -1;
+    for (j=0; j<no_of_graphs; j++) {
+      if (!igraph_vector_long_empty(VECTOR(order_vects)[j])) {
+	long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
+	igraph_vector_t *ev=VECTOR(edge_vects)[j];
+	long int from=VECTOR(*ev)[2*edge];
+	long int to=VECTOR(*ev)[2*edge+1];
+	if (from > tailfrom || (from == tailfrom && to > tailto)) {
+	  tailfrom = from; tailto = to;
+	}
+      }
+    }
+    if (tailfrom < 0) { continue; }
+
+    /* add the edge */
+    IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom));
+    IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto));
+      
+    /* update edge lists, we just modify the 'order' vectors */
+    for (j=0; j<no_of_graphs; j++) {
+      if (!igraph_vector_long_empty(VECTOR(order_vects)[j])) {
+	long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
+	igraph_vector_t *ev=VECTOR(edge_vects)[j];
+	long int from=VECTOR(*ev)[2*edge];
+	long int to=VECTOR(*ev)[2*edge+1];
+	if (from == tailfrom && to == tailto) {
+	  igraph_vector_long_pop_back(VECTOR(order_vects)[j]);
+	  if (edgemaps) {
+	    igraph_vector_t *map=VECTOR(*edgemaps)[j];
+	    VECTOR(*map)[edge]=idx;
+	  }
+	}
+      }
+    }
+    idx++;
+
+  }
+  
+  if (no_of_graphs > 0) {
+    igraph_i_union_many_free2(&order_vects);
+    igraph_i_union_many_free(&edge_vects);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  
+  igraph_vector_long_destroy(&no_edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); }    
+
+  return 0;
+}
+
+/**
+ * \function igraph_difference
+ * \brief Calculate the difference of two graphs
+ * 
+ * </para><para>
+ * The number of vertices in the result is the number of vertices in
+ * the original graph, ie. the left, first operand. In the results
+ * graph only edges will be included from \c orig which are not
+ * present in \c sub.
+ * 
+ * \param res Pointer to an uninitialized graph object, the result
+ * will be stored here.
+ * \param orig The left operand of the operator, a graph object.
+ * \param sub The right operand of the operator, a graph object.
+ * \return Error code.
+ * \sa \ref igraph_intersection() and \ref igraph_union() for other
+ * operators.
+ * 
+ * Time complexity: O(|V|+|E|), |V| is the number vertices in
+ * the smaller graph, |E| is the
+ * number of edges in the result graph.
+ * 
+ * \example examples/simple/igraph_difference.c
+ */
+
+int igraph_difference(igraph_t *res, 
+		      const igraph_t *orig, const igraph_t *sub) {
+
+  /* Quite nasty, but we will use that an edge adjacency list
+     contains the vertices according to the order of the 
+     vertex ids at the "other" end of the edge. */
+
+  long int no_of_nodes_orig=igraph_vcount(orig);
+  long int no_of_nodes_sub =igraph_vcount(sub);
+  long int no_of_nodes=no_of_nodes_orig;
+  long int smaller_nodes;
+  igraph_bool_t directed=igraph_is_directed(orig);
+  igraph_vector_t edges;
+  igraph_vector_t edge_ids;
+  igraph_vector_t *nei1, *nei2;
+  igraph_inclist_t inc_orig, inc_sub;
+  long int i;
+  igraph_integer_t v1, v2;
+
+  if (directed != igraph_is_directed(sub)) {
+    IGRAPH_ERROR("Cannot subtract directed and undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edge_ids, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_inclist_init(orig, &inc_orig, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inc_orig);
+  IGRAPH_CHECK(igraph_inclist_init(sub, &inc_sub, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inc_sub);
+  
+  smaller_nodes=no_of_nodes_orig > no_of_nodes_sub ?
+    no_of_nodes_sub : no_of_nodes_orig;
+  
+  for (i=0; i<smaller_nodes; i++) {
+    long int n1, n2, e1, e2;
+    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;
+    while (n1>=0 && n2>=0) {
+      e1=(long int) VECTOR(*nei1)[n1];
+      e2=(long int) VECTOR(*nei2)[n2];
+      v1=IGRAPH_OTHER(orig, e1, i);
+      v2=IGRAPH_OTHER(sub, e2, i);
+      
+      if (!directed && v1<i) { 
+	n1--;
+      } else if (!directed && v2<i) {
+	n2--;
+      } else if (v1>v2) {
+	IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
+	n1--;	
+      } else if (v2>v1) {
+	n2--;
+      } else {
+	n1--;
+	n2--;
+      }
+    }
+    
+    /* Copy remaining edges */
+    while (n1>=0) {
+      e1=(long int) VECTOR(*nei1)[n1];
+      v1=IGRAPH_OTHER(orig, e1, i);
+      if (directed || v1 >= i) { 
+	IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
+      }
+      n1--;
+    }
+  }
+
+  /* copy remaining edges, use the previous value of 'i' */
+  for (; i<no_of_nodes_orig; i++) {
+    long int n1, e1;
+    nei1=igraph_inclist_get(&inc_orig, i);
+    n1=igraph_vector_size(nei1)-1;
+    while (n1>=0) {
+      e1=(long int) VECTOR(*nei1)[n1];
+      v1=IGRAPH_OTHER(orig, e1, i);
+      if (directed || v1 >= i) { 
+	IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
+      }
+      n1--;
+    }
+  }
+
+  igraph_inclist_destroy(&inc_sub);
+  igraph_inclist_destroy(&inc_orig);
+  IGRAPH_FINALLY_CLEAN(2);
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+  igraph_vector_destroy(&edges);  
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Attributes */
+  if (orig->attr) {
+    IGRAPH_I_ATTRIBUTE_DESTROY(res);
+    IGRAPH_I_ATTRIBUTE_COPY(res, orig, /*graph=*/1, /*vertex=*/1, /*edge=*/0);
+    IGRAPH_CHECK(igraph_i_attribute_permute_edges(orig, res, &edge_ids));
+  }
+  
+  igraph_vector_destroy(&edge_ids);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_complementer
+ * \brief Create the complementer of a graph
+ * 
+ * </para><para>The complementer graph means that all edges which are
+ * not part of the original graph will be included in the result.
+ * 
+ * \param res Pointer to an uninitialized graph object.
+ * \param graph The original graph.
+ * \param loops Whether to add loop edges to the complementer graph. 
+ * \return Error code.
+ * \sa \ref igraph_union(), \ref igraph_intersection() and \ref
+ * igraph_difference().
+ * 
+ * Time complexity: O(|V|+|E1|+|E2|), |V| is the number of
+ * vertices in the graph, |E1| is the number of edges in the original
+ * and |E2| in the complementer graph.
+ * 
+ * \example examples/simple/igraph_complementer.c
+ */
+
+int igraph_complementer(igraph_t *res, const igraph_t *graph, 
+			igraph_bool_t loops) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t edges;
+  igraph_vector_t neis;
+  long int i, j;
+  long int zero=0, *limit;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  if (igraph_is_directed(graph)) {
+    limit=&zero;
+  } else {
+    limit=&i;
+  }
+  
+  for (i=0; i<no_of_nodes; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, 
+				  IGRAPH_OUT));
+    if (loops) {
+      for (j=no_of_nodes-1; j>=*limit; j--) {
+	if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	  IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+	} else {
+	  igraph_vector_pop_back(&neis);
+	}
+      }
+    } else {
+      for (j=no_of_nodes-1; j>=*limit; j--) {
+	if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) {
+	  if (i!=j) {
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	    IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+	  }
+	} else {
+	  igraph_vector_pop_back(&neis);
+	}
+      }
+    }      
+  }
+  
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, 
+			     igraph_is_directed(graph)));  
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&neis);
+  IGRAPH_I_ATTRIBUTE_DESTROY(res);
+  IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/1, /*vertex=*/1, /*edge=*/0);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_compose
+ * \brief Calculates the composition of two graphs
+ * 
+ * The composition of graphs contains the same number of vertices as
+ * the bigger graph of the two operands. It contains an (i,j) edge if
+ * and only if there is a k vertex, such that the first graphs
+ * contains an (i,k) edge and the second graph a (k,j) edge. 
+ * 
+ * </para><para>This is of course exactly the composition of two
+ * binary relations.
+ *
+ * </para><para>Two two graphs must have the same directedness,
+ * otherwise the function returns with an error message.
+ * Note that for undirected graphs the two relations are by definition
+ * symmetric. 
+ * 
+ * \param res Pointer to an uninitialized graph object, the result
+ *        will be stored here.
+ * \param g1 The firs operand, a graph object.
+ * \param g2 The second operand, another graph object.
+ * \param edge_map1 If not a null pointer, then it must be a pointer
+ *        to an initialized vector, and a mapping from the edges of
+ *        the result graph to the edges of the first graph is stored
+ *        here.
+ * \param edge_map1 If not a null pointer, then it must be a pointer
+ *        to an initialized vector, and a mapping from the edges of
+ *        the result graph to the edges of the second graph is stored
+ *        here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|*d1*d2), |V| is the number of vertices in the
+ * first graph, d1 and d2 the average degree in the first and second
+ * graphs. 
+ * 
+ * \example examples/simple/igraph_compose.c
+ */
+
+int igraph_compose(igraph_t *res, const igraph_t *g1, const igraph_t *g2,
+		   igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
+  
+  long int no_of_nodes_left=igraph_vcount(g1);
+  long int no_of_nodes_right=igraph_vcount(g2);
+  long int no_of_nodes;
+  igraph_bool_t directed=igraph_is_directed(g1);
+  igraph_vector_t edges;
+  igraph_vector_t neis1, neis2;
+  long int i;
+
+  if (directed != igraph_is_directed(g2)) {
+    IGRAPH_ERROR("Cannot compose directed and undirected graph",
+		 IGRAPH_EINVAL);
+  }
+
+  no_of_nodes= no_of_nodes_left > no_of_nodes_right ? 
+    no_of_nodes_left : no_of_nodes_right;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis2, 0);
+
+  if (edge_map1) { igraph_vector_clear(edge_map1); }
+  if (edge_map2) { igraph_vector_clear(edge_map2); }
+
+  for (i=0; i<no_of_nodes_left; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    IGRAPH_CHECK(igraph_incident(g1, &neis1, (igraph_integer_t) i,
+				 IGRAPH_OUT));
+    while (!igraph_vector_empty(&neis1)) {
+      long int con=(long int) igraph_vector_pop_back(&neis1);
+      long int v1=IGRAPH_OTHER(g1, con, i);
+      if (v1 < no_of_nodes_right) {
+	IGRAPH_CHECK(igraph_incident(g2, &neis2, (igraph_integer_t) v1,
+				     IGRAPH_OUT));
+      } else {
+	continue;
+      }
+      while (!igraph_vector_empty(&neis2)) {
+	long int con2=igraph_vector_pop_back(&neis2);
+	long int v2=IGRAPH_OTHER(g2, con2, v1);
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, v2));
+	if (edge_map1) {
+	  IGRAPH_CHECK(igraph_vector_push_back(edge_map1, con));
+	}
+	if (edge_map2) {
+	  IGRAPH_CHECK(igraph_vector_push_back(edge_map2, con2));
+	}
+      }
+    }
+  }
+
+  igraph_vector_destroy(&neis1);
+  igraph_vector_destroy(&neis2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
diff --git a/src/optimal_modularity.c b/src/optimal_modularity.c
new file mode 100644
index 0000000..c7ec2ed
--- /dev/null
+++ b/src/optimal_modularity.c
@@ -0,0 +1,260 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   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_interface.h"
+#include "igraph_structural.h"
+#include "igraph_community.h"
+#include "igraph_error.h"
+#include "igraph_glpk_support.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_centrality.h"
+#include "config.h"
+
+#ifdef HAVE_GLPK
+#include <glpk.h>
+#endif
+
+/**
+ * \function igraph_community_optimal_modularity
+ * Calculate the community structure with the highest modularity value
+ * 
+ * This function calculates the optimal community structure for a
+ * graph, in terms of maximal modularity score. 
+ * 
+ * </para><para>
+ * The calculation is done by transforming the modularity maximization
+ * into an integer programming problem, and then calling the GLPK
+ * library to solve that. Please see Ulrik Brandes et al.: On
+ * Modularity Clustering, IEEE Transactions on Knowledge and Data
+ * Engineering 20(2):172-188, 2008.
+ * 
+ * </para><para>
+ * 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.
+ * 
+ * \param graph The input graph. It is always treated as undirected.
+ * \param modularity Pointer to a real number, or a null pointer.
+ *        If it is not a null pointer, then a optimal modularity value 
+ *        is returned here.
+ * \param membership Pointer to a vector, or a null pointer. If not a
+ *        null pointer, then the membership vector of the optimal
+ *        community structure is stored here.
+ * \param weights Vector giving the weights of the edges. If it is
+ *        \c NULL then each edge is supposed to have the same weight.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_modularity(), \ref igraph_community_fastgreedy()
+ * for an algorithm that finds a local optimum in a greedy way. 
+ * 
+ * Time complexity: exponential in the number of vertices.
+ * 
+ * \example examples/simple/igraph_community_optimal_modularity.c
+ */
+
+int igraph_community_optimal_modularity(const igraph_t *graph,
+					igraph_real_t *modularity,
+					igraph_vector_t *membership,
+					const igraph_vector_t *weights) {
+
+#ifndef HAVE_GLPK
+  IGRAPH_ERROR("GLPK is not available", 
+	       IGRAPH_UNIMPLEMENTED);    
+#else
+
+  igraph_integer_t no_of_nodes=(igraph_integer_t) igraph_vcount(graph);
+  igraph_integer_t no_of_edges=(igraph_integer_t) igraph_ecount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  int no_of_variables=no_of_nodes * (no_of_nodes+1)/2;
+  int i, j, k, l, st;
+  int idx[] = { 0, 0, 0, 0 };
+  double coef[] = { 0.0, 1.0, 1.0, -2.0 };
+  igraph_real_t total_weight;
+  igraph_vector_t indegree;
+  igraph_vector_t outdegree;
+
+  glp_prob *ip;
+  glp_iocp parm;
+
+  if (weights != 0) {
+    if (igraph_vector_size(weights) != no_of_edges) {
+      IGRAPH_ERROR("Invalid length of weight vector", IGRAPH_EINVAL);
+    }
+    if (igraph_vector_min(weights) < 0) {
+      IGRAPH_ERROR("Negative weights are not allowed in weight vector", IGRAPH_EINVAL);
+    }
+  }
+
+  if (weights) {
+    total_weight = igraph_vector_sum(weights);
+  } else {
+    total_weight = no_of_edges;
+  }
+  if (!directed) {
+    total_weight *= 2;
+  }
+
+  /* Special case */
+  if (no_of_edges == 0 || total_weight == 0) {
+    if (modularity) {
+      *modularity=IGRAPH_NAN;
+    }
+    if (membership) {
+      IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+      igraph_vector_null(membership);
+    }
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdegree, no_of_nodes);
+  IGRAPH_CHECK(igraph_strength(graph, &indegree, igraph_vss_all(), 
+			     IGRAPH_IN, IGRAPH_LOOPS, weights));
+  IGRAPH_CHECK(igraph_strength(graph, &outdegree, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS, weights));
+
+  glp_term_out(GLP_OFF);
+  ip = glp_create_prob();
+  IGRAPH_FINALLY(glp_delete_prob, ip);
+
+  glp_set_obj_dir(ip, GLP_MAX);
+  st=glp_add_cols(ip, no_of_variables);
+
+  /* variables are binary */
+  for (i=0; i<no_of_variables; i++) {
+    glp_set_col_kind(ip, (st+i), GLP_BV);
+  }
+
+#define IDX(a,b) ((b)*((b)+1)/2+(a))
+
+  /* reflexivity */
+  for (i=0; i<no_of_nodes; i++) {
+    glp_set_col_bnds(ip, (st+IDX(i,i)), GLP_FX, 1.0, 1.0);
+  }
+  
+  /* transitivity */
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i+1; j<no_of_nodes; j++) {
+
+      IGRAPH_ALLOW_INTERRUPTION();
+
+      for (k=j+1; k<no_of_nodes; k++) {
+	int newrow=glp_add_rows(ip, 3);
+
+	glp_set_row_bnds(ip, newrow, GLP_UP, 0.0, 1.0);
+	idx[1] = (st+IDX(i,j)); idx[2] = (st+IDX(j,k)); 
+	idx[3] = (st+IDX(i,k));
+	glp_set_mat_row(ip, newrow, 3, idx, coef);
+
+	glp_set_row_bnds(ip, newrow+1, GLP_UP, 0.0, 1.0);
+	idx[1] = st+IDX(i,j); idx[2] = st+IDX(i,k); idx[3] = st+IDX(j,k);
+	glp_set_mat_row(ip, newrow+1, 3, idx, coef);
+
+	glp_set_row_bnds(ip, newrow+2, GLP_UP, 0.0, 1.0);
+	idx[1] = st+IDX(i,k); idx[2] = st+IDX(j,k); idx[3] = st+IDX(i,j);
+	glp_set_mat_row(ip, newrow+2, 3, idx, coef);
+
+      }
+    }
+  }
+
+  /* objective function */
+  {
+    igraph_real_t c;
+
+    /* first part: -strength(i)*strength(j)/total_weight for every node pair */
+    for (i=0; i<no_of_nodes; i++) {
+      for (j=i+1; j<no_of_nodes; j++) {
+	c = -VECTOR(indegree)[i]*VECTOR(outdegree)[j] / total_weight \
+	    -VECTOR(outdegree)[i]*VECTOR(indegree)[j] / total_weight;
+	glp_set_obj_coef(ip, st+IDX(i,j), c);
+      }
+      /* special case for (i,i) */
+      c = -VECTOR(indegree)[i]*VECTOR(outdegree)[i] / total_weight;
+      glp_set_obj_coef(ip, st+IDX(i,i), c);
+    }
+
+    /* second part: add the weighted adjacency matrix to the coefficient matrix */
+    for (k=0; k<no_of_edges; k++) {
+      i = IGRAPH_FROM(graph, k);
+      j = IGRAPH_TO(graph, k);
+      if (i > j) {
+	l = i; i = j; j = l;
+      }
+      c = weights ? VECTOR(*weights)[k] : 1.0;
+      if (!directed || i == j) {
+	c *= 2.0;
+      }
+      glp_set_obj_coef(ip, st+IDX(i,j), c + glp_get_obj_coef(ip, st+IDX(i,j)));
+    }
+  }
+
+  /* solve it */
+  glp_init_iocp(&parm);
+  parm.br_tech = GLP_BR_DTH;
+  parm.bt_tech = GLP_BT_BLB;
+  parm.presolve = GLP_ON;
+  parm.binarize = GLP_ON;
+  parm.cb_func = igraph_i_glpk_interruption_hook;
+  IGRAPH_GLPK_CHECK(glp_intopt(ip, &parm), "Modularity optimization failed");
+  
+  /* store the results */
+  if (modularity) {
+    *modularity = glp_mip_obj_val(ip) / total_weight;
+  }
+  
+  if (membership) {
+    long int comm=0;	 /* id of the last community that was found */
+    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+    for (i=0; i<no_of_nodes; i++) {
+      
+      IGRAPH_ALLOW_INTERRUPTION();
+      
+      for (j=0; j<i; j++) {
+	int val=(int) glp_mip_col_val(ip, st+IDX(j,i));
+	if (val==1) {
+	  VECTOR(*membership)[i]=VECTOR(*membership)[j];
+	  break;
+	}
+      }
+      if (j==i) {		/* new community */
+	VECTOR(*membership)[i]=comm++;
+      }
+    }
+  }
+  
+#undef IDX
+
+  igraph_vector_destroy(&indegree);
+  igraph_vector_destroy(&outdegree);
+  glp_delete_prob(ip);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+  
+#endif
+
+}
+
diff --git a/src/other.c b/src/other.c
new file mode 100644
index 0000000..8b13abe
--- /dev/null
+++ b/src/other.c
@@ -0,0 +1,417 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_nongraph.h"
+#include "igraph_types.h"
+#include "igraph_memory.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+#include "plfit/error.h"
+#include "plfit/plfit.h"
+#include <math.h>
+#include <stdarg.h>
+#include <string.h>
+
+/**
+ * \ingroup nongraph
+ * \function igraph_running_mean
+ * \brief Calculates the running mean of a vector.
+ * 
+ * </para><para>
+ * The running mean is defined by the mean of the
+ * previous \p binwidth values.
+ * \param data The vector containing the data.
+ * \param res The vector containing the result. This should be
+ *        initialized before calling this function and will be
+ *        resized. 
+ * \param binwidth Integer giving the width of the bin for the running
+ *        mean calculation.
+ * \return Error code.
+ * 
+ * Time complexity: O(n),
+ * n is the length of
+ * the data vector.
+ */
+
+int igraph_running_mean(const igraph_vector_t *data, igraph_vector_t *res, 
+			igraph_integer_t binwidth) {
+
+  double sum=0;
+  long int i;
+
+  /* Check */
+  if (igraph_vector_size(data) < binwidth) {
+    IGRAPH_ERROR("Vector too short for this binwidth", IGRAPH_EINVAL); 
+  }
+
+  /* Memory for result */
+
+  IGRAPH_CHECK(igraph_vector_resize(res, (long int)(igraph_vector_size(data)-binwidth+1)));
+  
+  /* Initial bin */
+  for (i=0; i<binwidth; i++) {
+    sum += VECTOR(*data)[i];
+  }
+  
+  VECTOR(*res)[0]=sum/binwidth;
+  
+  for (i=1; i<igraph_vector_size(data)-binwidth+1; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    sum -= VECTOR(*data)[i-1];
+    sum += VECTOR(*data)[ (long int)(i+binwidth-1)];
+    VECTOR(*res)[i] = sum/binwidth;
+  }
+  
+  return 0;
+}
+
+
+/**
+ * \ingroup nongraph
+ * \function igraph_convex_hull
+ * \brief Determines the convex hull of a given set of points in the 2D plane
+ *
+ * </para><para>
+ * The convex hull is determined by the Graham scan algorithm.
+ * See the following reference for details:
+ * 
+ * </para><para>
+ * 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.
+ * 
+ * \param data vector containing the coordinates. The length of the
+ *        vector must be even, since it contains X-Y coordinate pairs.
+ * \param resverts the vector containing the result, e.g. the vector of
+ *        vertex indices used as the corners of the convex hull. Supply
+ *        \c NULL here if you are only interested in the coordinates of
+ *        the convex hull corners.
+ * \param rescoords the matrix containing the coordinates of the selected
+ *        corner vertices. Supply \c NULL here if you are only interested in
+ *        the vertex indices.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM: not enough memory
+ * 
+ * Time complexity: O(n log(n)) where n is the number of vertices
+ * 
+ * \example examples/simple/igraph_convex_hull.c
+ */
+int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts,
+		       igraph_matrix_t *rescoords) {
+  igraph_integer_t no_of_nodes;
+  long int i, pivot_idx=0, last_idx, before_last_idx, next_idx, j;
+  igraph_real_t* angles;
+  igraph_vector_t stack;
+  igraph_indheap_t order;
+  igraph_real_t px, py, cp;
+  
+  no_of_nodes=(igraph_integer_t) igraph_matrix_nrow(data);
+  if (igraph_matrix_ncol(data) != 2) {
+    IGRAPH_ERROR("matrix must have 2 columns", IGRAPH_EINVAL);
+  }
+  if (no_of_nodes == 0) {
+    if (resverts != 0) {
+      IGRAPH_CHECK(igraph_vector_resize(resverts, 0));
+    } 
+    if (rescoords != 0) {
+      IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2));
+    }
+    /**************************** this is an exit here *********/
+    return 0;
+  }
+    
+  angles=igraph_Calloc(no_of_nodes, igraph_real_t);
+  if (!angles) IGRAPH_ERROR("not enough memory for angle array", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(free, angles);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&stack, 0);
+  
+  /* Search for the pivot vertex */
+  for (i=1; i<no_of_nodes; i++) {
+    if (MATRIX(*data, i, 1)<MATRIX(*data, pivot_idx, 1))
+      pivot_idx=i;
+    else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) &&
+	     MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0))
+      pivot_idx=i;
+  }
+  px=MATRIX(*data, pivot_idx, 0);
+  py=MATRIX(*data, pivot_idx, 1);
+  
+  /* Create angle array */
+  for (i=0; i<no_of_nodes; i++) {
+    if (i == pivot_idx) {
+      /* We can't calculate the angle of the pivot point with itself,
+       * so we use 10 here. This way, after sorting the angle vector,
+       * the pivot point will always be the first one, since the range
+       * of atan2 is -3.14..3.14 */
+      angles[i] = 10;
+    } else {
+      angles[i] = atan2(MATRIX(*data, i, 1)-py,
+			MATRIX(*data, i, 0)-px);
+    }
+  }
+
+  IGRAPH_CHECK(igraph_indheap_init_array(&order, angles, no_of_nodes));
+  IGRAPH_FINALLY(igraph_indheap_destroy, &order);
+  
+  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);
+      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++;
+      }
+    }
+  }
+  
+  /* Create result vector */
+  if (resverts != 0) {
+    igraph_vector_clear(resverts);
+    IGRAPH_CHECK(igraph_vector_append(resverts, &stack));
+  } 
+  if (rescoords != 0) {
+    igraph_matrix_select_rows(data, rescoords, &stack);
+  }
+  
+  /* Free everything */
+  igraph_vector_destroy(&stack);
+  igraph_indheap_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+
+static const char* igraph_i_plfit_error_message = 0;
+
+static void igraph_i_plfit_error_handler_store(const char *reason, const char *file,
+    int line, int plfit_errno) {
+  igraph_i_plfit_error_message = reason;
+}
+
+/**
+ * \ingroup nongraph
+ * \function igraph_power_law_fit
+ * \brief Fits a power-law distribution to a vector of numbers
+ *
+ * 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 P(X=x) is
+ * proportional to x<superscript>-alpha</superscript>, where x is a positive number and alpha
+ * is greater than 1. In many real-world cases, the power-law behaviour kicks
+ * in only above a threshold value \em xmin. The goal of this functions is to
+ * determine \em alpha if \em xmin is given, or to determine \em xmin and the
+ * corresponding value of \em alpha.
+ *
+ * </para><para>
+ * The function uses the maximum likelihood principle to determine \em alpha
+ * for a given \em xmin; in other words, the function will return the \em alpha
+ * value for which the probability of drawing the given sample is the highest.
+ * When \em xmin is not given in advance, the algorithm will attempt to find
+ * the optimal \em xmin value for which the 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 the following reference for
+ * details:
+ *
+ * </para><para>
+ * Aaron Clauset, Cosma R .Shalizi and Mark E.J. Newman: Power-law
+ * distributions in empirical data. SIAM Review 51(4):661-703, 2009.
+ *
+ * \param data vector containing the samples for which a power-law distribution
+ *             is to be fitted. Note that you have to provide the \em samples,
+ *             not the probability density function or the cumulative
+ *             distribution function. For example, if you wish to fit
+ *             a power-law to the degrees of a graph, you can use the output of
+ *             \ref igraph_degree directly as an input argument to
+ *             \ref igraph_power_law_fit
+ * \param result the result of the fitting algorithm. See \ref igraph_plfit_result_t
+ *             for more details.
+ * \param xmin the minimum value in the sample vector where the power-law
+ *             behaviour is expected to kick in. Samples smaller than \c xmin
+ *             will be ignored by the algoritm. Pass zero here if you want to
+ *             include all the samples. If \c xmin is negative, the algorithm
+ *             will attempt to determine its best value automatically.
+ * \param force_continuous assume that the samples in the \c data argument come
+ *             from a continuous distribution 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.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM: not enough memory
+ *         \c IGRAPH_EINVAL: one of the arguments is invalid
+ *         \c IGRAPH_EOVERFLOW: overflow during the fitting process
+ *         \c IGRAPH_EUNDERFLOW: underflow during the fitting process
+ *         \c IGRAPH_FAILURE: the underlying algorithm signaled a failure
+ *         without returning a more specific error code
+ * 
+ * Time complexity: in the continuous case, O(n log(n)) if \c xmin is given.
+ * In the discrete case, the time complexity is dominated by the complexity of
+ * the underlying L-BFGS algorithm that is used to optimize alpha. If \c xmin
+ * is not given, the time complexity is multiplied by the number of unique
+ * samples in the input vector (although it should be faster in practice).
+ * 
+ * \example examples/simple/igraph_power_law_fit.c
+ */
+int igraph_power_law_fit(const igraph_vector_t* data, igraph_plfit_result_t* result,
+	igraph_real_t xmin, igraph_bool_t force_continuous) {
+  plfit_error_handler_t* plfit_stored_error_handler;
+  plfit_result_t plfit_result;
+  plfit_continuous_options_t cont_options;
+  plfit_discrete_options_t disc_options;
+  igraph_bool_t discrete = force_continuous ? 0 : 1;
+  igraph_bool_t finite_size_correction;
+  int retval;
+  size_t i, n;
+
+  n = (size_t) igraph_vector_size(data);
+  finite_size_correction = (n < 50);
+
+  if (discrete) {
+    /* Does the vector contain discrete values only? */
+    for (i = 0; i < n; i++) {
+      if ((long int)(VECTOR(*data)[i]) != VECTOR(*data)[i]) {
+	discrete = 0;
+	break;
+      }
+    }
+  }
+
+  plfit_stored_error_handler = plfit_set_error_handler(igraph_i_plfit_error_handler_store);
+  if (discrete) {
+    plfit_discrete_options_init(&disc_options);
+    disc_options.finite_size_correction = (plfit_bool_t) finite_size_correction;
+
+    if (xmin >= 0) {
+      retval = plfit_estimate_alpha_discrete(VECTOR(*data), n, xmin,
+	  &disc_options, &plfit_result);
+    } else {
+      retval = plfit_discrete(VECTOR(*data), n, &disc_options, &plfit_result);
+    }
+  } else {
+    plfit_continuous_options_init(&cont_options);
+    cont_options.finite_size_correction = (plfit_bool_t) finite_size_correction;
+
+    if (xmin >= 0) {
+      retval = plfit_estimate_alpha_continuous(VECTOR(*data), n, xmin,
+	  &cont_options, &plfit_result);
+    } else {
+      retval = plfit_continuous(VECTOR(*data), n, &cont_options, &plfit_result);
+    }
+  }
+  plfit_set_error_handler(plfit_stored_error_handler);
+
+  switch (retval) {
+    case PLFIT_FAILURE:
+      IGRAPH_ERROR(igraph_i_plfit_error_message, IGRAPH_FAILURE);
+      break;
+
+    case PLFIT_EINVAL:
+      IGRAPH_ERROR(igraph_i_plfit_error_message, IGRAPH_EINVAL);
+      break;
+
+    case PLFIT_UNDRFLOW:
+      IGRAPH_ERROR(igraph_i_plfit_error_message, IGRAPH_EUNDERFLOW);
+      break;
+
+    case PLFIT_OVERFLOW:
+      IGRAPH_ERROR(igraph_i_plfit_error_message, IGRAPH_EOVERFLOW);
+      break;
+
+    case PLFIT_ENOMEM:
+      IGRAPH_ERROR(igraph_i_plfit_error_message, IGRAPH_ENOMEM);
+      break;
+
+    default:
+      break;
+  }
+
+  if (result) {
+    result->continuous = !discrete;
+    result->alpha = plfit_result.alpha;
+    result->xmin = plfit_result.xmin;
+    result->L = plfit_result.L;
+    result->D = plfit_result.D;
+    result->p = plfit_result.p;
+  }
+
+  return 0;
+}
+
+/**
+ * Internal function, floating point division
+ * Used only in compilers not supporting INFINITY and HUGE_VAL to create
+ * infinity values
+ */
+double igraph_i_fdiv(const double a, const double b) 
+{
+   return a / b;
+}
diff --git a/src/plfit/arithmetic_ansi.h b/src/plfit/arithmetic_ansi.h
new file mode 100644
index 0000000..c58c98a
--- /dev/null
+++ b/src/plfit/arithmetic_ansi.h
@@ -0,0 +1,133 @@
+/*
+ *      ANSI C implementation of vector operations.
+ *
+ * Copyright (c) 2007-2010 Naoaki Okazaki
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* $Id: arithmetic_ansi.h 65 2010-01-29 12:19:16Z naoaki $ */
+
+#include <stdlib.h>
+#include <memory.h>
+
+#if     LBFGS_FLOAT == 32 && LBFGS_IEEE_FLOAT
+#define fsigndiff(x, y) (((*(uint32_t*)(x)) ^ (*(uint32_t*)(y))) & 0x80000000U)
+#else
+#define fsigndiff(x, y) (*(x) * (*(y) / fabs(*(y))) < 0.)
+#endif/*LBFGS_IEEE_FLOAT*/
+
+inline static void* vecalloc(size_t size)
+{
+    void *memblock = malloc(size);
+    if (memblock) {
+        memset(memblock, 0, size);
+    }
+    return memblock;
+}
+
+inline static void vecfree(void *memblock)
+{
+    free(memblock);
+}
+
+inline static void vecset(lbfgsfloatval_t *x, const lbfgsfloatval_t c, const int n)
+{
+    int i;
+    
+    for (i = 0;i < n;++i) {
+        x[i] = c;
+    }
+}
+
+inline static void veccpy(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const int n)
+{
+    int i;
+
+    for (i = 0;i < n;++i) {
+        y[i] = x[i];
+    }
+}
+
+inline static void vecncpy(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const int n)
+{
+    int i;
+
+    for (i = 0;i < n;++i) {
+        y[i] = -x[i];
+    }
+}
+
+inline static void vecadd(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const lbfgsfloatval_t c, const int n)
+{
+    int i;
+
+    for (i = 0;i < n;++i) {
+        y[i] += c * x[i];
+    }
+}
+
+inline static void vecdiff(lbfgsfloatval_t *z, const lbfgsfloatval_t *x, const lbfgsfloatval_t *y, const int n)
+{
+    int i;
+
+    for (i = 0;i < n;++i) {
+        z[i] = x[i] - y[i];
+    }
+}
+
+inline static void vecscale(lbfgsfloatval_t *y, const lbfgsfloatval_t c, const int n)
+{
+    int i;
+
+    for (i = 0;i < n;++i) {
+        y[i] *= c;
+    }
+}
+
+inline static void vecmul(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const int n)
+{
+    int i;
+
+    for (i = 0;i < n;++i) {
+        y[i] *= x[i];
+    }
+}
+
+inline static void vecdot(lbfgsfloatval_t* s, const lbfgsfloatval_t *x, const lbfgsfloatval_t *y, const int n)
+{
+    int i;
+    *s = 0.;
+    for (i = 0;i < n;++i) {
+        *s += x[i] * y[i];
+    }
+}
+
+inline static void vec2norm(lbfgsfloatval_t* s, const lbfgsfloatval_t *x, const int n)
+{
+    vecdot(s, x, x, n);
+    *s = (lbfgsfloatval_t)sqrt(*s);
+}
+
+inline static void vec2norminv(lbfgsfloatval_t* s, const lbfgsfloatval_t *x, const int n)
+{
+    vec2norm(s, x, n);
+    *s = (lbfgsfloatval_t)(1.0 / *s);
+}
diff --git a/src/plfit/arithmetic_sse_double.h b/src/plfit/arithmetic_sse_double.h
new file mode 100644
index 0000000..a94d89d
--- /dev/null
+++ b/src/plfit/arithmetic_sse_double.h
@@ -0,0 +1,294 @@
+/*
+ *      SSE2 implementation of vector oprations (64bit double).
+ *
+ * Copyright (c) 2007-2010 Naoaki Okazaki
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* $Id: arithmetic_sse_double.h 65 2010-01-29 12:19:16Z naoaki $ */
+
+#include <stdlib.h>
+
+#if !defined(__APPLE__)
+#include <malloc.h>
+#endif
+
+#include <memory.h>
+
+#if     1400 <= _MSC_VER
+#include <intrin.h>
+#endif/*1400 <= _MSC_VER*/
+
+#if     HAVE_EMMINTRIN_H
+#include <emmintrin.h>
+#endif/*HAVE_EMMINTRIN_H*/
+
+inline static void* vecalloc(size_t size)
+{
+#ifdef	_MSC_VER
+    void *memblock = _aligned_malloc(size, 16);
+#elif defined(__APPLE__)
+	/* Memory on Mac OS X is already aligned to 16 bytes */
+	void *memblock = malloc(size);
+#else
+    void *memblock = memalign(16, size);
+#endif
+    if (memblock != NULL) {
+        memset(memblock, 0, size);
+    }
+    return memblock;
+}
+
+inline static void vecfree(void *memblock)
+{
+#ifdef	_MSC_VER
+    _aligned_free(memblock);
+#else
+    free(memblock);
+#endif
+}
+
+#define fsigndiff(x, y) \
+    ((_mm_movemask_pd(_mm_set_pd(*(x), *(y))) + 1) & 0x002)
+
+#define vecset(x, c, n) \
+{ \
+    int i; \
+    __m128d XMM0 = _mm_set1_pd(c); \
+    for (i = 0;i < (n);i += 8) { \
+        _mm_store_pd((x)+i  , XMM0); \
+        _mm_store_pd((x)+i+2, XMM0); \
+        _mm_store_pd((x)+i+4, XMM0); \
+        _mm_store_pd((x)+i+6, XMM0); \
+    } \
+}
+
+#define veccpy(y, x, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 8) { \
+        __m128d XMM0 = _mm_load_pd((x)+i  ); \
+        __m128d XMM1 = _mm_load_pd((x)+i+2); \
+        __m128d XMM2 = _mm_load_pd((x)+i+4); \
+        __m128d XMM3 = _mm_load_pd((x)+i+6); \
+        _mm_store_pd((y)+i  , XMM0); \
+        _mm_store_pd((y)+i+2, XMM1); \
+        _mm_store_pd((y)+i+4, XMM2); \
+        _mm_store_pd((y)+i+6, XMM3); \
+    } \
+}
+
+#define vecncpy(y, x, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 8) { \
+        __m128d XMM0 = _mm_setzero_pd(); \
+        __m128d XMM1 = _mm_setzero_pd(); \
+        __m128d XMM2 = _mm_setzero_pd(); \
+        __m128d XMM3 = _mm_setzero_pd(); \
+        __m128d XMM4 = _mm_load_pd((x)+i  ); \
+        __m128d XMM5 = _mm_load_pd((x)+i+2); \
+        __m128d XMM6 = _mm_load_pd((x)+i+4); \
+        __m128d XMM7 = _mm_load_pd((x)+i+6); \
+        XMM0 = _mm_sub_pd(XMM0, XMM4); \
+        XMM1 = _mm_sub_pd(XMM1, XMM5); \
+        XMM2 = _mm_sub_pd(XMM2, XMM6); \
+        XMM3 = _mm_sub_pd(XMM3, XMM7); \
+        _mm_store_pd((y)+i  , XMM0); \
+        _mm_store_pd((y)+i+2, XMM1); \
+        _mm_store_pd((y)+i+4, XMM2); \
+        _mm_store_pd((y)+i+6, XMM3); \
+    } \
+}
+
+#define vecadd(y, x, c, n) \
+{ \
+    int i; \
+    __m128d XMM7 = _mm_set1_pd(c); \
+    for (i = 0;i < (n);i += 4) { \
+        __m128d XMM0 = _mm_load_pd((x)+i  ); \
+        __m128d XMM1 = _mm_load_pd((x)+i+2); \
+        __m128d XMM2 = _mm_load_pd((y)+i  ); \
+        __m128d XMM3 = _mm_load_pd((y)+i+2); \
+        XMM0 = _mm_mul_pd(XMM0, XMM7); \
+        XMM1 = _mm_mul_pd(XMM1, XMM7); \
+        XMM2 = _mm_add_pd(XMM2, XMM0); \
+        XMM3 = _mm_add_pd(XMM3, XMM1); \
+        _mm_store_pd((y)+i  , XMM2); \
+        _mm_store_pd((y)+i+2, XMM3); \
+    } \
+}
+
+#define vecdiff(z, x, y, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 8) { \
+        __m128d XMM0 = _mm_load_pd((x)+i  ); \
+        __m128d XMM1 = _mm_load_pd((x)+i+2); \
+        __m128d XMM2 = _mm_load_pd((x)+i+4); \
+        __m128d XMM3 = _mm_load_pd((x)+i+6); \
+        __m128d XMM4 = _mm_load_pd((y)+i  ); \
+        __m128d XMM5 = _mm_load_pd((y)+i+2); \
+        __m128d XMM6 = _mm_load_pd((y)+i+4); \
+        __m128d XMM7 = _mm_load_pd((y)+i+6); \
+        XMM0 = _mm_sub_pd(XMM0, XMM4); \
+        XMM1 = _mm_sub_pd(XMM1, XMM5); \
+        XMM2 = _mm_sub_pd(XMM2, XMM6); \
+        XMM3 = _mm_sub_pd(XMM3, XMM7); \
+        _mm_store_pd((z)+i  , XMM0); \
+        _mm_store_pd((z)+i+2, XMM1); \
+        _mm_store_pd((z)+i+4, XMM2); \
+        _mm_store_pd((z)+i+6, XMM3); \
+    } \
+}
+
+#define vecscale(y, c, n) \
+{ \
+    int i; \
+    __m128d XMM7 = _mm_set1_pd(c); \
+    for (i = 0;i < (n);i += 4) { \
+        __m128d XMM0 = _mm_load_pd((y)+i  ); \
+        __m128d XMM1 = _mm_load_pd((y)+i+2); \
+        XMM0 = _mm_mul_pd(XMM0, XMM7); \
+        XMM1 = _mm_mul_pd(XMM1, XMM7); \
+        _mm_store_pd((y)+i  , XMM0); \
+        _mm_store_pd((y)+i+2, XMM1); \
+    } \
+}
+
+#define vecmul(y, x, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 8) { \
+        __m128d XMM0 = _mm_load_pd((x)+i  ); \
+        __m128d XMM1 = _mm_load_pd((x)+i+2); \
+        __m128d XMM2 = _mm_load_pd((x)+i+4); \
+        __m128d XMM3 = _mm_load_pd((x)+i+6); \
+        __m128d XMM4 = _mm_load_pd((y)+i  ); \
+        __m128d XMM5 = _mm_load_pd((y)+i+2); \
+        __m128d XMM6 = _mm_load_pd((y)+i+4); \
+        __m128d XMM7 = _mm_load_pd((y)+i+6); \
+        XMM4 = _mm_mul_pd(XMM4, XMM0); \
+        XMM5 = _mm_mul_pd(XMM5, XMM1); \
+        XMM6 = _mm_mul_pd(XMM6, XMM2); \
+        XMM7 = _mm_mul_pd(XMM7, XMM3); \
+        _mm_store_pd((y)+i  , XMM4); \
+        _mm_store_pd((y)+i+2, XMM5); \
+        _mm_store_pd((y)+i+4, XMM6); \
+        _mm_store_pd((y)+i+6, XMM7); \
+    } \
+}
+
+
+
+#if     3 <= __SSE__
+/*
+    Horizontal add with haddps SSE3 instruction. The work register (rw)
+    is unused.
+ */
+#define __horizontal_sum(r, rw) \
+    r = _mm_hadd_ps(r, r); \
+    r = _mm_hadd_ps(r, r);
+
+#else
+/*
+    Horizontal add with SSE instruction. The work register (rw) is used.
+ */
+#define __horizontal_sum(r, rw) \
+    rw = r; \
+    r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(1, 0, 3, 2)); \
+    r = _mm_add_ps(r, rw); \
+    rw = r; \
+    r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(2, 3, 0, 1)); \
+    r = _mm_add_ps(r, rw);
+
+#endif
+
+#define vecdot(s, x, y, n) \
+{ \
+    int i; \
+    __m128d XMM0 = _mm_setzero_pd(); \
+    __m128d XMM1 = _mm_setzero_pd(); \
+    __m128d XMM2, XMM3, XMM4, XMM5; \
+    for (i = 0;i < (n);i += 4) { \
+        XMM2 = _mm_load_pd((x)+i  ); \
+        XMM3 = _mm_load_pd((x)+i+2); \
+        XMM4 = _mm_load_pd((y)+i  ); \
+        XMM5 = _mm_load_pd((y)+i+2); \
+        XMM2 = _mm_mul_pd(XMM2, XMM4); \
+        XMM3 = _mm_mul_pd(XMM3, XMM5); \
+        XMM0 = _mm_add_pd(XMM0, XMM2); \
+        XMM1 = _mm_add_pd(XMM1, XMM3); \
+    } \
+    XMM0 = _mm_add_pd(XMM0, XMM1); \
+    XMM1 = _mm_shuffle_pd(XMM0, XMM0, _MM_SHUFFLE2(1, 1)); \
+    XMM0 = _mm_add_pd(XMM0, XMM1); \
+    _mm_store_sd((s), XMM0); \
+}
+
+#define vec2norm(s, x, n) \
+{ \
+    int i; \
+    __m128d XMM0 = _mm_setzero_pd(); \
+    __m128d XMM1 = _mm_setzero_pd(); \
+    __m128d XMM2, XMM3, XMM4, XMM5; \
+    for (i = 0;i < (n);i += 4) { \
+        XMM2 = _mm_load_pd((x)+i  ); \
+        XMM3 = _mm_load_pd((x)+i+2); \
+        XMM4 = XMM2; \
+        XMM5 = XMM3; \
+        XMM2 = _mm_mul_pd(XMM2, XMM4); \
+        XMM3 = _mm_mul_pd(XMM3, XMM5); \
+        XMM0 = _mm_add_pd(XMM0, XMM2); \
+        XMM1 = _mm_add_pd(XMM1, XMM3); \
+    } \
+    XMM0 = _mm_add_pd(XMM0, XMM1); \
+    XMM1 = _mm_shuffle_pd(XMM0, XMM0, _MM_SHUFFLE2(1, 1)); \
+    XMM0 = _mm_add_pd(XMM0, XMM1); \
+    XMM0 = _mm_sqrt_pd(XMM0); \
+    _mm_store_sd((s), XMM0); \
+}
+
+
+#define vec2norminv(s, x, n) \
+{ \
+    int i; \
+    __m128d XMM0 = _mm_setzero_pd(); \
+    __m128d XMM1 = _mm_setzero_pd(); \
+    __m128d XMM2, XMM3, XMM4, XMM5; \
+    for (i = 0;i < (n);i += 4) { \
+        XMM2 = _mm_load_pd((x)+i  ); \
+        XMM3 = _mm_load_pd((x)+i+2); \
+        XMM4 = XMM2; \
+        XMM5 = XMM3; \
+        XMM2 = _mm_mul_pd(XMM2, XMM4); \
+        XMM3 = _mm_mul_pd(XMM3, XMM5); \
+        XMM0 = _mm_add_pd(XMM0, XMM2); \
+        XMM1 = _mm_add_pd(XMM1, XMM3); \
+    } \
+    XMM2 = _mm_set1_pd(1.0); \
+    XMM0 = _mm_add_pd(XMM0, XMM1); \
+    XMM1 = _mm_shuffle_pd(XMM0, XMM0, _MM_SHUFFLE2(1, 1)); \
+    XMM0 = _mm_add_pd(XMM0, XMM1); \
+    XMM0 = _mm_sqrt_pd(XMM0); \
+    XMM2 = _mm_div_pd(XMM2, XMM0); \
+    _mm_store_sd((s), XMM2); \
+}
diff --git a/src/plfit/arithmetic_sse_float.h b/src/plfit/arithmetic_sse_float.h
new file mode 100644
index 0000000..b88f0e2
--- /dev/null
+++ b/src/plfit/arithmetic_sse_float.h
@@ -0,0 +1,291 @@
+/*
+ *      SSE/SSE3 implementation of vector oprations (32bit float).
+ *
+ * Copyright (c) 2007-2010 Naoaki Okazaki
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* $Id: arithmetic_sse_float.h 65 2010-01-29 12:19:16Z naoaki $ */
+
+#include <stdlib.h>
+
+#if !defined(__APPLE__)
+#include <malloc.h>
+#endif
+
+#include <memory.h>
+
+#if     1400 <= _MSC_VER
+#include <intrin.h>
+#endif/*_MSC_VER*/
+
+#if     HAVE_XMMINTRIN_H
+#include <xmmintrin.h>
+#endif/*HAVE_XMMINTRIN_H*/
+
+#if     LBFGS_FLOAT == 32 && LBFGS_IEEE_FLOAT
+#define fsigndiff(x, y) (((*(uint32_t*)(x)) ^ (*(uint32_t*)(y))) & 0x80000000U)
+#else
+#define fsigndiff(x, y) (*(x) * (*(y) / fabs(*(y))) < 0.)
+#endif/*LBFGS_IEEE_FLOAT*/
+
+inline static void* vecalloc(size_t size)
+{
+    void *memblock = _aligned_malloc(size, 16);
+    if (memblock != NULL) {
+        memset(memblock, 0, size);
+    }
+    return memblock;
+}
+
+inline static void vecfree(void *memblock)
+{
+    _aligned_free(memblock);
+}
+
+#define vecset(x, c, n) \
+{ \
+    int i; \
+    __m128 XMM0 = _mm_set_ps1(c); \
+    for (i = 0;i < (n);i += 16) { \
+        _mm_store_ps((x)+i   , XMM0); \
+        _mm_store_ps((x)+i+ 4, XMM0); \
+        _mm_store_ps((x)+i+ 8, XMM0); \
+        _mm_store_ps((x)+i+12, XMM0); \
+    } \
+}
+
+#define veccpy(y, x, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 16) { \
+        __m128 XMM0 = _mm_load_ps((x)+i   ); \
+        __m128 XMM1 = _mm_load_ps((x)+i+ 4); \
+        __m128 XMM2 = _mm_load_ps((x)+i+ 8); \
+        __m128 XMM3 = _mm_load_ps((x)+i+12); \
+        _mm_store_ps((y)+i   , XMM0); \
+        _mm_store_ps((y)+i+ 4, XMM1); \
+        _mm_store_ps((y)+i+ 8, XMM2); \
+        _mm_store_ps((y)+i+12, XMM3); \
+    } \
+}
+
+#define vecncpy(y, x, n) \
+{ \
+    int i; \
+    const uint32_t mask = 0x80000000; \
+    __m128 XMM4 = _mm_load_ps1((float*)&mask); \
+    for (i = 0;i < (n);i += 16) { \
+        __m128 XMM0 = _mm_load_ps((x)+i   ); \
+        __m128 XMM1 = _mm_load_ps((x)+i+ 4); \
+        __m128 XMM2 = _mm_load_ps((x)+i+ 8); \
+        __m128 XMM3 = _mm_load_ps((x)+i+12); \
+        XMM0 = _mm_xor_ps(XMM0, XMM4); \
+        XMM1 = _mm_xor_ps(XMM1, XMM4); \
+        XMM2 = _mm_xor_ps(XMM2, XMM4); \
+        XMM3 = _mm_xor_ps(XMM3, XMM4); \
+        _mm_store_ps((y)+i   , XMM0); \
+        _mm_store_ps((y)+i+ 4, XMM1); \
+        _mm_store_ps((y)+i+ 8, XMM2); \
+        _mm_store_ps((y)+i+12, XMM3); \
+    } \
+}
+
+#define vecadd(y, x, c, n) \
+{ \
+    int i; \
+    __m128 XMM7 = _mm_set_ps1(c); \
+    for (i = 0;i < (n);i += 8) { \
+        __m128 XMM0 = _mm_load_ps((x)+i  ); \
+        __m128 XMM1 = _mm_load_ps((x)+i+4); \
+        __m128 XMM2 = _mm_load_ps((y)+i  ); \
+        __m128 XMM3 = _mm_load_ps((y)+i+4); \
+        XMM0 = _mm_mul_ps(XMM0, XMM7); \
+        XMM1 = _mm_mul_ps(XMM1, XMM7); \
+        XMM2 = _mm_add_ps(XMM2, XMM0); \
+        XMM3 = _mm_add_ps(XMM3, XMM1); \
+        _mm_store_ps((y)+i  , XMM2); \
+        _mm_store_ps((y)+i+4, XMM3); \
+    } \
+}
+
+#define vecdiff(z, x, y, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 16) { \
+        __m128 XMM0 = _mm_load_ps((x)+i   ); \
+        __m128 XMM1 = _mm_load_ps((x)+i+ 4); \
+        __m128 XMM2 = _mm_load_ps((x)+i+ 8); \
+        __m128 XMM3 = _mm_load_ps((x)+i+12); \
+        __m128 XMM4 = _mm_load_ps((y)+i   ); \
+        __m128 XMM5 = _mm_load_ps((y)+i+ 4); \
+        __m128 XMM6 = _mm_load_ps((y)+i+ 8); \
+        __m128 XMM7 = _mm_load_ps((y)+i+12); \
+        XMM0 = _mm_sub_ps(XMM0, XMM4); \
+        XMM1 = _mm_sub_ps(XMM1, XMM5); \
+        XMM2 = _mm_sub_ps(XMM2, XMM6); \
+        XMM3 = _mm_sub_ps(XMM3, XMM7); \
+        _mm_store_ps((z)+i   , XMM0); \
+        _mm_store_ps((z)+i+ 4, XMM1); \
+        _mm_store_ps((z)+i+ 8, XMM2); \
+        _mm_store_ps((z)+i+12, XMM3); \
+    } \
+}
+
+#define vecscale(y, c, n) \
+{ \
+    int i; \
+    __m128 XMM7 = _mm_set_ps1(c); \
+    for (i = 0;i < (n);i += 8) { \
+        __m128 XMM0 = _mm_load_ps((y)+i  ); \
+        __m128 XMM1 = _mm_load_ps((y)+i+4); \
+        XMM0 = _mm_mul_ps(XMM0, XMM7); \
+        XMM1 = _mm_mul_ps(XMM1, XMM7); \
+        _mm_store_ps((y)+i  , XMM0); \
+        _mm_store_ps((y)+i+4, XMM1); \
+    } \
+}
+
+#define vecmul(y, x, n) \
+{ \
+    int i; \
+    for (i = 0;i < (n);i += 16) { \
+        __m128 XMM0 = _mm_load_ps((x)+i   ); \
+        __m128 XMM1 = _mm_load_ps((x)+i+ 4); \
+        __m128 XMM2 = _mm_load_ps((x)+i+ 8); \
+        __m128 XMM3 = _mm_load_ps((x)+i+12); \
+        __m128 XMM4 = _mm_load_ps((y)+i   ); \
+        __m128 XMM5 = _mm_load_ps((y)+i+ 4); \
+        __m128 XMM6 = _mm_load_ps((y)+i+ 8); \
+        __m128 XMM7 = _mm_load_ps((y)+i+12); \
+        XMM4 = _mm_mul_ps(XMM4, XMM0); \
+        XMM5 = _mm_mul_ps(XMM5, XMM1); \
+        XMM6 = _mm_mul_ps(XMM6, XMM2); \
+        XMM7 = _mm_mul_ps(XMM7, XMM3); \
+        _mm_store_ps((y)+i   , XMM4); \
+        _mm_store_ps((y)+i+ 4, XMM5); \
+        _mm_store_ps((y)+i+ 8, XMM6); \
+        _mm_store_ps((y)+i+12, XMM7); \
+    } \
+}
+
+
+
+#if     3 <= __SSE__
+/*
+    Horizontal add with haddps SSE3 instruction. The work register (rw)
+    is unused.
+ */
+#define __horizontal_sum(r, rw) \
+    r = _mm_hadd_ps(r, r); \
+    r = _mm_hadd_ps(r, r);
+
+#else
+/*
+    Horizontal add with SSE instruction. The work register (rw) is used.
+ */
+#define __horizontal_sum(r, rw) \
+    rw = r; \
+    r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(1, 0, 3, 2)); \
+    r = _mm_add_ps(r, rw); \
+    rw = r; \
+    r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(2, 3, 0, 1)); \
+    r = _mm_add_ps(r, rw);
+
+#endif
+
+#define vecdot(s, x, y, n) \
+{ \
+    int i; \
+    __m128 XMM0 = _mm_setzero_ps(); \
+    __m128 XMM1 = _mm_setzero_ps(); \
+    __m128 XMM2, XMM3, XMM4, XMM5; \
+    for (i = 0;i < (n);i += 8) { \
+        XMM2 = _mm_load_ps((x)+i  ); \
+        XMM3 = _mm_load_ps((x)+i+4); \
+        XMM4 = _mm_load_ps((y)+i  ); \
+        XMM5 = _mm_load_ps((y)+i+4); \
+        XMM2 = _mm_mul_ps(XMM2, XMM4); \
+        XMM3 = _mm_mul_ps(XMM3, XMM5); \
+        XMM0 = _mm_add_ps(XMM0, XMM2); \
+        XMM1 = _mm_add_ps(XMM1, XMM3); \
+    } \
+    XMM0 = _mm_add_ps(XMM0, XMM1); \
+    __horizontal_sum(XMM0, XMM1); \
+    _mm_store_ss((s), XMM0); \
+}
+
+#define vec2norm(s, x, n) \
+{ \
+    int i; \
+    __m128 XMM0 = _mm_setzero_ps(); \
+    __m128 XMM1 = _mm_setzero_ps(); \
+    __m128 XMM2, XMM3; \
+    for (i = 0;i < (n);i += 8) { \
+        XMM2 = _mm_load_ps((x)+i  ); \
+        XMM3 = _mm_load_ps((x)+i+4); \
+        XMM2 = _mm_mul_ps(XMM2, XMM2); \
+        XMM3 = _mm_mul_ps(XMM3, XMM3); \
+        XMM0 = _mm_add_ps(XMM0, XMM2); \
+        XMM1 = _mm_add_ps(XMM1, XMM3); \
+    } \
+    XMM0 = _mm_add_ps(XMM0, XMM1); \
+    __horizontal_sum(XMM0, XMM1); \
+    XMM2 = XMM0; \
+    XMM1 = _mm_rsqrt_ss(XMM0); \
+    XMM3 = XMM1; \
+    XMM1 = _mm_mul_ss(XMM1, XMM1); \
+    XMM1 = _mm_mul_ss(XMM1, XMM3); \
+    XMM1 = _mm_mul_ss(XMM1, XMM0); \
+    XMM1 = _mm_mul_ss(XMM1, _mm_set_ss(-0.5f)); \
+    XMM3 = _mm_mul_ss(XMM3, _mm_set_ss(1.5f)); \
+    XMM3 = _mm_add_ss(XMM3, XMM1); \
+    XMM3 = _mm_mul_ss(XMM3, XMM2); \
+    _mm_store_ss((s), XMM3); \
+}
+
+#define vec2norminv(s, x, n) \
+{ \
+    int i; \
+    __m128 XMM0 = _mm_setzero_ps(); \
+    __m128 XMM1 = _mm_setzero_ps(); \
+    __m128 XMM2, XMM3; \
+    for (i = 0;i < (n);i += 16) { \
+        XMM2 = _mm_load_ps((x)+i  ); \
+        XMM3 = _mm_load_ps((x)+i+4); \
+        XMM2 = _mm_mul_ps(XMM2, XMM2); \
+        XMM3 = _mm_mul_ps(XMM3, XMM3); \
+        XMM0 = _mm_add_ps(XMM0, XMM2); \
+        XMM1 = _mm_add_ps(XMM1, XMM3); \
+    } \
+    XMM0 = _mm_add_ps(XMM0, XMM1); \
+    __horizontal_sum(XMM0, XMM1); \
+    XMM2 = XMM0; \
+    XMM1 = _mm_rsqrt_ss(XMM0); \
+    XMM3 = XMM1; \
+    XMM1 = _mm_mul_ss(XMM1, XMM1); \
+    XMM1 = _mm_mul_ss(XMM1, XMM3); \
+    XMM1 = _mm_mul_ss(XMM1, XMM0); \
+    XMM1 = _mm_mul_ss(XMM1, _mm_set_ss(-0.5f)); \
+    XMM3 = _mm_mul_ss(XMM3, _mm_set_ss(1.5f)); \
+    XMM3 = _mm_add_ss(XMM3, XMM1); \
+    _mm_store_ss((s), XMM3); \
+}
diff --git a/src/plfit/error.c b/src/plfit/error.c
new file mode 100644
index 0000000..36355ec
--- /dev/null
+++ b/src/plfit/error.c
@@ -0,0 +1,74 @@
+/* error.c
+ *
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "error.h"
+
+static char *plfit_i_error_strings[] = {
+    "No error",
+    "Failed",
+    "Invalid value",
+    "Underflow",
+    "Overflow",
+    "Not enough memory"
+};
+
+#ifndef USING_R
+static plfit_error_handler_t* plfit_error_handler = plfit_error_handler_abort;
+#else
+/* This is overwritten, anyway */
+static plfit_error_handler_t* plfit_error_handler = plfit_error_handler_ignore;
+#endif
+
+const char* plfit_strerror(const int plfit_errno) {
+  return plfit_i_error_strings[plfit_errno];
+}
+
+plfit_error_handler_t* plfit_set_error_handler(plfit_error_handler_t* new_handler) {
+    plfit_error_handler_t* old_handler = plfit_error_handler;
+    plfit_error_handler = new_handler;
+    return old_handler;
+}
+
+void plfit_error(const char *reason, const char *file, int line,
+        int plfit_errno) {
+    plfit_error_handler(reason, file, line, plfit_errno);
+}
+
+#ifndef USING_R
+void plfit_error_handler_abort(const char *reason, const char *file, int line,
+        int plfit_errno) {
+    fprintf(stderr, "Error at %s:%i : %s, %s\n", file, line, reason,
+            plfit_strerror(plfit_errno));
+    abort();
+}
+#endif
+
+#ifndef USING_R
+void plfit_error_handler_printignore(const char *reason, const char *file, int line,
+        int plfit_errno) {
+    fprintf(stderr, "Error at %s:%i : %s, %s\n", file, line, reason,
+            plfit_strerror(plfit_errno));
+}
+#endif
+
+void plfit_error_handler_ignore(const char *reason, const char *file, int line,
+        int plfit_errno) {
+}
diff --git a/src/plfit/error.h b/src/plfit/error.h
new file mode 100644
index 0000000..f3bdacd
--- /dev/null
+++ b/src/plfit/error.h
@@ -0,0 +1,86 @@
+/* error.h
+ *
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * 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 __ERROR_H__
+#define __ERROR_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
+
+enum {
+	PLFIT_SUCCESS  = 0,
+	PLFIT_FAILURE  = 1,
+	PLFIT_EINVAL   = 2,
+	PLFIT_UNDRFLOW = 3,
+	PLFIT_OVERFLOW = 4,
+	PLFIT_ENOMEM   = 5
+};
+
+#if (defined(__GNUC__) && GCC_VERSION_MAJOR >= 3)
+#  define PLFIT_UNLIKELY(a) __builtin_expect((a), 0)
+#  define PLFIT_LIKELY(a)   __builtin_expect((a), 1)
+#else
+#  define PLFIT_UNLIKELY(a) a
+#  define PLFIT_LIKELY(a)   a
+#endif
+
+#define PLFIT_CHECK(a) \
+	do {\
+		int plfit_i_ret=(a); \
+		if (PLFIT_UNLIKELY(plfit_i_ret != PLFIT_SUCCESS)) {\
+			return plfit_i_ret; \
+		} \
+	} while(0)
+
+#define PLFIT_ERROR(reason,plfit_errno) \
+	do {\
+		plfit_error (reason, __FILE__, __LINE__, plfit_errno) ; \
+		return plfit_errno ; \
+	} while (0)
+
+typedef void plfit_error_handler_t(const char*, const char*, int, int);
+
+extern plfit_error_handler_t plfit_error_handler_abort;
+extern plfit_error_handler_t plfit_error_handler_ignore;
+extern plfit_error_handler_t plfit_error_handler_printignore;
+
+plfit_error_handler_t* plfit_set_error_handler(plfit_error_handler_t* new_handler);
+
+void plfit_error(const char *reason, const char *file, int line, int plfit_errno);
+const char* plfit_strerror(const int plfit_errno);
+
+void plfit_error_handler_abort(const char *reason, const char *file, int line,
+		int plfit_errno);
+void plfit_error_handler_ignore(const char *reason, const char *file, int line,
+		int plfit_errno);
+void plfit_error_handler_printignore(const char *reason, const char *file, int line,
+		int plfit_errno);
+
+__END_DECLS
+
+#endif /* __ERROR_H__ */
diff --git a/src/plfit/gss.c b/src/plfit/gss.c
new file mode 100644
index 0000000..6ee6714
--- /dev/null
+++ b/src/plfit/gss.c
@@ -0,0 +1,154 @@
+/* gss.c
+ *
+ * Copyright (C) 2012 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <float.h>
+#include <math.h>
+#include <string.h>
+#include "error.h"
+#include "gss.h"
+#include "platform.h"
+
+/**
+ * \def PHI
+ *
+ * The golden ratio, i.e. 1+sqrt(5)/2
+ */
+#define PHI 1.618033988749895
+
+/**
+ * \def RESPHI
+ *
+ * Constant defined as 2 - \c PHI
+ */
+#define RESPHI 0.3819660112501051
+
+/**
+ * \const _defparam
+ *
+ * Default parameters for the GSS algorithm.
+ */
+static const gss_parameter_t _defparam = {
+    /* .epsilon = */  DBL_MIN,
+	/* .on_error = */ GSS_ERROR_STOP
+};
+
+/**
+ * Stores whether the last optimization run triggered a warning or not.
+ */
+static unsigned short int gss_i_warning_flag = 0;
+
+void gss_parameter_init(gss_parameter_t *param) {
+    memcpy(param, &_defparam, sizeof(*param));
+}
+
+unsigned short int gss_get_warning_flag() {
+	return gss_i_warning_flag;
+}
+
+#define TERMINATE {        \
+    if (_min) {            \
+        *(_min) = min;     \
+    }                      \
+    if (_fmin) {           \
+        *(_fmin) = fmin;   \
+    }                      \
+}
+
+#define EVALUATE(x, fx) { \
+    fx = proc_evaluate(instance, x); \
+    if (fmin > fx) { \
+        min = x;     \
+        fmin = fx;   \
+    } \
+    if (proc_progress) { \
+        retval = proc_progress(instance, x, fx, min, fmin, \
+                (a < b) ? a : b, (a < b) ? b : a, k); \
+        if (retval) { \
+			TERMINATE;            \
+            return PLFIT_SUCCESS; \
+        } \
+    } \
+}
+
+int gss(double a, double b, double *_min, double *_fmin,
+        gss_evaluate_t proc_evaluate, gss_progress_t proc_progress,
+        void* instance, const gss_parameter_t *_param) {
+    double c, d, min;
+    double fa, fb, fc, fd, fmin;
+    int k = 0;
+    int retval;
+    unsigned short int successful = 1;
+
+    gss_parameter_t param = _param ? (*_param) : _defparam;
+
+	gss_i_warning_flag = 0;
+
+    if (a > b) {
+        c = a; a = b; b = c;
+    }
+
+    min = a;
+    fmin = proc_evaluate(instance, a);
+
+    c = a + RESPHI*(b-a);
+
+    EVALUATE(a, fa);
+    EVALUATE(b, fb);
+    EVALUATE(c, fc);
+
+    if (fc >= fa || fc >= fb) {
+		if (param.on_error == GSS_ERROR_STOP) {
+			return PLFIT_FAILURE;
+		} else {
+			gss_i_warning_flag = 1;
+		}
+	}
+
+    while (fabs(a-b) > param.epsilon) {
+        k++;
+
+        d = c + RESPHI*(b-c);
+        EVALUATE(d, fd);
+
+        if (fd >= fa || fd >= fb) {
+			if (param.on_error == GSS_ERROR_STOP) {
+				successful = 0;
+				break;
+			} else {
+				gss_i_warning_flag = 1;
+			}
+        }
+
+        if (fc <= fd) {
+            b = a; a = d;
+        } else {
+            a = c; c = d; fc = fd;
+        }
+    }
+
+    if (successful) {
+        c = (a+b) / 2.0;
+        k++;
+        EVALUATE(c, fc);
+		TERMINATE;
+    }
+
+    return successful ? PLFIT_SUCCESS : PLFIT_FAILURE;
+}
+
diff --git a/src/plfit/gss.h b/src/plfit/gss.h
new file mode 100644
index 0000000..1f3606c
--- /dev/null
+++ b/src/plfit/gss.h
@@ -0,0 +1,146 @@
+/* gss.h
+ *
+ * Copyright (C) 2012 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GSS_H__
+#define __GSS_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
+
+/**
+ * Enum specifying what the search should do when the function is not U-shaped.
+ */
+typedef enum {
+	GSS_ERROR_STOP,              /**< Stop and return an error code */
+	GSS_ERROR_WARN               /**< Continue and set the warning flag */
+} gss_error_handling_t;
+
+/**
+ * Parameter settings for a golden section search.
+ */
+typedef struct {
+    double epsilon;
+	gss_error_handling_t on_error;
+} gss_parameter_t;
+
+/**
+ * Callback interface to provide objective function evaluations for the golden
+ * section search.
+ *
+ * The gss() function calls this function to obtain the values of the objective
+ * function when needed. A client program must implement this function to evaluate
+ * the value of the objective function, given the location.
+ *  
+ * @param  instance    The user data sent for the gss() function by the client.
+ * @param  x           The current value of the variable.
+ * @retval double      The value of the objective function for the current
+ *                      variable.
+ */
+typedef double (*gss_evaluate_t)(void *instance, double x);
+
+/**
+ * Callback interface to receive the progress of the optimization process for
+ * the golden section search.
+ *
+ * The gss() function calls this function for each iteration. Implementing
+ * this function, a client program can store or display the current progress
+ * of the optimization process.
+ *
+ * @param  instance    The user data sent for the gss() function by the client.
+ * @param  x           The current value of the variable.
+ * @param  fx          The value of the objective function at x.
+ * @param  min         The location of the minimum value of the objective
+ *                     function found so far.
+ * @param  fmin        The minimum value of the objective function found so far.
+ * @param  left        The left side of the current bracket.
+ * @param  right       The right side of the current bracket.
+ * @param  k           The index of the current iteration.
+ * @retval int         Zero to continue the optimization process. Returning a
+ *                     non-zero value will cancel the optimization process.
+ */
+typedef int (*gss_progress_t)(void *instance, double x, double fx, double min,
+        double fmin, double left, double right, int k);
+
+/**
+ * Start a golden section search optimization.
+ *
+ * @param  a    The left side of the bracket to start from
+ * @param  b    The right side of the bracket to start from
+ * @param  min  The pointer to the variable that receives the location of the
+ *              final value of the objective function. This argument can be set to
+ *              \c NULL if the location of the final value of the objective
+ *              function is unnecessary.
+ * @param  fmin The pointer to the variable that receives the final value of
+ *              the objective function. This argument can be st to \c NULL if the
+ *              final value of the objective function is unnecessary.
+ * @param  proc_evaluate  The callback function to evaluate the objective
+ *                        function at a given location.
+ * @param  proc_progress  The callback function to receive the progress (the
+ *                        last evaluated location, the value of the objective
+ *                        function at that location, the width of the current
+ *                        bracket, the minimum found so far and the step
+ *                        count). This argument can be set to \c NULL if
+ *                        a progress report is unnecessary.
+ * @param  instance    A user data for the client program. The callback
+ *                     functions will receive the value of this argument.
+ * @param  param       The pointer to a structure representing parameters for
+ *                     GSS algorithm. A client program can set this parameter
+ *                     to \c NULL to use the default parameters.
+ *                     Call the \ref gss_parameter_init() function to fill a
+ *                     structure with the default values.
+ * @retval int         The status code. This function returns zero if the
+ *                     minimization process terminates without an error. A
+ *                     non-zero value indicates an error; in particular,
+ *                     \c PLFIT_FAILURE means that the function is not
+ *                     U-shaped.
+ */
+int gss(double a, double b, double *min, double *fmin,
+        gss_evaluate_t proc_evaluate, gss_progress_t proc_progress,
+        void* instance, const gss_parameter_t *_param);
+
+/**
+ * Return the state of the warning flag.
+ *
+ * The warning flag is 1 if the last optimization was run on a function that
+ * was not U-shaped.
+ */
+unsigned short int gss_get_warning_flag();
+
+/**
+ * Initialize GSS parameters to the default values.
+ *
+ * Call this function to fill a parameter structure with the default values
+ * and overwrite parameter values if necessary.
+ *
+ * @param  param       The pointer to the parameter structure.
+ */
+void gss_parameter_init(gss_parameter_t *param);
+
+__END_DECLS
+
+#endif /* __GSS_H__ */
diff --git a/src/plfit/kolmogorov.c b/src/plfit/kolmogorov.c
new file mode 100644
index 0000000..e6d3024
--- /dev/null
+++ b/src/plfit/kolmogorov.c
@@ -0,0 +1,66 @@
+/* kolmogorov.c
+ *
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <math.h>
+#include "kolmogorov.h"
+
+double plfit_kolmogorov(double z) {
+    const double fj[4] = { -2, -8, -18, -32 };
+    const double w = 2.50662827;
+    const double c1 = -1.2337005501361697;   /* -pi^2 / 8 */
+    const double c2 = -11.103304951225528;   /*  9*c1 */
+    const double c3 = -30.842513753404244;   /* 25*c1 */
+
+    double u = fabs(z);
+    double v;
+
+    if (u < 0.2)
+        return 1;
+
+    if (u < 0.755) {
+        v = 1.0 / (u*u);
+        return 1 - w * (exp(c1*v) + exp(c2*v) + exp(c3*v)) / u;
+    }
+
+    if (u < 6.8116) {
+        double r[4] = { 0, 0, 0, 0 };
+        long int maxj = (long int)(3.0 / u + 0.5);
+        long int j;
+
+        if (maxj < 1)
+            maxj = 1;
+
+        v = u*u;
+        for (j = 0; j < maxj; j++) {
+            r[j] = exp(fj[j] * v);
+        }
+
+        return 2*(r[0] - r[1] + r[2] - r[3]);
+    }
+
+    return 0;
+}
+
+double plfit_ks_test_one_sample_p(double d, size_t n) {
+    return plfit_kolmogorov(d * sqrt(n));
+}
+
+double plfit_ks_test_two_sample_p(double d, size_t n1, size_t n2) {
+    return plfit_kolmogorov(d * sqrt(n1*n2 / ((double)(n1+n2))));
+}
diff --git a/src/plfit/kolmogorov.h b/src/plfit/kolmogorov.h
new file mode 100644
index 0000000..ab85f92
--- /dev/null
+++ b/src/plfit/kolmogorov.h
@@ -0,0 +1,43 @@
+/* kolmogorov.h
+ * 
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * 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 __KOLMOGOROV_H__
+#define __KOLMOGOROV_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 <stdlib.h>
+
+__BEGIN_DECLS
+
+double plfit_kolmogorov(double z);
+double plfit_ks_test_one_sample_p(double d, size_t n);
+double plfit_ks_test_two_sample_p(double d, size_t n1, size_t n2);
+
+__END_DECLS
+
+#endif
diff --git a/src/plfit/lbfgs.c b/src/plfit/lbfgs.c
new file mode 100644
index 0000000..1067d1c
--- /dev/null
+++ b/src/plfit/lbfgs.c
@@ -0,0 +1,1378 @@
+/*
+ *      Limited memory BFGS (L-BFGS).
+ *
+ * Copyright (c) 1990, Jorge Nocedal
+ * Copyright (c) 2007-2010 Naoaki Okazaki
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* $Id: lbfgs.c 65 2010-01-29 12:19:16Z naoaki $ */
+
+/*
+This library is a C port of the FORTRAN implementation of Limited-memory
+Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal.
+The original FORTRAN source code is available at:
+http://www.ece.northwestern.edu/~nocedal/lbfgs.html
+
+The L-BFGS algorithm is described in:
+    - Jorge Nocedal.
+      Updating Quasi-Newton Matrices with Limited Storage.
+      <i>Mathematics of Computation</i>, Vol. 35, No. 151, pp. 773--782, 1980.
+    - Dong C. Liu and Jorge Nocedal.
+      On the limited memory BFGS method for large scale optimization.
+      <i>Mathematical Programming</i> B, Vol. 45, No. 3, pp. 503-528, 1989.
+
+The line search algorithms used in this implementation are described in:
+    - John E. Dennis and Robert B. Schnabel.
+      <i>Numerical Methods for Unconstrained Optimization and Nonlinear
+      Equations</i>, Englewood Cliffs, 1983.
+    - Jorge J. More and David J. Thuente.
+      Line search algorithm with guaranteed sufficient decrease.
+      <i>ACM Transactions on Mathematical Software (TOMS)</i>, Vol. 20, No. 3,
+      pp. 286-307, 1994.
+
+This library also implements Orthant-Wise Limited-memory Quasi-Newton (OWL-QN)
+method presented in:
+    - Galen Andrew and Jianfeng Gao.
+      Scalable training of L1-regularized log-linear models.
+      In <i>Proceedings of the 24th International Conference on Machine
+      Learning (ICML 2007)</i>, pp. 33-40, 2007.
+
+I would like to thank the original author, Jorge Nocedal, who has been
+distributing the effieicnt and explanatory implementation in an open source
+licence.
+*/
+
+#ifdef  HAVE_CONFIG_H
+#include "config.h"
+#endif/*HAVE_CONFIG_H*/
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "lbfgs.h"
+
+#ifdef  _MSC_VER
+#define inline  __inline
+typedef unsigned int uint32_t;
+#endif/*_MSC_VER*/
+
+#if     defined(USE_SSE) && defined(__SSE2__) && LBFGS_FLOAT == 64
+/* Use SSE2 optimization for 64bit double precision. */
+#include "arithmetic_sse_double.h"
+
+#elif   defined(USE_SSE) && defined(__SSE__) && LBFGS_FLOAT == 32
+/* Use SSE optimization for 32bit float precision. */
+#include "arithmetic_sse_float.h"
+
+#else
+/* No CPU specific optimization. */
+#include "arithmetic_ansi.h"
+
+#endif
+
+#define min2(a, b)      ((a) <= (b) ? (a) : (b))
+#define max2(a, b)      ((a) >= (b) ? (a) : (b))
+#define max3(a, b, c)   max2(max2((a), (b)), (c));
+
+#define is_aligned(p, bytes) \
+	(((uintptr_t)(const void*)(p)) % (bytes) == 0)
+
+struct tag_callback_data {
+    int n;
+    void *instance;
+    lbfgs_evaluate_t proc_evaluate;
+    lbfgs_progress_t proc_progress;
+};
+typedef struct tag_callback_data callback_data_t;
+
+struct tag_iteration_data {
+    lbfgsfloatval_t alpha;
+    lbfgsfloatval_t *s;     /* [n] */
+    lbfgsfloatval_t *y;     /* [n] */
+    lbfgsfloatval_t ys;     /* vecdot(y, s) */
+};
+typedef struct tag_iteration_data iteration_data_t;
+
+static const lbfgs_parameter_t _defparam = {
+    6, 1e-5, 0, 1e-5,
+    0, LBFGS_LINESEARCH_DEFAULT, 40,
+    1e-20, 1e20, 1e-4, 0.9, 0.9, 1.0e-16,
+    0.0, 0, -1,
+};
+
+/* Forward function declarations. */
+
+typedef int (*line_search_proc)(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+    
+static int line_search_backtracking(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+
+static int line_search_backtracking_owlqn(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wp,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+
+static int line_search_morethuente(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+
+static int update_trial_interval(
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *fx,
+    lbfgsfloatval_t *dx,
+    lbfgsfloatval_t *y,
+    lbfgsfloatval_t *fy,
+    lbfgsfloatval_t *dy,
+    lbfgsfloatval_t *t,
+    lbfgsfloatval_t *ft,
+    lbfgsfloatval_t *dt,
+    const lbfgsfloatval_t tmin,
+    const lbfgsfloatval_t tmax,
+    int *brackt
+    );
+
+static lbfgsfloatval_t owlqn_x1norm(
+    const lbfgsfloatval_t* x,
+    const int start,
+    const int n
+    );
+
+static void owlqn_pseudo_gradient(
+    lbfgsfloatval_t* pg,
+    const lbfgsfloatval_t* x,
+    const lbfgsfloatval_t* g,
+    const int n,
+    const lbfgsfloatval_t c,
+    const int start,
+    const int end
+    );
+
+static void owlqn_project(
+    lbfgsfloatval_t* d,
+    const lbfgsfloatval_t* sign,
+    const int start,
+    const int end
+    );
+
+
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+static int round_out_variables(int n)
+{
+    n += 7;
+    n /= 8;
+    n *= 8;
+    return n;
+}
+#endif/*defined(USE_SSE)*/
+
+lbfgsfloatval_t* lbfgs_malloc(int n)
+{
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+    n = round_out_variables(n);
+#endif/*defined(USE_SSE)*/
+    return (lbfgsfloatval_t*)vecalloc(sizeof(lbfgsfloatval_t) * (size_t) n);
+}
+
+void lbfgs_free(lbfgsfloatval_t *x)
+{
+    vecfree(x);
+}
+
+void lbfgs_parameter_init(lbfgs_parameter_t *param)
+{
+    memcpy(param, &_defparam, sizeof(*param));
+}
+
+int lbfgs(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *ptr_fx,
+    lbfgs_evaluate_t proc_evaluate,
+    lbfgs_progress_t proc_progress,
+    void *instance,
+    lbfgs_parameter_t *_param
+    )
+{
+    int ret;
+    int i, j, k, ls, end, bound;
+    lbfgsfloatval_t step;
+
+    /* Constant parameters and their default values. */
+    lbfgs_parameter_t param = (_param != NULL) ? (*_param) : _defparam;
+    const int m = param.m;
+
+    lbfgsfloatval_t *xp = NULL;
+    lbfgsfloatval_t *g = NULL, *gp = NULL, *pg = NULL;
+    lbfgsfloatval_t *d = NULL, *w = NULL, *pf = NULL;
+    iteration_data_t *lm = NULL, *it = NULL;
+    lbfgsfloatval_t ys, yy;
+    lbfgsfloatval_t xnorm, gnorm, beta;
+    lbfgsfloatval_t fx = 0.;
+    lbfgsfloatval_t rate = 0.;
+    line_search_proc linesearch = line_search_morethuente;
+
+    /* Construct a callback data. */
+    callback_data_t cd;
+    cd.n = n;
+    cd.instance = instance;
+    cd.proc_evaluate = proc_evaluate;
+    cd.proc_progress = proc_progress;
+
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+    /* Round out the number of variables. */
+    n = round_out_variables(n);
+#endif/*defined(USE_SSE)*/
+
+    /* Check the input parameters for errors. */
+    if (n <= 0) {
+        return LBFGSERR_INVALID_N;
+    }
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+    if (n % 8 != 0) {
+        return LBFGSERR_INVALID_N_SSE;
+    }
+    if (!is_aligned(x, 16)) {
+        return LBFGSERR_INVALID_X_SSE;
+    }
+#endif/*defined(USE_SSE)*/
+    if (param.epsilon < 0.) {
+        return LBFGSERR_INVALID_EPSILON;
+    }
+    if (param.past < 0) {
+        return LBFGSERR_INVALID_TESTPERIOD;
+    }
+    if (param.delta < 0.) {
+        return LBFGSERR_INVALID_DELTA;
+    }
+    if (param.min_step < 0.) {
+        return LBFGSERR_INVALID_MINSTEP;
+    }
+    if (param.max_step < param.min_step) {
+        return LBFGSERR_INVALID_MAXSTEP;
+    }
+    if (param.ftol < 0.) {
+        return LBFGSERR_INVALID_FTOL;
+    }
+    if (param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE ||
+        param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE) {
+        if (param.wolfe <= param.ftol || 1. <= param.wolfe) {
+            return LBFGSERR_INVALID_WOLFE;
+        }
+    }
+    if (param.gtol < 0.) {
+        return LBFGSERR_INVALID_GTOL;
+    }
+    if (param.xtol < 0.) {
+        return LBFGSERR_INVALID_XTOL;
+    }
+    if (param.max_linesearch <= 0) {
+        return LBFGSERR_INVALID_MAXLINESEARCH;
+    }
+    if (param.orthantwise_c < 0.) {
+        return LBFGSERR_INVALID_ORTHANTWISE;
+    }
+    if (param.orthantwise_start < 0 || n < param.orthantwise_start) {
+        return LBFGSERR_INVALID_ORTHANTWISE_START;
+    }
+    if (param.orthantwise_end < 0) {
+        param.orthantwise_end = n;
+    }
+    if (n < param.orthantwise_end) {
+        return LBFGSERR_INVALID_ORTHANTWISE_END;
+    }
+    if (param.orthantwise_c != 0.) {
+        switch (param.linesearch) {
+        case LBFGS_LINESEARCH_BACKTRACKING:
+            linesearch = line_search_backtracking_owlqn;
+            break;
+        default:
+            /* Only the backtracking method is available. */
+            return LBFGSERR_INVALID_LINESEARCH;
+        }
+    } else {
+        switch (param.linesearch) {
+        case LBFGS_LINESEARCH_MORETHUENTE:
+            linesearch = line_search_morethuente;
+            break;
+        case LBFGS_LINESEARCH_BACKTRACKING_ARMIJO:
+        case LBFGS_LINESEARCH_BACKTRACKING_WOLFE:
+        case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE:
+            linesearch = line_search_backtracking;
+            break;
+        default:
+            return LBFGSERR_INVALID_LINESEARCH;
+        }
+    }
+
+    /* Allocate working space. */
+    xp = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+    g = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+    gp = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+    d = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+    w = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+    if (xp == NULL || g == NULL || gp == NULL || d == NULL || w == NULL) {
+        ret = LBFGSERR_OUTOFMEMORY;
+        goto lbfgs_exit;
+    }
+
+    if (param.orthantwise_c != 0.) {
+        /* Allocate working space for OW-LQN. */
+        pg = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+        if (pg == NULL) {
+            ret = LBFGSERR_OUTOFMEMORY;
+            goto lbfgs_exit;
+        }
+    }
+
+    /* Allocate limited memory storage. */
+    lm = (iteration_data_t*)vecalloc((size_t) m * sizeof(iteration_data_t));
+    if (lm == NULL) {
+        ret = LBFGSERR_OUTOFMEMORY;
+        goto lbfgs_exit;
+    }
+
+    /* Initialize the limited memory. */
+    for (i = 0;i < m;++i) {
+        it = &lm[i];
+        it->alpha = 0;
+        it->ys = 0;
+        it->s = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+        it->y = (lbfgsfloatval_t*)vecalloc((size_t) n * sizeof(lbfgsfloatval_t));
+        if (it->s == NULL || it->y == NULL) {
+            ret = LBFGSERR_OUTOFMEMORY;
+            goto lbfgs_exit;
+        }
+    }
+
+    /* Allocate an array for storing previous values of the objective function. */
+    if (0 < param.past) {
+        pf = (lbfgsfloatval_t*)vecalloc((size_t) param.past * sizeof(lbfgsfloatval_t));
+    }
+
+    /* Evaluate the function value and its gradient. */
+    fx = cd.proc_evaluate(cd.instance, x, g, cd.n, 0);
+    if (0. != param.orthantwise_c) {
+        /* Compute the L1 norm of the variable and add it to the object value. */
+        xnorm = owlqn_x1norm(x, param.orthantwise_start, param.orthantwise_end);
+        fx += xnorm * param.orthantwise_c;
+        owlqn_pseudo_gradient(
+            pg, x, g, n,
+            param.orthantwise_c, param.orthantwise_start, param.orthantwise_end
+            );
+    }
+
+    /* Store the initial value of the objective function. */
+    if (pf != NULL) {
+        pf[0] = fx;
+    }
+
+    /*
+        Compute the direction;
+        we assume the initial hessian matrix H_0 as the identity matrix.
+     */
+    if (param.orthantwise_c == 0.) {
+        vecncpy(d, g, n);
+    } else {
+        vecncpy(d, pg, n);
+    }
+
+    /*
+       Make sure that the initial variables are not a minimizer.
+     */
+    vec2norm(&xnorm, x, n);
+    if (param.orthantwise_c == 0.) {
+        vec2norm(&gnorm, g, n);
+    } else {
+        vec2norm(&gnorm, pg, n);
+    }
+    if (xnorm < 1.0) xnorm = 1.0;
+    if (gnorm / xnorm <= param.epsilon) {
+        ret = LBFGS_ALREADY_MINIMIZED;
+        goto lbfgs_exit;
+    }
+
+    /* Compute the initial step:
+        step = 1.0 / sqrt(vecdot(d, d, n))
+     */
+    vec2norminv(&step, d, n);
+
+    k = 1;
+    end = 0;
+    for (;;) {
+        /* Store the current position and gradient vectors. */
+        veccpy(xp, x, n);
+        veccpy(gp, g, n);
+
+        /* Search for an optimal step. */
+        if (param.orthantwise_c == 0.) {
+            ls = linesearch(n, x, &fx, g, d, &step, xp, gp, w, &cd, &param);
+        } else {
+            ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, &param);
+            owlqn_pseudo_gradient(
+                pg, x, g, n,
+                param.orthantwise_c, param.orthantwise_start, param.orthantwise_end
+                );
+        }
+        if (ls < 0) {
+            /* Revert to the previous point. */
+            veccpy(x, xp, n);
+            veccpy(g, gp, n);
+            ret = ls;
+            goto lbfgs_exit;
+        }
+
+        /* Compute x and g norms. */
+        vec2norm(&xnorm, x, n);
+        if (param.orthantwise_c == 0.) {
+            vec2norm(&gnorm, g, n);
+        } else {
+            vec2norm(&gnorm, pg, n);
+        }
+
+        /* Report the progress. */
+        if (cd.proc_progress) {
+            if ((ret = cd.proc_progress(cd.instance, x, g, fx, xnorm, gnorm, step, cd.n, k, ls))) {
+                goto lbfgs_exit;
+            }
+        }
+
+        /*
+            Convergence test.
+            The criterion is given by the following formula:
+                |g(x)| / \max(1, |x|) < \epsilon
+         */
+        if (xnorm < 1.0) xnorm = 1.0;
+        if (gnorm / xnorm <= param.epsilon) {
+            /* Convergence. */
+            ret = LBFGS_SUCCESS;
+            break;
+        }
+
+        /*
+            Test for stopping criterion.
+            The criterion is given by the following formula:
+                (f(past_x) - f(x)) / f(x) < \delta
+         */
+        if (pf != NULL) {
+            /* We don't test the stopping criterion while k < past. */
+            if (param.past <= k) {
+                /* Compute the relative improvement from the past. */
+                rate = (pf[k % param.past] - fx) / fx;
+
+                /* The stopping criterion. */
+                if (rate < param.delta) {
+                    ret = LBFGS_STOP;
+                    break;
+                }
+            }
+
+            /* Store the current value of the objective function. */
+            pf[k % param.past] = fx;
+        }
+
+        if (param.max_iterations != 0 && param.max_iterations < k+1) {
+            /* Maximum number of iterations. */
+            ret = LBFGSERR_MAXIMUMITERATION;
+            break;
+        }
+
+        /*
+            Update vectors s and y:
+                s_{k+1} = x_{k+1} - x_{k} = \step * d_{k}.
+                y_{k+1} = g_{k+1} - g_{k}.
+         */
+        it = &lm[end];
+        vecdiff(it->s, x, xp, n);
+        vecdiff(it->y, g, gp, n);
+
+        /*
+            Compute scalars ys and yy:
+                ys = y^t \cdot s = 1 / \rho.
+                yy = y^t \cdot y.
+            Notice that yy is used for scaling the hessian matrix H_0 (Cholesky factor).
+         */
+        vecdot(&ys, it->y, it->s, n);
+        vecdot(&yy, it->y, it->y, n);
+        it->ys = ys;
+
+        /*
+            Recursive formula to compute dir = -(H \cdot g).
+                This is described in page 779 of:
+                Jorge Nocedal.
+                Updating Quasi-Newton Matrices with Limited Storage.
+                Mathematics of Computation, Vol. 35, No. 151,
+                pp. 773--782, 1980.
+         */
+        bound = (m <= k) ? m : k;
+        ++k;
+        end = (end + 1) % m;
+
+        /* Compute the steepest direction. */
+        if (param.orthantwise_c == 0.) {
+            /* Compute the negative of gradients. */
+            vecncpy(d, g, n);
+        } else {
+            vecncpy(d, pg, n);
+        }
+
+        j = end;
+        for (i = 0;i < bound;++i) {
+            j = (j + m - 1) % m;    /* if (--j == -1) j = m-1; */
+            it = &lm[j];
+            /* \alpha_{j} = \rho_{j} s^{t}_{j} \cdot q_{k+1}. */
+            vecdot(&it->alpha, it->s, d, n);
+            it->alpha /= it->ys;
+            /* q_{i} = q_{i+1} - \alpha_{i} y_{i}. */
+            vecadd(d, it->y, -it->alpha, n);
+        }
+
+        vecscale(d, ys / yy, n);
+
+        for (i = 0;i < bound;++i) {
+            it = &lm[j];
+            /* \beta_{j} = \rho_{j} y^t_{j} \cdot \gamma_{i}. */
+            vecdot(&beta, it->y, d, n);
+            beta /= it->ys;
+            /* \gamma_{i+1} = \gamma_{i} + (\alpha_{j} - \beta_{j}) s_{j}. */
+            vecadd(d, it->s, it->alpha - beta, n);
+            j = (j + 1) % m;        /* if (++j == m) j = 0; */
+        }
+
+        /*
+            Constrain the search direction for orthant-wise updates.
+         */
+        if (param.orthantwise_c != 0.) {
+            for (i = param.orthantwise_start;i < param.orthantwise_end;++i) {
+                if (d[i] * pg[i] >= 0) {
+                    d[i] = 0;
+                }
+            }
+        }
+
+        /*
+            Now the search direction d is ready. We try step = 1 first.
+         */
+        step = 1.0;
+    }
+
+lbfgs_exit:
+    /* Return the final value of the objective function. */
+    if (ptr_fx != NULL) {
+        *ptr_fx = fx;
+    }
+
+    vecfree(pf);
+
+    /* Free memory blocks used by this function. */
+    if (lm != NULL) {
+        for (i = 0;i < m;++i) {
+            vecfree(lm[i].s);
+            vecfree(lm[i].y);
+        }
+        vecfree(lm);
+    }
+    vecfree(pg);
+    vecfree(w);
+    vecfree(d);
+    vecfree(gp);
+    vecfree(g);
+    vecfree(xp);
+
+    return ret;
+}
+
+
+
+static int line_search_backtracking(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wp,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    )
+{
+    int count = 0;
+    lbfgsfloatval_t width, dg;
+    lbfgsfloatval_t finit, dginit = 0., dgtest;
+    const lbfgsfloatval_t dec = 0.5, inc = 2.1;
+
+    /* Check the input parameters for errors. */
+    if (*stp <= 0.) {
+        return LBFGSERR_INVALIDPARAMETERS;
+    }
+
+    /* Compute the initial gradient in the search direction. */
+    vecdot(&dginit, g, s, n);
+
+    /* Make sure that s points to a descent direction. */
+    if (0 < dginit) {
+        return LBFGSERR_INCREASEGRADIENT;
+    }
+
+    /* The initial value of the objective function. */
+    finit = *f;
+    dgtest = param->ftol * dginit;
+
+    for (;;) {
+        veccpy(x, xp, n);
+        vecadd(x, s, *stp, n);
+
+        /* Evaluate the function and gradient values. */
+        *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
+
+        ++count;
+
+        if (*f > finit + *stp * dgtest) {
+            width = dec;
+        } else {
+            /* The sufficient decrease condition (Armijo condition). */
+            if (param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_ARMIJO) {
+                /* Exit with the Armijo condition. */
+                return count;
+	        }
+
+	        /* Check the Wolfe condition. */
+	        vecdot(&dg, g, s, n);
+	        if (dg < param->wolfe * dginit) {
+    		    width = inc;
+	        } else {
+		        if(param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE) {
+		            /* Exit with the regular Wolfe condition. */
+		            return count;
+		        }
+
+		        /* Check the strong Wolfe condition. */
+		        if(dg > -param->wolfe * dginit) {
+		            width = dec;
+		        } else {
+		            /* Exit with the strong Wolfe condition. */
+		            return count;
+		        }
+            }
+        }
+
+        if (*stp < param->min_step) {
+            /* The step is the minimum value. */
+            return LBFGSERR_MINIMUMSTEP;
+        }
+        if (*stp > param->max_step) {
+            /* The step is the maximum value. */
+            return LBFGSERR_MAXIMUMSTEP;
+        }
+        if (param->max_linesearch <= count) {
+            /* Maximum number of iteration. */
+            return LBFGSERR_MAXIMUMLINESEARCH;
+        }
+
+        (*stp) *= width;
+    }
+}
+
+
+
+static int line_search_backtracking_owlqn(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wp,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    )
+{
+    int i, count = 0;
+    lbfgsfloatval_t width = 0.5, norm = 0.;
+    lbfgsfloatval_t finit = *f, dgtest;
+
+    /* Check the input parameters for errors. */
+    if (*stp <= 0.) {
+        return LBFGSERR_INVALIDPARAMETERS;
+    }
+
+    /* Choose the orthant for the new point. */
+    for (i = 0;i < n;++i) {
+        wp[i] = (xp[i] == 0.) ? -gp[i] : xp[i];
+    }
+
+    for (;;) {
+        /* Update the current point. */
+        veccpy(x, xp, n);
+        vecadd(x, s, *stp, n);
+
+        /* The current point is projected onto the orthant. */
+        owlqn_project(x, wp, param->orthantwise_start, param->orthantwise_end);
+
+        /* Evaluate the function and gradient values. */
+        *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
+
+        /* Compute the L1 norm of the variables and add it to the object value. */
+        norm = owlqn_x1norm(x, param->orthantwise_start, param->orthantwise_end);
+        *f += norm * param->orthantwise_c;
+
+        ++count;
+
+        dgtest = 0.;
+        for (i = 0;i < n;++i) {
+            dgtest += (x[i] - xp[i]) * gp[i];
+        }
+
+        if (*f <= finit + param->ftol * dgtest) {
+            /* The sufficient decrease condition. */
+            return count;
+        }
+
+        if (*stp < param->min_step) {
+            /* The step is the minimum value. */
+            return LBFGSERR_MINIMUMSTEP;
+        }
+        if (*stp > param->max_step) {
+            /* The step is the maximum value. */
+            return LBFGSERR_MAXIMUMSTEP;
+        }
+        if (param->max_linesearch <= count) {
+            /* Maximum number of iteration. */
+            return LBFGSERR_MAXIMUMLINESEARCH;
+        }
+
+        (*stp) *= width;
+    }
+}
+
+
+
+static int line_search_morethuente(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    )
+{
+    int count = 0;
+    int brackt, stage1, uinfo = 0;
+    lbfgsfloatval_t dg;
+    lbfgsfloatval_t stx, fx, dgx;
+    lbfgsfloatval_t sty, fy, dgy;
+    lbfgsfloatval_t fxm, dgxm, fym, dgym, fm, dgm;
+    lbfgsfloatval_t finit, ftest1, dginit, dgtest;
+    lbfgsfloatval_t width, prev_width;
+    lbfgsfloatval_t stmin, stmax;
+
+    /* Check the input parameters for errors. */
+    if (*stp <= 0.) {
+        return LBFGSERR_INVALIDPARAMETERS;
+    }
+
+    /* Compute the initial gradient in the search direction. */
+    vecdot(&dginit, g, s, n);
+
+    /* Make sure that s points to a descent direction. */
+    if (0 < dginit) {
+        return LBFGSERR_INCREASEGRADIENT;
+    }
+
+    /* Initialize local variables. */
+    brackt = 0;
+    stage1 = 1;
+    finit = *f;
+    dgtest = param->ftol * dginit;
+    width = param->max_step - param->min_step;
+    prev_width = 2.0 * width;
+
+    /*
+        The variables stx, fx, dgx contain the values of the step,
+        function, and directional derivative at the best step.
+        The variables sty, fy, dgy contain the value of the step,
+        function, and derivative at the other endpoint of
+        the interval of uncertainty.
+        The variables stp, f, dg contain the values of the step,
+        function, and derivative at the current step.
+    */
+    stx = sty = 0.;
+    fx = fy = finit;
+    dgx = dgy = dginit;
+
+    for (;;) {
+        /*
+            Set the minimum and maximum steps to correspond to the
+            present interval of uncertainty.
+         */
+        if (brackt) {
+            stmin = min2(stx, sty);
+            stmax = max2(stx, sty);
+        } else {
+            stmin = stx;
+            stmax = *stp + 4.0 * (*stp - stx);
+        }
+
+        /* Clip the step in the range of [stpmin, stpmax]. */
+        if (*stp < param->min_step) *stp = param->min_step;
+        if (param->max_step < *stp) *stp = param->max_step;
+
+        /*
+            If an unusual termination is to occur then let
+            stp be the lowest point obtained so far.
+         */
+        if ((brackt && ((*stp <= stmin || stmax <= *stp) || param->max_linesearch <= count + 1 || uinfo != 0)) || (brackt && (stmax - stmin <= param->xtol * stmax))) {
+            *stp = stx;
+        }
+
+        /*
+            Compute the current value of x:
+                x <- x + (*stp) * s.
+         */
+        veccpy(x, xp, n);
+        vecadd(x, s, *stp, n);
+
+        /* Evaluate the function and gradient values. */
+        *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
+        vecdot(&dg, g, s, n);
+
+        ftest1 = finit + *stp * dgtest;
+        ++count;
+
+        /* Test for errors and convergence. */
+        if (brackt && ((*stp <= stmin || stmax <= *stp) || uinfo != 0)) {
+            /* Rounding errors prevent further progress. */
+            return LBFGSERR_ROUNDING_ERROR;
+        }
+        if (*stp == param->max_step && *f <= ftest1 && dg <= dgtest) {
+            /* The step is the maximum value. */
+            return LBFGSERR_MAXIMUMSTEP;
+        }
+        if (*stp == param->min_step && (ftest1 < *f || dgtest <= dg)) {
+            /* The step is the minimum value. */
+            return LBFGSERR_MINIMUMSTEP;
+        }
+        if (brackt && (stmax - stmin) <= param->xtol * stmax) {
+            /* Relative width of the interval of uncertainty is at most xtol. */
+            return LBFGSERR_WIDTHTOOSMALL;
+        }
+        if (param->max_linesearch <= count) {
+            /* Maximum number of iteration. */
+            return LBFGSERR_MAXIMUMLINESEARCH;
+        }
+        if (*f <= ftest1 && fabs(dg) <= param->gtol * (-dginit)) {
+            /* The sufficient decrease condition and the directional derivative condition hold. */
+            return count;
+        }
+
+        /*
+            In the first stage we seek a step for which the modified
+            function has a nonpositive value and nonnegative derivative.
+         */
+        if (stage1 && *f <= ftest1 && min2(param->ftol, param->gtol) * dginit <= dg) {
+            stage1 = 0;
+        }
+
+        /*
+            A modified function is used to predict the step only if
+            we have not obtained a step for which the modified
+            function has a nonpositive function value and nonnegative
+            derivative, and if a lower function value has been
+            obtained but the decrease is not sufficient.
+         */
+        if (stage1 && ftest1 < *f && *f <= fx) {
+            /* Define the modified function and derivative values. */
+            fm = *f - *stp * dgtest;
+            fxm = fx - stx * dgtest;
+            fym = fy - sty * dgtest;
+            dgm = dg - dgtest;
+            dgxm = dgx - dgtest;
+            dgym = dgy - dgtest;
+
+            /*
+                Call update_trial_interval() to update the interval of
+                uncertainty and to compute the new step.
+             */
+            uinfo = update_trial_interval(
+                &stx, &fxm, &dgxm,
+                &sty, &fym, &dgym,
+                stp, &fm, &dgm,
+                stmin, stmax, &brackt
+                );
+
+            /* Reset the function and gradient values for f. */
+            fx = fxm + stx * dgtest;
+            fy = fym + sty * dgtest;
+            dgx = dgxm + dgtest;
+            dgy = dgym + dgtest;
+        } else {
+            /*
+                Call update_trial_interval() to update the interval of
+                uncertainty and to compute the new step.
+             */
+            uinfo = update_trial_interval(
+                &stx, &fx, &dgx,
+                &sty, &fy, &dgy,
+                stp, f, &dg,
+                stmin, stmax, &brackt
+                );
+        }
+
+        /*
+            Force a sufficient decrease in the interval of uncertainty.
+         */
+        if (brackt) {
+            if (0.66 * prev_width <= fabs(sty - stx)) {
+                *stp = stx + 0.5 * (sty - stx);
+            }
+            prev_width = width;
+            width = fabs(sty - stx);
+        }
+    }
+
+    return LBFGSERR_LOGICERROR;
+}
+
+
+
+/**
+ * Define the local variables for computing minimizers.
+ */
+#define USES_MINIMIZER \
+    lbfgsfloatval_t a, d, gamma, theta, p, q, r, s;
+
+/**
+ * Find a minimizer of an interpolated cubic function.
+ *  @param  cm      The minimizer of the interpolated cubic.
+ *  @param  u       The value of one point, u.
+ *  @param  fu      The value of f(u).
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  fv      The value of f(v).
+ *  @param  du      The value of f'(v).
+ */
+#define CUBIC_MINIMIZER(cm, u, fu, du, v, fv, dv) \
+    d = (v) - (u); \
+    theta = ((fu) - (fv)) * 3 / d + (du) + (dv); \
+    p = fabs(theta); \
+    q = fabs(du); \
+    r = fabs(dv); \
+    s = max3(p, q, r); \
+    /* gamma = s*sqrt((theta/s)**2 - (du/s) * (dv/s)) */ \
+    a = theta / s; \
+    gamma = s * sqrt(a * a - ((du) / s) * ((dv) / s)); \
+    if ((v) < (u)) gamma = -gamma; \
+    p = gamma - (du) + theta; \
+    q = gamma - (du) + gamma + (dv); \
+    r = p / q; \
+    (cm) = (u) + r * d;
+
+/**
+ * Find a minimizer of an interpolated cubic function.
+ *  @param  cm      The minimizer of the interpolated cubic.
+ *  @param  u       The value of one point, u.
+ *  @param  fu      The value of f(u).
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  fv      The value of f(v).
+ *  @param  du      The value of f'(v).
+ *  @param  xmin    The maximum value.
+ *  @param  xmin    The minimum value.
+ */
+#define CUBIC_MINIMIZER2(cm, u, fu, du, v, fv, dv, xmin, xmax) \
+    d = (v) - (u); \
+    theta = ((fu) - (fv)) * 3 / d + (du) + (dv); \
+    p = fabs(theta); \
+    q = fabs(du); \
+    r = fabs(dv); \
+    s = max3(p, q, r); \
+    /* gamma = s*sqrt((theta/s)**2 - (du/s) * (dv/s)) */ \
+    a = theta / s; \
+    gamma = s * sqrt(max2(0, a * a - ((du) / s) * ((dv) / s))); \
+    if ((u) < (v)) gamma = -gamma; \
+    p = gamma - (dv) + theta; \
+    q = gamma - (dv) + gamma + (du); \
+    r = p / q; \
+    if (r < 0. && gamma != 0.) { \
+        (cm) = (v) - r * d; \
+    } else if (a < 0) { \
+        (cm) = (xmax); \
+    } else { \
+        (cm) = (xmin); \
+    }
+
+/**
+ * Find a minimizer of an interpolated quadratic function.
+ *  @param  qm      The minimizer of the interpolated quadratic.
+ *  @param  u       The value of one point, u.
+ *  @param  fu      The value of f(u).
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  fv      The value of f(v).
+ */
+#define QUARD_MINIMIZER(qm, u, fu, du, v, fv) \
+    a = (v) - (u); \
+    (qm) = (u) + (du) / (((fu) - (fv)) / a + (du)) / 2 * a;
+
+/**
+ * Find a minimizer of an interpolated quadratic function.
+ *  @param  qm      The minimizer of the interpolated quadratic.
+ *  @param  u       The value of one point, u.
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  dv      The value of f'(v).
+ */
+#define QUARD_MINIMIZER2(qm, u, du, v, dv) \
+    a = (u) - (v); \
+    (qm) = (v) + (dv) / ((dv) - (du)) * a;
+
+/**
+ * Update a safeguarded trial value and interval for line search.
+ *
+ *  The parameter x represents the step with the least function value.
+ *  The parameter t represents the current step. This function assumes
+ *  that the derivative at the point of x in the direction of the step.
+ *  If the bracket is set to true, the minimizer has been bracketed in
+ *  an interval of uncertainty with endpoints between x and y.
+ *
+ *  @param  x       The pointer to the value of one endpoint.
+ *  @param  fx      The pointer to the value of f(x).
+ *  @param  dx      The pointer to the value of f'(x).
+ *  @param  y       The pointer to the value of another endpoint.
+ *  @param  fy      The pointer to the value of f(y).
+ *  @param  dy      The pointer to the value of f'(y).
+ *  @param  t       The pointer to the value of the trial value, t.
+ *  @param  ft      The pointer to the value of f(t).
+ *  @param  dt      The pointer to the value of f'(t).
+ *  @param  tmin    The minimum value for the trial value, t.
+ *  @param  tmax    The maximum value for the trial value, t.
+ *  @param  brackt  The pointer to the predicate if the trial value is
+ *                  bracketed.
+ *  @retval int     Status value. Zero indicates a normal termination.
+ *  
+ *  @see
+ *      Jorge J. More and David J. Thuente. Line search algorithm with
+ *      guaranteed sufficient decrease. ACM Transactions on Mathematical
+ *      Software (TOMS), Vol 20, No 3, pp. 286-307, 1994.
+ */
+static int update_trial_interval(
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *fx,
+    lbfgsfloatval_t *dx,
+    lbfgsfloatval_t *y,
+    lbfgsfloatval_t *fy,
+    lbfgsfloatval_t *dy,
+    lbfgsfloatval_t *t,
+    lbfgsfloatval_t *ft,
+    lbfgsfloatval_t *dt,
+    const lbfgsfloatval_t tmin,
+    const lbfgsfloatval_t tmax,
+    int *brackt
+    )
+{
+    int bound;
+    int dsign = fsigndiff(dt, dx);
+    lbfgsfloatval_t mc; /* minimizer of an interpolated cubic. */
+    lbfgsfloatval_t mq; /* minimizer of an interpolated quadratic. */
+    lbfgsfloatval_t newt;   /* new trial value. */
+    USES_MINIMIZER;     /* for CUBIC_MINIMIZER and QUARD_MINIMIZER. */
+
+    /* Check the input parameters for errors. */
+    if (*brackt) {
+        if (*t <= min2(*x, *y) || max2(*x, *y) <= *t) {
+            /* The trival value t is out of the interval. */
+            return LBFGSERR_OUTOFINTERVAL;
+        }
+        if (0. <= *dx * (*t - *x)) {
+            /* The function must decrease from x. */
+            return LBFGSERR_INCREASEGRADIENT;
+        }
+        if (tmax < tmin) {
+            /* Incorrect tmin and tmax specified. */
+            return LBFGSERR_INCORRECT_TMINMAX;
+        }
+    }
+
+    /*
+        Trial value selection.
+     */
+    if (*fx < *ft) {
+        /*
+            Case 1: a higher function value.
+            The minimum is brackt. If the cubic minimizer is closer
+            to x than the quadratic one, the cubic one is taken, else
+            the average of the minimizers is taken.
+         */
+        *brackt = 1;
+        bound = 1;
+        CUBIC_MINIMIZER(mc, *x, *fx, *dx, *t, *ft, *dt);
+        QUARD_MINIMIZER(mq, *x, *fx, *dx, *t, *ft);
+        if (fabs(mc - *x) < fabs(mq - *x)) {
+            newt = mc;
+        } else {
+            newt = mc + 0.5 * (mq - mc);
+        }
+    } else if (dsign) {
+        /*
+            Case 2: a lower function value and derivatives of
+            opposite sign. The minimum is brackt. If the cubic
+            minimizer is closer to x than the quadratic (secant) one,
+            the cubic one is taken, else the quadratic one is taken.
+         */
+        *brackt = 1;
+        bound = 0;
+        CUBIC_MINIMIZER(mc, *x, *fx, *dx, *t, *ft, *dt);
+        QUARD_MINIMIZER2(mq, *x, *dx, *t, *dt);
+        if (fabs(mc - *t) > fabs(mq - *t)) {
+            newt = mc;
+        } else {
+            newt = mq;
+        }
+    } else if (fabs(*dt) < fabs(*dx)) {
+        /*
+            Case 3: a lower function value, derivatives of the
+            same sign, and the magnitude of the derivative decreases.
+            The cubic minimizer is only used if the cubic tends to
+            infinity in the direction of the minimizer or if the minimum
+            of the cubic is beyond t. Otherwise the cubic minimizer is
+            defined to be either tmin or tmax. The quadratic (secant)
+            minimizer is also computed and if the minimum is brackt
+            then the the minimizer closest to x is taken, else the one
+            farthest away is taken.
+         */
+        bound = 1;
+        CUBIC_MINIMIZER2(mc, *x, *fx, *dx, *t, *ft, *dt, tmin, tmax);
+        QUARD_MINIMIZER2(mq, *x, *dx, *t, *dt);
+        if (*brackt) {
+            if (fabs(*t - mc) < fabs(*t - mq)) {
+                newt = mc;
+            } else {
+                newt = mq;
+            }
+        } else {
+            if (fabs(*t - mc) > fabs(*t - mq)) {
+                newt = mc;
+            } else {
+                newt = mq;
+            }
+        }
+    } else {
+        /*
+            Case 4: a lower function value, derivatives of the
+            same sign, and the magnitude of the derivative does
+            not decrease. If the minimum is not brackt, the step
+            is either tmin or tmax, else the cubic minimizer is taken.
+         */
+        bound = 0;
+        if (*brackt) {
+            CUBIC_MINIMIZER(newt, *t, *ft, *dt, *y, *fy, *dy);
+        } else if (*x < *t) {
+            newt = tmax;
+        } else {
+            newt = tmin;
+        }
+    }
+
+    /*
+        Update the interval of uncertainty. This update does not
+        depend on the new step or the case analysis above.
+
+        - Case a: if f(x) < f(t),
+            x <- x, y <- t.
+        - Case b: if f(t) <= f(x) && f'(t)*f'(x) > 0,
+            x <- t, y <- y.
+        - Case c: if f(t) <= f(x) && f'(t)*f'(x) < 0, 
+            x <- t, y <- x.
+     */
+    if (*fx < *ft) {
+        /* Case a */
+        *y = *t;
+        *fy = *ft;
+        *dy = *dt;
+    } else {
+        /* Case c */
+        if (dsign) {
+            *y = *x;
+            *fy = *fx;
+            *dy = *dx;
+        }
+        /* Cases b and c */
+        *x = *t;
+        *fx = *ft;
+        *dx = *dt;
+    }
+
+    /* Clip the new trial value in [tmin, tmax]. */
+    if (tmax < newt) newt = tmax;
+    if (newt < tmin) newt = tmin;
+
+    /*
+        Redefine the new trial value if it is close to the upper bound
+        of the interval.
+     */
+    if (*brackt && bound) {
+        mq = *x + 0.66 * (*y - *x);
+        if (*x < *y) {
+            if (mq < newt) newt = mq;
+        } else {
+            if (newt < mq) newt = mq;
+        }
+    }
+
+    /* Return the new trial value. */
+    *t = newt;
+    return 0;
+}
+
+
+
+
+
+static lbfgsfloatval_t owlqn_x1norm(
+    const lbfgsfloatval_t* x,
+    const int start,
+    const int n
+    )
+{
+    int i;
+    lbfgsfloatval_t norm = 0.;
+
+    for (i = start;i < n;++i) {
+        norm += fabs(x[i]);
+    }
+
+    return norm;
+}
+
+static void owlqn_pseudo_gradient(
+    lbfgsfloatval_t* pg,
+    const lbfgsfloatval_t* x,
+    const lbfgsfloatval_t* g,
+    const int n,
+    const lbfgsfloatval_t c,
+    const int start,
+    const int end
+    )
+{
+    int i;
+
+    /* Compute the negative of gradients. */
+    for (i = 0;i < start;++i) {
+        pg[i] = g[i];
+    }
+
+    /* Compute the psuedo-gradients. */
+    for (i = start;i < end;++i) {
+        if (x[i] < 0.) {
+            /* Differentiable. */
+            pg[i] = g[i] - c;
+        } else if (0. < x[i]) {
+            /* Differentiable. */
+            pg[i] = g[i] + c;
+        } else {
+            if (g[i] < -c) {
+                /* Take the right partial derivative. */
+                pg[i] = g[i] + c;
+            } else if (c < g[i]) {
+                /* Take the left partial derivative. */
+                pg[i] = g[i] - c;
+            } else {
+                pg[i] = 0.;
+            }
+        }
+    }
+
+    for (i = end;i < n;++i) {
+        pg[i] = g[i];
+    }
+}
+
+static void owlqn_project(
+    lbfgsfloatval_t* d,
+    const lbfgsfloatval_t* sign,
+    const int start,
+    const int end
+    )
+{
+    int i;
+
+    for (i = start;i < end;++i) {
+        if (d[i] * sign[i] <= 0) {
+            d[i] = 0;
+        }
+    }
+}
diff --git a/src/plfit/lbfgs.h b/src/plfit/lbfgs.h
new file mode 100644
index 0000000..f26ae87
--- /dev/null
+++ b/src/plfit/lbfgs.h
@@ -0,0 +1,736 @@
+/*
+ *      C library of Limited memory BFGS (L-BFGS).
+ *
+ * Copyright (c) 1990, Jorge Nocedal
+ * Copyright (c) 2007-2010 Naoaki Okazaki
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* $Id: lbfgs.h 65 2010-01-29 12:19:16Z naoaki $ */
+
+#ifndef __LBFGS_H__
+#define __LBFGS_H__
+
+#ifdef  __cplusplus
+extern "C" {
+#endif/*__cplusplus*/
+
+/*
+ * The default precision of floating point values is 64bit (double).
+ */
+#ifndef LBFGS_FLOAT
+#define LBFGS_FLOAT     64
+#endif/*LBFGS_FLOAT*/
+
+/*
+ * Activate optimization routines for IEEE754 floating point values.
+ */
+#ifndef LBFGS_IEEE_FLOAT
+#define LBFGS_IEEE_FLOAT    1
+#endif/*LBFGS_IEEE_FLOAT*/
+
+#if     LBFGS_FLOAT == 32
+typedef float lbfgsfloatval_t;
+
+#elif   LBFGS_FLOAT == 64
+typedef double lbfgsfloatval_t;
+
+#else
+#error "libLBFGS supports single (float; LBFGS_FLOAT = 32) or double (double; LBFGS_FLOAT=64) precision only."
+
+#endif
+
+
+/** 
+ * \addtogroup liblbfgs_api libLBFGS API
+ * @{
+ *
+ *  The libLBFGS API.
+ */
+
+/**
+ * Return values of lbfgs().
+ * 
+ *  Roughly speaking, a negative value indicates an error.
+ */
+enum {
+    /** L-BFGS reaches convergence. */
+    LBFGS_SUCCESS = 0,
+    LBFGS_CONVERGENCE = 0,
+    LBFGS_STOP,
+    /** The initial variables already minimize the objective function. */
+    LBFGS_ALREADY_MINIMIZED,
+
+    /** Unknown error. */
+    LBFGSERR_UNKNOWNERROR = -1024,
+    /** Logic error. */
+    LBFGSERR_LOGICERROR,
+    /** Insufficient memory. */
+    LBFGSERR_OUTOFMEMORY,
+    /** The minimization process has been canceled. */
+    LBFGSERR_CANCELED,
+    /** Invalid number of variables specified. */
+    LBFGSERR_INVALID_N,
+    /** Invalid number of variables (for SSE) specified. */
+    LBFGSERR_INVALID_N_SSE,
+    /** The array x must be aligned to 16 (for SSE). */
+    LBFGSERR_INVALID_X_SSE,
+    /** Invalid parameter lbfgs_parameter_t::epsilon specified. */
+    LBFGSERR_INVALID_EPSILON,
+    /** Invalid parameter lbfgs_parameter_t::past specified. */
+    LBFGSERR_INVALID_TESTPERIOD,
+    /** Invalid parameter lbfgs_parameter_t::delta specified. */
+    LBFGSERR_INVALID_DELTA,
+    /** Invalid parameter lbfgs_parameter_t::linesearch specified. */
+    LBFGSERR_INVALID_LINESEARCH,
+    /** Invalid parameter lbfgs_parameter_t::max_step specified. */
+    LBFGSERR_INVALID_MINSTEP,
+    /** Invalid parameter lbfgs_parameter_t::max_step specified. */
+    LBFGSERR_INVALID_MAXSTEP,
+    /** Invalid parameter lbfgs_parameter_t::ftol specified. */
+    LBFGSERR_INVALID_FTOL,
+    /** Invalid parameter lbfgs_parameter_t::wolfe specified. */
+    LBFGSERR_INVALID_WOLFE,
+    /** Invalid parameter lbfgs_parameter_t::gtol specified. */
+    LBFGSERR_INVALID_GTOL,
+    /** Invalid parameter lbfgs_parameter_t::xtol specified. */
+    LBFGSERR_INVALID_XTOL,
+    /** Invalid parameter lbfgs_parameter_t::max_linesearch specified. */
+    LBFGSERR_INVALID_MAXLINESEARCH,
+    /** Invalid parameter lbfgs_parameter_t::orthantwise_c specified. */
+    LBFGSERR_INVALID_ORTHANTWISE,
+    /** Invalid parameter lbfgs_parameter_t::orthantwise_start specified. */
+    LBFGSERR_INVALID_ORTHANTWISE_START,
+    /** Invalid parameter lbfgs_parameter_t::orthantwise_end specified. */
+    LBFGSERR_INVALID_ORTHANTWISE_END,
+    /** The line-search step went out of the interval of uncertainty. */
+    LBFGSERR_OUTOFINTERVAL,
+    /** A logic error occurred; alternatively, the interval of uncertainty
+        became too small. */
+    LBFGSERR_INCORRECT_TMINMAX,
+    /** A rounding error occurred; alternatively, no line-search step
+        satisfies the sufficient decrease and curvature conditions. */
+    LBFGSERR_ROUNDING_ERROR,
+    /** The line-search step became smaller than lbfgs_parameter_t::min_step. */
+    LBFGSERR_MINIMUMSTEP,
+    /** The line-search step became larger than lbfgs_parameter_t::max_step. */
+    LBFGSERR_MAXIMUMSTEP,
+    /** The line-search routine reaches the maximum number of evaluations. */
+    LBFGSERR_MAXIMUMLINESEARCH,
+    /** The algorithm routine reaches the maximum number of iterations. */
+    LBFGSERR_MAXIMUMITERATION,
+    /** Relative width of the interval of uncertainty is at most
+        lbfgs_parameter_t::xtol. */
+    LBFGSERR_WIDTHTOOSMALL,
+    /** A logic error (negative line-search step) occurred. */
+    LBFGSERR_INVALIDPARAMETERS,
+    /** The current search direction increases the objective function value. */
+    LBFGSERR_INCREASEGRADIENT,
+};
+
+/**
+ * Line search algorithms.
+ */
+enum {
+    /** The default algorithm (MoreThuente method). */
+    LBFGS_LINESEARCH_DEFAULT = 0,
+    /** MoreThuente method proposd by More and Thuente. */
+    LBFGS_LINESEARCH_MORETHUENTE = 0,
+    /**
+     * Backtracking method with the Armijo condition.
+     *  The backtracking method finds the step length such that it satisfies
+     *  the sufficient decrease (Armijo) condition,
+     *    - f(x + a * d) <= f(x) + lbfgs_parameter_t::ftol * a * g(x)^T d,
+     *
+     *  where x is the current point, d is the current search direction, and
+     *  a is the step length.
+     */
+    LBFGS_LINESEARCH_BACKTRACKING_ARMIJO = 1,
+    /** The backtracking method with the defualt (regular Wolfe) condition. */
+    LBFGS_LINESEARCH_BACKTRACKING = 2,
+    /**
+     * Backtracking method with regular Wolfe condition.
+     *  The backtracking method finds the step length such that it satisfies
+     *  both the Armijo condition (LBFGS_LINESEARCH_BACKTRACKING_ARMIJO)
+     *  and the curvature condition,
+     *    - g(x + a * d)^T d >= lbfgs_parameter_t::wolfe * g(x)^T d,
+     *
+     *  where x is the current point, d is the current search direction, and
+     *  a is the step length.
+     */
+    LBFGS_LINESEARCH_BACKTRACKING_WOLFE = 2,
+    /**
+     * Backtracking method with strong Wolfe condition.
+     *  The backtracking method finds the step length such that it satisfies
+     *  both the Armijo condition (LBFGS_LINESEARCH_BACKTRACKING_ARMIJO)
+     *  and the following condition,
+     *    - |g(x + a * d)^T d| <= lbfgs_parameter_t::wolfe * |g(x)^T d|,
+     *
+     *  where x is the current point, d is the current search direction, and
+     *  a is the step length.
+     */
+    LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE = 3,
+};
+
+/**
+ * L-BFGS optimization parameters.
+ *  Call lbfgs_parameter_init() function to initialize parameters to the
+ *  default values.
+ */
+typedef struct {
+    /**
+     * The number of corrections to approximate the inverse hessian matrix.
+     *  The L-BFGS routine stores the computation results of previous \ref m
+     *  iterations to approximate the inverse hessian matrix of the current
+     *  iteration. This parameter controls the size of the limited memories
+     *  (corrections). The default value is \c 6. Values less than \c 3 are
+     *  not recommended. Large values will result in excessive computing time.
+     */
+    int             m;
+
+    /**
+     * Epsilon for convergence test.
+     *  This parameter determines the accuracy with which the solution is to
+     *  be found. A minimization terminates when
+     *      ||g|| < \ref epsilon * max(1, ||x||),
+     *  where ||.|| denotes the Euclidean (L2) norm. The default value is
+     *  \c 1e-5.
+     */
+    lbfgsfloatval_t epsilon;
+
+    /**
+     * Distance for delta-based convergence test.
+     *  This parameter determines the distance, in iterations, to compute
+     *  the rate of decrease of the objective function. If the value of this
+     *  parameter is zero, the library does not perform the delta-based
+     *  convergence test. The default value is \c 0.
+     */
+    int             past;
+
+    /**
+     * Delta for convergence test.
+     *  This parameter determines the minimum rate of decrease of the
+     *  objective function. The library stops iterations when the
+     *  following condition is met:
+     *      (f' - f) / f < \ref delta,
+     *  where f' is the objective value of \ref past iterations ago, and f is
+     *  the objective value of the current iteration.
+     *  The default value is \c 0.
+     */
+    lbfgsfloatval_t delta;
+
+    /**
+     * The maximum number of iterations.
+     *  The lbfgs() function terminates an optimization process with
+     *  ::LBFGSERR_MAXIMUMITERATION status code when the iteration count
+     *  exceedes this parameter. Setting this parameter to zero continues an
+     *  optimization process until a convergence or error. The default value
+     *  is \c 0.
+     */
+    int             max_iterations;
+
+    /**
+     * The line search algorithm.
+     *  This parameter specifies a line search algorithm to be used by the
+     *  L-BFGS routine.
+     */
+    int             linesearch;
+
+    /**
+     * The maximum number of trials for the line search.
+     *  This parameter controls the number of function and gradients evaluations
+     *  per iteration for the line search routine. The default value is \c 20.
+     */
+    int             max_linesearch;
+
+    /**
+     * The minimum step of the line search routine.
+     *  The default value is \c 1e-20. This value need not be modified unless
+     *  the exponents are too large for the machine being used, or unless the
+     *  problem is extremely badly scaled (in which case the exponents should
+     *  be increased).
+     */
+    lbfgsfloatval_t min_step;
+
+    /**
+     * The maximum step of the line search.
+     *  The default value is \c 1e+20. This value need not be modified unless
+     *  the exponents are too large for the machine being used, or unless the
+     *  problem is extremely badly scaled (in which case the exponents should
+     *  be increased).
+     */
+    lbfgsfloatval_t max_step;
+
+    /**
+     * A parameter to control the accuracy of the line search routine.
+     *  The default value is \c 1e-4. This parameter should be greater
+     *  than zero and smaller than \c 0.5.
+     */
+    lbfgsfloatval_t ftol;
+
+    /**
+     * A coefficient for the Wolfe condition.
+     *  This parameter is valid only when the backtracking line-search
+     *  algorithm is used with the Wolfe condition,
+     *  ::LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE or
+     *  ::LBFGS_LINESEARCH_BACKTRACKING_WOLFE .
+     *  The default value is \c 0.9. This parameter should be greater
+     *  the \ref ftol parameter and smaller than \c 1.0.
+     */
+    lbfgsfloatval_t wolfe;
+
+    /**
+     * A parameter to control the accuracy of the line search routine.
+     *  The default value is \c 0.9. If the function and gradient
+     *  evaluations are inexpensive with respect to the cost of the
+     *  iteration (which is sometimes the case when solving very large
+     *  problems) it may be advantageous to set this parameter to a small
+     *  value. A typical small value is \c 0.1. This parameter shuold be
+     *  greater than the \ref ftol parameter (\c 1e-4) and smaller than
+     *  \c 1.0.
+     */
+    lbfgsfloatval_t gtol;
+
+    /**
+     * The machine precision for floating-point values.
+     *  This parameter must be a positive value set by a client program to
+     *  estimate the machine precision. The line search routine will terminate
+     *  with the status code (::LBFGSERR_ROUNDING_ERROR) if the relative width
+     *  of the interval of uncertainty is less than this parameter.
+     */
+    lbfgsfloatval_t xtol;
+
+    /**
+     * Coeefficient for the L1 norm of variables.
+     *  This parameter should be set to zero for standard minimization
+     *  problems. Setting this parameter to a positive value activates
+     *  Orthant-Wise Limited-memory Quasi-Newton (OWL-QN) method, which
+     *  minimizes the objective function F(x) combined with the L1 norm |x|
+     *  of the variables, {F(x) + C |x|}. This parameter is the coeefficient
+     *  for the |x|, i.e., C. As the L1 norm |x| is not differentiable at
+     *  zero, the library modifies function and gradient evaluations from
+     *  a client program suitably; a client program thus have only to return
+     *  the function value F(x) and gradients G(x) as usual. The default value
+     *  is zero.
+     */
+    lbfgsfloatval_t orthantwise_c;
+
+    /**
+     * Start index for computing L1 norm of the variables.
+     *  This parameter is valid only for OWL-QN method
+     *  (i.e., \ref orthantwise_c != 0). This parameter b (0 <= b < N)
+     *  specifies the index number from which the library computes the
+     *  L1 norm of the variables x,
+     *      |x| := |x_{b}| + |x_{b+1}| + ... + |x_{N}| .
+     *  In other words, variables x_1, ..., x_{b-1} are not used for
+     *  computing the L1 norm. Setting b (0 < b < N), one can protect
+     *  variables, x_1, ..., x_{b-1} (e.g., a bias term of logistic
+     *  regression) from being regularized. The default value is zero.
+     */
+    int             orthantwise_start;
+
+    /**
+     * End index for computing L1 norm of the variables.
+     *  This parameter is valid only for OWL-QN method
+     *  (i.e., \ref orthantwise_c != 0). This parameter e (0 < e <= N)
+     *  specifies the index number at which the library stops computing the
+     *  L1 norm of the variables x,
+     */
+    int             orthantwise_end;
+} lbfgs_parameter_t;
+
+
+/**
+ * Callback interface to provide objective function and gradient evaluations.
+ *
+ *  The lbfgs() function call this function to obtain the values of objective
+ *  function and its gradients when needed. A client program must implement
+ *  this function to evaluate the values of the objective function and its
+ *  gradients, given current values of variables.
+ *  
+ *  @param  instance    The user data sent for lbfgs() function by the client.
+ *  @param  x           The current values of variables.
+ *  @param  g           The gradient vector. The callback function must compute
+ *                      the gradient values for the current variables.
+ *  @param  n           The number of variables.
+ *  @param  step        The current step of the line search routine.
+ *  @retval lbfgsfloatval_t The value of the objective function for the current
+ *                          variables.
+ */
+typedef lbfgsfloatval_t (*lbfgs_evaluate_t)(
+    void *instance,
+    const lbfgsfloatval_t *x,
+    lbfgsfloatval_t *g,
+    const int n,
+    const lbfgsfloatval_t step
+    );
+
+/**
+ * Callback interface to receive the progress of the optimization process.
+ *
+ *  The lbfgs() function call this function for each iteration. Implementing
+ *  this function, a client program can store or display the current progress
+ *  of the optimization process.
+ *
+ *  @param  instance    The user data sent for lbfgs() function by the client.
+ *  @param  x           The current values of variables.
+ *  @param  g           The current gradient values of variables.
+ *  @param  fx          The current value of the objective function.
+ *  @param  xnorm       The Euclidean norm of the variables.
+ *  @param  gnorm       The Euclidean norm of the gradients.
+ *  @param  step        The line-search step used for this iteration.
+ *  @param  n           The number of variables.
+ *  @param  k           The iteration count.
+ *  @param  ls          The number of evaluations called for this iteration.
+ *  @retval int         Zero to continue the optimization process. Returning a
+ *                      non-zero value will cancel the optimization process.
+ */
+typedef int (*lbfgs_progress_t)(
+    void *instance,
+    const lbfgsfloatval_t *x,
+    const lbfgsfloatval_t *g,
+    const lbfgsfloatval_t fx,
+    const lbfgsfloatval_t xnorm,
+    const lbfgsfloatval_t gnorm,
+    const lbfgsfloatval_t step,
+    int n,
+    int k,
+    int ls
+    );
+
+/*
+A user must implement a function compatible with ::lbfgs_evaluate_t (evaluation
+callback) and pass the pointer to the callback function to lbfgs() arguments.
+Similarly, a user can implement a function compatible with ::lbfgs_progress_t
+(progress callback) to obtain the current progress (e.g., variables, function
+value, ||G||, etc) and to cancel the iteration process if necessary.
+Implementation of a progress callback is optional: a user can pass \c NULL if
+progress notification is not necessary.
+
+In addition, a user must preserve two requirements:
+    - The number of variables must be multiples of 16 (this is not 4).
+    - The memory block of variable array ::x must be aligned to 16.
+
+This algorithm terminates an optimization
+when:
+
+    ||G|| < \epsilon \cdot \max(1, ||x||) .
+
+In this formula, ||.|| denotes the Euclidean norm.
+*/
+
+/**
+ * Start a L-BFGS optimization.
+ *
+ *  @param  n           The number of variables.
+ *  @param  x           The array of variables. A client program can set
+ *                      default values for the optimization and receive the
+ *                      optimization result through this array. This array
+ *                      must be allocated by ::lbfgs_malloc function
+ *                      for libLBFGS built with SSE/SSE2 optimization routine
+ *                      enabled. The library built without SSE/SSE2
+ *                      optimization does not have such a requirement.
+ *  @param  ptr_fx      The pointer to the variable that receives the final
+ *                      value of the objective function for the variables.
+ *                      This argument can be set to \c NULL if the final
+ *                      value of the objective function is unnecessary.
+ *  @param  proc_evaluate   The callback function to provide function and
+ *                          gradient evaluations given a current values of
+ *                          variables. A client program must implement a
+ *                          callback function compatible with \ref
+ *                          lbfgs_evaluate_t and pass the pointer to the
+ *                          callback function.
+ *  @param  proc_progress   The callback function to receive the progress
+ *                          (the number of iterations, the current value of
+ *                          the objective function) of the minimization
+ *                          process. This argument can be set to \c NULL if
+ *                          a progress report is unnecessary.
+ *  @param  instance    A user data for the client program. The callback
+ *                      functions will receive the value of this argument.
+ *  @param  param       The pointer to a structure representing parameters for
+ *                      L-BFGS optimization. A client program can set this
+ *                      parameter to \c NULL to use the default parameters.
+ *                      Call lbfgs_parameter_init() function to fill a
+ *                      structure with the default values.
+ *  @retval int         The status code. This function returns zero if the
+ *                      minimization process terminates without an error. A
+ *                      non-zero value indicates an error.
+ */
+int lbfgs(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *ptr_fx,
+    lbfgs_evaluate_t proc_evaluate,
+    lbfgs_progress_t proc_progress,
+    void *instance,
+    lbfgs_parameter_t *param
+    );
+
+/**
+ * Initialize L-BFGS parameters to the default values.
+ *
+ *  Call this function to fill a parameter structure with the default values
+ *  and overwrite parameter values if necessary.
+ *
+ *  @param  param       The pointer to the parameter structure.
+ */
+void lbfgs_parameter_init(lbfgs_parameter_t *param);
+
+/**
+ * Allocate an array for variables.
+ *
+ *  This function allocates an array of variables for the convenience of
+ *  ::lbfgs function; the function has a requreiemt for a variable array
+ *  when libLBFGS is built with SSE/SSE2 optimization routines. A user does
+ *  not have to use this function for libLBFGS built without SSE/SSE2
+ *  optimization.
+ *  
+ *  @param  n           The number of variables.
+ */
+lbfgsfloatval_t* lbfgs_malloc(int n);
+
+/**
+ * Free an array of variables.
+ *  
+ *  @param  x           The array of variables allocated by ::lbfgs_malloc
+ *                      function.
+ */
+void lbfgs_free(lbfgsfloatval_t *x);
+
+/** @} */
+
+#ifdef  __cplusplus
+}
+#endif/*__cplusplus*/
+
+
+
+/**
+ at mainpage libLBFGS: a library of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS)
+
+ at section intro Introduction
+
+This library is a C port of the implementation of Limited-memory
+Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal.
+The original FORTRAN source code is available at:
+http://www.ece.northwestern.edu/~nocedal/lbfgs.html
+
+The L-BFGS method solves the unconstrainted minimization problem,
+
+<pre>
+    minimize F(x), x = (x1, x2, ..., xN),
+</pre>
+
+only if the objective function F(x) and its gradient G(x) are computable. The
+well-known Newton's method requires computation of the inverse of the hessian
+matrix of the objective function. However, the computational cost for the
+inverse hessian matrix is expensive especially when the objective function
+takes a large number of variables. The L-BFGS method iteratively finds a
+minimizer by approximating the inverse hessian matrix by information from last
+m iterations. This innovation saves the memory storage and computational time
+drastically for large-scaled problems.
+
+Among the various ports of L-BFGS, this library provides several features:
+- <b>Optimization with L1-norm (Orthant-Wise Limited-memory Quasi-Newton
+  (OWL-QN) method)</b>:
+  In addition to standard minimization problems, the library can minimize
+  a function F(x) combined with L1-norm |x| of the variables,
+  {F(x) + C |x|}, where C is a constant scalar parameter. This feature is
+  useful for estimating parameters of sparse log-linear models (e.g.,
+  logistic regression and maximum entropy) with L1-regularization (or
+  Laplacian prior).
+- <b>Clean C code</b>:
+  Unlike C codes generated automatically by f2c (Fortran 77 into C converter),
+  this port includes changes based on my interpretations, improvements,
+  optimizations, and clean-ups so that the ported code would be well-suited
+  for a C code. In addition to comments inherited from the original code,
+  a number of comments were added through my interpretations.
+- <b>Callback interface</b>:
+  The library receives function and gradient values via a callback interface.
+  The library also notifies the progress of the optimization by invoking a
+  callback function. In the original implementation, a user had to set
+  function and gradient values every time the function returns for obtaining
+  updated values.
+- <b>Thread safe</b>:
+  The library is thread-safe, which is the secondary gain from the callback
+  interface.
+- <b>Cross platform.</b> The source code can be compiled on Microsoft Visual
+  Studio 2005, GNU C Compiler (gcc), etc.
+- <b>Configurable precision</b>: A user can choose single-precision (float)
+  or double-precision (double) accuracy by changing ::LBFGS_FLOAT macro.
+- <b>SSE/SSE2 optimization</b>:
+  This library includes SSE/SSE2 optimization (written in compiler intrinsics)
+  for vector arithmetic operations on Intel/AMD processors. The library uses
+  SSE for float values and SSE2 for double values. The SSE/SSE2 optimization
+  routine is disabled by default.
+
+This library is used by:
+- <a href="http://www.chokkan.org/software/crfsuite/">CRFsuite: A fast implementation of Conditional Random Fields (CRFs)</a>
+- <a href="http://www.chokkan.org/software/classias/">Classias: A collection of machine-learning algorithms for classification</a>
+- <a href="http://www.public.iastate.edu/~gdancik/mlegp/">mlegp: an R package for maximum likelihood estimates for Gaussian processes</a>
+- <a href="http://infmath.uibk.ac.at/~matthiasf/imaging2/">imaging2: the imaging2 class library</a>
+- <a href="http://search.cpan.org/~laye/Algorithm-LBFGS-0.16/">Algorithm::LBFGS - Perl extension for L-BFGS</a>
+- <a href="http://www.cs.kuleuven.be/~bernd/yap-lbfgs/">YAP-LBFGS (an interface to call libLBFGS from YAP Prolog)</a>
+
+ at section download Download
+
+- <a href="http://www.chokkan.org/software/dist/liblbfgs-1.9.tar.gz">Source code</a>
+
+libLBFGS is distributed under the term of the
+<a href="http://opensource.org/licenses/mit-license.php">MIT license</a>.
+
+ at section changelog History
+- Version 1.9 (2010-01-29):
+    - Fixed a mistake in checking the validity of the parameters "ftol" and
+      "wolfe"; this was discovered by Kevin S. Van Horn.
+- Version 1.8 (2009-07-13):
+    - Accepted the patch submitted by Takashi Imamichi;
+      the backtracking method now has three criteria for choosing the step
+      length:
+        - ::LBFGS_LINESEARCH_BACKTRACKING_ARMIJO: sufficient decrease (Armijo)
+          condition only
+        - ::LBFGS_LINESEARCH_BACKTRACKING_WOLFE: regular Wolfe condition
+          (sufficient decrease condition + curvature condition)
+        - ::LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE: strong Wolfe condition
+    - Updated the documentation to explain the above three criteria.
+- Version 1.7 (2009-02-28):
+    - Improved OWL-QN routines for stability.
+    - Removed the support of OWL-QN method in MoreThuente algorithm because
+      it accidentally fails in early stages of iterations for some objectives.
+      Because of this change, <b>the OW-LQN method must be used with the
+      backtracking algorithm (::LBFGS_LINESEARCH_BACKTRACKING)</b>, or the
+      library returns ::LBFGSERR_INVALID_LINESEARCH.
+    - Renamed line search algorithms as follows:
+        - ::LBFGS_LINESEARCH_BACKTRACKING: regular Wolfe condition.
+        - ::LBFGS_LINESEARCH_BACKTRACKING_LOOSE: regular Wolfe condition.
+        - ::LBFGS_LINESEARCH_BACKTRACKING_STRONG: strong Wolfe condition.
+    - Source code clean-up.
+- Version 1.6 (2008-11-02):
+    - Improved line-search algorithm with strong Wolfe condition, which was
+      contributed by Takashi Imamichi. This routine is now default for
+      ::LBFGS_LINESEARCH_BACKTRACKING. The previous line search algorithm
+      with regular Wolfe condition is still available as
+      ::LBFGS_LINESEARCH_BACKTRACKING_LOOSE.
+    - Configurable stop index for L1-norm computation. A member variable
+      ::lbfgs_parameter_t::orthantwise_end was added to specify the index
+      number at which the library stops computing the L1 norm of the
+      variables. This is useful to prevent some variables from being
+      regularized by the OW-LQN method.
+    - A sample program written in C++ (sample/sample.cpp).
+- Version 1.5 (2008-07-10):
+    - Configurable starting index for L1-norm computation. A member variable
+      ::lbfgs_parameter_t::orthantwise_start was added to specify the index
+      number from which the library computes the L1 norm of the variables.
+      This is useful to prevent some variables from being regularized by the
+      OWL-QN method.
+    - Fixed a zero-division error when the initial variables have already
+      been a minimizer (reported by Takashi Imamichi). In this case, the
+      library returns ::LBFGS_ALREADY_MINIMIZED status code.
+    - Defined ::LBFGS_SUCCESS status code as zero; removed unused constants,
+      LBFGSFALSE and LBFGSTRUE.
+    - Fixed a compile error in an implicit down-cast.
+- Version 1.4 (2008-04-25):
+    - Configurable line search algorithms. A member variable
+      ::lbfgs_parameter_t::linesearch was added to choose either MoreThuente
+      method (::LBFGS_LINESEARCH_MORETHUENTE) or backtracking algorithm
+      (::LBFGS_LINESEARCH_BACKTRACKING).
+    - Fixed a bug: the previous version did not compute psuedo-gradients
+      properly in the line search routines for OWL-QN. This bug might quit
+      an iteration process too early when the OWL-QN routine was activated
+      (0 < ::lbfgs_parameter_t::orthantwise_c).
+    - Configure script for POSIX environments.
+    - SSE/SSE2 optimizations with GCC.
+    - New functions ::lbfgs_malloc and ::lbfgs_free to use SSE/SSE2 routines
+      transparently. It is uncessary to use these functions for libLBFGS built
+      without SSE/SSE2 routines; you can still use any memory allocators if
+      SSE/SSE2 routines are disabled in libLBFGS.
+- Version 1.3 (2007-12-16):
+    - An API change. An argument was added to lbfgs() function to receive the
+      final value of the objective function. This argument can be set to
+      \c NULL if the final value is unnecessary.
+    - Fixed a null-pointer bug in the sample code (reported by Takashi Imamichi).
+    - Added build scripts for Microsoft Visual Studio 2005 and GCC.
+    - Added README file.
+- Version 1.2 (2007-12-13):
+    - Fixed a serious bug in orthant-wise L-BFGS.
+      An important variable was used without initialization.
+- Version 1.1 (2007-12-01):
+    - Implemented orthant-wise L-BFGS.
+    - Implemented lbfgs_parameter_init() function.
+    - Fixed several bugs.
+    - API documentation.
+- Version 1.0 (2007-09-20):
+    - Initial release.
+
+ at section api Documentation
+
+- @ref liblbfgs_api "libLBFGS API"
+
+ at section sample Sample code
+
+ at include sample.c
+
+ at section ack Acknowledgements
+
+The L-BFGS algorithm is described in:
+    - Jorge Nocedal.
+      Updating Quasi-Newton Matrices with Limited Storage.
+      <i>Mathematics of Computation</i>, Vol. 35, No. 151, pp. 773--782, 1980.
+    - Dong C. Liu and Jorge Nocedal.
+      On the limited memory BFGS method for large scale optimization.
+      <i>Mathematical Programming</i> B, Vol. 45, No. 3, pp. 503-528, 1989.
+
+The line search algorithms used in this implementation are described in:
+    - John E. Dennis and Robert B. Schnabel.
+      <i>Numerical Methods for Unconstrained Optimization and Nonlinear
+      Equations</i>, Englewood Cliffs, 1983.
+    - Jorge J. More and David J. Thuente.
+      Line search algorithm with guaranteed sufficient decrease.
+      <i>ACM Transactions on Mathematical Software (TOMS)</i>, Vol. 20, No. 3,
+      pp. 286-307, 1994.
+
+This library also implements Orthant-Wise Limited-memory Quasi-Newton (OWL-QN)
+method presented in:
+    - Galen Andrew and Jianfeng Gao.
+      Scalable training of L1-regularized log-linear models.
+      In <i>Proceedings of the 24th International Conference on Machine
+      Learning (ICML 2007)</i>, pp. 33-40, 2007.
+
+Special thanks go to:
+    - Yoshimasa Tsuruoka and Daisuke Okanohara for technical information about
+      OWL-QN
+    - Takashi Imamichi for the useful enhancements of the backtracking method
+
+Finally I would like to thank the original author, Jorge Nocedal, who has been
+distributing the effieicnt and explanatory implementation in an open source
+licence.
+
+ at section reference Reference
+
+- <a href="http://www.ece.northwestern.edu/~nocedal/lbfgs.html">L-BFGS</a> by Jorge Nocedal.
+- <a href="http://research.microsoft.com/en-us/downloads/b1eb1016-1738-4bd5-83a9-370c9d498a03/default.aspx">Orthant-Wise Limited-memory Quasi-Newton Optimizer for L1-regularized Objectives</a> by Galen Andrew.
+- <a href="http://chasen.org/~taku/software/misc/lbfgs/">C port (via f2c)</a> by Taku Kudo.
+- <a href="http://www.alglib.net/optimization/lbfgs.php">C#/C++/Delphi/VisualBasic6 port</a> in ALGLIB.
+- <a href="http://cctbx.sourceforge.net/">Computational Crystallography Toolbox</a> includes
+  <a href="http://cctbx.sourceforge.net/current_cvs/c_plus_plus/namespacescitbx_1_1lbfgs.html">scitbx::lbfgs</a>.
+*/
+
+#endif/*__LBFGS_H__*/
diff --git a/src/plfit/options.c b/src/plfit/options.c
new file mode 100644
index 0000000..564293a
--- /dev/null
+++ b/src/plfit/options.c
@@ -0,0 +1,47 @@
+/* options.c
+ *
+ * Copyright (C) 2012 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "error.h"
+#include "plfit.h"
+
+const plfit_continuous_options_t plfit_continuous_default_options = {
+  /* .finite_size_correction = */ 0,
+  /* .xmin_method = */ PLFIT_GSS_OR_LINEAR
+};
+
+const plfit_discrete_options_t plfit_discrete_default_options = {
+  /* .finite_size_correction = */ 0,
+  /* .alpha_method = */ PLFIT_LBFGS,
+  /* .alpha = */ {
+    /* .min = */ 1.01,
+    /* .max = */ 5,
+    /* .step = */ 0.01
+  }
+};
+
+int plfit_continuous_options_init(plfit_continuous_options_t* options) {
+	*options = plfit_continuous_default_options;
+	return PLFIT_SUCCESS;
+}
+
+int plfit_discrete_options_init(plfit_discrete_options_t* options) {
+	*options = plfit_discrete_default_options;
+	return PLFIT_SUCCESS;
+}
+
diff --git a/src/plfit/platform.h b/src/plfit/platform.h
new file mode 100644
index 0000000..f1c2f15
--- /dev/null
+++ b/src/plfit/platform.h
@@ -0,0 +1,54 @@
+/* platform.h
+ *
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * 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 __PLATFORM_H__
+#define __PLATFORM_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 <float.h>
+
+__BEGIN_DECLS
+
+#ifdef _MSC_VER
+#define snprintf sprintf_s
+#define inline  __inline
+#define isnan(x) _isnan(x)
+#define isfinite(x) _finite(x)
+#endif
+
+#ifndef INFINITY
+#  define INFINITY (1.0/0.0)
+#endif
+
+#ifndef NAN
+#  define NAN (INFINITY-INFINITY)
+#endif
+
+__END_DECLS
+
+#endif /* __PLATFORM_H__ */
diff --git a/src/plfit/plfit.c b/src/plfit/plfit.c
new file mode 100644
index 0000000..f0a8aa1
--- /dev/null
+++ b/src/plfit/plfit.c
@@ -0,0 +1,778 @@
+/* plfit.c
+ *
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "gss.h"
+#include "lbfgs.h"
+#include "platform.h"
+#include "plfit.h"
+#include "kolmogorov.h"
+#include "zeta.h"
+
+/* #define PLFIT_DEBUG */
+
+#define DATA_POINTS_CHECK \
+    if (n <= 0) { \
+        PLFIT_ERROR("no data points", PLFIT_EINVAL); \
+    }
+
+#define XMIN_CHECK_ZERO \
+    if (xmin <= 0) { \
+        PLFIT_ERROR("xmin must be greater than zero", PLFIT_EINVAL); \
+    }
+#define XMIN_CHECK_ONE \
+    if (xmin < 1) { \
+        PLFIT_ERROR("xmin must be at least 1", PLFIT_EINVAL); \
+    }
+
+static int double_comparator(const void *a, const void *b) {
+    const double *da = (const double*)a;
+    const double *db = (const double*)b;
+    return (*da > *db) - (*da < *db);
+}
+
+/**
+ * Given a sorted array of doubles, return another array that contains pointers
+ * into the array for the start of each block of identical elements.
+ *
+ * \param  begin          pointer to the beginning of the array
+ * \param  end            pointer to the first element after the end of the array
+ * \param  result_length  if not \c NULL, the number of unique elements in the
+ *                        given array is returned here
+ */
+static double** unique_element_pointers(double* begin, double* end, size_t* result_length) {
+    double* ptr = begin;
+    double** result;
+    double prev_x;
+    size_t num_elts = 15;
+    size_t used_elts = 0;
+
+    /* Special case: empty array */
+    if (begin == end) {
+        result = calloc(1, sizeof(double*));
+        if (result != 0) {
+            result[0] = 0;
+        }
+        return result;
+    }
+
+    /* Allocate initial result array, including the guard element */
+    result = calloc(num_elts+1, sizeof(double*));
+    if (result == 0)
+        return 0;
+
+    prev_x = *begin;
+    result[used_elts++] = begin;
+
+    /* Process the input array */
+    for (ptr = begin+1; ptr < end; ptr++) {
+        if (*ptr == prev_x)
+            continue;
+
+        /* New block found */
+        if (used_elts >= num_elts) {
+            /* Array full; allocate a new chunk */
+            num_elts = num_elts*2 + 1;
+            result = realloc(result, sizeof(double*) * (num_elts+1));
+            if (result == 0)
+                return 0;
+        }
+
+        /* Store the new element */
+        result[used_elts++] = ptr;
+        prev_x = *ptr;
+    }
+
+    /* Calculate the result length */
+    if (result_length != 0) {
+        *result_length = used_elts;
+    }
+
+    /* Add the guard entry to the end of the result */
+    result[used_elts++] = 0;
+
+    return result;
+}
+
+static void plfit_i_perform_finite_size_correction(plfit_result_t* result, size_t n) {
+    result->alpha = result->alpha * (n-1) / n + 1.0 / n;
+}
+
+/********** Continuous power law distribution fitting **********/
+
+void plfit_i_logsum_less_than_continuous(double* begin, double* end,
+        double xmin, double* result, size_t* m) {
+    double logsum = 0.0;
+    size_t count = 0;
+
+    for (; begin != end; begin++) {
+        if (*begin >= xmin) {
+            count++;
+            logsum += log(*begin / xmin);
+        }
+    }
+
+    *m = count;
+    *result = logsum;
+}
+
+double plfit_i_logsum_continuous(double* begin, double* end, double xmin) {
+    double logsum = 0.0;
+    for (; begin != end; begin++)
+        logsum += log(*begin / xmin);
+    return logsum;
+}
+
+int plfit_i_estimate_alpha_continuous(double* xs, size_t n,
+        double xmin, double* alpha) {
+    double result;
+    size_t m;
+
+    XMIN_CHECK_ZERO;
+
+    plfit_i_logsum_less_than_continuous(xs, xs+n, xmin, &result, &m);
+
+    if (m == 0) {
+        PLFIT_ERROR("no data point was larger than xmin", PLFIT_EINVAL);
+    }
+
+    *alpha = 1 + m / result;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_i_estimate_alpha_continuous_sorted(double* xs, size_t n,
+        double xmin, double* alpha) {
+	double* end = xs+n;
+
+    XMIN_CHECK_ZERO;
+
+    for (; xs != end && *xs < xmin; xs++);
+    if (xs == end) {
+        PLFIT_ERROR("no data point was larger than xmin", PLFIT_EINVAL);
+    }
+
+    *alpha = 1 + (end-xs) / plfit_i_logsum_continuous(xs, end, xmin);
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_ks_test_continuous(double* xs, double* xs_end,
+        const double alpha, const double xmin, double* D) {
+    /* Assumption: xs is sorted and cut off at xmin so the first element is
+     * always larger than or equal to xmin. */
+    double result = 0, n;
+    int m = 0;
+
+    n = xs_end - xs;
+
+    while (xs < xs_end) {
+        double d = fabs(1-pow(xmin / *xs, alpha-1) - m / n);
+
+        if (d > result)
+            result = d;
+
+        xs++; m++;
+    }
+
+    *D = result;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_log_likelihood_continuous(double* xs, size_t n, double alpha,
+        double xmin, double* L) {
+    double logsum, c;
+    size_t m;
+
+    if (alpha <= 1) {
+        PLFIT_ERROR("alpha must be greater than one", PLFIT_EINVAL);
+    }
+    XMIN_CHECK_ZERO;
+
+    c = (alpha - 1) / xmin;
+    plfit_i_logsum_less_than_continuous(xs, xs+n, xmin, &logsum, &m);
+    *L = -alpha * logsum + log(c) * m;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_estimate_alpha_continuous(double* xs, size_t n, double xmin,
+        const plfit_continuous_options_t* options, plfit_result_t *result) {
+    double *xs_copy;
+
+	if (!options)
+		options = &plfit_continuous_default_options;
+
+    /* Make a copy of xs and sort it */
+    xs_copy = (double*)malloc(sizeof(double) * n);
+    memcpy(xs_copy, xs, sizeof(double) * n);
+    qsort(xs_copy, n, sizeof(double), double_comparator);
+
+    PLFIT_CHECK(plfit_estimate_alpha_continuous_sorted(xs_copy, n, xmin,
+				options, result));
+
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_estimate_alpha_continuous_sorted(double* xs, size_t n, double xmin,
+        const plfit_continuous_options_t* options, plfit_result_t *result) {
+    double* end;
+
+	if (!options)
+		options = &plfit_continuous_default_options;
+
+	end = xs + n;
+    while (xs < end && *xs < xmin)
+        xs++;
+    n = (size_t) (end - xs);
+
+    PLFIT_CHECK(plfit_i_estimate_alpha_continuous_sorted(xs, n,
+				xmin, &result->alpha));
+    PLFIT_CHECK(plfit_i_ks_test_continuous(xs, end, result->alpha,
+				xmin, &result->D));
+
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, n);
+    result->xmin = xmin;
+    result->p = plfit_ks_test_one_sample_p(result->D, n);
+    plfit_log_likelihood_continuous(xs, n, result->alpha, result->xmin, &result->L);
+
+    return PLFIT_SUCCESS;
+}
+
+typedef struct {
+	double *begin;        /**< Pointer to the beginning of the array holding the data */
+	double *end;          /**< Pointer to after the end of the array holding the data */
+	double **uniques;     /**< Pointers to unique elements of the input array */
+	plfit_result_t last;  /**< Result of the last evaluation */
+} plfit_continuous_xmin_opt_data_t;
+
+double plfit_i_continuous_xmin_opt_evaluate(void* instance, double x) {
+	plfit_continuous_xmin_opt_data_t* data = (plfit_continuous_xmin_opt_data_t*)instance;
+	double* begin = data->uniques[(int)x];
+
+	data->last.xmin = *begin;
+
+#ifdef PLFIT_DEBUG
+	printf("Trying with xmin = %.4f\n", *begin);
+#endif
+
+	plfit_i_estimate_alpha_continuous_sorted(begin, (size_t) (data->end-begin), *begin,
+			&data->last.alpha);
+	plfit_i_ks_test_continuous(begin, data->end, data->last.alpha, *begin,
+			&data->last.D);
+
+	return data->last.D;
+}
+
+int plfit_i_continuous_xmin_opt_progress(void* instance, double x, double fx,
+		double min, double fmin, double left, double right, int k) {
+#ifdef PLFIT_DEBUG
+    printf("Iteration #%d: [%.4f; %.4f), x=%.4f, fx=%.4f, min=%.4f, fmin=%.4f\n",
+            k, left, right, x, fx, min, fmin);
+#endif
+
+	/* Continue only if `left' and `right' point to different integers */
+	return (int)left == (int)right;
+}
+
+int plfit_continuous(double* xs, size_t n, const plfit_continuous_options_t* options,
+        plfit_result_t* result) {
+	gss_parameter_t gss_param;
+	plfit_continuous_xmin_opt_data_t opt_data;
+	plfit_result_t best_result;
+	int success;
+	size_t i, best_n, num_uniques;
+    double x, *px;
+
+    DATA_POINTS_CHECK;
+
+	if (!options)
+		options = &plfit_continuous_default_options;
+
+    /* Make a copy of xs and sort it */
+    opt_data.begin = (double*)malloc(sizeof(double) * n);
+    memcpy(opt_data.begin, xs, sizeof(double) * n);
+    qsort(opt_data.begin, n, sizeof(double), double_comparator);
+    opt_data.end = opt_data.begin + n;
+
+    /* Create an array containing pointers to the unique elements of the input. From
+     * each block of unique elements, we add the pointer to the first one. */
+    opt_data.uniques = unique_element_pointers(opt_data.begin, opt_data.end,
+			&num_uniques);
+    if (opt_data.uniques == 0)
+        return PLFIT_ENOMEM;
+
+    /* We will now determine the best xmin that yields the lowest D-score.
+	 * First we try a golden section search if needed. If that fails, we try
+	 * a linear search.
+     */
+	if (options->xmin_method == PLFIT_GSS_OR_LINEAR && num_uniques > 5) {
+		gss_parameter_init(&gss_param);
+		success = (gss(0, num_uniques-5, &x, 0,
+				plfit_i_continuous_xmin_opt_evaluate,
+				plfit_i_continuous_xmin_opt_progress, &opt_data, &gss_param) == 0);
+		best_result = opt_data.last;
+		/* plfit_i_continuous_xmin_opt_evaluate will set opt_data.last to
+		 * indicate the location of the optimum and the value of D */
+	} else {
+		success = 0;
+	}
+
+	if (success) {
+		/* calculate best_n because we'll need it later. Luckily x indicates
+		 * the index in opt_data.uniques that we have to look up in order to
+		 * find the first element in the array that is included */
+		px = opt_data.uniques[(int)x];
+		best_n = (size_t) (opt_data.end-px+1);
+	} else {
+		/* GSS failed or skipped; try linear search */
+
+		/* Prepare some variables */
+		best_n = 0;
+		best_result.D = DBL_MAX;
+		best_result.xmin = 0;
+		best_result.alpha = 0;
+		
+		for (i = 0; i < num_uniques-1; i++) {
+			plfit_i_continuous_xmin_opt_evaluate(&opt_data, i);
+			if (opt_data.last.D < best_result.D) {
+				best_result = opt_data.last;
+				best_n = (size_t) (opt_data.end - 
+						   opt_data.uniques[i] + 1);
+			}
+		}
+	}
+
+    /* Get rid of the uniques array, we don't need it any more */
+    free(opt_data.uniques);
+
+    /* Sort out the result */
+    *result = best_result;
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, best_n);
+    result->p = plfit_ks_test_one_sample_p(result->D, best_n);
+    plfit_log_likelihood_continuous(opt_data.begin + n - best_n, best_n,
+			result->alpha, result->xmin, &result->L);
+
+    /* Get rid of the copied data as well */
+    free(opt_data.begin);
+
+    return PLFIT_SUCCESS;
+}
+
+/********** Discrete power law distribution fitting **********/
+
+typedef struct {
+    size_t m;
+    double logsum;
+    double xmin;
+} plfit_i_estimate_alpha_discrete_data_t;
+
+double plfit_i_logsum_discrete(double* begin, double* end, double xmin) {
+    double logsum = 0.0;
+    for (; begin != end; begin++)
+        logsum += log(*begin);
+    return logsum;
+}
+
+void plfit_i_logsum_less_than_discrete(double* begin, double* end, double xmin,
+        double* logsum, size_t* m) {
+    double result = 0.0;
+    size_t count = 0;
+
+    for (; begin != end; begin++) {
+        if (*begin < xmin)
+            continue;
+
+        result += log(*begin);
+        count++;
+    }
+
+    *logsum = result;
+    *m = count;
+}
+
+lbfgsfloatval_t plfit_i_estimate_alpha_discrete_lbfgs_evaluate(
+        void* instance, const lbfgsfloatval_t* x,
+        lbfgsfloatval_t* g, const int n,
+        const lbfgsfloatval_t step) {
+    plfit_i_estimate_alpha_discrete_data_t* data;
+    lbfgsfloatval_t result;
+    double dx = step;
+    double huge = 1e10;     /* pseudo-infinity; apparently DBL_MAX does not work */
+
+    data = (plfit_i_estimate_alpha_discrete_data_t*)instance;
+
+#ifdef PLFIT_DEBUG
+    printf("- Evaluating at %.4f (step = %.4f, xmin = %.4f)\n", *x, step, data->xmin);
+#endif
+
+	if (isnan(*x)) {
+		g[0] = huge;
+		return huge;
+	}
+
+    /* Find the delta X value to estimate the gradient */
+    if (dx > 0.001 || dx == 0)
+        dx = 0.001;
+    else if (dx < -0.001)
+        dx = -0.001;
+
+	/* Is x[0] in its valid range? */
+	if (x[0] <= 1.0) {
+		/* The Hurwitz zeta function is infinite in this case */
+        g[0] = (dx > 0) ? -huge : huge;
+		return huge;
+	}
+	if (x[0] + dx <= 1.0)
+		g[0] = huge;
+	else
+		g[0] = data->logsum + data->m *
+			(log(gsl_sf_hzeta(x[0] + dx, data->xmin)) - log(gsl_sf_hzeta(x[0], data->xmin))) / dx;
+
+    result = x[0] * data->logsum + data->m * log(gsl_sf_hzeta(x[0], data->xmin));
+
+#ifdef PLFIT_DEBUG
+    printf("  - Gradient: %.4f\n", g[0]);
+    printf("  - Result: %.4f\n", result);
+#endif
+
+    return result;
+}
+
+int plfit_i_estimate_alpha_discrete_lbfgs_progress(void* instance,
+        const lbfgsfloatval_t* x, const lbfgsfloatval_t* g,
+        const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm,
+        const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step,
+        int n, int k, int ls) {
+    return 0;
+}
+
+int plfit_i_estimate_alpha_discrete_linear_scan(double* xs, size_t n, double xmin,
+        double* alpha, const plfit_discrete_options_t* options,
+		plfit_bool_t sorted) {
+    double curr_alpha, best_alpha, L, L_max;
+    double logsum;
+    size_t m;
+
+    XMIN_CHECK_ONE;
+	if (options->alpha.min <= 1.0) {
+		PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
+	}
+	if (options->alpha.max < options->alpha.min) {
+		PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
+	}
+	if (options->alpha.step <= 0) {
+		PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
+	}
+
+    if (sorted) {
+        logsum = plfit_i_logsum_discrete(xs, xs+n, xmin);
+        m = n;
+    } else {
+        plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &logsum, &m);
+    }
+
+    best_alpha = options->alpha.min; L_max = -DBL_MAX;
+    for (curr_alpha = options->alpha.min; curr_alpha <= options->alpha.max;
+			curr_alpha += options->alpha.step) {
+        L = -curr_alpha * logsum - m * log(gsl_sf_hzeta(curr_alpha, xmin));
+        if (L > L_max) {
+            L_max = L;
+            best_alpha = curr_alpha;
+        }
+    }
+
+    *alpha = best_alpha;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_i_estimate_alpha_discrete_lbfgs(double* xs, size_t n, double xmin,
+		double* alpha, const plfit_discrete_options_t* options, plfit_bool_t sorted) {
+    lbfgs_parameter_t param;
+    lbfgsfloatval_t* variables;
+    plfit_i_estimate_alpha_discrete_data_t data;
+    int ret;
+
+    XMIN_CHECK_ONE;
+
+    /* Initialize algorithm parameters */
+    lbfgs_parameter_init(&param);
+    param.max_iterations = 0;   /* proceed until infinity */
+
+    /* Set up context for optimization */
+    data.xmin = xmin;
+    if (sorted) {
+        data.logsum = plfit_i_logsum_discrete(xs, xs+n, xmin);
+        data.m = n;
+    } else {
+        plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &data.logsum, &data.m);
+    }
+
+    /* Allocate space for the single alpha variable */
+    variables = lbfgs_malloc(1);
+    variables[0] = 3.0;       /* initial guess */
+
+    /* Optimization */
+    ret = lbfgs(1, variables, /* ptr_fx = */ 0,
+            plfit_i_estimate_alpha_discrete_lbfgs_evaluate,
+            plfit_i_estimate_alpha_discrete_lbfgs_progress,
+            &data, &param);
+
+    if (ret < 0 &&
+        ret != LBFGSERR_ROUNDING_ERROR &&
+        ret != LBFGSERR_MAXIMUMLINESEARCH &&
+        ret != LBFGSERR_CANCELED) {
+        char buf[4096];
+        snprintf(buf, 4096, "L-BFGS optimization signaled an error (error code = %d)", ret);
+        lbfgs_free(variables);
+        PLFIT_ERROR(buf, PLFIT_FAILURE);
+    }
+    *alpha = variables[0];
+    
+    /* Deallocate the variable array */
+    lbfgs_free(variables);
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_i_estimate_alpha_discrete_fast(double* xs, size_t n, double xmin,
+        double* alpha, const plfit_discrete_options_t* options, plfit_bool_t sorted) {
+	plfit_continuous_options_t cont_options;
+
+	if (!options)
+		options = &plfit_discrete_default_options;
+
+	plfit_continuous_options_init(&cont_options);
+	cont_options.finite_size_correction = options->finite_size_correction;
+
+    XMIN_CHECK_ONE;
+
+	if (sorted) {
+		return plfit_i_estimate_alpha_continuous_sorted(xs, n, xmin-0.5, alpha);
+	} else {
+		return plfit_i_estimate_alpha_continuous(xs, n, xmin-0.5, alpha);
+	}
+}
+
+int plfit_i_estimate_alpha_discrete(double* xs, size_t n, double xmin,
+		double* alpha, const plfit_discrete_options_t* options,
+		plfit_bool_t sorted) {
+	switch (options->alpha_method) {
+		case PLFIT_LBFGS:
+			PLFIT_CHECK(plfit_i_estimate_alpha_discrete_lbfgs(xs, n, xmin, alpha,
+						options, sorted));
+			break;
+
+		case PLFIT_LINEAR_SCAN:
+			PLFIT_CHECK(plfit_i_estimate_alpha_discrete_linear_scan(xs, n, xmin,
+						alpha, options, sorted));
+			break;
+
+		case PLFIT_PRETEND_CONTINUOUS:
+			PLFIT_CHECK(plfit_i_estimate_alpha_discrete_fast(xs, n, xmin,
+						alpha, options, sorted));
+			break;
+
+		default:
+			PLFIT_ERROR("unknown optimization method specified", PLFIT_EINVAL);
+	}
+
+	return PLFIT_SUCCESS;
+}
+
+static int plfit_i_ks_test_discrete(double* xs, double* xs_end, const double alpha,
+        const double xmin, double* D) {
+    /* Assumption: xs is sorted and cut off at xmin so the first element is
+     * always larger than or equal to xmin. */
+    double result = 0, n, hzeta, x;
+    int m = 0;
+
+    n = xs_end - xs;
+    hzeta = gsl_sf_hzeta(alpha, xmin);
+
+    while (xs < xs_end) {
+        double d;
+
+        x = *xs;
+        d = fabs(1-(gsl_sf_hzeta(alpha, x) / hzeta) - m / n);
+
+        if (d > result)
+            result = d;
+
+        do {
+            xs++; m++;
+        } while (xs < xs_end && *xs == x);
+    }
+
+    *D = result;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_log_likelihood_discrete(double* xs, size_t n, double alpha, double xmin, double* L) {
+    double result;
+    size_t m;
+
+    if (alpha <= 1) {
+        PLFIT_ERROR("alpha must be greater than one", PLFIT_EINVAL);
+    }
+    XMIN_CHECK_ONE;
+
+    plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &result, &m);
+    result = - alpha * result - m * log(gsl_sf_hzeta(alpha, xmin));
+
+    *L = result;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_estimate_alpha_discrete(double* xs, size_t n, double xmin,
+        const plfit_discrete_options_t* options, plfit_result_t *result) {
+    double *xs_copy, *end;
+
+	if (!options)
+		options = &plfit_discrete_default_options;
+
+	/* Check the validity of the input parameters */
+    DATA_POINTS_CHECK;
+	if (options->alpha_method == PLFIT_LINEAR_SCAN) {
+		if (options->alpha.min <= 1.0) {
+			PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
+		}
+		if (options->alpha.max < options->alpha.min) {
+			PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
+		}
+		if (options->alpha.step <= 0) {
+			PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
+		}
+	}
+
+    /* Make a copy of xs and sort it */
+    xs_copy = (double*)malloc(sizeof(double) * n);
+    memcpy(xs_copy, xs, sizeof(double) * n);
+    qsort(xs_copy, n, sizeof(double), double_comparator);
+
+    xs = xs_copy; end = xs_copy + n;
+    while (xs < end && *xs < xmin)
+        xs++;
+    n = (size_t) (end - xs);
+
+    PLFIT_CHECK(plfit_i_estimate_alpha_discrete(xs, n, xmin, &result->alpha,
+				options, /* sorted = */ 1));
+    PLFIT_CHECK(plfit_i_ks_test_discrete(xs, end, result->alpha, xmin, &result->D));
+
+    result->xmin = xmin;
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, n);
+    result->p = plfit_ks_test_one_sample_p(result->D, n);
+    plfit_log_likelihood_discrete(xs, n, result->alpha, result->xmin, &result->L);
+
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_discrete(double* xs, size_t n, const plfit_discrete_options_t* options,
+        plfit_result_t* result) {
+    double curr_D, curr_alpha;
+    plfit_result_t best_result;
+    double *xs_copy, *px, *end, *end_xmin, prev_x;
+	size_t best_n;
+    size_t m;
+
+	if (!options)
+		options = &plfit_discrete_default_options;
+
+	/* Check the validity of the input parameters */
+    DATA_POINTS_CHECK;
+	if (options->alpha_method == PLFIT_LINEAR_SCAN) {
+		if (options->alpha.min <= 1.0) {
+			PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
+		}
+		if (options->alpha.max < options->alpha.min) {
+			PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
+		}
+		if (options->alpha.step <= 0) {
+			PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
+		}
+	}
+
+    /* Make a copy of xs and sort it */
+    xs_copy = (double*)malloc(sizeof(double) * n);
+    memcpy(xs_copy, xs, sizeof(double) * n);
+    qsort(xs_copy, n, sizeof(double), double_comparator);
+
+    best_result.D = DBL_MAX;
+    best_result.xmin = 1;
+    best_result.alpha = 1;
+	best_n = 0;
+
+    /* Make sure there are at least three distinct values if possible */
+    px = xs_copy; end = px + n; end_xmin = end - 1; m = 0;
+    prev_x = *end_xmin;
+    while (*end_xmin == prev_x && end_xmin > px)
+        end_xmin--;
+    prev_x = *end_xmin;
+    while (*end_xmin == prev_x && end_xmin > px)
+        end_xmin--;
+
+    prev_x = 0;
+    while (px < end_xmin) {
+        while (px < end_xmin && *px == prev_x) {
+            px++; m++;
+        }
+
+	plfit_i_estimate_alpha_discrete(px, n - m, *px,
+					&curr_alpha, options, /* sorted = */ 1);
+        plfit_i_ks_test_discrete(px, end, curr_alpha, *px, &curr_D);
+
+        if (curr_D < best_result.D) {
+            best_result.alpha = curr_alpha;
+            best_result.xmin = *px;
+            best_result.D = curr_D;
+	    best_n = n - m;
+        }
+
+        prev_x = *px;
+        px++; m++;
+    }
+
+    *result = best_result;
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, best_n);
+    result->p = plfit_ks_test_one_sample_p(result->D, best_n);
+    plfit_log_likelihood_discrete(xs_copy+(n-best_n), best_n,
+			result->alpha, result->xmin, &result->L);
+
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
diff --git a/src/plfit/plfit.h b/src/plfit/plfit.h
new file mode 100644
index 0000000..e9434bf
--- /dev/null
+++ b/src/plfit/plfit.h
@@ -0,0 +1,109 @@
+/* plfit.h
+ * 
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * 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 __PLFIT_H__
+#define __PLFIT_H__
+
+#include <stdlib.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 PLFIT_VERSION_MAJOR 0
+#define PLFIT_VERSION_MINOR 6
+#define PLFIT_VERSION_STRING "0.6"
+
+typedef unsigned short int plfit_bool_t;
+
+typedef enum {
+	PLFIT_GSS_OR_LINEAR,
+	PLFIT_LINEAR_ONLY,
+	PLFIT_DEFAULT_CONTINUOUS_METHOD = PLFIT_GSS_OR_LINEAR
+} plfit_continuous_method_t;
+
+typedef enum {
+	PLFIT_LBFGS,
+	PLFIT_LINEAR_SCAN,
+	PLFIT_PRETEND_CONTINUOUS,
+	PLFIT_DEFAULT_DISCRETE_METHOD = PLFIT_LBFGS
+} plfit_discrete_method_t;
+
+typedef struct _plfit_result_t {
+	double alpha;     /* fitted power-law exponent */
+	double xmin;      /* cutoff where the power-law behaviour kicks in */
+	double L;         /* log-likelihood of the sample */
+	double D;         /* test statistic for the KS test */
+	double p;         /* p-value of the KS test */
+} plfit_result_t;
+
+/********** structure that holds the options of plfit **********/
+
+typedef struct _plfit_continuous_options_t {
+	plfit_bool_t finite_size_correction;
+	plfit_continuous_method_t xmin_method;
+} plfit_continuous_options_t;
+
+typedef struct _plfit_discrete_options_t {
+	plfit_bool_t finite_size_correction;
+	plfit_discrete_method_t alpha_method;
+	struct {
+		double min;
+		double max;
+		double step;
+	} alpha;
+} plfit_discrete_options_t;
+
+int plfit_continuous_options_init(plfit_continuous_options_t* options);
+int plfit_discrete_options_init(plfit_discrete_options_t* options);
+
+extern const plfit_continuous_options_t plfit_continuous_default_options;
+extern const plfit_discrete_options_t plfit_discrete_default_options;
+
+/********** continuous power law distribution fitting **********/
+
+int plfit_log_likelihood_continuous(double* xs, size_t n, double alpha,
+		double xmin, double* l);
+int plfit_estimate_alpha_continuous(double* xs, size_t n, double xmin,
+        const plfit_continuous_options_t* options, plfit_result_t* result);
+int plfit_estimate_alpha_continuous_sorted(double* xs, size_t n, double xmin,
+        const plfit_continuous_options_t* options, plfit_result_t* result);
+int plfit_continuous(double* xs, size_t n,
+		const plfit_continuous_options_t* options, plfit_result_t* result);
+
+/********** discrete power law distribution fitting **********/
+
+int plfit_estimate_alpha_discrete(double* xs, size_t n, double xmin,
+        const plfit_discrete_options_t* options, plfit_result_t *result);
+int plfit_log_likelihood_discrete(double* xs, size_t n, double alpha, double xmin, double* l);
+int plfit_discrete(double* xs, size_t n, const plfit_discrete_options_t* options,
+		plfit_result_t* result);
+
+__END_DECLS
+
+#endif /* __PLFIT_H__ */
+
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/plfit/zeta.c b/src/plfit/zeta.c
new file mode 100644
index 0000000..c0bf6a4
--- /dev/null
+++ b/src/plfit/zeta.c
@@ -0,0 +1,154 @@
+/* specfunc/zeta.c
+ * 
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* Author:  G. Jungman */
+
+/* This file was taken from the GNU Scientific Library. Some modifications
+ * were done in order to make it independent from the rest of GSL
+ */
+
+/*
+#include <config.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_sf_elementary.h>
+#include <gsl/gsl_sf_exp.h>
+#include <gsl/gsl_sf_gamma.h>
+#include <gsl/gsl_sf_pow_int.h>
+#include <gsl/gsl_sf_zeta.h>
+
+#include "error.h"
+
+#include "chebyshev.h"
+#include "cheb_eval.c"
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include "error.h"
+
+/*-*-*-*-*-*-*-*-*-*- From gsl_machine.h -*-*-*-*-*-*-*-*-*-*-*-*-*/
+
+#define GSL_LOG_DBL_MIN   (-7.0839641853226408e+02)
+#define GSL_LOG_DBL_MAX    7.0978271289338397e+02
+#define GSL_DBL_EPSILON        2.2204460492503131e-16
+
+/*-*-*-*-*-*-*-*-*-* From gsl_sf_result.h *-*-*-*-*-*-*-*-*-*-*-*/
+
+struct gsl_sf_result_struct {
+  double val;
+  double err;
+};
+typedef struct gsl_sf_result_struct gsl_sf_result;
+
+/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/
+
+/* coefficients for Maclaurin summation in hzeta()
+ * B_{2j}/(2j)!
+ */
+static double hzeta_c[15] = {
+  1.00000000000000000000000000000,
+  0.083333333333333333333333333333,
+ -0.00138888888888888888888888888889,
+  0.000033068783068783068783068783069,
+ -8.2671957671957671957671957672e-07,
+  2.0876756987868098979210090321e-08,
+ -5.2841901386874931848476822022e-10,
+  1.3382536530684678832826980975e-11,
+ -3.3896802963225828668301953912e-13,
+  8.5860620562778445641359054504e-15,
+ -2.1748686985580618730415164239e-16,
+  5.5090028283602295152026526089e-18,
+ -1.3954464685812523340707686264e-19,
+  3.5347070396294674716932299778e-21,
+ -8.9535174270375468504026113181e-23
+};
+
+/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/
+
+static int gsl_sf_hzeta_e(const double s, const double q, gsl_sf_result * result)
+{
+  /* CHECK_POINTER(result) */
+
+  if(s <= 1.0 || q <= 0.0) {
+	PLFIT_ERROR("s must be larger than 1.0 and q must be larger than zero", PLFIT_EINVAL);
+  }
+  else {
+    const double max_bits = 54.0;
+    const double ln_term0 = -s * log(q);  
+
+    if(ln_term0 < GSL_LOG_DBL_MIN + 1.0) {
+	  PLFIT_ERROR("underflow", PLFIT_UNDRFLOW);
+    }
+    else if(ln_term0 > GSL_LOG_DBL_MAX - 1.0) {
+	  PLFIT_ERROR("overflow", PLFIT_OVERFLOW);
+    }
+    else if((s > max_bits && q < 1.0) || (s > 0.5*max_bits && q < 0.25)) {
+      result->val = pow(q, -s);
+      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);
+      return PLFIT_SUCCESS;
+    }
+    else if(s > 0.5*max_bits && q < 1.0) {
+      const double p1 = pow(q, -s);
+      const double p2 = pow(q/(1.0+q), s);
+      const double p3 = pow(q/(2.0+q), s);
+      result->val = p1 * (1.0 + p2 + p3);
+      result->err = GSL_DBL_EPSILON * (0.5*s + 2.0) * fabs(result->val);
+      return PLFIT_SUCCESS;
+    }
+    else {
+      /* Euler-Maclaurin summation formula 
+       * [Moshier, p. 400, with several typo corrections]
+       */
+      const int jmax = 12;
+      const int kmax = 10;
+      int j, k;
+      const double pmax  = pow(kmax + q, -s);
+      double scp = s;
+      double pcp = pmax / (kmax + q);
+      double ans = pmax*((kmax+q)/(s-1.0) + 0.5);
+
+      for(k=0; k<kmax; k++) {
+        ans += pow(k + q, -s);
+      }
+
+      for(j=0; j<=jmax; j++) {
+        double delta = hzeta_c[j+1] * scp * pcp;
+        ans += delta;
+        if(fabs(delta/ans) < 0.5*GSL_DBL_EPSILON) break;
+        scp *= (s+2*j+1)*(s+2*j+2);
+        pcp /= (kmax + q)*(kmax + q);
+      }
+
+      result->val = ans;
+      result->err = 2.0 * (jmax + 1.0) * GSL_DBL_EPSILON * fabs(ans);
+      return PLFIT_SUCCESS;
+    }
+  }
+}
+
+/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/
+
+double gsl_sf_hzeta(const double s, const double a)
+{
+  gsl_sf_result result;
+  gsl_sf_hzeta_e(s, a, &result);
+  return result.val;
+}
+
diff --git a/src/plfit/zeta.h b/src/plfit/zeta.h
new file mode 100644
index 0000000..ebee38b
--- /dev/null
+++ b/src/plfit/zeta.h
@@ -0,0 +1,53 @@
+/* specfunc/gsl_sf_zeta.h
+ * 
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* Author:  G. Jungman */
+
+/* This file was taken from the GNU Scientific Library. Some modifications
+ * were done in order to make it independent from the rest of GSL
+ */
+
+#ifndef __ZETA_H__
+#define __ZETA_H__
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+__BEGIN_DECLS
+
+
+/* Hurwitz Zeta Function
+ * zeta(s,q) = Sum[ (k+q)^(-s), {k,0,Infinity} ]
+ *
+ * s > 1.0, q > 0.0
+ */
+double gsl_sf_hzeta(const double s, const double q);
+
+
+__END_DECLS
+
+#endif /* __ZETA_H__ */
+
diff --git a/src/pottsmodel_2.cpp b/src/pottsmodel_2.cpp
new file mode 100644
index 0000000..6ac94bf
--- /dev/null
+++ b/src/pottsmodel_2.cpp
@@ -0,0 +1,2302 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by J�rg Reichardt 
+   This file was modified by Vincent Traag
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          pottsmodel.cpp  -  description
+                             -------------------
+    begin                : Fri May 28 2004
+    copyright            : (C) 2004 by 
+    email                : 
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <cmath>
+#include "pottsmodel_2.h"
+#include "NetRoutines.h"
+
+using namespace std;
+
+#include "igraph_random.h"
+#include "igraph_interrupt_internal.h"
+#include "config.h"
+
+//#################################################################################################
+PottsModel::PottsModel(network *n, unsigned int qvalue, int m) : acceptance(0)
+{
+  DLList_Iter<NNode*> iter;
+  NNode *n_cur;
+  unsigned int *i_ptr;
+  net=n;
+  q=qvalue;
+  operation_mode=m;
+  k_max=0;
+  //needed in calculating modularity
+  Qa     =new double[q+1];
+  //weights for each spin state needed in Monte Carlo process
+  weights=new double[q+1];
+  //bookkeeping of occupation numbers of spin states or the number of links in community
+  color_field=new double[q+1];
+  neighbours=new double[q+1];
+
+  num_of_nodes=net->node_list->Size();
+  num_of_links=net->link_list->Size();
+  
+  n_cur=iter.First(net->node_list);
+  //these lists are needed to keep track of spin states for parallel update mode
+  new_spins=new DL_Indexed_List<unsigned int*>();
+  previous_spins=new DL_Indexed_List<unsigned int*>();
+  while (!iter.End())
+  {
+    if (k_max<n_cur->Get_Degree()) k_max=n_cur->Get_Degree();
+    i_ptr=new unsigned int;
+    *i_ptr=0;
+    new_spins->Push(i_ptr);
+    i_ptr=new unsigned int;
+    *i_ptr=0;
+    previous_spins->Push(i_ptr);
+    n_cur=iter.Next();
+  }
+  return;
+}
+//#######################################################
+//Destructor of PottsModel
+//########################################################
+PottsModel::~PottsModel()
+{
+  /* The DLItem destructor does not delete its item currently, 
+     because of some bad design. As a workaround, we delete them here
+     by hand */
+  new_spins->delete_items();
+  previous_spins->delete_items();
+  delete new_spins;
+  delete previous_spins;
+  delete [] Qa;
+  delete [] weights;
+  delete [] color_field;
+  delete [] neighbours;
+  return;
+}
+//#####################################################
+//Assing an initial random configuration of spins to nodes
+//if called with negative argument or the spin used as argument
+//when called with positve one.
+//This may be handy, if you want to warm up the network.
+//####################################################
+unsigned long PottsModel::assign_initial_conf(int spin)
+{
+  int s;
+  DLList_Iter<NNode*> iter;
+  DLList_Iter<NLink*> l_iter;
+  NNode *n_cur;
+  NLink *l_cur;
+  double sum_weight;
+  double av_k_squared=0.0;
+  double av_k=0.0;
+//   printf("Assigning initial configuration...\n");
+  // initialize colorfield
+  for (unsigned int i=0; i<=q; i++) color_field[i]=0.0;
+  //
+  total_degree_sum=0.0;
+  n_cur=iter.First(net->node_list);
+  while (!iter.End())
+  {
+    if (spin<0) s=RNG_INTEGER(1,q); else s=spin;
+    n_cur->Set_ClusterIndex(s);
+      l_cur=l_iter.First(n_cur->Get_Links());
+      sum_weight=0;
+      while (!l_iter.End())
+      {
+        sum_weight+=l_cur->Get_Weight();   //weight should be one, in case we are not using it.
+        l_cur=l_iter.Next();
+      }
+      // we set the sum of the weights or the degree as the weight of the node, this way
+      // we do not have to calculate it again.
+      n_cur->Set_Weight(sum_weight);
+      av_k_squared+=sum_weight*sum_weight;
+      av_k+=sum_weight;
+
+    // in case we want all links to be contribute equally - parameter gamm=fixed
+    if (operation_mode==0) {
+      color_field[s]++;
+    } else {
+      color_field[s]+=sum_weight;
+    }
+    // or in case we want to use a weight of each link that is proportional to k_i\times k_j
+      total_degree_sum+=sum_weight;
+    n_cur=iter.Next();
+  }
+  av_k_squared/=double(net->node_list->Size());
+          av_k/=double(net->node_list->Size());
+  // total_degree_sum-=av_k_squared/av_k;
+//   printf("Total Degree Sum=2M=%f\n",total_degree_sum);
+  return net->node_list->Size();
+}
+//#####################################################################
+//If I ever manage to write a decent LookUp function, it will be here
+//#####################################################################
+unsigned long PottsModel::initialize_lookup(double kT, double gamma)
+{
+  IGRAPH_UNUSED(kT); 
+  IGRAPH_UNUSED(gamma);
+  /*
+  double beta;
+  // the look-up table contains all entries of exp(-beta(-neighbours+gamma*h))
+  // as needed in the HeatBath algorithm
+  beta=1.0/kT;
+  for (long w=0; w<=k_max+num_of_nodes; w++)
+  {
+     neg_lookup[w]=exp(-beta*-w
+  }
+  delta_ij[0]=1.0;
+  for (long w=-num_of_nodes-k_max; w<=k_max+num_of_nodes; w++)
+  {
+
+  }
+
+  // wenn wir spaeter exp(-1/kT*gamma*(nk+1-nj) fuer eine spin-flip von j nach k benoetigen schauen wir nur noch hier nach
+  for (unsigned long n=1; n<=num_of_nodes; n++)
+  {
+    gamma_term[n]=exp(-double(n)/kT*gamma);
+  }
+  gamma_term[0]=1.0;
+  */
+  return 1;
+}
+//#####################################################################
+// Q denotes the modulary of the network
+// This function calculates it initially 
+// In the event of a spin changing its state, it only needs updating
+// Note that Qmatrix and Qa are only counting! The normalization 
+// by num_of_links is done later
+//####################################################################
+double PottsModel::initialize_Qmatrix(void)
+{
+  DLList_Iter<NLink*> l_iter;
+  NLink *l_cur;
+  unsigned int i,j;
+  //initialize with zeros
+  num_of_links=net->link_list->Size();
+  for (i=0; i<=q; i++)
+  {
+      Qa[i]=0.0;
+      for (j=i; j<=q; j++) {
+          Qmatrix[i][j]=0.0;
+          Qmatrix[j][i]=0.0;
+      }
+  }
+  //go over all links and make corresponding entries in Q matrix
+  //An edge connecting state i wiht state j will get an entry in Qij and Qji
+  l_cur=l_iter.First(net->link_list);
+  while (!l_iter.End())
+  {
+    i=l_cur->Get_Start()->Get_ClusterIndex();
+    j=l_cur->Get_End()->Get_ClusterIndex();
+    //printf("%d %d\n",i,j);
+    Qmatrix[i][j]+=l_cur->Get_Weight();
+    Qmatrix[j][i]+=l_cur->Get_Weight();
+
+    l_cur=l_iter.Next();
+  }
+  //Finally, calculate sum over rows and keep in Qa
+  for (i=0; i<=q; i++)
+  {
+     for (j=0; j<=q; j++) Qa[i]+=Qmatrix[i][j];
+  }
+  return calculate_Q();
+}
+//####################################################################
+// This function does the actual calculation of Q from the matrix 
+// The normalization by num_of_links is done here
+//####################################################################
+double PottsModel::calculate_Q()
+{
+  double Q=0.0;
+  for (unsigned int i=0; i<=q; i++)
+  {
+    Q+=Qmatrix[i][i]-Qa[i]*Qa[i]/double(2.0*net->sum_weights);
+    if ((Qa[i]<0.0) || Qmatrix[i][i]<0.0) {
+//         printf("Negatives Qa oder Qii\n\n\n");
+        //printf("Press any key to continue\n\n");
+        //cin >> Q;
+    }
+  }
+  Q/=double(2.0*net->sum_weights);
+  return Q;
+}
+double PottsModel::calculate_genQ(double gamma)
+{
+  double Q=0.0;
+  for (unsigned int i=0; i<=q; i++)
+  {
+    Q+=Qmatrix[i][i]-gamma*Qa[i]*Qa[i]/double(2.0*net->sum_weights);
+    if ((Qa[i]<0.0) || Qmatrix[i][i]<0.0) {
+//         printf("Negatives Qa oder Qii\n\n\n");
+        //printf("Press any key to continue\n\n");
+        //cin >> Q;
+    }
+  }
+  Q/=double(2.0*net->sum_weights);
+  return Q;
+}
+//#######################################################################
+// This function calculates the Energy for the standard Hamiltonian
+// given a particular value of gamma and the current spin states
+// #####################################################################
+double PottsModel::calculate_energy(double gamma)
+{
+  double e=0.0;
+  DLList_Iter<NLink*> l_iter;
+  NLink *l_cur;
+  l_cur=l_iter.First(net->link_list);
+  //every in-cluster edge contributes -1
+  while (!l_iter.End())
+  {
+    if (l_cur->Get_Start()->Get_ClusterIndex()==l_cur->Get_End()->Get_ClusterIndex()) e--;;
+   l_cur=l_iter.Next();
+  }
+  //and the penalty term contributes according to cluster sizes
+  for (unsigned int i=1; i<=q; i++)
+  {
+      e+=gamma*0.5*double(color_field[i])*double((color_field[i]-1));
+  }
+  energy=e;
+  return e;
+}
+//##########################################################################
+// We would like to start from a temperature with at least 95 of all proposed 
+// spin changes accepted in 50 sweeps over the network
+// The function returns the Temperature found
+//#########################################################################
+double PottsModel::FindStartTemp(double gamma, double prob, double ts)
+{
+  double kT;
+  kT=ts;
+  //assing random initial condition
+  assign_initial_conf(-1);
+  //initialize Modularity matrix, from now on, it will be updated at every spin change
+  initialize_Qmatrix();
+  // the factor 1-1/q is important, since even, at infinite temperature,
+  // only 1-1/q of all spins do change their state, since a randomly chooses new
+  // state is with prob. 1/q the old state.
+  while (acceptance<(1.0-1.0/double(q))*0.95)      //want 95% acceptance
+  {
+       kT=kT*1.1;
+       // if I ever have a lookup table, it will need initialization for every kT
+       //initialize_lookup(kT,k_max,net->node_list->Size());
+       HeatBathParallelLookup(gamma,prob, kT,50);
+//        printf("kT=%f acceptance=%f\n", kT, acceptance);
+  }
+  kT*=1.1; // just to be sure...
+//   printf("Starting with acceptance ratio: %1.6f bei kT=%2.4f\n",acceptance,kT);
+  return kT;
+}
+
+//##############################################################
+//This function does a parallel update at zero T
+//Hence, it is really fast on easy problems
+//max sweeps is the maximum number of sweeps it should perform,
+//if it does not converge earlier
+//##############################################################
+long PottsModel::HeatBathParallelLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps)
+{
+  DLList_Iter<NNode*> iter, net_iter;
+  DLList_Iter<NLink*> l_iter;
+  DLList_Iter<unsigned int*> i_iter, i_iter2;
+  NNode *node, *n_cur;
+  NLink *l_cur;
+  unsigned int *SPIN, *P_SPIN, new_spin, spin_opt, old_spin, spin, sweep;
+  // long h; // degree;
+  unsigned long changes;
+  double h, delta=0, deltaE, deltaEmin, w, degree;
+  //HugeArray<double> neighbours;
+  bool cyclic=0;
+  
+  sweep=0;
+  changes=1;  
+  while (sweep<max_sweeps && changes)
+  {
+    cyclic=true;
+    sweep++;
+    changes=0;
+    //Loop over all nodes
+    node=net_iter.First(net->node_list);
+    SPIN=i_iter.First(new_spins);
+    while (!net_iter.End())
+    {
+      // How many neigbors of each type?
+      // set them all zero
+      for (unsigned int i=0; i<=q; i++) neighbours[i]=0;
+      degree=node->Get_Weight();
+      //Loop over all links (=neighbours)
+      l_cur=l_iter.First(node->Get_Links());
+      while (!l_iter.End())
+      {
+        //printf("%s %s\n",node->Get_Name(),n_cur->Get_Name());
+	w=l_cur->Get_Weight();
+	if (node==l_cur->Get_Start()) {
+	  n_cur=l_cur->Get_End();
+	} else { 
+	  n_cur=l_cur->Get_Start(); 
+	}
+        neighbours[n_cur->Get_ClusterIndex()]+=w;
+        l_cur=l_iter.Next();
+      }
+      //Search optimal Spin      
+      old_spin=node->Get_ClusterIndex();
+      //degree=node->Get_Degree();
+      switch (operation_mode) {
+      case 0: { 
+	delta=1.0; 
+	break;
+      } 
+      case 1: { //newman modularity 
+	prob=degree/total_degree_sum; 
+	delta=degree; 
+	break;
+       }
+      }
+
+
+      spin_opt=old_spin;
+      deltaEmin=0.0;
+      for (spin=1; spin<=q; spin++)  // all possible spin states
+      {
+          if (spin!=old_spin)
+          {
+            h=color_field[spin]+delta-color_field[old_spin];
+            deltaE=double(neighbours[old_spin]-neighbours[spin])+gamma*prob*double(h);
+            if (deltaE<deltaEmin) {
+              spin_opt=spin;
+              deltaEmin=deltaE;
+            }
+          }
+      } // for spin
+
+     //Put optimal spin on list for later update 
+     *SPIN=spin_opt;     
+     node=net_iter.Next();
+     SPIN=i_iter.Next();
+    } // while !net_iter.End()
+
+    //-------------------------------
+    //Now set all spins to new values
+    node=net_iter.First(net->node_list);
+    SPIN=i_iter.First(new_spins);
+    P_SPIN=i_iter2.First(previous_spins);    
+    while (!net_iter.End())
+    {
+      old_spin=node->Get_ClusterIndex();
+      new_spin=*SPIN;
+      if (new_spin!=old_spin) // Do we really have a change??
+      {
+        changes++;
+        node->Set_ClusterIndex(new_spin);
+	//this is important!!
+	//In Parallel update, there occur cyclic attractors of size two
+	//which then make the program run for ever
+        if (new_spin!=*P_SPIN) cyclic=false;
+        *P_SPIN=old_spin;
+        color_field[old_spin]--;
+        color_field[new_spin]++;
+
+        //Qmatrix update
+        //iteration over all neighbours
+        l_cur=l_iter.First(node->Get_Links());
+        while (!l_iter.End())
+        {
+	   w=l_cur->Get_Weight();
+	   if (node==l_cur->Get_Start()) {
+	     n_cur=l_cur->Get_End();
+	   } else { 
+	     n_cur=l_cur->Get_Start(); 
+	   }
+          Qmatrix[old_spin][n_cur->Get_ClusterIndex()]-=w;
+          Qmatrix[new_spin][n_cur->Get_ClusterIndex()]+=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][old_spin]-=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][new_spin]+=w;
+          Qa[old_spin]-=w;
+          Qa[new_spin]+=w;
+          l_cur=l_iter.Next();
+        }  // while l_iter
+      }
+      node=net_iter.Next();
+      SPIN=i_iter.Next();
+      P_SPIN=i_iter2.Next();
+    } // while (!net_iter.End())
+  }  // while markov
+
+  // In case of a cyclic attractor, we want to interrupt
+  if (cyclic)  {
+//       printf("Cyclic attractor!\n");
+      acceptance=0.0;
+      return 0;
+  } else {
+    acceptance=double(changes)/double(num_of_nodes);
+    return changes;
+  }
+}
+//###################################################################################
+//The same function as before, but rather than parallel update, it pics the nodes to update 
+//randomly
+//###################################################################################
+double PottsModel::HeatBathLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps)
+{
+  DLList_Iter<NNode*> iter;
+  DLList_Iter<NLink*> l_iter;
+  DLList_Iter<unsigned int*> i_iter, i_iter2;
+  NNode *node, *n_cur;
+  NLink *l_cur;
+  unsigned int new_spin, spin_opt, old_spin, spin, sweep;
+  long r;// degree;
+  unsigned long changes;
+  double delta=0, h, deltaE, deltaEmin,w,degree;
+  //HugeArray<int> neighbours;
+
+  sweep=0;
+  changes=0;
+  while (sweep<max_sweeps)
+  {
+    sweep++;
+    //ueber alle Knoten im Netz
+    for (unsigned long n=0; n<num_of_nodes; n++)
+    {
+      r=-1;
+      while ((r<0) || (r>(long)num_of_nodes-1))
+	r=RNG_INTEGER(0,num_of_nodes-1);
+      /* r=long(double(num_of_nodes*double(rand())/double(RAND_MAX+1.0)));*/
+      node=net->node_list->Get(r);
+      // Wir zaehlen, wieviele Nachbarn von jedem spin vorhanden sind
+      // erst mal alles Null setzen
+      for (unsigned int i=0; i<=q; i++) neighbours[i]=0;
+      degree=node->Get_Weight();
+      //Loop over all links (=neighbours)
+      l_cur=l_iter.First(node->Get_Links());
+      while (!l_iter.End())
+      {
+        //printf("%s %s\n",node->Get_Name(),n_cur->Get_Name());
+	w=l_cur->Get_Weight();
+	if (node==l_cur->Get_Start()) {
+	  n_cur=l_cur->Get_End();
+	} else { 
+	  n_cur=l_cur->Get_Start(); 
+	}
+        neighbours[n_cur->Get_ClusterIndex()]+=w;
+        l_cur=l_iter.Next();
+      }
+      //Search optimal Spin      
+      old_spin=node->Get_ClusterIndex();
+      //degree=node->Get_Degree();
+      switch (operation_mode) {
+      case 0: { 
+	delta=1.0; 
+	break;
+      } 
+      case 1: { //newman modularity 
+	prob=degree/total_degree_sum; 
+	delta=degree; 
+	break;
+       }
+      }
+
+
+      spin_opt=old_spin;
+      deltaEmin=0.0;
+      for (spin=1; spin<=q; spin++)  // alle moeglichen Spins
+      {
+          if (spin!=old_spin)
+          {
+            h=color_field[spin]+delta-color_field[old_spin];
+            deltaE=double(neighbours[old_spin]-neighbours[spin])+gamma*prob*double(h);
+            if (deltaE<deltaEmin) {
+              spin_opt=spin;
+              deltaEmin=deltaE;
+            }
+          }
+      } // for spin
+
+      //-------------------------------
+      //Now update the spins
+      new_spin=spin_opt;
+      if (new_spin!=old_spin) // Did we really change something??
+      {
+        changes++;
+        node->Set_ClusterIndex(new_spin);
+        color_field[old_spin]-=delta;
+        color_field[new_spin]+=delta;
+
+        //Qmatrix update
+        //iteration over all neighbours
+        l_cur=l_iter.First(node->Get_Links());
+        while (!l_iter.End())
+        {
+	   w=l_cur->Get_Weight();
+	   if (node==l_cur->Get_Start()) {
+	     n_cur=l_cur->Get_End();
+	   } else { 
+	     n_cur=l_cur->Get_Start(); 
+	   }
+          Qmatrix[old_spin][n_cur->Get_ClusterIndex()]-=w;
+          Qmatrix[new_spin][n_cur->Get_ClusterIndex()]+=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][old_spin]-=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][new_spin]+=w;
+          Qa[old_spin]-=w;
+          Qa[new_spin]+=w;
+          l_cur=l_iter.Next();
+        }  // while l_iter
+       }
+    } // for n
+  }  // while markov
+
+  acceptance=double(changes)/double(num_of_nodes)/double(sweep);
+  return acceptance;
+}
+//#####################################################################################
+//This function performs a parallel update at Terperature T
+//#####################################################################################
+long PottsModel::HeatBathParallelLookup(double gamma, double prob, double kT, unsigned int max_sweeps)
+{
+  DLList_Iter<NNode*> iter, net_iter;
+  DLList_Iter<NLink*> l_iter;
+  DLList_Iter<unsigned int*> i_iter, i_iter2;
+  NNode *node, *n_cur;
+  NLink *l_cur;
+  unsigned int new_spin, spin_opt, old_spin;
+  unsigned int *SPIN, *P_SPIN;
+  unsigned int sweep;
+  long max_q;
+  unsigned long changes, /*degree,*/ problemcount;
+  //HugeArray<int> neighbours;
+  double h, delta=0, norm, r, beta,minweight, prefac=0,w, degree;
+  bool cyclic=0, found;
+  unsigned long num_of_nodes;
+
+  sweep=0;
+  changes=1;
+  num_of_nodes=net->node_list->Size();
+  while (sweep<max_sweeps && changes)
+  {
+    cyclic=true;
+    sweep++;
+    changes=0;
+    //Loop over all nodes
+    node=net_iter.First(net->node_list);
+    SPIN=i_iter.First(new_spins);
+    while (!net_iter.End())
+    {
+      // Initialize neighbours and weights
+      problemcount=0;
+      for (unsigned int i=0; i<=q; i++) {
+        neighbours[i]=0;
+        weights[i]=0;
+      }
+      norm=0.0;
+      degree=node->Get_Weight();
+      //Loop over all links (=neighbours)
+      l_cur=l_iter.First(node->Get_Links());
+      while (!l_iter.End())
+      {
+        //printf("%s %s\n",node->Get_Name(),n_cur->Get_Name());
+	w=l_cur->Get_Weight();
+	if (node==l_cur->Get_Start()) {
+	  n_cur=l_cur->Get_End();
+	} else { 
+	  n_cur=l_cur->Get_Start(); 
+	}
+        neighbours[n_cur->Get_ClusterIndex()]+=w;
+        l_cur=l_iter.Next();
+      }
+      //Search optimal Spin      
+      old_spin=node->Get_ClusterIndex();
+      //degree=node->Get_Degree();
+      switch (operation_mode) {
+      case 0: { 
+	prefac=1.0; 
+	delta=1.0; 
+	break;
+      } 
+      case 1: { //newman modularity 
+	prefac=1.0; 
+	prob=degree/total_degree_sum; 
+	delta=degree; 
+	break;
+       }
+      }
+      spin_opt=old_spin;
+      beta=1.0/kT*prefac;
+      minweight=0.0;
+      weights[old_spin]=0.0;
+      for (unsigned spin=1; spin<=q; spin++)  // loop over all possible new spins
+      {
+          if (spin!=old_spin) // only if we have a different than old spin!
+          {
+            h=color_field[spin]+delta-color_field[old_spin];
+            weights[spin]=double(neighbours[old_spin]-neighbours[spin])+gamma*prob*double(h);
+            if (weights[spin]<minweight) minweight=weights[spin];
+          }
+      }   // for spin      
+      for (unsigned spin=1; spin<=q; spin++)  // loop over all possibe spins
+      {
+            weights[spin]-=minweight;         // subtract minweight
+                                              // to avoid numerical problems with large exponents
+            weights[spin]=exp(-beta*weights[spin]);
+            norm+=weights[spin];
+      }   // for spin
+
+     //now choose a new spin
+     r = RNG_UNIF(0, norm);
+     /* norm*double(rand())/double(RAND_MAX + 1.0); */
+     new_spin=1;
+     found=false;
+     while (!found && new_spin<=q) {
+       if (r<=weights[new_spin]) {
+         spin_opt=new_spin;
+         found=true;
+         break;
+       } else r-=weights[new_spin];
+       new_spin++;
+     }
+     if (!found) {
+//         printf(".");
+        problemcount++;
+     }
+     //Put new spin on list
+     *SPIN=spin_opt;
+
+     node=net_iter.Next();
+     SPIN=i_iter.Next();
+    } // while !net_iter.End()
+
+    //-------------------------------
+    //now update all spins
+    node=net_iter.First(net->node_list);
+    SPIN=i_iter.First(new_spins);
+    P_SPIN=i_iter2.First(previous_spins);
+    while (!net_iter.End())
+    {
+      old_spin=node->Get_ClusterIndex();
+      new_spin=*SPIN;
+      if (new_spin!=old_spin) // Did we really change something??
+      {
+        changes++;
+        node->Set_ClusterIndex(new_spin);
+        if (new_spin!=*P_SPIN) cyclic=false;
+        *P_SPIN=old_spin;
+        color_field[old_spin]-=delta;
+        color_field[new_spin]+=delta;
+
+        //Qmatrix update
+        //iteration over all neighbours
+        l_cur=l_iter.First(node->Get_Links());
+        while (!l_iter.End())
+        {
+	   w=l_cur->Get_Weight();
+	   if (node==l_cur->Get_Start()) {
+	     n_cur=l_cur->Get_End();
+	   } else { 
+	     n_cur=l_cur->Get_Start(); 
+	   }
+          Qmatrix[old_spin][n_cur->Get_ClusterIndex()]-=w;
+          Qmatrix[new_spin][n_cur->Get_ClusterIndex()]+=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][old_spin]-=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][new_spin]+=w;
+          Qa[old_spin]-=w;
+          Qa[new_spin]+=w;
+          l_cur=l_iter.Next();
+        }  // while l_iter
+      }
+      node=net_iter.Next();
+      SPIN=i_iter.Next();
+      P_SPIN=i_iter2.Next();
+    } // while (!net_iter.End())
+
+  }  // while markov
+  max_q=0;
+  for (unsigned int i=1; i<=q; i++) if (color_field[i]>max_q) max_q=long(color_field[i]);
+
+  //again, we would not like to end up in cyclic attractors
+  if (cyclic && changes)  {
+//       printf("Cyclic attractor!\n");
+      acceptance=double(changes)/double(num_of_nodes);
+      return 0;
+  } else {
+    acceptance=double(changes)/double(num_of_nodes);
+    return changes;
+  }
+}
+//##############################################################
+// This is the function generally used for optimisation, 
+// as the parallel update has its flaws, due to the cyclic attractors
+//##############################################################
+double PottsModel::HeatBathLookup(double gamma, double prob, double kT, unsigned int max_sweeps)
+{
+  DLList_Iter<NNode*> iter;
+  DLList_Iter<NLink*> l_iter;
+  DLList_Iter<unsigned int*> i_iter, i_iter2;
+  NNode *node, *n_cur;
+  NLink *l_cur;
+  unsigned int new_spin, spin_opt, old_spin;
+  unsigned int sweep;
+  long max_q, rn;
+  unsigned long changes, /*degree,*/ problemcount;
+  double degree,w, delta=0, h;
+  //HugeArray<int> neighbours;
+  double norm, r, beta,minweight, prefac=0;
+  bool found;
+  long int num_of_nodes;
+  sweep=0;
+  changes=0;
+  num_of_nodes=net->node_list->Size();
+  while (sweep<max_sweeps)
+  {
+    sweep++;
+    //loop over all nodes in network
+    for (int n=0; n<num_of_nodes; n++)
+    {
+      rn=-1;
+      while ((rn<0) || (rn>num_of_nodes-1))
+	rn=RNG_INTEGER(0, num_of_nodes-1);
+      /* rn=long(double(num_of_nodes*double(rand())/double(RAND_MAX+1.0))); */
+        
+      node=net->node_list->Get(rn);
+      // initialize the neighbours and the weights
+      problemcount=0;
+      for (unsigned int i=0; i<=q; i++) {
+        neighbours[i]=0.0;
+        weights[i]=0.0;
+      }
+      norm=0.0;
+      degree=node->Get_Weight();
+      //Loop over all links (=neighbours)
+      l_cur=l_iter.First(node->Get_Links());
+      while (!l_iter.End())
+      {
+        //printf("%s %s\n",node->Get_Name(),n_cur->Get_Name());
+	w=l_cur->Get_Weight();
+	if (node==l_cur->Get_Start()) {
+	  n_cur=l_cur->Get_End();
+	} else { 
+	  n_cur=l_cur->Get_Start(); 
+	}
+        neighbours[n_cur->Get_ClusterIndex()]+=w;
+        l_cur=l_iter.Next();
+      }
+      
+      //Look for optimal spin
+      
+      old_spin=node->Get_ClusterIndex();
+      //degree=node->Get_Degree();
+      switch (operation_mode) {
+      case 0: { 
+	prefac=1.0; 
+	delta=1.0; 
+	break;
+      } 
+      case 1:  {//newman modularity 
+	prefac=1.0; 
+	prob=degree/total_degree_sum; 
+	delta=degree; 
+	break;
+       }
+      }
+      spin_opt=old_spin;
+      beta=1.0/kT*prefac;
+      minweight=0.0;
+      weights[old_spin]=0.0;
+      for (unsigned spin=1; spin<=q; spin++)  // all possible new spins
+      {
+          if (spin!=old_spin) // except the old one!
+          {
+            h=color_field[spin]-(color_field[old_spin]-delta);
+            weights[spin]=neighbours[old_spin]-neighbours[spin]+gamma*prob*h;
+            if (weights[spin]<minweight) minweight=weights[spin];
+          }
+      }   // for spin      
+      for (unsigned spin=1; spin<=q; spin++)  // all possible new spins
+      {
+            weights[spin]-=minweight;         // subtract minweigt
+                                              // for numerical stability
+            weights[spin]=exp(-beta*weights[spin]);
+            norm+=weights[spin];
+      }   // for spin
+      
+
+     //choose a new spin
+/*      r = norm*double(rand())/double(RAND_MAX + 1.0); */
+     r=RNG_UNIF(0, norm);
+     new_spin=1;
+     found=false;
+     while (!found && new_spin<=q) {
+       if (r<=weights[new_spin]) {
+         spin_opt=new_spin;
+         found=true;
+         break;
+       } else r-=weights[new_spin];
+       new_spin++;
+     }
+     if (!found) {
+//         printf(".");
+        problemcount++;
+     }
+    //-------------------------------
+    //now set the new spin
+    new_spin=spin_opt;
+    if (new_spin!=old_spin) // Did we really change something??
+    {
+        changes++;
+        node->Set_ClusterIndex(new_spin);
+        color_field[old_spin]-=delta;
+        color_field[new_spin]+=delta;
+
+        //Qmatrix update
+        //iteration over all neighbours
+        l_cur=l_iter.First(node->Get_Links());
+        while (!l_iter.End())
+        {
+	   w=l_cur->Get_Weight();
+	   if (node==l_cur->Get_Start()) {
+	     n_cur=l_cur->Get_End();
+	   } else { 
+	     n_cur=l_cur->Get_Start(); 
+	   }
+          Qmatrix[old_spin][n_cur->Get_ClusterIndex()]-=w;
+          Qmatrix[new_spin][n_cur->Get_ClusterIndex()]+=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][old_spin]-=w;
+          Qmatrix[n_cur->Get_ClusterIndex()][new_spin]+=w;
+          Qa[old_spin]-=w;
+          Qa[new_spin]+=w;
+          l_cur=l_iter.Next();
+        }  // while l_iter
+      }
+    } // for n
+  }  // while markov
+  max_q=0;
+
+  for (unsigned int i=1; i<=q; i++) if (color_field[i]>max_q) max_q=long(color_field[i]+0.5);
+
+    acceptance=double(changes)/double(num_of_nodes)/double(sweep);
+    return acceptance;
+}
+
+//###############################################################################################
+//# Here we try to minimize the affinity to the rest of the network
+//###############################################################################################
+double PottsModel::FindCommunityFromStart(double gamma, double prob, 
+					  char *nodename, 
+					  igraph_vector_t *result,
+					  igraph_real_t *cohesion, 
+					  igraph_real_t *adhesion,
+					  igraph_integer_t *my_inner_links,
+					  igraph_integer_t *my_outer_links) {
+  DLList_Iter<NNode*> iter, iter2;
+  DLList_Iter<NLink*> l_iter;
+  DLList<NNode*>* to_do;
+  DLList<NNode*>* community;
+  NNode *start_node=0, *n_cur, *neighbor, *max_aff_node, *node;
+  NLink *l_cur;
+  bool found=false, add=false, remove=false;
+  double degree, delta_aff_add, delta_aff_rem, max_delta_aff, Ks=0.0, Kr=0, kis, kir, w;
+  long community_marker=5;
+  long to_do_marker=10;
+  double inner_links=0, outer_links=0, aff_r, aff_s;
+
+  IGRAPH_UNUSED(prob);
+
+  to_do=new DLList<NNode*>;
+  community=new DLList<NNode*>;
+  
+  // find the node in the network
+  n_cur=iter.First(net->node_list);
+  while (!found && !iter.End())
+  {
+    if (0==strcmp(n_cur->Get_Name(),nodename)) {
+      start_node=n_cur;
+      found=true;
+      start_node->Set_Affinity(0.0);
+      community->Push(start_node);
+      start_node->Set_Marker(community_marker);
+      Ks=start_node->Get_Weight();
+      Kr=total_degree_sum-start_node->Get_Weight();
+    }
+    n_cur=iter.Next();
+  }
+  if (!found) {
+//      printf("%s not found found. Aborting.\n",nodename);
+//      fprintf(file,"%s not found found. Aborting.\n",nodename);
+    delete to_do;
+    delete community;
+    return -1;
+  }
+  //#############################
+  // initialize the to_do list and community with the neighbours of start node
+  //#############################
+  neighbor=iter.First(start_node->Get_Neighbours());
+  while (!iter.End()) {
+//     printf("Adding node %s to comunity.\n",neighbor->Get_Name());
+    community->Push(neighbor);
+    neighbor->Set_Marker(community_marker);
+    Ks+=neighbor->Get_Weight();
+    Kr-=neighbor->Get_Weight();
+    neighbor=iter.Next();
+  }
+  node=iter.First(community);
+  while (!iter.End()) {
+    //now add at the second neighbors to the to_do list
+    neighbor=iter2.First(node->Get_Neighbours());
+    while (!iter2.End()) {
+      if ((long)neighbor->Get_Marker()!=community_marker && (long)neighbor->Get_Marker()!=to_do_marker) {
+	to_do->Push(neighbor);
+	neighbor->Set_Marker(to_do_marker);
+// 	printf("Adding node %s to to_do list.\n",neighbor->Get_Name());
+      }
+      neighbor=iter2.Next();
+    }
+    node=iter.Next();
+  }
+  
+  //#############
+  //repeat, as long as we are still adding nodes to the communtiy
+  //#############
+  add=true;
+  remove=true;
+  while (add || remove) {
+      //#############################
+      //calculate the affinity changes of all nodes for adding every node in the to_do list to the community
+      //##############################
+
+      IGRAPH_ALLOW_INTERRUPTION(); /* This is not clean.... */
+
+      max_delta_aff=0.0;
+      max_aff_node=NULL;
+      add=false;
+      node=iter.First(to_do);
+      while (!iter.End()) {
+	//printf("Checking Links of %s\n",node->Get_Name());
+	degree=node->Get_Weight();
+	kis=0.0;
+	kir=0.0;
+	// For every of the neighbors, check, count the links to the community
+	l_cur=l_iter.First(node->Get_Links());
+	while (!l_iter.End())
+	{
+	  w=l_cur->Get_Weight();
+	  if (node==l_cur->Get_Start()) {
+	    n_cur=l_cur->Get_End();
+	  } else { 
+	    n_cur=l_cur->Get_Start(); 
+	  }
+	  if ((long)n_cur->Get_Marker()==community_marker) {
+	    kis+=w;  //the weight/number of links to the community
+	  } else {
+	    kir+=w;  //the weight/number of links to the rest of the network
+	  }
+	  l_cur=l_iter.Next();
+	}
+	aff_r=kir-gamma/total_degree_sum*(Kr-degree)*degree;
+	aff_s=kis-gamma/total_degree_sum*Ks*degree;
+	delta_aff_add=aff_r-aff_s;
+	// 	if (aff_s>=aff_r && delta_aff_add<=max_delta_aff) {
+	if (delta_aff_add<=max_delta_aff) {
+	    node->Set_Affinity(aff_s);
+	    max_delta_aff=delta_aff_add;
+	    max_aff_node=node;
+	    add=true;
+	}
+	//printf("%s in to_do list with affinity %f\n",node->Get_Name(),node->Get_Affinity());
+	node=iter.Next();
+      }
+      //################
+      //calculate the affinity changes for removing every single node from the community
+      //################
+      inner_links=0;
+      outer_links=0;
+      remove=false;
+      node=iter.First(community);
+      while (!iter.End()) {
+	//printf("Checking Links of %s\n",node->Get_Name());
+	degree=node->Get_Weight();
+	kis=0.0;
+	kir=0.0;
+	// For every of the neighbors, check, count the links to the community
+	l_cur=l_iter.First(node->Get_Links());
+	while (!l_iter.End())
+	{
+	  w=l_cur->Get_Weight();
+	  if (node==l_cur->Get_Start()) {
+	    n_cur=l_cur->Get_End();
+	  } else { 
+	    n_cur=l_cur->Get_Start(); 
+	  }
+	  if ((long)n_cur->Get_Marker()==community_marker) {
+	    kis+=w;
+	    inner_links+=w;  //summing all w gives twice the number of inner links(weights)
+	  } else {
+	    kir+=w;
+	    outer_links+=w;
+	  }
+	  l_cur=l_iter.Next();
+	}
+// 	if (kir+kis!=degree) {  printf("error kir=%f\tkis=%f\tk=%f\n",kir,kis,degree); }
+	aff_r=kir-gamma/total_degree_sum*Kr*degree;
+	aff_s=kis-gamma/total_degree_sum*(Ks-degree)*degree;
+	delta_aff_rem=aff_s-aff_r;
+	node->Set_Affinity(aff_s);
+	// we should not remove the nodes, we have just added
+	if (delta_aff_rem<max_delta_aff) {
+	  max_delta_aff=delta_aff_rem ;
+	  max_aff_node=node;
+	  remove=true;
+	  add=false;
+	}
+	//printf("%s in to_do list with affinity %f\n",node->Get_Name(),node->Get_Affinity());
+	node=iter.Next();
+      }
+      inner_links=inner_links*0.5;
+      //################
+      // Now check, whether we want to remove or add a node
+      //################
+      if (add) {
+        //################
+	//add the node of maximum affinity to the community
+	//###############
+	community->Push(max_aff_node);
+	max_aff_node->Set_Marker(community_marker);
+	//delete node from to_do
+	to_do->fDelete(max_aff_node);
+	//update the sum of degrees in the community
+	Ks+=max_aff_node->Get_Weight();
+	Kr-=max_aff_node->Get_Weight();
+// 	printf("Adding node %s to community with affinity of %f delta_aff: %f.\n",max_aff_node->Get_Name(), max_aff_node->Get_Affinity(),max_delta_aff);
+	//now add all neighbors of this node, that are not already 
+	//in the to_do list or in the community
+	neighbor=iter.First(max_aff_node->Get_Neighbours());
+	while (!iter.End()) {
+	  if ((long)neighbor->Get_Marker()!=community_marker && (long)neighbor->Get_Marker()!=to_do_marker) {
+	    to_do->Push(neighbor);
+	    neighbor->Set_Marker(to_do_marker);
+	    //printf("Adding node %s to to_do list.\n",neighbor->Get_Name());
+	  }
+	  neighbor=iter.Next();
+	}
+      }
+      if (remove) {
+	//################
+	//remove those with negative affinities
+	//################
+	community->fDelete(max_aff_node);
+	max_aff_node->Set_Marker(to_do_marker);
+	//update the sum of degrees in the community
+	Ks-=max_aff_node->Get_Weight();
+	Kr+=max_aff_node->Get_Weight();
+	//add the node to to_do again
+	to_do->Push(max_aff_node);
+// 	printf("Removing node %s from community with affinity of %f delta_aff: %f.\n",max_aff_node->Get_Name(), max_aff_node->Get_Affinity(),max_delta_aff);
+      }
+      IGRAPH_ALLOW_INTERRUPTION(); /* This is not clean.... */
+  }
+  //###################
+  //write the node in the community to a file
+  //###################
+  // TODO return this instead of writing it
+//   fprintf(file,"Number_of_nodes:\t%d\n",community->Size());
+//   fprintf(file,"Inner_Links:\t%f\n",inner_links);
+//   fprintf(file,"Outer_Links:\t%f\n",Ks-2*inner_links);
+//   fprintf(file,"Cohesion:\t%f\n",inner_links-gamma/total_degree_sum*Ks*Ks*0.5);
+//   fprintf(file,"Adhesion:\t%f\n",outer_links-gamma/total_degree_sum*Ks*Kr);
+//   fprintf(file,"\n");
+  if (cohesion) {
+    *cohesion=inner_links-gamma/total_degree_sum*Ks*Ks*0.5;
+  } 
+  if (adhesion) {
+    *adhesion=outer_links-gamma/total_degree_sum*Ks*Kr;
+  }
+  if (my_inner_links) {
+    *my_inner_links=inner_links;
+  }
+  if (my_outer_links) {
+    *my_outer_links=outer_links;
+  }
+  if (result) {
+    node=iter.First(community);
+    igraph_vector_resize(result, 0);
+    while (!iter.End()) {
+      // printf("%s in community.\n",node->Get_Name());
+      // fprintf(file,"%s\t%f\n",node->Get_Name(),node->Get_Affinity());
+      IGRAPH_CHECK(igraph_vector_push_back(result, node->Get_Index()));
+      node=iter.Next();
+    }
+  }
+//   printf("%d nodes in community around %s\n",community->Size(),start_node->Get_Name());
+//   fclose(file);
+  unsigned int size=community->Size();
+  delete to_do;  
+  delete community;
+  return size;
+}
+
+//################################################################################################
+// this Function writes the clusters to disk
+//################################################################################################
+long PottsModel::WriteClusters(igraph_real_t *modularity,
+			       igraph_real_t *temperature,
+			       igraph_vector_t *csize,
+			       igraph_vector_t *membership,
+			       double kT, double gamma)
+{
+  NNode *n_cur, *n_cur2;
+  /*
+  double a1,a2,a3,p,p1,p2;
+  long n,N,lin,lout;
+  */
+  DLList_Iter<NNode*> iter, iter2;
+  HugeArray<int> inner_links;
+  HugeArray<int> outer_links;
+  HugeArray<int> nodes;
+  
+  //den Header schreiben
+//   p=2.0*double(num_of_links)/double(num_of_nodes)/double(num_of_nodes-1);
+//   fprintf(file,"      Nodes=\t%lu\n",num_of_nodes);
+//   fprintf(file,"      Links=\t%lu\n",num_of_links);
+//   fprintf(file,"          q=\t%d\n",q);
+//   fprintf(file,"          p=\t%f\n",p);
+//   fprintf(file," Modularity=\t%f\n",calculate_Q());
+//   fprintf(file,"Temperature=\t%f\n", kT);
+//   fprintf(file,"Cluster\tNodes\tInnerLinks\tOuterLinks\tp_in\tp_out\t<Ln(#comm.)>\n");
+  
+  if (temperature) { *temperature=kT; }
+
+  if (csize || membership || modularity) {
+    // TODO: count the number of clusters
+    for (unsigned int spin=1; spin<=q; spin++)
+      {
+	inner_links[spin]=0;
+	outer_links[spin]=0;
+	nodes[spin]=0;
+	n_cur=iter.First(net->node_list);
+	while (!iter.End())
+	  {
+	    if (n_cur->Get_ClusterIndex()==spin)
+	      {
+		nodes[spin]++;
+		n_cur2=iter2.First(n_cur->Get_Neighbours());
+		while (!iter2.End())
+		  {
+		    if (n_cur2->Get_ClusterIndex()==spin) inner_links[spin]++;
+		    else outer_links[spin]++;
+		    n_cur2=iter2.Next();
+		  }
+	      }
+	    n_cur=iter.Next();
+	  }
+      }
+  }
+  if (modularity) {
+    *modularity=0.0;
+    for (unsigned int spin=1; spin<=q; spin++) {
+      if (nodes[spin]>0) {
+	double t1= inner_links[spin] / net->sum_weights / 2.0;
+	double t2= (inner_links[spin] + outer_links[spin]) / 
+	  net->sum_weights / 2.0;
+	*modularity += t1;
+	*modularity -= gamma * t2 * t2;
+      }
+    }
+  }
+  if (csize) {
+    igraph_vector_resize(csize, 0);
+    for (unsigned int spin=1; spin<=q; spin++)
+      {
+	if (nodes[spin]>0)
+	  {
+	    inner_links[spin]/=2;
+	    //    fprintf(file,"Cluster\tNodes\tInnerLinks\tOuterLinks\tp_in\tp_out\n");
+        /*
+	    N=num_of_nodes;
+	    n=nodes[spin];
+	    lin=inner_links[spin];
+	    lout=outer_links[spin];
+	    a1=N*log((double)N)-n*log((double)n)*(N-n)*log((double)N-n);
+	    if ((lin==long(n*(n-1)*0.5+0.5)) || (n==1)) a2=0.0;
+	    else a2=(n*(n-1)*0.5    )*log((double)n*(n-1)*0.5    )-(n*(n-1)*0.5    )-
+		   (n*(n-1)*0.5-lin)*log((double)n*(n-1)*0.5-lin)+(n*(n-1)*0.5-lin)-
+		   lin*log((double)lin            )+lin;
+        */
+
+        /*
+	    if ((lout==n*(N-n)) || n==N) a3=0.0;
+	    else a3=(n*(N-n)     )*log((double)n*(N-n)     )-(n*(N-n))-
+		   (n*(N-n)-lout)*log((double)n*(N-n)-lout)+(n*(N-n)-lout)-
+		   lout*log((double)lout        )+lout;
+        */
+
+        /*
+	    p1=(lin+lout)*log((double)p);
+	    p2=(0.5*n*(n-1)-lin + n*(N-n)-lout)*log((double)1.0-p);
+        */
+	    //       fprintf(file,"%d\t%d\t%d\t%d\t%f\t%f\t%f\n",spin,nodes[spin], inner_links[spin], outer_links[spin], p_in, p_out,log_num_exp);
+	    IGRAPH_CHECK(igraph_vector_push_back(csize, nodes[spin]));
+	  }
+      }
+    //   fprintf(file,"\n");
+  }
+  
+  //die Elemente der Cluster
+  if (membership) {
+    long int no=-1;
+    IGRAPH_CHECK(igraph_vector_resize(membership, num_of_nodes));
+    for (unsigned int spin=1; spin<=q; spin++)
+      {
+	if (nodes[spin]>0) {
+	  no++;
+	}
+	n_cur=iter.First(net->node_list);
+	while (!iter.End())
+	  {
+	    if (n_cur->Get_ClusterIndex()==spin)
+	      {
+		//         fprintf(file,"%d\t%s\n",spin,n_cur->Get_Name());
+		VECTOR(*membership)[ n_cur->Get_Index() ]=no;
+	      }
+	    n_cur=iter.Next();
+	  }
+      }
+  }
+  
+  return num_of_nodes;
+}
+//################################################################################################
+//This function writes the soft clusters after a gamma sweep
+//that is, it groups every node together that was found in 
+// more than threshold percent together with the other node 
+// in the same cluster
+//################################################################################################
+// Does not work at the moment !!!
+//################################################################################################
+// long PottsModel::WriteSoftClusters(char *filename, double threshold)
+// {
+//   FILE *file;
+//   NNode *n_cur, *n_cur2;
+//   DLList_Iter<NNode*> iter, iter2;
+//   DL_Indexed_List<ClusterList<NNode*>*> *cl_list, *old_clusterlist;
+//   ClusterList<NNode*> *cl_cur;
+  
+//   double max;
+  
+//   file=fopen(filename,"w");
+//   if (!file) {
+//     printf("Could not open %s for writing.\n",filename);
+//     return -1;
+//   }
+
+//   max=correlation[0]->Get(0);
+//   //printf("max=%f\n",max);
+//   cl_list=new DL_Indexed_List<ClusterList<NNode*>*>();
+  
+//   n_cur=iter.First(net->node_list);
+//   while (!iter.End())
+//   {
+//     cl_cur=new ClusterList<NNode*>();
+//     cl_list->Push(cl_cur);
+//     n_cur2=iter2.First(net->node_list);
+//     while (!iter2.End())
+//     {
+//       if (double(correlation[n_cur->Get_Index()]->Get(n_cur2->Get_Index()))/max>threshold)
+//         cl_cur->Push(n_cur2);
+//       n_cur2=iter2.Next();
+//     }
+//     n_cur=iter.Next();
+//   }
+//   old_clusterlist=net->cluster_list;
+//   net->cluster_list=cl_list;
+//   clear_all_markers(net);
+//   //printf("Es gibt %d Cluster\n",cl_list->Size());
+//   reduce_cliques2(net, false, 15);
+//   //printf("Davon bleiben %d Cluster uebrig\n",cl_list->Size());
+//   clear_all_markers(net);
+//   while (net->cluster_list->Size()){
+//     cl_cur=net->cluster_list->Pop();
+//     while (cl_cur->Size())
+//     {
+//       n_cur=cl_cur->Pop();
+//       fprintf(file,"%s\n",n_cur->Get_Name());
+//       //printf("%s\n",n_cur->Get_Name());
+//     }
+//     fprintf(file,"\n");
+//   }
+//   net->cluster_list=old_clusterlist;
+//   fclose(file);
+
+//   return 1;
+// }
+//#############################################################################
+// Performs a gamma sweep
+//#############################################################################
+double PottsModel::GammaSweep(double gamma_start, double gamma_stop, double prob, unsigned int steps, bool non_parallel, int repetitions)
+{
+  double stepsize;
+  double kT, kT_start;
+  long changes;
+  double gamma, acc;
+  NNode *n_cur, *n_cur2;
+  DLList_Iter<NNode*> iter, iter2;
+  
+  stepsize=(gamma_stop-gamma_start)/double(steps);
+  
+  n_cur=iter.First(net->node_list);
+  while (!iter.End())
+  {
+    correlation[n_cur->Get_Index()]=new HugeArray<double>();
+    n_cur2=iter2.First(net->node_list);
+    while (!iter2.End())
+    {
+      correlation[n_cur->Get_Index()]->Set(n_cur->Get_Index())=0.0;
+      n_cur2=iter2.Next();
+    }
+    n_cur=iter.Next();
+  }
+
+  for (unsigned int n=0; n<=steps; n++)
+  {
+    assign_initial_conf(-1);
+    initialize_Qmatrix();
+    gamma=gamma_start+stepsize*n;
+    kT=0.5;
+    acceptance=0.5;
+    while (acceptance<(1.0-1.0/double(q))*0.95)     //wollen 95% Acceptance
+    {
+          kT*=1.1;
+          //initialize_lookup(kT,kmax,net->node_list->Size());
+          if (!non_parallel) HeatBathParallelLookup(gamma,prob, kT,25);
+          else HeatBathLookup(gamma,prob, kT,25);
+          // printf("kT=%f acceptance=%f\n", kT, acceptance);
+    }
+    // printf("Starting with gamma=%f\n", gamma);
+    kT_start=kT;
+    
+    for (int i=0; i<repetitions; i++)
+    {
+      changes=1;
+      kT=kT_start;
+      assign_initial_conf(-1);
+      initialize_Qmatrix();
+      while ((changes>0) && (kT>0.01)) 
+      {
+          kT=kT*0.99;
+          //initialize_lookup(kT,kmax,net->node_list->Size());
+          if (!non_parallel) {
+	    changes=HeatBathParallelLookup(gamma, prob, kT, 50);
+              // printf("kT: %f   \t Changes %li\n",kT, changes);
+          } else {
+	    acc=HeatBathLookup(gamma, prob, kT, 50);
+             if (acc>(1.0-1.0/double(q))*0.01) changes=1; else changes=0;
+             // printf("kT: %f   Acceptance: %f\n",kT, acc);
+          }
+      }
+      // printf("Finisched with acceptance: %1.6f bei kT=%2.4f und gamma=%2.4f\n",acceptance,kT, gamma);
+//      fprintf(file,"%f\t%f\n",gamma_,acceptance);
+//      fprintf(file2,"%f\t%f\n",gamma_,kT);
+   //   fprintf(file3,"%f\t%d\n",gamma_,count_clusters(5));
+
+      //Die Correlation berechnen
+      n_cur=iter.First(net->node_list);
+      while (!iter.End())
+      {
+        n_cur2=iter2.First(net->node_list);
+        while (!iter2.End())
+        {
+          if (n_cur->Get_ClusterIndex()==n_cur2->Get_ClusterIndex())
+          {
+            correlation[n_cur->Get_Index()]->Set(n_cur2->Get_Index())+=0.5;
+          }
+          n_cur2=iter2.Next();
+        }
+        n_cur=iter.Next();
+      }
+    } // for i
+} //for n
+  return kT;
+}
+//#############################################################################
+//Performs a Gamma sweep at zero T
+//#############################################################################
+double PottsModel::GammaSweepZeroTemp(double gamma_start, double gamma_stop, double prob, unsigned int steps, bool non_parallel, int repetitions)
+{
+  double stepsize;
+  long changes;
+  double gamma, acc;
+  long runs;
+  NNode *n_cur, *n_cur2;
+  DLList_Iter<NNode*> iter, iter2;
+
+  stepsize=(gamma_stop-gamma_start)/double(steps);
+
+  n_cur=iter.First(net->node_list);
+  while (!iter.End())
+  {
+    correlation[n_cur->Get_Index()]=new HugeArray<double>();
+    n_cur2=iter2.First(net->node_list);
+    while (!iter2.End())
+    {
+      correlation[n_cur->Get_Index()]->Set(n_cur->Get_Index())=0.0;
+      n_cur2=iter2.Next();
+    }
+    n_cur=iter.Next();
+  }
+
+  for (unsigned int n=0; n<=steps; n++)
+  {
+    assign_initial_conf(-1);
+    initialize_Qmatrix();
+    gamma=gamma_start+stepsize*n;
+    // printf("Starting with gamma=%f\n", gamma);
+    for (int i=0; i<repetitions; i++)
+    {
+      changes=1;
+      assign_initial_conf(-1);
+      initialize_Qmatrix();
+      runs=0;
+      while (changes>0 && runs<250)
+      {
+          //initialize_lookup(kT,kmax,net->node_list->Size());
+          if (!non_parallel) {
+	    changes=HeatBathParallelLookupZeroTemp(gamma, prob, 1);
+              // printf("Changes %li\n", changes);
+          } else {
+            acc=HeatBathLookupZeroTemp(gamma, prob, 1);
+            if (acc>(1.0-1.0/double(q))*0.01) changes=1; else changes=0;
+            // printf("Acceptance: %f\n", acc);
+          }
+          runs++;
+      }
+      // printf("Finisched with Modularity: %1.6f bei Gamma=%1.6f\n",calculate_Q(), gamma);
+//      fprintf(file,"%f\t%f\n",gamma_,acceptance);
+//      fprintf(file2,"%f\t%f\n",gamma_,kT);
+   //   fprintf(file3,"%f\t%d\n",gamma_,count_clusters(5));
+
+      //Die Correlation berechnen
+      n_cur=iter.First(net->node_list);
+      while (!iter.End())
+      {
+        n_cur2=iter2.First(net->node_list);
+        while (!iter2.End())
+        {
+          if (n_cur->Get_ClusterIndex()==n_cur2->Get_ClusterIndex())
+          {
+            correlation[n_cur->Get_Index()]->Set(n_cur2->Get_Index())+=0.5;
+            correlation[n_cur2->Get_Index()]->Set(n_cur->Get_Index())+=0.5;
+          }
+          n_cur2=iter2.Next();
+        }
+        n_cur=iter.Next();
+      }
+    } // for i
+} //for n
+  return gamma;
+}
+//#######################################################################
+//-----------------------------------------------------------------------
+//#######################################################################
+// This function writes the Correlation Matrix that results from a 
+// Gamma-Sweep, this matrix is used to make ps files of it.
+// ######################################################################
+// long PottsModel::WriteCorrelationMatrix(char *filename)
+// {
+//   FILE *file, *file2;
+//   char filename2[255];
+//   NNode *n_cur, *n_cur2;
+//   DLList_Iter<NNode*> iter, iter2;
+
+//   sprintf(filename2,"%s.mat",filename);
+//   file=fopen(filename,"w");
+//   if (!file) {
+//     printf("Could not open %s for writing.\n",filename);
+//     return -1;
+//   }
+//   file2=fopen(filename2,"w");
+//   if (!file2) {
+//     printf("Could not open %s for writing.\n",filename2);
+//     return -1;
+//   }
+//   //write the header in one line
+//   n_cur=iter.First(net->node_list);
+//   while (!iter.End())
+//   {  
+//       fprintf(file, "\t%s",n_cur->Get_Name());
+//       n_cur=iter.Next();
+//   }    
+//   fprintf(file, "\n");
+
+//   //fprintf(file, "%d\t%d\n",net->node_list->Size(),net->node_list->Size());
+
+//   long r=0,c=0;
+//   n_cur=iter.First(net->node_list);
+//   while (!iter.End())
+//   {
+//     fprintf(file, "%s",n_cur->Get_Name());
+//     r++;
+//     n_cur2=iter2.First(net->node_list);
+//     while (!iter2.End())
+//     {
+//       c++;
+//       fprintf(file,"\t%f",correlation[n_cur->Get_Index()]->Get(n_cur2->Get_Index()));
+//       fprintf(file2,"%li\t%li\t%f\n",r,c,correlation[n_cur->Get_Index()]->Get(n_cur2->Get_Index()));
+//       n_cur2=iter2.Next();
+//     }
+//     fprintf(file,"\n");
+//     n_cur=iter.Next();
+//   }
+//   fclose(file);
+//   fclose(file2);
+//   return 1;
+// }
+//##############################################################################
+
+//#################################################################################################
+PottsModelN::PottsModelN(network *n, unsigned int num_communities, bool directed)
+{
+	//Set internal variable
+	net	= n;
+	q	= num_communities;
+	
+	is_directed = directed;
+	
+	is_init = false;
+	
+	num_nodes	= net->node_list->Size();
+}
+//#######################################################
+//Destructor of PottsModel
+//########################################################
+PottsModelN::~PottsModelN()
+{
+	delete degree_pos_in;
+	delete degree_neg_in;
+	delete degree_pos_out;
+	delete degree_neg_out;
+	
+	delete degree_community_pos_in;
+	delete degree_community_neg_in;	
+	delete degree_community_pos_out;
+	delete degree_community_neg_out;
+	
+	delete weights;
+	delete neighbours;
+	delete csize;
+	
+	delete spin;
+	
+	return;
+}
+
+void PottsModelN::assign_initial_conf(bool init_spins)
+{
+	#ifdef DEBUG
+	printf("Start assigning.\n");
+	#endif
+	int s;
+	DLList_Iter<NNode*> iter;
+	DLList_Iter<NLink*> l_iter;
+	NNode *n_cur;
+	NLink *l_cur;
+	
+
+	if(init_spins)
+	{
+		#ifdef DEBUG
+		printf("Initializing spin.\n");
+		#endif
+		//Bookkeeping of the various degrees (positive/negative) and (in/out)
+		degree_pos_in	= new double[num_nodes]; //Postive indegree of the nodes (or sum of weights)
+		degree_neg_in	= new double[num_nodes]; //Negative indegree of the nodes (or sum of weights)
+		degree_pos_out	= new double[num_nodes]; //Postive outdegree of the nodes (or sum of weights)
+		degree_neg_out	= new double[num_nodes]; //Negative outdegree of the nodes (or sum of weights)	
+				
+		spin			= new unsigned int[num_nodes]; //The spin state of each node
+	}
+	
+	if (is_init)
+	{
+		delete degree_community_pos_in;
+		delete degree_community_neg_in;
+		delete degree_community_pos_out;
+		delete degree_community_neg_out;
+		
+		delete weights;
+		delete neighbours;
+		delete csize;
+	}
+	
+	is_init = true;
+	
+	//Bookkeep of occupation numbers of spin states or the number of links in community...
+	degree_community_pos_in		= new double[q+1]; //Positive sum of indegree for communities
+	degree_community_neg_in		= new double[q+1]; //Negative sum of indegree for communities
+	degree_community_pos_out	= new double[q+1];//Positive sum of outegree for communities
+	degree_community_neg_out	= new double[q+1]; //Negative sum of outdegree for communities	
+
+	//...and of weights and neighbours for in the HeathBathLookup
+	weights						= new double[q+1]; //The weights for changing to another spin state
+	neighbours					= new double[q+1]; //The number of neighbours (or weights) in different spin states
+	csize						= new unsigned int[q+1]; //The number of nodes in each community	
+	
+
+	//Initialize communities
+	for (unsigned int i=0; i<=q; i++) 
+	{
+		degree_community_pos_in[i]	= 0.0;
+		degree_community_neg_in[i]	= 0.0;	
+		degree_community_pos_out[i]	= 0.0;
+		degree_community_neg_out[i]	= 0.0;
+		
+		csize[i]					= 0;
+	}
+	
+	//Initialize vectors
+	if (init_spins)
+	{	
+		for (unsigned int i = 0; i < num_nodes; i++)
+		{
+			degree_pos_in[i]	= 0.0;
+			degree_neg_in[i]	= 0.0;
+			degree_pos_out[i]	= 0.0;
+			degree_neg_out[i]	= 0.0;
+			
+			#ifdef DEBUG
+			printf("Initializing spin %d", i);
+			#endif
+			spin[i]	= 0;
+		}
+	}
+	m_p=0.0;
+	m_n=0.0;
+	//Set community for each node, and 
+	//correctly store it in the bookkeeping
+	
+	double sum_weight_pos_in, sum_weight_pos_out, sum_weight_neg_in, sum_weight_neg_out;
+	//double av_w = 0.0, av_k=0.0;
+	//int l = 0;
+	#ifdef DEBUG
+	printf("Visiting each node.\n");
+	#endif
+	for (unsigned int v = 0; v < num_nodes; v++)
+	{
+		if (init_spins)
+		{
+			s = RNG_INTEGER(1, q);  //The new spin s
+			spin[v] = (unsigned int)s;
+		}
+		else
+			s = spin[v];
+		
+		#ifdef DEBUG		
+		printf("Spin %d assigned to node %d.\n", s, v);
+		#endif
+			
+		n_cur				=  net->node_list->Get(v);
+		
+		l_cur				= l_iter.First(n_cur->Get_Links());
+		
+		sum_weight_pos_in	= 0.0;
+		sum_weight_pos_out	= 0.0;
+		sum_weight_neg_in	= 0.0;
+		sum_weight_neg_out	= 0.0;
+		
+		while (!l_iter.End())
+		{
+			double w = l_cur->Get_Weight();
+			//av_w = (av_w*l + w)/(l+1); //Average weight
+			//l++;
+			if (l_cur->Get_Start() == n_cur) //From this to other, so outgoing link
+				if (w > 0)
+					sum_weight_pos_out += w;   //Increase positive outgoing weight
+				else
+					sum_weight_neg_out -= w;	//Increase negative outgoing weight
+			else
+				if (w > 0)
+					sum_weight_pos_in += w;   //Increase positive incoming weight
+				else
+					sum_weight_neg_in -= w;	//Increase negative incoming weight			
+			
+			l_cur=l_iter.Next();
+		}
+		
+		if (!is_directed)
+		{
+			double sum_weight_pos		= sum_weight_pos_out + sum_weight_pos_in; 
+				   sum_weight_pos_out	= sum_weight_pos; 
+				   sum_weight_pos_in	= sum_weight_pos;
+			double sum_weight_neg = sum_weight_neg_out + sum_weight_neg_in;
+				   sum_weight_neg_out	= sum_weight_neg; 
+				   sum_weight_neg_in	= sum_weight_neg;			
+		}
+		
+		//av_k = (av_k*l + sum_weight_pos_in)/(l+1); //Average k
+		
+		if (init_spins)
+		{
+			//Set the degrees correctly
+			degree_pos_in[v]	= sum_weight_pos_in;
+			degree_neg_in[v]	= sum_weight_neg_in;
+			degree_pos_out[v]	= sum_weight_pos_out;
+			degree_neg_out[v]	= sum_weight_neg_out;
+		}
+		
+		//Correct the community bookkeeping
+		degree_community_pos_in[s]	+= sum_weight_pos_in;
+		degree_community_neg_in[s]	+= sum_weight_neg_in;
+		degree_community_pos_out[s]	+= sum_weight_pos_out;
+		degree_community_neg_out[s]	+= sum_weight_neg_out;
+		
+		//Community just increased
+		csize[s]++;
+	
+		//Sum the weights (notice that sum of indegrees equals sum of outdegrees)
+		m_p += sum_weight_pos_in;
+		m_n += sum_weight_neg_in;
+	}
+	
+	#ifdef DEBUG
+	printf("Done assigning.\n");
+	#endif
+
+	return;
+}
+//##############################################################
+// This is the function generally used for optimisation, 
+// as the parallel update has its flaws, due to the cyclic attractors
+//##############################################################
+double PottsModelN::HeatBathLookup(double gamma, double lambda, double t, unsigned int max_sweeps)
+{
+	#ifdef DEBUG
+	printf("Starting sweep at temperature %f.\n", t);
+	#endif
+	DLList_Iter<NNode*> iter;
+	DLList_Iter<NLink*> l_iter;
+	DLList_Iter<unsigned int*> i_iter, i_iter2;
+	NNode *node, *n_cur;
+	NLink *l_cur;
+	/* The new_spin contains the spin to which we will update,
+	 * the spin_opt is the optional spin we will consider and
+	 * the old_spin is the spin of the node we are currently
+	 * changing.
+	 */  
+	unsigned int new_spin, spin_opt, old_spin;
+	unsigned int sweep; //current sweep
+	unsigned long changes, problemcount; //Number of changes and number of problems encountered
+
+	double exp_old_spin; //The expectation value for the old spin
+	double exp_spin; //The expectation value for the other spin(s)
+	int v; //The node we will be investigating
+	
+	//The variables required for the calculations
+	double delta_pos_out, delta_pos_in, delta_neg_out, delta_neg_in;
+	double k_v_pos_out, k_v_pos_in, k_v_neg_out, k_v_neg_in;
+	
+	//weight of edge
+	double w;
+	
+	double beta = 1/t; //Weight for probabilities
+	double r = 0.0; //random number used for assigning new spin
+	
+	double maxweight = 0.0;
+	double sum_weights = 0.0; //sum_weights for normalizing the probabilities
+	
+	sweep=0;
+	changes=0;
+	double m_pt = m_p;
+	double m_nt = m_n;
+	
+	if (m_pt < 0.001)
+		m_pt = 1;
+		
+	if (m_nt < 0.001)
+		m_nt = 1;
+		
+	while (sweep<max_sweeps)
+	{
+		sweep++;
+		//loop over all nodes in network
+		for (unsigned int n = 0; n < num_nodes; n++)
+		{
+			//Look for a random node
+			v = RNG_INTEGER(0, num_nodes-1);
+			//We will be investigating node v
+			
+			node=net->node_list->Get(v);
+			
+			/*******************************************/
+			// initialize the neighbours and the weights
+			problemcount=0;
+			for (unsigned int i=0; i<=q; i++) {
+				neighbours[i]=0.0;
+				weights[i]=0.0;
+			}
+
+			//Loop over all links (=neighbours)
+			l_cur=l_iter.First(node->Get_Links());
+			while (!l_iter.End())
+			{
+				w=l_cur->Get_Weight();
+				if (node==l_cur->Get_Start()) {
+					n_cur=l_cur->Get_End();
+				} else { 
+					n_cur=l_cur->Get_Start(); 
+				}
+				//Add the link to the correct cluster
+				neighbours[spin[n_cur->Get_Index()]]+=w;
+				l_cur=l_iter.Next();
+			}
+			//We now have the weight of the (in and out) neighbours 
+			//in each cluster available to us.
+			/*******************************************/
+			old_spin=spin[v];
+						
+			//Look for optimal spin
+						
+			//Set the appropriate variable
+			delta_pos_out	= degree_pos_out[v];
+			delta_pos_in	= degree_pos_in[v];
+			delta_neg_out	= degree_neg_out[v];
+			delta_neg_in	= degree_neg_in[v];
+			
+			k_v_pos_out		= gamma*delta_pos_out/m_pt;
+			k_v_pos_in		= gamma*delta_pos_in/m_pt;
+			k_v_neg_out		= lambda*delta_neg_out/m_nt;
+			k_v_neg_in		= lambda*delta_neg_in/m_nt;			
+			
+			//The expectation value for the old spin
+			if (is_directed)
+				exp_old_spin = (k_v_pos_out * (degree_community_pos_in[old_spin] - delta_pos_in) - 
+								k_v_neg_out * (degree_community_neg_in[old_spin] - delta_neg_in)) + 
+							   (k_v_pos_in * (degree_community_pos_out[old_spin] - delta_pos_out) - 
+								k_v_neg_in * (degree_community_neg_out[old_spin] - delta_neg_out));
+			else
+				exp_old_spin = (k_v_pos_out * (degree_community_pos_in[old_spin] - delta_pos_in) - 
+								k_v_neg_out * (degree_community_neg_in[old_spin] - delta_neg_in));			
+
+			/*******************************************/
+			//Calculating probabilities for each transition to another 
+			//community.			
+			
+			maxweight=0.0;
+			weights[old_spin]=0.0;
+														
+			for (spin_opt=1; spin_opt<=q; spin_opt++)  // all possible new spins
+			{
+				if (spin_opt!=old_spin) // except the old one!
+				{
+					if (is_directed)
+						exp_spin = (k_v_pos_out * degree_community_pos_in[spin_opt] - k_v_neg_out * degree_community_neg_in[spin_opt]) + 
+								   (k_v_pos_in * degree_community_pos_out[spin_opt] - k_v_neg_in * degree_community_neg_out[spin_opt]);
+					else
+						exp_spin = (k_v_pos_out * degree_community_pos_in[spin_opt] - k_v_neg_out * degree_community_neg_in[spin_opt]);
+						
+					weights[spin_opt] = (neighbours[spin_opt] - exp_spin) - (neighbours[old_spin] - exp_old_spin);
+					
+					if (weights[spin_opt] > maxweight)
+						maxweight = weights[spin_opt];
+				}
+			}   // for spin      
+			
+			//Calculate exp. prob. an
+			sum_weights = 0.0;
+			for (spin_opt=1; spin_opt<=q; spin_opt++)  // all possible new spins
+			{
+				weights[spin_opt] -= maxweight;  //subtract maxweight for numerical stability (otherwise overflow).
+				weights[spin_opt]  = exp((double)(beta*weights[spin_opt]));
+				sum_weights   += weights[spin_opt];
+			}   // for spin
+			/*******************************************/
+						
+			
+			/*******************************************/
+			//Choose a new spin dependent on the calculated probabilities
+			r = RNG_UNIF(0, sum_weights);
+			new_spin = 1;
+			
+			bool found = false;
+			while (!found && new_spin <= q) 
+			{
+				if (r <= weights[new_spin]) 
+				{
+					spin_opt = new_spin; //We have found are new spin
+					found = true;
+					break;
+				} 
+				else 
+					r -= weights[new_spin]; //Perhaps the next spin is the one we want
+
+				new_spin++;
+			}
+			
+			//Some weird thing happened. We haven't found a new spin
+			//while that shouldn't be the case. Numerical problems?
+			if (!found) 
+				problemcount++;
+
+			new_spin=spin_opt;
+			//If there wasn't a problem we should have found
+			//our new spin.
+			/*******************************************/
+			
+			
+			/*******************************************/
+			//The new spin is available to us, so change
+			//all the appropriate counters.
+			if (new_spin!=old_spin) // Did we really change something??
+			{
+				changes++;
+				spin[v] = new_spin;
+				
+				//The new spin increase by one, and the old spin decreases by one
+				csize[new_spin]++; csize[old_spin]--;
+				
+				//Change the sums of degree for the old spin...		
+				degree_community_pos_in[old_spin]	-= delta_pos_in;
+				degree_community_neg_in[old_spin]	-= delta_neg_in;
+				degree_community_pos_out[old_spin]	-= delta_pos_out;
+				degree_community_neg_out[old_spin]	-= delta_neg_out;
+				
+				//...and for the new spin
+				degree_community_pos_in[new_spin]	+= delta_pos_in;
+				degree_community_neg_in[new_spin]	+= delta_neg_in;
+				degree_community_pos_out[new_spin]	+= delta_pos_out;
+				degree_community_neg_out[new_spin]	+= delta_neg_out;				
+			}
+			
+			//We have no change a node from old_spin to new_spin
+			/*******************************************/
+		
+		} // for n
+	}  // while sweep
+	#ifdef DEBUG
+	printf("Done %d sweeps.\n", max_sweeps);
+	printf("%d changes made for %d nodes.\n", changes, num_nodes);
+	printf("Last node is %d and last random number is %f with sum of weights %f with spin %d.\n", v, r, sum_weights, old_spin);
+	#endif
+	
+    return (double(changes)/double(num_nodes)/double(sweep));
+}
+
+//We need to begin at a suitable temperature. That is, a temperature at which
+//enough nodes may change their initially assigned communties
+double PottsModelN::FindStartTemp(double gamma, double lambda, double ts)
+{
+  double kT;
+  kT=ts;
+  //assing random initial condition
+  assign_initial_conf(true);
+  // the factor 1-1/q is important, since even, at infinite temperature,
+  // only 1-1/q of all spins do change their state, since a randomly chooses new
+  // state is with prob. 1/q the old state.
+  double acceptance = 0.0;
+  while (acceptance<(1.0-1.0/double(q))*0.95)      //want 95% acceptance
+  {
+       kT=kT*1.1;
+       acceptance=HeatBathLookup(gamma,lambda, kT,50);
+  }
+  kT*=1.1; // just to be sure...
+  return kT;
+}
+
+long PottsModelN::WriteClusters(igraph_real_t *modularity,
+				igraph_real_t *temperature,
+				igraph_vector_t *community_size,
+				igraph_vector_t *membership,
+				igraph_matrix_t *adhesion,
+				igraph_matrix_t *normalised_adhesion,
+				igraph_real_t *polarization,
+				double t,
+				double d_p,
+				double d_n,
+				double gamma,
+				double lambda)
+{
+        IGRAPH_UNUSED(gamma);
+	IGRAPH_UNUSED(lambda);
+	#ifdef DEBUG
+	printf("Start writing clusters.\n");
+	#endif
+	//Reassign each community so that we retrieve a community assignment 1 through num_communities	
+	unsigned int *cluster_assign = new unsigned int[q+1];
+	for (unsigned int i = 0; i <= q; i++)
+	{
+		cluster_assign[i] = 0;
+	}
+	
+	int num_clusters = 0;
+	
+	//Find out what the new communities will be
+	for (unsigned int i = 0; i < num_nodes; i++)
+	{
+		int s = spin[i];
+		if (cluster_assign[s] == 0)
+		{
+			num_clusters++;		
+			cluster_assign[s] = num_clusters;
+			#ifdef DEBUG
+			printf("Setting cluster %d to %d.\n", s, num_clusters);
+			#endif
+		}
+	}
+	
+
+    /*
+	DLList_Iter<NNode*> iter;
+	NNode *n_cur=iter.First(net->node_list);		
+	n_cur = iter.First(net->node_list);
+    */
+
+	//And now assign each node to its new community
+	q = num_clusters;	
+	for (unsigned int i = 0; i < num_nodes; i++)
+	{
+		#ifdef DEBUG
+		printf("Setting node %d to %d.\n", i, cluster_assign[spin[i]]);
+		#endif
+		unsigned int s = cluster_assign[spin[i]];
+		spin[i] = s;
+		#ifdef DEBUG
+		printf("Have set node %d to %d.\n", i, s);
+		#endif
+	}
+	assign_initial_conf(false);
+	
+	delete cluster_assign;
+		
+	if (temperature) { *temperature=t; }
+	
+	if (community_size)
+	{
+		//Initialize the vector
+		IGRAPH_CHECK(igraph_vector_resize(community_size, q));
+		for (unsigned int spin_opt = 1; spin_opt <= q; spin_opt++)
+		{
+			//Set the community size
+			VECTOR(*community_size)[spin_opt-1]=csize[spin_opt];
+		}
+	}
+	
+	//Set the membership	
+	if (membership) 
+	{
+		IGRAPH_CHECK(igraph_vector_resize(membership, num_nodes));		
+		for (unsigned int i = 0; i < num_nodes; i++)
+		{
+			VECTOR(*membership)[ i ]= spin[i]-1;
+		}
+	}
+	
+	double Q = 0.0; //Modularity
+	if (adhesion)
+	{
+		IGRAPH_CHECK(igraph_matrix_resize(adhesion, q, q));
+		IGRAPH_CHECK(igraph_matrix_resize(normalised_adhesion, q, q));
+		
+		double **num_links_pos = 0;
+		double **num_links_neg = 0;
+		//memory allocated for elements of rows.
+		num_links_pos = new double *[q+1] ;
+		num_links_neg = new double *[q+1] ;
+
+		//memory allocated for  elements of each column.
+		for( unsigned int i = 0 ; i < q+1 ; i++)
+		{
+			num_links_pos[i] = new double[q+1];
+			num_links_neg[i] = new double[q+1];
+		}
+		
+
+		
+		//Init num_links
+		for (unsigned int i = 0; i <= q; i++)
+		{
+			for (unsigned int j = 0; j <= q; j++)
+			{
+				num_links_pos[i][j] = 0.0;
+				num_links_neg[i][j] = 0.0;
+			}
+		}
+		
+		DLList_Iter<NLink*> iter_l;
+		NLink *l_cur = iter_l.First(net->link_list);
+		
+		double w = 0.0;
+		
+		while (!iter_l.End())
+		{
+			w = l_cur->Get_Weight();
+			unsigned int a = spin[l_cur->Get_Start()->Get_Index()];
+			unsigned int b =  spin[l_cur->Get_End()->Get_Index()];
+			if (w > 0)
+			{
+				num_links_pos[a][b] += w;
+				if (!is_directed && a != b) //Only one edge is defined in case it is undirected
+					num_links_pos[b][a] += w;
+			}
+			else
+			{
+				num_links_neg[a][b] -= w;
+				if (!is_directed && a != b) //Only one edge is defined in case it is undirected
+					num_links_neg[b][a] -= w;
+			}
+			
+			l_cur = iter_l.Next();
+		} //while links
+		
+		#ifdef DEBUG
+		printf("d_p: %f\n", d_p);
+		printf("d_n: %f\n", d_n);
+		#endif
+	
+		double expected = 0.0;
+		double a = 0.0;
+		double normal_a = 0.0;
+		
+		double delta, u_p, u_n;
+		double max_expected, max_a;
+		
+		//We don't take into account the lambda or gamma for
+		//computing the modularity and adhesion, since they
+		//are then incomparable to other definitions.
+		for (unsigned int i = 1; i <= q; i++)
+		{
+			for (unsigned int j = 1; j <= q; j++)
+			{
+				if (!is_directed && i == j)
+					expected	= degree_community_pos_out[i] * degree_community_pos_in[j]/(m_p == 0 ? 1 : 2*m_p)
+								- degree_community_neg_out[i] * degree_community_neg_in[j]/(m_n == 0 ? 1 : 2*m_n);
+				else
+					expected	= degree_community_pos_out[i] * degree_community_pos_in[j]/(m_p == 0 ? 1: m_p)
+								- degree_community_neg_out[i] * degree_community_neg_in[j]/(m_n == 0 ? 1 : m_n);
+				
+				a			= (num_links_pos[i][j] - num_links_neg[i][j]) - expected;
+				
+				if (i == j) //cohesion
+				{
+					if (is_directed)
+						delta	= d_p * csize[i] * (csize[i] - 1); //Maximum amount
+					else
+						delta	= d_p * csize[i] * (csize[i] - 1)/2; //Maximum amount
+					
+					u_p		= delta - num_links_pos[i][i]; //Add as many positive links we can
+					u_n		= -num_links_neg[i][i]; //Delete as many negative links we can				
+					Q	   += a;
+				}
+				else //adhesion
+				{
+					if (is_directed)
+						delta	= d_n * csize[i] * csize[j]*2; //Maximum amount
+					else
+						delta	= d_n * csize[i] * csize[j]; //Maximum amount
+
+					u_p		= -num_links_pos[i][j]; //Delete as many positive links we can
+					u_n		= delta - num_links_neg[i][j]; //Add as many negative links we can
+				}
+				
+				if (!is_directed && i == j)
+					max_expected	= (degree_community_pos_out[i] + u_p) * (degree_community_pos_in[j] + u_p)/((m_p + u_p) == 0 ? 1 : 2*(m_p + u_p)) 
+									- (degree_community_neg_out[i] - u_n) * (degree_community_neg_in[j] + u_n)/((m_n + u_n) == 0 ? 1 : 2*(m_n + u_n));
+				else
+					max_expected	= (degree_community_pos_out[i] + u_p) * (degree_community_pos_in[j] + u_p)/((m_p + u_p) == 0 ? 1 : m_p + u_p) 
+									- (degree_community_neg_out[i] - u_n) * (degree_community_neg_in[j] + u_n)/((m_n + u_n) == 0 ? 1 : m_n + u_n);
+				//printf("%f/%f %d/%d\t", num_links_pos[i][j], num_links_neg[i][j], csize[i], csize[j]);
+				//printf("%f/%f - %f(%f)\t", u_p, u_n, expected, max_expected);
+				max_a			= ((num_links_pos[i][j] + u_p) - (num_links_neg[i][j] + u_n)) - max_expected;				
+				
+				
+				//In cases where we haven't actually found a ground state
+				//the adhesion/cohesion *might* not be negative/positive,
+				//hence the maximum adhesion and cohesion might behave quite
+				//strangely. In order to prevent that, we limit them to 1 in
+				//absolute value, and prevent from dividing by zero (even if
+				//chuck norris would).
+				if (i == j)
+					normal_a = a/(max_a == 0 ? a : max_a);
+				else
+					normal_a = -a/(max_a == 0 ? a : max_a);
+					
+				if (normal_a > 1)
+					normal_a = 1;
+				else if (normal_a < -1)
+					normal_a = -1;
+					
+				MATRIX(*adhesion, i - 1, j - 1) = a;
+				MATRIX(*normalised_adhesion, i - 1, j - 1) = normal_a;
+			} //for j
+			//printf("\n");
+		} //for i
+		
+		//free the allocated memory
+		for( unsigned int i = 0 ; i < q+1 ; i++ )
+		{
+			delete [] num_links_pos[i] ;
+			delete [] num_links_neg[i];
+		}
+		delete [] num_links_pos ;	
+		delete [] num_links_neg ;
+		
+	} //adhesion
+	
+	if (modularity)  
+	{ 
+		if (is_directed)
+			*modularity=Q/(m_p + m_n); 
+		else
+			*modularity=2*Q/(m_p + m_n); //Correction for the way m_p and m_n are counted. Modularity is 1/m, not 1/2m
+	}
+	
+	if (polarization) 
+	{ 
+		double sum_ad = 0.0;
+		for (unsigned int i = 0; i < q; i++)
+		{
+			for (unsigned int j = 0; j < q; j++)
+			{
+				if (i != j)
+				{
+					sum_ad -= MATRIX(*normalised_adhesion, i, j);
+				}
+			}
+		}
+		*polarization= sum_ad/(q*q - q);
+	}
+	#ifdef DEBUG	
+	printf("Finished writing cluster.\n");
+	#endif
+	return num_nodes;
+}
diff --git a/src/pottsmodel_2.h b/src/pottsmodel_2.h
new file mode 100644
index 0000000..9af31a7
--- /dev/null
+++ b/src/pottsmodel_2.h
@@ -0,0 +1,165 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+   02110-1301 USA
+
+*/
+
+/* The original version of this file was written by J�rg Reichardt 
+   This file was modified by Vincent Traag
+   The original copyright notice follows here */
+
+/***************************************************************************
+                          pottsmodel.h  -  description
+                             -------------------
+    begin                : Fri May 28 2004
+    copyright            : (C) 2004 by 
+    email                : 
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef POTTSMODEL_H
+#define POTTSMODEL_H
+
+#include "NetDataTypes.h"
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.h"
+
+#define qmax 500
+
+class PottsModel {
+  private:
+  //  HugeArray<double> neg_gammalookup;
+  //  HugeArray<double> pos_gammalookup;
+    DL_Indexed_List<unsigned int*> *new_spins;
+    DL_Indexed_List<unsigned int*> *previous_spins;
+    HugeArray<HugeArray<double>*> correlation;
+    network *net;
+    unsigned int q;
+    unsigned int operation_mode;
+    FILE *Qfile, *Magfile;
+    double Qmatrix[qmax+1][qmax+1];
+    double* Qa;
+    double* weights;
+    double total_degree_sum;
+    unsigned long num_of_nodes;
+    unsigned long num_of_links;
+    unsigned long k_max;
+    double energy;
+    double acceptance;
+    double *neighbours;
+  public:
+    PottsModel(network *net, unsigned int q, int norm_by_degree);
+    ~PottsModel();
+    double* color_field;
+    unsigned long assign_initial_conf(int spin);
+    unsigned long initialize_lookup(double kT, double gamma);
+    double initialize_Qmatrix(void);
+    double calculate_Q(void);
+    double calculate_genQ(double gamma);
+    double FindStartTemp(double gamma, double prob,  double ts);
+    long   HeatBathParallelLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps);
+    double HeatBathLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps);
+    long   HeatBathParallelLookup(double gamma, double prob, double kT, unsigned int max_sweeps);
+    double HeatBathLookup(double gamma, double prob, double kT, unsigned int max_sweeps);
+    double GammaSweep(double gamma_start, double gamma_stop, double prob, unsigned int steps, bool non_parallel=true, int repetitions=1);
+    double GammaSweepZeroTemp(double gamma_start, double gamma_stop, double prob, unsigned int steps, bool non_parallel=true, int repetitions=1);
+    long   WriteCorrelationMatrix(char *filename);
+    double calculate_energy(double gamma);
+    long   WriteClusters(igraph_real_t *modularity,
+			 igraph_real_t *temperature, 
+			 igraph_vector_t *csize, igraph_vector_t *membership,
+			 double kT, double gamma);
+    long   WriteSoftClusters(char *filename, double threshold);
+    double Get_Energy(void) { return energy;}
+    double FindCommunityFromStart(double gamma, double prob, char *nodename,
+				  igraph_vector_t *result, 
+				  igraph_real_t *cohesion,
+				  igraph_real_t *adhesion,
+				  igraph_integer_t *inner_links,
+				  igraph_integer_t *outer_links);
+};
+
+
+class PottsModelN {
+  private:
+  //  HugeArray<double> neg_gammalookup;
+  //  HugeArray<double> pos_gammalookup;
+    DL_Indexed_List<unsigned int*> *new_spins;
+    DL_Indexed_List<unsigned int*> *previous_spins;
+    HugeArray<HugeArray<double>*> correlation;
+    network *net;
+		
+    unsigned int q; //number of communities
+    double m_p; //number of positive ties (or sum of degrees), this equals the number of edges only if it is undirected and each edge has a weight of 1
+	double m_n; //number of negative ties (or sum of degrees)
+	unsigned int num_nodes; //number of nodes
+	bool is_directed;
+	
+	bool is_init;
+	
+	double *degree_pos_in; //Postive indegree of the nodes (or sum of weights)
+	double *degree_neg_in; //Negative indegree of the nodes (or sum of weights)
+	double *degree_pos_out; //Postive outdegree of the nodes (or sum of weights)
+	double *degree_neg_out; //Negative outdegree of the nodes (or sum of weights)	
+	
+	double *degree_community_pos_in; //Positive sum of indegree for communities
+	double *degree_community_neg_in; //Negative sum of indegree for communities
+	double *degree_community_pos_out; //Positive sum of outegree for communities
+	double *degree_community_neg_out; //Negative sum of outdegree for communities
+	
+	unsigned int *csize; //The number of nodes in each community
+	unsigned int *spin; //The membership of each node
+	
+    double *neighbours; //Array of neighbours of a vertex in each community
+    double *weights; //Weights of all possible transitions to another community
+	
+  public:
+    PottsModelN(network *n, unsigned int num_communities, bool directed);
+    ~PottsModelN();
+    void assign_initial_conf(bool init_spins);
+	double FindStartTemp(double gamma, double lambda, double ts);
+    double HeatBathLookup(double gamma, double lambda, double t, unsigned int max_sweeps);
+	double HeatBathJoin(double gamma, double lambda);
+    double HeatBathLookupZeroTemp(double gamma, double lambda, unsigned int max_sweeps);	
+	long WriteClusters(igraph_real_t *modularity,
+							   igraph_real_t *temperature,
+							   igraph_vector_t *community_size,
+							   igraph_vector_t *membership,
+							   igraph_matrix_t *adhesion,
+							   igraph_matrix_t *normalised_adhesion,
+							   igraph_real_t *polarization,
+							   double t,
+							   double d_p,
+							   double d_n,
+							   double gamma,
+							   double lambda);
+};
+
+#endif
diff --git a/src/progress.c b/src/progress.c
new file mode 100644
index 0000000..89a8cbd
--- /dev/null
+++ b/src/progress.c
@@ -0,0 +1,152 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_progress.h"
+#include "config.h"
+
+static IGRAPH_THREAD_LOCAL igraph_progress_handler_t *igraph_i_progress_handler=0;
+static IGRAPH_THREAD_LOCAL char igraph_i_progressmsg_buffer[1000];
+
+/**
+ * \function igraph_progress
+ * Report progress
+ * 
+ * Note that the usual way to report progress is the \ref IGRAPH_PROGRESS 
+ * macro, as that takes care of the return value of the progress 
+ * handler.
+ * \param message A string describing the function or algorithm 
+ *     that is reporting the progress. Current igraph functions
+ *     always use the name \p message argument if reporting from the 
+ *     same function.
+ * \param percent Numeric, the percentage that was completed by the 
+ *     algorithm or function.
+ * \param data User-defined data. Current igraph functions that 
+ *     report progress pass a null pointer here. Users can 
+ *     write their own progress handlers and functions with progress 
+ *     reporting, and then pass some meaningfull context here.
+ * \return If there is a progress handler installed and 
+ *     it does not return \c IGRAPH_SUCCESS, then \c IGRAPH_INTERRUPTED 
+ *     is returned.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_progress(const char *message, igraph_real_t percent, void *data) {
+  if (igraph_i_progress_handler) {
+    if (igraph_i_progress_handler(message, percent, data) != IGRAPH_SUCCESS)
+      return IGRAPH_INTERRUPTED;
+  }
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_progressf
+ * Report progress, printf-like version
+ * 
+ * This is a more flexible version of \ref igraph_progress(), with 
+ * a printf-like template string. First the template string 
+ * is filled with the additional arguments and then \ref
+ * igraph_progress() is called.
+ * 
+ * </para><para>Note that there is an upper limit for the length of
+ * the \p message string, currently 1000 characters.
+ * \param message A string describing the function or algorithm 
+ *     that is reporting the progress. For this function this is a 
+ *     template string, using the same syntax as the standard 
+ *     \c libc \c printf function.
+ * \param percent Numeric, the percentage that was completed by the 
+ *     algorithm or function.
+ * \param data User-defined data. Current igraph functions that 
+ *     report progress pass a null pointer here. Users can 
+ *     write their own progress handlers and functions with progress 
+ *     reporting, and then pass some meaningfull context here.
+ * \param ... Additional argument that were specified in the 
+ *     \p message argument.
+ * \return If there is a progress handler installed and 
+ *     it does not return \c IGRAPH_SUCCESS, then \c IGRAPH_INTERRUPTED 
+ *     is returned.
+ * \return 
+ */
+
+int igraph_progressf(const char *message, igraph_real_t percent, void *data, 
+		     ...) {
+  va_list ap;
+  va_start(ap, data);
+  vsnprintf(igraph_i_progressmsg_buffer, 
+	    sizeof(igraph_i_progressmsg_buffer) / sizeof(char), message, ap);
+  return igraph_progress(igraph_i_progressmsg_buffer, percent, data);
+}
+
+#ifndef USING_R
+
+/**
+ * \function igraph_progress_handler_stderr
+ * A simple predefined progress handler
+ * 
+ * This simple progress handler first prints \p message, and then
+ * the percentage complete value in a short message to standard error.
+ * \param message A string describing the function or algorithm 
+ *     that is reporting the progress. Current igraph functions
+ *     always use the name \p message argument if reporting from the 
+ *     same function.
+ * \param percent Numeric, the percentage that was completed by the 
+ *     algorithm or function.
+ * \param data User-defined data. Current igraph functions that 
+ *     report progress pass a null pointer here. Users can 
+ *     write their own progress handlers and functions with progress 
+ *     reporting, and then pass some meaningfull context here.
+ * \return This function always returns with \c IGRAPH_SUCCESS.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_progress_handler_stderr(const char *message, igraph_real_t percent,
+				  void* data) {
+  IGRAPH_UNUSED(data);
+  fputs(message, stderr);
+  fprintf(stderr, "%.1f percent ready\n", (double)percent);
+  return 0;
+}
+#endif
+
+/**
+ * \function igraph_set_progress_handler
+ * Install a progress handler, or remove the current handler
+ * 
+ * There is a single simple predefined progress handler:
+ * \ref igraph_progress_handler_stderr().
+ * \param new_handler Pointer to a function of type 
+ *     \ref igraph_progress_handler_t, the progress handler function to 
+ *     install. To uninstall the current progress handler, this argument
+ *     can be a null pointer.
+ * \return Pointer to the previously installed progress handler function.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_progress_handler_t *
+igraph_set_progress_handler(igraph_progress_handler_t new_handler) {
+  igraph_progress_handler_t *previous_handler=igraph_i_progress_handler;
+  igraph_i_progress_handler = new_handler;
+  return previous_handler;
+}
diff --git a/src/prpack.cpp b/src/prpack.cpp
new file mode 100644
index 0000000..1b145c7
--- /dev/null
+++ b/src/prpack.cpp
@@ -0,0 +1,98 @@
+/* -*- 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 "prpack.h"
+#include "prpack/prpack_igraph_graph.h"
+#include "prpack/prpack_solver.h"
+#include "igraph_error.h"
+
+using namespace prpack;
+using namespace std;
+
+/*
+ * PRPACK-based implementation of \c igraph_personalized_pagerank.
+ *
+ * See \c igraph_personalized_pagerank for the documentation of the parameters.
+ */
+int igraph_personalized_pagerank_prpack(const igraph_t *graph, igraph_vector_t *vector,
+            igraph_real_t *value, const igraph_vs_t vids,
+            igraph_bool_t directed, igraph_real_t damping, 
+            igraph_vector_t *reset,
+            const igraph_vector_t *weights) {
+    long int i, no_of_nodes = igraph_vcount(graph), nodes_to_calc;
+    igraph_vit_t vit;
+    double* u = 0;
+    double* v = 0;
+    const prpack_result* res;
+
+    if (reset) {
+        /* Normalize reset vector so the sum is 1 */
+        double reset_sum = igraph_vector_sum(reset);
+        if (igraph_vector_min(reset) < 0) {
+            IGRAPH_ERROR("the reset vector must not contain negative elements", IGRAPH_EINVAL);
+        }
+        if (reset_sum == 0) {
+            IGRAPH_ERROR("the sum of the elements in the reset vector must not be zero", IGRAPH_EINVAL);
+        }
+
+        // Construct the personalization vector
+        v = new double[no_of_nodes];
+        for (i = 0; i < no_of_nodes; i++) {
+            v[i] = VECTOR(*reset)[i] / reset_sum;
+        }
+    }
+
+    // Construct and run the solver
+    prpack_igraph_graph prpack_graph(graph, weights, directed);
+    prpack_solver solver(&prpack_graph, false);
+    res = solver.solve(damping, 1e-10, u, v, "");
+
+    // Check whether the solver converged
+    // TODO: this is commented out because some of the solvers do not implement it yet
+    /*
+    if (!res->converged) {
+        IGRAPH_WARNING("PRPACK solver failed to converge. Results may be inaccurate.");
+    }
+    */
+
+    // Fill the result vector
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+    nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+    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];
+    }
+    igraph_vit_destroy(&vit);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    // TODO: can we get the eigenvalue? We'll just fake it until we can.
+    if (value) {
+        *value = 1.0;
+    }
+    delete res;
+
+    return IGRAPH_SUCCESS;
+}
+
diff --git a/src/prpack.h b/src/prpack.h
new file mode 100644
index 0000000..18d7fad
--- /dev/null
+++ b/src/prpack.h
@@ -0,0 +1,54 @@
+/* -*- 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 IGRAPH_PRPACK
+#define IGRAPH_PRPACK
+
+#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"
+
+#include "igraph_interface.h"
+
+__BEGIN_DECLS
+
+int igraph_personalized_pagerank_prpack(const igraph_t *graph, igraph_vector_t *vector,
+		    igraph_real_t *value, const igraph_vs_t vids,
+		    igraph_bool_t directed, igraph_real_t damping, 
+		    igraph_vector_t *reset,
+		    const igraph_vector_t *weights);
+
+__END_DECLS
+
+#endif
+
diff --git a/src/prpack/prpack.h b/src/prpack/prpack.h
new file mode 100644
index 0000000..bcddf37
--- /dev/null
+++ b/src/prpack/prpack.h
@@ -0,0 +1,11 @@
+#ifndef PRPACK
+#define PRPACK
+
+#include "prpack_csc.h"
+#include "prpack_csr.h"
+#include "prpack_edge_list.h"
+#include "prpack_base_graph.h"
+#include "prpack_solver.h"
+#include "prpack_result.h"
+
+#endif
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/prpack_base_graph.cpp b/src/prpack/prpack_base_graph.cpp
new file mode 100644
index 0000000..b7a6cbe
--- /dev/null
+++ b/src/prpack/prpack_base_graph.cpp
@@ -0,0 +1,333 @@
+#include "prpack_base_graph.h"
+#include "prpack_utils.h"
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include <limits>
+using namespace prpack;
+using namespace std;
+
+void prpack_base_graph::initialize() {
+    heads = NULL;
+    tails = NULL;
+    vals = NULL;
+}
+
+prpack_base_graph::prpack_base_graph() {
+	initialize();
+	num_vs = num_es = 0;
+}
+
+prpack_base_graph::prpack_base_graph(const prpack_csc* g) {
+    initialize();
+    num_vs = g->num_vs;
+    num_es = g->num_es;
+    // fill in heads and tails
+    num_self_es = 0;
+    int* hs = g->heads;
+    int* ts = g->tails;
+    tails = new int[num_vs];
+    memset(tails, 0, num_vs*sizeof(tails[0]));
+    for (int h = 0; h < num_vs; ++h) {
+        const int start_ti = hs[h];
+        const int end_ti = (h + 1 != num_vs) ? hs[h + 1] : num_es;
+        for (int ti = start_ti; ti < end_ti; ++ti) {
+            const int t = ts[ti];
+            ++tails[t];
+            if (h == t)
+                ++num_self_es;
+        }
+    }
+    for (int i = 0, sum = 0; i < num_vs; ++i) {
+        const int temp = sum;
+        sum += tails[i];
+        tails[i] = temp;
+    }
+    heads = new int[num_es];
+    int* osets = new int[num_vs];
+    memset(osets, 0, num_vs*sizeof(osets[0]));
+    for (int h = 0; h < num_vs; ++h) {
+        const int start_ti = hs[h];
+        const int end_ti = (h + 1 != num_vs) ? hs[h + 1] : num_es;
+        for (int ti = start_ti; ti < end_ti; ++ti) {
+            const int t = ts[ti];
+            heads[tails[t] + osets[t]++] = h;
+        }
+    }
+    // clean up
+    delete[] osets;
+}
+
+prpack_base_graph::prpack_base_graph(const prpack_int64_csc* g) {
+    initialize();
+    // TODO remove the assert and add better behavior
+    assert(num_vs <= std::numeric_limits<int>::max());
+    num_vs = (int)g->num_vs;
+    num_es = (int)g->num_es;
+    // fill in heads and tails
+    num_self_es = 0;
+    int64_t* hs = g->heads;
+    int64_t* ts = g->tails;
+    tails = new int[num_vs];
+    memset(tails, 0, num_vs*sizeof(tails[0]));
+    for (int h = 0; h < num_vs; ++h) {
+        const int start_ti = (int)hs[h];
+        const int end_ti = (h + 1 != num_vs) ? (int)hs[h + 1] : num_es;
+        for (int ti = start_ti; ti < end_ti; ++ti) {
+            const int t = (int)ts[ti];
+            ++tails[t];
+            if (h == t)
+                ++num_self_es;
+        }
+    }
+    for (int i = 0, sum = 0; i < num_vs; ++i) {
+        const int temp = sum;
+        sum += tails[i];
+        tails[i] = temp;
+    }
+    heads = new int[num_es];
+    int* osets = new int[num_vs];
+    memset(osets, 0, num_vs*sizeof(osets[0]));
+    for (int h = 0; h < num_vs; ++h) {
+        const int start_ti = (int)hs[h];
+        const int end_ti = (h + 1 != num_vs) ? (int)hs[h + 1] : num_es;
+        for (int ti = start_ti; ti < end_ti; ++ti) {
+            const int t = (int)ts[ti];
+            heads[tails[t] + osets[t]++] = h;
+        }
+    }
+    // clean up
+    delete[] osets;
+}
+
+prpack_base_graph::prpack_base_graph(const prpack_csr* g) {
+    initialize();
+    assert(false);
+    // TODO
+}
+
+prpack_base_graph::prpack_base_graph(const prpack_edge_list* g) {
+    initialize();
+    num_vs = g->num_vs;
+    num_es = g->num_es;
+    // fill in heads and tails
+    num_self_es = 0;
+    int* hs = g->heads;
+    int* ts = g->tails;
+    tails = new int[num_vs];
+    memset(tails, 0, num_vs*sizeof(tails[0]));
+    for (int i = 0; i < num_es; ++i) {
+        ++tails[ts[i]];
+        if (hs[i] == ts[i])
+            ++num_self_es;
+    }
+    for (int i = 0, sum = 0; i < num_vs; ++i) {
+        const int temp = sum;
+        sum += tails[i];
+        tails[i] = temp;
+    }
+    heads = new int[num_es];
+    int* osets = new int[num_vs];
+    memset(osets, 0, num_vs*sizeof(osets[0]));
+    for (int i = 0; i < num_es; ++i)
+        heads[tails[ts[i]] + osets[ts[i]]++] = hs[i];
+    // clean up
+    delete[] osets;
+}
+
+prpack_base_graph::prpack_base_graph(const char* filename, const char* format, const bool weighted) {
+    initialize();
+    FILE* f = fopen(filename, "r");
+    const string s(filename);
+    const string t(format);
+    const string ext = (t == "") ? s.substr(s.rfind('.') + 1) : t;
+    if (ext == "smat") {
+        read_smat(f, weighted);
+    } else {
+        prpack_utils::validate(!weighted, 
+            "Error: graph format is not compatible with weighted option.");
+        if (ext == "edges" || ext == "eg2") {
+            read_edges(f);
+        } else if (ext == "graph-txt") {
+            read_ascii(f);
+        } else {
+            prpack_utils::validate(false, "Error: invalid graph format.");
+        }
+    }
+    fclose(f);
+}
+
+prpack_base_graph::~prpack_base_graph() {
+    delete[] heads;
+    delete[] tails;
+    delete[] vals;
+}
+
+void prpack_base_graph::read_smat(FILE* f, const bool weighted) {
+    // read in header
+    double ignore = 0.0;
+    assert(fscanf(f, "%d %lf %d", &num_vs, &ignore, &num_es) == 3);
+    // fill in heads and tails
+    num_self_es = 0;
+    int* hs = new int[num_es];
+    int* ts = new int[num_es];
+    heads = new int[num_es];
+    tails = new int[num_vs];
+    double* vs = NULL;
+    if (weighted) {
+        vs = new double[num_es];
+        vals = new double[num_es];
+    }
+    memset(tails, 0, num_vs*sizeof(tails[0]));
+    for (int i = 0; i < num_es; ++i) {
+        assert(fscanf(f, "%d %d %lf", 
+            &hs[i], &ts[i], &((weighted) ? vs[i] : ignore)) == 3);
+        ++tails[ts[i]];
+        if (hs[i] == ts[i])
+            ++num_self_es;
+    }
+    for (int i = 0, sum = 0; i < num_vs; ++i) {
+        const int temp = sum;
+        sum += tails[i];
+        tails[i] = temp;
+    }
+    int* osets = new int[num_vs];
+    memset(osets, 0, num_vs*sizeof(osets[0]));
+    for (int i = 0; i < num_es; ++i) {
+        const int idx = tails[ts[i]] + osets[ts[i]]++;
+        heads[idx] = hs[i];
+        if (weighted)
+            vals[idx] = vs[i];
+    }
+    // clean up
+    delete[] hs;
+    delete[] ts;
+    delete[] vs;
+    delete[] osets;
+}
+
+void prpack_base_graph::read_edges(FILE* f) {
+    vector<vector<int> > al;
+    int h, t;
+    num_es = num_self_es = 0;
+    while (fscanf(f, "%d %d", &h, &t) == 2) {
+        const int m = (h < t) ? t : h;
+        if ((int) al.size() < m + 1)
+            al.resize(m + 1);
+        al[t].push_back(h);
+        ++num_es;
+        if (h == t)
+            ++num_self_es;
+    }
+    num_vs = al.size();
+    heads = new int[num_es];
+    tails = new int[num_vs];
+    for (int tails_i = 0, heads_i = 0; tails_i < num_vs; ++tails_i) {
+        tails[tails_i] = heads_i;
+        for (int j = 0; j < (int) al[tails_i].size(); ++j)
+            heads[heads_i++] = al[tails_i][j];
+    }
+}
+
+void prpack_base_graph::read_ascii(FILE* f) {
+    assert(fscanf(f, "%d", &num_vs) == 1);
+    while (getc(f) != '\n');
+    vector<int>* al = new vector<int>[num_vs];
+    num_es = num_self_es = 0;
+    char s[32];
+    for (int h = 0; h < num_vs; ++h) {
+        bool line_ended = false;
+        while (!line_ended) {
+            for (int i = 0; ; ++i) {
+                s[i] = getc(f);
+                if ('9' < s[i] || s[i] < '0') {
+                    line_ended = s[i] == '\n';
+                    if (i != 0) {
+                        s[i] = '\0';
+                        const int t = atoi(s);
+                        al[t].push_back(h);
+                        ++num_es;
+                        if (h == t)
+                            ++num_self_es;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    heads = new int[num_es];
+    tails = new int[num_vs];
+    for (int tails_i = 0, heads_i = 0; tails_i < num_vs; ++tails_i) {
+        tails[tails_i] = heads_i;
+        for (int j = 0; j < (int) al[tails_i].size(); ++j)
+            heads[heads_i++] = al[tails_i][j];
+    }
+    delete[] al;
+}
+
+prpack_base_graph::prpack_base_graph(int nverts, int nedges, 
+        std::pair<int,int>* edges) {
+    initialize();
+    num_vs = nverts;
+    num_es = nedges;
+
+    // fill in heads and tails
+    num_self_es = 0;
+    int* hs = new int[num_es];
+    int* ts = new int[num_es];
+    tails = new int[num_vs];
+    memset(tails, 0, num_vs*sizeof(tails[0]));
+    for (int i = 0; i < num_es; ++i) {
+        assert(edges[i].first >= 0 && edges[i].first < num_vs);
+        assert(edges[i].second >= 0 && edges[i].second < num_vs);
+        hs[i] = edges[i].first;
+        ts[i] = edges[i].second;
+        ++tails[ts[i]];
+        if (hs[i] == ts[i])
+            ++num_self_es;
+    }
+    for (int i = 0, sum = 0; i < num_vs; ++i) {
+        int temp = sum;
+        sum += tails[i];
+        tails[i] = temp;
+    }
+    heads = new int[num_es];
+    int* osets = new int[num_vs];
+    memset(osets, 0, num_vs*sizeof(osets[0]));
+    for (int i = 0; i < num_es; ++i)
+        heads[tails[ts[i]] + osets[ts[i]]++] = hs[i];
+    // clean up
+    delete[] hs;
+    delete[] ts;
+    delete[] osets;
+}
+
+/** Normalize the edge weights to sum to one.  
+ */
+void prpack_base_graph::normalize_weights() {
+    if (!vals) { 
+        // skip normalizing weights if not using values
+        return;
+    }
+    std::vector<double> rowsums(num_vs,0.);
+    // the graph is in a compressed in-edge list.
+    for (int i=0; i<num_vs; ++i) {
+        int end_ei = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+        for (int ei=tails[i]; ei < end_ei; ++ei) {
+            int head = heads[ei];
+            rowsums[head] += vals[ei];
+        }
+    }
+    for (int i=0; i<num_vs; ++i) {
+        rowsums[i] = 1./rowsums[i];
+    }
+    for (int i=0; i<num_vs; ++i) {
+        int end_ei = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+        for (int ei=tails[i]; ei < end_ei; ++ei) {
+            vals[ei] *= rowsums[heads[ei]];
+        }
+    }
+}
+
diff --git a/src/prpack/prpack_base_graph.h b/src/prpack/prpack_base_graph.h
new file mode 100644
index 0000000..1150184
--- /dev/null
+++ b/src/prpack/prpack_base_graph.h
@@ -0,0 +1,42 @@
+#ifndef PRPACK_ADJACENCY_LIST
+#define PRPACK_ADJACENCY_LIST
+#include "prpack_csc.h"
+#include "prpack_csr.h"
+#include "prpack_edge_list.h"
+#include <cstdio>
+#include <utility>
+
+namespace prpack {
+
+    class prpack_base_graph {
+        private:
+            // helper methods
+            void initialize();
+            void read_smat(std::FILE* f, const bool weighted);
+            void read_edges(std::FILE* f);
+            void read_ascii(std::FILE* f);
+        public:
+            // instance variables
+            int num_vs;
+            int num_es;
+            int num_self_es;
+            int* heads;
+            int* tails;
+            double* vals;
+            // constructors
+            prpack_base_graph();    // only to support inheritance
+            prpack_base_graph(const prpack_csc* g);
+            prpack_base_graph(const prpack_int64_csc* g);
+            prpack_base_graph(const prpack_csr* g);
+            prpack_base_graph(const prpack_edge_list* g);
+            prpack_base_graph(const char* filename, const char* format, const bool weighted);
+            prpack_base_graph(int nverts, int nedges, std::pair<int,int>* edges);
+            // destructor
+            ~prpack_base_graph();
+            // operations
+            void normalize_weights();
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_csc.h b/src/prpack/prpack_csc.h
new file mode 100644
index 0000000..7826fa3
--- /dev/null
+++ b/src/prpack/prpack_csc.h
@@ -0,0 +1,25 @@
+#ifndef PRPACK_CSC
+#define PRPACK_CSC
+
+#include <stdint.h>
+
+namespace prpack {
+
+    class prpack_csc {
+        public:
+            int num_vs;
+            int num_es;
+            int* heads;
+            int* tails;
+    };
+
+    class prpack_int64_csc {
+        public:
+            int64_t num_vs;
+            int64_t num_es;
+            int64_t* heads;
+            int64_t* tails;
+    };
+};
+
+#endif
diff --git a/src/prpack/prpack_csr.h b/src/prpack/prpack_csr.h
new file mode 100644
index 0000000..5eab466
--- /dev/null
+++ b/src/prpack/prpack_csr.h
@@ -0,0 +1,16 @@
+#ifndef PRPACK_CSR
+#define PRPACK_CSR
+
+namespace prpack {
+
+    class prpack_csr {
+        public:
+            int num_vs;
+            int num_es;
+            int* heads;
+            int* tails;
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_edge_list.h b/src/prpack/prpack_edge_list.h
new file mode 100644
index 0000000..0f62113
--- /dev/null
+++ b/src/prpack/prpack_edge_list.h
@@ -0,0 +1,16 @@
+#ifndef PRPACK_EDGE_LIST
+#define PRPACK_EDGE_LIST
+
+namespace prpack {
+
+    class prpack_edge_list {
+        public:
+            int num_vs;
+            int num_es;
+            int* heads;
+            int* tails;
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_igraph_graph.cpp b/src/prpack/prpack_igraph_graph.cpp
new file mode 100644
index 0000000..76f9bf4
--- /dev/null
+++ b/src/prpack/prpack_igraph_graph.cpp
@@ -0,0 +1,146 @@
+#include "prpack_igraph_graph.h"
+#include <cstdlib>
+#include <cstring>
+
+using namespace prpack;
+using namespace std;
+
+#ifdef PRPACK_IGRAPH_SUPPORT
+
+prpack_igraph_graph::prpack_igraph_graph(const igraph_t* g, const igraph_vector_t* weights,
+		igraph_bool_t directed) {
+    const igraph_bool_t treat_as_directed = igraph_is_directed(g) && directed;
+    igraph_es_t es;
+    igraph_eit_t eit;
+	igraph_vector_t neis;
+    long int i, j, eid, sum, temp, num_ignored_es;
+    int *p_head, *p_head_copy;
+    double* p_weight;
+
+    // Get the number of vertices and edges. For undirected graphs, we add
+    // an edge in both directions.
+    num_vs = igraph_vcount(g);
+    num_es = igraph_ecount(g);
+	num_self_es = 0;
+    if (!treat_as_directed) {
+        num_es *= 2;
+    }
+
+    // Allocate memory for heads and tails
+    p_head = heads = new int[num_es];
+    tails = new int[num_vs];
+    memset(tails, 0, num_vs * sizeof(tails[0]));
+
+    // Allocate memory for weights if needed
+    if (weights != 0) {
+        p_weight = vals = new double[num_es];
+    }
+
+    // Count the number of ignored edges (those with negative or zero weight)
+    num_ignored_es = 0;
+
+	if (treat_as_directed) {
+		// Select all the edges and iterate over them by the source vertices
+		es = igraph_ess_all(IGRAPH_EDGEORDER_TO);
+
+		// Add the edges
+		igraph_eit_create(g, es, &eit);
+		while (!IGRAPH_EIT_END(eit)) {
+			eid = IGRAPH_EIT_GET(eit);
+			IGRAPH_EIT_NEXT(eit);
+
+            // Handle the weight
+            if (weights != 0) {
+                // Does this edge have zero or negative weight?
+                if (VECTOR(*weights)[eid] <= 0) {
+                    // Ignore it.
+                    num_ignored_es++;
+                    continue;
+                }
+
+				*p_weight = VECTOR(*weights)[eid];
+				++p_weight;
+            }
+
+			*p_head = IGRAPH_FROM(g, eid);
+			++p_head;
+			++tails[IGRAPH_TO(g, eid)];
+
+			if (IGRAPH_FROM(g, eid) == IGRAPH_TO(g, eid)) {
+				++num_self_es;
+			}
+		}
+		igraph_eit_destroy(&eit);
+	} else {
+		// Select all the edges and iterate over them by the target vertices
+		igraph_vector_init(&neis, 0);
+
+		for (i = 0; i < num_vs; i++) {
+			igraph_incident(g, &neis, i, IGRAPH_ALL);
+			temp = igraph_vector_size(&neis);
+
+			// TODO: should loop edges be added in both directions?
+            p_head_copy = p_head;
+			for (j = 0; j < temp; j++) {
+                if (weights != 0) {
+                    if (VECTOR(*weights)[(long int)VECTOR(neis)[j]] <= 0) {
+                        // Ignore
+                        num_ignored_es++;
+                        continue;
+                    }
+
+					*p_weight = VECTOR(*weights)[(long int)VECTOR(neis)[j]];
+					++p_weight;
+                }
+
+				*p_head = IGRAPH_OTHER(g, VECTOR(neis)[j], i);
+				if (i == *p_head) {
+					num_self_es++;
+				}
+				++p_head;
+			}
+            tails[i] = p_head - p_head_copy;
+		}
+
+		igraph_vector_destroy(&neis);
+	}
+
+    // Decrease num_es by the number of ignored edges
+    num_es -= num_ignored_es;
+
+    // Finalize the tails vector
+    for (i = 0, sum = 0; i < num_vs; ++i) {
+        temp = sum;
+        sum += tails[i];
+        tails[i] = temp;
+    }
+
+    // Normalize the weights
+    normalize_weights();
+
+	// Debug
+    /*
+	printf("Heads:");
+	for (i = 0; i < num_es; ++i) {
+		printf(" %d", heads[i]);
+	}
+	printf("\n");
+	printf("Tails:");
+	for (i = 0; i < num_vs; ++i) {
+		printf(" %d", tails[i]);
+	}
+	printf("\n");
+	if (vals) {
+		printf("Vals:");
+		for (i = 0; i < num_es; ++i) {
+			printf(" %.4f", vals[i]);
+		}
+		printf("\n");
+	}
+	printf("===========================\n");
+    */
+}
+
+// PRPACK_IGRAPH_SUPPORT 
+#endif 
+
diff --git a/src/prpack/prpack_igraph_graph.h b/src/prpack/prpack_igraph_graph.h
new file mode 100644
index 0000000..682c4c5
--- /dev/null
+++ b/src/prpack/prpack_igraph_graph.h
@@ -0,0 +1,26 @@
+#ifndef PRPACK_IGRAPH_GRAPH
+#define PRPACK_IGRAPH_GRAPH
+
+#ifdef PRPACK_IGRAPH_SUPPORT
+
+#include "igraph_interface.h"
+#include "prpack_base_graph.h"
+
+namespace prpack {
+
+    class prpack_igraph_graph : public prpack_base_graph {
+
+        public:
+            // constructors
+            explicit prpack_igraph_graph(const igraph_t* g,
+					const igraph_vector_t* weights = 0,
+					igraph_bool_t directed = true);
+    };
+
+};
+
+// PRPACK_IGRAPH_SUPPORT 
+#endif 
+
+// PRPACK_IGRAPH_GRAPH
+#endif
diff --git a/src/prpack/prpack_preprocessed_ge_graph.cpp b/src/prpack/prpack_preprocessed_ge_graph.cpp
new file mode 100644
index 0000000..20826e6
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_ge_graph.cpp
@@ -0,0 +1,64 @@
+#include "prpack_preprocessed_ge_graph.h"
+#include <algorithm>
+using namespace prpack;
+using namespace std;
+
+void prpack_preprocessed_ge_graph::initialize() {
+    matrix = NULL;
+    d = NULL;
+}
+
+void prpack_preprocessed_ge_graph::initialize_weighted(const prpack_base_graph* bg) {
+    // initialize d
+    fill(d, d + num_vs, 1);
+    // fill in the matrix
+    for (int i = 0, inum_vs = 0; i < num_vs; ++i, inum_vs += num_vs) {
+        const int start_j = bg->tails[i];
+        const int end_j = (i + 1 != num_vs) ? bg->tails[i + 1] : bg->num_es;
+        for (int j = start_j; j < end_j; ++j)
+            d[bg->heads[j]] -= matrix[inum_vs + bg->heads[j]] = bg->vals[j];
+    }
+}
+
+void prpack_preprocessed_ge_graph::initialize_unweighted(const prpack_base_graph* bg) {
+    // fill in the matrix
+    for (int i = 0, inum_vs = 0; i < num_vs; ++i, inum_vs += num_vs) {
+        const int start_j = bg->tails[i];
+        const int end_j = (i + 1 != num_vs) ? bg->tails[i + 1] : bg->num_es;
+        for (int j = start_j; j < end_j; ++j)
+            ++matrix[inum_vs + bg->heads[j]];
+    }
+    // normalize the columns
+    for (int j = 0; j < num_vs; ++j) {
+        double sum = 0;
+        for (int inum_vs = 0; inum_vs < num_vs*num_vs; inum_vs += num_vs)
+            sum += matrix[inum_vs + j];
+        if (sum > 0) {
+            d[j] = 0;
+            const double coeff = 1/sum;
+            for (int inum_vs = 0; inum_vs < num_vs*num_vs; inum_vs += num_vs)
+                matrix[inum_vs + j] *= coeff;
+        } else {
+            d[j] = 1;
+        }
+    }
+}
+
+prpack_preprocessed_ge_graph::prpack_preprocessed_ge_graph(const prpack_base_graph* bg) {
+    initialize();
+    num_vs = bg->num_vs;
+    num_es = bg->num_es;
+    matrix = new double[num_vs*num_vs];
+    d = new double[num_vs];
+    fill(matrix, matrix + num_vs*num_vs, 0);
+    if (bg->vals != NULL)
+        initialize_weighted(bg);
+    else
+        initialize_unweighted(bg);
+}
+
+prpack_preprocessed_ge_graph::~prpack_preprocessed_ge_graph() {
+    delete[] matrix;
+    delete[] d;
+}
+
diff --git a/src/prpack/prpack_preprocessed_ge_graph.h b/src/prpack/prpack_preprocessed_ge_graph.h
new file mode 100644
index 0000000..83476a6
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_ge_graph.h
@@ -0,0 +1,26 @@
+#ifndef PRPACK_PREPROCESSED_GE_GRAPH
+#define PRPACK_PREPROCESSED_GE_GRAPH
+#include "prpack_preprocessed_graph.h"
+#include "prpack_base_graph.h"
+
+namespace prpack {
+
+    // Pre-processed graph class
+    class prpack_preprocessed_ge_graph : public prpack_preprocessed_graph {
+        private:
+            // helper methods
+            void initialize();
+            void initialize_weighted(const prpack_base_graph* bg);
+            void initialize_unweighted(const prpack_base_graph* bg);
+        public:
+            // instance variables
+            double* matrix;
+            // constructors
+            prpack_preprocessed_ge_graph(const prpack_base_graph* bg);
+            // destructor
+            ~prpack_preprocessed_ge_graph();
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_preprocessed_graph.h b/src/prpack/prpack_preprocessed_graph.h
new file mode 100644
index 0000000..043415f
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_graph.h
@@ -0,0 +1,17 @@
+#ifndef PRPACK_PREPROCESSED_GRAPH
+#define PRPACK_PREPROCESSED_GRAPH
+
+namespace prpack {
+
+    // TODO: this class should not be seeable by the users of the library.
+    // Super graph class.
+    class prpack_preprocessed_graph {
+        public:
+            int num_vs;
+            int num_es;
+            double* d;
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_preprocessed_gs_graph.cpp b/src/prpack/prpack_preprocessed_gs_graph.cpp
new file mode 100644
index 0000000..c50e859
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_gs_graph.cpp
@@ -0,0 +1,81 @@
+#include "prpack_preprocessed_gs_graph.h"
+#include <algorithm>
+using namespace prpack;
+using namespace std;
+
+void prpack_preprocessed_gs_graph::initialize() {
+    heads = NULL;
+    tails = NULL;
+    vals = NULL;
+    ii = NULL;
+    d = NULL;
+    num_outlinks = NULL;
+}
+
+void prpack_preprocessed_gs_graph::initialize_weighted(const prpack_base_graph* bg) {
+    vals = new double[num_es];
+    d = new double[num_vs];
+    fill(d, d + num_vs, 1);
+    for (int tails_i = 0, heads_i = 0; tails_i < num_vs; ++tails_i) {
+        tails[tails_i] = heads_i;
+        ii[tails_i] = 0;
+        const int start_j = bg->tails[tails_i];
+        const int end_j = (tails_i + 1 != num_vs) ? bg->tails[tails_i + 1]: bg->num_es;
+        for (int j = start_j; j < end_j; ++j) {
+            if (tails_i == bg->heads[j])
+                ii[tails_i] += bg->vals[j];
+            else {
+                heads[heads_i] = bg->heads[j];
+                vals[heads_i] = bg->vals[j];
+                ++heads_i;
+            }
+            d[bg->heads[j]] -= bg->vals[j];
+        }
+    }
+}
+
+void prpack_preprocessed_gs_graph::initialize_unweighted(const prpack_base_graph* bg) {
+    num_outlinks = new double[num_vs];
+    fill(num_outlinks, num_outlinks + num_vs, 0);
+    for (int tails_i = 0, heads_i = 0; tails_i < num_vs; ++tails_i) {
+        tails[tails_i] = heads_i;
+        ii[tails_i] = 0;
+        const int start_j = bg->tails[tails_i];
+        const int end_j = (tails_i + 1 != num_vs) ? bg->tails[tails_i + 1]: bg->num_es;
+        for (int j = start_j; j < end_j; ++j) {
+            if (tails_i == bg->heads[j])
+                ++ii[tails_i];
+            else
+                heads[heads_i++] = bg->heads[j];
+            ++num_outlinks[bg->heads[j]];
+        }
+    }
+    for (int i = 0; i < num_vs; ++i) {
+        if (num_outlinks[i] == 0)
+            num_outlinks[i] = -1;
+        ii[i] /= num_outlinks[i];
+    }
+}
+
+prpack_preprocessed_gs_graph::prpack_preprocessed_gs_graph(const prpack_base_graph* bg) {
+    initialize();
+    num_vs = bg->num_vs;
+    num_es = bg->num_es - bg->num_self_es;
+    heads = new int[num_es];
+    tails = new int[num_vs];
+    ii = new double[num_vs];
+    if (bg->vals != NULL)
+        initialize_weighted(bg);
+    else
+        initialize_unweighted(bg);
+}
+
+prpack_preprocessed_gs_graph::~prpack_preprocessed_gs_graph() {
+    delete[] heads;
+    delete[] tails;
+    delete[] vals;
+    delete[] ii;
+    delete[] d;
+    delete[] num_outlinks;
+}
+
diff --git a/src/prpack/prpack_preprocessed_gs_graph.h b/src/prpack/prpack_preprocessed_gs_graph.h
new file mode 100644
index 0000000..5a459d2
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_gs_graph.h
@@ -0,0 +1,30 @@
+#ifndef PRPACK_PREPROCESSED_GS_GRAPH
+#define PRPACK_PREPROCESSED_GS_GRAPH
+#include "prpack_preprocessed_graph.h"
+#include "prpack_base_graph.h"
+
+namespace prpack {
+
+    // Pre-processed graph class
+    class prpack_preprocessed_gs_graph : public prpack_preprocessed_graph {
+        private:
+            // helper methods
+            void initialize();
+            void initialize_weighted(const prpack_base_graph* bg);
+            void initialize_unweighted(const prpack_base_graph* bg);
+        public:
+            // instance variables
+            int* heads;
+            int* tails;
+            double* vals;
+            double* ii;
+            double* num_outlinks;
+            // constructors
+            prpack_preprocessed_gs_graph(const prpack_base_graph* bg);
+            // destructor
+            ~prpack_preprocessed_gs_graph();
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_preprocessed_scc_graph.cpp b/src/prpack/prpack_preprocessed_scc_graph.cpp
new file mode 100644
index 0000000..6bf911e
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_scc_graph.cpp
@@ -0,0 +1,202 @@
+#include "prpack_preprocessed_scc_graph.h"
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+using namespace prpack;
+using namespace std;
+
+void prpack_preprocessed_scc_graph::initialize() {
+    heads_inside = NULL;
+    tails_inside = NULL;
+    vals_inside = NULL;
+    heads_outside = NULL;
+    tails_outside = NULL;
+    vals_outside = NULL;
+    ii = NULL;
+    d = NULL;
+    num_outlinks = NULL;
+    divisions = NULL;
+    encoding = NULL;
+    decoding = NULL;
+}
+
+void prpack_preprocessed_scc_graph::initialize_weighted(const prpack_base_graph* bg) {
+    vals_inside = new double[num_es];
+    vals_outside = new double[num_es];
+    d = new double[num_vs];
+    fill(d, d + num_vs, 1);
+    for (int comp_i = 0; comp_i < num_comps; ++comp_i) {
+        const int start_i = divisions[comp_i];
+        const int end_i = (comp_i + 1 != num_comps) ? divisions[comp_i + 1] : num_vs;
+        for (int i = start_i; i < end_i; ++i) {
+            ii[i] = 0;
+            const int decoded = decoding[i];
+            const int start_j = bg->tails[decoded];
+            const int end_j = (decoded + 1 != num_vs) ? bg->tails[decoded + 1] : bg->num_es;
+            tails_inside[i] = num_es_inside;
+            tails_outside[i] = num_es_outside;
+            for (int j = start_j; j < end_j; ++j) {
+                const int h = encoding[bg->heads[j]];
+                if (h == i) {
+                    ii[i] += bg->vals[j];
+                } else {
+                    if (start_i <= h && h < end_i) {
+                        heads_inside[num_es_inside] = h;
+                        vals_inside[num_es_inside] = bg->vals[j];
+                        ++num_es_inside;
+                    } else {
+                        heads_outside[num_es_outside] = h;
+                        vals_outside[num_es_outside] = bg->vals[j];
+                        ++num_es_outside;
+                    }
+                }
+                d[h] -= bg->vals[j];
+            }
+        }
+    }
+}
+
+void prpack_preprocessed_scc_graph::initialize_unweighted(const prpack_base_graph* bg) {
+    num_outlinks = new double[num_vs];
+    fill(num_outlinks, num_outlinks + num_vs, 0);
+    for (int comp_i = 0; comp_i < num_comps; ++comp_i) {
+        const int start_i = divisions[comp_i];
+        const int end_i = (comp_i + 1 != num_comps) ? divisions[comp_i + 1] : num_vs;
+        for (int i = start_i; i < end_i; ++i) {
+            ii[i] = 0;
+            const int decoded = decoding[i];
+            const int start_j = bg->tails[decoded];
+            const int end_j = (decoded + 1 != num_vs) ? bg->tails[decoded + 1] : bg->num_es;
+            tails_inside[i] = num_es_inside;
+            tails_outside[i] = num_es_outside;
+            for (int j = start_j; j < end_j; ++j) {
+                const int h = encoding[bg->heads[j]];
+                if (h == i) {
+                    ++ii[i];
+                } else {
+                    if (start_i <= h && h < end_i)
+                        heads_inside[num_es_inside++] = h;
+                    else
+                        heads_outside[num_es_outside++] = h;
+                }
+                ++num_outlinks[h];
+            }
+        }
+    }
+    for (int i = 0; i < num_vs; ++i) {
+        if (num_outlinks[i] == 0)
+            num_outlinks[i] = -1;
+        ii[i] /= num_outlinks[i];
+    }
+}
+
+prpack_preprocessed_scc_graph::prpack_preprocessed_scc_graph(const prpack_base_graph* bg) {
+    initialize();
+    // initialize instance variables
+    num_vs = bg->num_vs;
+    num_es = bg->num_es - bg->num_self_es;
+    // initialize Tarjan's algorithm variables
+    num_comps = 0;
+    int mn = 0;                 // the number of vertices seen so far
+    int sz = 0;                 // size of st
+    int decoding_i = 0;         // size of decoding currently filled in
+    decoding = new int[num_vs];
+    int* scc = new int[num_vs]; // the strongly connected component this vertex is in
+    int* low = new int[num_vs]; // the lowest index this vertex can reach
+    int* num = new int[num_vs]; // the index of this vertex in the dfs traversal
+    int* st = new int[num_vs];  // a stack for the dfs
+    memset(num, -1, num_vs*sizeof(num[0]));
+    memset(scc, -1, num_vs*sizeof(scc[0]));
+    int* cs1 = new int[num_vs]; // call stack variable for dfs
+    int* cs2 = new int[num_vs]; // call stack variable for dfs
+    // run iterative Tarjan's algorithm
+    for (int root = 0; root < num_vs; ++root) {
+        if (num[root] != -1)
+            continue;
+        int csz = 1;
+        cs1[0] = root;
+        cs2[0] = bg->tails[root];
+        // dfs
+        while (csz) {
+            const int p = cs1[csz - 1]; // node we're dfs-ing on
+            int& it = cs2[csz - 1]; // iteration of the for loop
+            if (it == bg->tails[p]) {
+                low[p] = num[p] = mn++;
+                st[sz++] = p;
+            } else {
+                low[p] = min(low[p], low[bg->heads[it - 1]]);
+            }
+            bool done = false;
+            int end_it = (p + 1 != num_vs) ? bg->tails[p + 1] : bg->num_es;
+            for (; it < end_it; ++it) {
+                int h = bg->heads[it];
+                if (scc[h] == -1) {
+                    if (num[h] == -1) {
+                        // dfs(h, p);
+                        cs1[csz] = h;
+                        cs2[csz++] = bg->tails[h];
+                        ++it;
+                        done = true;
+                        break;
+                    }
+                    low[p] = min(low[p], low[h]);
+                }
+            }
+            if (done)
+                continue;
+            // if p is the first explored vertex of a scc
+            if (low[p] == num[p]) {
+                cs1[num_vs - 1 - num_comps] = decoding_i;
+                while (scc[p] != num_comps) {
+                    scc[st[--sz]] = num_comps;
+                    decoding[decoding_i++] = st[sz];
+                }
+                ++num_comps;
+            }
+            --csz;
+        }
+    }
+    // set up other instance variables
+    divisions = new int[num_comps];
+    divisions[0] = 0;
+    for (int i = 1; i < num_comps; ++i)
+        divisions[i] = cs1[num_vs - 1 - i];
+    encoding = num;
+    for (int i = 0; i < num_vs; ++i)
+        encoding[decoding[i]] = i;
+    // fill in inside and outside instance variables
+    ii = new double[num_vs];
+    tails_inside = cs1;
+    heads_inside = new int[num_es];
+    tails_outside = cs2;
+    heads_outside = new int[num_es];
+    num_es_inside = num_es_outside = 0;
+    // continue initialization based off of weightedness
+    if (bg->vals != NULL)
+        initialize_weighted(bg);
+    else
+        initialize_unweighted(bg);
+    // free memory
+    // do not free num <==> encoding
+    // do not free cs1 <==> tails_inside
+    // do not free cs2 <==> tails_outside
+    delete[] scc;
+    delete[] low;
+    delete[] st;
+}
+
+prpack_preprocessed_scc_graph::~prpack_preprocessed_scc_graph() {
+    delete[] heads_inside;
+    delete[] tails_inside;
+    delete[] vals_inside;
+    delete[] heads_outside;
+    delete[] tails_outside;
+    delete[] vals_outside;
+    delete[] ii;
+    delete[] d;
+    delete[] num_outlinks;
+    delete[] divisions;
+    delete[] encoding;
+    delete[] decoding;
+}
+
diff --git a/src/prpack/prpack_preprocessed_scc_graph.h b/src/prpack/prpack_preprocessed_scc_graph.h
new file mode 100644
index 0000000..1cc9e94
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_scc_graph.h
@@ -0,0 +1,39 @@
+#ifndef PRPACK_PREPROCESSED_SCC_GRAPH
+#define PRPACK_PREPROCESSED_SCC_GRAPH
+#include "prpack_preprocessed_graph.h"
+#include "prpack_base_graph.h"
+
+namespace prpack {
+
+    // Pre-processed graph class
+    class prpack_preprocessed_scc_graph : public prpack_preprocessed_graph {
+        private:
+            // helper methods
+            void initialize();
+            void initialize_weighted(const prpack_base_graph* bg);
+            void initialize_unweighted(const prpack_base_graph* bg);
+        public:
+            // instance variables
+            int num_es_inside;
+            int* heads_inside;
+            int* tails_inside;
+            double* vals_inside;
+            int num_es_outside;
+            int* heads_outside;
+            int* tails_outside;
+            double* vals_outside;
+            double* ii;
+            double* num_outlinks;
+            int num_comps;
+            int* divisions;
+            int* encoding;
+            int* decoding;
+            // constructors
+            prpack_preprocessed_scc_graph(const prpack_base_graph* bg);
+            // destructor
+            ~prpack_preprocessed_scc_graph();
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_preprocessed_schur_graph.cpp b/src/prpack/prpack_preprocessed_schur_graph.cpp
new file mode 100644
index 0000000..a7e961e
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_schur_graph.cpp
@@ -0,0 +1,121 @@
+#include "prpack_preprocessed_schur_graph.h"
+#include <algorithm>
+#include <cstring>
+using namespace prpack;
+using namespace std;
+
+void prpack_preprocessed_schur_graph::initialize() {
+    heads = NULL;
+    tails = NULL;
+    vals = NULL;
+    ii = NULL;
+    d = NULL;
+    num_outlinks = NULL;
+    encoding = NULL;
+    decoding = NULL;
+}
+
+void prpack_preprocessed_schur_graph::initialize_weighted(const prpack_base_graph* bg) {
+    // permute d
+    ii = d;
+    d = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        d[encoding[i]] = ii[i];
+    // convert bg to head/tail format
+    for (int tails_i = 0, heads_i = 0; tails_i < num_vs; ++tails_i) {
+        ii[tails_i] = 0;
+        tails[tails_i] = heads_i;
+        const int decoded = decoding[tails_i];
+        const int start_i = bg->tails[decoded];
+        const int end_i = (decoded + 1 != num_vs) ? bg->tails[decoded + 1] : bg->num_es;
+        for (int i = start_i; i < end_i; ++i) {
+            if (decoded == bg->heads[i])
+                ii[tails_i] += bg->vals[i];
+            else {
+                heads[heads_i] = encoding[bg->heads[i]];
+                vals[heads_i] = bg->vals[i];
+                ++heads_i;
+            }
+        }
+    }
+}
+
+void prpack_preprocessed_schur_graph::initialize_unweighted(const prpack_base_graph* bg) {
+    // permute num_outlinks
+    ii = num_outlinks;
+    num_outlinks = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        num_outlinks[encoding[i]] = (ii[i] == 0) ? -1 : ii[i];
+    // convert bg to head/tail format
+    for (int tails_i = 0, heads_i = 0; tails_i < num_vs; ++tails_i) {
+        ii[tails_i] = 0;
+        tails[tails_i] = heads_i;
+        const int decoded = decoding[tails_i];
+        const int start_i = bg->tails[decoded];
+        const int end_i = (decoded + 1 != num_vs) ? bg->tails[decoded + 1] : bg->num_es;
+        for (int i = start_i; i < end_i; ++i) {
+            if (decoded == bg->heads[i])
+                ++ii[tails_i];
+            else
+                heads[heads_i++] = encoding[bg->heads[i]];
+        }
+        if (ii[tails_i] > 0)
+            ii[tails_i] /= num_outlinks[tails_i];
+    }
+}
+
+prpack_preprocessed_schur_graph::prpack_preprocessed_schur_graph(const prpack_base_graph* bg) {
+    initialize();
+    // initialize instance variables
+    num_vs = bg->num_vs;
+    num_es = bg->num_es - bg->num_self_es;
+    tails = new int[num_vs];
+    heads = new int[num_es];
+    const bool weighted = bg->vals != NULL;
+    if (weighted) {
+        vals = new double[num_vs];
+        d = new double[num_vs];
+        fill(d, d + num_vs, 1);
+        for (int i = 0; i < bg->num_es; ++i)
+            d[bg->heads[i]] -= bg->vals[i];
+    } else {
+        num_outlinks = new double[num_vs];
+        fill(num_outlinks, num_outlinks + num_vs, 0);
+        for (int i = 0; i < bg->num_es; ++i)
+            ++num_outlinks[bg->heads[i]];
+    }
+    // permute no-inlink vertices to the beginning, and no-outlink vertices to the end
+    encoding = new int[num_vs];
+    decoding = new int[num_vs];
+    num_no_in_vs = num_no_out_vs = 0;
+    for (int i = 0; i < num_vs; ++i) {
+        if (bg->tails[i] == ((i + 1 != num_vs) ? bg->tails[i + 1] : bg->num_es)) {
+            decoding[encoding[i] = num_no_in_vs] = i;
+            ++num_no_in_vs;
+        } else if ((weighted) ? (d[i] == 1) : (num_outlinks[i] == 0)) {
+            decoding[encoding[i] = num_vs - 1 - num_no_out_vs] = i;
+            ++num_no_out_vs;
+        }
+    }
+    // permute everything else
+    for (int i = 0, p = num_no_in_vs; i < num_vs; ++i)
+        if (bg->tails[i] < ((i + 1 != num_vs) ? bg->tails[i + 1] : bg->num_es) && ((weighted) ? (d[i] < 1) : (num_outlinks[i] > 0)))
+            decoding[encoding[i] = p++] = i;
+    // continue initialization based off of weightedness
+    if (weighted)
+        initialize_weighted(bg);
+    else
+        initialize_unweighted(bg);
+}
+
+prpack_preprocessed_schur_graph::~prpack_preprocessed_schur_graph() {
+    delete[] heads;
+    delete[] tails;
+    delete[] vals;
+    delete[] ii;
+    delete[] d;
+    delete[] num_outlinks;
+    delete[] encoding;
+    delete[] decoding;
+}
+
diff --git a/src/prpack/prpack_preprocessed_schur_graph.h b/src/prpack/prpack_preprocessed_schur_graph.h
new file mode 100644
index 0000000..a8c7845
--- /dev/null
+++ b/src/prpack/prpack_preprocessed_schur_graph.h
@@ -0,0 +1,33 @@
+#ifndef PRPACK_PREPROCESSED_SCHUR_GRAPH
+#define PRPACK_PREPROCESSED_SCHUR_GRAPH
+#include "prpack_preprocessed_graph.h"
+#include "prpack_base_graph.h"
+
+namespace prpack {
+
+    class prpack_preprocessed_schur_graph : public prpack_preprocessed_graph {
+        private:
+            // helper methods
+            void initialize();
+            void initialize_weighted(const prpack_base_graph* bg);
+            void initialize_unweighted(const prpack_base_graph* bg);
+        public:
+            // instance variables
+            int num_no_in_vs;
+            int num_no_out_vs;
+            int* heads;
+            int* tails;
+            double* vals;
+            double* ii;
+            double* num_outlinks;
+            int* encoding;
+            int* decoding;
+            // constructors
+            prpack_preprocessed_schur_graph(const prpack_base_graph* bg);
+            // destructor
+            ~prpack_preprocessed_schur_graph();
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_result.cpp b/src/prpack/prpack_result.cpp
new file mode 100644
index 0000000..05b6b5f
--- /dev/null
+++ b/src/prpack/prpack_result.cpp
@@ -0,0 +1,12 @@
+#include "prpack_result.h"
+#include <cstdlib>
+using namespace prpack;
+
+prpack_result::prpack_result() {
+    x = NULL;
+}
+
+prpack_result::~prpack_result() {
+    delete[] x;
+}
+
diff --git a/src/prpack/prpack_result.h b/src/prpack/prpack_result.h
new file mode 100644
index 0000000..0b7fa80
--- /dev/null
+++ b/src/prpack/prpack_result.h
@@ -0,0 +1,27 @@
+#ifndef PRPACK_RESULT
+#define PRPACK_RESULT
+
+namespace prpack {
+
+    // Result class.
+    class prpack_result {
+        public:
+            // instance variables
+            int num_vs;
+            int num_es;
+            double* x;
+            double read_time;
+            double preprocess_time;
+            double compute_time;
+            long num_es_touched;
+            const char* method;
+            int converged;
+            // constructor
+            prpack_result();
+            // destructor
+            ~prpack_result();
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_solver.cpp b/src/prpack/prpack_solver.cpp
new file mode 100644
index 0000000..8649d89
--- /dev/null
+++ b/src/prpack/prpack_solver.cpp
@@ -0,0 +1,877 @@
+#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/prpack_solver.h b/src/prpack/prpack_solver.h
new file mode 100644
index 0000000..00fda0f
--- /dev/null
+++ b/src/prpack/prpack_solver.h
@@ -0,0 +1,178 @@
+#ifndef PRPACK_SOLVER
+#define PRPACK_SOLVER
+#include "prpack_base_graph.h"
+#include "prpack_csc.h"
+#include "prpack_csr.h"
+#include "prpack_edge_list.h"
+#include "prpack_preprocessed_ge_graph.h"
+#include "prpack_preprocessed_gs_graph.h"
+#include "prpack_preprocessed_scc_graph.h"
+#include "prpack_preprocessed_schur_graph.h"
+#include "prpack_result.h"
+
+// TODO Make this a user configurable variable
+#define PRPACK_SOLVER_MAX_ITERS 1000000
+
+namespace prpack {
+
+    // Solver class.
+    class prpack_solver {
+        private:
+            // instance variables
+            double read_time;
+            prpack_base_graph* bg;
+            prpack_preprocessed_ge_graph* geg;
+            prpack_preprocessed_gs_graph* gsg;
+            prpack_preprocessed_schur_graph* sg;
+            prpack_preprocessed_scc_graph* sccg;
+			bool owns_bg;
+            // methods
+            void initialize();
+            static prpack_result* solve_via_ge(
+                    const double alpha,
+                    const double tol,
+                    const int num_vs,
+                    const double* matrix,
+                    const double* uv);
+            static prpack_result* 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);
+            static prpack_result* 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);
+            static prpack_result* 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);
+            static prpack_result* 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 = true);
+            static prpack_result* 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);
+            static prpack_result* 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 = true);
+            static prpack_result* 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);
+            static void ge(const int sz, double* A, double* b);
+            static void normalize(const int length, double* x);
+            static prpack_result* 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);
+        public:
+            // constructors
+            prpack_solver(const prpack_csc* g);
+            prpack_solver(const prpack_int64_csc* g);
+            prpack_solver(const prpack_csr* g);
+            prpack_solver(const prpack_edge_list* g);
+            prpack_solver(prpack_base_graph* g, bool owns_bg=true);
+            prpack_solver(const char* filename, const char* format, const bool weighted);
+            // destructor
+            ~prpack_solver();
+            // methods
+            int get_num_vs();
+            prpack_result* solve(const double alpha, const double tol, const char* method);
+            prpack_result* solve(
+                    const double alpha,
+                    const double tol,
+                    const double* u,
+                    const double* v,
+                    const char* method);
+    };
+
+};
+
+#endif
diff --git a/src/prpack/prpack_utils.cpp b/src/prpack/prpack_utils.cpp
new file mode 100644
index 0000000..f5aee84
--- /dev/null
+++ b/src/prpack/prpack_utils.cpp
@@ -0,0 +1,61 @@
+/**
+ * @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/prpack/prpack_utils.h b/src/prpack/prpack_utils.h
new file mode 100644
index 0000000..0148c1b
--- /dev/null
+++ b/src/prpack/prpack_utils.h
@@ -0,0 +1,34 @@
+#ifndef PRPACK_UTILS
+#define PRPACK_UTILS
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#endif
+#include <string>
+
+// Computes the time taken to do X and stores it in T.
+#define TIME(T, X)                  \
+    (T) = prpack_utils::get_time(); \
+    (X);                            \
+    (T) = prpack_utils::get_time() - (T)
+
+// Computes S += A using C as a carry-over.
+// This is a macro over a function as it is faster this way.
+#define COMPENSATED_SUM(S, A, C)                        \
+    double compensated_sum_y = (A) - (C);               \
+    double compensated_sum_t = (S) + compensated_sum_y; \
+    (C) = compensated_sum_t - (S) - compensated_sum_y;  \
+    (S) = compensated_sum_t
+
+namespace prpack {
+
+    class prpack_utils {
+        public:
+            static double get_time();
+            static void validate(const bool condition, const std::string& msg);
+            static double* permute(const int length, const double* a, const int* coding);
+    };
+
+};
+
+#endif
+
diff --git a/src/qsort.c b/src/qsort.c
new file mode 100644
index 0000000..739529d
--- /dev/null
+++ b/src/qsort.c
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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 ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+#ifdef _MSC_VER
+/* MSVC does not have inline when compiling C source files */
+#define inline __inline
+#define __unused
+#endif
+
+#ifndef __unused
+#define __unused	__attribute__ ((unused))
+#endif
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qsort.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+/*#include <sys/cdefs.h> */
+
+#include <stdlib.h>
+
+#ifdef I_AM_QSORT_R
+typedef int		 cmp_t(void *, const void *, const void *);
+#else
+typedef int		 cmp_t(const void *, const void *);
+#endif
+static inline char	*med3(char *, char *, char *, cmp_t *, void *);
+static inline void	 swapfunc(char *, char *, int, int);
+
+#define igraph_min(a, b)	(a) < (b) ? a : b
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { 		\
+	long i = (n) / sizeof (TYPE); 			\
+	TYPE *pi = (TYPE *) (parmi); 		\
+	TYPE *pj = (TYPE *) (parmj); 		\
+	do { 						\
+		TYPE	t = *pi;		\
+		*pi++ = *pj;				\
+		*pj++ = t;				\
+        } while (--i > 0);				\
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static inline void
+swapfunc(a, b, n, swaptype)
+	char *a, *b;
+	int n, swaptype;
+{
+	if(swaptype <= 1)
+		swapcode(long, a, b, n)
+	else
+		swapcode(char, a, b, n)
+}
+
+#define swap(a, b)					\
+	if (swaptype == 0) {				\
+		long t = *(long *)(a);			\
+		*(long *)(a) = *(long *)(b);		\
+		*(long *)(b) = t;			\
+	} else						\
+		swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+#ifdef I_AM_QSORT_R
+#define	CMP(t, x, y) (cmp((t), (x), (y)))
+#else
+#define	CMP(t, x, y) (cmp((x), (y)))
+#endif
+
+static inline char *
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
+#ifndef I_AM_QSORT_R
+__unused
+#endif
+)
+{
+	return CMP(thunk, a, b) < 0 ?
+	       (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
+              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+}
+
+#ifdef I_AM_QSORT_R
+void
+igraph_qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
+#else
+#define thunk NULL
+void
+igraph_qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+#endif
+{
+	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+	int d, r, swaptype, swap_cnt;
+
+loop:	SWAPINIT(a, es);
+	swap_cnt = 0;
+	if (n < 7) {
+		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+			for (pl = pm; 
+			     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+			     pl -= es)
+				swap(pl, pl - es);
+		return;
+	}
+	pm = (char *)a + (n / 2) * es;
+	if (n > 7) {
+		pl = a;
+		pn = (char *)a + (n - 1) * es;
+		if (n > 40) {
+			d = (n / 8) * es;
+			pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+			pm = med3(pm - d, pm, pm + d, cmp, thunk);
+			pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
+		}
+		pm = med3(pl, pm, pn, cmp, thunk);
+	}
+	swap(a, pm);
+	pa = pb = (char *)a + es;
+
+	pc = pd = (char *)a + (n - 1) * es;
+	for (;;) {
+		while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) {
+			if (r == 0) {
+				swap_cnt = 1;
+				swap(pa, pb);
+				pa += es;
+			}
+			pb += es;
+		}
+		while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) {
+			if (r == 0) {
+				swap_cnt = 1;
+				swap(pc, pd);
+				pd -= es;
+			}
+			pc -= es;
+		}
+		if (pb > pc)
+			break;
+		swap(pb, pc);
+		swap_cnt = 1;
+		pb += es;
+		pc -= es;
+	}
+	if (swap_cnt == 0) {  /* Switch to insertion sort */
+		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+			for (pl = pm; 
+			     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+			     pl -= es)
+				swap(pl, pl - es);
+		return;
+	}
+
+	pn = (char *)a + n * es;
+	r = igraph_min(pa - (char *)a, pb - pa);
+	vecswap(a, pb - r, r);
+	r = igraph_min((size_t)(pd - pc), (size_t)(pn - pd - es));
+	vecswap(pb, pn - r, r);
+	if ((size_t)(r = pb - pa) > es)
+#ifdef I_AM_QSORT_R
+		igraph_qsort_r(a, r / es, es, thunk, cmp);
+#else
+		igraph_qsort(a, r / es, es, cmp);
+#endif
+		if ((size_t)(r = pd - pc) > es) {
+		/* Iterate rather than recurse to save stack space */
+		a = pn - r;
+		n = r / es;
+		goto loop;
+	}
+/*		qsort(pn - r, r / es, es, cmp);*/
+}
+
diff --git a/src/qsort_r.c b/src/qsort_r.c
new file mode 100644
index 0000000..f7c0e54
--- /dev/null
+++ b/src/qsort_r.c
@@ -0,0 +1,8 @@
+/*
+ * This file is in the public domain.  Originally written by Garrett
+ * A. Wollman.
+ *
+ * $FreeBSD: src/lib/libc/stdlib/qsort_r.c,v 1.1 2002/09/10 02:04:49 wollman Exp $
+ */
+#define I_AM_QSORT_R
+#include "qsort.c"
diff --git a/src/random.c b/src/random.c
new file mode 100644
index 0000000..a9de73f
--- /dev/null
+++ b/src/random.c
@@ -0,0 +1,2094 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <math.h>
+#include <limits.h>
+#include <string.h>
+#include "igraph_math.h"
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_memory.h"
+
+/** 
+ * \section about_rngs 
+ * 
+ * <section>
+ * <title>About random numbers in igraph, use cases</title>
+ * 
+ * <para> 
+ * Some algorithms in igraph, e.g. the generation of random graphs,
+ * require random number generators (RNGs). Prior to version 0.6
+ * igraph did not have a sophisticated way to deal with random number
+ * generators at the C level, but this has changed. From version 0.6
+ * different and multiple random number generators are supported.
+ * </para>
+ * </section>
+ * 
+ */
+
+/** 
+ * \section rng_use_cases
+ * 
+ * <section><title>Use cases</title>
+ * 
+ * <section><title>Normal (default) use</title>
+ * <para> 
+ * If the user does not use any of the RNG functions explicitly, but calls
+ * some of the randomized igraph functions, then a default RNG is set
+ * up the first time an igraph function needs random numbers. The
+ * seed of this RNG is the output of the <code>time(0)</code> function
+ * call, using the <code>time</code> function from the standard C
+ * library. This ensures that igraph creates a different random graph,
+ * each time the C program is called.
+ * </para>
+ * 
+ * <para> 
+ * The created default generator is stored internally and can be
+ * queried with the \ref igraph_rng_default() function.
+ * </para>
+ * </section>
+ * 
+ * <section><title>Reproducible simulations</title>
+ * <para> 
+ * If reproducible results are needed, then the user should set the
+ * seed of the default random number generator explicitly, using the 
+ * \ref igraph_rng_seed() function on the default generator, \ref
+ * igraph_rng_default(). When setting the seed to the same number,
+ * igraph generates exactly the same random graph (or series of random
+ * graphs).
+ * </para>
+ * </section>
+ * 
+ * <section><title>Changing the default generator</title>
+ * <para> 
+ * By default igraph uses the \ref igraph_rng_default() random number
+ * generator. This can be changed any time by calling \ref
+ * igraph_rng_set_default(), with an already initialized random number
+ * generator. Note that the old (replaced) generator is not
+ * destroyed, so no memory is deallocated.
+ * </para>
+ * </section>
+ *
+ * <section><title>Using multiple generators</title>
+ * <para> 
+ * igraph also provides functions to set up multiple random number
+ * generators, using the \ref igraph_rng_init() function, and then
+ * generating random numbers from them, e.g. with \ref igraph_rng_get_integer()
+ * and/or \ref igraph_rng_get_unif() calls. 
+ * </para>
+ * 
+ * <para>
+ * Note that initializing a new random number generator is
+ * independent of the generator that the igraph functions themselves
+ * use. If you want to replace that, then please use \ref
+ * igraph_rng_set_default().
+ * </para>
+ * </section>
+ *
+ * <section><title>Example</title>
+ * <para>
+ * \example examples/simple/random_seed.c
+ * </para>
+ * </section>
+ *
+ * </section>
+ */
+
+/* ------------------------------------ */
+
+typedef struct {
+  int i, j;
+  long int x[31];
+} igraph_i_rng_glibc2_state_t;
+
+unsigned long int igraph_i_rng_glibc2_get(int *i, int *j, int n, 
+					  long int *x) {
+  unsigned long int k;
+
+  x[*i] += x[*j];
+  k = (x[*i] >> 1) & 0x7FFFFFFF;
+  
+  (*i)++;
+  if (*i == n) {
+    *i = 0;
+  }
+  
+  (*j)++ ;
+  if (*j == n) {
+    *j = 0;
+  }
+
+  return k;
+}
+
+unsigned long int igraph_rng_glibc2_get(void *vstate) {
+  igraph_i_rng_glibc2_state_t *state = 
+    (igraph_i_rng_glibc2_state_t*) vstate;
+  return igraph_i_rng_glibc2_get(&state->i, &state->j, 31, state->x);
+}
+
+igraph_real_t igraph_rng_glibc2_get_real(void *state) {
+  return igraph_rng_glibc2_get(state) / 2147483648.0;
+}
+
+/* this function is independent of the bit size */
+
+void igraph_i_rng_glibc2_init(long int *x, int n, 
+			      unsigned long int s) {
+  int i;
+  
+  if (s==0) { s=1; }
+  
+  x[0] = (long) s;
+  for (i=1 ; i<n ; i++) {
+    const long int h = s / 127773;
+    const long int t = 16807 * ((long) s - h * 127773) - h * 2836;
+    if (t < 0) {
+      s = (unsigned long) t + 2147483647 ;
+    } else { 
+      s = (unsigned long) t ;
+    }
+    
+    x[i] = (long int) s ;
+  }
+}
+
+int igraph_rng_glibc2_seed(void *vstate, unsigned long int seed) {
+  igraph_i_rng_glibc2_state_t *state = 
+    (igraph_i_rng_glibc2_state_t*) vstate;
+  int i;
+  
+  igraph_i_rng_glibc2_init(state->x, 31, seed);
+  
+  state->i=3;
+  state->j=0;
+  
+  for (i=0;i<10*31; i++) {
+    igraph_rng_glibc2_get(state);
+  }
+  
+  return 0;
+}
+
+int igraph_rng_glibc2_init(void **state) {
+  igraph_i_rng_glibc2_state_t *st;
+
+  st=igraph_Calloc(1, igraph_i_rng_glibc2_state_t);
+  if (!st) {
+    IGRAPH_ERROR("Cannot initialize RNG", IGRAPH_ENOMEM);
+  }
+  (*state)=st;
+
+  igraph_rng_glibc2_seed(st, 0);
+  
+  return 0;
+}
+
+void igraph_rng_glibc2_destroy(void *vstate) {
+  igraph_i_rng_glibc2_state_t *state = 
+    (igraph_i_rng_glibc2_state_t*) vstate;
+  igraph_Free(state);
+}
+
+/**
+ * \var igraph_rngtype_glibc2
+ * \brief The random number generator type introduced in GNU libc 2
+ * 
+ * It is a linear feedback shift register generator with a 128-byte
+ * buffer. This generator was the default prior to igraph version 0.6,
+ * at least on systems relying on GNU libc.
+ * 
+ * This generator was ported from the GNU Scientific Library.
+ */
+
+const igraph_rng_type_t igraph_rngtype_glibc2 = {
+  /* name= */      "LIBC",
+  /* min=  */      0,
+  /* max=  */      RAND_MAX,
+  /* init= */      igraph_rng_glibc2_init,
+  /* destroy= */   igraph_rng_glibc2_destroy,
+  /* seed= */      igraph_rng_glibc2_seed,
+  /* get= */       igraph_rng_glibc2_get,
+  /* get_real= */  igraph_rng_glibc2_get_real,
+  /* get_norm= */  0,
+  /* get_geom= */  0,
+  /* get_binom= */ 0,
+  /* get_exp= */   0
+};
+
+/* ------------------------------------ */
+
+typedef struct {
+  unsigned long int x;
+} igraph_i_rng_rand_state_t;
+
+unsigned long int igraph_rng_rand_get(void *vstate) {
+  igraph_i_rng_rand_state_t *state = vstate;
+  state->x = (1103515245 * state->x + 12345) & 0x7fffffffUL;
+  return state->x;
+}
+
+igraph_real_t igraph_rng_rand_get_real(void *vstate) {
+  return igraph_rng_rand_get (vstate) / 2147483648.0 ;
+}
+
+int igraph_rng_rand_seed(void *vstate, unsigned long int seed) {
+  igraph_i_rng_rand_state_t *state = vstate;
+  state->x = seed;
+  return 0;
+}
+
+int igraph_rng_rand_init(void **state) {
+  igraph_i_rng_rand_state_t *st;
+
+  st=igraph_Calloc(1, igraph_i_rng_rand_state_t);
+  if (!st) {
+    IGRAPH_ERROR("Cannot initialize RNG", IGRAPH_ENOMEM);
+  }
+  (*state)=st;
+  
+  igraph_rng_rand_seed(st, 0);
+  
+  return 0;
+}
+
+void igraph_rng_rand_destroy(void *vstate) {
+  igraph_i_rng_rand_state_t *state = 
+    (igraph_i_rng_rand_state_t*) vstate;
+  igraph_Free(state);  
+}  
+
+/**
+ * \var igraph_rngtype_rand
+ * \brief The old BSD rand/stand random number generator
+ * 
+ * The sequence is 
+ *     x_{n+1} = (a x_n + c) mod m 
+ * with a = 1103515245, c = 12345 and m = 2^31 = 2147483648. The seed
+ * specifies the initial value, x_1.
+ * 
+ * The theoretical value of x_{10001} is 1910041713.
+ *
+ *  The period of this generator is 2^31.
+ * 
+ * This generator is not very good -- the low bits of successive
+ * numbers are correlated.
+ * 
+ * This generator was ported from the GNU Scientific Library.
+ */
+
+const igraph_rng_type_t igraph_rngtype_rand = {
+  /* name= */      "RAND",
+  /* min=  */      0,
+  /* max=  */      0x7fffffffUL,
+  /* init= */      igraph_rng_rand_init,
+  /* destroy= */   igraph_rng_rand_destroy,
+  /* seed= */      igraph_rng_rand_seed,
+  /* get= */       igraph_rng_rand_get,
+  /* get_real= */  igraph_rng_rand_get_real,
+  /* get_norm= */  0,
+  /* get_geom= */  0,
+  /* get_binom= */ 0,
+  /* get_exp= */   0
+};
+
+/* ------------------------------------ */
+
+#define N 624   /* Period parameters */
+#define M 397
+
+/* most significant w-r bits */
+static const unsigned long UPPER_MASK = 0x80000000UL;   
+
+/* least significant r bits */
+static const unsigned long LOWER_MASK = 0x7fffffffUL;   
+
+typedef struct {
+  unsigned long mt[N];
+  int mti;
+} igraph_i_rng_mt19937_state_t;
+
+unsigned long int igraph_rng_mt19937_get(void *vstate) {
+  igraph_i_rng_mt19937_state_t *state = vstate;
+
+  unsigned long k ;
+  unsigned long int *const mt = state->mt;
+
+#define MAGIC(y) (((y)&0x1) ? 0x9908b0dfUL : 0)
+
+  if (state->mti >= N) {
+    /* generate N words at one time */
+    int kk;
+    
+    for (kk = 0; kk < N - M; kk++) {
+      unsigned long y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+      mt[kk] = mt[kk + M] ^ (y >> 1) ^ MAGIC(y);
+    }
+    for (; kk < N - 1; kk++) {
+      unsigned long y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+      mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ MAGIC(y);
+    }
+    
+    {
+      unsigned long y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+      mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ MAGIC(y);
+    }
+    
+    state->mti = 0;
+  }
+
+#undef MAGIC
+
+  /* Tempering */
+  
+  k = mt[state->mti];
+  k ^= (k >> 11);
+  k ^= (k << 7) & 0x9d2c5680UL;
+  k ^= (k << 15) & 0xefc60000UL;
+  k ^= (k >> 18);
+
+  state->mti++;
+
+  return k;
+}
+
+igraph_real_t igraph_rng_mt19937_get_real(void *vstate) {
+  return igraph_rng_mt19937_get (vstate) / 4294967296.0 ;
+}
+
+int igraph_rng_mt19937_seed(void *vstate, unsigned long int seed) {
+  igraph_i_rng_mt19937_state_t *state = vstate;
+  int i;
+
+  memset(state, 0, sizeof(igraph_i_rng_mt19937_state_t));
+
+  if (seed == 0) {
+    seed = 4357;   /* the default seed is 4357 */
+  }
+  state->mt[0]= seed & 0xffffffffUL;
+
+  for (i = 1; i < N; i++) {
+    /* See Knuth's "Art of Computer Programming" Vol. 2, 3rd
+       Ed. p.106 for multiplier. */
+    state->mt[i] =
+      (1812433253UL * (state->mt[i-1] ^ (state->mt[i-1] >> 30)) + 
+       (unsigned long) i);
+    state->mt[i] &= 0xffffffffUL;
+  }
+  
+  state->mti = i;
+  return 0;
+}
+
+int igraph_rng_mt19937_init(void **state) {
+  igraph_i_rng_mt19937_state_t *st;
+
+  st=igraph_Calloc(1, igraph_i_rng_mt19937_state_t);
+  if (!st) {
+    IGRAPH_ERROR("Cannot initialize RNG", IGRAPH_ENOMEM);
+  }
+  (*state)=st;
+  
+  igraph_rng_mt19937_seed(st, 0);
+  
+  return 0;
+}
+
+void igraph_rng_mt19937_destroy(void *vstate) {
+  igraph_i_rng_mt19937_state_t *state = 
+    (igraph_i_rng_mt19937_state_t*) vstate;
+  igraph_Free(state);  
+}  
+
+/** 
+ * \var igraph_rngtype_mt19937
+ * \brief The MT19937 random number generator
+ * 
+ * The MT19937 generator of Makoto Matsumoto and Takuji Nishimura is a
+ * variant of the twisted generalized feedback shift-register
+ * algorithm, and is known as the “Mersenne Twister” generator. It has
+ * a Mersenne prime period of 2^19937 - 1 (about 10^6000) and is
+ * equi-distributed in 623 dimensions. It has passed the diehard
+ * statistical tests. It uses 624 words of state per generator and is
+ * comparable in speed to the other generators. The original generator
+ * used a default seed of 4357 and choosing s equal to zero in
+ * gsl_rng_set reproduces this. Later versions switched to 5489 as the
+ * default seed, you can choose this explicitly via igraph_rng_seed
+ * instead if you require it. 
+ * 
+ * For more information see,
+ * Makoto Matsumoto and Takuji Nishimura, “Mersenne Twister: A
+ * 623-dimensionally equidistributed uniform pseudorandom number
+ * generator”. ACM Transactions on Modeling and Computer Simulation,
+ * Vol. 8, No. 1 (Jan. 1998), Pages 3–30 
+ * 
+ * The generator igraph_rngtype_mt19937 uses the second revision of the
+ * seeding procedure published by the two authors above in 2002. The
+ * original seeding procedures could cause spurious artifacts for some
+ * seed values.
+ * 
+ * This generator was ported from the GNU Scientific Library.
+ */
+
+const igraph_rng_type_t igraph_rngtype_mt19937 = {
+  /* name= */      "MT19937",
+  /* min=  */      0,
+  /* max=  */      0xffffffffUL,
+  /* init= */      igraph_rng_mt19937_init,
+  /* destroy= */   igraph_rng_mt19937_destroy,
+  /* seed= */      igraph_rng_mt19937_seed,
+  /* get= */       igraph_rng_mt19937_get,
+  /* get_real= */  igraph_rng_mt19937_get_real,
+  /* get_norm= */  0,
+  /* get_geom= */  0,
+  /* get_binom= */ 0,
+  /* get_exp= */   0
+};
+
+#undef N
+#undef M
+
+/* ------------------------------------ */
+
+#ifndef USING_R
+
+igraph_i_rng_mt19937_state_t igraph_i_rng_default_state;
+
+#define addr(a) (&a)
+
+/**
+ * \var igraph_i_rng_default
+ * The default igraph random number generator
+ * 
+ * This generator is used by all builtin igraph functions that need to
+ * generate random numbers; e.g. all random graph generators. 
+ * 
+ * You can use \ref igraph_i_rng_default with \ref igraph_rng_seed()
+ * to set its seed.
+ * 
+ * You can change the default generator using the \ref
+ * igraph_rng_set_default() function. 
+ */
+
+IGRAPH_THREAD_LOCAL igraph_rng_t igraph_i_rng_default = { 
+  addr(igraph_rngtype_mt19937),
+  addr(igraph_i_rng_default_state),
+  /* def= */ 1
+};
+
+#undef addr
+
+/** 
+ * \function igraph_rng_set_default
+ * Set the default igraph random number generator
+ * 
+ * \param rng The random number generator to use as default from now
+ *    on. Calling \ref igraph_rng_destroy() on it, while it is still
+ *    being used as the default will result craches and/or
+ *    unpredictable results.
+ * 
+ * Time complexity: O(1).
+ */
+
+void igraph_rng_set_default(igraph_rng_t *rng) {
+  igraph_i_rng_default = (*rng);
+}
+
+#endif
+
+
+/* ------------------------------------ */
+
+#ifdef USING_R
+
+double  unif_rand(void);
+double  norm_rand(void);
+double  exp_rand(void);
+double  Rf_rgeom(double);
+double  Rf_rbinom(double, double);
+
+int igraph_rng_R_init(void **state) {
+  IGRAPH_ERROR("R RNG error, unsupported function called",
+	       IGRAPH_EINTERNAL);
+  return 0;
+}
+
+void igraph_rng_R_destroy(void *state) {
+  igraph_error("R RNG error, unsupported function called",
+	       __FILE__, __LINE__, IGRAPH_EINTERNAL);
+}
+
+int igraph_rng_R_seed(void *state, unsigned long int seed) {
+  IGRAPH_ERROR("R RNG error, unsupported function called",
+	       IGRAPH_EINTERNAL);
+  return 0;
+}
+
+unsigned long int igraph_rng_R_get(void *state) {
+  return (unsigned long) (unif_rand() * 0x7FFFFFFFUL);
+}
+
+igraph_real_t igraph_rng_R_get_real(void *state) {
+  return unif_rand();
+}
+
+igraph_real_t igraph_rng_R_get_norm(void *state) {
+  return norm_rand();
+}
+
+igraph_real_t igraph_rng_R_get_geom(void *state, igraph_real_t p) {
+  return Rf_rgeom(p);
+}
+ 
+igraph_real_t igraph_rng_R_get_binom(void *state, long int n,
+				     igraph_real_t p) {
+  return Rf_rbinom(n, p);
+}
+
+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) {
+    if (scale == 0.0) { return 0.0; }
+    return IGRAPH_NAN;
+  }
+  return scale * exp_rand();
+}
+
+igraph_rng_type_t igraph_rngtype_R = {
+  /* name= */      "GNU R",
+  /* min=  */      0,
+  /* max=  */      0x7FFFFFFFUL,
+  /* init= */      igraph_rng_R_init,
+  /* destroy= */   igraph_rng_R_destroy,
+  /* seed= */      igraph_rng_R_seed,
+  /* get= */       igraph_rng_R_get,
+  /* get_real= */  igraph_rng_R_get_real,
+  /* get_norm= */  igraph_rng_R_get_norm,
+  /* get_geom= */  igraph_rng_R_get_geom,
+  /* get_binom= */ igraph_rng_R_get_binom,
+  /* get_exp= */   igraph_rng_R_get_exp
+};
+
+IGRAPH_THREAD_LOCAL igraph_rng_t igraph_i_rng_default = { 
+  &igraph_rngtype_R,
+  0,
+  /* def= */ 1
+};
+
+#endif
+
+/* ------------------------------------ */
+
+/**
+ * \function igraph_rng_default
+ * Query the default random number generator.
+ * 
+ * \return A pointer to the default random number generator.
+ * 
+ * \sa igraph_rng_set_default()
+ */
+
+igraph_rng_t *igraph_rng_default() {
+  return &igraph_i_rng_default;
+}
+
+/* ------------------------------------ */
+
+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);
+
+/** 
+ * \function igraph_rng_init
+ * Initialize a random number generator
+ * 
+ * This function allocates memory for a random number generator, with
+ * the given type, and sets its seed to the default.
+ * 
+ * \param rng Pointer to an uninitialized RNG.
+ * \param type The type of the RNG, please see the documentation for
+ *    the supported types.
+ * \return Error code.
+ * 
+ * Time complexity: depends on the type of the generator, but usually
+ * it should be O(1).
+ */
+
+int igraph_rng_init(igraph_rng_t *rng, const igraph_rng_type_t *type) {
+  rng->type=type;
+  IGRAPH_CHECK(rng->type->init(&rng->state));
+  return 0;
+}
+
+/** 
+ * \function igraph_rng_destroy
+ * Deallocate memory associated with a random number generator
+ * 
+ * \param rng The RNG to destroy. Do not destroy an RNG that is used
+ *    as the default igraph RNG. 
+ * 
+ * Time complexity: O(1).
+ */
+
+void igraph_rng_destroy(igraph_rng_t *rng) {
+  rng->type->destroy(rng->state);
+}
+
+/**
+ * \function igraph_rng_seed
+ * Set the seed of a random number generator
+ * 
+ * \param rng The RNG. 
+ * \param seed The new seed.
+ * \return Error code.
+ * 
+ * Time complexity: usually O(1), but may depend on the type of the
+ * RNG.
+ */
+int igraph_rng_seed(igraph_rng_t *rng, unsigned long int seed) {
+  const igraph_rng_type_t *type=rng->type;
+  rng->def=0;
+  IGRAPH_CHECK(type->seed(rng->state, seed));
+  return 0;
+}
+
+/** 
+ * \function igraph_rng_max 
+ * Query the maximum possible integer for a random number generator
+ * 
+ * \param rng The RNG.
+ * \return The largest possible integer that can be generated by
+ *         calling \ref igraph_rng_get_integer() on the RNG.
+ * 
+ * Time complexity: O(1).
+ */
+
+unsigned long int igraph_rng_max(igraph_rng_t *rng) {
+  const igraph_rng_type_t *type=rng->type;
+  return type->max;
+}
+
+/**
+ * \function igraph_rng_min
+ * Query the minimum possible integer for a random number generator
+ * 
+ * \param rng The RNG.
+ * \return The smallest possible integer that can be generated by
+ *         calling \ref igraph_rng_get_integer() on the RNG.
+ * 
+ * Time complexity: O(1).
+ */
+
+unsigned long int igraph_rng_min(igraph_rng_t *rng) {
+  const igraph_rng_type_t *type=rng->type;
+  return type->min;
+}
+
+/** 
+ * \function igraph_rng_name
+ * Query the type of a random number generator
+ * 
+ * \param rng The RNG.
+ * \return The name of the type of the generator. Do not deallocate or
+ *         change the returned string pointer.
+ * 
+ * Time complexity: O(1).
+ */
+
+const char *igraph_rng_name(igraph_rng_t *rng) {
+  const igraph_rng_type_t *type=rng->type;
+  return type->name;
+}
+
+/** 
+ * \function igraph_rng_get_integer
+ * Generate an integer random number from an interval
+ * 
+ * \param rng Pointer to the RNG to use for the generation. Use \ref
+ *        igraph_rng_default() here to use the default igraph RNG.
+ * \param l Lower limit, inclusive, it can be negative as well.
+ * \param h Upper limit, inclusive, it can be negative as well, but it
+ *        should be at least <code>l</code>.
+ * \return The generated random integer.
+ * 
+ * Time complexity: depends on the generator, but should be usually
+ * O(1).
+ */
+
+long int igraph_rng_get_integer(igraph_rng_t *rng,
+				long int l, long int h) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_real) {
+    return (long int)(type->get_real(rng->state)*(h-l+1)+l);
+  } else if (type->get) {
+    unsigned long int max=type->max;
+    return (long int)(type->get(rng->state) / ((double)max+1)*(h-l+1)+l);
+  }
+  IGRAPH_ERROR("Internal random generator error", IGRAPH_EINTERNAL);
+  return 0;
+}
+
+/** 
+ * \function igraph_rng_get_normal
+ * Normally distributed random numbers
+ * 
+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()
+ *        here to use the default igraph RNG.
+ * \param m The mean.
+ * \param s Standard deviation.
+ * \return The generated normally distributed random number.
+ * 
+ * Time complexity: depends on the type of the RNG.
+ */
+
+igraph_real_t igraph_rng_get_normal(igraph_rng_t *rng, 
+				    igraph_real_t m, igraph_real_t s) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_norm) {
+    return type->get_norm(rng->state)*s+m;
+  } else {
+    return igraph_norm_rand(rng)*s+m;
+  }
+}
+
+/** 
+ * \function igraph_rng_get_unif
+ * Generate real, uniform random numbers from an interval
+ * 
+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()
+ *        here to use the default igraph RNG.
+ * \param l The lower bound, it can be negative.
+ * \param h The upper bound, it can be negative, but it has to be
+ *        larger than the lower bound.
+ * \return The generated uniformly distributed random number.
+ * 
+ * Time complexity: depends on the type of the RNG.
+ */
+
+igraph_real_t igraph_rng_get_unif(igraph_rng_t *rng, 
+				  igraph_real_t l, igraph_real_t h) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_real) {
+    return type->get_real(rng->state)*(h-l)+l;
+  } else if (type->get) {
+    unsigned long int max=type->max;
+    return type->get(rng->state)/((double)max+1)*(double)(h-l)+l;
+  }
+  IGRAPH_ERROR("Internal random generator error", IGRAPH_EINTERNAL);
+  return 0;  
+}
+
+/** 
+ * \function igraph_rng_get_unif01
+ * Generate real, uniform random number from the unit interval
+ *
+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()
+ *        here to use the default igraph RNG.
+ * \return The generated uniformly distributed random number.
+ * 
+ * Time complexity: depends on the type of the RNG.
+ */
+
+igraph_real_t igraph_rng_get_unif01(igraph_rng_t *rng) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_real) {
+    return type->get_real(rng->state);
+  } else if (type->get) {
+    unsigned long int max=type->max;
+    return type->get(rng->state)/((double)max+1);
+  }
+  IGRAPH_ERROR("Internal random generator error", IGRAPH_EINTERNAL);
+  return 0;  
+}
+
+/** 
+ * \function igraph_rng_get_geom
+ * Generate geometrically distributed random numbers
+ * 
+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()
+ *        here to use the default igraph RNG.
+ * \param p The probability of success in each trial. Must be larger
+ *        than zero and smaller or equal to 1.
+ * \return The generated geometrically distributed random number.
+ * 
+ * Time complexity: depends on the type of the RNG.
+ */
+
+igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_geom) {
+    return type->get_geom(rng->state, p);
+  } else {
+    return igraph_rgeom(rng, p);
+  }
+}
+
+/** 
+ * \function igraph_rng_get_binom
+ * Generate binomially distributed random numbers
+ * 
+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()
+ *        here to use the default igraph RNG.
+ * \param n Number of observations.
+ * \param p Probability of an event.
+ * \return The generated binomially distributed random number.
+ * 
+ * Time complexity: depends on the type of the RNG.
+ */
+
+igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, long int n, 
+				   igraph_real_t p) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_binom) {
+    return type->get_binom(rng->state, n, p);
+  } else {
+    return igraph_rbinom(rng, n, p);
+  }
+}
+
+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;
+  if (type->get && max==0x7FFFFFFFUL) {
+    return type->get(rng->state);
+  } else if (type->get_real) {
+    return (unsigned long int) (type->get_real(rng->state)*0x7FFFFFFFUL);
+  } else { 
+    return (unsigned long int) (igraph_rng_get_unif01(rng)*0x7FFFFFFFUL);
+  }
+}
+
+igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_exp) {
+    return type->get_exp(rng->state, rate);
+  } else { 
+    return igraph_rexp(rng, rate);
+  }
+}
+
+
+#ifndef HAVE_EXPM1
+#ifndef USING_R			/* R provides a replacement */
+/* expm1 replacement */
+double expm1 (double x)
+{
+    if (fabs(x) < M_LN2)
+    {
+        /* Compute the Taylor series S = x + (1/2!) x^2 + (1/3!) x^3 + ... */
+
+        double i = 1.0;
+        double sum = x;
+        double term = x / 1.0;
+
+        do
+        {
+            term *= x / ++i;
+            sum += term;
+        }
+        while (fabs(term) > fabs(sum) * 2.22e-16);
+      
+        return sum;
+    }
+
+    return expl(x) - 1.0L;
+}
+#endif
+#endif
+
+#ifndef HAVE_RINT
+#ifndef USING_R			/* R provides a replacement */
+/* rint replacement */
+double rint (double x)
+{
+   return ( (x<0.) ? -floor(-x+.5) : floor(x+.5) );
+}
+#endif
+#endif
+
+#ifndef HAVE_RINTF
+float rintf (float x)
+{
+   return ( (x<(float)0.) ? -(float)floor(-x+.5) : (float)floor(x+.5) );
+}
+#endif
+
+/*
+ * \ingroup internal
+ * 
+ * This function appends the rest of the needed random number to the 
+ * result vector.
+ */
+
+int igraph_i_random_sample_alga(igraph_vector_t *res, igraph_integer_t l, igraph_integer_t h, 
+			      igraph_integer_t length) {
+  igraph_real_t N=h-l+1;
+  igraph_real_t n=length;
+  
+  igraph_real_t top=N-n;
+  igraph_real_t Nreal=N;
+  igraph_real_t S=0;
+  igraph_real_t V, quot;
+  
+  l=l-1;
+
+  while (n>=2) {
+    V=RNG_UNIF01();
+    S=1;
+    quot=top/Nreal;
+    while (quot>V) {
+      S+=1;
+      top=-1.0+top;
+      Nreal=-1.0+Nreal;
+      quot=(quot*top)/Nreal;
+    }
+    l+=S;
+    igraph_vector_push_back(res, l);	/* allocated */
+    Nreal=-1.0+Nreal; n=-1+n;
+  }
+  
+  S=floor(round(Nreal)*RNG_UNIF01());
+  l+=S+1;
+  igraph_vector_push_back(res, l);	/* allocated */
+  
+  return 0;
+}
+
+/**
+ * \ingroup nongraph
+ * \function igraph_random_sample
+ * \brief Generates an increasing random sequence of integers.
+ * 
+ * </para><para>
+ * This function generates an increasing sequence of random integer
+ * numbers from a given interval. The algorithm is taken literally
+ * from (Vitter 1987). This method can be used for generating numbers from a
+ * \em very large interval. It is primarily created for randomly
+ * selecting some edges from the sometimes huge set of possible edges
+ * in a large graph.
+ * </para><para>
+ * Note that the type of the lower and the upper limit is \c igraph_real_t,
+ * not \c igraph_integer_t. This does not mean that you can pass fractional
+ * numbers there; these values must still be integral, but we need the
+ * longer range of \c igraph_real_t in several places in the library
+ * (for instance, when generating Erdos-Renyi graphs).
+ * \param res Pointer to an initialized vector. This will hold the
+ *        result. It will be resized to the proper size.
+ * \param l The lower limit of the generation interval (inclusive). This must
+ *        be less than or equal to the upper limit, and it must be integral.
+ *        Passing a fractional number here results in undefined behaviour.
+ * \param h The upper limit of the generation interval (inclusive). This must
+ *        be greater than or equal to the lower limit, and it must be integral.
+ *        Passing a fractional number here results in undefined behaviour.
+ * \param length The number of random integers to generate.
+ * \return The error code \c IGRAPH_EINVAL is returned in each of the
+ *         following cases: (1) The given lower limit is greater than the
+ *         given upper limit, i.e. \c l > \c h. (2) Assuming that
+ *         \c l < \c h and N is the sample size, the above error code is
+ *         returned if N > |\c h - \c l|, i.e. the sample size exceeds the
+ *         size of the candidate pool.
+ *
+ * Time complexity: according to (Vitter 1987), the expected
+ * running time is O(length).
+ *
+ * </para><para>
+ * Reference:
+ * \clist
+ * \cli (Vitter 1987)
+ *   J. S. Vitter. An efficient algorithm for sequential random sampling.
+ *   \emb ACM Transactions on Mathematical Software, \eme 13(1):58--67, 1987.
+ * \endclist
+ *
+ * \example examples/simple/igraph_random_sample.c
+ */
+
+int igraph_random_sample(igraph_vector_t *res, igraph_real_t l, igraph_real_t h, 
+			 igraph_integer_t length) {
+  igraph_real_t N=h-l+1;
+  igraph_real_t n=length;
+  int retval;
+
+  igraph_real_t nreal=length;
+  igraph_real_t ninv=1.0/nreal;
+  igraph_real_t Nreal=N;
+  igraph_real_t Vprime;
+  igraph_real_t qu1=-n+1+N;
+  igraph_real_t qu1real=-nreal+1.0+Nreal;
+  igraph_real_t negalphainv=-13;
+  igraph_real_t threshold=-negalphainv*n;
+  igraph_real_t S;
+
+  /* getting back some sense of sanity */
+  if (l > h)
+    IGRAPH_ERROR("Lower limit is greater than upper limit", IGRAPH_EINVAL);
+  /* now we know that l <= h */
+  if (length > N)
+    IGRAPH_ERROR("Sample size exceeds size of candidate pool", IGRAPH_EINVAL);
+
+  /* treat rare cases quickly */
+  if (l==h) {
+    IGRAPH_CHECK(igraph_vector_resize(res, 1));
+    VECTOR(*res)[0] = l;
+    return 0;
+  }
+  if (length==N) {
+    long int i = 0;
+    IGRAPH_CHECK(igraph_vector_resize(res, length));
+    for (i = 0; i < length; i++) {
+      VECTOR(*res)[i] = l++;
+    }
+    return 0;
+  }
+
+  igraph_vector_clear(res);
+  IGRAPH_CHECK(igraph_vector_reserve(res, length));  
+
+  RNG_BEGIN();
+  
+  Vprime=exp(log(RNG_UNIF01())*ninv);
+  l=l-1;
+
+  while (n>1 && threshold < N) {
+    igraph_real_t X, U;
+    igraph_real_t limit, t;
+    igraph_real_t negSreal, y1, y2, top, bottom;
+    igraph_real_t nmin1inv=1.0/(-1.0+nreal);
+    while (1) {
+      while(1) {
+	X=Nreal*(-Vprime+1.0);
+	S=floor(X);
+	// if (S==0) { S=1; }
+	if (S <qu1) { break; }
+	Vprime = exp(log(RNG_UNIF01())*ninv);
+      }
+      U=RNG_UNIF01();
+      negSreal=-S;
+      
+      y1=exp(log(U*Nreal/qu1real)*nmin1inv);
+      Vprime=y1*(-X/Nreal+1.0)*(qu1real/(negSreal+qu1real));
+      if (Vprime <= 1.0) { break; }
+      
+      y2=1.0;
+      top=-1.0+Nreal;
+      if (-1+n > S) {
+	bottom=-nreal+Nreal; 
+	limit=-S+N;
+      } else {
+	bottom=-1.0+negSreal+Nreal;
+	limit=qu1;
+      }
+      for (t=-1+N; t>=limit; t--) {
+	y2=(y2*top)/bottom;
+	top=-1.0+top;
+	bottom=-1.0+bottom;
+      }
+      if (Nreal/(-X+Nreal) >= y1*exp(log(y2)*nmin1inv)) {
+	Vprime=exp(log(RNG_UNIF01())*nmin1inv);
+	break;
+      }
+      Vprime=exp(log(RNG_UNIF01())*ninv);
+    }
+        
+    l+=S+1;
+    igraph_vector_push_back(res, l);	/* allocated */
+    N=-S+(-1+N);   Nreal=negSreal+(-1.0+Nreal);
+    n=-1+n;   nreal=-1.0+nreal; ninv=nmin1inv;
+    qu1=-S+qu1; qu1real=negSreal+qu1real;
+    threshold=threshold+negalphainv;
+  }
+  
+  if (n>1) {
+    retval=igraph_i_random_sample_alga(res, (igraph_integer_t) l+1, 
+				       (igraph_integer_t) h, 
+				       (igraph_integer_t) n);
+  } else {
+    retval=0;
+    S=floor(N*Vprime);
+    l+=S+1;
+    igraph_vector_push_back(res, l);	/* allocated */
+  }
+
+  RNG_END();
+  
+  return retval;
+}
+  
+#ifdef USING_R
+
+/* These are never called. But they are correct, nevertheless */
+
+double igraph_norm_rand(igraph_rng_t *rng) {
+  return norm_rand();
+}
+
+double igraph_rgeom(igraph_rng_t *rng, double p) {
+  return Rf_rgeom(p);
+}
+
+double igraph_rbinom(igraph_rng_t *rng, double nin, double pp) {
+  return Rf_rbinom(nin, pp);
+}
+
+double igraph_rexp(igraph_rng_t *rng, double rate) {
+  igraph_real_t scale = 1.0 / rate;
+  if (!IGRAPH_FINITE(scale) || scale <= 0.0) {
+    if (scale == 0.0) { return 0.0; }
+    return IGRAPH_NAN;
+  }
+  return scale * exp_rand();
+}
+
+#else
+
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000 The R Development Core Team
+ *  based on AS 111 (C) 1977 Royal Statistical Society
+ *  and   on AS 241 (C) 1988 Royal Statistical Society
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ *  SYNOPSIS
+ *
+ *	double qnorm5(double p, double mu, double sigma,
+ *		      int lower_tail, int log_p)
+ *            {qnorm (..) is synonymous and preferred inside R}
+ *
+ *  DESCRIPTION
+ *
+ *	Compute the quantile function for the normal distribution.
+ *
+ *	For small to moderate probabilities, algorithm referenced
+ *	below is used to obtain an initial approximation which is
+ *	polished with a final Newton step.
+ *
+ *	For very large arguments, an algorithm of Wichura is used.
+ *
+ *  REFERENCE
+ *
+ *	Beasley, J. D. and S. G. Springer (1977).
+ *	Algorithm AS 111: The percentage points of the normal distribution,
+ *	Applied Statistics, 26, 118-121.
+ *
+ *      Wichura, M.J. (1988).
+ *      Algorithm AS 241: The Percentage Points of the Normal Distribution.
+ *      Applied Statistics, 37, 477-484.
+ */
+
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998-2004  The R Development 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* Private header file for use during compilation of Mathlib */
+#ifndef MATHLIB_PRIVATE_H
+#define MATHLIB_PRIVATE_H
+
+#ifdef _MSC_VER
+#  define ML_POSINF IGRAPH_INFINITY
+#  define ML_NEGINF -IGRAPH_INFINITY
+#  define ML_NAN    IGRAPH_NAN
+#else
+#  define ML_POSINF	(1.0 / 0.0)
+#  define ML_NEGINF	((-1.0) / 0.0)
+#  define ML_NAN		(0.0 / 0.0)
+#endif
+
+#define ML_ERROR(x)	/* nothing */
+#define ML_UNDERFLOW	(DBL_MIN * DBL_MIN)
+#define ML_VALID(x)	(!ISNAN(x))
+
+#define ME_NONE		0
+/*	no error */
+#define ME_DOMAIN	1
+/*	argument out of domain */
+#define ME_RANGE	2
+/*	value out of range */
+#define ME_NOCONV	4
+/*	process did not converge */
+#define ME_PRECISION	8
+/*	does not have "full" precision */
+#define ME_UNDERFLOW	16
+/*	and underflow occurred (important for IEEE)*/
+
+#define ML_ERR_return_NAN { ML_ERROR(ME_DOMAIN); return ML_NAN; }
+
+/* Wilcoxon Rank Sum Distribution */
+
+#define WILCOX_MAX 50
+
+/* Wilcoxon Signed Rank Distribution */
+
+#define SIGNRANK_MAX 50
+
+/* Formerly private part of Mathlib.h */
+
+/* always remap internal functions */
+#define bd0       	Rf_bd0
+#define chebyshev_eval	Rf_chebyshev_eval
+#define chebyshev_init	Rf_chebyshev_init
+#define i1mach		Rf_i1mach
+#define gammalims	Rf_gammalims
+#define lfastchoose	Rf_lfastchoose
+#define lgammacor	Rf_lgammacor
+#define stirlerr       	Rf_stirlerr
+
+	/* Chebyshev Series */
+
+int	chebyshev_init(double*, int, double);
+double	chebyshev_eval(double, const double *, const int);
+
+	/* Gamma and Related Functions */
+
+void	gammalims(double*, double*);
+double	lgammacor(double); /* log(gamma) correction */
+double  stirlerr(double);  /* Stirling expansion "error" */
+
+double	lfastchoose(double, double);
+
+double  bd0(double, double);
+
+/* Consider adding these two to the API (Rmath.h): */
+double	dbinom_raw(double, double, double, double, int);
+double	dpois_raw (double, double, int);
+double  pnchisq_raw(double, double, double, double, double, int);
+
+int	i1mach(int);
+
+/* From toms708.c */
+void bratio(double a, double b, double x, double y, 
+	    double *w, double *w1, int *ierr);
+
+
+#endif /* MATHLIB_PRIVATE_H */
+
+
+	/* Utilities for `dpq' handling (density/probability/quantile) */
+
+/* give_log in "d";  log_p in "p" & "q" : */
+#define give_log log_p
+							/* "DEFAULT" */
+							/* --------- */
+#define R_D__0	(log_p ? ML_NEGINF : 0.)		/* 0 */
+#define R_D__1	(log_p ? 0. : 1.)			/* 1 */
+#define R_DT_0	(lower_tail ? R_D__0 : R_D__1)		/* 0 */
+#define R_DT_1	(lower_tail ? R_D__1 : R_D__0)		/* 1 */
+
+#define R_D_Lval(p)	(lower_tail ? (p) : (1 - (p)))	/*  p  */
+#define R_D_Cval(p)	(lower_tail ? (1 - (p)) : (p))	/*  1 - p */
+
+#define R_D_val(x)	(log_p	? log(x) : (x))		/*  x  in pF(x,..) */
+#define R_D_qIv(p)	(log_p	? exp(p) : (p))		/*  p  in qF(p,..) */
+#define R_D_exp(x)	(log_p	?  (x)	 : exp(x))	/* exp(x) */
+#define R_D_log(p)	(log_p	?  (p)	 : log(p))	/* log(p) */
+#define R_D_Clog(p)	(log_p	? log1p(-(p)) : (1 - (p)))/* [log](1-p) */
+
+/* log(1-exp(x)):  R_D_LExp(x) == (log1p(- R_D_qIv(x))) but even more stable:*/
+#define R_D_LExp(x)     (log_p ? R_Log1_Exp(x) : log1p(-x))
+
+/*till 1.8.x:
+ * #define R_DT_val(x)	R_D_val(R_D_Lval(x))
+ * #define R_DT_Cval(x)	R_D_val(R_D_Cval(x)) */
+#define R_DT_val(x)	(lower_tail ? R_D_val(x)  : R_D_Clog(x))
+#define R_DT_Cval(x)	(lower_tail ? R_D_Clog(x) : R_D_val(x))
+
+/*#define R_DT_qIv(p)	R_D_Lval(R_D_qIv(p))		 *  p  in qF ! */
+#define R_DT_qIv(p)	(log_p ? (lower_tail ? exp(p) : - expm1(p)) \
+			       : R_D_Lval(p))
+
+/*#define R_DT_CIv(p)	R_D_Cval(R_D_qIv(p))		 *  1 - p in qF */
+#define R_DT_CIv(p)	(log_p ? (lower_tail ? -expm1(p) : exp(p)) \
+			       : R_D_Cval(p))
+
+#define R_DT_exp(x)	R_D_exp(R_D_Lval(x))		/* exp(x) */
+#define R_DT_Cexp(x)	R_D_exp(R_D_Cval(x))		/* exp(1 - x) */
+
+#define R_DT_log(p)	(lower_tail? R_D_log(p) : R_D_LExp(p))/* log(p) in qF */
+#define R_DT_Clog(p)	(lower_tail? R_D_LExp(p): R_D_log(p))/* log(1-p) in qF*/
+#define R_DT_Log(p)	(lower_tail? (p) : R_Log1_Exp(p))
+/* ==   R_DT_log when we already "know" log_p == TRUE :*/
+
+#define R_Q_P01_check(p)			\
+    if ((log_p	&& p > 0) ||			\
+	(!log_p && (p < 0 || p > 1)) )		\
+	ML_ERR_return_NAN
+
+/* additions for density functions (C.Loader) */
+#define R_D_fexp(f,x)     (give_log ? -0.5*log(f)+(x) : exp(x)/sqrt(f))
+#define R_D_forceint(x)   floor((x) + 0.5)
+#define R_D_nonint(x) 	  (fabs((x) - floor((x)+0.5)) > 1e-7)
+/* [neg]ative or [non int]eger : */
+#define R_D_negInonint(x) (x < 0. || R_D_nonint(x))
+
+#define R_D_nonint_check(x) 				\
+   if(R_D_nonint(x)) {					\
+	MATHLIB_WARNING("non-integer x = %f", x);	\
+	return R_D__0;					\
+   }
+
+double igraph_qnorm5(double p, double mu, double sigma, int lower_tail, int log_p)
+{
+    double p_, q, r, val;
+
+#ifdef IEEE_754
+    if (ISNAN(p) || ISNAN(mu) || ISNAN(sigma))
+	return p + mu + sigma;
+#endif
+    if (p == R_DT_0)	return ML_NEGINF;
+    if (p == R_DT_1)	return ML_POSINF;
+    R_Q_P01_check(p);
+
+    if(sigma  < 0)	ML_ERR_return_NAN;
+    if(sigma == 0)	return mu;
+
+    p_ = R_DT_qIv(p);/* real lower_tail prob. p */
+    q = p_ - 0.5;
+
+/*-- use AS 241 --- */
+/* double ppnd16_(double *p, long *ifault)*/
+/*      ALGORITHM AS241  APPL. STATIST. (1988) VOL. 37, NO. 3
+
+        Produces the normal deviate Z corresponding to a given lower
+        tail area of P; Z is accurate to about 1 part in 10**16.
+
+        (original fortran code used PARAMETER(..) for the coefficients
+         and provided hash codes for checking them...)
+*/
+    if (fabs(q) <= .425) {/* 0.075 <= p <= 0.925 */
+        r = .180625 - q * q;
+	val =
+            q * (((((((r * 2509.0809287301226727 +
+                       33430.575583588128105) * r + 67265.770927008700853) * r +
+                     45921.953931549871457) * r + 13731.693765509461125) * r +
+                   1971.5909503065514427) * r + 133.14166789178437745) * r +
+                 3.387132872796366608)
+            / (((((((r * 5226.495278852854561 +
+                     28729.085735721942674) * r + 39307.89580009271061) * r +
+                   21213.794301586595867) * r + 5394.1960214247511077) * r +
+                 687.1870074920579083) * r + 42.313330701600911252) * r + 1.);
+    }
+    else { /* closer than 0.075 from {0,1} boundary */
+
+	/* r = min(p, 1-p) < 0.075 */
+	if (q > 0)
+	    r = R_DT_CIv(p);/* 1-p */
+	else
+	    r = p_;/* = R_DT_Iv(p) ^=  p */
+
+	r = sqrt(- ((log_p &&
+		     ((lower_tail && q <= 0) || (!lower_tail && q > 0))) ?
+		    p : /* else */ log(r)));
+        /* r = sqrt(-log(r))  <==>  min(p, 1-p) = exp( - r^2 ) */
+
+        if (r <= 5.) { /* <==> min(p,1-p) >= exp(-25) ~= 1.3888e-11 */
+            r += -1.6;
+            val = (((((((r * 7.7454501427834140764e-4 +
+                       .0227238449892691845833) * r + .24178072517745061177) *
+                     r + 1.27045825245236838258) * r +
+                    3.64784832476320460504) * r + 5.7694972214606914055) *
+                  r + 4.6303378461565452959) * r +
+                 1.42343711074968357734)
+                / (((((((r *
+                         1.05075007164441684324e-9 + 5.475938084995344946e-4) *
+                        r + .0151986665636164571966) * r +
+                       .14810397642748007459) * r + .68976733498510000455) *
+                     r + 1.6763848301838038494) * r +
+                    2.05319162663775882187) * r + 1.);
+        }
+        else { /* very close to  0 or 1 */
+            r += -5.;
+            val = (((((((r * 2.01033439929228813265e-7 +
+                       2.71155556874348757815e-5) * r +
+                      .0012426609473880784386) * r + .026532189526576123093) *
+                    r + .29656057182850489123) * r +
+                   1.7848265399172913358) * r + 5.4637849111641143699) *
+                 r + 6.6579046435011037772)
+                / (((((((r *
+                         2.04426310338993978564e-15 + 1.4215117583164458887e-7)*
+                        r + 1.8463183175100546818e-5) * r +
+                       7.868691311456132591e-4) * r + .0148753612908506148525)
+                     * r + .13692988092273580531) * r +
+                    .59983220655588793769) * r + 1.);
+        }
+
+	if(q < 0.0)
+	    val = -val;
+        /* return (q >= 0.)? r : -r ;*/
+    }
+    return mu + sigma * val;
+}
+
+double fsign(double x, double y)
+{
+#ifdef IEEE_754
+    if (ISNAN(x) || ISNAN(y))
+        return x + y;
+#endif
+    return ((y >= 0) ? fabs(x) : -fabs(x));
+}
+
+int imax2(int x, int y)
+{
+    return (x < y) ? y : x;
+}
+
+int imin2(int x, int y)
+{
+    return (x < y) ? x : y;
+}
+
+#ifdef HAVE_WORKING_ISFINITE
+/* isfinite is defined in <math.h> according to C99 */
+# define R_FINITE(x)    isfinite(x)
+#elif HAVE_WORKING_FINITE
+/* include header needed to define finite() */
+#  ifdef HAVE_IEEE754_H
+#   include <ieee754.h>         /* newer Linuxen */
+#  else
+#   ifdef HAVE_IEEEFP_H
+#    include <ieeefp.h>         /* others [Solaris], .. */
+#   endif
+#  endif
+# define R_FINITE(x)    finite(x)
+#else
+# define R_FINITE(x)    R_finite(x)
+#endif
+
+int R_finite(double x)
+{
+#ifdef HAVE_WORKING_ISFINITE
+    return isfinite(x);
+#elif HAVE_WORKING_FINITE
+    return finite(x);
+#else
+/* neither finite nor isfinite work. Do we really need the AIX exception? */
+# ifdef _AIX
+#  include <fp.h>
+     return FINITE(x);
+# elif defined(_MSC_VER)
+     return _finite(x);
+#else
+    return (!isnan(x) & (x != 1/0.0) & (x != -1.0/0.0));
+# endif
+#endif
+}
+
+int R_isnancpp(double x)
+{
+   return (isnan(x)!=0);
+}
+
+#ifdef __cplusplus
+  int R_isnancpp(double); /* in arithmetic.c */
+#  define ISNAN(x)     R_isnancpp(x)
+#else
+#  define ISNAN(x)     (isnan(x)!=0)
+#endif
+
+double igraph_norm_rand(igraph_rng_t *rng) {
+  
+  double u1;
+
+#define BIG 134217728 /* 2^27 */
+  /* unif_rand() alone is not of high enough precision */
+  u1 = igraph_rng_get_unif01(rng);
+  u1 = (int)(BIG*u1) + igraph_rng_get_unif01(rng);
+  return igraph_qnorm5(u1/BIG, 0.0, 1.0, 1, 0);
+}
+
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000-2002 the R Development 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ *  SYNOPSIS
+ *
+ *    #include <Rmath.h>
+ *    double exp_rand(void);
+ *
+ *  DESCRIPTION
+ *
+ *    Random variates from the standard exponential distribution.
+ *
+ *  REFERENCE
+ *
+ *    Ahrens, J.H. and Dieter, U. (1972).
+ *    Computer methods for sampling from the exponential and
+ *    normal distributions.
+ *    Comm. ACM, 15, 873-882.
+ */
+
+double igraph_exp_rand(igraph_rng_t *rng)
+{
+    /* q[k-1] = sum(log(2)^k / k!)  k=1,..,n, */
+    /* The highest n (here 8) is determined by q[n-1] = 1.0 */
+    /* within standard precision */
+    const double q[] =
+    {
+	0.6931471805599453,
+	0.9333736875190459,
+	0.9888777961838675,
+	0.9984959252914960,
+	0.9998292811061389,
+	0.9999833164100727,
+	0.9999985691438767,
+	0.9999998906925558,
+	0.9999999924734159,
+	0.9999999995283275,
+	0.9999999999728814,
+	0.9999999999985598,
+	0.9999999999999289,
+	0.9999999999999968,
+	0.9999999999999999,
+	1.0000000000000000
+    };
+    double a, u, ustar, umin;
+    int i;
+
+    a = 0.;
+    /* precaution if u = 0 is ever returned */
+    u = igraph_rng_get_unif01(rng);
+    while(u <= 0.0 || u >= 1.0) u = igraph_rng_get_unif01(rng);
+    for (;;) {
+	u += u;
+	if (u > 1.0)
+	    break;
+	a += q[0];
+    }
+    u -= 1.;
+
+    if (u <= q[0])
+	return a + u;
+
+    i = 0;
+    ustar = igraph_rng_get_unif01(rng);
+    umin = ustar;
+    do {
+        ustar = igraph_rng_get_unif01(rng);
+	if (ustar < umin)
+	    umin = ustar;
+	i++;
+    } while (u > q[i]);
+    return a + umin * q[0];
+}
+
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000-2001 The R Development 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ *  SYNOPSIS
+ *
+ *    #include <Rmath.h>
+ *    double rpois(double lambda)
+ *
+ *  DESCRIPTION
+ *
+ *    Random variates from the Poisson distribution.
+ *
+ *  REFERENCE
+ *
+ *    Ahrens, J.H. and Dieter, U. (1982).
+ *    Computer generation of Poisson deviates
+ *    from modified normal distributions.
+ *    ACM Trans. Math. Software 8, 163-179.
+ */
+
+#define a0	-0.5
+#define a1	 0.3333333
+#define a2	-0.2500068
+#define a3	 0.2000118
+#define a4	-0.1661269
+#define a5	 0.1421878
+#define a6	-0.1384794
+#define a7	 0.1250060
+
+#define one_7	0.1428571428571428571
+#define one_12	0.0833333333333333333
+#define one_24	0.0416666666666666667
+
+#define repeat for(;;)
+
+#define FALSE 0
+#define TRUE  1
+#define M_1_SQRT_2PI    0.398942280401432677939946059934     /* 1/sqrt(2pi) */
+
+double igraph_rpois(igraph_rng_t *rng, double mu)
+{
+    /* Factorial Table (0:9)! */
+    const double fact[10] =
+    {
+	1., 1., 2., 6., 24., 120., 720., 5040., 40320., 362880.
+    };
+
+    /* These are static --- persistent between calls for same mu : */
+    static IGRAPH_THREAD_LOCAL int l, m;
+
+    static IGRAPH_THREAD_LOCAL double b1, b2, c, c0, c1, c2, c3;
+    static IGRAPH_THREAD_LOCAL double pp[36], p0, p, q, s, d, omega;
+    static IGRAPH_THREAD_LOCAL double big_l;/* integer "w/o overflow" */
+    static IGRAPH_THREAD_LOCAL double muprev = 0., muprev2 = 0.;/*, muold	 = 0.*/
+
+    /* Local Vars  [initialize some for -Wall]: */
+    double del, difmuk= 0., E= 0., fk= 0., fx, fy, g, px, py, t, u= 0., v, x;
+    double pois = -1.;
+    int k, kflag, big_mu, new_big_mu = FALSE;
+
+    if (!R_FINITE(mu))
+	ML_ERR_return_NAN;
+
+    if (mu <= 0.)
+	return 0.;
+
+    big_mu = mu >= 10.;
+    if(big_mu)
+	new_big_mu = FALSE;
+
+    if (!(big_mu && mu == muprev)) {/* maybe compute new persistent par.s */
+
+	if (big_mu) {
+	    new_big_mu = TRUE;
+	    /* Case A. (recalculation of s,d,l	because mu has changed):
+	     * The Poisson probabilities pk exceed the discrete normal
+	     * probabilities fk whenever k >= m(mu).
+	     */
+	    muprev = mu;
+	    s = sqrt(mu);
+	    d = 6. * mu * mu;
+	    big_l = floor(mu - 1.1484);
+	    /* = an upper bound to m(mu) for all mu >= 10.*/
+	}
+	else { /* Small mu ( < 10) -- not using normal approx. */
+
+	    /* Case B. (start new table and calculate p0 if necessary) */
+
+	    /*muprev = 0.;-* such that next time, mu != muprev ..*/
+	    if (mu != muprev) {
+		muprev = mu;
+		m = imax2(1, (int) mu);
+		l = 0; /* pp[] is already ok up to pp[l] */
+		q = p0 = p = exp(-mu);
+	    }
+
+	    repeat {
+		/* Step U. uniform sample for inversion method */
+	        u = igraph_rng_get_unif01(rng);
+		if (u <= p0)
+		    return 0.;
+
+		/* Step T. table comparison until the end pp[l] of the
+		   pp-table of cumulative Poisson probabilities
+		   (0.458 > ~= pp[9](= 0.45792971447) for mu=10 ) */
+		if (l != 0) {
+		    for (k = (u <= 0.458) ? 1 : imin2(l, m);  k <= l; k++)
+			if (u <= pp[k])
+			    return (double)k;
+		    if (l == 35) /* u > pp[35] */
+			continue;
+		}
+		/* Step C. creation of new Poisson
+		   probabilities p[l..] and their cumulatives q =: pp[k] */
+		l++;
+		for (k = l; k <= 35; k++) {
+		    p *= mu / k;
+		    q += p;
+		    pp[k] = q;
+		    if (u <= q) {
+			l = k;
+			return (double)k;
+		    }
+		}
+		l = 35;
+	    } /* end(repeat) */
+	}/* mu < 10 */
+
+    } /* end {initialize persistent vars} */
+
+/* Only if mu >= 10 : ----------------------- */
+
+    /* Step N. normal sample */
+    g = mu + s * igraph_norm_rand(rng);/* norm_rand() ~ N(0,1), standard normal */
+
+    if (g >= 0.) {
+	pois = floor(g);
+	/* Step I. immediate acceptance if pois is large enough */
+	if (pois >= big_l)
+	    return pois;
+	/* Step S. squeeze acceptance */
+	fk = pois;
+	difmuk = mu - fk;
+	u = igraph_rng_get_unif01(rng); /* ~ U(0,1) - sample */
+	if (d * u >= difmuk * difmuk * difmuk)
+	    return pois;
+    }
+
+    /* Step P. preparations for steps Q and H.
+       (recalculations of parameters if necessary) */
+
+    if (new_big_mu || mu != muprev2) {
+        /* Careful! muprev2 is not always == muprev
+	   because one might have exited in step I or S
+	   */
+        muprev2 = mu;
+	omega = M_1_SQRT_2PI / s;
+	/* The quantities b1, b2, c3, c2, c1, c0 are for the Hermite
+	 * approximations to the discrete normal probabilities fk. */
+
+	b1 = one_24 / mu;
+	b2 = 0.3 * b1 * b1;
+	c3 = one_7 * b1 * b2;
+	c2 = b2 - 15. * c3;
+	c1 = b1 - 6. * b2 + 45. * c3;
+	c0 = 1. - b1 + 3. * b2 - 15. * c3;
+	c = 0.1069 / mu; /* guarantees majorization by the 'hat'-function. */
+    }
+
+    if (g >= 0.) {
+	/* 'Subroutine' F is called (kflag=0 for correct return) */
+	kflag = 0;
+	goto Step_F;
+    }
+
+
+    repeat {
+	/* Step E. Exponential Sample */
+
+	E = igraph_exp_rand(rng);/* ~ Exp(1) (standard exponential) */
+
+	/*  sample t from the laplace 'hat'
+	    (if t <= -0.6744 then pk < fk for all mu >= 10.) */
+	u = 2 * igraph_rng_get_unif01(rng) - 1.;
+	t = 1.8 + fsign(E, u);
+	if (t > -0.6744) {
+	    pois = floor(mu + s * t);
+	    fk = pois;
+	    difmuk = mu - fk;
+
+	    /* 'subroutine' F is called (kflag=1 for correct return) */
+	    kflag = 1;
+
+	  Step_F: /* 'subroutine' F : calculation of px,py,fx,fy. */
+
+	    if (pois < 10) { /* use factorials from table fact[] */
+		px = -mu;
+		py = pow(mu, pois) / fact[(int)pois];
+	    }
+	    else {
+		/* Case pois >= 10 uses polynomial approximation
+		   a0-a7 for accuracy when advisable */
+		del = one_12 / fk;
+		del = del * (1. - 4.8 * del * del);
+		v = difmuk / fk;
+		if (fabs(v) <= 0.25)
+		    px = fk * v * v * (((((((a7 * v + a6) * v + a5) * v + a4) *
+					  v + a3) * v + a2) * v + a1) * v + a0)
+			- del;
+		else /* |v| > 1/4 */
+		    px = fk * log(1. + v) - difmuk - del;
+		py = M_1_SQRT_2PI / sqrt(fk);
+	    }
+	    x = (0.5 - difmuk) / s;
+	    x *= x;/* x^2 */
+	    fx = -0.5 * x;
+	    fy = omega * (((c3 * x + c2) * x + c1) * x + c0);
+	    if (kflag > 0) {
+		/* Step H. Hat acceptance (E is repeated on rejection) */
+		if (c * fabs(u) <= py * exp(px + E) - fy * exp(fx + E))
+		    break;
+	    } else
+		/* Step Q. Quotient acceptance (rare case) */
+		if (fy - u * fy <= py * exp(px - fx))
+		    break;
+	}/* t > -.67.. */
+    }
+    return pois;
+}
+
+double igraph_rgeom(igraph_rng_t *rng, double p) {
+    if (ISNAN(p) || p <= 0 || p > 1) ML_ERR_return_NAN;
+
+    return igraph_rpois(rng, igraph_exp_rand(rng) * ((1 - p) / p));
+}
+
+/* This is from nmath/rbinom.c */
+
+#define repeat for(;;)
+
+double igraph_rbinom(igraph_rng_t *rng, double nin, double pp)
+{
+    /* FIXME: These should become THREAD_specific globals : */
+
+    static IGRAPH_THREAD_LOCAL double c, fm, npq, p1, p2, p3, p4, qn;
+    static IGRAPH_THREAD_LOCAL double xl, xll, xlr, xm, xr;
+
+    static IGRAPH_THREAD_LOCAL double psave = -1.0;
+    static IGRAPH_THREAD_LOCAL int nsave = -1;
+    static IGRAPH_THREAD_LOCAL int m;
+
+    double f, f1, f2, u, v, w, w2, x, x1, x2, z, z2;
+    double p, q, np, g, r, al, alv, amaxp, ffm, ynorm;
+    int i,ix,k, n;
+
+    if (!R_FINITE(nin)) ML_ERR_return_NAN;
+    n = floor(nin + 0.5);
+    if (n != nin) ML_ERR_return_NAN;
+
+    if (!R_FINITE(pp) ||
+	/* n=0, p=0, p=1 are not errors <TSL>*/
+	n < 0 || pp < 0. || pp > 1.)	ML_ERR_return_NAN;
+
+    if (n == 0 || pp == 0.) return 0;
+    if (pp == 1.) return n;
+
+    p = fmin(pp, 1. - pp);
+    q = 1. - p;
+    np = n * p;
+    r = p / q;
+    g = r * (n + 1);
+
+    /* Setup, perform only when parameters change [using static (globals): */
+
+    /* FIXING: Want this thread safe
+       -- use as little (thread globals) as possible
+    */
+    if (pp != psave || n != nsave) {
+	psave = pp;
+	nsave = n;
+	if (np < 30.0) {
+	    /* inverse cdf logic for mean less than 30 */
+	    qn = pow(q, (double) n);
+	    goto L_np_small;
+	} else {
+	    ffm = np + p;
+	    m = ffm;
+	    fm = m;
+	    npq = np * q;
+	    p1 = (int)(2.195 * sqrt(npq) - 4.6 * q) + 0.5;
+	    xm = fm + 0.5;
+	    xl = xm - p1;
+	    xr = xm + p1;
+	    c = 0.134 + 20.5 / (15.3 + fm);
+	    al = (ffm - xl) / (ffm - xl * p);
+	    xll = al * (1.0 + 0.5 * al);
+	    al = (xr - ffm) / (xr * q);
+	    xlr = al * (1.0 + 0.5 * al);
+	    p2 = p1 * (1.0 + c + c);
+	    p3 = p2 + c / xll;
+	    p4 = p3 + c / xlr;
+	}
+    } else if (n == nsave) {
+	if (np < 30.0)
+	    goto L_np_small;
+    }
+
+    /*-------------------------- np = n*p >= 30 : ------------------- */
+    repeat {
+      u = igraph_rng_get_unif01(rng) * p4;
+      v = igraph_rng_get_unif01(rng);
+      /* triangular region */
+      if (u <= p1) {
+	  ix = xm - p1 * v + u;
+	  goto finis;
+      }
+      /* parallelogram region */
+      if (u <= p2) {
+	  x = xl + (u - p1) / c;
+	  v = v * c + 1.0 - fabs(xm - x) / p1;
+	  if (v > 1.0 || v <= 0.)
+	      continue;
+	  ix = x;
+      } else {
+	  if (u > p3) {	/* right tail */
+	      ix = xr - log(v) / xlr;
+	      if (ix > n)
+		  continue;
+	      v = v * (u - p3) * xlr;
+	  } else {/* left tail */
+	      ix = xl + log(v) / xll;
+	      if (ix < 0)
+		  continue;
+	      v = v * (u - p2) * xll;
+	  }
+      }
+      /* determine appropriate way to perform accept/reject test */
+      k = abs(ix - m);
+      if (k <= 20 || k >= npq / 2 - 1) {
+	  /* explicit evaluation */
+	  f = 1.0;
+	  if (m < ix) {
+	      for (i = m + 1; i <= ix; i++)
+		  f *= (g / i - r);
+	  } else if (m != ix) {
+	      for (i = ix + 1; i <= m; i++)
+		  f /= (g / i - r);
+	  }
+	  if (v <= f)
+	      goto finis;
+      } else {
+	  /* squeezing using upper and lower bounds on log(f(x)) */
+	  amaxp = (k / npq) * ((k * (k / 3. + 0.625) + 0.1666666666666) / npq + 0.5);
+	  ynorm = -k * k / (2.0 * npq);
+	  alv = log(v);
+	  if (alv < ynorm - amaxp)
+	      goto finis;
+	  if (alv <= ynorm + amaxp) {
+	      /* Stirling's formula to machine accuracy */
+	      /* for the final acceptance/rejection test */
+	      x1 = ix + 1;
+	      f1 = fm + 1.0;
+	      z = n + 1 - fm;
+	      w = n - ix + 1.0;
+	      z2 = z * z;
+	      x2 = x1 * x1;
+	      f2 = f1 * f1;
+	      w2 = w * w;
+	      if (alv <= xm * log(f1 / x1) + (n - m + 0.5) * log(z / w) + (ix - m) * log(w * p / (x1 * q)) + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / f2) / f2) / f2) / f2) / f1 / 166320.0 + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / z2) / z2) / z2) / z2) / z / 166320.0 + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / x2) / x2) / x2) / x2) / x1 / 166320.0 + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / w2) / w2) / w2) / w2) / w / 166320.)
+		  goto finis;
+	  }
+      }
+  }
+
+ L_np_small:
+    /*---------------------- np = n*p < 30 : ------------------------- */
+
+  repeat {
+     ix = 0;
+     f = qn;
+     u = igraph_rng_get_unif01(rng);
+     repeat {
+	 if (u < f)
+	     goto finis;
+	 if (ix > 110)
+	     break;
+	 u -= f;
+	 ix++;
+	 f *= (g / ix - r);
+     }
+  }
+ finis:
+    if (psave > 0.5)
+	 ix = n - ix;
+  return (double)ix;
+}
+
+igraph_real_t igraph_rexp(igraph_rng_t *rng, double rate) {
+  igraph_real_t scale = 1.0 / rate;
+  if (!IGRAPH_FINITE(scale) || scale <= 0.0) {
+    if (scale == 0.0) { return 0.0; }
+    return IGRAPH_NAN;
+  }
+  return scale * igraph_exp_rand(rng);
+}
+
+#endif
+
+/**********************************************************
+ * Testing purposes                                       *
+ *********************************************************/
+
+/* int main() { */
+
+/*   int i; */
+
+/*   RNG_BEGIN(); */
+
+/*   for (i=0; i<1000; i++) { */
+/*     printf("%li ", RNG_INTEGER(1,10)); */
+/*   } */
+/*   printf("\n"); */
+
+/*   for (i=0; i<1000; i++) { */
+/*     printf("%f ", RNG_UNIF(0,1)); */
+/*   } */
+/*   printf("\n"); */
+
+/*   for (i=0; i<1000; i++) { */
+/*     printf("%f ", RNG_NORMAL(0,5)); */
+/*   } */
+/*   printf("\n"); */
+
+/*   RNG_END(); */
+
+/*   return 0; */
+/* } */
diff --git a/src/revolver_cit.c b/src/revolver_cit.c
new file mode 100644
index 0000000..897caf1
--- /dev/null
+++ b/src/revolver_cit.c
@@ -0,0 +1,6479 @@
+/* -*- 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
new file mode 100644
index 0000000..9b43b3e
--- /dev/null
+++ b/src/revolver_grow.c
@@ -0,0 +1,1284 @@
+/* -*- 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
new file mode 100644
index 0000000..1bdf839
--- /dev/null
+++ b/src/revolver_ml_cit.c
@@ -0,0 +1,3548 @@
+/* -*- 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/sbm.c b/src/sbm.c
new file mode 100644
index 0000000..da18afb
--- /dev/null
+++ b/src/sbm.c
@@ -0,0 +1,214 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=8 sw=2 sts=2 et: */
+/* 
+   IGraph R library.
+   Copyright (C) 2003-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_interface.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.h"
+#include "igraph_random.h"
+#include "igraph_constructors.h"
+#include "igraph_games.h"
+
+/**
+ * \function igraph_sbm_game
+ * Sample from a stochastic block model
+ *
+ * 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, \p pref_matrix.
+ * See Faust, K., & Wasserman, S. (1992a). Blockmodels:
+ * Interpretation and evaluation. Social Networks, 14, 5-–61.
+ *
+ * </para><para>
+ * The order of the vertex ids in the generated graph corresponds to
+ * the \p block_sizes argument.
+ *
+ * \param graph The output graph.
+ * \param n Number of vertices.
+ * \param pref_matrix The matrix giving the Bernoulli rates.
+ *     This is a KxK matrix, where K is the number of groups.
+ *     The probability of creating an edge between vertices from
+ *     groups i and j is given by element (i,j).
+ * \param block_sizes An integer vector giving the number of
+ *     vertices in each group.
+ * \param directed Boolean, whether to create a directed graph. If
+ *     this argument is false, then \p pref_matrix must be symmetric.
+ * \param loops Boolean, whether to create self-loops.
+ * \return Error code.
+ *
+ * Time complexity: O(|V|+|E|+K^2), where |V| is the number of
+ * vertices, |E| is the number of edges, and K is the number of
+ * groups.
+ *
+ * \sa \ref igraph_erdos_renyi_game() for a simple Bernoulli graph.
+ *
+ */
+
+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 no_blocks=igraph_matrix_nrow(pref_matrix);
+  int from, to, fromoff=0;
+  igraph_real_t minp, maxp;
+  igraph_vector_t edges;
+  
+  /* ------------------------------------------------------------ */
+  /* Check arguments                                              */
+  /* ------------------------------------------------------------ */
+
+  if (igraph_matrix_ncol(pref_matrix) != no_blocks) {
+    IGRAPH_ERROR("Preference matrix is not square", 
+		 IGRAPH_NONSQUARE);
+  }
+
+  igraph_matrix_minmax(pref_matrix, &minp, &maxp);
+  if (minp < 0 || maxp > 1) { 
+    IGRAPH_ERROR("Connection probabilities must in [0,1]", IGRAPH_EINVAL);
+  }
+
+  if (n < 0) { 
+    IGRAPH_ERROR("Number of vertices must be non-negative", IGRAPH_EINVAL);
+  }
+
+  if (!directed && !igraph_matrix_is_symmetric(pref_matrix)) {
+    IGRAPH_ERROR("Preference matrix must be symmetric for undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_int_size(block_sizes) != no_blocks) {
+    IGRAPH_ERROR("Invalid block size vector length", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_int_min(block_sizes) < 0) {
+    IGRAPH_ERROR("Block size must be non-negative", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_int_sum(block_sizes) != n) {
+    IGRAPH_ERROR("Block sizes must sum up to number of vertices", 
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);  
+  
+  RNG_BEGIN();
+
+  for (from = 0; from < no_blocks; from++) {
+    int fromsize = VECTOR(*block_sizes)[from];
+    int start = directed ? 0 : from;
+    int i, tooff=0;
+    for (i=0; i<start; i++) {
+      tooff += VECTOR(*block_sizes)[i];
+    }
+    for (to = start; to < no_blocks; to++) {
+      int tosize = VECTOR(*block_sizes)[to];
+      igraph_real_t prob=MATRIX(*pref_matrix, from, to);
+      double maxedges, last=RNG_GEOM(prob);
+      if (directed && loops) {
+	maxedges = fromsize * tosize;
+	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(prob);
+	  last += 1;
+	}
+      } else if (directed && !loops && 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, fromoff + vfrom);
+	  igraph_vector_push_back(&edges, tooff + vto);
+	  last += RNG_GEOM(prob);
+	  last += 1;
+	}	
+      } else if (directed && !loops && from==to) {
+	maxedges = fromsize * (fromsize-1);
+	while (last < maxedges) {
+	  int vto=floor(last/fromsize);
+	  int vfrom=last - (igraph_real_t)vto * fromsize;
+	  if (vfrom == vto) { vto=fromsize-1; }
+	  igraph_vector_push_back(&edges, fromoff + vfrom);
+	  igraph_vector_push_back(&edges, tooff + vto);
+	  last += RNG_GEOM(prob);
+	  last += 1;
+	}
+      } else if (!directed && loops && 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, fromoff + vfrom);
+	  igraph_vector_push_back(&edges, tooff + vto);
+	  last += RNG_GEOM(prob);
+	  last += 1;
+	}
+      } else if (!directed && loops && from==to) {
+	maxedges = fromsize * (fromsize+1) / 2.0;
+	while (last < maxedges) {
+	  long int vto=floor((sqrt(8*last+1)-1)/2);
+	  long int vfrom=last-(((igraph_real_t)vto)*(vto+1))/2;
+	  igraph_vector_push_back(&edges, fromoff + vfrom);
+	  igraph_vector_push_back(&edges, tooff + vto);
+	  last += RNG_GEOM(prob);
+	  last += 1;
+	}	
+      } else if (!directed && !loops && 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, fromoff + vfrom);
+	  igraph_vector_push_back(&edges, tooff + vto);
+	  last += RNG_GEOM(prob);
+	  last += 1;
+	}
+      } else /*!directed && !loops && 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, fromoff + vfrom);
+	  igraph_vector_push_back(&edges, tooff + vto);
+	  last += RNG_GEOM(prob);
+	  last += 1;
+	}
+      }
+      
+      tooff += tosize;
+    }
+    fromoff += fromsize;
+  }
+
+  RNG_END();
+
+  igraph_create(graph, &edges, n, directed);
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
diff --git a/src/scg.c b/src/scg.c
new file mode 100644
index 0000000..40a0225
--- /dev/null
+++ b/src/scg.c
@@ -0,0 +1,2252 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-12  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    The grouping function takes as argument 'nev' eigenvectors and 
+ *	  and tries to minimize the eigenpair shifts induced by the coarse
+ *	  graining (Section 5 of the above reference). The eigenvectors are
+ *	  stored in a 'nev'x'n' matrix 'v'.
+ *	  The 'algo' parameter can take the following values
+ *		1  ->  Optimal method (sec. 5.3.1)
+ *		2  ->  Intervals+k-means (sec. 5.3.3)
+ *		3  ->  Intervals (sec. 5.3.2)
+ *		4  ->  Exact SCG (sec. 5.4.1--last paragraph)
+ *	  'nt' is a vector of length 'nev' giving either the size of the 
+ *	  partitions (if algo = 1) or the number of intervals to cut the
+ *	  eigenvectors if algo = 2 or algo = 3. When algo = 4 this parameter
+ *	  is ignored. 'maxiter' fixes the maximum number of iterations of
+ *	  the k-means algorithm, and is only considered when algo = 2.
+ *	  All the algorithms try to find a minimizing partition of
+ *	  ||v_i-Pv_i|| where P is a problem-specific projector and v_i denotes
+ *	  the eigenvectors stored in v. The final partition is worked out
+ *	  as decribed in Method 1 of Section 5.4.2.
+ *	  'matrix' provides the type of SCG (i.e. the form of P). So far,
+ *	  the options are those described in section 6, that is:
+ *		1  ->  Symmetric (sec. 6.1)
+ *		2  ->  Laplacian (sec. 6.2)
+ *		3  ->  Stochastic (sec. 6.3)
+ *	  In the stochastic case, a valid distribution probability 'p' must be
+ *	  provided. In all other cases, 'p' is ignored and can be set to NULL.
+ *	  The group labels in the final partition are given in 'gr' as positive
+ *	  consecutive integers starting from 0.
+ */
+
+#include "igraph_scg.h"
+#include "igraph_eigen.h"
+#include "igraph_interface.h"
+#include "igraph_structural.h"
+#include "igraph_constructors.h"
+#include "igraph_conversion.h"
+#include "igraph_memory.h"
+
+#include "scg_headers.h"
+
+#include "math.h"
+
+/**
+ * \section about_scg
+ * 
+ * <para>
+ * The SCG functions provide a framework, called Spectral Coarse Graining
+ * (SCG), for reducing large graphs while preserving their
+ * <emphasis>spectral-related features</emphasis>, 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).
+ * </para>
+ * 
+ * <para>
+ * 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).
+ * </para>
+ * 
+ * <para>
+ * SCG differs from traditional clustering schemes by producing a
+ * <emphasis>coarse-grained graph</emphasis> (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 <emphasis>exact SCG</emphasis>, where the matrix to be
+ * coarse-grained is the covariance matrix of some data set. 
+ * </para>
+ * 
+ * <para>
+ * 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.
+ * </para>
+ *
+ * <section><title>SCG in brief</title>
+ * <para>
+ * The main idea of SCG is to operate on a matrix a shrinkage operation
+ * specifically designed to preserve some of the matrix eigenpairs while
+ * not altering other important matrix features (such as its structure). 
+ * Mathematically, this idea was expressed as follows. Consider a
+ * (complex) n x n matrix M and form the product
+ * <blockquote><para><phrase role="math">
+ *   M'=LMR*,
+ * </phrase></para></blockquote>
+ * where n' < n and L, R are from C[n'xn]} and are such
+ * that LR*=I[n'] (R* denotes the conjugate transpose of R). Under
+ * these assumptions, it can be shown that P=R*L is an n'-rank
+ * projector and that, if (lambda, v) is a (right) 
+ * eigenpair of M (i.e. Mv=lambda v} and P is orthogonal, there exists
+ * an eigenvalue lambda' of M' such that 
+ * <blockquote><para><phrase role="math">
+ *   |lambda-lambda'| <= const ||e[P](v)|| 
+ *   [1+O(||e[P](v)||<superscript>2</superscript>)],
+ * </phrase></para></blockquote>
+ * where ||e[P](v)||=||v-Pv||. Hence, if P (or equivalently
+ * L, R) is chosen so as to make ||e[P](v)|| as small as possible, one
+ * can preserve to any desired level the original eigenvalue
+ * lambda in the coarse-grained matrix M';
+ * under extra assumptions on M, this result can be generalized to
+ * eigenvectors [1]. This leads to the following generic definition of a
+ * SCG problem.
+ * </para>
+ * 
+ * <para>
+ * Given M (C[nxn]) and (lambda, v), a (right) eigenpair of M to be
+ * preserved by the coarse graining, the problem is to find a projector
+ * P' solving
+ * <blockquote><para><phrase role="math">
+ *   min(||e[P](v)||, p in Omega),
+ * </phrase></para></blockquote>
+ * where Omega is a set of projectors in C[nxn] described by some 
+ * ad hoc constraints c[1], ..., c[r]
+ * (e.g. c[1]: P in R[nxn], c[2]: P=t(P), c[3]: P[i,j] >= 0}, etc).
+ * </para>
+ * 
+ * <para>
+ * 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
+ * P'=vv* (v is assumed normalized). We have designed a particular
+ * constraint, called <emphasis>homogeneous mixing</emphasis>, 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 1, ..., n (labeling the original vertices)
+ * minimizing 
+ * <blockquote><para><phrase role="math">
+ *   ||e[P](v)||<superscript>2</superscript> =
+ *   sum([v(i)-(Pv)(i)]<superscript>2</superscript>; 
+ *   alpha=1,...,n', i in alpha),
+ * </phrase></para></blockquote>
+ * where alpha denotes a group (i.e. a block) in a partition of
+ * {1, ..., n}, and |alpha| is the number of elements in alpha.
+ * </para>
+ * 
+ * <para>
+ * If M is symmetric or stochastic, for instance, then it may be
+ * desirable (or mandatory) to choose L, R so that M' is symmetric or
+ * stochastic as well. This <emphasis>structural constraint</emphasis>
+ * has led to the construction of particular semi-projectors for
+ * symmetric [1], stochastic [3] and Laplacian [2] matrices, that are
+ * made available.
+ * </para>
+ * 
+ * <para>
+ * In short, the coarse graining of matrices and graphs involves: 
+ * \olist
+ *   \oli Retrieving a matrix or a graph matrix M from the
+ *     problem. 
+ *   \oli Computing the eigenpairs of M to be preserved in the
+ *     coarse-grained graph or matrix. 
+ *   \oli Setting some problem-specific constraints (e.g. dimension of
+ *     the coarse-grained object). 
+ *   \oli Solving the constrained SCG problem, that is finding P'.
+ *   \oli Computing from P' two semi-projectors L' and R'
+ *     (e.g. following the method proposed in [1]). 
+ *   \oli Working out the product M'=L'MR'* and, if needed, defining
+ *     from M' a coarse-grained graph. 
+ * \endolist
+ * </para>
+ * </section>
+ * 
+ * <section><title>Functions for performing SCG</title>
+ * <para>
+ * The main functions are \ref igraph_scg_adjacency(), \ref
+ * igraph_scg_laplacian() and \ref igraph_scg_stochastic().
+ * These functions handle 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,
+ * they compute some prescribed eigenpairs of a matrix or a
+ * graph matrix, (for now adjacency, Laplacian and stochastic matrices are
+ * available), work out an optimal partition to preserve the eigenpairs,
+ * and finally output a coarse-grained matrix or graph along with other
+ * useful information. 
+ * </para>
+ * 
+ * <para>
+ * These steps can also be carried out independently: (1) Use
+ * \ref igraph_get_adjacency(), \ref igraph_get_sparsemat(), 
+ * \ref igraph_laplacian(), \ref igraph_get_stochastic() or \ref
+ * igraph_get_stochastic_sparsemat() to compute a matrix M. 
+ * (2) Work out some prescribed eigenpairs of M e.g. by 
+ * means of \ref igraph_arpack_rssolve() or \ref
+ * igraph_arpack_rnsolve(). (3) Invoke one the four
+ * algorithms of the function \ref igraph_scg_grouping() to get a
+ * partition that will preserve the eigenpairs in the coarse-grained
+ * matrix. (4) Compute the semi-projectors L and R using
+ * \ref igraph_scg_semiprojectors() and from there the coarse-grained
+ * matrix M'=LMR*. If necessary, construct a coarse-grained graph from
+ * M' (e.g. as in [1]).
+ * </para>
+ * </section>
+ * 
+ * <section><title>References</title>
+ * <para>
+ * [1] 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 
+ * <emphasis>SIAM Journal on Matrix Analysis and
+ * Applications</emphasis>, 2008.
+ * http://people.epfl.ch/david.morton
+ * </para>
+ * <para>
+ * [2] D. Gfeller, and P. De Los Rios, Spectral Coarse Graining and
+ * Synchronization in Oscillator Networks. 
+ * <emphasis>Physical Review Letters</emphasis>, 
+ * <emphasis role="strong">100</emphasis>(17), 2008. 
+ * http://arxiv.org/abs/0708.2055
+ * </para>
+ * <para>
+ * [3] D. Gfeller, and P. De Los Rios, Spectral Coarse Graining of Complex
+ * Networks, <emphasis>Physical Review Letters</emphasis>,
+ * <emphasis role="strong">99</emphasis>(3), 2007.
+ * http://arxiv.org/abs/0706.0812
+ * </para>
+ * </section>
+ */
+
+/**
+ * \function igraph_scg_grouping
+ * \brief SCG problem solver
+ * 
+ * This function solves the Spectral Coarse Graining (SCG) problem;
+ * either exactly, or approximately but faster.
+ * 
+ * </para><para>
+ * The algorithm \c IGRAPH_SCG_OPTIMUM solves exactly the SCG problem
+ * for each eigenvector in \p V. The running time of this algorithm is
+ * O(max(nt) m^2) for the symmetric and laplacian matrix problems
+ * It is O(m^3) for the stochastic problem. Here m is the number
+ * of rows in \p V. In all three cases, the memory usage is O(m^2).
+ * 
+ * </para><para>
+ * The algorithms \c IGRAPH_SCG_INTERV and \c IGRAPH_SCG_INTERV_KM solve
+ * approximately the SCG problem by performing a (for now) constant
+ * binning of the components of the eigenvectors, that is \p nt 
+ * <code>VECTOR(nt_vec)[i]</code>) constant-size bins are used to
+ * partition <code>V[,i]</code>. When \p algo is \c
+ * IGRAPH_SCG_INTERV_KM, the (Lloyd) k-means algorithm is
+ * run on each partition obtained by \c IGRAPH_SCG_INTERV to improve
+ * accuracy. 
+ * 
+ * </para><para>
+ * 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 the number
+ * of columns in \p V is larger than one.
+ * 
+ * </para><para>
+ * Finally, the algorithm \c IGRAPH_SCG_EXACT groups the vertices with
+ * equal components in each eigenvector. The last three algorithms
+ * essentially have linear running time and memory load.
+ * 
+ * \param V The matrix of eigenvectors to be preserved by coarse
+ *    graining, each column is an eigenvector.
+ * \param groups Pointer to an initialized vector, the result of the
+ *    SCG is stored here.
+ * \param nt Positive integer. When \p algo is \c IGRAPH_SCG_OPTIMUM,
+ *    it gives the number of groups to partition each eigenvector
+ *    separately. When \p algo is \c IGRAPH_SCG_INTERV or \c
+ *    IGRAPH_SCG_INTERV_KM, it gives the number of intervals to
+ *    partition each eigenvector. This is ignored when \p algo is \c
+ *    IGRAPH_SCG_EXACT.
+ * \param nt_vec A numeric vector of length one or the length must
+ *    match the number of eigenvectors given in \p V, or a \c NULL
+ *    pointer. If not \c NULL, then this argument gives the number of
+ *    groups or intervals, and \p nt is ignored. Different number of
+ *    groups or intervals can be specified for each eigenvector.
+ * \param mtype The type of semi-projectors used in the SCG. Possible
+ *    values are \c IGRAPH_SCG_SYMMETRIC, \c IGRAPH_SCG_STOCHASTIC and
+ *    \c IGRAPH_SCG_LAPLACIAN.
+ * \param algo The algorithm to solve the SCG problem. Possible
+ *    values: \c IGRAPH_SCG_OPTIMUM, \c IGRAPH_SCG_INTERV_KM, \c
+ *    IGRAPH_SCG_INTERV and \c IGRAPH_SCG_EXACT. Please see the
+ *    details about them above.
+ * \param p A probability vector, or \c NULL. This argument must be
+ *    given if \p mtype is \c IGRAPH_SCG_STOCHASTIC, but it is ignored
+ *    otherwise. For the stochastic case it gives the stationary
+ *    probability distribution of a Markov chain, the one specified by
+ *    the graph/matrix under study.
+ * \param maxiter A positive integer giving the number of iterations
+ *    of the k-means algorithm when \p algo is \c
+ *    IGRAPH_SCG_INTERV_KM. It is ignored in other cases. A reasonable
+ *    (initial) value for this argument is 100.
+ * \return Error code.
+ * 
+ * Time complexity: see description above.
+ * 
+ * \sa \ref igraph_scg_adjacency(), \ref igraph_scg_laplacian(), \ref
+ * igraph_scg_stochastic().
+ * 
+ * \example examples/simple/igraph_scg_grouping.c
+ * \example examples/simple/igraph_scg_grouping2.c
+ * \example examples/simple/igraph_scg_grouping3.c
+ * \example examples/simple/igraph_scg_grouping4.c
+ */
+
+int igraph_scg_grouping(const igraph_matrix_t *V, 
+			igraph_vector_t *groups,
+			igraph_integer_t nt,
+			const igraph_vector_t *nt_vec,
+			igraph_scg_matrix_t mtype,
+			igraph_scg_algorithm_t algo,
+			const igraph_vector_t *p,
+			igraph_integer_t maxiter) {
+
+  int no_of_nodes=(int) igraph_matrix_nrow(V);
+  int nev=(int) igraph_matrix_ncol(V);
+  igraph_matrix_int_t gr_mat;
+  int i;
+
+  if (nt_vec && igraph_vector_size(nt_vec) != 1 && 
+      igraph_vector_size(nt_vec) != nev) {
+    IGRAPH_ERROR("Invalid length for interval specification", IGRAPH_EINVAL);
+  }
+  if (nt_vec && igraph_vector_size(nt_vec) == 1) {
+    nt=(igraph_integer_t) VECTOR(*nt_vec)[0];
+    nt_vec=0;
+  }
+
+  if (!nt_vec && algo != IGRAPH_SCG_EXACT) {
+    if (nt <= 1 || nt >= no_of_nodes) {
+      IGRAPH_ERROR("Invalid interval specification", IGRAPH_EINVAL);
+    }
+  } else if (algo != IGRAPH_SCG_EXACT) {
+    igraph_real_t min, max;
+    igraph_vector_minmax(nt_vec, &min, &max);
+    if (min <= 1 || max >= no_of_nodes) {
+      IGRAPH_ERROR("Invalid interval specification", IGRAPH_EINVAL);
+    }
+  }
+
+  if (mtype == IGRAPH_SCG_STOCHASTIC && !p) {
+    IGRAPH_ERROR("`p' must be given for the stochastic matrix case", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (p && igraph_vector_size(p) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `p' vector size", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(groups, no_of_nodes));
+
+#define INVEC(i) (nt_vec ? VECTOR(*nt_vec)[i] : nt)
+
+  IGRAPH_CHECK(igraph_matrix_int_init(&gr_mat, no_of_nodes, nev));
+  IGRAPH_FINALLY(igraph_matrix_int_destroy, &gr_mat);
+
+  switch (algo) {
+  case IGRAPH_SCG_OPTIMUM:
+    for (i=0; i<nev; i++) {
+      IGRAPH_CHECK(igraph_i_optimal_partition(&MATRIX(*V, 0, i), 
+					      &MATRIX(gr_mat, 0, i), 
+					      no_of_nodes, (int) INVEC(i),
+					      mtype, 
+					      p ? VECTOR(*p) : 0, 0));
+    }
+    break;
+  case IGRAPH_SCG_INTERV_KM:
+    for (i=0; i<nev; i++) {
+      igraph_vector_t tmpv;
+      igraph_vector_view(&tmpv, &MATRIX(*V, 0, i), no_of_nodes);
+      IGRAPH_CHECK(igraph_i_intervals_plus_kmeans(&tmpv,
+						  &MATRIX(gr_mat, 0, i),
+						  no_of_nodes, (int) INVEC(i),
+						  maxiter));
+    }
+    break;
+  case IGRAPH_SCG_INTERV:
+    for (i=0; i<nev; i++) {
+      igraph_vector_t tmpv;
+      igraph_vector_view(&tmpv, &MATRIX(*V, 0, i), no_of_nodes);
+      IGRAPH_CHECK(igraph_i_intervals_method(&tmpv,
+					     &MATRIX(gr_mat, 0, i),
+					     no_of_nodes, (int) INVEC(i)));
+    }
+    break;
+  case IGRAPH_SCG_EXACT:
+    for (i=0; i<nev; i++) {
+      IGRAPH_CHECK(igraph_i_exact_coarse_graining(&MATRIX(*V, 0, i),
+						  &MATRIX(gr_mat, 0, i),
+						  no_of_nodes));
+    }
+    break;
+  }
+
+#undef INVEC
+
+  if (nev==1) {
+    for (i=0; i<no_of_nodes; i++) {
+      VECTOR(*groups)[i] = MATRIX(gr_mat, i, 0);
+    }
+  } else {
+    igraph_i_scg_groups_t *g = igraph_Calloc(no_of_nodes, 
+					     igraph_i_scg_groups_t);
+    int gr_nb=0;
+
+    IGRAPH_CHECK(igraph_matrix_int_transpose(&gr_mat));
+    for(i=0; i<no_of_nodes; i++){
+      g[i].ind = i;
+      g[i].n = nev;
+      g[i].gr = &MATRIX(gr_mat, 0, i);
+    }
+		
+    qsort(g, (size_t) no_of_nodes, sizeof(igraph_i_scg_groups_t), 
+	  igraph_i_compare_groups);
+    VECTOR(*groups)[g[0].ind] = gr_nb;
+    for(i=1; i<no_of_nodes; i++){
+      if(igraph_i_compare_groups(&g[i], &g[i-1]) != 0) gr_nb++;
+      VECTOR(*groups)[g[i].ind] = gr_nb;
+    }
+    igraph_Free(g);
+  }
+
+  igraph_matrix_int_destroy(&gr_mat);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_scg_semiprojectors_sym(const igraph_vector_t *groups,
+				    igraph_matrix_t *L,
+				    igraph_matrix_t *R,
+				    igraph_sparsemat_t *Lsparse,
+				    igraph_sparsemat_t *Rsparse,
+				    int no_of_groups,
+				    int no_of_nodes) {
+
+  igraph_vector_t tab;
+  int i;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tab, no_of_groups);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(tab)[ (int) VECTOR(*groups)[i] ] += 1;
+  }
+  for (i=0; i<no_of_groups; i++) {
+    VECTOR(tab)[i] = sqrt(VECTOR(tab)[i]);
+  }
+  
+  if (L) { 
+    IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));
+    igraph_matrix_null(L);
+    for (i=0; i<no_of_nodes; i++) {
+      int g=(int) VECTOR(*groups)[i];
+      MATRIX(*L, g, i) = 1/VECTOR(tab)[g];
+    }
+  }
+  
+  if (R) {
+    if (L) { 
+      IGRAPH_CHECK(igraph_matrix_update(R, L));
+    } else {
+      IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));
+      igraph_matrix_null(R);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*R, g, i) = 1/VECTOR(tab)[g];
+      }
+    }
+  }
+  
+  if (Lsparse) {
+    IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes, 
+					 /* nzmax= */ no_of_nodes));
+    for (i=0; i<no_of_nodes; i++) {
+      int g=(int) VECTOR(*groups)[i];
+      IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 1/VECTOR(tab)[g]));
+    }
+  }
+  
+  if (Rsparse) {
+    IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,
+					 /* nzmax= */ no_of_nodes));
+    for (i=0; i<no_of_nodes; i++) {
+      int g=(int) VECTOR(*groups)[i];
+      IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 1/VECTOR(tab)[g]));
+    }    
+  }
+
+  igraph_vector_destroy(&tab);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_scg_semiprojectors_lap(const igraph_vector_t *groups,
+				    igraph_matrix_t *L,
+				    igraph_matrix_t *R,
+				    igraph_sparsemat_t *Lsparse,
+				    igraph_sparsemat_t *Rsparse,
+				    int no_of_groups,
+				    int no_of_nodes,
+				    igraph_scg_norm_t norm) {
+  
+  igraph_vector_t tab;
+  int i;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tab, no_of_groups);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(tab)[ (int) VECTOR(*groups)[i] ] += 1;
+  }
+  for (i=0; i<no_of_groups; i++) {
+    VECTOR(tab)[i] = VECTOR(tab)[i];
+  }
+
+  if (norm == IGRAPH_SCG_NORM_ROW) {
+    if (L) {
+      IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));
+      igraph_matrix_null(L);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*L, g, i) = 1.0 / VECTOR(tab)[g];
+      }
+    }
+    if (R) {
+      IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));
+      igraph_matrix_null(R);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*R, g, i) = 1.0;
+      }
+    }
+    if (Lsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,
+					 /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 
+					    1.0 / VECTOR(tab)[g]));
+      }
+    }
+    if (Rsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,
+					   /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 1.0));
+      }
+    }
+  } else {
+    if (L) {
+      IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));
+      igraph_matrix_null(L);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*L, g, i) = 1.0;
+      }
+    }
+    if (R) {
+      IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));
+      igraph_matrix_null(R);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*R, g, i) = 1.0 / VECTOR(tab)[g];
+      }
+    }
+    if (Lsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,
+					 /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 1.0));
+      }
+    }
+    if (Rsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,
+					 /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 
+					    1.0 / VECTOR(tab)[g]));
+      }
+    }
+    
+  }
+
+  igraph_vector_destroy(&tab);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_scg_semiprojectors_sto(const igraph_vector_t *groups,
+				    igraph_matrix_t *L,
+				    igraph_matrix_t *R,
+				    igraph_sparsemat_t *Lsparse,
+				    igraph_sparsemat_t *Rsparse,
+				    int no_of_groups,
+				    int no_of_nodes,
+				    const igraph_vector_t *p,
+				    igraph_scg_norm_t norm) {
+  
+  igraph_vector_t pgr, pnormed;
+  int i;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&pgr, no_of_groups);
+  IGRAPH_VECTOR_INIT_FINALLY(&pnormed, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    int g=(int) VECTOR(*groups)[i];
+    VECTOR(pgr)[g] += VECTOR(*p)[i];
+  }
+  for (i=0; i<no_of_nodes; i++) {
+    int g=(int) VECTOR(*groups)[i];
+    VECTOR(pnormed)[i] = VECTOR(*p)[i] / VECTOR(pgr)[g];
+  }
+  
+  if (norm == IGRAPH_SCG_NORM_ROW) {
+    if (L) {
+      IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));
+      igraph_matrix_null(L);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*L, g, i) = VECTOR(pnormed)[i];
+      }
+    }
+    if (R) {
+      IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));
+      igraph_matrix_null(R);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*R, g, i) = 1.0;
+      }      
+    }
+    if (Lsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,
+					 /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i,
+					    VECTOR(pnormed)[i]));
+      }
+    }
+    if (Rsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,
+					 /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 1.0));
+      }
+    }
+  } else {
+    if (L) {
+      IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));
+      igraph_matrix_null(L);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int ) VECTOR(*groups)[i];
+	MATRIX(*L, g, i) = 1.0;
+      }
+    }
+    if (R) {
+      IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));
+      igraph_matrix_null(R);
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	MATRIX(*R, g, i) = VECTOR(pnormed)[i];
+      }      
+    }
+    if (Lsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,
+					   /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 1.0));
+      }
+    }
+    if (Rsparse) {
+      IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,
+					   /* nzmax= */ no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	int g=(int) VECTOR(*groups)[i];
+	IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i,
+					    VECTOR(pnormed)[i]));
+      }
+    }
+  }
+  
+  
+  igraph_vector_destroy(&pnormed);
+  igraph_vector_destroy(&pgr);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_scg_semiprojectors
+ * \brief Compute SCG semi-projectors for a given partition
+ * 
+ * The three types of semi-projectors are defined as follows.
+ * Let gamma(j) label the group of vertex j in a partition of all the
+ * vertices.
+ *
+ * </para><para>
+ * The symmetric semi-projectors are defined as
+ * <blockquote><para><phrase role="math">
+ *   L[alpha,j] = R[alpha,j] = 1/sqrt(|alpha|) delta[alpha,gamma(j)],
+ * </phrase></para></blockquote>
+ * the (row) Laplacian semi-projectors as
+ * <blockquote><para><phrase role="math">
+ *   L[alpha,j] = 1/|alpha| delta[alpha,gamma(j)]
+ * </phrase></para></blockquote>
+ * and
+ * <blockquote><para><phrase role="math">
+ *   R[alpha,j] = delta[alpha,gamma(j)],
+ * </phrase></para></blockquote>
+ * and the (row) stochastic semi-projectors as
+ * <blockquote><para><phrase role="math">
+ *     L[alpha,j] = p[1][j] / sum(p[1][k]; k in gamma(j))
+ *     delta[alpha,gamma(j)]
+ * </phrase></para></blockquote>
+ * and
+ * <blockquote><para><phrase role="math">
+ *     R[alpha,j] = delta[alpha,gamma(j)],
+ * </phrase></para></blockquote>
+ * where p[1] is the (left) eigenvector associated with the
+ * one-eigenvalue of the stochastic matrix. L and R are
+ * defined in a symmetric way when \p norm is \c
+ * IGRAPH_SCG_NORM_COL. All these semi-projectors verify various
+ * properties described in the reference.
+ * \param groups A vector of integers, giving the group label of every
+ *    vertex in the partition. Group labels should start at zero and
+ *    should be sequential.
+ * \param mtype The type of semi-projectors. For now \c
+ *    IGRAPH_SCG_SYMMETRIC, \c IGRAPH_SCG_STOCHASTIC and \c
+ *    IGRAP_SCG_LAPLACIAN are supported.
+ * \param L If not a \c NULL pointer, then it must be a pointer to
+ *    an initialized matrix. The left semi-projector is stored here.
+ * \param R If not a \c NULL pointer, then it must be a pointer to
+ *    an initialized matrix. The right semi-projector is stored here.
+ * \param Lsparse If not a \c NULL pointer, then it must be a pointer
+ *    to an uninitialized sparse matrix. The left semi-projector is
+ *    stored here.
+ * \param Rsparse If not a \c NULL pointer, then it must be a pointer
+ *    to an uninitialized sparse matrix. The right semi-projector is
+ *    stored here.
+ * \param p \c NULL, or a probability vector of the same length as \p
+ *    groups. \p p is the stationary probability distribution of a
+ *    Markov chain when \p mtype is \c IGRAPH_SCG_STOCHASTIC. This
+ *    argument is ignored in all other cases.
+ * \param norm Either \c IGRAPH_SCG_NORM_ROW or \c IGRAPH_SCG_NORM_COL. 
+ *    Specifies whether the rows or the columns of the Laplacian
+ *    matrix sum up to zero, or whether the rows or the columns of the
+ *    stochastic matrix sum up to one.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \sa \ref igraph_scg_adjacency(), \ref igraph_scg_stochastic() and
+ * \ref igraph_scg_laplacian(), \ref igraph_scg_grouping().
+ * 
+ * \example examples/simple/igraph_scg_semiprojectors.c
+ * \example examples/simple/igraph_scg_semiprojectors2.c
+ * \example examples/simple/igraph_scg_semiprojectors3.c
+ */
+
+int igraph_scg_semiprojectors(const igraph_vector_t *groups,
+			      igraph_scg_matrix_t mtype,
+			      igraph_matrix_t *L,
+			      igraph_matrix_t *R,
+			      igraph_sparsemat_t *Lsparse,
+			      igraph_sparsemat_t *Rsparse, 
+			      const igraph_vector_t *p,
+			      igraph_scg_norm_t norm) {
+  
+  int no_of_nodes=(int) igraph_vector_size(groups);
+  int no_of_groups;
+  igraph_real_t min, max;
+
+  igraph_vector_minmax(groups, &min, &max);
+  no_of_groups=(int) max+1;
+
+  if (min < 0 || max >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid membership vector", IGRAPH_EINVAL);
+  }
+
+  if (mtype == IGRAPH_SCG_STOCHASTIC && !p) {
+    IGRAPH_ERROR("`p' must be given for the stochastic matrix case", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (p && igraph_vector_size(p) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `p' vector length, should match number of vertices",
+		 IGRAPH_EINVAL);
+  }
+
+  switch (mtype) {
+  case IGRAPH_SCG_SYMMETRIC:
+    IGRAPH_CHECK(igraph_i_scg_semiprojectors_sym(groups, L, R, Lsparse, 
+						 Rsparse, no_of_groups,
+						 no_of_nodes));
+    break;
+
+  case IGRAPH_SCG_LAPLACIAN:
+    IGRAPH_CHECK(igraph_i_scg_semiprojectors_lap(groups, L, R, Lsparse, 
+						 Rsparse, no_of_groups,
+						 no_of_nodes, norm));
+    break;
+
+  case IGRAPH_SCG_STOCHASTIC:
+    IGRAPH_CHECK(igraph_i_scg_semiprojectors_sto(groups, L, R, Lsparse,
+						 Rsparse, no_of_groups,
+						 no_of_nodes, p, norm));
+    break;    
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_scg_norm_eps
+ * Calculate SCG residuals
+ * 
+ * Computes |v[i]-Pv[i]|, where v[i] is the i-th eigenvector in \p V
+ * and P is the projector corresponding to the \p mtype argument.
+ * 
+ * \param V The matrix of eigenvectors to be preserved by coarse
+ *    graining, each column is an eigenvector.
+ * \param groups A vector of integers, giving the group label of every
+ *    vertex in the partition. Group labels should start at zero and
+ *    should be sequential.
+ * \param eps Pointer to a real value, the result is stored here.
+ * \param mtype The type of semi-projectors. For now \c
+ *    IGRAPH_SCG_SYMMETRIC, \c IGRAPH_SCG_STOCHASTIC and \c
+ *    IGRAP_SCG_LAPLACIAN are supported.
+ * \param p \c NULL, or a probability vector of the same length as \p
+ *    groups. \p p is the stationary probability distribution of a
+ *    Markov chain when \p mtype is \c IGRAPH_SCG_STOCHASTIC. This
+ *    argument is ignored in all other cases.
+ * \param norm Either \c IGRAPH_SCG_NORM_ROW or \c IGRAPH_SCG_NORM_COL. 
+ *    Specifies whether the rows or the columns of the Laplacian
+ *    matrix sum up to zero, or whether the rows or the columns of the
+ *    stochastic matrix sum up to one.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \sa \ref igraph_scg_adjacency(), \ref igraph_scg_stochastic() and
+ * \ref igraph_scg_laplacian(), \ref igraph_scg_grouping(), \ref
+ * igraph_scg_semiprojectors().
+ */
+
+int igraph_scg_norm_eps(const igraph_matrix_t *V,
+			const igraph_vector_t *groups,
+			igraph_vector_t *eps,
+			igraph_scg_matrix_t mtype,
+			const igraph_vector_t *p,
+			igraph_scg_norm_t norm) {
+
+  int no_of_nodes=(int) igraph_vector_size(groups);
+  int no_of_groups;
+  int no_of_vectors=(int) igraph_matrix_ncol(V);
+  igraph_real_t min, max;
+  igraph_sparsemat_t Lsparse, Rsparse, Lsparse2, Rsparse2, Rsparse3, proj;
+  igraph_vector_t x, res;
+  int k, i;
+  
+  if (igraph_matrix_nrow(V) != no_of_nodes) {
+    IGRAPH_ERROR("Eigenvector length and group vector length do not match",
+		 IGRAPH_EINVAL);
+  }
+
+  igraph_vector_minmax(groups, &min, &max);
+  no_of_groups=(int) max+1;
+  
+  if (min < 0 || max >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid membership vector", IGRAPH_EINVAL);
+  }
+
+  if (mtype == IGRAPH_SCG_STOCHASTIC && !p) {
+    IGRAPH_ERROR("`p' must be given for the stochastic matrix case", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (p && igraph_vector_size(p) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `p' vector length, should match number of vertices",
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_scg_semiprojectors(groups, mtype, /* L= */ 0, 
+					 /* R= */ 0, &Lsparse, &Rsparse, p,
+					 norm));
+
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Lsparse);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse);
+
+  IGRAPH_CHECK(igraph_sparsemat_compress(&Lsparse, &Lsparse2));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Lsparse2);
+  IGRAPH_CHECK(igraph_sparsemat_compress(&Rsparse, &Rsparse2));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse2);
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&Rsparse2, &Rsparse3, 
+					  /*values=*/ 1));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse3);
+  
+  IGRAPH_CHECK(igraph_sparsemat_multiply(&Rsparse3, &Lsparse2, &proj));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &proj);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&res, no_of_nodes);
+  IGRAPH_CHECK(igraph_vector_resize(eps, no_of_vectors));
+  
+  for (k = 0; k < no_of_vectors; k++) {
+    igraph_vector_view(&x, &MATRIX(*V, 0, k), no_of_nodes);
+    igraph_vector_null(&res);
+    IGRAPH_CHECK(igraph_sparsemat_gaxpy(&proj, &x, &res));
+    VECTOR(*eps)[k] = 0.0;
+    for (i = 0; i < no_of_nodes; i++) {
+      igraph_real_t di=MATRIX(*V, i, k) - VECTOR(res)[i];
+      VECTOR(*eps)[k] += di * di;
+    }
+    VECTOR(*eps)[k] = sqrt(VECTOR(*eps)[k]);
+  }
+
+  igraph_vector_destroy(&res);
+  igraph_sparsemat_destroy(&proj);
+  igraph_sparsemat_destroy(&Rsparse3);
+  igraph_sparsemat_destroy(&Rsparse2);
+  igraph_sparsemat_destroy(&Lsparse2);
+  igraph_sparsemat_destroy(&Rsparse);
+  igraph_sparsemat_destroy(&Lsparse);
+  IGRAPH_FINALLY_CLEAN(7);
+
+  return 0;
+}
+
+int igraph_i_matrix_laplacian(const igraph_matrix_t *matrix, 
+			      igraph_matrix_t *mymatrix, 
+			      igraph_scg_norm_t norm) {
+
+  igraph_vector_t degree;
+  int i, j, n=(int) igraph_matrix_nrow(matrix);
+  IGRAPH_CHECK(igraph_matrix_resize(mymatrix, n, n));
+
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, n);  
+
+  if (norm==IGRAPH_SCG_NORM_ROW) { 
+    IGRAPH_CHECK(igraph_matrix_rowsum(matrix, &degree));
+  } else {
+    IGRAPH_CHECK(igraph_matrix_colsum(matrix, &degree));
+  }
+  for (i=0; i<n; i++) {
+    VECTOR(degree)[i] -= MATRIX(*matrix, i, i);
+  }
+
+  for (i=0; i<n; i++) {
+    for (j=0; j<n; j++) {
+      MATRIX(*mymatrix, i, j) = - MATRIX(*matrix, i, j);
+    }
+    MATRIX(*mymatrix, i, i) = VECTOR(degree)[i];
+  }
+  
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_sparsemat_laplacian(const igraph_sparsemat_t *sparse,
+				 igraph_sparsemat_t *mysparse,
+				 igraph_scg_norm_t norm) {
+
+  igraph_vector_t degree;
+  int i, n=(int) igraph_sparsemat_nrow(sparse);
+  int nzmax=igraph_sparsemat_nzmax(sparse);
+  igraph_sparsemat_iterator_t it;
+
+  IGRAPH_CHECK(igraph_sparsemat_init(mysparse, n, n, nzmax+n));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparse);
+  igraph_sparsemat_iterator_init(&it, (igraph_sparsemat_t *) sparse);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, n);  
+  for (igraph_sparsemat_iterator_reset(&it); 
+       !igraph_sparsemat_iterator_end(&it);
+       igraph_sparsemat_iterator_next(&it)) {
+    int row=igraph_sparsemat_iterator_row(&it);
+    int col=igraph_sparsemat_iterator_col(&it);
+    if (row != col) { 
+      igraph_real_t val=igraph_sparsemat_iterator_get(&it);
+      if (norm == IGRAPH_SCG_NORM_ROW) {
+	VECTOR(degree)[row] += val;
+      } else {
+	VECTOR(degree)[col] += val;
+      }
+    }
+  }
+
+  /* Diagonal */
+  for (i=0; i<n; i++) {
+    igraph_sparsemat_entry(mysparse, i, i, VECTOR(degree)[i]);
+  }
+
+  /* And the rest, filter out diagonal elements */
+  for (igraph_sparsemat_iterator_reset(&it); 
+       !igraph_sparsemat_iterator_end(&it);
+       igraph_sparsemat_iterator_next(&it)) {
+    int row=igraph_sparsemat_iterator_row(&it);
+    int col=igraph_sparsemat_iterator_col(&it);
+    if (row != col) { 
+      igraph_real_t val=igraph_sparsemat_iterator_get(&it);
+      igraph_sparsemat_entry(mysparse, row, col, -val);
+    }
+  }
+
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(2); 	/* + mysparse */
+  
+  return 0;
+}
+
+int igraph_i_matrix_stochastic(const igraph_matrix_t *matrix, 
+			       igraph_matrix_t *mymatrix, 
+			       igraph_scg_norm_t norm) {
+
+  int i, j, n=(int) igraph_matrix_nrow(matrix);
+  IGRAPH_CHECK(igraph_matrix_copy(mymatrix, matrix));
+
+  if (norm==IGRAPH_SCG_NORM_ROW){
+    for (i=0; i<n; i++) {
+      igraph_real_t sum=0.0;
+      for (j=0; j<n; j++) {
+	sum += MATRIX(*matrix, i, j);
+      }
+      if (sum == 0) { IGRAPH_WARNING("Zero degree vertices"); }
+      for (j=0; j<n; j++) {
+	MATRIX(*mymatrix, i, j) = MATRIX(*matrix, i, j) / sum;
+      }
+    }
+  } else {
+    for (i=0; i<n; i++) {
+      igraph_real_t sum=0.0;
+      for (j=0; j<n; j++) {
+	sum += MATRIX(*matrix, j, i);
+      }
+      if (sum == 0) { IGRAPH_WARNING("Zero degree vertices"); }
+      for (j=0; j<n; j++) {
+	MATRIX(*mymatrix, j, i) = MATRIX(*matrix, j, i) / sum;
+      }
+    }    
+  }	
+
+  return 0;
+}
+
+int igraph_i_normalize_sparsemat(igraph_sparsemat_t *sparsemat, 
+				 igraph_bool_t column_wise);
+
+int igraph_i_sparsemat_stochastic(const igraph_sparsemat_t *sparse,
+				  igraph_sparsemat_t *mysparse,
+				  igraph_scg_norm_t norm) {
+  
+  IGRAPH_CHECK(igraph_sparsemat_copy(mysparse, sparse));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparse);
+  IGRAPH_CHECK(igraph_i_normalize_sparsemat(mysparse, 
+					    norm==IGRAPH_SCG_NORM_COL));
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_scg_get_result(igraph_scg_matrix_t type,
+			    const igraph_matrix_t *matrix,
+			    const igraph_sparsemat_t *sparsemat,
+			    const igraph_sparsemat_t *Lsparse,
+			    const igraph_sparsemat_t *Rsparse_t,
+			    igraph_t *scg_graph,
+			    igraph_matrix_t *scg_matrix,
+			    igraph_sparsemat_t *scg_sparsemat, 
+			    igraph_bool_t directed) {
+
+  /* We need to calculate either scg_matrix (if input is dense), or
+     scg_sparsemat (if input is sparse). For the latter we might need
+     to temporarily use another matrix. */
+  
+  
+  if (matrix) {
+    igraph_matrix_t *my_scg_matrix=scg_matrix, v_scg_matrix;
+    igraph_matrix_t tmp;
+    igraph_sparsemat_t *myLsparse=(igraph_sparsemat_t *) Lsparse, v_Lsparse;
+
+    if (!scg_matrix) {
+      my_scg_matrix=&v_scg_matrix;
+      IGRAPH_CHECK(igraph_matrix_init(my_scg_matrix, 0, 0));
+      IGRAPH_FINALLY(igraph_matrix_destroy, my_scg_matrix);
+    }
+
+    if (!igraph_sparsemat_is_cc(Lsparse)) {
+      myLsparse=&v_Lsparse;
+      IGRAPH_CHECK(igraph_sparsemat_compress(Lsparse, myLsparse));
+      IGRAPH_FINALLY(igraph_sparsemat_destroy, myLsparse);
+    }
+
+    IGRAPH_CHECK(igraph_matrix_init(&tmp, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &tmp);
+    IGRAPH_CHECK(igraph_sparsemat_dense_multiply(matrix, Rsparse_t, &tmp));
+    IGRAPH_CHECK(igraph_sparsemat_multiply_by_dense(myLsparse, &tmp, 
+						    my_scg_matrix));
+    igraph_matrix_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    if (scg_sparsemat) {
+      IGRAPH_CHECK(igraph_matrix_as_sparsemat(scg_sparsemat, my_scg_matrix,
+					      /* tol= */ 0));
+      IGRAPH_FINALLY(igraph_sparsemat_destroy, scg_sparsemat);
+    }
+
+    if (scg_graph) {
+      if (type != IGRAPH_SCG_LAPLACIAN) {
+	IGRAPH_CHECK(igraph_weighted_adjacency(scg_graph, my_scg_matrix, 
+					       directed ? 
+					       IGRAPH_ADJ_DIRECTED : 
+					       IGRAPH_ADJ_UNDIRECTED, 
+					       "weight", /*loops=*/ 1));
+      } else {
+	int i, j, n=(int) igraph_matrix_nrow(my_scg_matrix);
+	igraph_matrix_t tmp;
+	IGRAPH_MATRIX_INIT_FINALLY(&tmp, n, n);
+	for (i=0; i<n; i++) {
+	  for (j=0; j<n; j++) {
+	    MATRIX(tmp, i, j) = -MATRIX(*my_scg_matrix, i, j);
+	  }
+	  MATRIX(tmp, i, i) = 0;
+	}
+	IGRAPH_CHECK(igraph_weighted_adjacency(scg_graph, &tmp, directed ?
+					       IGRAPH_ADJ_DIRECTED :
+					       IGRAPH_ADJ_UNDIRECTED, 
+					       "weight", /*loops=*/ 0));
+	igraph_matrix_destroy(&tmp);
+	IGRAPH_FINALLY_CLEAN(1);
+      }
+      IGRAPH_FINALLY(igraph_destroy, scg_graph);
+    }
+
+    if (scg_graph)     { IGRAPH_FINALLY_CLEAN(1); }
+    if (scg_sparsemat) { IGRAPH_FINALLY_CLEAN(1); }
+
+    if (!igraph_sparsemat_is_cc(Lsparse)) {
+      igraph_sparsemat_destroy(myLsparse);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    if (!scg_matrix) {
+      igraph_matrix_destroy(my_scg_matrix);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+  } else { /* sparsemat */
+    igraph_sparsemat_t *my_scg_sparsemat=scg_sparsemat, v_scg_sparsemat;
+    igraph_sparsemat_t tmp, *mysparsemat=(igraph_sparsemat_t *) sparsemat,
+      v_sparsemat, *myLsparse=(igraph_sparsemat_t *) Lsparse, v_Lsparse;
+    if (!scg_sparsemat) {
+      my_scg_sparsemat=&v_scg_sparsemat;
+    }
+    if (!igraph_sparsemat_is_cc(sparsemat)) {
+      mysparsemat=&v_sparsemat;
+      IGRAPH_CHECK(igraph_sparsemat_compress(sparsemat, mysparsemat));
+      IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparsemat);
+    }
+    if (!igraph_sparsemat_is_cc(Lsparse)) {
+      myLsparse=&v_Lsparse;
+      IGRAPH_CHECK(igraph_sparsemat_compress(Lsparse, myLsparse));
+      IGRAPH_FINALLY(igraph_sparsemat_destroy, myLsparse);
+    }
+    IGRAPH_CHECK(igraph_sparsemat_multiply(mysparsemat, Rsparse_t, 
+					   &tmp));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmp);
+    IGRAPH_CHECK(igraph_sparsemat_multiply(myLsparse, &tmp,
+					   my_scg_sparsemat));
+    igraph_sparsemat_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, my_scg_sparsemat);
+
+    if (scg_matrix) {
+      IGRAPH_CHECK(igraph_sparsemat_as_matrix(scg_matrix, my_scg_sparsemat));
+    }
+    if (scg_graph) {
+      if (type != IGRAPH_SCG_LAPLACIAN) {
+	IGRAPH_CHECK(igraph_weighted_sparsemat(scg_graph, my_scg_sparsemat,
+					       directed, "weight",
+					       /*loops=*/ 1));
+      } else {
+	igraph_sparsemat_t tmp;
+	IGRAPH_CHECK(igraph_sparsemat_copy(&tmp, my_scg_sparsemat));
+	IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmp);
+	IGRAPH_CHECK(igraph_sparsemat_neg(&tmp));
+	IGRAPH_CHECK(igraph_weighted_sparsemat(scg_graph, &tmp, directed, 
+					       "weight", /*loops=*/ 0));
+	igraph_sparsemat_destroy(&tmp);
+	IGRAPH_FINALLY_CLEAN(1);
+      }
+      IGRAPH_FINALLY(igraph_destroy, scg_graph);
+    }
+
+    if (scg_graph) { IGRAPH_FINALLY_CLEAN(1); }
+    if (!scg_sparsemat) {
+      igraph_sparsemat_destroy(my_scg_sparsemat);
+    }
+    IGRAPH_FINALLY_CLEAN(1);	/* my_scg_sparsemat */
+    if (!igraph_sparsemat_is_cc(Lsparse)) {
+      igraph_sparsemat_destroy(myLsparse);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    if (!igraph_sparsemat_is_cc(sparsemat)) {
+      igraph_sparsemat_destroy(mysparsemat);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_scg_common_checks(const igraph_t *graph, 
+			       const igraph_matrix_t *matrix,
+			       const igraph_sparsemat_t *sparsemat,
+			       const igraph_vector_t *ev,
+			       igraph_integer_t nt,
+			       const igraph_vector_t *nt_vec,
+			       const igraph_matrix_t *vectors,
+			       const igraph_matrix_complex_t *vectors_cmplx,
+			       const igraph_vector_t *groups,
+			       const igraph_t *scg_graph,
+			       const igraph_matrix_t *scg_matrix,
+			       const igraph_sparsemat_t *scg_sparsemat,
+			       const igraph_vector_t *p,
+			       igraph_real_t *evmin, igraph_real_t *evmax) {
+
+  int no_of_nodes=-1;
+  igraph_real_t min, max;
+  int no_of_ev=(int) igraph_vector_size(ev);
+
+  if ( (graph?1:0) + (matrix?1:0) + (sparsemat?1:0) != 1 ) {
+    IGRAPH_ERROR("Give exactly one of `graph', `matrix' and `sparsemat'",
+		 IGRAPH_EINVAL);
+  }
+  
+  if (graph) { 
+    no_of_nodes = igraph_vcount(graph);
+  } else if (matrix) {
+    no_of_nodes = (int) igraph_matrix_nrow(matrix);
+  } else if (sparsemat) {
+    no_of_nodes = (int) igraph_sparsemat_nrow(sparsemat);
+  }
+  
+  if ((matrix && igraph_matrix_ncol(matrix) != no_of_nodes) ||
+      (sparsemat && igraph_sparsemat_ncol(sparsemat) != no_of_nodes)) {
+    IGRAPH_ERROR("Matrix must be square", IGRAPH_NONSQUARE);
+  }
+
+  igraph_vector_minmax(ev, evmin, evmax);
+  if (*evmin < 0 || *evmax >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid eigenvectors given", IGRAPH_EINVAL);
+  }
+
+  if (!nt_vec && (nt <= 1 || nt >= no_of_nodes)) {
+    IGRAPH_ERROR("Invalid interval specification", IGRAPH_EINVAL);
+  }
+  
+  if (nt_vec) { 
+    if (igraph_vector_size(nt_vec) != 1 && 
+	igraph_vector_size(nt_vec) != no_of_ev) {
+      IGRAPH_ERROR("Invalid length for interval specification", 
+		   IGRAPH_EINVAL);
+    }
+    igraph_vector_minmax(nt_vec, &min, &max);
+    if (min <= 1 || max >= no_of_nodes) { 
+      IGRAPH_ERROR("Invalid interval specification", IGRAPH_EINVAL);
+    }
+  }
+
+  if (vectors && igraph_matrix_size(vectors) != 0 && 
+      (igraph_matrix_ncol(vectors) != no_of_ev ||
+       igraph_matrix_nrow(vectors) != no_of_nodes)) {
+    IGRAPH_ERROR("Invalid eigenvector matrix size", IGRAPH_EINVAL);
+  }
+
+  if (vectors_cmplx && igraph_matrix_complex_size(vectors_cmplx) != 0 &&
+      (igraph_matrix_complex_ncol(vectors_cmplx) != no_of_ev || 
+       igraph_matrix_complex_nrow(vectors_cmplx) != no_of_nodes)) {
+    IGRAPH_ERROR("Invalid eigenvector matrix size", IGRAPH_EINVAL);
+  }
+
+  if (groups && igraph_vector_size(groups) != 0 && 
+      igraph_vector_size(groups) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `groups' vector size", IGRAPH_EINVAL);
+  }
+
+  if ( (scg_graph!=0) + (scg_matrix!=0) + (scg_sparsemat!=0) == 0 ) {
+    IGRAPH_ERROR("No output is requested, please give at least one of "
+		 "`scg_graph', `scg_matrix' and `scg_sparsemat'", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (p && igraph_vector_size(p) != 0 &&
+      igraph_vector_size(p) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid `p' vector size", IGRAPH_EINVAL);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_scg_adjacency
+ * Spectral coarse graining, symmetric case.
+ * 
+ * This function handles all the steps involved in the Spectral Coarse
+ * Graining (SCG) of some matrices and graphs as described in the
+ * reference below.
+ * 
+ * \param graph The input graph. Exactly one of \p graph, \p matrix
+ *    and \p sparsemat must be given, the other two must be \c NULL
+ *    pointers.
+ * \param matrix The input matrix. Exactly one of \p graph, \p matrix
+ *    and \p sparsemat must be given, the other two must be \c NULL
+ *    pointers.
+ * \param sparsemat The input sparse matrix. Exactly one of \p graph,
+ *    \p matrix and \p sparsemat must be given, the other two must be
+ *    \c NULL pointers.
+ * \param ev A vector of positive integers giving the indexes of the
+ *   eigenpairs to be preserved. 1 designates the eigenvalue with
+ *    largest algebraic value, 2 the one with second largest algebraic
+ *    value, etc.
+ * \param nt Positive integer. When \p algo is \c IGRAPH_SCG_OPTIMUM,
+ *    it gives the number of groups to partition each eigenvector
+ *    separately. When \p algo is \c IGRAPH_SCG_INTERV or \c
+ *    IGRAPH_SCG_INTERV_KM, it gives the number of intervals to
+ *    partition each eigenvector. This is ignored when \p algo is \c
+ *    IGRAPH_SCG_EXACT.
+ * \param nt_vec A numeric vector of length one or the length must
+ *    match the number of eigenvectors given in \p V, or a \c NULL
+ *    pointer. If not \c NULL, then this argument gives the number of
+ *    groups or intervals, and \p nt is ignored. Different number of
+ *    groups or intervals can be specified for each eigenvector.
+ * \param algo The algorithm to solve the SCG problem. Possible
+ *    values: \c IGRAPH_SCG_OPTIMUM, \c IGRAPH_SCG_INTERV_KM, \c
+ *    IGRAPH_SCG_INTERV and \c IGRAPH_SCG_EXACT. Please see the
+ *    details about them above.
+ * \param values If this is not \c NULL and the eigenvectors are
+ *    re-calculated, then the eigenvalues are stored here.
+ * \param vectors If this is not \c NULL, and not a zero-length
+ *    matrix, then it is interpreted as the eigenvectors to use for
+ *    the coarse-graining. Otherwise the eigenvectors are
+ *    re-calculated, and they are stored here. (If this is not \c NULL.)
+ * \param groups If this is not \c NULL, and not a zero-length vector,
+ *    then it is interpreted as the vector of group labels. (Group
+ *    labels are integers from zero and are sequential.) Otherwise
+ *    group labels are re-calculated and stored here, if this argument
+ *    is not a null pointer.
+ * \param use_arpack Whether to use ARPACK for solving the
+ *    eigenproblem. Currently ARPACK is not implemented.
+ * \param maxiter A positive integer giving the number of iterations
+ *    of the k-means algorithm when \p algo is \c
+ *    IGRAPH_SCG_INTERV_KM. It is ignored in other cases. A reasonable
+ *    (initial) value for this argument is 100.
+ * \param scg_graph If not a \c NULL pointer, then the coarse-grained
+ *    graph is returned here.
+ * \param scg_matrix If not a \c NULL pointer, then it must be an
+ *    initialied matrix, and the coarse-grained matrix is returned
+ *    here.
+ * \param scg_sparsemat If not a \c NULL pointer, then the coarse
+ *    grained matrix is returned here, in sparse matrix form.
+ * \param L If not a \c NULL pointer, then it must be an initialized
+ *    matrix and the left semi-projector is returned here.
+ * \param R If not a \c NULL pointer, then it must be an initialized
+ *    matrix and the right semi-projector is returned here.
+ * \param Lsparse If not a \c NULL pointer, then the left
+ *    semi-projector is returned here.
+ * \param Rsparse If not a \c NULL pointer, then the right
+ *    semi-projector is returned here.
+ * \return Error code.
+ *
+ * Time complexity: TODO.
+ * 
+ * \sa \ref igraph_scg_grouping(), \ref igraph_scg_semiprojectors(), 
+ * \ref igraph_scg_stochastic() and \ref igraph_scg_laplacian().
+ * 
+ * \example examples/simple/scg.c
+ */
+
+int igraph_scg_adjacency(const igraph_t *graph,
+			 const igraph_matrix_t *matrix,
+			 const igraph_sparsemat_t *sparsemat,
+			 const igraph_vector_t *ev,
+			 igraph_integer_t nt,
+			 const igraph_vector_t *nt_vec,
+			 igraph_scg_algorithm_t algo,
+			 igraph_vector_t *values,
+			 igraph_matrix_t *vectors,
+			 igraph_vector_t *groups,
+			 igraph_bool_t use_arpack,
+			 igraph_integer_t maxiter,
+			 igraph_t *scg_graph,
+			 igraph_matrix_t *scg_matrix,
+			 igraph_sparsemat_t *scg_sparsemat,
+			 igraph_matrix_t *L,
+			 igraph_matrix_t *R,
+			 igraph_sparsemat_t *Lsparse,
+			 igraph_sparsemat_t *Rsparse) {
+
+  igraph_sparsemat_t *mysparsemat=(igraph_sparsemat_t*) sparsemat, 
+    real_sparsemat;  
+  int no_of_ev=(int) igraph_vector_size(ev);
+  /* eigenvectors are calculated and returned */
+  igraph_bool_t do_vectors= vectors && igraph_matrix_size(vectors)==0;
+  /* groups are calculated */
+  igraph_bool_t do_groups= !groups || igraph_vector_size(groups)==0;
+  /* eigenvectors are not returned but must be calculated for groups */
+  igraph_bool_t tmp_vectors= !do_vectors && do_groups;
+  /* need temporary vector for groups */
+  igraph_bool_t tmp_groups= !groups;
+  igraph_matrix_t myvectors;
+  igraph_vector_t mygroups;
+  igraph_bool_t tmp_lsparse=!Lsparse, tmp_rsparse=!Rsparse;
+  igraph_sparsemat_t myLsparse, myRsparse, tmpsparse, Rsparse_t;
+  int no_of_nodes;
+  igraph_real_t evmin, evmax;
+  igraph_bool_t directed;
+  
+  /* --------------------------------------------------------------------*/
+  /* Argument checks */
+
+  IGRAPH_CHECK(igraph_i_scg_common_checks(graph, matrix, sparsemat,
+					  ev, nt, nt_vec,
+					  vectors, 0, groups, scg_graph, 
+					  scg_matrix, scg_sparsemat, 
+					  /*p=*/ 0, &evmin, &evmax));
+
+  if (graph) { 
+    no_of_nodes=igraph_vcount(graph); 
+    directed=igraph_is_directed(graph);
+  } else if (matrix) {
+    no_of_nodes=(int) igraph_matrix_nrow(matrix);
+    directed=!igraph_matrix_is_symmetric(matrix);
+  } else {
+    no_of_nodes=(int) igraph_sparsemat_nrow(sparsemat);
+    directed=!igraph_sparsemat_is_symmetric(sparsemat);
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Convert graph, if needed */
+
+  if (graph) {
+    mysparsemat=&real_sparsemat;
+    IGRAPH_CHECK(igraph_get_sparsemat(graph, mysparsemat));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparsemat);
+  }   
+
+  /* -------------------------------------------------------------------- */
+  /* Compute eigenpairs, if needed */
+  if (tmp_vectors) {
+    vectors=&myvectors;
+    IGRAPH_MATRIX_INIT_FINALLY(vectors, no_of_nodes, no_of_ev);
+  }
+
+  if (do_vectors || tmp_vectors) {
+    igraph_arpack_options_t options;
+    igraph_eigen_which_t which;
+    igraph_matrix_t tmp;
+    igraph_vector_t tmpev;
+    igraph_vector_t tmpeval;
+    int i;
+    
+    which.pos = IGRAPH_EIGEN_SELECT;
+    which.il = (int) (no_of_nodes-evmax+1);
+    which.iu = (int) (no_of_nodes-evmin+1);
+
+    if (values) { IGRAPH_VECTOR_INIT_FINALLY(&tmpeval, 0); }
+    IGRAPH_CHECK(igraph_matrix_init(&tmp, no_of_nodes, 
+				    which.iu-which.il+1));
+    IGRAPH_FINALLY(igraph_matrix_destroy, &tmp);
+    IGRAPH_CHECK(igraph_eigen_matrix_symmetric(matrix, mysparsemat,
+					       /* fun= */ 0, no_of_nodes,
+					       /* extra= */ 0, 
+					       /* algorithm= */ 
+					       use_arpack ? 
+					       IGRAPH_EIGEN_ARPACK : 
+					       IGRAPH_EIGEN_LAPACK, &which, 
+					       &options, /*storage=*/ 0,
+					       values ? &tmpeval : 0,
+					       &tmp));
+    IGRAPH_VECTOR_INIT_FINALLY(&tmpev, no_of_ev);
+    for (i=0; i<no_of_ev; i++) {
+      VECTOR(tmpev)[i] = evmax - VECTOR(*ev)[i];
+    }
+    if (values) { IGRAPH_CHECK(igraph_vector_index(&tmpeval, values, &tmpev)); }
+    IGRAPH_CHECK(igraph_matrix_select_cols(&tmp, vectors, &tmpev));
+    igraph_vector_destroy(&tmpev);
+    igraph_matrix_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(2);
+    if (values) { 
+      igraph_vector_destroy(&tmpeval);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Work out groups, if needed */
+  if (tmp_groups) {
+    groups=&mygroups;
+    IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)groups, no_of_nodes);
+  }
+  if (do_groups) {
+    IGRAPH_CHECK(igraph_scg_grouping(vectors, (igraph_vector_t*)groups, 
+				     nt, nt_vec, 
+				     IGRAPH_SCG_SYMMETRIC, algo, 
+				     /*p=*/ 0, maxiter));
+  }
+  
+  /* -------------------------------------------------------------------- */
+  /* Perform coarse graining */
+  if (tmp_lsparse) {
+    Lsparse=&myLsparse;
+  }
+  if (tmp_rsparse) {
+    Rsparse=&myRsparse;
+  }
+  IGRAPH_CHECK(igraph_scg_semiprojectors(groups, IGRAPH_SCG_SYMMETRIC,
+					 L, R, Lsparse, Rsparse, /*p=*/ 0,
+					 IGRAPH_SCG_NORM_ROW));
+  if (tmp_groups) {
+    igraph_vector_destroy((igraph_vector_t*) groups);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (tmp_vectors) {
+    igraph_matrix_destroy(vectors);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (Rsparse) { IGRAPH_FINALLY(igraph_sparsemat_destroy, Rsparse); }
+  if (Lsparse) { IGRAPH_FINALLY(igraph_sparsemat_destroy, Lsparse); }
+
+  /* -------------------------------------------------------------------- */
+  /* Compute coarse grained matrix/graph/sparse matrix */
+  IGRAPH_CHECK(igraph_sparsemat_compress(Rsparse, &tmpsparse));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmpsparse);
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&tmpsparse, &Rsparse_t,
+					  /*values=*/ 1));
+  igraph_sparsemat_destroy(&tmpsparse);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse_t);  
+
+  IGRAPH_CHECK(igraph_i_scg_get_result(IGRAPH_SCG_SYMMETRIC,
+				       matrix, mysparsemat,
+				       Lsparse, &Rsparse_t,
+				       scg_graph, scg_matrix, 
+				       scg_sparsemat, directed));
+
+  /* -------------------------------------------------------------------- */
+  /* Clean up */
+  
+  igraph_sparsemat_destroy(&Rsparse_t);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (Lsparse) { IGRAPH_FINALLY_CLEAN(1); }
+  if (Rsparse) { IGRAPH_FINALLY_CLEAN(1); }
+
+  if (graph) {
+    igraph_sparsemat_destroy(mysparsemat);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_scg_stochastic
+ * Spectral coarse graining, stochastic case.
+ *
+ * This function handles all the steps involved in the Spectral Coarse
+ * Graining (SCG) of some matrices and graphs as described in the
+ * reference below.
+ * 
+ * \param graph The input graph. Exactly one of \p graph, \p matrix
+ *    and \p sparsemat must be given, the other two must be \c NULL
+ *    pointers.
+ * \param matrix The input matrix. Exactly one of \p graph, \p matrix
+ *    and \p sparsemat must be given, the other two must be \c NULL
+ *    pointers.
+ * \param sparsemat The input sparse matrix. Exactly one of \p graph,
+ *    \p matrix and \p sparsemat must be given, the other two must be
+ *    \c NULL pointers.
+ * \param ev A vector of positive integers giving the indexes of the
+ *   eigenpairs to be preserved. 1 designates the eigenvalue with
+ *    largest magnitude, 2 the one with second largest magnitude, etc.
+ * \param nt Positive integer. When \p algo is \c IGRAPH_SCG_OPTIMUM,
+ *    it gives the number of groups to partition each eigenvector
+ *    separately. When \p algo is \c IGRAPH_SCG_INTERV or \c
+ *    IGRAPH_SCG_INTERV_KM, it gives the number of intervals to
+ *    partition each eigenvector. This is ignored when \p algo is \c
+ *    IGRAPH_SCG_EXACT.
+ * \param nt_vec A numeric vector of length one or the length must
+ *    match the number of eigenvectors given in \p V, or a \c NULL
+ *    pointer. If not \c NULL, then this argument gives the number of
+ *    groups or intervals, and \p nt is ignored. Different number of
+ *    groups or intervals can be specified for each eigenvector.
+ * \param algo The algorithm to solve the SCG problem. Possible
+ *    values: \c IGRAPH_SCG_OPTIMUM, \c IGRAPH_SCG_INTERV_KM, \c
+ *    IGRAPH_SCG_INTERV and \c IGRAPH_SCG_EXACT. Please see the
+ *    details about them above.
+ * \param norm Either \c IGRAPH_SCG_NORM_ROW or \c IGRAPH_SCG_NORM_COL. 
+ *    Specifies whether the rows or the columns of the
+ *    stochastic matrix sum up to one.
+ * \param values If this is not \c NULL and the eigenvectors are
+ *    re-calculated, then the eigenvalues are stored here.
+ * \param vectors If this is not \c NULL, and not a zero-length
+ *    matrix, then it is interpreted as the eigenvectors to use for
+ *    the coarse-graining. Otherwise the eigenvectors are
+ *    re-calculated, and they are stored here. (If this is not \c NULL.)
+ * \param groups If this is not \c NULL, and not a zero-length vector,
+ *    then it is interpreted as the vector of group labels. (Group
+ *    labels are integers from zero and are sequential.) Otherwise
+ *    group labels are re-calculated and stored here, if this argument
+ *    is not a null pointer.
+ * \param p If this is not \c NULL, and not zero length, then it is
+ *    interpreted as the stationary probability distribution of the
+ *    Markov chain corresponding to the input matrix/graph. Its length
+ *    must match the number of  vertices in the input graph (or number
+ *    of rows in the input matrix). If not given, then the stationary
+ *    distribution is calculated and stored here. (Unless this
+ *    argument is a \c NULL pointer, in which case it is not stored.)
+ * \param use_arpack Whether to use ARPACK for solving the
+ *    eigenproblem. Currently ARPACK is not implemented.
+ * \param maxiter A positive integer giving the number of iterations
+ *    of the k-means algorithm when \p algo is \c
+ *    IGRAPH_SCG_INTERV_KM. It is ignored in other cases. A reasonable
+ *    (initial) value for this argument is 100.
+ * \param scg_graph If not a \c NULL pointer, then the coarse-grained
+ *    graph is returned here.
+ * \param scg_matrix If not a \c NULL pointer, then it must be an
+ *    initialied matrix, and the coarse-grained matrix is returned
+ *    here.
+ * \param scg_sparsemat If not a \c NULL pointer, then the coarse
+ *    grained matrix is returned here, in sparse matrix form.
+ * \param L If not a \c NULL pointer, then it must be an initialized
+ *    matrix and the left semi-projector is returned here.
+ * \param R If not a \c NULL pointer, then it must be an initialized
+ *    matrix and the right semi-projector is returned here.
+ * \param Lsparse If not a \c NULL pointer, then the left
+ *    semi-projector is returned here.
+ * \param Rsparse If not a \c NULL pointer, then the right
+ *    semi-projector is returned here.
+ * \return Error code.
+ *
+ * Time complexity: TODO.
+ * 
+ * \sa \ref igraph_scg_grouping(), \ref igraph_scg_semiprojectors(), 
+ * \ref igraph_scg_adjacency() and \ref igraph_scg_laplacian().
+ * 
+ * \example examples/simple/scg2.c
+ */
+
+int igraph_scg_stochastic(const igraph_t *graph,
+			  const igraph_matrix_t *matrix,
+			  const igraph_sparsemat_t *sparsemat,
+			  const igraph_vector_t *ev,
+			  igraph_integer_t nt,
+			  const igraph_vector_t *nt_vec,
+			  igraph_scg_algorithm_t algo,
+			  igraph_scg_norm_t norm,
+			  igraph_vector_complex_t *values,
+			  igraph_matrix_complex_t *vectors,
+			  igraph_vector_t *groups,
+			  igraph_vector_t *p,
+			  igraph_bool_t use_arpack,
+			  igraph_integer_t maxiter,
+			  igraph_t *scg_graph,
+			  igraph_matrix_t *scg_matrix,
+			  igraph_sparsemat_t *scg_sparsemat,
+			  igraph_matrix_t *L,
+			  igraph_matrix_t *R,
+			  igraph_sparsemat_t *Lsparse,
+			  igraph_sparsemat_t *Rsparse) {
+
+  igraph_matrix_t *mymatrix=(igraph_matrix_t*) matrix, real_matrix;
+  igraph_sparsemat_t *mysparsemat=(igraph_sparsemat_t*) sparsemat, 
+    real_sparsemat;
+  int no_of_nodes;
+  igraph_real_t evmin, evmax;
+  igraph_arpack_options_t options;
+  igraph_eigen_which_t which;
+  /* eigenvectors are calculated and returned */
+  igraph_bool_t do_vectors= vectors && igraph_matrix_complex_size(vectors)==0;
+  /* groups are calculated */
+  igraph_bool_t do_groups= !groups || igraph_vector_size(groups)==0;
+  igraph_bool_t tmp_groups= !groups;
+  /* eigenvectors are not returned but must be calculated for groups */
+  igraph_bool_t tmp_vectors= !do_vectors && do_groups;
+  igraph_matrix_complex_t myvectors;
+  igraph_vector_t mygroups;
+  igraph_bool_t do_p= !p || igraph_vector_size(p)==0;
+  igraph_vector_t *myp=(igraph_vector_t *) p, real_p;
+  int no_of_ev=(int) igraph_vector_size(ev);
+  igraph_bool_t tmp_lsparse=!Lsparse, tmp_rsparse=!Rsparse;
+  igraph_sparsemat_t myLsparse, myRsparse, tmpsparse, Rsparse_t;
+
+  /* --------------------------------------------------------------------*/
+  /* Argument checks */
+
+  IGRAPH_CHECK(igraph_i_scg_common_checks(graph, matrix, sparsemat,
+					  ev, nt, nt_vec,
+					  0, vectors, groups, scg_graph, 
+					  scg_matrix, scg_sparsemat, p,
+					  &evmin, &evmax));
+  
+  if (graph) { 
+    no_of_nodes=igraph_vcount(graph); 
+  } else if (matrix) {
+    no_of_nodes=(int) igraph_matrix_nrow(matrix);
+  } else {
+    no_of_nodes=(int) igraph_sparsemat_nrow(sparsemat);
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Convert graph, if needed */
+
+  if (graph) {
+    mysparsemat=&real_sparsemat;
+    IGRAPH_CHECK(igraph_get_stochastic_sparsemat(graph, mysparsemat, 
+						 norm==IGRAPH_SCG_NORM_COL));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparsemat);
+  } else if (matrix) {
+    mymatrix=&real_matrix;
+    IGRAPH_CHECK(igraph_i_matrix_stochastic(matrix, mymatrix, norm));
+    IGRAPH_FINALLY(igraph_matrix_destroy, mymatrix);
+  } else { /* sparsemat */
+    mysparsemat=&real_sparsemat;
+    IGRAPH_CHECK(igraph_i_sparsemat_stochastic(sparsemat, mysparsemat, norm));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparsemat);
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Compute eigenpairs, if needed */
+
+  if (tmp_vectors) {
+    vectors=&myvectors;
+    IGRAPH_CHECK(igraph_matrix_complex_init(vectors, no_of_nodes, no_of_ev));
+    IGRAPH_FINALLY(igraph_matrix_complex_destroy, vectors);
+  }
+
+  if (do_vectors || tmp_vectors) {
+    igraph_matrix_complex_t tmp;
+    igraph_vector_t tmpev;
+    igraph_vector_complex_t tmpeval;
+    int i;
+
+    which.pos = IGRAPH_EIGEN_SELECT;
+    which.il = (int) (no_of_nodes-evmax+1);
+    which.iu = (int) (no_of_nodes-evmin+1);
+
+    if (values) { 
+      IGRAPH_CHECK(igraph_vector_complex_init(&tmpeval, 0));
+      IGRAPH_FINALLY(igraph_vector_complex_destroy, &tmpeval);
+    }
+    IGRAPH_CHECK(igraph_matrix_complex_init(&tmp, no_of_nodes, 
+					    which.iu-which.il+1));
+    IGRAPH_FINALLY(igraph_matrix_complex_destroy, &tmp);
+    IGRAPH_CHECK(igraph_eigen_matrix(mymatrix, mysparsemat, /*fun=*/ 0,
+				     no_of_nodes, /*extra=*/ 0, use_arpack ? 
+				     IGRAPH_EIGEN_ARPACK : 
+				     IGRAPH_EIGEN_LAPACK, &which, &options, 
+				     /*storage=*/ 0, 
+				     values ? &tmpeval: 0, &tmp));
+    
+    IGRAPH_VECTOR_INIT_FINALLY(&tmpev, no_of_ev);
+    for (i=0; i<no_of_ev; i++) {
+      VECTOR(tmpev)[i] = evmax - VECTOR(*ev)[i];
+    }
+    if (values) { 
+      IGRAPH_CHECK(igraph_vector_complex_index(&tmpeval, values, &tmpev)); 
+    }
+    IGRAPH_CHECK(igraph_matrix_complex_select_cols(&tmp, vectors, &tmpev));
+    igraph_vector_destroy(&tmpev);
+    igraph_matrix_complex_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(2);
+    if (values) { 
+      igraph_vector_complex_destroy(&tmpeval);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  /* Compute p if not supplied */
+  if (do_p) {
+    igraph_eigen_which_t w;
+    igraph_matrix_complex_t tmp;
+    igraph_arpack_options_t o;
+    igraph_matrix_t trans, *mytrans=&trans;
+    igraph_sparsemat_t sparse_trans, *mysparse_trans=&sparse_trans;
+    int i;
+    igraph_arpack_options_init(&o);
+    if (!p) { 
+      IGRAPH_VECTOR_INIT_FINALLY(&real_p, no_of_nodes);
+      myp=&real_p;
+    } else { 
+      IGRAPH_CHECK(igraph_vector_resize(p, no_of_nodes));
+    }
+    IGRAPH_CHECK(igraph_matrix_complex_init(&tmp, 0, 0));
+    IGRAPH_FINALLY(igraph_matrix_complex_destroy, &tmp);
+    w.pos=IGRAPH_EIGEN_LR;
+    w.howmany=1;
+
+    if (mymatrix) { 
+      IGRAPH_CHECK(igraph_matrix_copy(&trans, mymatrix));
+      IGRAPH_FINALLY(igraph_matrix_destroy, &trans);
+      IGRAPH_CHECK(igraph_matrix_transpose(&trans));
+      mysparse_trans=0;
+    } else { 
+      IGRAPH_CHECK(igraph_sparsemat_transpose(mysparsemat, &sparse_trans, 
+					      /*values=*/ 1));
+      IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparse_trans);
+      mytrans=0;
+    }
+
+    IGRAPH_CHECK(igraph_eigen_matrix(mytrans, mysparse_trans, /*fun=*/ 0, 
+				     no_of_nodes, /*extra=*/ 0, /*algorith=*/ 
+				     use_arpack ? 
+				     IGRAPH_EIGEN_ARPACK : 
+				     IGRAPH_EIGEN_LAPACK, &w, &o, 
+				     /*storage=*/ 0, /*values=*/ 0, &tmp));
+
+    if (mymatrix) {
+      igraph_matrix_destroy(&trans);
+      IGRAPH_FINALLY_CLEAN(1);
+    } else {
+      igraph_sparsemat_destroy(mysparse_trans);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    for (i=0; i<no_of_nodes; i++) {
+      VECTOR(*myp)[i] = fabs(IGRAPH_REAL(MATRIX(tmp, i, 0)));
+    }
+    igraph_matrix_complex_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+  }    
+
+  /* -------------------------------------------------------------------- */
+  /* Work out groups, if needed */
+  /* TODO: use complex part as well */
+  if (tmp_groups) {
+    groups=&mygroups;
+    IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)groups, no_of_nodes);
+  }
+  if (do_groups) {
+    igraph_matrix_t tmp;
+    IGRAPH_MATRIX_INIT_FINALLY(&tmp, 0, 0);
+    IGRAPH_CHECK(igraph_matrix_complex_real(vectors, &tmp));
+    IGRAPH_CHECK(igraph_scg_grouping(&tmp, (igraph_vector_t*)groups, 
+				     nt, nt_vec, 
+				     IGRAPH_SCG_STOCHASTIC, algo, 
+				     myp, maxiter));
+    igraph_matrix_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  /* -------------------------------------------------------------------- */
+  /* Perform coarse graining */
+  if (tmp_lsparse) {
+    Lsparse=&myLsparse;
+  }
+  if (tmp_rsparse) {
+    Rsparse=&myRsparse;
+  }
+  IGRAPH_CHECK(igraph_scg_semiprojectors(groups, IGRAPH_SCG_STOCHASTIC,
+					 L, R, Lsparse, Rsparse, myp, norm));
+  if (tmp_groups) {
+    igraph_vector_destroy((igraph_vector_t*) groups);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (!p && do_p) { 
+    igraph_vector_destroy(myp);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (tmp_vectors) {
+    igraph_matrix_complex_destroy(vectors);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (Rsparse) { IGRAPH_FINALLY(igraph_sparsemat_destroy, Rsparse); }
+  if (Lsparse) { IGRAPH_FINALLY(igraph_sparsemat_destroy, Lsparse); }
+
+  /* -------------------------------------------------------------------- */
+  /* Compute coarse grained matrix/graph/sparse matrix */
+  IGRAPH_CHECK(igraph_sparsemat_compress(Rsparse, &tmpsparse));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmpsparse);
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&tmpsparse, &Rsparse_t,
+					  /*values=*/ 1));
+  igraph_sparsemat_destroy(&tmpsparse);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse_t);  
+
+  IGRAPH_CHECK(igraph_i_scg_get_result(IGRAPH_SCG_STOCHASTIC,
+				       mymatrix, mysparsemat,
+				       Lsparse, &Rsparse_t,
+				       scg_graph, scg_matrix, 
+				       scg_sparsemat, /*directed=*/ 1));
+
+  /* -------------------------------------------------------------------- */
+  /* Clean up */
+
+  igraph_sparsemat_destroy(&Rsparse_t);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (Lsparse) { IGRAPH_FINALLY_CLEAN(1); }
+  if (Rsparse) { IGRAPH_FINALLY_CLEAN(1); }  
+
+  if (graph) {
+    igraph_sparsemat_destroy(mysparsemat);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (matrix) { 
+    igraph_matrix_destroy(mymatrix);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    igraph_sparsemat_destroy(mysparsemat);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_scg_laplacian
+ * Spectral coarse graining, laplacian matrix.
+ * This function handles all the steps involved in the Spectral Coarse
+ * Graining (SCG) of some matrices and graphs as described in the
+ * reference below.
+ * 
+ * \param graph The input graph. Exactly one of \p graph, \p matrix
+ *    and \p sparsemat must be given, the other two must be \c NULL
+ *    pointers.
+ * \param matrix The input matrix. Exactly one of \p graph, \p matrix
+ *    and \p sparsemat must be given, the other two must be \c NULL
+ *    pointers.
+ * \param sparsemat The input sparse matrix. Exactly one of \p graph,
+ *    \p matrix and \p sparsemat must be given, the other two must be
+ *    \c NULL pointers.
+ * \param ev A vector of positive integers giving the indexes of the
+ *   eigenpairs to be preserved. 1 designates the eigenvalue with
+ *    largest magnitude, 2 the one with second largest magnitude, etc.
+ * \param nt Positive integer. When \p algo is \c IGRAPH_SCG_OPTIMUM,
+ *    it gives the number of groups to partition each eigenvector
+ *    separately. When \p algo is \c IGRAPH_SCG_INTERV or \c
+ *    IGRAPH_SCG_INTERV_KM, it gives the number of intervals to
+ *    partition each eigenvector. This is ignored when \p algo is \c
+ *    IGRAPH_SCG_EXACT.
+ * \param nt_vec A numeric vector of length one or the length must
+ *    match the number of eigenvectors given in \p V, or a \c NULL
+ *    pointer. If not \c NULL, then this argument gives the number of
+ *    groups or intervals, and \p nt is ignored. Different number of
+ *    groups or intervals can be specified for each eigenvector.
+ * \param algo The algorithm to solve the SCG problem. Possible
+ *    values: \c IGRAPH_SCG_OPTIMUM, \c IGRAPH_SCG_INTERV_KM, \c
+ *    IGRAPH_SCG_INTERV and \c IGRAPH_SCG_EXACT. Please see the
+ *    details about them above.
+ * \param norm Either \c IGRAPH_SCG_NORM_ROW or \c IGRAPH_SCG_NORM_COL. 
+ *    Specifies whether the rows or the columns of the Laplacian
+ *    matrix sum up to zero.
+ * \param direction Whether to work with left or right eigenvectors.
+ *    Possible values: \c IGRAPH_SCG_DIRECTION_DEFAULT, \c
+ *    IGRAPH_SCG_DIRECTION_LEFT, \c IGRAPH_SCG_DIRECTION_RIGHT. This
+ *    argument is currently ignored and right eigenvectors are always
+ *    used.
+ * \param values If this is not \c NULL and the eigenvectors are
+ *    re-calculated, then the eigenvalues are stored here.
+ * \param vectors If this is not \c NULL, and not a zero-length
+ *    matrix, then it is interpreted as the eigenvectors to use for
+ *    the coarse-graining. Otherwise the eigenvectors are
+ *    re-calculated, and they are stored here. (If this is not \c NULL.)
+ * \param groups If this is not \c NULL, and not a zero-length vector,
+ *    then it is interpreted as the vector of group labels. (Group
+ *    labels are integers from zero and are sequential.) Otherwise
+ *    group labels are re-calculated and stored here, if this argument
+ *    is not a null pointer.
+ * \param use_arpack Whether to use ARPACK for solving the
+ *    eigenproblem. Currently ARPACK is not implemented.
+ * \param maxiter A positive integer giving the number of iterations
+ *    of the k-means algorithm when \p algo is \c
+ *    IGRAPH_SCG_INTERV_KM. It is ignored in other cases. A reasonable
+ *    (initial) value for this argument is 100.
+ * \param scg_graph If not a \c NULL pointer, then the coarse-grained
+ *    graph is returned here.
+ * \param scg_matrix If not a \c NULL pointer, then it must be an
+ *    initialied matrix, and the coarse-grained matrix is returned
+ *    here.
+ * \param scg_sparsemat If not a \c NULL pointer, then the coarse
+ *    grained matrix is returned here, in sparse matrix form.
+ * \param L If not a \c NULL pointer, then it must be an initialized
+ *    matrix and the left semi-projector is returned here.
+ * \param R If not a \c NULL pointer, then it must be an initialized
+ *    matrix and the right semi-projector is returned here.
+ * \param Lsparse If not a \c NULL pointer, then the left
+ *    semi-projector is returned here.
+ * \param Rsparse If not a \c NULL pointer, then the right
+ *    semi-projector is returned here.
+ * \return Error code.
+ *
+ * Time complexity: TODO.
+ * 
+ * \sa \ref igraph_scg_grouping(), \ref igraph_scg_semiprojectors(), 
+ * \ref igraph_scg_stochastic() and \ref igraph_scg_adjacency().
+ * 
+ * \example examples/simple/scg3.c
+ */
+
+int igraph_scg_laplacian(const igraph_t *graph,
+			 const igraph_matrix_t *matrix,
+			 const igraph_sparsemat_t *sparsemat,
+			 const igraph_vector_t *ev,
+			 igraph_integer_t nt,
+			 const igraph_vector_t *nt_vec,
+			 igraph_scg_algorithm_t algo,
+			 igraph_scg_norm_t norm,
+			 igraph_scg_direction_t direction,
+			 igraph_vector_complex_t *values,
+			 igraph_matrix_complex_t *vectors,
+			 igraph_vector_t *groups,
+			 igraph_bool_t use_arpack,
+			 igraph_integer_t maxiter,
+			 igraph_t *scg_graph,
+			 igraph_matrix_t *scg_matrix,
+			 igraph_sparsemat_t *scg_sparsemat,
+			 igraph_matrix_t *L,
+			 igraph_matrix_t *R,
+			 igraph_sparsemat_t *Lsparse,
+			 igraph_sparsemat_t *Rsparse) {
+
+  igraph_matrix_t *mymatrix=(igraph_matrix_t*) matrix, real_matrix;
+  igraph_sparsemat_t *mysparsemat=(igraph_sparsemat_t*) sparsemat, 
+    real_sparsemat;
+  int no_of_nodes;
+  igraph_real_t evmin, evmax;
+  igraph_arpack_options_t options;
+  igraph_eigen_which_t which;
+  /* eigenvectors are calculated and returned */
+  igraph_bool_t do_vectors= vectors && igraph_matrix_complex_size(vectors)==0;
+  /* groups are calculated */
+  igraph_bool_t do_groups= !groups || igraph_vector_size(groups)==0;
+  igraph_bool_t tmp_groups= !groups;
+  /* eigenvectors are not returned but must be calculated for groups */
+  igraph_bool_t tmp_vectors= !do_vectors && do_groups;
+  igraph_matrix_complex_t myvectors;
+  igraph_vector_t mygroups;
+  int no_of_ev=(int) igraph_vector_size(ev);
+  igraph_bool_t tmp_lsparse=!Lsparse, tmp_rsparse=!Rsparse;
+  igraph_sparsemat_t myLsparse, myRsparse, tmpsparse, Rsparse_t;
+
+  /* --------------------------------------------------------------------*/
+  /* Argument checks */
+
+  IGRAPH_CHECK(igraph_i_scg_common_checks(graph, matrix, sparsemat,
+					  ev, nt, nt_vec,
+					  0, vectors, groups, scg_graph, 
+					  scg_matrix, scg_sparsemat, /*p=*/ 0,
+					  &evmin, &evmax));
+  
+  if (graph) { 
+    no_of_nodes=igraph_vcount(graph); 
+  } else if (matrix) {
+    no_of_nodes=(int) igraph_matrix_nrow(matrix);
+  } else {
+    no_of_nodes=(int) igraph_sparsemat_nrow(sparsemat);
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Convert graph, if needed, get Laplacian matrix */
+
+  if (graph) {
+    mysparsemat=&real_sparsemat;
+    IGRAPH_CHECK(igraph_sparsemat_init(mysparsemat, 0, 0, 0));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparsemat);
+    IGRAPH_CHECK(igraph_laplacian(graph, 0, mysparsemat, /*normalized=*/ 0, 
+				  /*weights=*/ 0));
+  } else if (matrix) { 
+    mymatrix=&real_matrix;
+    IGRAPH_MATRIX_INIT_FINALLY(mymatrix, no_of_nodes, no_of_nodes);
+    IGRAPH_CHECK(igraph_i_matrix_laplacian(matrix, mymatrix, norm));
+  } else { /* sparsemat */
+    mysparsemat=&real_sparsemat;
+    IGRAPH_CHECK(igraph_i_sparsemat_laplacian(sparsemat, mysparsemat, 
+					    norm==IGRAPH_SCG_NORM_COL));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparsemat);
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Compute eigenpairs, if needed */
+
+  if (tmp_vectors) {
+    vectors=&myvectors;
+    IGRAPH_CHECK(igraph_matrix_complex_init(vectors, no_of_nodes, no_of_ev));
+    IGRAPH_FINALLY(igraph_matrix_complex_destroy, vectors);
+  }
+
+  if (do_vectors || tmp_vectors) {
+    igraph_matrix_complex_t tmp;
+    igraph_vector_t tmpev;
+    igraph_vector_complex_t tmpeval;
+    int i;
+
+    which.pos = IGRAPH_EIGEN_SELECT;
+    which.il = (int) (no_of_nodes-evmax+1);
+    which.iu = (int) (no_of_nodes-evmin+1);
+
+    if (values) { 
+      IGRAPH_CHECK(igraph_vector_complex_init(&tmpeval, 0));
+      IGRAPH_FINALLY(igraph_vector_complex_destroy, &tmpeval);
+    }
+    IGRAPH_CHECK(igraph_matrix_complex_init(&tmp, no_of_nodes, 
+					    which.iu-which.il+1));
+    IGRAPH_FINALLY(igraph_matrix_complex_destroy, &tmp);
+    IGRAPH_CHECK(igraph_eigen_matrix(mymatrix, mysparsemat, /*fun=*/ 0,
+				     no_of_nodes, /*extra=*/ 0, use_arpack ? 
+				     IGRAPH_EIGEN_ARPACK : 
+				     IGRAPH_EIGEN_LAPACK, &which, &options, 
+				     /*storage=*/ 0,
+				     values ? &tmpeval : 0, &tmp));
+    
+    IGRAPH_VECTOR_INIT_FINALLY(&tmpev, no_of_ev);
+    for (i=0; i<no_of_ev; i++) {
+      VECTOR(tmpev)[i] = evmax - VECTOR(*ev)[i];
+    }
+    if (values) { 
+      IGRAPH_CHECK(igraph_vector_complex_index(&tmpeval, values, &tmpev)); 
+    }
+    IGRAPH_CHECK(igraph_matrix_complex_select_cols(&tmp, vectors, &tmpev));
+    igraph_vector_destroy(&tmpev);
+    igraph_matrix_complex_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(2);
+    if (values) { 
+      igraph_vector_complex_destroy(&tmpeval);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  /* -------------------------------------------------------------------- */
+  /* Work out groups, if needed */
+  /* TODO: use complex part as well */
+  if (tmp_groups) {
+    groups=&mygroups;
+    IGRAPH_VECTOR_INIT_FINALLY((igraph_vector_t*)groups, no_of_nodes);
+  }
+  if (do_groups) {
+    igraph_matrix_t tmp;
+    IGRAPH_MATRIX_INIT_FINALLY(&tmp, 0, 0);
+    IGRAPH_CHECK(igraph_matrix_complex_real(vectors, &tmp));
+    IGRAPH_CHECK(igraph_scg_grouping(&tmp, (igraph_vector_t*)groups, 
+				     nt, nt_vec, 
+				     IGRAPH_SCG_LAPLACIAN, algo, 
+				     /*p=*/ 0, maxiter));
+    igraph_matrix_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  /* -------------------------------------------------------------------- */
+  /* Perform coarse graining */
+  if (tmp_lsparse) {
+    Lsparse=&myLsparse;
+  }
+  if (tmp_rsparse) {
+    Rsparse=&myRsparse;
+  }
+  IGRAPH_CHECK(igraph_scg_semiprojectors(groups, IGRAPH_SCG_LAPLACIAN,
+					 L, R, Lsparse, Rsparse, /*p=*/ 0, 
+					 norm));
+  if (tmp_groups) {
+    igraph_vector_destroy((igraph_vector_t*) groups);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (tmp_vectors) {
+    igraph_matrix_complex_destroy(vectors);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (Rsparse) { IGRAPH_FINALLY(igraph_sparsemat_destroy, Rsparse); }
+  if (Lsparse) { IGRAPH_FINALLY(igraph_sparsemat_destroy, Lsparse); }
+
+  /* -------------------------------------------------------------------- */
+  /* Compute coarse grained matrix/graph/sparse matrix */
+  IGRAPH_CHECK(igraph_sparsemat_compress(Rsparse, &tmpsparse));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmpsparse);
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&tmpsparse, &Rsparse_t,
+					  /*values=*/ 1));
+  igraph_sparsemat_destroy(&tmpsparse);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse_t);  
+
+  IGRAPH_CHECK(igraph_i_scg_get_result(IGRAPH_SCG_LAPLACIAN,
+				       mymatrix, mysparsemat,
+				       Lsparse, &Rsparse_t,
+				       scg_graph, scg_matrix, 
+				       scg_sparsemat, /*directed=*/ 1));
+
+  /* -------------------------------------------------------------------- */
+  /* Clean up */
+
+  igraph_sparsemat_destroy(&Rsparse_t);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (Lsparse) { IGRAPH_FINALLY_CLEAN(1); }
+  if (Rsparse) { IGRAPH_FINALLY_CLEAN(1); }  
+
+  if (graph) {
+    igraph_sparsemat_destroy(mysparsemat);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else if (matrix) {
+    igraph_matrix_destroy(mymatrix);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    igraph_sparsemat_destroy(mysparsemat);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
diff --git a/src/scg_approximate_methods.c b/src/scg_approximate_methods.c
new file mode 100644
index 0000000..bc30b21
--- /dev/null
+++ b/src/scg_approximate_methods.c
@@ -0,0 +1,167 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-12  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    The intervals_method and intervals_plus_kmeans implements the 
+ *	  methods of sec. 5.3.2 and sec. 5.3.3 of the above reference.
+ *	  They take an eigenvector 'v' as parameter and a vector 'breaks'
+ *	  of length 'nb', which provide the intervals used to cut 'v'.
+ *	  Then all components of 'v' that fall into the same interval are
+ *	  assigned the same group label in 'gr'. The group labels are
+ *	  positive consecutive integers starting from 0.
+ *	  The intervals_method function is adapted from bincode of the R
+ *	  base package.
+ *	  The intervals_plus_kmeans is initialized with regularly-spaced
+ *	  breaks, which rougly corresponds to the intervals_method. Then
+ *	  kmeans minimizes iteratively the objective function until it gets
+ *	  stuck in a (usually) local minimum, or until 'itermax' is reached.
+ *	  So far, the breaks_computation function allows computation of 
+ *	  constant bins, as used in intervals_method, and of equidistant
+ *	  centers as used in intervals_plus_kmeans.
+ */
+
+#include "igraph_error.h"
+#include "igraph_types.h"
+#include "scg_headers.h"
+#include "igraph_memory.h"
+#include "igraph_vector.h"
+
+int igraph_i_intervals_plus_kmeans(const igraph_vector_t *v, int *gr, 
+				   int n, int n_interv, 
+				   int maxiter) {
+  int i;
+  igraph_vector_t centers;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&centers, n_interv);
+
+  igraph_i_breaks_computation(v, &centers, n_interv, 2);
+  IGRAPH_CHECK(igraph_i_kmeans_Lloyd(v, n, 1, &centers, n_interv, gr,
+				     maxiter));
+	
+  /*renumber the groups*/
+  for (i=0; i<n; i++) gr[i] = gr[i]-1;
+  
+  igraph_vector_destroy(&centers);
+  IGRAPH_FINALLY_CLEAN(1);
+    
+  return 0;
+}
+										
+int igraph_i_intervals_method(const igraph_vector_t *v, int *gr, int n,
+			      int n_interv) {
+  int i, lo, hi, new;
+  const int lft = 1;
+  const int include_border = 1;
+  igraph_vector_t breaks;
+			
+  IGRAPH_VECTOR_INIT_FINALLY(&breaks, n_interv+1);
+  
+  IGRAPH_CHECK(igraph_i_breaks_computation(v, &breaks, n_interv+1, 1));
+
+  for (i = 0; i < n; i++) {
+    lo = 0;
+    hi = n_interv;
+    if (VECTOR(*v)[i] <  VECTOR(breaks)[lo] ||
+	VECTOR(breaks)[hi] < VECTOR(*v)[i] ||
+	(VECTOR(*v)[i] == VECTOR(breaks)[lft ? hi : lo] && !include_border)) {
+      /* Do nothing */
+    } else {
+      while (hi - lo >= 2) {
+	new = (hi + lo)/2;
+	if (VECTOR(*v)[i] > VECTOR(breaks)[new] || 
+	    (lft && VECTOR(*v)[i] == VECTOR(breaks)[new])) {
+	  lo = new;
+	} else {
+	  hi = new;
+	}
+      }
+      gr[i] = lo;
+    }
+  }
+  igraph_vector_destroy(&breaks);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_breaks_computation(const igraph_vector_t *v,
+				igraph_vector_t *breaks,
+				int nb, int method) {
+  int i;
+  igraph_real_t eps, vmin, vmax;
+  igraph_vector_minmax(v, &vmin, &vmax);
+  
+  if (vmax == vmin) {
+    IGRAPH_ERROR("There is only one (repeated) value in argument 'v' "
+		 "of bin_size_computation()", IGRAPH_EINVAL);
+  }
+
+  if (nb < 2) {
+    IGRAPH_ERROR("'nb' in bin_size_computation() must be >= 2", 
+		 IGRAPH_EINVAL);
+  }
+  
+  switch (method) {
+  case 1: /* constant bins for fixed-size intervals method */
+    eps = (vmax - vmin) / (igraph_real_t)(nb-1);
+    VECTOR(*breaks)[0] = vmin;
+    for (i=1; i<nb-1; i++) { VECTOR(*breaks)[i]=VECTOR(*breaks)[i-1]+eps; }
+    VECTOR(*breaks)[nb-1] = vmax;
+    break;
+  case 2: /* equidistant centers for kmeans */
+    eps = (vmax-vmin)/(igraph_real_t)nb;
+    VECTOR(*breaks)[0] = vmin + eps/2.;
+    for (i=1; i<nb; i++) { VECTOR(*breaks)[i] = VECTOR(*breaks)[i-1]+eps; }
+    break;
+    /* TODO: implement logarithmic binning for power-law-like distributions */
+  default:
+    IGRAPH_ERROR("Internal SCG error, this should ot happen", 
+		 IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
diff --git a/src/scg_exact_scg.c b/src/scg_exact_scg.c
new file mode 100644
index 0000000..d15c45e
--- /dev/null
+++ b/src/scg_exact_scg.c
@@ -0,0 +1,66 @@
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    The exact_coarse_graining function labels all the objects whose
+ *	  components in 'v' are equal. The result is stored in 'gr'. Labels
+ *	  are positive consecutive integers starting from 0.
+ *	  See also Section 5.4.1 (last paragraph) of the above reference.
+ */
+
+#include "igraph_memory.h"
+#include "scg_headers.h"
+#include <math.h>
+
+int igraph_i_exact_coarse_graining(const igraph_real_t *v, 
+				   int *gr, const int n) {
+  int i, gr_nb;
+  igraph_i_scg_indval_t *w = igraph_Calloc(n, igraph_i_scg_indval_t);
+
+  if (!w) { 
+    IGRAPH_ERROR("SCG error", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, w);
+
+  for(i=0; i<n; i++){
+    w[i].val = v[i];
+    w[i].ind = i;
+  }
+
+  qsort(w, (size_t) n, sizeof(igraph_i_scg_indval_t), igraph_i_compare_ind_val);
+  
+  gr_nb = 0;
+  gr[w[0].ind] = gr_nb;
+  for (i=1; i<n; i++) {
+    if ( fabs(w[i].val - w[i-1].val) > 1e-14 ) { gr_nb++; }
+    gr[w[i].ind] = gr_nb;
+  }
+
+  igraph_Free(w);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+		
+
diff --git a/src/scg_headers.h b/src/scg_headers.h
new file mode 100644
index 0000000..8c79a4c
--- /dev/null
+++ b/src/scg_headers.h
@@ -0,0 +1,128 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    This file contains the headers of the library SCGlib.
+ *	  For use with R software <http://www.r-project.org/> define
+ *	  the constant R_COMPIL and refer to the R documentation to compile
+ *	  a dynamic library. The scg_r_wrapper function should be useful. 
+ */
+
+#ifndef SCG_HEADERS_H
+#define SCG_HEADERS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+
+typedef struct ind_val {
+  int ind;
+  igraph_real_t val;
+} igraph_i_scg_indval_t;
+
+int igraph_i_compare_ind_val(const void *a, const void *b);
+
+typedef struct groups{
+  int ind;
+  int n;
+  int* gr;
+} igraph_i_scg_groups_t;
+
+/*-------------------------------------------------
+------------DEFINED IN scg_approximate_methods.c---
+---------------------------------------------------*/	
+
+int igraph_i_breaks_computation(const igraph_vector_t *v,
+				igraph_vector_t *breaks, int nb, 
+				int method);
+int igraph_i_intervals_plus_kmeans(const igraph_vector_t *v, int *gr, 
+				   int n, int n_interv, 
+				   int maxiter);
+int igraph_i_intervals_method(const igraph_vector_t *v, int *gr, 
+			      int n, int n_interv);
+
+/*-------------------------------------------------
+------------DEFINED IN scg_optimal_method.c--------
+---------------------------------------------------*/	
+
+int igraph_i_cost_matrix(igraph_real_t *Cv, const igraph_i_scg_indval_t *vs, 
+			  int n, int matrix, const igraph_vector_t *ps);
+int igraph_i_optimal_partition(const igraph_real_t *v, int *gr, int n, int nt,
+			       int matrix, const igraph_real_t *p, 
+			       igraph_real_t *value);
+
+/*-------------------------------------------------
+------------DEFINED IN scg_kmeans.c----------------
+---------------------------------------------------*/
+
+int igraph_i_kmeans_Lloyd(const igraph_vector_t *x, int n,
+			  int p, igraph_vector_t *centers,
+			  int k, int *cl, int maxiter);
+
+/*-------------------------------------------------
+------------DEFINED IN scg_exact_scg.c-------------
+---------------------------------------------------*/
+
+int igraph_i_exact_coarse_graining(const igraph_real_t *v, int *gr, 
+				   int n);
+
+/*-------------------------------------------------
+------------DEFINED IN scg_utils.c-----------------
+---------------------------------------------------*/	
+
+int igraph_i_compare_groups(const void *a,const void *b);
+int igraph_i_compare_real(const void *a, const void *b);
+int igraph_i_compare_int(const void *a, const void *b);
+
+igraph_real_t *igraph_i_real_sym_matrix(int size);
+#define igraph_i_real_sym_mat_get(S,i,j) S[i+j*(j+1)/2]
+#define igraph_i_real_sym_mat_set(S,i,j,val) S[i+j*(j+1)/2] = val
+#define igraph_i_free_real_sym_matrix(S) igraph_Free(S)
+
+#endif
diff --git a/src/scg_kmeans.c b/src/scg_kmeans.c
new file mode 100644
index 0000000..c1c8c2f
--- /dev/null
+++ b/src/scg_kmeans.c
@@ -0,0 +1,93 @@
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    The kmeans_Lloyd function is adapted from the R-stats package.
+ *	  It perfoms Lloyd's k-means clustering on a p x n data matrix
+ *	  stored row-wise in a vector 'x'. 'cen' contains k initial centers.
+ *	  The group label to which each object belongs is stored in 'cl'.
+ *	  Labels are positive consecutive integers starting from 0.
+ *	  See also Section 5.3.3 of the above reference.
+ */
+
+#include "igraph_memory.h"
+ 
+#include "scg_headers.h"
+
+int igraph_i_kmeans_Lloyd(const igraph_vector_t *x, int n, int p, 
+			  igraph_vector_t *cen, int k, int *cl, int maxiter) {
+
+  int iter, i, j, c, it, inew = 0;
+  igraph_real_t best, dd, tmp;
+  int updated;
+  igraph_vector_int_t nc;
+  
+  IGRAPH_CHECK(igraph_vector_int_init(&nc, k));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &nc);
+  
+  for (i = 0; i < n; i++) { cl[i] = -1; }
+  for (iter = 0; iter < maxiter; iter++) {
+    updated = 0;
+    for (i = 0; i < n; i++) {
+      /* find nearest centre for each point */
+      best = IGRAPH_INFINITY;
+      for (j = 0; j < k; j++) {
+	dd = 0.0;
+	for (c = 0; c < p; c++) {
+	  tmp = VECTOR(*x)[i+n*c] - VECTOR(*cen)[j+k*c];
+	  dd += tmp * tmp;
+	}
+	if (dd < best) {
+	  best = dd;
+	  inew = j+1;
+	}
+      }
+      if (cl[i] != inew) {
+	updated = 1;
+	cl[i] = inew;
+      }
+    }
+    if (!updated) { break; }
+
+    /* update each centre */
+    for (j = 0; j < k*p; j++) { VECTOR(*cen)[j] = 0.0; }
+    for (j = 0; j < k; j++) { VECTOR(nc)[j] = 0; }
+    for (i = 0; i < n; i++) {
+      it = cl[i] - 1;
+      VECTOR(nc)[it]++;
+      for (c = 0; c < p; c++) { VECTOR(*cen)[it+c*k] += VECTOR(*x)[i+c*n]; }
+    }
+    for (j = 0; j < k*p; j++) { VECTOR(*cen)[j] /= VECTOR(nc)[j % k]; }
+  }
+  igraph_vector_int_destroy(&nc);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* convervenge check */
+  if (iter >= maxiter-1) { 
+    IGRAPH_ERROR("Lloyd k-means did not converge", IGRAPH_FAILURE);
+  }
+
+  return 0;
+}
+
diff --git a/src/scg_optimal_method.c b/src/scg_optimal_method.c
new file mode 100644
index 0000000..38fe958
--- /dev/null
+++ b/src/scg_optimal_method.c
@@ -0,0 +1,228 @@
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    This file implements algorithm 5.8 of the above reference.
+ *	  The optimal_partition function returns the minimizing partition
+ *	  with size 'nt' of the objective function ||v-Pv||, where P is
+ *	  a problem-specific projector. So far, Symmetric (matrix=1),
+ *	  Laplacian (matrix=2) and Stochastic (matrix=3) projectors
+ *	  have been implemented (the cost_matrix function below).
+ *	  In the stochastic case, 'p' is expected to be a valid propability
+ *	  vector. In all other cases, 'p' is ignored and can be set to NULL.
+ *	  The group labels are given in 'gr' as positive consecutive integers
+ *	  starting from 0.
+ */
+
+#include "igraph_error.h"
+#include "igraph_memory.h"
+#include "igraph_matrix.h"
+#include "igraph_vector.h"
+ 
+#include "scg_headers.h"
+
+int igraph_i_optimal_partition(const igraph_real_t *v, int *gr, int n, 
+			       int nt, int matrix, const igraph_real_t *p, 
+			       igraph_real_t *value) {
+
+  int i, non_ties, q, j, l, part_ind, col;
+  igraph_i_scg_indval_t *vs = igraph_Calloc(n, igraph_i_scg_indval_t);
+  igraph_real_t *Cv, temp, sumOfSquares;
+  igraph_vector_t ps;
+  igraph_matrix_t F;
+  igraph_matrix_int_t Q;
+
+  /*-----------------------------------------------
+    -----Sorts v and counts non-ties-----------------
+    -----------------------------------------------*/
+  
+  if (!vs) { 
+    IGRAPH_ERROR("SCG error", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, vs);
+  
+  for (i=0; i<n; i++) {
+    vs[i].val = v[i];
+    vs[i].ind = i;
+  }
+  
+  qsort(vs, (size_t) n, sizeof(igraph_i_scg_indval_t), 
+	igraph_i_compare_ind_val);
+  
+  non_ties = 1;
+  for (i=1; i<n; i++) {
+    if (vs[i].val < vs[i-1].val - 1e-14 ||
+	vs[i].val > vs[i-1].val + 1e-14) { non_ties++; }
+  }
+  
+  if (nt >= non_ties) {
+    IGRAPH_ERROR("`Invalid number of intervals, should be smaller than "
+		 "number of unique values in V", IGRAPH_EINVAL);
+  }
+	
+  /*------------------------------------------------
+    ------Computes Cv, the matrix of costs------------
+    ------------------------------------------------*/
+  Cv = igraph_i_real_sym_matrix(n);
+  if (!Cv) { 
+    IGRAPH_ERROR("SCG error", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, Cv);
+
+  /* if stochastic SCG orders p */
+  if (matrix==3) {
+    IGRAPH_VECTOR_INIT_FINALLY(&ps, n);
+    for (i=0; i<n; i++)
+      VECTOR(ps)[i] = p[vs[i].ind];
+  }
+    
+  IGRAPH_CHECK(igraph_i_cost_matrix(Cv, vs, n, matrix, &ps));
+  if (matrix==3) {
+    igraph_vector_destroy(&ps);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  /*-------------------------------------------------
+    -------Fills up matrices F and Q-------------------
+    -------------------------------------------------*/
+  /*here j also is a counter but the use of unsigned variables
+    is to be proscribed in "for (unsigned int j=...;j>=0;j--)",
+    for such loops never ends!*/
+  
+  IGRAPH_MATRIX_INIT_FINALLY(&F, nt, n);
+  IGRAPH_CHECK(igraph_matrix_int_init(&Q, nt, n));
+  IGRAPH_FINALLY(igraph_matrix_destroy, &Q);
+  
+  for (i=0; i<n; i++) MATRIX(Q, 0, i)++;
+  for (i=0; i<nt; i++) MATRIX(Q, i, i)=i+1;
+  
+  for (i=0; i<n; i++)
+    MATRIX(F, 0, i) = igraph_i_real_sym_mat_get(Cv,0,i);
+  
+  for (i=1; i<nt; i++)
+    for (j=i+1; j<n; j++) {
+      MATRIX(F, i, j) = MATRIX(F, i-1, i-1) + igraph_i_real_sym_mat_get(Cv,i,j);
+      MATRIX(Q, i, j) = 2;
+      
+      for (q=i-1; q<=j-1; q++) {
+	temp = MATRIX(F, i-1, q) + igraph_i_real_sym_mat_get(Cv,q+1,j);
+	if (temp < MATRIX(F, i, j)) {
+	  MATRIX(F, i, j) = temp;
+	  MATRIX(Q, i, j) = q+2;
+	}
+      }
+    }
+  igraph_i_free_real_sym_matrix(Cv);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /*--------------------------------------------------
+    -------Back-tracks through Q to work out the groups-
+    --------------------------------------------------*/
+  part_ind = nt;
+  col = n-1;
+
+  for (j=nt-1; j>=0; j--) {
+    for (i=MATRIX(Q, j, col)-1; i<=col; i++)
+      gr[vs[i].ind] = part_ind-1;
+    if (MATRIX(Q, j, col) != 2) {
+      col = MATRIX(Q, j, col)-2;
+      part_ind -= 1;
+    } else{
+      if (j>1) {
+	for (l=0; l<=(j-1); l++)
+	  gr[vs[l].ind] = l;
+	break;
+      } else{
+	col = MATRIX(Q, j, col)-2;
+	part_ind -= 1;
+      }
+    }
+  }
+  
+  sumOfSquares = MATRIX(F, nt-1, n-1);
+  
+  igraph_matrix_destroy(&F);
+  igraph_matrix_int_destroy(&Q);
+  igraph_Free(vs);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  if (value) { *value=sumOfSquares; }
+  return 0;
+}
+
+int igraph_i_cost_matrix(igraph_real_t*Cv, const igraph_i_scg_indval_t *vs,
+			  int n,  int matrix, const igraph_vector_t *ps) {
+
+    /* if symmetric of Laplacian SCG -> same Cv */
+    if (matrix==1 || matrix==2) {
+      int i,j;
+      igraph_vector_t w, w2;
+      
+      IGRAPH_VECTOR_INIT_FINALLY(&w, n+1);
+      IGRAPH_VECTOR_INIT_FINALLY(&w2, n+1);
+      
+      VECTOR(w)[1] = vs[0].val;
+      VECTOR(w2)[1] = vs[0].val*vs[0].val;
+      
+      for (i=2; i<=n; i++) {
+	VECTOR(w)[i] = VECTOR(w)[i-1] + vs[i-1].val;
+	VECTOR(w2)[i] = VECTOR(w2)[i-1] + vs[i-1].val*vs[i-1].val;
+      }
+      
+      for (i=0; i<n; i++) {
+	for (j=i+1; j<n; j++) {
+	  igraph_real_t v=(VECTOR(w2)[j+1]-VECTOR(w2)[i]) - 
+	    (VECTOR(w)[j+1]-VECTOR(w)[i]) * (VECTOR(w)[j+1]-VECTOR(w)[i]) / 
+	    (j-i+1);
+	    igraph_i_real_sym_mat_set(Cv, i, j, v);
+	}
+      }
+				    
+      igraph_vector_destroy(&w);
+      igraph_vector_destroy(&w2);
+      IGRAPH_FINALLY_CLEAN(2);
+    }
+    /* if stochastic */
+    /* TODO: optimize it to O(n^2) instead of O(n^3) (as above) */
+    if (matrix==3) {
+      int i,j,k;
+      igraph_real_t t1,t2;
+      for (i=0; i<n; i++) {
+	for (j=i+1; j<n; j++) {
+	  t1 = t2 = 0;
+	  for (k=i; k<j; k++) {
+	    t1 += VECTOR(*ps)[k];
+	    t2 += VECTOR(*ps)[k]*vs[k].val;
+	  }
+	  t1 = t2/t1;
+	  t2 = 0;
+	  for (k=i; k<j; k++)
+	    t2 += (vs[k].val-t1)*(vs[k].val-t1);
+	  igraph_i_real_sym_mat_set(Cv,i,j,t2);
+	}
+      }
+    }
+    
+    return 0;
+}
+
diff --git a/src/scg_utils.c b/src/scg_utils.c
new file mode 100644
index 0000000..59f16d9
--- /dev/null
+++ b/src/scg_utils.c
@@ -0,0 +1,92 @@
+/*
+ *  SCGlib : A C library for the spectral coarse graining of matrices
+ *	as described in the paper: Shrinking Matrices while preserving their
+ *	eigenpairs with Application to the Spectral Coarse Graining of Graphs.
+ *	Preprint available at <http://people.epfl.ch/david.morton>
+ *  
+ *	Copyright (C) 2008 David Morton de Lachapelle <david.morton at a3.epfl.ch>
+ *
+ *  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
+ *
+ *  DESCRIPTION
+ *	-----------
+ *    This files contains the data structures and error handing
+ *	  functions used throughout the SCGlib.  
+ */
+
+#include "igraph_error.h" 
+#include "igraph_memory.h"
+ 
+#include "scg_headers.h"
+
+/*to be used with qsort and struct ind_val arrays */  
+int igraph_i_compare_ind_val(const void *a, const void *b) {
+  igraph_i_scg_indval_t *arg1 = (igraph_i_scg_indval_t *) a;
+  igraph_i_scg_indval_t *arg2 = (igraph_i_scg_indval_t *) b;
+	
+  if ( arg1->val < arg2->val ) { 
+    return -1; 
+  } else if ( arg1->val == arg2->val ) {
+    return 0; 
+  } else {
+    return 1;
+  }
+}
+
+/*to be used with qsort and struct groups*/  
+int igraph_i_compare_groups(const void *a, const void *b) {
+  igraph_i_scg_groups_t *arg1 = (igraph_i_scg_groups_t *) a;
+  igraph_i_scg_groups_t *arg2 = (igraph_i_scg_groups_t *) b;
+  int i;
+  for (i=0; i<arg1->n; i++) {
+    if (arg1->gr[i]>arg2->gr[i]) return 1;
+    else if (arg1->gr[i]<arg2->gr[i]) return -1;
+  }
+  return 0;
+}
+
+/*to be used with qsort and real_vectors */  
+int igraph_i_compare_real(const void *a, const void *b) {
+  igraph_real_t arg1 = * (igraph_real_t *) a;
+  igraph_real_t arg2 = * (igraph_real_t *) b;
+  
+  if (arg1 < arg2) {
+    return -1;
+  } else if (arg1 == arg2) {
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
+/*to be used with qsort and integer vectors */ 
+int igraph_i_compare_int(const void *a, const void *b)
+{
+  int arg1 = * (int *) a;
+  int arg2 = * (int *) b;
+  return (arg1 -arg2);
+}
+
+/* allocate a igraph_real_t symmetrix matrix with dimension size x size 
+   in vector format*/ 
+igraph_real_t *igraph_i_real_sym_matrix(const int size)  { 
+  igraph_real_t *S = igraph_Calloc(size*(size+1)/2, igraph_real_t); 
+  if (!S) {
+    igraph_error("allocation failure in real_sym_matrix()",
+		 __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  }
+  return S;
+}
diff --git a/src/separators.c b/src/separators.c
new file mode 100644
index 0000000..a7f76d6
--- /dev/null
+++ b/src/separators.c
@@ -0,0 +1,814 @@
+/* -*- 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_separators.h"
+#include "igraph_memory.h"
+#include "igraph_adjlist.h"
+#include "igraph_dqueue.h"
+#include "igraph_vector.h"
+#include "igraph_interface.h"
+#include "igraph_flow.h"
+#include "igraph_flow_internal.h"
+#include "igraph_components.h"
+#include "igraph_structural.h"
+#include "igraph_constructors.h"
+#include "igraph_stack.h"
+#include "igraph_interrupt_internal.h"
+
+int igraph_i_is_separator(const igraph_t *graph,
+			  igraph_vit_t *vit,
+			  long int except,
+			  igraph_bool_t *res,
+			  igraph_vector_bool_t *removed,
+			  igraph_dqueue_t *Q,
+			  igraph_vector_t *neis,
+			  long int no_of_nodes) {
+
+  long int start=0;
+
+  if (IGRAPH_VIT_SIZE(*vit) >= no_of_nodes-1) {
+    /* Just need to check that we really have n-1 vertices in it */
+    igraph_vector_bool_t hit;
+    long int nohit=0;
+    IGRAPH_CHECK(igraph_vector_bool_init(&hit, no_of_nodes));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &hit);
+    for (IGRAPH_VIT_RESET(*vit); 
+	 !IGRAPH_VIT_END(*vit); 
+	 IGRAPH_VIT_NEXT(*vit)) {
+      long int v=IGRAPH_VIT_GET(*vit);
+      if (!VECTOR(hit)[v]) {
+	nohit++;
+	VECTOR(hit)[v] = 1;
+      }
+    }
+    igraph_vector_bool_destroy(&hit);
+    IGRAPH_FINALLY_CLEAN(1);
+    if (nohit == no_of_nodes-1) {
+      *res = 1;
+      return 0;
+    }
+  }
+  
+  /* Remove the given vertices from the graph, do a breadth-first
+     search and check the number of components */  
+
+  if (except < 0) {
+    for (IGRAPH_VIT_RESET(*vit); 
+	 !IGRAPH_VIT_END(*vit);
+	 IGRAPH_VIT_NEXT(*vit)) {
+      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
+    }
+  } else {
+    /* There is an exception */
+    long int i;
+    for (i=0, IGRAPH_VIT_RESET(*vit);
+	 i<except; 
+	 i++, IGRAPH_VIT_NEXT(*vit)) {
+      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
+    }
+    for (IGRAPH_VIT_NEXT(*vit); 
+	 !IGRAPH_VIT_END(*vit); 
+	 IGRAPH_VIT_NEXT(*vit)) {
+      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
+    }
+  }
+
+  /* Look for the first node that is not removed */
+  while (start < no_of_nodes && VECTOR(*removed)[start]) start++;
+  
+  if (start==no_of_nodes) { 
+    IGRAPH_ERROR("All vertices are included in the separator", 
+		 IGRAPH_EINVAL);
+  }
+  
+  igraph_dqueue_push(Q, start);
+  VECTOR(*removed)[start]=1;
+  while (!igraph_dqueue_empty(Q)) {
+    long int node=(long int) igraph_dqueue_pop(Q);
+    long int j, n;
+    igraph_neighbors(graph, neis, (igraph_integer_t) node, IGRAPH_ALL);
+    n=igraph_vector_size(neis);
+    for (j=0; j<n; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      if (!VECTOR(*removed)[nei]) {
+	IGRAPH_CHECK(igraph_dqueue_push(Q, nei));
+	VECTOR(*removed)[nei]=1;
+      }
+    }
+  }
+  
+  /* Look for the next node that was neighter removed, not visited */
+  while (start < no_of_nodes && VECTOR(*removed)[start]) start++;
+  
+  /* If there is another component, then we have a separator */
+  *res = (start < no_of_nodes);
+
+  return 0;
+}
+
+/**
+ * \function igraph_is_separator
+ * Decides whether the removal of a set of vertices disconnects the graph
+ * 
+ * \param graph The input graph. It may be directed, but edge
+ *        directions are ignored.
+ * \param condidate The candidate separator. It must not contain all
+ *        vertices.
+ * \param res Pointer to a boolean variable, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number vertices and edges.
+ * 
+ * \example examples/simple/igraph_is_separator.c
+ */
+
+int igraph_is_separator(const igraph_t *graph, 
+			const igraph_vs_t candidate,
+			igraph_bool_t *res) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_bool_t removed;
+  igraph_dqueue_t Q;
+  igraph_vector_t neis;
+  igraph_vit_t vit;
+
+  IGRAPH_CHECK(igraph_vit_create(graph, candidate, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  IGRAPH_CHECK(igraph_vector_bool_init(&removed, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed);
+  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  IGRAPH_CHECK(igraph_i_is_separator(graph, &vit, -1, res, &removed, 
+				     &Q, &neis, no_of_nodes));
+
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&Q);
+  igraph_vector_bool_destroy(&removed);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/**
+ * \function igraph_is_minimal_separator
+ * Decides whether a set of vertices is a minimal separator
+ * 
+ * A set of vertices is a minimal separator, if the removal of the
+ * vertices disconnects the graph, and this is not true for any subset
+ * of the set.
+ * 
+ * </para><para>This implementation first checks that the given
+ * candidate is a separator, by calling \ref
+ * igraph_is_separator(). If it is a separator, then it checks that
+ * each subset of size n-1, where n is the size of the candidate, is
+ * not a separator.
+ * \param graph The input graph. It may be directed, but edge
+ *        directions are ignored.
+ * \param candidate Pointer to a vector of long integers, the
+ *        candidate minimal separator.
+ * \param res Pointer to a boolean variable, the result is stored
+ *        here.
+ * \return Error code.
+ * 
+ * Time complexity: O(n(|V|+|E|)), |V| is the number of vertices, |E|
+ * is the number of edges, n is the number vertices in the candidate
+ * separator.
+ * 
+ * \example examples/simple/igraph_is_minimal_separator.c
+ */
+
+int igraph_is_minimal_separator(const igraph_t *graph,
+				const igraph_vs_t candidate, 
+				igraph_bool_t *res) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_bool_t removed;
+  igraph_dqueue_t Q;
+  igraph_vector_t neis;
+  long int candsize;
+  igraph_vit_t vit;
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, candidate, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  candsize=IGRAPH_VIT_SIZE(vit);
+
+  IGRAPH_CHECK(igraph_vector_bool_init(&removed, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed);
+  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  /* Is it a separator at all? */
+  IGRAPH_CHECK(igraph_i_is_separator(graph, &vit, -1, res, &removed, 
+				     &Q, &neis, no_of_nodes));
+  if (!(*res)) {
+    /* Not a separator at all, nothing to do, *res is already set */
+  } else if (candsize == 0) {
+    /* Nothing to do, minimal, *res is already set */
+  } else {
+    /* General case, we need to remove each vertex from 'candidate'
+     * and check whether the remainder is a separator. If this is
+     * false for all vertices, then 'candidate' is a minimal
+     * separator.
+     */
+    long int i;
+    for (i=0, *res=0; i<candsize && (!*res); i++) {
+      igraph_vector_bool_null(&removed);
+      IGRAPH_CHECK(igraph_i_is_separator(graph, &vit, i, res, &removed, 
+					 &Q, &neis, no_of_nodes));    
+    }
+    (*res) = (*res) ? 0 : 1;	/* opposite */
+  }
+  
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&Q);
+  igraph_vector_bool_destroy(&removed);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/* --------------------------------------------------------------------*/
+
+#define UPDATEMARK() do {                              \
+    (*mark)++;					       \
+    if (!(*mark)) {				       \
+      igraph_vector_null(leaveout);	               \
+      (*mark)=1;				       \
+    }                                                  \
+  } while (0)
+
+int igraph_i_clusters_leaveout(const igraph_adjlist_t *adjlist, 
+			       igraph_vector_t *components, 
+			       igraph_vector_t *leaveout, 
+			       unsigned long int *mark,
+			       igraph_dqueue_t *Q) {
+
+  /* Another trick: we use the same 'leaveout' vector to mark the
+   * vertices that were already found in the BFS 
+   */
+
+  long int i, no_of_nodes=igraph_adjlist_size(adjlist);
+  
+  igraph_dqueue_clear(Q);
+  igraph_vector_clear(components);
+
+  for (i=0; i<no_of_nodes; i++) {
+
+    if (VECTOR(*leaveout)[i] == *mark) continue;
+
+    VECTOR(*leaveout)[i]= *mark;
+    igraph_dqueue_push(Q, i);
+    igraph_vector_push_back(components, i);
+    
+    while (!igraph_dqueue_empty(Q)) {
+      long int act_node=(long int) igraph_dqueue_pop(Q);
+      igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, act_node);
+      long int j, n=igraph_vector_int_size(neis);
+      for (j=0; j<n; j++) {
+	long int nei=(long int) VECTOR(*neis)[j];
+	if (VECTOR(*leaveout)[nei]== *mark) continue;
+	IGRAPH_CHECK(igraph_dqueue_push(Q, nei));
+	VECTOR(*leaveout)[nei]= *mark;
+	igraph_vector_push_back(components, nei);
+      }
+    }
+    
+    igraph_vector_push_back(components, -1);
+  }
+  
+  UPDATEMARK();
+  
+  return 0;
+}
+
+igraph_bool_t igraph_i_separators_newsep(const igraph_vector_ptr_t *comps,
+					 const igraph_vector_t *newc) {
+
+  long int co, nocomps=igraph_vector_ptr_size(comps);
+  
+  for (co=0; co<nocomps; co++) {
+    igraph_vector_t *act=VECTOR(*comps)[co];
+    if (igraph_vector_all_e(act, newc)) return 0;
+  }
+
+  /* If not found, then it is new */
+  return 1;
+}
+
+int igraph_i_separators_store(igraph_vector_ptr_t *separators, 
+			      const igraph_adjlist_t *adjlist,
+			      igraph_vector_t *components, 
+			      igraph_vector_t *leaveout, 
+			      unsigned long int *mark, 
+			      igraph_vector_t *sorter) {
+  
+  /* We need to stote N(C), the neighborhood of C, but only if it is 
+   * not already stored among the separators.
+   */
+  
+  long int cptr=0, next, complen=igraph_vector_size(components);
+
+  while (cptr < complen) {
+    long int saved=cptr;
+    igraph_vector_clear(sorter);
+
+    /* Calculate N(C) for the next C */
+
+    while ( (next=(long int) VECTOR(*components)[cptr++]) != -1) {
+      VECTOR(*leaveout)[next] = *mark;
+    }
+    cptr=saved;
+
+    while ( (next=(long int) VECTOR(*components)[cptr++]) != -1) {
+      igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, next);
+      long int j, nn=igraph_vector_int_size(neis);
+      for (j=0; j<nn; j++) {
+	long int nei=(long int) VECTOR(*neis)[j];
+	if (VECTOR(*leaveout)[nei] != *mark) {
+	  igraph_vector_push_back(sorter, nei);
+	  VECTOR(*leaveout)[nei] = *mark;
+	}
+      }    
+    }
+    igraph_vector_sort(sorter);
+
+    UPDATEMARK();
+
+    /* Add it to the list of separators, if it is new */
+
+    if (igraph_i_separators_newsep(separators, sorter)) {
+      igraph_vector_t *newc=igraph_Calloc(1, igraph_vector_t);
+      if (!newc) {
+	IGRAPH_ERROR("Cannot calculate minimal separators", IGRAPH_ENOMEM);
+      }
+      IGRAPH_FINALLY(igraph_free, newc);
+      igraph_vector_copy(newc, sorter);
+      IGRAPH_FINALLY(igraph_vector_destroy, newc);
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(separators, newc));
+      IGRAPH_FINALLY_CLEAN(2);      
+    }
+  } /* while cptr < complen */
+
+  return 0;
+}
+
+void igraph_i_separators_free(igraph_vector_ptr_t *separators) {
+  long int i, n=igraph_vector_ptr_size(separators);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *vec=VECTOR(*separators)[i];
+    if (vec) {   
+      igraph_vector_destroy(vec);
+      igraph_Free(vec);
+    }
+  }
+}
+
+/**
+ * \function igraph_all_minimal_st_separators
+ * List all vertex sets that are minimal (s,t) separators for some s and t
+ * 
+ * This function lists all vertex sets that are minimal (s,t)
+ * separators for some (s,t) vertex pair.
+ * 
+ * </para><para>See more about the implemented algorithm in 
+ * 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): Graph-theoretic concepts in
+ * computer science, 1665, 167--172, 1999. Springer.
+ * 
+ * \param graph The input graph. It may be directed, but edge
+ *        directions are ignored.
+ * \param separators An initialized pointer vector, the separators
+ *        are stored here. It is a list of pointers to igraph_vector_t
+ *        objects. Each vector will contain the ids of the vertices in
+ *        the separator. 
+ *        To free all memory allocated for \c separators, you need call 
+ *        \ref igraph_vector_destroy() and then \ref igraph_free() on
+ *        each element, before destroying the pointer vector itself.
+ * \return Error code.
+ * 
+ * Time complexity: O(n|V|^3), |V| is the number of vertices, n is the
+ * number of separators.
+ * 
+ * \example examples/simple/igraph_minimal_separators.c
+ */
+
+int igraph_all_minimal_st_separators(const igraph_t *graph, 
+				     igraph_vector_ptr_t *separators) {
+
+  /* 
+   * Some notes about the tricks used here. For finding the components
+   * of the graph after removing some vertices, we do the
+   * following. First we mark the vertices with the actual mark stamp
+   * (mark), then run breadth-first search on the graph, but not
+   * considering the marked vertices. Then we increase the mark. If
+   * there is integer overflow here, then we zero out the mark and set
+   * it to one. (We might as well just always zero it out.)
+   * 
+   * For each separator the vertices are stored in vertex id order. 
+   * This facilitates the comparison of the separators when we find a
+   * potential new candidate. 
+   * 
+   * To keep track of which separator we already used as a basis, we
+   * keep a boolean vector (already_tried). The try_next pointer show
+   * the next separator to try as a basis.
+   */
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t leaveout;
+  igraph_vector_bool_t already_tried;
+  long int try_next=0;
+  unsigned long int mark=1;
+  long int v;
+  
+  igraph_adjlist_t adjlist;
+  igraph_vector_t components;
+  igraph_dqueue_t Q;
+  igraph_vector_t sorter;
+
+  igraph_vector_ptr_clear(separators);
+  IGRAPH_FINALLY(igraph_i_separators_free, separators);
+
+  IGRAPH_CHECK(igraph_vector_init(&leaveout, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_destroy, &leaveout);
+  IGRAPH_CHECK(igraph_vector_bool_init(&already_tried, 0));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &already_tried);
+  IGRAPH_CHECK(igraph_vector_init(&components, 0));
+  IGRAPH_FINALLY(igraph_vector_destroy, &components);
+  IGRAPH_CHECK(igraph_vector_reserve(&components, no_of_nodes*2));
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
+  IGRAPH_CHECK(igraph_vector_init(&sorter, 0));
+  IGRAPH_FINALLY(igraph_vector_destroy, &sorter);
+  IGRAPH_CHECK(igraph_vector_reserve(&sorter, no_of_nodes));
+  
+  /* --------------------------------------------------------------- 
+   * INITIALIZATION, we check whether the neighborhoods of the 
+   * vertices separate the graph. The ones that do will form the 
+   * initial basis.
+   */
+  
+  for (v=0; v<no_of_nodes; v++) {
+
+    /* Mark v and its neighbors */
+    igraph_vector_int_t *neis=igraph_adjlist_get(&adjlist, v);
+    long int i, n=igraph_vector_int_size(neis);
+    VECTOR(leaveout)[v]=mark;
+    for (i=0; i<n; i++) {
+      long int nei=(long int) VECTOR(*neis)[i];
+      VECTOR(leaveout)[nei]=mark;
+    }
+
+    /* Find the components */
+    IGRAPH_CHECK(igraph_i_clusters_leaveout(&adjlist, &components, &leaveout, 
+					    &mark, &Q));
+
+    /* Store the corresponding separators, N(C) for each component C */
+    IGRAPH_CHECK(igraph_i_separators_store(separators, &adjlist, &components, 
+					   &leaveout, &mark, &sorter));
+
+  }
+
+  /* ---------------------------------------------------------------
+   * GENERATION, we need to use all already found separators as
+   * basis and see if they generate more separators
+   */
+  
+  while (try_next < igraph_vector_ptr_size(separators)) {
+    igraph_vector_t *basis=VECTOR(*separators)[try_next];
+    long int b, basislen=igraph_vector_size(basis);
+    for (b=0; b<basislen; b++) {
+
+      /* Remove N(x) U basis */
+      long int x=(long int) VECTOR(*basis)[b];
+      igraph_vector_int_t *neis=igraph_adjlist_get(&adjlist, x);
+      long int i, n=igraph_vector_int_size(neis);
+      for (i=0; i<basislen; i++) {
+	long int sn=(long int) VECTOR(*basis)[i];
+	VECTOR(leaveout)[sn]=mark;
+      }
+      for (i=0; i<n; i++) {
+	long int nei=(long int) VECTOR(*neis)[i];
+	VECTOR(leaveout)[nei]=mark;
+      }
+      
+      /* Find the components */
+      IGRAPH_CHECK(igraph_i_clusters_leaveout(&adjlist, &components, 
+					      &leaveout, &mark, &Q));
+
+      /* Store the corresponding separators, N(C) for each component C */
+      IGRAPH_CHECK(igraph_i_separators_store(separators, &adjlist, 
+					     &components, &leaveout, &mark, 
+					     &sorter));
+    }
+    
+    try_next++;
+  }
+  
+  /* --------------------------------------------------------------- */
+
+  igraph_vector_destroy(&sorter);
+  igraph_dqueue_destroy(&Q);
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_destroy(&components);
+  igraph_vector_bool_destroy(&already_tried);
+  igraph_vector_destroy(&leaveout);
+  IGRAPH_FINALLY_CLEAN(7);	/* +1 for separators */
+
+  return 0;
+}
+
+#undef UPDATEMARK
+
+int igraph_i_minimum_size_separators_append(igraph_vector_ptr_t *old,
+					    igraph_vector_ptr_t *new) {
+
+  long int olen=igraph_vector_ptr_size(old);
+  long int nlen=igraph_vector_ptr_size(new);
+  long int i;
+  
+  for (i=0; i<nlen; i++) {
+    igraph_vector_t *newvec=VECTOR(*new)[i];
+    long int j;
+    for (j=0; j<olen; j++) {
+      igraph_vector_t *oldvec=VECTOR(*old)[j];
+      if (igraph_vector_all_e(oldvec, newvec)) { break; }
+    }
+    if (j==olen) {
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(old, newvec));
+      olen++;
+    } else {
+      igraph_vector_destroy(newvec);
+      igraph_free(newvec);
+    }
+    VECTOR(*new)[i]=0;
+  }
+  igraph_vector_ptr_clear(new);
+
+  return 0;
+}
+
+int igraph_i_minimum_size_separators_topkdeg(const igraph_t *graph, 
+					     igraph_vector_t *res,
+					     long int k) {
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t deg, order;
+  long int i;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);
+  IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(), IGRAPH_ALL, 
+			     /*loops=*/ 0));
+
+  IGRAPH_CHECK(igraph_vector_order1(&deg, &order, no_of_nodes));
+  IGRAPH_CHECK(igraph_vector_resize(res, k));
+  for (i=0; i<k; i++) {
+    VECTOR(*res)[i] = VECTOR(order)[no_of_nodes-1-i];
+  }
+  
+  igraph_vector_destroy(&order);
+  igraph_vector_destroy(&deg);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+void igraph_i_separators_stcuts_free(igraph_vector_ptr_t *p) {
+  long int i, n=igraph_vector_ptr_size(p);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*p)[i];
+    if (v) { 
+      igraph_vector_destroy(v);
+      igraph_free(v);
+      VECTOR(*p)[i]=0;
+    }
+  }
+  igraph_vector_ptr_destroy(p);
+}
+
+/** 
+ * \function igraph_minimum_size_separators
+ * Find all minimum size separating vertex sets
+ * 
+ * This function lists all separator vertex sets of minimum size. 
+ * A vertex set is a separator if its removal disconnects the graph.
+ * 
+ * </para><para>The implementation is based on the following paper:
+ * Arkady Kanevsky: Finding all minimum-size separating vertex sets in
+ * a graph, Networks 23, 533--541, 1993.
+ * 
+ * \param graph The input graph, it may be directed, but edge
+ *        directions will be ignored.
+ * \param separators An initialized pointer vector, the separators
+ *        are stored here. It is a list of pointers to igraph_vector_t
+ *        objects. Each vector will contain the ids of the vertices in
+ *        the separator. 
+ *        To free all memory allocated for \c separators, you need call 
+ *        \ref igraph_vector_destroy() and then \ref igraph_free() on
+ *        each element, before destroying the pointer vector itself.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_minimum_size_separators.c
+ */
+
+int igraph_minimum_size_separators(const igraph_t *graph,
+				   igraph_vector_ptr_t *separators) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_integer_t conn; long int k;  
+  igraph_vector_t X;
+  long int i, j;
+  igraph_bool_t issepX;
+  igraph_t Gbar;
+  igraph_vector_t phi;
+  igraph_t graph_copy;
+  igraph_vector_t capacity;
+  igraph_maxflow_stats_t stats;
+
+  igraph_vector_ptr_clear(separators);
+  IGRAPH_FINALLY(igraph_i_separators_free, separators);
+
+  /* ---------------------------------------------------------------- */
+  /* 1 Find the vertex connectivity of 'graph' */
+  IGRAPH_CHECK(igraph_vertex_connectivity(graph, &conn, 
+					  /* checks= */ 1)); k=conn;
+
+  /* Special cases for low connectivity, two exits here! */
+  if (conn==0) {
+    /* Nothing to do */
+    IGRAPH_FINALLY_CLEAN(1);	/* separators */
+    return 0;
+  } else if (conn==1) {
+    igraph_vector_t ap;
+    long int i, n;
+    IGRAPH_VECTOR_INIT_FINALLY(&ap, 0);
+    IGRAPH_CHECK(igraph_articulation_points(graph, &ap));
+    n=igraph_vector_size(&ap);
+    IGRAPH_CHECK(igraph_vector_ptr_resize(separators, n));
+    igraph_vector_ptr_null(separators);
+    for (i=0; i<n; i++) {
+      igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
+      if (!v) { 
+	IGRAPH_ERROR("Minimum size separators failed", IGRAPH_ENOMEM); 
+      }
+      IGRAPH_VECTOR_INIT_FINALLY(v, 1);
+      VECTOR(*v)[0] = VECTOR(ap)[i];
+      VECTOR(*separators)[i]=v;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    igraph_vector_destroy(&ap);
+    IGRAPH_FINALLY_CLEAN(2);	/* +1 for separators */
+    return 0;
+  } else if (conn==no_of_nodes-1) {
+    long int k;
+    IGRAPH_CHECK(igraph_vector_ptr_resize(separators, no_of_nodes));
+    igraph_vector_ptr_null(separators);
+    for (i=0; i<no_of_nodes; i++) {
+      igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
+      if (!v) {
+	IGRAPH_ERROR("Cannot list minimum size separators", IGRAPH_ENOMEM);
+      }
+      IGRAPH_VECTOR_INIT_FINALLY(v, no_of_nodes-1);
+      for (j=0, k=0; j<no_of_nodes; j++) {
+	if (j!=i) { VECTOR(*v)[k++] = j; }
+      }
+      VECTOR(*separators)[i]=v;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    IGRAPH_FINALLY_CLEAN(1);	/* separators */
+    return 0;
+  }
+
+  /* Work on a copy of 'graph' */
+  IGRAPH_CHECK(igraph_copy(&graph_copy, graph));
+  IGRAPH_FINALLY(igraph_destroy, &graph_copy);
+
+  /* ---------------------------------------------------------------- */
+  /* 2 Find k vertices with the largest degrees (x1;..,xk). Check
+     if these k vertices form a separating k-set of G */
+  IGRAPH_CHECK(igraph_vector_init(&X, conn));
+  IGRAPH_FINALLY(igraph_vector_destroy, &X);
+  IGRAPH_CHECK(igraph_i_minimum_size_separators_topkdeg(graph, &X, k));
+  IGRAPH_CHECK(igraph_is_separator(&graph_copy, igraph_vss_vector(&X), 
+				   &issepX));
+  if (issepX) {
+    igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
+    if (!v) { 
+      IGRAPH_ERROR("Cannot find minimal size separators", IGRAPH_ENOMEM);
+    }
+    IGRAPH_VECTOR_INIT_FINALLY(v, k);
+    for (i=0; i<k; i++) {
+      VECTOR(*v)[i] = VECTOR(X)[i];
+    }
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(separators, v));
+    IGRAPH_FINALLY_CLEAN(1);    
+  }
+
+  /* Create Gbar, the Even-Tarjan reduction of graph */
+  IGRAPH_VECTOR_INIT_FINALLY(&capacity, 0);
+  IGRAPH_CHECK(igraph_even_tarjan_reduction(&graph_copy, &Gbar, &capacity));
+  IGRAPH_FINALLY(igraph_destroy, &Gbar);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&phi, no_of_edges);
+  
+  /* ---------------------------------------------------------------- */  
+  /* 3 If v[j] != x[i] and v[j] is not adjacent to x[i] then */
+  for (i=0; i<k; i++) {
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    for (j=0; j<no_of_nodes; j++) {
+      long int ii=(long int) VECTOR(X)[i];
+      igraph_real_t phivalue;
+      igraph_bool_t conn;
+
+      if (ii == j) { continue; } /* the same vertex */
+      igraph_are_connected(&graph_copy, (igraph_integer_t) ii,  
+			   (igraph_integer_t) j, &conn);
+      if (conn) { continue; }	/* they are connected */
+
+      /* --------------------------------------------------------------- */  
+      /* 4 Compute a maximum flow phi in Gbar from x[i] to v[j].
+	 If |phi|=k, then */      
+      IGRAPH_CHECK(igraph_maxflow(&Gbar, &phivalue, &phi, /*cut=*/ 0, 
+				  /*partition=*/ 0, /*partition2=*/ 0, 
+				  /* source= */ 
+				  (igraph_integer_t) (ii+no_of_nodes),
+				  /* target= */ (igraph_integer_t) j,
+				  &capacity, &stats));
+
+      if (phivalue == k) {
+
+	/* ------------------------------------------------------------- */  
+	/* 5-6-7. Find all k-sets separating x[i] and v[j]. */
+	igraph_vector_ptr_t stcuts;
+	IGRAPH_CHECK(igraph_vector_ptr_init(&stcuts, 0));
+	IGRAPH_FINALLY(igraph_i_separators_stcuts_free, &stcuts);
+	IGRAPH_CHECK(igraph_all_st_mincuts(&Gbar, /*value=*/ 0, 
+					   /*cuts=*/ &stcuts,
+					   /*partition1s=*/ 0, 
+					   /*source=*/ (igraph_integer_t) 
+					   (ii+no_of_nodes),
+					   /*target=*/ (igraph_integer_t) j,
+					   /*capacity=*/ &capacity));
+
+	IGRAPH_CHECK(igraph_i_minimum_size_separators_append(separators,
+							     &stcuts));
+	igraph_vector_ptr_destroy(&stcuts);
+	IGRAPH_FINALLY_CLEAN(1);
+
+      }	/* if phivalue == k */
+      
+      /* --------------------------------------------------------------- */
+      /* 8 Add edge (x[i],v[j]) to G. */
+      IGRAPH_CHECK(igraph_add_edge(&graph_copy, (igraph_integer_t) ii, 
+				   (igraph_integer_t) j));
+      IGRAPH_CHECK(igraph_add_edge(&Gbar, (igraph_integer_t) (ii+no_of_nodes),
+				   (igraph_integer_t) j));
+      IGRAPH_CHECK(igraph_add_edge(&Gbar, (igraph_integer_t) (j+no_of_nodes),
+				   (igraph_integer_t) ii));
+      IGRAPH_CHECK(igraph_vector_push_back(&capacity, no_of_nodes));
+      IGRAPH_CHECK(igraph_vector_push_back(&capacity, no_of_nodes));
+      
+    } /* for j<no_of_nodes */
+  } /* for i<k */
+
+  igraph_vector_destroy(&phi);
+  igraph_destroy(&Gbar);
+  igraph_vector_destroy(&capacity);
+  igraph_vector_destroy(&X);
+  igraph_destroy(&graph_copy);
+  IGRAPH_FINALLY_CLEAN(6);	/* +1 for separators */
+  
+  return 0;
+}
diff --git a/src/sir.c b/src/sir.c
new file mode 100644
index 0000000..06da5ee
--- /dev/null
+++ b/src/sir.c
@@ -0,0 +1,257 @@
+/* -*- 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_epidemics.h"
+#include "igraph_random.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_psumtree.h"
+#include "igraph_memory.h"
+#include "igraph_structural.h"
+
+int igraph_sir_init(igraph_sir_t *sir) {
+  igraph_vector_init(&sir->times, 1);
+  IGRAPH_FINALLY(igraph_vector_destroy, &sir->times);
+  igraph_vector_int_init(&sir->no_s, 1);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &sir->no_s);
+  igraph_vector_int_init(&sir->no_i, 1);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &sir->no_i);
+  igraph_vector_int_init(&sir->no_r, 1);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+/**
+ * \function igraph_sir_destroy
+ * Deallocate memory associated with a SIR simulation run
+ *
+ * \param sir The \ref igraph_sir_t object storing the simulation.
+ */
+
+void igraph_sir_destroy(igraph_sir_t *sir) {
+  igraph_vector_destroy(&sir->times);
+  igraph_vector_int_destroy(&sir->no_s);
+  igraph_vector_int_destroy(&sir->no_i);
+  igraph_vector_int_destroy(&sir->no_r);
+}
+
+void igraph_i_sir_destroy(igraph_vector_ptr_t *v) {
+  int i, n=igraph_vector_ptr_size(v);
+  for (i=0; i<n; i++) {
+    igraph_sir_t *s=VECTOR(*v)[i];
+    if (s) {
+      igraph_sir_destroy(s);
+    }
+  }
+}
+
+#define S_S 0
+#define S_I 1
+#define S_R 2
+
+/** 
+ * \function igraph_sir
+ * Perform a number of SIR epidemics model runs 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. See these parameters below.
+ * 
+ * </para><para>
+ * This function runs multiple simulations, all starting with a 
+ * single uniformly randomly chosen infected individual.
+ * 
+ * \param graph The graph to perform the model on. For directed graphs 
+ *        edge directions are ignored and a warning is given.
+ * \param beta 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 The rate of recovery of an infected individual.
+ *        Formally, this is the rate parameter of an exponential
+ *        distribution.
+ * \param no_sim The number of simulation runs to perform.
+ * \param result The result of the simulation is stored here,
+ *        in a list of \ref igraph_sir_t objects. To deallocate
+ *        memory, the user needs to call \ref igraph_sir_destroy on
+ *        each element, before destroying the pointer vector itself.
+ * \return Error code.
+ * 
+ * Time complexity: O(no_sim * (|V| + |E| log(|V|))).
+ */
+
+int igraph_sir(const igraph_t *graph, igraph_real_t beta,
+	       igraph_real_t gamma, igraph_integer_t no_sim,
+	       igraph_vector_ptr_t *result) {
+
+  int infected;
+  igraph_vector_int_t status;
+  igraph_adjlist_t adjlist;
+  int no_of_nodes=igraph_vcount(graph);
+  int i, j, ns, ni, nr;
+  igraph_vector_int_t *neis;
+  igraph_psumtree_t tree;
+  igraph_real_t psum;
+  int neilen;
+  igraph_bool_t simple;
+
+  if (no_of_nodes==0) {
+    IGRAPH_ERROR("Cannot run SIR model on empty graph", IGRAPH_EINVAL);
+  }
+  if (igraph_is_directed(graph)) {
+    IGRAPH_WARNING("Edge directions are ignored in SIR model");
+  }
+  if (beta < 0) {
+    IGRAPH_ERROR("Beta must be non-negative in SIR model", IGRAPH_EINVAL);
+  }
+  if (gamma < 0) {
+    IGRAPH_ERROR("Gamma must be non-negative in SIR model", IGRAPH_EINVAL);
+  }
+  if (no_sim <= 0) {
+    IGRAPH_ERROR("Number of SIR simulations must be positive", IGRAPH_EINVAL);
+  }
+  
+  igraph_is_simple(graph, &simple);
+  if (!simple) {
+    IGRAPH_ERROR("SIR model only works with simple graphs", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_int_init(&status, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &status);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+  IGRAPH_CHECK(igraph_psumtree_init(&tree, no_of_nodes));
+  IGRAPH_FINALLY(igraph_psumtree_destroy, &tree);
+  
+  IGRAPH_CHECK(igraph_vector_ptr_resize(result, no_sim));
+  igraph_vector_ptr_null(result);
+  IGRAPH_FINALLY(igraph_i_sir_destroy, result);
+  for (i=0; i<no_sim; i++) {
+    igraph_sir_t *sir=igraph_Calloc(1, igraph_sir_t);
+    if (!sir) { IGRAPH_ERROR("Cannot run SIR model", IGRAPH_ENOMEM); }
+    igraph_sir_init(sir);
+    VECTOR(*result)[i]=sir;
+  }
+
+  RNG_BEGIN();
+
+  for (j = 0; j < no_sim; j++) {
+
+    igraph_sir_t *sir=VECTOR(*result)[j];
+    igraph_vector_t *times_v= &sir->times;
+    igraph_vector_int_t *no_s_v = &sir->no_s;
+    igraph_vector_int_t *no_i_v = &sir->no_i;
+    igraph_vector_int_t *no_r_v = &sir->no_r;
+
+    infected = RNG_INTEGER(0, no_of_nodes-1);
+  
+    /* Initially infected */
+    igraph_vector_int_null(&status);
+    VECTOR(status)[infected] = S_I;
+    ns = no_of_nodes - 1;
+    ni = 1;
+    nr = 0;
+    
+    VECTOR(*times_v)[0] = 0.0;
+    VECTOR(*no_s_v)[0]  = ns;
+    VECTOR(*no_i_v)[0]  = ni;
+    VECTOR(*no_r_v)[0]  = nr;
+    
+    if (igraph_psumtree_sum(&tree) != 0) { 
+      IGRAPH_ERROR("Internal SIR error", IGRAPH_EINTERNAL);
+    }
+    
+    /* Rates */
+    igraph_psumtree_update(&tree, infected, gamma);
+    neis=igraph_adjlist_get(&adjlist, infected);
+    neilen=igraph_vector_int_size(neis);
+    for (i=0; i<neilen; i++) {
+      int nei=VECTOR(*neis)[i];
+      igraph_psumtree_update(&tree, nei, beta);
+    }
+    psum=gamma + neilen * beta;	/* only works for simple graphs */
+  
+    while (psum > 0) {
+
+      igraph_real_t tt=igraph_rng_get_exp(igraph_rng_default(), psum);
+      igraph_real_t r=RNG_UNIF(0, psum);
+      long int vchange;
+
+      igraph_psumtree_search(&tree, &vchange, r);
+      neis=igraph_adjlist_get(&adjlist, vchange);
+      neilen=igraph_vector_int_size(neis);
+
+      if (VECTOR(status)[vchange] == S_I) {
+	VECTOR(status)[vchange] = S_R;
+	ni--; nr++;
+	psum -= igraph_psumtree_get(&tree, vchange);
+	igraph_psumtree_update(&tree, vchange, 0.0);
+	for (i=0; i<neilen; i++) {
+	  int nei=VECTOR(*neis)[i];
+	  if (VECTOR(status)[nei] == S_S) {
+	    igraph_real_t rate=igraph_psumtree_get(&tree, nei);
+	    psum -= beta;
+	    igraph_psumtree_update(&tree, nei, rate-beta);
+	  }
+	}
+
+      } else { /* S_S */
+	VECTOR(status)[vchange] = S_I;
+	ns--; ni++;
+	psum -= igraph_psumtree_get(&tree, vchange);
+	psum += gamma;
+	igraph_psumtree_update(&tree, vchange, gamma);
+	for (i=0; i<neilen; i++) {
+	  int nei=VECTOR(*neis)[i];
+	  if (VECTOR(status)[nei] == S_S) {
+	    igraph_real_t rate=igraph_psumtree_get(&tree, nei);
+	    psum += beta;
+	    igraph_psumtree_update(&tree, nei, rate + beta);
+	  }
+	}      
+      }
+    
+      if (times_v) {
+	igraph_vector_push_back(times_v, tt + igraph_vector_tail(times_v));
+      }
+      if (no_s_v)  { igraph_vector_int_push_back(no_s_v, ns); }    
+      if (no_i_v)  { igraph_vector_int_push_back(no_i_v, ni); }    
+      if (no_r_v)  { igraph_vector_int_push_back(no_r_v, nr); }    
+
+    } /* psum > 0 */
+
+  } /* j < no_sim */
+  
+  RNG_END();
+  
+  igraph_psumtree_destroy(&tree);
+  igraph_adjlist_destroy(&adjlist);
+  igraph_vector_int_destroy(&status);
+  IGRAPH_FINALLY_CLEAN(4);	/* + result */
+
+  return 0;
+}
diff --git a/src/spanning_trees.c b/src/spanning_trees.c
new file mode 100644
index 0000000..4873c28
--- /dev/null
+++ b/src/spanning_trees.c
@@ -0,0 +1,368 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   Copyright (C) 2011  Gabor Csardi <csardi.gabor at gmail.com>
+   Rue de l'Industrie 5, Lausanne 1005, Switzerland
+   
+   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_structural.h"
+#include "igraph_dqueue.h"
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_memory.h"
+#include "igraph_progress.h"
+#include "igraph_types_internal.h"
+
+int igraph_i_minimum_spanning_tree_unweighted(const igraph_t *graph,
+    igraph_vector_t *result);
+int igraph_i_minimum_spanning_tree_prim(const igraph_t *graph,
+    igraph_vector_t *result, const igraph_vector_t *weights);
+
+/**
+ * \ingroup structural
+ * \function igraph_minimum_spanning_tree
+ * \brief Calculates one minimum spanning tree of a graph.
+ * 
+ * </para><para>
+ * If the graph has more minimum spanning trees (this is always the
+ * case, except if it is a forest) this implementation returns only
+ * the same one.
+ * 
+ * </para><para>
+ * Directed graphs are considered as undirected for this computation.
+ *
+ * </para><para>
+ * If the graph is not connected then its minimum spanning forest is
+ * returned. This is the set of the minimum spanning trees of each
+ * component.
+ *
+ * \param graph The graph object.
+ * \param res An initialized vector, the IDs of the edges that constitute
+ *        a spanning tree will be returned here. Use
+ *        \ref igraph_subgraph_edges() to extract the spanning tree as
+ *        a separate graph object.
+ * \param weights A vector containing the weights of the edges
+ *        in the same order as the simple edge iterator visits them
+ *        (i.e. in increasing order of edge IDs).
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *
+ * Time complexity: O(|V|+|E|) for the unweighted case, O(|E| log |V|)
+ * for the weighted case. |V| is the number of vertices, |E| the
+ * number of edges in the graph. 
+ *
+ * \sa \ref igraph_minimum_spanning_tree_unweighted() and
+ *     \ref igraph_minimum_spanning_tree_prim() if you only need the
+ *     tree as a separate graph object.
+ * 
+ * \example examples/simple/igraph_minimum_spanning_tree.c
+ */
+int igraph_minimum_spanning_tree(const igraph_t* graph,
+    igraph_vector_t* res, const igraph_vector_t* weights) {
+  if (weights == 0)
+    IGRAPH_CHECK(igraph_i_minimum_spanning_tree_unweighted(graph, res));
+  else
+    IGRAPH_CHECK(igraph_i_minimum_spanning_tree_prim(graph, res, weights));
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_minimum_spanning_tree_unweighted
+ * \brief Calculates one minimum spanning tree of an unweighted graph.
+ * 
+ * </para><para>
+ * If the graph has more minimum spanning trees (this is always the
+ * case, except if it is a forest) this implementation returns only
+ * the same one.
+ * 
+ * </para><para>
+ * Directed graphs are considered as undirected for this computation.
+ *
+ * </para><para>
+ * If the graph is not connected then its minimum spanning forest is
+ * returned. This is the set of the minimum spanning trees of each
+ * component.
+ * \param graph The graph object.
+ * \param mst The minimum spanning tree, another graph object. Do
+ *        \em not initialize this object before passing it to
+ *        this function, but be sure to call \ref igraph_destroy() on it if
+ *        you don't need it any more.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *
+ * Time complexity: O(|V|+|E|),
+ * |V| is the 
+ * number of vertices, |E| the number
+ * of edges in the graph. 
+ *
+ * \sa \ref igraph_minimum_spanning_tree_prim() for weighted graphs,
+ *     \ref igraph_minimum_spanning_tree() if you need the IDs of the
+ *     edges that constitute the spanning tree.
+ */
+
+int igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, 
+					    igraph_t *mst) {
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, igraph_vcount(graph)-1);
+  IGRAPH_CHECK(igraph_i_minimum_spanning_tree_unweighted(graph, &edges));
+  IGRAPH_CHECK(igraph_subgraph_edges(graph, mst,
+        igraph_ess_vector(&edges), /* delete_vertices = */ 0));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_minimum_spanning_tree_prim
+ * \brief Calculates one minimum spanning tree of a weighted graph.
+ *
+ * </para><para>
+ * This function uses Prim's method for carrying out the computation,
+ * see Prim, R.C.: Shortest connection networks and some
+ * generalizations, Bell System Technical
+ * Journal, Vol. 36, 
+ * 1957, 1389--1401.
+ * 
+ * </para><para>
+ * If the graph has more than one minimum spanning tree, the current
+ * implementation returns always the same one.
+ *
+ * </para><para>
+ * Directed graphs are considered as undirected for this computation. 
+ * 
+ * </para><para>
+ * If the graph is not connected then its minimum spanning forest is
+ * returned. This is the set of the minimum spanning trees of each
+ * component.
+ * 
+ * \param graph The graph object.
+ * \param mst The result of the computation, a graph object containing
+ *        the minimum spanning tree of the graph.
+ *        Do \em not initialize this object before passing it to
+ *        this function, but be sure to call \ref igraph_destroy() on it if
+ *        you don't need it any more.
+ * \param weights A vector containing the weights of the edges
+ *        in the same order as the simple edge iterator visits them
+ *        (i.e. in increasing order of edge IDs).
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory.
+ *         \c IGRAPH_EINVAL, length of weight vector does not
+ *           match number of edges.
+ *
+ * Time complexity: O(|E| log |V|),
+ * |V| is the number of vertices,
+ * |E| the number of edges in the 
+ * graph. 
+ *
+ * \sa \ref igraph_minimum_spanning_tree_unweighted() for unweighted graphs,
+ *     \ref igraph_minimum_spanning_tree() if you need the IDs of the
+ *     edges that constitute the spanning tree.
+ * 
+ * \example examples/simple/igraph_minimum_spanning_tree.c
+ */
+
+int igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst,
+				      const igraph_vector_t *weights) {
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, igraph_vcount(graph)-1);
+  IGRAPH_CHECK(igraph_i_minimum_spanning_tree_prim(graph, &edges, weights));
+  IGRAPH_CHECK(igraph_subgraph_edges(graph, mst,
+        igraph_ess_vector(&edges), /* delete_vertices = */ 0));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+
+int igraph_i_minimum_spanning_tree_unweighted(const igraph_t* graph,
+    igraph_vector_t* res) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  char *already_added;
+  char *added_edges;
+  
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  igraph_vector_t tmp=IGRAPH_VECTOR_NULL;
+  long int i, j;
+
+  igraph_vector_clear(res);
+
+  added_edges=igraph_Calloc(no_of_edges, char);
+  if (added_edges==0) {
+    IGRAPH_ERROR("unweighted spanning tree failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added_edges);
+  already_added=igraph_Calloc(no_of_nodes, char);
+  if (already_added==0) {
+    IGRAPH_ERROR("unweighted spanning tree failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, already_added);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  
+  for (i=0; i<no_of_nodes; i++) {
+    if (already_added[i]>0) { continue; }
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    already_added[i]=1;
+    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
+    while (! igraph_dqueue_empty(&q)) {
+      long int act_node=(long int) igraph_dqueue_pop(&q);
+      IGRAPH_CHECK(igraph_incident(graph, &tmp, (igraph_integer_t) act_node,
+				   IGRAPH_ALL));
+      for (j=0; j<igraph_vector_size(&tmp); j++) {
+        long int edge=(long int) VECTOR(tmp)[j];
+        if (added_edges[edge]==0) {
+          igraph_integer_t from, to;
+          igraph_edge(graph, (igraph_integer_t) edge, &from, &to);
+          if (act_node==to) { to=from; }
+          if (already_added[(long int) to]==0) {
+            already_added[(long int) to]=1;
+            added_edges[edge]=1;
+            IGRAPH_CHECK(igraph_vector_push_back(res, edge));
+            IGRAPH_CHECK(igraph_dqueue_push(&q, to));
+          }
+        }
+      }
+    }
+  }
+  
+  igraph_dqueue_destroy(&q);
+  igraph_Free(already_added);
+  igraph_vector_destroy(&tmp);
+  igraph_Free(added_edges);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return IGRAPH_SUCCESS;
+}
+
+int igraph_i_minimum_spanning_tree_prim(const igraph_t* graph,
+    igraph_vector_t* res, const igraph_vector_t *weights) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  char *already_added;
+  char *added_edges;
+
+  igraph_d_indheap_t heap=IGRAPH_D_INDHEAP_NULL;
+  igraph_integer_t mode=IGRAPH_ALL;
+  
+  igraph_vector_t adj;
+
+  long int i, j;
+
+  igraph_vector_clear(res);
+
+  if (weights == 0)
+    return igraph_i_minimum_spanning_tree_unweighted(graph, res);
+
+  if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weights length", IGRAPH_EINVAL);
+  }
+
+  added_edges=igraph_Calloc(no_of_edges, char);
+  if (added_edges==0) {
+    IGRAPH_ERROR("prim spanning tree failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added_edges);
+  already_added=igraph_Calloc(no_of_nodes, char);
+  if (already_added == 0) {
+    IGRAPH_ERROR("prim spanning tree failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, already_added);
+  IGRAPH_CHECK(igraph_d_indheap_init(&heap, 0));
+  IGRAPH_FINALLY(igraph_d_indheap_destroy, &heap);
+  IGRAPH_VECTOR_INIT_FINALLY(&adj, 0);
+
+  for (i=0; i<no_of_nodes; i++) {
+    if (already_added[i]>0) { continue; }
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    already_added[i]=1;
+    /* add all edges of the first vertex */
+    igraph_incident(graph, &adj, (igraph_integer_t) i, (igraph_neimode_t) mode);
+    for (j=0; j<igraph_vector_size(&adj); j++) {
+      long int edgeno=(long int) VECTOR(adj)[j];
+      igraph_integer_t edgefrom, edgeto;
+      long int neighbor;
+      igraph_edge(graph, (igraph_integer_t) edgeno, &edgefrom, &edgeto);
+      neighbor= edgefrom != i ? edgefrom : edgeto;
+      if (already_added[neighbor] == 0) {
+	IGRAPH_CHECK(igraph_d_indheap_push(&heap, -VECTOR(*weights)[edgeno], i,
+					   edgeno));
+      }
+    }
+
+    while(! igraph_d_indheap_empty(&heap)) {
+      /* Get minimal edge */
+      long int from, edge;
+      igraph_integer_t tmp, to;
+      igraph_d_indheap_max_index(&heap, &from, &edge);
+      igraph_edge(graph, (igraph_integer_t) edge, &tmp, &to);
+      
+      /* Erase it */
+      igraph_d_indheap_delete_max(&heap);
+
+      /* Is this edge already included? */
+      if (added_edges[edge]==0) {
+        if (from==to) { to=tmp; }
+        /* Does it point to a visited node? */      
+        if (already_added[(long int)to]==0) {
+          already_added[(long int)to]=1;
+          added_edges[edge]=1;
+          IGRAPH_CHECK(igraph_vector_push_back(res, edge));
+          /* add all outgoing edges */
+          igraph_incident(graph, &adj, to, (igraph_neimode_t) mode);
+          for (j=0; j<igraph_vector_size(&adj); j++) {
+            long int edgeno=(long int) VECTOR(adj)[j];
+            igraph_integer_t edgefrom, edgeto;
+            long int neighbor;
+            igraph_edge(graph, (igraph_integer_t) edgeno, &edgefrom, &edgeto);
+            neighbor= edgefrom != to ? edgefrom : edgeto;
+            if (already_added[neighbor] == 0) {
+              IGRAPH_CHECK(igraph_d_indheap_push(&heap, -VECTOR(*weights)[edgeno], to,
+                   edgeno));
+            }
+          }
+        } /* for */
+      } /* if !already_added */
+    } /* while in the same component */
+  } /* for all nodes */
+
+  igraph_d_indheap_destroy(&heap);
+  igraph_Free(already_added);
+  igraph_vector_destroy(&adj);
+  igraph_Free(added_edges);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return IGRAPH_SUCCESS;
+}
+
+
diff --git a/src/sparsemat.c b/src/sparsemat.c
new file mode 100644
index 0000000..f96d022
--- /dev/null
+++ b/src/sparsemat.c
@@ -0,0 +1,2673 @@
+/* -*- 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
+
+*/
+
+#include "config.h"
+
+#include "cs/cs.h"
+
+#include "igraph_sparsemat.h"
+#include "igraph_error.h"
+#include "igraph_interface.h"
+#include "igraph_constructors.h"
+#include "igraph_memory.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_attributes.h"
+
+#include <string.h>
+
+/** 
+ * \section about_sparsemat About sparse matrices 
+ * 
+ * <para>
+ * The <code>igraph_sparsemat_t</code> data type stores sparse matrices, 
+ * i.e. matrices in which the majority of the elements are zero.
+ * </para>
+ *
+ * <para>The data type is essentially a wrapper to some of the
+ * functions in the CXSparse library, by Tim Davis, see
+ * http://www.cise.ufl.edu/research/sparse/CXSparse/
+ * </para>
+ * 
+ * <para>
+ * Matrices can be stored in two formats: triplet and
+ * column-compressed. The triplet format is intended for sparse matrix
+ * initialization, as it is easy to add new (non-zero) elements to
+ * it. Most of the computations are done on sparse matrices in
+ * column-compressed format, after the user has converted the triplet
+ * matrix to column-compressed, via \ref igraph_sparsemat_compress().
+ * </para>
+ * 
+ * <para>
+ * Both formats are dynamic, in the sense that new elements can be
+ * added to them, possibly resulting the allocation of more memory.
+ * </para>
+ * 
+ * <para>
+ * Row and column indices follow the C convention and are zero-based.
+ * </para>
+ * 
+ * <para>
+ * \example examples/simple/igraph_sparsemat.c
+ * \example examples/simple/igraph_sparsemat2.c
+ * \example examples/simple/igraph_sparsemat3.c
+ * \example examples/simple/igraph_sparsemat4.c
+ * \example examples/simple/igraph_sparsemat5.c
+ * \example examples/simple/igraph_sparsemat6.c
+ * \example examples/simple/igraph_sparsemat7.c
+ * \example examples/simple/igraph_sparsemat8.c
+ * </para>
+ */
+
+/**
+ * \function igraph_sparsemat_init
+ * Initialize a sparse matrix, in triplet format
+ * 
+ * This is the most common way to create a sparse matrix, together
+ * with the \ref igraph_sparsemat_entry() function, which can be used to
+ * add the non-zero elements one by one. Once done, the user can call
+ * \ref igraph_sparsemat_compress() to convert the matrix to
+ * column-compressed, to allow computations with it.
+ * 
+ * </para><para>The user must call \ref igraph_sparsemat_destroy() on
+ * the matrix to deallocate the memory, once the matrix is no more
+ * needed.
+ * \param A Pointer to a not yet initialized sparse matrix. 
+ * \param rows The number of rows in the matrix.
+ * \param cols The number of columns.
+ * \param nzmax The maximum number of non-zero elements in the
+ *    matrix. It is not compulsory to get this right, but it is
+ *    useful for the allocation of the proper amount of memory.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_init(igraph_sparsemat_t *A, int rows, int cols, int nzmax) {
+
+  if (rows < 0) { 
+    IGRAPH_ERROR("Negative number of rows", IGRAPH_EINVAL);
+  }
+  if (cols < 0) {
+    IGRAPH_ERROR("Negative number of columns", IGRAPH_EINVAL);
+  }
+  
+  A->cs=cs_spalloc( rows, cols, nzmax, /*values=*/ 1, 
+		  /*triplet=*/ 1);
+  if (!A->cs) {
+    IGRAPH_ERROR("Cannot allocate memory for sparse matrix", IGRAPH_ENOMEM);
+  }
+
+  return 0;
+}
+
+/** 
+ * \function igraph_sparsemat_copy
+ * Copy a sparse matrix
+ * 
+ * Create a sparse matrix object, by copying another one. The source
+ * matrix can be either in triplet or column-compressed format.
+ * 
+ * </para><para>
+ * Exactly the same amount of memory will be allocated to the
+ * copy matrix, as it is currently for the original one.
+ * \param to Pointer to an uninitialized sparse matrix, the copy will
+ *    be created here.
+ * \param from The sparse matrix to copy.
+ * \return Error code.
+ *
+ * Time complexity: O(n+nzmax), the number of columns plus the maximum
+ * number of non-zero elements.
+ */
+
+int igraph_sparsemat_copy(igraph_sparsemat_t *to, 
+			  const igraph_sparsemat_t *from) {
+
+  int ne=from->cs->nz == -1 ? from->cs->n+1 : from->cs->nzmax;
+
+  to->cs = cs_spalloc(from->cs->m, from->cs->n, from->cs->nzmax, 
+		      /*values=*/ 1, 
+		      /*triplet=*/ igraph_sparsemat_is_triplet(from));
+
+  to->cs->nzmax = from->cs->nzmax;
+  to->cs->m     = from->cs->m;
+  to->cs->n     = from->cs->n;
+  to->cs->nz    = from->cs->nz;
+
+  memcpy(to->cs->p, from->cs->p, sizeof(int) * (size_t) ne);
+  memcpy(to->cs->i, from->cs->i, sizeof(int) * (size_t) (from->cs->nzmax));
+  memcpy(to->cs->x, from->cs->x, sizeof(double) * (size_t) (from->cs->nzmax));
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_destroy
+ * Deallocate memory used by a sparse matrix
+ * 
+ * One destroyed, the sparse matrix must be initialized again, before
+ * calling any other operation on it.
+ * \param A The sparse matrix to destroy.
+ * 
+ * Time complexity: O(1).
+ */
+
+void igraph_sparsemat_destroy(igraph_sparsemat_t *A) {
+  cs_spfree(A->cs);
+}
+
+/**
+ * \function igraph_sparsemat_realloc
+ * Allocate more (or less) memory for a sparse matrix
+ * 
+ * Sparse matrices automatically allocate more memory, as needed. To
+ * control memory allocation, the user can call this function, to
+ * allocate memory for a given number of non-zero elements.
+ * \param A The sparse matrix, it can be in triplet or
+ *    column-compressed format.
+ * \param nzmax The new maximum number of non-zero elements.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_realloc(igraph_sparsemat_t *A, int nzmax) {
+  return !cs_sprealloc(A->cs, nzmax);
+}
+
+/**
+ * \function igraph_sparsemat_nrow
+ * Number of rows
+ * 
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \return The number of rows in the \p A matrix.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int igraph_sparsemat_nrow(const igraph_sparsemat_t *A) {
+  return A->cs->m;
+}
+
+/**
+ * \function igraph_sparsemat_ncol
+ * Number of columns.
+ * 
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \return The number of columns in the \p A matrix.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int igraph_sparsemat_ncol(const igraph_sparsemat_t *A) {
+  return A->cs->n;
+}
+
+/**
+ * \function igraph_sparsemat_type
+ * Type of a sparse matrix (triplet or column-compressed)
+ * 
+ * Gives whether a sparse matrix is stored in the triplet format or in
+ * column-compressed format.
+ * \param A The input matrix.
+ * \return Either \c IGRAPH_SPARSEMAT_CC or \c
+ * IGRAPH_SPARSEMAT_TRIPLET.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_sparsemat_type_t igraph_sparsemat_type(const igraph_sparsemat_t *A) {
+  return A->cs->nz < 0 ? IGRAPH_SPARSEMAT_CC : IGRAPH_SPARSEMAT_TRIPLET;
+}
+
+/**
+ * \function igraph_sparsemat_is_triplet
+ * Is this sparse matrix in triplet format?
+ * 
+ * Decides whether a sparse matrix is in triplet format. 
+ * \param A The input matrix.
+ * \return One if the input matrix is in triplet format, zero
+ * otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t igraph_sparsemat_is_triplet(const igraph_sparsemat_t *A) {
+  return A->cs->nz >= 0;
+}
+
+/**
+ * \function igraph_sparsemat_is_cc
+ * Is this sparse matrix in column-compressed format?
+ * 
+ * Decides whether a sparse matrix is in column-compressed format. 
+ * \param A The input matrix.
+ * \return One if the input matrix is in column-compressed format, zero
+ * otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t igraph_sparsemat_is_cc(const igraph_sparsemat_t *A) {
+  return A->cs->nz < 0;
+}
+
+/**
+ * \function igraph_sparsemat_permute
+ * Permute the rows and columns of a sparse matrix
+ * 
+ * \param A The input matrix, it must be in column-compressed format.
+ * \param p Integer vector, giving the permutation of the rows.
+ * \param q Integer vector, the permutation of the columns.
+ * \param res Pointer to an uninitialized sparse matrix, the result is
+ *   stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(m+n+nz), the number of rows plus the number of
+ * columns plus the number of non-zero elements in the matrix.
+ */
+
+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) {
+
+  long int nrow=A->cs->m, ncol=A->cs->n;
+  igraph_vector_int_t pinv;
+  long int i;
+
+  if (nrow != igraph_vector_int_size(p)) {
+    IGRAPH_ERROR("Invalid row permutation length", IGRAPH_FAILURE);
+  }
+  if (ncol != igraph_vector_int_size(q)) {
+    IGRAPH_ERROR("Invalid column permutation length", IGRAPH_FAILURE);
+  }
+
+  /* We invert the permutation by hand */
+  IGRAPH_CHECK(igraph_vector_int_init(&pinv, nrow));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &pinv);
+  for (i=0; i<nrow; i++) {
+    VECTOR(pinv)[ VECTOR(*p)[i] ] = (int) i;
+  }
+  
+  /* And call the permutation routine */
+  if (! (res->cs = cs_permute(A->cs, VECTOR(pinv), VECTOR(*q), /*values=*/ 1))) {
+    IGRAPH_ERROR("Cannot index sparse matrix", IGRAPH_FAILURE);
+  }
+  
+  igraph_vector_int_destroy(&pinv);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_index_rows(const igraph_sparsemat_t *A,
+				  const igraph_vector_int_t *p,
+				  igraph_sparsemat_t *res,
+				  igraph_real_t *constres) {
+
+  igraph_sparsemat_t II, II2;
+  long int nrow=A->cs->m;
+  long int idx_rows=igraph_vector_int_size(p);
+  long int k;
+
+  /* Create index matrix */
+  IGRAPH_CHECK(igraph_sparsemat_init(&II2, (int) idx_rows, (int) nrow, 
+				     (int) idx_rows));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &II2);
+  for (k=0; k<idx_rows; k++) {
+    igraph_sparsemat_entry(&II2, (int) k, VECTOR(*p)[k], 1.0);
+  }
+  IGRAPH_CHECK(igraph_sparsemat_compress(&II2, &II));
+  igraph_sparsemat_destroy(&II2);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &II);
+  
+  /* Multiply */
+  IGRAPH_CHECK(igraph_sparsemat_multiply(&II, A, res));
+  igraph_sparsemat_destroy(&II);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  if (constres) {
+    if (res->cs->p[1] != 0) {
+      *constres = res->cs->x[0];
+    } else {
+      *constres = 0.0;
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_sparsemat_index_cols(const igraph_sparsemat_t *A,
+				  const igraph_vector_int_t *q,
+				  igraph_sparsemat_t *res,
+				  igraph_real_t *constres) {
+
+  igraph_sparsemat_t JJ, JJ2;
+  long int ncol=A->cs->n;
+  long int idx_cols=igraph_vector_int_size(q);
+  long int k;
+  
+  /* Create index matrix */
+  IGRAPH_CHECK(igraph_sparsemat_init(&JJ2, (int) ncol, (int) idx_cols, 
+				     (int) idx_cols));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &JJ2);
+  for (k=0; k<idx_cols; k++) {
+    igraph_sparsemat_entry(&JJ2, VECTOR(*q)[k], (int) k, 1.0);
+  }
+  IGRAPH_CHECK(igraph_sparsemat_compress(&JJ2, &JJ));
+  igraph_sparsemat_destroy(&JJ2);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &JJ);
+
+  /* Multiply */
+  IGRAPH_CHECK(igraph_sparsemat_multiply(A, &JJ, res));
+  igraph_sparsemat_destroy(&JJ);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  if (constres) {
+    if (res->cs->p [1] != 0) {
+      *constres = res->cs->x [0];
+    } else {
+      *constres = 0.0;
+    }
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_index
+ * Index a sparse matrix, extract a submatrix, or a single element
+ * 
+ * This function serves two purposes. First, it can extract
+ * submatrices from a sparse matrix. Second, as a special case, it can
+ * extract a single element from a sparse matrix.
+ * \param A The input matrix, it must be in column-compressed format.
+ * \param p An integer vector, or a null pointer. The selected row
+ *    index or indices. A null pointer selects all rows.
+ * \param q An integer vector, or a null pointer. The selected column
+ *    index or indices. A null pointer selects all columns.
+ * \param res Pointer to an uninitialized sparse matrix, or a null
+ *    pointer. If not a null pointer, then the selected submatrix is
+ *    stored here.
+ * \param constres Pointer to a real variable or a null pointer. If
+ *    not a null pointer, then the first non-zero element in the
+ *    selected submatrix is stored here, if there is one. Otherwise
+ *    zero is stored here. This behavior is handy if one
+ *    wants to select a single entry from the matrix.
+ * \return Error code.
+ *
+ * Time complexity: TODO.
+ */
+
+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) {
+
+  igraph_sparsemat_t II, JJ, II2, JJ2, tmp;
+  long int nrow=A->cs->m;
+  long int ncol=A->cs->n;
+  long int idx_rows= p ? igraph_vector_int_size(p) : -1;
+  long int idx_cols= q ? igraph_vector_int_size(q) : -1;
+  long int k;
+
+  igraph_sparsemat_t *myres=res, mres;
+
+  if (!p && !q) {
+    IGRAPH_ERROR("No index vectors", IGRAPH_EINVAL);
+  }
+
+  if (!res && (idx_rows != 1 || idx_cols != 1)) {
+    IGRAPH_ERROR("Sparse matrix indexing: must give `res' if not a "
+		 "single element is selected", IGRAPH_EINVAL);
+  }
+
+  if (!q) {
+    return igraph_i_sparsemat_index_rows(A, p, res, constres);
+  }
+  if (!p) {
+    return igraph_i_sparsemat_index_cols(A, q, res, constres);
+  }
+
+  if (!res) {
+    myres=&mres;
+  }
+
+  /* Create first index matrix */
+  IGRAPH_CHECK(igraph_sparsemat_init(&II2, (int) idx_rows, (int) nrow, 
+				     (int) idx_rows));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &II2);
+  for (k=0; k<idx_rows; k++) {
+    igraph_sparsemat_entry(&II2, (int) k, VECTOR(*p)[k], 1.0);
+  }
+  IGRAPH_CHECK(igraph_sparsemat_compress(&II2, &II));
+  igraph_sparsemat_destroy(&II2);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &II);
+
+  /* Create second index matrix */
+  IGRAPH_CHECK(igraph_sparsemat_init(&JJ2, (int) ncol, (int) idx_cols, 
+				     (int) idx_cols));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &JJ2);
+  for (k=0; k<idx_cols; k++) {
+    igraph_sparsemat_entry(&JJ2, VECTOR(*q)[k], (int) k, 1.0);
+  }
+  IGRAPH_CHECK(igraph_sparsemat_compress(&JJ2, &JJ));
+  igraph_sparsemat_destroy(&JJ2);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &JJ);
+  
+  /* Multiply */
+  IGRAPH_CHECK(igraph_sparsemat_multiply(&II, A, &tmp));
+  igraph_sparsemat_destroy(&II);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmp);
+  IGRAPH_CHECK(igraph_sparsemat_multiply(&tmp, &JJ, myres));
+  igraph_sparsemat_destroy(&tmp);
+  igraph_sparsemat_destroy(&JJ);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (constres) {
+    if (myres->cs->p [1] != 0) {
+      *constres = myres->cs->x [0];
+    } else {
+      *constres = 0.0;
+    }
+  }
+
+  if (!res) {
+    igraph_sparsemat_destroy(myres);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_entry
+ * Add an element to a sparse matrix
+ * 
+ * This function can be used to add the entries to a sparse matrix,
+ * after initializing it with \ref igraph_sparsemat_init().
+ * \param A The input matrix, it must be in triplet format.
+ * \param row The row index of the entry to add.
+ * \param col The column index of the entry to add.
+ * \param elem The value of the entry.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_entry(igraph_sparsemat_t *A, int row, int col, 
+			   igraph_real_t elem) {
+  
+  if (!cs_entry(A->cs, row, col, elem)) {
+    IGRAPH_ERROR("Cannot add entry to sparse matrix", 
+		 IGRAPH_FAILURE);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_compress
+ * Compress a sparse matrix, i.e. convert it to column-compress format
+ * 
+ * Almost all sparse matrix operations require that the matrix is in
+ * column-compressed format.
+ * \param A The input matrix, it must be in triplet format.
+ * \param res Pointer to an uninitialized sparse matrix object, the
+ *    compressed version of \p A is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_compress(const igraph_sparsemat_t *A, 
+			      igraph_sparsemat_t *res) {
+
+  if (! (res->cs=cs_compress(A->cs)) ) {
+    IGRAPH_ERROR("Cannot compress sparse matrix", IGRAPH_FAILURE);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_transpose
+ * Transpose a sparse matrix
+ * 
+ * \param A The input matrix, column-compressed or triple format.
+ * \param res Pointer to an uninitialized sparse matrix, the result is
+ *    stored here.
+ * \param values If this is non-zero, the matrix transpose is
+ *    calculated the normal way. If it is zero, then only the pattern
+ *    of the input matrix is stored in the result, the values are not.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_transpose(const igraph_sparsemat_t *A, 
+			       igraph_sparsemat_t *res, 
+			       int values) {
+
+  if (A->cs->nz < 0) {
+    /* column-compressed */
+    if (! (res->cs=cs_transpose(A->cs, values)) ) {
+      IGRAPH_ERROR("Cannot transpose sparse matrix", IGRAPH_FAILURE); 
+    }
+  } else {
+    /* triplets */
+    int *tmp;
+    IGRAPH_CHECK(igraph_sparsemat_copy(res, A));
+    tmp = res->cs->p;
+    res->cs->p = res->cs->i;
+    res->cs->i = tmp;
+  }
+  return 0;
+}
+
+igraph_bool_t 
+igraph_i_sparsemat_is_symmetric_cc(const igraph_sparsemat_t *A) {
+  igraph_sparsemat_t t, tt;
+  igraph_bool_t res;
+  int nz;
+
+  IGRAPH_CHECK(igraph_sparsemat_transpose(A, &t, /*values=*/ 1));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &t);
+  IGRAPH_CHECK(igraph_sparsemat_dupl(&t));
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&t, &tt, /*values=*/ 1));
+  igraph_sparsemat_destroy(&t);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tt);
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&tt, &t, /*values=*/ 1));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &t);
+
+  nz=t.cs->p[t.cs->n];
+  res = memcmp(t.cs->i, tt.cs->i, sizeof(int) * (size_t) nz) == 0;
+  res = res && memcmp(t.cs->p, tt.cs->p, sizeof(int) *
+		      (size_t)(t.cs->n+1)) == 0;
+  res = res && memcmp(t.cs->x, tt.cs->x, sizeof(igraph_real_t) * (size_t)nz)==0;
+
+  igraph_sparsemat_destroy(&t);
+  igraph_sparsemat_destroy(&tt);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return res;
+}
+
+igraph_bool_t 
+igraph_i_sparsemat_is_symmetric_triplet(const igraph_sparsemat_t *A) {
+  igraph_sparsemat_t tmp;
+  igraph_bool_t res;
+  IGRAPH_CHECK(igraph_sparsemat_compress(A, &tmp));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmp);
+  res=igraph_i_sparsemat_is_symmetric_cc(&tmp);
+  igraph_sparsemat_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  return res;
+}
+
+igraph_bool_t igraph_sparsemat_is_symmetric(const igraph_sparsemat_t *A) {
+
+  if (A->cs->m != A->cs->n) { return 0; }
+
+  if (A->cs->nz < 0) {
+    return igraph_i_sparsemat_is_symmetric_cc(A);
+  } else {
+    return igraph_i_sparsemat_is_symmetric_triplet(A);
+  }
+}
+
+/**
+ * \function igraph_sparsemat_dupl
+ * Remove duplicate elements from a sparse matrix
+ * 
+ * It is possible that a column-compressed sparse matrix stores a
+ * single matrix entry in multiple pieces. The entry is then the sum
+ * of all its pieces. (Some functions create matrices like this.) This
+ * function eliminates the multiple pieces.
+ * \param A The input matrix, in column-compressed format.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_dupl(igraph_sparsemat_t *A) {
+
+  if (!cs_dupl(A->cs)) {
+    IGRAPH_ERROR("Cannot remove duplicates from sparse matrix", 
+		 IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_fkeep
+ * Filter the elements of a sparse matrix
+ * 
+ * This function can be used to filter the (non-zero) elements of a
+ * sparse matrix. For all entries, it calls the supplied function and
+ * depending on the return values either keeps, or deleted the element
+ * from the matrix.
+ * \param A The input matrix, in column-compressed format.
+ * \param fkeep The filter function. It must take four arguments: the
+ *    first is an \c int, the row index of the entry, the second is 
+ *    another \c int, the column index. The third is \c igraph_real_t,
+ *    the value of the entry. The fourth element is a \c void pointer,
+ *    the \p other argument is passed here. The function must return
+ *    an \c int. If this is zero, then the entry is deleted, otherwise
+ *    it is kept.
+ * \param other A \c void pointer that is passed to the filtering
+ * function.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_fkeep(igraph_sparsemat_t *A, 
+			   int (*fkeep)(int, int, igraph_real_t, void*),
+			   void *other) {
+  
+  if (!cs_fkeep(A->cs, fkeep, other)) {
+    IGRAPH_ERROR("Cannot filter sparse matrix", IGRAPH_FAILURE);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_dropzeros
+ * Drop the zero elements from a sparse matrix
+ * 
+ * As a result of matrix operations, some of the entries in a sparse
+ * matrix might be zero. This function removes these entries.
+ * \param A The input matrix, it must be in column-compressed format.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_dropzeros(igraph_sparsemat_t *A) {
+
+  if (!cs_dropzeros(A->cs)) {
+    IGRAPH_ERROR("Cannot drop zeros from sparse matrix", IGRAPH_FAILURE);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_droptol
+ * Drop the almost zero elements of a sparse matrix
+ * 
+ * This function is similar to \ref igraph_sparsemat_dropzeros(), but it
+ * also drops entries that are closer to zero than the given tolerance
+ * threshold.
+ * \param A The input matrix, it must be in column-compressed format.
+ * \param tol Real number, giving the tolerance threshold.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_droptol(igraph_sparsemat_t *A, igraph_real_t tol) {
+  
+  if (!cs_droptol(A->cs, tol)) {
+    IGRAPH_ERROR("Cannot drop (almost) zeros from sparse matrix", 
+		 IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_multiply
+ * Matrix multiplication
+ * 
+ * Multiplies two sparse matrices.
+ * \param A The first input matrix (left hand side), in
+ *   column-compressed format.
+ * \param B The second input matrix (right hand side), in
+ *   column-compressed format.
+ * \param res Pointer to an uninitialized sparse matrix, the result is
+ *   stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_multiply(const igraph_sparsemat_t *A,
+			      const igraph_sparsemat_t *B,
+			      igraph_sparsemat_t *res) {
+
+  if (! (res->cs=cs_multiply(A->cs, B->cs))) {
+    IGRAPH_ERROR("Cannot multiply matrices", IGRAPH_FAILURE);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_add
+ * Sum of two sparse matrices
+ * 
+ * \param A The first input matrix, in column-compressed format.
+ * \param B The second input matrix, in column-compressed format.
+ * \param alpha Real scalar, \p A is multiplied by \p alpha before the
+ *    addition. 
+ * \param beta Real scalar, \p B is multiplied by \p beta before the
+ *    addition. 
+ * \param res Pointer to an uninitialized sparse matrix, the result
+ *    is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+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) {
+
+  if (! (res->cs=cs_add(A->cs, B->cs, alpha, beta))) {
+    IGRAPH_ERROR("Cannot add matrices", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_gaxpy
+ * Matrix-vector product, added to another vector.
+ * 
+ * \param A The input matrix, in column-compressed format.
+ * \param x The input vector, its size must match the number of
+ *    columns in \p A.
+ * \param res This vector is added to the matrix-vector product 
+ *    and it is overwritten by the result.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_gaxpy(const igraph_sparsemat_t *A,
+			   const igraph_vector_t *x,
+			   igraph_vector_t *res) {
+
+  if (A->cs->n != igraph_vector_size(x) || 
+      A->cs->m != igraph_vector_size(res)) {
+    IGRAPH_ERROR("Invalid matrix/vector size for multiplication",
+		 IGRAPH_EINVAL);
+  }
+  
+  if (! (cs_gaxpy(A->cs, VECTOR(*x), VECTOR(*res)))) {
+    IGRAPH_ERROR("Cannot perform sparse matrix vector multiplication",
+		 IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_lsolve
+ * Solve a lower-triangular linear system
+ * 
+ * Solve the Lx=b linear equation system, where the L coefficient
+ * matrix is square and lower-triangular, with a zero-free diagonal.
+ * \param L The input matrix, in column-compressed format.
+ * \param b The right hand side of the linear system.
+ * \param res An initialized vector, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_lsolve(const igraph_sparsemat_t *L,
+			    const igraph_vector_t *b,
+			    igraph_vector_t *res) {
+
+  if (L->cs->m != L->cs->n) {
+    IGRAPH_ERROR("Cannot perform lower triangular solve", IGRAPH_NONSQUARE);
+  }
+
+  if (res != b) {
+    IGRAPH_CHECK(igraph_vector_update(res, b));
+  }
+
+  if (! cs_lsolve(L->cs, VECTOR(*res))) {
+    IGRAPH_ERROR("Cannot perform lower triangular solve", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_ltsolve
+ * Solve an upper-triangular linear system
+ * 
+ * Solve the L'x=b linear equation system, where the L
+ * matrix is square and lower-triangular, with a zero-free diagonal.
+ * \param L The input matrix, in column-compressed format.
+ * \param b The right hand side of the linear system.
+ * \param res An initialized vector, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_ltsolve(const igraph_sparsemat_t *L,
+			     const igraph_vector_t *b,
+			     igraph_vector_t *res) {
+  
+  if (L->cs->m != L->cs->n) {
+    IGRAPH_ERROR("Cannot perform transposed lower triangular solve",
+		 IGRAPH_NONSQUARE);
+  }
+  
+  if (res != b) {
+    IGRAPH_CHECK(igraph_vector_update(res,b));
+  }
+
+  if (!cs_ltsolve(L->cs, VECTOR(*res))) {
+    IGRAPH_ERROR("Cannot perform lower triangular solve", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_usolve
+ * Solve an upper-triangular linear system
+ * 
+ * Solves the Ux=b upper triangular system.
+ * \param U The input matrix, in column-compressed format.
+ * \param b The right hand side of the linear system.
+ * \param res An initialized vector, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_usolve(const igraph_sparsemat_t *U,
+			    const igraph_vector_t *b,
+			    igraph_vector_t *res) {
+
+  if (U->cs->m != U->cs->n) {
+    IGRAPH_ERROR("Cannot perform upper triangular solve", IGRAPH_NONSQUARE);
+  }
+
+  if (res != b) {
+    IGRAPH_CHECK(igraph_vector_update(res, b));
+  }
+
+  if (! cs_usolve(U->cs, VECTOR(*res))) {
+    IGRAPH_ERROR("Cannot perform upper triangular solve", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_utsolve
+ * Solve a lower-triangular linear system
+ * 
+ * This is the same as \ref igraph_sparsemat_usolve(), but U'x=b is
+ * solved, where the apostrophe denotes the transpose.
+ * \param U The input matrix, in column-compressed format.
+ * \param b The right hand side of the linear system.
+ * \param res An initialized vector, the result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_utsolve(const igraph_sparsemat_t *U,
+			     const igraph_vector_t *b,
+			     igraph_vector_t *res) {
+  
+  if (U->cs->m != U->cs->n) {
+    IGRAPH_ERROR("Cannot perform transposed upper triangular solve",
+		 IGRAPH_NONSQUARE);
+  }
+
+  if (res != b) { 
+    IGRAPH_CHECK(igraph_vector_update(res,b));
+  }
+
+  if (!cs_utsolve(U->cs, VECTOR(*res))) {
+    IGRAPH_ERROR("Cannot perform transposed upper triangular solve", 
+		 IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_sparsemat_cholsol
+ * Solve a symmetric linear system via Cholesky decomposition
+ * 
+ * Solve Ax=b, where A is a symmetric positive definite matrix.
+ * \param A The input matrix, in column-compressed format.
+ * \param v The right hand side.
+ * \param res An initialized vector, the result is stored here.
+ * \param order An integer giving the ordering method to use for the
+ *    factorization. Zero is the natural ordering; if it is one, then
+ *    the fill-reducing minimum-degree ordering of A+A' is used.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_cholsol(const igraph_sparsemat_t *A,
+			     const igraph_vector_t *b,
+			     igraph_vector_t *res, 
+			     int order) {
+  
+  if (A->cs->m != A->cs->n) {
+    IGRAPH_ERROR("Cannot perform sparse symmetric solve",
+		 IGRAPH_NONSQUARE);
+  }
+
+  if (res != b) { 
+    IGRAPH_CHECK(igraph_vector_update(res,b));
+  }
+
+  if (! cs_cholsol(order, A->cs, VECTOR(*res))) {
+    IGRAPH_ERROR("Cannot perform sparse symmetric solve", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_lusol
+ * Solve a linear system via LU decomposition
+ * 
+ * Solve Ax=b, via LU factorization of A.
+ * \param A The input matrix, in column-compressed format.
+ * \param b The right hand side of the equation.
+ * \param res An initialized vector, the result is stored here.
+ * \param order The ordering method to use, zero means the natural
+ *    ordering, one means the fill-reducing minimum-degree ordering of
+ *    A+A', two means the ordering of A'*A, after removing the dense
+ *    rows from A. Three means the ordering of A'*A.
+ * \param tol Real number, the tolerance limit to use for the numeric
+ *    LU factorization.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_lusol(const igraph_sparsemat_t *A,
+			   const igraph_vector_t *b,
+			   igraph_vector_t *res,
+			   int order,
+			   igraph_real_t tol) {
+  
+  if (A->cs->m != A->cs->n) {
+    IGRAPH_ERROR("Cannot perform LU solve",
+		 IGRAPH_NONSQUARE);
+  }
+
+  if (res != b) { 
+    IGRAPH_CHECK(igraph_vector_update(res,b));
+  }
+
+  if (! cs_lusol(order, A->cs, VECTOR(*res), tol)) {
+    IGRAPH_ERROR("Cannot perform LU solve", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_cc(igraph_t *graph, const igraph_sparsemat_t *A,
+			  igraph_bool_t directed) {
+
+  igraph_vector_t edges;
+  long int no_of_nodes=A->cs->m;
+  long int no_of_edges=A->cs->p[A->cs->n];
+  int *p=A->cs->p;
+  int *i=A->cs->i;
+  long int from=0;
+  long int to=0;
+  long int e=0;
+  
+  if (no_of_nodes != A->cs->n) {
+    IGRAPH_ERROR("Cannot create graph object", IGRAPH_NONSQUARE);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+  
+  while (*p < no_of_edges) {
+    while (to < *(p+1)) {
+      if (directed || from >= *i) {
+	VECTOR(edges)[e++] = from;
+	VECTOR(edges)[e++] = (*i);
+      }
+      to++;
+      i++;      
+    }
+    from++;
+    p++;
+  }
+  igraph_vector_resize(&edges, e);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_sparsemat_triplet(igraph_t *graph, const igraph_sparsemat_t *A,
+			       igraph_bool_t directed) {
+
+  igraph_vector_t edges;
+  long int no_of_nodes=A->cs->m;
+  long int no_of_edges=A->cs->nz;
+  int *i=A->cs->p;
+  int *j=A->cs->i;
+  long int e;
+  
+  if (no_of_nodes != A->cs->n) {
+    IGRAPH_ERROR("Cannot create graph object", IGRAPH_NONSQUARE);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+  
+  for (e=0; e<2*no_of_edges; i++, j++) {
+    if (directed || *i >= *j) {
+      VECTOR(edges)[e++] = (*i);
+      VECTOR(edges)[e++] = (*j);
+    }
+  }
+  igraph_vector_resize(&edges, e);
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat
+ * Create an igraph graph from a sparse matrix
+ * 
+ * One edge is created for each non-zero entry in the matrix. If you
+ * have a symmetric matrix, and want to create an undirected graph,
+ * then delete the entries in the upper diagonal first, or call \ref
+ * igraph_simplify() on the result graph to eliminate the multiple
+ * edges.
+ * \param graph Pointer to an uninitialized igraph_t object, the
+ *    graphs is stored here.
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \param directed Boolean scalar, whether to create a directed
+ *    graph.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,
+		     igraph_bool_t directed) {
+  
+  if (A->cs->nz < 0) {
+    return(igraph_i_sparsemat_cc(graph, A, directed));
+  } else {
+    return(igraph_i_sparsemat_triplet(graph, A, directed));
+  }
+}
+
+int igraph_i_weighted_sparsemat_cc(const igraph_sparsemat_t *A, 
+				   igraph_bool_t directed, const char *attr, 
+				   igraph_bool_t loops, 
+				   igraph_vector_t *edges,
+				   igraph_vector_t *weights) {
+
+  long int no_of_edges=A->cs->p[A->cs->n];
+  int *p=A->cs->p;
+  int *i=A->cs->i;
+  igraph_real_t *x=A->cs->x;
+  long int from=0;  
+  long int to=0;
+  long int e=0, w=0;
+
+  IGRAPH_UNUSED(attr);
+
+  igraph_vector_resize(edges, no_of_edges*2);
+  igraph_vector_resize(weights, no_of_edges);
+
+  while (*p < no_of_edges) {
+    while (to < *(p+1)) {
+      if ( (loops || from != *i) && (directed || from >= *i) && *x != 0) {
+	VECTOR(*edges)[e++] = (*i);
+	VECTOR(*edges)[e++] = from;
+	VECTOR(*weights)[w++] = (*x);
+      }
+      to++;
+      i++;
+      x++;
+    }
+    from++;
+    p++;
+  }
+
+  igraph_vector_resize(edges, e);
+  igraph_vector_resize(weights, w);
+  
+  return 0;
+}
+
+int igraph_i_weighted_sparsemat_triplet(const igraph_sparsemat_t *A, 
+					igraph_bool_t directed,
+					const char *attr, 
+					igraph_bool_t loops, 
+					igraph_vector_t *edges,
+					igraph_vector_t *weights) {
+
+  IGRAPH_UNUSED(A); IGRAPH_UNUSED(directed); IGRAPH_UNUSED(attr);
+  IGRAPH_UNUSED(loops); IGRAPH_UNUSED(edges); IGRAPH_UNUSED(weights);
+
+  /* TODO */
+  IGRAPH_ERROR("Triplet matrices are not implemented", 
+	       IGRAPH_UNIMPLEMENTED);
+  return 0;
+}
+
+int igraph_weighted_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A, 
+			      igraph_bool_t directed, const char *attr, 
+			      igraph_bool_t loops) {
+
+  igraph_vector_t edges, weights;
+  int pot_edges= A->cs->nz < 0 ? A->cs->p[A->cs->n] : A->cs->nz;
+  const char* default_attr = "weight";
+  igraph_vector_ptr_t attr_vec;
+  igraph_attribute_record_t attr_rec;
+  long int no_of_nodes=A->cs->m;
+
+  if (no_of_nodes != A->cs->n) {
+    IGRAPH_ERROR("Cannot create graph object", IGRAPH_NONSQUARE);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, pot_edges*2);
+  IGRAPH_VECTOR_INIT_FINALLY(&weights, pot_edges);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&attr_vec, 1);
+
+  if (A->cs->nz < 0) {
+    IGRAPH_CHECK(igraph_i_weighted_sparsemat_cc(A, directed, attr, loops, 
+					       &edges, &weights));
+  } else {
+    IGRAPH_CHECK(igraph_i_weighted_sparsemat_triplet(A, directed, attr, 
+						     loops, &edges, 
+						     &weights));
+  }
+
+  /* Prepare attribute record */
+  attr_rec.name = attr ? attr : default_attr;
+  attr_rec.type = IGRAPH_ATTRIBUTE_NUMERIC;
+  attr_rec.value = &weights;
+  VECTOR(attr_vec)[0] = &attr_rec;
+
+  /* Create graph */
+  IGRAPH_CHECK(igraph_empty(graph, (igraph_integer_t) no_of_nodes, directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  if (igraph_vector_size(&edges)>0) {
+    IGRAPH_CHECK(igraph_add_edges(graph, &edges, &attr_vec));
+  }
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Cleanup */
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&weights);
+  igraph_vector_ptr_destroy(&attr_vec);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_get_sparsemat
+ * Convert an igraph graph to a sparse matrix
+ * 
+ * If the graph is undirected, then a symmetric matrix is created.
+ * \param graph The input graph.
+ * \param res Pointer to an uninitialized sparse matrix. The result
+ *    will be stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *res) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  long int nzmax= directed ? no_of_edges : no_of_edges*2;
+  long int i;  
+  
+  IGRAPH_CHECK(igraph_sparsemat_init(res, (igraph_integer_t) no_of_nodes, 
+				     (igraph_integer_t) no_of_nodes, 
+				     (igraph_integer_t) nzmax));
+  
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+    long int to=IGRAPH_TO(graph, i);
+    IGRAPH_CHECK(igraph_sparsemat_entry(res, (int) from, (int) to, 1.0));
+    if (!directed && from != to) {
+      IGRAPH_CHECK(igraph_sparsemat_entry(res, (int) to, (int) from, 1.0));
+    }
+  }    
+  
+  return 0;
+}
+
+#define CHECK(x) if ((x)<0) { IGRAPH_ERROR("Cannot write to file", IGRAPH_EFILE); }
+
+/**
+ * \function igraph_sparsemat_print
+ * Print a sparse matrix to a file
+ * 
+ * Only the non-zero entries are printed. This function serves more as
+ * a debugging utility, as currently there is no function that could
+ * read back the printed matrix from the file.
+ * \param A The input matrix, triplet or column-compressed format.
+ * \param outstream The stream to print it to.
+ * \return Error code.
+ * 
+ * Time complexity: O(nz) for triplet matrices, O(n+nz) for
+ * column-compressed matrices. nz is the number of non-zero elements,
+ * n is the number columns in the matrix.
+ */
+
+int igraph_sparsemat_print(const igraph_sparsemat_t *A,
+			   FILE *outstream) {
+  
+  if (A->cs->nz < 0) {
+    /* CC */
+    int j, p;
+    for (j=0; j<A->cs->n; j++) {
+      CHECK(fprintf(outstream, "col %i: locations %i to %i\n", 
+		    j, A->cs->p[j], A->cs->p[j+1]-1));
+      for (p=A->cs->p[j]; p < A->cs->p[j+1]; p++) {
+	CHECK(fprintf(outstream, "%i : %g\n", A->cs->i[p], A->cs->x[p]));
+      }
+    }
+  } else {
+    /* Triplet */
+    int p;
+    for (p=0; p<A->cs->nz; p++) {
+      CHECK(fprintf(outstream, "%i %i : %g\n", 
+		    A->cs->i[p], A->cs->p[p], A->cs->x[p]));
+    }
+  }
+  
+  return 0;
+}
+
+#undef CHECK
+
+int igraph_i_sparsemat_eye_triplet(igraph_sparsemat_t *A, int n, int nzmax, 
+				   igraph_real_t value) {
+  long int i;
+
+  IGRAPH_CHECK(igraph_sparsemat_init(A, n, n, nzmax));
+  
+  for (i=0; i<n; i++) {
+    igraph_sparsemat_entry(A, (int) i, (int) i, value);
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_eye_cc(igraph_sparsemat_t *A, int n,
+			      igraph_real_t value) {
+  long int i;
+
+  if (! (A->cs = cs_spalloc(n, n, n, /*values=*/ 1, /*triplet=*/ 0)) ) {
+    IGRAPH_ERROR("Cannot create eye sparse matrix", IGRAPH_FAILURE);
+  }
+  
+  for (i=0; i<n; i++) {
+    A->cs->p [i] = (int) i;
+    A->cs->i [i] = (int) i;
+    A->cs->x [i] = value;
+  }
+  A->cs->p [n] = n;
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_eye
+ * Create a sparse identity matrix
+ * 
+ * \param A An uninitialized sparse matrix, the result is stored
+ *   here.
+ * \param n The number of rows and number of columns in the matrix.
+ * \param nzmax The maximum number of non-zero elements, this
+ *   essentially gives the amount of memory that will be allocated for
+ *   matrix elements.
+ * \param value The value to store in the diagonal.
+ * \param compress Whether to create a column-compressed matrix. If
+ *   false, then a triplet matrix is created.
+ * \return Error code.
+ * 
+ * Time complexity: O(n).
+ */
+
+int igraph_sparsemat_eye(igraph_sparsemat_t *A, int n, int nzmax,
+			 igraph_real_t value,
+			 igraph_bool_t compress) {
+  if (compress) {
+    return(igraph_i_sparsemat_eye_cc(A, n, value));
+  } else {
+    return(igraph_i_sparsemat_eye_triplet(A, n, nzmax, value));
+  }
+}
+
+int igraph_i_sparsemat_diag_triplet(igraph_sparsemat_t *A, int nzmax,
+				    const igraph_vector_t *values) {
+
+  int i, n=(int) igraph_vector_size(values);
+
+  IGRAPH_CHECK(igraph_sparsemat_init(A, n, n, nzmax));
+  
+  for (i=0; i<n; i++) {
+    igraph_sparsemat_entry(A, i, i, VECTOR(*values)[i]);
+  }
+  
+  return 0;
+  
+}
+
+int igraph_i_sparsemat_diag_cc(igraph_sparsemat_t *A,
+			       const igraph_vector_t *values) {
+
+  int i, n=(int) igraph_vector_size(values);
+
+  if (! (A->cs = cs_spalloc(n, n, n, /*values=*/ 1, /*triplet=*/ 0)) ) {
+    IGRAPH_ERROR("Cannot create eye sparse matrix", IGRAPH_FAILURE);
+  }
+  
+  for (i=0; i<n; i++) {
+    A->cs->p [i] = i;
+    A->cs->i [i] = i;
+    A->cs->x [i] = VECTOR(*values)[i];
+  }
+  A->cs->p [n] = n;
+  
+  return 0;
+
+}
+
+/**
+ * \function igraph_sparsemat_diag
+ * Create a sparse diagonal matrix
+ * 
+ * \param A An uninitialized sparse matrix, the result is stored
+ *    here.
+ * \param nzmax The maximum number of non-zero elements, this
+ *   essentially gives the amount of memory that will be allocated for
+ *   matrix elements.
+ * \param values The values to store in the diagonal, the size of the
+ *    matrix defined by the length of this vector.
+ * \param compress Whether to create a column-compressed matrix. If
+ *   false, then a triplet matrix is created.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the length of the diagonal vector.
+ */
+
+int igraph_sparsemat_diag(igraph_sparsemat_t *A, int nzmax,
+			  const igraph_vector_t *values,
+			  igraph_bool_t compress) {
+
+  if (compress) {
+    return(igraph_i_sparsemat_diag_cc(A, values));
+  } else {
+    return(igraph_i_sparsemat_diag_triplet(A, nzmax, values));
+  }
+}
+
+int igraph_i_sparsemat_arpack_multiply(igraph_real_t *to, 
+				       const igraph_real_t *from,
+				       int n,
+				       void *extra) {
+  igraph_sparsemat_t *A=extra;
+  igraph_vector_t vto, vfrom;
+  igraph_vector_view(&vto, to, n);
+  igraph_vector_view(&vfrom, from, n);
+  igraph_vector_null(&vto);
+  IGRAPH_CHECK(igraph_sparsemat_gaxpy(A, &vfrom, &vto));
+  return 0;
+}
+
+typedef struct igraph_i_sparsemat_arpack_rssolve_data_t {
+  igraph_sparsemat_symbolic_t *dis;
+  igraph_sparsemat_numeric_t *din;
+  igraph_real_t tol;
+  igraph_sparsemat_solve_t method;
+} igraph_i_sparsemat_arpack_rssolve_data_t;
+
+int igraph_i_sparsemat_arpack_solve(igraph_real_t *to, 
+				    const igraph_real_t *from,
+				    int n,
+				    void *extra) {
+
+  igraph_i_sparsemat_arpack_rssolve_data_t *data=extra;
+  igraph_vector_t vfrom, vto;
+
+  igraph_vector_view(&vfrom, from, n);
+  igraph_vector_view(&vto, to, n);
+
+  if (data->method == IGRAPH_SPARSEMAT_SOLVE_LU) {
+    IGRAPH_CHECK(igraph_sparsemat_luresol(data->dis, data->din, &vfrom, 
+					  &vto));
+  } else if (data->method == IGRAPH_SPARSEMAT_SOLVE_QR) {
+    IGRAPH_CHECK(igraph_sparsemat_qrresol(data->dis, data->din, &vfrom, 
+					  &vto));
+
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_arpack_rssolve
+ * Eigenvalues and eigenvectors of a symmetric sparse matrix via ARPACK
+ * 
+ * \param The input matrix, must be column-compressed.
+ * \param options It is passed to \ref igraph_arpack_rssolve(). See
+ *    \ref igraph_arpack_options_t for the details. If \c mode is 1,
+ *    then ARPACK uses regular mode, if \c mode is 3, then shift and
+ *    invert mode is used and the \c sigma structure member defines
+ *    the shift.
+ * \param storage Storage for ARPACK. See \ref
+ *    igraph_arpack_rssolve() and \ref igraph_arpack_storage_t for
+ *    details.
+ * \param values An initialized vector or a null pointer, the
+ *    eigenvalues are stored here.
+ * \param vectors An initialised matrix, or a null pointer, the
+ *    eigenvectors are stored here, in the columns.
+ * \param solvemethod The method to solve the linear system, if \c
+ *    mode is 3, i.e. the shift and invert mode is used. 
+ *    Possible values:
+ *    \clist 
+ *      \cli IGRAPH_SPARSEMAT_SOLVE_LU
+ *           The linear system is solved using LU decomposition.
+ *      \cli IGRAPH_SPARSEMAT_SOLVE_QR
+ *           The linear system is solved using QR decomposition.
+ *    \endclist
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+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 n=(int) igraph_sparsemat_nrow(A);
+
+  if (n != igraph_sparsemat_ncol(A)) {
+    IGRAPH_ERROR("Non-square matrix for ARPACK", IGRAPH_NONSQUARE);
+  }
+
+  options->n=n;
+
+  if (options->mode==1) {
+    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_sparsemat_arpack_multiply,
+				       (void*) A, options, storage, 
+				       values, vectors));
+  } else if (options->mode==3) {
+    igraph_real_t sigma=options->sigma;
+    igraph_sparsemat_t OP, eye;
+    igraph_sparsemat_symbolic_t symb;
+    igraph_sparsemat_numeric_t num;
+    igraph_i_sparsemat_arpack_rssolve_data_t data;
+    /*-----------------------------------*/
+    /* We need to factor the (A-sigma*I) */
+    /*-----------------------------------*/
+    
+    /* Create (A-sigma*I) */
+    IGRAPH_CHECK(igraph_sparsemat_eye(&eye, /*n=*/ n, /*nzmax=*/ n, 
+				      /*value=*/ -sigma, /*compress=*/ 1));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, &eye);
+    IGRAPH_CHECK(igraph_sparsemat_add(/*A=*/ A, /*B=*/ &eye, /*alpha=*/ 1.0,
+				      /*beta=*/ 1.0, /*res=*/ &OP));
+    igraph_sparsemat_destroy(&eye);
+    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, &OP);
+        
+    if (solvemethod==IGRAPH_SPARSEMAT_SOLVE_LU) {
+      /* Symbolic analysis */
+      IGRAPH_CHECK(igraph_sparsemat_symblu(/*order=*/ 0, &OP, &symb));
+      IGRAPH_FINALLY(igraph_sparsemat_symbolic_destroy, &symb);
+      /* Numeric LU factorization */
+      IGRAPH_CHECK(igraph_sparsemat_lu(&OP, &symb, &num, /*tol=*/ 0));
+      IGRAPH_FINALLY(igraph_sparsemat_numeric_destroy, &num);
+    } else if (solvemethod==IGRAPH_SPARSEMAT_SOLVE_QR) {
+      /* Symbolic analysis */
+      IGRAPH_CHECK(igraph_sparsemat_symbqr(/*order=*/ 0, &OP, &symb));
+      IGRAPH_FINALLY(igraph_sparsemat_symbolic_destroy, &symb);
+      /* Numeric QR factorization */
+      IGRAPH_CHECK(igraph_sparsemat_qr(&OP, &symb, &num));
+      IGRAPH_FINALLY(igraph_sparsemat_numeric_destroy, &num);
+    }
+
+    data.dis=&symb;
+    data.din=#
+    data.tol=options->tol;
+    data.method=solvemethod;
+    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_sparsemat_arpack_solve,
+				       (void*) &data, options, storage, 
+				       values, vectors));
+   
+    igraph_sparsemat_numeric_destroy(&num);
+    igraph_sparsemat_symbolic_destroy(&symb);
+    igraph_sparsemat_destroy(&OP);
+    IGRAPH_FINALLY_CLEAN(3);
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_arpack_rnsolve
+ * Eigenvalues and eigenvectors of a nonsymmetric sparse matrix via ARPACK
+ * 
+ * Eigenvalues and/or eigenvectors of a nonsymmetric sparse matrix.
+ * \param A The input matrix, in column-compressed mode.
+ * \param options ARPACK options, it is passed to \ref
+ *    igraph_arpack_rnsolve(). See also \ref igraph_arpack_options_t
+ *    for details.
+ * \param storage Storage for ARPACK, this is passed to \ref
+ *    igraph_arpack_rnsolve(). See \ref igraph_arpack_storage_t for
+ *    details.
+ * \param values An initialized matrix, or a null pointer. If not a
+ *    null pointer, then the eigenvalues are stored here, the first
+ *    column is the real part, the second column is the imaginary
+ *    part.
+ * \param vectors An initialized matrix, or a null pointer. If not a
+ *    null pointer, then the eigenvectors are stored here, please see 
+ *    \ref igraph_arpack_rnsolve() for the format.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+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 n=(int) igraph_sparsemat_nrow(A);
+
+  if (n != igraph_sparsemat_ncol(A)) {
+    IGRAPH_ERROR("Non-square matrix for ARPACK", IGRAPH_NONSQUARE);
+  }
+
+  options->n=n;
+
+  return igraph_arpack_rnsolve(igraph_i_sparsemat_arpack_multiply,
+			       (void*) A, options, storage, 
+			       values, vectors);
+}
+
+/**
+ * \function igraph_sparsemat_symbqr
+ * Symbolic QR decomposition
+ * 
+ * QR decomposition of sparse matrices involves two steps, the first
+ * is calling this function, and then \ref
+ * igraph_sparsemat_qr().
+ * \param order The ordering to use: 0 means natural ordering, 1 means
+ *   minimum degree ordering of A+A', 2 is minimum degree ordering of
+ *   A'A after removing the dense rows from A, and 3 is the minimum
+ *   degree ordering of A'A. 
+ * \param A The input matrix, in column-compressed format.
+ * \param dis The result of the symbolic analysis is stored here. Once
+ *    not needed anymore, it must be destroyed by calling \ref
+ *    igraph_sparsemat_symbolic_destroy().
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_symbqr(long int order, const igraph_sparsemat_t *A,
+			    igraph_sparsemat_symbolic_t *dis) {
+
+  dis->symbolic = cs_sqr((int) order, A->cs, /*qr=*/ 1);
+  if (!dis->symbolic) {
+    IGRAPH_ERROR("Cannot do symbolic QR decomposition", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_symblu
+ * Symbolic LU decomposition
+ * 
+ * LU decomposition of sparse matrices involves two steps, the first
+ * is calling this function, and then \ref igraph_sparsemat_lu().
+ * \param order The ordering to use: 0 means natural ordering, 1 means
+ *   minimum degree ordering of A+A', 2 is minimum degree ordering of
+ *   A'A after removing the dense rows from A, and 3 is the minimum
+ *   degree ordering of A'A. 
+ * \param A The input matrix, in column-compressed format.
+ * \param dis The result of the symbolic analysis is stored here. Once
+ *    not needed anymore, it must be destroyed by calling \ref
+ *    igraph_sparsemat_symbolic_destroy().
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_symblu(long int order, const igraph_sparsemat_t *A,
+			    igraph_sparsemat_symbolic_t *dis) {
+  
+  dis->symbolic = cs_sqr((int) order, A->cs, /*qr=*/ 0);
+  if (!dis->symbolic) {
+    IGRAPH_ERROR("Cannot do symbolic LU decomposition", IGRAPH_FAILURE);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_lu
+ * LU decomposition of a sparse matrix
+ * 
+ * Performs numeric sparse LU decomposition of a matrix.
+ * \param A The input matrix, in column-compressed format.
+ * \param dis The symbolic analysis for LU decomposition, coming from
+ *    a call to the \ref igraph_sparsemat_symblu() function.
+ * \param din The numeric decomposition, the result is stored here. It
+ *    can be used to solve linear systems with changing right hand
+ *    side vectors, by calling \ref igraph_sparsemat_luresol(). Once
+ *    not needed any more, it must be destroyed by calling \ref
+ *    igraph_sparsemat_symbolic_destroy() on it.
+ * \param tol The tolerance for the numeric LU decomposition.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_lu(const igraph_sparsemat_t *A, 
+			const igraph_sparsemat_symbolic_t *dis, 
+			igraph_sparsemat_numeric_t *din, double tol) {
+  din->numeric=cs_lu(A->cs, dis->symbolic, tol);
+  if (!din->numeric) {
+    IGRAPH_ERROR("Cannot do LU decomposition", IGRAPH_FAILURE);
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_qr
+ * QR decomposition of a sparse matrix
+ * 
+ * Numeric QR decomposition of a sparse matrix.
+ * \param A The input matrix, in column-compressed format.
+ * \param dis The result of the symbolic QR analysis, from the
+ *    function \ref igraph_sparsemat_symbqr().
+ * \param din The result of the decomposition is stored here, it can
+ *    be used to solve many linear systems with the same coefficient
+ *    matrix and changing right hand sides, using the \ref
+ *    igraph_sparsemat_qrresol() function. Once not needed any more,
+ *    one should call \ref igraph_sparsemat_numeric_destroy() on it to
+ *    free the allocated memory.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_qr(const igraph_sparsemat_t *A,
+			const igraph_sparsemat_symbolic_t *dis,
+			igraph_sparsemat_numeric_t *din) {
+  din->numeric=cs_qr(A->cs, dis->symbolic);
+  if (!din->numeric) {
+    IGRAPH_ERROR("Cannot do QR decomposition", IGRAPH_FAILURE);
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_luresol
+ * Solve linear system using a precomputed LU decomposition
+ * 
+ * Uses the LU decomposition of a matrix to solve linear systems.
+ * \param dis The symbolic analysis of the coefficient matrix, the
+ *    result of \ref igraph_sparsemat_symblu().
+ * \param din The LU decomposition, the result of a call to \ref
+ *    igraph_sparsemat_lu(). 
+ * \param b A vector that defines the right hand side of the linear
+ *    equation system.
+ * \param res An initialized vector, the solution of the linear system
+ *    is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+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 n=din->numeric->L->n;
+  igraph_real_t *workspace;
+
+  if (res != b) {
+    IGRAPH_CHECK(igraph_vector_update(res, b));
+  }
+  
+  workspace=igraph_Calloc(n, igraph_real_t);
+  if (!workspace) { 
+    IGRAPH_ERROR("Cannot LU (re)solve sparse matrix", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, workspace);
+
+  if (!cs_ipvec(din->numeric->pinv, VECTOR(*res), workspace, n)) {
+    IGRAPH_ERROR("Cannot LU (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+  if (!cs_lsolve(din->numeric->L, workspace)) {
+    IGRAPH_ERROR("Cannot LU (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+  if (!cs_usolve(din->numeric->U, workspace)) {
+    IGRAPH_ERROR("Cannot LU (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+  if (!cs_ipvec(dis->symbolic->q, workspace, VECTOR(*res), n)) {
+    IGRAPH_ERROR("Cannot LU (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+    
+  igraph_Free(workspace);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_qrresol
+ * Solve a linear system using a precomputed QR decomposition
+ * 
+ * Solves a linear system using a QR decomposition of its coefficient
+ * matrix.
+ * \param dis Symbolic analysis of the coefficient matrix, the result
+ *    of \ref igraph_sparsemat_symbqr().
+ * \param din The QR decomposition of the coefficient matrix, the
+ *    result of \ref igraph_sparsemat_qr().
+ * \param b Vector, giving the right hand side of the linear equation
+ *    system. 
+ * \param res An initialized vector, the solution is stored here. It
+ *    is resized as needed.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+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 n=din->numeric->L->n;
+  igraph_real_t *workspace;
+  int k;
+
+  if (res != b) {
+    IGRAPH_CHECK(igraph_vector_update(res, b));
+  }
+
+  workspace=igraph_Calloc(dis->symbolic ? dis->symbolic->m2 : 1, 
+			  igraph_real_t);
+  if (!workspace) { 
+    IGRAPH_ERROR("Cannot QR (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+  IGRAPH_FINALLY(igraph_free, workspace);
+
+  if (!cs_ipvec(dis->symbolic->pinv, VECTOR(*res), workspace, n)) {
+    IGRAPH_ERROR("Cannot QR (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+  for (k=0; k<n; k++) {
+    if (!cs_happly(din->numeric->L, k, din->numeric->B[k], workspace)) {
+      IGRAPH_ERROR("Cannot QR (re)solve sparse matrix", IGRAPH_FAILURE);
+    }
+  }
+  if (!cs_usolve(din->numeric->U, workspace)) {
+    IGRAPH_ERROR("Cannot QR (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+  if (!cs_ipvec(dis->symbolic->q, workspace, VECTOR(*res), n)) {
+    IGRAPH_ERROR("Cannot QR (re)solve sparse matrix", IGRAPH_FAILURE);
+  }
+
+  igraph_Free(workspace);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_symbolic_destroy
+ * Deallocate memory for a symbolic decomposition
+ * 
+ * Frees the memory allocated by \ref igraph_sparsemat_symbqr() or
+ * \ref igraph_sparsemat_symblu().
+ * \param dis The symbolic analysis.
+ * 
+ * Time complexity: O(1).
+ */
+
+void igraph_sparsemat_symbolic_destroy(igraph_sparsemat_symbolic_t *dis) {
+  cs_sfree(dis->symbolic);
+  dis->symbolic=0;
+}
+
+/**
+ * \function igraph_sparsemat_numeric_destroy
+ * Deallocate memory for a numeric decomposition
+ * 
+ * Frees the memoty allocated by \ref igraph_sparsemat_qr() or \ref
+ * igraph_sparsemat_lu().
+ * \param din The LU or QR decomposition.
+ * 
+ * Time complexity: O(1).
+ */
+
+void igraph_sparsemat_numeric_destroy(igraph_sparsemat_numeric_t *din) {
+  cs_nfree(din->numeric);
+  din->numeric=0;
+}
+
+/**
+ * \function igraph_matrix_as_sparsemat
+ * Convert a dense matrix to a sparse matrix
+ * 
+ * \param res An uninitialized sparse matrix, the result is stored
+ *    here.
+ * \param mat The dense input matrix.
+ * \param tol Real scalar, the tolerance. Values closer than \p tol to
+ *    zero are considered as zero, and will not be included in the
+ *    sparse matrix.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the dense
+ * matrix.
+ */
+
+int igraph_matrix_as_sparsemat(igraph_sparsemat_t *res,
+			       const igraph_matrix_t *mat,
+			       igraph_real_t tol) {
+  int nrow=(int) igraph_matrix_nrow(mat);
+  int ncol=(int) igraph_matrix_ncol(mat);
+  int i, j, nzmax=0;
+
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      if (fabs(MATRIX(*mat, i, j)) > tol) { nzmax++; }
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_sparsemat_init(res, nrow, ncol, nzmax));
+  
+  for (i=0; i<nrow; i++) {
+    for (j=0; j<ncol; j++) {
+      if (fabs(MATRIX(*mat, i, j)) > tol) {
+	IGRAPH_CHECK(igraph_sparsemat_entry(res, i, j, MATRIX(*mat, i, j)));
+      }
+    }
+  }
+
+  return 0;
+}
+
+int igraph_i_sparsemat_as_matrix_cc(igraph_matrix_t *res,
+				    const igraph_sparsemat_t *spmat) {
+
+  int nrow=(int) igraph_sparsemat_nrow(spmat);
+  int ncol=(int) igraph_sparsemat_ncol(spmat);
+  int *p=spmat->cs->p;
+  int *i=spmat->cs->i;
+  igraph_real_t *x=spmat->cs->x;
+  int nzmax=spmat->cs->nzmax;
+  int from=0, to=0;
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, nrow, ncol));
+  igraph_matrix_null(res);
+  
+  while (*p < nzmax) {
+    while (to < *(p+1)) {
+      MATRIX(*res, *i, from) += *x;
+      to++;
+      i++;
+      x++;
+    }
+    from++;
+    p++;
+  }
+
+  return 0;
+}
+
+int igraph_i_sparsemat_as_matrix_triplet(igraph_matrix_t *res,
+					 const igraph_sparsemat_t *spmat) {
+  int nrow=(int) igraph_sparsemat_nrow(spmat);
+  int ncol=(int) igraph_sparsemat_ncol(spmat);
+  int *i=spmat->cs->p;
+  int *j=spmat->cs->i;
+  igraph_real_t *x=spmat->cs->x;
+  int nz=spmat->cs->nz;
+  int e;
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, nrow, ncol));
+  igraph_matrix_null(res);
+
+  for (e=0; e<nz; e++, i++, j++, x++) {
+    MATRIX(*res, *j, *i) += *x;
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_as_matrix
+ * Convert a sparse matrix to a dense matrix
+ * 
+ * \param res Pointer to an initialized matrix, the result is stored
+ *    here. It will be resized to the required size.
+ * \param spmat The input sparse matrix, in triplet or
+ *    column-compressed format.
+ * \return Error code.
+ * 
+ * Time complexity: O(mn), the number of elements in the dense
+ * matrix.
+ */
+
+int igraph_sparsemat_as_matrix(igraph_matrix_t *res,
+			       const igraph_sparsemat_t *spmat) {
+  if (spmat->cs->nz < 0) {
+    return(igraph_i_sparsemat_as_matrix_cc(res, spmat));
+  } else {
+    return(igraph_i_sparsemat_as_matrix_triplet(res, spmat));
+  }
+}
+
+/**
+ * \function igraph_sparsemat_max
+ * Maximum of a sparse matrix
+ * 
+ * \param A The input matrix, column-compressed.
+ * \return The maximum in the input matrix, or \c IGRAPH_NEGINFINITY
+ *    if the matrix has zero elements.
+ * 
+ * Time complexity: TODO.
+ */
+
+igraph_real_t igraph_sparsemat_max(igraph_sparsemat_t *A) {
+  int i, n;
+  igraph_real_t *ptr;
+  igraph_real_t res;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+
+  ptr=A->cs->x;
+  n = A->cs->nz==-1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  if (n==0) { return IGRAPH_NEGINFINITY;  } 
+  res = *ptr;
+  for (i=1; i<n; i++, ptr++) {
+    if (*ptr > res) { res=*ptr; }
+  }
+  return res;
+}
+
+/* TODO: CC matrix don't actually need _dupl, 
+   because the elements are right beside each other. 
+   Same for max and minmax. */
+
+/**
+ * \function igraph_sparsemat_min
+ * Minimum of a sparse matrix
+ *
+ * \param A The input matrix, column-compressed.
+ * \return The minimum in the input matrix, or \c IGRAPH_POSINFINITY
+ *    if the matrix has zero elements.
+ * 
+ * Time complexity: TODO.
+ */
+
+igraph_real_t igraph_sparsemat_min(igraph_sparsemat_t *A) {
+  int i, n;
+  igraph_real_t *ptr;
+  igraph_real_t res;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+
+  ptr=A->cs->x;
+  n = A->cs->nz==-1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  if (n==0) { return IGRAPH_POSINFINITY;  } 
+  res = *ptr;
+  for (i=1; i<n; i++, ptr++) {
+    if (*ptr < res) { res=*ptr; }
+  }
+  return res;
+}
+
+/**
+ * \function igraph_sparsemat_minmax
+ * Minimum and maximum of a sparse matrix
+ *
+ * \param A The input matrix, column-compressed.
+ * \param min The minimum in the input matrix is stored here, or \c
+ *    IGRAPH_POSINFINITY if the matrix has zero elements.
+ * \param max The maximum in the input matrix is stored here, or \c
+ *    IGRAPH_NEGINFINITY if the matrix has zero elements.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+
+int igraph_sparsemat_minmax(igraph_sparsemat_t *A, 
+			    igraph_real_t *min, igraph_real_t *max) {
+  int i, n;
+  igraph_real_t *ptr;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+
+  ptr=A->cs->x;
+  n = A->cs->nz==-1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  if (n==0) { 
+    *min=IGRAPH_POSINFINITY;
+    *max=IGRAPH_NEGINFINITY;
+    return 0;
+  }
+  *min = *max = *ptr;
+  for (i=1; i<n; i++, ptr++) {
+    if (*ptr > *max) { 
+      *max=*ptr; 
+    } else if (*ptr < *min) {
+      *min=*ptr;
+    }
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_count_nonzero
+ * Count nonzero elements of a sparse matrix
+ * 
+ * \param A The input matrix, column-compressed.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+long int igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A) {
+  int i, n;
+  int res=0;
+  igraph_real_t *ptr;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+
+  ptr=A->cs->x;
+  n = A->cs->nz==-1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  if (n==0) { return 0; }
+  for (i=0; i<n; i++, ptr++) {
+    if (*ptr) { res++; }
+  }
+  return res;
+}
+
+/**
+ * \function igraph_sparsemat_count_nonzerotol
+ * Count nonzero elements of a sparse matrix, ignoring elements close to zero
+ * 
+ * Count the number of matrix entries that are closer to zero than \p
+ * tol.
+ * \param The input matrix, column-compressed.
+ * \param Real scalar, the tolerance. 
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+long int igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A, 
+					   igraph_real_t tol) {
+  int i, n;
+  int res=0;
+  igraph_real_t *ptr;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+
+  ptr=A->cs->x;
+  n = A->cs->nz==-1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  if (n==0) { return 0; }
+  for (i=0; i<n; i++, ptr++) {
+    if (*ptr < - tol || *ptr > tol) { res++; }
+  }
+  return res;
+}
+
+int igraph_i_sparsemat_rowsums_triplet(const igraph_sparsemat_t *A,
+				       igraph_vector_t *res) {
+  int i;
+  int *pi=A->cs->i;
+  double *px=A->cs->x;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  igraph_vector_null(res);
+  
+  for (i=0; i<A->cs->nz; i++, pi++, px++) {
+    VECTOR(*res)[ *pi ] += *px;
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_rowsums_cc(const igraph_sparsemat_t *A,
+				  igraph_vector_t *res) {
+  int ne=A->cs->p[A->cs->n];
+  double *px=A->cs->x;
+  int *pi=A->cs->i;
+
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  igraph_vector_null(res);
+  
+  for (; pi < A->cs->i+ne; pi++, px++) {
+    VECTOR(*res)[ *pi ] += *px;
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_rowsums
+ * Row-wise sums.
+ * 
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \param res An initialized vector, the result is stored here. It
+ *    will be resized as needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(nz), the number of non-zero elements.
+ */
+
+int igraph_sparsemat_rowsums(const igraph_sparsemat_t *A, 
+			     igraph_vector_t *res) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_rowsums_triplet(A, res);
+  } else {
+    return igraph_i_sparsemat_rowsums_cc(A, res);
+  }
+}
+
+int igraph_i_sparsemat_colsums_triplet(const igraph_sparsemat_t *A,
+				       igraph_vector_t *res) {
+  int i;
+  int *pp=A->cs->p;
+  double *px=A->cs->x;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));
+  igraph_vector_null(res);
+  
+  for (i=0; i<A->cs->nz; i++, pp++, px++) {
+    VECTOR(*res)[ *pp ] += *px;
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_colsums_cc(const igraph_sparsemat_t *A,
+				  igraph_vector_t *res) {
+  int n=A->cs->n;
+  double *px=A->cs->x;
+  int *pp=A->cs->p;
+  int *pi=A->cs->i;
+  double *pr;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, n));
+  igraph_vector_null(res);
+  pr=VECTOR(*res);
+  
+  for (; pp < A->cs->p + n; pp++, pr++) {
+    for (; pi < A->cs->i + *(pp+1); pi++, px++) {
+      *pr += *px;
+    }
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_colsums
+ * Column-wise sums
+ * 
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \param res An initialized vector, the result is stored here. It
+ *    will be resized as needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(nz) for triplet matrices, O(nz+n) for
+ * column-compressed ones, nz is the number of non-zero elements, n is
+ * the number of columns.
+ */
+
+int igraph_sparsemat_colsums(const igraph_sparsemat_t *A, 
+			     igraph_vector_t *res) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_colsums_triplet(A, res);
+  } else {
+    return igraph_i_sparsemat_colsums_cc(A, res);
+  }
+}
+
+/**
+ * \function igraph_sparsemat_scale
+ * Scale a sparse matrix
+ * 
+ * Multiplies all elements of a sparse matrix, by the given scalar.
+ * \param A The input matrix.
+ * \param by The scaling factor.
+ * \return Error code.
+ * 
+ * Time complexity: O(nz), the number of non-zero elements in the
+ * matrix.
+ */
+
+int igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by) {
+			   
+  double *px = A->cs->x;
+  int n = A->cs->nz == -1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  double *stop=px+n;
+  
+  for (; px < stop; px++) {
+    *px *= by;
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_sparsemat_add_rows
+ * Add rows to a sparse matrix
+ * 
+ * The current matrix elements are retained and all elements in the
+ * new rows are zero.
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \param n The number of rows to add.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_sparsemat_add_rows(igraph_sparsemat_t *A, long int n) {
+  A->cs->m += n;
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_add_cols
+ * Add columns to a sparse matrix
+ * 
+ * The current matrix elements are retained, and all elements in the
+ * new columns are zero.
+ * \param A The input matrix, in triplet or column-compressed format.
+ * \param n The number of columns to add.
+ * \return Error code.
+ * 
+ * Time complexity: TODO.
+ */
+
+int igraph_sparsemat_add_cols(igraph_sparsemat_t *A, long int n) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    A->cs->n += n;
+  } else {
+    int *newp=realloc(A->cs->p, sizeof(int) * (size_t) (A->cs->n + n + 1));
+    int i;
+    if (!newp) { 
+      IGRAPH_ERROR("Cannot add columns to sparse matrix", IGRAPH_ENOMEM);
+    }
+    if (newp != A->cs->p) { 
+      A->cs->p=newp;
+    }
+    for (i=A->cs->n+1; i<A->cs->n + n + 1; i++) {
+      A->cs->p[i]=A->cs->p[i-1];
+    }
+    A->cs->n += n;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_sparsemat_resize
+ * Resize a sparse matrix
+ * 
+ * This function resizes a sparse matrix. The resized sparse matrix 
+ * will be empty.
+ * 
+ * \param A The initialized sparse matrix to resize.
+ * \param nrow The new number of rows.
+ * \param ncol The new number of columns.
+ * \param nzmax The new maximum number of elements.
+ * \return Error code.
+ * 
+ * Time complexity: O(nzmax), the maximum number of non-zero elements.
+ */
+
+int igraph_sparsemat_resize(igraph_sparsemat_t *A, long int nrow, 
+			    long int ncol, int nzmax) {
+
+  if (A->cs->nz < 0) {
+    igraph_sparsemat_t tmp;
+    IGRAPH_CHECK(igraph_sparsemat_init(&tmp, (int) nrow, (int) ncol, nzmax));
+    igraph_sparsemat_destroy(A);
+    *A = tmp;
+  } else {
+    IGRAPH_CHECK(igraph_sparsemat_realloc(A, nzmax));
+    A->cs->m = (int) nrow;
+    A->cs->n = (int) ncol;
+    A->cs->nz = 0;
+  }
+  return 0;
+}
+
+int igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A) {
+  if (A->cs->nz < 0) {
+    return A->cs->p[A->cs->n];
+  } else {
+    return A->cs->nz;
+  }
+}
+
+int igraph_sparsemat_getelements(const igraph_sparsemat_t *A, 
+				igraph_vector_int_t *i,
+				igraph_vector_int_t *j, 
+				igraph_vector_t *x) {
+  int nz=A->cs->nz;
+  if (nz < 0) {
+    nz=A->cs->p[A->cs->n];
+    IGRAPH_CHECK(igraph_vector_int_resize(i, nz));
+    IGRAPH_CHECK(igraph_vector_int_resize(j, A->cs->n+1));
+    IGRAPH_CHECK(igraph_vector_resize(x, nz));
+    memcpy(VECTOR(*i), A->cs->i, (size_t) nz * sizeof(int));
+    memcpy(VECTOR(*j), A->cs->p, (size_t) (A->cs->n+1) * sizeof(int));
+    memcpy(VECTOR(*x), A->cs->x, (size_t) nz * sizeof(igraph_real_t));
+  } else {
+    IGRAPH_CHECK(igraph_vector_int_resize(i, nz));
+    IGRAPH_CHECK(igraph_vector_int_resize(j, nz));
+    IGRAPH_CHECK(igraph_vector_resize(x, nz));
+    memcpy(VECTOR(*i), A->cs->i, (size_t) nz * sizeof(int));
+    memcpy(VECTOR(*j), A->cs->p, (size_t) nz * sizeof(int));
+    memcpy(VECTOR(*x), A->cs->x, (size_t) nz * sizeof(igraph_real_t));
+  }
+  return 0;
+}
+
+int igraph_sparsemat_scale_rows(igraph_sparsemat_t *A,
+				const igraph_vector_t *fact) {
+  int *i=A->cs->i;
+  igraph_real_t *x=A->cs->x;
+  int no_of_edges=A->cs->nz < 0 ? A->cs->p[A->cs->n] : A->cs->nz;
+  int e;
+
+  for (e=0; e<no_of_edges; e++, x++, i++) {
+    igraph_real_t f=VECTOR(*fact)[*i];
+    (*x) *= f;
+  }
+
+  return 0;
+}
+
+int igraph_i_sparsemat_scale_cols_cc(igraph_sparsemat_t *A,
+				     const igraph_vector_t *fact) {
+  int *i=A->cs->i;
+  igraph_real_t *x=A->cs->x;
+  int no_of_edges=A->cs->p[A->cs->n];
+  int e;
+  int c=0;			/* actual column */
+  
+  for (e=0; e<no_of_edges; e++, x++, i++) {
+    igraph_real_t f;
+    while (c < A->cs->n && A->cs->p[c+1] == e) { c++; }
+    f=VECTOR(*fact)[c];
+    (*x) *= f;
+  }
+
+  return 0;
+}
+
+int igraph_i_sparsemat_scale_cols_triplet(igraph_sparsemat_t *A,
+					  const igraph_vector_t *fact) {
+  int *j=A->cs->p;
+  igraph_real_t *x=A->cs->x;
+  int no_of_edges=A->cs->nz;
+  int e;
+
+  for (e=0; e<no_of_edges; e++, x++, j++) {
+    igraph_real_t f=VECTOR(*fact)[*j];
+    (*x) *= f;
+  }
+
+  return 0;
+}
+
+int igraph_sparsemat_scale_cols(igraph_sparsemat_t *A,
+				const igraph_vector_t *fact) {
+  if (A->cs->nz < 0) {
+    return igraph_i_sparsemat_scale_cols_cc(A, fact);
+  } else {
+    return igraph_i_sparsemat_scale_cols_triplet(A, fact);
+  }
+}
+
+int igraph_sparsemat_multiply_by_dense(const igraph_sparsemat_t *A,
+				       const igraph_matrix_t *B,
+				       igraph_matrix_t *res) {
+
+  int m=(int) igraph_sparsemat_nrow(A);
+  int n=(int) igraph_sparsemat_ncol(A);
+  int p=(int) igraph_matrix_ncol(B);
+  int i;
+  
+  if (igraph_matrix_nrow(B) != n) {
+    IGRAPH_ERROR("Invalid dimensions in sparse-dense matrix product",
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, m, p));
+  igraph_matrix_null(res);
+
+  for (i=0; i<p; i++) {
+    if (!(cs_gaxpy(A->cs, &MATRIX(*B, 0, i), &MATRIX(*res, 0, i)))) {
+      IGRAPH_ERROR("Cannot perform sparse-dense matrix multiplication",
+		   IGRAPH_FAILURE);
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_sparsemat_dense_multiply(const igraph_matrix_t *A,
+				    const igraph_sparsemat_t *B,
+				    igraph_matrix_t *res) {
+  int m=(int) igraph_matrix_nrow(A);
+  int n=(int) igraph_matrix_ncol(A);
+  int p=(int) igraph_sparsemat_ncol(B);
+  int r, c;
+  int *Bp=B->cs->p;
+  
+  if (igraph_sparsemat_nrow(B) != n) {
+    IGRAPH_ERROR("Invalid dimensions in dense-sparse matrix product",
+		 IGRAPH_EINVAL);
+  }
+
+  if (!igraph_sparsemat_is_cc(B)) {
+    IGRAPH_ERROR("Dense-sparse product is only implemented for "
+		 "column-compressed sparse matrices", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, m, p));
+  igraph_matrix_null(res);
+  
+  for (c=0; c<p; c++) {
+    for (r=0; r<m; r++) {
+      int idx=*Bp;
+      while (idx < *(Bp+1)) {
+	MATRIX(*res, r, c) += MATRIX(*A, r, B->cs->i[idx]) * B->cs->x[idx];
+	idx++;
+      }
+    }
+    Bp++;
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_view(igraph_sparsemat_t *A, int nzmax, int m, int n, 
+			    int *p, int *i, double *x, int nz) {
+
+  A->cs = cs_calloc(1, sizeof(cs_di));
+  A->cs->nzmax = nzmax;
+  A->cs->m = m;
+  A->cs->n = n;
+  A->cs->p = p;
+  A->cs->i = i;
+  A->cs->x = x;
+  A->cs->nz = nz;
+  
+  return 0;
+}
+
+int igraph_sparsemat_sort(const igraph_sparsemat_t *A, 
+			  igraph_sparsemat_t *sorted) {
+  
+  igraph_sparsemat_t tmp;
+
+  IGRAPH_CHECK(igraph_sparsemat_transpose(A, &tmp, /*values=*/ 1));
+  IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmp);
+  IGRAPH_CHECK(igraph_sparsemat_transpose(&tmp, sorted, /*values=*/ 1));
+  igraph_sparsemat_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_sparsemat_getelements_sorted(const igraph_sparsemat_t *A, 
+					igraph_vector_int_t *i,
+					igraph_vector_int_t *j, 
+					igraph_vector_t *x) {
+  if (A->cs->nz < 0) {
+    igraph_sparsemat_t tmp;
+    IGRAPH_CHECK(igraph_sparsemat_sort(A, &tmp));
+    IGRAPH_FINALLY(igraph_sparsemat_destroy, &tmp);
+    IGRAPH_CHECK(igraph_sparsemat_getelements(&tmp, i, j, x));
+    igraph_sparsemat_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    IGRAPH_CHECK(igraph_sparsemat_getelements(A, i, j, x));
+  }
+
+  return 0;
+}
+
+int igraph_sparsemat_nzmax(const igraph_sparsemat_t *A) {
+  return A->cs->nzmax;
+}
+
+int igraph_sparsemat_neg(igraph_sparsemat_t *A) {
+  int i, nz=A->cs->nz == -1 ? A->cs->p[A->cs->n] : A->cs->nz;
+  igraph_real_t *px=A->cs->x;
+
+  for (i=0; i<nz; i++, px++) { 
+    *px = - (*px);
+  }
+  
+  return 0;
+}
+
+int igraph_sparsemat_iterator_init(igraph_sparsemat_iterator_t *it,
+				   igraph_sparsemat_t *sparsemat) {
+
+  it->mat=sparsemat;
+  igraph_sparsemat_iterator_reset(it);
+  return 0;
+}
+
+int igraph_sparsemat_iterator_reset(igraph_sparsemat_iterator_t *it) {
+  it->pos=0;
+  if (!igraph_sparsemat_is_triplet(it->mat)) {
+    it->col=0;
+    while (it->col < it->mat->cs->n && 
+	   it->mat->cs->p[it->col+1] == it->pos) { it->col ++; }
+  }
+  return 0;
+}
+
+igraph_bool_t 
+igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it) {
+  int nz=it->mat->cs->nz == -1 ? it->mat->cs->p[it->mat->cs->n] : 
+    it->mat->cs->nz;
+  return it->pos >= nz;
+}
+
+int igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it) {
+  return it->mat->cs->i[it->pos];
+}
+
+int igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it) {
+  if (igraph_sparsemat_is_triplet(it->mat)) {
+    return it->mat->cs->p[it->pos];
+  } else {
+    return it->col;
+  }
+}
+
+igraph_real_t 
+igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it) {
+  return it->mat->cs->x[it->pos];
+}
+
+int igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it) {
+  it->pos += 1;
+  while (it->col < it->mat->cs->n && 
+	 it->mat->cs->p[it->col+1] == it->pos) {
+    it->col++;
+  }
+  return it->pos;
+}
+
+int igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it) {
+  return it->pos;
+}
diff --git a/src/spectral_properties.c b/src/spectral_properties.c
new file mode 100644
index 0000000..0fe4d8f
--- /dev/null
+++ b/src/spectral_properties.c
@@ -0,0 +1,435 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=8 sw=2 sts=2 et: */
+/* 
+   IGraph library.
+   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
+   (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_structural.h"
+#include "igraph_interface.h"
+#include "config.h"
+#include <math.h>
+
+int igraph_i_weighted_laplacian(const igraph_t *graph, igraph_matrix_t *res,
+                                igraph_sparsemat_t *sparseres,
+				igraph_bool_t normalized, 
+                                const igraph_vector_t *weights) {
+  
+  igraph_eit_t edgeit;
+  int no_of_nodes=(int) igraph_vcount(graph);
+  int no_of_edges=(int) igraph_ecount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  igraph_vector_t degree;
+  long int i;
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid edge weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (res) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes));
+    igraph_matrix_null(res);
+  }
+  if (sparseres) {
+    int nz=directed ? no_of_edges + no_of_nodes : 
+      no_of_edges * 2 + no_of_nodes;
+    igraph_sparsemat_init(sparseres, no_of_nodes, no_of_nodes, nz);
+  }
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);
+  
+  if (directed) {
+
+    if (!normalized) {
+
+      while (!IGRAPH_EIT_END(edgeit)) {
+        long int edge=IGRAPH_EIT_GET(edgeit);
+        long int from=IGRAPH_FROM(graph, edge);
+        long int to  =IGRAPH_TO  (graph, edge);
+        igraph_real_t weight=VECTOR(*weights)[edge];
+        if (from != to) {
+	  if (res) {
+	    MATRIX(*res, from, to) -= weight;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) from, (int)to, 
+						-weight));
+	  }
+          VECTOR(degree)[from] += weight;
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+      
+      /* And the diagonal */
+      for (i=0; i<no_of_nodes; i++) {
+	if (res) {
+	  MATRIX(*res, i, i) = VECTOR(degree)[i];
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) i, (int) i, 
+					      VECTOR(degree)[i]));
+	}
+      }
+
+    } else /* normalized */ {
+
+      while (!IGRAPH_EIT_END(edgeit)) {
+        long int edge=IGRAPH_EIT_GET(edgeit);
+        long int from=IGRAPH_FROM(graph, edge);
+        long int to  =IGRAPH_TO  (graph, edge);
+        igraph_real_t weight=VECTOR(*weights)[edge];
+        if (from != to) {
+          VECTOR(degree)[from] += weight;
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+
+      for (i=0; i<no_of_nodes; i++) {
+	int t=VECTOR(degree)[i] > 0 ? 1 : 0;
+	if (res) {
+	  MATRIX(*res, i, i) = t;
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) i, (int) i, t));
+	}
+      }
+      
+      IGRAPH_EIT_RESET(edgeit);
+      while (!IGRAPH_EIT_END(edgeit)) {
+        long int edge=IGRAPH_EIT_GET(edgeit);
+        long int from=IGRAPH_FROM(graph, edge);
+        long int to  =IGRAPH_TO  (graph, edge);
+        igraph_real_t weight=VECTOR(*weights)[edge];
+        if (from != to) {
+	  igraph_real_t t=weight / VECTOR(degree)[from]; 
+	  if (res) {
+	    MATRIX(*res, from, to) -= t;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) from, (int) to,
+						-t));
+	  }
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+      
+    }
+
+  } else /* undirected */ {
+    
+    if (!normalized) {
+      
+      while (!IGRAPH_EIT_END(edgeit)) {
+        long int edge=IGRAPH_EIT_GET(edgeit);
+        long int from=IGRAPH_FROM(graph, edge);
+        long int to  =IGRAPH_TO  (graph, edge);
+        igraph_real_t weight=VECTOR(*weights)[edge];
+        if (from != to) {
+	  if (res) {
+	    MATRIX(*res, from, to) -= weight;
+	    MATRIX(*res, to, from) -= weight;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) from, (int) to,
+						-weight));
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) to, (int) from,
+						-weight));
+	  }
+          VECTOR(degree)[from] += weight;
+          VECTOR(degree)[to] += weight;
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+      
+      /* And the diagonal */
+      for (i=0; i<no_of_nodes; i++) {
+	if (res) {
+	  MATRIX(*res, i, i) = VECTOR(degree)[i];
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) i, (int) i, 
+					      VECTOR(degree)[i]));
+	}
+      }
+      
+    } else /* normalized */ {
+     
+      while (!IGRAPH_EIT_END(edgeit)) {
+        long int edge=IGRAPH_EIT_GET(edgeit);
+        long int from=IGRAPH_FROM(graph, edge);
+        long int to  =IGRAPH_TO  (graph, edge);
+        igraph_real_t weight=VECTOR(*weights)[edge];
+        if (from != to) {
+          VECTOR(degree)[from] += weight;
+          VECTOR(degree)[to] += weight;
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+
+      for (i=0; i<no_of_nodes; i++) {
+	int t=VECTOR(degree)[i] > 0 ? 1 : 0;
+	if (res) {
+	  MATRIX(*res, i, i) = t;
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) i, (int) i, t));
+	}
+        VECTOR(degree)[i] = sqrt(VECTOR(degree)[i]);
+      }
+      
+      IGRAPH_EIT_RESET(edgeit);
+      while (!IGRAPH_EIT_END(edgeit)) {
+        long int edge=IGRAPH_EIT_GET(edgeit);
+        long int from=IGRAPH_FROM(graph, edge);
+        long int to  =IGRAPH_TO  (graph, edge);
+        igraph_real_t weight=VECTOR(*weights)[edge];
+        if (from != to) {
+          double diff = weight / (VECTOR(degree)[from] * VECTOR(degree)[to]);
+	  if (res) {
+	    MATRIX(*res, from, to) -= diff;
+	    MATRIX(*res, to, from) -= diff;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) from, (int) to,
+						-diff));
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, (int) to, (int) from,
+						-diff));
+	  }
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+      
+    }
+
+  }
+
+  igraph_vector_destroy(&degree);
+  igraph_eit_destroy(&edgeit);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_laplacian
+ * \brief Returns the Laplacian matrix of a graph
+ * 
+ * </para><para>
+ * The graph Laplacian matrix is similar to an adjacency matrix but
+ * contains -1's instead of 1's and the vertex degrees are included in
+ * the diagonal. So the result for edge i--j is -1 if i!=j and is equal
+ * to the degree of vertex i if i==j. igraph_laplacian will work on a
+ * directed graph; in this case, the diagonal will contain the out-degrees.
+ * Loop edges will be ignored.
+ * 
+ * </para><para>
+ * The normalized version of the Laplacian matrix has 1 in the diagonal and 
+ * -1/sqrt(d[i]d[j]) if there is an edge from i to j.
+ * 
+ * </para><para>
+ * The first version of this function was written by Vincent Matossian.
+ * \param graph Pointer to the graph to convert.
+ * \param res Pointer to an initialized matrix object, the result is 
+ *        stored here. It will be resized if needed. 
+ *        If it is a null pointer, then it is ignored. 
+ *        At least one of \p res and \p sparseres must be a non-null pointer.
+ * \param sparseres Pointer to an initialized sparse matrix object, the 
+ *        result is stored here, if it is not a null pointer. 
+ *        At least one of \p res and \p sparseres must be a non-null pointer.
+ * \param normalized Whether to create a normalized Laplacian matrix.
+ * \param weights An optional vector containing edge weights, to calculate 
+ *        the weighted Laplacian matrix. Set it to a null pointer to 
+ *        calculate the unweighted Laplacian.
+ * \return Error code.
+ *
+ * Time complexity: O(|V||V|),
+ * |V| is the 
+ * number of vertices in the graph.
+ * 
+ * \example examples/simple/igraph_laplacian.c
+ */
+
+int igraph_laplacian(const igraph_t *graph, igraph_matrix_t *res,
+		     igraph_sparsemat_t *sparseres,
+                     igraph_bool_t normalized, 
+                     const igraph_vector_t *weights) {
+  
+  igraph_eit_t edgeit;
+  int no_of_nodes=(int) igraph_vcount(graph);
+  int no_of_edges=(int) igraph_ecount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  int from, to;
+  igraph_integer_t ffrom, fto;
+  igraph_vector_t degree;  
+  int i;
+
+  if (!res && !sparseres) {
+    IGRAPH_ERROR("Laplacian: give at least one of `res' or `sparseres'", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (weights) { 
+    return igraph_i_weighted_laplacian(graph, res, sparseres, normalized, 
+				       weights);
+  }
+
+  if (res) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes));
+    igraph_matrix_null(res);
+  }
+  if (sparseres) {
+    int nz=directed ? no_of_edges + no_of_nodes : 
+      no_of_edges * 2 + no_of_nodes;
+    IGRAPH_CHECK(igraph_sparsemat_resize(sparseres, no_of_nodes, 
+					 no_of_nodes, nz));
+  }
+  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);
+  
+  IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(),
+                             IGRAPH_OUT, IGRAPH_NO_LOOPS));
+  
+  if (directed){
+    if (!normalized) {
+      for (i=0;i<no_of_nodes;i++) {
+	if (res) {
+	  MATRIX(*res, i, i) = VECTOR(degree)[i];
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, i, i, 
+					      VECTOR(degree)[i]));
+	}
+      }
+      while (!IGRAPH_EIT_END(edgeit)) {
+        igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+        from=ffrom;
+        to=fto;
+        if (from != to) {
+	  if (res) {
+	    MATRIX(*res, from, to) -= 1;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, from, to, -1.0));
+	  }
+	}
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+    } else {
+      for (i=0;i<no_of_nodes;i++) {
+	int t = VECTOR(degree)[i]>0 ? 1 : 0;
+        if (res) {
+	  MATRIX(*res, i, i) = t;
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, i, i, t));
+	}
+        if (VECTOR(degree)[i] > 0)
+          VECTOR(degree)[i] = 1.0 / VECTOR(degree)[i];
+      }
+      
+      while (!IGRAPH_EIT_END(edgeit)) {
+        igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+        from=ffrom; to=fto;
+        if (from != to) {
+	  if (res) {
+	    MATRIX(*res, from, to) -= VECTOR(degree)[from]; 
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, from, to, 
+						-VECTOR(degree)[from]));
+	  }
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+    }
+
+  } else {
+
+    if (!normalized) {
+      for(i=0;i<no_of_nodes;i++) {
+        if (res) {
+	  MATRIX(*res, i, i) = VECTOR(degree)[i];
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, i, i, 
+					      VECTOR(degree)[i]));
+	}
+      }
+      
+      while (!IGRAPH_EIT_END(edgeit)) {
+        igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+        from=ffrom;
+        to=fto; 
+
+        if (from != to) {
+	  if (res) {
+	    MATRIX(*res, to, from) -= 1;
+	    MATRIX(*res, from, to) -= 1;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, to, from, -1.0));
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, from, to, -1.0));
+	  }
+        }
+
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+    } else {
+      for (i=0;i<no_of_nodes;i++) {
+	int t=VECTOR(degree)[i]>0 ? 1: 0;
+	if (res) {
+	  MATRIX(*res, i, i) = t;
+	}
+	if (sparseres) {
+	  IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, i, i, t));
+	}
+        VECTOR(degree)[i] = sqrt(VECTOR(degree)[i]);
+      }
+      
+      while (!IGRAPH_EIT_END(edgeit)) {
+        igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
+        from=ffrom; to=fto;
+        if (from != to) {
+          double diff = 1.0 / (VECTOR(degree)[from] * VECTOR(degree)[to]);
+	  if (res) {
+	    MATRIX(*res, from, to) -= diff;
+	    MATRIX(*res, to, from) -= diff;
+	  }
+	  if (sparseres) {
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, from, to, -diff));
+	    IGRAPH_CHECK(igraph_sparsemat_entry(sparseres, to, from, -diff));
+	  }	    
+        }
+        IGRAPH_EIT_NEXT(edgeit);
+      }
+    }
+
+  }
+
+  igraph_vector_destroy(&degree);
+  igraph_eit_destroy(&edgeit);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
diff --git a/src/spmatrix.c b/src/spmatrix.c
new file mode 100644
index 0000000..14ede7b
--- /dev/null
+++ b/src/spmatrix.c
@@ -0,0 +1,1004 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et */
+/* 
+   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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_spmatrix.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>     /* memcpy & co. */
+#include <stdlib.h>
+
+/**
+ * \section igraph_spmatrix_constructor_and_destructor Sparse matrix constructors
+ * and destructors.
+ */
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_init
+ * \brief Initializes a sparse matrix.
+ * 
+ * </para><para>
+ * Every sparse matrix needs to be initialized before using it, this is done
+ * by calling this function. A matrix has to be destroyed if it is not
+ * needed any more, see \ref igraph_spmatrix_destroy().
+ * \param m Pointer to a not yet initialized sparse matrix object to be
+ *        initialized. 
+ * \param nrow The number of rows in the matrix.
+ * \param ncol The number of columns in the matrix.
+ * \return Error code.
+ *
+ * Time complexity: operating system dependent.
+ */
+
+int igraph_spmatrix_init(igraph_spmatrix_t *m, long int nrow, long int ncol) {
+  assert(m != NULL);
+  IGRAPH_VECTOR_INIT_FINALLY(&m->ridx, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&m->cidx, ncol+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&m->data, 0);
+  IGRAPH_FINALLY_CLEAN(3);
+  m->nrow=nrow;
+  m->ncol=ncol;
+  return 0;
+}
+
+/** 
+ * \ingroup matrix
+ * \function igraph_spmatrix_destroy
+ * \brief Destroys a sparse matrix object.
+ * 
+ * </para><para>
+ * This function frees all the memory allocated for a sparse matrix
+ * object. The destroyed object needs to be reinitialized before using
+ * it again.
+ * \param m The matrix to destroy.
+ * 
+ * Time complexity: operating system dependent.
+ */ 
+
+void igraph_spmatrix_destroy(igraph_spmatrix_t *m) {
+  assert(m != NULL);
+  igraph_vector_destroy(&m->ridx);
+  igraph_vector_destroy(&m->cidx);
+  igraph_vector_destroy(&m->data);
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_copy
+ * \brief Copies a sparse matrix.
+ *
+ * </para><para>
+ * Creates a sparse matrix object by copying another one.
+ * \param to Pointer to an uninitialized sparse matrix object.
+ * \param from The initialized sparse matrix object to copy.
+ * \return Error code, \c IGRAPH_ENOMEM if there
+ *   isn't enough memory to allocate the new sparse matrix.
+ * 
+ * Time complexity: O(n), the number
+ * of elements in the matrix.
+ */
+
+int igraph_spmatrix_copy(igraph_spmatrix_t *to, const igraph_spmatrix_t *from) {
+  assert(from != NULL);
+  assert(to != NULL);
+  to->nrow = from->nrow;
+  to->ncol = from->ncol;
+  IGRAPH_CHECK(igraph_vector_copy(&to->ridx, &from->ridx));
+  IGRAPH_CHECK(igraph_vector_copy(&to->cidx, &from->cidx));
+  IGRAPH_CHECK(igraph_vector_copy(&to->data, &from->data));
+  return 0;
+}
+
+/**
+ * \section igraph_spmatrix_accessing_elements Accessing elements of a sparse matrix
+ */
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_e
+ * \brief Accessing an element of a sparse matrix.
+ *
+ * Note that there are no range checks right now. 
+ * \param m The matrix object.
+ * \param row The index of the row, starting with zero.
+ * \param col The index of the column, starting with zero.
+ *
+ * Time complexity: O(log n), where n is the number of nonzero elements in
+ * the requested column.
+ */
+igraph_real_t igraph_spmatrix_e(const igraph_spmatrix_t *m,
+                                long int row, long int col) {
+  long int start, end;
+ 
+  assert(m != NULL);
+  start = (long) VECTOR(m->cidx)[col];
+  end = (long) VECTOR(m->cidx)[col+1]-1;
+
+  if (end<start) return 0; 
+  /* Elements residing in column col are between m->data[start] and
+   * m->data[end], inclusive, ordered by row index */
+  while (start < end-1) {
+    long int mid=(start+end)/2;
+    if (VECTOR(m->ridx)[mid] > row) {
+      end=mid;
+    } else if (VECTOR(m->ridx)[mid] < row) {
+      start=mid;
+    } else {
+      start=mid;
+      break;
+    }
+  }
+
+  if (VECTOR(m->ridx)[start] == row)
+    return VECTOR(m->data)[start];
+  if (VECTOR(m->ridx)[start] != row && VECTOR(m->ridx)[end] == row)
+    return VECTOR(m->data)[end];
+  return 0;
+}
+
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_set
+ * \brief Setting an element of a sparse matrix.
+ *
+ * Note that there are no range checks right now. 
+ * \param m The matrix object.
+ * \param row The index of the row, starting with zero.
+ * \param col The index of the column, starting with zero.
+ * \param value The new value.
+ *
+ * Time complexity: O(log n), where n is the number of nonzero elements in
+ * the requested column.
+ */
+int igraph_spmatrix_set(igraph_spmatrix_t *m, long int row, long int col,
+            igraph_real_t value) {
+  long int start, end;
+
+  assert(m != NULL);
+  start = (long) VECTOR(m->cidx)[col];
+  end = (long) VECTOR(m->cidx)[col+1]-1;
+
+  if (end<start) {
+    /* First element in the column */
+    if (value == 0.0) return 0;
+    IGRAPH_CHECK(igraph_vector_insert(&m->ridx, start, row));
+    IGRAPH_CHECK(igraph_vector_insert(&m->data, start, value));
+    for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]++;
+    return 0;
+  }
+
+  /* Elements residing in column col are between m->data[start] and
+   * m->data[end], inclusive, ordered by row index */
+  while (start < end-1) {
+    long int mid=(start+end)/2;
+    if (VECTOR(m->ridx)[mid] > row) { 
+      end=mid;
+    } else if (VECTOR(m->ridx)[mid] < row) {
+      start=mid;
+    } else {
+      start=mid;
+      break;
+    }
+  }
+
+  if (VECTOR(m->ridx)[start] == row) {
+    /* Overwriting a value - or deleting it if it has been overwritten by zero */
+    if (value == 0) {
+      igraph_vector_remove(&m->ridx, start);
+      igraph_vector_remove(&m->data, start);
+      for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]--;
+    } else {
+      VECTOR(m->data)[start] = value;
+    }
+    return 0;
+  } else if (VECTOR(m->ridx)[end] == row) {
+    /* Overwriting a value - or deleting it if it has been overwritten by zero */
+    if (value == 0) {
+      igraph_vector_remove(&m->ridx, end);
+      igraph_vector_remove(&m->data, end);
+      for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]--;
+    } else {
+      VECTOR(m->data)[end] = value;
+    }
+    return 0;
+  }
+  
+  /* New element has to be inserted, but only if not a zero is
+   * being written into the matrix */
+  if (value != 0.0) {
+    if (VECTOR(m->ridx)[end] < row) {
+      IGRAPH_CHECK(igraph_vector_insert(&m->ridx, end+1, row));
+      IGRAPH_CHECK(igraph_vector_insert(&m->data, end+1, value));
+    } else if (VECTOR(m->ridx)[start] < row) {
+      IGRAPH_CHECK(igraph_vector_insert(&m->ridx, start+1, row));
+      IGRAPH_CHECK(igraph_vector_insert(&m->data, start+1, value));
+    } else {
+      IGRAPH_CHECK(igraph_vector_insert(&m->ridx, start, row));
+      IGRAPH_CHECK(igraph_vector_insert(&m->data, start, value));
+    }
+    for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]++;
+  }
+  return 0;
+}
+
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_add_e
+ * \brief Adding a real value to an element of a sparse matrix.
+ *
+ * Note that there are no range checks right now. This is implemented to avoid
+ * double lookup of a given element in the matrix by using \ref igraph_spmatrix_e()
+ * and \ref igraph_spmatrix_set() consecutively.
+ *
+ * \param m The matrix object.
+ * \param row The index of the row, starting with zero.
+ * \param col The index of the column, starting with zero.
+ * \param value The value to add.
+ *
+ * Time complexity: O(log n), where n is the number of nonzero elements in
+ * the requested column.
+ */
+int igraph_spmatrix_add_e(igraph_spmatrix_t *m, long int row, long int col,
+            igraph_real_t value) {
+  long int start, end;
+ 
+  assert(m != NULL);
+  start = (long) VECTOR(m->cidx)[col];
+  end = (long) VECTOR(m->cidx)[col+1]-1;
+
+  if (end<start) {
+    /* First element in the column */
+    if (value == 0.0) return 0;
+    IGRAPH_CHECK(igraph_vector_insert(&m->ridx, start, row));
+    IGRAPH_CHECK(igraph_vector_insert(&m->data, start, value));
+    for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]++;
+    return 0;
+  }
+
+  /* Elements residing in column col are between m->data[start] and
+   * m->data[end], inclusive, ordered by row index */
+  while (start < end-1) {
+    long int mid=(start+end)/2;
+    if (VECTOR(m->ridx)[mid] > row) { 
+      end=mid;
+    } else if (VECTOR(m->ridx)[mid] < row) {
+      start=mid;
+    } else {
+      start=mid;
+      break;
+    }
+  }
+
+  if (VECTOR(m->ridx)[start] == row) {
+    /* Overwriting a value */
+    if (VECTOR(m->data)[start] == -1) {
+      igraph_vector_remove(&m->ridx, start);
+      igraph_vector_remove(&m->data, start);
+      for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]--;
+    } else {
+      VECTOR(m->data)[start] += value;
+    }
+    return 0;
+  } else if (VECTOR(m->ridx)[end] == row) {
+    /* Overwriting a value */
+    if (VECTOR(m->data)[end] == -1) {
+      igraph_vector_remove(&m->ridx, end);
+      igraph_vector_remove(&m->data, end);
+      for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]--;
+    } else {
+      VECTOR(m->data)[end] += value;
+    }
+    return 0;
+  }
+  
+  /* New element has to be inserted, but only if not a zero is
+   * being added to a zero element of the matrix */
+  if (value != 0.0) {
+    if (VECTOR(m->ridx)[end] < row) {
+      IGRAPH_CHECK(igraph_vector_insert(&m->ridx, end+1, row));
+      IGRAPH_CHECK(igraph_vector_insert(&m->data, end+1, value));
+    } else if (VECTOR(m->ridx)[start] < row) {
+      IGRAPH_CHECK(igraph_vector_insert(&m->ridx, start+1, row));
+      IGRAPH_CHECK(igraph_vector_insert(&m->data, start+1, value));
+    } else {
+      IGRAPH_CHECK(igraph_vector_insert(&m->ridx, start, row));
+      IGRAPH_CHECK(igraph_vector_insert(&m->data, start, value));
+    }
+    for (start=col+1; start < m->ncol+1; start++) VECTOR(m->cidx)[start]++;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_add_col_values
+ * \brief Adds the values of a column to another column.
+ *
+ * \param to The index of the column to be added to
+ * \param from The index of the column to be added
+ * \return Error code.
+ */
+int igraph_spmatrix_add_col_values(igraph_spmatrix_t *m, long int to, long int from) {
+  long int i;
+  /* TODO: I think this implementation could be speeded up if I don't use
+   * igraph_spmatrix_add_e directly -- but maybe it's not worth the fuss */
+  for (i=(long int) VECTOR(m->cidx)[from]; i<VECTOR(m->cidx)[from+1]; i++) {
+    IGRAPH_CHECK(igraph_spmatrix_add_e(m, (long int) VECTOR(m->ridx)[i], 
+				       to, VECTOR(m->data)[i]));
+  }
+
+  return 0;
+}
+
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_resize
+ * \brief Resizes a sparse matrix.
+ *
+ * </para><para>
+ * This function resizes a sparse matrix by adding more elements to it.
+ * The matrix retains its data even after resizing it, except for the data
+ * which lies outside the new boundaries (if the new size is smaller).
+ * \param m Pointer to an already initialized sparse matrix object.
+ * \param nrow The number of rows in the resized matrix.
+ * \param ncol The number of columns in the resized matrix.
+ * \return Error code.
+ * 
+ * Time complexity: O(n).
+ * n is the number of elements in the old matrix.
+ */
+
+int igraph_spmatrix_resize(igraph_spmatrix_t *m, long int nrow, long int ncol) {
+  long int i, j, ci, ei, mincol;
+  assert(m != NULL);
+  /* Iterating through the matrix data and deleting unnecessary data. */
+  /* At the same time, we create the new indices as well */
+  if (nrow < m->nrow) {
+    ei = j = 0;
+    mincol = (m->ncol < ncol) ? m->ncol : ncol;
+    for (ci=0; ci < mincol; ci++) {
+      for (; ei<VECTOR(m->cidx)[ci+1]; ei++) {
+        if (VECTOR(m->ridx)[ei] < nrow) {
+          VECTOR(m->ridx)[j]=VECTOR(m->ridx)[ei];
+          VECTOR(m->data)[j]=VECTOR(m->data)[ei];
+          j++;
+        }
+      }
+      VECTOR(m->cidx)[ci]=j;
+    }
+    /* Contract the row index and the data vector */
+    IGRAPH_CHECK(igraph_vector_resize(&m->ridx, j));
+    IGRAPH_CHECK(igraph_vector_resize(&m->cidx, j));
+  }
+  /* Updating cidx */
+  IGRAPH_CHECK(igraph_vector_resize(&m->cidx, ncol+1));
+  for (i=m->ncol+1; i<ncol+1; i++) 
+    VECTOR(m->cidx)[i] = VECTOR(m->cidx)[m->ncol];
+  m->nrow=nrow;
+  m->ncol=ncol;
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_count_nonzero
+ * \brief The number of non-zero elements in a sparse matrix.
+ * 
+ * \param m Pointer to an initialized sparse matrix object.
+ * \return The size of the matrix.
+ *
+ * Time complexity: O(1).
+ */
+
+long int igraph_spmatrix_count_nonzero(const igraph_spmatrix_t *m) {
+  assert(m != NULL);
+  return igraph_vector_size(&m->data);
+}
+
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_size
+ * \brief The number of elements in a sparse matrix.
+ * 
+ * \param m Pointer to an initialized sparse matrix object.
+ * \return The size of the matrix.
+ *
+ * Time complexity: O(1).
+ */
+
+long int igraph_spmatrix_size(const igraph_spmatrix_t *m) {
+  assert(m != NULL);
+  return (m->nrow) * (m->ncol);
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_nrow
+ * \brief The number of rows in a sparse matrix.
+ * 
+ * \param m Pointer to an initialized sparse matrix object.
+ * \return The number of rows in the matrix.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int igraph_spmatrix_nrow(const igraph_spmatrix_t *m) {
+  assert(m != NULL);
+  return m->nrow;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_ncol
+ * \brief The number of columns in a sparse matrix.
+ * 
+ * \param m Pointer to an initialized sparse matrix object.
+ * \return The number of columns in the sparse matrix.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int igraph_spmatrix_ncol(const igraph_spmatrix_t *m) {
+  assert(m != NULL);
+  return m->ncol;
+}
+
+/** 
+ * \ingroup matrix
+ * \brief Copies a sparse matrix to a regular C array.
+ *
+ * </para><para>
+ * The matrix is copied columnwise, as this is the format most
+ * programs and languages use.
+ * The C array should be of sufficient size, there are (of course) no
+ * range checks done.
+ * \param m Pointer to an initialized sparse matrix object.
+ * \param to Pointer to a C array, the place to copy the data to.
+ * \return Error code.
+ *
+ * Time complexity: O(n),
+ * n is the number of 
+ * elements in the matrix.
+ */
+
+int igraph_spmatrix_copy_to(const igraph_spmatrix_t *m, igraph_real_t *to) {
+  long int c, dest_idx, idx;
+
+  memset(to, 0, sizeof(igraph_real_t) * (size_t) igraph_spmatrix_size(m));
+  for (c=0, dest_idx=0; c < m->ncol; c++, dest_idx+=m->nrow) {
+    for (idx=(long int) VECTOR(m->cidx)[c]; idx<VECTOR(m->cidx)[c+1]; idx++) {
+      to[dest_idx+(long)VECTOR(m->ridx)[idx]]=VECTOR(m->data)[idx];
+    }
+  }
+  return 0;
+}
+
+/** 
+ * \ingroup matrix
+ * \brief Sets all element in a sparse matrix to zero.
+ * 
+ * \param m Pointer to an initialized matrix object.
+ * \return Error code, always returns with success.
+ * 
+ * Time complexity: O(n),
+ * n is the number of columns in the matrix
+ */
+
+int igraph_spmatrix_null(igraph_spmatrix_t *m) {
+  assert(m != NULL);
+  igraph_vector_clear(&m->data);
+  igraph_vector_clear(&m->ridx);
+  igraph_vector_null(&m->cidx);
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_add_cols
+ * \brief Adds columns to a sparse matrix.
+ * \param m The sparse matrix object.
+ * \param n The number of columns to add.
+ * \return Error code.
+ *
+ * Time complexity: O(1).
+ */
+
+int igraph_spmatrix_add_cols(igraph_spmatrix_t *m, long int n) {
+  igraph_spmatrix_resize(m, m->nrow, m->ncol+n);
+  return 0;
+}
+
+/**
+ * \ingroup matrix
+ * \function igraph_spmatrix_add_rows
+ * \brief Adds rows to a sparse matrix.
+ * \param m The sparse matrix object.
+ * \param n The number of rows to add.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_spmatrix_add_rows(igraph_spmatrix_t *m, long int n) {
+  igraph_spmatrix_resize(m, m->nrow+n, m->ncol);
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_clear_row
+ * \brief Clears a row in the matrix (sets all of its elements to zero)
+ * \param m The matrix.
+ * \param row The index of the row to be cleared.
+ *
+ * Time complexity: O(n), the number of nonzero elements in the matrix.
+ */
+
+int igraph_spmatrix_clear_row(igraph_spmatrix_t *m, long int row) {
+  long int ci, ei, i, j, nremove=0, nremove_old=0;
+  igraph_vector_t permvec;
+
+  assert(m != NULL);
+  IGRAPH_VECTOR_INIT_FINALLY(&permvec, igraph_vector_size(&m->data));
+  for (ci=0, i=0, j=1; ci < m->ncol; ci++) {
+    for (ei=(long int) VECTOR(m->cidx)[ci]; ei < VECTOR(m->cidx)[ci+1]; ei++) {
+      if (VECTOR(m->ridx)[ei] == row) {
+        /* this element will be deleted, so all elements in cidx from the
+         * column index of this element will have to be decreased by one */
+        nremove++;
+      } else {
+        /* this element will be kept */
+        VECTOR(permvec)[i] = j;
+        j++;
+      }
+      i++;
+    }
+    if (ci > 0) {
+      VECTOR(m->cidx)[ci] -= nremove_old;
+    }
+    nremove_old = nremove;
+  }
+  VECTOR(m->cidx)[m->ncol] -= nremove;
+  igraph_vector_permdelete(&m->ridx, &permvec, nremove);
+  igraph_vector_permdelete(&m->data, &permvec, nremove);
+  igraph_vector_destroy(&permvec);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_i_spmatrix_clear_row_fast(igraph_spmatrix_t *m, long int row) {
+  long int ei, n;
+
+  assert(m != NULL);
+  n = igraph_vector_size(&m->data);
+  for (ei=0; ei<n; ei++) {
+    if (VECTOR(m->ridx)[ei] == row) VECTOR(m->data)[ei]=0.0;
+  }
+  return 0;
+}
+
+int igraph_i_spmatrix_cleanup(igraph_spmatrix_t *m) {
+  long int ci, ei, i, j, nremove=0, nremove_old=0;
+  igraph_vector_t permvec;
+
+  assert(m != NULL);
+  IGRAPH_VECTOR_INIT_FINALLY(&permvec, igraph_vector_size(&m->data));
+  for (ci=0, i=0, j=1; ci < m->ncol; ci++) {
+    for (ei=(long int) VECTOR(m->cidx)[ci]; ei < VECTOR(m->cidx)[ci+1]; ei++) {
+      if (VECTOR(m->data)[ei] == 0.0) {
+        /* this element will be deleted, so all elements in cidx from the
+         * column index of this element will have to be decreased by one */
+        nremove++;
+      } else {
+        /* this element will be kept */
+        VECTOR(permvec)[i] = j;
+        j++;
+      }
+      i++;
+    }
+    if (ci > 0) {
+      VECTOR(m->cidx)[ci] -= nremove_old;
+    }
+    nremove_old = nremove;
+  }
+  VECTOR(m->cidx)[m->ncol] -= nremove;
+  igraph_vector_permdelete(&m->ridx, &permvec, nremove);
+  igraph_vector_permdelete(&m->data, &permvec, nremove);
+  igraph_vector_destroy(&permvec);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_clear_col
+ * \brief Clears a column in the matrix (sets all of its elements to zero)
+ * \param m The matrix.
+ * \param col The index of the column to be cleared.
+ * \return Error code. The current implementation always succeeds.
+ *
+ * Time complexity: TODO
+ */
+
+int igraph_spmatrix_clear_col(igraph_spmatrix_t *m, long int col) {
+  long int i, n;
+  assert(m != NULL);
+  n = (long)VECTOR(m->cidx)[col+1] - (long)VECTOR(m->cidx)[col];
+  if (n == 0) return 0;
+  igraph_vector_remove_section(&m->ridx, (long int) VECTOR(m->cidx)[col], 
+			       (long int) VECTOR(m->cidx)[col+1]);
+  igraph_vector_remove_section(&m->data, (long int) VECTOR(m->cidx)[col], 
+			       (long int) VECTOR(m->cidx)[col+1]);
+  for (i=col+1; i <= m->ncol; i++) {
+    VECTOR(m->cidx)[i] -= n;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_scale
+ * \brief Multiplies each element of the sparse matrix by a constant.
+ * \param m The matrix.
+ * \param by The constant.
+ * 
+ * Time complexity: O(n), the number of elements in the matrix.
+ */
+
+void igraph_spmatrix_scale(igraph_spmatrix_t *m, igraph_real_t by) {
+  assert(m != NULL);
+  igraph_vector_scale(&m->data, by);
+}
+
+/**
+ * \function igraph_spmatrix_colsums
+ * \brief Calculates the column sums of the matrix.
+ * \param m The matrix.
+ * \param res An initialized \c igraph_vector_t, the result will be stored here.
+ *   The vector will be resized as needed.
+ *
+ * Time complexity: O(n), the number of nonzero elements in the matrix.
+ */
+
+int igraph_spmatrix_colsums(const igraph_spmatrix_t *m, igraph_vector_t *res) {
+  long int i, c;
+  assert(m != NULL);
+  IGRAPH_CHECK(igraph_vector_resize(res, m->ncol));
+  igraph_vector_null(res);
+  for (c=0; c < m->ncol; c++) {
+    for (i=(long int) VECTOR(m->cidx)[c]; i<VECTOR(m->cidx)[c+1]; i++) {
+      VECTOR(*res)[c] += VECTOR(m->data)[i];
+    }
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_rowsums
+ * \brief Calculates the row sums of the matrix.
+ * \param m The matrix.
+ * \param res An initialized \c igraph_vector_t, the result will be stored here.
+ *   The vector will be resized as needed.
+ *
+ * Time complexity: O(n), the number of nonzero elements in the matrix.
+ */
+
+int igraph_spmatrix_rowsums(const igraph_spmatrix_t *m, igraph_vector_t *res) {
+  long int i, n;
+  assert(m != NULL);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, m->nrow));
+	n = igraph_vector_size(&m->data);
+  igraph_vector_null(res);
+  for (i=0; i < n; i++) {
+    VECTOR(*res)[(long int)VECTOR(m->ridx)[i]] += VECTOR(m->data)[i];
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_max_nonzero
+ * \brief Returns the maximum nonzero element of a matrix.
+ * If the matrix is empty, zero is returned.
+ *
+ * \param m the matrix object.
+ * \param ridx the row index of the maximum element if not \c NULL.
+ * \param cidx the column index of the maximum element if not \c NULL.
+ *
+ * Time complexity: O(n), the number of nonzero elements in the matrix.
+ */
+igraph_real_t igraph_spmatrix_max_nonzero(const igraph_spmatrix_t *m,
+    igraph_real_t *ridx, igraph_real_t *cidx) {
+  igraph_real_t res;
+  long int i, n, maxidx;
+
+  assert(m != NULL);
+  n=igraph_vector_size(&m->data);
+  if (n == 0) return 0.0;
+   
+  maxidx = -1;
+  for (i=0; i<n; i++)
+    if (VECTOR(m->data)[i] != 0.0 &&
+	(maxidx == -1 || VECTOR(m->data)[i] >= VECTOR(m->data)[maxidx]))
+      maxidx = i;
+	
+  if (maxidx == -1) return 0.0;
+	
+  res=VECTOR(m->data)[maxidx];
+  if (ridx != 0) *ridx = VECTOR(m->ridx)[maxidx];
+  if (cidx != 0) {
+    igraph_vector_binsearch(&m->cidx, maxidx, &i);
+    while (VECTOR(m->cidx)[i+1] == VECTOR(m->cidx)[i]) i++;
+    *cidx = (igraph_real_t)i;
+  }
+  return res;
+}
+
+/**
+ * \function igraph_spmatrix_max
+ * \brief Returns the maximum element of a matrix.
+ * If the matrix is empty, zero is returned.
+ *
+ * \param m the matrix object.
+ * \param ridx the row index of the maximum element if not \c NULL.
+ * \param cidx the column index of the maximum element if not \c NULL.
+ *
+ * Time complexity: O(n), the number of nonzero elements in the matrix.
+ */
+igraph_real_t igraph_spmatrix_max(const igraph_spmatrix_t *m,
+    igraph_real_t *ridx, igraph_real_t *cidx) {
+  igraph_real_t res;
+  long int i, j, k, maxidx;
+
+  assert(m != NULL);
+  i=igraph_vector_size(&m->data);
+  if (i == 0) return 0.0;
+
+  maxidx=(long)igraph_vector_which_max(&m->data);
+  res=VECTOR(m->data)[maxidx];
+  if (res>=0.0 || i == m->nrow * m->ncol) {
+    if (ridx != 0) *ridx = VECTOR(m->ridx)[maxidx];
+    if (cidx != 0) {
+      igraph_vector_binsearch(&m->cidx, maxidx, &i);
+      i--;
+      while (i < m->ncol-1 && VECTOR(m->cidx)[i+1] == VECTOR(m->cidx)[i]) i++;
+      *cidx = (igraph_real_t)i;
+    }
+    return res;
+  }
+  /* the maximal nonzero element is negative and there is at least a
+   * single zero
+   */
+  res=0.0;
+  if (cidx != 0 || ridx != 0) {
+    for (i=0; i < m->ncol; i++) {
+      if (VECTOR(m->cidx)[i+1] - VECTOR(m->cidx)[i] < m->nrow) {
+        if (cidx != 0) *cidx = i;
+        if (ridx != 0) {
+          for (j=(long int) VECTOR(m->cidx)[i], k=0; 
+	       j < VECTOR(m->cidx)[i+1]; j++, k++) {
+            if (VECTOR(m->ridx)[j] != k) {
+              *ridx = k;
+              break;
+            }
+          }
+        }
+        break;
+      }
+    }
+  }
+
+  return res;
+}
+
+int igraph_i_spmatrix_get_col_nonzero_indices(const igraph_spmatrix_t *m,
+  igraph_vector_t *res, long int col) {
+  long int i, n;
+  assert(m != NULL);
+  n = (long int) (VECTOR(m->cidx)[col+1]-VECTOR(m->cidx)[col]);
+  IGRAPH_CHECK(igraph_vector_resize(res, n));
+  for (i=(long int) VECTOR(m->cidx)[col], n=0;
+       i<VECTOR(m->cidx)[col+1]; i++, n++)
+    if (VECTOR(m->data)[i] != 0.0) VECTOR(*res)[n] = VECTOR(m->ridx)[i];
+  return 0;
+}
+
+
+/**
+ * \section igraph_spmatrix_iterating Iterating over the non-zero elements of a sparse matrix
+ *
+ * <para>The \type igraph_spmatrix_iter_t type represents an iterator that can
+ * be used to step over the non-zero elements of a sparse matrix in columnwise
+ * order efficiently. In general, you shouldn't modify the elements of the matrix
+ * while iterating over it; doing so will probably invalidate the iterator, but
+ * there are no checks to prevent you from doing this.</para>
+ *
+ * <para>To access the row index of the current element of the iterator, use its
+ * \c ri field. Similarly, the \c ci field stores the column index of the current
+ * element and the \c value field stores the value of the element.</para>
+ */
+
+/**
+ * \function igraph_spmatrix_iter_create
+ * \brief Creates a sparse matrix iterator corresponding to the given matrix.
+ *
+ * \param  mit  pointer to the matrix iterator being initialized
+ * \param  m    pointer to the matrix we will be iterating over
+ * \return  Error code. The current implementation is always successful.
+ *
+ * Time complexity: O(1).
+ */
+int igraph_spmatrix_iter_create(igraph_spmatrix_iter_t *mit, const igraph_spmatrix_t *m) {
+  mit->m = m;
+  IGRAPH_CHECK(igraph_spmatrix_iter_reset(mit));
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_iter_reset
+ * \brief Resets a sparse matrix iterator.
+ *
+ * </para><para>
+ * After resetting, the iterator will point to the first nonzero element (if any).
+ *
+ * \param  mit  pointer to the matrix iterator being reset
+ * \return  Error code. The current implementation is always successful.
+ *
+ * Time complexity: O(1).
+ */
+int igraph_spmatrix_iter_reset(igraph_spmatrix_iter_t *mit) {
+  assert(mit->m);
+
+  if (igraph_spmatrix_count_nonzero(mit->m) == 0) {
+    mit->pos = mit->ri = mit->ci = -1L;
+    mit->value = -1;
+    return 0;
+  }
+
+  mit->ci = 0;
+  mit->pos = -1;
+
+  IGRAPH_CHECK(igraph_spmatrix_iter_next(mit));
+
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_iter_next
+ * \brief Moves a sparse matrix iterator to the next nonzero element.
+ *
+ * </para><para>
+ * You should call this function only if \ref igraph_spmatrix_iter_end()
+ * returns FALSE (0).
+ *
+ * \param  mit  pointer to the matrix iterator being moved
+ * \return  Error code. The current implementation is always successful.
+ *
+ * Time complexity: O(1).
+ */
+int igraph_spmatrix_iter_next(igraph_spmatrix_iter_t *mit) {
+  mit->pos++;
+
+  if (igraph_spmatrix_iter_end(mit))
+      return 0;
+
+  mit->ri = (long int)VECTOR(mit->m->ridx)[mit->pos];
+  mit->value = VECTOR(mit->m->data)[mit->pos];
+
+  while (VECTOR(mit->m->cidx)[mit->ci+1] <= mit->pos) {
+    mit->ci++;
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_spmatrix_iter_end
+ * \brief Checks whether there are more elements in the iterator.
+ *
+ * </para><para>
+ * You should call this function before calling \ref igraph_spmatrix_iter_next()
+ * to make sure you have more elements in the iterator.
+ *
+ * \param  mit  pointer to the matrix iterator being checked
+ * \return   TRUE (1) if there are more elements in the iterator,
+ *           FALSE (0) otherwise.
+ *
+ * Time complexity: O(1).
+ */
+igraph_bool_t igraph_spmatrix_iter_end(igraph_spmatrix_iter_t *mit) {
+  return mit->pos >= igraph_spmatrix_count_nonzero(mit->m);
+}
+
+/**
+ * \function igraph_spmatrix_iter_destroy
+ * \brief Frees the memory used by the iterator.
+ *
+ * </para><para>
+ * The current implementation does not allocate any memory upon
+ * creation, so this function does nothing. However, since there is
+ * no guarantee that future implementations will not allocate any
+ * memory in \ref igraph_spmatrix_iter_create(), you are still
+ * required to call this function whenever you are done with the
+ * iterator.
+ *
+ * \param  mit  pointer to the matrix iterator being destroyed
+ *
+ * Time complexity: O(1).
+ */
+void igraph_spmatrix_iter_destroy(igraph_spmatrix_iter_t *mit) {
+  IGRAPH_UNUSED(mit);
+  /* Nothing to do at the moment */
+}
+
+#ifndef USING_R
+/**
+ * \function igraph_spmatrix_print
+ * \brief Prints a sparse matrix.
+ *
+ * Prints a sparse matrix to the standard output. Only the non-zero entries
+ * are printed.
+ *
+ * \return Error code.
+ *
+ * Time complexity: O(n), the number of non-zero elements.
+ */
+int igraph_spmatrix_print(const igraph_spmatrix_t* matrix) {
+	return igraph_spmatrix_fprint(matrix, stdout);
+}
+#endif
+
+/**
+ * \function igraph_spmatrix_fprint
+ * \brief Prints a sparse matrix to the given file.
+ *
+ * Prints a sparse matrix to the given file. Only the non-zero entries
+ * are printed.
+ *
+ * \return Error code.
+ *
+ * Time complexity: O(n), the number of non-zero elements.
+ */
+int igraph_spmatrix_fprint(const igraph_spmatrix_t* matrix, FILE *file) {
+  igraph_spmatrix_iter_t mit;
+
+  IGRAPH_CHECK(igraph_spmatrix_iter_create(&mit, matrix));
+  IGRAPH_FINALLY(igraph_spmatrix_iter_destroy, &mit);
+  while (!igraph_spmatrix_iter_end(&mit)) {
+		fprintf(file, "[%ld, %ld] = %.4f\n", (long int)mit.ri,
+				(long int)mit.ci, mit.value);
+    igraph_spmatrix_iter_next(&mit);
+  }
+  igraph_spmatrix_iter_destroy(&mit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+
diff --git a/src/st-cuts.c b/src/st-cuts.c
new file mode 100644
index 0000000..01863d1
--- /dev/null
+++ b/src/st-cuts.c
@@ -0,0 +1,1510 @@
+/* -*- 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_flow.h"
+#include "igraph_flow_internal.h"
+#include "igraph_error.h"
+#include "igraph_memory.h"
+#include "igraph_constants.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_conversion.h"
+#include "igraph_constructors.h"
+#include "igraph_structural.h"
+#include "igraph_components.h"
+#include "igraph_types_internal.h"
+#include "config.h"
+#include "igraph_math.h"
+#include "igraph_dqueue.h"
+#include "igraph_visitor.h"
+#include "igraph_marked_queue.h"
+#include "igraph_stack.h"
+#include "igraph_estack.h"
+
+/*
+ * \function igraph_even_tarjan_reduction
+ * Even-Tarjan reduction of a graph
+ * 
+ * \example examples/simple/even_tarjan.c
+ */
+
+int igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *graphbar,
+				 igraph_vector_t *capacity) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  
+  long int new_no_of_nodes=no_of_nodes*2;
+  long int new_no_of_edges=no_of_nodes + no_of_edges * 2;
+  
+  igraph_vector_t edges;
+  long int edgeptr=0, capptr=0;
+  long int i;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, new_no_of_edges * 2);
+
+  if (capacity) { 
+    IGRAPH_CHECK(igraph_vector_resize(capacity, new_no_of_edges));
+  }
+
+  /* Every vertex 'i' is replaced by two vertices, i' and i'' */
+  /* id[i'] := id[i] ; id[i''] := id[i] + no_of_nodes */
+
+  /* One edge for each original vertex, for i, we add (i',i'') */
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(edges)[edgeptr++] = i;
+    VECTOR(edges)[edgeptr++] = i + no_of_nodes;
+    if (capacity) { 
+      VECTOR(*capacity)[capptr++] = 1.0;
+    }
+  }
+  
+  /* Two news edges for each original edge 
+     (from,to) becomes (from'',to'), (to'',from') */
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+    long int to=IGRAPH_TO(graph, i);
+    VECTOR(edges)[edgeptr++] = from + no_of_nodes;
+    VECTOR(edges)[edgeptr++] = to;
+    VECTOR(edges)[edgeptr++] = to + no_of_nodes;
+    VECTOR(edges)[edgeptr++] = from;
+    if (capacity) { 
+      VECTOR(*capacity)[capptr++] = no_of_nodes; /* TODO: should be Inf */
+      VECTOR(*capacity)[capptr++] = no_of_nodes; /* TODO: should be Inf */
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graphbar, &edges, (igraph_integer_t) 
+			     new_no_of_nodes, IGRAPH_DIRECTED));
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_residual_graph(const igraph_t *graph,
+			    const igraph_vector_t *capacity,
+			    igraph_t *residual,
+			    igraph_vector_t *residual_capacity,
+			    const igraph_vector_t *flow, 
+			    igraph_vector_t *tmp) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int i, no_new_edges=0;
+  long int edgeptr=0, capptr=0;
+  
+  for (i=0; i<no_of_edges; i++) {
+    if (VECTOR(*flow)[i] < VECTOR(*capacity)[i]) {
+      no_new_edges++;
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(tmp, no_new_edges*2));
+  if (residual_capacity) {
+    IGRAPH_CHECK(igraph_vector_resize(residual_capacity, no_new_edges));
+  }
+  
+  for (i=0; i<no_of_edges; i++) {
+    if (VECTOR(*capacity)[i] - VECTOR(*flow)[i] > 0) {
+      long int from=IGRAPH_FROM(graph, i);
+      long int to=IGRAPH_TO(graph, i);
+      igraph_real_t c=VECTOR(*capacity)[i];
+      VECTOR(*tmp)[edgeptr++] = from;
+      VECTOR(*tmp)[edgeptr++] = to;
+      if (residual_capacity) {
+	VECTOR(*residual_capacity)[capptr++] = c;
+      }
+    }
+  }
+
+  IGRAPH_CHECK(igraph_create(residual, tmp, (igraph_integer_t) no_of_nodes,
+			     IGRAPH_DIRECTED));  
+
+  return 0;
+}
+
+int igraph_residual_graph(const igraph_t *graph,
+			  const igraph_vector_t *capacity,
+			  igraph_t *residual,
+			  igraph_vector_t *residual_capacity,
+			  const igraph_vector_t *flow) {
+  
+  igraph_vector_t tmp;
+  long int no_of_edges=igraph_ecount(graph);
+  
+  if (igraph_vector_size(capacity) != no_of_edges) {
+    IGRAPH_ERROR("Invalid `capacity' vector size", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_size(flow) != no_of_edges) {
+    IGRAPH_ERROR("Invalid `flow' vector size", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+
+  IGRAPH_CHECK(igraph_i_residual_graph(graph, capacity, residual, 
+				       residual_capacity, flow, &tmp));
+  
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_reverse_residual_graph(const igraph_t *graph,
+				    const igraph_vector_t *capacity,
+				    igraph_t *residual,
+				    const igraph_vector_t *flow,
+				    igraph_vector_t *tmp) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int i, no_new_edges=0;
+  long int edgeptr=0;
+
+  for (i=0; i<no_of_edges; i++) {
+    igraph_real_t cap=capacity ? VECTOR(*capacity)[i] : 1.0;
+    if (VECTOR(*flow)[i] > 0) {
+      no_new_edges++;
+    }
+    if (VECTOR(*flow)[i] < cap) {
+      no_new_edges++;
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(tmp, no_new_edges*2));
+
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+    long int to=IGRAPH_TO(graph, i);
+    igraph_real_t cap=capacity ? VECTOR(*capacity)[i] : 1.0;
+    if (VECTOR(*flow)[i] > 0) {
+      VECTOR(*tmp)[edgeptr++] = from;
+      VECTOR(*tmp)[edgeptr++] = to;
+    }
+    if (VECTOR(*flow)[i] < cap) {
+      VECTOR(*tmp)[edgeptr++] = to;
+      VECTOR(*tmp)[edgeptr++] = from;
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(residual, tmp, (igraph_integer_t) no_of_nodes,
+			     IGRAPH_DIRECTED));
+  
+  return 0;
+}
+  
+int igraph_reverse_residual_graph(const igraph_t *graph,
+				  const igraph_vector_t *capacity,
+				  igraph_t *residual,
+				  const igraph_vector_t *flow) {
+  igraph_vector_t tmp;
+  long int no_of_edges=igraph_ecount(graph);
+  
+  if (capacity && igraph_vector_size(capacity) != no_of_edges) {
+    IGRAPH_ERROR("Invalid `capacity' vector size", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_size(flow) != no_of_edges) {
+    IGRAPH_ERROR("Invalid `flow' vector size", IGRAPH_EINVAL);
+  }
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  
+  IGRAPH_CHECK(igraph_i_reverse_residual_graph(graph, capacity, residual,
+					       flow, &tmp));
+  
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+typedef struct igraph_i_dbucket_t {
+  igraph_vector_long_t head;
+  igraph_vector_long_t next;
+} igraph_i_dbucket_t;
+
+int igraph_i_dbucket_init(igraph_i_dbucket_t *buck, long int size) {
+  IGRAPH_CHECK(igraph_vector_long_init(&buck->head, size));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &buck->head);
+  IGRAPH_CHECK(igraph_vector_long_init(&buck->next, size));
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+void igraph_i_dbucket_destroy(igraph_i_dbucket_t *buck) {
+  igraph_vector_long_destroy(&buck->head);
+  igraph_vector_long_destroy(&buck->next);
+}
+
+int igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, long int bid, 
+			    long int elem) {
+  /* Note: we can do this, since elem is not in any buckets */
+  VECTOR(buck->next)[elem]=VECTOR(buck->head)[bid];
+  VECTOR(buck->head)[bid]=elem+1;
+  return 0;
+}
+
+long int igraph_i_dbucket_empty(const igraph_i_dbucket_t *buck, 
+				long int bid) {
+  return VECTOR(buck->head)[bid] == 0;
+}
+
+long int igraph_i_dbucket_delete(igraph_i_dbucket_t *buck, long int bid) {
+  long int elem=VECTOR(buck->head)[bid]-1;
+  VECTOR(buck->head)[bid]=VECTOR(buck->next)[elem];
+  return elem;
+}
+
+int igraph_i_dominator_LINK(long int v, long int w,
+			    igraph_vector_long_t *ancestor) {
+  VECTOR(*ancestor)[w] = v+1;
+  return 0;
+}
+
+/* TODO: don't always reallocate path */
+
+int igraph_i_dominator_COMPRESS(long int v,
+				igraph_vector_long_t *ancestor,
+				igraph_vector_long_t *label,
+				igraph_vector_long_t *semi) {
+  igraph_stack_long_t path;
+  long int w=v;
+  long int top, pretop;
+    
+  IGRAPH_CHECK(igraph_stack_long_init(&path, 10));
+  IGRAPH_FINALLY(igraph_stack_long_destroy, &path);
+  
+  while (VECTOR(*ancestor)[w] != 0) {
+    IGRAPH_CHECK(igraph_stack_long_push(&path, w));
+    w=VECTOR(*ancestor)[w]-1;
+  }
+  
+  top=igraph_stack_long_pop(&path);
+  while (!igraph_stack_long_empty(&path)) {
+    pretop=igraph_stack_long_pop(&path);
+
+    if (VECTOR(*semi)[VECTOR(*label)[top]] < 
+	VECTOR(*semi)[VECTOR(*label)[pretop]]) {
+      VECTOR(*label)[pretop] = VECTOR(*label)[top];
+    }
+    VECTOR(*ancestor)[pretop]=VECTOR(*ancestor)[top];
+
+    top=pretop;
+  }
+
+  igraph_stack_long_destroy(&path);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+long int igraph_i_dominator_EVAL(long int v,
+				 igraph_vector_long_t *ancestor,
+				 igraph_vector_long_t *label,
+				 igraph_vector_long_t *semi) {
+  if (VECTOR(*ancestor)[v] == 0) { 
+    return v;
+  } else {
+    igraph_i_dominator_COMPRESS(v, ancestor, label, semi);
+    return VECTOR(*label)[v];
+  }
+}
+
+/* TODO: implement the faster version. */
+
+/** 
+ * \function igraph_dominator_tree
+ * Calculates the dominator tree of a flowgraph
+ * 
+ * A flowgraph is a directed graph with a distinguished start (or
+ * root) vertex r, such that for any vertex v, there is a path from r
+ * to v. A vertex v dominates another vertex w (not equal to v), if
+ * every path from r to w contains v. Vertex v is the immediate
+ * dominator or w, v=idom(w), if v dominates w and every other
+ * dominator of w dominates v. The edges {(idom(w), w)| w is not r}
+ * form a directed tree, rooted at r, called the dominator tree of the
+ * graph. Vertex v dominates vertex w if and only if v is an ancestor
+ * of w in the dominator tree.
+ * 
+ * </para><para>This function implements the Lengauer-Tarjan algorithm
+ * to construct the dominator tree of a directed graph. For details
+ * please see Thomas Lengauer, Robert Endre Tarjan: A fast algorithm
+ * for finding dominators in a flowgraph, ACM Transactions on
+ * Programming Languages and Systems (TOPLAS) I/1, 121--141, 1979.
+ * 
+ * \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 in the \c leftout
+ *        vector.
+ * \param root The id of the root (or source) vertex, this will be the
+ *        root of the tree.
+ * \param dom Pointer to an initialized vector or a null pointer. If
+ *        not a null pointer, then the immediate dominator of each
+ *        vertex will be stored here. For vertices that are not
+ *        reachable from the root, \c IGRAPH_NAN is stored here. For
+ *        the root vertex itself, -1 is added.
+ * \param domtree Pointer to an uninitialized igraph_t, or NULL. If
+ *        not a null pointer, then the dominator tree is returned
+ *        here. The graph contains the vertices that are unreachable
+ *        from the root (if any), these will be isolates.
+ * \param leftout Pointer to an initialized vector object, or NULL. If
+ *        not NULL, then the ids of the vertices that are unreachable
+ *        from the root vertex (and thus not part of the dominator
+ *        tree) are stored here.
+ * \param mode Constant, must be \c IGRAPH_IN or \c IGRAPH_OUT. If it
+ *        is \c IGRAPH_IN, then all directions are considered as
+ *        opposite to the original one in the input graph.
+ * \return Error code.
+ * 
+ * Time complexity: very close to O(|E|+|V|), linear in the number of
+ * edges and vertices. More precisely, it is O(|V|+|E|alpha(|E|,|V|)),
+ * where alpha(|E|,|V|) is a functional inverse of Ackermann's
+ * function.
+ * 
+ * \example examples/simple/dominator_tree.c
+ */
+
+int igraph_dominator_tree(const igraph_t *graph,
+			  igraph_integer_t root,
+			  igraph_vector_t *dom,
+			  igraph_t *domtree,
+			  igraph_vector_t *leftout,
+			  igraph_neimode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+
+  igraph_adjlist_t succ, pred;
+  igraph_vector_t parent;
+  igraph_vector_long_t semi;	/* +1 always */
+  igraph_vector_t vertex;	/* +1 always */
+  igraph_i_dbucket_t bucket;
+  igraph_vector_long_t ancestor;
+  igraph_vector_long_t label;
+
+  igraph_neimode_t invmode= mode==IGRAPH_IN ? IGRAPH_OUT: IGRAPH_IN;
+
+  long int i;
+
+  igraph_vector_t vdom, *mydom=dom;
+
+  long int component_size=0;
+
+  if (root < 0 || root >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid root vertex id for dominator tree", 
+		 IGRAPH_EINVAL);
+  }
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_ERROR("Dominator tree of an undirected graph requested",
+		 IGRAPH_EINVAL);
+  }
+  
+  if (mode == IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid neighbor mode for dominator tree",
+		 IGRAPH_EINVAL);
+  }
+
+  if (dom) {
+    IGRAPH_CHECK(igraph_vector_resize(dom, no_of_nodes));
+  } else {
+    mydom=&vdom;
+    IGRAPH_VECTOR_INIT_FINALLY(mydom, no_of_nodes);
+  }
+  igraph_vector_fill(mydom, IGRAPH_NAN);
+
+  IGRAPH_CHECK(igraph_vector_init(&parent, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_destroy, &parent);
+  IGRAPH_CHECK(igraph_vector_long_init(&semi, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &semi);
+  IGRAPH_CHECK(igraph_vector_init(&vertex, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_destroy, &vertex);
+  IGRAPH_CHECK(igraph_vector_long_init(&ancestor, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &ancestor);
+  IGRAPH_CHECK(igraph_vector_long_init_seq(&label, 0, no_of_nodes-1));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &label);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &succ, mode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &succ);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &pred, invmode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &pred);
+  IGRAPH_CHECK(igraph_i_dbucket_init(&bucket, no_of_nodes));
+  IGRAPH_FINALLY(igraph_i_dbucket_destroy, &bucket);
+
+  /* DFS first, to set semi, vertex and parent, step 1 */
+  
+  IGRAPH_CHECK(igraph_dfs(graph, root, mode, /*unreachable=*/ 0,
+			  /*order=*/ &vertex,
+			  /*order_out=*/ 0, /*father=*/ &parent,
+			  /*dist=*/ 0, /*in_callback=*/ 0, 
+			  /*out_callback=*/ 0, /*extra=*/ 0));
+
+  for (i=0; i<no_of_nodes; i++) {
+    if (IGRAPH_FINITE(VECTOR(vertex)[i])) {
+      long int t=(long int) VECTOR(vertex)[i];
+      VECTOR(semi)[t] = component_size+1;
+      VECTOR(vertex)[component_size] = t+1;
+      component_size++;
+    }
+  }
+  if (leftout) {
+    long int n=no_of_nodes-component_size;
+    long int p=0, j;
+    IGRAPH_CHECK(igraph_vector_resize(leftout, n));
+    for (j=0; j<no_of_nodes && p<n; j++) {
+      if (!IGRAPH_FINITE(VECTOR(parent)[j])) {
+	VECTOR(*leftout)[p++] = j;
+      }
+    }
+  }
+
+  /* We need to go over 'pred' because it should contain only the
+     edges towards the target vertex. */
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_vector_int_t *v=igraph_adjlist_get(&pred, i);
+    long int j, n=igraph_vector_int_size(v);
+    for (j=0; j<n; ) {
+      long int v2=(long int) VECTOR(*v)[j];
+      if (IGRAPH_FINITE(VECTOR(parent)[v2])) {
+	j++; 
+      } else {
+	VECTOR(*v)[j]=VECTOR(*v)[n-1];
+	igraph_vector_int_pop_back(v);
+	n--;
+      }
+    }
+  }
+
+  /* Now comes the main algorithm, steps 2 & 3 */
+
+  for (i=component_size-1; i>0; i--) {
+    long int w=(long int) VECTOR(vertex)[i]-1;
+    igraph_vector_int_t *predw=igraph_adjlist_get(&pred, w);
+    long int j, n=igraph_vector_int_size(predw);
+    for (j=0; j<n; j++) {
+      long int v=(long int) VECTOR(*predw)[j];
+      long int u=igraph_i_dominator_EVAL(v, &ancestor, &label, &semi);
+      if (VECTOR(semi)[u] < VECTOR(semi)[w]) {
+	VECTOR(semi)[w]=VECTOR(semi)[u];
+      }
+    }
+    igraph_i_dbucket_insert(&bucket, (long int) 
+			    VECTOR(vertex)[ VECTOR(semi)[w]-1 ]-1, w);
+    igraph_i_dominator_LINK((long int) VECTOR(parent)[w], w, &ancestor);
+    while (!igraph_i_dbucket_empty(&bucket, (long int) VECTOR(parent)[w])) {
+      long int v=igraph_i_dbucket_delete(&bucket, (long int) VECTOR(parent)[w]);
+      long int u=igraph_i_dominator_EVAL(v, &ancestor, &label, &semi);
+      VECTOR(*mydom)[v] = VECTOR(semi)[u] < VECTOR(semi)[v] ? u : 
+	VECTOR(parent)[w];
+    }
+  }
+
+  /* Finally, step 4 */
+
+  for (i=1; i<component_size; i++) {
+    long int w=(long int) VECTOR(vertex)[i]-1;
+    if (VECTOR(*mydom)[w] != VECTOR(vertex)[VECTOR(semi)[w]-1]-1) {
+      VECTOR(*mydom)[w] = VECTOR(*mydom)[(long int)VECTOR(*mydom)[w]];
+    }
+  }
+  VECTOR(*mydom)[(long int)root]=-1;
+
+  igraph_i_dbucket_destroy(&bucket);
+  igraph_adjlist_destroy(&pred);
+  igraph_adjlist_destroy(&succ);
+  igraph_vector_long_destroy(&label);
+  igraph_vector_long_destroy(&ancestor);
+  igraph_vector_destroy(&vertex);
+  igraph_vector_long_destroy(&semi);
+  igraph_vector_destroy(&parent);
+  IGRAPH_FINALLY_CLEAN(8);
+
+  if (domtree) {
+    igraph_vector_t edges;
+    long int ptr=0;
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, component_size*2-2);
+    for (i=0; i<no_of_nodes; i++) {
+      if (i!=root && IGRAPH_FINITE(VECTOR(*mydom)[i])) {
+	if (mode==IGRAPH_OUT) {
+	  VECTOR(edges)[ptr++] = VECTOR(*mydom)[i];
+	  VECTOR(edges)[ptr++] = i;
+	} else {
+	  VECTOR(edges)[ptr++] = i;
+	  VECTOR(edges)[ptr++] = VECTOR(*mydom)[i];
+	}
+      }
+    }
+    IGRAPH_CHECK(igraph_create(domtree, &edges, (igraph_integer_t) no_of_nodes,
+			       IGRAPH_DIRECTED));
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+    
+    IGRAPH_I_ATTRIBUTE_DESTROY(domtree);
+    IGRAPH_I_ATTRIBUTE_COPY(domtree, graph, /*graph=*/ 1, /*vertex=*/ 1, 
+			    /*edge=*/ 0);
+  }
+
+  if (!dom) {
+    igraph_vector_destroy(&vdom);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+typedef struct igraph_i_all_st_cuts_minimal_dfs_data_t {
+  igraph_stack_t *stack;
+  igraph_vector_bool_t *nomark;  
+  const igraph_vector_bool_t *GammaX;
+  long int root;
+  const igraph_vector_t *map;
+} igraph_i_all_st_cuts_minimal_dfs_data_t;
+
+igraph_bool_t igraph_i_all_st_cuts_minimal_dfs_incb(const igraph_t *graph,
+						    igraph_integer_t vid,
+						    igraph_integer_t dist,
+						    void *extra) {
+
+  igraph_i_all_st_cuts_minimal_dfs_data_t *data=extra;
+  igraph_stack_t *stack=data->stack;
+  igraph_vector_bool_t *nomark=data->nomark;
+  const igraph_vector_bool_t *GammaX=data->GammaX;
+  const igraph_vector_t *map=data->map;
+  long int realvid=(long int) VECTOR(*map)[(long int)vid];
+
+  IGRAPH_UNUSED(graph); IGRAPH_UNUSED(dist);
+
+  if (VECTOR(*GammaX)[(long int)realvid]) {
+    if (!igraph_stack_empty(stack)) {
+      long int top=(long int) igraph_stack_top(stack);
+      VECTOR(*nomark)[top]=1;	/* we just found a smaller one */
+    }
+    igraph_stack_push(stack, realvid); /* TODO: error check */
+  }
+
+  return 0;
+}
+
+igraph_bool_t igraph_i_all_st_cuts_minimal_dfs_otcb(const igraph_t *graph,
+						    igraph_integer_t vid,
+						    igraph_integer_t dist,
+						    void *extra) {
+  igraph_i_all_st_cuts_minimal_dfs_data_t *data=extra;
+  igraph_stack_t *stack=data->stack;
+  const igraph_vector_t *map=data->map;
+  long int realvid=(long int) VECTOR(*map)[(long int)vid];
+
+  IGRAPH_UNUSED(graph); IGRAPH_UNUSED(dist);
+
+  if (!igraph_stack_empty(stack) && 
+      igraph_stack_top(stack) == realvid) {
+    igraph_stack_pop(stack);
+  }
+
+  return 0;
+}
+
+int igraph_i_all_st_cuts_minimal(const igraph_t *graph,
+				 const igraph_t *domtree,
+				 long int root,
+				 const igraph_marked_queue_t *X,
+				 const igraph_vector_bool_t *GammaX,
+				 const igraph_vector_t *invmap,
+				 igraph_vector_t *minimal) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_stack_t stack;
+  igraph_vector_bool_t nomark;
+  igraph_i_all_st_cuts_minimal_dfs_data_t data;
+  long int i;
+
+  IGRAPH_UNUSED(X);
+  
+  IGRAPH_CHECK(igraph_stack_init(&stack, 10));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+  IGRAPH_CHECK(igraph_vector_bool_init(&nomark, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &nomark);
+
+  data.stack=&stack;
+  data.nomark=&nomark;
+  data.GammaX=GammaX;
+  data.root=root;
+  data.map=invmap;
+
+  /* We mark all GammaX elements as minimal first.
+     TODO: actually, we could just use GammaX to return the minimal
+     elements. */
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(nomark)[i] = VECTOR(*GammaX)[i] == 0 ? 1 : 0;
+  }
+
+  /* We do a reverse DFS from root. If, along a path we find a GammaX
+     vertex after (=below) another GammaX vertex, we mark the higher
+     one as non-minimal. */
+
+  IGRAPH_CHECK(igraph_dfs(domtree, (igraph_integer_t) root, IGRAPH_IN, 
+			  /*unreachable=*/ 0, /*order=*/ 0,
+			  /*order_out=*/ 0, /*father=*/ 0, 
+			  /*dist=*/ 0, /*in_callback=*/ 
+			  igraph_i_all_st_cuts_minimal_dfs_incb,
+			  /*out_callback=*/ 
+			  igraph_i_all_st_cuts_minimal_dfs_otcb,
+			  /*extra=*/ &data));
+  
+  igraph_vector_clear(minimal);
+  for (i=0; i<no_of_nodes; i++) {
+    if (!VECTOR(nomark)[i]) { 
+      IGRAPH_CHECK(igraph_vector_push_back(minimal, i));
+    }
+  }
+
+  igraph_vector_bool_destroy(&nomark);
+  igraph_stack_destroy(&stack);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+int igraph_i_all_st_cuts_pivot(const igraph_t *graph,
+			       const igraph_marked_queue_t *S,
+			       const igraph_estack_t *T,
+			       long int source,
+			       long int target,
+			       long int *v,
+			       igraph_vector_t *Isv,
+			       void *arg) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_t Sbar;
+  igraph_vector_t Sbar_map, Sbar_invmap;
+  igraph_vector_t keep;
+  igraph_t domtree;
+  igraph_vector_t leftout;
+  long int i, nomin;
+  long int root;
+  igraph_vector_t M;
+  igraph_vector_bool_t GammaS;
+  igraph_vector_t Nuv;
+  igraph_vector_t Isv_min;
+  igraph_vector_t GammaS_vec;
+  long int Sbar_size;
+
+  IGRAPH_UNUSED(arg);
+
+  /* We need to create the graph induced by Sbar */
+  IGRAPH_VECTOR_INIT_FINALLY(&Sbar_map, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&Sbar_invmap, 0);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&keep, 0);
+  for (i=0; i<no_of_nodes; i++) {
+    if (!igraph_marked_queue_iselement(S, i)) {
+      IGRAPH_CHECK(igraph_vector_push_back(&keep, i));
+    }
+  }
+  Sbar_size=igraph_vector_size(&keep);
+
+  IGRAPH_CHECK(igraph_induced_subgraph_map(graph, &Sbar,
+					   igraph_vss_vector(&keep),
+					   IGRAPH_SUBGRAPH_AUTO,
+					   /* map= */ &Sbar_map, 
+					   /* invmap= */ &Sbar_invmap));  
+  igraph_vector_destroy(&keep);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, &Sbar);
+
+  root=(long int) VECTOR(Sbar_map)[target]-1;
+
+  /* -------------------------------------------------------------*/
+  /* Construct the dominator tree of Sbar */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&leftout, 0);
+  IGRAPH_CHECK(igraph_dominator_tree(&Sbar, (igraph_integer_t) root, 
+				     /*dom=*/ 0, &domtree,
+				     &leftout, IGRAPH_IN));
+  IGRAPH_FINALLY(igraph_destroy, &domtree);
+
+  /* -------------------------------------------------------------*/
+  /* Identify the set M of minimal elements of Gamma(S) with respect
+     to the dominator relation. */
+  
+  /* First we create GammaS */
+  /* TODO: use the adjacency list, instead of neighbors() */
+  IGRAPH_CHECK(igraph_vector_bool_init(&GammaS, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &GammaS);
+  if (igraph_marked_queue_size(S)==0) {
+    VECTOR(GammaS)[(long int) VECTOR(Sbar_map)[source]-1]=1;
+  } else {
+    for (i=0; i<no_of_nodes; i++) {
+      if (igraph_marked_queue_iselement(S, i)) {
+	igraph_vector_t neis;
+	long int j, n;
+	IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+	IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i,
+				      IGRAPH_OUT));
+	n=igraph_vector_size(&neis);
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (!igraph_marked_queue_iselement(S, nei)) {
+	    VECTOR(GammaS)[nei]=1;
+	  }
+	}
+	igraph_vector_destroy(&neis);
+	IGRAPH_FINALLY_CLEAN(1);
+      }
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&M, 0);
+  if (igraph_ecount(&domtree)>0) {
+    IGRAPH_CHECK(igraph_i_all_st_cuts_minimal(graph, &domtree, root, S,
+					      &GammaS, &Sbar_invmap, &M));
+  }
+
+  igraph_vector_clear(Isv);
+  IGRAPH_VECTOR_INIT_FINALLY(&Nuv, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&Isv_min, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&GammaS_vec, 0);
+  for (i=0; i<no_of_nodes; i++) {
+    if (VECTOR(GammaS)[i]) {
+      IGRAPH_CHECK(igraph_vector_push_back(&GammaS_vec, i));
+    }
+  }
+
+  nomin=igraph_vector_size(&M);
+  for (i=0; i<nomin; i++) {
+    /* -------------------------------------------------------------*/
+    /* For each v in M find the set Nu(v)=dom(Sbar, v)-K
+       Nu(v) contains all vertices that are dominated by v, for every
+       v, this is a subtree of the dominator tree, rooted at v. The
+       different subtrees are disjoint. */
+    long int min=(long int) VECTOR(Sbar_map)[(long int) VECTOR(M)[i] ]-1;
+    long int nuvsize, isvlen, j;
+    IGRAPH_CHECK(igraph_dfs(&domtree, (igraph_integer_t) min, IGRAPH_IN, 
+			    /*unreachable=*/ 0, /*order=*/ &Nuv, 
+			    /*order_out=*/ 0, /*father=*/ 0, /*dist=*/ 0,
+			    /*in_callback=*/ 0, /*out_callback=*/ 0, 
+			    /*extra=*/ 0));
+    /* Remove the NAN values from the end of the vector */
+    for (nuvsize=0; nuvsize<Sbar_size; nuvsize++) {
+      igraph_real_t t=VECTOR(Nuv)[nuvsize];
+      if (IGRAPH_FINITE(t)) {
+	VECTOR(Nuv)[nuvsize]=VECTOR(Sbar_invmap)[(long int) t];
+      } else {
+	break;
+      }
+    }
+    igraph_vector_resize(&Nuv, nuvsize);
+    
+    /* -------------------------------------------------------------*/
+    /* By a BFS search of <Nu(v)> determine I(S,v)-K.
+       I(S,v) contains all vertices that are in Nu(v) and that are
+       reachable from Gamma(S) via a path in Nu(v). */
+    IGRAPH_CHECK(igraph_bfs(graph, /*root=*/ -1, /*roots=*/ &GammaS_vec,
+			    /*mode=*/ IGRAPH_OUT, /*unreachable=*/ 0,
+			    /*restricted=*/ &Nuv, 
+			    /*order=*/ &Isv_min, /*rank=*/ 0,
+			    /*father=*/ 0, /*pred=*/ 0, /*succ=*/ 0,
+			    /*dist=*/ 0, /*callback=*/ 0, /*extra=*/ 0));
+    for (isvlen=0; isvlen<no_of_nodes; isvlen++) {
+      if (!IGRAPH_FINITE(VECTOR(Isv_min)[isvlen])) { break; }
+    }
+    igraph_vector_resize(&Isv_min, isvlen);
+    
+    /* -------------------------------------------------------------*/
+    /* For each c in M check whether Isv-K is included in Tbar. If 
+       such a v is found, compute Isv={x|v[Nu(v) U K]x} and return v and 
+       Isv; otherwise return Isv={}. */
+    for (j=0; j<isvlen; j++) {
+      long int v=(long int) VECTOR(Isv_min)[j];
+      if (igraph_estack_iselement(T, v) || v==target) { break; }
+    }
+    /* We might have found one */
+    if (j==isvlen) {
+      *v=(long int) VECTOR(M)[i];
+      /* Calculate real Isv */
+      IGRAPH_CHECK(igraph_vector_append(&Nuv, &leftout));
+      IGRAPH_CHECK(igraph_bfs(graph, /*root=*/ (igraph_integer_t) *v, 
+			      /*roots=*/ 0, /*mode=*/ IGRAPH_OUT, 
+			      /*unreachable=*/ 0, /*restricted=*/ &Nuv, 
+			      /*order=*/ &Isv_min, /*rank=*/ 0,
+			      /*father=*/ 0, /*pred=*/ 0, /*succ=*/ 0,
+			      /*dist=*/ 0, /*callback=*/ 0, /*extra=*/ 0));
+      for (isvlen=0; isvlen<no_of_nodes; isvlen++) {
+	if (!IGRAPH_FINITE(VECTOR(Isv_min)[isvlen])) { break; }
+      }
+      igraph_vector_resize(&Isv_min, isvlen);
+      igraph_vector_update(Isv, &Isv_min);
+
+      break;
+    }
+  }
+
+  igraph_vector_destroy(&GammaS_vec);
+  igraph_vector_destroy(&Isv_min);
+  igraph_vector_destroy(&Nuv);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  igraph_vector_destroy(&M);
+  igraph_vector_bool_destroy(&GammaS);
+  igraph_destroy(&domtree);
+  igraph_vector_destroy(&leftout);  
+  igraph_destroy(&Sbar);
+  igraph_vector_destroy(&Sbar_map);
+  igraph_vector_destroy(&Sbar_invmap);
+  IGRAPH_FINALLY_CLEAN(7);
+
+  return 0;
+}
+
+/* TODO: This is a temporary recursive version, without proper error
+   handling */
+
+int igraph_provan_shier_list(const igraph_t *graph,
+			     igraph_marked_queue_t *S,
+			     igraph_estack_t *T,
+			     long int source,
+			     long int target,
+			     igraph_vector_ptr_t *result,
+			     igraph_provan_shier_pivot_t *pivot,
+			     void *pivot_arg) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t Isv;
+  long int v=0;
+  long int i, n;
+
+  igraph_vector_init(&Isv, 0);
+  
+  pivot(graph, S, T, source, target, &v, &Isv, pivot_arg);
+  if (igraph_vector_size(&Isv)==0) {
+    if (igraph_marked_queue_size(S) != 0 && 
+	igraph_marked_queue_size(S) != no_of_nodes) {
+      igraph_vector_t *vec=igraph_Calloc(1, igraph_vector_t);      
+      igraph_vector_init(vec, igraph_marked_queue_size(S));
+      igraph_marked_queue_as_vector(S, vec);      
+      IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec));
+    }
+  } else {
+    /* Put v into T */
+    igraph_estack_push(T, v);
+
+    /* Go down left in the search tree */
+    igraph_provan_shier_list(graph, S, T, source, target, 
+			     result, pivot, pivot_arg);
+
+    /* Take out v from T */
+    igraph_estack_pop(T);
+    
+    /* Add Isv to S */
+    igraph_marked_queue_start_batch(S);
+    n=igraph_vector_size(&Isv);
+    for (i=0; i<n; i++) {
+      if (!igraph_marked_queue_iselement(S, (long int) VECTOR(Isv)[i])) {
+	igraph_marked_queue_push(S, (long int) VECTOR(Isv)[i]);
+      }
+    }
+
+    /* Go down right in the search tree */
+    
+    igraph_provan_shier_list(graph, S, T, source, target, 
+			     result, pivot, pivot_arg);
+
+    /* Take out Isv from S */
+    igraph_marked_queue_pop_back_batch(S);
+  }
+    
+  igraph_vector_destroy(&Isv);
+
+  return 0;
+}
+
+/**
+ * \function igraph_all_st_cuts
+ * List all edge-cuts between two vertices in a directed graph
+ * 
+ * This function lists all edge-cuts between a source and a target
+ * vertex. Every cut is listed exactly once. The implemented algorithm
+ * is described in JS Provan and DR Shier: A Paradigm for listing
+ * (s,t)-cuts in graphs, Algorithmica 15, 351--372, 1996.
+ * 
+ * \param graph The input graph, is must be directed.
+ * \param cuts An initialized pointer vector, the cuts are stored
+ *        here. It is a list of pointers to igraph_vector_t
+ *        objects. Each vector will contain the ids of the edges in
+ *        the cut. This argument is ignored if it is a null pointer.
+ *        To free all memory allocated for \c cuts, you need call 
+ *        \ref igraph_vector_destroy() and then \ref igraph_free() on
+ *        each element, before destroying the pointer vector itself.
+ * \param partition1s An initialized pointer vector, the list of
+ *        vertex sets, generating the actual edge cuts, are stored
+ *        here. Each vector contains a set of vertex ids. If X is such
+ *        a set, then all edges going from X to the complement of X
+ *        form an (s,t) edge-cut in the graph. This argument is
+ *        ignored if it is a null pointer.
+ *        To free all memory allocated for \c partition1s, you need call 
+ *        \ref igraph_vector_destroy() and then \ref igraph_free() on
+ *        each element, before destroying the pointer vector itself.
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \return Error code.
+ * 
+ * Time complexity: O(n(|V|+|E|)), where |V| is the number of
+ * vertices, |E| is the number of edges, and n is the number of cuts.
+ * 
+ * \example examples/simple/igraph_all_st_cuts.c
+ */
+
+int igraph_all_st_cuts(const igraph_t *graph,
+		       igraph_vector_ptr_t *cuts,
+		       igraph_vector_ptr_t *partition1s,
+		       igraph_integer_t source,
+		       igraph_integer_t target) {
+
+  /* S is a special stack, in which elements are pushed in batches. 
+     It is then possible to remove the whole batch in one step.
+
+     T is a stack with an is-element operation.
+     Every element is included at most once.
+  */
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_marked_queue_t S;
+  igraph_estack_t T;
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_ERROR("Listing all s-t cuts only implemented for "
+		 "directed graphs", IGRAPH_UNIMPLEMENTED);
+  }
+  
+  if (!partition1s) { 
+    IGRAPH_ERROR("`partition1s' must not be a null pointer", 
+		 IGRAPH_UNIMPLEMENTED);
+  }
+
+  IGRAPH_CHECK(igraph_marked_queue_init(&S, no_of_nodes));
+  IGRAPH_FINALLY(igraph_marked_queue_destroy, &S);
+  IGRAPH_CHECK(igraph_estack_init(&T, no_of_nodes, 0));
+  IGRAPH_FINALLY(igraph_estack_destroy, &T);
+
+  if (cuts)        { igraph_vector_ptr_clear(cuts);        }
+  if (partition1s) { igraph_vector_ptr_clear(partition1s); }    
+  
+  /* We call it with S={}, T={} */
+  IGRAPH_CHECK(igraph_provan_shier_list(graph, &S, &T,
+					source, target, partition1s,
+					igraph_i_all_st_cuts_pivot, 
+					/*pivot_arg=*/ 0));
+  
+  if (cuts) {
+    igraph_vector_long_t inS;
+    long int i, nocuts=igraph_vector_ptr_size(partition1s);
+    IGRAPH_CHECK(igraph_vector_long_init(&inS, no_of_nodes));
+    IGRAPH_FINALLY(igraph_vector_long_destroy, &inS);
+    IGRAPH_CHECK(igraph_vector_ptr_resize(cuts, nocuts));
+    for (i=0; i<nocuts; i++) {
+      igraph_vector_t *cut;
+      igraph_vector_t *part=VECTOR(*partition1s)[i];
+      long int cutsize=0;
+      long int j, partlen=igraph_vector_size(part);
+      /* Mark elements */
+      for (j=0; j<partlen; j++) {
+	long int v=(long int) VECTOR(*part)[j];
+	VECTOR(inS)[v] = i+1;
+      }
+      /* Check how many edges */
+      for (j=0; j<no_of_edges; j++) {
+	long int from=IGRAPH_FROM(graph, j);
+	long int to=IGRAPH_TO(graph, j);
+	long int pfrom=VECTOR(inS)[from];
+	long int pto=VECTOR(inS)[to];
+	if (pfrom == i+1 && pto != i+1) { 
+	  cutsize++;
+	}
+      }
+      /* Add the edges */
+      cut=igraph_Calloc(1, igraph_vector_t);
+      if (!cut) {
+	IGRAPH_ERROR("Cannot calculate s-t cuts", IGRAPH_ENOMEM);
+      }
+      IGRAPH_VECTOR_INIT_FINALLY(cut, cutsize);
+      cutsize=0;
+      for (j=0; j<no_of_edges; j++) {
+	long int from=IGRAPH_FROM(graph, j);
+	long int to=IGRAPH_TO(graph, j);
+	long int pfrom=VECTOR(inS)[from];
+	long int pto=VECTOR(inS)[to];
+	if ((pfrom == i+1 && pto != i+1)) {
+	  VECTOR(*cut)[cutsize++]=j;
+	}
+      }
+      VECTOR(*cuts)[i]=cut;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    
+    igraph_vector_long_destroy(&inS);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/* We need to find the minimal active elements of Sbar. I.e. all
+   active Sbar elements 'v', s.t. there is no other 'w' active Sbar
+   element from which 'v' is reachable. (Not necessarily through
+   active vertices.)
+   
+   We calculate the in-degree of all vertices in Sbar first. Then we
+   look at the vertices with zero in-degree. If these are active,
+   then they are minimal. If they are are not active, then we remove
+   them from the graph, and check whether they resulted in more
+   zero-indegree vertices. 
+*/
+
+int igraph_i_all_st_mincuts_minimal(const igraph_t *Sbar,
+				    const igraph_vector_bool_t *active,
+				    const igraph_vector_t *invmap,
+				    igraph_vector_t *minimal) {
+
+  long int no_of_nodes=igraph_vcount(Sbar);
+  igraph_vector_t indeg;
+  long int i, minsize;
+  igraph_vector_t neis;
+  igraph_dqueue_t to_visit;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&indeg, no_of_nodes);
+  IGRAPH_CHECK(igraph_dqueue_init(&to_visit, 0));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &to_visit);
+
+  IGRAPH_CHECK(igraph_degree(Sbar, &indeg, igraph_vss_all(), 
+			     IGRAPH_IN, /*loops=*/ 1));
+
+#define ACTIVE(x) (VECTOR(*active)[(long int)VECTOR(*invmap)[(x)]])
+#define ZEROIN(x) (VECTOR(indeg)[(x)]==0)
+
+  for (i=0; i<no_of_nodes; i++) {
+    if (!ACTIVE(i) && ZEROIN(i)) {
+      IGRAPH_CHECK(igraph_dqueue_push(&to_visit, i));
+    }
+    while (!igraph_dqueue_empty(&to_visit)) {
+      long int rv=(long int) igraph_dqueue_pop(&to_visit);
+      long int j, n;
+      IGRAPH_CHECK(igraph_neighbors(Sbar, &neis, (igraph_integer_t) rv,
+				    IGRAPH_OUT));
+      n=igraph_vector_size(&neis);
+      for (j=0; j<n; j++) {
+	long int nei=(long int) VECTOR(neis)[j];
+	VECTOR(indeg)[nei] -= 1;
+	if (VECTOR(indeg)[nei] == 0) {
+	  IGRAPH_CHECK(igraph_dqueue_push(&to_visit, nei));
+	}
+      }
+    }
+  }
+  
+  for (minsize=0, i=0; i<no_of_nodes; i++) {
+    if (ACTIVE(i) && ZEROIN(i)) { minsize++; }
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(minimal, minsize));
+
+  for (minsize=0, i=0; i<no_of_nodes; i++) {
+    if (ACTIVE(i) && ZEROIN(i)) {
+      VECTOR(*minimal)[minsize++] = i; 
+    }
+  }
+
+#undef ACTIVE
+#undef ZEROIN
+  
+  igraph_dqueue_destroy(&to_visit);
+  igraph_vector_destroy(&indeg);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+typedef struct igraph_i_all_st_mincuts_data_t {
+  const igraph_vector_bool_t *active;
+} igraph_i_all_st_mincuts_data_t;
+
+int igraph_i_all_st_mincuts_pivot(const igraph_t *graph,
+				  const igraph_marked_queue_t *S,
+				  const igraph_estack_t *T,
+				  long int source,
+				  long int target,
+				  long int *v,
+				  igraph_vector_t *Isv,
+				  void *arg) {
+
+  igraph_i_all_st_mincuts_data_t *data=arg;
+  const igraph_vector_bool_t *active=data->active;
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  igraph_vector_t Sbar_map, Sbar_invmap;
+  igraph_vector_t keep;
+  igraph_t Sbar;
+  igraph_vector_t M;
+  long int nomin;
+
+  IGRAPH_UNUSED(source); IGRAPH_UNUSED(target);
+
+  if (igraph_marked_queue_size(S) == no_of_nodes) {
+    igraph_vector_clear(Isv);
+    return 0;
+  }
+
+  /* Create the graph induced by Sbar */
+  IGRAPH_VECTOR_INIT_FINALLY(&Sbar_map, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&Sbar_invmap, 0);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&keep, 0);
+  for (i=0; i<no_of_nodes; i++) {
+    if (!igraph_marked_queue_iselement(S, i)) {
+      IGRAPH_CHECK(igraph_vector_push_back(&keep, i));
+    }
+  }
+
+  /* TODO: it is not even necessary to create Sbar explicitly, we 
+     just need to find the M elements efficiently. See the
+     Provan-Shier paper for details. */
+  IGRAPH_CHECK(igraph_induced_subgraph_map(graph, &Sbar,
+					   igraph_vss_vector(&keep),
+					   IGRAPH_SUBGRAPH_AUTO,
+					   /* map= */ &Sbar_map, 
+					   /* invmap= */ &Sbar_invmap));  
+  IGRAPH_FINALLY(igraph_destroy, &Sbar);
+  
+  /* ------------------------------------------------------------- */
+  /* Identify the set M of minimal elements that are active */
+  IGRAPH_VECTOR_INIT_FINALLY(&M, 0);
+  IGRAPH_CHECK(igraph_i_all_st_mincuts_minimal(&Sbar, active, 
+					       &Sbar_invmap, &M));
+
+  /* ------------------------------------------------------------- */
+  /* Now find a minimal element that is not in T */  
+  igraph_vector_clear(Isv);
+  nomin=igraph_vector_size(&M);
+  for (i=0; i<nomin; i++) {
+    long int min=(long int) VECTOR(Sbar_invmap)[ (long int) VECTOR(M)[i] ];
+    if (!igraph_estack_iselement(T, min)) { break; }
+  }
+  if (i!=nomin) {
+    /* OK, we found a pivot element. I(S,v) contains all elements
+       that can reach the pivot element */
+    igraph_vector_t Isv_min;
+    long int isvlen;
+    IGRAPH_VECTOR_INIT_FINALLY(&Isv_min, 0);
+    *v=(long int) VECTOR(Sbar_invmap)[ (long int) VECTOR(M)[i] ];
+    /* TODO: restricted == keep ? */
+    IGRAPH_CHECK(igraph_bfs(graph, /*root=*/ (igraph_integer_t) *v,/*roots=*/ 0,
+			    /*mode=*/ IGRAPH_IN, /*unreachable=*/ 0,
+			    /*restricted=*/ &keep, /*order=*/ &Isv_min,
+			    /*rank=*/ 0, /*father=*/ 0, /*pred=*/ 0,
+			    /*succ=*/ 0, /*dist=*/ 0, /*callback=*/ 0,
+			    /*extra=*/ 0));
+    for (isvlen=0; isvlen<no_of_nodes; isvlen++) {
+      if (!IGRAPH_FINITE(VECTOR(Isv_min)[isvlen])) { break; }
+    }
+    igraph_vector_resize(&Isv_min, isvlen);
+    igraph_vector_update(Isv, &Isv_min);
+    igraph_vector_destroy(&Isv_min);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_destroy(&M);
+  igraph_destroy(&Sbar);
+  igraph_vector_destroy(&keep);
+  igraph_vector_destroy(&Sbar_invmap);
+  igraph_vector_destroy(&Sbar_map);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/** 
+ * \function igraph_all_st_mincuts
+ * All minimum s-t cuts of a directed graph
+ * 
+ * This function lists all minimum edge cuts between two vertices, in a
+ * directed graph. The implemented algorithm
+ * is described in JS Provan and DR Shier: A Paradigm for listing
+ * (s,t)-cuts in graphs, Algorithmica 15, 351--372, 1996.
+ * 
+ * \param graph The input graph, it must be directed.
+ * \param value Pointer to a real number, the value of the minimum cut
+ *        is stored here, unless it is a null pointer.
+ * \param cuts An initialized pointer vector, the cuts are stored
+ *        here. It is a list of pointers to igraph_vector_t
+ *        objects. Each vector will contain the ids of the edges in
+ *        the cut. This argument is ignored if it is a null pointer.
+ *        To free all memory allocated for \c cuts, you need call 
+ *        \ref igraph_vector_destroy() and then \ref igraph_free() on
+ *        each element, before destroying the pointer vector itself.
+ * \param partition1s An initialized pointer vector, the list of
+ *        vertex sets, generating the actual edge cuts, are stored
+ *        here. Each vector contains a set of vertex ids. If X is such
+ *        a set, then all edges going from X to the complement of X
+ *        form an (s,t) edge-cut in the graph. This argument is
+ *        ignored if it is a null pointer.
+ * \param source The id of the source vertex.
+ * \param target The id of the target vertex.
+ * \param capacity Vector of edge capacities. If this is a null
+ *        pointer, then all edges are assumed to have capacity one.
+ * \return Error code.
+ * 
+ * Time complexity: O(n(|V|+|E|))+O(F), where |V| is the number of
+ * vertices, |E| is the number of edges, and n is the number of cuts;
+ * O(F) is the time complexity of the maximum flow algorithm, see \ref
+ * igraph_maxflow().
+ * 
+ * \example examples/simple/igraph_all_st_mincuts.c
+ */
+
+int igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value,
+			  igraph_vector_ptr_t *cuts,
+			  igraph_vector_ptr_t *partition1s,
+			  igraph_integer_t source,
+			  igraph_integer_t target,
+			  const igraph_vector_t *capacity) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t flow;
+  igraph_t residual;
+  igraph_vector_t NtoL;
+  long int newsource, newtarget;
+  igraph_marked_queue_t S;
+  igraph_estack_t T;
+  igraph_i_all_st_mincuts_data_t pivot_data;
+  igraph_vector_bool_t VE1bool;
+  igraph_vector_t VE1;
+  long int VE1size=0;
+  long int i, nocuts;
+  igraph_integer_t proj_nodes;
+  igraph_vector_t revmap_ptr, revmap_next;
+  igraph_vector_ptr_t closedsets;
+  igraph_vector_ptr_t *mypartition1s=partition1s, vpartition1s;
+  igraph_maxflow_stats_t stats;
+
+  /* -------------------------------------------------------------------- */
+  /* Error checks */
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_ERROR("S-t cuts can only be listed in directed graphs",
+		 IGRAPH_UNIMPLEMENTED);
+  }
+  if (source < 0 || source >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid `source' vertex", IGRAPH_EINVAL);
+  }
+  if (target < 0 || target >= no_of_nodes) {
+    IGRAPH_ERROR("Invalid `target' vertex", IGRAPH_EINVAL);
+  }
+  if (source==target) {
+    IGRAPH_ERROR("`source' and 'target' are the same vertex", IGRAPH_EINVAL);
+  }
+  
+  if (!partition1s) {
+    mypartition1s=&vpartition1s;
+    IGRAPH_CHECK(igraph_vector_ptr_init(mypartition1s, 0));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, mypartition1s);
+  }
+
+  /* -------------------------------------------------------------------- */  
+  /* We need to calculate the maximum flow first */
+  IGRAPH_VECTOR_INIT_FINALLY(&flow, 0);
+  IGRAPH_CHECK(igraph_maxflow(graph, value, &flow, /*cut=*/ 0, 
+			      /*partition1=*/ 0, /*partition2=*/ 0, 
+			      /*source=*/ source, /*target=*/ target, 
+			      capacity, &stats));
+
+  /* -------------------------------------------------------------------- */
+  /* Then we need the reverse residual graph */
+  IGRAPH_CHECK(igraph_reverse_residual_graph(graph, capacity, &residual,
+					     &flow));
+  IGRAPH_FINALLY(igraph_destroy, &residual);
+
+  /* -------------------------------------------------------------------- */
+  /* We shrink it to its strongly connected components */
+  IGRAPH_VECTOR_INIT_FINALLY(&NtoL, 0);
+  IGRAPH_CHECK(igraph_clusters(&residual, /*membership=*/ &NtoL, 
+			       /*csize=*/ 0, /*no=*/ &proj_nodes, 
+			       IGRAPH_STRONG));
+  IGRAPH_CHECK(igraph_contract_vertices(&residual, /*mapping=*/ &NtoL, 
+					/*vertex_comb=*/ 0));
+  IGRAPH_CHECK(igraph_simplify(&residual, /*multiple=*/ 1, /*loops=*/ 1,
+			       /*edge_comb=*/ 0));
+
+  newsource=(long int) VECTOR(NtoL)[(long int)source];
+  newtarget=(long int) VECTOR(NtoL)[(long int)target];
+
+  /* TODO: handle the newsource == newtarget case */
+
+  /* -------------------------------------------------------------------- */
+  /* Determine the active vertices in the projection */
+  IGRAPH_VECTOR_INIT_FINALLY(&VE1, 0);
+  IGRAPH_CHECK(igraph_vector_bool_init(&VE1bool, proj_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &VE1bool);
+  for (i=0; i<no_of_edges; i++) {
+    if (VECTOR(flow)[i] > 0) {
+      long int from=IGRAPH_FROM(graph, i);
+      long int to=IGRAPH_TO(graph, i);
+      long int pfrom=(long int) VECTOR(NtoL)[from];
+      long int pto=(long int) VECTOR(NtoL)[to];
+      if (!VECTOR(VE1bool)[pfrom]) { 
+	VECTOR(VE1bool)[pfrom] = 1;
+	VE1size++;
+      }
+      if (!VECTOR(VE1bool)[pto]) {
+	VECTOR(VE1bool)[pto] = 1;
+	VE1size++;
+      }
+    }
+  }
+  IGRAPH_CHECK(igraph_vector_reserve(&VE1, VE1size));
+  for (i=0; i<proj_nodes; i++) {
+    if (VECTOR(VE1bool)[i]) {
+      igraph_vector_push_back(&VE1, i);
+    }
+  }
+
+  if (cuts)        { igraph_vector_ptr_clear(cuts);        }
+  if (partition1s) { igraph_vector_ptr_clear(partition1s); }    
+
+  /* -------------------------------------------------------------------- */
+  /* Everything is ready, list the cuts, using the right PIVOT
+     function  */
+  IGRAPH_CHECK(igraph_marked_queue_init(&S, no_of_nodes));
+  IGRAPH_FINALLY(igraph_marked_queue_destroy, &S);  
+  IGRAPH_CHECK(igraph_estack_init(&T, no_of_nodes, 0));
+  IGRAPH_FINALLY(igraph_estack_destroy, &T);
+
+  pivot_data.active=&VE1bool;
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&closedsets, 0));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &closedsets); /* TODO */
+  IGRAPH_CHECK(igraph_provan_shier_list(&residual, &S, &T, 
+					newsource, newtarget, &closedsets,
+					igraph_i_all_st_mincuts_pivot,
+					&pivot_data));
+
+  /* Convert the closed sets in the contracted graphs to cutsets in the
+     original graph */
+  IGRAPH_VECTOR_INIT_FINALLY(&revmap_ptr, igraph_vcount(&residual));
+  IGRAPH_VECTOR_INIT_FINALLY(&revmap_next, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    long int id=(long int) VECTOR(NtoL)[i];
+    VECTOR(revmap_next)[i]=VECTOR(revmap_ptr)[id];
+    VECTOR(revmap_ptr)[id]=i+1;
+  }
+  
+  nocuts=igraph_vector_ptr_size(&closedsets);
+  igraph_vector_ptr_clear(mypartition1s);
+  IGRAPH_CHECK(igraph_vector_ptr_reserve(mypartition1s, nocuts));
+  for (i=0; i<nocuts; i++) {
+    igraph_vector_t *supercut=VECTOR(closedsets)[i];
+    long int j, supercutsize=igraph_vector_size(supercut);
+    igraph_vector_t *cut=igraph_Calloc(1, igraph_vector_t);
+    IGRAPH_VECTOR_INIT_FINALLY(cut, 0); /* TODO: better allocation */
+    for (j=0; j<supercutsize; j++) {
+      long int vtx=(long int) VECTOR(*supercut)[j];
+      long int ovtx=(long int) VECTOR(revmap_ptr)[vtx];
+      while (ovtx != 0) {
+	ovtx--;
+	IGRAPH_CHECK(igraph_vector_push_back(cut, ovtx));
+	ovtx=(long int) VECTOR(revmap_next)[ovtx];
+      }
+    }
+    igraph_vector_ptr_push_back(mypartition1s, cut);
+    IGRAPH_FINALLY_CLEAN(1);
+    
+    igraph_vector_destroy(supercut);
+    igraph_free(supercut);
+    VECTOR(closedsets)[i] = 0;
+  }    
+
+  igraph_vector_destroy(&revmap_next);
+  igraph_vector_destroy(&revmap_ptr);
+  igraph_vector_ptr_destroy(&closedsets);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (cuts) {
+    igraph_vector_long_t memb;
+    IGRAPH_CHECK(igraph_vector_long_init(&memb, no_of_nodes));
+    IGRAPH_FINALLY(igraph_vector_long_destroy, &memb);
+    IGRAPH_CHECK(igraph_vector_ptr_resize(cuts, nocuts));
+    for (i=0; i<nocuts; i++) {
+      igraph_vector_t *part=VECTOR(*mypartition1s)[i];
+      long int j, n=igraph_vector_size(part);
+      igraph_vector_t *v;
+      v=igraph_Calloc(1, igraph_vector_t);
+      if (!v) { 
+	IGRAPH_ERROR("Cannot list minimum s-t cuts", IGRAPH_ENOMEM);
+      }
+      IGRAPH_VECTOR_INIT_FINALLY(v, 0);
+      for (j=0; j<n; j++) {
+	long int vtx=(long int) VECTOR(*part)[j];
+	VECTOR(memb)[vtx]=i+1;
+      }
+      for (j=0; j<no_of_edges; j++) {
+	long int from=IGRAPH_FROM(graph, j);
+	long int to=IGRAPH_TO(graph, j);
+	if (VECTOR(memb)[from] == i+1 && VECTOR(memb)[to] != i+1) {
+	  IGRAPH_CHECK(igraph_vector_push_back(v, j)); /* TODO: allocation */
+	}
+      }
+      VECTOR(*cuts)[i] = v;
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    igraph_vector_long_destroy(&memb);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  igraph_estack_destroy(&T);
+  igraph_marked_queue_destroy(&S);
+  igraph_vector_bool_destroy(&VE1bool);
+  igraph_vector_destroy(&VE1);
+  igraph_vector_destroy(&NtoL);
+  igraph_destroy(&residual);
+  igraph_vector_destroy(&flow);
+  IGRAPH_FINALLY_CLEAN(7);
+
+  if (!partition1s) {
+    for (i=0; i<nocuts; i++) {
+      igraph_vector_t *cut=VECTOR(*mypartition1s)[i];
+      igraph_vector_destroy(cut);
+      igraph_free(cut);
+      VECTOR(*mypartition1s)[i]=0;
+    }
+    igraph_vector_ptr_destroy(mypartition1s);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
diff --git a/src/stack.pmt b/src/stack.pmt
new file mode 100644
index 0000000..e8b8eaa
--- /dev/null
+++ b/src/stack.pmt
@@ -0,0 +1,291 @@
+/* -*- 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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_init
+ * \brief Initializes a stack.
+ * 
+ * The initialized stack is always empty.
+ * \param s Pointer to an uninitialized stack.
+ * \param size The number of elements to allocate memory for.
+ * \return Error code.
+ * 
+ * Time complexity: O(\p size).
+ */
+
+int FUNCTION(igraph_stack,init)       (TYPE(igraph_stack)* s, long int size) {
+        long int alloc_size= size > 0 ? size : 1;
+	assert (s != NULL);
+	if (size < 0) { size=0; }
+	s->stor_begin=igraph_Calloc(alloc_size, BASE);
+	if (s->stor_begin==0) {
+	  IGRAPH_ERROR("stack init failed", IGRAPH_ENOMEM);
+	}
+	s->stor_end=s->stor_begin + alloc_size;
+	s->end=s->stor_begin;
+	
+	return 0;
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_destroy
+ * \brief Destroys a stack object.
+ * 
+ * Deallocate the memory used for a stack.
+ * It is possible to reinitialize a destroyed stack again by 
+ * \ref igraph_stack_init().
+ * \param s The stack to destroy.
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_stack,destroy)    (TYPE(igraph_stack)* s) {
+  assert( s != NULL);
+  if (s->stor_begin != 0) {
+    igraph_Free(s->stor_begin);
+    s->stor_begin=NULL;
+  }
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_reserve
+ * \brief Reserve memory.
+ *
+ * Reverse memory for future use. The actual size of the stack is
+ * unchanged.
+ * \param s The stack object.
+ * \param size The number of elements to reserve memory for. If it is
+ *     not bigger than the current size then nothing happens.
+ * \return Error code.
+ * 
+ * Time complexity: should be around O(n), the new allocated size of
+ * the stack.
+ */
+
+int FUNCTION(igraph_stack,reserve)    (TYPE(igraph_stack)* s, long int size) {
+  long int actual_size=FUNCTION(igraph_stack,size)(s);
+  BASE *tmp;
+  assert(s != NULL);
+  assert(s->stor_begin != NULL);
+  
+  if (size <= actual_size) { return 0; }
+  
+  tmp=igraph_Realloc(s->stor_begin, (size_t) size, BASE);
+  if (tmp==0) {
+    IGRAPH_ERROR("stack reserve failed", IGRAPH_ENOMEM);
+  }
+  s->stor_begin=tmp; 
+  s->stor_end=s->stor_begin + size;
+  s->end=s->stor_begin+actual_size;
+  
+  return 0;
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_empty
+ * \brief Decides whether a stack object is empty.
+ * 
+ * \param s The stack object.
+ * \return Boolean, \c TRUE if the stack is empty, \c FALSE
+ * otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t FUNCTION(igraph_stack,empty)      (TYPE(igraph_stack)* s) {
+	assert (s != NULL);
+	assert (s->stor_begin != NULL);
+	assert (s->end != NULL);
+	return s->stor_begin == s->end;
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_size
+ * \brief Returns the number of elements in a stack.
+ * 
+ * \param s The stack object.
+ * \return The number of elements in the stack.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_stack,size)       (const TYPE(igraph_stack)* s) {
+	assert (s != NULL);
+	assert (s->stor_begin != NULL);
+	return s->end - s->stor_begin;
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_clear
+ * \brief Removes all elements from a stack.
+ * 
+ * \param s The stack object.
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_stack,clear)      (TYPE(igraph_stack)* s) {
+	assert (s != NULL);
+	assert (s->stor_begin != NULL);
+	s->end = s->stor_begin;
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_push
+ * \brief Places an element on the top of a stack.
+ *
+ * The capacity of the stack is increased, if needed.
+ * \param s The stack object.
+ * \param elem The element to push.
+ * \return Error code.
+ * 
+ * Time complexity: O(1) is no reallocation is needed, O(n)
+ * otherwise, but it is ensured that n push operations are performed
+ * in O(n) time.
+ */
+
+int FUNCTION(igraph_stack,push)(TYPE(igraph_stack)* s, BASE elem) {
+	assert (s != NULL);
+	assert (s->stor_begin != NULL);
+	if (s->end == s->stor_end) {
+		/* full, allocate more storage */
+		
+	        BASE *bigger=NULL, *old=s->stor_begin;
+		
+		bigger = igraph_Calloc(2*FUNCTION(igraph_stack,size)(s)+1, BASE);
+		if (bigger==0) {
+		  IGRAPH_ERROR("stack push failed", IGRAPH_ENOMEM);
+		}
+		memcpy(bigger, s->stor_begin, 
+		       (size_t) FUNCTION(igraph_stack,size)(s)*sizeof(BASE));
+
+		s->end        = bigger + (s->stor_end - s->stor_begin);
+		s->stor_end   = bigger + 2*(s->stor_end - s->stor_begin)+1;
+		s->stor_begin = bigger;
+		
+		*(s->end) = elem;
+		(s->end) += 1;
+
+		igraph_Free(old);
+	} else {
+		*(s->end) = elem;
+		(s->end) += 1;
+	}
+	return 0;
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_pop
+ * \brief Removes and returns an element from the top of a stack.
+ * 
+ * The stack must contain at least one element, call \ref
+ * igraph_stack_empty() to make sure of this.
+ * \param s The stack object.
+ * \return The removed top element.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_stack,pop)        (TYPE(igraph_stack)* s) {
+
+	assert (s != NULL);
+	assert (s->stor_begin != NULL);
+	assert (s->end != NULL);
+	assert (s->end != s->stor_begin);
+		
+	(s->end)--;
+	
+	return *(s->end);
+}
+
+/**
+ * \ingroup stack
+ * \function igraph_stack_top
+ * \brief Query top element.
+ * 
+ * Returns the top element of the stack, without removing it. 
+ * The stack must be non-empty.
+ * \param s The stack.
+ * \return The top element.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_stack,top)        (const TYPE(igraph_stack)* s) {
+
+	assert (s != NULL);
+	assert (s->stor_begin != NULL);
+	assert (s->end != NULL);
+	assert (s->end != s->stor_begin);
+
+	return *(s->end-1);
+}
+
+#if defined (OUT_FORMAT)
+#ifndef USING_R
+
+int FUNCTION(igraph_stack,print)(const TYPE(igraph_stack) *s) {
+  long int i, n=FUNCTION(igraph_stack,size)(s);
+  if (n!=0) {
+    printf(OUT_FORMAT, s->stor_begin[0]);
+  }
+  for (i=1; i<n; i++) {
+    printf(" " OUT_FORMAT, s->stor_begin[i]);
+  }
+  printf("\n");
+  return 0;
+}
+#endif
+
+int FUNCTION(igraph_stack,fprint)(const TYPE(igraph_stack) *s, FILE *file) {
+  long int i, n=FUNCTION(igraph_stack,size)(s);
+  if (n!=0) {
+    fprintf(file, OUT_FORMAT, s->stor_begin[0]);
+  }
+  for (i=1; i<n; i++) {
+    fprintf(file, " " OUT_FORMAT, s->stor_begin[i]);
+  }
+  fprintf(file, "\n");
+  return 0;
+}
+
+#endif
+
diff --git a/src/statusbar.c b/src/statusbar.c
new file mode 100644
index 0000000..9f40e0f
--- /dev/null
+++ b/src/statusbar.c
@@ -0,0 +1,130 @@
+/* -*- 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 "config.h"
+#include "igraph_types.h"
+#include "igraph_statusbar.h"
+#include "igraph_error.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+static IGRAPH_THREAD_LOCAL igraph_status_handler_t *igraph_i_status_handler=0;
+
+/** 
+ * \function igraph_status
+ * Report status from an igraph function.
+ * 
+ * It calls the installed status handler function, if there is 
+ * one. Otherwise it does nothing. Note that the standard way to 
+ * report the status from an igraph function is the 
+ * \ref IGRAPH_STATUS or \ref IGRAPH_STATUSF macro, as these 
+ * take care of the termination of the calling function if the 
+ * status handler returns with \c IGRAPH_INTERRUPTED.
+ * \param message The status message.
+ * \param data Additional context, with user-defined semantics.
+ *        Existing igraph functions pass a null pointer here.
+ * \return Error code. If a status handler function was called 
+ *        and it did not return with \c IGRAPH_SUCCESS, then 
+ *        \c IGRAPH_INTERRUPTED is returned by \c igraph_status().
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_status(const char *message, void *data) {
+  if (igraph_i_status_handler) {
+    if (igraph_i_status_handler(message, data) != IGRAPH_SUCCESS) { 
+      return IGRAPH_INTERRUPTED;
+    }
+  }
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_statusf
+ * Report status, more flexible printf-like version.
+ *
+ * This is the more flexible version of \ref igraph_status(), 
+ * that has a syntax similar to the \c printf standard C library function.
+ * It substitutes the values of the additional arguments into the 
+ * \p message template string and calls \ref igraph_status().
+ * \param message Status message template string, the syntax is the same 
+ *        as for the \c printf function.
+ * \param data Additional context, with user-defined semantics. 
+ *        Existing igraph functions pass a null pointer here.
+ * \param ... The additional arguments to fill the template given in the 
+ *        \p message argument.
+ * \return Error code. If a status handler function was called 
+ *        and it did not return with \c IGRAPH_SUCCESS, then 
+ *        \c IGRAPH_INTERRUPTED is returned by \c igraph_status().
+ */
+
+int igraph_statusf(const char *message, void *data, ...) {
+  char buffer[300];
+  va_list ap;
+  va_start(ap, data);
+  vsnprintf(buffer, sizeof(buffer)-1, message, ap);
+  return igraph_status(buffer, data);
+}
+
+#ifndef USING_R
+
+/**
+ * \function igraph_status_handler_stderr
+ * A simple predefined status handler function.
+ * 
+ * A simple status handler function, that writes the status 
+ * message to the standard errror.
+ * \param message The status message.
+ * \param data Additional context, with user-defined semantics.
+ *        Existing igraph functions pass a null pointer here.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ */
+
+int igraph_status_handler_stderr(const char *message, void *data) {
+  IGRAPH_UNUSED(data);
+  fputs(message, stderr);
+  return 0;
+}
+#endif
+
+/**
+ * \function igraph_set_status_handler
+ * Install of uninstall a status handler function.
+ *
+ * To uninstall the currently installed status handler, call
+ * this function with a null pointer.
+ * \param new_handler The status handler function to install.
+ * \return The previously installed status handler function.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_status_handler_t *
+igraph_set_status_handler(igraph_status_handler_t new_handler) {
+  igraph_status_handler_t *previous_handler=igraph_i_status_handler;
+  igraph_i_status_handler = new_handler;
+  return previous_handler;
+}
+
diff --git a/src/structural_properties.c b/src/structural_properties.c
new file mode 100644
index 0000000..61a264f
--- /dev/null
+++ b/src/structural_properties.c
@@ -0,0 +1,6771 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_structural.h"
+#include "igraph_transitivity.h"
+#include "igraph_paths.h"
+#include "igraph_math.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_progress.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_centrality.h"
+#include "igraph_components.h"
+#include "igraph_constructors.h"
+#include "igraph_conversion.h"
+#include "igraph_types_internal.h"
+#include "igraph_dqueue.h"
+#include "igraph_attributes.h"
+#include "igraph_neighborhood.h"
+#include "igraph_topology.h"
+#include "igraph_qsort.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+
+/** 
+ * \section about_structural
+ *
+ * <para>These functions usually calculate some structural property
+ * of a graph, like its diameter, the degree of the nodes, etc.</para>
+ */
+
+/**
+ * \ingroup structural
+ * \function igraph_diameter
+ * \brief Calculates the diameter of a graph (longest geodesic).
+ *
+ * \param graph The graph object.
+ * \param pres Pointer to an integer, if not \c NULL then it will contain 
+ *        the diameter (the actual distance).
+ * \param pfrom Pointer to an integer, if not \c NULL it will be set to the 
+ *        source vertex of the diameter path.
+ * \param pto Pointer to an integer, if not \c NULL it will be set to the 
+ *        target vertex of the diameter path.
+ * \param path Pointer to an initialized vector. If not \c NULL the actual 
+ *        longest geodesic path will be stored here. The vector will be 
+ *        resized as needed.
+ * \param directed Boolean, whether to consider directed
+ *        paths. Ignored for undirected graphs.
+ * \param unconn What to do if the graph is not connected. If
+ *        \c TRUE the longest geodesic within a component
+ *        will be returned, otherwise the number of vertices is
+ *        returned. (The rationale behind the latter is that this is
+ *        always longer than the longest possible diameter in a
+ *        graph.) 
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data.  
+ *
+ * Time complexity: O(|V||E|), the
+ * number of vertices times the number of edges.
+ * 
+ * \example examples/simple/igraph_diameter.c
+ */
+
+int igraph_diameter(const igraph_t *graph, igraph_integer_t *pres, 
+		    igraph_integer_t *pfrom, igraph_integer_t *pto, 
+		    igraph_vector_t *path,
+		    igraph_bool_t directed, igraph_bool_t unconn) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, j, n;
+  long int *already_added;
+  long int nodes_reached;
+  long int from=0, to=0;
+  long int res=0;
+
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  igraph_vector_int_t *neis;
+  igraph_neimode_t dirmode;
+  igraph_adjlist_t allneis;
+  
+  if (directed) { dirmode=IGRAPH_OUT; } else { dirmode=IGRAPH_ALL; }
+  already_added=igraph_Calloc(no_of_nodes, long int);
+  if (already_added==0) {
+    IGRAPH_ERROR("diameter failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, already_added);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, dirmode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+  
+  for (i=0; i<no_of_nodes; i++) {
+    nodes_reached=1;
+    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
+    IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+    already_added[i]=i+1;
+
+    IGRAPH_PROGRESS("Diameter: ", 100.0*i/no_of_nodes, NULL);
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      if (actdist>res) { 
+        res=actdist; 
+        from=i;
+        to=actnode;
+      }
+      
+      neis=igraph_adjlist_get(&allneis, actnode);
+      n=igraph_vector_int_size(neis);
+      for (j=0; j<n; j++) {
+	long int neighbor=(long int) VECTOR(*neis)[j];
+	if (already_added[neighbor] == i+1) { continue; }
+	already_added[neighbor]=i+1;
+	nodes_reached++;
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+      }
+    } /* while !igraph_dqueue_empty */
+    
+    /* not connected, return largest possible */
+    if (nodes_reached != no_of_nodes && !unconn) {
+      res=no_of_nodes;
+      from=-1;
+      to=-1;
+      break;
+    }
+  } /* for i<no_of_nodes */
+
+  IGRAPH_PROGRESS("Diameter: ", 100.0, NULL);
+  
+  /* return the requested info */
+  if (pres != 0) {
+    *pres=(igraph_integer_t) res;
+  }
+  if (pfrom != 0) {
+    *pfrom=(igraph_integer_t) from;
+  }
+  if (pto != 0) {
+    *pto=(igraph_integer_t) to;
+  }
+  if (path != 0) {
+    if (res==no_of_nodes) {
+      igraph_vector_clear(path);
+    } else {
+      igraph_vector_ptr_t tmpptr;
+      igraph_vector_ptr_init(&tmpptr, 1);
+      IGRAPH_FINALLY(igraph_vector_ptr_destroy, &tmpptr);
+      VECTOR(tmpptr)[0]=path;
+      IGRAPH_CHECK(igraph_get_shortest_paths(graph, &tmpptr, 0,
+					     (igraph_integer_t) from, 
+					     igraph_vss_1((igraph_integer_t)to),
+					     dirmode, 0, 0));
+      igraph_vector_ptr_destroy(&tmpptr);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+  
+  /* clean */
+  igraph_Free(already_added);
+  igraph_dqueue_destroy(&q);
+  igraph_adjlist_destroy(&allneis);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_average_path_length
+ * \brief Calculates the average geodesic length in a graph.
+ *
+ * \param graph The graph object.
+ * \param res Pointer to a real number, this will contain the result.
+ * \param directed Boolean, whether to consider directed
+ *        paths. Ignored for undirected graphs.
+ * \param unconn What to do if the graph is not connected. If
+ *        \c TRUE the average of the geodesics
+ *        within the components 
+ *        will be returned, otherwise the number of vertices is
+ *        used for the length of non-existing geodesics. (The rationale
+ *        behind this is that this is always longer than the longest
+ *        possible geodesic in a graph.) 
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         data structures 
+ *
+ * Time complexity: O(|V||E|), the
+ * number of vertices times the number of edges.
+ * 
+ * \example examples/simple/igraph_average_path_length.c
+ */
+
+int igraph_average_path_length(const igraph_t *graph, igraph_real_t *res,
+			       igraph_bool_t directed, igraph_bool_t unconn) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, j, n;
+  long int *already_added;
+  long int nodes_reached=0;
+  igraph_real_t normfact=0.0;
+
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  igraph_vector_int_t *neis;
+  igraph_neimode_t dirmode;
+  igraph_adjlist_t allneis;
+
+  *res=0;  
+  if (directed) { dirmode=IGRAPH_OUT; } else { dirmode=IGRAPH_ALL; }
+  already_added=igraph_Calloc(no_of_nodes, long int);
+  if (already_added==0) {
+    IGRAPH_ERROR("average path length failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, already_added); /* TODO: hack */
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+
+  igraph_adjlist_init(graph, &allneis, dirmode);
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+
+  for (i=0; i<no_of_nodes; i++) {
+    nodes_reached=0;
+    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
+    IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+    already_added[i]=i+1;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+    
+      neis=igraph_adjlist_get(&allneis, actnode);
+      n=igraph_vector_int_size(neis);
+      for (j=0; j<n; j++) {
+	long int neighbor=(long int) VECTOR(*neis)[j];
+	if (already_added[neighbor] == i+1) { continue; }
+	already_added[neighbor]=i+1;
+	nodes_reached++;
+	*res += actdist+1;
+	normfact+=1;
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+      }
+    } /* while !igraph_dqueue_empty */
+    
+    /* not connected, return largest possible */
+    if (!unconn) {
+      *res += (no_of_nodes * (no_of_nodes-1-nodes_reached));
+      normfact += no_of_nodes-1-nodes_reached;
+    }    
+  } /* for i<no_of_nodes */
+
+  *res /= normfact;
+
+  /* clean */
+  igraph_Free(already_added);
+  igraph_dqueue_destroy(&q);
+  igraph_adjlist_destroy(&allneis);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \function igraph_path_length_hist
+ * Create a histogram of all shortest path lengths.
+ * 
+ * This function calculates a histogram, by calculating the
+ * shortest path length between each pair of vertices. For directed
+ * graphs both directions might be considered and then every pair of vertices
+ * appears twice in the histogram.
+ * \param graph The input graph.
+ * \param res Pointer to an initialized vector, the result is stored
+ *     here. The first (i.e. zeroth) element contains the number of
+ *     shortest paths of length 1, etc. The supplied vector is resized
+ *     as needed.
+ * \param unconnected Pointer to a real number, the number of
+ *     pairs for which the second vertex is not reachable from the
+ *     first is stored here.
+ * \param directed Whether to consider directed paths in a directed
+ *     graph (if not zero). This argument is ignored for undirected
+ *     graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V||E|), the number of vertices times the number
+ * of edges.
+ * 
+ * \sa \ref igraph_average_path_length() and \ref igraph_shortest_paths()
+ */
+
+int igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res,
+			    igraph_real_t *unconnected, igraph_bool_t directed) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i,j,n;
+  igraph_vector_long_t already_added;
+  long int nodes_reached;
+  
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  igraph_vector_int_t *neis;
+  igraph_neimode_t dirmode;
+  igraph_adjlist_t allneis;
+  igraph_real_t unconn = 0;
+  long int ressize;
+  
+  if (directed) { dirmode=IGRAPH_OUT; } else { dirmode=IGRAPH_ALL; }
+
+  IGRAPH_CHECK(igraph_vector_long_init(&already_added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &already_added);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, dirmode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, 0));
+  ressize=0;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    nodes_reached=1;		/* itself */
+    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
+    IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+    VECTOR(already_added)[i]=i+1;
+    
+    IGRAPH_PROGRESS("Path-hist: ", 100.0*i/no_of_nodes, NULL);
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      
+      neis=igraph_adjlist_get(&allneis, actnode);
+      n=igraph_vector_int_size(neis);
+      for (j=0; j<n; j++) {
+	long int neighbor=(long int) VECTOR(*neis)[j];
+	if (VECTOR(already_added)[neighbor] == i+1) { continue; }
+	VECTOR(already_added)[neighbor] = i+1;
+	nodes_reached++;
+	if (actdist+1 > ressize) {
+	  IGRAPH_CHECK(igraph_vector_resize(res, actdist+1));
+	  for (; ressize<actdist+1; ressize++) {
+	    VECTOR(*res)[ressize]=0;
+	  }
+	}
+	VECTOR(*res)[actdist] += 1;
+
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+      }
+    } /* while !igraph_dqueue_empty */
+
+    unconn += (no_of_nodes-nodes_reached);
+
+  } /* for i<no_of_nodes */
+
+  IGRAPH_PROGRESS("Path-hist: ", 100.0, NULL);
+
+  /* count every pair only once for an undirected graph */
+  if (!directed || !igraph_is_directed(graph)) {
+    for (i=0; i<ressize; i++) {
+      VECTOR(*res)[i] /= 2;
+    }
+    unconn /= 2;
+  }
+
+  igraph_vector_long_destroy(&already_added);
+  igraph_dqueue_destroy(&q);
+  igraph_adjlist_destroy(&allneis);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (unconnected)
+	*unconnected = unconn;
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_shortest_paths
+ * \brief The length of the shortest paths between vertices.
+ *
+ * \param graph The graph object.
+ * \param res The result of the calculation, a matrix. A pointer to an
+ *        initialized matrix, to be more precise. The matrix will be
+ *        resized if needed. It will have the same
+ *        number of rows as the length of the \c from
+ *        argument, and its number of columns is the number of
+ *        vertices in the \c to argument. One row of the matrix shows the
+ *        distances from/to a given vertex to the ones in \c to.
+ *        For the unreachable vertices IGRAPH_INFINITY is returned.
+ * \param from Vector of the vertex ids for which the path length
+ *        calculations are done.
+ * \param to Vector of the vertex ids to which the path length 
+ *        calculations are done. It is not allowed to have duplicated
+ *        vertex ids here.
+ * \param mode The type of shortest paths to be used for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the lengths of the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the lengths of the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL 
+ *          the directed graph is considered as an undirected one for
+ *          the computation. 
+ *        \endclist
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM 
+ *           not enough memory for temporary
+ *           data.
+ *        \cli IGRAPH_EINVVID
+ *           invalid vertex id passed.
+ *        \cli IGRAPH_EINVMODE 
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(n(|V|+|E|)),
+ * n is the 
+ * number of vertices to calculate, |V| and
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ *
+ * \sa \ref igraph_get_shortest_paths() to get the paths themselves, 
+ * \ref igraph_shortest_paths_dijkstra() for the weighted version.
+ */
+
+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) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_from, no_of_to;
+  long int *already_counted;
+  igraph_adjlist_t adjlist;
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  igraph_vector_int_t *neis;
+  igraph_bool_t all_to;
+
+  long int i, j;
+  igraph_vit_t fromvit, tovit;
+  igraph_real_t my_infinity=IGRAPH_INFINITY;
+  igraph_vector_t indexv;
+
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
+  no_of_from=IGRAPH_VIT_SIZE(fromvit);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, mode));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+  already_counted=igraph_Calloc(no_of_nodes, long int);
+  if (already_counted==0) {
+    IGRAPH_ERROR("shortest paths failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, already_counted);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+
+  if ( (all_to=igraph_vs_is_all(&to)) ) {
+    no_of_to=no_of_nodes;
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&indexv, no_of_nodes);
+    IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
+    no_of_to=IGRAPH_VIT_SIZE(tovit);
+    for (i=0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) {
+      long int v=IGRAPH_VIT_GET(tovit);
+      if (VECTOR(indexv)[v]) {
+	IGRAPH_ERROR("Duplicate vertices in `to', this is not allowed", 
+		     IGRAPH_EINVAL);
+      }
+      VECTOR(indexv)[v] = ++i;
+    }
+  }
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
+  igraph_matrix_fill(res, my_infinity);
+
+  for (IGRAPH_VIT_RESET(fromvit), i=0; 
+       !IGRAPH_VIT_END(fromvit); 
+       IGRAPH_VIT_NEXT(fromvit), i++) {
+    long int reached=0;
+    IGRAPH_CHECK(igraph_dqueue_push(&q, IGRAPH_VIT_GET(fromvit)));
+    IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+    already_counted[ (long int) IGRAPH_VIT_GET(fromvit) ] = i+1;
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    while (!igraph_dqueue_empty(&q)) {
+      long int act=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+
+      if (all_to) {
+	MATRIX(*res, i, act)=actdist;
+      } else {
+	if (VECTOR(indexv)[act]) {
+	  MATRIX(*res, i, (long int)(VECTOR(indexv)[act]-1)) = actdist;
+	  reached++;
+	  if (reached==no_of_to) {
+	    igraph_dqueue_clear(&q);
+	    break;
+	  }
+	}
+      }
+      
+      neis = igraph_adjlist_get(&adjlist, act);
+      for (j=0; j<igraph_vector_int_size(neis); j++) {
+        long int neighbor=(long int) VECTOR(*neis)[j];
+        if (already_counted[neighbor] == i+1) { continue; }
+        already_counted[neighbor] = i+1;
+        IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+        IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+      }
+    }
+  }
+
+  /* Clean */
+  if (!all_to) {
+    igraph_vit_destroy(&tovit);
+    igraph_vector_destroy(&indexv);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+
+  igraph_Free(already_counted);
+  igraph_dqueue_destroy(&q);
+  igraph_vit_destroy(&fromvit);
+  igraph_adjlist_destroy(&adjlist);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_get_shortest_paths
+ * \brief Calculates the shortest paths from/to one vertex.
+ * 
+ * </para><para>
+ * If there is more than one geodesic between two vertices, this
+ * function gives only one of them. 
+ * \param graph The graph object.
+ * \param vertices The result, the ids of the vertices along the paths. 
+ *        This is a pointer vector, each element points to a vector
+ *        object. These should be initialized before passing them to
+ *        the function, which will properly clear and/or resize them
+ *        and fill the ids of the vertices along the geodesics from/to
+ *        the vertices. Supply a null pointer here if you don't need
+ *        these vectors.
+ * \param edges The result, the ids of the edges along the paths.
+ *        This is a pointer vector, each element points to a vector
+ *        object. These should be initialized before passing them to
+ *        the function, which will properly clear and/or resize them
+ *        and fill the ids of the vertices along the geodesics from/to
+ *        the vertices. Supply a null pointer here if you don't need
+ *        these vectors.
+ * \param from The id of the vertex from/to which the geodesics are
+ *        calculated. 
+ * \param to Vertex sequence with the ids of the vertices to/from which the 
+ *        shortest paths will be calculated. A vertex might be given multiple
+ *        times.
+ * \param mode The type of shortest paths to be used for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL 
+ *          the directed graph is considered as an
+ *          undirected one for the computation.
+ *        \endclist
+ * \param predecessors A pointer to an initialized igraph vector or null.
+ *        If not null, a vector containing the predecessor of each vertex in
+ *        the single source shortest path tree is returned here. The
+ *        predecessor of vertex i in the tree is the vertex from which vertex i
+ *        was reached. The predecessor of the start vertex (in the \c from
+ *        argument) is itself by definition. If the predecessor is -1, 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
+ *        \c to are reached.
+ * \param inbound_edges A pointer to an initialized igraph vector or null.
+ *        If not null, a vector containing the inbound edge of each vertex in
+ *        the single source shortest path tree is returned here. The
+ *        inbound edge of vertex i in the tree is the edge via which vertex i
+ *        was reached. The start vertex and vertices that were not reached
+ *        during the search will have -1 in the corresponding entry of the
+ *        vector. Note that the search terminates if all the vertices in
+ *        \c to are reached.
+ *
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM 
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           \p from is invalid vertex id, or the length of \p to is 
+ *           not the same as the length of \p res.
+ *        \cli IGRAPH_EINVMODE 
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| is the number of vertices,
+ * |E| the number of edges in the
+ * graph.  
+ *
+ * \sa \ref igraph_shortest_paths() if you only need the path length but
+ * not the paths themselves.
+ * 
+ * \example examples/simple/igraph_get_shortest_paths.c
+ */
+ 
+
+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) {
+
+  /* TODO: use inclist_t if to is long (longer than 1?) */
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int *father;
+  
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+
+  long int i, j;
+  igraph_vector_t tmp=IGRAPH_VECTOR_NULL;
+
+  igraph_vit_t vit;
+  
+  long int to_reach;
+  long int reached=0;
+
+  if (from<0 || from>=no_of_nodes) {
+    IGRAPH_ERROR("cannot get shortest paths", IGRAPH_EINVVID);
+  }
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  if (vertices && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(vertices)) {
+    IGRAPH_ERROR("Size of the `vertices' and the `to' should match", IGRAPH_EINVAL);
+  }
+  if (edges && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(edges)) {
+    IGRAPH_ERROR("Size of the `edges' and the `to' should match", IGRAPH_EINVAL);
+  }
+
+  father=igraph_Calloc(no_of_nodes, long int);
+  if (father==0) {
+    IGRAPH_ERROR("cannot get shortest paths", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, father);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+
+  /* Mark the vertices we need to reach */
+  to_reach=IGRAPH_VIT_SIZE(vit);
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    if (father[ (long int) IGRAPH_VIT_GET(vit) ] == 0) {
+      father[ (long int) IGRAPH_VIT_GET(vit) ] = -1;
+    } else {
+      to_reach--;		/* this node was given multiple times */
+    }
+  }
+
+  /* Meaning of father[i]:
+   *
+   * - If father[i] < 0, it means that vertex i has to be reached and has not
+   *   been reached yet.
+   *
+   * - If father[i] = 0, it means that vertex i does not have to be reached and
+   *   it has not been reached yet.
+   *
+   * - If father[i] = 1, it means that vertex i is the start vertex.
+   *
+   * - Otherwise, father[i] is the ID of the edge from which vertex i was
+   *   reached plus 2.
+   */
+
+  IGRAPH_CHECK(igraph_dqueue_push(&q, from+1));
+  if (father[ (long int) from ] < 0) { reached++; }
+  father[ (long int)from ] = 1;
+  
+  while (!igraph_dqueue_empty(&q) && reached < to_reach) {
+    long int act=(long int) igraph_dqueue_pop(&q)-1;
+    
+    IGRAPH_CHECK(igraph_incident(graph, &tmp, (igraph_integer_t) act, mode));
+    for (j=0; j<igraph_vector_size(&tmp); j++) {
+      long int edge=(long int) VECTOR(tmp)[j];
+      long int neighbor=IGRAPH_OTHER(graph, edge, act);
+      if (father[neighbor] > 0) { 
+	continue; 
+      } else if (father[neighbor] < 0) { 
+	reached++; 
+      }
+      father[neighbor] = edge+2;
+      IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor+1));
+    }
+  }
+
+  if (reached < to_reach) {
+    IGRAPH_WARNING("Couldn't reach some vertices");
+  }
+
+  /* Create `predecessors' if needed */
+  if (predecessors) {
+    IGRAPH_CHECK(igraph_vector_long_resize(predecessors, no_of_nodes));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      if (father[i] <= 0) {
+        /* i was not reached */
+        VECTOR(*predecessors)[i] = -1;
+      } else if (father[i] == 1) {
+        /* i is the start vertex */
+        VECTOR(*predecessors)[i] = i;
+      } else {
+        /* i was reached via the edge with ID = father[i] - 2 */
+        VECTOR(*predecessors)[i] = IGRAPH_OTHER(graph, father[i]-2, i);
+      }
+    }
+  }
+  
+  /* Create `inbound_edges' if needed */
+  if (inbound_edges) {
+    IGRAPH_CHECK(igraph_vector_long_resize(inbound_edges, no_of_nodes));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      if (father[i] <= 1) {
+        /* i was not reached or i is the start vertex */
+        VECTOR(*inbound_edges)[i] = -1;
+      } else {
+        /* i was reached via the edge with ID = father[i] - 2 */
+        VECTOR(*inbound_edges)[i] = father[i]-2;
+      }
+    }
+  }
+  
+  /* Create `vertices' and `edges' if needed */
+  if (vertices || edges) {
+    for (IGRAPH_VIT_RESET(vit), j=0; 
+	 !IGRAPH_VIT_END(vit);
+	 IGRAPH_VIT_NEXT(vit), j++) {
+      long int node=IGRAPH_VIT_GET(vit);
+      igraph_vector_t *vvec=0, *evec=0;
+      if (vertices) {
+	vvec=VECTOR(*vertices)[j];
+	igraph_vector_clear(vvec);
+      }
+      if (edges) {
+	evec=VECTOR(*edges)[j];
+	igraph_vector_clear(evec);
+      }
+      
+      IGRAPH_ALLOW_INTERRUPTION();
+      
+      if (father[node]>0) {
+	long int act=node;
+	long int size=0;
+	long int edge;
+	while (father[act]>1) {
+	  size++;
+	  edge=father[act]-2;
+	  act=IGRAPH_OTHER(graph, edge, act);
+	}
+	if (vvec) {
+	  IGRAPH_CHECK(igraph_vector_resize(vvec, size+1));
+	  VECTOR(*vvec)[size]=node;
+	}
+	if (evec) {
+	  IGRAPH_CHECK(igraph_vector_resize(evec, size));
+	}
+	act=node;
+	while (father[act]>1) {
+	  size--;
+	  edge=father[act]-2;
+	  act=IGRAPH_OTHER(graph, edge, act);
+	  if (vvec) { VECTOR(*vvec)[size]=act; }
+	  if (evec) { VECTOR(*evec)[size]=edge; }
+	}
+      }
+    }
+  }
+  
+  /* Clean */
+  igraph_Free(father);
+  igraph_dqueue_destroy(&q);
+  igraph_vector_destroy(&tmp);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/** 
+ * \function igraph_get_shortest_path
+ * Shortest path from one vertex to another one.
+ * 
+ * Calculates and returns a single unweighted shortest path from a
+ * given vertex to another one. If there are more than one shortest
+ * paths between the two vertices, then an arbitrary one is returned.
+ * 
+ * </para><para>This function is a wrapper to \ref
+ * igraph_get_shortest_paths(), for the special case when only one
+ * target vertex is considered.
+ * \param graph The input graph, it can be directed or
+ *        undirected. Directed paths are considered in directed
+ *        graphs.
+ * \param vertices Pointer to an initialized vector or a null
+ *        pointer. If not a null pointer, then the vertex ids along
+ *        the path are stored here, including the source and target
+ *        vertices. 
+ * \param edges Pointer to an uninitialized vector or a null
+ *        pointer. If not a null pointer, then the edge ids along the
+ *        path are stored here.
+ * \param from The id of the source vertex.
+ * \param to The id of the target vertex.
+ * \param mode A constant specifying how edge directions are
+ *        considered in directed graphs. Valid modes are:
+ *        \c IGRAPH_OUT, follows edge directions;
+ *        \c IGRAPH_IN, follows the opposite directions; and
+ *        \c IGRAPH_ALL, ignores edge directions. This argument is
+ *        ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges in the graph.
+ * 
+ * \sa \ref igraph_get_shortest_paths() for the version with more target
+ * vertices.
+ */
+
+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) {
+
+  igraph_vector_ptr_t vertices2, *vp=&vertices2;
+  igraph_vector_ptr_t edges2, *ep=&edges2;
+  
+  if (vertices) { 
+    IGRAPH_CHECK(igraph_vector_ptr_init(&vertices2, 1));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vertices2);
+    VECTOR(vertices2)[0]=vertices;
+  } else {
+    vp=0;
+  }
+  if (edges) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&edges2, 1));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &edges2);
+    VECTOR(edges2)[0]=edges;
+  } else {
+    ep=0;
+  }
+
+  IGRAPH_CHECK(igraph_get_shortest_paths(graph, vp, ep, from, 
+					 igraph_vss_1(to), mode, 0, 0));
+
+  if (edges) {
+    igraph_vector_ptr_destroy(&edges2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (vertices) {
+    igraph_vector_ptr_destroy(&vertices2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;  
+}
+
+void igraph_i_gasp_paths_destroy(igraph_vector_ptr_t *v);
+
+void igraph_i_gasp_paths_destroy(igraph_vector_ptr_t *v) {
+  long int i;
+  for (i=0; i<igraph_vector_ptr_size(v); i++) {
+    if (VECTOR(*v)[i] != 0) {
+      igraph_vector_destroy(VECTOR(*v)[i]);
+      igraph_Free(VECTOR(*v)[i]);
+    }
+  }
+  igraph_vector_ptr_destroy(v);
+}
+
+/**
+ * \function igraph_get_all_shortest_paths
+ * \brief Finds all shortest paths (geodesics) from a vertex to all other vertices.
+ * 
+ * \param graph The graph object.
+ * \param res Pointer to an initialized pointer vector, the result
+ *   will be stored here in igraph_vector_t objects. Each vector
+ *   object contains the vertices along a shortest path from \p from
+ *   to another vertex. The vectors are ordered according to their
+ *   target vertex: first the shortest paths to vertex 0, then to
+ *   vertex 1, etc. No data is included for unreachable vertices.
+ * \param nrgeo Pointer to an initialized igraph_vector_t object or
+ *   NULL. If not NULL the number of shortest paths from \p from are
+ *   stored here for every vertex in the graph. Note that the values
+ *   will be accurate only for those vertices that are in the target
+ *   vertex sequence (see \p to), since the search terminates as soon
+ *   as all the target vertices have been found.
+ * \param from The id of the vertex from/to which the geodesics are
+ *        calculated. 
+ * \param to Vertex sequence with the ids of the vertices to/from which the 
+ *        shortest paths will be calculated. A vertex might be given multiple
+ *        times.
+ * \param mode The type of shortest paths to be use for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the lengths of the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the lengths of the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL 
+ *          the directed graph is considered as an
+ *          undirected one for the computation.
+ *        \endclist
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM 
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           \p from is invalid vertex id.
+ *        \cli IGRAPH_EINVMODE 
+ *           invalid mode argument.
+ *        \endclist
+ *
+ * Added in version 0.2.</para><para>
+ *
+ * Time complexity: O(|V|+|E|) for most graphs, O(|V|^2) in the worst
+ * case. 
+ */
+
+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) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int *geodist;
+  igraph_vector_ptr_t paths;
+  igraph_dqueue_t q;
+  igraph_vector_t *vptr;
+  igraph_vector_t neis;
+  igraph_vector_t ptrlist;
+  igraph_vector_t ptrhead;
+  long int n, j, i;
+  long int to_reach, reached=0, maxdist=0;
+
+  igraph_vit_t vit;
+
+  if (from<0 || from>=no_of_nodes) {
+    IGRAPH_ERROR("cannot get shortest paths", IGRAPH_EINVVID);
+  }
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  /* paths will store the shortest paths during the search */
+  IGRAPH_CHECK(igraph_vector_ptr_init(&paths, 0));
+  IGRAPH_FINALLY(igraph_i_gasp_paths_destroy, &paths);
+  /* neis is a temporary vector holding the neighbors of the
+   * node being examined */
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  /* ptrlist stores indices into the paths vector, in the order
+   * of how they were found. ptrhead is a second-level index that
+   * will be used to find paths that terminate in a given vertex */
+  IGRAPH_VECTOR_INIT_FINALLY(&ptrlist, 0);
+  /* ptrhead contains indices into ptrlist.
+   * ptrhead[i] = j means that element #j-1 in ptrlist contains
+   * the shortest path from the root to node i. ptrhead[i] = 0
+   * means that node i was not reached so far */
+  IGRAPH_VECTOR_INIT_FINALLY(&ptrhead, no_of_nodes);
+  /* geodist[i] == 0 if i was not reached yet and it is not in the
+   * target vertex sequence, or -1 if i was not reached yet and it
+   * is in the target vertex sequence. Otherwise it is
+   * one larger than the length of the shortest path from the
+   * source */
+  geodist=igraph_Calloc(no_of_nodes, long int);
+  if (geodist==0) {
+    IGRAPH_ERROR("Cannot calculate shortest paths", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, geodist);
+  /* dequeue to store the BFS queue -- odd elements are the vertex indices,
+   * even elements are the distances from the root */
+  IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
+
+  if (nrgeo) { 
+    IGRAPH_CHECK(igraph_vector_resize(nrgeo, no_of_nodes));
+    igraph_vector_null(nrgeo);
+  }
+
+  /* use geodist to count how many vertices we have to reach */
+  to_reach=IGRAPH_VIT_SIZE(vit);
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    if (geodist[ (long int) IGRAPH_VIT_GET(vit) ] == 0) {
+      geodist[ (long int) IGRAPH_VIT_GET(vit) ] = -1;
+    } else {
+      to_reach--;		/* this node was given multiple times */
+    }
+  }
+
+  if (geodist[ (long int) from ] < 0) { reached++; }
+
+  /* from -> from */
+  vptr=igraph_Calloc(1, igraph_vector_t); /* TODO: dirty */
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(&paths, vptr));
+  IGRAPH_CHECK(igraph_vector_init(vptr, 1));
+  VECTOR(*vptr)[0]=from;
+  geodist[(long int)from]=1;
+  VECTOR(ptrhead)[(long int)from]=1;
+  IGRAPH_CHECK(igraph_vector_push_back(&ptrlist, 0));
+  if (nrgeo) { VECTOR(*nrgeo)[(long int)from]=1; }
+
+  /* Init queue */
+  IGRAPH_CHECK(igraph_dqueue_push(&q, from));
+  IGRAPH_CHECK(igraph_dqueue_push(&q, 0.0));
+  while (!igraph_dqueue_empty(&q)) {
+    long int actnode=(long int) igraph_dqueue_pop(&q);
+    long int actdist=(long int) igraph_dqueue_pop(&q);
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    if (reached >= to_reach) {
+      /* all nodes were reached. Since we need all the shortest paths
+       * to all these nodes, we can stop the search only if the distance
+       * of the current node to the root is larger than the distance of
+       * any of the nodes we wanted to reach */
+      if (actdist > maxdist) {
+        /* safety check, maxdist should have been set when we reached the last node */
+        if (maxdist < 0) {
+          IGRAPH_ERROR("possible bug in igraph_get_all_shortest_paths, "
+                       "maxdist is negative", IGRAPH_EINVAL);
+        }
+        break;
+      }
+    }
+
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, 
+				  mode));
+    n=igraph_vector_size(&neis);
+    for (j=0; j<n; j++) {
+      long int neighbor=(long int) VECTOR(neis)[j];
+      long int fatherptr;
+
+      if (geodist[neighbor] > 0 && 
+          geodist[neighbor]-1 < actdist+1) {
+        /* this node was reached via a shorter path before */
+        continue;
+      }
+
+      /* yay, found another shortest path to neighbor */
+
+      if (nrgeo) {
+        /* the number of geodesics leading to neighbor must be
+         * increased by the number of geodesics leading to actnode */
+        VECTOR(*nrgeo)[neighbor] += VECTOR(*nrgeo)[actnode];
+      }
+      if (geodist[neighbor] <= 0) {
+        /* this node was not reached yet, push it into the queue */
+        IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+        IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+        if (geodist[neighbor] < 0) {
+          reached++;
+        }
+        if (reached == to_reach)
+          maxdist = actdist;
+      }
+      geodist[neighbor]=actdist+2;
+
+      /* copy all existing paths to the parent */
+      fatherptr = (long int) VECTOR(ptrhead)[actnode];
+      while (fatherptr != 0) {
+        /* allocate a new igraph_vector_t at the end of paths */
+        vptr=igraph_Calloc(1, igraph_vector_t);
+        IGRAPH_CHECK(igraph_vector_ptr_push_back(&paths, vptr));
+        IGRAPH_CHECK(igraph_vector_copy(vptr, VECTOR(paths)[fatherptr-1]));
+        IGRAPH_CHECK(igraph_vector_reserve(vptr, actdist+2));
+        IGRAPH_CHECK(igraph_vector_push_back(vptr, neighbor));
+
+        IGRAPH_CHECK(igraph_vector_push_back(&ptrlist, 
+                     VECTOR(ptrhead)[neighbor]));
+        VECTOR(ptrhead)[neighbor]=igraph_vector_size(&ptrlist);
+
+        fatherptr=(long int) VECTOR(ptrlist)[fatherptr-1];
+      }
+    }
+  }
+
+  igraph_dqueue_destroy(&q);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* mark the nodes for which we need the result */
+  memset(geodist, 0, sizeof(long int) * (size_t) no_of_nodes);
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    geodist[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
+  }
+
+  /* count the number of paths in the result */
+  n=0;
+  for (i=0; i<no_of_nodes; i++) {
+    long int fatherptr=(long int) VECTOR(ptrhead)[i];
+    if (geodist[i] > 0) {
+      while (fatherptr != 0) {
+        n++;
+        fatherptr=(long int) VECTOR(ptrlist)[fatherptr-1];
+      }
+    }
+  }
+
+  IGRAPH_CHECK(igraph_vector_ptr_resize(res, n));
+  j=0;
+  for (i=0; i<no_of_nodes; i++) {
+    long int fatherptr=(long int) VECTOR(ptrhead)[i];
+
+    IGRAPH_ALLOW_INTERRUPTION();
+	
+    /* do we need the paths leading to vertex i? */
+    if (geodist[i] > 0) {
+      /* yes, copy them to the result vector */
+      while (fatherptr != 0) {
+        VECTOR(*res)[j++]=VECTOR(paths)[fatherptr-1];
+        fatherptr=(long int) VECTOR(ptrlist)[fatherptr-1];
+      }
+    } else {
+      /* no, free them */
+      while (fatherptr != 0) {
+        igraph_vector_destroy(VECTOR(paths)[fatherptr-1]);
+        igraph_Free(VECTOR(paths)[fatherptr-1]);
+        fatherptr=(long int) VECTOR(ptrlist)[fatherptr-1];
+      }
+    }
+  }
+
+  igraph_Free(geodist);
+  igraph_vector_destroy(&ptrlist);
+  igraph_vector_destroy(&ptrhead);
+  igraph_vector_destroy(&neis);
+  igraph_vector_ptr_destroy(&paths);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(6);
+
+  return 0;
+}
+		  
+
+/** 
+ * \ingroup structural
+ * \function igraph_subcomponent
+ * \brief The vertices in the same component as a given vertex.
+ *
+ * \param graph The graph object.
+ * \param res The result, vector with the ids of the vertices in the
+ *        same component. 
+ * \param vertex The id of the vertex of which the component is
+ *        searched. 
+ * \param mode Type of the component for directed graphs, possible
+ *        values:
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the set of vertices reachable \em from the
+ *          \p vertex, 
+ *        \cli IGRAPH_IN
+ *          the set of vertices from which the
+ *          \p vertex is reachable.
+ *        \cli IGRAPH_ALL 
+ *          the graph is considered as an
+ *          undirected graph. Note that this is \em not the same
+ *          as the union of the previous two.
+ *        \endclist
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM 
+ *          not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID 
+ *           \p vertex is an invalid vertex id
+ *        \cli IGRAPH_EINVMODE
+ *           invalid mode argument passed.
+ *        \endclist
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| and
+ * |E| are the number of vertices and
+ * edges in the graph. 
+ * 
+ * \sa \ref igraph_subgraph() if you want a graph object consisting only
+ * a given set of vertices and the edges between them.
+ */
+
+int igraph_subcomponent(const igraph_t *graph, igraph_vector_t *res, igraph_real_t vertex, 
+			igraph_neimode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
+  char *already_added;
+  long int i;
+  igraph_vector_t tmp=IGRAPH_VECTOR_NULL;
+
+  if (!IGRAPH_FINITE(vertex) || vertex<0 || vertex>=no_of_nodes) {
+    IGRAPH_ERROR("subcomponent failed", IGRAPH_EINVVID);
+  }
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("invalid mode argument", IGRAPH_EINVMODE);
+  }
+
+  already_added=igraph_Calloc(no_of_nodes, char);
+  if (already_added==0) {
+    IGRAPH_ERROR("subcomponent failed",IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, already_added); /* TODO: hack */
+
+  igraph_vector_clear(res);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  
+  IGRAPH_CHECK(igraph_dqueue_push(&q, vertex));
+  IGRAPH_CHECK(igraph_vector_push_back(res, vertex));
+  already_added[(long int)vertex]=1;
+  
+  while (!igraph_dqueue_empty(&q)) {
+    long int actnode=(long int) igraph_dqueue_pop(&q);
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) actnode,
+				  mode));
+    for (i=0; i<igraph_vector_size(&tmp); i++) {
+      long int neighbor=(long int) VECTOR(tmp)[i];
+      
+      if (already_added[neighbor]) { continue; }
+      already_added[neighbor]=1;
+      IGRAPH_CHECK(igraph_vector_push_back(res, neighbor));
+      IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+    }
+  }
+
+  igraph_dqueue_destroy(&q);
+  igraph_vector_destroy(&tmp);
+  igraph_Free(already_added);
+  IGRAPH_FINALLY_CLEAN(3);
+   
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_pagerank_old
+ * \brief Calculates the Google PageRank for the specified vertices.
+ * 
+ * </para><para>This is an old implementation, 
+ * it is provided for compatibility with igraph versions earlier than 
+ * 0.5. Please use the new implementation \ref igraph_pagerank() in 
+ * new projects.
+ *
+ * </para><para>
+ * From version 0.7 this function is deprecated and its use gives a
+ * warning message.
+ *
+ * </para><para>
+ * 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.
+ * </para>
+ * <para>
+ * 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.
+ * </para>
+ * 
+ * <para>
+ * For the explanation of the PageRank algorithm, see the following
+ * webpage:
+ * http://infolab.stanford.edu/~backrub/google.html , or the
+ * following reference:
+ * </para>
+ * 
+ * <para>
+ * 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.
+ * </para>
+ * <para>
+ * \param graph The graph object.
+ * \param res The result vector containing the PageRank values for the
+ * given nodes.
+ * \param vids Vector with the vertex ids
+ * \param directed Logical, if true directed paths will be considered
+ *        for directed graphs. It is ignored for undirected graphs.
+ * \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 damping The damping factor ("d" in the original paper)
+ * \param old Boolean, whether to use the pre-igraph 0.5 way to 
+ *        calculate page rank. Not recommended for new applications,
+ *        only included for compatibility. If this is non-zero then the damping 
+ *        factor is not divided by the number of vertices before adding it 
+ *        to the weighted page rank scores to calculate the 
+ *        new scores. I.e. the formula in the original PageRank paper
+ *        is used. Furthermore, if this is non-zero then the PageRank
+ *        vector is renormalized after each iteration.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVVID, invalid vertex id in
+ *         \p vids. 
+ * 
+ * Time complexity: O(|V|+|E|) per iteration. A handful iterations
+ * should be enough. Note that if the old-style dumping is used then 
+ * the iteration might not converge at all.
+ * 
+ * \sa \ref igraph_pagerank() for the new implementation.
+ */
+
+int igraph_pagerank_old(const igraph_t *graph, igraph_vector_t *res, 
+			const igraph_vs_t vids, igraph_bool_t directed,
+			igraph_integer_t niter, igraph_real_t eps, 
+			igraph_real_t damping, igraph_bool_t old) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i, j, n, nodes_to_calc;
+  igraph_real_t *prvec, *prvec_new, *prvec_aux, *prvec_scaled;
+  igraph_vector_int_t *neis;
+  igraph_vector_t outdegree;
+  igraph_neimode_t dirmode;
+  igraph_adjlist_t allneis;
+  igraph_real_t maxdiff=eps;
+  igraph_vit_t vit;
+
+  IGRAPH_WARNING("igraph_pagerank_old is deprecated from igraph 0.7, "
+		 "use igraph_pagerank instead");
+
+  if (niter<=0) IGRAPH_ERROR("Invalid iteration count", IGRAPH_EINVAL);
+  if (eps<=0) IGRAPH_ERROR("Invalid epsilon value", IGRAPH_EINVAL);
+  if (damping<=0 || damping>=1) IGRAPH_ERROR("Invalid damping factor", IGRAPH_EINVAL);
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  igraph_vector_null(res);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&outdegree, no_of_nodes);
+    
+  prvec=igraph_Calloc(no_of_nodes, igraph_real_t);
+  if (prvec==0) {
+    IGRAPH_ERROR("pagerank failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, prvec);
+  
+  prvec_new=igraph_Calloc(no_of_nodes, igraph_real_t);
+  if (prvec_new==0) {
+    IGRAPH_ERROR("pagerank failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, prvec_new);
+  
+  prvec_scaled=igraph_Calloc(no_of_nodes, igraph_real_t);
+  if (prvec_scaled==0) {
+    IGRAPH_ERROR("pagerank failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, prvec_scaled);
+  
+  if (directed) { dirmode=IGRAPH_IN; } else { dirmode=IGRAPH_ALL; }  
+  igraph_adjlist_init(graph, &allneis, dirmode);
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+
+  /* Calculate outdegrees for every node */
+  igraph_degree(graph, &outdegree, igraph_vss_all(),
+		directed?IGRAPH_OUT:IGRAPH_ALL, 0);
+  /* Initialize PageRank values */
+  for (i=0; i<no_of_nodes; i++) {
+    prvec[i]=1-damping;
+    /* The next line is necessary to avoid division by zero in the
+     * calculation of prvec_scaled. This won't cause any problem,
+     * since if a node doesn't have any outgoing links, its
+     * prvec_scaled value won't be used anywhere */
+    if (VECTOR(outdegree)[i]==0) VECTOR(outdegree)[i]=1;
+  }
+  
+  /* We will always calculate the new PageRank values into prvec_new
+   * based on the existing values from prvec. To avoid unnecessary
+   * copying from prvec_new to prvec at the end of every iteration,
+   * the pointers are swapped after every iteration */
+  while (niter>0 && maxdiff >= eps) {
+    igraph_real_t sumfrom=0, sum=0;
+    niter--;
+    maxdiff=0;
+
+    /* Calculate the quotient of the actual PageRank value and the
+     * outdegree for every node */
+     sumfrom=0.0; sum=0.0;
+    for (i=0; i<no_of_nodes; i++) {
+       sumfrom += prvec[i];
+      prvec_scaled[i]=prvec[i]/VECTOR(outdegree)[i];
+    }
+    
+    /* Calculate new PageRank values based on the old ones */
+    for (i=0; i<no_of_nodes; i++) {
+      
+      IGRAPH_ALLOW_INTERRUPTION();
+
+      prvec_new[i]=0;
+      neis=igraph_adjlist_get(&allneis, i);
+      n=igraph_vector_int_size(neis);
+      for (j=0; j<n; j++) {
+	long int neighbor=(long int) VECTOR(*neis)[j];
+	prvec_new[i]+=prvec_scaled[neighbor];
+      }
+      prvec_new[i]*=damping;
+      if (!old) {
+	prvec_new[i]+=(1-damping)/no_of_nodes;
+      } else {
+	prvec_new[i]+=(1-damping);
+      }
+      sum += prvec_new[i];
+      
+     }
+     for (i=0; i<no_of_nodes; i++) {
+       if (!old) { prvec_new[i] /= sum; }
+
+      if (prvec_new[i]-prvec[i]>maxdiff) 
+	maxdiff=prvec_new[i]-prvec[i];
+      else if (prvec[i]-prvec_new[i]>maxdiff)
+	maxdiff=prvec[i]-prvec_new[i];
+    }
+
+    /* Swap the vectors */
+    prvec_aux=prvec_new;
+    prvec_new=prvec;
+    prvec=prvec_aux;
+  }
+  
+  /* Copy results from prvec to res */
+  for (IGRAPH_VIT_RESET(vit), i=0; 
+       !IGRAPH_VIT_END(vit); 
+       IGRAPH_VIT_NEXT(vit), i++) {
+    long int vid=IGRAPH_VIT_GET(vit);
+    VECTOR(*res)[i]=prvec[vid];
+  }
+  
+  igraph_adjlist_destroy(&allneis);
+  igraph_vit_destroy(&vit);
+  igraph_vector_destroy(&outdegree);
+  igraph_Free(prvec);
+  igraph_Free(prvec_new);  
+  igraph_Free(prvec_scaled);
+  
+  IGRAPH_FINALLY_CLEAN(6);
+  
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_rewire
+ * \brief Randomly rewires a graph while preserving the degree distribution.
+ * 
+ * </para><para>
+ * This function generates a new graph based on the original one by randomly
+ * rewiring edges while preserving the original graph's degree distribution.
+ * Please note that the rewiring is done "in place", so no new graph will
+ * be allocated. If you would like to keep the original graph intact, use
+ * \ref igraph_copy() beforehand.
+ * 
+ * \param graph The graph object to be rewired.
+ * \param n Number of rewiring trials to perform.
+ * \param mode The rewiring algorithm to be used. It can be one of the following:
+ *         \clist
+ *           \cli IGRAPH_REWIRING_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 exist.  The method will
+ *                neither destroy nor create self-loops.
+ *           \cli IGRAPH_REWIRING_SIMPLE_LOOPS
+ *                Same as \c IGRAPH_REWIRING_SIMPLE but allows the creation or
+ *                destruction of self-loops.
+ *         \endclist
+ *
+ * \return Error code:
+ *         \clist
+ *           \cli IGRAPH_EINVMODE
+ *                Invalid rewiring mode.
+ *           \cli IGRAPH_EINVAL
+ *                Graph unsuitable for rewiring (e.g. it has
+ *                less than 4 nodes in case of \c IGRAPH_REWIRING_SIMPLE)
+ *           \cli IGRAPH_ENOMEM
+ *                Not enough memory for temporary data.
+ *         \endclist
+ *
+ * Time complexity: TODO.
+ * 
+ * \example examples/simple/igraph_rewire.c
+ */
+
+int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  char message[256];
+  igraph_integer_t a, b, c, d, dummy, num_swaps, num_successful_swaps;
+  igraph_vector_t eids, edgevec;
+  igraph_bool_t directed, loops, ok;
+  igraph_es_t es;
+  
+  if ((mode == IGRAPH_REWIRING_SIMPLE || mode == IGRAPH_REWIRING_SIMPLE_LOOPS) &&
+      no_of_nodes<4)
+    IGRAPH_ERROR("graph unsuitable for rewiring", IGRAPH_EINVAL);
+  
+  directed = igraph_is_directed(graph);
+  loops = (mode == IGRAPH_REWIRING_SIMPLE_LOOPS);
+  
+  RNG_BEGIN();
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edgevec, 4);
+  IGRAPH_VECTOR_INIT_FINALLY(&eids, 2);
+  es = igraph_ess_vector(&eids);
+
+  /* We don't want the algorithm to get stuck in an infinite loop when
+   * it can't choose two edges satisfying the conditions. Instead of
+   * this, we choose two arbitrary edges and if they have endpoints
+   * in common, we just decrease the number of trials left and continue
+   * (so unsuccessful rewirings still count as a trial)
+   */
+
+  num_swaps = num_successful_swaps = 0;
+  while (num_swaps < n) {
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    if (num_swaps % 1000 == 0) {
+      snprintf(message, sizeof(message),
+          "Random rewiring (%.2f%% of the trials were successful)",
+          (100.0 * num_successful_swaps) / num_swaps);
+      IGRAPH_PROGRESS(message, (100.0 * num_swaps) / n, 0);
+    }
+    
+    switch (mode) {
+    case IGRAPH_REWIRING_SIMPLE:
+    case IGRAPH_REWIRING_SIMPLE_LOOPS:
+      ok = 1;
+
+      /* Choose two edges randomly */
+      VECTOR(eids)[0]=RNG_INTEGER(0, no_of_edges-1);
+      do {
+        VECTOR(eids)[1]=RNG_INTEGER(0, no_of_edges-1);
+      } while (VECTOR(eids)[0] == VECTOR(eids)[1]);
+
+      /* Get the endpoints */
+      IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) VECTOR(eids)[0], 
+			       &a, &b));
+      IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) VECTOR(eids)[1],
+			       &c, &d));
+
+      /* For an undirected graph, we have two "variants" of each edge, i.e.
+       * a -- b and b -- a. Since some rewirings can be performed only when we
+       * "swap" the endpoints, we do it now with probability 0.5 */
+      if (!directed && RNG_UNIF01() < 0.5) {
+        dummy = c; c = d; d = dummy;
+      }
+
+      /* If we do not touch loops, check whether a == b or c == d and disallow
+       * the swap if needed */
+      if (!loops && (a == b || c == d)) {
+        ok = 0;
+      } else {
+        /* Check whether they are suitable for rewiring */
+        if (a == c || b == d) {
+          /* Swapping would have no effect */
+          ok = 0;
+        } else {
+          /* a != c && b != d */
+          /* If a == d or b == c, the swap would generate at least one loop, so
+           * we disallow them unless we want to have loops */
+          ok = loops || (a != d && b != c);
+          /* Also, if a == b and c == d and we allow loops, doing the swap
+           * would result in a multiple edge if the graph is undirected */
+          ok = ok && (directed || a != b || c != d);
+        }
+      }
+
+      /* All good so far. Now check for the existence of a --> d and c --> b to
+       * disallow the creation of multiple edges */
+      if (ok) {
+        IGRAPH_CHECK(igraph_are_connected(graph, a, d, &ok));
+        ok = !ok;
+      }
+      if (ok) {
+        IGRAPH_CHECK(igraph_are_connected(graph, c, b, &ok));
+        ok = !ok;
+      }
+
+      /* If we are still okay, we can perform the rewiring */
+      if (ok) {
+	/* printf("Deleting: %ld -> %ld, %ld -> %ld\n",
+                  (long)a, (long)b, (long)c, (long)d); */
+	IGRAPH_CHECK(igraph_delete_edges(graph, es));	
+	VECTOR(edgevec)[0]=a; VECTOR(edgevec)[1]=d;
+	VECTOR(edgevec)[2]=c; VECTOR(edgevec)[3]=b;
+	/* printf("Adding: %ld -> %ld, %ld -> %ld\n",
+                  (long)a, (long)d, (long)c, (long)b); */
+	igraph_add_edges(graph, &edgevec, 0);
+        num_successful_swaps++;
+      }
+      break;
+    default:
+      RNG_END();
+      IGRAPH_ERROR("unknown rewiring mode", IGRAPH_EINVMODE);
+    }
+    num_swaps++;
+  }
+  
+  IGRAPH_PROGRESS("Random rewiring: ", 100.0, 0);
+
+  igraph_vector_destroy(&eids);
+  igraph_vector_destroy(&edgevec);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  RNG_END();
+  
+  return 0;
+}
+
+int igraph_i_subgraph_copy_and_delete(const igraph_t *graph, igraph_t *res,
+				      const igraph_vs_t vids, 
+				      igraph_vector_t *map,
+				      igraph_vector_t *invmap);
+
+int igraph_i_subgraph_create_from_scratch(const igraph_t *graph, 
+					  igraph_t *res,
+					  const igraph_vs_t vids,
+					  igraph_vector_t *map,
+					  igraph_vector_t *invmap);
+
+/**
+ * Subgraph creation, old version: it copies the graph and then deletes
+ * unneeded vertices.
+ */
+int igraph_i_subgraph_copy_and_delete(const igraph_t *graph, igraph_t *res,
+				      const igraph_vs_t vids, 
+				      igraph_vector_t *map,
+				      igraph_vector_t *invmap) {
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t delete=IGRAPH_VECTOR_NULL;
+  char *remain;
+  long int i;
+  igraph_vit_t vit;
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&delete, 0);
+  remain=igraph_Calloc(no_of_nodes, char);
+  if (remain==0) {
+    IGRAPH_ERROR("subgraph failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, remain);	/* TODO: hack */
+  IGRAPH_CHECK(igraph_vector_reserve(&delete, no_of_nodes-IGRAPH_VIT_SIZE(vit)));
+  
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    remain[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
+  }
+
+  for (i=0; i<no_of_nodes; i++) {
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    if (remain[i] == 0) {
+      IGRAPH_CHECK(igraph_vector_push_back(&delete, i));
+    }
+  }
+
+  igraph_Free(remain);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  /* must set res->attr to 0 before calling igraph_copy */
+  res->attr=0;           /* Why is this needed? TODO */
+  IGRAPH_CHECK(igraph_copy(res, graph));
+  IGRAPH_FINALLY(igraph_destroy, res);
+  IGRAPH_CHECK(igraph_delete_vertices_idx(res, igraph_vss_vector(&delete), 
+					  map, invmap));
+  
+  igraph_vector_destroy(&delete);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+/**
+ * Subgraph creation, new version: creates the new graph instead of
+ * copying the old one.
+ */
+int igraph_i_subgraph_create_from_scratch(const igraph_t *graph, 
+					  igraph_t *res,
+					  const igraph_vs_t vids,
+					  igraph_vector_t *map,
+					  igraph_vector_t *invmap) {
+  igraph_bool_t directed = igraph_is_directed(graph);
+  long int no_of_nodes = igraph_vcount(graph);
+  long int no_of_new_nodes = 0;
+  char* seen_edges = 0;
+  long int i, j, n;
+  igraph_vector_t vids_old2new, vids_new2old;
+  igraph_vector_t eids_new2old;
+  igraph_vector_t nei_edges;
+  igraph_vector_t new_edges;
+  igraph_vit_t vit;
+  igraph_vector_t *my_vids_old2new=&vids_old2new, 
+    *my_vids_new2old=&vids_new2old;
+
+  /* The order of initialization is important here, they will be destroyed in the
+   * opposite order */
+  IGRAPH_VECTOR_INIT_FINALLY(&eids_new2old, 0);
+  if (invmap) {
+    my_vids_new2old=invmap;
+    igraph_vector_clear(my_vids_new2old);
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&vids_new2old, 0);
+  }
+  IGRAPH_VECTOR_INIT_FINALLY(&new_edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&nei_edges, 0);
+  if (map) {
+    my_vids_old2new=map;
+    IGRAPH_CHECK(igraph_vector_resize(map, no_of_nodes));
+    igraph_vector_null(map);
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&vids_old2new, no_of_nodes);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  /* Calculate the mapping from the old node IDs to the new ones. The other
+   * igraph_simplify implementation in igraph_i_simplify_copy_and_delete
+   * ensures that the order of vertex IDs is kept during remapping (i.e.
+   * if the old ID of vertex A is less than the old ID of vertex B, then
+   * the same will also be true for the new IDs). To ensure compatibility
+   * with the other implementation, we have to fetch the vertex IDs into
+   * a vector first and then sort it. We temporarily use new_edges for that.
+   */
+  IGRAPH_CHECK(igraph_vit_as_vector(&vit, &nei_edges));
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_vector_sort(&nei_edges);
+  n = igraph_vector_size(&nei_edges);
+  for (i = 0; i < n; i++) {
+    long int vid = (long int) VECTOR(nei_edges)[i];
+    if (VECTOR(*my_vids_old2new)[vid] == 0) {
+      VECTOR(*my_vids_old2new)[vid] = ++no_of_new_nodes;
+    }
+  }
+
+  /* Allocate some memory for the seen_edges array that avoids processing edges
+   * twice for undirected graphs */
+  if (!directed) {
+    seen_edges = igraph_Calloc(igraph_ecount(graph), char);
+    if (seen_edges == 0)
+      IGRAPH_ERROR("cannot calculate subgraph", IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(igraph_free, seen_edges);
+  }
+
+  /* Calculate the mapping from the new node IDs to the new ones
+   * and also create the new edge list */
+  IGRAPH_CHECK(igraph_vector_resize(my_vids_new2old, no_of_new_nodes));
+  for (i = 0; i < no_of_nodes; i++) {
+    long int new_vid = (long int) VECTOR(*my_vids_old2new)[i] - 1;
+    if (new_vid < 0)
+      continue;
+
+    VECTOR(*my_vids_new2old)[new_vid] = i;
+
+    IGRAPH_CHECK(igraph_incident(graph, &nei_edges, (igraph_integer_t) i,
+				 IGRAPH_OUT));
+    n = igraph_vector_size(&nei_edges);
+
+    if (directed) {
+      for (j = 0; j < n; j++) {
+        igraph_integer_t eid  = (igraph_integer_t) VECTOR(nei_edges)[j];
+        long int from, to;
+
+        from = (long int) VECTOR(*my_vids_old2new)[
+				(long int)IGRAPH_FROM(graph, eid) ];
+        if (!from) continue;
+        to = (long int) VECTOR(*my_vids_old2new)[
+				(long int)IGRAPH_TO(graph, eid)];
+        if (!to) continue;
+
+        IGRAPH_CHECK(igraph_vector_push_back(&new_edges, from-1));
+        IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to-1));
+        IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));
+      }
+    } else {
+      for (j = 0; j < n; j++) {
+        igraph_integer_t eid  = (igraph_integer_t) VECTOR(nei_edges)[j];
+        long int from, to;
+
+        from = (long int) VECTOR(*my_vids_old2new)[
+				(long int)IGRAPH_FROM(graph, eid)];
+        if (!from) continue;
+        to = (long int) VECTOR(*my_vids_old2new)[
+			        (long int)IGRAPH_TO(graph, eid)];
+        if (!to) continue;
+        if (seen_edges[(long int)eid])
+          continue;
+
+        seen_edges[(long int)eid] = 1;
+        IGRAPH_CHECK(igraph_vector_push_back(&new_edges, from-1));
+        IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to-1));
+        IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));
+      }
+    }
+  }
+
+  /* Get rid of some vectors that are not needed anymore */
+  if (!directed) {
+    igraph_free(seen_edges);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (!map) {
+    igraph_vector_destroy(&vids_old2new);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_vector_destroy(&nei_edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Create the new graph */
+  IGRAPH_CHECK(igraph_create(res, &new_edges, (igraph_integer_t) 
+			     no_of_new_nodes, directed));
+  IGRAPH_I_ATTRIBUTE_DESTROY(res);
+
+  /* Now we can also get rid of the new_edges vector */
+  igraph_vector_destroy(&new_edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Make sure that the newly created graph is destroyed if something happens from
+   * now on */
+  IGRAPH_FINALLY(igraph_destroy, res);
+
+  /* Copy the graph attributes */
+  IGRAPH_CHECK(igraph_i_attribute_copy(res, graph,
+        /* ga = */ 1, /* va = */ 0, /* ea = */ 0));
+
+  /* Copy the vertex attributes */
+  IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, res, 
+						   my_vids_new2old));
+
+  /* Copy the edge attributes */
+  IGRAPH_CHECK(igraph_i_attribute_permute_edges(graph, res, &eids_new2old));
+
+  if (!invmap) {
+    igraph_vector_destroy(my_vids_new2old);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  igraph_vector_destroy(&eids_new2old);
+  IGRAPH_FINALLY_CLEAN(2);   /* 1 + 1 since we don't need to destroy res */
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_subgraph
+ * \brief Creates a subgraph induced by the specified vertices.
+ * 
+ * </para><para>
+ * This function is an alias to \ref igraph_induced_subgraph(), it is
+ * left here to ensure API compatibility with igraph versions prior to 0.6.
+ *
+ * </para><para>
+ * This function collects the specified vertices and all edges between
+ * them to a new graph.
+ * As the vertex ids in a graph always start with zero, this function
+ * very likely needs to reassign ids to the vertices.
+ * \param graph The graph object.
+ * \param res The subgraph, another graph object will be stored here,
+ *        do \em not initialize this object before calling this
+ *        function, and call \ref igraph_destroy() on it if you don't need
+ *        it any more.
+ * \param vids A vertex selector describing which vertices to keep.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVVID, invalid vertex id in
+ *         \p vids. 
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| and
+ * |E| are the number of vertices and
+ * edges in the original graph.
+ *
+ * \sa \ref igraph_delete_vertices() to delete the specified set of
+ * vertices from a graph, the opposite of this function.
+ */
+
+int igraph_subgraph(const igraph_t *graph, igraph_t *res, 
+		    const igraph_vs_t vids) {
+	IGRAPH_WARNING("igraph_subgraph is deprecated from igraph 0.6, "
+			           "use igraph_induced_subgraph instead");
+  return igraph_induced_subgraph(graph, res, vids, IGRAPH_SUBGRAPH_AUTO);
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_induced_subgraph
+ * \brief Creates a subgraph induced by the specified vertices.
+ * 
+ * </para><para>
+ * This function collects the specified vertices and all edges between
+ * them to a new graph.
+ * As the vertex ids in a graph always start with zero, this function
+ * very likely needs to reassign ids to the vertices.
+ * \param graph The graph object.
+ * \param res The subgraph, another graph object will be stored here,
+ *        do \em not initialize this object before calling this
+ *        function, and call \ref igraph_destroy() on it if you don't need
+ *        it any more.
+ * \param vids A vertex selector describing which vertices to keep.
+ * \param impl This parameter selects which implementation should we
+ *        use when constructing the new graph. Basically there are two
+ *        possibilities: \c IGRAPH_SUBGRAPH_COPY_AND_DELETE copies the
+ *        existing graph and deletes the vertices that are not needed
+ *        in the new graph, while \c IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH
+ *        constructs the new graph from scratch without copying the old
+ *        one. The latter is more efficient if you are extracting a
+ *        relatively small subpart of a very large graph, while the
+ *        former is better if you want to extract a subgraph whose size
+ *        is comparable to the size of the whole graph. There is a third
+ *        possibility: \c IGRAPH_SUBGRAPH_AUTO will select one of the
+ *        two methods automatically based on the ratio of the number
+ *        of vertices in the new and the old graph.
+ *
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVVID, invalid vertex id in
+ *         \p vids. 
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| and
+ * |E| are the number of vertices and
+ * edges in the original graph.
+ *
+ * \sa \ref igraph_delete_vertices() to delete the specified set of
+ * vertices from a graph, the opposite of this function.
+ */
+int igraph_induced_subgraph(const igraph_t *graph, igraph_t *res, 
+		    const igraph_vs_t vids, igraph_subgraph_implementation_t impl) {
+  return igraph_induced_subgraph_map(graph, res, vids, impl, /* map= */ 0, 
+				     /* invmap= */ 0);
+}
+
+int igraph_induced_subgraph_map(const igraph_t *graph, igraph_t *res,
+				const igraph_vs_t vids, 
+				igraph_subgraph_implementation_t impl,
+				igraph_vector_t *map, 
+				igraph_vector_t *invmap) {
+
+  if (impl == IGRAPH_SUBGRAPH_AUTO) {
+    double ratio;
+
+    if (igraph_vs_is_all(&vids))
+      ratio = 1.0;
+    else {
+      igraph_integer_t num_vs;
+      IGRAPH_CHECK(igraph_vs_size(graph, &vids, &num_vs));
+      ratio = (igraph_real_t) num_vs / igraph_vcount(graph);
+    }
+
+    if (ratio > 0.5)
+      impl = IGRAPH_SUBGRAPH_COPY_AND_DELETE;
+    else
+      impl = IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH;
+  }
+
+  switch (impl) {
+    case IGRAPH_SUBGRAPH_COPY_AND_DELETE:
+      return igraph_i_subgraph_copy_and_delete(graph, res, vids, map, invmap);
+
+    case IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH:
+      return igraph_i_subgraph_create_from_scratch(graph, res, vids, map, 
+						   invmap);
+
+    default:
+      IGRAPH_ERROR("unknown subgraph implementation type", IGRAPH_EINVAL);
+  }
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_subgraph_edges
+ * \brief Creates a subgraph with the specified edges and their endpoints.
+ * 
+ * </para><para>
+ * This function collects the specified edges and their endpoints to a new
+ * graph.
+ * As the vertex ids in a graph always start with zero, this function
+ * very likely needs to reassign ids to the vertices.
+ * \param graph The graph object.
+ * \param res The subgraph, another graph object will be stored here,
+ *        do \em not initialize this object before calling this
+ *        function, and call \ref igraph_destroy() on it if you don't need
+ *        it any more.
+ * \param eids An edge selector describing which edges to keep.
+ * \param delete_vertices Whether to delete the vertices not incident on any
+ *        of the specified edges as well. If \c FALSE, the number of vertices
+ *        in the result graph will always be equal to the number of vertices
+ *        in the input graph.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM, not enough memory for
+ *         temporary data. 
+ *         \c IGRAPH_EINVEID, invalid edge id in
+ *         \p eids. 
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| and
+ * |E| are the number of vertices and
+ * edges in the original graph.
+ *
+ * \sa \ref igraph_delete_edges() to delete the specified set of
+ * edges from a graph, the opposite of this function.
+ */
+
+int igraph_subgraph_edges(const igraph_t *graph, igraph_t *res, 
+		    const igraph_es_t eids, igraph_bool_t delete_vertices) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t delete=IGRAPH_VECTOR_NULL;
+  char *vremain, *eremain;
+  long int i;
+  igraph_eit_t eit;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, eids, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&delete, 0);
+  vremain=igraph_Calloc(no_of_nodes, char);
+  if (vremain==0) {
+    IGRAPH_ERROR("subgraph_edges failed", IGRAPH_ENOMEM);
+  }
+  eremain=igraph_Calloc(no_of_edges, char);
+  if (eremain==0) {
+    IGRAPH_ERROR("subgraph_edges failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, vremain);	/* TODO: hack */
+  IGRAPH_FINALLY(free, eremain);	/* TODO: hack */
+  IGRAPH_CHECK(igraph_vector_reserve(&delete, no_of_edges-IGRAPH_EIT_SIZE(eit)));
+
+  /* Collect the vertex and edge IDs that will remain */
+  for (IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
+    igraph_integer_t from, to;
+    long int eid = (long int) IGRAPH_EIT_GET(eit);
+    IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) eid, &from, &to));
+    eremain[eid] = vremain[(long int)from] = vremain[(long int)to] = 1;
+  }
+
+  /* Collect the edge IDs to be deleted */
+  for (i=0; i<no_of_edges; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    if (eremain[i] == 0) {
+      IGRAPH_CHECK(igraph_vector_push_back(&delete, i));
+    }
+  }
+
+  igraph_Free(eremain);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Delete the unnecessary edges */
+  /* must set res->attr to 0 before calling igraph_copy */
+  res->attr=0;           /* Why is this needed? TODO */
+  IGRAPH_CHECK(igraph_copy(res, graph));
+  IGRAPH_FINALLY(igraph_destroy, res);
+  IGRAPH_CHECK(igraph_delete_edges(res, igraph_ess_vector(&delete)));
+
+  if (delete_vertices) {
+    /* Collect the vertex IDs to be deleted */
+    igraph_vector_clear(&delete);
+    for (i=0; i<no_of_nodes; i++) {
+      IGRAPH_ALLOW_INTERRUPTION();
+      if (vremain[i] == 0) {
+        IGRAPH_CHECK(igraph_vector_push_back(&delete, i));
+      }
+    }
+  }
+
+  igraph_Free(vremain);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Delete the unnecessary vertices */
+  if (delete_vertices) {
+    IGRAPH_CHECK(igraph_delete_vertices(res, igraph_vss_vector(&delete)));
+  }
+
+  igraph_vector_destroy(&delete);
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+void igraph_i_simplify_free(igraph_vector_ptr_t *p);
+
+void igraph_i_simplify_free(igraph_vector_ptr_t *p) {
+  long int i, n=igraph_vector_ptr_size(p);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *v=VECTOR(*p)[i];
+    if (v) { igraph_vector_destroy(v); }
+  }
+  igraph_vector_ptr_destroy(p);
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_simplify
+ * \brief Removes loop and/or multiple edges from the graph.
+ * 
+ * \param graph The graph object.
+ * \param multiple Logical, if true, multiple edges will be removed. 
+ * \param loops Logical, if true, loops (self edges) will be removed.
+ * \param edge_comb What to do with the edge attributes. See the igraph 
+ *        manual section about attributes for details.
+ * \return Error code:
+ *    \c IGRAPH_ENOMEM if we are out of memory.
+ *
+ * Time complexity: O(|V|+|E|).
+ * 
+ * \example examples/simple/igraph_simplify.c
+ */
+
+int igraph_simplify(igraph_t *graph, igraph_bool_t multiple, 
+		    igraph_bool_t loops, 
+		    const igraph_attribute_combination_t *edge_comb) {
+
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  long int edge;
+  igraph_bool_t attr=edge_comb && igraph_has_attribute_table();
+  long int from, to, pfrom=-1, pto=-2;
+  igraph_t res;
+  igraph_es_t es;
+  igraph_eit_t eit;
+  igraph_vector_t mergeinto;
+  long int actedge;
+
+  if (!multiple && !loops)
+    /* nothing to do */
+    return IGRAPH_SUCCESS;
+
+  if (!multiple) {
+    /* removing loop edges only, this is simple. No need to combine anything
+     * and the whole process can be done in-place */
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
+    IGRAPH_FINALLY(igraph_es_destroy, &es);
+    IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+    IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+    while (!IGRAPH_EIT_END(eit)) {
+      edge=IGRAPH_EIT_GET(eit);
+      from=IGRAPH_FROM(graph, edge);
+      to=IGRAPH_TO(graph, edge);
+      if (from == to)
+        IGRAPH_CHECK(igraph_vector_push_back(&edges, edge));
+      IGRAPH_EIT_NEXT(eit);
+    }
+
+    igraph_eit_destroy(&eit);
+    igraph_es_destroy(&es);
+    IGRAPH_FINALLY_CLEAN(2);
+
+    if (igraph_vector_size(&edges) > 0) {
+      IGRAPH_CHECK(igraph_delete_edges(graph, igraph_ess_vector(&edges)));
+    }
+
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    return IGRAPH_SUCCESS;
+  }
+
+  if (attr) {    
+    IGRAPH_VECTOR_INIT_FINALLY(&mergeinto, no_of_edges);
+  }
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+
+  IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_FROM));
+  IGRAPH_FINALLY(igraph_es_destroy, &es);
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+  for (actedge=-1; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
+    edge=IGRAPH_EIT_GET(eit);
+    from=IGRAPH_FROM(graph, edge);
+    to=IGRAPH_TO(graph, edge);
+    
+    if (loops && from==to) {
+      /* Loop edge to be removed */
+      if (attr) { VECTOR(mergeinto)[edge] = -1; }
+    } else if (multiple && from==pfrom && to==pto) {
+      /* Multiple edge to be contracted */
+      if (attr) {
+	VECTOR(mergeinto)[edge]=actedge;
+      }
+    } else {
+      /* Edge to be kept */
+      igraph_vector_push_back(&edges, from);
+      igraph_vector_push_back(&edges, to);
+      if (attr) { 
+	actedge++;
+	VECTOR(mergeinto)[edge]=actedge;
+      }
+    }
+    pfrom=from; pto=to;
+  }
+
+  igraph_eit_destroy(&eit);
+  igraph_es_destroy(&es);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  IGRAPH_CHECK(igraph_create(&res, &edges, (igraph_integer_t) no_of_nodes, 
+			     igraph_is_directed(graph)));
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  IGRAPH_FINALLY(igraph_destroy, &res);
+
+  IGRAPH_I_ATTRIBUTE_DESTROY(&res);
+  IGRAPH_I_ATTRIBUTE_COPY(&res, graph, /*graph=*/ 1, 
+			  /*vertex=*/ 1, /*edge=*/ 0);
+
+  if (attr) {
+    igraph_fixed_vectorlist_t vl;
+    IGRAPH_CHECK(igraph_fixed_vectorlist_convert(&vl, &mergeinto, 
+						 actedge+1));
+    IGRAPH_FINALLY(igraph_fixed_vectorlist_destroy, &vl);
+
+    IGRAPH_CHECK(igraph_i_attribute_combine_edges(graph, &res, &vl.v, 
+						  edge_comb));
+    
+    igraph_fixed_vectorlist_destroy(&vl);
+    igraph_vector_destroy(&mergeinto);
+    IGRAPH_FINALLY_CLEAN(2);
+  }
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_destroy(graph);
+  *graph=res;
+
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_reciprocity
+ * \brief Calculates the reciprocity of a directed graph.
+ * 
+ * </para><para>
+ * The measure of reciprocity defines the proportion 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. In adjacency matrix notation: 
+ * <code>sum(i, j, (A.*A')ij) / sum(i, j, Aij)</code>, where
+ * <code>A.*A'</code> is the element-wise product of matrix
+ * <code>A</code> and its transpose. This measure is
+ * calculated if the \p mode argument is \c
+ * IGRAPH_RECIPROCITY_DEFAULT.
+ * 
+ * </para><para>
+ * 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) disconnected, (2)
+ * non-reciprocally 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 \p mode is \c
+ * IGRAPH_RECIPROCITY_RATIO.
+ *
+ * \param graph The graph object.
+ * \param res Pointer to an \c igraph_real_t which will contain the result.
+ * \param ignore_loops Whether to ignore loop edges.
+ * \param mode Type of reciprocity to calculate, possible values are 
+ *    \c IGRAPH_RECIPROCITY_DEFAULT and \c IGRAPH_RECIPROCITY_RATIO,
+ *    please see their description above.
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: graph has no edges
+ *         \c IGRAPH_ENOMEM: not enough memory for
+ *         temporary data. 
+ * 
+ * Time complexity: O(|V|+|E|), |V| is the number of vertices, 
+ * |E| is the number of edges.
+ * 
+ * \example examples/simple/igraph_reciprocity.c
+ */
+
+int igraph_reciprocity(const igraph_t *graph, igraph_real_t *res, 
+		       igraph_bool_t ignore_loops, 
+		       igraph_reciprocity_t mode) {
+
+  igraph_integer_t nonrec=0, rec=0, loops=0;
+  igraph_vector_t inneis, outneis;
+  long int i;
+  long int no_of_nodes=igraph_vcount(graph);
+
+  if (mode != IGRAPH_RECIPROCITY_DEFAULT && 
+      mode != IGRAPH_RECIPROCITY_RATIO) { 
+    IGRAPH_ERROR("Invalid reciprocity type", IGRAPH_EINVAL);
+  }
+
+  /* THIS IS AN EXIT HERE !!!!!!!!!!!!!! */
+  if (!igraph_is_directed(graph)) {
+    *res=1.0;
+    return 0;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&inneis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&outneis, 0);
+
+  for (i=0; i<no_of_nodes; i++) {
+    long int ip, op;
+    igraph_neighbors(graph, &inneis, (igraph_integer_t) i, IGRAPH_IN);
+    igraph_neighbors(graph, &outneis, (igraph_integer_t) i, IGRAPH_OUT);
+    
+    ip=op=0;
+    while (ip < igraph_vector_size(&inneis) &&
+	   op < igraph_vector_size(&outneis)) {
+      if (VECTOR(inneis)[ip] < VECTOR(outneis)[op]) {
+	nonrec += 1;
+	ip++;
+      } else if (VECTOR(inneis)[ip] > VECTOR(outneis)[op]) {
+	nonrec += 1;
+	op++;
+      } else { 
+
+	/* loop edge? */
+	if (VECTOR(inneis)[ip]==i) {
+	  loops += 1;
+	  if (!ignore_loops) { rec += 1; }
+	} else { 
+	  rec += 1;
+	}
+
+	ip++;
+	op++;
+      }
+    }
+    nonrec += (igraph_vector_size(&inneis)-ip) + 
+      (igraph_vector_size(&outneis)-op);
+  }
+
+  if (mode==IGRAPH_RECIPROCITY_DEFAULT) {
+    if (ignore_loops) {
+      *res= (igraph_real_t) rec/(igraph_ecount(graph)-loops);
+    } else {
+      *res= (igraph_real_t) rec/(igraph_ecount(graph));
+    }
+  } else if (mode==IGRAPH_RECIPROCITY_RATIO) {
+    *res= (igraph_real_t) rec/(rec+nonrec);
+  }
+  
+  igraph_vector_destroy(&inneis);
+  igraph_vector_destroy(&outneis);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_constraint
+ * \brief Burt's constraint scores.
+ * 
+ * </para><para>
+ * This function calculates Burt's constraint scores for the given
+ * vertices, also known as structural holes.
+ * 
+ * </para><para>
+ * Burt's constraint is higher if ego has less, or mutually stronger
+ * related (i.e. more redundant) contacts. Burt's measure of
+ * constraint, C[i], of vertex i's ego network V[i], is defined for
+ * directed and valued graphs,
+ * <blockquote><para>
+ * C[i] = sum( sum( (p[i,q] p[q,j])^2, q in V[i], q != i,j ), j in
+ * V[], j != i)
+ * </para></blockquote>
+ * for a graph of order (ie. number of vertices) N, where proportional
+ * tie strengths are defined as 
+ * <blockquote><para>
+ * p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),
+ * </para></blockquote>
+ * a[i,j] are elements of A and
+ * the latter being the graph adjacency matrix. For isolated vertices,
+ * constraint is undefined. 
+ * 
+ * </para><para>
+ * Burt, R.S. (2004). Structural holes and good ideas. American
+ * Journal of Sociology 110, 349-399.
+ *
+ * </para><para>
+ * The first R version of this function was contributed by Jeroen
+ * Bruggeman. 
+ * \param graph A graph object.
+ * \param res Pointer to an initialized vector, the result will be
+ *        stored here. The vector will be resized to have the
+ *        appropriate size for holding the result.
+ * \param vids Vertex selector containing the vertices for which the
+ *        constraint should be calculated.
+ * \param weights Vector giving the weights of the edges. If it is
+ *        \c NULL then each edge is supposed to have the same weight.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+E|+n*d^2), n is the number of vertices for
+ * which the constraint is calculated and d is the average degree, |V|
+ * is the number of vertices, |E| the number of edges in the
+ * graph. If the weights argument is \c NULL then the time complexity
+ * is O(|V|+n*d^2).
+ */
+
+int igraph_constraint(const igraph_t *graph, igraph_vector_t *res,
+		      igraph_vs_t vids, const igraph_vector_t *weights) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vit_t vit;
+  long int nodes_to_calc;
+  long int a, b, c, i, j, q;
+  igraph_integer_t edge, from, to, edge2, from2, to2;
+  
+  igraph_vector_t contrib;
+  igraph_vector_t degree;
+  igraph_vector_t ineis_in, ineis_out, jneis_in, jneis_out;
+
+  if (weights != 0 && igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid length of weight vector", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&contrib, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&ineis_in, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&ineis_out, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&jneis_in, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&jneis_out, 0);
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+
+  if (weights==0) {
+    IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(),
+			       IGRAPH_ALL, IGRAPH_NO_LOOPS));
+  } else {
+    for (a=0; a<no_of_edges; a++) {
+      igraph_edge(graph, (igraph_integer_t) a, &from, &to);
+      if (from != to) {
+	VECTOR(degree)[(long int) from] += VECTOR(*weights)[a];
+	VECTOR(degree)[(long int) to  ] += VECTOR(*weights)[a];
+      }
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  igraph_vector_null(res);
+  
+  for (a=0; a<nodes_to_calc; a++, IGRAPH_VIT_NEXT(vit)) {
+    i=IGRAPH_VIT_GET(vit);
+    
+    /* get neighbors of i */
+    IGRAPH_CHECK(igraph_incident(graph, &ineis_in, (igraph_integer_t) i,
+				 IGRAPH_IN));
+    IGRAPH_CHECK(igraph_incident(graph, &ineis_out, (igraph_integer_t) i,
+				 IGRAPH_OUT));
+
+    /* NaN for isolates */
+    if (igraph_vector_size(&ineis_in) == 0 &&
+	igraph_vector_size(&ineis_out) == 0) {
+      VECTOR(*res)[a] = IGRAPH_NAN;
+    }
+
+    /* zero their contribution */
+    for (b=0; b<igraph_vector_size(&ineis_in); b++) {
+      edge=(igraph_integer_t) VECTOR(ineis_in)[b];
+      igraph_edge(graph, edge, &from, &to);
+      if (to==i) { to=from; }
+      j=to;
+      VECTOR(contrib)[j]=0.0;
+    }
+    for (b=0; b<igraph_vector_size(&ineis_out); b++) {
+      edge=(igraph_integer_t) VECTOR(ineis_out)[b];
+      igraph_edge(graph, edge, &from, &to);
+      if (to==i) { to=from; }
+      j=to;
+      VECTOR(contrib)[j]=0.0;
+    }
+
+    /* add the direct contributions, in-neighbors and out-neighbors */
+    for (b=0; b<igraph_vector_size(&ineis_in); b++) {
+      edge=(igraph_integer_t) VECTOR(ineis_in)[b];
+      igraph_edge(graph, edge, &from, &to);
+      if (to==i) { to=from; }
+      j=to;
+      if (i != j) {		/* excluding loops */
+	if (weights) {
+	  VECTOR(contrib)[j] += 
+	    VECTOR(*weights)[(long int)edge]/VECTOR(degree)[i];
+	} else {
+	  VECTOR(contrib)[j] += 1.0/VECTOR(degree)[i];
+	}
+      }
+    }
+    if (igraph_is_directed(graph)) {
+      for (b=0; b<igraph_vector_size(&ineis_out); b++) {
+	edge=(igraph_integer_t) VECTOR(ineis_out)[b];
+	igraph_edge(graph, edge, &from, &to);
+	if (to==i) { to=from; }
+	j=to;
+	if (i != j) {
+	  if (weights) {
+	    VECTOR(contrib)[j] += 
+	      VECTOR(*weights)[(long int)edge]/VECTOR(degree)[i];
+	  } else {
+	    VECTOR(contrib)[j] += 1.0/VECTOR(degree)[i];
+	  }
+	}
+      }
+    }
+
+    /* 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];
+      igraph_edge(graph, edge, &from, &to);
+      if (to==i) { to=from; }
+      j=to;
+      if (i == j) { continue; }
+      IGRAPH_CHECK(igraph_incident(graph, &jneis_in, (igraph_integer_t) j,
+				   IGRAPH_IN));
+      IGRAPH_CHECK(igraph_incident(graph, &jneis_out, (igraph_integer_t) j,
+				   IGRAPH_OUT));
+      for (c=0; c<igraph_vector_size(&jneis_in); c++) {
+	edge2=(igraph_integer_t) VECTOR(jneis_in)[c];
+	igraph_edge(graph, edge2, &from2, &to2);
+	if (to2==j) { to2=from2; }
+	q=to2;
+	if (j != q) {
+	  if (weights) {
+	    VECTOR(contrib)[q] += 
+	      VECTOR(*weights)[(long int)edge]*
+	      VECTOR(*weights)[(long int)edge2]/
+	      VECTOR(degree)[i]/VECTOR(degree)[j];
+	  } else {
+	    VECTOR(contrib)[q] += 1/VECTOR(degree)[i]/VECTOR(degree)[j];
+	  }
+	}
+      }
+      if (igraph_is_directed(graph)) {
+	for (c=0; c<igraph_vector_size(&jneis_out); c++) {
+	  edge2=(igraph_integer_t) VECTOR(jneis_out)[c];
+	  igraph_edge(graph, edge2, &from2, &to2);
+	  if (to2==j) { to2=from2; }
+	  q=to2;
+	  if (j != q) {
+	    if (weights) {
+	      VECTOR(contrib)[q] += 
+		VECTOR(*weights)[(long int)edge]*
+		VECTOR(*weights)[(long int)edge2]/
+		VECTOR(degree)[i]/VECTOR(degree)[j];
+	    } else {
+	      VECTOR(contrib)[q] += 1/VECTOR(degree)[i]/VECTOR(degree)[j];
+	    }
+	  }
+	}
+      }
+    }
+    if (igraph_is_directed(graph)) {
+      for (b=0; b<igraph_vector_size(&ineis_out); b++) {
+	edge=(igraph_integer_t) VECTOR(ineis_out)[b];
+	igraph_edge(graph, edge, &from, &to);
+	if (to==i) { to=from; }
+	j=to;
+	if (i == j) { continue; }
+	IGRAPH_CHECK(igraph_incident(graph, &jneis_in, (igraph_integer_t) j,
+				     IGRAPH_IN));
+	IGRAPH_CHECK(igraph_incident(graph, &jneis_out, (igraph_integer_t) j,
+				     IGRAPH_OUT));
+	for (c=0; c<igraph_vector_size(&jneis_in); c++) {
+	  edge2=(igraph_integer_t) VECTOR(jneis_in)[c];
+	  igraph_edge(graph, edge2, &from2, &to2);
+	  if (to2==j) { to2=from2; }
+	  q=to2;
+	  if (j != q) {
+	    if (weights) {
+	      VECTOR(contrib)[q] += 
+		VECTOR(*weights)[(long int)edge]*
+		VECTOR(*weights)[(long int)edge2]/
+		VECTOR(degree)[i]/VECTOR(degree)[j];
+	    } else {
+	      VECTOR(contrib)[q] += 1/VECTOR(degree)[i]/VECTOR(degree)[j];
+	    }
+	  }
+	}
+	for (c=0; c<igraph_vector_size(&jneis_out); c++) {
+	  edge2=(igraph_integer_t) VECTOR(jneis_out)[c];
+	  igraph_edge(graph, edge2, &from2, &to2);
+	  if (to2==j) { to2=from2; }
+	  q=to2;
+	  if (j != q) {
+	    if (weights) {
+	      VECTOR(contrib)[q] += 
+		VECTOR(*weights)[(long int)edge]*
+		VECTOR(*weights)[(long int)edge2]/
+		VECTOR(degree)[i]/VECTOR(degree)[j];
+	    } else {
+	      VECTOR(contrib)[q] += 1/VECTOR(degree)[i]/VECTOR(degree)[j];
+	    }
+	  }
+	}
+      }
+    }
+    
+    /* squared sum of the contributions */
+    for (b=0; b<igraph_vector_size(&ineis_in); b++) {
+      edge=(igraph_integer_t) VECTOR(ineis_in)[b];
+      igraph_edge(graph, edge, &from, &to);
+      if (to==i) { to=from; }
+      j=to;
+      if (i == j) { continue; }
+      VECTOR(*res)[a] += VECTOR(contrib)[j] * VECTOR(contrib)[j];
+      VECTOR(contrib)[j]=0.0;
+    }
+    if (igraph_is_directed(graph)) {
+      for (b=0; b<igraph_vector_size(&ineis_out); b++) {
+	edge=(igraph_integer_t) VECTOR(ineis_out)[b];
+	igraph_edge(graph, edge, &from, &to);
+	if (to==i) { to=from; }
+	j=to;
+	if (i == j) { continue; }
+	VECTOR(*res)[a] += VECTOR(contrib)[j] * VECTOR(contrib)[j];
+	VECTOR(contrib)[j]=0.0;
+      }
+    }
+  }
+
+  igraph_vit_destroy(&vit);
+  igraph_vector_destroy(&jneis_out);
+  igraph_vector_destroy(&jneis_in);
+  igraph_vector_destroy(&ineis_out);
+  igraph_vector_destroy(&ineis_in);
+  igraph_vector_destroy(&degree);
+  igraph_vector_destroy(&contrib);
+  IGRAPH_FINALLY_CLEAN(7);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_maxdegree
+ * \brief Calculate the maximum degree in a graph (or set of vertices).
+ * 
+ * </para><para>
+ * The largest in-, out- or total degree of the specified vertices is
+ * calculated.
+ * \param graph The input graph.
+ * \param res Pointer to an integer (\c igraph_integer_t), the result
+ *        will be stored here.
+ * \param vids Vector giving the vertex IDs for which the maximum degree will
+ *        be calculated.
+ * \param mode Defines the type of the degree.
+ *        \c IGRAPH_OUT, out-degree,
+ *        \c IGRAPH_IN, in-degree,
+ *        \c IGRAPH_ALL, total degree (sum of the
+ *        in- and out-degree). 
+ *        This parameter is ignored for undirected graphs. 
+ * \param loops Boolean, gives whether the self-loops should be
+ *        counted.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ *         \c IGRAPH_EINVMODE: invalid mode argument.
+ *
+ * Time complexity: O(v) if
+ * loops is 
+ * TRUE, and
+ * O(v*d)
+ * otherwise. v is the number
+ * vertices for which the degree will be calculated, and
+ * d is their (average) degree. 
+ */
+
+int igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res,
+		     igraph_vs_t vids, igraph_neimode_t mode, 
+		     igraph_bool_t loops) {
+
+  igraph_vector_t tmp;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  
+  igraph_degree(graph, &tmp, vids, mode, loops);  
+  *res=(igraph_integer_t) igraph_vector_max(&tmp);
+  
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_density
+ * Calculate the density of a graph.
+ * 
+ * </para><para>The density of a graph is simply the ratio number of
+ * edges and the number of possible edges. Note that density is
+ * ill-defined for graphs with multiple and/or loop edges, so consider
+ * calling \ref igraph_simplify() on the graph if you know that it
+ * contains multiple or loop edges. 
+ * \param graph The input graph object.
+ * \param res Pointer to a real number, the result will be stored
+ *   here.
+ * \param loops Logical constant, whether to include loops in the
+ *   calculation. If this constant is TRUE then
+ *   loop edges are thought to be possible in the graph (this does not
+ *   necessarily mean that the graph really contains any loops). If
+ *   this is FALSE then the result is only correct if the graph does not
+ *   contain loops.
+ * \return Error code.
+ *
+ * Time complexity: O(1).
+ */
+
+int igraph_density(const igraph_t *graph, igraph_real_t *res, 
+		   igraph_bool_t loops) {
+
+  igraph_integer_t no_of_nodes=igraph_vcount(graph);
+  igraph_real_t no_of_edges=igraph_ecount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+
+  if (no_of_nodes == 0) {
+    *res = IGRAPH_NAN;
+    return 0;
+  }
+
+  if (!loops) {
+    if (no_of_nodes == 1) {
+      *res = IGRAPH_NAN;
+    } else if (directed) {
+      *res = no_of_edges / no_of_nodes / (no_of_nodes-1);
+    } else {
+      *res = no_of_edges / no_of_nodes * 2.0 / (no_of_nodes-1);
+    }
+  } else {
+    if (directed) {
+      *res = no_of_edges / no_of_nodes / no_of_nodes;
+    } else {
+      *res = no_of_edges / no_of_nodes * 2.0 / (no_of_nodes+1);
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_neighborhood_size
+ * \brief Calculates the size of the neighborhood of a given vertex.
+ * 
+ * The neighborhood of a given order of a vertex includes all vertices
+ * which are closer to the vertex than the order. Ie. order 0 is
+ * always the vertex itself, order 1 is the vertex plus its immediate
+ * neighbors, order 2 is order 1 plus the immediate neighbors of the
+ * vertices in order 1, etc. 
+ * 
+ * </para><para> This function calculates the size of the neighborhood
+ * of the given order for the given vertices. 
+ * \param graph The input graph.
+ * \param res Pointer to an initialized vector, the result will be
+ *    stored here. It will be resized as needed.
+ * \param vids The vertices for which the calculation is performed.
+ * \param order Integer giving the order of the neighborhood.
+ * \param mode Specifies how to use the direction of the edges if a
+ *   directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
+ *   edges are followed, so all vertices reachable from the source
+ *   vertex in at most \c order steps are counted. For \c IGRAPH_IN
+ *   all vertices from which the source vertex is reachable in at most
+ *   \c order steps are counted. \c IGRAPH_ALL ignores the direction
+ *   of the edges. This argument is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_neighborhood() for calculating the actual neighborhood, 
+ * \ref igraph_neighborhood_graphs() for creating separate graphs from
+ * the neighborhoods.
+ * 
+ * Time complexity: O(n*d*o), where n is the number vertices for which
+ * the calculation is performed, d is the average degree, o is the order.
+ */ 
+
+int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
+			     igraph_vs_t vids, igraph_integer_t order,
+			     igraph_neimode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q;
+  igraph_vit_t vit;
+  long int i, j;
+  long int *added;
+  igraph_vector_t neis;
+  
+  if (order < 0) {
+    IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
+  }
+
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
+  
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    long int node=IGRAPH_VIT_GET(vit);
+    long int size=1;
+    added[node]=i+1;
+    igraph_dqueue_clear(&q);
+    if (order > 0) {
+      igraph_dqueue_push(&q, node);
+      igraph_dqueue_push(&q, 0);
+    }
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      long int n;
+      igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
+      n=igraph_vector_size(&neis);
+
+      if (actdist<order-1) {
+	/* we add them to the q */
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (added[nei] != i+1) {
+	    added[nei]=i+1;
+	    IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
+	    IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+	    size++;
+	  }
+	}
+      } else {
+	/* we just count them, but don't add them */
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (added[nei] != i+1) {
+	    added[nei]=i+1;
+	    size++;
+	  }
+	}
+      }
+
+    } /* while q not empty */
+
+    VECTOR(*res)[i]=size;
+  } /* for VIT, i */
+
+  igraph_vector_destroy(&neis);
+  igraph_vit_destroy(&vit);
+  igraph_dqueue_destroy(&q);
+  igraph_Free(added);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/** 
+ * \function igraph_neighborhood
+ * Calculate the neighborhood of vertices.
+ * 
+ * The neighborhood of a given order of a vertex includes all vertices
+ * which are closer to the vertex than the order. Ie. order 0 is
+ * always the vertex itself, order 1 is the vertex plus its immediate
+ * neighbors, order 2 is order 1 plus the immediate neighbors of the
+ * vertices in order 1, etc. 
+ * 
+ * </para><para> This function calculates the vertices within the
+ * neighborhood of the specified vertices.
+ * \param graph The input graph.
+ * \param res An initialized pointer vector. Note that the objects
+ *    (pointers) in the vector will \em not be freed, but the pointer
+ *    vector will be resized as needed. The result of the calculation
+ *    will be stored here in \c vector_t objects.
+ * \param vids The vertices for which the calculation is performed.
+ * \param order Integer giving the order of the neighborhood.
+ * \param mode Specifies how to use the direction of the edges if a
+ *   directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
+ *   edges are followed, so all vertices reachable from the source
+ *   vertex in at most \c order steps are included. For \c IGRAPH_IN
+ *   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.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_neighborhood_size() to calculate the size of the
+ * neighborhood, \ref igraph_neighborhood_graphs() for creating
+ * graphs from the neighborhoods.
+ * 
+ * Time complexity: O(n*d*o), n is the number of vertices for which
+ * the calculation is performed, d is the average degree, o is the
+ * order.
+ */
+
+int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
+			igraph_vs_t vids, igraph_integer_t order,
+			igraph_neimode_t mode) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q;
+  igraph_vit_t vit;
+  long int i, j;
+  long int *added;
+  igraph_vector_t neis;
+  igraph_vector_t tmp;
+  igraph_vector_t *newv;
+
+  if (order < 0) {
+    IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
+  }
+  
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  IGRAPH_CHECK(igraph_vector_ptr_resize(res, IGRAPH_VIT_SIZE(vit)));
+  
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    long int node=IGRAPH_VIT_GET(vit);
+    added[node]=i+1;
+    igraph_vector_clear(&tmp);
+    IGRAPH_CHECK(igraph_vector_push_back(&tmp, node));
+    if (order > 0) {
+      igraph_dqueue_push(&q, node);
+      igraph_dqueue_push(&q, 0);
+    }
+
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      long int n;
+      igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
+      n=igraph_vector_size(&neis);
+      
+      if (actdist<order-1) {
+	/* we add them to the q */
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (added[nei] != i+1) {
+	    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));
+	  }
+	}
+      } else {
+	/* we just count them but don't add them to q */
+	for (j=0; j<n; j++) {
+	  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));
+	  }
+	}
+      }
+
+    } /* while q not empty */
+
+    newv=igraph_Calloc(1, igraph_vector_t);
+    if (newv==0) {
+      IGRAPH_ERROR("Cannot calculate neighborhood", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, newv);
+    IGRAPH_CHECK(igraph_vector_copy(newv, &tmp));
+    VECTOR(*res)[i]=newv;
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_destroy(&tmp);
+  igraph_vector_destroy(&neis);
+  igraph_vit_destroy(&vit);
+  igraph_dqueue_destroy(&q);
+  igraph_Free(added);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \function igraph_neighborhood_graphs
+ * Create graphs from the neighborhood(s) of some vertex/vertices.
+ * 
+ * The neighborhood of a given order of a vertex includes all vertices
+ * which are closer to the vertex than the order. Ie. order 0 is
+ * always the vertex itself, order 1 is the vertex plus its immediate
+ * neighbors, order 2 is order 1 plus the immediate neighbors of the
+ * vertices in order 1, etc. 
+ * 
+ * </para><para> This function finds every vertex in the neighborhood
+ * of a given parameter vertex and creates a graph from these
+ * vertices. 
+ * 
+ * </para><para> The first version of this function was written by 
+ * Vincent Matossian, thanks Vincent.
+ * \param graph The input graph.
+ * \param res Pointer to a pointer vector, the result will be stored
+ *   here, ie. \c res will contain pointers to \c igraph_t
+ *   objects. It will be resized if needed but note that the
+ *   objects in the pointer vector will not be freed.
+ * \param vids The vertices for which the calculation is performed.
+ * \param order Integer giving the order of the neighborhood.
+ * \param mode Specifies how to use the direction of the edges if a
+ *   directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
+ *   edges are followed, so all vertices reachable from the source
+ *   vertex in at most \c order steps are counted. For \c IGRAPH_IN
+ *   all vertices from which the source vertex is reachable in at most
+ *   \c order steps are counted. \c IGRAPH_ALL ignores the direction
+ *   of the edges. This argument is ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_neighborhood_size() for calculating the neighborhood
+ * sizes only, \ref igraph_neighborhood() for calculating the
+ * neighborhoods (but not creating graphs).
+ * 
+ * Time complexity: O(n*(|V|+|E|)), where n is the number vertices for
+ * which the calculation is performed, |V| and |E| are the number of
+ * vertices and edges in the original input graph.
+ */
+
+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) {
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q;
+  igraph_vit_t vit;
+  long int i, j;
+  long int *added;
+  igraph_vector_t neis;
+  igraph_vector_t tmp;
+  igraph_t *newg;
+  
+  if (order < 0) {
+    IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
+  }
+  
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+  IGRAPH_CHECK(igraph_vector_ptr_resize(res, IGRAPH_VIT_SIZE(vit)));
+  
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    long int node=IGRAPH_VIT_GET(vit);
+    added[node]=i+1;
+    igraph_vector_clear(&tmp);
+    IGRAPH_CHECK(igraph_vector_push_back(&tmp, node));
+    if (order > 0) {
+      igraph_dqueue_push(&q, node);
+      igraph_dqueue_push(&q, 0);
+    }
+
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      long int n;
+      igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
+      n=igraph_vector_size(&neis);
+      
+      if (actdist<order-1) {
+	/* we add them to the q */
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (added[nei] != i+1) {
+	    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));
+	  }
+	}
+      } else {
+	/* we just count them but don't add them to q */
+	for (j=0; j<n; j++) {
+	  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));
+	  }
+	}
+      }
+
+    } /* while q not empty */
+
+    newg=igraph_Calloc(1, igraph_t);
+    if (newg==0) {
+      IGRAPH_ERROR("Cannot create neighborhood graph", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, newg);
+    if (igraph_vector_size(&tmp) < no_of_nodes) {
+      IGRAPH_CHECK(igraph_induced_subgraph(graph, newg, 
+					   igraph_vss_vector(&tmp), 
+					   IGRAPH_SUBGRAPH_AUTO));
+    } else {
+      IGRAPH_CHECK(igraph_copy(newg, graph));
+    }
+    VECTOR(*res)[i]=newg;
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_destroy(&tmp);
+  igraph_vector_destroy(&neis);
+  igraph_vit_destroy(&vit);
+  igraph_dqueue_destroy(&q);
+  igraph_Free(added);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \function igraph_topological_sorting
+ * \brief Calculate a possible topological sorting of the graph.
+ *
+ * </para><para>
+ * 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.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a vector, the result will be stored here.
+ *   It will be resized if needed.
+ * \param mode Specifies how to use the direction of the edges.
+ *   For \c IGRAPH_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 \c IGRAPH_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 Error code.
+ * 
+ * Time complexity: O(|V|+|E|), where |V| and |E| are the number of
+ * vertices and edges in the original input graph.
+ *
+ * \sa \ref igraph_is_dag() if you are only interested in whether a given
+ *     graph is a DAG or not, or \ref igraph_feedback_arc_set() to find a
+ *     set of edges whose removal makes the graph a DAG.
+ * 
+ * \example examples/simple/igraph_topological_sorting.c
+ */
+int igraph_topological_sorting(const igraph_t* graph, igraph_vector_t *res,
+			       igraph_neimode_t mode) {
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t degrees, neis;
+  igraph_dqueue_t sources;
+  igraph_neimode_t deg_mode;
+  long int node, i, j;
+
+  if (mode == IGRAPH_ALL || !igraph_is_directed(graph)) {
+    IGRAPH_ERROR("topological sorting does not make sense for undirected graphs", IGRAPH_EINVAL);
+  } else if (mode == IGRAPH_OUT) {
+    deg_mode = IGRAPH_IN;
+  } else if (mode == IGRAPH_IN) {
+    deg_mode = IGRAPH_OUT;
+  } else {
+    IGRAPH_ERROR("invalid mode", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&degrees, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_dqueue_init(&sources, 0));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &sources);
+  IGRAPH_CHECK(igraph_degree(graph, &degrees, igraph_vss_all(), deg_mode, 0));
+
+  igraph_vector_clear(res);
+
+  /* Do we have nodes with no incoming vertices? */
+  for (i=0; i<no_of_nodes; i++) {
+    if (VECTOR(degrees)[i] == 0)
+      IGRAPH_CHECK(igraph_dqueue_push(&sources, i));
+  }
+
+  /* Take all nodes with no incoming vertices and remove them */
+  while (!igraph_dqueue_empty(&sources)) {
+    igraph_real_t tmp=igraph_dqueue_pop(&sources); node=(long) tmp;
+    /* Add the node to the result vector */
+    igraph_vector_push_back(res, node);
+    /* Exclude the node from further source searches */
+    VECTOR(degrees)[node]=-1;
+    /* Get the neighbors and decrease their degrees by one */
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, mode));
+    j=igraph_vector_size(&neis);
+    for (i=0; i<j; i++) {
+      VECTOR(degrees)[(long)VECTOR(neis)[i]]--;
+      if (VECTOR(degrees)[(long)VECTOR(neis)[i]] == 0)
+	IGRAPH_CHECK(igraph_dqueue_push(&sources, VECTOR(neis)[i]));
+    }
+  }
+
+  if (igraph_vector_size(res)<no_of_nodes)
+    IGRAPH_WARNING("graph contains a cycle, partial result is returned");
+
+  igraph_vector_destroy(&degrees);
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&sources);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \function igraph_is_dag
+ * Checks whether a graph is a directed acyclic graph (DAG) or not.
+ *
+ * </para><para>
+ * A directed acyclic graph (DAG) is a directed graph with no cycles.
+ *
+ * \param graph The input graph.
+ * \param res Pointer to a boolean constant, the result
+ *     is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), where |V| and |E| are the number of
+ * vertices and edges in the original input graph.
+ *
+ * \sa \ref igraph_topological_sorting() to get a possible topological
+ *     sorting of a DAG.
+ */
+int igraph_is_dag(const igraph_t* graph, igraph_bool_t *res) {
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t degrees, neis;
+  igraph_dqueue_t sources;
+  long int node, i, j, nei, vertices_left;
+
+  if (!igraph_is_directed(graph)) {
+    *res = 0;
+    return IGRAPH_SUCCESS;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&degrees, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_dqueue_init(&sources, 0));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &sources);
+  IGRAPH_CHECK(igraph_degree(graph, &degrees, igraph_vss_all(), IGRAPH_OUT, 1));
+
+  vertices_left = no_of_nodes;
+
+  /* Do we have nodes with no incoming edges? */
+  for (i=0; i<no_of_nodes; i++) {
+    if (VECTOR(degrees)[i] == 0)
+      IGRAPH_CHECK(igraph_dqueue_push(&sources, i));
+  }
+
+  /* Take all nodes with no incoming edges and remove them */
+  while (!igraph_dqueue_empty(&sources)) {
+    igraph_real_t tmp=igraph_dqueue_pop(&sources); node=(long) tmp;
+    /* Exclude the node from further source searches */
+    VECTOR(degrees)[node]=-1;
+    vertices_left--;
+    /* Get the neighbors and decrease their degrees by one */
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
+				  IGRAPH_IN));
+    j=igraph_vector_size(&neis);
+    for (i=0; i<j; i++) {
+      nei = (long)VECTOR(neis)[i];
+      if (nei == node)
+        continue;
+      VECTOR(degrees)[nei]--;
+      if (VECTOR(degrees)[nei] == 0)
+        IGRAPH_CHECK(igraph_dqueue_push(&sources, nei));
+    }
+  }
+
+  *res = (vertices_left == 0);
+  if (vertices_left < 0) {
+    IGRAPH_WARNING("vertices_left < 0 in igraph_is_dag, possible bug");
+  }
+
+  igraph_vector_destroy(&degrees);
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&sources);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_is_simple
+ * \brief Decides whether the input graph is a simple graph.
+ * 
+ * </para><para>
+ * A graph is a simple graph if it does not contain loop edges and 
+ * multiple edges.
+ * 
+ * \param graph The input graph.
+ * \param res Pointer to a boolean constant, the result
+ *     is stored here.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_is_loop() and \ref igraph_is_multiple() to
+ * find the loops and multiple edges, \ref igraph_simplify() to
+ * get rid of them, or \ref igraph_has_multiple() to decide whether
+ * there is at least one multiple edge.
+ * 
+ * Time complexity: O(|V|+|E|). 
+ */
+
+int igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) {
+  long int vc=igraph_vcount(graph);
+  long int ec=igraph_ecount(graph);
+  
+  if (vc==0 || ec==0) {
+    *res=1;
+  } else {
+    igraph_vector_t neis;
+    long int i, j, n;
+    igraph_bool_t found = 0;
+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);    
+    for (i=0; i < vc; i++) {
+      igraph_neighbors(graph, &neis, (igraph_integer_t) i, IGRAPH_OUT);
+      n=igraph_vector_size(&neis);
+      for (j=0; j < n; j++) {
+        if (VECTOR(neis)[j]==i) {
+          found=1; break;
+        }
+        if (j>0 && VECTOR(neis)[j-1]==VECTOR(neis)[j]) {
+          found=1; break;
+        }
+      }
+    }
+    *res=!found;
+    igraph_vector_destroy(&neis);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_is_loop
+ * \brief Find the loop edges in a graph.
+ * 
+ * </para><para>
+ * A loop edge is an edge from a vertex to itself.
+ * \param graph The input graph.
+ * \param res Pointer to an initialized boolean vector for storing the result, 
+ *         it will be resized as needed.
+ * \param es The edges to check, for all edges supply \ref igraph_ess_all() here.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_simplify() to get rid of loop edges.
+ *
+ * Time complexity: O(e), the number of edges to check.
+ * 
+ * \example examples/simple/igraph_is_loop.c
+ */
+
+int igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, 
+		   igraph_es_t es) {
+  igraph_eit_t eit;  
+  long int i;
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+  IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit)));
+
+  for (i=0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
+    long int e=IGRAPH_EIT_GET(eit);
+    VECTOR(*res)[i] = (IGRAPH_FROM(graph, e)==IGRAPH_TO(graph, e)) ? 1 : 0;
+  }
+  
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_has_multiple
+ * \brief Check whether the graph has at least one multiple edge.
+ * 
+ * </para><para>
+ * An edge is a multiple edge if there is another 
+ * edge with the same head and tail vertices in the graph.
+ * 
+ * \param graph The input graph.
+ * \param res Pointer to a boolean variable, the result will be stored here.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_count_multiple(), \ref igraph_is_multiple() and \ref igraph_simplify().
+ * 
+ * Time complexity: O(e*d), e is the number of edges to check and d is the 
+ * average degree (out-degree in directed graphs) of the vertices at the 
+ * tail of the edges.
+ * 
+ * \example examples/simple/igraph_has_multiple.c
+ */
+
+int igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) {
+  long int vc=igraph_vcount(graph);
+  long int ec=igraph_ecount(graph);
+  igraph_bool_t directed=igraph_is_directed(graph);
+
+  if (vc==0 || ec==0) {
+    *res=0;
+  } else {
+    igraph_vector_t neis;
+    long int i, j, n;
+    igraph_bool_t found=0;
+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);    
+    for (i=0; i < vc && !found; i++) {
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i,
+				    IGRAPH_OUT));
+      n = igraph_vector_size(&neis);
+      for (j=1; j < n; j++) {
+	      if (VECTOR(neis)[j-1] == VECTOR(neis)[j]) {
+          /* If the graph is undirected, loop edges appear twice in the neighbor
+           * list, so check the next item as well */
+          if (directed) {
+            /* Directed, so this is a real multiple edge */
+            found=1; break;
+          } else if (VECTOR(neis)[j-1] != i) {
+            /* Undirected, but not a loop edge */
+            found=1; break;
+          } else if (j < n-1 && VECTOR(neis)[j] == VECTOR(neis)[j+1]) {
+            /* Undirected, loop edge, multiple times */
+            found=1; break;
+          }
+        }
+      }
+    }
+    *res=found;
+    igraph_vector_destroy(&neis);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_is_multiple
+ * \brief Find the multiple edges in a graph.
+ * 
+ * </para><para>
+ * An edge is a multiple edge if there is another 
+ * edge with the same head and tail vertices in the graph.
+ * 
+ * </para><para>
+ * Note that this function returns true only for the second or more 
+ * appearances of the multiple edges.
+ * \param graph The input graph.
+ * \param res Pointer to a boolean vector, the result will be stored 
+ *        here. It will be resized as needed.
+ * \param es The edges to check. Supply \ref igraph_ess_all() if you want
+ *        to check all edges.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_count_multiple(), \ref igraph_has_multiple() and \ref igraph_simplify().
+ * 
+ * Time complexity: O(e*d), e is the number of edges to check and d is the 
+ * average degree (out-degree in directed graphs) of the vertices at the 
+ * tail of the edges.
+ * 
+ * \example examples/simple/igraph_is_multiple.c
+ */
+
+int igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res, 
+		       igraph_es_t es) {
+  igraph_eit_t eit;
+  long int i;
+  igraph_lazy_inclist_t inclist;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+  
+  IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit)));
+  
+  for (i=0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
+    long int e=IGRAPH_EIT_GET(eit);
+    long int from=IGRAPH_FROM(graph, e);
+    long int to=IGRAPH_TO(graph, e);
+    igraph_vector_t *neis=igraph_lazy_inclist_get(&inclist,
+						  (igraph_integer_t) from);
+    long int j, n=igraph_vector_size(neis);
+    VECTOR(*res)[i]=0;
+    for (j=0; j<n; j++) {
+      long int e2=(long int) VECTOR(*neis)[j];
+      long int to2=IGRAPH_OTHER(graph,e2,from);
+      if (to2==to && e2<e) {
+	VECTOR(*res)[i]=1;
+      }
+    }
+  }
+  
+  igraph_lazy_inclist_destroy(&inclist);
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_count_multiple
+ * \brief Count the number of appearances of the edges in a graph.
+ * 
+ * </para><para>
+ * If the graph has no multiple edges then the result vector will be 
+ * filled with ones.
+ * (An edge is a multiple edge if there is another 
+ * edge with the same head and tail vertices in the graph.)
+ * 
+ * </para><para>
+ * \param graph The input graph.
+ * \param res Pointer to a vector, the result will be stored 
+ *        here. It will be resized as needed.
+ * \param es The edges to check. Supply \ref igraph_ess_all() if you want
+ *        to check all edges.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_is_multiple() and \ref igraph_simplify().
+ * 
+ * Time complexity: O(e*d), e is the number of edges to check and d is the 
+ * average degree (out-degree in directed graphs) of the vertices at the 
+ * tail of the edges.
+ */
+
+
+int igraph_count_multiple(const igraph_t *graph, igraph_vector_t *res, igraph_es_t es) {
+  igraph_eit_t eit;
+  long int i;
+  igraph_lazy_inclist_t inclist;
+  
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit)));
+  
+  for (i=0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
+    long int e=IGRAPH_EIT_GET(eit);
+    long int from=IGRAPH_FROM(graph, e);
+    long int to=IGRAPH_TO(graph, e);
+    igraph_vector_t *neis=igraph_lazy_inclist_get(&inclist, 
+						  (igraph_integer_t) from);
+    long int j, n=igraph_vector_size(neis);
+    VECTOR(*res)[i] = 0;
+    for (j=0; j<n; j++) {
+      long int e2=(long int) VECTOR(*neis)[j];
+      long int to2=IGRAPH_OTHER(graph,e2,from);
+      if (to2==to) VECTOR(*res)[i] += 1;
+    }
+    /* for loop edges, divide the result by two */
+    if (to == from) VECTOR(*res)[i] /= 2;
+  }
+  
+  igraph_lazy_inclist_destroy(&inclist);
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+/**
+ * \function igraph_girth
+ * \brief The girth of a graph is the length of the shortest circle in it.
+ * 
+ * </para><para>
+ * The current implementation works for undirected graphs only, 
+ * directed graphs are treated as undirected graphs. Loop edges and
+ * multiple edges are ignored.
+ * </para><para>
+ * If the graph is a forest (ie. acyclic), then zero is returned.
+ * </para><para>
+ * This implementation is based on Alon Itai and Michael Rodeh:
+ * Finding a minimum circuit in a graph
+ * \emb Proceedings of the ninth annual ACM symposium on Theory of
+ * computing \eme, 1-10, 1977. The first implementation of this
+ * function was done by Keith Briggs, thanks Keith.
+ * \param graph The input graph.
+ * \param girth Pointer to an integer, if not \c NULL then the result
+ *     will be stored here.
+ * \param circle Pointer to an initialized vector, the vertex ids in
+ *     the shortest circle will be stored here. If \c NULL then it is
+ *     ignored. 
+ * \return Error code.
+ *
+ * Time complexity: O((|V|+|E|)^2), |V| is the number of vertices, |E|
+ * is the number of edges in the general case. If the graph has no
+ * circles at all then the function needs O(|V|+|E|) time to realize
+ * this and then it stops.
+ * 
+ * \example examples/simple/igraph_girth.c
+ */
+
+int igraph_girth(const igraph_t *graph, igraph_integer_t *girth, 
+		 igraph_vector_t *circle) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q;
+  igraph_lazy_adjlist_t adjlist;
+  long int mincirc=LONG_MAX, minvertex=0;
+  long int node;
+  igraph_bool_t triangle=0;
+  igraph_vector_t *neis;
+  igraph_vector_long_t level;
+  long int stoplevel=no_of_nodes+1;
+  igraph_bool_t anycircle=0;
+  long int t1=0, t2=0;
+  
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_CHECK(igraph_vector_long_init(&level, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &level);
+  
+  for (node=0; !triangle && node<no_of_nodes; node++) {
+
+    /* Are there circles in this graph at all? */
+    if (node==1 && anycircle==0) { 
+      igraph_bool_t conn;
+      IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
+      if (conn) {
+	/* No, there are none */
+	break;
+      }
+    }
+
+    anycircle=0;
+    igraph_dqueue_clear(&q);
+    igraph_vector_long_null(&level);
+    IGRAPH_CHECK(igraph_dqueue_push(&q, node));
+    VECTOR(level)[node]=1;    
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actlevel=VECTOR(level)[actnode];
+      long int i, n;
+
+      if (actlevel>=stoplevel) { break; }
+
+      neis=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) actnode);
+      n=igraph_vector_size(neis);
+      for (i=0; i<n; i++) {
+	long int nei=(long int) VECTOR(*neis)[i];
+	long int neilevel=VECTOR(level)[nei];
+	if (neilevel != 0) {
+	  if (neilevel==actlevel-1) {
+	    continue;
+	  } else {
+	    /* found circle */
+	    stoplevel=neilevel;
+	    anycircle=1;
+	    if (actlevel<mincirc) {
+	      /* Is it a minimum circle? */
+	      mincirc=actlevel+neilevel-1;
+	      minvertex=node;
+	      t1=actnode; t2=nei;
+	      if (neilevel==2) {
+		/* Is it a triangle? */
+		triangle=1;
+	      }	    
+	    }
+	    if (neilevel==actlevel) {
+	      break;
+	    }
+	  }
+	} else {
+	  igraph_dqueue_push(&q, nei);
+	  VECTOR(level)[nei]=actlevel+1;
+	}
+      }
+
+    } /* while q !empty */
+  } /* node */
+
+  if (girth) {
+    if (mincirc==LONG_MAX) {
+      *girth=mincirc=0;
+    } else {
+      *girth=(igraph_integer_t) mincirc;
+    }
+  }
+
+  /* Store the actual circle, if needed */
+  if (circle) {
+    IGRAPH_CHECK(igraph_vector_resize(circle, mincirc));
+    if (mincirc != 0) {
+      long int i, n, idx=0;
+      igraph_dqueue_clear(&q);
+      igraph_vector_long_null(&level); /* used for father pointers */
+#define FATHER(x) (VECTOR(level)[(x)])
+      IGRAPH_CHECK(igraph_dqueue_push(&q, minvertex));
+      FATHER(minvertex)=minvertex;
+      while (FATHER(t1)==0 || FATHER(t2)==0) {
+	long int actnode=(long int) igraph_dqueue_pop(&q);
+	neis=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) actnode);
+	n=igraph_vector_size(neis);
+	for (i=0; i<n; i++) {
+	  long int nei=(long int) VECTOR(*neis)[i];
+	  if (FATHER(nei) == 0) {
+	    FATHER(nei)=actnode+1;
+	    igraph_dqueue_push(&q, nei);
+	  }
+	}
+      }  /* while q !empty */
+      /* Ok, now use FATHER to create the path */
+      while (t1!=minvertex) {
+	VECTOR(*circle)[idx++]=t1;
+	t1=FATHER(t1)-1;
+      }
+      VECTOR(*circle)[idx]=minvertex;
+      idx=mincirc-1;
+      while (t2!=minvertex) {
+	VECTOR(*circle)[idx--]=t2;
+	t2=FATHER(t2)-1;
+      }
+    } /* anycircle */
+  } /* circle */
+#undef FATHER
+
+  igraph_vector_long_destroy(&level);
+  igraph_dqueue_destroy(&q);
+  igraph_lazy_adjlist_destroy(&adjlist);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+int igraph_i_linegraph_undirected(const igraph_t *graph, igraph_t *linegraph);
+
+int igraph_i_linegraph_directed(const igraph_t *graph, igraph_t *linegraph);
+
+/* Note to self: tried using adjacency lists instead of igraph_incident queries,
+ * with minimal performance improvements on a graph with 70K vertices and 360K
+ * edges. (1.09s instead of 1.10s). I think it's not worth the fuss. */
+int igraph_i_linegraph_undirected(const igraph_t *graph, igraph_t *linegraph) {
+  long int no_of_edges=igraph_ecount(graph);  
+  long int i, j, n;
+  igraph_vector_t adjedges, adjedges2;
+  igraph_vector_t edges;
+  long int prev=-1;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&adjedges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&adjedges2, 0);
+  
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+    long int to=IGRAPH_TO(graph, i);
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    if (from != prev) {
+      IGRAPH_CHECK(igraph_incident(graph, &adjedges, (igraph_integer_t) from, 
+				   IGRAPH_ALL));
+    }
+    n=igraph_vector_size(&adjedges);
+    for (j=0; j<n; j++) {
+      long int e=(long int) VECTOR(adjedges)[j];
+      if (e<i) {
+        IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+        IGRAPH_CHECK(igraph_vector_push_back(&edges, e));
+      }
+    }
+    
+    IGRAPH_CHECK(igraph_incident(graph, &adjedges2, (igraph_integer_t) to,
+				 IGRAPH_ALL));
+    n=igraph_vector_size(&adjedges2);
+    for (j=0; j<n; j++) {
+      long int e=(long int) VECTOR(adjedges2)[j];
+      if (e<i) { 
+        IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+        IGRAPH_CHECK(igraph_vector_push_back(&edges, e));
+      }
+    }
+    
+    prev=from;
+  }
+
+  igraph_vector_destroy(&adjedges);
+  igraph_vector_destroy(&adjedges2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  igraph_create(linegraph, &edges, (igraph_integer_t) no_of_edges, 
+		igraph_is_directed(graph));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_linegraph_directed(const igraph_t *graph, igraph_t *linegraph) {
+  long int no_of_edges=igraph_ecount(graph);
+  long int i, j, n;
+  igraph_vector_t adjedges; 
+  igraph_vector_t edges;
+  long int prev=-1;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&adjedges, 0);
+  
+  for (i=0; i<no_of_edges; i++) {
+    long int from=IGRAPH_FROM(graph, i);
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    if (from != prev) {
+      IGRAPH_CHECK(igraph_incident(graph, &adjedges, (igraph_integer_t) from, 
+				   IGRAPH_IN));
+    }
+    n=igraph_vector_size(&adjedges);
+    for (j=0; j<n; j++) {
+      long int e=(long int) VECTOR(adjedges)[j];
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, e));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+    }
+    
+    prev=from;
+  }
+  
+  igraph_vector_destroy(&adjedges);
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_create(linegraph, &edges, (igraph_integer_t) no_of_edges, igraph_is_directed(graph));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_linegraph
+ * \brief Create the line graph of a graph.
+ *
+ * The line graph L(G) of a G undirected graph is defined as follows. 
+ * L(G) has one vertex for each edge in G and two vertices in L(G) are connected 
+ * by an edge if their corresponding edges share an end point.
+ *
+ * </para><para>
+ * The line graph L(G) of a G directed graph is slightly different, 
+ * L(G) has one vertex for each edge in G and two vertices in 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.
+ * 
+ * </para><para>
+ * Edge \em i  in the original graph will correspond to vertex \em i
+ * in the line graph.
+ *
+ * </para><para>
+ * The first version of this function was contributed by Vincent Matossian, 
+ * thanks.
+ * \param graph The input graph, may be directed or undirected.
+ * \param linegraph Pointer to an uninitialized graph object, the
+ *        result is stored here.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of edges plus the number of vertices.
+ */
+
+int igraph_linegraph(const igraph_t *graph, igraph_t *linegraph) {
+
+  if (igraph_is_directed(graph)) {
+    return igraph_i_linegraph_directed(graph, linegraph);
+  } else {
+    return igraph_i_linegraph_undirected(graph, linegraph);
+  }
+}
+
+/**
+ * \function igraph_add_edge
+ * \brief Adds a single edge to a graph.
+ * 
+ * </para><para>
+ * For directed graphs the edge points from \p from to \p to.
+ * 
+ * </para><para>
+ * Note that if you want to add many edges to a big graph, then it is
+ * inefficient to add them one by one, it is better to collect them into
+ * a vector and add all of them via a single \ref igraph_add_edges() call.
+ * \param igraph The graph.
+ * \param from The id of the first vertex of the edge.
+ * \param to The id of the second vertex of the edge.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_add_edges() to add many edges, \ref
+ * igraph_delete_edges() to remove edges and \ref
+ * igraph_add_vertices() to add vertices.
+ * 
+ * Time complexity: O(|V|+|E|), the number of edges plus the number of
+ * vertices.
+ */
+
+int igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to) {
+  
+  igraph_vector_t edges;
+  int ret;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2);
+
+  VECTOR(edges)[0]=from;
+  VECTOR(edges)[1]=to;
+  IGRAPH_CHECK(ret=igraph_add_edges(graph, &edges, 0));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return ret;
+}
+
+/*
+ * \example examples/simple/graph_convergence_degree.c
+ */
+
+int igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result,
+  igraph_vector_t *ins, igraph_vector_t *outs) {
+  long int no_of_nodes = igraph_vcount(graph);
+  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_dqueue_t q;
+  igraph_inclist_t inclist;
+  igraph_bool_t directed = igraph_is_directed(graph);
+
+  if (result != 0) IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));
+  IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
+
+  if (ins == 0) {
+	ins_p = &ins_v;
+	IGRAPH_VECTOR_INIT_FINALLY(ins_p, no_of_edges);
+  } else {
+	ins_p = ins;
+	IGRAPH_CHECK(igraph_vector_resize(ins_p, no_of_edges));
+	igraph_vector_null(ins_p);
+  }
+
+  if (outs == 0) {
+	outs_p = &outs_v;
+	IGRAPH_VECTOR_INIT_FINALLY(outs_p, no_of_edges);
+  } else {
+	outs_p = outs;
+	IGRAPH_CHECK(igraph_vector_resize(outs_p, no_of_edges));
+	igraph_vector_null(outs_p);
+  }
+
+  geodist=igraph_Calloc(no_of_nodes, long int);
+  if (geodist==0) {
+    IGRAPH_ERROR("Cannot calculate convergence degrees", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, geodist);
+
+  /* Collect shortest paths originating from/to every node to correctly
+   * determine input field sizes */
+  for (k=0; k<(directed?2:1); k++) {
+    igraph_neimode_t neimode = (k==0)?IGRAPH_OUT:IGRAPH_IN;
+    igraph_real_t *vec;
+    IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, neimode));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+    vec = (k==0)?VECTOR(*ins_p):VECTOR(*outs_p);
+    for (i=0; i<no_of_nodes; i++) {
+      igraph_dqueue_clear(&q);
+      memset(geodist, 0, sizeof(long int) * (size_t) no_of_nodes);
+      geodist[i]=1;
+      IGRAPH_CHECK(igraph_dqueue_push(&q, i));
+      IGRAPH_CHECK(igraph_dqueue_push(&q, 0.0));
+      while (!igraph_dqueue_empty(&q)) {
+        long int actnode=(long int) igraph_dqueue_pop(&q);
+        long int actdist=(long int) igraph_dqueue_pop(&q);
+        IGRAPH_ALLOW_INTERRUPTION();
+        eids=igraph_inclist_get(&inclist, actnode);
+        n=igraph_vector_size(eids);
+        for (j=0; j<n; j++) {
+          long int neighbor = IGRAPH_OTHER(graph, VECTOR(*eids)[j], actnode);
+          if (geodist[neighbor] != 0) {
+            /* we've already seen this node, another shortest path? */
+            if (geodist[neighbor]-1 == actdist+1) {
+              /* Since this edge is in the BFS tree rooted at i, we must
+               * increase either the size of the infield or the outfield */
+              if (!directed) {
+                if (actnode < neighbor)
+                  VECTOR(*ins_p)[(long int)VECTOR(*eids)[j]] += 1;
+                else
+                  VECTOR(*outs_p)[(long int)VECTOR(*eids)[j]] += 1;
+              } else vec[(long int)VECTOR(*eids)[j]] += 1;
+            } else if (geodist[neighbor]-1 < actdist+1) continue;
+          } else {
+            /* we haven't seen this node yet */
+            IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+            IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+            /* Since this edge is in the BFS tree rooted at i, we must
+             * increase either the size of the infield or the outfield */
+            if (!directed) {
+              if (actnode < neighbor)
+                VECTOR(*ins_p)[(long int)VECTOR(*eids)[j]] += 1;
+              else
+                VECTOR(*outs_p)[(long int)VECTOR(*eids)[j]] += 1;
+            } else vec[(long int)VECTOR(*eids)[j]] += 1;
+            geodist[neighbor]=actdist+2;
+          }
+        }
+      }
+    }
+
+    igraph_inclist_destroy(&inclist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  if (result != 0) {
+	for (i=0; i<no_of_edges; i++)
+      VECTOR(*result)[i] = (VECTOR(*ins_p)[i]-VECTOR(*outs_p)[i]) / 
+	    (VECTOR(*ins_p)[i]+VECTOR(*outs_p)[i]);
+	if (!directed) {
+	  for (i=0; i<no_of_edges; i++)
+		if (VECTOR(*result)[i] < 0) VECTOR(*result)[i] = -VECTOR(*result)[i];
+	}
+  }
+
+  if (ins == 0) {
+	igraph_vector_destroy(ins_p);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (outs == 0) {
+	igraph_vector_destroy(outs_p);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_free(geodist);
+  igraph_dqueue_destroy(&q);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_shortest_paths_dijkstra
+ * Weighted shortest paths from some sources.
+ * 
+ * This function is Dijkstra's algorithm to find the weighted 
+ * shortest paths to all vertices from a single source. (It is run 
+ * independently for the given sources.) It uses a binary heap for 
+ * efficient implementation.
+ * 
+ * \param graph The input graph, can be directed.
+ * \param res The result, a matrix. A pointer to an initialized matrix
+ *    should be passed here. The matrix will be resized as needed. 
+ *    Each row contains the distances from a single source, to the
+ *    vertices given in the \c to argument. 
+ *    Unreachable vertices has distance
+ *    \c IGRAPH_INFINITY. 
+ * \param from The source vertices.
+ * \param to The target vertices. It is not allowed to include a
+ *    vertex twice or more.
+ * \param weights The edge weights. They must be all non-negative for
+ *    Dijkstra's algorithm to work. An error code is returned if there
+ *    is a negative edge weight in the weight vector. If this is a null
+ *    pointer, then the
+ *    unweighted version, \ref igraph_shortest_paths() is called.
+ * \param mode For directed graphs; whether to follow paths along edge
+ *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
+ *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored 
+ *    for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(s*|E|log|E|+|V|), where |V| is the number of
+ * vertices, |E| the number of edges and s the number of sources.
+ * 
+ * \sa \ref igraph_shortest_paths() for a (slightly) faster unweighted
+ * version or \ref igraph_shortest_paths_bellman_ford() for a weighted
+ * variant that works in the presence of negative edge weights (but no
+ * negative loops).
+ * 
+ * \example examples/simple/dijkstra.c
+ */
+
+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) {
+
+  /* Implementation details. This is the basic Dijkstra algorithm, 
+     with a binary heap. The heap is indexed, i.e. it stores not only
+     the distances, but also which vertex they belong to.
+
+     From now on we use a 2-way heap, so the distances can be queried
+     directly from the heap.
+
+     Dirty tricks:
+     - the opposite of the distance is stored in the heap, as it is a
+       maximum heap and we need a minimum heap.
+     - we don't use IGRAPH_INFINITY in the res matrix during the
+       computation, as IGRAPH_FINITE() might involve a function call 
+       and we want to spare that. -1 will denote infinity instead.
+  */
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_2wheap_t Q;
+  igraph_vit_t fromvit, tovit;
+  long int no_of_from, no_of_to;
+  igraph_lazy_inclist_t inclist;
+  long int i,j;
+  igraph_real_t my_infinity=IGRAPH_INFINITY;
+  igraph_bool_t all_to;
+  igraph_vector_t indexv;
+
+  if (!weights) {
+    return igraph_shortest_paths(graph, res, from, to, mode);
+  }
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(weights) < 0) {
+    IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
+  no_of_from=IGRAPH_VIT_SIZE(fromvit);
+  
+  IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+
+  if ( (all_to=igraph_vs_is_all(&to)) ) {
+    no_of_to=no_of_nodes;
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&indexv, no_of_nodes);
+    IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
+    no_of_to=IGRAPH_VIT_SIZE(tovit);
+    for (i=0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) {
+      long int v=IGRAPH_VIT_GET(tovit);
+      if (VECTOR(indexv)[v]) {
+	IGRAPH_ERROR("Duplicate vertices in `to', this is not allowed", 
+		     IGRAPH_EINVAL);
+      }
+      VECTOR(indexv)[v] = ++i;
+    }
+  }
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
+  igraph_matrix_fill(res, my_infinity);
+
+  for (IGRAPH_VIT_RESET(fromvit), i=0; 
+       !IGRAPH_VIT_END(fromvit);
+       IGRAPH_VIT_NEXT(fromvit), i++) {
+    
+    long int reached=0;
+    long int source=IGRAPH_VIT_GET(fromvit);
+    igraph_2wheap_clear(&Q);
+    igraph_2wheap_push_with_index(&Q, source, -1.0);
+    
+    while (!igraph_2wheap_empty(&Q)) {
+      long int minnei=igraph_2wheap_max_index(&Q);
+      igraph_real_t mindist=-igraph_2wheap_deactivate_max(&Q);
+      igraph_vector_t *neis;
+      long int nlen;
+
+      if (all_to) {
+	MATRIX(*res, i, minnei)=mindist-1.0;
+      } else {
+	if (VECTOR(indexv)[minnei]) {
+	  MATRIX(*res, i, (long int)(VECTOR(indexv)[minnei]-1)) = mindist-1.0;
+	  reached++;
+	  if (reached==no_of_to) {
+	    igraph_2wheap_clear(&Q);
+	    break;
+	  }
+	}
+      }
+
+      /* Now check all neighbors of 'minnei' for a shorter path */
+      neis=igraph_lazy_inclist_get(&inclist, (igraph_integer_t) minnei);
+      nlen=igraph_vector_size(neis);
+      for (j=0; j<nlen; j++) {
+	long int edge=(long int) VECTOR(*neis)[j];
+	long int tto=IGRAPH_OTHER(graph, edge, minnei);
+	igraph_real_t altdist=mindist + VECTOR(*weights)[edge];
+	igraph_bool_t active=igraph_2wheap_has_active(&Q, tto);
+	igraph_bool_t has=igraph_2wheap_has_elem(&Q, tto);
+	igraph_real_t curdist= active ? -igraph_2wheap_get(&Q, tto) : 0.0;
+	if (!has) {
+	  /* This is the first non-infinite distance */
+	  IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
+	} else if (altdist < curdist) {
+	  /* This is a shorter path */
+	  IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
+	}
+      }
+      
+    } /* !igraph_2wheap_empty(&Q) */
+
+  } /* !IGRAPH_VIT_END(fromvit) */
+
+  if (!all_to) {
+    igraph_vit_destroy(&tovit);
+    igraph_vector_destroy(&indexv);
+    IGRAPH_FINALLY_CLEAN(2);
+  }  
+  
+  igraph_lazy_inclist_destroy(&inclist);
+  igraph_2wheap_destroy(&Q);
+  igraph_vit_destroy(&fromvit);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_get_shortest_paths_dijkstra
+ * \brief Calculates the weighted shortest paths from/to one vertex.
+ * 
+ * </para><para>
+ * If there is more than one path with the smallest weight between two vertices, this
+ * function gives only one of them. 
+ * \param graph The graph object.
+ * \param vertices The result, the ids of the vertices along the paths. 
+ *        This is a pointer vector, each element points to a vector
+ *        object. These should be initialized before passing them to
+ *        the function, which will properly clear and/or resize them
+ *        and fill the ids of the vertices along the geodesics from/to
+ *        the vertices. Supply a null pointer here if you don't need
+ *        these vectors. Normally, either this argument, or the \c
+ *        edges should be non-null, but no error or warning is given
+ *        if they are both null pointers.
+ * \param edges The result, the ids of the edges along the paths.
+ *        This is a pointer vector, each element points to a vector
+ *        object. These should be initialized before passing them to
+ *        the function, which will properly clear and/or resize them
+ *        and fill the ids of the vertices along the geodesics from/to
+ *        the vertices. Supply a null pointer here if you don't need
+ *        these vectors. Normally, either this argument, or the \c
+ *        vertices should be non-null, but no error or warning is given
+ *        if they are both null pointers.
+ * \param from The id of the vertex from/to which the geodesics are
+ *        calculated. 
+ * \param to Vertex sequence with the ids of the vertices to/from which the 
+ *        shortest paths will be calculated. A vertex might be given multiple
+ *        times.
+ * \param weights a vector holding the edge weights. All weights must be
+ *        positive.
+ * \param mode The type of shortest paths to be use for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL 
+ *          the directed graph is considered as an
+ *          undirected one for the computation.
+ *        \endclist
+ * \param predecessors A pointer to an initialized igraph vector or null.
+ *        If not null, a vector containing the predecessor of each vertex in
+ *        the single source shortest path tree is returned here. The
+ *        predecessor of vertex i in the tree is the vertex from which vertex i
+ *        was reached. The predecessor of the start vertex (in the \c from
+ *        argument) is itself by definition. If the predecessor is -1, 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
+ *        \c to are reached.
+ * \param inbound_edges A pointer to an initialized igraph vector or null.
+ *        If not null, a vector containing the inbound edge of each vertex in
+ *        the single source shortest path tree is returned here. The
+ *        inbound edge of vertex i in the tree is the edge via which vertex i
+ *        was reached. The start vertex and vertices that were not reached
+ *        during the search will have -1 in the corresponding entry of the
+ *        vector. Note that the search terminates if all the vertices in
+ *        \c to are reached.
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM 
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           \p from is invalid vertex id, or the length of \p to is 
+ *           not the same as the length of \p res.
+ *        \cli IGRAPH_EINVMODE 
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(|E|log|E|+|V|), where |V| is the number of
+ * vertices and |E| is the number of edges
+ * 
+ * \sa \ref igraph_shortest_paths_dijkstra() if you only need the path length but
+ * not the paths themselves, \ref igraph_get_shortest_paths() if all edge
+ * weights are equal. 
+ * 
+ * \example examples/simple/igraph_get_shortest_paths_dijkstra.c
+ */
+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) {
+  /* Implementation details. This is the basic Dijkstra algorithm, 
+     with a binary heap. The heap is indexed, i.e. it stores not only
+     the distances, but also which vertex they belong to. The other
+     mapping, i.e. getting the distance for a vertex is not in the
+     heap (that would by the double-indexed heap), but in the result
+     matrix.
+
+     Dirty tricks:
+     - the opposite of the distance is stored in the heap, as it is a
+       maximum heap and we need a minimum heap.
+     - we don't use IGRAPH_INFINITY in the distance vector during the
+       computation, as IGRAPH_FINITE() might involve a function call 
+       and we want to spare that. So we store distance+1.0 instead of 
+       distance, and zero denotes infinity.
+     - `parents' assigns the inbound edge IDs of all vertices in the
+       shortest path tree to the vertices. In this implementation, the
+       edge ID + 1 is stored, zero means unreachable vertices.
+  */
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vit_t vit;
+  igraph_2wheap_t Q;
+  igraph_lazy_inclist_t inclist;
+  igraph_vector_t dists;
+  long int *parents;
+  igraph_bool_t *is_target;
+  long int i,to_reach;
+
+  if (!weights) {
+    return igraph_get_shortest_paths(graph, vertices, edges, from, to, mode,
+        predecessors, inbound_edges);
+  }
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(weights) < 0) {
+    IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  if (vertices && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(vertices)) {
+    IGRAPH_ERROR("Size of `vertices' and `to' should match", IGRAPH_EINVAL);
+  }
+  if (edges && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(edges)) {
+    IGRAPH_ERROR("Size of `edges' and `to' should match", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes);
+  igraph_vector_fill(&dists, -1.0);
+
+  parents = igraph_Calloc(no_of_nodes, long int);
+  if (parents == 0) IGRAPH_ERROR("Can't calculate shortest paths", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_free, parents);
+  is_target = igraph_Calloc(no_of_nodes, igraph_bool_t);
+  if (is_target == 0) IGRAPH_ERROR("Can't calculate shortest paths", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_free, is_target);
+
+  /* Mark the vertices we need to reach */
+  to_reach=IGRAPH_VIT_SIZE(vit);
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    if (!is_target[ (long int) IGRAPH_VIT_GET(vit) ]) {
+      is_target[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
+    } else {
+      to_reach--;		/* this node was given multiple times */
+    }
+  }
+
+  VECTOR(dists)[(long int)from] = 0.0;	/* zero distance */
+  parents[(long int)from] = 0;
+  igraph_2wheap_push_with_index(&Q, from, 0);
+    
+  while (!igraph_2wheap_empty(&Q) && to_reach > 0) {
+    long int nlen, minnei=igraph_2wheap_max_index(&Q);
+    igraph_real_t mindist=-igraph_2wheap_delete_max(&Q);
+    igraph_vector_t *neis;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    if (is_target[minnei]) {
+      is_target[minnei] = 0;
+	  to_reach--;
+	}
+
+    /* Now check all neighbors of 'minnei' for a shorter path */
+    neis=igraph_lazy_inclist_get(&inclist, (igraph_integer_t) minnei);
+    nlen=igraph_vector_size(neis);
+    for (i=0; i<nlen; i++) {
+      long int edge=(long int) VECTOR(*neis)[i];
+      long int tto=IGRAPH_OTHER(graph, edge, minnei);
+      igraph_real_t altdist=mindist + VECTOR(*weights)[edge];
+      igraph_real_t curdist=VECTOR(dists)[tto];
+      if (curdist < 0) {
+        /* This is the first finite distance */
+        VECTOR(dists)[tto] = altdist;
+        parents[tto] = edge+1;
+        IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
+      } else if (altdist < curdist) {
+	      /* This is a shorter path */
+        VECTOR(dists)[tto] = altdist;
+        parents[tto] = edge+1;
+        IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
+      }
+    }
+  } /* !igraph_2wheap_empty(&Q) */
+
+  if (to_reach > 0) IGRAPH_WARNING("Couldn't reach some vertices");
+
+  /* Create `predecessors' if needed */
+  if (predecessors) {
+    IGRAPH_CHECK(igraph_vector_long_resize(predecessors, no_of_nodes));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      if (i == from) {
+        /* i is the start vertex */
+        VECTOR(*predecessors)[i] = i;
+      } else if (parents[i] <= 0) {
+        /* i was not reached */
+        VECTOR(*predecessors)[i] = -1;
+      } else {
+        /* i was reached via the edge with ID = parents[i] - 1 */
+        VECTOR(*predecessors)[i] = IGRAPH_OTHER(graph, parents[i]-1, i);
+      }
+    }
+  }
+  
+  /* Create `inbound_edges' if needed */
+  if (inbound_edges) {
+    IGRAPH_CHECK(igraph_vector_long_resize(inbound_edges, no_of_nodes));
+
+    for (i = 0; i < no_of_nodes; i++) {
+      if (parents[i] <= 0) {
+        /* i was not reached */
+        VECTOR(*inbound_edges)[i] = -1;
+      } else {
+        /* i was reached via the edge with ID = parents[i] - 1 */
+        VECTOR(*inbound_edges)[i] = parents[i]-1;
+      }
+    }
+  }
+  
+  /* Reconstruct the shortest paths based on vertex and/or edge IDs */
+  if (vertices || edges) {
+    for (IGRAPH_VIT_RESET(vit), i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+      long int node=IGRAPH_VIT_GET(vit);
+      igraph_vector_t *vvec=0, *evec=0;
+      if (vertices) {
+	vvec=VECTOR(*vertices)[i];
+	igraph_vector_clear(vvec);
+      }
+      if (edges) {
+	evec=VECTOR(*edges)[i];
+	igraph_vector_clear(evec);
+      }
+      
+      IGRAPH_ALLOW_INTERRUPTION();
+      
+      if (parents[node]>0) {
+	long int size=0;
+	long int act=node;
+	long int edge;
+	while (parents[act]) {
+	  size++;
+	  edge=parents[act]-1;
+	  act=IGRAPH_OTHER(graph, edge, act);
+	}
+	if (vvec) { 
+	  IGRAPH_CHECK(igraph_vector_resize(vvec, size+1)); 
+	  VECTOR(*vvec)[size]=node;
+	}
+	if (evec) {
+	  IGRAPH_CHECK(igraph_vector_resize(evec, size));
+	}
+	act=node;
+	while (parents[act]) {
+	  edge=parents[act]-1;
+	  act=IGRAPH_OTHER(graph, edge, act);
+	  size--;
+	  if (vvec) { VECTOR(*vvec)[size]=act; }
+	  if (evec) { VECTOR(*evec)[size]=edge; }
+	}
+      }
+    }
+  }
+  
+  igraph_lazy_inclist_destroy(&inclist);
+  igraph_2wheap_destroy(&Q);
+  igraph_vector_destroy(&dists);
+  igraph_Free(is_target);
+  igraph_Free(parents);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(6);
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_get_shortest_path_dijkstra
+ * Weighted shortest path from one vertex to another one.
+ * 
+ * Calculates a single (positively) weighted shortest path from
+ * a single vertex to another one, using Dijkstra's algorithm. 
+ * 
+ * </para><para>This function is a special case (and a wrapper) to
+ * \ref igraph_get_shortest_paths_dijkstra(). 
+ * 
+ * \param graph The input graph, it can be directed or undirected.
+ * \param vertices Pointer to an initialized vector or a null
+ *        pointer. If not a null pointer, then the vertex ids along
+ *        the path are stored here, including the source and target
+ *        vertices. 
+ * \param edges Pointer to an uninitialized vector or a null
+ *        pointer. If not a null pointer, then the edge ids along the
+ *        path are stored here.
+ * \param from The id of the source vertex.
+ * \param to The id of the target vertex.
+ * \param weights Vector of edge weights, in the order of edge
+ *        ids. They must be non-negative, otherwise the algorithm does
+ *        not work.
+ * \param mode A constant specifying how edge directions are
+ *        considered in directed graphs. \c IGRAPH_OUT follows edge
+ *        directions, \c IGRAPH_IN follows the opposite directions,
+ *        and \c IGRAPH_ALL ignores edge directions. This argument is
+ *        ignored for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|E|log|E|+|V|), |V| is the number of vertices,
+ * |E| is the number of edges in the graph.
+ * 
+ * \sa \ref igraph_get_shortest_paths_dijkstra() for the version with
+ * more target vertices.
+ */
+
+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) {
+
+  igraph_vector_ptr_t vertices2, *vp=&vertices2;
+  igraph_vector_ptr_t edges2, *ep=&edges2;
+
+  if (vertices) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&vertices2, 1));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vertices2);
+    VECTOR(vertices2)[0]=vertices;
+  } else {
+    vp=0;
+  }
+  if (edges) {
+    IGRAPH_CHECK(igraph_vector_ptr_init(&edges2, 1));
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &edges2);
+    VECTOR(edges2)[0]=edges;
+  } else {
+    ep=0;
+  }
+  
+  IGRAPH_CHECK(igraph_get_shortest_paths_dijkstra(graph, vp, ep, 
+						  from, igraph_vss_1(to),
+						  weights, mode, 0, 0));
+
+  if (edges) { 
+    igraph_vector_ptr_destroy(&edges2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  if (vertices) {
+    igraph_vector_ptr_destroy(&vertices2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+int igraph_i_vector_tail_cmp(const void* path1, const void* path2);
+
+/* Compares two paths based on their last elements. Required by
+ * igraph_get_all_shortest_paths_dijkstra to put the final result
+ * in order. Assumes that both paths are pointers to igraph_vector_t
+ * objects and that they are not empty
+ */
+int igraph_i_vector_tail_cmp(const void* path1, const void* path2) {
+  return (int) (igraph_vector_tail(*(const igraph_vector_t**)path1) -
+		igraph_vector_tail(*(const igraph_vector_t**)path2));
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_get_all_shortest_paths_dijkstra
+ * \brief Finds all shortest paths (geodesics) from a vertex to all other vertices.
+ * 
+ * \param graph The graph object.
+ * \param res Pointer to an initialized pointer vector, the result
+ *   will be stored here in igraph_vector_t objects. Each vector
+ *   object contains the vertices along a shortest path from \p from
+ *   to another vertex. The vectors are ordered according to their
+ *   target vertex: first the shortest paths to vertex 0, then to
+ *   vertex 1, etc. No data is included for unreachable vertices.
+ * \param nrgeo Pointer to an initialized igraph_vector_t object or
+ *   NULL. If not NULL the number of shortest paths from \p from are
+ *   stored here for every vertex in the graph. Note that the values
+ *   will be accurate only for those vertices that are in the target
+ *   vertex sequence (see \p to), since the search terminates as soon
+ *   as all the target vertices have been found.
+ * \param from The id of the vertex from/to which the geodesics are
+ *        calculated. 
+ * \param to Vertex sequence with the ids of the vertices to/from which the 
+ *        shortest paths will be calculated. A vertex might be given multiple
+ *        times.
+ * \param weights a vector holding the edge weights. All weights must be
+ *        non-negative.
+ * \param mode The type of shortest paths to be use for the
+ *        calculation in directed graphs. Possible values: 
+ *        \clist
+ *        \cli IGRAPH_OUT 
+ *          the outgoing paths are calculated. 
+ *        \cli IGRAPH_IN 
+ *          the incoming paths are calculated. 
+ *        \cli IGRAPH_ALL 
+ *          the directed graph is considered as an
+ *          undirected one for the computation.
+ *        \endclist
+ * \return Error code:
+ *        \clist
+ *        \cli IGRAPH_ENOMEM 
+ *           not enough memory for temporary data.
+ *        \cli IGRAPH_EINVVID
+ *           \p from is invalid vertex id, or the length of \p to is 
+ *           not the same as the length of \p res.
+ *        \cli IGRAPH_EINVMODE 
+ *           invalid mode argument.
+ *        \endclist
+ * 
+ * Time complexity: O(|E|log|E|+|V|), where |V| is the number of
+ * vertices and |E| is the number of edges
+ * 
+ * \sa \ref igraph_shortest_paths_dijkstra() if you only need the path
+ * length but not the paths themselves, \ref igraph_get_all_shortest_paths()
+ * if all edge weights are equal. 
+ * 
+ * \example examples/simple/igraph_get_all_shortest_paths_dijkstra.c
+ */
+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) {
+  /* Implementation details: see igraph_get_shortest_paths_dijkstra,
+     it's basically the same.
+  */
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vit_t vit;
+  igraph_2wheap_t Q;
+  igraph_lazy_inclist_t inclist;
+  igraph_vector_t dists, order;
+  igraph_vector_ptr_t parents;
+  unsigned char *is_target;
+  long int i, n, to_reach;
+
+  if (!weights) {
+    return igraph_get_all_shortest_paths(graph, res, nrgeo, from, to, mode);
+  }
+
+  if (res == 0 && nrgeo == 0)
+    return IGRAPH_SUCCESS;
+
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(weights) < 0) {
+    IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
+  }
+
+  /* parents stores a vector for each vertex, listing the parent vertices
+   * of each vertex in the traversal */
+  IGRAPH_CHECK(igraph_vector_ptr_init(&parents, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &parents);
+  igraph_vector_ptr_set_item_destructor(&parents, (igraph_finally_func_t*)igraph_vector_destroy);
+  for (i = 0; i < no_of_nodes; i++) {
+    igraph_vector_t* parent_vec;
+    parent_vec = igraph_Calloc(1, igraph_vector_t);
+    if (parent_vec == 0)
+      IGRAPH_ERROR("cannot run igraph_get_all_shortest_paths", IGRAPH_ENOMEM);
+    IGRAPH_CHECK(igraph_vector_init(parent_vec, 0));
+    VECTOR(parents)[i] = parent_vec; 
+  }
+
+  /* distance of each vertex from the root */
+  IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes);
+  igraph_vector_fill(&dists, -1.0);
+
+  /* order lists the order of vertices in which they were found during
+   * the traversal */
+  IGRAPH_VECTOR_INIT_FINALLY(&order, 0);
+
+  /* boolean array to mark whether a given vertex is a target or not */
+  is_target = igraph_Calloc(no_of_nodes, unsigned char);
+  if (is_target == 0) IGRAPH_ERROR("Can't calculate shortest paths", IGRAPH_ENOMEM);
+  IGRAPH_FINALLY(igraph_free, is_target);
+
+  /* two-way heap storing vertices and distances */
+  IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
+
+  /* lazy adjacency edge list to query neighbours efficiently */
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+
+  /* Mark the vertices we need to reach */
+  IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  to_reach=IGRAPH_VIT_SIZE(vit);
+  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+    if (!is_target[ (long int) IGRAPH_VIT_GET(vit) ]) {
+      is_target[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
+    } else {
+      to_reach--;		/* this node was given multiple times */
+    }
+  }
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  VECTOR(dists)[(long int)from] = 0.0;	/* zero distance */
+  igraph_2wheap_push_with_index(&Q, from, 0);
+    
+  while (!igraph_2wheap_empty(&Q) && to_reach > 0) {
+    long int nlen, minnei=igraph_2wheap_max_index(&Q);
+    igraph_real_t mindist=-igraph_2wheap_delete_max(&Q);
+    igraph_vector_t *neis;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    /*
+    printf("Reached vertex %ld, is_target[%ld] = %d, %ld to go\n",
+        minnei, minnei, (int)is_target[minnei], to_reach - is_target[minnei]);
+    */
+
+    if (is_target[minnei]) {
+      is_target[minnei] = 0;
+      to_reach--;
+    }
+
+    /* Mark that we have reached this vertex */
+    IGRAPH_CHECK(igraph_vector_push_back(&order, minnei));
+
+    /* Now check all neighbors of 'minnei' for a shorter path */
+    neis=igraph_lazy_inclist_get(&inclist, (igraph_integer_t) minnei);
+    nlen=igraph_vector_size(neis);
+    for (i=0; i<nlen; i++) {
+      long int edge=(long int) VECTOR(*neis)[i];
+      long int tto=IGRAPH_OTHER(graph, edge, minnei);
+      igraph_real_t altdist=mindist + VECTOR(*weights)[edge];
+      igraph_real_t curdist=VECTOR(dists)[tto];
+      igraph_vector_t *parent_vec;
+
+      if (curdist < 0) {
+        /* This is the first non-infinite distance */
+        VECTOR(dists)[tto] = altdist;
+        parent_vec = (igraph_vector_t*)VECTOR(parents)[tto];
+        IGRAPH_CHECK(igraph_vector_push_back(parent_vec, minnei));
+        IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
+      } else if (altdist == curdist && VECTOR(*weights)[edge] > 0) {
+	/* This is an alternative path with exactly the same length.
+         * Note that we consider this case only if the edge via which we
+         * reached the node has a nonzero weight; otherwise we could create
+         * infinite loops in undirected graphs by traversing zero-weight edges
+         * back-and-forth */
+        parent_vec = (igraph_vector_t*)VECTOR(parents)[tto];
+        IGRAPH_CHECK(igraph_vector_push_back(parent_vec, minnei));
+      } else if (altdist < curdist) {
+	/* This is a shorter path */
+        VECTOR(dists)[tto] = altdist;
+        parent_vec = (igraph_vector_t*)VECTOR(parents)[tto];
+        igraph_vector_clear(parent_vec);
+        IGRAPH_CHECK(igraph_vector_push_back(parent_vec, minnei));
+        IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
+      }
+    }
+  } /* !igraph_2wheap_empty(&Q) */
+
+  if (to_reach > 0)
+    IGRAPH_WARNING("Couldn't reach some vertices");
+
+  /* we don't need these anymore */
+  igraph_lazy_inclist_destroy(&inclist);
+  igraph_2wheap_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  /*
+  printf("Order:\n");
+  igraph_vector_print(&order);
+
+  printf("Parent vertices:\n");
+  for (i = 0; i < no_of_nodes; i++) {
+    if (igraph_vector_size(VECTOR(parents)[i]) > 0) {
+      printf("[%ld]: ", (long int)i);
+      igraph_vector_print(VECTOR(parents)[i]);
+    }
+  }
+  */
+
+  if (nrgeo) {
+    IGRAPH_CHECK(igraph_vector_resize(nrgeo, no_of_nodes));
+    igraph_vector_null(nrgeo);
+
+    /* Theoretically, we could calculate nrgeo in parallel with the traversal.
+     * However, that way we would have to check whether nrgeo is null or not
+     * every time we want to update some element in nrgeo. Since we need the
+     * order vector anyway for building the final result, we could just as well
+     * build nrgeo here.
+     */
+    VECTOR(*nrgeo)[(long int)from] = 1;
+    n = igraph_vector_size(&order);
+    for (i = 1; i < n; i++) {
+      long int node, j, k;
+      igraph_vector_t *parent_vec;
+
+      node = (long int)VECTOR(order)[i];
+      /* now, take the parent vertices */
+      parent_vec = (igraph_vector_t*)VECTOR(parents)[node];
+      k = igraph_vector_size(parent_vec);
+      for (j = 0; j < k; j++) {
+        VECTOR(*nrgeo)[node] += VECTOR(*nrgeo)[(long int)VECTOR(*parent_vec)[j]];
+      }
+    }
+  }
+
+  if (res) {
+    igraph_vector_t *path, *paths_index, *parent_vec;
+    igraph_stack_t stack;
+    long int j, node;
+
+    /* a shortest path from the starting vertex to vertex i can be
+     * obtained by calculating the shortest paths from the "parents"
+     * of vertex i in the traversal. Knowing which of the vertices
+     * are "targets" (see is_target), we can collect for which other
+     * vertices do we need to calculate the shortest paths. We reuse
+     * is_target for that; is_target = 0 means that we don't need the
+     * vertex, is_target = 1 means that the vertex is a target (hence
+     * we need it), is_target = 2 means that the vertex is not a target
+     * but it stands between a shortest path between the root and one
+     * of the targets 
+     */
+    if (igraph_vs_is_all(&to)) {
+      memset(is_target, 1, sizeof(unsigned char) * (size_t) no_of_nodes);
+    } else {
+      memset(is_target, 0, sizeof(unsigned char) * (size_t) no_of_nodes);
+
+      IGRAPH_CHECK(igraph_stack_init(&stack, 0));
+      IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+
+      /* Add the target vertices to the queue */
+      IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
+      IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+      for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+        i = (long int) IGRAPH_VIT_GET(vit);
+        if (!is_target[i]) {
+          is_target[i] = 1;
+          IGRAPH_CHECK(igraph_stack_push(&stack, i));
+        }
+      }
+      igraph_vit_destroy(&vit);
+      IGRAPH_FINALLY_CLEAN(1);
+
+      while (!igraph_stack_empty(&stack)) {
+        /* For each parent of node i, get its parents */
+	igraph_real_t el=igraph_stack_pop(&stack);
+        parent_vec = (igraph_vector_t*)VECTOR(parents)[(long int) el];
+        i = igraph_vector_size(parent_vec);
+
+        for (j = 0; j < i; j++) {
+          /* For each parent, check if it's already in the stack.
+           * If not, push it and mark it in is_target */
+          n = (long int) VECTOR(*parent_vec)[j];
+          if (!is_target[n]) {
+            is_target[n] = 2;
+            IGRAPH_CHECK(igraph_stack_push(&stack, n));
+          }
+        }
+      }
+      igraph_stack_destroy(&stack);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+
+    /* now, reconstruct the shortest paths from the parent list in the
+     * order we've found the nodes during the traversal.
+     * dists is being re-used as a vector where element i tells the
+     * index in res where the shortest paths leading to vertex i
+     * start, plus one (so that zero means that there are no paths
+     * for a given vertex).
+     */
+    paths_index = &dists;
+    n = igraph_vector_size(&order);
+    igraph_vector_null(paths_index);
+
+    /* clear the paths vector */
+    igraph_vector_ptr_clear(res);
+    igraph_vector_ptr_set_item_destructor(res,
+        (igraph_finally_func_t*)igraph_vector_destroy);
+
+    /* by definition, the shortest path leading to the starting vertex
+     * consists of the vertex itself only */
+    path = igraph_Calloc(1, igraph_vector_t);
+    if (path == 0)
+      IGRAPH_ERROR("cannot run igraph_get_all_shortest_paths_dijkstra",
+          IGRAPH_ENOMEM);
+    IGRAPH_FINALLY(igraph_free, path);
+    IGRAPH_CHECK(igraph_vector_init(path, 1));
+    IGRAPH_CHECK(igraph_vector_ptr_push_back(res, path));
+    IGRAPH_FINALLY_CLEAN(1);  /* ownership of path passed to res */
+    VECTOR(*path)[0] = from;
+    VECTOR(*paths_index)[(long int)from] = 1;
+
+    for (i = 1; i < n; i++) {
+      long int m, path_count;
+      igraph_vector_t *parent_path;
+
+      node = (long int) VECTOR(order)[i];
+
+      /* if we don't need the shortest paths for this node (because
+       * it is not standing in a shortest path between the source
+       * node and any of the target nodes), skip it */
+      if (!is_target[node])
+        continue;
+
+      IGRAPH_ALLOW_INTERRUPTION();
+
+      /* we are calculating the shortest paths of node now. */
+      /* first, we update the paths_index */
+      path_count = igraph_vector_ptr_size(res);
+      VECTOR(*paths_index)[node] = path_count+1;
+      /* res_end = (igraph_vector_t*)&(VECTOR(*res)[path_count]); */
+
+      /* now, take the parent vertices */
+      parent_vec = (igraph_vector_t*)VECTOR(parents)[node];
+      m = igraph_vector_size(parent_vec);
+
+      /*
+      printf("Calculating shortest paths to vertex %ld\n", node);
+      printf("Parents are: ");
+      igraph_vector_print(parent_vec);
+      */
+
+      for (j = 0; j < m; j++) {
+        /* for each parent, copy the shortest paths leading to that parent
+         * and add the current vertex in the end */
+        long int parent_node = (long int) VECTOR(*parent_vec)[j];
+        long int parent_path_idx = (long int) VECTOR(*paths_index)[parent_node] - 1;
+        /*
+        printf("  Considering parent: %ld\n", parent_node);
+        printf("  Paths to parent start at index %ld in res\n", parent_path_idx);
+        */
+        assert(parent_path_idx >= 0);
+        for (; parent_path_idx < path_count; parent_path_idx++) {
+          parent_path = (igraph_vector_t*)VECTOR(*res)[parent_path_idx];
+          if (igraph_vector_tail(parent_path) != parent_node)
+            break;
+
+          path = igraph_Calloc(1, igraph_vector_t);
+          if (path == 0)
+            IGRAPH_ERROR("cannot run igraph_get_all_shortest_paths_dijkstra",
+                IGRAPH_ENOMEM);
+          IGRAPH_FINALLY(igraph_free, path);
+          IGRAPH_CHECK(igraph_vector_copy(path, parent_path));
+          IGRAPH_CHECK(igraph_vector_ptr_push_back(res, path));
+          IGRAPH_FINALLY_CLEAN(1);  /* ownership of path passed to res */
+          IGRAPH_CHECK(igraph_vector_push_back(path, node));
+        }
+      }
+    }
+
+    /* remove the destructor from the path vector */
+    igraph_vector_ptr_set_item_destructor(res, 0);
+
+    /* free those paths from the result vector which we won't need */
+    n = igraph_vector_ptr_size(res);
+    j = 0;
+    for (i = 0; i < n; i++) {
+      igraph_real_t tmp;
+      path = (igraph_vector_t*)VECTOR(*res)[i];
+      tmp=igraph_vector_tail(path);
+      if (is_target[(long int)tmp] == 1) {
+        /* we need this path, keep it */
+        VECTOR(*res)[j] = path;
+        j++;
+      } else {
+        /* we don't need this path, free it */
+        igraph_vector_destroy(path); free(path);
+      }
+    }
+    IGRAPH_CHECK(igraph_vector_ptr_resize(res, j));
+
+    /* sort the paths by the target vertices */
+    igraph_vector_ptr_sort(res, igraph_i_vector_tail_cmp);
+  }
+
+  /* free the allocated memory */
+  igraph_vector_destroy(&order);
+  igraph_Free(is_target);
+  igraph_vector_destroy(&dists);
+  igraph_vector_ptr_destroy_all(&parents);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  return 0;
+}
+
+/**
+ * \function igraph_shortest_paths_bellman_ford
+ * Weighted shortest paths from some sources allowing negative weights.
+ * 
+ * This function is the Bellman-Ford algorithm to find the weighted 
+ * shortest paths to all vertices from a single source. (It is run 
+ * independently for the given sources.). If there are no negative
+ * weights, you are better off with \ref igraph_shortest_paths_dijkstra() .
+ * 
+ * \param graph The input graph, can be directed.
+ * \param res The result, a matrix. A pointer to an initialized matrix
+ *    should be passed here, the matrix will be resized if needed. 
+ *    Each row contains the distances from a single source, to all
+ *    vertices in the graph, in the order of vertex ids. For unreachable
+ *    vertices the matrix contains \c IGRAPH_INFINITY. 
+ * \param from The source vertices.
+ * \param weights The edge weights. There mustn't be any closed loop in
+ *    the graph that has a negative total weight (since this would allow
+ *    us to decrease the weight of any path containing at least a single
+ *    vertex of this loop infinitely). If this is a null pointer, then the
+ *    unweighted version, \ref igraph_shortest_paths() is called.
+ * \param mode For directed graphs; whether to follow paths along edge
+ *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
+ *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored 
+ *    for undirected graphs.
+ * \return Error code.
+ * 
+ * Time complexity: O(s*|E|*|V|), where |V| is the number of
+ * vertices, |E| the number of edges and s the number of sources.
+ * 
+ * \sa \ref igraph_shortest_paths() for a faster unweighted version
+ * or \ref igraph_shortest_paths_dijkstra() if you do not have negative
+ * edge weights.
+ * 
+ * \example examples/simple/bellman_ford.c
+ */
+
+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) {
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_lazy_inclist_t inclist;
+  long int i,j,k;
+  long int no_of_from, no_of_to;
+  igraph_dqueue_t Q; 
+  igraph_vector_t clean_vertices;
+  igraph_vector_t num_queued;
+  igraph_vit_t fromvit, tovit;
+  igraph_real_t my_infinity=IGRAPH_INFINITY;
+  igraph_bool_t all_to;
+  igraph_vector_t dist;
+
+  /*
+     - speedup: a vertex is marked clean if its distance from the source
+       did not change during the last phase. Neighbors of a clean vertex
+       are not relaxed again, since it would mean no change in the
+       shortest path values. Dirty vertices are queued. Negative loops can
+       be detected by checking whether a vertex has been queued at least
+       n times.
+  */
+  if (!weights) {
+    return igraph_shortest_paths(graph, res, from, to, mode);
+  }
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
+  no_of_from=IGRAPH_VIT_SIZE(fromvit);
+  
+  IGRAPH_DQUEUE_INIT_FINALLY(&Q, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&clean_vertices, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&num_queued, no_of_nodes);
+  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
+
+  if ( (all_to=igraph_vs_is_all(&to)) ) {
+    no_of_to=no_of_nodes;
+  } else {
+    IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
+    no_of_to=IGRAPH_VIT_SIZE(tovit);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
+
+  for (IGRAPH_VIT_RESET(fromvit), i=0; 
+       !IGRAPH_VIT_END(fromvit);
+       IGRAPH_VIT_NEXT(fromvit), i++) {
+    long int source=IGRAPH_VIT_GET(fromvit);
+
+    igraph_vector_fill(&dist, my_infinity);
+    VECTOR(dist)[source] = 0;
+    igraph_vector_null(&clean_vertices);
+    igraph_vector_null(&num_queued);
+
+    /* Fill the queue with vertices to be checked */
+    for (j=0; j<no_of_nodes; j++) IGRAPH_CHECK(igraph_dqueue_push(&Q, j));
+
+    while (!igraph_dqueue_empty(&Q)) {
+      igraph_vector_t *neis;
+      long int nlen;
+
+      j = (long int) igraph_dqueue_pop(&Q);
+      VECTOR(clean_vertices)[j] = 1;
+      VECTOR(num_queued)[j] += 1;
+      if (VECTOR(num_queued)[j] > no_of_nodes)
+        IGRAPH_ERROR("cannot run Bellman-Ford algorithm", IGRAPH_ENEGLOOP);
+
+      /* If we cannot get to j in finite time yet, there is no need to relax
+       * its edges */
+      if (!IGRAPH_FINITE(VECTOR(dist)[j])) continue;
+
+      neis = igraph_lazy_inclist_get(&inclist, (igraph_integer_t) j);
+      nlen = igraph_vector_size(neis);
+
+      for (k=0; k<nlen; k++) {
+        long int nei = (long int) VECTOR(*neis)[k];
+        long int target = IGRAPH_OTHER(graph, nei, j);
+        if (VECTOR(dist)[target] > VECTOR(dist)[j] + VECTOR(*weights)[nei]) {
+          /* relax the edge */
+          VECTOR(dist)[target] = VECTOR(dist)[j] + VECTOR(*weights)[nei];
+          if (VECTOR(clean_vertices)[target]) {
+            VECTOR(clean_vertices)[target] = 0;
+            IGRAPH_CHECK(igraph_dqueue_push(&Q, target));
+          }
+        }
+      }
+    }
+
+    /* Copy it to the result */
+    if (all_to) {
+      igraph_matrix_set_row(res, &dist, i);
+    } else {
+      for (IGRAPH_VIT_RESET(tovit), j=0; !IGRAPH_VIT_END(tovit); 
+           IGRAPH_VIT_NEXT(tovit), j++) {
+        long int v=IGRAPH_VIT_GET(tovit);
+        MATRIX(*res, i, j) = VECTOR(dist)[v];
+      }
+    }
+  }
+
+  igraph_vector_destroy(&dist);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  if (!all_to) {
+    igraph_vit_destroy(&tovit);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vit_destroy(&fromvit);
+  igraph_dqueue_destroy(&Q);
+  igraph_vector_destroy(&clean_vertices);
+  igraph_vector_destroy(&num_queued);
+  igraph_lazy_inclist_destroy(&inclist);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \function igraph_shortest_paths_johnson
+ * Calculate shortest paths from some sources using Johnson's algorithm.
+ * 
+ * See Wikipedia at http://en.wikipedia.org/wiki/Johnson's_algorithm
+ * for Johnson's algorithm. This algorithm works even if the graph
+ * contains negative edge weights, and it is worth using it if we
+ * calculate the shortest paths from many sources. 
+ * 
+ * </para><para> If no edge weights are supplied, then the unweighted
+ * version, \ref igraph_shortest_paths() is called. 
+ * 
+ * </para><para> If all the supplied edge weights are non-negative,
+ * then Dijkstra's algorithm is used by calling 
+ * \ref igraph_shortest_paths_dijkstra().
+ * 
+ * \param graph The input graph, typically it is directed.
+ * \param res Pointer to an initialized matrix, the result will be
+ *   stored here, one line for each source vertex, one column for each
+ *   target vertex.
+ * \param from The source vertices.
+ * \param to The target vertices. It is not allowed to include a
+ *   vertex twice or more.
+ * \param weights Optional edge weights. If it is a null-pointer, then
+ *   the unweighted breadth-first search based \ref
+ *   igraph_shortest_paths() will be called.
+ * \return Error code.
+ * 
+ * Time complexity: O(s|V|log|V|+|V||E|), |V| and |E| are the number
+ * of vertices and edges, s is the number of source vertices.
+ * 
+ * \sa \ref igraph_shortest_paths() for a faster unweighted version
+ * or \ref igraph_shortest_paths_dijkstra() if you do not have negative
+ * edge weights, \ref igraph_shortest_paths_bellman_ford() if you only
+ * need to calculate shortest paths from a couple of sources.
+ */
+
+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) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_t newgraph;
+  igraph_vector_t edges, newweights;
+  igraph_matrix_t bfres;
+  long int i, ptr;
+  long int nr, nc;
+  igraph_vit_t fromvit;
+
+  /* If no weights, then we can just run the unweighted version */
+  if (!weights) {
+    return igraph_shortest_paths(graph, res, from, to, IGRAPH_OUT);
+  }
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
+  }
+  
+  /* If no negative weights, then we can run Dijkstra's algorithm */
+  if (igraph_vector_min(weights) >= 0) {
+    return igraph_shortest_paths_dijkstra(graph, res, from, to,
+					  weights, IGRAPH_OUT);
+  }
+  
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_ERROR("Johnson's shortest path: undirected graph and negative weight",
+		 IGRAPH_EINVAL);
+  }
+  
+  /* ------------------------------------------------------------ */
+  /* -------------------- Otherwise proceed --------------------- */
+
+  IGRAPH_MATRIX_INIT_FINALLY(&bfres, 0, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&newweights, 0);
+
+  IGRAPH_CHECK(igraph_empty(&newgraph, (igraph_integer_t) no_of_nodes+1, 
+			    igraph_is_directed(graph)));
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+			    
+  /* Add a new node to the graph, plus edges from it to all the others. */
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2 + no_of_nodes*2);
+  igraph_get_edgelist(graph, &edges, /*bycol=*/ 0);
+  igraph_vector_resize(&edges, no_of_edges * 2 + no_of_nodes * 2);
+    for (i=0, ptr=no_of_edges*2; i<no_of_nodes; i++) {
+      VECTOR(edges)[ptr++] = no_of_nodes;
+      VECTOR(edges)[ptr++] = i;
+  }    
+  IGRAPH_CHECK(igraph_add_edges(&newgraph, &edges, 0));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  IGRAPH_CHECK(igraph_vector_reserve(&newweights, no_of_edges+no_of_nodes));
+  igraph_vector_update(&newweights, weights);
+  igraph_vector_resize(&newweights, no_of_edges+no_of_nodes);
+  for (i=no_of_edges; i<no_of_edges+no_of_nodes; i++) {
+    VECTOR(newweights)[i] = 0;
+  }
+  
+  /* Run Bellmann-Ford algorithm on the new graph, starting from the 
+     new vertex.  */
+  
+  IGRAPH_CHECK(igraph_shortest_paths_bellman_ford(&newgraph, &bfres,
+				  igraph_vss_1((igraph_integer_t) no_of_nodes),
+				  igraph_vss_all(), &newweights, IGRAPH_OUT));
+
+  igraph_destroy(&newgraph);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Now the edges of the original graph are reweighted, using the
+     values from the BF algorithm. Instead of w(u,v) we will have 
+     w(u,v) + h(u) - h(v) */
+  
+  igraph_vector_resize(&newweights, no_of_edges);
+  for (i=0; i<no_of_edges; i++) {
+    long int ffrom=IGRAPH_FROM(graph, i);
+    long int tto=IGRAPH_TO(graph, i);
+    VECTOR(newweights)[i] += MATRIX(bfres, 0, ffrom) - MATRIX(bfres, 0, tto);
+  }
+  
+  /* Run Dijkstra's algorithm on the new weights */
+  IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, res, from, 
+					      to, &newweights,
+					      IGRAPH_OUT));
+  
+  igraph_vector_destroy(&newweights);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Reweight the shortest paths */
+  nr=igraph_matrix_nrow(res);
+  nc=igraph_matrix_ncol(res);
+
+  IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
+
+  for (i=0; i<nr; i++, IGRAPH_VIT_NEXT(fromvit)) {
+    long int v1=IGRAPH_VIT_GET(fromvit);
+    if (igraph_vs_is_all(&to)) {
+      long int v2;
+      for (v2=0; v2<nc; v2++) {
+	igraph_real_t sub=MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2);
+	MATRIX(*res, i, v2) -= sub;
+      }
+    } else {
+      long int j;
+      igraph_vit_t tovit;
+      IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
+      IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
+      for (j=0, IGRAPH_VIT_RESET(tovit); j<nc; j++, IGRAPH_VIT_NEXT(tovit)) {
+	long int v2=IGRAPH_VIT_GET(tovit);
+	igraph_real_t sub=MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2);
+	MATRIX(*res, i, v2) -= sub;
+      }
+      igraph_vit_destroy(&tovit);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+
+  igraph_vit_destroy(&fromvit);
+  igraph_matrix_destroy(&bfres);
+  IGRAPH_FINALLY_CLEAN(2);
+    
+  return 0;
+}
+
+/**
+ * \function igraph_unfold_tree
+ * Unfolding a graph into a tree, by possibly multiplicating its vertices.
+ *
+ * A graph is converted into a tree (or forest, if it is unconnected),
+ * by performing a breadth-first search on it, and replicating
+ * vertices that were found a second, third, etc. time. 
+ * \param graph The input graph, it can be either directed or
+ *   undirected.
+ * \param tree Pointer to an uninitialized graph object, the result is
+ *   stored here.
+ * \param mode For directed graphs; whether to follow paths along edge
+ *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
+ *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored 
+ *    for undirected graphs.
+ * \param roots A numeric vector giving the root vertex, or vertices
+ *   (if the graph is not connected), to start from.
+ * \param vertex_index Pointer to an initialized vector, or a null
+ *   pointer. If not a null pointer, then a mapping from the vertices
+ *   in the new graph to the ones in the original is created here.
+ * \return Error code.
+ * 
+ * Time complexity: O(n+m), linear in the number vertices and edges.
+ * 
+ */
+
+int igraph_unfold_tree(const igraph_t *graph, igraph_t *tree,
+		       igraph_neimode_t mode, const igraph_vector_t *roots,
+		       igraph_vector_t *vertex_index) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  
+  igraph_vector_t edges;
+  igraph_vector_bool_t seen_vertices;
+  igraph_vector_bool_t seen_edges;
+
+  igraph_dqueue_t Q;
+  igraph_vector_t neis;
+  
+  long int r, v_ptr=no_of_nodes;
+
+  /* TODO: handle not-connected graphs, multiple root vertices */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2);
+  IGRAPH_DQUEUE_INIT_FINALLY(&Q, 100);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_vector_bool_init(&seen_vertices, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &seen_vertices);
+  IGRAPH_CHECK(igraph_vector_bool_init(&seen_edges, no_of_edges));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &seen_edges);
+  
+  if (vertex_index) { 
+    long int i;
+    IGRAPH_CHECK(igraph_vector_resize(vertex_index, 
+				      no_of_nodes > no_of_edges+1 ? 
+				      no_of_nodes : no_of_edges+1));
+    for (i=0; i<no_of_nodes; i++) {
+      VECTOR(*vertex_index)[i] = i;
+    }
+  }
+
+  for (r=0; r<igraph_vector_size(roots); r++) {
+
+    long int root=(long int) VECTOR(*roots)[r];
+    VECTOR(seen_vertices)[root] = 1;
+    igraph_dqueue_push(&Q, root);
+  
+    while (!igraph_dqueue_empty(&Q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&Q);
+      long int i, n;
+      
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) actnode,
+				   mode));
+      n=igraph_vector_size(&neis);
+      for (i=0; i<n; i++) {
+
+	long int edge=(long int) VECTOR(neis)[i];
+	long int from=IGRAPH_FROM(graph, edge);
+	long int to=IGRAPH_TO(graph, edge);
+	long int nei=IGRAPH_OTHER(graph, edge, actnode);
+
+	if (! VECTOR(seen_edges)[edge]) { 
+	  
+	  VECTOR(seen_edges)[edge] = 1;
+	  
+	  if (! VECTOR(seen_vertices)[nei]) {
+	    
+	    VECTOR(edges)[ edge*2 ] = from;
+	    VECTOR(edges)[ edge*2+1 ] = to;
+	    
+	    VECTOR(seen_vertices)[nei] = 1;
+	    IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));
+	    
+	  } else {
+	    
+	    if (vertex_index) { 
+	      VECTOR(*vertex_index)[v_ptr] = nei;
+	    }
+	    
+	    if (from==nei) {
+	      VECTOR(edges)[ edge*2 ] = v_ptr++;
+	      VECTOR(edges)[ edge*2+1 ] = to;
+	    } else {
+	      VECTOR(edges)[ edge*2 ] = from;
+	      VECTOR(edges)[ edge*2+1 ] = v_ptr++;
+	    }
+	  }
+	}
+
+      }	/* for i<n */
+      
+    } /* ! igraph_dqueue_empty(&Q) */
+
+  } /* r < igraph_vector_size(roots) */
+
+  igraph_vector_bool_destroy(&seen_edges);
+  igraph_vector_bool_destroy(&seen_vertices);
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  IGRAPH_CHECK(igraph_create(tree, &edges, (igraph_integer_t) no_of_edges+1, 
+			     igraph_is_directed(graph)));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_is_mutual
+ * Check whether the edges of a directed graph are mutual.
+ * 
+ * An (A,B) edge is mutual if the graph contains the (B,A) edge, too.
+ * </para>
+ * 
+ * <para>An undirected graph only has mutual edges, by definition.
+ * </para>
+ * 
+ * <para>Edge multiplicity is not considered here, e.g. if there are two 
+ * (A,B) edges and one (B,A) edge, then all three are considered to be
+ * mutual.
+ * 
+ * \param graph The input graph.
+ * \param res Pointer to an initialized vector, the result is stored
+ *        here.
+ * \param es The sequence of edges to check. Supply
+ *        <code>igraph_ess_all()</code> for all edges, see \ref
+ *        igraph_ess_all().
+ * \return Error code.
+ * 
+ * Time complexity: O(n log(d)), n is the number of edges supplied, d
+ * is the maximum in-degree of the vertices that are targets of the
+ * supplied edges. An upper limit of the time complexity is O(n log(|E|)),
+ * |E| is the number of edges in the graph.
+ */
+
+int igraph_is_mutual(igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es) {
+
+  igraph_eit_t eit;
+  igraph_lazy_adjlist_t adjlist;
+  long int i;
+  
+  /* How many edges do we have? */
+  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+  IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit)));
+
+  /* An undirected graph has mutual edges by definition,
+     res is already properly resized */
+  if (! igraph_is_directed(graph)) {
+    igraph_vector_bool_fill(res, 1);
+    igraph_eit_destroy(&eit);
+    IGRAPH_FINALLY_CLEAN(1);
+    return 0;
+  }
+
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_OUT, IGRAPH_DONT_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+  
+  for (i=0; ! IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
+    long int edge=IGRAPH_EIT_GET(eit);
+    long int from=IGRAPH_FROM(graph, edge);
+    long int to=IGRAPH_TO(graph, edge);
+    
+    /* Check whether there is a to->from edge, search for from in the
+       out-list of to. We don't search an empty vector, because
+       vector_binsearch seems to have a bug with this. */
+    igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, 
+						  (igraph_integer_t) to);
+    if (igraph_vector_empty(neis)) {
+      VECTOR(*res)[i]=0;
+    } else {
+      VECTOR(*res)[i]=igraph_vector_binsearch2(neis, from);
+    }
+  }
+
+  igraph_lazy_adjlist_destroy(&adjlist);
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+int igraph_i_avg_nearest_neighbor_degree_weighted(const igraph_t *graph,
+					    igraph_vs_t vids,
+					    igraph_vector_t *knn,
+					    igraph_vector_t *knnk, 
+					    const igraph_vector_t *weights);
+
+int igraph_i_avg_nearest_neighbor_degree_weighted(const igraph_t *graph,
+						  igraph_vs_t vids,
+						  igraph_vector_t *knn,
+						  igraph_vector_t *knnk, 
+						  const igraph_vector_t *weights) {
+
+  long int no_of_nodes = igraph_vcount(graph);
+  igraph_vector_t neis;
+  long int i, j, no_vids;
+  igraph_vit_t vit;
+  igraph_vector_t my_knn_v, *my_knn=knn;
+  igraph_vector_t deg;
+  long int maxdeg;
+  igraph_integer_t maxdeg2;
+  igraph_vector_t deghist;
+  igraph_real_t mynan=IGRAPH_NAN;
+
+  if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector size", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  no_vids=IGRAPH_VIT_SIZE(vit);
+  
+  if (!knn) {
+    IGRAPH_VECTOR_INIT_FINALLY(&my_knn_v, no_vids);
+    my_knn=&my_knn_v;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(knn, no_vids));
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, no_of_nodes);
+  IGRAPH_CHECK(igraph_strength(graph, &deg, igraph_vss_all(),
+			       /*mode=*/ IGRAPH_ALL, /*loops=*/ 1, weights));
+  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdeg2, igraph_vss_all(), 
+				/*mode=*/ IGRAPH_ALL, /*loops=*/ 1));
+  maxdeg=maxdeg2;
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, maxdeg);
+  igraph_vector_resize(&neis, 0);
+
+  if (knnk) {
+    IGRAPH_CHECK(igraph_vector_resize(knnk, maxdeg));
+    igraph_vector_null(knnk);
+    IGRAPH_VECTOR_INIT_FINALLY(&deghist, maxdeg);
+  }
+
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    igraph_real_t sum=0.0;
+    long int v=IGRAPH_VIT_GET(vit);
+    long int nv;
+    igraph_real_t str=VECTOR(deg)[v];
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, 
+				  IGRAPH_ALL));
+    nv=igraph_vector_size(&neis);
+    for (j=0; j<nv; j++) { 
+      long int nei=(long int) VECTOR(neis)[j];
+      sum += VECTOR(deg)[nei];
+    }
+    if (str != 0.0) {
+      VECTOR(*my_knn)[i] = sum / str;
+    } else {
+      VECTOR(*my_knn)[i] = mynan;
+    }
+    if (knnk && nv != 0) {
+      VECTOR(*knnk)[nv-1] += VECTOR(*my_knn)[i];
+      VECTOR(deghist)[nv-1] += 1;
+    }
+  }
+
+  if (knnk) {
+    for (i=0; i<maxdeg; i++) {
+      igraph_real_t dh=VECTOR(deghist)[i];
+      if (dh != 0) {
+	VECTOR(*knnk)[i] /= VECTOR(deghist)[i];
+      } else {
+	VECTOR(*knnk)[i] = mynan;
+      }
+    }
+    
+    igraph_vector_destroy(&deghist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&deg);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  if (!knn) {
+    igraph_vector_destroy(&my_knn_v);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_avg_nearest_neighbor_degree
+ * Average nearest neighbor degree.
+ *
+ * Calculates the average degree of the neighbors for each vertex, and
+ * optionally, the same quantity in the function of vertex degree.
+ * 
+ * </para><para>For isolate vertices \p knn is set to \c
+ * IGRAPH_NAN. The same is done in \p knnk for vertex degrees that
+ * don't appear in the graph.
+ * 
+ * \param graph The input graph, it can be directed but the
+ *   directedness of the edges is ignored.
+ * \param vids The vertices for which the calculation is performed. 
+ * \param knn Pointer to an initialized vector, the result will be
+ *   stored here. It will be resized as needed. Supply a NULL pointer
+ *   here, if you only want to calculate \c knnk.
+ * \param knnk Pointer to an initialized vector, the average nearest
+ *   neighbor degree in the function of vertex degree is stored
+ *   here. The first (zeroth) element is for degree one vertices,
+ *   etc. Supply a NULL pointer here if you don't want to calculate
+ *   this.
+ * \param weights Optional edge weights. Supply a null pointer here
+ *   for the non-weighted version. If this is not a null pointer, then
+ *   the strength of the vertices is used instead of the normal vertex
+ *   degree, see \ref igraph_strength().
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ * 
+ * \example examples/simple/igraph_knn.c
+ */
+
+int igraph_avg_nearest_neighbor_degree(const igraph_t *graph,
+				       igraph_vs_t vids,
+				       igraph_vector_t *knn,
+				       igraph_vector_t *knnk, 
+				       const igraph_vector_t *weights) {
+
+  long int no_of_nodes = igraph_vcount(graph);
+  igraph_vector_t neis;
+  long int i, j, no_vids;
+  igraph_vit_t vit;
+  igraph_vector_t my_knn_v, *my_knn=knn;
+  igraph_vector_t deg;
+  long int maxdeg;
+  igraph_vector_t deghist;
+  igraph_real_t mynan=IGRAPH_NAN;
+  igraph_bool_t simple;
+
+  IGRAPH_CHECK(igraph_is_simple(graph, &simple));
+  if (!simple) {
+    IGRAPH_ERROR("Average nearest neighbor degree Works only with "
+		 "simple graphs", IGRAPH_EINVAL);
+  }
+
+  if (weights) { 
+    return igraph_i_avg_nearest_neighbor_degree_weighted(graph, vids, knn, knnk,
+							 weights);
+  }
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  no_vids=IGRAPH_VIT_SIZE(vit);
+  
+  if (!knn) {
+    IGRAPH_VECTOR_INIT_FINALLY(&my_knn_v, no_vids);
+    my_knn=&my_knn_v;
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(knn, no_vids));
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, no_of_nodes);
+  IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(),
+			     /*mode=*/ IGRAPH_ALL, /*loops*/ 1));
+  maxdeg=(long int) igraph_vector_max(&deg);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, maxdeg);
+  igraph_vector_resize(&neis, 0);
+
+  if (knnk) {
+    IGRAPH_CHECK(igraph_vector_resize(knnk, maxdeg));
+    igraph_vector_null(knnk);
+    IGRAPH_VECTOR_INIT_FINALLY(&deghist, maxdeg);
+  }
+
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    igraph_real_t sum=0.0;
+    long int v=IGRAPH_VIT_GET(vit);
+    long int nv=(long int) VECTOR(deg)[v];
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v,
+				  IGRAPH_ALL));
+    for (j=0; j<nv; j++) { 
+      long int nei=(long int) VECTOR(neis)[j];
+      sum += VECTOR(deg)[nei];
+    }
+    if (nv != 0) {
+      VECTOR(*my_knn)[i] = sum / nv;
+    } else {
+      VECTOR(*my_knn)[i] = mynan;
+    }
+    if (knnk && nv != 0) {
+      VECTOR(*knnk)[nv-1] += VECTOR(*my_knn)[i];
+      VECTOR(deghist)[nv-1] += 1;
+    }
+  }
+
+  if (knnk) {
+    for (i=0; i<maxdeg; i++) {
+      long int dh=(long int) VECTOR(deghist)[i];
+      if (dh != 0) {
+	VECTOR(*knnk)[i] /= VECTOR(deghist)[i];
+      } else {
+	VECTOR(*knnk)[i] = mynan;
+      }
+    }
+    igraph_vector_destroy(&deghist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&deg);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  if (!knn) {
+    igraph_vector_destroy(&my_knn_v);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_strength
+ * Strength of the vertices, weighted vertex degree in other words.
+ * 
+ * In a weighted network the strength of a vertex is the sum of the
+ * weights of all incident edges. In a non-weighted network this is
+ * exactly the vertex degree.
+ * \param graph The input graph.
+ * \param res Pointer to an initialized vector, the result is stored
+ *   here. It will be resized as needed.
+ * \param vids The vertices for which the calculation is performed.
+ * \param mode Gives whether to count only outgoing (\c IGRAPH_OUT),
+ *   incoming (\c IGRAPH_IN) edges or both (\c IGRAPH_ALL).
+ * \param loops A logical scalar, whether to count loop edges as well.
+ * \param weights A vector giving the edge weights. If this is a NULL
+ *   pointer, then \ref igraph_degree() is called to perform the
+ *   calculation.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number vertices and
+ * edges.
+ * 
+ * \sa \ref igraph_degree() for the traditional, non-weighted version.
+ */
+
+int igraph_strength(const igraph_t *graph, igraph_vector_t *res,
+		    const igraph_vs_t vids, igraph_neimode_t mode,
+		    igraph_bool_t loops, const igraph_vector_t *weights) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vit_t vit;
+  long int no_vids;
+  igraph_vector_t neis;
+  long int i;
+
+  if (!weights)
+    return igraph_degree(graph, res, vids, mode, loops);
+  
+  if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  no_vids=IGRAPH_VIT_SIZE(vit);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&neis, no_of_nodes));
+  IGRAPH_CHECK(igraph_vector_resize(res, no_vids));
+  igraph_vector_null(res);
+  
+  if (loops) {
+    for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+      long int vid=IGRAPH_VIT_GET(vit);
+      long int j, n;
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) vid, mode));
+      n=igraph_vector_size(&neis);
+      for (j=0; j<n; j++) {
+	long int edge=(long int) VECTOR(neis)[j];
+	VECTOR(*res)[i] += VECTOR(*weights)[edge];
+      }
+    }
+  } else {
+    for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+      long int vid=IGRAPH_VIT_GET(vit);
+      long int j, n;
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) vid, mode));
+      n=igraph_vector_size(&neis);
+      for (j=0; j<n; j++) {
+	long int edge=(long int) VECTOR(neis)[j];
+	long int from=IGRAPH_FROM(graph, edge);
+	long int to=IGRAPH_TO(graph, edge);
+	if (from != to) {
+	  VECTOR(*res)[i] += VECTOR(*weights)[edge];
+	}
+      }
+    }
+  }
+  
+  igraph_vit_destroy(&vit);
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_diameter_dijkstra
+ * Weighted diameter using Dijkstra's algorithm, non-negative weights only.
+ * 
+ * The diameter of a graph is its longest geodesic. I.e. the
+ * (weighted) shortest path is calculated for all pairs of vertices
+ * and the longest one is the diameter.
+ * \param graph The input graph, can be directed or undirected.
+ * \param pres Pointer to a real number, if not \c NULL then it will contain 
+ *        the diameter (the actual distance).
+ * \param pfrom Pointer to an integer, if not \c NULL it will be set to the 
+ *        source vertex of the diameter path.
+ * \param pto Pointer to an integer, if not \c NULL it will be set to the 
+ *        target vertex of the diameter path.
+ * \param path Pointer to an initialized vector. If not \c NULL the actual 
+ *        longest geodesic path will be stored here. The vector will be 
+ *        resized as needed.
+ * \param directed Boolean, whether to consider directed
+ *        paths. Ignored for undirected graphs.
+ * \param unconn What to do if the graph is not connected. If
+ *        \c TRUE the longest geodesic within a component
+ *        will be returned, otherwise \c IGRAPH_INFINITY is
+ *        returned.
+ * \return Error code.
+ *
+ * Time complexity: O(|V||E|*log|E|), |V| is the number of vertices,
+ * |E| is the number of edges.
+ */
+
+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) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+
+  igraph_vector_t dist;
+  igraph_indheap_t Q;
+  igraph_inclist_t inclist;
+  igraph_vector_long_t already_added;
+  long int source;
+  igraph_neimode_t dirmode = directed ? IGRAPH_OUT : IGRAPH_ALL;
+
+  long int from=-1, to=-1;
+  igraph_real_t res=0;
+  long int nodes_reached=0;
+  
+  if (!weights) {
+    igraph_integer_t diameter;
+    IGRAPH_CHECK(igraph_diameter(graph, &diameter, pfrom, pto, path, directed, unconn));
+    *pres = diameter;
+    return IGRAPH_SUCCESS;
+  }
+
+  if (weights && igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+  
+  if (igraph_vector_min(weights) < 0) {
+    IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&already_added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &already_added);
+  IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
+  IGRAPH_CHECK(igraph_indheap_init(&Q, no_of_nodes));
+  IGRAPH_FINALLY(igraph_indheap_destroy, &Q);
+  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, dirmode));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
+  
+  for (source=0; source < no_of_nodes; source++) {
+
+    IGRAPH_PROGRESS("Weighted diameter: ", source*100.0/no_of_nodes, NULL);
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    igraph_indheap_push_with_index(&Q, source, -0);
+    VECTOR(already_added)[source] = source+1;
+    VECTOR(dist)[source] = 1.0;
+    nodes_reached = 0.0;
+
+    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;
+      long int nlen, j;
+      
+      if (mindist > res) {
+	res=mindist; from=source; to=minnei;
+      }
+      nodes_reached++;
+
+      neis=igraph_inclist_get(&inclist, minnei);
+      nlen=igraph_vector_size(neis);
+      for (j=0; j<nlen; j++) {
+	long int edge=(long int) VECTOR(*neis)[j];
+	long int tto=IGRAPH_OTHER(graph, edge, minnei);
+	igraph_real_t altdist=mindist + VECTOR(*weights)[edge];
+	igraph_real_t curdist= (VECTOR(already_added)[tto]==source+1) ? 
+	  VECTOR(dist)[tto] : 0;
+	
+	if (curdist==0) {
+	  /* First non-finite distance */
+	  VECTOR(already_added)[tto] = source+1;
+	  VECTOR(dist)[tto] = altdist+1.0;
+	  IGRAPH_CHECK(igraph_indheap_push_with_index(&Q, tto, -altdist));
+	} else if (altdist < curdist-1) {
+	  /* A shorter path */
+	  VECTOR(dist)[tto] = altdist+1.0;
+	  IGRAPH_CHECK(igraph_indheap_modify(&Q, tto, -altdist));
+	}
+      }
+      
+    } /* !igraph_indheap_empty(&Q) */
+
+    /* not connected, return infinity */
+    if (nodes_reached != no_of_nodes && !unconn) {
+      res=IGRAPH_INFINITY;
+      from=to=-1;
+      break;
+    }
+    
+  } /* source < no_of_nodes */
+  
+  igraph_inclist_destroy(&inclist);
+  igraph_indheap_destroy(&Q);
+  igraph_vector_destroy(&dist);
+  igraph_vector_long_destroy(&already_added);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  IGRAPH_PROGRESS("Weighted diameter: ", 100.0, NULL);
+  
+  if (pres) {
+    *pres=res;
+  }
+  if (pfrom) {
+    *pfrom=(igraph_integer_t) from;
+  }
+  if (pto) {
+    *pto=(igraph_integer_t) to;
+  }
+  if (path) {
+    if (!igraph_finite(res)) {
+      igraph_vector_clear(path);
+    } else {
+      igraph_vector_ptr_t tmpptr;
+      igraph_vector_ptr_init(&tmpptr, 1);
+      IGRAPH_FINALLY(igraph_vector_ptr_destroy, &tmpptr);
+      VECTOR(tmpptr)[0]=path;
+      IGRAPH_CHECK(igraph_get_shortest_paths_dijkstra(graph, 
+			      /*vertices=*/ &tmpptr, /*edges=*/ 0, 
+			      (igraph_integer_t) from,
+			      igraph_vss_1((igraph_integer_t) to), 
+			      weights, dirmode, /*predecessors=*/ 0,
+                              /*inbound_edges=*/ 0));
+      igraph_vector_ptr_destroy(&tmpptr);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+  }
+        
+  return 0;
+}
+
+/**
+ * \function igraph_sort_vertex_ids_by_degree
+ * \brief Calculate a list of vertex ids sorted by degree of the corresponding vertex.
+ * 
+ * The list of vertex ids is returned in a vector that is sorted
+ * in ascending or descending order of vertex degree.
+ *
+ * \param graph The input graph.
+ * \param outvids Pointer to an initialized vector that will be
+ *        resized and will contain the ordered vertex ids.
+ * \param vids Input vertex selector of vertex ids to include in
+ *        calculation.
+ * \param mode Defines the type of the degree.
+ *        \c IGRAPH_OUT, out-degree,
+ *        \c IGRAPH_IN, in-degree,
+ *        \c IGRAPH_ALL, total degree (sum of the
+ *        in- and out-degree). 
+ *        This parameter is ignored for undirected graphs. 
+ * \param loops Boolean, gives whether the self-loops should be
+ *        counted.
+ * \param order Specifies whether the ordering should be ascending
+ *        (\c IGRAPH_ASCENDING) or descending (\c IGRAPH_DESCENDING).
+ * \param only_indices If true, then return a sorted list of indices
+ *        into a vector corresponding to \c vids, rather than a list
+ *        of vertex ids. This parameter is ignored if \c vids is set
+ *        to all vertices via igraph_vs_all() or igraph_vss_all(),
+ *        because in this case the indices and vertex ids are the
+ *        same.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ *         \c IGRAPH_EINVMODE: invalid mode argument.
+ *
+ */
+
+int igraph_sort_vertex_ids_by_degree(const igraph_t *graph, 
+				     igraph_vector_t *outvids, 
+				     igraph_vs_t vids,
+				     igraph_neimode_t mode, 
+				     igraph_bool_t loops,
+             igraph_order_t order,
+				     igraph_bool_t only_indices) {
+  long int i;
+  igraph_vector_t degrees, vs_vec;
+  IGRAPH_VECTOR_INIT_FINALLY(&degrees, 0);
+  IGRAPH_CHECK(igraph_degree(graph, &degrees, vids, mode, loops));
+  IGRAPH_CHECK((int) igraph_vector_qsort_ind(&degrees, outvids,
+        order == IGRAPH_DESCENDING));
+  if (only_indices || igraph_vs_is_all(&vids) ) {
+    igraph_vector_destroy(&degrees);
+    IGRAPH_FINALLY_CLEAN(1);
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&vs_vec, 0);
+    IGRAPH_CHECK(igraph_vs_as_vector(graph, vids, &vs_vec));
+    for(i=0; i<igraph_vector_size(outvids); i++) {
+      VECTOR(*outvids)[i] = VECTOR(vs_vec)[(long int)VECTOR(*outvids)[i]];
+    }
+    igraph_vector_destroy(&vs_vec);
+    igraph_vector_destroy(&degrees);
+    IGRAPH_FINALLY_CLEAN(2);    
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_contract_vertices
+ * Replace multiple vertices with 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.
+ * \param graph The input graph, it can be directed or 
+ *        undirected.
+ * \param mapping A vector giving the mapping. For each 
+ *        vertex in the original graph, it should contain 
+ *        its id in the new graph.
+ * \param vertex_comb What to do with the vertex attributes. 
+ *        See the igraph manual section about attributes for 
+ *        details.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number 
+ * or vertices plus edges.
+ */
+
+int igraph_contract_vertices(igraph_t *graph,
+			     const igraph_vector_t *mapping,
+			     const igraph_attribute_combination_t 
+			     *vertex_comb) {
+  igraph_vector_t edges;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_bool_t vattr=vertex_comb && igraph_has_attribute_table();
+  igraph_t res;
+  long int e, last=-1;
+  long int no_new_vertices;
+
+  if (igraph_vector_size(mapping) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid mapping vector length", 
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+
+  if (no_of_nodes > 0)
+    last = (long int) igraph_vector_max(mapping);
+
+  for (e=0; e<no_of_edges; e++) {
+    long int from = IGRAPH_FROM(graph, e);
+    long int to = IGRAPH_TO(graph, e);
+
+    long int nfrom = (long int) VECTOR(*mapping)[from];
+    long int nto = (long int) VECTOR(*mapping)[to];
+    
+    igraph_vector_push_back(&edges, nfrom);
+    igraph_vector_push_back(&edges, nto);
+    
+    if (nfrom > last) { last = nfrom; }
+    if (nto   > last) { last = nto;   }
+  }
+ 
+  no_new_vertices = last+1;
+
+  IGRAPH_CHECK(igraph_create(&res, &edges, (igraph_integer_t) no_new_vertices,
+			     igraph_is_directed(graph)));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  IGRAPH_FINALLY(igraph_destroy, &res);
+  
+  IGRAPH_I_ATTRIBUTE_DESTROY(&res);
+  IGRAPH_I_ATTRIBUTE_COPY(&res, graph, /*graph=*/ 1,
+			  /*vertex=*/ 0, /*edge=*/ 1);
+  
+  if (vattr) {
+    long int i;
+    igraph_vector_ptr_t merges;
+    igraph_vector_t sizes;
+    igraph_vector_t *vecs;
+    
+    vecs=igraph_Calloc(no_new_vertices, igraph_vector_t);
+    if (!vecs) {
+      IGRAPH_ERROR("Cannot combine attributes while contracting"
+		   " vertices", IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_free, vecs);
+    IGRAPH_CHECK(igraph_vector_ptr_init(&merges, no_new_vertices));
+    IGRAPH_FINALLY(igraph_i_simplify_free, &merges);
+    IGRAPH_VECTOR_INIT_FINALLY(&sizes, no_new_vertices);
+    
+    for (i=0; i<no_of_nodes; i++) {
+      long int to=(long int) VECTOR(*mapping)[i];
+      VECTOR(sizes)[to] += 1;
+    }
+    for (i=0; i<no_new_vertices; i++) {
+      igraph_vector_t *v=&vecs[i];
+      IGRAPH_CHECK(igraph_vector_init(v, (long int) VECTOR(sizes)[i]));
+      igraph_vector_clear(v);
+      VECTOR(merges)[i]=v;
+    }
+    for (i=0; i<no_of_nodes; i++) {
+      long int to=(long int) VECTOR(*mapping)[i];
+      igraph_vector_t *v=&vecs[to];
+      igraph_vector_push_back(v, i);
+    }
+    
+    IGRAPH_CHECK(igraph_i_attribute_combine_vertices(graph, &res, 
+						     &merges,
+						     vertex_comb));
+    
+    igraph_vector_destroy(&sizes);
+    igraph_i_simplify_free(&merges);
+    igraph_free(vecs);
+    IGRAPH_FINALLY_CLEAN(3);
+  }
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_destroy(graph);
+  *graph=res;
+  
+  return 0;
+}
+
+/* Create the transitive closure of a tree graph. 
+   This is fairly simple, we just collect all ancestors of a vertex
+   using a depth-first search.     
+ */
+
+int igraph_transitive_closure_dag(const igraph_t *graph,
+				  igraph_t *closure) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t deg;
+  igraph_vector_t new_edges;
+  igraph_vector_t ancestors;
+  long int root;
+  igraph_vector_t neighbors;
+  igraph_stack_t path;
+  igraph_vector_bool_t done;
+
+  if (!igraph_is_directed(graph)) {
+    IGRAPH_ERROR("Tree transitive closure of a directed graph", 
+		 IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&new_edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&ancestors, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neighbors, 0);
+  IGRAPH_CHECK(igraph_stack_init(&path, 0));
+  IGRAPH_FINALLY(igraph_stack_destroy, &path);
+  IGRAPH_CHECK(igraph_vector_bool_init(&done, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &done);
+
+  IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS));
+
+#define STAR (-1)
+  
+  for (root=0; root<no_of_nodes; root++) {
+    if (VECTOR(deg)[root] != 0) { continue; }
+    IGRAPH_CHECK(igraph_stack_push(&path, root));
+
+    while (!igraph_stack_empty(&path)) {
+      long int node=(long int) igraph_stack_top(&path);
+      if (node == STAR) {
+	/* Leaving a node */
+	long int j, n;
+	igraph_stack_pop(&path);
+	node=(long int) igraph_stack_pop(&path);
+	if (!VECTOR(done)[node]) {
+	  igraph_vector_pop_back(&ancestors);
+	  VECTOR(done)[node]=1;
+	}
+	n=igraph_vector_size(&ancestors);
+	for (j=0; j<n; j++) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&new_edges, node));
+	  IGRAPH_CHECK(igraph_vector_push_back(&new_edges, 
+					       VECTOR(ancestors)[j]));
+	}
+      } else {
+	/* Getting into a node */
+	long int n, j;
+	if (!VECTOR(done)[node]) {
+	  IGRAPH_CHECK(igraph_vector_push_back(&ancestors, node));
+	}
+	IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, 
+				      (igraph_integer_t) node, IGRAPH_IN));
+	n=igraph_vector_size(&neighbors);
+	IGRAPH_CHECK(igraph_stack_push(&path, STAR));
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neighbors)[j];
+	  IGRAPH_CHECK(igraph_stack_push(&path, nei));
+	}
+      }
+    }
+  }
+
+#undef STAR
+
+  igraph_vector_bool_destroy(&done);
+  igraph_stack_destroy(&path);
+  igraph_vector_destroy(&neighbors);
+  igraph_vector_destroy(&ancestors);
+  igraph_vector_destroy(&deg);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  IGRAPH_CHECK(igraph_create(closure, &new_edges, (igraph_integer_t)no_of_nodes, 
+			     IGRAPH_DIRECTED));
+
+  igraph_vector_destroy(&new_edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_diversity
+ * Structural diversity index of the vertices
+ * 
+ * This measure was defined in Nathan Eagle, Michael Macy and Rob
+ * Claxton: Network Diversity and Economic Development, Science 328,
+ * 1029--1031, 2010. 
+ * 
+ * </para><para>
+ * It is simply the (normalized) Shannon entropy of the
+ * incident edges' weights. D(i)=H(i)/log(k[i]), and 
+ * H(i) = -sum(p[i,j] log(p[i,j]), j=1..k[i]), 
+ * where p[i,j]=w[i,j]/sum(w[i,l], l=1..k[i]),  k[i] is the (total)
+ * degree of vertex i, and w[i,j] is the weight of the edge(s) between
+ * vertex i and j. 
+ * \param graph The input graph, edge directions are ignored.
+ * \param weights The edge weights, in the order of the edge ids, must
+ *    have appropriate length.
+ * \param res An initialized vector, the results are stored here.
+ * \param vids Vector with the vertex ids for which to calculate the
+ *    measure.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear.
+ * 
+ */
+
+int igraph_diversity(igraph_t *graph, const igraph_vector_t *weights,
+		     igraph_vector_t *res, const igraph_vs_t vids) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t incident;
+  igraph_vit_t vit;
+  igraph_real_t s, ent, w;
+  int i, j, k;
+
+  if (!weights) { 
+    IGRAPH_ERROR("Edge weights must be given", IGRAPH_EINVAL);
+  }
+
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid edge weight vector length", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&incident, 10);
+
+  if (igraph_vs_is_all(&vids)) {
+    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+    for (i=0; i<no_of_nodes; i++) {
+      s = ent = 0.0;
+      IGRAPH_CHECK(igraph_incident(graph, &incident, i, /*mode=*/ IGRAPH_ALL));
+      for (j=0, k=(int) igraph_vector_size(&incident); j<k; j++) {
+        w = VECTOR(*weights)[(long int)VECTOR(incident)[j]];
+        s += w;
+        ent += (w * log(w));
+      }
+      VECTOR(*res)[i] = (log(s) - ent / s) / log(k);
+    }
+  } else {
+    IGRAPH_CHECK(igraph_vector_resize(res, 0));
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+    for (IGRAPH_VIT_RESET(vit), i=0; 
+         !IGRAPH_VIT_END(vit); 
+         IGRAPH_VIT_NEXT(vit), i++) {
+      long int v=IGRAPH_VIT_GET(vit);
+      s = ent = 0.0;
+      IGRAPH_CHECK(igraph_incident(graph, &incident, (igraph_integer_t) v, 
+				   /*mode=*/ IGRAPH_ALL));
+      for (j=0, k=(int) igraph_vector_size(&incident); j<k; j++) {
+        w = VECTOR(*weights)[(long int)VECTOR(incident)[j]];
+        s += w;
+        ent += (w * log(w));
+      }
+      IGRAPH_CHECK(igraph_vector_push_back(res, (log(s) - ent / s) / log(k)));
+    }
+
+    igraph_vit_destroy(&vit);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  igraph_vector_destroy(&incident);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+#define SUCCEED {   \
+  if (res) {        \
+    *res = 1;       \
+    return IGRAPH_SUCCESS; \
+  }                 \
+}
+
+#define FAIL {   \
+  if (res) {     \
+    *res = 0;    \
+    return IGRAPH_SUCCESS; \
+  }              \
+}
+
+/**
+ * \function igraph_is_degree_sequence
+ * Determines whether a degree sequence is valid.
+ *
+ * A sequence of n integers is a valid degree sequence if there exists some
+ * graph where the degree of the i-th vertex is equal to the i-th element of the
+ * sequence. Note that the graph may contain multiple or loop edges; if you are
+ * interested in whether the degrees of some \em simple graph may realize the
+ * given sequence, use \ref igraph_is_graphical_degree_sequence.
+ *
+ * </para><para>
+ * In particular, the function checks whether all the degrees are non-negative.
+ * 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.
+ *
+ * \param out_degrees  an integer vector specifying the degree sequence for
+ *     undirected graphs or the out-degree sequence for directed graphs.
+ * \param in_degrees   an integer vector specifying the in-degrees of the
+ *     vertices for directed graphs. For undirected graphs, this must be null.
+ * \param res  pointer to a boolean variable, the result will be stored here
+ * \return Error code.
+ * 
+ * Time complexity: O(n), where n is the length of the degree sequence.
+ */
+int igraph_is_degree_sequence(const igraph_vector_t *out_degrees,
+    const igraph_vector_t *in_degrees, igraph_bool_t *res) {
+  /* degrees must be non-negative */
+  if (igraph_vector_any_smaller(out_degrees, 0))
+    FAIL;
+  if (in_degrees && igraph_vector_any_smaller(in_degrees, 0))
+    FAIL;
+
+  if (in_degrees == 0) {
+    /* sum of degrees must be even */
+    if (((long int)igraph_vector_sum(out_degrees) % 2) != 0)
+      FAIL;
+  } else {
+    /* length of the two degree vectors must be equal */
+    if (igraph_vector_size(out_degrees) != igraph_vector_size(in_degrees))
+      FAIL;
+    /* sum of in-degrees must be equal to sum of out-degrees */
+    if (igraph_vector_sum(out_degrees) != igraph_vector_sum(in_degrees))
+      FAIL;
+  }
+
+  SUCCEED;
+  return 0;
+}
+
+int igraph_i_is_graphical_degree_sequence_undirected(
+    const igraph_vector_t *degrees, igraph_bool_t *res);
+int igraph_i_is_graphical_degree_sequence_directed(
+    const igraph_vector_t *out_degrees, const igraph_vector_t *in_degrees,
+    igraph_bool_t *res);
+
+/**
+ * \function igraph_is_graphical_degree_sequence
+ * Determines whether a sequence of integers can be a degree sequence of some
+ * simple graph.
+ *
+ * </para><para>
+ * References:
+ *
+ * </para><para>
+ * Hakimi SL: On the realizability of a set of integers as degrees of the
+ * vertices of a simple graph. J SIAM Appl Math 10:496-506, 1962.
+ *
+ * </para><para>
+ * PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm
+ * to realize graphical degree sequences of directed graphs. The Electronic
+ * Journal of Combinatorics 17(1):R66, 2010.
+ *
+ * \param out_degrees  an integer vector specifying the degree sequence for
+ *     undirected graphs or the out-degree sequence for directed graphs.
+ * \param in_degrees   an integer vector specifying the in-degrees of the
+ *     vertices for directed graphs. For undirected graphs, this must be null.
+ * \param res  pointer to a boolean variable, the result will be stored here
+ * \return Error code.
+ * 
+ * Time complexity: O(n^2 log n) where n is the length of the degree sequence.
+ */
+int igraph_is_graphical_degree_sequence(const igraph_vector_t *out_degrees,
+    const igraph_vector_t *in_degrees, igraph_bool_t *res) {
+  IGRAPH_CHECK(igraph_is_degree_sequence(out_degrees, in_degrees, res));
+  if (!*res)
+    FAIL;
+
+  if (igraph_vector_size(out_degrees) == 0)
+    SUCCEED;
+
+  if (in_degrees == 0) {
+    return igraph_i_is_graphical_degree_sequence_undirected(out_degrees, res);
+  } else {
+    return igraph_i_is_graphical_degree_sequence_directed(out_degrees, in_degrees, res);
+  }
+}
+
+int igraph_i_is_graphical_degree_sequence_undirected(
+    const igraph_vector_t *degrees, igraph_bool_t *res) {
+  igraph_vector_t work;
+  igraph_integer_t degree;
+  long int i, vcount;
+
+  IGRAPH_CHECK(igraph_vector_copy(&work, degrees));
+  IGRAPH_FINALLY(igraph_vector_destroy, &work);
+
+  vcount = igraph_vector_size(&work);
+  *res = 0;
+  while (vcount) {
+    /* RFE: theoretically, a counting sort would be only O(n) here and not
+     * O(n log n) since the degrees are bounded from above by n. I am not sure
+     * whether it's worth the fuss, though, sort() in the C library is highly
+     * optimized */
+    igraph_vector_sort(&work);
+    if (VECTOR(work)[0] < 0)
+      break;
+
+    degree = (igraph_integer_t) igraph_vector_pop_back(&work);
+    vcount--;
+
+    if (degree == 0) {
+      *res = 1;
+      break;
+    }
+
+    if (degree > vcount)
+      break;
+
+    for (i = vcount-degree; i < vcount; i++) {
+      VECTOR(work)[i]--;
+    }
+  }
+
+  igraph_vector_destroy(&work);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+typedef struct {
+	igraph_vector_t* first;
+	igraph_vector_t* second;
+} igraph_i_qsort_dual_vector_cmp_data_t;
+
+int igraph_i_qsort_dual_vector_cmp_asc(void* data, const void *p1, const void *p2) {
+	igraph_i_qsort_dual_vector_cmp_data_t* sort_data =
+		(igraph_i_qsort_dual_vector_cmp_data_t*)data;
+	long int index1 = *((long int*)p1);
+	long int index2 = *((long int*)p2);
+	if (VECTOR(*sort_data->first)[index1] < VECTOR(*sort_data->first)[index2])
+		return -1;
+	if (VECTOR(*sort_data->first)[index1] > VECTOR(*sort_data->first)[index2])
+		return 1;
+	if (VECTOR(*sort_data->second)[index1] < VECTOR(*sort_data->second)[index2])
+		return -1;
+	if (VECTOR(*sort_data->second)[index1] > VECTOR(*sort_data->second)[index2])
+		return 1;
+	return 0;
+}
+
+int igraph_i_is_graphical_degree_sequence_directed(
+    const igraph_vector_t *out_degrees, const igraph_vector_t *in_degrees,
+    igraph_bool_t *res) {
+  igraph_vector_t work_in;
+	igraph_vector_t work_out;
+	igraph_vector_long_t out_vertices;
+	igraph_vector_long_t index_array;
+	long int i, vcount, u, v, degree;
+	long int index_array_unused_prefix_length, nonzero_indegree_count;
+	igraph_i_qsort_dual_vector_cmp_data_t sort_data;
+
+  IGRAPH_CHECK(igraph_vector_copy(&work_in, in_degrees));
+  IGRAPH_FINALLY(igraph_vector_destroy, &work_in);
+  IGRAPH_CHECK(igraph_vector_copy(&work_out, out_degrees));
+  IGRAPH_FINALLY(igraph_vector_destroy, &work_in);
+	IGRAPH_CHECK(igraph_vector_long_init(&out_vertices, 0));
+	IGRAPH_FINALLY(igraph_vector_long_destroy, &out_vertices);
+	
+  vcount = igraph_vector_size(&work_out);
+	IGRAPH_CHECK(igraph_vector_long_reserve(&out_vertices, vcount));
+
+	IGRAPH_CHECK(igraph_vector_long_init(&index_array, vcount));
+	IGRAPH_FINALLY(igraph_vector_long_destroy, &index_array);
+
+	/* Set up the auxiliary struct for sorting */
+  sort_data.first  = &work_in;
+  sort_data.second = &work_out;
+
+	/* Fill the index array. This will contain the indices of the "active" vertices,
+	 * i.e. those that have a non-zero in- or out-degree */
+	nonzero_indegree_count = 0;
+	for (i = 0; i < vcount; i++) {
+		if (VECTOR(work_in)[i] > 0) {
+			VECTOR(index_array)[i] = i;
+			nonzero_indegree_count++;
+		}
+		if (VECTOR(work_out)[i] > 0) {
+			IGRAPH_CHECK(igraph_vector_long_push_back(&out_vertices, i));
+		}
+	}
+
+  *res = 0;
+	index_array_unused_prefix_length = 0;
+  while (!igraph_vector_long_empty(&out_vertices)) {
+		/* Find a vertex with non-zero out-degree. */
+		u = igraph_vector_long_pop_back(&out_vertices);
+		/*
+		printf("Using vertex %ld\n", (long int)u);
+		printf("  Degree vectors:\n  ");
+		igraph_vector_print(&work_out); printf("  ");
+		igraph_vector_print(&work_in);
+		*/
+
+		/* Remember the degree of u and clear the degree itself */
+		degree = (long int) VECTOR(work_out)[u];
+		VECTOR(work_out)[u] = 0;
+		/* printf("  Out-degree: %ld\n", (long int)degree); */
+
+		/* Is the degree larger than the number of vertices with nonzero in-degree?
+		 * (Make sure that u is excluded from the vertices with nonzero in-degree).
+		 */
+		if (degree > nonzero_indegree_count - (VECTOR(work_in)[u] > 0 ? 1 : 0))
+			break;
+
+		/* Find the prefix of index_array that consists solely of vertices with
+		 * zero indegree. We don't need to sort these */
+		while (index_array_unused_prefix_length < vcount &&
+				VECTOR(work_in)[VECTOR(index_array)[index_array_unused_prefix_length]] == 0) {
+			index_array_unused_prefix_length++;
+			nonzero_indegree_count--;
+		}
+
+		/* Sort work_in first and then sort work_out for equal indegrees only. This
+		 * is done by sorting an index vector first; indexing work_out and work_in by
+		 * the sorted index vector would then give the sorted order of these vectors. */
+		igraph_qsort_r(VECTOR(index_array) + index_array_unused_prefix_length,
+			       (size_t) nonzero_indegree_count, 
+			       sizeof(long int), &sort_data,
+				igraph_i_qsort_dual_vector_cmp_asc);
+		/* printf("  Sorted index array:\n  ");
+		igraph_vector_long_print(&index_array); */
+
+		/* Create edges from u to the vertices with the largest in-degrees */
+		i = vcount;
+		while (degree > 0) {
+			v = VECTOR(index_array)[--i];
+			if (u == v) {
+				/* Avoid creating a loop edge */
+				continue;
+			}
+      VECTOR(work_in)[v]--;
+		  /* printf("  Created edge from %ld to %ld, in-degree is now %ld\n", 
+					(long int)u, (long int)v, (long int)VECTOR(work_in)[v]); */
+			degree--;
+    }
+	}
+
+	if (igraph_vector_long_empty(&out_vertices)) {
+		/* No more vertices with non-zero outdegree, so we were successful */
+		*res = 1;
+	}
+
+	igraph_vector_long_destroy(&index_array);
+	igraph_vector_long_destroy(&out_vertices);
+  igraph_vector_destroy(&work_out);
+  igraph_vector_destroy(&work_in);
+  IGRAPH_FINALLY_CLEAN(4);
+
+	return IGRAPH_SUCCESS;
+}
+
+#undef SUCCEED
+#undef FAIL
diff --git a/src/structure_generators.c b/src/structure_generators.c
new file mode 100644
index 0000000..97dcd88
--- /dev/null
+++ b/src/structure_generators.c
@@ -0,0 +1,2288 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_constructors.h"
+#include "igraph_memory.h"
+#include "igraph_interface.h"
+#include "igraph_attributes.h"
+#include "igraph_adjlist.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_dqueue.h"
+#include "config.h"
+
+#include <stdarg.h>
+#include <math.h>
+#include <string.h>
+
+/** 
+ * \section about_generators
+ *
+ * <para>Graph generators create graphs.</para>
+ * 
+ * <para>Almost all functions which create graph objects are documented
+ * here. The exceptions are \ref igraph_subgraph() and alike, these 
+ * create graphs based on another graph.</para>
+ */
+
+
+/**
+ * \ingroup generators
+ * \function igraph_create
+ * \brief Creates a graph with the specified edges.
+ * 
+ * \param graph An uninitialized graph object.
+ * \param edges The edges to add, the first two elements are the first
+ *        edge, etc.
+ * \param n The number of vertices in the graph, if smaller or equal
+ *        to the highest vertex id in the \p edges vector it
+ *        will be increased automatically. So it is safe to give 0
+ *        here.
+ * \param directed Boolean, whether to create a directed graph or
+ *        not. If yes, then the first edge points from the first
+ *        vertex id in \p edges to the second, etc.
+ * \return Error code:
+ *         \c IGRAPH_EINVEVECTOR: invalid edges
+ *         vector (odd number of vertices).
+ *         \c IGRAPH_EINVVID: invalid (negative)
+ *         vertex id. 
+ *
+ * Time complexity: O(|V|+|E|),
+ * |V| is the number of vertices,
+ * |E| the number of edges in the
+ * graph. 
+ * 
+ * \example examples/simple/igraph_create.c
+ */
+int igraph_create(igraph_t *graph, const igraph_vector_t *edges,
+		igraph_integer_t n, igraph_bool_t directed) {
+  igraph_real_t max=igraph_vector_max(edges)+1;
+
+  if (igraph_vector_size(edges) % 2 != 0) {
+    IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVEVECTOR);
+  }
+  if (!igraph_vector_isininterval(edges, 0, max-1)) {
+    IGRAPH_ERROR("Invalid (negative) vertex id", IGRAPH_EINVVID);
+  }
+
+  IGRAPH_CHECK(igraph_empty(graph, n, directed));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  if (igraph_vector_size(edges)>0) {
+    igraph_integer_t vc=igraph_vcount(graph);
+    if (vc < max) {
+      IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) (max-vc), 0));
+    }
+    IGRAPH_CHECK(igraph_add_edges(graph, edges, 0));
+  }
+
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix, 
+				igraph_vector_t *edges);
+int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix, 
+			   igraph_vector_t *edges);
+int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix, 
+			     igraph_vector_t *edges);
+int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix, 
+			     igraph_vector_t *edges);
+int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix, 
+			   igraph_vector_t *edges);
+
+int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j, k;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<no_of_nodes; j++) {
+      long int M=(long int) MATRIX(*adjmatrix, i, j);
+      for (k=0; k<M; k++) {
+	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      }
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j, k;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      long int M1=(long int) MATRIX(*adjmatrix, i, j);
+      long int M2=(long int) MATRIX(*adjmatrix, j, i);
+      if (M1<M2) { M1=M2; }
+      for (k=0; k<M1; k++) {
+	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      }
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j, k;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      long int M=(long int) MATRIX(*adjmatrix, i, j);
+      for (k=0; k<M; k++) {
+	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      }
+    }
+  }
+  return 0;
+}
+
+int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j, k;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<=i; j++) {
+      long int M=(long int) MATRIX(*adjmatrix, i, j);
+      for (k=0; k<M; k++) {
+	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      }
+    }
+  }
+  return 0;
+}
+
+int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j, k;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      long int M1=(long int) MATRIX(*adjmatrix, i, j);
+      long int M2=(long int) MATRIX(*adjmatrix, j, i);
+      if (M1>M2) { M1=M2; }
+      for (k=0; k<M1; k++) {
+	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      }
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_adjacency
+ * \brief Creates a graph object from an adjacency matrix.
+ * 
+ * The order of the vertices in the matrix is preserved, i.e. the vertex 
+ * corresponding to the first row/column will be vertex with id 0, the 
+ * next row is for vertex 1, etc.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param adjmatrix The adjacency matrix. How it is interpreted
+ *        depends on the \p mode argument.
+ * \param mode Constant to specify how the given matrix is interpreted
+ *        as an adjacency matrix. Possible values
+ *        (A(i,j) 
+ *        is the element in row i and column
+ *        j in the adjacency matrix
+ *        \p adjmatrix): 
+ *        \clist
+ *        \cli IGRAPH_ADJ_DIRECTED
+ *          the graph will be directed and
+ *          an element gives the number of edges between two vertices.
+ *        \cli IGRAPH_ADJ_UNDIRECTED
+ *          this is the same as \c IGRAPH_ADJ_MAX,
+ *          for convenience. 
+ *        \cli IGRAPH_ADJ_MAX
+ *          undirected graph will be created
+ *          and the number of edges between vertices
+ *          i and 
+ *          j is
+ *          max(A(i,j), A(j,i)). 
+ *        \cli IGRAPH_ADJ_MIN
+ *          undirected graph will be created
+ *          with min(A(i,j), A(j,i))
+ *          edges between vertices
+ *          i and
+ *          j. 
+ *        \cli IGRAPH_ADJ_PLUS 
+ *          undirected graph will be created 
+ *          with A(i,j)+A(j,i) edges
+ *          between vertices
+ *          i and
+ *          j.  
+ *        \cli IGRAPH_ADJ_UPPER 
+ *          undirected graph will be created,
+ *          only the upper right triangle (including the diagonal) is
+ *          used for the number of edges.
+ *        \cli IGRAPH_ADJ_LOWER 
+ *          undirected graph will be created,
+ *          only the lower left triangle (including the diagonal) is 
+ *          used for creating the edges.
+ *       \endclist
+ * \return Error code,
+ *         \c IGRAPH_NONSQUARE: non-square matrix.
+ * 
+ * Time complexity: O(|V||V|),
+ * |V| is the number of vertices in the graph.
+ * 
+ * \example examples/simple/igraph_adjacency.c
+ */
+
+int igraph_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,
+		     igraph_adjacency_t mode) {
+
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int no_of_nodes;
+
+  /* Some checks */
+  if (igraph_matrix_nrow(adjmatrix) != igraph_matrix_ncol(adjmatrix)) {
+    IGRAPH_ERROR("Non-square matrix", IGRAPH_NONSQUARE);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  
+  /* Collect the edges */
+  no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  switch (mode) {
+  case IGRAPH_ADJ_DIRECTED:
+    IGRAPH_CHECK(igraph_i_adjacency_directed(adjmatrix, &edges));
+    break;
+  case IGRAPH_ADJ_MAX:
+    IGRAPH_CHECK(igraph_i_adjacency_max(adjmatrix, &edges));
+    break;
+  case IGRAPH_ADJ_UPPER:
+    IGRAPH_CHECK(igraph_i_adjacency_upper(adjmatrix, &edges));
+    break;
+  case IGRAPH_ADJ_LOWER:
+    IGRAPH_CHECK(igraph_i_adjacency_lower(adjmatrix, &edges));
+    break;
+  case IGRAPH_ADJ_MIN:
+    IGRAPH_CHECK(igraph_i_adjacency_min(adjmatrix, &edges));
+    break;
+  case IGRAPH_ADJ_PLUS:
+    IGRAPH_CHECK(igraph_i_adjacency_directed(adjmatrix, &edges));
+    break;
+  }
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     (mode == IGRAPH_ADJ_DIRECTED))); 
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+int igraph_i_weighted_adjacency_directed(const igraph_matrix_t *adjmatrix,
+					 igraph_vector_t *edges, 
+					 igraph_vector_t *weights, 
+					 igraph_bool_t loops);
+int igraph_i_weighted_adjacency_plus(const igraph_matrix_t *adjmatrix,
+				     igraph_vector_t *edges,
+				     igraph_vector_t *weights, 
+				     igraph_bool_t loops);
+int igraph_i_weighted_adjacency_max(const igraph_matrix_t *adjmatrix,
+				    igraph_vector_t *edges, 
+				    igraph_vector_t *weights, 
+				    igraph_bool_t loops);
+int igraph_i_weighted_adjacency_upper(const igraph_matrix_t *adjmatrix,
+				      igraph_vector_t *edges, 
+				      igraph_vector_t *weights,
+				      igraph_bool_t loops);
+int igraph_i_weighted_adjacency_lower(const igraph_matrix_t *adjmatrix,
+				      igraph_vector_t *edges, 
+				      igraph_vector_t *weights, 
+				      igraph_bool_t loops);
+int igraph_i_weighted_adjacency_min(const igraph_matrix_t *adjmatrix,
+				    igraph_vector_t *edges,
+				    igraph_vector_t *weights, 
+				    igraph_bool_t loops);
+
+int igraph_i_weighted_adjacency_directed(const igraph_matrix_t *adjmatrix,
+					 igraph_vector_t *edges, 
+					 igraph_vector_t *weights, 
+					 igraph_bool_t loops) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<no_of_nodes; j++) {
+      igraph_real_t M=MATRIX(*adjmatrix, i, j);
+      if (M == 0.0) continue;
+      if (i==j && !loops) { continue; }
+      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_i_weighted_adjacency_plus(const igraph_matrix_t *adjmatrix,
+				     igraph_vector_t *edges,
+				     igraph_vector_t *weights, 
+				     igraph_bool_t loops) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      igraph_real_t M=MATRIX(*adjmatrix, i, j) + MATRIX(*adjmatrix, j, i);
+      if (M == 0.0) continue;
+      if (i==j && !loops) { continue; }
+      if (i == j) M /= 2;
+      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_i_weighted_adjacency_max(const igraph_matrix_t *adjmatrix,
+				    igraph_vector_t *edges, 
+				    igraph_vector_t *weights, 
+				    igraph_bool_t loops) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      igraph_real_t M1=MATRIX(*adjmatrix, i, j);
+      igraph_real_t M2=MATRIX(*adjmatrix, j, i);
+      if (M1<M2) { M1=M2; }
+      if (M1 == 0.0) continue;
+      if (i==j && !loops) { continue; }
+      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      IGRAPH_CHECK(igraph_vector_push_back(weights, M1));
+    }
+  }
+  return 0;
+}
+
+int igraph_i_weighted_adjacency_upper(const igraph_matrix_t *adjmatrix,
+				      igraph_vector_t *edges, 
+				      igraph_vector_t *weights,
+				      igraph_bool_t loops) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      igraph_real_t M=MATRIX(*adjmatrix, i, j);
+      if (M == 0.0) continue;
+      if (i==j && !loops) { continue; }
+      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
+    }
+  }
+  return 0;
+}
+
+int igraph_i_weighted_adjacency_lower(const igraph_matrix_t *adjmatrix,
+				      igraph_vector_t *edges, 
+				      igraph_vector_t *weights, 
+				      igraph_bool_t loops) {
+
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=0; j<=i; j++) {
+      igraph_real_t M=MATRIX(*adjmatrix, i, j);
+      if (M == 0.0) continue;
+      if (i==j && !loops) { continue; }
+      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
+    }
+  }
+  return 0;
+}
+
+int igraph_i_weighted_adjacency_min(const igraph_matrix_t *adjmatrix,
+				    igraph_vector_t *edges,
+				    igraph_vector_t *weights, 
+				    igraph_bool_t loops) {
+  
+  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  long int i, j;
+  
+  for (i=0; i<no_of_nodes; i++) {
+    for (j=i; j<no_of_nodes; j++) {
+      igraph_real_t M1=MATRIX(*adjmatrix, i, j);
+      igraph_real_t M2=MATRIX(*adjmatrix, j, i);
+      if (M1>M2) { M1=M2; }
+      if (M1 == 0.0) continue;
+      if (i==j && !loops) { continue; }
+      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
+      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
+      IGRAPH_CHECK(igraph_vector_push_back(weights, M1));
+    }
+  }
+  
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_weighted_adjacency
+ * \brief Creates a graph object from a weighted adjacency matrix.
+ * 
+ * The order of the vertices in the matrix is preserved, i.e. the vertex 
+ * corresponding to the first row/column will be vertex with id 0, the 
+ * next row is for vertex 1, etc.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param adjmatrix The weighted adjacency matrix. How it is interpreted
+ *        depends on the \p mode argument. The common feature is that
+ *        edges with zero weights are considered nonexistent (however,
+ *        negative weights are permitted).
+ * \param mode Constant to specify how the given matrix is interpreted
+ *        as an adjacency matrix. Possible values
+ *        (A(i,j) 
+ *        is the element in row i and column
+ *        j in the adjacency matrix
+ *        \p adjmatrix): 
+ *        \clist
+ *        \cli IGRAPH_ADJ_DIRECTED
+ *          the graph will be directed and
+ *          an element gives the weight of the edge between two vertices.
+ *        \cli IGRAPH_ADJ_UNDIRECTED
+ *          this is the same as \c IGRAPH_ADJ_MAX,
+ *          for convenience. 
+ *        \cli IGRAPH_ADJ_MAX
+ *          undirected graph will be created
+ *          and the weight of the edge between vertices
+ *          i and 
+ *          j is
+ *          max(A(i,j), A(j,i)). 
+ *        \cli IGRAPH_ADJ_MIN
+ *          undirected graph will be created
+ *          with edge weight min(A(i,j), A(j,i))
+ *          between vertices
+ *          i and
+ *          j. 
+ *        \cli IGRAPH_ADJ_PLUS 
+ *          undirected graph will be created 
+ *          with edge weight A(i,j)+A(j,i)
+ *          between vertices
+ *          i and
+ *          j.  
+ *        \cli IGRAPH_ADJ_UPPER 
+ *          undirected graph will be created,
+ *          only the upper right triangle (including the diagonal) is
+ *          used for the edge weights.
+ *        \cli IGRAPH_ADJ_LOWER 
+ *          undirected graph will be created,
+ *          only the lower left triangle (including the diagonal) is 
+ *          used for the edge weights. 
+ *       \endclist
+ * \param attr the name of the attribute that will store the edge weights.
+ *         If \c NULL , it will use \c weight as the attribute name.
+ * \param loops Logical scalar, whether to ignore the diagonal elements 
+ *         in the adjacency matrix. 
+ * \return Error code,
+ *         \c IGRAPH_NONSQUARE: non-square matrix.
+ * 
+ * Time complexity: O(|V||V|),
+ * |V| is the number of vertices in the graph.
+ * 
+ * \example examples/simple/igraph_weighted_adjacency.c
+ */
+
+int igraph_weighted_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,
+			      igraph_adjacency_t mode, const char* attr, 
+			      igraph_bool_t loops) {
+
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  igraph_vector_t weights=IGRAPH_VECTOR_NULL;
+  const char* default_attr = "weight";
+  igraph_vector_ptr_t attr_vec;
+  igraph_attribute_record_t attr_rec;
+  long int no_of_nodes;
+
+  /* Some checks */
+  if (igraph_matrix_nrow(adjmatrix) != igraph_matrix_ncol(adjmatrix)) {
+    IGRAPH_ERROR("Non-square matrix", IGRAPH_NONSQUARE);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&weights, 0);
+  IGRAPH_VECTOR_PTR_INIT_FINALLY(&attr_vec, 1);
+
+  /* Collect the edges */
+  no_of_nodes=igraph_matrix_nrow(adjmatrix);
+  switch (mode) {
+  case IGRAPH_ADJ_DIRECTED:
+    IGRAPH_CHECK(igraph_i_weighted_adjacency_directed(adjmatrix, &edges, 
+						      &weights, loops));
+    break;
+  case IGRAPH_ADJ_MAX:
+    IGRAPH_CHECK(igraph_i_weighted_adjacency_max(adjmatrix, &edges, 
+						 &weights, loops));
+    break;
+  case IGRAPH_ADJ_UPPER:
+    IGRAPH_CHECK(igraph_i_weighted_adjacency_upper(adjmatrix, &edges,
+						   &weights, loops));
+    break;
+  case IGRAPH_ADJ_LOWER:
+    IGRAPH_CHECK(igraph_i_weighted_adjacency_lower(adjmatrix, &edges, 
+						   &weights, loops));
+    break;
+  case IGRAPH_ADJ_MIN:
+    IGRAPH_CHECK(igraph_i_weighted_adjacency_min(adjmatrix, &edges,
+						 &weights, loops));
+    break;
+  case IGRAPH_ADJ_PLUS:
+    IGRAPH_CHECK(igraph_i_weighted_adjacency_plus(adjmatrix, &edges,
+						  &weights, loops));
+    break;
+  }
+
+  /* Prepare attribute record */
+  attr_rec.name = attr ? attr : default_attr;
+  attr_rec.type = IGRAPH_ATTRIBUTE_NUMERIC;
+  attr_rec.value = &weights;
+  VECTOR(attr_vec)[0] = &attr_rec;
+
+  /* Create graph */
+  IGRAPH_CHECK(igraph_empty(graph, (igraph_integer_t) no_of_nodes, 
+			    (mode == IGRAPH_ADJ_DIRECTED)));
+  IGRAPH_FINALLY(igraph_destroy, graph);
+  if (igraph_vector_size(&edges)>0) {
+    IGRAPH_CHECK(igraph_add_edges(graph, &edges, &attr_vec));
+  }
+  IGRAPH_FINALLY_CLEAN(1);
+
+  /* Cleanup */
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&weights);
+  igraph_vector_ptr_destroy(&attr_vec);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_star
+ * \brief Creates a \em star graph, every vertex connects only to the center.
+ *
+ * \param graph Pointer to an uninitialized graph object, this will
+ *        be the result.
+ * \param n Integer constant, the number of vertices in the graph.
+ * \param mode Constant, gives the type of the star graph to
+ *        create. Possible values:
+ *        \clist
+ *        \cli IGRAPH_STAR_OUT
+ *          directed star graph, edges point
+ *          \em from the center to the other vertices.
+ *        \cli IGRAPH_STAR_IN
+ *          directed star graph, edges point
+ *          \em to the center from the other vertices.
+ *        \cli IGRAPH_STAR_MUTUAL
+ *          directed star graph with mutual edges.
+ *        \cli IGRAPH_STAR_UNDIRECTED 
+ *          an undirected star graph is
+ *          created. 
+ *        \endclist
+ * \param center Id of the vertex which will be the center of the
+ *          graph. 
+ * \return Error code:
+ *         \clist
+ *         \cli IGRAPH_EINVVID 
+ *           invalid number of vertices.
+ *         \cli IGRAPH_EINVAL 
+ *           invalid center vertex.
+ *         \cli IGRAPH_EINVMODE 
+ *           invalid mode argument.
+ *         \endclist
+ * 
+ * Time complexity: O(|V|), the
+ * number of vertices in the graph.
+ *
+ * \sa \ref igraph_lattice(), \ref igraph_ring(), \ref igraph_tree()
+ * for creating other regular structures.
+ * 
+ * \example examples/simple/igraph_star.c
+ */
+
+int igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode_t mode, 
+		igraph_integer_t center) {
+
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int i;
+
+  if (n<0) { 
+    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVVID);
+  }
+  if (center<0 || center >n-1) {
+    IGRAPH_ERROR("Invalid center vertex", IGRAPH_EINVAL);
+  }
+  if (mode != IGRAPH_STAR_OUT && mode != IGRAPH_STAR_IN && 
+      mode != IGRAPH_STAR_MUTUAL && mode != IGRAPH_STAR_UNDIRECTED) {
+    IGRAPH_ERROR("invalid mode", IGRAPH_EINVMODE);
+  }
+  
+  if (mode != IGRAPH_STAR_MUTUAL) {
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, (n-1)*2);
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, (n-1)*2*2);
+  }
+  
+  if (mode == IGRAPH_STAR_OUT) {
+    for (i=0; i<center; i++) {
+      VECTOR(edges)[2*i]=center;
+      VECTOR(edges)[2*i+1]=i;
+    }
+    for (i=center+1; i<n; i++) {
+      VECTOR(edges)[2*(i-1)]=center;
+      VECTOR(edges)[2*(i-1)+1]=i;
+    }
+  } else if (mode == IGRAPH_STAR_MUTUAL) {
+    for (i=0; i<center; i++) {
+      VECTOR(edges)[4*i]=center;
+      VECTOR(edges)[4*i+1]=i;
+      VECTOR(edges)[4*i+2]=i;
+      VECTOR(edges)[4*i+3]=center;
+    }
+    for (i=center+1; i<n; i++) {
+      VECTOR(edges)[4*i-4]=center;
+      VECTOR(edges)[4*i-3]=i;
+      VECTOR(edges)[4*i-2]=i;
+      VECTOR(edges)[4*i-1]=center;
+    }
+  } else {
+    for (i=0; i<center; i++) {
+      VECTOR(edges)[2*i+1]=center;
+      VECTOR(edges)[2*i]=i;
+    }
+    for (i=center+1; i<n; i++) {
+      VECTOR(edges)[2*(i-1)+1]=center;
+      VECTOR(edges)[2*(i-1)]=i;
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, 0, 
+			     (mode != IGRAPH_STAR_UNDIRECTED)));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \ingroup generators 
+ * \function igraph_lattice
+ * \brief Creates most kinds of lattices.
+ *
+ * \param graph An uninitialized graph object.
+ * \param dimvector Vector giving the sizes of the lattice in each of
+ *        its dimensions. Ie. the dimension of the lattice will be the
+ *        same as the length of this vector.
+ * \param nei Integer value giving the distance (number of steps)
+ *        within which two vertices will be connected.
+ * \param directed Boolean, whether to create a directed graph. The
+ *        direction of the edges is determined by the generation
+ *        algorithm and is unlikely to suit you, so this isn't a very
+ *        useful option.
+ * \param mutual Boolean, if the graph is directed this gives whether
+ *        to create all connections as mutual.
+ * \param circular Boolean, defines whether the generated lattice is
+ *        periodic.
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid (negative)
+ *         dimension vector. 
+ *
+ * Time complexity: if \p nei is less than two then it is O(|V|+|E|) (as
+ * far as I remember), |V| and |E| are the number of vertices 
+ * and edges in the generated graph. Otherwise it is O(|V|*d^o+|E|), d
+ * is the average degree of the graph, o is the \p nei argument.
+ */
+int igraph_lattice(igraph_t *graph, const igraph_vector_t *dimvector,
+		igraph_integer_t nei, igraph_bool_t directed, igraph_bool_t mutual,
+		igraph_bool_t circular) {
+
+  long int dims=igraph_vector_size(dimvector);
+  long int no_of_nodes=(long int) igraph_vector_prod(dimvector);
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int *coords, *weights;
+  long int i, j;
+  int carry, pos;
+
+  if (igraph_vector_any_smaller(dimvector, 0)) {
+    IGRAPH_ERROR("Invalid dimension vector", IGRAPH_EINVAL);
+  }
+
+  /* init coords & weights */
+
+  coords=igraph_Calloc(dims, long int);
+  if (coords==0) {
+    IGRAPH_ERROR("lattice failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, coords);	/* TODO: hack */
+  weights=igraph_Calloc(dims, long int);
+  if (weights == 0) {
+    IGRAPH_ERROR("lattice failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(free, weights);
+  if (dims > 0) {
+    weights[0]=1;
+    for (i=1; i<dims; i++) {
+      weights[i]=weights[i-1] * (long int) VECTOR(*dimvector)[i-1];
+    }
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_nodes*dims +
+				     mutual*directed * no_of_nodes*dims));
+
+  for (i=0; i<no_of_nodes; i++) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    for (j=0; j<dims; j++) {
+      if (circular || coords[j] != VECTOR(*dimvector)[j]-1) {
+	long int new_nei;
+	if (coords[j] != VECTOR(*dimvector)[j]-1) {
+	  new_nei = i + weights[j] + 1;
+	} else {
+	  new_nei = i - (long int) (VECTOR(*dimvector)[j]-1) * weights[j] + 1;
+	}
+	if (new_nei != i+1 && 
+	    (VECTOR(*dimvector)[j] != 2 || coords[j] != 1 || directed)) {
+	  igraph_vector_push_back(&edges, i); /* reserved */
+	  igraph_vector_push_back(&edges, new_nei-1); /* reserved */
+	}
+      } /* if circular || coords[j] */
+      if (mutual && directed && (circular || coords[j] != 0)) {
+	long int new_nei;
+	if (coords[j]!=0) {
+	  new_nei=i-weights[j]+1;
+	} else {
+	  new_nei=i + (long int) (VECTOR(*dimvector)[j]-1) * weights[j]+1;
+	}
+	if (new_nei != i+1 && 
+	    (VECTOR(*dimvector)[j] != 2 || !circular)) {
+	  igraph_vector_push_back(&edges, i); /* reserved */
+	  igraph_vector_push_back(&edges, new_nei-1); /* reserved */
+	}
+      } /* if circular || coords[0] */
+    } /* for j<dims */
+    
+    /* increase coords */
+    carry=1;
+    pos=0;
+    
+    while (carry==1 && pos != dims) {
+      if (coords[pos] != VECTOR(*dimvector)[pos]-1) {
+	coords[pos]++;
+	carry=0;
+      } else {
+	coords[pos]=0;
+	pos++;
+      }
+    }
+    
+  } /* for i<no_of_nodes */
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     directed));
+  if (nei >= 2) {
+    IGRAPH_CHECK(igraph_connect_neighborhood(graph, nei, IGRAPH_ALL));
+  }
+
+  /* clean up */
+  igraph_Free(coords);
+  igraph_Free(weights);
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_ring
+ * \brief Creates a \em ring graph, a one dimensional lattice.
+ * 
+ * An undirected (circular) ring on n vertices is commonly known in graph
+ * theory as the cycle graph C_n.
+ *
+ * \param graph Pointer to an uninitialized graph object.
+ * \param n The number of vertices in the ring.
+ * \param directed Logical, whether to create a directed ring.
+ * \param mutual Logical, whether to create mutual edges in a directed
+ *        ring. It is ignored for undirected graphs.
+ * \param circular Logical, if false, the ring will be open (this is
+ *        not a real \em ring actually).
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid number of vertices.
+ * 
+ * Time complexity: O(|V|), the
+ * number of vertices in the graph.
+ *
+ * \sa \ref igraph_lattice() for generating more general lattices.
+ * 
+ * \example examples/simple/igraph_ring.c
+ */
+
+int igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,
+		igraph_bool_t mutual, igraph_bool_t circular) {
+  
+  igraph_vector_t v=IGRAPH_VECTOR_NULL;
+
+  if (n<0) {
+    IGRAPH_ERROR("negative number of vertices", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&v, 1);
+  VECTOR(v)[0]=n;
+  
+  IGRAPH_CHECK(igraph_lattice(graph, &v, 1, directed, mutual, circular));
+  igraph_vector_destroy(&v);		 
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_tree
+ * \brief Creates a tree in which almost all vertices have the same number of children.
+ *
+ * \param graph Pointer to an uninitialized graph object.
+ * \param n Integer, the number of vertices in the graph.
+ * \param children Integer, the number of children of a vertex in the
+ *        tree. 
+ * \param type Constant, gives whether to create a directed tree, and
+ *        if this is the case, also its orientation. Possible values:
+ *        \clist
+ *        \cli IGRAPH_TREE_OUT 
+ *          directed tree, the edges point
+ *          from the parents to their children,
+ *        \cli IGRAPH_TREE_IN 
+ *          directed tree, the edges point from
+ *          the children to their parents.
+ *        \cli IGRAPH_TREE_UNDIRECTED
+ *          undirected tree.
+ *        \endclist
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid number of vertices.
+ *         \c IGRAPH_INVMODE: invalid mode argument.
+ * 
+ * Time complexity: O(|V|+|E|), the
+ * number of vertices plus the number of edges in the graph.
+ * 
+ * \sa \ref igraph_lattice(), \ref igraph_star() for creating other regular
+ * structures. 
+ * 
+ * \example examples/simple/igraph_tree.c
+ */
+
+int igraph_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, 
+		igraph_tree_mode_t type) {
+  
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int i, j;
+  long int idx=0;
+  long int to=1;
+
+  if (n<0 || children<=0) {
+    IGRAPH_ERROR("Invalid number of vertices or children", IGRAPH_EINVAL);
+  }
+  if (type != IGRAPH_TREE_OUT && type != IGRAPH_TREE_IN &&
+      type != IGRAPH_TREE_UNDIRECTED) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2*(n-1));
+  
+  i=0;
+  if (type == IGRAPH_TREE_OUT) {
+    while (idx<2*(n-1)) {
+      for (j=0; j<children && idx<2*(n-1); j++) {
+	VECTOR(edges)[idx++]=i;
+	VECTOR(edges)[idx++]=to++;
+      }
+      i++;
+    }
+  } else {
+    while (idx<2*(n-1)) {
+      for (j=0; j<children && idx<2*(n-1); j++) {
+	VECTOR(edges)[idx++]=to++;
+	VECTOR(edges)[idx++]=i;
+      }
+      i++;
+    }
+  }
+      
+  IGRAPH_CHECK(igraph_create(graph, &edges, 0, type!=IGRAPH_TREE_UNDIRECTED));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \ingroup generators
+ * \function igraph_full
+ * \brief Creates a full graph (directed or undirected, with or without loops). 
+ * 
+ * </para><para>
+ * In a full graph every possible edge is present, every vertex is
+ * connected to every other vertex. A full graph in \c igraph should be
+ * distinguished from the concept of complete graphs as used in graph theory.
+ * If n is a positive integer, then the complete graph K_n on n vertices is
+ * the undirected simple graph with the following property. For any distinct
+ * pair (u,v) of vertices in K_n, uv (or equivalently vu) is an edge of K_n.
+ * In \c igraph, a full graph on n vertices can be K_n, a directed version of
+ * K_n, or K_n with at least one loop edge. In any case, if F is a full graph
+ * on n vertices as generated by \c igraph, then K_n is a subgraph of the
+ * undirected version of F.
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param n Integer, the number of vertices in the graph.
+ * \param directed Logical, whether to create a directed graph.
+ * \param loops Logical, whether to include self-edges (loops).
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid number of vertices.
+ * 
+ * Time complexity: O(|V|+|E|),
+ * |V| is the number of vertices,
+ * |E| the number of edges in the
+ * graph. Of course this is the same as
+ * O(|E|)=O(|V||V|) 
+ * here. 
+ * 
+ * \sa \ref igraph_lattice(), \ref igraph_star(), \ref igraph_tree()
+ * for creating other regular structures.
+ * 
+ * \example examples/simple/igraph_full.c
+ */
+
+int igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,
+		igraph_bool_t loops) {
+  
+  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
+  long int i, j;
+
+  if (n<0) {
+    IGRAPH_ERROR("invalid number of vertices", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  if (directed && loops) {
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*n));
+    for (i=0; i<n; i++) {
+      for (j=0; j<n; j++) {
+	igraph_vector_push_back(&edges, i); /* reserved */
+	igraph_vector_push_back(&edges, j); /* reserved */
+      }
+    }
+  } else if (directed && !loops) {
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*(n-1)));
+    for (i=0; i<n; i++) {
+      for (j=0; j<i; j++) {
+	igraph_vector_push_back(&edges, i); /* reserved */
+	igraph_vector_push_back(&edges, j); /* reserved */
+      }
+      for (j=i+1; j<n; j++) {
+	igraph_vector_push_back(&edges, i); /* reserved */
+	igraph_vector_push_back(&edges, j); /* reserved */
+      }
+    }
+  } else if (!directed && loops) {
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*(n+1)/2));
+    for (i=0; i<n; i++) {
+      for (j=i; j<n; j++) {
+	igraph_vector_push_back(&edges, i); /* reserved */
+	igraph_vector_push_back(&edges, j); /* reserved */
+      }
+    }
+  } else {
+    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*(n-1)/2));
+    for (i=0; i<n; i++) {
+      for (j=i+1; j<n; j++) {
+	igraph_vector_push_back(&edges, i); /* reserved */
+	igraph_vector_push_back(&edges, j); /* reserved */
+      }
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_full_citation
+ * Creates a full citation graph
+ * 
+ * This is a directed graph, where every <code>i->j</code> edge is
+ * present if and only if <code>j<i</code>.
+ * If the \c directed argument is zero then an undirected graph is
+ * created, and it is just a full graph. 
+ * \param graph Pointer to an uninitialized graph object, the result
+ *    is stored here.
+ * \param n The number of vertices.
+ * \param directed Whether to created a directed graph. If zero an
+ *    undirected graph is created.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|^2), as we have many edges.
+ */
+
+int igraph_full_citation(igraph_t *graph, igraph_integer_t n, 
+			 igraph_bool_t directed) {
+  igraph_vector_t edges;
+  long int i, j, ptr=0;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, n*(n-1));
+  for (i=1; i<n; i++) {
+    for (j=0; j<i; j++) {
+      VECTOR(edges)[ptr++] = i;
+      VECTOR(edges)[ptr++] = j;
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_small
+ * \brief Shorthand to create a short graph, giving the edges as arguments.
+ * 
+ * </para><para>
+ * This function is handy when a relatively small graph needs to be created. 
+ * Instead of giving the edges as a vector, they are given simply as
+ * arguments and a '-1' needs to be given after the last meaningful
+ * edge argument. 
+ * 
+ * </para><para>Note that only graphs which have vertices less than
+ * the highest value of the 'int' type can be created this way. If you
+ * give larger values then the result is undefined.
+ * 
+ * \param graph Pointer to an uninitialized graph object. The result
+ *        will be stored here.
+ * \param n The number of vertices in the graph; a nonnegative integer.
+ * \param directed Logical constant; gives whether the graph should be
+ *        directed. Supported values are:
+ *        \clist
+ *        \cli IGRAPH_DIRECTED
+ *          The graph to be created will be \em directed.
+ *        \cli IGRAPH_UNDIRECTED
+ *          The graph to be created will be \em undirected.
+ *        \endclist
+ * \param ... The additional arguments giving the edges of the
+ *        graph. Don't forget to supply an additional '-1' after the last
+ *        (meaningful) argument.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges in the graph to create.
+ * 
+ * \example examples/simple/igraph_small.c
+ */
+
+int igraph_small(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, 
+		 ...) {
+  igraph_vector_t edges;
+  va_list ap;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  
+  va_start(ap, directed);
+  while (1) {
+    int num = va_arg(ap, int);
+    if (num == -1) {
+      break;
+    }
+    igraph_vector_push_back(&edges, num);
+  }
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_extended_chordal_ring
+ * Create an extended chordal ring
+ * 
+ * An extended chordal ring is a 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 <parameter>W</parameter> matrix. The extra edges of vertex i
+ * are added according to column (i mod p) in
+ * <parameter>W</parameter>. The number of extra edges is the number
+ * of rows in <parameter>W</parameter>: for each row j an edge
+ * i->i+w[ij] is added if i+w[ij] is less than the number of total
+ * nodes. 
+ * 
+ * </para><para>
+ * See also Kotsis, G: Interconnection Topologies for Parallel Processing
+ * Systems, PARS Mitteilungen 11, 1-6, 1993.
+ * 
+ * \param graph Pointer to an uninitialized graph object, the result
+ *   will be stored here. The result is always an undirected graph.
+ * \param nodes Integer constant, the number of vertices in the
+ *   graph. It must be at least 3.
+ * \param W The matrix specifying the extra edges. The number of
+ *   columns should divide the number of total vertices.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_ring().
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges.
+ */
+
+int igraph_extended_chordal_ring(igraph_t *graph, igraph_integer_t nodes, 
+				 const igraph_matrix_t *W) {
+
+  igraph_vector_t edges;
+  long int period=igraph_matrix_ncol(W);
+  long int degree=igraph_matrix_nrow(W)+2;
+  long int i, j, mpos=0, epos=0;
+  
+  if (nodes<3) {
+    IGRAPH_ERROR("An extended chordal ring has at least 3 nodes",
+		 IGRAPH_EINVAL);
+  }
+  
+  if ((long int)nodes % period != 0) {
+    IGRAPH_ERROR("The period (number of columns in W) should divide the " 
+		 "number of nodes", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, nodes*degree);
+
+  for (i=0; i<nodes-1; i++) {
+    VECTOR(edges)[epos++] = i;
+    VECTOR(edges)[epos++] = i+1;
+  }
+  VECTOR(edges)[epos++] = 0;
+  VECTOR(edges)[epos++] = nodes-1;
+  
+  if (degree > 2) {
+    for (i=0; i<nodes; i++) {
+      for (j=0; j<degree-2; j++) {
+	long int offset=(long int) MATRIX(*W, j, mpos);
+	if (i+offset < nodes) {
+	  VECTOR(edges)[epos++] = i;
+	  VECTOR(edges)[epos++] = i+offset;
+	}
+      }
+      mpos++; if (mpos==period) { mpos=0; }
+    }
+  }
+  
+  igraph_vector_resize(&edges, epos);
+  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, IGRAPH_UNDIRECTED));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;  
+}
+
+/**
+ * \function igraph_connect_neighborhood
+ * \brief Connects every vertex to its neighborhood
+ * 
+ * This function adds new edges to the input graph. For each vertex 
+ * vertices reachable by at most \p order steps and not yet connected
+ * to the vertex a new edge is created.
+ * 
+ * </para><para> Note that the input graph is modified in place, no
+ * new graph is created, call \ref igraph_copy() if you want to keep
+ * the original graph as well.
+ * 
+ * </para><para> For undirected graphs reachability is always
+ * symmetric: if vertex A can be reached from vertex B in at
+ * most \p order steps, then the opposite is also true. Only one
+ * undirected (A,B) edge will be added in this case.
+ * \param graph The input graph, this is the output graph as well.
+ * \param order Integer constant, it gives the distance within which
+ *    the vertices will be connected to the source vertex.
+ * \param mode Constant, it specifies how the neighborhood search is
+ *    performed for directed graphs. If \c IGRAPH_OUT then vertices
+ *    reachable from the source vertex will be connected, \c IGRAPH_IN
+ *    is the opposite. If \c IGRAPH_ALL then the directed graph is
+ *    considered as an undirected one.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_lattice() uses this function to connect the
+ * neighborhood of the vertices.
+ * 
+ * Time complexity: O(|V|*d^o), |V| is the number of vertices in the
+ * graph, d is the average degree and o is the \p order argument.
+ */
+
+int igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order,
+				igraph_neimode_t mode) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_dqueue_t q;
+  igraph_vector_t edges;
+  long int i, j, in;
+  long int *added;
+  igraph_vector_t neis;
+  
+  if (order<0) {
+    IGRAPH_ERROR("Negative order, cannot connect neighborhood", IGRAPH_EINVAL);
+  }
+
+  if (order<2) { 
+    IGRAPH_WARNING("Order smaller than two, graph will be unchanged");
+  }
+
+  if (!igraph_is_directed(graph)) {
+    mode=IGRAPH_ALL;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  added=igraph_Calloc(no_of_nodes, long int);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot connect neighborhood", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  
+  for (i=0; i<no_of_nodes; i++) {
+    added[i]=i+1;
+    igraph_neighbors(graph, &neis, (igraph_integer_t) i, mode);
+    in=igraph_vector_size(&neis);
+    if (order > 1) {
+      for (j=0; j<in; j++) {
+	long int nei=(long int) VECTOR(neis)[j];
+	added[nei]=i+1;
+	igraph_dqueue_push(&q, nei);
+	igraph_dqueue_push(&q, 1);
+      }
+    }
+    
+    while (!igraph_dqueue_empty(&q)) {
+      long int actnode=(long int) igraph_dqueue_pop(&q);
+      long int actdist=(long int) igraph_dqueue_pop(&q);
+      long int n;
+      igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
+      n=igraph_vector_size(&neis);
+      
+      if (actdist<order-1) {
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (added[nei] != i+1) {
+	    added[nei]=i+1;
+	    IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
+	    IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+	    if (mode != IGRAPH_ALL || i < nei) {
+	      if (mode == IGRAPH_IN) {
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	      } else {
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
+	      }
+	    }
+	  }
+	}
+      } else { 
+	for (j=0; j<n; j++) {
+	  long int nei=(long int) VECTOR(neis)[j];
+	  if (added[nei] != i+1) {
+	    added[nei]=i+1;
+	    if (mode != IGRAPH_ALL || i < nei) {
+	      if (mode == IGRAPH_IN) {
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	      } else {
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
+	      }
+	    }
+	  }
+	}
+      }
+      
+    } /* while q not empty */
+  } /* for i < no_of_nodes */
+  
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&q);
+  igraph_free(added);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  IGRAPH_CHECK(igraph_add_edges(graph, &edges, 0));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_de_bruijn
+ * \brief Generate a de Bruijn graph.
+ * 
+ * A de Bruijn graph represents relationships between strings. An alphabet
+ * of \c m letters are used and strings of length \c n are considered. 
+ * A vertex corresponds to every possible string and there is a directed edge
+ * from vertex \c v to vertex \c w if the string of \c v can be transformed into
+ * the string of \c w by removing its first letter and appending a letter to it.
+ * 
+ * </para><para>
+ * Please note that the graph will have \c m to the power \c n vertices and 
+ * even more edges, so probably you don't want to supply too big numbers for
+ * \c m and \c n.
+ * 
+ * </para><para>
+ * De Bruijn graphs have some interesting properties, please see another source,
+ * eg. Wikipedia for details. 
+ * 
+ * \param graph Pointer to an uninitialized graph object, the result will be 
+ *        stored here.
+ * \param m Integer, the number of letters in the alphabet.
+ * \param n Integer, the length of the strings.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_kautz().
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.
+ */
+
+int igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_integer_t n) {
+  
+  /* m - number of symbols */
+  /* n - length of strings */
+  
+  long int no_of_nodes, no_of_edges;
+  igraph_vector_t edges;
+  long int i, j;
+  long int mm=m;
+  
+  if (m<0 || n<0) {
+    IGRAPH_ERROR("`m' and `n' should be non-negative in a de Bruijn graph",
+		 IGRAPH_EINVAL);
+  }
+  
+  if (n==0) {
+    return igraph_empty(graph, 1, IGRAPH_DIRECTED);
+  }
+  if (m==0) {
+    return igraph_empty(graph, 0, IGRAPH_DIRECTED);
+  }
+  
+  no_of_nodes=(long int) pow(m, n);
+  no_of_edges=no_of_nodes*m;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+  
+  for (i=0; i<no_of_nodes; i++) {
+    long int basis=(i*mm) % no_of_nodes;
+    for (j=0; j<m; j++) {
+      igraph_vector_push_back(&edges, i);
+      igraph_vector_push_back(&edges, basis+j);
+    }
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
+			     IGRAPH_DIRECTED));
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_kautz
+ * \brief Generate a Kautz graph.
+ * 
+ * A Kautz graph is a labeled graph, vertices are labeled by strings
+ * of length \c n+1 above an alphabet with \c 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 \c v to
+ * another vertex \c w if it is possible to transform the string of
+ * \c v into the string of \c w by removing the first letter and
+ * appending a letter to it.
+ * 
+ * </para><para>
+ * Kautz graphs have some interesting properties, see eg. Wikipedia
+ * for details.
+ * 
+ * </para><para>
+ * Vincent Matossian wrote the first version of this function in R,
+ * thanks.
+ * \param graph Pointer to an uninitialized graph object, the result
+ * will be stored here.
+ * \param m Integer, \c m+1 is the number of letters in the alphabet.
+ * \param n Integer, \c n+1 is the length of the strings.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_de_bruijn().
+ * 
+ * Time complexity: O(|V|* [(m+1)/m]^n +|E|), in practice it is more
+ * like O(|V|+|E|). |V| is the number of vertices, |E| is the number
+ * of edges and \c m and \c n are the corresponding arguments.
+ */
+
+int igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_t n) {
+  
+  /* m+1 - number of symbols */
+  /* n+1 - length of strings */
+
+  long int mm=m;
+  long int no_of_nodes, no_of_edges;
+  long int allstrings;
+  long int i, j, idx=0;
+  igraph_vector_t edges;
+  igraph_vector_long_t digits, table;
+  igraph_vector_long_t index1, index2;
+  long int actb=0;
+  long int actvalue=0;
+  
+  if (m<0 || n<0) {
+    IGRAPH_ERROR("`m' and `n' should be non-negative in a Kautz graph",
+		 IGRAPH_EINVAL);
+  }
+
+  if (n==0) {
+    return igraph_full(graph, m+1, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
+  }
+  if (m==0) { 
+    return igraph_empty(graph, 0, IGRAPH_DIRECTED);
+  }
+  
+  no_of_nodes=(long int) ((m+1)*pow(m, n));
+  no_of_edges=no_of_nodes*m;
+  allstrings=(long int) pow(m+1, n+1);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&table, n+1));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &table);
+  j=1;
+  for (i=n; i>=0; i--) {
+    VECTOR(table)[i]=j;
+    j *= (m+1);
+  }
+
+  IGRAPH_CHECK(igraph_vector_long_init(&digits, n+1));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &digits);
+  IGRAPH_CHECK(igraph_vector_long_init(&index1, (long int) pow(m+1, n+1)));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &index1);
+  IGRAPH_CHECK(igraph_vector_long_init(&index2, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &index2);  
+
+  /* Fill the index tables*/
+  while (1) {
+    /* at the beginning of the loop, 0:actb contain the valid prefix */
+    /* we might need to fill it to get a valid string */
+    long int z=0;
+    if (VECTOR(digits)[actb]==0) { z=1; }
+    for (actb++; actb<=n; actb++) {
+      VECTOR(digits)[actb]=z;
+      actvalue += z*VECTOR(table)[actb];
+      z=1-z;
+    }
+    actb=n;
+
+    /* ok, we have a valid string now */
+    VECTOR(index1)[actvalue]=idx+1;
+    VECTOR(index2)[idx]=actvalue;
+    idx++;
+    
+    /* finished? */
+    if (idx >= no_of_nodes) { break; }
+    
+    /* not yet, we need a valid prefix now */
+    while (1) {
+      /* try to increase digits at position actb */
+      long int next=VECTOR(digits)[actb]+1;
+      if (actb != 0 && VECTOR(digits)[actb-1]==next) { next++; }
+      if (next <= m) {
+	/* ok, no problem */
+	actvalue += (next-VECTOR(digits)[actb])*VECTOR(table)[actb];
+	VECTOR(digits)[actb]=next;
+	break;
+      } else {
+	/* bad luck, try the previous digit */
+	actvalue -= VECTOR(digits)[actb]*VECTOR(table)[actb];
+	actb--;
+      }
+    }
+  }
+
+  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
+    
+  /* Now come the edges at last */
+  for (i=0; i<no_of_nodes; i++) {
+    long int fromvalue=VECTOR(index2)[i];
+    long int lastdigit=fromvalue % (mm+1);
+    long int basis=(fromvalue * (mm+1)) % allstrings;
+    for (j=0; j<=m; j++) {
+      long int tovalue, to;
+      if (j==lastdigit) { continue; }
+      tovalue=basis+j;
+      to=VECTOR(index1)[tovalue]-1;
+      if (to<0) { continue; }
+      igraph_vector_push_back(&edges, i);
+      igraph_vector_push_back(&edges, to);
+    }
+  }
+
+  igraph_vector_long_destroy(&index2);
+  igraph_vector_long_destroy(&index1);
+  igraph_vector_long_destroy(&digits);
+  igraph_vector_long_destroy(&table);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     IGRAPH_DIRECTED));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_lcf_vector
+ * \brief Create a graph from LCF notation
+ * 
+ * This function is essentially the same as \ref igraph_lcf(), only
+ * the way for giving the arguments is different. See \ref
+ * igraph_lcf() for details.
+ * \param graph Pointer to an uninitialized graph object.
+ * \param n Integer constant giving the number of vertices.
+ * \param shifts A vector giving the shifts.
+ * \param repeats An integer constant giving the number of repeats 
+ *        for the shifts.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_lcf()
+ * 
+ * Time complexity: O(|V|+|E|), linear in the number of vertices plus
+ * the number of edges.
+ */
+
+int igraph_lcf_vector(igraph_t *graph, igraph_integer_t n,
+		      const igraph_vector_t *shifts, 
+		      igraph_integer_t repeats) {
+  
+  igraph_vector_t edges;
+  long int no_of_shifts=igraph_vector_size(shifts);
+  long int ptr=0, i, sptr=0;
+  long int no_of_nodes=n;
+  long int no_of_edges=n+no_of_shifts*repeats/2;
+
+	if (repeats<0) IGRAPH_ERROR("number of repeats must be positive", IGRAPH_EINVAL);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2*no_of_edges);
+
+  /* Create a ring first */
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(edges)[ptr++]=i;
+    VECTOR(edges)[ptr++]=i+1;
+  }
+  VECTOR(edges)[ptr-1]=0;
+  
+  /* Then add the rest */
+  while (ptr<2*no_of_edges) {
+    long int sh=(long int) VECTOR(*shifts)[sptr % no_of_shifts];
+    long int from=sptr % no_of_nodes;
+    long int to=(no_of_nodes+sptr+sh) % no_of_nodes;
+    if (from < to) {
+      VECTOR(edges)[ptr++]=from;
+      VECTOR(edges)[ptr++]=to;
+    }
+    sptr++;
+  }
+  
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
+			     IGRAPH_UNDIRECTED));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;			     
+}
+
+/**
+ * \function igraph_lcf
+ * \brief Create a graph from LCF notation
+ * 
+ * </para><para>
+ * LCF is short for Lederberg-Coxeter-Frucht, it is a concise notation for
+ * 3-regular Hamiltonian graphs. It consists 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
+ * http://mathworld.wolfram.com/LCFNotation.html for details. 
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param n Integer, the number of vertices in the graph.
+ * \param ... The shifts and the number of repeats for the shifts,
+ *        plus an additional 0 to mark the end of the arguments.
+ * \return Error code.
+ * 
+ * \sa See \ref igraph_lcf_vector() for a similar function using a
+ * vector_t instead of the variable length argument list.
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges.
+ * 
+ * \example examples/simple/igraph_lcf.c
+ */
+
+int igraph_lcf(igraph_t *graph, igraph_integer_t n, ...) {
+  igraph_vector_t shifts;
+  igraph_integer_t repeats;
+  va_list ap;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&shifts, 0);
+  
+  va_start(ap, n);
+  while (1) {
+    int num=va_arg(ap, int);
+    if (num==0) {
+      break;
+    }
+    IGRAPH_CHECK(igraph_vector_push_back(&shifts, num));
+  }
+  if (igraph_vector_size(&shifts)==0) {
+    repeats=0;
+  } else {
+    repeats=(igraph_integer_t) igraph_vector_pop_back(&shifts);
+  }
+  
+  IGRAPH_CHECK(igraph_lcf_vector(graph, n, &shifts, repeats));
+  igraph_vector_destroy(&shifts);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
+
+const igraph_real_t igraph_i_famous_bull[] = {
+  5, 5, 0,
+  0,1,0,2,1,2,1,3,2,4
+};
+
+const igraph_real_t igraph_i_famous_chvatal[] = { 
+  12, 24, 0, 
+  5, 6, 6, 7, 7, 8, 8, 9, 5, 9, 4, 5, 4, 8, 2, 8, 2, 6, 0, 6, 0, 9, 3, 9, 3, 7, 
+  1, 7, 1, 5, 1, 10, 4, 10, 4, 11, 2, 11, 0, 10, 0, 11, 3, 11, 3, 10, 1, 2
+};
+
+const igraph_real_t igraph_i_famous_coxeter[] = {
+  28, 42, 0,
+  0, 1, 0, 2, 0, 7, 1, 4, 1, 13, 2, 3, 2, 8, 3, 6, 3, 9, 4, 5, 4, 12, 5, 6, 5, 
+  11, 6, 10, 7, 19, 7, 24, 8, 20, 8, 23, 9, 14, 9, 22, 10, 15, 10, 21, 11, 16, 
+  11, 27, 12, 17, 12, 26, 13, 18, 13, 25, 14, 17, 14, 18, 15, 18, 15, 19, 16, 19, 
+  16, 20, 17, 20, 21, 23, 21, 26, 22, 24, 22, 27, 23, 25, 24, 26, 25, 27
+};
+
+const igraph_real_t igraph_i_famous_cubical[] = {
+  8, 12, 0,
+  0, 1, 1, 2, 2, 3, 0, 3, 4, 5, 5, 6, 6, 7, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7
+};  
+
+const igraph_real_t igraph_i_famous_diamond[] = {
+  4, 5, 0,
+  0,1,0,2,1,2,1,3,2,3
+};
+
+const igraph_real_t igraph_i_famous_dodecahedron[] = {
+  20, 30, 0, 
+  0, 1, 0, 4, 0, 5, 1, 2, 1, 6, 2, 3, 2, 7, 3, 4, 3, 8, 4, 9, 5, 10, 5, 11, 6, 
+  10, 6, 14, 7, 13, 7, 14, 8, 12, 8, 13, 9, 11, 9, 12, 10, 15, 11, 16, 12, 17, 
+  13, 18, 14, 19, 15, 16, 15, 19, 16, 17, 17, 18, 18, 19
+};
+
+const igraph_real_t igraph_i_famous_folkman[] = {
+  20, 40, 0,
+  0, 5, 0, 8, 0, 10, 0, 13, 1, 7, 1, 9, 1, 12, 1, 14, 2, 6, 2, 8, 2, 11, 2, 13, 
+  3, 5, 3, 7, 3, 10, 3, 12, 4, 6, 4, 9, 4, 11, 4, 14, 5, 15, 5, 19, 6, 15, 6, 16, 
+  7, 16, 7, 17, 8, 17, 8, 18, 9, 18, 9, 19, 10, 15, 10, 19, 11, 15, 11, 16, 12, 
+  16, 12, 17, 13, 17, 13, 18, 14, 18, 14, 19
+};  
+
+const igraph_real_t igraph_i_famous_franklin[] = {
+  12, 18, 0,
+  0, 1, 0, 2, 0, 6, 1, 3, 1, 7, 2, 4, 2, 10, 3, 5, 3, 11, 4, 5, 4, 6, 5, 7, 6, 8, 
+  7, 9, 8, 9, 8, 11, 9, 10, 10, 11
+};  
+
+const igraph_real_t igraph_i_famous_frucht[] = {
+  12, 18, 0,
+  0, 1, 0, 2, 0, 11, 1, 3, 1, 6, 2, 5, 2, 10, 3, 4, 3, 6, 4, 8, 4, 11, 5, 9, 5, 
+  10, 6, 7, 7, 8, 7, 9, 8, 9, 10, 11
+};  
+
+const igraph_real_t igraph_i_famous_grotzsch[] = {
+  11, 20, 0,
+  0, 1, 0, 2, 0, 7, 0, 10, 1, 3, 1, 6, 1, 9, 2, 4, 2, 6, 2, 8, 3, 4, 3, 8, 3, 10, 
+  4, 7, 4, 9, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10
+};  
+
+const igraph_real_t igraph_i_famous_heawood[] = {
+  14, 21, 0,
+  0, 1, 0, 5, 0, 13, 1, 2, 1, 10, 2, 3, 2, 7, 3, 4, 3, 12, 4, 5, 4, 9, 5, 6, 6, 
+  7, 6, 11, 7, 8, 8, 9, 8, 13, 9, 10, 10, 11, 11, 12, 12, 13
+};  
+
+const igraph_real_t igraph_i_famous_herschel[] = {
+  11, 18, 0,
+  0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 6, 1, 7, 2, 10, 3, 9, 4, 8, 4, 9, 5, 8, 
+  5, 10, 6, 8, 6, 9, 7, 8, 7, 10
+};  
+
+const igraph_real_t igraph_i_famous_house[] = {
+  5, 6, 0,
+  0,1,0,2,1,3,2,3,2,4,3,4
+};
+
+const igraph_real_t igraph_i_famous_housex[] = {
+  5, 8, 0,
+  0,1,0,2,0,3,1,2,1,3,2,3,2,4,3,4
+};
+
+const igraph_real_t igraph_i_famous_icosahedron[] = {
+  12, 30, 0,
+  0, 1, 0, 2, 0, 3, 0, 4, 0, 8, 1, 2, 1, 6, 1, 7, 1, 8, 2, 4, 2, 5, 2, 6, 3, 4, 
+  3, 8, 3, 9, 3, 11, 4, 5, 4, 11, 5, 6, 5, 10, 5, 11, 6, 7, 6, 10, 7, 8, 7, 9, 7, 
+  10, 8, 9, 9, 10, 9, 11, 10, 11
+};  
+
+const igraph_real_t igraph_i_famous_krackhardt_kite[] = {
+  10,18,0,
+  0,1,0,2,0,3,0,5, 1,3,1,4,1,6, 2,3,2,5, 3,4,3,5,3,6, 4,6, 5,6,5,7, 6,7, 7,8, 8,9
+};
+
+const igraph_real_t igraph_i_famous_levi[] = {
+  30, 45, 0,
+  0, 1, 0, 7, 0, 29, 1, 2, 1, 24, 2, 3, 2, 11, 3, 4, 3, 16, 4, 5, 4, 21, 5, 6, 5, 
+  26, 6, 7, 6, 13, 7, 8, 8, 9, 8, 17, 9, 10, 9, 22, 10, 11, 10, 27, 11, 12, 12, 
+  13, 12, 19, 13, 14, 14, 15, 14, 23, 15, 16, 15, 28, 16, 17, 17, 18, 18, 19, 18, 
+  25, 19, 20, 20, 21, 20, 29, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 
+  28, 28, 29
+};  
+
+const igraph_real_t igraph_i_famous_mcgee[] = {
+  24, 36, 0,
+  0, 1, 0, 7, 0, 23, 1, 2, 1, 18, 2, 3, 2, 14, 3, 4, 3, 10, 4, 5, 4, 21, 5, 6, 5, 
+  17, 6, 7, 6, 13, 7, 8, 8, 9, 8, 20, 9, 10, 9, 16, 10, 11, 11, 12, 11, 23, 12, 
+  13, 12, 19, 13, 14, 14, 15, 15, 16, 15, 22, 16, 17, 17, 18, 18, 19, 19, 20, 20, 
+  21, 21, 22, 22, 23
+};
+
+const igraph_real_t igraph_i_famous_meredith[] = {
+  70, 140, 0,
+  0, 4, 0, 5, 0, 6, 1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6, 7, 11, 
+  7, 12, 7, 13, 8, 11, 8, 12, 8, 13, 9, 11, 9, 12, 9, 13, 10, 11, 10, 12, 10, 13, 
+  14, 18, 14, 19, 14, 20, 15, 18, 15, 19, 15, 20, 16, 18, 16, 19, 16, 20, 17, 18, 
+  17, 19, 17, 20, 21, 25, 21, 26, 21, 27, 22, 25, 22, 26, 22, 27, 23, 25, 23, 26, 
+  23, 27, 24, 25, 24, 26, 24, 27, 28, 32, 28, 33, 28, 34, 29, 32, 29, 33, 29, 34, 
+  30, 32, 30, 33, 30, 34, 31, 32, 31, 33, 31, 34, 35, 39, 35, 40, 35, 41, 36, 39, 
+  36, 40, 36, 41, 37, 39, 37, 40, 37, 41, 38, 39, 38, 40, 38, 41, 42, 46, 42, 47, 
+  42, 48, 43, 46, 43, 47, 43, 48, 44, 46, 44, 47, 44, 48, 45, 46, 45, 47, 45, 48, 
+  49, 53, 49, 54, 49, 55, 50, 53, 50, 54, 50, 55, 51, 53, 51, 54, 51, 55, 52, 53, 
+  52, 54, 52, 55, 56, 60, 56, 61, 56, 62, 57, 60, 57, 61, 57, 62, 58, 60, 58, 61, 
+  58, 62, 59, 60, 59, 61, 59, 62, 63, 67, 63, 68, 63, 69, 64, 67, 64, 68, 64, 69, 
+  65, 67, 65, 68, 65, 69, 66, 67, 66, 68, 66, 69, 2, 50, 1, 51, 9, 57, 8, 58, 16, 
+  64, 15, 65, 23, 36, 22, 37, 30, 43, 29, 44, 3, 21, 7, 24, 14, 31, 0, 17, 10, 
+  28, 38, 42, 35, 66, 59, 63, 52, 56, 45, 49
+};  
+
+const igraph_real_t igraph_i_famous_noperfectmatching[] = {
+  16, 27, 0,
+  0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3, 2, 4, 3, 4, 4, 5, 5, 6, 5, 7, 6, 12, 6, 13, 
+  7, 8, 7, 9, 8, 9, 8, 10, 8, 11, 9, 10, 9, 11, 10, 11, 12, 13, 12, 14, 12, 15, 
+  13, 14, 13, 15, 14, 15
+};  
+
+const igraph_real_t igraph_i_famous_nonline[] = {
+  50, 72, 0,
+  0, 1, 0, 2, 0, 3, 4, 6, 4, 7, 5, 6, 5, 7, 6, 7, 7, 8, 9, 11, 9, 12, 9, 13, 10, 
+  11, 10, 12, 10, 13, 11, 12, 11, 13, 12, 13, 14, 15, 15, 16, 15, 17, 16, 17, 16, 
+  18, 17, 18, 18, 19, 20, 21, 20, 22, 20, 23, 21, 22, 21, 23, 21, 24, 22, 23, 22, 
+  24, 24, 25, 26, 27, 26, 28, 26, 29, 27, 28, 27, 29, 27, 30, 27, 31, 28, 29, 28, 
+  30, 28, 31, 30, 31, 32, 34, 32, 35, 32, 36, 33, 34, 33, 35, 33, 37, 34, 35, 36, 
+  37, 38, 39, 38, 40, 38, 43, 39, 40, 39, 41, 39, 42, 39, 43, 40, 41, 41, 42, 42, 
+  43, 44, 45, 44, 46, 45, 46, 45, 47, 46, 47, 46, 48, 47, 48, 47, 49, 48, 49
+};  
+
+const igraph_real_t igraph_i_famous_octahedron[] = {
+  6, 12, 0,
+  0, 1, 0, 2, 1, 2, 3, 4, 3, 5, 4, 5, 0, 3, 0, 5, 1, 3, 1, 4, 2, 4, 2, 5
+};  
+
+const igraph_real_t igraph_i_famous_petersen[] = {
+  10, 15, 0,
+  0,1,0,4,0,5, 1,2,1,6, 2,3,2,7, 3,4,3,8, 4,9, 5,7,5,8, 6,8,6,9, 7,9
+};
+
+const igraph_real_t igraph_i_famous_robertson[] = {
+  19, 38, 0,
+  0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 
+  12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 0, 18, 0, 4, 4, 9, 9, 13, 13, 
+  17, 2, 17, 2, 6, 6, 10, 10, 15, 0, 15, 1, 8, 8, 16, 5, 16, 5, 12, 1, 12, 7, 18, 
+  7, 14, 3, 14, 3, 11, 11, 18
+};  
+
+const igraph_real_t igraph_i_famous_smallestcyclicgroup[] = {
+  9, 15, 0,
+  0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 7, 1, 8, 2, 5, 2, 6, 2, 7, 3, 8, 
+  4, 5, 6, 7
+};  
+
+const igraph_real_t igraph_i_famous_tetrahedron[] = {
+  4, 6, 0, 
+  0, 3, 1, 3, 2, 3, 0, 1, 1, 2, 0, 2
+};  
+
+const igraph_real_t igraph_i_famous_thomassen[] = {
+  34, 52, 0,
+  0, 2, 0, 3, 1, 3, 1, 4, 2, 4, 5, 7, 5, 8, 6, 8, 6, 9, 7, 9, 10, 12, 10, 13, 11, 
+  13, 11, 14, 12, 14, 15, 17, 15, 18, 16, 18, 16, 19, 17, 19, 9, 19, 4, 14, 24, 
+  25, 25, 26, 20, 26, 20, 21, 21, 22, 22, 23, 23, 27, 27, 28, 28, 29, 29, 30, 30, 
+  31, 31, 32, 32, 33, 24, 33, 5, 24, 6, 25, 7, 26, 8, 20, 0, 20, 1, 21, 2, 22, 3, 
+  23, 10, 27, 11, 28, 12, 29, 13, 30, 15, 30, 16, 31, 17, 32, 18, 33
+};  
+
+const igraph_real_t igraph_i_famous_tutte[] = {
+  46, 69, 0, 
+  0, 10, 0, 11, 0, 12, 1, 2, 1, 7, 1, 19, 2, 3, 2, 41, 3, 4, 3, 27, 4, 5, 4, 33, 
+  5, 6, 5, 45, 6, 9, 6, 29, 7, 8, 7, 21, 8, 9, 8, 22, 9, 24, 10, 13, 10, 14, 11, 
+  26, 11, 28, 12, 30, 12, 31, 13, 15, 13, 21, 14, 15, 14, 18, 15, 16, 16, 17, 16, 
+  20, 17, 18, 17, 23, 18, 24, 19, 25, 19, 40, 20, 21, 20, 22, 22, 23, 23, 24, 25, 
+  26, 25, 38, 26, 34, 27, 28, 27, 39, 28, 34, 29, 30, 29, 44, 30, 35, 31, 32, 31, 
+  35, 32, 33, 32, 42, 33, 43, 34, 36, 35, 37, 36, 38, 36, 39, 37, 42, 37, 44, 38, 
+  40, 39, 41, 40, 41, 42, 43, 43, 45, 44, 45
+};
+
+const igraph_real_t igraph_i_famous_uniquely3colorable[] = {
+  12, 22, 0,
+  0, 1, 0, 3, 0, 6, 0, 8, 1, 4, 1, 7, 1, 9, 2, 3, 2, 6, 2, 7, 2, 9, 2, 11, 3, 4, 
+  3, 10, 4, 5, 4, 11, 5, 6, 5, 7, 5, 8, 5, 10, 8, 11, 9, 10
+};  
+
+const igraph_real_t igraph_i_famous_walther[] = {
+  25, 31, 0,
+  0, 1, 1, 2, 1, 8, 2, 3, 2, 13, 3, 4, 3, 16, 4, 5, 5, 6, 5, 19, 6, 7, 6, 20, 7, 
+  21, 8, 9, 8, 13, 9, 10, 9, 22, 10, 11, 10, 20, 11, 12, 13, 14, 14, 15, 14, 23, 
+  15, 16, 15, 17, 17, 18, 18, 19, 18, 24, 20, 24, 22, 23, 23, 24
+};  
+
+const igraph_real_t igraph_i_famous_zachary[] = {
+  34, 78, 0,
+  0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
+  0,10, 0,11, 0,12, 0,13, 0,17, 0,19, 0,21, 0,31,
+  1, 2, 1, 3, 1, 7, 1,13, 1,17, 1,19, 1,21, 1,30,
+  2, 3, 2, 7, 2,27, 2,28, 2,32, 2, 9, 2, 8, 2,13,
+  3, 7, 3,12, 3,13, 4, 6, 4,10, 5, 6, 5,10, 5,16,
+  6,16, 8,30, 8,32, 8,33, 9,33,13,33,14,32,14,33,
+  15,32,15,33,18,32,18,33,19,33,20,32,20,33,
+  22,32,22,33,23,25,23,27,23,32,23,33,23,29,
+  24,25,24,27,24,31,25,31,26,29,26,33,27,33,
+  28,31,28,33,29,32,29,33,30,32,30,33,31,32,31,33,
+  32,33
+};
+
+int igraph_i_famous(igraph_t *graph, const igraph_real_t *data);
+
+int igraph_i_famous(igraph_t *graph, const igraph_real_t *data) {
+  long int no_of_nodes=(long int) data[0];
+  long int no_of_edges=(long int) data[1];
+  igraph_bool_t directed=(igraph_bool_t) data[2];
+  igraph_vector_t edges;
+  
+  igraph_vector_view(&edges, data+3, 2*no_of_edges);
+  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
+			     directed));
+  return 0;  
+}
+
+/**
+ * \function igraph_famous
+ * \brief Create a famous graph by simply providing its name
+ * 
+ * </para><para>
+ * The name of the graph can be simply supplied as a string. 
+ * Note that this function creates graphs which don't take any parameters,
+ * there are separate functions for graphs with parameters, eg. \ref
+ * igraph_full() for creating a full graph.
+ * 
+ * </para><para>
+ * The following graphs are supported:
+ * \clist
+ *   \cli Bull
+ *           The bull graph, 5 vertices, 5 edges, resembles the
+ *           head of a bull if drawn properly.
+ *   \cli 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.
+ *   \cli Coxeter 
+ *           A non-Hamiltonian cubic symmetric graph with 28
+ *           vertices and 42 edges.
+ *   \cli Cubical
+ *           The Platonic graph of the cube. A convex regular
+ *           polyhedron with 8 vertices and 12 edges.
+ *   \cli Diamond
+ *           A graph with 4 vertices and 5 edges, resembles a
+ *           schematic diamond if drawn properly.
+ *   \cli Dodecahedral, Dodecahedron
+ *           Another Platonic solid
+ *           with 20 vertices and 30 edges.
+ *   \cli Folkman 
+ *           The semisymmetric graph with minimum number of
+ *           vertices, 20 and 40 edges. A semisymmetric graph is
+ *           regular, edge transitive and not vertex transitive.
+ *   \cli Franklin 
+ *           This is a graph whose embedding to the Klein
+ *           bottle can be colored with six colors, it is a
+ *           counterexample to the necessity of the Heawood
+ *           conjecture on a Klein bottle. It has 12 vertices and 18
+ *           edges. 
+ *   \cli 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.
+ *   \cli 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. 
+ *   \cli 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. 
+ *   \cli Herschel 
+ *           The Herschel graph is the smallest
+ *           nonhamiltonian polyhedral graph. It is the
+ *           unique such graph on 11 nodes, and has 18 edges.
+ *   \cli House
+ *           The house graph is a 5-vertex, 6-edge graph, the
+ *           schematic draw of a house if drawn properly, basically a 
+ *           triangle on top of a square.
+ *   \cli HouseX
+ *           The same as the house graph with an X in the square. 5
+ *           vertices and 8 edges.
+ *   \cli Icosahedral, Icosahedron 
+ *           A Platonic solid with 12
+ *           vertices and 30 edges.
+ *   \cli 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. 
+ *   \cli Levi 
+ *           The graph is a 4-arc transitive cubic graph, it has
+ *           30 vertices and 45 edges.
+ *   \cli McGee 
+ *           The McGee graph is the unique 3-regular 7-cage
+ *           graph, it has 24 vertices and 36 edges.
+ *   \cli 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. 
+ *   \cli 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-incident edges; that is, no two edges
+ *           share a common vertex. A perfect matching is a matching
+ *           which covers all vertices of the graph. 
+ *   \cli 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.
+ *   \cli Octahedral, Octahedron 
+ *           Platonic solid with 6
+ *           vertices and 12 edges. 
+ *   \cli Petersen
+ *           A 3-regular graph with 10 vertices and 15 edges. It is
+ *           the smallest hypohamiltonian graph, ie. it is
+ *           non-hamiltonian but removing any single vertex from it makes it
+ *           Hamiltonian.
+ *   \cli Robertson 
+ *           The unique (4,5)-cage graph, ie. a 4-regular
+ *           graph of girth 5. It has 19 vertices and 38 edges.
+ *   \cli Smallestcyclicgroup 
+ *           A smallest nontrivial graph
+ *           whose automorphism group is cyclic. It has 9 vertices and
+ *           15 edges.
+ *   \cli Tetrahedral, Tetrahedron 
+ *           Platonic solid with 4
+ *           vertices and 6 edges.
+ *   \cli 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 traceable.
+ *   \cli 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. 
+ *   \cli Uniquely3colorable 
+ *           Returns a 12-vertex, triangle-free
+ *           graph with chromatic number 3 that is uniquely
+ *           3-colorable.
+ *   \cli Walther 
+ *           An identity graph with 25 vertices and 31
+ *           edges. An identity graph has a single graph automorphism,
+ *           the trivial one.
+ *   \cli 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). 
+ * \endclist
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param name Character constant, the name of the graph to be
+ *     created, it is case insensitive.
+ * \return Error code, IGRAPH_EINVAL if there is no graph with the
+ *     given name.
+ * 
+ * \sa Other functions for creating graph structures:
+ * \ref igraph_ring(), \ref igraph_tree(), \ref igraph_lattice(), \ref
+ * igraph_full().
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges in the graph.
+ */
+
+int igraph_famous(igraph_t *graph, const char *name) {
+
+  if (!strcasecmp(name, "bull")) {
+    return igraph_i_famous(graph, igraph_i_famous_bull);
+  } else if (!strcasecmp(name, "chvatal")) {
+    return igraph_i_famous(graph, igraph_i_famous_chvatal);
+  } else if (!strcasecmp(name, "coxeter")) {
+    return igraph_i_famous(graph, igraph_i_famous_coxeter);
+  } else if (!strcasecmp(name, "cubical")) {    
+    return igraph_i_famous(graph, igraph_i_famous_cubical);
+  } else if (!strcasecmp(name, "diamond")) {
+    return igraph_i_famous(graph, igraph_i_famous_diamond);
+  } else if (!strcasecmp(name, "dodecahedral") ||
+	     !strcasecmp(name, "dodecahedron")) {
+    return igraph_i_famous(graph, igraph_i_famous_dodecahedron);
+  } else if (!strcasecmp(name, "folkman")) {
+    return igraph_i_famous(graph, igraph_i_famous_folkman);
+  } else if (!strcasecmp(name, "franklin")) {
+    return igraph_i_famous(graph, igraph_i_famous_franklin);
+  } else if (!strcasecmp(name, "frucht")) {
+    return igraph_i_famous(graph, igraph_i_famous_frucht);
+  } else if (!strcasecmp(name, "grotzsch")) {
+    return igraph_i_famous(graph, igraph_i_famous_grotzsch);
+  } else if (!strcasecmp(name, "heawood")) {
+    return igraph_i_famous(graph, igraph_i_famous_heawood);
+  } else if (!strcasecmp(name, "herschel")) {
+    return igraph_i_famous(graph, igraph_i_famous_herschel);
+  } else if (!strcasecmp(name, "house")) {
+    return igraph_i_famous(graph, igraph_i_famous_house);
+  } else if (!strcasecmp(name, "housex")) {
+    return igraph_i_famous(graph, igraph_i_famous_housex);
+  } else if (!strcasecmp(name, "icosahedral") ||
+	     !strcasecmp(name, "icosahedron")) {
+    return igraph_i_famous(graph, igraph_i_famous_icosahedron);
+  } else if (!strcasecmp(name, "krackhardt_kite")) {
+    return igraph_i_famous(graph, igraph_i_famous_krackhardt_kite);
+  } else if (!strcasecmp(name, "levi")) {
+    return igraph_i_famous(graph, igraph_i_famous_levi);
+  } else if (!strcasecmp(name, "mcgee")) {
+    return igraph_i_famous(graph, igraph_i_famous_mcgee);
+  } else if (!strcasecmp(name, "meredith")) {
+    return igraph_i_famous(graph, igraph_i_famous_meredith);
+  } else if (!strcasecmp(name, "noperfectmatching")) {
+    return igraph_i_famous(graph, igraph_i_famous_noperfectmatching);
+  } else if (!strcasecmp(name, "nonline")) {
+    return igraph_i_famous(graph, igraph_i_famous_nonline);
+  } else if (!strcasecmp(name, "octahedral") ||
+	     !strcasecmp(name, "octahedron")) {
+    return igraph_i_famous(graph, igraph_i_famous_octahedron);
+  } else if (!strcasecmp(name, "petersen")) {
+    return igraph_i_famous(graph, igraph_i_famous_petersen);
+  } else if (!strcasecmp(name, "robertson")) {
+    return igraph_i_famous(graph, igraph_i_famous_robertson);
+  } else if (!strcasecmp(name, "smallestcyclicgroup")) {
+    return igraph_i_famous(graph, igraph_i_famous_smallestcyclicgroup);
+  } else if (!strcasecmp(name, "tetrahedral") ||
+	     !strcasecmp(name, "tetrahedron")) {
+    return igraph_i_famous(graph, igraph_i_famous_tetrahedron);
+  } else if (!strcasecmp(name, "thomassen")) {
+    return igraph_i_famous(graph, igraph_i_famous_thomassen);
+  } else if (!strcasecmp(name, "tutte")) {
+    return igraph_i_famous(graph, igraph_i_famous_tutte);
+  } else if (!strcasecmp(name, "uniquely3colorable")) {
+    return igraph_i_famous(graph, igraph_i_famous_uniquely3colorable);
+  } else if (!strcasecmp(name, "walther")) {
+    return igraph_i_famous(graph, igraph_i_famous_walther);
+  } else if (!strcasecmp(name, "zachary")) {
+    return igraph_i_famous(graph, igraph_i_famous_zachary);
+  } else {
+    IGRAPH_ERROR("Unknown graph, see documentation", IGRAPH_EINVAL);
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_adjlist
+ * Create a graph from an adjacency list
+ * 
+ * An adjacency list is a list of vectors, containing the neighbors 
+ * of all vertices. For operations that involve many changes to the
+ * graph structure, it is recommended that you convert the graph into
+ * an adjacency list via \ref igraph_adjlist_init(), perform the
+ * modifications (these are cheap for an adjacency list) and then
+ * recreate the igraph graph via this function.
+ * 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param adjlist The adjacency list.
+ * \param mode Whether or not to create a directed graph. \c IGRAPH_ALL
+ *             means an undirected graph, \c IGRAPH_OUT means a
+ *             directed graph from an out-adjacency list (i.e. each
+ *             list contains the successors of the corresponding
+ *             vertices), \c IGRAPH_IN means a directed graph from an
+ *             in-adjacency list
+ * \param duplicate Logical, for undirected graphs this specified
+ *        whether each edge is included twice, in the vectors of 
+ *        both adjacent vertices. If this is false (0), then it is
+ *        assumed that every edge is included only once. This argument 
+ *        is ignored for directed graphs.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_adjlist_init() for the opposite operation.
+ *
+ * Time complexity: O(|V|+|E|).
+ * 
+ */
+
+int igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist,
+		   igraph_neimode_t mode, igraph_bool_t duplicate) {
+  
+  long int no_of_nodes=igraph_adjlist_size(adjlist);
+  long int no_of_edges=0;
+  long int i;
+
+  igraph_vector_t edges;
+  long int edgeptr=0;
+
+  duplicate = duplicate && (mode == IGRAPH_ALL); /* only duplicate if undirected */
+  
+  for (i=0; i<no_of_nodes; i++) {
+    no_of_edges += igraph_vector_int_size(igraph_adjlist_get(adjlist, i));
+  }
+  
+  if (duplicate) {
+    no_of_edges /= 2;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2*no_of_edges);
+  
+  for (i=0; i<no_of_nodes; i++) {
+    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, i);
+    long int j, n=igraph_vector_int_size(neis);
+    long int loops=0;
+
+    for (j=0; j<n; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      if (nei==i) {
+        loops++; 
+      } else {
+        if (! duplicate || nei > i) {
+          if (edgeptr+2 > 2*no_of_edges) {
+            IGRAPH_ERROR("Invalid adjacency list, most probably not correctly"
+              " duplicated edges for an undirected graph", IGRAPH_EINVAL);
+          }
+          if (mode == IGRAPH_IN) {
+            VECTOR(edges)[edgeptr++] = nei;
+            VECTOR(edges)[edgeptr++] = i;
+          } else {
+            VECTOR(edges)[edgeptr++] = i;
+            VECTOR(edges)[edgeptr++] = nei;
+          }
+	    }
+      }
+    }
+    /* loops */
+    if (duplicate) { loops=loops/2; }
+    if (edgeptr+2*loops > 2*no_of_edges) {
+      IGRAPH_ERROR("Invalid adjacency list, most probably not correctly"
+		   " duplicated edges for an undirected graph", IGRAPH_EINVAL);
+    }
+    for (j=0; j<loops; j++) {
+      VECTOR(edges)[edgeptr++] = i;
+      VECTOR(edges)[edgeptr++] = i;
+    }
+  }
+
+  if (mode == IGRAPH_ALL)
+    IGRAPH_CHECK(igraph_create(graph, &edges, 
+			       (igraph_integer_t) no_of_nodes, 0));
+  else
+    IGRAPH_CHECK(igraph_create(graph, &edges, 
+			       (igraph_integer_t) no_of_nodes, 1));
+
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  return 0;
+}
diff --git a/src/sugiyama.c b/src/sugiyama.c
new file mode 100644
index 0000000..86bdc87
--- /dev/null
+++ b/src/sugiyama.c
@@ -0,0 +1,1309 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   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 "config.h"
+#include "igraph_centrality.h"
+#include "igraph_components.h"
+#include "igraph_constants.h"
+#include "igraph_constructors.h"
+#include "igraph_datatype.h"
+#include "igraph_error.h"
+#include "igraph_glpk_support.h"
+#include "igraph_interface.h"
+#include "igraph_memory.h"
+#include "igraph_structural.h"
+#include "igraph_types.h"
+
+#include <limits.h>
+
+/* #define SUGIYAMA_DEBUG */
+
+#ifdef _MSC_VER
+/* MSVC does not support variadic macros */
+#include <stdarg.h>
+static void debug(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+#ifdef SUGIYAMA_DEBUG
+  vfprintf(stderr, fmt, args);
+#endif
+  va_end(args);
+}
+#else
+#  ifdef SUGIYAMA_DEBUG
+#    define debug(...) fprintf(stderr, __VA_ARGS__)
+#  else
+#    define debug(...) 
+#  endif
+#endif
+
+/* MSVC uses __forceinline instead of inline */
+#ifdef _MSC_VER
+#  define INLINE __forceinline
+#else
+#  define INLINE inline
+#endif
+
+/*
+ * Implementation of the Sugiyama layout algorithm as described in:
+ *
+ * [1] 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.
+ *
+ * The layering (if not given in advance) is calculated by ... TODO
+ *
+ * [2] TODO
+ *
+ * The X coordinates of nodes within a layer are calculated using the method of
+ * Brandes & Köpf:
+ *
+ * [3] U. Brandes and B. Köpf, "Fast and Simple Horizontal Coordinate
+ * Assignment".  In: Lecture Notes in Computer Science 2265:31-44, 2002.
+ *
+ * Layer compaction is done according to:
+ *
+ * [4] N.S. Nikolov and A. Tarassov, "Graph layering by promotion of nodes".
+ * Journal of Discrete Applied Mathematics, special issue: IV ALIO/EURO
+ * workshop on applied combinatorial optimization, 154(5).
+ *
+ * The steps of the algorithm are as follows:
+ *
+ *   1. Cycle removal by finding an approximately minimal feedback arc set
+ *      and reversing the direction of edges in the set.  Algorithms for
+ *      finding minimal feedback arc sets are as follows:
+ *
+ *        - Find a cycle and find its minimum weight edge. Decrease the weight
+ *          of all the edges by w. Remove those edges whose weight became zero.
+ *          Repeat until there are no cycles. Re-introduce removed edges in
+ *          decreasing order of weights, ensuring that no cycles are created.
+ *
+ *        - Order the vertices somehow and remove edges which point backwards
+ *          in the ordering. Eades et al proposed the following procedure:
+ *
+ *            1. Iteratively remove sinks and prepend them to a vertex sequence
+ *               s2.
+ *
+ *            2. Iteratively remove sources and append them to a vertex sequence
+ *               s1.
+ *
+ *            3. Choose a vertex u s.t. the difference between the number of
+ *               rightward arcs and the number of leftward arcs is the largest,
+ *               remove u and append it to s1. Goto step 1 if there are still
+ *               more vertices.
+ *
+ *            4. Concatenate s1 with s2.
+ *
+ *          This algorithm is known to produce feedback arc sets at most the
+ *          size of m/2 - n/6, where m is the number of edges. Further
+ *          improvements are possible in step 3 which bring down the size of
+ *          the set to at most m/4 for cubic directed graphs, see Eades (1995).
+ *
+ *        - For undirected graphs, find a maximum weight spanning tree and
+ *          remove all the edges not in the spanning tree. For directed graphs,
+ *          find minimal cuts iteratively and remove edges pointing from A to
+ *          B or from B to A in the cut, depending on which one is smaller. Yes,
+ *          this is time-consuming.
+ *
+ *   2. Assigning vertices to layers according to [2].
+ *
+ *   3. Extracting weakly connected components. The remaining steps are
+ *      executed for each component.
+ *
+ *   4. Compacting the layering using the method of [4]. TODO
+ *      Steps 2-4 are performed only when no layering is given in advance.
+ *
+ *   5. Adding dummy nodes to ensure that each edge spans at most one layer
+ *      only.
+ *
+ *   6. Finding an optimal ordering of vertices within a layer using the
+ *      Sugiyama framework [1].
+ *
+ *   7. Assigning horizontal coordinates to each vertex using [3].
+ *
+ *   8. ???
+ *
+ *   9. Profit!
+ */
+
+/**
+ * Data structure to store a layering of the graph.
+ */
+typedef struct {
+  igraph_vector_ptr_t layers;
+} igraph_i_layering_t;
+
+/**
+ * Initializes a layering.
+ */
+int igraph_i_layering_init(igraph_i_layering_t* layering,
+    const igraph_vector_t* membership) {
+  long int i, n, num_layers;
+
+  if (igraph_vector_size(membership) == 0)
+    num_layers = 0;
+  else
+    num_layers = (long int) igraph_vector_max(membership) + 1;
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&layering->layers, num_layers));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &layering->layers);
+
+  for (i = 0; i < num_layers; i++) {
+    igraph_vector_t* vec = igraph_Calloc(1, igraph_vector_t);
+    IGRAPH_VECTOR_INIT_FINALLY(vec, 0);
+    VECTOR(layering->layers)[i] = vec;
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&layering->layers, igraph_vector_destroy); 
+
+  n = igraph_vector_size(membership);
+  for (i = 0; i < n; i++) {
+    long int l = (long int) VECTOR(*membership)[i];
+    igraph_vector_t* vec = VECTOR(layering->layers)[l];
+    IGRAPH_CHECK(igraph_vector_push_back(vec, i));
+  }
+
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Destroys a layering.
+ */
+void igraph_i_layering_destroy(igraph_i_layering_t* layering) {
+  igraph_vector_ptr_destroy_all(&layering->layers);
+}
+
+/**
+ * Returns the number of layers in a layering.
+ */
+int igraph_i_layering_num_layers(const igraph_i_layering_t* layering) {
+  return (int) igraph_vector_ptr_size(&layering->layers);
+}
+
+/**
+ * Returns the list of vertices in a given layer
+ */
+igraph_vector_t* igraph_i_layering_get(const igraph_i_layering_t* layering,
+    long int index) {
+  return (igraph_vector_t*)VECTOR(layering->layers)[index];
+}
+
+
+/**
+ * Forward declarations
+ */
+
+static int igraph_i_layout_sugiyama_place_nodes_vertically(const igraph_t* graph,
+    const igraph_vector_t* weights, igraph_vector_t* membership);
+static int igraph_i_layout_sugiyama_order_nodes_horizontally(const igraph_t* graph,
+    igraph_matrix_t* layout, const igraph_i_layering_t* layering,
+    long int maxiter);
+static int igraph_i_layout_sugiyama_place_nodes_horizontally(const igraph_t* graph,
+    igraph_matrix_t* layout, const igraph_i_layering_t* layering,
+    igraph_real_t hgap, igraph_integer_t no_of_real_nodes);
+
+/**
+ * Calculated the median of four numbers (not necessarily sorted).
+ */
+static INLINE igraph_real_t igraph_i_median_4(igraph_real_t x1,
+    igraph_real_t x2, igraph_real_t x3, igraph_real_t x4) {
+  igraph_real_t arr[4] = { x1, x2, x3, x4 };
+  igraph_vector_t vec;
+  igraph_vector_view(&vec, arr, 4);
+  igraph_vector_sort(&vec);
+  return (arr[1] + arr[2]) / 2.0;
+}
+
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_sugiyama
+ * \brief Sugiyama layout algorithm for layered directed acyclic graphs.
+ *
+ * </para><para>
+ * 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.
+ *
+ * </para><para>
+ * 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.
+ *
+ * </para><para>
+ * The Sugiyama layout may introduce "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.
+ * An edge in the original graph may either be mapped to a single edge in the
+ * extended graph or a \em path that starts and ends in the original
+ * source and target vertex and passes through multiple dummy vertices. In
+ * such cases, the user may also request the mapping of the edges of the extended
+ * graph back to the edges of the original graph.
+ *
+ * </para><para>
+ * For more details, see 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.
+ *
+ * \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. The first |V| rows
+ *              of the layout will contain the coordinates of the original graph,
+ *              the remaining rows contain the positions of the dummy nodes.
+ *              Therefore, you can use the result both with \p graph or with
+ *              \p extended_graph.
+ * \param extended_graph Pointer to an uninitialized graph object or \c NULL.
+ *                       The extended graph with the added dummy nodes will be
+ *                       returned here. In this graph, each edge points downwards
+ *                       to lower layers, spans exactly one layer and the first
+ *                       |V| vertices coincide with the vertices of the
+ *                       original graph.
+ * \param extd_to_orig_eids Pointer to a vector or \c NULL. If not \c NULL, the
+ *                          mapping from the edge IDs of the extended graph back
+ *                          to the edge IDs of the original graph will be stored
+ *                          here.
+ * \param layers  The layer index for each vertex or \c NULL if the layers should
+ *                be determined automatically by igraph.
+ * \param hgap  The preferred minimum horizontal gap between vertices in the same
+ *              layer.
+ * \param vgap  The distance between layers.
+ * \param maxiter 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 Weights of the edges. These are used only if the graph contains
+ *                cycles; igraph will tend to reverse edges with smaller
+ *                weights when breaking the cycles.
+ */
+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) {
+  long int i, j, k, l, m, nei;
+  long int no_of_nodes = (long int)igraph_vcount(graph);
+  long int comp_idx;
+  long int next_extd_vertex_id = no_of_nodes;
+  igraph_bool_t directed = igraph_is_directed(graph);
+  igraph_integer_t no_of_components;  /* number of components of the original graph */
+  igraph_vector_t membership;         /* components of the original graph */
+  igraph_vector_t extd_edgelist;   /* edge list of the extended graph */
+  igraph_vector_t layers_own;  /* layer indices after having eliminated empty layers */
+  igraph_real_t dx=0, dx2=0;  /* displacement of the current component on the X axis */
+  igraph_vector_t layer_to_y; /* mapping from layer indices to final Y coordinates */
+
+  if (layers && igraph_vector_size(layers) != no_of_nodes) {
+    IGRAPH_ERROR("layer vector too short or too long", IGRAPH_EINVAL);
+  }
+
+  if (extd_graph != 0) {
+    IGRAPH_VECTOR_INIT_FINALLY(&extd_edgelist, 0);
+    if (extd_to_orig_eids != 0)
+      igraph_vector_clear(extd_to_orig_eids);
+  }
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
+  IGRAPH_VECTOR_INIT_FINALLY(&membership, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&layer_to_y, 0);
+
+  /* 1. Find a feedback arc set if we don't have a layering yet. If we do have
+   *    a layering, we can leave all the edges as is as they will be re-oriented
+   *    to point downwards only anyway. */
+  if (layers == 0) {
+    IGRAPH_VECTOR_INIT_FINALLY(&layers_own, no_of_nodes);
+    IGRAPH_CHECK(igraph_i_layout_sugiyama_place_nodes_vertically(
+          graph, weights, &layers_own));
+  } else {
+    IGRAPH_CHECK(igraph_vector_copy(&layers_own, layers));
+    IGRAPH_FINALLY(igraph_vector_destroy, &layers_own);
+  }
+
+  /* Normalize layering, eliminate empty layers */
+  if (no_of_nodes > 0) {
+    igraph_vector_t inds;
+    IGRAPH_VECTOR_INIT_FINALLY(&inds, 0);
+    IGRAPH_CHECK((int) igraph_vector_qsort_ind(&layers_own, &inds, 0));
+    j = -1; dx = VECTOR(layers_own)[(long int)VECTOR(inds)[0]] - 1;
+    for (i = 0; i < no_of_nodes; i++) {
+      k = (long int)VECTOR(inds)[i];
+      if (VECTOR(layers_own)[k] > dx) {
+        /* New layer starts here */
+        dx = VECTOR(layers_own)[k];
+        j++;
+        IGRAPH_CHECK(igraph_vector_push_back(&layer_to_y, dx * vgap));
+      }
+      VECTOR(layers_own)[k] = j;
+    }
+    igraph_vector_destroy(&inds);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  /* 2. Find the connected components. */
+  IGRAPH_CHECK(igraph_clusters(graph, &membership, 0, &no_of_components,
+              IGRAPH_WEAK));
+
+  /* 3. For each component... */
+  dx = 0;
+  for (comp_idx = 0; comp_idx < no_of_components; comp_idx++) {
+    /* Extract the edges of the comp_idx'th component and add dummy nodes for edges
+     * spanning more than one layer. */
+    long int component_size, next_new_vertex_id;
+    igraph_vector_t old2new_vertex_ids;
+    igraph_vector_t new2old_vertex_ids;
+    igraph_vector_t new_layers;
+    igraph_vector_t edgelist;
+    igraph_vector_t neis;
+
+    IGRAPH_VECTOR_INIT_FINALLY(&edgelist, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&new2old_vertex_ids, no_of_nodes);
+    IGRAPH_VECTOR_INIT_FINALLY(&old2new_vertex_ids, no_of_nodes);
+    IGRAPH_VECTOR_INIT_FINALLY(&new_layers, 0);
+
+    igraph_vector_fill(&old2new_vertex_ids, -1);
+
+    /* Construct a mapping from the old vertex ids to the new ones */
+    for (i = 0, next_new_vertex_id = 0; i < no_of_nodes; i++) {
+      if (VECTOR(membership)[i] == comp_idx) {
+        IGRAPH_CHECK(igraph_vector_push_back(&new_layers, VECTOR(layers_own)[i]));
+        VECTOR(new2old_vertex_ids)[next_new_vertex_id] = i;
+        VECTOR(old2new_vertex_ids)[i] = next_new_vertex_id;
+        next_new_vertex_id++;
+      }
+    }
+    component_size = next_new_vertex_id;
+
+    /* Construct a proper layering of the component in new_graph where each edge
+     * points downwards and spans exactly one layer. */
+    for (i = 0; i < no_of_nodes; i++) {
+      if (VECTOR(membership)[i] != comp_idx)
+        continue;
+
+      /* Okay, this vertex is in the component we are considering.
+       * Add the neighbors of this vertex, excluding loops */
+      IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) i,
+				   IGRAPH_OUT));
+      j = igraph_vector_size(&neis);
+      for (k = 0; k < j; k++) {
+        long int eid = (long int) VECTOR(neis)[k];
+        if (directed) {
+          nei = IGRAPH_TO(graph, eid);
+        } else {
+          nei = IGRAPH_OTHER(graph, eid, i);
+          if (nei < i)   /* to avoid considering edges twice */
+            continue;
+        }
+        if (VECTOR(layers_own)[i] == VECTOR(layers_own)[nei]) {
+          /* Edge goes within the same layer, we don't need this in the
+           * layered graph, but we need it in the extended graph */
+          if (extd_graph != 0) {
+            IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, i));
+            IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, nei));
+            if (extd_to_orig_eids != 0)
+              IGRAPH_CHECK(igraph_vector_push_back(extd_to_orig_eids, eid));
+          }
+        } else if (VECTOR(layers_own)[i] > VECTOR(layers_own)[nei]) {
+          /* Edge goes upwards, we have to flip it */
+          IGRAPH_CHECK(igraph_vector_push_back(&edgelist, 
+                       VECTOR(old2new_vertex_ids)[nei]));
+          for (l = (long int) VECTOR(layers_own)[nei]+1; 
+	       l < VECTOR(layers_own)[i]; l++) {
+            IGRAPH_CHECK(igraph_vector_push_back(&new_layers, l));
+            IGRAPH_CHECK(igraph_vector_push_back(&edgelist, next_new_vertex_id));
+            IGRAPH_CHECK(igraph_vector_push_back(&edgelist, next_new_vertex_id++));
+          }
+          IGRAPH_CHECK(igraph_vector_push_back(&edgelist, 
+                       VECTOR(old2new_vertex_ids)[i]));
+          /* Also add the edge to the extended graph if needed, but this time
+           * with the proper orientation */
+          if (extd_graph != 0) {
+            IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, i));
+            next_extd_vertex_id += VECTOR(layers_own)[i] - VECTOR(layers_own)[nei] - 1;
+            for (l = (long int) VECTOR(layers_own)[i]-1, m = 1; 
+		 l > VECTOR(layers_own)[nei]; l--, m++) {
+              IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, next_extd_vertex_id-m));
+              IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, next_extd_vertex_id-m));
+              if (extd_to_orig_eids != 0)
+                IGRAPH_CHECK(igraph_vector_push_back(extd_to_orig_eids, eid));
+            }
+            IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, nei));
+            if (extd_to_orig_eids != 0)
+              IGRAPH_CHECK(igraph_vector_push_back(extd_to_orig_eids, eid));
+          }
+        } else {
+          /* Edge goes downwards */
+          IGRAPH_CHECK(igraph_vector_push_back(&edgelist, 
+                       VECTOR(old2new_vertex_ids)[i]));
+          for (l = (long int) VECTOR(layers_own)[i]+1;
+	       l < VECTOR(layers_own)[nei]; l++) {
+            IGRAPH_CHECK(igraph_vector_push_back(&new_layers, l));
+            IGRAPH_CHECK(igraph_vector_push_back(&edgelist, next_new_vertex_id));
+            IGRAPH_CHECK(igraph_vector_push_back(&edgelist, next_new_vertex_id++));
+          }
+          IGRAPH_CHECK(igraph_vector_push_back(&edgelist, 
+                       VECTOR(old2new_vertex_ids)[nei]));
+          /* Also add the edge to the extended graph */
+          if (extd_graph != 0) {
+            IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, i));
+            for (l = (long int) VECTOR(layers_own)[i]+1;
+		 l < VECTOR(layers_own)[nei]; l++) {
+              IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, next_extd_vertex_id));
+              IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, next_extd_vertex_id++));
+              if (extd_to_orig_eids != 0)
+                IGRAPH_CHECK(igraph_vector_push_back(extd_to_orig_eids, eid));
+            }
+            IGRAPH_CHECK(igraph_vector_push_back(&extd_edgelist, nei));
+            if (extd_to_orig_eids != 0)
+              IGRAPH_CHECK(igraph_vector_push_back(extd_to_orig_eids, eid));
+          }
+        }
+      }
+    }
+
+    /* At this point, we have the subgraph with the dummy nodes and
+     * edges, so we can run Sugiyama's algorithm on it. */
+    {
+      igraph_matrix_t layout;
+      igraph_i_layering_t layering;
+      igraph_t subgraph;
+
+      IGRAPH_CHECK(igraph_matrix_init(&layout, next_new_vertex_id, 2));
+      IGRAPH_FINALLY(igraph_matrix_destroy, &layout);
+      IGRAPH_CHECK(igraph_create(&subgraph, &edgelist, (igraph_integer_t) 
+				 next_new_vertex_id, 1));
+      IGRAPH_FINALLY(igraph_destroy, &subgraph);
+
+      /*
+      igraph_vector_print(&edgelist);
+      igraph_vector_print(&new_layers);
+      */
+
+      /* Assign the vertical coordinates */
+      for (i = 0; i < next_new_vertex_id; i++)
+        MATRIX(layout, i, 1) = VECTOR(new_layers)[i];
+
+      /* Create a layering */
+      IGRAPH_CHECK(igraph_i_layering_init(&layering, &new_layers));
+      IGRAPH_FINALLY(igraph_i_layering_destroy, &layering);
+
+      /* Find the order in which the nodes within a layer should be placed */
+      IGRAPH_CHECK(igraph_i_layout_sugiyama_order_nodes_horizontally(&subgraph, &layout,
+            &layering, maxiter));
+
+      /* Assign the horizontal coordinates. This is according to the algorithm
+       * of Brandes & Köpf */
+      IGRAPH_CHECK(igraph_i_layout_sugiyama_place_nodes_horizontally(&subgraph, &layout,
+            &layering, hgap, (igraph_integer_t) component_size));
+
+      /* Re-assign rows into the result matrix, and at the same time, */
+      /* adjust dx so that the next component does not overlap this one */
+      j = next_new_vertex_id - component_size;
+      k = igraph_matrix_nrow(res);
+      IGRAPH_CHECK(igraph_matrix_add_rows(res, j));
+      dx2 = dx;
+      for (i = 0; i < component_size; i++) {
+        l = (long int)VECTOR(new2old_vertex_ids)[i];
+        MATRIX(*res, l, 0) = MATRIX(layout, i, 0) + dx;
+        MATRIX(*res, l, 1) = VECTOR(layer_to_y)[(long)MATRIX(layout, i, 1)];
+        if (dx2 < MATRIX(*res, l, 0))
+          dx2 = MATRIX(*res, l, 0);
+      }
+      for (i = component_size; i < next_new_vertex_id; i++) {
+        MATRIX(*res, k, 0) = MATRIX(layout, i, 0) + dx;
+        MATRIX(*res, k, 1) = VECTOR(layer_to_y)[(long)MATRIX(layout, i, 1)];
+        if (dx2 < MATRIX(*res, k, 0))
+          dx2 = MATRIX(*res, k, 0);
+        k++;
+      }
+      dx = dx2 + hgap;
+
+      igraph_destroy(&subgraph);
+      igraph_i_layering_destroy(&layering);
+      igraph_matrix_destroy(&layout);
+      IGRAPH_FINALLY_CLEAN(3);
+    }
+
+    igraph_vector_destroy(&new_layers);
+    igraph_vector_destroy(&old2new_vertex_ids);
+    igraph_vector_destroy(&new2old_vertex_ids);
+    igraph_vector_destroy(&edgelist);
+    igraph_vector_destroy(&neis);
+    IGRAPH_FINALLY_CLEAN(5);
+  }
+
+  igraph_vector_destroy(&layers_own);
+  igraph_vector_destroy(&layer_to_y);
+  igraph_vector_destroy(&membership);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (extd_graph != 0) {
+    IGRAPH_CHECK(igraph_create(extd_graph, &extd_edgelist, (igraph_integer_t) 
+			       next_extd_vertex_id, igraph_is_directed(graph)));
+    igraph_vector_destroy(&extd_edgelist);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return IGRAPH_SUCCESS;
+}
+
+static int igraph_i_layout_sugiyama_place_nodes_vertically(const igraph_t* graph,
+    const igraph_vector_t* weights, igraph_vector_t* membership) {
+  long int no_of_nodes = igraph_vcount(graph);
+  long int no_of_edges = igraph_ecount(graph);
+  IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
+
+  if (no_of_edges == 0) {
+    igraph_vector_fill(membership, 0);
+    return IGRAPH_SUCCESS;
+  }
+
+#ifdef HAVE_GLPK
+  if (igraph_is_directed(graph) && no_of_nodes <= 1000) {
+    /* Network simplex algorithm of Gansner et al, using the original linear
+     * programming formulation */
+    long int i, j;
+    igraph_vector_t outdegs, indegs, feedback_edges;
+    glp_prob *ip;
+    glp_smcp parm;
+
+    /* Allocate storage and create the problem */
+    ip = glp_create_prob();
+    IGRAPH_FINALLY(glp_delete_prob, ip);
+    IGRAPH_VECTOR_INIT_FINALLY(&feedback_edges, 0);
+    IGRAPH_VECTOR_INIT_FINALLY(&outdegs, no_of_nodes);
+    IGRAPH_VECTOR_INIT_FINALLY(&indegs, no_of_nodes);
+
+    /* Find an approximate feedback edge set */
+    IGRAPH_CHECK(igraph_i_feedback_arc_set_eades(graph, &feedback_edges, weights, 0));
+    igraph_vector_sort(&feedback_edges);
+
+    /* Calculate in- and out-strengths for the remaining edges */
+    IGRAPH_CHECK(igraph_strength(graph, &indegs, igraph_vss_all(),
+          IGRAPH_IN, 1, weights));
+    IGRAPH_CHECK(igraph_strength(graph, &outdegs, igraph_vss_all(),
+          IGRAPH_IN, 1, weights));
+    j = igraph_vector_size(&feedback_edges);
+    for (i = 0; i < j; i++) {
+      long int eid = (long int) VECTOR(feedback_edges)[i];
+      long int from = IGRAPH_FROM(graph, eid);
+      long int to = IGRAPH_TO(graph, eid);
+      VECTOR(outdegs)[from] -= weights ? VECTOR(*weights)[eid] : 1;
+      VECTOR(indegs)[to] -= weights ? VECTOR(*weights)[eid] : 1;
+    }
+
+    /* Configure GLPK */
+    glp_term_out(GLP_OFF);
+    glp_init_smcp(&parm);
+    parm.msg_lev = GLP_MSG_OFF;
+    parm.presolve = GLP_OFF;
+
+    /* Set up variables and objective function coefficients */
+    glp_set_obj_dir(ip, GLP_MIN);
+    glp_add_cols(ip, (int) no_of_nodes);
+    IGRAPH_CHECK(igraph_vector_sub(&outdegs, &indegs));
+    for (i = 1; i <= no_of_nodes; i++) {
+      glp_set_col_kind(ip, (int) i, GLP_IV);
+      glp_set_col_bnds(ip, (int) i, GLP_LO, 0.0, 0.0);
+      glp_set_obj_coef(ip, (int) i, VECTOR(outdegs)[i-1]);
+    }
+    igraph_vector_destroy(&indegs);
+    igraph_vector_destroy(&outdegs);
+    IGRAPH_FINALLY_CLEAN(2);
+
+    /* Add constraints */
+    glp_add_rows(ip, (int) no_of_edges);
+    IGRAPH_CHECK(igraph_vector_push_back(&feedback_edges, -1));
+    j = 0;
+    for (i = 0; i < no_of_edges; i++) {
+      int ind[3];
+      double val[3] = {0, -1, 1};
+      ind[1] = IGRAPH_FROM(graph, i)+1;
+      ind[2] = IGRAPH_TO(graph, i)+1;
+
+      if (ind[1] == ind[2]) {
+        if (VECTOR(feedback_edges)[j] == i)
+          j++;
+        continue;
+      }
+
+      if (VECTOR(feedback_edges)[j] == i) {
+        /* This is a feedback edge, add it reversed */
+        glp_set_row_bnds(ip, (int) i+1, GLP_UP, -1, -1);
+        j++;
+      } else {
+        glp_set_row_bnds(ip, (int) i+1, GLP_LO, 1, 1);
+      }
+      glp_set_mat_row(ip, (int) i+1, 2, ind, val);
+    }
+
+    /* Solve the problem */
+    IGRAPH_GLPK_CHECK(glp_simplex(ip, &parm),
+        "Vertical arrangement step using IP failed");
+
+    /* The problem is totally unimodular, therefore the output of the simplex
+     * solver can be converted to an integer solution easily */
+    for (i = 0; i < no_of_nodes; i++)
+      VECTOR(*membership)[i] = floor(glp_get_col_prim(ip, (int) i+1));
+
+    glp_delete_prob(ip);
+    igraph_vector_destroy(&feedback_edges);
+    IGRAPH_FINALLY_CLEAN(2);
+  } else if (igraph_is_directed(graph)) {
+    IGRAPH_CHECK(igraph_i_feedback_arc_set_eades(graph, 0, weights, membership));
+  } else {
+    IGRAPH_CHECK(igraph_i_feedback_arc_set_undirected(graph, 0, weights, membership));
+  }
+#else
+  if (igraph_is_directed(graph)) {
+    IGRAPH_CHECK(igraph_i_feedback_arc_set_eades(graph, 0, weights, membership));
+  } else {
+    IGRAPH_CHECK(igraph_i_feedback_arc_set_undirected(graph, 0, weights, membership));
+  }
+#endif
+
+  return IGRAPH_SUCCESS;
+}
+
+static int igraph_i_layout_sugiyama_calculate_barycenters(const igraph_t* graph,
+    const igraph_i_layering_t* layering, long int layer_index,
+    igraph_neimode_t direction, const igraph_matrix_t* layout,
+    igraph_vector_t* barycenters) {
+  long int i, j, m, n;
+  igraph_vector_t* layer_members = igraph_i_layering_get(layering, layer_index);
+  igraph_vector_t neis;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+
+  n = igraph_vector_size(layer_members);
+  IGRAPH_CHECK(igraph_vector_resize(barycenters, n));
+  igraph_vector_null(barycenters);
+
+  for (i = 0; i < n; i++) {
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
+				  VECTOR(*layer_members)[i], direction));
+    m = igraph_vector_size(&neis);
+    if (m == 0) {
+      /* No neighbors in this direction. Just use the current X coordinate */
+      VECTOR(*barycenters)[i] = MATRIX(*layout, i, 0);
+    } else {
+      for (j = 0; j < m; j++) {
+        VECTOR(*barycenters)[i] += MATRIX(*layout, (long)VECTOR(neis)[j], 0);
+      }
+      VECTOR(*barycenters)[i] /= m;
+    }
+  }
+
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * Given a properly layered graph where each edge points downwards and spans
+ * exactly one layer, arranges the nodes in each layer horizontally in a way
+ * that strives to minimize edge crossings.
+ */
+static int igraph_i_layout_sugiyama_order_nodes_horizontally(const igraph_t* graph,
+    igraph_matrix_t* layout, const igraph_i_layering_t* layering,
+    long int maxiter) {
+  long int i, n, nei;
+  long int no_of_vertices = igraph_vcount(graph);
+  long int no_of_layers = igraph_i_layering_num_layers(layering);
+  long int iter, layer_index;
+  igraph_vector_t* layer_members;
+  igraph_vector_t neis, barycenters, sort_indices;
+  igraph_bool_t changed;
+
+  /* The first column of the matrix will serve as the ordering */
+  /* Start with a first-seen ordering within each layer */
+  {
+    long int *xs = igraph_Calloc(no_of_layers, long int);
+    if (xs == 0)
+      IGRAPH_ERROR("cannot order nodes horizontally", IGRAPH_ENOMEM);
+    for (i = 0; i < no_of_vertices; i++)
+      MATRIX(*layout, i, 0) = xs[(long int)MATRIX(*layout, i, 1)]++;
+    free(xs);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&barycenters, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&sort_indices, 0);
+
+  /* Start the effective part of the Sugiyama algorithm */
+  iter = 0; changed = 1;
+  while (changed && iter < maxiter) {
+    changed = 0;
+
+    /* Phase 1 */
+
+    /* Moving downwards and sorting by upper barycenters */
+    for (layer_index = 1; layer_index < no_of_layers; layer_index++) {
+      layer_members = igraph_i_layering_get(layering, layer_index);
+      n = igraph_vector_size(layer_members);
+
+      igraph_i_layout_sugiyama_calculate_barycenters(graph,
+          layering, layer_index, IGRAPH_IN, layout, &barycenters);
+
+#ifdef SUGIYAMA_DEBUG
+      printf("Layer %ld, aligning to upper barycenters\n", layer_index);
+      printf("Vertices: "); igraph_vector_print(layer_members);
+      printf("Barycenters: "); igraph_vector_print(&barycenters);
+#endif
+      IGRAPH_CHECK((int) igraph_vector_qsort_ind(&barycenters, 
+						 &sort_indices, 0));
+      for (i = 0; i < n; i++) {
+        nei = (long)VECTOR(*layer_members)[(long)VECTOR(sort_indices)[i]];
+        VECTOR(barycenters)[i] = nei;
+        MATRIX(*layout, nei, 0) = i;
+      }
+      if (!igraph_vector_all_e(layer_members, &barycenters)) {
+        IGRAPH_CHECK(igraph_vector_update(layer_members, &barycenters));
+#ifdef SUGIYAMA_DEBUG
+        printf("New vertex order: "); igraph_vector_print(layer_members);
+#endif
+        changed = 1;
+      } else {
+#ifdef SUGIYAMA_DEBUG
+        printf("Order did not change.\n");
+#endif
+      }
+    }
+
+    /* Moving upwards and sorting by lower barycenters */
+    for (layer_index = no_of_layers - 2; layer_index >= 0; layer_index--) {
+      layer_members = igraph_i_layering_get(layering, layer_index);
+      n = igraph_vector_size(layer_members);
+
+      igraph_i_layout_sugiyama_calculate_barycenters(graph,
+          layering, layer_index, IGRAPH_OUT, layout, &barycenters);
+
+#ifdef SUGIYAMA_DEBUG
+      printf("Layer %ld, aligning to lower barycenters\n", layer_index);
+      printf("Vertices: "); igraph_vector_print(layer_members);
+      printf("Barycenters: "); igraph_vector_print(&barycenters);
+#endif
+
+      IGRAPH_CHECK((int) igraph_vector_qsort_ind(&barycenters,
+						 &sort_indices, 0));
+      for (i = 0; i < n; i++) {
+        nei = (long)VECTOR(*layer_members)[(long)VECTOR(sort_indices)[i]];
+        VECTOR(barycenters)[i] = nei;
+        MATRIX(*layout, nei, 0) = i;
+      }
+      if (!igraph_vector_all_e(layer_members, &barycenters)) {
+        IGRAPH_CHECK(igraph_vector_update(layer_members, &barycenters));
+#ifdef SUGIYAMA_DEBUG
+        printf("New vertex order: "); igraph_vector_print(layer_members);
+#endif
+        changed = 1;
+      } else {
+#ifdef SUGIYAMA_DEBUG
+        printf("Order did not change.\n");
+#endif
+      }
+    }
+
+#ifdef SUGIYAMA_DEBUG
+    printf("==== Finished iteration %ld\n", iter);
+#endif
+
+    iter++;
+  }
+
+  igraph_vector_destroy(&barycenters);
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&sort_indices);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return IGRAPH_SUCCESS;
+}
+
+#define IS_DUMMY(v) ((v >= no_of_real_nodes))
+#define IS_INNER_SEGMENT(u, v) (IS_DUMMY(u) && IS_DUMMY(v))
+#define X_POS(v) (MATRIX(*layout, v, 0))
+
+static int igraph_i_layout_sugiyama_vertical_alignment(const igraph_t* graph,
+    const igraph_i_layering_t* layering, const igraph_matrix_t* layout,
+    const igraph_vector_bool_t* ignored_edges,
+    igraph_bool_t reverse, igraph_bool_t align_right,
+    igraph_vector_t* roots, igraph_vector_t* align);
+static int igraph_i_layout_sugiyama_horizontal_compaction(const igraph_t* graph,
+    const igraph_vector_t* vertex_to_the_left,
+    const igraph_vector_t* roots, const igraph_vector_t* align,
+    igraph_real_t hgap, igraph_vector_t* xs);
+static int igraph_i_layout_sugiyama_horizontal_compaction_place_block(long int v,
+    const igraph_vector_t* vertex_to_the_left,
+    const igraph_vector_t* roots, const igraph_vector_t* align,
+    igraph_vector_t* sinks, igraph_vector_t* shifts,
+    igraph_real_t hgap, igraph_vector_t* xs);
+
+static int igraph_i_layout_sugiyama_place_nodes_horizontally(const igraph_t* graph,
+    igraph_matrix_t* layout, const igraph_i_layering_t* layering,
+    igraph_real_t hgap, igraph_integer_t no_of_real_nodes) {
+
+  long int i, j, k, l, n;
+  long int no_of_layers = igraph_i_layering_num_layers(layering);
+  long int no_of_nodes = igraph_vcount(graph);
+  long int no_of_edges = igraph_ecount(graph);
+  igraph_vector_t neis1, neis2;
+  igraph_vector_t xs[4];
+  igraph_vector_t roots, align;
+  igraph_vector_t vertex_to_the_left;
+  igraph_vector_bool_t ignored_edges;
+
+  /*
+  {
+    igraph_vector_t edgelist;
+    IGRAPH_VECTOR_INIT_FINALLY(&edgelist, 0);
+    IGRAPH_CHECK(igraph_get_edgelist(graph, &edgelist, 0));
+    igraph_vector_print(&edgelist);
+    igraph_vector_destroy(&edgelist);
+    IGRAPH_FINALLY_CLEAN(1);
+
+    for (i = 0; i < no_of_layers; i++) {
+      igraph_vector_t* layer = igraph_i_layering_get(layering, i);
+      igraph_vector_print(layer);
+    }
+  }
+  */
+
+  IGRAPH_CHECK(igraph_vector_bool_init(&ignored_edges, no_of_edges));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &ignored_edges);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&vertex_to_the_left, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis2, 0);
+
+  /* First, find all type 1 conflicts and mark one of the edges participating
+   * in the conflict as being ignored. If one of the edges in the conflict
+   * is a non-inner segment and the other is an inner segment, we ignore the
+   * non-inner segment as we want to keep inner segments vertical.
+   */
+  for (i = 0; i < no_of_layers-1; i++) {
+    igraph_vector_t* vertices = igraph_i_layering_get(layering, i);
+    n = igraph_vector_size(vertices);
+
+    /* Find all the edges from this layer to the next */
+    igraph_vector_clear(&neis1);
+    for (j = 0; j < n; j++) {
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis2, (igraph_integer_t) 
+				    VECTOR(*vertices)[j], IGRAPH_OUT));
+      IGRAPH_CHECK(igraph_vector_append(&neis1, &neis2));
+    }
+
+    /* Consider all pairs of edges and check whether they are in a type 1
+     * conflict */
+    n = igraph_vector_size(&neis1);
+    for (j = 0; j < n; j++) {
+      long int u = IGRAPH_FROM(graph, j);
+      long int v = IGRAPH_TO(graph, j);
+      igraph_bool_t j_inner = IS_INNER_SEGMENT(u, v);
+      igraph_bool_t crossing;
+
+      for (k = j+1; k < n; k++) {
+        long int w = IGRAPH_FROM(graph, k);
+        long int x = IGRAPH_TO(graph, k);
+        if (IS_INNER_SEGMENT(w, x) == j_inner)
+          continue;
+        /* Do the u --> v and w --> x edges cross? */
+        crossing = (u == w || v == x);
+        if (!crossing) {
+          if (X_POS(u) <= X_POS(w)) {
+            crossing = X_POS(v) >= X_POS(x);
+          } else {
+            crossing = X_POS(v) <= X_POS(x);
+          }
+        }
+        if (crossing) {
+          if (j_inner) {
+            VECTOR(ignored_edges)[k] = 1;
+          } else {
+            VECTOR(ignored_edges)[j] = 1;
+          }
+        }
+      }
+    }
+  }
+
+  igraph_vector_destroy(&neis1);
+  igraph_vector_destroy(&neis2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  /*
+   * Prepare vertex_to_the_left where the ith element stores
+   * the index of the vertex to the left of vertex i, or i itself if the
+   * vertex is the leftmost vertex in a layer.
+   */
+  for (i = 0; i < no_of_layers; i++) {
+    igraph_vector_t* vertices = igraph_i_layering_get(layering, i);
+    n = igraph_vector_size(vertices);
+    if (n == 0)
+      continue;
+
+    k = l = (long int)VECTOR(*vertices)[0];
+    VECTOR(vertex_to_the_left)[k] = k;
+    for (j = 1; j < n; j++) {
+      k = (long int)VECTOR(*vertices)[j];
+      VECTOR(vertex_to_the_left)[k] = l;
+      l = k;
+    }
+  }
+
+  /* Type 1 conflicts found, ignored edges chosen, vertex_to_the_left
+   * prepared. Run vertical alignment for all four combinations */
+  for (i = 0; i < 4; i++)
+    IGRAPH_VECTOR_INIT_FINALLY(&xs[i], no_of_nodes);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&roots, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&align, no_of_nodes);
+
+  for (i = 0; i < 4; i++) {
+    IGRAPH_CHECK(igraph_i_layout_sugiyama_vertical_alignment(graph,
+          layering, layout, &ignored_edges,
+	  /* reverse = */ (igraph_bool_t) i / 2, /* align_right = */ i % 2,
+          &roots, &align));
+    IGRAPH_CHECK(igraph_i_layout_sugiyama_horizontal_compaction(graph,
+          &vertex_to_the_left, &roots, &align, hgap, &xs[i]));
+  }
+
+  {
+    igraph_real_t width, min_width, mins[4], maxs[4], diff;
+    /* Find the alignment with the minimum width */
+    min_width = IGRAPH_INFINITY; j = 0;
+    for (i = 0; i < 4; i++) {
+      mins[i] = igraph_vector_min(&xs[i]);
+      maxs[i] = igraph_vector_max(&xs[i]);
+      width = maxs[i] - mins[i];
+      if (width < min_width) {
+        min_width = width;
+        j = i;
+      }
+    }
+
+    /* Leftmost alignments: align them s.t. the min X coordinate is equal to
+     * the minimum X coordinate of the alignment with the smallest width.
+     * Rightmost alignments: align them s.t. the max X coordinate is equal to
+     * the max X coordinate of the alignment with the smallest width.
+     */
+    for (i = 0; i < 4; i++) {
+      if (j == i)
+        continue;
+      if (i % 2 == 0) {
+        /* Leftmost alignment */
+        diff = mins[j] - mins[i];
+      } else {
+        /* Rightmost alignment */
+        diff = maxs[j] - maxs[i];
+      }
+      igraph_vector_add_constant(&xs[i], diff);
+    }
+  }
+
+  /* For every vertex, find the median of the X coordinates in the four
+   * alignments */
+  for (i = 0; i < no_of_nodes; i++) {
+    X_POS(i) = igraph_i_median_4(VECTOR(xs[0])[i], VECTOR(xs[1])[i],
+        VECTOR(xs[2])[i], VECTOR(xs[3])[i]);
+  }
+
+  igraph_vector_destroy(&roots);
+  igraph_vector_destroy(&align);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  for (i = 0; i < 4; i++)
+    igraph_vector_destroy(&xs[i]);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  igraph_vector_destroy(&vertex_to_the_left);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  igraph_vector_bool_destroy(&ignored_edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return IGRAPH_SUCCESS;
+}
+
+static int igraph_i_layout_sugiyama_vertical_alignment(const igraph_t* graph,
+    const igraph_i_layering_t* layering, const igraph_matrix_t* layout,
+    const igraph_vector_bool_t* ignored_edges,
+    igraph_bool_t reverse, igraph_bool_t align_right,
+    igraph_vector_t* roots, igraph_vector_t* align) {
+  long int i, j, k, n, di, dj, i_limit, j_limit, r;
+  long int no_of_layers = igraph_i_layering_num_layers(layering);
+  long int no_of_nodes = igraph_vcount(graph);
+  igraph_neimode_t neimode = (reverse ? IGRAPH_OUT : IGRAPH_IN);
+  igraph_vector_t neis, xs, inds;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&xs, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&inds, 0);
+
+  IGRAPH_CHECK(igraph_vector_resize(roots, no_of_nodes));
+  IGRAPH_CHECK(igraph_vector_resize(align, no_of_nodes));
+
+  for (i = 0; i < no_of_nodes; i++) {
+    VECTOR(*roots)[i] = VECTOR(*align)[i] = i;
+  }
+
+  /* When reverse = False, we are aligning "upwards" in the tree, hence we
+   * have to loop i from 1 to no_of_layers-1 (inclusive) and use neimode=IGRAPH_IN.
+   * When reverse = True, we are aligning "downwards", hence we have to loop
+   * i from no_of_layers-2 to 0 (inclusive) and use neimode=IGRAPH_OUT.
+   */
+  i       = reverse ? (no_of_layers-2) : 1;
+  di      = reverse ? -1 : 1;
+  i_limit = reverse ? -1 : no_of_layers;
+  for (; i != i_limit; i += di) {
+    igraph_vector_t *layer = igraph_i_layering_get(layering, i);
+
+    /* r = 0 in the paper, but C arrays are indexed from 0 */
+    r = align_right ? LONG_MAX : -1;
+
+    /* If align_right is 1, we have to process the layer in reverse order */
+    j       = align_right ? (igraph_vector_size(layer)-1) : 0;
+    dj      = align_right ? -1 : 1;
+    j_limit = align_right ? -1 : igraph_vector_size(layer);
+    for (; j != j_limit; j += dj) {
+      long int medians[2];
+      long int vertex = (long int) VECTOR(*layer)[j];
+      long int pos;
+
+      if (VECTOR(*align)[vertex] != vertex)
+        /* This vertex is already aligned with some other vertex,
+         * so there's nothing to do */
+        continue;
+
+      /* Find the neighbors of vertex j in layer i */
+      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) vertex, 
+				    neimode));
+
+      n = igraph_vector_size(&neis);
+      if (n == 0)
+        /* No neighbors in this direction, continue */
+        continue;
+      if (n == 1) {
+        /* Just one neighbor; the median is trivial */
+        medians[0] = (long int) VECTOR(neis)[0];
+        medians[1] = -1;
+      } else {
+        /* Sort the neighbors by their X coordinates */
+        IGRAPH_CHECK(igraph_vector_resize(&xs, n));
+        for (k = 0; k < n; k++)
+          VECTOR(xs)[k] = X_POS((long int)VECTOR(neis)[k]);
+        IGRAPH_CHECK((int) igraph_vector_qsort_ind(&xs, &inds, 0));
+
+        if (n % 2 == 1) {
+          /* Odd number of neighbors, so the median is unique */
+          medians[0] = (long int) VECTOR(neis)[(long int)VECTOR(inds)[n / 2]];
+          medians[1] = -1;
+        } else {
+          /* Even number of neighbors, so we have two medians. The order
+           * depends on whether we are processing the layer in leftmost
+           * or rightmost fashion. */
+          if (align_right) {
+            medians[0] = (long int) VECTOR(neis)[(long int)VECTOR(inds)[n / 2]];
+            medians[1] = (long int) VECTOR(neis)[(long int)VECTOR(inds)[n / 2 - 1]];
+          } else {
+            medians[0] = (long int) VECTOR(neis)[(long int)VECTOR(inds)[n / 2 - 1]];
+            medians[1] = (long int) VECTOR(neis)[(long int)VECTOR(inds)[n / 2]];
+          }
+        }
+      }
+
+      /* Try aligning with the medians */
+      for (k = 0; k < 2; k++) {
+        igraph_integer_t eid;
+        if (medians[k] < 0)
+          continue;
+        if (VECTOR(*align)[vertex] != vertex) {
+          /* Vertex already aligned, continue */
+          continue;
+        }
+        /* Is the edge between medians[k] and vertex ignored
+         * because of a type 1 conflict? */
+        IGRAPH_CHECK(igraph_get_eid(graph, &eid, (igraph_integer_t) vertex,
+				    (igraph_integer_t) medians[k], 0, 1));
+        if (VECTOR(*ignored_edges)[(long int)eid])
+          continue;
+        /* Okay, align with the median if possible */
+        pos = (long int) X_POS(medians[k]);
+        if ((align_right && r > pos) || (!align_right && r < pos)) {
+          VECTOR(*align)[medians[k]] = vertex;
+          VECTOR(*roots)[vertex] = VECTOR(*roots)[medians[k]];
+          VECTOR(*align)[vertex] = VECTOR(*roots)[medians[k]];
+          r = pos;
+        }
+      }
+    }
+  }
+
+  igraph_vector_destroy(&inds);
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&xs);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return IGRAPH_SUCCESS;
+}
+
+/*
+ * Runs a horizontal compaction given a vertical alignment (in `align`)
+ * and the roots (in `roots`). These come out directly from
+ * igraph_i_layout_sugiyama_vertical_alignment.
+ *
+ * Returns the X coordinates for each vertex in `xs`.
+ *
+ * `graph` is the input graph, `layering` is the layering on which we operate.
+ * `hgap` is the preferred horizontal gap between vertices.
+ */
+static int igraph_i_layout_sugiyama_horizontal_compaction(const igraph_t* graph,
+    const igraph_vector_t* vertex_to_the_left,
+    const igraph_vector_t* roots, const igraph_vector_t* align,
+    igraph_real_t hgap, igraph_vector_t* xs) {
+  long int i;
+  long int no_of_nodes = igraph_vcount(graph);
+  igraph_vector_t sinks, shifts, old_xs;
+  igraph_real_t shift;
+
+  /* Initialization */
+
+  IGRAPH_VECTOR_INIT_FINALLY(&sinks, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&shifts, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&old_xs, no_of_nodes);
+
+  IGRAPH_CHECK(igraph_vector_resize(xs, no_of_nodes));
+
+  for (i = 0; i < no_of_nodes; i++) {
+    VECTOR(sinks)[i] = i;
+  }
+  igraph_vector_fill(&shifts, IGRAPH_INFINITY);
+  igraph_vector_fill(xs, -1);
+
+  /* Calculate the coordinates of the vertices relative to their sinks
+   * in their own class. At the end of this for loop, xs will contain the
+   * relative displacement of a vertex from its sink, while the shifts list
+   * will contain the absolute displacement of the sinks.
+   * (For the sinks only, of course, the rest is undefined and unused)
+   */
+  for (i = 0; i < no_of_nodes; i++) {
+    if (VECTOR(*roots)[i] == i) {
+      IGRAPH_CHECK(
+          igraph_i_layout_sugiyama_horizontal_compaction_place_block(i,
+          vertex_to_the_left, roots, align, &sinks, &shifts, hgap, xs)
+      );
+    }
+  }
+
+  /* In "sinks", only those indices `i` matter for which `i` is in `roots`.
+   * All the other values will never be touched.
+   */
+
+  /* Calculate the absolute coordinates */
+  IGRAPH_CHECK(igraph_vector_update(&old_xs, xs));
+  for (i = 0; i < no_of_nodes; i++) {
+    long int root = (long int) VECTOR(*roots)[i];
+    VECTOR(*xs)[i] = VECTOR(old_xs)[root];
+    shift = VECTOR(shifts)[(long int)VECTOR(sinks)[root]];
+    if (shift < IGRAPH_INFINITY)
+      VECTOR(*xs)[i] += shift;
+  }
+
+  igraph_vector_destroy(&sinks);
+  igraph_vector_destroy(&shifts);
+  igraph_vector_destroy(&old_xs);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return IGRAPH_SUCCESS;
+}
+
+static int igraph_i_layout_sugiyama_horizontal_compaction_place_block(long int v,
+    const igraph_vector_t* vertex_to_the_left,
+    const igraph_vector_t* roots, const igraph_vector_t* align,
+    igraph_vector_t* sinks, igraph_vector_t* shifts,
+    igraph_real_t hgap, igraph_vector_t* xs) {
+  long int u, w;
+  long int u_sink, v_sink;
+
+  if (VECTOR(*xs)[v] >= 0)
+    return IGRAPH_SUCCESS;
+
+  VECTOR(*xs)[v] = 0;
+
+  w = v;
+  do {
+    /* Check whether vertex w is the leftmost in its own layer */
+    u = (long int) VECTOR(*vertex_to_the_left)[w];
+    if (u != w) {
+      /* Get the root of u (proceeding all the way upwards in the block) */
+      u = (long int) VECTOR(*roots)[u];
+      /* Place the block of u recursively */
+      IGRAPH_CHECK(
+          igraph_i_layout_sugiyama_horizontal_compaction_place_block(u,
+            vertex_to_the_left, roots, align, sinks, shifts, hgap, xs)
+      );
+
+      u_sink = (long int) VECTOR(*sinks)[u];
+      v_sink = (long int) VECTOR(*sinks)[v];
+      /* If v is its own sink yet, set its sink to the sink of u */
+      if (v_sink == v) {
+        VECTOR(*sinks)[v] = v_sink = u_sink;
+      }
+      /* If v and u have different sinks (i.e. they are in different classes),
+       * shift the sink of u so that the two blocks are separated by the
+       * preferred gap
+       */
+      if (v_sink != u_sink) {
+        if (VECTOR(*shifts)[u_sink] > VECTOR(*xs)[v] - VECTOR(*xs)[u] - hgap) {
+          VECTOR(*shifts)[u_sink] = VECTOR(*xs)[v] - VECTOR(*xs)[u] - hgap;
+        }
+      } else {
+        /* v and u have the same sink, i.e. they are in the same class. Make sure
+         * that v is separated from u by at least hgap.
+         */
+        if (VECTOR(*xs)[v] < VECTOR(*xs)[u] + hgap)
+          VECTOR(*xs)[v] = VECTOR(*xs)[u] + hgap;
+      }
+    }
+
+    /* Follow the alignment */
+    w = (long int) VECTOR(*align)[w];
+  } while (w != v);
+
+  return IGRAPH_SUCCESS;
+}
+
+#undef IS_INNER_SEGMENT
+#undef IS_DUMMY
+#undef X_POS
+
+#ifdef SUGIYAMA_DEBUG
+#undef SUGIYAMA_DEBUG
+#endif
+
+
diff --git a/src/topology.c b/src/topology.c
new file mode 100644
index 0000000..e384a50
--- /dev/null
+++ b/src/topology.c
@@ -0,0 +1,2955 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+   (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_topology.h"
+#include "igraph_memory.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_constructors.h"
+#include "igraph_conversion.h"
+#include "igraph_stack.h"
+#include "igraph_attributes.h"
+#include "config.h"
+
+const unsigned int igraph_i_isoclass_3[] = {  0, 1, 1, 3, 1, 5, 6, 7,
+					      1, 6,10,11, 3, 7,11,15,
+					      1, 6, 5, 7,10,21,21,23,
+					      6,25,21,27,11,27,30,31,
+					      1,10, 6,11, 6,21,25,27,
+					      5,21,21,30, 7,23,27,31,
+					      3,11, 7,15,11,30,27,31,
+					      7,27,23,31,15,31,31,63 };
+
+const unsigned int igraph_i_isoclass_3_idx[] = { 0, 4, 16, 1, 0, 32, 2, 8, 0 };
+
+const unsigned int igraph_i_isoclass_4[] = { 
+     0,   1,   1,   3,   1,   3,   3,   7,   1,   9,  10,  11,  10,
+    11,  14,  15,   1,  10,  18,  19,  20,  21,  22,  23,   3,  11,
+    19,  27,  21,  29,  30,  31,   1,  10,  20,  21,  18,  19,  22,
+    23,   3,  11,  21,  29,  19,  27,  30,  31,   3,  14,  22,  30,
+    22,  30,  54,  55,   7,  15,  23,  31,  23,  31,  55,  63,   1,
+    10,   9,  11,  10,  14,  11,  15,  18,  73,  73,  75,  76,  77,
+    77,  79,  10,  81,  73,  83,  84,  85,  86,  87,  19,  83,  90,
+    91,  92,  93,  94,  95,  20,  84,  98,  99, 100, 101, 102, 103,
+    22,  86, 106, 107, 108, 109, 110, 111,  21,  85, 106, 115, 116,
+   117, 118, 119,  23,  87, 122, 123, 124, 125, 126, 127,   1,  18,
+    10,  19,  20,  22,  21,  23,  10,  73,  81,  83,  84,  86,  85,
+    87,   9,  73,  73,  90,  98, 106, 106, 122,  11,  75,  83,  91,
+    99, 107, 115, 123,  10,  76,  84,  92, 100, 108, 116, 124,  14,
+    77,  85,  93, 101, 109, 117, 125,  11,  77,  86,  94, 102, 110,
+   118, 126,  15,  79,  87,  95, 103, 111, 119, 127,   3,  19,  11,
+    27,  21,  30,  29,  31,  19,  90,  83,  91,  92,  94,  93,  95,
+    11,  83,  75,  91,  99, 115, 107, 123,  27,  91,  91, 219, 220,
+   221, 221, 223,  21,  92,  99, 220, 228, 229, 230, 231,  30,  94,
+   115, 221, 229, 237, 238, 239,  29,  93, 107, 221, 230, 238, 246,
+   247,  31,  95, 123, 223, 231, 239, 247, 255,   1,  20,  10,  21,
+    18,  22,  19,  23,  20,  98,  84,  99, 100, 102, 101, 103,  10,
+    84,  76,  92, 100, 116, 108, 124,  21,  99,  92, 220, 228, 230,
+   229, 231,  18, 100, 100, 228, 292, 293, 293, 295,  22, 102, 116,
+   230, 293, 301, 302, 303,  19, 101, 108, 229, 293, 302, 310, 311,
+    23, 103, 124, 231, 295, 303, 311, 319,   3,  21,  11,  29,  19,
+    30,  27,  31,  22, 106,  86, 107, 108, 110, 109, 111,  14,  85,
+    77,  93, 101, 117, 109, 125,  30, 115,  94, 221, 229, 238, 237,
+   239,  22, 116, 102, 230, 293, 302, 301, 303,  54, 118, 118, 246,
+   310, 365, 365, 367,  30, 117, 110, 238, 302, 373, 365, 375,  55,
+   119, 126, 247, 311, 375, 382, 383,   3,  22,  14,  30,  22,  54,
+    30,  55,  21, 106,  85, 115, 116, 118, 117, 119,  11,  86,  77,
+    94, 102, 118, 110, 126,  29, 107,  93, 221, 230, 246, 238, 247,
+    19, 108, 101, 229, 293, 310, 302, 311,  30, 110, 117, 238, 302,
+   365, 373, 375,  27, 109, 109, 237, 301, 365, 365, 382,  31, 111,
+   125, 239, 303, 367, 375, 383,   7,  23,  15,  31,  23,  55,  31,
+    63,  23, 122,  87, 123, 124, 126, 125, 127,  15,  87,  79,  95,
+   103, 119, 111, 127,  31, 123,  95, 223, 231, 247, 239, 255,  23,
+   124, 103, 231, 295, 311, 303, 319,  55, 126, 119, 247, 311, 382,
+   375, 383,  31, 125, 111, 239, 303, 375, 367, 383,  63, 127, 127,
+   255, 319, 383, 383, 511,   1,  10,  10,  14,   9,  11,  11,  15,
+    18,  73,  76,  77,  73,  75,  77,  79,  20,  84, 100, 101,  98,
+    99, 102, 103,  22,  86, 108, 109, 106, 107, 110, 111,  10,  81,
+    84,  85,  73,  83,  86,  87,  19,  83,  92,  93,  90,  91,  94,
+    95,  21,  85, 116, 117, 106, 115, 118, 119,  23,  87, 124, 125,
+   122, 123, 126, 127,  18,  76,  73,  77,  73,  77,  75,  79, 292,
+   585, 585, 587, 585, 587, 587, 591, 100, 593, 594, 595, 596, 597,
+   598, 599, 293, 601, 602, 603, 604, 605, 606, 607, 100, 593, 596,
+   597, 594, 595, 598, 599, 293, 601, 604, 605, 602, 603, 606, 607,
+   228, 625, 626, 627, 626, 627, 630, 631, 295, 633, 634, 635, 634,
+   635, 638, 639,  20, 100,  84, 101,  98, 102,  99, 103, 100, 594,
+   593, 595, 596, 598, 597, 599,  98, 596, 596, 659, 660, 661, 661,
+   663, 102, 598, 666, 667, 661, 669, 670, 671,  84, 593, 674, 675,
+   596, 666, 678, 679, 101, 595, 675, 683, 659, 667, 686, 687,  99,
+   597, 678, 686, 661, 670, 694, 695, 103, 599, 679, 687, 663, 671,
+   695, 703,  22, 108,  86, 109, 106, 110, 107, 111, 293, 602, 601,
+   603, 604, 606, 605, 607, 102, 666, 598, 667, 661, 670, 669, 671,
+   301, 729, 729, 731, 732, 733, 733, 735, 116, 737, 678, 739, 626,
+   741, 742, 743, 302, 745, 746, 747, 748, 749, 750, 751, 230, 753,
+   742, 755, 756, 757, 758, 759, 303, 761, 762, 763, 764, 765, 766,
+   767,  10,  84,  81,  85,  73,  86,  83,  87, 100, 596, 593, 597,
+   594, 598, 595, 599,  84, 674, 593, 675, 596, 678, 666, 679, 116,
+   678, 737, 739, 626, 742, 741, 743,  76, 593, 593, 625, 585, 601,
+   601, 633, 108, 666, 737, 753, 602, 729, 745, 761,  92, 675, 737,
+   819, 604, 746, 822, 823, 124, 679, 826, 827, 634, 762, 830, 831,
+    19,  92,  83,  93,  90,  94,  91,  95, 293, 604, 601, 605, 602,
+   606, 603, 607, 101, 675, 595, 683, 659, 686, 667, 687, 302, 746,
+   745, 747, 748, 750, 749, 751, 108, 737, 666, 753, 602, 745, 729,
+   761, 310, 822, 822, 875, 876, 877, 877, 879, 229, 819, 741, 883,
+   748, 885, 886, 887, 311, 823, 830, 891, 892, 893, 894, 895,  21,
+   116,  85, 117, 106, 118, 115, 119, 228, 626, 625, 627, 626, 630,
+   627, 631,  99, 678, 597, 686, 661, 694, 670, 695, 230, 742, 753,
+   755, 756, 758, 757, 759,  92, 737, 675, 819, 604, 822, 746, 823,
+   229, 741, 819, 883, 748, 886, 885, 887, 220, 739, 739, 947, 732,
+   949, 949, 951, 231, 743, 827, 955, 764, 957, 958, 959,  23, 124,
+    87, 125, 122, 126, 123, 127, 295, 634, 633, 635, 634, 638, 635,
+   639, 103, 679, 599, 687, 663, 695, 671, 703, 303, 762, 761, 763,
+   764, 766, 765, 767, 124, 826, 679, 827, 634, 830, 762, 831, 311,
+   830, 823, 891, 892, 894, 893, 895, 231, 827, 743, 955, 764, 958,
+   957, 959, 319, 831, 831,1019,1020,1021,1021,1023,   1,  18,  20,
+    22,  10,  19,  21,  23,  10,  73,  84,  86,  81,  83,  85,  87,
+    10,  76, 100, 108,  84,  92, 116, 124,  14,  77, 101, 109,  85,
+    93, 117, 125,   9,  73,  98, 106,  73,  90, 106, 122,  11,  75,
+    99, 107,  83,  91, 115, 123,  11,  77, 102, 110,  86,  94, 118,
+   126,  15,  79, 103, 111,  87,  95, 119, 127,  20, 100,  98, 102,
+    84, 101,  99, 103, 100, 594, 596, 598, 593, 595, 597, 599,  84,
+   593, 596, 666, 674, 675, 678, 679, 101, 595, 659, 667, 675, 683,
+   686, 687,  98, 596, 660, 661, 596, 659, 661, 663, 102, 598, 661,
+   669, 666, 667, 670, 671,  99, 597, 661, 670, 678, 686, 694, 695,
+   103, 599, 663, 671, 679, 687, 695, 703,  18, 292, 100, 293, 100,
+   293, 228, 295,  76, 585, 593, 601, 593, 601, 625, 633,  73, 585,
+   594, 602, 596, 604, 626, 634,  77, 587, 595, 603, 597, 605, 627,
+   635,  73, 585, 596, 604, 594, 602, 626, 634,  77, 587, 597, 605,
+   595, 603, 627, 635,  75, 587, 598, 606, 598, 606, 630, 638,  79,
+   591, 599, 607, 599, 607, 631, 639,  22, 293, 102, 301, 116, 302,
+   230, 303, 108, 602, 666, 729, 737, 745, 753, 761,  86, 601, 598,
+   729, 678, 746, 742, 762, 109, 603, 667, 731, 739, 747, 755, 763,
+   106, 604, 661, 732, 626, 748, 756, 764, 110, 606, 670, 733, 741,
+   749, 757, 765, 107, 605, 669, 733, 742, 750, 758, 766, 111, 607,
+   671, 735, 743, 751, 759, 767,  10, 100,  84, 116,  76, 108,  92,
+   124,  84, 596, 674, 678, 593, 666, 675, 679,  81, 593, 593, 737,
+   593, 737, 737, 826,  85, 597, 675, 739, 625, 753, 819, 827,  73,
+   594, 596, 626, 585, 602, 604, 634,  86, 598, 678, 742, 601, 729,
+   746, 762,  83, 595, 666, 741, 601, 745, 822, 830,  87, 599, 679,
+   743, 633, 761, 823, 831,  21, 228,  99, 230,  92, 229, 220, 231,
+   116, 626, 678, 742, 737, 741, 739, 743,  85, 625, 597, 753, 675,
+   819, 739, 827, 117, 627, 686, 755, 819, 883, 947, 955, 106, 626,
+   661, 756, 604, 748, 732, 764, 118, 630, 694, 758, 822, 886, 949,
+   957, 115, 627, 670, 757, 746, 885, 949, 958, 119, 631, 695, 759,
+   823, 887, 951, 959,  19, 293, 101, 302, 108, 310, 229, 311,  92,
+   604, 675, 746, 737, 822, 819, 823,  83, 601, 595, 745, 666, 822,
+   741, 830,  93, 605, 683, 747, 753, 875, 883, 891,  90, 602, 659,
+   748, 602, 876, 748, 892,  94, 606, 686, 750, 745, 877, 885, 893,
+    91, 603, 667, 749, 729, 877, 886, 894,  95, 607, 687, 751, 761,
+   879, 887, 895,  23, 295, 103, 303, 124, 311, 231, 319, 124, 634,
+   679, 762, 826, 830, 827, 831,  87, 633, 599, 761, 679, 823, 743,
+   831, 125, 635, 687, 763, 827, 891, 955,1019, 122, 634, 663, 764,
+   634, 892, 764,1020, 126, 638, 695, 766, 830, 894, 958,1021, 123,
+   635, 671, 765, 762, 893, 957,1021, 127, 639, 703, 767, 831, 895,
+   959,1023,   3,  19,  21,  30,  11,  27,  29,  31,  19,  90,  92,
+    94,  83,  91,  93,  95,  21,  92, 228, 229,  99, 220, 230, 231,
+    30,  94, 229, 237, 115, 221, 238, 239,  11,  83,  99, 115,  75,
+    91, 107, 123,  27,  91, 220, 221,  91, 219, 221, 223,  29,  93,
+   230, 238, 107, 221, 246, 247,  31,  95, 231, 239, 123, 223, 247,
+   255,  22, 108, 106, 110,  86, 109, 107, 111, 293, 602, 604, 606,
+   601, 603, 605, 607, 116, 737, 626, 741, 678, 739, 742, 743, 302,
+   745, 748, 749, 746, 747, 750, 751, 102, 666, 661, 670, 598, 667,
+   669, 671, 301, 729, 732, 733, 729, 731, 733, 735, 230, 753, 756,
+   757, 742, 755, 758, 759, 303, 761, 764, 765, 762, 763, 766, 767,
+    22, 293, 116, 302, 102, 301, 230, 303, 108, 602, 737, 745, 666,
+   729, 753, 761, 106, 604, 626, 748, 661, 732, 756, 764, 110, 606,
+   741, 749, 670, 733, 757, 765,  86, 601, 678, 746, 598, 729, 742,
+   762, 109, 603, 739, 747, 667, 731, 755, 763, 107, 605, 742, 750,
+   669, 733, 758, 766, 111, 607, 743, 751, 671, 735, 759, 767,  54,
+   310, 118, 365, 118, 365, 246, 367, 310, 876, 822, 877, 822, 877,
+   875, 879, 118, 822, 630, 886, 694, 949, 758, 957, 365, 877, 886,
+  1755, 949,1757,1758,1759, 118, 822, 694, 949, 630, 886, 758, 957,
+   365, 877, 949,1757, 886,1755,1758,1759, 246, 875, 758,1758, 758,
+  1758,1782,1783, 367, 879, 957,1759, 957,1759,1783,1791,  14, 101,
+    85, 117,  77, 109,  93, 125, 101, 659, 675, 686, 595, 667, 683,
+   687,  85, 675, 625, 819, 597, 739, 753, 827, 117, 686, 819, 947,
+   627, 755, 883, 955,  77, 595, 597, 627, 587, 603, 605, 635, 109,
+   667, 739, 755, 603, 731, 747, 763,  93, 683, 753, 883, 605, 747,
+   875, 891, 125, 687, 827, 955, 635, 763, 891,1019,  30, 229, 115,
+   238,  94, 237, 221, 239, 302, 748, 746, 750, 745, 749, 747, 751,
+   117, 819, 627, 883, 686, 947, 755, 955, 373, 885, 885,1883, 885,
+  1883,1883,1887, 110, 741, 670, 757, 606, 749, 733, 765, 365, 886,
+   949,1758, 877,1755,1757,1759, 238, 883, 757,1907, 750,1883,1758,
+  1911, 375, 887, 958,1911, 893,1917,1918,1919,  30, 302, 117, 373,
+   110, 365, 238, 375, 229, 748, 819, 885, 741, 886, 883, 887, 115,
+   746, 627, 885, 670, 949, 757, 958, 238, 750, 883,1883, 757,1758,
+  1907,1911,  94, 745, 686, 885, 606, 877, 750, 893, 237, 749, 947,
+  1883, 749,1755,1883,1917, 221, 747, 755,1883, 733,1757,1758,1918,
+   239, 751, 955,1887, 765,1759,1911,1919,  55, 311, 119, 375, 126,
+   382, 247, 383, 311, 892, 823, 893, 830, 894, 891, 895, 119, 823,
+   631, 887, 695, 951, 759, 959, 375, 893, 887,1917, 958,1918,1911,
+  1919, 126, 830, 695, 958, 638, 894, 766,1021, 382, 894, 951,1918,
+   894,2029,1918,2031, 247, 891, 759,1911, 766,1918,1783,2039, 383,
+   895, 959,1919,1021,2031,2039,2047,   1,  20,  18,  22,  10,  21,
+    19,  23,  20,  98, 100, 102,  84,  99, 101, 103,  18, 100, 292,
+   293, 100, 228, 293, 295,  22, 102, 293, 301, 116, 230, 302, 303,
+    10,  84, 100, 116,  76,  92, 108, 124,  21,  99, 228, 230,  92,
+   220, 229, 231,  19, 101, 293, 302, 108, 229, 310, 311,  23, 103,
+   295, 303, 124, 231, 311, 319,  10,  84,  73,  86,  81,  85,  83,
+    87, 100, 596, 594, 598, 593, 597, 595, 599,  76, 593, 585, 601,
+   593, 625, 601, 633, 108, 666, 602, 729, 737, 753, 745, 761,  84,
+   674, 596, 678, 593, 675, 666, 679, 116, 678, 626, 742, 737, 739,
+   741, 743,  92, 675, 604, 746, 737, 819, 822, 823, 124, 679, 634,
+   762, 826, 827, 830, 831,  10, 100,  76, 108,  84, 116,  92, 124,
+    84, 596, 593, 666, 674, 678, 675, 679,  73, 594, 585, 602, 596,
+   626, 604, 634,  86, 598, 601, 729, 678, 742, 746, 762,  81, 593,
+   593, 737, 593, 737, 737, 826,  85, 597, 625, 753, 675, 739, 819,
+   827,  83, 595, 601, 745, 666, 741, 822, 830,  87, 599, 633, 761,
+   679, 743, 823, 831,  14, 101,  77, 109,  85, 117,  93, 125, 101,
+   659, 595, 667, 675, 686, 683, 687,  77, 595, 587, 603, 597, 627,
+   605, 635, 109, 667, 603, 731, 739, 755, 747, 763,  85, 675, 597,
+   739, 625, 819, 753, 827, 117, 686, 627, 755, 819, 947, 883, 955,
+    93, 683, 605, 747, 753, 883, 875, 891, 125, 687, 635, 763, 827,
+   955, 891,1019,   9,  98,  73, 106,  73, 106,  90, 122,  98, 660,
+   596, 661, 596, 661, 659, 663,  73, 596, 585, 604, 594, 626, 602,
+   634, 106, 661, 604, 732, 626, 756, 748, 764,  73, 596, 594, 626,
+   585, 604, 602, 634, 106, 661, 626, 756, 604, 732, 748, 764,  90,
+   659, 602, 748, 602, 748, 876, 892, 122, 663, 634, 764, 634, 764,
+   892,1020,  11,  99,  75, 107,  83, 115,  91, 123, 102, 661, 598,
+   669, 666, 670, 667, 671,  77, 597, 587, 605, 595, 627, 603, 635,
+   110, 670, 606, 733, 741, 757, 749, 765,  86, 678, 598, 742, 601,
+   746, 729, 762, 118, 694, 630, 758, 822, 949, 886, 957,  94, 686,
+   606, 750, 745, 885, 877, 893, 126, 695, 638, 766, 830, 958, 894,
+  1021,  11, 102,  77, 110,  86, 118,  94, 126,  99, 661, 597, 670,
+   678, 694, 686, 695,  75, 598, 587, 606, 598, 630, 606, 638, 107,
+   669, 605, 733, 742, 758, 750, 766,  83, 666, 595, 741, 601, 822,
+   745, 830, 115, 670, 627, 757, 746, 949, 885, 958,  91, 667, 603,
+   749, 729, 886, 877, 894, 123, 671, 635, 765, 762, 957, 893,1021,
+    15, 103,  79, 111,  87, 119,  95, 127, 103, 663, 599, 671, 679,
+   695, 687, 703,  79, 599, 591, 607, 599, 631, 607, 639, 111, 671,
+   607, 735, 743, 759, 751, 767,  87, 679, 599, 743, 633, 823, 761,
+   831, 119, 695, 631, 759, 823, 951, 887, 959,  95, 687, 607, 751,
+   761, 887, 879, 895, 127, 703, 639, 767, 831, 959, 895,1023,   3,
+    21,  19,  30,  11,  29,  27,  31,  22, 106, 108, 110,  86, 107,
+   109, 111,  22, 116, 293, 302, 102, 230, 301, 303,  54, 118, 310,
+   365, 118, 246, 365, 367,  14,  85, 101, 117,  77,  93, 109, 125,
+    30, 115, 229, 238,  94, 221, 237, 239,  30, 117, 302, 373, 110,
+   238, 365, 375,  55, 119, 311, 375, 126, 247, 382, 383,  19,  92,
+    90,  94,  83,  93,  91,  95, 293, 604, 602, 606, 601, 605, 603,
+   607, 108, 737, 602, 745, 666, 753, 729, 761, 310, 822, 876, 877,
+   822, 875, 877, 879, 101, 675, 659, 686, 595, 683, 667, 687, 302,
+   746, 748, 750, 745, 747, 749, 751, 229, 819, 748, 885, 741, 883,
+   886, 887, 311, 823, 892, 893, 830, 891, 894, 895,  21, 228,  92,
+   229,  99, 230, 220, 231, 116, 626, 737, 741, 678, 742, 739, 743,
+   106, 626, 604, 748, 661, 756, 732, 764, 118, 630, 822, 886, 694,
+   758, 949, 957,  85, 625, 675, 819, 597, 753, 739, 827, 117, 627,
+   819, 883, 686, 755, 947, 955, 115, 627, 746, 885, 670, 757, 949,
+   958, 119, 631, 823, 887, 695, 759, 951, 959,  30, 229,  94, 237,
+   115, 238, 221, 239, 302, 748, 745, 749, 746, 750, 747, 751, 110,
+   741, 606, 749, 670, 757, 733, 765, 365, 886, 877,1755, 949,1758,
+  1757,1759, 117, 819, 686, 947, 627, 883, 755, 955, 373, 885, 885,
+  1883, 885,1883,1883,1887, 238, 883, 750,1883, 757,1907,1758,1911,
+   375, 887, 893,1917, 958,1911,1918,1919,  11,  99,  83, 115,  75,
+   107,  91, 123, 102, 661, 666, 670, 598, 669, 667, 671,  86, 678,
+   601, 746, 598, 742, 729, 762, 118, 694, 822, 949, 630, 758, 886,
+   957,  77, 597, 595, 627, 587, 605, 603, 635, 110, 670, 741, 757,
+   606, 733, 749, 765,  94, 686, 745, 885, 606, 750, 877, 893, 126,
+   695, 830, 958, 638, 766, 894,1021,  27, 220,  91, 221,  91, 221,
+   219, 223, 301, 732, 729, 733, 729, 733, 731, 735, 109, 739, 603,
+   747, 667, 755, 731, 763, 365, 949, 877,1757, 886,1758,1755,1759,
+   109, 739, 667, 755, 603, 747, 731, 763, 365, 949, 886,1758, 877,
+  1757,1755,1759, 237, 947, 749,1883, 749,1883,1755,1917, 382, 951,
+   894,1918, 894,1918,2029,2031,  29, 230,  93, 238, 107, 246, 221,
+   247, 230, 756, 753, 757, 742, 758, 755, 759, 107, 742, 605, 750,
+   669, 758, 733, 766, 246, 758, 875,1758, 758,1782,1758,1783,  93,
+   753, 683, 883, 605, 875, 747, 891, 238, 757, 883,1907, 750,1758,
+  1883,1911, 221, 755, 747,1883, 733,1758,1757,1918, 247, 759, 891,
+  1911, 766,1783,1918,2039,  31, 231,  95, 239, 123, 247, 223, 255,
+   303, 764, 761, 765, 762, 766, 763, 767, 111, 743, 607, 751, 671,
+   759, 735, 767, 367, 957, 879,1759, 957,1783,1759,1791, 125, 827,
+   687, 955, 635, 891, 763,1019, 375, 958, 887,1911, 893,1918,1917,
+  1919, 239, 955, 751,1887, 765,1911,1759,1919, 383, 959, 895,1919,
+  1021,2039,2031,2047,   3,  22,  22,  54,  14,  30,  30,  55,  21,
+   106, 116, 118,  85, 115, 117, 119,  19, 108, 293, 310, 101, 229,
+   302, 311,  30, 110, 302, 365, 117, 238, 373, 375,  11,  86, 102,
+   118,  77,  94, 110, 126,  29, 107, 230, 246,  93, 221, 238, 247,
+    27, 109, 301, 365, 109, 237, 365, 382,  31, 111, 303, 367, 125,
+   239, 375, 383,  21, 116, 106, 118,  85, 117, 115, 119, 228, 626,
+   626, 630, 625, 627, 627, 631,  92, 737, 604, 822, 675, 819, 746,
+   823, 229, 741, 748, 886, 819, 883, 885, 887,  99, 678, 661, 694,
+   597, 686, 670, 695, 230, 742, 756, 758, 753, 755, 757, 759, 220,
+   739, 732, 949, 739, 947, 949, 951, 231, 743, 764, 957, 827, 955,
+   958, 959,  19, 293, 108, 310, 101, 302, 229, 311,  92, 604, 737,
+   822, 675, 746, 819, 823,  90, 602, 602, 876, 659, 748, 748, 892,
+    94, 606, 745, 877, 686, 750, 885, 893,  83, 601, 666, 822, 595,
+   745, 741, 830,  93, 605, 753, 875, 683, 747, 883, 891,  91, 603,
+   729, 877, 667, 749, 886, 894,  95, 607, 761, 879, 687, 751, 887,
+   895,  30, 302, 110, 365, 117, 373, 238, 375, 229, 748, 741, 886,
+   819, 885, 883, 887,  94, 745, 606, 877, 686, 885, 750, 893, 237,
+   749, 749,1755, 947,1883,1883,1917, 115, 746, 670, 949, 627, 885,
+   757, 958, 238, 750, 757,1758, 883,1883,1907,1911, 221, 747, 733,
+  1757, 755,1883,1758,1918, 239, 751, 765,1759, 955,1887,1911,1919,
+    11, 102,  86, 118,  77, 110,  94, 126,  99, 661, 678, 694, 597,
+   670, 686, 695,  83, 666, 601, 822, 595, 741, 745, 830, 115, 670,
+   746, 949, 627, 757, 885, 958,  75, 598, 598, 630, 587, 606, 606,
+   638, 107, 669, 742, 758, 605, 733, 750, 766,  91, 667, 729, 886,
+   603, 749, 877, 894, 123, 671, 762, 957, 635, 765, 893,1021,  29,
+   230, 107, 246,  93, 238, 221, 247, 230, 756, 742, 758, 753, 757,
+   755, 759,  93, 753, 605, 875, 683, 883, 747, 891, 238, 757, 750,
+  1758, 883,1907,1883,1911, 107, 742, 669, 758, 605, 750, 733, 766,
+   246, 758, 758,1782, 875,1758,1758,1783, 221, 755, 733,1758, 747,
+  1883,1757,1918, 247, 759, 766,1783, 891,1911,1918,2039,  27, 301,
+   109, 365, 109, 365, 237, 382, 220, 732, 739, 949, 739, 949, 947,
+   951,  91, 729, 603, 877, 667, 886, 749, 894, 221, 733, 747,1757,
+   755,1758,1883,1918,  91, 729, 667, 886, 603, 877, 749, 894, 221,
+   733, 755,1758, 747,1757,1883,1918, 219, 731, 731,1755, 731,1755,
+  1755,2029, 223, 735, 763,1759, 763,1759,1917,2031,  31, 303, 111,
+   367, 125, 375, 239, 383, 231, 764, 743, 957, 827, 958, 955, 959,
+    95, 761, 607, 879, 687, 887, 751, 895, 239, 765, 751,1759, 955,
+  1911,1887,1919, 123, 762, 671, 957, 635, 893, 765,1021, 247, 766,
+   759,1783, 891,1918,1911,2039, 223, 763, 735,1759, 763,1917,1759,
+  2031, 255, 767, 767,1791,1019,1919,1919,2047,   7,  23,  23,  55,
+    15,  31,  31,  63,  23, 122, 124, 126,  87, 123, 125, 127,  23,
+   124, 295, 311, 103, 231, 303, 319,  55, 126, 311, 382, 119, 247,
+   375, 383,  15,  87, 103, 119,  79,  95, 111, 127,  31, 123, 231,
+   247,  95, 223, 239, 255,  31, 125, 303, 375, 111, 239, 367, 383,
+    63, 127, 319, 383, 127, 255, 383, 511,  23, 124, 122, 126,  87,
+   125, 123, 127, 295, 634, 634, 638, 633, 635, 635, 639, 124, 826,
+   634, 830, 679, 827, 762, 831, 311, 830, 892, 894, 823, 891, 893,
+   895, 103, 679, 663, 695, 599, 687, 671, 703, 303, 762, 764, 766,
+   761, 763, 765, 767, 231, 827, 764, 958, 743, 955, 957, 959, 319,
+   831,1020,1021, 831,1019,1021,1023,  23, 295, 124, 311, 103, 303,
+   231, 319, 124, 634, 826, 830, 679, 762, 827, 831, 122, 634, 634,
+   892, 663, 764, 764,1020, 126, 638, 830, 894, 695, 766, 958,1021,
+    87, 633, 679, 823, 599, 761, 743, 831, 125, 635, 827, 891, 687,
+   763, 955,1019, 123, 635, 762, 893, 671, 765, 957,1021, 127, 639,
+   831, 895, 703, 767, 959,1023,  55, 311, 126, 382, 119, 375, 247,
+   383, 311, 892, 830, 894, 823, 893, 891, 895, 126, 830, 638, 894,
+   695, 958, 766,1021, 382, 894, 894,2029, 951,1918,1918,2031, 119,
+   823, 695, 951, 631, 887, 759, 959, 375, 893, 958,1918, 887,1917,
+  1911,1919, 247, 891, 766,1918, 759,1911,1783,2039, 383, 895,1021,
+  2031, 959,1919,2039,2047,  15, 103,  87, 119,  79, 111,  95, 127,
+   103, 663, 679, 695, 599, 671, 687, 703,  87, 679, 633, 823, 599,
+   743, 761, 831, 119, 695, 823, 951, 631, 759, 887, 959,  79, 599,
+   599, 631, 591, 607, 607, 639, 111, 671, 743, 759, 607, 735, 751,
+   767,  95, 687, 761, 887, 607, 751, 879, 895, 127, 703, 831, 959,
+   639, 767, 895,1023,  31, 231, 123, 247,  95, 239, 223, 255, 303,
+   764, 762, 766, 761, 765, 763, 767, 125, 827, 635, 891, 687, 955,
+   763,1019, 375, 958, 893,1918, 887,1911,1917,1919, 111, 743, 671,
+   759, 607, 751, 735, 767, 367, 957, 957,1783, 879,1759,1759,1791,
+   239, 955, 765,1911, 751,1887,1759,1919, 383, 959,1021,2039, 895,
+  1919,2031,2047,  31, 303, 125, 375, 111, 367, 239, 383, 231, 764,
+   827, 958, 743, 957, 955, 959, 123, 762, 635, 893, 671, 957, 765,
+  1021, 247, 766, 891,1918, 759,1783,1911,2039,  95, 761, 687, 887,
+   607, 879, 751, 895, 239, 765, 955,1911, 751,1759,1887,1919, 223,
+   763, 763,1917, 735,1759,1759,2031, 255, 767,1019,1919, 767,1791,
+  1919,2047,  63, 319, 127, 383, 127, 383, 255, 511, 319,1020, 831,
+  1021, 831,1021,1019,1023, 127, 831, 639, 895, 703, 959, 767,1023,
+   383,1021, 895,2031, 959,2039,1919,2047, 127, 831, 703, 959, 639,
+   895, 767,1023, 383,1021, 959,2039, 895,2031,1919,2047, 255,1019,
+   767,1919, 767,1919,1791,2047, 511,1023,1023,2047,1023,2047,2047,
+  4095 };
+
+const unsigned int igraph_i_isoclass_4_idx[] = {
+  0, 8, 64, 512, 1, 0, 128, 1024, 2, 16, 0, 2048, 4, 32, 256, 0 };
+
+const unsigned int igraph_i_isoclass_3u[] = { 0,1,1,3,1,3,3,7 };
+
+const unsigned int igraph_i_isoclass_3u_idx[] = { 0,1,2,1,0,4,2,4,0 };
+
+const unsigned int igraph_i_isoclass_4u[] = {
+  0, 1, 1, 3, 1, 3, 3, 7, 1, 3, 3,11,12,13,13,15, 1, 3,12,13, 3,11,13,15, 3, 7,
+ 13,15,13,15,30,31, 1,12, 3,13, 3,13,11,15, 3,13, 7,15,13,30,15,31, 3,13,13,30,
+  7,15,15,31,11,15,15,31,15,31,31,63 };
+
+const unsigned int igraph_i_isoclass_4u_idx[] = {
+  0, 1, 2, 8, 1, 0, 4, 16, 2, 4, 0, 32, 8, 16, 32, 0 };
+
+const unsigned int igraph_i_isoclass2_3[] = {
+ 0, 1, 1, 2, 1, 3, 4, 5, 1, 4, 6, 7, 2, 5, 7, 8, 1, 4, 3, 5, 6, 9, 9,10, 4,11,
+ 9,12, 7,12,13,14, 1, 6, 4, 7, 4, 9,11,12, 3, 9, 9,13, 5,10,12,14, 2, 7, 5, 8,
+ 7,13,12,14, 5,12,10,14, 8,14,14,15
+};
+
+const unsigned int igraph_i_isoclass2_3u[] = {
+  0,1,1,2,1,2,2,3 
+};
+
+const unsigned int igraph_i_isoclass2_4u[] = { 
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 4, 5, 6, 6, 7, 1, 2, 5, 6, 2, 4, 6, 7, 2, 3,
+ 6, 7, 6, 7, 8, 9, 1, 5, 2, 6, 2, 6, 4, 7, 2, 6, 3, 7, 6, 8, 7, 9, 2, 6, 6, 8,
+ 3, 7, 7, 9, 4, 7, 7, 9, 7, 9, 9,10
+};
+
+const unsigned int igraph_i_isoclass2_4[] = {
+  0,  1,  1,  2,  1,  2,  2,  3,  1,  4,  5,  6,  5,  6,  7,  8,  1,  5,  9, 10,
+ 11, 12, 13, 14,  2,  6, 10, 15, 12, 16, 17, 18,  1,  5, 11, 12,  9, 10, 13, 14,
+  2,  6, 12, 16, 10, 15, 17, 18,  2,  7, 13, 17, 13, 17, 19, 20,  3,  8, 14, 18,
+ 14, 18, 20, 21,  1,  5,  4,  6,  5,  7,  6,  8,  9, 22, 22, 23, 24, 25, 25, 26,
+  5, 27, 22, 28, 29, 30, 31, 32, 10, 28, 33, 34, 35, 36, 37, 38, 11, 29, 39, 40,
+ 41, 42, 43, 44, 13, 31, 45, 46, 47, 48, 49, 50, 12, 30, 45, 51, 52, 53, 54, 55,
+ 14, 32, 56, 57, 58, 59, 60, 61,  1,  9,  5, 10, 11, 13, 12, 14,  5, 22, 27, 28,
+ 29, 31, 30, 32,  4, 22, 22, 33, 39, 45, 45, 56,  6, 23, 28, 34, 40, 46, 51, 57,
+  5, 24, 29, 35, 41, 47, 52, 58,  7, 25, 30, 36, 42, 48, 53, 59,  6, 25, 31, 37,
+ 43, 49, 54, 60,  8, 26, 32, 38, 44, 50, 55, 61,  2, 10,  6, 15, 12, 17, 16, 18,
+ 10, 33, 28, 34, 35, 37, 36, 38,  6, 28, 23, 34, 40, 51, 46, 57, 15, 34, 34, 62,
+ 63, 64, 64, 65, 12, 35, 40, 63, 66, 67, 68, 69, 17, 37, 51, 64, 67, 70, 71, 72,
+ 16, 36, 46, 64, 68, 71, 73, 74, 18, 38, 57, 65, 69, 72, 74, 75,  1, 11,  5, 12,
+  9, 13, 10, 14, 11, 39, 29, 40, 41, 43, 42, 44,  5, 29, 24, 35, 41, 52, 47, 58,
+ 12, 40, 35, 63, 66, 68, 67, 69,  9, 41, 41, 66, 76, 77, 77, 78, 13, 43, 52, 68,
+ 77, 79, 80, 81, 10, 42, 47, 67, 77, 80, 82, 83, 14, 44, 58, 69, 78, 81, 83, 84,
+  2, 12,  6, 16, 10, 17, 15, 18, 13, 45, 31, 46, 47, 49, 48, 50,  7, 30, 25, 36,
+ 42, 53, 48, 59, 17, 51, 37, 64, 67, 71, 70, 72, 13, 52, 43, 68, 77, 80, 79, 81,
+ 19, 54, 54, 73, 82, 85, 85, 86, 17, 53, 49, 71, 80, 87, 85, 88, 20, 55, 60, 74,
+ 83, 88, 89, 90,  2, 13,  7, 17, 13, 19, 17, 20, 12, 45, 30, 51, 52, 54, 53, 55,
+  6, 31, 25, 37, 43, 54, 49, 60, 16, 46, 36, 64, 68, 73, 71, 74, 10, 47, 42, 67,
+ 77, 82, 80, 83, 17, 49, 53, 71, 80, 85, 87, 88, 15, 48, 48, 70, 79, 85, 85, 89,
+ 18, 50, 59, 72, 81, 86, 88, 90,  3, 14,  8, 18, 14, 20, 18, 21, 14, 56, 32, 57,
+ 58, 60, 59, 61,  8, 32, 26, 38, 44, 55, 50, 61, 18, 57, 38, 65, 69, 74, 72, 75,
+ 14, 58, 44, 69, 78, 83, 81, 84, 20, 60, 55, 74, 83, 89, 88, 90, 18, 59, 50, 72,
+ 81, 88, 86, 90, 21, 61, 61, 75, 84, 90, 90, 91,  1,  5,  5,  7,  4,  6,  6,  8,
+  9, 22, 24, 25, 22, 23, 25, 26, 11, 29, 41, 42, 39, 40, 43, 44, 13, 31, 47, 48,
+ 45, 46, 49, 50,  5, 27, 29, 30, 22, 28, 31, 32, 10, 28, 35, 36, 33, 34, 37, 38,
+ 12, 30, 52, 53, 45, 51, 54, 55, 14, 32, 58, 59, 56, 57, 60, 61,  9, 24, 22, 25,
+ 22, 25, 23, 26, 76, 92, 92, 93, 92, 93, 93, 94, 41, 95, 96, 97, 98, 99,100,101,
+ 77,102,103,104,105,106,107,108, 41, 95, 98, 99, 96, 97,100,101, 77,102,105,106,
+103,104,107,108, 66,109,110,111,110,111,112,113, 78,114,115,116,115,116,117,118,
+ 11, 41, 29, 42, 39, 43, 40, 44, 41, 96, 95, 97, 98,100, 99,101, 39, 98, 98,119,
+120,121,121,122, 43,100,123,124,121,125,126,127, 29, 95,128,129, 98,123,130,131,
+ 42, 97,129,132,119,124,133,134, 40, 99,130,133,121,126,135,136, 44,101,131,134,
+122,127,136,137, 13, 47, 31, 48, 45, 49, 46, 50, 77,103,102,104,105,107,106,108,
+ 43,123,100,124,121,126,125,127, 79,138,138,139,140,141,141,142, 52,143,130,144,
+110,145,146,147, 80,148,149,150,151,152,153,154, 68,155,146,156,157,158,159,160,
+ 81,161,162,163,164,165,166,167,  5, 29, 27, 30, 22, 31, 28, 32, 41, 98, 95, 99,
+ 96,100, 97,101, 29,128, 95,129, 98,130,123,131, 52,130,143,144,110,146,145,147,
+ 24, 95, 95,109, 92,102,102,114, 47,123,143,155,103,138,148,161, 35,129,143,168,
+105,149,169,170, 58,131,171,172,115,162,173,174, 10, 35, 28, 36, 33, 37, 34, 38,
+ 77,105,102,106,103,107,104,108, 42,129, 97,132,119,133,124,134, 80,149,148,150,
+151,153,152,154, 47,143,123,155,103,148,138,161, 82,169,169,175,176,177,177,178,
+ 67,168,145,179,151,180,181,182, 83,170,173,183,184,185,186,187, 12, 52, 30, 53,
+ 45, 54, 51, 55, 66,110,109,111,110,112,111,113, 40,130, 99,133,121,135,126,136,
+ 68,146,155,156,157,159,158,160, 35,143,129,168,105,169,149,170, 67,145,168,179,
+151,181,180,182, 63,144,144,188,140,189,189,190, 69,147,172,191,164,192,193,194,
+ 14, 58, 32, 59, 56, 60, 57, 61, 78,115,114,116,115,117,116,118, 44,131,101,134,
+122,136,127,137, 81,162,161,163,164,166,165,167, 58,171,131,172,115,173,162,174,
+ 83,173,170,183,184,186,185,187, 69,172,147,191,164,193,192,194, 84,174,174,195,
+196,197,197,198,  1,  9, 11, 13,  5, 10, 12, 14,  5, 22, 29, 31, 27, 28, 30, 32,
+  5, 24, 41, 47, 29, 35, 52, 58,  7, 25, 42, 48, 30, 36, 53, 59,  4, 22, 39, 45,
+ 22, 33, 45, 56,  6, 23, 40, 46, 28, 34, 51, 57,  6, 25, 43, 49, 31, 37, 54, 60,
+  8, 26, 44, 50, 32, 38, 55, 61, 11, 41, 39, 43, 29, 42, 40, 44, 41, 96, 98,100,
+ 95, 97, 99,101, 29, 95, 98,123,128,129,130,131, 42, 97,119,124,129,132,133,134,
+ 39, 98,120,121, 98,119,121,122, 43,100,121,125,123,124,126,127, 40, 99,121,126,
+130,133,135,136, 44,101,122,127,131,134,136,137,  9, 76, 41, 77, 41, 77, 66, 78,
+ 24, 92, 95,102, 95,102,109,114, 22, 92, 96,103, 98,105,110,115, 25, 93, 97,104,
+ 99,106,111,116, 22, 92, 98,105, 96,103,110,115, 25, 93, 99,106, 97,104,111,116,
+ 23, 93,100,107,100,107,112,117, 26, 94,101,108,101,108,113,118, 13, 77, 43, 79,
+ 52, 80, 68, 81, 47,103,123,138,143,148,155,161, 31,102,100,138,130,149,146,162,
+ 48,104,124,139,144,150,156,163, 45,105,121,140,110,151,157,164, 49,107,126,141,
+145,152,158,165, 46,106,125,141,146,153,159,166, 50,108,127,142,147,154,160,167,
+  5, 41, 29, 52, 24, 47, 35, 58, 29, 98,128,130, 95,123,129,131, 27, 95, 95,143,
+ 95,143,143,171, 30, 99,129,144,109,155,168,172, 22, 96, 98,110, 92,103,105,115,
+ 31,100,130,146,102,138,149,162, 28, 97,123,145,102,148,169,173, 32,101,131,147,
+114,161,170,174, 12, 66, 40, 68, 35, 67, 63, 69, 52,110,130,146,143,145,144,147,
+ 30,109, 99,155,129,168,144,172, 53,111,133,156,168,179,188,191, 45,110,121,157,
+105,151,140,164, 54,112,135,159,169,181,189,192, 51,111,126,158,149,180,189,193,
+ 55,113,136,160,170,182,190,194, 10, 77, 42, 80, 47, 82, 67, 83, 35,105,129,149,
+143,169,168,170, 28,102, 97,148,123,169,145,173, 36,106,132,150,155,175,179,183,
+ 33,103,119,151,103,176,151,184, 37,107,133,153,148,177,180,185, 34,104,124,152,
+138,177,181,186, 38,108,134,154,161,178,182,187, 14, 78, 44, 81, 58, 83, 69, 84,
+ 58,115,131,162,171,173,172,174, 32,114,101,161,131,170,147,174, 59,116,134,163,
+172,183,191,195, 56,115,122,164,115,184,164,196, 60,117,136,166,173,186,193,197,
+ 57,116,127,165,162,185,192,197, 61,118,137,167,174,187,194,198,  2, 10, 12, 17,
+  6, 15, 16, 18, 10, 33, 35, 37, 28, 34, 36, 38, 12, 35, 66, 67, 40, 63, 68, 69,
+ 17, 37, 67, 70, 51, 64, 71, 72,  6, 28, 40, 51, 23, 34, 46, 57, 15, 34, 63, 64,
+ 34, 62, 64, 65, 16, 36, 68, 71, 46, 64, 73, 74, 18, 38, 69, 72, 57, 65, 74, 75,
+ 13, 47, 45, 49, 31, 48, 46, 50, 77,103,105,107,102,104,106,108, 52,143,110,145,
+130,144,146,147, 80,148,151,152,149,150,153,154, 43,123,121,126,100,124,125,127,
+ 79,138,140,141,138,139,141,142, 68,155,157,158,146,156,159,160, 81,161,164,165,
+162,163,166,167, 13, 77, 52, 80, 43, 79, 68, 81, 47,103,143,148,123,138,155,161,
+ 45,105,110,151,121,140,157,164, 49,107,145,152,126,141,158,165, 31,102,130,149,
+100,138,146,162, 48,104,144,150,124,139,156,163, 46,106,146,153,125,141,159,166,
+ 50,108,147,154,127,142,160,167, 19, 82, 54, 85, 54, 85, 73, 86, 82,176,169,177,
+169,177,175,178, 54,169,112,181,135,189,159,192, 85,177,181,199,189,200,201,202,
+ 54,169,135,189,112,181,159,192, 85,177,189,200,181,199,201,202, 73,175,159,201,
+159,201,203,204, 86,178,192,202,192,202,204,205,  7, 42, 30, 53, 25, 48, 36, 59,
+ 42,119,129,133, 97,124,132,134, 30,129,109,168, 99,144,155,172, 53,133,168,188,
+111,156,179,191, 25, 97, 99,111, 93,104,106,116, 48,124,144,156,104,139,150,163,
+ 36,132,155,179,106,150,175,183, 59,134,172,191,116,163,183,195, 17, 67, 51, 71,
+ 37, 70, 64, 72, 80,151,149,153,148,152,150,154, 53,168,111,179,133,188,156,191,
+ 87,180,180,206,180,206,206,207, 49,145,126,158,107,152,141,165, 85,181,189,201,
+177,199,200,202, 71,179,158,208,153,206,201,209, 88,182,193,209,185,210,211,212,
+ 17, 80, 53, 87, 49, 85, 71, 88, 67,151,168,180,145,181,179,182, 51,149,111,180,
+126,189,158,193, 71,153,179,206,158,201,208,209, 37,148,133,180,107,177,153,185,
+ 70,152,188,206,152,199,206,210, 64,150,156,206,141,200,201,211, 72,154,191,207,
+165,202,209,212, 20, 83, 55, 88, 60, 89, 74, 90, 83,184,170,185,173,186,183,187,
+ 55,170,113,182,136,190,160,194, 88,185,182,210,193,211,209,212, 60,173,136,193,
+117,186,166,197, 89,186,190,211,186,213,211,214, 74,183,160,209,166,211,204,215,
+ 90,187,194,212,197,214,215,216,  1, 11,  9, 13,  5, 12, 10, 14, 11, 39, 41, 43,
+ 29, 40, 42, 44,  9, 41, 76, 77, 41, 66, 77, 78, 13, 43, 77, 79, 52, 68, 80, 81,
+  5, 29, 41, 52, 24, 35, 47, 58, 12, 40, 66, 68, 35, 63, 67, 69, 10, 42, 77, 80,
+ 47, 67, 82, 83, 14, 44, 78, 81, 58, 69, 83, 84,  5, 29, 22, 31, 27, 30, 28, 32,
+ 41, 98, 96,100, 95, 99, 97,101, 24, 95, 92,102, 95,109,102,114, 47,123,103,138,
+143,155,148,161, 29,128, 98,130, 95,129,123,131, 52,130,110,146,143,144,145,147,
+ 35,129,105,149,143,168,169,170, 58,131,115,162,171,172,173,174,  5, 41, 24, 47,
+ 29, 52, 35, 58, 29, 98, 95,123,128,130,129,131, 22, 96, 92,103, 98,110,105,115,
+ 31,100,102,138,130,146,149,162, 27, 95, 95,143, 95,143,143,171, 30, 99,109,155,
+129,144,168,172, 28, 97,102,148,123,145,169,173, 32,101,114,161,131,147,170,174,
+  7, 42, 25, 48, 30, 53, 36, 59, 42,119, 97,124,129,133,132,134, 25, 97, 93,104,
+ 99,111,106,116, 48,124,104,139,144,156,150,163, 30,129, 99,144,109,168,155,172,
+ 53,133,111,156,168,188,179,191, 36,132,106,150,155,179,175,183, 59,134,116,163,
+172,191,183,195,  4, 39, 22, 45, 22, 45, 33, 56, 39,120, 98,121, 98,121,119,122,
+ 22, 98, 92,105, 96,110,103,115, 45,121,105,140,110,157,151,164, 22, 98, 96,110,
+ 92,105,103,115, 45,121,110,157,105,140,151,164, 33,119,103,151,103,151,176,184,
+ 56,122,115,164,115,164,184,196,  6, 40, 23, 46, 28, 51, 34, 57, 43,121,100,125,
+123,126,124,127, 25, 99, 93,106, 97,111,104,116, 49,126,107,141,145,158,152,165,
+ 31,130,100,146,102,149,138,162, 54,135,112,159,169,189,181,192, 37,133,107,153,
+148,180,177,185, 60,136,117,166,173,193,186,197,  6, 43, 25, 49, 31, 54, 37, 60,
+ 40,121, 99,126,130,135,133,136, 23,100, 93,107,100,112,107,117, 46,125,106,141,
+146,159,153,166, 28,123, 97,145,102,169,148,173, 51,126,111,158,149,189,180,193,
+ 34,124,104,152,138,181,177,186, 57,127,116,165,162,192,185,197,  8, 44, 26, 50,
+ 32, 55, 38, 61, 44,122,101,127,131,136,134,137, 26,101, 94,108,101,113,108,118,
+ 50,127,108,142,147,160,154,167, 32,131,101,147,114,170,161,174, 55,136,113,160,
+170,190,182,194, 38,134,108,154,161,182,178,187, 61,137,118,167,174,194,187,198,
+  2, 12, 10, 17,  6, 16, 15, 18, 13, 45, 47, 49, 31, 46, 48, 50, 13, 52, 77, 80,
+ 43, 68, 79, 81, 19, 54, 82, 85, 54, 73, 85, 86,  7, 30, 42, 53, 25, 36, 48, 59,
+ 17, 51, 67, 71, 37, 64, 70, 72, 17, 53, 80, 87, 49, 71, 85, 88, 20, 55, 83, 88,
+ 60, 74, 89, 90, 10, 35, 33, 37, 28, 36, 34, 38, 77,105,103,107,102,106,104,108,
+ 47,143,103,148,123,155,138,161, 82,169,176,177,169,175,177,178, 42,129,119,133,
+ 97,132,124,134, 80,149,151,153,148,150,152,154, 67,168,151,180,145,179,181,182,
+ 83,170,184,185,173,183,186,187, 12, 66, 35, 67, 40, 68, 63, 69, 52,110,143,145,
+130,146,144,147, 45,110,105,151,121,157,140,164, 54,112,169,181,135,159,189,192,
+ 30,109,129,168, 99,155,144,172, 53,111,168,179,133,156,188,191, 51,111,149,180,
+126,158,189,193, 55,113,170,182,136,160,190,194, 17, 67, 37, 70, 51, 71, 64, 72,
+ 80,151,148,152,149,153,150,154, 49,145,107,152,126,158,141,165, 85,181,177,199,
+189,201,200,202, 53,168,133,188,111,179,156,191, 87,180,180,206,180,206,206,207,
+ 71,179,153,206,158,208,201,209, 88,182,185,210,193,209,211,212,  6, 40, 28, 51,
+ 23, 46, 34, 57, 43,121,123,126,100,125,124,127, 31,130,102,149,100,146,138,162,
+ 54,135,169,189,112,159,181,192, 25, 99, 97,111, 93,106,104,116, 49,126,145,158,
+107,141,152,165, 37,133,148,180,107,153,177,185, 60,136,173,193,117,166,186,197,
+ 15, 63, 34, 64, 34, 64, 62, 65, 79,140,138,141,138,141,139,142, 48,144,104,150,
+124,156,139,163, 85,189,177,200,181,201,199,202, 48,144,124,156,104,150,139,163,
+ 85,189,181,201,177,200,199,202, 70,188,152,206,152,206,199,210, 89,190,186,211,
+186,211,213,214, 16, 68, 36, 71, 46, 73, 64, 74, 68,157,155,158,146,159,156,160,
+ 46,146,106,153,125,159,141,166, 73,159,175,201,159,203,201,204, 36,155,132,179,
+106,175,150,183, 71,158,179,208,153,201,206,209, 64,156,150,206,141,201,200,211,
+ 74,160,183,209,166,204,211,215, 18, 69, 38, 72, 57, 74, 65, 75, 81,164,161,165,
+162,166,163,167, 50,147,108,154,127,160,142,167, 86,192,178,202,192,204,202,205,
+ 59,172,134,191,116,183,163,195, 88,193,182,209,185,211,210,212, 72,191,154,207,
+165,209,202,212, 90,194,187,212,197,215,214,216,  2, 13, 13, 19,  7, 17, 17, 20,
+ 12, 45, 52, 54, 30, 51, 53, 55, 10, 47, 77, 82, 42, 67, 80, 83, 17, 49, 80, 85,
+ 53, 71, 87, 88,  6, 31, 43, 54, 25, 37, 49, 60, 16, 46, 68, 73, 36, 64, 71, 74,
+ 15, 48, 79, 85, 48, 70, 85, 89, 18, 50, 81, 86, 59, 72, 88, 90, 12, 52, 45, 54,
+ 30, 53, 51, 55, 66,110,110,112,109,111,111,113, 35,143,105,169,129,168,149,170,
+ 67,145,151,181,168,179,180,182, 40,130,121,135, 99,133,126,136, 68,146,157,159,
+155,156,158,160, 63,144,140,189,144,188,189,190, 69,147,164,192,172,191,193,194,
+ 10, 77, 47, 82, 42, 80, 67, 83, 35,105,143,169,129,149,168,170, 33,103,103,176,
+119,151,151,184, 37,107,148,177,133,153,180,185, 28,102,123,169, 97,148,145,173,
+ 36,106,155,175,132,150,179,183, 34,104,138,177,124,152,181,186, 38,108,161,178,
+134,154,182,187, 17, 80, 49, 85, 53, 87, 71, 88, 67,151,145,181,168,180,179,182,
+ 37,148,107,177,133,180,153,185, 70,152,152,199,188,206,206,210, 51,149,126,189,
+111,180,158,193, 71,153,158,201,179,206,208,209, 64,150,141,200,156,206,201,211,
+ 72,154,165,202,191,207,209,212,  6, 43, 31, 54, 25, 49, 37, 60, 40,121,130,135,
+ 99,126,133,136, 28,123,102,169, 97,145,148,173, 51,126,149,189,111,158,180,193,
+ 23,100,100,112, 93,107,107,117, 46,125,146,159,106,141,153,166, 34,124,138,181,
+104,152,177,186, 57,127,162,192,116,165,185,197, 16, 68, 46, 73, 36, 71, 64, 74,
+ 68,157,146,159,155,158,156,160, 36,155,106,175,132,179,150,183, 71,158,153,201,
+179,208,206,209, 46,146,125,159,106,153,141,166, 73,159,159,203,175,201,201,204,
+ 64,156,141,201,150,206,200,211, 74,160,166,204,183,209,211,215, 15, 79, 48, 85,
+ 48, 85, 70, 89, 63,140,144,189,144,189,188,190, 34,138,104,177,124,181,152,186,
+ 64,141,150,200,156,201,206,211, 34,138,124,181,104,177,152,186, 64,141,156,201,
+150,200,206,211, 62,139,139,199,139,199,199,213, 65,142,163,202,163,202,210,214,
+ 18, 81, 50, 86, 59, 88, 72, 90, 69,164,147,192,172,193,191,194, 38,161,108,178,
+134,182,154,187, 72,165,154,202,191,209,207,212, 57,162,127,192,116,185,165,197,
+ 74,166,160,204,183,211,209,215, 65,163,142,202,163,210,202,214, 75,167,167,205,
+195,212,212,216,  3, 14, 14, 20,  8, 18, 18, 21, 14, 56, 58, 60, 32, 57, 59, 61,
+ 14, 58, 78, 83, 44, 69, 81, 84, 20, 60, 83, 89, 55, 74, 88, 90,  8, 32, 44, 55,
+ 26, 38, 50, 61, 18, 57, 69, 74, 38, 65, 72, 75, 18, 59, 81, 88, 50, 72, 86, 90,
+ 21, 61, 84, 90, 61, 75, 90, 91, 14, 58, 56, 60, 32, 59, 57, 61, 78,115,115,117,
+114,116,116,118, 58,171,115,173,131,172,162,174, 83,173,184,186,170,183,185,187,
+ 44,131,122,136,101,134,127,137, 81,162,164,166,161,163,165,167, 69,172,164,193,
+147,191,192,194, 84,174,196,197,174,195,197,198, 14, 78, 58, 83, 44, 81, 69, 84,
+ 58,115,171,173,131,162,172,174, 56,115,115,184,122,164,164,196, 60,117,173,186,
+136,166,193,197, 32,114,131,170,101,161,147,174, 59,116,172,183,134,163,191,195,
+ 57,116,162,185,127,165,192,197, 61,118,174,187,137,167,194,198, 20, 83, 60, 89,
+ 55, 88, 74, 90, 83,184,173,186,170,185,183,187, 60,173,117,186,136,193,166,197,
+ 89,186,186,213,190,211,211,214, 55,170,136,190,113,182,160,194, 88,185,193,211,
+182,210,209,212, 74,183,166,211,160,209,204,215, 90,187,197,214,194,212,215,216,
+  8, 44, 32, 55, 26, 50, 38, 61, 44,122,131,136,101,127,134,137, 32,131,114,170,
+101,147,161,174, 55,136,170,190,113,160,182,194, 26,101,101,113, 94,108,108,118,
+ 50,127,147,160,108,142,154,167, 38,134,161,182,108,154,178,187, 61,137,174,194,
+118,167,187,198, 18, 69, 57, 74, 38, 72, 65, 75, 81,164,162,166,161,165,163,167,
+ 59,172,116,183,134,191,163,195, 88,193,185,211,182,209,210,212, 50,147,127,160,
+108,154,142,167, 86,192,192,204,178,202,202,205, 72,191,165,209,154,207,202,212,
+ 90,194,197,215,187,212,214,216, 18, 81, 59, 88, 50, 86, 72, 90, 69,164,172,193,
+147,192,191,194, 57,162,116,185,127,192,165,197, 74,166,183,211,160,204,209,215,
+ 38,161,134,182,108,178,154,187, 72,165,191,209,154,202,207,212, 65,163,163,210,
+142,202,202,214, 75,167,195,212,167,205,212,216, 21, 84, 61, 90, 61, 90, 75, 91,
+ 84,196,174,197,174,197,195,198, 61,174,118,187,137,194,167,198, 90,197,187,214,
+194,215,212,216, 61,174,137,194,118,187,167,198, 90,197,194,215,187,214,212,216,
+ 75,195,167,212,167,212,205,216, 91,198,198,216,198,216,216,217
+};
+
+const unsigned int igraph_i_isographs_3[] =  { 0, 1, 3, 5, 6, 7, 10, 11, 15, 21, 
+					       23, 25, 27, 30, 31, 63 };
+const unsigned int igraph_i_isographs_3u[] = { 0, 1, 3, 7 };
+const unsigned int igraph_i_isographs_4[] = {
+   0,    1,    3,    7,    9,   10,   11,   14,   15,   18,   19,   20,   21, 
+  22,   23,   27,   29,   30,   31,   54,   55,   63,   73,   75,   76,   77, 
+  79,   81,   83,   84,   85,   86,   87,   90,   91,   92,   93,   94,   95, 
+  98,   99,  100,  101,  102,  103,  106,  107,  108,  109,  110,  111,  115, 
+ 116,  117,  118,  119,  122,  123,  124,  125,  126,  127,  219,  220,  221, 
+ 223,  228,  229,  230,  231,  237,  238,  239,  246,  247,  255,  292,  293, 
+ 295,  301,  302,  303,  310,  311,  319,  365,  367,  373,  375,  382,  383, 
+ 511,  585,  587,  591,  593,  594,  595,  596,  597,  598,  599,  601,  602, 
+ 603,  604,  605,  606,  607,  625,  626,  627,  630,  631,  633,  634,  635, 
+ 638,  639,  659,  660,  661,  663,  666,  667,  669,  670,  671,  674,  675, 
+ 678,  679,  683,  686,  687,  694,  695,  703,  729,  731,  732,  733,  735, 
+ 737,  739,  741,  742,  743,  745,  746,  747,  748,  749,  750,  751,  753, 
+ 755,  756,  757,  758,  759,  761,  762,  763,  764,  765,  766,  767,  819, 
+ 822,  823,  826,  827,  830,  831,  875,  876,  877,  879,  883,  885,  886, 
+ 887,  891,  892,  893,  894,  895,  947,  949,  951,  955,  957,  958,  959, 
+1019, 1020, 1021, 1023, 1755, 1757, 1758, 1759, 1782, 1783, 1791, 1883, 1887, 
+1907, 1911, 1917, 1918, 1919, 2029, 2031, 2039, 2047, 4095};
+const unsigned int igraph_i_isographs_4u[] = { 0, 1, 3, 7, 11, 12, 13, 
+					15, 30, 31, 63};
+
+const unsigned int igraph_i_classedges_3[] = { 1,2, 0,2, 2,1, 0,1, 2,0, 1,0 };
+const unsigned int igraph_i_classedges_3u[] = { 1,2, 0,2, 0,1 };
+const unsigned int igraph_i_classedges_4[] = { 2,3, 1,3, 0,3, 3,2, 1,2, 0,2,
+					       3,1, 2,1, 0,1, 3,0, 2,0, 1,0 };
+const unsigned int igraph_i_classedges_4u[] = { 2,3, 1,3, 0,3, 1,2, 0,2, 0,1 };
+
+/**
+ * \section about_graph_isomorphism
+ * 
+ * <para>igraph provides four set of functions to deal with graph
+ * isomorphism problems.</para>
+ * 
+ * <para>The \ref igraph_isomorphic() and \ref igraph_subisomorphic()
+ * functions make up the first set (in addition with the \ref
+ * igraph_permute_vertices() function). These functions choose the
+ * algorithm which is best for the supplied input graph. (The choice is
+ * not very sophisticated though, see their documentation for
+ * details.)</para>
+ * 
+ * <para>The VF2 graph (and subgraph) isomorphism algorithm is implemented in
+ * igraph, these functions are the second set. See \ref
+ * igraph_isomorphic_vf2() and \ref igraph_subisomorphic_vf2() for
+ * starters.</para>
+ * 
+ * <para>Functions for the BLISS algorithm constitute the third set, 
+ * see \ref igraph_isomorphic_bliss(). This implementation only works
+ * for undirected graphs.</para>
+ * 
+ * <para>Finally, the isomorphism classes of all graphs with three and
+ * four vertices are precomputed and stored in igraph, so for these
+ * small graphs there is a very simple fast way to decide isomorphism.
+ * See \ref igraph_isomorphic_34().
+ * </para>
+ */
+
+/**
+ * \function igraph_isoclass
+ * \brief Determine the isomorphism class of a graph with 3 or 4 vertices
+ * 
+ * </para><para>
+ * All graphs with a given number of vertices belong to a number of
+ * isomorphism classes, with every graph in a given class being
+ * isomorphic to each other.
+ * 
+ * </para><para>
+ * This function gives the isomorphism class (a number) of a
+ * graph. Two graphs have the same isomorphism class if and only if
+ * they are isomorphic.
+ * 
+ * </para><para>
+ * The first isomorphism class is numbered zero and it is the empty
+ * graph, the last isomorphism class is the full graph. The number of
+ * isomorphism class for directed graphs with three vertices is 16
+ * (between 0 and 15), for undirected graph it is only 4. For graphs
+ * with four vertices it is 218 (directed) and 11 (undirected).
+ * 
+ * \param graph The graph object.
+ * \param isoclass Pointer to an integer, the isomorphism class will
+ *        be stored here.
+ * \return Error code.
+ * \sa \ref igraph_isomorphic(), \ref igraph_isoclass_subgraph(),
+ * \ref igraph_isoclass_create(), \ref igraph_motifs_randesu().
+ * 
+ * Because of some limitations this function works only for graphs
+ * with three of four vertices.
+ * 
+ * </para><para>
+ * Time complexity: O(|E|), the number of edges in the graph.
+ */
+
+int igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass) {
+  long int e;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_integer_t from, to;
+  unsigned char idx, mul;
+  const unsigned int *arr_idx, *arr_code;
+  int code=0;
+
+  if (no_of_nodes < 3 || no_of_nodes > 4) {
+    IGRAPH_ERROR("Only implemented for graphs with 3 or 4 vertices",
+		 IGRAPH_UNIMPLEMENTED);
+  }
+
+  if (igraph_is_directed(graph)) {
+    if (no_of_nodes==3) {
+      arr_idx=igraph_i_isoclass_3_idx;
+      arr_code=igraph_i_isoclass2_3;
+      mul=3;
+    } else {
+      arr_idx=igraph_i_isoclass_4_idx;
+      arr_code=igraph_i_isoclass2_4;
+      mul=4;
+    }
+  } else {
+    if (no_of_nodes==3) {
+      arr_idx=igraph_i_isoclass_3u_idx;
+      arr_code=igraph_i_isoclass2_3u;
+      mul=3;
+    } else {
+      arr_idx=igraph_i_isoclass_4u_idx;
+      arr_code=igraph_i_isoclass2_4u;
+      mul=4;
+    }
+  } 
+
+  for (e=0; e<no_of_edges; e++) {
+    igraph_edge(graph, (igraph_integer_t) e, &from, &to);
+    idx=(unsigned char) (mul*from+to);
+    code |= arr_idx[idx];
+  }
+  
+  *isoclass=(igraph_integer_t) arr_code[code];
+  return 0;
+}
+
+/**
+ * \function igraph_isomorphic 
+ * \brief Decides whether two graphs are isomorphic
+ * 
+ * </para><para>
+ * From Wikipedia: The graph isomorphism problem or GI problem is the
+ * graph theory problem of determining whether, given two graphs G1
+ * and G2, it is possible to permute (or relabel) the vertices of one
+ * graph so that it is equal to the other. Such a permutation is
+ * called a graph isomorphism.</para>
+ * 
+ * <para>This function decides which graph isomorphism algorithm to be
+ * used based on the input graphs. Right now it does the following:
+ * \olist
+ * \oli If one graph is directed and the other undirected then an
+ *    error is triggered.
+ * \oli If the two graphs does not have the same number of vertices
+ *    and edges it returns with \c FALSE.
+ * \oli Otherwise, if the graphs have three or four vertices then an O(1)
+ *    algorithm is used with precomputed data.
+ * \oli Otherwise, if the graphs are directed then VF2 is used, see
+ *    \ref igraph_isomorphic_vf2().
+ * \oli Otherwise BLISS is used, see \ref igraph_isomorphic_bliss().
+ * \endolist 
+ * </para>
+ * 
+ * <para> Please call the VF2 and BLISS functions directly if you need
+ * something more sophisticated, e.g. you need the isomorphic mapping.
+ * 
+ * \param graph1 The first graph.
+ * \param graph2 The second graph.
+ * \param iso Pointer to a logical variable, will be set to TRUE (1)
+ *        if the two graphs are isomorphic, and FALSE (0) otherwise.
+ * \return Error code.
+ * \sa \ref igraph_isoclass(), \ref igraph_isoclass_subgraph(),
+ * \ref igraph_isoclass_create().
+ * 
+ * Time complexity: exponential.
+ */
+
+int igraph_isomorphic(const igraph_t *graph1, const igraph_t *graph2,
+		      igraph_bool_t *iso) {
+  
+  long int nodes1=igraph_vcount(graph1), nodes2=igraph_vcount(graph2);
+  long int edges1=igraph_ecount(graph1), edges2=igraph_ecount(graph2);
+  igraph_bool_t dir1=igraph_is_directed(graph1), dir2=igraph_is_directed(graph2);
+
+  if (dir1 != dir2) {
+    IGRAPH_ERROR("Cannot compare directed and undirected graphs", IGRAPH_EINVAL);
+  } else if (nodes1 != nodes2 || edges1 != edges2) { 
+    *iso=0;
+  } else if (nodes1==3 || nodes1==4) {
+	igraph_isomorphic_34(graph1, graph2, iso);
+  } else if (dir1) {
+    igraph_isomorphic_vf2(graph1, graph2, 0, 0, 0, 0, iso, 0, 0, 0, 0, 0);
+  } else {
+    igraph_isomorphic_bliss(graph1, graph2, iso, 0, 0, /*sh1=*/0, /*sh2=*/0, 0, 0);
+  }
+				
+  return 0;
+}
+
+/**
+ * \function igraph_isomorphic_34
+ * Graph isomorphism for 3-4 vertices
+ * 
+ * This function uses precomputed indices to decide isomorphism
+ * problems for graphs with only 3 or 4 vertices.
+ * \param graph1 The first input graph.
+ * \param graph2 The second input graph. Must have the same
+ *   directedness as \p graph1.
+ * \param iso Pointer to a boolean, the result is stored here. 
+ * \return Error code.
+ *
+ * Time complexity: O(1).
+ */
+
+int igraph_isomorphic_34(const igraph_t *graph1, const igraph_t *graph2, 
+			 igraph_bool_t *iso) {
+
+  igraph_integer_t class1, class2;  
+  IGRAPH_CHECK(igraph_isoclass(graph1, &class1));
+  IGRAPH_CHECK(igraph_isoclass(graph2, &class2));
+  *iso= (class1 == class2);
+  return 0;
+}
+
+/**
+ * \function igraph_isoclass_subgraph
+ * \brief The isomorphism class of a subgraph of a graph.
+ * 
+ * </para><para>
+ * This function is only implemented for subgraphs with three or four
+ * vertices.
+ * \param graph The graph object.
+ * \param vids A vector containing the vertex ids to be considered as
+ *        a subgraph. Each vertex id should be included at most once.
+ * \param isoclass Pointer to an integer, this will be set to the
+ *        isomorphism class.
+ * \return Error code.
+ * \sa \ref igraph_isoclass(), \ref igraph_isomorphic(),
+ * \ref igraph_isoclass_create().
+ * 
+ * Time complexity: O((d+n)*n), d is the average degree in the network,
+ * and n is the number of vertices in \c vids.
+ */
+
+int igraph_isoclass_subgraph(const igraph_t *graph, igraph_vector_t *vids,
+			     igraph_integer_t *isoclass) {
+  int nodes=(int) igraph_vector_size(vids);
+  igraph_bool_t directed=igraph_is_directed(graph);
+  igraph_vector_t neis;
+  
+  unsigned char mul, idx;
+  const unsigned int *arr_idx, *arr_code;
+  int code=0;
+  
+  long int i, j, s;
+
+  if (nodes < 3 || nodes > 4) { 
+    IGRAPH_ERROR("Only for three- or four-vertex subgraphs",
+		 IGRAPH_UNIMPLEMENTED);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  
+  if (directed) {
+    if (nodes==3) {
+      arr_idx=igraph_i_isoclass_3_idx;
+      arr_code=igraph_i_isoclass2_3;
+      mul=3;
+    } else {
+      arr_idx=igraph_i_isoclass_4_idx;
+      arr_code=igraph_i_isoclass2_4;
+      mul=4;
+    }
+  } else {
+    if (nodes==3) {
+      arr_idx=igraph_i_isoclass_3u_idx;
+      arr_code=igraph_i_isoclass2_3u;
+      mul=3;
+    } else {
+      arr_idx=igraph_i_isoclass_4u_idx;
+      arr_code=igraph_i_isoclass2_4u;
+      mul=4;
+    }
+  }
+
+  for (i=0; i<nodes; i++) {
+    long int from=(long int) VECTOR(*vids)[i];
+    igraph_neighbors(graph, &neis, (igraph_integer_t) from, IGRAPH_OUT);
+    s=igraph_vector_size(&neis);
+    for (j=0; j<s; j++) {
+      long int nei=(long int) VECTOR(neis)[j], to;
+      if (igraph_vector_search(vids, 0, nei, &to)) {
+	idx=(unsigned char) (mul*i+to);
+	code |= arr_idx[idx];
+      }
+    }
+  }
+  
+  *isoclass=(igraph_integer_t) arr_code[code];
+  igraph_vector_destroy(&neis);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_isoclass_create
+ * \brief Creates a graph from the given isomorphism class.
+ *
+ * </para><para>
+ * This function is implemented only for graphs with three or four
+ * vertices. 
+ * \param graph Pointer to an uninitialized graph object.
+ * \param size The number of vertices to add to the graph.
+ * \param number The isomorphism class.
+ * \param directed Logical constant, whether to create a directed
+ *        graph. 
+ * \return Error code.
+ * \sa \ref igraph_isoclass(), 
+ * \ref igraph_isoclass_subgraph(),
+ * \ref igraph_isomorphic().
+ * 
+ * Time complexity: O(|V|+|E|), the number of vertices plus the number
+ * of edges in the graph to create.
+ */
+
+int igraph_isoclass_create(igraph_t *graph, igraph_integer_t size,
+			   igraph_integer_t number, igraph_bool_t directed) {
+  igraph_vector_t edges;
+  const unsigned int *classedges;
+  long int power;
+  long int code;
+  long int pos;
+
+  if (size < 3 || size > 4) {
+    IGRAPH_ERROR("Only for graphs with three of four vertices", 
+		 IGRAPH_UNIMPLEMENTED);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  if (directed) {
+    if (size==3) {
+      classedges=igraph_i_classedges_3;
+
+      if (number < 0 || 
+	  number >= (int)(sizeof(igraph_i_isographs_3)/sizeof(unsigned int))){
+	IGRAPH_ERROR("`number' invalid, cannot create graph", IGRAPH_EINVAL);
+      }
+
+      code=igraph_i_isographs_3[ (long int) number];
+      power=32;
+    } else {
+      classedges=igraph_i_classedges_4;
+
+      if (number < 0 ||
+	  number >= (int)(sizeof(igraph_i_isographs_4)/sizeof(unsigned int))){
+	IGRAPH_ERROR("`number' invalid, cannot create graph", IGRAPH_EINVAL);
+      }
+
+      code=igraph_i_isographs_4[ (long int) number];
+      power=2048;
+    }
+  } else {
+    if (size==3) {
+      classedges=igraph_i_classedges_3u;
+
+      if (number < 0 ||
+	  number >= (int)(sizeof(igraph_i_isographs_3u)/
+			  sizeof(unsigned int))){
+	IGRAPH_ERROR("`number' invalid, cannot create graph", IGRAPH_EINVAL);
+      }
+
+      code=igraph_i_isographs_3u[ (long int) number];
+      power=4;
+    } else {
+      classedges=igraph_i_classedges_4u;
+
+      if (number < 0 ||
+	  number >= (int)(sizeof(igraph_i_isographs_4u)/
+			  sizeof(unsigned int))) {
+	IGRAPH_ERROR("`number' invalid, cannot create graph", IGRAPH_EINVAL);
+      }
+
+      code=igraph_i_isographs_4u[ (long int) number];
+      power=32;
+    }
+  }
+
+  pos=0;
+  while (code > 0) {
+    if (code >= power) {
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, classedges[2*pos]));
+      IGRAPH_CHECK(igraph_vector_push_back(&edges, classedges[2*pos+1]));
+      code -= power;
+    }
+    power /= 2;
+    pos++;
+  }
+
+  IGRAPH_CHECK(igraph_create(graph, &edges, size, directed));
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_isomorphic_function_vf2
+ * The generic VF2 interface
+ * 
+ * </para><para>
+ * This function is an implementation of the VF2 isomorphism algorithm, 
+ * see P. Foggia, C. Sansone, M. Vento, An Improved algorithm for
+ * matching large graphs, Proc. of the 3rd IAPR-TC-15 International
+ * Workshop on Graph-based Representations, Italy, 2001.</para>
+ * 
+ * <para>For using it you need to define a callback function of type
+ * \ref igraph_isohandler_t. This function will be called whenever VF2
+ * finds an isomorphism between the two graphs. The mapping between
+ * the two graphs will be also provided to this function. If the
+ * callback returns a nonzero value then the search is continued,
+ * otherwise it stops.
+ * \param graph1 The first input graph.
+ * \param graph2 The second input graph.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param map12 Pointer to an initialized vector or \c NULL. If not \c
+ *   NULL and the supplied graphs are isomorphic then the permutation
+ *   taking \p graph1 to \p graph is stored here. If not \c NULL and the
+ *   graphs are not isomorphic then a zero-length vector is returned.
+ * \param map21 This is the same as \p map12, but for the permutation
+ *   taking \p graph2 to \p graph1.
+ * \param isohandler_fn The callback function to be called if an
+ *   isomorphism is found. See also \ref igraph_isohandler_t.
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p isohandler_fn, \p
+ *   node_compat_fn and \p edge_compat_fn. 
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+  
+int igraph_isomorphic_function_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+				   const igraph_vector_int_t *vertex_color1,
+				   const igraph_vector_int_t *vertex_color2,
+				   const igraph_vector_int_t *edge_color1,
+				   const igraph_vector_int_t *edge_color2,
+				   igraph_vector_t *map12,
+				   igraph_vector_t *map21,
+				   igraph_isohandler_t *isohandler_fn,
+				   igraph_isocompat_t *node_compat_fn,
+				   igraph_isocompat_t *edge_compat_fn,
+				   void *arg) {
+  
+  long int no_of_nodes=igraph_vcount(graph1);
+  long int no_of_edges=igraph_ecount(graph1);
+  igraph_vector_t mycore_1, mycore_2, *core_1=&mycore_1, *core_2=&mycore_2;
+  igraph_vector_t in_1, in_2, out_1, out_2;
+  long int in_1_size=0, in_2_size=0, out_1_size=0, out_2_size=0;
+  igraph_vector_t *inneis_1, *inneis_2, *outneis_1, *outneis_2;
+  long int matched_nodes=0;
+  long int depth;
+  long int cand1, cand2;
+  long int last1, last2;
+  igraph_stack_t path;
+  igraph_lazy_adjlist_t inadj1, inadj2, outadj1, outadj2;
+  igraph_vector_t indeg1, indeg2, outdeg1, outdeg2;
+
+  if (igraph_is_directed(graph1) != igraph_is_directed(graph2)) {
+    IGRAPH_ERROR("Cannot compare directed and undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+
+  if ( (vertex_color1 && !vertex_color2) || (!vertex_color1 && vertex_color2) ) {
+    IGRAPH_WARNING("Only one graph is vertex-colored, vertex colors will be ignored");
+    vertex_color1=vertex_color2=0;
+  }
+
+  if ( (edge_color1 && !edge_color2) || (!edge_color1 && edge_color2)) {
+    IGRAPH_WARNING("Only one graph is edge-colored, edge colors will be ignored");
+    edge_color1 = edge_color2 = 0;
+  }
+
+  if (vertex_color1) {
+    if (igraph_vector_int_size(vertex_color1) != no_of_nodes ||
+	igraph_vector_int_size(vertex_color2) != no_of_nodes) {
+      IGRAPH_ERROR("Invalid vertex color vector length", IGRAPH_EINVAL);
+    }
+  }
+
+  if (edge_color1) {
+    if (igraph_vector_int_size(edge_color1) != no_of_edges ||
+	igraph_vector_int_size(edge_color2) != no_of_edges) {
+      IGRAPH_ERROR("Invalid edge color vector length", IGRAPH_EINVAL);
+    }
+  }
+
+  if (no_of_nodes != igraph_vcount(graph2) ||
+      no_of_edges != igraph_ecount(graph2)) {
+    return 0;
+  }
+  
+  /* Check color distribution */
+  if (vertex_color1) {
+    int ret=0;
+    igraph_vector_int_t tmp1, tmp2;
+    IGRAPH_CHECK(igraph_vector_int_copy(&tmp1, vertex_color1));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &tmp1);
+    IGRAPH_CHECK(igraph_vector_int_copy(&tmp2, vertex_color2));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &tmp2);
+    igraph_vector_int_sort(&tmp1);
+    igraph_vector_int_sort(&tmp2);
+    ret= !igraph_vector_int_all_e(&tmp1, &tmp2);
+    igraph_vector_int_destroy(&tmp1);
+    igraph_vector_int_destroy(&tmp2);
+    IGRAPH_FINALLY_CLEAN(2);
+    if (ret) { return 0; }
+  }
+
+  /* Check edge color distribution */
+  if (edge_color1) {
+    int ret=0;
+    igraph_vector_int_t tmp1, tmp2;
+    IGRAPH_CHECK(igraph_vector_int_copy(&tmp1, edge_color1));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &tmp1);
+    IGRAPH_CHECK(igraph_vector_int_copy(&tmp2, edge_color2));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &tmp2);
+    igraph_vector_int_sort(&tmp1);
+    igraph_vector_int_sort(&tmp2);
+    ret= !igraph_vector_int_all_e(&tmp1, &tmp2);
+    igraph_vector_int_destroy(&tmp1);
+    igraph_vector_int_destroy(&tmp2);
+    IGRAPH_FINALLY_CLEAN(2);
+    if (ret) { return 0; }
+  }
+
+  if (map12) {
+    core_1=map12;
+    IGRAPH_CHECK(igraph_vector_resize(core_1, no_of_nodes));
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(core_1, no_of_nodes);
+  }
+  igraph_vector_fill(core_1, -1);
+  if (map21) {
+    core_2=map21;
+    IGRAPH_CHECK(igraph_vector_resize(core_2, no_of_nodes));
+    igraph_vector_null(core_2);
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(core_2, no_of_nodes);
+  }
+  igraph_vector_fill(core_2, -1);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&in_1, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&in_2, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&out_1, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&out_2, no_of_nodes);
+  IGRAPH_CHECK(igraph_stack_init(&path, 0));
+  IGRAPH_FINALLY(igraph_stack_destroy, &path);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph1, &inadj1, IGRAPH_IN, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &inadj1);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph1, &outadj1, IGRAPH_OUT, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &outadj1);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph2, &inadj2, IGRAPH_IN, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &inadj2);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph2, &outadj2, IGRAPH_OUT, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &outadj2);
+  IGRAPH_VECTOR_INIT_FINALLY(&indeg1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&indeg2, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdeg1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdeg2, 0);
+
+  IGRAPH_CHECK(igraph_stack_reserve(&path, no_of_nodes*2));
+  IGRAPH_CHECK(igraph_degree(graph1, &indeg1, igraph_vss_all(), 
+			     IGRAPH_IN, IGRAPH_LOOPS));
+  IGRAPH_CHECK(igraph_degree(graph2, &indeg2, igraph_vss_all(), 
+			     IGRAPH_IN, IGRAPH_LOOPS));
+  IGRAPH_CHECK(igraph_degree(graph1, &outdeg1, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS));
+  IGRAPH_CHECK(igraph_degree(graph2, &outdeg2, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS));
+
+  depth=0; last1=-1; last2=-1;
+  while (depth >= 0) {
+    long int i;
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    cand1=-1; cand2=-1;
+    /* Search for the next pair to try */
+    if ((in_1_size != in_2_size) ||
+	(out_1_size != out_2_size)) {
+      /* step back, nothing to do */
+    } else if (out_1_size > 0 && out_2_size > 0) {
+      /**************************************************************/
+      /* cand2, search not always needed */
+      if (last2 >= 0) {
+	cand2=last2;
+      } else {
+	i=0;
+	while (cand2<0 && i<no_of_nodes) {
+	  if (VECTOR(out_2)[i]>0 && VECTOR(*core_2)[i] < 0) {
+	    cand2=i;
+	  }
+	  i++;
+	}
+      }
+      /* search for cand1 now, it should be bigger than last1 */
+      i=last1+1;
+      while (cand1<0 && i<no_of_nodes) {
+	if (VECTOR(out_1)[i]>0 && VECTOR(*core_1)[i] < 0) {
+	  cand1=i;
+	}
+	i++;
+      }
+    } else if (in_1_size > 0 && in_2_size > 0) {
+      /**************************************************************/
+      /* cand2, search not always needed */
+      if (last2 >= 0) {
+	cand2=last2;
+      } else {
+	i=0;
+	while (cand2<0 && i<no_of_nodes) {
+	  if (VECTOR(in_2)[i]>0 && VECTOR(*core_2)[i] < 0) {
+	    cand2=i;
+	  }
+	  i++;
+	}
+      }
+      /* search for cand1 now, should be bigger than last1 */
+      i=last1+1;
+      while (cand1<0 && i<no_of_nodes) {
+	if (VECTOR(in_1)[i]>0 && VECTOR(*core_1)[i] < 0) {
+	  cand1=i;
+	}
+	i++;
+      }
+    } else {
+      /**************************************************************/
+      /* cand2, search not always needed */
+      if (last2 >= 0) {
+	cand2=last2;
+      } else {
+	i=0;
+	while (cand2<0 && i<no_of_nodes) {
+	  if (VECTOR(*core_2)[i] < 0) { 
+	    cand2=i;
+	  }
+	  i++;
+	}
+      }
+      /* search for cand1, should be bigger than last1 */
+      i=last1+1;
+      while (cand1<0 && i<no_of_nodes) {
+	if (VECTOR(*core_1)[i] < 0) {
+	  cand1=i;
+	}
+	i++;
+      }
+    }
+        
+    /* Ok, we have cand1, cand2 as candidates. Or not? */
+    if (cand1<0 || cand2<0) {
+      /**************************************************************/
+      /* dead end, step back, if possible. Otherwise we'll terminate */
+      if (depth >= 1) {
+	last2=(long int) igraph_stack_pop(&path);
+	last1=(long int) igraph_stack_pop(&path);
+	matched_nodes -= 1;
+	VECTOR(*core_1)[last1]=-1;
+	VECTOR(*core_2)[last2]=-1;
+	
+	if (VECTOR(in_1)[last1] != 0) {
+	  in_1_size += 1;
+	}
+	if (VECTOR(out_1)[last1] != 0) {
+	  out_1_size += 1;
+	}
+	if (VECTOR(in_2)[last2] != 0) {
+	  in_2_size += 1;
+	} 
+	if (VECTOR(out_2)[last2] != 0) {
+	  out_2_size += 1;
+	}
+	
+	inneis_1=igraph_lazy_adjlist_get(&inadj1, (igraph_integer_t) last1);
+	for (i=0; i<igraph_vector_size(inneis_1); i++) {
+	  long int node=(long int) VECTOR(*inneis_1)[i];
+	  if (VECTOR(in_1)[node] == depth) {
+	    VECTOR(in_1)[node]=0;
+	    in_1_size -= 1;
+	  }
+	}
+	outneis_1=igraph_lazy_adjlist_get(&outadj1, (igraph_integer_t) last1);
+	for (i=0; i<igraph_vector_size(outneis_1); i++) {
+	  long int node=(long int) VECTOR(*outneis_1)[i];
+	  if (VECTOR(out_1)[node] == depth) {
+	    VECTOR(out_1)[node]=0;
+	    out_1_size -= 1;
+	  }
+	}
+	inneis_2=igraph_lazy_adjlist_get(&inadj2, (igraph_integer_t) last2);
+	for (i=0; i<igraph_vector_size(inneis_2); i++) {
+	  long int node=(long int) VECTOR(*inneis_2)[i];
+	  if (VECTOR(in_2)[node] == depth) {
+	    VECTOR(in_2)[node]=0;
+	    in_2_size -= 1;
+	  }
+	}
+	outneis_2=igraph_lazy_adjlist_get(&outadj2, (igraph_integer_t) last2);
+	for (i=0; i<igraph_vector_size(outneis_2); i++) {
+	  long int node=(long int) VECTOR(*outneis_2)[i];
+	  if (VECTOR(out_2)[node] == depth) {
+	    VECTOR(out_2)[node]=0;
+	    out_2_size -= 1;
+	  }
+	}
+	
+      }	/* end of stepping back */
+      
+      depth -= 1;
+
+    } else {
+      /**************************************************************/
+      /* step forward if worth, check if worth first */
+      long int xin1=0, xin2=0, xout1=0, xout2=0;
+      igraph_bool_t end=0;
+      inneis_1=igraph_lazy_adjlist_get(&inadj1, (igraph_integer_t) cand1);
+      outneis_1=igraph_lazy_adjlist_get(&outadj1, (igraph_integer_t) cand1);
+      inneis_2=igraph_lazy_adjlist_get(&inadj2, (igraph_integer_t) cand2);
+      outneis_2=igraph_lazy_adjlist_get(&outadj2, (igraph_integer_t) cand2);
+      if (VECTOR(indeg1)[cand1] != VECTOR(indeg2)[cand2] ||
+	  VECTOR(outdeg1)[cand1] != VECTOR(outdeg2)[cand2]) {
+	end=1;
+      }
+      if (vertex_color1 && VECTOR(*vertex_color1)[cand1] != VECTOR(*vertex_color2)[cand2]) {
+	end=1;
+      }
+      if (node_compat_fn && !node_compat_fn(graph1, graph2, 
+					    (igraph_integer_t) cand1, 
+					    (igraph_integer_t) cand2, arg)) {
+	end=1;
+      }
+
+      for (i=0; !end && i<igraph_vector_size(inneis_1); i++) {
+	long int node=(long int) VECTOR(*inneis_1)[i];
+	if (VECTOR(*core_1)[node]>=0) {
+	  long int node2=(long int) VECTOR(*core_1)[node];
+	  /* check if there is a node2->cand2 edge */
+	  if (!igraph_vector_binsearch2(inneis_2, node2)) {
+	    end=1;
+	  } else if (edge_color1 || edge_compat_fn) {
+	    igraph_integer_t eid1, eid2;
+	    igraph_get_eid(graph1, &eid1, (igraph_integer_t) node, 
+			   (igraph_integer_t) cand1, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    igraph_get_eid(graph2, &eid2, (igraph_integer_t) node2, 
+			   (igraph_integer_t) cand2, /*directed=*/ 1,
+			   /*error=*/ 1);
+	    if (edge_color1 && VECTOR(*edge_color1)[(long int)eid1] !=
+		VECTOR(*edge_color2)[(long int)eid2]) {
+	      end=1;
+	    }
+	    if (edge_compat_fn && !edge_compat_fn(graph1, graph2,
+						  eid1, eid2, arg)) {
+	      end=1;
+	    }
+	  }
+	} else { 
+	  if (VECTOR(in_1)[node] != 0) {
+	    xin1++;
+	  }
+	  if (VECTOR(out_1)[node] != 0) {
+	    xout1++;
+	  }
+	}
+      }
+      for (i=0; !end && i<igraph_vector_size(outneis_1); i++) {
+	long int node=(long int) VECTOR(*outneis_1)[i];
+	if (VECTOR(*core_1)[node]>=0) {
+	  long int node2=(long int) VECTOR(*core_1)[node];
+	  /* check if there is a cand2->node2 edge */
+	  if (!igraph_vector_binsearch2(outneis_2, node2)) {
+	    end=1;
+	  } else if (edge_color1 || edge_compat_fn) {
+	    igraph_integer_t eid1, eid2;
+	    igraph_get_eid(graph1, &eid1, (igraph_integer_t) cand1, 
+			   (igraph_integer_t) node, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    igraph_get_eid(graph2, &eid2, (igraph_integer_t) cand2, 
+			   (igraph_integer_t) node2, /*directed=*/ 1,
+			   /*error=*/ 1);
+	    if (edge_color1 && VECTOR(*edge_color1)[(long int)eid1] != 
+		VECTOR(*edge_color2)[(long int)eid2]) {
+	      end=1;
+	    }
+	    if (edge_compat_fn && !edge_compat_fn(graph1, graph2, 
+						  eid1, eid2, arg)) {
+	      end=1;
+	    }
+	  }
+	} else {
+	  if (VECTOR(in_1)[node] != 0) {
+	    xin1++;
+	  }
+	  if (VECTOR(out_1)[node] != 0) {
+	    xout1++;
+	  }
+	}
+      }      
+      for (i=0; !end && i<igraph_vector_size(inneis_2); i++) {
+	long int node=(long int) VECTOR(*inneis_2)[i];
+	if (VECTOR(*core_2)[node]>=0) {
+	  long int node2=(long int) VECTOR(*core_2)[node];
+	  /* check if there is a node2->cand1 edge */
+	  if (!igraph_vector_binsearch2(inneis_1, node2)) {
+	    end=1;
+	  } else if (edge_color1 || edge_compat_fn) {
+	    igraph_integer_t eid1, eid2;
+	    igraph_get_eid(graph1, &eid1, (igraph_integer_t) node2, 
+			   (igraph_integer_t) cand1, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    igraph_get_eid(graph2, &eid2, (igraph_integer_t) node, 
+			   (igraph_integer_t) cand2, /*directed=*/ 1,
+			   /*error=*/ 1);
+	    if (edge_color1 && VECTOR(*edge_color1)[(long int)eid1] != 
+		VECTOR(*edge_color2)[(long int)eid2]) {
+	      end=1;
+	    }
+	    if (edge_compat_fn && !edge_compat_fn(graph1, graph2, 
+						  eid1, eid2, arg)) {
+	      end=1;
+	    }
+	  }
+	} else { 
+	  if (VECTOR(in_2)[node] != 0) {
+	    xin2++;
+	  }
+	  if (VECTOR(out_2)[node] != 0) {
+	    xout2++;
+	  }
+	}
+      }      
+      for (i=0; !end && i<igraph_vector_size(outneis_2); i++) {
+	long int node=(long int) VECTOR(*outneis_2)[i];
+	if (VECTOR(*core_2)[node] >= 0) {
+	  long int node2=(long int) VECTOR(*core_2)[node];
+	  /* check if there is a cand1->node2 edge */
+	  if (!igraph_vector_binsearch2(outneis_1, node2)) {
+	    end=1;
+	  } else if (edge_color1 || edge_compat_fn) {
+	    igraph_integer_t eid1, eid2;
+	    igraph_get_eid(graph1, &eid1, (igraph_integer_t) cand1, 
+			   (igraph_integer_t) node2, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    igraph_get_eid(graph2, &eid2, (igraph_integer_t) cand2, 
+			   (igraph_integer_t) node, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    if (edge_color1 && VECTOR(*edge_color1)[(long int)eid1] != 
+		VECTOR(*edge_color2)[(long int)eid2]) {
+	      end=1;
+	    }
+	    if (edge_compat_fn && !edge_compat_fn(graph1, graph2, 
+						  eid1, eid2, arg)) {
+	      end=1;
+	    }
+	  }
+	} else {
+	  if (VECTOR(in_2)[node] != 0) {
+	    xin2++;
+	  }
+	  if (VECTOR(out_2)[node] != 0) {
+	    xout2++;
+	  }
+	}
+      }      
+      
+      if (!end && (xin1==xin2 && xout1==xout2)) {
+	/* Ok, we add the (cand1, cand2) pair to the mapping */
+	depth += 1;
+	IGRAPH_CHECK(igraph_stack_push(&path, cand1));
+	IGRAPH_CHECK(igraph_stack_push(&path, cand2));
+	matched_nodes += 1;
+	VECTOR(*core_1)[cand1]=cand2;
+	VECTOR(*core_2)[cand2]=cand1;
+	
+	/* update in_*, out_* */
+	if (VECTOR(in_1)[cand1] != 0) {
+	  in_1_size -= 1;
+	}
+	if (VECTOR(out_1)[cand1] != 0) {
+	  out_1_size -= 1;
+	}
+	if (VECTOR(in_2)[cand2] != 0) {
+	  in_2_size -= 1;
+	}
+	if (VECTOR(out_2)[cand2] != 0) {
+	  out_2_size -= 1;
+	}
+	
+	inneis_1=igraph_lazy_adjlist_get(&inadj1, (igraph_integer_t) cand1);
+	for (i=0; i<igraph_vector_size(inneis_1); i++) {
+	  long int node=(long int) VECTOR(*inneis_1)[i];
+	  if (VECTOR(in_1)[node]==0 && VECTOR(*core_1)[node] < 0) {
+	    VECTOR(in_1)[node]=depth;
+	    in_1_size += 1;
+	  }
+	}
+	outneis_1=igraph_lazy_adjlist_get(&outadj1, (igraph_integer_t) cand1);
+	for (i=0; i<igraph_vector_size(outneis_1); i++) {
+	  long int node=(long int) VECTOR(*outneis_1)[i];
+	  if (VECTOR(out_1)[node]==0 && VECTOR(*core_1)[node] < 0) {
+	    VECTOR(out_1)[node]=depth;
+	    out_1_size += 1;
+	  }
+	}
+	inneis_2=igraph_lazy_adjlist_get(&inadj2, (igraph_integer_t) cand2);
+	for (i=0; i<igraph_vector_size(inneis_2); i++) {
+	  long int node=(long int) VECTOR(*inneis_2)[i];
+	  if (VECTOR(in_2)[node]==0 && VECTOR(*core_2)[node] < 0) {
+	    VECTOR(in_2)[node]=depth;
+	    in_2_size += 1;
+	  }
+	}
+	outneis_2=igraph_lazy_adjlist_get(&outadj2, (igraph_integer_t) cand2);
+	for (i=0; i<igraph_vector_size(outneis_2); i++) {
+	  long int node=(long int) VECTOR(*outneis_2)[i];
+	  if (VECTOR(out_2)[node]==0 && VECTOR(*core_2)[node] < 0) {
+	    VECTOR(out_2)[node]=depth;
+	    out_2_size += 1;
+	  }
+	}
+	last1=-1; last2=-1;    	      /* this the first time here */
+      } else {
+	last1=cand1;
+	last2=cand2;
+      }
+      
+    }
+    
+    if (matched_nodes==no_of_nodes && isohandler_fn) {
+      if (!isohandler_fn(core_1, core_2, arg)) {
+	break;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&outdeg2);
+  igraph_vector_destroy(&outdeg1);
+  igraph_vector_destroy(&indeg2);
+  igraph_vector_destroy(&indeg1);
+  igraph_lazy_adjlist_destroy(&outadj2);
+  igraph_lazy_adjlist_destroy(&inadj2);
+  igraph_lazy_adjlist_destroy(&outadj1);
+  igraph_lazy_adjlist_destroy(&inadj1);  
+  igraph_stack_destroy(&path);
+  igraph_vector_destroy(&out_2);
+  igraph_vector_destroy(&out_1);
+  igraph_vector_destroy(&in_2);
+  igraph_vector_destroy(&in_1);
+  IGRAPH_FINALLY_CLEAN(13);
+  if (!map21) {
+    igraph_vector_destroy(core_2);
+    IGRAPH_FINALLY_CLEAN(1);
+  } 
+  if (!map12) { 
+    igraph_vector_destroy(core_1);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+typedef struct {
+  igraph_isocompat_t *node_compat_fn, *edge_compat_fn;
+  void *arg, *carg;
+} igraph_i_iso_cb_data_t;
+
+igraph_bool_t igraph_i_isocompat_node_cb(const igraph_t *graph1, 
+					 const igraph_t *graph2, 
+					 const igraph_integer_t g1_num,
+					 const igraph_integer_t g2_num,
+					 void *arg) {
+  igraph_i_iso_cb_data_t *data=arg;
+  return data->node_compat_fn(graph1, graph2, g1_num, g2_num, data->carg);
+}
+
+igraph_bool_t igraph_i_isocompat_edge_cb(const igraph_t *graph1, 
+					 const igraph_t *graph2,
+					 const igraph_integer_t g1_num,
+					 const igraph_integer_t g2_num,
+					 void *arg) {
+  igraph_i_iso_cb_data_t *data=arg;
+  return data->edge_compat_fn(graph1, graph2, g1_num, g2_num, data->carg);
+}
+
+igraph_bool_t igraph_i_isomorphic_vf2(igraph_vector_t *map12,
+				      igraph_vector_t *map21,
+				      void *arg) {
+  igraph_i_iso_cb_data_t *data = arg;
+  igraph_bool_t *iso = data->arg;
+  IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21);
+  *iso = 1;
+  return 0;			/* don't need to continue */
+}
+
+/**
+ * \function igraph_isomorphic_vf2
+ * \brief Isomorphism via VF2
+ * 
+ * </para><para>
+ * This function performs the VF2 algorithm via calling \ref
+ * igraph_isomorphic_function_vf2().
+ * 
+ * </para><para> Note that this function cannot be used for
+ * deciding subgraph isomorphism, use \ref igraph_subisomorphic_vf2()
+ * for that.
+ * \param graph1 The first graph, may be directed or undirected.
+ * \param graph2 The second graph. It must have the same directedness
+ *    as \p graph1, otherwise an error is reported.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param iso Pointer to a logical constant, the result of the
+ *    algorithm will be placed here.
+ * \param map12 Pointer to an initialized vector or a NULL pointer. If not 
+ *    a NULL pointer then the mapping from \p graph1 to \p graph2 is
+ *    stored here. If the graphs are not isomorphic then the vector is
+ *    cleared (ie. has zero elements).
+ * \param map21 Pointer to an initialized vector or a NULL pointer. If not
+ *    a NULL pointer then the mapping from \p graph2 to \p graph1 is
+ *    stored here. If the graphs are not isomorphic then the vector is
+ *    cleared (ie. has zero elements).
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p node_compat_fn
+ *   and \p edge_compat_fn. 
+ * \return Error code.
+ * 
+ * \sa \ref igraph_subisomorphic_vf2(),
+ * \ref igraph_count_isomorphisms_vf2(), 
+ * \ref igraph_get_isomorphisms_vf2(),
+ * 
+ * Time complexity: exponential, what did you expect?
+ * 
+ * \example examples/simple/igraph_isomorphic_vf2.c
+ */
+
+int igraph_isomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+			  const igraph_vector_int_t *vertex_color1,
+			  const igraph_vector_int_t *vertex_color2,
+			  const igraph_vector_int_t *edge_color1,
+			  const igraph_vector_int_t *edge_color2,
+			  igraph_bool_t *iso, igraph_vector_t *map12, 
+			  igraph_vector_t *map21,
+			  igraph_isocompat_t *node_compat_fn,
+			  igraph_isocompat_t *edge_compat_fn,
+			  void *arg) {
+
+  igraph_i_iso_cb_data_t data = { node_compat_fn, edge_compat_fn, iso, arg };
+  igraph_isocompat_t *ncb = node_compat_fn ? igraph_i_isocompat_node_cb : 0;
+  igraph_isocompat_t *ecb = edge_compat_fn ? igraph_i_isocompat_edge_cb : 0;
+  *iso=0;
+  IGRAPH_CHECK(igraph_isomorphic_function_vf2(graph1, graph2, 
+					      vertex_color1, vertex_color2,
+					      edge_color1, edge_color2,
+					      map12, map21,
+					      (igraph_isohandler_t*)
+					      igraph_i_isomorphic_vf2,
+					      ncb, ecb, &data));
+  if (! *iso) {
+    if (map12) { igraph_vector_clear(map12); }
+    if (map21) { igraph_vector_clear(map21); }
+  }
+  return 0;
+}
+
+igraph_bool_t igraph_i_count_isomorphisms_vf2(const igraph_vector_t *map12,
+					      const igraph_vector_t *map21,
+					      void *arg) {
+  igraph_i_iso_cb_data_t *data = arg;
+  igraph_integer_t *count = data->arg;
+  IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21);
+  *count += 1;
+  return 1;			/* always continue */
+}
+
+/**
+ * \function igraph_count_isomorphisms_vf2
+ * Number of isomorphisms via VF2
+ * 
+ * This function counts the number of isomorphic mappings between two
+ * graphs. It uses the generic \ref igraph_isomorphic_function_vf2()
+ * function. 
+ * \param graph1 The first input graph, may be directed or undirected.
+ * \param graph2 The second input graph, it must have the same
+ *   directedness as \p graph1, or an error will be reported.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param count Point to an integer, the result will be stored here.
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p node_compat_fn and
+ *   \p edge_compat_fn.
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+
+int igraph_count_isomorphisms_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+				  const igraph_vector_int_t *vertex_color1,
+				  const igraph_vector_int_t *vertex_color2,
+				  const igraph_vector_int_t *edge_color1,
+				  const igraph_vector_int_t *edge_color2,
+				  igraph_integer_t *count,
+				  igraph_isocompat_t *node_compat_fn,
+				  igraph_isocompat_t *edge_compat_fn,
+				  void *arg) {
+
+  igraph_i_iso_cb_data_t data = { node_compat_fn, edge_compat_fn, 
+				  count, arg };
+  igraph_isocompat_t *ncb = node_compat_fn ? igraph_i_isocompat_node_cb : 0;
+  igraph_isocompat_t *ecb = edge_compat_fn ? igraph_i_isocompat_edge_cb : 0;
+  *count=0;
+  IGRAPH_CHECK(igraph_isomorphic_function_vf2(graph1, graph2, 
+					      vertex_color1, vertex_color2, 
+					      edge_color1, edge_color2,
+					      0, 0,
+					      (igraph_isohandler_t*)
+					      igraph_i_count_isomorphisms_vf2,
+					      ncb, ecb, &data));
+  return 0;
+}
+
+void igraph_i_get_isomorphisms_free(igraph_vector_ptr_t *data) {
+  long int i, n=igraph_vector_ptr_size(data);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *vec=VECTOR(*data)[i];
+    igraph_vector_destroy(vec);
+    igraph_free(vec);
+  }
+}
+
+igraph_bool_t igraph_i_get_isomorphisms_vf2(const igraph_vector_t *map12,
+					    const igraph_vector_t *map21,
+					    void *arg) {
+
+  igraph_i_iso_cb_data_t *data=arg;
+  igraph_vector_ptr_t *ptrvector=data->arg;
+  igraph_vector_t *newvector=igraph_Calloc(1, igraph_vector_t);
+  IGRAPH_UNUSED(map12);
+  if (!newvector) { 
+    igraph_error("Out of memory", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;			/* stop right here */
+  }
+  IGRAPH_FINALLY(igraph_free, newvector);
+  IGRAPH_CHECK(igraph_vector_copy(newvector, map21));
+  IGRAPH_FINALLY(igraph_vector_destroy, newvector);
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(ptrvector, newvector));
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 1;			/* continue finding subisomorphisms */
+}
+
+/** 
+ * \function igraph_get_isomorphisms_vf2
+ * Collect the isomorphic mappings
+ * 
+ * This function finds all the isomorphic mappings between two
+ * graphs. It uses the \ref igraph_isomorphic_function_vf2()
+ * function. Call the function with the same graph as \p graph1 and \p
+ * graph2 to get automorphisms.
+ * \param graph1 The first input graph, may be directed or undirected.
+ * \param graph2 The second input graph, it must have the same
+ *   directedness as \p graph1, or an error will be reported.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param maps Pointer vector. On return it is empty if the input graphs
+ *   are no isomorphic. Otherwise it contains pointers to
+ *   <type>igraph_vector_t</type> objects, each vector is an
+ *   isomorphic mapping of \p graph2 to \p graph1. Please note that
+ *   you need to 1) Destroy the vectors via \ref
+ *   igraph_vector_destroy(), 2) free them via
+ *   <function>free()</function> and then 3) call \ref
+ *   igraph_vector_ptr_destroy() on the pointer vector to deallocate all
+ *   memory when \p maps is no longer needed.
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p node_compat_fn
+ *   and \p edge_compat_fn. 
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+ 
+int igraph_get_isomorphisms_vf2(const igraph_t *graph1,
+				const igraph_t *graph2,
+				const igraph_vector_int_t *vertex_color1,
+				const igraph_vector_int_t *vertex_color2,
+				const igraph_vector_int_t *edge_color1,
+				const igraph_vector_int_t *edge_color2,
+				igraph_vector_ptr_t *maps,
+				igraph_isocompat_t *node_compat_fn,
+				igraph_isocompat_t *edge_compat_fn,
+				void *arg) {
+  
+  igraph_i_iso_cb_data_t data = { node_compat_fn, edge_compat_fn, maps, arg };
+  igraph_isocompat_t *ncb = node_compat_fn ? igraph_i_isocompat_node_cb : 0;
+  igraph_isocompat_t *ecb = edge_compat_fn ? igraph_i_isocompat_edge_cb : 0;
+
+  igraph_vector_ptr_clear(maps);
+  IGRAPH_FINALLY(igraph_i_get_isomorphisms_free, maps);
+  IGRAPH_CHECK(igraph_isomorphic_function_vf2(graph1, graph2, 
+					      vertex_color1, vertex_color2, 
+					      edge_color1, edge_color2,
+					      0, 0,
+					      (igraph_isohandler_t*)
+					      igraph_i_get_isomorphisms_vf2,
+					      ncb, ecb, &data));
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+
+/**
+ * \function igraph_subisomorphic
+ * Decide subgraph isomorphism
+ * 
+ * Check whether \p graph2 is isomorphic to a subgraph of \p graph1.
+ * Currently this function just calls \ref igraph_subisomorphic_vf2()
+ * for all graphs.
+ * \param graph1 The first input graph, may be directed or
+ *   undirected. This is supposed to be the bigger graph.
+ * \param graph2 The second input graph, it must have the same
+ *   directedness as \p graph2, or an error is triggered. This is
+ *   supposed to be the smaller graph.
+ * \param iso Pointer to a boolean, the result is stored here.
+ * \return Error code.
+ *
+ * Time complexity: exponential. 
+ */
+
+int igraph_subisomorphic(const igraph_t *graph1, const igraph_t *graph2,
+			 igraph_bool_t *iso) {
+
+  return igraph_subisomorphic_vf2(graph1, graph2, 0, 0, 0, 0, iso, 0, 0, 0, 0, 0);
+}
+
+/**
+ * \function igraph_subisomorphic_function_vf2
+ * Generic VF2 function for subgraph isomorphism problems
+ * 
+ * This function is the pair of \ref igraph_isomorphic_function_vf2(),
+ * for subgraph isomorphism problems. It searches for subgraphs of \p
+ * graph1 which are isomorphic to \p graph2. When it founds an
+ * isomorphic mapping it calls the supplied callback \p isohandler_fn.
+ * The mapping (and its inverse) and the additional \p arg argument
+ * are supplied to the callback.
+ * \param graph1 The first input graph, may be directed or
+ *    undirected. This is supposed to be the larger graph.
+ * \param graph2 The second input graph, it must have the same
+ *    directedness as \p graph1. This is supposed to be the smaller
+ *    graph.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the subgraph isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param map12 Pointer to a vector or \c NULL. If not \c NULL, then an
+ *    isomorphic mapping from \p graph1 to \p graph2 is stored here.
+ * \param map21 Pointer to a vector ot \c NULL. If not \c NULL, then
+ *    an isomorphic mapping from \p graph2 to \p graph1 is stored
+ *    here.
+ * \param isohandler_fn A pointer to a function of type \ref
+ *   igraph_isohandler_t. This will be called whenever a subgraph
+ *   isomorphism is found. If the function returns with a non-zero value
+ *   then the search is continued, otherwise it stops and the function
+ *   returns. 
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p isohandler_fn, \p
+ *   node_compat_fn and \p edge_compat_fn.
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+
+int igraph_subisomorphic_function_vf2(const igraph_t *graph1, 
+				      const igraph_t *graph2,
+				      const igraph_vector_int_t *vertex_color1,
+				      const igraph_vector_int_t *vertex_color2,
+				      const igraph_vector_int_t *edge_color1,
+				      const igraph_vector_int_t *edge_color2,
+				      igraph_vector_t *map12,
+				      igraph_vector_t *map21,
+				      igraph_isohandler_t *isohandler_fn,
+				      igraph_isocompat_t *node_compat_fn,
+				      igraph_isocompat_t *edge_compat_fn,
+				      void *arg) {
+  
+  long int no_of_nodes1=igraph_vcount(graph1), 
+    no_of_nodes2=igraph_vcount(graph2);
+  long int no_of_edges1=igraph_ecount(graph1), 
+    no_of_edges2=igraph_ecount(graph2);
+  igraph_vector_t mycore_1, mycore_2, *core_1=&mycore_1, *core_2=&mycore_2;
+  igraph_vector_t in_1, in_2, out_1, out_2;
+  long int in_1_size=0, in_2_size=0, out_1_size=0, out_2_size=0;
+  igraph_vector_t *inneis_1, *inneis_2, *outneis_1, *outneis_2;
+  long int matched_nodes=0;
+  long int depth;
+  long int cand1, cand2;
+  long int last1, last2;
+  igraph_stack_t path;
+  igraph_lazy_adjlist_t inadj1, inadj2, outadj1, outadj2;
+  igraph_vector_t indeg1, indeg2, outdeg1, outdeg2;
+
+  if (igraph_is_directed(graph1) != igraph_is_directed(graph2)) {
+    IGRAPH_ERROR("Cannot compare directed and undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+
+  if (no_of_nodes1 < no_of_nodes2 || 
+      no_of_edges1 < no_of_edges2) {
+    return 0;
+  }
+
+  if ( (vertex_color1 && !vertex_color2) || (!vertex_color1 && vertex_color2) ) {
+    IGRAPH_WARNING("Only one graph is vertex colored, colors will be ignored");
+    vertex_color1=vertex_color2=0;
+  }
+
+  if ( (edge_color1 && !edge_color2) || (!edge_color1 && edge_color2) ) {
+    IGRAPH_WARNING("Only one graph is edge colored, colors will be ignored");
+    edge_color1=edge_color2=0;
+  }
+
+  if (vertex_color1) {
+    if (igraph_vector_int_size(vertex_color1) != no_of_nodes1 ||
+	igraph_vector_int_size(vertex_color2) != no_of_nodes2) {
+      IGRAPH_ERROR("Invalid vertex color vector length", IGRAPH_EINVAL);
+    }
+  }
+
+  if (edge_color1) {
+    if (igraph_vector_int_size(edge_color1) != no_of_edges1 ||
+	igraph_vector_int_size(edge_color2) != no_of_edges2) {
+      IGRAPH_ERROR("Invalid edge color vector length", IGRAPH_EINVAL);
+    }
+  }
+
+  /* Check color distribution */
+  if (vertex_color1) {
+    /* TODO */
+  }
+
+  /* Check edge color distribution */
+  if (edge_color1) {
+    /* TODO */
+  }
+
+  if (map12) {
+    core_1=map12;
+    IGRAPH_CHECK(igraph_vector_resize(core_1, no_of_nodes1));
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(core_1, no_of_nodes1);
+  }
+  igraph_vector_fill(core_1, -1);
+  if (map21) {
+    core_2=map21;
+    IGRAPH_CHECK(igraph_vector_resize(core_2, no_of_nodes2));
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(core_2, no_of_nodes2);
+  }
+  igraph_vector_fill(core_2, -1);
+  IGRAPH_VECTOR_INIT_FINALLY(&in_1, no_of_nodes1);
+  IGRAPH_VECTOR_INIT_FINALLY(&in_2, no_of_nodes2);
+  IGRAPH_VECTOR_INIT_FINALLY(&out_1, no_of_nodes1);
+  IGRAPH_VECTOR_INIT_FINALLY(&out_2, no_of_nodes2);
+  IGRAPH_CHECK(igraph_stack_init(&path, 0));
+  IGRAPH_FINALLY(igraph_stack_destroy, &path);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph1, &inadj1, IGRAPH_IN, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &inadj1);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph1, &outadj1, IGRAPH_OUT, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &outadj1);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph2, &inadj2, IGRAPH_IN, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &inadj2);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph2, &outadj2, IGRAPH_OUT, 
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &outadj2);
+  IGRAPH_VECTOR_INIT_FINALLY(&indeg1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&indeg2, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdeg1, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&outdeg2, 0);
+
+  IGRAPH_CHECK(igraph_stack_reserve(&path, no_of_nodes2*2));
+  IGRAPH_CHECK(igraph_degree(graph1, &indeg1, igraph_vss_all(), 
+			     IGRAPH_IN, IGRAPH_LOOPS));
+  IGRAPH_CHECK(igraph_degree(graph2, &indeg2, igraph_vss_all(), 
+			     IGRAPH_IN, IGRAPH_LOOPS));
+  IGRAPH_CHECK(igraph_degree(graph1, &outdeg1, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS));
+  IGRAPH_CHECK(igraph_degree(graph2, &outdeg2, igraph_vss_all(), 
+			     IGRAPH_OUT, IGRAPH_LOOPS));
+
+  depth=0; last1=-1; last2=-1;
+  while (depth >= 0) {
+    long int i;
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    cand1=-1; cand2=-1;
+    /* Search for the next pair to try */
+    if ((in_1_size < in_2_size) ||
+	(out_1_size < out_2_size)) {
+      /* step back, nothing to do */
+    } else if (out_1_size > 0 && out_2_size > 0) {
+      /**************************************************************/
+      /* cand2, search not always needed */
+      if (last2 >= 0) {
+	cand2=last2;
+      } else {
+	i=0;
+	while (cand2<0 && i<no_of_nodes2) {
+	  if (VECTOR(out_2)[i]>0 && VECTOR(*core_2)[i] < 0) {
+	    cand2=i;
+	  }
+	  i++;
+	}
+      }
+      /* search for cand1 now, it should be bigger than last1 */
+      i=last1+1;
+      while (cand1<0 && i<no_of_nodes1) {
+	if (VECTOR(out_1)[i]>0 && VECTOR(*core_1)[i] < 0) {
+	  cand1=i;
+	}
+	i++;
+      }
+    } else if (in_1_size > 0 && in_2_size > 0) {
+      /**************************************************************/
+      /* cand2, search not always needed */
+      if (last2 >= 0) {
+	cand2=last2;
+      } else {
+	i=0;
+	while (cand2<0 && i<no_of_nodes2) {
+	  if (VECTOR(in_2)[i]>0 && VECTOR(*core_2)[i] < 0) {
+	    cand2=i;
+	  }
+	  i++;
+	}
+      }
+      /* search for cand1 now, should be bigger than last1 */
+      i=last1+1;
+      while (cand1<0 && i<no_of_nodes1) {
+	if (VECTOR(in_1)[i]>0 && VECTOR(*core_1)[i] < 0) {
+	  cand1=i;
+	}
+	i++;
+      }
+    } else {
+      /**************************************************************/
+      /* cand2, search not always needed */
+      if (last2 >= 0) {
+	cand2=last2;
+      } else {
+	i=0;
+	while (cand2<0 && i<no_of_nodes2) {
+	  if (VECTOR(*core_2)[i] < 0) { 
+	    cand2=i;
+	  }
+	  i++;
+	}
+      }
+      /* search for cand1, should be bigger than last1 */
+      i=last1+1;
+      while (cand1<0 && i<no_of_nodes1) {
+	if (VECTOR(*core_1)[i] < 0) {
+	  cand1=i;
+	}
+	i++;
+      }
+    }
+        
+    /* Ok, we have cand1, cand2 as candidates. Or not? */
+    if (cand1<0 || cand2<0) {
+      /**************************************************************/
+      /* dead end, step back, if possible. Otherwise we'll terminate */
+      if (depth >= 1) {
+	last2=(long int) igraph_stack_pop(&path);
+	last1=(long int) igraph_stack_pop(&path);
+	matched_nodes -= 1;
+	VECTOR(*core_1)[last1]=-1;
+	VECTOR(*core_2)[last2]=-1;
+
+	if (VECTOR(in_1)[last1] != 0) {
+	  in_1_size += 1;
+	}
+	if (VECTOR(out_1)[last1] != 0) {
+	  out_1_size += 1;
+	}
+	if (VECTOR(in_2)[last2] != 0) {
+	  in_2_size += 1;
+	} 
+	if (VECTOR(out_2)[last2] != 0) {
+	  out_2_size += 1;
+	}
+	
+	inneis_1=igraph_lazy_adjlist_get(&inadj1, (igraph_integer_t) last1);
+	for (i=0; i<igraph_vector_size(inneis_1); i++) {
+	  long int node=(long int) VECTOR(*inneis_1)[i];
+	  if (VECTOR(in_1)[node] == depth) {
+	    VECTOR(in_1)[node]=0;
+	    in_1_size -= 1;
+	  }
+	}
+	outneis_1=igraph_lazy_adjlist_get(&outadj1, (igraph_integer_t) last1);
+	for (i=0; i<igraph_vector_size(outneis_1); i++) {
+	  long int node=(long int) VECTOR(*outneis_1)[i];
+	  if (VECTOR(out_1)[node] == depth) {
+	    VECTOR(out_1)[node]=0;
+	    out_1_size -= 1;
+	  }
+	}
+	inneis_2=igraph_lazy_adjlist_get(&inadj2, (igraph_integer_t) last2);
+	for (i=0; i<igraph_vector_size(inneis_2); i++) {
+	  long int node=(long int) VECTOR(*inneis_2)[i];
+	  if (VECTOR(in_2)[node] == depth) {
+	    VECTOR(in_2)[node]=0;
+	    in_2_size -= 1;
+	  }
+	}
+	outneis_2=igraph_lazy_adjlist_get(&outadj2, (igraph_integer_t) last2);
+	for (i=0; i<igraph_vector_size(outneis_2); i++) {
+	  long int node=(long int) VECTOR(*outneis_2)[i];
+	  if (VECTOR(out_2)[node] == depth) {
+	    VECTOR(out_2)[node]=0;
+	    out_2_size -= 1;
+	  }
+	}
+	
+      }	/* end of stepping back */
+      
+      depth -= 1;
+
+    } else {
+      /**************************************************************/
+      /* step forward if worth, check if worth first */
+      long int xin1=0, xin2=0, xout1=0, xout2=0;
+      igraph_bool_t end=0;
+      inneis_1=igraph_lazy_adjlist_get(&inadj1, (igraph_integer_t) cand1);
+      outneis_1=igraph_lazy_adjlist_get(&outadj1, (igraph_integer_t) cand1);
+      inneis_2=igraph_lazy_adjlist_get(&inadj2, (igraph_integer_t) cand2);
+      outneis_2=igraph_lazy_adjlist_get(&outadj2, (igraph_integer_t) cand2);
+      if (VECTOR(indeg1)[cand1] < VECTOR(indeg2)[cand2] ||
+	  VECTOR(outdeg1)[cand1] < VECTOR(outdeg2)[cand2]) {
+	end=1;
+      }
+      if (vertex_color1 && VECTOR(*vertex_color1)[cand1] != VECTOR(*vertex_color2)[cand2]) {
+	end=1;
+      }
+      if (node_compat_fn && !node_compat_fn(graph1, graph2, 
+					    (igraph_integer_t) cand1,
+					    (igraph_integer_t) cand2, arg)) {
+	end=1;
+      }
+
+      for (i=0; !end && i<igraph_vector_size(inneis_1); i++) {
+	long int node=(long int) VECTOR(*inneis_1)[i];
+	if (VECTOR(*core_1)[node] < 0) {
+	  if (VECTOR(in_1)[node] != 0) {
+	    xin1++;
+	  }
+	  if (VECTOR(out_1)[node] != 0) {
+	    xout1++;
+	  }
+	}
+      }
+      for (i=0; !end && i<igraph_vector_size(outneis_1); i++) {
+	long int node=(long int) VECTOR(*outneis_1)[i];
+	if (VECTOR(*core_1)[node] < 0) {
+	  if (VECTOR(in_1)[node] != 0) {
+	    xin1++;
+	  }
+	  if (VECTOR(out_1)[node] != 0) {
+	    xout1++;
+	  }
+	}
+      }      
+      for (i=0; !end && i<igraph_vector_size(inneis_2); i++) {
+	long int node=(long int) VECTOR(*inneis_2)[i];
+	if (VECTOR(*core_2)[node] >= 0) {
+	  long int node2=(long int) VECTOR(*core_2)[node];
+	  /* check if there is a node2->cand1 edge */
+	  if (!igraph_vector_binsearch2(inneis_1, node2)) {
+	    end=1;
+	  } else if (edge_color1 || edge_compat_fn) {
+	    igraph_integer_t eid1, eid2;
+	    igraph_get_eid(graph1, &eid1, (igraph_integer_t) node2, 
+			   (igraph_integer_t) cand1, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    igraph_get_eid(graph2, &eid2, (igraph_integer_t) node, 
+			   (igraph_integer_t) cand2, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    if (edge_color1 && VECTOR(*edge_color1)[(long int)eid1] != 
+		VECTOR(*edge_color2)[(long int)eid2]) {
+	      end=1;
+	    }
+	    if (edge_compat_fn && !edge_compat_fn(graph1, graph2, 
+						  eid1, eid2, arg)) {
+	      end=1;
+	    }
+	  }
+	} else { 
+	  if (VECTOR(in_2)[node] != 0) {
+	    xin2++;
+	  }
+	  if (VECTOR(out_2)[node] != 0) {
+	    xout2++;
+	  }
+	}
+      }      
+      for (i=0; !end && i<igraph_vector_size(outneis_2); i++) {
+	long int node=(long int) VECTOR(*outneis_2)[i];
+	if (VECTOR(*core_2)[node] >= 0) {
+	  long int node2=(long int) VECTOR(*core_2)[node];
+	  /* check if there is a cand1->node2 edge */
+	  if (!igraph_vector_binsearch2(outneis_1, node2)) {
+	    end=1;
+	  } else if (edge_color1 || edge_compat_fn) {
+	    igraph_integer_t eid1, eid2;
+	    igraph_get_eid(graph1, &eid1, (igraph_integer_t) cand1, 
+			   (igraph_integer_t) node2, /*directed=*/ 1, 
+			   /*error=*/ 1);
+	    igraph_get_eid(graph2, &eid2, (igraph_integer_t) cand2, 
+			   (igraph_integer_t) node, /*directed=*/ 1,
+			   /*error=*/ 1);
+	    if (edge_color1 && VECTOR(*edge_color1)[(long int)eid1] != 
+		VECTOR(*edge_color2)[(long int)eid2]) {
+	      end=1;
+	    }
+	    if (edge_compat_fn && !edge_compat_fn(graph1, graph2, 
+						  eid1, eid2, arg)) {
+	      end=1;
+	    }
+	  }
+	} else {
+	  if (VECTOR(in_2)[node] != 0) {
+	    xin2++;
+	  }
+	  if (VECTOR(out_2)[node] != 0) {
+	    xout2++;
+	  }
+	}
+      }      
+      
+      if (!end && (xin1>=xin2 && xout1>=xout2)) {
+	/* Ok, we add the (cand1, cand2) pair to the mapping */
+	depth += 1;
+	IGRAPH_CHECK(igraph_stack_push(&path, cand1));
+	IGRAPH_CHECK(igraph_stack_push(&path, cand2));
+	matched_nodes += 1;
+	VECTOR(*core_1)[cand1]=cand2;
+	VECTOR(*core_2)[cand2]=cand1;
+	
+	/* update in_*, out_* */
+	if (VECTOR(in_1)[cand1] != 0) {
+	  in_1_size -= 1;
+	}
+	if (VECTOR(out_1)[cand1] != 0) {
+	  out_1_size -= 1;
+	}
+	if (VECTOR(in_2)[cand2] != 0) {
+	  in_2_size -= 1;
+	}
+	if (VECTOR(out_2)[cand2] != 0) {
+	  out_2_size -= 1;
+	}
+	
+	inneis_1=igraph_lazy_adjlist_get(&inadj1, (igraph_integer_t) cand1);
+	for (i=0; i<igraph_vector_size(inneis_1); i++) {
+	  long int node=(long int) VECTOR(*inneis_1)[i];
+	  if (VECTOR(in_1)[node]==0 && VECTOR(*core_1)[node] < 0) {
+	    VECTOR(in_1)[node]=depth;
+	    in_1_size += 1;
+	  }
+	}
+	outneis_1=igraph_lazy_adjlist_get(&outadj1, (igraph_integer_t) cand1);
+	for (i=0; i<igraph_vector_size(outneis_1); i++) {
+	  long int node=(long int) VECTOR(*outneis_1)[i];
+	  if (VECTOR(out_1)[node]==0 && VECTOR(*core_1)[node] < 0) {
+	    VECTOR(out_1)[node]=depth;
+	    out_1_size += 1;
+	  }
+	}
+	inneis_2=igraph_lazy_adjlist_get(&inadj2, (igraph_integer_t) cand2);
+	for (i=0; i<igraph_vector_size(inneis_2); i++) {
+	  long int node=(long int) VECTOR(*inneis_2)[i];
+	  if (VECTOR(in_2)[node]==0 && VECTOR(*core_2)[node] < 0) {
+	    VECTOR(in_2)[node]=depth;
+	    in_2_size += 1;
+	  }
+	}
+	outneis_2=igraph_lazy_adjlist_get(&outadj2, (igraph_integer_t) cand2);
+	for (i=0; i<igraph_vector_size(outneis_2); i++) {
+	  long int node=(long int) VECTOR(*outneis_2)[i];
+	  if (VECTOR(out_2)[node]==0 && VECTOR(*core_2)[node] < 0) {
+	    VECTOR(out_2)[node]=depth;
+	    out_2_size += 1;
+	  }
+	}
+	last1=-1; last2=-1;    	      /* this the first time here */
+      } else {
+	last1=cand1;
+	last2=cand2;
+      }
+      
+    }
+
+    if (matched_nodes==no_of_nodes2 && isohandler_fn) { 
+      if (!isohandler_fn(core_1, core_2, arg)) {
+	break;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&outdeg2);
+  igraph_vector_destroy(&outdeg1);
+  igraph_vector_destroy(&indeg2);
+  igraph_vector_destroy(&indeg1);
+  igraph_lazy_adjlist_destroy(&outadj2);
+  igraph_lazy_adjlist_destroy(&inadj2);
+  igraph_lazy_adjlist_destroy(&outadj1);
+  igraph_lazy_adjlist_destroy(&inadj1);  
+  igraph_stack_destroy(&path);
+  igraph_vector_destroy(&out_2);
+  igraph_vector_destroy(&out_1);
+  igraph_vector_destroy(&in_2);
+  igraph_vector_destroy(&in_1);
+  IGRAPH_FINALLY_CLEAN(13);
+  if (!map21) { 
+    igraph_vector_destroy(core_2);
+    IGRAPH_FINALLY_CLEAN(1);
+  }    
+  if (!map12) {
+    igraph_vector_destroy(core_1);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+igraph_bool_t igraph_i_subisomorphic_vf2(const igraph_vector_t *map12,
+					 const igraph_vector_t *map21,
+					 void *arg) {
+  igraph_i_iso_cb_data_t *data = arg;
+  igraph_bool_t *iso = data->arg;
+  IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21);
+  *iso=1;
+  return 0; /* stop */
+}
+
+/**
+ * \function igraph_subisomorphic_vf2
+ * Decide subgraph isomorphism using VF2
+ * 
+ * Decides whether a subgraph of \p graph1 is isomorphic to \p
+ * graph2. It uses \ref igraph_subisomorphic_function_vf2().
+ * \param graph1 The first input graph, may be directed or
+ *    undirected. This is supposed to be the larger graph.
+ * \param graph2 The second input graph, it must have the same
+ *    directedness as \p graph1. This is supposed to be the smaller
+ *    graph.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the subgraph isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param iso Pointer to a boolean. The result of the decision problem
+ *    is stored here.
+ * \param map12 Pointer to a vector or \c NULL. If not \c NULL, then an
+ *    isomorphic mapping from \p graph1 to \p graph2 is stored here.
+ * \param map21 Pointer to a vector ot \c NULL. If not \c NULL, then
+ *    an isomorphic mapping from \p graph2 to \p graph1 is stored
+ *    here.
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p node_compat_fn 
+ *   and \p edge_compat_fn. 
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+
+int igraph_subisomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+			     const igraph_vector_int_t *vertex_color1,
+			     const igraph_vector_int_t *vertex_color2,
+			     const igraph_vector_int_t *edge_color1,
+			     const igraph_vector_int_t *edge_color2,
+			     igraph_bool_t *iso, igraph_vector_t *map12, 
+			     igraph_vector_t *map21,
+			     igraph_isocompat_t *node_compat_fn,
+			     igraph_isocompat_t *edge_compat_fn,
+			     void *arg) {
+
+  igraph_i_iso_cb_data_t data = { node_compat_fn, edge_compat_fn, iso, arg };
+  igraph_isocompat_t *ncb = node_compat_fn ? igraph_i_isocompat_node_cb : 0;
+  igraph_isocompat_t *ecb = edge_compat_fn ? igraph_i_isocompat_edge_cb : 0;
+
+  *iso=0;
+  IGRAPH_CHECK(igraph_subisomorphic_function_vf2(graph1, graph2, 
+						 vertex_color1, vertex_color2,
+						 edge_color1, edge_color2,
+						 map12, map21,
+						 (igraph_isohandler_t *)
+						 igraph_i_subisomorphic_vf2,
+						 ncb, ecb, &data));
+  if (! *iso) {
+    if (map12) { igraph_vector_clear(map12); }
+    if (map21) { igraph_vector_clear(map21); }
+    }
+  return 0;
+}
+
+igraph_bool_t igraph_i_count_subisomorphisms_vf2(const igraph_vector_t *map12,
+						 const igraph_vector_t *map21,
+						 void *arg) {
+  igraph_i_iso_cb_data_t *data = arg;
+  igraph_integer_t *count = data->arg;
+  IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21);
+  *count += 1;
+  return 1;			/* always continue */
+}
+  
+/**
+ * \function igraph_count_subisomorphisms_vf2
+ * Number of subgraph isomorphisms using VF2
+ * 
+ * Count the number of isomorphisms between subgraphs of \p graph1 and
+ * \p graph2. This function uses \ref
+ * igraph_subisomorphic_function_vf2().
+ * \param graph1 The first input graph, may be directed or
+ *    undirected. This is supposed to be the larger graph.
+ * \param graph2 The second input graph, it must have the same
+ *    directedness as \p graph1. This is supposed to be the smaller
+ *    graph.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the subgraph isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param count Pointer to an integer. The number of subgraph
+ *    isomorphisms is stored here.
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p node_compat_fn and
+ *   \p edge_compat_fn. 
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+
+int igraph_count_subisomorphisms_vf2(const igraph_t *graph1, const igraph_t *graph2, 
+				     const igraph_vector_int_t *vertex_color1,
+				     const igraph_vector_int_t *vertex_color2,
+				     const igraph_vector_int_t *edge_color1,
+				     const igraph_vector_int_t *edge_color2,
+				     igraph_integer_t *count,
+				     igraph_isocompat_t *node_compat_fn,
+				     igraph_isocompat_t *edge_compat_fn,
+				     void *arg) {
+
+  igraph_i_iso_cb_data_t data = { node_compat_fn, edge_compat_fn, 
+				  count, arg };
+  igraph_isocompat_t *ncb = node_compat_fn ? igraph_i_isocompat_node_cb : 0;
+  igraph_isocompat_t *ecb = edge_compat_fn ? igraph_i_isocompat_edge_cb : 0;
+  *count=0;
+  IGRAPH_CHECK(igraph_subisomorphic_function_vf2(graph1, graph2, 
+					 vertex_color1, vertex_color2, 
+					 edge_color1, edge_color2,
+					 0, 0,
+					 (igraph_isohandler_t*)
+					 igraph_i_count_subisomorphisms_vf2,
+					 ncb, ecb, &data));
+    return 0;
+  }
+  
+void igraph_i_get_subisomorphisms_free(igraph_vector_ptr_t *data) {
+  long int i, n=igraph_vector_ptr_size(data);
+  for (i=0; i<n; i++) {
+    igraph_vector_t *vec=VECTOR(*data)[i];
+    igraph_vector_destroy(vec);
+    igraph_free(vec);
+  }
+}
+
+igraph_bool_t igraph_i_get_subisomorphisms_vf2(const igraph_vector_t *map12,
+					       const igraph_vector_t *map21,
+					       void *arg) {
+
+  igraph_i_iso_cb_data_t *data = arg;
+  igraph_vector_ptr_t *vector = data->arg;
+  igraph_vector_t *newvector=igraph_Calloc(1, igraph_vector_t);
+  IGRAPH_UNUSED(map12);
+  if (!newvector) { 
+    igraph_error("Out of memory", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    return 0;			/* stop right here */
+  }
+  IGRAPH_FINALLY(igraph_free, newvector);
+  IGRAPH_CHECK(igraph_vector_copy(newvector, map21));
+  IGRAPH_FINALLY(igraph_vector_destroy, newvector);
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(vector, newvector));
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 1;			/* continue finding subisomorphisms */
+}
+
+/** 
+ * \function igraph_get_subisomorphisms_vf2
+ * Return all subgraph isomorphic mappings
+ * 
+ * This function collects all isomorphic mappings of \p graph2 to a
+ * subgraph of \p graph1. It uses the \ref
+ * igraph_subisomorphic_function_vf2() function.
+ * \param graph1 The first input graph, may be directed or
+ *    undirected. This is supposed to be the larger graph.
+ * \param graph2 The second input graph, it must have the same
+ *    directedness as \p graph1. This is supposed to be the smaller
+ *    graph.
+ * \param vertex_color1 An optional color vector for the first graph. If
+ *   color vectors are given for both graphs, then the subgraph isomorphism is
+ *   calculated on the colored graphs; i.e. two vertices can match
+ *   only if their color also matches. Supply a null pointer here if
+ *   your graphs are not colored.
+ * \param vertex_color2 An optional color vector for the second graph. See
+ *   the previous argument for explanation.
+ * \param edge_color1 An optional edge color vector for the first
+ *   graph. The matching edges in the two graphs must have matching
+ *   colors as well. Supply a null pointer here if your graphs are not 
+ *   edge-colored.
+ * \param edge_color2 The edge color vector for the second graph.
+ * \param maps Pointer vector. On return it contains pointers to
+ *   <type>igraph_vector_t</type> objects, each vector is an
+ *   isomorphic mapping of \p graph2 to a subgraph of \p graph1. Please note that
+ *   you need to 1) Destroy the vectors via \ref
+ *   igraph_vector_destroy(), 2) free them via
+ *   <function>free()</function> and then 3) call \ref
+ *   igraph_vector_ptr_destroy() on the pointer vector to deallocate all
+ *   memory when \p maps is no longer needed.
+ * \param node_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two nodes are compatible.
+ * \param edge_compat_fn A pointer to a function of type \ref 
+ *   igraph_isocompat_t. This function will be called by the algorithm to
+ *   determine whether two edges are compatible.
+ * \param arg Extra argument to supply to functions \p node_compat_fn 
+ *   and \p edge_compat_fn.
+ * \return Error code.
+ * 
+ * Time complexity: exponential.
+ */
+ 
+int igraph_get_subisomorphisms_vf2(const igraph_t *graph1,
+				   const igraph_t *graph2,
+				   const igraph_vector_int_t *vertex_color1,
+				   const igraph_vector_int_t *vertex_color2,
+				   const igraph_vector_int_t *edge_color1,
+				   const igraph_vector_int_t *edge_color2,
+				   igraph_vector_ptr_t *maps,
+				   igraph_isocompat_t *node_compat_fn,
+				   igraph_isocompat_t *edge_compat_fn,
+				   void *arg) {
+  
+  igraph_i_iso_cb_data_t data = { node_compat_fn, edge_compat_fn, maps, arg };
+  igraph_isocompat_t *ncb = node_compat_fn ? igraph_i_isocompat_node_cb : 0;
+  igraph_isocompat_t *ecb = edge_compat_fn ? igraph_i_isocompat_edge_cb : 0;
+
+  igraph_vector_ptr_clear(maps);
+  IGRAPH_FINALLY(igraph_i_get_subisomorphisms_free, maps);
+  IGRAPH_CHECK(igraph_subisomorphic_function_vf2(graph1, graph2, 
+					 vertex_color1, vertex_color2,
+					 edge_color1, edge_color2,
+					 0, 0,
+					 (igraph_isohandler_t*)
+					 igraph_i_get_subisomorphisms_vf2,
+					 ncb, ecb, &data));
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \function igraph_permute_vertices
+ * Permute the vertices
+ * 
+ * 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 \ref igraph_canonical_permutation() to create
+ * the canonical form of a graph.
+ * \param graph The input graph.
+ * \param res Pointer to an uninitialized graph object. The new graph
+ *    is created here.
+ * \param permutation The permutation to apply. Vertex 0 is mapped to
+ *    the first element of the vector, vertex 1 to the second,
+ * etc. Note that it is not checked that the vector contains every
+ *    element only once, and no range checking is performed either.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|+|E|), linear in terms of the number of
+ * vertices and edges.
+ */
+
+int igraph_permute_vertices(const igraph_t *graph, igraph_t *res,
+			    const igraph_vector_t *permutation) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t edges;
+  long int i, p=0;
+  
+  if (igraph_vector_size(permutation) != no_of_nodes) {
+    IGRAPH_ERROR("Permute vertices: invalid permutation vector size", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+
+  for (i=0; i<no_of_edges; i++) {
+    VECTOR(edges)[p++] = VECTOR(*permutation)[ (long int) IGRAPH_FROM(graph, i) ];
+    VECTOR(edges)[p++] = VECTOR(*permutation)[ (long int) IGRAPH_TO(graph, i) ];
+  }
+  
+  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, 
+			     igraph_is_directed(graph)));
+  
+  /* Attributes */
+  if (graph->attr) {
+    igraph_vector_t index;
+    igraph_vector_t vtypes;
+    IGRAPH_I_ATTRIBUTE_DESTROY(res);
+    IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/1, /*vertex=*/0, /*edge=*/1);
+    IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
+    IGRAPH_CHECK(igraph_i_attribute_get_info(graph, 0, 0, 0, &vtypes, 0, 0));
+    if (igraph_vector_size(&vtypes) != 0) {      
+      IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_nodes);
+      for (i=0; i<no_of_nodes; i++) {
+	VECTOR(index)[ (long int) VECTOR(*permutation)[i] ] = i;
+      }
+      IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, res, &index));
+      igraph_vector_destroy(&index);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    igraph_vector_destroy(&vtypes);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/** 
+ * \section about_bliss 
+ * 
+ * <para>
+ * BLISS is a successor of the famous NAUTY algorithm and
+ * implementation. While using the same ideas in general, with better
+ * heuristics and data structure BLISS outperforms NAUTY on most
+ * graphs.
+ * </para>
+ * 
+ * <para>
+ * BLISS was developed and implemented by Tommi Junttila and Petteri Kaski at 
+ * Helsinki University of Technology, Finland. See Tommi Juntilla's 
+ * homepage at http://www.tcs.hut.fi/~tjunttil/ and the publication at 
+ * http://www.siam.org/proceedings/alenex/2007/alx07_013junttilat.pdf
+ * for more information.
+ * </para>
+ * 
+ * <para>
+ * BLISS version 0.35 is included in igraph.
+ * </para>
+ */
+
+/**
+ * \function igraph_isomorphic_bliss
+ * Graph isomorphism via BLISS
+ * 
+ * This function uses the BLISS graph isomorphism algorithm, a
+ * successor of the famous NAUTY algorithm and implementation. BLISS
+ * is open source and licensed according to the GNU GPL. See 
+ * http://www.tcs.hut.fi/Software/bliss/index.html for
+ * details. Currently the 0.35 version of BLISS is included in igraph.
+ * \param graph1 The first input graph, it is assumed to be
+ *   undirected, directed graphs are treated as undirected too.
+ *   The algorithm eliminates multiple edges from the graph first.
+ * \param graph2 The second input graph, it is assumed to be
+ *   undirected, directed graphs are treated as undirected too.
+ *   The algorithm eliminates multiple edges from the graph first.
+ * \param iso Pointer to a boolean, the result is stored here.
+ * \param map12 A vector or \c NULL pointer. If not \c NULL then an
+ *   isomorphic mapping from \p graph1 to \p graph2 is stored here.
+ *   If the input graphs are not isomorphic then this vector is
+ *   cleared, i.e. it will have length zero.
+ * \param map21 Similar to \p map12, but for the mapping from \p
+ *   graph2 to \p graph1. 
+ * \param sh1 Splitting heuristics to be used for the first graph. See
+ *   \ref igraph_bliss_sh_t.
+ * \param sh2 Splitting heuristics to be used for the second
+ *   graph. See \ref igraph_bliss_sh_t.
+ * \param info1 If not \c NULL, information about the canonization of
+ *    the first input graph is stored here. See \ref igraph_bliss_info_t
+ *    for details. Note that if the two graphs have different number
+ *    of vertices or edges, then this is not filled.
+ * \param info2 Same as \p info1, but for the second graph.
+ * \return Error code.
+ * 
+ * Time complexity: exponential, but in practice it is quite fast.
+ */
+
+int igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *graph2, 
+			    igraph_bool_t *iso, igraph_vector_t *map12, 
+			    igraph_vector_t *map21,
+			    igraph_bliss_sh_t sh1, igraph_bliss_sh_t sh2,
+			    igraph_bliss_info_t *info1, igraph_bliss_info_t *info2) {
+  
+  long int no_of_nodes=igraph_vcount(graph1);
+  long int no_of_edges=igraph_ecount(graph1);
+  igraph_vector_t perm1, perm2;
+  igraph_vector_t vmap12, *mymap12=&vmap12;  
+  igraph_vector_t from, to, index;
+  igraph_vector_t from2, to2, index2;
+  long int i, j;
+
+  *iso=0;
+	if (info1) {
+		info1->nof_nodes = info1->nof_leaf_nodes = info1->nof_bad_nodes = 
+			info1->nof_canupdates = info1->max_level = -1;
+		info1->group_size = 0;
+	}
+	if (info2) {
+		info2->nof_nodes = info2->nof_leaf_nodes = info2->nof_bad_nodes = 
+			info2->nof_canupdates = info2->max_level = -1;
+		info2->group_size = 0;
+	}
+
+  if (igraph_is_directed(graph1) != igraph_is_directed(graph2)) {
+    IGRAPH_ERROR("Cannot compare directed and undirected graphs",
+		 IGRAPH_EINVAL);
+  }
+
+  if (no_of_nodes != igraph_vcount(graph2) ||
+      no_of_edges != igraph_ecount(graph2)) {
+    if (map12) { igraph_vector_clear(map12); }
+    if (map21) { igraph_vector_clear(map21); }
+    return 0;
+  }
+
+  if (map12) {
+    mymap12=map12;
+  } else {
+    IGRAPH_VECTOR_INIT_FINALLY(mymap12, 0);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&perm1, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&perm2, no_of_nodes);
+  
+  IGRAPH_CHECK(igraph_canonical_permutation(graph1, &perm1, sh1, info1));
+  IGRAPH_CHECK(igraph_canonical_permutation(graph2, &perm2, sh2, info2));
+
+  IGRAPH_CHECK(igraph_vector_resize(mymap12, no_of_nodes));
+    
+  /* The inverse of perm2 is produced in mymap12 */
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(*mymap12)[ (long int)VECTOR(perm2)[i] ] = i;
+  }
+  /* Now we produce perm2^{-1} o perm1 in perm2 */
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(perm2)[i] = VECTOR(*mymap12)[ (long int) VECTOR(perm1)[i] ];
+  }
+  /* Copy it to mymap12 */
+  igraph_vector_update(mymap12, &perm2);
+  
+  igraph_vector_destroy(&perm1);
+  igraph_vector_destroy(&perm2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  /* Check isomorphism, we apply the permutation in mymap12 to graph1
+     and should get graph2 */
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&from, no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&to, no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&from2, no_of_edges*2);
+  IGRAPH_VECTOR_INIT_FINALLY(&to2, no_of_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&index2, no_of_edges);  
+  
+  for (i=0; i<no_of_edges; i++) {
+    VECTOR(from)[i] = VECTOR(*mymap12)[ (long int) IGRAPH_FROM(graph1, i) ];
+    VECTOR(to)[i]   = VECTOR(*mymap12)[ (long int) IGRAPH_TO  (graph1, i) ];
+    if (VECTOR(from)[i] < VECTOR(to)[i]) {
+      igraph_real_t tmp=VECTOR(from)[i];
+      VECTOR(from)[i] = VECTOR(to)[i];
+      VECTOR(to)[i] = tmp;
+    }
+  }
+  igraph_vector_order(&from, &to, &index, no_of_nodes);
+  
+  igraph_get_edgelist(graph2, &from2, /*bycol=*/ 1);
+  for (i=0, j=no_of_edges; i<no_of_edges; i++, j++) {
+    VECTOR(to2)[i] = VECTOR(from2)[j];
+    if (VECTOR(from2)[i] < VECTOR(to2)[i]) {
+      igraph_real_t tmp=VECTOR(from2)[i];
+      VECTOR(from2)[i] = VECTOR(to2)[i];
+      VECTOR(to2)[i] = tmp;
+    }
+  }
+  igraph_vector_resize(&from2, no_of_edges);
+  igraph_vector_order(&from2, &to2, &index2, no_of_nodes);
+  
+  *iso=1;
+  for (i=0; i<no_of_edges; i++) {
+    long int i1=(long int) VECTOR(index)[i];
+    long int i2=(long int) VECTOR(index2)[i];
+    if (VECTOR(from)[i1] != VECTOR(from2)[i2] ||
+	VECTOR(to)[i1] != VECTOR(to2)[i2]) {
+      *iso=0;
+      break;
+    }
+  }
+  
+  igraph_vector_destroy(&index2);
+  igraph_vector_destroy(&to2);
+  igraph_vector_destroy(&from2);
+  igraph_vector_destroy(&index);
+  igraph_vector_destroy(&to);
+  igraph_vector_destroy(&from);
+  IGRAPH_FINALLY_CLEAN(6);
+  
+  if (*iso) {
+    /* The inverse of mymap12 */
+    if (map21) {
+      IGRAPH_CHECK(igraph_vector_resize(map21, no_of_nodes));
+      for (i=0; i<no_of_nodes; i++) {
+	VECTOR(*map21)[ (long int) VECTOR(*mymap12)[i] ] = i;
+      }
+    }
+  } else {
+    if (map12) { igraph_vector_clear(map12); }
+    if (map21) { igraph_vector_clear(map21); }
+  }
+  
+  if (!map12) {
+    igraph_vector_destroy(mymap12);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+  
+  return 0;
+}
diff --git a/src/triangles.c b/src/triangles.c
new file mode 100644
index 0000000..f5859fa
--- /dev/null
+++ b/src/triangles.c
@@ -0,0 +1,925 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_transitivity.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_memory.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_centrality.h"
+#include "igraph_motifs.h"
+
+/**
+ * \function igraph_transitivity_avglocal_undirected
+ * \brief Average local transitivity (clustering coefficient).
+ * 
+ * The transitivity measures the probability that two neighbors of a
+ * vertex are connected. In case of the average local transitivity,
+ * this probability is calculated for each vertex and then the average
+ * is taken. Vertices with less than two neighbors require special treatment,
+ * they will either be left out from the calculation or they will be considered
+ * as having zero transitivity, depending on the \c mode argument.
+ *
+ * </para><para>
+ * Note that this measure is different from the global transitivity measure
+ * (see \ref igraph_transitivity_undirected() ) as it simply takes the
+ * average local transitivity across the whole network. See the following
+ * reference for more details:
+ *
+ * </para><para>
+ * D. J. Watts and S. Strogatz: Collective dynamics of small-world networks.
+ * Nature 393(6684):440-442 (1998).
+ *
+ * </para><para>
+ * Clustering coefficient is an alternative name for transitivity.
+ *
+ * \param graph The input graph, directed graphs are considered as 
+ *    undirected ones.
+ * \param res Pointer to a real variable, the result will be stored here.
+ * \param mode Defines how to treat vertices with degree less than two.
+ *    \c IGRAPH_TRANSITIVITY_NAN leaves them out from averaging,
+ *    \c IGRAPH_TRANSITIVITY_ZERO includes them with zero transitivity.
+ *    The result will be \c NaN if the mode is \c IGRAPH_TRANSITIVITY_NAN
+ *    and there are no vertices with more than one neighbor.
+ *    
+ * \return Error code.
+ * 
+ * \sa \ref igraph_transitivity_undirected(), \ref
+ * igraph_transitivity_local_undirected().
+ * 
+ * Time complexity: O(|V|*d^2), |V| is the number of vertices in the
+ * graph and d is the average degree.
+ */
+
+int igraph_transitivity_avglocal_undirected(const igraph_t *graph,
+					    igraph_real_t *res,
+					    igraph_transitivity_mode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_real_t sum=0.0;
+  igraph_integer_t count=0;
+  long int node, i, j, nn;
+  igraph_adjlist_t allneis;
+  igraph_vector_int_t *neis1, *neis2;
+  long int neilen1, neilen2;
+  igraph_integer_t triples;
+  long int *neis;
+  long int maxdegree;
+
+  igraph_vector_t order;
+  igraph_vector_t rank;
+  igraph_vector_t degree;
+  igraph_vector_t triangles;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);
+  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(&degree, &order, maxdegree);
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_VECTOR_INIT_FINALLY(&rank, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(rank)[ (long int) VECTOR(order)[i] ] = no_of_nodes-i-1;
+  }
+  
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+  IGRAPH_CHECK(igraph_adjlist_simplify(&allneis));
+
+  neis=igraph_Calloc(no_of_nodes, long int);
+  if (neis==0) {
+    IGRAPH_ERROR("undirected average local transitivity failed",
+		 IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, neis);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&triangles, no_of_nodes);
+  
+  for (nn=no_of_nodes-1; nn >= 0; nn--) {
+    node=(long int) VECTOR(order)[nn];
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    neis1=igraph_adjlist_get(&allneis, node);
+    neilen1=igraph_vector_int_size(neis1);
+    triples = (igraph_integer_t) ((double)neilen1 * (neilen1-1) / 2);
+    /* Mark the neighbors of 'node' */
+    for (i=0; i<neilen1; i++) {
+      neis[ (long int)VECTOR(*neis1)[i] ] = node+1;
+    }
+    
+    for (i=0; i<neilen1; i++) {
+      long int nei=(long int) VECTOR(*neis1)[i];
+      if (VECTOR(rank)[nei] > VECTOR(rank)[node]) {
+				neis2=igraph_adjlist_get(&allneis, nei);
+				neilen2=igraph_vector_int_size(neis2);
+				for (j=0; j<neilen2; j++) {
+					long int nei2=(long int) VECTOR(*neis2)[j];
+					if (VECTOR(rank)[nei2] < VECTOR(rank)[nei]) {
+						continue;
+					}
+					if (neis[nei2] == node+1) {
+						VECTOR(triangles)[nei2] += 1;
+						VECTOR(triangles)[nei] += 1;
+						VECTOR(triangles)[node] += 1;
+					}
+				}
+      }
+    }
+    
+    if (triples != 0) {
+      sum += VECTOR(triangles)[node] / triples;
+      count++;
+    } else if (mode == IGRAPH_TRANSITIVITY_ZERO) {
+      count++;
+    }
+  }
+  
+  *res = sum/count;
+
+  igraph_vector_destroy(&triangles);
+  igraph_Free(neis);
+  igraph_adjlist_destroy(&allneis);
+  igraph_vector_destroy(&rank);
+  igraph_vector_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(5);
+  return 0;
+}
+  
+int igraph_transitivity_local_undirected1(const igraph_t *graph, 
+					  igraph_vector_t *res,
+					  const igraph_vs_t vids,
+					  igraph_transitivity_mode_t mode) {
+	
+#define TRIPLES
+#define TRANSIT
+#include "triangles_template1.h"
+#undef TRIPLES
+#undef TRANSIT	
+	
+	return 0;
+}
+
+int igraph_transitivity_local_undirected2(const igraph_t *graph, 
+					  igraph_vector_t *res,
+					  const igraph_vs_t vids,
+					  igraph_transitivity_mode_t mode) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vit_t vit;
+  long int nodes_to_calc, affected_nodes;
+  long int maxdegree=0;
+  long int i, j, k, nn;
+  igraph_lazy_adjlist_t adjlist;
+  igraph_vector_t indexv, avids, rank, order, triangles, degree;
+  long int *neis;
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL,
+					  IGRAPH_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&indexv, no_of_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&avids, 0);
+  IGRAPH_CHECK(igraph_vector_reserve(&avids, nodes_to_calc));
+  k=0;
+  for (i=0; i<nodes_to_calc; IGRAPH_VIT_NEXT(vit), i++) {
+    long int v=IGRAPH_VIT_GET(vit);
+    igraph_vector_t *neis2;
+    long int neilen;
+    if (VECTOR(indexv)[v]==0) {
+      VECTOR(indexv)[v]=k+1; k++;
+      IGRAPH_CHECK(igraph_vector_push_back(&avids, v));
+    } 
+    
+    neis2=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) v);
+    neilen=igraph_vector_size(neis2);
+    for (j=0; j<neilen; j++) {
+      long int nei=(long int) VECTOR(*neis2)[j];
+      if (VECTOR(indexv)[nei]==0) {
+				VECTOR(indexv)[nei]=k+1; k++;
+				IGRAPH_CHECK(igraph_vector_push_back(&avids, nei));
+      }
+    }
+  }
+
+  /* Degree, ordering, ranking */
+  affected_nodes=igraph_vector_size(&avids);
+  IGRAPH_VECTOR_INIT_FINALLY(&order, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, affected_nodes);
+  for (i=0; i<affected_nodes; i++) {
+    long int v=(long int) VECTOR(avids)[i];
+    igraph_vector_t *neis2;
+    long int deg;
+    neis2=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) v);
+    VECTOR(degree)[i]=deg=igraph_vector_size(neis2);
+    if (deg > maxdegree) { maxdegree = deg; }
+  }
+  igraph_vector_order1(&degree, &order, maxdegree+1);
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_VECTOR_INIT_FINALLY(&rank, affected_nodes);
+  for (i=0; i<affected_nodes; i++) {
+    VECTOR(rank)[ (long int) VECTOR(order)[i] ] = affected_nodes-i-1;
+  }
+  
+  neis=igraph_Calloc(no_of_nodes, long int);
+  if (neis==0) {
+    IGRAPH_ERROR("local transitivity calculation failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, neis);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&triangles, affected_nodes);
+  for (nn=affected_nodes-1; nn>=0; nn--) {
+    long int node=(long int) VECTOR(avids) [ (long int) VECTOR(order)[nn] ];
+    igraph_vector_t *neis1, *neis2;
+    long int neilen1, neilen2;
+    long int nodeindex=(long int) VECTOR(indexv)[node];
+    long int noderank=(long int) VECTOR(rank) [nodeindex-1];
+    
+/*     fprintf(stderr, "node %li (indexv %li, rank %li)\n", node, */
+/* 	    (long int)VECTOR(indexv)[node]-1, noderank); */
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    neis1=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) node);
+    neilen1=igraph_vector_size(neis1);
+    for (i=0; i<neilen1; i++) {
+      long int nei=(long int) VECTOR(*neis1)[i];
+      neis[nei] = node+1;
+    }
+    for (i=0; i<neilen1; i++) {
+      long int nei=(long int) VECTOR(*neis1)[i];
+      long int neiindex=(long int) VECTOR(indexv)[nei];
+      long int neirank=(long int) VECTOR(rank)[neiindex-1];
+
+/*       fprintf(stderr, "  nei %li (indexv %li, rank %li)\n", nei, */
+/* 	      neiindex, neirank); */
+      if (neirank > noderank) {
+				neis2=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) nei);
+				neilen2=igraph_vector_size(neis2);
+				for (j=0; j<neilen2; j++) {	  
+					long int nei2=(long int) VECTOR(*neis2)[j];
+					long int nei2index=(long int) VECTOR(indexv)[nei2];
+					long int nei2rank=(long int) VECTOR(rank)[nei2index-1];
+/* 	  fprintf(stderr, "    triple %li %li %li\n", node, nei, nei2); */
+					if (nei2rank < neirank) {
+						continue;
+					} 
+					if (neis[nei2] == node+1) {
+						/* 	    fprintf(stderr, "    triangle\n"); */
+						VECTOR(triangles) [ nei2index-1 ] += 1;
+						VECTOR(triangles) [ neiindex-1 ] += 1;
+						VECTOR(triangles) [ nodeindex-1 ] += 1;
+					}
+				}
+      }
+    }    
+  }
+  
+  /* Ok, for all affected vertices the number of triangles were counted */
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  IGRAPH_VIT_RESET(vit);
+  for (i=0; i<nodes_to_calc; i++, IGRAPH_VIT_NEXT(vit)) {
+    long int node=IGRAPH_VIT_GET(vit);
+    long int idx=(long int) VECTOR(indexv)[node]-1;
+    igraph_vector_t *neis2=igraph_lazy_adjlist_get(&adjlist, 
+						   (igraph_integer_t) node);
+    long int deg=igraph_vector_size(neis2);
+    igraph_real_t triples=(double) deg * (deg-1) / 2;
+    if (mode == IGRAPH_TRANSITIVITY_ZERO && triples == 0)
+      VECTOR(*res)[i] = 0.0;
+    else
+      VECTOR(*res)[i] = VECTOR(triangles)[idx] / triples;
+/*     fprintf(stderr, "%f %f\n", VECTOR(triangles)[idx], triples); */
+  }
+  
+  igraph_vector_destroy(&triangles);
+  igraph_free(neis);
+  igraph_vector_destroy(&rank);
+  igraph_vector_destroy(&order);
+  igraph_vector_destroy(&avids);
+  igraph_vector_destroy(&indexv);
+  igraph_lazy_adjlist_destroy(&adjlist);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(8);
+
+  return 0;
+}
+
+/* We don't use this, it is theoretically good, but practically not.
+ */
+
+/* int igraph_transitivity_local_undirected3(const igraph_t *graph, */
+/* 				      igraph_vector_t *res, */
+/* 				      const igraph_vs_t vids) { */
+
+/*   igraph_vit_t vit; */
+/*   long int nodes_to_calc; */
+/*   igraph_lazy_adjlist_t adjlist; */
+/*   long int i, j; */
+  
+/*   IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); */
+/*   IGRAPH_FINALLY(igraph_vit_destroy, &vit); */
+/*   nodes_to_calc=IGRAPH_VIT_SIZE(vit); */
+  
+/*   IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL, */
+/* 					  IGRAPH_SIMPLIFY)); */
+/*   IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); */
+  
+/*   IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc)); */
+/*   for (i=0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit);  */
+/*        i++, IGRAPH_VIT_NEXT(vit)) { */
+/*     long int node=IGRAPH_VIT_GET(vit); */
+/*     igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, node); */
+/*     long int n1=igraph_vector_size(neis); */
+/*     igraph_real_t triangles=0; */
+/*     igraph_real_t triples=(double)n1*(n1-1); */
+/*     IGRAPH_ALLOW_INTERRUPTION(); */
+/*     for (j=0; j<n1; j++) { */
+/*       long int node2=VECTOR(*neis)[j]; */
+/*       igraph_vector_t *neis2=igraph_lazy_adjlist_get(&adjlist, node2); */
+/*       long int n2=igraph_vector_size(neis2); */
+/*       long int l1=0, l2=0; */
+/*       while (l1 < n1 && l2 < n2) { */
+/* 	long int nei1=VECTOR(*neis)[l1]; */
+/* 	long int nei2=VECTOR(*neis2)[l2]; */
+/* 	if (nei1 < nei2) {  */
+/* 	  l1++; */
+/* 	} else if (nei1 > nei2) { */
+/* 	  l2++; */
+/* 	} else { */
+/* 	  triangles+=1; */
+/* 	  l1++; l2++; */
+/* 	} */
+/*       } */
+/*     } */
+/*     /\* We're done with 'node' *\/ */
+/*     VECTOR(*res)[i] = triangles / triples;   */
+/*   } */
+
+/*   igraph_lazy_adjlist_destroy(&adjlist); */
+/*   igraph_vit_destroy(&vit); */
+/*   IGRAPH_FINALLY_CLEAN(2); */
+
+/*   return 0; */
+/* } */
+
+/* This removes loop, multiple edges and edges that point
+	 "backwards" according to the rank vector. */
+
+int igraph_i_trans4_al_simplify(igraph_adjlist_t *al,
+				const igraph_vector_int_t *rank) {
+  long int i;
+  long int n=al->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=&al->adjs[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 e=(long int) VECTOR(*v)[j];
+      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;
+
+}
+
+int igraph_transitivity_local_undirected4(const igraph_t *graph,
+					  igraph_vector_t *res,
+					  const igraph_vs_t vids,
+					  igraph_transitivity_mode_t mode) {
+
+#define TRIPLES 1
+#define TRANSIT 1
+#include "triangles_template.h"
+#undef TRIPLES
+#undef TRANSIT
+  
+  return 0;
+}
+
+/**
+ * \function igraph_transitivity_local_undirected
+ * \brief Calculates the local transitivity (clustering coefficient) of a graph.
+ * 
+ * The transitivity measures the probability that two neighbors of a
+ * vertex are connected. In case of the local transitivity, this
+ * probability is calculated separately for each vertex.
+ *
+ * </para><para>
+ * Note that this measure is different from the global transitivity measure
+ * (see \ref igraph_transitivity_undirected() ) as it calculates a transitivity
+ * value for each vertex individually. See the following reference for more
+ * details:
+ *
+ * </para><para>
+ * D. J. Watts and S. Strogatz: Collective dynamics of small-world networks.
+ * Nature 393(6684):440-442 (1998).
+ *
+ * </para><para>
+ * Clustering coefficient is an alternative name for transitivity.
+ *
+ * \param graph The input graph, it can be directed but direction of
+ *   the edges will be ignored.
+ * \param res Pointer to an initialized vector, the result will be
+ *   stored here. It will be resized as needed.
+ * \param vids Vertex set, the vertices for which the local
+ *   transitivity will be calculated.
+ * \param mode Defines how to treat vertices with degree less than two.
+ *    \c IGRAPH_TRANSITIVITY_NAN returns \c NaN for these vertices,
+ *    \c IGRAPH_TRANSITIVITY_ZERO returns zero.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_transitivity_undirected(), \ref
+ * igraph_transitivity_avglocal_undirected().
+ * 
+ * Time complexity: O(n*d^2), n is the number of vertices for which
+ * the transitivity is calculated, d is the average vertex degree.
+ */
+
+int igraph_transitivity_local_undirected(const igraph_t *graph,
+					 igraph_vector_t *res,
+					 const igraph_vs_t vids,
+					 igraph_transitivity_mode_t mode) {
+  if (igraph_vs_is_all(&vids)) {
+    return igraph_transitivity_local_undirected4(graph, res, vids, mode);
+  } else {
+    igraph_vit_t vit;
+    long int size;
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+    size=IGRAPH_VIT_SIZE(vit);
+    igraph_vit_destroy(&vit);
+		IGRAPH_FINALLY_CLEAN(1);
+    if (size < 100) {
+      return igraph_transitivity_local_undirected1(graph, res, vids, mode);
+    } else {
+      return igraph_transitivity_local_undirected2(graph, res, vids, mode);
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_adjacent_triangles1(const igraph_t *graph,
+			       igraph_vector_t *res,
+			       const igraph_vs_t vids) {
+# include "triangles_template1.h"
+  return 0;
+}
+
+int igraph_adjacent_triangles4(const igraph_t *graph,
+			       igraph_vector_t *res) {
+# include "triangles_template.h"
+  return 0;
+}
+
+int igraph_adjacent_triangles(const igraph_t *graph,
+			      igraph_vector_t *res,
+			      const igraph_vs_t vids) {
+  if (igraph_vs_is_all(&vids)) {
+    return igraph_adjacent_triangles4(graph, res);
+  } else {
+    return igraph_adjacent_triangles1(graph, res, vids);
+  }
+  
+  return 0;
+
+}
+
+/**
+ * \ingroup structural
+ * \function igraph_transitivity_undirected
+ * \brief Calculates the transitivity (clustering coefficient) of a graph.
+ * 
+ * </para><para>
+ * The transitivity measures the probability that two neighbors of a
+ * vertex are connected. More precisely, this is the ratio of the
+ * triangles and connected triples in the graph, the result is a
+ * single real number. Directed graphs are considered as undirected ones.
+ *
+ * </para><para>
+ * Note that this measure is different from the local transitivity measure
+ * (see \ref igraph_transitivity_local_undirected() ) as it calculates a single
+ * value for the whole graph. See the following reference for more details:
+ *
+ * </para><para>
+ * S. Wasserman and K. Faust: Social Network Analysis: Methods and
+ * Applications. Cambridge: Cambridge University Press, 1994.
+ *
+ * </para><para>
+ * Clustering coefficient is an alternative name for transitivity.
+ *
+ * \param graph The graph object.  
+ * \param res Pointer to a real variable, the result will be stored here.
+ * \param mode Defines how to treat graphs with no connected triples.
+ *   \c IGRAPH_TRANSITIVITY_NAN returns \c NaN in this case,
+ *   \c IGRAPH_TRANSITIVITY_ZERO returns zero.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM: not enough memory for
+ *         temporary data. 
+ *
+ * \sa \ref igraph_transitivity_local_undirected(), 
+ * \ref igraph_transitivity_avglocal_undirected().
+ *
+ * Time complexity: O(|V|*d^2), |V| is the number of vertices in 
+ * the graph, d is the average node degree. 
+ * 
+ * \example examples/simple/igraph_transitivity.c
+ */
+
+
+int igraph_transitivity_undirected(const igraph_t *graph,
+				   igraph_real_t *res,
+				   igraph_transitivity_mode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_real_t triples=0, triangles=0;
+  long int node, nn;
+  long int maxdegree;
+  long int *neis;
+  igraph_vector_t order;
+  igraph_vector_t rank;
+  igraph_vector_t degree;
+  
+  igraph_adjlist_t allneis;
+  igraph_vector_int_t *neis1, *neis2;
+  long int i, j, neilen1, neilen2;
+
+  IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);
+  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(&degree, &order, maxdegree);
+  igraph_vector_destroy(&degree);
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_VECTOR_INIT_FINALLY(&rank, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(rank)[ (long int) VECTOR(order)[i] ]=no_of_nodes-i-1;
+  }
+  
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+  IGRAPH_CHECK(igraph_adjlist_simplify(&allneis));
+
+  neis=igraph_Calloc(no_of_nodes, long int);
+  if (neis==0) {
+    IGRAPH_ERROR("undirected transitivity failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, neis);
+  
+  for (nn=no_of_nodes-1; nn >=0; nn--) { 
+    node=(long int) VECTOR(order)[nn];
+
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    neis1=igraph_adjlist_get(&allneis, node);
+    neilen1=igraph_vector_int_size(neis1);
+    triples += (double)neilen1 * (neilen1-1);
+    /* Mark the neighbors of 'node' */
+    for (i=0; i<neilen1; i++) {
+      long int nei=(long int) VECTOR(*neis1)[i];
+      neis[nei] = node+1;
+    }
+    for (i=0; i<neilen1; i++) {
+      long int nei=(long int) VECTOR(*neis1)[i];
+      /* If 'nei' is not ready yet */      
+      if (VECTOR(rank)[nei] > VECTOR(rank)[node]) {
+				neis2=igraph_adjlist_get(&allneis, nei);
+				neilen2=igraph_vector_int_size(neis2);
+				for (j=0; j<neilen2; j++) {
+					long int nei2=(long int) VECTOR(*neis2)[j];
+					if (neis[nei2] == node+1) {
+						triangles += 1.0;
+					}
+				}
+      }
+    }
+  }
+	
+  igraph_Free(neis);
+  igraph_adjlist_destroy(&allneis);
+  igraph_vector_destroy(&rank);
+  igraph_vector_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  if (triples == 0 && mode == IGRAPH_TRANSITIVITY_ZERO)
+    *res = 0;
+  else
+    *res = triangles / triples * 2.0;
+  
+  return 0;
+}
+
+int igraph_transitivity_barrat1(const igraph_t *graph,
+				igraph_vector_t *res,
+				const igraph_vs_t vids,
+				const igraph_vector_t *weights,
+				igraph_transitivity_mode_t mode);
+
+int igraph_transitivity_barrat4(const igraph_t *graph,
+				igraph_vector_t *res,
+				const igraph_vs_t vids,
+				const igraph_vector_t *weights,
+				igraph_transitivity_mode_t mode);
+
+int igraph_transitivity_barrat1(const igraph_t *graph,
+				igraph_vector_t *res,
+				const igraph_vs_t vids,
+				const igraph_vector_t *weights,
+				igraph_transitivity_mode_t mode) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vit_t vit;
+  long int nodes_to_calc;
+  igraph_vector_t *adj1, *adj2;
+  igraph_vector_long_t neis;
+  igraph_vector_t actw;
+  igraph_lazy_inclist_t incident;
+  long int i;
+  igraph_vector_t strength;
+  
+  if (!weights) {
+    IGRAPH_WARNING("No weights given for Barrat's transitivity, unweighted version is used");
+    return igraph_transitivity_local_undirected(graph, res, vids, mode);
+  }
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid edge weight vector length", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&neis, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &neis);
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&actw, no_of_nodes);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&strength, 0);  
+  IGRAPH_CHECK(igraph_strength(graph, &strength, igraph_vss_all(), IGRAPH_ALL,
+															 IGRAPH_LOOPS, weights));  
+  
+  igraph_lazy_inclist_init(graph, &incident, IGRAPH_ALL);
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &incident);  
+	
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    long int node=IGRAPH_VIT_GET(vit);
+    long int adjlen1, adjlen2, j, k;
+    igraph_real_t triples, triangles;
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    adj1=igraph_lazy_inclist_get(&incident, (igraph_integer_t) node);
+    adjlen1=igraph_vector_size(adj1);
+    /* Mark the neighbors of the node */
+    for (j=0; j<adjlen1; j++) {
+      long int edge=(long int) VECTOR(*adj1)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, node);
+      VECTOR(neis)[nei] = i+1;
+      VECTOR(actw)[nei] = VECTOR(*weights)[edge];
+    }
+    triples = VECTOR(strength)[node] * (adjlen1-1);
+    triangles = 0.0;
+    
+    for (j=0; j<adjlen1; j++) {
+      long int edge1=(long int) VECTOR(*adj1)[j];
+      igraph_real_t weight1=VECTOR(*weights)[edge1];
+      long int v=IGRAPH_OTHER(graph, edge1, node);
+      adj2=igraph_lazy_inclist_get(&incident, (igraph_integer_t) v);
+      adjlen2=igraph_vector_size(adj2);
+      for (k=0; k<adjlen2; k++) {
+				long int edge2=(long int) VECTOR(*adj2)[k];
+				long int v2=IGRAPH_OTHER(graph, edge2, v);
+				if (VECTOR(neis)[v2] == i+1) {
+					triangles += (VECTOR(actw)[v2] + weight1) / 2.0;
+				}
+      }
+    }
+    if (mode == IGRAPH_TRANSITIVITY_ZERO && triples == 0)
+      VECTOR(*res)[i] = 0.0;
+    else
+      VECTOR(*res)[i] = triangles/triples;
+  }
+	
+  igraph_lazy_inclist_destroy(&incident);
+  igraph_vector_destroy(&strength);
+  igraph_vector_destroy(&actw);
+  igraph_vector_long_destroy(&neis);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(5);
+  
+  return 0;    
+}
+
+int igraph_transitivity_barrat4(const igraph_t *graph,
+																igraph_vector_t *res,
+																const igraph_vs_t vids,
+																const igraph_vector_t *weights,
+																igraph_transitivity_mode_t mode) {
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_vector_t order, degree, rank;
+  long int maxdegree;
+  igraph_inclist_t incident;
+  igraph_vector_long_t neis;
+  igraph_vector_t *adj1, *adj2;
+  igraph_vector_t actw;
+  long int i, nn;
+  
+  if (!weights) { 
+    IGRAPH_WARNING("No weights given for Barrat's transitivity, unweighted version is used");
+    return igraph_transitivity_local_undirected(graph, res, vids, mode);
+  }
+  
+  if (igraph_vector_size(weights) != no_of_edges) {
+    IGRAPH_ERROR("Invalid edge weight vector length", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);
+  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_CHECK(igraph_vector_order1(&degree, &order, maxdegree));
+
+  IGRAPH_CHECK(igraph_strength(graph, &degree, igraph_vss_all(), IGRAPH_ALL,
+			       IGRAPH_LOOPS, weights));
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&rank, no_of_nodes);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(rank)[ (long int)VECTOR(order)[i] ] = no_of_nodes-i-1;
+  }
+  
+  IGRAPH_CHECK(igraph_inclist_init(graph, &incident, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incident);
+  
+  IGRAPH_CHECK(igraph_vector_long_init(&neis, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &neis);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&actw, no_of_nodes);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+  igraph_vector_null(res);
+  
+  for (nn=no_of_nodes-1; nn>=0; nn--) {
+    long int adjlen1, adjlen2;
+    igraph_real_t triples;
+    long int node=(long int) VECTOR(order)[nn];
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    adj1=igraph_inclist_get(&incident, node);
+    adjlen1=igraph_vector_size(adj1);
+    triples = VECTOR(degree)[node] * (adjlen1-1) / 2.0;
+    /* Mark the neighbors of the node */
+    for (i=0; i<adjlen1; i++) {
+      long int edge=(long int) VECTOR(*adj1)[i];
+      long int nei=IGRAPH_OTHER(graph, edge, node);
+      VECTOR(neis)[nei] = node+1;
+      VECTOR(actw)[nei] = VECTOR(*weights)[edge];
+    }
+    
+    for (i=0; i<adjlen1; i++) {
+      long int edge1=(long int) VECTOR(*adj1)[i];
+      igraph_real_t weight1=VECTOR(*weights)[edge1];
+      long int nei=IGRAPH_OTHER(graph, edge1, node);
+      long int j;
+      if (VECTOR(rank)[nei] > VECTOR(rank)[node]) {
+				adj2=igraph_inclist_get(&incident, nei);
+				adjlen2=igraph_vector_size(adj2);
+				for (j=0; j<adjlen2; j++) {
+					long int edge2=(long int) VECTOR(*adj2)[j];
+					igraph_real_t weight2=VECTOR(*weights)[edge2];
+					long int nei2=IGRAPH_OTHER(graph, edge2, nei);
+					if (VECTOR(rank)[nei2] < VECTOR(rank)[nei]) {
+						continue;
+					}
+					if (VECTOR(neis)[nei2] == node+1) {
+						VECTOR(*res)[nei2] += (VECTOR(actw)[nei2] + weight2) / 2.0;
+						VECTOR(*res)[nei] += (weight1 + weight2) / 2.0;
+						VECTOR(*res)[node] += (VECTOR(actw)[nei2] + weight1) / 2.0;
+					}
+				}
+      }
+    }
+
+    if (mode == IGRAPH_TRANSITIVITY_ZERO && triples == 0)
+      VECTOR(*res)[node] = 0.0;
+    else
+      VECTOR(*res)[node] /= triples;
+  }
+	
+  igraph_vector_destroy(&actw);
+  igraph_vector_long_destroy(&neis);
+  igraph_inclist_destroy(&incident);
+  igraph_vector_destroy(&rank);
+  igraph_vector_destroy(&degree);
+  igraph_vector_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(6);
+	
+  return 0;
+}
+
+/**
+ * \function igraph_transitivity_barrat
+ * Weighted transitivity, as defined by A. Barrat.
+ *
+ * This is a local transitivity, i.e. a vertex-level index. For a
+ * given vertex \c i, from all triangles in which it participates we
+ * consider the weight of the edges incident on \c i. The transitivity
+ * is the sum of these weights divided by twice the strength of the
+ * vertex (see \ref igraph_strength()) and the degree of the vertex
+ * minus one. See   Alain Barrat, Marc Barthelemy, Romualdo
+ * Pastor-Satorras, Alessandro Vespignani: The architecture of complex
+ * weighted networks, Proc. Natl. Acad. Sci. USA 101, 3747 (2004) at 
+ * http://arxiv.org/abs/cond-mat/0311416 for the exact formula.
+ * 
+ * \param graph The input graph, edge directions are ignored for
+ *   directed graphs. Note that the function does NOT work for
+ *   non-simple graphs.
+ * \param res Pointer to an initialized vector, the result will be
+ *   stored here. It will be resized as needed.
+ * \param vids The vertices for which the calculation is performed.
+ * \param weights Edge weights. If this is a null pointer, then a
+ *   warning is given and \ref igraph_transitivity_local_undirected()
+ *   is called.
+ * \param mode Defines how to treat vertices with zero strength.
+ *   \c IGRAPH_TRANSITIVITY_NAN says that the transitivity of these
+ *   vertices is \c NaN, \c IGRAPH_TRANSITIVITY_ZERO says it is zero.
+ *
+ * \return Error code.
+ *
+ * Time complexity: O(|V|*d^2), |V| is the number of vertices in 
+ * the graph, d is the average node degree. 
+ * 
+ * \sa \ref igraph_transitivity_undirected(), \ref
+ * igraph_transitivity_local_undirected() and \ref
+ * igraph_transitivity_avglocal_undirected() for other kinds of
+ * (non-weighted) transitivity.
+ */
+
+int igraph_transitivity_barrat(const igraph_t *graph,
+			       igraph_vector_t *res,
+			       const igraph_vs_t vids,
+			       const igraph_vector_t *weights,
+				   igraph_transitivity_mode_t mode) {
+  if (igraph_vs_is_all(&vids)) {
+    return igraph_transitivity_barrat4(graph, res, vids, weights, mode);
+  } else {
+    return igraph_transitivity_barrat1(graph, res, vids, weights, mode);
+  }
+  
+  return 0;
+}
diff --git a/src/triangles_template.h b/src/triangles_template.h
new file mode 100644
index 0000000..6b9bd1a
--- /dev/null
+++ b/src/triangles_template.h
@@ -0,0 +1,110 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   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
+
+*/
+
+  long int no_of_nodes=igraph_vcount(graph);
+  long int node, i, j, nn;
+  igraph_adjlist_t allneis;
+  igraph_vector_int_t *neis1, *neis2;
+  long int neilen1, neilen2, deg1;
+#ifdef TRIPLES
+  igraph_integer_t triples;
+#endif
+  long int *neis;
+  long int maxdegree;
+
+  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);
+  
+  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_adjlist_init(graph, &allneis, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
+  IGRAPH_CHECK(igraph_i_trans4_al_simplify(&allneis, &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_vector_resize(res, no_of_nodes));
+  igraph_vector_null(res);
+  
+  for (nn=no_of_nodes-1; nn>=0; nn--) {
+    node=VECTOR(order)[nn];
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    neis1=igraph_adjlist_get(&allneis, node);
+    neilen1=igraph_vector_int_size(neis1);
+    deg1=(long int) VECTOR(degree)[node];
+#ifdef TRIPLES
+    triples=(igraph_integer_t) ((double)deg1*(deg1-1)/2);
+#endif
+    /* Mark the neighbors of the node */
+    for (i=0; i<neilen1; i++) {
+      neis[ (long int) VECTOR(*neis1)[i] ] = node+1;
+    }
+    
+    for (i=0; i<neilen1; i++) {
+      long int nei=(long int) VECTOR(*neis1)[i];
+      neis2=igraph_adjlist_get(&allneis, nei);
+      neilen2=igraph_vector_int_size(neis2);
+      for (j=0; j<neilen2; j++) {
+	long int nei2=(long int) VECTOR(*neis2)[j];
+	if (neis[nei2] == node+1) {
+	  VECTOR(*res)[nei2] += 1;
+	  VECTOR(*res)[nei] += 1;
+	  VECTOR(*res)[node] += 1;
+	}
+      }
+    }
+
+#ifdef TRANSIT
+    if (mode == IGRAPH_TRANSITIVITY_ZERO && triples == 0)
+      VECTOR(*res)[node] = 0.0;
+    else
+      VECTOR(*res)[node] /= triples;
+#endif
+  }
+
+  igraph_free(neis);
+  igraph_adjlist_destroy(&allneis);
+  igraph_vector_int_destroy(&rank);
+	igraph_vector_destroy(&degree);
+  igraph_vector_int_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(5);
diff --git a/src/triangles_template1.h b/src/triangles_template1.h
new file mode 100644
index 0000000..6f77fd2
--- /dev/null
+++ b/src/triangles_template1.h
@@ -0,0 +1,93 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sts=2 sw=2 et: */
+/* 
+   IGraph library.
+   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
+
+*/
+
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vit_t vit;
+  long int nodes_to_calc;
+  igraph_vector_t *neis1, *neis2;
+#ifdef TRIPLES
+  igraph_real_t triples;
+#endif
+  igraph_real_t triangles;
+  long int i, j, k;
+  long int neilen1, neilen2;
+  long int *neis;
+  igraph_lazy_adjlist_t adjlist;
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+
+  neis=igraph_Calloc(no_of_nodes, long int);
+  if (neis==0) {
+    IGRAPH_ERROR("local undirected transitivity failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, neis);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+
+  igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL, IGRAPH_SIMPLIFY);
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);  
+
+  for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    long int node=IGRAPH_VIT_GET(vit);
+    
+    IGRAPH_ALLOW_INTERRUPTION();
+    
+    neis1=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) node);
+    neilen1=igraph_vector_size(neis1);
+    for (j=0; j<neilen1; j++) {
+      neis[ (long int)VECTOR(*neis1)[j] ] = i+1;
+    }
+#ifdef TRIPLES
+    triples = (double)neilen1*(neilen1-1);
+#endif
+    triangles = 0;
+
+    for (j=0; j<neilen1; j++) {
+      long int v=(long int) VECTOR(*neis1)[j];
+      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;
+				}
+      }
+    }
+
+#ifdef TRANSIT		
+    if (mode == IGRAPH_TRANSITIVITY_ZERO && triples == 0)
+      VECTOR(*res)[i] = 0.0;
+    else
+      VECTOR(*res)[i] = triangles/triples;
+#else 
+		VECTOR(*res)[i] = triangles/2;
+#endif
+  }
+
+  igraph_lazy_adjlist_destroy(&adjlist);
+  igraph_Free(neis);
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(3);
diff --git a/src/type_indexededgelist.c b/src/type_indexededgelist.c
new file mode 100644
index 0000000..f292ceb
--- /dev/null
+++ b/src/type_indexededgelist.c
@@ -0,0 +1,1702 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   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
+
+*/
+
+#include "igraph_datatype.h"
+#include "igraph_interface.h"
+#include "igraph_attributes.h"
+#include "igraph_memory.h"
+#include <string.h>		/* memset & co. */
+#include "config.h"
+
+/* Internal functions */
+
+int igraph_i_create_start(igraph_vector_t *res, igraph_vector_t *el, igraph_vector_t *index, 
+			  igraph_integer_t nodes);
+
+/**
+ * \section about_basic_interface
+ *
+ * <para>This is the very minimal API in \a igraph. All the other
+ * functions use this minimal set for creating and manipulating
+ * graphs.</para>
+ * 
+ * <para>This is a very important principle since it makes possible to
+ * implement other data representations by implementing only this
+ * minimal set.</para>
+ */
+
+/** 
+ * \ingroup interface
+ * \function igraph_empty
+ * \brief Creates an empty graph with some vertices and no edges.
+ *
+ * </para><para>
+ * The most basic constructor, all the other constructors should call
+ * this to create a minimal graph object. Our use of the term "empty graph"
+ * in the above description should be distinguished from the mathematical
+ * definition of the empty or null graph. Strictly speaking, the empty or null
+ * graph in graph theory is the graph with no vertices and no edges. However
+ * by "empty graph" as used in \c igraph we mean a graph having zero or more
+ * vertices, but no edges.
+ * \param graph Pointer to a not-yet initialized graph object.
+ * \param n The number of vertices in the graph, a non-negative
+ *          integer number is expected.
+ * \param directed Boolean; whether the graph is directed or not. Supported
+ *        values are:
+ *        \clist
+ *        \cli IGRAPH_DIRECTED
+ *          The graph will be \em directed.
+ *        \cli IGRAPH_UNDIRECTED
+ *          The graph will be \em undirected.
+ *        \endclist
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid number of vertices.
+ * 
+ * Time complexity: O(|V|) for a graph with
+ * |V| vertices (and no edges).
+ * 
+ * \example examples/simple/igraph_empty.c
+ */
+int igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed) {
+  return igraph_empty_attrs(graph, n, directed, 0);
+}
+
+
+/** 
+ * \ingroup interface
+ * \function igraph_empty_attrs
+ * \brief Creates an empty graph with some vertices, no edges and some graph attributes.
+ *
+ * </para><para>
+ * Use this instead of \ref igraph_empty() if you wish to add some graph
+ * attributes right after initialization. This function is currently
+ * not very interesting for the ordinary user. Just supply 0 here or 
+ * use \ref igraph_empty().
+ * \param graph Pointer to a not-yet initialized graph object.
+ * \param n The number of vertices in the graph; a non-negative
+ *          integer number is expected.
+ * \param directed Boolean; whether the graph is directed or not. Supported
+ *        values are:
+ *        \clist
+ *        \cli IGRAPH_DIRECTED
+ *          Create a \em directed graph.
+ *        \cli IGRAPH_UNDIRECTED
+ *          Create an \em undirected graph.
+ *        \endclist
+ * \param attr The attributes. 
+ * \return Error code:
+ *         \c IGRAPH_EINVAL: invalid number of vertices.
+ * 
+ * Time complexity: O(|V|) for a graph with
+ * |V| vertices (and no edges).
+ */
+int igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, void* attr) {
+
+  if (n<0) {
+    IGRAPH_ERROR("cannot create empty graph with negative number of vertices",
+		  IGRAPH_EINVAL);
+  }
+  
+  if (!IGRAPH_FINITE(n)) {
+    IGRAPH_ERROR("number of vertices is not finite (NA, NaN or Inf)", IGRAPH_EINVAL);
+  }
+
+  graph->n=0;
+  graph->directed=directed;
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->from, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->to, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->oi, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->ii, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->os, 1);
+  IGRAPH_VECTOR_INIT_FINALLY(&graph->is, 1);
+
+  VECTOR(graph->os)[0]=0;
+  VECTOR(graph->is)[0]=0;
+
+  /* init attributes */
+  graph->attr=0;
+  IGRAPH_CHECK(igraph_i_attribute_init(graph, attr));
+
+  /* add the vertices */
+  IGRAPH_CHECK(igraph_add_vertices(graph, n, 0));
+  
+  IGRAPH_FINALLY_CLEAN(6);
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_destroy
+ * \brief Frees the memory allocated for a graph object. 
+ * 
+ * </para><para>
+ * This function should be called for every graph object exactly once.
+ *
+ * </para><para>
+ * This function invalidates all iterators (of course), but the
+ * iterators of a graph should be destroyed before the graph itself
+ * anyway. 
+ * \param graph Pointer to the graph to free.
+ * \return Error code.
+ * 
+ * Time complexity: operating system specific.
+ */
+int igraph_destroy(igraph_t *graph) {
+
+  IGRAPH_I_ATTRIBUTE_DESTROY(graph);
+
+  igraph_vector_destroy(&graph->from);
+  igraph_vector_destroy(&graph->to);
+  igraph_vector_destroy(&graph->oi);
+  igraph_vector_destroy(&graph->ii);
+  igraph_vector_destroy(&graph->os);
+  igraph_vector_destroy(&graph->is);
+  
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_copy
+ * \brief Creates an exact (deep) copy of a graph.
+ * 
+ * </para><para>
+ * This function deeply copies a graph object to create an exact
+ * replica of it. The new replica should be destroyed by calling
+ * \ref igraph_destroy() on it when not needed any more.
+ * 
+ * </para><para>
+ * You can also create a shallow copy of a graph by simply using the
+ * standard assignment operator, but be careful and do \em not
+ * destroy a shallow replica. To avoid this mistake, creating shallow
+ * copies is not recommended.
+ * \param to Pointer to an uninitialized graph object.
+ * \param from Pointer to the graph object to copy.
+ * \return Error code.
+ *
+ * Time complexity:  O(|V|+|E|) for a
+ * graph with |V| vertices and
+ * |E| edges.
+ * 
+ * \example examples/simple/igraph_copy.c
+ */
+
+int igraph_copy(igraph_t *to, const igraph_t *from) {
+  to->n=from->n;
+  to->directed=from->directed;
+  IGRAPH_CHECK(igraph_vector_copy(&to->from, &from->from));
+  IGRAPH_FINALLY(igraph_vector_destroy, &to->from);
+  IGRAPH_CHECK(igraph_vector_copy(&to->to, &from->to));
+  IGRAPH_FINALLY(igraph_vector_destroy, &to->to);
+  IGRAPH_CHECK(igraph_vector_copy(&to->oi, &from->oi));
+  IGRAPH_FINALLY(igraph_vector_destroy, &to->oi);
+  IGRAPH_CHECK(igraph_vector_copy(&to->ii, &from->ii));
+  IGRAPH_FINALLY(igraph_vector_destroy, &to->ii);
+  IGRAPH_CHECK(igraph_vector_copy(&to->os, &from->os));
+  IGRAPH_FINALLY(igraph_vector_destroy, &to->os);
+  IGRAPH_CHECK(igraph_vector_copy(&to->is, &from->is));
+  IGRAPH_FINALLY(igraph_vector_destroy, &to->is);
+
+  IGRAPH_I_ATTRIBUTE_COPY(to, from, 1,1,1); /* does IGRAPH_CHECK */
+
+  IGRAPH_FINALLY_CLEAN(6);
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_add_edges
+ * \brief Adds edges to a graph object. 
+ * 
+ * </para><para>
+ * The edges are given in a vector, the
+ * first two elements define the first edge (the order is
+ * <code>from</code>, <code>to</code> for directed
+ * graphs). The vector 
+ * should contain even number of integer numbers between zero and the
+ * number of vertices in the graph minus one (inclusive). If you also
+ * want to add new vertices, call igraph_add_vertices() first.
+ * \param graph The graph to which the edges will be added.
+ * \param edges The edges themselves.
+ * \param attr The attributes of the new edges, only used by high level
+ *        interfaces currently, you can supply 0 here.
+ * \return Error code:
+ *    \c IGRAPH_EINVEVECTOR: invalid (odd)
+ *    edges vector length, \c IGRAPH_EINVVID:
+ *    invalid vertex id in edges vector. 
+ *
+ * This function invalidates all iterators.
+ *
+ * </para><para>
+ * Time complexity: O(|V|+|E|) where
+ * |V| is the number of vertices and
+ * |E| is the number of
+ * edges in the \em new, extended graph.
+ * 
+ * \example examples/simple/igraph_add_edges.c
+ */
+int igraph_add_edges(igraph_t *graph, const igraph_vector_t *edges,
+		     void *attr) {
+  long int no_of_edges=igraph_vector_size(&graph->from);
+  long int edges_to_add=igraph_vector_size(edges)/2;
+  long int i=0;
+  igraph_error_handler_t *oldhandler;
+  int ret1, ret2;
+  igraph_vector_t newoi, newii;
+  igraph_bool_t directed=igraph_is_directed(graph);
+
+  if (igraph_vector_size(edges) % 2 != 0) {
+    IGRAPH_ERROR("invalid (odd) length of edges vector", IGRAPH_EINVEVECTOR);
+  }
+  if (!igraph_vector_isininterval(edges, 0, igraph_vcount(graph)-1)) {
+    IGRAPH_ERROR("cannot add edges", IGRAPH_EINVVID);
+  }
+
+  /* from & to */
+  IGRAPH_CHECK(igraph_vector_reserve(&graph->from, no_of_edges+edges_to_add));
+  IGRAPH_CHECK(igraph_vector_reserve(&graph->to  , no_of_edges+edges_to_add));
+
+  while (i<edges_to_add*2) {
+    if (directed || VECTOR(*edges)[i] > VECTOR(*edges)[i+1]) {
+      igraph_vector_push_back(&graph->from, VECTOR(*edges)[i++]); /* reserved */
+      igraph_vector_push_back(&graph->to,   VECTOR(*edges)[i++]); /* reserved */
+    } else {
+      igraph_vector_push_back(&graph->to,   VECTOR(*edges)[i++]); /* reserved */
+      igraph_vector_push_back(&graph->from, VECTOR(*edges)[i++]); /* reserved */
+    }      
+  }
+
+  /* disable the error handler temporarily */
+  oldhandler=igraph_set_error_handler(igraph_error_handler_ignore);
+    
+  /* oi & ii */
+  ret1=igraph_vector_init(&newoi, no_of_edges);
+  ret2=igraph_vector_init(&newii, no_of_edges);
+  if (ret1 != 0 || ret2 != 0) {
+    igraph_vector_resize(&graph->from, no_of_edges); /* gets smaller */
+    igraph_vector_resize(&graph->to, no_of_edges);   /* gets smaller */
+    igraph_set_error_handler(oldhandler);
+    IGRAPH_ERROR("cannot add edges", IGRAPH_ERROR_SELECT_2(ret1, ret2));
+  }  
+  ret1=igraph_vector_order(&graph->from, &graph->to, &newoi, graph->n);
+  ret2=igraph_vector_order(&graph->to  , &graph->from, &newii, graph->n);
+  if (ret1 != 0 || ret2 != 0) {
+    igraph_vector_resize(&graph->from, no_of_edges);
+    igraph_vector_resize(&graph->to, no_of_edges);
+    igraph_vector_destroy(&newoi);
+    igraph_vector_destroy(&newii);
+    igraph_set_error_handler(oldhandler);
+    IGRAPH_ERROR("cannot add edges", IGRAPH_ERROR_SELECT_2(ret1, ret2));
+  }  
+
+  /* Attributes */
+  if (graph->attr) { 
+    igraph_set_error_handler(oldhandler);
+    ret1=igraph_i_attribute_add_edges(graph, edges, attr);
+    igraph_set_error_handler(igraph_error_handler_ignore);
+    if (ret1 != 0) {
+      igraph_vector_resize(&graph->from, no_of_edges);
+      igraph_vector_resize(&graph->to, no_of_edges);
+      igraph_vector_destroy(&newoi);
+      igraph_vector_destroy(&newii);
+      igraph_set_error_handler(oldhandler);
+      IGRAPH_ERROR("cannot add edges", ret1);
+    }  
+  }
+  
+  /* os & is, its length does not change, error safe */
+  igraph_i_create_start(&graph->os, &graph->from, &newoi, graph->n);
+  igraph_i_create_start(&graph->is, &graph->to  , &newii, graph->n);
+
+  /* everything went fine  */
+  igraph_vector_destroy(&graph->oi);
+  igraph_vector_destroy(&graph->ii);
+  graph->oi=newoi;
+  graph->ii=newii;
+  igraph_set_error_handler(oldhandler);
+  
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_add_vertices
+ * \brief Adds vertices to a graph. 
+ *
+ * </para><para>
+ * This function invalidates all iterators.
+ *
+ * \param graph The graph object to extend.
+ * \param nv Non-negative integer giving the number of 
+ *           vertices to add.
+ * \param attr The attributes of the new vertices, only used by 
+ *           high level interfaces, you can supply 0 here.
+ * \return Error code: 
+ *         \c IGRAPH_EINVAL: invalid number of new
+ *         vertices. 
+ *
+ * Time complexity: O(|V|) where
+ * |V| is 
+ * the number of vertices in the \em new, extended graph.
+ * 
+ * \example examples/simple/igraph_add_vertices.c
+ */
+int igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr) {
+  long int ec=igraph_ecount(graph);
+  long int i;
+
+  if (nv < 0) {
+    IGRAPH_ERROR("cannot add negative number of vertices", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vector_reserve(&graph->os, graph->n+nv+1));
+  IGRAPH_CHECK(igraph_vector_reserve(&graph->is, graph->n+nv+1));
+  
+  igraph_vector_resize(&graph->os, graph->n+nv+1); /* reserved */
+  igraph_vector_resize(&graph->is, graph->n+nv+1); /* reserved */
+  for (i=graph->n+1; i<graph->n+nv+1; i++) {
+    VECTOR(graph->os)[i]=ec;
+    VECTOR(graph->is)[i]=ec;
+  }
+  
+  graph->n += nv;   
+  
+  if (graph->attr) {
+    IGRAPH_CHECK(igraph_i_attribute_add_vertices(graph, nv, attr));
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_delete_edges
+ * \brief Removes edges from a graph.
+ *
+ * </para><para>
+ * The edges to remove are given as an edge selector.
+ *
+ * </para><para>
+ * This function cannot remove vertices, they will be kept, even if
+ * they lose all their edges.
+ *
+ * </para><para>
+ * This function invalidates all iterators.
+ * \param graph The graph to work on.
+ * \param edges The edges to remove.
+ * \return Error code.
+ *
+ * Time complexity: O(|V|+|E|) where
+ * |V| 
+ * and |E| are the number of vertices
+ * and edges in the \em original graph, respectively.
+ * 
+ * \example examples/simple/igraph_delete_edges.c
+ */
+int igraph_delete_edges(igraph_t *graph, igraph_es_t edges) {
+  long int no_of_edges=igraph_ecount(graph);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int edges_to_remove=0;
+  long int remaining_edges;
+  igraph_eit_t eit;
+  
+  igraph_vector_t newfrom, newto, newoi;
+
+  int *mark;
+  long int i, j;
+  
+  mark=igraph_Calloc(no_of_edges, int);
+  if (mark==0) {
+    IGRAPH_ERROR("Cannot delete edges", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, mark);
+
+  IGRAPH_CHECK(igraph_eit_create(graph, edges, &eit));
+  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
+
+  for (IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
+    long int e=IGRAPH_EIT_GET(eit);
+    if (mark[e]==0) {
+      edges_to_remove++;
+      mark[e]++;
+    }
+  }
+  remaining_edges=no_of_edges-edges_to_remove;
+
+  /* We don't need the iterator any more */
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&newfrom, remaining_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&newto, remaining_edges);
+  
+  /* Actually remove the edges, move from pos i to pos j in newfrom/newto */
+  for (i=0,j=0; j<remaining_edges; i++) {
+    if (mark[i]==0) {
+      VECTOR(newfrom)[j] = VECTOR(graph->from)[i];
+      VECTOR(newto)[j] = VECTOR(graph->to)[i];
+      j++;
+    }
+  }
+
+  /* Create index, this might require additional memory */
+  IGRAPH_VECTOR_INIT_FINALLY(&newoi, remaining_edges);
+  IGRAPH_CHECK(igraph_vector_order(&newfrom, &newto, &newoi, no_of_nodes));
+  IGRAPH_CHECK(igraph_vector_order(&newto, &newfrom, &graph->ii, no_of_nodes));
+
+  /* Edge attributes, we need an index that gives the ids of the 
+     original edges for every new edge. 
+  */
+  if (graph->attr) {    
+    igraph_vector_t idx;
+    IGRAPH_VECTOR_INIT_FINALLY(&idx, remaining_edges);
+    for (i=0, j=0; i<no_of_edges; i++) {
+      if (mark[i] == 0) {
+	VECTOR(idx)[j++] = i;
+      }
+    }
+    IGRAPH_CHECK(igraph_i_attribute_permute_edges(graph, graph, &idx));
+    igraph_vector_destroy(&idx);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  /* Ok, we've all memory needed, free the old structure  */
+  igraph_vector_destroy(&graph->from);
+  igraph_vector_destroy(&graph->to);
+  igraph_vector_destroy(&graph->oi);
+  graph->from=newfrom;
+  graph->to=newto;
+  graph->oi=newoi;
+  IGRAPH_FINALLY_CLEAN(3);
+
+  igraph_Free(mark);
+  IGRAPH_FINALLY_CLEAN(1);
+  
+  /* Create start vectors, no memory is needed for this */
+  igraph_i_create_start(&graph->os, &graph->from, &graph->oi, 
+			(igraph_integer_t) no_of_nodes);
+  igraph_i_create_start(&graph->is, &graph->to,   &graph->ii, 
+			(igraph_integer_t) no_of_nodes);
+  
+  /* Nothing to deallocate... */
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_delete_vertices
+ * \brief Removes vertices (with all their edges) from the graph.
+ *
+ * </para><para>
+ * This function changes the ids of the vertices (except in some very
+ * special cases, but these should not be relied on anyway).
+ *
+ * </para><para>
+ * This function invalidates all iterators.
+ * 
+ * \param graph The graph to work on.
+ * \param vertices The ids of the vertices to remove in a 
+ *                 vector. The vector may contain the same id more
+ *                 than once.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ *
+ * Time complexity: O(|V|+|E|),
+ * |V| and 
+ * |E| are the number of vertices and
+ * edges in the original graph.
+ * 
+ * \example examples/simple/igraph_delete_vertices.c
+ */
+int igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices) {
+  return igraph_delete_vertices_idx(graph, vertices, /* idx= */ 0, 
+				    /* invidx= */ 0);
+}
+
+int igraph_delete_vertices_idx(igraph_t *graph, const igraph_vs_t vertices,
+			       igraph_vector_t *idx, 
+			       igraph_vector_t *invidx) {
+
+  long int no_of_edges=igraph_ecount(graph);
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_vector_t edge_recoding, vertex_recoding;
+  igraph_vector_t *my_vertex_recoding=&vertex_recoding;
+  igraph_vit_t vit;
+  igraph_t newgraph;
+  long int i, j;
+  long int remaining_vertices, remaining_edges;
+
+  if (idx) {
+    my_vertex_recoding=idx;
+    IGRAPH_CHECK(igraph_vector_resize(idx, no_of_nodes));
+    igraph_vector_null(idx);
+  } else { 
+    IGRAPH_VECTOR_INIT_FINALLY(&vertex_recoding, no_of_nodes);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&edge_recoding, no_of_edges);
+ 
+  IGRAPH_CHECK(igraph_vit_create(graph, vertices, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  
+  /* mark the vertices to delete */
+  for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit) ) {
+    long int vertex=IGRAPH_VIT_GET(vit);
+    if (vertex < 0 || vertex >= no_of_nodes) {
+      IGRAPH_ERROR("Cannot delete vertices", IGRAPH_EINVVID);
+    }
+    VECTOR(*my_vertex_recoding)[vertex]=1;
+  }
+  /* create vertex recoding vector */
+  for (remaining_vertices=0, i=0; i<no_of_nodes; i++) {
+    if (VECTOR(*my_vertex_recoding)[i]==0) {
+      VECTOR(*my_vertex_recoding)[i]=remaining_vertices+1;
+      remaining_vertices++;
+    } else { 
+      VECTOR(*my_vertex_recoding)[i]=0;
+    }
+  }
+  /* create edge recoding vector */
+  for (remaining_edges=0, i=0; i<no_of_edges; i++) {
+    long int from=(long int) VECTOR(graph->from)[i];
+    long int to=(long int) VECTOR(graph->to)[i];
+    if (VECTOR(*my_vertex_recoding)[from] != 0 &&
+	VECTOR(*my_vertex_recoding)[to  ] != 0) {
+      VECTOR(edge_recoding)[i]=remaining_edges+1;
+      remaining_edges++;
+    } 
+  }
+
+  /* start creating the graph */
+  newgraph.n=(igraph_integer_t) remaining_vertices;
+  newgraph.directed=graph->directed;  
+
+  /* allocate vectors */
+  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.from, remaining_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.to, remaining_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.oi, remaining_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.ii, remaining_edges);
+  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.os, remaining_vertices+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.is, remaining_vertices+1);
+  
+  /* Add the edges */
+  for (i=0, j=0; j<remaining_edges; i++) {
+    if (VECTOR(edge_recoding)[i]>0) {
+      long int from=(long int) VECTOR(graph->from)[i];
+      long int to=(long int) VECTOR(graph->to  )[i];
+      VECTOR(newgraph.from)[j]=VECTOR(*my_vertex_recoding)[from]-1;
+      VECTOR(newgraph.to  )[j]=VECTOR(*my_vertex_recoding)[to]-1;
+      j++;
+    }
+  }
+  /* update oi & ii */
+  IGRAPH_CHECK(igraph_vector_order(&newgraph.from, &newgraph.to, &newgraph.oi, 
+				   remaining_vertices));
+  IGRAPH_CHECK(igraph_vector_order(&newgraph.to, &newgraph.from, &newgraph.ii, 
+				   remaining_vertices));  
+
+  IGRAPH_CHECK(igraph_i_create_start(&newgraph.os, &newgraph.from, 
+				     &newgraph.oi, (igraph_integer_t) 
+				     remaining_vertices));
+  IGRAPH_CHECK(igraph_i_create_start(&newgraph.is, &newgraph.to,
+				     &newgraph.ii, (igraph_integer_t) 
+				     remaining_vertices));
+  
+  /* attributes */
+  IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 
+			  /*graph=*/ 1, /*vertex=*/0, /*edge=*/0);
+  IGRAPH_FINALLY_CLEAN(6);
+  IGRAPH_FINALLY(igraph_destroy, &newgraph);
+
+  if (newgraph.attr) {
+    igraph_vector_t iidx;
+    IGRAPH_VECTOR_INIT_FINALLY(&iidx, remaining_vertices);
+    for (i=0; i<no_of_nodes; i++) {
+      long int jj=(long int) VECTOR(*my_vertex_recoding)[i];
+      if (jj != 0) {
+	VECTOR(iidx)[ jj-1 ] = i;
+      }
+    }
+    IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph,
+						     &newgraph,
+						     &iidx));
+    IGRAPH_CHECK(igraph_vector_resize(&iidx, remaining_edges));
+    for (i=0; i<no_of_edges; i++) {
+      long int jj=(long int) VECTOR(edge_recoding)[i];
+      if (jj != 0) {
+	VECTOR(iidx)[ jj-1 ] = i;
+      }
+    }
+    IGRAPH_CHECK(igraph_i_attribute_permute_edges(graph, &newgraph, &iidx));
+    igraph_vector_destroy(&iidx);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+	       
+  igraph_vit_destroy(&vit);
+  igraph_vector_destroy(&edge_recoding);
+  igraph_destroy(graph);
+  *graph=newgraph;
+
+  IGRAPH_FINALLY_CLEAN(3);  
+
+  /* TODO: this is duplicate */
+  if (invidx) {
+    IGRAPH_CHECK(igraph_vector_resize(invidx, remaining_vertices));
+    for (i=0; i<no_of_nodes; i++) {
+      long int newid=(long int) VECTOR(*my_vertex_recoding)[i];
+      if (newid != 0) {
+	VECTOR(*invidx)[newid-1] = i;
+      }
+    }
+  }
+
+  if (!idx) {
+    igraph_vector_destroy(my_vertex_recoding);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_vcount
+ * \brief The number of vertices in a graph.
+ * 
+ * \param graph The graph.
+ * \return Number of vertices.
+ *
+ * Time complexity: O(1)
+ */
+igraph_integer_t igraph_vcount(const igraph_t *graph) {
+  return graph->n;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_ecount
+ * \brief The number of edges in a graph.
+ * 
+ * \param graph The graph.
+ * \return Number of edges.
+ *
+ * Time complexity: O(1)
+ */
+igraph_integer_t igraph_ecount(const igraph_t *graph) {
+  return (igraph_integer_t) igraph_vector_size(&graph->from);
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_neighbors
+ * \brief Adjacent vertices to a vertex.
+ *
+ * \param graph The graph to work on.
+ * \param neis This vector will contain the result. The vector should
+ *        be initialized beforehand and will be resized. Starting from igraph 
+ *        version 0.4 this vector is always sorted, the vertex ids are
+ *        in increasing order.
+ * \param pnode The id of the node for which the adjacent vertices are
+ *        to be searched.
+ * \param mode Defines the way adjacent vertices are searched in
+ *        directed graphs. It can have the following values:
+ *        \c IGRAPH_OUT, vertices reachable by an
+ *        edge from the specified vertex are searched;
+ *        \c IGRAPH_IN, vertices from which the
+ *        specified vertex is reachable are searched;
+ *        \c IGRAPH_ALL, both kinds of vertices are
+ *        searched. 
+ *        This parameter is ignored for undirected graphs.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ *         \c IGRAPH_EINVMODE: invalid mode argument.
+ *         \c IGRAPH_ENOMEM: not enough memory.
+ * 
+ * Time complexity: O(d),
+ * d is the number
+ * of adjacent vertices to the queried vertex.
+ * 
+ * \example examples/simple/igraph_neighbors.c
+ */
+int igraph_neighbors(const igraph_t *graph, igraph_vector_t *neis, igraph_integer_t pnode, 
+		     igraph_neimode_t mode) {
+
+  long int length=0, idx=0;   
+  long int i, j;
+
+  long int node=pnode;
+
+  if (node<0 || node>igraph_vcount(graph)-1) {
+    IGRAPH_ERROR("cannot get neighbors", IGRAPH_EINVVID);
+  }
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("cannot get neighbors", IGRAPH_EINVMODE);
+  }
+
+  if (! graph->directed) {
+    mode=IGRAPH_ALL;
+  }
+
+  /* Calculate needed space first & allocate it*/
+
+  if (mode & IGRAPH_OUT) {
+    length += (VECTOR(graph->os)[node+1] - VECTOR(graph->os)[node]);
+  }
+  if (mode & IGRAPH_IN) {
+    length += (VECTOR(graph->is)[node+1] - VECTOR(graph->is)[node]);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(neis, length));
+  
+  if (!igraph_is_directed(graph) || mode != IGRAPH_ALL) {
+
+    if (mode & IGRAPH_OUT) {
+      j=(long int) VECTOR(graph->os)[node+1];
+      for (i=(long int) VECTOR(graph->os)[node]; i<j; i++) {
+	VECTOR(*neis)[idx++] = 
+	  VECTOR(graph->to)[ (long int)VECTOR(graph->oi)[i] ];
+      }
+    }
+    if (mode & IGRAPH_IN) {
+      j=(long int) VECTOR(graph->is)[node+1];
+      for (i=(long int) VECTOR(graph->is)[node]; i<j; i++) {
+	VECTOR(*neis)[idx++] =
+	  VECTOR(graph->from)[ (long int)VECTOR(graph->ii)[i] ];
+      }
+    }
+  } else {
+    /* both in- and out- neighbors in a directed graph,
+       we need to merge the two 'vectors' */
+    long int jj1=(long int) VECTOR(graph->os)[node+1];
+    long int j2=(long int) VECTOR(graph->is)[node+1];
+    long int i1=(long int) VECTOR(graph->os)[node];
+    long int i2=(long int) VECTOR(graph->is)[node];
+    while (i1 < jj1 && i2 < j2) {
+      long int n1=(long int) VECTOR(graph->to)[ 
+		       (long int)VECTOR(graph->oi)[i1] ];
+      long int n2=(long int) VECTOR(graph->from)[
+		       (long int)VECTOR(graph->ii)[i2] ];
+      if (n1<n2) {
+	VECTOR(*neis)[idx++]=n1;
+	i1++;
+      } else if (n1>n2) {
+	VECTOR(*neis)[idx++]=n2;
+	i2++;
+      } else {
+	VECTOR(*neis)[idx++]=n1;
+	VECTOR(*neis)[idx++]=n2;
+	i1++;
+	i2++;
+      }
+    }
+    while (i1 < jj1) {
+      long int n1=(long int) VECTOR(graph->to)[ 
+		       (long int)VECTOR(graph->oi)[i1] ];
+      VECTOR(*neis)[idx++]=n1;
+      i1++;
+    }
+    while (i2 < j2) {
+      long int n2=(long int) VECTOR(graph->from)[ 
+		       (long int)VECTOR(graph->ii)[i2] ];
+      VECTOR(*neis)[idx++]=n2;
+      i2++;
+    }
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup internal
+ * 
+ */
+
+int igraph_i_create_start(igraph_vector_t *res, igraph_vector_t *el, igraph_vector_t *iindex, 
+			  igraph_integer_t nodes) {
+  
+# define EDGE(i) (VECTOR(*el)[ (long int) VECTOR(*iindex)[(i)] ])
+  
+  long int no_of_nodes;
+  long int no_of_edges;
+  long int i, j, idx;
+  
+  no_of_nodes=nodes;
+  no_of_edges=igraph_vector_size(el);
+  
+  /* result */
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes+1));
+  
+  /* create the index */
+
+  if (igraph_vector_size(el)==0) {
+    /* empty graph */
+    igraph_vector_null(res);
+  } else {
+    idx=-1;
+    for (i=0; i<=EDGE(0); i++) {
+      idx++; VECTOR(*res)[idx]=0;
+    }
+    for (i=1; i<no_of_edges; i++) {
+      long int n=(long int) (EDGE(i) - EDGE((long int)VECTOR(*res)[idx]));
+      for (j=0; j<n; j++) {
+	idx++; VECTOR(*res)[idx]=i;
+      }
+    }
+    j=(long int) EDGE((long int)VECTOR(*res)[idx]);
+    for (i=0; i<no_of_nodes-j; i++) {
+      idx++; VECTOR(*res)[idx]=no_of_edges;
+    }
+  }
+
+  /* clean */
+
+# undef EDGE
+  return 0;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_is_directed
+ * \brief Is this a directed graph?
+ *
+ * \param graph The graph.
+ * \return Logical value, <code>TRUE</code> if the graph is directed,
+ * <code>FALSE</code> otherwise.
+ *
+ * Time complexity: O(1)
+ * 
+ * \example examples/simple/igraph_is_directed.c
+ */
+
+igraph_bool_t igraph_is_directed(const igraph_t *graph) {
+  return graph->directed;
+}
+
+/**
+ * \ingroup interface
+ * \function igraph_degree
+ * \brief The degree of some vertices in a graph.
+ *
+ * </para><para>
+ * This function calculates the in-, out- or total degree of the
+ * specified vertices. 
+ * \param graph The graph.
+ * \param res Vector, this will contain the result. It should be
+ *        initialized and will be resized to be the appropriate size.
+ * \param vids Vector, giving the vertex ids of which the degree will
+ *        be calculated.
+ * \param mode Defines the type of the degree. Valid modes are:
+ *        \c IGRAPH_OUT, out-degree;
+ *        \c IGRAPH_IN, in-degree;
+ *        \c IGRAPH_ALL, total degree (sum of the
+ *        in- and out-degree). 
+ *        This parameter is ignored for undirected graphs. 
+ * \param loops Boolean, gives whether the self-loops should be
+ *        counted.
+ * \return Error code:
+ *         \c IGRAPH_EINVVID: invalid vertex id.
+ *         \c IGRAPH_EINVMODE: invalid mode argument.
+ *
+ * Time complexity: O(v) if
+ * loops is 
+ * TRUE, and
+ * O(v*d)
+ * otherwise. v is the number of
+ * vertices for which the degree will be calculated, and
+ * d is their (average) degree. 
+ *
+ * \sa \ref igraph_strength() for the version that takes into account
+ * edge weights.
+ * 
+ * \example examples/simple/igraph_degree.c
+ */
+int igraph_degree(const igraph_t *graph, igraph_vector_t *res, 
+		  const igraph_vs_t vids, 
+		  igraph_neimode_t mode, igraph_bool_t loops) {
+
+  long int nodes_to_calc;
+  long int i, j;
+  igraph_vit_t vit;
+
+  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("degree calculation failed", IGRAPH_EINVMODE);
+  }
+  
+  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
+  if (!igraph_is_directed(graph)) {
+    mode=IGRAPH_ALL;
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
+  igraph_vector_null(res);
+
+  if (loops) {
+    if (mode & IGRAPH_OUT) {
+      for (IGRAPH_VIT_RESET(vit), i=0; 
+	   !IGRAPH_VIT_END(vit); 
+	   IGRAPH_VIT_NEXT(vit), i++) {
+	long int vid=IGRAPH_VIT_GET(vit);
+	VECTOR(*res)[i] += (VECTOR(graph->os)[vid+1]-VECTOR(graph->os)[vid]);
+      }
+    }
+    if (mode & IGRAPH_IN) {
+      for (IGRAPH_VIT_RESET(vit), i=0; 
+	   !IGRAPH_VIT_END(vit); 
+	   IGRAPH_VIT_NEXT(vit), i++) {
+	long int vid=IGRAPH_VIT_GET(vit);
+	VECTOR(*res)[i] += (VECTOR(graph->is)[vid+1]-VECTOR(graph->is)[vid]);
+      }
+    }
+  } else { /* no loops */
+    if (mode & IGRAPH_OUT) {
+      for (IGRAPH_VIT_RESET(vit), i=0; 
+	   !IGRAPH_VIT_END(vit); 
+	   IGRAPH_VIT_NEXT(vit), i++) {
+	long int vid=IGRAPH_VIT_GET(vit);
+	VECTOR(*res)[i] += (VECTOR(graph->os)[vid+1]-VECTOR(graph->os)[vid]);
+	for (j=(long int) VECTOR(graph->os)[vid]; 
+	     j<VECTOR(graph->os)[vid+1]; j++) {
+	  if (VECTOR(graph->to)[ (long int)VECTOR(graph->oi)[j] ]==vid) {
+	    VECTOR(*res)[i] -= 1;
+	  }
+	}
+      }
+    }
+    if (mode & IGRAPH_IN) {
+      for (IGRAPH_VIT_RESET(vit), i=0; 
+	   !IGRAPH_VIT_END(vit);
+	   IGRAPH_VIT_NEXT(vit), i++) {
+	long int vid=IGRAPH_VIT_GET(vit);
+	VECTOR(*res)[i] += (VECTOR(graph->is)[vid+1]-VECTOR(graph->is)[vid]);
+	for (j=(long int) VECTOR(graph->is)[vid]; 
+	     j<VECTOR(graph->is)[vid+1]; j++) {
+	  if (VECTOR(graph->from)[ (long int)VECTOR(graph->ii)[j] ]==vid) {
+	    VECTOR(*res)[i] -= 1;
+	  }
+	}
+      }
+    }
+  }  /* loops */
+
+  igraph_vit_destroy(&vit);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_edge
+ * \brief Gives the head and tail vertices of an edge.
+ * 
+ * \param graph The graph object.
+ * \param eid The edge id. 
+ * \param from Pointer to an \type igraph_integer_t. The tail of the edge
+ * will be placed here. 
+ * \param to Pointer to an \type igraph_integer_t. The head of the edge 
+ * will be placed here.
+ * \return Error code. The current implementation always returns with
+ * success. 
+ * \sa \ref igraph_get_eid() for the opposite operation.
+ * 
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(1).
+ */
+
+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;
+  }
+
+  return 0;
+}
+
+int igraph_edges(const igraph_t *graph, igraph_es_t eids,
+		 igraph_vector_t *edges) {
+  
+  igraph_eit_t eit;
+  long int n, ptr=0;
+
+  IGRAPH_CHECK(igraph_eit_create(graph, eids, &eit));
+  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);
+  }
+  
+  igraph_eit_destroy(&eit);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/* This is an unsafe macro. Only supply variable names, i.e. no
+   expressions as parameters, otherwise nasty things can happen */
+
+#define BINSEARCH(start,end,value,iindex,edgelist,N,pos)     \
+  do {                                                      \
+  while ((start) < (end)) {                                 \
+    long int mid=(start)+((end)-(start))/2;                 \
+    long int e=(long int) VECTOR((iindex))[mid];		    \
+    if (VECTOR((edgelist))[e] < (value)) {                  \
+      (start)=mid+1;                                        \
+    } else {                                                \
+      (end)=mid;                                            \
+    }                                                       \
+  }                                                         \
+  if ((start)<(N)) {                                        \
+    long int e=(long int) VECTOR((iindex))[(start)];	    \
+    if (VECTOR((edgelist))[e] == (value)) {                 \
+      *(pos)=(igraph_integer_t) e;			    \
+    }                                                       \
+  } } while(0)
+
+#define FIND_DIRECTED_EDGE(graph,xfrom,xto,eid)                     \
+  do {                                                              \
+    long int start=(long int) VECTOR(graph->os)[xfrom];		    \
+    long int end=(long int) VECTOR(graph->os)[xfrom+1];		    \
+    long int N=end;                                                 \
+    long int start2=(long int) VECTOR(graph->is)[xto];		    \
+    long int end2=(long int) VECTOR(graph->is)[xto+1];		    \
+    long int N2=end2;                                               \
+    if (end-start<end2-start2) {                                    \
+      BINSEARCH(start,end,xto,graph->oi,graph->to,N,eid);           \
+    } else {                                                        \
+      BINSEARCH(start2,end2,xfrom,graph->ii,graph->from,N2,eid);    \
+    }                                                               \
+  } while (0)
+
+#define FIND_UNDIRECTED_EDGE(graph,from,to,eid)                     \
+  do {                                                              \
+    long int xfrom1= from > to ? from : to;                         \
+    long int xto1= from > to ? to : from;                           \
+    FIND_DIRECTED_EDGE(graph,xfrom1,xto1,eid);                      \
+  } while (0)
+
+/**
+ * \function igraph_get_eid
+ * \brief Get the edge id from the end points of an edge.
+ * 
+ * For undirected graphs \c pfrom and \c pto are exchangeable.
+ *
+ * \param graph The graph object.
+ * \param eid Pointer to an integer, the edge id will be stored here.
+ * \param pfrom The starting point of the edge.
+ * \param pto The end point of the edge.
+ * \param directed Logical constant, whether to search for directed
+ *        edges in a directed graph. Ignored for undirected graphs.
+ * \param error Logical scalar, whether to report an error if the edge 
+ *        was not found. If it is false, then -1 will be assigned to \p eid.
+ * \return Error code. 
+ * \sa \ref igraph_edge() for the opposite operation.
+ * 
+ * Time complexity: O(log (d)), where d is smaller of the out-degree 
+ * of \c pfrom and in-degree of \c pto if \p directed is true. If \p directed 
+ * is false, then it is O(log(d)+log(d2)), where d is the same as before and 
+ * d2 is the minimum of the out-degree of \c pto and the in-degree of \c pfrom.
+ * 
+ * \example examples/simple/igraph_get_eid.c
+ * 
+ * Added in version 0.2.</para><para>
+ */
+
+int igraph_get_eid(const igraph_t *graph, igraph_integer_t *eid,
+		   igraph_integer_t pfrom, igraph_integer_t pto,
+		   igraph_bool_t directed, igraph_bool_t error) {
+
+  long int from=pfrom, to=pto;
+  long int nov=igraph_vcount(graph);
+
+  if (from < 0 || to < 0 || from > nov-1 || to > nov-1) {
+    IGRAPH_ERROR("cannot get edge id", IGRAPH_EINVVID);
+  }
+
+  *eid=-1;
+  if (igraph_is_directed(graph)) {
+
+    /* Directed graph */
+    FIND_DIRECTED_EDGE(graph,from,to,eid);
+    if (!directed && *eid < 0) {
+      FIND_DIRECTED_EDGE(graph,to,from,eid);
+    }
+    
+  } else {
+
+    /* Undirected graph, they only have one mode */
+    FIND_UNDIRECTED_EDGE(graph,from,to,eid);
+
+  }
+
+  if (*eid < 0) {
+    if (error) {
+      IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+    }
+  }
+  
+  return IGRAPH_SUCCESS;  
+}
+
+int igraph_get_eids_pairs(const igraph_t *graph, igraph_vector_t *eids,
+			  const igraph_vector_t *pairs, 
+			  igraph_bool_t directed, igraph_bool_t error);
+
+int igraph_get_eids_path(const igraph_t *graph, igraph_vector_t *eids,
+			 const igraph_vector_t *path, 
+			 igraph_bool_t directed, igraph_bool_t error);
+
+int igraph_get_eids_pairs(const igraph_t *graph, igraph_vector_t *eids,
+			  const igraph_vector_t *pairs, 
+			  igraph_bool_t directed, igraph_bool_t error) {
+  long int n=igraph_vector_size(pairs);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  igraph_integer_t eid=-1;
+    
+  if (n % 2 != 0) {
+    IGRAPH_ERROR("Cannot get edge ids, invalid length of edge ids",
+		 IGRAPH_EINVAL);
+  }
+  if (!igraph_vector_isininterval(pairs, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot get edge ids, invalid vertex id", IGRAPH_EINVVID);
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(eids, n/2));
+  
+  if (igraph_is_directed(graph)) {
+    for (i=0; i<n/2; i++) {
+      long int from=(long int) VECTOR(*pairs)[2*i];
+      long int to=(long int) VECTOR(*pairs)[2*i+1];
+
+      eid=-1;
+      FIND_DIRECTED_EDGE(graph,from,to,&eid);
+      if (!directed && eid < 0) {
+	FIND_DIRECTED_EDGE(graph,to,from,&eid);
+      }
+      
+      VECTOR(*eids)[i]=eid;
+      if (eid < 0 && error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  } else {
+    for (i=0; i<n/2; i++) {
+      long int from=(long int) VECTOR(*pairs)[2*i];
+      long int to=(long int) VECTOR(*pairs)[2*i+1];
+
+      eid=-1;
+      FIND_UNDIRECTED_EDGE(graph,from,to,&eid);
+      VECTOR(*eids)[i]=eid;
+      if (eid < 0 && error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_get_eids_path(const igraph_t *graph, igraph_vector_t *eids,
+			 const igraph_vector_t *path, 
+			 igraph_bool_t directed, igraph_bool_t error) {
+
+  long int n=igraph_vector_size(path);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  igraph_integer_t eid=-1;
+
+  if (!igraph_vector_isininterval(path, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot get edge ids, invalid vertex id", IGRAPH_EINVVID);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(eids, n==0 ? 0 : n-1));
+  
+  if (igraph_is_directed(graph)) {
+    for (i=0; i<n-1; i++) {
+      long int from=(long int) VECTOR(*path)[i];
+      long int to=(long int) VECTOR(*path)[i+1];
+      
+      eid=-1;
+      FIND_DIRECTED_EDGE(graph, from, to, &eid);
+      if (!directed && eid < 0) {
+	FIND_DIRECTED_EDGE(graph, to, from, &eid);
+      }
+      
+      VECTOR(*eids)[i]=eid;
+      if (eid < 0 && error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  } else {
+    for (i=0; i<n-1; i++) {
+      long int from=(long int) VECTOR(*path)[i];
+      long int to=(long int) VECTOR(*path)[i+1];
+      
+      eid=-1;
+      FIND_UNDIRECTED_EDGE(graph, from, to, &eid);
+      VECTOR(*eids)[i]=eid;
+      if (eid < 0 && error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  }
+  
+  return 0;
+}
+
+/** 
+ * \function igraph_get_eids
+ * Return edge ids based on the adjacent vertices.
+ * 
+ * This function operates in two modes. If the \c pairs argument is
+ * not a null pointer, but the \c path argument is, then it searches
+ * for the edge ids of all pairs of vertices given in \c pairs. The
+ * pairs of vertex ids are taken consecutively from the vector,
+ * i.e. <code>VECTOR(pairs)[0]</code> and
+ * <code>VECTOR(pairs)[1]</code> give the first 
+ * pair, <code>VECTOR(pairs)[2]</code> and
+ * <code>VECTOR(pairs)[3]</code> the second pair, etc.
+ * 
+ * </para><para>
+ * If the \c pairs argument is a null pointer, and \c path is not a
+ * null pointer, then the \c path is interpreted as a path given by
+ * vertex ids and the edges along the path are returned.
+ * 
+ * </para><para>
+ * If neither \c pairs nor \c path are null pointers, then both are
+ * considered (first \c pairs and then \c path), and the results are
+ * concatenated.
+ * 
+ * </para><para>
+ * If the \c error argument is true, then it is an error to give pairs
+ * of vertices that are not connected. Otherwise -1 is
+ * reported for not connected vertices.
+ * 
+ * </para><para>
+ * If there are multiple edges in the graph, then these are ignored;
+ * i.e. for a given pair of vertex ids, always the same edge id is
+ * returned, even if the pair is given multiple time in \c pairs or in
+ * \c path. See \ref igraph_get_eids_multi() for a similar function
+ * that works differently in case of multiple edges.
+ * 
+ * \param graph The input graph.
+ * \param eids Pointer to an initialized vector, the result is stored
+ *        here. It will be resized as needed.
+ * \param pairs Vector giving pairs of vertices, or a null pointer.
+ * \param path Vector giving vertex ids along a path, or a null
+ *        pointer.
+ * \param directed Logical scalar, whether to consider edge directions
+ *        in directed graphs. This is ignored for undirected graphs.
+ * \param error Logical scalar, whether it is an error to supply
+ *        non-connected vertices. If false, then -1 is
+ *        returned for non-connected pairs.
+ * \return Error code.
+ * 
+ * Time complexity: O(n log(d)), where n is the number of queried
+ * edges and d is the average degree of the vertices.
+ * 
+ * \sa \ref igraph_get_eid() for a single edge, \ref
+ * igraph_get_eids_multi() for a version that handles multiple edges
+ * better (at a cost).
+ * 
+ * \example examples/simple/igraph_get_eids.c
+ */
+
+int igraph_get_eids(const igraph_t *graph, igraph_vector_t *eids,
+		    const igraph_vector_t *pairs, 
+		    const igraph_vector_t *path, 
+		    igraph_bool_t directed, igraph_bool_t error) {
+
+  if (!pairs && !path) {
+    igraph_vector_clear(eids);
+    return 0;
+  } else if (pairs && !path) {
+    return igraph_get_eids_pairs(graph, eids, pairs, directed, error);
+  } else if (!pairs && path) { 
+    return igraph_get_eids_path(graph, eids, path, directed, error);
+  } else {
+    /* both */
+    igraph_vector_t tmp;
+    IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
+    IGRAPH_CHECK(igraph_get_eids_pairs(graph, eids, pairs, directed, error));
+    IGRAPH_CHECK(igraph_get_eids_path(graph, &tmp, path, directed, error));
+    IGRAPH_CHECK(igraph_vector_append(eids, &tmp));
+    igraph_vector_destroy(&tmp);
+    IGRAPH_FINALLY_CLEAN(1);
+    return 0;
+  }
+}
+
+#undef BINSEARCH
+#undef FIND_DIRECTED_EDGE
+#undef FIND_UNDIRECTED_EDGE
+
+#define BINSEARCH(start,end,value,iindex,edgelist,N,pos,seen)    \
+  do {                                                      \
+  while ((start) < (end)) {                                 \
+    long int mid=(start)+((end)-(start))/2;                 \
+    long int e=(long int) VECTOR((iindex))[mid];	    \
+    if (VECTOR((edgelist))[e] < (value)) {                  \
+      (start)=mid+1;                                        \
+    } else {                                                \
+      (end)=mid;                                            \
+    }                                                       \
+  }                                                         \
+  if ((start)<(N)) {                                        \
+    long int e=(long int) VECTOR((iindex))[(start)];	    \
+    while ((start)<(N) && seen[e] && VECTOR(edgelist)[e] == (value)) {	\
+      (start)++;					    \
+      e=(long int) VECTOR(iindex)[(start)];		    \
+    }				                            \
+    if ((start)<(N) && !(seen[e]) && VECTOR(edgelist)[e] == (value)) {	\
+      *(pos)=(igraph_integer_t) e;					\
+    }                                                       \
+  } } while(0)
+
+#define FIND_DIRECTED_EDGE(graph,xfrom,xto,eid,seen)		    \
+  do {                                                              \
+    long int start=(long int) VECTOR(graph->os)[xfrom];		    \
+    long int end=(long int) VECTOR(graph->os)[xfrom+1];		    \
+    long int N=end;                                                 \
+    long int start2=(long int) VECTOR(graph->is)[xto];		    \
+    long int end2=(long int) VECTOR(graph->is)[xto+1];		    \
+    long int N2=end2;                                               \
+    if (end-start<end2-start2) {                                    \
+      BINSEARCH(start,end,xto,graph->oi,graph->to,N,eid,seen);	    \
+    } else {                                                        \
+      BINSEARCH(start2,end2,xfrom,graph->ii,graph->from,N2,eid,seen);   \
+    }                                                               \
+  } while (0)
+
+#define FIND_UNDIRECTED_EDGE(graph,from,to,eid,seen)		    \
+  do {                                                              \
+    long int xfrom1= from > to ? from : to;                         \
+    long int xto1= from > to ? to : from;                           \
+    FIND_DIRECTED_EDGE(graph,xfrom1,xto1,eid,seen);		    \
+  } while (0)
+
+
+int igraph_get_eids_multipairs(const igraph_t *graph, igraph_vector_t *eids,
+			       const igraph_vector_t *pairs, 
+			       igraph_bool_t directed, igraph_bool_t error);
+
+int igraph_get_eids_multipath(const igraph_t *graph, igraph_vector_t *eids,
+			      const igraph_vector_t *path, 
+			      igraph_bool_t directed, igraph_bool_t error);
+
+int igraph_get_eids_multipairs(const igraph_t *graph, igraph_vector_t *eids,
+			       const igraph_vector_t *pairs, 
+			       igraph_bool_t directed, igraph_bool_t error) {
+
+  long int n=igraph_vector_size(pairs);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_bool_t *seen;
+  long int i;
+  igraph_integer_t eid=-1;
+    
+  if (n % 2 != 0) {
+    IGRAPH_ERROR("Cannot get edge ids, invalid length of edge ids",
+		 IGRAPH_EINVAL);
+  }
+  if (!igraph_vector_isininterval(pairs, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot get edge ids, invalid vertex id", IGRAPH_EINVVID);
+  }
+
+  seen=igraph_Calloc(no_of_edges, igraph_bool_t);
+  if (seen==0) {
+    IGRAPH_ERROR("Cannot get edge ids", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, seen);
+  IGRAPH_CHECK(igraph_vector_resize(eids, n/2));
+  
+  if (igraph_is_directed(graph)) {
+    for (i=0; i<n/2; i++) {
+      long int from=(long int) VECTOR(*pairs)[2*i];
+      long int to=(long int) VECTOR(*pairs)[2*i+1];
+
+      eid=-1;
+      FIND_DIRECTED_EDGE(graph,from,to,&eid,seen);
+      if (!directed && eid < 0) {
+	FIND_DIRECTED_EDGE(graph,to,from,&eid,seen);
+      }
+      
+      VECTOR(*eids)[i]=eid;
+      if (eid >= 0) {
+	seen[(long int)(eid)]=1;
+      } else if (error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  } else {
+    for (i=0; i<n/2; i++) {
+      long int from=(long int) VECTOR(*pairs)[2*i];
+      long int to=(long int) VECTOR(*pairs)[2*i+1];
+
+      eid=-1;
+      FIND_UNDIRECTED_EDGE(graph,from,to,&eid,seen);
+      VECTOR(*eids)[i]=eid;
+      if (eid >= 0) {
+	seen[(long int)(eid)]=1;
+      } else if (error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  }
+  
+  igraph_Free(seen);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+int igraph_get_eids_multipath(const igraph_t *graph, igraph_vector_t *eids,
+			      const igraph_vector_t *path, 
+			      igraph_bool_t directed, igraph_bool_t error) {
+  
+  long int n=igraph_vector_size(path);
+  long int no_of_nodes=igraph_vcount(graph);
+  long int no_of_edges=igraph_ecount(graph);
+  igraph_bool_t *seen;
+  long int i;
+  igraph_integer_t eid=-1;
+
+  if (!igraph_vector_isininterval(path, 0, no_of_nodes-1)) {
+    IGRAPH_ERROR("Cannot get edge ids, invalid vertex id", IGRAPH_EINVVID);
+  }
+  
+  seen=igraph_Calloc(no_of_edges, igraph_bool_t);
+  if (!seen) {
+    IGRAPH_ERROR("Cannot get edge ids", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, seen);
+  IGRAPH_CHECK(igraph_vector_resize(eids, n==0 ? 0 : n-1));
+  
+  if (igraph_is_directed(graph)) {
+    for (i=0; i<n-1; i++) {
+      long int from=(long int) VECTOR(*path)[i];
+      long int to=(long int) VECTOR(*path)[i+1];
+      
+      eid=-1;
+      FIND_DIRECTED_EDGE(graph, from, to, &eid, seen);
+      if (!directed && eid < 0) {
+	FIND_DIRECTED_EDGE(graph, to, from, &eid, seen);
+      }
+      
+      VECTOR(*eids)[i]=eid;
+      if (eid >= 0) {
+	seen[(long int)(eid)]=1;
+      } else if (error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  } else {
+    for (i=0; i<n-1; i++) {
+      long int from=(long int) VECTOR(*path)[i];
+      long int to=(long int) VECTOR(*path)[i+1];
+      
+      eid=-1;
+      FIND_UNDIRECTED_EDGE(graph, from, to, &eid, seen);
+      VECTOR(*eids)[i]=eid;
+      if (eid >= 0) {
+	seen[(long int)(eid)]=1;
+      } else if (error) {
+	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
+      }
+    }
+  }
+  
+  igraph_Free(seen);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+#undef BINSEARCH
+#undef FIND_DIRECTED_EDGE
+#undef FIND_UNDIRECTED_EDGE
+
+/** 
+ * \function igraph_get_eids_multi
+ * \brief Query edge ids based on their adjacent vertices, handle multiple edges.
+ * 
+ * This function operates in two modes. If the \c pairs argument is
+ * not a null pointer, but the \c path argument is, then it searches
+ * for the edge ids of all pairs of vertices given in \c pairs. The
+ * pairs of vertex ids are taken consecutively from the vector,
+ * i.e. <code>VECTOR(pairs)[0]</code> and
+ * <code>VECTOR(pairs)[1]</code> give the first pair,
+ * <code>VECTOR(pairs)[2]</code> and <code>VECTOR(pairs)[3]</code> the
+ * second pair, etc.
+ * 
+ * </para><para>
+ * If the \c pairs argument is a null pointer, and \c path is not a
+ * null pointer, then the \c path is interpreted as a path given by
+ * vertex ids and the edges along the path are returned.
+ * 
+ * </para><para>
+ * If the \c error argument is true, then it is an error to give pairs of
+ * vertices that are not connected. Otherwise -1 is
+ * returned for not connected vertex pairs.
+ *
+ * </para><para>
+ * An error is triggered if both \c pairs and \c path are non-null
+ * pointers. 
+ * 
+ * </para><para>
+ * This function handles multiple edges properly, i.e. if the same
+ * pair is given multiple times and they are indeed connected by
+ * multiple edges, then each time a different edge id is reported.
+ * 
+ * \param graph The input graph.
+ * \param eids Pointer to an initialized vector, the result is stored
+ *        here. It will be resized as needed.
+ * \param pairs Vector giving pairs of vertices, or a null pointer.
+ * \param path Vector giving vertex ids along a path, or a null
+ *        pointer.
+ * \param directed Logical scalar, whether to consider edge directions
+ *        in directed graphs. This is ignored for undirected graphs.
+ * \param error Logical scalar, whether to report an error if
+ *        non-connected vertices are specified. If false, then -1
+ *        is returned for non-connected vertex pairs.
+ * \return Error code.
+ * 
+ * Time complexity: O(|E|+n log(d)), where |E| is the number of edges
+ * in the graph, n is the number of queried edges and d is the average
+ * degree of the vertices. 
+ * 
+ * \sa \ref igraph_get_eid() for a single edge, \ref
+ * igraph_get_eids() for a faster version that does not handle
+ * multiple edges.
+ */
+
+int igraph_get_eids_multi(const igraph_t *graph, igraph_vector_t *eids,
+			  const igraph_vector_t *pairs, 
+			  const igraph_vector_t *path,
+			  igraph_bool_t directed, igraph_bool_t error) {
+  
+  if (!pairs && !path) {
+    igraph_vector_clear(eids);
+    return 0;
+  } else if (pairs && !path) {
+    return igraph_get_eids_multipairs(graph, eids, pairs, directed, error);
+  } else if (!pairs && path) {
+    return igraph_get_eids_multipath(graph, eids, path, directed, error);
+  } else { /* both */
+    IGRAPH_ERROR("Give `pairs' or `path' but not both", IGRAPH_EINVAL);
+  }
+}
+
+/**
+ * \function igraph_adjacent
+ * \brief Gives the incident edges of a vertex.
+ *
+ * This function was superseded by \ref igraph_incident() in igraph 0.6.
+ * Please use \ref igraph_incident() instead of this function.
+ *
+ * </para><para>
+ * Added in version 0.2, deprecated in version 0.6.
+ */
+int igraph_adjacent(const igraph_t *graph, igraph_vector_t *eids,
+		    igraph_integer_t pnode, igraph_neimode_t mode) {
+  IGRAPH_WARNING("igraph_adjacent is deprecated, use igraph_incident");
+  return igraph_incident(graph, eids, pnode, mode);
+}
+
+/**
+ * \function igraph_incident
+ * \brief Gives the incident edges of a vertex.
+ * 
+ * \param graph The graph object.
+ * \param eids An initialized \type vector_t object. It will be resized
+ * to hold the result.
+ * \param pnode A vertex id.
+ * \param mode Specifies what kind of edges to include for directed
+ * graphs. \c IGRAPH_OUT means only outgoing edges, \c IGRAPH_IN only
+ * incoming edges, \c IGRAPH_ALL both. This parameter is ignored for
+ * undirected graphs.
+ * \return Error code. \c IGRAPH_EINVVID: invalid \p pnode argument, 
+ *   \c IGRAPH_EINVMODE: invalid \p mode argument.
+ * 
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(d), the number of incident edges to \p pnode.
+ */
+
+int igraph_incident(const igraph_t *graph, igraph_vector_t *eids, 
+		    igraph_integer_t pnode, igraph_neimode_t mode) {
+  
+  long int length=0, idx=0;   
+  long int i, j;
+
+  long int node=pnode;
+
+  if (node<0 || node>igraph_vcount(graph)-1) {
+    IGRAPH_ERROR("cannot get neighbors", IGRAPH_EINVVID);
+  }
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("cannot get neighbors", IGRAPH_EINVMODE);
+  }
+
+  if (! graph->directed) {
+    mode=IGRAPH_ALL;
+  }
+
+  /* Calculate needed space first & allocate it*/
+
+  if (mode & IGRAPH_OUT) {
+    length += (VECTOR(graph->os)[node+1] - VECTOR(graph->os)[node]);
+  }
+  if (mode & IGRAPH_IN) {
+    length += (VECTOR(graph->is)[node+1] - VECTOR(graph->is)[node]);
+  }
+  
+  IGRAPH_CHECK(igraph_vector_resize(eids, length));
+  
+  if (mode & IGRAPH_OUT) {
+    j=(long int) VECTOR(graph->os)[node+1];
+    for (i=(long int) VECTOR(graph->os)[node]; i<j; i++) {
+      VECTOR(*eids)[idx++] = VECTOR(graph->oi)[i];
+    }
+  }
+  if (mode & IGRAPH_IN) {
+    j=(long int) VECTOR(graph->is)[node+1];
+    for (i=(long int) VECTOR(graph->is)[node]; i<j; i++) {
+      VECTOR(*eids)[idx++] = VECTOR(graph->ii)[i];
+    }
+  }
+
+  return 0;
+}
diff --git a/src/types.c b/src/types.c
new file mode 100644
index 0000000..a84b8de
--- /dev/null
+++ b/src/types.c
@@ -0,0 +1,146 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 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_types.h"
+#include <float.h>
+
+#ifdef _MSC_VER
+#  define snprintf _snprintf
+#endif
+
+#ifdef DBL_DIG
+/* Use DBL_DIG to determine the maximum precision used for %g */
+#  define STRINGIFY_HELPER(x) #x
+#  define STRINGIFY(x) STRINGIFY_HELPER(x)
+#  define IGRAPH_REAL_PRINTF_PRECISE_FORMAT "%." STRINGIFY(DBL_DIG) "g"
+#else
+/* Assume a precision of 10 digits for %g */
+#  define IGRAPH_REAL_PRINTF_PRECISE_FORMAT "%.10g"
+#endif
+
+#ifndef USING_R
+int igraph_real_printf(igraph_real_t val) {
+  if (igraph_finite(val)) {
+    return printf("%g", val);
+  } else if (igraph_is_nan(val)) {
+    return printf("NaN");
+  } else if (igraph_is_inf(val)) {
+    if (val < 0) {
+      return printf("-Inf");
+    } else {
+      return printf("Inf");
+    }
+  } else {
+    /* fallback */
+    return printf("%g", val);
+  }
+}
+#endif
+
+int igraph_real_fprintf(FILE *file, igraph_real_t val) {
+  if (igraph_finite(val)) {
+    return fprintf(file, "%g", val);
+  } else if (igraph_is_nan(val)) {
+    return fprintf(file, "NaN");
+  } else if (igraph_is_inf(val)) {
+    if (val < 0) {
+      return fprintf(file, "-Inf");
+    } else {
+      return fprintf(file, "Inf");
+    }
+  } else {
+    /* fallback */
+    return fprintf(file, "%g", val);
+  }
+}
+
+int igraph_real_snprintf(char* str, size_t size, igraph_real_t val) {
+  if (igraph_finite(val)) {
+    return snprintf(str, size, "%g", val);
+  } else if (igraph_is_nan(val)) {
+    return snprintf(str, size, "NaN");
+  } else if (igraph_is_inf(val)) {
+    if (val < 0) {
+      return snprintf(str, size, "-Inf");
+    } else {
+      return snprintf(str, size, "Inf");
+    }
+  } else {
+    /* fallback */
+    return snprintf(str, size, "%g", val);
+  }
+}
+
+#ifndef USING_R
+int igraph_real_printf_precise(igraph_real_t val) {
+  if (igraph_finite(val)) {
+    return printf(IGRAPH_REAL_PRINTF_PRECISE_FORMAT, val);
+  } else if (igraph_is_nan(val)) {
+    return printf("NaN");
+  } else if (igraph_is_inf(val)) {
+    if (val < 0) {
+      return printf("-Inf");
+    } else {
+      return printf("Inf");
+    }
+  } else {
+    /* fallback */
+    return printf(IGRAPH_REAL_PRINTF_PRECISE_FORMAT, val);
+  }
+}
+#endif
+
+int igraph_real_fprintf_precise(FILE *file, igraph_real_t val) {
+  if (igraph_finite(val)) {
+    return fprintf(file, IGRAPH_REAL_PRINTF_PRECISE_FORMAT, val);
+  } else if (igraph_is_nan(val)) {
+    return fprintf(file, "NaN");
+  } else if (igraph_is_inf(val)) {
+    if (val < 0) {
+      return fprintf(file, "-Inf");
+    } else {
+      return fprintf(file, "Inf");
+    }
+  } else {
+    /* fallback */
+    return fprintf(file, IGRAPH_REAL_PRINTF_PRECISE_FORMAT, val);
+  }
+}
+
+int igraph_real_snprintf_precise(char* str, size_t size, igraph_real_t val) {
+  if (igraph_finite(val)) {
+    return snprintf(str, size, IGRAPH_REAL_PRINTF_PRECISE_FORMAT, val);
+  } else if (igraph_is_nan(val)) {
+    return snprintf(str, size, "NaN");
+  } else if (igraph_is_inf(val)) {
+    if (val < 0) {
+      return snprintf(str, size, "-Inf");
+    } else {
+      return snprintf(str, size, "Inf");
+    }
+  } else {
+    /* fallback */
+    return snprintf(str, size, IGRAPH_REAL_PRINTF_PRECISE_FORMAT, val);
+  }
+}
+
diff --git a/src/vector.c b/src/vector.c
new file mode 100644
index 0000000..577eb8f
--- /dev/null
+++ b/src/vector.c
@@ -0,0 +1,434 @@
+/* -*- 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_types.h"
+#include "igraph_types_internal.h"
+#include "igraph_complex.h"
+#include "config.h"
+#include <float.h>
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define BASE_COMPLEX
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_COMPLEX
+
+#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]);
+  }
+  return 0;
+}
+
+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]);
+  }
+  return 0;
+}
+
+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);
+
+  igraph_vector_clear(v);
+  while (!igraph_indheap_empty(&heap)) {
+    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;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_order
+ * \brief Calculate the order of the elements in a vector.
+ *
+ * </para><para>
+ * The smallest element will have order zero, the second smallest
+ * 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
+ *    resized to match the size of \p v. The
+ *    result of the computation will be stored here.
+ * \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, 
+			const igraph_vector_t *v2,
+			igraph_vector_t* res, igraph_real_t nodes) {
+  long int edges=igraph_vector_size(v);
+  igraph_vector_t ptr;
+  igraph_vector_t rad;
+  long int i, j;
+
+  assert(v!=NULL);
+  assert(v->stor_begin != NULL);
+
+  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++) {
+    if (VECTOR(ptr)[i] != 0) {
+      long int next=(long int) VECTOR(ptr)[i]-1;
+      res->stor_begin[j++]=next;
+      while (VECTOR(rad)[next] != 0) {
+	next=(long int) VECTOR(rad)[next]-1;
+	res->stor_begin[j++]=next;
+      }
+    }
+  }
+
+  igraph_vector_null(&ptr);
+  igraph_vector_null(&rad);
+
+  for (i=0; i<edges; i++) {
+    long int edge=(long int) VECTOR(*res)[edges-i-1];
+    long int radix=(long int) VECTOR(*v)[edge];
+    if (VECTOR(ptr)[radix]!= 0) {
+      VECTOR(rad)[edge]=VECTOR(ptr)[radix];
+    }
+    VECTOR(ptr)[radix]=edge+1;
+  }
+  
+  j=0;
+  for (i=0; i<nodes+1; i++) {
+    if (VECTOR(ptr)[i] != 0) {
+      long int next=(long int) VECTOR(ptr)[i]-1;
+      res->stor_begin[j++]=next;
+      while (VECTOR(rad)[next] != 0) {
+	next=(long int) VECTOR(rad)[next]-1;
+	res->stor_begin[j++]=next;
+      }
+    }
+  } 
+  
+  igraph_vector_destroy(&ptr);
+  igraph_vector_destroy(&rad);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+int igraph_vector_order1(const igraph_vector_t* v,
+			 igraph_vector_t* res, igraph_real_t nodes) {
+  long int edges=igraph_vector_size(v);
+  igraph_vector_t ptr;
+  igraph_vector_t rad;
+  long int i, j;
+
+  assert(v!=NULL);
+  assert(v->stor_begin != NULL);
+
+  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) {
+      VECTOR(rad)[i]=VECTOR(ptr)[radix];
+    }
+    VECTOR(ptr)[radix]=i+1;
+  }
+  
+  j=0;
+  for (i=0; i<nodes+1; i++) {
+    if (VECTOR(ptr)[i] != 0) {
+      long int next=(long int) VECTOR(ptr)[i]-1;
+      res->stor_begin[j++]=next;
+      while (VECTOR(rad)[next] != 0) {
+	next=(long int) VECTOR(rad)[next]-1;
+	res->stor_begin[j++]=next;
+      }
+    }
+  }
+  
+  igraph_vector_destroy(&ptr);
+  igraph_vector_destroy(&rad);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  return 0;
+}
+
+int igraph_vector_order1_int(const igraph_vector_t* v,
+														 igraph_vector_int_t* res,
+														 igraph_real_t nodes) {
+  long int edges=igraph_vector_size(v);
+  igraph_vector_t ptr;
+  igraph_vector_t rad;
+  long int i, j;
+
+  assert(v!=NULL);
+  assert(v->stor_begin != NULL);
+
+  IGRAPH_VECTOR_INIT_FINALLY(&ptr, (long int) nodes+1);
+  IGRAPH_VECTOR_INIT_FINALLY(&rad, edges);
+  IGRAPH_CHECK(igraph_vector_int_resize(res, edges));
+
+  for (i=0; i<edges; i++) {
+    long int radix=(long int) v->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++) {
+    if (VECTOR(ptr)[i] != 0) {
+      long int next=(long int) VECTOR(ptr)[i]-1;
+      res->stor_begin[j++]=next;
+      while (VECTOR(rad)[next] != 0) {
+				next=(long int) VECTOR(rad)[next]-1;
+				res->stor_begin[j++]=next;
+      }
+    }
+  }
+
+  igraph_vector_destroy(&ptr);
+  igraph_vector_destroy(&rad);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+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) {      
+      VECTOR(*res)[p-1]=c++;
+      p=(long int) VECTOR(ptr)[p-1];
+    }
+  }
+
+  igraph_vector_destroy(&ptr);
+  igraph_vector_destroy(&rad);
+  IGRAPH_FINALLY_CLEAN(2);
+  return 0;
+}
+
+#ifndef USING_R
+int igraph_vector_complex_print(const igraph_vector_complex_t *v) {
+  long int i, n=igraph_vector_complex_size(v);
+  if (n!=0) {
+    igraph_complex_t z=VECTOR(*v)[0];
+    printf("%g%+gi", IGRAPH_REAL(z), IGRAPH_IMAG(z));
+  }
+  for (i=1; i<n; i++) {
+    igraph_complex_t z=VECTOR(*v)[i];
+    printf(" %g%+gi", IGRAPH_REAL(z), IGRAPH_IMAG(z));
+  }
+  printf("\n");
+  return 0;
+}
+#endif
+
+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) {
+    igraph_complex_t z=VECTOR(*v)[0];
+    fprintf(file, "%g%+g", IGRAPH_REAL(z), IGRAPH_IMAG(z));
+  }
+  for (i=1; i<n; i++) {
+    igraph_complex_t z=VECTOR(*v)[i];
+    fprintf(file, " %g%+g", IGRAPH_REAL(z), IGRAPH_IMAG(z));
+  }
+  fprintf(file, "\n");
+  return 0;
+}
+
+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));
+  for (i=0; i<n; i++) {
+    VECTOR(*real)[i] = IGRAPH_REAL(VECTOR(*v)[i]);
+  }
+
+  return 0;
+}
+
+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));
+  for (i=0; i<n; i++) {
+    VECTOR(*imag)[i] = IGRAPH_IMAG(VECTOR(*v)[i]);
+  }
+
+  return 0;
+}
+
+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));
+  IGRAPH_CHECK(igraph_vector_resize(imag, n));
+  for (i=0; i<n; i++) {
+    igraph_complex_t z=VECTOR(*v)[i];
+    VECTOR(*real)[i] = IGRAPH_REAL(z);
+    VECTOR(*imag)[i] = IGRAPH_IMAG(z);
+  }
+
+  return 0;
+}
+
+int igraph_vector_complex_create(igraph_vector_complex_t *v,
+				 const igraph_vector_t *real,
+				 const igraph_vector_t *imag) {
+  int i, n=(int) igraph_vector_size(real);
+  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]);
+  }
+
+  return 0;
+}
+
+int igraph_vector_complex_create_polar(igraph_vector_complex_t *v,
+				       const igraph_vector_t *r,
+				       const igraph_vector_t *theta) {
+  int i, n=(int) igraph_vector_size(r);
+  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]);
+  }
+
+  return 0;
+}
+
+igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs,
+				  const igraph_vector_t *rhs,
+				  igraph_real_t tol) {
+  long int i, s;
+  assert(lhs != 0);
+  assert(rhs != 0);
+  assert(lhs->stor_begin != 0);
+  assert(rhs->stor_begin != 0);
+
+  s=igraph_vector_size(lhs);
+  if (s != igraph_vector_size(rhs)) {
+    return 0;
+  } else {
+    if (tol==0) { tol=DBL_EPSILON; }
+    for (i=0; i<s; i++) {
+      igraph_real_t l=VECTOR(*lhs)[i];
+      igraph_real_t r=VECTOR(*rhs)[i];
+      if (l < r-tol || l > r+tol) {
+	return 0;
+      }
+    }
+    return 1;
+  }  
+}
diff --git a/src/vector.pmt b/src/vector.pmt
new file mode 100644
index 0000000..8187248
--- /dev/null
+++ b/src/vector.pmt
@@ -0,0 +1,2644 @@
+/* -*- 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
+
+*/
+
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "igraph_random.h"
+#include "igraph_qsort.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+#include <stdarg.h>		/* va_start & co */
+#include <math.h>
+
+/**
+ * \ingroup vector
+ * \section about_igraph_vector_t_objects About \type igraph_vector_t objects
+ * 
+ * <para>The \type igraph_vector_t data type is a simple and efficient
+ * interface to arrays containing numbers. It is something
+ * similar as (but much simpler than) the \type vector template
+ * in the C++ standard library.</para>
+ *
+ * <para>Vectors are used extensively in \a igraph, all
+ * functions which expect or return a list of numbers use
+ * igraph_vector_t to achieve this.</para>
+ *
+ * <para>The \type igraph_vector_t type usually uses
+ * O(n) space
+ * to store n elements. Sometimes it
+ * uses more, this is because vectors can shrink, but even if they
+ * shrink, the current implementation does not free a single bit of
+ * memory.</para>
+ * 
+ * <para>The elements in an \type igraph_vector_t
+ * object are indexed from zero, we follow the usual C convention
+ * here.</para>
+ * 
+ * <para>The elements of a vector always occupy a single block of
+ * memory, the starting address of this memory block can be queried
+ * with the \ref VECTOR macro. This way, vector objects can be used
+ * with standard mathematical libraries, like the GNU Scientific
+ * Library.</para>
+ */
+
+/**
+ * \ingroup vector
+ * \section igraph_vector_constructors_and_destructors Constructors and
+ * Destructors
+ * 
+ * <para>\type igraph_vector_t objects have to be initialized before using
+ * them, this is analogous to calling a constructor on them. There are a
+ * number of \type igraph_vector_t constructors, for your
+ * convenience. \ref igraph_vector_init() is the basic constructor, it
+ * creates a vector of the given length, filled with zeros.
+ * \ref igraph_vector_copy() creates a new identical copy
+ * of an already existing and initialized vector. \ref
+ * igraph_vector_init_copy() creates a vector by copying a regular C array. 
+ * \ref igraph_vector_init_seq() creates a vector containing a regular
+ * sequence with increment one.</para>
+ * 
+ * <para>\ref igraph_vector_view() is a special constructor, it allows you to
+ * handle a regular C array as a \type vector without copying
+ * its elements.
+ * </para> 
+ *
+ * <para>If a \type igraph_vector_t object is not needed any more, it
+ * should be destroyed to free its allocated memory by calling the
+ * \type igraph_vector_t destructor, \ref igraph_vector_destroy().</para>
+ * 
+ * <para> Note that vectors created by \ref igraph_vector_view() are special,
+ * you mustn't call \ref igraph_vector_destroy() on these.</para>
+ */
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init
+ * \brief Initializes a vector object (constructor).
+ * 
+ * </para><para>
+ * Every vector needs to be initialized before it can be used, and
+ * there are a number of initialization functions or otherwise called
+ * constructors. This function constructs a vector of the given size and
+ * initializes each entry to 0. Note that \ref igraph_vector_null() can be
+ * used to set each element of a vector to zero. However, if you want a
+ * vector of zeros, it is much faster to use this function than to create a
+ * vector and then invoke \ref igraph_vector_null().
+ * 
+ * </para><para>
+ * Every vector object initialized by this function should be
+ * destroyed (ie. the memory allocated for it should be freed) when it
+ * is not needed anymore, the \ref igraph_vector_destroy() function is
+ * responsible for this.
+ * \param v Pointer to a not yet initialized vector object.
+ * \param size The size of the vector.
+ * \return error code:
+ *       \c IGRAPH_ENOMEM if there is not enough memory.
+ * 
+ * Time complexity: operating system dependent, the amount of 
+ * \quote time \endquote required to allocate
+ * O(n) elements,
+ * n is the number of elements. 
+ */
+
+int FUNCTION(igraph_vector,init)      (TYPE(igraph_vector)* v, int long size) {	
+        long int alloc_size= size > 0 ? size : 1;
+	if (size < 0) { size=0; }
+	v->stor_begin=igraph_Calloc(alloc_size, BASE);
+	if (v->stor_begin==0) {
+	  IGRAPH_ERROR("cannot init vector", IGRAPH_ENOMEM);
+	}
+	v->stor_end=v->stor_begin + alloc_size;
+	v->end=v->stor_begin+size;
+
+	return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_view
+ * \brief Handle a regular C array as a \type igraph_vector_t.
+ * 
+ * </para><para>
+ * This is a special \type igraph_vector_t constructor. It allows to
+ * handle a regular C array as a \type igraph_vector_t temporarily.
+ * Be sure that you \em don't ever call the destructor (\ref
+ * igraph_vector_destroy()) on objects created by this constructor.
+ * \param v Pointer to an uninitialized \type igraph_vector_t object.
+ * \param data Pointer, the C array.
+ * \param length The length of the C array.
+ * \return Pointer to the vector object, the same as the 
+ *     \p v parameter, for convenience.
+ * 
+ * Time complexity: O(1)
+ */ 
+
+const TYPE(igraph_vector)*FUNCTION(igraph_vector,view) (const TYPE(igraph_vector) *v,
+							const BASE *data, 
+							long int length) {
+  TYPE(igraph_vector) *v2=(TYPE(igraph_vector)*)v;
+  v2->stor_begin=(BASE*)data;
+  v2->stor_end=(BASE*)data+length;
+  v2->end=v2->stor_end;
+  return v;
+}
+
+#ifndef BASE_COMPLEX
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init_real
+ * \brief Create an \type igraph_vector_t from the parameters.
+ * 
+ * </para><para>
+ * Because of how C and the C library handles variable length argument
+ * lists, it is required that you supply real constants to this
+ * function. This means that
+ * \verbatim igraph_vector_t v;
+ * igraph_vector_init_real(&v, 5, 1,2,3,4,5); \endverbatim
+ * is an error at runtime and the results are undefined. This is
+ * the proper way:
+ * \verbatim igraph_vector_t v;
+ * igraph_vector_init_real(&v, 5, 1.0,2.0,3.0,4.0,5.0); \endverbatim
+ * \param v Pointer to an uninitialized \type igraph_vector_t object.
+ * \param no Positive integer, the number of \type igraph_real_t
+ *    parameters to follow.
+ * \param ... The elements of the vector.
+ * \return Error code, this can be \c IGRAPH_ENOMEM
+ *     if there isn't enough memory to allocate the vector.
+ *
+ * \sa \ref igraph_vector_init_real_end(), \ref igraph_vector_init_int() for similar
+ * functions.
+ *
+ * Time complexity: depends on the time required to allocate memory,
+ * but at least O(n), the number of
+ * elements in the vector.
+ */
+
+int FUNCTION(igraph_vector,init_real)(TYPE(igraph_vector) *v, int no, ...) {
+  int i=0;
+  va_list ap;
+  IGRAPH_CHECK(FUNCTION(igraph_vector,init)(v, no));
+
+  va_start(ap, no);
+  for (i=0; i<no; i++) {
+    VECTOR(*v)[i]=(BASE) va_arg(ap, double);
+  }
+  va_end(ap);
+  
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init_real_end
+ * \brief Create an \type igraph_vector_t from the parameters.
+ * 
+ * </para><para>
+ * This constructor is similar to \ref igraph_vector_init_real(), the only
+ * difference is that instead of giving the number of elements in the
+ * vector, a special marker element follows the last real vector
+ * element.
+ * \param v Pointer to an uninitialized \type igraph_vector_t object.
+ * \param endmark This element will signal the end of the vector. It
+ *    will \em not be part of the vector.
+ * \param ... The elements of the vector.
+ * \return Error code, \c IGRAPH_ENOMEM if there
+ *    isn't enough memory.
+ * 
+ * \sa \ref igraph_vector_init_real() and \ref igraph_vector_init_int_end() for
+ * similar functions.
+ * 
+ * Time complexity: at least O(n) for 
+ * n elements plus the time
+ * complexity of the memory allocation.
+ */
+
+int FUNCTION(igraph_vector,init_real_end)(TYPE(igraph_vector) *v, 
+					  BASE endmark, ...) {
+  int i=0, n=0;
+  va_list ap;
+
+  va_start(ap, endmark);
+  while (1) {
+    BASE num = (BASE) va_arg(ap, double);
+    if (num == endmark) {
+      break;
+    }
+    n++;
+  }
+  va_end(ap);
+
+  IGRAPH_CHECK(FUNCTION(igraph_vector,init)(v,n));
+  IGRAPH_FINALLY(FUNCTION(igraph_vector,destroy), v);
+  
+  va_start(ap, endmark);
+  for (i=0; i<n; i++) {
+    VECTOR(*v)[i]=(BASE) va_arg(ap, double);
+  }
+  va_end(ap);
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init_int
+ * \brief Create an \type igraph_vector_t containing the parameters.
+ * 
+ * </para><para>
+ * This function is similar to \ref igraph_vector_init_real(), but it expects 
+ * \type int parameters. It is important that all parameters
+ * should be of this type, otherwise the result of the function call
+ * is undefined.
+ * \param v Pointer to an uninitialized \type igraph_vector_t object.
+ * \param no The number of \type int parameters to follow.
+ * \param ... The elements of the vector.
+ * \return Error code, \c IGRAPH_ENOMEM if there is
+ *    not enough memory.
+ * \sa \ref igraph_vector_init_real() and igraph_vector_init_int_end(), these are
+ *    similar functions.
+ *
+ * Time complexity: at least O(n) for 
+ * n elements plus the time
+ * complexity of the memory allocation.
+ */
+
+int FUNCTION(igraph_vector,init_int)(TYPE(igraph_vector) *v, int no, ...) {
+  int i=0;
+  va_list ap;
+  IGRAPH_CHECK(FUNCTION(igraph_vector,init)(v, no));
+
+  va_start(ap, no);
+  for (i=0; i<no; i++) {
+    VECTOR(*v)[i]=(BASE) va_arg(ap, int);
+  }
+  va_end(ap);
+  
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init_int_end
+ * \brief Create an \type igraph_vector_t from the parameters.
+ * 
+ * </para><para>
+ * This constructor is similar to \ref igraph_vector_init_int(), the only
+ * difference is that instead of giving the number of elements in the
+ * vector, a special marker element follows the last real vector
+ * element.
+ * \param v Pointer to an uninitialized \type igraph_vector_t object.
+ * \param endmark This element will signal the end of the vector. It
+ *    will \em not be part of the vector.
+ * \param ... The elements of the vector.
+ * \return Error code, \c IGRAPH_ENOMEM if there
+ *    isn't enough memory.
+ * 
+ * \sa \ref igraph_vector_init_int() and \ref igraph_vector_init_real_end() for
+ * similar functions.
+ *
+ * Time complexity: at least O(n) for 
+ * n elements plus the time
+ * complexity of the memory allocation.
+ */
+
+int FUNCTION(igraph_vector_init,int_end)(TYPE(igraph_vector) *v, int endmark, ...) {
+  int i=0, n=0;
+  va_list ap;
+
+  va_start(ap, endmark);
+  while (1) {
+    int num = va_arg(ap, int);
+    if (num == endmark) {
+      break;
+    }
+    n++;
+  }
+  va_end(ap);
+
+  IGRAPH_CHECK(FUNCTION(igraph_vector,init)(v, n));
+  IGRAPH_FINALLY(FUNCTION(igraph_vector,destroy), v);
+  
+  va_start(ap, endmark);
+  for (i=0; i<n; i++) {
+    VECTOR(*v)[i]=(BASE) va_arg(ap, int);
+  }
+  va_end(ap);
+  
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+}
+
+#endif /* ifndef BASE_COMPLEX */
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_destroy
+ * \brief Destroys a vector object.
+ *
+ * </para><para>
+ * All vectors initialized by \ref igraph_vector_init() should be properly
+ * destroyed by this function. A destroyed vector needs to be
+ * reinitialized by \ref igraph_vector_init(), \ref igraph_vector_init_copy() or
+ * another constructor.
+ * \param v Pointer to the (previously initialized) vector object to
+ *        destroy. 
+ *
+ * Time complexity: operating system dependent.
+ */
+
+void FUNCTION(igraph_vector,destroy)   (TYPE(igraph_vector)* v) {
+  assert(v != 0);
+  if (v->stor_begin != 0) {
+    igraph_Free(v->stor_begin);
+    v->stor_begin = NULL;
+  }
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_capacity
+ * \brief Returns the allocated capacity of the vector
+ * 
+ * Note that this might be different from the size of the vector (as 
+ * queried by \ref igraph_vector_size(), and specifies how many elements 
+ * the vector can hold, without reallocation.
+ * \param v Pointer to the (previously initialized) vector object
+ *          to query.
+ * \return The allocated capacity.
+ * 
+ * \sa \ref igraph_vector_size().
+ * 
+ * Time complexity: O(1).
+ */
+
+long int FUNCTION(igraph_vector,capacity)(const TYPE(igraph_vector)*v) {
+  return v->stor_end - v->stor_begin;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_reserve
+ * \brief Reserves memory for a vector.
+ * 
+ * </para><para>
+ * \a igraph vectors are flexible, they can grow and
+ * shrink. Growing 
+ * however occasionally needs the data in the vector to be copied.
+ * In order to avoid this, you can call this function to reserve space for
+ * future growth of the vector. 
+ * 
+ * </para><para>
+ * Note that this function does \em not change the size of the
+ * vector. Let us see a small example to clarify things: if you
+ * reserve space for 100 elements and the size of your
+ * vector was (and still is) 60, then you can surely add additional 40
+ * elements to your vector before it will be copied.
+ * \param v The vector object.
+ * \param size The new \em allocated size of the vector.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM if there is not enough memory.
+ *
+ * Time complexity: operating system dependent, should be around
+ * O(n), n 
+ * is the new allocated size of the vector.
+ */
+
+int FUNCTION(igraph_vector,reserve)   (TYPE(igraph_vector)* v, long int size) {
+	long int actual_size=FUNCTION(igraph_vector,size)(v);
+	BASE *tmp;
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	if (size <= FUNCTION(igraph_vector,size)(v)) { return 0; }
+
+	tmp=igraph_Realloc(v->stor_begin, (size_t) size, BASE);
+	if (tmp==0) {
+	  IGRAPH_ERROR("cannot reserve space for vector", IGRAPH_ENOMEM);
+	}
+	v->stor_begin=tmp;
+	v->stor_end=v->stor_begin + size;
+	v->end=v->stor_begin+actual_size;
+	
+	return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_empty
+ * \brief Decides whether the size of the vector is zero.
+ *
+ * \param v The vector object.
+ * \return Non-zero number (true) if the size of the vector is zero and
+ *         zero (false) otherwise.
+ * 
+ * Time complexity: O(1).
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,empty)     (const TYPE(igraph_vector)* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	return v->stor_begin == v->end;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_size
+ * \brief Gives the size (=length) of the vector.
+ * 
+ * \param v The vector object
+ * \return The size of the vector.
+ *
+ * Time complexity: O(1). 
+ */
+
+long int FUNCTION(igraph_vector,size)      (const TYPE(igraph_vector)* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	return v->end - v->stor_begin;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_clear
+ * \brief Removes all elements from a vector.
+ * 
+ * </para><para>
+ * This function simply sets the size of the vector to zero, it does
+ * not free any allocated memory. For that you have to call
+ * \ref igraph_vector_destroy().
+ * \param v The vector object.
+ * 
+ * Time complexity: O(1).
+ */
+
+void FUNCTION(igraph_vector,clear)     (TYPE(igraph_vector)* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	v->end = v->stor_begin;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_push_back
+ * \brief Appends one element to a vector.
+ * 
+ * </para><para>
+ * This function resizes the vector to be one element longer and
+ * sets the very last element in the vector to \p e.
+ * \param v The vector object.
+ * \param e The element to append to the vector.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM: not enough memory.
+ * 
+ * Time complexity: operating system dependent. What is important is that
+ * a sequence of n
+ * subsequent calls to this function has time complexity
+ * O(n), even if there 
+ * hadn't been any space reserved for the new elements by
+ * \ref igraph_vector_reserve(). This is implemented by a trick similar to the C++
+ * \type vector class: each time more memory is allocated for a
+ * vector, the size of the additionally allocated memory is the same
+ * as the vector's current length. (We assume here that the time
+ * complexity of memory allocation is at most linear.)
+ */
+
+int FUNCTION(igraph_vector,push_back) (TYPE(igraph_vector)* v, BASE e) {
+  	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	
+	/* full, allocate more storage */
+	if (v->stor_end == v->end) {
+		long int new_size = FUNCTION(igraph_vector,size)(v) * 2;
+		if (new_size == 0) { new_size = 1; }
+		IGRAPH_CHECK(FUNCTION(igraph_vector,reserve)(v, new_size));
+	}
+	
+	*(v->end) = e;
+	v->end += 1;
+	
+	return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_insert
+ * \brief Inserts a single element into a vector.
+ *
+ * Note that this function does not do range checking. Insertion will shift the
+ * elements from the position given to the end of the vector one position to the
+ * right, and the new element will be inserted in the empty space created at
+ * the given position. The size of the vector will increase by one.
+ *
+ * \param v The vector object.
+ * \param pos The position where the new element is to be inserted.
+ * \param value The new element to be inserted.
+ */
+int FUNCTION(igraph_vector,insert)(TYPE(igraph_vector) *v, long int pos,
+				   BASE value) {
+  size_t size = (size_t) FUNCTION(igraph_vector,size)(v);
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(v, (long) size+1));
+  if (pos<size) {
+    memmove(v->stor_begin+pos+1, v->stor_begin+pos, 
+	    sizeof(BASE)*(size - (size_t) pos));
+  }
+  v->stor_begin[pos] = value;
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \section igraph_vector_accessing_elements Accessing elements
+ * 
+ * <para>The simplest way to access an element of a vector is to use the
+ * \ref VECTOR macro. This macro can be used both for querying and setting
+ * \type igraph_vector_t elements. If you need a function, \ref
+ * igraph_vector_e() queries and \ref igraph_vector_set() sets an element of a
+ * vector. \ref igraph_vector_e_ptr() returns the address of an element.</para>
+ * 
+ * <para>\ref igraph_vector_tail() returns the last element of a non-empty
+ * vector. There is no <function>igraph_vector_head()</function> function
+ * however, as it is easy to write <code>VECTOR(v)[0]</code>
+ * instead.</para>
+ */
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_e
+ * \brief Access an element of a vector.
+ * \param v The \type igraph_vector_t object.
+ * \param pos The position of the element, the index of the first
+ *    element is zero.
+ * \return The desired element.
+ * \sa \ref igraph_vector_e_ptr() and the \ref VECTOR macro.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_vector,e)         (const TYPE(igraph_vector)* v, long int pos) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	return * (v->stor_begin + pos);
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_e_ptr
+ * \brief Get the address of an element of a vector
+ * \param v The \type igraph_vector_t object.
+ * \param pos The position of the element, the position of the first
+ *   element is zero.
+ * \return Pointer to the desired element.
+ * \sa \ref igraph_vector_e() and the \ref VECTOR macro.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE* FUNCTION(igraph_vector,e_ptr)  (const TYPE(igraph_vector)* v, long int pos) {
+  assert(v!=NULL);
+  assert(v->stor_begin != NULL);
+  return v->stor_begin+pos;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_set
+ * \brief Assignment to an element of a vector.
+ * \param v The \type igraph_vector_t element.
+ * \param pos Position of the element to set.
+ * \param value New value of the element.
+ * \sa \ref igraph_vector_e().
+ */
+
+void FUNCTION(igraph_vector,set)       (TYPE(igraph_vector)* v, 
+					long int pos, BASE value) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);	
+	*(v->stor_begin + pos) = value;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_null
+ * \brief Sets each element in the vector to zero.
+ * 
+ * </para><para>
+ * Note that \ref igraph_vector_init() sets the elements to zero as well, so
+ * it makes no sense to call this function on a just initialized
+ * vector. Thus if you want to construct a vector of zeros, then you should
+ * use \ref igraph_vector_init().
+ * \param v The vector object.
+ *
+ * Time complexity: O(n), the size of
+ * the vector. 
+ */
+
+void FUNCTION(igraph_vector,null)      (TYPE(igraph_vector)* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	if (FUNCTION(igraph_vector,size)(v)>0) {
+		memset(v->stor_begin, 0, 
+		       sizeof(BASE)*(size_t) FUNCTION(igraph_vector,size)(v));
+	}
+}
+
+/**
+ * \function igraph_vector_fill
+ * \brief Fill a vector with a constant element
+ * 
+ * Sets each element of the vector to the supplied constant.
+ * \param vector The vector to work on.
+ * \param e The element to fill with.
+ * 
+ * Time complexity: O(n), the size of the vector.
+ */
+
+void FUNCTION(igraph_vector,fill)      (TYPE(igraph_vector)* v, BASE e) {
+  BASE *ptr;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  for (ptr = v->stor_begin; ptr < v->end; ptr++) {
+    *ptr = e;
+  }  
+}  
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_tail
+ * \brief Returns the last element in a vector.
+ *
+ * </para><para>
+ * It is an error to call this function on an empty vector, the result
+ * is undefined.
+ * \param v The vector object.
+ * \return The last element.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_vector,tail)(const TYPE(igraph_vector) *v) {
+  assert(v!=NULL);
+  assert(v->stor_begin != NULL);
+  return *((v->end)-1);
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_pop_back
+ * \brief Removes and returns the last element of a vector.
+ *
+ * </para><para>
+ * It is an error to call this function with an empty vector.
+ * \param v The vector object.
+ * \return The removed last element.
+ * 
+ * Time complexity: O(1).
+ */
+
+BASE FUNCTION(igraph_vector,pop_back)(TYPE(igraph_vector)* v) {
+  BASE tmp;
+  assert(v!=NULL);
+  assert(v->stor_begin != NULL);
+  assert(v->end != v->stor_begin);
+  tmp=FUNCTION(igraph_vector,e)(v, FUNCTION(igraph_vector,size)(v)-1);
+  v->end -= 1;
+  return tmp;
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_sort_cmp
+ * \brief Internal comparison function of vector elements, used by 
+ * \ref igraph_vector_sort().
+ */
+
+int FUNCTION(igraph_vector,sort_cmp)(const void *a, const void *b) {
+  const BASE *da = (const BASE *) a;
+  const BASE *db = (const BASE *) b;
+
+  return (*da > *db) - (*da < *db);
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_sort
+ * \brief Sorts the elements of the vector into ascending order.
+ * 
+ * </para><para>
+ * This function uses the built-in sort function of the C library.
+ * \param v Pointer to an initialized vector object.
+ *
+ * Time complexity: should be
+ * O(nlogn) for
+ * n 
+ * elements.
+ */
+
+void FUNCTION(igraph_vector,sort)(TYPE(igraph_vector) *v) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  igraph_qsort(v->stor_begin, (size_t) FUNCTION(igraph_vector,size)(v), 
+    sizeof(BASE), FUNCTION(igraph_vector,sort_cmp));
+}
+
+/**
+ * Ascending comparison function passed to qsort from  igraph_vector_qsort_ind
+ */
+int FUNCTION(igraph_vector,i_qsort_ind_cmp_asc)(const void *p1 , const void *p2) {
+  BASE **pa = (BASE **) p1;
+  BASE **pb = (BASE **) p2;
+  if( **pa < **pb ) return -1;
+  if( **pa > **pb) return 1;
+  return 0;
+}
+
+/**
+ * Descending comparison function passed to qsort from  igraph_vector_qsort_ind
+ */
+int FUNCTION(igraph_vector,i_qsort_ind_cmp_desc)(const void *p1 , const void *p2) {
+  BASE **pa = (BASE **) p1;
+  BASE **pb = (BASE **) p2;
+  if( **pa < **pb ) return 1;
+  if( **pa > **pb) return -1;
+  return 0;
+}
+
+/**
+ * \function igraph_vector_qsort_ind
+ * \brief Return a permutation of indices that sorts a vector 
+ *
+ * Takes an unsorted array \c v as input and computes an array of
+ * indices inds such that v[ inds[i] ], with i increasing from 0, is
+ * an ordered array (either ascending or descending, depending on
+ * \v order). The order of indices for identical elements is not
+ * defined.
+ *
+ * \param v the array to be sorted
+ * \param inds the output array of indices. this must be initialized,
+ *         but will be resized 
+ * \param descending whether the output array should be sorted in descending
+ *        order.
+ * \return Error code.
+ *
+ * This routine uses the C library qsort routine.
+ * Algorithm: 1) create an array of pointers to the elements of v. 2)
+ * Pass this array to qsort. 3) after sorting the difference between
+ * the pointer value and the first pointer value gives its original
+ * position in the array. Use this to set the values of inds. 
+ *
+ * Some tests show that this routine is faster than
+ * igraph_vector_heapsort_ind by about 10 percent 
+ * for small vectors to a factor of two for large vectors.
+ */
+
+long int FUNCTION(igraph_vector,qsort_ind)(TYPE(igraph_vector) *v, 
+					   igraph_vector_t *inds, igraph_bool_t descending) {
+  long int i;
+  BASE **vind, *first;
+  size_t n = (size_t) FUNCTION(igraph_vector,size)(v);
+  IGRAPH_CHECK(igraph_vector_resize(inds, (long) n));
+  if (n==0) { return 0; }
+  vind = igraph_Calloc(n, BASE*);
+  if (vind == 0) {
+    IGRAPH_ERROR("igraph_vector_qsort_ind failed", IGRAPH_ENOMEM);
+  }
+  for(i=0; i<n; i++) {
+    vind[i] = &VECTOR(*v)[i];
+  }
+  first = vind[0];
+  if (descending)
+    igraph_qsort(vind, n, sizeof(BASE**), FUNCTION(igraph_vector,i_qsort_ind_cmp_desc));
+  else
+    igraph_qsort(vind, n, sizeof(BASE**), FUNCTION(igraph_vector,i_qsort_ind_cmp_asc));
+  for(i=0; i<n; i++) {
+    VECTOR(*inds)[i] = vind[i]-first;
+  }
+  igraph_Free(vind);
+  return 0;
+}
+
+#endif
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_resize
+ * \brief Resize the vector.
+ *
+ * </para><para>
+ * Note that this function does not free any memory, just sets the
+ * size of the vector to the given one. It can on the other hand 
+ * allocate more memory if the new size is larger than the previous
+ * one. In this case the newly appeared elements in the vector are
+ * \em not set to zero, they are uninitialized.
+ * \param v The vector object
+ * \param newsize The new size of the vector.
+ * \return Error code, 
+ *         \c IGRAPH_ENOMEM if there is not enough
+ *         memory. Note that this function \em never returns an error
+ *         if the vector is made smaller.
+ * \sa \ref igraph_vector_reserve() for allocating memory for future
+ * extensions of a vector. \ref igraph_vector_resize_min() for 
+ * deallocating the unnneded memory for a vector.
+ * 
+ * Time complexity: O(1) if the new
+ * size is smaller, operating system dependent if it is larger. In the
+ * latter case it is usually around
+ * O(n),
+ * n is the new size of the vector. 
+ */
+
+int FUNCTION(igraph_vector,resize)(TYPE(igraph_vector)* v, long int newsize) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  IGRAPH_CHECK(FUNCTION(igraph_vector,reserve)(v, newsize));
+  v->end = v->stor_begin+newsize;
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_resize_min
+ * \brief Deallocate the unused memory of a vector.
+ * 
+ * </para><para>
+ * Note that this function involves additional memory allocation and 
+ * may result an out-of-memory error.
+ * \param v Pointer to an initialized vector.
+ * \return Error code.
+ *
+ * \sa \ref igraph_vector_resize(), \ref igraph_vector_reserve().
+ * 
+ * Time complexity: operating system dependent. 
+ */
+
+int FUNCTION(igraph_vector,resize_min)(TYPE(igraph_vector)*v) {
+  size_t size;
+  BASE *tmp;
+  if (v->stor_end == v->end) { return 0; }
+  
+  size = (size_t) (v->end - v->stor_begin);
+  tmp=igraph_Realloc(v->stor_begin, size, BASE);
+  if (tmp==0) {
+    IGRAPH_ERROR("cannot resize vector", IGRAPH_ENOMEM);
+  } else {
+    v->stor_begin = tmp;
+    v->stor_end = v->end = v->stor_begin + size;
+  }
+  
+  return 0;
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_max
+ * \brief Gives the maximum element of the vector.
+ *
+ * </para><para>
+ * If the size of the vector is zero, an arbitrary number is
+ * returned.
+ * \param v The vector object.
+ * \return The maximum element.
+ *
+ * Time complexity: O(n),
+ * n is the size of the vector. 
+ */
+
+BASE FUNCTION(igraph_vector,max)(const TYPE(igraph_vector)* v) {
+  BASE max;
+  BASE *ptr;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  max=*(v->stor_begin);
+  ptr=v->stor_begin+1;
+  while (ptr < v->end) {
+    if ((*ptr) > max) {
+      max=*ptr;
+    }
+    ptr++;
+  }
+  return max;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_which_max
+ * \brief Gives the position of the maximum element of the vector.
+ *
+ * </para><para>
+ * If the size of the vector is zero, -1 is 
+ * returned.
+ * \param v The vector object.
+ * \return The position of the first maximum element.
+ *
+ * Time complexity: O(n),
+ * n is the size of the vector. 
+ */
+
+long int FUNCTION(igraph_vector,which_max)(const TYPE(igraph_vector)* v) {
+  long int which=-1;
+  if (!FUNCTION(igraph_vector,empty)(v)) {
+    BASE max;
+    BASE *ptr;
+    long int pos;
+    assert(v != NULL);
+    assert(v->stor_begin != NULL);
+    max=*(v->stor_begin); which=0;
+    ptr=v->stor_begin+1; pos=1;
+    while (ptr < v->end) {
+      if ((*ptr) > max) {
+	max=*ptr;
+	which=pos;
+      }
+      ptr++; pos++;
+    }
+  }
+  return which;
+}
+
+/**
+ * \function igraph_vector_min
+ * \brief Smallest element of a vector.
+ * 
+ * The vector must be non-empty.
+ * \param v The input vector.
+ * \return The smallest element of \p v.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+BASE FUNCTION(igraph_vector,min)(const TYPE(igraph_vector)* v) {
+  BASE min;
+  BASE *ptr;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  min=*(v->stor_begin);
+  ptr=v->stor_begin+1;
+  while (ptr < v->end) {
+    if ((*ptr) < min) {
+      min=*ptr;
+    }
+    ptr++;
+  }
+  return min;
+}
+
+/**
+ * \function igraph_vector_which_min
+ * \brief Index of the smallest element.
+ * 
+ * The vector must be non-empty.
+ * If the smallest element is not unique, then the index of the first
+ * is returned.
+ * \param v The input vector.
+ * \return Index of the smallest element.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+long int FUNCTION(igraph_vector,which_min)(const TYPE(igraph_vector)* v) {
+  long int which=-1;
+  if (!FUNCTION(igraph_vector,empty)(v)) {
+    BASE min;
+    BASE *ptr;
+    long int pos;
+    assert(v != NULL);
+    assert(v->stor_begin != NULL);
+    min=*(v->stor_begin); which=0;
+    ptr=v->stor_begin+1; pos=1;
+    while (ptr < v->end) {
+      if ((*ptr) < min) {
+	min=*ptr;
+	which=pos;
+      }
+      ptr++; pos++;
+    }
+  }
+  return which;
+}
+
+#endif
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init_copy
+ * \brief Initializes a vector from an ordinary C array (constructor).
+ * 
+ * \param v Pointer to an uninitialized vector object.
+ * \param data A regular C array.
+ * \param length The length of the C array.
+ * \return Error code: 
+ *         \c IGRAPH_ENOMEM if there is not enough memory.
+ * 
+ * Time complexity: operating system specific, usually
+ * O(\p length).
+ */
+
+int FUNCTION(igraph_vector,init_copy)(TYPE(igraph_vector) *v, 
+				      BASE *data, long int length) {
+  v->stor_begin=igraph_Calloc(length, BASE);
+  if (v->stor_begin==0) {
+    IGRAPH_ERROR("cannot init vector from array", IGRAPH_ENOMEM);
+  }
+  v->stor_end=v->stor_begin+length;
+  v->end=v->stor_end;
+  memcpy(v->stor_begin, data, (size_t) length * sizeof(BASE));
+  
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_copy_to
+ * \brief Copies the contents of a vector to a C array.
+ * 
+ * </para><para>
+ * The C array should have sufficient length.
+ * \param v The vector object.
+ * \param to The C array.
+ * 
+ * Time complexity: O(n),
+ * n is the size of the vector.
+ */
+
+void FUNCTION(igraph_vector,copy_to)(const TYPE(igraph_vector) *v, BASE *to) {
+				     
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  if (v->end != v->stor_begin) {
+    memcpy(to, v->stor_begin, sizeof(BASE) * (size_t) (v->end - v->stor_begin));
+  }
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_copy
+ * \brief Initializes a vector from another vector object (constructor).
+ * 
+ * </para><para>
+ * The contents of the existing vector object will be copied to
+ * the new one.
+ * \param to Pointer to a not yet initialized vector object.
+ * \param from The original vector object to copy.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM if there is not enough memory.
+ * 
+ * Time complexity: operating system dependent, usually
+ * O(n),
+ * n is the size of the vector. 
+ */
+
+int FUNCTION(igraph_vector,copy)(TYPE(igraph_vector) *to, 
+				 const TYPE(igraph_vector) *from) {
+  assert(from != NULL);
+  assert(from->stor_begin != NULL);
+  to->stor_begin=igraph_Calloc(FUNCTION(igraph_vector,size)(from), BASE);
+  if (to->stor_begin==0) {
+    IGRAPH_ERROR("cannot copy vector", IGRAPH_ENOMEM);
+  }
+  to->stor_end=to->stor_begin+FUNCTION(igraph_vector,size)(from);
+  to->end=to->stor_end;
+  memcpy(to->stor_begin, from->stor_begin, 
+	 (size_t) FUNCTION(igraph_vector,size)(from) * sizeof(BASE));
+  
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_sum
+ * \brief Calculates the sum of the elements in the vector.
+ *
+ * </para><para>
+ * For the empty vector 0.0 is returned.
+ * \param v The vector object.
+ * \return The sum of the elements.
+ * 
+ * Time complexity: O(n), the size of
+ * the vector. 
+ */
+
+BASE FUNCTION(igraph_vector,sum)(const TYPE(igraph_vector) *v) {
+  BASE res=ZERO;
+  BASE *p;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  for (p=v->stor_begin; p<v->end; p++) {
+#ifdef SUM
+    SUM(res,res,*p);
+#else
+    res += *p;
+#endif
+  }
+  return res;
+}
+
+igraph_real_t FUNCTION(igraph_vector,sumsq)(const TYPE(igraph_vector) *v) {
+  igraph_real_t res=0.0;
+  BASE *p;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  for (p=v->stor_begin; p<v->end; p++) {
+#ifdef SQ
+    res += SQ(*p);
+#else
+    res += (*p) * (*p);
+#endif
+  }
+  return res;
+}
+  
+/**
+ * \ingroup vector
+ * \function igraph_vector_prod
+ * \brief Calculates the product of the elements in the vector.
+ * 
+ * </para><para>
+ * For the empty vector one (1) is returned.
+ * \param v The vector object.
+ * \return The product of the elements.
+ * 
+ * Time complexity: O(n), the size of
+ * the vector. 
+ */
+
+BASE FUNCTION(igraph_vector,prod)(const TYPE(igraph_vector) *v) {
+  BASE res=ONE;
+  BASE *p;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  for (p=v->stor_begin; p<v->end; p++) {
+#ifdef PROD
+    PROD(res,res,*p);
+#else
+    res *= *p;
+#endif
+  }
+  return res;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_cumsum
+ * \brief Calculates the cumulative sum of the elements in the vector.
+ *
+ * </para><para>
+ * \param to An initialized vector object that will store the cumulative
+ *           sums. Element i of this vector will store the sum of the elements
+ *           of the 'from' vector, up to and including element i.
+ * \param from The input vector.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the size of the vector. 
+ */
+
+int FUNCTION(igraph_vector,cumsum)(TYPE(igraph_vector) *to,
+                                   const TYPE(igraph_vector) *from) {
+  BASE res=ZERO;
+  BASE *p, *p2;
+
+  assert(from != NULL);
+  assert(from->stor_begin != NULL);
+  assert(to != NULL);
+  assert(to->stor_begin != NULL);
+
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(to, FUNCTION(igraph_vector,size)(from)));
+
+  for (p = from->stor_begin, p2 = to->stor_begin; p < from->end; p++, p2++) {
+#ifdef SUM
+    SUM(res,res,*p);
+#else
+    res += *p;
+#endif
+    *p2 = res;
+  }
+
+  return 0;
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_init_seq
+ * \brief Initializes a vector with a sequence.
+ * 
+ * </para><para>
+ * The vector will contain the numbers \p from,
+ * \p from+1, ..., \p to.
+ * \param v Pointer to an uninitialized vector object.
+ * \param from The lower limit in the sequence (inclusive).
+ * \param to The upper limit in the sequence (inclusive).
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM: out of memory.
+ *
+ * Time complexity: O(n), the number
+ * of elements in the vector. 
+ */
+
+int FUNCTION(igraph_vector,init_seq)(TYPE(igraph_vector) *v, 
+				     BASE from, BASE to) {
+  BASE *p;
+  IGRAPH_CHECK(FUNCTION(igraph_vector,init)(v, (long int) (to-from+1)));
+
+  for (p=v->stor_begin; p<v->end; p++) {
+    *p = from++;
+  }
+  
+  return 0;
+}
+
+#endif
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_remove_section
+ * \brief Deletes a section from a vector.
+ * 
+ * </para><para>
+ * Note that this function does not do range checking. The result is
+ * undefined if you supply invalid limits.
+ * \param v The vector object.
+ * \param from The position of the first element to remove.
+ * \param to The position of the first element \em not to remove.
+ *
+ * Time complexity: O(n-from),
+ * n is the number of elements in the
+ * vector. 
+ */
+
+void FUNCTION(igraph_vector,remove_section)(TYPE(igraph_vector) *v, 
+					    long int from, long int to) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  /* Not removing from the end? */
+  if (to < FUNCTION(igraph_vector,size)(v)) {
+    memmove(v->stor_begin+from, v->stor_begin+to,
+	    sizeof(BASE) * (size_t) (v->end-v->stor_begin-to));
+  }
+  v->end -= (to-from);
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_remove
+ * \brief Removes a single element from a vector.
+ *
+ * Note that this function does not do range checking.
+ * \param v The vector object.
+ * \param elem The position of the element to remove.
+ * 
+ * Time complexity: O(n-elem),
+ * n is the number of elements in the
+ * vector. 
+ */
+
+void FUNCTION(igraph_vector,remove)(TYPE(igraph_vector) *v, long int elem) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  FUNCTION(igraph_vector,remove_section)(v, elem, elem+1);
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_move_interval
+ * \brief Copies a section of a vector.
+ *
+ * </para><para>
+ * The result of this function is undefined if the source and target
+ * intervals overlap.
+ * \param v The vector object.
+ * \param begin The position of the first element to move.
+ * \param end The position of the first element \em not to move.
+ * \param to The target position.
+ * \return Error code, the current implementation always returns with
+ *    success. 
+ *
+ * Time complexity: O(end-begin).
+ */
+
+int FUNCTION(igraph_vector,move_interval)(TYPE(igraph_vector) *v, 
+					  long int begin, long int end, 
+					  long int to) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  memcpy(v->stor_begin+to, v->stor_begin+begin, 
+	 sizeof(BASE) * (size_t) (end-begin));
+
+  return 0;
+}
+
+int FUNCTION(igraph_vector,move_interval2)(TYPE(igraph_vector) *v, 
+					  long int begin, long int end, 
+					  long int to) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  memmove(v->stor_begin+to, v->stor_begin+begin, 
+	  sizeof(BASE) * (size_t) (end-begin));
+
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_permdelete
+ * \brief Remove elements of a vector (for internal use).
+ */
+
+void FUNCTION(igraph_vector,permdelete)(TYPE(igraph_vector) *v, 
+					const igraph_vector_t *index, long int nremove) {
+  long int i, n;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  n = FUNCTION(igraph_vector,size)(v);
+  for (i=0; i<n; i++) {
+    if (VECTOR(*index)[i] != 0) {
+      VECTOR(*v)[ (long int)VECTOR(*index)[i]-1 ] = VECTOR(*v)[i];
+    }
+  }
+  v->end -= nremove;
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_isininterval
+ * \brief Checks if all elements of a vector are in the given
+ * interval.
+ * 
+ * \param v The vector object.
+ * \param low The lower limit of the interval (inclusive).
+ * \param high The higher limit of the interval (inclusive).
+ * \return True (positive integer) if all vector elements are in the
+ *   interval, false (zero) otherwise.
+ *
+ * Time complexity: O(n), the number
+ * of elements in the vector.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,isininterval)(const TYPE(igraph_vector) *v, 
+						   BASE low, 
+						   BASE high) {
+  BASE *ptr;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  for (ptr=v->stor_begin; ptr<v->end; ptr++) {
+    if (*ptr < low || *ptr >high) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_any_smaller
+ * \brief Checks if any element of a vector is smaller than a limit.
+ * 
+ * \param v The \type igraph_vector_t object.
+ * \param limit The limit.
+ * \return True (positive integer) if the vector contains at least one
+ *   smaller element than \p limit, false (zero)
+ *   otherwise. 
+ * 
+ * Time complexity: O(n), the number
+ * of elements in the vector.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,any_smaller)(const TYPE(igraph_vector) *v, 
+						  BASE limit) {
+  BASE *ptr;
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  for (ptr=v->stor_begin; ptr<v->end; ptr++) {
+    if (*ptr < limit) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+#endif
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_all_e
+ * \brief Are all elements equal?
+ * 
+ * \param lhs The first vector.
+ * \param rhs The second vector.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    equal to the corresponding elements in \p rhs. Returns \c 0
+ *    (=false) if the lengths of the vectors don't match.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,all_e)(const TYPE(igraph_vector) *lhs, 
+					    const TYPE(igraph_vector) *rhs) {
+  long int i, s;
+  assert(lhs != 0);
+  assert(rhs != 0);
+  assert(lhs->stor_begin != 0);
+  assert(rhs->stor_begin != 0);
+  
+  s=FUNCTION(igraph_vector,size)(lhs);
+  if (s != FUNCTION(igraph_vector,size)(rhs)) {
+    return 0;
+  } else {
+    for (i=0; i<s; i++) {
+      BASE l=VECTOR(*lhs)[i];
+      BASE r=VECTOR(*rhs)[i];
+#ifdef EQ
+      if (!EQ(l,r)) {
+#else
+      if (l!=r) {
+#endif
+	return 0;
+      }
+    }
+    return 1;
+  }
+}
+
+igraph_bool_t 
+FUNCTION(igraph_vector,is_equal)(const TYPE(igraph_vector) *lhs, 
+				 const TYPE(igraph_vector) *rhs) {
+  return FUNCTION(igraph_vector,all_e)(lhs, rhs);
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_all_l
+ * \brief Are all elements less?
+ * 
+ * \param lhs The first vector.
+ * \param rhs The second vector.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    less than the corresponding elements in \p rhs. Returns \c 0
+ *    (=false) if the lengths of the vectors don't match.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,all_l)(const TYPE(igraph_vector) *lhs, 
+					    const TYPE(igraph_vector) *rhs) {
+  long int i, s;
+  assert(lhs != 0);
+  assert(rhs != 0);
+  assert(lhs->stor_begin != 0);
+  assert(rhs->stor_begin != 0);
+  
+  s=FUNCTION(igraph_vector,size)(lhs);
+  if (s != FUNCTION(igraph_vector,size)(rhs)) {
+    return 0;
+  } else {
+    for (i=0; i<s; i++) {
+      BASE l=VECTOR(*lhs)[i];
+      BASE r=VECTOR(*rhs)[i];
+      if (l>=r) {
+	return 0;
+      }
+    }
+    return 1;
+  }  
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_all_g
+ * \brief Are all elements greater?
+ * 
+ * \param lhs The first vector.
+ * \param rhs The second vector.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    greater than the corresponding elements in \p rhs. Returns \c 0
+ *    (=false) if the lengths of the vectors don't match.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,all_g)(const TYPE(igraph_vector) *lhs, 
+					    const TYPE(igraph_vector) *rhs) {
+
+  long int i, s;
+  assert(lhs != 0);
+  assert(rhs != 0);
+  assert(lhs->stor_begin != 0);
+  assert(rhs->stor_begin != 0);
+  
+  s=FUNCTION(igraph_vector,size)(lhs);
+  if (s != FUNCTION(igraph_vector,size)(rhs)) {
+    return 0;
+  } else {
+    for (i=0; i<s; i++) {
+      BASE l=VECTOR(*lhs)[i];
+      BASE r=VECTOR(*rhs)[i];
+      if (l<=r) {
+	return 0;
+      }
+    }
+    return 1;
+  }  
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_all_le
+ * \brief Are all elements less or equal?
+ * 
+ * \param lhs The first vector.
+ * \param rhs The second vector.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    less than or equal to the corresponding elements in \p
+ *    rhs. Returns \c 0 (=false) if the lengths of the vectors don't
+ *    match.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+igraph_bool_t 
+FUNCTION(igraph_vector,all_le)(const TYPE(igraph_vector) *lhs, 
+			       const TYPE(igraph_vector) *rhs) {
+  long int i, s;
+  assert(lhs != 0);
+  assert(rhs != 0);
+  assert(lhs->stor_begin != 0);
+  assert(rhs->stor_begin != 0);
+  
+  s=FUNCTION(igraph_vector,size)(lhs);
+  if (s != FUNCTION(igraph_vector,size)(rhs)) {
+    return 0;
+  } else {
+    for (i=0; i<s; i++) {
+      BASE l=VECTOR(*lhs)[i];
+      BASE r=VECTOR(*rhs)[i];
+      if (l>r) {
+	return 0;
+      }
+    }
+    return 1;
+  }  
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_all_ge
+ * \brief Are all elements greater or equal?
+ * 
+ * \param lhs The first vector.
+ * \param rhs The second vector.
+ * \return Positive integer (=true) if the elements in the \p lhs are all 
+ *    greater than or equal to the corresponding elements in \p
+ *    rhs. Returns \c 0 (=false) if the lengths of the vectors don't
+ *    match.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+igraph_bool_t 
+FUNCTION(igraph_vector,all_ge)(const TYPE(igraph_vector) *lhs, 
+			       const TYPE(igraph_vector) *rhs) {
+  long int i, s;
+  assert(lhs != 0);
+  assert(rhs != 0);
+  assert(lhs->stor_begin != 0);
+  assert(rhs->stor_begin != 0);
+  
+  s=FUNCTION(igraph_vector,size)(lhs);
+  if (s != FUNCTION(igraph_vector,size)(rhs)) {
+    return 0;
+  } else {
+    for (i=0; i<s; i++) {
+      BASE l=VECTOR(*lhs)[i];
+      BASE r=VECTOR(*rhs)[i];
+      if (l<r) {
+	return 0;
+      }
+    }
+    return 1;
+  }  
+}
+
+#endif
+
+igraph_bool_t FUNCTION(igraph_i_vector,binsearch_slice)(const TYPE(igraph_vector) *v,
+                                                        BASE what, long int *pos,
+                                                        long int start, long int end);
+
+#ifndef NOTORDERED
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_binsearch
+ * \brief Finds an element by binary searching a sorted vector.
+ * 
+ * </para><para>
+ * It is assumed that the vector is sorted. If the specified element
+ * (\p what) is not in the vector, then the
+ * position of where it should be inserted (to keep the vector sorted)
+ * is returned.
+ * \param v The \type igraph_vector_t object.
+ * \param what The element to search for.
+ * \param pos Pointer to a \type long int. This is set to the
+ *   position of an instance of \p what in the
+ *   vector if it is present. If \p v does not
+ *   contain \p what then
+ *   \p pos is set to the position to which it
+ *   should be inserted (to keep the the vector sorted of course).
+ * \return Positive integer (true) if \p what is
+ *   found in the vector, zero (false) otherwise.
+ * 
+ * Time complexity: O(log(n)),
+ * n is the number of elements in
+ * \p v.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,binsearch)(const TYPE(igraph_vector) *v, 
+						BASE what, long int *pos) {
+  return FUNCTION(igraph_i_vector,binsearch_slice)(v, what, pos,
+      0, FUNCTION(igraph_vector,size)(v));
+}
+
+igraph_bool_t FUNCTION(igraph_i_vector,binsearch_slice)(const TYPE(igraph_vector) *v,
+                                                        BASE what, long int *pos,
+                                                        long int start, long int end) {
+  long int left  = start;
+  long int right = end-1;
+
+  while (left <= right) {
+    /* (right + left) / 2 could theoretically overflow for long vectors */
+    long int middle = left + ((right - left) >> 1);
+    if (VECTOR(*v)[middle] > what) {
+      right = middle - 1;
+    } else if (VECTOR(*v)[middle] < what) {
+      left = middle + 1;
+    } else {
+      if (pos != 0) {
+        *pos = middle;
+      }
+      return 1;
+    }
+  }
+
+  /* if we are here, the element was not found */
+  if (pos != 0) {
+    *pos = left;
+  }
+
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_binsearch2
+ * \brief Binary search, without returning the index.
+ * 
+ * </para><para>
+ * It is assumed that the vector is sorted.
+ * \param v The \type igraph_vector_t object.
+ * \param what The element to search for.
+ * \return Positive integer (true) if \p what is
+ *   found in the vector, zero (false) otherwise.
+ * 
+ * Time complexity: O(log(n)),
+ * n is the number of elements in
+ * \p v.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,binsearch2)(const TYPE(igraph_vector) *v, 
+						 BASE what) {
+  long int left=0;
+  long int right=FUNCTION(igraph_vector,size)(v)-1;
+
+  while (left <= right) {
+    /* (right + left) / 2 could theoretically overflow for long vectors */
+    long int middle = left + ((right - left) >> 1);
+    if (what < VECTOR(*v)[middle]) {
+      right = middle - 1;
+    } else if (what > VECTOR(*v)[middle]) {
+      left = middle + 1;
+    } else {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+#endif
+
+/**
+ * \function igraph_vector_scale
+ * \brief Multiply all elements of a vector by a constant
+ * 
+ * \param v The vector.
+ * \param by The constant.
+ * \return Error code. The current implementation always returns with success.
+ * 
+ * Added in version 0.2.</para><para>
+ * 
+ * Time complexity: O(n), the number of elements in a vector.
+ */
+
+void FUNCTION(igraph_vector,scale)(TYPE(igraph_vector) *v, BASE by) {
+  long int i;
+  for (i=0; i<FUNCTION(igraph_vector,size)(v); i++) {
+#ifdef PROD
+    PROD(VECTOR(*v)[i], VECTOR(*v)[i], by);
+#else
+    VECTOR(*v)[i] *= by;
+#endif
+  }
+}
+
+/**
+ * \function igraph_vector_add_constant
+ * \brief Add a constant to the vector.
+ * 
+ * \p plus is added to every element of \p v. Note that overflow
+ * might happen.
+ * \param v The input vector.
+ * \param plus The constant to add.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+void FUNCTION(igraph_vector,add_constant)(TYPE(igraph_vector) *v, BASE plus) {
+  long int i, n=FUNCTION(igraph_vector,size)(v);
+  for (i=0; i<n; i++) {
+#ifdef SUM
+    SUM(VECTOR(*v)[i], VECTOR(*v)[i], plus);
+#else
+    VECTOR(*v)[i] += plus;
+#endif
+  }
+}
+
+/** 
+ * \function igraph_vector_contains
+ * \brief Linear search in a vector.
+ * 
+ * Check whether the supplied element is included in the vector, by
+ * linear search.
+ * \param v The input vector.
+ * \param e The element to look for.
+ * \return \c TRUE if the element is found and \c FALSE otherwise.
+ * 
+ * Time complexity: O(n), the length of the vector.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,contains)(const TYPE(igraph_vector) *v, 
+					       BASE e) {
+  BASE *p=v->stor_begin;
+  while (p<v->end) {
+#ifdef EQ
+    if (EQ(*p,e)) {
+#else
+    if (*p==e) { 
+#endif
+      return 1;
+    }
+    p++;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_vector_search
+ * \brief Search from a given position
+ *
+ * The supplied element \p what is searched in vector \p v, starting
+ * from element index \p from. If found then the index of the first
+ * instance (after \p from) is stored in \p pos.
+ * \param v The input vector.
+ * \param from The index to start searching from. No range checking is
+ *     performed. 
+ * \param what The element to find.
+ * \param pos If not \c NULL then the index of the found element is
+ *    stored here.
+ * \return Boolean, \c TRUE if the element was found, \c FALSE
+ *   otherwise.
+ * 
+ * Time complexity: O(m), the number of elements to search, the length
+ * of the vector minus the \p from argument.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,search)(const TYPE(igraph_vector) *v, 
+					     long int from, BASE what, 
+					     long int *pos) {
+  long int i, n=FUNCTION(igraph_vector,size)(v);  
+  for (i=from; i<n; i++) {
+#ifdef EQ
+    if (EQ(VECTOR(*v)[i], what)) break;
+#else
+    if (VECTOR(*v)[i]==what) break;
+#endif
+  }
+  
+  if (i<n) {
+    if (pos != 0) {
+      *pos=i;
+    }
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_vector_filter_smaller
+ * \ingroup internal
+ */
+
+int FUNCTION(igraph_vector,filter_smaller)(TYPE(igraph_vector) *v, 
+					   BASE elem) {
+  long int i=0, n=FUNCTION(igraph_vector,size)(v);
+  long int s;
+  while (i<n && VECTOR(*v)[i]<elem) {
+    i++;
+  }
+  s=i;
+  
+  while (s<n && VECTOR(*v)[s]==elem) {
+    s++;
+  }
+  
+  FUNCTION(igraph_vector,remove_section)(v, 0, i+(s-i)/2);
+  return 0;
+}
+
+#endif
+
+/**
+ * \function igraph_vector_append
+ * \brief Append a vector to another one.
+ * 
+ * The target vector will be resized (except \p from is empty).
+ * \param to The vector to append to.
+ * \param from The vector to append, it is kept unchanged.
+ * \return Error code.
+ *
+ * Time complexity: O(n), the number of elements in the new vector.
+ */
+
+int FUNCTION(igraph_vector,append)(TYPE(igraph_vector) *to, 
+				   const TYPE(igraph_vector) *from) {
+  long tosize, fromsize;
+  
+  tosize=FUNCTION(igraph_vector,size)(to);
+  fromsize=FUNCTION(igraph_vector,size)(from);
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(to, tosize+fromsize));
+  memcpy(to->stor_begin+tosize, from->stor_begin, 
+	 sizeof(BASE) * (size_t) fromsize);
+  to->end=to->stor_begin+tosize+fromsize;
+  
+  return 0;
+}
+
+/**
+ * \function igraph_vector_get_interval
+ */
+
+int FUNCTION(igraph_vector,get_interval)(const TYPE(igraph_vector) *v, 
+					 TYPE(igraph_vector) *res,
+					 long int from, long int to) {
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(res, to-from));
+  memcpy(res->stor_begin, v->stor_begin+from, 
+	 (size_t) (to-from) * sizeof(BASE));
+  return 0;
+}
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_vector_maxdifference
+ * \brief The maximum absolute difference of \p m1 and \p m2
+ *
+ * The element with the largest absolute value in \p m1 - \p m2 is
+ * returned. Both vectors must be non-empty, but they not need to have
+ * the same length, the extra elements in the longer vector are ignored.
+ * \param m1 The first vector.
+ * \param m2 The second vector.
+ * \return The maximum absolute difference of \p m1 and \p m2.
+ *
+ * Time complexity: O(n), the number of elements in the shorter
+ * vector.
+ */
+
+BASE FUNCTION(igraph_vector,maxdifference)(const TYPE(igraph_vector) *m1,
+					   const TYPE(igraph_vector) *m2) {
+  long int n1=FUNCTION(igraph_vector,size)(m1);
+  long int n2=FUNCTION(igraph_vector,size)(m2);
+  long int n= n1 < n2 ? n1 : n2;
+  long int i;
+  BASE diff=ZERO;
+  
+  for (i=0; i<n; i++) {
+    BASE d=(BASE) fabs(VECTOR(*m1)[i]-VECTOR(*m2)[i]);
+    if (d > diff) {
+      diff=d;
+    }
+  }
+  
+  return diff;
+}
+
+#endif
+
+/**
+ * \function igraph_vector_update
+ * \brief Update a vector from another one.
+ * 
+ * After this operation the contents of \p to will be exactly the same
+ * \p from. \p to will be resized if it was originally shorter or
+ * longer than \p from.
+ * \param to The vector to update.
+ * \param from The vector to update from.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of elements in \p from.
+ */
+
+int FUNCTION(igraph_vector,update)(TYPE(igraph_vector) *to, 
+				   const TYPE(igraph_vector) *from) {
+  size_t n=(size_t) FUNCTION(igraph_vector,size)(from);
+  FUNCTION(igraph_vector,resize)(to, (long) n);
+  memcpy(to->stor_begin, from->stor_begin, sizeof(BASE)*n);
+  return 0;
+}
+
+/**
+ * \function igraph_vector_swap
+ * \brief Swap elements of two vectors.
+ * 
+ * The two vectors must have the same length, otherwise an error
+ * happens.
+ * \param v1 The first vector.
+ * \param v2 The second vector.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+int FUNCTION(igraph_vector,swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2) {
+  
+  long int i, n1=FUNCTION(igraph_vector,size)(v1);
+  long int n2=FUNCTION(igraph_vector,size)(v2);
+  if (n1 != n2) {
+    IGRAPH_ERROR("Vectors must have the same number of elements for swapping",
+		 IGRAPH_EINVAL);
+  }
+  
+  for (i=0; i<n1; i++) {
+    BASE tmp;
+    tmp=VECTOR(*v1)[i];
+    VECTOR(*v1)[i]=VECTOR(*v2)[i];
+    VECTOR(*v2)[i]=tmp;
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_vector_swap_elements
+ * \brief Swap two elements in a vector.
+ * 
+ * Note that currently no range checking is performed.
+ * \param v The input vector.
+ * \param i Index of the first element.
+ * \param j index of the second element. (Might be the same as the
+ * first.)
+ * \return Error code, currently always \c IGRAPH_SUCCESS.
+ * 
+ * Time complexity: O(1).
+ */
+
+int FUNCTION(igraph_vector,swap_elements)(TYPE(igraph_vector) *v,
+					  long int i, long int j) {
+  BASE tmp=VECTOR(*v)[i];
+  VECTOR(*v)[i]=VECTOR(*v)[j];
+  VECTOR(*v)[j]=tmp;
+  
+  return 0;
+}
+
+/**
+ * \function igraph_vector_reverse
+ * \brief Reverse the elements of a vector.
+ * 
+ * The first element will be last, the last element will be
+ * first, etc.
+ * \param v The input vector.
+ * \return Error code, currently always \c IGRAPH_SUCCESS.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+int FUNCTION(igraph_vector,reverse)(TYPE(igraph_vector) *v) {
+  
+  long int n=FUNCTION(igraph_vector,size)(v), n2=n/2;
+  long int i,j;
+  for (i=0, j=n-1; i<n2; i++, j--) {
+    BASE tmp;
+    tmp=VECTOR(*v)[i];
+    VECTOR(*v)[i]=VECTOR(*v)[j];
+    VECTOR(*v)[j]=tmp;
+  }
+  return 0;
+}
+
+/**
+ * \ingroup vector
+ * \function igraph_vector_shuffle
+ * \brief Shuffles a vector in-place using the Fisher-Yates method
+ * 
+ * </para><para>
+ * The Fisher-Yates shuffle ensures that every implementation is
+ * equally probable when using a proper randomness source. Of course
+ * this does not apply to pseudo-random generators as the cycle of
+ * these generators is less than the number of possible permutations
+ * of the vector if the vector is long enough.
+ * \param v The vector object.
+ * \return Error code, currently always \c IGRAPH_SUCCESS.
+ *
+ * Time complexity: O(n),
+ * n is the number of elements in the
+ * vector. 
+ *
+ * </para><para>
+ * References:
+ * \clist
+ * \cli (Fisher & Yates 1963)
+ *   R. A. Fisher and F. Yates. \emb Statistical Tables for Biological,
+ *   Agricultural and Medical Research. \eme Oliver and Boyd, 6th edition,
+ *   1963, page 37.
+ * \cli (Knuth 1998)
+ *   D. E. Knuth. \emb Seminumerical Algorithms, \eme volume 2 of \emb The Art
+ *   of Computer Programming. \eme Addison-Wesley, 3rd edition, 1998, page 145.
+ * \endclist
+ *
+ * \example examples/simple/igraph_fisher_yates_shuffle.c
+ */
+
+int FUNCTION(igraph_vector,shuffle)(TYPE(igraph_vector) *v) {
+  long int n = FUNCTION(igraph_vector,size)(v);
+  long int k;
+  BASE dummy;
+
+  RNG_BEGIN();
+  while (n > 1) {
+    k = RNG_INTEGER(0, n-1);
+    n--;
+    dummy = VECTOR(*v)[n];
+    VECTOR(*v)[n] = VECTOR(*v)[k];
+    VECTOR(*v)[k] = dummy;
+  }
+  RNG_END();
+
+  return IGRAPH_SUCCESS;
+}
+
+/**
+ * \function igraph_vector_add
+ * \brief Add two vectors.
+ * 
+ * Add the elements of \p v2 to \p v1, the result is stored in \p
+ * v1. The two vectors must have the same length.
+ * \param v1 The first vector, the result will be stored here.
+ * \param v2 The second vector, its contents will be unchanged. 
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+int FUNCTION(igraph_vector,add)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2) {
+  
+  long int n1=FUNCTION(igraph_vector,size)(v1);
+  long int n2=FUNCTION(igraph_vector,size)(v2);
+  long int i;
+  if (n1 != n2) {
+    IGRAPH_ERROR("Vectors must have the same number of elements for swapping",
+		 IGRAPH_EINVAL);
+  }
+  
+  for (i=0; i<n1; i++) {
+#ifdef SUM
+    SUM(VECTOR(*v1)[i], VECTOR(*v1)[i], VECTOR(*v2)[i]);
+#else
+    VECTOR(*v1)[i] += VECTOR(*v2)[i];
+#endif
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_vector_sub
+ * \brief Subtract a vector from another one.
+ * 
+ * Subtract the elements of \p v2 from \p v1, the result is stored in
+ * \p v1. The two vectors must have the same length.
+ * \param v1 The first vector, to subtract from. The result is stored
+ *    here.
+ * \param v2 The vector to subtract, it will be unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+int FUNCTION(igraph_vector,sub)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2) {
+  
+  long int n1=FUNCTION(igraph_vector,size)(v1);
+  long int n2=FUNCTION(igraph_vector,size)(v2);
+  long int i;
+  if (n1 != n2) {
+    IGRAPH_ERROR("Vectors must have the same number of elements for swapping",
+		 IGRAPH_EINVAL);
+  }
+  
+  for (i=0; i<n1; i++) {
+#ifdef DIFF
+    DIFF(VECTOR(*v1)[i], VECTOR(*v1)[i], VECTOR(*v2)[i]);
+#else
+    VECTOR(*v1)[i] -= VECTOR(*v2)[i];
+#endif
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_vector_mul
+ * \brief Multiply two vectors.
+ * 
+ * \p v1 will be multiplied by \p v2, elementwise. The two vectors
+ * must have the same length.
+ * \param v1 The first vector, the result will be stored here.
+ * \param v2 The second vector, it is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+int FUNCTION(igraph_vector,mul)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2) {
+  
+  long int n1=FUNCTION(igraph_vector,size)(v1);
+  long int n2=FUNCTION(igraph_vector,size)(v2);
+  long int i;
+  if (n1 != n2) {
+    IGRAPH_ERROR("Vectors must have the same number of elements for swapping",
+		 IGRAPH_EINVAL);
+  }
+  
+  for (i=0; i<n1; i++) {
+#ifdef PROD
+    PROD(VECTOR(*v1)[i], VECTOR(*v1)[i], VECTOR(*v2)[i]);
+#else
+    VECTOR(*v1)[i] *= VECTOR(*v2)[i];
+#endif
+  }
+  
+  return 0;
+}
+
+/**
+ * \function igraph_vector_div
+ * \brief Divide a vector by another one.
+ * 
+ * \p v1 is divided by \p v2, elementwise. They must have the same length. If the
+ * base type of the vector can generate divide by zero errors then
+ * please make sure that \p v2 contains no zero if you want to avoid
+ * trouble.
+ * \param v1 The dividend. The result is also stored here.
+ * \param v2 The divisor, it is left unchanged.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the length of the vectors.
+ */
+
+int FUNCTION(igraph_vector,div)(TYPE(igraph_vector) *v1, 
+				const TYPE(igraph_vector) *v2) {
+  
+  long int n1=FUNCTION(igraph_vector,size)(v1);
+  long int n2=FUNCTION(igraph_vector,size)(v2);
+  long int i;
+  if (n1 != n2) {
+    IGRAPH_ERROR("Vectors must have the same number of elements for swapping",
+		 IGRAPH_EINVAL);
+  }
+  
+  for (i=0; i<n1; i++) {
+#ifdef DIV
+    DIV(VECTOR(*v1)[i], VECTOR(*v1)[i], VECTOR(*v2)[i]);
+#else
+    VECTOR(*v1)[i] /= VECTOR(*v2)[i];
+#endif
+  }
+  
+  return 0;
+}
+
+#ifndef NOABS
+
+int FUNCTION(igraph_vector,abs)(TYPE(igraph_vector) *v) {
+#ifdef UNSIGNED
+  /* Nothing do to, unsigned type */
+#else
+  long int i, n=FUNCTION(igraph_vector,size)(v);
+  for (i=0; i<n; i++) {
+    VECTOR(*v)[i]= VECTOR(*v)[i] >= 0 ? VECTOR(*v)[i] : -VECTOR(*v)[i];
+  }
+#endif
+  
+  return 0;
+}
+
+#endif
+
+#ifndef NOTORDERED
+
+/**
+ * \function igraph_vector_minmax
+ * \brief Minimum and maximum elements of a vector.
+ * 
+ * Handy if you want to have both the smallest and largest element of
+ * a vector. The vector is only traversed once. The vector must by non-empty.
+ * \param v The input vector. It must contain at least one element.
+ * \param min Pointer to a base type variable, the minimum is stored
+ *     here.
+ * \param max Pointer to a base type variable, the maximum is stored
+ *     here.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+int FUNCTION(igraph_vector,minmax)(const TYPE(igraph_vector) *v,
+				   BASE *min, BASE *max) {
+  long int n=FUNCTION(igraph_vector,size)(v);
+  long int i;
+  *min=*max=VECTOR(*v)[0];
+  for (i=1; i<n; i++) {
+    BASE tmp=VECTOR(*v)[i];
+    if (tmp > *max) { 
+      *max=tmp;
+    } else if (tmp < *min) {
+      *min=tmp;
+    }
+  }
+  return 0;
+}
+
+/**
+ * \function igraph_vector_which_minmax
+ * \brief Index of the minimum and maximum elements
+ * 
+ * Handy if you need the indices of the smallest and largest
+ * elements. The vector is traversed only once. The vector must to
+ * non-empty.
+ * \param v The input vector. It must contain at least one element.
+ * \param which_min The index of the minimum element will be stored
+ *   here.
+ * \param which_max The index of the maximum element will be stored
+ *   here.
+ * \return Error code.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+int FUNCTION(igraph_vector,which_minmax)(const TYPE(igraph_vector) *v,
+					 long int *which_min, long int *which_max) {
+
+  long int n=FUNCTION(igraph_vector,size)(v);
+  long int i;
+  BASE min, max;
+  *which_min=*which_max=0;
+  min=max=VECTOR(*v)[0];
+  for (i=1; i<n; i++) {
+    BASE tmp=VECTOR(*v)[i];
+    if (tmp > max) {
+      max=tmp;
+      *which_max=i;
+    } else if (tmp < min) {
+      min=tmp;
+      *which_min=i;
+    }
+  }
+  return 0;
+}
+
+#endif
+
+/**
+ * \function igraph_vector_isnull
+ * \brief Are all elements zero?
+ * 
+ * Checks whether all elements of a vector are zero.
+ * \param v The input vector
+ * \return Boolean, \c TRUE if the vector contains only zeros, \c
+ *    FALSE otherwise.
+ * 
+ * Time complexity: O(n), the number of elements.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector,isnull)(const TYPE(igraph_vector) *v) {
+
+  long int n=FUNCTION(igraph_vector,size)(v);
+  long int i=0;
+  
+#ifdef EQ
+  while (i<n && EQ(VECTOR(*v)[i], ZERO)) {
+#else
+  while (i<n && VECTOR(*v)[i]==ZERO) {
+#endif
+    i++;
+  }
+  
+  return i==n;
+}
+
+#ifndef NOTORDERED
+
+int FUNCTION(igraph_i_vector,intersect_sorted)(
+    const TYPE(igraph_vector) *v1, long int begin1, long int end1,
+    const TYPE(igraph_vector) *v2, long int begin2, long int end2,
+    TYPE(igraph_vector) *result);
+
+/**
+ * \function igraph_vector_intersect_sorted
+ * \brief Calculates the intersection of two sorted vectors
+ *
+ * The elements that are contained in both vectors are stored in the result
+ * vector. All three vectors must be initialized.
+ *
+ * </para><para>
+ * Instead of the naive intersection which takes O(n), this function uses
+ * the set intersection method of Ricardo Baeza-Yates, which is more efficient
+ * when one of the vectors is significantly smaller than the other, and
+ * gives similar performance on average when the two vectors are equal.
+ *
+ * </para><para>
+ * The algorithm keeps the multiplicities of the elements: if an element appears
+ * k1 times in the first vector and k2 times in the second, the result
+ * will include that element min(k1, k2) times.
+ *
+ * </para><para>
+ * Reference: Baeza-Yates R: A fast set intersection algorithm for sorted
+ * sequences. In: Lecture Notes in Computer Science, vol. 3109/2004, pp.
+ * 400--408, 2004. Springer Berlin/Heidelberg. ISBN: 978-3-540-22341-2.
+ *
+ * \param v1 the first vector
+ * \param v2 the second vector
+ * \param result the result vector, which will also be sorted.
+ *
+ * Time complexity: O(m log(n)) where m is the size of the smaller vector
+ * and n is the size of the larger one.
+ */
+int FUNCTION(igraph_vector,intersect_sorted)(const TYPE(igraph_vector) *v1,
+    const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result) {
+  long int size1, size2;
+
+  size1 = FUNCTION(igraph_vector,size)(v1);
+  size2 = FUNCTION(igraph_vector,size)(v2);
+
+  FUNCTION(igraph_vector,clear)(result);
+
+  if (size1 == 0 || size2 == 0)
+    return 0;
+
+  IGRAPH_CHECK(FUNCTION(igraph_i_vector,intersect_sorted)(
+    v1, 0, size1, v2, 0, size2, result));
+  return 0;
+}
+
+int FUNCTION(igraph_i_vector,intersect_sorted)(
+    const TYPE(igraph_vector) *v1, long int begin1, long int end1,
+    const TYPE(igraph_vector) *v2, long int begin2, long int end2,
+    TYPE(igraph_vector) *result) {
+  long int size1, size2, probe1, probe2;
+
+  if (begin1 == end1 || begin2 == end2)
+    return 0;
+
+  size1 = end1 - begin1;
+  size2 = end2 - begin2;
+
+  if (size1 < size2) {
+    probe1 = begin1 + (size1 >> 1);      /* pick the median element */
+    FUNCTION(igraph_i_vector,binsearch_slice)(v2, VECTOR(*v1)[probe1], &probe2, begin2, end2);
+    IGRAPH_CHECK(FUNCTION(igraph_i_vector,intersect_sorted)(
+        v1, begin1, probe1, v2, begin2, probe2, result
+    ));
+    if (!(probe2 == end2 || VECTOR(*v1)[probe1] < VECTOR(*v2)[probe2])) {
+      IGRAPH_CHECK(FUNCTION(igraph_vector,push_back)(result, VECTOR(*v2)[probe2]));
+      probe2++;
+    }
+    IGRAPH_CHECK(FUNCTION(igraph_i_vector,intersect_sorted)(
+        v1, probe1+1, end1, v2, probe2, end2, result
+    ));
+  } else {
+    probe2 = begin2 + (size2 >> 1);      /* pick the median element */
+    FUNCTION(igraph_i_vector,binsearch_slice)(v1, VECTOR(*v2)[probe2], &probe1, begin1, end1);
+    IGRAPH_CHECK(FUNCTION(igraph_i_vector,intersect_sorted)(
+        v1, begin1, probe1, v2, begin2, probe2, result
+    ));
+    if (!(probe1 == end1 || VECTOR(*v2)[probe2] < VECTOR(*v1)[probe1])) {
+      IGRAPH_CHECK(FUNCTION(igraph_vector,push_back)(result, VECTOR(*v2)[probe2]));
+      probe1++;
+    }
+    IGRAPH_CHECK(FUNCTION(igraph_i_vector,intersect_sorted)(
+        v1, probe1, end1, v2, probe2+1, end2, result
+    ));
+  }
+
+  return 0;
+}
+
+/**
+ * \function igraph_vector_difference_sorted
+ * \brief Calculates the difference between two sorted vectors (considered as sets)
+ *
+ * The elements that are contained in only the first vector but not the second are
+ * stored in the result vector. All three vectors must be initialized.
+ *
+ * \param v1 the first vector
+ * \param v2 the second vector
+ * \param result the result vector
+ */
+int FUNCTION(igraph_vector,difference_sorted)(const TYPE(igraph_vector) *v1,
+    const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result) {
+  long int i, j, i0, j0;
+  i0 = FUNCTION(igraph_vector,size)(v1);
+  j0 = FUNCTION(igraph_vector,size)(v2);
+  i = j = 0;
+
+  if (i0 == 0) {
+    /* v1 is empty, this is easy */
+    FUNCTION(igraph_vector,clear)(result);
+    return IGRAPH_SUCCESS;
+  }
+
+  if (j0 == 0) {
+    /* v2 is empty, this is easy */
+    IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(result, i0));
+    memcpy(result->stor_begin, v1->stor_begin, sizeof(BASE) * (size_t) i0);
+    return IGRAPH_SUCCESS;
+  }
+
+  FUNCTION(igraph_vector,clear)(result);
+
+  /* Copy the part of v1 that is less than the first element of v2 */
+  while (i < i0 && VECTOR(*v1)[i] < VECTOR(*v2)[j]) { i++; }
+  if (i > 0) {
+    IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(result, i));
+    memcpy(result->stor_begin, v1->stor_begin, sizeof(BASE) * (size_t) i);
+  }
+
+  while (i < i0 && j < j0) {
+    BASE element = VECTOR(*v1)[i];
+    if (element == VECTOR(*v2)[j]) {
+      i++; j++;
+      while (i < i0 && VECTOR(*v1)[i] == element) { i++; }
+      while (j < j0 && VECTOR(*v2)[j] == element) { j++; }
+    } else if (element < VECTOR(*v2)[j]) {
+      IGRAPH_CHECK(FUNCTION(igraph_vector,push_back)(result, element));
+      i++;
+    }
+    else j++;
+  }
+  if (i < i0) {
+    long int oldsize = FUNCTION(igraph_vector,size)(result);
+    IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(result, oldsize+i0-i));
+    memcpy(result->stor_begin+oldsize, v1->stor_begin+i, 
+	   sizeof(BASE)* (size_t) (i0-i));
+  }
+
+  return 0;
+}
+
+#endif
+
+#if defined(OUT_FORMAT)
+
+#ifndef USING_R
+int FUNCTION(igraph_vector,print)(const TYPE(igraph_vector) *v) {
+  long int i, n=FUNCTION(igraph_vector,size)(v);
+  if (n!=0) {
+#ifdef PRINTFUNC
+    PRINTFUNC(VECTOR(*v)[0]);
+#else
+    printf(OUT_FORMAT, VECTOR(*v)[0]);
+#endif
+  }
+  for (i=1; i<n; i++) {
+#ifdef PRINTFUNC
+    putchar(' '); PRINTFUNC(VECTOR(*v)[i]);
+#else
+    printf(" " OUT_FORMAT, VECTOR(*v)[i]);
+#endif
+  }
+  printf("\n");
+  return 0;
+}
+
+int FUNCTION(igraph_vector,printf)(const TYPE(igraph_vector) *v,
+																	 const char *format) {
+  long int i, n=FUNCTION(igraph_vector,size)(v);
+  if (n!=0) {
+    printf(format, VECTOR(*v)[0]);
+  }
+  for (i=1; i<n; i++) {
+    putchar(' '); printf(format, VECTOR(*v)[i]);
+  }
+  printf("\n");
+  return 0;
+}
+
+#endif
+
+int FUNCTION(igraph_vector,fprint)(const TYPE(igraph_vector) *v, FILE *file) {
+  long int i, n=FUNCTION(igraph_vector,size)(v);
+  if (n!=0) {
+#ifdef FPRINTFUNC
+    FPRINTFUNC(file, VECTOR(*v)[0]);
+#else
+    fprintf(file, OUT_FORMAT, VECTOR(*v)[0]);
+#endif
+  }
+  for (i=1; i<n; i++) {
+#ifdef FPRINTFUNC
+    fputc(' ', file); FPRINTFUNC(file, VECTOR(*v)[i]);
+#else
+    fprintf(file, " " OUT_FORMAT, VECTOR(*v)[i]);
+#endif
+  }
+  fprintf(file, "\n");
+  return 0;
+}
+
+#endif
+
+int FUNCTION(igraph_vector,index)(const TYPE(igraph_vector) *v,
+                                  TYPE(igraph_vector) *newv,
+                                  const igraph_vector_t *idx) {
+  
+  long int i, newlen=igraph_vector_size(idx);
+  IGRAPH_CHECK(FUNCTION(igraph_vector,resize)(newv, newlen));
+  
+  for (i=0; i<newlen; i++) {
+    long int j=(long int) VECTOR(*idx)[i];
+    VECTOR(*newv)[i] = VECTOR(*v)[j];
+  }
+  
+  return 0;
+}
+
+int FUNCTION(igraph_vector,index_int)(TYPE(igraph_vector) *v,
+				      const igraph_vector_int_t *idx) {
+  BASE *tmp;
+  int i, n=igraph_vector_int_size(idx);
+
+  tmp=igraph_Calloc(n, BASE);
+  if (!tmp) { IGRAPH_ERROR("Cannot index vector", IGRAPH_ENOMEM); }
+
+  for (i=0; i<n; i++) { tmp[i] = VECTOR(*v)[ VECTOR(*idx)[i] ]; }
+
+  igraph_Free(v->stor_begin);
+  v->stor_begin = tmp;
+  v->stor_end = v->end = tmp + n;
+
+  return 0;
+}
diff --git a/src/vector_ptr.c b/src/vector_ptr.c
new file mode 100644
index 0000000..3b8c717
--- /dev/null
+++ b/src/vector_ptr.c
@@ -0,0 +1,620 @@
+/* -*- 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
+
+*/
+
+#include "igraph_types.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_memory.h"
+#include "igraph_random.h"
+#include "igraph_error.h"
+#include "config.h"
+
+#include <assert.h>
+#include <string.h> 		/* memcpy & co. */
+#include <stdlib.h>
+
+/**
+ * \section about_igraph_vector_ptr_objects Pointer vectors
+ * (<type>igraph_vector_ptr_t</type>)
+ * 
+ * <para>The \type igraph_vector_ptr_t data type is very similar to
+ * the \type igraph_vector_t type, but it stores generic pointers instead of
+ * real numbers.</para>
+ * 
+ * <para>This type has the same space complexity as \type
+ * igraph_vector_t, and most implemented operations work the same way
+ * as for \type igraph_vector_t. </para>
+ * 
+ * <para>This type is mostly used to pass to or receive from a set of
+ * graphs to some \a igraph functions, such as \ref
+ * igraph_decompose(), which decomposes a graph to connected
+ * components.</para>
+ * 
+ * <para>The same \ref VECTOR macro used for ordinary vectors can be
+ * used for pointer vectors as well, please note that a typeless
+ * generic pointer will be provided by this macro and you may need to
+ * cast it to a specific pointer before starting to work with it.</para>
+ *
+ * <para>Pointer vectors may have an associated item destructor function
+ * which takes a pointer and returns nothing. The item destructor will
+ * be called on each item in the pointer vector when it is destroyed by
+ * \ref igraph_vector_ptr_destroy() or \ref igraph_vector_ptr_destroy_all(),
+ * or when its elements are freed by \ref igraph_vector_ptr_free_all().
+ * Note that the semantics of an item destructor does not coincide with
+ * C++ destructors; for instance, when a pointer vector is resized to a
+ * smaller size, the extra items will \em not be destroyed automatically!
+ * Nevertheless, item destructors may become handy in many cases; for
+ * instance, a vector of graphs generated by \ref igraph_decompose() can
+ * be destroyed with a single call to \ref igraph_vector_ptr_destroy_all()
+ * if the item destructor is set to \ref igraph_destroy().</para>
+ */
+
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_init
+ * \brief Initialize a pointer vector (constructor).
+ *
+ * </para><para>
+ * This is the constructor of the pointer vector data type. All
+ * pointer vectors constructed this way should be destroyed via
+ * calling \ref igraph_vector_ptr_destroy().
+ * \param v Pointer to an uninitialized
+ *        <type>igraph_vector_ptr_t</type> object, to be created.
+ * \param size Integer, the size of the pointer vector.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM if out of memory
+ * 
+ * Time complexity: operating system dependent, the amount of \quote
+ * time \endquote required to allocate \p size elements.
+ */
+
+int igraph_vector_ptr_init      (igraph_vector_ptr_t* v, int long size) {	
+        long int alloc_size= size > 0 ? size : 1;
+	assert(v != NULL);
+	if (size < 0) { size=0; }
+	v->stor_begin=igraph_Calloc(alloc_size, void*);
+	if (v->stor_begin==0) {
+	  IGRAPH_ERROR("vector ptr init failed", IGRAPH_ENOMEM);
+	}
+	v->stor_end=v->stor_begin + alloc_size;
+	v->end=v->stor_begin+size;
+	v->item_destructor=0;
+
+	return 0;
+}
+
+/**
+ */ 
+
+const igraph_vector_ptr_t *igraph_vector_ptr_view (const igraph_vector_ptr_t *v, void *const *data, 
+				     long int length) {
+  igraph_vector_ptr_t *v2=(igraph_vector_ptr_t*) v;
+  v2->stor_begin=(void **)data;
+  v2->stor_end=(void**)data+length;
+  v2->end=v2->stor_end;
+  v2->item_destructor=0;
+  return v;
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_destroy
+ * \brief Destroys a pointer vector.
+ * 
+ * </para><para>
+ * The destructor for pointer vectors.
+ * \param v Pointer to the pointer vector to destroy.
+ * 
+ * Time complexity: operating system dependent, the \quote time
+ * \endquote required to deallocate O(n) bytes, n is the number of
+ * elements allocated for the pointer vector (not necessarily the
+ * number of elements in the vector).
+ */
+
+void igraph_vector_ptr_destroy   (igraph_vector_ptr_t* v) {
+  assert(v != 0);
+  if (v->stor_begin != 0) {
+    igraph_Free(v->stor_begin);
+    v->stor_begin = NULL;
+  }
+}
+
+void igraph_i_vector_ptr_call_item_destructor_all(igraph_vector_ptr_t* v) {
+  void **ptr;
+
+  if (v->item_destructor != 0) {
+    for (ptr=v->stor_begin; ptr<v->end; ptr++) {
+      if (*ptr != 0)
+        v->item_destructor(*ptr);
+    }
+  }
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_free_all
+ * \brief Frees all the elements of a pointer vector.
+ *
+ * If an item destructor is set for this pointer vector, this function will
+ * first call the destructor on all elements of the vector and then
+ * free all the elements using free(). If an item destructor is not set,
+ * the elements will simply be freed.
+ *
+ * \param v Pointer to the pointer vector whose elements will be freed.
+ * 
+ * Time complexity: operating system dependent, the \quote time
+ * \endquote required to call the destructor n times and then
+ * deallocate O(n) pointers, each pointing to a memory area of
+ * arbitrary size. n is the number of elements in the pointer vector.
+ */
+
+void igraph_vector_ptr_free_all   (igraph_vector_ptr_t* v) {
+  void **ptr;
+  assert(v != 0);
+  assert(v->stor_begin != 0);
+
+  igraph_i_vector_ptr_call_item_destructor_all(v);
+  for (ptr=v->stor_begin; ptr<v->end; ptr++) {
+    igraph_Free(*ptr);
+  }
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_destroy_all
+ * \brief Frees all the elements and destroys the pointer vector.
+ *
+ * This function is equivalent to \ref igraph_vector_ptr_free_all()
+ * followed by \ref igraph_vector_ptr_destroy().
+ *
+ * \param v Pointer to the pointer vector to destroy.
+ *
+ * Time complexity: operating system dependent, the \quote time
+ * \endquote required to deallocate O(n) pointers, each pointing to
+ * a memory area of arbitrary size, plus the \quote time \endquote
+ * required to deallocate O(n) bytes, n being the number of elements
+ * allocated for the pointer vector (not necessarily the number of
+ * elements in the vector).
+ */
+
+void igraph_vector_ptr_destroy_all   (igraph_vector_ptr_t* v) { 
+  assert(v != 0);
+  assert(v->stor_begin != 0);
+  igraph_vector_ptr_free_all(v);
+  igraph_vector_ptr_set_item_destructor(v, 0);
+  igraph_vector_ptr_destroy(v);
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Reserves memory for a pointer vector for later use.
+ *
+ * @return Error code:
+ *         - <b>IGRAPH_ENOMEM</b>: out of memory
+ */
+
+int igraph_vector_ptr_reserve   (igraph_vector_ptr_t* v, long int size) {
+	long int actual_size=igraph_vector_ptr_size(v);
+	void **tmp;
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	
+	if (size <= igraph_vector_ptr_size(v)) { return 0; }
+
+	tmp=igraph_Realloc(v->stor_begin, (size_t) size, void*);
+	if (tmp==0) {
+	  IGRAPH_ERROR("vector ptr reserve failed", IGRAPH_ENOMEM);
+	}
+	v->stor_begin=tmp;
+	v->stor_end=v->stor_begin + size;
+	v->end=v->stor_begin+actual_size;
+	
+	return 0;
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Decides whether the pointer vector is empty.
+ */
+
+igraph_bool_t igraph_vector_ptr_empty     (const igraph_vector_ptr_t* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);	
+	return v->stor_begin == v->end;
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_size
+ * \brief Gives the number of elements in the pointer vector.
+ * 
+ * \param v The pointer vector object.
+ * \return The size of the object, ie. the number of pointers stored.
+ * 
+ * Time complexity: O(1).
+ */
+
+long int igraph_vector_ptr_size      (const igraph_vector_ptr_t* v) {
+	assert(v != NULL);
+/* 	assert(v->stor_begin != NULL);		 */ /* TODO */
+	return v->end - v->stor_begin;
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_clear
+ * \brief Removes all elements from a pointer vector.
+ * 
+ * </para><para>
+ * This function resizes a pointer to vector to zero length. Note that
+ * the pointed objects are \em not deallocated, you should call
+ * free() on them, or make sure that their allocated memory is freed
+ * in some other way, you'll get memory leaks otherwise. If you have
+ * set up an item destructor earlier, the destructor will be called
+ * on every element.
+ * 
+ * </para><para>
+ * Note that the current implementation of this function does
+ * \em not deallocate the memory required for storing the
+ * pointers, so making a pointer vector smaller this way does not give
+ * back any memory. This behavior might change in the future.
+ * \param v The pointer vector to clear.
+ * 
+ * Time complexity: O(1).
+ */
+
+void igraph_vector_ptr_clear     (igraph_vector_ptr_t* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	igraph_i_vector_ptr_call_item_destructor_all(v);
+	v->end = v->stor_begin;	
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_push_back
+ * \brief Appends an element to the back of a pointer vector.
+ * 
+ * \param v The pointer vector.
+ * \param e The new element to include in the pointer vector.
+ * \return Error code.
+ * \sa igraph_vector_push_back() for the corresponding operation of
+ * the ordinary vector type.
+ * 
+ * Time complexity: O(1) or O(n), n is the number of elements in the
+ * vector. The pointer vector implementation ensures that n subsequent
+ * push_back operations need O(n) time to complete.
+ */
+
+int igraph_vector_ptr_push_back (igraph_vector_ptr_t* v, void* e) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);	
+
+	/* full, allocate more storage */
+	if (v->stor_end == v->end) {
+		long int new_size = igraph_vector_ptr_size(v) * 2;
+		if (new_size == 0) { new_size = 1; }
+		IGRAPH_CHECK(igraph_vector_ptr_reserve(v, new_size));
+	}
+	
+	*(v->end) = e;
+	v->end += 1;
+	
+	return 0;
+}
+
+void *igraph_vector_ptr_pop_back (igraph_vector_ptr_t *v) {
+	void *tmp;
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);
+	assert(v->stor_begin != v->end);
+	tmp=*(v->end);
+	v->end -= 1;
+	  
+	return tmp;
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_insert
+ * \brief Inserts a single element into a pointer vector.
+ *
+ * Note that this function does not do range checking. Insertion will shift the
+ * elements from the position given to the end of the vector one position to the
+ * right, and the new element will be inserted in the empty space created at
+ * the given position. The size of the vector will increase by one.
+ *
+ * \param v The pointer vector object.
+ * \param pos The position where the new element is inserted.
+ * \param e The inserted element
+ */
+int igraph_vector_ptr_insert(igraph_vector_ptr_t* v, long int pos, void* e) {
+  long int size = igraph_vector_ptr_size(v);
+  IGRAPH_CHECK(igraph_vector_ptr_resize(v, size+1));
+  if (pos<size) {
+    memmove(v->stor_begin+pos+1, v->stor_begin+pos, 
+	    sizeof(void*) * (size_t) (size-pos));
+  }
+  v->stor_begin[pos] = e;
+  return 0;
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_e
+ * \brief Access an element of a pointer vector.
+ * 
+ * \param v Pointer to a pointer vector.
+ * \param pos The index of the pointer to return.
+ * \return The pointer at \p pos position.
+ * 
+ * Time complexity: O(1).
+ */
+
+void* igraph_vector_ptr_e         (const igraph_vector_ptr_t* v, long int pos) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);	
+	return * (v->stor_begin + pos);
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_set
+ * \brief Assign to an element of a pointer vector.
+ * 
+ * \param v Pointer to a pointer vector.
+ * \param pos The index of the pointer to update.
+ * \param value The new pointer to set in the vector.
+ *
+ * Time complexity: O(1).
+ */
+
+void igraph_vector_ptr_set       (igraph_vector_ptr_t* v, long int pos, void* value) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);		
+	*(v->stor_begin + pos) = value;
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Set all elements of a pointer vector to the NULL pointer.
+ */
+
+void igraph_vector_ptr_null      (igraph_vector_ptr_t* v) {
+	assert(v != NULL);
+	assert(v->stor_begin != NULL);		
+	if (igraph_vector_ptr_size(v)>0) {
+	  memset(v->stor_begin, 0, sizeof(void*) * 
+		 (size_t) igraph_vector_ptr_size(v));
+	}
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_resize
+ * \brief Resizes a pointer vector.
+ * 
+ * </para><para>
+ * Note that if a vector is made smaller the pointed object are not
+ * deallocated by this function and the item destructor is not called
+ * on the extra elements.
+ *
+ * \param v A pointer vector.
+ * \param newsize The new size of the pointer vector.
+ * \return Error code.
+ * 
+ * Time complexity: O(1) if the vector if made smaller. Operating
+ * system dependent otherwise, the amount of \quote time \endquote
+ * needed to allocate the memory for the vector elements.
+ */
+
+int igraph_vector_ptr_resize(igraph_vector_ptr_t* v, long int newsize) {
+  IGRAPH_CHECK(igraph_vector_ptr_reserve(v, newsize));
+  v->end = v->stor_begin+newsize;
+  return 0;
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Initializes a pointer vector from an array (constructor).
+ *
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM if out of memory
+ */
+
+int igraph_vector_ptr_init_copy(igraph_vector_ptr_t *v, void* *data, long int length) {
+  v->stor_begin=igraph_Calloc(length, void*);
+  if (v->stor_begin==0) {
+    IGRAPH_ERROR("cannot init ptr vector from array", IGRAPH_ENOMEM);
+  }
+  v->stor_end=v->stor_begin+length;
+  v->end=v->stor_end;
+  v->item_destructor=0;
+  memcpy(v->stor_begin, data, (size_t) length * sizeof(void*));
+  
+  return 0;
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Copy the contents of a pointer vector to a regular C array.
+ */
+
+void igraph_vector_ptr_copy_to(const igraph_vector_ptr_t *v, void** to) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);		
+  if (v->end != v->stor_begin) {
+    memcpy(to, v->stor_begin, sizeof(void*) * 
+	   (size_t) (v->end - v->stor_begin));
+  }
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_copy
+ * \brief Copy a pointer vector (constructor).
+ *
+ * </para><para>
+ * This function creates a pointer vector by copying another one. This
+ * is shallow copy, only the pointers in the vector will be copied.
+ *
+ * </para><para>
+ * It is potentially dangerous to copy a pointer vector with an associated
+ * item destructor. The copied vector will inherit the item destructor,
+ * which may cause problems when both vectors are destroyed as the items
+ * might get destroyed twice. Make sure you know what you are doing when
+ * copying a pointer vector with an item destructor, or unset the item
+ * destructor on one of the vectors later.
+ *
+ * \param to Pointer to an uninitialized pointer vector object.
+ * \param from A pointer vector object.
+ * \return Error code:
+ *         \c IGRAPH_ENOMEM if out of memory
+ * 
+ * Time complexity: O(n) if allocating memory for n elements can be
+ * done in O(n) time.
+ */
+
+int igraph_vector_ptr_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from) {
+  assert(from != NULL);
+/*   assert(from->stor_begin != NULL); */ /* TODO */
+  to->stor_begin=igraph_Calloc(igraph_vector_ptr_size(from), void*);
+  if (to->stor_begin==0) {
+    IGRAPH_ERROR("cannot copy ptr vector", IGRAPH_ENOMEM);
+  }
+  to->stor_end=to->stor_begin+igraph_vector_ptr_size(from);
+  to->end=to->stor_end;
+  to->item_destructor=from->item_destructor;
+  memcpy(to->stor_begin, from->stor_begin, 
+	 (size_t) igraph_vector_ptr_size(from)*sizeof(void*));
+  
+  return 0;
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Remove an element from a pointer vector.
+ */
+
+void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, long int pos) {
+  assert(v != NULL);
+  assert(v->stor_begin != NULL);
+  if (pos+1<igraph_vector_ptr_size(v)) { /* TOOD: why is this needed */
+    memmove(v->stor_begin+pos, v->stor_begin+pos+1,
+	    sizeof(void*) * (size_t) (igraph_vector_ptr_size(v)-pos-1));
+  }
+  v->end--;
+}
+
+/**
+ * \ingroup vectorptr
+ * \brief Sort the pointer vector based on an external comparison function
+ *
+ * Sometimes it is necessary to sort the pointers in the vector based on
+ * the property of the element being referenced by the pointer. This
+ * function allows us to sort the vector based on an arbitrary external
+ * comparison function which accepts two \c void* pointers \c p1 and \c p2
+ * and returns an integer less than, equal to or greater than zero if the
+ * first argument is considered to be respectively less than, equal to, or
+ * greater than the second. \c p1 and \c p2 will point to the pointer in the
+ * vector, so they have to be double-dereferenced if one wants to get access
+ * to the underlying object the address of which is stored in \c v .
+ */
+void igraph_vector_ptr_sort(igraph_vector_ptr_t *v, int (*compar)(const void*, const void*)) {
+  qsort(v->stor_begin, (size_t) igraph_vector_ptr_size(v), sizeof(void*), 
+	compar);
+}
+
+int igraph_vector_ptr_index_int(igraph_vector_ptr_t *v,
+				const igraph_vector_int_t *idx) {
+  void **tmp;
+  int i, n=igraph_vector_int_size(idx);
+
+  tmp=igraph_Calloc(n, void*);
+  if (!tmp) { IGRAPH_ERROR("Cannot index pointer vector", IGRAPH_ENOMEM); }
+
+  for (i=0; i<n; i++) { tmp[i] = VECTOR(*v)[ VECTOR(*idx)[i] ]; }
+
+  igraph_Free(v->stor_begin);
+  v->stor_begin = tmp;
+  v->stor_end = v->end = tmp + n;
+
+  return 0;
+}
+
+int igraph_vector_ptr_append    (igraph_vector_ptr_t *to, 
+				 const igraph_vector_ptr_t *from) {
+  long int origsize=igraph_vector_ptr_size(to);
+  long int othersize=igraph_vector_ptr_size(from);
+  long int i;
+  
+  IGRAPH_CHECK(igraph_vector_ptr_resize(to, origsize+othersize));
+  for (i=0; i<othersize; i++, origsize++) {
+    to->stor_begin[origsize]=from->stor_begin[i];
+  }
+
+  return 0;
+}
+
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_set_item_destructor
+ * \brief Sets the item destructor for this pointer vector.
+ *
+ * The item destructor is a function which will be called on every non-null
+ * pointer stored in this vector when \ref igraph_vector_ptr_destroy(),
+ * igraph_vector_ptr_destroy_all() or \ref igraph_vector_ptr_free_all()
+ * is called.
+ *
+ * \return The old item destructor.
+ *
+ * Time complexity: O(1).
+ */
+igraph_finally_func_t* igraph_vector_ptr_set_item_destructor(
+        igraph_vector_ptr_t *v, igraph_finally_func_t *func) {
+  igraph_finally_func_t* result = v->item_destructor;
+
+  v->item_destructor = func;
+
+  return result;
+}
+
+/**
+ * \ingroup vectorptr
+ * \function igraph_vector_ptr_get_item_destructor
+ * \brief Gets the current item destructor for this pointer vector.
+ *
+ * The item destructor is a function which will be called on every non-null
+ * pointer stored in this vector when \ref igraph_vector_ptr_destroy(),
+ * igraph_vector_ptr_destroy_all() or \ref igraph_vector_ptr_free_all()
+ * is called.
+ *
+ * \return The current item destructor.
+ *
+ * Time complexity: O(1).
+ */
+igraph_finally_func_t* igraph_vector_ptr_get_item_destructor(const igraph_vector_ptr_t *v) {
+  assert(v != 0);
+  return v->item_destructor;
+}
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..150e98f
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,67 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2008-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_version.h"
+
+#include <stdio.h>
+
+static const char *igraph_version_string=IGRAPH_VERSION;
+
+/** 
+ * \function igraph_version
+ * Return the version of the igraph C library
+ * 
+ * \param version_string Pointer to a string pointer. If not null, it
+ *    is set to the igraph version string, e.g. "0.6" or "0.5.3". This
+ *    string should not be modified or deallocated.
+ * \param major If not a null pointer, then it is set to the major
+ *    igraph version. E.g. for version "0.5.3" this is 0.
+ * \param minor If not a null pointer, then it is set to the minor 
+ *    igraph version. E.g. for version "0.5.3" this is 5.
+ * \param subminor If not a null pointer, then it is set to the
+ *    subminor igraph version. E.g. for version "0.5.3" this is 3.
+ * \return Error code.
+ * 
+ * Time complexity: O(1).
+ * 
+ * \example examples/simple/igraph_version.c
+ */
+
+int igraph_version(const char **version_string,
+		   int *major,
+		   int *minor,
+		   int *subminor) {
+  int i1, i2, i3;
+  int *p1= major ? major : &i1, 
+    *p2= minor ? minor : &i2,
+    *p3= subminor ? subminor : &i3;
+
+  if (version_string) { 
+    *version_string = igraph_version_string;
+  }
+  
+  *p1 = *p2 = *p3 = 0;
+  sscanf(IGRAPH_VERSION, "%i.%i.%i", p1, p2, p3);
+  
+  return 0;
+}
diff --git a/src/visitors.c b/src/visitors.c
new file mode 100644
index 0000000..4fb061f
--- /dev/null
+++ b/src/visitors.c
@@ -0,0 +1,533 @@
+/* -*- mode: C -*-  */
+/* 
+   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
+   (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_visitor.h"
+#include "igraph_memory.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_dqueue.h"
+#include "igraph_stack.h"
+#include "config.h"
+
+/**
+ * \function igraph_bfs
+ * Breadth-first search
+ * 
+ * A simple breadth-first search, with a lot of different results and
+ * the possibility to call a callback whenever a vertex is visited.
+ * It is allowed to supply null pointers as the output arguments the
+ * user is not interested in, in this case they will be ignored.
+ * 
+ * </para><para>
+ * If not all vertices can be reached from the supplied root vertex,
+ * then additional root vertices will be used, in the order of their
+ * vertex ids.
+ * \param graph The input graph.
+ * \param root The id of the root vertex. It is ignored if the \c
+ *        roots argument is not a null pointer.
+ * \param roots Pointer to an initialized vector, or a null
+ *        pointer. If not a null pointer, then it is a vector
+ *        containing root vertices to start the BFS from. The vertices
+ *        are considered in the order they appear. If a root vertex
+ *        was already found while searching from another one, then no
+ *        search is conducted from it.
+ * \param mode For directed graphs, it defines which edges to follow.
+ *        \c IGRAPH_OUT means following the direction of the edges,
+ *        \c IGRAPH_IN means the opposite, and 
+ *        \c IGRAPH_ALL ignores the direction of the edges.
+ *        This parameter is ignored for undirected graphs. 
+ * \param unreachable Logical scalar, whether the search should visit
+ *        the vertices that are unreachable from the given root
+ *        node(s). If true, then additional searches are performed
+ *        until all vertices are visited.
+ * \param restricted If not a null pointer, then it must be a pointer 
+ *        to a vector containing vertex ids. The BFS is carried out
+ *        only on these vertices.
+ * \param order If not null pointer, then the vertex ids of the graph are
+ *        stored here, in the same order as they were visited.
+ * \param rank If not a null pointer, then the rank of each vertex is
+ *        stored here.
+ * \param father If not a null pointer, then the id of the father of
+ *        each vertex is stored here.
+ * \param pred If not a null pointer, then the id of vertex that was
+ *        visited before the current one is stored here. If there is
+ *        no such vertex (the current vertex is the root of a search
+ *        tree), then -1 is stored.
+ * \param succ If not a null pointer, then the id of the vertex that
+ *        was visited after the current one is stored here. If there
+ *        is no such vertex (the current one is the last in a search
+ *        tree), then -1 is stored.
+ * \param dist If not a null pointer, then the distance from the root of
+ *        the current search tree is stored here.
+ * \param callback If not null, then it should be a pointer to a
+ *        function of type \ref igraph_bfshandler_t. This function
+ *        will be called, whenever a new vertex is visited.
+ * \param extra Extra argument to pass to the callback function.
+ * \return Error code.
+ *
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ * 
+ * \example examples/simple/igraph_bfs.c
+ * \example examples/simple/igraph_bfs2.c
+ */
+
+int igraph_bfs(const igraph_t *graph, 
+	       igraph_integer_t root, const igraph_vector_t *roots,
+	       igraph_neimode_t mode, igraph_bool_t unreachable,
+	       const igraph_vector_t *restricted,
+	       igraph_vector_t *order, igraph_vector_t *rank,
+	       igraph_vector_t *father,
+	       igraph_vector_t *pred, igraph_vector_t *succ,
+	       igraph_vector_t *dist, igraph_bfshandler_t *callback,
+	       void *extra) {
+  
+  igraph_dqueue_t Q;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int actroot=0;
+  igraph_vector_char_t added;
+
+  igraph_lazy_adjlist_t adjlist;
+  
+  long int act_rank=0;
+  long int pred_vec=-1;
+  
+  long int rootpos=0;
+  long int noroots= roots ? igraph_vector_size(roots) : 1;
+
+  if (!roots && (root < 0 || root >= no_of_nodes)) {
+    IGRAPH_ERROR("Invalid root vertex in BFS", IGRAPH_EINVAL);
+  }
+  
+  if (roots) {
+    igraph_real_t min, max;
+    igraph_vector_minmax(roots, &min, &max);
+    if (min < 0 || max >= no_of_nodes) {
+      IGRAPH_ERROR("Invalid root vertex in BFS", IGRAPH_EINVAL);
+    }
+  }
+
+  if (restricted) {
+    igraph_real_t min, max;
+    igraph_vector_minmax(restricted, &min, &max);
+    if (min < 0 || max >= no_of_nodes) {
+      IGRAPH_ERROR("Invalid vertex id in restricted set", IGRAPH_EINVAL);
+    }
+  }
+
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+  
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+
+  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
+  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
+
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, /*simplify=*/ 0));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+
+  /* Mark the vertices that are not in the restricted set, as already
+     found. Special care must be taken for vertices that are not in
+     the restricted set, but are to be used as 'root' vertices. */
+  if (restricted) {
+    long int i, n=igraph_vector_size(restricted);
+    igraph_vector_char_fill(&added, 1);
+    for (i=0; i<n; i++) {
+      long int v=(long int) VECTOR(*restricted)[i];
+      VECTOR(added)[v]=0;
+    }
+  }
+
+  /* Resize result vectors, and fill them with IGRAPH_NAN */
+
+# define VINIT(v) if (v) {                      \
+  igraph_vector_resize((v), no_of_nodes);	\
+  igraph_vector_fill((v), IGRAPH_NAN); }
+
+  VINIT(order);
+  VINIT(rank);
+  VINIT(father);
+  VINIT(pred);
+  VINIT(succ);
+  VINIT(dist);
+# undef VINIT
+
+  while (1) { 
+
+    /* Get the next root vertex, if any */
+
+    if (roots && rootpos < noroots) {
+      /* We are still going through the 'roots' vector */
+      actroot=(long int) VECTOR(*roots)[rootpos++];
+    } else if (!roots && rootpos==0) {
+      /* We have a single root vertex given, and start now */
+      actroot=root;
+      rootpos++;
+    } else if (rootpos==noroots && unreachable) {
+      /* We finished the given root(s), but other vertices are also
+	 tried as root */
+      actroot=0;
+      rootpos++;
+    } else if (unreachable && actroot+1 < no_of_nodes) {
+      /* We are already doing the other vertices, take the next one */
+      actroot++;
+    } else {
+      /* No more root nodes to do */
+      break;
+    }
+
+    /* OK, we have a new root, start BFS */
+    if (VECTOR(added)[actroot]) { continue; }
+    IGRAPH_CHECK(igraph_dqueue_push(&Q, actroot));
+    IGRAPH_CHECK(igraph_dqueue_push(&Q, 0));
+    VECTOR(added)[actroot] = 1;
+    if (father) { VECTOR(*father)[actroot] = -1; }
+      
+    pred_vec=-1;
+
+    while (!igraph_dqueue_empty(&Q)) {
+      long int actvect=(long int) igraph_dqueue_pop(&Q);
+      long int actdist=(long int) igraph_dqueue_pop(&Q);
+      long int succ_vec;
+      igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, 
+						    (igraph_integer_t) actvect);
+      long int i, n=igraph_vector_size(neis);    
+      
+      if (pred) { VECTOR(*pred)[actvect] = pred_vec; }
+      if (rank) { VECTOR(*rank) [actvect] = act_rank; }
+      if (order) { VECTOR(*order)[act_rank++] = actvect; }
+      if (dist) { VECTOR(*dist)[actvect] = actdist; }      
+      
+      for (i=0; i<n; i++) {
+	long int nei=(long int) VECTOR(*neis)[i];
+	if (! VECTOR(added)[nei]) {
+	  VECTOR(added)[nei] = 1;
+	  IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));
+	  IGRAPH_CHECK(igraph_dqueue_push(&Q, actdist+1));
+	  if (father) { VECTOR(*father)[nei] = actvect; }
+	}
+      }
+
+      succ_vec = igraph_dqueue_empty(&Q) ? -1L : 
+	(long int) igraph_dqueue_head(&Q);
+      if (callback) {
+	igraph_bool_t terminate=
+	  callback(graph, (igraph_integer_t) actvect, (igraph_integer_t) 
+		   pred_vec, (igraph_integer_t) succ_vec, 
+		   (igraph_integer_t) act_rank-1, (igraph_integer_t) actdist, 
+		   extra);
+	if (terminate) {
+	  igraph_lazy_adjlist_destroy(&adjlist);
+	  igraph_dqueue_destroy(&Q);
+	  igraph_vector_char_destroy(&added);
+	  IGRAPH_FINALLY_CLEAN(3);
+	  return 0;
+	}
+      }
+
+      if (succ) { VECTOR(*succ)[actvect] = succ_vec; }
+      pred_vec=actvect;
+
+    } /* while Q !empty */
+
+  } /* for actroot < no_of_nodes */
+
+  igraph_lazy_adjlist_destroy(&adjlist);
+  igraph_dqueue_destroy(&Q);
+  igraph_vector_char_destroy(&added);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
+
+/**
+ * \function igraph_i_bfs
+ * \ingroup internal
+ * 
+ * Added in version 0.2.
+ * 
+ * TODO
+ */
+
+int igraph_i_bfs(igraph_t *graph, igraph_integer_t vid, igraph_neimode_t mode,
+		 igraph_vector_t *vids, igraph_vector_t *layers,
+		 igraph_vector_t *parents) {   
+
+  igraph_dqueue_t q;
+  long int vidspos=0;
+  igraph_vector_t neis;
+  long int no_of_nodes=igraph_vcount(graph);
+  long int i;
+  char *added;
+  long int lastlayer=-1;
+  
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+  
+  /* temporary storage */
+  added=igraph_Calloc(no_of_nodes, char);
+  if (added==0) {
+    IGRAPH_ERROR("Cannot calculate BFS", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, added);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
+  IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
+
+  /* results */
+  IGRAPH_CHECK(igraph_vector_resize(vids, no_of_nodes));
+  igraph_vector_clear(layers);
+  IGRAPH_CHECK(igraph_vector_resize(parents, no_of_nodes));
+  
+  /* ok start with vid */
+  IGRAPH_CHECK(igraph_dqueue_push(&q, vid));
+  IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
+  IGRAPH_CHECK(igraph_vector_push_back(layers, vidspos)); 
+  VECTOR(*vids)[vidspos++]=vid; 
+  VECTOR(*parents)[(long int)vid]=vid;
+  added[(long int)vid]=1;
+  
+  while (!igraph_dqueue_empty(&q)) {
+    long int actvect=(long int) igraph_dqueue_pop(&q);
+    long int actdist=(long int) igraph_dqueue_pop(&q);
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actvect, 
+				  mode));
+    for (i=0; i<igraph_vector_size(&neis); i++) {
+      long int neighbor=(long int) VECTOR(neis)[i];
+      if (added[neighbor]==0) {
+	added[neighbor]=1;
+	VECTOR(*parents)[neighbor]=actvect;
+	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
+	IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
+	if (lastlayer != actdist+1) { 
+	  IGRAPH_CHECK(igraph_vector_push_back(layers, vidspos));
+	}
+	VECTOR(*vids)[vidspos++]=neighbor;
+	lastlayer=actdist+1;
+      }
+    } /* for i in neis */
+  } /* while ! dqueue_empty */
+  IGRAPH_CHECK(igraph_vector_push_back(layers, vidspos));
+  
+  igraph_vector_destroy(&neis);
+  igraph_dqueue_destroy(&q);
+  igraph_Free(added);
+  IGRAPH_FINALLY_CLEAN(3);
+		 
+  return 0;
+}
+
+/**
+ * \function igraph_dfs
+ * Depth-first search
+ * 
+ * A simple depth-first search, with
+ * the possibility to call a callback whenever a vertex is discovered
+ * and/or whenever a subtree is finished.
+ * It is allowed to supply null pointers as the output arguments the
+ * user is not interested in, in this case they will be ignored.
+ * 
+ * </para><para>
+ * If not all vertices can be reached from the supplied root vertex,
+ * then additional root vertices will be used, in the order of their
+ * vertex ids.
+ * \param graph The input graph.
+ * \param root The id of the root vertex.
+ * \param mode For directed graphs, it defines which edges to follow.
+ *        \c IGRAPH_OUT means following the direction of the edges,
+ *        \c IGRAPH_IN means the opposite, and 
+ *        \c IGRAPH_ALL ignores the direction of the edges.
+ *        This parameter is ignored for undirected graphs. 
+ * \param unreachable Logical scalar, whether the search should visit
+ *        the vertices that are unreachable from the given root
+ *        node(s). If true, then additional searches are performed
+ *        until all vertices are visited.
+ * \param order If not null pointer, then the vertex ids of the graph are
+ *        stored here, in the same order as they were discovered.
+ * \param order_out If not a null pointer, then the vertex ids of the
+ *        graphs are stored here, in the order of the completion of
+ *        their subtree.
+ * \param father If not a null pointer, then the id of the father of
+ *        each vertex is stored here.
+ * \param dist If not a null pointer, then the distance from the root of
+ *        the current search tree is stored here.
+ * \param in_callback If not null, then it should be a pointer to a
+ *        function of type \ref igraph_dfshandler_t. This function
+ *        will be called, whenever a new vertex is discovered.
+ * \param out_callback If not null, then it should be a pointer to a
+ *        function of type \ref igraph_dfshandler_t. This function
+ *        will be called, whenever the subtree of a vertex is completed.
+ * \param extra Extra argument to pass to the callback function(s).
+ * \return Error code.
+ *
+ * Time complexity: O(|V|+|E|), linear in the number of vertices and
+ * edges.
+ */
+
+int igraph_dfs(const igraph_t *graph, igraph_integer_t root,
+	       igraph_neimode_t mode, igraph_bool_t unreachable, 
+	       igraph_vector_t *order,
+	       igraph_vector_t *order_out, igraph_vector_t *father,
+	       igraph_vector_t *dist, igraph_dfshandler_t *in_callback,
+	       igraph_dfshandler_t *out_callback,
+	       void *extra) {
+  
+  long int no_of_nodes=igraph_vcount(graph);
+  igraph_lazy_adjlist_t adjlist;
+  igraph_stack_t stack;
+  igraph_vector_char_t added;
+  igraph_vector_long_t nptr;
+  long int actroot;
+  long int act_rank=0;
+  long int rank_out=0;
+  long int act_dist=0;
+
+  if (root < 0 || root >= no_of_nodes) { 
+    IGRAPH_ERROR("Invalid root vertex for DFS", IGRAPH_EINVAL);
+  }
+
+  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
+      mode != IGRAPH_ALL) {
+    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
+  }
+  
+  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
+
+  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
+  IGRAPH_CHECK(igraph_stack_init(&stack, 100));
+  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, /*simplify=*/ 0));  
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+  IGRAPH_CHECK(igraph_vector_long_init(&nptr, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &nptr);
+
+# define FREE_ALL() do { 			\
+  igraph_vector_long_destroy(&nptr);            \
+  igraph_lazy_adjlist_destroy(&adjlist);        \
+  igraph_stack_destroy(&stack);                 \
+  igraph_vector_char_destroy(&added);           \
+  IGRAPH_FINALLY_CLEAN(4); } while (0)
+
+  /* Resize result vectors and fill them with IGRAPH_NAN */
+  
+# define VINIT(v) if (v) {                      \
+    igraph_vector_resize(v, no_of_nodes);       \
+    igraph_vector_fill(v, IGRAPH_NAN); }
+  
+  VINIT(order);
+  VINIT(order_out);
+  VINIT(father);
+  VINIT(dist);
+
+# undef VINIT
+
+  IGRAPH_CHECK(igraph_stack_push(&stack, root));
+  VECTOR(added)[(long int)root] = 1;
+  if (father) { VECTOR(*father)[(long int)root] = -1; }
+  if (order) { VECTOR(*order)[act_rank++] = root; }
+  if (dist) { VECTOR(*dist)[(long int)root] = 0; }
+  if (in_callback) {
+    igraph_bool_t terminate=in_callback(graph, root, 0, extra);
+    if (terminate) { FREE_ALL(); return 0; }
+  }
+
+  for (actroot=0; actroot<no_of_nodes; actroot++) {
+
+    /* 'root' first, then all other vertices */
+    if (igraph_stack_empty(&stack)) {
+      if (!unreachable) { break; }
+      if (VECTOR(added)[actroot]) { continue; }
+      IGRAPH_CHECK(igraph_stack_push(&stack, actroot));
+      VECTOR(added)[actroot] = 1;
+      if (father) { VECTOR(*father)[actroot] = -1; }
+      if (order) { VECTOR(*order)[act_rank++] = actroot; }
+      if (dist) { VECTOR(*dist)[actroot] = 0; }
+
+      if (in_callback) {
+	igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) actroot,
+					    0, extra);
+	if (terminate) { FREE_ALL(); return 0; }
+      }
+    }
+    
+    while (!igraph_stack_empty(&stack)) {
+      long int actvect=(long int) igraph_stack_top(&stack);
+      igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, 
+						    (igraph_integer_t) actvect);
+      long int n=igraph_vector_size(neis);
+      long int *ptr=igraph_vector_long_e_ptr(&nptr, actvect);
+
+      /* Search for a neighbor that was not yet visited */
+      igraph_bool_t any=0;
+      long int nei;
+      while (!any && (*ptr) <n) {
+	nei=(long int) VECTOR(*neis)[(*ptr)];
+	any=!VECTOR(added)[nei];
+	(*ptr) ++;
+      }
+      if (any) {
+	/* There is such a neighbor, add it */
+	IGRAPH_CHECK(igraph_stack_push(&stack, nei));
+	VECTOR(added)[nei] = 1;
+	if (father) { VECTOR(*father)[ nei ] = actvect; }
+	if (order) { VECTOR(*order)[act_rank++] = nei; }
+	act_dist++;
+	if (dist) { VECTOR(*dist)[nei] = act_dist; }
+
+	if (in_callback) {
+	  igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) nei,
+					      (igraph_integer_t) act_dist, 
+					      extra);
+	  if (terminate) { FREE_ALL(); return 0; }
+	}
+
+      } else {
+	/* There is no such neighbor, finished with the subtree */
+	igraph_stack_pop(&stack);
+	if (order_out) { VECTOR(*order_out)[rank_out++] = actvect; }
+	act_dist--;
+
+	if (out_callback) {
+	  igraph_bool_t terminate=out_callback(graph, (igraph_integer_t) 
+					       actvect, (igraph_integer_t) 
+					       act_dist, extra);
+	  if (terminate) { FREE_ALL(); return 0; }
+	}
+      }
+    }      
+  }
+
+  FREE_ALL();
+# undef FREE_ALL
+
+  return 0;
+}
diff --git a/src/walktrap.cpp b/src/walktrap.cpp
new file mode 100644
index 0000000..d709cb9
--- /dev/null
+++ b/src/walktrap.cpp
@@ -0,0 +1,173 @@
+/* -*- 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here. The FSF address was
+   fixed by Tamas Nepusz */
+
+// File: walktrap.cpp
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pascal.pons at gmail.com
+// Web page : http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+#include "walktrap_graph.h"
+#include "walktrap_communities.h"
+#include <ctime>
+#include <set>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+#include "igraph_community.h"
+#include "igraph_components.h"
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+
+using namespace std;
+using namespace igraph::walktrap;
+
+/** 
+ * \function igraph_community_walktrap
+ * 
+ * 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
+ * 
+ * </para><para>
+ * Currently the original C++ implementation is used in igraph, 
+ * see http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+ * I'm grateful to Matthieu Latapy and Pascal Pons for providing this 
+ * source code.
+ *
+ * </para><para>
+ * In contrast to the original implementation, isolated vertices are allowed
+ * in the graph and they are assumed to have a single incident loop edge with
+ * weight 1.
+ *
+ * \param graph The input graph, edge directions are ignored.
+ * \param weights Numeric vector giving the weights of the edges. 
+ *     If it is a NULL pointer then all edges will have equal
+ *     weights. The weights are expected to be positive.
+ * \param steps Integer constant, the length of the random walks.
+ * \param merges Pointer to a matrix, the merges performed by the
+ *     algorithm will be stored here (if not NULL). Each merge is a
+ *     row in a two-column matrix and contains the ids of the merged
+ *     clusters. Clusters are numbered from zero and cluster numbers 
+ *     smaller than the number of nodes in the network belong to the
+ *     individual vertices as singleton clusters. In each step a new
+ *     cluster is created from two other clusters and its id will be 
+ *     one larger than the largest cluster id so far. This means that 
+ *     before the first merge we have \c n clusters (the number of
+ *     vertices in the graph) numbered from zero to \c n-1. The first
+ *     merge creates cluster \c n, the second cluster \c n+1, etc.
+ * \param modularity Pointer to a vector. If not NULL then the
+ *     modularity score of the current clustering is stored here after
+ *     each merge operation. 
+ * \param membership Pointer to a vector. If not a NULL pointer, then
+ *     the membership vector corresponding to the maximal modularity
+ *     score is stored here. If it is not a NULL pointer, then neither
+ *     \p modularity nor \p merges may be NULL.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_community_spinglass(), \ref
+ * igraph_community_edge_betweenness(). 
+ * 
+ * Time complexity: O(|E||V|^2) in the worst case, O(|V|^2 log|V|) typically, 
+ * |V| is the number of vertices, |E| is the number of edges.
+ * 
+ * \example examples/simple/walktrap.c
+ */
+
+int igraph_community_walktrap(const igraph_t *graph, 
+			      const igraph_vector_t *weights,
+			      int steps,
+			      igraph_matrix_t *merges,
+			      igraph_vector_t *modularity, 
+			      igraph_vector_t *membership) {
+
+  long int no_of_nodes=(long int)igraph_vcount(graph);
+  int length=steps;
+  long max_memory=-1;
+
+  if (membership && !(modularity && merges)) {
+    IGRAPH_ERROR("Cannot calculate membership without modularity or merges",
+		 IGRAPH_EINVAL);
+  }
+
+  Graph* G = new Graph;
+  if (G->convert_from_igraph(graph, weights))
+      IGRAPH_ERROR("Cannot convert igraph graph into walktrap format", IGRAPH_EINVAL);
+  
+  if (merges) {
+    igraph_integer_t no;
+    IGRAPH_CHECK(igraph_clusters(graph, /*membership=*/ 0, /*csize=*/ 0, 
+				 &no, IGRAPH_WEAK));
+    IGRAPH_CHECK(igraph_matrix_resize(merges, no_of_nodes-no, 2));
+  }
+  if (modularity) {
+    IGRAPH_CHECK(igraph_vector_resize(modularity, no_of_nodes));
+	igraph_vector_null(modularity);
+  }
+  Communities C(G, length, max_memory, merges, modularity);
+  
+  while (!C.H->is_empty()) {
+    IGRAPH_ALLOW_INTERRUPTION();
+    C.merge_nearest_communities();
+  }
+  
+  delete G;
+
+  if (membership) {
+    long int m=igraph_vector_which_max(modularity);
+    IGRAPH_CHECK(igraph_community_to_membership(merges, no_of_nodes, 
+						/*steps=*/ m,
+						membership, 
+						/*csize=*/ 0));
+  }
+  
+  return 0;
+}
diff --git a/src/walktrap_communities.cpp b/src/walktrap_communities.cpp
new file mode 100644
index 0000000..1221e2d
--- /dev/null
+++ b/src/walktrap_communities.cpp
@@ -0,0 +1,843 @@
+/* -*- 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here. The FSF address was
+   fixed by Tamas Nepusz */
+
+// File: communities.cpp
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pascal.pons at gmail.com
+// Web page : http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+#include "walktrap_communities.h"
+#include <cstdlib>
+#include <iostream>
+#include <cmath>
+#include <algorithm>
+
+#include "config.h"
+
+namespace igraph {
+
+namespace walktrap {
+
+IGRAPH_THREAD_LOCAL int Probabilities::length = 0;
+IGRAPH_THREAD_LOCAL Communities* Probabilities::C = 0;
+IGRAPH_THREAD_LOCAL float* Probabilities::tmp_vector1 = 0;
+IGRAPH_THREAD_LOCAL float* Probabilities::tmp_vector2 = 0;
+IGRAPH_THREAD_LOCAL int* Probabilities::id = 0;
+IGRAPH_THREAD_LOCAL int* Probabilities::vertices1 = 0;
+IGRAPH_THREAD_LOCAL int* Probabilities::vertices2 = 0;
+IGRAPH_THREAD_LOCAL int Probabilities::current_id = 0;
+
+
+Neighbor::Neighbor() {
+  next_community1 = 0;
+  previous_community1 = 0;
+  next_community2 = 0;	     
+  previous_community2 = 0;
+  heap_index = -1;
+}
+
+Probabilities::~Probabilities() {
+  C->memory_used -= memory();
+  if(P) delete[] P;
+  if(vertices) delete[] vertices;
+}
+
+Probabilities::Probabilities(int community) {
+  Graph* G = C->G;
+  int nb_vertices1 = 0;
+  int nb_vertices2 = 0;
+
+  float initial_proba = 1./float(C->communities[community].size);
+  int last =  C->members[C->communities[community].last_member];  
+  for(int m = C->communities[community].first_member; m != last; m = C->members[m]) {
+    tmp_vector1[m] = initial_proba;
+    vertices1[nb_vertices1++] = m;
+  }
+  
+  for(int t = 0; t < length; t++) {
+    current_id++;    
+    if(nb_vertices1 > (G->nb_vertices/2)) {
+      nb_vertices2 = G->nb_vertices;
+      for(int i = 0; i < G->nb_vertices; i++)
+	tmp_vector2[i] = 0.;
+      if(nb_vertices1 == G->nb_vertices) {
+	for(int i = 0; i < G->nb_vertices; i++) {
+	  float proba = tmp_vector1[i]/G->vertices[i].total_weight;
+  	  for(int j = 0; j < G->vertices[i].degree; j++)
+	    tmp_vector2[G->vertices[i].edges[j].neighbor] += proba*G->vertices[i].edges[j].weight;
+	}
+      }
+      else {
+	for(int i = 0; i < nb_vertices1; i++) {
+	  int v1 = vertices1[i];
+	  float proba = tmp_vector1[v1]/G->vertices[v1].total_weight;
+  	  for(int j = 0; j < G->vertices[v1].degree; j++)
+	    tmp_vector2[G->vertices[v1].edges[j].neighbor] += proba*G->vertices[v1].edges[j].weight;
+	}
+      }
+    }
+    else {
+      nb_vertices2 = 0;
+      for(int i = 0; i < nb_vertices1; i++) {
+	int v1 = vertices1[i];
+        float proba = tmp_vector1[v1]/G->vertices[v1].total_weight;
+        for(int j = 0; j < G->vertices[v1].degree; j++) {
+	  int v2 = G->vertices[v1].edges[j].neighbor;
+	  if(id[v2] == current_id)
+  	    tmp_vector2[v2] += proba*G->vertices[v1].edges[j].weight;
+  	  else {
+	    tmp_vector2[v2] = proba*G->vertices[v1].edges[j].weight;
+	    id[v2] = current_id;
+	    vertices2[nb_vertices2++] = v2;
+	  }
+        }
+      }
+    }
+    float* tmp = tmp_vector2;
+    tmp_vector2 = tmp_vector1;
+    tmp_vector1 = tmp;
+
+    int* tmp2 = vertices2;
+    vertices2 = vertices1;
+    vertices1 = tmp2;
+
+    nb_vertices1 = nb_vertices2;
+  }
+
+  if(nb_vertices1 > (G->nb_vertices/2)) {
+    P = new float[G->nb_vertices];
+    size = G->nb_vertices;
+    vertices = 0;
+    if(nb_vertices1 == G->nb_vertices) {
+      for(int i = 0; i < G->nb_vertices; i++)
+	P[i] = tmp_vector1[i]/sqrt(G->vertices[i].total_weight);
+    }
+    else {
+      for(int i = 0; i < G->nb_vertices; i++)
+	P[i] = 0.;
+      for(int i = 0; i < nb_vertices1; i++)
+	P[vertices1[i]] = tmp_vector1[vertices1[i]]/sqrt(G->vertices[vertices1[i]].total_weight);
+    }
+  }
+  else {
+    P = new float[nb_vertices1];
+    size = nb_vertices1;
+    vertices = new int[nb_vertices1];
+    int j = 0;
+    for(int i = 0; i < G->nb_vertices; i++) {
+      if(id[i] == current_id) {
+	P[j] = tmp_vector1[i]/sqrt(G->vertices[i].total_weight);
+	vertices[j] = i;
+	j++;
+      }
+    }
+  }
+  C->memory_used += memory();
+}
+
+Probabilities::Probabilities(int community1, int community2) {
+  // The two following probability vectors must exist.
+  // Do not call this function if it is not the case.
+  Probabilities* P1 = C->communities[community1].P;
+  Probabilities* P2 = C->communities[community2].P;
+  
+  float w1 = float(C->communities[community1].size)/float(C->communities[community1].size + C->communities[community2].size);
+  float w2 = float(C->communities[community2].size)/float(C->communities[community1].size + C->communities[community2].size);
+
+
+  if(P1->size == C->G->nb_vertices) {
+    P = new float[C->G->nb_vertices];
+    size = C->G->nb_vertices;
+    vertices = 0;
+    
+    if(P2->size == C->G->nb_vertices) {	// two full vectors
+      for(int i = 0; i < C->G->nb_vertices; i++)
+	P[i] = P1->P[i]*w1 + P2->P[i]*w2;
+    }
+    else {  // P1 full vector, P2 partial vector
+      int j = 0;
+      for(int i = 0; i < P2->size; i++) {
+	for(; j < P2->vertices[i]; j++)
+	  P[j] = P1->P[j]*w1;
+	P[j] = P1->P[j]*w1 + P2->P[i]*w2;
+	j++;
+      }
+      for(; j < C->G->nb_vertices; j++)
+	P[j] = P1->P[j]*w1;
+    }
+  }
+  else {
+    if(P2->size == C->G->nb_vertices) { // P1 partial vector, P2 full vector
+      P = new float[C->G->nb_vertices];
+      size = C->G->nb_vertices;
+      vertices = 0;
+
+      int j = 0;
+      for(int i = 0; i < P1->size; i++) {
+	for(; j < P1->vertices[i]; j++)
+	  P[j] = P2->P[j]*w2;
+	P[j] = P1->P[i]*w1 + P2->P[j]*w2;
+	j++;
+      }
+      for(; j < C->G->nb_vertices; j++)
+	P[j] = P2->P[j]*w2;
+    }
+    else {  // two partial vectors
+      int i = 0;
+      int j = 0;
+      int nb_vertices1 = 0;
+      while((i < P1->size) && (j < P2->size)) {
+	if(P1->vertices[i] < P2->vertices[j]) {
+	  tmp_vector1[P1->vertices[i]] = P1->P[i]*w1;
+	  vertices1[nb_vertices1++] = P1->vertices[i];
+	  i++;
+	  continue;
+	}
+	if(P1->vertices[i] > P2->vertices[j]) {
+	  tmp_vector1[P2->vertices[j]] = P2->P[j]*w2;
+	  vertices1[nb_vertices1++] = P2->vertices[j];
+	  j++;
+	  continue;
+	}
+	tmp_vector1[P1->vertices[i]] = P1->P[i]*w1 + P2->P[j]*w2;
+	vertices1[nb_vertices1++] = P1->vertices[i];
+	i++;
+	j++;
+      }
+      if(i == P1->size) {
+	for(; j < P2->size; j++) {
+	  tmp_vector1[P2->vertices[j]] = P2->P[j]*w2;
+	  vertices1[nb_vertices1++] = P2->vertices[j];
+	}
+      }
+      else {
+	for(; i < P1->size; i++) {
+	  tmp_vector1[P1->vertices[i]] = P1->P[i]*w1;
+	  vertices1[nb_vertices1++] = P1->vertices[i];
+	}
+      }
+
+      if(nb_vertices1 > (C->G->nb_vertices/2)) {
+	P = new float[C->G->nb_vertices];
+	size = C->G->nb_vertices;
+	vertices = 0;
+	for(int i = 0; i < C->G->nb_vertices; i++)
+	  P[i] = 0.;
+	for(int i = 0; i < nb_vertices1; i++)
+	  P[vertices1[i]] = tmp_vector1[vertices1[i]];
+      }
+      else {
+	P = new float[nb_vertices1];
+	size = nb_vertices1;
+	vertices = new int[nb_vertices1];
+	for(int i = 0; i < nb_vertices1; i++) {
+	  vertices[i] = vertices1[i];
+	  P[i] = tmp_vector1[vertices1[i]];
+	}
+      }
+    }
+  }
+
+  C->memory_used += memory();
+}
+
+double Probabilities::compute_distance(const Probabilities* P2) const {
+  double r = 0.;
+  if(vertices) {
+    if(P2->vertices) {  // two partial vectors
+      int i = 0;
+      int j = 0;
+      while((i < size) && (j < P2->size)) {
+	if(vertices[i] < P2->vertices[j]) {
+	  r += P[i]*P[i];
+	  i++;
+	  continue;
+	}
+	if(vertices[i] > P2->vertices[j]) {
+	  r += P2->P[j]*P2->P[j];
+	  j++;
+	  continue;
+	}
+	r += (P[i] - P2->P[j])*(P[i] - P2->P[j]);
+	i++;
+	j++;
+      }
+      if(i == size) {
+	for(; j < P2->size; j++)
+	  r += P2->P[j]*P2->P[j];
+      }
+      else {
+	for(; i < size; i++)
+	  r += P[i]*P[i];
+      }
+    }
+    else {  // P1 partial vector, P2 full vector 
+
+      int i = 0;
+      for(int j = 0; j < size; j++) {
+	for(; i < vertices[j]; i++)
+	  r += P2->P[i]*P2->P[i];
+	r += (P[j] - P2->P[i])*(P[j] - P2->P[i]);
+	i++;
+      }
+      for(; i < P2->size; i++)
+	r += P2->P[i]*P2->P[i];      
+    }
+  }
+  else {
+    if(P2->vertices) {  // P1 full vector, P2 partial vector
+      int i = 0;
+      for(int j = 0; j < P2->size; j++) {
+	for(; i < P2->vertices[j]; i++)
+	  r += P[i]*P[i];
+	r += (P[i] - P2->P[j])*(P[i] - P2->P[j]);
+	i++;
+      }
+      for(; i < size; i++)
+	r += P[i]*P[i];
+    }
+    else {  // two full vectors
+      for(int i = 0; i < size; i++)
+	r += (P[i] - P2->P[i])*(P[i] - P2->P[i]);
+    }
+  }
+  return r;
+}
+
+long Probabilities::memory() {
+  if(vertices)
+    return (sizeof(Probabilities) + long(size)*(sizeof(float) + sizeof(int)));
+  else
+    return (sizeof(Probabilities) + long(size)*sizeof(float));
+}
+
+Community::Community() {
+  P = 0;
+  first_neighbor = 0;
+  last_neighbor = 0;
+  sub_community_of = -1;
+  sub_communities[0] = -1;
+  sub_communities[1] = -1;
+  sigma = 0.;
+  internal_weight = 0.;
+  total_weight = 0.;
+}
+
+Community::~Community() {
+  if(P) delete P;
+}
+
+
+Communities::Communities(Graph* graph, int random_walks_length, 
+			 long m, igraph_matrix_t *pmerges,
+			 igraph_vector_t *pmodularity) {
+  max_memory = m;
+  memory_used = 0;
+  G = graph;
+  merges=pmerges;
+  mergeidx=0;
+  modularity=pmodularity;
+  
+  Probabilities::C = this;
+  Probabilities::length = random_walks_length;
+  Probabilities::tmp_vector1 = new float[G->nb_vertices];
+  Probabilities::tmp_vector2 = new float[G->nb_vertices];
+  Probabilities::id = new int[G->nb_vertices];
+  for(int i = 0; i < G->nb_vertices; i++) Probabilities::id[i] = 0;
+  Probabilities::vertices1 = new int[G->nb_vertices];
+  Probabilities::vertices2 = new int[G->nb_vertices];
+  Probabilities::current_id = 0;
+
+  
+  members = new int[G->nb_vertices];  
+  for(int i = 0; i < G->nb_vertices; i++)
+    members[i] = -1;
+
+  H = new Neighbor_heap(G->nb_edges);
+  communities = new Community[2*G->nb_vertices];
+
+// init the n single vertex communities
+
+  if(max_memory != -1)
+    min_delta_sigma = new Min_delta_sigma_heap(G->nb_vertices*2);
+  else min_delta_sigma = 0;
+  
+  for(int i = 0; i < G->nb_vertices; i++) {
+    communities[i].this_community = i;
+    communities[i].first_member = i;
+    communities[i].last_member = i;
+    communities[i].size = 1;
+    communities[i].sub_community_of = 0;
+  }
+
+  nb_communities = G->nb_vertices;
+  nb_active_communities = G->nb_vertices;
+
+  for(int i = 0; i < G->nb_vertices; i++)
+    for(int j = 0; j < G->vertices[i].degree; j++)
+      if (i < G->vertices[i].edges[j].neighbor) {
+	communities[i].total_weight += G->vertices[i].edges[j].weight/2.;
+	communities[G->vertices[i].edges[j].neighbor].total_weight += G->vertices[i].edges[j].weight/2.;
+	Neighbor* N = new Neighbor;
+	N->community1 = i;
+	N->community2 = G->vertices[i].edges[j].neighbor;
+	N->delta_sigma = -1./double(min(G->vertices[i].degree,  G->vertices[G->vertices[i].edges[j].neighbor].degree));
+	N->weight = G->vertices[i].edges[j].weight;
+	N->exact = false;
+	add_neighbor(N);
+      }
+
+  if(max_memory != -1) {
+    memory_used += min_delta_sigma->memory();
+    memory_used += 2*long(G->nb_vertices)*sizeof(Community);
+    memory_used += long(G->nb_vertices)*(2*sizeof(float) + 3*sizeof(int)); // the static data of Probabilities class
+    memory_used += H->memory() + long(G->nb_edges)*sizeof(Neighbor);
+    memory_used += G->memory();    
+  }
+
+/*   int c = 0; */
+  Neighbor* N = H->get_first();  
+  if (N == 0)
+    return;   /* this can happen if there are no edges */
+  while(!N->exact) {
+    update_neighbor(N, compute_delta_sigma(N->community1, N->community2));
+    N->exact = true;
+    N = H->get_first();
+    if(max_memory != -1) manage_memory();
+    /* TODO: this could use igraph_progress */
+/*     if(!silent) { */
+/*       c++; */
+/*       for(int k = (500*(c-1))/G->nb_edges + 1; k <= (500*c)/G->nb_edges; k++) { */
+/* 	if(k % 50 == 1) {cerr.width(2); cerr << endl << k/ 5 << "% ";} */
+/* 	cerr << "."; */
+/*       } */
+/*     } */
+  }
+  
+}
+
+Communities::~Communities() {
+  delete[] members;
+  delete[] communities;
+  delete H;
+  if(min_delta_sigma) delete min_delta_sigma;
+  
+  delete[] Probabilities::tmp_vector1;
+  delete[] Probabilities::tmp_vector2;
+  delete[] Probabilities::id;
+  delete[] Probabilities::vertices1;
+  delete[] Probabilities::vertices2;
+}
+
+float Community::min_delta_sigma() {
+  float r = 1.;
+  for(Neighbor* N = first_neighbor; N != 0;) {
+    if(N->delta_sigma < r) r = N->delta_sigma;
+    if(N->community1 == this_community)
+      N = N->next_community1;
+    else
+      N = N->next_community2;
+  }
+  return r;
+}
+
+
+void Community::add_neighbor(Neighbor* N) { // add a new neighbor at the end of the list
+  if (last_neighbor) {
+    if(last_neighbor->community1 == this_community)
+      last_neighbor->next_community1 = N;
+    else
+      last_neighbor->next_community2 = N;
+    
+    if(N->community1 == this_community)
+      N->previous_community1 = last_neighbor;
+    else
+      N->previous_community2 = last_neighbor;
+  }
+  else {
+    first_neighbor = N;
+    if(N->community1 == this_community)
+      N->previous_community1 = 0;
+    else
+      N->previous_community2 = 0;
+  }
+  last_neighbor = N;
+}
+
+void Community::remove_neighbor(Neighbor* N) {	// remove a neighbor from the list
+  if (N->community1 == this_community) {
+    if(N->next_community1) {
+//      if (N->next_community1->community1 == this_community)
+	N->next_community1->previous_community1 = N->previous_community1;
+//      else 
+//	N->next_community1->previous_community2 = N->previous_community1;
+    }
+    else last_neighbor = N->previous_community1;
+    if(N->previous_community1) {
+      if (N->previous_community1->community1 == this_community)
+	N->previous_community1->next_community1 = N->next_community1;
+      else 
+	N->previous_community1->next_community2 = N->next_community1;
+    }
+    else first_neighbor = N->next_community1;
+  }
+  else {
+    if(N->next_community2) {
+      if (N->next_community2->community1 == this_community)
+	N->next_community2->previous_community1 = N->previous_community2;
+      else 
+	N->next_community2->previous_community2 = N->previous_community2;
+    }
+    else last_neighbor = N->previous_community2;
+    if(N->previous_community2) {
+//      if (N->previous_community2->community1 == this_community)
+//	N->previous_community2->next_community1 = N->next_community2;
+//      else 
+	N->previous_community2->next_community2 = N->next_community2;
+    }
+    else first_neighbor = N->next_community2;
+  }
+}
+
+void Communities::remove_neighbor(Neighbor* N) {
+  communities[N->community1].remove_neighbor(N);
+  communities[N->community2].remove_neighbor(N);
+  H->remove(N);
+
+  if(max_memory !=-1) {
+    if(N->delta_sigma == min_delta_sigma->delta_sigma[N->community1]) {
+      min_delta_sigma->delta_sigma[N->community1] = communities[N->community1].min_delta_sigma();
+      if(communities[N->community1].P) min_delta_sigma->update(N->community1);
+    }
+
+    if(N->delta_sigma == min_delta_sigma->delta_sigma[N->community2]) {
+      min_delta_sigma->delta_sigma[N->community2] = communities[N->community2].min_delta_sigma();
+      if(communities[N->community2].P) min_delta_sigma->update(N->community2);
+    }
+  }
+}
+
+void Communities::add_neighbor(Neighbor* N) {
+  communities[N->community1].add_neighbor(N);
+  communities[N->community2].add_neighbor(N);
+  H->add(N);
+
+  if(max_memory !=-1) {
+    if(N->delta_sigma < min_delta_sigma->delta_sigma[N->community1]) {
+      min_delta_sigma->delta_sigma[N->community1] = N->delta_sigma;
+      if(communities[N->community1].P) min_delta_sigma->update(N->community1);
+    }
+
+    if(N->delta_sigma < min_delta_sigma->delta_sigma[N->community2]) {
+      min_delta_sigma->delta_sigma[N->community2] = N->delta_sigma;
+      if(communities[N->community2].P) min_delta_sigma->update(N->community2);
+    }
+  }
+}
+
+void Communities::update_neighbor(Neighbor* N, float new_delta_sigma) {
+  if(max_memory !=-1) {
+    if(new_delta_sigma < min_delta_sigma->delta_sigma[N->community1]) {
+      min_delta_sigma->delta_sigma[N->community1] = new_delta_sigma;
+      if(communities[N->community1].P) min_delta_sigma->update(N->community1);
+    }
+   
+    if(new_delta_sigma < min_delta_sigma->delta_sigma[N->community2]) {
+      min_delta_sigma->delta_sigma[N->community2] = new_delta_sigma;
+      if(communities[N->community2].P) min_delta_sigma->update(N->community2);
+    }
+
+    float old_delta_sigma = N->delta_sigma;
+    N->delta_sigma = new_delta_sigma;
+    H->update(N);
+
+    if(old_delta_sigma == min_delta_sigma->delta_sigma[N->community1]) {
+      min_delta_sigma->delta_sigma[N->community1] = communities[N->community1].min_delta_sigma();
+      if(communities[N->community1].P) min_delta_sigma->update(N->community1);
+    }
+
+    if(old_delta_sigma == min_delta_sigma->delta_sigma[N->community2]) {
+      min_delta_sigma->delta_sigma[N->community2] = communities[N->community2].min_delta_sigma();
+      if(communities[N->community2].P) min_delta_sigma->update(N->community2);
+    }
+  }
+  else {
+    N->delta_sigma = new_delta_sigma;
+    H->update(N);
+  }
+}
+
+void Communities::manage_memory() {
+  while((memory_used > max_memory) && !min_delta_sigma->is_empty()) {
+    int c = min_delta_sigma->get_max_community();
+    delete communities[c].P;
+    communities[c].P = 0;
+    min_delta_sigma->remove_community(c);
+  }  
+}
+
+
+
+void Communities::merge_communities(Neighbor* merge_N) {
+  int c1 = merge_N->community1;
+  int c2 = merge_N->community2;
+  
+  communities[nb_communities].first_member = communities[c1].first_member;	// merge the 
+  communities[nb_communities].last_member = communities[c2].last_member;	// two lists   
+  members[communities[c1].last_member] = communities[c2].first_member;		// of members
+
+  communities[nb_communities].size = communities[c1].size + communities[c2].size;
+  communities[nb_communities].this_community = nb_communities;
+  communities[nb_communities].sub_community_of = 0;
+  communities[nb_communities].sub_communities[0] = c1;
+  communities[nb_communities].sub_communities[1] = c2;
+  communities[nb_communities].total_weight = communities[c1].total_weight + communities[c2].total_weight;
+  communities[nb_communities].internal_weight = communities[c1].internal_weight + communities[c2].internal_weight + merge_N->weight;
+  communities[nb_communities].sigma = communities[c1].sigma + communities[c2].sigma + merge_N->delta_sigma;
+  
+  communities[c1].sub_community_of = nb_communities;
+  communities[c2].sub_community_of = nb_communities;
+
+// update the new probability vector...
+  
+  if(communities[c1].P && communities[c2].P) communities[nb_communities].P = new Probabilities(c1, c2);
+
+  if(communities[c1].P) {
+    delete communities[c1].P; 
+    communities[c1].P = 0;
+    if(max_memory != -1) min_delta_sigma->remove_community(c1);
+  }
+  if(communities[c2].P) {
+    delete communities[c2].P;
+    communities[c2].P = 0;
+    if(max_memory != -1) min_delta_sigma->remove_community(c2);
+  }
+
+  if(max_memory != -1) {
+    min_delta_sigma->delta_sigma[c1] = -1.;		    // to avoid to update the min_delta_sigma for these communities
+    min_delta_sigma->delta_sigma[c2] = -1.;		    // 
+    min_delta_sigma->delta_sigma[nb_communities] = -1.;
+  }
+  
+// update the new neighbors
+// by enumerating all the neighbors of c1 and c2
+
+  Neighbor* N1 = communities[c1].first_neighbor;
+  Neighbor* N2 = communities[c2].first_neighbor;
+
+  while(N1 && N2) { 
+    int neighbor_community1;
+    int neighbor_community2;
+    
+    if (N1->community1 == c1) neighbor_community1 = N1->community2;
+    else neighbor_community1 = N1->community1;
+    if (N2->community1 == c2) neighbor_community2 = N2->community2;
+    else neighbor_community2 = N2->community1;
+
+    if (neighbor_community1 < neighbor_community2) {
+      Neighbor* tmp = N1;
+      if (N1->community1 == c1) N1 = N1->next_community1;
+      else N1 = N1->next_community2;
+      remove_neighbor(tmp);
+      Neighbor* N = new Neighbor;
+      N->weight = tmp->weight;
+      N->community1 = neighbor_community1;
+      N->community2 = nb_communities;
+      N->delta_sigma = (double(communities[c1].size+communities[neighbor_community1].size)*tmp->delta_sigma + double(communities[c2].size)*merge_N->delta_sigma)/(double(communities[c1].size+communities[c2].size+communities[neighbor_community1].size));//compute_delta_sigma(neighbor_community1, nb_communities);
+      N->exact = false;
+      delete tmp;
+      add_neighbor(N); 
+    }
+    
+    if (neighbor_community2 < neighbor_community1) {
+      Neighbor* tmp = N2;
+      if (N2->community1 == c2) N2 = N2->next_community1;
+      else N2 = N2->next_community2;
+      remove_neighbor(tmp);
+      Neighbor* N = new Neighbor;
+      N->weight = tmp->weight;
+      N->community1 = neighbor_community2;
+      N->community2 = nb_communities;
+      N->delta_sigma = (double(communities[c1].size)*merge_N->delta_sigma + double(communities[c2].size+communities[neighbor_community2].size)*tmp->delta_sigma)/(double(communities[c1].size+communities[c2].size+communities[neighbor_community2].size));//compute_delta_sigma(neighbor_community2, nb_communities);
+      N->exact = false;
+      delete tmp;
+      add_neighbor(N); 
+    }
+    
+    if (neighbor_community1 == neighbor_community2) {
+      Neighbor* tmp1 = N1;
+      Neighbor* tmp2 = N2;
+      bool exact = N1->exact && N2->exact;
+      if (N1->community1 == c1) N1 = N1->next_community1;
+      else N1 = N1->next_community2;
+      if (N2->community1 == c2) N2 = N2->next_community1;
+      else N2 = N2->next_community2;
+      remove_neighbor(tmp1);
+      remove_neighbor(tmp2);
+      Neighbor* N = new Neighbor;
+      N->weight = tmp1->weight + tmp2->weight;
+      N->community1 = neighbor_community1;
+      N->community2 = nb_communities;
+      N->delta_sigma = (double(communities[c1].size+communities[neighbor_community1].size)*tmp1->delta_sigma + double(communities[c2].size+communities[neighbor_community1].size)*tmp2->delta_sigma - double(communities[neighbor_community1].size)*merge_N->delta_sigma)/(double(communities[c1].size+communities[c2].size+communities[neighbor_community1].size));
+      N->exact = exact;
+      delete tmp1;
+      delete tmp2;
+      add_neighbor(N);
+    }
+  }
+
+  
+  if(!N1) {
+    while(N2) {
+//      double delta_sigma2 = N2->delta_sigma;
+      int neighbor_community;
+      if (N2->community1 == c2) neighbor_community = N2->community2;
+      else neighbor_community = N2->community1;
+      Neighbor* tmp = N2;
+      if (N2->community1 == c2) N2 = N2->next_community1;
+      else N2 = N2->next_community2;
+      remove_neighbor(tmp);
+      Neighbor* N = new Neighbor;
+      N->weight = tmp->weight;
+      N->community1 = neighbor_community;
+      N->community2 = nb_communities;
+      N->delta_sigma = (double(communities[c1].size)*merge_N->delta_sigma + double(communities[c2].size+communities[neighbor_community].size)*tmp->delta_sigma)/(double(communities[c1].size+communities[c2].size+communities[neighbor_community].size));//compute_delta_sigma(neighbor_community, nb_communities);
+      N->exact = false;
+      delete tmp;
+      add_neighbor(N);
+    }
+  }
+  if(!N2) {
+    while(N1) {
+//      double delta_sigma1 = N1->delta_sigma;
+      int neighbor_community;
+      if (N1->community1 == c1) neighbor_community = N1->community2;
+      else neighbor_community = N1->community1;
+      Neighbor* tmp = N1;
+      if (N1->community1 == c1) N1 = N1->next_community1;
+      else N1 = N1->next_community2;
+      remove_neighbor(tmp);
+      Neighbor* N = new Neighbor;
+      N->weight = tmp->weight;
+      N->community1 = neighbor_community;
+      N->community2 = nb_communities;
+      N->delta_sigma = (double(communities[c1].size+communities[neighbor_community].size)*tmp->delta_sigma + double(communities[c2].size)*merge_N->delta_sigma)/(double(communities[c1].size+communities[c2].size+communities[neighbor_community].size));//compute_delta_sigma(neighbor_community, nb_communities);
+      N->exact = false;
+      delete tmp;
+      add_neighbor(N);
+    }
+  }
+
+  if(max_memory != -1) {
+    min_delta_sigma->delta_sigma[nb_communities] = communities[nb_communities].min_delta_sigma();
+    min_delta_sigma->update(nb_communities);
+  } 
+
+  nb_communities++;
+  nb_active_communities--;
+}
+
+double Communities::merge_nearest_communities() {
+  Neighbor* N = H->get_first();  
+  while(!N->exact) {
+    update_neighbor(N, compute_delta_sigma(N->community1, N->community2));
+    N->exact = true;
+    N = H->get_first();
+    if(max_memory != -1) manage_memory();
+  }
+
+  double d = N->delta_sigma;
+  remove_neighbor(N);
+
+  merge_communities(N);
+  if(max_memory != -1) manage_memory();
+  
+  if (merges) {
+    MATRIX(*merges, mergeidx, 0)=N->community1;
+    MATRIX(*merges, mergeidx, 1)=N->community2;
+    mergeidx++;
+  }
+
+  if (modularity) {
+    float Q = 0.;
+    for(int i = 0; i < nb_communities; i++) {
+      if(communities[i].sub_community_of == 0) {
+	Q += (communities[i].internal_weight - communities[i].total_weight*communities[i].total_weight/G->total_weight)/G->total_weight;
+      }
+    }
+    VECTOR(*modularity)[mergeidx]=Q;
+  }
+
+  delete N;
+
+  /* This could use igraph_progress */
+/*   if(!silent) { */
+/*     for(int k = (500*(G->nb_vertices - nb_active_communities - 1))/(G->nb_vertices-1) + 1; k <= (500*(G->nb_vertices - nb_active_communities))/(G->nb_vertices-1); k++) { */
+/*       if(k % 50 == 1) {cerr.width(2); cerr << endl << k/ 5 << "% ";} */
+/*       cerr << "."; */
+/*     } */
+/*   } */
+  return d;
+}
+
+double Communities::compute_delta_sigma(int community1, int community2) {
+  if(!communities[community1].P) {
+    communities[community1].P = new Probabilities(community1);
+    if(max_memory != -1) min_delta_sigma->update(community1);
+  }
+  if(!communities[community2].P) {
+    communities[community2].P = new Probabilities(community2);
+    if(max_memory != -1) min_delta_sigma->update(community2);
+  }
+  
+  return communities[community1].P->compute_distance(communities[community2].P)*double(communities[community1].size)*double(communities[community2].size)/double(communities[community1].size + communities[community2].size);
+}
+
+} }    /* end of namespaces */
diff --git a/src/walktrap_communities.h b/src/walktrap_communities.h
new file mode 100644
index 0000000..4196ae3
--- /dev/null
+++ b/src/walktrap_communities.h
@@ -0,0 +1,175 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here. The FSF address was
+   fixed by Tamas Nepusz */
+
+// File: communities.h
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pascal.pons at gmail.com
+// Web page : http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+
+#ifndef COMMUNITIES_H
+#define COMMUNITIES_H
+
+#include "walktrap_graph.h"
+#include "walktrap_heap.h"
+
+#include "igraph_community.h"
+#include "config.h"
+
+namespace igraph {
+
+namespace walktrap {
+
+class Communities;
+class Probabilities {
+public:
+  static IGRAPH_THREAD_LOCAL float* tmp_vector1;	// 
+  static IGRAPH_THREAD_LOCAL float* tmp_vector2;	// 
+  static IGRAPH_THREAD_LOCAL int* id;	    // 
+  static IGRAPH_THREAD_LOCAL int* vertices1;    //
+  static IGRAPH_THREAD_LOCAL int* vertices2;    //  
+  static IGRAPH_THREAD_LOCAL int current_id;    // 
+
+  static IGRAPH_THREAD_LOCAL Communities* C;				    // pointer to all the communities
+  static IGRAPH_THREAD_LOCAL int length;					    // length of the random walks
+
+  
+  int size;						    // number of probabilities stored
+  int* vertices;					    // the vertices corresponding to the stored probabilities, 0 if all the probabilities are stored
+  float* P;						    // the probabilities
+  
+  long memory();					    // the memory (in Bytes) used by the object
+  double compute_distance(const Probabilities* P2) const;   // compute the squared distance r^2 between this probability vector and P2
+  Probabilities(int community);				    // compute the probability vector of a community
+  Probabilities(int community1, int community2);	    // merge the probability vectors of two communities in a new one
+							    // the two communities must have their probability vectors stored
+							    
+  ~Probabilities();					    // destructor
+};
+
+class Community {
+public:
+  
+  Neighbor* first_neighbor;	// first item of the list of adjacent communities
+  Neighbor* last_neighbor;	// last item of the list of adjacent communities
+  
+  int this_community;		// number of this community
+  int first_member;		// number of the first vertex of the community
+  int last_member;		// number of the last vertex of the community
+  int size;			// number of members of the community
+  
+  Probabilities* P;		// the probability vector, 0 if not stored.  
+
+
+  float sigma;			// sigma(C) of the community
+  float internal_weight;	// sum of the weight of the internal edges
+  float total_weight;		// sum of the weight of all the edges of the community (an edge between two communities is a half-edge for each community)
+    
+  int sub_communities[2];	// the two sub sommunities, -1 if no sub communities;
+  int sub_community_of;		// number of the community in which this community has been merged
+				// 0 if the community is active
+				// -1 if the community is not used
+  
+  void merge(Community &C1, Community &C2);	// create a new community by merging C1 an C2
+  void add_neighbor(Neighbor* N);
+  void remove_neighbor(Neighbor* N);
+  float min_delta_sigma();			// compute the minimal delta sigma among all the neighbors of this community
+  
+  Community();			// create an empty community
+  ~Community();			// destructor
+};
+
+class Communities {
+private:
+  long max_memory;	// size in Byte of maximal memory usage, -1 for no limit
+  igraph_matrix_t *merges;
+  long int mergeidx;
+  igraph_vector_t *modularity;
+  
+public:
+  
+  long memory_used;				    // in bytes
+  Min_delta_sigma_heap* min_delta_sigma;    	    // the min delta_sigma of the community with a saved probability vector (for memory management)
+  
+  Graph* G;		    // the graph
+  int* members;		    // the members of each community represented as a chained list.
+			    // a community points to the first_member the array which contains 
+			    // the next member (-1 = end of the community)
+  Neighbor_heap* H;	    // the distances between adjacent communities.
+
+
+  Community* communities;	// array of the communities
+  
+  int nb_communities;		// number of valid communities 
+  int nb_active_communities;	// number of active communities
+  
+  Communities(Graph* G, int random_walks_length = 3,
+	      long max_memory = -1, igraph_matrix_t *merges=0,
+	      igraph_vector_t *modularity=0);    // Constructor
+  ~Communities();					// Destructor
+
+
+  void merge_communities(Neighbor* N);			// create a community by merging two existing communities
+  double merge_nearest_communities();
+
+  
+  double compute_delta_sigma(int c1, int c2);		// compute delta_sigma(c1,c2) 
+
+  void remove_neighbor(Neighbor* N);
+  void add_neighbor(Neighbor* N);
+  void update_neighbor(Neighbor* N, float new_delta_sigma);
+
+  void manage_memory();
+  
+};
+
+} }       /* end of namespaces */
+
+#endif
diff --git a/src/walktrap_graph.cpp b/src/walktrap_graph.cpp
new file mode 100644
index 0000000..98a1a8f
--- /dev/null
+++ b/src/walktrap_graph.cpp
@@ -0,0 +1,240 @@
+/* -*- 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here. The FSF address was
+   fixed by Tamas Nepusz */
+
+// File: graph.cpp
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pascal.pons at gmail.com
+// Web page : http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <algorithm>
+#include <cstring>		// strlen
+#include "walktrap_graph.h"
+
+#include "igraph_interface.h"
+
+using namespace std;
+
+namespace igraph {
+
+namespace walktrap {
+
+bool operator<(const Edge& E1, const Edge& E2) {
+  return(E1.neighbor < E2.neighbor);
+}
+
+
+Vertex::Vertex() {
+  degree = 0;
+  edges = 0;
+  total_weight = 0.;
+}
+
+Vertex::~Vertex() {
+  if(edges) delete[] edges;
+}
+
+Graph::Graph() {
+  nb_vertices = 0;
+  nb_edges = 0;
+  vertices = 0;
+  index = 0;
+  total_weight = 0.;
+}
+
+Graph::~Graph () {
+  if (vertices) delete[] vertices;
+}
+
+class Edge_list {  
+public:
+  int* V1;
+  int* V2;
+  float* W;
+
+  int size;
+  int size_max;
+  
+  void add(int v1, int v2, float w);
+  Edge_list() {
+    size = 0;
+    size_max = 1024;
+    V1 = new int[1024];
+    V2 = new int[1024];
+    W = new float[1024];
+  }
+  ~Edge_list() {
+    if(V1) delete[] V1;
+    if(V2) delete[] V2;
+    if(W) delete[] W;
+  }
+};
+
+void Edge_list::add(int v1, int v2, float w) {
+  if(size == size_max) {
+    int* tmp1 = new int[2*size_max];
+    int* tmp2 = new int[2*size_max];
+    float* tmp3 = new float[2*size_max];
+    for(int i = 0; i < size_max; i++) {
+      tmp1[i] = V1[i];
+      tmp2[i] = V2[i];      
+      tmp3[i] = W[i];
+    }
+    delete[] V1;
+    delete[] V2;
+    delete[] W;
+    V1 = tmp1;
+    V2 = tmp2;
+    W = tmp3;
+    size_max *= 2;
+  }
+  V1[size] = v1;
+  V2[size] = v2;
+  W[size] = w;
+  size++;
+}
+
+int Graph::convert_from_igraph(const igraph_t *graph, 
+				const igraph_vector_t *weights) {
+  Graph &G=*this;  
+  
+  int max_vertex=(int)igraph_vcount(graph)-1;
+  long int no_of_edges=(long int)igraph_ecount(graph); 
+  long int i;
+  long int deg;
+  double w;
+  
+  Edge_list EL;
+  
+  for (i=0; i<no_of_edges; i++) {
+    igraph_integer_t from, to;
+    int v1, v2;
+    w=weights ? VECTOR(*weights)[i] : 1.0;
+    igraph_edge(graph, i, &from, &to);
+    v1=(int)from; v2=(int)to;
+    EL.add(v1, v2, w);
+  }
+    
+  G.nb_vertices=max_vertex+1;
+  G.vertices=new Vertex[G.nb_vertices];
+  G.nb_edges=0;
+  G.total_weight=0.0;
+  
+  for(int i = 0; i < EL.size; i++) {
+      G.vertices[EL.V1[i]].degree++;
+      G.vertices[EL.V2[i]].degree++;
+      G.vertices[EL.V1[i]].total_weight += EL.W[i];
+      G.vertices[EL.V2[i]].total_weight += EL.W[i];
+      G.nb_edges++;
+      G.total_weight += EL.W[i];
+    }
+
+  for(int i = 0; i < G.nb_vertices; i++) {
+    deg = G.vertices[i].degree;
+    w = (deg == 0) ? 1.0 : (G.vertices[i].total_weight / double(deg));
+    G.vertices[i].edges = new Edge[deg + 1];
+    G.vertices[i].edges[0].neighbor = i;
+    G.vertices[i].edges[0].weight = w;
+    G.vertices[i].total_weight += w;
+    G.vertices[i].degree = 1;
+  }
+ 
+  for(int i = 0; i < EL.size; i++) {
+    G.vertices[EL.V1[i]].edges[G.vertices[EL.V1[i]].degree].neighbor = EL.V2[i];
+    G.vertices[EL.V1[i]].edges[G.vertices[EL.V1[i]].degree].weight = EL.W[i];
+    G.vertices[EL.V1[i]].degree++;
+    G.vertices[EL.V2[i]].edges[G.vertices[EL.V2[i]].degree].neighbor = EL.V1[i];
+    G.vertices[EL.V2[i]].edges[G.vertices[EL.V2[i]].degree].weight = EL.W[i];
+    G.vertices[EL.V2[i]].degree++;
+  }  
+  
+  for(int i = 0; i < G.nb_vertices; i++)
+    sort(G.vertices[i].edges, G.vertices[i].edges+G.vertices[i].degree);
+
+  for(int i = 0; i < G.nb_vertices; i++) {  // merge multi edges
+    int a = 0;
+    for(int b = 1; b < G.vertices[i].degree; b++) {
+      if(G.vertices[i].edges[b].neighbor == G.vertices[i].edges[a].neighbor)
+	G.vertices[i].edges[a].weight += G.vertices[i].edges[b].weight;
+      else 
+	G.vertices[i].edges[++a] = G.vertices[i].edges[b];
+    }
+    G.vertices[i].degree = a+1;
+  }
+
+  return 0;
+}
+
+long Graph::memory() {
+  size_t m = 0;
+  m += size_t(nb_vertices)*sizeof(Vertex);
+  m += 2*size_t(nb_edges)*sizeof(Edge);
+  m += sizeof(Graph);
+  if(index != 0) {
+    m += size_t(nb_vertices)*sizeof(char*);
+    for(int i = 0; i < nb_vertices; i++)
+      m += strlen(index[i]) + 1;
+  }
+  return m;
+}
+
+} }
+
+
+
+
+
+
+
+
+
+
diff --git a/src/walktrap_graph.h b/src/walktrap_graph.h
new file mode 100644
index 0000000..c818849
--- /dev/null
+++ b/src/walktrap_graph.h
@@ -0,0 +1,107 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here */
+
+// File: graph.h
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pascal.pons at gmail.com
+// Web page : http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+/* FSF address above was fixed by Tamas Nepusz */
+
+
+#ifndef GRAPH_H
+#define GRAPH_H
+#include <iostream>
+
+#include "igraph_community.h"
+
+namespace igraph {
+
+namespace walktrap {
+
+using namespace std;
+
+class Edge {			// code an edge of a given vertex
+public:
+  int neighbor;			// the number of the neighbor vertex
+  float weight;			// the weight of the edge
+};
+bool operator<(const Edge& E1, const Edge& E2);
+
+
+class Vertex {
+public:
+  Edge* edges;			// the edges of the vertex
+  int degree;			// number of neighbors
+  float total_weight;		// the total weight of the vertex
+
+  Vertex();			// creates empty vertex
+  ~Vertex();			// destructor
+};
+
+class Graph {
+public:
+  int nb_vertices;		// number of vertices
+  int nb_edges;			// number of edges
+  float total_weight;		// total weight of the edges
+  Vertex* vertices;		// array of the vertices
+
+  long memory();			// the total memory used in Bytes
+  Graph();			// create an empty graph
+  ~Graph();			// destructor
+  char** index;			// to keep the real name of the vertices
+
+  int convert_from_igraph(const igraph_t * igraph, 
+			   const igraph_vector_t *weights);
+};
+
+} }        /* end of namespaces */
+
+#endif
+
diff --git a/src/walktrap_heap.cpp b/src/walktrap_heap.cpp
new file mode 100644
index 0000000..b77ef53
--- /dev/null
+++ b/src/walktrap_heap.cpp
@@ -0,0 +1,223 @@
+/* -*- 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here. The FSF address was
+   fixed by Tamas Nepusz */
+
+// File: heap.cpp
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pascal.pons at gmail.com
+// Web page : http://www-rp.lip6.fr/~latapy/PP/walktrap.html
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+#include "walktrap_heap.h"
+#include <cstdlib>
+#include <iostream>
+
+
+using namespace std;
+using namespace igraph::walktrap;
+
+void Neighbor_heap::move_up(int index) {
+  while(H[index/2]->delta_sigma > H[index]->delta_sigma) {
+    Neighbor* tmp = H[index/2];
+    H[index]->heap_index = index/2;
+    H[index/2] = H[index];
+    tmp->heap_index = index;
+    H[index] = tmp;
+    index = index/2;
+  }
+}
+
+void Neighbor_heap::move_down(int index) {
+  while(true) {
+    int min = index;
+    if((2*index < size) && (H[2*index]->delta_sigma < H[min]->delta_sigma))
+      min = 2*index;
+    if(2*index+1 < size && H[2*index+1]->delta_sigma < H[min]->delta_sigma)
+      min = 2*index+1;
+    if(min != index) {
+      Neighbor* tmp = H[min];
+      H[index]->heap_index = min;
+      H[min] = H[index];
+      tmp->heap_index = index;
+      H[index] = tmp;
+      index = min;
+    }
+    else break;
+  }
+}
+
+Neighbor* Neighbor_heap::get_first() {
+  if(size == 0) return 0;
+  else return H[0];
+}
+
+void Neighbor_heap::remove(Neighbor* N) {
+  if(N->heap_index == -1 || size == 0) return;
+  Neighbor* last_N = H[--size];
+  H[N->heap_index] = last_N;
+  last_N->heap_index = N->heap_index;
+  move_up(last_N->heap_index);
+  move_down(last_N->heap_index);  
+  N->heap_index = -1;
+}
+
+void Neighbor_heap::add(Neighbor* N) {
+  if(size >= max_size) return;
+    N->heap_index = size++;
+    H[N->heap_index] = N;
+  move_up(N->heap_index);
+}
+
+void Neighbor_heap::update(Neighbor* N) {
+  if(N->heap_index == -1) return;
+  move_up(N->heap_index);
+  move_down(N->heap_index);
+}
+
+long Neighbor_heap::memory() {
+  return (sizeof(Neighbor_heap) + long(max_size)*sizeof(Neighbor*));
+}
+  
+Neighbor_heap::Neighbor_heap(int max_s) {
+  max_size = max_s;
+  size = 0;
+  H = new Neighbor*[max_s];
+}
+
+Neighbor_heap::~Neighbor_heap() {
+  delete[] H;
+}
+
+bool Neighbor_heap::is_empty() {
+  return (size == 0);
+}
+
+
+
+//#################################################################
+
+void Min_delta_sigma_heap::move_up(int index) {
+  while(delta_sigma[H[index/2]] < delta_sigma[H[index]]) {
+    int tmp = H[index/2];
+    I[H[index]] = index/2;
+    H[index/2] = H[index];
+    I[tmp] = index;
+    H[index] = tmp;
+    index = index/2;
+  }
+}
+
+void Min_delta_sigma_heap::move_down(int index) {
+  while(true) {
+    int max = index;
+    if(2*index < size && delta_sigma[H[2*index]] > delta_sigma[H[max]])
+      max = 2*index;
+    if(2*index+1 < size && delta_sigma[H[2*index+1]] > delta_sigma[H[max]])
+      max = 2*index+1;
+    if(max != index) {
+      int tmp = H[max];
+      I[H[index]] = max;
+      H[max] = H[index];
+      I[tmp] = index;
+      H[index] = tmp;
+      index = max;
+    }
+    else break;
+  }
+}
+
+int Min_delta_sigma_heap::get_max_community() {
+  if(size == 0) return -1;
+  else return H[0];
+}
+
+void Min_delta_sigma_heap::remove_community(int community) {
+  if(I[community] == -1 || size == 0) return;
+  int last_community = H[--size];
+  H[I[community]] = last_community;
+  I[last_community] = I[community];
+  move_up(I[last_community]);
+  move_down(I[last_community]);  
+  I[community] = -1;
+}
+
+void Min_delta_sigma_heap::update(int community) {
+  if(community < 0 || community >= max_size) return;
+  if(I[community] == -1) {
+    I[community] = size++;
+    H[I[community]] = community;
+  }
+  move_up(I[community]);
+  move_down(I[community]);
+}
+
+long Min_delta_sigma_heap::memory() {
+  return (sizeof(Min_delta_sigma_heap) + long(max_size)*(2*sizeof(int) + sizeof(float)));
+}
+  
+Min_delta_sigma_heap::Min_delta_sigma_heap(int max_s) {
+  max_size = max_s;
+  size = 0;
+  H = new int[max_s];
+  I = new int[max_s];
+  delta_sigma = new float[max_s];
+  for(int i = 0; i < max_size; i++) {
+    I[i] = -1;
+    delta_sigma[i] = 1.;
+  }
+}
+
+Min_delta_sigma_heap::~Min_delta_sigma_heap() {
+  delete[] H;
+  delete[] I;
+  delete[] delta_sigma;
+}
+
+bool Min_delta_sigma_heap::is_empty() {
+  return (size == 0);
+}
diff --git a/src/walktrap_heap.h b/src/walktrap_heap.h
new file mode 100644
index 0000000..2176006
--- /dev/null
+++ b/src/walktrap_heap.h
@@ -0,0 +1,133 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   334 Harvard st, Cambridge, MA, 02138 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
+
+*/
+
+/* The original version of this file was written by Pascal Pons
+   The original copyright notice follows here. The FSF address was
+   fixed by Tamas Nepusz */
+
+// File: heap.h
+//-----------------------------------------------------------------------------
+// Walktrap v0.2 -- Finds community structure of networks using random walks
+// Copyright (C) 2004-2005 Pascal Pons
+//
+// 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
+//-----------------------------------------------------------------------------
+// Author   : Pascal Pons 
+// Email    : pons at liafa.jussieu.fr
+// Web page : http://www.liafa.jussieu.fr/~pons/
+// Location : Paris, France
+// Time	    : June 2005
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+#ifndef HEAP_H
+#define HEAP_H
+
+namespace igraph {
+
+namespace walktrap {
+
+class Neighbor {
+public:
+  int community1;   // the two adjacent communities
+  int community2;   // community1 < community2
+
+  float delta_sigma;	// the delta sigma between the two communities
+  float weight;		// the total weight of the edges between the two communities
+  bool exact;		// true if delta_sigma is exact, false if it is only a lower bound
+  
+  Neighbor* next_community1;	    // pointers of two double
+  Neighbor* previous_community1;    // chained lists containing
+  Neighbor* next_community2;	    // all the neighbors of
+  Neighbor* previous_community2;    // each communities.
+
+  int heap_index;	// 
+  
+  Neighbor();
+};
+
+
+class Neighbor_heap {  
+private:
+  int size;
+  int max_size;
+
+  Neighbor** H;   // the heap that contains a pointer to each Neighbor object stored
+
+  void move_up(int index);
+  void move_down(int index);
+  
+public:
+  void add(Neighbor* N);	    // add a new distance
+  void update(Neighbor* N);	    // update a distance 
+  void remove(Neighbor* N);	    // remove a distance
+  Neighbor* get_first();	    // get the first item
+  long memory();
+  bool is_empty();
+  
+  Neighbor_heap(int max_size);
+  ~Neighbor_heap();
+};
+
+
+class Min_delta_sigma_heap {
+private:
+  int size;
+  int max_size;
+
+  int* H;   // the heap that contains the number of each community
+  int* I;   // the index of each community in the heap (-1 = not stored)
+
+  void move_up(int index);
+  void move_down(int index);
+
+public:
+  int get_max_community();			    // return the community with the maximal delta_sigma
+  void remove_community(int community);		    // remove a community;
+  void update(int community);			    // update (or insert if necessary) the community
+  long memory();				    // the memory used in Bytes.
+  bool is_empty();
+
+  float* delta_sigma;				     // the delta_sigma of the stored communities
+  
+  Min_delta_sigma_heap(int max_size);
+  ~Min_delta_sigma_heap();
+};
+
+} }        /* end of namespaces */
+
+#endif
+
diff --git a/src/zeroin.c b/src/zeroin.c
new file mode 100644
index 0000000..ce80a64
--- /dev/null
+++ b/src/zeroin.c
@@ -0,0 +1,203 @@
+/* -*- 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
+
+*/
+
+/* from GNU R's zeroin.c, minor modifications by Gabor Csardi */
+
+/* from NETLIB c/brent.shar with max.iter, add'l info and convergence
+   details hacked in by Peter Dalgaard */
+
+/*************************************************************************
+ *			    C math library
+ * function ZEROIN - obtain a function zero within the given range
+ *
+ * Input
+ *	double zeroin(ax,bx,f,info,Tol,Maxit)
+ *	double ax;			Root will be seeked for within
+ *	double bx;			a range [ax,bx]
+ *	double (*f)(double x, void *info); Name of the function whose zero
+ *					will be seeked for
+ *	void *info;			Add'l info passed to f
+ *	double *Tol;			Acceptable tolerance for the root
+ *					value.
+ *					May be specified as 0.0 to cause
+ *					the program to find the root as
+ *					accurate as possible
+ *
+ *	int *Maxit;			Max. iterations
+ *
+ *
+ * Output
+ *	Zeroin returns an estimate for the root with accuracy
+ *	4*EPSILON*abs(x) + tol
+ *	*Tol returns estimated precision
+ *	*Maxit returns actual # of iterations, or -1 if maxit was
+ *      reached without convergence.
+ *
+ * Algorithm
+ *	G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical
+ *	computations. M., Mir, 1980, p.180 of the Russian edition
+ *
+ *	The function makes use of the bisection procedure combined with
+ *	the linear or quadric inverse interpolation.
+ *	At every step program operates on three abscissae - a, b, and c.
+ *	b - the last and the best approximation to the root
+ *	a - the last but one approximation
+ *	c - the last but one or even earlier approximation than a that
+ *		1) |f(b)| <= |f(c)|
+ *		2) f(b) and f(c) have opposite signs, i.e. b and c confine
+ *		   the root
+ *	At every step Zeroin selects one of the two new approximations, the
+ *	former being obtained by the bisection procedure and the latter
+ *	resulting in the interpolation (if a,b, and c are all different
+ *	the quadric interpolation is utilized, otherwise the linear one).
+ *	If the latter (i.e. obtained by the interpolation) point is
+ *	reasonable (i.e. lies within the current interval [b,c] not being
+ *	too close to the boundaries) it is accepted. The bisection result
+ *	is used in the other case. Therefore, the range of uncertainty is
+ *	ensured to be reduced at least by the factor 1.6
+ *
+ ************************************************************************
+ */
+
+#include "igraph_types.h"
+#include "igraph_interrupt_internal.h"
+
+#include <float.h>
+#include <math.h>
+
+#define EPSILON DBL_EPSILON
+
+int igraph_zeroin(		        /* An estimate of the root */
+    igraph_real_t *ax,			/* Left border | of the range	*/
+    igraph_real_t *bx,			/* Right border| the root is seeked*/
+    igraph_real_t (*f)(igraph_real_t x, void *info),	/* Function under investigation	*/
+    void *info,				/* Add'l info passed on to f	*/
+    igraph_real_t *Tol,			/* Acceptable tolerance		*/
+    int *Maxit,				/* Max # of iterations */
+    igraph_real_t *res)                 /* Result is stored here */
+{
+    igraph_real_t a,b,c,		/* Abscissae, descr. see above	*/
+	fa, fb, fc;			/* f(a), f(b), f(c) */
+    igraph_real_t tol;
+    int maxit;
+
+    a = *ax;  b = *bx;  fa = (*f)(a, info);  fb = (*f)(b, info);
+    c = a;   fc = fa;
+    maxit = *Maxit + 1; tol = * Tol;
+
+    /* First test if we have found a root at an endpoint */
+    if(fa == 0.0) {
+	*Tol = 0.0;
+	*Maxit = 0;
+	*res=a;
+	return 0;
+    }
+    if(fb ==  0.0) {
+	*Tol = 0.0;
+	*Maxit = 0;
+	*res=b;
+	return 0;
+    }
+
+    while(maxit--)		/* Main iteration loop	*/
+    {
+	igraph_real_t prev_step = b-a;	/* Distance from the last but one
+					   to the last approximation	*/
+	igraph_real_t tol_act;		/* Actual tolerance		*/
+	igraph_real_t p;		/* Interpolation step is calcu- */
+	igraph_real_t q;		/* lated in the form p/q; divi-
+					 * sion operations is delayed
+					 * until the last moment	*/
+	igraph_real_t new_step;		/* Step at this iteration	*/
+
+	IGRAPH_ALLOW_INTERRUPTION();
+
+	if( fabs(fc) < fabs(fb) )
+	{				/* Swap data for b to be the	*/
+	    a = b;  b = c;  c = a;	/* best approximation		*/
+	    fa=fb;  fb=fc;  fc=fa;
+	}
+	tol_act = 2*EPSILON*fabs(b) + tol/2;
+	new_step = (c-b)/2;
+
+	if( fabs(new_step) <= tol_act || fb == (igraph_real_t)0 )
+	{
+	    *Maxit -= maxit;
+	    *Tol = fabs(c-b);
+	    *res=b;
+	    return 0;			/* Acceptable approx. is found	*/
+	}
+
+	/* Decide if the interpolation can be tried	*/
+	if( fabs(prev_step) >= tol_act	/* If prev_step was large enough*/
+	    && fabs(fa) > fabs(fb) ) {	/* and was in true direction,
+					 * Interpolation may be tried	*/
+	    register igraph_real_t t1,cb,t2;
+	    cb = c-b;
+	    if( a==c ) {		/* If we have only two distinct	*/
+					/* points linear interpolation	*/
+		t1 = fb/fa;		/* can only be applied		*/
+		p = cb*t1;
+		q = 1.0 - t1;
+	    }
+	    else {			/* Quadric inverse interpolation*/
+
+		q = fa/fc;  t1 = fb/fc;	 t2 = fb/fa;
+		p = t2 * ( cb*q*(q-t1) - (b-a)*(t1-1.0) );
+		q = (q-1.0) * (t1-1.0) * (t2-1.0);
+	    }
+	    if( p>(igraph_real_t)0 )	/* p was calculated with the */
+		q = -q;			/* opposite sign; make p positive */
+	    else			/* and assign possible minus to	*/
+		p = -p;			/* q				*/
+
+	    if( p < (0.75*cb*q-fabs(tol_act*q)/2) /* If b+p/q falls in [b,c]*/
+		&& p < fabs(prev_step*q/2) )	/* and isn't too large	*/
+		new_step = p/q;			/* it is accepted
+						 * If p/q is too large then the
+						 * bisection procedure can
+						 * reduce [b,c] range to more
+						 * extent */
+	}
+
+	if( fabs(new_step) < tol_act) {	/* Adjust the step to be not less*/
+	    if( new_step > (igraph_real_t)0 )	/* than tolerance		*/
+		new_step = tol_act;
+	    else
+		new_step = -tol_act;
+	}
+	a = b;	fa = fb;			/* Save the previous approx. */
+	b += new_step;	fb = (*f)(b, info);	/* Do step to a new approxim. */
+	if( (fb > 0 && fc > 0) || (fb < 0 && fc < 0) ) {
+	    /* Adjust c for it to have a sign opposite to that of b */
+	    c = a;  fc = fa;
+	}
+
+    }
+    /* failed! */
+    *Tol = fabs(c-b);
+    *Maxit = -1;
+    *res=b;
+    return IGRAPH_DIVERGED;
+}
+
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..6da83b2
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,44 @@
+
+EXTRA_DIST = $(TESTSUITE_AT) $(top_builddir)/tests/testsuite
+
+MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE) package.m4 atconfig
+
+$(srcdir)/package.m4: $(top_srcdir)/configure.ac
+	{					\
+	  echo '# Signature of the current package.'; \
+	  echo 'm4_define([AT_PACKAGE_NAME],      [@PACKAGE_NAME@])'; \
+	  echo 'm4_define([AT_PACKAGE_TARNAME],   [@PACKAGE_TARNAME@])'; \
+	  echo 'm4_define([AT_PACKAGE_VERSION],   [@PACKAGE_VERSION@])'; \
+	  echo 'm4_define([AT_PACKAGE_STRING],    [@PACKAGE_STRING@])'; \
+	  echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
+	} >$(srcdir)/package.m4
+
+EXTRA_DIST += package.m4
+
+TESTSUITE_AT = \
+	testsuite.at \
+	types.at basic.at structure_generators.at \
+	structural_properties.at iterators.at components.at \
+	visitors.at layout.at motifs.at topology.at foreign.at operators.at \
+	other.at foreign.at conversion.at flow.at community.at eigen.at \
+	cliques.at attributes.at arpack.at bipartite.at centralization.at \
+	version.at separators.at hrg.at microscopic.at mt.at random.at scg.at \
+	matching.at qsort.at
+
+TESTSUITE = testsuite
+
+AUTOTEST = $(AUTOM4TE) --language=autotest
+$(TESTSUITE): $(srcdir)/package.m4 $(TESTSUITE_AT)
+	$(AUTOTEST) -I $(top_srcdir)/tests $(top_srcdir)/tests/testsuite.at -o $@.tmp
+	mv $@.tmp $@
+
+clean-local: $(TESTSUITE)
+	$(SHELL) $(TESTSUITE) --clean
+
+check-local: atconfig atlocal $(TESTSUITE)
+	if [ ! -f $(TESTSUITE) ]; then cp $(top_srcdir)/tests/testsuite .; fi
+	$(SHELL) $(TESTSUITE)
+
+# Run the test suite on the *installed* tree.
+installcheck-local:
+	$(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644
index 0000000..0c0db40
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,484 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = tests
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(srcdir)/atlocal.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/tools/autoconf/ax_tls.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = atlocal
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOM4TE = @AUTOM4TE@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLOATSTORE = @FLOATSTORE@
+GREP = @GREP@
+HAVE_TLS = @HAVE_TLS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_LIBS_PRIVATE = @PKGCONFIG_LIBS_PRIVATE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WERROR_CFLAGS = @WERROR_CFLAGS@
+XML2CONFIG = @XML2CONFIG@
+XML2_CFLAGS = @XML2_CFLAGS@
+XML2_LIBS = @XML2_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = $(TESTSUITE_AT) $(top_builddir)/tests/testsuite \
+	package.m4
+MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE) package.m4 atconfig
+TESTSUITE_AT = \
+	testsuite.at \
+	types.at basic.at structure_generators.at \
+	structural_properties.at iterators.at components.at \
+	visitors.at layout.at motifs.at topology.at foreign.at operators.at \
+	other.at foreign.at conversion.at flow.at community.at eigen.at \
+	cliques.at attributes.at arpack.at bipartite.at centralization.at \
+	version.at separators.at hrg.at microscopic.at mt.at random.at scg.at \
+	matching.at qsort.at
+
+TESTSUITE = testsuite
+AUTOTEST = $(AUTOM4TE) --language=autotest
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+atlocal: $(top_builddir)/config.status $(srcdir)/atlocal.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am: installcheck-local
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: all all-am check check-am check-local clean clean-generic \
+	clean-libtool clean-local cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installcheck-local installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags-am uninstall uninstall-am
+
+
+$(srcdir)/package.m4: $(top_srcdir)/configure.ac
+	{					\
+	  echo '# Signature of the current package.'; \
+	  echo 'm4_define([AT_PACKAGE_NAME],      [@PACKAGE_NAME@])'; \
+	  echo 'm4_define([AT_PACKAGE_TARNAME],   [@PACKAGE_TARNAME@])'; \
+	  echo 'm4_define([AT_PACKAGE_VERSION],   [@PACKAGE_VERSION@])'; \
+	  echo 'm4_define([AT_PACKAGE_STRING],    [@PACKAGE_STRING@])'; \
+	  echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
+	} >$(srcdir)/package.m4
+$(TESTSUITE): $(srcdir)/package.m4 $(TESTSUITE_AT)
+	$(AUTOTEST) -I $(top_srcdir)/tests $(top_srcdir)/tests/testsuite.at -o $@.tmp
+	mv $@.tmp $@
+
+clean-local: $(TESTSUITE)
+	$(SHELL) $(TESTSUITE) --clean
+
+check-local: atconfig atlocal $(TESTSUITE)
+	if [ ! -f $(TESTSUITE) ]; then cp $(top_srcdir)/tests/testsuite .; fi
+	$(SHELL) $(TESTSUITE)
+
+# Run the test suite on the *installed* tree.
+installcheck-local:
+	$(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/arpack.at b/tests/arpack.at
new file mode 100644
index 0000000..640df23
--- /dev/null
+++ b/tests/arpack.at
@@ -0,0 +1,68 @@
+# Check ARPACK based functins
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[BLAS, LAPACK and ARPACK based functions]])
+
+AT_SETUP([Basic BLAS functions (igraph_blas_*):])
+AT_KEYWORDS([blas BLAS matrix vector dgemv igraph_blas_dgemv])
+AT_COMPILE_CHECK([simple/blas.c],
+                 [simple/blas.out])
+AT_CLEANUP
+
+AT_SETUP([Dense symmetric eigenvalues and eigenvectors (igraph_lapack_dsyevr):])
+AT_KEYWORDS([lapack LAPACK dsyevr eigenvalue eigenvector dense])
+AT_COMPILE_CHECK([simple/igraph_lapack_dsyevr.c])
+AT_CLEANUP
+
+AT_SETUP([Dense non-symmetric eigenvalues and eigenvectors (igraph_lapack_dgeev):])
+AT_KEYWORDS([lapack LAPACK dgeev eigenvalue eigenvector dense])
+AT_COMPILE_CHECK([simple/igraph_lapack_dgeev.c])
+AT_CLEANUP
+
+AT_SETUP([Dense non-symmetric eigenvalues and eigenvectors (igraph_lapack_dgeevx):])
+AT_KEYWORDS([lapack LAPACK dgeevx eigenvalue eigenvector dense])
+AT_COMPILE_CHECK([simple/igraph_lapack_dgeevx.c])
+AT_CLEANUP
+
+AT_SETUP([Solving linear systems with LU factorization (igraph_lapack_dgesv):])
+AT_KEYWORDS([lapack LAPACK dgesv solve LU factorization])
+AT_COMPILE_CHECK([simple/igraph_lapack_dgesv.c],
+		 [simple/igraph_lapack_dgesv.out])
+AT_CLEANUP
+
+AT_SETUP([Upper Hessenberg transformation (igraph_lapack_dgehrd):])
+AT_KEYWORDS([lapack dgehrd Hessenberg])
+AT_COMPILE_CHECK([simple/igraph_lapack_dgehrd.c],
+		 [simple/igraph_lapack_dgehrd.out])
+AT_CLEANUP
+
+AT_SETUP([Eigenvector centrality (igraph_eigenvector_centrality):])
+AT_KEYWORDS([eigenvector centrality arpack ARPACK])
+AT_COMPILE_CHECK([simple/eigenvector_centrality.c],
+                 [simple/eigenvector_centrality.out])
+AT_CLEANUP
+
+AT_SETUP([Non-symmetric ARPACK solver (igraph_arpack_rnsolve):])
+AT_KEYWORDS([ARPACK eigenvalue eigenvector eigen eigenproblem 
+             non-symmetric])
+AT_COMPILE_CHECK([simple/igraph_arpack_rnsolve.c],
+		 [simple/igraph_arpack_rnsolve.out])
+AT_CLEANUP
diff --git a/tests/atlocal.in b/tests/atlocal.in
new file mode 100644
index 0000000..7afe765
--- /dev/null
+++ b/tests/atlocal.in
@@ -0,0 +1,11 @@
+# @configure_input@
+# Configurable variable values for igraph test suite. Taken from bison source.
+# Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+# We need a C compiler.
+CC='@CC@'
+CFLAGS='@CFLAGS@ @WARNING_CFLAGS@ @WERROR_CFLAGS@'
+
+# We need `config.h'.
+CPPFLAGS="-I$abs_top_builddir @CPPFLAGS@"
+
diff --git a/tests/attributes.at b/tests/attributes.at
new file mode 100644
index 0000000..7f44884
--- /dev/null
+++ b/tests/attributes.at
@@ -0,0 +1,44 @@
+# Check functions for graph, vertex and edge attributes
+
+# Test suite for the 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
+
+AT_BANNER([[Attributes from C]])
+
+AT_SETUP([Reading a Pajek file with attributes:])
+AT_KEYWORDS([pajek attributes])
+AT_COMPILE_CHECK([simple/cattributes.c], [simple/cattributes.out], 
+	         [simple/LINKS.NET])
+AT_CLEANUP
+
+AT_SETUP([Writing an attributed graph in GML and GraphML:])
+AT_KEYWORDS([gml GML graphml GraphML attributes])
+AT_COMPILE_CHECK([simple/cattributes2.c], [simple/cattributes2.out])
+AT_CLEANUP
+
+AT_SETUP([Combining numeric attributes:])
+AT_KEYWORDS([attributes combination combining])
+AT_COMPILE_CHECK([simple/cattributes3.c], [simple/cattributes3.out])
+AT_CLEANUP
+
+AT_SETUP([Combining string attributes:])
+AT_KEYWORDS([attributes combination combining])
+AT_COMPILE_CHECK([simple/cattributes4.c], [simple/cattributes4.out])
+AT_CLEANUP
+
diff --git a/tests/basic.at b/tests/basic.at
new file mode 100644
index 0000000..76e479c
--- /dev/null
+++ b/tests/basic.at
@@ -0,0 +1,81 @@
+# Check the basic (interface) functions and implicitly also compilation
+
+# Test suite for the IGraph library.
+# 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
+
+# Macros
+
+AT_BANNER([[Basic (interface) functions.]])
+
+AT_SETUP([Creating an empty graph (igraph_empty): ])
+AT_KEYWORDS([igraph_empty])
+AT_COMPILE_CHECK([simple/igraph_empty.c])
+AT_CLEANUP
+
+AT_SETUP([Copying a graph (igraph_copy): ])
+AT_KEYWORDS([igraph_copy igraph_create])
+AT_COMPILE_CHECK([simple/igraph_copy.c])
+AT_CLEANUP
+
+AT_SETUP([Adding edges to a graph (igraph_add_edges): ])
+AT_KEYWORDS([igraph_add_edges])
+AT_COMPILE_CHECK([simple/igraph_add_edges.c], 
+	[simple/igraph_add_edges.out])
+AT_CLEANUP
+
+AT_SETUP([Adding vertices (igraph_add_vertices): ])
+AT_KEYWORDS([igraph_add_vertices])
+AT_COMPILE_CHECK([simple/igraph_add_vertices.c])
+AT_CLEANUP
+
+AT_SETUP([Deleting edges (igraph_delete_edges): ])
+AT_KEYWORDS([igraph_delete_vertices])
+AT_COMPILE_CHECK([simple/igraph_delete_edges.c])
+AT_CLEANUP
+
+AT_SETUP([Deleting vertices (igraph_delete_vertices): ])
+AT_KEYWORDS([igraph_delete_vertices])
+AT_COMPILE_CHECK([simple/igraph_delete_vertices.c])
+AT_CLEANUP
+
+AT_SETUP([Neighbors (igraph_neighbors): ])
+AT_KEYWORDS([igraph_neighbors])
+AT_COMPILE_CHECK([simple/igraph_neighbors.c], [simple/igraph_neighbors.out])
+AT_CLEANUP
+
+AT_SETUP([Is the graph directed? (igraph_is_directed): ])
+AT_KEYWORDS([igraph_is_directed])
+AT_COMPILE_CHECK([simple/igraph_is_directed.c])
+AT_CLEANUP
+
+AT_SETUP([Degree of the vertices (igraph_degree): ])
+AT_KEYWORDS([igraph_degree])
+AT_COMPILE_CHECK([simple/igraph_degree.c], [simple/igraph_degree.out])
+AT_CLEANUP
+
+AT_SETUP([Query edge ids (igraph_get_eid): ])
+AT_KEYWORDS([igraph_get_eid edge id])
+AT_COMPILE_CHECK([simple/igraph_get_eid.c], [simple/igraph_get_eid.out])
+AT_CLEANUP
+
+AT_SETUP([Query many edge ids (igraph_get_eids): ])
+AT_KEYWORDS([igraph_get_eids edge id])
+AT_COMPILE_CHECK([simple/igraph_get_eids.c], [simple/igraph_get_eids.out])
+AT_CLEANUP
+
diff --git a/tests/bipartite.at b/tests/bipartite.at
new file mode 100644
index 0000000..2e419b0
--- /dev/null
+++ b/tests/bipartite.at
@@ -0,0 +1,33 @@
+# Check functions for bipartite graphs
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Bipartite graphs]])
+
+AT_SETUP([Create bipartite graphs (igraph_create_bipartite):])
+AT_KEYWORDS([bipartite two mode igraph_create_bipartite])
+AT_COMPILE_CHECK([simple/igraph_bipartite_create.c],
+                 [simple/igraph_bipartite_create.out])
+AT_CLEANUP
+
+AT_SETUP([Projection of bipartite graphs (igraph_bipartite_projection):])
+AT_KEYWORDS([bipartite two mode projection igraph_bipartite_projection])
+AT_COMPILE_CHECK([simple/igraph_bipartite_projection.c])
+AT_CLEANUP
diff --git a/tests/centralization.at b/tests/centralization.at
new file mode 100644
index 0000000..dc4446c
--- /dev/null
+++ b/tests/centralization.at
@@ -0,0 +1,27 @@
+# Check functions for centralization
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Centralization]])
+
+AT_SETUP([Centralization (igraph_centralization_*):])
+AT_KEYWORDS([centralization])
+AT_COMPILE_CHECK([simple/centralization.c])
+AT_CLEANUP
diff --git a/tests/cliques.at b/tests/cliques.at
new file mode 100644
index 0000000..bfcdbee
--- /dev/null
+++ b/tests/cliques.at
@@ -0,0 +1,61 @@
+# Check the functions related to clique and independent set calculations
+
+# Test suite for the IGraph library.
+# 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
+
+# Macros
+
+AT_BANNER([[Cliques and independent vertex sets.]])
+
+AT_SETUP([Calculating cliques (igraph_cliques): ])
+AT_KEYWORDS([igraph_cliques, igraph_maximal_cliques, igraph_clique_number])
+AT_COMPILE_CHECK([simple/igraph_cliques.c], [simple/igraph_cliques.out])
+AT_CLEANUP
+
+AT_SETUP([Additional test for maximal cliques (igraph_maximal_cliques):])
+AT_KEYWORDS([igraph_maximal_cliques cliques maximal cliques])
+AT_COMPILE_CHECK([simple/igraph_maximal_cliques.c],
+		 [simple/igraph_maximal_cliques.out])
+AT_CLEANUP
+
+AT_SETUP([More maximal cliques (igraph_maximal_cliques):])
+AT_KEYWORDS([igraph_maximal_cliques cliques maximal cliques])
+AT_COMPILE_CHECK([simple/igraph_maximal_cliques2.c], 
+                 [simple/igraph_maximal_cliques2.out])
+AT_CLEANUP
+
+AT_SETUP([Maximal cliques 3 (igraph_maximal_cliques):])
+AT_KEYWORDS([igraph_maximal_cliques cliques maximal cliques])
+AT_COMPILE_CHECK([simple/igraph_maximal_cliques3.c], 
+                 [simple/igraph_maximal_cliques3.out])
+AT_CLEANUP
+
+AT_SETUP([Maximal cliques for a subset (igraph_maximal_cliques):])
+AT_KEYWORDS([igraph_maximal_cliques cliques maximal cliques])
+AT_COMPILE_CHECK([simple/igraph_maximal_cliques4.c], 
+                 [simple/igraph_maximal_cliques4.out])
+AT_CLEANUP
+
+AT_SETUP([Calculating independent vertex sets (igraph_independent_vertex_sets): ])
+AT_KEYWORDS([igraph_independent_vertex_sets,
+	igraph_maximal_independent_vertex_sets,
+	igraph_independence_number])
+AT_COMPILE_CHECK([simple/igraph_independent_sets.c], [simple/igraph_independent_sets.out])
+AT_CLEANUP
+
diff --git a/tests/community.at b/tests/community.at
new file mode 100644
index 0000000..6ca91ab
--- /dev/null
+++ b/tests/community.at
@@ -0,0 +1,91 @@
+# Community structure
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Community structure]])
+
+AT_SETUP([Spinglass clustering (igraph_spinglass_community): ])
+AT_KEYWORDS([spin glass spinglass community clustering])
+AT_COMPILE_CHECK([simple/spinglass.c])
+AT_CLEANUP
+
+AT_SETUP([Walktrap community structure (igraph_walktrap_community): ])
+AT_KEYWORDS([random walk community structure clustering walktrap])
+AT_COMPILE_CHECK([simple/walktrap.c], [simple/walktrap.out])
+AT_CLEANUP
+
+AT_SETUP([Edge betweenness community structure (igraph_community_edge_betweenness): ])
+AT_KEYWORDS([community structure edge betweenness Newman Girvan])
+AT_COMPILE_CHECK([simple/igraph_community_edge_betweenness.c],
+		 [simple/igraph_community_edge_betweenness.out])
+AT_CLEANUP
+
+AT_SETUP([Modularity optimization (igraph_community_fastgreedy): ])
+AT_KEYWORDS([community structure Clauset Newman Moore modularity greedy])
+AT_COMPILE_CHECK([simple/igraph_community_fastgreedy.c],
+                 [simple/igraph_community_fastgreedy.out])
+AT_CLEANUP
+
+AT_SETUP([Leading eigenvector community structure (igraph_community_leading_eigenvector) :])
+AT_KEYWORDS([community structure leading eigenvector Newman])
+AT_COMPILE_CHECK([simple/igraph_community_leading_eigenvector.c],
+                 [simple/igraph_community_leading_eigenvector.out])
+AT_CLEANUP
+
+AT_SETUP([Weighted leading eigenvector community structure (igraph_community_leading_eigenvector) :])
+AT_KEYWORDS([community structure leading eigenvector Newman weighted])
+AT_COMPILE_CHECK([simple/igraph_community_leading_eigenvector2.c],
+                 [simple/igraph_community_leading_eigenvector2.out])
+AT_CLEANUP
+
+AT_SETUP([Leading eigenvector bug #1002140 test (igraph_community_leading_eigenvector) :])
+AT_KEYWORDS([community structure leading eigenvector Newman])
+AT_COMPILE_CHECK([simple/levc-stress.c], [], [simple/input.dl])
+AT_CLEANUP
+
+
+AT_SETUP([Label propagation algorithm (igraph_community_label_propagation) :])
+AT_KEYWORDS([community structure label propagation Raghavan Albert Kumara])
+AT_COMPILE_CHECK([simple/igraph_community_label_propagation.c],
+                 [simple/igraph_community_label_propagation.out])
+AT_CLEANUP
+
+AT_SETUP([Multilevel community detection (igraph_community_multilevel) :])
+AT_KEYWORDS([community structure multilevel Blondel Guillaume Lambiotte Lefebvre])
+AT_COMPILE_CHECK([simple/igraph_community_multilevel.c],
+                 [simple/igraph_community_multilevel.out])
+AT_CLEANUP
+
+AT_SETUP([Multilevel community detection, isolates (igraph_community_multilevel) :])
+AT_KEYWORDS([community structure multilevel Blondel Guillaume Lambiotte Lefebvre])
+AT_COMPILE_CHECK([simple/bug-1149658.c])
+AT_CLEANUP
+
+AT_SETUP([Modularity optimization, integer programming (igraph_community_optimal_modularity) :])
+AT_KEYWORDS([community structure optimal modularity integer programming])
+AT_COMPILE_CHECK([simple/igraph_community_optimal_modularity.c])
+AT_CLEANUP
+
+AT_SETUP([Infomap community structure (igraph_community_infomap) :])
+AT_KEYWORDS([community structure infomap Rosvall Bergstrom])
+AT_COMPILE_CHECK([simple/igraph_community_infomap.c],
+                 [simple/igraph_community_infomap.out],
+                 [simple/wikti_en_V_syn.elist])
+AT_CLEANUP
diff --git a/tests/components.at b/tests/components.at
new file mode 100644
index 0000000..ccaa4c8
--- /dev/null
+++ b/tests/components.at
@@ -0,0 +1,34 @@
+# Check functions for working with connected components
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Components]])
+
+AT_SETUP([Decompose a graph (igraph_decompose):])
+AT_KEYWORDS([igraph_decompose decompose component])
+AT_COMPILE_CHECK([simple/igraph_decompose.c], [simple/igraph_decompose.out])
+AT_CLEANUP
+
+AT_SETUP([Biconnected components (igraph_biconnected_components):])
+AT_KEYWORDS([igraph_biconnected_components biconnected component])
+AT_COMPILE_CHECK([simple/igraph_biconnected_components.c],
+  [simple/igraph_biconnected_components.out])
+AT_CLEANUP
+
diff --git a/tests/conversion.at b/tests/conversion.at
new file mode 100644
index 0000000..48c92f4
--- /dev/null
+++ b/tests/conversion.at
@@ -0,0 +1,40 @@
+# Check various conversion functions
+
+# Test suite for the IGraph library.
+# 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
+# (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
+
+AT_BANNER([[Conversion functions]])
+
+AT_SETUP([Directed to undirected (igraph_to_undirected):])
+AT_KEYWORDS([igraph_to_undirected directedness undirected directed])
+AT_COMPILE_CHECK([simple/igraph_to_undirected.c], 
+	         [simple/igraph_to_undirected.out])
+AT_CLEANUP
+
+AT_SETUP([Graphs from adjacency list (igraph_adjlist):])
+AT_KEYWORDS([igraph_adjlist adjacency list adjlist])
+AT_COMPILE_CHECK([simple/adjlist.c])
+AT_CLEANUP
+
+AT_SETUP([Graph to Laplacian matrix (igraph_laplacian):])
+AT_KEYWORDS([igraph_laplacian laplacian matrix])
+AT_COMPILE_CHECK([simple/igraph_laplacian.c],
+                 [simple/igraph_laplacian.out])
+AT_CLEANUP
+
diff --git a/tests/eigen.at b/tests/eigen.at
new file mode 100644
index 0000000..e90e9b5
--- /dev/null
+++ b/tests/eigen.at
@@ -0,0 +1,59 @@
+# Eigenvalues, eigenvectors
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Eigenvalues, eigenvectors]])
+
+AT_SETUP([Symmetric matrix, LAPACK (igraph_eigen_matrix_symmetric):])
+AT_KEYWORDS([eigenvalue lapack LAPACK])
+AT_COMPILE_CHECK([simple/igraph_eigen_matrix_symmetric.c],
+		 [simple/igraph_eigen_matrix_symmetric.out])
+AT_CLEANUP
+
+AT_SETUP([Symmetric matrix, ARPACK (igraph_eigen_matrix_symmetric):])
+AT_KEYWORDS([eigenvalue lapack LAPACK])
+AT_COMPILE_CHECK([simple/igraph_eigen_matrix_symmetric_arpack.c],
+		 [simple/igraph_eigen_matrix_symmetric_arpack.out])
+AT_CLEANUP
+
+AT_SETUP([General matrix, LAPACK, LM, SM (igraph_eigen_matrix):])
+AT_KEYWORDS([eigenvalue lapack LAPACK])
+AT_COMPILE_CHECK([simple/igraph_eigen_matrix.c],
+		 [simple/igraph_eigen_matrix.out])
+AT_CLEANUP
+
+AT_SETUP([General matrix, LAPACK, LR, SR (igraph_eigen_matrix):])
+AT_KEYWORDS([eigenvalue lapack LAPACK])
+AT_COMPILE_CHECK([simple/igraph_eigen_matrix2.c],
+		 [simple/igraph_eigen_matrix2.out])
+AT_CLEANUP
+
+AT_SETUP([General matrix, LAPACK, LI, SI (igraph_eigen_matrix):])
+AT_KEYWORDS([eigenvalue lapack LAPACK])
+AT_COMPILE_CHECK([simple/igraph_eigen_matrix4.c],
+		 [simple/igraph_eigen_matrix4.out])
+AT_CLEANUP
+
+AT_SETUP([General matrix, LAPACK, SELECT (igraph_eigen_matrix):])
+AT_KEYWORDS([eigenvalue lapack LAPACK])
+AT_COMPILE_CHECK([simple/igraph_eigen_matrix3.c],
+		 [simple/igraph_eigen_matrix3.out])
+AT_CLEANUP
+
diff --git a/tests/flow.at b/tests/flow.at
new file mode 100644
index 0000000..ac945ff
--- /dev/null
+++ b/tests/flow.at
@@ -0,0 +1,66 @@
+# Check maximum flow and related functions
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Maximum flows and such]])
+
+AT_SETUP([Maximum flow value (igraph_maxflow_value): ])
+AT_KEYWORDS([maximum flow maxflow minimum cut])
+AT_COMPILE_CHECK([simple/flow.c], [], [simple/ak-4102.max])
+AT_CLEANUP
+
+AT_SETUP([Maximum flow (igraph_maxflow): ])
+AT_KEYWORDS([maximum flow maxflow minimum cut])
+AT_COMPILE_CHECK([simple/flow2.c], [simple/flow2.out], [simple/ak-4102.max])
+AT_CLEANUP
+
+AT_SETUP([Minimum cut (igraph_mincut): ])
+AT_KEYWORDS([minimum cut Stoer-Wagner])
+AT_COMPILE_CHECK([simple/igraph_mincut.c], [simple/igraph_mincut.out])
+AT_CLEANUP
+
+AT_SETUP([Even-Tarjan reduction (igraph_even_tarjan_reduction): ])
+AT_KEYWORDS([Even Tarjan reduction vertex cut separator])
+AT_COMPILE_CHECK([simple/even_tarjan.c])
+AT_CLEANUP
+
+AT_SETUP([Dominator tree of a flow graph (igraph_dominator_tree): ])
+AT_KEYWORDS([dominator tree])
+AT_COMPILE_CHECK([simple/dominator_tree.c],
+                 [simple/dominator_tree.out])
+AT_CLEANUP
+
+AT_SETUP([All s-t cuts of a graph (igraph_all_st_cuts): ])
+AT_KEYWORDS([s-t cut])
+AT_COMPILE_CHECK([simple/igraph_all_st_cuts.c], 
+                 [simple/igraph_all_st_cuts.out], [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([All minimal s-t cuts of a graph (igraph_all_st_mincuts): ])
+AT_KEYWORDS([minimal s-t cut])
+AT_COMPILE_CHECK([simple/igraph_all_st_mincuts.c], 
+                 [simple/igraph_all_st_mincuts.out])
+AT_CLEANUP
+
+AT_SETUP([Gomory-Hu tree (igraph_gomory_hu_tree): ])
+AT_KEYWORDS([Gomory-Hu tree])
+AT_COMPILE_CHECK([simple/igraph_gomory_hu_tree.c])
+AT_CLEANUP
+
diff --git a/tests/foreign.at b/tests/foreign.at
new file mode 100644
index 0000000..b1918ea
--- /dev/null
+++ b/tests/foreign.at
@@ -0,0 +1,114 @@
+# Check functions for importing and exporting various formats
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Foreign formats]])
+
+AT_SETUP([Reading Pajek (igraph_read_graph_pajek):])
+AT_KEYWORDS([igraph_read_graph_pajek foreign pajek])
+AT_COMPILE_CHECK([simple/foreign.c], [simple/foreign.out], [simple/LINKS.NET])
+AT_CLEANUP
+
+AT_SETUP([GraphML (igraph_{read,write}_graph_graphml):])
+AT_KEYWORDS([igraph_read_graph_graphml igraph_write_graph_graphml foreign graphml])
+AT_COMPILE_CHECK([simple/graphml.c], [simple/graphml.out], 
+	[simple/{test.gxl,graphml-hsa05010.xml}])
+AT_CLEANUP
+
+AT_SETUP([Writing Pajek (igraph_write_graph_pajek):])
+AT_KEYWORDS([igraph_write_graph_pajek foreign pajek])
+AT_COMPILE_CHECK([simple/igraph_write_graph_pajek.c], 
+ 		 [simple/igraph_write_graph_pajek.out])
+AT_CLEANUP
+
+AT_SETUP([Pajek with number of edges present (igraph_read_graph_pajek):])
+AT_KEYWORDS([igraph_read_graph_pajek pajek foreign])
+AT_COMPILE_CHECK([simple/pajek.c], [], [simple/pajek{5,6}.net])
+AT_CLEANUP
+
+AT_SETUP([Pajek, bipartite (igraph_read_graph_pajek):])
+AT_KEYWORDS([igraph_read_graph_pajek pajek foreign bipartite])
+AT_COMPILE_CHECK([simple/pajek2.c], [simple/pajek2.out], 
+		 [simple/bipartite.net])
+AT_CLEANUP
+
+AT_SETUP([Pajek, bipartite incidence matrix (igraph_read_graph_pajek):])
+AT_KEYWORDS([igraph_read_graph_pajek pajek foreign bipartite incidence])
+AT_COMPILE_CHECK([simple/pajek_bipartite2.c], [simple/pajek_bipartite2.out], 
+	         [simple/pajek_{bip,bip2}.net])
+AT_CLEANUP
+
+AT_SETUP([Pajek, signed (igraph_read_graph_pajek):])
+AT_KEYWORDS([igraph_read_graph_pajek pajek foreign signed])
+AT_COMPILE_CHECK([simple/pajek_signed.c], [simple/pajek_signed.out], 
+		 [simple/pajek_signed.net])
+AT_CLEANUP
+
+AT_SETUP([Pajek, writing bipartite graph (igraph_write_graph_pajek):])
+AT_KEYWORDS([igraph_write_graph_pajek pajek foreign bipartite])
+AT_COMPILE_CHECK([simple/pajek_bipartite.c], [simple/pajek_bipartite.out])
+AT_CLEANUP
+
+AT_SETUP([Reading an LGL file (igraph_read_graph_lgl):])
+AT_KEYWORDS([igraph_read_graph_lgl LGL foreign])
+AT_COMPILE_CHECK([simple/igraph_read_graph_lgl.c],
+		 [simple/igraph_read_graph_lgl.out],
+		 [{simple/igraph_read_graph_lgl-1.lgl,simple/igraph_read_graph_lgl-2.lgl,simple/igraph_read_graph_lgl-3.lgl}])
+AT_CLEANUP
+
+AT_SETUP([Writing LGL (igraph_write_graph_lgl):])
+AT_KEYWORDS([igraph_write_graph_lgl foreign LGL])
+AT_COMPILE_CHECK([simple/igraph_write_graph_lgl.c])
+AT_CLEANUP
+
+AT_SETUP([Reading a graph from the graph database (igraph_read_graph_graphdb):])
+AT_KEYWORDS([igraph_read_graph_graphdb foreign graphdb database isomorphism])
+AT_COMPILE_CHECK([simple/igraph_read_graph_graphdb.c],
+	[simple/igraph_read_graph_graphdb.out],
+	[simple/iso_b03_m1000.A00])
+AT_CLEANUP
+
+AT_SETUP([Reading a GML file (igraph_read_graph_gml):])
+AT_KEYWORDS([igraph_read_graph_gml foreign GML])
+AT_COMPILE_CHECK([simple/gml.c], [simple/gml.out], [simple/karate.gml])
+AT_CLEANUP
+
+AT_SETUP([Writing a DOT file (igraph_write_graph_dot):])
+AT_KEYWORDS([igraph_write_graph_dot foreign DOT GraphViz])
+AT_COMPILE_CHECK([simple/dot.c], [simple/dot.out], [simple/karate.gml])
+AT_CLEANUP
+
+AT_SETUP([Different line endings:])
+AT_KEYWORDS([igraph_read_graph_pajek igraph_write_graph_pajek 
+	foreign line ending lineending])
+AT_COMPILE_CHECK([simple/lineendings.c], [simple/lineendings.out],
+	[{simple/pajek1.net,simple/pajek2.net,simple/pajek3.net,simple/pajek4.net}])
+AT_CLEANUP
+
+AT_SETUP([UNICET DL format:])
+AT_KEYWORDS([igraph_read_graph_dl DL UCINET])
+AT_COMPILE_CHECK([simple/igraph_read_graph_dl.c], [simple/igraph_read_graph_dl.out],
+        [simple/{edgelist1,edgelist2,edgelist3,edgelist4,edgelist5,edgelist6,fullmatrix1,fullmatrix2,fullmatrix3,fullmatrix4,nodelist1,nodelist2}.dl])
+AT_CLEANUP
+
+AT_SETUP([LEDA format:])
+AT_KEYWORDS([igraph_write_graph_leda LEDA])
+AT_COMPILE_CHECK([simple/igraph_write_graph_leda.c], [simple/igraph_write_graph_leda.out], [])
+AT_CLEANUP
diff --git a/tests/hrg.at b/tests/hrg.at
new file mode 100644
index 0000000..317fc0c
--- /dev/null
+++ b/tests/hrg.at
@@ -0,0 +1,37 @@
+# Hierarchical random graphs
+
+# Test suite for the 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
+
+AT_BANNER([[Hierarchical random graphs]])
+
+AT_SETUP([Fitting a hierarchical model (igraph_hrg_fit) :])
+AT_KEYWORDS([hierarchical random graph])
+AT_COMPILE_CHECK([simple/igraph_hrg.c])
+AT_CLEANUP
+
+AT_SETUP([Consensus tree (igraph_hrg_consensus) :])
+AT_KEYWORDS([hierarchical random graph consensus tree])
+AT_COMPILE_CHECK([simple/igraph_hrg2.c], [simple/igraph_hrg2.out])
+AT_CLEANUP
+
+AT_SETUP([Missing edge prediction (igraph_hrg_predict) :])
+AT_KEYWORDS([hierarchical random graph missing edge prediction])
+AT_COMPILE_CHECK([simple/igraph_hrg3.c], [simple/igraph_hrg3.out])
+AT_CLEANUP
diff --git a/tests/iterators.at b/tests/iterators.at
new file mode 100644
index 0000000..d8237f5
--- /dev/null
+++ b/tests/iterators.at
@@ -0,0 +1,57 @@
+# Check vertex and edge sequences (=iterators)
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Iterators aka vertex and edge sequences]])
+
+AT_SETUP([Vertices in a vector (igraph_vs_vector): ])
+AT_KEYWORDS([iterator vector igraph_vs_vector igraph_vs_vectorview])
+AT_COMPILE_CHECK([simple/igraph_vs_vector.c], [simple/igraph_vs_vector.out])
+AT_CLEANUP
+
+AT_SETUP([Non-adjacent vertices (igraph_vs_nonadj): ])
+AT_KEYWORDS([iterator igraph_vs_nonadj])
+AT_COMPILE_CHECK([simple/igraph_vs_nonadj.c], [simple/igraph_vs_nonadj.out])
+AT_CLEANUP
+
+AT_SETUP([Sequence (igraph_vs_seq): ])
+AT_KEYWORDS([iterator igraph_vs_seq seq sequence])
+AT_COMPILE_CHECK([simple/igraph_vs_seq.c], [simple/igraph_vs_seq.out])
+AT_CLEANUP
+
+#AT_SETUP([Adjacent edges (igraph_es_adj): ])
+#AT_KEYWORDS([iterator adjacent igraph_es_adj])
+#AT_COMPILE_CHECK([simple/igraph_es_adj.c], [simple/igraph_es_adj.out])
+#AT_CLEANUP
+
+#AT_SETUP([Edges connecting two vertex sets (igraph_es_fromto): ])
+#AT_KEYWORDS([iterator igraph_es_fromto])
+#AT_COMPILE_CHECK([simple/igraph_es_fromto.c], [simple/igraph_es_fromto.out])
+#AT_CLEANUP
+
+AT_SETUP([Edges given by end points (igraph_es_pairs): ])
+AT_KEYWORDS([iterator igraph_es_pairs])
+AT_COMPILE_CHECK([simple/igraph_es_pairs.c])
+AT_CLEANUP
+
+AT_SETUP([Edges in a path (igraph_es_path): ])
+AT_KEYWORDS([iterator, igraph_es_path])
+AT_COMPILE_CHECK([simple/igraph_es_path.c])
+AT_CLEANUP
diff --git a/tests/layout.at b/tests/layout.at
new file mode 100644
index 0000000..752a57f
--- /dev/null
+++ b/tests/layout.at
@@ -0,0 +1,69 @@
+# Check functions for generating layouts
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Layouts]])
+
+AT_SETUP([Grid layout (igraph_layout_grid, igraph_layout_grid_3d):])
+AT_KEYWORDS([igraph_layout_grid igraph_layout_grid_3d grid layout])
+AT_COMPILE_CHECK([simple/igraph_layout_grid.c], [simple/igraph_layout_grid.out])
+AT_CLEANUP
+
+AT_SETUP([Large Graph Layout (igraph_layout_lgl):])
+AT_KEYWORDS([igraph_layout_lgl LGL])
+AT_COMPILE_CHECK([simple/igraph_layout_lgl.c])
+AT_CLEANUP
+
+AT_SETUP([Reingold-Tilford tree layout (igraph_layout_reingold_tilford):])
+AT_KEYWORDS([reingold tilford tree layout igraph_layout_reingold_tilford])
+AT_COMPILE_CHECK([simple/igraph_layout_reingold_tilford.c], [],
+  [simple/igraph_layout_reingold_tilford.in])
+AT_CLEANUP
+
+AT_SETUP([Sugiyama layout (igraph_layout_sugiyama):])
+AT_KEYWORDS([sugiyama layout igraph_layout_sugiyama])
+AT_COMPILE_CHECK([simple/igraph_layout_sugiyama.c], [simple/igraph_layout_sugiyama.out])
+AT_CLEANUP
+
+AT_SETUP([Multidimensional scaling (igraph_layout_mds):])
+AT_KEYWORDS([multidimensional scaling layout igraph_layout_mds])
+AT_COMPILE_CHECK([simple/igraph_layout_mds.c], [simple/igraph_layout_mds.out])
+AT_CLEANUP
+
+AT_SETUP([Covering circle and sphere (igraph_i_layout_sphere_{2,3}d):])
+AT_KEYWORDS([covering circle sphere layout])
+AT_COMPILE_CHECK([simple/igraph_i_layout_sphere.c])
+AT_CLEANUP
+
+AT_SETUP([Merging layouts (igraph_i_layout_merge):])
+AT_KEYWORDS([layout merge dla])
+AT_COMPILE_CHECK([simple/igraph_layout_merge.c], [], [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Merging layouts 2 (igraph_i_layout_merge):])
+AT_KEYWORDS([layout merge dla])
+AT_COMPILE_CHECK([simple/igraph_layout_merge2.c], 
+		 [simple/igraph_layout_merge2.out])
+AT_CLEANUP
+
+AT_SETUP([Merging layouts 3 (igraph_i_layout_merge):])
+AT_KEYWORDS([layout merge dla])
+AT_COMPILE_CHECK([simple/igraph_layout_merge3.c])
+AT_CLEANUP
diff --git a/tests/matching.at b/tests/matching.at
new file mode 100644
index 0000000..f62c8a3
--- /dev/null
+++ b/tests/matching.at
@@ -0,0 +1,26 @@
+# Maximum bipartite and non-bipartite matchings
+
+# Test suite for the IGraph library.
+# Copyright (C) 2012  Tamas Nepusz <ntamas at gmail.com>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA 
+# 02110-1301 USA
+
+AT_BANNER([[Maximum matchings]])
+
+AT_SETUP([Maximum bipartite matching (igraph_maximum_bipartite_matching): ])
+AT_KEYWORDS([bipartite matching])
+AT_COMPILE_CHECK([simple/igraph_maximum_bipartite_matching.c])
+AT_CLEANUP
diff --git a/tests/microscopic.at b/tests/microscopic.at
new file mode 100644
index 0000000..1151373
--- /dev/null
+++ b/tests/microscopic.at
@@ -0,0 +1,41 @@
+# Check functions for microscopic updates at the agent level
+
+# Test suite for the IGraph library.
+# Copyright (C) 2011 Minh Van Nguyen <nguyenminh2 at gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+AT_BANNER([[Microscopic updates]])
+
+AT_SETUP([Deterministic optimal imitation:])
+AT_KEYWORDS([deterministic imitation strategy])
+AT_COMPILE_CHECK([simple/igraph_deterministic_optimal_imitation.c])
+AT_CLEANUP
+
+AT_SETUP([Stochastic imitation via uniform selection:])
+AT_KEYWORDS([stochastic imitation strategy uniform selection])
+AT_COMPILE_CHECK([simple/igraph_stochastic_imitation.c])
+AT_CLEANUP
+
+AT_SETUP([Stochastic imitation via roulette selection:])
+AT_KEYWORDS([stochastic imitation strategy roulette wheel])
+AT_COMPILE_CHECK([simple/igraph_roulette_wheel_imitation.c])
+AT_CLEANUP
+
+AT_SETUP([Moran process:])
+AT_KEYWORDS([Moran process haploid reproduction])
+AT_COMPILE_CHECK([simple/igraph_moran_process.c])
+AT_CLEANUP
diff --git a/tests/motifs.at b/tests/motifs.at
new file mode 100644
index 0000000..d809944
--- /dev/null
+++ b/tests/motifs.at
@@ -0,0 +1,27 @@
+# Check functions for motif detectors
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Motifs]])
+
+AT_SETUP([RAND-ESU algorithm (igraph_motifs_randesu)])
+AT_KEYWORDS([motif RAND-ESU])
+AT_COMPILE_CHECK([simple/igraph_motifs_randesu.c], [simple/igraph_motifs_randesu.out])
+AT_CLEANUP
diff --git a/tests/mt.at b/tests/mt.at
new file mode 100644
index 0000000..050974a
--- /dev/null
+++ b/tests/mt.at
@@ -0,0 +1,33 @@
+# Thread-safety tests
+
+# Test suite for the 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
+
+AT_BANNER([[Thread-safety tests]])
+
+AT_SETUP([Simple error handling test :])
+AT_KEYWORDS([thread-safe])
+AT_COMPILE_CHECK([simple/tls1.c], [], [], [], [-lpthread])
+AT_CLEANUP
+
+AT_SETUP([Thread-safe ARPACK:])
+AT_KEYWORDS([thread-safe ARPACK])
+AT_COMPILE_CHECK([simple/tls2.c], [simple/tls2.out], [], [internal], 
+                 [-lpthread])
+AT_CLEANUP
diff --git a/tests/operators.at b/tests/operators.at
new file mode 100644
index 0000000..93c8ae0
--- /dev/null
+++ b/tests/operators.at
@@ -0,0 +1,65 @@
+# Check functions for graph operators
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Graphs operators]])
+
+AT_SETUP([Disjoint union (igraph_disjoint_union, igraph_dosjoint_union_many):])
+AT_KEYWORDS([igraph_disjoint_union, igraph_disjoint_union_many, 
+	disjoint_union, union])
+AT_COMPILE_CHECK([simple/igraph_disjoint_union.c], 
+	[simple/igraph_disjoint_union.out])
+AT_CLEANUP
+
+AT_SETUP([Union (igraph_union, igraph_union_many):])
+AT_KEYWORDS([igraph_union, igraph_union_many, union])
+AT_COMPILE_CHECK([simple/igraph_union.c], 
+	[simple/igraph_union.out])
+AT_CLEANUP
+
+AT_SETUP([Intersection (igraph_intersection, igraph_intersection_many):])
+AT_KEYWORDS([igraph_intersection, igraph_intersection_many, intersection])
+AT_COMPILE_CHECK([simple/igraph_intersection.c], 
+	[simple/igraph_intersection.out])
+AT_CLEANUP
+
+AT_SETUP([Intersection 2 (igraph_intersection, igraph_intersection_many):])
+AT_KEYWORDS([igraph_intersection, igraph_intersection_many, intersection])
+AT_COMPILE_CHECK([simple/igraph_intersection2.c],
+	[simple/igraph_intersection2.out])
+AT_CLEANUP
+
+AT_SETUP([Difference (igraph_difference):])
+AT_KEYWORDS([igraph_difference, difference])
+AT_COMPILE_CHECK([simple/igraph_difference.c], 
+	[simple/igraph_difference.out])
+AT_CLEANUP
+
+AT_SETUP([Complementer (igraph_complementer):])
+AT_KEYWORDS([igraph_complementer, complementer])
+AT_COMPILE_CHECK([simple/igraph_complementer.c], 
+	[simple/igraph_complementer.out])
+AT_CLEANUP
+
+AT_SETUP([Composition (igraph_compose):])
+AT_KEYWORDS([igraph_composition, composition, compose])
+AT_COMPILE_CHECK([simple/igraph_compose.c], 
+	[simple/igraph_compose.out])
+AT_CLEANUP
diff --git a/tests/other.at b/tests/other.at
new file mode 100644
index 0000000..3345f44
--- /dev/null
+++ b/tests/other.at
@@ -0,0 +1,32 @@
+# Check functions for other miscellaneous functions
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Miscellaneous functions]])
+
+AT_SETUP([Convex hull calculation (igraph_convex_hull):])
+AT_KEYWORDS([igraph_convex_hull other])
+AT_COMPILE_CHECK([simple/igraph_convex_hull.c], [simple/igraph_convex_hull.out])
+AT_CLEANUP
+
+AT_SETUP([Fitting power-law distributions (igraph_power_law_fit):])
+AT_KEYWORDS([igraph_power_law_fit other power law fitting])
+AT_COMPILE_CHECK([simple/igraph_power_law_fit.c], [simple/igraph_power_law_fit.out])
+AT_CLEANUP
diff --git a/tests/package.m4 b/tests/package.m4
new file mode 100644
index 0000000..7347770
--- /dev/null
+++ b/tests/package.m4
@@ -0,0 +1,6 @@
+# Signature of the current package.
+m4_define([AT_PACKAGE_NAME],      [igraph])
+m4_define([AT_PACKAGE_TARNAME],   [igraph])
+m4_define([AT_PACKAGE_VERSION],   [0.7.1])
+m4_define([AT_PACKAGE_STRING],    [igraph 0.7.1])
+m4_define([AT_PACKAGE_BUGREPORT], [csardi.gabor at gmail.com])
diff --git a/tests/qsort.at b/tests/qsort.at
new file mode 100644
index 0000000..57ddadc
--- /dev/null
+++ b/tests/qsort.at
@@ -0,0 +1,32 @@
+# qsort test
+
+# Test suite for the IGraph library.
+# Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+# 334 Harvard st, 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
+
+AT_BANNER([[Quick sort]])
+
+AT_SETUP([Regular qsort (igraph_qsort):])
+AT_KEYWORDS([qsort quick sort igraph_qsort])
+AT_COMPILE_CHECK([simple/igraph_qsort.c], [simple/igraph_qsort.out])
+AT_CLEANUP
+
+AT_SETUP([qsort with extra argument (igraph_qsort_r):])
+AT_KEYWORDS([qsort quick sort igraph_qsort_r])
+AT_COMPILE_CHECK([simple/igraph_qsort_r.c], [simple/igraph_qsort_r.out])
+AT_CLEANUP
diff --git a/tests/random.at b/tests/random.at
new file mode 100644
index 0000000..c4bf997
--- /dev/null
+++ b/tests/random.at
@@ -0,0 +1,48 @@
+# Check functions for other miscellaneous functions
+
+# Test suite for the IGraph library.
+# Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+# 334 Harvard st, 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
+
+AT_BANNER([Random number generators])
+
+AT_SETUP([Random seed:])
+AT_KEYWORDS([RNG seed random])
+AT_COMPILE_CHECK([simple/random_seed.c])
+AT_CLEANUP
+
+AT_SETUP([MT19937 RNG on 64 bit machines:])
+AT_KEYWORDS([RNG MT19937])
+AT_COMPILE_CHECK([simple/mt.c])
+AT_CLEANUP
+
+AT_SETUP([Exponentially distributed random numbers:])
+AT_KEYWORDS([exponential random numbers])
+AT_COMPILE_CHECK([simple/igraph_rng_get_exp.c], 
+		 [simple/igraph_rng_get_exp.out])
+AT_CLEANUP
+
+AT_SETUP([Random sampling from consecutive sequence:])
+AT_KEYWORDS([random sampling])
+AT_COMPILE_CHECK([simple/igraph_random_sample.c])
+AT_CLEANUP
+
+AT_SETUP([Fisher-Yates shuffle:])
+AT_KEYWORDS([Fisher-Yates shuffle random permutation])
+AT_COMPILE_CHECK([simple/igraph_fisher_yates_shuffle.c])
+AT_CLEANUP
diff --git a/tests/scg.at b/tests/scg.at
new file mode 100644
index 0000000..08888e3
--- /dev/null
+++ b/tests/scg.at
@@ -0,0 +1,79 @@
+# Spectral coarse graining
+
+# Test suite for the 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
+
+AT_BANNER([[Spectral coarse graining]])
+
+AT_SETUP([Solving the SCG problem (igraph_scg_grouping) :])
+AT_KEYWORDS([SCG spectral coarse graining grouping])
+AT_COMPILE_CHECK([simple/igraph_scg_grouping.c], 
+		 [simple/igraph_scg_grouping.out])
+AT_CLEANUP
+
+AT_SETUP([Solving the SCG problem, adjacency matrix (igraph_scg_grouping) :])
+AT_KEYWORDS([SCG spectral coarse graining grouping adjacency])
+AT_COMPILE_CHECK([simple/igraph_scg_grouping2.c], 
+		 [simple/igraph_scg_grouping2.out])
+AT_CLEANUP
+
+AT_SETUP([Solving the SCG problem, stochastic matrix (igraph_scg_grouping) :])
+AT_KEYWORDS([SCG spectral coarse graining grouping stochastic])
+AT_COMPILE_CHECK([simple/igraph_scg_grouping3.c], 
+		 [simple/igraph_scg_grouping3.out])
+AT_CLEANUP
+
+AT_SETUP([Solving the SCG problem, laplacian matrix (igraph_scg_grouping) :])
+AT_KEYWORDS([SCG spectral coarse graining grouping laplacian])
+AT_COMPILE_CHECK([simple/igraph_scg_grouping4.c], 
+		 [simple/igraph_scg_grouping4.out])
+AT_CLEANUP
+
+AT_SETUP([SCG semi-projectors, symmetric (igraph_scg_semiprojectors) :])
+AT_KEYWORDS([SCG spectral coarse graining semi-projectors adjancency])
+AT_COMPILE_CHECK([simple/igraph_scg_semiprojectors.c],
+		 [simple/igraph_scg_semiprojectors.out])
+AT_CLEANUP
+
+AT_SETUP([SCG semi-projectors, stochastic (igraph_scg_semiprojectors) :])
+AT_KEYWORDS([SCG spectral coarse graining semi-projectors stochastic])
+AT_COMPILE_CHECK([simple/igraph_scg_semiprojectors2.c],
+		 [simple/igraph_scg_semiprojectors2.out])
+AT_CLEANUP
+
+AT_SETUP([SCG semi-projectors, laplacian (igraph_scg_semiprojectors) :])
+AT_KEYWORDS([SCG spectral coarse graining semi-projectors laplacian])
+AT_COMPILE_CHECK([simple/igraph_scg_semiprojectors3.c],
+		 [simple/igraph_scg_semiprojectors3.out])
+AT_CLEANUP
+
+AT_SETUP([SCG of a graph, adjacency matrix (igraph_scg) :])
+AT_KEYWORDS([SCG spectral coarse graining])
+AT_COMPILE_CHECK([simple/scg.c], [simple/scg.out])
+AT_CLEANUP
+
+AT_SETUP([SCG of a graph, stochastic matrix (igraph_scg) :])
+AT_KEYWORDS([SCG spectral coarse graining])
+AT_COMPILE_CHECK([simple/scg2.c], [simple/scg2.out])
+AT_CLEANUP
+
+AT_SETUP([SCG of a graph, laplacian matrix (igraph_scg) :])
+AT_KEYWORDS([SCG spectral coarse graining])
+AT_COMPILE_CHECK([simple/scg3.c], [simple/scg3.out])
+AT_CLEANUP
diff --git a/tests/separators.at b/tests/separators.at
new file mode 100644
index 0000000..7c01a60
--- /dev/null
+++ b/tests/separators.at
@@ -0,0 +1,53 @@
+# Minimal separators
+
+# Test suite for the 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
+
+AT_BANNER([[Minimal separators]])
+
+AT_SETUP([Decision problem (igraph_is_separator): ])
+AT_KEYWORDS([vertex separator])
+AT_COMPILE_CHECK([simple/igraph_is_separator.c])
+AT_CLEANUP
+
+AT_SETUP([Decision problem, minimal separator (igraph_is_minimal separator): ])
+AT_KEYWORDS([minimal vertex separator])
+AT_COMPILE_CHECK([simple/igraph_is_minimal_separator.c])
+AT_CLEANUP
+
+AT_SETUP([Minimal separators (igraph_all_minimal_ab_separators): ])
+AT_KEYWORDS([minimal separator])
+AT_COMPILE_CHECK([simple/igraph_minimal_separators.c])
+AT_CLEANUP
+
+AT_SETUP([Minimal separators, bug 1033045 (igraph_all_minimal_st_separators): ])
+AT_KEYWORDS([minimal separator])
+AT_COMPILE_CHECK([simple/bug-1033045.c], [simple/bug-1033045.out])
+AT_CLEANUP
+
+AT_SETUP([Minimum size separators (igraph_minimum_size_separators): ])
+AT_KEYWORDS([minimum size separators])
+AT_COMPILE_CHECK([simple/igraph_minimum_size_separators.c],
+                 [simple/igraph_minimum_size_separators.out])
+AT_CLEANUP
+
+AT_SETUP([Cohesive blocking (igraph_cohesive_blocks): ])
+AT_KEYWORDS([structurally cohesive blocks])
+AT_COMPILE_CHECK([simple/cohesive_blocks.c], [simple/cohesive_blocks.out])
+AT_CLEANUP
diff --git a/tests/structural_properties.at b/tests/structural_properties.at
new file mode 100644
index 0000000..8a87546
--- /dev/null
+++ b/tests/structural_properties.at
@@ -0,0 +1,213 @@
+# Check functions calculating structural properties
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Structural properties]])
+
+AT_SETUP([Two vertices connected by an edge:])
+AT_KEYWORDS([igraph_are_connected])
+AT_COMPILE_CHECK([simple/igraph_are_connected.c])
+AT_CLEANUP
+
+AT_SETUP([Density of a graph (igraph_density):])
+AT_KEYWORDS([igraph_density density])
+AT_COMPILE_CHECK([simple/igraph_density.c], [simple/igraph_density.out])
+AT_CLEANUP
+
+AT_SETUP([Diameter of a graph (igraph_diameter):])
+AT_KEYWORDS([igraph_diameter])
+AT_COMPILE_CHECK([simple/igraph_diameter.c], [simple/igraph_diameter.out])
+AT_CLEANUP
+
+AT_SETUP([Average geodesic length (igraph_average_path_length): ])
+AT_KEYWORDS([igraph_average_path_length])
+AT_COMPILE_CHECK([simple/igraph_average_path_length.c])
+AT_CLEANUP
+
+AT_SETUP([Google PageRank (igraph_pagerank): ])
+AT_KEYWORDS([igraph_pagerank])
+AT_COMPILE_CHECK([simple/igraph_pagerank.c], [simple/igraph_pagerank.out])
+AT_CLEANUP
+
+AT_SETUP([Random rewiring (igraph_rewire): ])
+AT_KEYWORDS([igraph_rewire])
+AT_COMPILE_CHECK([simple/igraph_rewire.c], [simple/igraph_rewire.out])
+AT_CLEANUP
+
+AT_SETUP([Get the shortest paths (igraph_get_shortest_paths): ])
+AT_KEYWORDS([igraph_get_shortest_paths shortest paths geodesic])
+AT_COMPILE_CHECK([simple/igraph_get_shortest_paths.c], 
+		 [simple/igraph_get_shortest_paths.out])
+AT_CLEANUP
+
+AT_SETUP([Get the shortest paths #2 (igraph_get_shortest_paths): ])
+AT_KEYWORDS([igraph_get_shortest_paths shortest paths geodesic])
+AT_COMPILE_CHECK([simple/igraph_get_shortest_paths2.c], 
+		 [simple/igraph_get_shortest_paths2.out])
+AT_CLEANUP
+
+AT_SETUP([Weighted shortest paths (Dijkstra): ])
+AT_KEYWORDS([igraph_shortest_paths_dijkstra Dijkstra shortest paths geodesic])
+AT_COMPILE_CHECK([simple/dijkstra.c], [simple/dijkstra.out])
+AT_CLEANUP
+
+AT_SETUP([Weighted shortest paths (Bellman-Ford): ])
+AT_KEYWORDS([igraph_shortest_paths_bellman_ford Bellman-Ford shortest paths geodesic])
+AT_COMPILE_CHECK([simple/bellman_ford.c], [simple/bellman_ford.out])
+AT_CLEANUP
+
+AT_SETUP([Get the weighted shortest paths (Dijkstra): ])
+AT_KEYWORDS([igraph_get_shortest_paths_dijkstra Dijkstra shortest paths geodesic])
+AT_COMPILE_CHECK([simple/igraph_get_shortest_paths_dijkstra.c],
+         [simple/igraph_get_shortest_paths_dijkstra.out])
+AT_CLEANUP
+
+AT_SETUP([Get all weighted shortest paths (Dijkstra): ])
+AT_KEYWORDS([igraph_get_all_shortest_paths_dijkstra Dijkstra shortest paths geodesic])
+AT_COMPILE_CHECK([simple/igraph_get_all_shortest_paths_dijkstra.c],
+         [simple/igraph_get_all_shortest_paths_dijkstra.out])
+AT_CLEANUP
+
+AT_SETUP([Shortest path wrappers for single target node: ])
+AT_KEYWORDS([igraph_get_shortest_path igraph_get_shortest_path_dijkstra])
+AT_COMPILE_CHECK([simple/single_target_shortest_path.c], 
+                 [simple/single_target_shortest_path.out])
+AT_CLEANUP
+
+AT_SETUP([Betweenness (igraph_betweenness): ])
+AT_KEYWORDS([igraph_betweenness betweenness])
+AT_COMPILE_CHECK([simple/igraph_betweenness.c])
+AT_CLEANUP
+
+AT_SETUP([Betweenness, big integers (igraph_betweenness): ])
+AT_KEYWORDS([igraph_betweenness betweenness arbitrarily large integers biguint bigint])
+AT_COMPILE_CHECK([simple/biguint_betweenness.c])
+AT_CLEANUP
+
+AT_SETUP([Edge betweenness (igraph_edge_betweenness): ])
+AT_KEYWORDS([igraph_edge_betweenness betwenness])
+AT_COMPILE_CHECK([simple/igraph_edge_betweenness.c], 
+	         [simple/igraph_edge_betweenness.out])
+AT_CLEANUP
+
+AT_SETUP([Transitivity (igraph_transitivity): ])
+AT_KEYWORDS([igraph_transitivity transitivity igraph_transitivity_undirected])
+AT_COMPILE_CHECK([simple/igraph_transitivity.c])
+AT_CLEANUP
+
+AT_SETUP([Local transitivity (igraph_local_transitivity): ])
+AT_KEYWORDS([transitivity igraph_transitivity_local_undirected])
+AT_COMPILE_CHECK([simple/igraph_local_transitivity.c])
+AT_CLEANUP
+
+AT_SETUP([Reciprocity (igraph_reciprocity): ])
+AT_KEYWORDS([igraph_reciprocity reciprocity])
+AT_COMPILE_CHECK([simple/igraph_reciprocity.c])
+AT_CLEANUP
+
+AT_SETUP([Minimum spanning tree (igraph_minimum_spanning_tree_*): ])
+AT_KEYWORDS([igraph_minimum_spanning_tree_prim Prim minimum spanning tree])
+AT_COMPILE_CHECK([simple/igraph_minimum_spanning_tree.c],
+	         [simple/igraph_minimum_spanning_tree.out])
+AT_CLEANUP
+
+AT_SETUP([Cocitation and bibcoupling (igraph_cocitation,igraph_bibcoupling):])
+AT_KEYWORDS([cocitation bibliographic coupling])
+AT_COMPILE_CHECK([simple/igraph_cocitation.c], [simple/igraph_cocitation.out])
+AT_CLEANUP
+
+AT_SETUP([Similarity coefficients (igraph_similarity_*):])
+AT_KEYWORDS([similarity jaccard dice])
+AT_COMPILE_CHECK([simple/igraph_similarity.c], [simple/igraph_similarity.out])
+AT_CLEANUP
+
+AT_SETUP([Simplification of non-simple graphs (igraph_simplify): ])
+AT_KEYWORDS([simplify multiple edge loop edges non-simple graphs simple graphs])
+AT_COMPILE_CHECK([simple/igraph_simplify.c], [simple/igraph_simplify.out])
+AT_CLEANUP
+
+AT_SETUP([Topological sorting (igraph_topological_sorting, igraph_is_dag): ])
+AT_KEYWORDS([topological sorting directed acyclic graphs])
+AT_COMPILE_CHECK([simple/igraph_topological_sorting.c], [simple/igraph_topological_sorting.out])
+AT_CLEANUP
+
+AT_SETUP([Feedback arc sets, Eades heuristics (igraph_feedback_arc_set): ])
+AT_KEYWORDS([feedback arc set directed graphs])
+AT_COMPILE_CHECK([simple/igraph_feedback_arc_set.c], [simple/igraph_feedback_arc_set.out])
+AT_CLEANUP
+
+AT_SETUP([Feedback arc sets, integer programming (igraph_feedback_arc_set): ])
+AT_KEYWORDS([feedback arc set directed graphs])
+AT_COMPILE_CHECK([simple/igraph_feedback_arc_set_ip.c], [simple/igraph_feedback_arc_set_ip.out])
+AT_CLEANUP
+
+AT_SETUP([Loop edges test (igraph_is_loop): ])
+AT_KEYWORDS([loop edge igraph_is_loop])
+AT_COMPILE_CHECK([simple/igraph_is_loop.c], [simple/igraph_is_loop.out])
+AT_CLEANUP
+
+AT_SETUP([Multiple edges test (igraph_is_multiple): ])
+AT_KEYWORDS([multiple edge parallel edge igraph_is_multiple])
+AT_COMPILE_CHECK([simple/igraph_is_multiple.c], [simple/igraph_is_multiple.out])
+AT_CLEANUP
+
+AT_SETUP([Multiple edges test (igraph_has_multiple): ])
+AT_KEYWORDS([multiple edge parallel edge igraph_has_multiple])
+AT_COMPILE_CHECK([simple/igraph_has_multiple.c])
+AT_CLEANUP
+
+AT_SETUP([Girth (igraph_girth): ])
+AT_KEYWORDS([girth igraph_girth])
+AT_COMPILE_CHECK([simple/igraph_girth.c])
+AT_CLEANUP
+
+AT_SETUP([Convergence degree (igraph_convergence_degree): ])
+AT_KEYWORDS([edge convergence degree igraph_convergence_degree])
+AT_COMPILE_CHECK([simple/igraph_convergence_degree.c], [simple/igraph_convergence_degree.out])
+AT_CLEANUP
+
+AT_SETUP([Assortativity coefficient (igraph_assortativity): ])
+AT_KEYWORDS([assortativity mixing igraph_assortativity])
+AT_COMPILE_CHECK([simple/assortativity.c], [simple/assortativity.out], 
+                 [simple/{karate,celegansneural}.gml])
+AT_CLEANUP
+
+AT_SETUP([Average nearest neighbor degree (igraph_avg_nearest_neighbor_degree): ])
+AT_KEYWORDS([nearest neighbor degree degree correlations])
+AT_COMPILE_CHECK([simple/igraph_knn.c])
+AT_CLEANUP
+
+AT_SETUP([Transitive closure of a DAG (igraph_transitive_closure_dag): ])
+AT_KEYWORDS([transitive closure DAG])
+AT_COMPILE_CHECK([simple/igraph_transitive_closure_dag.c],
+                 [simple/igraph_transitive_closure_dag.out])
+AT_CLEANUP
+
+AT_SETUP([Eccentricity (igraph_eccentricity): ])
+AT_KEYWORDS([eccentricity])
+AT_COMPILE_CHECK([simple/igraph_eccentricity.c], 
+                 [simple/igraph_eccentricity.out])
+AT_CLEANUP
+
+AT_SETUP([Radius (igraph_radius): ])
+AT_KEYWORDS([radius eccentricity])
+AT_COMPILE_CHECK([simple/igraph_radius.c])
+AT_CLEANUP
+
diff --git a/tests/structure_generators.at b/tests/structure_generators.at
new file mode 100644
index 0000000..a9a4ab0
--- /dev/null
+++ b/tests/structure_generators.at
@@ -0,0 +1,122 @@
+# Check graph generators
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Structure generators]])
+
+AT_SETUP([Simple graph creation (igraph_create): ])
+AT_KEYWORDS([igraph_create])
+AT_COMPILE_CHECK([simple/igraph_create.c])
+AT_CLEANUP
+
+AT_SETUP([Barabasi-Albert model (igraph_barabasi_game):])
+AT_KEYWORDS([barabasi barabasi-albert igraph_barabasi_game])
+AT_COMPILE_CHECK([simple/igraph_barabasi_game.c])
+AT_CLEANUP
+
+AT_SETUP([More Barabasi-Albert model (igraph_barabasi_game):])
+AT_KEYWORDS([barabasi barabasi-albert igraph_barabasi_game])
+AT_COMPILE_CHECK([simple/igraph_barabasi_game2.c])
+AT_CLEANUP
+
+AT_SETUP([Erdos-Renyi model (igraph_erdos_renyi_game):])
+AT_KEYWORDS([erdos renyi erdos-renyi igraph_erdos_renyi_game])
+AT_COMPILE_CHECK([simple/igraph_erdos_renyi_game.c])
+AT_CLEANUP
+
+AT_SETUP([Degree sequence (igraph_degree_sequence_game):])
+AT_KEYWORDS([degree sequence igraph_degree_sequence_game])
+AT_COMPILE_CHECK([simple/igraph_degree_sequence_game.c], [simple/igraph_degree_sequence_game.out])
+AT_CLEANUP
+
+AT_SETUP([k-regular graphs (igraph_k_regular_game):])
+AT_KEYWORDS([regular k-regular igraph_k_regular_game])
+AT_COMPILE_CHECK([simple/igraph_k_regular_game.c], [simple/igraph_k_regular_game.out])
+AT_CLEANUP
+
+AT_SETUP([Growing random (igraph_growing_random_game):])
+AT_KEYWORDS([growing random game igraph_growing_random_game])
+AT_COMPILE_CHECK([simple/igraph_growing_random_game.c])
+AT_CLEANUP
+
+AT_SETUP([Preference model (igraph_preference_game):])
+AT_KEYWORDS([preference game igraph_preference_game igraph_asymmetric_preference_game])
+AT_COMPILE_CHECK([simple/igraph_preference_game.c])
+AT_CLEANUP
+
+AT_SETUP([From adjacency matrix (igraph_adjacency):])
+AT_KEYWORDS([adjacency matrix igraph_adjacency])
+AT_COMPILE_CHECK([simple/igraph_adjacency.c])
+AT_CLEANUP
+
+AT_SETUP([From weighted adjacency matrix (igraph_weighted_adjacency):])
+AT_KEYWORDS([weighted adjacency matrix igraph_weighted_adjacency])
+AT_COMPILE_CHECK([simple/igraph_weighted_adjacency.c], [simple/igraph_weighted_adjacency.out])
+AT_CLEANUP
+
+AT_SETUP([Star graph (igraph_star):])
+AT_KEYWORDS([star igraph_star])
+AT_COMPILE_CHECK([simple/igraph_star.c])
+AT_CLEANUP
+
+AT_SETUP([Lattice graph (igraph_lattice):])
+AT_KEYWORDS([lattice igraph_lattice])
+AT_COMPILE_CHECK([simple/igraph_lattice.c])
+AT_CLEANUP
+
+AT_SETUP([Ring graph (igraph_ring):])
+AT_KEYWORDS([ring igraph_ring])
+AT_COMPILE_CHECK([simple/igraph_ring.c])
+AT_CLEANUP
+
+AT_SETUP([Tree graph (igraph_tree):])
+AT_KEYWORDS([tree igraph_tree])
+AT_COMPILE_CHECK([simple/igraph_tree.c])
+AT_CLEANUP
+
+AT_SETUP([Full graph (igraph_full):])
+AT_KEYWORDS([full igraph_full])
+AT_COMPILE_CHECK([simple/igraph_full.c])
+AT_CLEANUP
+
+AT_SETUP([Graph atlas (igraph_atlas):])
+AT_KEYWORDS([atlas igraph_atlas])
+AT_COMPILE_CHECK([simple/igraph_atlas.c], [simple/igraph_atlas.out])
+AT_CLEANUP
+
+AT_SETUP([Small graph (igraph_small):])
+AT_KEYWORDS([graph constructor small igraph_small])
+AT_COMPILE_CHECK([simple/igraph_small.c], [simple/igraph_small.out])
+AT_CLEANUP
+
+AT_SETUP([Geomeric random graphs (igraph_grg_game):])
+AT_KEYWORDS([graph GRG grg geometric random graph igraph_grg_game])
+AT_COMPILE_CHECK([simple/igraph_grg_game.c])
+AT_CLEANUP
+
+AT_SETUP([Graphs in LCF notation (igraph_lcf{,_vector}):])
+AT_KEYWORDS([LCF graph constructor])
+AT_COMPILE_CHECK([simple/igraph_lcf.c])
+AT_CLEANUP
+
+AT_SETUP([Watts-Strogatz graphs (igraph_watts_strogatz_game):])
+AT_KEYWORDS([small world small-world Watts Strogratz])
+AT_COMPILE_CHECK([simple/watts_strogatz_game.c])
+AT_CLEANUP
diff --git a/tests/testsuite b/tests/testsuite
new file mode 100755
index 0000000..2d0700a
--- /dev/null
+++ b/tests/testsuite
@@ -0,0 +1,17988 @@
+#! /bin/sh
+# Generated from ../tests/testsuite.at by GNU Autoconf 2.69.
+#
+# Copyright (C) 2009-2012 Free Software Foundation, Inc.
+#
+# This test suite is free software; the Free Software Foundation gives
+# unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf at gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# How were we run?
+at_cli_args="$@"
+
+
+# Not all shells have the 'times' builtin; the subshell is needed to make
+# sure we discard the 'times: not found' message from the shell.
+at_times_p=false
+(times) >/dev/null 2>&1 && at_times_p=:
+
+# CLI Arguments to pass to the debugging scripts.
+at_debug_args=
+# -e sets to true
+at_errexit_p=false
+# Shall we be verbose?  ':' means no, empty means yes.
+at_verbose=:
+at_quiet=
+# Running several jobs in parallel, 0 means as many as test groups.
+at_jobs=1
+at_traceon=:
+at_trace_echo=:
+at_check_filter_trace=:
+
+# Shall we keep the debug scripts?  Must be `:' when the suite is
+# run by a debug script, so that the script doesn't remove itself.
+at_debug_p=false
+# Display help message?
+at_help_p=false
+# Display the version message?
+at_version_p=false
+# List test groups?
+at_list_p=false
+# --clean
+at_clean=false
+# Test groups to run
+at_groups=
+# Whether to rerun failed tests.
+at_recheck=
+# Whether a write failure occurred
+at_write_fail=0
+
+# The directory we run the suite in.  Default to . if no -C option.
+at_dir=`pwd`
+# An absolute reference to this testsuite script.
+case $as_myself in
+  [\\/]* | ?:[\\/]* ) at_myself=$as_myself ;;
+  * ) at_myself=$at_dir/$as_myself ;;
+esac
+# Whether -C is in effect.
+at_change_dir=false
+
+# Whether to enable colored test results.
+at_color=no
+# List of the tested programs.
+at_tested=''
+# As many question marks as there are digits in the last test group number.
+# Used to normalize the test group numbers so that `ls' lists them in
+# numerical order.
+at_format='???'
+# Description of all the test groups.
+at_help_all="1;version.at:26;Simple version query (igraph_version): ;version igraph_version;
+2;types.at:24;Vector (vector_t): ;vector vector_t;
+3;types.at:29;Vector (more) (vector_t): ;vector vector_t;
+4;types.at:34;Vector (even more) (vector_t): ;vector vector_t;
+5;types.at:39;Matrix (matrix_t): ;matrix matrix_t;
+6;types.at:44;Matrix (more) (matrix_t): ;matrix matrix_t;
+7;types.at:49;Matrix (even more) (matrix_t): ;matrix matrix_t;
+8;types.at:54;Double ended queue (dqueue_t): ;dqueue double queue dqueue_t;
+9;types.at:59;Vector of pointers (vector_ptr_t): ;vector pointers vector_ptr_t;
+10;types.at:64;Stack (stack_t): ;stack stack_t;
+11;types.at:69;Heap (heap_t): ;heap heap_t;
+12;types.at:74;Indexed heap (indheap_t): ;indexed heap indheap_t;
+13;types.at:79;Doubly indexed heap (d_indheap_t): ;doubly indexed heap d_indheap_t;
+14;types.at:84;String vector (igraph_strvector_t): ;string vector igraph_strvector_t;
+15;types.at:89;Trie (igraph_trie_t): ;trie igraph_trie_t;
+16;types.at:95;Partial Sum-Tree (igraph_psumtree_t): ;partial sumtree igraph_psumtree_t;
+17;types.at:100;Three dimensional array (igraph_array3_t): ;array array3 three dimensional;
+18;types.at:105;Hash table (string->string) (igraph_hashtable_t): ;igraph_hashtable_t hash table;
+19;types.at:111;Special heap for minimum cuts (igraph_i_cutheap_t): ;heap minimum cut;
+20;types.at:117;Set (igraph_set_t): ;set igraph_set_t;
+21;types.at:123;2-way heap (igraph_2wheap_t): ;heap two-way 2-way igraph_2wheap_t;
+22;types.at:128;Sparse matrix (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+23;types.at:133;Sparse matrix, multiplications (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+24;types.at:139;Sparse matrix, indexing (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+25;types.at:145;Sparse matrix, solvers (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+26;types.at:151;Sparse matrix, ARPACK eigensolver (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t arpack;
+27;types.at:156;Sparse matrix, conversion to dense (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+28;types.at:161;Sparse matrix, min & max (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+29;types.at:166;Sparse matrix, other operations (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t;
+30;types.at:171;Sparse matrix, multiplications with dense (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t sparse-dense dense-sparse;
+31;types.at:176;Sparse matrix, is symmetric? (igraph_sparsemat_t): ;sparse matrix igraph_sparsemat_t symmetric is_symmetric;
+32;types.at:181;Another sparse matrix (igraph_spmatrix_t): ;sparse matrix igraph_spmatrix_t;
+33;types.at:186;Arbitrarily big integers (igraph_biguint_t): ;bignum bigint big integer arbitrarily;
+34;types.at:191;Marked double ended queue (igraph_marked_queue_t): ;dqueue queue igraph_marked_queue_t;
+35;types.at:196;Complex numbers (igraph_complex_t): ;complex;
+36;basic.at:26;Creating an empty graph (igraph_empty): ;igraph_empty;
+37;basic.at:31;Copying a graph (igraph_copy): ;igraph_copy igraph_create;
+38;basic.at:36;Adding edges to a graph (igraph_add_edges): ;igraph_add_edges;
+39;basic.at:42;Adding vertices (igraph_add_vertices): ;igraph_add_vertices;
+40;basic.at:47;Deleting edges (igraph_delete_edges): ;igraph_delete_vertices;
+41;basic.at:52;Deleting vertices (igraph_delete_vertices): ;igraph_delete_vertices;
+42;basic.at:57;Neighbors (igraph_neighbors): ;igraph_neighbors;
+43;basic.at:62;Is the graph directed? (igraph_is_directed): ;igraph_is_directed;
+44;basic.at:67;Degree of the vertices (igraph_degree): ;igraph_degree;
+45;basic.at:72;Query edge ids (igraph_get_eid): ;igraph_get_eid edge id;
+46;basic.at:77;Query many edge ids (igraph_get_eids): ;igraph_get_eids edge id;
+47;iterators.at:24;Vertices in a vector (igraph_vs_vector): ;iterator vector igraph_vs_vector igraph_vs_vectorview;
+48;iterators.at:29;Non-adjacent vertices (igraph_vs_nonadj): ;iterator igraph_vs_nonadj;
+49;iterators.at:34;Sequence (igraph_vs_seq): ;iterator igraph_vs_seq seq sequence;
+50;iterators.at:49;Edges given by end points (igraph_es_pairs): ;iterator igraph_es_pairs;
+51;iterators.at:54;Edges in a path (igraph_es_path): ;iterator, igraph_es_path;
+52;structure_generators.at:24;Simple graph creation (igraph_create): ;igraph_create;
+53;structure_generators.at:29;Barabasi-Albert model (igraph_barabasi_game):;barabasi barabasi-albert igraph_barabasi_game;
+54;structure_generators.at:34;More Barabasi-Albert model (igraph_barabasi_game):;barabasi barabasi-albert igraph_barabasi_game;
+55;structure_generators.at:39;Erdos-Renyi model (igraph_erdos_renyi_game):;erdos renyi erdos-renyi igraph_erdos_renyi_game;
+56;structure_generators.at:44;Degree sequence (igraph_degree_sequence_game):;degree sequence igraph_degree_sequence_game;
+57;structure_generators.at:49;k-regular graphs (igraph_k_regular_game):;regular k-regular igraph_k_regular_game;
+58;structure_generators.at:54;Growing random (igraph_growing_random_game):;growing random game igraph_growing_random_game;
+59;structure_generators.at:59;Preference model (igraph_preference_game):;preference game igraph_preference_game igraph_asymmetric_preference_game;
+60;structure_generators.at:64;From adjacency matrix (igraph_adjacency):;adjacency matrix igraph_adjacency;
+61;structure_generators.at:69;From weighted adjacency matrix (igraph_weighted_adjacency):;weighted adjacency matrix igraph_weighted_adjacency;
+62;structure_generators.at:74;Star graph (igraph_star):;star igraph_star;
+63;structure_generators.at:79;Lattice graph (igraph_lattice):;lattice igraph_lattice;
+64;structure_generators.at:84;Ring graph (igraph_ring):;ring igraph_ring;
+65;structure_generators.at:89;Tree graph (igraph_tree):;tree igraph_tree;
+66;structure_generators.at:94;Full graph (igraph_full):;full igraph_full;
+67;structure_generators.at:99;Graph atlas (igraph_atlas):;atlas igraph_atlas;
+68;structure_generators.at:104;Small graph (igraph_small):;graph constructor small igraph_small;
+69;structure_generators.at:109;Geomeric random graphs (igraph_grg_game):;graph grg geometric random igraph_grg_game;
+70;structure_generators.at:114;Graphs in LCF notation (igraph_lcf{,_vector}):;lcf graph constructor;
+71;structure_generators.at:119;Watts-Strogatz graphs (igraph_watts_strogatz_game):;small world small-world watts strogratz;
+72;structural_properties.at:24;Two vertices connected by an edge:;igraph_are_connected;
+73;structural_properties.at:29;Density of a graph (igraph_density):;igraph_density density;
+74;structural_properties.at:34;Diameter of a graph (igraph_diameter):;igraph_diameter;
+75;structural_properties.at:39;Average geodesic length (igraph_average_path_length): ;igraph_average_path_length;
+76;structural_properties.at:44;Google PageRank (igraph_pagerank): ;igraph_pagerank;
+77;structural_properties.at:49;Random rewiring (igraph_rewire): ;igraph_rewire;
+78;structural_properties.at:54;Get the shortest paths (igraph_get_shortest_paths): ;igraph_get_shortest_paths shortest paths geodesic;
+79;structural_properties.at:60;Get the shortest paths #2 (igraph_get_shortest_paths): ;igraph_get_shortest_paths shortest paths geodesic;
+80;structural_properties.at:66;Weighted shortest paths (Dijkstra): ;igraph_shortest_paths_dijkstra dijkstra shortest paths geodesic;
+81;structural_properties.at:71;Weighted shortest paths (Bellman-Ford): ;igraph_shortest_paths_bellman_ford bellman-ford shortest paths geodesic;
+82;structural_properties.at:76;Get the weighted shortest paths (Dijkstra): ;igraph_get_shortest_paths_dijkstra dijkstra shortest paths geodesic;
+83;structural_properties.at:82;Get all weighted shortest paths (Dijkstra): ;igraph_get_all_shortest_paths_dijkstra dijkstra shortest paths geodesic;
+84;structural_properties.at:88;Shortest path wrappers for single target node: ;igraph_get_shortest_path igraph_get_shortest_path_dijkstra;
+85;structural_properties.at:94;Betweenness (igraph_betweenness): ;igraph_betweenness betweenness;
+86;structural_properties.at:99;Betweenness, big integers (igraph_betweenness): ;igraph_betweenness betweenness arbitrarily large integers biguint bigint;
+87;structural_properties.at:104;Edge betweenness (igraph_edge_betweenness): ;igraph_edge_betweenness betwenness;
+88;structural_properties.at:110;Transitivity (igraph_transitivity): ;igraph_transitivity transitivity igraph_transitivity_undirected;
+89;structural_properties.at:115;Local transitivity (igraph_local_transitivity): ;transitivity igraph_transitivity_local_undirected;
+90;structural_properties.at:120;Reciprocity (igraph_reciprocity): ;igraph_reciprocity reciprocity;
+91;structural_properties.at:125;Minimum spanning tree (igraph_minimum_spanning_tree_*): ;igraph_minimum_spanning_tree_prim prim minimum spanning tree;
+92;structural_properties.at:131;Cocitation and bibcoupling (igraph_cocitation,igraph_bibcoupling):;cocitation bibliographic coupling;
+93;structural_properties.at:136;Similarity coefficients (igraph_similarity_*):;similarity jaccard dice;
+94;structural_properties.at:141;Simplification of non-simple graphs (igraph_simplify): ;simplify multiple edge loop edges non-simple graphs simple;
+95;structural_properties.at:146;Topological sorting (igraph_topological_sorting, igraph_is_dag): ;topological sorting directed acyclic graphs;
+96;structural_properties.at:151;Feedback arc sets, Eades heuristics (igraph_feedback_arc_set): ;feedback arc set directed graphs;
+97;structural_properties.at:156;Feedback arc sets, integer programming (igraph_feedback_arc_set): ;feedback arc set directed graphs;
+98;structural_properties.at:161;Loop edges test (igraph_is_loop): ;loop edge igraph_is_loop;
+99;structural_properties.at:166;Multiple edges test (igraph_is_multiple): ;multiple edge parallel igraph_is_multiple;
+100;structural_properties.at:171;Multiple edges test (igraph_has_multiple): ;multiple edge parallel igraph_has_multiple;
+101;structural_properties.at:176;Girth (igraph_girth): ;girth igraph_girth;
+102;structural_properties.at:181;Convergence degree (igraph_convergence_degree): ;edge convergence degree igraph_convergence_degree;
+103;structural_properties.at:186;Assortativity coefficient (igraph_assortativity): ;assortativity mixing igraph_assortativity;
+104;structural_properties.at:192;Average nearest neighbor degree (igraph_avg_nearest_neighbor_degree): ;nearest neighbor degree correlations;
+105;structural_properties.at:197;Transitive closure of a DAG (igraph_transitive_closure_dag): ;transitive closure dag;
+106;structural_properties.at:203;Eccentricity (igraph_eccentricity): ;eccentricity;
+107;structural_properties.at:209;Radius (igraph_radius): ;radius eccentricity;
+108;components.at:24;Decompose a graph (igraph_decompose):;igraph_decompose decompose component;
+109;components.at:29;Biconnected components (igraph_biconnected_components):;igraph_biconnected_components biconnected component;
+110;layout.at:24;Grid layout (igraph_layout_grid, igraph_layout_grid_3d):;igraph_layout_grid igraph_layout_grid_3d grid layout;
+111;layout.at:29;Large Graph Layout (igraph_layout_lgl):;igraph_layout_lgl lgl;
+112;layout.at:34;Reingold-Tilford tree layout (igraph_layout_reingold_tilford):;reingold tilford tree layout igraph_layout_reingold_tilford;
+113;layout.at:40;Sugiyama layout (igraph_layout_sugiyama):;sugiyama layout igraph_layout_sugiyama;
+114;layout.at:45;Multidimensional scaling (igraph_layout_mds):;multidimensional scaling layout igraph_layout_mds;
+115;layout.at:50;Covering circle and sphere (igraph_i_layout_sphere_{2,3}d):;covering circle sphere layout;
+116;layout.at:55;Merging layouts (igraph_i_layout_merge):;layout merge dla;
+117;layout.at:60;Merging layouts 2 (igraph_i_layout_merge):;layout merge dla;
+118;layout.at:66;Merging layouts 3 (igraph_i_layout_merge):;layout merge dla;
+119;visitors.at:24;Internal breadth-first search (igraph_i_bfs):;igraph_i_bfs bfs breadth-first visitor;
+120;visitors.at:29;Breadth-first search (igraph_bfs):;igraph_bfs bfs breadth-first visitor;
+121;topology.at:24;The isomorphism class of a subgraph (igraph_isolass_subgraph);isomorph isomorphism class motif;
+122;topology.at:29;The VF2 isomorphism algorithm;isomorph isomorphic vf2;
+123;topology.at:34;VF algorithm with compatibility functions;isomorph isomorphic vf2 compatibility;
+124;topology.at:39;LAD subgraph isomorphism algorithm;isomorph isomorphic subgraph isomorphism lad;
+125;topology.at:45;Graphical degree sequences;degree sequence graphical;
+126;motifs.at:24;RAND-ESU algorithm (igraph_motifs_randesu);motif rand-esu;
+127;foreign.at:24;Reading Pajek (igraph_read_graph_pajek):;igraph_read_graph_pajek foreign pajek;
+128;foreign.at:29;GraphML (igraph_{read,write}_graph_graphml):;igraph_read_graph_graphml igraph_write_graph_graphml foreign graphml;
+129;foreign.at:35;Writing Pajek (igraph_write_graph_pajek):;igraph_write_graph_pajek foreign pajek;
+130;foreign.at:41;Pajek with number of edges present (igraph_read_graph_pajek):;igraph_read_graph_pajek pajek foreign;
+131;foreign.at:46;Pajek, bipartite (igraph_read_graph_pajek):;igraph_read_graph_pajek pajek foreign bipartite;
+132;foreign.at:52;Pajek, bipartite incidence matrix (igraph_read_graph_pajek):;igraph_read_graph_pajek pajek foreign bipartite incidence;
+133;foreign.at:58;Pajek, signed (igraph_read_graph_pajek):;igraph_read_graph_pajek pajek foreign signed;
+134;foreign.at:64;Pajek, writing bipartite graph (igraph_write_graph_pajek):;igraph_write_graph_pajek pajek foreign bipartite;
+135;foreign.at:69;Reading an LGL file (igraph_read_graph_lgl):;igraph_read_graph_lgl lgl foreign;
+136;foreign.at:76;Writing LGL (igraph_write_graph_lgl):;igraph_write_graph_lgl foreign lgl;
+137;foreign.at:81;Reading a graph from the graph database (igraph_read_graph_graphdb):;igraph_read_graph_graphdb foreign graphdb database isomorphism;
+138;foreign.at:88;Reading a GML file (igraph_read_graph_gml):;igraph_read_graph_gml foreign gml;
+139;foreign.at:93;Writing a DOT file (igraph_write_graph_dot):;igraph_write_graph_dot foreign dot graphviz;
+140;foreign.at:98;Different line endings:;igraph_read_graph_pajek igraph_write_graph_pajek foreign line ending lineending;
+141;foreign.at:105;UNICET DL format:;igraph_read_graph_dl dl ucinet;
+142;foreign.at:111;LEDA format:;igraph_write_graph_leda leda;
+143;other.at:24;Convex hull calculation (igraph_convex_hull):;igraph_convex_hull other;
+144;other.at:29;Fitting power-law distributions (igraph_power_law_fit):;igraph_power_law_fit other power law fitting;
+145;operators.at:24;Disjoint union (igraph_disjoint_union, igraph_dosjoint_union_many):;igraph_disjoint_union, igraph_disjoint_union_many, disjoint_union, union;
+146;operators.at:31;Union (igraph_union, igraph_union_many):;igraph_union, igraph_union_many, union;
+147;operators.at:37;Intersection (igraph_intersection, igraph_intersection_many):;igraph_intersection, igraph_intersection_many, intersection;
+148;operators.at:43;Intersection 2 (igraph_intersection, igraph_intersection_many):;igraph_intersection, igraph_intersection_many, intersection;
+149;operators.at:49;Difference (igraph_difference):;igraph_difference, difference;
+150;operators.at:55;Complementer (igraph_complementer):;igraph_complementer, complementer;
+151;operators.at:61;Composition (igraph_compose):;igraph_composition, composition, compose;
+152;conversion.at:24;Directed to undirected (igraph_to_undirected):;igraph_to_undirected directedness undirected directed;
+153;conversion.at:30;Graphs from adjacency list (igraph_adjlist):;igraph_adjlist adjacency list adjlist;
+154;conversion.at:35;Graph to Laplacian matrix (igraph_laplacian):;igraph_laplacian laplacian matrix;
+155;flow.at:24;Maximum flow value (igraph_maxflow_value): ;maximum flow maxflow minimum cut;
+156;flow.at:29;Maximum flow (igraph_maxflow): ;maximum flow maxflow minimum cut;
+157;flow.at:34;Minimum cut (igraph_mincut): ;minimum cut stoer-wagner;
+158;flow.at:39;Even-Tarjan reduction (igraph_even_tarjan_reduction): ;even tarjan reduction vertex cut separator;
+159;flow.at:44;Dominator tree of a flow graph (igraph_dominator_tree): ;dominator tree;
+160;flow.at:50;All s-t cuts of a graph (igraph_all_st_cuts): ;s-t cut;
+161;flow.at:56;All minimal s-t cuts of a graph (igraph_all_st_mincuts): ;minimal s-t cut;
+162;flow.at:62;Gomory-Hu tree (igraph_gomory_hu_tree): ;gomory-hu tree;
+163;community.at:24;Spinglass clustering (igraph_spinglass_community): ;spin glass spinglass community clustering;
+164;community.at:29;Walktrap community structure (igraph_walktrap_community): ;random walk community structure clustering walktrap;
+165;community.at:34;Edge betweenness community structure (igraph_community_edge_betweenness): ;community structure edge betweenness newman girvan;
+166;community.at:40;Modularity optimization (igraph_community_fastgreedy): ;community structure clauset newman moore modularity greedy;
+167;community.at:46;Leading eigenvector community structure (igraph_community_leading_eigenvector) :;community structure leading eigenvector newman;
+168;community.at:52;Weighted leading eigenvector community structure (igraph_community_leading_eigenvector) :;community structure leading eigenvector newman weighted;
+169;community.at:58;Leading eigenvector bug #1002140 test (igraph_community_leading_eigenvector) :;community structure leading eigenvector newman;
+170;community.at:64;Label propagation algorithm (igraph_community_label_propagation) :;community structure label propagation raghavan albert kumara;
+171;community.at:70;Multilevel community detection (igraph_community_multilevel) :;community structure multilevel blondel guillaume lambiotte lefebvre;
+172;community.at:76;Multilevel community detection, isolates (igraph_community_multilevel) :;community structure multilevel blondel guillaume lambiotte lefebvre;
+173;community.at:81;Modularity optimization, integer programming (igraph_community_optimal_modularity) :;community structure optimal modularity integer programming;
+174;community.at:86;Infomap community structure (igraph_community_infomap) :;community structure infomap rosvall bergstrom;
+175;cliques.at:26;Calculating cliques (igraph_cliques): ;igraph_cliques, igraph_maximal_cliques, igraph_clique_number;
+176;cliques.at:31;Additional test for maximal cliques (igraph_maximal_cliques):;igraph_maximal_cliques cliques maximal;
+177;cliques.at:37;More maximal cliques (igraph_maximal_cliques):;igraph_maximal_cliques cliques maximal;
+178;cliques.at:43;Maximal cliques 3 (igraph_maximal_cliques):;igraph_maximal_cliques cliques maximal;
+179;cliques.at:49;Maximal cliques for a subset (igraph_maximal_cliques):;igraph_maximal_cliques cliques maximal;
+180;cliques.at:55;Calculating independent vertex sets (igraph_independent_vertex_sets): ;igraph_independent_vertex_sets, igraph_maximal_independent_vertex_sets, igraph_independence_number;
+181;eigen.at:24;Symmetric matrix, LAPACK (igraph_eigen_matrix_symmetric):;eigenvalue lapack;
+182;eigen.at:30;Symmetric matrix, ARPACK (igraph_eigen_matrix_symmetric):;eigenvalue lapack;
+183;eigen.at:36;General matrix, LAPACK, LM, SM (igraph_eigen_matrix):;eigenvalue lapack;
+184;eigen.at:42;General matrix, LAPACK, LR, SR (igraph_eigen_matrix):;eigenvalue lapack;
+185;eigen.at:48;General matrix, LAPACK, LI, SI (igraph_eigen_matrix):;eigenvalue lapack;
+186;eigen.at:54;General matrix, LAPACK, SELECT (igraph_eigen_matrix):;eigenvalue lapack;
+187;attributes.at:24;Reading a Pajek file with attributes:;pajek attributes;
+188;attributes.at:30;Writing an attributed graph in GML and GraphML:;gml graphml attributes;
+189;attributes.at:35;Combining numeric attributes:;attributes combination combining;
+190;attributes.at:40;Combining string attributes:;attributes combination combining;
+191;arpack.at:24;Basic BLAS functions (igraph_blas_*):;blas matrix vector dgemv igraph_blas_dgemv;
+192;arpack.at:30;Dense symmetric eigenvalues and eigenvectors (igraph_lapack_dsyevr):;lapack dsyevr eigenvalue eigenvector dense;
+193;arpack.at:35;Dense non-symmetric eigenvalues and eigenvectors (igraph_lapack_dgeev):;lapack dgeev eigenvalue eigenvector dense;
+194;arpack.at:40;Dense non-symmetric eigenvalues and eigenvectors (igraph_lapack_dgeevx):;lapack dgeevx eigenvalue eigenvector dense;
+195;arpack.at:45;Solving linear systems with LU factorization (igraph_lapack_dgesv):;lapack dgesv solve lu factorization;
+196;arpack.at:51;Upper Hessenberg transformation (igraph_lapack_dgehrd):;lapack dgehrd hessenberg;
+197;arpack.at:57;Eigenvector centrality (igraph_eigenvector_centrality):;eigenvector centrality arpack;
+198;arpack.at:63;Non-symmetric ARPACK solver (igraph_arpack_rnsolve):;arpack eigenvalue eigenvector eigen eigenproblem non-symmetric;
+199;bipartite.at:24;Create bipartite graphs (igraph_create_bipartite):;bipartite two mode igraph_create_bipartite;
+200;bipartite.at:30;Projection of bipartite graphs (igraph_bipartite_projection):;bipartite two mode projection igraph_bipartite_projection;
+201;centralization.at:24;Centralization (igraph_centralization_*):;centralization;
+202;separators.at:24;Decision problem (igraph_is_separator): ;vertex separator;
+203;separators.at:29;Decision problem, minimal separator (igraph_is_minimal separator): ;minimal vertex separator;
+204;separators.at:34;Minimal separators (igraph_all_minimal_ab_separators): ;minimal separator;
+205;separators.at:39;Minimal separators, bug 1033045 (igraph_all_minimal_st_separators): ;minimal separator;
+206;separators.at:44;Minimum size separators (igraph_minimum_size_separators): ;minimum size separators;
+207;separators.at:50;Cohesive blocking (igraph_cohesive_blocks): ;structurally cohesive blocks;
+208;hrg.at:24;Fitting a hierarchical model (igraph_hrg_fit) :;hierarchical random graph;
+209;hrg.at:29;Consensus tree (igraph_hrg_consensus) :;hierarchical random graph consensus tree;
+210;hrg.at:34;Missing edge prediction (igraph_hrg_predict) :;hierarchical random graph missing edge prediction;
+211;microscopic.at:23;Deterministic optimal imitation:;deterministic imitation strategy;
+212;microscopic.at:28;Stochastic imitation via uniform selection:;stochastic imitation strategy uniform selection;
+213;microscopic.at:33;Stochastic imitation via roulette selection:;stochastic imitation strategy roulette wheel;
+214;microscopic.at:38;Moran process:;moran process haploid reproduction;
+215;mt.at:24;Simple error handling test :;thread-safe;
+216;mt.at:29;Thread-safe ARPACK:;thread-safe arpack;
+217;scg.at:24;Solving the SCG problem (igraph_scg_grouping) :;scg spectral coarse graining grouping;
+218;scg.at:30;Solving the SCG problem, adjacency matrix (igraph_scg_grouping) :;scg spectral coarse graining grouping adjacency;
+219;scg.at:36;Solving the SCG problem, stochastic matrix (igraph_scg_grouping) :;scg spectral coarse graining grouping stochastic;
+220;scg.at:42;Solving the SCG problem, laplacian matrix (igraph_scg_grouping) :;scg spectral coarse graining grouping laplacian;
+221;scg.at:48;SCG semi-projectors, symmetric (igraph_scg_semiprojectors) :;scg spectral coarse graining semi-projectors adjancency;
+222;scg.at:54;SCG semi-projectors, stochastic (igraph_scg_semiprojectors) :;scg spectral coarse graining semi-projectors stochastic;
+223;scg.at:60;SCG semi-projectors, laplacian (igraph_scg_semiprojectors) :;scg spectral coarse graining semi-projectors laplacian;
+224;scg.at:66;SCG of a graph, adjacency matrix (igraph_scg) :;scg spectral coarse graining;
+225;scg.at:71;SCG of a graph, stochastic matrix (igraph_scg) :;scg spectral coarse graining;
+226;scg.at:76;SCG of a graph, laplacian matrix (igraph_scg) :;scg spectral coarse graining;
+227;random.at:24;Random seed:;rng seed random;
+228;random.at:29;MT19937 RNG on 64 bit machines:;rng mt19937;
+229;random.at:34;Exponentially distributed random numbers:;exponential random numbers;
+230;random.at:40;Random sampling from consecutive sequence:;random sampling;
+231;random.at:45;Fisher-Yates shuffle:;fisher-yates shuffle random permutation;
+232;qsort.at:24;Regular qsort (igraph_qsort):;qsort quick sort igraph_qsort;
+233;qsort.at:29;qsort with extra argument (igraph_qsort_r):;qsort quick sort igraph_qsort_r;
+234;matching.at:23;Maximum bipartite matching (igraph_maximum_bipartite_matching): ;bipartite matching;
+"
+# List of the all the test groups.
+at_groups_all=`$as_echo "$at_help_all" | sed 's/;.*//'`
+
+# at_fn_validate_ranges NAME...
+# -----------------------------
+# Validate and normalize the test group number contained in each variable
+# NAME. Leading zeroes are treated as decimal.
+at_fn_validate_ranges ()
+{
+  for at_grp
+  do
+    eval at_value=\$$at_grp
+    if test $at_value -lt 1 || test $at_value -gt 234; then
+      $as_echo "invalid test group: $at_value" >&2
+      exit 1
+    fi
+    case $at_value in
+      0*) # We want to treat leading 0 as decimal, like expr and test, but
+	  # AS_VAR_ARITH treats it as octal if it uses $(( )).
+	  # With XSI shells, ${at_value#${at_value%%[1-9]*}} avoids the
+	  # expr fork, but it is not worth the effort to determine if the
+	  # shell supports XSI when the user can just avoid leading 0.
+	  eval $at_grp='`expr $at_value + 0`' ;;
+    esac
+  done
+}
+
+at_prev=
+for at_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$at_prev"; then
+    at_option=$at_prev=$at_option
+    at_prev=
+  fi
+
+  case $at_option in
+  *=?*) at_optarg=`expr "X$at_option" : '[^=]*=\(.*\)'` ;;
+  *)    at_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $at_option in
+    --help | -h )
+	at_help_p=:
+	;;
+
+    --list | -l )
+	at_list_p=:
+	;;
+
+    --version | -V )
+	at_version_p=:
+	;;
+
+    --clean | -c )
+	at_clean=:
+	;;
+
+    --color )
+	at_color=always
+	;;
+    --color=* )
+	case $at_optarg in
+	no | never | none) at_color=never ;;
+	auto | tty | if-tty) at_color=auto ;;
+	always | yes | force) at_color=always ;;
+	*) at_optname=`echo " $at_option" | sed 's/^ //; s/=.*//'`
+	   as_fn_error $? "unrecognized argument to $at_optname: $at_optarg" ;;
+	esac
+	;;
+
+    --debug | -d )
+	at_debug_p=:
+	;;
+
+    --errexit | -e )
+	at_debug_p=:
+	at_errexit_p=:
+	;;
+
+    --verbose | -v )
+	at_verbose=; at_quiet=:
+	;;
+
+    --trace | -x )
+	at_traceon='set -x'
+	at_trace_echo=echo
+	at_check_filter_trace=at_fn_filter_trace
+	;;
+
+    [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9])
+	at_fn_validate_ranges at_option
+	as_fn_append at_groups "$at_option$as_nl"
+	;;
+
+    # Ranges
+    [0-9]- | [0-9][0-9]- | [0-9][0-9][0-9]- | [0-9][0-9][0-9][0-9]-)
+	at_range_start=`echo $at_option |tr -d X-`
+	at_fn_validate_ranges at_range_start
+	at_range=`$as_echo "$at_groups_all" | \
+	  sed -ne '/^'$at_range_start'$/,$p'`
+	as_fn_append at_groups "$at_range$as_nl"
+	;;
+
+    -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | -[0-9][0-9][0-9][0-9])
+	at_range_end=`echo $at_option |tr -d X-`
+	at_fn_validate_ranges at_range_end
+	at_range=`$as_echo "$at_groups_all" | \
+	  sed -ne '1,/^'$at_range_end'$/p'`
+	as_fn_append at_groups "$at_range$as_nl"
+	;;
+
+    [0-9]-[0-9] | [0-9]-[0-9][0-9] | [0-9]-[0-9][0-9][0-9] | \
+    [0-9]-[0-9][0-9][0-9][0-9] | [0-9][0-9]-[0-9][0-9] | \
+    [0-9][0-9]-[0-9][0-9][0-9] | [0-9][0-9]-[0-9][0-9][0-9][0-9] | \
+    [0-9][0-9][0-9]-[0-9][0-9][0-9] | \
+    [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9] | \
+    [0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9] )
+	at_range_start=`expr $at_option : '\(.*\)-'`
+	at_range_end=`expr $at_option : '.*-\(.*\)'`
+	if test $at_range_start -gt $at_range_end; then
+	  at_tmp=$at_range_end
+	  at_range_end=$at_range_start
+	  at_range_start=$at_tmp
+	fi
+	at_fn_validate_ranges at_range_start at_range_end
+	at_range=`$as_echo "$at_groups_all" | \
+	  sed -ne '/^'$at_range_start'$/,/^'$at_range_end'$/p'`
+	as_fn_append at_groups "$at_range$as_nl"
+	;;
+
+    # Directory selection.
+    --directory | -C )
+	at_prev=--directory
+	;;
+    --directory=* )
+	at_change_dir=:
+	at_dir=$at_optarg
+	if test x- = "x$at_dir" ; then
+	  at_dir=./-
+	fi
+	;;
+
+    # Parallel execution.
+    --jobs | -j )
+	at_jobs=0
+	;;
+    --jobs=* | -j[0-9]* )
+	if test -n "$at_optarg"; then
+	  at_jobs=$at_optarg
+	else
+	  at_jobs=`expr X$at_option : 'X-j\(.*\)'`
+	fi
+	case $at_jobs in *[!0-9]*)
+	  at_optname=`echo " $at_option" | sed 's/^ //; s/[0-9=].*//'`
+	  as_fn_error $? "non-numeric argument to $at_optname: $at_jobs" ;;
+	esac
+	;;
+
+    # Keywords.
+    --keywords | -k )
+	at_prev=--keywords
+	;;
+    --keywords=* )
+	at_groups_selected=$at_help_all
+	at_save_IFS=$IFS
+	IFS=,
+	set X $at_optarg
+	shift
+	IFS=$at_save_IFS
+	for at_keyword
+	do
+	  at_invert=
+	  case $at_keyword in
+	  '!'*)
+	    at_invert="-v"
+	    at_keyword=`expr "X$at_keyword" : 'X!\(.*\)'`
+	    ;;
+	  esac
+	  # It is on purpose that we match the test group titles too.
+	  at_groups_selected=`$as_echo "$at_groups_selected" |
+	      grep -i $at_invert "^[1-9][^;]*;.*[; ]$at_keyword[ ;]"`
+	done
+	# Smash the keywords.
+	at_groups_selected=`$as_echo "$at_groups_selected" | sed 's/;.*//'`
+	as_fn_append at_groups "$at_groups_selected$as_nl"
+	;;
+    --recheck)
+	at_recheck=:
+	;;
+
+    *=*)
+	at_envvar=`expr "x$at_option" : 'x\([^=]*\)='`
+	# Reject names that are not valid shell variable names.
+	case $at_envvar in
+	  '' | [0-9]* | *[!_$as_cr_alnum]* )
+	    as_fn_error $? "invalid variable name: \`$at_envvar'" ;;
+	esac
+	at_value=`$as_echo "$at_optarg" | sed "s/'/'\\\\\\\\''/g"`
+	# Export now, but save eval for later and for debug scripts.
+	export $at_envvar
+	as_fn_append at_debug_args " $at_envvar='$at_value'"
+	;;
+
+     *) $as_echo "$as_me: invalid option: $at_option" >&2
+	$as_echo "Try \`$0 --help' for more information." >&2
+	exit 1
+	;;
+  esac
+done
+
+# Verify our last option didn't require an argument
+if test -n "$at_prev"; then :
+  as_fn_error $? "\`$at_prev' requires an argument"
+fi
+
+# The file containing the suite.
+at_suite_log=$at_dir/$as_me.log
+
+# Selected test groups.
+if test -z "$at_groups$at_recheck"; then
+  at_groups=$at_groups_all
+else
+  if test -n "$at_recheck" && test -r "$at_suite_log"; then
+    at_oldfails=`sed -n '
+      /^Failed tests:$/,/^Skipped tests:$/{
+	s/^[ ]*\([1-9][0-9]*\):.*/\1/p
+      }
+      /^Unexpected passes:$/,/^## Detailed failed tests/{
+	s/^[ ]*\([1-9][0-9]*\):.*/\1/p
+      }
+      /^## Detailed failed tests/q
+      ' "$at_suite_log"`
+    as_fn_append at_groups "$at_oldfails$as_nl"
+  fi
+  # Sort the tests, removing duplicates.
+  at_groups=`$as_echo "$at_groups" | sort -nu | sed '/^$/d'`
+fi
+
+if test x"$at_color" = xalways \
+   || { test x"$at_color" = xauto && test -t 1; }; then
+  at_red=`printf '\033[0;31m'`
+  at_grn=`printf '\033[0;32m'`
+  at_lgn=`printf '\033[1;32m'`
+  at_blu=`printf '\033[1;34m'`
+  at_std=`printf '\033[m'`
+else
+  at_red= at_grn= at_lgn= at_blu= at_std=
+fi
+
+# Help message.
+if $at_help_p; then
+  cat <<_ATEOF || at_write_fail=1
+Usage: $0 [OPTION]... [VARIABLE=VALUE]... [TESTS]
+
+Run all the tests, or the selected TESTS, given by numeric ranges, and
+save a detailed log file.  Upon failure, create debugging scripts.
+
+Do not change environment variables directly.  Instead, set them via
+command line arguments.  Set \`AUTOTEST_PATH' to select the executables
+to exercise.  Each relative directory is expanded as build and source
+directories relative to the top level of this distribution.
+E.g., from within the build directory /tmp/foo-1.0, invoking this:
+
+  $ $0 AUTOTEST_PATH=bin
+
+is equivalent to the following, assuming the source directory is /src/foo-1.0:
+
+  PATH=/tmp/foo-1.0/bin:/src/foo-1.0/bin:\$PATH $0
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Operation modes:
+  -h, --help     print the help message, then exit
+  -V, --version  print version number, then exit
+  -c, --clean    remove all the files this test suite might create and exit
+  -l, --list     describes all the tests, or the selected TESTS
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Execution tuning:
+  -C, --directory=DIR
+                 change to directory DIR before starting
+      --color[=never|auto|always]
+                 enable colored test results on terminal, or always
+  -j, --jobs[=N]
+                 Allow N jobs at once; infinite jobs with no arg (default 1)
+  -k, --keywords=KEYWORDS
+                 select the tests matching all the comma-separated KEYWORDS
+                 multiple \`-k' accumulate; prefixed \`!' negates a KEYWORD
+      --recheck  select all tests that failed or passed unexpectedly last time
+  -e, --errexit  abort as soon as a test fails; implies --debug
+  -v, --verbose  force more detailed output
+                 default for debugging scripts
+  -d, --debug    inhibit clean up and top-level logging
+                 default for debugging scripts
+  -x, --trace    enable tests shell tracing
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Report bugs to <csardi.gabor at gmail.com>.
+_ATEOF
+  exit $at_write_fail
+fi
+
+# List of tests.
+if $at_list_p; then
+  cat <<_ATEOF || at_write_fail=1
+igraph 0.7.1 test suite: igraph test groups:
+
+ NUM: FILE-NAME:LINE     TEST-GROUP-NAME
+      KEYWORDS
+
+_ATEOF
+  # Pass an empty line as separator between selected groups and help.
+  $as_echo "$at_groups$as_nl$as_nl$at_help_all" |
+    awk 'NF == 1 && FS != ";" {
+	   selected[$ 1] = 1
+	   next
+	 }
+	 /^$/ { FS = ";" }
+	 NF > 0 {
+	   if (selected[$ 1]) {
+	     printf " %3d: %-18s %s\n", $ 1, $ 2, $ 3
+	     if ($ 4) {
+	       lmax = 79
+	       indent = "     "
+	       line = indent
+	       len = length (line)
+	       n = split ($ 4, a, " ")
+	       for (i = 1; i <= n; i++) {
+		 l = length (a[i]) + 1
+		 if (i > 1 && len + l > lmax) {
+		   print line
+		   line = indent " " a[i]
+		   len = length (line)
+		 } else {
+		   line = line " " a[i]
+		   len += l
+		 }
+	       }
+	       if (n)
+		 print line
+	     }
+	   }
+	 }' || at_write_fail=1
+  exit $at_write_fail
+fi
+if $at_version_p; then
+  $as_echo "$as_me (igraph 0.7.1)" &&
+  cat <<\_ATEOF || at_write_fail=1
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This test suite is free software; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+_ATEOF
+  exit $at_write_fail
+fi
+
+# Should we print banners?  Yes if more than one test is run.
+case $at_groups in #(
+  *$as_nl* )
+      at_print_banners=: ;; #(
+  * ) at_print_banners=false ;;
+esac
+# Text for banner N, set to a single space once printed.
+# Banner 1. version.at:24
+# Category starts at test group 1.
+at_banner_text_1="igraph version number."
+# Banner 2. types.at:22
+# Category starts at test group 2.
+at_banner_text_2="Utility types (vector_t, etc.)"
+# Banner 3. basic.at:24
+# Category starts at test group 36.
+at_banner_text_3="Basic (interface) functions."
+# Banner 4. iterators.at:22
+# Category starts at test group 47.
+at_banner_text_4="Iterators aka vertex and edge sequences"
+# Banner 5. structure_generators.at:22
+# Category starts at test group 52.
+at_banner_text_5="Structure generators"
+# Banner 6. structural_properties.at:22
+# Category starts at test group 72.
+at_banner_text_6="Structural properties"
+# Banner 7. components.at:22
+# Category starts at test group 108.
+at_banner_text_7="Components"
+# Banner 8. layout.at:22
+# Category starts at test group 110.
+at_banner_text_8="Layouts"
+# Banner 9. visitors.at:22
+# Category starts at test group 119.
+at_banner_text_9="Visitors"
+# Banner 10. topology.at:22
+# Category starts at test group 121.
+at_banner_text_10="Graph topology"
+# Banner 11. motifs.at:22
+# Category starts at test group 126.
+at_banner_text_11="Motifs"
+# Banner 12. foreign.at:22
+# Category starts at test group 127.
+at_banner_text_12="Foreign formats"
+# Banner 13. other.at:22
+# Category starts at test group 143.
+at_banner_text_13="Miscellaneous functions"
+# Banner 14. operators.at:22
+# Category starts at test group 145.
+at_banner_text_14="Graphs operators"
+# Banner 15. conversion.at:22
+# Category starts at test group 152.
+at_banner_text_15="Conversion functions"
+# Banner 16. flow.at:22
+# Category starts at test group 155.
+at_banner_text_16="Maximum flows and such"
+# Banner 17. community.at:22
+# Category starts at test group 163.
+at_banner_text_17="Community structure"
+# Banner 18. cliques.at:24
+# Category starts at test group 175.
+at_banner_text_18="Cliques and independent vertex sets."
+# Banner 19. eigen.at:22
+# Category starts at test group 181.
+at_banner_text_19="Eigenvalues, eigenvectors"
+# Banner 20. attributes.at:22
+# Category starts at test group 187.
+at_banner_text_20="Attributes from C"
+# Banner 21. arpack.at:22
+# Category starts at test group 191.
+at_banner_text_21="BLAS, LAPACK and ARPACK based functions"
+# Banner 22. bipartite.at:22
+# Category starts at test group 199.
+at_banner_text_22="Bipartite graphs"
+# Banner 23. centralization.at:22
+# Category starts at test group 201.
+at_banner_text_23="Centralization"
+# Banner 24. separators.at:22
+# Category starts at test group 202.
+at_banner_text_24="Minimal separators"
+# Banner 25. hrg.at:22
+# Category starts at test group 208.
+at_banner_text_25="Hierarchical random graphs"
+# Banner 26. microscopic.at:21
+# Category starts at test group 211.
+at_banner_text_26="Microscopic updates"
+# Banner 27. mt.at:22
+# Category starts at test group 215.
+at_banner_text_27="Thread-safety tests"
+# Banner 28. scg.at:22
+# Category starts at test group 217.
+at_banner_text_28="Spectral coarse graining"
+# Banner 29. random.at:22
+# Category starts at test group 227.
+at_banner_text_29="Random number generators"
+# Banner 30. qsort.at:22
+# Category starts at test group 232.
+at_banner_text_30="Quick sort"
+# Banner 31. matching.at:21
+# Category starts at test group 234.
+at_banner_text_31="Maximum matchings"
+
+# Take any -C into account.
+if $at_change_dir ; then
+  test x != "x$at_dir" && cd "$at_dir" \
+    || as_fn_error $? "unable to change directory"
+  at_dir=`pwd`
+fi
+
+# Load the config files for any default variable assignments.
+for at_file in atconfig atlocal
+do
+  test -r $at_file || continue
+  . ./$at_file || as_fn_error $? "invalid content: $at_file"
+done
+
+# Autoconf <=2.59b set at_top_builddir instead of at_top_build_prefix:
+: "${at_top_build_prefix=$at_top_builddir}"
+
+# Perform any assignments requested during argument parsing.
+eval "$at_debug_args"
+
+# atconfig delivers names relative to the directory the test suite is
+# in, but the groups themselves are run in testsuite-dir/group-dir.
+if test -n "$at_top_srcdir"; then
+  builddir=../..
+  for at_dir_var in srcdir top_srcdir top_build_prefix
+  do
+    eval at_val=\$at_$at_dir_var
+    case $at_val in
+      [\\/$]* | ?:[\\/]* ) at_prefix= ;;
+      *) at_prefix=../../ ;;
+    esac
+    eval "$at_dir_var=\$at_prefix\$at_val"
+  done
+fi
+
+## -------------------- ##
+## Directory structure. ##
+## -------------------- ##
+
+# This is the set of directories and files used by this script
+# (non-literals are capitalized):
+#
+# TESTSUITE         - the testsuite
+# TESTSUITE.log     - summarizes the complete testsuite run
+# TESTSUITE.dir/    - created during a run, remains after -d or failed test
+# + at-groups/      - during a run: status of all groups in run
+# | + NNN/          - during a run: meta-data about test group NNN
+# | | + check-line  - location (source file and line) of current AT_CHECK
+# | | + status      - exit status of current AT_CHECK
+# | | + stdout      - stdout of current AT_CHECK
+# | | + stder1      - stderr, including trace
+# | | + stderr      - stderr, with trace filtered out
+# | | + test-source - portion of testsuite that defines group
+# | | + times       - timestamps for computing duration
+# | | + pass        - created if group passed
+# | | + xpass       - created if group xpassed
+# | | + fail        - created if group failed
+# | | + xfail       - created if group xfailed
+# | | + skip        - created if group skipped
+# + at-stop         - during a run: end the run if this file exists
+# + at-source-lines - during a run: cache of TESTSUITE line numbers for extraction
+# + 0..NNN/         - created for each group NNN, remains after -d or failed test
+# | + TESTSUITE.log - summarizes the group results
+# | + ...           - files created during the group
+
+# The directory the whole suite works in.
+# Should be absolute to let the user `cd' at will.
+at_suite_dir=$at_dir/$as_me.dir
+# The file containing the suite ($at_dir might have changed since earlier).
+at_suite_log=$at_dir/$as_me.log
+# The directory containing helper files per test group.
+at_helper_dir=$at_suite_dir/at-groups
+# Stop file: if it exists, do not start new jobs.
+at_stop_file=$at_suite_dir/at-stop
+# The fifo used for the job dispatcher.
+at_job_fifo=$at_suite_dir/at-job-fifo
+
+if $at_clean; then
+  test -d "$at_suite_dir" &&
+    find "$at_suite_dir" -type d ! -perm -700 -exec chmod u+rwx \{\} \;
+  rm -f -r "$at_suite_dir" "$at_suite_log"
+  exit $?
+fi
+
+# Don't take risks: use only absolute directories in PATH.
+#
+# For stand-alone test suites (ie. atconfig was not found),
+# AUTOTEST_PATH is relative to `.'.
+#
+# For embedded test suites, AUTOTEST_PATH is relative to the top level
+# of the package.  Then expand it into build/src parts, since users
+# may create executables in both places.
+AUTOTEST_PATH=`$as_echo "$AUTOTEST_PATH" | sed "s|:|$PATH_SEPARATOR|g"`
+at_path=
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $AUTOTEST_PATH $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -n "$at_path" && as_fn_append at_path $PATH_SEPARATOR
+case $as_dir in
+  [\\/]* | ?:[\\/]* )
+    as_fn_append at_path "$as_dir"
+    ;;
+  * )
+    if test -z "$at_top_build_prefix"; then
+      # Stand-alone test suite.
+      as_fn_append at_path "$as_dir"
+    else
+      # Embedded test suite.
+      as_fn_append at_path "$at_top_build_prefix$as_dir$PATH_SEPARATOR"
+      as_fn_append at_path "$at_top_srcdir/$as_dir"
+    fi
+    ;;
+esac
+  done
+IFS=$as_save_IFS
+
+
+# Now build and simplify PATH.
+#
+# There might be directories that don't exist, but don't redirect
+# builtins' (eg., cd) stderr directly: Ultrix's sh hates that.
+at_new_path=
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $at_path
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -d "$as_dir" || continue
+case $as_dir in
+  [\\/]* | ?:[\\/]* ) ;;
+  * ) as_dir=`(cd "$as_dir" && pwd) 2>/dev/null` ;;
+esac
+case $PATH_SEPARATOR$at_new_path$PATH_SEPARATOR in
+  *$PATH_SEPARATOR$as_dir$PATH_SEPARATOR*) ;;
+  $PATH_SEPARATOR$PATH_SEPARATOR) at_new_path=$as_dir ;;
+  *) as_fn_append at_new_path "$PATH_SEPARATOR$as_dir" ;;
+esac
+  done
+IFS=$as_save_IFS
+
+PATH=$at_new_path
+export PATH
+
+# Setting up the FDs.
+
+
+
+# 5 is the log file.  Not to be overwritten if `-d'.
+if $at_debug_p; then
+  at_suite_log=/dev/null
+else
+  : >"$at_suite_log"
+fi
+exec 5>>"$at_suite_log"
+
+# Banners and logs.
+$as_echo "## -------------------------------- ##
+## igraph 0.7.1 test suite: igraph. ##
+## -------------------------------- ##"
+{
+  $as_echo "## -------------------------------- ##
+## igraph 0.7.1 test suite: igraph. ##
+## -------------------------------- ##"
+  echo
+
+  $as_echo "$as_me: command line was:"
+  $as_echo "  \$ $0 $at_cli_args"
+  echo
+
+  # If ChangeLog exists, list a few lines in case it might help determining
+  # the exact version.
+  if test -n "$at_top_srcdir" && test -f "$at_top_srcdir/ChangeLog"; then
+    $as_echo "## ---------- ##
+## ChangeLog. ##
+## ---------- ##"
+    echo
+    sed 's/^/| /;10q' "$at_top_srcdir/ChangeLog"
+    echo
+  fi
+
+  {
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+}
+  echo
+
+  # Contents of the config files.
+  for at_file in atconfig atlocal
+  do
+    test -r $at_file || continue
+    $as_echo "$as_me: $at_file:"
+    sed 's/^/| /' $at_file
+    echo
+  done
+} >&5
+
+
+## ------------------------- ##
+## Autotest shell functions. ##
+## ------------------------- ##
+
+# at_fn_banner NUMBER
+# -------------------
+# Output banner NUMBER, provided the testsuite is running multiple groups and
+# this particular banner has not yet been printed.
+at_fn_banner ()
+{
+  $at_print_banners || return 0
+  eval at_banner_text=\$at_banner_text_$1
+  test "x$at_banner_text" = "x " && return 0
+  eval "at_banner_text_$1=\" \""
+  if test -z "$at_banner_text"; then
+    $at_first || echo
+  else
+    $as_echo "$as_nl$at_banner_text$as_nl"
+  fi
+} # at_fn_banner
+
+# at_fn_check_prepare_notrace REASON LINE
+# ---------------------------------------
+# Perform AT_CHECK preparations for the command at LINE for an untraceable
+# command; REASON is the reason for disabling tracing.
+at_fn_check_prepare_notrace ()
+{
+  $at_trace_echo "Not enabling shell tracing (command contains $1)"
+  $as_echo "$2" >"$at_check_line_file"
+  at_check_trace=: at_check_filter=:
+  : >"$at_stdout"; : >"$at_stderr"
+}
+
+# at_fn_check_prepare_trace LINE
+# ------------------------------
+# Perform AT_CHECK preparations for the command at LINE for a traceable
+# command.
+at_fn_check_prepare_trace ()
+{
+  $as_echo "$1" >"$at_check_line_file"
+  at_check_trace=$at_traceon at_check_filter=$at_check_filter_trace
+  : >"$at_stdout"; : >"$at_stderr"
+}
+
+# at_fn_check_prepare_dynamic COMMAND LINE
+# ----------------------------------------
+# Decide if COMMAND at LINE is traceable at runtime, and call the appropriate
+# preparation function.
+at_fn_check_prepare_dynamic ()
+{
+  case $1 in
+    *$as_nl*)
+      at_fn_check_prepare_notrace 'an embedded newline' "$2" ;;
+    *)
+      at_fn_check_prepare_trace "$2" ;;
+  esac
+}
+
+# at_fn_filter_trace
+# ------------------
+# Remove the lines in the file "$at_stderr" generated by "set -x" and print
+# them to stderr.
+at_fn_filter_trace ()
+{
+  mv "$at_stderr" "$at_stder1"
+  grep '^ *+' "$at_stder1" >&2
+  grep -v '^ *+' "$at_stder1" >"$at_stderr"
+}
+
+# at_fn_log_failure FILE-LIST
+# ---------------------------
+# Copy the files in the list on stdout with a "> " prefix, and exit the shell
+# with a failure exit code.
+at_fn_log_failure ()
+{
+  for file
+    do $as_echo "$file:"; sed 's/^/> /' "$file"; done
+  echo 1 > "$at_status_file"
+  exit 1
+}
+
+# at_fn_check_skip EXIT-CODE LINE
+# -------------------------------
+# Check whether EXIT-CODE is a special exit code (77 or 99), and if so exit
+# the test group subshell with that same exit code. Use LINE in any report
+# about test failure.
+at_fn_check_skip ()
+{
+  case $1 in
+    99) echo 99 > "$at_status_file"; at_failed=:
+	$as_echo "$2: hard failure"; exit 99;;
+    77) echo 77 > "$at_status_file"; exit 77;;
+  esac
+}
+
+# at_fn_check_status EXPECTED EXIT-CODE LINE
+# ------------------------------------------
+# Check whether EXIT-CODE is the EXPECTED exit code, and if so do nothing.
+# Otherwise, if it is 77 or 99, exit the test group subshell with that same
+# exit code; if it is anything else print an error message referring to LINE,
+# and fail the test.
+at_fn_check_status ()
+{
+  case $2 in
+    $1 ) ;;
+    77) echo 77 > "$at_status_file"; exit 77;;
+    99) echo 99 > "$at_status_file"; at_failed=:
+	$as_echo "$3: hard failure"; exit 99;;
+    *) $as_echo "$3: exit code was $2, expected $1"
+      at_failed=:;;
+  esac
+}
+
+# at_fn_diff_devnull FILE
+# -----------------------
+# Emit a diff between /dev/null and FILE. Uses "test -s" to avoid useless diff
+# invocations.
+at_fn_diff_devnull ()
+{
+  test -s "$1" || return 0
+  $at_diff "$at_devnull" "$1"
+}
+
+# at_fn_test NUMBER
+# -----------------
+# Parse out test NUMBER from the tail of this file.
+at_fn_test ()
+{
+  eval at_sed=\$at_sed$1
+  sed "$at_sed" "$at_myself" > "$at_test_source"
+}
+
+# at_fn_create_debugging_script
+# -----------------------------
+# Create the debugging script $at_group_dir/run which will reproduce the
+# current test group.
+at_fn_create_debugging_script ()
+{
+  {
+    echo "#! /bin/sh" &&
+    echo 'test "${ZSH_VERSION+set}" = set && alias -g '\''${1+"$@"}'\''='\''"$@"'\''' &&
+    $as_echo "cd '$at_dir'" &&
+    $as_echo "exec \${CONFIG_SHELL-$SHELL} \"$at_myself\" -v -d $at_debug_args $at_group \${1+\"\$@\"}" &&
+    echo 'exit 1'
+  } >"$at_group_dir/run" &&
+  chmod +x "$at_group_dir/run"
+}
+
+## -------------------------------- ##
+## End of autotest shell functions. ##
+## -------------------------------- ##
+{
+  $as_echo "## ---------------- ##
+## Tested programs. ##
+## ---------------- ##"
+  echo
+} >&5
+
+# Report what programs are being tested.
+for at_program in : $at_tested
+do
+  test "$at_program" = : && continue
+  case $at_program in
+    [\\/]* | ?:[\\/]* ) $at_program_=$at_program ;;
+    * )
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -f "$as_dir/$at_program" && break
+  done
+IFS=$as_save_IFS
+
+    at_program_=$as_dir/$at_program ;;
+  esac
+  if test -f "$at_program_"; then
+    {
+      $as_echo "$at_srcdir/testsuite.at:22: $at_program_ --version"
+      "$at_program_" --version </dev/null
+      echo
+    } >&5 2>&1
+  else
+    as_fn_error $? "cannot find $at_program" "$LINENO" 5
+  fi
+done
+
+{
+  $as_echo "## ------------------ ##
+## Running the tests. ##
+## ------------------ ##"
+} >&5
+
+at_start_date=`date`
+at_start_time=`date +%s 2>/dev/null`
+$as_echo "$as_me: starting at: $at_start_date" >&5
+
+# Create the master directory if it doesn't already exist.
+as_dir="$at_suite_dir"; as_fn_mkdir_p ||
+  as_fn_error $? "cannot create \`$at_suite_dir'" "$LINENO" 5
+
+# Can we diff with `/dev/null'?  DU 5.0 refuses.
+if diff /dev/null /dev/null >/dev/null 2>&1; then
+  at_devnull=/dev/null
+else
+  at_devnull=$at_suite_dir/devnull
+  >"$at_devnull"
+fi
+
+# Use `diff -u' when possible.
+if at_diff=`diff -u "$at_devnull" "$at_devnull" 2>&1` && test -z "$at_diff"
+then
+  at_diff='diff -u'
+else
+  at_diff=diff
+fi
+
+# Get the last needed group.
+for at_group in : $at_groups; do :; done
+
+# Extract the start and end lines of each test group at the tail
+# of this file
+awk '
+BEGIN { FS="" }
+/^#AT_START_/ {
+  start = NR
+}
+/^#AT_STOP_/ {
+  test = substr ($ 0, 10)
+  print "at_sed" test "=\"1," start "d;" (NR-1) "q\""
+  if (test == "'"$at_group"'") exit
+}' "$at_myself" > "$at_suite_dir/at-source-lines" &&
+. "$at_suite_dir/at-source-lines" ||
+  as_fn_error $? "cannot create test line number cache" "$LINENO" 5
+rm -f "$at_suite_dir/at-source-lines"
+
+# Set number of jobs for `-j'; avoid more jobs than test groups.
+set X $at_groups; shift; at_max_jobs=$#
+if test $at_max_jobs -eq 0; then
+  at_jobs=1
+fi
+if test $at_jobs -ne 1 &&
+   { test $at_jobs -eq 0 || test $at_jobs -gt $at_max_jobs; }; then
+  at_jobs=$at_max_jobs
+fi
+
+# If parallel mode, don't output banners, don't split summary lines.
+if test $at_jobs -ne 1; then
+  at_print_banners=false
+  at_quiet=:
+fi
+
+# Set up helper dirs.
+rm -rf "$at_helper_dir" &&
+mkdir "$at_helper_dir" &&
+cd "$at_helper_dir" &&
+{ test -z "$at_groups" || mkdir $at_groups; } ||
+as_fn_error $? "testsuite directory setup failed" "$LINENO" 5
+
+# Functions for running a test group.  We leave the actual
+# test group execution outside of a shell function in order
+# to avoid hitting zsh 4.x exit status bugs.
+
+# at_fn_group_prepare
+# -------------------
+# Prepare for running a test group.
+at_fn_group_prepare ()
+{
+  # The directory for additional per-group helper files.
+  at_job_dir=$at_helper_dir/$at_group
+  # The file containing the location of the last AT_CHECK.
+  at_check_line_file=$at_job_dir/check-line
+  # The file containing the exit status of the last command.
+  at_status_file=$at_job_dir/status
+  # The files containing the output of the tested commands.
+  at_stdout=$at_job_dir/stdout
+  at_stder1=$at_job_dir/stder1
+  at_stderr=$at_job_dir/stderr
+  # The file containing the code for a test group.
+  at_test_source=$at_job_dir/test-source
+  # The file containing dates.
+  at_times_file=$at_job_dir/times
+
+  # Be sure to come back to the top test directory.
+  cd "$at_suite_dir"
+
+  # Clearly separate the test groups when verbose.
+  $at_first || $at_verbose echo
+
+  at_group_normalized=$at_group
+
+  eval 'while :; do
+    case $at_group_normalized in #(
+    '"$at_format"'*) break;;
+    esac
+    at_group_normalized=0$at_group_normalized
+  done'
+
+
+  # Create a fresh directory for the next test group, and enter.
+  # If one already exists, the user may have invoked ./run from
+  # within that directory; we remove the contents, but not the
+  # directory itself, so that we aren't pulling the rug out from
+  # under the shell's notion of the current directory.
+  at_group_dir=$at_suite_dir/$at_group_normalized
+  at_group_log=$at_group_dir/$as_me.log
+  if test -d "$at_group_dir"; then
+  find "$at_group_dir" -type d ! -perm -700 -exec chmod u+rwx {} \;
+  rm -fr "$at_group_dir"/* "$at_group_dir"/.[!.] "$at_group_dir"/.??*
+fi ||
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: test directory for $at_group_normalized could not be cleaned" >&5
+$as_echo "$as_me: WARNING: test directory for $at_group_normalized could not be cleaned" >&2;}
+  # Be tolerant if the above `rm' was not able to remove the directory.
+  as_dir="$at_group_dir"; as_fn_mkdir_p
+
+  echo 0 > "$at_status_file"
+
+  # In verbose mode, append to the log file *and* show on
+  # the standard output; in quiet mode only write to the log.
+  if test -z "$at_verbose"; then
+    at_tee_pipe='tee -a "$at_group_log"'
+  else
+    at_tee_pipe='cat >> "$at_group_log"'
+  fi
+}
+
+# at_fn_group_banner ORDINAL LINE DESC PAD [BANNER]
+# -------------------------------------------------
+# Declare the test group ORDINAL, located at LINE with group description DESC,
+# and residing under BANNER. Use PAD to align the status column.
+at_fn_group_banner ()
+{
+  at_setup_line="$2"
+  test -n "$5" && at_fn_banner $5
+  at_desc="$3"
+  case $1 in
+    [0-9])      at_desc_line="  $1: ";;
+    [0-9][0-9]) at_desc_line=" $1: " ;;
+    *)          at_desc_line="$1: "  ;;
+  esac
+  as_fn_append at_desc_line "$3$4"
+  $at_quiet $as_echo_n "$at_desc_line"
+  echo "#                             -*- compilation -*-" >> "$at_group_log"
+}
+
+# at_fn_group_postprocess
+# -----------------------
+# Perform cleanup after running a test group.
+at_fn_group_postprocess ()
+{
+  # Be sure to come back to the suite directory, in particular
+  # since below we might `rm' the group directory we are in currently.
+  cd "$at_suite_dir"
+
+  if test ! -f "$at_check_line_file"; then
+    sed "s/^ */$as_me: WARNING: /" <<_ATEOF
+      A failure happened in a test group before any test could be
+      run. This means that test suite is improperly designed.  Please
+      report this failure to <csardi.gabor at gmail.com>.
+_ATEOF
+    $as_echo "$at_setup_line" >"$at_check_line_file"
+    at_status=99
+  fi
+  $at_verbose $as_echo_n "$at_group. $at_setup_line: "
+  $as_echo_n "$at_group. $at_setup_line: " >> "$at_group_log"
+  case $at_xfail:$at_status in
+    yes:0)
+	at_msg="UNEXPECTED PASS"
+	at_res=xpass
+	at_errexit=$at_errexit_p
+	at_color=$at_red
+	;;
+    no:0)
+	at_msg="ok"
+	at_res=pass
+	at_errexit=false
+	at_color=$at_grn
+	;;
+    *:77)
+	at_msg='skipped ('`cat "$at_check_line_file"`')'
+	at_res=skip
+	at_errexit=false
+	at_color=$at_blu
+	;;
+    no:* | *:99)
+	at_msg='FAILED ('`cat "$at_check_line_file"`')'
+	at_res=fail
+	at_errexit=$at_errexit_p
+	at_color=$at_red
+	;;
+    yes:*)
+	at_msg='expected failure ('`cat "$at_check_line_file"`')'
+	at_res=xfail
+	at_errexit=false
+	at_color=$at_lgn
+	;;
+  esac
+  echo "$at_res" > "$at_job_dir/$at_res"
+  # In parallel mode, output the summary line only afterwards.
+  if test $at_jobs -ne 1 && test -n "$at_verbose"; then
+    $as_echo "$at_desc_line $at_color$at_msg$at_std"
+  else
+    # Make sure there is a separator even with long titles.
+    $as_echo " $at_color$at_msg$at_std"
+  fi
+  at_log_msg="$at_group. $at_desc ($at_setup_line): $at_msg"
+  case $at_status in
+    0|77)
+      # $at_times_file is only available if the group succeeded.
+      # We're not including the group log, so the success message
+      # is written in the global log separately.  But we also
+      # write to the group log in case they're using -d.
+      if test -f "$at_times_file"; then
+	at_log_msg="$at_log_msg     ("`sed 1d "$at_times_file"`')'
+	rm -f "$at_times_file"
+      fi
+      $as_echo "$at_log_msg" >> "$at_group_log"
+      $as_echo "$at_log_msg" >&5
+
+      # Cleanup the group directory, unless the user wants the files
+      # or the success was unexpected.
+      if $at_debug_p || test $at_res = xpass; then
+	at_fn_create_debugging_script
+	if test $at_res = xpass && $at_errexit; then
+	  echo stop > "$at_stop_file"
+	fi
+      else
+	if test -d "$at_group_dir"; then
+	  find "$at_group_dir" -type d ! -perm -700 -exec chmod u+rwx \{\} \;
+	  rm -fr "$at_group_dir"
+	fi
+	rm -f "$at_test_source"
+      fi
+      ;;
+    *)
+      # Upon failure, include the log into the testsuite's global
+      # log.  The failure message is written in the group log.  It
+      # is later included in the global log.
+      $as_echo "$at_log_msg" >> "$at_group_log"
+
+      # Upon failure, keep the group directory for autopsy, and create
+      # the debugging script.  With -e, do not start any further tests.
+      at_fn_create_debugging_script
+      if $at_errexit; then
+	echo stop > "$at_stop_file"
+      fi
+      ;;
+  esac
+}
+
+
+## ------------ ##
+## Driver loop. ##
+## ------------ ##
+
+
+if (set -m && set +m && set +b) >/dev/null 2>&1; then
+  set +b
+  at_job_control_on='set -m' at_job_control_off='set +m' at_job_group=-
+else
+  at_job_control_on=: at_job_control_off=: at_job_group=
+fi
+
+for at_signal in 1 2 15; do
+  trap 'set +x; set +e
+	$at_job_control_off
+	at_signal='"$at_signal"'
+	echo stop > "$at_stop_file"
+	trap "" $at_signal
+	at_pgids=
+	for at_pgid in `jobs -p 2>/dev/null`; do
+	  at_pgids="$at_pgids $at_job_group$at_pgid"
+	done
+	test -z "$at_pgids" || kill -$at_signal $at_pgids 2>/dev/null
+	wait
+	if test "$at_jobs" -eq 1 || test -z "$at_verbose"; then
+	  echo >&2
+	fi
+	at_signame=`kill -l $at_signal 2>&1 || echo $at_signal`
+	set x $at_signame
+	test 1 -gt 2 && at_signame=$at_signal
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: caught signal $at_signame, bailing out" >&5
+$as_echo "$as_me: WARNING: caught signal $at_signame, bailing out" >&2;}
+	as_fn_arith 128 + $at_signal && exit_status=$as_val
+	as_fn_exit $exit_status' $at_signal
+done
+
+rm -f "$at_stop_file"
+at_first=:
+
+if test $at_jobs -ne 1 &&
+     rm -f "$at_job_fifo" &&
+     test -n "$at_job_group" &&
+     ( mkfifo "$at_job_fifo" && trap 'exit 1' PIPE STOP TSTP ) 2>/dev/null
+then
+  # FIFO job dispatcher.
+
+  trap 'at_pids=
+	for at_pid in `jobs -p`; do
+	  at_pids="$at_pids $at_job_group$at_pid"
+	done
+	if test -n "$at_pids"; then
+	  at_sig=TSTP
+	  test "${TMOUT+set}" = set && at_sig=STOP
+	  kill -$at_sig $at_pids 2>/dev/null
+	fi
+	kill -STOP $$
+	test -z "$at_pids" || kill -CONT $at_pids 2>/dev/null' TSTP
+
+  echo
+  # Turn jobs into a list of numbers, starting from 1.
+  at_joblist=`$as_echo "$at_groups" | sed -n 1,${at_jobs}p`
+
+  set X $at_joblist
+  shift
+  for at_group in $at_groups; do
+    $at_job_control_on 2>/dev/null
+    (
+      # Start one test group.
+      $at_job_control_off
+      if $at_first; then
+	exec 7>"$at_job_fifo"
+      else
+	exec 6<&-
+      fi
+      trap 'set +x; set +e
+	    trap "" PIPE
+	    echo stop > "$at_stop_file"
+	    echo >&7
+	    as_fn_exit 141' PIPE
+      at_fn_group_prepare
+      if cd "$at_group_dir" &&
+	 at_fn_test $at_group &&
+	 . "$at_test_source"
+      then :; else
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to parse test group: $at_group" >&5
+$as_echo "$as_me: WARNING: unable to parse test group: $at_group" >&2;}
+	at_failed=:
+      fi
+      at_fn_group_postprocess
+      echo >&7
+    ) &
+    $at_job_control_off
+    if $at_first; then
+      at_first=false
+      exec 6<"$at_job_fifo" 7>"$at_job_fifo"
+    fi
+    shift # Consume one token.
+    if test $# -gt 0; then :; else
+      read at_token <&6 || break
+      set x $*
+    fi
+    test -f "$at_stop_file" && break
+  done
+  exec 7>&-
+  # Read back the remaining ($at_jobs - 1) tokens.
+  set X $at_joblist
+  shift
+  if test $# -gt 0; then
+    shift
+    for at_job
+    do
+      read at_token
+    done <&6
+  fi
+  exec 6<&-
+  wait
+else
+  # Run serially, avoid forks and other potential surprises.
+  for at_group in $at_groups; do
+    at_fn_group_prepare
+    if cd "$at_group_dir" &&
+       at_fn_test $at_group &&
+       . "$at_test_source"; then :; else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to parse test group: $at_group" >&5
+$as_echo "$as_me: WARNING: unable to parse test group: $at_group" >&2;}
+      at_failed=:
+    fi
+    at_fn_group_postprocess
+    test -f "$at_stop_file" && break
+    at_first=false
+  done
+fi
+
+# Wrap up the test suite with summary statistics.
+cd "$at_helper_dir"
+
+# Use ?..???? when the list must remain sorted, the faster * otherwise.
+at_pass_list=`for f in */pass; do echo $f; done | sed '/\*/d; s,/pass,,'`
+at_skip_list=`for f in */skip; do echo $f; done | sed '/\*/d; s,/skip,,'`
+at_xfail_list=`for f in */xfail; do echo $f; done | sed '/\*/d; s,/xfail,,'`
+at_xpass_list=`for f in ?/xpass ??/xpass ???/xpass ????/xpass; do
+		 echo $f; done | sed '/?/d; s,/xpass,,'`
+at_fail_list=`for f in ?/fail ??/fail ???/fail ????/fail; do
+		echo $f; done | sed '/?/d; s,/fail,,'`
+
+set X $at_pass_list $at_xpass_list $at_xfail_list $at_fail_list $at_skip_list
+shift; at_group_count=$#
+set X $at_xpass_list; shift; at_xpass_count=$#; at_xpass_list=$*
+set X $at_xfail_list; shift; at_xfail_count=$#
+set X $at_fail_list; shift; at_fail_count=$#; at_fail_list=$*
+set X $at_skip_list; shift; at_skip_count=$#
+
+as_fn_arith $at_group_count - $at_skip_count && at_run_count=$as_val
+as_fn_arith $at_xpass_count + $at_fail_count && at_unexpected_count=$as_val
+as_fn_arith $at_xfail_count + $at_fail_count && at_total_fail_count=$as_val
+
+# Back to the top directory.
+cd "$at_dir"
+rm -rf "$at_helper_dir"
+
+# Compute the duration of the suite.
+at_stop_date=`date`
+at_stop_time=`date +%s 2>/dev/null`
+$as_echo "$as_me: ending at: $at_stop_date" >&5
+case $at_start_time,$at_stop_time in
+  [0-9]*,[0-9]*)
+    as_fn_arith $at_stop_time - $at_start_time && at_duration_s=$as_val
+    as_fn_arith $at_duration_s / 60 && at_duration_m=$as_val
+    as_fn_arith $at_duration_m / 60 && at_duration_h=$as_val
+    as_fn_arith $at_duration_s % 60 && at_duration_s=$as_val
+    as_fn_arith $at_duration_m % 60 && at_duration_m=$as_val
+    at_duration="${at_duration_h}h ${at_duration_m}m ${at_duration_s}s"
+    $as_echo "$as_me: test suite duration: $at_duration" >&5
+    ;;
+esac
+
+echo
+$as_echo "## ------------- ##
+## Test results. ##
+## ------------- ##"
+echo
+{
+  echo
+  $as_echo "## ------------- ##
+## Test results. ##
+## ------------- ##"
+  echo
+} >&5
+
+if test $at_run_count = 1; then
+  at_result="1 test"
+  at_were=was
+else
+  at_result="$at_run_count tests"
+  at_were=were
+fi
+if $at_errexit_p && test $at_unexpected_count != 0; then
+  if test $at_xpass_count = 1; then
+    at_result="$at_result $at_were run, one passed"
+  else
+    at_result="$at_result $at_were run, one failed"
+  fi
+  at_result="$at_result unexpectedly and inhibited subsequent tests."
+  at_color=$at_red
+else
+  # Don't you just love exponential explosion of the number of cases?
+  at_color=$at_red
+  case $at_xpass_count:$at_fail_count:$at_xfail_count in
+    # So far, so good.
+    0:0:0) at_result="$at_result $at_were successful." at_color=$at_grn ;;
+    0:0:*) at_result="$at_result behaved as expected." at_color=$at_lgn ;;
+
+    # Some unexpected failures
+    0:*:0) at_result="$at_result $at_were run,
+$at_fail_count failed unexpectedly." ;;
+
+    # Some failures, both expected and unexpected
+    0:*:1) at_result="$at_result $at_were run,
+$at_total_fail_count failed ($at_xfail_count expected failure)." ;;
+    0:*:*) at_result="$at_result $at_were run,
+$at_total_fail_count failed ($at_xfail_count expected failures)." ;;
+
+    # No unexpected failures, but some xpasses
+    *:0:*) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly." ;;
+
+    # No expected failures, but failures and xpasses
+    *:1:0) at_result="$at_result $at_were run,
+$at_unexpected_count did not behave as expected ($at_fail_count unexpected failure)." ;;
+    *:*:0) at_result="$at_result $at_were run,
+$at_unexpected_count did not behave as expected ($at_fail_count unexpected failures)." ;;
+
+    # All of them.
+    *:*:1) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly,
+$at_total_fail_count failed ($at_xfail_count expected failure)." ;;
+    *:*:*) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly,
+$at_total_fail_count failed ($at_xfail_count expected failures)." ;;
+  esac
+
+  if test $at_skip_count = 0 && test $at_run_count -gt 1; then
+    at_result="All $at_result"
+  fi
+fi
+
+# Now put skips in the mix.
+case $at_skip_count in
+  0) ;;
+  1) at_result="$at_result
+1 test was skipped." ;;
+  *) at_result="$at_result
+$at_skip_count tests were skipped." ;;
+esac
+
+if test $at_unexpected_count = 0; then
+  echo "$at_color$at_result$at_std"
+  echo "$at_result" >&5
+else
+  echo "${at_color}ERROR: $at_result$at_std" >&2
+  echo "ERROR: $at_result" >&5
+  {
+    echo
+    $as_echo "## ------------------------ ##
+## Summary of the failures. ##
+## ------------------------ ##"
+
+    # Summary of failed and skipped tests.
+    if test $at_fail_count != 0; then
+      echo "Failed tests:"
+      $SHELL "$at_myself" $at_fail_list --list
+      echo
+    fi
+    if test $at_skip_count != 0; then
+      echo "Skipped tests:"
+      $SHELL "$at_myself" $at_skip_list --list
+      echo
+    fi
+    if test $at_xpass_count != 0; then
+      echo "Unexpected passes:"
+      $SHELL "$at_myself" $at_xpass_list --list
+      echo
+    fi
+    if test $at_fail_count != 0; then
+      $as_echo "## ---------------------- ##
+## Detailed failed tests. ##
+## ---------------------- ##"
+      echo
+      for at_group in $at_fail_list
+      do
+	at_group_normalized=$at_group
+
+  eval 'while :; do
+    case $at_group_normalized in #(
+    '"$at_format"'*) break;;
+    esac
+    at_group_normalized=0$at_group_normalized
+  done'
+
+	cat "$at_suite_dir/$at_group_normalized/$as_me.log"
+	echo
+      done
+      echo
+    fi
+    if test -n "$at_top_srcdir"; then
+      sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## ${at_top_build_prefix}config.log ##
+_ASBOX
+      sed 's/^/| /' ${at_top_build_prefix}config.log
+      echo
+    fi
+  } >&5
+
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## $as_me.log was created. ##
+_ASBOX
+
+  echo
+  if $at_debug_p; then
+    at_msg='per-test log files'
+  else
+    at_msg="\`${at_testdir+${at_testdir}/}$as_me.log'"
+  fi
+  $as_echo "Please send $at_msg and all information you think might help:
+
+   To: <csardi.gabor at gmail.com>
+   Subject: [igraph 0.7.1] $as_me: $at_fail_list${at_fail_list:+ failed${at_xpass_list:+, }}$at_xpass_list${at_xpass_list:+ passed unexpectedly}
+
+You may investigate any problem if you feel able to do so, in which
+case the test suite provides a good starting point.  Its output may
+be found below \`${at_testdir+${at_testdir}/}$as_me.dir'.
+"
+  exit 1
+fi
+
+exit 0
+
+## ------------- ##
+## Actual tests. ##
+## ------------- ##
+#AT_START_1
+at_fn_group_banner 1 'version.at:26' \
+  "Simple version query (igraph_version): " "        " 1
+at_xfail=no
+(
+  $as_echo "1. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/version.at:28: \$CC \${abs_top_srcdir}/examples/simple/igraph_version.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "version.at:28"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_version.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/version.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/version.at:28: >expout"
+at_fn_check_prepare_trace "version.at:28"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/version.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/version.at:28: "
+at_fn_check_prepare_trace "version.at:28"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/version.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/version.at:28: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "version.at:28"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/version.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_1
+#AT_START_2
+at_fn_group_banner 2 'types.at:24' \
+  "Vector (vector_t): " "                            " 2
+at_xfail=no
+(
+  $as_echo "2. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:26: \$CC \${abs_top_srcdir}/examples/simple/vector.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/vector.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:26: cat \${abs_top_srcdir}/examples/'simple/vector.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/vector.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:26: "
+at_fn_check_prepare_trace "types.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_2
+#AT_START_3
+at_fn_group_banner 3 'types.at:29' \
+  "Vector (more) (vector_t): " "                     " 2
+at_xfail=no
+(
+  $as_echo "3. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:31: \$CC \${abs_top_srcdir}/examples/simple/vector2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/vector2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:31: cat \${abs_top_srcdir}/examples/'simple/vector2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/vector2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:31: "
+at_fn_check_prepare_trace "types.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_3
+#AT_START_4
+at_fn_group_banner 4 'types.at:34' \
+  "Vector (even more) (vector_t): " "                " 2
+at_xfail=no
+(
+  $as_echo "4. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:36: \$CC \${abs_top_srcdir}/examples/simple/vector3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/vector3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:36: >expout"
+at_fn_check_prepare_trace "types.at:36"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:36: "
+at_fn_check_prepare_trace "types.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_4
+#AT_START_5
+at_fn_group_banner 5 'types.at:39' \
+  "Matrix (matrix_t): " "                            " 2
+at_xfail=no
+(
+  $as_echo "5. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:41: \$CC \${abs_top_srcdir}/examples/simple/matrix.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:41"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/matrix.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:41: cat \${abs_top_srcdir}/examples/'simple/matrix.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:41"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/matrix.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:41: "
+at_fn_check_prepare_trace "types.at:41"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:41: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:41"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_5
+#AT_START_6
+at_fn_group_banner 6 'types.at:44' \
+  "Matrix (more) (matrix_t): " "                     " 2
+at_xfail=no
+(
+  $as_echo "6. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:46: \$CC \${abs_top_srcdir}/examples/simple/matrix2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:46"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/matrix2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:46: cat \${abs_top_srcdir}/examples/'simple/matrix2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:46"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/matrix2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:46: "
+at_fn_check_prepare_trace "types.at:46"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:46: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:46"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_6
+#AT_START_7
+at_fn_group_banner 7 'types.at:49' \
+  "Matrix (even more) (matrix_t): " "                " 2
+at_xfail=no
+(
+  $as_echo "7. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:51: \$CC \${abs_top_srcdir}/examples/simple/matrix3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:51"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/matrix3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:51: >expout"
+at_fn_check_prepare_trace "types.at:51"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:51: "
+at_fn_check_prepare_trace "types.at:51"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:51: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:51"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_7
+#AT_START_8
+at_fn_group_banner 8 'types.at:54' \
+  "Double ended queue (dqueue_t): " "                " 2
+at_xfail=no
+(
+  $as_echo "8. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:56: \$CC \${abs_top_srcdir}/examples/simple/dqueue.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:56"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/dqueue.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:56: cat \${abs_top_srcdir}/examples/'simple/dqueue.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:56"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/dqueue.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:56: "
+at_fn_check_prepare_trace "types.at:56"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:56: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:56"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_8
+#AT_START_9
+at_fn_group_banner 9 'types.at:59' \
+  "Vector of pointers (vector_ptr_t): " "            " 2
+at_xfail=no
+(
+  $as_echo "9. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:61: \$CC \${abs_top_srcdir}/examples/simple/vector_ptr.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:61"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/vector_ptr.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:61: >expout"
+at_fn_check_prepare_trace "types.at:61"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:61: "
+at_fn_check_prepare_trace "types.at:61"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:61: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:61"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_9
+#AT_START_10
+at_fn_group_banner 10 'types.at:64' \
+  "Stack (stack_t): " "                              " 2
+at_xfail=no
+(
+  $as_echo "10. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:66: \$CC \${abs_top_srcdir}/examples/simple/stack.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:66"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/stack.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:66: >expout"
+at_fn_check_prepare_trace "types.at:66"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:66: "
+at_fn_check_prepare_trace "types.at:66"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:66: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:66"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_10
+#AT_START_11
+at_fn_group_banner 11 'types.at:69' \
+  "Heap (heap_t): " "                                " 2
+at_xfail=no
+(
+  $as_echo "11. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:71: \$CC \${abs_top_srcdir}/examples/simple/heap.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:71"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/heap.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:71: >expout"
+at_fn_check_prepare_trace "types.at:71"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:71: "
+at_fn_check_prepare_trace "types.at:71"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:71: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:71"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_11
+#AT_START_12
+at_fn_group_banner 12 'types.at:74' \
+  "Indexed heap (indheap_t): " "                     " 2
+at_xfail=no
+(
+  $as_echo "12. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:76: \$CC \${abs_top_srcdir}/examples/simple/indheap.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:76"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/indheap.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:76: >expout"
+at_fn_check_prepare_trace "types.at:76"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:76: "
+at_fn_check_prepare_trace "types.at:76"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:76: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:76"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_12
+#AT_START_13
+at_fn_group_banner 13 'types.at:79' \
+  "Doubly indexed heap (d_indheap_t): " "            " 2
+at_xfail=no
+(
+  $as_echo "13. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:81: \$CC \${abs_top_srcdir}/examples/simple/d_indheap.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:81"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/d_indheap.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:81: cat \${abs_top_srcdir}/examples/'simple/d_indheap.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:81"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/d_indheap.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:81: "
+at_fn_check_prepare_trace "types.at:81"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:81: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:81"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_13
+#AT_START_14
+at_fn_group_banner 14 'types.at:84' \
+  "String vector (igraph_strvector_t): " "           " 2
+at_xfail=no
+(
+  $as_echo "14. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:86: \$CC \${abs_top_srcdir}/examples/simple/igraph_strvector.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:86"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_strvector.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:86: cat \${abs_top_srcdir}/examples/'simple/igraph_strvector.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:86"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_strvector.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:86: "
+at_fn_check_prepare_trace "types.at:86"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:86: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:86"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_14
+#AT_START_15
+at_fn_group_banner 15 'types.at:89' \
+  "Trie (igraph_trie_t): " "                         " 2
+at_xfail=no
+(
+  $as_echo "15. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:92: \$CC \${abs_top_srcdir}/examples/simple/igraph_trie.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:92"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_trie.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:92"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:92: cat \${abs_top_srcdir}/examples/'simple/igraph_trie.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:92"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_trie.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:92"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:92: "
+at_fn_check_prepare_trace "types.at:92"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:92"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:92: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:92"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:92"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_15
+#AT_START_16
+at_fn_group_banner 16 'types.at:95' \
+  "Partial Sum-Tree (igraph_psumtree_t): " "         " 2
+at_xfail=no
+(
+  $as_echo "16. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:97: \$CC \${abs_top_srcdir}/examples/simple/igraph_psumtree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:97"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_psumtree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:97"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:97: >expout"
+at_fn_check_prepare_trace "types.at:97"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:97"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:97: "
+at_fn_check_prepare_trace "types.at:97"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:97"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:97: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:97"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:97"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_16
+#AT_START_17
+at_fn_group_banner 17 'types.at:100' \
+  "Three dimensional array (igraph_array3_t): " "    " 2
+at_xfail=no
+(
+  $as_echo "17. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:102: \$CC \${abs_top_srcdir}/examples/simple/igraph_array.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:102"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_array.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:102: cat \${abs_top_srcdir}/examples/'simple/igraph_array.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:102"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_array.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:102: "
+at_fn_check_prepare_trace "types.at:102"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:102: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:102"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_17
+#AT_START_18
+at_fn_group_banner 18 'types.at:105' \
+  "Hash table (string->string) (igraph_hashtable_t): " "" 2
+at_xfail=no
+(
+  $as_echo "18. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:108: \$CC \${abs_top_srcdir}/examples/simple/igraph_hashtable.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:108"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_hashtable.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:108: cat \${abs_top_srcdir}/examples/'simple/igraph_hashtable.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:108"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_hashtable.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:108: "
+at_fn_check_prepare_trace "types.at:108"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:108: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:108"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_18
+#AT_START_19
+at_fn_group_banner 19 'types.at:111' \
+  "Special heap for minimum cuts (igraph_i_cutheap_t): " "" 2
+at_xfail=no
+(
+  $as_echo "19. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:114: \$CC \${abs_top_srcdir}/examples/simple/igraph_i_cutheap.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:114"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_i_cutheap.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:114"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:114: cat \${abs_top_srcdir}/examples/'simple/igraph_i_cutheap.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:114"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_i_cutheap.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:114"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:114: "
+at_fn_check_prepare_trace "types.at:114"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:114"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:114: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:114"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:114"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_19
+#AT_START_20
+at_fn_group_banner 20 'types.at:117' \
+  "Set (igraph_set_t): " "                           " 2
+at_xfail=no
+(
+  $as_echo "20. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:120: \$CC \${abs_top_srcdir}/examples/simple/igraph_set.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:120"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_set.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:120"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:120: cat \${abs_top_srcdir}/examples/'simple/igraph_set.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:120"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_set.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:120"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:120: "
+at_fn_check_prepare_trace "types.at:120"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:120"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:120: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:120"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:120"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_20
+#AT_START_21
+at_fn_group_banner 21 'types.at:123' \
+  "2-way heap (igraph_2wheap_t): " "                 " 2
+at_xfail=no
+(
+  $as_echo "21. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:125: \$CC \${abs_top_srcdir}/examples/simple/2wheap.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:125"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/2wheap.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:125"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:125: >expout"
+at_fn_check_prepare_trace "types.at:125"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:125"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:125: "
+at_fn_check_prepare_trace "types.at:125"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:125"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:125: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:125"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:125"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_21
+#AT_START_22
+at_fn_group_banner 22 'types.at:128' \
+  "Sparse matrix (igraph_sparsemat_t): " "           " 2
+at_xfail=no
+(
+  $as_echo "22. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:130: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:130"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:130"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:130: cat \${abs_top_srcdir}/examples/'simple/igraph_sparsemat.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:130"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_sparsemat.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:130"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:130: "
+at_fn_check_prepare_trace "types.at:130"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:130"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:130: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:130"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:130"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_22
+#AT_START_23
+at_fn_group_banner 23 'types.at:133' \
+  "Sparse matrix, multiplications (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "23. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:136: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat2.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm -lblas -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:136"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat2.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm -lblas -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:136"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:136: cat \${abs_top_srcdir}/examples/'simple/igraph_sparsemat2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:136"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_sparsemat2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:136"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:136: "
+at_fn_check_prepare_trace "types.at:136"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:136"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:136: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:136"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:136"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_23
+#AT_START_24
+at_fn_group_banner 24 'types.at:139' \
+  "Sparse matrix, indexing (igraph_sparsemat_t): " " " 2
+at_xfail=no
+(
+  $as_echo "24. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:142: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat3.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:142"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat3.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:142"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:142: cat \${abs_top_srcdir}/examples/'simple/igraph_sparsemat3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:142"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_sparsemat3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:142"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:142: "
+at_fn_check_prepare_trace "types.at:142"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:142"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:142: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:142"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:142"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_24
+#AT_START_25
+at_fn_group_banner 25 'types.at:145' \
+  "Sparse matrix, solvers (igraph_sparsemat_t): " "  " 2
+at_xfail=no
+(
+  $as_echo "25. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:148: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat4.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:148"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat4.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:148: cat \${abs_top_srcdir}/examples/'simple/igraph_sparsemat4.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:148"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_sparsemat4.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:148: "
+at_fn_check_prepare_trace "types.at:148"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:148: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:148"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_25
+#AT_START_26
+at_fn_group_banner 26 'types.at:151' \
+  "Sparse matrix, ARPACK eigensolver (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "26. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:153: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat5.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:153"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat5.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:153: cat \${abs_top_srcdir}/examples/'simple/igraph_sparsemat5.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:153"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_sparsemat5.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:153: "
+at_fn_check_prepare_trace "types.at:153"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:153: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:153"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_26
+#AT_START_27
+at_fn_group_banner 27 'types.at:156' \
+  "Sparse matrix, conversion to dense (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "27. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:158: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat6.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:158"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat6.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:158: >expout"
+at_fn_check_prepare_trace "types.at:158"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:158: "
+at_fn_check_prepare_trace "types.at:158"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:158: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:158"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_27
+#AT_START_28
+at_fn_group_banner 28 'types.at:161' \
+  "Sparse matrix, min & max (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "28. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:163: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat7.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:163"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat7.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:163: >expout"
+at_fn_check_prepare_trace "types.at:163"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:163: "
+at_fn_check_prepare_trace "types.at:163"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:163: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:163"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_28
+#AT_START_29
+at_fn_group_banner 29 'types.at:166' \
+  "Sparse matrix, other operations (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "29. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:168: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat8.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:168"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat8.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:168: >expout"
+at_fn_check_prepare_trace "types.at:168"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:168: "
+at_fn_check_prepare_trace "types.at:168"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:168: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:168"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_29
+#AT_START_30
+at_fn_group_banner 30 'types.at:171' \
+  "Sparse matrix, multiplications with dense (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "30. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:173: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat9.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:173"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat9.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:173: >expout"
+at_fn_check_prepare_trace "types.at:173"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:173: "
+at_fn_check_prepare_trace "types.at:173"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:173: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:173"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_30
+#AT_START_31
+at_fn_group_banner 31 'types.at:176' \
+  "Sparse matrix, is symmetric? (igraph_sparsemat_t): " "" 2
+at_xfail=no
+(
+  $as_echo "31. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:178: \$CC \${abs_top_srcdir}/examples/simple/igraph_sparsemat_is_symmetric.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:178"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_sparsemat_is_symmetric.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:178: >expout"
+at_fn_check_prepare_trace "types.at:178"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:178: "
+at_fn_check_prepare_trace "types.at:178"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:178: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:178"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_31
+#AT_START_32
+at_fn_group_banner 32 'types.at:181' \
+  "Another sparse matrix (igraph_spmatrix_t): " "    " 2
+at_xfail=no
+(
+  $as_echo "32. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:183: \$CC \${abs_top_srcdir}/examples/simple/spmatrix.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:183"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/spmatrix.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:183: cat \${abs_top_srcdir}/examples/'simple/spmatrix.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:183"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/spmatrix.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:183: "
+at_fn_check_prepare_trace "types.at:183"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:183: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:183"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_32
+#AT_START_33
+at_fn_group_banner 33 'types.at:186' \
+  "Arbitrarily big integers (igraph_biguint_t): " "  " 2
+at_xfail=no
+(
+  $as_echo "33. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:188: \$CC \${abs_top_srcdir}/examples/simple/biguint.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:188"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/biguint.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:188"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:188: cat \${abs_top_srcdir}/examples/'simple/biguint.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "types.at:188"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/biguint.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:188"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:188: "
+at_fn_check_prepare_trace "types.at:188"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:188"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:188: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:188"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:188"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_33
+#AT_START_34
+at_fn_group_banner 34 'types.at:191' \
+  "Marked double ended queue (igraph_marked_queue_t): " "" 2
+at_xfail=no
+(
+  $as_echo "34. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:193: \$CC \${abs_top_srcdir}/examples/simple/igraph_marked_queue.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:193"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_marked_queue.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:193"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:193: >expout"
+at_fn_check_prepare_trace "types.at:193"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:193"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:193: "
+at_fn_check_prepare_trace "types.at:193"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:193"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:193: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:193"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:193"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_34
+#AT_START_35
+at_fn_group_banner 35 'types.at:196' \
+  "Complex numbers (igraph_complex_t): " "           " 2
+at_xfail=no
+(
+  $as_echo "35. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/types.at:198: \$CC \${abs_top_srcdir}/examples/simple/igraph_complex.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:198"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_complex.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:198"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:198: >expout"
+at_fn_check_prepare_trace "types.at:198"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:198"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:198: "
+at_fn_check_prepare_trace "types.at:198"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:198"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/types.at:198: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "types.at:198"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/types.at:198"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_35
+#AT_START_36
+at_fn_group_banner 36 'basic.at:26' \
+  "Creating an empty graph (igraph_empty): " "       " 3
+at_xfail=no
+(
+  $as_echo "36. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:28: \$CC \${abs_top_srcdir}/examples/simple/igraph_empty.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:28"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_empty.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:28: >expout"
+at_fn_check_prepare_trace "basic.at:28"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:28: "
+at_fn_check_prepare_trace "basic.at:28"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:28: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:28"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_36
+#AT_START_37
+at_fn_group_banner 37 'basic.at:31' \
+  "Copying a graph (igraph_copy): " "                " 3
+at_xfail=no
+(
+  $as_echo "37. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:33: \$CC \${abs_top_srcdir}/examples/simple/igraph_copy.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:33"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_copy.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:33: >expout"
+at_fn_check_prepare_trace "basic.at:33"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:33: "
+at_fn_check_prepare_trace "basic.at:33"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:33: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:33"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_37
+#AT_START_38
+at_fn_group_banner 38 'basic.at:36' \
+  "Adding edges to a graph (igraph_add_edges): " "   " 3
+at_xfail=no
+(
+  $as_echo "38. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:39: \$CC \${abs_top_srcdir}/examples/simple/igraph_add_edges.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:39"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_add_edges.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:39: cat \${abs_top_srcdir}/examples/'simple/igraph_add_edges.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "basic.at:39"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_add_edges.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:39: "
+at_fn_check_prepare_trace "basic.at:39"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:39: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:39"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_38
+#AT_START_39
+at_fn_group_banner 39 'basic.at:42' \
+  "Adding vertices (igraph_add_vertices): " "        " 3
+at_xfail=no
+(
+  $as_echo "39. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:44: \$CC \${abs_top_srcdir}/examples/simple/igraph_add_vertices.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:44"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_add_vertices.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:44"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:44: >expout"
+at_fn_check_prepare_trace "basic.at:44"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:44"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:44: "
+at_fn_check_prepare_trace "basic.at:44"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:44"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:44: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:44"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:44"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_39
+#AT_START_40
+at_fn_group_banner 40 'basic.at:47' \
+  "Deleting edges (igraph_delete_edges): " "         " 3
+at_xfail=no
+(
+  $as_echo "40. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:49: \$CC \${abs_top_srcdir}/examples/simple/igraph_delete_edges.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:49"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_delete_edges.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:49: >expout"
+at_fn_check_prepare_trace "basic.at:49"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:49: "
+at_fn_check_prepare_trace "basic.at:49"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:49: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:49"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_40
+#AT_START_41
+at_fn_group_banner 41 'basic.at:52' \
+  "Deleting vertices (igraph_delete_vertices): " "   " 3
+at_xfail=no
+(
+  $as_echo "41. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:54: \$CC \${abs_top_srcdir}/examples/simple/igraph_delete_vertices.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:54"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_delete_vertices.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:54: >expout"
+at_fn_check_prepare_trace "basic.at:54"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:54: "
+at_fn_check_prepare_trace "basic.at:54"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:54: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:54"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_41
+#AT_START_42
+at_fn_group_banner 42 'basic.at:57' \
+  "Neighbors (igraph_neighbors): " "                 " 3
+at_xfail=no
+(
+  $as_echo "42. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:59: \$CC \${abs_top_srcdir}/examples/simple/igraph_neighbors.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:59"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_neighbors.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:59: cat \${abs_top_srcdir}/examples/'simple/igraph_neighbors.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "basic.at:59"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_neighbors.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:59: "
+at_fn_check_prepare_trace "basic.at:59"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:59: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:59"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_42
+#AT_START_43
+at_fn_group_banner 43 'basic.at:62' \
+  "Is the graph directed? (igraph_is_directed): " "  " 3
+at_xfail=no
+(
+  $as_echo "43. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:64: \$CC \${abs_top_srcdir}/examples/simple/igraph_is_directed.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:64"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_is_directed.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:64: >expout"
+at_fn_check_prepare_trace "basic.at:64"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:64: "
+at_fn_check_prepare_trace "basic.at:64"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:64: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:64"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_43
+#AT_START_44
+at_fn_group_banner 44 'basic.at:67' \
+  "Degree of the vertices (igraph_degree): " "       " 3
+at_xfail=no
+(
+  $as_echo "44. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:69: \$CC \${abs_top_srcdir}/examples/simple/igraph_degree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:69"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_degree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:69: cat \${abs_top_srcdir}/examples/'simple/igraph_degree.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "basic.at:69"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_degree.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:69: "
+at_fn_check_prepare_trace "basic.at:69"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:69: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:69"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_44
+#AT_START_45
+at_fn_group_banner 45 'basic.at:72' \
+  "Query edge ids (igraph_get_eid): " "              " 3
+at_xfail=no
+(
+  $as_echo "45. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:74: \$CC \${abs_top_srcdir}/examples/simple/igraph_get_eid.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:74"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_get_eid.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:74"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:74: cat \${abs_top_srcdir}/examples/'simple/igraph_get_eid.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "basic.at:74"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_get_eid.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:74"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:74: "
+at_fn_check_prepare_trace "basic.at:74"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:74"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:74: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:74"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:74"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_45
+#AT_START_46
+at_fn_group_banner 46 'basic.at:77' \
+  "Query many edge ids (igraph_get_eids): " "        " 3
+at_xfail=no
+(
+  $as_echo "46. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:79: \$CC \${abs_top_srcdir}/examples/simple/igraph_get_eids.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:79"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_get_eids.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:79: cat \${abs_top_srcdir}/examples/'simple/igraph_get_eids.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "basic.at:79"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_get_eids.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:79: "
+at_fn_check_prepare_trace "basic.at:79"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/basic.at:79: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "basic.at:79"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/basic.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_46
+#AT_START_47
+at_fn_group_banner 47 'iterators.at:24' \
+  "Vertices in a vector (igraph_vs_vector): " "      " 4
+at_xfail=no
+(
+  $as_echo "47. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_vs_vector.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_vs_vector.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_vs_vector.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "iterators.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_vs_vector.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:26: "
+at_fn_check_prepare_trace "iterators.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_47
+#AT_START_48
+at_fn_group_banner 48 'iterators.at:29' \
+  "Non-adjacent vertices (igraph_vs_nonadj): " "     " 4
+at_xfail=no
+(
+  $as_echo "48. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_vs_nonadj.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_vs_nonadj.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:31: cat \${abs_top_srcdir}/examples/'simple/igraph_vs_nonadj.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "iterators.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_vs_nonadj.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:31: "
+at_fn_check_prepare_trace "iterators.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_48
+#AT_START_49
+at_fn_group_banner 49 'iterators.at:34' \
+  "Sequence (igraph_vs_seq): " "                     " 4
+at_xfail=no
+(
+  $as_echo "49. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:36: \$CC \${abs_top_srcdir}/examples/simple/igraph_vs_seq.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_vs_seq.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:36: cat \${abs_top_srcdir}/examples/'simple/igraph_vs_seq.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "iterators.at:36"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_vs_seq.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:36: "
+at_fn_check_prepare_trace "iterators.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_49
+#AT_START_50
+at_fn_group_banner 50 'iterators.at:49' \
+  "Edges given by end points (igraph_es_pairs): " "  " 4
+at_xfail=no
+(
+  $as_echo "50. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:51: \$CC \${abs_top_srcdir}/examples/simple/igraph_es_pairs.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:51"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_es_pairs.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:51: >expout"
+at_fn_check_prepare_trace "iterators.at:51"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:51: "
+at_fn_check_prepare_trace "iterators.at:51"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:51: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:51"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_50
+#AT_START_51
+at_fn_group_banner 51 'iterators.at:54' \
+  "Edges in a path (igraph_es_path): " "             " 4
+at_xfail=no
+(
+  $as_echo "51. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:56: \$CC \${abs_top_srcdir}/examples/simple/igraph_es_path.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:56"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_es_path.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:56: >expout"
+at_fn_check_prepare_trace "iterators.at:56"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:56: "
+at_fn_check_prepare_trace "iterators.at:56"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/iterators.at:56: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "iterators.at:56"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/iterators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_51
+#AT_START_52
+at_fn_group_banner 52 'structure_generators.at:24' \
+  "Simple graph creation (igraph_create): " "        " 5
+at_xfail=no
+(
+  $as_echo "52. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_create.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_create.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:26: >expout"
+at_fn_check_prepare_trace "structure_generators.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:26: "
+at_fn_check_prepare_trace "structure_generators.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_52
+#AT_START_53
+at_fn_group_banner 53 'structure_generators.at:29' \
+  "Barabasi-Albert model (igraph_barabasi_game):" "  " 5
+at_xfail=no
+(
+  $as_echo "53. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_barabasi_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_barabasi_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:31: >expout"
+at_fn_check_prepare_trace "structure_generators.at:31"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:31: "
+at_fn_check_prepare_trace "structure_generators.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_53
+#AT_START_54
+at_fn_group_banner 54 'structure_generators.at:34' \
+  "More Barabasi-Albert model (igraph_barabasi_game):" "" 5
+at_xfail=no
+(
+  $as_echo "54. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:36: \$CC \${abs_top_srcdir}/examples/simple/igraph_barabasi_game2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_barabasi_game2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:36: >expout"
+at_fn_check_prepare_trace "structure_generators.at:36"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:36: "
+at_fn_check_prepare_trace "structure_generators.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_54
+#AT_START_55
+at_fn_group_banner 55 'structure_generators.at:39' \
+  "Erdos-Renyi model (igraph_erdos_renyi_game):" "   " 5
+at_xfail=no
+(
+  $as_echo "55. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:41: \$CC \${abs_top_srcdir}/examples/simple/igraph_erdos_renyi_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:41"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_erdos_renyi_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:41: >expout"
+at_fn_check_prepare_trace "structure_generators.at:41"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:41: "
+at_fn_check_prepare_trace "structure_generators.at:41"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:41: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:41"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_55
+#AT_START_56
+at_fn_group_banner 56 'structure_generators.at:44' \
+  "Degree sequence (igraph_degree_sequence_game):" " " 5
+at_xfail=no
+(
+  $as_echo "56. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:46: \$CC \${abs_top_srcdir}/examples/simple/igraph_degree_sequence_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:46"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_degree_sequence_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:46: cat \${abs_top_srcdir}/examples/'simple/igraph_degree_sequence_game.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structure_generators.at:46"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_degree_sequence_game.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:46: "
+at_fn_check_prepare_trace "structure_generators.at:46"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:46: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:46"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_56
+#AT_START_57
+at_fn_group_banner 57 'structure_generators.at:49' \
+  "k-regular graphs (igraph_k_regular_game):" "      " 5
+at_xfail=no
+(
+  $as_echo "57. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:51: \$CC \${abs_top_srcdir}/examples/simple/igraph_k_regular_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:51"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_k_regular_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:51: cat \${abs_top_srcdir}/examples/'simple/igraph_k_regular_game.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structure_generators.at:51"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_k_regular_game.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:51: "
+at_fn_check_prepare_trace "structure_generators.at:51"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:51: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:51"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_57
+#AT_START_58
+at_fn_group_banner 58 'structure_generators.at:54' \
+  "Growing random (igraph_growing_random_game):" "   " 5
+at_xfail=no
+(
+  $as_echo "58. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:56: \$CC \${abs_top_srcdir}/examples/simple/igraph_growing_random_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:56"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_growing_random_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:56: >expout"
+at_fn_check_prepare_trace "structure_generators.at:56"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:56: "
+at_fn_check_prepare_trace "structure_generators.at:56"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:56: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:56"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_58
+#AT_START_59
+at_fn_group_banner 59 'structure_generators.at:59' \
+  "Preference model (igraph_preference_game):" "     " 5
+at_xfail=no
+(
+  $as_echo "59. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:61: \$CC \${abs_top_srcdir}/examples/simple/igraph_preference_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:61"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_preference_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:61: >expout"
+at_fn_check_prepare_trace "structure_generators.at:61"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:61: "
+at_fn_check_prepare_trace "structure_generators.at:61"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:61: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:61"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_59
+#AT_START_60
+at_fn_group_banner 60 'structure_generators.at:64' \
+  "From adjacency matrix (igraph_adjacency):" "      " 5
+at_xfail=no
+(
+  $as_echo "60. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:66: \$CC \${abs_top_srcdir}/examples/simple/igraph_adjacency.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:66"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_adjacency.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:66: >expout"
+at_fn_check_prepare_trace "structure_generators.at:66"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:66: "
+at_fn_check_prepare_trace "structure_generators.at:66"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:66: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:66"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_60
+#AT_START_61
+at_fn_group_banner 61 'structure_generators.at:69' \
+  "From weighted adjacency matrix (igraph_weighted_adjacency):" "" 5
+at_xfail=no
+(
+  $as_echo "61. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:71: \$CC \${abs_top_srcdir}/examples/simple/igraph_weighted_adjacency.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:71"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_weighted_adjacency.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:71: cat \${abs_top_srcdir}/examples/'simple/igraph_weighted_adjacency.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structure_generators.at:71"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_weighted_adjacency.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:71: "
+at_fn_check_prepare_trace "structure_generators.at:71"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:71: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:71"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_61
+#AT_START_62
+at_fn_group_banner 62 'structure_generators.at:74' \
+  "Star graph (igraph_star):" "                      " 5
+at_xfail=no
+(
+  $as_echo "62. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:76: \$CC \${abs_top_srcdir}/examples/simple/igraph_star.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:76"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_star.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:76: >expout"
+at_fn_check_prepare_trace "structure_generators.at:76"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:76: "
+at_fn_check_prepare_trace "structure_generators.at:76"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:76: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:76"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:76"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_62
+#AT_START_63
+at_fn_group_banner 63 'structure_generators.at:79' \
+  "Lattice graph (igraph_lattice):" "                " 5
+at_xfail=no
+(
+  $as_echo "63. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:81: \$CC \${abs_top_srcdir}/examples/simple/igraph_lattice.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:81"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lattice.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:81: >expout"
+at_fn_check_prepare_trace "structure_generators.at:81"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:81: "
+at_fn_check_prepare_trace "structure_generators.at:81"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:81: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:81"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_63
+#AT_START_64
+at_fn_group_banner 64 'structure_generators.at:84' \
+  "Ring graph (igraph_ring):" "                      " 5
+at_xfail=no
+(
+  $as_echo "64. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:86: \$CC \${abs_top_srcdir}/examples/simple/igraph_ring.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:86"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_ring.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:86: >expout"
+at_fn_check_prepare_trace "structure_generators.at:86"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:86: "
+at_fn_check_prepare_trace "structure_generators.at:86"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:86: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:86"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:86"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_64
+#AT_START_65
+at_fn_group_banner 65 'structure_generators.at:89' \
+  "Tree graph (igraph_tree):" "                      " 5
+at_xfail=no
+(
+  $as_echo "65. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:91: \$CC \${abs_top_srcdir}/examples/simple/igraph_tree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:91"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_tree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:91: >expout"
+at_fn_check_prepare_trace "structure_generators.at:91"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:91: "
+at_fn_check_prepare_trace "structure_generators.at:91"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:91: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:91"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_65
+#AT_START_66
+at_fn_group_banner 66 'structure_generators.at:94' \
+  "Full graph (igraph_full):" "                      " 5
+at_xfail=no
+(
+  $as_echo "66. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:96: \$CC \${abs_top_srcdir}/examples/simple/igraph_full.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:96"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_full.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:96: >expout"
+at_fn_check_prepare_trace "structure_generators.at:96"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:96: "
+at_fn_check_prepare_trace "structure_generators.at:96"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:96: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:96"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_66
+#AT_START_67
+at_fn_group_banner 67 'structure_generators.at:99' \
+  "Graph atlas (igraph_atlas):" "                    " 5
+at_xfail=no
+(
+  $as_echo "67. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:101: \$CC \${abs_top_srcdir}/examples/simple/igraph_atlas.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:101"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_atlas.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:101: cat \${abs_top_srcdir}/examples/'simple/igraph_atlas.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structure_generators.at:101"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_atlas.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:101: "
+at_fn_check_prepare_trace "structure_generators.at:101"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:101: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:101"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_67
+#AT_START_68
+at_fn_group_banner 68 'structure_generators.at:104' \
+  "Small graph (igraph_small):" "                    " 5
+at_xfail=no
+(
+  $as_echo "68. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:106: \$CC \${abs_top_srcdir}/examples/simple/igraph_small.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:106"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_small.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:106"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:106: cat \${abs_top_srcdir}/examples/'simple/igraph_small.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structure_generators.at:106"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_small.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:106"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:106: "
+at_fn_check_prepare_trace "structure_generators.at:106"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:106"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:106: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:106"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:106"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_68
+#AT_START_69
+at_fn_group_banner 69 'structure_generators.at:109' \
+  "Geomeric random graphs (igraph_grg_game):" "      " 5
+at_xfail=no
+(
+  $as_echo "69. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:111: \$CC \${abs_top_srcdir}/examples/simple/igraph_grg_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:111"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_grg_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:111"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:111: >expout"
+at_fn_check_prepare_trace "structure_generators.at:111"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:111"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:111: "
+at_fn_check_prepare_trace "structure_generators.at:111"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:111"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:111: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:111"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:111"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_69
+#AT_START_70
+at_fn_group_banner 70 'structure_generators.at:114' \
+  "Graphs in LCF notation (igraph_lcf{,_vector}):" " " 5
+at_xfail=no
+(
+  $as_echo "70. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:116: \$CC \${abs_top_srcdir}/examples/simple/igraph_lcf.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:116"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lcf.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:116"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:116: >expout"
+at_fn_check_prepare_trace "structure_generators.at:116"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:116"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:116: "
+at_fn_check_prepare_trace "structure_generators.at:116"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:116"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:116: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:116"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:116"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_70
+#AT_START_71
+at_fn_group_banner 71 'structure_generators.at:119' \
+  "Watts-Strogatz graphs (igraph_watts_strogatz_game):" "" 5
+at_xfail=no
+(
+  $as_echo "71. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:121: \$CC \${abs_top_srcdir}/examples/simple/watts_strogatz_game.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:121"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/watts_strogatz_game.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:121"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:121: >expout"
+at_fn_check_prepare_trace "structure_generators.at:121"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:121"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:121: "
+at_fn_check_prepare_trace "structure_generators.at:121"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:121"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structure_generators.at:121: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structure_generators.at:121"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structure_generators.at:121"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_71
+#AT_START_72
+at_fn_group_banner 72 'structural_properties.at:24' \
+  "Two vertices connected by an edge:" "             " 6
+at_xfail=no
+(
+  $as_echo "72. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_are_connected.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_are_connected.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:26: >expout"
+at_fn_check_prepare_trace "structural_properties.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:26: "
+at_fn_check_prepare_trace "structural_properties.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_72
+#AT_START_73
+at_fn_group_banner 73 'structural_properties.at:29' \
+  "Density of a graph (igraph_density):" "           " 6
+at_xfail=no
+(
+  $as_echo "73. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_density.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_density.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:31: cat \${abs_top_srcdir}/examples/'simple/igraph_density.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_density.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:31: "
+at_fn_check_prepare_trace "structural_properties.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_73
+#AT_START_74
+at_fn_group_banner 74 'structural_properties.at:34' \
+  "Diameter of a graph (igraph_diameter):" "         " 6
+at_xfail=no
+(
+  $as_echo "74. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:36: \$CC \${abs_top_srcdir}/examples/simple/igraph_diameter.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_diameter.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:36: cat \${abs_top_srcdir}/examples/'simple/igraph_diameter.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:36"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_diameter.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:36: "
+at_fn_check_prepare_trace "structural_properties.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_74
+#AT_START_75
+at_fn_group_banner 75 'structural_properties.at:39' \
+  "Average geodesic length (igraph_average_path_length): " "" 6
+at_xfail=no
+(
+  $as_echo "75. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:41: \$CC \${abs_top_srcdir}/examples/simple/igraph_average_path_length.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:41"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_average_path_length.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:41: >expout"
+at_fn_check_prepare_trace "structural_properties.at:41"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:41: "
+at_fn_check_prepare_trace "structural_properties.at:41"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:41: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:41"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_75
+#AT_START_76
+at_fn_group_banner 76 'structural_properties.at:44' \
+  "Google PageRank (igraph_pagerank): " "            " 6
+at_xfail=no
+(
+  $as_echo "76. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:46: \$CC \${abs_top_srcdir}/examples/simple/igraph_pagerank.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:46"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_pagerank.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:46: cat \${abs_top_srcdir}/examples/'simple/igraph_pagerank.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:46"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_pagerank.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:46: "
+at_fn_check_prepare_trace "structural_properties.at:46"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:46: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:46"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_76
+#AT_START_77
+at_fn_group_banner 77 'structural_properties.at:49' \
+  "Random rewiring (igraph_rewire): " "              " 6
+at_xfail=no
+(
+  $as_echo "77. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:51: \$CC \${abs_top_srcdir}/examples/simple/igraph_rewire.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:51"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_rewire.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:51: cat \${abs_top_srcdir}/examples/'simple/igraph_rewire.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:51"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_rewire.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:51: "
+at_fn_check_prepare_trace "structural_properties.at:51"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:51: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:51"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_77
+#AT_START_78
+at_fn_group_banner 78 'structural_properties.at:54' \
+  "Get the shortest paths (igraph_get_shortest_paths): " "" 6
+at_xfail=no
+(
+  $as_echo "78. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:57: \$CC \${abs_top_srcdir}/examples/simple/igraph_get_shortest_paths.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:57"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_get_shortest_paths.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:57: cat \${abs_top_srcdir}/examples/'simple/igraph_get_shortest_paths.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:57"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_get_shortest_paths.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:57: "
+at_fn_check_prepare_trace "structural_properties.at:57"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:57: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:57"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_78
+#AT_START_79
+at_fn_group_banner 79 'structural_properties.at:60' \
+  "Get the shortest paths #2 (igraph_get_shortest_paths): " "" 6
+at_xfail=no
+(
+  $as_echo "79. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:63: \$CC \${abs_top_srcdir}/examples/simple/igraph_get_shortest_paths2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:63"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_get_shortest_paths2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:63: cat \${abs_top_srcdir}/examples/'simple/igraph_get_shortest_paths2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:63"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_get_shortest_paths2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:63: "
+at_fn_check_prepare_trace "structural_properties.at:63"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:63: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:63"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_79
+#AT_START_80
+at_fn_group_banner 80 'structural_properties.at:66' \
+  "Weighted shortest paths (Dijkstra): " "           " 6
+at_xfail=no
+(
+  $as_echo "80. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:68: \$CC \${abs_top_srcdir}/examples/simple/dijkstra.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:68"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/dijkstra.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:68: cat \${abs_top_srcdir}/examples/'simple/dijkstra.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:68"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/dijkstra.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:68: "
+at_fn_check_prepare_trace "structural_properties.at:68"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:68: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:68"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_80
+#AT_START_81
+at_fn_group_banner 81 'structural_properties.at:71' \
+  "Weighted shortest paths (Bellman-Ford): " "       " 6
+at_xfail=no
+(
+  $as_echo "81. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:73: \$CC \${abs_top_srcdir}/examples/simple/bellman_ford.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:73"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/bellman_ford.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:73: cat \${abs_top_srcdir}/examples/'simple/bellman_ford.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:73"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/bellman_ford.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:73: "
+at_fn_check_prepare_trace "structural_properties.at:73"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:73: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:73"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_81
+#AT_START_82
+at_fn_group_banner 82 'structural_properties.at:76' \
+  "Get the weighted shortest paths (Dijkstra): " "   " 6
+at_xfail=no
+(
+  $as_echo "82. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:79: \$CC \${abs_top_srcdir}/examples/simple/igraph_get_shortest_paths_dijkstra.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:79"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_get_shortest_paths_dijkstra.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:79: cat \${abs_top_srcdir}/examples/'simple/igraph_get_shortest_paths_dijkstra.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:79"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_get_shortest_paths_dijkstra.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:79: "
+at_fn_check_prepare_trace "structural_properties.at:79"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:79: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:79"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_82
+#AT_START_83
+at_fn_group_banner 83 'structural_properties.at:82' \
+  "Get all weighted shortest paths (Dijkstra): " "   " 6
+at_xfail=no
+(
+  $as_echo "83. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:85: \$CC \${abs_top_srcdir}/examples/simple/igraph_get_all_shortest_paths_dijkstra.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:85"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_get_all_shortest_paths_dijkstra.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:85: cat \${abs_top_srcdir}/examples/'simple/igraph_get_all_shortest_paths_dijkstra.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:85"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_get_all_shortest_paths_dijkstra.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:85: "
+at_fn_check_prepare_trace "structural_properties.at:85"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:85: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:85"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_83
+#AT_START_84
+at_fn_group_banner 84 'structural_properties.at:88' \
+  "Shortest path wrappers for single target node: " "" 6
+at_xfail=no
+(
+  $as_echo "84. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:91: \$CC \${abs_top_srcdir}/examples/simple/single_target_shortest_path.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:91"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/single_target_shortest_path.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:91: cat \${abs_top_srcdir}/examples/'simple/single_target_shortest_path.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:91"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/single_target_shortest_path.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:91: "
+at_fn_check_prepare_trace "structural_properties.at:91"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:91: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:91"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:91"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_84
+#AT_START_85
+at_fn_group_banner 85 'structural_properties.at:94' \
+  "Betweenness (igraph_betweenness): " "             " 6
+at_xfail=no
+(
+  $as_echo "85. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:96: \$CC \${abs_top_srcdir}/examples/simple/igraph_betweenness.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:96"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_betweenness.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:96: >expout"
+at_fn_check_prepare_trace "structural_properties.at:96"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:96: "
+at_fn_check_prepare_trace "structural_properties.at:96"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:96: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:96"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:96"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_85
+#AT_START_86
+at_fn_group_banner 86 'structural_properties.at:99' \
+  "Betweenness, big integers (igraph_betweenness): " "" 6
+at_xfail=no
+(
+  $as_echo "86. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:101: \$CC \${abs_top_srcdir}/examples/simple/biguint_betweenness.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:101"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/biguint_betweenness.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:101: >expout"
+at_fn_check_prepare_trace "structural_properties.at:101"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:101: "
+at_fn_check_prepare_trace "structural_properties.at:101"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:101: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:101"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:101"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_86
+#AT_START_87
+at_fn_group_banner 87 'structural_properties.at:104' \
+  "Edge betweenness (igraph_edge_betweenness): " "   " 6
+at_xfail=no
+(
+  $as_echo "87. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:107: \$CC \${abs_top_srcdir}/examples/simple/igraph_edge_betweenness.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:107"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_edge_betweenness.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:107"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:107: cat \${abs_top_srcdir}/examples/'simple/igraph_edge_betweenness.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:107"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_edge_betweenness.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:107"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:107: "
+at_fn_check_prepare_trace "structural_properties.at:107"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:107"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:107: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:107"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:107"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_87
+#AT_START_88
+at_fn_group_banner 88 'structural_properties.at:110' \
+  "Transitivity (igraph_transitivity): " "           " 6
+at_xfail=no
+(
+  $as_echo "88. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:112: \$CC \${abs_top_srcdir}/examples/simple/igraph_transitivity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:112"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_transitivity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:112"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:112: >expout"
+at_fn_check_prepare_trace "structural_properties.at:112"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:112"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:112: "
+at_fn_check_prepare_trace "structural_properties.at:112"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:112"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:112: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:112"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:112"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_88
+#AT_START_89
+at_fn_group_banner 89 'structural_properties.at:115' \
+  "Local transitivity (igraph_local_transitivity): " "" 6
+at_xfail=no
+(
+  $as_echo "89. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:117: \$CC \${abs_top_srcdir}/examples/simple/igraph_local_transitivity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:117"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_local_transitivity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:117"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:117: >expout"
+at_fn_check_prepare_trace "structural_properties.at:117"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:117"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:117: "
+at_fn_check_prepare_trace "structural_properties.at:117"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:117"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:117: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:117"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:117"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_89
+#AT_START_90
+at_fn_group_banner 90 'structural_properties.at:120' \
+  "Reciprocity (igraph_reciprocity): " "             " 6
+at_xfail=no
+(
+  $as_echo "90. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:122: \$CC \${abs_top_srcdir}/examples/simple/igraph_reciprocity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:122"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_reciprocity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:122"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:122: >expout"
+at_fn_check_prepare_trace "structural_properties.at:122"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:122"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:122: "
+at_fn_check_prepare_trace "structural_properties.at:122"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:122"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:122: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:122"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:122"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_90
+#AT_START_91
+at_fn_group_banner 91 'structural_properties.at:125' \
+  "Minimum spanning tree (igraph_minimum_spanning_tree_*): " "" 6
+at_xfail=no
+(
+  $as_echo "91. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:128: \$CC \${abs_top_srcdir}/examples/simple/igraph_minimum_spanning_tree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:128"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_minimum_spanning_tree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:128"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:128: cat \${abs_top_srcdir}/examples/'simple/igraph_minimum_spanning_tree.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:128"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_minimum_spanning_tree.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:128"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:128: "
+at_fn_check_prepare_trace "structural_properties.at:128"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:128"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:128: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:128"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:128"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_91
+#AT_START_92
+at_fn_group_banner 92 'structural_properties.at:131' \
+  "Cocitation and bibcoupling (igraph_cocitation,igraph_bibcoupling):" "" 6
+at_xfail=no
+(
+  $as_echo "92. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:133: \$CC \${abs_top_srcdir}/examples/simple/igraph_cocitation.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:133"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_cocitation.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:133"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:133: cat \${abs_top_srcdir}/examples/'simple/igraph_cocitation.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:133"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_cocitation.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:133"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:133: "
+at_fn_check_prepare_trace "structural_properties.at:133"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:133"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:133: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:133"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:133"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_92
+#AT_START_93
+at_fn_group_banner 93 'structural_properties.at:136' \
+  "Similarity coefficients (igraph_similarity_*):" " " 6
+at_xfail=no
+(
+  $as_echo "93. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:138: \$CC \${abs_top_srcdir}/examples/simple/igraph_similarity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:138"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_similarity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:138"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:138: cat \${abs_top_srcdir}/examples/'simple/igraph_similarity.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:138"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_similarity.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:138"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:138: "
+at_fn_check_prepare_trace "structural_properties.at:138"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:138"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:138: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:138"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:138"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_93
+#AT_START_94
+at_fn_group_banner 94 'structural_properties.at:141' \
+  "Simplification of non-simple graphs (igraph_simplify): " "" 6
+at_xfail=no
+(
+  $as_echo "94. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:143: \$CC \${abs_top_srcdir}/examples/simple/igraph_simplify.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:143"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_simplify.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:143"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:143: cat \${abs_top_srcdir}/examples/'simple/igraph_simplify.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:143"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_simplify.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:143"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:143: "
+at_fn_check_prepare_trace "structural_properties.at:143"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:143"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:143: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:143"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:143"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_94
+#AT_START_95
+at_fn_group_banner 95 'structural_properties.at:146' \
+  "Topological sorting (igraph_topological_sorting, igraph_is_dag): " "" 6
+at_xfail=no
+(
+  $as_echo "95. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:148: \$CC \${abs_top_srcdir}/examples/simple/igraph_topological_sorting.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:148"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_topological_sorting.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:148: cat \${abs_top_srcdir}/examples/'simple/igraph_topological_sorting.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:148"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_topological_sorting.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:148: "
+at_fn_check_prepare_trace "structural_properties.at:148"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:148: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:148"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:148"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_95
+#AT_START_96
+at_fn_group_banner 96 'structural_properties.at:151' \
+  "Feedback arc sets, Eades heuristics (igraph_feedback_arc_set): " "" 6
+at_xfail=no
+(
+  $as_echo "96. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:153: \$CC \${abs_top_srcdir}/examples/simple/igraph_feedback_arc_set.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:153"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_feedback_arc_set.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:153: cat \${abs_top_srcdir}/examples/'simple/igraph_feedback_arc_set.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:153"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_feedback_arc_set.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:153: "
+at_fn_check_prepare_trace "structural_properties.at:153"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:153: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:153"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_96
+#AT_START_97
+at_fn_group_banner 97 'structural_properties.at:156' \
+  "Feedback arc sets, integer programming (igraph_feedback_arc_set): " "" 6
+at_xfail=no
+(
+  $as_echo "97. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:158: \$CC \${abs_top_srcdir}/examples/simple/igraph_feedback_arc_set_ip.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:158"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_feedback_arc_set_ip.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:158: cat \${abs_top_srcdir}/examples/'simple/igraph_feedback_arc_set_ip.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:158"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_feedback_arc_set_ip.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:158: "
+at_fn_check_prepare_trace "structural_properties.at:158"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:158: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:158"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:158"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_97
+#AT_START_98
+at_fn_group_banner 98 'structural_properties.at:161' \
+  "Loop edges test (igraph_is_loop): " "             " 6
+at_xfail=no
+(
+  $as_echo "98. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:163: \$CC \${abs_top_srcdir}/examples/simple/igraph_is_loop.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:163"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_is_loop.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:163: cat \${abs_top_srcdir}/examples/'simple/igraph_is_loop.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:163"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_is_loop.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:163: "
+at_fn_check_prepare_trace "structural_properties.at:163"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:163: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:163"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:163"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_98
+#AT_START_99
+at_fn_group_banner 99 'structural_properties.at:166' \
+  "Multiple edges test (igraph_is_multiple): " "     " 6
+at_xfail=no
+(
+  $as_echo "99. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:168: \$CC \${abs_top_srcdir}/examples/simple/igraph_is_multiple.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:168"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_is_multiple.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:168: cat \${abs_top_srcdir}/examples/'simple/igraph_is_multiple.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:168"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_is_multiple.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:168: "
+at_fn_check_prepare_trace "structural_properties.at:168"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:168: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:168"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:168"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_99
+#AT_START_100
+at_fn_group_banner 100 'structural_properties.at:171' \
+  "Multiple edges test (igraph_has_multiple): " "    " 6
+at_xfail=no
+(
+  $as_echo "100. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:173: \$CC \${abs_top_srcdir}/examples/simple/igraph_has_multiple.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:173"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_has_multiple.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:173: >expout"
+at_fn_check_prepare_trace "structural_properties.at:173"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:173: "
+at_fn_check_prepare_trace "structural_properties.at:173"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:173: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:173"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_100
+#AT_START_101
+at_fn_group_banner 101 'structural_properties.at:176' \
+  "Girth (igraph_girth): " "                         " 6
+at_xfail=no
+(
+  $as_echo "101. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:178: \$CC \${abs_top_srcdir}/examples/simple/igraph_girth.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:178"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_girth.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:178: >expout"
+at_fn_check_prepare_trace "structural_properties.at:178"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:178: "
+at_fn_check_prepare_trace "structural_properties.at:178"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:178: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:178"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_101
+#AT_START_102
+at_fn_group_banner 102 'structural_properties.at:181' \
+  "Convergence degree (igraph_convergence_degree): " "" 6
+at_xfail=no
+(
+  $as_echo "102. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:183: \$CC \${abs_top_srcdir}/examples/simple/igraph_convergence_degree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:183"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_convergence_degree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:183: cat \${abs_top_srcdir}/examples/'simple/igraph_convergence_degree.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:183"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_convergence_degree.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:183: "
+at_fn_check_prepare_trace "structural_properties.at:183"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:183: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:183"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:183"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_102
+#AT_START_103
+at_fn_group_banner 103 'structural_properties.at:186' \
+  "Assortativity coefficient (igraph_assortativity): " "" 6
+at_xfail=no
+(
+  $as_echo "103. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:189: \$CC \${abs_top_srcdir}/examples/simple/assortativity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:189"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/assortativity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:189"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:189: cat \${abs_top_srcdir}/examples/'simple/assortativity.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:189"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/assortativity.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:189"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:189: cp \${abs_top_srcdir}/examples/simple/{karate,celegansneural}.gml ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:189"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/{karate,celegansneural}.gml .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:189"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:189: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:189"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:189"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_103
+#AT_START_104
+at_fn_group_banner 104 'structural_properties.at:192' \
+  "Average nearest neighbor degree (igraph_avg_nearest_neighbor_degree): " "" 6
+at_xfail=no
+(
+  $as_echo "104. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:194: \$CC \${abs_top_srcdir}/examples/simple/igraph_knn.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:194"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_knn.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:194"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:194: >expout"
+at_fn_check_prepare_trace "structural_properties.at:194"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:194"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:194: "
+at_fn_check_prepare_trace "structural_properties.at:194"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:194"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:194: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:194"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:194"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_104
+#AT_START_105
+at_fn_group_banner 105 'structural_properties.at:197' \
+  "Transitive closure of a DAG (igraph_transitive_closure_dag): " "" 6
+at_xfail=no
+(
+  $as_echo "105. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:200: \$CC \${abs_top_srcdir}/examples/simple/igraph_transitive_closure_dag.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:200"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_transitive_closure_dag.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:200"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:200: cat \${abs_top_srcdir}/examples/'simple/igraph_transitive_closure_dag.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:200"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_transitive_closure_dag.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:200"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:200: "
+at_fn_check_prepare_trace "structural_properties.at:200"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:200"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:200: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:200"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:200"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_105
+#AT_START_106
+at_fn_group_banner 106 'structural_properties.at:203' \
+  "Eccentricity (igraph_eccentricity): " "           " 6
+at_xfail=no
+(
+  $as_echo "106. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:206: \$CC \${abs_top_srcdir}/examples/simple/igraph_eccentricity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:206"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eccentricity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:206"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:206: cat \${abs_top_srcdir}/examples/'simple/igraph_eccentricity.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "structural_properties.at:206"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eccentricity.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:206"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:206: "
+at_fn_check_prepare_trace "structural_properties.at:206"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:206"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:206: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:206"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:206"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_106
+#AT_START_107
+at_fn_group_banner 107 'structural_properties.at:209' \
+  "Radius (igraph_radius): " "                       " 6
+at_xfail=no
+(
+  $as_echo "107. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:211: \$CC \${abs_top_srcdir}/examples/simple/igraph_radius.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:211"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_radius.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:211"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:211: >expout"
+at_fn_check_prepare_trace "structural_properties.at:211"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:211"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:211: "
+at_fn_check_prepare_trace "structural_properties.at:211"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:211"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/structural_properties.at:211: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "structural_properties.at:211"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/structural_properties.at:211"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_107
+#AT_START_108
+at_fn_group_banner 108 'components.at:24' \
+  "Decompose a graph (igraph_decompose):" "          " 7
+at_xfail=no
+(
+  $as_echo "108. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/components.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_decompose.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "components.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_decompose.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/components.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_decompose.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "components.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_decompose.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/components.at:26: "
+at_fn_check_prepare_trace "components.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/components.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "components.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_108
+#AT_START_109
+at_fn_group_banner 109 'components.at:29' \
+  "Biconnected components (igraph_biconnected_components):" "" 7
+at_xfail=no
+(
+  $as_echo "109. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/components.at:32: \$CC \${abs_top_srcdir}/examples/simple/igraph_biconnected_components.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "components.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_biconnected_components.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/components.at:32: cat \${abs_top_srcdir}/examples/'simple/igraph_biconnected_components.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "components.at:32"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_biconnected_components.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/components.at:32: "
+at_fn_check_prepare_trace "components.at:32"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/components.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "components.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/components.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_109
+#AT_START_110
+at_fn_group_banner 110 'layout.at:24' \
+  "Grid layout (igraph_layout_grid, igraph_layout_grid_3d):" "" 8
+at_xfail=no
+(
+  $as_echo "110. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_grid.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_grid.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_layout_grid.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "layout.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_layout_grid.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:26: "
+at_fn_check_prepare_trace "layout.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_110
+#AT_START_111
+at_fn_group_banner 111 'layout.at:29' \
+  "Large Graph Layout (igraph_layout_lgl):" "        " 8
+at_xfail=no
+(
+  $as_echo "111. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_lgl.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_lgl.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:31: >expout"
+at_fn_check_prepare_trace "layout.at:31"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:31: "
+at_fn_check_prepare_trace "layout.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_111
+#AT_START_112
+at_fn_group_banner 112 'layout.at:34' \
+  "Reingold-Tilford tree layout (igraph_layout_reingold_tilford):" "" 8
+at_xfail=no
+(
+  $as_echo "112. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:37: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_reingold_tilford.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:37"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_reingold_tilford.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:37: >expout"
+at_fn_check_prepare_trace "layout.at:37"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:37: cp \${abs_top_srcdir}/examples/simple/igraph_layout_reingold_tilford.in ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:37"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/igraph_layout_reingold_tilford.in .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:37: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:37"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_112
+#AT_START_113
+at_fn_group_banner 113 'layout.at:40' \
+  "Sugiyama layout (igraph_layout_sugiyama):" "      " 8
+at_xfail=no
+(
+  $as_echo "113. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:42: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_sugiyama.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:42"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_sugiyama.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:42: cat \${abs_top_srcdir}/examples/'simple/igraph_layout_sugiyama.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "layout.at:42"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_layout_sugiyama.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:42: "
+at_fn_check_prepare_trace "layout.at:42"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:42: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:42"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_113
+#AT_START_114
+at_fn_group_banner 114 'layout.at:45' \
+  "Multidimensional scaling (igraph_layout_mds):" "  " 8
+at_xfail=no
+(
+  $as_echo "114. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:47: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_mds.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:47"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_mds.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:47: cat \${abs_top_srcdir}/examples/'simple/igraph_layout_mds.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "layout.at:47"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_layout_mds.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:47: "
+at_fn_check_prepare_trace "layout.at:47"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:47: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:47"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_114
+#AT_START_115
+at_fn_group_banner 115 'layout.at:50' \
+  "Covering circle and sphere (igraph_i_layout_sphere_{2,3}d):" "" 8
+at_xfail=no
+(
+  $as_echo "115. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:52: \$CC \${abs_top_srcdir}/examples/simple/igraph_i_layout_sphere.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:52"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_i_layout_sphere.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:52: >expout"
+at_fn_check_prepare_trace "layout.at:52"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:52: "
+at_fn_check_prepare_trace "layout.at:52"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:52: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:52"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_115
+#AT_START_116
+at_fn_group_banner 116 'layout.at:55' \
+  "Merging layouts (igraph_i_layout_merge):" "       " 8
+at_xfail=no
+(
+  $as_echo "116. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:57: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_merge.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:57"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_merge.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:57: >expout"
+at_fn_check_prepare_trace "layout.at:57"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:57: "
+at_fn_check_prepare_trace "layout.at:57"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:57: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:57"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_116
+#AT_START_117
+at_fn_group_banner 117 'layout.at:60' \
+  "Merging layouts 2 (igraph_i_layout_merge):" "     " 8
+at_xfail=no
+(
+  $as_echo "117. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:63: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_merge2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:63"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_merge2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:63: cat \${abs_top_srcdir}/examples/'simple/igraph_layout_merge2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "layout.at:63"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_layout_merge2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:63: "
+at_fn_check_prepare_trace "layout.at:63"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:63: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:63"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_117
+#AT_START_118
+at_fn_group_banner 118 'layout.at:66' \
+  "Merging layouts 3 (igraph_i_layout_merge):" "     " 8
+at_xfail=no
+(
+  $as_echo "118. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:68: \$CC \${abs_top_srcdir}/examples/simple/igraph_layout_merge3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:68"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_layout_merge3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:68: >expout"
+at_fn_check_prepare_trace "layout.at:68"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:68: "
+at_fn_check_prepare_trace "layout.at:68"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/layout.at:68: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "layout.at:68"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/layout.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_118
+#AT_START_119
+at_fn_group_banner 119 'visitors.at:24' \
+  "Internal breadth-first search (igraph_i_bfs):" "  " 9
+at_xfail=no
+(
+  $as_echo "119. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_bfs.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "visitors.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_bfs.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_bfs.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "visitors.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_bfs.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:26: "
+at_fn_check_prepare_trace "visitors.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "visitors.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_119
+#AT_START_120
+at_fn_group_banner 120 'visitors.at:29' \
+  "Breadth-first search (igraph_bfs):" "             " 9
+at_xfail=no
+(
+  $as_echo "120. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_bfs2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "visitors.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_bfs2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:31: cat \${abs_top_srcdir}/examples/'simple/igraph_bfs2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "visitors.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_bfs2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:31: "
+at_fn_check_prepare_trace "visitors.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/visitors.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "visitors.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/visitors.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_120
+#AT_START_121
+at_fn_group_banner 121 'topology.at:24' \
+  "The isomorphism class of a subgraph (igraph_isolass_subgraph)" "" 10
+at_xfail=no
+(
+  $as_echo "121. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:26: \$CC \${abs_top_srcdir}/examples/simple/topology.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/topology.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:26: cat \${abs_top_srcdir}/examples/'simple/topology.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "topology.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/topology.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:26: "
+at_fn_check_prepare_trace "topology.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_121
+#AT_START_122
+at_fn_group_banner 122 'topology.at:29' \
+  "The VF2 isomorphism algorithm" "                  " 10
+at_xfail=no
+(
+  $as_echo "122. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_isomorphic_vf2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_isomorphic_vf2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:31: >expout"
+at_fn_check_prepare_trace "topology.at:31"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:31: "
+at_fn_check_prepare_trace "topology.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_122
+#AT_START_123
+at_fn_group_banner 123 'topology.at:34' \
+  "VF algorithm with compatibility functions" "      " 10
+at_xfail=no
+(
+  $as_echo "123. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:36: \$CC \${abs_top_srcdir}/examples/simple/VF2-compat.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/VF2-compat.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:36: >expout"
+at_fn_check_prepare_trace "topology.at:36"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:36: "
+at_fn_check_prepare_trace "topology.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_123
+#AT_START_124
+at_fn_group_banner 124 'topology.at:39' \
+  "LAD subgraph isomorphism algorithm" "             " 10
+at_xfail=no
+(
+  $as_echo "124. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:42: \$CC \${abs_top_srcdir}/examples/simple/igraph_subisomorphic_lad.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:42"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_subisomorphic_lad.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:42: cat \${abs_top_srcdir}/examples/'simple/igraph_subisomorphic_lad.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "topology.at:42"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_subisomorphic_lad.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:42: "
+at_fn_check_prepare_trace "topology.at:42"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:42: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:42"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_124
+#AT_START_125
+at_fn_group_banner 125 'topology.at:45' \
+  "Graphical degree sequences" "                     " 10
+at_xfail=no
+(
+  $as_echo "125. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:47: \$CC \${abs_top_srcdir}/examples/simple/igraph_is_degree_sequence.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:47"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_is_degree_sequence.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:47: >expout"
+at_fn_check_prepare_trace "topology.at:47"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:47: "
+at_fn_check_prepare_trace "topology.at:47"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/topology.at:47: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "topology.at:47"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/topology.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_125
+#AT_START_126
+at_fn_group_banner 126 'motifs.at:24' \
+  "RAND-ESU algorithm (igraph_motifs_randesu)" "     " 11
+at_xfail=no
+(
+  $as_echo "126. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/motifs.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_motifs_randesu.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "motifs.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_motifs_randesu.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/motifs.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/motifs.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_motifs_randesu.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "motifs.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_motifs_randesu.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/motifs.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/motifs.at:26: "
+at_fn_check_prepare_trace "motifs.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/motifs.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/motifs.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "motifs.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/motifs.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_126
+#AT_START_127
+at_fn_group_banner 127 'foreign.at:24' \
+  "Reading Pajek (igraph_read_graph_pajek):" "       " 12
+at_xfail=no
+(
+  $as_echo "127. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:26: \$CC \${abs_top_srcdir}/examples/simple/foreign.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/foreign.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:26: cat \${abs_top_srcdir}/examples/'simple/foreign.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/foreign.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:26: cp \${abs_top_srcdir}/examples/simple/LINKS.NET ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:26"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/LINKS.NET .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_127
+#AT_START_128
+at_fn_group_banner 128 'foreign.at:29' \
+  "GraphML (igraph_{read,write}_graph_graphml):" "   " 12
+at_xfail=no
+(
+  $as_echo "128. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:32: \$CC \${abs_top_srcdir}/examples/simple/graphml.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/graphml.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:32: cat \${abs_top_srcdir}/examples/'simple/graphml.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:32"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/graphml.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:32: cp \${abs_top_srcdir}/examples/simple/{test.gxl,graphml-hsa05010.xml} ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:32"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/{test.gxl,graphml-hsa05010.xml} .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_128
+#AT_START_129
+at_fn_group_banner 129 'foreign.at:35' \
+  "Writing Pajek (igraph_write_graph_pajek):" "      " 12
+at_xfail=no
+(
+  $as_echo "129. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:38: \$CC \${abs_top_srcdir}/examples/simple/igraph_write_graph_pajek.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:38"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_write_graph_pajek.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:38: cat \${abs_top_srcdir}/examples/'simple/igraph_write_graph_pajek.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:38"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_write_graph_pajek.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:38: "
+at_fn_check_prepare_trace "foreign.at:38"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:38: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:38"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_129
+#AT_START_130
+at_fn_group_banner 130 'foreign.at:41' \
+  "Pajek with number of edges present (igraph_read_graph_pajek):" "" 12
+at_xfail=no
+(
+  $as_echo "130. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:43: \$CC \${abs_top_srcdir}/examples/simple/pajek.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:43"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/pajek.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:43: >expout"
+at_fn_check_prepare_trace "foreign.at:43"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:43: cp \${abs_top_srcdir}/examples/simple/pajek{5,6}.net ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:43"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/pajek{5,6}.net .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:43: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:43"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_130
+#AT_START_131
+at_fn_group_banner 131 'foreign.at:46' \
+  "Pajek, bipartite (igraph_read_graph_pajek):" "    " 12
+at_xfail=no
+(
+  $as_echo "131. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:49: \$CC \${abs_top_srcdir}/examples/simple/pajek2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:49"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/pajek2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:49: cat \${abs_top_srcdir}/examples/'simple/pajek2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:49"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/pajek2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:49: cp \${abs_top_srcdir}/examples/simple/bipartite.net ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:49"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/bipartite.net .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:49: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:49"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_131
+#AT_START_132
+at_fn_group_banner 132 'foreign.at:52' \
+  "Pajek, bipartite incidence matrix (igraph_read_graph_pajek):" "" 12
+at_xfail=no
+(
+  $as_echo "132. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:55: \$CC \${abs_top_srcdir}/examples/simple/pajek_bipartite2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:55"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/pajek_bipartite2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:55: cat \${abs_top_srcdir}/examples/'simple/pajek_bipartite2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:55"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/pajek_bipartite2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:55: cp \${abs_top_srcdir}/examples/simple/pajek_{bip,bip2}.net ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:55"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/pajek_{bip,bip2}.net .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:55: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:55"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_132
+#AT_START_133
+at_fn_group_banner 133 'foreign.at:58' \
+  "Pajek, signed (igraph_read_graph_pajek):" "       " 12
+at_xfail=no
+(
+  $as_echo "133. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:61: \$CC \${abs_top_srcdir}/examples/simple/pajek_signed.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:61"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/pajek_signed.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:61: cat \${abs_top_srcdir}/examples/'simple/pajek_signed.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:61"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/pajek_signed.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:61: cp \${abs_top_srcdir}/examples/simple/pajek_signed.net ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:61"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/pajek_signed.net .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:61: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:61"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_133
+#AT_START_134
+at_fn_group_banner 134 'foreign.at:64' \
+  "Pajek, writing bipartite graph (igraph_write_graph_pajek):" "" 12
+at_xfail=no
+(
+  $as_echo "134. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:66: \$CC \${abs_top_srcdir}/examples/simple/pajek_bipartite.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:66"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/pajek_bipartite.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:66: cat \${abs_top_srcdir}/examples/'simple/pajek_bipartite.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:66"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/pajek_bipartite.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:66: "
+at_fn_check_prepare_trace "foreign.at:66"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:66: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:66"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_134
+#AT_START_135
+at_fn_group_banner 135 'foreign.at:69' \
+  "Reading an LGL file (igraph_read_graph_lgl):" "   " 12
+at_xfail=no
+(
+  $as_echo "135. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:73: \$CC \${abs_top_srcdir}/examples/simple/igraph_read_graph_lgl.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:73"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_read_graph_lgl.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:73: cat \${abs_top_srcdir}/examples/'simple/igraph_read_graph_lgl.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:73"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_read_graph_lgl.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:73: cp \${abs_top_srcdir}/examples/{simple/igraph_read_graph_lgl-1.lgl,simple/igraph_read_graph_lgl-2.lgl,simple/igraph_read_graph_lgl-3.lgl} ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:73"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/{simple/igraph_read_graph_lgl-1.lgl,simple/igraph_read_graph_lgl-2.lgl,simple/igraph_read_graph_lgl-3.lgl} .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:73: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:73"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_135
+#AT_START_136
+at_fn_group_banner 136 'foreign.at:76' \
+  "Writing LGL (igraph_write_graph_lgl):" "          " 12
+at_xfail=no
+(
+  $as_echo "136. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:78: \$CC \${abs_top_srcdir}/examples/simple/igraph_write_graph_lgl.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:78"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_write_graph_lgl.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:78: >expout"
+at_fn_check_prepare_trace "foreign.at:78"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:78: "
+at_fn_check_prepare_trace "foreign.at:78"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:78: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:78"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_136
+#AT_START_137
+at_fn_group_banner 137 'foreign.at:81' \
+  "Reading a graph from the graph database (igraph_read_graph_graphdb):" "" 12
+at_xfail=no
+(
+  $as_echo "137. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:85: \$CC \${abs_top_srcdir}/examples/simple/igraph_read_graph_graphdb.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:85"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_read_graph_graphdb.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:85: cat \${abs_top_srcdir}/examples/'simple/igraph_read_graph_graphdb.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:85"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_read_graph_graphdb.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:85: cp \${abs_top_srcdir}/examples/simple/iso_b03_m1000.A00 ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:85"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/iso_b03_m1000.A00 .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:85: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:85"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:85"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_137
+#AT_START_138
+at_fn_group_banner 138 'foreign.at:88' \
+  "Reading a GML file (igraph_read_graph_gml):" "    " 12
+at_xfail=no
+(
+  $as_echo "138. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:90: \$CC \${abs_top_srcdir}/examples/simple/gml.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:90"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/gml.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:90: cat \${abs_top_srcdir}/examples/'simple/gml.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:90"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/gml.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:90: cp \${abs_top_srcdir}/examples/simple/karate.gml ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:90"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/karate.gml .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:90: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:90"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_138
+#AT_START_139
+at_fn_group_banner 139 'foreign.at:93' \
+  "Writing a DOT file (igraph_write_graph_dot):" "   " 12
+at_xfail=no
+(
+  $as_echo "139. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:95: \$CC \${abs_top_srcdir}/examples/simple/dot.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:95"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/dot.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:95"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:95: cat \${abs_top_srcdir}/examples/'simple/dot.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:95"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/dot.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:95"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:95: cp \${abs_top_srcdir}/examples/simple/karate.gml ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:95"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/karate.gml .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:95"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:95: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:95"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:95"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_139
+#AT_START_140
+at_fn_group_banner 140 'foreign.at:98' \
+  "Different line endings:" "                        " 12
+at_xfail=no
+(
+  $as_echo "140. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:102: \$CC \${abs_top_srcdir}/examples/simple/lineendings.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:102"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/lineendings.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:102: cat \${abs_top_srcdir}/examples/'simple/lineendings.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:102"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/lineendings.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:102: cp \${abs_top_srcdir}/examples/{simple/pajek1.net,simple/pajek2.net,simple/pajek3.net,simple/pajek4.net} ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:102"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/{simple/pajek1.net,simple/pajek2.net,simple/pajek3.net,simple/pajek4.net} .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:102: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:102"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:102"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_140
+#AT_START_141
+at_fn_group_banner 141 'foreign.at:105' \
+  "UNICET DL format:" "                              " 12
+at_xfail=no
+(
+  $as_echo "141. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:108: \$CC \${abs_top_srcdir}/examples/simple/igraph_read_graph_dl.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:108"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_read_graph_dl.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:108: cat \${abs_top_srcdir}/examples/'simple/igraph_read_graph_dl.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:108"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_read_graph_dl.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:108: cp \${abs_top_srcdir}/examples/simple/{edgelist1,edgelist2,edgelist3,edgelist4,edgelist5,edgelist6,fullmatrix1,fullmatrix2,fullmatrix3,fullmatrix4,nodelist1,nodelist2}.dl ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:108"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/{edgelist1,edgelist2,edgelist3,edgelist4,edgelist5,edgelist6,fullmatrix1,fullmatrix2,fullmatrix3,fullmatrix4,nodelist1,nodelist2}.dl .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:108: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:108"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:108"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_141
+#AT_START_142
+at_fn_group_banner 142 'foreign.at:111' \
+  "LEDA format:" "                                   " 12
+at_xfail=no
+(
+  $as_echo "142. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:113: \$CC \${abs_top_srcdir}/examples/simple/igraph_write_graph_leda.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:113"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_write_graph_leda.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:113"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:113: cat \${abs_top_srcdir}/examples/'simple/igraph_write_graph_leda.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "foreign.at:113"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_write_graph_leda.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:113"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:113: "
+at_fn_check_prepare_trace "foreign.at:113"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:113"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/foreign.at:113: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "foreign.at:113"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/foreign.at:113"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_142
+#AT_START_143
+at_fn_group_banner 143 'other.at:24' \
+  "Convex hull calculation (igraph_convex_hull):" "  " 13
+at_xfail=no
+(
+  $as_echo "143. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/other.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_convex_hull.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "other.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_convex_hull.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/other.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_convex_hull.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "other.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_convex_hull.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/other.at:26: "
+at_fn_check_prepare_trace "other.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/other.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "other.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_143
+#AT_START_144
+at_fn_group_banner 144 'other.at:29' \
+  "Fitting power-law distributions (igraph_power_law_fit):" "" 13
+at_xfail=no
+(
+  $as_echo "144. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/other.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_power_law_fit.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "other.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_power_law_fit.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/other.at:31: cat \${abs_top_srcdir}/examples/'simple/igraph_power_law_fit.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "other.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_power_law_fit.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/other.at:31: "
+at_fn_check_prepare_trace "other.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/other.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "other.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/other.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_144
+#AT_START_145
+at_fn_group_banner 145 'operators.at:24' \
+  "Disjoint union (igraph_disjoint_union, igraph_dosjoint_union_many):" "" 14
+at_xfail=no
+(
+  $as_echo "145. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:28: \$CC \${abs_top_srcdir}/examples/simple/igraph_disjoint_union.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:28"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_disjoint_union.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:28: cat \${abs_top_srcdir}/examples/'simple/igraph_disjoint_union.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:28"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_disjoint_union.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:28: "
+at_fn_check_prepare_trace "operators.at:28"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:28: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:28"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_145
+#AT_START_146
+at_fn_group_banner 146 'operators.at:31' \
+  "Union (igraph_union, igraph_union_many):" "       " 14
+at_xfail=no
+(
+  $as_echo "146. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:34: \$CC \${abs_top_srcdir}/examples/simple/igraph_union.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:34"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_union.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:34: cat \${abs_top_srcdir}/examples/'simple/igraph_union.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:34"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_union.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:34: "
+at_fn_check_prepare_trace "operators.at:34"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:34: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:34"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_146
+#AT_START_147
+at_fn_group_banner 147 'operators.at:37' \
+  "Intersection (igraph_intersection, igraph_intersection_many):" "" 14
+at_xfail=no
+(
+  $as_echo "147. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:40: \$CC \${abs_top_srcdir}/examples/simple/igraph_intersection.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:40"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_intersection.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:40: cat \${abs_top_srcdir}/examples/'simple/igraph_intersection.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:40"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_intersection.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:40: "
+at_fn_check_prepare_trace "operators.at:40"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:40: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:40"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_147
+#AT_START_148
+at_fn_group_banner 148 'operators.at:43' \
+  "Intersection 2 (igraph_intersection, igraph_intersection_many):" "" 14
+at_xfail=no
+(
+  $as_echo "148. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:46: \$CC \${abs_top_srcdir}/examples/simple/igraph_intersection2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:46"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_intersection2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:46: cat \${abs_top_srcdir}/examples/'simple/igraph_intersection2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:46"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_intersection2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:46: "
+at_fn_check_prepare_trace "operators.at:46"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:46: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:46"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_148
+#AT_START_149
+at_fn_group_banner 149 'operators.at:49' \
+  "Difference (igraph_difference):" "                " 14
+at_xfail=no
+(
+  $as_echo "149. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:52: \$CC \${abs_top_srcdir}/examples/simple/igraph_difference.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:52"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_difference.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:52: cat \${abs_top_srcdir}/examples/'simple/igraph_difference.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:52"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_difference.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:52: "
+at_fn_check_prepare_trace "operators.at:52"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:52: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:52"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_149
+#AT_START_150
+at_fn_group_banner 150 'operators.at:55' \
+  "Complementer (igraph_complementer):" "            " 14
+at_xfail=no
+(
+  $as_echo "150. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:58: \$CC \${abs_top_srcdir}/examples/simple/igraph_complementer.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:58"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_complementer.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:58"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:58: cat \${abs_top_srcdir}/examples/'simple/igraph_complementer.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:58"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_complementer.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:58"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:58: "
+at_fn_check_prepare_trace "operators.at:58"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:58"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:58: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:58"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:58"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_150
+#AT_START_151
+at_fn_group_banner 151 'operators.at:61' \
+  "Composition (igraph_compose):" "                  " 14
+at_xfail=no
+(
+  $as_echo "151. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:64: \$CC \${abs_top_srcdir}/examples/simple/igraph_compose.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:64"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_compose.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:64: cat \${abs_top_srcdir}/examples/'simple/igraph_compose.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "operators.at:64"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_compose.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:64: "
+at_fn_check_prepare_trace "operators.at:64"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/operators.at:64: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "operators.at:64"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/operators.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_151
+#AT_START_152
+at_fn_group_banner 152 'conversion.at:24' \
+  "Directed to undirected (igraph_to_undirected):" " " 15
+at_xfail=no
+(
+  $as_echo "152. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:27: \$CC \${abs_top_srcdir}/examples/simple/igraph_to_undirected.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "conversion.at:27"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_to_undirected.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:27: cat \${abs_top_srcdir}/examples/'simple/igraph_to_undirected.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "conversion.at:27"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_to_undirected.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:27: "
+at_fn_check_prepare_trace "conversion.at:27"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:27: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "conversion.at:27"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_152
+#AT_START_153
+at_fn_group_banner 153 'conversion.at:30' \
+  "Graphs from adjacency list (igraph_adjlist):" "   " 15
+at_xfail=no
+(
+  $as_echo "153. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:32: \$CC \${abs_top_srcdir}/examples/simple/adjlist.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "conversion.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/adjlist.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:32: >expout"
+at_fn_check_prepare_trace "conversion.at:32"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:32: "
+at_fn_check_prepare_trace "conversion.at:32"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "conversion.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_153
+#AT_START_154
+at_fn_group_banner 154 'conversion.at:35' \
+  "Graph to Laplacian matrix (igraph_laplacian):" "  " 15
+at_xfail=no
+(
+  $as_echo "154. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:38: \$CC \${abs_top_srcdir}/examples/simple/igraph_laplacian.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "conversion.at:38"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_laplacian.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:38: cat \${abs_top_srcdir}/examples/'simple/igraph_laplacian.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "conversion.at:38"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_laplacian.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:38: "
+at_fn_check_prepare_trace "conversion.at:38"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/conversion.at:38: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "conversion.at:38"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/conversion.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_154
+#AT_START_155
+at_fn_group_banner 155 'flow.at:24' \
+  "Maximum flow value (igraph_maxflow_value): " "    " 16
+at_xfail=no
+(
+  $as_echo "155. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:26: \$CC \${abs_top_srcdir}/examples/simple/flow.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/flow.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:26: >expout"
+at_fn_check_prepare_trace "flow.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:26: cp \${abs_top_srcdir}/examples/simple/ak-4102.max ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:26"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/ak-4102.max .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_155
+#AT_START_156
+at_fn_group_banner 156 'flow.at:29' \
+  "Maximum flow (igraph_maxflow): " "                " 16
+at_xfail=no
+(
+  $as_echo "156. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:31: \$CC \${abs_top_srcdir}/examples/simple/flow2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/flow2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:31: cat \${abs_top_srcdir}/examples/'simple/flow2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "flow.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/flow2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:31: cp \${abs_top_srcdir}/examples/simple/ak-4102.max ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:31"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/ak-4102.max .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_156
+#AT_START_157
+at_fn_group_banner 157 'flow.at:34' \
+  "Minimum cut (igraph_mincut): " "                  " 16
+at_xfail=no
+(
+  $as_echo "157. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:36: \$CC \${abs_top_srcdir}/examples/simple/igraph_mincut.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_mincut.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:36: cat \${abs_top_srcdir}/examples/'simple/igraph_mincut.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "flow.at:36"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_mincut.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:36: "
+at_fn_check_prepare_trace "flow.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_157
+#AT_START_158
+at_fn_group_banner 158 'flow.at:39' \
+  "Even-Tarjan reduction (igraph_even_tarjan_reduction): " "" 16
+at_xfail=no
+(
+  $as_echo "158. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:41: \$CC \${abs_top_srcdir}/examples/simple/even_tarjan.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:41"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/even_tarjan.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:41: >expout"
+at_fn_check_prepare_trace "flow.at:41"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:41: "
+at_fn_check_prepare_trace "flow.at:41"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:41: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:41"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_158
+#AT_START_159
+at_fn_group_banner 159 'flow.at:44' \
+  "Dominator tree of a flow graph (igraph_dominator_tree): " "" 16
+at_xfail=no
+(
+  $as_echo "159. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:47: \$CC \${abs_top_srcdir}/examples/simple/dominator_tree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:47"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/dominator_tree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:47: cat \${abs_top_srcdir}/examples/'simple/dominator_tree.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "flow.at:47"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/dominator_tree.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:47: "
+at_fn_check_prepare_trace "flow.at:47"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:47: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:47"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_159
+#AT_START_160
+at_fn_group_banner 160 'flow.at:50' \
+  "All s-t cuts of a graph (igraph_all_st_cuts): " " " 16
+at_xfail=no
+(
+  $as_echo "160. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:53: \$CC \${abs_top_srcdir}/examples/simple/igraph_all_st_cuts.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:53"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_all_st_cuts.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:53"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:53: cat \${abs_top_srcdir}/examples/'simple/igraph_all_st_cuts.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "flow.at:53"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_all_st_cuts.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:53"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:53: "
+at_fn_check_prepare_trace "flow.at:53"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:53"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:53: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:53"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:53"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_160
+#AT_START_161
+at_fn_group_banner 161 'flow.at:56' \
+  "All minimal s-t cuts of a graph (igraph_all_st_mincuts): " "" 16
+at_xfail=no
+(
+  $as_echo "161. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:59: \$CC \${abs_top_srcdir}/examples/simple/igraph_all_st_mincuts.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:59"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_all_st_mincuts.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:59: cat \${abs_top_srcdir}/examples/'simple/igraph_all_st_mincuts.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "flow.at:59"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_all_st_mincuts.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:59: "
+at_fn_check_prepare_trace "flow.at:59"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:59: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:59"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_161
+#AT_START_162
+at_fn_group_banner 162 'flow.at:62' \
+  "Gomory-Hu tree (igraph_gomory_hu_tree): " "       " 16
+at_xfail=no
+(
+  $as_echo "162. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:64: \$CC \${abs_top_srcdir}/examples/simple/igraph_gomory_hu_tree.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:64"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_gomory_hu_tree.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:64: >expout"
+at_fn_check_prepare_trace "flow.at:64"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:64: "
+at_fn_check_prepare_trace "flow.at:64"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/flow.at:64: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "flow.at:64"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/flow.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_162
+#AT_START_163
+at_fn_group_banner 163 'community.at:24' \
+  "Spinglass clustering (igraph_spinglass_community): " "" 17
+at_xfail=no
+(
+  $as_echo "163. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:26: \$CC \${abs_top_srcdir}/examples/simple/spinglass.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/spinglass.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:26: >expout"
+at_fn_check_prepare_trace "community.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:26: "
+at_fn_check_prepare_trace "community.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_163
+#AT_START_164
+at_fn_group_banner 164 'community.at:29' \
+  "Walktrap community structure (igraph_walktrap_community): " "" 17
+at_xfail=no
+(
+  $as_echo "164. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:31: \$CC \${abs_top_srcdir}/examples/simple/walktrap.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/walktrap.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:31: cat \${abs_top_srcdir}/examples/'simple/walktrap.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/walktrap.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:31: "
+at_fn_check_prepare_trace "community.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_164
+#AT_START_165
+at_fn_group_banner 165 'community.at:34' \
+  "Edge betweenness community structure (igraph_community_edge_betweenness): " "" 17
+at_xfail=no
+(
+  $as_echo "165. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:37: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_edge_betweenness.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:37"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_edge_betweenness.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:37: cat \${abs_top_srcdir}/examples/'simple/igraph_community_edge_betweenness.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:37"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_edge_betweenness.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:37: "
+at_fn_check_prepare_trace "community.at:37"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:37: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:37"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_165
+#AT_START_166
+at_fn_group_banner 166 'community.at:40' \
+  "Modularity optimization (igraph_community_fastgreedy): " "" 17
+at_xfail=no
+(
+  $as_echo "166. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:43: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_fastgreedy.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:43"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_fastgreedy.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:43: cat \${abs_top_srcdir}/examples/'simple/igraph_community_fastgreedy.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:43"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_fastgreedy.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:43: "
+at_fn_check_prepare_trace "community.at:43"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:43: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:43"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_166
+#AT_START_167
+at_fn_group_banner 167 'community.at:46' \
+  "Leading eigenvector community structure (igraph_community_leading_eigenvector) :" "" 17
+at_xfail=no
+(
+  $as_echo "167. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:49: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_leading_eigenvector.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:49"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_leading_eigenvector.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:49: cat \${abs_top_srcdir}/examples/'simple/igraph_community_leading_eigenvector.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:49"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_leading_eigenvector.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:49: "
+at_fn_check_prepare_trace "community.at:49"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:49: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:49"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_167
+#AT_START_168
+at_fn_group_banner 168 'community.at:52' \
+  "Weighted leading eigenvector community structure (igraph_community_leading_eigenvector) :" "" 17
+at_xfail=no
+(
+  $as_echo "168. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:55: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_leading_eigenvector2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:55"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_leading_eigenvector2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:55: cat \${abs_top_srcdir}/examples/'simple/igraph_community_leading_eigenvector2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:55"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_leading_eigenvector2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:55: "
+at_fn_check_prepare_trace "community.at:55"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:55: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:55"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_168
+#AT_START_169
+at_fn_group_banner 169 'community.at:58' \
+  "Leading eigenvector bug #1002140 test (igraph_community_leading_eigenvector) :" "" 17
+at_xfail=no
+(
+  $as_echo "169. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:60: \$CC \${abs_top_srcdir}/examples/simple/levc-stress.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:60"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/levc-stress.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:60: >expout"
+at_fn_check_prepare_trace "community.at:60"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:60: cp \${abs_top_srcdir}/examples/simple/input.dl ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:60"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/input.dl .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:60: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:60"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_169
+#AT_START_170
+at_fn_group_banner 170 'community.at:64' \
+  "Label propagation algorithm (igraph_community_label_propagation) :" "" 17
+at_xfail=no
+(
+  $as_echo "170. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:67: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_label_propagation.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:67"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_label_propagation.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:67: cat \${abs_top_srcdir}/examples/'simple/igraph_community_label_propagation.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:67"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_label_propagation.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:67: "
+at_fn_check_prepare_trace "community.at:67"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:67: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:67"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_170
+#AT_START_171
+at_fn_group_banner 171 'community.at:70' \
+  "Multilevel community detection (igraph_community_multilevel) :" "" 17
+at_xfail=no
+(
+  $as_echo "171. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:73: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_multilevel.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:73"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_multilevel.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:73: cat \${abs_top_srcdir}/examples/'simple/igraph_community_multilevel.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:73"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_multilevel.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:73: "
+at_fn_check_prepare_trace "community.at:73"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:73: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:73"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_171
+#AT_START_172
+at_fn_group_banner 172 'community.at:76' \
+  "Multilevel community detection, isolates (igraph_community_multilevel) :" "" 17
+at_xfail=no
+(
+  $as_echo "172. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:78: \$CC \${abs_top_srcdir}/examples/simple/bug-1149658.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:78"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/bug-1149658.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:78: >expout"
+at_fn_check_prepare_trace "community.at:78"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:78: "
+at_fn_check_prepare_trace "community.at:78"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:78: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:78"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_172
+#AT_START_173
+at_fn_group_banner 173 'community.at:81' \
+  "Modularity optimization, integer programming (igraph_community_optimal_modularity) :" "" 17
+at_xfail=no
+(
+  $as_echo "173. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:83: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_optimal_modularity.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:83"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_optimal_modularity.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:83"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:83: >expout"
+at_fn_check_prepare_trace "community.at:83"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:83"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:83: "
+at_fn_check_prepare_trace "community.at:83"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:83"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:83: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:83"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:83"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_173
+#AT_START_174
+at_fn_group_banner 174 'community.at:86' \
+  "Infomap community structure (igraph_community_infomap) :" "" 17
+at_xfail=no
+(
+  $as_echo "174. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/community.at:90: \$CC \${abs_top_srcdir}/examples/simple/igraph_community_infomap.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:90"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_community_infomap.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:90: cat \${abs_top_srcdir}/examples/'simple/igraph_community_infomap.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "community.at:90"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_community_infomap.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:90: cp \${abs_top_srcdir}/examples/simple/wikti_en_V_syn.elist ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:90"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/wikti_en_V_syn.elist .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/community.at:90: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "community.at:90"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/community.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_174
+#AT_START_175
+at_fn_group_banner 175 'cliques.at:26' \
+  "Calculating cliques (igraph_cliques): " "         " 18
+at_xfail=no
+(
+  $as_echo "175. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:28: \$CC \${abs_top_srcdir}/examples/simple/igraph_cliques.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:28"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_cliques.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:28: cat \${abs_top_srcdir}/examples/'simple/igraph_cliques.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "cliques.at:28"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_cliques.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:28: "
+at_fn_check_prepare_trace "cliques.at:28"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:28: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:28"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_175
+#AT_START_176
+at_fn_group_banner 176 'cliques.at:31' \
+  "Additional test for maximal cliques (igraph_maximal_cliques):" "" 18
+at_xfail=no
+(
+  $as_echo "176. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:34: \$CC \${abs_top_srcdir}/examples/simple/igraph_maximal_cliques.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:34"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_maximal_cliques.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:34: cat \${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "cliques.at:34"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:34: "
+at_fn_check_prepare_trace "cliques.at:34"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:34: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:34"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_176
+#AT_START_177
+at_fn_group_banner 177 'cliques.at:37' \
+  "More maximal cliques (igraph_maximal_cliques):" " " 18
+at_xfail=no
+(
+  $as_echo "177. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:40: \$CC \${abs_top_srcdir}/examples/simple/igraph_maximal_cliques2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:40"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_maximal_cliques2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:40: cat \${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "cliques.at:40"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:40: "
+at_fn_check_prepare_trace "cliques.at:40"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:40: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:40"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_177
+#AT_START_178
+at_fn_group_banner 178 'cliques.at:43' \
+  "Maximal cliques 3 (igraph_maximal_cliques):" "    " 18
+at_xfail=no
+(
+  $as_echo "178. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:46: \$CC \${abs_top_srcdir}/examples/simple/igraph_maximal_cliques3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:46"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_maximal_cliques3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:46: cat \${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "cliques.at:46"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:46: "
+at_fn_check_prepare_trace "cliques.at:46"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:46: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:46"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_178
+#AT_START_179
+at_fn_group_banner 179 'cliques.at:49' \
+  "Maximal cliques for a subset (igraph_maximal_cliques):" "" 18
+at_xfail=no
+(
+  $as_echo "179. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:52: \$CC \${abs_top_srcdir}/examples/simple/igraph_maximal_cliques4.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:52"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_maximal_cliques4.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:52: cat \${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques4.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "cliques.at:52"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_maximal_cliques4.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:52: "
+at_fn_check_prepare_trace "cliques.at:52"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:52: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:52"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_179
+#AT_START_180
+at_fn_group_banner 180 'cliques.at:55' \
+  "Calculating independent vertex sets (igraph_independent_vertex_sets): " "" 18
+at_xfail=no
+(
+  $as_echo "180. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:59: \$CC \${abs_top_srcdir}/examples/simple/igraph_independent_sets.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:59"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_independent_sets.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:59: cat \${abs_top_srcdir}/examples/'simple/igraph_independent_sets.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "cliques.at:59"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_independent_sets.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:59: "
+at_fn_check_prepare_trace "cliques.at:59"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/cliques.at:59: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "cliques.at:59"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/cliques.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_180
+#AT_START_181
+at_fn_group_banner 181 'eigen.at:24' \
+  "Symmetric matrix, LAPACK (igraph_eigen_matrix_symmetric):" "" 19
+at_xfail=no
+(
+  $as_echo "181. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:27: \$CC \${abs_top_srcdir}/examples/simple/igraph_eigen_matrix_symmetric.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:27"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eigen_matrix_symmetric.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:27: cat \${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix_symmetric.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "eigen.at:27"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix_symmetric.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:27: "
+at_fn_check_prepare_trace "eigen.at:27"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:27: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:27"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_181
+#AT_START_182
+at_fn_group_banner 182 'eigen.at:30' \
+  "Symmetric matrix, ARPACK (igraph_eigen_matrix_symmetric):" "" 19
+at_xfail=no
+(
+  $as_echo "182. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:33: \$CC \${abs_top_srcdir}/examples/simple/igraph_eigen_matrix_symmetric_arpack.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:33"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eigen_matrix_symmetric_arpack.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:33: cat \${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix_symmetric_arpack.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "eigen.at:33"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix_symmetric_arpack.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:33: "
+at_fn_check_prepare_trace "eigen.at:33"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:33: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:33"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_182
+#AT_START_183
+at_fn_group_banner 183 'eigen.at:36' \
+  "General matrix, LAPACK, LM, SM (igraph_eigen_matrix):" "" 19
+at_xfail=no
+(
+  $as_echo "183. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:39: \$CC \${abs_top_srcdir}/examples/simple/igraph_eigen_matrix.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:39"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eigen_matrix.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:39: cat \${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "eigen.at:39"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:39: "
+at_fn_check_prepare_trace "eigen.at:39"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:39: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:39"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_183
+#AT_START_184
+at_fn_group_banner 184 'eigen.at:42' \
+  "General matrix, LAPACK, LR, SR (igraph_eigen_matrix):" "" 19
+at_xfail=no
+(
+  $as_echo "184. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:45: \$CC \${abs_top_srcdir}/examples/simple/igraph_eigen_matrix2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:45"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eigen_matrix2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:45: cat \${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "eigen.at:45"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:45: "
+at_fn_check_prepare_trace "eigen.at:45"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:45: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:45"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_184
+#AT_START_185
+at_fn_group_banner 185 'eigen.at:48' \
+  "General matrix, LAPACK, LI, SI (igraph_eigen_matrix):" "" 19
+at_xfail=no
+(
+  $as_echo "185. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:51: \$CC \${abs_top_srcdir}/examples/simple/igraph_eigen_matrix4.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:51"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eigen_matrix4.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:51: cat \${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix4.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "eigen.at:51"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix4.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:51: "
+at_fn_check_prepare_trace "eigen.at:51"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:51: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:51"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_185
+#AT_START_186
+at_fn_group_banner 186 'eigen.at:54' \
+  "General matrix, LAPACK, SELECT (igraph_eigen_matrix):" "" 19
+at_xfail=no
+(
+  $as_echo "186. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:57: \$CC \${abs_top_srcdir}/examples/simple/igraph_eigen_matrix3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:57"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_eigen_matrix3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:57: cat \${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "eigen.at:57"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_eigen_matrix3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:57: "
+at_fn_check_prepare_trace "eigen.at:57"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/eigen.at:57: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "eigen.at:57"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/eigen.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_186
+#AT_START_187
+at_fn_group_banner 187 'attributes.at:24' \
+  "Reading a Pajek file with attributes:" "          " 20
+at_xfail=no
+(
+  $as_echo "187. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:27: \$CC \${abs_top_srcdir}/examples/simple/cattributes.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:27"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/cattributes.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:27: cat \${abs_top_srcdir}/examples/'simple/cattributes.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "attributes.at:27"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/cattributes.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:27: cp \${abs_top_srcdir}/examples/simple/LINKS.NET ."
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:27"
+( $at_check_trace; cp ${abs_top_srcdir}/examples/simple/LINKS.NET .
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:27: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:27"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_187
+#AT_START_188
+at_fn_group_banner 188 'attributes.at:30' \
+  "Writing an attributed graph in GML and GraphML:" "" 20
+at_xfail=no
+(
+  $as_echo "188. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:32: \$CC \${abs_top_srcdir}/examples/simple/cattributes2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/cattributes2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:32: cat \${abs_top_srcdir}/examples/'simple/cattributes2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "attributes.at:32"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/cattributes2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:32: "
+at_fn_check_prepare_trace "attributes.at:32"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_188
+#AT_START_189
+at_fn_group_banner 189 'attributes.at:35' \
+  "Combining numeric attributes:" "                  " 20
+at_xfail=no
+(
+  $as_echo "189. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:37: \$CC \${abs_top_srcdir}/examples/simple/cattributes3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:37"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/cattributes3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:37: cat \${abs_top_srcdir}/examples/'simple/cattributes3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "attributes.at:37"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/cattributes3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:37: "
+at_fn_check_prepare_trace "attributes.at:37"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:37: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:37"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_189
+#AT_START_190
+at_fn_group_banner 190 'attributes.at:40' \
+  "Combining string attributes:" "                   " 20
+at_xfail=no
+(
+  $as_echo "190. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:42: \$CC \${abs_top_srcdir}/examples/simple/cattributes4.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:42"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/cattributes4.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:42: cat \${abs_top_srcdir}/examples/'simple/cattributes4.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "attributes.at:42"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/cattributes4.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:42: "
+at_fn_check_prepare_trace "attributes.at:42"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/attributes.at:42: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "attributes.at:42"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/attributes.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_190
+#AT_START_191
+at_fn_group_banner 191 'arpack.at:24' \
+  "Basic BLAS functions (igraph_blas_*):" "          " 21
+at_xfail=no
+(
+  $as_echo "191. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:27: \$CC \${abs_top_srcdir}/examples/simple/blas.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:27"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/blas.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:27: cat \${abs_top_srcdir}/examples/'simple/blas.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "arpack.at:27"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/blas.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:27: "
+at_fn_check_prepare_trace "arpack.at:27"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:27: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:27"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_191
+#AT_START_192
+at_fn_group_banner 192 'arpack.at:30' \
+  "Dense symmetric eigenvalues and eigenvectors (igraph_lapack_dsyevr):" "" 21
+at_xfail=no
+(
+  $as_echo "192. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:32: \$CC \${abs_top_srcdir}/examples/simple/igraph_lapack_dsyevr.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lapack_dsyevr.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:32: >expout"
+at_fn_check_prepare_trace "arpack.at:32"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:32: "
+at_fn_check_prepare_trace "arpack.at:32"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_192
+#AT_START_193
+at_fn_group_banner 193 'arpack.at:35' \
+  "Dense non-symmetric eigenvalues and eigenvectors (igraph_lapack_dgeev):" "" 21
+at_xfail=no
+(
+  $as_echo "193. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:37: \$CC \${abs_top_srcdir}/examples/simple/igraph_lapack_dgeev.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:37"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lapack_dgeev.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:37: >expout"
+at_fn_check_prepare_trace "arpack.at:37"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:37: "
+at_fn_check_prepare_trace "arpack.at:37"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:37: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:37"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_193
+#AT_START_194
+at_fn_group_banner 194 'arpack.at:40' \
+  "Dense non-symmetric eigenvalues and eigenvectors (igraph_lapack_dgeevx):" "" 21
+at_xfail=no
+(
+  $as_echo "194. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:42: \$CC \${abs_top_srcdir}/examples/simple/igraph_lapack_dgeevx.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:42"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lapack_dgeevx.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:42: >expout"
+at_fn_check_prepare_trace "arpack.at:42"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:42: "
+at_fn_check_prepare_trace "arpack.at:42"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:42: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:42"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_194
+#AT_START_195
+at_fn_group_banner 195 'arpack.at:45' \
+  "Solving linear systems with LU factorization (igraph_lapack_dgesv):" "" 21
+at_xfail=no
+(
+  $as_echo "195. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:48: \$CC \${abs_top_srcdir}/examples/simple/igraph_lapack_dgesv.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:48"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lapack_dgesv.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:48"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:48: cat \${abs_top_srcdir}/examples/'simple/igraph_lapack_dgesv.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "arpack.at:48"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_lapack_dgesv.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:48"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:48: "
+at_fn_check_prepare_trace "arpack.at:48"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:48"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:48: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:48"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:48"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_195
+#AT_START_196
+at_fn_group_banner 196 'arpack.at:51' \
+  "Upper Hessenberg transformation (igraph_lapack_dgehrd):" "" 21
+at_xfail=no
+(
+  $as_echo "196. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:54: \$CC \${abs_top_srcdir}/examples/simple/igraph_lapack_dgehrd.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:54"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_lapack_dgehrd.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:54: cat \${abs_top_srcdir}/examples/'simple/igraph_lapack_dgehrd.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "arpack.at:54"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_lapack_dgehrd.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:54: "
+at_fn_check_prepare_trace "arpack.at:54"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:54: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:54"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_196
+#AT_START_197
+at_fn_group_banner 197 'arpack.at:57' \
+  "Eigenvector centrality (igraph_eigenvector_centrality):" "" 21
+at_xfail=no
+(
+  $as_echo "197. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:60: \$CC \${abs_top_srcdir}/examples/simple/eigenvector_centrality.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:60"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/eigenvector_centrality.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:60: cat \${abs_top_srcdir}/examples/'simple/eigenvector_centrality.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "arpack.at:60"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/eigenvector_centrality.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:60: "
+at_fn_check_prepare_trace "arpack.at:60"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:60: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:60"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:60"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_197
+#AT_START_198
+at_fn_group_banner 198 'arpack.at:63' \
+  "Non-symmetric ARPACK solver (igraph_arpack_rnsolve):" "" 21
+at_xfail=no
+(
+  $as_echo "198. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:67: \$CC \${abs_top_srcdir}/examples/simple/igraph_arpack_rnsolve.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:67"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_arpack_rnsolve.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:67: cat \${abs_top_srcdir}/examples/'simple/igraph_arpack_rnsolve.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "arpack.at:67"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_arpack_rnsolve.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:67: "
+at_fn_check_prepare_trace "arpack.at:67"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/arpack.at:67: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "arpack.at:67"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/arpack.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_198
+#AT_START_199
+at_fn_group_banner 199 'bipartite.at:24' \
+  "Create bipartite graphs (igraph_create_bipartite):" "" 22
+at_xfail=no
+(
+  $as_echo "199. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:27: \$CC \${abs_top_srcdir}/examples/simple/igraph_bipartite_create.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "bipartite.at:27"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_bipartite_create.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:27: cat \${abs_top_srcdir}/examples/'simple/igraph_bipartite_create.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "bipartite.at:27"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_bipartite_create.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:27: "
+at_fn_check_prepare_trace "bipartite.at:27"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:27: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "bipartite.at:27"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_199
+#AT_START_200
+at_fn_group_banner 200 'bipartite.at:30' \
+  "Projection of bipartite graphs (igraph_bipartite_projection):" "" 22
+at_xfail=no
+(
+  $as_echo "200. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:32: \$CC \${abs_top_srcdir}/examples/simple/igraph_bipartite_projection.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "bipartite.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_bipartite_projection.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:32: >expout"
+at_fn_check_prepare_trace "bipartite.at:32"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:32: "
+at_fn_check_prepare_trace "bipartite.at:32"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/bipartite.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "bipartite.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/bipartite.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_200
+#AT_START_201
+at_fn_group_banner 201 'centralization.at:24' \
+  "Centralization (igraph_centralization_*):" "      " 23
+at_xfail=no
+(
+  $as_echo "201. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/centralization.at:26: \$CC \${abs_top_srcdir}/examples/simple/centralization.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "centralization.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/centralization.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/centralization.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/centralization.at:26: >expout"
+at_fn_check_prepare_trace "centralization.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/centralization.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/centralization.at:26: "
+at_fn_check_prepare_trace "centralization.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/centralization.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/centralization.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "centralization.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/centralization.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_201
+#AT_START_202
+at_fn_group_banner 202 'separators.at:24' \
+  "Decision problem (igraph_is_separator): " "       " 24
+at_xfail=no
+(
+  $as_echo "202. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_is_separator.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_is_separator.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:26: >expout"
+at_fn_check_prepare_trace "separators.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:26: "
+at_fn_check_prepare_trace "separators.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_202
+#AT_START_203
+at_fn_group_banner 203 'separators.at:29' \
+  "Decision problem, minimal separator (igraph_is_minimal separator): " "" 24
+at_xfail=no
+(
+  $as_echo "203. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_is_minimal_separator.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_is_minimal_separator.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:31: >expout"
+at_fn_check_prepare_trace "separators.at:31"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:31: "
+at_fn_check_prepare_trace "separators.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_203
+#AT_START_204
+at_fn_group_banner 204 'separators.at:34' \
+  "Minimal separators (igraph_all_minimal_ab_separators): " "" 24
+at_xfail=no
+(
+  $as_echo "204. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:36: \$CC \${abs_top_srcdir}/examples/simple/igraph_minimal_separators.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_minimal_separators.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:36: >expout"
+at_fn_check_prepare_trace "separators.at:36"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:36: "
+at_fn_check_prepare_trace "separators.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_204
+#AT_START_205
+at_fn_group_banner 205 'separators.at:39' \
+  "Minimal separators, bug 1033045 (igraph_all_minimal_st_separators): " "" 24
+at_xfail=no
+(
+  $as_echo "205. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:41: \$CC \${abs_top_srcdir}/examples/simple/bug-1033045.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:41"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/bug-1033045.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:41: cat \${abs_top_srcdir}/examples/'simple/bug-1033045.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "separators.at:41"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/bug-1033045.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:41: "
+at_fn_check_prepare_trace "separators.at:41"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:41: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:41"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_205
+#AT_START_206
+at_fn_group_banner 206 'separators.at:44' \
+  "Minimum size separators (igraph_minimum_size_separators): " "" 24
+at_xfail=no
+(
+  $as_echo "206. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:47: \$CC \${abs_top_srcdir}/examples/simple/igraph_minimum_size_separators.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:47"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_minimum_size_separators.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:47: cat \${abs_top_srcdir}/examples/'simple/igraph_minimum_size_separators.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "separators.at:47"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_minimum_size_separators.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:47: "
+at_fn_check_prepare_trace "separators.at:47"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:47: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:47"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_206
+#AT_START_207
+at_fn_group_banner 207 'separators.at:50' \
+  "Cohesive blocking (igraph_cohesive_blocks): " "   " 24
+at_xfail=no
+(
+  $as_echo "207. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:52: \$CC \${abs_top_srcdir}/examples/simple/cohesive_blocks.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:52"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/cohesive_blocks.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:52: cat \${abs_top_srcdir}/examples/'simple/cohesive_blocks.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "separators.at:52"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/cohesive_blocks.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:52: "
+at_fn_check_prepare_trace "separators.at:52"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/separators.at:52: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "separators.at:52"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/separators.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_207
+#AT_START_208
+at_fn_group_banner 208 'hrg.at:24' \
+  "Fitting a hierarchical model (igraph_hrg_fit) :" "" 25
+at_xfail=no
+(
+  $as_echo "208. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_hrg.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "hrg.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_hrg.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:26: >expout"
+at_fn_check_prepare_trace "hrg.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:26: "
+at_fn_check_prepare_trace "hrg.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "hrg.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_208
+#AT_START_209
+at_fn_group_banner 209 'hrg.at:29' \
+  "Consensus tree (igraph_hrg_consensus) :" "        " 25
+at_xfail=no
+(
+  $as_echo "209. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_hrg2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "hrg.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_hrg2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:31: cat \${abs_top_srcdir}/examples/'simple/igraph_hrg2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "hrg.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_hrg2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:31: "
+at_fn_check_prepare_trace "hrg.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "hrg.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_209
+#AT_START_210
+at_fn_group_banner 210 'hrg.at:34' \
+  "Missing edge prediction (igraph_hrg_predict) :" " " 25
+at_xfail=no
+(
+  $as_echo "210. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:36: \$CC \${abs_top_srcdir}/examples/simple/igraph_hrg3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "hrg.at:36"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_hrg3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:36: cat \${abs_top_srcdir}/examples/'simple/igraph_hrg3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "hrg.at:36"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_hrg3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:36: "
+at_fn_check_prepare_trace "hrg.at:36"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/hrg.at:36: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "hrg.at:36"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/hrg.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_210
+#AT_START_211
+at_fn_group_banner 211 'microscopic.at:23' \
+  "Deterministic optimal imitation:" "               " 26
+at_xfail=no
+(
+  $as_echo "211. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:25: \$CC \${abs_top_srcdir}/examples/simple/igraph_deterministic_optimal_imitation.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:25"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_deterministic_optimal_imitation.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:25: >expout"
+at_fn_check_prepare_trace "microscopic.at:25"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:25: "
+at_fn_check_prepare_trace "microscopic.at:25"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:25: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:25"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_211
+#AT_START_212
+at_fn_group_banner 212 'microscopic.at:28' \
+  "Stochastic imitation via uniform selection:" "    " 26
+at_xfail=no
+(
+  $as_echo "212. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:30: \$CC \${abs_top_srcdir}/examples/simple/igraph_stochastic_imitation.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:30"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_stochastic_imitation.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:30"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:30: >expout"
+at_fn_check_prepare_trace "microscopic.at:30"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:30"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:30: "
+at_fn_check_prepare_trace "microscopic.at:30"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:30"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:30: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:30"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:30"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_212
+#AT_START_213
+at_fn_group_banner 213 'microscopic.at:33' \
+  "Stochastic imitation via roulette selection:" "   " 26
+at_xfail=no
+(
+  $as_echo "213. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:35: \$CC \${abs_top_srcdir}/examples/simple/igraph_roulette_wheel_imitation.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:35"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_roulette_wheel_imitation.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:35"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:35: >expout"
+at_fn_check_prepare_trace "microscopic.at:35"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:35"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:35: "
+at_fn_check_prepare_trace "microscopic.at:35"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:35"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:35: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:35"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:35"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_213
+#AT_START_214
+at_fn_group_banner 214 'microscopic.at:38' \
+  "Moran process:" "                                 " 26
+at_xfail=no
+(
+  $as_echo "214. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:40: \$CC \${abs_top_srcdir}/examples/simple/igraph_moran_process.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:40"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_moran_process.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:40: >expout"
+at_fn_check_prepare_trace "microscopic.at:40"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:40: "
+at_fn_check_prepare_trace "microscopic.at:40"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/microscopic.at:40: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "microscopic.at:40"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/microscopic.at:40"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_214
+#AT_START_215
+at_fn_group_banner 215 'mt.at:24' \
+  "Simple error handling test :" "                   " 27
+at_xfail=no
+(
+  $as_echo "215. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:26: \$CC \${abs_top_srcdir}/examples/simple/tls1.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm -lpthread -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "mt.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/tls1.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm -lpthread -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:26: >expout"
+at_fn_check_prepare_trace "mt.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:26: "
+at_fn_check_prepare_trace "mt.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "mt.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_215
+#AT_START_216
+at_fn_group_banner 216 'mt.at:29' \
+  "Thread-safe ARPACK:" "                            " 27
+at_xfail=no
+(
+  $as_echo "216. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:32: \$CC \${abs_top_srcdir}/examples/simple/tls2.c -I\${abs_top_srcdir}/include -I\${abs_top_srcdir}/src -I\${abs_top_builddir}/include -I\${abs_top_builddir} -L\${abs_top_builddir}/src/.libs -ligraph -lm -lpthread -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "mt.at:32"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/tls2.c -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm -lpthread -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:32: cat \${abs_top_srcdir}/examples/'simple/tls2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "mt.at:32"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/tls2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:32: "
+at_fn_check_prepare_trace "mt.at:32"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/mt.at:32: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "mt.at:32"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/mt.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_216
+#AT_START_217
+at_fn_group_banner 217 'scg.at:24' \
+  "Solving the SCG problem (igraph_scg_grouping) :" "" 28
+at_xfail=no
+(
+  $as_echo "217. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:27: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_grouping.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:27"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_grouping.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:27: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_grouping.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:27"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_grouping.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:27: "
+at_fn_check_prepare_trace "scg.at:27"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:27: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:27"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:27"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_217
+#AT_START_218
+at_fn_group_banner 218 'scg.at:30' \
+  "Solving the SCG problem, adjacency matrix (igraph_scg_grouping) :" "" 28
+at_xfail=no
+(
+  $as_echo "218. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:33: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_grouping2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:33"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_grouping2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:33: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_grouping2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:33"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_grouping2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:33: "
+at_fn_check_prepare_trace "scg.at:33"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:33: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:33"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_218
+#AT_START_219
+at_fn_group_banner 219 'scg.at:36' \
+  "Solving the SCG problem, stochastic matrix (igraph_scg_grouping) :" "" 28
+at_xfail=no
+(
+  $as_echo "219. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:39: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_grouping3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:39"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_grouping3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:39: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_grouping3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:39"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_grouping3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:39: "
+at_fn_check_prepare_trace "scg.at:39"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:39: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:39"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_219
+#AT_START_220
+at_fn_group_banner 220 'scg.at:42' \
+  "Solving the SCG problem, laplacian matrix (igraph_scg_grouping) :" "" 28
+at_xfail=no
+(
+  $as_echo "220. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:45: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_grouping4.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:45"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_grouping4.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:45: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_grouping4.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:45"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_grouping4.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:45: "
+at_fn_check_prepare_trace "scg.at:45"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:45: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:45"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_220
+#AT_START_221
+at_fn_group_banner 221 'scg.at:48' \
+  "SCG semi-projectors, symmetric (igraph_scg_semiprojectors) :" "" 28
+at_xfail=no
+(
+  $as_echo "221. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:51: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_semiprojectors.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:51"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_semiprojectors.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:51: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_semiprojectors.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:51"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_semiprojectors.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:51: "
+at_fn_check_prepare_trace "scg.at:51"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:51: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:51"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_221
+#AT_START_222
+at_fn_group_banner 222 'scg.at:54' \
+  "SCG semi-projectors, stochastic (igraph_scg_semiprojectors) :" "" 28
+at_xfail=no
+(
+  $as_echo "222. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:57: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_semiprojectors2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:57"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_semiprojectors2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:57: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_semiprojectors2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:57"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_semiprojectors2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:57: "
+at_fn_check_prepare_trace "scg.at:57"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:57: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:57"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_222
+#AT_START_223
+at_fn_group_banner 223 'scg.at:60' \
+  "SCG semi-projectors, laplacian (igraph_scg_semiprojectors) :" "" 28
+at_xfail=no
+(
+  $as_echo "223. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:63: \$CC \${abs_top_srcdir}/examples/simple/igraph_scg_semiprojectors3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:63"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_scg_semiprojectors3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:63: cat \${abs_top_srcdir}/examples/'simple/igraph_scg_semiprojectors3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:63"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_scg_semiprojectors3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:63: "
+at_fn_check_prepare_trace "scg.at:63"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:63: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:63"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:63"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_223
+#AT_START_224
+at_fn_group_banner 224 'scg.at:66' \
+  "SCG of a graph, adjacency matrix (igraph_scg) :" "" 28
+at_xfail=no
+(
+  $as_echo "224. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:68: \$CC \${abs_top_srcdir}/examples/simple/scg.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:68"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/scg.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:68: cat \${abs_top_srcdir}/examples/'simple/scg.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:68"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/scg.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:68: "
+at_fn_check_prepare_trace "scg.at:68"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:68: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:68"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:68"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_224
+#AT_START_225
+at_fn_group_banner 225 'scg.at:71' \
+  "SCG of a graph, stochastic matrix (igraph_scg) :" "" 28
+at_xfail=no
+(
+  $as_echo "225. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:73: \$CC \${abs_top_srcdir}/examples/simple/scg2.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:73"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/scg2.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:73: cat \${abs_top_srcdir}/examples/'simple/scg2.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:73"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/scg2.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:73: "
+at_fn_check_prepare_trace "scg.at:73"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:73: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:73"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_225
+#AT_START_226
+at_fn_group_banner 226 'scg.at:76' \
+  "SCG of a graph, laplacian matrix (igraph_scg) :" "" 28
+at_xfail=no
+(
+  $as_echo "226. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:78: \$CC \${abs_top_srcdir}/examples/simple/scg3.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:78"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/scg3.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:78: cat \${abs_top_srcdir}/examples/'simple/scg3.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "scg.at:78"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/scg3.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:78: "
+at_fn_check_prepare_trace "scg.at:78"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/scg.at:78: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "scg.at:78"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/scg.at:78"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_226
+#AT_START_227
+at_fn_group_banner 227 'random.at:24' \
+  "Random seed:" "                                   " 29
+at_xfail=no
+(
+  $as_echo "227. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/random.at:26: \$CC \${abs_top_srcdir}/examples/simple/random_seed.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/random_seed.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:26: >expout"
+at_fn_check_prepare_trace "random.at:26"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:26: "
+at_fn_check_prepare_trace "random.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_227
+#AT_START_228
+at_fn_group_banner 228 'random.at:29' \
+  "MT19937 RNG on 64 bit machines:" "                " 29
+at_xfail=no
+(
+  $as_echo "228. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/random.at:31: \$CC \${abs_top_srcdir}/examples/simple/mt.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/mt.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:31: >expout"
+at_fn_check_prepare_trace "random.at:31"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:31: "
+at_fn_check_prepare_trace "random.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_228
+#AT_START_229
+at_fn_group_banner 229 'random.at:34' \
+  "Exponentially distributed random numbers:" "      " 29
+at_xfail=no
+(
+  $as_echo "229. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/random.at:37: \$CC \${abs_top_srcdir}/examples/simple/igraph_rng_get_exp.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:37"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_rng_get_exp.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:37: cat \${abs_top_srcdir}/examples/'simple/igraph_rng_get_exp.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "random.at:37"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_rng_get_exp.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:37: "
+at_fn_check_prepare_trace "random.at:37"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:37: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:37"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_229
+#AT_START_230
+at_fn_group_banner 230 'random.at:40' \
+  "Random sampling from consecutive sequence:" "     " 29
+at_xfail=no
+(
+  $as_echo "230. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/random.at:42: \$CC \${abs_top_srcdir}/examples/simple/igraph_random_sample.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:42"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_random_sample.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:42: >expout"
+at_fn_check_prepare_trace "random.at:42"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:42: "
+at_fn_check_prepare_trace "random.at:42"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:42: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:42"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_230
+#AT_START_231
+at_fn_group_banner 231 'random.at:45' \
+  "Fisher-Yates shuffle:" "                          " 29
+at_xfail=no
+(
+  $as_echo "231. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/random.at:47: \$CC \${abs_top_srcdir}/examples/simple/igraph_fisher_yates_shuffle.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:47"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_fisher_yates_shuffle.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:47: >expout"
+at_fn_check_prepare_trace "random.at:47"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:47: "
+at_fn_check_prepare_trace "random.at:47"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/random.at:47: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "random.at:47"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/random.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_231
+#AT_START_232
+at_fn_group_banner 232 'qsort.at:24' \
+  "Regular qsort (igraph_qsort):" "                  " 30
+at_xfail=no
+(
+  $as_echo "232. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:26: \$CC \${abs_top_srcdir}/examples/simple/igraph_qsort.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "qsort.at:26"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_qsort.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:26: cat \${abs_top_srcdir}/examples/'simple/igraph_qsort.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "qsort.at:26"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_qsort.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:26: "
+at_fn_check_prepare_trace "qsort.at:26"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:26: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "qsort.at:26"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_232
+#AT_START_233
+at_fn_group_banner 233 'qsort.at:29' \
+  "qsort with extra argument (igraph_qsort_r):" "    " 30
+at_xfail=no
+(
+  $as_echo "233. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:31: \$CC \${abs_top_srcdir}/examples/simple/igraph_qsort_r.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "qsort.at:31"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_qsort_r.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:31: cat \${abs_top_srcdir}/examples/'simple/igraph_qsort_r.out' | sed \"s/@VERSION@/\$(cat \${abs_top_srcdir}/VERSION)/g\" > expout"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "qsort.at:31"
+( $at_check_trace; cat ${abs_top_srcdir}/examples/'simple/igraph_qsort_r.out' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:31: "
+at_fn_check_prepare_trace "qsort.at:31"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/qsort.at:31: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "qsort.at:31"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/qsort.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_233
+#AT_START_234
+at_fn_group_banner 234 'matching.at:23' \
+  "Maximum bipartite matching (igraph_maximum_bipartite_matching): " "" 31
+at_xfail=no
+(
+  $as_echo "234. $at_setup_line: testing $at_desc ..."
+  $at_traceon
+
+
+
+{ set +x
+$as_echo "$at_srcdir/matching.at:25: \$CC \${abs_top_srcdir}/examples/simple/igraph_maximum_bipartite_matching.c -I\${abs_top_srcdir}/include -I\${abs_top_builddir}/include -L\${abs_top_builddir}/src/.libs -ligraph -lm  -o itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "matching.at:25"
+( $at_check_trace; $CC ${abs_top_srcdir}/examples/simple/igraph_maximum_bipartite_matching.c -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm  -o itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/matching.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/matching.at:25: >expout"
+at_fn_check_prepare_trace "matching.at:25"
+( $at_check_trace; >expout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/matching.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/matching.at:25: "
+at_fn_check_prepare_trace "matching.at:25"
+( $at_check_trace;
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/matching.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+$as_echo "$at_srcdir/matching.at:25: DYLD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${DYLD_LIBRARY_PATH+:\$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=\${abs_top_builddir}/src/.libs\${LD_LIBRARY_PATH+:\$LD_LIBRARY_PATH} ./itest"
+at_fn_check_prepare_notrace 'a ${...} parameter expansion' "matching.at:25"
+( $at_check_trace; DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+$at_diff expout "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/matching.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+  set +x
+  $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_234
diff --git a/tests/testsuite.at b/tests/testsuite.at
new file mode 100644
index 0000000..6a3d027
--- /dev/null
+++ b/tests/testsuite.at
@@ -0,0 +1,62 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for the IGraph library.
+# 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
+
+AT_INIT([igraph])
+
+m4_define([AT_COMPILE_CHECK], [
+AT_CHECK([m4_if([[$4]],[[]],
+	[[$CC ${abs_top_srcdir}/examples/$1 -I${abs_top_srcdir}/include -I${abs_top_builddir}/include -L${abs_top_builddir}/src/.libs -ligraph -lm $5 -o itest]], 
+	[[$CC ${abs_top_srcdir}/examples/$1 -I${abs_top_srcdir}/include -I${abs_top_srcdir}/src -I${abs_top_builddir}/include -I${abs_top_builddir} -L${abs_top_builddir}/src/.libs -ligraph -lm $5 -o itest]])])
+AT_CHECK([m4_if([[$2]],[[]],[[>expout]],[[cat ${abs_top_srcdir}/examples/'$2' | sed "s/@VERSION@/$(cat ${abs_top_srcdir}/VERSION)/g" > expout]])])
+AT_CHECK([m4_if([[$3]],[[]],[[]],[[cp ${abs_top_srcdir}/examples/$3 .]])])
+AT_CHECK([DYLD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${DYLD_LIBRARY_PATH+:$DYLD_LIBRARY_PATH} LD_LIBRARY_PATH=${abs_top_builddir}/src/.libs${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH} ./itest], [], [expout])])
+
+m4_include([version.at])
+m4_include([types.at])
+m4_include([basic.at])
+m4_include([iterators.at])
+m4_include([structure_generators.at])
+m4_include([structural_properties.at])
+m4_include([components.at])
+m4_include([layout.at])
+m4_include([visitors.at])
+m4_include([topology.at])
+m4_include([motifs.at])
+m4_include([foreign.at])
+m4_include([other.at])
+m4_include([operators.at])
+m4_include([conversion.at])
+m4_include([flow.at])
+m4_include([community.at])
+m4_include([cliques.at])
+m4_include([eigen.at])
+m4_include([attributes.at])
+m4_include([arpack.at])
+m4_include([bipartite.at])
+m4_include([centralization.at])
+m4_include([separators.at])
+m4_include([hrg.at])
+m4_include([microscopic.at])
+m4_include([mt.at])
+m4_include([scg.at])
+m4_include([random.at])
+m4_include([qsort.at])
+m4_include([matching.at])
diff --git a/tests/topology.at b/tests/topology.at
new file mode 100644
index 0000000..b7f76e1
--- /dev/null
+++ b/tests/topology.at
@@ -0,0 +1,48 @@
+# Check graph topology related functions
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Graph topology]])
+
+AT_SETUP([The isomorphism class of a subgraph (igraph_isolass_subgraph)])
+AT_KEYWORDS([isomorph isomorphism class motif])
+AT_COMPILE_CHECK([simple/topology.c], [simple/topology.out])
+AT_CLEANUP
+
+AT_SETUP([The VF2 isomorphism algorithm])
+AT_KEYWORDS([isomorph isomorphic VF2])
+AT_COMPILE_CHECK([simple/igraph_isomorphic_vf2.c])
+AT_CLEANUP
+
+AT_SETUP([VF algorithm with compatibility functions])
+AT_KEYWORDS([isomorph isomorphic VF2 compatibility])
+AT_COMPILE_CHECK([simple/VF2-compat.c])
+AT_CLEANUP
+
+AT_SETUP([LAD subgraph isomorphism algorithm])
+AT_KEYWORDS([isomorph isomorphic subgraph isomorphism LAD])
+AT_COMPILE_CHECK([simple/igraph_subisomorphic_lad.c],
+		 [simple/igraph_subisomorphic_lad.out])
+AT_CLEANUP
+
+AT_SETUP([Graphical degree sequences])
+AT_KEYWORDS([degree sequence graphical])
+AT_COMPILE_CHECK([simple/igraph_is_degree_sequence.c])
+AT_CLEANUP
diff --git a/tests/types.at b/tests/types.at
new file mode 100644
index 0000000..f80a6a2
--- /dev/null
+++ b/tests/types.at
@@ -0,0 +1,199 @@
+# Check the utility types (vector_t, etc.)
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Utility types (vector_t, etc.)]])
+
+AT_SETUP([Vector (vector_t): ])
+AT_KEYWORDS([vector vector_t])
+AT_COMPILE_CHECK([simple/vector.c], [simple/vector.out])
+AT_CLEANUP
+
+AT_SETUP([Vector (more) (vector_t): ])
+AT_KEYWORDS([vector vector_t])
+AT_COMPILE_CHECK([simple/vector2.c], [simple/vector2.out])
+AT_CLEANUP
+
+AT_SETUP([Vector (even more) (vector_t): ])
+AT_KEYWORDS([vector vector_t])
+AT_COMPILE_CHECK([simple/vector3.c])
+AT_CLEANUP
+
+AT_SETUP([Matrix (matrix_t): ])
+AT_KEYWORDS([matrix matrix_t])
+AT_COMPILE_CHECK([simple/matrix.c], [simple/matrix.out])
+AT_CLEANUP
+
+AT_SETUP([Matrix (more) (matrix_t): ])
+AT_KEYWORDS([matrix matrix_t])
+AT_COMPILE_CHECK([simple/matrix2.c], [simple/matrix2.out])
+AT_CLEANUP
+
+AT_SETUP([Matrix (even more) (matrix_t): ])
+AT_KEYWORDS([matrix matrix_t])
+AT_COMPILE_CHECK([simple/matrix3.c])
+AT_CLEANUP
+
+AT_SETUP([Double ended queue (dqueue_t): ])
+AT_KEYWORDS([dqueue double queue dqueue_t])
+AT_COMPILE_CHECK([simple/dqueue.c], [simple/dqueue.out])
+AT_CLEANUP
+
+AT_SETUP([Vector of pointers (vector_ptr_t): ])
+AT_KEYWORDS([vector pointers vector_ptr_t])
+AT_COMPILE_CHECK([simple/vector_ptr.c])
+AT_CLEANUP
+
+AT_SETUP([Stack (stack_t): ])
+AT_KEYWORDS([stack stack_t])
+AT_COMPILE_CHECK([simple/stack.c])
+AT_CLEANUP
+
+AT_SETUP([Heap (heap_t): ])
+AT_KEYWORDS([heap heap_t])
+AT_COMPILE_CHECK([simple/heap.c])
+AT_CLEANUP
+
+AT_SETUP([Indexed heap (indheap_t): ])
+AT_KEYWORDS([indexed heap indheap_t])
+AT_COMPILE_CHECK([simple/indheap.c], [], [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Doubly indexed heap (d_indheap_t): ])
+AT_KEYWORDS([doubly indexed heap d_indheap_t])
+AT_COMPILE_CHECK([simple/d_indheap.c], [simple/d_indheap.out], [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([String vector (igraph_strvector_t): ])
+AT_KEYWORDS([string vector igraph_strvector_t])
+AT_COMPILE_CHECK([simple/igraph_strvector.c], [simple/igraph_strvector.out])
+AT_CLEANUP
+
+AT_SETUP([Trie (igraph_trie_t): ])
+AT_KEYWORDS([trie igraph_trie_t])
+AT_COMPILE_CHECK([simple/igraph_trie.c], [simple/igraph_trie.out], [], 
+		 [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Partial Sum-Tree (igraph_psumtree_t): ])
+AT_KEYWORDS([partial sumtree igraph_psumtree_t])
+AT_COMPILE_CHECK([simple/igraph_psumtree.c])
+AT_CLEANUP
+
+AT_SETUP([Three dimensional array (igraph_array3_t): ])
+AT_KEYWORDS([array array3 three dimensional array])
+AT_COMPILE_CHECK([simple/igraph_array.c], [simple/igraph_array.out])
+AT_CLEANUP
+
+AT_SETUP([Hash table (string->string) (igraph_hashtable_t): ])
+AT_KEYWORDS([igraph_hashtable_t hash table])
+AT_COMPILE_CHECK([simple/igraph_hashtable.c], [simple/igraph_hashtable.out],
+                 [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Special heap for minimum cuts (igraph_i_cutheap_t): ])
+AT_KEYWORDS([heap minimum cut])
+AT_COMPILE_CHECK([simple/igraph_i_cutheap.c], [simple/igraph_i_cutheap.out],
+                 [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Set (igraph_set_t): ])
+AT_KEYWORDS([set igraph_set_t])
+AT_COMPILE_CHECK([simple/igraph_set.c], [simple/igraph_set.out],
+                 [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([2-way heap (igraph_2wheap_t): ])
+AT_KEYWORDS([heap two-way 2-way igraph_2wheap_t])
+AT_COMPILE_CHECK([simple/2wheap.c], [], [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat.c], [simple/igraph_sparsemat.out])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, multiplications (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat2.c], [simple/igraph_sparsemat2.out],
+                 [], [INTERNAL], [-lblas])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, indexing (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat3.c], [simple/igraph_sparsemat3.out],
+                 [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, solvers (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat4.c], [simple/igraph_sparsemat4.out],
+                 [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, ARPACK eigensolver (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t ARPACK])
+AT_COMPILE_CHECK([simple/igraph_sparsemat5.c], [simple/igraph_sparsemat5.out])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, conversion to dense (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat6.c])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, min & max (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat7.c])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, other operations (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t])
+AT_COMPILE_CHECK([simple/igraph_sparsemat8.c])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, multiplications with dense (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t sparse-dense dense-sparse])
+AT_COMPILE_CHECK([simple/igraph_sparsemat9.c])
+AT_CLEANUP
+
+AT_SETUP([Sparse matrix, is symmetric? (igraph_sparsemat_t): ])
+AT_KEYWORDS([sparse matrix igraph_sparsemat_t symmetric is_symmetric])
+AT_COMPILE_CHECK([simple/igraph_sparsemat_is_symmetric.c])
+AT_CLEANUP
+
+AT_SETUP([Another sparse matrix (igraph_spmatrix_t): ])
+AT_KEYWORDS([sparse matrix igraph_spmatrix_t])
+AT_COMPILE_CHECK([simple/spmatrix.c], [simple/spmatrix.out])
+AT_CLEANUP
+
+AT_SETUP([Arbitrarily big integers (igraph_biguint_t): ])
+AT_KEYWORDS([bignum bigint big integer arbitrarily])
+AT_COMPILE_CHECK([simple/biguint.c],[simple/biguint.out],[],[INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Marked double ended queue (igraph_marked_queue_t): ])
+AT_KEYWORDS([dqueue queue igraph_marked_queue_t])
+AT_COMPILE_CHECK([simple/igraph_marked_queue.c], [], [], [INTERNAL])
+AT_CLEANUP
+
+AT_SETUP([Complex numbers (igraph_complex_t): ])
+AT_KEYWORDS([complex])
+AT_COMPILE_CHECK([simple/igraph_complex.c])
+AT_CLEANUP
diff --git a/tests/version.at b/tests/version.at
new file mode 100644
index 0000000..cdd533d
--- /dev/null
+++ b/tests/version.at
@@ -0,0 +1,29 @@
+# Query version number
+
+# Test suite for the 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
+
+# Macros
+
+AT_BANNER([[igraph version number.]])
+
+AT_SETUP([Simple version query (igraph_version): ])
+AT_KEYWORDS([version igraph_version])
+AT_COMPILE_CHECK([simple/igraph_version.c])
+AT_CLEANUP
diff --git a/tests/visitors.at b/tests/visitors.at
new file mode 100644
index 0000000..0436143
--- /dev/null
+++ b/tests/visitors.at
@@ -0,0 +1,33 @@
+# Check functions for different visitor-like functions
+
+# Test suite for the IGraph library.
+# 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
+
+AT_BANNER([[Visitors]])
+
+AT_SETUP([Internal breadth-first search (igraph_i_bfs):])
+AT_KEYWORDS([igraph_i_bfs bfs breadth-first visitor])
+AT_COMPILE_CHECK([simple/igraph_bfs.c], [simple/igraph_bfs.out])
+AT_CLEANUP
+
+AT_SETUP([Breadth-first search (igraph_bfs):])
+AT_KEYWORDS([igraph_bfs bfs breadth-first visitor])
+AT_COMPILE_CHECK([simple/igraph_bfs2.c], [simple/igraph_bfs2.out])
+AT_CLEANUP
+
diff --git a/tools/autoconf/ax_tls.m4 b/tools/autoconf/ax_tls.m4
new file mode 100644
index 0000000..e3119ea
--- /dev/null
+++ b/tools/autoconf/ax_tls.m4
@@ -0,0 +1,76 @@
+# ===========================================================================
+#          http://www.gnu.org/software/autoconf-archive/ax_tls.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_TLS([action-if-found], [action-if-not-found])
+#
+# DESCRIPTION
+#
+#   Provides a test for the compiler support of thread local storage (TLS)
+#   extensions. Defines TLS if it is found. Currently knows about GCC/ICC
+#   and MSVC. I think SunPro uses the same as GCC, and Borland apparently
+#   supports either.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Alan Woodland <ajw05 at aber.ac.uk>
+#   Copyright (c) 2010 Diego Elio Petteno` <flameeyes at gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 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/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 10
+
+AC_DEFUN([AX_TLS], [
+  AC_MSG_CHECKING(for thread local storage (TLS) class)
+  AC_CACHE_VAL(ac_cv_tls, [
+    ax_tls_keywords="__thread __declspec(thread) none"
+    for ax_tls_keyword in $ax_tls_keywords; do
+       AS_CASE([$ax_tls_keyword],
+          [none], [ac_cv_tls=none ; break],
+          [AC_TRY_COMPILE(
+              [#include <stdlib.h>
+               static void
+               foo(void) {
+               static ] $ax_tls_keyword [ int bar;
+               exit(1);
+               }],
+               [],
+               [ac_cv_tls=$ax_tls_keyword ; break],
+               ac_cv_tls=none
+           )])
+    done
+  ])
+  AC_MSG_RESULT($ac_cv_tls)
+
+  AS_IF([test "$ac_cv_tls" != "none"],
+    AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here])
+      m4_ifval([$1], [$1], [true]),
+    m4_ifval([$2], [$2], [true])
+  )
+])
diff --git a/ylwrap b/ylwrap
new file mode 100755
index 0000000..8f072a8
--- /dev/null
+++ b/ylwrap
@@ -0,0 +1,247 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2013-01-12.17; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey at cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, 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/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+get_dirname ()
+{
+  case $1 in
+    */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
+    # Otherwise,  we want the empty string (not ".").
+  esac
+}
+
+# guard FILE
+# ----------
+# The CPP macro used to guard inclusion of FILE.
+guard ()
+{
+  printf '%s\n' "$1"                                                    \
+    | sed                                                               \
+        -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'   \
+        -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'                        \
+        -e 's/__*/_/g'
+}
+
+# quote_for_sed [STRING]
+# ----------------------
+# Return STRING (or stdin) quoted to be used as a sed pattern.
+quote_for_sed ()
+{
+  case $# in
+    0) cat;;
+    1) printf '%s\n' "$1";;
+  esac \
+    | sed -e 's|[][\\.*]|\\&|g'
+}
+
+case "$1" in
+  '')
+    echo "$0: No files given.  Try '$0 --help' for more information." 1>&2
+    exit 1
+    ;;
+  --basedir)
+    basedir=$2
+    shift 2
+    ;;
+  -h|--h*)
+    cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+  INPUT is the input file
+  OUTPUT is one file PROG generates
+  DESIRED is the file we actually want instead of OUTPUT
+  PROGRAM is program to run
+  ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v|--v*)
+    echo "ylwrap $scriptversion"
+    exit $?
+    ;;
+esac
+
+
+# The input.
+input=$1
+shift
+# We'll later need for a correct munging of "#line" directives.
+input_sub_rx=`get_dirname "$input" | quote_for_sed`
+case $input in
+  [\\/]* | ?:[\\/]*)
+    # Absolute path; do nothing.
+    ;;
+  *)
+    # Relative path.  Make it absolute.
+    input=`pwd`/$input
+    ;;
+esac
+input_rx=`get_dirname "$input" | quote_for_sed`
+
+# Since DOS filename conventions don't allow two dots,
+# the DOS version of Bison writes out y_tab.c instead of y.tab.c
+# and y_tab.h instead of y.tab.h. Test to see if this is the case.
+y_tab_nodot=false
+if test -f y_tab.c || test -f y_tab.h; then
+  y_tab_nodot=true
+fi
+
+# The parser itself, the first file, is the destination of the .y.c
+# rule in the Makefile.
+parser=$1
+
+# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
+# instance, we rename #include "y.tab.h" into #include "parse.h"
+# during the conversion from y.tab.c to parse.c.
+sed_fix_filenames=
+
+# Also rename header guards, as Bison 2.7 for instance uses its header
+# guard in its implementation file.
+sed_fix_header_guards=
+
+while test $# -ne 0; do
+  if test x"$1" = x"--"; then
+    shift
+    break
+  fi
+  from=$1
+  # Handle y_tab.c and y_tab.h output by DOS
+  if $y_tab_nodot; then
+    case $from in
+      "y.tab.c") from=y_tab.c;;
+      "y.tab.h") from=y_tab.h;;
+    esac
+  fi
+  shift
+  to=$1
+  shift
+  sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
+  sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
+done
+
+# The program to run.
+prog=$1
+shift
+# Make any relative path in $prog absolute.
+case $prog in
+  [\\/]* | ?:[\\/]*) ;;
+  *[\\/]*) prog=`pwd`/$prog ;;
+esac
+
+dirname=ylwrap$$
+do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+  0) "$prog" "$input" ;;
+  *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+  for from in *
+  do
+    to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
+    if test -f "$from"; then
+      # If $2 is an absolute path name, then just use that,
+      # otherwise prepend '../'.
+      case $to in
+        [\\/]* | ?:[\\/]*) target=$to;;
+        *) target=../$to;;
+      esac
+
+      # Do not overwrite unchanged header files to avoid useless
+      # recompilations.  Always update the parser itself: it is the
+      # destination of the .y.c rule in the Makefile.  Divert the
+      # output of all other files to a temporary file so we can
+      # compare them to existing versions.
+      if test $from != $parser; then
+        realtarget=$target
+        target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
+      fi
+
+      # Munge "#line" or "#" directives.  Don't let the resulting
+      # debug information point at an absolute srcdir.  Use the real
+      # output file name, not yy.lex.c for instance.  Adjust the
+      # include guards too.
+      sed -e "/^#/!b"                           \
+          -e "s|$input_rx|$input_sub_rx|"       \
+          -e "$sed_fix_filenames"               \
+          -e "$sed_fix_header_guards"           \
+        "$from" >"$target" || ret=$?
+
+      # Check whether files must be updated.
+      if test "$from" != "$parser"; then
+        if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+          echo "$to is unchanged"
+          rm -f "$target"
+        else
+          echo "updating $to"
+          mv -f "$target" "$realtarget"
+        fi
+      fi
+    else
+      # A missing file is only an error for the parser.  This is a
+      # blatant hack to let us support using "yacc -d".  If -d is not
+      # specified, don't fail when the header file is "missing".
+      if test "$from" = "$parser"; then
+        ret=1
+      fi
+    fi
+  done
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:

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



More information about the debian-med-commit mailing list